mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-04 18:29:48 +02:00
Merge branch 'main' into bugfix/SMA-voltages
This commit is contained in:
commit
3550881b65
223 changed files with 7435 additions and 4765 deletions
|
@ -1,17 +1,15 @@
|
|||
#include "../include.h"
|
||||
|
||||
#include "BATTERIES.h"
|
||||
#include "../datalayer/datalayer_extended.h"
|
||||
#include "CanBattery.h"
|
||||
#include "RS485Battery.h"
|
||||
|
||||
#if !defined(COMMON_IMAGE) && !defined(SELECTED_BATTERY_CLASS)
|
||||
#error No battery selected! Choose one from the USER_SETTINGS.h file
|
||||
#error No battery selected! Choose one from the USER_SETTINGS.h file or build COMMON_IMAGE.
|
||||
#endif
|
||||
|
||||
Battery* battery = nullptr;
|
||||
Battery* battery2 = nullptr;
|
||||
|
||||
#ifdef COMMON_IMAGE
|
||||
std::vector<BatteryType> supported_battery_types() {
|
||||
std::vector<BatteryType> types;
|
||||
|
||||
|
@ -22,7 +20,39 @@ std::vector<BatteryType> supported_battery_types() {
|
|||
return types;
|
||||
}
|
||||
|
||||
extern const char* name_for_battery_type(BatteryType type) {
|
||||
const char* name_for_chemistry(battery_chemistry_enum chem) {
|
||||
switch (chem) {
|
||||
case battery_chemistry_enum::LFP:
|
||||
return "LFP";
|
||||
case battery_chemistry_enum::NCA:
|
||||
return "NCA";
|
||||
case battery_chemistry_enum::NMC:
|
||||
return "NMC";
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const char* name_for_comm_interface(comm_interface comm) {
|
||||
switch (comm) {
|
||||
case comm_interface::Modbus:
|
||||
return "Modbus";
|
||||
case comm_interface::RS485:
|
||||
return "RS485";
|
||||
case comm_interface::CanNative:
|
||||
return "Native CAN";
|
||||
case comm_interface::CanFdNative:
|
||||
return "Native CAN FD";
|
||||
case comm_interface::CanAddonMcp2515:
|
||||
return "CAN MCP 2515 add-on";
|
||||
case comm_interface::CanFdAddonMcp2518:
|
||||
return "CAN FD MCP 2518 add-on";
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const char* name_for_battery_type(BatteryType type) {
|
||||
switch (type) {
|
||||
case BatteryType::None:
|
||||
return "None";
|
||||
|
@ -36,10 +66,8 @@ extern const char* name_for_battery_type(BatteryType type) {
|
|||
return BydAttoBattery::Name;
|
||||
case BatteryType::CellPowerBms:
|
||||
return CellPowerBms::Name;
|
||||
#ifdef CHADEMO_PIN_2 // Only support chademo for certain platforms
|
||||
case BatteryType::Chademo:
|
||||
return ChademoBattery::Name;
|
||||
#endif
|
||||
case BatteryType::CmfaEv:
|
||||
return CmfaEvBattery::Name;
|
||||
case BatteryType::Foxess:
|
||||
|
@ -66,6 +94,8 @@ extern const char* name_for_battery_type(BatteryType type) {
|
|||
return MebBattery::Name;
|
||||
case BatteryType::Mg5:
|
||||
return Mg5Battery::Name;
|
||||
case BatteryType::MgHsPhev:
|
||||
return MgHsPHEVBattery::Name;
|
||||
case BatteryType::NissanLeaf:
|
||||
return NissanLeafBattery::Name;
|
||||
case BatteryType::Pylon:
|
||||
|
@ -102,8 +132,15 @@ extern const char* name_for_battery_type(BatteryType type) {
|
|||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef LFP_CHEMISTRY
|
||||
const battery_chemistry_enum battery_chemistry_default = battery_chemistry_enum::LFP;
|
||||
#else
|
||||
const battery_chemistry_enum battery_chemistry_default = battery_chemistry_enum::NMC;
|
||||
#endif
|
||||
|
||||
battery_chemistry_enum user_selected_battery_chemistry = battery_chemistry_default;
|
||||
|
||||
#ifdef COMMON_IMAGE
|
||||
#ifdef SELECTED_BATTERY_CLASS
|
||||
#error "Compile time SELECTED_BATTERY_CLASS should not be defined with COMMON_IMAGE"
|
||||
|
@ -126,10 +163,8 @@ Battery* create_battery(BatteryType type) {
|
|||
return new BydAttoBattery();
|
||||
case BatteryType::CellPowerBms:
|
||||
return new CellPowerBms();
|
||||
#ifdef CHADEMO_PIN_2 // Only support chademo for certain platforms
|
||||
case BatteryType::Chademo:
|
||||
return new ChademoBattery();
|
||||
#endif
|
||||
case BatteryType::CmfaEv:
|
||||
return new CmfaEvBattery();
|
||||
case BatteryType::Foxess:
|
||||
|
@ -156,6 +191,8 @@ Battery* create_battery(BatteryType type) {
|
|||
return new MebBattery();
|
||||
case BatteryType::Mg5:
|
||||
return new Mg5Battery();
|
||||
case BatteryType::MgHsPhev:
|
||||
return new MgHsPHEVBattery();
|
||||
case BatteryType::NissanLeaf:
|
||||
return new NissanLeafBattery();
|
||||
case BatteryType::Pylon:
|
||||
|
@ -179,7 +216,7 @@ Battery* create_battery(BatteryType type) {
|
|||
case BatteryType::SimpBms:
|
||||
return new SimpBmsBattery();
|
||||
case BatteryType::TeslaModel3Y:
|
||||
return new TeslaModel3YBattery();
|
||||
return new TeslaModel3YBattery(user_selected_battery_chemistry);
|
||||
case BatteryType::TeslaModelSX:
|
||||
return new TeslaModelSXBattery();
|
||||
case BatteryType::TestFake:
|
||||
|
@ -212,7 +249,7 @@ void setup_battery() {
|
|||
break;
|
||||
case BatteryType::BmwI3:
|
||||
battery2 = new BmwI3Battery(&datalayer.battery2, &datalayer.system.status.battery2_allowed_contactor_closing,
|
||||
can_config.battery_double, WUP_PIN2);
|
||||
can_config.battery_double, esp32hal->WUP_PIN2());
|
||||
break;
|
||||
case BatteryType::KiaHyundai64:
|
||||
battery2 = new KiaHyundai64Battery(&datalayer.battery2, &datalayer_extended.KiaHyundai64_2,
|
||||
|
@ -221,6 +258,9 @@ void setup_battery() {
|
|||
case BatteryType::SantaFePhev:
|
||||
battery2 = new SantaFePhevBattery(&datalayer.battery2, can_config.battery_double);
|
||||
break;
|
||||
case BatteryType::RenaultZoe1:
|
||||
battery2 = new RenaultZoeGen1Battery(&datalayer.battery2, nullptr, can_config.battery_double);
|
||||
break;
|
||||
case BatteryType::TestFake:
|
||||
battery2 = new TestFakeBattery(&datalayer.battery2, can_config.battery_double);
|
||||
break;
|
||||
|
@ -236,7 +276,11 @@ void setup_battery() {
|
|||
void setup_battery() {
|
||||
// Instantiate the battery only once just in case this function gets called multiple times.
|
||||
if (battery == nullptr) {
|
||||
#ifdef TESLA_MODEL_3Y_BATTERY
|
||||
battery = new SELECTED_BATTERY_CLASS(user_selected_battery_chemistry);
|
||||
#else
|
||||
battery = new SELECTED_BATTERY_CLASS();
|
||||
#endif
|
||||
}
|
||||
battery->setup();
|
||||
|
||||
|
@ -245,7 +289,7 @@ void setup_battery() {
|
|||
#if defined(BMW_I3_BATTERY)
|
||||
battery2 =
|
||||
new SELECTED_BATTERY_CLASS(&datalayer.battery2, &datalayer.system.status.battery2_allowed_contactor_closing,
|
||||
can_config.battery_double, WUP_PIN2);
|
||||
can_config.battery_double, esp32hal->WUP_PIN2());
|
||||
#elif defined(KIA_HYUNDAI_64_BATTERY)
|
||||
battery2 = new SELECTED_BATTERY_CLASS(&datalayer.battery2, &datalayer_extended.KiaHyundai64_2,
|
||||
&datalayer.system.status.battery2_allowed_contactor_closing,
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#include "../datalayer/datalayer.h"
|
||||
#include "../datalayer/datalayer_extended.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../include.h"
|
||||
|
||||
/* Do not change code below unless you are sure what you are doing */
|
||||
|
||||
|
@ -44,7 +43,7 @@ uint8_t BmwI3Battery::increment_alive_counter(uint8_t counter) {
|
|||
void BmwI3Battery::update_values() { //This function maps all the values fetched via CAN to the battery datalayer
|
||||
if (datalayer.system.settings.equipment_stop_active == true) {
|
||||
digitalWrite(wakeup_pin, LOW); // Turn off wakeup pin
|
||||
} else {
|
||||
} else if (millis() > INTERVAL_1_S) {
|
||||
digitalWrite(wakeup_pin, HIGH); // Wake up the battery
|
||||
}
|
||||
|
||||
|
@ -235,7 +234,7 @@ void BmwI3Battery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
|||
case 0x607: //BMS - responses to message requests on 0x615
|
||||
if ((cmdState == CELL_VOLTAGE_CELLNO || cmdState == CELL_VOLTAGE_CELLNO_LAST) && (rx_frame.data.u8[0] == 0xF4)) {
|
||||
if (rx_frame.DLC == 6) {
|
||||
transmit_can_frame(&BMW_6F4_CELL_CONTINUE, can_interface); // tell battery to send the cellvoltage
|
||||
transmit_can_frame(&BMW_6F4_CELL_CONTINUE); // tell battery to send the cellvoltage
|
||||
}
|
||||
if (rx_frame.DLC == 8) { // We have the full value, map it
|
||||
datalayer_battery->status.cell_voltages_mV[current_cell_polled - 1] =
|
||||
|
@ -248,7 +247,7 @@ void BmwI3Battery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
|||
while (count < rx_frame.DLC && next_data < 49) {
|
||||
message_data[next_data++] = rx_frame.data.u8[count++];
|
||||
}
|
||||
transmit_can_frame(&BMW_6F1_CONTINUE, can_interface); // tell battery to send additional messages
|
||||
transmit_can_frame(&BMW_6F1_CONTINUE); // tell battery to send additional messages
|
||||
|
||||
} else if (rx_frame.DLC > 3 && next_data > 0 && rx_frame.data.u8[0] == 0xf1 &&
|
||||
((rx_frame.data.u8[1] & 0xF0) == 0x20)) {
|
||||
|
@ -316,9 +315,9 @@ void BmwI3Battery::transmit_can(unsigned long currentMillis) {
|
|||
} else if (allows_contactor_closing) {
|
||||
//If battery is not in Fault mode, and we are allowed to control contactors, we allow contactor to close by sending 10B
|
||||
*allows_contactor_closing = true;
|
||||
transmit_can_frame(&BMW_10B, can_interface);
|
||||
transmit_can_frame(&BMW_10B);
|
||||
} else if (contactor_closing_allowed && *contactor_closing_allowed) {
|
||||
transmit_can_frame(&BMW_10B, can_interface);
|
||||
transmit_can_frame(&BMW_10B);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -331,7 +330,7 @@ void BmwI3Battery::transmit_can(unsigned long currentMillis) {
|
|||
|
||||
alive_counter_100ms = increment_alive_counter(alive_counter_100ms);
|
||||
|
||||
transmit_can_frame(&BMW_12F, can_interface);
|
||||
transmit_can_frame(&BMW_12F);
|
||||
}
|
||||
// Send 200ms CAN Message
|
||||
if (currentMillis - previousMillis200 >= INTERVAL_200_MS) {
|
||||
|
@ -342,7 +341,7 @@ void BmwI3Battery::transmit_can(unsigned long currentMillis) {
|
|||
|
||||
alive_counter_200ms = increment_alive_counter(alive_counter_200ms);
|
||||
|
||||
transmit_can_frame(&BMW_19B, can_interface);
|
||||
transmit_can_frame(&BMW_19B);
|
||||
}
|
||||
// Send 500ms CAN Message
|
||||
if (currentMillis - previousMillis500 >= INTERVAL_500_MS) {
|
||||
|
@ -353,14 +352,14 @@ void BmwI3Battery::transmit_can(unsigned long currentMillis) {
|
|||
|
||||
alive_counter_500ms = increment_alive_counter(alive_counter_500ms);
|
||||
|
||||
transmit_can_frame(&BMW_30B, can_interface);
|
||||
transmit_can_frame(&BMW_30B);
|
||||
}
|
||||
// Send 640ms CAN Message
|
||||
if (currentMillis - previousMillis640 >= INTERVAL_640_MS) {
|
||||
previousMillis640 = currentMillis;
|
||||
|
||||
transmit_can_frame(&BMW_512, can_interface); // Keep BMS alive
|
||||
transmit_can_frame(&BMW_5F8, can_interface);
|
||||
transmit_can_frame(&BMW_512); // Keep BMS alive
|
||||
transmit_can_frame(&BMW_5F8);
|
||||
}
|
||||
// Send 1000ms CAN Message
|
||||
if (currentMillis - previousMillis1000 >= INTERVAL_1_S) {
|
||||
|
@ -397,22 +396,22 @@ void BmwI3Battery::transmit_can(unsigned long currentMillis) {
|
|||
|
||||
alive_counter_1000ms = increment_alive_counter(alive_counter_1000ms);
|
||||
|
||||
transmit_can_frame(&BMW_3E8, can_interface); //Order comes from CAN logs
|
||||
transmit_can_frame(&BMW_328, can_interface);
|
||||
transmit_can_frame(&BMW_3F9, can_interface);
|
||||
transmit_can_frame(&BMW_2E2, can_interface);
|
||||
transmit_can_frame(&BMW_41D, can_interface);
|
||||
transmit_can_frame(&BMW_3D0, can_interface);
|
||||
transmit_can_frame(&BMW_3CA, can_interface);
|
||||
transmit_can_frame(&BMW_3A7, can_interface);
|
||||
transmit_can_frame(&BMW_2CA, can_interface);
|
||||
transmit_can_frame(&BMW_3FB, can_interface);
|
||||
transmit_can_frame(&BMW_418, can_interface);
|
||||
transmit_can_frame(&BMW_1D0, can_interface);
|
||||
transmit_can_frame(&BMW_3EC, can_interface);
|
||||
transmit_can_frame(&BMW_192, can_interface);
|
||||
transmit_can_frame(&BMW_13E, can_interface);
|
||||
transmit_can_frame(&BMW_433, can_interface);
|
||||
transmit_can_frame(&BMW_3E8); //Order comes from CAN logs
|
||||
transmit_can_frame(&BMW_328);
|
||||
transmit_can_frame(&BMW_3F9);
|
||||
transmit_can_frame(&BMW_2E2);
|
||||
transmit_can_frame(&BMW_41D);
|
||||
transmit_can_frame(&BMW_3D0);
|
||||
transmit_can_frame(&BMW_3CA);
|
||||
transmit_can_frame(&BMW_3A7);
|
||||
transmit_can_frame(&BMW_2CA);
|
||||
transmit_can_frame(&BMW_3FB);
|
||||
transmit_can_frame(&BMW_418);
|
||||
transmit_can_frame(&BMW_1D0);
|
||||
transmit_can_frame(&BMW_3EC);
|
||||
transmit_can_frame(&BMW_192);
|
||||
transmit_can_frame(&BMW_13E);
|
||||
transmit_can_frame(&BMW_433);
|
||||
|
||||
BMW_433.data.u8[1] = 0x01; // First 433 message byte1 we send is unique, once we sent initial value send this
|
||||
BMW_3E8.data.u8[0] = 0xF1; // First 3E8 message byte0 we send is unique, once we sent initial value send this
|
||||
|
@ -420,15 +419,15 @@ void BmwI3Battery::transmit_can(unsigned long currentMillis) {
|
|||
next_data = 0;
|
||||
switch (cmdState) {
|
||||
case SOC:
|
||||
transmit_can_frame(&BMW_6F1_CELL, can_interface);
|
||||
transmit_can_frame(&BMW_6F1_CELL);
|
||||
cmdState = CELL_VOLTAGE_MINMAX;
|
||||
break;
|
||||
case CELL_VOLTAGE_MINMAX:
|
||||
transmit_can_frame(&BMW_6F1_SOH, can_interface);
|
||||
transmit_can_frame(&BMW_6F1_SOH);
|
||||
cmdState = SOH;
|
||||
break;
|
||||
case SOH:
|
||||
transmit_can_frame(&BMW_6F1_CELL_VOLTAGE_AVG, can_interface);
|
||||
transmit_can_frame(&BMW_6F1_CELL_VOLTAGE_AVG);
|
||||
cmdState = CELL_VOLTAGE_CELLNO;
|
||||
current_cell_polled = 0;
|
||||
|
||||
|
@ -441,11 +440,11 @@ void BmwI3Battery::transmit_can(unsigned long currentMillis) {
|
|||
cmdState = CELL_VOLTAGE_CELLNO;
|
||||
|
||||
BMW_6F4_CELL_VOLTAGE_CELLNO.data.u8[6] = current_cell_polled;
|
||||
transmit_can_frame(&BMW_6F4_CELL_VOLTAGE_CELLNO, can_interface);
|
||||
transmit_can_frame(&BMW_6F4_CELL_VOLTAGE_CELLNO);
|
||||
}
|
||||
break;
|
||||
case CELL_VOLTAGE_CELLNO_LAST:
|
||||
transmit_can_frame(&BMW_6F1_SOC, can_interface);
|
||||
transmit_can_frame(&BMW_6F1_SOC);
|
||||
cmdState = SOC;
|
||||
break;
|
||||
}
|
||||
|
@ -457,16 +456,16 @@ void BmwI3Battery::transmit_can(unsigned long currentMillis) {
|
|||
BMW_3FC.data.u8[1] = ((BMW_3FC.data.u8[1] & 0xF0) + alive_counter_5000ms);
|
||||
BMW_3C5.data.u8[0] = ((BMW_3C5.data.u8[0] & 0xF0) + alive_counter_5000ms);
|
||||
|
||||
transmit_can_frame(&BMW_3FC, can_interface); //Order comes from CAN logs
|
||||
transmit_can_frame(&BMW_3C5, can_interface);
|
||||
transmit_can_frame(&BMW_3A0, can_interface);
|
||||
transmit_can_frame(&BMW_592_0, can_interface);
|
||||
transmit_can_frame(&BMW_592_1, can_interface);
|
||||
transmit_can_frame(&BMW_3FC); //Order comes from CAN logs
|
||||
transmit_can_frame(&BMW_3C5);
|
||||
transmit_can_frame(&BMW_3A0);
|
||||
transmit_can_frame(&BMW_592_0);
|
||||
transmit_can_frame(&BMW_592_1);
|
||||
|
||||
alive_counter_5000ms = increment_alive_counter(alive_counter_5000ms);
|
||||
|
||||
if (BMW_380_counter < 3) {
|
||||
transmit_can_frame(&BMW_380, can_interface); // This message stops after 3 times on startup
|
||||
transmit_can_frame(&BMW_380); // This message stops after 3 times on startup
|
||||
BMW_380_counter++;
|
||||
}
|
||||
}
|
||||
|
@ -474,9 +473,9 @@ void BmwI3Battery::transmit_can(unsigned long currentMillis) {
|
|||
if (currentMillis - previousMillis10000 >= INTERVAL_10_S) {
|
||||
previousMillis10000 = currentMillis;
|
||||
|
||||
transmit_can_frame(&BMW_3E5, can_interface); //Order comes from CAN logs
|
||||
transmit_can_frame(&BMW_3E4, can_interface);
|
||||
transmit_can_frame(&BMW_37B, can_interface);
|
||||
transmit_can_frame(&BMW_3E5); //Order comes from CAN logs
|
||||
transmit_can_frame(&BMW_3E4);
|
||||
transmit_can_frame(&BMW_37B);
|
||||
|
||||
BMW_3E5.data.u8[0] = 0xFD; // First 3E5 message byte0 we send is unique, once we sent initial value send this
|
||||
}
|
||||
|
@ -493,6 +492,10 @@ void BmwI3Battery::transmit_can(unsigned long currentMillis) {
|
|||
}
|
||||
|
||||
void BmwI3Battery::setup(void) { // Performs one time setup at startup
|
||||
if (!esp32hal->alloc_pins(Name, wakeup_pin)) {
|
||||
return;
|
||||
}
|
||||
|
||||
strncpy(datalayer.system.info.battery_protocol, Name, 63);
|
||||
datalayer.system.info.battery_protocol[63] = '\0';
|
||||
|
||||
|
@ -507,5 +510,5 @@ void BmwI3Battery::setup(void) { // Performs one time setup at startup
|
|||
datalayer_battery->info.number_of_cells = NUMBER_OF_CELLS;
|
||||
|
||||
pinMode(wakeup_pin, OUTPUT);
|
||||
digitalWrite(wakeup_pin, HIGH); // Wake up the battery
|
||||
digitalWrite(wakeup_pin, LOW); // Set pin to low, prepare to wakeup later on!
|
||||
}
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
#define BMW_I3_BATTERY_H
|
||||
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../include.h"
|
||||
#include "BMW-I3-HTML.h"
|
||||
#include "CanBattery.h"
|
||||
#include "src/devboard/hal/hal.h"
|
||||
|
||||
#ifdef BMW_I3_BATTERY
|
||||
#define SELECTED_BATTERY_CLASS BmwI3Battery
|
||||
|
@ -14,7 +14,7 @@ class BmwI3Battery : public CanBattery {
|
|||
public:
|
||||
// Use this constructor for the second battery.
|
||||
BmwI3Battery(DATALAYER_BATTERY_TYPE* datalayer_ptr, bool* contactor_closing_allowed_ptr, CAN_Interface targetCan,
|
||||
int wakeup)
|
||||
gpio_num_t wakeup)
|
||||
: CanBattery(targetCan), renderer(*this) {
|
||||
datalayer_battery = datalayer_ptr;
|
||||
contactor_closing_allowed = contactor_closing_allowed_ptr;
|
||||
|
@ -30,7 +30,7 @@ class BmwI3Battery : public CanBattery {
|
|||
datalayer_battery = &datalayer.battery;
|
||||
allows_contactor_closing = &datalayer.system.status.battery_allows_contactor_closing;
|
||||
contactor_closing_allowed = nullptr;
|
||||
wakeup_pin = WUP_PIN1;
|
||||
wakeup_pin = esp32hal->WUP_PIN1();
|
||||
}
|
||||
|
||||
virtual void setup(void);
|
||||
|
@ -95,7 +95,7 @@ class BmwI3Battery : public CanBattery {
|
|||
// If not null, this battery listens to this boolean to determine whether contactor closing is allowed
|
||||
bool* contactor_closing_allowed;
|
||||
|
||||
int wakeup_pin;
|
||||
gpio_num_t wakeup_pin;
|
||||
|
||||
unsigned long previousMillis20 = 0; // will store last time a 20ms CAN Message was send
|
||||
unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was send
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#include "BMW-I3-HTML.h"
|
||||
#include "../include.h"
|
||||
#include "BMW-I3-BATTERY.h"
|
||||
|
||||
// Helper function for safe array access
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include "../datalayer/datalayer.h"
|
||||
#include "../datalayer/datalayer_extended.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../include.h"
|
||||
#include "../devboard/utils/logging.h"
|
||||
|
||||
// Function to check if a value has gone stale over a specified time period
|
||||
bool BmwIXBattery::isStale(int16_t currentValue, uint16_t& lastValue, unsigned long& lastChangeTime) {
|
||||
|
@ -173,7 +173,7 @@ void BmwIXBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
|||
}
|
||||
|
||||
//Frame has continued data - so request it
|
||||
transmit_can_frame(&BMWiX_6F4_CONTINUE_DATA, can_config.battery);
|
||||
transmit_can_frame(&BMWiX_6F4_CONTINUE_DATA);
|
||||
}
|
||||
|
||||
if (rx_frame.DLC = 64 && rx_frame.data.u8[0] == 0xF4 &&
|
||||
|
@ -307,7 +307,7 @@ void BmwIXBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
|||
logging.println("Cell MinMax Qualifier Invalid - Requesting BMS Reset");
|
||||
#endif // DEBUG_LOG
|
||||
//set_event(EVENT_BATTERY_VALUE_UNAVAILABLE, (millis())); //Eventually need new Info level event type
|
||||
transmit_can_frame(&BMWiX_6F4_REQUEST_HARD_RESET, can_config.battery);
|
||||
transmit_can_frame(&BMWiX_6F4_REQUEST_HARD_RESET);
|
||||
} else { //Only ingest values if they are not the 10V Error state
|
||||
min_cell_voltage = (rx_frame.data.u8[6] << 8 | rx_frame.data.u8[7]);
|
||||
max_cell_voltage = (rx_frame.data.u8[8] << 8 | rx_frame.data.u8[9]);
|
||||
|
@ -405,8 +405,8 @@ void BmwIXBattery::transmit_can(unsigned long currentMillis) {
|
|||
ContactorState.closed ==
|
||||
true) { // Do not send unless the contactors are requested to be closed and are closed, as sending these does not allow the contactors to close
|
||||
uds_req_id_counter = increment_uds_req_id_counter(uds_req_id_counter);
|
||||
transmit_can_frame(UDS_REQUESTS100MS[uds_req_id_counter],
|
||||
can_config.battery); // FIXME: sending these does not allow the contactors to close
|
||||
transmit_can_frame(
|
||||
UDS_REQUESTS100MS[uds_req_id_counter]); // FIXME: sending these does not allow the contactors to close
|
||||
} else { // FIXME: hotfix: If contactors are not requested to be closed, ensure the battery is reported as alive, even if no CAN messages are received
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
}
|
||||
|
@ -419,7 +419,7 @@ void BmwIXBattery::transmit_can(unsigned long currentMillis) {
|
|||
}
|
||||
|
||||
//Send SME Keep alive values 100ms
|
||||
//transmit_can_frame(&BMWiX_510, can_config.battery);
|
||||
//transmit_can_frame(&BMWiX_510);
|
||||
}
|
||||
// Send 200ms CAN Message
|
||||
if (currentMillis - previousMillis200 >= INTERVAL_200_MS) {
|
||||
|
@ -427,7 +427,7 @@ void BmwIXBattery::transmit_can(unsigned long currentMillis) {
|
|||
|
||||
//Send SME Keep alive values 200ms
|
||||
//BMWiX_C0.data.u8[0] = increment_C0_counter(BMWiX_C0.data.u8[0]); //Keep Alive 1
|
||||
//transmit_can_frame(&BMWiX_C0, can_config.battery);
|
||||
//transmit_can_frame(&BMWiX_C0);
|
||||
}
|
||||
// Send 1000ms CAN Message
|
||||
if (currentMillis - previousMillis1000 >= INTERVAL_1_S) {
|
||||
|
@ -438,8 +438,8 @@ void BmwIXBattery::transmit_can(unsigned long currentMillis) {
|
|||
// Send 10000ms CAN Message
|
||||
if (currentMillis - previousMillis10000 >= INTERVAL_10_S) {
|
||||
previousMillis10000 = currentMillis;
|
||||
//transmit_can_frame(&BMWiX_6F4_REQUEST_BALANCING_START2, can_config.battery);
|
||||
//transmit_can_frame(&BMWiX_6F4_REQUEST_BALANCING_START, can_config.battery);
|
||||
//transmit_can_frame(&BMWiX_6F4_REQUEST_BALANCING_START2);
|
||||
//transmit_can_frame(&BMWiX_6F4_REQUEST_BALANCING_START);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -448,7 +448,7 @@ void BmwIXBattery::setup(void) { // Performs one time setup at startup
|
|||
datalayer.system.info.battery_protocol[63] = '\0';
|
||||
|
||||
//Reset Battery at bootup
|
||||
//transmit_can_frame(&BMWiX_6F4_REQUEST_HARD_RESET, can_config.battery);
|
||||
//transmit_can_frame(&BMWiX_6F4_REQUEST_HARD_RESET);
|
||||
|
||||
//Before we have started up and detected which battery is in use, use 108S values
|
||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
||||
|
@ -547,20 +547,20 @@ void BmwIXBattery::HandleBmwIxCloseContactorsRequest(uint16_t counter_10ms) {
|
|||
|
||||
if (counter_10ms == 0) {
|
||||
// @0 ms
|
||||
transmit_can_frame(&BMWiX_510, can_config.battery);
|
||||
transmit_can_frame(&BMWiX_510);
|
||||
#ifdef DEBUG_LOG
|
||||
logging.println("Transmitted 0x510 - 1/6");
|
||||
#endif // DEBUG_LOG
|
||||
} else if (counter_10ms == 5) {
|
||||
// @50 ms
|
||||
transmit_can_frame(&BMWiX_276, can_config.battery);
|
||||
transmit_can_frame(&BMWiX_276);
|
||||
#ifdef DEBUG_LOG
|
||||
logging.println("Transmitted 0x276 - 2/6");
|
||||
#endif // DEBUG_LOG
|
||||
} else if (counter_10ms == 10) {
|
||||
// @100 ms
|
||||
BMWiX_510.data.u8[2] = 0x04; // TODO: check if needed
|
||||
transmit_can_frame(&BMWiX_510, can_config.battery);
|
||||
transmit_can_frame(&BMWiX_510);
|
||||
#ifdef DEBUG_LOG
|
||||
logging.println("Transmitted 0x510 - 3/6");
|
||||
#endif // DEBUG_LOG
|
||||
|
@ -568,7 +568,7 @@ void BmwIXBattery::HandleBmwIxCloseContactorsRequest(uint16_t counter_10ms) {
|
|||
// @200 ms
|
||||
BMWiX_510.data.u8[2] = 0x10; // TODO: check if needed
|
||||
BMWiX_510.data.u8[5] = 0x80; // needed to close contactors
|
||||
transmit_can_frame(&BMWiX_510, can_config.battery);
|
||||
transmit_can_frame(&BMWiX_510);
|
||||
#ifdef DEBUG_LOG
|
||||
logging.println("Transmitted 0x510 - 4/6");
|
||||
#endif // DEBUG_LOG
|
||||
|
@ -576,7 +576,7 @@ void BmwIXBattery::HandleBmwIxCloseContactorsRequest(uint16_t counter_10ms) {
|
|||
// @300 ms
|
||||
BMWiX_16E.data.u8[0] = 0x6A;
|
||||
BMWiX_16E.data.u8[1] = 0xAD;
|
||||
transmit_can_frame(&BMWiX_16E, can_config.battery);
|
||||
transmit_can_frame(&BMWiX_16E);
|
||||
#ifdef DEBUG_LOG
|
||||
logging.println("Transmitted 0x16E - 5/6");
|
||||
#endif // DEBUG_LOG
|
||||
|
@ -584,7 +584,7 @@ void BmwIXBattery::HandleBmwIxCloseContactorsRequest(uint16_t counter_10ms) {
|
|||
// @500 ms
|
||||
BMWiX_16E.data.u8[0] = 0x03;
|
||||
BMWiX_16E.data.u8[1] = 0xA9;
|
||||
transmit_can_frame(&BMWiX_16E, can_config.battery);
|
||||
transmit_can_frame(&BMWiX_16E);
|
||||
#ifdef DEBUG_LOG
|
||||
logging.println("Transmitted 0x16E - 6/6");
|
||||
#endif // DEBUG_LOG
|
||||
|
@ -613,20 +613,20 @@ void BmwIXBattery::BmwIxKeepContactorsClosed(uint8_t counter_100ms) {
|
|||
logging.println("Sending keep contactors closed messages started");
|
||||
#endif // DEBUG_LOG
|
||||
// @0 ms
|
||||
transmit_can_frame(&BMWiX_510, can_config.battery);
|
||||
transmit_can_frame(&BMWiX_510);
|
||||
} else if (counter_100ms == 7) {
|
||||
// @ 730 ms
|
||||
BMWiX_16E.data.u8[0] = 0x8C;
|
||||
BMWiX_16E.data.u8[1] = 0xA0;
|
||||
transmit_can_frame(&BMWiX_16E, can_config.battery);
|
||||
transmit_can_frame(&BMWiX_16E);
|
||||
} else if (counter_100ms == 24) {
|
||||
// @2380 ms
|
||||
transmit_can_frame(&BMWiX_510, can_config.battery);
|
||||
transmit_can_frame(&BMWiX_510);
|
||||
} else if (counter_100ms == 29) {
|
||||
// @ 2900 ms
|
||||
BMWiX_16E.data.u8[0] = 0x02;
|
||||
BMWiX_16E.data.u8[1] = 0xA7;
|
||||
transmit_can_frame(&BMWiX_16E, can_config.battery);
|
||||
transmit_can_frame(&BMWiX_16E);
|
||||
#ifdef DEBUG_LOG
|
||||
logging.println("Sending keep contactors closed messages finished");
|
||||
#endif // DEBUG_LOG
|
||||
|
@ -645,14 +645,14 @@ void BmwIXBattery::HandleBmwIxOpenContactorsRequest(uint16_t counter_10ms) {
|
|||
// @0 ms (0.00) RX0 510 [8] 40 10 00 00 00 80 00 00
|
||||
BMWiX_510.data = {0x40, 0x10, 0x00, 0x00,
|
||||
0x00, 0x80, 0x00, 0x00}; // Explicit declaration, to prevent modification by other functions
|
||||
transmit_can_frame(&BMWiX_510, can_config.battery);
|
||||
transmit_can_frame(&BMWiX_510);
|
||||
// set back to default values
|
||||
BMWiX_510.data = {0x40, 0x10, 0x04, 0x00, 0x00, 0x80, 0x01, 0x00}; // default values
|
||||
} else if (counter_10ms == 6) {
|
||||
// @60 ms (0.06) RX0 16E [8] E6 A4 C8 FF 60 C9 33 F0
|
||||
BMWiX_16E.data = {0xE6, 0xA4, 0xC8, 0xFF,
|
||||
0x60, 0xC9, 0x33, 0xF0}; // Explicit declaration, to prevent modification by other functions
|
||||
transmit_can_frame(&BMWiX_16E, can_config.battery);
|
||||
transmit_can_frame(&BMWiX_16E);
|
||||
// set back to default values
|
||||
BMWiX_16E.data = {0x00, 0xA0, 0xC9, 0xFF, 0x60, 0xC9, 0x3A, 0xF7}; // default values
|
||||
ContactorState.closed = false;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#ifndef BMW_IX_BATTERY_H
|
||||
#define BMW_IX_BATTERY_H
|
||||
#include <Arduino.h>
|
||||
#include "../include.h"
|
||||
#include "BMW-IX-HTML.h"
|
||||
#include "CanBattery.h"
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#include "BMW-IX-HTML.h"
|
||||
#include "../include.h"
|
||||
#include "BMW-IX-BATTERY.h"
|
||||
|
||||
String BmwIXHtmlRenderer::get_status_html() {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include "../datalayer/datalayer.h"
|
||||
#include "../datalayer/datalayer_extended.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../include.h"
|
||||
#include "../devboard/utils/logging.h"
|
||||
|
||||
const unsigned char crc8_table[256] =
|
||||
{ // CRC8_SAE_J1850_ZER0 formula,0x1D Poly,initial value 0x3F,Final XOR value varies
|
||||
|
@ -188,12 +188,12 @@ void BmwPhevBattery::wake_battery_via_canbus() {
|
|||
// Followed by a Recessive interval of at least ~3 µs (min) and at most ~10 µs (max)
|
||||
// Then a second dominant pulse of similar timing.
|
||||
|
||||
CAN_cfg.speed = CAN_SPEED_100KBPS; //Slow down canbus to achieve wakeup timings
|
||||
ESP32Can.CANInit(); // ReInit native CAN module at new speed
|
||||
transmit_can_frame(&BMW_PHEV_BUS_WAKEUP_REQUEST, can_config.battery);
|
||||
transmit_can_frame(&BMW_PHEV_BUS_WAKEUP_REQUEST, can_config.battery);
|
||||
CAN_cfg.speed = CAN_SPEED_500KBPS; //Resume fullspeed
|
||||
ESP32Can.CANInit(); // ReInit native CAN module at new speed
|
||||
auto original_speed = change_can_speed(CAN_Speed::CAN_SPEED_100KBPS);
|
||||
|
||||
transmit_can_frame(&BMW_PHEV_BUS_WAKEUP_REQUEST);
|
||||
transmit_can_frame(&BMW_PHEV_BUS_WAKEUP_REQUEST);
|
||||
|
||||
change_can_speed(original_speed);
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
logging.println("Sent magic wakeup packet to SME at 100kbps...");
|
||||
|
@ -432,7 +432,7 @@ void BmwPhevBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
|||
#if defined(DEBUG_LOG) && defined(UDS_LOG)
|
||||
logging.println("Requesting continue frame...");
|
||||
#endif // DEBUG_LOG && UDS_LOG
|
||||
transmit_can_frame(&BMW_6F1_REQUEST_CONTINUE_MULTIFRAME, can_config.battery);
|
||||
transmit_can_frame(&BMW_6F1_REQUEST_CONTINUE_MULTIFRAME);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -478,7 +478,7 @@ void BmwPhevBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
|||
#if defined(DEBUG_LOG) && defined(UDS_LOG)
|
||||
logging.println("Batch Complete - Requesting continue frame...");
|
||||
#endif // DEBUG_LOG && UDS_LOG
|
||||
transmit_can_frame(&BMW_6F1_REQUEST_CONTINUE_MULTIFRAME, can_config.battery);
|
||||
transmit_can_frame(&BMW_6F1_REQUEST_CONTINUE_MULTIFRAME);
|
||||
gUDSContext.receivedInBatch = 0; // Reset batch count
|
||||
Serial.println("Sent FC for next batch of 3 frames.");
|
||||
}
|
||||
|
@ -659,7 +659,7 @@ void BmwPhevBattery::transmit_can(unsigned long currentMillis) {
|
|||
//if (datalayer.battery.status.bms_status == FAULT) { //ALLOW ANY TIME - TEST ONLY
|
||||
//} //If battery is not in Fault mode, allow contactor to close by sending 10B
|
||||
//else {
|
||||
transmit_can_frame(&BMW_10B, can_config.battery);
|
||||
transmit_can_frame(&BMW_10B);
|
||||
//}
|
||||
}
|
||||
|
||||
|
@ -672,7 +672,7 @@ void BmwPhevBattery::transmit_can(unsigned long currentMillis) {
|
|||
previousMillis200 = currentMillis;
|
||||
uds_fast_req_id_counter = increment_uds_req_id_counter(
|
||||
uds_fast_req_id_counter, numFastUDSreqs); //Loop through and send a different UDS request each cycle
|
||||
transmit_can_frame(UDS_REQUESTS_FAST[uds_fast_req_id_counter], can_config.battery);
|
||||
transmit_can_frame(UDS_REQUESTS_FAST[uds_fast_req_id_counter]);
|
||||
}
|
||||
// Send 1000ms CAN Message
|
||||
if (currentMillis - previousMillis1000 >= INTERVAL_1_S) {
|
||||
|
@ -680,7 +680,7 @@ void BmwPhevBattery::transmit_can(unsigned long currentMillis) {
|
|||
|
||||
uds_slow_req_id_counter = increment_uds_req_id_counter(
|
||||
uds_slow_req_id_counter, numSlowUDSreqs); //Loop through and send a different UDS request each cycle
|
||||
transmit_can_frame(UDS_REQUESTS_SLOW[uds_slow_req_id_counter], can_config.battery);
|
||||
transmit_can_frame(UDS_REQUESTS_SLOW[uds_slow_req_id_counter]);
|
||||
}
|
||||
// Send 5000ms CAN Message
|
||||
if (currentMillis - previousMillis5000 >= INTERVAL_5_S) {
|
||||
|
@ -692,8 +692,7 @@ void BmwPhevBattery::transmit_can(unsigned long currentMillis) {
|
|||
// Send 10000ms CAN Message
|
||||
if (currentMillis - previousMillis10000 >= INTERVAL_10_S) {
|
||||
previousMillis10000 = currentMillis;
|
||||
transmit_can_frame(&BMWPHEV_6F1_REQUEST_BALANCING_START,
|
||||
can_config.battery); // Enable Balancing
|
||||
transmit_can_frame(&BMWPHEV_6F1_REQUEST_BALANCING_START); // Enable Balancing
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -703,8 +702,7 @@ void BmwPhevBattery::setup(void) { // Performs one time setup at startup
|
|||
//Wakeup the SME
|
||||
wake_battery_via_canbus();
|
||||
|
||||
transmit_can_frame(&BMWPHEV_6F1_REQUEST_ISOLATION_TEST,
|
||||
can_config.battery); // Run Internal Isolation Test at startup
|
||||
transmit_can_frame(&BMWPHEV_6F1_REQUEST_ISOLATION_TEST); // Run Internal Isolation Test at startup
|
||||
|
||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
||||
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#ifndef BMW_PHEV_BATTERY_H
|
||||
#define BMW_PHEV_BATTERY_H
|
||||
#include <Arduino.h>
|
||||
#include "../include.h"
|
||||
#include "BMW-PHEV-HTML.h"
|
||||
#include "CanBattery.h"
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#include "BMW-SBOX.h"
|
||||
#include "../communication/can/comm_can.h"
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../include.h"
|
||||
|
||||
uint8_t reverse_bits(uint8_t byte) {
|
||||
uint8_t reversed = 0;
|
||||
|
@ -172,8 +171,8 @@ void BmwSbox::transmit_can(unsigned long currentMillis) {
|
|||
SBOX_100.data.u8[1] = CAN100_cnt << 4 | 0x01;
|
||||
SBOX_100.data.u8[3] = 0x00;
|
||||
SBOX_100.data.u8[3] = calculateCRC(SBOX_100);
|
||||
transmit_can_frame(&SBOX_100, can_config.shunt);
|
||||
transmit_can_frame(&SBOX_300, can_config.shunt);
|
||||
transmit_can_frame(&SBOX_100);
|
||||
transmit_can_frame(&SBOX_300);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#ifndef BMW_SBOX_CONTROL_H
|
||||
#define BMW_SBOX_CONTROL_H
|
||||
#include "../include.h"
|
||||
|
||||
#ifdef BMW_SBOX
|
||||
#define SELECTED_SHUNT_CLASS BmwSbox
|
||||
|
|
|
@ -3,27 +3,22 @@
|
|||
#include "../datalayer/datalayer.h"
|
||||
#include "../datalayer/datalayer_extended.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../include.h"
|
||||
|
||||
/*
|
||||
TODOs left for this implementation
|
||||
- The battery has 3 CAN ports. One of the internal modules is responsible for the 7E4 polls, the battery for the 7E7 polls
|
||||
- Current implementation only seems to get the 7E7 polls working.
|
||||
- We might need to poll on 7E6 also?
|
||||
|
||||
- The values missing for a working implementation is:
|
||||
- SOC% missing! This is absolutely mandatory to fix before starting to use this!
|
||||
- Capacity (kWh) (can be estimated)
|
||||
- Charge max power (can be estimated)
|
||||
- Discharge max power (can be estimated)
|
||||
- SOH% (low prio))
|
||||
- The values missing for a fully working implementation is:
|
||||
- SOC% missing! (now estimated based on voltage)
|
||||
- Capacity (kWh) (now estimated)
|
||||
- Charge max power (now estimated)
|
||||
- Discharge max power (now estimated)
|
||||
- Current is updating extremely slow, consider switching to sensed_ value
|
||||
- Balancing info seems to be available via OBD/ISO-TP service $22OBD/ISO-TP service $22 , 4340 and onwards
|
||||
*/
|
||||
|
||||
/*TODO, messages we might need to send towards the battery to keep it happy and close contactors
|
||||
0x262 Battery Block Voltage Diag Status HV (Who sends this? Battery?)
|
||||
0x272 Battery Cell Voltage Diag Status HV (Who sends this? Battery?)
|
||||
0x274 Battery Temperature Sensor diagnostic status HV (Who sends this? Battery?)
|
||||
0x270 Battery VoltageSensor BalancingSwitches diagnostic status (Who sends this? Battery?)
|
||||
0x214 Charger coolant temp info HV
|
||||
0x20E Hybrid balancing request HV
|
||||
0x30E High Voltage Charger Command HV
|
||||
|
@ -39,48 +34,86 @@ TODOs left for this implementation
|
|||
0x460 Energy Storage System Temp HV (Who sends this? Battery?)
|
||||
*/
|
||||
|
||||
void BoltAmperaBattery::update_values() { //This function maps all the values fetched via CAN to the battery datalayer
|
||||
// Define the data points for %SOC depending on cell voltage
|
||||
// NCM Discharge Curve Lookup Table (100 points, 4.2V-3.0V)
|
||||
// SOC[100] = State of Charge (0.01% units, e.g., 10000 = 100.00%)
|
||||
// voltage_lookup[100] = Pack voltage (mV)
|
||||
const uint8_t numEntries = 100;
|
||||
const uint16_t SOC[100] = {
|
||||
10000, 9985, 9970, 9955, 9940, 9925, 9910, 9895, 9880, 9865, // 4.20V - 4.15V (High plateau)
|
||||
9850, 9820, 9790, 9760, 9730, 9700, 9660, 9620, 9580, 9540, // 4.14V - 4.00V
|
||||
9500, 9450, 9400, 9350, 9300, 9250, 9200, 9150, 9100, 9050, // 3.99V - 3.90V
|
||||
9000, 8900, 8800, 8700, 8600, 8500, 8400, 8300, 8200, 8100, // 3.89V - 3.80V
|
||||
8000, 7850, 7700, 7550, 7400, 7250, 7100, 6950, 6800, 6650, // 3.79V - 3.70V
|
||||
6500, 6300, 6100, 5900, 5700, 5500, 5300, 5100, 4900, 4700, // 3.69V - 3.60V
|
||||
4500, 4300, 4100, 3900, 3700, 3500, 3300, 3100, 2900, 2700, // 3.59V - 3.50V
|
||||
2500, 2250, 2000, 1750, 1500, 1250, 1000, 800, 600, 400, // 3.49V - 3.40V (Steep drop)
|
||||
300, 200, 150, 100, 80, 60, 40, 30, 20, 10, // 3.39V - 3.30V
|
||||
5, 2, 1, 0, 0, 0, 0, 0, 0, 0 // <3.30V (Cutoff)
|
||||
};
|
||||
|
||||
datalayer.battery.status.real_soc = battery_SOC_display;
|
||||
|
||||
//datalayer.battery.status.voltage_dV = battery_voltage * 0.52;
|
||||
datalayer.battery.status.voltage_dV = (battery_voltage_periodic / 8) * 10;
|
||||
|
||||
datalayer.battery.status.current_dA = battery_current_7E7;
|
||||
|
||||
datalayer.battery.info.total_capacity_Wh;
|
||||
|
||||
datalayer.battery.status.remaining_capacity_Wh;
|
||||
|
||||
datalayer.battery.status.soh_pptt;
|
||||
|
||||
datalayer.battery.status.max_discharge_power_W;
|
||||
|
||||
datalayer.battery.status.max_charge_power_W;
|
||||
|
||||
// Store temperatures in an array
|
||||
int16_t temperatures[] = {temperature_1, temperature_2, temperature_3, temperature_4, temperature_5, temperature_6};
|
||||
|
||||
// Initialize highest and lowest to the first element
|
||||
temperature_highest = temperatures[0];
|
||||
temperature_lowest = temperatures[0];
|
||||
|
||||
// Iterate through the array to find the highest and lowest values
|
||||
for (uint8_t i = 1; i < 6; ++i) {
|
||||
if (temperatures[i] > temperature_highest) {
|
||||
temperature_highest = temperatures[i];
|
||||
}
|
||||
if (temperatures[i] < temperature_lowest) {
|
||||
temperature_lowest = temperatures[i];
|
||||
}
|
||||
const uint16_t voltage_lookup[100] = {
|
||||
4200, 4195, 4190, 4185, 4180, 4175, 4170, 4165, 4160, 4155, // High plateau
|
||||
4150, 4140, 4130, 4120, 4110, 4100, 4090, 4080, 4070, 4060, 4050, 4040, 4030, 4020, 4010, 4000, 3990, 3980,
|
||||
3970, 3960, 3950, 3940, 3930, 3920, 3910, 3900, 3890, 3880, 3870, 3860, 3850, 3840, 3830, 3820, 3810, 3800,
|
||||
3790, 3780, 3770, 3760, 3750, 3740, 3730, 3720, 3710, 3700, 3690, 3680, 3670, 3660, 3650, 3640, 3630, 3620,
|
||||
3610, 3600, 3590, 3580, 3570, 3560, 3550, 3540, 3530, 3520, 3510, 3500, 3490, 3480, 3470, 3460, 3450, 3440,
|
||||
3430, 3420, 3410, 3400, 3390, 3380, 3370, 3360, 3350, 3340, 3330, 3320, 3310, 3300, 3290, 3280, 3270, 3260};
|
||||
static uint16_t estimateSOC(uint16_t cellVoltage) { // Linear interpolation function
|
||||
if (cellVoltage >= voltage_lookup[0]) {
|
||||
return SOC[0];
|
||||
}
|
||||
if (cellVoltage <= voltage_lookup[numEntries - 1]) {
|
||||
return SOC[numEntries - 1];
|
||||
}
|
||||
|
||||
datalayer.battery.status.temperature_min_dC = temperature_lowest * 10;
|
||||
for (int i = 1; i < numEntries; ++i) {
|
||||
if (cellVoltage >= voltage_lookup[i]) {
|
||||
double t = (cellVoltage - voltage_lookup[i]) / (voltage_lookup[i - 1] - voltage_lookup[i]);
|
||||
return SOC[i] + t * (SOC[i - 1] - SOC[i]);
|
||||
}
|
||||
}
|
||||
return 0; // Default return for safety, should never reach here
|
||||
}
|
||||
|
||||
datalayer.battery.status.temperature_max_dC = temperature_highest * 10;
|
||||
void BoltAmperaBattery::update_values() { //This function maps all the values fetched via CAN to the battery datalayer
|
||||
|
||||
datalayer.battery.status.real_soc = estimateSOC(battery_cell_voltage_max_mV); //TODO, this is bad and barely works
|
||||
|
||||
datalayer.battery.status.voltage_dV = battery_voltage_periodic_dV;
|
||||
|
||||
datalayer.battery.status.current_dA = (sensed_current_sensor_1 * 0.2); //TODO: Is sensor 1 OK?
|
||||
|
||||
datalayer.battery.status.remaining_capacity_Wh = static_cast<uint32_t>(
|
||||
(static_cast<double>(datalayer.battery.status.real_soc) / 10000) * datalayer.battery.info.total_capacity_Wh);
|
||||
|
||||
datalayer.battery.status.soh_pptt = 9900;
|
||||
|
||||
// Charge power is set in .h file (TODO: Remove this estimation when real value has been found)
|
||||
if (datalayer.battery.status.real_soc > 9900) {
|
||||
datalayer.battery.status.max_charge_power_W = MAX_CHARGE_POWER_WHEN_TOPBALANCING_W;
|
||||
} else if (datalayer.battery.status.real_soc > RAMPDOWN_SOC) {
|
||||
// When real SOC is between RAMPDOWN_SOC-99%, ramp the value between Max<->0
|
||||
datalayer.battery.status.max_charge_power_W =
|
||||
MAX_CHARGE_POWER_ALLOWED_W *
|
||||
(1 - (datalayer.battery.status.real_soc - RAMPDOWN_SOC) / (10000.0 - RAMPDOWN_SOC));
|
||||
} else { // No limits, max charging power allowed
|
||||
datalayer.battery.status.max_charge_power_W = MAX_CHARGE_POWER_ALLOWED_W;
|
||||
}
|
||||
|
||||
// Discharge power is also set in .h file (TODO: Remove this estimation when real value has been found)
|
||||
datalayer.battery.status.max_discharge_power_W = MAX_DISCHARGE_POWER_ALLOWED_W;
|
||||
|
||||
datalayer.battery.status.temperature_min_dC = temperature_lowest_C * 10;
|
||||
|
||||
datalayer.battery.status.temperature_max_dC = temperature_highest_C * 10;
|
||||
|
||||
//Map all cell voltages to the global array
|
||||
memcpy(datalayer.battery.status.cell_voltages_mV, battery_cell_voltages, 96 * sizeof(uint16_t));
|
||||
memcpy(datalayer.battery.status.cell_voltages_mV, cellblock_voltage, 96 * sizeof(uint16_t));
|
||||
|
||||
datalayer.battery.status.cell_max_voltage_mV = battery_cell_voltage_max_mV;
|
||||
|
||||
datalayer.battery.status.cell_min_voltage_mV = battery_cell_voltage_min_mV;
|
||||
|
||||
// Update webserver datalayer
|
||||
datalayer_extended.boltampera.battery_5V_ref = battery_5V_ref;
|
||||
|
@ -120,38 +153,223 @@ void BoltAmperaBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
|||
switch (rx_frame.ID) {
|
||||
case 0x200: //High voltage Battery Cell Voltage Matrix 1
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
mux = ((rx_frame.data.u8[6] & 0xE0) >> 5); //goes from 0-7
|
||||
cellbank_mux = ((rx_frame.data.u8[6] & 0xE0) >> 5); //Goes from 0-7
|
||||
switch (cellbank_mux) {
|
||||
case 0:
|
||||
cellblock_voltage[0] = (((rx_frame.data.u8[0] & 0x1F) << 7) | ((rx_frame.data.u8[1] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[1] = (((rx_frame.data.u8[2] & 0x1F) << 7) | ((rx_frame.data.u8[3] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[2] = (((rx_frame.data.u8[4]) << 4) | ((rx_frame.data.u8[5] & 0xF0) >> 4)) * 1.25;
|
||||
break;
|
||||
case 1:
|
||||
cellblock_voltage[3] = (((rx_frame.data.u8[0] & 0x1F) << 7) | ((rx_frame.data.u8[1] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[4] = (((rx_frame.data.u8[2] & 0x1F) << 7) | ((rx_frame.data.u8[3] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[5] = (((rx_frame.data.u8[4]) << 4) | ((rx_frame.data.u8[5] & 0xF0) >> 4)) * 1.25;
|
||||
break;
|
||||
case 2:
|
||||
cellblock_voltage[6] = (((rx_frame.data.u8[0] & 0x1F) << 7) | ((rx_frame.data.u8[1] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[7] = (((rx_frame.data.u8[2] & 0x1F) << 7) | ((rx_frame.data.u8[3] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[8] = (((rx_frame.data.u8[4]) << 4) | ((rx_frame.data.u8[5] & 0xF0) >> 4)) * 1.25;
|
||||
break;
|
||||
case 3:
|
||||
cellblock_voltage[9] = (((rx_frame.data.u8[0] & 0x1F) << 7) | ((rx_frame.data.u8[1] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[10] = (((rx_frame.data.u8[2] & 0x1F) << 7) | ((rx_frame.data.u8[3] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[11] = (((rx_frame.data.u8[4]) << 4) | ((rx_frame.data.u8[5] & 0xF0) >> 4)) * 1.25;
|
||||
break;
|
||||
case 4:
|
||||
cellblock_voltage[12] = (((rx_frame.data.u8[0] & 0x1F) << 7) | ((rx_frame.data.u8[1] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[13] = (((rx_frame.data.u8[2] & 0x1F) << 7) | ((rx_frame.data.u8[3] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[14] = (((rx_frame.data.u8[4]) << 4) | ((rx_frame.data.u8[5] & 0xF0) >> 4)) * 1.25;
|
||||
break;
|
||||
case 5:
|
||||
cellblock_voltage[15] = (((rx_frame.data.u8[0] & 0x1F) << 7) | ((rx_frame.data.u8[1] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[16] = (((rx_frame.data.u8[2] & 0x1F) << 7) | ((rx_frame.data.u8[3] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[17] = (((rx_frame.data.u8[4]) << 4) | ((rx_frame.data.u8[5] & 0xF0) >> 4)) * 1.25;
|
||||
break;
|
||||
case 6:
|
||||
cellblock_voltage[18] = (((rx_frame.data.u8[0] & 0x1F) << 7) | ((rx_frame.data.u8[1] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[19] = (((rx_frame.data.u8[2] & 0x1F) << 7) | ((rx_frame.data.u8[3] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[20] = (((rx_frame.data.u8[4]) << 4) | ((rx_frame.data.u8[5] & 0xF0) >> 4)) * 1.25;
|
||||
break;
|
||||
case 7:
|
||||
cellblock_voltage[21] = (((rx_frame.data.u8[0] & 0x1F) << 7) | ((rx_frame.data.u8[1] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[22] = (((rx_frame.data.u8[2] & 0x1F) << 7) | ((rx_frame.data.u8[3] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[23] = (((rx_frame.data.u8[4]) << 4) | ((rx_frame.data.u8[5] & 0xF0) >> 4)) * 1.25;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x202: //High voltage Battery Cell Voltage Matrix 2
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
mux = ((rx_frame.data.u8[6] & 0xE0) >> 5); //goes from 0-7
|
||||
cellbank_mux = ((rx_frame.data.u8[6] & 0xE0) >> 5); //goes from 0-7
|
||||
switch (cellbank_mux) {
|
||||
case 0:
|
||||
cellblock_voltage[24] = (((rx_frame.data.u8[0] & 0x1F) << 7) | ((rx_frame.data.u8[1] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[25] = (((rx_frame.data.u8[2] & 0x1F) << 7) | ((rx_frame.data.u8[3] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[26] = (((rx_frame.data.u8[4]) << 4) | ((rx_frame.data.u8[5] & 0xF0) >> 4)) * 1.25;
|
||||
break;
|
||||
case 1:
|
||||
cellblock_voltage[27] = (((rx_frame.data.u8[0] & 0x1F) << 7) | ((rx_frame.data.u8[1] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[28] = (((rx_frame.data.u8[2] & 0x1F) << 7) | ((rx_frame.data.u8[3] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[29] = (((rx_frame.data.u8[4]) << 4) | ((rx_frame.data.u8[5] & 0xF0) >> 4)) * 1.25;
|
||||
break;
|
||||
case 2:
|
||||
cellblock_voltage[30] = (((rx_frame.data.u8[0] & 0x1F) << 7) | ((rx_frame.data.u8[1] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[31] = (((rx_frame.data.u8[2] & 0x1F) << 7) | ((rx_frame.data.u8[3] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[32] = (((rx_frame.data.u8[4]) << 4) | ((rx_frame.data.u8[5] & 0xF0) >> 4)) * 1.25;
|
||||
break;
|
||||
case 3:
|
||||
cellblock_voltage[33] = (((rx_frame.data.u8[0] & 0x1F) << 7) | ((rx_frame.data.u8[1] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[34] = (((rx_frame.data.u8[2] & 0x1F) << 7) | ((rx_frame.data.u8[3] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[35] = (((rx_frame.data.u8[4]) << 4) | ((rx_frame.data.u8[5] & 0xF0) >> 4)) * 1.25;
|
||||
break;
|
||||
case 4:
|
||||
cellblock_voltage[36] = (((rx_frame.data.u8[0] & 0x1F) << 7) | ((rx_frame.data.u8[1] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[37] = (((rx_frame.data.u8[2] & 0x1F) << 7) | ((rx_frame.data.u8[3] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[38] = (((rx_frame.data.u8[4]) << 4) | ((rx_frame.data.u8[5] & 0xF0) >> 4)) * 1.25;
|
||||
break;
|
||||
case 5:
|
||||
cellblock_voltage[39] = (((rx_frame.data.u8[0] & 0x1F) << 7) | ((rx_frame.data.u8[1] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[40] = (((rx_frame.data.u8[2] & 0x1F) << 7) | ((rx_frame.data.u8[3] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[41] = (((rx_frame.data.u8[4]) << 4) | ((rx_frame.data.u8[5] & 0xF0) >> 4)) * 1.25;
|
||||
break;
|
||||
case 6:
|
||||
cellblock_voltage[42] = (((rx_frame.data.u8[0] & 0x1F) << 7) | ((rx_frame.data.u8[1] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[43] = (((rx_frame.data.u8[2] & 0x1F) << 7) | ((rx_frame.data.u8[3] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[44] = (((rx_frame.data.u8[4]) << 4) | ((rx_frame.data.u8[5] & 0xF0) >> 4)) * 1.25;
|
||||
break;
|
||||
case 7:
|
||||
cellblock_voltage[45] = (((rx_frame.data.u8[0] & 0x1F) << 7) | ((rx_frame.data.u8[1] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[46] = (((rx_frame.data.u8[2] & 0x1F) << 7) | ((rx_frame.data.u8[3] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[47] = (((rx_frame.data.u8[4]) << 4) | ((rx_frame.data.u8[5] & 0xF0) >> 4)) * 1.25;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x204: //High voltage Battery Cell Voltage Matrix 3
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
mux = ((rx_frame.data.u8[6] & 0xE0) >> 5); //goes from 0-7
|
||||
cellbank_mux = ((rx_frame.data.u8[6] & 0xE0) >> 5); //goes from 0-7
|
||||
switch (cellbank_mux) {
|
||||
case 0:
|
||||
cellblock_voltage[48] = (((rx_frame.data.u8[0] & 0x1F) << 7) | ((rx_frame.data.u8[1] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[49] = (((rx_frame.data.u8[2] & 0x1F) << 7) | ((rx_frame.data.u8[3] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[50] = (((rx_frame.data.u8[4]) << 4) | ((rx_frame.data.u8[5] & 0xF0) >> 4)) * 1.25;
|
||||
break;
|
||||
case 1:
|
||||
cellblock_voltage[51] = (((rx_frame.data.u8[0] & 0x1F) << 7) | ((rx_frame.data.u8[1] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[52] = (((rx_frame.data.u8[2] & 0x1F) << 7) | ((rx_frame.data.u8[3] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[53] = (((rx_frame.data.u8[4]) << 4) | ((rx_frame.data.u8[5] & 0xF0) >> 4)) * 1.25;
|
||||
break;
|
||||
case 2:
|
||||
cellblock_voltage[54] = (((rx_frame.data.u8[0] & 0x1F) << 7) | ((rx_frame.data.u8[1] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[55] = (((rx_frame.data.u8[2] & 0x1F) << 7) | ((rx_frame.data.u8[3] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[56] = (((rx_frame.data.u8[4]) << 4) | ((rx_frame.data.u8[5] & 0xF0) >> 4)) * 1.25;
|
||||
break;
|
||||
case 3:
|
||||
cellblock_voltage[57] = (((rx_frame.data.u8[0] & 0x1F) << 7) | ((rx_frame.data.u8[1] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[58] = (((rx_frame.data.u8[2] & 0x1F) << 7) | ((rx_frame.data.u8[3] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[59] = (((rx_frame.data.u8[4]) << 4) | ((rx_frame.data.u8[5] & 0xF0) >> 4)) * 1.25;
|
||||
break;
|
||||
case 4:
|
||||
cellblock_voltage[60] = (((rx_frame.data.u8[0] & 0x1F) << 7) | ((rx_frame.data.u8[1] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[61] = (((rx_frame.data.u8[2] & 0x1F) << 7) | ((rx_frame.data.u8[3] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[62] = (((rx_frame.data.u8[4]) << 4) | ((rx_frame.data.u8[5] & 0xF0) >> 4)) * 1.25;
|
||||
break;
|
||||
case 5:
|
||||
cellblock_voltage[63] = (((rx_frame.data.u8[0] & 0x1F) << 7) | ((rx_frame.data.u8[1] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[64] = (((rx_frame.data.u8[2] & 0x1F) << 7) | ((rx_frame.data.u8[3] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[65] = (((rx_frame.data.u8[4]) << 4) | ((rx_frame.data.u8[5] & 0xF0) >> 4)) * 1.25;
|
||||
break;
|
||||
case 6:
|
||||
cellblock_voltage[66] = (((rx_frame.data.u8[0] & 0x1F) << 7) | ((rx_frame.data.u8[1] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[67] = (((rx_frame.data.u8[2] & 0x1F) << 7) | ((rx_frame.data.u8[3] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[68] = (((rx_frame.data.u8[4]) << 4) | ((rx_frame.data.u8[5] & 0xF0) >> 4)) * 1.25;
|
||||
break;
|
||||
case 7:
|
||||
cellblock_voltage[69] = (((rx_frame.data.u8[0] & 0x1F) << 7) | ((rx_frame.data.u8[1] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[70] = (((rx_frame.data.u8[2] & 0x1F) << 7) | ((rx_frame.data.u8[3] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[71] = (((rx_frame.data.u8[4]) << 4) | ((rx_frame.data.u8[5] & 0xF0) >> 4)) * 1.25;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x206: //High voltage Battery Cell Voltage Matrix 4
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
mux = ((rx_frame.data.u8[6] & 0xE0) >> 5); //goes from 0-7
|
||||
cellbank_mux = ((rx_frame.data.u8[6] & 0xE0) >> 5); //goes from 0-7
|
||||
switch (cellbank_mux) {
|
||||
case 0:
|
||||
cellblock_voltage[72] = (((rx_frame.data.u8[0] & 0x1F) << 7) | ((rx_frame.data.u8[1] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[73] = (((rx_frame.data.u8[2] & 0x1F) << 7) | ((rx_frame.data.u8[3] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[74] = (((rx_frame.data.u8[4]) << 4) | ((rx_frame.data.u8[5] & 0xF0) >> 4)) * 1.25;
|
||||
break;
|
||||
case 1:
|
||||
cellblock_voltage[75] = (((rx_frame.data.u8[0] & 0x1F) << 7) | ((rx_frame.data.u8[1] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[76] = (((rx_frame.data.u8[2] & 0x1F) << 7) | ((rx_frame.data.u8[3] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[77] = (((rx_frame.data.u8[4]) << 4) | ((rx_frame.data.u8[5] & 0xF0) >> 4)) * 1.25;
|
||||
break;
|
||||
case 2:
|
||||
cellblock_voltage[78] = (((rx_frame.data.u8[0] & 0x1F) << 7) | ((rx_frame.data.u8[1] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[79] = (((rx_frame.data.u8[2] & 0x1F) << 7) | ((rx_frame.data.u8[3] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[80] = (((rx_frame.data.u8[4]) << 4) | ((rx_frame.data.u8[5] & 0xF0) >> 4)) * 1.25;
|
||||
break;
|
||||
case 3:
|
||||
cellblock_voltage[81] = (((rx_frame.data.u8[0] & 0x1F) << 7) | ((rx_frame.data.u8[1] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[82] = (((rx_frame.data.u8[2] & 0x1F) << 7) | ((rx_frame.data.u8[3] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[83] = (((rx_frame.data.u8[4]) << 4) | ((rx_frame.data.u8[5] & 0xF0) >> 4)) * 1.25;
|
||||
break;
|
||||
case 4:
|
||||
cellblock_voltage[84] = (((rx_frame.data.u8[0] & 0x1F) << 7) | ((rx_frame.data.u8[1] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[85] = (((rx_frame.data.u8[2] & 0x1F) << 7) | ((rx_frame.data.u8[3] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[86] = (((rx_frame.data.u8[4]) << 4) | ((rx_frame.data.u8[5] & 0xF0) >> 4)) * 1.25;
|
||||
break;
|
||||
case 5:
|
||||
cellblock_voltage[87] = (((rx_frame.data.u8[0] & 0x1F) << 7) | ((rx_frame.data.u8[1] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[88] = (((rx_frame.data.u8[2] & 0x1F) << 7) | ((rx_frame.data.u8[3] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[89] = (((rx_frame.data.u8[4]) << 4) | ((rx_frame.data.u8[5] & 0xF0) >> 4)) * 1.25;
|
||||
break;
|
||||
case 6:
|
||||
cellblock_voltage[90] = (((rx_frame.data.u8[0] & 0x1F) << 7) | ((rx_frame.data.u8[1] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[91] = (((rx_frame.data.u8[2] & 0x1F) << 7) | ((rx_frame.data.u8[3] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[92] = (((rx_frame.data.u8[4]) << 4) | ((rx_frame.data.u8[5] & 0xF0) >> 4)) * 1.25;
|
||||
break;
|
||||
case 7:
|
||||
cellblock_voltage[93] = (((rx_frame.data.u8[0] & 0x1F) << 7) | ((rx_frame.data.u8[1] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[94] = (((rx_frame.data.u8[2] & 0x1F) << 7) | ((rx_frame.data.u8[3] & 0xFE) >> 1)) * 1.25;
|
||||
cellblock_voltage[95] = (((rx_frame.data.u8[4]) << 4) | ((rx_frame.data.u8[5] & 0xF0) >> 4)) * 1.25;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x208: //High voltage Battery Cell Voltage Matrix 5
|
||||
case 0x208: //High voltage Battery Cell Voltage Matrix 5 (Empty on most packs)
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
mux = ((rx_frame.data.u8[6] & 0xE0) >> 5); //goes from 0-7
|
||||
cellbank_mux = ((rx_frame.data.u8[6] & 0xE0) >> 5); //goes from 0-7
|
||||
break;
|
||||
case 0x20A: //VICM Status HV
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x20C: //VITM Status HV
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
battery_isolation_kohm = (rx_frame.data.u8[1] * 25);
|
||||
battery_cell_voltage_max_mV = (rx_frame.data.u8[4] * 20);
|
||||
battery_cell_voltage_min_mV = (rx_frame.data.u8[5] * 20);
|
||||
break;
|
||||
case 0x216: // High voltage battery sensed Output HV
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
sensed_battery_voltage_mV = (((rx_frame.data.u8[1] & 0x0F) << 4) | rx_frame.data.u8[2]) * 125; //mV
|
||||
sensed_current_sensor_1 = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4]);
|
||||
sensed_current_sensor_2 = ((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6]);
|
||||
break;
|
||||
case 0x2C7:
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
battery_voltage_periodic = (rx_frame.data.u8[3] << 4) | (rx_frame.data.u8[4] >> 4);
|
||||
battery_voltage_periodic_dV = ((rx_frame.data.u8[3] << 4) | (rx_frame.data.u8[4] >> 4)) * 1.25;
|
||||
/*355V 2C7 [6] 03 20 00 AF A0 00
|
||||
360V 2C7 [6] 03 20 00 AD D0 00
|
||||
396V 2C7 [6] 03 20 53 C7 30 00*/
|
||||
break;
|
||||
case 0x260: //VITM Diagnostic Status 1 HV
|
||||
case 0x260: //VITM Diagnostic Status 1 HV (Contains which DTCs are active)
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x262: //Battery block voltage diagnostic status
|
||||
|
@ -174,28 +392,35 @@ void BoltAmperaBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
|||
temperature_4 = ((rx_frame.data.u8[4] / 2) - 40); //Module 4 Temperature
|
||||
temperature_5 = ((rx_frame.data.u8[5] / 2) - 40); //Module 5 Temperature
|
||||
temperature_6 = ((rx_frame.data.u8[6] / 2) - 40); //Module 6 Temperature
|
||||
//There is also a mux here to get more temps, but not required for our integration
|
||||
//since we only care about min and max temps (from message 3E3)
|
||||
break;
|
||||
case 0x304: //High Voltage Control Energy Management HV
|
||||
break;
|
||||
case 0x307: //High Voltage Battery SOC HV
|
||||
//TODO: Is this CAN message on all packs? If so, SOC is here
|
||||
break;
|
||||
case 0x3E3:
|
||||
case 0x308: //24 92 49 24 90
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x3E3: //Min and maximum values
|
||||
//Frame0 is cellvoltage min * 20
|
||||
//Frame1 is cellvoltage max * 20
|
||||
//Frame7 is cellvoltage avg * 20
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
temperature_lowest_C = ((rx_frame.data.u8[2] / 2) - 40);
|
||||
temperature_highest_C = ((rx_frame.data.u8[4] / 2) - 40);
|
||||
break;
|
||||
case 0x460: //Energy Storage System Temp HV
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
inlet_coolant_temperature = ((((rx_frame.data.u8[0] & 0x03) << 8) | rx_frame.data.u8[1]) / 2) - 40;
|
||||
outlet_coolant_temperature = ((((rx_frame.data.u8[2] & 0x03) << 8) | rx_frame.data.u8[3]) / 2) - 40;
|
||||
break;
|
||||
case 0x5EF: //OBD7E7 Unsolicited tester responce (ECU to tester)
|
||||
case 0x5EF: //OBD7E7 Unsolicited tester responce (UUDT)
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x5EC: //OBD7E4 Unsolicited tester responce (ECU to tester)
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x7EC: //When polling 7E4 BMS replies with 7EC
|
||||
case 0x7EC: //When polling 7E4 BMS replies with 7EC (This is not working for some reason)
|
||||
|
||||
if (rx_frame.data.u8[0] == 0x10) { //"PID Header"
|
||||
transmit_can_frame(&BOLT_ACK_7E4, can_config.battery);
|
||||
transmit_can_frame(&BOLT_ACK_7E4);
|
||||
}
|
||||
|
||||
//Frame 2 & 3 contains reply
|
||||
|
@ -267,7 +492,7 @@ void BoltAmperaBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
|||
case 0x7EF: //When polling 7E7 BMS replies with 7EF
|
||||
|
||||
if (rx_frame.data.u8[0] == 0x10) { //"PID Header"
|
||||
transmit_can_frame(&BOLT_ACK_7E7, can_config.battery);
|
||||
transmit_can_frame(&BOLT_ACK_7E7);
|
||||
}
|
||||
|
||||
//Frame 2 & 3 contains reply
|
||||
|
@ -611,7 +836,7 @@ void BoltAmperaBattery::transmit_can(unsigned long currentMillis) {
|
|||
//Send 20ms message
|
||||
if (currentMillis - previousMillis20ms >= INTERVAL_20_MS) {
|
||||
previousMillis20ms = currentMillis;
|
||||
transmit_can_frame(&BOLT_778, can_config.battery);
|
||||
transmit_can_frame(&BOLT_778);
|
||||
}
|
||||
|
||||
//Send 100ms message
|
||||
|
@ -625,7 +850,7 @@ void BoltAmperaBattery::transmit_can(unsigned long currentMillis) {
|
|||
BOLT_POLL_7E7.data.u8[2] = (uint8_t)((currentpoll_7E7 & 0xFF00) >> 8);
|
||||
BOLT_POLL_7E7.data.u8[3] = (uint8_t)(currentpoll_7E7 & 0x00FF);
|
||||
|
||||
transmit_can_frame(&BOLT_POLL_7E7, can_config.battery);
|
||||
transmit_can_frame(&BOLT_POLL_7E7);
|
||||
}
|
||||
|
||||
//Send 120ms message
|
||||
|
@ -639,7 +864,7 @@ void BoltAmperaBattery::transmit_can(unsigned long currentMillis) {
|
|||
BOLT_POLL_7E4.data.u8[2] = (uint8_t)((currentpoll_7E4 & 0xFF00) >> 8);
|
||||
BOLT_POLL_7E4.data.u8[3] = (uint8_t)(currentpoll_7E4 & 0x00FF);
|
||||
|
||||
transmit_can_frame(&BOLT_POLL_7E4, can_config.battery);
|
||||
//transmit_can_frame(&BOLT_POLL_7E4); //TODO: Battery does not seem to reply on this poll
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -647,6 +872,7 @@ void BoltAmperaBattery::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.battery.info.total_capacity_Wh = 64000;
|
||||
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;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#ifndef BOLT_AMPERA_BATTERY_H
|
||||
#define BOLT_AMPERA_BATTERY_H
|
||||
#include <Arduino.h>
|
||||
#include "../include.h"
|
||||
|
||||
#include "BOLT-AMPERA-HTML.h"
|
||||
#include "CanBattery.h"
|
||||
|
@ -23,11 +22,17 @@ class BoltAmperaBattery : public CanBattery {
|
|||
|
||||
private:
|
||||
BoltAmperaHtmlRenderer renderer;
|
||||
static const int MAX_PACK_VOLTAGE_DV = 4150; //5000 = 500.0V
|
||||
static const int MIN_PACK_VOLTAGE_DV = 2500;
|
||||
static const int MAX_DISCHARGE_POWER_ALLOWED_W = 10000;
|
||||
static const int MAX_CHARGE_POWER_ALLOWED_W = 10000;
|
||||
static const int MAX_CHARGE_POWER_WHEN_TOPBALANCING_W = 500;
|
||||
static const int RAMPDOWN_SOC =
|
||||
9000; // (90.00) SOC% to start ramping down from max charge power towards 0 at 100.00%
|
||||
|
||||
static const int MAX_PACK_VOLTAGE_DV = 4040; //5000 = 500.0V
|
||||
static const int MIN_PACK_VOLTAGE_DV = 2510;
|
||||
static const int MAX_CELL_DEVIATION_MV = 150;
|
||||
static const int MAX_CELL_VOLTAGE_MV = 4250; //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
|
||||
static const int MAX_CELL_VOLTAGE_MV = 4220; //Battery is put into emergency stop if one cell goes over this value
|
||||
static const int MIN_CELL_VOLTAGE_MV = 3000; //Battery is put into emergency stop if one cell goes below this value
|
||||
static const int POLL_7E4_CAPACITY_EST_GEN1 = 0x41A3;
|
||||
static const int POLL_7E4_CAPACITY_EST_GEN2 = 0x45F9;
|
||||
static const int POLL_7E4_SOC_DISPLAY = 0x8334;
|
||||
|
@ -167,30 +172,6 @@ class BoltAmperaBattery : public CanBattery {
|
|||
static const int POLL_7E7_CELL_94 = 0x423E;
|
||||
static const int POLL_7E7_CELL_95 = 0x423F;
|
||||
static const int POLL_7E7_CELL_96 = 0x4240;
|
||||
static const int POLL_7E7_CELL_97 = 0x4241; // Normal pack ends at 96, these cells might be unpopulated
|
||||
static const int POLL_7E7_CELL_98 = 0x4242;
|
||||
static const int POLL_7E7_CELL_99 = 0x4243;
|
||||
static const int POLL_7E7_CELL_100 = 0x4244;
|
||||
static const int POLL_7E7_CELL_101 = 0x4245;
|
||||
static const int POLL_7E7_CELL_102 = 0x4246;
|
||||
static const int POLL_7E7_CELL_103 = 0x4247;
|
||||
static const int POLL_7E7_CELL_104 = 0x4248;
|
||||
static const int POLL_7E7_CELL_105 = 0x4249;
|
||||
static const int POLL_7E7_CELL_106 = 0x424A;
|
||||
static const int POLL_7E7_CELL_107 = 0x424B;
|
||||
static const int POLL_7E7_CELL_108 = 0x424C;
|
||||
static const int POLL_7E7_CELL_109 = 0x424D;
|
||||
static const int POLL_7E7_CELL_110 = 0x424E;
|
||||
static const int POLL_7E7_CELL_111 = 0x424F;
|
||||
static const int POLL_7E7_CELL_112 = 0x4250;
|
||||
static const int POLL_7E7_CELL_113 = 0x4251;
|
||||
static const int POLL_7E7_CELL_114 = 0x4252;
|
||||
static const int POLL_7E7_CELL_115 = 0x4253;
|
||||
static const int POLL_7E7_CELL_116 = 0x4254;
|
||||
static const int POLL_7E7_CELL_117 = 0x4255;
|
||||
static const int POLL_7E7_CELL_118 = 0x4256;
|
||||
static const int POLL_7E7_CELL_119 = 0x4257;
|
||||
static const int POLL_7E7_CELL_120 = 0x4258;
|
||||
|
||||
unsigned long previousMillis20ms = 0; // will store last time a 20ms CAN Message was send
|
||||
unsigned long previousMillis100ms = 0; // will store last time a 100ms CAN Message was send
|
||||
|
@ -226,11 +207,16 @@ class BoltAmperaBattery : public CanBattery {
|
|||
// All HV ECUs - 0x101
|
||||
// HPCC HV - 0x243 replies on 0x643
|
||||
// OBCM HV - 0x244 replies on 0x644
|
||||
// VICM_HV - 0x7E4 replies 0x7EC (This is battery)
|
||||
// VICM2_HV - 0x7E6 replies 0x7EF (Tis is battery also)
|
||||
// VICM_HV - 0x7E4 replies 0x7EC (This is battery?)
|
||||
// VICM2_HV - 0x7E6 replies 0x7EF (Tis is battery also?)
|
||||
// VITM_HV - 0x7E7 replies on 7EF (This is battery)
|
||||
|
||||
uint16_t battery_cell_voltages[96]; //array with all the cellvoltages
|
||||
uint16_t soc_periodic = 0;
|
||||
uint16_t battery_cell_voltages[96]; //array with all the cellvoltages polled via PID
|
||||
uint16_t cellblock_voltage[96]; //array with all the cellvoltages, constantly broadcasted
|
||||
uint32_t sensed_battery_voltage_mV = 0;
|
||||
int16_t sensed_current_sensor_1 = 0;
|
||||
int16_t sensed_current_sensor_2 = 0;
|
||||
uint16_t battery_capacity_my17_18 = 0;
|
||||
uint16_t battery_capacity_my19plus = 0;
|
||||
uint16_t battery_SOC_display = 0;
|
||||
|
@ -243,9 +229,9 @@ class BoltAmperaBattery : public CanBattery {
|
|||
uint16_t battery_lowest_cell = 0;
|
||||
uint16_t battery_highest_cell = 0;
|
||||
uint16_t battery_voltage_polled = 0;
|
||||
uint16_t battery_voltage_periodic = 0;
|
||||
uint16_t battery_voltage_periodic_dV = 3700;
|
||||
uint16_t battery_vehicle_isolation = 0;
|
||||
uint16_t battery_isolation_kohm = 0;
|
||||
uint16_t battery_isolation_kohm = 9999;
|
||||
uint16_t battery_HV_locked = 0;
|
||||
uint16_t battery_crash_event = 0;
|
||||
uint16_t battery_HVIL = 0;
|
||||
|
@ -258,20 +244,24 @@ class BoltAmperaBattery : public CanBattery {
|
|||
int16_t battery_module_temp_4 = 0;
|
||||
int16_t battery_module_temp_5 = 0;
|
||||
int16_t battery_module_temp_6 = 0;
|
||||
uint16_t battery_cell_voltage_max_mV = 3700;
|
||||
uint16_t battery_cell_voltage_min_mV = 3700;
|
||||
uint16_t battery_cell_average_voltage = 0;
|
||||
uint16_t battery_cell_average_voltage_2 = 0;
|
||||
uint16_t battery_terminal_voltage = 0;
|
||||
uint16_t battery_ignition_power_mode = 0;
|
||||
int16_t battery_current_7E7 = 0;
|
||||
int16_t inlet_coolant_temperature = 0;
|
||||
int16_t outlet_coolant_temperature = 0;
|
||||
int16_t temperature_1 = 0;
|
||||
int16_t temperature_2 = 0;
|
||||
int16_t temperature_3 = 0;
|
||||
int16_t temperature_4 = 0;
|
||||
int16_t temperature_5 = 0;
|
||||
int16_t temperature_6 = 0;
|
||||
int16_t temperature_highest = 0;
|
||||
int16_t temperature_lowest = 0;
|
||||
uint8_t mux = 0;
|
||||
int16_t temperature_highest_C = 0;
|
||||
int16_t temperature_lowest_C = 0;
|
||||
uint8_t cellbank_mux = 0;
|
||||
uint8_t poll_index_7E4 = 0;
|
||||
uint16_t currentpoll_7E4 = POLL_7E4_CAPACITY_EST_GEN1;
|
||||
uint16_t reply_poll_7E4 = 0;
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#include "../datalayer/datalayer.h"
|
||||
#include "../datalayer/datalayer_extended.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../include.h"
|
||||
|
||||
/* Notes
|
||||
SOC% by default is now ESTIMATED.
|
||||
|
@ -21,17 +20,17 @@ After battery has been unlocked, you can remove the "USE_ESTIMATED_SOC" from the
|
|||
#define UNKNOWN_POLL_0 0x1FFE //0x64 19 C4 3B
|
||||
#define UNKNOWN_POLL_1 0x1FFC //0x72 1F C4 3B
|
||||
#define POLL_MAX_CHARGE_POWER 0x000A
|
||||
#define UNKNOWN_POLL_3 0x000B //0x00B1 (177 interesting!)
|
||||
#define UNKNOWN_POLL_4 0x000E //0x0B27 (2855 interesting!)
|
||||
#define POLL_CHARGE_TIMES 0x000B // Using Carscanner name for now. Likely a counter for BMS 100% SOC calibration
|
||||
#define POLL_MAX_DISCHARGE_POWER 0x000E
|
||||
#define POLL_TOTAL_CHARGED_AH 0x000F
|
||||
#define POLL_TOTAL_DISCHARGED_AH 0x0010
|
||||
#define POLL_TOTAL_CHARGED_KWH 0x0011
|
||||
#define POLL_TOTAL_DISCHARGED_KWH 0x0012
|
||||
#define UNKNOWN_POLL_9 0x0004 //0x0034 (52 interesting!)
|
||||
#define UNKNOWN_POLL_10 0x002A //0x5B
|
||||
#define UNKNOWN_POLL_11 0x002E //0x08 (probably module number, or cell number?)
|
||||
#define UNKNOWN_POLL_12 0x002C //0x43
|
||||
#define UNKNOWN_POLL_13 0x0030 //0x01 (probably module number, or cell number?)
|
||||
#define POLL_TIMES_FULL_POWER 0x0004 // Using Carscanner name for now. Unknown what it means for the moment
|
||||
#define UNKNOWN_POLL_10 0x002A //0x5B
|
||||
#define UNKNOWN_POLL_11 0x002E //0x08 (probably module number, or cell number?)
|
||||
#define UNKNOWN_POLL_12 0x002C //0x43
|
||||
#define UNKNOWN_POLL_13 0x0030 //0x01 (probably module number, or cell number?)
|
||||
#define POLL_MODULE_1_LOWEST_MV_NUMBER 0x016C
|
||||
#define POLL_MODULE_1_LOWEST_CELL_MV 0x016D
|
||||
#define POLL_MODULE_1_HIGHEST_MV_NUMBER 0x016E
|
||||
|
@ -172,9 +171,20 @@ void BydAttoBattery::
|
|||
datalayer_battery->status.remaining_capacity_Wh = static_cast<uint32_t>(
|
||||
(static_cast<double>(datalayer_battery->status.real_soc) / 10000) * datalayer_battery->info.total_capacity_Wh);
|
||||
|
||||
datalayer_battery->status.max_discharge_power_W = MAXPOWER_DISCHARGE_W; //TODO: Map from CAN later on
|
||||
if (SOC_method == ESTIMATED && battery_estimated_SOC * 0.1 < RAMPDOWN_SOC && RAMPDOWN_SOC > 0) {
|
||||
// If using estimated SOC, ramp down max discharge power as SOC decreases.
|
||||
rampdown_power = RAMPDOWN_POWER_ALLOWED * ((battery_estimated_SOC * 0.1) / RAMPDOWN_SOC);
|
||||
|
||||
datalayer_battery->status.max_charge_power_W = BMS_allowed_charge_power * 10; //TODO: Scaling unknown, *10 best guess
|
||||
if (rampdown_power < BMS_allowed_discharge_power * 100) { // Never allow more than BMS_allowed_discharge_power
|
||||
datalayer_battery->status.max_discharge_power_W = rampdown_power;
|
||||
} else {
|
||||
datalayer_battery->status.max_discharge_power_W = BMS_allowed_discharge_power * 100;
|
||||
}
|
||||
} else {
|
||||
datalayer_battery->status.max_discharge_power_W = BMS_allowed_discharge_power * 100;
|
||||
}
|
||||
|
||||
datalayer_battery->status.max_charge_power_W = BMS_allowed_charge_power * 100;
|
||||
|
||||
datalayer_battery->status.cell_max_voltage_mV = BMS_highest_cell_voltage_mV;
|
||||
|
||||
|
@ -277,13 +287,13 @@ void BydAttoBattery::
|
|||
datalayer_bydatto->unknown0 = BMS_unknown0;
|
||||
datalayer_bydatto->unknown1 = BMS_unknown1;
|
||||
datalayer_bydatto->chargePower = BMS_allowed_charge_power;
|
||||
datalayer_bydatto->unknown3 = BMS_unknown3;
|
||||
datalayer_bydatto->unknown4 = BMS_unknown4;
|
||||
datalayer_bydatto->charge_times = BMS_charge_times;
|
||||
datalayer_bydatto->dischargePower = BMS_allowed_discharge_power;
|
||||
datalayer_bydatto->total_charged_ah = BMS_total_charged_ah;
|
||||
datalayer_bydatto->total_discharged_ah = BMS_total_discharged_ah;
|
||||
datalayer_bydatto->total_charged_kwh = BMS_total_charged_kwh;
|
||||
datalayer_bydatto->total_discharged_kwh = BMS_total_discharged_kwh;
|
||||
datalayer_bydatto->unknown9 = BMS_unknown9;
|
||||
datalayer_bydatto->times_full_power = BMS_times_full_power;
|
||||
datalayer_bydatto->unknown10 = BMS_unknown10;
|
||||
datalayer_bydatto->unknown11 = BMS_unknown11;
|
||||
datalayer_bydatto->unknown12 = BMS_unknown12;
|
||||
|
@ -400,7 +410,7 @@ void BydAttoBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
|||
break;
|
||||
case 0x7EF: //OBD2 PID reply from battery
|
||||
if (rx_frame.data.u8[0] == 0x10) {
|
||||
transmit_can_frame(&ATTO_3_7E7_ACK, can_interface); //Send next line request
|
||||
transmit_can_frame(&ATTO_3_7E7_ACK); //Send next line request
|
||||
}
|
||||
pid_reply = ((rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]);
|
||||
switch (pid_reply) {
|
||||
|
@ -439,11 +449,11 @@ void BydAttoBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
|||
case POLL_MAX_CHARGE_POWER:
|
||||
BMS_allowed_charge_power = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4];
|
||||
break;
|
||||
case UNKNOWN_POLL_3:
|
||||
BMS_unknown3 = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4];
|
||||
case POLL_CHARGE_TIMES:
|
||||
BMS_charge_times = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4];
|
||||
break;
|
||||
case UNKNOWN_POLL_4:
|
||||
BMS_unknown4 = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4];
|
||||
case POLL_MAX_DISCHARGE_POWER:
|
||||
BMS_allowed_discharge_power = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4];
|
||||
break;
|
||||
case POLL_TOTAL_CHARGED_AH:
|
||||
BMS_total_charged_ah = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4];
|
||||
|
@ -457,8 +467,8 @@ void BydAttoBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
|||
case POLL_TOTAL_DISCHARGED_KWH:
|
||||
BMS_total_discharged_kwh = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4];
|
||||
break;
|
||||
case UNKNOWN_POLL_9:
|
||||
BMS_unknown9 = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4];
|
||||
case POLL_TIMES_FULL_POWER:
|
||||
BMS_times_full_power = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4];
|
||||
break;
|
||||
case UNKNOWN_POLL_10:
|
||||
BMS_unknown10 = rx_frame.data.u8[4];
|
||||
|
@ -517,7 +527,7 @@ void BydAttoBattery::transmit_can(unsigned long currentMillis) {
|
|||
ATTO_3_12D.data.u8[6] = (0x0F | (frame6_counter << 4));
|
||||
ATTO_3_12D.data.u8[7] = (0x09 | (frame7_counter << 4));
|
||||
|
||||
transmit_can_frame(&ATTO_3_12D, can_interface);
|
||||
transmit_can_frame(&ATTO_3_12D);
|
||||
}
|
||||
// Send 100ms CAN Message
|
||||
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
|
||||
|
@ -534,21 +544,21 @@ void BydAttoBattery::transmit_can(unsigned long currentMillis) {
|
|||
ATTO_3_441.data.u8[7] = 0xF5;
|
||||
}
|
||||
|
||||
transmit_can_frame(&ATTO_3_441, can_interface);
|
||||
transmit_can_frame(&ATTO_3_441);
|
||||
switch (stateMachineClearCrash) {
|
||||
case STARTED:
|
||||
ATTO_3_7E7_CLEAR_CRASH.data = {0x02, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
transmit_can_frame(&ATTO_3_7E7_CLEAR_CRASH, can_interface);
|
||||
transmit_can_frame(&ATTO_3_7E7_CLEAR_CRASH);
|
||||
stateMachineClearCrash = RUNNING_STEP_1;
|
||||
break;
|
||||
case RUNNING_STEP_1:
|
||||
ATTO_3_7E7_CLEAR_CRASH.data = {0x04, 0x14, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00};
|
||||
transmit_can_frame(&ATTO_3_7E7_CLEAR_CRASH, can_interface);
|
||||
transmit_can_frame(&ATTO_3_7E7_CLEAR_CRASH);
|
||||
stateMachineClearCrash = RUNNING_STEP_2;
|
||||
break;
|
||||
case RUNNING_STEP_2:
|
||||
ATTO_3_7E7_CLEAR_CRASH.data = {0x03, 0x19, 0x02, 0x09, 0x00, 0x00, 0x00, 0x00};
|
||||
transmit_can_frame(&ATTO_3_7E7_CLEAR_CRASH, can_interface);
|
||||
transmit_can_frame(&ATTO_3_7E7_CLEAR_CRASH);
|
||||
stateMachineClearCrash = NOT_RUNNING;
|
||||
break;
|
||||
case NOT_RUNNING:
|
||||
|
@ -615,16 +625,16 @@ void BydAttoBattery::transmit_can(unsigned long currentMillis) {
|
|||
case POLL_MAX_CHARGE_POWER:
|
||||
ATTO_3_7E7_POLL.data.u8[2] = (uint8_t)((POLL_MAX_CHARGE_POWER & 0xFF00) >> 8);
|
||||
ATTO_3_7E7_POLL.data.u8[3] = (uint8_t)(POLL_MAX_CHARGE_POWER & 0x00FF);
|
||||
poll_state = UNKNOWN_POLL_3;
|
||||
poll_state = POLL_CHARGE_TIMES;
|
||||
break;
|
||||
case UNKNOWN_POLL_3:
|
||||
ATTO_3_7E7_POLL.data.u8[2] = (uint8_t)((UNKNOWN_POLL_3 & 0xFF00) >> 8);
|
||||
ATTO_3_7E7_POLL.data.u8[3] = (uint8_t)(UNKNOWN_POLL_3 & 0x00FF);
|
||||
poll_state = UNKNOWN_POLL_4;
|
||||
case POLL_CHARGE_TIMES:
|
||||
ATTO_3_7E7_POLL.data.u8[2] = (uint8_t)((POLL_CHARGE_TIMES & 0xFF00) >> 8);
|
||||
ATTO_3_7E7_POLL.data.u8[3] = (uint8_t)(POLL_CHARGE_TIMES & 0x00FF);
|
||||
poll_state = POLL_MAX_DISCHARGE_POWER;
|
||||
break;
|
||||
case UNKNOWN_POLL_4:
|
||||
ATTO_3_7E7_POLL.data.u8[2] = (uint8_t)((UNKNOWN_POLL_4 & 0xFF00) >> 8);
|
||||
ATTO_3_7E7_POLL.data.u8[3] = (uint8_t)(UNKNOWN_POLL_4 & 0x00FF);
|
||||
case POLL_MAX_DISCHARGE_POWER:
|
||||
ATTO_3_7E7_POLL.data.u8[2] = (uint8_t)((POLL_MAX_DISCHARGE_POWER & 0xFF00) >> 8);
|
||||
ATTO_3_7E7_POLL.data.u8[3] = (uint8_t)(POLL_MAX_DISCHARGE_POWER & 0x00FF);
|
||||
poll_state = POLL_TOTAL_CHARGED_AH;
|
||||
break;
|
||||
case POLL_TOTAL_CHARGED_AH:
|
||||
|
@ -645,11 +655,11 @@ void BydAttoBattery::transmit_can(unsigned long currentMillis) {
|
|||
case POLL_TOTAL_DISCHARGED_KWH:
|
||||
ATTO_3_7E7_POLL.data.u8[2] = (uint8_t)((POLL_TOTAL_DISCHARGED_KWH & 0xFF00) >> 8);
|
||||
ATTO_3_7E7_POLL.data.u8[3] = (uint8_t)(POLL_TOTAL_DISCHARGED_KWH & 0x00FF);
|
||||
poll_state = UNKNOWN_POLL_9;
|
||||
poll_state = POLL_TIMES_FULL_POWER;
|
||||
break;
|
||||
case UNKNOWN_POLL_9:
|
||||
ATTO_3_7E7_POLL.data.u8[2] = (uint8_t)((UNKNOWN_POLL_9 & 0xFF00) >> 8);
|
||||
ATTO_3_7E7_POLL.data.u8[3] = (uint8_t)(UNKNOWN_POLL_9 & 0x00FF);
|
||||
case POLL_TIMES_FULL_POWER:
|
||||
ATTO_3_7E7_POLL.data.u8[2] = (uint8_t)((POLL_TIMES_FULL_POWER & 0xFF00) >> 8);
|
||||
ATTO_3_7E7_POLL.data.u8[3] = (uint8_t)(POLL_TIMES_FULL_POWER & 0x00FF);
|
||||
poll_state = UNKNOWN_POLL_10;
|
||||
break;
|
||||
case UNKNOWN_POLL_10:
|
||||
|
@ -678,7 +688,7 @@ void BydAttoBattery::transmit_can(unsigned long currentMillis) {
|
|||
}
|
||||
|
||||
if (stateMachineClearCrash == NOT_RUNNING) { //Don't poll battery for data if clear crash running
|
||||
transmit_can_frame(&ATTO_3_7E7_POLL, can_interface);
|
||||
transmit_can_frame(&ATTO_3_7E7_POLL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,20 +3,22 @@
|
|||
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../datalayer/datalayer_extended.h"
|
||||
#include "../include.h"
|
||||
|
||||
#include "BYD-ATTO-3-HTML.h"
|
||||
#include "CanBattery.h"
|
||||
|
||||
#define USE_ESTIMATED_SOC // If enabled, SOC is estimated from pack voltage. Useful for locked packs. \
|
||||
// Comment out this only if you know your BMS is unlocked and able to send SOC%
|
||||
#define MAXPOWER_CHARGE_W 10000
|
||||
#define MAXPOWER_DISCHARGE_W 10000
|
||||
|
||||
//Uncomment and configure this line, if you want to filter out a broken temperature sensor (1-10)
|
||||
//Make sure you understand risks associated with disabling. Values can be read via "More Battery info"
|
||||
//#define SKIP_TEMPERATURE_SENSOR_NUMBER 1
|
||||
|
||||
// Ramp down settings that are used when SOC is estimated from voltage
|
||||
static const int RAMPDOWN_SOC = 100; // SOC to start ramping down from. Value set here is scaled by 10 (100 = 10.0%)
|
||||
static const int RAMPDOWN_POWER_ALLOWED =
|
||||
10000; // Power to start ramp down from, set a lower value to limit the power even further as SOC decreases
|
||||
|
||||
/* Do not modify the rows below */
|
||||
#ifdef BYD_ATTO_3_BATTERY
|
||||
#define SELECTED_BATTERY_CLASS BydAttoBattery
|
||||
|
@ -116,19 +118,20 @@ class BydAttoBattery : public CanBattery {
|
|||
uint32_t BMS_unknown0 = 0;
|
||||
uint32_t BMS_unknown1 = 0;
|
||||
uint16_t BMS_allowed_charge_power = 0;
|
||||
uint16_t BMS_unknown3 = 0;
|
||||
uint16_t BMS_unknown4 = 0;
|
||||
uint16_t BMS_charge_times = 0;
|
||||
uint16_t BMS_allowed_discharge_power = 0;
|
||||
uint16_t BMS_total_charged_ah = 0;
|
||||
uint16_t BMS_total_discharged_ah = 0;
|
||||
uint16_t BMS_total_charged_kwh = 0;
|
||||
uint16_t BMS_total_discharged_kwh = 0;
|
||||
uint16_t BMS_unknown9 = 0;
|
||||
uint16_t BMS_times_full_power = 0;
|
||||
uint8_t BMS_unknown10 = 0;
|
||||
uint8_t BMS_unknown11 = 0;
|
||||
uint8_t BMS_unknown12 = 0;
|
||||
uint8_t BMS_unknown13 = 0;
|
||||
uint8_t battery_frame_index = 0;
|
||||
uint16_t battery_cellvoltages[CELLCOUNT_EXTENDED] = {0};
|
||||
uint16_t rampdown_power = 0;
|
||||
|
||||
uint16_t poll_state = POLL_FOR_BATTERY_SOC;
|
||||
uint16_t pid_reply = 0;
|
||||
|
|
|
@ -12,33 +12,38 @@ class BydAtto3HtmlRenderer : public BatteryHtmlRenderer {
|
|||
String get_status_html() {
|
||||
String content;
|
||||
|
||||
float soc_estimated = static_cast<float>(byd_datalayer->SOC_estimated) * 0.01;
|
||||
float soc_measured = static_cast<float>(byd_datalayer->SOC_highprec) * 0.1;
|
||||
float BMS_maxChargePower = static_cast<float>(byd_datalayer->chargePower) * 0.1;
|
||||
float BMS_maxDischargePower = static_cast<float>(byd_datalayer->dischargePower) * 0.1;
|
||||
static const char* SOCmethod[2] = {"Estimated from voltage", "Measured by BMS"};
|
||||
|
||||
content += "<h4>SOC method used: " + String(SOCmethod[byd_datalayer->SOC_method]) + "</h4>";
|
||||
content += "<h4>SOC estimated: " + String(byd_datalayer->SOC_estimated) + "</h4>";
|
||||
content += "<h4>SOC highprec: " + String(byd_datalayer->SOC_highprec) + "</h4>";
|
||||
content += "<h4>SOC OBD2: " + String(byd_datalayer->SOC_polled) + "</h4>";
|
||||
content += "<h4>Voltage periodic: " + String(byd_datalayer->voltage_periodic) + "</h4>";
|
||||
content += "<h4>Voltage OBD2: " + String(byd_datalayer->voltage_polled) + "</h4>";
|
||||
content += "<h4>Temperature sensor 1: " + String(byd_datalayer->battery_temperatures[0]) + "</h4>";
|
||||
content += "<h4>Temperature sensor 2: " + String(byd_datalayer->battery_temperatures[1]) + "</h4>";
|
||||
content += "<h4>Temperature sensor 3: " + String(byd_datalayer->battery_temperatures[2]) + "</h4>";
|
||||
content += "<h4>Temperature sensor 4: " + String(byd_datalayer->battery_temperatures[3]) + "</h4>";
|
||||
content += "<h4>Temperature sensor 5: " + String(byd_datalayer->battery_temperatures[4]) + "</h4>";
|
||||
content += "<h4>Temperature sensor 6: " + String(byd_datalayer->battery_temperatures[5]) + "</h4>";
|
||||
content += "<h4>Temperature sensor 7: " + String(byd_datalayer->battery_temperatures[6]) + "</h4>";
|
||||
content += "<h4>Temperature sensor 8: " + String(byd_datalayer->battery_temperatures[7]) + "</h4>";
|
||||
content += "<h4>Temperature sensor 9: " + String(byd_datalayer->battery_temperatures[8]) + "</h4>";
|
||||
content += "<h4>Temperature sensor 10: " + String(byd_datalayer->battery_temperatures[9]) + "</h4>";
|
||||
content += "<h4>SOC estimated: " + String(soc_estimated) + "%</h4>";
|
||||
content += "<h4>SOC measured: " + String(soc_measured) + "%</h4>";
|
||||
content += "<h4>SOC OBD2: " + String(byd_datalayer->SOC_polled) + "%</h4>";
|
||||
content += "<h4>Voltage periodic: " + String(byd_datalayer->voltage_periodic) + " V</h4>";
|
||||
content += "<h4>Voltage OBD2: " + String(byd_datalayer->voltage_polled) + " V</h4>";
|
||||
content += "<h4>Temperature sensor 1: " + String(byd_datalayer->battery_temperatures[0]) + " °C</h4>";
|
||||
content += "<h4>Temperature sensor 2: " + String(byd_datalayer->battery_temperatures[1]) + " °C</h4>";
|
||||
content += "<h4>Temperature sensor 3: " + String(byd_datalayer->battery_temperatures[2]) + " °C</h4>";
|
||||
content += "<h4>Temperature sensor 4: " + String(byd_datalayer->battery_temperatures[3]) + " °C</h4>";
|
||||
content += "<h4>Temperature sensor 5: " + String(byd_datalayer->battery_temperatures[4]) + " °C</h4>";
|
||||
content += "<h4>Temperature sensor 6: " + String(byd_datalayer->battery_temperatures[5]) + " °C</h4>";
|
||||
content += "<h4>Temperature sensor 7: " + String(byd_datalayer->battery_temperatures[6]) + " °C</h4>";
|
||||
content += "<h4>Temperature sensor 8: " + String(byd_datalayer->battery_temperatures[7]) + " °C</h4>";
|
||||
content += "<h4>Temperature sensor 9: " + String(byd_datalayer->battery_temperatures[8]) + " °C</h4>";
|
||||
content += "<h4>Temperature sensor 10: " + String(byd_datalayer->battery_temperatures[9]) + " °C</h4>";
|
||||
content += "<h4>Max discharge power: " + String(BMS_maxDischargePower) + " kW</h4>";
|
||||
content += "<h4>Max charge (regen) power: " + String(BMS_maxChargePower) + " kW</h4>";
|
||||
content += "<h4>Total charged: " + String(byd_datalayer->total_charged_kwh) + " kWh</h4>";
|
||||
content += "<h4>Total discharged: " + String(byd_datalayer->total_discharged_kwh) + " kWh</h4>";
|
||||
content += "<h4>Total charged: " + String(byd_datalayer->total_charged_ah) + " Ah</h4>";
|
||||
content += "<h4>Total discharged: " + String(byd_datalayer->total_discharged_ah) + " Ah</h4>";
|
||||
content += "<h4>Charge times: " + String(byd_datalayer->charge_times) + "</h4>";
|
||||
content += "<h4>Times of full power: " + String(byd_datalayer->times_full_power) + "</h4>";
|
||||
content += "<h4>Unknown0: " + String(byd_datalayer->unknown0) + "</h4>";
|
||||
content += "<h4>Unknown1: " + String(byd_datalayer->unknown1) + "</h4>";
|
||||
content += "<h4>Charge power raw: " + String(byd_datalayer->chargePower) + "</h4>";
|
||||
content += "<h4>Unknown3: " + String(byd_datalayer->unknown3) + "</h4>";
|
||||
content += "<h4>Unknown4: " + String(byd_datalayer->unknown4) + "</h4>";
|
||||
content += "<h4>Total charged Ah: " + String(byd_datalayer->total_charged_ah) + "</h4>";
|
||||
content += "<h4>Total discharged Ah: " + String(byd_datalayer->total_discharged_ah) + "</h4>";
|
||||
content += "<h4>Total charged kWh: " + String(byd_datalayer->total_charged_kwh) + "</h4>";
|
||||
content += "<h4>Total discharged kWh: " + String(byd_datalayer->total_discharged_kwh) + "</h4>";
|
||||
content += "<h4>Unknown9: " + String(byd_datalayer->unknown9) + "</h4>";
|
||||
content += "<h4>Unknown10: " + String(byd_datalayer->unknown10) + "</h4>";
|
||||
content += "<h4>Unknown11: " + String(byd_datalayer->unknown11) + "</h4>";
|
||||
content += "<h4>Unknown12: " + String(byd_datalayer->unknown12) + "</h4>";
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
#define BATTERY_H
|
||||
|
||||
#include <vector>
|
||||
#include "src/devboard/utils/types.h"
|
||||
#include "src/devboard/webserver/BatteryHtmlRenderer.h"
|
||||
|
||||
enum class BatteryType {
|
||||
None = 0,
|
||||
BmwSbox = 1,
|
||||
BmwI3 = 2,
|
||||
BmwIx = 3,
|
||||
BoltAmpera = 4,
|
||||
|
@ -48,10 +48,14 @@ enum class BatteryType {
|
|||
|
||||
extern std::vector<BatteryType> supported_battery_types();
|
||||
extern const char* name_for_battery_type(BatteryType type);
|
||||
extern const char* name_for_chemistry(battery_chemistry_enum chem);
|
||||
extern const char* name_for_comm_interface(comm_interface comm);
|
||||
|
||||
extern BatteryType user_selected_battery_type;
|
||||
extern bool user_selected_second_battery;
|
||||
|
||||
extern battery_chemistry_enum user_selected_battery_chemistry;
|
||||
|
||||
// Abstract base class for next-generation battery implementations.
|
||||
// Defines the interface to call battery specific functionality.
|
||||
class Battery {
|
||||
|
@ -60,7 +64,7 @@ class Battery {
|
|||
virtual void update_values() = 0;
|
||||
|
||||
// The name of the comm interface the battery is using.
|
||||
virtual String interface_name() = 0;
|
||||
virtual const char* interface_name() = 0;
|
||||
|
||||
// These are commands from external I/O (UI, MQTT etc.)
|
||||
// Override in battery if it supports them. Otherwise they are NOP.
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#include "../datalayer/datalayer.h"
|
||||
#include "../datalayer/datalayer_extended.h" //For "More battery info" webpage
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../include.h"
|
||||
|
||||
void CellPowerBms::update_values() {
|
||||
|
||||
|
@ -220,10 +219,10 @@ void CellPowerBms::transmit_can(unsigned long currentMillis) {
|
|||
previousMillis1s = currentMillis;
|
||||
|
||||
/*
|
||||
transmit_can_frame(&CELLPOWER_18FF50E9, can_config.battery);
|
||||
transmit_can_frame(&CELLPOWER_18FF50E8, can_config.battery);
|
||||
transmit_can_frame(&CELLPOWER_18FF50E7, can_config.battery);
|
||||
transmit_can_frame(&CELLPOWER_18FF50E5, can_config.battery);
|
||||
transmit_can_frame(&CELLPOWER_18FF50E9);
|
||||
transmit_can_frame(&CELLPOWER_18FF50E8);
|
||||
transmit_can_frame(&CELLPOWER_18FF50E7);
|
||||
transmit_can_frame(&CELLPOWER_18FF50E5);
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#ifndef CELLPOWER_BMS_H
|
||||
#define CELLPOWER_BMS_H
|
||||
#include <Arduino.h>
|
||||
#include "../include.h"
|
||||
#include "CELLPOWER-HTML.h"
|
||||
#include "CanBattery.h"
|
||||
|
||||
|
@ -11,7 +10,7 @@
|
|||
|
||||
class CellPowerBms : public CanBattery {
|
||||
public:
|
||||
CellPowerBms() : CanBattery(true) {}
|
||||
CellPowerBms() : CanBattery(CAN_Speed::CAN_SPEED_250KBPS) {}
|
||||
|
||||
virtual void setup(void);
|
||||
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
#include "CHADEMO-BATTERY.h"
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../include.h"
|
||||
#include "CHADEMO-SHUNTS.h"
|
||||
|
||||
#ifdef CHADEMO_PIN_2 // Only support chademo for certain platforms
|
||||
|
||||
//This function maps all the values fetched via CAN to the correct parameters used for the inverter
|
||||
void ChademoBattery::update_values() {
|
||||
|
||||
|
@ -93,7 +90,7 @@ void ChademoBattery::process_vehicle_charging_session(CAN_frame rx_frame) {
|
|||
|
||||
vehicle_can_initialized = true;
|
||||
|
||||
vehicle_permission = digitalRead(CHADEMO_PIN_4);
|
||||
vehicle_permission = digitalRead(pin4);
|
||||
|
||||
x102_chg_session.ControlProtocolNumberEV = rx_frame.data.u8[0];
|
||||
|
||||
|
@ -598,8 +595,8 @@ void ChademoBattery::transmit_can(unsigned long currentMillis) {
|
|||
* that is the limiting factor. Therefore, we
|
||||
* can generally send as is without tweaks here.
|
||||
*/
|
||||
transmit_can_frame(&CHADEMO_108, can_config.battery);
|
||||
transmit_can_frame(&CHADEMO_109, can_config.battery);
|
||||
transmit_can_frame(&CHADEMO_108);
|
||||
transmit_can_frame(&CHADEMO_109);
|
||||
|
||||
/* TODO for dynamic control: can send x118 with byte 6 bit 0 set to 0 for 1s (before flipping back to 1) as a way of giving vehicle a chance to update 101.1 and 101.2
|
||||
* within 6 seconds of x118 toggle.
|
||||
|
@ -608,9 +605,9 @@ void ChademoBattery::transmit_can(unsigned long currentMillis) {
|
|||
*/
|
||||
|
||||
if (EVSE_mode == CHADEMO_DISCHARGE || EVSE_mode == CHADEMO_BIDIRECTIONAL) {
|
||||
transmit_can_frame(&CHADEMO_208, can_config.battery);
|
||||
transmit_can_frame(&CHADEMO_208);
|
||||
if (x201_received) {
|
||||
transmit_can_frame(&CHADEMO_209, can_config.battery);
|
||||
transmit_can_frame(&CHADEMO_209);
|
||||
x209_sent = true;
|
||||
}
|
||||
}
|
||||
|
@ -622,7 +619,7 @@ void ChademoBattery::transmit_can(unsigned long currentMillis) {
|
|||
//FIXME REMOVE
|
||||
logging.println("REMOVE: proto 2.0");
|
||||
#endif
|
||||
transmit_can_frame(&CHADEMO_118, can_config.battery);
|
||||
transmit_can_frame(&CHADEMO_118);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -650,10 +647,11 @@ void ChademoBattery::transmit_can(unsigned long currentMillis) {
|
|||
*/
|
||||
void ChademoBattery::handle_chademo_sequence() {
|
||||
|
||||
precharge_low = digitalRead(PRECHARGE_PIN) == LOW;
|
||||
positive_high = digitalRead(POSITIVE_CONTACTOR_PIN) == HIGH;
|
||||
precharge_low = digitalRead(precharge) == LOW;
|
||||
positive_high = digitalRead(positive_contactor) == HIGH;
|
||||
contactors_ready = precharge_low && positive_high;
|
||||
vehicle_permission = digitalRead(CHADEMO_PIN_4);
|
||||
|
||||
vehicle_permission = digitalRead(pin4);
|
||||
|
||||
/* ------------------- State override conditions checks ------------------- */
|
||||
/* ------------------------------------------------------------------------------ */
|
||||
|
@ -676,8 +674,8 @@ void ChademoBattery::handle_chademo_sequence() {
|
|||
switch (CHADEMO_Status) {
|
||||
case CHADEMO_IDLE:
|
||||
/* this is where we can unlock connector */
|
||||
digitalWrite(CHADEMO_LOCK, LOW);
|
||||
plug_inserted = digitalRead(CHADEMO_PIN_7);
|
||||
digitalWrite(pin_lock, LOW);
|
||||
plug_inserted = digitalRead(pin7);
|
||||
|
||||
if (!plug_inserted) {
|
||||
#ifdef DEBUG_LOG
|
||||
|
@ -704,7 +702,7 @@ void ChademoBattery::handle_chademo_sequence() {
|
|||
/* If connection is detectable, jumpstart handshake by
|
||||
* indicate that the EVSE is ready to begin
|
||||
*/
|
||||
digitalWrite(CHADEMO_PIN_2, HIGH);
|
||||
digitalWrite(pin2, HIGH);
|
||||
|
||||
/* State change to initializing. We will re-enter the handler upon receipt of CAN */
|
||||
CHADEMO_Status = CHADEMO_INIT;
|
||||
|
@ -715,9 +713,7 @@ void ChademoBattery::handle_chademo_sequence() {
|
|||
* with timers to have higher confidence of certain conditions hitting
|
||||
* a steady state
|
||||
*/
|
||||
#ifdef DEBUG_LOG
|
||||
logging.println("CHADEMO plug is not inserted, cannot connect d2 relay to begin initialization.");
|
||||
#endif
|
||||
DEBUG_PRINTLN("CHADEMO plug is not inserted, cannot connect d2 relay to begin initialization.");
|
||||
CHADEMO_Status = CHADEMO_IDLE;
|
||||
}
|
||||
break;
|
||||
|
@ -726,9 +722,7 @@ void ChademoBattery::handle_chademo_sequence() {
|
|||
* Used for triggers/error handling elsewhere;
|
||||
* State change to CHADEMO_NEGOTIATE occurs in handle_incoming_can_frame_battery(..)
|
||||
*/
|
||||
#ifdef DEBUG_LOG
|
||||
// logging.println("Awaiting initial vehicle CAN to trigger negotiation");
|
||||
#endif
|
||||
DEBUG_PRINTLN("Awaiting initial vehicle CAN to trigger negotiation");
|
||||
evse_init();
|
||||
break;
|
||||
case CHADEMO_NEGOTIATE:
|
||||
|
@ -750,7 +744,7 @@ void ChademoBattery::handle_chademo_sequence() {
|
|||
// that pin 4 (j) reads high
|
||||
if (vehicle_permission) {
|
||||
//lock connector here
|
||||
digitalWrite(CHADEMO_LOCK, HIGH);
|
||||
digitalWrite(pin_lock, HIGH);
|
||||
|
||||
//TODO spec requires test to validate solenoid has indeed engaged.
|
||||
// example uses a comparator/current consumption check around solenoid
|
||||
|
@ -780,7 +774,7 @@ void ChademoBattery::handle_chademo_sequence() {
|
|||
if (x102_chg_session.s.status.StatusVehicleChargingEnabled) {
|
||||
if (get_measured_voltage() < 20) {
|
||||
|
||||
digitalWrite(CHADEMO_PIN_10, HIGH);
|
||||
digitalWrite(pin10, HIGH);
|
||||
evse_permission = true;
|
||||
} else {
|
||||
logging.println("Insulation check measures > 20v ");
|
||||
|
@ -898,8 +892,8 @@ void ChademoBattery::handle_chademo_sequence() {
|
|||
*/
|
||||
if (get_measured_current() <= 5 && get_measured_voltage() <= 10) {
|
||||
/* welding detection ideally here */
|
||||
digitalWrite(CHADEMO_PIN_10, LOW);
|
||||
digitalWrite(CHADEMO_PIN_2, LOW);
|
||||
digitalWrite(pin10, LOW);
|
||||
digitalWrite(pin2, LOW);
|
||||
CHADEMO_Status = CHADEMO_IDLE;
|
||||
}
|
||||
|
||||
|
@ -916,8 +910,8 @@ void ChademoBattery::handle_chademo_sequence() {
|
|||
#ifdef DEBUG_LOG
|
||||
logging.println("CHADEMO fault encountered, tearing down to make safe");
|
||||
#endif
|
||||
digitalWrite(CHADEMO_PIN_10, LOW);
|
||||
digitalWrite(CHADEMO_PIN_2, LOW);
|
||||
digitalWrite(pin10, LOW);
|
||||
digitalWrite(pin2, LOW);
|
||||
evse_permission = false;
|
||||
vehicle_permission = false;
|
||||
x209_sent = false;
|
||||
|
@ -937,14 +931,18 @@ void ChademoBattery::handle_chademo_sequence() {
|
|||
|
||||
void ChademoBattery::setup(void) { // Performs one time setup at startup
|
||||
|
||||
pinMode(CHADEMO_PIN_2, OUTPUT);
|
||||
digitalWrite(CHADEMO_PIN_2, LOW);
|
||||
pinMode(CHADEMO_PIN_10, OUTPUT);
|
||||
digitalWrite(CHADEMO_PIN_10, LOW);
|
||||
pinMode(CHADEMO_LOCK, OUTPUT);
|
||||
digitalWrite(CHADEMO_LOCK, LOW);
|
||||
pinMode(CHADEMO_PIN_4, INPUT);
|
||||
pinMode(CHADEMO_PIN_7, INPUT);
|
||||
if (!esp32hal->alloc_pins(Name, pin2, pin10, pin4, pin7, pin_lock)) {
|
||||
return;
|
||||
}
|
||||
|
||||
pinMode(pin2, OUTPUT);
|
||||
digitalWrite(pin2, LOW);
|
||||
pinMode(pin10, OUTPUT);
|
||||
digitalWrite(pin10, LOW);
|
||||
pinMode(pin_lock, OUTPUT);
|
||||
digitalWrite(pin_lock, LOW);
|
||||
pinMode(pin4, INPUT);
|
||||
pinMode(pin7, INPUT);
|
||||
|
||||
strncpy(datalayer.system.info.battery_protocol, Name, 63);
|
||||
datalayer.system.info.battery_protocol[63] = '\0';
|
||||
|
@ -995,5 +993,3 @@ void ChademoBattery::setup(void) { // Performs one time setup at startup
|
|||
|
||||
setupMillis = millis();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
#include <Arduino.h>
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../datalayer/datalayer_extended.h"
|
||||
#include "../include.h"
|
||||
#include "CHADEMO-BATTERY-HTML.h"
|
||||
#include "CanBattery.h"
|
||||
#include "src/devboard/hal/hal.h"
|
||||
|
||||
#ifdef CHADEMO_BATTERY
|
||||
#define SELECTED_BATTERY_CLASS ChademoBattery
|
||||
|
@ -16,6 +16,18 @@
|
|||
|
||||
class ChademoBattery : public CanBattery {
|
||||
public:
|
||||
ChademoBattery() {
|
||||
pin2 = esp32hal->CHADEMO_PIN_2();
|
||||
pin10 = esp32hal->CHADEMO_PIN_10();
|
||||
pin4 = esp32hal->CHADEMO_PIN_4();
|
||||
pin7 = esp32hal->CHADEMO_PIN_7();
|
||||
pin_lock = esp32hal->CHADEMO_LOCK();
|
||||
|
||||
// Assuming these are initialized by contactor control module.
|
||||
precharge = esp32hal->PRECHARGE_PIN();
|
||||
positive_contactor = esp32hal->POSITIVE_CONTACTOR_PIN();
|
||||
}
|
||||
|
||||
virtual void setup(void);
|
||||
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
||||
virtual void update_values();
|
||||
|
@ -31,6 +43,7 @@ class ChademoBattery : public CanBattery {
|
|||
static constexpr const char* Name = "Chademo V2X mode";
|
||||
|
||||
private:
|
||||
gpio_num_t pin2, pin10, pin4, pin7, pin_lock, precharge, positive_contactor;
|
||||
ChademoBatteryHtmlRenderer renderer;
|
||||
|
||||
void process_vehicle_charging_minimums(CAN_frame rx_frame);
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
#include "CHADEMO-SHUNTS.h"
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../include.h"
|
||||
#include "CHADEMO-BATTERY.h"
|
||||
#include "src/devboard/utils/logging.h"
|
||||
|
||||
/* Initial frames received from ISA shunts provide invalid during initialization */
|
||||
static int framecount = 0;
|
||||
|
@ -236,6 +236,10 @@ inline void ISA_handle528(CAN_frame* frame) {
|
|||
lastWh = wh;
|
||||
}
|
||||
|
||||
static void transmit_can_frame(CAN_frame* frame, CAN_Interface can_interface) {
|
||||
transmit_can_frame_to_interface(frame, can_interface);
|
||||
}
|
||||
|
||||
void ISA_initialize() {
|
||||
firstframe = false;
|
||||
ISA_STOP();
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#include "../datalayer/datalayer.h"
|
||||
#include "../datalayer/datalayer_extended.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../include.h"
|
||||
|
||||
/* The raw SOC value sits at 90% when the battery is full, so we should report back 100% once this value is reached
|
||||
Same goes for low point, when 10% is reached we report 0% */
|
||||
|
@ -128,7 +127,7 @@ void CmfaEvBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
|||
break;
|
||||
case 0x7BB: // Reply from battery
|
||||
if (rx_frame.data.u8[0] == 0x10) { //PID header
|
||||
transmit_can_frame(&CMFA_ACK, can_config.battery);
|
||||
transmit_can_frame(&CMFA_ACK);
|
||||
}
|
||||
|
||||
pid_reply = (rx_frame.data.u8[2] << 8) + rx_frame.data.u8[3];
|
||||
|
@ -440,10 +439,10 @@ void CmfaEvBattery::transmit_can(unsigned long currentMillis) {
|
|||
// Send 10ms CAN Message
|
||||
if (currentMillis - previousMillis10ms >= INTERVAL_10_MS) {
|
||||
previousMillis10ms = currentMillis;
|
||||
transmit_can_frame(&CMFA_1EA, can_config.battery);
|
||||
transmit_can_frame(&CMFA_135, can_config.battery);
|
||||
transmit_can_frame(&CMFA_134, can_config.battery);
|
||||
transmit_can_frame(&CMFA_125, can_config.battery);
|
||||
transmit_can_frame(&CMFA_1EA);
|
||||
transmit_can_frame(&CMFA_135);
|
||||
transmit_can_frame(&CMFA_134);
|
||||
transmit_can_frame(&CMFA_125);
|
||||
|
||||
CMFA_135.data.u8[1] = content_135[counter_10ms];
|
||||
CMFA_125.data.u8[3] = content_125[counter_10ms];
|
||||
|
@ -453,8 +452,8 @@ void CmfaEvBattery::transmit_can(unsigned long currentMillis) {
|
|||
if (currentMillis - previousMillis100ms >= INTERVAL_100_MS) {
|
||||
previousMillis100ms = currentMillis;
|
||||
|
||||
transmit_can_frame(&CMFA_59B, can_config.battery);
|
||||
transmit_can_frame(&CMFA_3D3, can_config.battery);
|
||||
transmit_can_frame(&CMFA_59B);
|
||||
transmit_can_frame(&CMFA_3D3);
|
||||
}
|
||||
//Send 200ms message
|
||||
if (currentMillis - previousMillis200ms >= INTERVAL_200_MS) {
|
||||
|
@ -935,7 +934,7 @@ void CmfaEvBattery::transmit_can(unsigned long currentMillis) {
|
|||
break;
|
||||
}
|
||||
|
||||
transmit_can_frame(&CMFA_POLLING_FRAME, can_config.battery);
|
||||
transmit_can_frame(&CMFA_POLLING_FRAME);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#ifndef CMFA_EV_BATTERY_H
|
||||
#define CMFA_EV_BATTERY_H
|
||||
#include "../include.h"
|
||||
|
||||
#include "CMFA-EV-HTML.h"
|
||||
#include "CanBattery.h"
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
#include "CanBattery.h"
|
||||
#include "../../src/include.h"
|
||||
|
||||
CanBattery::CanBattery(bool halfSpeed) {
|
||||
CanBattery::CanBattery(CAN_Speed speed) {
|
||||
can_interface = can_config.battery;
|
||||
register_transmitter(this);
|
||||
register_can_receiver(this, can_interface, halfSpeed);
|
||||
register_can_receiver(this, can_interface, speed);
|
||||
}
|
||||
|
||||
CAN_Speed CanBattery::change_can_speed(CAN_Speed speed) {
|
||||
return ::change_can_speed(can_interface, speed);
|
||||
}
|
||||
|
|
|
@ -3,8 +3,10 @@
|
|||
|
||||
#include "Battery.h"
|
||||
|
||||
#include "USER_SETTINGS.h"
|
||||
#include "src/communication/Transmitter.h"
|
||||
#include "src/communication/can/CanReceiver.h"
|
||||
#include "src/communication/can/comm_can.h"
|
||||
#include "src/devboard/utils/types.h"
|
||||
|
||||
// Abstract base class for batteries using the CAN bus
|
||||
|
@ -13,7 +15,7 @@ class CanBattery : public Battery, Transmitter, CanReceiver {
|
|||
virtual void handle_incoming_can_frame(CAN_frame rx_frame) = 0;
|
||||
virtual void transmit_can(unsigned long currentMillis) = 0;
|
||||
|
||||
String interface_name() { return getCANInterfaceName(can_interface); }
|
||||
const char* interface_name() { return getCANInterfaceName(can_interface); }
|
||||
|
||||
void transmit(unsigned long currentMillis) { transmit_can(currentMillis); }
|
||||
|
||||
|
@ -22,13 +24,17 @@ class CanBattery : public Battery, Transmitter, CanReceiver {
|
|||
protected:
|
||||
CAN_Interface can_interface;
|
||||
|
||||
CanBattery(bool halfSpeed = false);
|
||||
CanBattery(CAN_Speed speed = CAN_Speed::CAN_SPEED_500KBPS);
|
||||
|
||||
CanBattery(CAN_Interface interface, bool halfSpeed = false) {
|
||||
CanBattery(CAN_Interface interface, CAN_Speed speed = CAN_Speed::CAN_SPEED_500KBPS) {
|
||||
can_interface = interface;
|
||||
register_transmitter(this);
|
||||
register_can_receiver(this, can_interface, halfSpeed);
|
||||
register_can_receiver(this, can_interface, speed);
|
||||
}
|
||||
|
||||
CAN_Speed change_can_speed(CAN_Speed speed);
|
||||
|
||||
void transmit_can_frame(CAN_frame* frame) { transmit_can_frame_to_interface(frame, can_interface); }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#include "DALY-BMS.h"
|
||||
#include <cstdint>
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../devboard/hal/hal.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../include.h"
|
||||
|
||||
/* Do not change code below unless you are sure what you are doing */
|
||||
|
||||
|
@ -70,7 +70,14 @@ void DalyBms::setup(void) { // Performs one time setup at startup
|
|||
datalayer.battery.info.total_capacity_Wh = BATTERY_WH_MAX;
|
||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
||||
|
||||
Serial2.begin(baud_rate(), SERIAL_8N1, RS485_RX_PIN, RS485_TX_PIN);
|
||||
auto rx_pin = esp32hal->RS485_RX_PIN();
|
||||
auto tx_pin = esp32hal->RS485_TX_PIN();
|
||||
|
||||
if (!esp32hal->alloc_pins(Name, rx_pin, tx_pin)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Serial2.begin(baud_rate(), SERIAL_8N1, rx_pin, tx_pin);
|
||||
}
|
||||
|
||||
uint8_t calculate_checksum(uint8_t buff[12]) {
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#include "../datalayer/datalayer.h"
|
||||
#include "../datalayer/datalayer_extended.h" //For More Battery Info page
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../include.h"
|
||||
|
||||
/* TODO:
|
||||
This integration is still ongoing. Here is what still needs to be done in order to use this battery type
|
||||
|
@ -466,7 +465,7 @@ void EcmpBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
|||
} else { //Normal PID polling ongoing
|
||||
|
||||
if (rx_frame.data.u8[0] == 0x10) { //Multiframe response, send ACK
|
||||
transmit_can_frame(&ECMP_ACK, can_config.battery);
|
||||
transmit_can_frame(&ECMP_ACK);
|
||||
//Multiframe has the poll reply slightly different location
|
||||
incoming_poll = (rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4];
|
||||
}
|
||||
|
@ -852,19 +851,19 @@ void EcmpBattery::transmit_can(unsigned long currentMillis) {
|
|||
//Failure to do this results in the contactors opening after 30 seconds with load
|
||||
if (datalayer_extended.stellantisECMP.UserRequestDisableIsoMonitoring) {
|
||||
if (DisableIsoMonitoringStatemachine == 0) {
|
||||
transmit_can_frame(&ECMP_DIAG_START, can_config.battery);
|
||||
transmit_can_frame(&ECMP_DIAG_START);
|
||||
DisableIsoMonitoringStatemachine = 1;
|
||||
}
|
||||
if (DisableIsoMonitoringStatemachine == 2) {
|
||||
transmit_can_frame(&ECMP_ACK_MESSAGE, can_config.battery);
|
||||
transmit_can_frame(&ECMP_ACK_MESSAGE);
|
||||
DisableIsoMonitoringStatemachine = 3;
|
||||
}
|
||||
if (DisableIsoMonitoringStatemachine == 4) {
|
||||
transmit_can_frame(&ECMP_FACTORY_MODE_ACTIVATION, can_config.battery);
|
||||
transmit_can_frame(&ECMP_FACTORY_MODE_ACTIVATION);
|
||||
DisableIsoMonitoringStatemachine = 5;
|
||||
}
|
||||
if (DisableIsoMonitoringStatemachine == 6) {
|
||||
transmit_can_frame(&ECMP_DISABLE_ISOLATION_REQ, can_config.battery);
|
||||
transmit_can_frame(&ECMP_DISABLE_ISOLATION_REQ);
|
||||
DisableIsoMonitoringStatemachine = 7;
|
||||
}
|
||||
timeSpentDisableIsoMonitoring++;
|
||||
|
@ -875,15 +874,15 @@ void EcmpBattery::transmit_can(unsigned long currentMillis) {
|
|||
}
|
||||
} else if (datalayer_extended.stellantisECMP.UserRequestContactorReset) {
|
||||
if (ContactorResetStatemachine == 0) {
|
||||
transmit_can_frame(&ECMP_DIAG_START, can_config.battery);
|
||||
transmit_can_frame(&ECMP_DIAG_START);
|
||||
ContactorResetStatemachine = 1;
|
||||
}
|
||||
if (ContactorResetStatemachine == 2) {
|
||||
transmit_can_frame(&ECMP_CONTACTOR_RESET_START, can_config.battery);
|
||||
transmit_can_frame(&ECMP_CONTACTOR_RESET_START);
|
||||
ContactorResetStatemachine = 3;
|
||||
}
|
||||
if (ContactorResetStatemachine == 4) {
|
||||
transmit_can_frame(&ECMP_CONTACTOR_RESET_PROGRESS, can_config.battery);
|
||||
transmit_can_frame(&ECMP_CONTACTOR_RESET_PROGRESS);
|
||||
ContactorResetStatemachine = 5;
|
||||
}
|
||||
|
||||
|
@ -897,15 +896,15 @@ void EcmpBattery::transmit_can(unsigned long currentMillis) {
|
|||
} else if (datalayer_extended.stellantisECMP.UserRequestCollisionReset) {
|
||||
|
||||
if (CollisionResetStatemachine == 0) {
|
||||
transmit_can_frame(&ECMP_DIAG_START, can_config.battery);
|
||||
transmit_can_frame(&ECMP_DIAG_START);
|
||||
CollisionResetStatemachine = 1;
|
||||
}
|
||||
if (CollisionResetStatemachine == 2) {
|
||||
transmit_can_frame(&ECMP_COLLISION_RESET_START, can_config.battery);
|
||||
transmit_can_frame(&ECMP_COLLISION_RESET_START);
|
||||
CollisionResetStatemachine = 3;
|
||||
}
|
||||
if (CollisionResetStatemachine == 4) {
|
||||
transmit_can_frame(&ECMP_COLLISION_RESET_PROGRESS, can_config.battery);
|
||||
transmit_can_frame(&ECMP_COLLISION_RESET_PROGRESS);
|
||||
CollisionResetStatemachine = 5;
|
||||
}
|
||||
|
||||
|
@ -919,15 +918,15 @@ void EcmpBattery::transmit_can(unsigned long currentMillis) {
|
|||
} else if (datalayer_extended.stellantisECMP.UserRequestIsolationReset) {
|
||||
|
||||
if (IsolationResetStatemachine == 0) {
|
||||
transmit_can_frame(&ECMP_DIAG_START, can_config.battery);
|
||||
transmit_can_frame(&ECMP_DIAG_START);
|
||||
IsolationResetStatemachine = 1;
|
||||
}
|
||||
if (IsolationResetStatemachine == 2) {
|
||||
transmit_can_frame(&ECMP_ISOLATION_RESET_START, can_config.battery);
|
||||
transmit_can_frame(&ECMP_ISOLATION_RESET_START);
|
||||
IsolationResetStatemachine = 3;
|
||||
}
|
||||
if (IsolationResetStatemachine == 4) {
|
||||
transmit_can_frame(&ECMP_ISOLATION_RESET_PROGRESS, can_config.battery);
|
||||
transmit_can_frame(&ECMP_ISOLATION_RESET_PROGRESS);
|
||||
IsolationResetStatemachine = 5;
|
||||
}
|
||||
|
||||
|
@ -1299,7 +1298,7 @@ void EcmpBattery::transmit_can(unsigned long currentMillis) {
|
|||
poll_state = PID_WELD_CHECK;
|
||||
break;
|
||||
}
|
||||
transmit_can_frame(&ECMP_POLL, can_config.battery);
|
||||
transmit_can_frame(&ECMP_POLL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1328,14 +1327,14 @@ void EcmpBattery::transmit_can(unsigned long currentMillis) {
|
|||
ECMP_17B.data.u8[7] = counter_10ms << 4 | checksum_calc(counter_10ms, ECMP_17B);
|
||||
ECMP_112.data.u8[7] = counter_10ms << 4 | checksum_calc(counter_10ms, ECMP_112);
|
||||
|
||||
transmit_can_frame(&ECMP_112, can_config.battery); //MCU1_112
|
||||
transmit_can_frame(&ECMP_0C5, can_config.battery); //DC2_0C5
|
||||
transmit_can_frame(&ECMP_17B, can_config.battery); //VCU_PCANInfo_17B
|
||||
transmit_can_frame(&ECMP_0F2, can_config.battery); //CtrlMCU1_0F2
|
||||
transmit_can_frame(&ECMP_112); //MCU1_112
|
||||
transmit_can_frame(&ECMP_0C5); //DC2_0C5
|
||||
transmit_can_frame(&ECMP_17B); //VCU_PCANInfo_17B
|
||||
transmit_can_frame(&ECMP_0F2); //CtrlMCU1_0F2
|
||||
if (simulateEntireCar) {
|
||||
transmit_can_frame(&ECMP_111, can_config.battery);
|
||||
transmit_can_frame(&ECMP_110, can_config.battery);
|
||||
transmit_can_frame(&ECMP_114, can_config.battery);
|
||||
transmit_can_frame(&ECMP_111);
|
||||
transmit_can_frame(&ECMP_110);
|
||||
transmit_can_frame(&ECMP_114);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1354,7 +1353,7 @@ void EcmpBattery::transmit_can(unsigned long currentMillis) {
|
|||
|
||||
ECMP_0F0.data.u8[7] = counter_20ms << 4 | checksum_calc(counter_20ms, ECMP_0F0);
|
||||
|
||||
transmit_can_frame(&ECMP_0F0, can_config.battery); //VCU2_0F0
|
||||
transmit_can_frame(&ECMP_0F0); //VCU2_0F0
|
||||
}
|
||||
// Send 50ms periodic CAN Message simulating the car still being attached
|
||||
if (currentMillis - previousMillis50 >= INTERVAL_50_MS) {
|
||||
|
@ -1367,8 +1366,8 @@ void EcmpBattery::transmit_can(unsigned long currentMillis) {
|
|||
//Normal operation for contactor closing
|
||||
ECMP_27A.data = {0x4F, 0x58, 0x00, 0x02, 0x24, 0x00, 0x00, 0x00};
|
||||
}
|
||||
transmit_can_frame(&ECMP_230, can_config.battery); //OBC3_230
|
||||
transmit_can_frame(&ECMP_27A, can_config.battery); //VCU_BSI_Wakeup_27A
|
||||
transmit_can_frame(&ECMP_230); //OBC3_230
|
||||
transmit_can_frame(&ECMP_27A); //VCU_BSI_Wakeup_27A
|
||||
}
|
||||
// Send 100ms periodic CAN Message simulating the car still being attached
|
||||
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
|
||||
|
@ -1418,7 +1417,7 @@ void EcmpBattery::transmit_can(unsigned long currentMillis) {
|
|||
data_3A2_CRC[13] = 0xDF;
|
||||
data_3A2_CRC[14] = 0xEE;
|
||||
data_3A2_CRC[15] = 0xFD;
|
||||
transmit_can_frame(&ECMP_3D0, can_config.battery); //Not in logs, but makes speed go to 0km/h
|
||||
transmit_can_frame(&ECMP_3D0); //Not in logs, but makes speed go to 0km/h
|
||||
} else {
|
||||
//Normal operation for contactor closing
|
||||
ECMP_31E.data.u8[0] = 0x50;
|
||||
|
@ -1472,26 +1471,26 @@ void EcmpBattery::transmit_can(unsigned long currentMillis) {
|
|||
ECMP_31D.data.u8[7] = counter_100ms << 4 | checksum_calc(counter_100ms, ECMP_31D);
|
||||
ECMP_3D0.data.u8[7] = counter_100ms << 4 | checksum_calc(counter_100ms, ECMP_3D0);
|
||||
|
||||
transmit_can_frame(&ECMP_382, can_config.battery); //PSA Specific VCU (BSIInfo_382)
|
||||
transmit_can_frame(&ECMP_345, can_config.battery); //DC1_345
|
||||
transmit_can_frame(&ECMP_3A2, can_config.battery); //OBC2_3A2
|
||||
transmit_can_frame(&ECMP_3A3, can_config.battery); //OBC1_3A3
|
||||
transmit_can_frame(&ECMP_010, can_config.battery); //VCU_BCM_Crash
|
||||
transmit_can_frame(&ECMP_382); //PSA Specific VCU (BSIInfo_382)
|
||||
transmit_can_frame(&ECMP_345); //DC1_345
|
||||
transmit_can_frame(&ECMP_3A2); //OBC2_3A2
|
||||
transmit_can_frame(&ECMP_3A3); //OBC1_3A3
|
||||
transmit_can_frame(&ECMP_010); //VCU_BCM_Crash
|
||||
if (simulateEntireCar) {
|
||||
transmit_can_frame(&ECMP_31E, can_config.battery);
|
||||
transmit_can_frame(&ECMP_383, can_config.battery);
|
||||
transmit_can_frame(&ECMP_0A6, can_config.battery); //Not in all logs
|
||||
transmit_can_frame(&ECMP_37F, can_config.battery); //Seems to be temperatures of some sort
|
||||
transmit_can_frame(&ECMP_372, can_config.battery);
|
||||
transmit_can_frame(&ECMP_351, can_config.battery);
|
||||
transmit_can_frame(&ECMP_31D, can_config.battery);
|
||||
transmit_can_frame(&ECMP_31E);
|
||||
transmit_can_frame(&ECMP_383);
|
||||
transmit_can_frame(&ECMP_0A6); //Not in all logs
|
||||
transmit_can_frame(&ECMP_37F); //Seems to be temperatures of some sort
|
||||
transmit_can_frame(&ECMP_372);
|
||||
transmit_can_frame(&ECMP_351);
|
||||
transmit_can_frame(&ECMP_31D);
|
||||
}
|
||||
}
|
||||
// Send 500ms periodic CAN Message simulating the car still being attached
|
||||
if (currentMillis - previousMillis500 >= INTERVAL_500_MS) {
|
||||
previousMillis500 = currentMillis;
|
||||
if (simulateEntireCar) {
|
||||
transmit_can_frame(&ECMP_0AE, can_config.battery);
|
||||
transmit_can_frame(&ECMP_0AE);
|
||||
}
|
||||
}
|
||||
// Send 1s CAN Message
|
||||
|
@ -1515,21 +1514,21 @@ void EcmpBattery::transmit_can(unsigned long currentMillis) {
|
|||
ECMP_552.data.u8[2] = ((ticks_552 & 0x0000FF00) >> 8);
|
||||
ECMP_552.data.u8[3] = (ticks_552 & 0x000000FF);
|
||||
|
||||
transmit_can_frame(&ECMP_439, can_config.battery); //OBC4
|
||||
transmit_can_frame(&ECMP_552, can_config.battery); //VCU_552 timetracking
|
||||
transmit_can_frame(&ECMP_439); //OBC4
|
||||
transmit_can_frame(&ECMP_552); //VCU_552 timetracking
|
||||
if (simulateEntireCar) {
|
||||
transmit_can_frame(&ECMP_486, can_config.battery); //Not in all logs
|
||||
transmit_can_frame(&ECMP_041, can_config.battery); //Not in all logs
|
||||
transmit_can_frame(&ECMP_786, can_config.battery); //Not in all logs
|
||||
transmit_can_frame(&ECMP_591, can_config.battery); //Not in all logs
|
||||
transmit_can_frame(&ECMP_794, can_config.battery); //Not in all logs
|
||||
transmit_can_frame(&ECMP_486); //Not in all logs
|
||||
transmit_can_frame(&ECMP_041); //Not in all logs
|
||||
transmit_can_frame(&ECMP_786); //Not in all logs
|
||||
transmit_can_frame(&ECMP_591); //Not in all logs
|
||||
transmit_can_frame(&ECMP_794); //Not in all logs
|
||||
}
|
||||
}
|
||||
// Send 5s periodic CAN Message simulating the car still being attached
|
||||
if (currentMillis - previousMillis5000 >= INTERVAL_5_S) {
|
||||
previousMillis5000 = currentMillis;
|
||||
if (simulateEntireCar) {
|
||||
transmit_can_frame(&ECMP_55F, can_config.battery);
|
||||
transmit_can_frame(&ECMP_55F);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#ifndef STELLANTIS_ECMP_BATTERY_H
|
||||
#define STELLANTIS_ECMP_BATTERY_H
|
||||
#include <Arduino.h>
|
||||
#include "../include.h"
|
||||
|
||||
#include "CanBattery.h"
|
||||
#include "ECMP-HTML.h"
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#include "../communication/can/comm_can.h"
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../include.h"
|
||||
|
||||
/*
|
||||
Can bus @ 500k - all Extended ID, little endian
|
||||
|
@ -417,7 +416,7 @@ void FoxessBattery::transmit_can(unsigned long currentMillis) {
|
|||
FOX_1871.data.u8[5] = 0x00;
|
||||
FOX_1871.data.u8[6] = 0x00;
|
||||
FOX_1871.data.u8[7] = 0x00;
|
||||
transmit_can_frame(&FOX_1871, can_config.battery); //bms_send_pack_statistics
|
||||
transmit_can_frame(&FOX_1871); //bms_send_pack_statistics
|
||||
break;
|
||||
case 1: //1s
|
||||
FOX_1871.data.u8[0] = 0x02;
|
||||
|
@ -428,7 +427,7 @@ void FoxessBattery::transmit_can(unsigned long currentMillis) {
|
|||
FOX_1871.data.u8[5] = 0x00;
|
||||
FOX_1871.data.u8[6] = 0x00;
|
||||
FOX_1871.data.u8[7] = 0x00;
|
||||
transmit_can_frame(&FOX_1871, can_config.battery); //bms_stop_sending
|
||||
transmit_can_frame(&FOX_1871); //bms_stop_sending
|
||||
break;
|
||||
case 2: //1.5s
|
||||
FOX_1871.data.u8[0] = 0x05;
|
||||
|
@ -439,7 +438,7 @@ void FoxessBattery::transmit_can(unsigned long currentMillis) {
|
|||
FOX_1871.data.u8[5] = 0x00;
|
||||
FOX_1871.data.u8[6] = 0x00;
|
||||
FOX_1871.data.u8[7] = 0x00;
|
||||
transmit_can_frame(&FOX_1871, can_config.battery); //bms_serial_request
|
||||
transmit_can_frame(&FOX_1871); //bms_serial_request
|
||||
break;
|
||||
case 3: //2.0s
|
||||
FOX_1871.data.u8[0] = 0x01;
|
||||
|
@ -450,7 +449,7 @@ void FoxessBattery::transmit_can(unsigned long currentMillis) {
|
|||
FOX_1871.data.u8[5] = 0x00;
|
||||
FOX_1871.data.u8[6] = 0x00;
|
||||
FOX_1871.data.u8[7] = 0x00;
|
||||
transmit_can_frame(&FOX_1871, can_config.battery); //bms_send_pack_statistics
|
||||
transmit_can_frame(&FOX_1871); //bms_send_pack_statistics
|
||||
break;
|
||||
case 4: //2.5s
|
||||
FOX_1871.data.u8[0] = 0x02;
|
||||
|
@ -461,7 +460,7 @@ void FoxessBattery::transmit_can(unsigned long currentMillis) {
|
|||
FOX_1871.data.u8[5] = 0x00;
|
||||
FOX_1871.data.u8[6] = 0x00;
|
||||
FOX_1871.data.u8[7] = 0x00;
|
||||
transmit_can_frame(&FOX_1871, can_config.battery); //bms_stop_sending
|
||||
transmit_can_frame(&FOX_1871); //bms_stop_sending
|
||||
break;
|
||||
case 5: //3.0s cell temp and voltages
|
||||
//0x1871 [0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00]
|
||||
|
@ -473,7 +472,7 @@ void FoxessBattery::transmit_can(unsigned long currentMillis) {
|
|||
FOX_1871.data.u8[5] = 0x00;
|
||||
FOX_1871.data.u8[6] = 0x00;
|
||||
FOX_1871.data.u8[7] = 0x00;
|
||||
transmit_can_frame(&FOX_1871, can_config.battery); //bms_send_pack_cell_volts
|
||||
transmit_can_frame(&FOX_1871); //bms_send_pack_cell_volts
|
||||
//0x1871 [0x01, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00]
|
||||
FOX_1871.data.u8[0] = 0x01;
|
||||
FOX_1871.data.u8[1] = 0x00;
|
||||
|
@ -483,7 +482,7 @@ void FoxessBattery::transmit_can(unsigned long currentMillis) {
|
|||
FOX_1871.data.u8[5] = 0x00;
|
||||
FOX_1871.data.u8[6] = 0x00;
|
||||
FOX_1871.data.u8[7] = 0x00;
|
||||
transmit_can_frame(&FOX_1871, can_config.battery); //bms_send_pack_cell_temps
|
||||
transmit_can_frame(&FOX_1871); //bms_send_pack_cell_temps
|
||||
break;
|
||||
case 6: //3.5s
|
||||
FOX_1871.data.u8[0] = 0x01;
|
||||
|
@ -494,7 +493,7 @@ void FoxessBattery::transmit_can(unsigned long currentMillis) {
|
|||
FOX_1871.data.u8[5] = 0x00;
|
||||
FOX_1871.data.u8[6] = 0x00;
|
||||
FOX_1871.data.u8[7] = 0x00;
|
||||
transmit_can_frame(&FOX_1871, can_config.battery); //bms_send_pack_statistics
|
||||
transmit_can_frame(&FOX_1871); //bms_send_pack_statistics
|
||||
break;
|
||||
case 7: //4.0s
|
||||
FOX_1871.data.u8[0] = 0x02;
|
||||
|
@ -505,7 +504,7 @@ void FoxessBattery::transmit_can(unsigned long currentMillis) {
|
|||
FOX_1871.data.u8[5] = 0x00;
|
||||
FOX_1871.data.u8[6] = 0x00;
|
||||
FOX_1871.data.u8[7] = 0x00;
|
||||
transmit_can_frame(&FOX_1871, can_config.battery); //bms_stop_sending
|
||||
transmit_can_frame(&FOX_1871); //bms_stop_sending
|
||||
break;
|
||||
case 8: //4.5s
|
||||
FOX_1871.data.u8[0] = 0x01;
|
||||
|
@ -516,7 +515,7 @@ void FoxessBattery::transmit_can(unsigned long currentMillis) {
|
|||
FOX_1871.data.u8[5] = 0x00;
|
||||
FOX_1871.data.u8[6] = 0x00;
|
||||
FOX_1871.data.u8[7] = 0x00;
|
||||
transmit_can_frame(&FOX_1871, can_config.battery); //bms_send_pack_statistics
|
||||
transmit_can_frame(&FOX_1871); //bms_send_pack_statistics
|
||||
break;
|
||||
case 9: //5.0s
|
||||
FOX_1871.data.u8[0] = 0x02;
|
||||
|
@ -527,7 +526,7 @@ void FoxessBattery::transmit_can(unsigned long currentMillis) {
|
|||
FOX_1871.data.u8[5] = 0x00;
|
||||
FOX_1871.data.u8[6] = 0x00;
|
||||
FOX_1871.data.u8[7] = 0x00;
|
||||
transmit_can_frame(&FOX_1871, can_config.battery); //bms_stop_sending
|
||||
transmit_can_frame(&FOX_1871); //bms_stop_sending
|
||||
break;
|
||||
case 10: //5.5s
|
||||
//0x1871 [0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00]
|
||||
|
@ -539,7 +538,7 @@ void FoxessBattery::transmit_can(unsigned long currentMillis) {
|
|||
FOX_1871.data.u8[5] = 0x00;
|
||||
FOX_1871.data.u8[6] = 0x00;
|
||||
FOX_1871.data.u8[7] = 0x00;
|
||||
transmit_can_frame(&FOX_1871, can_config.battery); //bms_send_pack_cell_volts
|
||||
transmit_can_frame(&FOX_1871); //bms_send_pack_cell_volts
|
||||
//0x1871 [0x01, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00]
|
||||
FOX_1871.data.u8[0] = 0x01;
|
||||
FOX_1871.data.u8[1] = 0x00;
|
||||
|
@ -549,7 +548,7 @@ void FoxessBattery::transmit_can(unsigned long currentMillis) {
|
|||
FOX_1871.data.u8[5] = 0x00;
|
||||
FOX_1871.data.u8[6] = 0x00;
|
||||
FOX_1871.data.u8[7] = 0x00;
|
||||
transmit_can_frame(&FOX_1871, can_config.battery); //bms_send_pack_cell_temps
|
||||
transmit_can_frame(&FOX_1871); //bms_send_pack_cell_temps
|
||||
break;
|
||||
case 11: //6.0s 0x1871 [0x03, 0x06, 0x17, 0x05, 0x09, 0x09, 0x28, 0x22]
|
||||
FOX_1871.data.u8[0] = 0x03;
|
||||
|
@ -560,7 +559,7 @@ void FoxessBattery::transmit_can(unsigned long currentMillis) {
|
|||
FOX_1871.data.u8[5] = 0x09;
|
||||
FOX_1871.data.u8[6] = 0x28;
|
||||
FOX_1871.data.u8[7] = 0x22;
|
||||
transmit_can_frame(&FOX_1871, can_config.battery); //timestamp
|
||||
transmit_can_frame(&FOX_1871); //timestamp
|
||||
break;
|
||||
default:
|
||||
statemachine_polling = 0;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#ifndef FOXESS_BATTERY_H
|
||||
#define FOXESS_BATTERY_H
|
||||
#include <Arduino.h>
|
||||
#include "../include.h"
|
||||
|
||||
#include "CanBattery.h"
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#include "../datalayer/datalayer.h"
|
||||
#include "../datalayer/datalayer_extended.h" //For "More battery info" webpage
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../include.h"
|
||||
|
||||
/* TODO
|
||||
- Contactor closing: CAN log needed from complete H-CAN of Geely Geometry C vehicle. We are not sure what needs to be sent towards the battery yet to get contactor closing working. DTC readout complains that a "Power CAN BUS Data Missing" message is still missing
|
||||
|
@ -309,7 +308,7 @@ void GeelyGeometryCBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
|||
break;
|
||||
case 0x7EA:
|
||||
if (rx_frame.data.u8[0] == 0x10) { //Multiframe response, send ACK
|
||||
transmit_can_frame(&GEELY_ACK, can_config.battery);
|
||||
transmit_can_frame(&GEELY_ACK);
|
||||
//Multiframe has the poll reply slightly different location
|
||||
incoming_poll = (rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4];
|
||||
}
|
||||
|
@ -488,15 +487,15 @@ void GeelyGeometryCBattery::transmit_can(unsigned long currentMillis) {
|
|||
|
||||
counter_10ms = (counter_10ms + 1) % 17; // 0-1-...F-0-1 etc.
|
||||
|
||||
transmit_can_frame(&GEELY_191, can_config.battery);
|
||||
transmit_can_frame(&GEELY_0A6, can_config.battery);
|
||||
transmit_can_frame(&GEELY_160, can_config.battery);
|
||||
transmit_can_frame(&GEELY_165, can_config.battery);
|
||||
transmit_can_frame(&GEELY_1A4, can_config.battery);
|
||||
transmit_can_frame(&GEELY_162, can_config.battery); //CONFIRMED MANDATORY! VCU message
|
||||
transmit_can_frame(&GEELY_1A5, can_config.battery);
|
||||
transmit_can_frame(&GEELY_220, can_config.battery); //CONFIRMED MANDATORY! OBC message
|
||||
transmit_can_frame(&GEELY_0E0, can_config.battery);
|
||||
transmit_can_frame(&GEELY_191);
|
||||
transmit_can_frame(&GEELY_0A6);
|
||||
transmit_can_frame(&GEELY_160);
|
||||
transmit_can_frame(&GEELY_165);
|
||||
transmit_can_frame(&GEELY_1A4);
|
||||
transmit_can_frame(&GEELY_162); //CONFIRMED MANDATORY! VCU message
|
||||
transmit_can_frame(&GEELY_1A5);
|
||||
transmit_can_frame(&GEELY_220); //CONFIRMED MANDATORY! OBC message
|
||||
transmit_can_frame(&GEELY_0E0);
|
||||
}
|
||||
if (currentMillis - previousMillis20 >= INTERVAL_20_MS) {
|
||||
previousMillis20 = currentMillis;
|
||||
|
@ -508,11 +507,11 @@ void GeelyGeometryCBattery::transmit_can(unsigned long currentMillis) {
|
|||
|
||||
counter_20ms = (counter_20ms + 1) % 17; // 0-1-...F-0-1 etc.
|
||||
|
||||
transmit_can_frame(&GEELY_145, can_config.battery); //CONFIRMED MANDATORY! shifter
|
||||
transmit_can_frame(&GEELY_0F9, can_config.battery); //CONFIRMED MANDATORY! shifter
|
||||
transmit_can_frame(&GEELY_0FA, can_config.battery); //Might be unnecessary, not in workshop manual
|
||||
transmit_can_frame(&GEELY_197, can_config.battery); //Might be unnecessary, not in workshop manual
|
||||
transmit_can_frame(&GEELY_150, can_config.battery);
|
||||
transmit_can_frame(&GEELY_145); //CONFIRMED MANDATORY! shifter
|
||||
transmit_can_frame(&GEELY_0F9); //CONFIRMED MANDATORY! shifter
|
||||
transmit_can_frame(&GEELY_0FA); //Might be unnecessary, not in workshop manual
|
||||
transmit_can_frame(&GEELY_197); //Might be unnecessary, not in workshop manual
|
||||
transmit_can_frame(&GEELY_150);
|
||||
}
|
||||
if (currentMillis - previousMillis50 >= INTERVAL_50_MS) {
|
||||
previousMillis50 = currentMillis;
|
||||
|
@ -524,13 +523,13 @@ void GeelyGeometryCBattery::transmit_can(unsigned long currentMillis) {
|
|||
|
||||
counter_50ms = (counter_50ms + 1) % 17; // 0-1-...F-0-1 etc.
|
||||
|
||||
transmit_can_frame(&GEELY_1B2, can_config.battery);
|
||||
transmit_can_frame(&GEELY_221, can_config.battery); //CONFIRMED MANDATORY! OBC message
|
||||
//transmit_can_frame(&GEELY_1A3, can_config.battery); //Might be unnecessary, radar info
|
||||
transmit_can_frame(&GEELY_1A7, can_config.battery); //Might be unnecessary
|
||||
transmit_can_frame(&GEELY_0A8, can_config.battery); //CONFIRMED MANDATORY! IPU message
|
||||
transmit_can_frame(&GEELY_1F2, can_config.battery); //Might be unnecessary, not in manual
|
||||
transmit_can_frame(&GEELY_1A6, can_config.battery); //Might be unnecessary, not in manual
|
||||
transmit_can_frame(&GEELY_1B2);
|
||||
transmit_can_frame(&GEELY_221); //CONFIRMED MANDATORY! OBC message
|
||||
//transmit_can_frame(&GEELY_1A3); //Might be unnecessary, radar info
|
||||
transmit_can_frame(&GEELY_1A7); //Might be unnecessary
|
||||
transmit_can_frame(&GEELY_0A8); //CONFIRMED MANDATORY! IPU message
|
||||
transmit_can_frame(&GEELY_1F2); //Might be unnecessary, not in manual
|
||||
transmit_can_frame(&GEELY_1A6); //Might be unnecessary, not in manual
|
||||
}
|
||||
// Send 100ms CAN Message
|
||||
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
|
||||
|
@ -541,9 +540,9 @@ void GeelyGeometryCBattery::transmit_can(unsigned long currentMillis) {
|
|||
|
||||
counter_100ms = (counter_100ms + 1) % 17; // 0-1-...F-0-1 etc.
|
||||
|
||||
transmit_can_frame(&GEELY_222, can_config.battery); //CONFIRMED MANDATORY! OBC message
|
||||
//transmit_can_frame(&GEELY_2D2, can_config.battery); //Might be unnecessary, seat info
|
||||
transmit_can_frame(&GEELY_292, can_config.battery); //CONFIRMED MANDATORY! T-BOX
|
||||
transmit_can_frame(&GEELY_222); //CONFIRMED MANDATORY! OBC message
|
||||
//transmit_can_frame(&GEELY_2D2); //Might be unnecessary, seat info
|
||||
transmit_can_frame(&GEELY_292); //CONFIRMED MANDATORY! T-BOX
|
||||
}
|
||||
// Send 200ms CAN Message
|
||||
if (currentMillis - previousMillis200 >= INTERVAL_200_MS) {
|
||||
|
@ -655,7 +654,7 @@ void GeelyGeometryCBattery::transmit_can(unsigned long currentMillis) {
|
|||
break;
|
||||
}
|
||||
|
||||
transmit_can_frame(&GEELY_POLL, can_config.battery);
|
||||
transmit_can_frame(&GEELY_POLL);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#define GEELY_GEOMETRY_C_BATTERY_H
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../datalayer/datalayer_extended.h"
|
||||
#include "../include.h"
|
||||
#include "CanBattery.h"
|
||||
#include "GEELY-GEOMETRY-C-HTML.h"
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#include "../communication/can/comm_can.h"
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../include.h"
|
||||
#include "../devboard/utils/logging.h"
|
||||
|
||||
//Code still work in progress, TODO:
|
||||
//Figure out if CAN messages need to be sent to keep the system happy?
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#ifndef IMIEV_CZERO_ION_BATTERY_H
|
||||
#define IMIEV_CZERO_ION_BATTERY_H
|
||||
#include <Arduino.h>
|
||||
#include "../include.h"
|
||||
|
||||
#include "CanBattery.h"
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#include "../communication/can/comm_can.h"
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../include.h"
|
||||
#include "../devboard/utils/logging.h"
|
||||
|
||||
/* Do not change code below unless you are sure what you are doing */
|
||||
static unsigned long previousMillisKeepAlive = 0;
|
||||
|
@ -56,7 +56,7 @@ CAN_frame ipace_keep_alive = {.FD = false,
|
|||
.ID = 0x59e,
|
||||
.data = {0x9E, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}};*/
|
||||
|
||||
static void print_units(char* header, int value, char* units) {
|
||||
static void print_units(const char* header, int value, const char* units) {
|
||||
logging.print(header);
|
||||
logging.print(value);
|
||||
logging.print(units);
|
||||
|
@ -221,12 +221,12 @@ void JaguarIpaceBattery::transmit_can(unsigned long currentMillis) {
|
|||
/* Send keep-alive every 200ms */
|
||||
if (currentMillis - previousMillisKeepAlive >= INTERVAL_200_MS) {
|
||||
previousMillisKeepAlive = currentMillis;
|
||||
transmit_can_frame(&ipace_keep_alive, can_config.battery);
|
||||
transmit_can_frame(&ipace_keep_alive);
|
||||
}
|
||||
}
|
||||
|
||||
void JaguarIpaceBattery::setup(void) { // Performs one time setup at startup
|
||||
strncpy(datalayer.system.info.battery_protocol, "Jaguar I-PACE", 63);
|
||||
strncpy(datalayer.system.info.battery_protocol, Name, 63);
|
||||
datalayer.system.info.battery_protocol[63] = '\0';
|
||||
datalayer.battery.info.number_of_cells = 108;
|
||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
#include "../communication/can/comm_can.h"
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../include.h"
|
||||
#include "../lib/pierremolinaro-ACAN2517FD/ACAN2517FD.h"
|
||||
#include "../devboard/utils/logging.h"
|
||||
#include "../system_settings.h"
|
||||
|
||||
const unsigned char crc8_table[256] =
|
||||
{ // CRC8_SAE_J1850_ZER0 formula,0x1D Poly,initial value 0x3F,Final XOR value varies
|
||||
|
@ -811,6 +811,29 @@ void KiaEGmpBattery::
|
|||
#endif
|
||||
}
|
||||
|
||||
// Getter implementations for HTML renderer
|
||||
int KiaEGmpBattery::get_battery_12V() const {
|
||||
return leadAcidBatteryVoltage;
|
||||
}
|
||||
int KiaEGmpBattery::get_waterleakageSensor() const {
|
||||
return waterleakageSensor;
|
||||
}
|
||||
int KiaEGmpBattery::get_temperature_water_inlet() const {
|
||||
return temperature_water_inlet;
|
||||
}
|
||||
int KiaEGmpBattery::get_powerRelayTemperature() const {
|
||||
return powerRelayTemperature;
|
||||
}
|
||||
int KiaEGmpBattery::get_batteryManagementMode() const {
|
||||
return batteryManagementMode;
|
||||
}
|
||||
int KiaEGmpBattery::get_BMS_ign() const {
|
||||
return BMS_ign;
|
||||
}
|
||||
int KiaEGmpBattery::get_batRelay() const {
|
||||
return batteryRelay;
|
||||
}
|
||||
|
||||
void KiaEGmpBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
||||
startedUp = true;
|
||||
switch (rx_frame.ID) {
|
||||
|
@ -872,7 +895,7 @@ void KiaEGmpBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
|||
// logging.println ("Send ack");
|
||||
poll_data_pid = rx_frame.data.u8[4];
|
||||
// if (rx_frame.data.u8[4] == poll_data_pid) {
|
||||
transmit_can_frame(&EGMP_7E4_ack, can_config.battery); //Send ack to BMS if the same frame is sent as polled
|
||||
transmit_can_frame(&EGMP_7E4_ack); //Send ack to BMS if the same frame is sent as polled
|
||||
// }
|
||||
break;
|
||||
case 0x21: //First frame in PID group
|
||||
|
@ -1053,7 +1076,7 @@ void KiaEGmpBattery::transmit_can(unsigned long currentMillis) {
|
|||
if (currentMillis - startMillis >= messageDelays[messageIndex]) {
|
||||
|
||||
// Transmit the current message
|
||||
transmit_can_frame(messages[messageIndex], can_config.battery);
|
||||
transmit_can_frame(messages[messageIndex]);
|
||||
|
||||
// Move to the next message
|
||||
messageIndex++;
|
||||
|
@ -1072,7 +1095,7 @@ void KiaEGmpBattery::transmit_can(unsigned long currentMillis) {
|
|||
EGMP_7E4.data.u8[3] = KIA_7E4_COUNTER;
|
||||
|
||||
if (ok_start_polling_battery) {
|
||||
transmit_can_frame(&EGMP_7E4, can_config.battery);
|
||||
transmit_can_frame(&EGMP_7E4);
|
||||
}
|
||||
|
||||
KIA_7E4_COUNTER++;
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
#ifndef KIA_E_GMP_BATTERY_H
|
||||
#define KIA_E_GMP_BATTERY_H
|
||||
#include <Arduino.h>
|
||||
#include "../include.h"
|
||||
#include "../lib/pierremolinaro-ACAN2517FD/ACAN2517FD.h"
|
||||
#include "CanBattery.h"
|
||||
|
||||
extern ACAN2517FD canfd;
|
||||
#include "KIA-E-GMP-HTML.h"
|
||||
|
||||
#define ESTIMATE_SOC_FROM_CELLVOLTAGE
|
||||
|
||||
|
@ -15,13 +12,24 @@ extern ACAN2517FD canfd;
|
|||
|
||||
class KiaEGmpBattery : public CanBattery {
|
||||
public:
|
||||
KiaEGmpBattery() : renderer(*this) {}
|
||||
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 = "Kia/Hyundai EGMP platform";
|
||||
BatteryHtmlRenderer& get_status_renderer() { return renderer; }
|
||||
// Getter implementations for HTML renderer
|
||||
int get_battery_12V() const;
|
||||
int get_waterleakageSensor() const;
|
||||
int get_temperature_water_inlet() const;
|
||||
int get_powerRelayTemperature() const;
|
||||
int get_batteryManagementMode() const;
|
||||
int get_BMS_ign() const;
|
||||
int get_batRelay() const;
|
||||
|
||||
private:
|
||||
KiaEGMPHtmlRenderer renderer;
|
||||
uint16_t estimateSOC(uint16_t packVoltage, uint16_t cellCount, int16_t currentAmps);
|
||||
void set_voltage_minmax_limits();
|
||||
|
||||
|
@ -44,9 +52,9 @@ class KiaEGmpBattery : public CanBattery {
|
|||
|
||||
uint16_t inverterVoltageFrameHigh = 0;
|
||||
uint16_t inverterVoltage = 0;
|
||||
uint16_t soc_calculated = 0;
|
||||
uint16_t SOC_BMS = 0;
|
||||
uint16_t SOC_Display = 0;
|
||||
uint16_t soc_calculated = 500;
|
||||
uint16_t SOC_BMS = 500;
|
||||
uint16_t SOC_Display = 500;
|
||||
uint16_t SOC_estimated_lowest = 0;
|
||||
uint16_t SOC_estimated_highest = 0;
|
||||
uint16_t batterySOH = 1000;
|
||||
|
@ -55,24 +63,24 @@ class KiaEGmpBattery : public CanBattery {
|
|||
uint16_t batteryVoltage = 6700;
|
||||
int16_t leadAcidBatteryVoltage = 120;
|
||||
int16_t batteryAmps = 0;
|
||||
int16_t temperatureMax = 0;
|
||||
int16_t temperatureMin = 0;
|
||||
int16_t temperatureMax = 20;
|
||||
int16_t temperatureMin = 20;
|
||||
int16_t allowedDischargePower = 0;
|
||||
int16_t allowedChargePower = 0;
|
||||
int16_t poll_data_pid = 0;
|
||||
uint8_t CellVmaxNo = 0;
|
||||
uint8_t CellVminNo = 0;
|
||||
uint8_t batteryManagementMode = 0;
|
||||
uint8_t BMS_ign = 0;
|
||||
uint8_t BMS_ign = 0xff;
|
||||
uint8_t batteryRelay = 0;
|
||||
uint8_t waterleakageSensor = 164;
|
||||
bool startedUp = false;
|
||||
bool ok_start_polling_battery = false;
|
||||
uint8_t counter_200 = 0;
|
||||
uint8_t KIA_7E4_COUNTER = 0x01;
|
||||
int8_t temperature_water_inlet = 0;
|
||||
int8_t powerRelayTemperature = 0;
|
||||
int8_t heatertemp = 0;
|
||||
int8_t temperature_water_inlet = 20;
|
||||
int8_t powerRelayTemperature = 10;
|
||||
int8_t heatertemp = 20;
|
||||
bool set_voltage_limits = false;
|
||||
uint8_t ticks_200ms_counter = 0;
|
||||
uint8_t EGMP_1CF_counter = 0;
|
||||
|
|
15
Software/src/battery/KIA-E-GMP-HTML.cpp
Normal file
15
Software/src/battery/KIA-E-GMP-HTML.cpp
Normal file
|
@ -0,0 +1,15 @@
|
|||
#include "KIA-E-GMP-HTML.h"
|
||||
#include "KIA-E-GMP-BATTERY.h"
|
||||
|
||||
String KiaEGMPHtmlRenderer::get_status_html() {
|
||||
String content;
|
||||
content += "<h4>Cells: " + String(datalayer.battery.info.number_of_cells) + "S</h4>";
|
||||
content += "<h4>12V voltage: " + String(batt.get_battery_12V() / 10.0, 1) + "</h4>";
|
||||
content += "<h4>Waterleakage: " + String(batt.get_waterleakageSensor()) + "</h4>";
|
||||
content += "<h4>Temperature, water inlet: " + String(batt.get_temperature_water_inlet()) + "</h4>";
|
||||
content += "<h4>Temperature, power relay: " + String(batt.get_powerRelayTemperature() * 2) + "</h4>";
|
||||
content += "<h4>Batterymanagement mode: " + String(batt.get_batteryManagementMode()) + "</h4>";
|
||||
content += "<h4>BMS ignition: " + String(batt.get_BMS_ign()) + "</h4>";
|
||||
content += "<h4>Battery relay: " + String(batt.get_batRelay()) + "</h4>";
|
||||
return content;
|
||||
}
|
18
Software/src/battery/KIA-E-GMP-HTML.h
Normal file
18
Software/src/battery/KIA-E-GMP-HTML.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
#ifndef _KIA_E_GMP_HTML_H
|
||||
#define _KIA_E_GMP_HTML_H
|
||||
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "src/devboard/webserver/BatteryHtmlRenderer.h"
|
||||
|
||||
class KiaEGmpBattery;
|
||||
|
||||
class KiaEGMPHtmlRenderer : public BatteryHtmlRenderer {
|
||||
private:
|
||||
KiaEGmpBattery& batt;
|
||||
|
||||
public:
|
||||
KiaEGMPHtmlRenderer(KiaEGmpBattery& b) : batt(b) {}
|
||||
String get_status_html();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -3,7 +3,7 @@
|
|||
#include "../datalayer/datalayer.h"
|
||||
#include "../datalayer/datalayer_extended.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../include.h"
|
||||
#include "../devboard/utils/logging.h"
|
||||
|
||||
void KiaHyundai64Battery::
|
||||
update_values() { //This function maps all the values fetched via CAN to the correct parameters used for modbus
|
||||
|
@ -178,17 +178,17 @@ void KiaHyundai64Battery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
|||
}
|
||||
poll_data_pid++;
|
||||
if (poll_data_pid == 1) {
|
||||
transmit_can_frame(&KIA64_7E4_id1, can_interface);
|
||||
transmit_can_frame(&KIA64_7E4_id1);
|
||||
} else if (poll_data_pid == 2) {
|
||||
transmit_can_frame(&KIA64_7E4_id2, can_interface);
|
||||
transmit_can_frame(&KIA64_7E4_id2);
|
||||
} else if (poll_data_pid == 3) {
|
||||
transmit_can_frame(&KIA64_7E4_id3, can_interface);
|
||||
transmit_can_frame(&KIA64_7E4_id3);
|
||||
} else if (poll_data_pid == 4) {
|
||||
transmit_can_frame(&KIA64_7E4_id4, can_interface);
|
||||
transmit_can_frame(&KIA64_7E4_id4);
|
||||
} else if (poll_data_pid == 5) {
|
||||
transmit_can_frame(&KIA64_7E4_id5, can_interface);
|
||||
transmit_can_frame(&KIA64_7E4_id5);
|
||||
} else if (poll_data_pid == 6) {
|
||||
transmit_can_frame(&KIA64_7E4_id6, can_interface);
|
||||
transmit_can_frame(&KIA64_7E4_id6);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -196,8 +196,7 @@ void KiaHyundai64Battery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
|||
switch (rx_frame.data.u8[0]) {
|
||||
case 0x10: //"PID Header"
|
||||
if (rx_frame.data.u8[4] == poll_data_pid) {
|
||||
transmit_can_frame(&KIA64_7E4_ack,
|
||||
can_interface); //Send ack to BMS if the same frame is sent as polled
|
||||
transmit_can_frame(&KIA64_7E4_ack); //Send ack to BMS if the same frame is sent as polled
|
||||
}
|
||||
break;
|
||||
case 0x21: //First frame in PID group
|
||||
|
@ -403,9 +402,9 @@ void KiaHyundai64Battery::transmit_can(unsigned long currentMillis) {
|
|||
previousMillis100 = currentMillis;
|
||||
|
||||
if (contactor_closing_allowed == nullptr || *contactor_closing_allowed) {
|
||||
transmit_can_frame(&KIA64_553, can_interface);
|
||||
transmit_can_frame(&KIA64_57F, can_interface);
|
||||
transmit_can_frame(&KIA64_2A1, can_interface);
|
||||
transmit_can_frame(&KIA64_553);
|
||||
transmit_can_frame(&KIA64_57F);
|
||||
transmit_can_frame(&KIA64_2A1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -455,9 +454,9 @@ void KiaHyundai64Battery::transmit_can(unsigned long currentMillis) {
|
|||
break;
|
||||
}
|
||||
|
||||
transmit_can_frame(&KIA_HYUNDAI_200, can_interface);
|
||||
transmit_can_frame(&KIA_HYUNDAI_523, can_interface);
|
||||
transmit_can_frame(&KIA_HYUNDAI_524, can_interface);
|
||||
transmit_can_frame(&KIA_HYUNDAI_200);
|
||||
transmit_can_frame(&KIA_HYUNDAI_523);
|
||||
transmit_can_frame(&KIA_HYUNDAI_524);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#include <Arduino.h>
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../datalayer/datalayer_extended.h"
|
||||
#include "../include.h"
|
||||
#include "CanBattery.h"
|
||||
#include "KIA-HYUNDAI-64-HTML.h"
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#include "../communication/can/comm_can.h"
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../include.h"
|
||||
|
||||
/* TODO:
|
||||
- The HEV battery seems to turn off after 1 minute of use. When this happens SOC% stops updating.
|
||||
|
@ -65,7 +64,7 @@ void KiaHyundaiHybridBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
|||
switch (rx_frame.data.u8[0]) {
|
||||
case 0x10: //"PID Header"
|
||||
if (rx_frame.data.u8[3] == poll_data_pid) {
|
||||
transmit_can_frame(&KIA_7E4_ack, can_config.battery); //Send ack to BMS if the same frame is sent as polled
|
||||
transmit_can_frame(&KIA_7E4_ack); //Send ack to BMS if the same frame is sent as polled
|
||||
}
|
||||
break;
|
||||
case 0x21: //First frame in PID group
|
||||
|
@ -200,15 +199,15 @@ void KiaHyundaiHybridBattery::transmit_can(unsigned long currentMillis) {
|
|||
}
|
||||
poll_data_pid++;
|
||||
if (poll_data_pid == 1) {
|
||||
transmit_can_frame(&KIA_7E4_id1, can_config.battery);
|
||||
transmit_can_frame(&KIA_7E4_id1);
|
||||
} else if (poll_data_pid == 2) {
|
||||
transmit_can_frame(&KIA_7E4_id2, can_config.battery);
|
||||
transmit_can_frame(&KIA_7E4_id2);
|
||||
} else if (poll_data_pid == 3) {
|
||||
transmit_can_frame(&KIA_7E4_id3, can_config.battery);
|
||||
transmit_can_frame(&KIA_7E4_id3);
|
||||
} else if (poll_data_pid == 4) {
|
||||
|
||||
} else if (poll_data_pid == 5) {
|
||||
transmit_can_frame(&KIA_7E4_id5, can_config.battery);
|
||||
transmit_can_frame(&KIA_7E4_id5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#ifndef KIA_HYUNDAI_HYBRID_BATTERY_H
|
||||
#define KIA_HYUNDAI_HYBRID_BATTERY_H
|
||||
#include <Arduino.h>
|
||||
#include "../include.h"
|
||||
|
||||
#include "CanBattery.h"
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include "../datalayer/datalayer.h"
|
||||
#include "../datalayer/datalayer_extended.h" //For "More battery info" webpage
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../include.h"
|
||||
#include "../devboard/utils/logging.h"
|
||||
|
||||
/*
|
||||
TODO list
|
||||
|
@ -750,7 +750,7 @@ void MebBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
|||
break;
|
||||
case 0x1C42007B: // Reply from battery
|
||||
if (rx_frame.data.u8[0] == 0x10) { //PID header
|
||||
transmit_can_frame(&MEB_ACK_FRAME, can_config.battery);
|
||||
transmit_can_frame(&MEB_ACK_FRAME);
|
||||
}
|
||||
if (rx_frame.DLC == 8) {
|
||||
pid_reply = (rx_frame.data.u8[2] << 8) + rx_frame.data.u8[3];
|
||||
|
@ -1290,7 +1290,7 @@ void MebBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
|||
|
||||
void MebBattery::transmit_can(unsigned long currentMillis) {
|
||||
|
||||
if (currentMillis > last_can_msg_timestamp + 500) {
|
||||
if (currentMillis - last_can_msg_timestamp > 500) {
|
||||
#ifdef DEBUG_LOG
|
||||
if (first_can_msg)
|
||||
logging.printf("MEB: No CAN msg received for 500ms\n");
|
||||
|
@ -1311,7 +1311,7 @@ void MebBattery::transmit_can(unsigned long currentMillis) {
|
|||
|
||||
counter_10ms = (counter_10ms + 1) % 16; //Goes from 0-1-2-3...15-0-1-2-3..
|
||||
|
||||
transmit_can_frame(&MEB_0FC, can_config.battery); // Required for contactor closing
|
||||
transmit_can_frame(&MEB_0FC); // Required for contactor closing
|
||||
}
|
||||
// Send 20ms CAN Message
|
||||
if (currentMillis - previousMillis20ms >= INTERVAL_20_MS) {
|
||||
|
@ -1322,7 +1322,7 @@ void MebBattery::transmit_can(unsigned long currentMillis) {
|
|||
|
||||
counter_20ms = (counter_20ms + 1) % 16; //Goes from 0-1-2-3...15-0-1-2-3..
|
||||
|
||||
transmit_can_frame(&MEB_0FD, can_config.battery); // Required for contactor closing
|
||||
transmit_can_frame(&MEB_0FD); // Required for contactor closing
|
||||
}
|
||||
// Send 40ms CAN Message
|
||||
if (currentMillis - previousMillis40ms >= INTERVAL_40_MS) {
|
||||
|
@ -1339,7 +1339,7 @@ void MebBattery::transmit_can(unsigned long currentMillis) {
|
|||
}
|
||||
toggle = !toggle; // Flip the toggle each time the code block is executed
|
||||
|
||||
transmit_can_frame(&MEB_040, can_config.battery); // Airbag message - Needed for contactor closing
|
||||
transmit_can_frame(&MEB_040); // Airbag message - Needed for contactor closing
|
||||
}
|
||||
// Send 50ms CAN Message
|
||||
if (currentMillis - previousMillis50ms >= INTERVAL_50_MS) {
|
||||
|
@ -1355,7 +1355,7 @@ void MebBattery::transmit_can(unsigned long currentMillis) {
|
|||
MEB_0C0.data.u8[0] = vw_crc_calc(MEB_0C0.data.u8, MEB_0C0.DLC, MEB_0C0.ID);
|
||||
counter_50ms = (counter_50ms + 1) % 16; //Goes from 0-1-2-3...15-0-1-2-3..
|
||||
|
||||
transmit_can_frame(&MEB_0C0, can_config.battery); // Needed for contactor closing
|
||||
transmit_can_frame(&MEB_0C0); // Needed for contactor closing
|
||||
}
|
||||
// Send 100ms CAN Message
|
||||
if (currentMillis - previousMillis100ms >= INTERVAL_100_MS) {
|
||||
|
@ -1443,11 +1443,11 @@ void MebBattery::transmit_can(unsigned long currentMillis) {
|
|||
MEB_14C.data.u8[0] = vw_crc_calc(MEB_14C.data.u8, MEB_14C.DLC, MEB_14C.ID);
|
||||
|
||||
counter_100ms = (counter_100ms + 1) % 16; //Goes from 0-1-2-3...15-0-1-2-3..
|
||||
transmit_can_frame(&MEB_503, can_config.battery);
|
||||
transmit_can_frame(&MEB_272, can_config.battery);
|
||||
transmit_can_frame(&MEB_3C0, can_config.battery);
|
||||
transmit_can_frame(&MEB_3BE, can_config.battery);
|
||||
transmit_can_frame(&MEB_14C, can_config.battery);
|
||||
transmit_can_frame(&MEB_503);
|
||||
transmit_can_frame(&MEB_272);
|
||||
transmit_can_frame(&MEB_3C0);
|
||||
transmit_can_frame(&MEB_3BE);
|
||||
transmit_can_frame(&MEB_14C);
|
||||
}
|
||||
//Send 200ms message
|
||||
if (currentMillis - previousMillis200ms >= INTERVAL_200_MS) {
|
||||
|
@ -1457,11 +1457,11 @@ void MebBattery::transmit_can(unsigned long currentMillis) {
|
|||
|
||||
//TODO: MEB_1B0000B9 & MEB_1B000010 & MEB_1B000046 has CAN sleep commands. May be removed?
|
||||
|
||||
transmit_can_frame(&MEB_5E1, can_config.battery);
|
||||
transmit_can_frame(&MEB_153, can_config.battery);
|
||||
transmit_can_frame(&MEB_1B0000B9, can_config.battery);
|
||||
transmit_can_frame(&MEB_1B000010, can_config.battery);
|
||||
transmit_can_frame(&MEB_1B000046, can_config.battery);
|
||||
transmit_can_frame(&MEB_5E1);
|
||||
transmit_can_frame(&MEB_153);
|
||||
transmit_can_frame(&MEB_1B0000B9);
|
||||
transmit_can_frame(&MEB_1B000010);
|
||||
transmit_can_frame(&MEB_1B000046);
|
||||
|
||||
switch (poll_pid) {
|
||||
case PID_SOC:
|
||||
|
@ -1990,7 +1990,7 @@ void MebBattery::transmit_can(unsigned long currentMillis) {
|
|||
break;
|
||||
}
|
||||
if (first_can_msg > 0 && currentMillis > first_can_msg + 1000) {
|
||||
transmit_can_frame(&MEB_POLLING_FRAME, can_config.battery);
|
||||
transmit_can_frame(&MEB_POLLING_FRAME);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1998,11 +1998,11 @@ void MebBattery::transmit_can(unsigned long currentMillis) {
|
|||
if (currentMillis - previousMillis500ms >= INTERVAL_500_MS) {
|
||||
previousMillis500ms = currentMillis;
|
||||
|
||||
transmit_can_frame(&MEB_16A954B4, can_config.battery); //eTM, Cooling valves and pumps for BMS
|
||||
transmit_can_frame(&MEB_569, can_config.battery); // Battery heating requests
|
||||
transmit_can_frame(&MEB_1A55552B, can_config.battery); //Climate, heatpump and priorities
|
||||
transmit_can_frame(&MEB_1A555548, can_config.battery); //ORU, OTA update message for reserving battery
|
||||
transmit_can_frame(&MEB_16A954FB, can_config.battery); //Climate, request to BMS for starting preconditioning
|
||||
transmit_can_frame(&MEB_16A954B4); //eTM, Cooling valves and pumps for BMS
|
||||
transmit_can_frame(&MEB_569); // Battery heating requests
|
||||
transmit_can_frame(&MEB_1A55552B); //Climate, heatpump and priorities
|
||||
transmit_can_frame(&MEB_1A555548); //ORU, OTA update message for reserving battery
|
||||
transmit_can_frame(&MEB_16A954FB); //Climate, request to BMS for starting preconditioning
|
||||
}
|
||||
|
||||
//Send 1s CANFD message
|
||||
|
@ -2023,12 +2023,12 @@ void MebBattery::transmit_can(unsigned long currentMillis) {
|
|||
MEB_6B2.data.u8[7] = (uint8_t)((seconds & 0x3E) >> 1);
|
||||
seconds = (seconds + 1) % 60;
|
||||
|
||||
counter_1000ms = (counter_1000ms + 1) % 16; //Goes from 0-1-2-3...15-0-1-2-3..
|
||||
transmit_can_frame(&MEB_6B2, can_config.battery); // Diagnostics - Needed for contactor closing
|
||||
transmit_can_frame(&MEB_641, can_config.battery); // Motor - OBD
|
||||
transmit_can_frame(&MEB_5F5, can_config.battery); // Loading profile
|
||||
transmit_can_frame(&MEB_585, can_config.battery); // Systeminfo
|
||||
transmit_can_frame(&MEB_1A5555A6, can_config.battery); // Temperature QBit
|
||||
counter_1000ms = (counter_1000ms + 1) % 16; //Goes from 0-1-2-3...15-0-1-2-3..
|
||||
transmit_can_frame(&MEB_6B2); // Diagnostics - Needed for contactor closing
|
||||
transmit_can_frame(&MEB_641); // Motor - OBD
|
||||
transmit_can_frame(&MEB_5F5); // Loading profile
|
||||
transmit_can_frame(&MEB_585); // Systeminfo
|
||||
transmit_can_frame(&MEB_1A5555A6); // Temperature QBit
|
||||
|
||||
transmit_obd_can_frame(0x18DA05F1, can_config.battery, true);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#ifndef MEB_BATTERY_H
|
||||
#define MEB_BATTERY_H
|
||||
#include <Arduino.h>
|
||||
#include "../include.h"
|
||||
#include "CanBattery.h"
|
||||
#include "MEB-HTML.h"
|
||||
|
||||
|
|
|
@ -253,8 +253,15 @@ class MebHtmlRenderer : public BatteryHtmlRenderer {
|
|||
content += "<h4>Cell imbalance: " + String(rt_enum[datalayer_extended.meb.rt_cell_imbalance & 0x03]) + "</h4>";
|
||||
content +=
|
||||
"<h4>Battery unathorized: " + String(rt_enum[datalayer_extended.meb.rt_battery_unathorized & 0x03]) + "</h4>";
|
||||
content +=
|
||||
"<h4>Battery temperature: " + String(datalayer_extended.meb.battery_temperature_dC / 10.f, 1) + " °C</h4>";
|
||||
content += "<h4>Battery temperature: ";
|
||||
if (datalayer_extended.meb.battery_temperature_dC == 875) { //Raw value 255
|
||||
content += "ERROR</h4>";
|
||||
} else if (datalayer_extended.meb.battery_temperature_dC == 870) { //Raw value 254
|
||||
content += "INIT</h4>";
|
||||
} else {
|
||||
content += String(datalayer_extended.meb.battery_temperature_dC / 10.f, 1) + " °C</h4>";
|
||||
}
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
content += "<h4>Temperature points " + String(i * 6 + 1) + "-" + String(i * 6 + 6) + " :";
|
||||
for (int j = 0; j < 6; j++)
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#include "../communication/can/comm_can.h"
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../include.h"
|
||||
|
||||
/* TODO:
|
||||
- Get contactor closing working
|
||||
|
@ -102,13 +101,13 @@ void Mg5Battery::transmit_can(unsigned long currentMillis) {
|
|||
if (currentMillis - previousMillis10 >= INTERVAL_10_MS) {
|
||||
previousMillis10 = currentMillis;
|
||||
|
||||
transmit_can_frame(&MG_5_100, can_config.battery);
|
||||
transmit_can_frame(&MG_5_100);
|
||||
}
|
||||
// Send 100ms CAN Message
|
||||
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
|
||||
previousMillis100 = currentMillis;
|
||||
|
||||
//transmit_can_frame(&MG_5_100, can_config.battery);
|
||||
//transmit_can_frame(&MG_5_100);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#ifndef MG_5_BATTERY_H
|
||||
#define MG_5_BATTERY_H
|
||||
#include <Arduino.h>
|
||||
#include "../include.h"
|
||||
|
||||
#include "CanBattery.h"
|
||||
|
||||
|
|
|
@ -1,351 +1,371 @@
|
|||
#include "../include.h"
|
||||
#ifdef MG_HS_PHEV_BATTERY_H
|
||||
#include "MG-HS-PHEV-BATTERY.h"
|
||||
#include "../communication/can/comm_can.h"
|
||||
#include "../communication/contactorcontrol/comm_contactorcontrol.h"
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "MG-HS-PHEV-BATTERY.h"
|
||||
#include "../devboard/utils/logging.h"
|
||||
|
||||
/* TODO:
|
||||
- Get contactor closing working
|
||||
- Figure out which CAN messages need to be sent towards the battery to keep it alive
|
||||
- Map all values from battery CAN messages
|
||||
- Note: Charge power/discharge power is estimated for now
|
||||
/*
|
||||
MG HS PHEV 16.6kWh battery integration
|
||||
|
||||
This may work on other MG batteries, but will need some hardcoded constants
|
||||
changing.
|
||||
|
||||
|
||||
OPTIONAL SETTINGS
|
||||
|
||||
Put these in your USER_SETTINGS.h:
|
||||
|
||||
// This will scale the SoC so the batteries top out at 4.2V/cell instead of
|
||||
4.1V/cell. The car only seems to use up to 4.1V/cell in service.
|
||||
#define MG_HS_PHEV_USE_FULL_CAPACITY true
|
||||
|
||||
// If you have bypassed the contactors, you can avoid them being activated //
|
||||
(which also disables isolation resistance measuring).
|
||||
#define MG_HS_PHEV_DISABLE_CONTACTORS true
|
||||
|
||||
|
||||
CAN CONNECTIONS
|
||||
|
||||
Battery Emulator should be connected via CAN to either:
|
||||
|
||||
- CAN1 (pins 1+2 on the LV connector)
|
||||
|
||||
This provides efficient data updates including individual cell voltages, and
|
||||
allows control over the contactors.
|
||||
|
||||
- CAN1 and CAN2 (pins 3+4) in parallel
|
||||
|
||||
This adds extra information (currently just SoH), and works in practice despite
|
||||
the potential problems with connecting CAN buses in parallel.
|
||||
|
||||
NOTES
|
||||
|
||||
- Charge power/discharge power is estimated for now
|
||||
|
||||
# row3 pin2 needs strobing to 12V (via a 1k) to wake up the BMU
|
||||
# but contactor won't come on until deasserted
|
||||
# BMU goes to sleep after after ~18s of no CAN
|
||||
*/
|
||||
|
||||
void MgHsPHEVBattery::
|
||||
update_values() { //This function maps all the values fetched via CAN to the correct parameters used for modbus
|
||||
|
||||
datalayer.battery.status.real_soc;
|
||||
// Should be called every second
|
||||
if (cellVoltageValidTime > 0) {
|
||||
cellVoltageValidTime--;
|
||||
}
|
||||
}
|
||||
|
||||
datalayer.battery.status.voltage_dV;
|
||||
void MgHsPHEVBattery::update_soc(uint16_t soc_times_ten) {
|
||||
#if MG_HS_PHEV_USE_FULL_CAPACITY
|
||||
// The SoC hits 100% at 4.1V/cell. To get the full 4.2V/cell we need to use
|
||||
// voltage instead for the last bit.
|
||||
|
||||
datalayer.battery.status.current_dA;
|
||||
if (cellVoltageValidTime == 0) {
|
||||
// We don't have a recent cell max voltage reading, so can't do
|
||||
// voltage-based SoC.
|
||||
} else if (soc_times_ten > 900 && datalayer.battery.status.cell_max_voltage_mV < 4000) {
|
||||
// Something is wrong with our max cell voltage reading (it is too low), so
|
||||
// don't trust it - we'll just let the SoC hit 100%.
|
||||
} else if (soc_times_ten == 1000 && datalayer.battery.status.cell_max_voltage_mV >= 4100) {
|
||||
// We've hit 100%, so use voltage-based-SoC calculation for the last bit.
|
||||
|
||||
datalayer.battery.info.total_capacity_Wh;
|
||||
// We usually hit 92% at ~369V, and the pack max is 378V.
|
||||
|
||||
datalayer.battery.status.remaining_capacity_Wh;
|
||||
// Scale so that 100% becomes 92%
|
||||
soc_times_ten = (uint16_t)(((uint32_t)soc_times_ten * 9200) / 10000);
|
||||
|
||||
datalayer.battery.status.max_discharge_power_W;
|
||||
// Add on the last 100mV as the last 8% of SoC.
|
||||
soc_times_ten += (uint16_t)((((uint32_t)datalayer.battery.status.cell_max_voltage_mV - 4100) * 800) / 1000);
|
||||
if (soc_times_ten > 1000) {
|
||||
soc_times_ten = 1000; // Don't let it go above 100%
|
||||
}
|
||||
} else {
|
||||
// Scale so that 100% becomes 92%
|
||||
soc_times_ten = (uint16_t)(((uint32_t)soc_times_ten * 9200) / 10000);
|
||||
}
|
||||
#endif
|
||||
|
||||
datalayer.battery.status.max_charge_power_W;
|
||||
// Set the state of charge in the datalayer
|
||||
datalayer.battery.status.real_soc = soc_times_ten * 10;
|
||||
|
||||
datalayer.battery.status.temperature_min_dC;
|
||||
RealSoC = datalayer.battery.status.real_soc / 100;
|
||||
|
||||
datalayer.battery.status.temperature_max_dC;
|
||||
// Calculate the remaining capacity.
|
||||
tempfloat = datalayer.battery.info.total_capacity_Wh * (RealSoC - MinSoC) / 100;
|
||||
if (tempfloat > 0) {
|
||||
datalayer.battery.status.remaining_capacity_Wh = tempfloat;
|
||||
} else {
|
||||
datalayer.battery.status.remaining_capacity_Wh = 0;
|
||||
}
|
||||
|
||||
// Calculate the maximum charge power. Taper the charge power between 90% and 100% SoC, as 100% SoC is approached
|
||||
if (RealSoC < StartChargeTaper) {
|
||||
datalayer.battery.status.max_charge_power_W = MaxChargePower;
|
||||
} else if (RealSoC >= 100) {
|
||||
datalayer.battery.status.max_charge_power_W = TricklePower;
|
||||
} else {
|
||||
//Taper the charge to the Trickle value. The shape and start point of the taper is set by the constants
|
||||
datalayer.battery.status.max_charge_power_W =
|
||||
(MaxChargePower * pow(((100 - RealSoC) / (100 - StartChargeTaper)), ChargeTaperExponent)) + TricklePower;
|
||||
}
|
||||
|
||||
// Calculate the maximum discharge power. Taper the discharge power between 35% and Min% SoC, as Min% SoC is approached
|
||||
if (RealSoC > StartDischargeTaper) {
|
||||
datalayer.battery.status.max_discharge_power_W = MaxDischargePower;
|
||||
} else if (RealSoC < MinSoC) {
|
||||
datalayer.battery.status.max_discharge_power_W = TricklePower;
|
||||
} else {
|
||||
//Taper the charge to the Trickle value. The shape and start point of the taper is set by the constants
|
||||
datalayer.battery.status.max_discharge_power_W =
|
||||
(MaxDischargePower * pow(((RealSoC - MinSoC) / (StartDischargeTaper - MinSoC)), DischargeTaperExponent)) +
|
||||
TricklePower;
|
||||
}
|
||||
}
|
||||
|
||||
void MgHsPHEVBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
||||
uint16_t soc1, soc2, cell_id, v;
|
||||
switch (rx_frame.ID) {
|
||||
case 0x171: //Following messages were detected on a MG5 battery BMS
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x172:
|
||||
break;
|
||||
case 0x173:
|
||||
break;
|
||||
case 0x293:
|
||||
break;
|
||||
case 0x295:
|
||||
// Contains cell min/max voltages
|
||||
|
||||
v = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
||||
if (v > 0 && v < 0x2000) {
|
||||
datalayer.battery.status.cell_max_voltage_mV = v;
|
||||
v = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
|
||||
if (v > 0 && v < 0x2000) {
|
||||
datalayer.battery.status.cell_min_voltage_mV = v;
|
||||
cellVoltageValidTime = CELL_VOLTAGE_TIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case 0x297:
|
||||
// Contains battery status in rx_frame.data.u8[1]
|
||||
// Presumed mapping:
|
||||
// 1 = disconnected
|
||||
// 2 = precharge
|
||||
// 3 = connected
|
||||
// 15 = isolation fault
|
||||
// 0/8 = checking
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
if (rx_frame.data.u8[1] != previousState) {
|
||||
logging.printf("MG_HS_PHEV: Battery status changed to %d (%d)\n", rx_frame.data.u8[1], rx_frame.data.u8[0]);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (rx_frame.data.u8[1] == 0xf && previousState != 0xf) {
|
||||
// Isolation fault, set event
|
||||
set_event(EVENT_BATTERY_ISOLATION, rx_frame.data.u8[0]);
|
||||
} else if (rx_frame.data.u8[1] != 0xf && previousState == 0xf) {
|
||||
// Isolation fault has cleared, clear event
|
||||
clear_event(EVENT_BATTERY_ISOLATION);
|
||||
}
|
||||
|
||||
if (datalayer.battery.status.bms_status == FAULT) {
|
||||
// If in fault state, don't try resetting things yet as it'll turn the
|
||||
// BMS off and we'll lose CAN info
|
||||
} else if ((rx_frame.data.u8[0] == 0x02 || rx_frame.data.u8[0] == 0x06) && rx_frame.data.u8[1] == 0x01) {
|
||||
// A weird 'stuck' state where the battery won't reconnect
|
||||
datalayer.system.status.battery_allows_contactor_closing = false;
|
||||
if (!datalayer.system.status.BMS_startup_in_progress) {
|
||||
#ifdef DEBUG_LOG
|
||||
logging.printf("MG_HS_PHEV: Stuck, resetting.\n");
|
||||
#endif
|
||||
start_bms_reset();
|
||||
}
|
||||
} else if (rx_frame.data.u8[1] == 0xf) {
|
||||
// A fault state (likely isolation failure)
|
||||
datalayer.system.status.battery_allows_contactor_closing = false;
|
||||
if (!datalayer.system.status.BMS_startup_in_progress) {
|
||||
#ifdef DEBUG_LOG
|
||||
logging.printf("MG_HS_PHEV: Fault, resetting.\n");
|
||||
#endif
|
||||
start_bms_reset();
|
||||
}
|
||||
} else {
|
||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
||||
}
|
||||
|
||||
previousState = rx_frame.data.u8[1];
|
||||
|
||||
break;
|
||||
case 0x29B: //This ID is on the MG HS RX WITHOUT ANY TX PRESENT
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
case 0x2A2:
|
||||
// Contains temperatures.
|
||||
|
||||
if (rx_frame.data.u8[0] < 0xfe) {
|
||||
// Max cell temp
|
||||
datalayer.battery.status.temperature_max_dC = ((rx_frame.data.u8[0] << 8) / 50) - 400;
|
||||
}
|
||||
if (rx_frame.data.u8[5] < 0xfe) {
|
||||
// Min cell temp
|
||||
datalayer.battery.status.temperature_min_dC = ((rx_frame.data.u8[5] << 8) / 50) - 400;
|
||||
}
|
||||
// Coolant temp
|
||||
// ((rx_frame.data.u8[1] << 8)/50) - 400;
|
||||
|
||||
// There is another unknown temp in [6]/[7]
|
||||
|
||||
break;
|
||||
case 0x29C:
|
||||
break;
|
||||
case 0x2A0:
|
||||
break;
|
||||
case 0x2A2: //This ID is on the MG HS RX WITHOUT ANY TX PRESENT
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x322:
|
||||
break;
|
||||
case 0x334:
|
||||
break;
|
||||
case 0x33F:
|
||||
break;
|
||||
case 0x391: //This ID is on the MG HS RX WITHOUT ANY TX PRESENT
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x393:
|
||||
break;
|
||||
case 0x3AB: //This ID is on the MG HS RX WITHOUT ANY TX PRESENT
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x3AC: //This ID is on the MG HS RX WITHOUT ANY TX PRESENT
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x3B8:
|
||||
break;
|
||||
case 0x3BA:
|
||||
break;
|
||||
case 0x3BC:
|
||||
case 0x3AC:
|
||||
// Contains SoCs, voltage, current. Is emitted by both CAN1 and CAN2, but
|
||||
// the CAN2 version only has one SoC (soc2), the CAN1 version has all four
|
||||
// values.
|
||||
|
||||
// Both SoCs top out at about ~4.1V/cell, the first SoC at 92%, and the
|
||||
// second at 100%.
|
||||
|
||||
// They are scaled differently, the relationship seems to be:
|
||||
// soc2 = (1.392*soc1) - 28.064
|
||||
|
||||
soc1 = (rx_frame.data.u8[0] << 8 | rx_frame.data.u8[1]);
|
||||
soc2 = (rx_frame.data.u8[2] << 8 | rx_frame.data.u8[3]);
|
||||
|
||||
// soc2 is present in both CAN1 and CAN2 messages
|
||||
if (soc2 < 1022) {
|
||||
update_soc(soc2);
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
}
|
||||
|
||||
if (((rx_frame.data.u8[4] << 8) & 0xf00 | rx_frame.data.u8[5]) != 0) {
|
||||
// 3AC message contains a nonzero voltage (so must have come from CAN1)
|
||||
v = (rx_frame.data.u8[4] << 8) & 0xf00 | rx_frame.data.u8[5];
|
||||
if (v > 0 && v < 4000) {
|
||||
datalayer.battery.status.voltage_dV = v * 2.5;
|
||||
}
|
||||
// Current
|
||||
v = (rx_frame.data.u8[6] << 8 | rx_frame.data.u8[7]);
|
||||
if (v > 0 && v < 0xf000) {
|
||||
datalayer.battery.status.current_dA = -(v - 20000) * 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case 0x3BE:
|
||||
// Per-cell voltages and temps
|
||||
cell_id = rx_frame.data.u8[5];
|
||||
if (cell_id < 90) {
|
||||
v = 1000 + (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
|
||||
datalayer.battery.status.cell_voltages_mV[cell_id] = v < 10000 ? v : 0;
|
||||
// cell temperature is rx_frame.data.u8[1]-40 but BE doesn't use it
|
||||
}
|
||||
|
||||
break;
|
||||
case 0x3C0:
|
||||
break;
|
||||
case 0x3C2:
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x400:
|
||||
break;
|
||||
case 0x402:
|
||||
break;
|
||||
case 0x418:
|
||||
break;
|
||||
case 0x44C: //This ID is on the MG HS RX WITHOUT ANY TX PRESENT
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x620:
|
||||
break; //This is the last on the list in the MG5 template.
|
||||
case 0x3a8: //This ID is on the MG HS RX WITHOUT ANY TX PRESENT
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x508: //This ID is a new one MG HS RX WHEN TRANSMITTING 03 22 B0 41 00 00 00 00. Rx data is 00 00 00 00 00 00 00 00
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
break;
|
||||
case 0x7ED: //This ID is the battery BMS
|
||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||
//Process rx data for incoming responses to "Read data by ID" Tx
|
||||
case 0x7ED:
|
||||
// A response from our CAN2 OBD requests
|
||||
// We mostly ignore these, apart from SoH, and also the voltage as a
|
||||
// safety measure (in case CAN1 misbehaves).
|
||||
if (rx_frame.data.u8[1] == 0x62) {
|
||||
if (rx_frame.data.u8[2] == 0xB0) { //Battery information
|
||||
if (rx_frame.data.u8[3] == 0x41 && rx_frame.data.u8[0] == 0x05) { // Battery bus voltage
|
||||
// Serial.print ("Battery Bus voltage frame = ");
|
||||
// print_can_frame_MG5(rx_frame, frameDirection(MSG_RX));
|
||||
// datalayer.battery.status.PARAMETER = (rx_frame.data.u8[4] << 8 | rx_frame.data.u8[5]) * 2.5;
|
||||
// Serial.print ("Battery Bus Voltage = ");
|
||||
// Serial.println (datalayer.battery.status.PARAMETER);
|
||||
}
|
||||
if (rx_frame.data.u8[3] == 0x42 && rx_frame.data.u8[0] == 0x05) { // Battery voltage
|
||||
// Serial.print ("Battery voltage frame = ");
|
||||
// print_can_frame_MG5(rx_frame, frameDirection(MSG_RX));
|
||||
// Battery bus voltage
|
||||
// (rx_frame.data.u8[4] << 8 | rx_frame.data.u8[5]) * 2.5;
|
||||
} else if (rx_frame.data.u8[3] == 0x42 && rx_frame.data.u8[0] == 0x05) {
|
||||
// Battery voltage
|
||||
datalayer.battery.status.voltage_dV = (rx_frame.data.u8[4] << 8 | rx_frame.data.u8[5]) * 2.5;
|
||||
// Serial.print ("Battery voltage = ");
|
||||
// Serial.println (datalayer.battery.status.voltage_dV);
|
||||
}
|
||||
if (rx_frame.data.u8[3] == 0x43 && rx_frame.data.u8[0] == 0x05) { // Battery current
|
||||
// Serial.print ("Battery current frame = ");
|
||||
// print_can_frame_MG5(rx_frame, frameDirection(MSG_RX));
|
||||
datalayer.battery.status.current_dA = ((rx_frame.data.u8[4] << 8 | rx_frame.data.u8[5]) - 40000) / -4;
|
||||
// Serial.print ("Battery current = ");
|
||||
// Serial.println (datalayer.battery.status.current_dA);
|
||||
}
|
||||
|
||||
if (rx_frame.data.u8[3] == 0x45 && rx_frame.data.u8[0] == 0x05) { // Battery resistance
|
||||
// Serial.print ("Battery resistance frame = ");
|
||||
// print_can_frame_MG5(rx_frame, frameDirection(MSG_RX));
|
||||
// datalayer.battery.status.PARAMETER = (rx_frame.data.u8[4] << 8 | rx_frame.data.u8[5]);
|
||||
// Serial.print ("Battery resistance = ");
|
||||
// Serial.println (datalayer.battery.status.PARAMETER);
|
||||
}
|
||||
if (rx_frame.data.u8[3] == 0x46 && rx_frame.data.u8[0] == 0x05) { // Battery SoC
|
||||
// Serial.print ("Battery SoC frame = ");
|
||||
// print_can_frame_MG5(rx_frame, frameDirection(MSG_RX));
|
||||
datalayer.battery.status.real_soc = (rx_frame.data.u8[4] << 8 | rx_frame.data.u8[5]) * 10;
|
||||
// Serial.print ("Battery SoC = ");
|
||||
// Serial.println (datalayer.battery.status.real_soc);
|
||||
RealSoC = datalayer.battery.status.real_soc / 100; // For calculation of charge and discharge rates
|
||||
}
|
||||
|
||||
if (rx_frame.data.u8[3] == 0x47) { // && rx_frame.data.u8[0] == 0x05) { // BMS error code
|
||||
// Serial.print ("BMS error code frame = ");
|
||||
// print_can_frame_MG5(rx_frame, frameDirection(MSG_RX));
|
||||
// datalayer.battery.status.PARAMETER = (rx_frame.data.u8[4] << 8 | rx_frame.data.u8[5]); // HOLD: What to do with this data
|
||||
// Serial.print ("Battery error = ");
|
||||
// Serial.println (datalayer.battery.status.PARAMETER);
|
||||
}
|
||||
|
||||
if (rx_frame.data.u8[3] == 0x48) { // && rx_frame.data.u8[0] == 0x05) { // BMS status code
|
||||
// Serial.print ("BMS status code frame = ");
|
||||
// print_can_frame_MG5(rx_frame, frameDirection(MSG_RX));
|
||||
// datalayer.battery.status.PARAMETER = (rx_frame.data.u8[4] << 8 | rx_frame.data.u8[5]); // HOLD: What to do with this data
|
||||
// Serial.print ("Battery Status = ");
|
||||
// Serial.println (datalayer.battery.status.PARAMETER);
|
||||
}
|
||||
|
||||
if (rx_frame.data.u8[3] == 0x49) { // && rx_frame.data.u8[0] == 0x05) { // System main relay B status
|
||||
// Serial.print ("System main relay B status frame = ");
|
||||
// print_can_frame_MG5(rx_frame, frameDirection(MSG_RX));
|
||||
// datalayer.battery.status.PARAMETER = (rx_frame.data.u8[4] << 8 | rx_frame.data.u8[5]); // HOLD: What to do with this data
|
||||
// Serial.print ("Main relay B status = ");
|
||||
// Serial.println (datalayer.battery.status.PARAMETER);
|
||||
}
|
||||
|
||||
if (rx_frame.data.u8[3] == 0x4A) { // && rx_frame.data.u8[0] == 0x05) { // System main relay G status
|
||||
// Serial.print ("System main relay G status frame = ");
|
||||
// print_can_frame_MG5(rx_frame, frameDirection(MSG_RX));
|
||||
// datalayer.battery.status.PARAMETER = (rx_frame.data.u8[4] << 8 | rx_frame.data.u8[5]); // HOLD: What to do with this data
|
||||
// Serial.print ("Main relay G status = ");
|
||||
// Serial.println (datalayer.battery.status.PARAMETER);
|
||||
}
|
||||
|
||||
if (rx_frame.data.u8[3] == 0x52) { // && rx_frame.data.u8[0] == 0x05) { // System main relay P status
|
||||
// Serial.print ("System main relay P status frame = ");
|
||||
// print_can_frame_MG5(rx_frame, frameDirection(MSG_RX));
|
||||
// datalayer.battery.status.PARAMETER = (rx_frame.data.u8[4] << 8 | rx_frame.data.u8[5]); // HOLD: What to do with this data
|
||||
// Serial.print ("BMain relay P status = ");
|
||||
// Serial.println (datalayer.battery.status.PARAMETER);
|
||||
}
|
||||
|
||||
if (rx_frame.data.u8[3] == 0x56 && rx_frame.data.u8[0] == 0x05) { // Max cell temperature
|
||||
// Serial.print ("Max cell temperature frame = ");
|
||||
// print_can_frame_MG5(rx_frame, frameDirection(MSG_RX));
|
||||
datalayer.battery.status.temperature_max_dC =
|
||||
(((rx_frame.data.u8[4] << 8 | rx_frame.data.u8[5]) / 500) - 40) * 10;
|
||||
// Serial.print ("Max cell temperature = ");
|
||||
// Serial.println (datalayer.battery.status.temperature_max_dC);
|
||||
}
|
||||
|
||||
if (rx_frame.data.u8[3] == 0x57 && rx_frame.data.u8[0] == 0x05) { // Min cell temperature
|
||||
// Serial.print ("Min cell temperature frame = ");
|
||||
// print_can_frame_MG5(rx_frame, frameDirection(MSG_RX));
|
||||
datalayer.battery.status.temperature_min_dC =
|
||||
(((rx_frame.data.u8[4] << 8 | rx_frame.data.u8[5]) / 500) - 40) * 10;
|
||||
// Serial.print ("Min cell temperature = ");
|
||||
// Serial.println (datalayer.battery.status.temperature_min_dC);
|
||||
}
|
||||
|
||||
if (rx_frame.data.u8[3] == 0x58 && rx_frame.data.u8[0] == 0x06) { // Max cell voltage
|
||||
// Serial.print ("Max cell voltage frame = ");
|
||||
// print_can_frame_MG5(rx_frame, frameDirection(MSG_RX));
|
||||
datalayer.battery.status.cell_max_voltage_mV =
|
||||
(rx_frame.data.u8[4] << 16 | rx_frame.data.u8[5] << 8 | rx_frame.data.u8[6]) / 250;
|
||||
// Serial.print ("Max cell voltage = ");
|
||||
// Serial.println (datalayer.battery.status.cell_max_voltage_mV);
|
||||
}
|
||||
|
||||
if (rx_frame.data.u8[3] == 0x59 && rx_frame.data.u8[0] == 0x06) { // Min cell voltage
|
||||
// Serial.print ("Min cell voltage frame = ");
|
||||
// print_can_frame_MG5(rx_frame, frameDirection(MSG_RX));
|
||||
datalayer.battery.status.cell_min_voltage_mV =
|
||||
(rx_frame.data.u8[4] << 16 | rx_frame.data.u8[5] << 8 | rx_frame.data.u8[6]) / 250;
|
||||
// Serial.print ("Min cell voltage = ");
|
||||
// Serial.println (datalayer.battery.status.cell_min_voltage_mV);
|
||||
}
|
||||
|
||||
if (rx_frame.data.u8[3] == 0x61 && rx_frame.data.u8[0] == 0x05) { // Battery SoH
|
||||
// Serial.print ("Battery SoH frame = ");
|
||||
// print_can_frame_MG5(rx_frame, frameDirection(MSG_RX));
|
||||
} else if (rx_frame.data.u8[3] == 0x43 && rx_frame.data.u8[0] == 0x05) {
|
||||
// Battery current
|
||||
// we won't update this as it differs in rounding from the CAN1 version
|
||||
//datalayer.battery.status.current_dA = ((rx_frame.data.u8[4] << 8 | rx_frame.data.u8[5]) - 40000) / -4;
|
||||
} else if (rx_frame.data.u8[3] == 0x45 && rx_frame.data.u8[0] == 0x05) {
|
||||
// Battery resistance
|
||||
// rx_frame.data.u8[4] << 8 | rx_frame.data.u8[5]);
|
||||
} else if (rx_frame.data.u8[3] == 0x46 && rx_frame.data.u8[0] == 0x05) {
|
||||
// The battery SoC, the same as soc1 in 3AC.
|
||||
soc1 = (rx_frame.data.u8[4] << 8 | rx_frame.data.u8[5]);
|
||||
// We won't use since we're using soc2
|
||||
} else if (rx_frame.data.u8[3] == 0x47) {
|
||||
// BMS error code
|
||||
// (rx_frame.data.u8[4] << 8 | rx_frame.data.u8[5]); // HOLD: What to do with this data
|
||||
} else if (rx_frame.data.u8[3] == 0x48) {
|
||||
// BMS status coded
|
||||
// (rx_frame.data.u8[4] << 8 | rx_frame.data.u8[5]); // HOLD: What to do with this data
|
||||
// This is the same as 297[1]
|
||||
} else if (rx_frame.data.u8[3] == 0x49) {
|
||||
// System main relay B status
|
||||
// (rx_frame.data.u8[4] << 8 | rx_frame.data.u8[5]); // HOLD: What to do with this data
|
||||
} else if (rx_frame.data.u8[3] == 0x4A) {
|
||||
// System main relay G status
|
||||
// (rx_frame.data.u8[4] << 8 | rx_frame.data.u8[5]); // HOLD: What to do with this data
|
||||
} else if (rx_frame.data.u8[3] ==
|
||||
0x52) { // && rx_frame.data.u8[0] == 0x05) { // System main relay P status
|
||||
// System main relay P status
|
||||
// (rx_frame.data.u8[4] << 8 | rx_frame.data.u8[5]); // HOLD: What to do with this data
|
||||
} else if (rx_frame.data.u8[3] == 0x56 && rx_frame.data.u8[0] == 0x05) {
|
||||
// Max cell temperature
|
||||
// datalayer.battery.status.temperature_max_dC =
|
||||
// (((rx_frame.data.u8[4] << 8 | rx_frame.data.u8[5]) / 500) - 40) * 10;
|
||||
} else if (rx_frame.data.u8[3] == 0x57 && rx_frame.data.u8[0] == 0x05) {
|
||||
// Min cell temperature
|
||||
// datalayer.battery.status.temperature_min_dC =
|
||||
// (((rx_frame.data.u8[4] << 8 | rx_frame.data.u8[5]) / 500) - 40) * 10;
|
||||
} else if (rx_frame.data.u8[3] == 0x58 && rx_frame.data.u8[0] == 0x06) {
|
||||
// Max cell voltage
|
||||
// datalayer.battery.status.cell_max_voltage_mV = rx_frame.data.u8[4] << 8 | rx_frame.data.u8[5];
|
||||
// cellVoltageValidTime = CELL_VOLTAGE_TIMEOUT;
|
||||
} else if (rx_frame.data.u8[3] == 0x59 && rx_frame.data.u8[0] == 0x06) {
|
||||
// Min cell voltage
|
||||
// datalayer.battery.status.cell_min_voltage_mV = rx_frame.data.u8[4] << 8 | rx_frame.data.u8[5];
|
||||
} else if (rx_frame.data.u8[3] == 0x61 && rx_frame.data.u8[0] == 0x05) {
|
||||
// Battery SoH
|
||||
datalayer.battery.status.soh_pptt = (rx_frame.data.u8[4] << 8 | rx_frame.data.u8[5]);
|
||||
// Serial.print ("Battery SoH = ");
|
||||
// Serial.println (datalayer.battery.status.soh_pptt);
|
||||
}
|
||||
|
||||
} // data.u8[2]=0xB0
|
||||
} // data.u8[1] = 0x62)
|
||||
|
||||
//Set calculated and derived parameters
|
||||
|
||||
// Calculate the remaining capacity.
|
||||
tempfloat = datalayer.battery.info.total_capacity_Wh * (RealSoC - MinSoC) / 100;
|
||||
// Serial.print ("Remaining capacity calculated = ");
|
||||
// Serial.println (tempfloat);
|
||||
if (tempfloat > 0) {
|
||||
datalayer.battery.status.remaining_capacity_Wh = tempfloat;
|
||||
} else {
|
||||
datalayer.battery.status.remaining_capacity_Wh = 0;
|
||||
}
|
||||
|
||||
// Calculate the maximum charge power. Taper the charge power between 90% and 100% SoC, as 100% SoC is approached
|
||||
if (RealSoC < StartChargeTaper) {
|
||||
datalayer.battery.status.max_charge_power_W = MaxChargePower;
|
||||
} else if (RealSoC >= 100) {
|
||||
datalayer.battery.status.max_charge_power_W = TricklePower;
|
||||
} else {
|
||||
//Taper the charge to the Trickle value. The shape and start point of the taper is set by the constants
|
||||
datalayer.battery.status.max_charge_power_W =
|
||||
(MaxChargePower * pow(((100 - RealSoC) / (100 - StartChargeTaper)), ChargeTaperExponent)) + TricklePower;
|
||||
}
|
||||
|
||||
// Calculate the maximum discharge power. Taper the discharge power between 35% and Min% SoC, as Min% SoC is approached
|
||||
if (RealSoC > StartDischargeTaper) {
|
||||
datalayer.battery.status.max_discharge_power_W = MaxDischargePower;
|
||||
} else if (RealSoC < MinSoC) {
|
||||
datalayer.battery.status.max_discharge_power_W = TricklePower;
|
||||
} else {
|
||||
//Taper the charge to the Trickle value. The shape and start point of the taper is set by the constants
|
||||
datalayer.battery.status.max_discharge_power_W =
|
||||
(MaxDischargePower * pow(((RealSoC - MinSoC) / (StartDischargeTaper - MinSoC)), DischargeTaperExponent)) +
|
||||
TricklePower;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
void MgHsPHEVBattery::transmit_can(unsigned long currentMillis) {
|
||||
// Send 70ms CAN Message
|
||||
if (currentMillis - previousMillis70 >= INTERVAL_70_MS) {
|
||||
previousMillis70 = currentMillis;
|
||||
if (datalayer.system.status.BMS_reset_in_progress || datalayer.system.status.BMS_startup_in_progress) {
|
||||
// Transmitting towards battery is halted while BMS is being reset
|
||||
previousMillis100 = currentMillis;
|
||||
previousMillis200 = currentMillis;
|
||||
return;
|
||||
}
|
||||
|
||||
// Send 100ms CAN Message
|
||||
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
|
||||
previousMillis100 = currentMillis;
|
||||
|
||||
#if MG_HS_PHEV_DISABLE_CONTACTORS
|
||||
// Leave the contactors open
|
||||
MG_HS_8A.data.u8[5] = 0x00;
|
||||
#else
|
||||
if (datalayer.battery.status.bms_status == FAULT) {
|
||||
//Open contactors!
|
||||
// Fault, so open contactors!
|
||||
MG_HS_8A.data.u8[5] = 0x00;
|
||||
} else { // Not in faulted mode, Close contactors!
|
||||
} else if (!datalayer.system.status.inverter_allows_contactor_closing) {
|
||||
// Inverter requests contactor opening
|
||||
MG_HS_8A.data.u8[5] = 0x00;
|
||||
} else {
|
||||
// Everything ready, close contactors
|
||||
MG_HS_8A.data.u8[5] = 0x02;
|
||||
}
|
||||
#endif // MG_HS_PHEV_DISABLE_CONTACTORS
|
||||
|
||||
transmit_can_frame(&MG_HS_8A, can_config.battery);
|
||||
transmit_can_frame(&MG_HS_1F1, can_config.battery);
|
||||
transmit_can_frame(&MG_HS_8A);
|
||||
transmit_can_frame(&MG_HS_1F1);
|
||||
}
|
||||
// Send 200ms CAN Message
|
||||
if (currentMillis - previousMillis200 >= INTERVAL_200_MS) {
|
||||
previousMillis200 = currentMillis;
|
||||
|
||||
switch (messageindex) {
|
||||
switch (transmitIndex) {
|
||||
case 1:
|
||||
transmit_can_frame(&MG_HS_7E5_B0_42, can_config.battery); //Battery voltage
|
||||
transmit_can_frame(&MG_HS_7E5_B0_42); //Battery voltage
|
||||
break;
|
||||
case 2:
|
||||
transmit_can_frame(&MG_HS_7E5_B0_43, can_config.battery); //Battery current
|
||||
break;
|
||||
case 3:
|
||||
transmit_can_frame(&MG_HS_7E5_B0_46, can_config.battery); //Battery SoC
|
||||
break;
|
||||
case 4:
|
||||
transmit_can_frame(&MG_HS_7E5_B0_47, can_config.battery); // Get BMS error code
|
||||
break;
|
||||
case 5:
|
||||
transmit_can_frame(&MG_HS_7E5_B0_48, can_config.battery); // Get BMS status
|
||||
break;
|
||||
case 6:
|
||||
transmit_can_frame(&MG_HS_7E5_B0_49, can_config.battery); // Get System main relay B status
|
||||
break;
|
||||
case 7:
|
||||
transmit_can_frame(&MG_HS_7E5_B0_4A, can_config.battery); // Get System main relay G status
|
||||
break;
|
||||
case 8:
|
||||
transmit_can_frame(&MG_HS_7E5_B0_52, can_config.battery); // Get System main relay P status
|
||||
break;
|
||||
case 9:
|
||||
transmit_can_frame(&MG_HS_7E5_B0_56, can_config.battery); //Max cell temperature
|
||||
break;
|
||||
case 10:
|
||||
transmit_can_frame(&MG_HS_7E5_B0_57, can_config.battery); //Min cell temperature
|
||||
break;
|
||||
case 11:
|
||||
transmit_can_frame(&MG_HS_7E5_B0_58, can_config.battery); //Max cell voltage
|
||||
break;
|
||||
case 12:
|
||||
transmit_can_frame(&MG_HS_7E5_B0_59, can_config.battery); //Min cell voltage
|
||||
break;
|
||||
case 13:
|
||||
transmit_can_frame(&MG_HS_7E5_B0_61, can_config.battery); //Battery SoH
|
||||
messageindex = 0; //Return to the first message index. This goes in the last message entry
|
||||
transmit_can_frame(&MG_HS_7E5_B0_61); //Battery SoH
|
||||
transmitIndex = 0; //Return to the first message index. This goes in the last message entry
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
} //switch
|
||||
|
||||
messageindex++; //Increment the message index
|
||||
transmitIndex++; //Increment the message index
|
||||
|
||||
} //endif
|
||||
}
|
||||
|
@ -358,6 +378,6 @@ void MgHsPHEVBattery::setup(void) { // Performs one time setup at startup
|
|||
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.total_capacity_Wh = BATTERY_WH_MAX;
|
||||
datalayer.battery.info.number_of_cells = 90;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
#ifndef MG_HS_PHEV_BATTERY_H
|
||||
#define MG_HS_PHEV_BATTERY_H
|
||||
#include <Arduino.h>
|
||||
#include "../include.h"
|
||||
|
||||
#include "CanBattery.h"
|
||||
|
||||
|
@ -19,22 +17,28 @@ class MgHsPHEVBattery : public CanBattery {
|
|||
static constexpr const char* Name = "MG HS PHEV 16.6kWh battery";
|
||||
|
||||
private:
|
||||
static const int MAX_PACK_VOLTAGE_DV = 4040; //5000 = 500.0V
|
||||
static const int MIN_PACK_VOLTAGE_DV = 3100;
|
||||
void update_soc(uint16_t soc_times_ten);
|
||||
|
||||
static const int MAX_PACK_VOLTAGE_DV = 3780; //5000 = 500.0V
|
||||
static const int MIN_PACK_VOLTAGE_DV = 2790;
|
||||
static const int MAX_CELL_DEVIATION_MV = 150;
|
||||
static const int MAX_CELL_VOLTAGE_MV = 4250; //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
|
||||
static const int MIN_CELL_VOLTAGE_MV = 2610; //Battery is put into emergency stop if one cell goes below this value
|
||||
|
||||
unsigned long previousMillis70 = 0; // will store last time a 70ms CAN Message was send
|
||||
unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was send
|
||||
unsigned long previousMillis200 = 0; // will store last time a 200ms CAN Message was send
|
||||
|
||||
int BMS_SOC = 0;
|
||||
// For calculating charge and discharge power
|
||||
float RealVoltage;
|
||||
float RealSoC;
|
||||
float tempfloat;
|
||||
|
||||
uint8_t messageindex = 0; //For polling switchcase
|
||||
uint8_t previousState = 0;
|
||||
|
||||
static const uint16_t CELL_VOLTAGE_TIMEOUT = 10; // in seconds
|
||||
uint16_t cellVoltageValidTime = 0;
|
||||
|
||||
uint8_t transmitIndex = 0; //For polling switchcase
|
||||
|
||||
const int MaxChargePower = 3000; // Maximum allowable charge power, excluding the taper
|
||||
const int StartChargeTaper = 90; // Battery percentage above which the charge power will taper to zero
|
||||
|
@ -52,7 +56,7 @@ class MgHsPHEVBattery : public CanBattery {
|
|||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x08A,
|
||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x36, 0xB0}};
|
||||
.data = {0x80, 0x00, 0x00, 0x04, 0x00, 0x02, 0x36, 0xB0}};
|
||||
CAN_frame MG_HS_1F1 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
#include "NISSAN-LEAF-BATTERY.h"
|
||||
#include "../include.h"
|
||||
#ifdef MQTT
|
||||
#include "../devboard/mqtt/mqtt.h"
|
||||
#endif
|
||||
#include "../communication/can/comm_can.h"
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../datalayer/datalayer_extended.h" //For "More battery info" webpage
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../devboard/utils/logging.h"
|
||||
|
||||
#include "../charger/CHARGERS.h"
|
||||
#include "../charger/CanCharger.h"
|
||||
|
||||
uint16_t Temp_fromRAW_to_F(uint16_t temperature);
|
||||
|
@ -334,7 +331,7 @@ void NissanLeafBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
|||
group_7bb = rx_frame.data.u8[3];
|
||||
}
|
||||
|
||||
transmit_can_frame(&LEAF_NEXT_LINE_REQUEST, can_interface); //Request the next frame for the group
|
||||
transmit_can_frame(&LEAF_NEXT_LINE_REQUEST); //Request the next frame for the group
|
||||
|
||||
if (group_7bb == 0x01) //High precision SOC, Current, voltages etc.
|
||||
{
|
||||
|
@ -584,7 +581,7 @@ void NissanLeafBattery::transmit_can(unsigned long currentMillis) {
|
|||
LEAF_1D4.data.u8[7] = 0xDE;
|
||||
break;
|
||||
}
|
||||
transmit_can_frame(&LEAF_1D4, can_interface);
|
||||
transmit_can_frame(&LEAF_1D4);
|
||||
|
||||
switch (mprun10r) {
|
||||
case (0):
|
||||
|
@ -677,7 +674,7 @@ void NissanLeafBattery::transmit_can(unsigned long currentMillis) {
|
|||
|
||||
//Only send this message when NISSANLEAF_CHARGER is not defined (otherwise it will collide!)
|
||||
if (!charger || charger->type() != ChargerType::NissanLeaf) {
|
||||
transmit_can_frame(&LEAF_1F2, can_interface);
|
||||
transmit_can_frame(&LEAF_1F2);
|
||||
}
|
||||
|
||||
mprun10r = (mprun10r + 1) % 20; // 0x1F2 patter repeats after 20 messages. 0-1..19-0
|
||||
|
@ -701,7 +698,7 @@ void NissanLeafBattery::transmit_can(unsigned long currentMillis) {
|
|||
}
|
||||
|
||||
// VCM message, containing info if battery should sleep or stay awake
|
||||
transmit_can_frame(&LEAF_50B, can_interface); // HCM_WakeUpSleepCommand == 11b == WakeUp, and CANMASK = 1
|
||||
transmit_can_frame(&LEAF_50B); // HCM_WakeUpSleepCommand == 11b == WakeUp, and CANMASK = 1
|
||||
|
||||
LEAF_50C.data.u8[3] = mprun100;
|
||||
switch (mprun100) {
|
||||
|
@ -722,7 +719,7 @@ void NissanLeafBattery::transmit_can(unsigned long currentMillis) {
|
|||
LEAF_50C.data.u8[5] = 0x9A;
|
||||
break;
|
||||
}
|
||||
transmit_can_frame(&LEAF_50C, can_interface);
|
||||
transmit_can_frame(&LEAF_50C);
|
||||
|
||||
mprun100 = (mprun100 + 1) % 4; // mprun100 cycles between 0-1-2-3-0-1...
|
||||
}
|
||||
|
@ -738,7 +735,7 @@ void NissanLeafBattery::transmit_can(unsigned long currentMillis) {
|
|||
PIDindex = (PIDindex + 1) % 7; // 7 = amount of elements in the PIDgroups[]
|
||||
LEAF_GROUP_REQUEST.data.u8[2] = PIDgroups[PIDindex];
|
||||
|
||||
transmit_can_frame(&LEAF_GROUP_REQUEST, can_interface);
|
||||
transmit_can_frame(&LEAF_GROUP_REQUEST);
|
||||
}
|
||||
|
||||
if (hold_off_with_polling_10seconds > 0) {
|
||||
|
@ -800,19 +797,19 @@ void NissanLeafBattery::clearSOH(void) {
|
|||
break;
|
||||
case 1: // Set CAN_PROCESS_FLAG to 0xC0
|
||||
LEAF_CLEAR_SOH.data = {0x02, 0x10, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
transmit_can_frame(&LEAF_CLEAR_SOH, can_interface);
|
||||
transmit_can_frame(&LEAF_CLEAR_SOH);
|
||||
// BMS should reply 02 50 C0 FF FF FF FF FF
|
||||
stateMachineClearSOH = 2;
|
||||
break;
|
||||
case 2: // Set something ?
|
||||
LEAF_CLEAR_SOH.data = {0x02, 0x3E, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
transmit_can_frame(&LEAF_CLEAR_SOH, can_interface);
|
||||
transmit_can_frame(&LEAF_CLEAR_SOH);
|
||||
// BMS should reply 7E FF FF FF FF FF FF
|
||||
stateMachineClearSOH = 3;
|
||||
break;
|
||||
case 3: // Request challenge to solve
|
||||
LEAF_CLEAR_SOH.data = {0x02, 0x27, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
transmit_can_frame(&LEAF_CLEAR_SOH, can_interface);
|
||||
transmit_can_frame(&LEAF_CLEAR_SOH);
|
||||
// BMS should reply with (challenge) 06 67 65 (02 DD 86 43) FF
|
||||
stateMachineClearSOH = 4;
|
||||
break;
|
||||
|
@ -820,34 +817,34 @@ void NissanLeafBattery::clearSOH(void) {
|
|||
decodeChallengeData(incomingChallenge, solvedChallenge);
|
||||
LEAF_CLEAR_SOH.data = {
|
||||
0x10, 0x0A, 0x27, 0x66, solvedChallenge[0], solvedChallenge[1], solvedChallenge[2], solvedChallenge[3]};
|
||||
transmit_can_frame(&LEAF_CLEAR_SOH, can_interface);
|
||||
transmit_can_frame(&LEAF_CLEAR_SOH);
|
||||
// BMS should reply 7BB 8 30 01 00 FF FF FF FF FF // Proceed with more data (PID ACK)
|
||||
stateMachineClearSOH = 5;
|
||||
break;
|
||||
case 5: // Reply with even more decoded challenge data
|
||||
LEAF_CLEAR_SOH.data = {
|
||||
0x21, solvedChallenge[4], solvedChallenge[5], solvedChallenge[6], solvedChallenge[7], 0x00, 0x00, 0x00};
|
||||
transmit_can_frame(&LEAF_CLEAR_SOH, can_interface);
|
||||
transmit_can_frame(&LEAF_CLEAR_SOH);
|
||||
// BMS should reply 02 67 66 FF FF FF FF FF // Thank you for the data
|
||||
stateMachineClearSOH = 6;
|
||||
break;
|
||||
case 6: // Check if solved data was OK
|
||||
LEAF_CLEAR_SOH.data = {0x03, 0x31, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
transmit_can_frame(&LEAF_CLEAR_SOH, can_interface);
|
||||
transmit_can_frame(&LEAF_CLEAR_SOH);
|
||||
//7BB 8 03 71 03 01 FF FF FF FF // If all is well, BMS replies with 03 71 03 01.
|
||||
//Incase you sent wrong challenge, you get 03 7f 31 12
|
||||
stateMachineClearSOH = 7;
|
||||
break;
|
||||
case 7: // Reset SOH% request
|
||||
LEAF_CLEAR_SOH.data = {0x03, 0x31, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00};
|
||||
transmit_can_frame(&LEAF_CLEAR_SOH, can_interface);
|
||||
transmit_can_frame(&LEAF_CLEAR_SOH);
|
||||
//7BB 8 03 71 03 02 FF FF FF FF // 03 71 03 02 means that BMS accepted command.
|
||||
//7BB 03 7f 31 12 means your challenge was wrong, so command ignored
|
||||
stateMachineClearSOH = 8;
|
||||
break;
|
||||
case 8: // Please proceed with resetting SOH
|
||||
LEAF_CLEAR_SOH.data = {0x02, 0x10, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
transmit_can_frame(&LEAF_CLEAR_SOH, can_interface);
|
||||
transmit_can_frame(&LEAF_CLEAR_SOH);
|
||||
// 7BB 8 02 50 81 FF FF FF FF FF // SOH reset OK
|
||||
stateMachineClearSOH = 255;
|
||||
break;
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../datalayer/datalayer_extended.h"
|
||||
#include "../include.h"
|
||||
#include "CanBattery.h"
|
||||
#include "NISSAN-LEAF-HTML.h"
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#include "../communication/can/comm_can.h"
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../include.h"
|
||||
|
||||
void findMinMaxCellvoltages(const uint16_t arr[], size_t size, uint16_t& Minimum_Cell_Voltage,
|
||||
uint16_t& Maximum_Cell_Voltage) {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#ifndef ORION_BMS_H
|
||||
#define ORION_BMS_H
|
||||
#include <Arduino.h>
|
||||
#include "../include.h"
|
||||
|
||||
#include "../system_settings.h"
|
||||
#include "CanBattery.h"
|
||||
|
||||
#ifdef ORION_BMS
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#include "../communication/can/comm_can.h"
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../include.h"
|
||||
|
||||
void PylonBattery::update_values() {
|
||||
|
||||
|
@ -117,10 +116,10 @@ void PylonBattery::transmit_can(unsigned long currentMillis) {
|
|||
if (currentMillis - previousMillis1000 >= INTERVAL_1_S) {
|
||||
previousMillis1000 = currentMillis;
|
||||
|
||||
transmit_can_frame(&PYLON_3010, can_config.battery); // Heartbeat
|
||||
transmit_can_frame(&PYLON_4200, can_config.battery); // Ensemble OR System equipment info, depends on frame0
|
||||
transmit_can_frame(&PYLON_8200, can_config.battery); // Control device quit sleep status
|
||||
transmit_can_frame(&PYLON_8210, can_config.battery); // Charge command
|
||||
transmit_can_frame(&PYLON_3010); // Heartbeat
|
||||
transmit_can_frame(&PYLON_4200); // Ensemble OR System equipment info, depends on frame0
|
||||
transmit_can_frame(&PYLON_8200); // Control device quit sleep status
|
||||
transmit_can_frame(&PYLON_8210); // Charge command
|
||||
|
||||
if (ensemble_info_ack) {
|
||||
PYLON_4200.data.u8[0] = 0x00; //Request system equipment info
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#include <Arduino.h>
|
||||
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../include.h"
|
||||
#include "CanBattery.h"
|
||||
|
||||
#ifdef PYLON_BATTERY
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#include "../communication/can/comm_can.h"
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../include.h"
|
||||
|
||||
/* TODO
|
||||
- LOG files from vehicle needed to determine CAN content needed to send towards battery!
|
||||
|
@ -202,7 +201,7 @@ void RangeRoverPhevBattery::transmit_can(unsigned long currentMillis) {
|
|||
if (currentMillis - previousMillis50ms >= INTERVAL_50_MS) {
|
||||
previousMillis50ms = currentMillis;
|
||||
|
||||
transmit_can_frame(&RANGE_ROVER_18B, can_config.battery);
|
||||
transmit_can_frame(&RANGE_ROVER_18B);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#ifndef RANGE_ROVER_PHEV_BATTERY_H
|
||||
#define RANGE_ROVER_PHEV_BATTERY_H
|
||||
#include <Arduino.h>
|
||||
#include "../include.h"
|
||||
|
||||
#include "CanBattery.h"
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#include "../communication/can/comm_can.h"
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../include.h"
|
||||
#include "../devboard/utils/logging.h"
|
||||
|
||||
/* TODO:
|
||||
There seems to be some values on the Kangoo that differ between the 22/33 kWh version
|
||||
|
@ -162,7 +162,7 @@ void RenaultKangooBattery::transmit_can(unsigned long currentMillis) {
|
|||
// Send 100ms CAN Message (for 2.4s, then pause 10s)
|
||||
if ((currentMillis - previousMillis100) >= (INTERVAL_100_MS + GVL_pause)) {
|
||||
previousMillis100 = currentMillis;
|
||||
transmit_can_frame(&KANGOO_423, can_config.battery);
|
||||
transmit_can_frame(&KANGOO_423);
|
||||
GVI_Pollcounter++;
|
||||
GVL_pause = 0;
|
||||
if (GVI_Pollcounter >= 24) {
|
||||
|
@ -174,9 +174,9 @@ void RenaultKangooBattery::transmit_can(unsigned long currentMillis) {
|
|||
if (currentMillis - previousMillis1000 >= INTERVAL_1_S) {
|
||||
previousMillis1000 = currentMillis;
|
||||
if (GVB_79B_Continue)
|
||||
transmit_can_frame(&KANGOO_79B_Continue, can_config.battery);
|
||||
transmit_can_frame(&KANGOO_79B_Continue);
|
||||
} else {
|
||||
transmit_can_frame(&KANGOO_79B, can_config.battery);
|
||||
transmit_can_frame(&KANGOO_79B);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#ifndef RENAULT_KANGOO_BATTERY_H
|
||||
#define RENAULT_KANGOO_BATTERY_H
|
||||
#include <Arduino.h>
|
||||
#include "../include.h"
|
||||
|
||||
#include "CanBattery.h"
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#include <cstdint>
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../include.h"
|
||||
|
||||
int16_t max_value(int16_t* entries, size_t len) {
|
||||
int result = INT16_MIN;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#ifndef RENAULT_TWIZY_BATTERY_H
|
||||
#define RENAULT_TWIZY_BATTERY_H
|
||||
#include "../include.h"
|
||||
#include "CanBattery.h"
|
||||
|
||||
#ifdef RENAULT_TWIZY_BATTERY
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#include "../datalayer/datalayer.h"
|
||||
#include "../datalayer/datalayer_extended.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../include.h"
|
||||
|
||||
void transmit_can_frame(CAN_frame* tx_frame, int interface);
|
||||
|
||||
|
@ -166,7 +165,7 @@ void RenaultZoeGen1Battery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
|||
switch (frame0) {
|
||||
case 0x10: //PID HEADER, datarow 0
|
||||
requested_poll = rx_frame.data.u8[3];
|
||||
transmit_can_frame(&ZOE_ACK_79B, can_interface);
|
||||
transmit_can_frame(&ZOE_ACK_79B);
|
||||
|
||||
if (requested_poll == GROUP1_CELLVOLTAGES_1_POLL) {
|
||||
cellvoltages[0] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
||||
|
@ -469,7 +468,7 @@ void RenaultZoeGen1Battery::transmit_can(unsigned long currentMillis) {
|
|||
// Send 100ms CAN Message
|
||||
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
|
||||
previousMillis100 = currentMillis;
|
||||
transmit_can_frame(&ZOE_423, can_interface);
|
||||
transmit_can_frame(&ZOE_423);
|
||||
|
||||
if ((counter_423 / 5) % 2 == 0) { // Alternate every 5 messages between these two
|
||||
ZOE_423.data.u8[4] = 0xB2;
|
||||
|
@ -508,7 +507,7 @@ void RenaultZoeGen1Battery::transmit_can(unsigned long currentMillis) {
|
|||
|
||||
ZOE_POLL_79B.data.u8[2] = current_poll;
|
||||
|
||||
transmit_can_frame(&ZOE_POLL_79B, can_interface);
|
||||
transmit_can_frame(&ZOE_POLL_79B);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#include "../datalayer/datalayer.h"
|
||||
#include "../datalayer/datalayer_extended.h" //For "More battery info" webpage
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../include.h"
|
||||
|
||||
/* TODO
|
||||
- Add //NVROL Reset
|
||||
|
@ -108,7 +107,7 @@ void RenaultZoeGen2Battery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
|||
case 0x18DAF1DB: // LBC Reply from active polling
|
||||
|
||||
if (rx_frame.data.u8[0] == 0x10) { //First frame of a group
|
||||
transmit_can_frame(&ZOE_POLL_FLOW_CONTROL, can_interface);
|
||||
transmit_can_frame(&ZOE_POLL_FLOW_CONTROL);
|
||||
//frame 2 & 3 contains which PID is sent
|
||||
reply_poll = (rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4];
|
||||
}
|
||||
|
@ -676,7 +675,7 @@ void RenaultZoeGen2Battery::transmit_can(unsigned long currentMillis) {
|
|||
counter_373 = (counter_373 + 1) % 10;
|
||||
*/
|
||||
|
||||
transmit_can_frame(&ZOE_373, can_interface);
|
||||
transmit_can_frame(&ZOE_373);
|
||||
transmit_can_frame_376();
|
||||
}
|
||||
|
||||
|
@ -691,7 +690,7 @@ void RenaultZoeGen2Battery::transmit_can(unsigned long currentMillis) {
|
|||
ZOE_POLL_18DADBF1.data.u8[2] = (uint8_t)((currentpoll & 0xFF00) >> 8);
|
||||
ZOE_POLL_18DADBF1.data.u8[3] = (uint8_t)(currentpoll & 0x00FF);
|
||||
|
||||
transmit_can_frame(&ZOE_POLL_18DADBF1, can_interface);
|
||||
transmit_can_frame(&ZOE_POLL_18DADBF1);
|
||||
}
|
||||
|
||||
if (currentMillis - previousMillis1000 >= INTERVAL_1_S) {
|
||||
|
@ -733,7 +732,7 @@ void RenaultZoeGen2Battery::transmit_can_frame_376(void) {
|
|||
ZOE_376.data.u8[4] = hourSeg;
|
||||
ZOE_376.data.u8[5] = minuteSeg;
|
||||
|
||||
transmit_can_frame(&ZOE_376, can_interface);
|
||||
transmit_can_frame(&ZOE_376);
|
||||
}
|
||||
|
||||
void RenaultZoeGen2Battery::transmit_reset_nvrol_frames(void) {
|
||||
|
@ -742,14 +741,14 @@ void RenaultZoeGen2Battery::transmit_reset_nvrol_frames(void) {
|
|||
startTimeNVROL = millis();
|
||||
// NVROL reset, part 1: send 0x021003AAAAAAAAAA
|
||||
ZOE_POLL_18DADBF1.data = {0x02, 0x10, 0x03, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA};
|
||||
transmit_can_frame(&ZOE_POLL_18DADBF1, can_interface);
|
||||
transmit_can_frame(&ZOE_POLL_18DADBF1);
|
||||
NVROLstateMachine = 1;
|
||||
break;
|
||||
case 1: // wait 100 ms
|
||||
if ((millis() - startTimeNVROL) > INTERVAL_100_MS) {
|
||||
// NVROL reset, part 2: send 0x043101B00900AAAA
|
||||
ZOE_POLL_18DADBF1.data = {0x04, 0x31, 0x01, 0xB0, 0x09, 0x00, 0xAA, 0xAA};
|
||||
transmit_can_frame(&ZOE_POLL_18DADBF1, can_interface);
|
||||
transmit_can_frame(&ZOE_POLL_18DADBF1);
|
||||
startTimeNVROL = millis(); //Reset time start, so we can check time for next step
|
||||
NVROLstateMachine = 2;
|
||||
}
|
||||
|
@ -758,7 +757,7 @@ void RenaultZoeGen2Battery::transmit_reset_nvrol_frames(void) {
|
|||
if ((millis() - startTimeNVROL) > INTERVAL_1_S) {
|
||||
// Enable temporisation before sleep, part 1: send 0x021003AAAAAAAAAA
|
||||
ZOE_POLL_18DADBF1.data = {0x02, 0x10, 0x03, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA};
|
||||
transmit_can_frame(&ZOE_POLL_18DADBF1, can_interface);
|
||||
transmit_can_frame(&ZOE_POLL_18DADBF1);
|
||||
startTimeNVROL = millis(); //Reset time start, so we can check time for next step
|
||||
NVROLstateMachine = 3;
|
||||
}
|
||||
|
@ -767,7 +766,7 @@ void RenaultZoeGen2Battery::transmit_reset_nvrol_frames(void) {
|
|||
if ((millis() - startTimeNVROL) > INTERVAL_100_MS) {
|
||||
// Enable temporisation before sleep, part 2: send 0x042E928101AAAAAA
|
||||
ZOE_POLL_18DADBF1.data = {0x04, 0x2E, 0x92, 0x81, 0x01, 0xAA, 0xAA, 0xAA};
|
||||
transmit_can_frame(&ZOE_POLL_18DADBF1, can_interface);
|
||||
transmit_can_frame(&ZOE_POLL_18DADBF1);
|
||||
// Set data back to init values, we are done with the ZOE_POLL_18DADBF1 frame
|
||||
ZOE_POLL_18DADBF1.data = {0x03, 0x22, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
poll_index = 0;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#ifndef RENAULT_ZOE_GEN2_BATTERY_H
|
||||
#define RENAULT_ZOE_GEN2_BATTERY_H
|
||||
#include "../include.h"
|
||||
|
||||
#include "CanBattery.h"
|
||||
#include "RENAULT-ZOE-GEN2-HTML.h"
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#include "../communication/can/comm_can.h"
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../include.h"
|
||||
|
||||
void RjxzsBms::update_values() {
|
||||
|
||||
|
@ -509,8 +508,8 @@ void RjxzsBms::transmit_can(unsigned long currentMillis) {
|
|||
}
|
||||
|
||||
if (!setup_completed) {
|
||||
transmit_can_frame(&RJXZS_10, can_config.battery); // Communication connected flag
|
||||
transmit_can_frame(&RJXZS_1C, can_config.battery); // CAN OK
|
||||
transmit_can_frame(&RJXZS_10); // Communication connected flag
|
||||
transmit_can_frame(&RJXZS_1C); // CAN OK
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#ifndef RJXZS_BMS_H
|
||||
#define RJXZS_BMS_H
|
||||
#include <Arduino.h>
|
||||
#include "../include.h"
|
||||
|
||||
#include "../system_settings.h"
|
||||
#include "CanBattery.h"
|
||||
|
||||
#ifdef RJXZS_BMS
|
||||
|
@ -11,7 +11,7 @@
|
|||
|
||||
class RjxzsBms : public CanBattery {
|
||||
public:
|
||||
RjxzsBms() : CanBattery(true) {}
|
||||
RjxzsBms() : CanBattery(CAN_Speed::CAN_SPEED_250KBPS) {}
|
||||
|
||||
virtual void setup(void);
|
||||
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
||||
|
|
|
@ -13,7 +13,7 @@ class RS485Battery : public Battery, Transmitter, Rs485Receiver {
|
|||
public:
|
||||
virtual void transmit_rs485(unsigned long currentMillis) = 0;
|
||||
|
||||
String interface_name() { return "RS485"; }
|
||||
const char* interface_name() { return "RS485"; }
|
||||
|
||||
void transmit(unsigned long currentMillis) { transmit_rs485(currentMillis); }
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#include "../communication/can/comm_can.h"
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../include.h"
|
||||
|
||||
/* Credits go to maciek16c for these findings!
|
||||
https://github.com/maciek16c/hyundai-santa-fe-phev-battery
|
||||
|
@ -116,8 +115,7 @@ void SantaFePhevBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
|||
switch (rx_frame.data.u8[0]) {
|
||||
case 0x10: //"PID Header"
|
||||
if (rx_frame.data.u8[4] == poll_data_pid) {
|
||||
transmit_can_frame(&SANTAFE_7E4_ack,
|
||||
can_interface); //Send ack to BMS if the same frame is sent as polled
|
||||
transmit_can_frame(&SANTAFE_7E4_ack); //Send ack to BMS if the same frame is sent as polled
|
||||
}
|
||||
break;
|
||||
case 0x21: //First frame in PID group
|
||||
|
@ -290,9 +288,9 @@ void SantaFePhevBattery::transmit_can(unsigned long currentMillis) {
|
|||
|
||||
SANTAFE_200.data.u8[7] = checksum_200;
|
||||
|
||||
transmit_can_frame(&SANTAFE_200, can_interface);
|
||||
transmit_can_frame(&SANTAFE_2A1, can_interface);
|
||||
transmit_can_frame(&SANTAFE_2F0, can_interface);
|
||||
transmit_can_frame(&SANTAFE_200);
|
||||
transmit_can_frame(&SANTAFE_2A1);
|
||||
transmit_can_frame(&SANTAFE_2F0);
|
||||
|
||||
counter_200++;
|
||||
if (counter_200 > 0xF) {
|
||||
|
@ -304,7 +302,7 @@ void SantaFePhevBattery::transmit_can(unsigned long currentMillis) {
|
|||
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
|
||||
previousMillis100 = currentMillis;
|
||||
|
||||
transmit_can_frame(&SANTAFE_523, can_interface);
|
||||
transmit_can_frame(&SANTAFE_523);
|
||||
}
|
||||
|
||||
// Send 500ms CAN Message
|
||||
|
@ -314,7 +312,7 @@ void SantaFePhevBattery::transmit_can(unsigned long currentMillis) {
|
|||
// PID data is polled after last message sent from battery:
|
||||
poll_data_pid = (poll_data_pid % 5) + 1;
|
||||
SANTAFE_7E4_poll.data.u8[3] = (uint8_t)poll_data_pid;
|
||||
transmit_can_frame(&SANTAFE_7E4_poll, can_interface);
|
||||
transmit_can_frame(&SANTAFE_7E4_poll);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#define SANTA_FE_PHEV_BATTERY_H
|
||||
#include <Arduino.h>
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../include.h"
|
||||
#include "CanBattery.h"
|
||||
|
||||
#ifdef SANTA_FE_PHEV_BATTERY
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#include "SIMPBMS-BATTERY.h"
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../include.h"
|
||||
|
||||
void SimpBmsBattery::update_values() {
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#ifndef SIMPBMS_BATTERY_H
|
||||
#define SIMPBMS_BATTERY_H
|
||||
#include <Arduino.h>
|
||||
#include "../include.h"
|
||||
|
||||
#include "CanBattery.h"
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#include "../communication/can/comm_can.h"
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../include.h"
|
||||
|
||||
void SonoBattery::
|
||||
update_values() { //This function maps all the values fetched via CAN to the correct parameters used for modbus
|
||||
|
@ -120,7 +119,7 @@ void SonoBattery::transmit_can(unsigned long currentMillis) {
|
|||
if (datalayer.battery.status.bms_status == FAULT) {
|
||||
SONO_400.data.u8[0] = 0x14; //Charging DISABLED
|
||||
}
|
||||
transmit_can_frame(&SONO_400, can_config.battery);
|
||||
transmit_can_frame(&SONO_400);
|
||||
}
|
||||
// Send 1000ms CAN Message
|
||||
if (currentMillis - previousMillis1000 >= INTERVAL_1_S) {
|
||||
|
@ -128,14 +127,14 @@ void SonoBattery::transmit_can(unsigned long currentMillis) {
|
|||
|
||||
//Time and date
|
||||
//Let's see if the battery is happy with just getting seconds incrementing
|
||||
SONO_401.data.u8[0] = 2025; //Year
|
||||
SONO_401.data.u8[0] = 25; //Year
|
||||
SONO_401.data.u8[1] = 1; //Month
|
||||
SONO_401.data.u8[2] = 1; //Day
|
||||
SONO_401.data.u8[3] = 12; //Hour
|
||||
SONO_401.data.u8[4] = 15; //Minute
|
||||
SONO_401.data.u8[5] = seconds; //Second
|
||||
seconds = (seconds + 1) % 61;
|
||||
transmit_can_frame(&SONO_401, can_config.battery);
|
||||
transmit_can_frame(&SONO_401);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#ifndef SONO_BATTERY_H
|
||||
#define SONO_BATTERY_H
|
||||
#include <Arduino.h>
|
||||
#include "../include.h"
|
||||
|
||||
#include "CanBattery.h"
|
||||
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
#ifndef _SHUNT_H
|
||||
#define _SHUNT_H
|
||||
|
||||
#include "USER_SETTINGS.h"
|
||||
#include "src/communication/Transmitter.h"
|
||||
#include "src/communication/can/CanReceiver.h"
|
||||
#include "src/communication/can/comm_can.h"
|
||||
#include "src/devboard/safety/safety.h"
|
||||
#include "src/devboard/utils/types.h"
|
||||
|
||||
enum class ShuntType { None = 0, BmwSbox = 1, Highest };
|
||||
|
||||
class CanShunt : public Transmitter, CanReceiver {
|
||||
public:
|
||||
virtual void setup() = 0;
|
||||
|
@ -12,7 +17,7 @@ class CanShunt : public Transmitter, CanReceiver {
|
|||
virtual void handle_incoming_can_frame(CAN_frame rx_frame) = 0;
|
||||
|
||||
// The name of the comm interface the shunt is using.
|
||||
virtual String interface_name() { return getCANInterfaceName(can_config.shunt); }
|
||||
virtual const char* interface_name() { return getCANInterfaceName(can_config.shunt); }
|
||||
|
||||
void transmit(unsigned long currentMillis) {
|
||||
if (allowed_to_send_CAN) {
|
||||
|
@ -26,12 +31,18 @@ class CanShunt : public Transmitter, CanReceiver {
|
|||
CAN_Interface can_interface;
|
||||
|
||||
CanShunt() {
|
||||
can_interface = can_config.battery;
|
||||
can_interface = can_config.shunt;
|
||||
register_transmitter(this);
|
||||
register_can_receiver(this, can_interface);
|
||||
}
|
||||
|
||||
void transmit_can_frame(CAN_frame* frame) { transmit_can_frame_to_interface(frame, can_interface); }
|
||||
};
|
||||
|
||||
extern CanShunt* shunt;
|
||||
|
||||
extern std::vector<ShuntType> supported_shunt_types();
|
||||
extern const char* name_for_shunt_type(ShuntType type);
|
||||
extern ShuntType user_selected_shunt_type;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,8 +1,36 @@
|
|||
#include "../include.h"
|
||||
#include "BMW-SBOX.h"
|
||||
#include "Shunt.h"
|
||||
|
||||
CanShunt* shunt = nullptr;
|
||||
ShuntType user_selected_shunt_type = ShuntType::None;
|
||||
|
||||
#ifdef COMMON_IMAGE
|
||||
#ifdef SELECTED_SHUNT_CLASS
|
||||
#error "Compile time SELECTED_SHUNT_CLASS should not be defined with COMMON_IMAGE"
|
||||
#endif
|
||||
|
||||
void setup_can_shunt() {
|
||||
if (shunt) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (user_selected_shunt_type) {
|
||||
case ShuntType::None:
|
||||
shunt = nullptr;
|
||||
return;
|
||||
case ShuntType::BmwSbox:
|
||||
shunt = new BmwSbox();
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if (shunt) {
|
||||
shunt->setup();
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
void setup_can_shunt() {
|
||||
if (shunt) {
|
||||
return;
|
||||
|
@ -15,3 +43,25 @@ void setup_can_shunt() {
|
|||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
extern std::vector<ShuntType> supported_shunt_types() {
|
||||
std::vector<ShuntType> types;
|
||||
|
||||
for (int i = 0; i < (int)ShuntType::Highest; i++) {
|
||||
types.push_back((ShuntType)i);
|
||||
}
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
extern const char* name_for_shunt_type(ShuntType type) {
|
||||
switch (type) {
|
||||
case ShuntType::None:
|
||||
return "None";
|
||||
case ShuntType::BmwSbox:
|
||||
return BmwSbox::Name;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,7 +1,6 @@
|
|||
#ifndef TESLA_BATTERY_H
|
||||
#define TESLA_BATTERY_H
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../include.h"
|
||||
#include "CanBattery.h"
|
||||
#include "TESLA-HTML.h"
|
||||
|
||||
|
@ -12,6 +11,11 @@
|
|||
#define SELECTED_BATTERY_CLASS TeslaModelSXBattery
|
||||
#endif
|
||||
|
||||
/*NOTE! IMPORTANT INFORMATION!
|
||||
Be sure to scroll down in this file and configure all "GTW_" parameters to suit your battery.
|
||||
Failure to configure these will result in VCFRONT and GTW MIA errors
|
||||
*/
|
||||
|
||||
//#define EXP_TESLA_BMS_DIGITAL_HVIL // Experimental parameter. Forces the transmission of additional CAN frames for experimental purposes, to test potential HVIL issues in 3/Y packs with newer firmware.
|
||||
|
||||
class TeslaBattery : public CanBattery {
|
||||
|
@ -43,7 +47,25 @@ class TeslaBattery : public CanBattery {
|
|||
static const int MAXDISCHARGEPOWERALLOWED =
|
||||
60000; // 60000W we use a define since the value supplied by Tesla is always 0
|
||||
|
||||
/* Do not change the defines below */
|
||||
// Set this to true to try to close contactors/full startup even with no inverter defined/connected
|
||||
bool batteryTestOverride = false;
|
||||
|
||||
// 0x7FF gateway config, "Gen3" vehicles only, not applicable to Gen2 "classic" Model S and Model X
|
||||
//
|
||||
// ** MANUALLY SET FOR NOW **, TODO: change based on USER_SETTINGS.h or preset
|
||||
//
|
||||
static const uint16_t GTW_country =
|
||||
18242; // "US" (USA): 21843, "CA" (Canada): 17217, "GB" (UK & N Ireland): 18242, "DK" (Denmark): 17483, "DE" (Germany): 17477, "AU" (Australia): 16725 [HVP shows errors if EU/US region mismatch for example]
|
||||
// GTW_country is ISO 3166-1 Alpha-2 code, each letter converted to binary (8-bit chunks), those 8-bit chunks concatenated and then converted to decimal
|
||||
static const uint8_t GTW_rightHandDrive =
|
||||
1; // Left: 0, Right: 1 (not sure this matters but there for consistency in emulating the car - make sure correct for GTW_country, e.g. 0 for USA)
|
||||
static const uint8_t GTW_mapRegion =
|
||||
1; // "ME": 8, "NONE": 2, "CN": 3, "TW": 6, "JP": 5, "US": 0, "KR": 7, "AU": 4, "EU": 1 (not sure this matters but there for consistency)
|
||||
static const uint8_t GTW_chassisType =
|
||||
2; // "MODEL_3_CHASSIS": 2, "MODEL_Y_CHASSIS": 3 ("MODEL_S_CHASSIS": 0, "MODEL_X_CHASSIS": 1)
|
||||
static const uint8_t GTW_packEnergy = 1; // "PACK_50_KWH": 0, "PACK_74_KWH": 1, "PACK_62_KWH": 2, "PACK_100_KWH": 3
|
||||
|
||||
/* Do not change anything below this line! */
|
||||
static const int RAMPDOWN_SOC = 900; // 90.0 SOC% to start ramping down from max charge power towards 0 at 100.00%
|
||||
static const int RAMPDOWNPOWERALLOWED = 10000; // What power we ramp down from towards top balancing
|
||||
static const int FLOAT_MAX_POWER_W = 200; // W, what power to allow for top balancing battery
|
||||
|
@ -75,53 +97,391 @@ class TeslaBattery : public CanBattery {
|
|||
unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was sent
|
||||
unsigned long previousMillis500 = 0; // will store last time a 500ms CAN Message was sent
|
||||
unsigned long previousMillis1000 = 0; // will store last time a 1000ms CAN Message was sent
|
||||
bool alternate243 = false;
|
||||
//0x221 545 VCFRONT_LVPowerState: "GenMsgCycleTime" 50ms
|
||||
CAN_frame TESLA_221_1 = {
|
||||
.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x221,
|
||||
.data = {0x41, 0x11, 0x01, 0x00, 0x00, 0x00, 0x20, 0x96}}; //Contactor frame 221 - close contactors
|
||||
CAN_frame TESLA_221_2 = {
|
||||
.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x221,
|
||||
.data = {0x61, 0x15, 0x01, 0x00, 0x00, 0x00, 0x20, 0xBA}}; //Contactor Frame 221 - hv_up_for_drive
|
||||
//0x241 VCFRONT_coolant 100ms
|
||||
|
||||
//UDS session tracker
|
||||
//static bool uds_SessionInProgress = false; // Future use
|
||||
//0x221 VCFRONT_LVPowerState
|
||||
uint8_t muxNumber_TESLA_221 = 0;
|
||||
uint8_t frameCounter_TESLA_221 = 15; // Start at 15 for Mux 0
|
||||
uint8_t vehicleState = 1; // "OFF": 0, "DRIVE": 1, "ACCESSORY": 2, "GOING_DOWN": 3
|
||||
uint16_t powerDownTimer = 180; // Car power down (i.e. contactor open) tracking timer, 3 seconds per sendingState
|
||||
//0x2E1 VCFRONT_status, 6 mux tracker
|
||||
uint8_t muxNumber_TESLA_2E1 = 0;
|
||||
//0x334 UI
|
||||
bool TESLA_334_INITIAL_SENT = false;
|
||||
//0x3A1 VCFRONT_vehicleStatus, 15 frame counter (temporary)
|
||||
uint8_t frameCounter_TESLA_3A1 = 0;
|
||||
//0x3C2 VCLEFT_switchStatus
|
||||
uint8_t muxNumber_TESLA_3C2 = 0;
|
||||
//0x504 TWC_status
|
||||
bool TESLA_504_INITIAL_SENT = false;
|
||||
//0x7FF GTW_carConfig, 5 mux tracker
|
||||
uint8_t muxNumber_TESLA_7FF = 0;
|
||||
//Max percentage charge tracker
|
||||
uint16_t previous_max_percentage = datalayer.battery.settings.max_percentage;
|
||||
|
||||
//0x082 UI_tripPlanning: "cycle_time" 1000ms
|
||||
CAN_frame TESLA_082 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x082,
|
||||
.data = {0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80}};
|
||||
|
||||
//0x102 VCLEFT_doorStatus: "cycle_time" 100ms
|
||||
CAN_frame TESLA_102 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x102,
|
||||
.data = {0x22, 0x33, 0x00, 0x00, 0xC0, 0x38, 0x21, 0x08}};
|
||||
|
||||
//0x103 VCRIGHT_doorStatus: "cycle_time" 100ms
|
||||
CAN_frame TESLA_103 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x103,
|
||||
.data = {0x22, 0x33, 0x00, 0x00, 0x30, 0xF2, 0x20, 0x02}};
|
||||
|
||||
//0x118 DI_systemStatus: "cycle_time" 50ms, DI_systemStatusChecksum/DI_systemStatusCounter generated via generateFrameCounterChecksum
|
||||
CAN_frame TESLA_118 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x118,
|
||||
.data = {0xAB, 0x60, 0x2A, 0x00, 0x00, 0x08, 0x00, 0x00}};
|
||||
|
||||
//0x2A8 CMPD_state: "cycle_time" 100ms, different depending on firmware, semi-manual increment for now
|
||||
CAN_frame TESLA_2A8 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x2A8,
|
||||
.data = {0x02, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x2C}};
|
||||
|
||||
//0x213 UI_cruiseControl: "cycle_time" 500ms, UI_speedLimitTick/UI_cruiseControlCounter - different depending on firmware, semi-manual increment for now
|
||||
CAN_frame TESLA_213 = {.FD = false, .ext_ID = false, .DLC = 2, .ID = 0x213, .data = {0x00, 0x15}};
|
||||
|
||||
//0x221 These frames will/should eventually be migrated to 2 base frames (1 per mux), and then just the relevant bits changed
|
||||
|
||||
//0x221 VCFRONT_LVPowerState "Drive"
|
||||
//VCFRONT_vehiclePowerState VEHICLE_POWER_STATE_DRIVE (Mux0, Counter 15): "cycle_time" 50ms each mux/LVPowerStateIndex, VCFRONT_LVPowerStateChecksum/VCFRONT_LVPowerStateCounter generated via generateMuxFrameCounterChecksum
|
||||
CAN_frame TESLA_221_DRIVE_Mux0 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x221,
|
||||
.data = {0x60, 0x55, 0x55, 0x15, 0x54, 0x51, 0xF1, 0xD8}};
|
||||
|
||||
//0x221 VCFRONT_LVPowerState "Drive"
|
||||
//VCFRONT_vehiclePowerState VEHICLE_POWER_STATE_DRIVE (Mux1, Counter 0): "cycle_time" 50ms each mux/LVPowerStateIndex, VCFRONT_LVPowerStateChecksum/VCFRONT_LVPowerStateCounter generated via generateMuxFrameCounterChecksum
|
||||
CAN_frame TESLA_221_DRIVE_Mux1 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x221,
|
||||
.data = {0x61, 0x05, 0x55, 0x05, 0x00, 0x00, 0x00, 0xE3}};
|
||||
|
||||
//0x221 VCFRONT_LVPowerState "Accessory"
|
||||
//VCFRONT_vehiclePowerState VEHICLE_POWER_STATE_ACCESSORY (Mux0, Counter 15): "cycle_time" 50ms each mux/LVPowerStateIndex, VCFRONT_LVPowerStateChecksum/VCFRONT_LVPowerStateCounter generated via generateMuxFrameCounterChecksum
|
||||
CAN_frame TESLA_221_ACCESSORY_Mux0 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x221,
|
||||
.data = {0x40, 0x55, 0x55, 0x05, 0x54, 0x51, 0xF5, 0xAC}};
|
||||
|
||||
//0x221 VCFRONT_LVPowerState "Accessory"
|
||||
//VCFRONT_vehiclePowerState VEHICLE_POWER_STATE_ACCESSORY (Mux1, Counter 0): "cycle_time" 50ms each mux/LVPowerStateIndex, VCFRONT_LVPowerStateChecksum/VCFRONT_LVPowerStateCounter generated via generateMuxFrameCounterChecksum
|
||||
CAN_frame TESLA_221_ACCESSORY_Mux1 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x221,
|
||||
.data = {0x41, 0x05, 0x55, 0x55, 0x01, 0x00, 0x04, 0x18}};
|
||||
|
||||
//0x221 VCFRONT_LVPowerState "Going Down"
|
||||
//VCFRONT_vehiclePowerState VEHICLE_POWER_STATE_OFF, key parts GOING_DOWN (Mux0, Counter 15): "cycle_time" 50ms each mux/LVPowerStateIndex, VCFRONT_LVPowerStateChecksum/VCFRONT_LVPowerStateCounter generated via generateMuxFrameCounterChecksum
|
||||
CAN_frame TESLA_221_GOING_DOWN_Mux0 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x221,
|
||||
.data = {0x00, 0x89, 0x55, 0x06, 0xA4, 0x51, 0xF1, 0xED}};
|
||||
|
||||
//0x221 VCFRONT_LVPowerState "Going Down"
|
||||
//VCFRONT_vehiclePowerState VEHICLE_POWER_STATE_OFF, key parts GOING_DOWN (Mux1, Counter 0): "cycle_time" 50ms each mux/LVPowerStateIndex, VCFRONT_LVPowerStateChecksum/VCFRONT_LVPowerStateCounter generated via generateMuxFrameCounterChecksum
|
||||
CAN_frame TESLA_221_GOING_DOWN_Mux1 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x221,
|
||||
.data = {0x01, 0x09, 0x55, 0x59, 0x00, 0x00, 0x00, 0xDB}};
|
||||
|
||||
//0x221 VCFRONT_LVPowerState "Off"
|
||||
//VCFRONT_vehiclePowerState VEHICLE_POWER_STATE_OFF, key parts OFF (Mux0, Counter 15): "cycle_time" 50ms each mux/LVPowerStateIndex, VCFRONT_LVPowerStateChecksum/VCFRONT_LVPowerStateCounter generated via generateMuxFrameCounterChecksum
|
||||
CAN_frame TESLA_221_OFF_Mux0 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x221,
|
||||
.data = {0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0xF1, 0x65}};
|
||||
|
||||
//0x221 VCFRONT_LVPowerState "Off"
|
||||
//VCFRONT_vehiclePowerState VEHICLE_POWER_STATE_OFF, key parts OFF (Mux1, Counter 0): "cycle_time" 50ms each mux/LVPowerStateIndex, VCFRONT_LVPowerStateChecksum/VCFRONT_LVPowerStateCounter generated via generateMuxFrameCounterChecksum
|
||||
CAN_frame TESLA_221_OFF_Mux1 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x221,
|
||||
.data = {0x01, 0x01, 0x01, 0x50, 0x00, 0x00, 0x00, 0x76}};
|
||||
|
||||
//0x229 SCCM_rightStalk: "cycle_time" 100ms, SCCM_rightStalkChecksum/SCCM_rightStalkCounter generated via dedicated generateTESLA_229 function for now
|
||||
//CRC seemingly related to AUTOSAR ID array... "autosarDataIds": [124,182,240,47,105,163,221,28,86,144,202,9,67,125,183,241] found in Model 3 firmware
|
||||
CAN_frame TESLA_229 = {.FD = false, .ext_ID = false, .DLC = 3, .ID = 0x229, .data = {0x46, 0x00, 0x00}};
|
||||
|
||||
//0x241 VCFRONT_coolant: "cycle_time" 100ms
|
||||
CAN_frame TESLA_241 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 7,
|
||||
.ID = 0x241,
|
||||
.data = {0x3C, 0x78, 0x2C, 0x0F, 0x1E, 0x5B, 0x00}};
|
||||
//0x242 VCLEFT_LVPowerState 100ms
|
||||
CAN_frame TESLA_242 = {.FD = false, .ext_ID = false, .DLC = 2, .ID = 0x242, .data = {0x10, 0x95}};
|
||||
//0x243 VCRIGHT_hvacStatus 50ms
|
||||
CAN_frame TESLA_243_1 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x243,
|
||||
.data = {0xC9, 0x00, 0xEB, 0xD4, 0x31, 0x32, 0x02, 0x00}};
|
||||
CAN_frame TESLA_243_2 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x243,
|
||||
.data = {0x08, 0x81, 0x42, 0x60, 0x92, 0x2C, 0x0E, 0x09}};
|
||||
//0x129 SteeringAngle 10ms
|
||||
CAN_frame TESLA_129 = {.FD = false,
|
||||
.data = {0x35, 0x34, 0x0C, 0x0F, 0x8F, 0x55, 0x00}};
|
||||
|
||||
//0x2D1 VCFRONT_okToUseHighPower: "cycle_time" 100ms
|
||||
CAN_frame TESLA_2D1 = {.FD = false, .ext_ID = false, .DLC = 2, .ID = 0x2D1, .data = {0xFF, 0x01}};
|
||||
|
||||
//0x2E1, 6 muxes
|
||||
//0x2E1 VCFRONT_status: "cycle_time" 10ms each mux/statusIndex
|
||||
CAN_frame TESLA_2E1_VEHICLE_AND_RAILS = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x2E1,
|
||||
.data = {0x29, 0x0A, 0x00, 0xFF, 0x0F, 0x00, 0x00, 0x00}};
|
||||
|
||||
//{0x29, 0x0A, 0x00, 0xFF, 0x0F, 0x00, 0x00, 0x00} INIT
|
||||
//{0x29, 0x0A, 0x0D, 0xFF, 0x0F, 0x00, 0x00, 0x00} DRIVE
|
||||
//{0x29, 0x0A, 0x09, 0xFF, 0x0F, 0x00, 0x00, 0x00} HV_UP_STANDBY
|
||||
//{0x29, 0x0A, 0x0A, 0xFF, 0x0F, 0x00, 0x00, 0x00} ACCESSORY
|
||||
//{0x29, 0x0A, 0x06, 0xFF, 0x0F, 0x00, 0x00, 0x00} SLEEP_STANDBY
|
||||
|
||||
//0x2E1 VCFRONT_status: "cycle_time" 10ms each mux/statusIndex
|
||||
CAN_frame TESLA_2E1_HOMELINK = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x2E1,
|
||||
.data = {0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00}};
|
||||
|
||||
//0x2E1 VCFRONT_status: "cycle_time" 10ms each mux/statusIndex
|
||||
CAN_frame TESLA_2E1_REFRIGERANT_SYSTEM = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x2E1,
|
||||
.data = {0x03, 0x6D, 0x99, 0x02, 0x1B, 0x57, 0x00, 0x00}};
|
||||
|
||||
//0x2E1 VCFRONT_status: "cycle_time" 10ms each mux/statusIndex
|
||||
CAN_frame TESLA_2E1_LV_BATTERY_DEBUG = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x2E1,
|
||||
.data = {0xFC, 0x1B, 0xD1, 0x99, 0x9A, 0xD8, 0x09, 0x00}};
|
||||
|
||||
//0x2E1 VCFRONT_status: "cycle_time" 10ms each mux/statusIndex
|
||||
CAN_frame TESLA_2E1_MUX_5 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x2E1,
|
||||
.data = {0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
|
||||
//0x2E1 VCFRONT_status: "cycle_time" 10ms each mux/statusIndex
|
||||
CAN_frame TESLA_2E1_BODY_CONTROLS = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x2E1,
|
||||
.data = {0x08, 0x21, 0x04, 0x6E, 0xA0, 0x88, 0x06, 0x04}};
|
||||
|
||||
//0x2E8 EPBR_status: "cycle_time" 100ms
|
||||
CAN_frame TESLA_2E8 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x129,
|
||||
.data = {0x21, 0x24, 0x36, 0x5F, 0x00, 0x20, 0xFF, 0x3F}};
|
||||
//0x612 UDS diagnostic requests - on demand
|
||||
.ID = 0x2E8,
|
||||
.data = {0x02, 0x00, 0x10, 0x00, 0x00, 0x80, 0x00, 0x6C}};
|
||||
|
||||
//0x284 UI_vehicleModes: "cycle_time" 500ms
|
||||
CAN_frame TESLA_284 = {.FD = false, .ext_ID = false, .DLC = 5, .ID = 0x284, .data = {0x10, 0x00, 0x00, 0x00, 0x00}};
|
||||
|
||||
//0x293 UI_chassisControl: "cycle_time" 500ms, UI_chassisControlChecksum/UI_chassisControlCounter generated via generateFrameCounterChecksum
|
||||
CAN_frame TESLA_293 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x293,
|
||||
.data = {0x01, 0x0C, 0x55, 0x91, 0x55, 0x15, 0x01, 0xF3}};
|
||||
|
||||
//0x3A1 VCFRONT_vehicleStatus: "cycle_time" 50ms, VCFRONT_vehicleStatusChecksum/VCFRONT_vehicleStatusCounter eventually need to be generated via generateMuxFrameCounterChecksum
|
||||
//Looks like 2 muxes, counter at bit 52 width 4 and checksum at bit 56 width 8? Need later software Model3_ETH.compact.json signal file or DBC.
|
||||
//Migrated to an array until figured out
|
||||
CAN_frame TESLA_3A1[16] = {
|
||||
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x3A1, .data = {0xC3, 0xFF, 0xFF, 0xFF, 0x3D, 0x00, 0xD0, 0x01}},
|
||||
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x3A1, .data = {0x08, 0x62, 0x0B, 0x18, 0x00, 0x28, 0xE2, 0xCB}},
|
||||
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x3A1, .data = {0xC3, 0xFF, 0xFF, 0xFF, 0x3D, 0x00, 0xF0, 0x21}},
|
||||
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x3A1, .data = {0x08, 0x62, 0x0B, 0x18, 0x00, 0x28, 0x02, 0xEB}},
|
||||
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x3A1, .data = {0xC3, 0xFF, 0xFF, 0xFF, 0x3D, 0x00, 0x10, 0x41}},
|
||||
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x3A1, .data = {0x08, 0x62, 0x0B, 0x18, 0x00, 0x28, 0x22, 0x0B}},
|
||||
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x3A1, .data = {0xC3, 0xFF, 0xFF, 0xFF, 0x3D, 0x00, 0x30, 0x61}},
|
||||
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x3A1, .data = {0x08, 0x62, 0x0B, 0x18, 0x00, 0x28, 0x42, 0x2B}},
|
||||
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x3A1, .data = {0xC3, 0xFF, 0xFF, 0xFF, 0x3D, 0x00, 0x50, 0x81}},
|
||||
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x3A1, .data = {0x08, 0x62, 0x0B, 0x18, 0x00, 0x28, 0x62, 0x4B}},
|
||||
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x3A1, .data = {0xC3, 0xFF, 0xFF, 0xFF, 0x3D, 0x00, 0x70, 0xA1}},
|
||||
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x3A1, .data = {0x08, 0x62, 0x0B, 0x18, 0x00, 0x28, 0x82, 0x6B}},
|
||||
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x3A1, .data = {0xC3, 0xFF, 0xFF, 0xFF, 0x3D, 0x00, 0x90, 0xC1}},
|
||||
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x3A1, .data = {0x08, 0x62, 0x0B, 0x18, 0x00, 0x28, 0xA2, 0x8B}},
|
||||
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x3A1, .data = {0xC3, 0xFF, 0xFF, 0xFF, 0x3D, 0x00, 0xB0, 0xE1}},
|
||||
{.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x3A1, .data = {0x08, 0x62, 0x0B, 0x18, 0x00, 0x28, 0xC2, 0xAB}}};
|
||||
|
||||
//0x313 UI_powertrainControl: "cycle_time" 500ms, UI_powertrainControlChecksum/UI_powertrainControlCounter generated via generateFrameCounterChecksum
|
||||
CAN_frame TESLA_313 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x313,
|
||||
.data = {0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x1B}};
|
||||
|
||||
//0x321 VCFRONT_sensors: "cycle_time" 1000ms
|
||||
CAN_frame TESLA_321 = {
|
||||
.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x321,
|
||||
.data = {0xEC, 0x71, 0xA7, 0x6E, 0x02, 0x6C, 0x00, 0x04}}; // Last 2 bytes are counter and checksum
|
||||
|
||||
//0x333 UI_chargeRequest: "cycle_time" 500ms, UI_chargeTerminationPct value = 900 [bit 16, width 10, scale 0.1, min 25, max 100]
|
||||
CAN_frame TESLA_333 = {.FD = false, .ext_ID = false, .DLC = 5, .ID = 0x333, .data = {0x84, 0x30, 0x84, 0x07, 0x02}};
|
||||
|
||||
//0x334 UI request: "cycle_time" 500ms, initial frame car sends
|
||||
CAN_frame TESLA_334_INITIAL = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x334,
|
||||
.data = {0x3F, 0x3F, 0xC8, 0x00, 0xE2, 0x3F, 0x80, 0x1E}};
|
||||
|
||||
//0x334 UI request: "cycle_time" 500ms, generated via generateFrameCounterChecksum
|
||||
CAN_frame TESLA_334 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x334,
|
||||
.data = {0x3F, 0x3F, 0x00, 0x0F, 0xE2, 0x3F, 0x90, 0x75}};
|
||||
|
||||
//0x3B3 UI_vehicleControl2: "cycle_time" 500ms
|
||||
CAN_frame TESLA_3B3 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x3B3,
|
||||
.data = {0x90, 0x80, 0x05, 0x08, 0x00, 0x00, 0x00, 0x01}};
|
||||
|
||||
//0x39D IBST_status: "cycle_time" 50ms, IBST_statusChecksum/IBST_statusCounter generated via generateFrameCounterChecksum
|
||||
CAN_frame TESLA_39D = {.FD = false, .ext_ID = false, .DLC = 5, .ID = 0x39D, .data = {0xE1, 0x59, 0xC1, 0x27, 0x00}};
|
||||
|
||||
//0x3C2 VCLEFT_switchStatus (Mux0, initial frame car sends): "cycle_time" 50ms, sent once
|
||||
CAN_frame TESLA_3C2_INITIAL = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x3C2,
|
||||
.data = {0x00, 0x55, 0x55, 0x55, 0x00, 0x00, 0x5A, 0x05}};
|
||||
|
||||
//0x3C2 VCLEFT_switchStatus (Mux0): "cycle_time" 50ms each mux/SwitchStatusIndex
|
||||
CAN_frame TESLA_3C2_Mux0 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x3C2,
|
||||
.data = {0x00, 0x55, 0x55, 0x55, 0x00, 0x00, 0x5A, 0x45}};
|
||||
|
||||
//0x3C2 VCLEFT_switchStatus (Mux1): "cycle_time" 50ms each mux/SwitchStatusIndex
|
||||
CAN_frame TESLA_3C2_Mux1 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x3C2,
|
||||
.data = {0x29, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
|
||||
//0x504 Initially sent
|
||||
CAN_frame TESLA_504_INITIAL = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x504,
|
||||
.data = {0x00, 0x1B, 0x06, 0x03, 0x00, 0x01, 0x00, 0x01}};
|
||||
|
||||
//0x55A Unknown but always sent: "cycle_time" 500ms
|
||||
CAN_frame TESLA_55A = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x55A,
|
||||
.data = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
|
||||
//0x7FF GTW_carConfig: "cycle_time" 100ms each mux/carConfigMultiplexer (UK/RHD)
|
||||
CAN_frame TESLA_7FF_Mux1 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x7FF,
|
||||
.data = {0x01, 0x49, 0x42, 0x47, 0x00, 0x03, 0x15, 0x01}};
|
||||
|
||||
//0x7FF GTW_carConfig: "cycle_time" 100ms each mux/carConfigMultiplexer
|
||||
CAN_frame TESLA_7FF_Mux2 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x7FF,
|
||||
.data = {0x02, 0x66, 0x32, 0x24, 0x04, 0x49, 0x95, 0x82}};
|
||||
|
||||
//0x7FF GTW_carConfig: "cycle_time" 100ms each mux/carConfigMultiplexer (EU/Long Range)
|
||||
CAN_frame TESLA_7FF_Mux3 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x7FF,
|
||||
.data = {0x03, 0x01, 0x08, 0x48, 0x01, 0x00, 0x00, 0x12}};
|
||||
|
||||
//0x7FF GTW_carConfig: "cycle_time" 100ms each mux/carConfigMultiplexer
|
||||
CAN_frame TESLA_7FF_Mux4 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x7FF,
|
||||
.data = {0x04, 0x73, 0x03, 0x67, 0x5C, 0x00, 0x00, 0x00}};
|
||||
|
||||
//0x7FF GTW_carConfig: "cycle_time" 100ms each mux/carConfigMultiplexer
|
||||
CAN_frame TESLA_7FF_Mux5 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x7FF,
|
||||
.data = {0x05, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00}};
|
||||
|
||||
//0x7FF GTW_carConfig: "cycle_time" 100ms each mux/carConfigMultiplexer - later firmware has muxes 6 & 7, needed?
|
||||
CAN_frame TESLA_7FF_Mux6 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x7FF,
|
||||
.data = {0x06, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0xD0}};
|
||||
|
||||
//0x7FF GTW_carConfig: "cycle_time" 100ms each mux/carConfigMultiplexer - later firmware has muxes 6 & 7, needed?
|
||||
CAN_frame TESLA_7FF_Mux7 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x7FF,
|
||||
.data = {0x07, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00}};
|
||||
|
||||
//0x722 BMS_bmbKeepAlive: "cycle_time" 100ms, should only be sent when testing packs or diagnosing problems
|
||||
CAN_frame TESLA_722 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x722,
|
||||
.data = {0x02, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}};
|
||||
|
||||
//0x25D CP_status: "cycle_time" 100ms, stops some cpMia errors, but not necessary for standalone pack operation so not used/necessary. Note CP_type for different regions, the below has "IEC_CCS"
|
||||
CAN_frame TESLA_25D = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x25D,
|
||||
.data = {0x37, 0x41, 0x01, 0x16, 0x08, 0x00, 0x00, 0x00}};
|
||||
|
||||
//0x602 BMS UDS diagnostic request: on demand
|
||||
CAN_frame TESLA_602 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x602,
|
||||
.data = {0x02, 0x27, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||
.data = {0x02, 0x27, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00}}; // Define initial UDS request
|
||||
|
||||
//0x610 BMS Query UDS request: on demand
|
||||
CAN_frame TESLA_610 = {.FD = false,
|
||||
.ext_ID = false,
|
||||
.DLC = 8,
|
||||
.ID = 0x610,
|
||||
.data = {0x02, 0x10, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}}; // Define initial UDS request
|
||||
|
||||
uint8_t stateMachineClearIsolationFault = 0xFF;
|
||||
uint8_t stateMachineBMSReset = 0xFF;
|
||||
uint8_t stateMachineBMSQuery = 0xFF;
|
||||
uint16_t sendContactorClosingMessagesStill = 300;
|
||||
uint16_t battery_cell_max_v = 3300;
|
||||
uint16_t battery_cell_min_v = 3300;
|
||||
|
@ -162,8 +522,8 @@ class TeslaBattery : public CanBattery {
|
|||
//0x2d2: 722 BMSVAlimits
|
||||
uint16_t battery_max_discharge_current = 0;
|
||||
uint16_t battery_max_charge_current = 0;
|
||||
uint16_t battery_bms_max_voltage = 0;
|
||||
uint16_t battery_bms_min_voltage = 0;
|
||||
uint16_t BMS_max_voltage = 0;
|
||||
uint16_t BMS_min_voltage = 0;
|
||||
//0x2b4: 692 PCS_dcdcRailStatus
|
||||
uint16_t battery_dcdcHvBusVolt = 0; // Change name from battery_high_voltage to battery_dcdcHvBusVolt
|
||||
uint16_t battery_dcdcLvBusVolt = 0; // Change name from battery_low_voltage to battery_dcdcLvBusVolt
|
||||
|
@ -198,7 +558,7 @@ class TeslaBattery : public CanBattery {
|
|||
uint8_t battery_packContNegativeState = 0;
|
||||
uint8_t battery_packContPositiveState = 0;
|
||||
uint8_t battery_packContactorSetState = 0;
|
||||
bool battery_packCtrsClosingAllowed = false; // Change to bool
|
||||
bool battery_packCtrsClosingBlocked = false; // Change to bool
|
||||
bool battery_pyroTestInProgress = false; // Change to bool
|
||||
bool battery_packCtrsOpenNowRequested = false; // Change to bool
|
||||
bool battery_packCtrsOpenRequested = false; // Change to bool
|
||||
|
@ -216,48 +576,69 @@ class TeslaBattery : public CanBattery {
|
|||
uint8_t battery_fcCtrsRequestStatus = 0;
|
||||
bool battery_fcCtrsResetRequestRequired = false; // Change to bool
|
||||
bool battery_fcLinkAllowedToEnergize = false; // Change to bool
|
||||
//0x72A: BMS_serialNumber
|
||||
uint8_t BMS_SerialNumber[14] = {0}; // Stores raw HEX values for ASCII chars
|
||||
//0x72A: BMS_serialNumber
|
||||
uint8_t battery_serialNumber[14] = {0}; // Stores raw HEX values for ASCII chars
|
||||
bool parsed_battery_serialNumber = false;
|
||||
char* battery_manufactureDate; // YYYY-MM-DD\0
|
||||
//Via UDS
|
||||
uint8_t battery_partNumber[12] = {0}; //stores raw HEX values for ASCII chars
|
||||
bool parsed_battery_partNumber = false;
|
||||
//Via UDS
|
||||
//static uint8_t BMS_partNumber[12] = {0}; //stores raw HEX values for ASCII chars
|
||||
//static bool parsed_BMS_partNumber = false;
|
||||
//0x300: BMS_info
|
||||
uint16_t BMS_info_buildConfigId = 0;
|
||||
uint16_t BMS_info_hardwareId = 0;
|
||||
uint16_t BMS_info_componentId = 0;
|
||||
uint8_t BMS_info_pcbaId = 0;
|
||||
uint8_t BMS_info_assemblyId = 0;
|
||||
uint16_t BMS_info_usageId = 0;
|
||||
uint16_t BMS_info_subUsageId = 0;
|
||||
uint8_t BMS_info_platformType = 0;
|
||||
uint32_t BMS_info_appCrc = 0;
|
||||
uint64_t BMS_info_bootGitHash = 0;
|
||||
uint8_t BMS_info_bootUdsProtoVersion = 0;
|
||||
uint32_t BMS_info_bootCrc = 0;
|
||||
//0x212: 530 BMS_status
|
||||
bool battery_BMS_hvacPowerRequest = false; //Change to bool
|
||||
bool battery_BMS_notEnoughPowerForDrive = false; //Change to bool
|
||||
bool battery_BMS_notEnoughPowerForSupport = false; //Change to bool
|
||||
bool battery_BMS_preconditionAllowed = false; //Change to bool
|
||||
bool battery_BMS_updateAllowed = false; //Change to bool
|
||||
bool battery_BMS_activeHeatingWorthwhile = false; //Change to bool
|
||||
bool battery_BMS_cpMiaOnHvs = false; //Change to bool
|
||||
uint8_t battery_BMS_contactorState = 0;
|
||||
uint8_t battery_BMS_state = 0;
|
||||
uint8_t battery_BMS_hvState = 0;
|
||||
uint16_t battery_BMS_isolationResistance = 0;
|
||||
bool battery_BMS_chargeRequest = false; //Change to bool
|
||||
bool battery_BMS_keepWarmRequest = false; //Change to bool
|
||||
uint8_t battery_BMS_uiChargeStatus = 0;
|
||||
bool battery_BMS_diLimpRequest = false; //Change to bool
|
||||
bool battery_BMS_okToShipByAir = false; //Change to bool
|
||||
bool battery_BMS_okToShipByLand = false; //Change to bool
|
||||
uint32_t battery_BMS_chgPowerAvailable = 0;
|
||||
uint8_t battery_BMS_chargeRetryCount = 0;
|
||||
bool battery_BMS_pcsPwmEnabled = false; //Change to bool
|
||||
bool battery_BMS_ecuLogUploadRequest = false; //Change to bool
|
||||
uint8_t battery_BMS_minPackTemperature = 0;
|
||||
bool BMS_hvacPowerRequest = false; //Change to bool
|
||||
bool BMS_notEnoughPowerForDrive = false; //Change to bool
|
||||
bool BMS_notEnoughPowerForSupport = false; //Change to bool
|
||||
bool BMS_preconditionAllowed = false; //Change to bool
|
||||
bool BMS_updateAllowed = false; //Change to bool
|
||||
bool BMS_activeHeatingWorthwhile = false; //Change to bool
|
||||
bool BMS_cpMiaOnHvs = false; //Change to bool
|
||||
uint8_t BMS_contactorState = 0;
|
||||
uint8_t BMS_state = 0;
|
||||
uint8_t BMS_hvState = 0;
|
||||
uint16_t BMS_isolationResistance = 0;
|
||||
bool BMS_chargeRequest = false; //Change to bool
|
||||
bool BMS_keepWarmRequest = false; //Change to bool
|
||||
uint8_t BMS_uiChargeStatus = 0;
|
||||
bool BMS_diLimpRequest = false; //Change to bool
|
||||
bool BMS_okToShipByAir = false; //Change to bool
|
||||
bool BMS_okToShipByLand = false; //Change to bool
|
||||
uint32_t BMS_chgPowerAvailable = 0;
|
||||
uint8_t BMS_chargeRetryCount = 0;
|
||||
bool BMS_pcsPwmEnabled = false; //Change to bool
|
||||
bool BMS_ecuLogUploadRequest = false; //Change to bool
|
||||
uint8_t BMS_minPackTemperature = 0;
|
||||
// 0x224:548 PCS_dcdcStatus
|
||||
uint8_t battery_PCS_dcdcPrechargeStatus = 0;
|
||||
uint8_t battery_PCS_dcdc12VSupportStatus = 0;
|
||||
uint8_t battery_PCS_dcdcHvBusDischargeStatus = 0;
|
||||
uint16_t battery_PCS_dcdcMainState = 0;
|
||||
uint8_t battery_PCS_dcdcSubState = 0;
|
||||
bool battery_PCS_dcdcFaulted = false; //Change to bool
|
||||
bool battery_PCS_dcdcOutputIsLimited = false; //Change to bool
|
||||
uint32_t battery_PCS_dcdcMaxOutputCurrentAllowed = 0;
|
||||
uint8_t battery_PCS_dcdcPrechargeRtyCnt = 0;
|
||||
uint8_t battery_PCS_dcdc12VSupportRtyCnt = 0;
|
||||
uint8_t battery_PCS_dcdcDischargeRtyCnt = 0;
|
||||
uint8_t battery_PCS_dcdcPwmEnableLine = 0;
|
||||
uint8_t battery_PCS_dcdcSupportingFixedLvTarget = 0;
|
||||
uint8_t battery_PCS_ecuLogUploadRequest = 0;
|
||||
uint8_t battery_PCS_dcdcPrechargeRestartCnt = 0;
|
||||
uint8_t battery_PCS_dcdcInitialPrechargeSubState = 0;
|
||||
uint8_t PCS_dcdcPrechargeStatus = 0;
|
||||
uint8_t PCS_dcdc12VSupportStatus = 0;
|
||||
uint8_t PCS_dcdcHvBusDischargeStatus = 0;
|
||||
uint16_t PCS_dcdcMainState = 0;
|
||||
uint8_t PCS_dcdcSubState = 0;
|
||||
bool PCS_dcdcFaulted = false; //Change to bool
|
||||
bool PCS_dcdcOutputIsLimited = false; //Change to bool
|
||||
uint32_t PCS_dcdcMaxOutputCurrentAllowed = 0;
|
||||
uint8_t PCS_dcdcPrechargeRtyCnt = 0;
|
||||
uint8_t PCS_dcdc12VSupportRtyCnt = 0;
|
||||
uint8_t PCS_dcdcDischargeRtyCnt = 0;
|
||||
uint8_t PCS_dcdcPwmEnableLine = 0;
|
||||
uint8_t PCS_dcdcSupportingFixedLvTarget = 0;
|
||||
uint8_t PCS_ecuLogUploadRequest = 0;
|
||||
uint8_t PCS_dcdcPrechargeRestartCnt = 0;
|
||||
uint8_t PCS_dcdcInitialPrechargeSubState = 0;
|
||||
//0x312: 786 BMS_thermalStatus
|
||||
uint16_t BMS_powerDissipation = 0;
|
||||
uint16_t BMS_flowRequest = 0;
|
||||
|
@ -268,6 +649,22 @@ class TeslaBattery : public CanBattery {
|
|||
uint16_t BMS_packTMax = 0;
|
||||
bool BMS_pcsNoFlowRequest = false;
|
||||
bool BMS_noFlowRequest = false;
|
||||
//0x3C4: PCS_info
|
||||
uint8_t PCS_partNumber[12] = {0}; //stores raw HEX values for ASCII chars
|
||||
bool parsed_PCS_partNumber = false;
|
||||
uint16_t PCS_info_buildConfigId = 0;
|
||||
uint16_t PCS_info_hardwareId = 0;
|
||||
uint16_t PCS_info_componentId = 0;
|
||||
uint8_t PCS_info_pcbaId = 0;
|
||||
uint8_t PCS_info_assemblyId = 0;
|
||||
uint16_t PCS_info_usageId = 0;
|
||||
uint16_t PCS_info_subUsageId = 0;
|
||||
uint8_t PCS_info_platformType = 0;
|
||||
uint32_t PCS_info_appCrc = 0;
|
||||
uint32_t PCS_info_cpu2AppCrc = 0;
|
||||
uint64_t PCS_info_bootGitHash = 0;
|
||||
uint8_t PCS_info_bootUdsProtoVersion = 0;
|
||||
uint32_t PCS_info_bootCrc = 0;
|
||||
//0x2A4; 676 PCS_thermalStatus
|
||||
int16_t PCS_chgPhATemp = 0;
|
||||
int16_t PCS_chgPhBTemp = 0;
|
||||
|
@ -330,6 +727,18 @@ class TeslaBattery : public CanBattery {
|
|||
bool HVP_shuntRefVoltageMismatch = false; //Change to bool
|
||||
bool HVP_shuntThermistorMia = false; //Change to bool
|
||||
bool HVP_shuntHwMia = false; //Change to bool
|
||||
uint16_t HVP_info_buildConfigId = 0;
|
||||
uint16_t HVP_info_hardwareId = 0;
|
||||
uint16_t HVP_info_componentId = 0;
|
||||
uint8_t HVP_info_pcbaId = 0;
|
||||
uint8_t HVP_info_assemblyId = 0;
|
||||
uint16_t HVP_info_usageId = 0;
|
||||
uint16_t HVP_info_subUsageId = 0;
|
||||
uint8_t HVP_info_platformType = 0;
|
||||
uint32_t HVP_info_appCrc = 0;
|
||||
uint64_t HVP_info_bootGitHash = 0;
|
||||
uint8_t HVP_info_bootUdsProtoVersion = 0;
|
||||
uint32_t HVP_info_bootCrc = 0;
|
||||
int16_t HVP_dcLinkVoltage = 0;
|
||||
int16_t HVP_packVoltage = 0;
|
||||
int16_t HVP_fcLinkVoltage = 0;
|
||||
|
@ -411,104 +820,105 @@ class TeslaBattery : public CanBattery {
|
|||
bool battery_fcCtrCloseFailed = false;
|
||||
bool battery_shuntThermistorMia = false;
|
||||
//0x320: 800 BMS_alertMatrix
|
||||
uint8_t battery_BMS_matrixIndex = 0; // Changed to bool
|
||||
bool battery_BMS_a061_robinBrickOverVoltage = false;
|
||||
bool battery_BMS_a062_SW_BrickV_Imbalance = false;
|
||||
bool battery_BMS_a063_SW_ChargePort_Fault = false;
|
||||
bool battery_BMS_a064_SW_SOC_Imbalance = false;
|
||||
bool battery_BMS_a127_SW_shunt_SNA = false;
|
||||
bool battery_BMS_a128_SW_shunt_MIA = false;
|
||||
bool battery_BMS_a069_SW_Low_Power = false;
|
||||
bool battery_BMS_a130_IO_CAN_Error = false;
|
||||
bool battery_BMS_a071_SW_SM_TransCon_Not_Met = false;
|
||||
bool battery_BMS_a132_HW_BMB_OTP_Uncorrctbl = false;
|
||||
bool battery_BMS_a134_SW_Delayed_Ctr_Off = false;
|
||||
bool battery_BMS_a075_SW_Chg_Disable_Failure = false;
|
||||
bool battery_BMS_a076_SW_Dch_While_Charging = false;
|
||||
bool battery_BMS_a017_SW_Brick_OV = false;
|
||||
bool battery_BMS_a018_SW_Brick_UV = false;
|
||||
bool battery_BMS_a019_SW_Module_OT = false;
|
||||
bool battery_BMS_a021_SW_Dr_Limits_Regulation = false;
|
||||
bool battery_BMS_a022_SW_Over_Current = false;
|
||||
bool battery_BMS_a023_SW_Stack_OV = false;
|
||||
bool battery_BMS_a024_SW_Islanded_Brick = false;
|
||||
bool battery_BMS_a025_SW_PwrBalance_Anomaly = false;
|
||||
bool battery_BMS_a026_SW_HFCurrent_Anomaly = false;
|
||||
bool battery_BMS_a087_SW_Feim_Test_Blocked = false;
|
||||
bool battery_BMS_a088_SW_VcFront_MIA_InDrive = false;
|
||||
bool battery_BMS_a089_SW_VcFront_MIA = false;
|
||||
bool battery_BMS_a090_SW_Gateway_MIA = false;
|
||||
bool battery_BMS_a091_SW_ChargePort_MIA = false;
|
||||
bool battery_BMS_a092_SW_ChargePort_Mia_On_Hv = false;
|
||||
bool battery_BMS_a034_SW_Passive_Isolation = false;
|
||||
bool battery_BMS_a035_SW_Isolation = false;
|
||||
bool battery_BMS_a036_SW_HvpHvilFault = false;
|
||||
bool battery_BMS_a037_SW_Flood_Port_Open = false;
|
||||
bool battery_BMS_a158_SW_HVP_HVI_Comms = false;
|
||||
bool battery_BMS_a039_SW_DC_Link_Over_Voltage = false;
|
||||
bool battery_BMS_a041_SW_Power_On_Reset = false;
|
||||
bool battery_BMS_a042_SW_MPU_Error = false;
|
||||
bool battery_BMS_a043_SW_Watch_Dog_Reset = false;
|
||||
bool battery_BMS_a044_SW_Assertion = false;
|
||||
bool battery_BMS_a045_SW_Exception = false;
|
||||
bool battery_BMS_a046_SW_Task_Stack_Usage = false;
|
||||
bool battery_BMS_a047_SW_Task_Stack_Overflow = false;
|
||||
bool battery_BMS_a048_SW_Log_Upload_Request = false;
|
||||
bool battery_BMS_a169_SW_FC_Pack_Weld = false;
|
||||
bool battery_BMS_a050_SW_Brick_Voltage_MIA = false;
|
||||
bool battery_BMS_a051_SW_HVC_Vref_Bad = false;
|
||||
bool battery_BMS_a052_SW_PCS_MIA = false;
|
||||
bool battery_BMS_a053_SW_ThermalModel_Sanity = false;
|
||||
bool battery_BMS_a054_SW_Ver_Supply_Fault = false;
|
||||
bool battery_BMS_a176_SW_GracefulPowerOff = false;
|
||||
bool battery_BMS_a059_SW_Pack_Voltage_Sensing = false;
|
||||
bool battery_BMS_a060_SW_Leakage_Test_Failure = false;
|
||||
bool battery_BMS_a077_SW_Charger_Regulation = false;
|
||||
bool battery_BMS_a081_SW_Ctr_Close_Blocked = false;
|
||||
bool battery_BMS_a082_SW_Ctr_Force_Open = false;
|
||||
bool battery_BMS_a083_SW_Ctr_Close_Failure = false;
|
||||
bool battery_BMS_a084_SW_Sleep_Wake_Aborted = false;
|
||||
bool battery_BMS_a094_SW_Drive_Inverter_MIA = false;
|
||||
bool battery_BMS_a099_SW_BMB_Communication = false;
|
||||
bool battery_BMS_a105_SW_One_Module_Tsense = false;
|
||||
bool battery_BMS_a106_SW_All_Module_Tsense = false;
|
||||
bool battery_BMS_a107_SW_Stack_Voltage_MIA = false;
|
||||
bool battery_BMS_a121_SW_NVRAM_Config_Error = false;
|
||||
bool battery_BMS_a122_SW_BMS_Therm_Irrational = false;
|
||||
bool battery_BMS_a123_SW_Internal_Isolation = false;
|
||||
bool battery_BMS_a129_SW_VSH_Failure = false;
|
||||
bool battery_BMS_a131_Bleed_FET_Failure = false;
|
||||
bool battery_BMS_a136_SW_Module_OT_Warning = false;
|
||||
bool battery_BMS_a137_SW_Brick_UV_Warning = false;
|
||||
bool battery_BMS_a138_SW_Brick_OV_Warning = false;
|
||||
bool battery_BMS_a139_SW_DC_Link_V_Irrational = false;
|
||||
bool battery_BMS_a141_SW_BMB_Status_Warning = false;
|
||||
bool battery_BMS_a144_Hvp_Config_Mismatch = false;
|
||||
bool battery_BMS_a145_SW_SOC_Change = false;
|
||||
bool battery_BMS_a146_SW_Brick_Overdischarged = false;
|
||||
bool battery_BMS_a149_SW_Missing_Config_Block = false;
|
||||
bool battery_BMS_a151_SW_external_isolation = false;
|
||||
bool battery_BMS_a156_SW_BMB_Vref_bad = false;
|
||||
bool battery_BMS_a157_SW_HVP_HVS_Comms = false;
|
||||
bool battery_BMS_a159_SW_HVP_ECU_Error = false;
|
||||
bool battery_BMS_a161_SW_DI_Open_Request = false;
|
||||
bool battery_BMS_a162_SW_No_Power_For_Support = false;
|
||||
bool battery_BMS_a163_SW_Contactor_Mismatch = false;
|
||||
bool battery_BMS_a164_SW_Uncontrolled_Regen = false;
|
||||
bool battery_BMS_a165_SW_Pack_Partial_Weld = false;
|
||||
bool battery_BMS_a166_SW_Pack_Full_Weld = false;
|
||||
bool battery_BMS_a167_SW_FC_Partial_Weld = false;
|
||||
bool battery_BMS_a168_SW_FC_Full_Weld = false;
|
||||
bool battery_BMS_a170_SW_Limp_Mode = false;
|
||||
bool battery_BMS_a171_SW_Stack_Voltage_Sense = false;
|
||||
bool battery_BMS_a174_SW_Charge_Failure = false;
|
||||
bool battery_BMS_a179_SW_Hvp_12V_Fault = false;
|
||||
bool battery_BMS_a180_SW_ECU_reset_blocked = false;
|
||||
uint8_t BMS_matrixIndex = 0; // Changed to bool
|
||||
bool BMS_a061_robinBrickOverVoltage = false;
|
||||
bool BMS_a062_SW_BrickV_Imbalance = false;
|
||||
bool BMS_a063_SW_ChargePort_Fault = false;
|
||||
bool BMS_a064_SW_SOC_Imbalance = false;
|
||||
bool BMS_a127_SW_shunt_SNA = false;
|
||||
bool BMS_a128_SW_shunt_MIA = false;
|
||||
bool BMS_a069_SW_Low_Power = false;
|
||||
bool BMS_a130_IO_CAN_Error = false;
|
||||
bool BMS_a071_SW_SM_TransCon_Not_Met = false;
|
||||
bool BMS_a132_HW_BMB_OTP_Uncorrctbl = false;
|
||||
bool BMS_a134_SW_Delayed_Ctr_Off = false;
|
||||
bool BMS_a075_SW_Chg_Disable_Failure = false;
|
||||
bool BMS_a076_SW_Dch_While_Charging = false;
|
||||
bool BMS_a017_SW_Brick_OV = false;
|
||||
bool BMS_a018_SW_Brick_UV = false;
|
||||
bool BMS_a019_SW_Module_OT = false;
|
||||
bool BMS_a021_SW_Dr_Limits_Regulation = false;
|
||||
bool BMS_a022_SW_Over_Current = false;
|
||||
bool BMS_a023_SW_Stack_OV = false;
|
||||
bool BMS_a024_SW_Islanded_Brick = false;
|
||||
bool BMS_a025_SW_PwrBalance_Anomaly = false;
|
||||
bool BMS_a026_SW_HFCurrent_Anomaly = false;
|
||||
bool BMS_a087_SW_Feim_Test_Blocked = false;
|
||||
bool BMS_a088_SW_VcFront_MIA_InDrive = false;
|
||||
bool BMS_a089_SW_VcFront_MIA = false;
|
||||
bool BMS_a090_SW_Gateway_MIA = false;
|
||||
bool BMS_a091_SW_ChargePort_MIA = false;
|
||||
bool BMS_a092_SW_ChargePort_Mia_On_Hv = false;
|
||||
bool BMS_a034_SW_Passive_Isolation = false;
|
||||
bool BMS_a035_SW_Isolation = false;
|
||||
bool BMS_a036_SW_HvpHvilFault = false;
|
||||
bool BMS_a037_SW_Flood_Port_Open = false;
|
||||
bool BMS_a158_SW_HVP_HVI_Comms = false;
|
||||
bool BMS_a039_SW_DC_Link_Over_Voltage = false;
|
||||
bool BMS_a041_SW_Power_On_Reset = false;
|
||||
bool BMS_a042_SW_MPU_Error = false;
|
||||
bool BMS_a043_SW_Watch_Dog_Reset = false;
|
||||
bool BMS_a044_SW_Assertion = false;
|
||||
bool BMS_a045_SW_Exception = false;
|
||||
bool BMS_a046_SW_Task_Stack_Usage = false;
|
||||
bool BMS_a047_SW_Task_Stack_Overflow = false;
|
||||
bool BMS_a048_SW_Log_Upload_Request = false;
|
||||
bool BMS_a169_SW_FC_Pack_Weld = false;
|
||||
bool BMS_a050_SW_Brick_Voltage_MIA = false;
|
||||
bool BMS_a051_SW_HVC_Vref_Bad = false;
|
||||
bool BMS_a052_SW_PCS_MIA = false;
|
||||
bool BMS_a053_SW_ThermalModel_Sanity = false;
|
||||
bool BMS_a054_SW_Ver_Supply_Fault = false;
|
||||
bool BMS_a176_SW_GracefulPowerOff = false;
|
||||
bool BMS_a059_SW_Pack_Voltage_Sensing = false;
|
||||
bool BMS_a060_SW_Leakage_Test_Failure = false;
|
||||
bool BMS_a077_SW_Charger_Regulation = false;
|
||||
bool BMS_a081_SW_Ctr_Close_Blocked = false;
|
||||
bool BMS_a082_SW_Ctr_Force_Open = false;
|
||||
bool BMS_a083_SW_Ctr_Close_Failure = false;
|
||||
bool BMS_a084_SW_Sleep_Wake_Aborted = false;
|
||||
bool BMS_a094_SW_Drive_Inverter_MIA = false;
|
||||
bool BMS_a099_SW_BMB_Communication = false;
|
||||
bool BMS_a105_SW_One_Module_Tsense = false;
|
||||
bool BMS_a106_SW_All_Module_Tsense = false;
|
||||
bool BMS_a107_SW_Stack_Voltage_MIA = false;
|
||||
bool BMS_a121_SW_NVRAM_Config_Error = false;
|
||||
bool BMS_a122_SW_BMS_Therm_Irrational = false;
|
||||
bool BMS_a123_SW_Internal_Isolation = false;
|
||||
bool BMS_a129_SW_VSH_Failure = false;
|
||||
bool BMS_a131_Bleed_FET_Failure = false;
|
||||
bool BMS_a136_SW_Module_OT_Warning = false;
|
||||
bool BMS_a137_SW_Brick_UV_Warning = false;
|
||||
bool BMS_a138_SW_Brick_OV_Warning = false;
|
||||
bool BMS_a139_SW_DC_Link_V_Irrational = false;
|
||||
bool BMS_a141_SW_BMB_Status_Warning = false;
|
||||
bool BMS_a144_Hvp_Config_Mismatch = false;
|
||||
bool BMS_a145_SW_SOC_Change = false;
|
||||
bool BMS_a146_SW_Brick_Overdischarged = false;
|
||||
bool BMS_a149_SW_Missing_Config_Block = false;
|
||||
bool BMS_a151_SW_external_isolation = false;
|
||||
bool BMS_a156_SW_BMB_Vref_bad = false;
|
||||
bool BMS_a157_SW_HVP_HVS_Comms = false;
|
||||
bool BMS_a159_SW_HVP_ECU_Error = false;
|
||||
bool BMS_a161_SW_DI_Open_Request = false;
|
||||
bool BMS_a162_SW_No_Power_For_Support = false;
|
||||
bool BMS_a163_SW_Contactor_Mismatch = false;
|
||||
bool BMS_a164_SW_Uncontrolled_Regen = false;
|
||||
bool BMS_a165_SW_Pack_Partial_Weld = false;
|
||||
bool BMS_a166_SW_Pack_Full_Weld = false;
|
||||
bool BMS_a167_SW_FC_Partial_Weld = false;
|
||||
bool BMS_a168_SW_FC_Full_Weld = false;
|
||||
bool BMS_a170_SW_Limp_Mode = false;
|
||||
bool BMS_a171_SW_Stack_Voltage_Sense = false;
|
||||
bool BMS_a174_SW_Charge_Failure = false;
|
||||
bool BMS_a179_SW_Hvp_12V_Fault = false;
|
||||
bool BMS_a180_SW_ECU_reset_blocked = false;
|
||||
};
|
||||
|
||||
class TeslaModel3YBattery : public TeslaBattery {
|
||||
public:
|
||||
TeslaModel3YBattery() {
|
||||
TeslaModel3YBattery(battery_chemistry_enum chemistry) {
|
||||
datalayer.battery.info.chemistry = chemistry;
|
||||
#ifdef EXP_TESLA_BMS_DIGITAL_HVIL
|
||||
operate_contactors = true;
|
||||
#endif
|
||||
|
|
|
@ -39,8 +39,8 @@ class TeslaHtmlRenderer : public BatteryHtmlRenderer {
|
|||
float packMass = static_cast<float>(datalayer_extended.tesla.battery_packMass);
|
||||
float platformMaxBusVoltage =
|
||||
static_cast<float>(datalayer_extended.tesla.battery_platformMaxBusVoltage) * 0.1 + 375;
|
||||
float bms_min_voltage = static_cast<float>(datalayer_extended.tesla.battery_bms_min_voltage) * 0.01 * 2;
|
||||
float bms_max_voltage = static_cast<float>(datalayer_extended.tesla.battery_bms_max_voltage) * 0.01 * 2;
|
||||
float bms_min_voltage = static_cast<float>(datalayer_extended.tesla.BMS_min_voltage) * 0.01 * 2;
|
||||
float bms_max_voltage = static_cast<float>(datalayer_extended.tesla.BMS_max_voltage) * 0.01 * 2;
|
||||
float max_charge_current = static_cast<float>(datalayer_extended.tesla.battery_max_charge_current);
|
||||
float max_discharge_current = static_cast<float>(datalayer_extended.tesla.battery_max_discharge_current);
|
||||
float soc_ave = static_cast<float>(datalayer_extended.tesla.battery_soc_ave) * 0.1;
|
||||
|
@ -51,9 +51,9 @@ class TeslaHtmlRenderer : public BatteryHtmlRenderer {
|
|||
float BrickVoltageMin = static_cast<float>(datalayer_extended.tesla.battery_BrickVoltageMin) * 0.002;
|
||||
float BrickModelTMax = static_cast<float>(datalayer_extended.tesla.battery_BrickModelTMax) * 0.5 - 40;
|
||||
float BrickModelTMin = static_cast<float>(datalayer_extended.tesla.battery_BrickModelTMin) * 0.5 - 40;
|
||||
float isolationResistance = static_cast<float>(datalayer_extended.tesla.battery_BMS_isolationResistance) * 10;
|
||||
float isolationResistance = static_cast<float>(datalayer_extended.tesla.BMS_isolationResistance) * 10;
|
||||
float PCS_dcdcMaxOutputCurrentAllowed =
|
||||
static_cast<float>(datalayer_extended.tesla.battery_PCS_dcdcMaxOutputCurrentAllowed) * 0.1;
|
||||
static_cast<float>(datalayer_extended.tesla.PCS_dcdcMaxOutputCurrentAllowed) * 0.1;
|
||||
float PCS_dcdcTemp = static_cast<float>(datalayer_extended.tesla.PCS_dcdcTemp) * 0.1 + 40;
|
||||
float PCS_ambientTemp = static_cast<float>(datalayer_extended.tesla.PCS_ambientTemp) * 0.1 + 40;
|
||||
float PCS_chgPhATemp = static_cast<float>(datalayer_extended.tesla.PCS_chgPhATemp) * 0.1 + 40;
|
||||
|
@ -128,7 +128,7 @@ class TeslaHtmlRenderer : public BatteryHtmlRenderer {
|
|||
static const char* contactorText[] = {"UNKNOWN(0)", "OPEN", "CLOSING", "BLOCKED", "OPENING",
|
||||
"CLOSED", "UNKNOWN(6)", "WELDED", "POS_CL", "NEG_CL",
|
||||
"UNKNOWN(10)", "UNKNOWN(11)", "UNKNOWN(12)"};
|
||||
static const char* hvilStatusState[] = {"NOT Ok",
|
||||
static const char* hvilStatusState[] = {"UNKNOWN or CONTACTORS OPEN",
|
||||
"STATUS_OK",
|
||||
"CURRENT_SOURCE_FAULT",
|
||||
"INTERNAL_OPEN_FAULT",
|
||||
|
@ -183,15 +183,46 @@ class TeslaHtmlRenderer : public BatteryHtmlRenderer {
|
|||
static const char* noYes[] = {"No", "Yes"};
|
||||
static const char* Fault[] = {"NOT_ACTIVE", "ACTIVE"};
|
||||
|
||||
//0x20A 522 HVP_contatorState
|
||||
content += "<h4>Contactor Status: " + String(contactorText[datalayer_extended.tesla.status_contactor]) + "</h4>";
|
||||
content += "<h4>HVIL: " + String(hvilStatusState[datalayer_extended.tesla.hvil_status]) + "</h4>";
|
||||
//Main battery info
|
||||
char readableBatterySerialNumber[15]; // One extra space for null terminator
|
||||
memcpy(readableBatterySerialNumber, datalayer_extended.tesla.battery_serialNumber,
|
||||
sizeof(datalayer_extended.tesla.battery_serialNumber));
|
||||
readableBatterySerialNumber[14] = '\0'; // Null terminate the string
|
||||
content += "<h4>Battery Serial Number: " + String(readableBatterySerialNumber) + "</h4>";
|
||||
char readableBatteryPartNumber[13]; // One extra space for null terminator
|
||||
memcpy(readableBatteryPartNumber, datalayer_extended.tesla.battery_partNumber,
|
||||
sizeof(datalayer_extended.tesla.battery_partNumber));
|
||||
readableBatteryPartNumber[12] = '\0'; // Null terminate the string
|
||||
content += "<h4>Battery Part Number: " + String(readableBatteryPartNumber) + "</h4>";
|
||||
//0x3C4 PCS_info
|
||||
char readablePCSPartNumber[13]; // One extra space for null terminator
|
||||
memcpy(readablePCSPartNumber, datalayer_extended.tesla.PCS_partNumber,
|
||||
sizeof(datalayer_extended.tesla.PCS_partNumber));
|
||||
readablePCSPartNumber[13] = '\0'; // Null terminate the string
|
||||
content += "<h4>PCS Part Number: " + String(readablePCSPartNumber) + "</h4>";
|
||||
content += "<h4>Battery Manufacture Date: " + String(datalayer_extended.tesla.battery_manufactureDate) + "</h4>";
|
||||
content += "<h4>Battery Pack Mass: " + String(packMass) + " KG</h4>";
|
||||
//0x3D2 978 BMS_kwhCounter
|
||||
content += "<h4>Battery Total Discharge: " + String(total_discharge) + " kWh</h4>";
|
||||
content += "<h4>Battery Total Charge: " + String(total_charge) + " kWh</h4>";
|
||||
//0x20A 522 HVP_contactorState + HVIL
|
||||
//content += "<h4>HVIL Fault: " + String(noYes[datalayer_extended.tesla.BMS_hvilFault]) + "</h4>";
|
||||
content += "<h4>HVIL Status: " + String(hvilStatusState[datalayer_extended.tesla.hvil_status]) + "</h4>";
|
||||
content +=
|
||||
"<h4>Negative contactor: " + String(contactorState[datalayer_extended.tesla.packContNegativeState]) + "</h4>";
|
||||
"<h4>HVP Contactor State: " + String(contactorText[datalayer_extended.tesla.packContactorSetState]) + "</h4>";
|
||||
content +=
|
||||
"<h4>Positive contactor: " + String(contactorState[datalayer_extended.tesla.packContPositiveState]) + "</h4>";
|
||||
content += "<h4>Closing allowed?: " + String(noYes[datalayer_extended.tesla.packCtrsClosingAllowed]) + "</h4>";
|
||||
content += "<h4>Pyrotest in Progress: " + String(noYes[datalayer_extended.tesla.pyroTestInProgress]) + "</h4>";
|
||||
"<h4>BMS Contactor State: " + String(BMS_contactorState[datalayer_extended.tesla.BMS_contactorState]) + "</h4>";
|
||||
content +=
|
||||
"<h4>Negative Contactor: " + String(contactorState[datalayer_extended.tesla.packContNegativeState]) + "</h4>";
|
||||
content +=
|
||||
"<h4>Positive Contactor: " + String(contactorState[datalayer_extended.tesla.packContPositiveState]) + "</h4>";
|
||||
if (datalayer_extended.tesla.packContactorSetState == 5) { //Closed
|
||||
content += "<h4>Closing blocked: " + String(noYes[datalayer_extended.tesla.packCtrsClosingBlocked]) +
|
||||
" (already CLOSED)</h4>";
|
||||
} else {
|
||||
content += "<h4>Closing blocked: " + String(noYes[datalayer_extended.tesla.packCtrsClosingBlocked]) + "</h4>";
|
||||
}
|
||||
content += "<h4>Pyrotest in progress: " + String(noYes[datalayer_extended.tesla.pyroTestInProgress]) + "</h4>";
|
||||
content += "<h4>Contactors Open Now Requested: " +
|
||||
String(noYes[datalayer_extended.tesla.battery_packCtrsOpenNowRequested]) + "</h4>";
|
||||
content +=
|
||||
|
@ -204,21 +235,16 @@ class TeslaHtmlRenderer : public BatteryHtmlRenderer {
|
|||
content +=
|
||||
"<h4>DC Link Allowed to Energize: " + String(noYes[datalayer_extended.tesla.battery_dcLinkAllowedToEnergize]) +
|
||||
"</h4>";
|
||||
char readableSerialNumber[15]; // One extra space for null terminator
|
||||
memcpy(readableSerialNumber, datalayer_extended.tesla.BMS_SerialNumber,
|
||||
sizeof(datalayer_extended.tesla.BMS_SerialNumber));
|
||||
readableSerialNumber[14] = '\0'; // Null terminate the string
|
||||
content += "<h4>BMS Serial number: " + String(readableSerialNumber) + "</h4>";
|
||||
// Comment what data you would like to display, order can be changed.
|
||||
//0x352 850 BMS_energyStatus
|
||||
if (datalayer_extended.tesla.BMS352_mux == false) {
|
||||
content += "<h3>BMS 0x352 w/o mux</h3>"; //if using older BMS <2021 and comment 0x352 without MUX
|
||||
content += "<h4>Calculated SOH: " + String(nominal_full_pack_energy * 100 / beginning_of_life) + "</h4>";
|
||||
content += "<h4>Nominal Full Pack Energy: " + String(nominal_full_pack_energy) + " KWh</h4>";
|
||||
content += "<h4>Nominal Energy Remaining: " + String(nominal_energy_remaining) + " KWh</h4>";
|
||||
content += "<h4>Ideal Energy Remaining: " + String(ideal_energy_remaining) + " KWh</h4>";
|
||||
content += "<h4>Energy to Charge Complete: " + String(energy_to_charge_complete) + " KWh</h4>";
|
||||
content += "<h4>Energy Buffer: " + String(energy_buffer) + " KWh</h4>";
|
||||
content += "<h4>Nominal Full Pack Energy: " + String(nominal_full_pack_energy) + " kWh</h4>";
|
||||
content += "<h4>Nominal Energy Remaining: " + String(nominal_energy_remaining) + " kWh</h4>";
|
||||
content += "<h4>Ideal Energy Remaining: " + String(ideal_energy_remaining) + " kWh</h4>";
|
||||
content += "<h4>Energy to Charge Complete: " + String(energy_to_charge_complete) + " kWh</h4>";
|
||||
content += "<h4>Energy Buffer: " + String(energy_buffer) + " kWh</h4>";
|
||||
content += "<h4>Full Charge Complete: " + String(noYes[datalayer_extended.tesla.battery_full_charge_complete]) +
|
||||
"</h4>"; //bool
|
||||
}
|
||||
|
@ -226,19 +252,26 @@ class TeslaHtmlRenderer : public BatteryHtmlRenderer {
|
|||
if (datalayer_extended.tesla.BMS352_mux == true) {
|
||||
content += "<h3>BMS 0x352 w/ mux</h3>"; //if using newer BMS >2021 and comment 0x352 with MUX
|
||||
content += "<h4>Calculated SOH: " + String(nominal_full_pack_energy_m0 * 100 / beginning_of_life) + "</h4>";
|
||||
content += "<h4>Nominal Full Pack Energy: " + String(nominal_full_pack_energy_m0) + " KWh</h4>";
|
||||
content += "<h4>Nominal Energy Remaining: " + String(nominal_energy_remaining_m0) + " KWh</h4>";
|
||||
content += "<h4>Ideal Energy Remaining: " + String(ideal_energy_remaining_m0) + " KWh</h4>";
|
||||
content += "<h4>Energy to Charge Complete: " + String(energy_to_charge_complete_m1) + " KWh</h4>";
|
||||
content += "<h4>Energy Buffer: " + String(energy_buffer_m1) + " KWh</h4>";
|
||||
content += "<h4>Expected Energy Remaining: " + String(expected_energy_remaining_m1) + " KWh</h4>";
|
||||
content += "<h4>Nominal Full Pack Energy: " + String(nominal_full_pack_energy_m0) + " kWh</h4>";
|
||||
content += "<h4>Nominal Energy Remaining: " + String(nominal_energy_remaining_m0) + " kWh</h4>";
|
||||
content += "<h4>Ideal Energy Remaining: " + String(ideal_energy_remaining_m0) + " kWh</h4>";
|
||||
content += "<h4>Energy to Charge Complete: " + String(energy_to_charge_complete_m1) + " kWh</h4>";
|
||||
content += "<h4>Energy Buffer: " + String(energy_buffer_m1) + " kWh</h4>";
|
||||
content += "<h4>Expected Energy Remaining: " + String(expected_energy_remaining_m1) + " kWh</h4>";
|
||||
content += "<h4>Fully Charged: " + String(noYes[datalayer_extended.tesla.battery_fully_charged]) + "</h4>";
|
||||
}
|
||||
//0x3D2 978 BMS_kwhCounter
|
||||
content += "<h4>Total Discharge: " + String(total_discharge) + " KWh</h4>";
|
||||
content += "<h4>Total Charge: " + String(total_charge) + " KWh</h4>";
|
||||
//0x212 530 BMS_status
|
||||
content += "<h4>Isolation Resistance: " + String(isolationResistance) + " kOhms</h4>";
|
||||
content += "<h4>BMS State: " + String(BMS_state[datalayer_extended.tesla.BMS_state]) + "</h4>";
|
||||
content += "<h4>BMS HV State: " + String(BMS_hvState[datalayer_extended.tesla.BMS_hvState]) + "</h4>";
|
||||
content += "<h4>BMS UI Charge Status: " + String(BMS_uiChargeStatus[datalayer_extended.tesla.BMS_uiChargeStatus]) +
|
||||
"</h4>";
|
||||
content += "<h4>BMS_buildConfigId: " + String(datalayer_extended.tesla.BMS_info_buildConfigId) + "</h4>";
|
||||
content += "<h4>BMS_hardwareId: " + String(datalayer_extended.tesla.BMS_info_hardwareId) + "</h4>";
|
||||
content += "<h4>BMS_componentId: " + String(datalayer_extended.tesla.BMS_info_componentId) + "</h4>";
|
||||
content += "<h4>BMS PCS PWM Enabled: " + String(Fault[datalayer_extended.tesla.BMS_pcsPwmEnabled]) + "</h4>";
|
||||
//0x292 658 BMS_socStates
|
||||
content += "<h4>Battery Beginning of Life: " + String(beginning_of_life) + " KWh</h4>";
|
||||
content += "<h4>Battery Beginning of Life: " + String(beginning_of_life) + " kWh</h4>";
|
||||
content += "<h4>Battery SOC UI: " + String(soc_ui) + " </h4>";
|
||||
content += "<h4>Battery SOC Ave: " + String(soc_ave) + " </h4>";
|
||||
content += "<h4>Battery SOC Max: " + String(soc_max) + " </h4>";
|
||||
|
@ -252,7 +285,7 @@ class TeslaHtmlRenderer : public BatteryHtmlRenderer {
|
|||
//content += "<h4>packConfigMultiplexer: " + String(datalayer_extended.tesla.battery_packConfigMultiplexer) + "</h4>"; // Not giving useable data
|
||||
//content += "<h4>moduleType: " + String(datalayer_extended.tesla.battery_moduleType) + "</h4>"; // Not giving useable data
|
||||
//content += "<h4>reserveConfig: " + String(datalayer_extended.tesla.battery_reservedConfig) + "</h4>"; // Not giving useable data
|
||||
content += "<h4>Battery Pack Mass: " + String(packMass) + " KG</h4>";
|
||||
//content += "<h4>Battery Pack Mass: " + String(packMass) + " KG</h4>";
|
||||
content += "<h4>Platform Max Bus Voltage: " + String(platformMaxBusVoltage) + " V</h4>";
|
||||
//0x2D2 722 BMSVAlimits
|
||||
content += "<h4>BMS Min Voltage: " + String(bms_min_voltage) + " V</h4>";
|
||||
|
@ -273,25 +306,14 @@ class TeslaHtmlRenderer : public BatteryHtmlRenderer {
|
|||
content += "<h4>PCS Chg PhB Temp: " + String(PCS_chgPhBTemp) + " DegC</h4>";
|
||||
content += "<h4>PCS Chg PhC Temp: " + String(PCS_chgPhCTemp) + " DegC</h4>";
|
||||
//0x252 594 BMS_powerAvailable
|
||||
content += "<h4>Max Regen Power: " + String(BMS_maxRegenPower) + " KW</h4>";
|
||||
content += "<h4>Max Discharge Power: " + String(BMS_maxDischargePower) + " KW</h4>";
|
||||
//content += "<h4>Max Stationary Heat Power: " + String(BMS_maxStationaryHeatPower) + " KWh</h4>"; // Not giving useable data
|
||||
//content += "<h4>HVAC Power Budget: " + String(BMS_hvacPowerBudget) + " KW</h4>"; // Not giving useable data
|
||||
content += "<h4>Max Regen Power: " + String(BMS_maxRegenPower) + " kW</h4>";
|
||||
content += "<h4>Max Discharge Power: " + String(BMS_maxDischargePower) + " kW</h4>";
|
||||
//content += "<h4>Max Stationary Heat Power: " + String(BMS_maxStationaryHeatPower) + " kWh</h4>"; // Not giving useable data
|
||||
//content += "<h4>HVAC Power Budget: " + String(BMS_hvacPowerBudget) + " kW</h4>"; // Not giving useable data
|
||||
//content += "<h4>Not Enough Power For Heat Pump: " + String(noYes[datalayer_extended.tesla.BMS_notEnoughPowerForHeatPump]) + "</h4>"; // Not giving useable data
|
||||
content +=
|
||||
"<h4>Power Limit State: " + String(BMS_powerLimitState[datalayer_extended.tesla.BMS_powerLimitState]) + "</h4>";
|
||||
//content += "<h4>Inverter TQF: " + String(datalayer_extended.tesla.BMS_inverterTQF) + "</h4>"; // Not giving useable data
|
||||
//0x212 530 BMS_status
|
||||
content += "<h4>Isolation Resistance: " + String(isolationResistance) + " kOhms</h4>";
|
||||
content +=
|
||||
"<h4>BMS Contactor State: " + String(BMS_contactorState[datalayer_extended.tesla.battery_BMS_contactorState]) +
|
||||
"</h4>";
|
||||
content += "<h4>BMS State: " + String(BMS_state[datalayer_extended.tesla.battery_BMS_state]) + "</h4>";
|
||||
content += "<h4>BMS HV State: " + String(BMS_hvState[datalayer_extended.tesla.battery_BMS_hvState]) + "</h4>";
|
||||
content += "<h4>BMS UI Charge Status: " + String(BMS_uiChargeStatus[datalayer_extended.tesla.battery_BMS_hvState]) +
|
||||
"</h4>";
|
||||
content +=
|
||||
"<h4>BMS PCS PWM Enabled: " + String(Fault[datalayer_extended.tesla.battery_BMS_pcsPwmEnabled]) + "</h4>";
|
||||
//0x312 786 BMS_thermalStatus
|
||||
content += "<h4>Power Dissipation: " + String(BMS_powerDissipation) + " kW</h4>";
|
||||
content += "<h4>Flow Request: " + String(BMS_flowRequest) + " LPM</h4>";
|
||||
|
@ -304,36 +326,34 @@ class TeslaHtmlRenderer : public BatteryHtmlRenderer {
|
|||
content += "<h4>BMS No Flow Request: " + String(Fault[datalayer_extended.tesla.BMS_noFlowRequest]) + "</h4>";
|
||||
//0x224 548 PCS_dcdcStatus
|
||||
content +=
|
||||
"<h4>Precharge Status: " + String(PCS_dcdcStatus[datalayer_extended.tesla.battery_PCS_dcdcPrechargeStatus]) +
|
||||
"</h4>";
|
||||
content +=
|
||||
"<h4>12V Support Status: " + String(PCS_dcdcStatus[datalayer_extended.tesla.battery_PCS_dcdc12VSupportStatus]) +
|
||||
"</h4>";
|
||||
"<h4>Precharge Status: " + String(PCS_dcdcStatus[datalayer_extended.tesla.PCS_dcdcPrechargeStatus]) + "</h4>";
|
||||
content += "<h4>12V Support Status: " + String(PCS_dcdcStatus[datalayer_extended.tesla.PCS_dcdc12VSupportStatus]) +
|
||||
"</h4>";
|
||||
content += "<h4>HV Bus Discharge Status: " +
|
||||
String(PCS_dcdcStatus[datalayer_extended.tesla.battery_PCS_dcdcHvBusDischargeStatus]) + "</h4>";
|
||||
content +=
|
||||
"<h4>Main State: " + String(PCS_dcdcMainState[datalayer_extended.tesla.battery_PCS_dcdcMainState]) + "</h4>";
|
||||
content +=
|
||||
"<h4>Sub State: " + String(PCS_dcdcSubState[datalayer_extended.tesla.battery_PCS_dcdcSubState]) + "</h4>";
|
||||
content += "<h4>PCS Faulted: " + String(Fault[datalayer_extended.tesla.battery_PCS_dcdcFaulted]) + "</h4>";
|
||||
content +=
|
||||
"<h4>Output Is Limited: " + String(Fault[datalayer_extended.tesla.battery_PCS_dcdcOutputIsLimited]) + "</h4>";
|
||||
String(PCS_dcdcStatus[datalayer_extended.tesla.PCS_dcdcHvBusDischargeStatus]) + "</h4>";
|
||||
content += "<h4>Main State: " + String(PCS_dcdcMainState[datalayer_extended.tesla.PCS_dcdcMainState]) + "</h4>";
|
||||
content += "<h4>Sub State: " + String(PCS_dcdcSubState[datalayer_extended.tesla.PCS_dcdcSubState]) + "</h4>";
|
||||
content += "<h4>PCS Faulted: " + String(Fault[datalayer_extended.tesla.PCS_dcdcFaulted]) + "</h4>";
|
||||
content += "<h4>Output Is Limited: " + String(Fault[datalayer_extended.tesla.PCS_dcdcOutputIsLimited]) + "</h4>";
|
||||
content += "<h4>Max Output Current Allowed: " + String(PCS_dcdcMaxOutputCurrentAllowed) + " A</h4>";
|
||||
content += "<h4>Precharge Rty Cnt: " + String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdcPrechargeRtyCnt]) +
|
||||
"</h4>";
|
||||
content +=
|
||||
"<h4>12V Support Rty Cnt: " + String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdc12VSupportRtyCnt]) +
|
||||
"<h4>Precharge Rty Cnt: " + String(falseTrue[datalayer_extended.tesla.PCS_dcdcPrechargeRtyCnt]) + "</h4>";
|
||||
content +=
|
||||
"<h4>12V Support Rty Cnt: " + String(falseTrue[datalayer_extended.tesla.PCS_dcdc12VSupportRtyCnt]) + "</h4>";
|
||||
content +=
|
||||
"<h4>Discharge Rty Cnt: " + String(falseTrue[datalayer_extended.tesla.PCS_dcdcDischargeRtyCnt]) + "</h4>";
|
||||
content += "<h4>PWM Enable Line: " + String(Fault[datalayer_extended.tesla.PCS_dcdcPwmEnableLine]) + "</h4>";
|
||||
content +=
|
||||
"<h4>Supporting Fixed LV Target: " + String(Fault[datalayer_extended.tesla.PCS_dcdcSupportingFixedLvTarget]) +
|
||||
"</h4>";
|
||||
content += "<h4>Discharge Rty Cnt: " + String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdcDischargeRtyCnt]) +
|
||||
content += "<h4>Precharge Restart Cnt: " + String(falseTrue[datalayer_extended.tesla.PCS_dcdcPrechargeRestartCnt]) +
|
||||
"</h4>";
|
||||
content +=
|
||||
"<h4>PWM Enable Line: " + String(Fault[datalayer_extended.tesla.battery_PCS_dcdcPwmEnableLine]) + "</h4>";
|
||||
content += "<h4>Supporting Fixed LV Target: " +
|
||||
String(Fault[datalayer_extended.tesla.battery_PCS_dcdcSupportingFixedLvTarget]) + "</h4>";
|
||||
content += "<h4>Precharge Restart Cnt: " +
|
||||
String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdcPrechargeRestartCnt]) + "</h4>";
|
||||
content += "<h4>Initial Precharge Substate: " +
|
||||
String(PCS_dcdcSubState[datalayer_extended.tesla.battery_PCS_dcdcInitialPrechargeSubState]) + "</h4>";
|
||||
String(PCS_dcdcSubState[datalayer_extended.tesla.PCS_dcdcInitialPrechargeSubState]) + "</h4>";
|
||||
//0x3C4 PCS_info
|
||||
content += "<h4>PCS_buildConfigId: " + String(datalayer_extended.tesla.PCS_info_buildConfigId) + "</h4>";
|
||||
content += "<h4>PCS_hardwareId: " + String(datalayer_extended.tesla.PCS_info_hardwareId) + "</h4>";
|
||||
content += "<h4>PCS_componentId: " + String(datalayer_extended.tesla.PCS_info_componentId) + "</h4>";
|
||||
//0x2C4 708 PCS_logging
|
||||
content += "<h4>PCS_dcdcMaxLvOutputCurrent: " + String(PCS_dcdcMaxLvOutputCurrent) + " A</h4>";
|
||||
content += "<h4>PCS_dcdcCurrentLimit: " + String(PCS_dcdcCurrentLimit) + " A</h4>";
|
||||
|
@ -355,6 +375,10 @@ class TeslaHtmlRenderer : public BatteryHtmlRenderer {
|
|||
content += "<h4>PCS_dcdcIntervalMinLvBusVolt: " + String(PCS_dcdcIntervalMinLvBusVolt) + " V</h4>";
|
||||
content += "<h4>PCS_dcdcIntervalMinLvOutputCurr: " + String(PCS_dcdcIntervalMinLvOutputCurr) + " A</h4>";
|
||||
content += "<h4>PCS_dcdc12vSupportLifetimekWh: " + String(PCS_dcdc12vSupportLifetimekWh) + " kWh</h4>";
|
||||
//0x310 HVP_info
|
||||
content += "<h4>HVP_buildConfigId: " + String(datalayer_extended.tesla.HVP_info_buildConfigId) + "</h4>";
|
||||
content += "<h4>HVP_hardwareId: " + String(datalayer_extended.tesla.HVP_info_hardwareId) + "</h4>";
|
||||
content += "<h4>HVP_componentId: " + String(datalayer_extended.tesla.HVP_info_componentId) + "</h4>";
|
||||
//0x7AA 1962 HVP_debugMessage
|
||||
content += "<h4>HVP_battery12V: " + String(HVP_battery12V) + " V</h4>";
|
||||
content += "<h4>HVP_dcLinkVoltage: " + String(HVP_dcLinkVoltage) + " V</h4>";
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#include "TEST-FAKE-BATTERY.h"
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../include.h"
|
||||
#include "../devboard/utils/logging.h"
|
||||
|
||||
static void print_units(char* header, int value, char* units) {
|
||||
static void print_units(const char* header, int value, const char* units) {
|
||||
logging.print(header);
|
||||
logging.print(value);
|
||||
logging.print(units);
|
||||
|
@ -67,7 +67,7 @@ void TestFakeBattery::transmit_can(unsigned long currentMillis) {
|
|||
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
|
||||
previousMillis100 = currentMillis;
|
||||
// Put fake messages here incase you want to test sending CAN
|
||||
//transmit_can_frame(&TEST, can_interface);
|
||||
//transmit_can_frame(&TEST);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#ifndef TEST_FAKE_BATTERY_H
|
||||
#define TEST_FAKE_BATTERY_H
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../include.h"
|
||||
#include "CanBattery.h"
|
||||
|
||||
#ifdef TEST_FAKE_BATTERY
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include "../datalayer/datalayer.h"
|
||||
#include "../datalayer/datalayer_extended.h" //For "More battery info" webpage
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../include.h"
|
||||
#include "../devboard/utils/logging.h"
|
||||
|
||||
void VolvoSpaBattery::
|
||||
update_values() { //This function maps all the values fetched via CAN to the correct parameters used for the inverter
|
||||
|
@ -27,15 +27,15 @@ void VolvoSpaBattery::
|
|||
|
||||
// Update requests from webserver datalayer
|
||||
if (datalayer_extended.VolvoPolestar.UserRequestDTCreset) {
|
||||
transmit_can_frame(&VOLVO_DTC_Erase, can_config.battery); //Send global DTC erase command
|
||||
transmit_can_frame(&VOLVO_DTC_Erase); //Send global DTC erase command
|
||||
datalayer_extended.VolvoPolestar.UserRequestDTCreset = false;
|
||||
}
|
||||
if (datalayer_extended.VolvoPolestar.UserRequestBECMecuReset) {
|
||||
transmit_can_frame(&VOLVO_BECM_ECUreset, can_config.battery); //Send BECM ecu reset command
|
||||
transmit_can_frame(&VOLVO_BECM_ECUreset); //Send BECM ecu reset command
|
||||
datalayer_extended.VolvoPolestar.UserRequestBECMecuReset = false;
|
||||
}
|
||||
if (datalayer_extended.VolvoPolestar.UserRequestDTCreadout) {
|
||||
transmit_can_frame(&VOLVO_DTCreadout, can_config.battery); //Send DTC readout command
|
||||
transmit_can_frame(&VOLVO_DTCreadout); //Send DTC readout command
|
||||
datalayer_extended.VolvoPolestar.UserRequestDTCreadout = false;
|
||||
}
|
||||
|
||||
|
@ -287,7 +287,7 @@ void VolvoSpaBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
|||
(rx_frame.data.u8[3] == 0x6D)) // SOH response frame
|
||||
{
|
||||
datalayer.battery.status.soh_pptt = ((rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]);
|
||||
transmit_can_frame(&VOLVO_BECMsupplyVoltage_Req, can_config.battery); //Send BECM supply voltage req
|
||||
transmit_can_frame(&VOLVO_BECMsupplyVoltage_Req); //Send BECM supply voltage req
|
||||
} else if ((rx_frame.data.u8[0] == 0x05) && (rx_frame.data.u8[1] == 0x62) && (rx_frame.data.u8[2] == 0xF4) &&
|
||||
(rx_frame.data.u8[3] == 0x42)) // BECM module voltage supply
|
||||
{
|
||||
|
@ -297,12 +297,12 @@ void VolvoSpaBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
|||
{
|
||||
cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6]);
|
||||
cell_voltages[battery_request_idx] = (rx_frame.data.u8[7] << 8);
|
||||
transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control
|
||||
transmit_can_frame(&VOLVO_FlowControl); // Send flow control
|
||||
rxConsecutiveFrames = 1;
|
||||
} else if ((rx_frame.data.u8[0] == 0x10) && (rx_frame.data.u8[2] == 0x59) &&
|
||||
(rx_frame.data.u8[3] == 0x03)) // First response frame for DTC with more than one code
|
||||
{
|
||||
transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control
|
||||
transmit_can_frame(&VOLVO_FlowControl); // Send flow control
|
||||
} else if ((rx_frame.data.u8[0] == 0x21) && (rxConsecutiveFrames == 1)) {
|
||||
cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
|
||||
|
@ -311,7 +311,7 @@ void VolvoSpaBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
|||
if (batteryModuleNumber <= 0x2A) // Run until last pack is read
|
||||
{
|
||||
VOLVO_CELL_U_Req.data.u8[3] = batteryModuleNumber++;
|
||||
transmit_can_frame(&VOLVO_CELL_U_Req, can_config.battery); //Send cell voltage read request for next module
|
||||
transmit_can_frame(&VOLVO_CELL_U_Req); //Send cell voltage read request for next module
|
||||
} else {
|
||||
min_max_voltage[0] = 9999;
|
||||
min_max_voltage[1] = 0;
|
||||
|
@ -321,7 +321,7 @@ void VolvoSpaBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
|||
if (min_max_voltage[1] < cell_voltages[cellcounter])
|
||||
min_max_voltage[1] = cell_voltages[cellcounter];
|
||||
}
|
||||
transmit_can_frame(&VOLVO_SOH_Req, can_config.battery); //Send SOH read request
|
||||
transmit_can_frame(&VOLVO_SOH_Req); //Send SOH read request
|
||||
}
|
||||
rxConsecutiveFrames = 0;
|
||||
}
|
||||
|
@ -336,7 +336,7 @@ void VolvoSpaBattery::readCellVoltages() {
|
|||
batteryModuleNumber = 0x10;
|
||||
rxConsecutiveFrames = 0;
|
||||
VOLVO_CELL_U_Req.data.u8[3] = batteryModuleNumber++;
|
||||
transmit_can_frame(&VOLVO_CELL_U_Req, can_config.battery); //Send cell voltage read request for first module
|
||||
transmit_can_frame(&VOLVO_CELL_U_Req); //Send cell voltage read request for first module
|
||||
}
|
||||
|
||||
void VolvoSpaBattery::transmit_can(unsigned long currentMillis) {
|
||||
|
@ -344,22 +344,22 @@ void VolvoSpaBattery::transmit_can(unsigned long currentMillis) {
|
|||
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
|
||||
previousMillis100 = currentMillis;
|
||||
|
||||
transmit_can_frame(&VOLVO_536, can_config.battery); //Send 0x536 Network managing frame to keep BMS alive
|
||||
transmit_can_frame(&VOLVO_372, can_config.battery); //Send 0x372 ECMAmbientTempCalculated
|
||||
transmit_can_frame(&VOLVO_536); //Send 0x536 Network managing frame to keep BMS alive
|
||||
transmit_can_frame(&VOLVO_372); //Send 0x372 ECMAmbientTempCalculated
|
||||
|
||||
if ((datalayer.battery.status.bms_status == ACTIVE) && startedUp) {
|
||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
||||
transmit_can_frame(&VOLVO_140_CLOSE, can_config.battery); //Send 0x140 Close contactors message
|
||||
transmit_can_frame(&VOLVO_140_CLOSE); //Send 0x140 Close contactors message
|
||||
} else { //datalayer.battery.status.bms_status == FAULT , OR inverter requested opening contactors, OR system not started yet
|
||||
datalayer.system.status.battery_allows_contactor_closing = false;
|
||||
transmit_can_frame(&VOLVO_140_OPEN, can_config.battery); //Send 0x140 Open contactors message
|
||||
transmit_can_frame(&VOLVO_140_OPEN); //Send 0x140 Open contactors message
|
||||
}
|
||||
}
|
||||
if (currentMillis - previousMillis1s >= INTERVAL_1_S) {
|
||||
previousMillis1s = currentMillis;
|
||||
|
||||
if (!startedUp) {
|
||||
transmit_can_frame(&VOLVO_DTC_Erase, can_config.battery); //Erase any DTCs preventing startup
|
||||
transmit_can_frame(&VOLVO_DTC_Erase); //Erase any DTCs preventing startup
|
||||
DTC_reset_counter++;
|
||||
if (DTC_reset_counter > 1) { // Performed twice before starting
|
||||
startedUp = true;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#ifndef VOLVO_SPA_BATTERY_H
|
||||
#define VOLVO_SPA_BATTERY_H
|
||||
#include <Arduino.h>
|
||||
#include "../include.h"
|
||||
|
||||
#include "CanBattery.h"
|
||||
#include "VOLVO-SPA-HTML.h"
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include "../datalayer/datalayer.h"
|
||||
#include "../datalayer/datalayer_extended.h" //For "More battery info" webpage
|
||||
#include "../devboard/utils/events.h"
|
||||
#include "../include.h"
|
||||
#include "../devboard/utils/logging.h"
|
||||
|
||||
void VolvoSpaHybridBattery::
|
||||
update_values() { //This function maps all the values fetched via CAN to the correct parameters used for the inverter
|
||||
|
@ -27,15 +27,15 @@ void VolvoSpaHybridBattery::
|
|||
|
||||
// Update requests from webserver datalayer
|
||||
if (datalayer_extended.VolvoHybrid.UserRequestDTCreset) {
|
||||
transmit_can_frame(&VOLVO_DTC_Erase, can_config.battery); //Send global DTC erase command
|
||||
transmit_can_frame(&VOLVO_DTC_Erase); //Send global DTC erase command
|
||||
datalayer_extended.VolvoHybrid.UserRequestDTCreset = false;
|
||||
}
|
||||
if (datalayer_extended.VolvoHybrid.UserRequestBECMecuReset) {
|
||||
transmit_can_frame(&VOLVO_BECM_ECUreset, can_config.battery); //Send BECM ecu reset command
|
||||
transmit_can_frame(&VOLVO_BECM_ECUreset); //Send BECM ecu reset command
|
||||
datalayer_extended.VolvoHybrid.UserRequestBECMecuReset = false;
|
||||
}
|
||||
if (datalayer_extended.VolvoHybrid.UserRequestDTCreadout) {
|
||||
transmit_can_frame(&VOLVO_DTCreadout, can_config.battery); //Send DTC readout command
|
||||
transmit_can_frame(&VOLVO_DTCreadout); //Send DTC readout command
|
||||
datalayer_extended.VolvoHybrid.UserRequestDTCreadout = false;
|
||||
}
|
||||
|
||||
|
@ -283,7 +283,7 @@ void VolvoSpaHybridBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
|||
(rx_frame.data.u8[3] == 0x6D)) // SOH response frame
|
||||
{
|
||||
datalayer.battery.status.soh_pptt = ((rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]);
|
||||
transmit_can_frame(&VOLVO_BECMsupplyVoltage_Req, can_config.battery); //Send BECM supply voltage req
|
||||
transmit_can_frame(&VOLVO_BECMsupplyVoltage_Req); //Send BECM supply voltage req
|
||||
} else if ((rx_frame.data.u8[0] == 0x05) && (rx_frame.data.u8[1] == 0x62) && (rx_frame.data.u8[2] == 0xF4) &&
|
||||
(rx_frame.data.u8[3] == 0x42)) // BECM module voltage supply
|
||||
{
|
||||
|
@ -294,193 +294,193 @@ void VolvoSpaHybridBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
|||
{
|
||||
cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6]);
|
||||
cell_voltages[battery_request_idx] = (rx_frame.data.u8[7] << 8);
|
||||
transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control
|
||||
transmit_can_frame(&VOLVO_FlowControl); // Send flow control
|
||||
rxConsecutiveFrames = 1;
|
||||
} else if ((rx_frame.data.u8[0] == 0x10) && (rx_frame.data.u8[2] == 0x59) &&
|
||||
(rx_frame.data.u8[3] == 0x03)) // First response frame for DTC with more than one code
|
||||
{
|
||||
transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control
|
||||
transmit_can_frame(&VOLVO_FlowControl); // Send flow control
|
||||
} else if ((rx_frame.data.u8[0] == 0x21) && (rxConsecutiveFrames == 1)) {
|
||||
cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
|
||||
//transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control
|
||||
//transmit_can_frame(&VOLVO_FlowControl); // Send flow control
|
||||
} else if ((rx_frame.data.u8[0] == 0x22) && (rxConsecutiveFrames == 1)) {
|
||||
cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]);
|
||||
cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4]);
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6];
|
||||
cell_voltages[battery_request_idx] = (rx_frame.data.u8[7] << 8);
|
||||
//transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control
|
||||
//transmit_can_frame(&VOLVO_FlowControl); // Send flow control
|
||||
} else if ((rx_frame.data.u8[0] == 0x23) && (rxConsecutiveFrames == 1)) {
|
||||
cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
|
||||
//transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control
|
||||
//transmit_can_frame(&VOLVO_FlowControl); // Send flow control
|
||||
} else if ((rx_frame.data.u8[0] == 0x24) && (rxConsecutiveFrames == 1)) {
|
||||
cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]);
|
||||
cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4]);
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6];
|
||||
cell_voltages[battery_request_idx] = (rx_frame.data.u8[7] << 8);
|
||||
//transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control
|
||||
//transmit_can_frame(&VOLVO_FlowControl); // Send flow control
|
||||
} else if ((rx_frame.data.u8[0] == 0x25) && (rxConsecutiveFrames == 1)) {
|
||||
cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
|
||||
//transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control
|
||||
//transmit_can_frame(&VOLVO_FlowControl); // Send flow control
|
||||
} else if ((rx_frame.data.u8[0] == 0x26) && (rxConsecutiveFrames == 1)) {
|
||||
cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]);
|
||||
cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4]);
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6];
|
||||
cell_voltages[battery_request_idx] = (rx_frame.data.u8[7] << 8);
|
||||
//transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control
|
||||
//transmit_can_frame(&VOLVO_FlowControl); // Send flow control
|
||||
} else if ((rx_frame.data.u8[0] == 0x27) && (rxConsecutiveFrames == 1)) {
|
||||
cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
|
||||
//transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control
|
||||
//transmit_can_frame(&VOLVO_FlowControl); // Send flow control
|
||||
} else if ((rx_frame.data.u8[0] == 0x28) && (rxConsecutiveFrames == 1)) {
|
||||
cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]);
|
||||
cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4]);
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6];
|
||||
cell_voltages[battery_request_idx] = (rx_frame.data.u8[7] << 8);
|
||||
//transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control
|
||||
//transmit_can_frame(&VOLVO_FlowControl); // Send flow control
|
||||
} else if ((rx_frame.data.u8[0] == 0x29) && (rxConsecutiveFrames == 1)) {
|
||||
cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
|
||||
//transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control
|
||||
//transmit_can_frame(&VOLVO_FlowControl); // Send flow control
|
||||
} else if ((rx_frame.data.u8[0] == 0x2A) && (rxConsecutiveFrames == 1)) {
|
||||
cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]);
|
||||
cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4]);
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6];
|
||||
cell_voltages[battery_request_idx] = (rx_frame.data.u8[7] << 8);
|
||||
//transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control
|
||||
//transmit_can_frame(&VOLVO_FlowControl); // Send flow control
|
||||
} else if ((rx_frame.data.u8[0] == 0x2B) && (rxConsecutiveFrames == 1)) {
|
||||
cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
|
||||
//transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control
|
||||
//transmit_can_frame(&VOLVO_FlowControl); // Send flow control
|
||||
} else if ((rx_frame.data.u8[0] == 0x2C) && (rxConsecutiveFrames == 1)) {
|
||||
cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]);
|
||||
cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4]);
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6];
|
||||
cell_voltages[battery_request_idx] = (rx_frame.data.u8[7] << 8);
|
||||
//transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control
|
||||
//transmit_can_frame(&VOLVO_FlowControl); // Send flow control
|
||||
} else if ((rx_frame.data.u8[0] == 0x2D) && (rxConsecutiveFrames == 1)) {
|
||||
cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
|
||||
//transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control
|
||||
//transmit_can_frame(&VOLVO_FlowControl); // Send flow control
|
||||
} else if ((rx_frame.data.u8[0] == 0x2E) && (rxConsecutiveFrames == 1)) {
|
||||
cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]);
|
||||
cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4]);
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6];
|
||||
cell_voltages[battery_request_idx] = (rx_frame.data.u8[7] << 8);
|
||||
//transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control
|
||||
//transmit_can_frame(&VOLVO_FlowControl); // Send flow control
|
||||
} else if ((rx_frame.data.u8[0] == 0x2F) && (rxConsecutiveFrames == 1)) {
|
||||
cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
|
||||
//transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control
|
||||
//transmit_can_frame(&VOLVO_FlowControl); // Send flow control
|
||||
rxConsecutiveFrames = 2;
|
||||
} else if ((rx_frame.data.u8[0] == 0x20) && (rxConsecutiveFrames == 2)) {
|
||||
cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]);
|
||||
cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4]);
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6];
|
||||
cell_voltages[battery_request_idx] = (rx_frame.data.u8[7] << 8);
|
||||
//transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control
|
||||
//transmit_can_frame(&VOLVO_FlowControl); // Send flow control
|
||||
} else if ((rx_frame.data.u8[0] == 0x21) && (rxConsecutiveFrames == 2)) {
|
||||
cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
|
||||
//transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control
|
||||
//transmit_can_frame(&VOLVO_FlowControl); // Send flow control
|
||||
} else if ((rx_frame.data.u8[0] == 0x22) && (rxConsecutiveFrames == 2)) {
|
||||
cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]);
|
||||
cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4]);
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6];
|
||||
cell_voltages[battery_request_idx] = (rx_frame.data.u8[7] << 8);
|
||||
//transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control
|
||||
//transmit_can_frame(&VOLVO_FlowControl); // Send flow control
|
||||
} else if ((rx_frame.data.u8[0] == 0x23) && (rxConsecutiveFrames == 2)) {
|
||||
cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
|
||||
//transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control
|
||||
//transmit_can_frame(&VOLVO_FlowControl); // Send flow control
|
||||
} else if ((rx_frame.data.u8[0] == 0x24) && (rxConsecutiveFrames == 2)) {
|
||||
cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]);
|
||||
cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4]);
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6];
|
||||
cell_voltages[battery_request_idx] = (rx_frame.data.u8[7] << 8);
|
||||
//transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control
|
||||
//transmit_can_frame(&VOLVO_FlowControl); // Send flow control
|
||||
} else if ((rx_frame.data.u8[0] == 0x25) && (rxConsecutiveFrames == 2)) {
|
||||
cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
|
||||
//transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control
|
||||
//transmit_can_frame(&VOLVO_FlowControl); // Send flow control
|
||||
} else if ((rx_frame.data.u8[0] == 0x26) && (rxConsecutiveFrames == 2)) {
|
||||
cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]);
|
||||
cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4]);
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6];
|
||||
cell_voltages[battery_request_idx] = (rx_frame.data.u8[7] << 8);
|
||||
//transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control
|
||||
//transmit_can_frame(&VOLVO_FlowControl); // Send flow control
|
||||
} else if ((rx_frame.data.u8[0] == 0x27) && (rxConsecutiveFrames == 2)) {
|
||||
cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
|
||||
//transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control
|
||||
//transmit_can_frame(&VOLVO_FlowControl); // Send flow control
|
||||
} else if ((rx_frame.data.u8[0] == 0x28) && (rxConsecutiveFrames == 2)) {
|
||||
cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]);
|
||||
cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4]);
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6];
|
||||
cell_voltages[battery_request_idx] = (rx_frame.data.u8[7] << 8);
|
||||
//transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control
|
||||
//transmit_can_frame(&VOLVO_FlowControl); // Send flow control
|
||||
} else if ((rx_frame.data.u8[0] == 0x29) && (rxConsecutiveFrames == 2)) {
|
||||
cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
|
||||
//transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control
|
||||
//transmit_can_frame(&VOLVO_FlowControl); // Send flow control
|
||||
} else if ((rx_frame.data.u8[0] == 0x2A) && (rxConsecutiveFrames == 2)) {
|
||||
cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]);
|
||||
cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4]);
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6];
|
||||
cell_voltages[battery_request_idx] = (rx_frame.data.u8[7] << 8);
|
||||
//transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control
|
||||
//transmit_can_frame(&VOLVO_FlowControl); // Send flow control
|
||||
} else if ((rx_frame.data.u8[0] == 0x2B) && (rxConsecutiveFrames == 2)) {
|
||||
cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
|
||||
//transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control
|
||||
//transmit_can_frame(&VOLVO_FlowControl); // Send flow control
|
||||
} else if ((rx_frame.data.u8[0] == 0x2C) && (rxConsecutiveFrames == 2)) {
|
||||
cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]);
|
||||
cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4]);
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6];
|
||||
cell_voltages[battery_request_idx] = (rx_frame.data.u8[7] << 8);
|
||||
//transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control
|
||||
//transmit_can_frame(&VOLVO_FlowControl); // Send flow control
|
||||
} else if ((rx_frame.data.u8[0] == 0x2D) && (rxConsecutiveFrames == 2)) {
|
||||
cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
|
||||
cell_voltages[battery_request_idx++] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
||||
//cell_voltages[battery_request_idx++] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7];
|
||||
//transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control
|
||||
//transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control
|
||||
//transmit_can_frame(&VOLVO_FlowControl); // Send flow control
|
||||
//transmit_can_frame(&VOLVO_FlowControl); // Send flow control
|
||||
|
||||
if (false) // Run until last pack is read
|
||||
{
|
||||
//VOLVO_CELL_U_Req.data.u8[3] = batteryModuleNumber++;
|
||||
//transmit_can_frame(&VOLVO_CELL_U_Req, can_config.battery); //Send cell voltage read request for next module
|
||||
//transmit_can_frame(&VOLVO_CELL_U_Req); //Send cell voltage read request for next module
|
||||
;
|
||||
} else {
|
||||
min_max_voltage[0] = 9999;
|
||||
|
@ -496,7 +496,7 @@ void VolvoSpaHybridBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
|||
CELL_U_MAX = min_max_voltage[1];
|
||||
CELL_U_MIN = min_max_voltage[0];
|
||||
|
||||
transmit_can_frame(&VOLVO_SOH_Req, can_config.battery); //Send SOH read request
|
||||
transmit_can_frame(&VOLVO_SOH_Req); //Send SOH read request
|
||||
}
|
||||
rxConsecutiveFrames = 0;
|
||||
}
|
||||
|
@ -511,7 +511,7 @@ void VolvoSpaHybridBattery::readCellVoltages() {
|
|||
//batteryModuleNumber = 0x10;
|
||||
rxConsecutiveFrames = 0;
|
||||
//VOLVO_CELL_U_Req.data.u8[3] = batteryModuleNumber++;
|
||||
transmit_can_frame(&VOLVO_CELL_U_Req, can_config.battery); //Send cell voltage read request for first module
|
||||
transmit_can_frame(&VOLVO_CELL_U_Req); //Send cell voltage read request for first module
|
||||
}
|
||||
|
||||
void VolvoSpaHybridBattery::transmit_can(unsigned long currentMillis) {
|
||||
|
@ -519,22 +519,22 @@ void VolvoSpaHybridBattery::transmit_can(unsigned long currentMillis) {
|
|||
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
|
||||
previousMillis100 = currentMillis;
|
||||
|
||||
transmit_can_frame(&VOLVO_536, can_config.battery); //Send 0x536 Network managing frame to keep BMS alive
|
||||
transmit_can_frame(&VOLVO_372, can_config.battery); //Send 0x372 ECMAmbientTempCalculated
|
||||
transmit_can_frame(&VOLVO_536); //Send 0x536 Network managing frame to keep BMS alive
|
||||
transmit_can_frame(&VOLVO_372); //Send 0x372 ECMAmbientTempCalculated
|
||||
|
||||
if ((datalayer.battery.status.bms_status == ACTIVE) && startedUp) {
|
||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
||||
//transmit_can_frame(&VOLVO_140_CLOSE, can_config.battery); //Send 0x140 Close contactors message
|
||||
//transmit_can_frame(&VOLVO_140_CLOSE); //Send 0x140 Close contactors message
|
||||
} else { //datalayer.battery.status.bms_status == FAULT , OR inverter requested opening contactors, OR system not started yet
|
||||
datalayer.system.status.battery_allows_contactor_closing = false;
|
||||
transmit_can_frame(&VOLVO_140_OPEN, can_config.battery); //Send 0x140 Open contactors message
|
||||
transmit_can_frame(&VOLVO_140_OPEN); //Send 0x140 Open contactors message
|
||||
}
|
||||
}
|
||||
if (currentMillis - previousMillis1s >= INTERVAL_1_S) {
|
||||
previousMillis1s = currentMillis;
|
||||
|
||||
if (!startedUp) {
|
||||
transmit_can_frame(&VOLVO_DTC_Erase, can_config.battery); //Erase any DTCs preventing startup
|
||||
transmit_can_frame(&VOLVO_DTC_Erase); //Erase any DTCs preventing startup
|
||||
DTC_reset_counter++;
|
||||
if (DTC_reset_counter > 1) { // Performed twice before starting
|
||||
startedUp = true;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#ifndef VOLVO_SPA_HYBRID_BATTERY_H
|
||||
#define VOLVO_SPA_HYBRID_BATTERY_H
|
||||
#include <Arduino.h>
|
||||
#include "../include.h"
|
||||
|
||||
#include "CanBattery.h"
|
||||
#include "VOLVO-SPA-HYBRID-HTML.h"
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
#include "../include.h"
|
||||
#include "CHARGERS.h"
|
||||
#include <vector>
|
||||
#include "CanCharger.h"
|
||||
|
||||
CanCharger* charger = nullptr;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "CHEVY-VOLT-CHARGER.h"
|
||||
#include "../communication/can/comm_can.h"
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../include.h"
|
||||
#include "../devboard/utils/logging.h"
|
||||
|
||||
/* This implements Chevy Volt / Ampera charger support (2011-2015 model years).
|
||||
*
|
||||
|
@ -105,7 +105,7 @@ void ChevyVoltCharger::transmit_can(unsigned long currentMillis) {
|
|||
|
||||
charger_keepalive_frame.data.u8[0] = charger_mode;
|
||||
|
||||
transmit_can_frame(&charger_keepalive_frame, can_config.charger);
|
||||
transmit_can_frame(&charger_keepalive_frame);
|
||||
}
|
||||
|
||||
/* Send current targets every 200ms */
|
||||
|
@ -142,7 +142,7 @@ void ChevyVoltCharger::transmit_can(unsigned long currentMillis) {
|
|||
/* LSB of the voltage command. Then MSB LSB is divided by 2 */
|
||||
charger_set_targets.data.u8[3] = lowByte(Vol_temp);
|
||||
|
||||
transmit_can_frame(&charger_set_targets, can_config.charger);
|
||||
transmit_can_frame(&charger_set_targets);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#define CHEVYVOLT_CHARGER_H
|
||||
#include <Arduino.h>
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../include.h"
|
||||
#include "CanCharger.h"
|
||||
|
||||
#ifdef CHEVYVOLT_CHARGER
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#include "../datalayer/datalayer.h"
|
||||
#include "src/communication/Transmitter.h"
|
||||
#include "src/communication/can/CanReceiver.h"
|
||||
#include "src/communication/can/comm_can.h"
|
||||
#include "src/devboard/safety/safety.h"
|
||||
|
||||
enum class ChargerType { None, NissanLeaf, ChevyVolt, Highest };
|
||||
|
||||
|
@ -56,11 +58,18 @@ class CanCharger : public Charger, Transmitter, CanReceiver {
|
|||
|
||||
void receive_can_frame(CAN_frame* frame) { map_can_frame_to_variable(*frame); }
|
||||
|
||||
CAN_Interface interface() { return can_interface; }
|
||||
|
||||
protected:
|
||||
CAN_Interface can_interface;
|
||||
|
||||
CanCharger(ChargerType type) : Charger(type) {
|
||||
can_interface = can_config.charger;
|
||||
register_transmitter(this);
|
||||
register_can_receiver(this, can_config.charger);
|
||||
register_can_receiver(this, can_interface);
|
||||
}
|
||||
|
||||
void transmit_can_frame(CAN_frame* frame) { transmit_can_frame_to_interface(frame, can_interface); }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#include "NISSAN-LEAF-CHARGER.h"
|
||||
#include "../communication/can/comm_can.h"
|
||||
#include "../datalayer/datalayer.h"
|
||||
#include "../include.h"
|
||||
|
||||
/* This implements Nissan LEAF PDM charger support. 2013-2024 Gen2/3 PDMs are supported
|
||||
*
|
||||
|
@ -107,13 +106,13 @@ void NissanLeafCharger::transmit_can(unsigned long currentMillis) {
|
|||
#ifndef NISSAN_LEAF_BATTERY
|
||||
|
||||
// VCM message, containing info if battery should sleep or stay awake
|
||||
transmit_can_frame(&LEAF_50B, can_config.charger); // HCM_WakeUpSleepCommand == 11b == WakeUp, and CANMASK = 1
|
||||
transmit_can_frame(&LEAF_50B); // HCM_WakeUpSleepCommand == 11b == WakeUp, and CANMASK = 1
|
||||
|
||||
LEAF_1DB.data.u8[7] = calculate_CRC_Nissan(&LEAF_1DB);
|
||||
transmit_can_frame(&LEAF_1DB, can_config.charger);
|
||||
transmit_can_frame(&LEAF_1DB);
|
||||
|
||||
LEAF_1DC.data.u8[7] = calculate_CRC_Nissan(&LEAF_1DC);
|
||||
transmit_can_frame(&LEAF_1DC, can_config.charger);
|
||||
transmit_can_frame(&LEAF_1DC);
|
||||
#endif
|
||||
|
||||
OBCpowerSetpoint = ((datalayer.charger.charger_setpoint_HV_IDC * 4) + 0x64);
|
||||
|
@ -159,9 +158,7 @@ void NissanLeafCharger::transmit_can(unsigned long currentMillis) {
|
|||
LEAF_1F2.data.u8[6] = mprun10;
|
||||
LEAF_1F2.data.u8[7] = calculate_checksum_nibble(&LEAF_1F2);
|
||||
|
||||
transmit_can_frame(
|
||||
&LEAF_1F2,
|
||||
can_config.charger); // Sending of 1F2 message is halted in LEAF-BATTERY function incase used here
|
||||
transmit_can_frame(&LEAF_1F2); // Sending of 1F2 message is halted in LEAF-BATTERY function incase used here
|
||||
}
|
||||
|
||||
/* Send messages every 100ms here */
|
||||
|
@ -176,11 +173,11 @@ void NissanLeafCharger::transmit_can(unsigned long currentMillis) {
|
|||
LEAF_55B.data.u8[6] = ((0x1 << 4) | (mprun100));
|
||||
|
||||
LEAF_55B.data.u8[7] = calculate_CRC_Nissan(&LEAF_55B);
|
||||
transmit_can_frame(&LEAF_55B, can_config.charger);
|
||||
transmit_can_frame(&LEAF_55B);
|
||||
|
||||
transmit_can_frame(&LEAF_59E, can_config.charger);
|
||||
transmit_can_frame(&LEAF_59E);
|
||||
|
||||
transmit_can_frame(&LEAF_5BC, can_config.charger);
|
||||
transmit_can_frame(&LEAF_5BC);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#ifndef NISSANLEAF_CHARGER_H
|
||||
#define NISSANLEAF_CHARGER_H
|
||||
#include <Arduino.h>
|
||||
#include "../include.h"
|
||||
|
||||
#include "CanCharger.h"
|
||||
|
||||
|
|
|
@ -8,7 +8,4 @@ class CanReceiver {
|
|||
virtual void receive_can_frame(CAN_frame* rx_frame) = 0;
|
||||
};
|
||||
|
||||
// Register a receiver object for a given CAN interface
|
||||
void register_can_receiver(CanReceiver* receiver, CAN_Interface interface, bool halfSpeed = false);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,26 +1,24 @@
|
|||
#include "comm_can.h"
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include "../../include.h"
|
||||
#include "../../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
#include "../../lib/pierremolinaro-ACAN2517FD/ACAN2517FD.h"
|
||||
#include "../../lib/pierremolinaro-acan2515/ACAN2515.h"
|
||||
#include "CanReceiver.h"
|
||||
#include "USER_SETTINGS.h"
|
||||
#include "comm_can.h"
|
||||
#include "src/datalayer/datalayer.h"
|
||||
#include "src/devboard/safety/safety.h"
|
||||
#include "src/devboard/sdcard/sdcard.h"
|
||||
#include "src/devboard/utils/logging.h"
|
||||
|
||||
struct CanReceiverRegistration {
|
||||
CanReceiver* receiver;
|
||||
bool halfSpeed;
|
||||
CAN_Speed speed;
|
||||
};
|
||||
|
||||
static std::multimap<CAN_Interface, CanReceiverRegistration> can_receivers;
|
||||
|
||||
bool hasHalfSpeedReceivers(const CAN_Interface& iface) {
|
||||
auto range = can_receivers.equal_range(iface);
|
||||
for (auto it = range.first; it != range.second; ++it) {
|
||||
if (it->second.halfSpeed) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Parameters
|
||||
CAN_device_t CAN_cfg; // CAN Config
|
||||
const uint8_t rx_queue_size = 10; // Receive Queue size
|
||||
|
@ -29,107 +27,173 @@ volatile bool send_ok_2515 = 0;
|
|||
volatile bool send_ok_2518 = 0;
|
||||
static unsigned long previousMillis10 = 0;
|
||||
|
||||
#ifdef USE_CANFD_INTERFACE_AS_CLASSIC_CAN
|
||||
const bool use_canfd_as_can_default = true;
|
||||
#else
|
||||
const bool use_canfd_as_can_default = false;
|
||||
#endif
|
||||
bool use_canfd_as_can = use_canfd_as_can_default;
|
||||
|
||||
void map_can_frame_to_variable(CAN_frame* rx_frame, CAN_Interface interface);
|
||||
|
||||
#ifdef CAN_ADDON
|
||||
void register_can_receiver(CanReceiver* receiver, CAN_Interface interface, CAN_Speed speed) {
|
||||
can_receivers.insert({interface, {receiver, speed}});
|
||||
DEBUG_PRINTF("CAN receiver registered, total: %d\n", can_receivers.size());
|
||||
}
|
||||
|
||||
static const uint32_t QUARTZ_FREQUENCY = CRYSTAL_FREQUENCY_MHZ * 1000000UL; //MHZ configured in USER_SETTINGS.h
|
||||
SPIClass SPI2515;
|
||||
ACAN2515 can(MCP2515_CS, SPI2515, MCP2515_INT);
|
||||
|
||||
ACAN2515* can2515;
|
||||
ACAN2515Settings* settings2515;
|
||||
|
||||
static ACAN2515_Buffer16 gBuffer;
|
||||
#endif //CAN_ADDON
|
||||
#ifdef CANFD_ADDON
|
||||
|
||||
SPIClass SPI2517;
|
||||
ACAN2517FD canfd(MCP2517_CS, SPI2517, MCP2517_INT);
|
||||
#endif //CANFD_ADDON
|
||||
ACAN2517FD* canfd;
|
||||
ACAN2517FDSettings* settings2517;
|
||||
|
||||
// Initialization functions
|
||||
|
||||
void init_CAN() {
|
||||
DEBUG_PRINTF("init_CAN called\n");
|
||||
// CAN pins
|
||||
#ifdef CAN_SE_PIN
|
||||
pinMode(CAN_SE_PIN, OUTPUT);
|
||||
digitalWrite(CAN_SE_PIN, LOW);
|
||||
#endif // CAN_SE_PIN
|
||||
bool native_can_initialized = false;
|
||||
|
||||
// Half-speed currently only supported for CAN_NATIVE
|
||||
auto anyHalfSpeedNative = hasHalfSpeedReceivers(CAN_Interface::CAN_NATIVE);
|
||||
bool init_CAN() {
|
||||
|
||||
CAN_cfg.speed = anyHalfSpeedNative ? CAN_SPEED_250KBPS : CAN_SPEED_500KBPS;
|
||||
CAN_cfg.tx_pin_id = CAN_TX_PIN;
|
||||
CAN_cfg.rx_pin_id = CAN_RX_PIN;
|
||||
CAN_cfg.rx_queue = xQueueCreate(rx_queue_size, sizeof(CAN_frame_t));
|
||||
// Init CAN Module
|
||||
ESP32Can.CANInit();
|
||||
auto nativeIt = can_receivers.find(CAN_NATIVE);
|
||||
if (nativeIt != can_receivers.end()) {
|
||||
auto se_pin = esp32hal->CAN_SE_PIN();
|
||||
auto tx_pin = esp32hal->CAN_TX_PIN();
|
||||
auto rx_pin = esp32hal->CAN_RX_PIN();
|
||||
|
||||
DEBUG_PRINTF("init_CAN performed\n");
|
||||
if (se_pin != GPIO_NUM_NC) {
|
||||
if (!esp32hal->alloc_pins("CAN", se_pin)) {
|
||||
return false;
|
||||
}
|
||||
pinMode(se_pin, OUTPUT);
|
||||
digitalWrite(se_pin, LOW);
|
||||
}
|
||||
|
||||
#ifdef CAN_ADDON
|
||||
#ifdef DEBUG_LOG
|
||||
logging.println("Dual CAN Bus (ESP32+MCP2515) selected");
|
||||
#endif // DEBUG_LOG
|
||||
gBuffer.initWithSize(25);
|
||||
SPI2515.begin(MCP2515_SCK, MCP2515_MISO, MCP2515_MOSI);
|
||||
ACAN2515Settings settings2515(QUARTZ_FREQUENCY, 500UL * 1000UL); // CAN bit rate 500 kb/s
|
||||
settings2515.mRequestedMode = ACAN2515Settings::NormalMode;
|
||||
const uint16_t errorCode2515 = can.begin(settings2515, [] { can.isr(); });
|
||||
if (errorCode2515 == 0) {
|
||||
#ifdef DEBUG_LOG
|
||||
logging.println("Can ok");
|
||||
#endif // DEBUG_LOG
|
||||
} else {
|
||||
#ifdef DEBUG_LOG
|
||||
logging.print("Error Can: 0x");
|
||||
logging.println(errorCode2515, HEX);
|
||||
#endif // DEBUG_LOG
|
||||
set_event(EVENT_CANMCP2515_INIT_FAILURE, (uint8_t)errorCode2515);
|
||||
CAN_cfg.speed = (CAN_speed_t)nativeIt->second.speed;
|
||||
|
||||
if (!esp32hal->alloc_pins("CAN", tx_pin, rx_pin)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CAN_cfg.tx_pin_id = tx_pin;
|
||||
CAN_cfg.rx_pin_id = rx_pin;
|
||||
CAN_cfg.rx_queue = xQueueCreate(rx_queue_size, sizeof(CAN_frame_t));
|
||||
// Init CAN Module
|
||||
ESP32Can.CANInit();
|
||||
native_can_initialized = true;
|
||||
}
|
||||
#endif // CAN_ADDON
|
||||
|
||||
#ifdef CANFD_ADDON
|
||||
auto addonIt = can_receivers.find(CAN_ADDON_MCP2515);
|
||||
if (addonIt != can_receivers.end()) {
|
||||
auto cs_pin = esp32hal->MCP2515_CS();
|
||||
auto int_pin = esp32hal->MCP2515_INT();
|
||||
auto sck_pin = esp32hal->MCP2515_SCK();
|
||||
auto miso_pin = esp32hal->MCP2515_MISO();
|
||||
auto mosi_pin = esp32hal->MCP2515_MOSI();
|
||||
|
||||
if (!esp32hal->alloc_pins("CAN", cs_pin, int_pin, sck_pin, miso_pin, mosi_pin)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
logging.println("CAN FD add-on (ESP32+MCP2517) selected");
|
||||
logging.println("Dual CAN Bus (ESP32+MCP2515) selected");
|
||||
#endif // DEBUG_LOG
|
||||
SPI2517.begin(MCP2517_SCK, MCP2517_SDO, MCP2517_SDI);
|
||||
ACAN2517FDSettings settings2517(CANFD_ADDON_CRYSTAL_FREQUENCY_MHZ, 500 * 1000,
|
||||
DataBitRateFactor::x4); // Arbitration bit rate: 500 kbit/s, data bit rate: 2 Mbit/s
|
||||
#ifdef USE_CANFD_INTERFACE_AS_CLASSIC_CAN
|
||||
settings2517.mRequestedMode = ACAN2517FDSettings::Normal20B; // ListenOnly / Normal20B / NormalFD
|
||||
#else // not USE_CANFD_INTERFACE_AS_CLASSIC_CAN
|
||||
settings2517.mRequestedMode = ACAN2517FDSettings::NormalFD; // ListenOnly / Normal20B / NormalFD
|
||||
#endif // USE_CANFD_INTERFACE_AS_CLASSIC_CAN
|
||||
const uint32_t errorCode2517 = canfd.begin(settings2517, [] { canfd.isr(); });
|
||||
canfd.poll();
|
||||
if (errorCode2517 == 0) {
|
||||
gBuffer.initWithSize(25);
|
||||
|
||||
can2515 = new ACAN2515(cs_pin, SPI2515, int_pin);
|
||||
|
||||
SPI2515.begin(sck_pin, miso_pin, mosi_pin);
|
||||
|
||||
// CAN bit rate 250 or 500 kb/s
|
||||
auto bitRate = (int)addonIt->second.speed * 1000UL;
|
||||
|
||||
settings2515 = new ACAN2515Settings(QUARTZ_FREQUENCY, bitRate);
|
||||
settings2515->mRequestedMode = ACAN2515Settings::NormalMode;
|
||||
const uint16_t errorCode2515 = can2515->begin(*settings2515, [] { can2515->isr(); });
|
||||
if (errorCode2515 == 0) {
|
||||
#ifdef DEBUG_LOG
|
||||
logging.print("Bit Rate prescaler: ");
|
||||
logging.println(settings2517.mBitRatePrescaler);
|
||||
logging.print("Arbitration Phase segment 1: ");
|
||||
logging.print(settings2517.mArbitrationPhaseSegment1);
|
||||
logging.print(" segment 2: ");
|
||||
logging.print(settings2517.mArbitrationPhaseSegment2);
|
||||
logging.print(" SJW: ");
|
||||
logging.println(settings2517.mArbitrationSJW);
|
||||
logging.print("Actual Arbitration Bit Rate: ");
|
||||
logging.print(settings2517.actualArbitrationBitRate());
|
||||
logging.print(" bit/s");
|
||||
logging.print(" (Exact:");
|
||||
logging.println(settings2517.exactArbitrationBitRate() ? "yes)" : "no)");
|
||||
logging.print("Arbitration Sample point: ");
|
||||
logging.print(settings2517.arbitrationSamplePointFromBitStart());
|
||||
logging.println("%");
|
||||
logging.println("Can ok");
|
||||
#endif // DEBUG_LOG
|
||||
} else {
|
||||
} else {
|
||||
#ifdef DEBUG_LOG
|
||||
logging.print("CAN-FD Configuration error 0x");
|
||||
logging.println(errorCode2517, HEX);
|
||||
logging.print("Error Can: 0x");
|
||||
logging.println(errorCode2515, HEX);
|
||||
#endif // DEBUG_LOG
|
||||
set_event(EVENT_CANMCP2517FD_INIT_FAILURE, (uint8_t)errorCode2517);
|
||||
set_event(EVENT_CANMCP2515_INIT_FAILURE, (uint8_t)errorCode2515);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif // CANFD_ADDON
|
||||
|
||||
auto fdNativeIt = can_receivers.find(CANFD_NATIVE);
|
||||
auto fdAddonIt = can_receivers.find(CANFD_ADDON_MCP2518);
|
||||
|
||||
if (fdNativeIt != can_receivers.end() || fdAddonIt != can_receivers.end()) {
|
||||
|
||||
auto speed = (fdNativeIt != can_receivers.end()) ? fdNativeIt->second.speed : fdAddonIt->second.speed;
|
||||
|
||||
auto cs_pin = esp32hal->MCP2517_CS();
|
||||
auto int_pin = esp32hal->MCP2517_INT();
|
||||
auto sck_pin = esp32hal->MCP2517_SCK();
|
||||
auto sdo_pin = esp32hal->MCP2517_SDO();
|
||||
auto sdi_pin = esp32hal->MCP2517_SDI();
|
||||
|
||||
if (!esp32hal->alloc_pins("CAN", cs_pin, int_pin, sck_pin, sdo_pin, sdi_pin)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
canfd = new ACAN2517FD(cs_pin, SPI2517, int_pin);
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
logging.println("CAN FD add-on (ESP32+MCP2517) selected");
|
||||
#endif // DEBUG_LOG
|
||||
SPI2517.begin(sck_pin, sdo_pin, sdi_pin);
|
||||
auto bitRate = (int)speed * 1000UL;
|
||||
settings2517 = new ACAN2517FDSettings(
|
||||
CANFD_ADDON_CRYSTAL_FREQUENCY_MHZ, bitRate,
|
||||
DataBitRateFactor::x4); // Arbitration bit rate: 250/500 kbit/s, data bit rate: 1/2 Mbit/s
|
||||
|
||||
// ListenOnly / Normal20B / NormalFD
|
||||
settings2517->mRequestedMode = use_canfd_as_can ? ACAN2517FDSettings::Normal20B : ACAN2517FDSettings::NormalFD;
|
||||
|
||||
const uint32_t errorCode2517 = canfd->begin(*settings2517, [] { canfd->isr(); });
|
||||
canfd->poll();
|
||||
if (errorCode2517 == 0) {
|
||||
#ifdef DEBUG_LOG
|
||||
logging.print("Bit Rate prescaler: ");
|
||||
logging.println(settings2517->mBitRatePrescaler);
|
||||
logging.print("Arbitration Phase segment 1: ");
|
||||
logging.print(settings2517->mArbitrationPhaseSegment1);
|
||||
logging.print(" segment 2: ");
|
||||
logging.print(settings2517->mArbitrationPhaseSegment2);
|
||||
logging.print(" SJW: ");
|
||||
logging.println(settings2517->mArbitrationSJW);
|
||||
logging.print("Actual Arbitration Bit Rate: ");
|
||||
logging.print(settings2517->actualArbitrationBitRate());
|
||||
logging.print(" bit/s");
|
||||
logging.print(" (Exact:");
|
||||
logging.println(settings2517->exactArbitrationBitRate() ? "yes)" : "no)");
|
||||
logging.print("Arbitration Sample point: ");
|
||||
logging.print(settings2517->arbitrationSamplePointFromBitStart());
|
||||
logging.println("%");
|
||||
#endif // DEBUG_LOG
|
||||
} else {
|
||||
#ifdef DEBUG_LOG
|
||||
logging.print("CAN-FD Configuration error 0x");
|
||||
logging.println(errorCode2517, HEX);
|
||||
#endif // DEBUG_LOG
|
||||
set_event(EVENT_CANMCP2517FD_INIT_FAILURE, (uint8_t)errorCode2517);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void transmit_can_frame(CAN_frame* tx_frame, int interface) {
|
||||
void transmit_can_frame_to_interface(CAN_frame* tx_frame, int interface) {
|
||||
if (!allowed_to_send_CAN) {
|
||||
return;
|
||||
}
|
||||
|
@ -156,7 +220,6 @@ void transmit_can_frame(CAN_frame* tx_frame, int interface) {
|
|||
}
|
||||
break;
|
||||
case CAN_ADDON_MCP2515: {
|
||||
#ifdef CAN_ADDON
|
||||
//Struct with ACAN2515 library format, needed to use the MCP2515 library for CAN2
|
||||
CANMessage MCP2515Frame;
|
||||
MCP2515Frame.id = tx_frame->ID;
|
||||
|
@ -167,17 +230,13 @@ void transmit_can_frame(CAN_frame* tx_frame, int interface) {
|
|||
MCP2515Frame.data[i] = tx_frame->data.u8[i];
|
||||
}
|
||||
|
||||
send_ok_2515 = can.tryToSend(MCP2515Frame);
|
||||
send_ok_2515 = can2515->tryToSend(MCP2515Frame);
|
||||
if (!send_ok_2515) {
|
||||
datalayer.system.info.can_2515_send_fail = true;
|
||||
}
|
||||
#else // Interface not compiled, and settings try to use it
|
||||
set_event(EVENT_INTERFACE_MISSING, interface);
|
||||
#endif //CAN_ADDON
|
||||
} break;
|
||||
case CANFD_NATIVE:
|
||||
case CANFD_ADDON_MCP2518: {
|
||||
#ifdef CANFD_ADDON
|
||||
CANFDMessage MCP2518Frame;
|
||||
if (tx_frame->FD) {
|
||||
MCP2518Frame.type = CANFDMessage::CANFD_WITH_BIT_RATE_SWITCH;
|
||||
|
@ -190,13 +249,10 @@ void transmit_can_frame(CAN_frame* tx_frame, int interface) {
|
|||
for (uint8_t i = 0; i < MCP2518Frame.len; i++) {
|
||||
MCP2518Frame.data[i] = tx_frame->data.u8[i];
|
||||
}
|
||||
send_ok_2518 = canfd.tryToSend(MCP2518Frame);
|
||||
send_ok_2518 = canfd->tryToSend(MCP2518Frame);
|
||||
if (!send_ok_2518) {
|
||||
datalayer.system.info.can_2518_send_fail = true;
|
||||
}
|
||||
#else // Interface not compiled, and settings try to use it
|
||||
set_event(EVENT_INTERFACE_MISSING, interface);
|
||||
#endif //CANFD_ADDON
|
||||
} break;
|
||||
default:
|
||||
// Invalid interface sent with function call. TODO: Raise event that coders messed up
|
||||
|
@ -206,13 +262,17 @@ void transmit_can_frame(CAN_frame* tx_frame, int interface) {
|
|||
|
||||
// Receive functions
|
||||
void receive_can() {
|
||||
receive_frame_can_native(); // Receive CAN messages from native CAN port
|
||||
#ifdef CAN_ADDON
|
||||
receive_frame_can_addon(); // Receive CAN messages on add-on MCP2515 chip
|
||||
#endif // CAN_ADDON
|
||||
#ifdef CANFD_ADDON
|
||||
receive_frame_canfd_addon(); // Receive CAN-FD messages.
|
||||
#endif // CANFD_ADDON
|
||||
if (native_can_initialized) {
|
||||
receive_frame_can_native(); // Receive CAN messages from native CAN port
|
||||
}
|
||||
|
||||
if (can2515) {
|
||||
receive_frame_can_addon(); // Receive CAN messages on add-on MCP2515 chip
|
||||
}
|
||||
|
||||
if (canfd) {
|
||||
receive_frame_canfd_addon(); // Receive CAN-FD messages.
|
||||
}
|
||||
}
|
||||
|
||||
void receive_frame_can_native() { // This section checks if we have a complete CAN message incoming on native CAN port
|
||||
|
@ -234,13 +294,12 @@ void receive_frame_can_native() { // This section checks if we have a complete
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef CAN_ADDON
|
||||
void receive_frame_can_addon() { // This section checks if we have a complete CAN message incoming on add-on CAN port
|
||||
CAN_frame rx_frame; // Struct with our CAN format
|
||||
CANMessage MCP2515frame; // Struct with ACAN2515 library format, needed to use the MCP2515 library
|
||||
|
||||
if (can.available()) {
|
||||
can.receive(MCP2515frame);
|
||||
if (can2515->available()) {
|
||||
can2515->receive(MCP2515frame);
|
||||
|
||||
rx_frame.ID = MCP2515frame.id;
|
||||
rx_frame.ext_ID = MCP2515frame.ext ? CAN_frame_ext : CAN_frame_std;
|
||||
|
@ -253,26 +312,23 @@ void receive_frame_can_addon() { // This section checks if we have a complete C
|
|||
map_can_frame_to_variable(&rx_frame, CAN_ADDON_MCP2515);
|
||||
}
|
||||
}
|
||||
#endif // CAN_ADDON
|
||||
|
||||
#ifdef CANFD_ADDON
|
||||
void receive_frame_canfd_addon() { // This section checks if we have a complete CAN-FD message incoming
|
||||
CANFDMessage MCP2518frame;
|
||||
int count = 0;
|
||||
while (canfd.available() && count++ < 16) {
|
||||
canfd.receive(MCP2518frame);
|
||||
while (canfd->available() && count++ < 16) {
|
||||
canfd->receive(MCP2518frame);
|
||||
|
||||
CAN_frame rx_frame;
|
||||
rx_frame.ID = MCP2518frame.id;
|
||||
rx_frame.ext_ID = MCP2518frame.ext;
|
||||
rx_frame.DLC = MCP2518frame.len;
|
||||
memcpy(rx_frame.data.u8, MCP2518frame.data, MIN(rx_frame.DLC, 64));
|
||||
memcpy(rx_frame.data.u8, MCP2518frame.data, std::min(rx_frame.DLC, (uint8_t)64));
|
||||
//message incoming, pass it on to the handler
|
||||
map_can_frame_to_variable(&rx_frame, CANFD_ADDON_MCP2518);
|
||||
map_can_frame_to_variable(&rx_frame, CANFD_NATIVE);
|
||||
}
|
||||
}
|
||||
#endif // CANFD_ADDON
|
||||
|
||||
// Support functions
|
||||
void print_can_frame(CAN_frame frame, frameDirection msgDir) {
|
||||
|
@ -299,11 +355,6 @@ void print_can_frame(CAN_frame frame, frameDirection msgDir) {
|
|||
}
|
||||
}
|
||||
|
||||
void register_can_receiver(CanReceiver* receiver, CAN_Interface interface, bool halfSpeed) {
|
||||
can_receivers.insert({interface, {receiver, halfSpeed}});
|
||||
DEBUG_PRINTF("CAN receiver registered, total: %d\n", can_receivers.size());
|
||||
}
|
||||
|
||||
void map_can_frame_to_variable(CAN_frame* rx_frame, CAN_Interface interface) {
|
||||
if (interface !=
|
||||
CANFD_NATIVE) { //Avoid printing twice due to receive_frame_canfd_addon sending to both FD interfaces
|
||||
|
@ -361,3 +412,45 @@ void dump_can_frame(CAN_frame& frame, frameDirection msgDir) {
|
|||
|
||||
datalayer.system.info.logged_can_messages_offset = offset; // Update offset in buffer
|
||||
}
|
||||
|
||||
void stop_can() {
|
||||
if (can_receivers.find(CAN_NATIVE) != can_receivers.end()) {
|
||||
ESP32Can.CANStop();
|
||||
}
|
||||
|
||||
if (can2515) {
|
||||
can2515->end();
|
||||
SPI2515.end();
|
||||
}
|
||||
|
||||
if (canfd) {
|
||||
canfd->end();
|
||||
SPI2517.end();
|
||||
}
|
||||
}
|
||||
|
||||
void restart_can() {
|
||||
if (can_receivers.find(CAN_NATIVE) != can_receivers.end()) {
|
||||
ESP32Can.CANInit();
|
||||
}
|
||||
|
||||
if (can2515) {
|
||||
SPI2515.begin();
|
||||
can2515->begin(*settings2515, [] { can2515->isr(); });
|
||||
}
|
||||
|
||||
if (canfd) {
|
||||
SPI2517.begin();
|
||||
canfd->begin(*settings2517, [] { can2515->isr(); });
|
||||
}
|
||||
}
|
||||
|
||||
CAN_Speed change_can_speed(CAN_Interface interface, CAN_Speed speed) {
|
||||
auto oldSpeed = (CAN_Speed)CAN_cfg.speed;
|
||||
if (interface == CAN_Interface::CAN_NATIVE) {
|
||||
CAN_cfg.speed = (CAN_speed_t)speed;
|
||||
// ReInit native CAN module at new speed
|
||||
ESP32Can.CANInit();
|
||||
}
|
||||
return oldSpeed;
|
||||
}
|
||||
|
|
|
@ -1,34 +1,42 @@
|
|||
#ifndef _COMM_CAN_H_
|
||||
#define _COMM_CAN_H_
|
||||
|
||||
#include "../../include.h"
|
||||
#include "../../devboard/utils/types.h"
|
||||
|
||||
#include "../../datalayer/datalayer.h"
|
||||
#include "../../devboard/utils/events.h"
|
||||
#include "../../devboard/utils/value_mapping.h"
|
||||
#include "../../lib/ESP32Async-ESPAsyncWebServer/src/ESPAsyncWebServer.h"
|
||||
#include "../../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
#ifdef CAN_ADDON
|
||||
#include "../../lib/pierremolinaro-acan2515/ACAN2515.h"
|
||||
#endif //CAN_ADDON
|
||||
#ifdef CANFD_ADDON
|
||||
#include "../../lib/pierremolinaro-ACAN2517FD/ACAN2517FD.h"
|
||||
#endif //CANFD_ADDON
|
||||
extern bool use_canfd_as_can;
|
||||
|
||||
void dump_can_frame(CAN_frame& frame, frameDirection msgDir);
|
||||
void transmit_can_frame(CAN_frame* tx_frame, int interface);
|
||||
void transmit_can_frame_to_interface(CAN_frame* tx_frame, int interface);
|
||||
|
||||
class CanReceiver;
|
||||
|
||||
enum class CAN_Speed {
|
||||
CAN_SPEED_100KBPS = 100,
|
||||
CAN_SPEED_125KBPS = 125,
|
||||
CAN_SPEED_200KBPS = 200,
|
||||
CAN_SPEED_250KBPS = 250,
|
||||
CAN_SPEED_500KBPS = 500,
|
||||
CAN_SPEED_800KBPS = 800,
|
||||
CAN_SPEED_1000KBPS = 1000
|
||||
};
|
||||
|
||||
// Register a receiver object for a given CAN interface.
|
||||
// By default receivers expect the CAN interface to be operated at "fast" speed.
|
||||
// If halfSpeed is true, half speed is used.
|
||||
void register_can_receiver(CanReceiver* receiver, CAN_Interface interface,
|
||||
CAN_Speed speed = CAN_Speed::CAN_SPEED_500KBPS);
|
||||
|
||||
/**
|
||||
* @brief Initialization function for CAN.
|
||||
* @brief Initializes all CAN interfaces requested earlier by other modules (see register_can_receiver)
|
||||
*
|
||||
* @param[in] void
|
||||
*
|
||||
* @return void
|
||||
* @return true if CAN interfaces were initialized successfully, false otherwise.
|
||||
*/
|
||||
void init_CAN();
|
||||
bool init_CAN();
|
||||
|
||||
/**
|
||||
* @brief Receive CAN messages from all interfaces
|
||||
* @brief Receive CAN messages from all interfaces. Respective CanReceivers are called.
|
||||
*
|
||||
* @param[in] void
|
||||
*
|
||||
|
@ -72,4 +80,13 @@ void receive_frame_canfd_addon();
|
|||
*/
|
||||
void print_can_frame(CAN_frame frame, frameDirection msgDir);
|
||||
|
||||
// Stop/pause CAN communication for all interfaces
|
||||
void stop_can();
|
||||
|
||||
// Restart CAN communication for all interfaces
|
||||
void restart_can();
|
||||
|
||||
// Change the speed of the CAN interface and return the old speed.
|
||||
CAN_Speed change_can_speed(CAN_Interface interface, CAN_Speed speed);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
#include "obd.h"
|
||||
#include "../../devboard/utils/logging.h"
|
||||
#include "comm_can.h"
|
||||
|
||||
void transmit_can_frame(CAN_frame* tx_frame, int interface);
|
||||
|
||||
void show_dtc(uint8_t byte0, uint8_t byte1);
|
||||
|
||||
void show_dtc(uint8_t byte0, uint8_t byte1) {
|
||||
|
@ -128,21 +127,21 @@ void transmit_obd_can_frame(unsigned int address, int interface, bool canFD) {
|
|||
static int cnt = 0;
|
||||
switch (cnt) {
|
||||
case 2:
|
||||
transmit_can_frame(&OBD_frame, interface); // DTC TP-ISO
|
||||
transmit_can_frame_to_interface(&OBD_frame, interface); // DTC TP-ISO
|
||||
break;
|
||||
case 3:
|
||||
OBD_frame.data.u8[1] = 0x07;
|
||||
transmit_can_frame(&OBD_frame, interface); // DTC TP-ISO
|
||||
transmit_can_frame_to_interface(&OBD_frame, interface); // DTC TP-ISO
|
||||
break;
|
||||
case 4:
|
||||
OBD_frame.data.u8[1] = 0x0A;
|
||||
transmit_can_frame(&OBD_frame, interface); // DTC TP-ISO
|
||||
transmit_can_frame_to_interface(&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
|
||||
transmit_can_frame_to_interface(&OBD_frame, interface); // DTC TP-ISO
|
||||
break;
|
||||
}
|
||||
cnt++;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#ifndef _OBD_H_
|
||||
#define _OBD_H_
|
||||
|
||||
#include "../../include.h"
|
||||
#include "../../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
#include "comm_can.h"
|
||||
|
||||
void handle_obd_frame(CAN_frame& rx_frame);
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include "comm_contactorcontrol.h"
|
||||
#include "../../include.h"
|
||||
#include "../../devboard/hal/hal.h"
|
||||
#include "../../devboard/safety/safety.h"
|
||||
#include "../../inverter/INVERTERS.h"
|
||||
|
||||
#ifdef CONTACTOR_CONTROL
|
||||
const bool contactor_control_enabled_default = true;
|
||||
|
@ -25,7 +27,7 @@ bool periodic_bms_reset = periodic_bms_reset_default;
|
|||
#ifdef REMOTE_BMS_RESET
|
||||
const bool remote_bms_reset_default = true;
|
||||
#else
|
||||
const bool remote_bms_reset_default = true;
|
||||
const bool remote_bms_reset_default = false;
|
||||
#endif
|
||||
bool remote_bms_reset = remote_bms_reset_default;
|
||||
|
||||
|
@ -73,7 +75,6 @@ unsigned long currentTime = 0;
|
|||
unsigned long lastPowerRemovalTime = 0;
|
||||
unsigned long bmsPowerOnTime = 0;
|
||||
const unsigned long powerRemovalInterval = 24 * 60 * 60 * 1000; // 24 hours in milliseconds
|
||||
const unsigned long powerRemovalDuration = 30000; // 30 seconds in milliseconds
|
||||
const unsigned long bmsWarmupDuration = 3000;
|
||||
|
||||
void set(uint8_t pin, bool direction, uint32_t pwm_freq = 0xFFFF) {
|
||||
|
@ -92,41 +93,57 @@ void set(uint8_t pin, bool direction, uint32_t pwm_freq = 0xFFFF) {
|
|||
|
||||
// Initialization functions
|
||||
|
||||
void init_contactors() {
|
||||
const char* contactors = "Contactors";
|
||||
|
||||
bool init_contactors() {
|
||||
// Init contactor pins
|
||||
if (contactor_control_enabled) {
|
||||
auto posPin = esp32hal->POSITIVE_CONTACTOR_PIN();
|
||||
auto negPin = esp32hal->NEGATIVE_CONTACTOR_PIN();
|
||||
auto precPin = esp32hal->PRECHARGE_PIN();
|
||||
|
||||
if (!esp32hal->alloc_pins(contactors, posPin, negPin, precPin)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pwm_contactor_control) {
|
||||
// Setup PWM Channel Frequency and Resolution
|
||||
ledcAttachChannel(POSITIVE_CONTACTOR_PIN, PWM_Freq, PWM_Res, PWM_Positive_Channel);
|
||||
ledcAttachChannel(NEGATIVE_CONTACTOR_PIN, PWM_Freq, PWM_Res, PWM_Negative_Channel);
|
||||
ledcAttachChannel(posPin, PWM_Freq, PWM_Res, PWM_Positive_Channel);
|
||||
ledcAttachChannel(negPin, PWM_Freq, PWM_Res, PWM_Negative_Channel);
|
||||
// Set all pins OFF (0% PWM)
|
||||
ledcWrite(POSITIVE_CONTACTOR_PIN, PWM_OFF_DUTY);
|
||||
ledcWrite(NEGATIVE_CONTACTOR_PIN, PWM_OFF_DUTY);
|
||||
ledcWrite(posPin, PWM_OFF_DUTY);
|
||||
ledcWrite(negPin, PWM_OFF_DUTY);
|
||||
} else { //Normal CONTACTOR_CONTROL
|
||||
pinMode(POSITIVE_CONTACTOR_PIN, OUTPUT);
|
||||
set(POSITIVE_CONTACTOR_PIN, OFF);
|
||||
pinMode(NEGATIVE_CONTACTOR_PIN, OUTPUT);
|
||||
set(NEGATIVE_CONTACTOR_PIN, OFF);
|
||||
pinMode(posPin, OUTPUT);
|
||||
set(posPin, OFF);
|
||||
pinMode(negPin, OUTPUT);
|
||||
set(negPin, OFF);
|
||||
} // Precharge never has PWM regardless of setting
|
||||
pinMode(PRECHARGE_PIN, OUTPUT);
|
||||
set(PRECHARGE_PIN, OFF);
|
||||
pinMode(precPin, OUTPUT);
|
||||
set(precPin, OFF);
|
||||
}
|
||||
if (contactor_control_enabled_double_battery) {
|
||||
pinMode(SECOND_BATTERY_CONTACTORS_PIN, OUTPUT);
|
||||
set(SECOND_BATTERY_CONTACTORS_PIN, OFF);
|
||||
}
|
||||
// Init BMS contactor
|
||||
#if defined HW_STARK || defined HW_3LB // This hardware has dedicated pin, always enable on start
|
||||
pinMode(BMS_POWER, OUTPUT); //LilyGo is omitted from this, only enabled if user selects PERIODIC_BMS_RESET
|
||||
digitalWrite(BMS_POWER, HIGH);
|
||||
#endif // HW with dedicated BMS pins
|
||||
|
||||
#ifdef BMS_POWER
|
||||
if (periodic_bms_reset || remote_bms_reset) {
|
||||
pinMode(BMS_POWER, OUTPUT);
|
||||
digitalWrite(BMS_POWER, HIGH);
|
||||
if (contactor_control_enabled_double_battery) {
|
||||
auto second_contactors = esp32hal->SECOND_BATTERY_CONTACTORS_PIN();
|
||||
if (!esp32hal->alloc_pins(contactors, second_contactors)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
pinMode(second_contactors, OUTPUT);
|
||||
set(second_contactors, OFF);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Init BMS contactor
|
||||
if (periodic_bms_reset || remote_bms_reset || esp32hal->always_enable_bms_power()) {
|
||||
auto pin = esp32hal->BMS_POWER();
|
||||
if (!esp32hal->alloc_pins("BMS power", pin)) {
|
||||
return false;
|
||||
}
|
||||
pinMode(pin, OUTPUT);
|
||||
digitalWrite(pin, HIGH);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dbg_contactors(const char* state) {
|
||||
|
@ -144,9 +161,14 @@ void handle_contactors() {
|
|||
datalayer.system.status.inverter_allows_contactor_closing = inverter->allows_contactor_closing();
|
||||
}
|
||||
|
||||
#ifdef BMS_POWER
|
||||
handle_BMSpower(); // Some batteries need to be periodically power cycled
|
||||
#endif
|
||||
auto posPin = esp32hal->POSITIVE_CONTACTOR_PIN();
|
||||
auto negPin = esp32hal->NEGATIVE_CONTACTOR_PIN();
|
||||
auto prechargePin = esp32hal->PRECHARGE_PIN();
|
||||
auto bms_power_pin = esp32hal->BMS_POWER();
|
||||
|
||||
if (bms_power_pin != GPIO_NUM_NC) {
|
||||
handle_BMSpower(); // Some batteries need to be periodically power cycled
|
||||
}
|
||||
|
||||
#ifdef CONTACTOR_CONTROL_DOUBLE_BATTERY
|
||||
handle_contactors_battery2();
|
||||
|
@ -166,9 +188,9 @@ void handle_contactors() {
|
|||
}
|
||||
|
||||
if (contactorStatus == SHUTDOWN_REQUESTED) {
|
||||
set(PRECHARGE_PIN, OFF);
|
||||
set(NEGATIVE_CONTACTOR_PIN, OFF, PWM_OFF_DUTY);
|
||||
set(POSITIVE_CONTACTOR_PIN, OFF, PWM_OFF_DUTY);
|
||||
set(prechargePin, OFF);
|
||||
set(negPin, OFF, PWM_OFF_DUTY);
|
||||
set(posPin, OFF, PWM_OFF_DUTY);
|
||||
set_event(EVENT_ERROR_OPEN_CONTACTOR, 0);
|
||||
datalayer.system.status.contactors_engaged = false;
|
||||
return; // A fault scenario latches the contactor control. It is not possible to recover without a powercycle (and investigation why fault occured)
|
||||
|
@ -176,9 +198,9 @@ void handle_contactors() {
|
|||
|
||||
// After that, check if we are OK to start turning on the battery
|
||||
if (contactorStatus == DISCONNECTED) {
|
||||
set(PRECHARGE_PIN, OFF);
|
||||
set(NEGATIVE_CONTACTOR_PIN, OFF, PWM_OFF_DUTY);
|
||||
set(POSITIVE_CONTACTOR_PIN, OFF, PWM_OFF_DUTY);
|
||||
set(prechargePin, OFF);
|
||||
set(negPin, OFF, PWM_OFF_DUTY);
|
||||
set(posPin, OFF, PWM_OFF_DUTY);
|
||||
datalayer.system.status.contactors_engaged = false;
|
||||
|
||||
if (datalayer.system.status.battery_allows_contactor_closing &&
|
||||
|
@ -210,7 +232,7 @@ void handle_contactors() {
|
|||
// Handle actual state machine. This first turns on Negative, then Precharge, then Positive, and finally turns OFF precharge
|
||||
switch (contactorStatus) {
|
||||
case START_PRECHARGE:
|
||||
set(NEGATIVE_CONTACTOR_PIN, ON, PWM_ON_DUTY);
|
||||
set(negPin, ON, PWM_ON_DUTY);
|
||||
dbg_contactors("NEGATIVE");
|
||||
prechargeStartTime = currentTime;
|
||||
contactorStatus = PRECHARGE;
|
||||
|
@ -218,7 +240,7 @@ void handle_contactors() {
|
|||
|
||||
case PRECHARGE:
|
||||
if (currentTime - prechargeStartTime >= NEGATIVE_CONTACTOR_TIME_MS) {
|
||||
set(PRECHARGE_PIN, ON);
|
||||
set(prechargePin, ON);
|
||||
dbg_contactors("PRECHARGE");
|
||||
negativeStartTime = currentTime;
|
||||
contactorStatus = POSITIVE;
|
||||
|
@ -227,7 +249,7 @@ void handle_contactors() {
|
|||
|
||||
case POSITIVE:
|
||||
if (currentTime - negativeStartTime >= PRECHARGE_TIME_MS) {
|
||||
set(POSITIVE_CONTACTOR_PIN, ON, PWM_ON_DUTY);
|
||||
set(posPin, ON, PWM_ON_DUTY);
|
||||
dbg_contactors("POSITIVE");
|
||||
prechargeCompletedTime = currentTime;
|
||||
contactorStatus = PRECHARGE_OFF;
|
||||
|
@ -236,9 +258,9 @@ void handle_contactors() {
|
|||
|
||||
case PRECHARGE_OFF:
|
||||
if (currentTime - prechargeCompletedTime >= PRECHARGE_COMPLETED_TIME_MS) {
|
||||
set(PRECHARGE_PIN, OFF);
|
||||
set(NEGATIVE_CONTACTOR_PIN, ON, PWM_HOLD_DUTY);
|
||||
set(POSITIVE_CONTACTOR_PIN, ON, PWM_HOLD_DUTY);
|
||||
set(prechargePin, OFF);
|
||||
set(negPin, ON, PWM_HOLD_DUTY);
|
||||
set(posPin, ON, PWM_HOLD_DUTY);
|
||||
dbg_contactors("PRECHARGE_OFF");
|
||||
contactorStatus = COMPLETED;
|
||||
datalayer.system.status.contactors_engaged = true;
|
||||
|
@ -269,9 +291,10 @@ This makes the BMS recalculate all SOC% and avoid memory leaks
|
|||
During that time we also set the emulator state to paused in order to not try and send CAN messages towards the battery
|
||||
Feature is only used if user has enabled PERIODIC_BMS_RESET in the USER_SETTINGS */
|
||||
|
||||
#ifdef BMS_POWER
|
||||
void handle_BMSpower() {
|
||||
if (periodic_bms_reset || remote_bms_reset) {
|
||||
auto bms_power_pin = esp32hal->BMS_POWER();
|
||||
|
||||
// Get current time
|
||||
currentTime = millis();
|
||||
|
||||
|
@ -282,13 +305,11 @@ void handle_BMSpower() {
|
|||
}
|
||||
}
|
||||
|
||||
// If power has been removed for 30 seconds, restore the power
|
||||
if (datalayer.system.status.BMS_reset_in_progress && currentTime - lastPowerRemovalTime >= powerRemovalDuration) {
|
||||
// If power has been removed for user configured interval (1-59 seconds), restore the power
|
||||
if (datalayer.system.status.BMS_reset_in_progress &&
|
||||
currentTime - lastPowerRemovalTime >= datalayer.battery.settings.user_set_bms_reset_duration_ms) {
|
||||
// Reapply power to the BMS
|
||||
digitalWrite(BMS_POWER, HIGH);
|
||||
#ifdef BMS_2_POWER
|
||||
digitalWrite(BMS_2_POWER, HIGH); // Same for battery 2
|
||||
#endif
|
||||
digitalWrite(bms_power_pin, HIGH);
|
||||
bmsPowerOnTime = currentTime;
|
||||
datalayer.system.status.BMS_reset_in_progress = false; // Reset the power removal flag
|
||||
datalayer.system.status.BMS_startup_in_progress = true; // Set the BMS warmup flag
|
||||
|
@ -303,10 +324,11 @@ void handle_BMSpower() {
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void start_bms_reset() {
|
||||
if (periodic_bms_reset || remote_bms_reset) {
|
||||
auto bms_power_pin = esp32hal->BMS_POWER();
|
||||
|
||||
if (!datalayer.system.status.BMS_reset_in_progress) {
|
||||
lastPowerRemovalTime = currentTime; // Record the time when BMS reset was started
|
||||
// we are now resetting at the correct time. We don't need to offset anymore
|
||||
|
@ -319,12 +341,7 @@ void start_bms_reset() {
|
|||
// We try to keep contactors engaged during this pause, and just ramp power down to 0.
|
||||
setBatteryPause(true, false, false, false);
|
||||
|
||||
#ifdef BMS_POWER
|
||||
digitalWrite(BMS_POWER, LOW); // Remove power by setting the BMS power pin to LOW
|
||||
#endif
|
||||
#ifdef BMS_2_POWER
|
||||
digitalWrite(BMS_2_POWER, LOW); // Same for battery 2
|
||||
#endif
|
||||
digitalWrite(bms_power_pin, LOW); // Remove power by setting the BMS power pin to LOW
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
#ifndef _COMM_CONTACTORCONTROL_H_
|
||||
#define _COMM_CONTACTORCONTROL_H_
|
||||
|
||||
#include "../../include.h"
|
||||
|
||||
#include "../../datalayer/datalayer.h"
|
||||
#include "../../devboard/utils/events.h"
|
||||
|
||||
|
@ -36,9 +34,9 @@ void start_bms_reset();
|
|||
*
|
||||
* @param[in] void
|
||||
*
|
||||
* @return void
|
||||
* @return true if contactor init was successful, false otherwise.
|
||||
*/
|
||||
void init_contactors();
|
||||
bool init_contactors();
|
||||
|
||||
/**
|
||||
* @brief Handle contactors
|
||||
|
|
|
@ -1,33 +1,47 @@
|
|||
#include "comm_equipmentstopbutton.h"
|
||||
#include "../../include.h"
|
||||
#include "../../devboard/hal/hal.h"
|
||||
#include "../../devboard/safety/safety.h"
|
||||
#include "USER_SETTINGS.h"
|
||||
|
||||
STOP_BUTTON_BEHAVIOR equipment_stop_behavior = stop_button_default_behavior;
|
||||
|
||||
// Parameters
|
||||
#ifdef EQUIPMENT_STOP_BUTTON
|
||||
const unsigned long equipment_button_long_press_duration =
|
||||
15000; // 15 seconds for long press in case of MOMENTARY_SWITCH
|
||||
const unsigned long equipment_button_debounce_duration = 200; // 200ms for debouncing the button
|
||||
unsigned long timeSincePress = 0; // Variable to store the time since the last press
|
||||
DebouncedButton equipment_stop_button; // Debounced button object
|
||||
#endif // EQUIPMENT_STOP_BUTTON
|
||||
|
||||
// Initialization functions
|
||||
#ifdef EQUIPMENT_STOP_BUTTON
|
||||
void init_equipment_stop_button() {
|
||||
bool init_equipment_stop_button() {
|
||||
if (equipment_stop_behavior == STOP_BUTTON_BEHAVIOR::NOT_CONNECTED) {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto pin = esp32hal->EQUIPMENT_STOP_PIN();
|
||||
if (!esp32hal->alloc_pins("Equipment stop button", pin)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//using external pullup resistors NC
|
||||
pinMode(EQUIPMENT_STOP_PIN, INPUT);
|
||||
pinMode(pin, INPUT);
|
||||
// Initialize the debounced button with NC switch type and equipment_button_debounce_duration debounce time
|
||||
initDebouncedButton(equipment_stop_button, EQUIPMENT_STOP_PIN, NC, equipment_button_debounce_duration);
|
||||
initDebouncedButton(equipment_stop_button, pin, NC, equipment_button_debounce_duration);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif // EQUIPMENT_STOP_BUTTON
|
||||
|
||||
// Main functions
|
||||
|
||||
#ifdef EQUIPMENT_STOP_BUTTON
|
||||
void monitor_equipment_stop_button() {
|
||||
|
||||
if (equipment_stop_behavior == STOP_BUTTON_BEHAVIOR::NOT_CONNECTED) {
|
||||
return;
|
||||
}
|
||||
|
||||
ButtonState changed_state = debounceButton(equipment_stop_button, timeSincePress);
|
||||
|
||||
if (equipment_stop_behavior == LATCHING_SWITCH) {
|
||||
if (equipment_stop_behavior == STOP_BUTTON_BEHAVIOR::LATCHING_SWITCH) {
|
||||
if (changed_state == PRESSED) {
|
||||
// Changed to ON – initiating equipment stop.
|
||||
setBatteryPause(true, false, true);
|
||||
|
@ -35,7 +49,7 @@ void monitor_equipment_stop_button() {
|
|||
// Changed to OFF – ending equipment stop.
|
||||
setBatteryPause(false, false, false);
|
||||
}
|
||||
} else if (equipment_stop_behavior == MOMENTARY_SWITCH) {
|
||||
} else if (equipment_stop_behavior == STOP_BUTTON_BEHAVIOR::MOMENTARY_SWITCH) {
|
||||
if (changed_state == RELEASED) { // button is released
|
||||
|
||||
if (timeSincePress < equipment_button_long_press_duration) {
|
||||
|
@ -48,4 +62,3 @@ void monitor_equipment_stop_button() {
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif // EQUIPMENT_STOP_BUTTON
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue