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:
Wed Apr 03 16:09:10 2013 +0000
Revision:
6:32592425aa57
Parent:
5:d0b067be6d44
Child:
7:5ec65e6e8095
Added wrapper for 11-bit requests

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 6:32592425aa57 80 GMLAN_11Bit_Request::GMLAN_11Bit_Request(int _id, vector<char> _request) {
foxdie 6:32592425aa57 81 id = _id;
foxdie 6:32592425aa57 82 request_data = _request;
foxdie 6:32592425aa57 83 tx_bytes = rx_bytes = 0;
foxdie 6:32592425aa57 84 tx_frame_counter = rx_frame_counter = 1;
foxdie 6:32592425aa57 85 const char _fp [8] = {0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA};
foxdie 6:32592425aa57 86 memcpy(frame_padding, _fp, 8);
foxdie 6:32592425aa57 87 request_state = GMLAN_STATE_READY_TO_SEND;
foxdie 6:32592425aa57 88 }
foxdie 6:32592425aa57 89 CANMessage GMLAN_11Bit_Request::getNextFrame(void) {
foxdie 6:32592425aa57 90 char datatochars [8];
foxdie 6:32592425aa57 91 memcpy(datatochars, frame_padding, 8);
foxdie 6:32592425aa57 92
foxdie 6:32592425aa57 93 if (request_data.size() < 8) {
foxdie 6:32592425aa57 94 // Unsegmented frame
foxdie 6:32592425aa57 95 datatochars[0] = (GMLAN_PCI_UNSEGMENTED << 4) | (request_data.size() & 0xF);
foxdie 6:32592425aa57 96 for (int i = 0; i < request_data.size(); i++) datatochars[i+1] = request_data[i];
foxdie 6:32592425aa57 97 request_state = GMLAN_STATE_AWAITING_REPLY;
foxdie 6:32592425aa57 98 } else if (tx_bytes == 0) {
foxdie 6:32592425aa57 99 // First segmented frame
foxdie 6:32592425aa57 100 datatochars[0] = (GMLAN_PCI_SEGMENTED << 4) | ((request_data.size() >> 8) & 0xF);
foxdie 6:32592425aa57 101 datatochars[1] = request_data.size() & 0xFF;
foxdie 6:32592425aa57 102 for (int i = 0; i < 6; i++) {
foxdie 6:32592425aa57 103 datatochars[i+2] = request_data[i];
foxdie 6:32592425aa57 104 tx_bytes++;
foxdie 6:32592425aa57 105 }
foxdie 6:32592425aa57 106 request_state = GMLAN_STATE_AWAITING_FC;
foxdie 6:32592425aa57 107 } else if (tx_bytes <= request_data.size()) {
foxdie 6:32592425aa57 108 // Additional segmented frame with data left to transmit
foxdie 6:32592425aa57 109 datatochars[0] = (GMLAN_PCI_ADDITIONAL << 4) | (tx_frame_counter & 0xF);
foxdie 6:32592425aa57 110 int old_tx_bytes = tx_bytes;
foxdie 6:32592425aa57 111 for (int i = old_tx_bytes; i < old_tx_bytes + 7; i++) {
foxdie 6:32592425aa57 112 if (i >= request_data.size()) break;
foxdie 6:32592425aa57 113 datatochars[(i+1)-old_tx_bytes] = request_data[i];
foxdie 6:32592425aa57 114 tx_bytes++;
foxdie 6:32592425aa57 115 }
foxdie 6:32592425aa57 116 tx_frame_counter++;
foxdie 6:32592425aa57 117 if (tx_frame_counter > 0xF) tx_frame_counter = 0x0;
foxdie 6:32592425aa57 118 }
foxdie 6:32592425aa57 119
foxdie 6:32592425aa57 120 if (tx_bytes >= request_data.size()) request_state = GMLAN_STATE_AWAITING_REPLY;
foxdie 6:32592425aa57 121
foxdie 6:32592425aa57 122 return CANMessage(id, datatochars, 8, CANData, CANStandard);
foxdie 6:32592425aa57 123 }
foxdie 6:32592425aa57 124 CANMessage GMLAN_11Bit_Request::getFlowControl(void) {
foxdie 6:32592425aa57 125 request_state = GMLAN_STATE_AWAITING_REPLY;
foxdie 6:32592425aa57 126 GMLAN_Message buffer = GMLAN_Message(0x0, id, 0x0, 0x30, 0x0, 0x0);
foxdie 6:32592425aa57 127 return buffer.generate();
foxdie 6:32592425aa57 128 }
foxdie 6:32592425aa57 129 void GMLAN_11Bit_Request::processFrame(CANMessage msg) {
foxdie 6:32592425aa57 130 if (((msg.id & 0xFF) == (id & 0xFF)) && (request_state == GMLAN_STATE_AWAITING_REPLY)) {
foxdie 6:32592425aa57 131 // Only handle requests we've instigated
foxdie 6:32592425aa57 132 char datatochars [8];
foxdie 6:32592425aa57 133 memcpy(datatochars, msg.data, 8);
foxdie 6:32592425aa57 134
foxdie 6:32592425aa57 135 if (((datatochars[0] >> 4) & 0xF) == GMLAN_PCI_UNSEGMENTED) {
foxdie 6:32592425aa57 136 // Unsegmented frame
foxdie 6:32592425aa57 137 rx_bytes = datatochars[0] & 0xF;
foxdie 6:32592425aa57 138 if (datatochars[1] == GMLAN_SID_ERROR) {
foxdie 6:32592425aa57 139 // Error frame
foxdie 6:32592425aa57 140 if ((rx_bytes == 3) && (datatochars[3] == 0x78)) return; // "Still processing request" message, ignore this one
foxdie 6:32592425aa57 141 request_state = GMLAN_STATE_ERROR;
foxdie 6:32592425aa57 142 } else request_state = GMLAN_STATE_COMPLETED;
foxdie 6:32592425aa57 143 for (int i = 1; i < (rx_bytes+1); i++) response_data.push_back(datatochars[i]);
foxdie 6:32592425aa57 144 } else if (((datatochars[0] >> 4) & 0xF) == GMLAN_PCI_SEGMENTED) {
foxdie 6:32592425aa57 145 // First segmented frame
foxdie 6:32592425aa57 146 rx_bytes = datatochars[0] & 0xF;
foxdie 6:32592425aa57 147 rx_bytes = (rx_bytes << 8) | datatochars[1];
foxdie 6:32592425aa57 148 for (int i = 2; i < 8; i++) {
foxdie 6:32592425aa57 149 if ((i - 2) >= rx_bytes) {
foxdie 6:32592425aa57 150 // Safety net for incorrectly formatted packets
foxdie 6:32592425aa57 151 request_state = GMLAN_STATE_COMPLETED;
foxdie 6:32592425aa57 152 return;
foxdie 6:32592425aa57 153 }
foxdie 6:32592425aa57 154 response_data.push_back(datatochars[i]);
foxdie 6:32592425aa57 155 }
foxdie 6:32592425aa57 156 request_state = GMLAN_STATE_SEND_FC;
foxdie 6:32592425aa57 157 } else if (((datatochars[0] >> 4) & 0xF) == GMLAN_PCI_ADDITIONAL) {
foxdie 6:32592425aa57 158 // Additional segmented frame
foxdie 6:32592425aa57 159 // TODO check for frame order
foxdie 6:32592425aa57 160 for (int i = 1; i < 8; i++) {
foxdie 6:32592425aa57 161 if (response_data.size() + 1 >= rx_bytes) {
foxdie 6:32592425aa57 162 request_state = GMLAN_STATE_COMPLETED;
foxdie 6:32592425aa57 163 return;
foxdie 6:32592425aa57 164 }
foxdie 6:32592425aa57 165 response_data.push_back(datatochars[i]);
foxdie 6:32592425aa57 166 }
foxdie 6:32592425aa57 167 } else if (((datatochars[0] >> 4) & 0xF) == GMLAN_PCI_FLOW_CONTROL) {
foxdie 6:32592425aa57 168 // Flow control frame
foxdie 6:32592425aa57 169 request_state = GMLAN_STATE_SEND_DATA;
foxdie 6:32592425aa57 170 }
foxdie 6:32592425aa57 171 }
foxdie 0:9266fbfbef88 172 }