Skip to content

Thunderstruck: Update CAN handler for Thunderstruck#2144

Open
dalathegreat wants to merge 4 commits intomainfrom
bugfix/thunderstruck-CAN
Open

Thunderstruck: Update CAN handler for Thunderstruck#2144
dalathegreat wants to merge 4 commits intomainfrom
bugfix/thunderstruck-CAN

Conversation

@dalathegreat
Copy link
Copy Markdown
Owner

What

This PR improves the J1939_MCU_ReadRequest handling

Why

User feedback, initial implementation did not work

How

We follow the newer v1.3.4 protocol

@veriqster
Copy link
Copy Markdown

veriqster commented Mar 18, 2026

Hi,
I tried the new file and it has the same issue as the one I compiled localy before the Thunderstruck was pulled into the Main - it doesn't save any changes in the configuration.
On the positive side, it does show that we are transmitting a variety of messages.
On the negative side, I'm not receiving any reply from MCU and I think this is dues to sending the wrong messages. It inrder to get the MCU to respond we need the FF in the message sent as seen in the png with the initial testing CAN logger
I am attaching the original testing png screenshot, the text with the current CAN log (16-51) and the text with the current putty "trace" log.
Also attaching previous CAN log (34-10 and 59-58)

This is the recommendation from Thunderstruck :

"

I was wondering if the "not locked" is reported as an "error" by the MCU
Correct.

in which case it would explain why the Emulator reports the battery as being in "fault" state.
This really just depends on how the implementation is programmed. The MCU doesnt really give a single "fault state" but just gives all of the faults discretely in the "Summary" message (0xff20).
I certainly would consider "not locked" a fault, including all of the other flags in the Summary message.

The .dbc should make it pretty clear what is where, but heres a list of the more important messages:

Summary Message (0xff20)
-general states
-fault map

Pack Summary (0xff21)
-Pack Voltage
-Pack Current

Cell Summary (0xff22)
-Lowest/Highest/Mean cell voltage

Thermistor Summray (0xff23)
-highest/lowest thermistor values

SOC Summary (0xff24)
-SOC
-Max Energy (kwh)
-Remaining Energy (kwh)

Current Limits Summary (0xff25)
-Discharge Current Limit
-Charge Current Limit
-Attribution (the reason) for the limits

Power Limits Summary (0xff28)
-Discharge Power Limit (0.01 kw)
-Charge Power Limit (0.01 kw)

I can do a full code review another time.. Even though it is short a full review requires me to fully understand how the system works with a BMS as well as make sure there arent any dangerous edge cases. For now, here are a few things I see in my once over.

  1. static const int MAX_CELL_VOLTAGE_MV = 3800; //Battery is put into emergency stop if one cell goes over this value
    static const int MIN_CELL_VOLTAGE_MV = 2700; //Battery is put into emergency stop if one cell goes below this value

Dont hard-code this... It is fine to grab things like cell voltage and temperature for telemetry - but fault handling should be done by the MCU. Look at things like the fault map (HVC and LVC specifically in this case) so that the MCU can handle all the faults itself. This way we arent relying on the emulator implementation to handle all the lithium safety stuff, and the MCU can be configured for different cells/packs without having to modify the emulator configuration.

  1. Power Limits
    It looks like you are evaluating power limits by multiplying current limits by voltage - it is best not to do this, since pack resistance can throw this simple calculation off. The MCU provides power limits that take resistance into account so it is best to use this directly if you need power limits.

  2. Overall timeouts
    This is one of the harder things to do... You need to make sure that if any of the important information (primarily 0xff20) is not being received successfully that the emulator needs to throw a fault.

Kelan

"

canlog_00-34-20.txt
canlog_00-59-58.txt

canlog_00-16-51.txt
Putty 03_18_2026.txt

Comment thread Software/src/battery/THUNDERSTRUCK-BMS.cpp
Comment thread Software/src/battery/THUNDERSTRUCK-BMS.cpp Outdated
@dalathegreat
Copy link
Copy Markdown
Owner Author

Hi @veriqster

I have fixed the "I tried the new file and it has the same issue as the one I compiled localy before the Thunderstruck was pulled into the Main - it doesn't save any changes in the configuration."

Main was broken, but 10.4.dev is now fixed. I just pulled new main into the branch, so now if you re-test, it will work.

I also added back the 0xFF instead of 0x00

@veriqster
Copy link
Copy Markdown

