A simple CAN adapter that supports two channels of CAN on the mbed. Configurable speed, monitor mode, statistics and send/receive via the USB serial port to a PC (or terminal program set for 921.6 kbaud)

Dependencies:   CommandProcessor Watchdog mbed

Files at this revision

API Documentation at this revision

Comitter:
WiredHome
Date:
Mon Apr 11 11:32:05 2011 +0000
Child:
1:6b831d0c058c
Commit message:

Changed in this revision

CANUtilities.lib Show annotated file Show diff for this revision Revisions of this file
CANadapter.cpp Show annotated file Show diff for this revision Revisions of this file
CommandProcessor.lib Show annotated file Show diff for this revision Revisions of this file
VStudioCompat.lib Show annotated file Show diff for this revision Revisions of this file
Watchdog.lib Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CANUtilities.lib	Mon Apr 11 11:32:05 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/WiredHome/code/CANUtilities/#5ac97276c770
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CANadapter.cpp	Mon Apr 11 11:32:05 2011 +0000
@@ -0,0 +1,329 @@
+/// CANadapter is a simple program that permits monitoring as well as transmitting
+/// on both CAN buses that the mbed supports. It communicates to either the user or
+/// a PC hosted program via the USB Serial port.
+///
+/// For robustness, there is a small CommandProcessor, which permits setting
+/// CAN interface metrics, reviewing statistics, and sending messages.
+///
+/// There is also a watchdog, which will keep the system running and recover
+/// if there was a problem.
+///
+/// @note Copyright &copr; 2011 by Smartware Computing, all rights reserved.
+///     Individuals may use this application for evaluation or non-commercial
+///     purposes. Within this restriction, changes may be made to this application
+///     as long as this copyright notice is retained. The user shall make
+///     clear that their work is a derived work, and not the original.
+///     Users of this application and sources accept this application "as is" and
+///     shall hold harmless Smartware Computing, for any undesired results while
+///     using this application - whether real or imagined.
+/// @author David Smart, Smartware Computing
+///
+#include "mbed.h"
+#include "Watchdog.h"
+#include "CommandProcessor.h"
+#include "CANUtilities.h"
+#include "CANQueue.h"
+#include "vs_string.h"      // helpers that normalize between compilers for string functions
+
+extern "C" void mbed_reset();
+
+Serial pc(USBTX, USBRX);    ///!< Used as the console for interactively reporting progress
+DigitalOut myled(LED4);     /// LED sign of life
+
+Watchdog wd;
+
+//Ticker ticker;          // for automated sending of messages during development
+
+//Timer timestamp;
+CAN can1(p9, p10);      // bind CAN1 to the hardware
+CAN can2(p30, p29);     // bind CAN2 to the hardware
+Timeout t1;             // create a timeout mechanism for can1
+Timeout t2;             // create a timeout mechanism for can2
+void c1off();           // extinquish the can1 activity indicator
+void c2off();           // extinquish the can2 activity indicator
+
+struct {
+    CAN *can;
+    Timeout *flash;
+    DigitalOut led;
+    void (*off)(void);
+    bool active;
+    int bitrate;
+    uint32_t txCounter;
+    uint32_t rxCounter;
+} can[] = {
+    {&can1, &t1, LED1, c1off, false, 250000, 0, 0},
+    {&can2, &t2, LED2, c2off, false, 250000, 0, 0}
+};
+
+CANQueue inQueue(10);
+
+bool CANTransmitMsg(CANmsg msg);
+
+RUNRESULT_T CANconfig(char *p);
+const CMD_T CANconfigCmd = {"CANconfig", "Configure [channel mode speed], ? for more", CANconfig, visible};
+RUNRESULT_T CANmessage(char *p);
+const CMD_T CANmessageCmd = {"CANmessage", "Shows the CAN message format", CANmessage, visible};
+RUNRESULT_T CANtransmit(char *p);
+const CMD_T CANtransmitCmd = {"t", "transmit a CAN message (see CANmessage format)", CANtransmit, visible};
+RUNRESULT_T CANstatistics(char *p);
+const CMD_T CANstatisticsCmd = {"CANstats", "Shows the CAN statistics", CANstatistics, visible};
+RUNRESULT_T CANreset(char *p);
+const CMD_T CANresetCmd = {"CANreset", "Reset CAN channel [0|1|*]", CANreset, visible};
+RUNRESULT_T Free(char *p);
+const CMD_T FreeCmd = {"Free", "Shows the free memory in bytes", Free, visible};
+RUNRESULT_T Reboot(char *p);
+const CMD_T RebootCmd = {"Reboot", "Causes a near immediate reboot", Reboot, visible};
+
+RUNRESULT_T Reboot(char *p) {
+    (void)p;
+    pc.printf(" now...\r\n");
+    wait(0.5);
+    mbed_reset();
+    return runok;
+}
+
+RUNRESULT_T Free(char *p) {
+    (void)p;
+    uint32_t max = 100000;
+    uint32_t x = max / 2;
+    uint32_t min = 0;
+
+    while (min < max-1) {
+        void * p = malloc(x);
+        if (p) {
+            free(p);
+            min = x;
+        } else {
+            max = x;
+        }
+        x = (max + min)/2;
+    }
+    pc.printf("\r\n%u bytes free\r\n", x);
+    return runok;
+}
+
+
+RUNRESULT_T CANconfig(char *p) {
+    int ch, mode, bitrate;
+    char *token;
+    char *search = " ,\t";
+
+    token = strtok(p, search);
+    ch = atoi(token);
+    token = strtok(NULL, search);
+    if (mystrnicmp(token, "monitor", 7) == 0)
+        mode = 0;
+    else if (mystrnicmp(token, "0", 1) == 0)
+        mode = 0;
+    else if (mystrnicmp(token, "active", 7) == 0)
+        mode = 1;
+    else if (mystrnicmp(token, "1", 1) == 0)
+        mode = 1;
+    else
+        mode = -1;
+    token = strtok(NULL, search);
+    bitrate = atoi(token);
+
+    if (ch >=1 && ch <= 2 && mode != -1 && bitrate > 1000 && bitrate <= 1000000) {
+        can[ch-1].can->monitor(mode);
+        can[ch-1].can->frequency(bitrate);
+        pc.printf("\r\n");
+    } else {
+        pc.printf("\r\n CANconfig [channel mode bits/sec]\r\n"
+                  "     channel = 1 or 2\r\n"
+                  "     mode    = 0|monitor|1|active\r\n"
+                  "     speed   = baud rate (e.g. 10000, 250000, 500000, etc.)\r\n"
+                  "");
+    }
+    return runok;
+}
+
+RUNRESULT_T CANreset(char *p) {
+    if (*p == '1' || *p == '*')
+        can[CH1].can->reset();
+    if (*p == '2' || *p == '*')
+        can[CH2].can->reset();
+    pc.printf("\r\n");
+    return runok;
+}
+
+
+RUNRESULT_T CANmessage(char *p) {
+    pc.printf( "\r\n// CAN Message Format\r\n"
+               "//\r\n"
+               "// +--- 'r'eceive or 't'ransmit\r\n"
+               "// |  +--- 'nrm' 11 bit identifier, 'xtd' 29 bit identifier\r\n"
+               "// |  |   +--- channel '1' to '2'\r\n"
+               "// |  |   |     +--- identifier in hex\r\n"
+               "// |  |   |     |     +--- dlc is data length control from 0 to 8\r\n"
+               "// |  |   |     |     |            +---  data bytes 1 to 8\r\n"
+               "// |  |   |     |     |            |            [Below not required to send\r\n"
+               "// |  |   |     |     |            |            +--- fixed zero\r\n"
+               "// |  |   |     |     |            |            |   +--- err count\r\n"
+               "// |  |   |     |     |            |            |   |    +--- timestamp\r\n"
+               "// |  |   |     |     |            |            |   |    |\r\n"
+               "// _ ___ __ ________ __ _______________________ _ ___ ___________\r\n"
+               "// r xtd 02 1CF00400 08 11 22 33 44 55 66 77 88 0   0 1234.567890\r\n"
+               "// t xtd 01 18EAFF03 03 EE EE 00                0   0 1235.654321\r\n"
+               "// 12345678901234567890123456789012345678901234567890123456789012\r\n");
+    return runok;
+}
+
+RUNRESULT_T CANtransmit(char *p) {
+    if (*p) {
+        CANmsg msg(p);
+        if (msg.dir == xmt)
+            CANTransmitMsg(msg);
+        pc.printf("\r\n");
+    } else {
+        pc.printf( "\r\n't'ransmit a CAN message in the message format\r\n");
+    }
+    return runok;
+}
+
+RUNRESULT_T CANstatistics(char *p) {
+    pc.printf("\r\n  ch    mode  bitrate rxCount rxErrors txCount txErrors\r\n");
+    for (int i=0; i<CANCHANNELS; i++)
+        pc.printf("  %2u %7s %8u %7u %8u %7u %8u\r\n",
+                  i+1,
+                  can[i].active ? "active" : "monitor",
+                  can[i].bitrate,
+                  can[i].rxCounter,
+                  can[i].can->rderror(),
+                  can[i].txCounter,
+                  can[i].can->tderror()
+                 );
+    return runok;
+}
+
+
+
+
+int mReadable() {
+    return pc.readable();
+}
+int mGetCh() {
+    return pc.getc();
+}
+int mPutCh(int a) {
+    return pc.putc(a);
+}
+int mPutS(const char * s) {
+    return pc.printf("%s\r\n", s);
+}
+
+void c1off() {
+    can[CH1].led = false;
+}
+void c2off() {
+    can[CH2].led = false;
+}
+
+void canreceive(CANCHANNEL_T ch) {
+    CANMessage msg;
+
+    if (can[ch].can->read(msg)) {
+        CANmsg _msg(ch, rcv, msg);
+
+        inQueue.Enqueue(_msg);
+        can[ch].rxCounter++;
+        can[ch].led = true;
+        can[ch].flash->attach(can[ch].off, 0.02);
+    }
+}
+
+
+void can1rcv() {
+    canreceive(CH1);
+}
+void can2rcv() {
+    canreceive(CH2);
+}
+
+bool CANTransmitMsg(CANmsg msg) {
+    if (msg.dir == xmt) {
+        if (can[msg.ch].can->write(CANMessage(msg.id, (char *)&msg.data, msg.len, CANData, msg.format)))
+            return true;
+    }
+    return false;
+}
+
+void cantransmit(int ch) {
+    char byte = (char)can[ch].txCounter;
+
+    if (can[ch].can->write(CANMessage(1337, &byte, 1))) {
+        can[ch].txCounter++;
+    }
+}
+
+void can1send() {
+    cantransmit(1);
+}
+void can2send() {
+    cantransmit(2);
+}
+
+
+
+int main(int argc, char* argv[]) {
+    CMDP_T * cp = GetCommandProcessor();
+    RUNRESULT_T cp_state;
+
+    pc.baud(921600);
+    if (wd.WatchdogCausedReset())
+        pc.printf("Watchdog caused reset. WD is now rearmed\r\n");
+    wd.Configure(2.0);  // sets the timeout interval pretty short
+
+    // Set up the Command Processor interface
+    cp->Init(
+        0xFFFF,     // Everything is enabled
+        TRUE,       // Case Insensitive
+        TRUE,       // Echo on
+        50,         // Command Buffer length
+        mReadable,  // User provided API (kbhit())
+        mGetCh,     // User provided API
+        mPutCh,     // User provided API
+        mPutS);     // User provided API
+    cp->Add(&CANconfigCmd);
+    cp->Add(&CANmessageCmd);
+    cp->Add(&CANtransmitCmd);
+    cp->Add(&CANstatisticsCmd);
+    cp->Add(&CANresetCmd);
+    cp->Add(&FreeCmd);
+    cp->Add(&RebootCmd);
+
+    can2.attach(can2rcv);
+    can1.attach(can1rcv);
+    can[CH1].can->monitor(false);       // make them active on the network or tx errors result
+    can[CH2].can->monitor(false);
+
+    // This just sends a message every now and again
+    //ticker.attach(&can1send, 1);
+
+    // Do nothing to waste time in here...
+    do {
+        myled = !myled;         // activity indicator
+        
+        wd.Service();           // service the dog
+        cp_state = cp->Run();   // user interactions on the console interface
+
+        while (inQueue.QueueCount()) {  // If we handle messages badly, could watchdog in here
+            CANmsg msg;
+
+            if (inQueue.Dequeue(&msg)) {
+                char buf[100];
+                msg.FormatCANMessage(buf, sizeof(buf));
+                pc.printf("%s\r\n", buf);
+                // To test, just enable the following, which tosses the ball back and forth
+                //wait(0.2);
+                //msg.dir = xmt;      // What we received, we reflect back
+                //CANTransmitMsg(msg);
+            }
+        }
+    } while (cp_state == runok);
+    cp->End();
+    return 0;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CommandProcessor.lib	Mon Apr 11 11:32:05 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/WiredHome/code/CommandProcessor/#41046d2fd8e7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/VStudioCompat.lib	Mon Apr 11 11:32:05 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/WiredHome/libraries/VStudioCompat/lpfk6g
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Watchdog.lib	Mon Apr 11 11:32:05 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/WiredHome/code/Watchdog/#5a1ff72b5915
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Mon Apr 11 11:32:05 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/63bcd7ba4912