mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-05 10:49:42 +02:00
Add multiframe polling and module temperatures
This commit is contained in:
parent
cf71ec9de2
commit
3b51872aa0
4 changed files with 143 additions and 50 deletions
|
@ -226,6 +226,8 @@ static uint16_t poll_cap_module_max = 0;
|
||||||
static uint16_t poll_cap_module_min = 0;
|
static uint16_t poll_cap_module_min = 0;
|
||||||
static uint16_t poll_unknown7 = 0;
|
static uint16_t poll_unknown7 = 0;
|
||||||
static uint16_t poll_unknown8 = 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
|
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;
|
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.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_min_voltage_mV = maximum_cell_voltage - 10; //TODO: Fix once we have min value
|
||||||
|
|
||||||
datalayer.battery.status.cell_max_voltage_mV = maximum_cell_voltage;
|
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) {
|
if (HVIL_signal > 0) {
|
||||||
set_event(EVENT_HVIL_FAILURE, HVIL_signal);
|
set_event(EVENT_HVIL_FAILURE, HVIL_signal);
|
||||||
} else {
|
} else {
|
||||||
|
@ -266,6 +281,7 @@ void update_values_battery() { //This function maps all the values fetched via
|
||||||
|
|
||||||
//Update webserver more battery info page
|
//Update webserver more battery info page
|
||||||
memcpy(datalayer_extended.geometryC.BatterySerialNumber, serialnumbers, sizeof(serialnumbers));
|
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.soc = poll_soc;
|
||||||
datalayer_extended.geometryC.CC2voltage = poll_cc2_voltage;
|
datalayer_extended.geometryC.CC2voltage = poll_cc2_voltage;
|
||||||
datalayer_extended.geometryC.cellMaxVoltageNumber = poll_cell_max_voltage_number;
|
datalayer_extended.geometryC.cellMaxVoltageNumber = poll_cell_max_voltage_number;
|
||||||
|
@ -374,11 +390,9 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
|
||||||
break;
|
break;
|
||||||
case 0x351: //100ms (4A 31 71 B8 6E F8 84 00)
|
case 0x351: //100ms (4A 31 71 B8 6E F8 84 00)
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
maximum_temperature = ((rx_frame.data.u8[6] / 2) - 40); //TODO, not confirmed
|
|
||||||
break;
|
break;
|
||||||
case 0x352: //500ms (76 78 00 00 82 FF FF 00)
|
case 0x352: //500ms (76 78 00 00 82 FF FF 00)
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
minimum_temperature = ((rx_frame.data.u8[4] / 2) - 40); //TODO, not confirmed
|
|
||||||
break;
|
break;
|
||||||
case 0x353: //500ms (00 00 00 00 62 00 EA 5D) (car 00 00 00 00 00 00 E6 04)
|
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;
|
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:
|
case 0x7EA:
|
||||||
if (rx_frame.data.u8[0] == 0x10) { //Multiframe response, send ACK
|
if (rx_frame.data.u8[0] == 0x10) { //Multiframe response, send ACK
|
||||||
transmit_can_frame(&GEELY_ACK, can_config.battery);
|
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];
|
incoming_poll = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
|
||||||
|
|
||||||
switch (incoming_poll) {
|
switch (incoming_poll) {
|
||||||
|
@ -503,6 +520,31 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
|
||||||
default:
|
default:
|
||||||
break;
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -674,6 +716,36 @@ void transmit_can_battery() {
|
||||||
case POLL_UNKNOWN_8:
|
case POLL_UNKNOWN_8:
|
||||||
GEELY_POLL.data.u8[2] = (uint8_t)(POLL_UNKNOWN_8 >> 8);
|
GEELY_POLL.data.u8[2] = (uint8_t)(POLL_UNKNOWN_8 >> 8);
|
||||||
GEELY_POLL.data.u8[3] = (uint8_t)POLL_UNKNOWN_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;
|
poll_pid = POLL_SOC;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -25,6 +25,12 @@
|
||||||
#define POLL_CAPACITY_MODULE_MIN 0x4B3E
|
#define POLL_CAPACITY_MODULE_MIN 0x4B3E
|
||||||
#define POLL_UNKNOWN_7 0x4B24 //1 (the other battery 23)
|
#define POLL_UNKNOWN_7 0x4B24 //1 (the other battery 23)
|
||||||
#define POLL_UNKNOWN_8 0x4B26 //16 (the other battery 33)
|
#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 setup_battery(void);
|
||||||
void transmit_can_frame(CAN_frame* tx_frame, int interface);
|
void transmit_can_frame(CAN_frame* tx_frame, int interface);
|
||||||
|
|
|
@ -276,6 +276,9 @@ typedef struct {
|
||||||
/** uint8_t */
|
/** uint8_t */
|
||||||
/** Battery serial numbers, stores raw HEX values for ASCII chars */
|
/** Battery serial numbers, stores raw HEX values for ASCII chars */
|
||||||
uint8_t BatterySerialNumber[28] = {0};
|
uint8_t BatterySerialNumber[28] = {0};
|
||||||
|
/** int16_t */
|
||||||
|
/** Module temperatures 1-6 */
|
||||||
|
int16_t ModuleTemperatures[6] = {0};
|
||||||
/** uint16_t */
|
/** uint16_t */
|
||||||
/** Various values polled via OBD2 PIDs */
|
/** Various values polled via OBD2 PIDs */
|
||||||
uint16_t soc = 0;
|
uint16_t soc = 0;
|
||||||
|
|
|
@ -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>Capacity module min: " + String((datalayer_extended.geometryC.capModMin / 10)) + "Ah</h4>";
|
||||||
content += "<h4>Unknown7: " + String(datalayer_extended.geometryC.unknown7) + "</h4>";
|
content += "<h4>Unknown7: " + String(datalayer_extended.geometryC.unknown7) + "</h4>";
|
||||||
content += "<h4>Unknown8: " + String(datalayer_extended.geometryC.unknown8) + "</h4>";
|
content += "<h4>Unknown8: " + String(datalayer_extended.geometryC.unknown8) + "</h4>";
|
||||||
|
content +=
|
||||||
|
"<h4>Module 1 temperature: " + String(datalayer_extended.geometryC.ModuleTemperatures[0]) + " °C</h4>";
|
||||||
|
content +=
|
||||||
|
"<h4>Module 2 temperature: " + String(datalayer_extended.geometryC.ModuleTemperatures[1]) + " °C</h4>";
|
||||||
|
content +=
|
||||||
|
"<h4>Module 3 temperature: " + String(datalayer_extended.geometryC.ModuleTemperatures[2]) + " °C</h4>";
|
||||||
|
content +=
|
||||||
|
"<h4>Module 4 temperature: " + String(datalayer_extended.geometryC.ModuleTemperatures[3]) + " °C</h4>";
|
||||||
|
content +=
|
||||||
|
"<h4>Module 5 temperature: " + String(datalayer_extended.geometryC.ModuleTemperatures[4]) + " °C</h4>";
|
||||||
|
content +=
|
||||||
|
"<h4>Module 6 temperature: " + String(datalayer_extended.geometryC.ModuleTemperatures[5]) + " °C</h4>";
|
||||||
#endif //GEELY_GEOMETRY_C_BATTERY
|
#endif //GEELY_GEOMETRY_C_BATTERY
|
||||||
|
|
||||||
#ifdef KIA_HYUNDAI_64_BATTERY
|
#ifdef KIA_HYUNDAI_64_BATTERY
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue