Add multiframe polling and module temperatures

This commit is contained in:
Daniel Öster 2025-04-21 12:47:46 +03:00
parent cf71ec9de2
commit 3b51872aa0
4 changed files with 143 additions and 50 deletions

View file

@ -226,6 +226,8 @@ static uint16_t poll_cap_module_max = 0;
static uint16_t poll_cap_module_min = 0;
static uint16_t poll_unknown7 = 0;
static uint16_t poll_unknown8 = 0;
static int16_t poll_temperature[6] = {0};
#define TEMP_OFFSET 30 //TODO, not calibrated yet, best guess
void update_values_battery() { //This function maps all the values fetched via CAN to the correct parameters used for modbus
datalayer.battery.status.soh_pptt;
@ -250,14 +252,27 @@ void update_values_battery() { //This function maps all the values fetched via
datalayer.battery.status.max_charge_power_W;
datalayer.battery.status.temperature_min_dC = minimum_temperature * 10;
datalayer.battery.status.temperature_max_dC = maximum_temperature * 10;
datalayer.battery.status.cell_min_voltage_mV = maximum_cell_voltage - 10; //TODO: Fix once we have min value
datalayer.battery.status.cell_max_voltage_mV = maximum_cell_voltage;
// Initialize highest and lowest to the first element
maximum_temperature = poll_temperature[0];
minimum_temperature = poll_temperature[0];
// Iterate through the array to find the highest and lowest values
for (uint8_t i = 1; i < 6; ++i) {
if (poll_temperature[i] > maximum_temperature) {
maximum_temperature = poll_temperature[i];
}
if (poll_temperature[i] < minimum_temperature) {
minimum_temperature = poll_temperature[i];
}
}
datalayer.battery.status.temperature_min_dC = minimum_temperature * 10;
datalayer.battery.status.temperature_max_dC = maximum_temperature * 10;
if (HVIL_signal > 0) {
set_event(EVENT_HVIL_FAILURE, HVIL_signal);
} else {
@ -266,6 +281,7 @@ void update_values_battery() { //This function maps all the values fetched via
//Update webserver more battery info page
memcpy(datalayer_extended.geometryC.BatterySerialNumber, serialnumbers, sizeof(serialnumbers));
memcpy(datalayer_extended.geometryC.ModuleTemperatures, poll_temperature, sizeof(poll_temperature));
datalayer_extended.geometryC.soc = poll_soc;
datalayer_extended.geometryC.CC2voltage = poll_cc2_voltage;
datalayer_extended.geometryC.cellMaxVoltageNumber = poll_cell_max_voltage_number;
@ -374,11 +390,9 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
break;
case 0x351: //100ms (4A 31 71 B8 6E F8 84 00)
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
maximum_temperature = ((rx_frame.data.u8[6] / 2) - 40); //TODO, not confirmed
break;
case 0x352: //500ms (76 78 00 00 82 FF FF 00)
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
minimum_temperature = ((rx_frame.data.u8[4] / 2) - 40); //TODO, not confirmed
break;
case 0x353: //500ms (00 00 00 00 62 00 EA 5D) (car 00 00 00 00 00 00 E6 04)
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
@ -453,7 +467,10 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
case 0x7EA:
if (rx_frame.data.u8[0] == 0x10) { //Multiframe response, send ACK
transmit_can_frame(&GEELY_ACK, can_config.battery);
//Multiframe has the poll reply slightly different location
incoming_poll = (rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4];
}
if (rx_frame.data.u8[0] < 0x10) { //One line response
incoming_poll = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
switch (incoming_poll) {
@ -503,6 +520,31 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
default:
break;
}
}
switch (incoming_poll) //Multiframe response
{
case POLL_MULTI_TEMPS:
switch (rx_frame.data.u8[0]) {
case 0x10:
poll_temperature[0] = (rx_frame.data.u8[5] - TEMP_OFFSET);
poll_temperature[1] = (rx_frame.data.u8[6] - TEMP_OFFSET);
poll_temperature[2] = (rx_frame.data.u8[7] - TEMP_OFFSET);
break;
case 0x21:
poll_temperature[3] = (rx_frame.data.u8[1] - TEMP_OFFSET);
poll_temperature[4] = (rx_frame.data.u8[2] - TEMP_OFFSET);
poll_temperature[5] = (rx_frame.data.u8[3] - TEMP_OFFSET);
break;
default:
break;
}
break;
default:
//Not a multiframe response, do nothing
break;
}
break;
default:
break;
@ -674,6 +716,36 @@ void transmit_can_battery() {
case POLL_UNKNOWN_8:
GEELY_POLL.data.u8[2] = (uint8_t)(POLL_UNKNOWN_8 >> 8);
GEELY_POLL.data.u8[3] = (uint8_t)POLL_UNKNOWN_8;
poll_pid = POLL_MULTI_TEMPS;
break;
case POLL_MULTI_TEMPS:
GEELY_POLL.data.u8[2] = (uint8_t)(POLL_MULTI_TEMPS >> 8);
GEELY_POLL.data.u8[3] = (uint8_t)POLL_MULTI_TEMPS;
poll_pid = POLL_MULTI_UNKNOWN_2;
break;
case POLL_MULTI_UNKNOWN_2:
GEELY_POLL.data.u8[2] = (uint8_t)(POLL_MULTI_UNKNOWN_2 >> 8);
GEELY_POLL.data.u8[3] = (uint8_t)POLL_MULTI_UNKNOWN_2;
poll_pid = POLL_MULTI_UNKNOWN_3;
break;
case POLL_MULTI_UNKNOWN_3:
GEELY_POLL.data.u8[2] = (uint8_t)(POLL_MULTI_UNKNOWN_3 >> 8);
GEELY_POLL.data.u8[3] = (uint8_t)POLL_MULTI_UNKNOWN_3;
poll_pid = POLL_MULTI_UNKNOWN_4;
break;
case POLL_MULTI_UNKNOWN_4:
GEELY_POLL.data.u8[2] = (uint8_t)(POLL_MULTI_UNKNOWN_4 >> 8);
GEELY_POLL.data.u8[3] = (uint8_t)POLL_MULTI_UNKNOWN_4;
poll_pid = POLL_MULTI_UNKNOWN_5;
break;
case POLL_MULTI_UNKNOWN_5:
GEELY_POLL.data.u8[2] = (uint8_t)(POLL_MULTI_UNKNOWN_5 >> 8);
GEELY_POLL.data.u8[3] = (uint8_t)POLL_MULTI_UNKNOWN_5;
poll_pid = POLL_MULTI_UNKNOWN_6;
break;
case POLL_MULTI_UNKNOWN_6:
GEELY_POLL.data.u8[2] = (uint8_t)(POLL_MULTI_UNKNOWN_6 >> 8);
GEELY_POLL.data.u8[3] = (uint8_t)POLL_MULTI_UNKNOWN_6;
poll_pid = POLL_SOC;
break;
default:

View file

@ -25,6 +25,12 @@
#define POLL_CAPACITY_MODULE_MIN 0x4B3E
#define POLL_UNKNOWN_7 0x4B24 //1 (the other battery 23)
#define POLL_UNKNOWN_8 0x4B26 //16 (the other battery 33)
#define POLL_MULTI_TEMPS 0x4B0F
#define POLL_MULTI_UNKNOWN_2 0x4B10
#define POLL_MULTI_UNKNOWN_3 0x4B53
#define POLL_MULTI_UNKNOWN_4 0x4B54
#define POLL_MULTI_UNKNOWN_5 0x4B6B
#define POLL_MULTI_UNKNOWN_6 0x4B6C
void setup_battery(void);
void transmit_can_frame(CAN_frame* tx_frame, int interface);

View file

@ -276,6 +276,9 @@ typedef struct {
/** uint8_t */
/** Battery serial numbers, stores raw HEX values for ASCII chars */
uint8_t BatterySerialNumber[28] = {0};
/** int16_t */
/** Module temperatures 1-6 */
int16_t ModuleTemperatures[6] = {0};
/** uint16_t */
/** Various values polled via OBD2 PIDs */
uint16_t soc = 0;

View file

@ -476,6 +476,18 @@ String advanced_battery_processor(const String& var) {
content += "<h4>Capacity module min: " + String((datalayer_extended.geometryC.capModMin / 10)) + "Ah</h4>";
content += "<h4>Unknown7: " + String(datalayer_extended.geometryC.unknown7) + "</h4>";
content += "<h4>Unknown8: " + String(datalayer_extended.geometryC.unknown8) + "</h4>";
content +=
"<h4>Module 1 temperature: " + String(datalayer_extended.geometryC.ModuleTemperatures[0]) + " &deg;C</h4>";
content +=
"<h4>Module 2 temperature: " + String(datalayer_extended.geometryC.ModuleTemperatures[1]) + " &deg;C</h4>";
content +=
"<h4>Module 3 temperature: " + String(datalayer_extended.geometryC.ModuleTemperatures[2]) + " &deg;C</h4>";
content +=
"<h4>Module 4 temperature: " + String(datalayer_extended.geometryC.ModuleTemperatures[3]) + " &deg;C</h4>";
content +=
"<h4>Module 5 temperature: " + String(datalayer_extended.geometryC.ModuleTemperatures[4]) + " &deg;C</h4>";
content +=
"<h4>Module 6 temperature: " + String(datalayer_extended.geometryC.ModuleTemperatures[5]) + " &deg;C</h4>";
#endif //GEELY_GEOMETRY_C_BATTERY
#ifdef KIA_HYUNDAI_64_BATTERY