mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-05 10:49:42 +02:00
Merge branch 'main' into feature/zoe-gen2-double-battery
This commit is contained in:
commit
0566dcecd7
155 changed files with 2923 additions and 1785 deletions
57
.github/workflows/compile-common-image-lilygo.yml
vendored
Normal file
57
.github/workflows/compile-common-image-lilygo.yml
vendored
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
# This is the name of the workflow, visible on GitHub UI.
|
||||||
|
name: 🔋 Compile Common Image for Lilygo
|
||||||
|
|
||||||
|
# Here we tell GitHub when to run the workflow.
|
||||||
|
on:
|
||||||
|
# The workflow is run when a commit is pushed or for a
|
||||||
|
# Pull Request.
|
||||||
|
- push
|
||||||
|
- pull_request
|
||||||
|
|
||||||
|
# This is the list of jobs that will be run concurrently.
|
||||||
|
jobs:
|
||||||
|
# This pre-job is run to skip workflows in case a workflow is already run, i.e. because the workflow is triggered by both push and pull_request
|
||||||
|
skip-duplicate-actions:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
# Map a step output to a job output
|
||||||
|
outputs:
|
||||||
|
should_skip: ${{ steps.skip_check.outputs.should_skip }}
|
||||||
|
steps:
|
||||||
|
- id: skip_check
|
||||||
|
uses: fkirc/skip-duplicate-actions@v5
|
||||||
|
with:
|
||||||
|
# All of these options are optional, so you can remove them if you are happy with the defaults
|
||||||
|
concurrent_skipping: 'never'
|
||||||
|
skip_after_successful_duplicate: 'true'
|
||||||
|
do_not_skip: '["pull_request", "workflow_dispatch", "schedule"]'
|
||||||
|
|
||||||
|
build-common-image:
|
||||||
|
# This is the platform GitHub will use to run our workflow.
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
# Copy USER_SECRETS.TEMPLATE.h to USER_SECRETS.h
|
||||||
|
- name: Copy USER_SECRETS.TEMPLATE.h to USER_SECRETS.h
|
||||||
|
run: cp ./Software/USER_SECRETS.TEMPLATE.h ./Software/USER_SECRETS.h
|
||||||
|
|
||||||
|
# We use the `arduino/setup-arduino-cli` action to install and
|
||||||
|
# configure the Arduino CLI on the system.
|
||||||
|
- name: Setup Arduino CLI
|
||||||
|
uses: arduino/setup-arduino-cli@v2
|
||||||
|
|
||||||
|
# We then install the platform.
|
||||||
|
- name: Install platform
|
||||||
|
run: |
|
||||||
|
arduino-cli core update-index
|
||||||
|
arduino-cli core install esp32:esp32
|
||||||
|
|
||||||
|
- name: Compile Sketch
|
||||||
|
run: arduino-cli compile --output-dir ./ --fqbn esp32:esp32:esp32 --build-property build.partitions=min_spiffs --build-property upload.maximum_size=1966080 --build-property "build.extra_flags=-Wall -Wextra -Wpedantic -Werror -DESP32 -DCOMMON_IMAGE -DHW_LILYGO" ./Software
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
path: Software.ino.bin
|
|
@ -123,6 +123,8 @@ void setup() {
|
||||||
// Start tasks
|
// Start tasks
|
||||||
|
|
||||||
#ifdef MQTT
|
#ifdef MQTT
|
||||||
|
init_mqtt();
|
||||||
|
|
||||||
xTaskCreatePinnedToCore((TaskFunction_t)&mqtt_loop, "mqtt_loop", 4096, NULL, TASK_MQTT_PRIO, &mqtt_loop_task,
|
xTaskCreatePinnedToCore((TaskFunction_t)&mqtt_loop, "mqtt_loop", 4096, NULL, TASK_MQTT_PRIO, &mqtt_loop_task,
|
||||||
WIFI_CORE);
|
WIFI_CORE);
|
||||||
#endif
|
#endif
|
||||||
|
@ -191,8 +193,6 @@ void connectivity_loop(void*) {
|
||||||
void mqtt_loop(void*) {
|
void mqtt_loop(void*) {
|
||||||
esp_task_wdt_add(NULL); // Register this task with WDT
|
esp_task_wdt_add(NULL); // Register this task with WDT
|
||||||
|
|
||||||
init_mqtt();
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
START_TIME_MEASUREMENT(mqtt);
|
START_TIME_MEASUREMENT(mqtt);
|
||||||
mqtt_loop();
|
mqtt_loop();
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define __USER_SETTINGS_H__
|
#define __USER_SETTINGS_H__
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include "src/devboard/utils/types.h"
|
||||||
|
|
||||||
/* This file contains all the battery/inverter protocol settings Battery-Emulator software */
|
/* This file contains all the battery/inverter protocol settings Battery-Emulator software */
|
||||||
/* To switch between batteries/inverters, uncomment a line to enable, comment out to disable. */
|
/* To switch between batteries/inverters, uncomment a line to enable, comment out to disable. */
|
||||||
|
@ -138,7 +139,7 @@
|
||||||
#define HA_AUTODISCOVERY // Enable this line to send Home Assistant autodiscovery messages. If not enabled manual configuration of Home Assitant is required
|
#define HA_AUTODISCOVERY // Enable this line to send Home Assistant autodiscovery messages. If not enabled manual configuration of Home Assitant is required
|
||||||
|
|
||||||
/* Battery settings */
|
/* Battery settings */
|
||||||
// Predefined total energy capacity of the battery in Watt-hours
|
// Predefined total energy capacity of the battery in Watt-hours (updates automatically from battery data when available)
|
||||||
#define BATTERY_WH_MAX 30000
|
#define BATTERY_WH_MAX 30000
|
||||||
// Increases battery life. If true will rescale SOC between the configured min/max-percentage
|
// Increases battery life. If true will rescale SOC between the configured min/max-percentage
|
||||||
#define BATTERY_USE_SCALED_SOC true
|
#define BATTERY_USE_SCALED_SOC true
|
||||||
|
@ -173,7 +174,6 @@
|
||||||
|
|
||||||
/* Do not change any code below this line */
|
/* Do not change any code below this line */
|
||||||
/* Only change battery specific settings above and in "USER_SETTINGS.cpp" */
|
/* Only change battery specific settings above and in "USER_SETTINGS.cpp" */
|
||||||
typedef enum { CAN_NATIVE = 0, CANFD_NATIVE = 1, CAN_ADDON_MCP2515 = 2, CANFD_ADDON_MCP2518 = 3 } CAN_Interface;
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
CAN_Interface battery;
|
CAN_Interface battery;
|
||||||
CAN_Interface inverter;
|
CAN_Interface inverter;
|
||||||
|
@ -181,7 +181,6 @@ typedef struct {
|
||||||
CAN_Interface charger;
|
CAN_Interface charger;
|
||||||
CAN_Interface shunt;
|
CAN_Interface shunt;
|
||||||
} CAN_Configuration;
|
} CAN_Configuration;
|
||||||
extern const char* getCANInterfaceName(CAN_Interface interface);
|
|
||||||
extern volatile CAN_Configuration can_config;
|
extern volatile CAN_Configuration can_config;
|
||||||
extern volatile uint8_t AccessPointEnabled;
|
extern volatile uint8_t AccessPointEnabled;
|
||||||
extern const uint8_t wifi_channel;
|
extern const uint8_t wifi_channel;
|
||||||
|
|
|
@ -4,16 +4,233 @@
|
||||||
#include "CanBattery.h"
|
#include "CanBattery.h"
|
||||||
#include "RS485Battery.h"
|
#include "RS485Battery.h"
|
||||||
|
|
||||||
// These functions adapt the old C-style global functions battery-API to the
|
#if !defined(COMMON_IMAGE) && !defined(SELECTED_BATTERY_CLASS)
|
||||||
// object-oriented battery API.
|
#error No battery selected! Choose one from the USER_SETTINGS.h file
|
||||||
|
#endif
|
||||||
// The instantiated class is defined by the pre-compiler define
|
|
||||||
// to support battery class selection at compile-time
|
|
||||||
#ifdef SELECTED_BATTERY_CLASS
|
|
||||||
|
|
||||||
Battery* battery = nullptr;
|
Battery* battery = nullptr;
|
||||||
Battery* battery2 = nullptr;
|
Battery* battery2 = nullptr;
|
||||||
|
|
||||||
|
std::vector<BatteryType> supported_battery_types() {
|
||||||
|
std::vector<BatteryType> types;
|
||||||
|
|
||||||
|
for (int i = 0; i < (int)BatteryType::Highest; i++) {
|
||||||
|
types.push_back((BatteryType)i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return types;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern const char* name_for_battery_type(BatteryType type) {
|
||||||
|
switch (type) {
|
||||||
|
case BatteryType::None:
|
||||||
|
return "None";
|
||||||
|
case BatteryType::BmwI3:
|
||||||
|
return BmwI3Battery::Name;
|
||||||
|
case BatteryType::BmwIx:
|
||||||
|
return BmwIXBattery::Name;
|
||||||
|
case BatteryType::BoltAmpera:
|
||||||
|
return BoltAmperaBattery::Name;
|
||||||
|
case BatteryType::BydAtto3:
|
||||||
|
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:
|
||||||
|
return FoxessBattery::Name;
|
||||||
|
case BatteryType::GeelyGeometryC:
|
||||||
|
return GeelyGeometryCBattery::Name;
|
||||||
|
case BatteryType::OrionBms:
|
||||||
|
return OrionBms::Name;
|
||||||
|
case BatteryType::Sono:
|
||||||
|
return SonoBattery::Name;
|
||||||
|
case BatteryType::StellantisEcmp:
|
||||||
|
return EcmpBattery::Name;
|
||||||
|
case BatteryType::ImievCZeroIon:
|
||||||
|
return ImievCZeroIonBattery::Name;
|
||||||
|
case BatteryType::JaguarIpace:
|
||||||
|
return JaguarIpaceBattery::Name;
|
||||||
|
case BatteryType::KiaEGmp:
|
||||||
|
return KiaEGmpBattery::Name;
|
||||||
|
case BatteryType::KiaHyundai64:
|
||||||
|
return KiaHyundai64Battery::Name;
|
||||||
|
case BatteryType::KiaHyundaiHybrid:
|
||||||
|
return KiaHyundaiHybridBattery::Name;
|
||||||
|
case BatteryType::Meb:
|
||||||
|
return MebBattery::Name;
|
||||||
|
case BatteryType::Mg5:
|
||||||
|
return Mg5Battery::Name;
|
||||||
|
case BatteryType::NissanLeaf:
|
||||||
|
return NissanLeafBattery::Name;
|
||||||
|
case BatteryType::Pylon:
|
||||||
|
return PylonBattery::Name;
|
||||||
|
case BatteryType::DalyBms:
|
||||||
|
return DalyBms::Name;
|
||||||
|
case BatteryType::RjxzsBms:
|
||||||
|
return RjxzsBms::Name;
|
||||||
|
case BatteryType::RangeRoverPhev:
|
||||||
|
return RangeRoverPhevBattery::Name;
|
||||||
|
case BatteryType::RenaultKangoo:
|
||||||
|
return RenaultKangooBattery::Name;
|
||||||
|
case BatteryType::RenaultTwizy:
|
||||||
|
return RenaultTwizyBattery::Name;
|
||||||
|
case BatteryType::RenaultZoe1:
|
||||||
|
return RenaultZoeGen1Battery::Name;
|
||||||
|
case BatteryType::RenaultZoe2:
|
||||||
|
return RenaultZoeGen2Battery::Name;
|
||||||
|
case BatteryType::SantaFePhev:
|
||||||
|
return SantaFePhevBattery::Name;
|
||||||
|
case BatteryType::SimpBms:
|
||||||
|
return SimpBmsBattery::Name;
|
||||||
|
case BatteryType::TeslaModel3Y:
|
||||||
|
return TeslaModel3YBattery::Name;
|
||||||
|
case BatteryType::TeslaModelSX:
|
||||||
|
return TeslaModelSXBattery::Name;
|
||||||
|
case BatteryType::TestFake:
|
||||||
|
return TestFakeBattery::Name;
|
||||||
|
case BatteryType::VolvoSpa:
|
||||||
|
return VolvoSpaBattery::Name;
|
||||||
|
case BatteryType::VolvoSpaHybrid:
|
||||||
|
return VolvoSpaHybridBattery::Name;
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef COMMON_IMAGE
|
||||||
|
#ifdef SELECTED_BATTERY_CLASS
|
||||||
|
#error "Compile time SELECTED_BATTERY_CLASS should not be defined with COMMON_IMAGE"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
BatteryType user_selected_battery_type = BatteryType::NissanLeaf;
|
||||||
|
bool user_selected_second_battery = false;
|
||||||
|
|
||||||
|
Battery* create_battery(BatteryType type) {
|
||||||
|
switch (type) {
|
||||||
|
case BatteryType::None:
|
||||||
|
return nullptr;
|
||||||
|
case BatteryType::BmwI3:
|
||||||
|
return new BmwI3Battery();
|
||||||
|
case BatteryType::BmwIx:
|
||||||
|
return new BmwIXBattery();
|
||||||
|
case BatteryType::BoltAmpera:
|
||||||
|
return new BoltAmperaBattery();
|
||||||
|
case BatteryType::BydAtto3:
|
||||||
|
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:
|
||||||
|
return new FoxessBattery();
|
||||||
|
case BatteryType::GeelyGeometryC:
|
||||||
|
return new GeelyGeometryCBattery();
|
||||||
|
case BatteryType::OrionBms:
|
||||||
|
return new OrionBms();
|
||||||
|
case BatteryType::Sono:
|
||||||
|
return new SonoBattery();
|
||||||
|
case BatteryType::StellantisEcmp:
|
||||||
|
return new EcmpBattery();
|
||||||
|
case BatteryType::ImievCZeroIon:
|
||||||
|
return new ImievCZeroIonBattery();
|
||||||
|
case BatteryType::JaguarIpace:
|
||||||
|
return new JaguarIpaceBattery();
|
||||||
|
case BatteryType::KiaEGmp:
|
||||||
|
return new KiaEGmpBattery();
|
||||||
|
case BatteryType::KiaHyundai64:
|
||||||
|
return new KiaHyundai64Battery();
|
||||||
|
case BatteryType::KiaHyundaiHybrid:
|
||||||
|
return new KiaHyundaiHybridBattery();
|
||||||
|
case BatteryType::Meb:
|
||||||
|
return new MebBattery();
|
||||||
|
case BatteryType::Mg5:
|
||||||
|
return new Mg5Battery();
|
||||||
|
case BatteryType::NissanLeaf:
|
||||||
|
return new NissanLeafBattery();
|
||||||
|
case BatteryType::Pylon:
|
||||||
|
return new PylonBattery();
|
||||||
|
case BatteryType::DalyBms:
|
||||||
|
return new DalyBms();
|
||||||
|
case BatteryType::RjxzsBms:
|
||||||
|
return new RjxzsBms();
|
||||||
|
case BatteryType::RangeRoverPhev:
|
||||||
|
return new RangeRoverPhevBattery();
|
||||||
|
case BatteryType::RenaultKangoo:
|
||||||
|
return new RenaultKangooBattery();
|
||||||
|
case BatteryType::RenaultTwizy:
|
||||||
|
return new RenaultTwizyBattery();
|
||||||
|
case BatteryType::RenaultZoe1:
|
||||||
|
return new RenaultZoeGen1Battery();
|
||||||
|
case BatteryType::RenaultZoe2:
|
||||||
|
return new RenaultZoeGen2Battery();
|
||||||
|
case BatteryType::SantaFePhev:
|
||||||
|
return new SantaFePhevBattery();
|
||||||
|
case BatteryType::SimpBms:
|
||||||
|
return new SimpBmsBattery();
|
||||||
|
case BatteryType::TeslaModel3Y:
|
||||||
|
return new TeslaModel3YBattery();
|
||||||
|
case BatteryType::TeslaModelSX:
|
||||||
|
return new TeslaModelSXBattery();
|
||||||
|
case BatteryType::TestFake:
|
||||||
|
return new TestFakeBattery();
|
||||||
|
case BatteryType::VolvoSpa:
|
||||||
|
return new VolvoSpaBattery();
|
||||||
|
case BatteryType::VolvoSpaHybrid:
|
||||||
|
return new VolvoSpaHybridBattery();
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_battery() {
|
||||||
|
if (battery) {
|
||||||
|
// Let's not create the battery again.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
battery = create_battery(user_selected_battery_type);
|
||||||
|
|
||||||
|
if (battery) {
|
||||||
|
battery->setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user_selected_second_battery && !battery2) {
|
||||||
|
switch (user_selected_battery_type) {
|
||||||
|
case BatteryType::NissanLeaf:
|
||||||
|
battery2 = new NissanLeafBattery(&datalayer.battery2, nullptr, can_config.battery_double);
|
||||||
|
break;
|
||||||
|
case BatteryType::BmwI3:
|
||||||
|
battery2 = new BmwI3Battery(&datalayer.battery2, &datalayer.system.status.battery2_allowed_contactor_closing,
|
||||||
|
can_config.battery_double, WUP_PIN2);
|
||||||
|
break;
|
||||||
|
case BatteryType::KiaHyundai64:
|
||||||
|
battery2 = new KiaHyundai64Battery(&datalayer.battery2, &datalayer_extended.KiaHyundai64_2,
|
||||||
|
&datalayer.system.status.battery2_allowed_contactor_closing,
|
||||||
|
can_config.battery_double);
|
||||||
|
case BatteryType::SantaFePhev:
|
||||||
|
battery2 = new SantaFePhevBattery(&datalayer.battery2, can_config.battery_double);
|
||||||
|
break;
|
||||||
|
case BatteryType::TestFake:
|
||||||
|
battery2 = new TestFakeBattery(&datalayer.battery2, can_config.battery_double);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (battery2) {
|
||||||
|
battery2->setup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else // Battery selection has been made at build-time
|
||||||
|
|
||||||
void setup_battery() {
|
void setup_battery() {
|
||||||
// Instantiate the battery only once just in case this function gets called multiple times.
|
// Instantiate the battery only once just in case this function gets called multiple times.
|
||||||
if (battery == nullptr) {
|
if (battery == nullptr) {
|
||||||
|
@ -40,5 +257,4 @@ void setup_battery() {
|
||||||
battery2->setup();
|
battery2->setup();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -11,151 +11,45 @@ extern Battery* battery2;
|
||||||
|
|
||||||
void setup_can_shunt();
|
void setup_can_shunt();
|
||||||
|
|
||||||
#ifdef BMW_SBOX
|
|
||||||
#include "BMW-SBOX.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef BMW_I3_BATTERY
|
|
||||||
#include "BMW-I3-BATTERY.h"
|
#include "BMW-I3-BATTERY.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef BMW_IX_BATTERY
|
|
||||||
#include "BMW-IX-BATTERY.h"
|
#include "BMW-IX-BATTERY.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef BMW_PHEV_BATTERY
|
|
||||||
#include "BMW-PHEV-BATTERY.h"
|
#include "BMW-PHEV-BATTERY.h"
|
||||||
#endif
|
#include "BMW-SBOX.h"
|
||||||
|
|
||||||
#ifdef BOLT_AMPERA_BATTERY
|
|
||||||
#include "BOLT-AMPERA-BATTERY.h"
|
#include "BOLT-AMPERA-BATTERY.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef BYD_ATTO_3_BATTERY
|
|
||||||
#include "BYD-ATTO-3-BATTERY.h"
|
#include "BYD-ATTO-3-BATTERY.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CELLPOWER_BMS
|
|
||||||
#include "CELLPOWER-BMS.h"
|
#include "CELLPOWER-BMS.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CHADEMO_BATTERY
|
|
||||||
#include "CHADEMO-BATTERY.h"
|
#include "CHADEMO-BATTERY.h"
|
||||||
#include "CHADEMO-SHUNTS.h"
|
#include "CHADEMO-SHUNTS.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CMFA_EV_BATTERY
|
|
||||||
#include "CMFA-EV-BATTERY.h"
|
#include "CMFA-EV-BATTERY.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef FOXESS_BATTERY
|
|
||||||
#include "FOXESS-BATTERY.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef GEELY_GEOMETRY_C_BATTERY
|
|
||||||
#include "GEELY-GEOMETRY-C-BATTERY.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef ORION_BMS
|
|
||||||
#include "ORION-BMS.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef SONO_BATTERY
|
|
||||||
#include "SONO-BATTERY.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef STELLANTIS_ECMP_BATTERY
|
|
||||||
#include "ECMP-BATTERY.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef IMIEV_CZERO_ION_BATTERY
|
|
||||||
#include "IMIEV-CZERO-ION-BATTERY.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef JAGUAR_IPACE_BATTERY
|
|
||||||
#include "JAGUAR-IPACE-BATTERY.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef KIA_E_GMP_BATTERY
|
|
||||||
#include "KIA-E-GMP-BATTERY.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef KIA_HYUNDAI_64_BATTERY
|
|
||||||
#include "KIA-HYUNDAI-64-BATTERY.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef KIA_HYUNDAI_HYBRID_BATTERY
|
|
||||||
#include "KIA-HYUNDAI-HYBRID-BATTERY.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef MEB_BATTERY
|
|
||||||
#include "MEB-BATTERY.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef MG_5_BATTERY
|
|
||||||
#include "MG-5-BATTERY.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef NISSAN_LEAF_BATTERY
|
|
||||||
#include "NISSAN-LEAF-BATTERY.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef PYLON_BATTERY
|
|
||||||
#include "PYLON-BATTERY.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef DALY_BMS
|
|
||||||
#include "DALY-BMS.h"
|
#include "DALY-BMS.h"
|
||||||
#endif
|
#include "ECMP-BATTERY.h"
|
||||||
|
#include "FOXESS-BATTERY.h"
|
||||||
#ifdef RJXZS_BMS
|
#include "GEELY-GEOMETRY-C-BATTERY.h"
|
||||||
#include "RJXZS-BMS.h"
|
#include "IMIEV-CZERO-ION-BATTERY.h"
|
||||||
#endif
|
#include "JAGUAR-IPACE-BATTERY.h"
|
||||||
|
#include "KIA-E-GMP-BATTERY.h"
|
||||||
#ifdef RANGE_ROVER_PHEV_BATTERY
|
#include "KIA-HYUNDAI-64-BATTERY.h"
|
||||||
|
#include "KIA-HYUNDAI-HYBRID-BATTERY.h"
|
||||||
|
#include "MEB-BATTERY.h"
|
||||||
|
#include "MG-5-BATTERY.h"
|
||||||
|
#include "NISSAN-LEAF-BATTERY.h"
|
||||||
|
#include "ORION-BMS.h"
|
||||||
|
#include "PYLON-BATTERY.h"
|
||||||
#include "RANGE-ROVER-PHEV-BATTERY.h"
|
#include "RANGE-ROVER-PHEV-BATTERY.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef RENAULT_KANGOO_BATTERY
|
|
||||||
#include "RENAULT-KANGOO-BATTERY.h"
|
#include "RENAULT-KANGOO-BATTERY.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef RENAULT_TWIZY_BATTERY
|
|
||||||
#include "RENAULT-TWIZY.h"
|
#include "RENAULT-TWIZY.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef RENAULT_ZOE_GEN1_BATTERY
|
|
||||||
#include "RENAULT-ZOE-GEN1-BATTERY.h"
|
#include "RENAULT-ZOE-GEN1-BATTERY.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef RENAULT_ZOE_GEN2_BATTERY
|
|
||||||
#include "RENAULT-ZOE-GEN2-BATTERY.h"
|
#include "RENAULT-ZOE-GEN2-BATTERY.h"
|
||||||
#endif
|
#include "RJXZS-BMS.h"
|
||||||
|
|
||||||
#ifdef SANTA_FE_PHEV_BATTERY
|
|
||||||
#include "SANTA-FE-PHEV-BATTERY.h"
|
#include "SANTA-FE-PHEV-BATTERY.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef SIMPBMS_BATTERY
|
|
||||||
#include "SIMPBMS-BATTERY.h"
|
#include "SIMPBMS-BATTERY.h"
|
||||||
#endif
|
#include "SONO-BATTERY.h"
|
||||||
|
|
||||||
#if defined(TESLA_MODEL_SX_BATTERY) || defined(TESLA_MODEL_3Y_BATTERY)
|
|
||||||
#define TESLA_BATTERY
|
|
||||||
#include "TESLA-BATTERY.h"
|
#include "TESLA-BATTERY.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef TEST_FAKE_BATTERY
|
|
||||||
#include "TEST-FAKE-BATTERY.h"
|
#include "TEST-FAKE-BATTERY.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef VOLVO_SPA_BATTERY
|
|
||||||
#include "VOLVO-SPA-BATTERY.h"
|
#include "VOLVO-SPA-BATTERY.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef VOLVO_SPA_HYBRID_BATTERY
|
|
||||||
#include "VOLVO-SPA-HYBRID-BATTERY.h"
|
#include "VOLVO-SPA-HYBRID-BATTERY.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
void setup_battery(void);
|
void setup_battery(void);
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
#include "../include.h"
|
#include "BMW-I3-BATTERY.h"
|
||||||
#ifdef BMW_I3_BATTERY
|
|
||||||
#include "../communication/can/comm_can.h"
|
#include "../communication/can/comm_can.h"
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../datalayer/datalayer_extended.h"
|
#include "../datalayer/datalayer_extended.h"
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
#include "BMW-I3-BATTERY.h"
|
#include "../include.h"
|
||||||
|
|
||||||
/* Do not change code below unless you are sure what you are doing */
|
/* Do not change code below unless you are sure what you are doing */
|
||||||
|
|
||||||
|
@ -34,7 +33,7 @@ static uint8_t calculateCRC(CAN_frame rx_frame, uint8_t length, uint8_t initial_
|
||||||
return crc;
|
return crc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t increment_alive_counter(uint8_t counter) {
|
uint8_t BmwI3Battery::increment_alive_counter(uint8_t counter) {
|
||||||
counter++;
|
counter++;
|
||||||
if (counter > ALIVE_MAX_VALUE) {
|
if (counter > ALIVE_MAX_VALUE) {
|
||||||
counter = 0;
|
counter = 0;
|
||||||
|
@ -509,7 +508,7 @@ void BmwI3Battery::transmit_can(unsigned long currentMillis) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void BmwI3Battery::setup(void) { // Performs one time setup at startup
|
void BmwI3Battery::setup(void) { // Performs one time setup at startup
|
||||||
strncpy(datalayer.system.info.battery_protocol, "BMW i3", 63);
|
strncpy(datalayer.system.info.battery_protocol, Name, 63);
|
||||||
datalayer.system.info.battery_protocol[63] = '\0';
|
datalayer.system.info.battery_protocol[63] = '\0';
|
||||||
|
|
||||||
//Before we have started up and detected which battery is in use, use 60AH values
|
//Before we have started up and detected which battery is in use, use 60AH values
|
||||||
|
@ -525,5 +524,3 @@ void BmwI3Battery::setup(void) { // Performs one time setup at startup
|
||||||
pinMode(wakeup_pin, OUTPUT);
|
pinMode(wakeup_pin, OUTPUT);
|
||||||
digitalWrite(wakeup_pin, HIGH); // Wake up the battery
|
digitalWrite(wakeup_pin, HIGH); // Wake up the battery
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -7,8 +7,9 @@
|
||||||
#include "BMW-I3-HTML.h"
|
#include "BMW-I3-HTML.h"
|
||||||
#include "CanBattery.h"
|
#include "CanBattery.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#ifdef BMW_I3_BATTERY
|
||||||
#define SELECTED_BATTERY_CLASS BmwI3Battery
|
#define SELECTED_BATTERY_CLASS BmwI3Battery
|
||||||
|
#endif
|
||||||
|
|
||||||
class BmwI3Battery : public CanBattery {
|
class BmwI3Battery : public CanBattery {
|
||||||
public:
|
public:
|
||||||
|
@ -20,7 +21,6 @@ class BmwI3Battery : public CanBattery {
|
||||||
contactor_closing_allowed = contactor_closing_allowed_ptr;
|
contactor_closing_allowed = contactor_closing_allowed_ptr;
|
||||||
allows_contactor_closing = nullptr;
|
allows_contactor_closing = nullptr;
|
||||||
wakeup_pin = wakeup;
|
wakeup_pin = wakeup;
|
||||||
*allows_contactor_closing = true;
|
|
||||||
|
|
||||||
//Init voltage to 0 to allow contactor check to operate without fear of default values colliding
|
//Init voltage to 0 to allow contactor check to operate without fear of default values colliding
|
||||||
battery_volts = 0;
|
battery_volts = 0;
|
||||||
|
@ -38,6 +38,7 @@ class BmwI3Battery : public CanBattery {
|
||||||
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
||||||
virtual void update_values();
|
virtual void update_values();
|
||||||
virtual void transmit_can(unsigned long currentMillis);
|
virtual void transmit_can(unsigned long currentMillis);
|
||||||
|
static constexpr char* Name = "BMW i3";
|
||||||
|
|
||||||
BatteryHtmlRenderer& get_status_renderer() { return renderer; }
|
BatteryHtmlRenderer& get_status_renderer() { return renderer; }
|
||||||
|
|
||||||
|
@ -79,7 +80,9 @@ class BmwI3Battery : public CanBattery {
|
||||||
unsigned long previousMillis5000 = 0; // will store last time a 5000ms CAN Message was send
|
unsigned long previousMillis5000 = 0; // will store last time a 5000ms CAN Message was send
|
||||||
unsigned long previousMillis10000 = 0; // will store last time a 10000ms CAN Message was send
|
unsigned long previousMillis10000 = 0; // will store last time a 10000ms CAN Message was send
|
||||||
|
|
||||||
#define ALIVE_MAX_VALUE 14 // BMW CAN messages contain alive counter, goes from 0...14
|
static const int ALIVE_MAX_VALUE = 14; // BMW CAN messages contain alive counter, goes from 0...14
|
||||||
|
|
||||||
|
uint8_t increment_alive_counter(uint8_t counter);
|
||||||
|
|
||||||
enum BatterySize { BATTERY_60AH, BATTERY_94AH, BATTERY_120AH };
|
enum BatterySize { BATTERY_60AH, BATTERY_94AH, BATTERY_120AH };
|
||||||
BatterySize detectedBattery = BATTERY_60AH;
|
BatterySize detectedBattery = BATTERY_60AH;
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
#include "../include.h"
|
#include "BMW-IX-BATTERY.h"
|
||||||
#ifdef BMW_IX_BATTERY
|
|
||||||
#include "../communication/can/comm_can.h"
|
#include "../communication/can/comm_can.h"
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../datalayer/datalayer_extended.h"
|
#include "../datalayer/datalayer_extended.h"
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
#include "BMW-IX-BATTERY.h"
|
#include "../include.h"
|
||||||
|
|
||||||
// Function to check if a value has gone stale over a specified time period
|
// 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) {
|
bool BmwIXBattery::isStale(int16_t currentValue, uint16_t& lastValue, unsigned long& lastChangeTime) {
|
||||||
|
@ -475,7 +474,7 @@ void BmwIXBattery::transmit_can(unsigned long currentMillis) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void BmwIXBattery::setup(void) { // Performs one time setup at startup
|
void BmwIXBattery::setup(void) { // Performs one time setup at startup
|
||||||
strncpy(datalayer.system.info.battery_protocol, "BMW iX and i4-7 platform", 63);
|
strncpy(datalayer.system.info.battery_protocol, Name, 63);
|
||||||
datalayer.system.info.battery_protocol[63] = '\0';
|
datalayer.system.info.battery_protocol[63] = '\0';
|
||||||
|
|
||||||
//Reset Battery at bootup
|
//Reset Battery at bootup
|
||||||
|
@ -696,5 +695,3 @@ void BmwIXBattery::HandleBmwIxOpenContactorsRequest(uint16_t counter_10ms) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // BMW_IX_BATTERY
|
|
||||||
|
|
|
@ -5,8 +5,9 @@
|
||||||
#include "BMW-IX-HTML.h"
|
#include "BMW-IX-HTML.h"
|
||||||
#include "CanBattery.h"
|
#include "CanBattery.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#ifdef BMW_IX_BATTERY
|
||||||
#define SELECTED_BATTERY_CLASS BmwIXBattery
|
#define SELECTED_BATTERY_CLASS BmwIXBattery
|
||||||
|
#endif
|
||||||
|
|
||||||
class BmwIXBattery : public CanBattery {
|
class BmwIXBattery : public CanBattery {
|
||||||
public:
|
public:
|
||||||
|
@ -21,6 +22,8 @@ class BmwIXBattery : public CanBattery {
|
||||||
void request_open_contactors() { datalayer_extended.bmwix.UserRequestContactorOpen = true; }
|
void request_open_contactors() { datalayer_extended.bmwix.UserRequestContactorOpen = true; }
|
||||||
void request_close_contactors() { datalayer_extended.bmwix.UserRequestContactorClose = true; }
|
void request_close_contactors() { datalayer_extended.bmwix.UserRequestContactorClose = true; }
|
||||||
|
|
||||||
|
static constexpr char* Name = "BMW iX and i4-7 platform";
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BmwIXHtmlRenderer renderer;
|
BmwIXHtmlRenderer renderer;
|
||||||
static const int MAX_PACK_VOLTAGE_DV = 4650; //4650 = 465.0V
|
static const int MAX_PACK_VOLTAGE_DV = 4650; //4650 = 465.0V
|
||||||
|
|
|
@ -25,13 +25,37 @@ class BmwIXHtmlRenderer : public BatteryHtmlRenderer {
|
||||||
content += "<h4>Allowed Charge Power: " + String(datalayer.battery.status.max_charge_power_W) + " W</h4>";
|
content += "<h4>Allowed Charge Power: " + String(datalayer.battery.status.max_charge_power_W) + " W</h4>";
|
||||||
content += "<h4>T30 Terminal Voltage: " + String(datalayer_extended.bmwix.T30_Voltage) + " mV</h4>";
|
content += "<h4>T30 Terminal Voltage: " + String(datalayer_extended.bmwix.T30_Voltage) + " mV</h4>";
|
||||||
content += "<h4>Detected Cell Count: " + String(datalayer.battery.info.number_of_cells) + "</h4>";
|
content += "<h4>Detected Cell Count: " + String(datalayer.battery.info.number_of_cells) + "</h4>";
|
||||||
static const char* balanceText[5] = {"0 No balancing mode active", "1 Voltage-Controlled Balancing Mode",
|
content += "<h4>Balancing: ";
|
||||||
"2 Time-Controlled Balancing Mode with Demand Calculation at End of Charging",
|
switch (datalayer_extended.bmwix.balancing_status) {
|
||||||
"3 Time-Controlled Balancing Mode with Demand Calculation at Resting Voltage",
|
case 0:
|
||||||
"4 No balancing mode active, qualifier invalid"};
|
content += "0 No balancing mode active</h4>";
|
||||||
content += "<h4>Balancing: " + String((balanceText[datalayer_extended.bmwix.balancing_status])) + "</h4>";
|
break;
|
||||||
static const char* hvilText[2] = {"Error (Loop Open)", "OK (Loop Closed)"};
|
case 1:
|
||||||
content += "<h4>HVIL Status: " + String(hvilText[datalayer_extended.bmwix.hvil_status]) + "</h4>";
|
content += "1 Voltage-Controlled Balancing Mode</h4>";
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
content += "2 Time-Controlled Balancing Mode with Demand Calculation at End of Charging</h4>";
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
content += "3 Time-Controlled Balancing Mode with Demand Calculation at Resting Voltage</h4>";
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
content += "4 No balancing mode active, qualifier invalid</h4>";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
content += "Unknown</h4>";
|
||||||
|
}
|
||||||
|
content += "<h4>HVIL Status: ";
|
||||||
|
switch (datalayer_extended.bmwix.hvil_status) {
|
||||||
|
case 0:
|
||||||
|
content += "Error (Loop Open)</h4>";
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
content += "OK (Loop Closed)</h4>";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
content += "Unknown</h4>";
|
||||||
|
}
|
||||||
content += "<h4>BMS Uptime: " + String(datalayer_extended.bmwix.bms_uptime) + " seconds</h4>";
|
content += "<h4>BMS Uptime: " + String(datalayer_extended.bmwix.bms_uptime) + " seconds</h4>";
|
||||||
content += "<h4>BMS Allowed Charge Amps: " + String(datalayer_extended.bmwix.allowable_charge_amps) + " A</h4>";
|
content += "<h4>BMS Allowed Charge Amps: " + String(datalayer_extended.bmwix.allowable_charge_amps) + " A</h4>";
|
||||||
content +=
|
content +=
|
||||||
|
@ -41,11 +65,66 @@ class BmwIXHtmlRenderer : public BatteryHtmlRenderer {
|
||||||
content += "<h4>Isolation Positive: " + String(datalayer_extended.bmwix.iso_safety_positive) + " kOhm</h4>";
|
content += "<h4>Isolation Positive: " + String(datalayer_extended.bmwix.iso_safety_positive) + " kOhm</h4>";
|
||||||
content += "<h4>Isolation Negative: " + String(datalayer_extended.bmwix.iso_safety_negative) + " kOhm</h4>";
|
content += "<h4>Isolation Negative: " + String(datalayer_extended.bmwix.iso_safety_negative) + " kOhm</h4>";
|
||||||
content += "<h4>Isolation Parallel: " + String(datalayer_extended.bmwix.iso_safety_parallel) + " kOhm</h4>";
|
content += "<h4>Isolation Parallel: " + String(datalayer_extended.bmwix.iso_safety_parallel) + " kOhm</h4>";
|
||||||
static const char* pyroText[5] = {"0 Value Invalid", "1 Successfully Blown", "2 Disconnected",
|
content += "<h4>Pyro Status PSS1: ";
|
||||||
"3 Not Activated - Pyro Intact", "4 Unknown"};
|
switch (datalayer_extended.bmwix.pyro_status_pss1) {
|
||||||
content += "<h4>Pyro Status PSS1: " + String((pyroText[datalayer_extended.bmwix.pyro_status_pss1])) + "</h4>";
|
case 0:
|
||||||
content += "<h4>Pyro Status PSS4: " + String((pyroText[datalayer_extended.bmwix.pyro_status_pss4])) + "</h4>";
|
content += "0 Value Invalid</h4>";
|
||||||
content += "<h4>Pyro Status PSS6: " + String((pyroText[datalayer_extended.bmwix.pyro_status_pss6])) + "</h4>";
|
break;
|
||||||
|
case 1:
|
||||||
|
content += "1 Successfully Blown</h4>";
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
content += "2 Disconnected</h4>";
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
content += "3 Not Activated - Pyro Intact</h4>";
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
content += "4 Unknown</h4>";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
content += "Unknown</h4>";
|
||||||
|
}
|
||||||
|
content += "<h4>Pyro Status PSS4: ";
|
||||||
|
switch (datalayer_extended.bmwix.pyro_status_pss4) {
|
||||||
|
case 0:
|
||||||
|
content += "0 Value Invalid</h4>";
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
content += "1 Successfully Blown</h4>";
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
content += "2 Disconnected</h4>";
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
content += "3 Not Activated - Pyro Intact</h4>";
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
content += "4 Unknown</h4>";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
content += "Unknown</h4>";
|
||||||
|
}
|
||||||
|
content += "<h4>Pyro Status PSS6: ";
|
||||||
|
switch (datalayer_extended.bmwix.pyro_status_pss6) {
|
||||||
|
case 0:
|
||||||
|
content += "0 Value Invalid</h4>";
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
content += "1 Successfully Blown</h4>";
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
content += "2 Disconnected</h4>";
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
content += "3 Not Activated - Pyro Intact</h4>";
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
content += "4 Unknown</h4>";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
content += "Unknown</h4>";
|
||||||
|
}
|
||||||
|
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
#include "../include.h"
|
#include "BMW-PHEV-BATTERY.h"
|
||||||
#ifdef BMW_PHEV_BATTERY
|
|
||||||
#include "../communication/can/comm_can.h"
|
#include "../communication/can/comm_can.h"
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../datalayer/datalayer_extended.h"
|
#include "../datalayer/datalayer_extended.h"
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
#include "BMW-PHEV-BATTERY.h"
|
#include "../include.h"
|
||||||
|
|
||||||
const unsigned char crc8_table[256] =
|
const unsigned char crc8_table[256] =
|
||||||
{ // CRC8_SAE_J1850_ZER0 formula,0x1D Poly,initial value 0x3F,Final XOR value varies
|
{ // CRC8_SAE_J1850_ZER0 formula,0x1D Poly,initial value 0x3F,Final XOR value varies
|
||||||
|
@ -714,5 +713,3 @@ void BmwPhevBattery::setup(void) { // Performs one time setup at startup
|
||||||
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
||||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
datalayer.system.status.battery_allows_contactor_closing = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -5,8 +5,9 @@
|
||||||
#include "BMW-PHEV-HTML.h"
|
#include "BMW-PHEV-HTML.h"
|
||||||
#include "CanBattery.h"
|
#include "CanBattery.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#ifdef BMW_PHEV_BATTERY
|
||||||
#define SELECTED_BATTERY_CLASS BmwPhevBattery
|
#define SELECTED_BATTERY_CLASS BmwPhevBattery
|
||||||
|
#endif
|
||||||
|
|
||||||
class BmwPhevBattery : public CanBattery {
|
class BmwPhevBattery : public CanBattery {
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -15,90 +15,203 @@ class BmwPhevHtmlRenderer : public BatteryHtmlRenderer {
|
||||||
" dV</h4>";
|
" dV</h4>";
|
||||||
content += "<h4>Allowed Discharge Power: " + String(datalayer.battery.status.max_discharge_power_W) + " W</h4>";
|
content += "<h4>Allowed Discharge Power: " + String(datalayer.battery.status.max_discharge_power_W) + " W</h4>";
|
||||||
content += "<h4>Allowed Charge Power: " + String(datalayer.battery.status.max_charge_power_W) + " W</h4>";
|
content += "<h4>Allowed Charge Power: " + String(datalayer.battery.status.max_charge_power_W) + " W</h4>";
|
||||||
static const char* balanceText[5] = {"0 Balancing Inactive - Balancing not needed", "1 Balancing Active",
|
content += "<h4>Balancing: ";
|
||||||
"2 Balancing Inactive - Cells not in rest break wait 10mins",
|
switch (datalayer_extended.bmwphev.balancing_status) {
|
||||||
"3 Balancing Inactive", "4 Unknown"};
|
case 0:
|
||||||
content += "<h4>Balancing: " + String((balanceText[datalayer_extended.bmwphev.balancing_status])) + "</h4>";
|
content += String("0 Balancing Inactive - Balancing not needed</h4>");
|
||||||
static const char* pyroText[5] = {"0 Value Invalid", "1 Successfully Blown", "2 Disconnected",
|
break;
|
||||||
"3 Not Activated - Pyro Intact", "4 Unknown"};
|
case 1:
|
||||||
static const char* statusText[16] = {
|
content += String("1 Balancing Active</h4>");
|
||||||
"Not evaluated", "OK", "Error!", "Invalid signal", "", "", "", "", "", "", "", "", "", "", "", ""};
|
break;
|
||||||
content += "<h4>Interlock: " + String(statusText[datalayer_extended.bmwphev.ST_interlock]) + "</h4>";
|
case 2:
|
||||||
content += "<h4>Isolation external: " + String(statusText[datalayer_extended.bmwphev.ST_iso_ext]) + "</h4>";
|
content += String("2 Balancing Inactive - Cells not in rest break wait 10mins</h4>");
|
||||||
content += "<h4>Isolation internal: " + String(statusText[datalayer_extended.bmwphev.ST_iso_int]) + "</h4>";
|
break;
|
||||||
content += "<h4>Isolation: " + String(statusText[datalayer_extended.bmwphev.ST_isolation]) + "</h4>";
|
case 3:
|
||||||
content += "<h4>Cooling valve: " + String(statusText[datalayer_extended.bmwphev.ST_valve_cooling]) + "</h4>";
|
content += String("3 Balancing Inactive</h4>");
|
||||||
content += "<h4>Emergency: " + String(statusText[datalayer_extended.bmwphev.ST_EMG]) + "</h4>";
|
break;
|
||||||
static const char* prechargeText[16] = {"Not evaluated",
|
case 4:
|
||||||
"Not active, closing not blocked",
|
content += String("4 Unknown</h4>");
|
||||||
"Error precharge blocked",
|
break;
|
||||||
"Invalid signal",
|
default:
|
||||||
"",
|
content += String("Unknown</h4>");
|
||||||
"",
|
}
|
||||||
"",
|
content += "<h4>Interlock: ";
|
||||||
"",
|
switch (datalayer_extended.bmwphev.ST_interlock) {
|
||||||
"",
|
case 0:
|
||||||
"",
|
content += String("Not Evaluated</h4>");
|
||||||
"",
|
break;
|
||||||
"",
|
case 1:
|
||||||
"",
|
content += String("OK</h4>");
|
||||||
"",
|
break;
|
||||||
"",
|
case 2:
|
||||||
""};
|
content += String("Error! Not seated!</h4>");
|
||||||
content += "<h4>Precharge: " + String(prechargeText[datalayer_extended.bmwphev.ST_precharge]) +
|
break;
|
||||||
"</h4>"; //Still unclear of enum
|
case 3:
|
||||||
static const char* DCSWText[16] = {"Contactors open",
|
content += String("Invalid signal</h4>");
|
||||||
"Precharge ongoing",
|
break;
|
||||||
"Contactors engaged",
|
default:
|
||||||
"Invalid signal",
|
content += String("Unknown</h4>");
|
||||||
"",
|
}
|
||||||
"",
|
content += "<h4>Isolation external: ";
|
||||||
"",
|
switch (datalayer_extended.bmwphev.ST_iso_ext) {
|
||||||
"",
|
case 0:
|
||||||
"",
|
content += String("Not Evaluated</h4>");
|
||||||
"",
|
break;
|
||||||
"",
|
case 1:
|
||||||
"",
|
content += String("OK</h4>");
|
||||||
"",
|
break;
|
||||||
"",
|
case 2:
|
||||||
"",
|
content += String("Error!</h4>");
|
||||||
""};
|
break;
|
||||||
content += "<h4>Contactor status: " + String(DCSWText[datalayer_extended.bmwphev.ST_DCSW]) + "</h4>";
|
case 3:
|
||||||
static const char* contText[16] = {"Contactors OK",
|
content += String("Invalid signal</h4>");
|
||||||
"One contactor welded!",
|
break;
|
||||||
"Two contactors welded!",
|
default:
|
||||||
"Invalid signal",
|
content += String("Unknown</h4>");
|
||||||
"",
|
}
|
||||||
"",
|
content += "<h4>Isolation internal: ";
|
||||||
"",
|
switch (datalayer_extended.bmwphev.ST_iso_int) {
|
||||||
"",
|
case 0:
|
||||||
"",
|
content += String("Not Evaluated</h4>");
|
||||||
"",
|
break;
|
||||||
"",
|
case 1:
|
||||||
"",
|
content += String("OK</h4>");
|
||||||
"",
|
break;
|
||||||
"",
|
case 2:
|
||||||
"",
|
content += String("Error!</h4>");
|
||||||
""};
|
break;
|
||||||
content += "<h4>Contactor weld: " + String(contText[datalayer_extended.bmwphev.ST_WELD]) + "</h4>";
|
case 3:
|
||||||
static const char* valveText[16] = {"OK",
|
content += String("Invalid signal</h4>");
|
||||||
"Short circuit to GND",
|
break;
|
||||||
"Short circuit to 12V",
|
default:
|
||||||
"Line break",
|
content += String("Unknown</h4>");
|
||||||
"",
|
}
|
||||||
"",
|
content += "<h4>Isolation: ";
|
||||||
"Driver error",
|
switch (datalayer_extended.bmwphev.ST_isolation) {
|
||||||
"",
|
case 0:
|
||||||
"",
|
content += String("Not Evaluated</h4>");
|
||||||
"",
|
break;
|
||||||
"",
|
case 1:
|
||||||
"",
|
content += String("OK</h4>");
|
||||||
"Stuck",
|
break;
|
||||||
"Stuck",
|
case 2:
|
||||||
"",
|
content += String("Error!</h4>");
|
||||||
"Invalid Signal"};
|
break;
|
||||||
content +=
|
case 3:
|
||||||
"<h4>Cold shutoff valve: " + String(valveText[datalayer_extended.bmwphev.ST_cold_shutoff_valve]) + "</h4>";
|
content += String("Invalid signal</h4>");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
content += String("Unknown</h4>");
|
||||||
|
}
|
||||||
|
content += "<h4>Cooling valve: ";
|
||||||
|
switch (datalayer_extended.bmwphev.ST_valve_cooling) {
|
||||||
|
case 0:
|
||||||
|
content += String("Not Evaluated</h4>");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
content += String("OK</h4>");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
content += String("Error!</h4>");
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
content += String("Invalid signal</h4>");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
content += String("Unknown</h4>");
|
||||||
|
}
|
||||||
|
content += "<h4>Emergency: ";
|
||||||
|
switch (datalayer_extended.bmwphev.ST_EMG) {
|
||||||
|
case 0:
|
||||||
|
content += String("Not Evaluated</h4>");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
content += String("OK</h4>");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
content += String("Error!</h4>");
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
content += String("Invalid signal</h4>");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
content += String("Unknown</h4>");
|
||||||
|
}
|
||||||
|
content += "<h4>Precharge: ";
|
||||||
|
switch (datalayer_extended.bmwphev.ST_precharge) {
|
||||||
|
case 0:
|
||||||
|
content += String("Not Evaluated</h4>");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
content += String("Not active, closing not blocked</h4>");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
content += String("Error precharge blocked</h4>");
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
content += String("Invalid signal</h4>");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
content += String("Unknown</h4>"); //Still unclear of enum
|
||||||
|
}
|
||||||
|
content += "<h4>Contactor status: ";
|
||||||
|
switch (datalayer_extended.bmwphev.ST_DCSW) {
|
||||||
|
case 0:
|
||||||
|
content += String("Contactors open</h4>");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
content += String("Precharge ongoing</h4>");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
content += String("Contactors engaged</h4>");
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
content += String("Invalid signal</h4>");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
content += String("Unknown</h4>");
|
||||||
|
}
|
||||||
|
content += "<h4>Contactor weld: ";
|
||||||
|
switch (datalayer_extended.bmwphev.ST_WELD) {
|
||||||
|
case 0:
|
||||||
|
content += String("Contactors OK</h4>");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
content += String("One contactor welded!</h4>");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
content += String("Two contactors welded!</h4>");
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
content += String("Invalid signal</h4>");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
content += String("Unknown</h4>");
|
||||||
|
}
|
||||||
|
content += "<h4>Cold shutoff valve: ";
|
||||||
|
switch (datalayer_extended.bmwphev.ST_cold_shutoff_valve) {
|
||||||
|
case 0:
|
||||||
|
content += String("OK</h4>");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
content += String("Short circuit to GND</h4>");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
content += String("Short circuit to 12V</h4>");
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
content += String("Line break</h4>");
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
content += String("Driver error</h4>");
|
||||||
|
break;
|
||||||
|
case 12:
|
||||||
|
case 13:
|
||||||
|
content += String("Stuck</h4>");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
content += String("Invalid Signal</h4>");
|
||||||
|
}
|
||||||
content +=
|
content +=
|
||||||
"<h4>Min Cell Voltage Data Age: " + String(datalayer_extended.bmwphev.min_cell_voltage_data_age) + " ms</h4>";
|
"<h4>Min Cell Voltage Data Age: " + String(datalayer_extended.bmwphev.min_cell_voltage_data_age) + " ms</h4>";
|
||||||
content +=
|
content +=
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
#include "../include.h"
|
#include "BMW-SBOX.h"
|
||||||
#ifdef BMW_SBOX
|
|
||||||
#include "../communication/can/comm_can.h"
|
#include "../communication/can/comm_can.h"
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "BMW-SBOX.h"
|
#include "../include.h"
|
||||||
|
|
||||||
uint8_t reverse_bits(uint8_t byte) {
|
uint8_t reverse_bits(uint8_t byte) {
|
||||||
uint8_t reversed = 0;
|
uint8_t reversed = 0;
|
||||||
|
@ -179,7 +178,6 @@ void BmwSbox::transmit_can(unsigned long currentMillis) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void BmwSbox::setup() {
|
void BmwSbox::setup() {
|
||||||
strncpy(datalayer.system.info.shunt_protocol, "BMW SBOX", 63);
|
strncpy(datalayer.system.info.shunt_protocol, Name, 63);
|
||||||
datalayer.system.info.shunt_protocol[63] = '\0';
|
datalayer.system.info.shunt_protocol[63] = '\0';
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
|
@ -2,8 +2,9 @@
|
||||||
#define BMW_SBOX_CONTROL_H
|
#define BMW_SBOX_CONTROL_H
|
||||||
#include "../include.h"
|
#include "../include.h"
|
||||||
|
|
||||||
#define CAN_SHUNT_SELECTED
|
#ifdef BMW_SBOX
|
||||||
#define SELECTED_SHUNT_CLASS BmwSbox
|
#define SELECTED_SHUNT_CLASS BmwSbox
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "Shunt.h"
|
#include "Shunt.h"
|
||||||
|
|
||||||
|
@ -12,6 +13,7 @@ class BmwSbox : public CanShunt {
|
||||||
void setup();
|
void setup();
|
||||||
void transmit_can(unsigned long currentMillis);
|
void transmit_can(unsigned long currentMillis);
|
||||||
void handle_incoming_can_frame(CAN_frame rx_frame);
|
void handle_incoming_can_frame(CAN_frame rx_frame);
|
||||||
|
static constexpr char* Name = "BMW SBOX";
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/** Minimum input voltage required to enable relay control **/
|
/** Minimum input voltage required to enable relay control **/
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
#include "../include.h"
|
#include "BOLT-AMPERA-BATTERY.h"
|
||||||
#ifdef BOLT_AMPERA_BATTERY
|
|
||||||
#include "../communication/can/comm_can.h"
|
#include "../communication/can/comm_can.h"
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../datalayer/datalayer_extended.h"
|
#include "../datalayer/datalayer_extended.h"
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
#include "BOLT-AMPERA-BATTERY.h"
|
#include "../include.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
TODOs left for this implementation
|
TODOs left for this implementation
|
||||||
|
@ -645,7 +644,7 @@ void BoltAmperaBattery::transmit_can(unsigned long currentMillis) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void BoltAmperaBattery::setup(void) { // Performs one time setup at startup
|
void BoltAmperaBattery::setup(void) { // Performs one time setup at startup
|
||||||
strncpy(datalayer.system.info.battery_protocol, "Chevrolet Bolt EV/Opel Ampera-e", 63);
|
strncpy(datalayer.system.info.battery_protocol, Name, 63);
|
||||||
datalayer.system.info.battery_protocol[63] = '\0';
|
datalayer.system.info.battery_protocol[63] = '\0';
|
||||||
datalayer.battery.info.number_of_cells = 96;
|
datalayer.battery.info.number_of_cells = 96;
|
||||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
||||||
|
@ -655,5 +654,3 @@ void BoltAmperaBattery::setup(void) { // Performs one time setup at startup
|
||||||
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
||||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
datalayer.system.status.battery_allows_contactor_closing = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -6,8 +6,9 @@
|
||||||
#include "BOLT-AMPERA-HTML.h"
|
#include "BOLT-AMPERA-HTML.h"
|
||||||
#include "CanBattery.h"
|
#include "CanBattery.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#ifdef BOLT_AMPERA_BATTERY
|
||||||
#define SELECTED_BATTERY_CLASS BoltAmperaBattery
|
#define SELECTED_BATTERY_CLASS BoltAmperaBattery
|
||||||
|
#endif
|
||||||
|
|
||||||
class BoltAmperaBattery : public CanBattery {
|
class BoltAmperaBattery : public CanBattery {
|
||||||
public:
|
public:
|
||||||
|
@ -16,6 +17,8 @@ class BoltAmperaBattery : public CanBattery {
|
||||||
virtual void update_values();
|
virtual void update_values();
|
||||||
virtual void transmit_can(unsigned long currentMillis);
|
virtual void transmit_can(unsigned long currentMillis);
|
||||||
|
|
||||||
|
static constexpr char* Name = "Chevrolet Bolt EV/Opel Ampera-e";
|
||||||
|
|
||||||
BatteryHtmlRenderer& get_status_renderer() { return renderer; }
|
BatteryHtmlRenderer& get_status_renderer() { return renderer; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
#include "../include.h"
|
#include "BYD-ATTO-3-BATTERY.h"
|
||||||
#ifdef BYD_ATTO_3_BATTERY
|
|
||||||
#include "../communication/can/comm_can.h"
|
#include "../communication/can/comm_can.h"
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../datalayer/datalayer_extended.h"
|
#include "../datalayer/datalayer_extended.h"
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
#include "BYD-ATTO-3-BATTERY.h"
|
#include "../include.h"
|
||||||
|
|
||||||
/* Notes
|
/* Notes
|
||||||
SOC% by default is now ESTIMATED.
|
SOC% by default is now ESTIMATED.
|
||||||
|
@ -22,12 +21,12 @@ 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_0 0x1FFE //0x64 19 C4 3B
|
||||||
#define UNKNOWN_POLL_1 0x1FFC //0x72 1F C4 3B
|
#define UNKNOWN_POLL_1 0x1FFC //0x72 1F C4 3B
|
||||||
#define POLL_MAX_CHARGE_POWER 0x000A
|
#define POLL_MAX_CHARGE_POWER 0x000A
|
||||||
#define UNKNOWN_POLL_3 0x000B //0x00B1 (177 interesting!)
|
#define UNKNOWN_POLL_3 0x000B //0x00B1 (177 interesting!)
|
||||||
#define UNKNOWN_POLL_4 0x000E //0x0B27 (2855 interesting!)
|
#define UNKNOWN_POLL_4 0x000E //0x0B27 (2855 interesting!)
|
||||||
#define UNKNOWN_POLL_5 0x000F //0x00237B (9083 interesting!)
|
#define POLL_TOTAL_CHARGED_AH 0x000F
|
||||||
#define UNKNOWN_POLL_6 0x0010 //0x00231B (8987 interesting!)
|
#define POLL_TOTAL_DISCHARGED_AH 0x0010
|
||||||
#define UNKNOWN_POLL_7 0x0011 //0x0E4E (3662 interesting!)
|
#define POLL_TOTAL_CHARGED_KWH 0x0011
|
||||||
#define UNKNOWN_POLL_8 0x0012 //0x0E27 (3623 interesting)
|
#define POLL_TOTAL_DISCHARGED_KWH 0x0012
|
||||||
#define UNKNOWN_POLL_9 0x0004 //0x0034 (52 interesting!)
|
#define UNKNOWN_POLL_9 0x0004 //0x0034 (52 interesting!)
|
||||||
#define UNKNOWN_POLL_10 0x002A //0x5B
|
#define UNKNOWN_POLL_10 0x002A //0x5B
|
||||||
#define UNKNOWN_POLL_11 0x002E //0x08 (probably module number, or cell number?)
|
#define UNKNOWN_POLL_11 0x002E //0x08 (probably module number, or cell number?)
|
||||||
|
@ -151,6 +150,13 @@ void BydAttoBattery::
|
||||||
datalayer_battery->status.voltage_dV = BMS_voltage * 10;
|
datalayer_battery->status.voltage_dV = BMS_voltage * 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (battery_type == EXTENDED_RANGE) {
|
||||||
|
battery_estimated_SOC = estimateSOCextended(datalayer_battery->status.voltage_dV);
|
||||||
|
}
|
||||||
|
if (battery_type == STANDARD_RANGE) {
|
||||||
|
battery_estimated_SOC = estimateSOCstandard(datalayer_battery->status.voltage_dV);
|
||||||
|
}
|
||||||
|
|
||||||
if (SOC_method == MEASURED) {
|
if (SOC_method == MEASURED) {
|
||||||
// Pack is not crashed, we can use periodically transmitted SOC
|
// Pack is not crashed, we can use periodically transmitted SOC
|
||||||
datalayer_battery->status.real_soc = battery_highprecision_SOC * 10;
|
datalayer_battery->status.real_soc = battery_highprecision_SOC * 10;
|
||||||
|
@ -158,12 +164,7 @@ void BydAttoBattery::
|
||||||
// When the battery is crashed hard, it locks itself and SOC becomes unavailable.
|
// When the battery is crashed hard, it locks itself and SOC becomes unavailable.
|
||||||
// We instead estimate the SOC% based on the battery voltage.
|
// We instead estimate the SOC% based on the battery voltage.
|
||||||
// This is a bad solution, you wont be able to use 100% of the battery
|
// This is a bad solution, you wont be able to use 100% of the battery
|
||||||
if (battery_type == EXTENDED_RANGE) {
|
datalayer_battery->status.real_soc = battery_estimated_SOC;
|
||||||
datalayer_battery->status.real_soc = estimateSOCextended(datalayer_battery->status.voltage_dV);
|
|
||||||
}
|
|
||||||
if (battery_type == STANDARD_RANGE) {
|
|
||||||
datalayer_battery->status.real_soc = estimateSOCstandard(datalayer_battery->status.voltage_dV);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
datalayer_battery->status.current_dA = -BMS_current;
|
datalayer_battery->status.current_dA = -BMS_current;
|
||||||
|
@ -179,6 +180,9 @@ void BydAttoBattery::
|
||||||
|
|
||||||
datalayer_battery->status.cell_min_voltage_mV = BMS_lowest_cell_voltage_mV;
|
datalayer_battery->status.cell_min_voltage_mV = BMS_lowest_cell_voltage_mV;
|
||||||
|
|
||||||
|
datalayer_battery->status.total_discharged_battery_Wh = BMS_total_discharged_kwh * 1000;
|
||||||
|
datalayer_battery->status.total_charged_battery_Wh = BMS_total_charged_kwh * 1000;
|
||||||
|
|
||||||
//Map all cell voltages to the global array
|
//Map all cell voltages to the global array
|
||||||
memcpy(datalayer_battery->status.cell_voltages_mV, battery_cellvoltages, CELLCOUNT_EXTENDED * sizeof(uint16_t));
|
memcpy(datalayer_battery->status.cell_voltages_mV, battery_cellvoltages, CELLCOUNT_EXTENDED * sizeof(uint16_t));
|
||||||
|
|
||||||
|
@ -255,8 +259,7 @@ void BydAttoBattery::
|
||||||
// Update webserver datalayer
|
// Update webserver datalayer
|
||||||
if (datalayer_bydatto) {
|
if (datalayer_bydatto) {
|
||||||
datalayer_bydatto->SOC_method = SOC_method;
|
datalayer_bydatto->SOC_method = SOC_method;
|
||||||
datalayer_bydatto->SOC_estimated = datalayer_battery->status.real_soc;
|
datalayer_bydatto->SOC_estimated = battery_estimated_SOC;
|
||||||
//Once we implement switching logic, remember to change from where the estimated is taken
|
|
||||||
datalayer_bydatto->SOC_highprec = battery_highprecision_SOC;
|
datalayer_bydatto->SOC_highprec = battery_highprecision_SOC;
|
||||||
datalayer_bydatto->SOC_polled = BMS_SOC;
|
datalayer_bydatto->SOC_polled = BMS_SOC;
|
||||||
datalayer_bydatto->voltage_periodic = battery_voltage;
|
datalayer_bydatto->voltage_periodic = battery_voltage;
|
||||||
|
@ -276,10 +279,10 @@ void BydAttoBattery::
|
||||||
datalayer_bydatto->chargePower = BMS_allowed_charge_power;
|
datalayer_bydatto->chargePower = BMS_allowed_charge_power;
|
||||||
datalayer_bydatto->unknown3 = BMS_unknown3;
|
datalayer_bydatto->unknown3 = BMS_unknown3;
|
||||||
datalayer_bydatto->unknown4 = BMS_unknown4;
|
datalayer_bydatto->unknown4 = BMS_unknown4;
|
||||||
datalayer_bydatto->unknown5 = BMS_unknown5;
|
datalayer_bydatto->total_charged_ah = BMS_total_charged_ah;
|
||||||
datalayer_bydatto->unknown6 = BMS_unknown6;
|
datalayer_bydatto->total_discharged_ah = BMS_total_discharged_ah;
|
||||||
datalayer_bydatto->unknown7 = BMS_unknown7;
|
datalayer_bydatto->total_charged_kwh = BMS_total_charged_kwh;
|
||||||
datalayer_bydatto->unknown8 = BMS_unknown8;
|
datalayer_bydatto->total_discharged_kwh = BMS_total_discharged_kwh;
|
||||||
datalayer_bydatto->unknown9 = BMS_unknown9;
|
datalayer_bydatto->unknown9 = BMS_unknown9;
|
||||||
datalayer_bydatto->unknown10 = BMS_unknown10;
|
datalayer_bydatto->unknown10 = BMS_unknown10;
|
||||||
datalayer_bydatto->unknown11 = BMS_unknown11;
|
datalayer_bydatto->unknown11 = BMS_unknown11;
|
||||||
|
@ -442,17 +445,17 @@ void BydAttoBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
||||||
case UNKNOWN_POLL_4:
|
case UNKNOWN_POLL_4:
|
||||||
BMS_unknown4 = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4];
|
BMS_unknown4 = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4];
|
||||||
break;
|
break;
|
||||||
case UNKNOWN_POLL_5:
|
case POLL_TOTAL_CHARGED_AH:
|
||||||
BMS_unknown5 = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4];
|
BMS_total_charged_ah = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4];
|
||||||
break;
|
break;
|
||||||
case UNKNOWN_POLL_6:
|
case POLL_TOTAL_DISCHARGED_AH:
|
||||||
BMS_unknown6 = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4];
|
BMS_total_discharged_ah = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4];
|
||||||
break;
|
break;
|
||||||
case UNKNOWN_POLL_7:
|
case POLL_TOTAL_CHARGED_KWH:
|
||||||
BMS_unknown7 = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4];
|
BMS_total_charged_kwh = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4];
|
||||||
break;
|
break;
|
||||||
case UNKNOWN_POLL_8:
|
case POLL_TOTAL_DISCHARGED_KWH:
|
||||||
BMS_unknown8 = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4];
|
BMS_total_discharged_kwh = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4];
|
||||||
break;
|
break;
|
||||||
case UNKNOWN_POLL_9:
|
case UNKNOWN_POLL_9:
|
||||||
BMS_unknown9 = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4];
|
BMS_unknown9 = (rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4];
|
||||||
|
@ -622,26 +625,26 @@ void BydAttoBattery::transmit_can(unsigned long currentMillis) {
|
||||||
case UNKNOWN_POLL_4:
|
case UNKNOWN_POLL_4:
|
||||||
ATTO_3_7E7_POLL.data.u8[2] = (uint8_t)((UNKNOWN_POLL_4 & 0xFF00) >> 8);
|
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);
|
ATTO_3_7E7_POLL.data.u8[3] = (uint8_t)(UNKNOWN_POLL_4 & 0x00FF);
|
||||||
poll_state = UNKNOWN_POLL_5;
|
poll_state = POLL_TOTAL_CHARGED_AH;
|
||||||
break;
|
break;
|
||||||
case UNKNOWN_POLL_5:
|
case POLL_TOTAL_CHARGED_AH:
|
||||||
ATTO_3_7E7_POLL.data.u8[2] = (uint8_t)((UNKNOWN_POLL_5 & 0xFF00) >> 8);
|
ATTO_3_7E7_POLL.data.u8[2] = (uint8_t)((POLL_TOTAL_CHARGED_AH & 0xFF00) >> 8);
|
||||||
ATTO_3_7E7_POLL.data.u8[3] = (uint8_t)(UNKNOWN_POLL_5 & 0x00FF);
|
ATTO_3_7E7_POLL.data.u8[3] = (uint8_t)(POLL_TOTAL_CHARGED_AH & 0x00FF);
|
||||||
poll_state = UNKNOWN_POLL_6;
|
poll_state = POLL_TOTAL_DISCHARGED_AH;
|
||||||
break;
|
break;
|
||||||
case UNKNOWN_POLL_6:
|
case POLL_TOTAL_DISCHARGED_AH:
|
||||||
ATTO_3_7E7_POLL.data.u8[2] = (uint8_t)((UNKNOWN_POLL_6 & 0xFF00) >> 8);
|
ATTO_3_7E7_POLL.data.u8[2] = (uint8_t)((POLL_TOTAL_DISCHARGED_AH & 0xFF00) >> 8);
|
||||||
ATTO_3_7E7_POLL.data.u8[3] = (uint8_t)(UNKNOWN_POLL_6 & 0x00FF);
|
ATTO_3_7E7_POLL.data.u8[3] = (uint8_t)(POLL_TOTAL_DISCHARGED_AH & 0x00FF);
|
||||||
poll_state = UNKNOWN_POLL_7;
|
poll_state = POLL_TOTAL_CHARGED_KWH;
|
||||||
break;
|
break;
|
||||||
case UNKNOWN_POLL_7:
|
case POLL_TOTAL_CHARGED_KWH:
|
||||||
ATTO_3_7E7_POLL.data.u8[2] = (uint8_t)((UNKNOWN_POLL_7 & 0xFF00) >> 8);
|
ATTO_3_7E7_POLL.data.u8[2] = (uint8_t)((POLL_TOTAL_CHARGED_KWH & 0xFF00) >> 8);
|
||||||
ATTO_3_7E7_POLL.data.u8[3] = (uint8_t)(UNKNOWN_POLL_7 & 0x00FF);
|
ATTO_3_7E7_POLL.data.u8[3] = (uint8_t)(POLL_TOTAL_CHARGED_KWH & 0x00FF);
|
||||||
poll_state = UNKNOWN_POLL_8;
|
poll_state = POLL_TOTAL_DISCHARGED_KWH;
|
||||||
break;
|
break;
|
||||||
case UNKNOWN_POLL_8:
|
case POLL_TOTAL_DISCHARGED_KWH:
|
||||||
ATTO_3_7E7_POLL.data.u8[2] = (uint8_t)((UNKNOWN_POLL_8 & 0xFF00) >> 8);
|
ATTO_3_7E7_POLL.data.u8[2] = (uint8_t)((POLL_TOTAL_DISCHARGED_KWH & 0xFF00) >> 8);
|
||||||
ATTO_3_7E7_POLL.data.u8[3] = (uint8_t)(UNKNOWN_POLL_8 & 0x00FF);
|
ATTO_3_7E7_POLL.data.u8[3] = (uint8_t)(POLL_TOTAL_DISCHARGED_KWH & 0x00FF);
|
||||||
poll_state = UNKNOWN_POLL_9;
|
poll_state = UNKNOWN_POLL_9;
|
||||||
break;
|
break;
|
||||||
case UNKNOWN_POLL_9:
|
case UNKNOWN_POLL_9:
|
||||||
|
@ -681,7 +684,7 @@ void BydAttoBattery::transmit_can(unsigned long currentMillis) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void BydAttoBattery::setup(void) { // Performs one time setup at startup
|
void BydAttoBattery::setup(void) { // Performs one time setup at startup
|
||||||
strncpy(datalayer.system.info.battery_protocol, "BYD Atto 3", 63);
|
strncpy(datalayer.system.info.battery_protocol, Name, 63);
|
||||||
datalayer.system.info.battery_protocol[63] = '\0';
|
datalayer.system.info.battery_protocol[63] = '\0';
|
||||||
datalayer_battery->info.number_of_cells = CELLCOUNT_STANDARD;
|
datalayer_battery->info.number_of_cells = CELLCOUNT_STANDARD;
|
||||||
datalayer_battery->info.chemistry = battery_chemistry_enum::LFP;
|
datalayer_battery->info.chemistry = battery_chemistry_enum::LFP;
|
||||||
|
@ -696,5 +699,3 @@ void BydAttoBattery::setup(void) { // Performs one time setup at startup
|
||||||
SOC_method = MEASURED;
|
SOC_method = MEASURED;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -18,18 +18,9 @@
|
||||||
//#define SKIP_TEMPERATURE_SENSOR_NUMBER 1
|
//#define SKIP_TEMPERATURE_SENSOR_NUMBER 1
|
||||||
|
|
||||||
/* Do not modify the rows below */
|
/* Do not modify the rows below */
|
||||||
#define BATTERY_SELECTED
|
#ifdef BYD_ATTO_3_BATTERY
|
||||||
#define SELECTED_BATTERY_CLASS BydAttoBattery
|
#define SELECTED_BATTERY_CLASS BydAttoBattery
|
||||||
|
#endif
|
||||||
#define CELLCOUNT_EXTENDED 126
|
|
||||||
#define CELLCOUNT_STANDARD 104
|
|
||||||
#define MAX_PACK_VOLTAGE_EXTENDED_DV 4410 //Extended range
|
|
||||||
#define MIN_PACK_VOLTAGE_EXTENDED_DV 3800 //Extended range
|
|
||||||
#define MAX_PACK_VOLTAGE_STANDARD_DV 3640 //Standard range
|
|
||||||
#define MIN_PACK_VOLTAGE_STANDARD_DV 3136 //Standard range
|
|
||||||
#define MAX_CELL_DEVIATION_MV 230
|
|
||||||
#define MAX_CELL_VOLTAGE_MV 3650 //Charging stops if one cell exceeds this value
|
|
||||||
#define MIN_CELL_VOLTAGE_MV 2800 //Discharging stops if one cell goes below this value
|
|
||||||
|
|
||||||
class BydAttoBattery : public CanBattery {
|
class BydAttoBattery : public CanBattery {
|
||||||
public:
|
public:
|
||||||
|
@ -53,6 +44,9 @@ class BydAttoBattery : public CanBattery {
|
||||||
virtual void update_values();
|
virtual void update_values();
|
||||||
virtual void transmit_can(unsigned long currentMillis);
|
virtual void transmit_can(unsigned long currentMillis);
|
||||||
|
|
||||||
|
static constexpr char* Name = "BYD Atto 3";
|
||||||
|
|
||||||
|
bool supports_charged_energy() { return true; }
|
||||||
bool supports_reset_crash() { return true; }
|
bool supports_reset_crash() { return true; }
|
||||||
|
|
||||||
void reset_crash() { datalayer_bydatto->UserRequestCrashReset = true; }
|
void reset_crash() { datalayer_bydatto->UserRequestCrashReset = true; }
|
||||||
|
@ -67,6 +61,16 @@ class BydAttoBattery : public CanBattery {
|
||||||
BatteryHtmlRenderer& get_status_renderer() { return renderer; }
|
BatteryHtmlRenderer& get_status_renderer() { return renderer; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static const int CELLCOUNT_EXTENDED = 126;
|
||||||
|
static const int CELLCOUNT_STANDARD = 104;
|
||||||
|
static const int MAX_PACK_VOLTAGE_EXTENDED_DV = 4410; //Extended range
|
||||||
|
static const int MIN_PACK_VOLTAGE_EXTENDED_DV = 3800; //Extended range
|
||||||
|
static const int MAX_PACK_VOLTAGE_STANDARD_DV = 3640; //Standard range
|
||||||
|
static const int MIN_PACK_VOLTAGE_STANDARD_DV = 3136; //Standard range
|
||||||
|
static const int MAX_CELL_DEVIATION_MV = 230;
|
||||||
|
static const int MAX_CELL_VOLTAGE_MV = 3650; //Charging stops if one cell exceeds this value
|
||||||
|
static const int MIN_CELL_VOLTAGE_MV = 2800; //Discharging stops if one cell goes below this value
|
||||||
|
|
||||||
BydAtto3HtmlRenderer renderer;
|
BydAtto3HtmlRenderer renderer;
|
||||||
DATALAYER_BATTERY_TYPE* datalayer_battery;
|
DATALAYER_BATTERY_TYPE* datalayer_battery;
|
||||||
DATALAYER_INFO_BYDATTO3* datalayer_bydatto;
|
DATALAYER_INFO_BYDATTO3* datalayer_bydatto;
|
||||||
|
@ -100,6 +104,7 @@ class BydAttoBattery : public CanBattery {
|
||||||
int16_t battery_calc_min_temperature = 0;
|
int16_t battery_calc_min_temperature = 0;
|
||||||
int16_t battery_calc_max_temperature = 0;
|
int16_t battery_calc_max_temperature = 0;
|
||||||
uint16_t battery_highprecision_SOC = 0;
|
uint16_t battery_highprecision_SOC = 0;
|
||||||
|
uint16_t battery_estimated_SOC = 0;
|
||||||
uint16_t BMS_SOC = 0;
|
uint16_t BMS_SOC = 0;
|
||||||
uint16_t BMS_voltage = 0;
|
uint16_t BMS_voltage = 0;
|
||||||
int16_t BMS_current = 0;
|
int16_t BMS_current = 0;
|
||||||
|
@ -113,10 +118,10 @@ class BydAttoBattery : public CanBattery {
|
||||||
uint16_t BMS_allowed_charge_power = 0;
|
uint16_t BMS_allowed_charge_power = 0;
|
||||||
uint16_t BMS_unknown3 = 0;
|
uint16_t BMS_unknown3 = 0;
|
||||||
uint16_t BMS_unknown4 = 0;
|
uint16_t BMS_unknown4 = 0;
|
||||||
uint16_t BMS_unknown5 = 0;
|
uint16_t BMS_total_charged_ah = 0;
|
||||||
uint16_t BMS_unknown6 = 0;
|
uint16_t BMS_total_discharged_ah = 0;
|
||||||
uint16_t BMS_unknown7 = 0;
|
uint16_t BMS_total_charged_kwh = 0;
|
||||||
uint16_t BMS_unknown8 = 0;
|
uint16_t BMS_total_discharged_kwh = 0;
|
||||||
uint16_t BMS_unknown9 = 0;
|
uint16_t BMS_unknown9 = 0;
|
||||||
uint8_t BMS_unknown10 = 0;
|
uint8_t BMS_unknown10 = 0;
|
||||||
uint8_t BMS_unknown11 = 0;
|
uint8_t BMS_unknown11 = 0;
|
||||||
|
|
|
@ -34,10 +34,10 @@ class BydAtto3HtmlRenderer : public BatteryHtmlRenderer {
|
||||||
content += "<h4>Charge power raw: " + String(byd_datalayer->chargePower) + "</h4>";
|
content += "<h4>Charge power raw: " + String(byd_datalayer->chargePower) + "</h4>";
|
||||||
content += "<h4>Unknown3: " + String(byd_datalayer->unknown3) + "</h4>";
|
content += "<h4>Unknown3: " + String(byd_datalayer->unknown3) + "</h4>";
|
||||||
content += "<h4>Unknown4: " + String(byd_datalayer->unknown4) + "</h4>";
|
content += "<h4>Unknown4: " + String(byd_datalayer->unknown4) + "</h4>";
|
||||||
content += "<h4>Unknown5: " + String(byd_datalayer->unknown5) + "</h4>";
|
content += "<h4>Total charged Ah: " + String(byd_datalayer->total_charged_ah) + "</h4>";
|
||||||
content += "<h4>Unknown6: " + String(byd_datalayer->unknown6) + "</h4>";
|
content += "<h4>Total discharged Ah: " + String(byd_datalayer->total_discharged_ah) + "</h4>";
|
||||||
content += "<h4>Unknown7: " + String(byd_datalayer->unknown7) + "</h4>";
|
content += "<h4>Total charged kWh: " + String(byd_datalayer->total_charged_kwh) + "</h4>";
|
||||||
content += "<h4>Unknown8: " + String(byd_datalayer->unknown8) + "</h4>";
|
content += "<h4>Total discharged kWh: " + String(byd_datalayer->total_discharged_kwh) + "</h4>";
|
||||||
content += "<h4>Unknown9: " + String(byd_datalayer->unknown9) + "</h4>";
|
content += "<h4>Unknown9: " + String(byd_datalayer->unknown9) + "</h4>";
|
||||||
content += "<h4>Unknown10: " + String(byd_datalayer->unknown10) + "</h4>";
|
content += "<h4>Unknown10: " + String(byd_datalayer->unknown10) + "</h4>";
|
||||||
content += "<h4>Unknown11: " + String(byd_datalayer->unknown11) + "</h4>";
|
content += "<h4>Unknown11: " + String(byd_datalayer->unknown11) + "</h4>";
|
||||||
|
|
6
Software/src/battery/Battery.cpp
Normal file
6
Software/src/battery/Battery.cpp
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#include "Battery.h"
|
||||||
|
#include "../datalayer/datalayer.h"
|
||||||
|
|
||||||
|
float Battery::get_voltage() {
|
||||||
|
return static_cast<float>(datalayer.battery.status.voltage_dV) / 10.0;
|
||||||
|
}
|
|
@ -1,9 +1,56 @@
|
||||||
#ifndef BATTERY_H
|
#ifndef BATTERY_H
|
||||||
#define BATTERY_H
|
#define BATTERY_H
|
||||||
|
|
||||||
#include "../datalayer/datalayer.h"
|
#include <vector>
|
||||||
#include "src/devboard/webserver/BatteryHtmlRenderer.h"
|
#include "src/devboard/webserver/BatteryHtmlRenderer.h"
|
||||||
|
|
||||||
|
enum class BatteryType {
|
||||||
|
None = 0,
|
||||||
|
BmwSbox = 1,
|
||||||
|
BmwI3 = 2,
|
||||||
|
BmwIx = 3,
|
||||||
|
BoltAmpera = 4,
|
||||||
|
BydAtto3 = 5,
|
||||||
|
CellPowerBms = 6,
|
||||||
|
Chademo = 7,
|
||||||
|
CmfaEv = 8,
|
||||||
|
Foxess = 9,
|
||||||
|
GeelyGeometryC = 10,
|
||||||
|
OrionBms = 11,
|
||||||
|
Sono = 12,
|
||||||
|
StellantisEcmp = 13,
|
||||||
|
ImievCZeroIon = 14,
|
||||||
|
JaguarIpace = 15,
|
||||||
|
KiaEGmp = 16,
|
||||||
|
KiaHyundai64 = 17,
|
||||||
|
KiaHyundaiHybrid = 18,
|
||||||
|
Meb = 19,
|
||||||
|
Mg5 = 20,
|
||||||
|
NissanLeaf = 21,
|
||||||
|
Pylon = 22,
|
||||||
|
DalyBms = 23,
|
||||||
|
RjxzsBms = 24,
|
||||||
|
RangeRoverPhev = 25,
|
||||||
|
RenaultKangoo = 26,
|
||||||
|
RenaultTwizy = 27,
|
||||||
|
RenaultZoe1 = 28,
|
||||||
|
RenaultZoe2 = 29,
|
||||||
|
SantaFePhev = 30,
|
||||||
|
SimpBms = 31,
|
||||||
|
TeslaModel3Y = 32,
|
||||||
|
TeslaModelSX = 33,
|
||||||
|
TestFake = 34,
|
||||||
|
VolvoSpa = 35,
|
||||||
|
VolvoSpaHybrid = 36,
|
||||||
|
Highest
|
||||||
|
};
|
||||||
|
|
||||||
|
extern std::vector<BatteryType> supported_battery_types();
|
||||||
|
extern const char* name_for_battery_type(BatteryType type);
|
||||||
|
|
||||||
|
extern BatteryType user_selected_battery_type;
|
||||||
|
extern bool user_selected_second_battery;
|
||||||
|
|
||||||
// Abstract base class for next-generation battery implementations.
|
// Abstract base class for next-generation battery implementations.
|
||||||
// Defines the interface to call battery specific functionality.
|
// Defines the interface to call battery specific functionality.
|
||||||
class Battery {
|
class Battery {
|
||||||
|
@ -48,7 +95,7 @@ class Battery {
|
||||||
virtual void set_factory_mode() {}
|
virtual void set_factory_mode() {}
|
||||||
|
|
||||||
virtual void set_fake_voltage(float v) {}
|
virtual void set_fake_voltage(float v) {}
|
||||||
virtual float get_voltage() { return static_cast<float>(datalayer.battery.status.voltage_dV) / 10.0; }
|
virtual float get_voltage();
|
||||||
|
|
||||||
// This allows for battery specific SOC plausibility calculations to be performed.
|
// This allows for battery specific SOC plausibility calculations to be performed.
|
||||||
virtual bool soc_plausible() { return true; }
|
virtual bool soc_plausible() { return true; }
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
#include "../include.h"
|
#include "CELLPOWER-BMS.h"
|
||||||
#ifdef CELLPOWER_BMS
|
|
||||||
#include "../communication/can/comm_can.h"
|
#include "../communication/can/comm_can.h"
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../datalayer/datalayer_extended.h" //For "More battery info" webpage
|
#include "../datalayer/datalayer_extended.h" //For "More battery info" webpage
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
#include "CELLPOWER-BMS.h"
|
#include "../include.h"
|
||||||
|
|
||||||
void CellPowerBms::update_values() {
|
void CellPowerBms::update_values() {
|
||||||
|
|
||||||
|
@ -230,7 +229,7 @@ void CellPowerBms::transmit_can(unsigned long currentMillis) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CellPowerBms::setup(void) { // Performs one time setup at startup
|
void CellPowerBms::setup(void) { // Performs one time setup at startup
|
||||||
strncpy(datalayer.system.info.battery_protocol, "Cellpower BMS", 63);
|
strncpy(datalayer.system.info.battery_protocol, Name, 63);
|
||||||
datalayer.system.info.battery_protocol[63] = '\0';
|
datalayer.system.info.battery_protocol[63] = '\0';
|
||||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
datalayer.system.status.battery_allows_contactor_closing = true;
|
||||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
||||||
|
@ -238,5 +237,3 @@ void CellPowerBms::setup(void) { // Performs one time setup at startup
|
||||||
datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV;
|
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.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // CELLPOWER_BMS
|
|
||||||
|
|
|
@ -5,8 +5,9 @@
|
||||||
#include "CELLPOWER-HTML.h"
|
#include "CELLPOWER-HTML.h"
|
||||||
#include "CanBattery.h"
|
#include "CanBattery.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#ifdef CELLPOWER_BMS
|
||||||
#define SELECTED_BATTERY_CLASS CellPowerBms
|
#define SELECTED_BATTERY_CLASS CellPowerBms
|
||||||
|
#endif
|
||||||
|
|
||||||
class CellPowerBms : public CanBattery {
|
class CellPowerBms : public CanBattery {
|
||||||
public:
|
public:
|
||||||
|
@ -15,6 +16,8 @@ class CellPowerBms : public CanBattery {
|
||||||
virtual void update_values();
|
virtual void update_values();
|
||||||
virtual void transmit_can(unsigned long currentMillis);
|
virtual void transmit_can(unsigned long currentMillis);
|
||||||
|
|
||||||
|
static constexpr char* Name = "Cellpower BMS";
|
||||||
|
|
||||||
BatteryHtmlRenderer& get_status_renderer() { return renderer; }
|
BatteryHtmlRenderer& get_status_renderer() { return renderer; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
#include "../include.h"
|
#include "CHADEMO-BATTERY.h"
|
||||||
#ifdef CHADEMO_BATTERY
|
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
#include "CHADEMO-BATTERY.h"
|
#include "../include.h"
|
||||||
#include "CHADEMO-SHUNTS.h"
|
#include "CHADEMO-SHUNTS.h"
|
||||||
|
|
||||||
|
#ifdef CHADEMO_PIN_2 // Only support chademo for certain platforms
|
||||||
|
|
||||||
/* CHADEMO handling runs at 6.25 times the rate of most other code, so, rather than the
|
/* CHADEMO handling runs at 6.25 times the rate of most other code, so, rather than the
|
||||||
* default value of 12 (for 12 iterations of the 5s value update loop) * 5 for a 60s timeout,
|
* default value of 12 (for 12 iterations of the 5s value update loop) * 5 for a 60s timeout,
|
||||||
* instead use 75 for 75*0.8s = 60s
|
* instead use 75 for 75*0.8s = 60s
|
||||||
|
@ -21,7 +22,9 @@ void ChademoBattery::update_values() {
|
||||||
datalayer.battery.status.max_discharge_power_W =
|
datalayer.battery.status.max_discharge_power_W =
|
||||||
(x200_discharge_limits.MaximumDischargeCurrent * x100_chg_lim.MaximumBatteryVoltage); //In Watts, Convert A to P
|
(x200_discharge_limits.MaximumDischargeCurrent * x100_chg_lim.MaximumBatteryVoltage); //In Watts, Convert A to P
|
||||||
|
|
||||||
datalayer.battery.status.voltage_dV = get_measured_voltage() * 10;
|
if (vehicle_can_received) { // Only update the value sent towards inverter if vehicle is connected (avoids false positive events)
|
||||||
|
datalayer.battery.status.voltage_dV = get_measured_voltage() * 10;
|
||||||
|
}
|
||||||
|
|
||||||
datalayer.battery.info.total_capacity_Wh = (x101_chg_est.RatedBatteryCapacity * 100);
|
datalayer.battery.info.total_capacity_Wh = (x101_chg_est.RatedBatteryCapacity * 100);
|
||||||
//(Added in CHAdeMO v1.0.1), maybe handle hardcoded on lower protocol version?
|
//(Added in CHAdeMO v1.0.1), maybe handle hardcoded on lower protocol version?
|
||||||
|
@ -202,7 +205,7 @@ void ChademoBattery::process_vehicle_charging_session(CAN_frame rx_frame) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_LOG
|
#ifdef DEBUG_LOG
|
||||||
logging.println("UNHANDLED STATE IN process_vehicle_charging_session()");
|
logging.println("UNHANDLED CHADEMO STATE, try unplugging chademo cable, reboot emulator, and retry!");
|
||||||
#endif
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -229,6 +232,10 @@ void ChademoBattery::process_vehicle_charging_limits(CAN_frame rx_frame) {
|
||||||
if (get_measured_voltage() <= x200_discharge_limits.MinimumDischargeVoltage && CHADEMO_Status > CHADEMO_NEGOTIATE) {
|
if (get_measured_voltage() <= x200_discharge_limits.MinimumDischargeVoltage && CHADEMO_Status > CHADEMO_NEGOTIATE) {
|
||||||
#ifdef DEBUG_LOG
|
#ifdef DEBUG_LOG
|
||||||
logging.println("x200 minimum discharge voltage met or exceeded, stopping.");
|
logging.println("x200 minimum discharge voltage met or exceeded, stopping.");
|
||||||
|
logging.print("Measured: ");
|
||||||
|
logging.print(get_measured_voltage());
|
||||||
|
logging.print("Minimum voltage: ");
|
||||||
|
logging.print(x200_discharge_limits.MinimumDischargeVoltage);
|
||||||
#endif
|
#endif
|
||||||
CHADEMO_Status = CHADEMO_STOP;
|
CHADEMO_Status = CHADEMO_STOP;
|
||||||
}
|
}
|
||||||
|
@ -939,7 +946,7 @@ void ChademoBattery::setup(void) { // Performs one time setup at startup
|
||||||
pinMode(CHADEMO_PIN_4, INPUT);
|
pinMode(CHADEMO_PIN_4, INPUT);
|
||||||
pinMode(CHADEMO_PIN_7, INPUT);
|
pinMode(CHADEMO_PIN_7, INPUT);
|
||||||
|
|
||||||
strncpy(datalayer.system.info.battery_protocol, "Chademo V2X mode", 63);
|
strncpy(datalayer.system.info.battery_protocol, Name, 63);
|
||||||
datalayer.system.info.battery_protocol[63] = '\0';
|
datalayer.system.info.battery_protocol[63] = '\0';
|
||||||
|
|
||||||
CHADEMO_Status = CHADEMO_IDLE;
|
CHADEMO_Status = CHADEMO_IDLE;
|
||||||
|
@ -988,4 +995,5 @@ void ChademoBattery::setup(void) { // Performs one time setup at startup
|
||||||
|
|
||||||
setupMillis = millis();
|
setupMillis = millis();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -4,15 +4,12 @@
|
||||||
#include "../include.h"
|
#include "../include.h"
|
||||||
#include "CanBattery.h"
|
#include "CanBattery.h"
|
||||||
|
|
||||||
|
#ifdef CHADEMO_BATTERY
|
||||||
|
#define SELECTED_BATTERY_CLASS ChademoBattery
|
||||||
|
|
||||||
//Contactor control is required for CHADEMO support
|
//Contactor control is required for CHADEMO support
|
||||||
#define CONTACTOR_CONTROL
|
#define CONTACTOR_CONTROL
|
||||||
|
#endif
|
||||||
//ISA shunt is currently required for CHADEMO support
|
|
||||||
// other measurement sources may be added in the future
|
|
||||||
#define ISA_SHUNT
|
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
|
||||||
#define SELECTED_BATTERY_CLASS ChademoBattery
|
|
||||||
|
|
||||||
class ChademoBattery : public CanBattery {
|
class ChademoBattery : public CanBattery {
|
||||||
public:
|
public:
|
||||||
|
@ -21,6 +18,8 @@ class ChademoBattery : public CanBattery {
|
||||||
virtual void update_values();
|
virtual void update_values();
|
||||||
virtual void transmit_can(unsigned long currentMillis);
|
virtual void transmit_can(unsigned long currentMillis);
|
||||||
|
|
||||||
|
static constexpr char* Name = "Chademo V2X mode";
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void process_vehicle_charging_minimums(CAN_frame rx_frame);
|
void process_vehicle_charging_minimums(CAN_frame rx_frame);
|
||||||
void process_vehicle_charging_maximums(CAN_frame rx_frame);
|
void process_vehicle_charging_maximums(CAN_frame rx_frame);
|
||||||
|
@ -127,7 +126,7 @@ uint8_t CHADEMO_seq = 0x0;
|
||||||
} status;
|
} status;
|
||||||
} s;
|
} s;
|
||||||
|
|
||||||
uint8_t StateOfCharge = 0; //6 state of charge?
|
uint8_t StateOfCharge = 50; //6 state of charge?
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ---------- CHARGING: EVSE Data structures */
|
/* ---------- CHARGING: EVSE Data structures */
|
||||||
|
@ -180,7 +179,7 @@ uint8_t CHADEMO_seq = 0x0;
|
||||||
//H200 - Vehicle - Discharge limits
|
//H200 - Vehicle - Discharge limits
|
||||||
struct x200_Vehicle_Discharge_Limits {
|
struct x200_Vehicle_Discharge_Limits {
|
||||||
uint8_t MaximumDischargeCurrent = 0xFF;
|
uint8_t MaximumDischargeCurrent = 0xFF;
|
||||||
uint16_t MinimumDischargeVoltage = 0;
|
uint16_t MinimumDischargeVoltage = 260; //Initialized to a semi-sane value, updates via CAN later
|
||||||
uint16_t MinimumBatteryDischargeLevel = 0;
|
uint16_t MinimumBatteryDischargeLevel = 0;
|
||||||
uint16_t MaxRemainingCapacityForCharging = 0;
|
uint16_t MaxRemainingCapacityForCharging = 0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -18,12 +18,11 @@
|
||||||
* by NJbubo
|
* by NJbubo
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#include "../include.h"
|
#include "CHADEMO-SHUNTS.h"
|
||||||
#ifdef CHADEMO_BATTERY
|
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
|
#include "../include.h"
|
||||||
#include "CHADEMO-BATTERY.h"
|
#include "CHADEMO-BATTERY.h"
|
||||||
#include "CHADEMO-SHUNTS.h"
|
|
||||||
|
|
||||||
/* Initial frames received from ISA shunts provide invalid during initialization */
|
/* Initial frames received from ISA shunts provide invalid during initialization */
|
||||||
static int framecount = 0;
|
static int framecount = 0;
|
||||||
|
@ -429,4 +428,3 @@ void ISA_getINFO(uint8_t i) {
|
||||||
|
|
||||||
transmit_can_frame(&outframe, can_config.battery);
|
transmit_can_frame(&outframe, can_config.battery);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
#ifndef CHADEMO_SHUNTS_H
|
#ifndef CHADEMO_SHUNTS_H
|
||||||
#define CHADEMO_SHUNTS_H
|
#define CHADEMO_SHUNTS_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "../devboard/utils/types.h"
|
||||||
|
|
||||||
uint16_t get_measured_voltage();
|
uint16_t get_measured_voltage();
|
||||||
uint16_t get_measured_current();
|
uint16_t get_measured_current();
|
||||||
void ISA_handleFrame(CAN_frame* frame);
|
void ISA_handleFrame(CAN_frame* frame);
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
#include "../include.h"
|
#include "CMFA-EV-BATTERY.h"
|
||||||
#ifdef CMFA_EV_BATTERY
|
|
||||||
#include "../communication/can/comm_can.h"
|
#include "../communication/can/comm_can.h"
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../datalayer/datalayer_extended.h"
|
#include "../datalayer/datalayer_extended.h"
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
#include "CMFA-EV-BATTERY.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
|
/* 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% */
|
Same goes for low point, when 10% is reached we report 0% */
|
||||||
|
@ -28,68 +27,68 @@ uint16_t CmfaEvBattery::rescale_raw_SOC(uint32_t raw_SOC) {
|
||||||
|
|
||||||
void CmfaEvBattery::
|
void CmfaEvBattery::
|
||||||
update_values() { //This function maps all the values fetched via CAN to the correct parameters used for modbus
|
update_values() { //This function maps all the values fetched via CAN to the correct parameters used for modbus
|
||||||
datalayer.battery.status.soh_pptt = (SOH * 100);
|
datalayer_battery->status.soh_pptt = (SOH * 100);
|
||||||
|
|
||||||
datalayer.battery.status.real_soc = rescale_raw_SOC(SOC_raw);
|
datalayer_battery->status.real_soc = rescale_raw_SOC(SOC_raw);
|
||||||
|
|
||||||
datalayer.battery.status.current_dA = current * 10;
|
datalayer_battery->status.current_dA = current * 10;
|
||||||
|
|
||||||
datalayer.battery.status.voltage_dV = average_voltage_of_cells / 100;
|
datalayer_battery->status.voltage_dV = average_voltage_of_cells / 100;
|
||||||
|
|
||||||
datalayer.battery.info.total_capacity_Wh = 27000;
|
datalayer_battery->info.total_capacity_Wh = 27000;
|
||||||
|
|
||||||
//Calculate the remaining Wh amount from SOC% and max Wh value.
|
//Calculate the remaining Wh amount from SOC% and max Wh value.
|
||||||
datalayer.battery.status.remaining_capacity_Wh = static_cast<uint32_t>(
|
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);
|
(static_cast<double>(datalayer_battery->status.real_soc) / 10000) * datalayer_battery->info.total_capacity_Wh);
|
||||||
|
|
||||||
datalayer.battery.status.max_discharge_power_W = discharge_power_w;
|
datalayer_battery->status.max_discharge_power_W = discharge_power_w;
|
||||||
|
|
||||||
datalayer.battery.status.max_charge_power_W = charge_power_w;
|
datalayer_battery->status.max_charge_power_W = charge_power_w;
|
||||||
|
|
||||||
datalayer.battery.status.temperature_min_dC = (lowest_cell_temperature * 10);
|
datalayer_battery->status.temperature_min_dC = (lowest_cell_temperature * 10);
|
||||||
|
|
||||||
datalayer.battery.status.temperature_max_dC = (highest_cell_temperature * 10);
|
datalayer_battery->status.temperature_max_dC = (highest_cell_temperature * 10);
|
||||||
|
|
||||||
datalayer.battery.status.cell_min_voltage_mV = lowest_cell_voltage_mv;
|
datalayer_battery->status.cell_min_voltage_mV = lowest_cell_voltage_mv;
|
||||||
|
|
||||||
datalayer.battery.status.cell_max_voltage_mV = highest_cell_voltage_mv;
|
datalayer_battery->status.cell_max_voltage_mV = highest_cell_voltage_mv;
|
||||||
|
|
||||||
//Map all cell voltages to the global array
|
//Map all cell voltages to the global array
|
||||||
memcpy(datalayer.battery.status.cell_voltages_mV, cellvoltages_mv, 72 * sizeof(uint16_t));
|
memcpy(datalayer_battery->status.cell_voltages_mV, cellvoltages_mv, 72 * sizeof(uint16_t));
|
||||||
|
|
||||||
if (lead_acid_voltage < 11000) { //11.000V
|
if (lead_acid_voltage < 11000) { //11.000V
|
||||||
set_event(EVENT_12V_LOW, lead_acid_voltage);
|
set_event(EVENT_12V_LOW, lead_acid_voltage);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update webserver datalayer
|
// Update webserver datalayer
|
||||||
datalayer_extended.CMFAEV.soc_u = soc_u;
|
datalayer_cmfa->soc_u = soc_u;
|
||||||
datalayer_extended.CMFAEV.soc_z = soc_z;
|
datalayer_cmfa->soc_z = soc_z;
|
||||||
datalayer_extended.CMFAEV.lead_acid_voltage = lead_acid_voltage;
|
datalayer_cmfa->lead_acid_voltage = lead_acid_voltage;
|
||||||
datalayer_extended.CMFAEV.highest_cell_voltage_number = highest_cell_voltage_number;
|
datalayer_cmfa->highest_cell_voltage_number = highest_cell_voltage_number;
|
||||||
datalayer_extended.CMFAEV.lowest_cell_voltage_number = lowest_cell_voltage_number;
|
datalayer_cmfa->lowest_cell_voltage_number = lowest_cell_voltage_number;
|
||||||
datalayer_extended.CMFAEV.max_regen_power = max_regen_power;
|
datalayer_cmfa->max_regen_power = max_regen_power;
|
||||||
datalayer_extended.CMFAEV.max_discharge_power = max_discharge_power;
|
datalayer_cmfa->max_discharge_power = max_discharge_power;
|
||||||
datalayer_extended.CMFAEV.average_temperature = average_temperature;
|
datalayer_cmfa->average_temperature = average_temperature;
|
||||||
datalayer_extended.CMFAEV.minimum_temperature = minimum_temperature;
|
datalayer_cmfa->minimum_temperature = minimum_temperature;
|
||||||
datalayer_extended.CMFAEV.maximum_temperature = maximum_temperature;
|
datalayer_cmfa->maximum_temperature = maximum_temperature;
|
||||||
datalayer_extended.CMFAEV.maximum_charge_power = maximum_charge_power;
|
datalayer_cmfa->maximum_charge_power = maximum_charge_power;
|
||||||
datalayer_extended.CMFAEV.SOH_available_power = SOH_available_power;
|
datalayer_cmfa->SOH_available_power = SOH_available_power;
|
||||||
datalayer_extended.CMFAEV.SOH_generated_power = SOH_generated_power;
|
datalayer_cmfa->SOH_generated_power = SOH_generated_power;
|
||||||
datalayer_extended.CMFAEV.cumulative_energy_when_discharging = cumulative_energy_when_discharging;
|
datalayer_cmfa->cumulative_energy_when_discharging = cumulative_energy_when_discharging;
|
||||||
datalayer_extended.CMFAEV.cumulative_energy_when_charging = cumulative_energy_when_charging;
|
datalayer_cmfa->cumulative_energy_when_charging = cumulative_energy_when_charging;
|
||||||
datalayer_extended.CMFAEV.cumulative_energy_in_regen = cumulative_energy_in_regen;
|
datalayer_cmfa->cumulative_energy_in_regen = cumulative_energy_in_regen;
|
||||||
datalayer_extended.CMFAEV.soh_average = soh_average;
|
datalayer_cmfa->soh_average = soh_average;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CmfaEvBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
void CmfaEvBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
||||||
switch (rx_frame.ID) { //These frames are transmitted by the battery
|
switch (rx_frame.ID) { //These frames are transmitted by the battery
|
||||||
case 0x127: //10ms , Same structure as old Zoe 0x155 message!
|
case 0x127: //10ms , Same structure as old Zoe 0x155 message!
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
current = (((((rx_frame.data.u8[1] & 0x0F) << 8) | rx_frame.data.u8[2]) * 0.25) - 500);
|
current = (((((rx_frame.data.u8[1] & 0x0F) << 8) | rx_frame.data.u8[2]) * 0.25) - 500);
|
||||||
SOC_raw = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]);
|
SOC_raw = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]);
|
||||||
break;
|
break;
|
||||||
case 0x3D6: //100ms, Same structure as old Zoe 0x424 message!
|
case 0x3D6: //100ms, Same structure as old Zoe 0x424 message!
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
charge_power_w = rx_frame.data.u8[2] * 500;
|
charge_power_w = rx_frame.data.u8[2] * 500;
|
||||||
discharge_power_w = rx_frame.data.u8[3] * 500;
|
discharge_power_w = rx_frame.data.u8[3] * 500;
|
||||||
lowest_cell_temperature = (rx_frame.data.u8[4] - 40);
|
lowest_cell_temperature = (rx_frame.data.u8[4] - 40);
|
||||||
|
@ -98,34 +97,34 @@ void CmfaEvBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
||||||
highest_cell_temperature = (rx_frame.data.u8[7] - 40);
|
highest_cell_temperature = (rx_frame.data.u8[7] - 40);
|
||||||
break;
|
break;
|
||||||
case 0x3D7: //100ms
|
case 0x3D7: //100ms
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
pack_voltage = ((rx_frame.data.u8[6] << 4 | (rx_frame.data.u8[5] & 0x0F)));
|
pack_voltage = ((rx_frame.data.u8[6] << 4 | (rx_frame.data.u8[5] & 0x0F)));
|
||||||
break;
|
break;
|
||||||
case 0x3D8: //100ms
|
case 0x3D8: //100ms
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
//counter_3D8 = rx_frame.data.u8[3]; //?
|
//counter_3D8 = rx_frame.data.u8[3]; //?
|
||||||
//CRC_3D8 = rx_frame.data.u8[4]; //?
|
//CRC_3D8 = rx_frame.data.u8[4]; //?
|
||||||
break;
|
break;
|
||||||
case 0x43C: //100ms
|
case 0x43C: //100ms
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
heartbeat2 = rx_frame.data.u8[2]; //Alternates between 0x55 and 0xAA every 5th frame
|
heartbeat2 = rx_frame.data.u8[2]; //Alternates between 0x55 and 0xAA every 5th frame
|
||||||
break;
|
break;
|
||||||
case 0x431: //100ms
|
case 0x431: //100ms
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
//byte0 9C always
|
//byte0 9C always
|
||||||
//byte1 40 always
|
//byte1 40 always
|
||||||
break;
|
break;
|
||||||
case 0x5A9:
|
case 0x5A9:
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
break;
|
break;
|
||||||
case 0x5AB:
|
case 0x5AB:
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
break;
|
break;
|
||||||
case 0x5C8:
|
case 0x5C8:
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
break;
|
break;
|
||||||
case 0x5E1:
|
case 0x5E1:
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
break;
|
break;
|
||||||
case 0x7BB: // Reply from battery
|
case 0x7BB: // Reply from battery
|
||||||
if (rx_frame.data.u8[0] == 0x10) { //PID header
|
if (rx_frame.data.u8[0] == 0x10) { //PID header
|
||||||
|
@ -941,15 +940,13 @@ void CmfaEvBattery::transmit_can(unsigned long currentMillis) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CmfaEvBattery::setup(void) { // Performs one time setup at startup
|
void CmfaEvBattery::setup(void) { // Performs one time setup at startup
|
||||||
strncpy(datalayer.system.info.battery_protocol, "CMFA platform, 27 kWh battery", 63);
|
strncpy(datalayer.system.info.battery_protocol, Name, 63);
|
||||||
datalayer.system.info.battery_protocol[63] = '\0';
|
datalayer.system.info.battery_protocol[63] = '\0';
|
||||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
datalayer.system.status.battery_allows_contactor_closing = true;
|
||||||
datalayer.battery.info.number_of_cells = 72;
|
datalayer_battery->info.number_of_cells = 72;
|
||||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
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.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV;
|
||||||
datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV;
|
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.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV;
|
||||||
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
datalayer_battery->info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //CMFA_EV_BATTERY
|
|
||||||
|
|
|
@ -5,21 +5,46 @@
|
||||||
#include "CMFA-EV-HTML.h"
|
#include "CMFA-EV-HTML.h"
|
||||||
#include "CanBattery.h"
|
#include "CanBattery.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#ifdef CMFA_EV_BATTERY
|
||||||
#define SELECTED_BATTERY_CLASS CmfaEvBattery
|
#define SELECTED_BATTERY_CLASS CmfaEvBattery
|
||||||
|
#endif
|
||||||
|
|
||||||
class CmfaEvBattery : public CanBattery {
|
class CmfaEvBattery : public CanBattery {
|
||||||
public:
|
public:
|
||||||
|
// Use this constructor for the second battery.
|
||||||
|
CmfaEvBattery(DATALAYER_BATTERY_TYPE* datalayer_ptr, DATALAYER_INFO_CMFAEV* extended, CAN_Interface targetCan)
|
||||||
|
: CanBattery(targetCan) {
|
||||||
|
datalayer_battery = datalayer_ptr;
|
||||||
|
allows_contactor_closing = nullptr;
|
||||||
|
datalayer_cmfa = extended;
|
||||||
|
|
||||||
|
average_voltage_of_cells = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the default constructor to create the first or single battery.
|
||||||
|
CmfaEvBattery() {
|
||||||
|
datalayer_battery = &datalayer.battery;
|
||||||
|
allows_contactor_closing = &datalayer.system.status.battery_allows_contactor_closing;
|
||||||
|
datalayer_cmfa = &datalayer_extended.CMFAEV;
|
||||||
|
}
|
||||||
|
|
||||||
virtual void setup(void);
|
virtual void setup(void);
|
||||||
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
||||||
virtual void update_values();
|
virtual void update_values();
|
||||||
virtual void transmit_can(unsigned long currentMillis);
|
virtual void transmit_can(unsigned long currentMillis);
|
||||||
|
static constexpr char* Name = "CMFA platform, 27 kWh battery";
|
||||||
|
|
||||||
BatteryHtmlRenderer& get_status_renderer() { return renderer; }
|
BatteryHtmlRenderer& get_status_renderer() { return renderer; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CmfaEvHtmlRenderer renderer;
|
CmfaEvHtmlRenderer renderer;
|
||||||
|
|
||||||
|
DATALAYER_BATTERY_TYPE* datalayer_battery;
|
||||||
|
DATALAYER_INFO_CMFAEV* datalayer_cmfa;
|
||||||
|
|
||||||
|
// If not null, this battery decides when the contactor can be closed and writes the value here.
|
||||||
|
bool* allows_contactor_closing;
|
||||||
|
|
||||||
uint16_t rescale_raw_SOC(uint32_t raw_SOC);
|
uint16_t rescale_raw_SOC(uint32_t raw_SOC);
|
||||||
|
|
||||||
static const int MAX_PACK_VOLTAGE_DV = 3040; // 5000 = 500.0V
|
static const int MAX_PACK_VOLTAGE_DV = 3040; // 5000 = 500.0V
|
||||||
|
|
8
Software/src/battery/CanBattery.cpp
Normal file
8
Software/src/battery/CanBattery.cpp
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#include "CanBattery.h"
|
||||||
|
#include "../../src/include.h"
|
||||||
|
|
||||||
|
CanBattery::CanBattery() {
|
||||||
|
can_interface = can_config.battery;
|
||||||
|
register_transmitter(this);
|
||||||
|
register_can_receiver(this, can_interface);
|
||||||
|
}
|
|
@ -22,11 +22,7 @@ class CanBattery : public Battery, Transmitter, CanReceiver {
|
||||||
protected:
|
protected:
|
||||||
CAN_Interface can_interface;
|
CAN_Interface can_interface;
|
||||||
|
|
||||||
CanBattery() {
|
CanBattery();
|
||||||
can_interface = can_config.battery;
|
|
||||||
register_transmitter(this);
|
|
||||||
register_can_receiver(this, can_interface);
|
|
||||||
}
|
|
||||||
|
|
||||||
CanBattery(CAN_Interface interface) {
|
CanBattery(CAN_Interface interface) {
|
||||||
can_interface = interface;
|
can_interface = interface;
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
#include "../include.h"
|
#include "DALY-BMS.h"
|
||||||
#ifdef DALY_BMS
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
#include "DALY-BMS.h"
|
#include "../include.h"
|
||||||
|
|
||||||
/* Do not change code below unless you are sure what you are doing */
|
/* Do not change code below unless you are sure what you are doing */
|
||||||
|
|
||||||
|
@ -61,7 +60,7 @@ void DalyBms::update_values() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DalyBms::setup(void) { // Performs one time setup at startup
|
void DalyBms::setup(void) { // Performs one time setup at startup
|
||||||
strncpy(datalayer.system.info.battery_protocol, "DALY RS485", 63);
|
strncpy(datalayer.system.info.battery_protocol, Name, 63);
|
||||||
datalayer.system.info.battery_protocol[63] = '\0';
|
datalayer.system.info.battery_protocol[63] = '\0';
|
||||||
datalayer.battery.info.number_of_cells = CELL_COUNT;
|
datalayer.battery.info.number_of_cells = CELL_COUNT;
|
||||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
||||||
|
@ -207,5 +206,3 @@ void DalyBms::receive() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -3,20 +3,9 @@
|
||||||
|
|
||||||
#include "RS485Battery.h"
|
#include "RS485Battery.h"
|
||||||
|
|
||||||
/* Tweak these according to your battery build */
|
#ifdef DALY_BMS
|
||||||
#define CELL_COUNT 14
|
|
||||||
#define MAX_PACK_VOLTAGE_DV 580 //580 = 58.0V
|
|
||||||
#define MIN_PACK_VOLTAGE_DV 460 //480 = 48.0V
|
|
||||||
#define MAX_CELL_VOLTAGE_MV 4200 //Battery is put into emergency stop if one cell goes over this value
|
|
||||||
#define MIN_CELL_VOLTAGE_MV 3200 //Battery is put into emergency stop if one cell goes below this value
|
|
||||||
#define POWER_PER_PERCENT 50 // below 20% and above 80% limit power to 50W * SOC (i.e. 150W at 3%, 500W at 10%, ...)
|
|
||||||
#define POWER_PER_DEGREE_C 60 // max power added/removed per degree above/below 0°C
|
|
||||||
#define POWER_AT_0_DEGREE_C 800 // power at 0°C
|
|
||||||
|
|
||||||
/* Do not modify any rows below*/
|
|
||||||
#define BATTERY_SELECTED
|
|
||||||
#define RS485_BATTERY_SELECTED
|
|
||||||
#define SELECTED_BATTERY_CLASS DalyBms
|
#define SELECTED_BATTERY_CLASS DalyBms
|
||||||
|
#endif
|
||||||
|
|
||||||
class DalyBms : public RS485Battery {
|
class DalyBms : public RS485Battery {
|
||||||
public:
|
public:
|
||||||
|
@ -24,8 +13,20 @@ class DalyBms : public RS485Battery {
|
||||||
void update_values();
|
void update_values();
|
||||||
void transmit_rs485(unsigned long currentMillis);
|
void transmit_rs485(unsigned long currentMillis);
|
||||||
void receive();
|
void receive();
|
||||||
|
static constexpr char* Name = "DALY RS485";
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/* Tweak these according to your battery build */
|
||||||
|
static const int CELL_COUNT = 14;
|
||||||
|
static const int MAX_PACK_VOLTAGE_DV = 580; //580 = 58.0V
|
||||||
|
static const int MIN_PACK_VOLTAGE_DV = 460; //480 = 48.0V
|
||||||
|
static const int MAX_CELL_VOLTAGE_MV = 4200; //Battery is put into emergency stop if one cell goes over this value
|
||||||
|
static const int MIN_CELL_VOLTAGE_MV = 3200; //Battery is put into emergency stop if one cell goes below this value
|
||||||
|
static const int POWER_PER_PERCENT =
|
||||||
|
50; // below 20% and above 80% limit power to 50W * SOC (i.e. 150W at 3%, 500W at 10%, ...)
|
||||||
|
static const int POWER_PER_DEGREE_C = 60; // max power added/removed per degree above/below 0°C
|
||||||
|
static const int POWER_AT_0_DEGREE_C = 800; // power at 0°C
|
||||||
|
|
||||||
int baud_rate() { return 9600; }
|
int baud_rate() { return 9600; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,13 @@
|
||||||
#include "../include.h"
|
#include "ECMP-BATTERY.h"
|
||||||
#ifdef STELLANTIS_ECMP_BATTERY
|
|
||||||
#include "../communication/can/comm_can.h"
|
#include "../communication/can/comm_can.h"
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../datalayer/datalayer_extended.h" //For More Battery Info page
|
#include "../datalayer/datalayer_extended.h" //For More Battery Info page
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
#include "ECMP-BATTERY.h"
|
#include "../include.h"
|
||||||
|
|
||||||
/* TODO:
|
/* TODO:
|
||||||
This integration is still ongoing. Here is what still needs to be done in order to use this battery type
|
This integration is still ongoing. Here is what still needs to be done in order to use this battery type
|
||||||
- Disable the isolation resistance requirement that opens contactors after 30s
|
- Disable the isolation resistance requirement that opens contactors after 30s under load. Factory mode?
|
||||||
- Battery says it might need 37E and 485, but no logs of this?
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Do not change code below unless you are sure what you are doing */
|
/* Do not change code below unless you are sure what you are doing */
|
||||||
|
@ -21,7 +19,7 @@ void EcmpBattery::update_values() {
|
||||||
|
|
||||||
datalayer.battery.status.voltage_dV = battery_voltage * 10;
|
datalayer.battery.status.voltage_dV = battery_voltage * 10;
|
||||||
|
|
||||||
datalayer.battery.status.current_dA = battery_current * 10;
|
datalayer.battery.status.current_dA = -(battery_current * 10);
|
||||||
|
|
||||||
datalayer.battery.status.active_power_W = //Power in watts, Negative = charging batt
|
datalayer.battery.status.active_power_W = //Power in watts, Negative = charging batt
|
||||||
((datalayer.battery.status.voltage_dV * datalayer.battery.status.current_dA) / 100);
|
((datalayer.battery.status.voltage_dV * datalayer.battery.status.current_dA) / 100);
|
||||||
|
@ -375,19 +373,31 @@ void EcmpBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
||||||
if (datalayer_extended.stellantisECMP.UserRequestDisableIsoMonitoring) {
|
if (datalayer_extended.stellantisECMP.UserRequestDisableIsoMonitoring) {
|
||||||
if ((rx_frame.data.u8[0] == 0x06) && (rx_frame.data.u8[1] == 0x50) && (rx_frame.data.u8[2] == 0x03)) {
|
if ((rx_frame.data.u8[0] == 0x06) && (rx_frame.data.u8[1] == 0x50) && (rx_frame.data.u8[2] == 0x03)) {
|
||||||
//06,50,03,00,C8,00,14,00,
|
//06,50,03,00,C8,00,14,00,
|
||||||
DisableIsoMonitoringStatemachine = 2; //Send ECMP_FACTORY_MODE_ACTIVATION next loop
|
DisableIsoMonitoringStatemachine = 2; //Send ECMP_ACK_MESSAGE (02 3e 00)
|
||||||
}
|
}
|
||||||
//if ((rx_frame.data.u8[0] == 0x03) && (rx_frame.data.u8[1] == 0x7F) && (rx_frame.data.u8[2] == 0x2E)) {
|
if ((rx_frame.data.u8[0] == 0x02) && (rx_frame.data.u8[1] == 0x7E) && (rx_frame.data.u8[2] == 0x00)) {
|
||||||
if (DisableIsoMonitoringStatemachine == 3) {
|
//Expected 02,7E,00
|
||||||
DisableIsoMonitoringStatemachine = 4;
|
DisableIsoMonitoringStatemachine = 4; //Send ECMP_FACTORY_MODE_ACTIVATION next loop
|
||||||
}
|
}
|
||||||
//if ((rx_frame.data.u8[0] == 0x03) && (rx_frame.data.u8[1] == 0x7F) && (rx_frame.data.u8[2] == 0x2E)) {
|
if ((rx_frame.data.u8[0] == 0x03) && (rx_frame.data.u8[1] == 0x6E) && (rx_frame.data.u8[2] == 0xD9)) {
|
||||||
if (DisableIsoMonitoringStatemachine == 5) {
|
//Factory mode ENTRY: 2E.D9.00.01
|
||||||
DisableIsoMonitoringStatemachine = 6;
|
DisableIsoMonitoringStatemachine = 6; //Send ECMP_DISABLE_ISOLATION_REQ next loop
|
||||||
}
|
}
|
||||||
//if ((rx_frame.data.u8[0] == 0x03) && (rx_frame.data.u8[1] == 0x7F) && (rx_frame.data.u8[2] == 0x31)) {
|
if ((rx_frame.data.u8[0] == 0x03) && (rx_frame.data.u8[1] == 0x7F) && (rx_frame.data.u8[2] == 0x2E)) {
|
||||||
if (DisableIsoMonitoringStatemachine == 7) {
|
//Factory mode fails to enter with 7F
|
||||||
//UNKNOWN? 03,7F,31,24 (or 7F?)
|
set_event(EVENT_PID_FAILED, rx_frame.data.u8[2]);
|
||||||
|
DisableIsoMonitoringStatemachine =
|
||||||
|
6; //Send ECMP_DISABLE_ISOLATION_REQ next loop (pointless, since it will fail)
|
||||||
|
}
|
||||||
|
if ((rx_frame.data.u8[0] == 0x04) && (rx_frame.data.u8[1] == 0x31) && (rx_frame.data.u8[2] == 0x02)) {
|
||||||
|
//Disable isolation successful 04 31 02 df e1
|
||||||
|
DisableIsoMonitoringStatemachine = COMPLETED_STATE;
|
||||||
|
datalayer_extended.stellantisECMP.UserRequestDisableIsoMonitoring = false;
|
||||||
|
timeSpentDisableIsoMonitoring = COMPLETED_STATE;
|
||||||
|
}
|
||||||
|
if ((rx_frame.data.u8[0] == 0x03) && (rx_frame.data.u8[1] == 0x7F) && (rx_frame.data.u8[2] == 0x31)) {
|
||||||
|
//Disable Isolation fails to enter with 7F
|
||||||
|
set_event(EVENT_PID_FAILED, rx_frame.data.u8[2]);
|
||||||
DisableIsoMonitoringStatemachine = COMPLETED_STATE;
|
DisableIsoMonitoringStatemachine = COMPLETED_STATE;
|
||||||
datalayer_extended.stellantisECMP.UserRequestDisableIsoMonitoring = false;
|
datalayer_extended.stellantisECMP.UserRequestDisableIsoMonitoring = false;
|
||||||
timeSpentDisableIsoMonitoring = COMPLETED_STATE;
|
timeSpentDisableIsoMonitoring = COMPLETED_STATE;
|
||||||
|
@ -535,10 +545,10 @@ void EcmpBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
||||||
pid_avg_cell_voltage = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
pid_avg_cell_voltage = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
||||||
break;
|
break;
|
||||||
case PID_CURRENT:
|
case PID_CURRENT:
|
||||||
pid_current = (((rx_frame.data.u8[4] << 24) | (rx_frame.data.u8[5] << 16) | (rx_frame.data.u8[6] << 8) |
|
pid_current = -(((rx_frame.data.u8[4] << 24) | (rx_frame.data.u8[5] << 16) | (rx_frame.data.u8[6] << 8) |
|
||||||
rx_frame.data.u8[7]) -
|
rx_frame.data.u8[7]) -
|
||||||
76800) *
|
76800) *
|
||||||
10;
|
20;
|
||||||
break;
|
break;
|
||||||
case PID_INSULATION_NEG:
|
case PID_INSULATION_NEG:
|
||||||
pid_insulation_res_neg = ((rx_frame.data.u8[4] << 24) | (rx_frame.data.u8[5] << 16) |
|
pid_insulation_res_neg = ((rx_frame.data.u8[4] << 24) | (rx_frame.data.u8[5] << 16) |
|
||||||
|
@ -579,7 +589,7 @@ void EcmpBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
||||||
pid_lowest_cell_voltage_num = (rx_frame.data.u8[4]);
|
pid_lowest_cell_voltage_num = (rx_frame.data.u8[4]);
|
||||||
break;
|
break;
|
||||||
case PID_SUM_OF_CELLS:
|
case PID_SUM_OF_CELLS:
|
||||||
pid_sum_of_cells = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
pid_sum_of_cells = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) / 2;
|
||||||
break;
|
break;
|
||||||
case PID_CELL_MIN_CAPACITY:
|
case PID_CELL_MIN_CAPACITY:
|
||||||
pid_cell_min_capacity = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
pid_cell_min_capacity = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
||||||
|
@ -846,15 +856,15 @@ void EcmpBattery::transmit_can(unsigned long currentMillis) {
|
||||||
DisableIsoMonitoringStatemachine = 1;
|
DisableIsoMonitoringStatemachine = 1;
|
||||||
}
|
}
|
||||||
if (DisableIsoMonitoringStatemachine == 2) {
|
if (DisableIsoMonitoringStatemachine == 2) {
|
||||||
transmit_can_frame(&ECMP_FACTORY_MODE_ACTIVATION_NEW, can_config.battery);
|
transmit_can_frame(&ECMP_ACK_MESSAGE, can_config.battery);
|
||||||
DisableIsoMonitoringStatemachine = 3;
|
DisableIsoMonitoringStatemachine = 3;
|
||||||
}
|
}
|
||||||
if (DisableIsoMonitoringStatemachine == 4) {
|
if (DisableIsoMonitoringStatemachine == 4) {
|
||||||
transmit_can_frame(&ECMP_DISABLE_ISOLATION_REQ, can_config.battery);
|
transmit_can_frame(&ECMP_FACTORY_MODE_ACTIVATION, can_config.battery);
|
||||||
DisableIsoMonitoringStatemachine = 5;
|
DisableIsoMonitoringStatemachine = 5;
|
||||||
}
|
}
|
||||||
if (DisableIsoMonitoringStatemachine == 6) {
|
if (DisableIsoMonitoringStatemachine == 6) {
|
||||||
transmit_can_frame(&ECMP_FACTORY_MODE_ACTIVATION, can_config.battery);
|
transmit_can_frame(&ECMP_DISABLE_ISOLATION_REQ, can_config.battery);
|
||||||
DisableIsoMonitoringStatemachine = 7;
|
DisableIsoMonitoringStatemachine = 7;
|
||||||
}
|
}
|
||||||
timeSpentDisableIsoMonitoring++;
|
timeSpentDisableIsoMonitoring++;
|
||||||
|
@ -1322,9 +1332,11 @@ void EcmpBattery::transmit_can(unsigned long currentMillis) {
|
||||||
transmit_can_frame(&ECMP_0C5, can_config.battery); //DC2_0C5
|
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_17B, can_config.battery); //VCU_PCANInfo_17B
|
||||||
transmit_can_frame(&ECMP_0F2, can_config.battery); //CtrlMCU1_0F2
|
transmit_can_frame(&ECMP_0F2, can_config.battery); //CtrlMCU1_0F2
|
||||||
transmit_can_frame(&ECMP_111, can_config.battery);
|
if (simulateEntireCar) {
|
||||||
transmit_can_frame(&ECMP_110, can_config.battery);
|
transmit_can_frame(&ECMP_111, can_config.battery);
|
||||||
transmit_can_frame(&ECMP_114, can_config.battery);
|
transmit_can_frame(&ECMP_110, can_config.battery);
|
||||||
|
transmit_can_frame(&ECMP_114, can_config.battery);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send 20ms periodic CAN Message simulating the car still being attached
|
// Send 20ms periodic CAN Message simulating the car still being attached
|
||||||
|
@ -1356,7 +1368,7 @@ void EcmpBattery::transmit_can(unsigned long currentMillis) {
|
||||||
ECMP_27A.data = {0x4F, 0x58, 0x00, 0x02, 0x24, 0x00, 0x00, 0x00};
|
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_230, can_config.battery); //OBC3_230
|
||||||
transmit_can_frame(&ECMP_27A, can_config.battery); //PSA specific VCU message (VCU_BSI_Wakeup_27A)
|
transmit_can_frame(&ECMP_27A, can_config.battery); //VCU_BSI_Wakeup_27A
|
||||||
}
|
}
|
||||||
// Send 100ms periodic CAN Message simulating the car still being attached
|
// Send 100ms periodic CAN Message simulating the car still being attached
|
||||||
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
|
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
|
||||||
|
@ -1464,20 +1476,23 @@ void EcmpBattery::transmit_can(unsigned long currentMillis) {
|
||||||
transmit_can_frame(&ECMP_345, can_config.battery); //DC1_345
|
transmit_can_frame(&ECMP_345, can_config.battery); //DC1_345
|
||||||
transmit_can_frame(&ECMP_3A2, can_config.battery); //OBC2_3A2
|
transmit_can_frame(&ECMP_3A2, can_config.battery); //OBC2_3A2
|
||||||
transmit_can_frame(&ECMP_3A3, can_config.battery); //OBC1_3A3
|
transmit_can_frame(&ECMP_3A3, can_config.battery); //OBC1_3A3
|
||||||
transmit_can_frame(&ECMP_31E, can_config.battery);
|
transmit_can_frame(&ECMP_010, can_config.battery); //VCU_BCM_Crash
|
||||||
transmit_can_frame(&ECMP_383, can_config.battery);
|
if (simulateEntireCar) {
|
||||||
transmit_can_frame(&ECMP_010, can_config.battery);
|
transmit_can_frame(&ECMP_31E, can_config.battery);
|
||||||
transmit_can_frame(&ECMP_0A6, can_config.battery); //Not in all logs
|
transmit_can_frame(&ECMP_383, can_config.battery);
|
||||||
transmit_can_frame(&ECMP_37F, can_config.battery); //Seems to be temperatures of some sort
|
transmit_can_frame(&ECMP_0A6, can_config.battery); //Not in all logs
|
||||||
transmit_can_frame(&ECMP_372, can_config.battery);
|
transmit_can_frame(&ECMP_37F, can_config.battery); //Seems to be temperatures of some sort
|
||||||
transmit_can_frame(&ECMP_351, can_config.battery);
|
transmit_can_frame(&ECMP_372, can_config.battery);
|
||||||
transmit_can_frame(&ECMP_31D, can_config.battery);
|
transmit_can_frame(&ECMP_351, can_config.battery);
|
||||||
|
transmit_can_frame(&ECMP_31D, can_config.battery);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Send 500ms periodic CAN Message simulating the car still being attached
|
// Send 500ms periodic CAN Message simulating the car still being attached
|
||||||
if (currentMillis - previousMillis500 >= INTERVAL_500_MS) {
|
if (currentMillis - previousMillis500 >= INTERVAL_500_MS) {
|
||||||
previousMillis500 = currentMillis;
|
previousMillis500 = currentMillis;
|
||||||
|
if (simulateEntireCar) {
|
||||||
transmit_can_frame(&ECMP_0AE, can_config.battery);
|
transmit_can_frame(&ECMP_0AE, can_config.battery);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Send 1s CAN Message
|
// Send 1s CAN Message
|
||||||
if (currentMillis - previousMillis1000 >= INTERVAL_1_S) {
|
if (currentMillis - previousMillis1000 >= INTERVAL_1_S) {
|
||||||
|
@ -1500,24 +1515,27 @@ void EcmpBattery::transmit_can(unsigned long currentMillis) {
|
||||||
ECMP_552.data.u8[2] = ((ticks_552 & 0x0000FF00) >> 8);
|
ECMP_552.data.u8[2] = ((ticks_552 & 0x0000FF00) >> 8);
|
||||||
ECMP_552.data.u8[3] = (ticks_552 & 0x000000FF);
|
ECMP_552.data.u8[3] = (ticks_552 & 0x000000FF);
|
||||||
|
|
||||||
transmit_can_frame(&ECMP_439, can_config.battery); //PSA Specific? Not in all logs
|
transmit_can_frame(&ECMP_439, can_config.battery); //OBC4
|
||||||
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_552, can_config.battery); //VCU_552 timetracking
|
transmit_can_frame(&ECMP_552, can_config.battery); //VCU_552 timetracking
|
||||||
transmit_can_frame(&ECMP_794, can_config.battery); //Not in all logs
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Send 5s periodic CAN Message simulating the car still being attached
|
// Send 5s periodic CAN Message simulating the car still being attached
|
||||||
if (currentMillis - previousMillis5000 >= INTERVAL_5_S) {
|
if (currentMillis - previousMillis5000 >= INTERVAL_5_S) {
|
||||||
previousMillis5000 = currentMillis;
|
previousMillis5000 = currentMillis;
|
||||||
|
if (simulateEntireCar) {
|
||||||
transmit_can_frame(&ECMP_55F, can_config.battery);
|
transmit_can_frame(&ECMP_55F, can_config.battery);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EcmpBattery::setup(void) { // Performs one time setup at startup
|
void EcmpBattery::setup(void) { // Performs one time setup at startup
|
||||||
strncpy(datalayer.system.info.battery_protocol, "Stellantis ECMP battery", 63);
|
strncpy(datalayer.system.info.battery_protocol, Name, 63);
|
||||||
datalayer.system.info.battery_protocol[63] = '\0';
|
datalayer.system.info.battery_protocol[63] = '\0';
|
||||||
datalayer.battery.info.number_of_cells = 108;
|
datalayer.battery.info.number_of_cells = 108;
|
||||||
datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV;
|
datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV;
|
||||||
|
@ -1527,5 +1545,3 @@ void EcmpBattery::setup(void) { // Performs one time setup at startup
|
||||||
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV;
|
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV;
|
||||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
datalayer.system.status.battery_allows_contactor_closing = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -6,8 +6,9 @@
|
||||||
#include "CanBattery.h"
|
#include "CanBattery.h"
|
||||||
#include "ECMP-HTML.h"
|
#include "ECMP-HTML.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#ifdef STELLANTIS_ECMP_BATTERY
|
||||||
#define SELECTED_BATTERY_CLASS EcmpBattery
|
#define SELECTED_BATTERY_CLASS EcmpBattery
|
||||||
|
#endif
|
||||||
|
|
||||||
class EcmpBattery : public CanBattery {
|
class EcmpBattery : public CanBattery {
|
||||||
public:
|
public:
|
||||||
|
@ -15,6 +16,7 @@ class EcmpBattery : public CanBattery {
|
||||||
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
||||||
virtual void update_values();
|
virtual void update_values();
|
||||||
virtual void transmit_can(unsigned long currentMillis);
|
virtual void transmit_can(unsigned long currentMillis);
|
||||||
|
static constexpr char* Name = "Stellantis ECMP battery";
|
||||||
|
|
||||||
bool supports_clear_isolation() { return true; }
|
bool supports_clear_isolation() { return true; }
|
||||||
void clear_isolation() { datalayer_extended.stellantisECMP.UserRequestIsolationReset = true; }
|
void clear_isolation() { datalayer_extended.stellantisECMP.UserRequestIsolationReset = true; }
|
||||||
|
@ -37,8 +39,10 @@ class EcmpBattery : public CanBattery {
|
||||||
static const int MAX_CELL_DEVIATION_MV = 100;
|
static const int MAX_CELL_DEVIATION_MV = 100;
|
||||||
static const int MAX_CELL_VOLTAGE_MV = 4250;
|
static const int MAX_CELL_VOLTAGE_MV = 4250;
|
||||||
static const int MIN_CELL_VOLTAGE_MV = 2700;
|
static const int MIN_CELL_VOLTAGE_MV = 2700;
|
||||||
#define NOT_SAMPLED_YET 255
|
bool simulateEntireCar =
|
||||||
#define COMPLETED_STATE 0
|
false; //Set this to true to simulate the whole car (useful for when using external diagnostic tools)
|
||||||
|
static const int NOT_SAMPLED_YET = 255;
|
||||||
|
static const int COMPLETED_STATE = 0;
|
||||||
bool battery_RelayOpenRequest = false;
|
bool battery_RelayOpenRequest = false;
|
||||||
bool battery_InterlockOpen = false;
|
bool battery_InterlockOpen = false;
|
||||||
uint8_t ContactorResetStatemachine = 0;
|
uint8_t ContactorResetStatemachine = 0;
|
||||||
|
@ -142,82 +146,82 @@ class EcmpBattery : public CanBattery {
|
||||||
unsigned long previousMillis500 = 0; // will store last time a 500ms 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
|
unsigned long previousMillis1000 = 0; // will store last time a 1000ms CAN Message was sent
|
||||||
unsigned long previousMillis5000 = 0; // will store last time a 1000ms CAN Message was sent
|
unsigned long previousMillis5000 = 0; // will store last time a 1000ms CAN Message was sent
|
||||||
#define PID_WELD_CHECK 0xD814
|
|
||||||
#define PID_CONT_REASON_OPEN 0xD812
|
static const uint16_t PID_WELD_CHECK = 0xD814;
|
||||||
#define PID_CONTACTOR_STATUS 0xD813
|
static const uint16_t PID_CONT_REASON_OPEN = 0xD812;
|
||||||
#define PID_NEG_CONT_CONTROL 0xD44F
|
static const uint16_t PID_CONTACTOR_STATUS = 0xD813;
|
||||||
#define PID_NEG_CONT_STATUS 0xD453
|
static const uint16_t PID_NEG_CONT_CONTROL = 0xD44F;
|
||||||
#define PID_POS_CONT_CONTROL 0xD44E
|
static const uint16_t PID_NEG_CONT_STATUS = 0xD453;
|
||||||
#define PID_POS_CONT_STATUS 0xD452
|
static const uint16_t PID_POS_CONT_CONTROL = 0xD44E;
|
||||||
#define PID_CONTACTOR_NEGATIVE 0xD44C
|
static const uint16_t PID_POS_CONT_STATUS = 0xD452;
|
||||||
#define PID_CONTACTOR_POSITIVE 0xD44D
|
static const uint16_t PID_CONTACTOR_NEGATIVE = 0xD44C;
|
||||||
#define PID_PRECHARGE_RELAY_CONTROL 0xD44B
|
static const uint16_t PID_CONTACTOR_POSITIVE = 0xD44D;
|
||||||
#define PID_PRECHARGE_RELAY_STATUS 0xD451
|
static const uint16_t PID_PRECHARGE_RELAY_CONTROL = 0xD44B;
|
||||||
#define PID_RECHARGE_STATUS 0xD864
|
static const uint16_t PID_PRECHARGE_RELAY_STATUS = 0xD451;
|
||||||
#define PID_DELTA_TEMPERATURE 0xD878
|
static const uint16_t PID_RECHARGE_STATUS = 0xD864;
|
||||||
#define PID_COLDEST_MODULE 0xD446
|
static const uint16_t PID_DELTA_TEMPERATURE = 0xD878;
|
||||||
#define PID_LOWEST_TEMPERATURE 0xD87D
|
static const uint16_t PID_COLDEST_MODULE = 0xD446;
|
||||||
#define PID_AVERAGE_TEMPERATURE 0xD877
|
static const uint16_t PID_LOWEST_TEMPERATURE = 0xD87D;
|
||||||
#define PID_HIGHEST_TEMPERATURE 0xD817
|
static const uint16_t PID_AVERAGE_TEMPERATURE = 0xD877;
|
||||||
#define PID_HOTTEST_MODULE 0xD445
|
static const uint16_t PID_HIGHEST_TEMPERATURE = 0xD817;
|
||||||
#define PID_AVG_CELL_VOLTAGE 0xD43D
|
static const uint16_t PID_HOTTEST_MODULE = 0xD445;
|
||||||
#define PID_CURRENT 0xD816
|
static const uint16_t PID_AVG_CELL_VOLTAGE = 0xD43D;
|
||||||
#define PID_INSULATION_NEG 0xD87C
|
static const uint16_t PID_CURRENT = 0xD816;
|
||||||
#define PID_INSULATION_POS 0xD87B
|
static const uint16_t PID_INSULATION_NEG = 0xD87C;
|
||||||
#define PID_MAX_CURRENT_10S 0xD876
|
static const uint16_t PID_INSULATION_POS = 0xD87B;
|
||||||
#define PID_MAX_DISCHARGE_10S 0xD873
|
static const uint16_t PID_MAX_CURRENT_10S = 0xD876;
|
||||||
#define PID_MAX_DISCHARGE_30S 0xD874
|
static const uint16_t PID_MAX_DISCHARGE_10S = 0xD873;
|
||||||
#define PID_MAX_CHARGE_10S 0xD871
|
static const uint16_t PID_MAX_DISCHARGE_30S = 0xD874;
|
||||||
#define PID_MAX_CHARGE_30S 0xD872
|
static const uint16_t PID_MAX_CHARGE_10S = 0xD871;
|
||||||
#define PID_ENERGY_CAPACITY 0xD860
|
static const uint16_t PID_MAX_CHARGE_30S = 0xD872;
|
||||||
#define PID_HIGH_CELL_NUM 0xD43B
|
static const uint16_t PID_ENERGY_CAPACITY = 0xD860;
|
||||||
#define PID_LOW_CELL_NUM 0xD43C
|
static const uint16_t PID_HIGH_CELL_NUM = 0xD43B;
|
||||||
#define PID_SUM_OF_CELLS 0xD438
|
static const uint16_t PID_LOW_CELL_NUM = 0xD43C;
|
||||||
#define PID_CELL_MIN_CAPACITY 0xD413
|
static const uint16_t PID_SUM_OF_CELLS = 0xD438;
|
||||||
#define PID_CELL_VOLTAGE_MEAS_STATUS 0xD48A
|
static const uint16_t PID_CELL_MIN_CAPACITY = 0xD413;
|
||||||
#define PID_INSULATION_RES 0xD47A
|
static const uint16_t PID_CELL_VOLTAGE_MEAS_STATUS = 0xD48A;
|
||||||
#define PID_PACK_VOLTAGE 0xD815
|
static const uint16_t PID_INSULATION_RES = 0xD47A;
|
||||||
#define PID_HIGH_CELL_VOLTAGE 0xD870
|
static const uint16_t PID_PACK_VOLTAGE = 0xD815;
|
||||||
#define PID_ALL_CELL_VOLTAGES 0xD440 //Multi-frame
|
static const uint16_t PID_HIGH_CELL_VOLTAGE = 0xD870;
|
||||||
#define PID_LOW_CELL_VOLTAGE 0xD86F
|
static const uint16_t PID_ALL_CELL_VOLTAGES = 0xD440; //Multi-frame
|
||||||
#define PID_BATTERY_ENERGY 0xD865
|
static const uint16_t PID_LOW_CELL_VOLTAGE = 0xD86F;
|
||||||
#define PID_BATTERY_ENERGY 0xD865
|
static const uint16_t PID_BATTERY_ENERGY = 0xD865;
|
||||||
#define PID_CELLBALANCE_STATUS 0xD46F //Multi-frame?
|
static const uint16_t PID_CELLBALANCE_STATUS = 0xD46F; //Multi-frame?
|
||||||
#define PID_CELLBALANCE_HWERR_MASK 0xD470 //Multi-frame
|
static const uint16_t PID_CELLBALANCE_HWERR_MASK = 0xD470; //Multi-frame
|
||||||
#define PID_CRASH_COUNTER 0xD42F
|
static const uint16_t PID_CRASH_COUNTER = 0xD42F;
|
||||||
#define PID_WIRE_CRASH 0xD87F
|
static const uint16_t PID_WIRE_CRASH = 0xD87F;
|
||||||
#define PID_CAN_CRASH 0xD48D
|
static const uint16_t PID_CAN_CRASH = 0xD48D;
|
||||||
#define PID_HISTORY_DATA 0xD465
|
static const uint16_t PID_HISTORY_DATA = 0xD465;
|
||||||
#define PID_LOWSOC_COUNTER 0xD492 //Not supported on all batteris
|
static const uint16_t PID_LOWSOC_COUNTER = 0xD492; //Not supported on all batteris
|
||||||
#define PID_LAST_CAN_FAILURE_DETAIL 0xD89E //Not supported on all batteris
|
static const uint16_t PID_LAST_CAN_FAILURE_DETAIL = 0xD89E; //Not supported on all batteris
|
||||||
#define PID_HW_VERSION_NUM 0xF193 //Not supported on all batteris
|
static const uint16_t PID_HW_VERSION_NUM = 0xF193; //Not supported on all batteris
|
||||||
#define PID_SW_VERSION_NUM 0xF195 //Not supported on all batteris
|
static const uint16_t PID_SW_VERSION_NUM = 0xF195; //Not supported on all batteris
|
||||||
#define PID_FACTORY_MODE_CONTROL 0xD900
|
static const uint16_t PID_FACTORY_MODE_CONTROL = 0xD900;
|
||||||
#define PID_BATTERY_SERIAL 0xD901
|
static const uint16_t PID_BATTERY_SERIAL = 0xD901;
|
||||||
#define PID_ALL_CELL_SOH 0xD4B5 //Very long message reply, too much data for this integration
|
static const uint16_t PID_ALL_CELL_SOH = 0xD4B5; //Very long message reply, too much data for this integration
|
||||||
#define PID_AUX_FUSE_STATE 0xD86C
|
static const uint16_t PID_AUX_FUSE_STATE = 0xD86C;
|
||||||
#define PID_BATTERY_STATE 0xD811
|
static const uint16_t PID_BATTERY_STATE = 0xD811;
|
||||||
#define PID_PRECHARGE_SHORT_CIRCUIT 0xD4D8
|
static const uint16_t PID_PRECHARGE_SHORT_CIRCUIT = 0xD4D8;
|
||||||
#define PID_ESERVICE_PLUG_STATE 0xD86A
|
static const uint16_t PID_ESERVICE_PLUG_STATE = 0xD86A;
|
||||||
#define PID_MAINFUSE_STATE 0xD86B
|
static const uint16_t PID_MAINFUSE_STATE = 0xD86B;
|
||||||
#define PID_MOST_CRITICAL_FAULT 0xD481
|
static const uint16_t PID_MOST_CRITICAL_FAULT = 0xD481;
|
||||||
#define PID_CURRENT_TIME 0xD47F
|
static const uint16_t PID_CURRENT_TIME = 0xD47F;
|
||||||
#define PID_TIME_SENT_BY_CAR 0xD4CA
|
static const uint16_t PID_TIME_SENT_BY_CAR = 0xD4CA;
|
||||||
#define PID_12V 0xD822
|
static const uint16_t PID_12V = 0xD822;
|
||||||
#define PID_12V_ABNORMAL 0xD42B
|
static const uint16_t PID_12V_ABNORMAL = 0xD42B;
|
||||||
#define PID_HVIL_IN_VOLTAGE 0xD46B
|
static const uint16_t PID_HVIL_IN_VOLTAGE = 0xD46B;
|
||||||
#define PID_HVIL_OUT_VOLTAGE 0xD46A
|
static const uint16_t PID_HVIL_OUT_VOLTAGE = 0xD46A;
|
||||||
#define PID_HVIL_STATE 0xD869
|
static const uint16_t PID_HVIL_STATE = 0xD869;
|
||||||
#define PID_BMS_STATE 0xD45A
|
static const uint16_t PID_BMS_STATE = 0xD45A;
|
||||||
#define PID_VEHICLE_SPEED 0xD802
|
static const uint16_t PID_VEHICLE_SPEED = 0xD802;
|
||||||
#define PID_TIME_SPENT_OVER_55C 0xE082
|
static const uint16_t PID_TIME_SPENT_OVER_55C = 0xE082;
|
||||||
#define PID_CONTACTOR_CLOSING_COUNTER 0xD416
|
static const uint16_t PID_CONTACTOR_CLOSING_COUNTER = 0xD416;
|
||||||
#define PID_DATE_OF_MANUFACTURE 0xF18B
|
static const uint16_t PID_DATE_OF_MANUFACTURE = 0xF18B;
|
||||||
|
|
||||||
uint16_t poll_state = PID_WELD_CHECK;
|
uint16_t poll_state = PID_WELD_CHECK;
|
||||||
uint16_t incoming_poll = 0;
|
uint16_t incoming_poll = 0;
|
||||||
|
|
||||||
CAN_frame ECMP_010 = {.FD = false, .ext_ID = false, .DLC = 1, .ID = 0x010, .data = {0xB4}};
|
CAN_frame ECMP_010 = {.FD = false, .ext_ID = false, .DLC = 1, .ID = 0x010, .data = {0xB4}}; //VCU_BCM_Crash 100ms
|
||||||
CAN_frame ECMP_041 = {.FD = false, .ext_ID = false, .DLC = 1, .ID = 0x041, .data = {0x00}};
|
CAN_frame ECMP_041 = {.FD = false, .ext_ID = false, .DLC = 1, .ID = 0x041, .data = {0x00}};
|
||||||
CAN_frame ECMP_0A6 = {.FD = false,
|
CAN_frame ECMP_0A6 = {.FD = false,
|
||||||
.ext_ID = false,
|
.ext_ID = false,
|
||||||
|
@ -333,7 +337,7 @@ class EcmpBattery : public CanBattery {
|
||||||
.DLC = 8,
|
.DLC = 8,
|
||||||
.ID = 0x3A3,
|
.ID = 0x3A3,
|
||||||
.data = {0x4A, 0x4A, 0x40, 0x00, 0x00, 0x08, 0x00, 0x0F}};
|
.data = {0x4A, 0x4A, 0x40, 0x00, 0x00, 0x08, 0x00, 0x0F}};
|
||||||
CAN_frame ECMP_439 = {.FD = false, //??? 1s periodic (Perfectly emulated in Battery-Emulator)
|
CAN_frame ECMP_439 = {.FD = false, //OBC4 1s periodic (Perfectly emulated in Battery-Emulator)
|
||||||
.ext_ID = false, //Same content always, fully static
|
.ext_ID = false, //Same content always, fully static
|
||||||
.DLC = 8,
|
.DLC = 8,
|
||||||
.ID = 0x439,
|
.ID = 0x439,
|
||||||
|
@ -412,16 +416,12 @@ class EcmpBattery : public CanBattery {
|
||||||
.DLC = 5,
|
.DLC = 5,
|
||||||
.ID = 0x6B4,
|
.ID = 0x6B4,
|
||||||
.data = {0x04, 0x2E, 0xD9, 0x00, 0x01}};
|
.data = {0x04, 0x2E, 0xD9, 0x00, 0x01}};
|
||||||
CAN_frame ECMP_FACTORY_MODE_ACTIVATION_NEW = {.FD = false,
|
|
||||||
.ext_ID = false,
|
|
||||||
.DLC = 4,
|
|
||||||
.ID = 0x6B4,
|
|
||||||
.data = {0x04, 0x2E, 0x19, 0x01}};
|
|
||||||
CAN_frame ECMP_DISABLE_ISOLATION_REQ = {.FD = false,
|
CAN_frame ECMP_DISABLE_ISOLATION_REQ = {.FD = false,
|
||||||
.ext_ID = false,
|
.ext_ID = false,
|
||||||
.DLC = 5,
|
.DLC = 5,
|
||||||
.ID = 0x6B4,
|
.ID = 0x6B4,
|
||||||
.data = {0x04, 0x31, 0x02, 0xDF, 0xE1}};
|
.data = {0x04, 0x31, 0x02, 0xDF, 0xE1}};
|
||||||
|
CAN_frame ECMP_ACK_MESSAGE = {.FD = false, .ext_ID = false, .DLC = 3, .ID = 0x6B4, .data = {0x02, 0x3E, 0x00}};
|
||||||
uint8_t data_010_CRC[8] = {0xB4, 0x96, 0x78, 0x5A, 0x3C, 0x1E, 0xF0, 0xD2};
|
uint8_t data_010_CRC[8] = {0xB4, 0x96, 0x78, 0x5A, 0x3C, 0x1E, 0xF0, 0xD2};
|
||||||
uint8_t data_3A2_CRC[16] = {0x0C, 0x1B, 0x2A, 0x39, 0x48, 0x57,
|
uint8_t data_3A2_CRC[16] = {0x0C, 0x1B, 0x2A, 0x39, 0x48, 0x57,
|
||||||
0x66, 0x75, 0x84, 0x93, 0xA2, 0xB1}; // NOTE. Changes on BMS state
|
0x66, 0x75, 0x84, 0x93, 0xA2, 0xB1}; // NOTE. Changes on BMS state
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
#include "../include.h"
|
#include "FOXESS-BATTERY.h"
|
||||||
#ifdef FOXESS_BATTERY
|
|
||||||
#include "../communication/can/comm_can.h"
|
#include "../communication/can/comm_can.h"
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
#include "FOXESS-BATTERY.h"
|
#include "../include.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Can bus @ 500k - all Extended ID, little endian
|
Can bus @ 500k - all Extended ID, little endian
|
||||||
|
@ -573,7 +572,7 @@ void FoxessBattery::transmit_can(unsigned long currentMillis) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FoxessBattery::setup(void) { // Performs one time setup at startup
|
void FoxessBattery::setup(void) { // Performs one time setup at startup
|
||||||
strncpy(datalayer.system.info.battery_protocol, "FoxESS HV2600/ECS4100 OEM battery", 63);
|
strncpy(datalayer.system.info.battery_protocol, Name, 63);
|
||||||
datalayer.system.info.battery_protocol[63] = '\0';
|
datalayer.system.info.battery_protocol[63] = '\0';
|
||||||
datalayer.battery.info.number_of_cells = 0; //Startup with no cells, populates later when we know packsize
|
datalayer.battery.info.number_of_cells = 0; //Startup with no cells, populates later when we know packsize
|
||||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
||||||
|
@ -583,5 +582,3 @@ void FoxessBattery::setup(void) { // Performs one time setup at startup
|
||||||
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
||||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
datalayer.system.status.battery_allows_contactor_closing = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -5,8 +5,9 @@
|
||||||
|
|
||||||
#include "CanBattery.h"
|
#include "CanBattery.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#ifdef FOXESS_BATTERY
|
||||||
#define SELECTED_BATTERY_CLASS FoxessBattery
|
#define SELECTED_BATTERY_CLASS FoxessBattery
|
||||||
|
#endif
|
||||||
|
|
||||||
class FoxessBattery : public CanBattery {
|
class FoxessBattery : public CanBattery {
|
||||||
public:
|
public:
|
||||||
|
@ -14,6 +15,7 @@ class FoxessBattery : public CanBattery {
|
||||||
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
||||||
virtual void update_values();
|
virtual void update_values();
|
||||||
virtual void transmit_can(unsigned long currentMillis);
|
virtual void transmit_can(unsigned long currentMillis);
|
||||||
|
static constexpr char* Name = "FoxESS HV2600/ECS4100 OEM battery";
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const int MAX_PACK_VOLTAGE_DV = 4672; //467.2V for HS20.8 (used during startup, refined later)
|
static const int MAX_PACK_VOLTAGE_DV = 4672; //467.2V for HS20.8 (used during startup, refined later)
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
#include "../include.h"
|
#include "GEELY-GEOMETRY-C-BATTERY.h"
|
||||||
#ifdef GEELY_GEOMETRY_C_BATTERY
|
|
||||||
#include "../communication/can/comm_can.h"
|
#include "../communication/can/comm_can.h"
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../datalayer/datalayer_extended.h" //For "More battery info" webpage
|
#include "../datalayer/datalayer_extended.h" //For "More battery info" webpage
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
#include "GEELY-GEOMETRY-C-BATTERY.h"
|
#include "../include.h"
|
||||||
|
|
||||||
/* TODO
|
/* 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
|
- 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
|
||||||
|
@ -661,7 +660,7 @@ void GeelyGeometryCBattery::transmit_can(unsigned long currentMillis) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GeelyGeometryCBattery::setup(void) { // Performs one time setup at startup
|
void GeelyGeometryCBattery::setup(void) { // Performs one time setup at startup
|
||||||
strncpy(datalayer.system.info.battery_protocol, "Geely Geometry C", 63);
|
strncpy(datalayer.system.info.battery_protocol, Name, 63);
|
||||||
datalayer.system.info.battery_protocol[63] = '\0';
|
datalayer.system.info.battery_protocol[63] = '\0';
|
||||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
datalayer.system.status.battery_allows_contactor_closing = true;
|
||||||
datalayer_battery->info.number_of_cells = 102; //70kWh pack has 102S, startup in this mode
|
datalayer_battery->info.number_of_cells = 102; //70kWh pack has 102S, startup in this mode
|
||||||
|
@ -671,5 +670,3 @@ void GeelyGeometryCBattery::setup(void) { // Performs one time setup at startup
|
||||||
datalayer_battery->info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV;
|
datalayer_battery->info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV;
|
||||||
datalayer_battery->info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
datalayer_battery->info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -6,29 +6,9 @@
|
||||||
#include "CanBattery.h"
|
#include "CanBattery.h"
|
||||||
#include "GEELY-GEOMETRY-C-HTML.h"
|
#include "GEELY-GEOMETRY-C-HTML.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#ifdef GEELY_GEOMETRY_C_BATTERY
|
||||||
#define SELECTED_BATTERY_CLASS GeelyGeometryCBattery
|
#define SELECTED_BATTERY_CLASS GeelyGeometryCBattery
|
||||||
|
#endif
|
||||||
#define POLL_SOC 0x4B35
|
|
||||||
#define POLL_CC2_VOLTAGE 0x4BCF
|
|
||||||
#define POLL_CELL_MAX_VOLTAGE_NUMBER 0x4B1E
|
|
||||||
#define POLL_CELL_MIN_VOLTAGE_NUMBER 0x4B20
|
|
||||||
#define POLL_AMOUNT_CELLS 0x4B07
|
|
||||||
#define POLL_SPECIFICIAL_VOLTAGE 0x4B05
|
|
||||||
#define POLL_UNKNOWN_1 0x4BDA //245 on two batteries
|
|
||||||
#define POLL_RAW_SOC_MAX 0x4BC3
|
|
||||||
#define POLL_RAW_SOC_MIN 0x4BC4
|
|
||||||
#define POLL_UNKNOWN_4 0xDF00 //144 (the other battery 143)
|
|
||||||
#define POLL_CAPACITY_MODULE_MAX 0x4B3D
|
|
||||||
#define POLL_CAPACITY_MODULE_MIN 0x4B3E
|
|
||||||
#define POLL_UNKNOWN_7 0x4B24 //1 (the other battery 23)
|
|
||||||
#define POLL_UNKNOWN_8 0x4B26 //16 (the other battery 33)
|
|
||||||
#define POLL_MULTI_TEMPS 0x4B0F
|
|
||||||
#define POLL_MULTI_UNKNOWN_2 0x4B10
|
|
||||||
#define POLL_MULTI_UNKNOWN_3 0x4B53
|
|
||||||
#define POLL_MULTI_UNKNOWN_4 0x4B54
|
|
||||||
#define POLL_MULTI_HARDWARE_VERSION 0x4B6B
|
|
||||||
#define POLL_MULTI_SOFTWARE_VERSION 0x4B6C
|
|
||||||
|
|
||||||
class GeelyGeometryCBattery : public CanBattery {
|
class GeelyGeometryCBattery : public CanBattery {
|
||||||
public:
|
public:
|
||||||
|
@ -36,10 +16,32 @@ class GeelyGeometryCBattery : public CanBattery {
|
||||||
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
||||||
virtual void update_values();
|
virtual void update_values();
|
||||||
virtual void transmit_can(unsigned long currentMillis);
|
virtual void transmit_can(unsigned long currentMillis);
|
||||||
|
static constexpr char* Name = "Geely Geometry C";
|
||||||
|
|
||||||
BatteryHtmlRenderer& get_status_renderer() { return renderer; }
|
BatteryHtmlRenderer& get_status_renderer() { return renderer; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static const int POLL_SOC = 0x4B35;
|
||||||
|
static const int POLL_CC2_VOLTAGE = 0x4BCF;
|
||||||
|
static const int POLL_CELL_MAX_VOLTAGE_NUMBER = 0x4B1E;
|
||||||
|
static const int POLL_CELL_MIN_VOLTAGE_NUMBER = 0x4B20;
|
||||||
|
static const int POLL_AMOUNT_CELLS = 0x4B07;
|
||||||
|
static const int POLL_SPECIFICIAL_VOLTAGE = 0x4B05;
|
||||||
|
static const int POLL_UNKNOWN_1 = 0x4BDA; //245 on two batteries
|
||||||
|
static const int POLL_RAW_SOC_MAX = 0x4BC3;
|
||||||
|
static const int POLL_RAW_SOC_MIN = 0x4BC4;
|
||||||
|
static const int POLL_UNKNOWN_4 = 0xDF00; //144 (the other battery 143)
|
||||||
|
static const int POLL_CAPACITY_MODULE_MAX = 0x4B3D;
|
||||||
|
static const int POLL_CAPACITY_MODULE_MIN = 0x4B3E;
|
||||||
|
static const int POLL_UNKNOWN_7 = 0x4B24; //1 (the other battery 23)
|
||||||
|
static const int POLL_UNKNOWN_8 = 0x4B26; //16 (the other battery 33)
|
||||||
|
static const int POLL_MULTI_TEMPS = 0x4B0F;
|
||||||
|
static const int POLL_MULTI_UNKNOWN_2 = 0x4B10;
|
||||||
|
static const int POLL_MULTI_UNKNOWN_3 = 0x4B53;
|
||||||
|
static const int POLL_MULTI_UNKNOWN_4 = 0x4B54;
|
||||||
|
static const int POLL_MULTI_HARDWARE_VERSION = 0x4B6B;
|
||||||
|
static const int POLL_MULTI_SOFTWARE_VERSION = 0x4B6C;
|
||||||
|
|
||||||
GeelyGeometryCHtmlRenderer renderer;
|
GeelyGeometryCHtmlRenderer renderer;
|
||||||
|
|
||||||
static const int MAX_PACK_VOLTAGE_70_DV = 4420; //70kWh
|
static const int MAX_PACK_VOLTAGE_70_DV = 4420; //70kWh
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
#include "../include.h"
|
#include "IMIEV-CZERO-ION-BATTERY.h"
|
||||||
#ifdef IMIEV_CZERO_ION_BATTERY
|
|
||||||
#include "../communication/can/comm_can.h"
|
#include "../communication/can/comm_can.h"
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
#include "IMIEV-CZERO-ION-BATTERY.h"
|
#include "../include.h"
|
||||||
|
|
||||||
//Code still work in progress, TODO:
|
//Code still work in progress, TODO:
|
||||||
//Figure out if CAN messages need to be sent to keep the system happy?
|
//Figure out if CAN messages need to be sent to keep the system happy?
|
||||||
|
@ -191,7 +190,7 @@ void ImievCZeroIonBattery::transmit_can(unsigned long currentMillis) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImievCZeroIonBattery::setup(void) { // Performs one time setup at startup
|
void ImievCZeroIonBattery::setup(void) { // Performs one time setup at startup
|
||||||
strncpy(datalayer.system.info.battery_protocol, "I-Miev / C-Zero / Ion Triplet", 63);
|
strncpy(datalayer.system.info.battery_protocol, Name, 63);
|
||||||
datalayer.system.info.battery_protocol[63] = '\0';
|
datalayer.system.info.battery_protocol[63] = '\0';
|
||||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
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.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV;
|
||||||
|
@ -200,5 +199,3 @@ void ImievCZeroIonBattery::setup(void) { // Performs one time setup at startup
|
||||||
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
||||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
datalayer.system.status.battery_allows_contactor_closing = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -5,8 +5,9 @@
|
||||||
|
|
||||||
#include "CanBattery.h"
|
#include "CanBattery.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#ifdef IMIEV_CZERO_ION_BATTERY
|
||||||
#define SELECTED_BATTERY_CLASS ImievCZeroIonBattery
|
#define SELECTED_BATTERY_CLASS ImievCZeroIonBattery
|
||||||
|
#endif
|
||||||
|
|
||||||
class ImievCZeroIonBattery : public CanBattery {
|
class ImievCZeroIonBattery : public CanBattery {
|
||||||
public:
|
public:
|
||||||
|
@ -14,6 +15,7 @@ class ImievCZeroIonBattery : public CanBattery {
|
||||||
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
||||||
virtual void update_values();
|
virtual void update_values();
|
||||||
virtual void transmit_can(unsigned long currentMillis);
|
virtual void transmit_can(unsigned long currentMillis);
|
||||||
|
static constexpr char* Name = "I-Miev / C-Zero / Ion Triplet";
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const int MAX_PACK_VOLTAGE_DV = 3696; //5000 = 500.0V
|
static const int MAX_PACK_VOLTAGE_DV = 3696; //5000 = 500.0V
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
#include "../include.h"
|
#include "JAGUAR-IPACE-BATTERY.h"
|
||||||
#ifdef JAGUAR_IPACE_BATTERY
|
|
||||||
#include "../communication/can/comm_can.h"
|
#include "../communication/can/comm_can.h"
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
#include "JAGUAR-IPACE-BATTERY.h"
|
#include "../include.h"
|
||||||
|
|
||||||
/* Do not change code below unless you are sure what you are doing */
|
/* Do not change code below unless you are sure what you are doing */
|
||||||
static unsigned long previousMillisKeepAlive = 0;
|
static unsigned long previousMillisKeepAlive = 0;
|
||||||
|
@ -57,7 +56,7 @@ CAN_frame ipace_keep_alive = {.FD = false,
|
||||||
.ID = 0x59e,
|
.ID = 0x59e,
|
||||||
.data = {0x9E, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}};*/
|
.data = {0x9E, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}};*/
|
||||||
|
|
||||||
void print_units(char* header, int value, char* units) {
|
static void print_units(char* header, int value, char* units) {
|
||||||
logging.print(header);
|
logging.print(header);
|
||||||
logging.print(value);
|
logging.print(value);
|
||||||
logging.print(units);
|
logging.print(units);
|
||||||
|
@ -237,5 +236,3 @@ void JaguarIpaceBattery::setup(void) { // Performs one time setup at startup
|
||||||
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
||||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
datalayer.system.status.battery_allows_contactor_closing = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -3,14 +3,9 @@
|
||||||
|
|
||||||
#include "CanBattery.h"
|
#include "CanBattery.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#ifdef JAGUAR_IPACE_BATTERY
|
||||||
#define SELECTED_BATTERY_CLASS JaguarIpaceBattery
|
#define SELECTED_BATTERY_CLASS JaguarIpaceBattery
|
||||||
|
#endif
|
||||||
#define MAX_PACK_VOLTAGE_DV 4546 //5000 = 500.0V
|
|
||||||
#define MIN_PACK_VOLTAGE_DV 3370
|
|
||||||
#define MAX_CELL_DEVIATION_MV 250
|
|
||||||
#define MAX_CELL_VOLTAGE_MV 4250 //Battery is put into emergency stop if one cell goes over this value
|
|
||||||
#define MIN_CELL_VOLTAGE_MV 2700 //Battery is put into emergency stop if one cell goes below this value
|
|
||||||
|
|
||||||
class JaguarIpaceBattery : public CanBattery {
|
class JaguarIpaceBattery : public CanBattery {
|
||||||
public:
|
public:
|
||||||
|
@ -18,6 +13,14 @@ class JaguarIpaceBattery : public CanBattery {
|
||||||
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
||||||
virtual void update_values();
|
virtual void update_values();
|
||||||
virtual void transmit_can(unsigned long currentMillis);
|
virtual void transmit_can(unsigned long currentMillis);
|
||||||
|
static constexpr char* Name = "Jaguar I-PACE";
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const int MAX_PACK_VOLTAGE_DV = 4546; //5000 = 500.0V
|
||||||
|
static const int MIN_PACK_VOLTAGE_DV = 3370;
|
||||||
|
static const int MAX_CELL_DEVIATION_MV = 250;
|
||||||
|
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
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
#include "../include.h"
|
#include "KIA-E-GMP-BATTERY.h"
|
||||||
#ifdef KIA_E_GMP_BATTERY
|
|
||||||
#include "../communication/can/comm_can.h"
|
#include "../communication/can/comm_can.h"
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
|
#include "../include.h"
|
||||||
#include "../lib/pierremolinaro-ACAN2517FD/ACAN2517FD.h"
|
#include "../lib/pierremolinaro-ACAN2517FD/ACAN2517FD.h"
|
||||||
#include "KIA-E-GMP-BATTERY.h"
|
|
||||||
|
|
||||||
const unsigned char crc8_table[256] =
|
const unsigned char crc8_table[256] =
|
||||||
{ // CRC8_SAE_J1850_ZER0 formula,0x1D Poly,initial value 0x3F,Final XOR value varies
|
{ // CRC8_SAE_J1850_ZER0 formula,0x1D Poly,initial value 0x3F,Final XOR value varies
|
||||||
|
@ -1091,7 +1090,7 @@ void KiaEGmpBattery::transmit_can(unsigned long currentMillis) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void KiaEGmpBattery::setup(void) { // Performs one time setup at startup
|
void KiaEGmpBattery::setup(void) { // Performs one time setup at startup
|
||||||
strncpy(datalayer.system.info.battery_protocol, "Kia/Hyundai EGMP platform", 63);
|
strncpy(datalayer.system.info.battery_protocol, Name, 63);
|
||||||
datalayer.system.info.battery_protocol[63] = '\0';
|
datalayer.system.info.battery_protocol[63] = '\0';
|
||||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
datalayer.system.status.battery_allows_contactor_closing = true;
|
||||||
datalayer.battery.info.number_of_cells = 192; // TODO: will vary depending on battery
|
datalayer.battery.info.number_of_cells = 192; // TODO: will vary depending on battery
|
||||||
|
@ -1101,5 +1100,3 @@ void KiaEGmpBattery::setup(void) { // Performs one time setup at startup
|
||||||
datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV;
|
datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV;
|
||||||
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -9,8 +9,9 @@ extern ACAN2517FD canfd;
|
||||||
|
|
||||||
#define ESTIMATE_SOC_FROM_CELLVOLTAGE
|
#define ESTIMATE_SOC_FROM_CELLVOLTAGE
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#ifdef KIA_E_GMP_BATTERY
|
||||||
#define SELECTED_BATTERY_CLASS KiaEGmpBattery
|
#define SELECTED_BATTERY_CLASS KiaEGmpBattery
|
||||||
|
#endif
|
||||||
|
|
||||||
class KiaEGmpBattery : public CanBattery {
|
class KiaEGmpBattery : public CanBattery {
|
||||||
public:
|
public:
|
||||||
|
@ -18,6 +19,7 @@ class KiaEGmpBattery : public CanBattery {
|
||||||
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
||||||
virtual void update_values();
|
virtual void update_values();
|
||||||
virtual void transmit_can(unsigned long currentMillis);
|
virtual void transmit_can(unsigned long currentMillis);
|
||||||
|
static constexpr char* Name = "Kia/Hyundai EGMP platform";
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint16_t estimateSOC(uint16_t packVoltage, uint16_t cellCount, int16_t currentAmps);
|
uint16_t estimateSOC(uint16_t packVoltage, uint16_t cellCount, int16_t currentAmps);
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
#include "../include.h"
|
#include "KIA-HYUNDAI-64-BATTERY.h"
|
||||||
#ifdef KIA_HYUNDAI_64_BATTERY
|
|
||||||
#include "../communication/can/comm_can.h"
|
#include "../communication/can/comm_can.h"
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../datalayer/datalayer_extended.h"
|
#include "../datalayer/datalayer_extended.h"
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
#include "KIA-HYUNDAI-64-BATTERY.h"
|
#include "../include.h"
|
||||||
|
|
||||||
void KiaHyundai64Battery::
|
void KiaHyundai64Battery::
|
||||||
update_values() { //This function maps all the values fetched via CAN to the correct parameters used for modbus
|
update_values() { //This function maps all the values fetched via CAN to the correct parameters used for modbus
|
||||||
|
@ -112,21 +111,18 @@ void KiaHyundai64Battery::
|
||||||
}
|
}
|
||||||
|
|
||||||
void KiaHyundai64Battery::update_number_of_cells() {
|
void KiaHyundai64Battery::update_number_of_cells() {
|
||||||
//If we have cell values and number_of_cells not initialized yet
|
// Check if we have 98S or 90S battery. If the 98th cell is valid range, we are on a 98S battery
|
||||||
if (cellvoltages_mv[0] > 0 && datalayer_battery->info.number_of_cells == 0) {
|
if ((datalayer_battery->status.cell_voltages_mV[97] > 2000) &&
|
||||||
// Check if we have 98S or 90S battery. If the 98th cell is valid range, we are on a 98S battery
|
(datalayer_battery->status.cell_voltages_mV[97] < 4500)) {
|
||||||
if ((datalayer_battery->status.cell_voltages_mV[97] > 2000) &&
|
datalayer_battery->info.number_of_cells = 98;
|
||||||
(datalayer_battery->status.cell_voltages_mV[97] < 4300)) {
|
datalayer_battery->info.max_design_voltage_dV = MAX_PACK_VOLTAGE_98S_DV;
|
||||||
datalayer_battery->info.number_of_cells = 98;
|
datalayer_battery->info.min_design_voltage_dV = MIN_PACK_VOLTAGE_98S_DV;
|
||||||
datalayer_battery->info.max_design_voltage_dV = MAX_PACK_VOLTAGE_98S_DV;
|
datalayer_battery->info.total_capacity_Wh = 64000;
|
||||||
datalayer_battery->info.min_design_voltage_dV = MIN_PACK_VOLTAGE_98S_DV;
|
} else {
|
||||||
datalayer_battery->info.total_capacity_Wh = 64000;
|
datalayer_battery->info.number_of_cells = 90;
|
||||||
} else {
|
datalayer_battery->info.max_design_voltage_dV = MAX_PACK_VOLTAGE_90S_DV;
|
||||||
datalayer_battery->info.number_of_cells = 90;
|
datalayer_battery->info.min_design_voltage_dV = MIN_PACK_VOLTAGE_90S_DV;
|
||||||
datalayer_battery->info.max_design_voltage_dV = MAX_PACK_VOLTAGE_90S_DV;
|
datalayer_battery->info.total_capacity_Wh = 40000;
|
||||||
datalayer_battery->info.min_design_voltage_dV = MIN_PACK_VOLTAGE_90S_DV;
|
|
||||||
datalayer_battery->info.total_capacity_Wh = 40000;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,16 +361,18 @@ void KiaHyundai64Battery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x26: //Sixth datarow in PID group
|
case 0x26: //Sixth datarow in PID group
|
||||||
//We have read all cells, check that content is valid:
|
if (poll_data_pid == 5) {
|
||||||
for (uint8_t i = 85; i < 97; ++i) {
|
//We have read all cells, check that content is valid:
|
||||||
if (cellvoltages_mv[i] < 300) { // Zero the value if it's below 300
|
for (uint8_t i = 85; i < 97; ++i) {
|
||||||
cellvoltages_mv[i] = 0; // Some packs incorrectly report the last unpopulated cells as 20-60mV
|
if (cellvoltages_mv[i] < 300) { // Zero the value if it's below 300
|
||||||
|
cellvoltages_mv[i] = 0; // Some packs incorrectly report the last unpopulated cells as 20-60mV
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
//Map all cell voltages to the global array
|
||||||
|
memcpy(datalayer_battery->status.cell_voltages_mV, cellvoltages_mv, 98 * sizeof(uint16_t));
|
||||||
|
//Update number of cells
|
||||||
|
update_number_of_cells();
|
||||||
}
|
}
|
||||||
//Map all cell voltages to the global array
|
|
||||||
memcpy(datalayer_battery->status.cell_voltages_mV, cellvoltages_mv, 98 * sizeof(uint16_t));
|
|
||||||
//Update number of cells
|
|
||||||
update_number_of_cells();
|
|
||||||
break;
|
break;
|
||||||
case 0x27: //Seventh datarow in PID group
|
case 0x27: //Seventh datarow in PID group
|
||||||
if (poll_data_pid == 1) {
|
if (poll_data_pid == 1) {
|
||||||
|
@ -465,7 +463,7 @@ void KiaHyundai64Battery::transmit_can(unsigned long currentMillis) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void KiaHyundai64Battery::setup(void) { // Performs one time setup at startup
|
void KiaHyundai64Battery::setup(void) { // Performs one time setup at startup
|
||||||
strncpy(datalayer.system.info.battery_protocol, "Kia/Hyundai 64/40kWh battery", 63);
|
strncpy(datalayer.system.info.battery_protocol, Name, 63);
|
||||||
datalayer.system.info.battery_protocol[63] = '\0';
|
datalayer.system.info.battery_protocol[63] = '\0';
|
||||||
datalayer_battery->info.max_design_voltage_dV = MAX_PACK_VOLTAGE_98S_DV; //Start with 98S value. Precised later
|
datalayer_battery->info.max_design_voltage_dV = MAX_PACK_VOLTAGE_98S_DV; //Start with 98S value. Precised later
|
||||||
datalayer_battery->info.min_design_voltage_dV = MIN_PACK_VOLTAGE_90S_DV; //Start with 90S value. Precised later
|
datalayer_battery->info.min_design_voltage_dV = MIN_PACK_VOLTAGE_90S_DV; //Start with 90S value. Precised later
|
||||||
|
@ -476,5 +474,3 @@ void KiaHyundai64Battery::setup(void) { // Performs one time setup at startup
|
||||||
*allows_contactor_closing = true;
|
*allows_contactor_closing = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -7,8 +7,9 @@
|
||||||
#include "CanBattery.h"
|
#include "CanBattery.h"
|
||||||
#include "KIA-HYUNDAI-64-HTML.h"
|
#include "KIA-HYUNDAI-64-HTML.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#ifdef KIA_HYUNDAI_64_BATTERY
|
||||||
#define SELECTED_BATTERY_CLASS KiaHyundai64Battery
|
#define SELECTED_BATTERY_CLASS KiaHyundai64Battery
|
||||||
|
#endif
|
||||||
|
|
||||||
class KiaHyundai64Battery : public CanBattery {
|
class KiaHyundai64Battery : public CanBattery {
|
||||||
public:
|
public:
|
||||||
|
@ -34,6 +35,7 @@ class KiaHyundai64Battery : public CanBattery {
|
||||||
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
||||||
virtual void update_values();
|
virtual void update_values();
|
||||||
virtual void transmit_can(unsigned long currentMillis);
|
virtual void transmit_can(unsigned long currentMillis);
|
||||||
|
static constexpr char* Name = "Kia/Hyundai 64/40kWh battery";
|
||||||
|
|
||||||
BatteryHtmlRenderer& get_status_renderer() { return renderer; }
|
BatteryHtmlRenderer& get_status_renderer() { return renderer; }
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
#include "../include.h"
|
#include "KIA-HYUNDAI-HYBRID-BATTERY.h"
|
||||||
#ifdef KIA_HYUNDAI_HYBRID_BATTERY
|
|
||||||
#include "../communication/can/comm_can.h"
|
#include "../communication/can/comm_can.h"
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
#include "KIA-HYUNDAI-HYBRID-BATTERY.h"
|
#include "../include.h"
|
||||||
|
|
||||||
/* TODO:
|
/* TODO:
|
||||||
- The HEV battery seems to turn off after 1 minute of use. When this happens SOC% stops updating.
|
- The HEV battery seems to turn off after 1 minute of use. When this happens SOC% stops updating.
|
||||||
|
@ -215,7 +214,7 @@ void KiaHyundaiHybridBattery::transmit_can(unsigned long currentMillis) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void KiaHyundaiHybridBattery::setup(void) { // Performs one time setup at startup
|
void KiaHyundaiHybridBattery::setup(void) { // Performs one time setup at startup
|
||||||
strncpy(datalayer.system.info.battery_protocol, "Kia/Hyundai Hybrid", 63);
|
strncpy(datalayer.system.info.battery_protocol, Name, 63);
|
||||||
datalayer.system.info.battery_protocol[63] = '\0';
|
datalayer.system.info.battery_protocol[63] = '\0';
|
||||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
datalayer.system.status.battery_allows_contactor_closing = true;
|
||||||
datalayer.battery.info.number_of_cells = 56; // HEV , TODO: Make dynamic according to HEV/PHEV
|
datalayer.battery.info.number_of_cells = 56; // HEV , TODO: Make dynamic according to HEV/PHEV
|
||||||
|
@ -224,5 +223,3 @@ void KiaHyundaiHybridBattery::setup(void) { // Performs one time setup at start
|
||||||
datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV;
|
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.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -5,8 +5,9 @@
|
||||||
|
|
||||||
#include "CanBattery.h"
|
#include "CanBattery.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#ifdef KIA_HYUNDAI_HYBRID_BATTERY
|
||||||
#define SELECTED_BATTERY_CLASS KiaHyundaiHybridBattery
|
#define SELECTED_BATTERY_CLASS KiaHyundaiHybridBattery
|
||||||
|
#endif
|
||||||
|
|
||||||
class KiaHyundaiHybridBattery : public CanBattery {
|
class KiaHyundaiHybridBattery : public CanBattery {
|
||||||
public:
|
public:
|
||||||
|
@ -14,6 +15,7 @@ class KiaHyundaiHybridBattery : public CanBattery {
|
||||||
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
||||||
virtual void update_values();
|
virtual void update_values();
|
||||||
virtual void transmit_can(unsigned long currentMillis);
|
virtual void transmit_can(unsigned long currentMillis);
|
||||||
|
static constexpr char* Name = "Kia/Hyundai Hybrid";
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const int MAX_PACK_VOLTAGE_DV = 2550; //5000 = 500.0V
|
static const int MAX_PACK_VOLTAGE_DV = 2550; //5000 = 500.0V
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
#include "../include.h"
|
#include "MEB-BATTERY.h"
|
||||||
#ifdef MEB_BATTERY
|
|
||||||
#include <algorithm> // For std::min and std::max
|
#include <algorithm> // For std::min and std::max
|
||||||
#include "../communication/can/comm_can.h"
|
#include "../communication/can/comm_can.h"
|
||||||
#include "../communication/can/obd.h"
|
#include "../communication/can/obd.h"
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../datalayer/datalayer_extended.h" //For "More battery info" webpage
|
#include "../datalayer/datalayer_extended.h" //For "More battery info" webpage
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
#include "MEB-BATTERY.h"
|
#include "../include.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
TODO list
|
TODO list
|
||||||
|
@ -2036,7 +2035,7 @@ void MebBattery::transmit_can(unsigned long currentMillis) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MebBattery::setup(void) { // Performs one time setup at startup
|
void MebBattery::setup(void) { // Performs one time setup at startup
|
||||||
strncpy(datalayer.system.info.battery_protocol, "Volkswagen Group MEB platform via CAN-FD", 63);
|
strncpy(datalayer.system.info.battery_protocol, Name, 63);
|
||||||
datalayer.system.info.battery_protocol[63] = '\0';
|
datalayer.system.info.battery_protocol[63] = '\0';
|
||||||
datalayer.battery.info.number_of_cells = 108; //Startup in 108S mode. We figure out the actual count later.
|
datalayer.battery.info.number_of_cells = 108; //Startup in 108S mode. We figure out the actual count later.
|
||||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_108S_DV; //Defined later to correct pack size
|
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_108S_DV; //Defined later to correct pack size
|
||||||
|
@ -2045,5 +2044,3 @@ void MebBattery::setup(void) { // Performs one time setup at startup
|
||||||
datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV;
|
datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV;
|
||||||
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -5,8 +5,9 @@
|
||||||
#include "CanBattery.h"
|
#include "CanBattery.h"
|
||||||
#include "MEB-HTML.h"
|
#include "MEB-HTML.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#ifdef MEB_BATTERY
|
||||||
#define SELECTED_BATTERY_CLASS MebBattery
|
#define SELECTED_BATTERY_CLASS MebBattery
|
||||||
|
#endif
|
||||||
|
|
||||||
class MebBattery : public CanBattery {
|
class MebBattery : public CanBattery {
|
||||||
public:
|
public:
|
||||||
|
@ -16,6 +17,7 @@ class MebBattery : public CanBattery {
|
||||||
virtual void transmit_can(unsigned long currentMillis);
|
virtual void transmit_can(unsigned long currentMillis);
|
||||||
bool supports_real_BMS_status() { return true; }
|
bool supports_real_BMS_status() { return true; }
|
||||||
bool supports_charged_energy() { return true; }
|
bool supports_charged_energy() { return true; }
|
||||||
|
static constexpr char* Name = "Volkswagen Group MEB platform via CAN-FD";
|
||||||
|
|
||||||
BatteryHtmlRenderer& get_status_renderer() { return renderer; }
|
BatteryHtmlRenderer& get_status_renderer() { return renderer; }
|
||||||
|
|
||||||
|
|
|
@ -20,119 +20,119 @@ class MebHtmlRenderer : public BatteryHtmlRenderer {
|
||||||
content += "<h4>HVIL status: ";
|
content += "<h4>HVIL status: ";
|
||||||
switch (datalayer_extended.meb.HVIL) {
|
switch (datalayer_extended.meb.HVIL) {
|
||||||
case 0:
|
case 0:
|
||||||
content += String("Init");
|
content += "Init";
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
content += String("Closed");
|
content += "Closed";
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
content += String("Open!");
|
content += "Open!";
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
content += String("Fault");
|
content += "Fault";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
content += String("?");
|
content += "?";
|
||||||
}
|
}
|
||||||
content += "</h4><h4>KL30C status: ";
|
content += "</h4><h4>KL30C status: ";
|
||||||
switch (datalayer_extended.meb.BMS_Kl30c_Status) {
|
switch (datalayer_extended.meb.BMS_Kl30c_Status) {
|
||||||
case 0:
|
case 0:
|
||||||
content += String("Init");
|
content += "Init";
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
content += String("Closed");
|
content += "Closed";
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
content += String("Open!");
|
content += "Open!";
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
content += String("Fault");
|
content += "Fault";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
content += String("?");
|
content += "?";
|
||||||
}
|
}
|
||||||
content += "</h4><h4>BMS mode: ";
|
content += "</h4><h4>BMS mode: ";
|
||||||
switch (datalayer_extended.meb.BMS_mode) {
|
switch (datalayer_extended.meb.BMS_mode) {
|
||||||
case 0:
|
case 0:
|
||||||
content += String("HV inactive");
|
content += "HV inactive";
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
content += String("HV active");
|
content += "HV active";
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
content += String("Balancing");
|
content += "Balancing";
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
content += String("Extern charging");
|
content += "Extern charging";
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
content += String("AC charging");
|
content += "AC charging";
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
content += String("Battery error");
|
content += "Battery error";
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
content += String("DC charging");
|
content += "DC charging";
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
content += String("Init");
|
content += "Init";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
content += String("?");
|
content += "?";
|
||||||
}
|
}
|
||||||
content += String("</h4><h4>Charging: ") + (datalayer_extended.meb.charging_active ? "active" : "not active");
|
content += String("</h4><h4>Charging: ") + (datalayer_extended.meb.charging_active ? "active" : "not active");
|
||||||
content += String("</h4><h4>Balancing: ");
|
content += String("</h4><h4>Balancing: ");
|
||||||
switch (datalayer_extended.meb.balancing_active) {
|
switch (datalayer_extended.meb.balancing_active) {
|
||||||
case 0:
|
case 0:
|
||||||
content += String("init");
|
content += "init";
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
content += String("active");
|
content += "active";
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
content += String("inactive");
|
content += "inactive";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
content += String("?");
|
content += "?";
|
||||||
}
|
}
|
||||||
content +=
|
content +=
|
||||||
String("</h4><h4>Slow charging: ") + (datalayer_extended.meb.balancing_request ? "requested" : "not requested");
|
String("</h4><h4>Slow charging: ") + (datalayer_extended.meb.balancing_request ? "requested" : "not requested");
|
||||||
content += "</h4><h4>Diagnostic: ";
|
content += "</h4><h4>Diagnostic: ";
|
||||||
switch (datalayer_extended.meb.battery_diagnostic) {
|
switch (datalayer_extended.meb.battery_diagnostic) {
|
||||||
case 0:
|
case 0:
|
||||||
content += String("Init");
|
content += "Init";
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
content += String("Battery display");
|
content += "Battery display";
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
content += String("Battery display OK");
|
content += "Battery display OK";
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
content += String("Battery display check");
|
content += "Battery display check";
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
content += String("Fault");
|
content += "Fault";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
content += String("?");
|
content += "?";
|
||||||
}
|
}
|
||||||
content += "</h4><h4>HV line status: ";
|
content += "</h4><h4>HV line status: ";
|
||||||
switch (datalayer_extended.meb.status_HV_line) {
|
switch (datalayer_extended.meb.status_HV_line) {
|
||||||
case 0:
|
case 0:
|
||||||
content += String("Init");
|
content += "Init";
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
content += String("No open HV line detected");
|
content += "No open HV line detected";
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
content += String("Open HV line");
|
content += "Open HV line";
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
content += String("Fault");
|
content += "Fault";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
content += String("? ") + String(datalayer_extended.meb.status_HV_line);
|
content += "? " + String(datalayer_extended.meb.status_HV_line);
|
||||||
}
|
}
|
||||||
content += "</h4>";
|
content += "</h4>";
|
||||||
content += datalayer_extended.meb.BMS_fault_performance ? "<h4>BMS fault performance: Active!</h4>"
|
content += datalayer_extended.meb.BMS_fault_performance ? "<h4>BMS fault performance: Active!</h4>"
|
||||||
|
@ -147,83 +147,83 @@ class MebHtmlRenderer : public BatteryHtmlRenderer {
|
||||||
content += "<h4>Welded contactors: ";
|
content += "<h4>Welded contactors: ";
|
||||||
switch (datalayer_extended.meb.BMS_welded_contactors_status) {
|
switch (datalayer_extended.meb.BMS_welded_contactors_status) {
|
||||||
case 0:
|
case 0:
|
||||||
content += String("Init");
|
content += "Init";
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
content += String("No contactor welded");
|
content += "No contactor welded";
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
content += String("At least 1 contactor welded");
|
content += "At least 1 contactor welded";
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
content += String("Protection status detection error");
|
content += "Protection status detection error";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
content += String("?");
|
content += "?";
|
||||||
}
|
}
|
||||||
content += "</h4><h4>Warning support: ";
|
content += "</h4><h4>Warning support: ";
|
||||||
switch (datalayer_extended.meb.warning_support) {
|
switch (datalayer_extended.meb.warning_support) {
|
||||||
case 0:
|
case 0:
|
||||||
content += String("OK");
|
content += "OK";
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
content += String("Not OK");
|
content += "Not OK";
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
content += String("Init");
|
content += "Init";
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
content += String("Fault");
|
content += "Fault";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
content += String("?");
|
content += "?";
|
||||||
}
|
}
|
||||||
content += "</h4><h4>Interm. Voltage (" + String(datalayer_extended.meb.BMS_voltage_intermediate_dV / 10.0, 1) +
|
content += "</h4><h4>Interm. Voltage (" + String(datalayer_extended.meb.BMS_voltage_intermediate_dV / 10.0, 1) +
|
||||||
"V) status: ";
|
"V) status: ";
|
||||||
switch (datalayer_extended.meb.BMS_status_voltage_free) {
|
switch (datalayer_extended.meb.BMS_status_voltage_free) {
|
||||||
case 0:
|
case 0:
|
||||||
content += String("Init");
|
content += "Init";
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
content += String("BMS interm circuit voltage free (U<20V)");
|
content += "BMS interm circuit voltage free (U<20V)";
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
content += String("BMS interm circuit not voltage free (U >= 25V)");
|
content += "BMS interm circuit not voltage free (U >= 25V)";
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
content += String("Error");
|
content += "Error";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
content += String("?");
|
content += "?";
|
||||||
}
|
}
|
||||||
content += "</h4><h4>BMS error status: ";
|
content += "</h4><h4>BMS error status: ";
|
||||||
switch (datalayer_extended.meb.BMS_error_status) {
|
switch (datalayer_extended.meb.BMS_error_status) {
|
||||||
case 0:
|
case 0:
|
||||||
content += String("Component IO");
|
content += "Component IO";
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
content += String("Iso Error 1");
|
content += "Iso Error 1";
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
content += String("Iso Error 2");
|
content += "Iso Error 2";
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
content += String("Interlock");
|
content += "Interlock";
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
content += String("SD");
|
content += "SD";
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
content += String("Performance red");
|
content += "Performance red";
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
content += String("No component function");
|
content += "No component function";
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
content += String("Init");
|
content += "Init";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
content += String("?");
|
content += "?";
|
||||||
}
|
}
|
||||||
content += "</h4><h4>BMS voltage: " + String(datalayer_extended.meb.BMS_voltage_dV / 10.0, 1) + "</h4>";
|
content += "</h4><h4>BMS voltage: " + String(datalayer_extended.meb.BMS_voltage_dV / 10.0, 1) + "</h4>";
|
||||||
content += datalayer_extended.meb.BMS_OBD_MIL ? "<h4>OBD MIL: ON!</h4>" : "<h4>OBD MIL: Off</h4>";
|
content += datalayer_extended.meb.BMS_OBD_MIL ? "<h4>OBD MIL: ON!</h4>" : "<h4>OBD MIL: Off</h4>";
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
#include "../include.h"
|
#include "MG-5-BATTERY.h"
|
||||||
#ifdef MG_5_BATTERY_H
|
|
||||||
#include "../communication/can/comm_can.h"
|
#include "../communication/can/comm_can.h"
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
#include "MG-5-BATTERY.h"
|
#include "../include.h"
|
||||||
|
|
||||||
/* TODO:
|
/* TODO:
|
||||||
- Get contactor closing working
|
- Get contactor closing working
|
||||||
|
@ -122,5 +121,3 @@ void Mg5Battery::setup(void) { // Performs one time setup at startup
|
||||||
datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV;
|
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.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -5,8 +5,9 @@
|
||||||
|
|
||||||
#include "CanBattery.h"
|
#include "CanBattery.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#ifdef MG_5_BATTERY
|
||||||
#define SELECTED_BATTERY_CLASS Mg5Battery
|
#define SELECTED_BATTERY_CLASS Mg5Battery
|
||||||
|
#endif
|
||||||
|
|
||||||
class Mg5Battery : public CanBattery {
|
class Mg5Battery : public CanBattery {
|
||||||
public:
|
public:
|
||||||
|
@ -14,6 +15,7 @@ class Mg5Battery : public CanBattery {
|
||||||
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
||||||
virtual void update_values();
|
virtual void update_values();
|
||||||
virtual void transmit_can(unsigned long currentMillis);
|
virtual void transmit_can(unsigned long currentMillis);
|
||||||
|
static constexpr char* Name = "MG 5 battery";
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const int MAX_PACK_VOLTAGE_DV = 4040; //5000 = 500.0V
|
static const int MAX_PACK_VOLTAGE_DV = 4040; //5000 = 500.0V
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#include "../include.h"
|
|
||||||
#ifdef NISSAN_LEAF_BATTERY
|
|
||||||
#include "NISSAN-LEAF-BATTERY.h"
|
#include "NISSAN-LEAF-BATTERY.h"
|
||||||
|
#include "../include.h"
|
||||||
#ifdef MQTT
|
#ifdef MQTT
|
||||||
#include "../devboard/mqtt/mqtt.h"
|
#include "../devboard/mqtt/mqtt.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -970,7 +969,7 @@ void decodeChallengeData(unsigned int incomingChallenge, unsigned char* solvedCh
|
||||||
}
|
}
|
||||||
|
|
||||||
void NissanLeafBattery::setup(void) { // Performs one time setup at startup
|
void NissanLeafBattery::setup(void) { // Performs one time setup at startup
|
||||||
strncpy(datalayer.system.info.battery_protocol, "Nissan LEAF battery", 63);
|
strncpy(datalayer.system.info.battery_protocol, Name, 63);
|
||||||
datalayer.system.info.battery_protocol[63] = '\0';
|
datalayer.system.info.battery_protocol[63] = '\0';
|
||||||
datalayer_battery->info.number_of_cells = 96;
|
datalayer_battery->info.number_of_cells = 96;
|
||||||
datalayer_battery->info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
datalayer_battery->info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
||||||
|
@ -979,5 +978,3 @@ void NissanLeafBattery::setup(void) { // Performs one time setup at startup
|
||||||
datalayer_battery->info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV;
|
datalayer_battery->info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV;
|
||||||
datalayer_battery->info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
datalayer_battery->info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //NISSAN_LEAF_BATTERY
|
|
||||||
|
|
|
@ -7,15 +7,9 @@
|
||||||
#include "CanBattery.h"
|
#include "CanBattery.h"
|
||||||
#include "NISSAN-LEAF-HTML.h"
|
#include "NISSAN-LEAF-HTML.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#ifdef NISSAN_LEAF_BATTERY
|
||||||
#define SELECTED_BATTERY_CLASS NissanLeafBattery
|
#define SELECTED_BATTERY_CLASS NissanLeafBattery
|
||||||
#define EXTENDED_DATA_PTR (&datalayer_extended.nissanleaf)
|
#endif
|
||||||
|
|
||||||
#define MAX_PACK_VOLTAGE_DV 4040 //5000 = 500.0V
|
|
||||||
#define MIN_PACK_VOLTAGE_DV 2600
|
|
||||||
#define MAX_CELL_DEVIATION_MV 150
|
|
||||||
#define MAX_CELL_VOLTAGE_MV 4250 //Battery is put into emergency stop if one cell goes over this value
|
|
||||||
#define MIN_CELL_VOLTAGE_MV 2700 //Battery is put into emergency stop if one cell goes below this value
|
|
||||||
|
|
||||||
class NissanLeafBattery : public CanBattery {
|
class NissanLeafBattery : public CanBattery {
|
||||||
public:
|
public:
|
||||||
|
@ -52,8 +46,15 @@ class NissanLeafBattery : public CanBattery {
|
||||||
}
|
}
|
||||||
|
|
||||||
BatteryHtmlRenderer& get_status_renderer() { return renderer; }
|
BatteryHtmlRenderer& get_status_renderer() { return renderer; }
|
||||||
|
static constexpr char* Name = "Nissan LEAF battery";
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static const int MAX_PACK_VOLTAGE_DV = 4040; //5000 = 500.0V
|
||||||
|
static const int MIN_PACK_VOLTAGE_DV = 2600;
|
||||||
|
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
|
||||||
|
|
||||||
NissanLeafHtmlRenderer renderer;
|
NissanLeafHtmlRenderer renderer;
|
||||||
|
|
||||||
bool is_message_corrupt(CAN_frame rx_frame);
|
bool is_message_corrupt(CAN_frame rx_frame);
|
||||||
|
|
|
@ -10,8 +10,20 @@ class NissanLeafHtmlRenderer : public BatteryHtmlRenderer {
|
||||||
String get_status_html() {
|
String get_status_html() {
|
||||||
String content;
|
String content;
|
||||||
|
|
||||||
static const char* LEAFgen[] = {"ZE0", "AZE0", "ZE1"};
|
content += "<h4>LEAF generation: ";
|
||||||
content += "<h4>LEAF generation: " + String(LEAFgen[datalayer_extended.nissanleaf.LEAF_gen]) + "</h4>";
|
switch (datalayer_extended.nissanleaf.LEAF_gen) {
|
||||||
|
case 0:
|
||||||
|
content += String("ZE0</h4>");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
content += String("AZE0</h4>");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
content += String("ZE1</h4>");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
content += String("Unknown</h4>");
|
||||||
|
}
|
||||||
char readableSerialNumber[16]; // One extra space for null terminator
|
char readableSerialNumber[16]; // One extra space for null terminator
|
||||||
memcpy(readableSerialNumber, datalayer_extended.nissanleaf.BatterySerialNumber,
|
memcpy(readableSerialNumber, datalayer_extended.nissanleaf.BatterySerialNumber,
|
||||||
sizeof(datalayer_extended.nissanleaf.BatterySerialNumber));
|
sizeof(datalayer_extended.nissanleaf.BatterySerialNumber));
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
#include "../include.h"
|
#include "ORION-BMS.h"
|
||||||
#ifdef ORION_BMS
|
|
||||||
#include "../communication/can/comm_can.h"
|
#include "../communication/can/comm_can.h"
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
#include "ORION-BMS.h"
|
#include "../include.h"
|
||||||
|
|
||||||
void findMinMaxCellvoltages(const uint16_t arr[], size_t size, uint16_t& Minimum_Cell_Voltage,
|
void findMinMaxCellvoltages(const uint16_t arr[], size_t size, uint16_t& Minimum_Cell_Voltage,
|
||||||
uint16_t& Maximum_Cell_Voltage) {
|
uint16_t& Maximum_Cell_Voltage) {
|
||||||
|
@ -115,7 +114,7 @@ void OrionBms::transmit_can(unsigned long currentMillis) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void OrionBms::setup(void) { // Performs one time setup at startup
|
void OrionBms::setup(void) { // Performs one time setup at startup
|
||||||
strncpy(datalayer.system.info.battery_protocol, "DIY battery with Orion BMS (Victron setting)", 63);
|
strncpy(datalayer.system.info.battery_protocol, Name, 63);
|
||||||
datalayer.system.info.battery_protocol[63] = '\0';
|
datalayer.system.info.battery_protocol[63] = '\0';
|
||||||
datalayer.battery.info.number_of_cells = NUMBER_OF_CELLS;
|
datalayer.battery.info.number_of_cells = NUMBER_OF_CELLS;
|
||||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
||||||
|
@ -124,5 +123,3 @@ void OrionBms::setup(void) { // Performs one time setup at startup
|
||||||
datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV;
|
datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV;
|
||||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
datalayer.system.status.battery_allows_contactor_closing = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -5,8 +5,9 @@
|
||||||
|
|
||||||
#include "CanBattery.h"
|
#include "CanBattery.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#ifdef ORION_BMS
|
||||||
#define SELECTED_BATTERY_CLASS OrionBms
|
#define SELECTED_BATTERY_CLASS OrionBms
|
||||||
|
#endif
|
||||||
|
|
||||||
class OrionBms : public CanBattery {
|
class OrionBms : public CanBattery {
|
||||||
public:
|
public:
|
||||||
|
@ -14,6 +15,7 @@ class OrionBms : public CanBattery {
|
||||||
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
||||||
virtual void update_values();
|
virtual void update_values();
|
||||||
virtual void transmit_can(unsigned long currentMillis);
|
virtual void transmit_can(unsigned long currentMillis);
|
||||||
|
static constexpr char* Name = "DIY battery with Orion BMS (Victron setting)";
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/* Change the following to suit your battery */
|
/* Change the following to suit your battery */
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
#include "../include.h"
|
#include "PYLON-BATTERY.h"
|
||||||
#ifdef PYLON_BATTERY
|
|
||||||
#include "../communication/can/comm_can.h"
|
#include "../communication/can/comm_can.h"
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
#include "PYLON-BATTERY.h"
|
#include "../include.h"
|
||||||
|
|
||||||
void PylonBattery::update_values() {
|
void PylonBattery::update_values() {
|
||||||
|
|
||||||
|
@ -144,5 +143,3 @@ void PylonBattery::setup(void) { // Performs one time setup at startup
|
||||||
*allows_contactor_closing = true;
|
*allows_contactor_closing = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -6,8 +6,9 @@
|
||||||
#include "../include.h"
|
#include "../include.h"
|
||||||
#include "CanBattery.h"
|
#include "CanBattery.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#ifdef PYLON_BATTERY
|
||||||
#define SELECTED_BATTERY_CLASS PylonBattery
|
#define SELECTED_BATTERY_CLASS PylonBattery
|
||||||
|
#endif
|
||||||
|
|
||||||
class PylonBattery : public CanBattery {
|
class PylonBattery : public CanBattery {
|
||||||
public:
|
public:
|
||||||
|
@ -30,6 +31,7 @@ class PylonBattery : public CanBattery {
|
||||||
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
||||||
virtual void update_values();
|
virtual void update_values();
|
||||||
virtual void transmit_can(unsigned long currentMillis);
|
virtual void transmit_can(unsigned long currentMillis);
|
||||||
|
static constexpr char* Name = "Pylon compatible battery";
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/* Change the following to suit your battery */
|
/* Change the following to suit your battery */
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
#include "../include.h"
|
#include "RANGE-ROVER-PHEV-BATTERY.h"
|
||||||
#ifdef RANGE_ROVER_PHEV_BATTERY
|
|
||||||
#include "../communication/can/comm_can.h"
|
#include "../communication/can/comm_can.h"
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
#include "RANGE-ROVER-PHEV-BATTERY.h"
|
#include "../include.h"
|
||||||
|
|
||||||
/* TODO
|
/* TODO
|
||||||
- LOG files from vehicle needed to determine CAN content needed to send towards battery!
|
- LOG files from vehicle needed to determine CAN content needed to send towards battery!
|
||||||
|
@ -208,7 +207,7 @@ void RangeRoverPhevBattery::transmit_can(unsigned long currentMillis) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RangeRoverPhevBattery::setup(void) { // Performs one time setup at startup
|
void RangeRoverPhevBattery::setup(void) { // Performs one time setup at startup
|
||||||
strncpy(datalayer.system.info.battery_protocol, "Range Rover 13kWh PHEV battery (L494/L405)", 63);
|
strncpy(datalayer.system.info.battery_protocol, Name, 63);
|
||||||
datalayer.system.info.battery_protocol[63] = '\0';
|
datalayer.system.info.battery_protocol[63] = '\0';
|
||||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
datalayer.system.status.battery_allows_contactor_closing = true;
|
||||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
||||||
|
@ -216,5 +215,3 @@ void RangeRoverPhevBattery::setup(void) { // Performs one time setup at startup
|
||||||
datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV;
|
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.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //RANGE_ROVER_PHEV_BATTERY
|
|
||||||
|
|
|
@ -5,8 +5,9 @@
|
||||||
|
|
||||||
#include "CanBattery.h"
|
#include "CanBattery.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#ifdef RANGE_ROVER_PHEV_BATTERY
|
||||||
#define SELECTED_BATTERY_CLASS RangeRoverPhevBattery
|
#define SELECTED_BATTERY_CLASS RangeRoverPhevBattery
|
||||||
|
#endif
|
||||||
|
|
||||||
class RangeRoverPhevBattery : public CanBattery {
|
class RangeRoverPhevBattery : public CanBattery {
|
||||||
public:
|
public:
|
||||||
|
@ -14,6 +15,7 @@ class RangeRoverPhevBattery : public CanBattery {
|
||||||
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
||||||
virtual void update_values();
|
virtual void update_values();
|
||||||
virtual void transmit_can(unsigned long currentMillis);
|
virtual void transmit_can(unsigned long currentMillis);
|
||||||
|
static constexpr char* Name = "Range Rover 13kWh PHEV battery (L494/L405)";
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/* Change the following to suit your battery */
|
/* Change the following to suit your battery */
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
#include "../include.h"
|
#include "RENAULT-KANGOO-BATTERY.h"
|
||||||
#ifdef RENAULT_KANGOO_BATTERY
|
|
||||||
#include "../communication/can/comm_can.h"
|
#include "../communication/can/comm_can.h"
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
#include "RENAULT-KANGOO-BATTERY.h"
|
#include "../include.h"
|
||||||
|
|
||||||
/* TODO:
|
/* TODO:
|
||||||
There seems to be some values on the Kangoo that differ between the 22/33 kWh version
|
There seems to be some values on the Kangoo that differ between the 22/33 kWh version
|
||||||
|
@ -182,7 +181,7 @@ void RenaultKangooBattery::transmit_can(unsigned long currentMillis) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenaultKangooBattery::setup(void) { // Performs one time setup at startup
|
void RenaultKangooBattery::setup(void) { // Performs one time setup at startup
|
||||||
strncpy(datalayer.system.info.battery_protocol, "Renault Kangoo", 63);
|
strncpy(datalayer.system.info.battery_protocol, Name, 63);
|
||||||
datalayer.system.info.battery_protocol[63] = '\0';
|
datalayer.system.info.battery_protocol[63] = '\0';
|
||||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
datalayer.system.status.battery_allows_contactor_closing = true;
|
||||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
||||||
|
@ -191,5 +190,3 @@ void RenaultKangooBattery::setup(void) { // Performs one time setup at startup
|
||||||
datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV;
|
datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV;
|
||||||
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -5,8 +5,9 @@
|
||||||
|
|
||||||
#include "CanBattery.h"
|
#include "CanBattery.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#ifdef RENAULT_KANGOO_BATTERY
|
||||||
#define SELECTED_BATTERY_CLASS RenaultKangooBattery
|
#define SELECTED_BATTERY_CLASS RenaultKangooBattery
|
||||||
|
#endif
|
||||||
|
|
||||||
class RenaultKangooBattery : public CanBattery {
|
class RenaultKangooBattery : public CanBattery {
|
||||||
public:
|
public:
|
||||||
|
@ -14,6 +15,7 @@ class RenaultKangooBattery : public CanBattery {
|
||||||
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
||||||
virtual void update_values();
|
virtual void update_values();
|
||||||
virtual void transmit_can(unsigned long currentMillis);
|
virtual void transmit_can(unsigned long currentMillis);
|
||||||
|
static constexpr char* Name = "Renault Kangoo";
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const int MAX_PACK_VOLTAGE_DV = 4150; //5000 = 500.0V
|
static const int MAX_PACK_VOLTAGE_DV = 4150; //5000 = 500.0V
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
|
#include "RENAULT-TWIZY.h"
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include "../include.h"
|
|
||||||
#ifdef RENAULT_TWIZY_BATTERY
|
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
#include "RENAULT-TWIZY.h"
|
#include "../include.h"
|
||||||
|
|
||||||
int16_t max_value(int16_t* entries, size_t len) {
|
int16_t max_value(int16_t* entries, size_t len) {
|
||||||
int result = INT16_MIN;
|
int result = INT16_MIN;
|
||||||
|
@ -119,7 +118,7 @@ void RenaultTwizyBattery::transmit_can(unsigned long currentMillis) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenaultTwizyBattery::setup(void) { // Performs one time setup at startup
|
void RenaultTwizyBattery::setup(void) { // Performs one time setup at startup
|
||||||
strncpy(datalayer.system.info.battery_protocol, "Renault Twizy", 63);
|
strncpy(datalayer.system.info.battery_protocol, Name, 63);
|
||||||
datalayer.system.info.battery_protocol[63] = '\0';
|
datalayer.system.info.battery_protocol[63] = '\0';
|
||||||
datalayer.battery.info.number_of_cells = 14;
|
datalayer.battery.info.number_of_cells = 14;
|
||||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
||||||
|
@ -129,5 +128,3 @@ void RenaultTwizyBattery::setup(void) { // Performs one time setup at startup
|
||||||
datalayer.battery.info.total_capacity_Wh = 6600;
|
datalayer.battery.info.total_capacity_Wh = 6600;
|
||||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
datalayer.system.status.battery_allows_contactor_closing = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -3,8 +3,9 @@
|
||||||
#include "../include.h"
|
#include "../include.h"
|
||||||
#include "CanBattery.h"
|
#include "CanBattery.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#ifdef RENAULT_TWIZY_BATTERY
|
||||||
#define SELECTED_BATTERY_CLASS RenaultTwizyBattery
|
#define SELECTED_BATTERY_CLASS RenaultTwizyBattery
|
||||||
|
#endif
|
||||||
|
|
||||||
class RenaultTwizyBattery : public CanBattery {
|
class RenaultTwizyBattery : public CanBattery {
|
||||||
public:
|
public:
|
||||||
|
@ -12,6 +13,7 @@ class RenaultTwizyBattery : public CanBattery {
|
||||||
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
||||||
virtual void update_values();
|
virtual void update_values();
|
||||||
virtual void transmit_can(unsigned long currentMillis);
|
virtual void transmit_can(unsigned long currentMillis);
|
||||||
|
static constexpr char* Name = "Renault Twizy";
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const int MAX_PACK_VOLTAGE_DV = 579; // 57.9V at 100% SOC (with 70% SOH, new one might be higher)
|
static const int MAX_PACK_VOLTAGE_DV = 579; // 57.9V at 100% SOC (with 70% SOH, new one might be higher)
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
#include "../include.h"
|
#include "RENAULT-ZOE-GEN1-BATTERY.h"
|
||||||
#ifdef RENAULT_ZOE_GEN1_BATTERY
|
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../datalayer/datalayer_extended.h"
|
#include "../datalayer/datalayer_extended.h"
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
#include "RENAULT-ZOE-GEN1-BATTERY.h"
|
#include "../include.h"
|
||||||
|
|
||||||
void transmit_can_frame(CAN_frame* tx_frame, int interface);
|
void transmit_can_frame(CAN_frame* tx_frame, int interface);
|
||||||
|
|
||||||
|
@ -15,52 +14,6 @@ Still TODO:
|
||||||
/*
|
/*
|
||||||
|
|
||||||
/* Do not change code below unless you are sure what you are doing */
|
/* Do not change code below unless you are sure what you are doing */
|
||||||
static uint16_t LB_SOC = 50;
|
|
||||||
static uint16_t LB_Display_SOC = 50;
|
|
||||||
static uint16_t LB_SOH = 99;
|
|
||||||
static int16_t LB_Average_Temperature = 0;
|
|
||||||
static uint32_t LB_Charging_Power_W = 0;
|
|
||||||
static uint32_t LB_Regen_allowed_W = 0;
|
|
||||||
static uint32_t LB_Discharge_allowed_W = 0;
|
|
||||||
static int16_t LB_Current = 0;
|
|
||||||
static int16_t LB_Cell_minimum_temperature = 0;
|
|
||||||
static int16_t LB_Cell_maximum_temperature = 0;
|
|
||||||
static uint16_t LB_Cell_minimum_voltage = 3700;
|
|
||||||
static uint16_t LB_Cell_maximum_voltage = 3700;
|
|
||||||
static uint16_t LB_kWh_Remaining = 0;
|
|
||||||
static uint16_t LB_Battery_Voltage = 3700;
|
|
||||||
static uint8_t LB_Heartbeat = 0;
|
|
||||||
static uint8_t LB_CUV = 0;
|
|
||||||
static uint8_t LB_HVBIR = 0;
|
|
||||||
static uint8_t LB_HVBUV = 0;
|
|
||||||
static uint8_t LB_EOCR = 0;
|
|
||||||
static uint8_t LB_HVBOC = 0;
|
|
||||||
static uint8_t LB_HVBOT = 0;
|
|
||||||
static uint8_t LB_HVBOV = 0;
|
|
||||||
static uint8_t LB_COV = 0;
|
|
||||||
static uint8_t frame0 = 0;
|
|
||||||
static uint8_t current_poll = 0;
|
|
||||||
static uint8_t requested_poll = 0;
|
|
||||||
static uint8_t group = 0;
|
|
||||||
static uint16_t cellvoltages[96];
|
|
||||||
static uint32_t calculated_total_pack_voltage_mV = 370000;
|
|
||||||
static uint8_t highbyte_cell_next_frame = 0;
|
|
||||||
static uint16_t SOC_polled = 50;
|
|
||||||
static int16_t cell_1_temperature_polled = 0;
|
|
||||||
static int16_t cell_2_temperature_polled = 0;
|
|
||||||
static int16_t cell_3_temperature_polled = 0;
|
|
||||||
static int16_t cell_4_temperature_polled = 0;
|
|
||||||
static int16_t cell_5_temperature_polled = 0;
|
|
||||||
static int16_t cell_6_temperature_polled = 0;
|
|
||||||
static int16_t cell_7_temperature_polled = 0;
|
|
||||||
static int16_t cell_8_temperature_polled = 0;
|
|
||||||
static int16_t cell_9_temperature_polled = 0;
|
|
||||||
static int16_t cell_10_temperature_polled = 0;
|
|
||||||
static int16_t cell_11_temperature_polled = 0;
|
|
||||||
static int16_t cell_12_temperature_polled = 0;
|
|
||||||
static uint16_t battery_mileage_in_km = 0;
|
|
||||||
static uint16_t kWh_from_beginning_of_battery_life = 0;
|
|
||||||
static bool looping_over_20 = false;
|
|
||||||
|
|
||||||
CAN_frame ZOE_423 = {.FD = false,
|
CAN_frame ZOE_423 = {.FD = false,
|
||||||
.ext_ID = false,
|
.ext_ID = false,
|
||||||
|
@ -90,20 +43,20 @@ static uint8_t counter_423 = 0;
|
||||||
|
|
||||||
void RenaultZoeGen1Battery::
|
void RenaultZoeGen1Battery::
|
||||||
update_values() { //This function maps all the values fetched via CAN to the correct parameters used for modbus
|
update_values() { //This function maps all the values fetched via CAN to the correct parameters used for modbus
|
||||||
datalayer.battery.status.soh_pptt = (LB_SOH * 100); // Increase range from 99% -> 99.00%
|
datalayer_battery->status.soh_pptt = (LB_SOH * 100); // Increase range from 99% -> 99.00%
|
||||||
|
|
||||||
datalayer.battery.status.real_soc = SOC_polled;
|
datalayer_battery->status.real_soc = SOC_polled;
|
||||||
//datalayer.battery.status.real_soc = LB_Display_SOC; //Alternative would be to use Dash SOC%
|
//datalayer_battery->status.real_soc = LB_Display_SOC; //Alternative would be to use Dash SOC%
|
||||||
|
|
||||||
datalayer.battery.status.current_dA = LB_Current * 10; //Convert A to dA
|
datalayer_battery->status.current_dA = LB_Current * 10; //Convert A to dA
|
||||||
|
|
||||||
//Calculate the remaining Wh amount from SOC% and max Wh value.
|
//Calculate the remaining Wh amount from SOC% and max Wh value.
|
||||||
datalayer.battery.status.remaining_capacity_Wh = static_cast<uint32_t>(
|
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);
|
(static_cast<double>(datalayer_battery->status.real_soc) / 10000) * datalayer_battery->info.total_capacity_Wh);
|
||||||
|
|
||||||
datalayer.battery.status.max_discharge_power_W = LB_Discharge_allowed_W;
|
datalayer_battery->status.max_discharge_power_W = LB_Discharge_allowed_W;
|
||||||
|
|
||||||
datalayer.battery.status.max_charge_power_W = LB_Regen_allowed_W;
|
datalayer_battery->status.max_charge_power_W = LB_Regen_allowed_W;
|
||||||
|
|
||||||
int16_t temperatures[] = {cell_1_temperature_polled, cell_2_temperature_polled, cell_3_temperature_polled,
|
int16_t temperatures[] = {cell_1_temperature_polled, cell_2_temperature_polled, cell_3_temperature_polled,
|
||||||
cell_4_temperature_polled, cell_5_temperature_polled, cell_6_temperature_polled,
|
cell_4_temperature_polled, cell_5_temperature_polled, cell_6_temperature_polled,
|
||||||
|
@ -114,52 +67,53 @@ void RenaultZoeGen1Battery::
|
||||||
int16_t min_temperature = *std::min_element(temperatures, temperatures + 12);
|
int16_t min_temperature = *std::min_element(temperatures, temperatures + 12);
|
||||||
int16_t max_temperature = *std::max_element(temperatures, temperatures + 12);
|
int16_t max_temperature = *std::max_element(temperatures, temperatures + 12);
|
||||||
|
|
||||||
datalayer.battery.status.temperature_min_dC = min_temperature * 10;
|
datalayer_battery->status.temperature_min_dC = min_temperature * 10;
|
||||||
|
|
||||||
datalayer.battery.status.temperature_max_dC = max_temperature * 10;
|
datalayer_battery->status.temperature_max_dC = max_temperature * 10;
|
||||||
|
|
||||||
//Map all cell voltages to the global array
|
|
||||||
memcpy(datalayer.battery.status.cell_voltages_mV, cellvoltages, 96 * sizeof(uint16_t));
|
|
||||||
|
|
||||||
// Calculate total pack voltage on packs that require this. Only calculate once all cellvotages have been read
|
// Calculate total pack voltage on packs that require this. Only calculate once all cellvotages have been read
|
||||||
if (datalayer.battery.status.cell_voltages_mV[95] > 0) {
|
if (datalayer_battery->status.cell_voltages_mV[95] > 0) {
|
||||||
calculated_total_pack_voltage_mV = datalayer.battery.status.cell_voltages_mV[0];
|
calculated_total_pack_voltage_mV = datalayer_battery->status.cell_voltages_mV[0];
|
||||||
for (uint8_t i = 0; i < datalayer.battery.info.number_of_cells; ++i) {
|
for (uint8_t i = 0; i < datalayer_battery->info.number_of_cells; ++i) {
|
||||||
calculated_total_pack_voltage_mV += datalayer.battery.status.cell_voltages_mV[i];
|
calculated_total_pack_voltage_mV += datalayer_battery->status.cell_voltages_mV[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
datalayer.battery.status.cell_min_voltage_mV = LB_Cell_minimum_voltage;
|
datalayer_battery->status.cell_min_voltage_mV = LB_Cell_minimum_voltage;
|
||||||
datalayer.battery.status.cell_max_voltage_mV = LB_Cell_maximum_voltage;
|
datalayer_battery->status.cell_max_voltage_mV = LB_Cell_maximum_voltage;
|
||||||
datalayer.battery.status.voltage_dV = static_cast<uint32_t>((calculated_total_pack_voltage_mV / 100)); // mV to dV
|
datalayer_battery->status.voltage_dV = ((calculated_total_pack_voltage_mV / 100)); // mV to dV
|
||||||
|
|
||||||
//Update extended datalayer
|
//Update extended datalayer
|
||||||
datalayer_extended.zoe.CUV = LB_CUV;
|
if (datalayer_zoe) {
|
||||||
datalayer_extended.zoe.HVBIR = LB_HVBIR;
|
datalayer_zoe->CUV = LB_CUV;
|
||||||
datalayer_extended.zoe.HVBUV = LB_HVBUV;
|
datalayer_zoe->HVBIR = LB_HVBIR;
|
||||||
datalayer_extended.zoe.EOCR = LB_EOCR;
|
datalayer_zoe->HVBUV = LB_HVBUV;
|
||||||
datalayer_extended.zoe.HVBOC = LB_HVBOC;
|
datalayer_zoe->EOCR = LB_EOCR;
|
||||||
datalayer_extended.zoe.HVBOT = LB_HVBOT;
|
datalayer_zoe->HVBOC = LB_HVBOC;
|
||||||
datalayer_extended.zoe.HVBOV = LB_HVBOV;
|
datalayer_zoe->HVBOT = LB_HVBOT;
|
||||||
datalayer_extended.zoe.COV = LB_COV;
|
datalayer_zoe->HVBOV = LB_HVBOV;
|
||||||
|
datalayer_zoe->COV = LB_COV;
|
||||||
|
datalayer_zoe->mileage_km = battery_mileage_in_km;
|
||||||
|
datalayer_zoe->alltime_kWh = kWh_from_beginning_of_battery_life;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenaultZoeGen1Battery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
void RenaultZoeGen1Battery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
||||||
switch (rx_frame.ID) {
|
switch (rx_frame.ID) {
|
||||||
case 0x155: //10ms - Charging power, current and SOC - Confirmed sent by: Fluence ZE40, Zoe 22/41kWh, Kangoo 33kWh
|
case 0x155: //10ms - Charging power, current and SOC - Confirmed sent by: Fluence ZE40, Zoe 22/41kWh, Kangoo 33kWh
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
LB_Charging_Power_W = rx_frame.data.u8[0] * 300;
|
LB_Charging_Power_W = rx_frame.data.u8[0] * 300;
|
||||||
LB_Current = (((((rx_frame.data.u8[1] & 0x0F) << 8) | rx_frame.data.u8[2]) * 0.25) - 500);
|
LB_Current = (((((rx_frame.data.u8[1] & 0x0F) << 8) | rx_frame.data.u8[2]) * 0.25) - 500);
|
||||||
LB_Display_SOC = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]);
|
LB_Display_SOC = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x42E: //NOTE: Not present on 41kWh battery!
|
case 0x42E: //NOTE: Not present on 41kWh battery!
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
LB_Battery_Voltage = (((((rx_frame.data.u8[3] << 8) | (rx_frame.data.u8[4])) >> 5) & 0x3ff) * 0.5); //0.5V/bit
|
LB_Battery_Voltage = (((((rx_frame.data.u8[3] << 8) | (rx_frame.data.u8[4])) >> 5) & 0x3ff) * 0.5); //0.5V/bit
|
||||||
LB_Average_Temperature = (((((rx_frame.data.u8[5] << 8) | (rx_frame.data.u8[6])) >> 5) & 0x7F) - 40);
|
LB_Average_Temperature = (((((rx_frame.data.u8[5] << 8) | (rx_frame.data.u8[6])) >> 5) & 0x7F) - 40);
|
||||||
break;
|
break;
|
||||||
case 0x424: //100ms - Charge limits, Temperatures, SOH - Confirmed sent by: Fluence ZE40, Zoe 22/41kWh, Kangoo 33kWh
|
case 0x424: //100ms - Charge limits, Temperatures, SOH - Confirmed sent by: Fluence ZE40, Zoe 22/41kWh, Kangoo 33kWh
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
LB_CUV = (rx_frame.data.u8[0] & 0x03);
|
LB_CUV = (rx_frame.data.u8[0] & 0x03);
|
||||||
LB_HVBIR = (rx_frame.data.u8[0] & 0x0C) >> 2;
|
LB_HVBIR = (rx_frame.data.u8[0] & 0x0C) >> 2;
|
||||||
LB_HVBUV = (rx_frame.data.u8[0] & 0x30) >> 4;
|
LB_HVBUV = (rx_frame.data.u8[0] & 0x30) >> 4;
|
||||||
|
@ -176,35 +130,35 @@ void RenaultZoeGen1Battery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
||||||
LB_Cell_maximum_temperature = (rx_frame.data.u8[7] - 40);
|
LB_Cell_maximum_temperature = (rx_frame.data.u8[7] - 40);
|
||||||
break;
|
break;
|
||||||
case 0x425: //100ms Cellvoltages and kWh remaining - Confirmed sent by: Fluence ZE40
|
case 0x425: //100ms Cellvoltages and kWh remaining - Confirmed sent by: Fluence ZE40
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
LB_Cell_maximum_voltage = (((((rx_frame.data.u8[4] & 0x03) << 7) | (rx_frame.data.u8[5] >> 1)) * 10) + 1000);
|
LB_Cell_maximum_voltage = (((((rx_frame.data.u8[4] & 0x03) << 7) | (rx_frame.data.u8[5] >> 1)) * 10) + 1000);
|
||||||
LB_Cell_minimum_voltage = (((((rx_frame.data.u8[6] & 0x01) << 8) | rx_frame.data.u8[7]) * 10) + 1000);
|
LB_Cell_minimum_voltage = (((((rx_frame.data.u8[6] & 0x01) << 8) | rx_frame.data.u8[7]) * 10) + 1000);
|
||||||
break;
|
break;
|
||||||
case 0x427: // NOTE: Not present on 41kWh battery!
|
case 0x427: // NOTE: Not present on 41kWh battery!
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
LB_kWh_Remaining = (((((rx_frame.data.u8[6] << 8) | (rx_frame.data.u8[7])) >> 6) & 0x3ff) * 0.1);
|
LB_kWh_Remaining = (((((rx_frame.data.u8[6] << 8) | (rx_frame.data.u8[7])) >> 6) & 0x3ff) * 0.1);
|
||||||
break;
|
break;
|
||||||
case 0x445: //100ms - Confirmed sent by: Fluence ZE40
|
case 0x445: //100ms - Confirmed sent by: Fluence ZE40
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
break;
|
break;
|
||||||
case 0x4AE: //3000ms
|
case 0x4AE: //3000ms
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
//Sent only? by 41kWh battery (potential use for detecting which generation we are on)
|
//Sent only? by 41kWh battery (potential use for detecting which generation we are on)
|
||||||
break;
|
break;
|
||||||
case 0x4AF: //100ms
|
case 0x4AF: //100ms
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
//Sent only? by 41kWh battery (potential use for detecting which generation we are on)
|
//Sent only? by 41kWh battery (potential use for detecting which generation we are on)
|
||||||
break;
|
break;
|
||||||
case 0x654: //SOC
|
case 0x654: //SOC
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
LB_SOC = rx_frame.data.u8[3];
|
LB_SOC = rx_frame.data.u8[3];
|
||||||
break;
|
break;
|
||||||
case 0x658: //SOH - NOTE: Not present on 41kWh battery! (Is this message on 21kWh?)
|
case 0x658: //SOH - NOTE: Not present on 41kWh battery! (Is this message on 21kWh?)
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
//LB_SOH = (rx_frame.data.u8[4] & 0x7F);
|
//LB_SOH = (rx_frame.data.u8[4] & 0x7F);
|
||||||
break;
|
break;
|
||||||
case 0x659: //3000ms - Confirmed sent by: Fluence ZE40
|
case 0x659: //3000ms - Confirmed sent by: Fluence ZE40
|
||||||
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
|
||||||
break;
|
break;
|
||||||
case 0x7BB: //Reply from active polling
|
case 0x7BB: //Reply from active polling
|
||||||
frame0 = rx_frame.data.u8[0];
|
frame0 = rx_frame.data.u8[0];
|
||||||
|
@ -437,6 +391,8 @@ void RenaultZoeGen1Battery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
||||||
}
|
}
|
||||||
if (requested_poll == GROUP2_CELLVOLTAGES_2_POLL) {
|
if (requested_poll == GROUP2_CELLVOLTAGES_2_POLL) {
|
||||||
cellvoltages[95] = (highbyte_cell_next_frame << 8) | rx_frame.data.u8[1];
|
cellvoltages[95] = (highbyte_cell_next_frame << 8) | rx_frame.data.u8[1];
|
||||||
|
//All cells read, map them to the global array
|
||||||
|
memcpy(datalayer_battery->status.cell_voltages_mV, cellvoltages, 96 * sizeof(uint16_t));
|
||||||
}
|
}
|
||||||
if (requested_poll == GROUP5_TEMPERATURE_POLL) {
|
if (requested_poll == GROUP5_TEMPERATURE_POLL) {
|
||||||
//2A,FF,FF,FF,FF,FF,3A,3A,
|
//2A,FF,FF,FF,FF,FF,3A,3A,
|
||||||
|
@ -557,15 +513,13 @@ void RenaultZoeGen1Battery::transmit_can(unsigned long currentMillis) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenaultZoeGen1Battery::setup(void) { // Performs one time setup at startup
|
void RenaultZoeGen1Battery::setup(void) { // Performs one time setup at startup
|
||||||
strncpy(datalayer.system.info.battery_protocol, "Renault Zoe Gen1 22/40kWh", 63);
|
strncpy(datalayer.system.info.battery_protocol, Name, 63);
|
||||||
datalayer.system.info.battery_protocol[63] = '\0';
|
datalayer.system.info.battery_protocol[63] = '\0';
|
||||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
datalayer.system.status.battery_allows_contactor_closing = true;
|
||||||
datalayer.battery.info.number_of_cells = 96;
|
datalayer_battery->info.number_of_cells = 96;
|
||||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
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.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV;
|
||||||
datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV;
|
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.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV;
|
||||||
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
datalayer_battery->info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -4,26 +4,98 @@
|
||||||
#include "CanBattery.h"
|
#include "CanBattery.h"
|
||||||
#include "RENAULT-ZOE-GEN1-HTML.h"
|
#include "RENAULT-ZOE-GEN1-HTML.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#ifdef RENAULT_ZOE_GEN1_BATTERY
|
||||||
#define SELECTED_BATTERY_CLASS RenaultZoeGen1Battery
|
#define SELECTED_BATTERY_CLASS RenaultZoeGen1Battery
|
||||||
|
#endif
|
||||||
#define MAX_PACK_VOLTAGE_DV 4200 //5000 = 500.0V
|
|
||||||
#define MIN_PACK_VOLTAGE_DV 3000
|
|
||||||
#define MAX_CELL_DEVIATION_MV 150
|
|
||||||
#define MAX_CELL_VOLTAGE_MV 4250 //Battery is put into emergency stop if one cell goes over this value
|
|
||||||
#define MIN_CELL_VOLTAGE_MV 2700 //Battery is put into emergency stop if one cell goes below this value
|
|
||||||
|
|
||||||
class RenaultZoeGen1Battery : public CanBattery {
|
class RenaultZoeGen1Battery : public CanBattery {
|
||||||
public:
|
public:
|
||||||
|
// Use this constructor for the second battery.
|
||||||
|
RenaultZoeGen1Battery(DATALAYER_BATTERY_TYPE* datalayer_ptr, DATALAYER_INFO_ZOE* extended, CAN_Interface targetCan)
|
||||||
|
: CanBattery(targetCan) {
|
||||||
|
datalayer_battery = datalayer_ptr;
|
||||||
|
allows_contactor_closing = nullptr;
|
||||||
|
datalayer_zoe = extended;
|
||||||
|
|
||||||
|
calculated_total_pack_voltage_mV = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the default constructor to create the first or single battery.
|
||||||
|
RenaultZoeGen1Battery() {
|
||||||
|
datalayer_battery = &datalayer.battery;
|
||||||
|
allows_contactor_closing = &datalayer.system.status.battery_allows_contactor_closing;
|
||||||
|
datalayer_zoe = &datalayer_extended.zoe;
|
||||||
|
}
|
||||||
|
|
||||||
virtual void setup(void);
|
virtual void setup(void);
|
||||||
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
||||||
virtual void update_values();
|
virtual void update_values();
|
||||||
virtual void transmit_can(unsigned long currentMillis);
|
virtual void transmit_can(unsigned long currentMillis);
|
||||||
|
static constexpr char* Name = "Renault Zoe Gen1 22/40kWh";
|
||||||
|
|
||||||
BatteryHtmlRenderer& get_status_renderer() { return renderer; }
|
BatteryHtmlRenderer& get_status_renderer() { return renderer; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static const int MAX_PACK_VOLTAGE_DV = 4200; //5000 = 500.0V
|
||||||
|
static const int MIN_PACK_VOLTAGE_DV = 3000;
|
||||||
|
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
|
||||||
|
|
||||||
RenaultZoeGen1HtmlRenderer renderer;
|
RenaultZoeGen1HtmlRenderer renderer;
|
||||||
|
|
||||||
|
DATALAYER_BATTERY_TYPE* datalayer_battery;
|
||||||
|
DATALAYER_INFO_ZOE* datalayer_zoe;
|
||||||
|
|
||||||
|
// If not null, this battery decides when the contactor can be closed and writes the value here.
|
||||||
|
bool* allows_contactor_closing;
|
||||||
|
|
||||||
|
uint16_t LB_SOC = 50;
|
||||||
|
uint16_t LB_Display_SOC = 50;
|
||||||
|
uint16_t LB_SOH = 99;
|
||||||
|
int16_t LB_Average_Temperature = 0;
|
||||||
|
uint32_t LB_Charging_Power_W = 0;
|
||||||
|
uint32_t LB_Regen_allowed_W = 0;
|
||||||
|
uint32_t LB_Discharge_allowed_W = 0;
|
||||||
|
int16_t LB_Current = 0;
|
||||||
|
int16_t LB_Cell_minimum_temperature = 0;
|
||||||
|
int16_t LB_Cell_maximum_temperature = 0;
|
||||||
|
uint16_t LB_Cell_minimum_voltage = 3700;
|
||||||
|
uint16_t LB_Cell_maximum_voltage = 3700;
|
||||||
|
uint16_t LB_kWh_Remaining = 0;
|
||||||
|
uint16_t LB_Battery_Voltage = 3700;
|
||||||
|
uint8_t LB_Heartbeat = 0;
|
||||||
|
uint8_t LB_CUV = 0;
|
||||||
|
uint8_t LB_HVBIR = 0;
|
||||||
|
uint8_t LB_HVBUV = 0;
|
||||||
|
uint8_t LB_EOCR = 0;
|
||||||
|
uint8_t LB_HVBOC = 0;
|
||||||
|
uint8_t LB_HVBOT = 0;
|
||||||
|
uint8_t LB_HVBOV = 0;
|
||||||
|
uint8_t LB_COV = 0;
|
||||||
|
uint8_t frame0 = 0;
|
||||||
|
uint8_t current_poll = 0;
|
||||||
|
uint8_t requested_poll = 0;
|
||||||
|
uint8_t group = 0;
|
||||||
|
uint16_t cellvoltages[96];
|
||||||
|
uint32_t calculated_total_pack_voltage_mV = 370000;
|
||||||
|
uint8_t highbyte_cell_next_frame = 0;
|
||||||
|
uint16_t SOC_polled = 5000;
|
||||||
|
int16_t cell_1_temperature_polled = 0;
|
||||||
|
int16_t cell_2_temperature_polled = 0;
|
||||||
|
int16_t cell_3_temperature_polled = 0;
|
||||||
|
int16_t cell_4_temperature_polled = 0;
|
||||||
|
int16_t cell_5_temperature_polled = 0;
|
||||||
|
int16_t cell_6_temperature_polled = 0;
|
||||||
|
int16_t cell_7_temperature_polled = 0;
|
||||||
|
int16_t cell_8_temperature_polled = 0;
|
||||||
|
int16_t cell_9_temperature_polled = 0;
|
||||||
|
int16_t cell_10_temperature_polled = 0;
|
||||||
|
int16_t cell_11_temperature_polled = 0;
|
||||||
|
int16_t cell_12_temperature_polled = 0;
|
||||||
|
uint16_t battery_mileage_in_km = 0;
|
||||||
|
uint16_t kWh_from_beginning_of_battery_life = 0;
|
||||||
|
bool looping_over_20 = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -18,7 +18,8 @@ class RenaultZoeGen1HtmlRenderer : public BatteryHtmlRenderer {
|
||||||
content += "<h4>HVBOT " + String(datalayer_extended.zoe.HVBOT) + "</h4>";
|
content += "<h4>HVBOT " + String(datalayer_extended.zoe.HVBOT) + "</h4>";
|
||||||
content += "<h4>HVBOV " + String(datalayer_extended.zoe.HVBOV) + "</h4>";
|
content += "<h4>HVBOV " + String(datalayer_extended.zoe.HVBOV) + "</h4>";
|
||||||
content += "<h4>COV " + String(datalayer_extended.zoe.COV) + "</h4>";
|
content += "<h4>COV " + String(datalayer_extended.zoe.COV) + "</h4>";
|
||||||
|
content += "<h4>Battery mileage " + String(datalayer_extended.zoe.mileage_km) + " km</h4>";
|
||||||
|
content += "<h4>Alltime energy " + String(datalayer_extended.zoe.alltime_kWh) + " kWh</h4>";
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
#include "../include.h"
|
#include "RENAULT-ZOE-GEN2-BATTERY.h"
|
||||||
#ifdef RENAULT_ZOE_GEN2_BATTERY
|
|
||||||
#include "../communication/can/comm_can.h"
|
#include "../communication/can/comm_can.h"
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../datalayer/datalayer_extended.h" //For "More battery info" webpage
|
#include "../datalayer/datalayer_extended.h" //For "More battery info" webpage
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
#include "RENAULT-ZOE-GEN2-BATTERY.h"
|
#include "../include.h"
|
||||||
|
|
||||||
/* TODO
|
/* TODO
|
||||||
- Add //NVROL Reset
|
- Add //NVROL Reset
|
||||||
|
@ -88,7 +87,6 @@ void RenaultZoeGen2Battery::update_values() {
|
||||||
datalayer_extended.zoePH2.battery_balance_capacity_wake = battery_balance_capacity_wake;
|
datalayer_extended.zoePH2.battery_balance_capacity_wake = battery_balance_capacity_wake;
|
||||||
datalayer_extended.zoePH2.battery_balance_time_wake = battery_balance_time_wake;
|
datalayer_extended.zoePH2.battery_balance_time_wake = battery_balance_time_wake;
|
||||||
datalayer_extended.zoePH2.battery_bms_state = battery_bms_state;
|
datalayer_extended.zoePH2.battery_bms_state = battery_bms_state;
|
||||||
datalayer_extended.zoePH2.battery_balance_switches = battery_balance_switches;
|
|
||||||
datalayer_extended.zoePH2.battery_energy_complete = battery_energy_complete;
|
datalayer_extended.zoePH2.battery_energy_complete = battery_energy_complete;
|
||||||
datalayer_extended.zoePH2.battery_energy_partial = battery_energy_partial;
|
datalayer_extended.zoePH2.battery_energy_partial = battery_energy_partial;
|
||||||
datalayer_extended.zoePH2.battery_slave_failures = battery_slave_failures;
|
datalayer_extended.zoePH2.battery_slave_failures = battery_slave_failures;
|
||||||
|
@ -208,30 +206,119 @@ void RenaultZoeGen2Battery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
||||||
battery_bms_state = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
battery_bms_state = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
||||||
break;
|
break;
|
||||||
case POLL_BALANCE_SWITCHES:
|
case POLL_BALANCE_SWITCHES:
|
||||||
if (rx_frame.data.u8[0] == 0x10) {
|
if (rx_frame.data.u8[0] == 0x23) {
|
||||||
for (int i = 0; i < 8; i++) {
|
battery_balancing_shunts[0] = (rx_frame.data.u8[4] & 0x80) >> 7;
|
||||||
// Byte 4 - 7 (bits 0-31)
|
battery_balancing_shunts[1] = (rx_frame.data.u8[4] & 0x40) >> 6;
|
||||||
for (int byte_i = 0; byte_i < 4; byte_i++) {
|
battery_balancing_shunts[2] = (rx_frame.data.u8[4] & 0x20) >> 5;
|
||||||
battery_balancing_shunts[byte_i * 8 + i] = (rx_frame.data.u8[4 + byte_i] & (1 << i)) >> i;
|
battery_balancing_shunts[3] = (rx_frame.data.u8[4] & 0x10) >> 4;
|
||||||
}
|
battery_balancing_shunts[4] = (rx_frame.data.u8[4] & 0x08) >> 3;
|
||||||
}
|
battery_balancing_shunts[5] = (rx_frame.data.u8[4] & 0x04) >> 2;
|
||||||
|
battery_balancing_shunts[6] = (rx_frame.data.u8[4] & 0x02) >> 1;
|
||||||
|
battery_balancing_shunts[7] = (rx_frame.data.u8[4] & 0x01);
|
||||||
|
|
||||||
|
battery_balancing_shunts[8] = (rx_frame.data.u8[5] & 0x80) >> 7;
|
||||||
|
battery_balancing_shunts[9] = (rx_frame.data.u8[5] & 0x40) >> 6;
|
||||||
|
battery_balancing_shunts[10] = (rx_frame.data.u8[5] & 0x20) >> 5;
|
||||||
|
battery_balancing_shunts[11] = (rx_frame.data.u8[5] & 0x10) >> 4;
|
||||||
|
battery_balancing_shunts[12] = (rx_frame.data.u8[5] & 0x08) >> 3;
|
||||||
|
battery_balancing_shunts[13] = (rx_frame.data.u8[5] & 0x04) >> 2;
|
||||||
|
battery_balancing_shunts[14] = (rx_frame.data.u8[5] & 0x02) >> 1;
|
||||||
|
battery_balancing_shunts[15] = (rx_frame.data.u8[5] & 0x01);
|
||||||
|
|
||||||
|
battery_balancing_shunts[16] = (rx_frame.data.u8[6] & 0x80) >> 7;
|
||||||
|
battery_balancing_shunts[17] = (rx_frame.data.u8[6] & 0x40) >> 6;
|
||||||
|
battery_balancing_shunts[18] = (rx_frame.data.u8[6] & 0x20) >> 5;
|
||||||
|
battery_balancing_shunts[19] = (rx_frame.data.u8[6] & 0x10) >> 4;
|
||||||
|
battery_balancing_shunts[20] = (rx_frame.data.u8[6] & 0x08) >> 3;
|
||||||
|
battery_balancing_shunts[21] = (rx_frame.data.u8[6] & 0x04) >> 2;
|
||||||
|
battery_balancing_shunts[22] = (rx_frame.data.u8[6] & 0x02) >> 1;
|
||||||
|
battery_balancing_shunts[23] = (rx_frame.data.u8[6] & 0x01);
|
||||||
|
|
||||||
|
battery_balancing_shunts[24] = (rx_frame.data.u8[7] & 0x80) >> 7;
|
||||||
|
battery_balancing_shunts[25] = (rx_frame.data.u8[7] & 0x40) >> 6;
|
||||||
|
battery_balancing_shunts[26] = (rx_frame.data.u8[7] & 0x20) >> 5;
|
||||||
|
battery_balancing_shunts[27] = (rx_frame.data.u8[7] & 0x10) >> 4;
|
||||||
|
battery_balancing_shunts[28] = (rx_frame.data.u8[7] & 0x08) >> 3;
|
||||||
|
battery_balancing_shunts[29] = (rx_frame.data.u8[7] & 0x04) >> 2;
|
||||||
|
battery_balancing_shunts[30] = (rx_frame.data.u8[7] & 0x02) >> 1;
|
||||||
|
battery_balancing_shunts[31] = (rx_frame.data.u8[7] & 0x01);
|
||||||
}
|
}
|
||||||
if (rx_frame.data.u8[0] == 0x21) {
|
if (rx_frame.data.u8[0] == 0x24) {
|
||||||
for (int i = 0; i < 8; i++) {
|
battery_balancing_shunts[32] = (rx_frame.data.u8[1] & 0x80) >> 7;
|
||||||
// Byte 1 to 7 (bits 32-87)
|
battery_balancing_shunts[33] = (rx_frame.data.u8[1] & 0x40) >> 6;
|
||||||
for (int byte_i = 0; byte_i < 7; byte_i++) {
|
battery_balancing_shunts[34] = (rx_frame.data.u8[1] & 0x20) >> 5;
|
||||||
battery_balancing_shunts[32 + byte_i * 8 + i] = (rx_frame.data.u8[1 + byte_i] & (1 << i)) >> i;
|
battery_balancing_shunts[35] = (rx_frame.data.u8[1] & 0x10) >> 4;
|
||||||
}
|
battery_balancing_shunts[36] = (rx_frame.data.u8[1] & 0x08) >> 3;
|
||||||
}
|
battery_balancing_shunts[37] = (rx_frame.data.u8[1] & 0x04) >> 2;
|
||||||
|
battery_balancing_shunts[38] = (rx_frame.data.u8[1] & 0x02) >> 1;
|
||||||
|
battery_balancing_shunts[39] = (rx_frame.data.u8[1] & 0x01);
|
||||||
|
|
||||||
|
battery_balancing_shunts[40] = (rx_frame.data.u8[2] & 0x80) >> 7;
|
||||||
|
battery_balancing_shunts[41] = (rx_frame.data.u8[2] & 0x40) >> 6;
|
||||||
|
battery_balancing_shunts[42] = (rx_frame.data.u8[2] & 0x20) >> 5;
|
||||||
|
battery_balancing_shunts[43] = (rx_frame.data.u8[2] & 0x10) >> 4;
|
||||||
|
battery_balancing_shunts[44] = (rx_frame.data.u8[2] & 0x08) >> 3;
|
||||||
|
battery_balancing_shunts[45] = (rx_frame.data.u8[2] & 0x04) >> 2;
|
||||||
|
battery_balancing_shunts[46] = (rx_frame.data.u8[2] & 0x02) >> 1;
|
||||||
|
battery_balancing_shunts[47] = (rx_frame.data.u8[2] & 0x01);
|
||||||
|
|
||||||
|
battery_balancing_shunts[48] = (rx_frame.data.u8[3] & 0x80) >> 7;
|
||||||
|
battery_balancing_shunts[49] = (rx_frame.data.u8[3] & 0x40) >> 6;
|
||||||
|
battery_balancing_shunts[50] = (rx_frame.data.u8[3] & 0x20) >> 5;
|
||||||
|
battery_balancing_shunts[51] = (rx_frame.data.u8[3] & 0x10) >> 4;
|
||||||
|
battery_balancing_shunts[52] = (rx_frame.data.u8[3] & 0x08) >> 3;
|
||||||
|
battery_balancing_shunts[53] = (rx_frame.data.u8[3] & 0x04) >> 2;
|
||||||
|
battery_balancing_shunts[54] = (rx_frame.data.u8[3] & 0x02) >> 1;
|
||||||
|
battery_balancing_shunts[55] = (rx_frame.data.u8[3] & 0x01);
|
||||||
|
|
||||||
|
battery_balancing_shunts[56] = (rx_frame.data.u8[4] & 0x80) >> 7;
|
||||||
|
battery_balancing_shunts[57] = (rx_frame.data.u8[4] & 0x40) >> 6;
|
||||||
|
battery_balancing_shunts[58] = (rx_frame.data.u8[4] & 0x20) >> 5;
|
||||||
|
battery_balancing_shunts[59] = (rx_frame.data.u8[4] & 0x10) >> 4;
|
||||||
|
battery_balancing_shunts[60] = (rx_frame.data.u8[4] & 0x08) >> 3;
|
||||||
|
battery_balancing_shunts[61] = (rx_frame.data.u8[4] & 0x04) >> 2;
|
||||||
|
battery_balancing_shunts[62] = (rx_frame.data.u8[4] & 0x02) >> 1;
|
||||||
|
battery_balancing_shunts[63] = (rx_frame.data.u8[4] & 0x01);
|
||||||
|
|
||||||
|
battery_balancing_shunts[64] = (rx_frame.data.u8[5] & 0x80) >> 7;
|
||||||
|
battery_balancing_shunts[65] = (rx_frame.data.u8[5] & 0x40) >> 6;
|
||||||
|
battery_balancing_shunts[66] = (rx_frame.data.u8[5] & 0x20) >> 5;
|
||||||
|
battery_balancing_shunts[67] = (rx_frame.data.u8[5] & 0x10) >> 4;
|
||||||
|
battery_balancing_shunts[68] = (rx_frame.data.u8[5] & 0x08) >> 3;
|
||||||
|
battery_balancing_shunts[69] = (rx_frame.data.u8[5] & 0x04) >> 2;
|
||||||
|
battery_balancing_shunts[70] = (rx_frame.data.u8[5] & 0x02) >> 1;
|
||||||
|
battery_balancing_shunts[71] = (rx_frame.data.u8[5] & 0x01);
|
||||||
|
|
||||||
|
battery_balancing_shunts[72] = (rx_frame.data.u8[6] & 0x80) >> 7;
|
||||||
|
battery_balancing_shunts[73] = (rx_frame.data.u8[6] & 0x40) >> 6;
|
||||||
|
battery_balancing_shunts[74] = (rx_frame.data.u8[6] & 0x20) >> 5;
|
||||||
|
battery_balancing_shunts[75] = (rx_frame.data.u8[6] & 0x10) >> 4;
|
||||||
|
battery_balancing_shunts[76] = (rx_frame.data.u8[6] & 0x08) >> 3;
|
||||||
|
battery_balancing_shunts[77] = (rx_frame.data.u8[6] & 0x04) >> 2;
|
||||||
|
battery_balancing_shunts[78] = (rx_frame.data.u8[6] & 0x02) >> 1;
|
||||||
|
battery_balancing_shunts[79] = (rx_frame.data.u8[6] & 0x01);
|
||||||
|
|
||||||
|
battery_balancing_shunts[80] = (rx_frame.data.u8[7] & 0x80) >> 7;
|
||||||
|
battery_balancing_shunts[81] = (rx_frame.data.u8[7] & 0x40) >> 6;
|
||||||
|
battery_balancing_shunts[82] = (rx_frame.data.u8[7] & 0x20) >> 5;
|
||||||
|
battery_balancing_shunts[83] = (rx_frame.data.u8[7] & 0x10) >> 4;
|
||||||
|
battery_balancing_shunts[84] = (rx_frame.data.u8[7] & 0x08) >> 3;
|
||||||
|
battery_balancing_shunts[85] = (rx_frame.data.u8[7] & 0x04) >> 2;
|
||||||
|
battery_balancing_shunts[86] = (rx_frame.data.u8[7] & 0x02) >> 1;
|
||||||
|
battery_balancing_shunts[87] = (rx_frame.data.u8[7] & 0x01);
|
||||||
}
|
}
|
||||||
if (rx_frame.data.u8[0] == 0x22) {
|
if (rx_frame.data.u8[0] == 0x25) {
|
||||||
for (int i = 0; i < 8; i++) {
|
battery_balancing_shunts[88] = (rx_frame.data.u8[1] & 0x80) >> 7;
|
||||||
// Byte 1 (bits 88-95)
|
battery_balancing_shunts[89] = (rx_frame.data.u8[1] & 0x40) >> 6;
|
||||||
battery_balancing_shunts[88 + i] = (rx_frame.data.u8[1] & (1 << i)) >> i;
|
battery_balancing_shunts[90] = (rx_frame.data.u8[1] & 0x20) >> 5;
|
||||||
}
|
battery_balancing_shunts[91] = (rx_frame.data.u8[1] & 0x10) >> 4;
|
||||||
memcpy(datalayer_battery->status.cell_balancing_status, battery_balancing_shunts, 96 * sizeof(bool));
|
battery_balancing_shunts[92] = (rx_frame.data.u8[1] & 0x08) >> 3;
|
||||||
|
battery_balancing_shunts[93] = (rx_frame.data.u8[1] & 0x04) >> 2;
|
||||||
|
battery_balancing_shunts[94] = (rx_frame.data.u8[1] & 0x02) >> 1;
|
||||||
|
battery_balancing_shunts[95] = (rx_frame.data.u8[1] & 0x01);
|
||||||
|
|
||||||
|
memcpy(datalayer.battery.status.cell_balancing_status, battery_balancing_shunts, 96 * sizeof(bool));
|
||||||
}
|
}
|
||||||
battery_balance_switches = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
|
||||||
break;
|
break;
|
||||||
case POLL_ENERGY_COMPLETE:
|
case POLL_ENERGY_COMPLETE:
|
||||||
battery_energy_complete = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
battery_energy_complete = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
||||||
|
@ -573,8 +660,6 @@ void RenaultZoeGen2Battery::transmit_can(unsigned long currentMillis) {
|
||||||
if (datalayer_extended.zoePH2.UserRequestNVROLReset) {
|
if (datalayer_extended.zoePH2.UserRequestNVROLReset) {
|
||||||
// Send NVROL reset frames
|
// Send NVROL reset frames
|
||||||
transmit_reset_nvrol_frames();
|
transmit_reset_nvrol_frames();
|
||||||
// after transmitting the NVROL reset frames, set the nvrol reset flag to false, to continue normal operation
|
|
||||||
datalayer_extended.zoePH2.UserRequestNVROLReset = false;
|
|
||||||
} else {
|
} else {
|
||||||
// Send 100ms CAN Message
|
// Send 100ms CAN Message
|
||||||
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
|
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
|
||||||
|
@ -609,7 +694,6 @@ void RenaultZoeGen2Battery::transmit_can(unsigned long currentMillis) {
|
||||||
transmit_can_frame(&ZOE_POLL_18DADBF1, can_config.battery);
|
transmit_can_frame(&ZOE_POLL_18DADBF1, can_config.battery);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1000mss
|
|
||||||
if (currentMillis - previousMillis1000 >= INTERVAL_1_S) {
|
if (currentMillis - previousMillis1000 >= INTERVAL_1_S) {
|
||||||
previousMillis1000 = currentMillis;
|
previousMillis1000 = currentMillis;
|
||||||
|
|
||||||
|
@ -620,7 +704,7 @@ void RenaultZoeGen2Battery::transmit_can(unsigned long currentMillis) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenaultZoeGen2Battery::setup(void) { // Performs one time setup at startup
|
void RenaultZoeGen2Battery::setup(void) { // Performs one time setup at startup
|
||||||
strncpy(datalayer.system.info.battery_protocol, "Renault Zoe Gen2 50kWh", 63);
|
strncpy(datalayer.system.info.battery_protocol, Name, 63);
|
||||||
datalayer.system.info.battery_protocol[63] = '\0';
|
datalayer.system.info.battery_protocol[63] = '\0';
|
||||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
datalayer.system.status.battery_allows_contactor_closing = true;
|
||||||
datalayer_battery->info.number_of_cells = 96;
|
datalayer_battery->info.number_of_cells = 96;
|
||||||
|
@ -653,40 +737,53 @@ void RenaultZoeGen2Battery::transmit_can_frame_376(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenaultZoeGen2Battery::transmit_reset_nvrol_frames(void) {
|
void RenaultZoeGen2Battery::transmit_reset_nvrol_frames(void) {
|
||||||
// NVROL reset, part 1: send 0x021003AAAAAAAAAA
|
switch (NVROLstateMachine) {
|
||||||
ZOE_POLL_18DADBF1.data = {0x02, 0x10, 0x03, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA};
|
case 0:
|
||||||
transmit_can_frame(&ZOE_POLL_18DADBF1, can_config.battery);
|
startTimeNVROL = millis();
|
||||||
// wait 100 ms
|
// NVROL reset, part 1: send 0x021003AAAAAAAAAA
|
||||||
wait_ms(100);
|
ZOE_POLL_18DADBF1.data = {0x02, 0x10, 0x03, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA};
|
||||||
// NVROL reset, part 2: send 0x043101B00900AAAA
|
transmit_can_frame(&ZOE_POLL_18DADBF1, can_config.battery);
|
||||||
ZOE_POLL_18DADBF1.data = {0x04, 0x31, 0x01, 0xB0, 0x09, 0x00, 0xAA, 0xAA};
|
NVROLstateMachine = 1;
|
||||||
transmit_can_frame(&ZOE_POLL_18DADBF1, can_config.battery);
|
break;
|
||||||
|
case 1: // wait 100 ms
|
||||||
// wait 1 s
|
if ((millis() - startTimeNVROL) > INTERVAL_100_MS) {
|
||||||
wait_ms(1000);
|
// NVROL reset, part 2: send 0x043101B00900AAAA
|
||||||
|
ZOE_POLL_18DADBF1.data = {0x04, 0x31, 0x01, 0xB0, 0x09, 0x00, 0xAA, 0xAA};
|
||||||
// Enable temporisation before sleep, part 1: send 0x021003AAAAAAAAAA
|
transmit_can_frame(&ZOE_POLL_18DADBF1, can_config.battery);
|
||||||
ZOE_POLL_18DADBF1.data = {0x02, 0x10, 0x03, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA};
|
startTimeNVROL = millis(); //Reset time start, so we can check time for next step
|
||||||
transmit_can_frame(&ZOE_POLL_18DADBF1, can_config.battery);
|
NVROLstateMachine = 2;
|
||||||
// wait 100 ms
|
}
|
||||||
wait_ms(100);
|
break;
|
||||||
// Enable temporisation before sleep, part 2: send 0x042E928101AAAAAA
|
case 2: // wait 1 s
|
||||||
ZOE_POLL_18DADBF1.data = {0x04, 0x2E, 0x92, 0x81, 0x01, 0xAA, 0xAA, 0xAA};
|
if ((millis() - startTimeNVROL) > INTERVAL_1_S) {
|
||||||
transmit_can_frame(&ZOE_POLL_18DADBF1, can_config.battery);
|
// Enable temporisation before sleep, part 1: send 0x021003AAAAAAAAAA
|
||||||
|
ZOE_POLL_18DADBF1.data = {0x02, 0x10, 0x03, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA};
|
||||||
// Set data back to init values
|
transmit_can_frame(&ZOE_POLL_18DADBF1, can_config.battery);
|
||||||
ZOE_POLL_18DADBF1.data = {0x03, 0x22, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00};
|
startTimeNVROL = millis(); //Reset time start, so we can check time for next step
|
||||||
poll_index = 0;
|
NVROLstateMachine = 3;
|
||||||
|
}
|
||||||
// after transmitting these frames, wait 30 s
|
break;
|
||||||
wait_ms(30000);
|
case 3: //Wait 100ms
|
||||||
}
|
if ((millis() - startTimeNVROL) > INTERVAL_100_MS) {
|
||||||
|
// Enable temporisation before sleep, part 2: send 0x042E928101AAAAAA
|
||||||
void RenaultZoeGen2Battery::wait_ms(int duration_ms) {
|
ZOE_POLL_18DADBF1.data = {0x04, 0x2E, 0x92, 0x81, 0x01, 0xAA, 0xAA, 0xAA};
|
||||||
unsigned long freezeMillis = millis();
|
transmit_can_frame(&ZOE_POLL_18DADBF1, can_config.battery);
|
||||||
while (millis() - freezeMillis < duration_ms) {
|
// Set data back to init values, we are done with the ZOE_POLL_18DADBF1 frame
|
||||||
// Do nothing - just wait
|
ZOE_POLL_18DADBF1.data = {0x03, 0x22, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
poll_index = 0;
|
||||||
|
NVROLstateMachine = 4;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 4: //Wait 30s
|
||||||
|
if ((millis() - startTimeNVROL) > INTERVAL_30_S) {
|
||||||
|
// after sleeping, set the nvrol reset flag to false, to continue normal operation of sending CAN messages
|
||||||
|
datalayer_extended.zoePH2.UserRequestNVROLReset = false;
|
||||||
|
// reset state machine, we are done!
|
||||||
|
NVROLstateMachine = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: //Something went catastrophically wrong. Reset state machine
|
||||||
|
NVROLstateMachine = 0;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -5,8 +5,9 @@
|
||||||
#include "CanBattery.h"
|
#include "CanBattery.h"
|
||||||
#include "RENAULT-ZOE-GEN2-HTML.h"
|
#include "RENAULT-ZOE-GEN2-HTML.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#ifdef RENAULT_ZOE_GEN2_BATTERY
|
||||||
#define SELECTED_BATTERY_CLASS RenaultZoeGen2Battery
|
#define SELECTED_BATTERY_CLASS RenaultZoeGen2Battery
|
||||||
|
#endif
|
||||||
|
|
||||||
class RenaultZoeGen2Battery : public CanBattery {
|
class RenaultZoeGen2Battery : public CanBattery {
|
||||||
public:
|
public:
|
||||||
|
@ -31,6 +32,7 @@ class RenaultZoeGen2Battery : public CanBattery {
|
||||||
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
||||||
virtual void update_values();
|
virtual void update_values();
|
||||||
virtual void transmit_can(unsigned long currentMillis);
|
virtual void transmit_can(unsigned long currentMillis);
|
||||||
|
static constexpr char* Name = "Renault Zoe Gen2 50kWh";
|
||||||
|
|
||||||
bool supports_reset_NVROL() { return true; }
|
bool supports_reset_NVROL() { return true; }
|
||||||
|
|
||||||
|
@ -191,7 +193,8 @@ class RenaultZoeGen2Battery : public CanBattery {
|
||||||
static const int POLL_CELL_93 = 0x9081;
|
static const int POLL_CELL_93 = 0x9081;
|
||||||
static const int POLL_CELL_94 = 0x9082;
|
static const int POLL_CELL_94 = 0x9082;
|
||||||
static const int POLL_CELL_95 = 0x9083;
|
static const int POLL_CELL_95 = 0x9083;
|
||||||
|
volatile unsigned long startTimeNVROL = 0;
|
||||||
|
uint8_t NVROLstateMachine = 0;
|
||||||
uint16_t battery_soc = 0;
|
uint16_t battery_soc = 0;
|
||||||
uint16_t battery_usable_soc = 5000;
|
uint16_t battery_usable_soc = 5000;
|
||||||
uint16_t battery_soh = 10000;
|
uint16_t battery_soh = 10000;
|
||||||
|
|
|
@ -40,7 +40,6 @@ class RenaultZoeGen2HtmlRenderer : public BatteryHtmlRenderer {
|
||||||
"<h4>balance capacity wake: " + String(datalayer_extended.zoePH2.battery_balance_capacity_wake) + "</h4>";
|
"<h4>balance capacity wake: " + String(datalayer_extended.zoePH2.battery_balance_capacity_wake) + "</h4>";
|
||||||
content += "<h4>balance time wake: " + String(datalayer_extended.zoePH2.battery_balance_time_wake) + "</h4>";
|
content += "<h4>balance time wake: " + String(datalayer_extended.zoePH2.battery_balance_time_wake) + "</h4>";
|
||||||
content += "<h4>bms state: " + String(datalayer_extended.zoePH2.battery_bms_state) + "</h4>";
|
content += "<h4>bms state: " + String(datalayer_extended.zoePH2.battery_bms_state) + "</h4>";
|
||||||
content += "<h4>balance switches: " + String(datalayer_extended.zoePH2.battery_balance_switches) + "</h4>";
|
|
||||||
content += "<h4>energy complete: " + String(datalayer_extended.zoePH2.battery_energy_complete) + "</h4>";
|
content += "<h4>energy complete: " + String(datalayer_extended.zoePH2.battery_energy_complete) + "</h4>";
|
||||||
content += "<h4>energy partial: " + String(datalayer_extended.zoePH2.battery_energy_partial) + "</h4>";
|
content += "<h4>energy partial: " + String(datalayer_extended.zoePH2.battery_energy_partial) + "</h4>";
|
||||||
content += "<h4>slave failures: " + String(datalayer_extended.zoePH2.battery_slave_failures) + "</h4>";
|
content += "<h4>slave failures: " + String(datalayer_extended.zoePH2.battery_slave_failures) + "</h4>";
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
#include "../include.h"
|
#include "RJXZS-BMS.h"
|
||||||
#ifdef RJXZS_BMS
|
|
||||||
#include "../communication/can/comm_can.h"
|
#include "../communication/can/comm_can.h"
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
#include "RJXZS-BMS.h"
|
#include "../include.h"
|
||||||
|
|
||||||
void RjxzsBms::update_values() {
|
void RjxzsBms::update_values() {
|
||||||
|
|
||||||
|
@ -517,7 +516,7 @@ void RjxzsBms::transmit_can(unsigned long currentMillis) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RjxzsBms::setup(void) { // Performs one time setup at startup
|
void RjxzsBms::setup(void) { // Performs one time setup at startup
|
||||||
strncpy(datalayer.system.info.battery_protocol, "RJXZS BMS, DIY battery", 63);
|
strncpy(datalayer.system.info.battery_protocol, Name, 63);
|
||||||
datalayer.system.info.battery_protocol[63] = '\0';
|
datalayer.system.info.battery_protocol[63] = '\0';
|
||||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
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.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV;
|
||||||
|
@ -525,5 +524,3 @@ void RjxzsBms::setup(void) { // Performs one time setup at startup
|
||||||
datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV;
|
datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV;
|
||||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
datalayer.system.status.battery_allows_contactor_closing = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // RJXZS_BMS
|
|
||||||
|
|
|
@ -5,8 +5,9 @@
|
||||||
|
|
||||||
#include "CanBattery.h"
|
#include "CanBattery.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#ifdef RJXZS_BMS
|
||||||
#define SELECTED_BATTERY_CLASS RjxzsBms
|
#define SELECTED_BATTERY_CLASS RjxzsBms
|
||||||
|
#endif
|
||||||
|
|
||||||
class RjxzsBms : public CanBattery {
|
class RjxzsBms : public CanBattery {
|
||||||
public:
|
public:
|
||||||
|
@ -14,6 +15,7 @@ class RjxzsBms : public CanBattery {
|
||||||
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
||||||
virtual void update_values();
|
virtual void update_values();
|
||||||
virtual void transmit_can(unsigned long currentMillis);
|
virtual void transmit_can(unsigned long currentMillis);
|
||||||
|
static constexpr char* Name = "RJXZS BMS, DIY battery";
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/* Tweak these according to your battery build */
|
/* Tweak these according to your battery build */
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
#include "../include.h"
|
#include "SANTA-FE-PHEV-BATTERY.h"
|
||||||
#ifdef SANTA_FE_PHEV_BATTERY
|
|
||||||
#include "../communication/can/comm_can.h"
|
#include "../communication/can/comm_can.h"
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
#include "SANTA-FE-PHEV-BATTERY.h"
|
#include "../include.h"
|
||||||
|
|
||||||
/* Credits go to maciek16c for these findings!
|
/* Credits go to maciek16c for these findings!
|
||||||
https://github.com/maciek16c/hyundai-santa-fe-phev-battery
|
https://github.com/maciek16c/hyundai-santa-fe-phev-battery
|
||||||
|
@ -320,7 +319,7 @@ void SantaFePhevBattery::transmit_can(unsigned long currentMillis) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SantaFePhevBattery::setup(void) { // Performs one time setup at startup
|
void SantaFePhevBattery::setup(void) { // Performs one time setup at startup
|
||||||
strncpy(datalayer.system.info.battery_protocol, "Santa Fe PHEV", 63);
|
strncpy(datalayer.system.info.battery_protocol, Name, 63);
|
||||||
datalayer.system.info.battery_protocol[63] = '\0';
|
datalayer.system.info.battery_protocol[63] = '\0';
|
||||||
datalayer_battery->info.number_of_cells = 96;
|
datalayer_battery->info.number_of_cells = 96;
|
||||||
datalayer_battery->info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
datalayer_battery->info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
||||||
|
@ -333,5 +332,3 @@ void SantaFePhevBattery::setup(void) { // Performs one time setup at startup
|
||||||
*allows_contactor_closing = true;
|
*allows_contactor_closing = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -5,8 +5,9 @@
|
||||||
#include "../include.h"
|
#include "../include.h"
|
||||||
#include "CanBattery.h"
|
#include "CanBattery.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#ifdef SANTA_FE_PHEV_BATTERY
|
||||||
#define SELECTED_BATTERY_CLASS SantaFePhevBattery
|
#define SELECTED_BATTERY_CLASS SantaFePhevBattery
|
||||||
|
#endif
|
||||||
|
|
||||||
class SantaFePhevBattery : public CanBattery {
|
class SantaFePhevBattery : public CanBattery {
|
||||||
public:
|
public:
|
||||||
|
@ -26,6 +27,7 @@ class SantaFePhevBattery : public CanBattery {
|
||||||
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
||||||
virtual void update_values();
|
virtual void update_values();
|
||||||
virtual void transmit_can(unsigned long currentMillis);
|
virtual void transmit_can(unsigned long currentMillis);
|
||||||
|
static constexpr char* Name = "Santa Fe PHEV";
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DATALAYER_BATTERY_TYPE* datalayer_battery;
|
DATALAYER_BATTERY_TYPE* datalayer_battery;
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
#include "../include.h"
|
#include "SIMPBMS-BATTERY.h"
|
||||||
#ifdef SIMPBMS_BATTERY
|
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
#include "SIMPBMS-BATTERY.h"
|
#include "../include.h"
|
||||||
|
|
||||||
void SimpBmsBattery::update_values() {
|
void SimpBmsBattery::update_values() {
|
||||||
|
|
||||||
|
@ -93,7 +92,7 @@ void SimpBmsBattery::transmit_can(unsigned long currentMillis) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimpBmsBattery::setup(void) { // Performs one time setup at startup
|
void SimpBmsBattery::setup(void) { // Performs one time setup at startup
|
||||||
strncpy(datalayer.system.info.battery_protocol, "SIMPBMS battery", 63);
|
strncpy(datalayer.system.info.battery_protocol, Name, 63);
|
||||||
datalayer.system.info.battery_protocol[63] = '\0';
|
datalayer.system.info.battery_protocol[63] = '\0';
|
||||||
datalayer.battery.info.number_of_cells = CELL_COUNT;
|
datalayer.battery.info.number_of_cells = CELL_COUNT;
|
||||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
||||||
|
@ -102,5 +101,3 @@ void SimpBmsBattery::setup(void) { // Performs one time setup at startup
|
||||||
datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV;
|
datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV;
|
||||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
datalayer.system.status.battery_allows_contactor_closing = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -5,8 +5,9 @@
|
||||||
|
|
||||||
#include "CanBattery.h"
|
#include "CanBattery.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#ifdef SIMPBMS_BATTERY
|
||||||
#define SELECTED_BATTERY_CLASS SimpBmsBattery
|
#define SELECTED_BATTERY_CLASS SimpBmsBattery
|
||||||
|
#endif
|
||||||
|
|
||||||
class SimpBmsBattery : public CanBattery {
|
class SimpBmsBattery : public CanBattery {
|
||||||
public:
|
public:
|
||||||
|
@ -14,6 +15,7 @@ class SimpBmsBattery : public CanBattery {
|
||||||
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
||||||
virtual void update_values();
|
virtual void update_values();
|
||||||
virtual void transmit_can(unsigned long currentMillis);
|
virtual void transmit_can(unsigned long currentMillis);
|
||||||
|
static constexpr char* Name = "SIMPBMS battery";
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/* DEFAULT VALUES BMS will send configured */
|
/* DEFAULT VALUES BMS will send configured */
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
#include "../include.h"
|
#include "SONO-BATTERY.h"
|
||||||
#ifdef SONO_BATTERY
|
|
||||||
#include "../communication/can/comm_can.h"
|
#include "../communication/can/comm_can.h"
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
#include "SONO-BATTERY.h"
|
#include "../include.h"
|
||||||
|
|
||||||
void SonoBattery::
|
void SonoBattery::
|
||||||
update_values() { //This function maps all the values fetched via CAN to the correct parameters used for modbus
|
update_values() { //This function maps all the values fetched via CAN to the correct parameters used for modbus
|
||||||
|
@ -141,7 +140,7 @@ void SonoBattery::transmit_can(unsigned long currentMillis) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SonoBattery::setup(void) { // Performs one time setup at startup
|
void SonoBattery::setup(void) { // Performs one time setup at startup
|
||||||
strncpy(datalayer.system.info.battery_protocol, "Sono Motors Sion 64kWh LFP ", 63);
|
strncpy(datalayer.system.info.battery_protocol, Name, 63);
|
||||||
datalayer.system.info.battery_protocol[63] = '\0';
|
datalayer.system.info.battery_protocol[63] = '\0';
|
||||||
datalayer.battery.info.number_of_cells = 96;
|
datalayer.battery.info.number_of_cells = 96;
|
||||||
datalayer.system.status.battery_allows_contactor_closing = true;
|
datalayer.system.status.battery_allows_contactor_closing = true;
|
||||||
|
@ -152,5 +151,3 @@ void SonoBattery::setup(void) { // Performs one time setup at startup
|
||||||
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
||||||
datalayer.battery.info.chemistry = battery_chemistry_enum::LFP;
|
datalayer.battery.info.chemistry = battery_chemistry_enum::LFP;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -5,8 +5,9 @@
|
||||||
|
|
||||||
#include "CanBattery.h"
|
#include "CanBattery.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#ifdef SONO_BATTERY
|
||||||
#define SELECTED_BATTERY_CLASS SonoBattery
|
#define SELECTED_BATTERY_CLASS SonoBattery
|
||||||
|
#endif
|
||||||
|
|
||||||
class SonoBattery : public CanBattery {
|
class SonoBattery : public CanBattery {
|
||||||
public:
|
public:
|
||||||
|
@ -14,6 +15,7 @@ class SonoBattery : public CanBattery {
|
||||||
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
||||||
virtual void update_values();
|
virtual void update_values();
|
||||||
virtual void transmit_can(unsigned long currentMillis);
|
virtual void transmit_can(unsigned long currentMillis);
|
||||||
|
static constexpr char* Name = "Sono Motors Sion 64kWh LFP ";
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const int MAX_PACK_VOLTAGE_DV = 5000; //5000 = 500.0V
|
static const int MAX_PACK_VOLTAGE_DV = 5000; //5000 = 500.0V
|
||||||
|
|
|
@ -11,6 +11,9 @@ class CanShunt : public Transmitter, CanReceiver {
|
||||||
virtual void transmit_can(unsigned long currentMillis) = 0;
|
virtual void transmit_can(unsigned long currentMillis) = 0;
|
||||||
virtual void handle_incoming_can_frame(CAN_frame rx_frame) = 0;
|
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); }
|
||||||
|
|
||||||
void transmit(unsigned long currentMillis) {
|
void transmit(unsigned long currentMillis) {
|
||||||
if (allowed_to_send_CAN) {
|
if (allowed_to_send_CAN) {
|
||||||
transmit_can(currentMillis);
|
transmit_can(currentMillis);
|
||||||
|
|
|
@ -4,6 +4,10 @@
|
||||||
CanShunt* shunt = nullptr;
|
CanShunt* shunt = nullptr;
|
||||||
|
|
||||||
void setup_can_shunt() {
|
void setup_can_shunt() {
|
||||||
|
if (shunt) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(SELECTED_SHUNT_CLASS)
|
#if defined(SELECTED_SHUNT_CLASS)
|
||||||
shunt = new SELECTED_SHUNT_CLASS();
|
shunt = new SELECTED_SHUNT_CLASS();
|
||||||
if (shunt) {
|
if (shunt) {
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
#include "../include.h"
|
#include "TESLA-BATTERY.h"
|
||||||
#ifdef TESLA_BATTERY
|
|
||||||
#include "../communication/can/comm_can.h"
|
#include "../communication/can/comm_can.h"
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../datalayer/datalayer_extended.h" //For Advanced Battery Insights webpage
|
#include "../datalayer/datalayer_extended.h" //For Advanced Battery Insights webpage
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
#include "TESLA-BATTERY.h"
|
#include "../include.h"
|
||||||
|
|
||||||
/* Credits: Most of the code comes from Per Carlen's bms_comms_tesla_model3.py (https://gitlab.com/pelle8/batt2gen24/) */
|
/* Credits: Most of the code comes from Per Carlen's bms_comms_tesla_model3.py (https://gitlab.com/pelle8/batt2gen24/) */
|
||||||
|
|
||||||
|
@ -1764,8 +1763,7 @@ void TeslaModel3YBattery::setup(void) { // Performs one time setup at startup
|
||||||
*allows_contactor_closing = true;
|
*allows_contactor_closing = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TESLA_MODEL_3Y_BATTERY // Model 3/Y can be either LFP or NCM/A
|
strncpy(datalayer.system.info.battery_protocol, Name, 63);
|
||||||
strncpy(datalayer.system.info.battery_protocol, "Tesla Model 3/Y", 63);
|
|
||||||
datalayer.system.info.battery_protocol[63] = '\0';
|
datalayer.system.info.battery_protocol[63] = '\0';
|
||||||
#ifdef LFP_CHEMISTRY
|
#ifdef LFP_CHEMISTRY
|
||||||
datalayer.battery.info.chemistry = battery_chemistry_enum::LFP;
|
datalayer.battery.info.chemistry = battery_chemistry_enum::LFP;
|
||||||
|
@ -1781,7 +1779,6 @@ void TeslaModel3YBattery::setup(void) { // Performs one time setup at startup
|
||||||
datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_NCA_NCM;
|
datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_NCA_NCM;
|
||||||
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_NCA_NCM;
|
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_NCA_NCM;
|
||||||
#endif // !LFP_CHEMISTRY
|
#endif // !LFP_CHEMISTRY
|
||||||
#endif // TESLA_MODEL_3Y_BATTERY
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TeslaModelSXBattery::setup(void) {
|
void TeslaModelSXBattery::setup(void) {
|
||||||
|
@ -1789,7 +1786,7 @@ void TeslaModelSXBattery::setup(void) {
|
||||||
*allows_contactor_closing = true;
|
*allows_contactor_closing = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
strncpy(datalayer.system.info.battery_protocol, "Tesla Model S/X", 63);
|
strncpy(datalayer.system.info.battery_protocol, Name, 63);
|
||||||
datalayer.system.info.battery_protocol[63] = '\0';
|
datalayer.system.info.battery_protocol[63] = '\0';
|
||||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_SX_NCMA;
|
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_SX_NCMA;
|
||||||
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_SX_NCMA;
|
datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_SX_NCMA;
|
||||||
|
@ -1797,5 +1794,3 @@ void TeslaModelSXBattery::setup(void) {
|
||||||
datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_NCA_NCM;
|
datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_NCA_NCM;
|
||||||
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_NCA_NCM;
|
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_NCA_NCM;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // TESLA_BATTERY
|
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
#include "CanBattery.h"
|
#include "CanBattery.h"
|
||||||
#include "TESLA-HTML.h"
|
#include "TESLA-HTML.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
|
||||||
#ifdef TESLA_MODEL_3Y_BATTERY
|
#ifdef TESLA_MODEL_3Y_BATTERY
|
||||||
#define SELECTED_BATTERY_CLASS TeslaModel3YBattery
|
#define SELECTED_BATTERY_CLASS TeslaModel3YBattery
|
||||||
#endif
|
#endif
|
||||||
|
@ -514,12 +513,14 @@ class TeslaModel3YBattery : public TeslaBattery {
|
||||||
operate_contactors = true;
|
operate_contactors = true;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
static constexpr char* Name = "Tesla Model 3/Y";
|
||||||
virtual void setup(void);
|
virtual void setup(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
class TeslaModelSXBattery : public TeslaBattery {
|
class TeslaModelSXBattery : public TeslaBattery {
|
||||||
public:
|
public:
|
||||||
TeslaModelSXBattery() { operate_contactors = true; }
|
TeslaModelSXBattery() { operate_contactors = true; }
|
||||||
|
static constexpr char* Name = "Tesla Model S/X";
|
||||||
virtual void setup(void);
|
virtual void setup(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
#include "../include.h"
|
|
||||||
#ifdef TEST_FAKE_BATTERY
|
|
||||||
#include "../datalayer/datalayer.h"
|
|
||||||
#include "TEST-FAKE-BATTERY.h"
|
#include "TEST-FAKE-BATTERY.h"
|
||||||
|
#include "../datalayer/datalayer.h"
|
||||||
|
#include "../include.h"
|
||||||
|
|
||||||
void print_units(char* header, int value, char* units) {
|
static void print_units(char* header, int value, char* units) {
|
||||||
logging.print(header);
|
logging.print(header);
|
||||||
logging.print(value);
|
logging.print(value);
|
||||||
logging.print(units);
|
logging.print(units);
|
||||||
|
@ -75,7 +74,7 @@ void TestFakeBattery::transmit_can(unsigned long currentMillis) {
|
||||||
void TestFakeBattery::setup(void) { // Performs one time setup at startup
|
void TestFakeBattery::setup(void) { // Performs one time setup at startup
|
||||||
randomSeed(analogRead(0));
|
randomSeed(analogRead(0));
|
||||||
|
|
||||||
strncpy(datalayer.system.info.battery_protocol, "Fake battery for testing purposes", 63);
|
strncpy(datalayer.system.info.battery_protocol, Name, 63);
|
||||||
datalayer.system.info.battery_protocol[63] = '\0';
|
datalayer.system.info.battery_protocol[63] = '\0';
|
||||||
|
|
||||||
datalayer_battery->info.max_design_voltage_dV =
|
datalayer_battery->info.max_design_voltage_dV =
|
||||||
|
@ -87,5 +86,3 @@ void TestFakeBattery::setup(void) { // Performs one time setup at startup
|
||||||
*allows_contactor_closing = true;
|
*allows_contactor_closing = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -4,8 +4,9 @@
|
||||||
#include "../include.h"
|
#include "../include.h"
|
||||||
#include "CanBattery.h"
|
#include "CanBattery.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#ifdef TEST_FAKE_BATTERY
|
||||||
#define SELECTED_BATTERY_CLASS TestFakeBattery
|
#define SELECTED_BATTERY_CLASS TestFakeBattery
|
||||||
|
#endif
|
||||||
|
|
||||||
class TestFakeBattery : public CanBattery {
|
class TestFakeBattery : public CanBattery {
|
||||||
public:
|
public:
|
||||||
|
@ -21,6 +22,8 @@ class TestFakeBattery : public CanBattery {
|
||||||
allows_contactor_closing = &datalayer.system.status.battery_allows_contactor_closing;
|
allows_contactor_closing = &datalayer.system.status.battery_allows_contactor_closing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static constexpr char* Name = "Fake battery for testing purposes";
|
||||||
|
|
||||||
virtual void setup();
|
virtual void setup();
|
||||||
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
||||||
virtual void update_values();
|
virtual void update_values();
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
#include "../include.h"
|
#include "VOLVO-SPA-BATTERY.h"
|
||||||
#ifdef VOLVO_SPA_BATTERY
|
|
||||||
#include "../communication/can/comm_can.h"
|
#include "../communication/can/comm_can.h"
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../datalayer/datalayer_extended.h" //For "More battery info" webpage
|
#include "../datalayer/datalayer_extended.h" //For "More battery info" webpage
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
#include "VOLVO-SPA-BATTERY.h"
|
#include "../include.h"
|
||||||
|
|
||||||
void VolvoSpaBattery::
|
void VolvoSpaBattery::
|
||||||
update_values() { //This function maps all the values fetched via CAN to the correct parameters used for the inverter
|
update_values() { //This function maps all the values fetched via CAN to the correct parameters used for the inverter
|
||||||
|
@ -378,7 +377,7 @@ void VolvoSpaBattery::transmit_can(unsigned long currentMillis) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void VolvoSpaBattery::setup(void) { // Performs one time setup at startup
|
void VolvoSpaBattery::setup(void) { // Performs one time setup at startup
|
||||||
strncpy(datalayer.system.info.battery_protocol, "Volvo / Polestar 69/78kWh SPA battery", 63);
|
strncpy(datalayer.system.info.battery_protocol, Name, 63);
|
||||||
datalayer.system.info.battery_protocol[63] = '\0';
|
datalayer.system.info.battery_protocol[63] = '\0';
|
||||||
datalayer.battery.info.number_of_cells = 0; // Initializes when all cells have been read
|
datalayer.battery.info.number_of_cells = 0; // Initializes when all cells have been read
|
||||||
datalayer.battery.info.total_capacity_Wh = 78200; //Startout in 78kWh mode (This value used for SOC calc)
|
datalayer.battery.info.total_capacity_Wh = 78200; //Startout in 78kWh mode (This value used for SOC calc)
|
||||||
|
@ -388,4 +387,3 @@ void VolvoSpaBattery::setup(void) { // Performs one time setup at startup
|
||||||
datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV;
|
datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV;
|
||||||
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
|
@ -6,8 +6,9 @@
|
||||||
#include "CanBattery.h"
|
#include "CanBattery.h"
|
||||||
#include "VOLVO-SPA-HTML.h"
|
#include "VOLVO-SPA-HTML.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#ifdef VOLVO_SPA_BATTERY
|
||||||
#define SELECTED_BATTERY_CLASS VolvoSpaBattery
|
#define SELECTED_BATTERY_CLASS VolvoSpaBattery
|
||||||
|
#endif
|
||||||
|
|
||||||
class VolvoSpaBattery : public CanBattery {
|
class VolvoSpaBattery : public CanBattery {
|
||||||
public:
|
public:
|
||||||
|
@ -15,6 +16,7 @@ class VolvoSpaBattery : public CanBattery {
|
||||||
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
||||||
virtual void update_values();
|
virtual void update_values();
|
||||||
virtual void transmit_can(unsigned long currentMillis);
|
virtual void transmit_can(unsigned long currentMillis);
|
||||||
|
static constexpr char* Name = "Volvo / Polestar 69/78kWh SPA battery";
|
||||||
|
|
||||||
bool supports_reset_DTC() { return true; }
|
bool supports_reset_DTC() { return true; }
|
||||||
void reset_DTC() { datalayer_extended.VolvoPolestar.UserRequestDTCreset = true; }
|
void reset_DTC() { datalayer_extended.VolvoPolestar.UserRequestDTCreset = true; }
|
||||||
|
@ -25,7 +27,11 @@ class VolvoSpaBattery : public CanBattery {
|
||||||
bool supports_reset_BECM() { return true; }
|
bool supports_reset_BECM() { return true; }
|
||||||
void reset_BECM() { datalayer_extended.VolvoPolestar.UserRequestBECMecuReset = true; }
|
void reset_BECM() { datalayer_extended.VolvoPolestar.UserRequestBECMecuReset = true; }
|
||||||
|
|
||||||
|
BatteryHtmlRenderer& get_status_renderer() { return renderer; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
VolvoSpaHtmlRenderer renderer;
|
||||||
|
|
||||||
void readCellVoltages();
|
void readCellVoltages();
|
||||||
|
|
||||||
static const int MAX_PACK_VOLTAGE_108S_DV = 4540;
|
static const int MAX_PACK_VOLTAGE_108S_DV = 4540;
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
#include "../include.h"
|
#include "VOLVO-SPA-HYBRID-BATTERY.h"
|
||||||
#ifdef VOLVO_SPA_HYBRID_BATTERY
|
|
||||||
#include "../communication/can/comm_can.h"
|
#include "../communication/can/comm_can.h"
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../datalayer/datalayer_extended.h" //For "More battery info" webpage
|
#include "../datalayer/datalayer_extended.h" //For "More battery info" webpage
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
#include "VOLVO-SPA-HYBRID-BATTERY.h"
|
#include "../include.h"
|
||||||
|
|
||||||
void VolvoSpaHybridBattery::
|
void VolvoSpaHybridBattery::
|
||||||
update_values() { //This function maps all the values fetched via CAN to the correct parameters used for the inverter
|
update_values() { //This function maps all the values fetched via CAN to the correct parameters used for the inverter
|
||||||
|
@ -553,8 +552,8 @@ void VolvoSpaHybridBattery::transmit_can(unsigned long currentMillis) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VolvoSpaHybridBattery::setup(void) { // Performs one time setup at startup
|
void VolvoSpaHybridBattery::setup(void) { // Performs one time setup at startup
|
||||||
strncpy(datalayer.system.info.battery_protocol, "Volvo PHEV battery", 63); //changed
|
strncpy(datalayer.system.info.battery_protocol, Name, 63); //changed
|
||||||
datalayer.system.info.battery_protocol[63] = '\0';
|
datalayer.system.info.battery_protocol[63] = '\0';
|
||||||
datalayer.battery.info.number_of_cells = 102; //was 108, changed
|
datalayer.battery.info.number_of_cells = 102; //was 108, changed
|
||||||
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV;
|
||||||
|
@ -563,4 +562,3 @@ void VolvoSpaHybridBattery::setup(void) { //
|
||||||
datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV;
|
datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV;
|
||||||
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
|
@ -6,8 +6,9 @@
|
||||||
#include "CanBattery.h"
|
#include "CanBattery.h"
|
||||||
#include "VOLVO-SPA-HYBRID-HTML.h"
|
#include "VOLVO-SPA-HYBRID-HTML.h"
|
||||||
|
|
||||||
#define BATTERY_SELECTED
|
#ifdef VOLVO_SPA_HYBRID_BATTERY
|
||||||
#define SELECTED_BATTERY_CLASS VolvoSpaHybridBattery
|
#define SELECTED_BATTERY_CLASS VolvoSpaHybridBattery
|
||||||
|
#endif
|
||||||
|
|
||||||
class VolvoSpaHybridBattery : public CanBattery {
|
class VolvoSpaHybridBattery : public CanBattery {
|
||||||
public:
|
public:
|
||||||
|
@ -15,6 +16,7 @@ class VolvoSpaHybridBattery : public CanBattery {
|
||||||
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
||||||
virtual void update_values();
|
virtual void update_values();
|
||||||
virtual void transmit_can(unsigned long currentMillis);
|
virtual void transmit_can(unsigned long currentMillis);
|
||||||
|
static constexpr char* Name = "Volvo PHEV battery";
|
||||||
|
|
||||||
bool supports_reset_DTC() { return true; }
|
bool supports_reset_DTC() { return true; }
|
||||||
void reset_DTC() { datalayer_extended.VolvoHybrid.UserRequestDTCreset = true; }
|
void reset_DTC() { datalayer_extended.VolvoHybrid.UserRequestDTCreset = true; }
|
||||||
|
|
|
@ -2,8 +2,42 @@
|
||||||
|
|
||||||
CanCharger* charger = nullptr;
|
CanCharger* charger = nullptr;
|
||||||
|
|
||||||
|
ChargerType user_selected_charger_type = ChargerType::None;
|
||||||
|
|
||||||
|
std::vector<ChargerType> supported_charger_types() {
|
||||||
|
std::vector<ChargerType> types;
|
||||||
|
|
||||||
|
for (int i = 0; i < (int)ChargerType::Highest; i++) {
|
||||||
|
types.push_back((ChargerType)i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return types;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern const char* name_for_charger_type(ChargerType type) {
|
||||||
|
switch (type) {
|
||||||
|
case ChargerType::ChevyVolt:
|
||||||
|
return ChevyVoltCharger::Name;
|
||||||
|
case ChargerType::NissanLeaf:
|
||||||
|
return NissanLeafCharger::Name;
|
||||||
|
case ChargerType::None:
|
||||||
|
return "None";
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void setup_charger() {
|
void setup_charger() {
|
||||||
|
#ifdef COMMON_IMAGE
|
||||||
|
switch (user_selected_charger_type) {
|
||||||
|
case ChargerType::ChevyVolt:
|
||||||
|
charger = new ChevyVoltCharger();
|
||||||
|
case ChargerType::NissanLeaf:
|
||||||
|
charger = new NissanLeafCharger();
|
||||||
|
}
|
||||||
|
#else
|
||||||
#ifdef SELECTED_CHARGER_CLASS
|
#ifdef SELECTED_CHARGER_CLASS
|
||||||
charger = new SELECTED_CHARGER_CLASS();
|
charger = new SELECTED_CHARGER_CLASS();
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,8 @@ class ChevyVoltCharger : public CanCharger {
|
||||||
public:
|
public:
|
||||||
ChevyVoltCharger() : CanCharger(ChargerType::ChevyVolt) {}
|
ChevyVoltCharger() : CanCharger(ChargerType::ChevyVolt) {}
|
||||||
|
|
||||||
const char* name() { return "Chevy Volt Gen1 Charger"; }
|
const char* name() { return Name; }
|
||||||
|
static constexpr char* Name = "Chevy Volt Gen1 Charger";
|
||||||
|
|
||||||
void map_can_frame_to_variable(CAN_frame rx_frame);
|
void map_can_frame_to_variable(CAN_frame rx_frame);
|
||||||
void transmit_can(unsigned long currentMillis);
|
void transmit_can(unsigned long currentMillis);
|
||||||
|
|
|
@ -7,7 +7,12 @@
|
||||||
#include "src/communication/Transmitter.h"
|
#include "src/communication/Transmitter.h"
|
||||||
#include "src/communication/can/CanReceiver.h"
|
#include "src/communication/can/CanReceiver.h"
|
||||||
|
|
||||||
enum class ChargerType { NissanLeaf, ChevyVolt };
|
enum class ChargerType { None, NissanLeaf, ChevyVolt, Highest };
|
||||||
|
|
||||||
|
extern ChargerType user_selected_charger_type;
|
||||||
|
|
||||||
|
extern std::vector<ChargerType> supported_charger_types();
|
||||||
|
extern const char* name_for_charger_type(ChargerType type);
|
||||||
|
|
||||||
// Generic base class for all chargers
|
// Generic base class for all chargers
|
||||||
class Charger {
|
class Charger {
|
||||||
|
|
|
@ -13,7 +13,9 @@ class NissanLeafCharger : public CanCharger {
|
||||||
public:
|
public:
|
||||||
NissanLeafCharger() : CanCharger(ChargerType::NissanLeaf) {}
|
NissanLeafCharger() : CanCharger(ChargerType::NissanLeaf) {}
|
||||||
|
|
||||||
const char* name() { return "Nissan LEAF 2013-2024 PDM charger"; }
|
const char* name() { return Name; }
|
||||||
|
static constexpr char* Name = "Nissan LEAF 2013-2024 PDM charger";
|
||||||
|
|
||||||
void map_can_frame_to_variable(CAN_frame rx_frame);
|
void map_can_frame_to_variable(CAN_frame rx_frame);
|
||||||
void transmit_can(unsigned long currentMillis);
|
void transmit_can(unsigned long currentMillis);
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
#define _CANRECEIVER_H
|
#define _CANRECEIVER_H
|
||||||
|
|
||||||
#include "src/devboard/utils/types.h"
|
#include "src/devboard/utils/types.h"
|
||||||
#include "src/include.h"
|
|
||||||
|
|
||||||
class CanReceiver {
|
class CanReceiver {
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -1,19 +1,50 @@
|
||||||
#include "comm_contactorcontrol.h"
|
#include "comm_contactorcontrol.h"
|
||||||
#include "../../include.h"
|
#include "../../include.h"
|
||||||
|
|
||||||
// Parameters
|
|
||||||
#ifndef CONTACTOR_CONTROL
|
|
||||||
#ifdef PWM_CONTACTOR_CONTROL
|
|
||||||
#error CONTACTOR_CONTROL needs to be enabled for PWM_CONTACTOR_CONTROL
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CONTACTOR_CONTROL
|
#ifdef CONTACTOR_CONTROL
|
||||||
|
const bool contactor_control_enabled_default = true;
|
||||||
|
#else
|
||||||
|
const bool contactor_control_enabled_default = false;
|
||||||
|
#endif
|
||||||
|
bool contactor_control_enabled = contactor_control_enabled_default;
|
||||||
|
|
||||||
|
#ifdef PWM_CONTACTOR_CONTROL
|
||||||
|
const bool pwn_contactor_control_default = true;
|
||||||
|
#else
|
||||||
|
const bool pwn_contactor_control_default = false;
|
||||||
|
#endif
|
||||||
|
bool pwm_contactor_control = pwn_contactor_control_default;
|
||||||
|
|
||||||
|
#ifdef PERIODIC_BMS_RESET
|
||||||
|
const bool periodic_bms_reset_default = true;
|
||||||
|
#else
|
||||||
|
const bool periodic_bms_reset_default = false;
|
||||||
|
#endif
|
||||||
|
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;
|
||||||
|
#endif
|
||||||
|
bool remote_bms_reset = remote_bms_reset_default;
|
||||||
|
|
||||||
|
#ifdef CONTACTOR_CONTROL_DOUBLE_BATTERY
|
||||||
|
const bool contactor_control_enabled_double_battery_default = true;
|
||||||
|
#else
|
||||||
|
const bool contactor_control_enabled_double_battery_default = false;
|
||||||
|
#endif
|
||||||
|
bool contactor_control_enabled_double_battery = contactor_control_enabled_double_battery_default;
|
||||||
|
|
||||||
|
// TODO: Ensure valid values at run-time
|
||||||
|
|
||||||
|
// Parameters
|
||||||
|
|
||||||
enum State { DISCONNECTED, START_PRECHARGE, PRECHARGE, POSITIVE, PRECHARGE_OFF, COMPLETED, SHUTDOWN_REQUESTED };
|
enum State { DISCONNECTED, START_PRECHARGE, PRECHARGE, POSITIVE, PRECHARGE_OFF, COMPLETED, SHUTDOWN_REQUESTED };
|
||||||
State contactorStatus = DISCONNECTED;
|
State contactorStatus = DISCONNECTED;
|
||||||
|
|
||||||
#define ON 1
|
const int ON = 1;
|
||||||
#define OFF 0
|
const int OFF = 0;
|
||||||
|
|
||||||
#ifdef NC_CONTACTORS //Normally closed contactors use inverted logic
|
#ifdef NC_CONTACTORS //Normally closed contactors use inverted logic
|
||||||
#undef ON
|
#undef ON
|
||||||
|
@ -34,11 +65,10 @@ State contactorStatus = DISCONNECTED;
|
||||||
#define PWM_ON_DUTY 1023
|
#define PWM_ON_DUTY 1023
|
||||||
#define PWM_Positive_Channel 0
|
#define PWM_Positive_Channel 0
|
||||||
#define PWM_Negative_Channel 1
|
#define PWM_Negative_Channel 1
|
||||||
unsigned long prechargeStartTime = 0;
|
static unsigned long prechargeStartTime = 0;
|
||||||
unsigned long negativeStartTime = 0;
|
unsigned long negativeStartTime = 0;
|
||||||
unsigned long prechargeCompletedTime = 0;
|
unsigned long prechargeCompletedTime = 0;
|
||||||
unsigned long timeSpentInFaultedMode = 0;
|
unsigned long timeSpentInFaultedMode = 0;
|
||||||
#endif
|
|
||||||
unsigned long currentTime = 0;
|
unsigned long currentTime = 0;
|
||||||
unsigned long lastPowerRemovalTime = 0;
|
unsigned long lastPowerRemovalTime = 0;
|
||||||
unsigned long bmsPowerOnTime = 0;
|
unsigned long bmsPowerOnTime = 0;
|
||||||
|
@ -47,12 +77,12 @@ const unsigned long powerRemovalDuration = 30000; // 30 seconds i
|
||||||
const unsigned long bmsWarmupDuration = 3000;
|
const unsigned long bmsWarmupDuration = 3000;
|
||||||
|
|
||||||
void set(uint8_t pin, bool direction, uint32_t pwm_freq = 0xFFFF) {
|
void set(uint8_t pin, bool direction, uint32_t pwm_freq = 0xFFFF) {
|
||||||
#ifdef PWM_CONTACTOR_CONTROL
|
if (pwm_contactor_control) {
|
||||||
if (pwm_freq != 0xFFFF) {
|
if (pwm_freq != 0xFFFF) {
|
||||||
ledcWrite(pin, pwm_freq);
|
ledcWrite(pin, pwm_freq);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
if (direction == 1) {
|
if (direction == 1) {
|
||||||
digitalWrite(pin, HIGH);
|
digitalWrite(pin, HIGH);
|
||||||
} else { // 0
|
} else { // 0
|
||||||
|
@ -64,46 +94,39 @@ void set(uint8_t pin, bool direction, uint32_t pwm_freq = 0xFFFF) {
|
||||||
|
|
||||||
void init_contactors() {
|
void init_contactors() {
|
||||||
// Init contactor pins
|
// Init contactor pins
|
||||||
#ifdef CONTACTOR_CONTROL
|
if (contactor_control_enabled) {
|
||||||
#ifdef PWM_CONTACTOR_CONTROL
|
if (pwm_contactor_control) {
|
||||||
// Setup PWM Channel Frequency and Resolution
|
// Setup PWM Channel Frequency and Resolution
|
||||||
ledcAttachChannel(POSITIVE_CONTACTOR_PIN, PWM_Freq, PWM_Res, PWM_Positive_Channel);
|
ledcAttachChannel(POSITIVE_CONTACTOR_PIN, PWM_Freq, PWM_Res, PWM_Positive_Channel);
|
||||||
ledcAttachChannel(NEGATIVE_CONTACTOR_PIN, PWM_Freq, PWM_Res, PWM_Negative_Channel);
|
ledcAttachChannel(NEGATIVE_CONTACTOR_PIN, PWM_Freq, PWM_Res, PWM_Negative_Channel);
|
||||||
// Set all pins OFF (0% PWM)
|
// Set all pins OFF (0% PWM)
|
||||||
ledcWrite(POSITIVE_CONTACTOR_PIN, PWM_OFF_DUTY);
|
ledcWrite(POSITIVE_CONTACTOR_PIN, PWM_OFF_DUTY);
|
||||||
ledcWrite(NEGATIVE_CONTACTOR_PIN, PWM_OFF_DUTY);
|
ledcWrite(NEGATIVE_CONTACTOR_PIN, PWM_OFF_DUTY);
|
||||||
#else //Normal CONTACTOR_CONTROL
|
} else { //Normal CONTACTOR_CONTROL
|
||||||
pinMode(POSITIVE_CONTACTOR_PIN, OUTPUT);
|
pinMode(POSITIVE_CONTACTOR_PIN, OUTPUT);
|
||||||
set(POSITIVE_CONTACTOR_PIN, OFF);
|
set(POSITIVE_CONTACTOR_PIN, OFF);
|
||||||
pinMode(NEGATIVE_CONTACTOR_PIN, OUTPUT);
|
pinMode(NEGATIVE_CONTACTOR_PIN, OUTPUT);
|
||||||
set(NEGATIVE_CONTACTOR_PIN, OFF);
|
set(NEGATIVE_CONTACTOR_PIN, OFF);
|
||||||
#endif // Precharge never has PWM regardless of setting
|
} // Precharge never has PWM regardless of setting
|
||||||
pinMode(PRECHARGE_PIN, OUTPUT);
|
pinMode(PRECHARGE_PIN, OUTPUT);
|
||||||
set(PRECHARGE_PIN, OFF);
|
set(PRECHARGE_PIN, OFF);
|
||||||
#endif // CONTACTOR_CONTROL
|
}
|
||||||
#ifdef CONTACTOR_CONTROL_DOUBLE_BATTERY
|
if (contactor_control_enabled_double_battery) {
|
||||||
pinMode(SECOND_POSITIVE_CONTACTOR_PIN, OUTPUT);
|
pinMode(SECOND_BATTERY_CONTACTORS_PIN, OUTPUT);
|
||||||
set(SECOND_POSITIVE_CONTACTOR_PIN, OFF);
|
set(SECOND_BATTERY_CONTACTORS_PIN, OFF);
|
||||||
pinMode(SECOND_NEGATIVE_CONTACTOR_PIN, OUTPUT);
|
}
|
||||||
set(SECOND_NEGATIVE_CONTACTOR_PIN, OFF);
|
|
||||||
#endif // CONTACTOR_CONTROL_DOUBLE_BATTERY
|
|
||||||
// Init BMS contactor
|
// Init BMS contactor
|
||||||
#if defined HW_STARK || defined HW_3LB // This hardware has dedicated pin, always enable on start
|
#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
|
pinMode(BMS_POWER, OUTPUT); //LilyGo is omitted from this, only enabled if user selects PERIODIC_BMS_RESET
|
||||||
digitalWrite(BMS_POWER, HIGH);
|
digitalWrite(BMS_POWER, HIGH);
|
||||||
#ifdef BMS_2_POWER //Hardware supports 2x BMS
|
#endif // HW with dedicated BMS pins
|
||||||
pinMode(BMS_2_POWER, OUTPUT);
|
|
||||||
digitalWrite(BMS_2_POWER, HIGH);
|
#ifdef BMS_POWER
|
||||||
#endif //BMS_2_POWER
|
if (periodic_bms_reset || remote_bms_reset) {
|
||||||
#endif // HW with dedicated BMS pins
|
pinMode(BMS_POWER, OUTPUT);
|
||||||
#if defined(PERIODIC_BMS_RESET) || defined(REMOTE_BMS_RESET) // User has enabled BMS reset, turn on output on start
|
digitalWrite(BMS_POWER, HIGH);
|
||||||
pinMode(BMS_POWER, OUTPUT);
|
}
|
||||||
digitalWrite(BMS_POWER, HIGH);
|
#endif
|
||||||
#ifdef BMS_2_POWER //Hardware supports 2x BMS
|
|
||||||
pinMode(BMS_2_POWER, OUTPUT);
|
|
||||||
digitalWrite(BMS_2_POWER, HIGH);
|
|
||||||
#endif //BMS_2_POWER
|
|
||||||
#endif //PERIODIC_BMS_RESET
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dbg_contactors(const char* state) {
|
static void dbg_contactors(const char* state) {
|
||||||
|
@ -117,125 +140,127 @@ static void dbg_contactors(const char* state) {
|
||||||
|
|
||||||
// Main functions of the handle_contactors include checking if inverter allows for closing, checking battery 2, checking BMS power output, and actual contactor closing/precharge via GPIO
|
// Main functions of the handle_contactors include checking if inverter allows for closing, checking battery 2, checking BMS power output, and actual contactor closing/precharge via GPIO
|
||||||
void handle_contactors() {
|
void handle_contactors() {
|
||||||
#if defined(SMA_BYD_H_CAN) || defined(SMA_BYD_HVS_CAN) || defined(SMA_TRIPOWER_CAN)
|
if (inverter && inverter->controls_contactor()) {
|
||||||
datalayer.system.status.inverter_allows_contactor_closing = digitalRead(INVERTER_CONTACTOR_ENABLE_PIN);
|
datalayer.system.status.inverter_allows_contactor_closing = inverter->allows_contactor_closing();
|
||||||
#endif
|
}
|
||||||
|
|
||||||
|
#ifdef BMS_POWER
|
||||||
handle_BMSpower(); // Some batteries need to be periodically power cycled
|
handle_BMSpower(); // Some batteries need to be periodically power cycled
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONTACTOR_CONTROL_DOUBLE_BATTERY
|
#ifdef CONTACTOR_CONTROL_DOUBLE_BATTERY
|
||||||
handle_contactors_battery2();
|
handle_contactors_battery2();
|
||||||
#endif // CONTACTOR_CONTROL_DOUBLE_BATTERY
|
#endif // CONTACTOR_CONTROL_DOUBLE_BATTERY
|
||||||
|
|
||||||
#ifdef CONTACTOR_CONTROL
|
if (contactor_control_enabled) {
|
||||||
// First check if we have any active errors, incase we do, turn off the battery
|
// First check if we have any active errors, incase we do, turn off the battery
|
||||||
if (datalayer.battery.status.bms_status == FAULT) {
|
if (datalayer.battery.status.bms_status == FAULT) {
|
||||||
timeSpentInFaultedMode++;
|
timeSpentInFaultedMode++;
|
||||||
} else {
|
} else {
|
||||||
timeSpentInFaultedMode = 0;
|
timeSpentInFaultedMode = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//handle contactor control SHUTDOWN_REQUESTED
|
//handle contactor control SHUTDOWN_REQUESTED
|
||||||
if (timeSpentInFaultedMode > MAX_ALLOWED_FAULT_TICKS) {
|
if (timeSpentInFaultedMode > MAX_ALLOWED_FAULT_TICKS) {
|
||||||
contactorStatus = SHUTDOWN_REQUESTED;
|
contactorStatus = SHUTDOWN_REQUESTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (contactorStatus == SHUTDOWN_REQUESTED) {
|
if (contactorStatus == SHUTDOWN_REQUESTED) {
|
||||||
set(PRECHARGE_PIN, OFF);
|
set(PRECHARGE_PIN, OFF);
|
||||||
set(NEGATIVE_CONTACTOR_PIN, OFF, PWM_OFF_DUTY);
|
set(NEGATIVE_CONTACTOR_PIN, OFF, PWM_OFF_DUTY);
|
||||||
set(POSITIVE_CONTACTOR_PIN, OFF, PWM_OFF_DUTY);
|
set(POSITIVE_CONTACTOR_PIN, OFF, PWM_OFF_DUTY);
|
||||||
set_event(EVENT_ERROR_OPEN_CONTACTOR, 0);
|
set_event(EVENT_ERROR_OPEN_CONTACTOR, 0);
|
||||||
datalayer.system.status.contactors_engaged = false;
|
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)
|
return; // A fault scenario latches the contactor control. It is not possible to recover without a powercycle (and investigation why fault occured)
|
||||||
}
|
}
|
||||||
|
|
||||||
// After that, check if we are OK to start turning on the battery
|
// After that, check if we are OK to start turning on the battery
|
||||||
if (contactorStatus == DISCONNECTED) {
|
if (contactorStatus == DISCONNECTED) {
|
||||||
set(PRECHARGE_PIN, OFF);
|
set(PRECHARGE_PIN, OFF);
|
||||||
set(NEGATIVE_CONTACTOR_PIN, OFF, PWM_OFF_DUTY);
|
set(NEGATIVE_CONTACTOR_PIN, OFF, PWM_OFF_DUTY);
|
||||||
set(POSITIVE_CONTACTOR_PIN, OFF, PWM_OFF_DUTY);
|
set(POSITIVE_CONTACTOR_PIN, OFF, PWM_OFF_DUTY);
|
||||||
datalayer.system.status.contactors_engaged = false;
|
datalayer.system.status.contactors_engaged = false;
|
||||||
|
|
||||||
if (datalayer.system.status.battery_allows_contactor_closing &&
|
if (datalayer.system.status.battery_allows_contactor_closing &&
|
||||||
datalayer.system.status.inverter_allows_contactor_closing && !datalayer.system.settings.equipment_stop_active) {
|
datalayer.system.status.inverter_allows_contactor_closing &&
|
||||||
contactorStatus = START_PRECHARGE;
|
!datalayer.system.settings.equipment_stop_active) {
|
||||||
|
contactorStatus = START_PRECHARGE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// In case the inverter requests contactors to open, set the state accordingly
|
||||||
|
if (contactorStatus == COMPLETED) {
|
||||||
|
//Incase inverter (or estop) requests contactors to open, make state machine jump to Disconnected state (recoverable)
|
||||||
|
if (!datalayer.system.status.inverter_allows_contactor_closing ||
|
||||||
|
datalayer.system.settings.equipment_stop_active) {
|
||||||
|
contactorStatus = DISCONNECTED;
|
||||||
|
}
|
||||||
|
// Skip running the state machine below if it has already completed
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentTime = millis();
|
||||||
|
|
||||||
|
if (currentTime < INTERVAL_10_S) {
|
||||||
|
// Skip running the state machine before system has started up.
|
||||||
|
// Gives the system some time to detect any faults from battery before blindly just engaging the contactors
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
dbg_contactors("NEGATIVE");
|
||||||
|
prechargeStartTime = currentTime;
|
||||||
|
contactorStatus = PRECHARGE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PRECHARGE:
|
||||||
|
if (currentTime - prechargeStartTime >= NEGATIVE_CONTACTOR_TIME_MS) {
|
||||||
|
set(PRECHARGE_PIN, ON);
|
||||||
|
dbg_contactors("PRECHARGE");
|
||||||
|
negativeStartTime = currentTime;
|
||||||
|
contactorStatus = POSITIVE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case POSITIVE:
|
||||||
|
if (currentTime - negativeStartTime >= PRECHARGE_TIME_MS) {
|
||||||
|
set(POSITIVE_CONTACTOR_PIN, ON, PWM_ON_DUTY);
|
||||||
|
dbg_contactors("POSITIVE");
|
||||||
|
prechargeCompletedTime = currentTime;
|
||||||
|
contactorStatus = PRECHARGE_OFF;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
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);
|
||||||
|
dbg_contactors("PRECHARGE_OFF");
|
||||||
|
contactorStatus = COMPLETED;
|
||||||
|
datalayer.system.status.contactors_engaged = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// In case the inverter requests contactors to open, set the state accordingly
|
|
||||||
if (contactorStatus == COMPLETED) {
|
|
||||||
//Incase inverter (or estop) requests contactors to open, make state machine jump to Disconnected state (recoverable)
|
|
||||||
if (!datalayer.system.status.inverter_allows_contactor_closing || datalayer.system.settings.equipment_stop_active) {
|
|
||||||
contactorStatus = DISCONNECTED;
|
|
||||||
}
|
|
||||||
// Skip running the state machine below if it has already completed
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
currentTime = millis();
|
|
||||||
|
|
||||||
if (currentTime < INTERVAL_10_S) {
|
|
||||||
// Skip running the state machine before system has started up.
|
|
||||||
// Gives the system some time to detect any faults from battery before blindly just engaging the contactors
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
dbg_contactors("NEGATIVE");
|
|
||||||
prechargeStartTime = currentTime;
|
|
||||||
contactorStatus = PRECHARGE;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PRECHARGE:
|
|
||||||
if (currentTime - prechargeStartTime >= NEGATIVE_CONTACTOR_TIME_MS) {
|
|
||||||
set(PRECHARGE_PIN, ON);
|
|
||||||
dbg_contactors("PRECHARGE");
|
|
||||||
negativeStartTime = currentTime;
|
|
||||||
contactorStatus = POSITIVE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case POSITIVE:
|
|
||||||
if (currentTime - negativeStartTime >= PRECHARGE_TIME_MS) {
|
|
||||||
set(POSITIVE_CONTACTOR_PIN, ON, PWM_ON_DUTY);
|
|
||||||
dbg_contactors("POSITIVE");
|
|
||||||
prechargeCompletedTime = currentTime;
|
|
||||||
contactorStatus = PRECHARGE_OFF;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
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);
|
|
||||||
dbg_contactors("PRECHARGE_OFF");
|
|
||||||
contactorStatus = COMPLETED;
|
|
||||||
datalayer.system.status.contactors_engaged = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif // CONTACTOR_CONTROL
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONTACTOR_CONTROL_DOUBLE_BATTERY
|
#ifdef CONTACTOR_CONTROL_DOUBLE_BATTERY
|
||||||
void handle_contactors_battery2() {
|
void handle_contactors_battery2() {
|
||||||
if ((contactorStatus == COMPLETED) && datalayer.system.status.battery2_allowed_contactor_closing) {
|
if ((contactorStatus == COMPLETED) && datalayer.system.status.battery2_allowed_contactor_closing) {
|
||||||
set(SECOND_NEGATIVE_CONTACTOR_PIN, ON);
|
set(SECOND_BATTERY_CONTACTORS_PIN, ON);
|
||||||
set(SECOND_POSITIVE_CONTACTOR_PIN, ON);
|
|
||||||
datalayer.system.status.contactors_battery2_engaged = true;
|
datalayer.system.status.contactors_battery2_engaged = true;
|
||||||
} else { // Closing contactors on secondary battery not allowed
|
} else { // Closing contactors on secondary battery not allowed
|
||||||
set(SECOND_NEGATIVE_CONTACTOR_PIN, OFF);
|
set(SECOND_BATTERY_CONTACTORS_PIN, OFF);
|
||||||
set(SECOND_POSITIVE_CONTACTOR_PIN, OFF);
|
|
||||||
datalayer.system.status.contactors_battery2_engaged = false;
|
datalayer.system.status.contactors_battery2_engaged = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // CONTACTOR_CONTROL_DOUBLE_BATTERY
|
#endif
|
||||||
|
|
||||||
/* PERIODIC_BMS_RESET - Once every 24 hours we remove power from the BMS_power pin for 30 seconds.
|
/* PERIODIC_BMS_RESET - Once every 24 hours we remove power from the BMS_power pin for 30 seconds.
|
||||||
REMOTE_BMS_RESET - Allows the user to remotely powercycle the BMS by sending a command to the emulator via MQTT.
|
REMOTE_BMS_RESET - Allows the user to remotely powercycle the BMS by sending a command to the emulator via MQTT.
|
||||||
|
@ -244,58 +269,62 @@ 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
|
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 */
|
Feature is only used if user has enabled PERIODIC_BMS_RESET in the USER_SETTINGS */
|
||||||
|
|
||||||
|
#ifdef BMS_POWER
|
||||||
void handle_BMSpower() {
|
void handle_BMSpower() {
|
||||||
#if defined(PERIODIC_BMS_RESET) || defined(REMOTE_BMS_RESET)
|
if (periodic_bms_reset || remote_bms_reset) {
|
||||||
// Get current time
|
// Get current time
|
||||||
currentTime = millis();
|
currentTime = millis();
|
||||||
|
|
||||||
#ifdef PERIODIC_BMS_RESET
|
if (periodic_bms_reset) {
|
||||||
// Check if 24 hours have passed since the last power removal
|
// Check if 24 hours have passed since the last power removal
|
||||||
if ((currentTime + bmsResetTimeOffset) - lastPowerRemovalTime >= powerRemovalInterval) {
|
if ((currentTime + bmsResetTimeOffset) - lastPowerRemovalTime >= powerRemovalInterval) {
|
||||||
start_bms_reset();
|
start_bms_reset();
|
||||||
}
|
}
|
||||||
#endif //PERIODIC_BMS_RESET
|
}
|
||||||
|
|
||||||
// If power has been removed for 30 seconds, restore the power
|
// If power has been removed for 30 seconds, restore the power
|
||||||
if (datalayer.system.status.BMS_reset_in_progress && currentTime - lastPowerRemovalTime >= powerRemovalDuration) {
|
if (datalayer.system.status.BMS_reset_in_progress && currentTime - lastPowerRemovalTime >= powerRemovalDuration) {
|
||||||
// Reapply power to the BMS
|
// Reapply power to the BMS
|
||||||
digitalWrite(BMS_POWER, HIGH);
|
digitalWrite(BMS_POWER, HIGH);
|
||||||
#ifdef BMS_2_POWER
|
#ifdef BMS_2_POWER
|
||||||
digitalWrite(BMS_2_POWER, HIGH); // Same for battery 2
|
digitalWrite(BMS_2_POWER, HIGH); // Same for battery 2
|
||||||
#endif
|
#endif
|
||||||
bmsPowerOnTime = currentTime;
|
bmsPowerOnTime = currentTime;
|
||||||
datalayer.system.status.BMS_reset_in_progress = false; // Reset the power removal flag
|
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
|
datalayer.system.status.BMS_startup_in_progress = true; // Set the BMS warmup flag
|
||||||
}
|
}
|
||||||
//if power has been restored we need to wait a couple of seconds to unpause the battery
|
//if power has been restored we need to wait a couple of seconds to unpause the battery
|
||||||
if (datalayer.system.status.BMS_startup_in_progress && currentTime - bmsPowerOnTime >= bmsWarmupDuration) {
|
if (datalayer.system.status.BMS_startup_in_progress && currentTime - bmsPowerOnTime >= bmsWarmupDuration) {
|
||||||
|
|
||||||
setBatteryPause(false, false, false, false);
|
setBatteryPause(false, false, false, false);
|
||||||
|
|
||||||
datalayer.system.status.BMS_startup_in_progress = false; // Reset the BMS warmup removal flag
|
datalayer.system.status.BMS_startup_in_progress = false; // Reset the BMS warmup removal flag
|
||||||
set_event(EVENT_PERIODIC_BMS_RESET, 0);
|
set_event(EVENT_PERIODIC_BMS_RESET, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif //defined(PERIODIC_BMS_RESET) || defined(REMOTE_BMS_RESET)
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void start_bms_reset() {
|
void start_bms_reset() {
|
||||||
#if defined(PERIODIC_BMS_RESET) || defined(REMOTE_BMS_RESET)
|
if (periodic_bms_reset || remote_bms_reset) {
|
||||||
if (!datalayer.system.status.BMS_reset_in_progress) {
|
if (!datalayer.system.status.BMS_reset_in_progress) {
|
||||||
lastPowerRemovalTime = currentTime; // Record the time when BMS reset was started
|
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
|
// we are now resetting at the correct time. We don't need to offset anymore
|
||||||
bmsResetTimeOffset = 0;
|
bmsResetTimeOffset = 0;
|
||||||
// Set a flag to let the rest of the system know we are cutting power to the BMS.
|
// Set a flag to let the rest of the system know we are cutting power to the BMS.
|
||||||
// The battery CAN sending routine will then know not to try guto send anything towards battery while active
|
// The battery CAN sending routine will then know not to try guto send anything towards battery while active
|
||||||
datalayer.system.status.BMS_reset_in_progress = true;
|
datalayer.system.status.BMS_reset_in_progress = true;
|
||||||
|
|
||||||
// Set emulator state to paused (Max Charge/Discharge = 0 & CAN = stop)
|
// Set emulator state to paused (Max Charge/Discharge = 0 & CAN = stop)
|
||||||
// We try to keep contactors engaged during this pause, and just ramp power down to 0.
|
// We try to keep contactors engaged during this pause, and just ramp power down to 0.
|
||||||
setBatteryPause(true, false, false, false);
|
setBatteryPause(true, false, false, false);
|
||||||
|
|
||||||
digitalWrite(BMS_POWER, LOW); // Remove power by setting the BMS power pin to LOW
|
#ifdef BMS_POWER
|
||||||
#ifdef BMS_2_POWER
|
digitalWrite(BMS_POWER, LOW); // Remove power by setting the BMS power pin to LOW
|
||||||
digitalWrite(BMS_2_POWER, LOW); // Same for battery 2
|
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef BMS_2_POWER
|
||||||
|
digitalWrite(BMS_2_POWER, LOW); // Same for battery 2
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif //defined(PERIODIC_BMS_RESET) || defined(REMOTE_BMS_RESET)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,13 @@
|
||||||
#include "../../datalayer/datalayer.h"
|
#include "../../datalayer/datalayer.h"
|
||||||
#include "../../devboard/utils/events.h"
|
#include "../../devboard/utils/events.h"
|
||||||
|
|
||||||
|
// Settings that can be changed at run-time
|
||||||
|
extern bool contactor_control_enabled;
|
||||||
|
extern bool contactor_control_enabled_double_battery;
|
||||||
|
extern bool pwm_contactor_control;
|
||||||
|
extern bool periodic_bms_reset;
|
||||||
|
extern bool remote_bms_reset;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Handle BMS power output
|
* @brief Handle BMS power output
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "comm_nvm.h"
|
#include "comm_nvm.h"
|
||||||
#include "../../include.h"
|
#include "../../include.h"
|
||||||
|
#include "../contactorcontrol/comm_contactorcontrol.h"
|
||||||
|
|
||||||
// Parameters
|
// Parameters
|
||||||
Preferences settings; // Store user settings
|
Preferences settings; // Store user settings
|
||||||
|
@ -69,6 +70,19 @@ void init_stored_settings() {
|
||||||
datalayer.battery.settings.max_user_set_discharge_voltage_dV = temp;
|
datalayer.battery.settings.max_user_set_discharge_voltage_dV = temp;
|
||||||
}
|
}
|
||||||
datalayer.battery.settings.user_set_voltage_limits_active = settings.getBool("USEVOLTLIMITS", false);
|
datalayer.battery.settings.user_set_voltage_limits_active = settings.getBool("USEVOLTLIMITS", false);
|
||||||
|
|
||||||
|
#ifdef COMMON_IMAGE
|
||||||
|
user_selected_battery_type = (BatteryType)settings.getUInt("BATTTYPE", (int)BatteryType::None);
|
||||||
|
user_selected_inverter_protocol = (InverterProtocolType)settings.getUInt("INVTYPE", (int)InverterProtocolType::None);
|
||||||
|
user_selected_charger_type = (ChargerType)settings.getUInt("CHGTYPE", (int)ChargerType::None);
|
||||||
|
user_selected_second_battery = settings.getBool("DBLBTR", false);
|
||||||
|
contactor_control_enabled = settings.getBool("CNTCTRL", false);
|
||||||
|
contactor_control_enabled_double_battery = settings.getBool("CNTCTRLDBL", false);
|
||||||
|
pwm_contactor_control = settings.getBool("PWMCNTCTRL", false);
|
||||||
|
periodic_bms_reset = settings.getBool("PERBMSRESET", false);
|
||||||
|
remote_bms_reset = settings.getBool("REMBMSRESET", false);
|
||||||
|
#endif
|
||||||
|
|
||||||
settings.end();
|
settings.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,5 +135,6 @@ void store_settings() {
|
||||||
if (!settings.putUInt("TARGETDISCHVOLT", datalayer.battery.settings.max_user_set_discharge_voltage_dV)) {
|
if (!settings.putUInt("TARGETDISCHVOLT", datalayer.battery.settings.max_user_set_discharge_voltage_dV)) {
|
||||||
set_event(EVENT_PERSISTENT_SAVE_INFO, 11);
|
set_event(EVENT_PERSISTENT_SAVE_INFO, 11);
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.end(); // Close preferences handle
|
settings.end(); // Close preferences handle
|
||||||
}
|
}
|
||||||
|
|
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