A working demonstration on how to read GMLAN packets using an mbed and a compatible CAN transceiver such as (and tested with) the CAN-Bus demo board. The SparkFun CAN Shield should also work perfectly too, as should just about every MCP2551-based solution (but this code should be portable to other transceivers). Please note to get this to work, you must tie CAN_L to ground and connect CAN_H to the single wire CAN.

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 #include "mbed.h"
00002 #include <vector>
00003 #include <algorithm>
00004 
00005 DigitalOut rx_led(LED1);
00006 DigitalOut filter_led(LED4);
00007 Serial pc(USBTX, USBRX);
00008 CAN gmlan(p30, p29);
00009 Timer uptime;
00010 bool filterPackets = false;
00011 vector<int> filteredPackets;
00012 extern "C" void mbed_reset();
00013 
00014 namespace mbed {
00015     class CANHeader {
00016         // Example header packet for Steering Wheel Switches:
00017         // Hexadecimal:    0x10     0x0D     0x00     0x60
00018         // Binary:       00010000 00001101 00000000 01100000
00019         // Priority:        ---
00020         // Arbitration:        -- -------- ---
00021         // Sending ECU:                       ----- --------
00022 
00023         private:
00024             int priorityID, arbitrationID, senderID;
00025         
00026         public:
00027             int priority(void) { return priorityID; }
00028             void priority(int _priority) { priorityID = _priority; }
00029             int arbitration(void) { return arbitrationID; }
00030             void arbitration(int _arbitration) { arbitrationID = _arbitration; }
00031             int sender(void) { return senderID; }
00032             void sender(int _sender) { senderID = _sender; }
00033             
00034             void decode(int _header) {
00035                 priorityID = (_header >> 26) & 0x7;
00036                 arbitrationID = (_header >> 13) & 0x1FFF;
00037                 senderID = (_header >> 0)  & 0x1FFF;
00038             }
00039             int encode(void) {
00040                 long int buffer = 0;
00041                 buffer = (buffer << 3) | 0x0; // 3 bit padding
00042                 buffer = (buffer << 3) | priorityID;
00043                 buffer = (buffer << 13) | arbitrationID;
00044                 buffer = (buffer << 13) | senderID;
00045                 return buffer;
00046             }
00047     };
00048 }
00049 
00050 void processMessage()
00051 {
00052     // Turn on rx_led to indicate we are receiving data
00053     rx_led = 1;
00054     
00055     // Create a CANMessage object and read the buffer into it
00056     CANMessage rxmsg;
00057     gmlan.read(rxmsg);
00058     
00059     // Check to see if our header is in the filtered packet list or we are filtering, if so we skip over
00060     bool packetFound = false;
00061     if (find(filteredPackets.begin(), filteredPackets.end(), rxmsg.id) != filteredPackets.end())
00062         packetFound = true;
00063         
00064     // If we are filtering packets and this one isn't found, add it to the list
00065     if (filterPackets == true && packetFound == false)
00066     {
00067         filteredPackets.push_back(rxmsg.id);
00068         pc.printf("Added 0x%08X to filter at position %u\r\n", rxmsg.id, filteredPackets.size());
00069     }
00070     else if (filterPackets == false && packetFound == false) {
00071         CANHeader rxHeader;
00072         rxHeader.decode(rxmsg.id);
00073         
00074         // Print these results to the serial terminal using printf to format
00075         // Ref: http://www.cplusplus.com/reference/cstdio/printf/
00076         pc.printf("[%10.2f] ", uptime.read());            // Seconds (to 2 decimal places) since start
00077         pc.printf("[0x%1X] ", rxHeader.priority());       // Packet priority (0-7, 0 being highest)
00078         pc.printf("[0x%4X] ", rxHeader.arbitration());    // Arbitration ID (0x0 to 0x1FFF)
00079         pc.printf("[0x%4X] ", rxHeader.sender());         // ECU ID (0x0 to 0x1FFF)
00080         pc.printf("[0x%08X] ", rxmsg.id);                 // Full header for legacy reasons (4 bytes)
00081         pc.printf("[%d] ", rxmsg.len);                    // Length of message (0-8 bytes typically)
00082         
00083         // Process actual message here, only run this if we have a message
00084         if (rxmsg.len > 0)
00085         {
00086             pc.printf("[%02X", rxmsg.data[0]);  // Print first byte
00087             for (unsigned int i = 1; i < rxmsg.len; i++)
00088             pc.printf(" %02X", rxmsg.data[i]);  // Print additional byte(s) with a preceeding space
00089             pc.printf("]");                     // Print closing bracket
00090         }
00091         pc.printf("\r\n");                      // Print carriage return and newline
00092     }
00093         
00094     // Turn off our rx_led as we have finished reading data
00095     rx_led = 0;
00096 }
00097 
00098 void clearAndHome()
00099 {
00100     pc.printf("%c", 27);    // ESC
00101     pc.printf("[2J");       // clear screen
00102     pc.printf("%c", 27);    // ESC
00103     pc.printf("[H");        // cursor to home
00104 }
00105 
00106 int main() {
00107     // Set serial baud rate to 115kbit
00108     pc.baud(115200);
00109     
00110     // Set CANBUS to 33.3kbit and put into monitor mode (does not ACK packets, aka stealth mode)
00111     int baudrate = 33333;
00112     gmlan.frequency(baudrate);
00113     gmlan.monitor(true);
00114     
00115     // Clear serial terminal
00116     clearAndHome();
00117     pc.printf("Keys:\r\nF = start/stop filter capture\r\nD = display filtered headers\r\nC = clear filter\r\nR = restart mbed\r\n");
00118     pc.printf("Starting packet capture at %i bps\r\n\r\n", baudrate);
00119     
00120     // Start capturing packets
00121     uptime.start();
00122     gmlan.attach(&processMessage);
00123     
00124     while(1) {
00125         // Poll serial for keypresses for certain tasks
00126         if (pc.readable())
00127         {
00128             switch (pc.getc())
00129             {
00130                 case 'f':
00131                 case 'F':
00132                 {
00133                     // Toggle filter
00134                     filterPackets = !filterPackets;
00135                     filter_led = (int)filterPackets;
00136                     break;
00137                 }
00138                 case 'c':
00139                 case 'C':
00140                 {
00141                     // Clear filter
00142                     filteredPackets.clear();
00143                     pc.printf("Packet filter cleared\r\n");
00144                     break;
00145                 }
00146                 case 'd':
00147                 case 'D':
00148                 {
00149                     // Show filter
00150                     clearAndHome();
00151                     pc.printf("[%u] entries in filter:\r\n", filteredPackets.size());
00152                     for (int i=0; i < filteredPackets.size(); i++)
00153                         pc.printf("%u: 0x%08X ", i+1, filteredPackets[i]);
00154                     pc.printf("\r\n");
00155                     break;
00156                 }
00157                 case 'r':
00158                 case 'R':
00159                 {
00160                     // Restart mbed
00161                     pc.printf("Restarting mbed...\r\n");
00162                     mbed_reset();
00163                     break;
00164                 }
00165                 default:
00166                     pc.printf("Unknown keypress!\r\n");
00167                     break;
00168             }
00169         }       
00170         // Sleep for 20ms repeatedly, as all messages are handled by an interrupt, this prevents
00171         // keeping the mbed at full load
00172         wait(0.02);
00173     }
00174 }