Libraries to support working with GMLAN - General Motors CAN BUS network in most of their vehicles between 2007-present day. Please note this is a work in progress and not guaranteed to be correct, use at your own risk! Read commit logs / subscribe to see what has been added, it's a work in progress after all ;)

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers GMLAN.cpp Source File

GMLAN.cpp

00001 /*
00002 GMLAN.cpp - Source file for GMLAN Library
00003 
00004 GMLAN is a Controller Area Network Bus used in General Motors vehicles from
00005 roughly 2007-onwards. Its purpose is to allow various Electronic Control Units
00006 (aka ECUs) within a modern vehicle to share information and enact procedures.
00007 
00008 An example of this would be communication between the HU (Head unit) and the
00009 DIC (Dashboard Information Cluster), when you adjust the volume up / down, this
00010 is reported to the cluster to be displayed.
00011 
00012 It is the function of this library to "crack open" this world to allow anyone
00013 with only as little as a few hours of C++ programming under their belt to get
00014 started in what can sometimes seem a daunting world.
00015 
00016 Jason Gaunt, 18th Feb 2013
00017 */
00018 
00019 #include "mbed.h"
00020 #include "GMLAN.h"
00021 #include <vector>
00022 
00023 void CANHeader::decode(int _header) {
00024     if (_header < 0x800)
00025     {
00026         // 11-bit header
00027         arbitrationID = (_header >> 0) & 0x7FF;
00028     } else {
00029         // 29-bit header
00030         priorityID = (_header >> 26) & 0x7;
00031         arbitrationID = (_header >> 13) & 0x1FFF;
00032         senderID = (_header >> 0) & 0x1FFF;
00033     }
00034 }
00035 int CANHeader::encode29bit(void) {
00036     long int buffer = 0;
00037     buffer = (buffer << 3) | 0x0; // 3 bit padding
00038     buffer = (buffer << 3) | priorityID;
00039     buffer = (buffer << 13) | arbitrationID;
00040     buffer = (buffer << 13) | senderID;
00041     return buffer;
00042 }
00043 int CANHeader::encode11bit(void) {
00044     short int buffer = 0;
00045     buffer = (buffer << 5) | 0x0; // 5 bit padding
00046     buffer = (buffer << 11) | arbitrationID;
00047     return buffer;
00048 }
00049 
00050     
00051 GMLAN_Message::GMLAN_Message(int _priority, int _arbitration, int _sender,
00052 int _b0, int _b1, int _b2, int _b3, int _b4, int _b5, int _b6, int _b7) {
00053     priority = _priority;
00054     arbitration = _arbitration;
00055     sender = _sender;
00056     if (_b0 != -1) data.push_back(_b0);
00057     if (_b1 != -1) data.push_back(_b1);
00058     if (_b2 != -1) data.push_back(_b2);
00059     if (_b3 != -1) data.push_back(_b3);
00060     if (_b4 != -1) data.push_back(_b4);
00061     if (_b5 != -1) data.push_back(_b5);
00062     if (_b6 != -1) data.push_back(_b6);
00063     if (_b7 != -1) data.push_back(_b7);
00064 }
00065 CANMessage GMLAN_Message::generate(void) {
00066     CANHeader hdr;
00067     hdr.priority(priority);
00068     hdr.arbitration(arbitration);
00069     hdr.sender(sender);
00070     
00071     char datatochars [data.size()];
00072     for (int i = 0; i < data.size(); i++) datatochars[i] = data[i];
00073     
00074     if (sender > 0x0)
00075         return CANMessage(hdr.encode29bit(), datatochars, data.size(), CANData, CANExtended);
00076     else
00077         return CANMessage(arbitration, datatochars, data.size(), CANData, CANStandard);
00078 }
00079 
00080 GMLAN_11Bit_Request::GMLAN_11Bit_Request(int _id, vector<char> _request, bool _await_response, bool _handle_flowcontrol) {
00081     id = _id;
00082     request_data = _request;
00083     await_response = _await_response;
00084     handle_flowcontrol = _handle_flowcontrol;
00085     tx_bytes = rx_bytes = 0;
00086     tx_frame_counter = rx_frame_counter = 1;
00087     const char _fp [8] = {0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA};
00088     memcpy(frame_padding, _fp, 8);
00089     request_state = GMLAN_STATE_READY_TO_SEND;
00090 }
00091 CANMessage GMLAN_11Bit_Request::getNextFrame(void) {
00092     char datatochars [8];
00093     memcpy(datatochars, frame_padding, 8);
00094     
00095     if (handle_flowcontrol == true) {
00096         // Only run this section if we need flow control
00097         if (request_data.size() < 8) {
00098             // Unsegmented frame
00099             datatochars[0] = (GMLAN_PCI_UNSEGMENTED << 4) | (request_data.size() & 0xF);
00100             for (int i = 0; i < request_data.size(); i++) {
00101                 datatochars[i+1] = request_data[i];
00102                 tx_bytes++;
00103             }
00104             request_state = GMLAN_STATE_AWAITING_REPLY;
00105         } else if (tx_bytes == 0) {
00106             // First segmented frame
00107             datatochars[0] = (GMLAN_PCI_SEGMENTED << 4) | ((request_data.size() >> 8) & 0xF);
00108             datatochars[1] = request_data.size() & 0xFF;
00109             for (int i = 0; i < 6; i++) {
00110                 datatochars[i+2] = request_data[i];
00111                 tx_bytes++;
00112             }
00113             request_state = GMLAN_STATE_AWAITING_FC;
00114         } else if (tx_bytes <= request_data.size()) {
00115             // Additional segmented frame with data left to transmit
00116             datatochars[0] = (GMLAN_PCI_ADDITIONAL << 4) | (tx_frame_counter & 0xF);
00117             int old_tx_bytes = tx_bytes;
00118             for (int i = old_tx_bytes; i < old_tx_bytes + 7; i++) {
00119                 if (i >= request_data.size()) break;
00120                 datatochars[(i+1)-old_tx_bytes] = request_data[i];
00121                 tx_bytes++;
00122             }
00123             tx_frame_counter++;
00124             if (tx_frame_counter > 0xF) tx_frame_counter = 0x0;
00125         }
00126         if (tx_bytes >= request_data.size()) {
00127             if (await_response == true) request_state = GMLAN_STATE_AWAITING_REPLY;
00128             else request_state = GMLAN_STATE_COMPLETED;
00129         }
00130     } else {
00131         // No flow control required, build the frames without parsing but make sure we don't overshoot 8 bytes
00132         for (int i = 0; i < request_data.size(); i++) {
00133             if (i < 8) {
00134                 datatochars[i] = request_data[i];
00135                 tx_bytes++;
00136             }
00137             else break;
00138         }
00139         if (await_response == true) request_state = GMLAN_STATE_AWAITING_REPLY;
00140         else request_state = GMLAN_STATE_COMPLETED;
00141     }
00142     
00143     return CANMessage(id, datatochars, 8, CANData, CANStandard);
00144 }
00145 CANMessage GMLAN_11Bit_Request::getFlowControl(void) {
00146     request_state = GMLAN_STATE_AWAITING_REPLY;
00147     GMLAN_Message buffer = GMLAN_Message(0x0, id, 0x0, 0x30, 0x0, 0x0);
00148     return buffer.generate();
00149 }
00150 void GMLAN_11Bit_Request::processFrame(CANMessage msg) {
00151     if (((msg.id & 0xFF) == (id & 0xFF)) && 
00152         ((request_state == GMLAN_STATE_AWAITING_REPLY) || (request_state == GMLAN_STATE_AWAITING_FC))
00153     ) {
00154         // Only handle requests we've instigated
00155         char datatochars [8];
00156         memcpy(datatochars, msg.data, 8);
00157         
00158         if (((datatochars[0] >> 4) & 0xF) == GMLAN_PCI_UNSEGMENTED) {
00159             // Unsegmented frame
00160             rx_bytes = (datatochars[0] & 0xF);
00161             if (datatochars[1] == GMLAN_SID_ERROR) {
00162                 // Error frame
00163                 if ((rx_bytes == 3) && (datatochars[3] == 0x78)) return; // "Still processing request" message, ignore this one
00164                 request_state = GMLAN_STATE_ERROR;
00165             } else request_state = GMLAN_STATE_COMPLETED;
00166             for (int i = 1; i < (rx_bytes+1); i++) response_data.push_back(datatochars[i]);
00167         } else if (((datatochars[0] >> 4) & 0xF) == GMLAN_PCI_SEGMENTED) {
00168             // First segmented frame
00169             rx_bytes = (datatochars[0] & 0xF);
00170             rx_bytes = (rx_bytes << 8) | datatochars[1];
00171             for (int i = 2; i < 8; i++) {
00172                 if ((i - 2) >= rx_bytes) {
00173                     // Safety net for incorrectly formatted packets
00174                     request_state = GMLAN_STATE_COMPLETED;
00175                     return;
00176                 }
00177                 response_data.push_back(datatochars[i]);
00178             }
00179             request_state = GMLAN_STATE_SEND_FC;
00180         } else if (((datatochars[0] >> 4) & 0xF) == GMLAN_PCI_ADDITIONAL) {
00181             // Additional segmented frame
00182             // TODO check for frame order
00183             for (int i = 1; i < 8; i++) {
00184                 if (response_data.size() >= rx_bytes) {
00185                     request_state = GMLAN_STATE_COMPLETED;
00186                     return;
00187                 }
00188                 response_data.push_back(datatochars[i]);
00189             }
00190             if (response_data.size() >= rx_bytes) {
00191                 request_state = GMLAN_STATE_COMPLETED;
00192                 return;
00193             }
00194         } else if (((datatochars[0] >> 4) & 0xF) == GMLAN_PCI_FLOW_CONTROL) {
00195             // Flow control frame
00196             request_state = GMLAN_STATE_SEND_DATA;
00197         }
00198     }
00199 }