Skip to content

Commit

Permalink
Merge pull request #791 from dalathegreat/feature/automatic-precharge
Browse files Browse the repository at this point in the history
Fix MEB max 1A issue / Add automatic precharge / Add basic OBD functionality
  • Loading branch information
dalathegreat authored Jan 15, 2025
2 parents fceae63 + 1dcc6fe commit cb3713c
Show file tree
Hide file tree
Showing 18 changed files with 626 additions and 82 deletions.
11 changes: 11 additions & 0 deletions Software/Software.ino
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "src/communication/contactorcontrol/comm_contactorcontrol.h"
#include "src/communication/equipmentstopbutton/comm_equipmentstopbutton.h"
#include "src/communication/nvm/comm_nvm.h"
#include "src/communication/precharge_control/precharge_control.h"
#include "src/communication/rs485/comm_rs485.h"
#include "src/communication/seriallink/comm_seriallink.h"
#include "src/datalayer/datalayer.h"
Expand Down Expand Up @@ -120,6 +121,10 @@ void setup() {

init_contactors();

#ifdef PRECHARGE_CONTROL
init_precharge_control();
#endif // PRECHARGE_CONTROL

init_rs485();

init_serialDataLink();
Expand Down Expand Up @@ -247,6 +252,9 @@ void core_loop(void* task_time_us) {
previousMillis10ms = millis();
led_exe();
handle_contactors(); // Take care of startup precharge/contactor closing
#ifdef PRECHARGE_CONTROL
handle_precharge_control();
#endif // PRECHARGE_CONTROL
}
END_TIME_MEASUREMENT_MAX(time_10ms, datalayer.system.status.time_10ms_us);

Expand Down Expand Up @@ -298,6 +306,9 @@ void core_loop(void* task_time_us) {
if (check_pause_2s.elapsed()) {
emulator_pause_state_transmit_can_battery();
}
#ifdef DEBUG_LOG
logging.log_bms_status(datalayer.battery.status.real_bms_status, 1);
#endif

vTaskDelayUntil(&xLastWakeTime, xFrequency);
}
Expand Down
3 changes: 3 additions & 0 deletions Software/USER_SETTINGS.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@
/* Shunt/Contactor settings */
//#define BMW_SBOX // SBOX relay control & battery current/voltage measurement

/* Automatic Precharge settings. If you have a battery that expects an external voltage applied before opening contactors (within the battery), configure this section */
//#define PRECHARGE_CONTROL //Enable this line to control a modified HIA4V1 (see wiki) by PWM on the PRECHARGE_PIN.

/* Other options */
//#define LOG_TO_SD //Enable this line to log diagnostic data to SD card
//#define DEBUG_VIA_USB //Enable this line to have the USB port output serial diagnostic data while program runs (WARNING, raises CPU load, do not use for production)
Expand Down
157 changes: 131 additions & 26 deletions Software/src/battery/MEB-BATTERY.cpp

Large diffs are not rendered by default.

66 changes: 34 additions & 32 deletions Software/src/communication/can/comm_can.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand Down Expand Up @@ -351,3 +320,36 @@ void map_can_frame_to_variable(CAN_frame* rx_frame, int interface) {
#endif
}
}
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;
}
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
}
2 changes: 2 additions & 0 deletions Software/src/communication/can/comm_can.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#include "../../lib/pierremolinaro-ACAN2517FD/ACAN2517FD.h"
#endif //CANFD_ADDON

void dump_can_frame(CAN_frame& frame, frameDirection msgDir);

/**
* @brief Initialization function for CAN.
*
Expand Down
148 changes: 148 additions & 0 deletions Software/src/communication/can/obd.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
#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) {
#ifdef DEBUG_LOG
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);
#endif
}

void transmit_obd_can_frame(unsigned int address, int interface) {
static CAN_frame OBD_frame;
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;
}
11 changes: 11 additions & 0 deletions Software/src/communication/can/obd.h
Original file line number Diff line number Diff line change
@@ -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_
Loading

0 comments on commit cb3713c

Please sign in to comment.