I finally managed to compile a local one that allows saving the settings (redownloaded the code).
Is there any way to see which parameter triggered the "FAULT" state for the battery?

@dalathegreat
Copy link
Copy Markdown
Owner Author

@veriqster
Copy link
Copy Markdown

Got that.
Here's the event page:
image
Here's main page:
image

I modifies the cpp and h files for Thunderstruck to send the 14ebd0d8 message with 20 to 25 extensions.
It looks like we're getting replies but they are being "routed" incorrectly, the cell voltages and other data is definitely not what's reported on the MCU side.

I'm not good at figuring out that dbc file, can someone help with that or should I try to reach out again to Keelan?
CAN Logger file attached.
The battery consists of 4 A123 modules that are not wired in any way currently but configured as "wired in series" in the MCU, the MCU reports the "pack voltage" correctly in the Putty screen.

canlog_01-58-42+with_MultipleCAN.txt

@veriqster
Copy link
Copy Markdown

I loaded the log file into SavvyCAN and it looks like the MCU is sending the correct data as requested but the values are being mapped wrong into the Emulator.
I don't know how this data is processed but if we can figure this out I can test it and confirm if it works or not.

Below are the cpp and h files as I modified:
CPP:
"#include "THUNDERSTRUCK-BMS.h"
#include //For unit test
#include "../communication/can/comm_can.h"
#include "../datalayer/datalayer.h"
#include "../devboard/utils/events.h"

void ThunderstruckBMS::
update_values() { //This function maps all the values fetched via CAN to the correct parameters used for modbus

datalayer.battery.status.real_soc = (SOC * 100); //increase SOC range from 0-100 -> 100.00

datalayer.battery.status.soh_pptt = 9900; //Not in CAN data, hardcoded to 99%

datalayer.battery.status.voltage_dV = packvoltage_dV;

datalayer.battery.status.current_dA = pack_curent_dA;

datalayer.battery.status.remaining_capacity_Wh = static_cast<uint32_t>(
(static_cast(datalayer.battery.status.real_soc) / 10000) * datalayer.battery.info.total_capacity_Wh);

datalayer.battery.status.max_discharge_power_W = DCLMax * (packvoltage_dV / 10);

datalayer.battery.status.max_charge_power_W = CCLMax * (packvoltage_dV / 10);

datalayer.battery.status.cell_max_voltage_mV = highest_cell_voltage / 10;

datalayer.battery.status.cell_min_voltage_mV = lowest_cell_voltage / 10;

datalayer.battery.status.temperature_min_dC = lowest_cell_temperature * 10;

datalayer.battery.status.temperature_max_dC = highest_cell_temperature * 10;
}

void ThunderstruckBMS::handle_incoming_can_frame(CAN_frame rx_frame) {
switch (rx_frame.ID) {
case 0x14ffcfd0: // Temperatures
case 0x14ffced0:
case 0x14ffcdd0:
case 0x14ffccd0:
case 0x14ffcbd0:
case 0x14ffcad0:
case 0x14ffc9d0:
case 0x14ffc8d0:
case 0x14ffc7d0:
case 0x14ffc6d0:
case 0x14ffc5d0:
case 0x14ffc4d0:
case 0x14ffc3d0:
case 0x14ffc2d0:
case 0x14ffc1d0:
case 0x14ffc0d0:
//Mux = frame0
//ID = 0-F
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x14ffafd0: // Cellvoltages
case 0x14ffaed0:
case 0x14ffadd0:
case 0x14ffacd0:
case 0x14ffabd0:
case 0x14ffaad0:
case 0x14ffa9d0:
case 0x14ffa8d0:
case 0x14ffa7d0:
case 0x14ffa6d0:
case 0x14ffa5d0:
case 0x14ffa4d0:
case 0x14ffa3d0:
case 0x14ffa2d0:
case 0x14ffa1d0:
case 0x14ffa0d0:
//Mux = frame0
//ID = 0-F
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x14ff27d0: //Cell internal resistance
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x14ff26d0: //OCV
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x14ff25d0: //DCL / CCL
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
DCLMin = ((rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]);
CCLMin = ((rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]);
DCLMax = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]);
CCLMax = ((rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]);
break;
case 0x14ff24d0: //SOC
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
SOC = rx_frame.data.u8[1];
break;
case 0x14ff23d0: //Minmax temperatures
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
lowest_cell_temperature = rx_frame.data.u8[2];
highest_cell_temperature = rx_frame.data.u8[3];
break;
case 0x14ff22d0: //Minmax cellvoltages
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
lowest_cell_voltage = ((rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]);
highest_cell_voltage = ((rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]);
break;
case 0x14ff21d0: //Packvoltage
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
packvoltage_dV = ((rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]);
pack_curent_dA = (int16_t)((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]);
break;
case 0x14ff20d0: //Active faults
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x14ff1ad0: //GM12-15
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x14ff19d0: //GM11-9
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x14ff18d0: //GM0-5
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x14ff12d0: //HVCC, LVCC
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x14ff11d0: //HVC LVC
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x14ff10d0: //Firmware version
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x14ff06d0: //Float status
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x14ff05d0: //Finishing status
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x14ff04d0: //Charger status
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x14ff03d0: //Line EVSE wait
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x14ff02d0: //Max status
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x14ff01d0: //Charger Model
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x14ff00d0: //Balancing status
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
default:
break;
}
}
void ThunderstruckBMS::transmit_can(unsigned long currentMillis) {

// Send 500ms CAN Message
if (currentMillis - previousMillis500 >= INTERVAL_500_MS) {
previousMillis500 = currentMillis;

transmit_can_frame(&THUND_14ebd0d8_20);
//TODO, should 14ebd0d8 be sent also?
transmit_can_frame(&THUND_14ebd0d8_21);
transmit_can_frame(&THUND_14ebd0d8_22);
transmit_can_frame(&THUND_14ebd0d8_23);
transmit_can_frame(&THUND_14ebd0d8_24);
transmit_can_frame(&THUND_14ebd0d8_25);

}
}

