diff --git a/Software/src/communication/can/comm_can.cpp b/Software/src/communication/can/comm_can.cpp index d34b106f..174ead30 100644 --- a/Software/src/communication/can/comm_can.cpp +++ b/Software/src/communication/can/comm_can.cpp @@ -282,38 +282,7 @@ void print_can_frame(CAN_frame frame, frameDirection msgDir) { #endif // DEBUG_CAN_DATA if (datalayer.system.info.can_logging_active) { // If user clicked on CAN Logging page in webserver, start recording - char* message_string = datalayer.system.info.logged_can_messages; - int offset = datalayer.system.info.logged_can_messages_offset; // Keeps track of the current position in the buffer - size_t message_string_size = sizeof(datalayer.system.info.logged_can_messages); - - if (offset + 128 > sizeof(datalayer.system.info.logged_can_messages)) { - // Not enough space, reset and start from the beginning - offset = 0; - } - unsigned long currentTime = millis(); - // Add timestamp - offset += snprintf(message_string + offset, message_string_size - offset, "(%lu.%03lu) ", currentTime / 1000, - currentTime % 1000); - - // Add direction. The 0 and 1 after RX and TX ensures that SavvyCAN puts TX and RX in a different bus. - offset += - snprintf(message_string + offset, message_string_size - offset, "%s ", (msgDir == MSG_RX) ? "RX0" : "TX1"); - - // Add ID and DLC - offset += snprintf(message_string + offset, message_string_size - offset, "%X [%u] ", frame.ID, frame.DLC); - - // Add data bytes - for (uint8_t i = 0; i < frame.DLC; i++) { - if (i < frame.DLC - 1) { - offset += snprintf(message_string + offset, message_string_size - offset, "%02X ", frame.data.u8[i]); - } else { - offset += snprintf(message_string + offset, message_string_size - offset, "%02X", frame.data.u8[i]); - } - } - // Add linebreak - offset += snprintf(message_string + offset, message_string_size - offset, "\n"); - - datalayer.system.info.logged_can_messages_offset = offset; // Update offset in buffer + dump_can_frame(frame, msgDir); } } @@ -351,37 +320,37 @@ void map_can_frame_to_variable(CAN_frame* rx_frame, int interface) { #endif } } -void dump_frame(CAN_frame &frame, frameDirection msgDir){ - char* message_string = datalayer.system.info.logged_can_messages; - int offset = datalayer.system.info.logged_can_messages_offset; // Keeps track of the current position in the buffer - size_t message_string_size = sizeof(datalayer.system.info.logged_can_messages); +void dump_can_frame(CAN_frame &frame, frameDirection msgDir) { + char* message_string = datalayer.system.info.logged_can_messages; + int offset = datalayer.system.info.logged_can_messages_offset; // Keeps track of the current position in the buffer + size_t message_string_size = sizeof(datalayer.system.info.logged_can_messages); - if (offset + 128 > sizeof(datalayer.system.info.logged_can_messages)) { - // Not enough space, reset and start from the beginning - offset = 0; + if (offset + 128 > sizeof(datalayer.system.info.logged_can_messages)) { + // Not enough space, reset and start from the beginning + offset = 0; + } + unsigned long currentTime = millis(); + // Add timestamp + offset += snprintf(message_string + offset, message_string_size - offset, "(%lu.%03lu) ", currentTime / 1000, + currentTime % 1000); + + // Add direction. The 0 and 1 after RX and TX ensures that SavvyCAN puts TX and RX in a different bus. + offset += + snprintf(message_string + offset, message_string_size - offset, "%s ", (msgDir == MSG_RX) ? "RX0" : "TX1"); + + // Add ID and DLC + offset += snprintf(message_string + offset, message_string_size - offset, "%X [%u] ", frame.ID, frame.DLC); + + // Add data bytes + for (uint8_t i = 0; i < frame.DLC; i++) { + if (i < frame.DLC - 1) { + offset += snprintf(message_string + offset, message_string_size - offset, "%02X ", frame.data.u8[i]); + } else { + offset += snprintf(message_string + offset, message_string_size - offset, "%02X", frame.data.u8[i]); } - unsigned long currentTime = millis(); - // Add timestamp - offset += snprintf(message_string + offset, message_string_size - offset, "(%lu.%03lu) ", currentTime / 1000, - currentTime % 1000); + } + // Add linebreak + offset += snprintf(message_string + offset, message_string_size - offset, "\n"); - // Add direction. The 0 and 1 after RX and TX ensures that SavvyCAN puts TX and RX in a different bus. - offset += - snprintf(message_string + offset, message_string_size - offset, "%s ", (msgDir == MSG_RX) ? "RX0" : "TX1"); - - // Add ID and DLC - offset += snprintf(message_string + offset, message_string_size - offset, "%X [%u] ", frame.ID, frame.DLC); - - // Add data bytes - for (uint8_t i = 0; i < frame.DLC; i++) { - if (i < frame.DLC - 1) { - offset += snprintf(message_string + offset, message_string_size - offset, "%02X ", frame.data.u8[i]); - } else { - offset += snprintf(message_string + offset, message_string_size - offset, "%02X", frame.data.u8[i]); - } - } - // Add linebreak - offset += snprintf(message_string + offset, message_string_size - offset, "\n"); - - datalayer.system.info.logged_can_messages_offset = offset; // Update offset in buffer + datalayer.system.info.logged_can_messages_offset = offset; // Update offset in buffer } diff --git a/Software/src/communication/can/comm_can.h b/Software/src/communication/can/comm_can.h index 2a1ac1a8..f0921ac5 100644 --- a/Software/src/communication/can/comm_can.h +++ b/Software/src/communication/can/comm_can.h @@ -15,7 +15,7 @@ #include "../../lib/pierremolinaro-ACAN2517FD/ACAN2517FD.h" #endif //CANFD_ADDON -void dump_frame(CAN_frame &frame, frameDirection msgDir); +void dump_can_frame(CAN_frame &frame, frameDirection msgDir); /** * @brief Initialization function for CAN. diff --git a/Software/src/communication/can/obd.cpp b/Software/src/communication/can/obd.cpp new file mode 100644 index 00000000..c3723b63 --- /dev/null +++ b/Software/src/communication/can/obd.cpp @@ -0,0 +1,151 @@ +#include "obd.h" +#include "comm_can.h" + +void show_dtc(uint8_t byte0, uint8_t byte1); + +void show_dtc(uint8_t byte0, uint8_t byte1) { + char letter; + switch (byte0 >> 6){ + case 0: + letter = 'P'; + break; + case 1: + letter = 'C'; + break; + case 2: + letter = 'B'; + break; + case 3: + letter = 'U'; + break; + } + logging.printf("%c%d\n", letter, ((byte0 & 0x3F) << 8) | byte1); +} + +void handle_obd_frame(CAN_frame &rx_frame) { + if (rx_frame.data.u8[1] == 0x7F) { + const char *error_str = "?"; + switch (rx_frame.data.u8[3]) { // See https://automotive.wiki/index.php/ISO_14229 + case 0x10: + error_str = "generalReject"; + break; + case 0x11: + error_str = "serviceNotSupported"; + break; + case 0x12: + error_str = "subFunctionNotSupported"; + break; + case 0x13: + error_str = "incorrectMessageLengthOrInvalidFormat"; + break; + case 0x14: + error_str = "responseTooLong"; + break; + case 0x21: + error_str = "busyRepeatReques"; + break; + case 0x22: + error_str = "conditionsNotCorrect"; + break; + case 0x24: + error_str = "requestSequenceError"; + break; + case 0x31: + error_str = "requestOutOfRange"; + break; + case 0x33: + error_str = "securityAccessDenied"; + break; + case 0x35: + error_str = "invalidKey"; + break; + case 0x36: + error_str = "exceedNumberOfAttempts"; + break; + case 0x37: + error_str = "requiredTimeDelayNotExpired"; + break; + case 0x70: + error_str = "uploadDownloadNotAccepted"; + break; + case 0x71: + error_str = "transferDataSuspended"; + break; + case 0x72: + error_str = "generalProgrammingFailure"; + break; + case 0x73: + error_str = "wrongBlockSequenceCounter"; + break; + case 0x78: + error_str = "requestCorrectlyReceived-ResponsePending"; + break; + case 0x7E: + error_str = "subFunctionNotSupportedInActiveSession"; + break; + case 0x7F: + error_str = "serviceNotSupportedInActiveSession"; + break; + + } + logging.printf("ODB reply Request for service 0x%02X: %s\n", rx_frame.data.u8[2], error_str); + } else { + switch (rx_frame.data.u8[1] & 0x3F) { + case 3: + logging.printf("ODB reply service 03: Show stored DTCs, %d present:\n", rx_frame.data.u8[2]); + for (int i = 0; i < rx_frame.data.u8[2]; i++) + show_dtc(rx_frame.data.u8[3+2*i], rx_frame.data.u8[4+2*i]); + break; + case 7: + logging.printf("ODB reply service 07: Show pending DTCs, %d present:\n", rx_frame.data.u8[2]); + for (int i = 0; i < rx_frame.data.u8[2]; i++) + show_dtc(rx_frame.data.u8[3+2*i], rx_frame.data.u8[4+2*i]); + break; + default: + logging.printf("ODBx reply frame received:\n"); + } + } + dump_can_frame(rx_frame, MSG_RX); +} + +void transmit_obd_can_frame(unsigned int address, int interface){ + static CAN_frame OBD_frame = {.FD = true, + .ext_ID = false, + .DLC = 8, + .ID = 0x700, + .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; + OBD_frame.ID = address; + OBD_frame.ext_ID = address > 0x7FF; + OBD_frame.DLC = 8; + OBD_frame.data.u8[0]=0x01; + OBD_frame.data.u8[1]=0x03; + OBD_frame.data.u8[2]=0xAA; + OBD_frame.data.u8[3]=0xAA; + OBD_frame.data.u8[4]=0xAA; + OBD_frame.data.u8[5]=0xAA; + OBD_frame.data.u8[6]=0xAA; + OBD_frame.data.u8[7]=0xAA; + static int cnt = 0; + switch (cnt) { + case 2: + transmit_can_frame(&OBD_frame, interface); // DTC TP-ISO + break; + case 3: + OBD_frame.data.u8[1]=0x07; + transmit_can_frame(&OBD_frame, interface); // DTC TP-ISO + break; + case 4: + OBD_frame.data.u8[1]=0x0A; + transmit_can_frame(&OBD_frame, interface); // DTC TP-ISO + break; + case 5: + OBD_frame.data.u8[0]=0x02; + OBD_frame.data.u8[1]=0x01; + OBD_frame.data.u8[2]=0x1C; + transmit_can_frame(&OBD_frame, interface); // DTC TP-ISO + break; + } + cnt++; + if (cnt == 3600) + cnt = 0; +} diff --git a/Software/src/communication/can/obd.h b/Software/src/communication/can/obd.h new file mode 100644 index 00000000..0d2a063b --- /dev/null +++ b/Software/src/communication/can/obd.h @@ -0,0 +1,11 @@ +#ifndef _OBD_H_ +#define _OBD_H_ + +#include "../../include.h" +#include "../../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" + +void handle_obd_frame(CAN_frame &rx_frame); + +void transmit_obd_can_frame(unsigned int address, int interface); + +#endif // _OBD_H_