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 ;)

Committer:
foxdie
Date:
Mon Apr 08 11:31:12 2013 +0000
Revision:
9:4af02032daeb
Parent:
8:bc97fa5d306e
Fixed bug where transmission of multi-frame messages wasn't recognising flow control to continue resulting in code waiting around doing nada

Who changed what in which revision?

UserRevisionLine numberNew contents of line
foxdie 0:9266fbfbef88 1 /*
foxdie 0:9266fbfbef88 2 GMLAN.cpp - Source file for GMLAN Library
foxdie 0:9266fbfbef88 3
foxdie 0:9266fbfbef88 4 GMLAN is a Controller Area Network Bus used in General Motors vehicles from
foxdie 0:9266fbfbef88 5 roughly 2007-onwards. Its purpose is to allow various Electronic Control Units
foxdie 0:9266fbfbef88 6 (aka ECUs) within a modern vehicle to share information and enact procedures.
foxdie 0:9266fbfbef88 7
foxdie 0:9266fbfbef88 8 An example of this would be communication between the HU (Head unit) and the
foxdie 0:9266fbfbef88 9 DIC (Dashboard Information Cluster), when you adjust the volume up / down, this
foxdie 0:9266fbfbef88 10 is reported to the cluster to be displayed.
foxdie 0:9266fbfbef88 11
foxdie 0:9266fbfbef88 12 It is the function of this library to "crack open" this world to allow anyone
foxdie 0:9266fbfbef88 13 with only as little as a few hours of C++ programming under their belt to get
foxdie 0:9266fbfbef88 14 started in what can sometimes seem a daunting world.
foxdie 0:9266fbfbef88 15
foxdie 0:9266fbfbef88 16 Jason Gaunt, 18th Feb 2013
foxdie 0:9266fbfbef88 17 */
foxdie 0:9266fbfbef88 18
foxdie 5:d0b067be6d44 19 #include "mbed.h"
foxdie 0:9266fbfbef88 20 #include "GMLAN.h"
foxdie 5:d0b067be6d44 21 #include <vector>
foxdie 0:9266fbfbef88 22
foxdie 0:9266fbfbef88 23 void CANHeader::decode(int _header) {
foxdie 3:09fdfec053cd 24 if (_header < 0x800)
foxdie 3:09fdfec053cd 25 {
foxdie 3:09fdfec053cd 26 // 11-bit header
foxdie 4:486fec88517e 27 arbitrationID = (_header >> 0) & 0x7FF;
foxdie 3:09fdfec053cd 28 } else {
foxdie 3:09fdfec053cd 29 // 29-bit header
foxdie 3:09fdfec053cd 30 priorityID = (_header >> 26) & 0x7;
foxdie 3:09fdfec053cd 31 arbitrationID = (_header >> 13) & 0x1FFF;
foxdie 3:09fdfec053cd 32 senderID = (_header >> 0) & 0x1FFF;
foxdie 3:09fdfec053cd 33 }
foxdie 0:9266fbfbef88 34 }
foxdie 3:09fdfec053cd 35 int CANHeader::encode29bit(void) {
foxdie 0:9266fbfbef88 36 long int buffer = 0;
foxdie 0:9266fbfbef88 37 buffer = (buffer << 3) | 0x0; // 3 bit padding
foxdie 0:9266fbfbef88 38 buffer = (buffer << 3) | priorityID;
foxdie 0:9266fbfbef88 39 buffer = (buffer << 13) | arbitrationID;
foxdie 0:9266fbfbef88 40 buffer = (buffer << 13) | senderID;
foxdie 0:9266fbfbef88 41 return buffer;
foxdie 4:486fec88517e 42 }
foxdie 4:486fec88517e 43 int CANHeader::encode11bit(void) {
foxdie 4:486fec88517e 44 short int buffer = 0;
foxdie 4:486fec88517e 45 buffer = (buffer << 5) | 0x0; // 5 bit padding
foxdie 4:486fec88517e 46 buffer = (buffer << 11) | arbitrationID;
foxdie 4:486fec88517e 47 return buffer;
foxdie 5:d0b067be6d44 48 }
foxdie 5:d0b067be6d44 49
foxdie 5:d0b067be6d44 50
foxdie 5:d0b067be6d44 51 GMLAN_Message::GMLAN_Message(int _priority, int _arbitration, int _sender,
foxdie 5:d0b067be6d44 52 int _b0, int _b1, int _b2, int _b3, int _b4, int _b5, int _b6, int _b7) {
foxdie 5:d0b067be6d44 53 priority = _priority;
foxdie 5:d0b067be6d44 54 arbitration = _arbitration;
foxdie 5:d0b067be6d44 55 sender = _sender;
foxdie 5:d0b067be6d44 56 if (_b0 != -1) data.push_back(_b0);
foxdie 5:d0b067be6d44 57 if (_b1 != -1) data.push_back(_b1);
foxdie 5:d0b067be6d44 58 if (_b2 != -1) data.push_back(_b2);
foxdie 5:d0b067be6d44 59 if (_b3 != -1) data.push_back(_b3);
foxdie 5:d0b067be6d44 60 if (_b4 != -1) data.push_back(_b4);
foxdie 5:d0b067be6d44 61 if (_b5 != -1) data.push_back(_b5);
foxdie 5:d0b067be6d44 62 if (_b6 != -1) data.push_back(_b6);
foxdie 5:d0b067be6d44 63 if (_b7 != -1) data.push_back(_b7);
foxdie 5:d0b067be6d44 64 }
foxdie 5:d0b067be6d44 65 CANMessage GMLAN_Message::generate(void) {
foxdie 5:d0b067be6d44 66 CANHeader hdr;
foxdie 5:d0b067be6d44 67 hdr.priority(priority);
foxdie 5:d0b067be6d44 68 hdr.arbitration(arbitration);
foxdie 5:d0b067be6d44 69 hdr.sender(sender);
foxdie 5:d0b067be6d44 70
foxdie 5:d0b067be6d44 71 char datatochars [data.size()];
foxdie 5:d0b067be6d44 72 for (int i = 0; i < data.size(); i++) datatochars[i] = data[i];
foxdie 5:d0b067be6d44 73
foxdie 5:d0b067be6d44 74 if (sender > 0x0)
foxdie 5:d0b067be6d44 75 return CANMessage(hdr.encode29bit(), datatochars, data.size(), CANData, CANExtended);
foxdie 5:d0b067be6d44 76 else
foxdie 5:d0b067be6d44 77 return CANMessage(arbitration, datatochars, data.size(), CANData, CANStandard);
foxdie 6:32592425aa57 78 }
foxdie 6:32592425aa57 79
foxdie 8:bc97fa5d306e 80 GMLAN_11Bit_Request::GMLAN_11Bit_Request(int _id, vector<char> _request, bool _await_response, bool _handle_flowcontrol) {
foxdie 6:32592425aa57 81 id = _id;
foxdie 6:32592425aa57 82 request_data = _request;
foxdie 7:5ec65e6e8095 83 await_response = _await_response;
foxdie 8:bc97fa5d306e 84 handle_flowcontrol = _handle_flowcontrol;
foxdie 6:32592425aa57 85 tx_bytes = rx_bytes = 0;
foxdie 6:32592425aa57 86 tx_frame_counter = rx_frame_counter = 1;
foxdie 6:32592425aa57 87 const char _fp [8] = {0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA};
foxdie 6:32592425aa57 88 memcpy(frame_padding, _fp, 8);
foxdie 6:32592425aa57 89 request_state = GMLAN_STATE_READY_TO_SEND;
foxdie 6:32592425aa57 90 }
foxdie 6:32592425aa57 91 CANMessage GMLAN_11Bit_Request::getNextFrame(void) {
foxdie 6:32592425aa57 92 char datatochars [8];
foxdie 6:32592425aa57 93 memcpy(datatochars, frame_padding, 8);
foxdie 8:bc97fa5d306e 94
foxdie 8:bc97fa5d306e 95 if (handle_flowcontrol == true) {
foxdie 8:bc97fa5d306e 96 // Only run this section if we need flow control
foxdie 8:bc97fa5d306e 97 if (request_data.size() < 8) {
foxdie 8:bc97fa5d306e 98 // Unsegmented frame
foxdie 8:bc97fa5d306e 99 datatochars[0] = (GMLAN_PCI_UNSEGMENTED << 4) | (request_data.size() & 0xF);
foxdie 8:bc97fa5d306e 100 for (int i = 0; i < request_data.size(); i++) {
foxdie 8:bc97fa5d306e 101 datatochars[i+1] = request_data[i];
foxdie 8:bc97fa5d306e 102 tx_bytes++;
foxdie 8:bc97fa5d306e 103 }
foxdie 8:bc97fa5d306e 104 request_state = GMLAN_STATE_AWAITING_REPLY;
foxdie 8:bc97fa5d306e 105 } else if (tx_bytes == 0) {
foxdie 8:bc97fa5d306e 106 // First segmented frame
foxdie 8:bc97fa5d306e 107 datatochars[0] = (GMLAN_PCI_SEGMENTED << 4) | ((request_data.size() >> 8) & 0xF);
foxdie 8:bc97fa5d306e 108 datatochars[1] = request_data.size() & 0xFF;
foxdie 8:bc97fa5d306e 109 for (int i = 0; i < 6; i++) {
foxdie 8:bc97fa5d306e 110 datatochars[i+2] = request_data[i];
foxdie 8:bc97fa5d306e 111 tx_bytes++;
foxdie 8:bc97fa5d306e 112 }
foxdie 8:bc97fa5d306e 113 request_state = GMLAN_STATE_AWAITING_FC;
foxdie 8:bc97fa5d306e 114 } else if (tx_bytes <= request_data.size()) {
foxdie 8:bc97fa5d306e 115 // Additional segmented frame with data left to transmit
foxdie 8:bc97fa5d306e 116 datatochars[0] = (GMLAN_PCI_ADDITIONAL << 4) | (tx_frame_counter & 0xF);
foxdie 8:bc97fa5d306e 117 int old_tx_bytes = tx_bytes;
foxdie 8:bc97fa5d306e 118 for (int i = old_tx_bytes; i < old_tx_bytes + 7; i++) {
foxdie 8:bc97fa5d306e 119 if (i >= request_data.size()) break;
foxdie 8:bc97fa5d306e 120 datatochars[(i+1)-old_tx_bytes] = request_data[i];
foxdie 8:bc97fa5d306e 121 tx_bytes++;
foxdie 8:bc97fa5d306e 122 }
foxdie 8:bc97fa5d306e 123 tx_frame_counter++;
foxdie 8:bc97fa5d306e 124 if (tx_frame_counter > 0xF) tx_frame_counter = 0x0;
foxdie 6:32592425aa57 125 }
foxdie 8:bc97fa5d306e 126 if (tx_bytes >= request_data.size()) {
foxdie 8:bc97fa5d306e 127 if (await_response == true) request_state = GMLAN_STATE_AWAITING_REPLY;
foxdie 8:bc97fa5d306e 128 else request_state = GMLAN_STATE_COMPLETED;
foxdie 6:32592425aa57 129 }
foxdie 8:bc97fa5d306e 130 } else {
foxdie 8:bc97fa5d306e 131 // No flow control required, build the frames without parsing but make sure we don't overshoot 8 bytes
foxdie 8:bc97fa5d306e 132 for (int i = 0; i < request_data.size(); i++) {
foxdie 8:bc97fa5d306e 133 if (i < 8) {
foxdie 8:bc97fa5d306e 134 datatochars[i] = request_data[i];
foxdie 8:bc97fa5d306e 135 tx_bytes++;
foxdie 8:bc97fa5d306e 136 }
foxdie 8:bc97fa5d306e 137 else break;
foxdie 8:bc97fa5d306e 138 }
foxdie 7:5ec65e6e8095 139 if (await_response == true) request_state = GMLAN_STATE_AWAITING_REPLY;
foxdie 7:5ec65e6e8095 140 else request_state = GMLAN_STATE_COMPLETED;
foxdie 7:5ec65e6e8095 141 }
foxdie 6:32592425aa57 142
foxdie 6:32592425aa57 143 return CANMessage(id, datatochars, 8, CANData, CANStandard);
foxdie 6:32592425aa57 144 }
foxdie 6:32592425aa57 145 CANMessage GMLAN_11Bit_Request::getFlowControl(void) {
foxdie 6:32592425aa57 146 request_state = GMLAN_STATE_AWAITING_REPLY;
foxdie 6:32592425aa57 147 GMLAN_Message buffer = GMLAN_Message(0x0, id, 0x0, 0x30, 0x0, 0x0);
foxdie 6:32592425aa57 148 return buffer.generate();
foxdie 6:32592425aa57 149 }
foxdie 6:32592425aa57 150 void GMLAN_11Bit_Request::processFrame(CANMessage msg) {
foxdie 9:4af02032daeb 151 if (((msg.id & 0xFF) == (id & 0xFF)) &&
foxdie 9:4af02032daeb 152 ((request_state == GMLAN_STATE_AWAITING_REPLY) || (request_state == GMLAN_STATE_AWAITING_FC))
foxdie 9:4af02032daeb 153 ) {
foxdie 6:32592425aa57 154 // Only handle requests we've instigated
foxdie 6:32592425aa57 155 char datatochars [8];
foxdie 6:32592425aa57 156 memcpy(datatochars, msg.data, 8);
foxdie 6:32592425aa57 157
foxdie 6:32592425aa57 158 if (((datatochars[0] >> 4) & 0xF) == GMLAN_PCI_UNSEGMENTED) {
foxdie 6:32592425aa57 159 // Unsegmented frame
foxdie 7:5ec65e6e8095 160 rx_bytes = (datatochars[0] & 0xF);
foxdie 6:32592425aa57 161 if (datatochars[1] == GMLAN_SID_ERROR) {
foxdie 6:32592425aa57 162 // Error frame
foxdie 6:32592425aa57 163 if ((rx_bytes == 3) && (datatochars[3] == 0x78)) return; // "Still processing request" message, ignore this one
foxdie 6:32592425aa57 164 request_state = GMLAN_STATE_ERROR;
foxdie 6:32592425aa57 165 } else request_state = GMLAN_STATE_COMPLETED;
foxdie 6:32592425aa57 166 for (int i = 1; i < (rx_bytes+1); i++) response_data.push_back(datatochars[i]);
foxdie 6:32592425aa57 167 } else if (((datatochars[0] >> 4) & 0xF) == GMLAN_PCI_SEGMENTED) {
foxdie 6:32592425aa57 168 // First segmented frame
foxdie 7:5ec65e6e8095 169 rx_bytes = (datatochars[0] & 0xF);
foxdie 6:32592425aa57 170 rx_bytes = (rx_bytes << 8) | datatochars[1];
foxdie 6:32592425aa57 171 for (int i = 2; i < 8; i++) {
foxdie 6:32592425aa57 172 if ((i - 2) >= rx_bytes) {
foxdie 6:32592425aa57 173 // Safety net for incorrectly formatted packets
foxdie 6:32592425aa57 174 request_state = GMLAN_STATE_COMPLETED;
foxdie 6:32592425aa57 175 return;
foxdie 6:32592425aa57 176 }
foxdie 6:32592425aa57 177 response_data.push_back(datatochars[i]);
foxdie 6:32592425aa57 178 }
foxdie 6:32592425aa57 179 request_state = GMLAN_STATE_SEND_FC;
foxdie 6:32592425aa57 180 } else if (((datatochars[0] >> 4) & 0xF) == GMLAN_PCI_ADDITIONAL) {
foxdie 6:32592425aa57 181 // Additional segmented frame
foxdie 6:32592425aa57 182 // TODO check for frame order
foxdie 6:32592425aa57 183 for (int i = 1; i < 8; i++) {
foxdie 7:5ec65e6e8095 184 if (response_data.size() >= rx_bytes) {
foxdie 6:32592425aa57 185 request_state = GMLAN_STATE_COMPLETED;
foxdie 6:32592425aa57 186 return;
foxdie 6:32592425aa57 187 }
foxdie 6:32592425aa57 188 response_data.push_back(datatochars[i]);
foxdie 6:32592425aa57 189 }
foxdie 7:5ec65e6e8095 190 if (response_data.size() >= rx_bytes) {
foxdie 7:5ec65e6e8095 191 request_state = GMLAN_STATE_COMPLETED;
foxdie 7:5ec65e6e8095 192 return;
foxdie 7:5ec65e6e8095 193 }
foxdie 6:32592425aa57 194 } else if (((datatochars[0] >> 4) & 0xF) == GMLAN_PCI_FLOW_CONTROL) {
foxdie 6:32592425aa57 195 // Flow control frame
foxdie 6:32592425aa57 196 request_state = GMLAN_STATE_SEND_DATA;
foxdie 6:32592425aa57 197 }
foxdie 6:32592425aa57 198 }
foxdie 0:9266fbfbef88 199 }