void ThunderstruckBMS::setup(void) { // Performs one time setup at startup
strncpy(datalayer.system.info.battery_protocol, Name, 63);
datalayer.system.info.battery_protocol[63] = '\0';
datalayer.battery.info.number_of_cells = 96;
datalayer.system.status.battery_allows_contactor_closing = true;
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV;
datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV;
datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV;
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
}
"
H
"
#ifndef THUNDERSTRUCK_BMS_H
#define THUNDERSTRUCK_BMS_H

#include "CanBattery.h"

class ThunderstruckBMS : public CanBattery {
public:
virtual void setup(void);
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
virtual void update_values();
virtual void transmit_can(unsigned long currentMillis);
static constexpr const char* Name = "Thunderstruck BMS";

private:
static const int MAX_PACK_VOLTAGE_DV = 5000; //5000 = 500.0V
static const int MIN_PACK_VOLTAGE_DV = 2500;
static const int MAX_CELL_DEVIATION_MV = 250;
static const int MAX_CELL_VOLTAGE_MV = 3800; //Battery is put into emergency stop if one cell goes over this value
static const int MIN_CELL_VOLTAGE_MV = 2700; //Battery is put into emergency stop if one cell goes below this value

unsigned long previousMillis500 = 0; // will store last time a 500ms CAN Message was send

uint16_t lowest_cell_voltage = 3700;
uint16_t highest_cell_voltage = 3700;
uint16_t packvoltage_dV = 3700;
uint16_t DCLMin = 0;
uint16_t CCLMin = 0;
uint16_t DCLMax = 0;
uint16_t CCLMax = 0;

int16_t pack_curent_dA = 0;

uint8_t SOC = 50;

int8_t highest_cell_temperature = 0;
int8_t lowest_cell_temperature = 0;

CAN_frame THUND_14ebd0d8_21 = {.FD = false,
.ext_ID = true,
.DLC = 8,
.ID = 0x14ebd0d8,
.data = {0x21, 0xff, 0x0a, 0x08, 0x00, 0x00, 0x00, 0x00}};

CAN_frame THUND_14ebd0d8_20 = {.FD = false,
                          .ext_ID = true,
                          .DLC = 8,
                          .ID = 0x14ebd0d8,
                          .data = {0x20, 0xff, 0x0a, 0x08, 0x00, 0x00, 0x00, 0x00}};
CAN_frame THUND_14ebd0d8_25 = {.FD = false,
                          .ext_ID = true,
                          .DLC = 8,
                          .ID = 0x14ebd0d8,
                          .data = {0x25, 0xff, 0x0a, 0x08, 0x00, 0x00, 0x00, 0x00}};
CAN_frame THUND_14ebd0d8_24 = {.FD = false,
                          .ext_ID = true,
                          .DLC = 8,
                          .ID = 0x14ebd0d8,
                          .data = {0x24, 0xff, 0x0a, 0x08, 0x00, 0x00, 0x00, 0x00}};
CAN_frame THUND_14ebd0d8_23 = {.FD = false,
                          .ext_ID = true,
                          .DLC = 8,
                          .ID = 0x14ebd0d8,
                          .data = {0x23, 0xff, 0x0a, 0x08, 0x00, 0x00, 0x00, 0x00}};
CAN_frame THUND_14ebd0d8_22 = {.FD = false,
                          .ext_ID = true,
                          .DLC = 8,
                          .ID = 0x14ebd0d8,
                          .data = {0x22, 0xff, 0x0a, 0x08, 0x00, 0x00, 0x00, 0x00}};

};

