diff --git a/SavvyCAN.pro b/SavvyCAN.pro index 481cf8d..ac6e484 100644 --- a/SavvyCAN.pro +++ b/SavvyCAN.pro @@ -50,7 +50,6 @@ SOURCES += main.cpp\ re/flowviewwindow.cpp \ re/frameinfowindow.cpp \ re/fuzzingwindow.cpp \ - re/isotp_handler.cpp \ re/isotp_interpreterwindow.cpp \ re/rangestatewindow.cpp \ re/udsscanwindow.cpp \ diff --git a/bus_protocols/isotp_handler.cpp b/bus_protocols/isotp_handler.cpp index f679213..dde42ba 100644 --- a/bus_protocols/isotp_handler.cpp +++ b/bus_protocols/isotp_handler.cpp @@ -1,124 +1,23 @@ #include "isotp_handler.h" +#include "connections/canconmanager.h" -CODE_STRUCT OBDII_FUNCTS[] = -{ - {1, "UDS_OBDII_SHOW_CURRENT", "OBDII - Show current data"}, - {2, "UDS_OBDII_SHOW_FREEZE", "OBDII - Show freeze data"}, - {3, "UDS_OBDII_SHOW_STORED_DTC", "OBDII - Show stored DTC codes"}, - {4, "UDS_OBDII_CLEAR_DTC", "OBDII - Clear current DTC codes"}, - {5, "UDS_OBDII_TEST_O2", "OBDII - O2 sensor testing"}, - {6, "UDS_OBDII_TEST_RESULTS", "OBDII - Show emissions testing results"}, - {7, "UDS_OBDII_SHOW_PENDING_DTC", "OBDII - Show pending DTC codes"}, - {8, "UDS_OBDII_CONTROL_DEVICES", "OBDII - Control vehicle devices"}, - {9, "UDS_OBDII_VEH_INFO", "OBDII - Retrieve vehicle information"}, - {0xA, "UDS_OBDII_PERM_DTC", "OBDII - Show permanent DTC codes"}, - {0xFF, "UDS_UNKNOWN", "Unknown OBDII code - Likely proprietary"} -}; +ISOTP_HANDLER* ISOTP_HANDLER::mInstance = NULL; -CODE_STRUCT UDS_FUNCS[] = +ISOTP_HANDLER* ISOTP_HANDLER::getInstance() { - {0x10, "UDS_DIAG_CONTROL", "Diagnostic session control"}, - {0x11, "UDS_ECU_RESET", "Reset ECU"}, - {0x14, "UDS_CLEAR_DIAG", "Clear diagnostic trouble codes"}, - {0x19, "UDS_READ_DTC", "Read diagnostic trouble codes"}, - {0x22, "UDS_READ_BY_ID", "Read data by ID"}, - {0x23, "UDS_READ_BY_ADDR", "Read data by address"}, - {0x24, "UDS_READ_SCALING_ID", "Read scaling data by ID"}, - {0x27, "UDS_SECURITY_ACCESS", "Request security access"}, - {0x28, "UDS_COMM_CTRL", "Communication control"}, - {0x2A, "UDS_READ_DATA_ID_PERIODIC", "Read data by ID periodically"}, - {0x2C, "UDS_DYNAMIC_DATA_DEFINE", "Create dynamic data ID"}, - {0x2E, "UDS_WRITE_BY_ID", "Write data by ID"}, - {0x2F, "UDS_IO_CTRL", "Input/Output control (force)"}, - {0x31, "UDS_ROUTINE_CTRL", "Call a service routine"}, - {0x34, "UDS_REQUEST_DOWNLOAD", "Request data download (from PC to ECU)"}, - {0x35, "UDS_REQUEST_UPLOAD", "Request data upload (from ECU to PC)"}, - {0x36, "UDS_TRANSFER_DATA", "Transfer data"}, - {0x37, "UDS_REQ_TRANS_EXIT", "Request that data transfer cease"}, - {0x38, "UDS_REQ_FILE_TRANS", "Request file transfer"}, - {0x3D, "UDS_WRITE_BY_ADDR", "Write data by address"}, - {0x3E, "UDS_TESTER_PRESENT", "Tester is present"}, - {0x83, "UDS_ACCESS_TIMING", "Read or write comm timing parameters"}, - {0x84, "UDS_SECURED_DATA_TRANS", "Secured data transmission"}, - {0x85, "UDS_CTRL_DTC_SETTINGS", "Control DTC settings"}, - {0x86, "UDS_RESPONSE_ON_EVENT", "Request start/stop transmission on event"}, - {0x87, "UDS_RESPONSE_LINK_CTRL", "Control comm link"}, - {0xFF, "UDS_UNKNOWN_CODE", "Unknown, likely proprietary UDS function code"} -}; + if(!mInstance) + { + mInstance = new ISOTP_HANDLER(); + mInstance->modelFrames = MainWindow::getReference()->getCANFrameModel()->getListReference(); + } -CODE_STRUCT UDS_NEG_RESPONSE[] = -{ - {0x10, "UDS_NEG_GENERAL_REJECT", "General rejection (no other codes matched)"}, - {0x11, "UDS_NEG_SERVICE_NOTSUPP", "ECU does not support this service code"}, - {0x12, "UDS_NEG_SUBFUNCT_NOTSUPP", "ECU does not support the requested sub function"}, - {0x13, "UDS_NEG_INVALID_FORMAT", "Invalid request length or format error"}, - {0x14, "UDS_NEG_RESPONSE_TOOLONG", "Response would be too long to send"}, - {0x21, "UDS_NEG_BUSY", "ECU is busy. Try again later"}, - {0x22, "UDS_NEG_COND_INCORR", "A prereq. condition was not met"}, - {0x24, "UDS_NEG_REQ_SEQ_ERR", "Invalid sequence of requests"}, - {0x25, "UDS_NEG_SUBNET_NORESP", "ECU tried to gateway request but response timed out"}, - {0x26, "UDS_NEG_FAILURE", "A failure (indicated in a DTC) is preventing a reply"}, - {0x31, "UDS_NEG_REQ_OUTOFRANGE", "A parameter is outside of the valid range"}, - {0x33, "UDS_NEG_SECURITY_DENIED", "Security access was denied. (invalid seq or ECU not unlocked?)"}, - {0x35, "UDS_NEG_INVALID_KEY", "Key passed was invalid. Failure counter has been incremented."}, - {0x36, "UDS_NEG_EXCEED_ATTEMPTS", "Key failed too many times. ECU security access locked out"}, - {0x37, "UDS_NEG_TIMEDELAY", "Security access too soon after last attempt"}, - {0x38, "UDS_NEG_EXT_SECUR_1", "Extended security failure code 1"}, - {0x39, "UDS_NEG_EXT_SECUR_2", "Extended security failure code 2"}, - {0x3A, "UDS_NEG_EXT_SECUR_3", "Extended security failure code 3"}, - {0x3B, "UDS_NEG_EXT_SECUR_4", "Extended security failure code 4"}, - {0x3C, "UDS_NEG_EXT_SECUR_5", "Extended security failure code 5"}, - {0x3D, "UDS_NEG_EXT_SECUR_6", "Extended security failure code 6"}, - {0x3E, "UDS_NEG_EXT_SECUR_7", "Extended security failure code 7"}, - {0x3F, "UDS_NEG_EXT_SECUR_8", "Extended security failure code 8"}, - {0x40, "UDS_NEG_EXT_SECUR_9", "Extended security failure code 9"}, - {0x41, "UDS_NEG_EXT_SECUR_10", "Extended security failure code 10"}, - {0x42, "UDS_NEG_EXT_SECUR_11", "Extended security failure code 11"}, - {0x43, "UDS_NEG_EXT_SECUR_12", "Extended security failure code 12"}, - {0x44, "UDS_NEG_EXT_SECUR_13", "Extended security failure code 13"}, - {0x45, "UDS_NEG_EXT_SECUR_14", "Extended security failure code 14"}, - {0x46, "UDS_NEG_EXT_SECUR_15", "Extended security failure code 15"}, - {0x47, "UDS_NEG_EXT_SECUR_16", "Extended security failure code 16"}, - {0x48, "UDS_NEG_EXT_SECUR_17", "Extended security failure code 17"}, - {0x49, "UDS_NEG_EXT_SECUR_18", "Extended security failure code 18"}, - {0x4A, "UDS_NEG_EXT_SECUR_19", "Extended security failure code 19"}, - {0x4B, "UDS_NEG_EXT_SECUR_20", "Extended security failure code 20"}, - {0x4C, "UDS_NEG_EXT_SECUR_21", "Extended security failure code 21"}, - {0x4D, "UDS_NEG_EXT_SECUR_22", "Extended security failure code 22"}, - {0x4E, "UDS_NEG_EXT_SECUR_23", "Extended security failure code 23"}, - {0x4F, "UDS_NEG_EXT_SECUR_24", "Extended security failure code 24"}, - {0x70, "UDS_NEG_UPLOAD_DOWNLOAD", "Fault when attempting to start upload/download"}, - {0x71, "UDS_NEG_TRX_SUSPENDED", "Transfer aborting due to a fault"}, - {0x72, "UDS_NEG_GEN_PROGRAMMING", "Fault while attempting to write to ECU memory"}, - {0x73, "UDS_NEG_WRONG_BLOCK_SEQ", "Invalid sequence value detected during transfer"}, - {0x78, "UDS_NEG_RESP_PENDING", "Request successful but ECU still busy - Response pending"}, - {0x7E, "UDS_NEG_SUBFUNCT_CURRSESS", "ECU does not support this subfunction in current session type"}, - {0x7F, "UDS_NEG_SERVICE_CURRSESS", "ECU does not support this service in current session type"}, - {0x81, "UDS_NEG_RPM_TOOHIGH", "RPM is too high to execute request"}, - {0x82, "UDS_NEG_RPM_TOOLOW", "RPM is too low to execute request"}, - {0x83, "UDS_NEG_ENGINE_RUNNING", "Cannot execute request while engine is running"}, - {0x84, "UDS_NEG_ENGINE_NOTRUNNING", "Cannot execute request while engine is off"}, - {0x85, "UDS_NEG_ENG_RUNTIME_LOW", "Cannot execute request until engine has run for longer"}, - {0x86, "UDS_NEG_TEMPERATURE_HIGH", "Cannot execute request until temperature is lower"}, - {0x87, "UDS_NEG_TEMPERATURE_LOW", "Cannot execute request until temperature is higher"}, - {0x88, "UDS_NEG_SPEED_HIGH", "Cannot execute request until vehicle slows down"}, - {0x89, "UDS_NEG_SPEED_LOW", "Cannot execute request until vehicle is going faster"}, - {0x8A, "UDS_NEG_PEDAL_HIGH", "Cannot execute request until throttle is lower"}, - {0x8B, "UDS_NEG_PEDAL_LOW", "Cannot execute request until throttle is higher"}, - {0x8C, "UDS_NEG_NOT_NEUTRAL", "Cannot execute request until transmission is in neutral"}, - {0x8D, "UDS_NEG_NOT_INGEAR", "Cannot execute request until vehicle is in gear"}, - {0x8F, "UDS_NEG_BRAKE_NOTPRESSED", "Cannot execute request until brake pedal is pressed (Hold down)"}, - {0x90, "UDS_NEG_NOT_PARK", "Cannot execute request until vehicle is in park"}, - {0x91, "UDS_NEG_CLUTCH_LOCKED", "Cannot execute request while clutch is locked"}, - {0x92, "UDS_NEG_VOLTAGE_HIGH", "Cannot execute request until voltage is lower"}, - {0x93, "UDS_NEG_VOLTAGE_LOW", "Cannot execute request until voltage is higher"}, -}; + return mInstance; +} -ISOTP_HANDLER::ISOTP_HANDLER(const QVector *frames, QObject *parent) - : QObject(parent) +ISOTP_HANDLER::ISOTP_HANDLER() { - modelFrames = frames; useExtendedAddressing = false; + isReceiving = false; } void ISOTP_HANDLER::setExtendedAddressing(bool mode) @@ -126,6 +25,64 @@ void ISOTP_HANDLER::setExtendedAddressing(bool mode) useExtendedAddressing = mode; } +void ISOTP_HANDLER::setReception(bool mode) +{ + if (isReceiving == mode) return; + isReceiving = mode; + + if (isReceiving) + { + connect(CANConManager::getInstance(), &CANConManager::framesReceived, this, &ISOTP_HANDLER::rapidFrames); + qDebug() << "Enabling reception in ISOTP handler"; + } + else + { + disconnect(CANConManager::getInstance(), &CANConManager::framesReceived, this, &ISOTP_HANDLER::rapidFrames); + qDebug() << "Disabling reception in ISOTP handler"; + } +} + +void ISOTP_HANDLER::sendISOTPFrame(int bus, int ID, QVector data) +{ + CANFrame frame; + int currByte = 0; + int index = 0; + if (bus < 0) return; + if (bus >= CANConManager::getInstance()->getNumBuses()) return; + + if (data.length() < 8) + { + frame.bus = bus; + frame.extended = false; + frame.ID = ID; + frame.len = data.length() + 1; + frame.data[0] = frame.len - 1; + for (int i = 0; i < frame.data[0]; i++) frame.data[i + 1] = data[i]; + CANConManager::getInstance()->sendFrame(frame); + } + else //need to send a multi-part ISO_TP message - no flow control possible right now. TODO - Add flow control + { + frame.bus = bus; + frame.ID = ID; + frame.extended = false; + frame.len = 8; + frame.data[0] = 0x10 + (data.length() / 256); + frame.data[1] = data.length() & 0xFF; + for (int i = 0; i < 6; i++) frame.data[2 + i] = data[currByte++]; + CANConManager::getInstance()->sendFrame(frame); + while (currByte < data.length()) + { + frame.data[0] = 0x20 + index; + index = (index + 1) & 0xF; + int bytesToGo = data.length() - currByte; + if (bytesToGo > 7) bytesToGo = 7; + for (int i = 0; i < bytesToGo; i++) frame.data[1 + i] = data[currByte++]; + frame.len = 1 + bytesToGo; + CANConManager::getInstance()->sendFrame(frame); + } + } +} + //remember, negative numbers are special -1 = all frames deleted, -2 = totally new set of frames. void ISOTP_HANDLER::updatedFrames(int numFrames) { @@ -140,11 +97,23 @@ void ISOTP_HANDLER::updatedFrames(int numFrames) { for (int i = modelFrames->count() - numFrames; i < modelFrames->count(); i++) { - processFrame(modelFrames->at(i)); + //processFrame(modelFrames->at(i)); } } } +void ISOTP_HANDLER::rapidFrames(const CANConnection* conn, const QVector& pFrames) +{ + if (pFrames.length() <= 0) return; + + qDebug() << "received messages in ISOTP handler"; + + foreach(const CANFrame& thisFrame, pFrames) + { + processFrame(thisFrame); + } +} + void ISOTP_HANDLER::processFrame(const CANFrame &frame) { uint64_t ID = frame.ID; diff --git a/bus_protocols/isotp_handler.h b/bus_protocols/isotp_handler.h index 00c2cb8..dc6a1f8 100644 --- a/bus_protocols/isotp_handler.h +++ b/bus_protocols/isotp_handler.h @@ -1,16 +1,25 @@ -#ifndef ISOTP_DECODER_H -#define ISOTP_DECODER_H +#ifndef ISOTP_HANDLER_H +#define ISOTP_HANDLER_H #include #include #include #include "can_structs.h" +#include "mainwindow.h" +#include "canframemodel.h" -struct CODE_STRUCT +//the same as the CANFrame struct but with arbitrary data size. +struct ISOTP_MESSAGE { - int code; - QString shortDesc; - QString longDesc; +public: + uint32_t ID; + int bus; + bool extended; + bool isReceived; + int len; //# of bytes this message should have (as reported) + int actualSize; //# we actually got + QVector data; + uint64_t timestamp; }; class ISOTP_HANDLER : public QObject @@ -18,11 +27,15 @@ class ISOTP_HANDLER : public QObject Q_OBJECT public: - explicit ISOTP_HANDLER(const QVector *frames, QObject *parent = 0); + ISOTP_HANDLER(); void setExtendedAddressing(bool mode); + static ISOTP_HANDLER* getInstance(); + void setReception(bool mode); //set whether to accept and forward frames or not + void sendISOTPFrame(int bus, int ID, QVector data); public slots: void updatedFrames(int); + void rapidFrames(const CANConnection* conn, const QVector& pFrames); signals: void newISOMessage(ISOTP_MESSAGE &msg); @@ -31,9 +44,12 @@ private: QList messageBuffer; const QVector *modelFrames; bool useExtendedAddressing; + bool isReceiving; void processFrame(const CANFrame &frame); void checkNeedFlush(uint64_t ID); + + static ISOTP_HANDLER* mInstance; }; -#endif // ISOTP_DECODER_H +#endif // ISOTP_HANDLER_H diff --git a/bus_protocols/j1939_handler.h b/bus_protocols/j1939_handler.h index 504ca14..53ff315 100644 --- a/bus_protocols/j1939_handler.h +++ b/bus_protocols/j1939_handler.h @@ -6,5 +6,16 @@ #include #include "can_structs.h" +struct J1939ID +{ +public: + int src; + int dest; + int pgn; + int pf; + int ps; + int priority; + bool isBroadcast; +}; #endif // J1939_HANDLER_H diff --git a/bus_protocols/uds_handler.cpp b/bus_protocols/uds_handler.cpp index c967857..cb5e743 100644 --- a/bus_protocols/uds_handler.cpp +++ b/bus_protocols/uds_handler.cpp @@ -1,3 +1,215 @@ #include "uds_handler.h" +#include "connections/canconmanager.h" +#include +QVector UDS_SERVICE_DESC = { + {1, "OBDII_SHOW_CURRENT", "OBDII - Show current data"}, + {2, "OBDII_SHOW_FREEZE", "OBDII - Show freeze data"}, + {3, "OBDII_SHOW_STORED_DTC", "OBDII - Show stored DTC codes"}, + {4, "OBDII_CLEAR_DTC", "OBDII - Clear current DTC codes"}, + {5, "OBDII_TEST_O2", "OBDII - O2 sensor testing"}, + {6, "OBDII_TEST_RESULTS", "OBDII - Show emissions testing results"}, + {7, "OBDII_SHOW_PENDING_DTC", "OBDII - Show pending DTC codes"}, + {8, "OBDII_CONTROL_DEVICES", "OBDII - Control vehicle devices"}, + {9, "OBDII_VEH_INFO", "OBDII - Retrieve vehicle information"}, + {0xA, "OBDII_PERM_DTC", "OBDII - Show permanent DTC codes"}, + {0x10, "DIAG_CONTROL", "Diagnostic session control"}, + {0x11, "ECU_RESET", "Reset ECU"}, + {0x12, "GMLAN_READ_FAILURE_RECORD", "GMLAN - Read Fail"}, + {0x14, "CLEAR_DIAG", "Clear diagnostic trouble codes"}, + {0x19, "READ_DTC", "Read diagnostic trouble codes"}, + {0x1A, "GMLAN_READ_DIAGNOSTIC_ID", "GMLAN - Read diagnostics ID"}, + {0x20, "RETURN_TO_NORMAL", "Return to normal mode"}, + {0x22, "READ_BY_ID", "Read data by ID"}, + {0x23, "READ_BY_ADDR", "Read data by address"}, + {0x24, "READ_SCALING_ID", "Read scaling data by ID"}, + {0x27, "SECURITY_ACCESS", "Request security access"}, + {0x28, "COMM_CTRL", "Communication control"}, + {0x2A, "READ_DATA_ID_PERIODIC", "Read data by ID periodically"}, + {0x2C, "DYNAMIC_DATA_DEFINE", "Create dynamic data ID"}, + {0x2D, "DEFINE_PID_BY_ADDR", "Create a PID for a given memory address"}, + {0x2E, "WRITE_BY_ID", "Write data by ID"}, + {0x2F, "IO_CTRL", "Input/Output control (force)"}, + {0x31, "ROUTINE_CTRL", "Call a service routine"}, + {0x34, "REQUEST_DOWNLOAD", "Request data download (from PC to ECU)"}, + {0x35, "REQUEST_UPLOAD", "Request data upload (from ECU to PC)"}, + {0x36, "TRANSFER_DATA", "Transfer data"}, + {0x37, "REQ_TRANS_EXIT", "Request that data transfer cease"}, + {0x38, "REQ_FILE_TRANS", "Request file transfer"}, + {0x3B, "GMLAN_WRITE_DID", "GMLAN - Write DID"}, + {0x3D, "WRITE_BY_ADDR", "Write data by address"}, + {0x3E, "TESTER_PRESENT", "Tester is present"}, + {0x7F, "NEG_RESPONSE","Negative Response"}, + {0x83, "ACCESS_TIMING", "Read or write comm timing parameters"}, + {0x84, "SECURED_DATA_TRANS", "Secured data transmission"}, + {0x85, "CTRL_DTC_SETTINGS", "Control DTC settings"}, + {0x86, "RESPONSE_ON_EVENT", "Request start/stop transmission on event"}, + {0x87, "RESPONSE_LINK_CTRL", "Control comm link"}, + {0xA2, "GMLAN_REPORT_PROG_STATE", "GMLAN - Report programming state"}, + {0xA5, "GMLAN_ENTER_PROG_MODE", "GMLAN - Enter programming mode"}, + {0xA9, "GMLAN_CHECK_CODES", "GMLAN - Check codes"}, + {0xAA, "GMLAN_READ_DPID", "GMLAN - Read dynamic PID"}, + {0xAE, "GMLAN_DEVICE_CTRL", "GMLAN - Device control"}, + {0xFF, "UNKNOWN_CODE", "Unknown, likely proprietary UDS function code"} +}; + +QVector UDS_NEG_RESPONSE = +{ + {0x10, "UDS_NEG_GENERAL_REJECT", "General rejection (no other codes matched)"}, + {0x11, "UDS_NEG_SERVICE_NOTSUPP", "ECU does not support this service code"}, + {0x12, "UDS_NEG_SUBFUNCT_NOTSUPP", "ECU does not support the requested sub function"}, + {0x13, "UDS_NEG_INVALID_FORMAT", "Invalid request length or format error"}, + {0x14, "UDS_NEG_RESPONSE_TOOLONG", "Response would be too long to send"}, + {0x21, "UDS_NEG_BUSY", "ECU is busy. Try again later"}, + {0x22, "UDS_NEG_COND_INCORR", "A prereq. condition was not met"}, + {0x24, "UDS_NEG_REQ_SEQ_ERR", "Invalid sequence of requests"}, + {0x25, "UDS_NEG_SUBNET_NORESP", "ECU tried to gateway request but response timed out"}, + {0x26, "UDS_NEG_FAILURE", "A failure (indicated in a DTC) is preventing a reply"}, + {0x31, "UDS_NEG_REQ_OUTOFRANGE", "A parameter is outside of the valid range"}, + {0x33, "UDS_NEG_SECURITY_DENIED", "Security access was denied. (invalid seq or ECU not unlocked?)"}, + {0x35, "UDS_NEG_INVALID_KEY", "Key passed was invalid. Failure counter has been incremented."}, + {0x36, "UDS_NEG_EXCEED_ATTEMPTS", "Key failed too many times. ECU security access locked out"}, + {0x37, "UDS_NEG_TIMEDELAY", "Security access too soon after last attempt"}, + {0x38, "UDS_NEG_EXT_SECUR_1", "Extended security failure code 1"}, + {0x39, "UDS_NEG_EXT_SECUR_2", "Extended security failure code 2"}, + {0x3A, "UDS_NEG_EXT_SECUR_3", "Extended security failure code 3"}, + {0x3B, "UDS_NEG_EXT_SECUR_4", "Extended security failure code 4"}, + {0x3C, "UDS_NEG_EXT_SECUR_5", "Extended security failure code 5"}, + {0x3D, "UDS_NEG_EXT_SECUR_6", "Extended security failure code 6"}, + {0x3E, "UDS_NEG_EXT_SECUR_7", "Extended security failure code 7"}, + {0x3F, "UDS_NEG_EXT_SECUR_8", "Extended security failure code 8"}, + {0x40, "UDS_NEG_EXT_SECUR_9", "Extended security failure code 9"}, + {0x41, "UDS_NEG_EXT_SECUR_10", "Extended security failure code 10"}, + {0x42, "UDS_NEG_EXT_SECUR_11", "Extended security failure code 11"}, + {0x43, "UDS_NEG_EXT_SECUR_12", "Extended security failure code 12"}, + {0x44, "UDS_NEG_EXT_SECUR_13", "Extended security failure code 13"}, + {0x45, "UDS_NEG_EXT_SECUR_14", "Extended security failure code 14"}, + {0x46, "UDS_NEG_EXT_SECUR_15", "Extended security failure code 15"}, + {0x47, "UDS_NEG_EXT_SECUR_16", "Extended security failure code 16"}, + {0x48, "UDS_NEG_EXT_SECUR_17", "Extended security failure code 17"}, + {0x49, "UDS_NEG_EXT_SECUR_18", "Extended security failure code 18"}, + {0x4A, "UDS_NEG_EXT_SECUR_19", "Extended security failure code 19"}, + {0x4B, "UDS_NEG_EXT_SECUR_20", "Extended security failure code 20"}, + {0x4C, "UDS_NEG_EXT_SECUR_21", "Extended security failure code 21"}, + {0x4D, "UDS_NEG_EXT_SECUR_22", "Extended security failure code 22"}, + {0x4E, "UDS_NEG_EXT_SECUR_23", "Extended security failure code 23"}, + {0x4F, "UDS_NEG_EXT_SECUR_24", "Extended security failure code 24"}, + {0x70, "UDS_NEG_UPLOAD_DOWNLOAD", "Fault when attempting to start upload/download"}, + {0x71, "UDS_NEG_TRX_SUSPENDED", "Transfer aborting due to a fault"}, + {0x72, "UDS_NEG_GEN_PROGRAMMING", "Fault while attempting to write to ECU memory"}, + {0x73, "UDS_NEG_WRONG_BLOCK_SEQ", "Invalid sequence value detected during transfer"}, + {0x78, "UDS_NEG_RESP_PENDING", "Request successful but ECU still busy - Response pending"}, + {0x7E, "UDS_NEG_SUBFUNCT_CURRSESS", "ECU does not support this subfunction in current session type"}, + {0x7F, "UDS_NEG_SERVICE_CURRSESS", "ECU does not support this service in current session type"}, + {0x81, "UDS_NEG_RPM_TOOHIGH", "RPM is too high to execute request"}, + {0x82, "UDS_NEG_RPM_TOOLOW", "RPM is too low to execute request"}, + {0x83, "UDS_NEG_ENGINE_RUNNING", "Cannot execute request while engine is running"}, + {0x84, "UDS_NEG_ENGINE_NOTRUNNING", "Cannot execute request while engine is off"}, + {0x85, "UDS_NEG_ENG_RUNTIME_LOW", "Cannot execute request until engine has run for longer"}, + {0x86, "UDS_NEG_TEMPERATURE_HIGH", "Cannot execute request until temperature is lower"}, + {0x87, "UDS_NEG_TEMPERATURE_LOW", "Cannot execute request until temperature is higher"}, + {0x88, "UDS_NEG_SPEED_HIGH", "Cannot execute request until vehicle slows down"}, + {0x89, "UDS_NEG_SPEED_LOW", "Cannot execute request until vehicle is going faster"}, + {0x8A, "UDS_NEG_PEDAL_HIGH", "Cannot execute request until throttle is lower"}, + {0x8B, "UDS_NEG_PEDAL_LOW", "Cannot execute request until throttle is higher"}, + {0x8C, "UDS_NEG_NOT_NEUTRAL", "Cannot execute request until transmission is in neutral"}, + {0x8D, "UDS_NEG_NOT_INGEAR", "Cannot execute request until vehicle is in gear"}, + {0x8F, "UDS_NEG_BRAKE_NOTPRESSED", "Cannot execute request until brake pedal is pressed (Hold down)"}, + {0x90, "UDS_NEG_NOT_PARK", "Cannot execute request until vehicle is in park"}, + {0x91, "UDS_NEG_CLUTCH_LOCKED", "Cannot execute request while clutch is locked"}, + {0x92, "UDS_NEG_VOLTAGE_HIGH", "Cannot execute request until voltage is lower"}, + {0x93, "UDS_NEG_VOLTAGE_LOW", "Cannot execute request until voltage is higher"}, +}; + +UDS_HANDLER* UDS_HANDLER::mInstance = NULL; + +UDS_HANDLER* UDS_HANDLER::getInstance() +{ + if(!mInstance) + { + mInstance = new UDS_HANDLER(); + mInstance->modelFrames = MainWindow::getReference()->getCANFrameModel()->getListReference(); + } + + return mInstance; +} + +UDS_HANDLER::UDS_HANDLER() +{ + isReceiving = false; + useExtendedAddressing = false; +} + +void UDS_HANDLER::gotISOTPFrame(ISOTP_MESSAGE &msg) +{ + qDebug() << "UDS handler got ISOTP frame"; +} + +void UDS_HANDLER::setReception(bool mode) +{ + if (isReceiving == mode) return; + + isReceiving = mode; + + if (isReceiving) + { + connect(ISOTP_HANDLER::getInstance(), SIGNAL(newISOMessage(ISOTP_MESSAGE&)), this, SLOT(gotISOTPFrame(ISOTP_MESSAGE&))); + ISOTP_HANDLER::getInstance()->setReception(true); //must enable ISOTP reception too. + qDebug() << "Enabling reception of ISO-TP frames in UDS handler"; + } + else + { + disconnect(ISOTP_HANDLER::getInstance(), SIGNAL(newISOMessage(ISOTP_MESSAGE&)), this, SLOT(gotISOTPFrame(ISOTP_MESSAGE&))); + //can't disable ISOTP reception because something else might be using it. + qDebug() << "Disabling reception of ISOTP frames in UDS handler"; + } +} + +void UDS_HANDLER::sendUDSFrame(int bus, int ID, int service, QVector payload) +{ + QVector data; + if (bus < 0) return; + if (bus >= CANConManager::getInstance()->getNumBuses()) return; + if (service < 0 || service > 0xFF) return; + data.append(service); + data.append(payload); + ISOTP_HANDLER::getInstance()->sendISOTPFrame(bus, ID, data); + qDebug() << "Sent UDS service: " << getServiceShortDesc(service) << " on bus " << bus; +} + +QString UDS_HANDLER::getServiceShortDesc(int service) +{ + foreach (CODE_STRUCT code, UDS_SERVICE_DESC) + { + if (code.code == service) return code.shortDesc; + } + return QString(); +} + +QString UDS_HANDLER::getServiceLongDesc(int service) +{ + foreach (CODE_STRUCT code, UDS_SERVICE_DESC) + { + if (code.code == service) return code.longDesc; + } + return QString(); +} + +QString UDS_HANDLER::getNegativeResponseShort(int respCode) +{ + foreach (CODE_STRUCT code, UDS_NEG_RESPONSE) + { + if (code.code == respCode) return code.shortDesc; + } + return QString(); +} + +QString UDS_HANDLER::getNegativeResponseLong(int respCode) +{ + foreach (CODE_STRUCT code, UDS_NEG_RESPONSE) + { + if (code.code == respCode) return code.longDesc; + } + return QString(); +} diff --git a/bus_protocols/uds_handler.h b/bus_protocols/uds_handler.h index e58eb7d..315f722 100644 --- a/bus_protocols/uds_handler.h +++ b/bus_protocols/uds_handler.h @@ -5,5 +5,100 @@ #include #include #include "can_structs.h" +#include "isotp_handler.h" + +namespace UDS_SERVICES +{ + enum + { + OBDII_SHOW_CURRENT = 1, + OBDII_SHOW_FREEZE = 2, + OBDII_SHOW_STORED_DTC = 3, + OBDII_CLEAR_DTC = 4, + OBDII_TEST_O2 = 5, + OBDII_TEST_RESULTS = 6, + OBDII_SHOW_PENDING_DTC = 7, + OBDII_CONTROL_DEVICES = 8, + OBDII_VEH_INFO = 9, + OBDII_PERM_DTC = 0xA, + DIAG_CONTROL = 0x10, + ECU_RESET = 0x11, + GMLAN_READ_FAILURE_RECORD = 0x12, + CLEAR_DIAG = 0x14, + READ_DTC = 0x19, + GMLAN_READ_DIAGNOSTIC_ID = 0x1A, + RETURN_TO_NORMAL = 0x20, + READ_BY_ID = 0x22, + READ_BY_ADDR = 0x23, + READ_SCALING_ID = 0x24, + SECURITY_ACCESS = 0x27, + COMM_CTRL = 0x28, + READ_DATA_ID_PERIODIC = 0x2A, + DYNAMIC_DATA_DEFINE = 0x2C, + DEFINE_PID_BY_ADDR = 0x2D, + WRITE_BY_ID = 0x2E, + IO_CTRL = 0x2F, + ROUTINE_CTRL = 0x31, + REQUEST_DOWNLOAD = 0x34, + REQUEST_UPLOAD = 0x35, + TRANSFER_DATA = 0x36, + REQ_TRANS_EXIT = 0x37, + REQ_FILE_TRANS = 0x38, + GMLAN_WRITE_DID = 0x3B, + WRITE_BY_ADDR = 0x3D, + TESTER_PRESENT = 0x3E, + NEG_RESPONSE = 0x7F, + ACCESS_TIMING = 0x83, + SECURED_DATA_TRANS = 0x84, + CTRL_DTC_SETTINGS = 0x85, + RESPONSE_ON_EVENT = 0x86, + RESPONSE_LINK_CTRL = 0x87, + GMLAN_REPORT_PROG_STATE = 0xA2, + GMLAN_ENTER_PROG_MODE = 0xA5, + GMLAN_CHECK_CODES = 0xA9, + GMLAN_READ_DPID = 0xAA, + GMLAN_DEVICE_CTRL = 0xAE + }; +} + +struct CODE_STRUCT +{ + int code; + QString shortDesc; + QString longDesc; +}; + +class UDS_HANDLER : public QObject +{ + Q_OBJECT + +public: + UDS_HANDLER(); + void setExtendedAddressing(bool mode); + static UDS_HANDLER* getInstance(); + void setReception(bool mode); //set whether to accept and forward frames or not + void sendUDSFrame(int bus, int ID, int service, QVector payload); + QString getServiceShortDesc(int service); + QString getServiceLongDesc(int service); + QString getNegativeResponseShort(int respCode); + QString getNegativeResponseLong(int respCode); + +public slots: + void gotISOTPFrame(ISOTP_MESSAGE &msg); + +signals: + void newUDSMessage(ISOTP_MESSAGE &msg); + +private: + QList messageBuffer; + const QVector *modelFrames; + bool isReceiving; + bool useExtendedAddressing; + + void processFrame(const CANFrame &frame); + + static UDS_HANDLER* mInstance; +}; + #endif // UDS_HANDLER_H diff --git a/can_structs.h b/can_structs.h index 40428b5..ece14b1 100644 --- a/can_structs.h +++ b/can_structs.h @@ -32,31 +32,5 @@ public: } }; -struct J1939ID -{ -public: - int src; - int dest; - int pgn; - int pf; - int ps; - int priority; - bool isBroadcast; -}; - -//the same as the CANFrame struct but with arbitrary data size. -struct ISOTP_MESSAGE -{ -public: - uint32_t ID; - int bus; - bool extended; - bool isReceived; - int len; //# of bytes this message should have (as reported) - int actualSize; //# we actually got - QVector data; - uint64_t timestamp; -}; - #endif // CAN_STRUCTS_H diff --git a/connections/canconmanager.cpp b/connections/canconmanager.cpp index 0fe5453..b83f663 100644 --- a/connections/canconmanager.cpp +++ b/connections/canconmanager.cpp @@ -17,7 +17,7 @@ CANConManager* CANConManager::getInstance() CANConManager::CANConManager(QObject *parent): QObject(parent) { connect(&mTimer, SIGNAL(timeout()), this, SLOT(refreshCanList())); - mTimer.setInterval(62); /*tick 16 times a second */ + mTimer.setInterval(20); /*Tick 50 times per second to allow for good resolution in reception where needed. GUI updates *MUCH* more slowly*/ mTimer.setSingleShot(false); mTimer.start(); diff --git a/mainwindow.cpp b/mainwindow.cpp index 9af3409..b4b9778 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -168,7 +168,7 @@ MainWindow::MainWindow(QWidget *parent) : //Automatically create the connection window so it can be updated even if we never opened it. connectionWindow = new ConnectionWindow(); - connect(this, SIGNAL(suspendCapturing(bool)), connectionWindow, SLOT(setSuspendAll(bool))); + connect(this, SIGNAL(suspendCapturing(bool)), connectionWindow, SLOT(setSuspendAll(bool))); } @@ -644,7 +644,7 @@ void MainWindow::toggleCapture() } void MainWindow::connectionStatusUpdated(int conns) -{ +{ lbStatusConnected.setText(tr("Connected to ") + QString::number(conns) + tr(" buses")); } @@ -674,6 +674,11 @@ void MainWindow::updateFileStatus() lbStatusFilename.setText(output); } +CANFrameModel* MainWindow::getCANFrameModel() +{ + return model; +} + void MainWindow::showSettingsDialog() { if (!settingsDialog) diff --git a/mainwindow.h b/mainwindow.h index e9ada2e..4a03275 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -8,6 +8,9 @@ #include "canframemodel.h" #include "can_structs.h" #include "framefileio.h" +#include "dbc/dbchandler.h" +#include "bus_protocols/isotp_handler.h" + #include "re/graphingwindow.h" #include "re/frameinfowindow.h" #include "frameplaybackwindow.h" @@ -15,7 +18,6 @@ #include "re/flowviewwindow.h" #include "framesenderwindow.h" #include "re/filecomparatorwindow.h" -#include "dbc/dbchandler.h" #include "dbc/dbcmaineditor.h" #include "mainsettingsdialog.h" #include "firmwareuploaderwindow.h" @@ -32,6 +34,7 @@ #include "signalviewerwindow.h" class ConnectionWindow; +class ISOTP_InterpreterWindow; namespace Ui { class MainWindow; @@ -45,6 +48,7 @@ public: explicit MainWindow(QWidget *parent = 0); static QString loadedFileName; static MainWindow *getReference(); + CANFrameModel * getCANFrameModel(); ~MainWindow(); private slots: diff --git a/re/frameinfowindow.h b/re/frameinfowindow.h index dc3ac57..67bbb44 100644 --- a/re/frameinfowindow.h +++ b/re/frameinfowindow.h @@ -6,6 +6,7 @@ #include #include #include "can_structs.h" +#include "bus_protocols/j1939_handler.h" namespace Ui { class FrameInfoWindow; diff --git a/re/isotp_interpreterwindow.cpp b/re/isotp_interpreterwindow.cpp index 778a2d8..54ccd52 100644 --- a/re/isotp_interpreterwindow.cpp +++ b/re/isotp_interpreterwindow.cpp @@ -9,7 +9,7 @@ ISOTP_InterpreterWindow::ISOTP_InterpreterWindow(const QVector *frames ui->setupUi(this); modelFrames = frames; - decoder = new ISOTP_HANDLER(modelFrames); + decoder = ISOTP_HANDLER::getInstance(); connect(MainWindow::getReference(), &MainWindow::framesUpdated, this, &ISOTP_InterpreterWindow::updatedFrames); connect(MainWindow::getReference(), &MainWindow::framesUpdated, decoder, &ISOTP_HANDLER::updatedFrames); diff --git a/re/isotp_interpreterwindow.h b/re/isotp_interpreterwindow.h index ff099e1..354cef0 100644 --- a/re/isotp_interpreterwindow.h +++ b/re/isotp_interpreterwindow.h @@ -2,8 +2,10 @@ #define ISOTP_INTERPRETERWINDOW_H #include -#include "can_structs.h" -#include "isotp_handler.h" +#include "bus_protocols/isotp_handler.h" + +class ISOTP_MESSAGE; +class ISOTP_HANDLER; namespace Ui { class ISOTP_InterpreterWindow; diff --git a/re/udsscanwindow.cpp b/re/udsscanwindow.cpp index 0ff08e1..ad4e103 100644 --- a/re/udsscanwindow.cpp +++ b/re/udsscanwindow.cpp @@ -2,6 +2,7 @@ #include "ui_udsscanwindow.h" #include "mainwindow.h" #include "connections/canconmanager.h" +#include "bus_protocols/uds_handler.h" UDSScanWindow::UDSScanWindow(const QVector *frames, QWidget *parent) : QDialog(parent), @@ -72,19 +73,20 @@ void UDSScanWindow::saveResults() } } -void UDSScanWindow::sendOnBuses(CANFrame &frame, int buses) +void UDSScanWindow::sendOnBuses(UDS_TESTS test, int buses) { - if (buses < ui->cbBuses->count()- 1) + int busList = buses; + if (busList < ui->cbBuses->count() - 1) { - frame.bus = buses; - sendingFrames.append(frame); + test.bus = buses; + sendingFrames.append(test); } else { for (int c = 0; c < ui->cbBuses->count() - 1; c++) { - frame.bus = c; - sendingFrames.append(frame); + test.bus = c; + sendingFrames.append(test); } } } @@ -105,7 +107,7 @@ void UDSScanWindow::scanUDS() ui->listResults->clear(); sendingFrames.clear(); - CANFrame frame; + UDS_TESTS test; int typ, id; int startID, endID; startID = Utility::ParseStringToNum(ui->txtStartID->text()); @@ -115,48 +117,34 @@ void UDSScanWindow::scanUDS() for (id = startID; id <= endID; id++) { - frame.ID = id; - frame.len = 8; - frame.extended = false; + test.ID = id; if (ui->ckTester->isChecked()) { - frame.data[0] = 2; - frame.data[1] = 0x3E; //tester present - frame.data[2] = 0; - frame.data[3] = 0;frame.data[4] = 0;frame.data[5] = 0; - frame.data[6] = 0;frame.data[7] = 0; - sendOnBuses(frame, buses); + test.service = UDS_SERVICES::TESTER_PRESENT; + test.subFunc = 0; + sendOnBuses(test, buses); } if (ui->ckSession->isChecked()) { for (typ = 1; typ < 4; typ++) //try each type of session access { - frame.data[0] = 2; - frame.data[1] = 0x10; - frame.data[2] = typ; - frame.data[3] = 0;frame.data[4] = 0;frame.data[5] = 0; - frame.data[6] = 0;frame.data[7] = 0; - sendOnBuses(frame, buses); + test.service = UDS_SERVICES::DIAG_CONTROL; + test.subFunc = typ; + sendOnBuses(test, buses); } } if (ui->ckReset->isChecked()) //try to command a reset of the ECU. You're likely to know if it works. ;) { - frame.data[0] = 2; - frame.data[1] = 0x11; //Reset - frame.data[2] = 1; //hard reset. 2 = key off/on 3 = soft reset - frame.data[3] = 0;frame.data[4] = 0;frame.data[5] = 0; - frame.data[6] = 0;frame.data[7] = 0; - sendOnBuses(frame, buses); + test.service = UDS_SERVICES::ECU_RESET; + test.subFunc = 1; + sendOnBuses(test, buses); } if (ui->ckSecurity->isChecked()) //try to enter security mode - very likely to get a response if an ECU exists. { - frame.data[0] = 2; - frame.data[1] = 0x27; //request security mode - frame.data[2] = 1; //request seed from ECU - frame.data[3] = 0;frame.data[4] = 0;frame.data[5] = 0; - frame.data[6] = 0;frame.data[7] = 0; - sendOnBuses(frame, buses); + test.service = UDS_SERVICES::SECURITY_ACCESS; + test.subFunc = 1; + sendOnBuses(test, buses); } } @@ -188,7 +176,7 @@ void UDSScanWindow::rapidFrames(const CANConnection* conn, const QVectorspinReplyOffset->value(); - CANFrame sentFrame; + UDS_TESTS sentFrame; bool gotReply = false; if (pFrames.length() <= 0) return; @@ -205,27 +193,27 @@ void UDSScanWindow::rapidFrames(const CANConnection* conn, const QVectorcbAllowAdaptiveOffset->isChecked()) { - int temp = thisFrame.data[0] >> 4; - if (temp == 0) //single frame reply (maybe) - { - if (thisFrame.data[1] == 0x40 + sendingFrames[currIdx].data[1]) + //int temp = thisFrame.data[0] >> 4; + //if (temp == 0) //single frame reply (maybe) + //{ + if (thisFrame.data[1] == 0x40 + sendingFrames[currIdx].service) { result = "Request on bus " + QString::number(sentFrame.bus) + " ID: " + QString::number(sentFrame.ID, 16) + " got response to mode " - + QString::number(sentFrame.data[1], 16) - + " " + QString::number(sentFrame.data[2], 16) + " with affirmation from ID " + QString::number(id, 16) + + QString::number(sentFrame.service, 16) + + " " + QString::number(sentFrame.subFunc, 16) + " with affirmation from ID " + QString::number(id, 16) + " on bus " + QString::number(thisFrame.bus) + "."; gotReply = true; } else if ( thisFrame.data[1] == 0x7F) { result = "Request on bus " + QString::number(sentFrame.bus) + " ID: " + QString::number(sentFrame.ID, 16) + " got response to mode " - + QString::number(sentFrame.data[1], 16) - + " " + QString::number(sentFrame.data[2], 16) + " with an error from ID " + QString::number(id, 16) + + QString::number(sentFrame.service, 16) + + " " + QString::number(sentFrame.subFunc, 16) + " with an error from ID " + QString::number(id, 16) + " on bus " + QString::number(thisFrame.bus) + "."; gotReply = true; } - } - + //} + /* if (temp == 1) //start of a multiframe reply { if (thisFrame.data[2] == 0x40 + sendingFrames[currIdx].data[1]) @@ -237,7 +225,7 @@ void UDSScanWindow::rapidFrames(const CANConnection* conn, const QVectorlistResults->addItem(result); sendNextMsg(); @@ -259,10 +247,14 @@ void UDSScanWindow::timeOut() void UDSScanWindow::sendNextMsg() { + QVector data; + currIdx++; if (currIdx < sendingFrames.count()) { - CANConManager::getInstance()->sendFrame(sendingFrames[currIdx]); + data.clear(); + data.append(sendingFrames[currIdx].subFunc); + UDS_HANDLER::getInstance()->sendUDSFrame(sendingFrames[currIdx].bus, sendingFrames[currIdx].ID, sendingFrames[currIdx].service, data); waitTimer->start(); } else diff --git a/re/udsscanwindow.h b/re/udsscanwindow.h index 0ffc42e..55851f7 100644 --- a/re/udsscanwindow.h +++ b/re/udsscanwindow.h @@ -10,6 +10,14 @@ namespace Ui { class UDSScanWindow; } +struct UDS_TESTS +{ + int ID; + int bus; + int service; + int subFunc; +}; + class UDSScanWindow : public QDialog { Q_OBJECT @@ -29,12 +37,12 @@ private: Ui::UDSScanWindow *ui; const QVector *modelFrames; QTimer *waitTimer; - QList sendingFrames; + QList sendingFrames; int currIdx = 0; bool currentlyRunning; void sendNextMsg(); - void sendOnBuses(CANFrame &frame, int buses); + void sendOnBuses(UDS_TESTS frame, int buses); }; #endif // UDSSCANWINDOW_H