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 ;)
Revision 6:32592425aa57, committed 2013-04-03
- Comitter:
- foxdie
- Date:
- Wed Apr 03 16:09:10 2013 +0000
- Parent:
- 5:d0b067be6d44
- Child:
- 7:5ec65e6e8095
- Commit message:
- Added wrapper for 11-bit requests
Changed in this revision
--- a/GMLAN.cpp Tue Mar 19 10:03:21 2013 +0000 +++ b/GMLAN.cpp Wed Apr 03 16:09:10 2013 +0000 @@ -75,4 +75,98 @@ return CANMessage(hdr.encode29bit(), datatochars, data.size(), CANData, CANExtended); else return CANMessage(arbitration, datatochars, data.size(), CANData, CANStandard); +} + +GMLAN_11Bit_Request::GMLAN_11Bit_Request(int _id, vector<char> _request) { + id = _id; + request_data = _request; + tx_bytes = rx_bytes = 0; + tx_frame_counter = rx_frame_counter = 1; + const char _fp [8] = {0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA}; + memcpy(frame_padding, _fp, 8); + request_state = GMLAN_STATE_READY_TO_SEND; +} +CANMessage GMLAN_11Bit_Request::getNextFrame(void) { + char datatochars [8]; + memcpy(datatochars, frame_padding, 8); + + if (request_data.size() < 8) { + // Unsegmented frame + datatochars[0] = (GMLAN_PCI_UNSEGMENTED << 4) | (request_data.size() & 0xF); + for (int i = 0; i < request_data.size(); i++) datatochars[i+1] = request_data[i]; + request_state = GMLAN_STATE_AWAITING_REPLY; + } else if (tx_bytes == 0) { + // First segmented frame + datatochars[0] = (GMLAN_PCI_SEGMENTED << 4) | ((request_data.size() >> 8) & 0xF); + datatochars[1] = request_data.size() & 0xFF; + for (int i = 0; i < 6; i++) { + datatochars[i+2] = request_data[i]; + tx_bytes++; + } + request_state = GMLAN_STATE_AWAITING_FC; + } else if (tx_bytes <= request_data.size()) { + // Additional segmented frame with data left to transmit + datatochars[0] = (GMLAN_PCI_ADDITIONAL << 4) | (tx_frame_counter & 0xF); + int old_tx_bytes = tx_bytes; + for (int i = old_tx_bytes; i < old_tx_bytes + 7; i++) { + if (i >= request_data.size()) break; + datatochars[(i+1)-old_tx_bytes] = request_data[i]; + tx_bytes++; + } + tx_frame_counter++; + if (tx_frame_counter > 0xF) tx_frame_counter = 0x0; + } + + if (tx_bytes >= request_data.size()) request_state = GMLAN_STATE_AWAITING_REPLY; + + return CANMessage(id, datatochars, 8, CANData, CANStandard); +} +CANMessage GMLAN_11Bit_Request::getFlowControl(void) { + request_state = GMLAN_STATE_AWAITING_REPLY; + GMLAN_Message buffer = GMLAN_Message(0x0, id, 0x0, 0x30, 0x0, 0x0); + return buffer.generate(); +} +void GMLAN_11Bit_Request::processFrame(CANMessage msg) { + if (((msg.id & 0xFF) == (id & 0xFF)) && (request_state == GMLAN_STATE_AWAITING_REPLY)) { + // Only handle requests we've instigated + char datatochars [8]; + memcpy(datatochars, msg.data, 8); + + if (((datatochars[0] >> 4) & 0xF) == GMLAN_PCI_UNSEGMENTED) { + // Unsegmented frame + rx_bytes = datatochars[0] & 0xF; + if (datatochars[1] == GMLAN_SID_ERROR) { + // Error frame + if ((rx_bytes == 3) && (datatochars[3] == 0x78)) return; // "Still processing request" message, ignore this one + request_state = GMLAN_STATE_ERROR; + } else request_state = GMLAN_STATE_COMPLETED; + for (int i = 1; i < (rx_bytes+1); i++) response_data.push_back(datatochars[i]); + } else if (((datatochars[0] >> 4) & 0xF) == GMLAN_PCI_SEGMENTED) { + // First segmented frame + rx_bytes = datatochars[0] & 0xF; + rx_bytes = (rx_bytes << 8) | datatochars[1]; + for (int i = 2; i < 8; i++) { + if ((i - 2) >= rx_bytes) { + // Safety net for incorrectly formatted packets + request_state = GMLAN_STATE_COMPLETED; + return; + } + response_data.push_back(datatochars[i]); + } + request_state = GMLAN_STATE_SEND_FC; + } else if (((datatochars[0] >> 4) & 0xF) == GMLAN_PCI_ADDITIONAL) { + // Additional segmented frame + // TODO check for frame order + for (int i = 1; i < 8; i++) { + if (response_data.size() + 1 >= rx_bytes) { + request_state = GMLAN_STATE_COMPLETED; + return; + } + response_data.push_back(datatochars[i]); + } + } else if (((datatochars[0] >> 4) & 0xF) == GMLAN_PCI_FLOW_CONTROL) { + // Flow control frame + request_state = GMLAN_STATE_SEND_DATA; + } + } } \ No newline at end of file
--- a/GMLAN.h Tue Mar 19 10:03:21 2013 +0000 +++ b/GMLAN.h Wed Apr 03 16:09:10 2013 +0000 @@ -96,4 +96,38 @@ CANMessage generate(void); }; +class GMLAN_11Bit_Request { + /* + Class to allow easier handling of sending and receiving 11-bit messages + */ + private: + vector<char> request_data, response_data; + int id, request_state; + int tx_frame_counter, tx_bytes; + int rx_frame_counter, rx_bytes; + + char frame_padding [8]; + + public: + // (Main function) Create message and send it + GMLAN_11Bit_Request(int _id, vector<char> _request); + + // Process each frame to transmit and flow control frame if needed + CANMessage getNextFrame(void); + CANMessage getFlowControl(void); + // Process each received frame + void processFrame(CANMessage msg); + + // Handle starting and flow control + void start(void) { request_state = GMLAN_STATE_SEND_DATA; } + void continueFlow(void) { request_state = GMLAN_STATE_SEND_DATA; } + + // Return request_state to confirm status + int getState(void) { return request_state; } + // Return ID + int getID(void) { return id; } + // Return response + vector<char> getResponse(void) { return response_data; } +}; + #endif \ No newline at end of file
--- a/GMLAN_11bit.h Tue Mar 19 10:03:21 2013 +0000 +++ b/GMLAN_11bit.h Wed Apr 03 16:09:10 2013 +0000 @@ -19,6 +19,7 @@ #ifndef GMLAN_11BIT_H #define GMLAN_11BIT_H +// CAN IDs #define GMLAN_INITIAL_WAKE_UP_REQUEST 0x100 #define GMLAN_REQUEST_TO_ALL_NODES 0x101 #define GMLAN_DIAGNOSTIC_REQUEST 0x102 @@ -49,4 +50,42 @@ #define GMLAN_ECM_TO_EXTERNAL_OBD_TEST_EQUIPMENT 0x7E8 #define GMLAN_SPECIFIC_OBD_COMPLIANT_ECU_TO_EXTERNAL_OBD_TEST_EQUIPMENT 0x7E9 +// PCI byte +#define GMLAN_PCI_UNSEGMENTED 0x0 +#define GMLAN_PCI_SEGMENTED 0x1 +#define GMLAN_PCI_ADDITIONAL 0x2 +#define GMLAN_PCI_FLOW_CONTROL 0x3 + +// Service ID byte +#define GMLAN_SID_CLEAR_DTC 0x4 +#define GMLAN_SID_START_DIAG 0x10 +#define GMLAN_SID_REQ_FAIL_RECS 0x12 +#define GMLAN_SID_REQ_DID 0x1A +#define GMLAN_SID_RES_NORM_OP 0x20 +#define GMLAN_SID_REQ_PID 0x22 +#define GMLAN_SID_READ_ADDR 0x23 +#define GMLAN_SID_REQ_SEC_ACCESS 0x27 +#define GMLAN_SID_DSBL_NORM_OP 0x28 +#define GMLAN_SID_DEF_DPID_MSG 0x2C +#define GMLAN_SID_DEF_PID_BY_ADDR 0x2D +#define GMLAN_SID_DL_REQ 0x34 +#define GMLAN_SID_DATA_TRANS 0x36 +#define GMLAN_SID_WRITE_DID 0x3B +#define GMLAN_SID_TESTER_PRESENT 0x3E +#define GMLAN_SID_ERROR 0x7F +#define GMLAN_SID_REQ_PROG_STATE 0xA2 +#define GMLAN_SID_PROG_MODE 0xA5 +#define GMLAN_SID_READ_DTC 0xA9 +#define GMLAN_SID_REQ_DPID 0xAA +#define GMLAN_SID_REQ_CONTROL 0xAE + +// States of request +#define GMLAN_STATE_READY_TO_SEND 0x0 +#define GMLAN_STATE_SEND_DATA 0x1 +#define GMLAN_STATE_AWAITING_FC 0x2 +#define GMLAN_STATE_AWAITING_REPLY 0x3 +#define GMLAN_STATE_SEND_FC 0x4 +#define GMLAN_STATE_COMPLETED 0x5 +#define GMLAN_STATE_ERROR 0x6 + #endif \ No newline at end of file