#endif
"
Attached are the text files with the decoding by SavvyCAN.
CAN_Savvy_Decoding_Cell_Summary.txt
CAN_Savvy_Decoding_MCU_Summary.txt
CAN_Savvy_Decoding_Pack_Summary.txt
CAN_Savvy_Decoding_SOC_Summary.txt
CAN_Savvy_Decoding_Therm_Summary.txt

@veriqster
Copy link
Copy Markdown

I will retest tomorrow as I went through the code and at least to my limited understanding the handling of the messages from MCU looks correct (I know nothing about bit shifting).

@veriqster
Copy link
Copy Markdown

I updated the CAN handler to work LSB | MSB byte wise and IT WORKS.
Also added the requests for cell summary and discharge / charge KW limits but the MCU is not sending those, I guess maybe it's "running out of time" based on the setting for the CAN messages.
Below are the cpp and h files as modified by me and a screenshot of the Emulator webpage and the Putty with the MCU received CAN frames.
Can anyone assist with figuring out how to change the CAN READ Requests so the MCU reports back all the requested data?
Is it safe at this point to wire things up with contactors and connect the battery to inverter for further testing (under constant supervision, I don't plant to leave it unattended until things are figured out).
Attached is the CAN Log from Emulator
canlog_21-46-57_Cell_Request.txt

H:

"
#ifndef THUNDERSTRUCK_BMS_H
#define THUNDERSTRUCK_BMS_H

#include "CanBattery.h"

class ThunderstruckBMS : public CanBattery {
public:
virtual void setup(void);
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
virtual void update_values();
virtual void transmit_can(unsigned long currentMillis);
static constexpr const char* Name = "Thunderstruck BMS";

private:
static const int MAX_PACK_VOLTAGE_DV = 5000; //5000 = 500.0V
static const int MIN_PACK_VOLTAGE_DV = 2500;
static const int MAX_CELL_DEVIATION_MV = 250;
static const int MAX_CELL_VOLTAGE_MV = 3800; //Battery is put into emergency stop if one cell goes over this value
static const int MIN_CELL_VOLTAGE_MV = 2700; //Battery is put into emergency stop if one cell goes below this value

unsigned long previousMillis500 = 0; // will store last time a 500ms CAN Message was send

uint16_t lowest_cell_voltage = 3700;
uint16_t highest_cell_voltage = 3700;
uint16_t packvoltage_dV = 3700;
uint16_t DCLMin = 0;
uint16_t CCLMin = 0;
uint16_t DCLMax = 0;
uint16_t CCLMax = 0;

int16_t pack_curent_dA = 0;

uint8_t SOC = 50;

int8_t highest_cell_temperature = 0;
int8_t lowest_cell_temperature = 0;

  CAN_frame THUND_14ebd0d8_25 = {.FD = false,
                          .ext_ID = true,
                          .DLC = 8,
                          .ID = 0x14ebd0d8,
                          .data = {0x25, 0xff, 0x0a, 0x01, 0x00, 0x00, 0x00, 0x00}};
CAN_frame THUND_14ebd0d8_24 = {.FD = false,
                          .ext_ID = true,
                          .DLC = 8,
                          .ID = 0x14ebd0d8,
                          .data = {0x24, 0xff, 0x0a, 0x01, 0x00, 0x00, 0x00, 0x00}};
CAN_frame THUND_14ebd0d8_23 = {.FD = false,
                          .ext_ID = true,
                          .DLC = 8,
                          .ID = 0x14ebd0d8,
                          .data = {0x23, 0xff, 0x0a, 0x01, 0x00, 0x00, 0x00, 0x00}};
CAN_frame THUND_14ebd0d8_22 = {.FD = false,
                          .ext_ID = true,
                          .DLC = 8,
                          .ID = 0x14ebd0d8,
                          .data = {0x22, 0xff, 0x0a, 0x01, 0x00, 0x00, 0x00, 0x00}};
CAN_frame THUND_14ebd0d8_21 = {.FD = false,
                          .ext_ID = true,
                          .DLC = 8,
                          .ID = 0x14ebd0d8,
                          .data = {0x21, 0xff, 0x0a, 0x01, 0x00, 0x00, 0x00, 0x00}};

CAN_frame THUND_14ebd0d8_20 = {.FD = false,
                          .ext_ID = true,
                          .DLC = 8,
                          .ID = 0x14ebd0d8,
                          .data = {0x20, 0xff, 0x0a, 0x01, 0x00, 0x00, 0x00, 0x00}};
CAN_frame THUND_14ebd0d8_30 = {.FD = false,
                          .ext_ID = true,
                          .DLC = 8,
                          .ID = 0x14ebd0d8,
                          .data = {0x30, 0xff, 0x0a, 0x01, 0x00, 0x00, 0x00, 0x00}};
CAN_frame THUND_14ebd0d8_31 = {.FD = false,
                          .ext_ID = true,
                          .DLC = 8,
                          .ID = 0x14ebd0d8,
                          .data = {0x31, 0xff, 0x0a, 0x01, 0x00, 0x00, 0x00, 0x00}};

};

#endif
"

CPP:

"
#include "THUNDERSTRUCK-BMS.h"
#include //For unit test
#include "../communication/can/comm_can.h"
#include "../datalayer/datalayer.h"
#include "../devboard/utils/events.h"

void ThunderstruckBMS::
update_values() { //This function maps all the values fetched via CAN to the correct parameters used for modbus

datalayer.battery.status.real_soc = (SOC * 100); //increase SOC range from 0-100 -> 100.00

datalayer.battery.status.soh_pptt = 9900; //Not in CAN data, hardcoded to 99%

datalayer.battery.status.voltage_dV = packvoltage_dV;

datalayer.battery.status.current_dA = pack_curent_dA;

datalayer.battery.status.remaining_capacity_Wh = static_cast<uint32_t>(
(static_cast(datalayer.battery.status.real_soc) / 10000) * datalayer.battery.info.total_capacity_Wh);

datalayer.battery.status.max_discharge_power_W = DCLMax * (packvoltage_dV / 10);

datalayer.battery.status.max_charge_power_W = CCLMax * (packvoltage_dV / 10);

datalayer.battery.status.cell_max_voltage_mV = highest_cell_voltage / 10;

datalayer.battery.status.cell_min_voltage_mV = lowest_cell_voltage / 10;

datalayer.battery.status.temperature_min_dC = lowest_cell_temperature * 10;

datalayer.battery.status.temperature_max_dC = highest_cell_temperature * 10;
}

void ThunderstruckBMS::handle_incoming_can_frame(CAN_frame rx_frame) {
switch (rx_frame.ID) {
case 0x14ffcfd0: // Temperatures
case 0x14ffced0:
case 0x14ffcdd0:
case 0x14ffccd0:
case 0x14ffcbd0:
case 0x14ffcad0:
case 0x14ffc9d0:
case 0x14ffc8d0:
case 0x14ffc7d0:
case 0x14ffc6d0:
case 0x14ffc5d0:
case 0x14ffc4d0:
case 0x14ffc3d0:
case 0x14ffc2d0:
case 0x14ffc1d0:
case 0x14ffc0d0:
//Mux = frame0
//ID = 0-F
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x14ffafd0: // Cellvoltages
case 0x14ffaed0:
case 0x14ffadd0:
case 0x14ffacd0:
case 0x14ffabd0:
case 0x14ffaad0:
case 0x14ffa9d0:
case 0x14ffa8d0:
case 0x14ffa7d0:
case 0x14ffa6d0:
case 0x14ffa5d0:
case 0x14ffa4d0:
case 0x14ffa3d0:
case 0x14ffa2d0:
case 0x14ffa1d0:
case 0x14ffa0d0:
//Mux = frame0
//ID = 0-F
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x14ff27d0: //Cell internal resistance
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x14ff26d0: //OCV
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x14ff25d0: //DCL / CCL / Discharge/Charge Current Limits
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
DCLMin = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]);
CCLMin = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]);
DCLMax = ((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4]);
CCLMax = ((rx_frame.data.u8[7] << 8) | rx_frame.data.u8[6]);
break;
case 0x14ff24d0: //SOC
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
SOC = rx_frame.data.u8[1];
break;
case 0x14ff23d0: //Minmax temperatures
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
lowest_cell_temperature = rx_frame.data.u8[2];
highest_cell_temperature = rx_frame.data.u8[3];
break;
case 0x14ff22d0: //Minmax cellvoltages
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
lowest_cell_voltage = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]);
highest_cell_voltage = ((rx_frame.data.u8[7] << 8) | rx_frame.data.u8[6]);
break;
case 0x14ff21d0: //Packvoltage
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
packvoltage_dV = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]);
pack_curent_dA = (int16_t)((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4]);
break;
case 0x14ff20d0: //Active faults
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x14ff1ad0: //GM12-15
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x14ff19d0: //GM11-9
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x14ff18d0: //GM0-5
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x14ff12d0: //HVCC, LVCC
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x14ff11d0: //HVC LVC
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x14ff10d0: //Firmware version
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x14ff06d0: //Float status
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x14ff05d0: //Finishing status
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x14ff04d0: //Charger status
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x14ff03d0: //Line EVSE wait
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x14ff02d0: //Max status
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x14ff01d0: //Charger Model
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
case 0x14ff00d0: //Balancing status
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
break;
default:
break;
}
}
void ThunderstruckBMS::transmit_can(unsigned long currentMillis) {

// Send 500ms CAN Message
if (currentMillis - previousMillis500 >= INTERVAL_500_MS) {
previousMillis500 = currentMillis;

transmit_can_frame(&THUND_14ebd0d8_20);
//TODO, should 14ebd0d8 be sent also?
transmit_can_frame(&THUND_14ebd0d8_21);
transmit_can_frame(&THUND_14ebd0d8_22);
transmit_can_frame(&THUND_14ebd0d8_23);
transmit_can_frame(&THUND_14ebd0d8_24);
transmit_can_frame(&THUND_14ebd0d8_25);
transmit_can_frame(&THUND_14ebd0d8_30);
transmit_can_frame(&THUND_14ebd0d8_31);

}
}

void ThunderstruckBMS::setup(void) { // Performs one time setup at startup
strncpy(datalayer.system.info.battery_protocol, Name, 63);
datalayer.system.info.battery_protocol[63] = '\0';
datalayer.battery.info.number_of_cells = 96;
datalayer.system.status.battery_allows_contactor_closing = true;
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV;
datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV;
datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV;
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
}
"
image

image

@veriqster
Copy link
Copy Markdown

I updated the CPP and H files.
It fixes the MCU responding to only 2 of the info requests.
Had to modify another file that defines the "INTERVAL"s.
I basically spaced the requests that are sent to the MCU and am sending them in pairs.
This causes the MCU to respond much better but it is still NOT providing all the info that I'm requesting. It is only providing the "20 through 24" info packets but not the 25 or anything above.
I reached out to Thunderstruck and am hoping for a response but if someone can have a look and see if I'm doing something wrong based on the files attached and the MCU DBC file I'd highly appreciate it.
CPP, H and CAN Log files attached as a zip file.
Currently I'm not sure that the unit can be marked as "SUPPORTED" as the charge and discharge current limits are NOT reported by the MCU (Message 25). I tried moving it to the "front of the line" but that doesn't fix the issue.
Thunderstruck_CPP_H_CAN_Log.zip

@dalathegreat
Copy link
Copy Markdown
Owner Author

Thanks for the investigation @veriqster , and I agree with your asessment, we need some input from Thunderstruck on how to proceed. Anyways, I also updated the PR with your findings on the byteorder. So we are a bit closer atleast!

@veriqster
Copy link
Copy Markdown

Got a response from Thunderstruck.
Part of the issues is that the firmware on my unit was quite old. After update I'm able to get a response from the MCU for the 20, 21, 22, 23, 24, 25, 27 inquiries.
Now it's all a matter of figuring out how to map all those values to the appropriate variables in the Emulator.
I'm attaching the CAN log for that.
The other issue with my unit is that it's possible that without a current sensor attached to the MCU the MCU would not report or even compute certain values that we are trying to bring over. I have an Isabellenhutte on order and will wire it up over the next couple of days. Hopefully after that we can get all the data needed to make this work.

I would also like some help with figuring out how the SIDs play into the "creation" of the EID for the CAN message. Looks like there's quite a few parameters and data types that can be obtained from the MCU but they are only described by EID and I'm not knowledgeable enough to see how modifying the SID of the message would affect the EID.
canlog_23-29-13.txtThank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants