diff --git a/.github/workflows/compile-all-batteries.yml b/.github/workflows/compile-all-batteries.yml index 3e04e5d4..ae6bafb6 100644 --- a/.github/workflows/compile-all-batteries.yml +++ b/.github/workflows/compile-all-batteries.yml @@ -70,6 +70,7 @@ jobs: - RENAULT_ZOE_GEN1_BATTERY - RENAULT_ZOE_GEN2_BATTERY - SANTA_FE_PHEV_BATTERY + - STELLANTIS_ECMP_BATTERY - TESLA_MODEL_3Y_BATTERY - TESLA_MODEL_SX_BATTERY - VOLVO_SPA_BATTERY @@ -78,6 +79,10 @@ jobs: # These are the emulated inverter communication protocols for which the code will be compiled. inverter: - BYD_CAN + # These are the supported hardware platforms for which the code will be compiled. + hardware: + - HW_LILYGO + # This is the platform GitHub will use to run our workflow. runs-on: ubuntu-latest @@ -86,6 +91,10 @@ jobs: # First we clone the repo using the `checkout` action. - 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. @@ -102,4 +111,4 @@ jobs: # in the build matrix, and using build flags to define the # battery and inverter set in the build matrix. - name: Compile Sketch - run: arduino-cli compile --fqbn ${{ matrix.fqbn }} --build-property "build.extra_flags=-Wall -DESP32 -D${{ matrix.battery}} -D${{ matrix.inverter}}" ./Software + run: arduino-cli compile --fqbn ${{ matrix.fqbn }} --build-property "build.extra_flags=-Wall -DESP32 -D${{ matrix.battery}} -D${{ matrix.inverter}} -D${{ matrix.hardware}}" ./Software diff --git a/.github/workflows/compile-all-combinations-part1-batteries-A-to-M.yml b/.github/workflows/compile-all-combinations-part1-batteries-A-to-M.yml index 3fc07734..47d9a4fc 100644 --- a/.github/workflows/compile-all-combinations-part1-batteries-A-to-M.yml +++ b/.github/workflows/compile-all-combinations-part1-batteries-A-to-M.yml @@ -72,17 +72,20 @@ jobs: - BYD_CAN - BYD_KOSTAL_RS485 - BYD_MODBUS - - BYD_SMA - FOXESS_CAN - PYLON_CAN - PYLON_LV_CAN - SCHNEIDER_CAN - - SMA_CAN + - SMA_BYD_H_CAN + - SMA_BYD_HVS_CAN - SMA_LV_CAN - SMA_TRIPOWER_CAN - SOFAR_CAN - SOLAX_CAN - SERIAL_LINK_TRANSMITTER + # These are the supported hardware platforms for which the code will be compiled. + hardware: + - HW_LILYGO # This is the platform GitHub will use to run our workflow. runs-on: ubuntu-latest @@ -92,6 +95,10 @@ jobs: # First we clone the repo using the `checkout` action. - 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. @@ -108,4 +115,4 @@ jobs: # in the build matrix, and using build flags to define the # battery and inverter set in the build matrix. - name: Compile Sketch - run: arduino-cli compile --fqbn ${{ matrix.fqbn }} --build-property "build.extra_flags=-Wall -DESP32 -D${{ matrix.battery}} -D${{ matrix.inverter}}" ./Software + run: arduino-cli compile --fqbn ${{ matrix.fqbn }} --build-property "build.extra_flags=-Wall -DESP32 -D${{ matrix.battery}} -D${{ matrix.inverter}} -D${{ matrix.hardware}}" ./Software diff --git a/.github/workflows/compile-all-combinations-part2-batteries-N-to-Z.yml b/.github/workflows/compile-all-combinations-part2-batteries-N-to-Z.yml index 668f6db3..c7c5ca5a 100644 --- a/.github/workflows/compile-all-combinations-part2-batteries-N-to-Z.yml +++ b/.github/workflows/compile-all-combinations-part2-batteries-N-to-Z.yml @@ -63,6 +63,7 @@ jobs: - RENAULT_ZOE_GEN1_BATTERY - RENAULT_ZOE_GEN2_BATTERY - SANTA_FE_PHEV_BATTERY + - STELLANTIS_ECMP_BATTERY - TESLA_MODEL_3Y_BATTERY - TESLA_MODEL_SX_BATTERY - VOLVO_SPA_BATTERY @@ -73,17 +74,20 @@ jobs: - BYD_CAN - BYD_KOSTAL_RS485 - BYD_MODBUS - - BYD_SMA - FOXESS_CAN - PYLON_CAN - PYLON_LV_CAN - SCHNEIDER_CAN - - SMA_CAN + - SMA_BYD_H_CAN + - SMA_BYD_HVS_CAN - SMA_LV_CAN - SMA_TRIPOWER_CAN - SOFAR_CAN - SOLAX_CAN - SERIAL_LINK_TRANSMITTER + # These are the supported hardware platforms for which the code will be compiled. + hardware: + - HW_LILYGO # This is the platform GitHub will use to run our workflow. runs-on: ubuntu-latest @@ -93,6 +97,10 @@ jobs: # First we clone the repo using the `checkout` action. - 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. @@ -109,4 +117,4 @@ jobs: # in the build matrix, and using build flags to define the # battery and inverter set in the build matrix. - name: Compile Sketch - run: arduino-cli compile --fqbn ${{ matrix.fqbn }} --build-property "build.extra_flags=-Wall -DESP32 -D${{ matrix.battery}} -D${{ matrix.inverter}}" ./Software + run: arduino-cli compile --fqbn ${{ matrix.fqbn }} --build-property "build.extra_flags=-Wall -DESP32 -D${{ matrix.battery}} -D${{ matrix.inverter}} -D${{ matrix.hardware}}" ./Software diff --git a/.github/workflows/compile-all-hardware.yml b/.github/workflows/compile-all-hardware.yml new file mode 100644 index 00000000..473e0fb2 --- /dev/null +++ b/.github/workflows/compile-all-hardware.yml @@ -0,0 +1,93 @@ +# This is the name of the workflow, visible on GitHub UI. +name: Compile All Hardware + +# 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"]' + + # Since we use a build matrix, the actual number of jobs + # started depends on how many configurations the matrix + # will produce. + + # This is the name of the job. + build-hardware: + needs: skip-duplicate-actions + if: needs.skip-duplicate-actions.outputs.should_skip != 'true' + + # Here we tell GitHub that the jobs must be determined + # dynamically depending on a matrix configuration. + strategy: + # The matrix will produce one job for each combination of parameters. + matrix: + # This is the development board hardware for which the code will be compiled. + # FBQN stands for "fully qualified board name", and is used by Arduino to define the hardware to compile for. + fqbn: + - esp32:esp32:esp32 + # further ESP32 chips + #- esp32:esp32:esp32c3 + #- esp32:esp32:esp32c2 + #- esp32:esp32:esp32c6 + #- esp32:esp32:esp32h2 + #- esp32:esp32:esp32s3 + # These are the batteries for which the code will be compiled. + battery: + - NISSAN_LEAF_BATTERY + # These are the emulated inverter communication protocols for which the code will be compiled. + inverter: + - BYD_CAN + # These are the supported hardware platforms for which the code will be compiled. + hardware: + - HW_LILYGO + - HW_STARK + - HW_3LB + - HW_DEVKIT + + # This is the platform GitHub will use to run our workflow. + runs-on: ubuntu-latest + + # This is the list of steps this job will run. + steps: + # First we clone the repo using the `checkout` action. + - 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 + + # Finally, we compile the sketch, using the FQBN that was set + # in the build matrix, and using build flags to define the + # battery and inverter set in the build matrix. + - name: Compile Sketch + run: arduino-cli compile --fqbn ${{ matrix.fqbn }} --build-property "build.extra_flags=-Wall -DESP32 -D${{ matrix.battery}} -D${{ matrix.inverter}} -D${{ matrix.hardware}}" ./Software diff --git a/.github/workflows/compile-all-inverters.yml b/.github/workflows/compile-all-inverters.yml index 6723c803..f1b0fcf5 100644 --- a/.github/workflows/compile-all-inverters.yml +++ b/.github/workflows/compile-all-inverters.yml @@ -58,18 +58,22 @@ jobs: - BYD_CAN - BYD_KOSTAL_RS485 - BYD_MODBUS - - BYD_SMA - FOXESS_CAN - PYLON_CAN - PYLON_LV_CAN - SCHNEIDER_CAN - - SMA_CAN + - SMA_BYD_H_CAN + - SMA_BYD_HVS_CAN - SMA_LV_CAN - SMA_TRIPOWER_CAN - SOFAR_CAN - SOLAX_CAN - SERIAL_LINK_TRANSMITTER - NISSANLEAF_CHARGER # Last element is not an inverter, but good to also test if the charger compiles + # These are the supported hardware platforms for which the code will be compiled. + hardware: + - HW_LILYGO + # This is the platform GitHub will use to run our workflow. runs-on: ubuntu-latest @@ -78,6 +82,10 @@ jobs: # First we clone the repo using the `checkout` action. - 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. @@ -94,4 +102,4 @@ jobs: # in the build matrix, and using build flags to define the # battery and inverter set in the build matrix. - name: Compile Sketch - run: arduino-cli compile --fqbn ${{ matrix.fqbn }} --build-property "build.extra_flags=-Wall -DESP32 -D${{ matrix.battery}} -D${{ matrix.inverter}}" ./Software + run: arduino-cli compile --fqbn ${{ matrix.fqbn }} --build-property "build.extra_flags=-Wall -DESP32 -D${{ matrix.battery}} -D${{ matrix.inverter}} -D${{ matrix.hardware}}" ./Software diff --git a/.gitignore b/.gitignore index f4dd4582..f0e530d2 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,6 @@ compile.bat # Ignore binary files *.bin + +# Ignore secret file +USER_SECRETS.h \ No newline at end of file diff --git a/README.md b/README.md index c2d9630c..1c4e676e 100644 --- a/README.md +++ b/README.md @@ -44,17 +44,19 @@ For more examples showing wiring, see each battery types own Wiki page. For inst 3. Click `File` menu -> `Preferences` -> `Additional Development` -> `Additional Board Manager URLs` -> Enter the URL in the input box: `https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json` and click OK. 4. Click `Tools` menu -> `Board: "...."` -> `Boards Manager...`, install the `esp32` package by `Espressif Systems` (not `Arduino ESP32 Boards`), then press `Close`. -**NOTE: The version depends on which release of Battery-Emulator you are running!** +**NOTE: The ESP32 version depends on which release of Battery-Emulator you are running!** - ⚠️ Make sure to use a 2.x.x version if you are on a release **older** than 6.0.0 (For instance ESP32 v2.0.11 when using Battery-Emulator v5.4.0) -- ⚠️ Make sure to use a 3.x.x version if you are on a release **newer** than 6.0.0 (For instance ESP32 v3.0.0 when using Battery-Emulator v6.0.0) - +- ⚠️ Make sure to use a 3.0.x version if you are on a release **newer** than 6.0.0 (For instance ESP32 v3.0.0 when using Battery-Emulator v6.0.0) +- ⚠️ Make sure to use a 3.1.x version if you are on a release **newer** than 8.0.0 (For instance ESP32 v3.1.0 when using Battery-Emulator v8.0.0) + ![bild](https://github.com/dalathegreat/Battery-Emulator/assets/26695010/6a2414b1-f2ca-4746-8e8d-9afd78bd9252) 5. The Arduino board should be set to `ESP32 Dev Module` (under `Tools` -> `Board` -> `ESP32 Arduino`) with the following settings: ![alt text](https://github.com/Xinyuan-LilyGO/T-CAN485/blob/main/img/arduino_setting.png) 6. Select which battery type you will use, along with other optional settings. This is done in the `USER_SETTINGS.h` file. -7. Press `Verify` and `Upload` to send the sketch to the board. +7. Copy the `USER_SECRETS.TEMPLATE.h` file to `USER_SECRETS.h` and update connectivity settings inside this file. +8. Press `Verify` and `Upload` to send the sketch to the board. NOTE: In some cases, the LilyGo must be powered through the main power connector instead of USB-C when performing the initial firmware upload. NOTE: On Mac, the following USB driver may need to be installed: https://github.com/WCHSoftGroup/ch34xser_macos @@ -83,7 +85,7 @@ This code uses the following excellent libraries: - [eModbus/eModbus](https://github.com/eModbus/eModbus) MIT-License - [knolleary/pubsubclient](https://github.com/knolleary/pubsubclient) MIT-License - [mackelec/SerialDataLink](https://github.com/mackelec/SerialDataLink) -- [mathieucarbou/AsyncTCP](https://github.com/mathieucarbou/AsyncTCP) LGPL-3.0 license +- [me-no-dev/AsyncTCP](https://github.com/me-no-dev/AsyncTCP) LGPL-3.0 license - [me-no-dev/ESPAsyncWebServer](https://github.com/me-no-dev/ESPAsyncWebServer) - [miwagner/ESP32-Arduino-CAN](https://github.com/miwagner/ESP32-Arduino-CAN/) MIT-License - [pierremolinaro/acan2515](https://github.com/pierremolinaro/acan2515) MIT-License diff --git a/Software/Software.ino b/Software/Software.ino index 70d9c76a..015aed70 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -1,16 +1,13 @@ /* Do not change any code below this line unless you are sure what you are doing */ /* Only change battery specific settings in "USER_SETTINGS.h" */ - -#include "src/include.h" - #include "HardwareSerial.h" +#include "USER_SECRETS.h" #include "USER_SETTINGS.h" #include "esp_system.h" #include "esp_task_wdt.h" #include "esp_timer.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" -#include "src/charger/CHARGERS.h" #include "src/communication/can/comm_can.h" #include "src/communication/contactorcontrol/comm_contactorcontrol.h" #include "src/communication/equipmentstopbutton/comm_equipmentstopbutton.h" @@ -18,9 +15,12 @@ #include "src/communication/rs485/comm_rs485.h" #include "src/communication/seriallink/comm_seriallink.h" #include "src/datalayer/datalayer.h" +#include "src/devboard/sdcard/sdcard.h" #include "src/devboard/utils/events.h" #include "src/devboard/utils/led_handler.h" +#include "src/devboard/utils/logging.h" #include "src/devboard/utils/value_mapping.h" +#include "src/include.h" #include "src/lib/YiannisBourkelis-Uptime-Library/src/uptime.h" #include "src/lib/YiannisBourkelis-Uptime-Library/src/uptime_formatter.h" #include "src/lib/bblanchon-ArduinoJson/ArduinoJson.h" @@ -29,7 +29,10 @@ #include "src/lib/eModbus-eModbus/scripts/mbServerFCs.h" #include "src/lib/miwagner-ESP32-Arduino-CAN/CAN_config.h" #include "src/lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" - +#ifndef AP_PASSWORD +#error \ + "Initial setup not completed, USER_SECRETS.h is missing. Please rename the file USER_SECRETS.TEMPLATE.h to USER_SECRETS.h and fill in the required credentials. This file is ignored by version control to keep sensitive information private." +#endif #ifdef WIFI #include "src/devboard/wifi/wifi.h" #ifdef WEBSERVER @@ -77,12 +80,18 @@ MyTimer core_task_timer_10s(INTERVAL_10_S); int64_t connectivity_task_time_us; MyTimer connectivity_task_timer_10s(INTERVAL_10_S); +int64_t logging_task_time_us; +MyTimer logging_task_timer_10s(INTERVAL_10_S); + MyTimer loop_task_timer_10s(INTERVAL_10_S); MyTimer check_pause_2s(INTERVAL_2_S); TaskHandle_t main_loop_task; TaskHandle_t connectivity_loop_task; +TaskHandle_t logging_loop_task; + +Logging logging; // Initialization void setup() { @@ -95,6 +104,11 @@ void setup() { TASK_CONNECTIVITY_PRIO, &connectivity_loop_task, WIFI_CORE); #endif +#ifdef LOG_CAN_TO_SD + xTaskCreatePinnedToCore((TaskFunction_t)&logging_loop, "logging_loop", 4096, &logging_task_time_us, + TASK_CONNECTIVITY_PRIO, &logging_loop_task, WIFI_CORE); +#endif + init_events(); init_CAN(); @@ -137,6 +151,18 @@ void loop() { #endif } +#ifdef LOG_CAN_TO_SD +void logging_loop(void* task_time_us) { + + init_logging_buffer(); + init_sdcard(); + + while (true) { + write_can_frame_to_sdcard(); + } +} +#endif + #ifdef WIFI void connectivity_loop(void* task_time_us) { @@ -191,13 +217,7 @@ void core_loop(void* task_time_us) { #endif // Input, Runs as fast as possible - receive_can_native(); // Receive CAN messages from native CAN port -#ifdef CANFD_ADDON - receive_canfd_addon(); // Receive CAN-FD messages. -#endif // CANFD_ADDON -#ifdef CAN_ADDON - receive_can_addon(); // Receive CAN messages on add-on MCP2515 chip -#endif // CAN_ADDON + receive_can(); // Receive CAN messages #ifdef RS485_INVERTER_SELECTED receive_RS485(); // Process serial2 RS485 interface #endif // RS485_INVERTER_SELECTED @@ -233,15 +253,12 @@ void core_loop(void* task_time_us) { update_machineryprotection(); // Check safeties (Not on serial link reciever board) #endif // SERIAL_LINK_RECEIVER update_values_inverter(); // Update values heading towards inverter - if (DUMMY_EVENT_ENABLED) { - set_event(EVENT_DUMMY_ERROR, (uint8_t)millis()); - } } END_TIME_MEASUREMENT_MAX(time_values, datalayer.system.status.time_values_us); START_TIME_MEASUREMENT(cantx); // Output - send_can(); // Send CAN messages to all components + transmit_can(); // Send CAN messages to all components END_TIME_MEASUREMENT_MAX(cantx, datalayer.system.status.time_cantx_us); END_TIME_MEASUREMENT_MAX(all, datalayer.system.status.core_task_10s_max_us); @@ -269,7 +286,7 @@ void core_loop(void* task_time_us) { } #endif // FUNCTION_TIME_MEASUREMENT if (check_pause_2s.elapsed()) { - emulator_pause_state_send_CAN_battery(); + emulator_pause_state_transmit_can_battery(); } vTaskDelayUntil(&xLastWakeTime, xFrequency); diff --git a/Software/USER_SECRETS.TEMPLATE.h b/Software/USER_SECRETS.TEMPLATE.h new file mode 100644 index 00000000..1cd013b9 --- /dev/null +++ b/Software/USER_SECRETS.TEMPLATE.h @@ -0,0 +1,20 @@ +/* This file should be renamed to USER_SECRETS.h to be able to use the software! +It contains all the credentials that should never be made public */ + +//Password to the access point generated by the Battery-Emulator +#define AP_PASSWORD "123456789" // Minimum of 8 characters; set to blank if you want the access point to be open + +//Name and password of Wifi network you want the emulator to connect to +#define WIFI_SSID "REPLACE_WITH_YOUR_SSID" // Maximum of 63 characters +#define WIFI_PASSWORD "REPLACE_WITH_YOUR_PASSWORD" // Minimum of 8 characters + +//Set WEBSERVER_AUTH_REQUIRED to true to require a password when accessing the webserver homepage. Improves cybersecurity. +#define WEBSERVER_AUTH_REQUIRED false +#define HTTP_USERNAME "admin" // Username for webserver authentication +#define HTTP_PASSWORD "admin" // Password for webserver authentication + +//MQTT credentials +#define MQTT_SERVER "192.168.xxx.yyy" // MQTT server address +#define MQTT_PORT 1883 // MQTT server port +#define MQTT_USER NULL // MQTT username, leave blank for no authentication +#define MQTT_PASSWORD NULL // MQTT password, leave blank for no authentication diff --git a/Software/USER_SETTINGS.cpp b/Software/USER_SETTINGS.cpp index 1dd5a0ec..7b1fb064 100644 --- a/Software/USER_SETTINGS.cpp +++ b/Software/USER_SETTINGS.cpp @@ -1,5 +1,6 @@ #include "USER_SETTINGS.h" #include +#include "USER_SECRETS.h" #include "src/devboard/hal/hal.h" /* This file contains all the battery settings and limits */ @@ -16,36 +17,29 @@ volatile CAN_Configuration can_config = { .battery = CAN_NATIVE, // Which CAN is your battery connected to? .inverter = CAN_NATIVE, // Which CAN is your inverter connected to? (No need to configure incase you use RS485) .battery_double = CAN_ADDON_MCP2515, // (OPTIONAL) Which CAN is your second battery connected to? - .charger = CAN_NATIVE, // (OPTIONAL) Which CAN is your charger connected to? - .shunt = CAN_NATIVE // (OPTIONAL) Which CAN is your charger connected to? + .charger = CAN_NATIVE, // (OPTIONAL) Which CAN is your charger connected to? + .shunt = CAN_NATIVE // (OPTIONAL) Which CAN is your charger connected to? }; -#ifdef WIFI - -volatile uint8_t AccessPointEnabled = true; //Set to either true/false to enable direct wifi access point -std::string ssid = "REPLACE_WITH_YOUR_SSID"; // Maximum of 63 characters -std::string password = "REPLACE_WITH_YOUR_PASSWORD"; // Minimum of 8 characters +std::string ssid = WIFI_SSID; // Set in USER_SECRETS.h +std::string password = WIFI_PASSWORD; // Set in USER_SECRETS.h const char* ssidAP = "Battery Emulator"; // Maximum of 63 characters, also used for device name on web interface -const char* passwordAP = "123456789"; // Minimum of 8 characters; set to NULL if you want the access point to be open -const uint8_t wifi_channel = 0; // Set to 0 for automatic channel selection +const char* passwordAP = AP_PASSWORD; // Set in USER_SECRETS.h +const uint8_t wifi_channel = 0; // Set to 0 for automatic channel selection -#ifdef WIFICONFIG -// Set your Static IP address -IPAddress local_IP(192, 168, 10, 150); -// Set your Gateway IP address -IPAddress gateway(192, 168, 10, 1); -// Set your Subnet IP address -IPAddress subnet(255, 255, 255, 0); -#endif #ifdef WEBSERVER -const char* http_username = "admin"; // username to webserver authentication; -const char* http_password = "admin"; // password to webserver authentication; - +const char* http_username = HTTP_USERNAME; // Set in USER_SECRETS.h +const char* http_password = HTTP_PASSWORD; // Set in USER_SECRETS.h +// Set your Static IP address. Only used incase WIFICONFIG is set in USER_SETTINGS.h +IPAddress local_IP(192, 168, 10, 150); +IPAddress gateway(192, 168, 10, 1); +IPAddress subnet(255, 255, 255, 0); #endif // WEBSERVER + // MQTT #ifdef MQTT -const char* mqtt_user = "REDACTED"; // Set NULL for no username -const char* mqtt_password = "REDACTED"; // Set NULL for no password +const char* mqtt_user = MQTT_USER; // Set in USER_SECRETS.h +const char* mqtt_password = MQTT_PASSWORD; // Set in USER_SECRETS.h #ifdef MQTT_MANUAL_TOPIC_OBJECT_NAME const char* mqtt_topic_name = "BE"; // Custom MQTT topic name. Previously, the name was automatically set to "battery-emulator_esp32-XXXXXX" @@ -55,7 +49,6 @@ const char* mqtt_device_name = "Battery Emulator"; // Custom device name in Home Assistant. Previously, the name was automatically set to "BatteryEmulator_esp32-XXXXXX" #endif // MQTT_MANUAL_TOPIC_OBJECT_NAME #endif // USE_MQTT -#endif // WIFI #ifdef EQUIPMENT_STOP_BUTTON // Equipment stop button behavior. Use NC button for safety reasons. diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 4161d871..0d60bdd0 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -11,6 +11,7 @@ /* Select battery used */ //#define BMW_I3_BATTERY //#define BMW_IX_BATTERY +//#define BOLT_AMPERA_BATTERY //#define BYD_ATTO_3_BATTERY //#define CELLPOWER_BMS //#define CHADEMO_BATTERY //NOTE: inherently enables CONTACTOR_CONTROL below @@ -30,6 +31,7 @@ //#define RENAULT_ZOE_GEN1_BATTERY //#define RENAULT_ZOE_GEN2_BATTERY //#define SANTA_FE_PHEV_BATTERY +//#define STELLANTIS_ECMP_BATTERY //#define TESLA_MODEL_3Y_BATTERY //#define TESLA_MODEL_SX_BATTERY //#define VOLVO_SPA_BATTERY @@ -41,21 +43,22 @@ //#define BYD_CAN //Enable this line to emulate a "BYD Battery-Box Premium HVS" over CAN Bus //#define BYD_KOSTAL_RS485 //Enable this line to emulate a "BYD 11kWh HVM battery" over Kostal RS485 //#define BYD_MODBUS //Enable this line to emulate a "BYD 11kWh HVM battery" over Modbus RTU -//#define BYD_SMA //Enable this line to emulate a SMA compatible "BYD Battery-Box HVS 10.2KW battery" over CAN bus //#define FOXESS_CAN //Enable this line to emulate a "HV2600/ECS4100 battery" over CAN bus //#define PYLON_LV_CAN //Enable this line to emulate a "48V Pylontech battery" over CAN bus //#define PYLON_CAN //Enable this line to emulate a "High Voltage Pylontech battery" over CAN bus //#define SCHNEIDER_CAN //Enable this line to emulate a "Schneider Version 2: SE BMS" over CAN bus -//#define SMA_CAN //Enable this line to emulate a "BYD Battery-Box H 8.9kWh, 7 mod" over CAN bus +//#define SMA_BYD_H_CAN //Enable this line to emulate a "BYD Battery-Box H 8.9kWh, 7 mod" (SMA compatible) over CAN bus +//#define SMA_BYD_HVS_CAN //Enable this line to emulate a "BYD Battery-Box HVS 10.2KW battery" (SMA compatible) over CAN bus //#define SMA_LV_CAN //Enable this line to emulate a "SMA Sunny Island 48V battery" over CAN bus //#define SMA_TRIPOWER_CAN //Enable this line to emulate a "SMA Home Storage battery" over CAN bus //#define SOFAR_CAN //Enable this line to emulate a "Sofar Energy Storage Inverter High Voltage BMS General Protocol (Extended Frame)" over CAN bus //#define SOLAX_CAN //Enable this line to emulate a "SolaX Triple Power LFP" over CAN bus /* Select hardware used for Battery-Emulator */ -#define HW_LILYGO +//#define HW_LILYGO //#define HW_STARK //#define HW_3LB +//#define HW_DEVKIT /* Contactor settings. If you have a battery that does not activate contactors via CAN, configure this section */ #define PRECHARGE_TIME_MS 500 //Precharge time in milliseconds. Modify to suit your inverter (See wiki for more info) @@ -65,38 +68,37 @@ //#define NC_CONTACTORS //Enable this line to control normally closed contactors. CONTACTOR_CONTROL must be enabled for this option. Extremely rare setting! /* Shunt/Contactor settings */ -//#define BMW_SBOX // SBOX relay control & battery current/voltage measurement +//#define BMW_SBOX // SBOX relay control & battery current/voltage measurement /* Other options */ //#define DEBUG_VIA_USB //Enable this line to have the USB port output serial diagnostic data while program runs (WARNING, raises CPU load, do not use for production) +//#define DEBUG_VIA_WEB //Enable this line to log diagnostic data while program runs, which can be viewed via webpage (WARNING, slightly raises CPU load, do not use for production) +#if defined(DEBUG_VIA_USB) || defined(DEBUG_VIA_WEB) +#define DEBUG_LOG +#endif + //#define DEBUG_CAN_DATA //Enable this line to print incoming/outgoing CAN & CAN-FD messages to USB serial (WARNING, raises CPU load, do not use for production) +//#define LOG_CAN_TO_SD //Enable this line to log incoming/outgoing CAN & CAN-FD messages to SD card //#define INTERLOCK_REQUIRED //Nissan LEAF specific setting, if enabled requires both high voltage conenctors to be seated before starting //#define CAN_ADDON //Enable this line to activate an isolated secondary CAN Bus using add-on MCP2515 chip (Needed for some inverters / double battery) #define CRYSTAL_FREQUENCY_MHZ 8 //CAN_ADDON option, what is your MCP2515 add-on boards crystal frequency? //#define CANFD_ADDON //Enable this line to activate an isolated secondary CAN-FD bus using add-on MCP2518FD chip / Native CANFD on Stark board -#ifdef CANFD_ADDON // CANFD_ADDON additional options if enabled #define CANFD_ADDON_CRYSTAL_FREQUENCY_MHZ \ - ACAN2517FDSettings:: \ - OSC_40MHz //CANFD_ADDON option, what is your MCP2518 add-on boards crystal frequency? (Default OSC_40MHz) -#endif // CANFD_ADDON + ACAN2517FDSettings::OSC_40MHz //CANFD_ADDON option, what is your MCP2518 add-on boards crystal frequency? //#define USE_CANFD_INTERFACE_AS_CLASSIC_CAN // Enable this line if you intend to use the CANFD as normal CAN //#define SERIAL_LINK_RECEIVER //Enable this line to receive battery data over RS485 pins from another Lilygo (This LilyGo interfaces with inverter) //#define SERIAL_LINK_TRANSMITTER //Enable this line to send battery data over RS485 pins to another Lilygo (This LilyGo interfaces with battery) #define WIFI //#define WIFICONFIG //Enable this line to set a static IP address / gateway /subnet mask for the device. see USER_SETTINGS.cpp for the settings #define WEBSERVER //Enable this line to enable WiFi, and to run the webserver. See USER_SETTINGS.cpp for the Wifi settings. -#define WEBSERVER_AUTH_REQUIRED \ - false //Set this line to true to activate webserver authentication (this line must not be commented). Refer to USER_SETTINGS.cpp for setting the credentials. -#define WIFIAP //Disable this line to permanently disable WIFI AP mode (make sure to hardcode ssid and password of you home wifi network). When enabled WIFI AP can still be disabled by a setting in the future. +#define WIFIAP //When enabled, the emulator will broadcast its own access point Wifi. Can be used at the same time as a normal Wifi connection to a router. #define MDNSRESPONDER //Enable this line to enable MDNS, allows battery monitor te be found by .local address. Requires WEBSERVER to be enabled. -#define LOAD_SAVED_SETTINGS_ON_BOOT //Enable this line to read settings stored via the webserver on boot (overrides Wifi/battery settings set below) +#define LOAD_SAVED_SETTINGS_ON_BOOT // Enable this line to read settings stored via the webserver on boot (overrides Wifi credentials set here) //#define FUNCTION_TIME_MEASUREMENT // Enable this to record execution times and present them in the web UI (WARNING, raises CPU load, do not use for production) //#define EQUIPMENT_STOP_BUTTON // Enable this to allow an equipment stop button connected to the Battery-Emulator to disengage the battery /* MQTT options */ // #define MQTT // Enable this line to enable MQTT -#define MQTT_SERVER "192.168.xxx.yyy" -#define MQTT_PORT 1883 #define MQTT_MANUAL_TOPIC_OBJECT_NAME // Enable this to use custom MQTT topic, object ID prefix, and device name. \ // WARNING: If this is not defined, the previous default naming format \ // 'battery-emulator_esp32-XXXXXX' (based on hardware ID) will be used. \ @@ -108,9 +110,6 @@ /* Home Assistant options */ #define HA_AUTODISCOVERY // Enable this line to send Home Assistant autodiscovery messages. If not enabled manual configuration of Home Assitant is required -/* Event options*/ -#define DUMMY_EVENT_ENABLED false //Enable this line to have a dummy event that gets logged to test the interface - /* Select charger used (Optional) */ //#define CHEVYVOLT_CHARGER //Enable this line to control a Chevrolet Volt charger connected to battery - for example, when generator charging or using an inverter without a charging function. //#define NISSANLEAF_CHARGER //Enable this line to control a Nissan LEAF PDM connected to battery - for example, when generator charging @@ -139,8 +138,8 @@ // 3000 = 300.0V, Target discharge voltage (Value can be tuned on the fly via webserver). Not used unless BATTERY_USE_VOLTAGE_LIMITS = true #define BATTERY_MAX_DISCHARGE_VOLTAGE 3000 -/* Do not change any code below this line unless you are sure what you are doing */ -/* Only change battery specific settings in "USER_SETTINGS.h" */ +/* Do not change any code below this line */ +/* 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 { CAN_Interface battery; @@ -171,9 +170,7 @@ extern volatile STOP_BUTTON_BEHAVIOR equipment_stop_behavior; #ifdef WIFICONFIG extern IPAddress local_IP; -// Set your Gateway IP address extern IPAddress gateway; -// Set your Subnet IP address extern IPAddress subnet; #endif diff --git a/Software/src/battery/BATTERIES.h b/Software/src/battery/BATTERIES.h index 9f5fe8f3..c72c3f34 100644 --- a/Software/src/battery/BATTERIES.h +++ b/Software/src/battery/BATTERIES.h @@ -4,8 +4,8 @@ #ifdef BMW_SBOX #include "BMW-SBOX.h" -void receive_can_shunt(CAN_frame rx_frame); -void send_can_shunt(); +void map_can_frame_to_variable_shunt(CAN_frame rx_frame); +void transmit_can_shunt(); void setup_can_shunt(); #endif @@ -17,6 +17,10 @@ void setup_can_shunt(); #include "BMW-IX-BATTERY.h" #endif +#ifdef BOLT_AMPERA_BATTERY +#include "BOLT-AMPERA-BATTERY.h" +#endif + #ifdef BYD_ATTO_3_BATTERY #include "BYD-ATTO-3-BATTERY.h" #endif @@ -30,6 +34,10 @@ void setup_can_shunt(); #include "CHADEMO-SHUNTS.h" #endif +#ifdef STELLANTIS_ECMP_BATTERY +#include "ECMP-BATTERY.h" +#endif + #ifdef IMIEV_CZERO_ION_BATTERY #include "IMIEV-CZERO-ION-BATTERY.h" #endif @@ -111,14 +119,14 @@ void setup_can_shunt(); #include "SERIAL-LINK-RECEIVER-FROM-BATTERY.h" #endif -void receive_can_battery(CAN_frame rx_frame); +void handle_incoming_can_frame_battery(CAN_frame rx_frame); void update_values_battery(); -void send_can_battery(); +void transmit_can_battery(); void setup_battery(void); #ifdef DOUBLE_BATTERY void update_values_battery2(); -void receive_can_battery2(CAN_frame rx_frame); +void handle_incoming_can_frame_battery2(CAN_frame rx_frame); #endif #endif diff --git a/Software/src/battery/BMW-I3-BATTERY.cpp b/Software/src/battery/BMW-I3-BATTERY.cpp index cf535f5f..55bc2b97 100644 --- a/Software/src/battery/BMW-I3-BATTERY.cpp +++ b/Software/src/battery/BMW-I3-BATTERY.cpp @@ -19,6 +19,7 @@ static unsigned long previousMillis10000 = 0; // will store last time a 10000ms enum BatterySize { BATTERY_60AH, BATTERY_94AH, BATTERY_120AH }; static BatterySize detectedBattery = BATTERY_60AH; +static BatterySize detectedBattery2 = BATTERY_60AH; // For double battery setups enum CmdState { SOH, CELL_VOLTAGE_MINMAX, SOC, CELL_VOLTAGE_CELLNO, CELL_VOLTAGE_CELLNO_LAST }; @@ -269,7 +270,6 @@ static uint8_t battery_status_diagnostics_HV = 0; // 0 all OK, 1 HV protection static uint8_t battery_status_diagnosis_powertrain_maximum_multiplexer = 0; static uint8_t battery_status_diagnosis_powertrain_immediate_multiplexer = 0; static uint8_t battery_ID2 = 0; -static uint8_t battery_cellvoltage_mux = 0; static uint8_t battery_soh = 99; static uint32_t battery2_serial_number = 0; @@ -337,7 +337,6 @@ static uint8_t battery2_status_diagnostics_HV = 0; // 0 all OK, 1 HV protection static uint8_t battery2_status_diagnosis_powertrain_maximum_multiplexer = 0; static uint8_t battery2_status_diagnosis_powertrain_immediate_multiplexer = 0; static uint8_t battery2_ID2 = 0; -static uint8_t battery2_cellvoltage_mux = 0; static uint8_t battery2_soh = 99; static uint8_t message_data[50]; @@ -392,12 +391,12 @@ void update_values_battery2() { //This function maps all the values fetched via if (battery2_info_available) { // Start checking safeties. First up, cellvoltages! - if (detectedBattery == BATTERY_60AH) { + if (detectedBattery2 == BATTERY_60AH) { datalayer.battery2.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_60AH; datalayer.battery2.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_60AH; datalayer.battery2.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_60AH; datalayer.battery2.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_60AH; - } else if (detectedBattery == BATTERY_94AH) { + } else if (detectedBattery2 == BATTERY_94AH) { datalayer.battery2.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_94AH; datalayer.battery2.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_94AH; datalayer.battery2.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_94AH; @@ -425,9 +424,15 @@ void update_values_battery2() { //This function maps all the values fetched via void update_values_battery() { //This function maps all the values fetched via CAN to the battery datalayer if (datalayer.system.settings.equipment_stop_active == true) { - digitalWrite(WUP_PIN, LOW); // Turn off WUP_PIN + digitalWrite(WUP_PIN1, LOW); // Turn off WUP_PIN1 +#if defined(WUP_PIN2) && defined(DOUBLE_BATTERY) + digitalWrite(WUP_PIN2, LOW); // Turn off WUP_PIN2 +#endif // defined(WUP_PIN2) && defined (DOUBLE_BATTERY) } else { - digitalWrite(WUP_PIN, HIGH); // Wake up the battery + digitalWrite(WUP_PIN1, HIGH); // Wake up the battery +#if defined(WUP_PIN2) && defined(DOUBLE_BATTERY) + digitalWrite(WUP_PIN2, HIGH); // Wake up the battery2 +#endif // defined(WUP_PIN2) && defined (DOUBLE_BATTERY) } if (!battery_awake) { @@ -502,7 +507,7 @@ void update_values_battery() { //This function maps all the values fetched via datalayer_extended.bmwi3.ST_cold_shutoff_valve = battery_status_cold_shutoff_valve; } -void receive_can_battery(CAN_frame rx_frame) { +void handle_incoming_can_frame_battery(CAN_frame rx_frame) { switch (rx_frame.ID) { case 0x112: //BMS [10ms] Status Of High-Voltage Battery - 2 battery_awake = true; @@ -632,7 +637,7 @@ void receive_can_battery(CAN_frame rx_frame) { case 0x607: //BMS - responses to message requests on 0x615 if ((cmdState == CELL_VOLTAGE_CELLNO || cmdState == CELL_VOLTAGE_CELLNO_LAST) && (rx_frame.data.u8[0] == 0xF4)) { if (rx_frame.DLC == 6) { - transmit_can(&BMW_6F4_CELL_CONTINUE, can_config.battery); // tell battery to send the cellvoltage + transmit_can_frame(&BMW_6F4_CELL_CONTINUE, can_config.battery); // tell battery to send the cellvoltage } if (rx_frame.DLC == 8) { // We have the full value, map it datalayer.battery.status.cell_voltages_mV[current_cell_polled - 1] = @@ -645,7 +650,7 @@ void receive_can_battery(CAN_frame rx_frame) { while (count < rx_frame.DLC && next_data < 49) { message_data[next_data++] = rx_frame.data.u8[count++]; } - transmit_can(&BMW_6F1_CONTINUE, can_config.battery); // tell battery to send additional messages + transmit_can_frame(&BMW_6F1_CONTINUE, can_config.battery); // tell battery to send additional messages } else if (rx_frame.DLC > 3 && next_data > 0 && rx_frame.data.u8[0] == 0xf1 && ((rx_frame.data.u8[1] & 0xF0) == 0x20)) { @@ -681,7 +686,7 @@ void receive_can_battery(CAN_frame rx_frame) { break; } } -void receive_can_battery2(CAN_frame rx_frame) { +void handle_incoming_can_frame_battery2(CAN_frame rx_frame) { switch (rx_frame.ID) { case 0x112: //BMS [10ms] Status Of High-Voltage Battery - 2 battery2_awake = true; @@ -776,18 +781,6 @@ void receive_can_battery2(CAN_frame rx_frame) { case 0x41C: //BMS [1s] Operating Mode Status Of Hybrid - 2 battery2_status_cooling_HV = (rx_frame.data.u8[1] & 0x03); break; - case 0x426: // TODO: Figure out how to trigger sending of this. Does the SME require some CAN command? - battery2_cellvoltage_mux = rx_frame.data.u8[0]; - if (battery2_cellvoltage_mux == 0) { - datalayer.battery2.status.cell_voltages_mV[0] = ((rx_frame.data.u8[1] * 10) + 1800); - datalayer.battery2.status.cell_voltages_mV[1] = ((rx_frame.data.u8[2] * 10) + 1800); - datalayer.battery2.status.cell_voltages_mV[2] = ((rx_frame.data.u8[3] * 10) + 1800); - datalayer.battery2.status.cell_voltages_mV[3] = ((rx_frame.data.u8[4] * 10) + 1800); - datalayer.battery2.status.cell_voltages_mV[4] = ((rx_frame.data.u8[5] * 10) + 1800); - datalayer.battery2.status.cell_voltages_mV[5] = ((rx_frame.data.u8[6] * 10) + 1800); - datalayer.battery2.status.cell_voltages_mV[6] = ((rx_frame.data.u8[7] * 10) + 1800); - } - break; case 0x430: //BMS [1s] - Charging status of high-voltage battery - 2 battery2_prediction_voltage_shortterm_charge = (rx_frame.data.u8[1] << 8 | rx_frame.data.u8[0]); battery2_prediction_voltage_shortterm_discharge = (rx_frame.data.u8[3] << 8 | rx_frame.data.u8[2]); @@ -801,6 +794,13 @@ void receive_can_battery2(CAN_frame rx_frame) { battery2_prediction_duration_charging_minutes = (rx_frame.data.u8[3] << 8 | rx_frame.data.u8[2]); battery2_prediction_time_end_of_charging_minutes = rx_frame.data.u8[4]; battery2_energy_content_maximum_kWh = (((rx_frame.data.u8[6] & 0x0F) << 8 | rx_frame.data.u8[5])) / 50; + if (battery2_energy_content_maximum_kWh > 33) { + detectedBattery2 = BATTERY_120AH; + } else if (battery2_energy_content_maximum_kWh > 20) { + detectedBattery2 = BATTERY_94AH; + } else { + detectedBattery2 = BATTERY_60AH; + } break; case 0x432: //BMS [200ms] SOC% info battery2_request_operating_mode = (rx_frame.data.u8[0] & 0x03); @@ -815,12 +815,23 @@ void receive_can_battery2(CAN_frame rx_frame) { battery2_ID2 = rx_frame.data.u8[0]; break; case 0x607: //BMS - responses to message requests on 0x615 + if ((cmdState == CELL_VOLTAGE_CELLNO || cmdState == CELL_VOLTAGE_CELLNO_LAST) && (rx_frame.data.u8[0] == 0xF4)) { + if (rx_frame.DLC == 6) { + transmit_can_frame(&BMW_6F4_CELL_CONTINUE, + can_config.battery_double); // tell battery to send the cellvoltage + } + if (rx_frame.DLC == 8) { // We have the full value, map it + datalayer.battery2.status.cell_voltages_mV[current_cell_polled - 1] = + (rx_frame.data.u8[6] << 8 | rx_frame.data.u8[7]); + } + } + if (rx_frame.DLC > 6 && next_data == 0 && rx_frame.data.u8[0] == 0xf1) { uint8_t count2 = 6; while (count2 < rx_frame.DLC && next_data < 49) { message_data[next_data++] = rx_frame.data.u8[count2++]; } - transmit_can(&BMW_6F1_CONTINUE, can_config.battery_double); + transmit_can_frame(&BMW_6F1_CONTINUE, can_config.battery_double); } else if (rx_frame.DLC > 3 && next_data > 0 && rx_frame.data.u8[0] == 0xf1 && ((rx_frame.data.u8[1] & 0xF0) == 0x20)) { @@ -856,7 +867,7 @@ void receive_can_battery2(CAN_frame rx_frame) { break; } } -void send_can_battery() { +void transmit_can_battery() { unsigned long currentMillis = millis(); if (battery_awake) { @@ -887,12 +898,12 @@ void send_can_battery() { if (datalayer.battery.status.bms_status == FAULT) { } //If battery is not in Fault mode, allow contactor to close by sending 10B else { - transmit_can(&BMW_10B, can_config.battery); + transmit_can_frame(&BMW_10B, can_config.battery); } #ifdef DOUBLE_BATTERY //If second battery is allowed to join in, also send 10B if (datalayer.system.status.battery2_allows_contactor_closing == true) { - transmit_can(&BMW_10B, can_config.battery_double); + transmit_can_frame(&BMW_10B, can_config.battery_double); } #endif } @@ -905,9 +916,9 @@ void send_can_battery() { alive_counter_100ms = increment_alive_counter(alive_counter_100ms); - transmit_can(&BMW_12F, can_config.battery); + transmit_can_frame(&BMW_12F, can_config.battery); #ifdef DOUBLE_BATTERY - transmit_can(&BMW_12F, can_config.battery_double); + transmit_can_frame(&BMW_12F, can_config.battery_double); #endif } // Send 200ms CAN Message @@ -919,9 +930,9 @@ void send_can_battery() { alive_counter_200ms = increment_alive_counter(alive_counter_200ms); - transmit_can(&BMW_19B, can_config.battery); + transmit_can_frame(&BMW_19B, can_config.battery); #ifdef DOUBLE_BATTERY - transmit_can(&BMW_19B, can_config.battery_double); + transmit_can_frame(&BMW_19B, can_config.battery_double); #endif } // Send 500ms CAN Message @@ -933,20 +944,20 @@ void send_can_battery() { alive_counter_500ms = increment_alive_counter(alive_counter_500ms); - transmit_can(&BMW_30B, can_config.battery); + transmit_can_frame(&BMW_30B, can_config.battery); #ifdef DOUBLE_BATTERY - transmit_can(&BMW_30B, can_config.battery_double); + transmit_can_frame(&BMW_30B, can_config.battery_double); #endif } // Send 640ms CAN Message if (currentMillis - previousMillis640 >= INTERVAL_640_MS) { previousMillis640 = currentMillis; - transmit_can(&BMW_512, can_config.battery); // Keep BMS alive - transmit_can(&BMW_5F8, can_config.battery); + transmit_can_frame(&BMW_512, can_config.battery); // Keep BMS alive + transmit_can_frame(&BMW_5F8, can_config.battery); #ifdef DOUBLE_BATTERY - transmit_can(&BMW_512, can_config.battery_double); - transmit_can(&BMW_5F8, can_config.battery_double); + transmit_can_frame(&BMW_512, can_config.battery_double); + transmit_can_frame(&BMW_5F8, can_config.battery_double); #endif } // Send 1000ms CAN Message @@ -973,39 +984,39 @@ void send_can_battery() { alive_counter_1000ms = increment_alive_counter(alive_counter_1000ms); - transmit_can(&BMW_3E8, can_config.battery); //Order comes from CAN logs - transmit_can(&BMW_328, can_config.battery); - transmit_can(&BMW_3F9, can_config.battery); - transmit_can(&BMW_2E2, can_config.battery); - transmit_can(&BMW_41D, can_config.battery); - transmit_can(&BMW_3D0, can_config.battery); - transmit_can(&BMW_3CA, can_config.battery); - transmit_can(&BMW_3A7, can_config.battery); - transmit_can(&BMW_2CA, can_config.battery); - transmit_can(&BMW_3FB, can_config.battery); - transmit_can(&BMW_418, can_config.battery); - transmit_can(&BMW_1D0, can_config.battery); - transmit_can(&BMW_3EC, can_config.battery); - transmit_can(&BMW_192, can_config.battery); - transmit_can(&BMW_13E, can_config.battery); - transmit_can(&BMW_433, can_config.battery); + transmit_can_frame(&BMW_3E8, can_config.battery); //Order comes from CAN logs + transmit_can_frame(&BMW_328, can_config.battery); + transmit_can_frame(&BMW_3F9, can_config.battery); + transmit_can_frame(&BMW_2E2, can_config.battery); + transmit_can_frame(&BMW_41D, can_config.battery); + transmit_can_frame(&BMW_3D0, can_config.battery); + transmit_can_frame(&BMW_3CA, can_config.battery); + transmit_can_frame(&BMW_3A7, can_config.battery); + transmit_can_frame(&BMW_2CA, can_config.battery); + transmit_can_frame(&BMW_3FB, can_config.battery); + transmit_can_frame(&BMW_418, can_config.battery); + transmit_can_frame(&BMW_1D0, can_config.battery); + transmit_can_frame(&BMW_3EC, can_config.battery); + transmit_can_frame(&BMW_192, can_config.battery); + transmit_can_frame(&BMW_13E, can_config.battery); + transmit_can_frame(&BMW_433, can_config.battery); #ifdef DOUBLE_BATTERY - transmit_can(&BMW_3E8, can_config.battery_double); - transmit_can(&BMW_328, can_config.battery_double); - transmit_can(&BMW_3F9, can_config.battery_double); - transmit_can(&BMW_2E2, can_config.battery_double); - transmit_can(&BMW_41D, can_config.battery_double); - transmit_can(&BMW_3D0, can_config.battery_double); - transmit_can(&BMW_3CA, can_config.battery_double); - transmit_can(&BMW_3A7, can_config.battery_double); - transmit_can(&BMW_2CA, can_config.battery_double); - transmit_can(&BMW_3FB, can_config.battery_double); - transmit_can(&BMW_418, can_config.battery_double); - transmit_can(&BMW_1D0, can_config.battery_double); - transmit_can(&BMW_3EC, can_config.battery_double); - transmit_can(&BMW_192, can_config.battery_double); - transmit_can(&BMW_13E, can_config.battery_double); - transmit_can(&BMW_433, can_config.battery_double); + transmit_can_frame(&BMW_3E8, can_config.battery_double); + transmit_can_frame(&BMW_328, can_config.battery_double); + transmit_can_frame(&BMW_3F9, can_config.battery_double); + transmit_can_frame(&BMW_2E2, can_config.battery_double); + transmit_can_frame(&BMW_41D, can_config.battery_double); + transmit_can_frame(&BMW_3D0, can_config.battery_double); + transmit_can_frame(&BMW_3CA, can_config.battery_double); + transmit_can_frame(&BMW_3A7, can_config.battery_double); + transmit_can_frame(&BMW_2CA, can_config.battery_double); + transmit_can_frame(&BMW_3FB, can_config.battery_double); + transmit_can_frame(&BMW_418, can_config.battery_double); + transmit_can_frame(&BMW_1D0, can_config.battery_double); + transmit_can_frame(&BMW_3EC, can_config.battery_double); + transmit_can_frame(&BMW_192, can_config.battery_double); + transmit_can_frame(&BMW_13E, can_config.battery_double); + transmit_can_frame(&BMW_433, can_config.battery_double); #endif BMW_433.data.u8[1] = 0x01; // First 433 message byte1 we send is unique, once we sent initial value send this @@ -1014,23 +1025,23 @@ void send_can_battery() { next_data = 0; switch (cmdState) { case SOC: - transmit_can(&BMW_6F1_CELL, can_config.battery); + transmit_can_frame(&BMW_6F1_CELL, can_config.battery); #ifdef DOUBLE_BATTERY - transmit_can(&BMW_6F1_CELL, can_config.battery_double); + transmit_can_frame(&BMW_6F1_CELL, can_config.battery_double); #endif cmdState = CELL_VOLTAGE_MINMAX; break; case CELL_VOLTAGE_MINMAX: - transmit_can(&BMW_6F1_SOH, can_config.battery); + transmit_can_frame(&BMW_6F1_SOH, can_config.battery); #ifdef DOUBLE_BATTERY - transmit_can(&BMW_6F1_SOH, can_config.battery_double); + transmit_can_frame(&BMW_6F1_SOH, can_config.battery_double); #endif cmdState = SOH; break; case SOH: - transmit_can(&BMW_6F1_CELL_VOLTAGE_AVG, can_config.battery); + transmit_can_frame(&BMW_6F1_CELL_VOLTAGE_AVG, can_config.battery); #ifdef DOUBLE_BATTERY - transmit_can(&BMW_6F1_CELL_VOLTAGE_AVG, can_config.battery_double); + transmit_can_frame(&BMW_6F1_CELL_VOLTAGE_AVG, can_config.battery_double); #endif cmdState = CELL_VOLTAGE_CELLNO; current_cell_polled = 0; @@ -1045,16 +1056,16 @@ void send_can_battery() { cmdState = CELL_VOLTAGE_CELLNO; BMW_6F4_CELL_VOLTAGE_CELLNO.data.u8[6] = current_cell_polled; - transmit_can(&BMW_6F4_CELL_VOLTAGE_CELLNO, can_config.battery); + transmit_can_frame(&BMW_6F4_CELL_VOLTAGE_CELLNO, can_config.battery); #ifdef DOUBLE_BATTERY - transmit_can(&BMW_6F4_CELL_VOLTAGE_CELLNO, can_config.battery_double); + transmit_can_frame(&BMW_6F4_CELL_VOLTAGE_CELLNO, can_config.battery_double); #endif } break; case CELL_VOLTAGE_CELLNO_LAST: - transmit_can(&BMW_6F1_SOC, can_config.battery); + transmit_can_frame(&BMW_6F1_SOC, can_config.battery); #ifdef DOUBLE_BATTERY - transmit_can(&BMW_6F1_SOC, can_config.battery_double); + transmit_can_frame(&BMW_6F1_SOC, can_config.battery_double); #endif cmdState = SOC; break; @@ -1067,25 +1078,25 @@ void send_can_battery() { BMW_3FC.data.u8[1] = ((BMW_3FC.data.u8[1] & 0xF0) + alive_counter_5000ms); BMW_3C5.data.u8[0] = ((BMW_3C5.data.u8[0] & 0xF0) + alive_counter_5000ms); - transmit_can(&BMW_3FC, can_config.battery); //Order comes from CAN logs - transmit_can(&BMW_3C5, can_config.battery); - transmit_can(&BMW_3A0, can_config.battery); - transmit_can(&BMW_592_0, can_config.battery); - transmit_can(&BMW_592_1, can_config.battery); + transmit_can_frame(&BMW_3FC, can_config.battery); //Order comes from CAN logs + transmit_can_frame(&BMW_3C5, can_config.battery); + transmit_can_frame(&BMW_3A0, can_config.battery); + transmit_can_frame(&BMW_592_0, can_config.battery); + transmit_can_frame(&BMW_592_1, can_config.battery); #ifdef DOUBLE_BATTERY - transmit_can(&BMW_3FC, can_config.battery_double); - transmit_can(&BMW_3C5, can_config.battery_double); - transmit_can(&BMW_3A0, can_config.battery_double); - transmit_can(&BMW_592_0, can_config.battery_double); - transmit_can(&BMW_592_1, can_config.battery_double); + transmit_can_frame(&BMW_3FC, can_config.battery_double); + transmit_can_frame(&BMW_3C5, can_config.battery_double); + transmit_can_frame(&BMW_3A0, can_config.battery_double); + transmit_can_frame(&BMW_592_0, can_config.battery_double); + transmit_can_frame(&BMW_592_1, can_config.battery_double); #endif alive_counter_5000ms = increment_alive_counter(alive_counter_5000ms); if (BMW_380_counter < 3) { - transmit_can(&BMW_380, can_config.battery); // This message stops after 3 times on startup + transmit_can_frame(&BMW_380, can_config.battery); // This message stops after 3 times on startup #ifdef DOUBLE_BATTERY - transmit_can(&BMW_380, can_config.battery_double); + transmit_can_frame(&BMW_380, can_config.battery_double); #endif BMW_380_counter++; } @@ -1094,13 +1105,13 @@ void send_can_battery() { if (currentMillis - previousMillis10000 >= INTERVAL_10_S) { previousMillis10000 = currentMillis; - transmit_can(&BMW_3E5, can_config.battery); //Order comes from CAN logs - transmit_can(&BMW_3E4, can_config.battery); - transmit_can(&BMW_37B, can_config.battery); + transmit_can_frame(&BMW_3E5, can_config.battery); //Order comes from CAN logs + transmit_can_frame(&BMW_3E4, can_config.battery); + transmit_can_frame(&BMW_37B, can_config.battery); #ifdef DOUBLE_BATTERY - transmit_can(&BMW_3E5, can_config.battery_double); - transmit_can(&BMW_3E4, can_config.battery_double); - transmit_can(&BMW_37B, can_config.battery_double); + transmit_can_frame(&BMW_3E5, can_config.battery_double); + transmit_can_frame(&BMW_3E4, can_config.battery_double); + transmit_can_frame(&BMW_37B, can_config.battery_double); #endif BMW_3E5.data.u8[0] = 0xFD; // First 3E5 message byte0 we send is unique, once we sent initial value send this @@ -1134,8 +1145,12 @@ void setup_battery(void) { // Performs one time setup at startup datalayer.battery2.status.voltage_dV = 0; //Init voltage to 0 to allow contactor check to operate without fear of default values colliding #endif - pinMode(WUP_PIN, OUTPUT); - digitalWrite(WUP_PIN, HIGH); // Wake up the battery + pinMode(WUP_PIN1, OUTPUT); + digitalWrite(WUP_PIN1, HIGH); // Wake up the battery +#if defined(DOUBLE_BATTERY) && defined(WUP_PIN2) + pinMode(WUP_PIN2, OUTPUT); + digitalWrite(WUP_PIN2, HIGH); // Wake up the battery +#endif // defined(WUP_PIN2) && defined (DOUBLE_BATTERY) } #endif diff --git a/Software/src/battery/BMW-I3-BATTERY.h b/Software/src/battery/BMW-I3-BATTERY.h index 63228ea8..ca5e9553 100644 --- a/Software/src/battery/BMW-I3-BATTERY.h +++ b/Software/src/battery/BMW-I3-BATTERY.h @@ -5,7 +5,6 @@ #define BATTERY_SELECTED -#define WUP_PIN 25 #define MAX_CELL_VOLTAGE_60AH 4110 // Battery is put into emergency stop if one cell goes over this value #define MIN_CELL_VOLTAGE_60AH 2700 // Battery is put into emergency stop if one cell goes below this value #define MAX_CELL_VOLTAGE_94AH 4140 // Battery is put into emergency stop if one cell goes over this value @@ -20,6 +19,6 @@ #define MAX_PACK_VOLTAGE_120AH 4030 // Charge stops if pack voltage exceeds this value #define MIN_PACK_VOLTAGE_120AH 2680 // Discharge stops if pack voltage exceeds this value void setup_battery(void); -void transmit_can(CAN_frame* tx_frame, int interface); +void transmit_can_frame(CAN_frame* tx_frame, int interface); #endif diff --git a/Software/src/battery/BMW-IX-BATTERY.cpp b/Software/src/battery/BMW-IX-BATTERY.cpp index bcd22983..4296793f 100644 --- a/Software/src/battery/BMW-IX-BATTERY.cpp +++ b/Software/src/battery/BMW-IX-BATTERY.cpp @@ -516,7 +516,7 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV; } } -void receive_can_battery(CAN_frame rx_frame) { +void handle_incoming_can_frame_battery(CAN_frame rx_frame) { battery_awake = true; switch (rx_frame.ID) { case 0x112: @@ -540,7 +540,7 @@ void receive_can_battery(CAN_frame rx_frame) { } //Frame has continued data - so request it - transmit_can(&BMWiX_6F4_CONTINUE_DATA, can_config.battery); + transmit_can_frame(&BMWiX_6F4_CONTINUE_DATA, can_config.battery); } if (rx_frame.DLC = 64 && rx_frame.data.u8[0] == 0xF4 && @@ -670,11 +670,11 @@ void receive_can_battery(CAN_frame rx_frame) { if ((rx_frame.data.u8[6] << 8 | rx_frame.data.u8[7]) == 10000 || (rx_frame.data.u8[8] << 8 | rx_frame.data.u8[9]) == 10000) { //Qualifier Invalid Mode - Request Reboot -#ifdef DEBUG_VIA_USB - Serial.println("Cell MinMax Qualifier Invalid - Requesting BMS Reset"); +#ifdef DEBUG_LOG + logging.println("Cell MinMax Qualifier Invalid - Requesting BMS Reset"); #endif //set_event(EVENT_BATTERY_VALUE_UNAVAILABLE, (millis())); //Eventually need new Info level event type - transmit_can(&BMWiX_6F4_REQUEST_HARD_RESET, can_config.battery); + transmit_can_frame(&BMWiX_6F4_REQUEST_HARD_RESET, can_config.battery); } else { //Only ingest values if they are not the 10V Error state min_cell_voltage = (rx_frame.data.u8[6] << 8 | rx_frame.data.u8[7]); max_cell_voltage = (rx_frame.data.u8[8] << 8 | rx_frame.data.u8[9]); @@ -724,7 +724,7 @@ void receive_can_battery(CAN_frame rx_frame) { } } -void send_can_battery() { +void transmit_can_battery() { unsigned long currentMillis = millis(); //if (battery_awake) { //We can always send CAN as the iX BMS will wake up on vehicle comms @@ -734,10 +734,10 @@ void send_can_battery() { //Loop through and send a different UDS request each cycle uds_req_id_counter = increment_uds_req_id_counter(uds_req_id_counter); - transmit_can(UDS_REQUESTS100MS[uds_req_id_counter], can_config.battery); + transmit_can_frame(UDS_REQUESTS100MS[uds_req_id_counter], can_config.battery); //Send SME Keep alive values 100ms - transmit_can(&BMWiX_510, can_config.battery); + transmit_can_frame(&BMWiX_510, can_config.battery); } // Send 200ms CAN Message if (currentMillis - previousMillis200 >= INTERVAL_200_MS) { @@ -745,16 +745,16 @@ void send_can_battery() { //Send SME Keep alive values 200ms BMWiX_0C0.data.u8[0] = increment_0C0_counter(BMWiX_0C0.data.u8[0]); //Keep Alive 1 - transmit_can(&BMWiX_0C0, can_config.battery); + transmit_can_frame(&BMWiX_0C0, can_config.battery); } // Send 1000ms CAN Message if (currentMillis - previousMillis1000 >= INTERVAL_1_S) { previousMillis1000 = currentMillis; //Send SME Keep alive values 1000ms - //Don't believe this is needed: transmit_can(&BMWiX_06D, can_config.battery); - //Don't believe this is needed: transmit_can(&BMWiX_2F1, can_config.battery); - //Don't believe this is needed: transmit_can(&BMWiX_439, can_config.battery); + //Don't believe this is needed: transmit_can_frame(&BMWiX_06D, can_config.battery); + //Don't believe this is needed: transmit_can_frame(&BMWiX_2F1, can_config.battery); + //Don't believe this is needed: transmit_can_frame(&BMWiX_439, can_config.battery); } // Send 5000ms CAN Message if (currentMillis - previousMillis5000 >= INTERVAL_5_S) { diff --git a/Software/src/battery/BMW-IX-BATTERY.h b/Software/src/battery/BMW-IX-BATTERY.h index a5336778..e04a0d87 100644 --- a/Software/src/battery/BMW-IX-BATTERY.h +++ b/Software/src/battery/BMW-IX-BATTERY.h @@ -5,7 +5,6 @@ #define BATTERY_SELECTED -//#define WUP_PIN 25 //Not used #define MAX_PACK_VOLTAGE_DV 4650 //4650 = 465.0V #define MIN_PACK_VOLTAGE_DV 3000 #define MAX_CELL_DEVIATION_MV 250 @@ -18,6 +17,6 @@ #define STALE_PERIOD_CONFIG \ 300000; //Number of milliseconds before critical values are classed as stale/stuck 300000 = 300 seconds void setup_battery(void); -void transmit_can(CAN_frame* tx_frame, int interface); +void transmit_can_frame(CAN_frame* tx_frame, int interface); #endif diff --git a/Software/src/battery/BMW-SBOX.cpp b/Software/src/battery/BMW-SBOX.cpp index 40b91a4a..bf5f0598 100644 --- a/Software/src/battery/BMW-SBOX.cpp +++ b/Software/src/battery/BMW-SBOX.cpp @@ -21,98 +21,93 @@ uint32_t avg_sum; uint8_t k; //avg array pointer -uint8_t CAN100_cnt=0; +uint8_t CAN100_cnt = 0; CAN_frame SBOX_100 = {.FD = false, - .ext_ID = false, - .DLC = 4, - .ID = 0x100, - .data = {0x55, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00}}; // Byte 0: relay control, Byte 1: counter 0-E, Byte 4: CRC + .ext_ID = false, + .DLC = 4, + .ID = 0x100, + .data = {0x55, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00}}; // Byte 0: relay control, Byte 1: counter 0-E, Byte 4: CRC CAN_frame SBOX_300 = {.FD = false, - .ext_ID = false, - .DLC = 4, - .ID = 0x300, - .data = {0xFF, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}}; // Static frame - + .ext_ID = false, + .DLC = 4, + .ID = 0x300, + .data = {0xFF, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}}; // Static frame uint8_t reverse_bits(uint8_t byte) { uint8_t reversed = 0; for (int i = 0; i < 8; i++) { - reversed = (reversed << 1) | (byte & 1); - byte >>= 1; + reversed = (reversed << 1) | (byte & 1); + byte >>= 1; } return reversed; } - /** CRC8, both inverted, poly 0x31 **/ uint8_t calculateCRC(CAN_frame CAN) { uint8_t crc = 0; for (size_t i = 0; i < CAN.DLC; i++) { - uint8_t reversed_byte = reverse_bits(CAN.data.u8[i]); - crc ^= reversed_byte; + uint8_t reversed_byte = reverse_bits(CAN.data.u8[i]); + crc ^= reversed_byte; for (int j = 0; j < 8; j++) { - if (crc & 0x80) { - crc = (crc << 1) ^ 0x31; + if (crc & 0x80) { + crc = (crc << 1) ^ 0x31; } else { - crc <<= 1; + crc <<= 1; } - crc &= 0xFF; + crc &= 0xFF; } } - crc=reverse_bits(crc); + crc = reverse_bits(crc); return crc; } -void receive_can_shunt(CAN_frame rx_frame) { +void map_can_frame_to_variable_shunt(CAN_frame rx_frame) { unsigned long currentTime = millis(); - if(rx_frame.ID ==0x200) - { - ShuntLastSeen=currentTime; - datalayer.shunt.measured_amperage_mA=((rx_frame.data.u8[2]<<24)| (rx_frame.data.u8[1]<<16)| (rx_frame.data.u8[0]<<8))/256; + if (rx_frame.ID == 0x200) { + ShuntLastSeen = currentTime; + datalayer.shunt.measured_amperage_mA = + ((rx_frame.data.u8[2] << 24) | (rx_frame.data.u8[1] << 16) | (rx_frame.data.u8[0] << 8)) / 256; + datalayer.shunt.measured_amperage_dA = datalayer.shunt.measured_amperage_mA / 100; /** Calculate 1S avg current **/ - if(LastAvgTime+1009) { - k=0; + if (LastAvgTime + 100 < currentTime) { + LastAvgTime = currentTime; + if (k > 9) { + k = 0; } - avg_mA_array[k]=datalayer.shunt.measured_amperage_mA; + avg_mA_array[k] = datalayer.shunt.measured_amperage_mA; k++; - avg_sum=0; - for (uint8_t i = 0; i < 10; i++) - { - avg_sum=avg_sum+avg_mA_array[i]; + avg_sum = 0; + for (uint8_t i = 0; i < 10; i++) { + avg_sum = avg_sum + avg_mA_array[i]; } - datalayer.shunt.measured_avg1S_amperage_mA=avg_sum/10; + datalayer.shunt.measured_avg1S_amperage_mA = avg_sum / 10; } - } - else if(rx_frame.ID ==0x210) //SBOX input (battery side) voltage - { - ShuntLastSeen=currentTime; - datalayer.shunt.measured_voltage_mV=((rx_frame.data.u8[2]<<16)| (rx_frame.data.u8[1]<<8)| (rx_frame.data.u8[0])); - } - else if(rx_frame.ID ==0x220) //SBOX output voltage - { - ShuntLastSeen=currentTime; - datalayer.shunt.measured_outvoltage_mV=((rx_frame.data.u8[2]<<16)| (rx_frame.data.u8[1]<<8)| (rx_frame.data.u8[0])); - datalayer.shunt.available=true; + } else if (rx_frame.ID == 0x210) //SBOX input (battery side) voltage + { + ShuntLastSeen = currentTime; + datalayer.shunt.measured_voltage_mV = + ((rx_frame.data.u8[2] << 16) | (rx_frame.data.u8[1] << 8) | (rx_frame.data.u8[0])); + } else if (rx_frame.ID == 0x220) //SBOX output voltage + { + ShuntLastSeen = currentTime; + datalayer.shunt.measured_outvoltage_mV = + ((rx_frame.data.u8[2] << 16) | (rx_frame.data.u8[1] << 8) | (rx_frame.data.u8[0])); + datalayer.shunt.available = true; } } -void send_can_shunt() { +void transmit_can_shunt() { unsigned long currentTime = millis(); /** Shunt can frames seen? **/ - if(ShuntLastSeen+1000= INTERVAL_20_MS) { @@ -127,7 +122,7 @@ void send_can_shunt() { //handle contactor control SHUTDOWN_REQUESTED if (timeSpentInFaultedMode > MAX_ALLOWED_FAULT_TICKS) { contactorStatus = SHUTDOWN_REQUESTED; - SBOX_100.data.u8[0]=0x55; // All open + SBOX_100.data.u8[0] = 0x55; // All open } if (contactorStatus == SHUTDOWN_REQUESTED) { @@ -138,24 +133,27 @@ void send_can_shunt() { // After that, check if we are OK to start turning on the contactors if (contactorStatus == DISCONNECTED) { datalayer.shunt.contactors_engaged = false; - SBOX_100.data.u8[0]=0x55; // All open + SBOX_100.data.u8[0] = 0x55; // All open if (datalayer.system.status.battery_allows_contactor_closing && - datalayer.system.status.inverter_allows_contactor_closing && !datalayer.system.settings.equipment_stop_active && ( datalayer.shunt.measured_voltage_mV > MINIMUM_INPUT_VOLTAGE*1000)) { + datalayer.system.status.inverter_allows_contactor_closing && + !datalayer.system.settings.equipment_stop_active && + (datalayer.shunt.measured_voltage_mV > MINIMUM_INPUT_VOLTAGE * 1000)) { contactorStatus = 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) { + if (!datalayer.system.status.inverter_allows_contactor_closing || + datalayer.system.settings.equipment_stop_active) { contactorStatus = DISCONNECTED; } } // Handle actual state machine. This first turns on Precharge, then Negative, then Positive, and finally turns OFF precharge switch (contactorStatus) { case PRECHARGE: - SBOX_100.data.u8[0]=0x86; // Precharge relay only + SBOX_100.data.u8[0] = 0x86; // Precharge relay only prechargeStartTime = currentTime; contactorStatus = NEGATIVE; #ifdef DEBUG_VIA_USB @@ -164,50 +162,52 @@ void send_can_shunt() { break; case NEGATIVE: if (currentTime - prechargeStartTime >= CONTACTOR_CONTROL_T1) { - SBOX_100.data.u8[0]=0xA6; // Precharge + Negative + SBOX_100.data.u8[0] = 0xA6; // Precharge + Negative negativeStartTime = currentTime; contactorStatus = POSITIVE; datalayer.shunt.precharging = true; #ifdef DEBUG_VIA_USB - Serial.println("S-BOX Negative relay engaged"); + Serial.println("S-BOX Negative relay engaged"); #endif } break; case POSITIVE: - if (currentTime - negativeStartTime >= CONTACTOR_CONTROL_T2 && (datalayer.shunt.measured_voltage_mV * MAX_PRECHARGE_RESISTOR_VOLTAGE_PERCENT < datalayer.shunt.measured_outvoltage_mV)) { - SBOX_100.data.u8[0]=0xAA; // Precharge + Negative + Positive + if (currentTime - negativeStartTime >= CONTACTOR_CONTROL_T2 && + (datalayer.shunt.measured_voltage_mV * MAX_PRECHARGE_RESISTOR_VOLTAGE_PERCENT < + datalayer.shunt.measured_outvoltage_mV)) { + SBOX_100.data.u8[0] = 0xAA; // Precharge + Negative + Positive positiveStartTime = currentTime; contactorStatus = PRECHARGE_OFF; datalayer.shunt.precharging = false; #ifdef DEBUG_VIA_USB - Serial.println("S-BOX Positive relay engaged"); + Serial.println("S-BOX Positive relay engaged"); #endif } break; case PRECHARGE_OFF: if (currentTime - positiveStartTime >= CONTACTOR_CONTROL_T3) { - SBOX_100.data.u8[0]=0x6A; // Negative + Positive + SBOX_100.data.u8[0] = 0x6A; // Negative + Positive contactorStatus = COMPLETED; #ifdef DEBUG_VIA_USB - Serial.println("S-BOX Precharge relay released"); + Serial.println("S-BOX Precharge relay released"); #endif datalayer.shunt.contactors_engaged = true; } break; case COMPLETED: - SBOX_100.data.u8[0]=0x6A; // Negative + Positive + SBOX_100.data.u8[0] = 0x6A; // Negative + Positive default: break; } CAN100_cnt++; - if (CAN100_cnt>0x0E) { - CAN100_cnt=0; - } - SBOX_100.data.u8[1]=CAN100_cnt<<4|0x01; - SBOX_100.data.u8[3]=0x00; - SBOX_100.data.u8[3]=calculateCRC(SBOX_100); - transmit_can(&SBOX_100, can_config.shunt); - transmit_can(&SBOX_300, can_config.shunt); + if (CAN100_cnt > 0x0E) { + CAN100_cnt = 0; + } + SBOX_100.data.u8[1] = CAN100_cnt << 4 | 0x01; + SBOX_100.data.u8[3] = 0x00; + SBOX_100.data.u8[3] = calculateCRC(SBOX_100); + transmit_can_frame(&SBOX_100, can_config.shunt); + transmit_can_frame(&SBOX_300, can_config.shunt); } } diff --git a/Software/src/battery/BMW-SBOX.h b/Software/src/battery/BMW-SBOX.h index 70aa788b..131fa3a0 100644 --- a/Software/src/battery/BMW-SBOX.h +++ b/Software/src/battery/BMW-SBOX.h @@ -15,8 +15,8 @@ void transmit_can(CAN_frame* tx_frame, int interface); * t=3RC at minimum, t=5RC ideally */ -#define CONTACTOR_CONTROL_T1 5000 // Time before negative contactor engages and precharging starts -#define CONTACTOR_CONTROL_T2 5000 // Precharge time before precharge resistor is bypassed by positive contactor -#define CONTACTOR_CONTROL_T3 2000 // Precharge relay lead time after positive contactor has been engaged +#define CONTACTOR_CONTROL_T1 5000 // Time before negative contactor engages and precharging starts +#define CONTACTOR_CONTROL_T2 5000 // Precharge time before precharge resistor is bypassed by positive contactor +#define CONTACTOR_CONTROL_T3 2000 // Precharge relay lead time after positive contactor has been engaged #endif diff --git a/Software/src/battery/BOLT-AMPERA-BATTERY.cpp b/Software/src/battery/BOLT-AMPERA-BATTERY.cpp new file mode 100644 index 00000000..e7c2e0f6 --- /dev/null +++ b/Software/src/battery/BOLT-AMPERA-BATTERY.cpp @@ -0,0 +1,789 @@ +#include "../include.h" +#ifdef BOLT_AMPERA_BATTERY +#include "../datalayer/datalayer.h" +#include "../datalayer/datalayer_extended.h" +#include "../devboard/utils/events.h" +#include "BOLT-AMPERA-BATTERY.h" + +/* +TODOs left for this implementation +- The battery has 3 CAN ports. One of them is responsible for the 7E4 polls, the other for the 7E7 polls +- Current implementation only seems to get the 7E7 polls working. +- Could on of the CAN channels be GMLAN? + +- The values missing for a working implementation is: +- SOC% missing! This is absolutely mandatory to fix before starting to use this! +- Capacity (kWh) (can be estimated) +- Charge max power (can be estimated) +- Discharge max power (can be estimated) +- SOH% (low prio)) +*/ + +/* Do not change code below unless you are sure what you are doing */ +static unsigned long previousMillis20ms = 0; // will store last time a 20ms CAN Message was send +static unsigned long previousMillis100ms = 0; // will store last time a 100ms CAN Message was send +static unsigned long previousMillis120ms = 0; // will store last time a 120ms CAN Message was send + +CAN_frame BOLT_778 = {.FD = false, // Unsure of what this message is, added only as example + .ext_ID = false, + .DLC = 7, + .ID = 0x778, + .data = {0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00}}; +CAN_frame BOLT_POLL_7E4 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x7E4, + .data = {0x03, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +CAN_frame BOLT_ACK_7E4 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x7E4, + .data = {0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +CAN_frame BOLT_POLL_7E7 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x7E7, + .data = {0x03, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +CAN_frame BOLT_ACK_7E7 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x7E7, + .data = {0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; + +// 7E4 Battery , reply 000007EC +// 7E7 Battery (Cell voltages), reply 000007EF + +static uint16_t battery_cell_voltages[96]; //array with all the cellvoltages +static uint16_t battery_capacity_my17_18 = 0; +static uint16_t battery_capacity_my19plus = 0; +static uint16_t battery_SOC_display = 0; +static uint16_t battery_SOC_raw_highprec = 0; +static uint16_t battery_max_temperature = 0; +static uint16_t battery_min_temperature = 0; +static uint16_t battery_min_cell_voltage = 0; +static uint16_t battery_max_cell_voltage = 0; +static uint16_t battery_internal_resistance = 0; +static uint16_t battery_lowest_cell = 0; +static uint16_t battery_highest_cell = 0; +static uint16_t battery_voltage_polled = 0; +static uint16_t battery_voltage_periodic = 0; +static uint16_t battery_vehicle_isolation = 0; +static uint16_t battery_isolation_kohm = 0; +static uint16_t battery_HV_locked = 0; +static uint16_t battery_crash_event = 0; +static uint16_t battery_HVIL = 0; +static uint16_t battery_HVIL_status = 0; +static uint16_t battery_5V_ref = 0; +static int16_t battery_current_7E4 = 0; +static int16_t battery_module_temp_1 = 0; +static int16_t battery_module_temp_2 = 0; +static int16_t battery_module_temp_3 = 0; +static int16_t battery_module_temp_4 = 0; +static int16_t battery_module_temp_5 = 0; +static int16_t battery_module_temp_6 = 0; +static uint16_t battery_cell_average_voltage = 0; +static uint16_t battery_cell_average_voltage_2 = 0; +static uint16_t battery_terminal_voltage = 0; +static uint16_t battery_ignition_power_mode = 0; +static int16_t battery_current_7E7 = 0; +static int16_t temperature_1 = 0; +static int16_t temperature_2 = 0; +static int16_t temperature_3 = 0; +static int16_t temperature_4 = 0; +static int16_t temperature_5 = 0; +static int16_t temperature_6 = 0; +static int16_t temperature_highest = 0; +static int16_t temperature_lowest = 0; +static uint8_t mux = 0; +static uint8_t poll_index_7E4 = 0; +static uint16_t currentpoll_7E4 = POLL_7E4_CAPACITY_EST_GEN1; +static uint16_t reply_poll_7E4 = 0; +static uint8_t poll_index_7E7 = 0; +static uint16_t currentpoll_7E7 = POLL_7E7_CURRENT; +static uint16_t reply_poll_7E7 = 0; + +const uint16_t poll_commands_7E4[19] = {POLL_7E4_CAPACITY_EST_GEN1, + POLL_7E4_CAPACITY_EST_GEN2, + POLL_7E4_SOC_DISPLAY, + POLL_7E4_SOC_RAW_HIGHPREC, + POLL_7E4_MAX_TEMPERATURE, + POLL_7E4_MIN_TEMPERATURE, + POLL_7E4_MIN_CELL_V, + POLL_7E4_MAX_CELL_V, + POLL_7E4_INTERNAL_RES, + POLL_7E4_LOWEST_CELL_NUMBER, + POLL_7E4_HIGHEST_CELL_NUMBER, + POLL_7E4_VOLTAGE, + POLL_7E4_VEHICLE_ISOLATION, + POLL_7E4_ISOLATION_TEST_KOHM, + POLL_7E4_HV_LOCKED_OUT, + POLL_7E4_CRASH_EVENT, + POLL_7E4_HVIL, + POLL_7E4_HVIL_STATUS, + POLL_7E4_CURRENT}; + +const uint16_t poll_commands_7E7[108] = {POLL_7E7_CURRENT, POLL_7E7_5V_REF, + POLL_7E7_MODULE_TEMP_1, POLL_7E7_MODULE_TEMP_2, + POLL_7E7_MODULE_TEMP_3, POLL_7E7_MODULE_TEMP_4, + POLL_7E7_MODULE_TEMP_5, POLL_7E7_MODULE_TEMP_6, + POLL_7E7_CELL_AVG_VOLTAGE, POLL_7E7_CELL_AVG_VOLTAGE_2, + POLL_7E7_TERMINAL_VOLTAGE, POLL_7E7_IGNITION_POWER_MODE, + POLL_7E7_CELL_01, POLL_7E7_CELL_02, + POLL_7E7_CELL_03, POLL_7E7_CELL_04, + POLL_7E7_CELL_05, POLL_7E7_CELL_06, + POLL_7E7_CELL_07, POLL_7E7_CELL_08, + POLL_7E7_CELL_09, POLL_7E7_CELL_10, + POLL_7E7_CELL_11, POLL_7E7_CELL_12, + POLL_7E7_CELL_13, POLL_7E7_CELL_14, + POLL_7E7_CELL_15, POLL_7E7_CELL_16, + POLL_7E7_CELL_17, POLL_7E7_CELL_18, + POLL_7E7_CELL_19, POLL_7E7_CELL_20, + POLL_7E7_CELL_21, POLL_7E7_CELL_22, + POLL_7E7_CELL_23, POLL_7E7_CELL_24, + POLL_7E7_CELL_25, POLL_7E7_CELL_26, + POLL_7E7_CELL_27, POLL_7E7_CELL_28, + POLL_7E7_CELL_29, POLL_7E7_CELL_30, + POLL_7E7_CELL_31, POLL_7E7_CELL_32, + POLL_7E7_CELL_33, POLL_7E7_CELL_34, + POLL_7E7_CELL_35, POLL_7E7_CELL_36, + POLL_7E7_CELL_37, POLL_7E7_CELL_38, + POLL_7E7_CELL_39, POLL_7E7_CELL_40, + POLL_7E7_CELL_41, POLL_7E7_CELL_42, + POLL_7E7_CELL_43, POLL_7E7_CELL_44, + POLL_7E7_CELL_45, POLL_7E7_CELL_46, + POLL_7E7_CELL_47, POLL_7E7_CELL_48, + POLL_7E7_CELL_49, POLL_7E7_CELL_50, + POLL_7E7_CELL_51, POLL_7E7_CELL_52, + POLL_7E7_CELL_53, POLL_7E7_CELL_54, + POLL_7E7_CELL_55, POLL_7E7_CELL_56, + POLL_7E7_CELL_57, POLL_7E7_CELL_58, + POLL_7E7_CELL_59, POLL_7E7_CELL_60, + POLL_7E7_CELL_61, POLL_7E7_CELL_62, + POLL_7E7_CELL_63, POLL_7E7_CELL_64, + POLL_7E7_CELL_65, POLL_7E7_CELL_66, + POLL_7E7_CELL_67, POLL_7E7_CELL_68, + POLL_7E7_CELL_69, POLL_7E7_CELL_70, + POLL_7E7_CELL_71, POLL_7E7_CELL_72, + POLL_7E7_CELL_73, POLL_7E7_CELL_74, + POLL_7E7_CELL_75, POLL_7E7_CELL_76, + POLL_7E7_CELL_77, POLL_7E7_CELL_78, + POLL_7E7_CELL_79, POLL_7E7_CELL_80, + POLL_7E7_CELL_81, POLL_7E7_CELL_82, + POLL_7E7_CELL_83, POLL_7E7_CELL_84, + POLL_7E7_CELL_85, POLL_7E7_CELL_86, + POLL_7E7_CELL_87, POLL_7E7_CELL_88, + POLL_7E7_CELL_89, POLL_7E7_CELL_90, + POLL_7E7_CELL_91, POLL_7E7_CELL_92, + POLL_7E7_CELL_93, POLL_7E7_CELL_94, + POLL_7E7_CELL_95, POLL_7E7_CELL_96}; + +void update_values_battery() { //This function maps all the values fetched via CAN to the battery datalayer + + datalayer.battery.status.real_soc = battery_SOC_display; + + //datalayer.battery.status.voltage_dV = battery_voltage * 0.52; + datalayer.battery.status.voltage_dV = (battery_voltage_periodic / 8) * 10; + + datalayer.battery.status.current_dA = battery_current_7E7; + + datalayer.battery.info.total_capacity_Wh; + + datalayer.battery.status.remaining_capacity_Wh; + + datalayer.battery.status.soh_pptt; + + datalayer.battery.status.max_discharge_power_W; + + datalayer.battery.status.max_charge_power_W; + + // Store temperatures in an array + int16_t temperatures[] = {temperature_1, temperature_2, temperature_3, temperature_4, temperature_5, temperature_6}; + + // Initialize highest and lowest to the first element + temperature_highest = temperatures[0]; + temperature_lowest = temperatures[0]; + + // Iterate through the array to find the highest and lowest values + for (uint8_t i = 1; i < 6; ++i) { + if (temperatures[i] > temperature_highest) { + temperature_highest = temperatures[i]; + } + if (temperatures[i] < temperature_lowest) { + temperature_lowest = temperatures[i]; + } + } + + datalayer.battery.status.temperature_min_dC = temperature_lowest * 10; + + datalayer.battery.status.temperature_max_dC = temperature_highest * 10; + + //Map all cell voltages to the global array + memcpy(datalayer.battery.status.cell_voltages_mV, battery_cell_voltages, 96 * sizeof(uint16_t)); + + // Update webserver datalayer + datalayer_extended.boltampera.battery_5V_ref = battery_5V_ref; + datalayer_extended.boltampera.battery_module_temp_1 = battery_module_temp_1; + datalayer_extended.boltampera.battery_module_temp_2 = battery_module_temp_2; + datalayer_extended.boltampera.battery_module_temp_3 = battery_module_temp_3; + datalayer_extended.boltampera.battery_module_temp_4 = battery_module_temp_4; + datalayer_extended.boltampera.battery_module_temp_5 = battery_module_temp_5; + datalayer_extended.boltampera.battery_module_temp_6 = battery_module_temp_6; + datalayer_extended.boltampera.battery_cell_average_voltage = battery_cell_average_voltage; + datalayer_extended.boltampera.battery_cell_average_voltage_2 = battery_cell_average_voltage_2; + datalayer_extended.boltampera.battery_terminal_voltage = battery_terminal_voltage; + datalayer_extended.boltampera.battery_ignition_power_mode = battery_ignition_power_mode; + datalayer_extended.boltampera.battery_current_7E7 = battery_current_7E7; + datalayer_extended.boltampera.battery_capacity_my17_18 = battery_capacity_my17_18; + datalayer_extended.boltampera.battery_capacity_my19plus = battery_capacity_my19plus; + datalayer_extended.boltampera.battery_SOC_display = battery_SOC_display; + datalayer_extended.boltampera.battery_SOC_raw_highprec = battery_SOC_raw_highprec; + datalayer_extended.boltampera.battery_max_temperature = battery_max_temperature; + datalayer_extended.boltampera.battery_min_temperature = battery_min_temperature; + datalayer_extended.boltampera.battery_min_cell_voltage = battery_min_cell_voltage; + datalayer_extended.boltampera.battery_max_cell_voltage = battery_max_cell_voltage; + datalayer_extended.boltampera.battery_lowest_cell = battery_lowest_cell; + datalayer_extended.boltampera.battery_highest_cell = battery_highest_cell; + datalayer_extended.boltampera.battery_internal_resistance = battery_internal_resistance; + datalayer_extended.boltampera.battery_voltage_polled = battery_voltage_polled; + datalayer_extended.boltampera.battery_vehicle_isolation = battery_vehicle_isolation; + datalayer_extended.boltampera.battery_isolation_kohm = battery_isolation_kohm; + datalayer_extended.boltampera.battery_HV_locked = battery_HV_locked; + datalayer_extended.boltampera.battery_crash_event = battery_crash_event; + datalayer_extended.boltampera.battery_HVIL = battery_HVIL; + datalayer_extended.boltampera.battery_HVIL_status = battery_HVIL_status; + datalayer_extended.boltampera.battery_current_7E4 = battery_current_7E4; +} + +void handle_incoming_can_frame_battery(CAN_frame rx_frame) { + switch (rx_frame.ID) { + case 0x200: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + mux = ((rx_frame.data.u8[6] & 0xE0) >> 5); //goes from 0-7 + break; + case 0x202: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + mux = ((rx_frame.data.u8[6] & 0xE0) >> 5); //goes from 0-7 + break; + case 0x204: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + mux = ((rx_frame.data.u8[6] & 0xE0) >> 5); //goes from 0-7 + break; + case 0x206: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + mux = ((rx_frame.data.u8[6] & 0xE0) >> 5); //goes from 0-7 + break; + case 0x208: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + mux = ((rx_frame.data.u8[6] & 0xE0) >> 5); //goes from 0-7 + break; + case 0x20C: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; + case 0x216: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; + case 0x2C7: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + battery_voltage_periodic = (rx_frame.data.u8[3] << 4) | (rx_frame.data.u8[4] >> 4); + break; + case 0x260: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; + case 0x270: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; + case 0x272: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; + case 0x274: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; + case 0x302: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + temperature_1 = ((rx_frame.data.u8[1] / 2) - 40); //Module 1 Temperature + temperature_2 = ((rx_frame.data.u8[2] / 2) - 40); //Module 2 Temperature + temperature_3 = ((rx_frame.data.u8[3] / 2) - 40); //Module 3 Temperature + temperature_4 = ((rx_frame.data.u8[4] / 2) - 40); //Module 4 Temperature + temperature_5 = ((rx_frame.data.u8[5] / 2) - 40); //Module 5 Temperature + temperature_6 = ((rx_frame.data.u8[6] / 2) - 40); //Module 6 Temperature + break; + case 0x3E3: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; + case 0x460: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; + case 0x5EF: + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + break; + case 0x7EC: //When polling 7E4 BMS replies with 7EC ?? + + if (rx_frame.data.u8[0] == 0x10) { //"PID Header" + transmit_can_frame(&BOLT_ACK_7E4, can_config.battery); + } + + //Frame 2 & 3 contains reply + reply_poll_7E4 = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + + switch (reply_poll_7E4) { + case POLL_7E4_CAPACITY_EST_GEN1: + battery_capacity_my17_18 = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + break; + case POLL_7E4_CAPACITY_EST_GEN2: + battery_capacity_my19plus = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + break; + case POLL_7E4_SOC_DISPLAY: + battery_SOC_display = ((rx_frame.data.u8[4] * 100) / 255); + break; + case POLL_7E4_SOC_RAW_HIGHPREC: + battery_SOC_raw_highprec = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 100) / 65535); + break; + case POLL_7E4_MAX_TEMPERATURE: + battery_max_temperature = (rx_frame.data.u8[4] - 40); + break; + case POLL_7E4_MIN_TEMPERATURE: + battery_min_temperature = (rx_frame.data.u8[4] - 40); + break; + case POLL_7E4_MIN_CELL_V: + battery_min_cell_voltage = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) / 1666; + break; + case POLL_7E4_MAX_CELL_V: + battery_max_cell_voltage = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) / 1666; + break; + case POLL_7E4_INTERNAL_RES: + battery_internal_resistance = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) / 2; + break; + case POLL_7E4_LOWEST_CELL_NUMBER: + battery_lowest_cell = rx_frame.data.u8[4]; + break; + case POLL_7E4_HIGHEST_CELL_NUMBER: + battery_highest_cell = rx_frame.data.u8[4]; + break; + case POLL_7E4_VOLTAGE: + battery_voltage_polled = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 0.52); + break; + case POLL_7E4_VEHICLE_ISOLATION: + battery_vehicle_isolation = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + break; + case POLL_7E4_ISOLATION_TEST_KOHM: + battery_isolation_kohm = (rx_frame.data.u8[4] * 25); + break; + case POLL_7E4_HV_LOCKED_OUT: + battery_HV_locked = rx_frame.data.u8[4]; + break; + case POLL_7E4_CRASH_EVENT: + battery_crash_event = rx_frame.data.u8[4]; + break; + case POLL_7E4_HVIL: + battery_HVIL = rx_frame.data.u8[4]; + break; + case POLL_7E4_HVIL_STATUS: + battery_HVIL_status = rx_frame.data.u8[4]; + break; + case POLL_7E4_CURRENT: + battery_current_7E4 = (((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) / (-6.675)); + break; + default: + break; + } + + break; + case 0x7EF: //When polling 7E7 BMS replies with 7EF + + if (rx_frame.data.u8[0] == 0x10) { //"PID Header" + transmit_can_frame(&BOLT_ACK_7E7, can_config.battery); + } + + //Frame 2 & 3 contains reply + reply_poll_7E7 = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + + switch (reply_poll_7E7) { + case POLL_7E7_CURRENT: + battery_current_7E7 = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case POLL_7E7_5V_REF: + battery_5V_ref = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5) / 65535); + break; + case POLL_7E7_MODULE_TEMP_1: + battery_module_temp_1 = (rx_frame.data.u8[4] - 40); + break; + case POLL_7E7_MODULE_TEMP_2: + battery_module_temp_2 = (rx_frame.data.u8[4] - 40); + break; + case POLL_7E7_MODULE_TEMP_3: + battery_module_temp_3 = (rx_frame.data.u8[4] - 40); + break; + case POLL_7E7_MODULE_TEMP_4: + battery_module_temp_4 = (rx_frame.data.u8[4] - 40); + break; + case POLL_7E7_MODULE_TEMP_5: + battery_module_temp_5 = (rx_frame.data.u8[4] - 40); + break; + case POLL_7E7_MODULE_TEMP_6: + battery_module_temp_6 = (rx_frame.data.u8[4] - 40); + break; + case POLL_7E7_CELL_AVG_VOLTAGE: + battery_cell_average_voltage = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_AVG_VOLTAGE_2: + battery_cell_average_voltage_2 = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) / 8000) * 1000); + break; + case POLL_7E7_TERMINAL_VOLTAGE: + battery_terminal_voltage = rx_frame.data.u8[4] * 2; + break; + case POLL_7E7_IGNITION_POWER_MODE: + battery_ignition_power_mode = rx_frame.data.u8[4]; + break; + case POLL_7E7_CELL_01: + battery_cell_voltages[0] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_02: + battery_cell_voltages[1] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_03: + battery_cell_voltages[2] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_04: + battery_cell_voltages[3] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_05: + battery_cell_voltages[4] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_06: + battery_cell_voltages[5] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_07: + battery_cell_voltages[6] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_08: + battery_cell_voltages[7] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_09: + battery_cell_voltages[8] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_10: + battery_cell_voltages[9] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_11: + battery_cell_voltages[10] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_12: + battery_cell_voltages[11] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_13: + battery_cell_voltages[12] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_14: + battery_cell_voltages[13] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_15: + battery_cell_voltages[14] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_16: + battery_cell_voltages[15] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_17: + battery_cell_voltages[16] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_18: + battery_cell_voltages[17] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_19: + battery_cell_voltages[18] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_20: + battery_cell_voltages[19] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_21: + battery_cell_voltages[20] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_22: + battery_cell_voltages[21] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_23: + battery_cell_voltages[22] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_24: + battery_cell_voltages[23] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_25: + battery_cell_voltages[24] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_26: + battery_cell_voltages[25] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_27: + battery_cell_voltages[26] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_28: + battery_cell_voltages[27] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_29: + battery_cell_voltages[28] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_30: + battery_cell_voltages[29] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_31: + battery_cell_voltages[30] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_32: + battery_cell_voltages[31] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_33: + battery_cell_voltages[32] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_34: + battery_cell_voltages[33] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_35: + battery_cell_voltages[34] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_36: + battery_cell_voltages[35] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_37: + battery_cell_voltages[36] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_38: + battery_cell_voltages[37] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_39: + battery_cell_voltages[38] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_40: + battery_cell_voltages[39] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_41: + battery_cell_voltages[40] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_42: + battery_cell_voltages[41] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_43: + battery_cell_voltages[42] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_44: + battery_cell_voltages[43] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_45: + battery_cell_voltages[44] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_46: + battery_cell_voltages[45] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_47: + battery_cell_voltages[46] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_48: + battery_cell_voltages[47] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_49: + battery_cell_voltages[48] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_50: + battery_cell_voltages[49] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_51: + battery_cell_voltages[50] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_52: + battery_cell_voltages[51] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_53: + battery_cell_voltages[52] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_54: + battery_cell_voltages[53] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_55: + battery_cell_voltages[54] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_56: + battery_cell_voltages[55] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_57: + battery_cell_voltages[56] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_58: + battery_cell_voltages[57] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_59: + battery_cell_voltages[58] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_60: + battery_cell_voltages[59] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_61: + battery_cell_voltages[60] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_62: + battery_cell_voltages[61] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_63: + battery_cell_voltages[62] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_64: + battery_cell_voltages[63] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_65: + battery_cell_voltages[64] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_66: + battery_cell_voltages[65] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_67: + battery_cell_voltages[66] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_68: + battery_cell_voltages[67] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_69: + battery_cell_voltages[68] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_70: + battery_cell_voltages[69] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_71: + battery_cell_voltages[70] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_72: + battery_cell_voltages[71] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_73: + battery_cell_voltages[72] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_74: + battery_cell_voltages[73] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_75: + battery_cell_voltages[74] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_76: + battery_cell_voltages[75] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_77: + battery_cell_voltages[76] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_78: + battery_cell_voltages[77] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_79: + battery_cell_voltages[78] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_80: + battery_cell_voltages[79] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_81: + battery_cell_voltages[80] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_82: + battery_cell_voltages[81] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_83: + battery_cell_voltages[82] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_84: + battery_cell_voltages[83] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_85: + battery_cell_voltages[84] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_86: + battery_cell_voltages[85] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_87: + battery_cell_voltages[86] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_88: + battery_cell_voltages[87] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_89: + battery_cell_voltages[88] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_90: + battery_cell_voltages[89] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_91: + battery_cell_voltages[90] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_92: + battery_cell_voltages[91] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_93: + battery_cell_voltages[92] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_94: + battery_cell_voltages[93] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_95: + battery_cell_voltages[94] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + case POLL_7E7_CELL_96: + battery_cell_voltages[95] = ((((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]) * 5000) / 65535); + break; + default: + break; + } + default: + break; + } +} + +void transmit_can_battery() { + unsigned long currentMillis = millis(); + + //Send 20ms message + if (currentMillis - previousMillis20ms >= INTERVAL_20_MS) { + // Check if sending of CAN messages has been delayed too much. + if ((currentMillis - previousMillis20ms >= INTERVAL_20_MS_DELAYED) && (currentMillis > BOOTUP_TIME)) { + set_event(EVENT_CAN_OVERRUN, (currentMillis - previousMillis20ms)); + } else { + clear_event(EVENT_CAN_OVERRUN); + } + previousMillis20ms = currentMillis; + transmit_can_frame(&BOLT_778, can_config.battery); + } + + //Send 100ms message + if (currentMillis - previousMillis100ms >= INTERVAL_100_MS) { + previousMillis100ms = currentMillis; + + // Update current poll from the 7E7 array + currentpoll_7E7 = poll_commands_7E7[poll_index_7E7]; + poll_index_7E7 = (poll_index_7E7 + 1) % 108; + + BOLT_POLL_7E7.data.u8[2] = (uint8_t)((currentpoll_7E7 & 0xFF00) >> 8); + BOLT_POLL_7E7.data.u8[3] = (uint8_t)(currentpoll_7E7 & 0x00FF); + + transmit_can_frame(&BOLT_POLL_7E7, can_config.battery); + } + + //Send 120ms message + if (currentMillis - previousMillis120ms >= 120) { + previousMillis120ms = currentMillis; + + // Update current poll from the 7E4 array + currentpoll_7E4 = poll_commands_7E4[poll_index_7E4]; + poll_index_7E4 = (poll_index_7E4 + 1) % 19; + + BOLT_POLL_7E4.data.u8[2] = (uint8_t)((currentpoll_7E4 & 0xFF00) >> 8); + BOLT_POLL_7E4.data.u8[3] = (uint8_t)(currentpoll_7E4 & 0x00FF); + + transmit_can_frame(&BOLT_POLL_7E4, can_config.battery); + } +} + +void setup_battery(void) { // Performs one time setup at startup + strncpy(datalayer.system.info.battery_protocol, "Chevrolet Bolt EV/Opel Ampera-e", 63); + datalayer.system.info.battery_protocol[63] = '\0'; + datalayer.battery.info.number_of_cells = 96; + datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; + datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; + datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV; + datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV; + datalayer.battery.info.max_cell_voltage_deviation_mV = MAX_CELL_DEVIATION_MV; + datalayer.system.status.battery_allows_contactor_closing = true; +} + +#endif diff --git a/Software/src/battery/BOLT-AMPERA-BATTERY.h b/Software/src/battery/BOLT-AMPERA-BATTERY.h new file mode 100644 index 00000000..56a515fd --- /dev/null +++ b/Software/src/battery/BOLT-AMPERA-BATTERY.h @@ -0,0 +1,146 @@ +#ifndef BOLT_AMPERA_BATTERY_H +#define BOLT_AMPERA_BATTERY_H +#include +#include "../include.h" + +#define BATTERY_SELECTED + +#define MAX_PACK_VOLTAGE_DV 4150 //5000 = 500.0V +#define MIN_PACK_VOLTAGE_DV 2500 +#define MAX_CELL_DEVIATION_MV 500 +#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 + +#define POLL_7E4_CAPACITY_EST_GEN1 0x41A3 +#define POLL_7E4_CAPACITY_EST_GEN2 0x45F9 +#define POLL_7E4_SOC_DISPLAY 0x8334 +#define POLL_7E4_SOC_RAW_HIGHPREC 0x43AF +#define POLL_7E4_MAX_TEMPERATURE 0x4349 +#define POLL_7E4_MIN_TEMPERATURE 0x434A +#define POLL_7E4_MIN_CELL_V 0x4329 +#define POLL_7E4_MAX_CELL_V 0x432B +#define POLL_7E4_INTERNAL_RES 0x40E9 +#define POLL_7E4_LOWEST_CELL_NUMBER 0x433B +#define POLL_7E4_HIGHEST_CELL_NUMBER 0x433C +#define POLL_7E4_VOLTAGE 0x432D +#define POLL_7E4_VEHICLE_ISOLATION 0x41EC +#define POLL_7E4_ISOLATION_TEST_KOHM 0x43A6 +#define POLL_7E4_HV_LOCKED_OUT 0x44F8 +#define POLL_7E4_CRASH_EVENT 0x4522 +#define POLL_7E4_HVIL 0x4310 +#define POLL_7E4_HVIL_STATUS 0x4311 +#define POLL_7E4_CURRENT 0x4356 + +#define POLL_7E7_CURRENT 0x40D4 +#define POLL_7E7_5V_REF 0x40D3 +#define POLL_7E7_MODULE_TEMP_1 0x40D7 +#define POLL_7E7_MODULE_TEMP_2 0x40D9 +#define POLL_7E7_MODULE_TEMP_3 0x40DB +#define POLL_7E7_MODULE_TEMP_4 0x40DD +#define POLL_7E7_MODULE_TEMP_5 0x40DF +#define POLL_7E7_MODULE_TEMP_6 0x40E1 +#define POLL_7E7_CELL_AVG_VOLTAGE 0xC218 +#define POLL_7E7_CELL_AVG_VOLTAGE_2 0x44B9 +#define POLL_7E7_TERMINAL_VOLTAGE 0x82A3 +#define POLL_7E7_IGNITION_POWER_MODE 0x8002 +#define POLL_7E7_CELL_01 0x4181 +#define POLL_7E7_CELL_02 0x4182 +#define POLL_7E7_CELL_03 0x4183 +#define POLL_7E7_CELL_04 0x4184 +#define POLL_7E7_CELL_05 0x4185 +#define POLL_7E7_CELL_06 0x4186 +#define POLL_7E7_CELL_07 0x4187 +#define POLL_7E7_CELL_08 0x4188 +#define POLL_7E7_CELL_09 0x4189 +#define POLL_7E7_CELL_10 0x418A +#define POLL_7E7_CELL_11 0x418B +#define POLL_7E7_CELL_12 0x418C +#define POLL_7E7_CELL_13 0x418D +#define POLL_7E7_CELL_14 0x418E +#define POLL_7E7_CELL_15 0x418F +#define POLL_7E7_CELL_16 0x4190 +#define POLL_7E7_CELL_17 0x4191 +#define POLL_7E7_CELL_18 0x4192 +#define POLL_7E7_CELL_19 0x4193 +#define POLL_7E7_CELL_20 0x4194 +#define POLL_7E7_CELL_21 0x4195 +#define POLL_7E7_CELL_22 0x4196 +#define POLL_7E7_CELL_23 0x4197 +#define POLL_7E7_CELL_24 0x4198 +#define POLL_7E7_CELL_25 0x4199 +#define POLL_7E7_CELL_26 0x419A +#define POLL_7E7_CELL_27 0x419B +#define POLL_7E7_CELL_28 0x419C +#define POLL_7E7_CELL_29 0x419D +#define POLL_7E7_CELL_30 0x419E +#define POLL_7E7_CELL_31 0x419F +#define POLL_7E7_CELL_32 0x4200 +#define POLL_7E7_CELL_33 0x4201 +#define POLL_7E7_CELL_34 0x4202 +#define POLL_7E7_CELL_35 0x4203 +#define POLL_7E7_CELL_36 0x4204 +#define POLL_7E7_CELL_37 0x4205 +#define POLL_7E7_CELL_38 0x4206 +#define POLL_7E7_CELL_39 0x4207 +#define POLL_7E7_CELL_40 0x4208 +#define POLL_7E7_CELL_41 0x4209 +#define POLL_7E7_CELL_42 0x420A +#define POLL_7E7_CELL_43 0x420B +#define POLL_7E7_CELL_44 0x420C +#define POLL_7E7_CELL_45 0x420D +#define POLL_7E7_CELL_46 0x420E +#define POLL_7E7_CELL_47 0x420F +#define POLL_7E7_CELL_48 0x4210 +#define POLL_7E7_CELL_49 0x4211 +#define POLL_7E7_CELL_50 0x4212 +#define POLL_7E7_CELL_51 0x4213 +#define POLL_7E7_CELL_52 0x4214 +#define POLL_7E7_CELL_53 0x4215 +#define POLL_7E7_CELL_54 0x4216 +#define POLL_7E7_CELL_55 0x4217 +#define POLL_7E7_CELL_56 0x4218 +#define POLL_7E7_CELL_57 0x4219 +#define POLL_7E7_CELL_58 0x421A +#define POLL_7E7_CELL_59 0x421B +#define POLL_7E7_CELL_60 0x421C +#define POLL_7E7_CELL_61 0x421D +#define POLL_7E7_CELL_62 0x421E +#define POLL_7E7_CELL_63 0x421F +#define POLL_7E7_CELL_64 0x4220 +#define POLL_7E7_CELL_65 0x4221 +#define POLL_7E7_CELL_66 0x4222 +#define POLL_7E7_CELL_67 0x4223 +#define POLL_7E7_CELL_68 0x4224 +#define POLL_7E7_CELL_69 0x4225 +#define POLL_7E7_CELL_70 0x4226 +#define POLL_7E7_CELL_71 0x4227 +#define POLL_7E7_CELL_72 0x4228 +#define POLL_7E7_CELL_73 0x4229 +#define POLL_7E7_CELL_74 0x422A +#define POLL_7E7_CELL_75 0x422B +#define POLL_7E7_CELL_76 0x422C +#define POLL_7E7_CELL_77 0x422D +#define POLL_7E7_CELL_78 0x422E +#define POLL_7E7_CELL_79 0x422F +#define POLL_7E7_CELL_80 0x4230 +#define POLL_7E7_CELL_81 0x4231 +#define POLL_7E7_CELL_82 0x4232 +#define POLL_7E7_CELL_83 0x4233 +#define POLL_7E7_CELL_84 0x4234 +#define POLL_7E7_CELL_85 0x4235 +#define POLL_7E7_CELL_86 0x4236 +#define POLL_7E7_CELL_87 0x4237 +#define POLL_7E7_CELL_88 0x4238 +#define POLL_7E7_CELL_89 0x4239 +#define POLL_7E7_CELL_90 0x423A +#define POLL_7E7_CELL_91 0x423B +#define POLL_7E7_CELL_92 0x423C +#define POLL_7E7_CELL_93 0x423D +#define POLL_7E7_CELL_94 0x423E +#define POLL_7E7_CELL_95 0x423F +#define POLL_7E7_CELL_96 0x4240 + +void setup_battery(void); +void transmit_can_frame(CAN_frame* tx_frame, int interface); + +#endif diff --git a/Software/src/battery/BYD-ATTO-3-BATTERY.cpp b/Software/src/battery/BYD-ATTO-3-BATTERY.cpp index f0f74da4..892767a4 100644 --- a/Software/src/battery/BYD-ATTO-3-BATTERY.cpp +++ b/Software/src/battery/BYD-ATTO-3-BATTERY.cpp @@ -162,7 +162,7 @@ void update_values_battery() { //This function maps all the values fetched via datalayer_extended.bydAtto3.voltage_polled = BMS_voltage; } -void receive_can_battery(CAN_frame rx_frame) { +void handle_incoming_can_frame_battery(CAN_frame rx_frame) { switch (rx_frame.ID) { //Log values taken with 422V from battery case 0x244: //00,00,00,04,41,0F,20,8B - Static, values never changes between logs break; @@ -292,7 +292,7 @@ void receive_can_battery(CAN_frame rx_frame) { break; } } -void send_can_battery() { +void transmit_can_battery() { unsigned long currentMillis = millis(); //Send 50ms message if (currentMillis - previousMillis50 >= INTERVAL_50_MS) { @@ -334,9 +334,9 @@ void send_can_battery() { ATTO_3_12D.data.u8[6] = (0x0F | (frame6_counter << 4)); ATTO_3_12D.data.u8[7] = (0x09 | (frame7_counter << 4)); - transmit_can(&ATTO_3_12D, can_config.battery); + transmit_can_frame(&ATTO_3_12D, can_config.battery); #ifdef DOUBLE_BATTERY - transmit_can(&ATTO_3_12D, can_config.battery_double); + transmit_can_frame(&ATTO_3_12D, can_config.battery_double); #endif //DOUBLE_BATTERY } // Send 100ms CAN Message @@ -355,9 +355,9 @@ void send_can_battery() { ATTO_3_441.data.u8[7] = 0xF5; } - transmit_can(&ATTO_3_441, can_config.battery); + transmit_can_frame(&ATTO_3_441, can_config.battery); #ifdef DOUBLE_BATTERY - transmit_can(&ATTO_3_441, can_config.battery_double); + transmit_can_frame(&ATTO_3_441, can_config.battery_double); #endif //DOUBLE_BATTERY } // Send 500ms CAN Message @@ -402,9 +402,9 @@ void send_can_battery() { break; } - transmit_can(&ATTO_3_7E7_POLL, can_config.battery); + transmit_can_frame(&ATTO_3_7E7_POLL, can_config.battery); #ifdef DOUBLE_BATTERY - transmit_can(&ATTO_3_7E7_POLL, can_config.battery_double); + transmit_can_frame(&ATTO_3_7E7_POLL, can_config.battery_double); #endif //DOUBLE_BATTERY } } @@ -477,7 +477,7 @@ void update_values_battery2() { //This function maps all the values fetched via datalayer.battery2.status.temperature_max_dC = battery2_calc_max_temperature * 10; } -void receive_can_battery2(CAN_frame rx_frame) { +void handle_incoming_can_frame_battery2(CAN_frame rx_frame) { switch (rx_frame.ID) { //Log values taken with 422V from battery2 case 0x244: //00,00,00,04,41,0F,20,8B - Static, values never changes between logs break; diff --git a/Software/src/battery/BYD-ATTO-3-BATTERY.h b/Software/src/battery/BYD-ATTO-3-BATTERY.h index 1829ec6b..57f943ff 100644 --- a/Software/src/battery/BYD-ATTO-3-BATTERY.h +++ b/Software/src/battery/BYD-ATTO-3-BATTERY.h @@ -17,6 +17,6 @@ #define MIN_CELL_VOLTAGE_MV 2800 //Battery is put into emergency stop if one cell goes below this value void setup_battery(void); -void transmit_can(CAN_frame* tx_frame, int interface); +void transmit_can_frame(CAN_frame* tx_frame, int interface); #endif diff --git a/Software/src/battery/CELLPOWER-BMS.cpp b/Software/src/battery/CELLPOWER-BMS.cpp index 80c981c6..9a73ed40 100644 --- a/Software/src/battery/CELLPOWER-BMS.cpp +++ b/Software/src/battery/CELLPOWER-BMS.cpp @@ -213,7 +213,7 @@ void update_values_battery() { //TODO, shall we react on this? } } -void receive_can_battery(CAN_frame rx_frame) { +void handle_incoming_can_frame_battery(CAN_frame rx_frame) { switch (rx_frame.ID) { case 0x1A4: //PDO1_TX - 200ms @@ -316,7 +316,7 @@ void receive_can_battery(CAN_frame rx_frame) { } } -void send_can_battery() { +void transmit_can_battery() { unsigned long currentMillis = millis(); // Send 1s CAN Message if (currentMillis - previousMillis1s >= INTERVAL_1_S) { @@ -324,10 +324,10 @@ void send_can_battery() { previousMillis1s = currentMillis; /* - transmit_can(&CELLPOWER_18FF50E9, can_config.battery); - transmit_can(&CELLPOWER_18FF50E8, can_config.battery); - transmit_can(&CELLPOWER_18FF50E7, can_config.battery); - transmit_can(&CELLPOWER_18FF50E5, can_config.battery); + transmit_can_frame(&CELLPOWER_18FF50E9, can_config.battery); + transmit_can_frame(&CELLPOWER_18FF50E8, can_config.battery); + transmit_can_frame(&CELLPOWER_18FF50E7, can_config.battery); + transmit_can_frame(&CELLPOWER_18FF50E5, can_config.battery); */ } } diff --git a/Software/src/battery/CELLPOWER-BMS.h b/Software/src/battery/CELLPOWER-BMS.h index e1956b74..c5da0ece 100644 --- a/Software/src/battery/CELLPOWER-BMS.h +++ b/Software/src/battery/CELLPOWER-BMS.h @@ -14,6 +14,6 @@ #define NATIVECAN_250KBPS void setup_battery(void); -void transmit_can(CAN_frame* tx_frame, int interface); +void transmit_can_frame(CAN_frame* tx_frame, int interface); #endif diff --git a/Software/src/battery/CHADEMO-BATTERY.cpp b/Software/src/battery/CHADEMO-BATTERY.cpp index 14720065..f99d61ed 100644 --- a/Software/src/battery/CHADEMO-BATTERY.cpp +++ b/Software/src/battery/CHADEMO-BATTERY.cpp @@ -197,13 +197,13 @@ inline void process_vehicle_charging_session(CAN_frame rx_frame) { x102_chg_session.ChargingCurrentRequest = newChargingCurrentRequest; x102_chg_session.TargetBatteryVoltage = newTargetBatteryVoltage; -#ifdef DEBUG_VIA_USB +#ifdef DEBUG_LOG //Note on p131 uint8_t chargingrate = 0; if (x100_chg_lim.ConstantOfChargingRateIndication > 0) { chargingrate = x102_chg_session.StateOfCharge / x100_chg_lim.ConstantOfChargingRateIndication * 100; - Serial.print("Charge Rate (kW): "); - Serial.println(chargingrate); + logging.print("Charge Rate (kW): "); + logging.println(chargingrate); } #endif @@ -217,40 +217,40 @@ inline void process_vehicle_charging_session(CAN_frame rx_frame) { */ if ((CHADEMO_Status == CHADEMO_INIT && vehicle_permission) || (x102_chg_session.s.status.StatusVehicleChargingEnabled && !vehicle_permission)) { -#ifdef DEBUG_VIA_USB - Serial.println("Inconsistent charge/discharge state."); +#ifdef DEBUG_LOG + logging.println("Inconsistent charge/discharge state."); #endif CHADEMO_Status = CHADEMO_FAULT; return; } if (x102_chg_session.f.fault.FaultBatteryOverVoltage) { -#ifdef DEBUG_VIA_USB - Serial.println("Vehicle indicates fault, battery over voltage."); +#ifdef DEBUG_LOG + logging.println("Vehicle indicates fault, battery over voltage."); #endif CHADEMO_Status = CHADEMO_STOP; return; } if (x102_chg_session.f.fault.FaultBatteryUnderVoltage) { -#ifdef DEBUG_VIA_USB - Serial.println("Vehicle indicates fault, battery under voltage."); +#ifdef DEBUG_LOG + logging.println("Vehicle indicates fault, battery under voltage."); #endif CHADEMO_Status = CHADEMO_STOP; return; } if (x102_chg_session.f.fault.FaultBatteryCurrentDeviation) { -#ifdef DEBUG_VIA_USB - Serial.println("Vehicle indicates fault, battery current deviation. Possible EVSE issue?"); +#ifdef DEBUG_LOG + logging.println("Vehicle indicates fault, battery current deviation. Possible EVSE issue?"); #endif CHADEMO_Status = CHADEMO_STOP; return; } if (x102_chg_session.f.fault.FaultBatteryVoltageDeviation) { -#ifdef DEBUG_VIA_USB - Serial.println("Vehicle indicates fault, battery voltage deviation. Possible EVSE issue?"); +#ifdef DEBUG_LOG + logging.println("Vehicle indicates fault, battery voltage deviation. Possible EVSE issue?"); #endif CHADEMO_Status = CHADEMO_STOP; return; @@ -264,8 +264,8 @@ inline void process_vehicle_charging_session(CAN_frame rx_frame) { //FIXME condition nesting or more stanzas needed here for clear determination of cessation reason if (CHADEMO_Status == CHADEMO_POWERFLOW && EVSE_mode == CHADEMO_CHARGE && !vehicle_permission) { -#ifdef DEBUG_VIA_USB - Serial.println("State of charge ceiling reached or charging interrupted, stop charging"); +#ifdef DEBUG_LOG + logging.println("State of charge ceiling reached or charging interrupted, stop charging"); #endif CHADEMO_Status = CHADEMO_STOP; return; @@ -273,8 +273,8 @@ inline void process_vehicle_charging_session(CAN_frame rx_frame) { if (vehicle_permission && CHADEMO_Status == CHADEMO_NEGOTIATE) { CHADEMO_Status = CHADEMO_EV_ALLOWED; -#ifdef DEBUG_VIA_USB - Serial.println("STATE shift to CHADEMO_EV_ALLOWED in process_vehicle_charging_session()"); +#ifdef DEBUG_LOG + logging.println("STATE shift to CHADEMO_EV_ALLOWED in process_vehicle_charging_session()"); #endif return; } @@ -284,22 +284,22 @@ inline void process_vehicle_charging_session(CAN_frame rx_frame) { // consider relocating if (vehicle_permission && CHADEMO_Status == CHADEMO_EVSE_PREPARE && priorTargetBatteryVoltage == 0 && newTargetBatteryVoltage > 0 && x102_chg_session.s.status.StatusVehicleChargingEnabled) { -#ifdef DEBUG_VIA_USB - Serial.println("STATE SHIFT to EVSE_START reached in process_vehicle_charging_session()"); +#ifdef DEBUG_LOG + logging.println("STATE SHIFT to EVSE_START reached in process_vehicle_charging_session()"); #endif CHADEMO_Status = CHADEMO_EVSE_START; return; } if (vehicle_permission && evse_permission && CHADEMO_Status == CHADEMO_POWERFLOW) { -#ifdef DEBUG_VIA_USB - Serial.println("updating vehicle request in process_vehicle_charging_session()"); +#ifdef DEBUG_LOG + logging.println("updating vehicle request in process_vehicle_charging_session()"); #endif return; } -#ifdef DEBUG_VIA_USB - Serial.println("UNHANDLED STATE IN process_vehicle_charging_session()"); +#ifdef DEBUG_LOG + logging.println("UNHANDLED STATE IN process_vehicle_charging_session()"); #endif return; } @@ -312,20 +312,20 @@ inline void process_vehicle_charging_limits(CAN_frame rx_frame) { x200_discharge_limits.MinimumBatteryDischargeLevel = rx_frame.data.u8[6]; x200_discharge_limits.MaxRemainingCapacityForCharging = rx_frame.data.u8[7]; -#ifdef DEBUG_VIA_USB +#ifdef DEBUG_LOG /* unsigned long currentMillis = millis(); if (currentMillis - previousMillis5000 >= INTERVAL_5_S) { previousMillis5000 = currentMillis; - Serial.println("x200 Max remaining capacity for charging/discharging:"); + logging.println("x200 Max remaining capacity for charging/discharging:"); // initially this is set to 0, which is represented as 0xFF - Serial.println(0xFF - x200_discharge_limits.MaxRemainingCapacityForCharging); + logging.println(0xFF - x200_discharge_limits.MaxRemainingCapacityForCharging); } */ #endif if (get_measured_voltage() <= x200_discharge_limits.MinimumDischargeVoltage && CHADEMO_Status > CHADEMO_NEGOTIATE) { -#ifdef DEBUG_VIA_USB - Serial.println("x200 minimum discharge voltage met or exceeded, stopping."); +#ifdef DEBUG_LOG + logging.println("x200 minimum discharge voltage met or exceeded, stopping."); #endif CHADEMO_Status = CHADEMO_STOP; } @@ -341,13 +341,13 @@ inline void process_vehicle_discharge_estimate(CAN_frame rx_frame) { x201_discharge_estimate.ApproxDischargeCompletionTime = ((rx_frame.data.u8[2] << 8) | rx_frame.data.u8[1]); x201_discharge_estimate.AvailableVehicleEnergy = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[3]); -#ifdef DEBUG_VIA_USB +#ifdef DEBUG_LOG if (currentMillis - previousMillis5000 >= INTERVAL_5_S) { previousMillis5000 = currentMillis; - Serial.print("x201 availabile vehicle energy, completion time: "); - Serial.println(x201_discharge_estimate.AvailableVehicleEnergy); - Serial.print("x201 approx vehicle completion time: "); - Serial.println(x201_discharge_estimate.ApproxDischargeCompletionTime); + logging.print("x201 availabile vehicle energy, completion time: "); + logging.println(x201_discharge_estimate.AvailableVehicleEnergy); + logging.print("x201 approx vehicle completion time: "); + logging.println(x201_discharge_estimate.ApproxDischargeCompletionTime); } #endif } @@ -367,19 +367,19 @@ inline void process_vehicle_vendor_ID(CAN_frame rx_frame) { ((rx_frame.data.u8[2] << 8) | rx_frame.data.u8[1]); //Actually more bytes, but not needed for our purpose } -void receive_can_battery(CAN_frame rx_frame) { +void handle_incoming_can_frame_battery(CAN_frame rx_frame) { #ifdef CH_CAN_DEBUG - Serial.print(millis()); // Example printout, time, ID, length, data: 7553 1DB 8 FF C0 B9 EA 0 0 2 5D - Serial.print(" "); - Serial.print(rx_frame.ID, HEX); - Serial.print(" "); - Serial.print(rx_frame.DLC); - Serial.print(" "); + logging.print(millis()); // Example printout, time, ID, length, data: 7553 1DB 8 FF C0 B9 EA 0 0 2 5D + logging.print(" "); + logging.print(rx_frame.ID, HEX); + logging.print(" "); + logging.print(rx_frame.DLC); + logging.print(" "); for (int i = 0; i < rx_frame.DLC; ++i) { - Serial.print(rx_frame.data.u8[i], HEX); - Serial.print(" "); + logging.print(rx_frame.data.u8[i], HEX); + logging.print(" "); } - Serial.println(""); + logging.println(""); #endif // CHADEMO coexists with a CAN-based shunt. Only process CHADEMO-specific IDs @@ -657,7 +657,7 @@ void update_evse_discharge_capabilities(CAN_frame& f) { CHADEMO_208.data.u8[7] = highByte(x208_evse_dischg_cap.lower_threshold_voltage); } -void send_can_battery() { +void transmit_can_battery() { unsigned long currentMillis = millis(); @@ -693,8 +693,8 @@ void send_can_battery() { * that is the limiting factor. Therefore, we * can generally send as is without tweaks here. */ - transmit_can(&CHADEMO_108, can_config.battery); - transmit_can(&CHADEMO_109, can_config.battery); + transmit_can_frame(&CHADEMO_108, can_config.battery); + transmit_can_frame(&CHADEMO_109, can_config.battery); /* TODO for dynamic control: can send x118 with byte 6 bit 0 set to 0 for 1s (before flipping back to 1) as a way of giving vehicle a chance to update 101.1 and 101.2 * within 6 seconds of x118 toggle. @@ -703,9 +703,9 @@ void send_can_battery() { */ if (EVSE_mode == CHADEMO_DISCHARGE || EVSE_mode == CHADEMO_BIDIRECTIONAL) { - transmit_can(&CHADEMO_208, can_config.battery); + transmit_can_frame(&CHADEMO_208, can_config.battery); if (x201_received) { - transmit_can(&CHADEMO_209, can_config.battery); + transmit_can_frame(&CHADEMO_209, can_config.battery); x209_sent = true; } } @@ -713,11 +713,11 @@ void send_can_battery() { // TODO need an update_evse_dynamic_control(..) function above before we send 118 // 110.0.0 if (x102_chg_session.ControlProtocolNumberEV >= 0x03) { //Only send the following on Chademo 2.0 vehicles? -#ifdef DEBUG_VIA_USB +#ifdef DEBUG_LOG //FIXME REMOVE - Serial.println("REMOVE: proto 2.0"); + logging.println("REMOVE: proto 2.0"); #endif - transmit_can(&CHADEMO_118, can_config.battery); + transmit_can_frame(&CHADEMO_118, can_config.battery); } } } @@ -753,15 +753,15 @@ void handle_chademo_sequence() { /* ------------------- State override conditions checks ------------------- */ /* ------------------------------------------------------------------------------ */ if (CHADEMO_Status >= CHADEMO_EV_ALLOWED && x102_chg_session.s.status.StatusVehicleShifterPosition) { -#ifdef DEBUG_VIA_USB - Serial.println("Vehicle is not parked, abort."); +#ifdef DEBUG_LOG + logging.println("Vehicle is not parked, abort."); #endif CHADEMO_Status = CHADEMO_STOP; } if (CHADEMO_Status >= CHADEMO_EV_ALLOWED && !vehicle_permission) { -#ifdef DEBUG_VIA_USB - Serial.println("Vehicle charge/discharge permission ended, stop."); +#ifdef DEBUG_LOG + logging.println("Vehicle charge/discharge permission ended, stop."); #endif CHADEMO_Status = CHADEMO_STOP; } @@ -775,24 +775,24 @@ void handle_chademo_sequence() { plug_inserted = digitalRead(CHADEMO_PIN_7); if (!plug_inserted) { -#ifdef DEBUG_VIA_USB +#ifdef DEBUG_LOG // Commented unless needed for debug -// Serial.println("CHADEMO plug is not inserted."); +// logging.println("CHADEMO plug is not inserted."); #endif return; } CHADEMO_Status = CHADEMO_CONNECTED; -#ifdef DEBUG_VIA_USB - Serial.println("CHADEMO plug is inserted. Provide EVSE power to vehicle to trigger initialization."); +#ifdef DEBUG_LOG + logging.println("CHADEMO plug is inserted. Provide EVSE power to vehicle to trigger initialization."); #endif break; case CHADEMO_CONNECTED: -#ifdef DEBUG_VIA_USB +#ifdef DEBUG_LOG // Commented unless needed for debug - //Serial.println("CHADEMO_CONNECTED State"); + //logging.println("CHADEMO_CONNECTED State"); #endif /* plug_inserted is .. essentially a volatile of sorts, so verify */ if (plug_inserted) { @@ -810,8 +810,8 @@ void handle_chademo_sequence() { * with timers to have higher confidence of certain conditions hitting * a steady state */ -#ifdef DEBUG_VIA_USB - Serial.println("CHADEMO plug is not inserted, cannot connect d2 relay to begin initialization."); +#ifdef DEBUG_LOG + logging.println("CHADEMO plug is not inserted, cannot connect d2 relay to begin initialization."); #endif CHADEMO_Status = CHADEMO_IDLE; } @@ -819,10 +819,10 @@ void handle_chademo_sequence() { case CHADEMO_INIT: /* Transient state while awaiting CAN from Vehicle. * Used for triggers/error handling elsewhere; - * State change to CHADEMO_NEGOTIATE occurs in receive_can_battery(..) + * State change to CHADEMO_NEGOTIATE occurs in handle_incoming_can_frame_battery(..) */ -#ifdef DEBUG_VIA_USB -// Serial.println("Awaiting initial vehicle CAN to trigger negotiation"); +#ifdef DEBUG_LOG +// logging.println("Awaiting initial vehicle CAN to trigger negotiation"); #endif evse_init(); break; @@ -830,16 +830,16 @@ void handle_chademo_sequence() { /* Vehicle and EVSE dance */ //TODO if pin 4 / j goes high, -#ifdef DEBUG_VIA_USB +#ifdef DEBUG_LOG // Commented unless needed for debug -// Serial.println("CHADEMO_NEGOTIATE State"); +// logging.println("CHADEMO_NEGOTIATE State"); #endif x109_evse_state.s.status.ChgDischStopControl = 1; break; case CHADEMO_EV_ALLOWED: -#ifdef DEBUG_VIA_USB +#ifdef DEBUG_LOG // Commented unless needed for debug - Serial.println("CHADEMO_EV_ALLOWED State"); + logging.println("CHADEMO_EV_ALLOWED State"); #endif // If we are in this state, vehicle_permission was already set to true...but re-verify // that pin 4 (j) reads high @@ -855,9 +855,9 @@ void handle_chademo_sequence() { } break; case CHADEMO_EVSE_PREPARE: -#ifdef DEBUG_VIA_USB +#ifdef DEBUG_LOG // Commented unless needed for debug - Serial.println("CHADEMO_EVSE_PREPARE State"); + logging.println("CHADEMO_EVSE_PREPARE State"); #endif /* TODO voltage check of output < 20v * insulation test hypothetically happens here before triggering PIN 10 high @@ -878,7 +878,7 @@ void handle_chademo_sequence() { digitalWrite(CHADEMO_PIN_10, HIGH); evse_permission = true; } else { - Serial.println("Insulation check measures > 20v "); + logging.println("Insulation check measures > 20v "); } // likely unnecessary but just to be sure. consider removal @@ -891,9 +891,9 @@ void handle_chademo_sequence() { //state changes to CHADEMO_EVSE_START only upon receipt of charging session request break; case CHADEMO_EVSE_START: -#ifdef DEBUG_VIA_USB +#ifdef DEBUG_LOG // Commented unless needed for debug - Serial.println("CHADEMO_EVSE_START State"); + logging.println("CHADEMO_EVSE_START State"); #endif datalayer.system.status.battery_allows_contactor_closing = true; x109_evse_state.s.status.ChgDischStopControl = 1; @@ -901,8 +901,8 @@ void handle_chademo_sequence() { CHADEMO_Status = CHADEMO_EVSE_CONTACTORS_ENABLED; -#ifdef DEBUG_VIA_USB - Serial.println("Initiating contactors"); +#ifdef DEBUG_LOG + logging.println("Initiating contactors"); #endif /* break rather than fall through because contactors are not instantaneous; @@ -911,17 +911,17 @@ void handle_chademo_sequence() { break; case CHADEMO_EVSE_CONTACTORS_ENABLED: -#ifdef DEBUG_VIA_USB +#ifdef DEBUG_LOG // Commented unless needed for debug - Serial.println("CHADEMO_EVSE_CONTACTORS State"); + logging.println("CHADEMO_EVSE_CONTACTORS State"); #endif /* check whether contactors ready, because externally dependent upon inverter allow during discharge */ if (contactors_ready) { -#ifdef DEBUG_VIA_USB - Serial.println("Contactors ready"); - Serial.print("Voltage: "); - Serial.println(get_measured_voltage()); +#ifdef DEBUG_LOG + logging.println("Contactors ready"); + logging.print("Voltage: "); + logging.println(get_measured_voltage()); #endif /* transition to POWERFLOW state if discharge compatible on both sides */ if (x109_evse_state.discharge_compatible && x102_chg_session.s.status.StatusVehicleDischargeCompatible && @@ -941,9 +941,9 @@ void handle_chademo_sequence() { /* break or fall through ? TODO */ break; case CHADEMO_POWERFLOW: -#ifdef DEBUG_VIA_USB +#ifdef DEBUG_LOG // Commented unless needed for debug - Serial.println("CHADEMO_POWERFLOW State"); + logging.println("CHADEMO_POWERFLOW State"); #endif /* POWERFLOW for charging, discharging, and bidirectional */ /* Interpretation */ @@ -961,8 +961,8 @@ void handle_chademo_sequence() { } if (get_measured_voltage() <= x200_discharge_limits.MinimumDischargeVoltage) { -#ifdef DEBUG_VIA_USB - Serial.println("x200 minimum discharge voltage met or exceeded, stopping."); +#ifdef DEBUG_LOG + logging.println("x200 minimum discharge voltage met or exceeded, stopping."); #endif CHADEMO_Status = CHADEMO_STOP; } @@ -972,9 +972,9 @@ void handle_chademo_sequence() { x109_evse_state.s.status.EVSE_status = 1; break; case CHADEMO_STOP: -#ifdef DEBUG_VIA_USB +#ifdef DEBUG_LOG // Commented unless needed for debug - Serial.println("CHADEMO_STOP State"); + logging.println("CHADEMO_STOP State"); #endif /* back to CHADEMO_IDLE after teardown */ x109_evse_state.s.status.ChgDischStopControl = 1; @@ -1000,16 +1000,16 @@ void handle_chademo_sequence() { break; case CHADEMO_FAULT: -#ifdef DEBUG_VIA_USB +#ifdef DEBUG_LOG // Commented unless needed for debug - Serial.println("CHADEMO_FAULT State"); + logging.println("CHADEMO_FAULT State"); #endif /* Once faulted, never departs CHADEMO_FAULT state unless device is power cycled as a safety measure */ x109_evse_state.s.status.EVSE_error = 1; x109_evse_state.s.status.ChgDischError = 1; x109_evse_state.s.status.ChgDischStopControl = 1; -#ifdef DEBUG_VIA_USB - Serial.println("CHADEMO fault encountered, tearing down to make safe"); +#ifdef DEBUG_LOG + logging.println("CHADEMO fault encountered, tearing down to make safe"); #endif digitalWrite(CHADEMO_PIN_10, LOW); digitalWrite(CHADEMO_PIN_2, LOW); @@ -1020,8 +1020,8 @@ void handle_chademo_sequence() { break; default: -#ifdef DEBUG_VIA_USB - Serial.println("UNHANDLED CHADEMO_STATE, setting FAULT"); +#ifdef DEBUG_LOG + logging.println("UNHANDLED CHADEMO_STATE, setting FAULT"); #endif CHADEMO_Status = CHADEMO_FAULT; break; diff --git a/Software/src/battery/CHADEMO-BATTERY.h b/Software/src/battery/CHADEMO-BATTERY.h index fa6545a9..eacc2fd1 100644 --- a/Software/src/battery/CHADEMO-BATTERY.h +++ b/Software/src/battery/CHADEMO-BATTERY.h @@ -13,6 +13,6 @@ #define ISA_SHUNT void setup_battery(void); -void transmit_can(CAN_frame* tx_frame, int interface); +void transmit_can_frame(CAN_frame* tx_frame, int interface); #endif diff --git a/Software/src/battery/CHADEMO-SHUNTS.cpp b/Software/src/battery/CHADEMO-SHUNTS.cpp index 6ca55ca7..61ca170b 100644 --- a/Software/src/battery/CHADEMO-SHUNTS.cpp +++ b/Software/src/battery/CHADEMO-SHUNTS.cpp @@ -91,17 +91,17 @@ void ISA_handleFrame(CAN_frame* frame) { case 0x510: case 0x511: - Serial.print(millis()); // Example printout, time, ID, length, data: 7553 1DB 8 FF C0 B9 EA 0 0 2 5D - Serial.print(" "); - Serial.print(frame->ID, HEX); - Serial.print(" "); - Serial.print(frame->DLC); - Serial.print(" "); + logging.print(millis()); // Example printout, time, ID, length, data: 7553 1DB 8 FF C0 B9 EA 0 0 2 5D + logging.print(" "); + logging.print(frame->ID, HEX); + logging.print(" "); + logging.print(frame->DLC); + logging.print(" "); for (int i = 0; i < frame->DLC; ++i) { - Serial.print(frame->data.u8[i], HEX); - Serial.print(" "); + logging.print(frame->data.u8[i], HEX); + logging.print(" "); } - Serial.println(""); + logging.println(""); break; case 0x521: @@ -245,8 +245,8 @@ void ISA_initialize() { ISA_STOP(); delay(500); for (int i = 0; i < 8; i++) { - Serial.print("ISA Initialization "); - Serial.println(i); + logging.print("ISA Initialization "); + logging.println(i); outframe.data.u8[0] = (0x20 + i); outframe.data.u8[1] = 0x02; @@ -257,7 +257,7 @@ void ISA_initialize() { outframe.data.u8[6] = 0x00; outframe.data.u8[7] = 0x00; - transmit_can(&outframe, can_config.battery); + transmit_can_frame(&outframe, can_config.battery); delay(500); } @@ -271,7 +271,7 @@ void ISA_initialize() { } void ISA_STOP() { - Serial.println("ISA STOP"); + logging.println("ISA STOP"); outframe.data.u8[0] = 0x34; outframe.data.u8[1] = 0x00; @@ -282,11 +282,11 @@ void ISA_STOP() { outframe.data.u8[6] = 0x00; outframe.data.u8[7] = 0x00; - transmit_can(&outframe, can_config.battery); + transmit_can_frame(&outframe, can_config.battery); } void ISA_sendSTORE() { - Serial.println("ISA send STORE"); + logging.println("ISA send STORE"); outframe.data.u8[0] = 0x32; outframe.data.u8[1] = 0x00; @@ -297,11 +297,11 @@ void ISA_sendSTORE() { outframe.data.u8[6] = 0x00; outframe.data.u8[7] = 0x00; - transmit_can(&outframe, can_config.battery); + transmit_can_frame(&outframe, can_config.battery); } void ISA_START() { - Serial.println("ISA START"); + logging.println("ISA START"); outframe.data.u8[0] = 0x34; outframe.data.u8[1] = 0x01; @@ -312,12 +312,12 @@ void ISA_START() { outframe.data.u8[6] = 0x00; outframe.data.u8[7] = 0x00; - transmit_can(&outframe, can_config.battery); + transmit_can_frame(&outframe, can_config.battery); } void ISA_RESTART() { //Has the effect of zeroing AH and KWH - Serial.println("ISA RESTART"); + logging.println("ISA RESTART"); outframe.data.u8[0] = 0x3F; outframe.data.u8[1] = 0x00; @@ -328,7 +328,7 @@ void ISA_RESTART() { outframe.data.u8[6] = 0x00; outframe.data.u8[7] = 0x00; - transmit_can(&outframe, can_config.battery); + transmit_can_frame(&outframe, can_config.battery); } void ISA_deFAULT() { @@ -336,7 +336,7 @@ void ISA_deFAULT() { ISA_STOP(); delay(500); - Serial.println("ISA RESTART to default"); + logging.println("ISA RESTART to default"); outframe.data.u8[0] = 0x3D; outframe.data.u8[1] = 0x00; @@ -347,7 +347,7 @@ void ISA_deFAULT() { outframe.data.u8[6] = 0x00; outframe.data.u8[7] = 0x00; - transmit_can(&outframe, can_config.battery); + transmit_can_frame(&outframe, can_config.battery); delay(500); ISA_START(); @@ -358,7 +358,7 @@ void ISA_initCurrent() { ISA_STOP(); delay(500); - Serial.println("ISA Initialization Current"); + logging.println("ISA Initialization Current"); outframe.data.u8[0] = 0x21; outframe.data.u8[1] = 0x02; @@ -369,7 +369,7 @@ void ISA_initCurrent() { outframe.data.u8[6] = 0x00; outframe.data.u8[7] = 0x00; - transmit_can(&outframe, can_config.battery); + transmit_can_frame(&outframe, can_config.battery); delay(500); ISA_sendSTORE(); @@ -382,8 +382,8 @@ void ISA_initCurrent() { } void ISA_getCONFIG(uint8_t i) { - Serial.print("ISA Get Config "); - Serial.println(i); + logging.print("ISA Get Config "); + logging.println(i); outframe.data.u8[0] = (0x60 + i); outframe.data.u8[1] = 0x00; @@ -394,12 +394,12 @@ void ISA_getCONFIG(uint8_t i) { outframe.data.u8[6] = 0x00; outframe.data.u8[7] = 0x00; - transmit_can(&outframe, can_config.battery); + transmit_can_frame(&outframe, can_config.battery); } void ISA_getCAN_ID(uint8_t i) { - Serial.print("ISA Get CAN ID "); - Serial.println(i); + logging.print("ISA Get CAN ID "); + logging.println(i); outframe.data.u8[0] = (0x50 + i); if (i == 8) @@ -414,12 +414,12 @@ void ISA_getCAN_ID(uint8_t i) { outframe.data.u8[6] = 0x00; outframe.data.u8[7] = 0x00; - transmit_can(&outframe, can_config.battery); + transmit_can_frame(&outframe, can_config.battery); } void ISA_getINFO(uint8_t i) { - Serial.print("ISA Get INFO "); - Serial.println(i, HEX); + logging.print("ISA Get INFO "); + logging.println(i, HEX); outframe.data.u8[0] = (0x70 + i); outframe.data.u8[1] = 0x00; @@ -430,6 +430,6 @@ void ISA_getINFO(uint8_t i) { outframe.data.u8[6] = 0x00; outframe.data.u8[7] = 0x00; - transmit_can(&outframe, can_config.battery); + transmit_can_frame(&outframe, can_config.battery); } #endif diff --git a/Software/src/battery/CHADEMO-SHUNTS.h b/Software/src/battery/CHADEMO-SHUNTS.h index b4ebe3cb..9a40e53c 100644 --- a/Software/src/battery/CHADEMO-SHUNTS.h +++ b/Software/src/battery/CHADEMO-SHUNTS.h @@ -25,6 +25,6 @@ void ISA_getCONFIG(uint8_t i); void ISA_getCAN_ID(uint8_t i); void ISA_getINFO(uint8_t i); -void transmit_can(CAN_frame* tx_frame, int interface); +void transmit_can_frame(CAN_frame* tx_frame, int interface); #endif diff --git a/Software/src/battery/ECMP-BATTERY.cpp b/Software/src/battery/ECMP-BATTERY.cpp new file mode 100644 index 00000000..9bea886a --- /dev/null +++ b/Software/src/battery/ECMP-BATTERY.cpp @@ -0,0 +1,308 @@ +#include "../include.h" +#ifdef STELLANTIS_ECMP_BATTERY +#include // For std::min and std::max +#include "../datalayer/datalayer.h" +#include "../devboard/utils/events.h" +#include "ECMP-BATTERY.h" + +/* TODO: +This integration is still ongoing. Here is what still needs to be done in order to use this battery type +- Find SOC% +- Find battery voltage +- Find current value +- Find/estimate charge/discharge limits +- Find temperature +- Figure out contactor closing + - Which CAN messages need to be sent towards the battery? +*/ + +/* Do not change code below unless you are sure what you are doing */ +static unsigned long previousMillis1000 = 0; // will store last time a 1s CAN Message was sent + +//Actual content messages +CAN_frame ECMP_XXX = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x301, + .data = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; + +static uint16_t battery_voltage = 37000; +static uint16_t battery_soc = 0; +static uint16_t cellvoltages[108]; + +void update_values_battery() { + + datalayer.battery.status.real_soc = battery_soc * 100; + + datalayer.battery.status.soh_pptt; + + datalayer.battery.status.voltage_dV = (battery_voltage / 10); + + datalayer.battery.status.current_dA; + + 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.max_charge_power_W; + + datalayer.battery.status.max_discharge_power_W; + + datalayer.battery.status.temperature_min_dC; + + datalayer.battery.status.temperature_max_dC; + + // Initialize min and max, lets find which cells are min and max! + uint16_t min_cell_mv_value = std::numeric_limits::max(); + uint16_t max_cell_mv_value = 0; + // Loop to find the min and max while ignoring zero values + for (uint8_t i = 0; i < datalayer.battery.info.number_of_cells; ++i) { + uint16_t voltage_mV = datalayer.battery.status.cell_voltages_mV[i]; + if (voltage_mV != 0) { // Skip unread values (0) + min_cell_mv_value = std::min(min_cell_mv_value, voltage_mV); + max_cell_mv_value = std::max(max_cell_mv_value, voltage_mV); + } + } + // If all array values are 0, reset min/max to 3700 + if (min_cell_mv_value == std::numeric_limits::max()) { + min_cell_mv_value = 3700; + max_cell_mv_value = 3700; + } + + datalayer.battery.status.cell_min_voltage_mV = min_cell_mv_value; + datalayer.battery.status.cell_max_voltage_mV = max_cell_mv_value; +} + +void handle_incoming_can_frame_battery(CAN_frame rx_frame) { + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + switch (rx_frame.ID) { + case 0x125: + break; + case 0x127: + break; + case 0x129: + break; + case 0x31B: + break; + case 0x358: + break; + case 0x359: + break; + case 0x361: + battery_voltage = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + break; + case 0x362: + break; + case 0x454: + break; + case 0x494: + break; + case 0x594: + break; + case 0x6D0: + battery_soc = (100 - rx_frame.data.u8[0]); + break; + case 0x6D1: + break; + case 0x6D2: + break; + case 0x6D3: + cellvoltages[0] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[1] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[2] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[3] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + break; + case 0x6D4: + cellvoltages[4] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[5] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[6] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[7] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + break; + case 0x6E0: + break; + case 0x6E1: + cellvoltages[8] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[9] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[10] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[11] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + break; + case 0x6E2: + cellvoltages[12] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[13] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[14] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[15] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + break; + case 0x6E3: + break; + case 0x6E4: + break; + case 0x6E5: + break; + case 0x6E6: + break; + case 0x6E7: + cellvoltages[16] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[17] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[18] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[19] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + break; + case 0x6E8: + cellvoltages[20] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[21] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[22] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[23] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + break; + case 0x6E9: + cellvoltages[24] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[25] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[26] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[27] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + break; + case 0x6EB: + cellvoltages[28] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[29] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[30] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[31] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + break; + case 0x6EC: + //Not available on e-C4 + break; + case 0x6ED: + cellvoltages[32] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[33] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[34] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[35] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + break; + case 0x6EE: + cellvoltages[36] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[37] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[38] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[39] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + break; + case 0x6EF: + cellvoltages[40] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[41] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[42] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[43] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + break; + case 0x6F0: + cellvoltages[44] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[45] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[46] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[47] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + break; + case 0x6F1: + cellvoltages[48] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[49] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[50] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[51] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + break; + case 0x6F2: + cellvoltages[52] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[53] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[54] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[55] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + break; + case 0x6F3: + cellvoltages[56] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[57] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[58] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[59] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + break; + case 0x6F4: + cellvoltages[60] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[61] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[62] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[63] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + break; + case 0x6F5: + cellvoltages[64] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[65] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[66] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[67] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + break; + case 0x6F6: + cellvoltages[68] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[69] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[70] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[71] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + break; + case 0x6F7: + cellvoltages[72] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[73] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[74] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[75] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + break; + case 0x6F8: + cellvoltages[76] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[77] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[78] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[79] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + break; + case 0x6F9: + cellvoltages[80] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[81] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[82] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[83] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + break; + case 0x6FA: + cellvoltages[84] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[85] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[86] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[87] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + break; + case 0x6FB: + cellvoltages[88] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[89] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[90] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[91] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + break; + case 0x6FC: + cellvoltages[92] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[93] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[94] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[95] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + break; + case 0x6FD: + cellvoltages[96] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[97] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[98] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[99] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + break; + case 0x6FE: + cellvoltages[100] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[101] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[102] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[103] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + break; + case 0x6FF: + cellvoltages[104] = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + cellvoltages[105] = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + cellvoltages[106] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; + cellvoltages[107] = (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]; + memcpy(datalayer.battery.status.cell_voltages_mV, cellvoltages, 108 * sizeof(uint16_t)); + break; + case 0x794: + break; + default: + break; + } +} + +void transmit_can_battery() { + unsigned long currentMillis = millis(); + // Send 1s CAN Message + if (currentMillis - previousMillis1000 >= INTERVAL_1_S) { + previousMillis1000 = currentMillis; + } +} + +void setup_battery(void) { // Performs one time setup at startup +#ifdef DEBUG_VIA_USB + Serial.println("ECMP battery selected"); +#endif + datalayer.battery.info.number_of_cells = 108; + datalayer.battery.info.max_design_voltage_dV = 4546; // 454.6V, charging over this is not possible + datalayer.battery.info.min_design_voltage_dV = 3210; // 321.0V, under this, discharging further is disabled +} + +#endif diff --git a/Software/src/battery/ECMP-BATTERY.h b/Software/src/battery/ECMP-BATTERY.h new file mode 100644 index 00000000..a637ad8c --- /dev/null +++ b/Software/src/battery/ECMP-BATTERY.h @@ -0,0 +1,12 @@ +#ifndef STELLANTIS_ECMP_BATTERY_H +#define STELLANTIS_ECMP_BATTERY_H +#include +#include "../include.h" + +#define BATTERY_SELECTED +#define MAX_CELL_DEVIATION_MV 250 + +void setup_battery(void); +void transmit_can_frame(CAN_frame* tx_frame, int interface); + +#endif diff --git a/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp b/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp index 05e6e7c6..ddc63814 100644 --- a/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp +++ b/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp @@ -103,33 +103,33 @@ void update_values_battery() { //This function maps all the values fetched via } if (!BMU_Detected) { -#ifdef DEBUG_VIA_USB - Serial.println("BMU not detected, check wiring!"); +#ifdef DEBUG_LOG + logging.println("BMU not detected, check wiring!"); #endif } -#ifdef DEBUG_VIA_USB - Serial.println("Battery Values"); - Serial.print("BMU SOC: "); - Serial.print(BMU_SOC); - Serial.print(" BMU Current: "); - Serial.print(BMU_Current); - Serial.print(" BMU Battery Voltage: "); - Serial.print(BMU_PackVoltage); - Serial.print(" BMU_Power: "); - Serial.print(BMU_Power); - Serial.print(" Cell max voltage: "); - Serial.print(max_volt_cel); - Serial.print(" Cell min voltage: "); - Serial.print(min_volt_cel); - Serial.print(" Cell max temp: "); - Serial.print(max_temp_cel); - Serial.print(" Cell min temp: "); - Serial.println(min_temp_cel); +#ifdef DEBUG_LOG + logging.println("Battery Values"); + logging.print("BMU SOC: "); + logging.print(BMU_SOC); + logging.print(" BMU Current: "); + logging.print(BMU_Current); + logging.print(" BMU Battery Voltage: "); + logging.print(BMU_PackVoltage); + logging.print(" BMU_Power: "); + logging.print(BMU_Power); + logging.print(" Cell max voltage: "); + logging.print(max_volt_cel); + logging.print(" Cell min voltage: "); + logging.print(min_volt_cel); + logging.print(" Cell max temp: "); + logging.print(max_temp_cel); + logging.print(" Cell min temp: "); + logging.println(min_temp_cel); #endif } -void receive_can_battery(CAN_frame rx_frame) { +void handle_incoming_can_frame_battery(CAN_frame rx_frame) { switch (rx_frame.ID) { case 0x374: //BMU message, 10ms - SOC datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; @@ -207,7 +207,7 @@ void receive_can_battery(CAN_frame rx_frame) { } } -void send_can_battery() { +void transmit_can_battery() { unsigned long currentMillis = millis(); // Send 100ms CAN Message if (currentMillis - previousMillis100 >= INTERVAL_100_MS) { diff --git a/Software/src/battery/IMIEV-CZERO-ION-BATTERY.h b/Software/src/battery/IMIEV-CZERO-ION-BATTERY.h index 70bbf9fb..4191ab67 100644 --- a/Software/src/battery/IMIEV-CZERO-ION-BATTERY.h +++ b/Software/src/battery/IMIEV-CZERO-ION-BATTERY.h @@ -11,6 +11,6 @@ #define MIN_CELL_VOLTAGE_MV 2750 //Battery is put into emergency stop if one cell goes below this value void setup_battery(void); -void transmit_can(CAN_frame* tx_frame, int interface); +void transmit_can_frame(CAN_frame* tx_frame, int interface); #endif diff --git a/Software/src/battery/JAGUAR-IPACE-BATTERY.cpp b/Software/src/battery/JAGUAR-IPACE-BATTERY.cpp index eb13017c..4f499411 100644 --- a/Software/src/battery/JAGUAR-IPACE-BATTERY.cpp +++ b/Software/src/battery/JAGUAR-IPACE-BATTERY.cpp @@ -57,9 +57,9 @@ CAN_frame ipace_keep_alive = {.FD = false, .data = {0x9E, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}};*/ void print_units(char* header, int value, char* units) { - Serial.print(header); - Serial.print(value); - Serial.print(units); + logging.print(header); + logging.print(value); + logging.print(units); } void update_values_battery() { @@ -104,10 +104,10 @@ void update_values_battery() { } /*Finally print out values to serial if configured to do so*/ -#ifdef DEBUG_VIA_USB - Serial.println("Values going to inverter"); - print_units("SOH%: ", (datalayer.battery.status.soh_pptt * 0.01), "% "); - print_units(", SOC%: ", (datalayer.battery.status.reported_soc * 0.01), "% "); +#ifdef DEBUG_LOG + logging.println("Values going to inverter"); + print_units("SOH: ", (datalayer.battery.status.soh_pptt * 0.01), "pct "); + print_units(", SOC: ", (datalayer.battery.status.reported_soc * 0.01), "pct "); print_units(", Voltage: ", (datalayer.battery.status.voltage_dV * 0.1), "V "); print_units(", Max discharge power: ", datalayer.battery.status.max_discharge_power_W, "W "); print_units(", Max charge power: ", datalayer.battery.status.max_charge_power_W, "W "); @@ -115,11 +115,11 @@ void update_values_battery() { print_units(", Min temp: ", (datalayer.battery.status.temperature_min_dC * 0.1), "°C "); print_units(", Max cell voltage: ", datalayer.battery.status.cell_max_voltage_mV, "mV "); print_units(", Min cell voltage: ", datalayer.battery.status.cell_min_voltage_mV, "mV "); - Serial.println(""); + logging.println(""); #endif } -void receive_can_battery(CAN_frame rx_frame) { +void handle_incoming_can_frame_battery(CAN_frame rx_frame) { // Do not log noisy startup messages - there are many ! if (rx_frame.ID == 0 && rx_frame.DLC == 8 && rx_frame.data.u8[0] == 0 && rx_frame.data.u8[1] == 0 && @@ -229,26 +229,26 @@ void receive_can_battery(CAN_frame rx_frame) { } // All CAN messages recieved will be logged via serial - Serial.print(millis()); // Example printout, time, ID, length, data: 7553 1DB 8 FF C0 B9 EA 0 0 2 5D - Serial.print(" "); - Serial.print(rx_frame.ID, HEX); - Serial.print(" "); - Serial.print(rx_frame.DLC); - Serial.print(" "); + logging.print(millis()); // Example printout, time, ID, length, data: 7553 1DB 8 FF C0 B9 EA 0 0 2 5D + logging.print(" "); + logging.print(rx_frame.ID, HEX); + logging.print(" "); + logging.print(rx_frame.DLC); + logging.print(" "); for (int i = 0; i < rx_frame.DLC; ++i) { - Serial.print(rx_frame.data.u8[i], HEX); - Serial.print(" "); + logging.print(rx_frame.data.u8[i], HEX); + logging.print(" "); } - Serial.println(""); + logging.println(""); } -void send_can_battery() { +void transmit_can_battery() { unsigned long currentMillis = millis(); /* Send keep-alive every 200ms */ if (currentMillis - previousMillisKeepAlive >= INTERVAL_200_MS) { previousMillisKeepAlive = currentMillis; - transmit_can(&ipace_keep_alive, can_config.battery); + transmit_can_frame(&ipace_keep_alive, can_config.battery); return; } } diff --git a/Software/src/battery/JAGUAR-IPACE-BATTERY.h b/Software/src/battery/JAGUAR-IPACE-BATTERY.h index 6ff7827f..adf120a1 100644 --- a/Software/src/battery/JAGUAR-IPACE-BATTERY.h +++ b/Software/src/battery/JAGUAR-IPACE-BATTERY.h @@ -10,6 +10,6 @@ #define MIN_CELL_VOLTAGE_MV 2700 //Battery is put into emergency stop if one cell goes below this value void setup_battery(void); -void transmit_can(CAN_frame* tx_frame, int interface); +void transmit_can_frame(CAN_frame* tx_frame, int interface); #endif diff --git a/Software/src/battery/KIA-E-GMP-BATTERY.cpp b/Software/src/battery/KIA-E-GMP-BATTERY.cpp index a0715a26..8d218687 100644 --- a/Software/src/battery/KIA-E-GMP-BATTERY.cpp +++ b/Software/src/battery/KIA-E-GMP-BATTERY.cpp @@ -690,67 +690,67 @@ void update_values_battery() { //This function maps all the values fetched via /* Safeties verified. Perform USB serial printout if configured to do so */ -#ifdef DEBUG_VIA_USB - Serial.println(); //sepatator - Serial.println("Values from battery: "); - Serial.print("SOC BMS: "); - Serial.print((uint16_t)SOC_BMS / 10.0, 1); - Serial.print("% | SOC Display: "); - Serial.print((uint16_t)SOC_Display / 10.0, 1); - Serial.print("% | SOH "); - Serial.print((uint16_t)batterySOH / 10.0, 1); - Serial.println("%"); - Serial.print((int16_t)batteryAmps / 10.0, 1); - Serial.print(" Amps | "); - Serial.print((uint16_t)batteryVoltage / 10.0, 1); - Serial.print(" Volts | "); - Serial.print((int16_t)datalayer.battery.status.active_power_W); - Serial.println(" Watts"); - Serial.print("Allowed Charge "); - Serial.print((uint16_t)allowedChargePower * 10); - Serial.print(" W | Allowed Discharge "); - Serial.print((uint16_t)allowedDischargePower * 10); - Serial.println(" W"); - Serial.print("MaxCellVolt "); - Serial.print(CellVoltMax_mV); - Serial.print(" mV No "); - Serial.print(CellVmaxNo); - Serial.print(" | MinCellVolt "); - Serial.print(CellVoltMin_mV); - Serial.print(" mV No "); - Serial.println(CellVminNo); - Serial.print("TempHi "); - Serial.print((int16_t)temperatureMax); - Serial.print("°C TempLo "); - Serial.print((int16_t)temperatureMin); - Serial.print("°C WaterInlet "); - Serial.print((int8_t)temperature_water_inlet); - Serial.print("°C PowerRelay "); - Serial.print((int8_t)powerRelayTemperature * 2); - Serial.println("°C"); - Serial.print("Aux12volt: "); - Serial.print((int16_t)leadAcidBatteryVoltage / 10.0, 1); - Serial.println("V | "); - Serial.print("BmsManagementMode "); - Serial.print((uint8_t)batteryManagementMode, BIN); +#ifdef DEBUG_LOG + logging.println(); //sepatator + logging.println("Values from battery: "); + logging.print("SOC BMS: "); + logging.print((uint16_t)SOC_BMS / 10.0, 1); + logging.print("pct | SOC Display: "); + logging.print((uint16_t)SOC_Display / 10.0, 1); + logging.print("pct | SOH "); + logging.print((uint16_t)batterySOH / 10.0, 1); + logging.println("pct"); + logging.print((int16_t)batteryAmps / 10.0, 1); + logging.print(" Amps | "); + logging.print((uint16_t)batteryVoltage / 10.0, 1); + logging.print(" Volts | "); + logging.print((int16_t)datalayer.battery.status.active_power_W); + logging.println(" Watts"); + logging.print("Allowed Charge "); + logging.print((uint16_t)allowedChargePower * 10); + logging.print(" W | Allowed Discharge "); + logging.print((uint16_t)allowedDischargePower * 10); + logging.println(" W"); + logging.print("MaxCellVolt "); + logging.print(CellVoltMax_mV); + logging.print(" mV No "); + logging.print(CellVmaxNo); + logging.print(" | MinCellVolt "); + logging.print(CellVoltMin_mV); + logging.print(" mV No "); + logging.println(CellVminNo); + logging.print("TempHi "); + logging.print((int16_t)temperatureMax); + logging.print("°C TempLo "); + logging.print((int16_t)temperatureMin); + logging.print("°C WaterInlet "); + logging.print((int8_t)temperature_water_inlet); + logging.print("°C PowerRelay "); + logging.print((int8_t)powerRelayTemperature * 2); + logging.println("°C"); + logging.print("Aux12volt: "); + logging.print((int16_t)leadAcidBatteryVoltage / 10.0, 1); + logging.println("V | "); + logging.print("BmsManagementMode "); + logging.print((uint8_t)batteryManagementMode, BIN); if (bitRead((uint8_t)BMS_ign, 2) == 1) { - Serial.print(" | BmsIgnition ON"); + logging.print(" | BmsIgnition ON"); } else { - Serial.print(" | BmsIgnition OFF"); + logging.print(" | BmsIgnition OFF"); } if (bitRead((uint8_t)batteryRelay, 0) == 1) { - Serial.print(" | PowerRelay ON"); + logging.print(" | PowerRelay ON"); } else { - Serial.print(" | PowerRelay OFF"); + logging.print(" | PowerRelay OFF"); } - Serial.print(" | Inverter "); - Serial.print(inverterVoltage); - Serial.println(" Volts"); + logging.print(" | Inverter "); + logging.print(inverterVoltage); + logging.println(" Volts"); #endif } -void receive_can_battery(CAN_frame rx_frame) { +void handle_incoming_can_frame_battery(CAN_frame rx_frame) { startedUp = true; switch (rx_frame.ID) { case 0x055: @@ -808,10 +808,10 @@ void receive_can_battery(CAN_frame rx_frame) { // print_canfd_frame(frame); switch (rx_frame.data.u8[0]) { case 0x10: //"PID Header" - // Serial.println ("Send ack"); + // logging.println ("Send ack"); poll_data_pid = rx_frame.data.u8[4]; // if (rx_frame.data.u8[4] == poll_data_pid) { - transmit_can(&EGMP_7E4_ack, can_config.battery); //Send ack to BMS if the same frame is sent as polled + transmit_can_frame(&EGMP_7E4_ack, can_config.battery); //Send ack to BMS if the same frame is sent as polled // } break; case 0x21: //First frame in PID group @@ -982,7 +982,7 @@ void receive_can_battery(CAN_frame rx_frame) { } } -void send_can_battery() { +void transmit_can_battery() { unsigned long currentMillis = millis(); if (startedUp) { //Send Contactor closing message loop @@ -993,7 +993,7 @@ void send_can_battery() { if (currentMillis - startMillis >= messageDelays[messageIndex]) { // Transmit the current message - transmit_can(messages[messageIndex], can_config.battery); + transmit_can_frame(messages[messageIndex], can_config.battery); // Move to the next message messageIndex++; @@ -1019,7 +1019,7 @@ void send_can_battery() { EGMP_7E4.data.u8[3] = KIA_7E4_COUNTER; if (ok_start_polling_battery) { - transmit_can(&EGMP_7E4, can_config.battery); + transmit_can_frame(&EGMP_7E4, can_config.battery); } KIA_7E4_COUNTER++; diff --git a/Software/src/battery/KIA-E-GMP-BATTERY.h b/Software/src/battery/KIA-E-GMP-BATTERY.h index 8c9f0db7..b0f3dccc 100644 --- a/Software/src/battery/KIA-E-GMP-BATTERY.h +++ b/Software/src/battery/KIA-E-GMP-BATTERY.h @@ -18,6 +18,6 @@ extern ACAN2517FD canfd; #define RAMPDOWNPOWERALLOWED 10000 // What power we ramp down from towards top balancing void setup_battery(void); -void transmit_can(CAN_frame* tx_frame, int interface); +void transmit_can_frame(CAN_frame* tx_frame, int interface); #endif diff --git a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp index 3a6663c6..084d6549 100644 --- a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp +++ b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp @@ -142,63 +142,63 @@ void update_values_battery() { //This function maps all the values fetched via /* Safeties verified. Perform USB serial printout if configured to do so */ -#ifdef DEBUG_VIA_USB - Serial.println(); //sepatator - Serial.println("Values from battery: "); - Serial.print("SOC BMS: "); - Serial.print((uint16_t)SOC_BMS / 10.0, 1); - Serial.print("% | SOC Display: "); - Serial.print((uint16_t)SOC_Display / 10.0, 1); - Serial.print("% | SOH "); - Serial.print((uint16_t)batterySOH / 10.0, 1); - Serial.println("%"); - Serial.print((int16_t)batteryAmps / 10.0, 1); - Serial.print(" Amps | "); - Serial.print((uint16_t)batteryVoltage / 10.0, 1); - Serial.print(" Volts | "); - Serial.print((int16_t)datalayer.battery.status.active_power_W); - Serial.println(" Watts"); - Serial.print("Allowed Charge "); - Serial.print((uint16_t)allowedChargePower * 10); - Serial.print(" W | Allowed Discharge "); - Serial.print((uint16_t)allowedDischargePower * 10); - Serial.println(" W"); - Serial.print("MaxCellVolt "); - Serial.print(CellVoltMax_mV); - Serial.print(" mV No "); - Serial.print(CellVmaxNo); - Serial.print(" | MinCellVolt "); - Serial.print(CellVoltMin_mV); - Serial.print(" mV No "); - Serial.println(CellVminNo); - Serial.print("TempHi "); - Serial.print((int16_t)temperatureMax); - Serial.print("°C TempLo "); - Serial.print((int16_t)temperatureMin); - Serial.print("°C WaterInlet "); - Serial.print((int8_t)temperature_water_inlet); - Serial.print("°C PowerRelay "); - Serial.print((int8_t)powerRelayTemperature * 2); - Serial.println("°C"); - Serial.print("Aux12volt: "); - Serial.print((int16_t)leadAcidBatteryVoltage / 10.0, 1); - Serial.println("V | "); - Serial.print("BmsManagementMode "); - Serial.print((uint8_t)batteryManagementMode, BIN); +#ifdef DEBUG_LOG + logging.println(); //sepatator + logging.println("Values from battery: "); + logging.print("SOC BMS: "); + logging.print((uint16_t)SOC_BMS / 10.0, 1); + logging.print("pct | SOC Display: "); + logging.print((uint16_t)SOC_Display / 10.0, 1); + logging.print("pct | SOH "); + logging.print((uint16_t)batterySOH / 10.0, 1); + logging.println("pct"); + logging.print((int16_t)batteryAmps / 10.0, 1); + logging.print(" Amps | "); + logging.print((uint16_t)batteryVoltage / 10.0, 1); + logging.print(" Volts | "); + logging.print((int16_t)datalayer.battery.status.active_power_W); + logging.println(" Watts"); + logging.print("Allowed Charge "); + logging.print((uint16_t)allowedChargePower * 10); + logging.print(" W | Allowed Discharge "); + logging.print((uint16_t)allowedDischargePower * 10); + logging.println(" W"); + logging.print("MaxCellVolt "); + logging.print(CellVoltMax_mV); + logging.print(" mV No "); + logging.print(CellVmaxNo); + logging.print(" | MinCellVolt "); + logging.print(CellVoltMin_mV); + logging.print(" mV No "); + logging.println(CellVminNo); + logging.print("TempHi "); + logging.print((int16_t)temperatureMax); + logging.print("°C TempLo "); + logging.print((int16_t)temperatureMin); + logging.print("°C WaterInlet "); + logging.print((int8_t)temperature_water_inlet); + logging.print("°C PowerRelay "); + logging.print((int8_t)powerRelayTemperature * 2); + logging.println("°C"); + logging.print("Aux12volt: "); + logging.print((int16_t)leadAcidBatteryVoltage / 10.0, 1); + logging.println("V | "); + logging.print("BmsManagementMode "); + logging.print((uint8_t)batteryManagementMode, BIN); if (bitRead((uint8_t)BMS_ign, 2) == 1) { - Serial.print(" | BmsIgnition ON"); + logging.print(" | BmsIgnition ON"); } else { - Serial.print(" | BmsIgnition OFF"); + logging.print(" | BmsIgnition OFF"); } if (bitRead((uint8_t)batteryRelay, 0) == 1) { - Serial.print(" | PowerRelay ON"); + logging.print(" | PowerRelay ON"); } else { - Serial.print(" | PowerRelay OFF"); + logging.print(" | PowerRelay OFF"); } - Serial.print(" | Inverter "); - Serial.print(inverterVoltage); - Serial.println(" Volts"); + logging.print(" | Inverter "); + logging.print(inverterVoltage); + logging.println(" Volts"); #endif } @@ -220,7 +220,7 @@ void update_number_of_cells() { } } -void receive_can_battery(CAN_frame rx_frame) { +void handle_incoming_can_frame_battery(CAN_frame rx_frame) { switch (rx_frame.ID) { case 0x4DE: startedUp = true; @@ -268,17 +268,17 @@ void receive_can_battery(CAN_frame rx_frame) { } poll_data_pid++; if (poll_data_pid == 1) { - transmit_can(&KIA64_7E4_id1, can_config.battery); + transmit_can_frame(&KIA64_7E4_id1, can_config.battery); } else if (poll_data_pid == 2) { - transmit_can(&KIA64_7E4_id2, can_config.battery); + transmit_can_frame(&KIA64_7E4_id2, can_config.battery); } else if (poll_data_pid == 3) { - transmit_can(&KIA64_7E4_id3, can_config.battery); + transmit_can_frame(&KIA64_7E4_id3, can_config.battery); } else if (poll_data_pid == 4) { - transmit_can(&KIA64_7E4_id4, can_config.battery); + transmit_can_frame(&KIA64_7E4_id4, can_config.battery); } else if (poll_data_pid == 5) { - transmit_can(&KIA64_7E4_id5, can_config.battery); + transmit_can_frame(&KIA64_7E4_id5, can_config.battery); } else if (poll_data_pid == 6) { - transmit_can(&KIA64_7E4_id6, can_config.battery); + transmit_can_frame(&KIA64_7E4_id6, can_config.battery); } else if (poll_data_pid == 7) { } else if (poll_data_pid == 8) { } else if (poll_data_pid == 9) { @@ -289,7 +289,8 @@ void receive_can_battery(CAN_frame rx_frame) { switch (rx_frame.data.u8[0]) { case 0x10: //"PID Header" if (rx_frame.data.u8[4] == poll_data_pid) { - transmit_can(&KIA64_7E4_ack, can_config.battery); //Send ack to BMS if the same frame is sent as polled + transmit_can_frame(&KIA64_7E4_ack, + can_config.battery); //Send ack to BMS if the same frame is sent as polled } break; case 0x21: //First frame in PID group @@ -460,7 +461,7 @@ void receive_can_battery(CAN_frame rx_frame) { } } -void send_can_battery() { +void transmit_can_battery() { unsigned long currentMillis = millis(); if (!startedUp) { @@ -471,9 +472,9 @@ void send_can_battery() { if (currentMillis - previousMillis100 >= INTERVAL_100_MS) { previousMillis100 = currentMillis; - transmit_can(&KIA64_553, can_config.battery); - transmit_can(&KIA64_57F, can_config.battery); - transmit_can(&KIA64_2A1, can_config.battery); + transmit_can_frame(&KIA64_553, can_config.battery); + transmit_can_frame(&KIA64_57F, can_config.battery); + transmit_can_frame(&KIA64_2A1, can_config.battery); } // Send 10ms CAN Message if (currentMillis - previousMillis10 >= INTERVAL_10_MS) { @@ -525,11 +526,11 @@ void send_can_battery() { break; } - transmit_can(&KIA_HYUNDAI_200, can_config.battery); + transmit_can_frame(&KIA_HYUNDAI_200, can_config.battery); - transmit_can(&KIA_HYUNDAI_523, can_config.battery); + transmit_can_frame(&KIA_HYUNDAI_523, can_config.battery); - transmit_can(&KIA_HYUNDAI_524, can_config.battery); + transmit_can_frame(&KIA_HYUNDAI_524, can_config.battery); } } diff --git a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.h b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.h index 8b1b3935..ff972508 100644 --- a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.h +++ b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.h @@ -14,6 +14,6 @@ void setup_battery(void); void update_number_of_cells(); -void transmit_can(CAN_frame* tx_frame, int interface); +void transmit_can_frame(CAN_frame* tx_frame, int interface); #endif diff --git a/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp b/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp index c37fcb15..71c4c88f 100644 --- a/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp +++ b/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.cpp @@ -86,7 +86,7 @@ void update_values_battery() { //This function maps all the values fetched via } } -void receive_can_battery(CAN_frame rx_frame) { +void handle_incoming_can_frame_battery(CAN_frame rx_frame) { datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; switch (rx_frame.ID) { case 0x5F1: @@ -108,7 +108,7 @@ void receive_can_battery(CAN_frame rx_frame) { switch (rx_frame.data.u8[0]) { case 0x10: //"PID Header" if (rx_frame.data.u8[3] == poll_data_pid) { - transmit_can(&KIA_7E4_ack, can_config.battery); //Send ack to BMS if the same frame is sent as polled + transmit_can_frame(&KIA_7E4_ack, can_config.battery); //Send ack to BMS if the same frame is sent as polled } break; case 0x21: //First frame in PID group @@ -230,7 +230,7 @@ void receive_can_battery(CAN_frame rx_frame) { break; } } -void send_can_battery() { +void transmit_can_battery() { unsigned long currentMillis = millis(); // Send 1000ms CAN Message @@ -243,15 +243,15 @@ void send_can_battery() { } poll_data_pid++; if (poll_data_pid == 1) { - transmit_can(&KIA_7E4_id1, can_config.battery); + transmit_can_frame(&KIA_7E4_id1, can_config.battery); } else if (poll_data_pid == 2) { - transmit_can(&KIA_7E4_id2, can_config.battery); + transmit_can_frame(&KIA_7E4_id2, can_config.battery); } else if (poll_data_pid == 3) { - transmit_can(&KIA_7E4_id3, can_config.battery); + transmit_can_frame(&KIA_7E4_id3, can_config.battery); } else if (poll_data_pid == 4) { } else if (poll_data_pid == 5) { - transmit_can(&KIA_7E4_id5, can_config.battery); + transmit_can_frame(&KIA_7E4_id5, can_config.battery); } } } diff --git a/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.h b/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.h index 26b06d6f..5808723e 100644 --- a/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.h +++ b/Software/src/battery/KIA-HYUNDAI-HYBRID-BATTERY.h @@ -11,6 +11,6 @@ #define MIN_CELL_VOLTAGE_MV 2700 //Battery is put into emergency stop if one cell goes below this value void setup_battery(void); -void transmit_can(CAN_frame* tx_frame, int interface); +void transmit_can_frame(CAN_frame* tx_frame, int interface); #endif diff --git a/Software/src/battery/MEB-BATTERY.cpp b/Software/src/battery/MEB-BATTERY.cpp index 643824ee..c73a6f51 100644 --- a/Software/src/battery/MEB-BATTERY.cpp +++ b/Software/src/battery/MEB-BATTERY.cpp @@ -618,7 +618,7 @@ void update_values_battery() { //This function maps all the values fetched via datalayer_extended.meb.rt_battery_unathorized = realtime_warning_battery_unathorized; } -void receive_can_battery(CAN_frame rx_frame) { +void handle_incoming_can_frame_battery(CAN_frame rx_frame) { last_can_msg_timestamp = millis(); if (first_can_msg == 0) first_can_msg = last_can_msg_timestamp; @@ -994,7 +994,7 @@ void receive_can_battery(CAN_frame rx_frame) { break; case 0x1C42007B: // Reply from battery if (rx_frame.data.u8[0] == 0x10) { //PID header - transmit_can(&MEB_ACK_FRAME, can_config.battery); + transmit_can_frame(&MEB_ACK_FRAME, can_config.battery); } if (rx_frame.DLC == 8) { pid_reply = (rx_frame.data.u8[2] << 8) + rx_frame.data.u8[3]; @@ -1453,7 +1453,7 @@ void receive_can_battery(CAN_frame rx_frame) { } } -void send_can_battery() { +void transmit_can_battery() { unsigned long currentMillis = millis(); // Send 10ms CAN Message if (currentMillis > last_can_msg_timestamp + 500) { @@ -1474,7 +1474,7 @@ void send_can_battery() { counter_10ms = (counter_10ms + 1) % 16; //Goes from 0-1-2-3...15-0-1-2-3.. - transmit_can(&MEB_0FC, can_config.battery); // Required for contactor closing + transmit_can_frame(&MEB_0FC, can_config.battery); // Required for contactor closing } // Send 20ms CAN Message if (currentMillis - previousMillis20ms >= INTERVAL_20_MS) { @@ -1485,7 +1485,7 @@ void send_can_battery() { counter_20ms = (counter_20ms + 1) % 16; //Goes from 0-1-2-3...15-0-1-2-3.. - transmit_can(&MEB_0FD, can_config.battery); // Required for contactor closing + transmit_can_frame(&MEB_0FD, can_config.battery); // Required for contactor closing } // Send 40ms CAN Message if (currentMillis - previousMillis40ms >= INTERVAL_40_MS) { @@ -1502,7 +1502,7 @@ void send_can_battery() { } toggle = !toggle; // Flip the toggle each time the code block is executed - transmit_can(&MEB_040, can_config.battery); // Airbag message - Needed for contactor closing + transmit_can_frame(&MEB_040, can_config.battery); // Airbag message - Needed for contactor closing } // Send 50ms CAN Message if (currentMillis - previousMillis50ms >= INTERVAL_50_MS) { @@ -1518,7 +1518,7 @@ void send_can_battery() { MEB_0C0.data.u8[0] = vw_crc_calc(MEB_0C0.data.u8, MEB_0C0.DLC, MEB_0C0.ID); counter_50ms = (counter_50ms + 1) % 16; //Goes from 0-1-2-3...15-0-1-2-3.. - transmit_can(&MEB_0C0, can_config.battery); // Needed for contactor closing + transmit_can_frame(&MEB_0C0, can_config.battery); // Needed for contactor closing } // Send 100ms CAN Message if (currentMillis - previousMillis100ms >= INTERVAL_100_MS) { @@ -1560,11 +1560,11 @@ void send_can_battery() { MEB_14C.data.u8[0] = vw_crc_calc(MEB_14C.data.u8, MEB_14C.DLC, MEB_14C.ID); counter_100ms = (counter_100ms + 1) % 16; //Goes from 0-1-2-3...15-0-1-2-3.. - transmit_can(&MEB_503, can_config.battery); - transmit_can(&MEB_272, can_config.battery); - transmit_can(&MEB_3C0, can_config.battery); - transmit_can(&MEB_3BE, can_config.battery); - transmit_can(&MEB_14C, can_config.battery); + transmit_can_frame(&MEB_503, can_config.battery); + transmit_can_frame(&MEB_272, can_config.battery); + transmit_can_frame(&MEB_3C0, can_config.battery); + transmit_can_frame(&MEB_3BE, can_config.battery); + transmit_can_frame(&MEB_14C, can_config.battery); } //Send 200ms message if (currentMillis - previousMillis200ms >= INTERVAL_200_MS) { @@ -1574,11 +1574,11 @@ void send_can_battery() { //TODO: MEB_1B0000B9 & MEB_1B000010 & MEB_1B000046 has CAN sleep commands, static OK? - transmit_can(&MEB_5E1, can_config.battery); - transmit_can(&MEB_153, can_config.battery); - transmit_can(&MEB_1B0000B9, can_config.battery); - transmit_can(&MEB_1B000010, can_config.battery); - transmit_can(&MEB_1B000046, can_config.battery); + transmit_can_frame(&MEB_5E1, can_config.battery); + transmit_can_frame(&MEB_153, can_config.battery); + transmit_can_frame(&MEB_1B0000B9, can_config.battery); + transmit_can_frame(&MEB_1B000010, can_config.battery); + transmit_can_frame(&MEB_1B000046, can_config.battery); switch (poll_pid) { case PID_SOC: @@ -2076,7 +2076,7 @@ void send_can_battery() { break; } if (first_can_msg > 0 && currentMillis > first_can_msg + 2000) { - transmit_can(&MEB_POLLING_FRAME, can_config.battery); + transmit_can_frame(&MEB_POLLING_FRAME, can_config.battery); } } @@ -2084,11 +2084,11 @@ void send_can_battery() { if (currentMillis - previousMillis500ms >= INTERVAL_500_MS) { previousMillis500ms = currentMillis; - transmit_can(&MEB_16A954B4, can_config.battery); //eTM, Cooling valves and pumps for BMS - transmit_can(&MEB_569, can_config.battery); // Battery heating requests - transmit_can(&MEB_1A55552B, can_config.battery); //Climate, heatpump and priorities - transmit_can(&MEB_1A555548, can_config.battery); //ORU, OTA update message for reserving battery - transmit_can(&MEB_16A954FB, can_config.battery); //Climate, request to BMS for starting preconditioning + transmit_can_frame(&MEB_16A954B4, can_config.battery); //eTM, Cooling valves and pumps for BMS + transmit_can_frame(&MEB_569, can_config.battery); // Battery heating requests + transmit_can_frame(&MEB_1A55552B, can_config.battery); //Climate, heatpump and priorities + transmit_can_frame(&MEB_1A555548, can_config.battery); //ORU, OTA update message for reserving battery + transmit_can_frame(&MEB_16A954FB, can_config.battery); //Climate, request to BMS for starting preconditioning } //Send 1s CANFD message @@ -2109,12 +2109,12 @@ void send_can_battery() { MEB_6B2.data.u8[7] = (uint8_t)((seconds & 0x3E) >> 1); seconds = (seconds + 1) % 60; - counter_1000ms = (counter_1000ms + 1) % 16; //Goes from 0-1-2-3...15-0-1-2-3.. - transmit_can(&MEB_6B2, can_config.battery); // Diagnostics - Needed for contactor closing - transmit_can(&MEB_641, can_config.battery); // Motor - OBD - transmit_can(&MEB_5F5, can_config.battery); // Loading profile - transmit_can(&MEB_585, can_config.battery); // Systeminfo - transmit_can(&MEB_1A5555A6, can_config.battery); // Temperature QBit + counter_1000ms = (counter_1000ms + 1) % 16; //Goes from 0-1-2-3...15-0-1-2-3.. + transmit_can_frame(&MEB_6B2, can_config.battery); // Diagnostics - Needed for contactor closing + transmit_can_frame(&MEB_641, can_config.battery); // Motor - OBD + transmit_can_frame(&MEB_5F5, can_config.battery); // Loading profile + transmit_can_frame(&MEB_585, can_config.battery); // Systeminfo + transmit_can_frame(&MEB_1A5555A6, can_config.battery); // Temperature QBit } } diff --git a/Software/src/battery/MEB-BATTERY.h b/Software/src/battery/MEB-BATTERY.h index 3648dec4..00be49b5 100644 --- a/Software/src/battery/MEB-BATTERY.h +++ b/Software/src/battery/MEB-BATTERY.h @@ -133,6 +133,6 @@ #define PID_CELLVOLTAGE_CELL_108 0x1EAB void setup_battery(void); -void transmit_can(CAN_frame* tx_frame, int interface); +void transmit_can_frame(CAN_frame* tx_frame, int interface); #endif diff --git a/Software/src/battery/MG-5-BATTERY.cpp b/Software/src/battery/MG-5-BATTERY.cpp index 35c8ee96..07c54a7d 100644 --- a/Software/src/battery/MG-5-BATTERY.cpp +++ b/Software/src/battery/MG-5-BATTERY.cpp @@ -42,13 +42,9 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.temperature_min_dC; datalayer.battery.status.temperature_max_dC; - -#ifdef DEBUG_VIA_USB - -#endif } -void receive_can_battery(CAN_frame rx_frame) { +void handle_incoming_can_frame_battery(CAN_frame rx_frame) { datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; switch (rx_frame.ID) { case 0x171: //Following messages were detected on a MG5 battery BMS @@ -112,7 +108,7 @@ void receive_can_battery(CAN_frame rx_frame) { break; } } -void send_can_battery() { +void transmit_can_battery() { unsigned long currentMillis = millis(); //Send 10ms message if (currentMillis - previousMillis10 >= INTERVAL_10_MS) { @@ -124,13 +120,13 @@ void send_can_battery() { } previousMillis10 = currentMillis; - transmit_can(&MG_5_100, can_config.battery); + transmit_can_frame(&MG_5_100, can_config.battery); } // Send 100ms CAN Message if (currentMillis - previousMillis100 >= INTERVAL_100_MS) { previousMillis100 = currentMillis; - //transmit_can(&MG_5_100, can_config.battery); + //transmit_can_frame(&MG_5_100, can_config.battery); } } diff --git a/Software/src/battery/MG-5-BATTERY.h b/Software/src/battery/MG-5-BATTERY.h index 4efd3735..415ed0dc 100644 --- a/Software/src/battery/MG-5-BATTERY.h +++ b/Software/src/battery/MG-5-BATTERY.h @@ -11,6 +11,6 @@ #define MIN_CELL_VOLTAGE_MV 2700 //Battery is put into emergency stop if one cell goes below this value void setup_battery(void); -void transmit_can(CAN_frame* tx_frame, int interface); +void transmit_can_frame(CAN_frame* tx_frame, int interface); #endif diff --git a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp index b4b94b65..9ba820c9 100644 --- a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp +++ b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp @@ -502,7 +502,7 @@ void update_values_battery2() { // Handle the values coming in from battery #2 } } } -void receive_can_battery2(CAN_frame rx_frame) { +void handle_incoming_can_frame_battery2(CAN_frame rx_frame) { switch (rx_frame.ID) { case 0x1DB: if (is_message_corrupt(rx_frame)) { @@ -612,7 +612,7 @@ void receive_can_battery2(CAN_frame rx_frame) { //First check which group data we are getting if (rx_frame.data.u8[0] == 0x10) { //First message of a group battery2_group_7bb = rx_frame.data.u8[3]; - transmit_can(&LEAF_NEXT_LINE_REQUEST, can_config.battery_double); + transmit_can_frame(&LEAF_NEXT_LINE_REQUEST, can_config.battery_double); } if (battery2_group_7bb == 1) //High precision SOC, Current, voltages etc. @@ -740,7 +740,7 @@ void receive_can_battery2(CAN_frame rx_frame) { } #endif // DOUBLE_BATTERY -void receive_can_battery(CAN_frame rx_frame) { +void handle_incoming_can_frame_battery(CAN_frame rx_frame) { switch (rx_frame.ID) { case 0x1DB: if (is_message_corrupt(rx_frame)) { @@ -870,7 +870,7 @@ void receive_can_battery(CAN_frame rx_frame) { if (rx_frame.data.u8[0] == 0x10) { //First message of a group group_7bb = rx_frame.data.u8[3]; - transmit_can(&LEAF_NEXT_LINE_REQUEST, can_config.battery); //Request the next frame for the group + transmit_can_frame(&LEAF_NEXT_LINE_REQUEST, can_config.battery); //Request the next frame for the group } if (group_7bb == 1) //High precision SOC, Current, voltages etc. @@ -1056,7 +1056,7 @@ void receive_can_battery(CAN_frame rx_frame) { break; } } -void send_can_battery() { +void transmit_can_battery() { if (battery_can_alive) { unsigned long currentMillis = millis(); @@ -1089,9 +1089,9 @@ void send_can_battery() { LEAF_1D4.data.u8[7] = 0xDE; break; } - transmit_can(&LEAF_1D4, can_config.battery); + transmit_can_frame(&LEAF_1D4, can_config.battery); #ifdef DOUBLE_BATTERY - transmit_can(&LEAF_1D4, can_config.battery_double); + transmit_can_frame(&LEAF_1D4, can_config.battery_double); #endif // DOUBLE_BATTERY switch (mprun10r) { @@ -1185,9 +1185,9 @@ void send_can_battery() { //Only send this message when NISSANLEAF_CHARGER is not defined (otherwise it will collide!) #ifndef NISSANLEAF_CHARGER - transmit_can(&LEAF_1F2, can_config.battery); + transmit_can_frame(&LEAF_1F2, can_config.battery); #ifdef DOUBLE_BATTERY - transmit_can(&LEAF_1F2, can_config.battery_double); + transmit_can_frame(&LEAF_1F2, can_config.battery_double); #endif // DOUBLE_BATTERY #endif @@ -1212,9 +1212,9 @@ void send_can_battery() { } // VCM message, containing info if battery should sleep or stay awake - transmit_can(&LEAF_50B, can_config.battery); // HCM_WakeUpSleepCommand == 11b == WakeUp, and CANMASK = 1 + transmit_can_frame(&LEAF_50B, can_config.battery); // HCM_WakeUpSleepCommand == 11b == WakeUp, and CANMASK = 1 #ifdef DOUBLE_BATTERY - transmit_can(&LEAF_50B, can_config.battery_double); + transmit_can_frame(&LEAF_50B, can_config.battery_double); #endif // DOUBLE_BATTERY LEAF_50C.data.u8[3] = mprun100; @@ -1236,9 +1236,9 @@ void send_can_battery() { LEAF_50C.data.u8[5] = 0x9A; break; } - transmit_can(&LEAF_50C, can_config.battery); + transmit_can_frame(&LEAF_50C, can_config.battery); #ifdef DOUBLE_BATTERY - transmit_can(&LEAF_50C, can_config.battery_double); + transmit_can_frame(&LEAF_50C, can_config.battery_double); #endif // DOUBLE_BATTERY mprun100 = (mprun100 + 1) % 4; // mprun100 cycles between 0-1-2-3-0-1... @@ -1255,9 +1255,9 @@ void send_can_battery() { PIDindex = (PIDindex + 1) % 6; // 6 = amount of elements in the PIDgroups[] LEAF_GROUP_REQUEST.data.u8[2] = PIDgroups[PIDindex]; - transmit_can(&LEAF_GROUP_REQUEST, can_config.battery); + transmit_can_frame(&LEAF_GROUP_REQUEST, can_config.battery); #ifdef DOUBLE_BATTERY - transmit_can(&LEAF_GROUP_REQUEST, can_config.battery_double); + transmit_can_frame(&LEAF_GROUP_REQUEST, can_config.battery_double); #endif // DOUBLE_BATTERY } @@ -1320,19 +1320,19 @@ void clearSOH(void) { break; case 1: // Set CAN_PROCESS_FLAG to 0xC0 LEAF_CLEAR_SOH.data = {0x02, 0x10, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00}; - transmit_can(&LEAF_CLEAR_SOH, can_config.battery); + transmit_can_frame(&LEAF_CLEAR_SOH, can_config.battery); // BMS should reply 02 50 C0 FF FF FF FF FF stateMachineClearSOH = 2; break; case 2: // Set something ? LEAF_CLEAR_SOH.data = {0x02, 0x3E, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}; - transmit_can(&LEAF_CLEAR_SOH, can_config.battery); + transmit_can_frame(&LEAF_CLEAR_SOH, can_config.battery); // BMS should reply 7E FF FF FF FF FF FF stateMachineClearSOH = 3; break; case 3: // Request challenge to solve LEAF_CLEAR_SOH.data = {0x02, 0x27, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00}; - transmit_can(&LEAF_CLEAR_SOH, can_config.battery); + transmit_can_frame(&LEAF_CLEAR_SOH, can_config.battery); // BMS should reply with (challenge) 06 67 65 (02 DD 86 43) FF stateMachineClearSOH = 4; break; @@ -1340,34 +1340,34 @@ void clearSOH(void) { decodeChallengeData(incomingChallenge, solvedChallenge); LEAF_CLEAR_SOH.data = { 0x10, 0x0A, 0x27, 0x66, solvedChallenge[0], solvedChallenge[1], solvedChallenge[2], solvedChallenge[3]}; - transmit_can(&LEAF_CLEAR_SOH, can_config.battery); + transmit_can_frame(&LEAF_CLEAR_SOH, can_config.battery); // BMS should reply 7BB 8 30 01 00 FF FF FF FF FF // Proceed with more data (PID ACK) stateMachineClearSOH = 5; break; case 5: // Reply with even more decoded challenge data LEAF_CLEAR_SOH.data = { 0x21, solvedChallenge[4], solvedChallenge[5], solvedChallenge[6], solvedChallenge[7], 0x00, 0x00, 0x00}; - transmit_can(&LEAF_CLEAR_SOH, can_config.battery); + transmit_can_frame(&LEAF_CLEAR_SOH, can_config.battery); // BMS should reply 02 67 66 FF FF FF FF FF // Thank you for the data stateMachineClearSOH = 6; break; case 6: // Check if solved data was OK LEAF_CLEAR_SOH.data = {0x03, 0x31, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}; - transmit_can(&LEAF_CLEAR_SOH, can_config.battery); + transmit_can_frame(&LEAF_CLEAR_SOH, can_config.battery); //7BB 8 03 71 03 01 FF FF FF FF // If all is well, BMS replies with 03 71 03 01. //Incase you sent wrong challenge, you get 03 7f 31 12 stateMachineClearSOH = 7; break; case 7: // Reset SOH% request LEAF_CLEAR_SOH.data = {0x03, 0x31, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00}; - transmit_can(&LEAF_CLEAR_SOH, can_config.battery); + transmit_can_frame(&LEAF_CLEAR_SOH, can_config.battery); //7BB 8 03 71 03 02 FF FF FF FF // 03 71 03 02 means that BMS accepted command. //7BB 03 7f 31 12 means your challenge was wrong, so command ignored stateMachineClearSOH = 8; break; case 8: // Please proceed with resetting SOH LEAF_CLEAR_SOH.data = {0x02, 0x10, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00}; - transmit_can(&LEAF_CLEAR_SOH, can_config.battery); + transmit_can_frame(&LEAF_CLEAR_SOH, can_config.battery); // 7BB 8 02 50 81 FF FF FF FF FF // SOH reset OK stateMachineClearSOH = 255; break; diff --git a/Software/src/battery/NISSAN-LEAF-BATTERY.h b/Software/src/battery/NISSAN-LEAF-BATTERY.h index 245f0f39..f5e7adcd 100644 --- a/Software/src/battery/NISSAN-LEAF-BATTERY.h +++ b/Software/src/battery/NISSAN-LEAF-BATTERY.h @@ -13,7 +13,7 @@ uint16_t Temp_fromRAW_to_F(uint16_t temperature); bool is_message_corrupt(CAN_frame rx_frame); void setup_battery(void); -void transmit_can(CAN_frame* tx_frame, int interface); +void transmit_can_frame(CAN_frame* tx_frame, int interface); void clearSOH(void); //Cryptographic functions void decodeChallengeData(unsigned int SeedInput, unsigned char* Crypt_Output_Buffer); diff --git a/Software/src/battery/PYLON-BATTERY.cpp b/Software/src/battery/PYLON-BATTERY.cpp index ec61901d..86ea9c0f 100644 --- a/Software/src/battery/PYLON-BATTERY.cpp +++ b/Software/src/battery/PYLON-BATTERY.cpp @@ -80,7 +80,7 @@ void update_values_battery() { datalayer.battery.info.min_design_voltage_dV = discharge_cutoff_voltage; } -void receive_can_battery(CAN_frame rx_frame) { +void handle_incoming_can_frame_battery(CAN_frame rx_frame) { datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; switch (rx_frame.ID) { case 0x7310: @@ -156,17 +156,17 @@ void receive_can_battery(CAN_frame rx_frame) { } } -void send_can_battery() { +void transmit_can_battery() { unsigned long currentMillis = millis(); // Send 1s CAN Message if (currentMillis - previousMillis1000 >= INTERVAL_1_S) { previousMillis1000 = currentMillis; - transmit_can(&PYLON_3010, can_config.battery); // Heartbeat - transmit_can(&PYLON_4200, can_config.battery); // Ensemble OR System equipment info, depends on frame0 - transmit_can(&PYLON_8200, can_config.battery); // Control device quit sleep status - transmit_can(&PYLON_8210, can_config.battery); // Charge command + transmit_can_frame(&PYLON_3010, can_config.battery); // Heartbeat + transmit_can_frame(&PYLON_4200, can_config.battery); // Ensemble OR System equipment info, depends on frame0 + transmit_can_frame(&PYLON_8200, can_config.battery); // Control device quit sleep status + transmit_can_frame(&PYLON_8210, can_config.battery); // Charge command if (ensemble_info_ack) { PYLON_4200.data.u8[0] = 0x00; //Request system equipment info diff --git a/Software/src/battery/PYLON-BATTERY.h b/Software/src/battery/PYLON-BATTERY.h index 98588c69..8d17c047 100644 --- a/Software/src/battery/PYLON-BATTERY.h +++ b/Software/src/battery/PYLON-BATTERY.h @@ -13,6 +13,6 @@ #define MAX_CELL_DEVIATION_MV 500 void setup_battery(void); -void transmit_can(CAN_frame* tx_frame, int interface); +void transmit_can_frame(CAN_frame* tx_frame, int interface); #endif diff --git a/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.cpp b/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.cpp index 4ca3a330..3ff1325e 100644 --- a/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.cpp +++ b/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.cpp @@ -180,7 +180,7 @@ void update_values_battery() { datalayer.battery.info.min_design_voltage_dV = DischargeVoltageLimit * 10; } -void receive_can_battery(CAN_frame rx_frame) { +void handle_incoming_can_frame_battery(CAN_frame rx_frame) { datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; switch (rx_frame.ID) { case 0x080: // 15ms @@ -301,14 +301,14 @@ void receive_can_battery(CAN_frame rx_frame) { } } -void send_can_battery() { +void transmit_can_battery() { unsigned long currentMillis = millis(); // Send 50ms CAN Message if (currentMillis - previousMillis50ms >= INTERVAL_50_MS) { previousMillis50ms = currentMillis; - transmit_can(&RANGE_ROVER_18B, can_config.battery); + transmit_can_frame(&RANGE_ROVER_18B, can_config.battery); } } diff --git a/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.h b/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.h index c4cdcf07..9dfcaf06 100644 --- a/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.h +++ b/Software/src/battery/RANGE-ROVER-PHEV-BATTERY.h @@ -13,6 +13,6 @@ #define MAX_CELL_DEVIATION_MV 500 //TODO: Configure void setup_battery(void); -void transmit_can(CAN_frame* tx_frame, int interface); +void transmit_can_frame(CAN_frame* tx_frame, int interface); #endif diff --git a/Software/src/battery/RENAULT-KANGOO-BATTERY.cpp b/Software/src/battery/RENAULT-KANGOO-BATTERY.cpp index 096cb629..80430db1 100644 --- a/Software/src/battery/RENAULT-KANGOO-BATTERY.cpp +++ b/Software/src/battery/RENAULT-KANGOO-BATTERY.cpp @@ -103,41 +103,41 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.cell_max_voltage_mV = LB_Cell_Max_Voltage; -#ifdef DEBUG_VIA_USB - Serial.println("Values going to inverter:"); - Serial.print("SOH%: "); - Serial.print(datalayer.battery.status.soh_pptt); - Serial.print(", SOC% scaled: "); - Serial.print(datalayer.battery.status.reported_soc); - Serial.print(", Voltage: "); - Serial.print(datalayer.battery.status.voltage_dV); - Serial.print(", Max discharge power: "); - Serial.print(datalayer.battery.status.max_discharge_power_W); - Serial.print(", Max charge power: "); - Serial.print(datalayer.battery.status.max_charge_power_W); - Serial.print(", Max temp: "); - Serial.print(datalayer.battery.status.temperature_max_dC); - Serial.print(", Min temp: "); - Serial.print(datalayer.battery.status.temperature_min_dC); - Serial.print(", BMS Status (3=OK): "); - Serial.print(datalayer.battery.status.bms_status); +#ifdef DEBUG_LOG + logging.println("Values going to inverter:"); + logging.print("SOH: "); + logging.print(datalayer.battery.status.soh_pptt); + logging.print(", SOC scaled: "); + logging.print(datalayer.battery.status.reported_soc); + logging.print(", Voltage: "); + logging.print(datalayer.battery.status.voltage_dV); + logging.print(", Max discharge power: "); + logging.print(datalayer.battery.status.max_discharge_power_W); + logging.print(", Max charge power: "); + logging.print(datalayer.battery.status.max_charge_power_W); + logging.print(", Max temp: "); + logging.print(datalayer.battery.status.temperature_max_dC); + logging.print(", Min temp: "); + logging.print(datalayer.battery.status.temperature_min_dC); + logging.print(", BMS Status (3=OK): "); + logging.print(datalayer.battery.status.bms_status); - Serial.println("Battery values: "); - Serial.print("Real SOC: "); - Serial.print(LB_SOC); - Serial.print(", Current: "); - Serial.print(LB_Current); - Serial.print(", kWh remain: "); - Serial.print(LB_kWh_Remaining); - Serial.print(", max mV: "); - Serial.print(LB_Cell_Max_Voltage); - Serial.print(", min mV: "); - Serial.print(LB_Cell_Min_Voltage); + logging.println("Battery values: "); + logging.print("Real SOC: "); + logging.print(LB_SOC); + logging.print(", Current: "); + logging.print(LB_Current); + logging.print(", kWh remain: "); + logging.print(LB_kWh_Remaining); + logging.print(", max mV: "); + logging.print(LB_Cell_Max_Voltage); + logging.print(", min mV: "); + logging.print(LB_Cell_Min_Voltage); #endif } -void receive_can_battery(CAN_frame rx_frame) { +void handle_incoming_can_frame_battery(CAN_frame rx_frame) { switch (rx_frame.ID) { case 0x155: //BMS1 @@ -210,12 +210,12 @@ void receive_can_battery(CAN_frame rx_frame) { } } -void send_can_battery() { +void transmit_can_battery() { unsigned long currentMillis = millis(); // Send 100ms CAN Message (for 2.4s, then pause 10s) if ((currentMillis - previousMillis100) >= (INTERVAL_100_MS + GVL_pause)) { previousMillis100 = currentMillis; - transmit_can(&KANGOO_423, can_config.battery); + transmit_can_frame(&KANGOO_423, can_config.battery); GVI_Pollcounter++; GVL_pause = 0; if (GVI_Pollcounter >= 24) { @@ -227,9 +227,9 @@ void send_can_battery() { if (currentMillis - previousMillis1000 >= INTERVAL_1_S) { previousMillis1000 = currentMillis; if (GVB_79B_Continue) - transmit_can(&KANGOO_79B_Continue, can_config.battery); + transmit_can_frame(&KANGOO_79B_Continue, can_config.battery); } else { - transmit_can(&KANGOO_79B, can_config.battery); + transmit_can_frame(&KANGOO_79B, can_config.battery); } } diff --git a/Software/src/battery/RENAULT-KANGOO-BATTERY.h b/Software/src/battery/RENAULT-KANGOO-BATTERY.h index 6afb2335..25f739c6 100644 --- a/Software/src/battery/RENAULT-KANGOO-BATTERY.h +++ b/Software/src/battery/RENAULT-KANGOO-BATTERY.h @@ -12,6 +12,6 @@ #define MAX_CHARGE_POWER_W 5000 // Battery can be charged with this amount of power void setup_battery(void); -void transmit_can(CAN_frame* tx_frame, int interface); +void transmit_can_frame(CAN_frame* tx_frame, int interface); #endif diff --git a/Software/src/battery/RENAULT-TWIZY.cpp b/Software/src/battery/RENAULT-TWIZY.cpp index b0140eff..b6c746f2 100644 --- a/Software/src/battery/RENAULT-TWIZY.cpp +++ b/Software/src/battery/RENAULT-TWIZY.cpp @@ -65,7 +65,7 @@ void update_values_battery() { max_value(cell_temperatures_dC, sizeof(cell_temperatures_dC) / sizeof(*cell_temperatures_dC)); } -void receive_can_battery(CAN_frame rx_frame) { +void handle_incoming_can_frame_battery(CAN_frame rx_frame) { datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; switch (rx_frame.ID) { case 0x155: @@ -127,7 +127,7 @@ void receive_can_battery(CAN_frame rx_frame) { } } -void send_can_battery() { +void transmit_can_battery() { // we do not need to send anything to the battery for now } diff --git a/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp b/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp index 84a8463f..28a69df6 100644 --- a/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp +++ b/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.cpp @@ -90,7 +90,7 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.max_discharge_power_W = LB_Discharge_allowed_W; - datalayer.battery.status.max_charge_power_W = LB_Charging_Power_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, cell_4_temperature_polled, cell_5_temperature_polled, cell_6_temperature_polled, @@ -135,7 +135,7 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.voltage_dV = static_cast((calculated_total_pack_voltage_mV / 100)); // mV to dV } -void receive_can_battery(CAN_frame rx_frame) { +void handle_incoming_can_frame_battery(CAN_frame rx_frame) { switch (rx_frame.ID) { case 0x155: //10ms - Charging power, current and SOC datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; @@ -195,7 +195,7 @@ void receive_can_battery(CAN_frame rx_frame) { switch (frame0) { case 0x10: //PID HEADER, datarow 0 requested_poll = rx_frame.data.u8[3]; - transmit_can(&ZOE_ACK_79B, can_config.battery); + transmit_can_frame(&ZOE_ACK_79B, can_config.battery); if (requested_poll == GROUP1_CELLVOLTAGES_1_POLL) { cellvoltages[0] = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; @@ -486,7 +486,7 @@ void receive_can_battery(CAN_frame rx_frame) { } } -void send_can_battery() { +void transmit_can_battery() { unsigned long currentMillis = millis(); // Send 100ms CAN Message if (currentMillis - previousMillis100 >= INTERVAL_100_MS) { @@ -495,7 +495,7 @@ void send_can_battery() { set_event(EVENT_CAN_OVERRUN, (currentMillis - previousMillis100)); } previousMillis100 = currentMillis; - transmit_can(&ZOE_423, can_config.battery); + transmit_can_frame(&ZOE_423, can_config.battery); if ((counter_423 / 5) % 2 == 0) { // Alternate every 5 messages between these two ZOE_423.data.u8[4] = 0xB2; @@ -534,7 +534,7 @@ void send_can_battery() { ZOE_POLL_79B.data.u8[2] = current_poll; - transmit_can(&ZOE_POLL_79B, can_config.battery); + transmit_can_frame(&ZOE_POLL_79B, can_config.battery); } } diff --git a/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.h b/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.h index 81c7c2cc..1a3968bf 100644 --- a/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.h +++ b/Software/src/battery/RENAULT-ZOE-GEN1-BATTERY.h @@ -11,6 +11,6 @@ #define MIN_CELL_VOLTAGE_MV 2700 //Battery is put into emergency stop if one cell goes below this value void setup_battery(void); -void transmit_can(CAN_frame* tx_frame, int interface); +void transmit_can_frame(CAN_frame* tx_frame, int interface); #endif diff --git a/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.cpp b/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.cpp index 08ac57bf..ec0e8e8d 100644 --- a/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.cpp +++ b/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.cpp @@ -216,13 +216,9 @@ void update_values_battery() { //This function maps all the values fetched via datalayer_extended.zoePH2.battery_pack_time = battery_pack_time; datalayer_extended.zoePH2.battery_soc_min = battery_soc_min; datalayer_extended.zoePH2.battery_soc_max = battery_soc_max; - -#ifdef DEBUG_VIA_USB - -#endif } -void receive_can_battery(CAN_frame rx_frame) { +void handle_incoming_can_frame_battery(CAN_frame rx_frame) { datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; switch (rx_frame.ID) { case 0x18DAF1DB: // LBC Reply from active polling @@ -362,7 +358,7 @@ void receive_can_battery(CAN_frame rx_frame) { } } -void send_can_battery() { +void transmit_can_battery() { unsigned long currentMillis = millis(); // Send 200ms CAN Message if (currentMillis - previousMillis200 >= INTERVAL_200_MS) { @@ -379,8 +375,8 @@ void send_can_battery() { ZOE_POLL_18DADBF1.data.u8[2] = (uint8_t)((currentpoll & 0xFF00) >> 8); ZOE_POLL_18DADBF1.data.u8[3] = (uint8_t)(currentpoll & 0x00FF); - transmit_can(&ZOE_POLL_18DADBF1, can_config.battery); - transmit_can(&ZOE_373, can_config.battery); + transmit_can_frame(&ZOE_POLL_18DADBF1, can_config.battery); + transmit_can_frame(&ZOE_373, can_config.battery); } } diff --git a/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.h b/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.h index c75bb774..cfcc65d7 100644 --- a/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.h +++ b/Software/src/battery/RENAULT-ZOE-GEN2-BATTERY.h @@ -10,7 +10,7 @@ #define MIN_CELL_VOLTAGE_MV 2700 //Battery is put into emergency stop if one cell goes below this value void setup_battery(void); -void transmit_can(CAN_frame* tx_frame, int interface); +void transmit_can_frame(CAN_frame* tx_frame, int interface); #define POLL_SOC 0x9001 #define POLL_USABLE_SOC 0x9002 diff --git a/Software/src/battery/RJXZS-BMS.cpp b/Software/src/battery/RJXZS-BMS.cpp index 85b96434..345e8eae 100644 --- a/Software/src/battery/RJXZS-BMS.cpp +++ b/Software/src/battery/RJXZS-BMS.cpp @@ -158,21 +158,21 @@ void update_values_battery() { datalayer.battery.status.cell_min_voltage_mV = minimum_cell_voltage; } -void receive_can_battery(CAN_frame rx_frame) { +void handle_incoming_can_frame_battery(CAN_frame rx_frame) { /* // All CAN messages recieved will be logged via serial - Serial.print(millis()); // Example printout, time, ID, length, data: 7553 1DB 8 FF C0 B9 EA 0 0 2 5D - Serial.print(" "); - Serial.print(rx_frame.ID, HEX); - Serial.print(" "); - Serial.print(rx_frame.DLC); - Serial.print(" "); + logging.print(millis()); // Example printout, time, ID, length, data: 7553 1DB 8 FF C0 B9 EA 0 0 2 5D + logging.print(" "); + logging.print(rx_frame.ID, HEX); + logging.print(" "); + logging.print(rx_frame.DLC); + logging.print(" "); for (int i = 0; i < rx_frame.DLC; ++i) { - Serial.print(rx_frame.data.u8[i], HEX); - Serial.print(" "); + logging.print(rx_frame.data.u8[i], HEX); + logging.print(" "); } - Serial.println(""); + logging.println(""); */ switch (rx_frame.ID) { case 0xF5: // This is the only message is sent from BMS @@ -550,7 +550,7 @@ void receive_can_battery(CAN_frame rx_frame) { } } -void send_can_battery() { +void transmit_can_battery() { unsigned long currentMillis = millis(); // Send 10s CAN Message if (currentMillis - previousMillis10s >= INTERVAL_10_S) { @@ -563,8 +563,8 @@ void send_can_battery() { } if (!setup_completed) { - transmit_can(&RJXZS_10, can_config.battery); // Communication connected flag - transmit_can(&RJXZS_1C, can_config.battery); // CAN OK + transmit_can_frame(&RJXZS_10, can_config.battery); // Communication connected flag + transmit_can_frame(&RJXZS_1C, can_config.battery); // CAN OK } } } diff --git a/Software/src/battery/RJXZS-BMS.h b/Software/src/battery/RJXZS-BMS.h index f42af734..a6067039 100644 --- a/Software/src/battery/RJXZS-BMS.h +++ b/Software/src/battery/RJXZS-BMS.h @@ -19,6 +19,6 @@ #define NATIVECAN_250KBPS void setup_battery(void); -void transmit_can(CAN_frame* tx_frame, int interface); +void transmit_can_frame(CAN_frame* tx_frame, int interface); #endif diff --git a/Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp b/Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp index 766a9094..db1e4377 100644 --- a/Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp +++ b/Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp @@ -116,7 +116,7 @@ void update_values_battery() { //This function maps all the values fetched via } } -void receive_can_battery(CAN_frame rx_frame) { +void handle_incoming_can_frame_battery(CAN_frame rx_frame) { switch (rx_frame.ID) { case 0x1FF: datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; @@ -171,7 +171,8 @@ void receive_can_battery(CAN_frame rx_frame) { switch (rx_frame.data.u8[0]) { case 0x10: //"PID Header" if (rx_frame.data.u8[4] == poll_data_pid) { - transmit_can(&SANTAFE_7E4_ack, can_config.battery); //Send ack to BMS if the same frame is sent as polled + transmit_can_frame(&SANTAFE_7E4_ack, + can_config.battery); //Send ack to BMS if the same frame is sent as polled } break; case 0x21: //First frame in PID group @@ -332,7 +333,7 @@ void receive_can_battery(CAN_frame rx_frame) { break; } } -void send_can_battery() { +void transmit_can_battery() { unsigned long currentMillis = millis(); //Send 10ms message @@ -351,13 +352,13 @@ void send_can_battery() { SANTAFE_200.data.u8[7] = checksum_200; - transmit_can(&SANTAFE_200, can_config.battery); - transmit_can(&SANTAFE_2A1, can_config.battery); - transmit_can(&SANTAFE_2F0, can_config.battery); + transmit_can_frame(&SANTAFE_200, can_config.battery); + transmit_can_frame(&SANTAFE_2A1, can_config.battery); + transmit_can_frame(&SANTAFE_2F0, can_config.battery); #ifdef DOUBLE_BATTERY - transmit_can(&SANTAFE_200, can_config.battery_double); - transmit_can(&SANTAFE_2A1, can_config.battery_double); - transmit_can(&SANTAFE_2F0, can_config.battery_double); + transmit_can_frame(&SANTAFE_200, can_config.battery_double); + transmit_can_frame(&SANTAFE_2A1, can_config.battery_double); + transmit_can_frame(&SANTAFE_2F0, can_config.battery_double); #endif //DOUBLE_BATTERY counter_200++; @@ -370,9 +371,9 @@ void send_can_battery() { if (currentMillis - previousMillis100 >= INTERVAL_100_MS) { previousMillis100 = currentMillis; - transmit_can(&SANTAFE_523, can_config.battery); + transmit_can_frame(&SANTAFE_523, can_config.battery); #ifdef DOUBLE_BATTERY - transmit_can(&SANTAFE_523, can_config.battery_double); + transmit_can_frame(&SANTAFE_523, can_config.battery_double); #endif //DOUBLE_BATTERY } @@ -383,9 +384,9 @@ void send_can_battery() { // PID data is polled after last message sent from battery: poll_data_pid = (poll_data_pid % 5) + 1; SANTAFE_7E4_poll.data.u8[3] = (uint8_t)poll_data_pid; - transmit_can(&SANTAFE_7E4_poll, can_config.battery); + transmit_can_frame(&SANTAFE_7E4_poll, can_config.battery); #ifdef DOUBLE_BATTERY - transmit_can(&SANTAFE_7E4_poll, can_config.battery_double); + transmit_can_frame(&SANTAFE_7E4_poll, can_config.battery_double); #endif //DOUBLE_BATTERY } } @@ -425,7 +426,7 @@ void update_values_battery2() { //This function maps all the values fetched via } } -void receive_can_battery2(CAN_frame rx_frame) { +void handle_incoming_can_frame_battery2(CAN_frame rx_frame) { switch (rx_frame.ID) { case 0x1FF: datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE; @@ -480,8 +481,8 @@ void receive_can_battery2(CAN_frame rx_frame) { switch (rx_frame.data.u8[0]) { case 0x10: //"PID Header" if (rx_frame.data.u8[4] == poll_data_pid) { - transmit_can(&SANTAFE_7E4_ack, - can_config.battery_double); //Send ack to BMS if the same frame is sent as polled + transmit_can_frame(&SANTAFE_7E4_ack, + can_config.battery_double); //Send ack to BMS if the same frame is sent as polled } break; case 0x21: //First frame in PID group diff --git a/Software/src/battery/SANTA-FE-PHEV-BATTERY.h b/Software/src/battery/SANTA-FE-PHEV-BATTERY.h index fb4774a5..092a200e 100644 --- a/Software/src/battery/SANTA-FE-PHEV-BATTERY.h +++ b/Software/src/battery/SANTA-FE-PHEV-BATTERY.h @@ -12,6 +12,6 @@ uint8_t CalculateCRC8(CAN_frame rx_frame); void setup_battery(void); -void transmit_can(CAN_frame* tx_frame, int interface); +void transmit_can_frame(CAN_frame* tx_frame, int interface); #endif diff --git a/Software/src/battery/SERIAL-LINK-RECEIVER-FROM-BATTERY.cpp b/Software/src/battery/SERIAL-LINK-RECEIVER-FROM-BATTERY.cpp index 41697c33..35a7104c 100644 --- a/Software/src/battery/SERIAL-LINK-RECEIVER-FROM-BATTERY.cpp +++ b/Software/src/battery/SERIAL-LINK-RECEIVER-FROM-BATTERY.cpp @@ -94,8 +94,8 @@ void manageSerialLinkReceiver() { bool readError = dataLinkReceive.checkReadError(true); // check for error & clear error flag if (readError) { - Serial.print(currentTime); - Serial.println(" - ERROR: SerialDataLink - Read Error"); + logging.print(currentTime); + logging.println(" - ERROR: SerialDataLink - Read Error"); lasterror = true; errors++; } @@ -112,8 +112,8 @@ void manageSerialLinkReceiver() { //bms_status = ACTIVE; // just testing if (lasterror) { lasterror = false; - Serial.print(currentTime); - Serial.println(" - RECOVERY: SerialDataLink - Read GOOD"); + logging.print(currentTime); + logging.println(" - RECOVERY: SerialDataLink - Read GOOD"); } } @@ -134,34 +134,34 @@ void manageSerialLinkReceiver() { // report Lost data & Max charge / Discharge reductions if (minutesLost != last_minutesLost) { last_minutesLost = minutesLost; - Serial.print(currentTime); + logging.print(currentTime); if (batteryFault) { - Serial.print("Battery Fault (minutes) : "); + logging.print("Battery Fault (minutes) : "); } else { - Serial.print(" - Minutes without data : "); + logging.print(" - Minutes without data : "); } - Serial.print(minutesLost); - Serial.print(", max Charge = "); - Serial.print(datalayer.battery.status.max_charge_power_W); - Serial.print(", max Discharge = "); - Serial.println(datalayer.battery.status.max_discharge_power_W); + logging.print(minutesLost); + logging.print(", max Charge = "); + logging.print(datalayer.battery.status.max_charge_power_W); + logging.print(", max Discharge = "); + logging.println(datalayer.battery.status.max_discharge_power_W); } } if (currentTime - reportTime > 59999) { reportTime = currentTime; - Serial.print(currentTime); - Serial.print(" SerialDataLink-Receiver - NewData :"); - Serial.print(reads); - Serial.print(" Errors : "); - Serial.println(errors); + logging.print(currentTime); + logging.print(" SerialDataLink-Receiver - NewData :"); + logging.print(reads); + logging.print(" Errors : "); + logging.println(errors); reads = 0; errors = 0; // --- printUsefullData(); -//Serial.print("SOC = "); -//Serial.println(SOC); -#ifdef DEBUG_VIA_USB +//logging.print("SOC = "); +//logging.println(SOC); +#ifdef DEBUG_LOG update_values_serial_link(); #endif } @@ -179,43 +179,43 @@ void manageSerialLinkReceiver() { } void update_values_serial_link() { - Serial.println("Values from battery: "); - Serial.print("SOC: "); - Serial.print(datalayer.battery.status.real_soc); - Serial.print(" SOH: "); - Serial.print(datalayer.battery.status.soh_pptt); - Serial.print(" Voltage: "); - Serial.print(datalayer.battery.status.voltage_dV); - Serial.print(" Current: "); - Serial.print(datalayer.battery.status.current_dA); - Serial.print(" Capacity: "); - Serial.print(datalayer.battery.info.total_capacity_Wh); - Serial.print(" Remain cap: "); - Serial.print(datalayer.battery.status.remaining_capacity_Wh); - Serial.print(" Max discharge W: "); - Serial.print(datalayer.battery.status.max_discharge_power_W); - Serial.print(" Max charge W: "); - Serial.print(datalayer.battery.status.max_charge_power_W); - Serial.print(" BMS status: "); - Serial.print(datalayer.battery.status.bms_status); - Serial.print(" Power: "); - Serial.print(datalayer.battery.status.active_power_W); - Serial.print(" Temp min: "); - Serial.print(datalayer.battery.status.temperature_min_dC); - Serial.print(" Temp max: "); - Serial.print(datalayer.battery.status.temperature_max_dC); - Serial.print(" Cell max: "); - Serial.print(datalayer.battery.status.cell_max_voltage_mV); - Serial.print(" Cell min: "); - Serial.print(datalayer.battery.status.cell_min_voltage_mV); - Serial.print(" LFP : "); - Serial.print(datalayer.battery.info.chemistry); - Serial.print(" Battery Allows Contactor Closing: "); - Serial.print(datalayer.system.status.battery_allows_contactor_closing); - Serial.print(" Inverter Allows Contactor Closing: "); - Serial.print(datalayer.system.status.inverter_allows_contactor_closing); + logging.println("Values from battery: "); + logging.print("SOC: "); + logging.print(datalayer.battery.status.real_soc); + logging.print(" SOH: "); + logging.print(datalayer.battery.status.soh_pptt); + logging.print(" Voltage: "); + logging.print(datalayer.battery.status.voltage_dV); + logging.print(" Current: "); + logging.print(datalayer.battery.status.current_dA); + logging.print(" Capacity: "); + logging.print(datalayer.battery.info.total_capacity_Wh); + logging.print(" Remain cap: "); + logging.print(datalayer.battery.status.remaining_capacity_Wh); + logging.print(" Max discharge W: "); + logging.print(datalayer.battery.status.max_discharge_power_W); + logging.print(" Max charge W: "); + logging.print(datalayer.battery.status.max_charge_power_W); + logging.print(" BMS status: "); + logging.print(datalayer.battery.status.bms_status); + logging.print(" Power: "); + logging.print(datalayer.battery.status.active_power_W); + logging.print(" Temp min: "); + logging.print(datalayer.battery.status.temperature_min_dC); + logging.print(" Temp max: "); + logging.print(datalayer.battery.status.temperature_max_dC); + logging.print(" Cell max: "); + logging.print(datalayer.battery.status.cell_max_voltage_mV); + logging.print(" Cell min: "); + logging.print(datalayer.battery.status.cell_min_voltage_mV); + logging.print(" LFP : "); + logging.print(datalayer.battery.info.chemistry); + logging.print(" Battery Allows Contactor Closing: "); + logging.print(datalayer.system.status.battery_allows_contactor_closing); + logging.print(" Inverter Allows Contactor Closing: "); + logging.print(datalayer.system.status.inverter_allows_contactor_closing); - Serial.println(""); + logging.println(""); } void setup_battery(void) { @@ -224,7 +224,7 @@ void setup_battery(void) { } // Needed to make the compiler happy void update_values_battery() {} -void send_can_battery() {} -void receive_can_battery(CAN_frame rx_frame) {} +void transmit_can_battery() {} +void handle_incoming_can_frame_battery(CAN_frame rx_frame) {} #endif diff --git a/Software/src/battery/TESLA-BATTERY.cpp b/Software/src/battery/TESLA-BATTERY.cpp index f6db10a8..50112449 100644 --- a/Software/src/battery/TESLA-BATTERY.cpp +++ b/Software/src/battery/TESLA-BATTERY.cpp @@ -8,8 +8,8 @@ /* Do not change code below unless you are sure what you are doing */ /* Credits: Most of the code comes from Per Carlen's bms_comms_tesla_model3.py (https://gitlab.com/pelle8/batt2gen24/) */ -static unsigned long previousMillis30 = 0; // will store last time a 30ms CAN Message was send - +static unsigned long previousMillis50 = 0; // will store last time a 50ms CAN Message was send +//0x221 545 VCFRONT_LVPowerState: "GenMsgCycleTime" 50ms CAN_frame TESLA_221_1 = { .FD = false, .ext_ID = false, @@ -22,240 +22,776 @@ CAN_frame TESLA_221_2 = { .DLC = 8, .ID = 0x221, .data = {0x61, 0x15, 0x01, 0x00, 0x00, 0x00, 0x20, 0xBA}}; //Contactor Frame 221 - hv_up_for_drive + static uint16_t sendContactorClosingMessagesStill = 300; +static uint16_t battery_cell_max_v = 3300; +static uint16_t battery_cell_min_v = 3300; +static uint16_t battery_cell_deviation_mV = 0; //contains the deviation between highest and lowest cell in mV +static bool cellvoltagesRead = false; +//0x3d2: 978 BMS_kwhCounter static uint32_t battery_total_discharge = 0; static uint32_t battery_total_charge = 0; -static uint16_t battery_volts = 0; // V -static int16_t battery_amps = 0; // A -static uint16_t battery_raw_amps = 0; // A -static int16_t battery_max_temp = 0; // C* -static int16_t battery_min_temp = 0; // C* -static uint16_t battery_energy_buffer = 0; // kWh -static uint16_t battery_energy_buffer_m1 = 0; // kWh -static uint16_t battery_energy_to_charge_complete = 0; // kWh -static uint16_t battery_energy_to_charge_complete_m1 = 0; // kWh -static uint16_t battery_expected_energy_remaining = 0; // kWh -static uint16_t battery_expected_energy_remaining_m1 = 0; // kWh -static uint8_t battery_full_charge_complete = 0; // kWh -static uint8_t battery_fully_charged = 0; // kWh -static uint16_t battery_ideal_energy_remaining = 0; // kWh -static uint16_t battery_ideal_energy_remaining_m0 = 0; // kWh -static uint16_t battery_nominal_energy_remaining = 0; // kWh -static uint16_t battery_nominal_energy_remaining_m0 = 0; // kWh -static uint16_t battery_nominal_full_pack_energy = 600; // Kwh -static uint16_t battery_nominal_full_pack_energy_m0 = 600; // Kwh -static uint16_t battery_beginning_of_life = 600; // kWh -static uint16_t battery_charge_time_remaining = 0; // Minutes -static uint16_t battery_regenerative_limit = 0; -static uint16_t battery_discharge_limit = 0; -static uint16_t battery_max_heat_park = 0; -static uint16_t battery_hvac_max_power = 0; +//0x352: 850 BMS_energyStatus +static uint16_t battery_energy_buffer = 0; // kWh +static uint16_t battery_energy_buffer_m1 = 0; // kWh +static uint16_t battery_energy_to_charge_complete = 0; // kWh +static uint16_t battery_energy_to_charge_complete_m1 = 0; // kWh +static uint16_t battery_expected_energy_remaining = 0; // kWh +static uint16_t battery_expected_energy_remaining_m1 = 0; // kWh +static bool battery_full_charge_complete = false; // Changed to bool +static bool battery_fully_charged = false; // Changed to bool +static uint16_t battery_ideal_energy_remaining = 0; // kWh +static uint16_t battery_ideal_energy_remaining_m0 = 0; // kWh +static uint16_t battery_nominal_energy_remaining = 0; // kWh +static uint16_t battery_nominal_energy_remaining_m0 = 0; // kWh +static uint16_t battery_nominal_full_pack_energy = 0; // Kwh +static uint16_t battery_nominal_full_pack_energy_m0 = 0; // Kwh +//0x132 306 HVBattAmpVolt +static uint16_t battery_volts = 0; // V +static int16_t battery_amps = 0; // A +static int16_t battery_raw_amps = 0; // A +static uint16_t battery_charge_time_remaining = 0; // Minutes +//0x252 594 BMS_powerAvailable +static uint16_t BMS_maxRegenPower = 0; //rename from battery_regenerative_limit +static uint16_t BMS_maxDischargePower = 0; // rename from battery_discharge_limit +static uint16_t BMS_maxStationaryHeatPower = 0; //rename from battery_max_heat_park +static uint16_t BMS_hvacPowerBudget = 0; //rename from battery_hvac_max_power +static uint8_t BMS_notEnoughPowerForHeatPump = 0; +static uint8_t BMS_powerLimitState = 0; +static uint8_t BMS_inverterTQF = 0; +//0x2d2: 722 BMSVAlimits static uint16_t battery_max_discharge_current = 0; static uint16_t battery_max_charge_current = 0; static uint16_t battery_bms_max_voltage = 0; static uint16_t battery_bms_min_voltage = 0; +//0x2b4: 692 PCS_dcdcRailStatus static uint16_t battery_dcdcHvBusVolt = 0; // Change name from battery_high_voltage to battery_dcdcHvBusVolt static uint16_t battery_dcdcLvBusVolt = 0; // Change name from battery_low_voltage to battery_dcdcLvBusVolt static uint16_t battery_dcdcLvOutputCurrent = 0; // Change name from battery_output_current to battery_dcdcLvOutputCurrent +//0x292: 658 BMS_socStatus +static uint16_t battery_beginning_of_life = 0; // kWh static uint16_t battery_soc_min = 0; static uint16_t battery_soc_max = 0; static uint16_t battery_soc_ui = 0; //Change name from battery_soc_vi to reflect DBC battery_soc_ui static uint16_t battery_soc_ave = 0; -static uint16_t battery_cell_max_v = 3700; -static uint16_t battery_cell_min_v = 3700; -static uint16_t battery_cell_deviation_mV = 0; //contains the deviation between highest and lowest cell in mV -static uint8_t battery_max_vno = 0; -static uint8_t battery_min_vno = 0; -static uint8_t battery_contactor = 0; //State of contactor -static uint8_t battery_hvil_status = 0; -static uint8_t battery_packContNegativeState = 0; -static uint8_t battery_packContPositiveState = 0; -static uint8_t battery_packContactorSetState = 0; -static uint8_t battery_packCtrsClosingAllowed = 0; -static uint8_t battery_pyroTestInProgress = 0; static uint8_t battery_battTempPct = 0; +//0x392: BMS_packConfig static uint32_t battery_packMass = 0; static uint32_t battery_platformMaxBusVoltage = 0; static uint32_t battery_packConfigMultiplexer = 0; static uint32_t battery_moduleType = 0; static uint32_t battery_reservedConfig = 0; -//Fault codes -static uint8_t battery_WatchdogReset = 0; //Warns if the processor has experienced a reset due to watchdog reset. -static uint8_t battery_PowerLossReset = 0; //Warns if the processor has experienced a reset due to power loss. -static uint8_t battery_SwAssertion = 0; //An internal software assertion has failed. -static uint8_t battery_CrashEvent = 0; //Warns if the crash signal is detected by HVP -static uint8_t battery_OverDchgCurrentFault = 0; //Warns if the pack discharge is above max discharge current limit -static uint8_t battery_OverChargeCurrentFault = - 0; //Warns if the pack discharge current is above max charge current limit -static uint8_t battery_OverCurrentFault = - 0; //Warns if the pack current (discharge or charge) is above max current limit. -static uint8_t battery_OverTemperatureFault = 0; //A pack module temperature is above maximum temperature limit -static uint8_t battery_OverVoltageFault = 0; //A brick voltage is above maximum voltage limit -static uint8_t battery_UnderVoltageFault = 0; //A brick voltage is below minimum voltage limit -static uint8_t battery_PrimaryBmbMiaFault = - 0; //Warns if the voltage and temperature readings from primary BMB chain are mia -static uint8_t battery_SecondaryBmbMiaFault = - 0; //Warns if the voltage and temperature readings from secondary BMB chain are mia -static uint8_t battery_BmbMismatchFault = - 0; //Warns if the primary and secondary BMB chain readings don't match with each other -static uint8_t battery_BmsHviMiaFault = 0; //Warns if the BMS node is mia on HVS or HVI CAN -static uint8_t battery_CpMiaFault = 0; //Warns if the CP node is mia on HVS CAN -static uint8_t battery_PcsMiaFault = 0; //The PCS node is mia on HVS CAN -static uint8_t battery_BmsFault = 0; //Warns if the BMS ECU has faulted -static uint8_t battery_PcsFault = 0; //Warns if the PCS ECU has faulted -static uint8_t battery_CpFault = 0; //Warns if the CP ECU has faulted -static uint8_t battery_ShuntHwMiaFault = 0; //Warns if the shunt current reading is not available -static uint8_t battery_PyroMiaFault = 0; //Warns if the pyro squib is not connected -static uint8_t battery_hvsMiaFault = 0; //Warns if the pack contactor hw fault -static uint8_t battery_hviMiaFault = 0; //Warns if the FC contactor hw fault -static uint8_t battery_Supply12vFault = 0; //Warns if the low voltage (12V) battery is below minimum voltage threshold -static uint8_t battery_VerSupplyFault = - 0; //Warns if the Energy reserve voltage supply is below minimum voltage threshold -static uint8_t battery_HvilFault = 0; //Warn if a High Voltage Inter Lock fault is detected -static uint8_t battery_BmsHvsMiaFault = 0; //Warns if the BMS node is mia on HVS or HVI CAN -static uint8_t battery_PackVoltMismatchFault = - 0; //Warns if the pack voltage doesn't match approximately with sum of brick voltages -static uint8_t battery_EnsMiaFault = 0; //Warns if the ENS line is not connected to HVC -static uint8_t battery_PackPosCtrArcFault = 0; //Warns if the HVP detectes series arc at pack contactor -static uint8_t battery_packNegCtrArcFault = 0; //Warns if the HVP detectes series arc at FC contactor -static uint8_t battery_ShuntHwAndBmsMiaFault = 0; -static uint8_t battery_fcContHwFault = 0; -static uint8_t battery_robinOverVoltageFault = 0; -static uint8_t battery_packContHwFault = 0; -static uint8_t battery_pyroFuseBlown = 0; -static uint8_t battery_pyroFuseFailedToBlow = 0; -static uint8_t battery_CpilFault = 0; -static uint8_t battery_PackContactorFellOpen = 0; -static uint8_t battery_FcContactorFellOpen = 0; -static uint8_t battery_packCtrCloseBlocked = 0; -static uint8_t battery_fcCtrCloseBlocked = 0; -static uint8_t battery_packContactorForceOpen = 0; -static uint8_t battery_fcContactorForceOpen = 0; -static uint8_t battery_dcLinkOverVoltage = 0; -static uint8_t battery_shuntOverTemperature = 0; -static uint8_t battery_passivePyroDeploy = 0; -static uint8_t battery_logUploadRequest = 0; -static uint8_t battery_packCtrCloseFailed = 0; -static uint8_t battery_fcCtrCloseFailed = 0; -static uint8_t battery_shuntThermistorMia = 0; +//0x332: 818 BattBrickMinMax:BMS_bmbMinMax +static int16_t battery_max_temp = 0; // C* +static int16_t battery_min_temp = 0; // C* +static uint16_t battery_BrickVoltageMax = 0; +static uint16_t battery_BrickVoltageMin = 0; +static uint8_t battery_BrickTempMaxNum = 0; +static uint8_t battery_BrickTempMinNum = 0; +static uint8_t battery_BrickModelTMax = 0; +static uint8_t battery_BrickModelTMin = 0; +static uint8_t battery_BrickVoltageMaxNum = 0; //rename from battery_max_vno +static uint8_t battery_BrickVoltageMinNum = 0; //rename from battery_min_vno +//0x20A: 522 HVP_contactorState +static uint8_t battery_contactor = 0; //State of contactor +static uint8_t battery_hvil_status = 0; +static uint8_t battery_packContNegativeState = 0; +static uint8_t battery_packContPositiveState = 0; +static uint8_t battery_packContactorSetState = 0; +static bool battery_packCtrsClosingAllowed = false; // Change to bool +static bool battery_pyroTestInProgress = false; // Change to bool +static bool battery_packCtrsOpenNowRequested = false; // Change to bool +static bool battery_packCtrsOpenRequested = false; // Change to bool +static uint8_t battery_packCtrsRequestStatus = 0; +static bool battery_packCtrsResetRequestRequired = false; // Change to bool +static bool battery_dcLinkAllowedToEnergize = false; // Change to bool +static bool battery_fcContNegativeAuxOpen = false; // Change to bool +static uint8_t battery_fcContNegativeState = 0; +static bool battery_fcContPositiveAuxOpen = false; // Change to bool +static uint8_t battery_fcContPositiveState = 0; +static uint8_t battery_fcContactorSetState = 0; +static bool battery_fcCtrsClosingAllowed = false; // Change to bool +static bool battery_fcCtrsOpenNowRequested = false; // Change to bool +static bool battery_fcCtrsOpenRequested = false; // Change to bool +static uint8_t battery_fcCtrsRequestStatus = 0; +static bool battery_fcCtrsResetRequestRequired = false; // Change to bool +static bool battery_fcLinkAllowedToEnergize = false; // Change to bool +//0x212: 530 BMS_status +static bool battery_BMS_hvacPowerRequest = false; //Change to bool +static bool battery_BMS_notEnoughPowerForDrive = false; //Change to bool +static bool battery_BMS_notEnoughPowerForSupport = false; //Change to bool +static bool battery_BMS_preconditionAllowed = false; //Change to bool +static bool battery_BMS_updateAllowed = false; //Change to bool +static bool battery_BMS_activeHeatingWorthwhile = false; //Change to bool +static bool battery_BMS_cpMiaOnHvs = false; //Change to bool +static uint8_t battery_BMS_contactorState = 0; +static uint8_t battery_BMS_state = 0; +static uint8_t battery_BMS_hvState = 0; +static uint16_t battery_BMS_isolationResistance = 0; +static bool battery_BMS_chargeRequest = false; //Change to bool +static bool battery_BMS_keepWarmRequest = false; //Change to bool +static uint8_t battery_BMS_uiChargeStatus = 0; +static bool battery_BMS_diLimpRequest = false; //Change to bool +static bool battery_BMS_okToShipByAir = false; //Change to bool +static bool battery_BMS_okToShipByLand = false; //Change to bool +static uint32_t battery_BMS_chgPowerAvailable = 0; +static uint8_t battery_BMS_chargeRetryCount = 0; +static bool battery_BMS_pcsPwmEnabled = false; //Change to bool +static bool battery_BMS_ecuLogUploadRequest = false; //Change to bool +static uint8_t battery_BMS_minPackTemperature = 0; +// 0x224:548 PCS_dcdcStatus +static uint8_t battery_PCS_dcdcPrechargeStatus = 0; +static uint8_t battery_PCS_dcdc12VSupportStatus = 0; +static uint8_t battery_PCS_dcdcHvBusDischargeStatus = 0; +static uint16_t battery_PCS_dcdcMainState = 0; +static uint8_t battery_PCS_dcdcSubState = 0; +static bool battery_PCS_dcdcFaulted = false; //Change to bool +static bool battery_PCS_dcdcOutputIsLimited = false; //Change to bool +static uint32_t battery_PCS_dcdcMaxOutputCurrentAllowed = 0; +static uint8_t battery_PCS_dcdcPrechargeRtyCnt = 0; +static uint8_t battery_PCS_dcdc12VSupportRtyCnt = 0; +static uint8_t battery_PCS_dcdcDischargeRtyCnt = 0; +static uint8_t battery_PCS_dcdcPwmEnableLine = 0; +static uint8_t battery_PCS_dcdcSupportingFixedLvTarget = 0; +static uint8_t battery_PCS_ecuLogUploadRequest = 0; +static uint8_t battery_PCS_dcdcPrechargeRestartCnt = 0; +static uint8_t battery_PCS_dcdcInitialPrechargeSubState = 0; +//0x312: 786 BMS_thermalStatus +static uint16_t BMS_powerDissipation = 0; +static uint16_t BMS_flowRequest = 0; +static uint16_t BMS_inletActiveCoolTargetT = 0; +static uint16_t BMS_inletPassiveTargetT = 0; +static uint16_t BMS_inletActiveHeatTargetT = 0; +static uint16_t BMS_packTMin = 0; +static uint16_t BMS_packTMax = 0; +static bool BMS_pcsNoFlowRequest = false; +static bool BMS_noFlowRequest = false; +//0x2A4; 676 PCS_thermalStatus +static int16_t PCS_chgPhATemp = 0; +static int16_t PCS_chgPhBTemp = 0; +static int16_t PCS_chgPhCTemp = 0; +static int16_t PCS_dcdcTemp = 0; +static int16_t PCS_ambientTemp = 0; +//0x2C4; 708 PCS_logging +static uint16_t PCS_logMessageSelect = 0; +static uint16_t PCS_dcdcMaxLvOutputCurrent = 0; +static uint16_t PCS_dcdcCurrentLimit = 0; +static uint16_t PCS_dcdcLvOutputCurrentTempLimit = 0; +static uint16_t PCS_dcdcUnifiedCommand = 0; +static uint16_t PCS_dcdcCLAControllerOutput = 0; +static int16_t PCS_dcdcTankVoltage = 0; +static uint16_t PCS_dcdcTankVoltageTarget = 0; +static uint16_t PCS_dcdcClaCurrentFreq = 0; +static int16_t PCS_dcdcTCommMeasured = 0; +static uint16_t PCS_dcdcShortTimeUs = 0; +static uint16_t PCS_dcdcHalfPeriodUs = 0; +static uint16_t PCS_dcdcIntervalMaxFrequency = 0; +static uint16_t PCS_dcdcIntervalMaxHvBusVolt = 0; +static uint16_t PCS_dcdcIntervalMaxLvBusVolt = 0; +static uint16_t PCS_dcdcIntervalMaxLvOutputCurr = 0; +static uint16_t PCS_dcdcIntervalMinFrequency = 0; +static uint16_t PCS_dcdcIntervalMinHvBusVolt = 0; +static uint16_t PCS_dcdcIntervalMinLvBusVolt = 0; +static uint16_t PCS_dcdcIntervalMinLvOutputCurr = 0; +static uint32_t PCS_dcdc12vSupportLifetimekWh = 0; +//0x7AA: //1962 HVP_debugMessage: +static uint8_t HVP_debugMessageMultiplexer = 0; +static bool HVP_gpioPassivePyroDepl = false; //Change to bool +static bool HVP_gpioPyroIsoEn = false; //Change to bool +static bool HVP_gpioCpFaultIn = false; //Change to bool +static bool HVP_gpioPackContPowerEn = false; //Change to bool +static bool HVP_gpioHvCablesOk = false; //Change to bool +static bool HVP_gpioHvpSelfEnable = false; //Change to bool +static bool HVP_gpioLed = false; //Change to bool +static bool HVP_gpioCrashSignal = false; //Change to bool +static bool HVP_gpioShuntDataReady = false; //Change to bool +static bool HVP_gpioFcContPosAux = false; //Change to bool +static bool HVP_gpioFcContNegAux = false; //Change to bool +static bool HVP_gpioBmsEout = false; //Change to bool +static bool HVP_gpioCpFaultOut = false; //Change to bool +static bool HVP_gpioPyroPor = false; //Change to bool +static bool HVP_gpioShuntEn = false; //Change to bool +static bool HVP_gpioHvpVerEn = false; //Change to bool +static bool HVP_gpioPackCoontPosFlywheel = false; //Change to bool +static bool HVP_gpioCpLatchEnable = false; //Change to bool +static bool HVP_gpioPcsEnable = false; //Change to bool +static bool HVP_gpioPcsDcdcPwmEnable = false; //Change to bool +static bool HVP_gpioPcsChargePwmEnable = false; //Change to bool +static bool HVP_gpioFcContPowerEnable = false; //Change to bool +static bool HVP_gpioHvilEnable = false; //Change to bool +static bool HVP_gpioSecDrdy = false; //Change to bool +static uint16_t HVP_hvp1v5Ref = 0; +static int16_t HVP_shuntCurrentDebug = 0; +static bool HVP_packCurrentMia = false; //Change to bool +static bool HVP_auxCurrentMia = false; //Change to bool +static bool HVP_currentSenseMia = false; //Change to bool +static bool HVP_shuntRefVoltageMismatch = false; //Change to bool +static bool HVP_shuntThermistorMia = false; //Change to bool +static bool HVP_shuntHwMia = false; //Change to bool +static int16_t HVP_dcLinkVoltage = 0; +static int16_t HVP_packVoltage = 0; +static int16_t HVP_fcLinkVoltage = 0; +static uint16_t HVP_packContVoltage = 0; +static int16_t HVP_packNegativeV = 0; +static int16_t HVP_packPositiveV = 0; +static uint16_t HVP_pyroAnalog = 0; +static int16_t HVP_dcLinkNegativeV = 0; +static int16_t HVP_dcLinkPositiveV = 0; +static int16_t HVP_fcLinkNegativeV = 0; +static uint16_t HVP_fcContCoilCurrent = 0; +static uint16_t HVP_fcContVoltage = 0; +static uint16_t HVP_hvilInVoltage = 0; +static uint16_t HVP_hvilOutVoltage = 0; +static int16_t HVP_fcLinkPositiveV = 0; +static uint16_t HVP_packContCoilCurrent = 0; +static uint16_t HVP_battery12V = 0; +static int16_t HVP_shuntRefVoltageDbg = 0; +static int16_t HVP_shuntAuxCurrentDbg = 0; +static int16_t HVP_shuntBarTempDbg = 0; +static int16_t HVP_shuntAsicTempDbg = 0; +static uint8_t HVP_shuntAuxCurrentStatus = 0; +static uint8_t HVP_shuntBarTempStatus = 0; +static uint8_t HVP_shuntAsicTempStatus = 0; +//0x3aa: HVP_alertMatrix1 Fault codes // Change to bool +static bool battery_WatchdogReset = false; //Warns if the processor has experienced a reset due to watchdog reset. +static bool battery_PowerLossReset = false; //Warns if the processor has experienced a reset due to power loss. +static bool battery_SwAssertion = false; //An internal software assertion has failed. +static bool battery_CrashEvent = false; //Warns if the crash signal is detected by HVP +static bool battery_OverDchgCurrentFault = false; //Warns if the pack discharge is above max discharge current limit +static bool battery_OverChargeCurrentFault = + false; //Warns if the pack discharge current is above max charge current limit +static bool battery_OverCurrentFault = + false; //Warns if the pack current (discharge or charge) is above max current limit. +static bool battery_OverTemperatureFault = false; //A pack module temperature is above maximum temperature limit +static bool battery_OverVoltageFault = false; //A brick voltage is above maximum voltage limit +static bool battery_UnderVoltageFault = false; //A brick voltage is below minimum voltage limit +static bool battery_PrimaryBmbMiaFault = + false; //Warns if the voltage and temperature readings from primary BMB chain are mia +static bool battery_SecondaryBmbMiaFault = + false; //Warns if the voltage and temperature readings from secondary BMB chain are mia +static bool battery_BmbMismatchFault = + false; //Warns if the primary and secondary BMB chain readings don't match with each other +static bool battery_BmsHviMiaFault = false; //Warns if the BMS node is mia on HVS or HVI CAN +static bool battery_CpMiaFault = false; //Warns if the CP node is mia on HVS CAN +static bool battery_PcsMiaFault = false; //The PCS node is mia on HVS CAN +static bool battery_BmsFault = false; //Warns if the BMS ECU has faulted +static bool battery_PcsFault = false; //Warns if the PCS ECU has faulted +static bool battery_CpFault = false; //Warns if the CP ECU has faulted +static bool battery_ShuntHwMiaFault = false; //Warns if the shunt current reading is not available +static bool battery_PyroMiaFault = false; //Warns if the pyro squib is not connected +static bool battery_hvsMiaFault = false; //Warns if the pack contactor hw fault +static bool battery_hviMiaFault = false; //Warns if the FC contactor hw fault +static bool battery_Supply12vFault = false; //Warns if the low voltage (12V) battery is below minimum voltage threshold +static bool battery_VerSupplyFault = + false; //Warns if the Energy reserve voltage supply is below minimum voltage threshold +static bool battery_HvilFault = false; //Warn if a High Voltage Inter Lock fault is detected +static bool battery_BmsHvsMiaFault = false; //Warns if the BMS node is mia on HVS or HVI CAN +static bool battery_PackVoltMismatchFault = + false; //Warns if the pack voltage doesn't match approximately with sum of brick voltages +static bool battery_EnsMiaFault = false; //Warns if the ENS line is not connected to HVC +static bool battery_PackPosCtrArcFault = false; //Warns if the HVP detectes series arc at pack contactor +static bool battery_packNegCtrArcFault = false; //Warns if the HVP detectes series arc at FC contactor +static bool battery_ShuntHwAndBmsMiaFault = false; +static bool battery_fcContHwFault = false; +static bool battery_robinOverVoltageFault = false; +static bool battery_packContHwFault = false; +static bool battery_pyroFuseBlown = false; +static bool battery_pyroFuseFailedToBlow = false; +static bool battery_CpilFault = false; +static bool battery_PackContactorFellOpen = false; +static bool battery_FcContactorFellOpen = false; +static bool battery_packCtrCloseBlocked = false; +static bool battery_fcCtrCloseBlocked = false; +static bool battery_packContactorForceOpen = false; +static bool battery_fcContactorForceOpen = false; +static bool battery_dcLinkOverVoltage = false; +static bool battery_shuntOverTemperature = false; +static bool battery_passivePyroDeploy = false; +static bool battery_logUploadRequest = false; +static bool battery_packCtrCloseFailed = false; +static bool battery_fcCtrCloseFailed = false; +static bool battery_shuntThermistorMia = false; +//0x320: 800 BMS_alertMatrix +static uint8_t battery_BMS_matrixIndex = 0; // Changed to bool +static bool battery_BMS_a061_robinBrickOverVoltage = false; +static bool battery_BMS_a062_SW_BrickV_Imbalance = false; +static bool battery_BMS_a063_SW_ChargePort_Fault = false; +static bool battery_BMS_a064_SW_SOC_Imbalance = false; +static bool battery_BMS_a127_SW_shunt_SNA = false; +static bool battery_BMS_a128_SW_shunt_MIA = false; +static bool battery_BMS_a069_SW_Low_Power = false; +static bool battery_BMS_a130_IO_CAN_Error = false; +static bool battery_BMS_a071_SW_SM_TransCon_Not_Met = false; +static bool battery_BMS_a132_HW_BMB_OTP_Uncorrctbl = false; +static bool battery_BMS_a134_SW_Delayed_Ctr_Off = false; +static bool battery_BMS_a075_SW_Chg_Disable_Failure = false; +static bool battery_BMS_a076_SW_Dch_While_Charging = false; +static bool battery_BMS_a017_SW_Brick_OV = false; +static bool battery_BMS_a018_SW_Brick_UV = false; +static bool battery_BMS_a019_SW_Module_OT = false; +static bool battery_BMS_a021_SW_Dr_Limits_Regulation = false; +static bool battery_BMS_a022_SW_Over_Current = false; +static bool battery_BMS_a023_SW_Stack_OV = false; +static bool battery_BMS_a024_SW_Islanded_Brick = false; +static bool battery_BMS_a025_SW_PwrBalance_Anomaly = false; +static bool battery_BMS_a026_SW_HFCurrent_Anomaly = false; +static bool battery_BMS_a087_SW_Feim_Test_Blocked = false; +static bool battery_BMS_a088_SW_VcFront_MIA_InDrive = false; +static bool battery_BMS_a089_SW_VcFront_MIA = false; +static bool battery_BMS_a090_SW_Gateway_MIA = false; +static bool battery_BMS_a091_SW_ChargePort_MIA = false; +static bool battery_BMS_a092_SW_ChargePort_Mia_On_Hv = false; +static bool battery_BMS_a034_SW_Passive_Isolation = false; +static bool battery_BMS_a035_SW_Isolation = false; +static bool battery_BMS_a036_SW_HvpHvilFault = false; +static bool battery_BMS_a037_SW_Flood_Port_Open = false; +static bool battery_BMS_a158_SW_HVP_HVI_Comms = false; +static bool battery_BMS_a039_SW_DC_Link_Over_Voltage = false; +static bool battery_BMS_a041_SW_Power_On_Reset = false; +static bool battery_BMS_a042_SW_MPU_Error = false; +static bool battery_BMS_a043_SW_Watch_Dog_Reset = false; +static bool battery_BMS_a044_SW_Assertion = false; +static bool battery_BMS_a045_SW_Exception = false; +static bool battery_BMS_a046_SW_Task_Stack_Usage = false; +static bool battery_BMS_a047_SW_Task_Stack_Overflow = false; +static bool battery_BMS_a048_SW_Log_Upload_Request = false; +static bool battery_BMS_a169_SW_FC_Pack_Weld = false; +static bool battery_BMS_a050_SW_Brick_Voltage_MIA = false; +static bool battery_BMS_a051_SW_HVC_Vref_Bad = false; +static bool battery_BMS_a052_SW_PCS_MIA = false; +static bool battery_BMS_a053_SW_ThermalModel_Sanity = false; +static bool battery_BMS_a054_SW_Ver_Supply_Fault = false; +static bool battery_BMS_a176_SW_GracefulPowerOff = false; +static bool battery_BMS_a059_SW_Pack_Voltage_Sensing = false; +static bool battery_BMS_a060_SW_Leakage_Test_Failure = false; +static bool battery_BMS_a077_SW_Charger_Regulation = false; +static bool battery_BMS_a081_SW_Ctr_Close_Blocked = false; +static bool battery_BMS_a082_SW_Ctr_Force_Open = false; +static bool battery_BMS_a083_SW_Ctr_Close_Failure = false; +static bool battery_BMS_a084_SW_Sleep_Wake_Aborted = false; +static bool battery_BMS_a094_SW_Drive_Inverter_MIA = false; +static bool battery_BMS_a099_SW_BMB_Communication = false; +static bool battery_BMS_a105_SW_One_Module_Tsense = false; +static bool battery_BMS_a106_SW_All_Module_Tsense = false; +static bool battery_BMS_a107_SW_Stack_Voltage_MIA = false; +static bool battery_BMS_a121_SW_NVRAM_Config_Error = false; +static bool battery_BMS_a122_SW_BMS_Therm_Irrational = false; +static bool battery_BMS_a123_SW_Internal_Isolation = false; +static bool battery_BMS_a129_SW_VSH_Failure = false; +static bool battery_BMS_a131_Bleed_FET_Failure = false; +static bool battery_BMS_a136_SW_Module_OT_Warning = false; +static bool battery_BMS_a137_SW_Brick_UV_Warning = false; +static bool battery_BMS_a138_SW_Brick_OV_Warning = false; +static bool battery_BMS_a139_SW_DC_Link_V_Irrational = false; +static bool battery_BMS_a141_SW_BMB_Status_Warning = false; +static bool battery_BMS_a144_Hvp_Config_Mismatch = false; +static bool battery_BMS_a145_SW_SOC_Change = false; +static bool battery_BMS_a146_SW_Brick_Overdischarged = false; +static bool battery_BMS_a149_SW_Missing_Config_Block = false; +static bool battery_BMS_a151_SW_external_isolation = false; +static bool battery_BMS_a156_SW_BMB_Vref_bad = false; +static bool battery_BMS_a157_SW_HVP_HVS_Comms = false; +static bool battery_BMS_a159_SW_HVP_ECU_Error = false; +static bool battery_BMS_a161_SW_DI_Open_Request = false; +static bool battery_BMS_a162_SW_No_Power_For_Support = false; +static bool battery_BMS_a163_SW_Contactor_Mismatch = false; +static bool battery_BMS_a164_SW_Uncontrolled_Regen = false; +static bool battery_BMS_a165_SW_Pack_Partial_Weld = false; +static bool battery_BMS_a166_SW_Pack_Full_Weld = false; +static bool battery_BMS_a167_SW_FC_Partial_Weld = false; +static bool battery_BMS_a168_SW_FC_Full_Weld = false; +static bool battery_BMS_a170_SW_Limp_Mode = false; +static bool battery_BMS_a171_SW_Stack_Voltage_Sense = false; +static bool battery_BMS_a174_SW_Charge_Failure = false; +static bool battery_BMS_a179_SW_Hvp_12V_Fault = false; +static bool battery_BMS_a180_SW_ECU_reset_blocked = false; -#ifdef DOUBLE_BATTERY +#ifdef DOUBLE_BATTERY //need to update for battery2 + +static uint16_t battery2_cell_max_v = 3300; +static uint16_t battery2_cell_min_v = 3300; +static uint16_t battery2_cell_deviation_mV = 0; //contains the deviation between highest and lowest cell in mV +static bool battery2_cellvoltagesRead = false; +//0x3d2: 978 BMS_kwhCounter static uint32_t battery2_total_discharge = 0; static uint32_t battery2_total_charge = 0; -static uint16_t battery2_volts = 0; // V -static int16_t battery2_amps = 0; // A -static uint16_t battery2_raw_amps = 0; // A -static int16_t battery2_max_temp = 0; // C* -static int16_t battery2_min_temp = 0; // C* +//0x352: 850 BMS_energyStatus static uint16_t battery2_energy_buffer = 0; static uint16_t battery2_energy_buffer_m1 = 0; // kWh static uint16_t battery2_energy_to_charge_complete = 0; static uint16_t battery2_energy_to_charge_complete_m1 = 0; // kWh static uint16_t battery2_expected_energy_remaining = 0; static uint16_t battery2_expected_energy_remaining_m1 = 0; // kWh -static uint8_t battery2_full_charge_complete = 0; -static uint8_t battery2_fully_charged = 0; +static bool battery2_full_charge_complete = false; +static bool battery2_fully_charged = false; static uint16_t battery2_ideal_energy_remaining = 0; static uint16_t battery2_ideal_energy_remaining_m0 = 0; // kWh static uint16_t battery2_nominal_energy_remaining = 0; static uint16_t battery2_nominal_energy_remaining_m0 = 0; // kWh -static uint16_t battery2_nominal_full_pack_energy = 600; -static uint16_t battery2_nominal_full_pack_energy_m0 = 600; // Kwh -static uint16_t battery2_beginning_of_life = 600; +static uint16_t battery2_nominal_full_pack_energy = 0; +static uint16_t battery2_nominal_full_pack_energy_m0 = 0; // Kwh +//0x132 306 HVBattAmpVolt +static uint16_t battery2_volts = 0; // V +static int16_t battery2_amps = 0; // A +static int16_t battery2_raw_amps = 0; // A static uint16_t battery2_charge_time_remaining = 0; // Minutes -static uint16_t battery2_regenerative_limit = 0; -static uint16_t battery2_discharge_limit = 0; -static uint16_t battery2_max_heat_park = 0; -static uint16_t battery2_hvac_max_power = 0; +//0x252 594 BMS_powerAvailable +static uint16_t BMS2_maxRegenPower = 0; //rename from battery_regenerative_limit +static uint16_t BMS2_maxDischargePower = 0; // rename from battery_discharge_limit +static uint16_t BMS2_maxStationaryHeatPower = 0; //rename from battery_max_heat_park +static uint16_t BMS2_hvacPowerBudget = 0; //rename from battery_hvac_max_power +static uint8_t BMS2_notEnoughPowerForHeatPump = 0; +static uint8_t BMS2_powerLimitState = 0; +static uint8_t BMS2_inverterTQF = 0; +//0x2d2: 722 BMSVAlimits static uint16_t battery2_max_discharge_current = 0; static uint16_t battery2_max_charge_current = 0; static uint16_t battery2_bms_max_voltage = 0; static uint16_t battery2_bms_min_voltage = 0; +//0x2b4: 692 PCS_dcdcRailStatus static uint16_t battery2_dcdcHvBusVolt = 0; //update name static uint16_t battery2_dcdcLvBusVolt = 0; //update name static uint16_t battery2_dcdcLvOutputCurrent = 0; //update name +//0x292: 658 BMS_socStatus +static uint16_t battery2_beginning_of_life = 0; static uint16_t battery2_soc_min = 0; static uint16_t battery2_soc_max = 0; static uint16_t battery2_soc_ui = 0; static uint16_t battery2_soc_ave = 0; -static uint16_t battery2_cell_max_v = 3700; -static uint16_t battery2_cell_min_v = 3700; -static uint16_t battery2_cell_deviation_mV = 0; //contains the deviation between highest and lowest cell in mV -static uint8_t battery2_max_vno = 0; -static uint8_t battery2_min_vno = 0; -static uint8_t battery2_contactor = 0; //State of contactor -static uint8_t battery2_hvil_status = 0; -static uint8_t battery2_packContNegativeState = 0; -static uint8_t battery2_packContPositiveState = 0; -static uint8_t battery2_packContactorSetState = 0; -static uint8_t battery2_packCtrsClosingAllowed = 0; -static uint8_t battery2_pyroTestInProgress = 0; static uint8_t battery2_battTempPct = 0; +//0x392: BMS_packConfig static uint32_t battery2_packMass = 0; static uint32_t battery2_platformMaxBusVoltage = 0; static uint32_t battery2_packConfigMultiplexer = 0; static uint32_t battery2_moduleType = 0; static uint32_t battery2_reservedConfig = 0; -//Fault codes -static uint8_t battery2_WatchdogReset = 0; //Warns if the processor has experienced a reset due to watchdog reset. -static uint8_t battery2_PowerLossReset = 0; //Warns if the processor has experienced a reset due to power loss. -static uint8_t battery2_SwAssertion = 0; //An internal software assertion has failed. -static uint8_t battery2_CrashEvent = 0; //Warns if the crash signal is detected by HVP -static uint8_t battery2_OverDchgCurrentFault = 0; //Warns if the pack discharge is above max discharge current limit -static uint8_t battery2_OverChargeCurrentFault = - 0; //Warns if the pack discharge current is above max charge current limit -static uint8_t battery2_OverCurrentFault = - 0; //Warns if the pack current (discharge or charge) is above max current limit. -static uint8_t battery2_OverTemperatureFault = 0; //A pack module temperature is above maximum temperature limit -static uint8_t battery2_OverVoltageFault = 0; //A brick voltage is above maximum voltage limit -static uint8_t battery2_UnderVoltageFault = 0; //A brick voltage is below minimum voltage limit -static uint8_t battery2_PrimaryBmbMiaFault = - 0; //Warns if the voltage and temperature readings from primary BMB chain are mia -static uint8_t battery2_SecondaryBmbMiaFault = - 0; //Warns if the voltage and temperature readings from secondary BMB chain are mia -static uint8_t battery2_BmbMismatchFault = - 0; //Warns if the primary and secondary BMB chain readings don't match with each other -static uint8_t battery2_BmsHviMiaFault = 0; //Warns if the BMS node is mia on HVS or HVI CAN -static uint8_t battery2_CpMiaFault = 0; //Warns if the CP node is mia on HVS CAN -static uint8_t battery2_PcsMiaFault = 0; //The PCS node is mia on HVS CAN -static uint8_t battery2_BmsFault = 0; //Warns if the BMS ECU has faulted -static uint8_t battery2_PcsFault = 0; //Warns if the PCS ECU has faulted -static uint8_t battery2_CpFault = 0; //Warns if the CP ECU has faulted -static uint8_t battery2_ShuntHwMiaFault = 0; //Warns if the shunt current reading is not available -static uint8_t battery2_PyroMiaFault = 0; //Warns if the pyro squib is not connected -static uint8_t battery2_hvsMiaFault = 0; //Warns if the pack contactor hw fault -static uint8_t battery2_hviMiaFault = 0; //Warns if the FC contactor hw fault -static uint8_t battery2_Supply12vFault = 0; //Warns if the low voltage (12V) battery is below minimum voltage threshold -static uint8_t battery2_VerSupplyFault = - 0; //Warns if the Energy reserve voltage supply is below minimum voltage threshold -static uint8_t battery2_HvilFault = 0; //Warn if a High Voltage Inter Lock fault is detected -static uint8_t battery2_BmsHvsMiaFault = 0; //Warns if the BMS node is mia on HVS or HVI CAN -static uint8_t battery2_PackVoltMismatchFault = - 0; //Warns if the pack voltage doesn't match approximately with sum of brick voltages -static uint8_t battery2_EnsMiaFault = 0; //Warns if the ENS line is not connected to HVC -static uint8_t battery2_PackPosCtrArcFault = 0; //Warns if the HVP detectes series arc at pack contactor -static uint8_t battery2_packNegCtrArcFault = 0; //Warns if the HVP detectes series arc at FC contactor -static uint8_t battery2_ShuntHwAndBmsMiaFault = 0; -static uint8_t battery2_fcContHwFault = 0; -static uint8_t battery2_robinOverVoltageFault = 0; -static uint8_t battery2_packContHwFault = 0; -static uint8_t battery2_pyroFuseBlown = 0; -static uint8_t battery2_pyroFuseFailedToBlow = 0; -static uint8_t battery2_CpilFault = 0; -static uint8_t battery2_PackContactorFellOpen = 0; -static uint8_t battery2_FcContactorFellOpen = 0; -static uint8_t battery2_packCtrCloseBlocked = 0; -static uint8_t battery2_fcCtrCloseBlocked = 0; -static uint8_t battery2_packContactorForceOpen = 0; -static uint8_t battery2_fcContactorForceOpen = 0; -static uint8_t battery2_dcLinkOverVoltage = 0; -static uint8_t battery2_shuntOverTemperature = 0; -static uint8_t battery2_passivePyroDeploy = 0; -static uint8_t battery2_logUploadRequest = 0; -static uint8_t battery2_packCtrCloseFailed = 0; -static uint8_t battery2_fcCtrCloseFailed = 0; -static uint8_t battery2_shuntThermistorMia = 0; +//0x332: 818 BattBrickMinMax:BMS_bmbMinMax +static int16_t battery2_max_temp = 0; // C* +static int16_t battery2_min_temp = 0; // C* +static uint16_t battery2_BrickVoltageMax = 0; +static uint16_t battery2_BrickVoltageMin = 0; +static uint8_t battery2_BrickTempMaxNum = 0; +static uint8_t battery2_BrickTempMinNum = 0; +static uint8_t battery2_BrickModelTMax = 0; +static uint8_t battery2_BrickModelTMin = 0; +static uint8_t battery2_BrickVoltageMaxNum = 0; //rename from battery_max_vno +static uint8_t battery2_BrickVoltageMinNum = 0; //rename from battery_min_vno +//0x20A: 522 HVP_contactorState +static uint8_t battery2_contactor = 0; //State of contactor +static uint8_t battery2_hvil_status = 0; +static uint8_t battery2_packContNegativeState = 0; +static uint8_t battery2_packContPositiveState = 0; +static uint8_t battery2_packContactorSetState = 0; +static bool battery2_packCtrsClosingAllowed = false; +static bool battery2_pyroTestInProgress = false; +static bool battery2_packCtrsOpenNowRequested = false; +static bool battery2_packCtrsOpenRequested = false; +static uint8_t battery2_packCtrsRequestStatus = 0; +static bool battery2_packCtrsResetRequestRequired = false; +static bool battery2_dcLinkAllowedToEnergize = false; +static bool battery2_fcContNegativeAuxOpen = false; +static uint8_t battery2_fcContNegativeState = 0; +static bool battery2_fcContPositiveAuxOpen = false; +static uint8_t battery2_fcContPositiveState = 0; +static uint8_t battery2_fcContactorSetState = 0; +static bool battery2_fcCtrsClosingAllowed = false; +static bool battery2_fcCtrsOpenNowRequested = false; +static bool battery2_fcCtrsOpenRequested = false; +static uint8_t battery2_fcCtrsRequestStatus = 0; +static bool battery2_fcCtrsResetRequestRequired = false; +static bool battery2_fcLinkAllowedToEnergize = false; +//0x212: 530 BMS_status +static bool battery2_BMS_hvacPowerRequest = false; +static bool battery2_BMS_notEnoughPowerForDrive = false; +static bool battery2_BMS_notEnoughPowerForSupport = false; +static bool battery2_BMS_preconditionAllowed = false; +static bool battery2_BMS_updateAllowed = false; +static bool battery2_BMS_activeHeatingWorthwhile = false; +static bool battery2_BMS_cpMiaOnHvs = false; +static uint8_t battery2_BMS_contactorState = 0; +static uint8_t battery2_BMS_state = 0; +static uint8_t battery2_BMS_hvState = 0; +static uint16_t battery2_BMS_isolationResistance = 0; +static bool battery2_BMS_chargeRequest = false; +static bool battery2_BMS_keepWarmRequest = false; +static uint8_t battery2_BMS_uiChargeStatus = 0; +static bool battery2_BMS_diLimpRequest = false; +static bool battery2_BMS_okToShipByAir = false; +static bool battery2_BMS_okToShipByLand = false; +static uint32_t battery2_BMS_chgPowerAvailable = 0; +static uint8_t battery2_BMS_chargeRetryCount = 0; +static bool battery2_BMS_pcsPwmEnabled = false; +static bool battery2_BMS_ecuLogUploadRequest = false; +static uint8_t battery2_BMS_minPackTemperature = 0; +// 0x224:548 PCS_dcdcStatus +static uint8_t battery2_PCS_dcdcPrechargeStatus = 0; +static uint8_t battery2_PCS_dcdc12VSupportStatus = 0; +static uint8_t battery2_PCS_dcdcHvBusDischargeStatus = 0; +static uint16_t battery2_PCS_dcdcMainState = 0; +static uint8_t battery2_PCS_dcdcSubState = 0; +static bool battery2_PCS_dcdcFaulted = false; +static bool battery2_PCS_dcdcOutputIsLimited = false; +static uint32_t battery2_PCS_dcdcMaxOutputCurrentAllowed = 0; +static uint8_t battery2_PCS_dcdcPrechargeRtyCnt = 0; +static uint8_t battery2_PCS_dcdc12VSupportRtyCnt = 0; +static uint8_t battery2_PCS_dcdcDischargeRtyCnt = 0; +static uint8_t battery2_PCS_dcdcPwmEnableLine = 0; +static uint8_t battery2_PCS_dcdcSupportingFixedLvTarget = 0; +static uint8_t battery2_PCS_ecuLogUploadRequest = 0; +static uint8_t battery2_PCS_dcdcPrechargeRestartCnt = 0; +static uint8_t battery2_PCS_dcdcInitialPrechargeSubState = 0; +//0x312: 786 BMS_thermalStatus +static uint16_t BMS2_powerDissipation = 0; +static uint16_t BMS2_flowRequest = 0; +static uint16_t BMS2_inletActiveCoolTargetT = 0; +static uint16_t BMS2_inletPassiveTargetT = 0; +static uint16_t BMS2_inletActiveHeatTargetT = 0; +static uint16_t BMS2_packTMin = 0; +static uint16_t BMS2_packTMax = 0; +static bool BMS2_pcsNoFlowRequest = false; +static bool BMS2_noFlowRequest = false; +//0x2A4; 676 PCS_thermalStatus +static int16_t PCS2_chgPhATemp = 0; +static int16_t PCS2_chgPhBTemp = 0; +static int16_t PCS2_chgPhCTemp = 0; +static int16_t PCS2_dcdcTemp = 0; +static int16_t PCS2_ambientTemp = 0; +//0x2C4; 708 PCS_logging +static uint16_t PCS2_logMessageSelect = 0; +static uint16_t PCS2_dcdcMaxLvOutputCurrent = 0; +static uint16_t PCS2_dcdcCurrentLimit = 0; +static uint16_t PCS2_dcdcLvOutputCurrentTempLimit = 0; +static uint16_t PCS2_dcdcUnifiedCommand = 0; +static uint16_t PCS2_dcdcCLAControllerOutput = 0; +static int16_t PCS2_dcdcTankVoltage = 0; +static uint16_t PCS2_dcdcTankVoltageTarget = 0; +static uint16_t PCS2_dcdcClaCurrentFreq = 0; +static int16_t PCS2_dcdcTCommMeasured = 0; +static uint16_t PCS2_dcdcShortTimeUs = 0; +static uint16_t PCS2_dcdcHalfPeriodUs = 0; +static uint16_t PCS2_dcdcIntervalMaxFrequency = 0; +static uint16_t PCS2_dcdcIntervalMaxHvBusVolt = 0; +static uint16_t PCS2_dcdcIntervalMaxLvBusVolt = 0; +static uint16_t PCS2_dcdcIntervalMaxLvOutputCurr = 0; +static uint16_t PCS2_dcdcIntervalMinFrequency = 0; +static uint16_t PCS2_dcdcIntervalMinHvBusVolt = 0; +static uint16_t PCS2_dcdcIntervalMinLvBusVolt = 0; +static uint16_t PCS2_dcdcIntervalMinLvOutputCurr = 0; +static uint32_t PCS2_dcdc12vSupportLifetimekWh = 0; +//0x7AA: //1962 HVP_debugMessage: +static uint8_t HVP2_debugMessageMultiplexer = 0; +static bool HVP2_gpioPassivePyroDepl = false; +static bool HVP2_gpioPyroIsoEn = false; +static bool HVP2_gpioCpFaultIn = false; +static bool HVP2_gpioPackContPowerEn = false; +static bool HVP2_gpioHvCablesOk = false; +static bool HVP2_gpioHVPSelfEnable = false; +static bool HVP2_gpioLed = false; +static bool HVP2_gpioCrashSignal = false; +static bool HVP2_gpioShuntDataReady = false; +static bool HVP2_gpioFcContPosAux = false; +static bool HVP2_gpioFcContNegAux = false; +static bool HVP2_gpioBmsEout = false; +static bool HVP2_gpioCpFaultOut = false; +static bool HVP2_gpioPyroPor = false; +static bool HVP2_gpioShuntEn = false; +static bool HVP2_gpioHVPVerEn = false; +static bool HVP2_gpioPackCoontPosFlywheel = false; +static bool HVP2_gpioCpLatchEnable = false; +static bool HVP2_gpioPcsEnable = false; +static bool HVP2_gpioPcsDcdcPwmEnable = false; +static bool HVP2_gpioPcsChargePwmEnable = false; +static bool HVP2_gpioFcContPowerEnable = false; +static bool HVP2_gpioHvilEnable = false; +static bool HVP2_gpioSecDrdy = false; +static uint16_t HVP2_hvp1v5Ref = 0; +static int16_t HVP2_shuntCurrentDebug = 0; +static bool HVP2_packCurrentMia = false; +static bool HVP2_auxCurrentMia = false; +static bool HVP2_currentSenseMia = false; +static bool HVP2_shuntRefVoltageMismatch = false; +static bool HVP2_shuntThermistorMia = false; +static bool HVP2_shuntHwMia = false; +static int16_t HVP2_dcLinkVoltage = 0; +static int16_t HVP2_packVoltage = 0; +static int16_t HVP2_fcLinkVoltage = 0; +static uint16_t HVP2_packContVoltage = 0; +static int16_t HVP2_packNegativeV = 0; +static int16_t HVP2_packPositiveV = 0; +static uint16_t HVP2_pyroAnalog = 0; +static int16_t HVP2_dcLinkNegativeV = 0; +static int16_t HVP2_dcLinkPositiveV = 0; +static int16_t HVP2_fcLinkNegativeV = 0; +static uint16_t HVP2_fcContCoilCurrent = 0; +static uint16_t HVP2_fcContVoltage = 0; +static uint16_t HVP2_hvilInVoltage = 0; +static uint16_t HVP2_hvilOutVoltage = 0; +static int16_t HVP2_fcLinkPositiveV = 0; +static uint16_t HVP2_packContCoilCurrent = 0; +static uint16_t HVP2_battery12V = 0; +static int16_t HVP2_shuntRefVoltageDbg = 0; +static int16_t HVP2_shuntAuxCurrentDbg = 0; +static int16_t HVP2_shuntBarTempDbg = 0; +static int16_t HVP2_shuntAsicTempDbg = 0; +static uint8_t HVP2_shuntAuxCurrentStatus = 0; +static uint8_t HVP2_shuntBarTempStatus = 0; +static uint8_t HVP2_shuntAsicTempStatus = 0; +//0x3aa: HVP_alertMatrix1 Fault codes +static bool battery2_WatchdogReset = false; //Warns if the processor has experienced a reset due to watchdog reset. +static bool battery2_PowerLossReset = false; //Warns if the processor has experienced a reset due to power loss. +static bool battery2_SwAssertion = false; //An internal software assertion has failed. +static bool battery2_CrashEvent = false; //Warns if the crash signal is detected by HVP +static bool battery2_OverDchgCurrentFault = false; //Warns if the pack discharge is above max discharge current limit +static bool battery2_OverChargeCurrentFault = + false; //Warns if the pack discharge current is above max charge current limit +static bool battery2_OverCurrentFault = + false; //Warns if the pack current (discharge or charge) is above max current limit. +static bool battery2_OverTemperatureFault = false; //A pack module temperature is above maximum temperature limit +static bool battery2_OverVoltageFault = false; //A brick voltage is above maximum voltage limit +static bool battery2_UnderVoltageFault = false; //A brick voltage is below minimum voltage limit +static bool battery2_PrimaryBmbMiaFault = + false; //Warns if the voltage and temperature readings from primary BMB chain are mia +static bool battery2_SecondaryBmbMiaFault = + false; //Warns if the voltage and temperature readings from secondary BMB chain are mia +static bool battery2_BmbMismatchFault = + false; //Warns if the primary and secondary BMB chain readings don't match with each other +static bool battery2_BmsHviMiaFault = false; //Warns if the BMS node is mia on HVS or HVI CAN +static bool battery2_CpMiaFault = false; //Warns if the CP node is mia on HVS CAN +static bool battery2_PcsMiaFault = false; //The PCS node is mia on HVS CAN +static bool battery2_BmsFault = false; //Warns if the BMS ECU has faulted +static bool battery2_PcsFault = false; //Warns if the PCS ECU has faulted +static bool battery2_CpFault = false; //Warns if the CP ECU has faulted +static bool battery2_ShuntHwMiaFault = false; //Warns if the shunt current reading is not available +static bool battery2_PyroMiaFault = false; //Warns if the pyro squib is not connected +static bool battery2_hvsMiaFault = false; //Warns if the pack contactor hw fault +static bool battery2_hviMiaFault = false; //Warns if the FC contactor hw fault +static bool battery2_Supply12vFault = + false; //Warns if the low voltage (12V) battery is below minimum voltage threshold +static bool battery2_VerSupplyFault = + false; //Warns if the Energy reserve voltage supply is below minimum voltage threshold +static bool battery2_HvilFault = false; //Warn if a High Voltage Inter Lock fault is detected +static bool battery2_BmsHvsMiaFault = false; //Warns if the BMS node is mia on HVS or HVI CAN +static bool battery2_PackVoltMismatchFault = + false; //Warns if the pack voltage doesn't match approximately with sum of brick voltages +static bool battery2_EnsMiaFault = false; //Warns if the ENS line is not connected to HVC +static bool battery2_PackPosCtrArcFault = false; //Warns if the HVP detectes series arc at pack contactor +static bool battery2_packNegCtrArcFault = false; //Warns if the HVP detectes series arc at FC contactor +static bool battery2_ShuntHwAndBmsMiaFault = false; +static bool battery2_fcContHwFault = false; +static bool battery2_robinOverVoltageFault = false; +static bool battery2_packContHwFault = false; +static bool battery2_pyroFuseBlown = false; +static bool battery2_pyroFuseFailedToBlow = false; +static bool battery2_CpilFault = false; +static bool battery2_PackContactorFellOpen = false; +static bool battery2_FcContactorFellOpen = false; +static bool battery2_packCtrCloseBlocked = false; +static bool battery2_fcCtrCloseBlocked = false; +static bool battery2_packContactorForceOpen = false; +static bool battery2_fcContactorForceOpen = false; +static bool battery2_dcLinkOverVoltage = false; +static bool battery2_shuntOverTemperature = false; +static bool battery2_passivePyroDeploy = false; +static bool battery2_logUploadRequest = false; +static bool battery2_packCtrCloseFailed = false; +static bool battery2_fcCtrCloseFailed = false; +static bool battery2_shuntThermistorMia = false; +//0x320: 800 BMS_alertMatrix +static uint8_t battery2_BMS_matrixIndex = 4; +static bool battery2_BMS_a061_robinBrickOverVoltage = false; +static bool battery2_BMS_a062_SW_BrickV_Imbalance = false; +static bool battery2_BMS_a063_SW_ChargePort_Fault = false; +static bool battery2_BMS_a064_SW_SOC_Imbalance = false; +static bool battery2_BMS_a127_SW_shunt_SNA = false; +static bool battery2_BMS_a128_SW_shunt_MIA = false; +static bool battery2_BMS_a069_SW_Low_Power = false; +static bool battery2_BMS_a130_IO_CAN_Error = false; +static bool battery2_BMS_a071_SW_SM_TransCon_Not_Met = false; +static bool battery2_BMS_a132_HW_BMB_OTP_Uncorrctbl = false; +static bool battery2_BMS_a134_SW_Delayed_Ctr_Off = false; +static bool battery2_BMS_a075_SW_Chg_Disable_Failure = false; +static bool battery2_BMS_a076_SW_Dch_While_Charging = false; +static bool battery2_BMS_a017_SW_Brick_OV = false; +static bool battery2_BMS_a018_SW_Brick_UV = false; +static bool battery2_BMS_a019_SW_Module_OT = false; +static bool battery2_BMS_a021_SW_Dr_Limits_Regulation = false; +static bool battery2_BMS_a022_SW_Over_Current = false; +static bool battery2_BMS_a023_SW_Stack_OV = false; +static bool battery2_BMS_a024_SW_Islanded_Brick = false; +static bool battery2_BMS_a025_SW_PwrBalance_Anomaly = false; +static bool battery2_BMS_a026_SW_HFCurrent_Anomaly = false; +static bool battery2_BMS_a087_SW_Feim_Test_Blocked = false; +static bool battery2_BMS_a088_SW_VcFront_MIA_InDrive = false; +static bool battery2_BMS_a089_SW_VcFront_MIA = false; +static bool battery2_BMS_a090_SW_Gateway_MIA = false; +static bool battery2_BMS_a091_SW_ChargePort_MIA = false; +static bool battery2_BMS_a092_SW_ChargePort_Mia_On_Hv = false; +static bool battery2_BMS_a034_SW_Passive_Isolation = false; +static bool battery2_BMS_a035_SW_Isolation = false; +static bool battery2_BMS_a036_SW_HvpHvilFault = false; +static bool battery2_BMS_a037_SW_Flood_Port_Open = false; +static bool battery2_BMS_a158_SW_HVP_HVI_Comms = false; +static bool battery2_BMS_a039_SW_DC_Link_Over_Voltage = 1; +static bool battery2_BMS_a041_SW_Power_On_Reset = false; +static bool battery2_BMS_a042_SW_MPU_Error = false; +static bool battery2_BMS_a043_SW_Watch_Dog_Reset = false; +static bool battery2_BMS_a044_SW_Assertion = false; +static bool battery2_BMS_a045_SW_Exception = false; +static bool battery2_BMS_a046_SW_Task_Stack_Usage = false; +static bool battery2_BMS_a047_SW_Task_Stack_Overflow = false; +static bool battery2_BMS_a048_SW_Log_Upload_Request = false; +static bool battery2_BMS_a169_SW_FC_Pack_Weld = false; +static bool battery2_BMS_a050_SW_Brick_Voltage_MIA = false; +static bool battery2_BMS_a051_SW_HVC_Vref_Bad = false; +static bool battery2_BMS_a052_SW_PCS_MIA = false; +static bool battery2_BMS_a053_SW_ThermalModel_Sanity = false; +static bool battery2_BMS_a054_SW_Ver_Supply_Fault = false; +static bool battery2_BMS_a176_SW_GracefulPowerOff = false; +static bool battery2_BMS_a059_SW_Pack_Voltage_Sensing = false; +static bool battery2_BMS_a060_SW_Leakage_Test_Failure = false; +static bool battery2_BMS_a077_SW_Charger_Regulation = false; +static bool battery2_BMS_a081_SW_Ctr_Close_Blocked = false; +static bool battery2_BMS_a082_SW_Ctr_Force_Open = false; +static bool battery2_BMS_a083_SW_Ctr_Close_Failure = false; +static bool battery2_BMS_a084_SW_Sleep_Wake_Aborted = false; +static bool battery2_BMS_a094_SW_Drive_Inverter_MIA = false; +static bool battery2_BMS_a099_SW_BMB_Communication = false; +static bool battery2_BMS_a105_SW_One_Module_Tsense = false; +static bool battery2_BMS_a106_SW_All_Module_Tsense = false; +static bool battery2_BMS_a107_SW_Stack_Voltage_MIA = false; +static bool battery2_BMS_a121_SW_NVRAM_Config_Error = false; +static bool battery2_BMS_a122_SW_BMS_Therm_Irrational = false; +static bool battery2_BMS_a123_SW_Internal_Isolation = false; +static bool battery2_BMS_a129_SW_VSH_Failure = false; +static bool battery2_BMS_a131_Bleed_FET_Failure = false; +static bool battery2_BMS_a136_SW_Module_OT_Warning = false; +static bool battery2_BMS_a137_SW_Brick_UV_Warning = false; +static bool battery2_BMS_a138_SW_Brick_OV_Warning = false; +static bool battery2_BMS_a139_SW_DC_Link_V_Irrational = false; +static bool battery2_BMS_a141_SW_BMB_Status_Warning = false; +static bool battery2_BMS_a144_Hvp_Config_Mismatch = false; +static bool battery2_BMS_a145_SW_SOC_Change = false; +static bool battery2_BMS_a146_SW_Brick_Overdischarged = false; +static bool battery2_BMS_a149_SW_Missing_Config_Block = false; +static bool battery2_BMS_a151_SW_external_isolation = false; +static bool battery2_BMS_a156_SW_BMB_Vref_bad = false; +static bool battery2_BMS_a157_SW_HVP_HVS_Comms = false; +static bool battery2_BMS_a159_SW_HVP_ECU_Error = false; +static bool battery2_BMS_a16false_SW_DI_Open_Request = false; +static bool battery2_BMS_a162_SW_No_Power_For_Support = false; +static bool battery2_BMS_a163_SW_Contactor_Mismatch = false; +static bool battery2_BMS_a164_SW_Uncontrolled_Regen = false; +static bool battery2_BMS_a165_SW_Pack_Partial_Weld = false; +static bool battery2_BMS_a166_SW_Pack_Full_Weld = false; +static bool battery2_BMS_a167_SW_FC_Partial_Weld = false; +static bool battery2_BMS_a168_SW_FC_Full_Weld = false; +static bool battery2_BMS_a170_SW_Limp_Mode = false; +static bool battery2_BMS_a171_SW_Stack_Voltage_Sense = false; +static bool battery2_BMS_a174_SW_Charge_Failure = false; +static bool battery2_BMS_a179_SW_Hvp_12V_Fault = false; +static bool battery2_BMS_a180_SW_ECU_reset_blocked = false; + #endif //DOUBLE_BATTERY static const char* contactorText[] = {"UNKNOWN(0)", "OPEN", "CLOSING", "BLOCKED", "OPENING", @@ -368,6 +904,7 @@ void update_values_battery() { //This function maps all the values fetched via #endif // TESLA_MODEL_3Y_BATTERY // Update webserver datalayer + //0x20A datalayer_extended.tesla.status_contactor = battery_contactor; datalayer_extended.tesla.hvil_status = battery_hvil_status; datalayer_extended.tesla.packContNegativeState = battery_packContNegativeState; @@ -375,11 +912,16 @@ void update_values_battery() { //This function maps all the values fetched via datalayer_extended.tesla.packContactorSetState = battery_packContactorSetState; datalayer_extended.tesla.packCtrsClosingAllowed = battery_packCtrsClosingAllowed; datalayer_extended.tesla.pyroTestInProgress = battery_pyroTestInProgress; - datalayer_extended.tesla.battery_beginning_of_life = battery_beginning_of_life; //add from her down - datalayer_extended.tesla.battery_battTempPct = battery_battTempPct; + datalayer_extended.tesla.battery_packCtrsOpenNowRequested = battery_packCtrsOpenNowRequested; + datalayer_extended.tesla.battery_packCtrsOpenRequested = battery_packCtrsOpenRequested; + datalayer_extended.tesla.battery_packCtrsRequestStatus = battery_packCtrsRequestStatus; + datalayer_extended.tesla.battery_packCtrsResetRequestRequired = battery_packCtrsResetRequestRequired; + datalayer_extended.tesla.battery_dcLinkAllowedToEnergize = battery_dcLinkAllowedToEnergize; + //0x2B4 datalayer_extended.tesla.battery_dcdcLvBusVolt = battery_dcdcLvBusVolt; datalayer_extended.tesla.battery_dcdcHvBusVolt = battery_dcdcHvBusVolt; datalayer_extended.tesla.battery_dcdcLvOutputCurrent = battery_dcdcLvOutputCurrent; + //0x352 datalayer_extended.tesla.battery_nominal_full_pack_energy = battery_nominal_full_pack_energy; datalayer_extended.tesla.battery_nominal_full_pack_energy_m0 = battery_nominal_full_pack_energy_m0; datalayer_extended.tesla.battery_nominal_energy_remaining = battery_nominal_energy_remaining; @@ -390,107 +932,249 @@ void update_values_battery() { //This function maps all the values fetched via datalayer_extended.tesla.battery_energy_to_charge_complete_m1 = battery_energy_to_charge_complete_m1; datalayer_extended.tesla.battery_energy_buffer = battery_energy_buffer; datalayer_extended.tesla.battery_energy_buffer_m1 = battery_energy_buffer_m1; + datalayer_extended.tesla.battery_expected_energy_remaining_m1 = battery_expected_energy_remaining_m1; datalayer_extended.tesla.battery_full_charge_complete = battery_full_charge_complete; + datalayer_extended.tesla.battery_fully_charged = battery_fully_charged; + //0x3D2 datalayer_extended.tesla.battery_total_discharge = battery_total_discharge; datalayer_extended.tesla.battery_total_charge = battery_total_charge; - datalayer_extended.tesla.battery_fully_charged = battery_fully_charged; - datalayer_extended.tesla.battery_packConfigMultiplexer = battery_packConfigMultiplexer; + //0x392 datalayer_extended.tesla.battery_moduleType = battery_moduleType; - datalayer_extended.tesla.battery_reservedConfig = battery_reservedConfig; datalayer_extended.tesla.battery_packMass = battery_packMass; datalayer_extended.tesla.battery_platformMaxBusVoltage = battery_platformMaxBusVoltage; + //0x2D2 datalayer_extended.tesla.battery_bms_min_voltage = battery_bms_min_voltage; datalayer_extended.tesla.battery_bms_max_voltage = battery_bms_max_voltage; datalayer_extended.tesla.battery_max_charge_current = battery_max_charge_current; datalayer_extended.tesla.battery_max_discharge_current = battery_max_discharge_current; + //0x292 + datalayer_extended.tesla.battery_beginning_of_life = battery_beginning_of_life; + datalayer_extended.tesla.battery_battTempPct = battery_battTempPct; datalayer_extended.tesla.battery_soc_ave = battery_soc_ave; datalayer_extended.tesla.battery_soc_max = battery_soc_max; datalayer_extended.tesla.battery_soc_min = battery_soc_min; datalayer_extended.tesla.battery_soc_ui = battery_soc_ui; + //0x332 + datalayer_extended.tesla.battery_BrickVoltageMax = battery_BrickVoltageMax; + datalayer_extended.tesla.battery_BrickVoltageMin = battery_BrickVoltageMin; + datalayer_extended.tesla.battery_BrickTempMaxNum = battery_BrickTempMaxNum; + datalayer_extended.tesla.battery_BrickTempMinNum = battery_BrickTempMinNum; + datalayer_extended.tesla.battery_BrickModelTMax = battery_BrickModelTMax; + datalayer_extended.tesla.battery_BrickModelTMin = battery_BrickModelTMin; + //0x212 + datalayer_extended.tesla.battery_BMS_isolationResistance = battery_BMS_isolationResistance; + datalayer_extended.tesla.battery_BMS_contactorState = battery_BMS_contactorState; + datalayer_extended.tesla.battery_BMS_state = battery_BMS_state; + datalayer_extended.tesla.battery_BMS_hvState = battery_BMS_hvState; + datalayer_extended.tesla.battery_BMS_uiChargeStatus = battery_BMS_uiChargeStatus; + datalayer_extended.tesla.battery_BMS_diLimpRequest = battery_BMS_diLimpRequest; + datalayer_extended.tesla.battery_BMS_chgPowerAvailable = battery_BMS_chgPowerAvailable; + datalayer_extended.tesla.battery_BMS_pcsPwmEnabled = battery_BMS_pcsPwmEnabled; + //0x224 + datalayer_extended.tesla.battery_PCS_dcdcPrechargeStatus = battery_PCS_dcdcPrechargeStatus; + datalayer_extended.tesla.battery_PCS_dcdc12VSupportStatus = battery_PCS_dcdc12VSupportStatus; + datalayer_extended.tesla.battery_PCS_dcdcHvBusDischargeStatus = battery_PCS_dcdcHvBusDischargeStatus; + datalayer_extended.tesla.battery_PCS_dcdcMainState = battery_PCS_dcdcMainState; + datalayer_extended.tesla.battery_PCS_dcdcSubState = battery_PCS_dcdcSubState; + datalayer_extended.tesla.battery_PCS_dcdcFaulted = battery_PCS_dcdcFaulted; + datalayer_extended.tesla.battery_PCS_dcdcOutputIsLimited = battery_PCS_dcdcOutputIsLimited; + datalayer_extended.tesla.battery_PCS_dcdcMaxOutputCurrentAllowed = battery_PCS_dcdcMaxOutputCurrentAllowed; + datalayer_extended.tesla.battery_PCS_dcdcPrechargeRtyCnt = battery_PCS_dcdcPrechargeRtyCnt; + datalayer_extended.tesla.battery_PCS_dcdc12VSupportRtyCnt = battery_PCS_dcdc12VSupportRtyCnt; + datalayer_extended.tesla.battery_PCS_dcdcDischargeRtyCnt = battery_PCS_dcdcDischargeRtyCnt; + datalayer_extended.tesla.battery_PCS_dcdcPwmEnableLine = battery_PCS_dcdcPwmEnableLine; + datalayer_extended.tesla.battery_PCS_dcdcSupportingFixedLvTarget = battery_PCS_dcdcSupportingFixedLvTarget; + datalayer_extended.tesla.battery_PCS_dcdcPrechargeRestartCnt = battery_PCS_dcdcPrechargeRestartCnt; + datalayer_extended.tesla.battery_PCS_dcdcInitialPrechargeSubState = battery_PCS_dcdcInitialPrechargeSubState; + //0x252 + datalayer_extended.tesla.BMS_maxRegenPower = BMS_maxRegenPower; + datalayer_extended.tesla.BMS_maxDischargePower = BMS_maxDischargePower; + datalayer_extended.tesla.BMS_maxStationaryHeatPower = BMS_maxStationaryHeatPower; + datalayer_extended.tesla.BMS_hvacPowerBudget = BMS_hvacPowerBudget; + datalayer_extended.tesla.BMS_notEnoughPowerForHeatPump = BMS_notEnoughPowerForHeatPump; + datalayer_extended.tesla.BMS_powerLimitState = BMS_powerLimitState; + datalayer_extended.tesla.BMS_inverterTQF = BMS_inverterTQF; + //0x312 + datalayer_extended.tesla.BMS_powerDissipation = BMS_powerDissipation; + datalayer_extended.tesla.BMS_flowRequest = BMS_flowRequest; + datalayer_extended.tesla.BMS_inletActiveCoolTargetT = BMS_inletActiveCoolTargetT; + datalayer_extended.tesla.BMS_inletPassiveTargetT = BMS_inletPassiveTargetT; + datalayer_extended.tesla.BMS_inletActiveHeatTargetT = BMS_inletActiveHeatTargetT; + datalayer_extended.tesla.BMS_packTMin = BMS_packTMin; + datalayer_extended.tesla.BMS_packTMax = BMS_packTMax; + datalayer_extended.tesla.BMS_pcsNoFlowRequest = BMS_pcsNoFlowRequest; + datalayer_extended.tesla.BMS_noFlowRequest = BMS_noFlowRequest; + //0x2A4 + datalayer_extended.tesla.PCS_dcdcTemp = PCS_dcdcTemp; + datalayer_extended.tesla.PCS_ambientTemp = PCS_ambientTemp; + //0x2C4 + datalayer_extended.tesla.PCS_dcdcMaxLvOutputCurrent = PCS_dcdcMaxLvOutputCurrent; + datalayer_extended.tesla.PCS_dcdcCurrentLimit = PCS_dcdcCurrentLimit; + datalayer_extended.tesla.PCS_dcdcLvOutputCurrentTempLimit = PCS_dcdcLvOutputCurrentTempLimit; + datalayer_extended.tesla.PCS_dcdcUnifiedCommand = PCS_dcdcUnifiedCommand; + datalayer_extended.tesla.PCS_dcdcCLAControllerOutput = PCS_dcdcCLAControllerOutput; + datalayer_extended.tesla.PCS_dcdcTankVoltage = PCS_dcdcTankVoltage; + datalayer_extended.tesla.PCS_dcdcTankVoltageTarget = PCS_dcdcTankVoltageTarget; + datalayer_extended.tesla.PCS_dcdcClaCurrentFreq = PCS_dcdcClaCurrentFreq; + datalayer_extended.tesla.PCS_dcdcTCommMeasured = PCS_dcdcTCommMeasured; + datalayer_extended.tesla.PCS_dcdcShortTimeUs = PCS_dcdcShortTimeUs; + datalayer_extended.tesla.PCS_dcdcHalfPeriodUs = PCS_dcdcHalfPeriodUs; + datalayer_extended.tesla.PCS_dcdcIntervalMaxFrequency = PCS_dcdcIntervalMaxFrequency; + datalayer_extended.tesla.PCS_dcdcIntervalMaxHvBusVolt = PCS_dcdcIntervalMaxHvBusVolt; + datalayer_extended.tesla.PCS_dcdcIntervalMaxLvBusVolt = PCS_dcdcIntervalMaxLvBusVolt; + datalayer_extended.tesla.PCS_dcdcIntervalMaxLvOutputCurr = PCS_dcdcIntervalMaxLvOutputCurr; + datalayer_extended.tesla.PCS_dcdcIntervalMinFrequency = PCS_dcdcIntervalMinFrequency; + datalayer_extended.tesla.PCS_dcdcIntervalMinHvBusVolt = PCS_dcdcIntervalMinHvBusVolt; + datalayer_extended.tesla.PCS_dcdcIntervalMinLvBusVolt = PCS_dcdcIntervalMinLvBusVolt; + datalayer_extended.tesla.PCS_dcdcIntervalMinLvOutputCurr = PCS_dcdcIntervalMinLvOutputCurr; + datalayer_extended.tesla.PCS_dcdc12vSupportLifetimekWh = PCS_dcdc12vSupportLifetimekWh; + //0x7AA + datalayer_extended.tesla.HVP_gpioPassivePyroDepl = HVP_gpioPassivePyroDepl; + datalayer_extended.tesla.HVP_gpioPyroIsoEn = HVP_gpioPyroIsoEn; + datalayer_extended.tesla.HVP_gpioCpFaultIn = HVP_gpioCpFaultIn; + datalayer_extended.tesla.HVP_gpioPackContPowerEn = HVP_gpioPackContPowerEn; + datalayer_extended.tesla.HVP_gpioHvCablesOk = HVP_gpioHvCablesOk; + datalayer_extended.tesla.HVP_gpioHvpSelfEnable = HVP_gpioHvpSelfEnable; + datalayer_extended.tesla.HVP_gpioLed = HVP_gpioLed; + datalayer_extended.tesla.HVP_gpioCrashSignal = HVP_gpioCrashSignal; + datalayer_extended.tesla.HVP_gpioShuntDataReady = HVP_gpioShuntDataReady; + datalayer_extended.tesla.HVP_gpioFcContPosAux = HVP_gpioFcContPosAux; + datalayer_extended.tesla.HVP_gpioFcContNegAux = HVP_gpioFcContNegAux; + datalayer_extended.tesla.HVP_gpioBmsEout = HVP_gpioBmsEout; + datalayer_extended.tesla.HVP_gpioCpFaultOut = HVP_gpioCpFaultOut; + datalayer_extended.tesla.HVP_gpioPyroPor = HVP_gpioPyroPor; + datalayer_extended.tesla.HVP_gpioShuntEn = HVP_gpioShuntEn; + datalayer_extended.tesla.HVP_gpioHvpVerEn = HVP_gpioHvpVerEn; + datalayer_extended.tesla.HVP_gpioPackCoontPosFlywheel = HVP_gpioPackCoontPosFlywheel; + datalayer_extended.tesla.HVP_gpioCpLatchEnable = HVP_gpioCpLatchEnable; + datalayer_extended.tesla.HVP_gpioPcsEnable = HVP_gpioPcsEnable; + datalayer_extended.tesla.HVP_gpioPcsDcdcPwmEnable = HVP_gpioPcsDcdcPwmEnable; + datalayer_extended.tesla.HVP_gpioPcsChargePwmEnable = HVP_gpioPcsChargePwmEnable; + datalayer_extended.tesla.HVP_gpioFcContPowerEnable = HVP_gpioFcContPowerEnable; + datalayer_extended.tesla.HVP_gpioHvilEnable = HVP_gpioHvilEnable; + datalayer_extended.tesla.HVP_gpioSecDrdy = HVP_gpioSecDrdy; + datalayer_extended.tesla.HVP_hvp1v5Ref = HVP_hvp1v5Ref; + datalayer_extended.tesla.HVP_shuntCurrentDebug = HVP_shuntCurrentDebug; + datalayer_extended.tesla.HVP_packCurrentMia = HVP_packCurrentMia; + datalayer_extended.tesla.HVP_auxCurrentMia = HVP_auxCurrentMia; + datalayer_extended.tesla.HVP_currentSenseMia = HVP_currentSenseMia; + datalayer_extended.tesla.HVP_shuntRefVoltageMismatch = HVP_shuntRefVoltageMismatch; + datalayer_extended.tesla.HVP_shuntThermistorMia = HVP_shuntThermistorMia; + datalayer_extended.tesla.HVP_shuntHwMia = HVP_shuntHwMia; + datalayer_extended.tesla.HVP_dcLinkVoltage = HVP_dcLinkVoltage; + datalayer_extended.tesla.HVP_packVoltage = HVP_packVoltage; + datalayer_extended.tesla.HVP_fcLinkVoltage = HVP_fcLinkVoltage; + datalayer_extended.tesla.HVP_packContVoltage = HVP_packContVoltage; + datalayer_extended.tesla.HVP_packNegativeV = HVP_packNegativeV; + datalayer_extended.tesla.HVP_packPositiveV = HVP_packPositiveV; + datalayer_extended.tesla.HVP_pyroAnalog = HVP_pyroAnalog; + datalayer_extended.tesla.HVP_dcLinkNegativeV = HVP_dcLinkNegativeV; + datalayer_extended.tesla.HVP_dcLinkPositiveV = HVP_dcLinkPositiveV; + datalayer_extended.tesla.HVP_fcLinkNegativeV = HVP_fcLinkNegativeV; + datalayer_extended.tesla.HVP_fcContCoilCurrent = HVP_fcContCoilCurrent; + datalayer_extended.tesla.HVP_fcContVoltage = HVP_fcContVoltage; + datalayer_extended.tesla.HVP_hvilInVoltage = HVP_hvilInVoltage; + datalayer_extended.tesla.HVP_hvilOutVoltage = HVP_hvilOutVoltage; + datalayer_extended.tesla.HVP_fcLinkPositiveV = HVP_fcLinkPositiveV; + datalayer_extended.tesla.HVP_packContCoilCurrent = HVP_packContCoilCurrent; + datalayer_extended.tesla.HVP_battery12V = HVP_battery12V; + datalayer_extended.tesla.HVP_shuntRefVoltageDbg = HVP_shuntRefVoltageDbg; + datalayer_extended.tesla.HVP_shuntAuxCurrentDbg = HVP_shuntAuxCurrentDbg; + datalayer_extended.tesla.HVP_shuntBarTempDbg = HVP_shuntBarTempDbg; + datalayer_extended.tesla.HVP_shuntAsicTempDbg = HVP_shuntAsicTempDbg; + datalayer_extended.tesla.HVP_shuntAuxCurrentStatus = HVP_shuntAuxCurrentStatus; + datalayer_extended.tesla.HVP_shuntBarTempStatus = HVP_shuntBarTempStatus; + datalayer_extended.tesla.HVP_shuntAsicTempStatus = HVP_shuntAsicTempStatus; -#ifdef DEBUG_VIA_USB +#ifdef DEBUG_LOG printFaultCodesIfActive(); - Serial.print("STATUS: Contactor: "); - Serial.print(contactorText[battery_contactor]); //Display what state the contactor is in - Serial.print(", HVIL: "); - Serial.print(hvilStatusState[battery_hvil_status]); - Serial.print(", NegativeState: "); - Serial.print(contactorState[battery_packContNegativeState]); - Serial.print(", PositiveState: "); - Serial.print(contactorState[battery_packContPositiveState]); - Serial.print(", setState: "); - Serial.print(contactorState[battery_packContactorSetState]); - Serial.print(", close allowed: "); - Serial.print(battery_packCtrsClosingAllowed); - Serial.print(", Pyrotest: "); - Serial.println(battery_pyroTestInProgress); + logging.print("STATUS: Contactor: "); + logging.print(contactorText[battery_contactor]); //Display what state the contactor is in + logging.print(", HVIL: "); + logging.print(hvilStatusState[battery_hvil_status]); + logging.print(", NegativeState: "); + logging.print(contactorState[battery_packContNegativeState]); + logging.print(", PositiveState: "); + logging.print(contactorState[battery_packContPositiveState]); + logging.print(", setState: "); + logging.print(contactorState[battery_packContactorSetState]); + logging.print(", close allowed: "); + logging.print(battery_packCtrsClosingAllowed); + logging.print(", Pyrotest: "); + logging.println(battery_pyroTestInProgress); - Serial.print("Battery values: "); - Serial.print("Real SOC: "); - Serial.print(battery_soc_ui / 10.0, 1); + logging.print("Battery values: "); + logging.print("Real SOC: "); + logging.print(battery_soc_ui / 10.0, 1); print_int_with_units(", Battery voltage: ", battery_volts, "V"); print_int_with_units(", Battery HV current: ", (battery_amps * 0.1), "A"); - Serial.print(", Fully charged?: "); + logging.print(", Fully charged?: "); if (battery_full_charge_complete) - Serial.print("YES, "); + logging.print("YES, "); else - Serial.print("NO, "); + logging.print("NO, "); if (datalayer.battery.info.chemistry == battery_chemistry_enum::LFP) { - Serial.print("LFP chemistry detected!"); + logging.print("LFP chemistry detected!"); } - Serial.println(""); - Serial.print("Cellstats, Max: "); - Serial.print(battery_cell_max_v); - Serial.print("mV (cell "); - Serial.print(battery_max_vno); - Serial.print("), Min: "); - Serial.print(battery_cell_min_v); - Serial.print("mV (cell "); - Serial.print(battery_min_vno); - Serial.print("), Imbalance: "); - Serial.print(battery_cell_deviation_mV); - Serial.println("mV."); + logging.println(""); + logging.print("Cellstats, Max: "); + logging.print(battery_cell_max_v); + logging.print("mV (cell "); + logging.print(battery_BrickVoltageMaxNum); + logging.print("), Min: "); + logging.print(battery_cell_min_v); + logging.print("mV (cell "); + logging.print(battery_BrickVoltageMinNum); + logging.print("), Imbalance: "); + logging.print(battery_cell_deviation_mV); + logging.println("mV."); print_int_with_units("High Voltage Output Pins: ", battery_dcdcHvBusVolt, "V"); - Serial.print(", "); + logging.print(", "); print_int_with_units("Low Voltage: ", battery_dcdcLvBusVolt, "V"); - Serial.println(""); + logging.println(""); print_int_with_units("DC/DC 12V current: ", battery_dcdcLvOutputCurrent, "A"); - Serial.println(""); + logging.println(""); - Serial.println("Values passed to the inverter: "); + logging.println("Values passed to the inverter: "); print_SOC(" SOC: ", datalayer.battery.status.reported_soc); print_int_with_units(" Max discharge power: ", datalayer.battery.status.max_discharge_power_W, "W"); - Serial.print(", "); + logging.print(", "); print_int_with_units(" Max charge power: ", datalayer.battery.status.max_charge_power_W, "W"); - Serial.println(""); + logging.println(""); print_int_with_units(" Max temperature: ", ((int16_t)datalayer.battery.status.temperature_min_dC * 0.1), "°C"); - Serial.print(", "); + logging.print(", "); print_int_with_units(" Min temperature: ", ((int16_t)datalayer.battery.status.temperature_max_dC * 0.1), "°C"); - Serial.println(""); -#endif //DEBUG_VIA_USB + logging.println(""); +#endif //DEBUG_LOG } -void receive_can_battery(CAN_frame rx_frame) { +void handle_incoming_can_frame_battery(CAN_frame rx_frame) { static uint8_t mux = 0; static uint16_t temp = 0; switch (rx_frame.ID) { - case 0x352: // BMS_energyStatus // newer BMS >2021 + case 0x352: // 850 BMS_energyStatus newer BMS mux = (rx_frame.data.u8[0] & 0x02); //BMS_energyStatusIndex M : 0|2@1+ (1,0) [0|0] "" X if (mux == 0) { - //battery_nominal_full_pack_energy_m0 = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]); //BMS_nominalFullPackEnergy m0 : 16|16@1+ (0.02,0) [0|0] "kWh" X - //battery_nominal_energy_remaining_m0 = ((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4]); //BMS_nominalEnergyRemaining m0 : 32|16@1+ (0.02,0) [0|0] "kWh" X - //battery_ideal_energy_remaining_m0 = ((rx_frame.data.u8[7] << 8) | rx_frame.data.u8[6]); //BMS_idealEnergyRemaining m0 : 48|16@1+ (0.02,0) [0|0] "kWh" X + battery_nominal_full_pack_energy_m0 = + ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]); //16|16@1+ (0.02,0) [0|0] "kWh"//to datalayer_extended + battery_nominal_energy_remaining_m0 = + ((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4]); //32|16@1+ (0.02,0) [0|0] "kWh"//to datalayer_extended + battery_ideal_energy_remaining_m0 = + ((rx_frame.data.u8[7] << 8) | rx_frame.data.u8[6]); //48|16@1+ (0.02,0) [0|0] "kWh"//to datalayer_extended } if (mux == 1) { - //battery_fully_charged = (rx_frame.data.u8[1] & 0x01); //BMS_fullyCharged m1 : 15|1@1+ (1,0) [0|1] "" X - //battery_energy_buffer_m1 = (rx_frame.data.u8[3] | rx_frame.data.u8[2]); //BMS_energyBuffer m1 : 16|16@1+ (0.01,0) [0|0] "kWh" X - //battery_expected_energy_remaining_m1 = (rx_frame.data.u8[5] | rx_frame.data.u8[4]); //BMS_expectedEnergyRemaining m1 : 32|16@1+ (0.02,0) [0|0] "kWh" X - //battery_energy_to_charge_complete_m1 = (rx_frame.data.u8[7] | rx_frame.data.u8[6]); //BMS_energyToChargeComplete m1 : 48|16@1+ (0.02,0) [0|0] "kWh" X + battery_fully_charged = (rx_frame.data.u8[1] & 0x01); //15|1@1+ (1,0) [0|1]//to datalayer_extended + battery_energy_buffer_m1 = + (rx_frame.data.u8[3] | rx_frame.data.u8[2]); //16|16@1+ (0.01,0) [0|0] "kWh"//to datalayer_extended + battery_expected_energy_remaining_m1 = + (rx_frame.data.u8[5] | rx_frame.data.u8[4]); //32|16@1+ (0.02,0) [0|0] "kWh"//to datalayer_extended + battery_energy_to_charge_complete_m1 = + (rx_frame.data.u8[7] | rx_frame.data.u8[6]); //48|16@1+ (0.02,0) [0|0] "kWh"//to datalayer_extended } if (mux == 2) {} // Additional information needed on this mux, example frame: 02 26 02 20 02 80 00 00 doesn't change @@ -511,42 +1195,122 @@ void receive_can_battery(CAN_frame rx_frame) { battery_full_charge_complete = //BMS_fullChargeComplete : 63|1@1+ (1,0) [0|1] ""//((_d[7] >> 7) & (0x01U)); ((rx_frame.data.u8[7] & 0x01) >> 7); break; - case 0x20A: //Contactor state //HVP_contactorState: - battery_packContNegativeState = (rx_frame.data.u8[0] & 0x07); //0|3@1+ (1,0) [0|7] "" - battery_packContPositiveState = (rx_frame.data.u8[0] & 0x38) >> 3; //3|3@1+ (1,0) [0|7] "" - battery_contactor = (rx_frame.data.u8[1] & 0x0F); //HVP_packContactorSetState : 8|4@1+ (1,0) [0|9] "" - battery_packContactorSetState = (rx_frame.data.u8[1] & 0x0F); //HVP_packContactorSetState : 8|4@1+ (1,0) [0|9] "" - battery_packCtrsClosingAllowed = (rx_frame.data.u8[4] & 0x08) >> 3; //35|1@1+ (1,0) [0|1] "" - battery_pyroTestInProgress = (rx_frame.data.u8[4] & 0x20) >> 5; //37|1@1+ (1,0) [0|1] "" - battery_hvil_status = (rx_frame.data.u8[5] & 0x0F); //40|4@1+ (1,0) [0|9] "" - //HVP_packCtrsOpenNowRequested : 33|1@1+ (1,0) [0|1] "" - //HVP_packCtrsOpenRequested : 34|1@1+ (1,0) [0|1] "" - //HVP_packCtrsRequestStatus : 30|2@1+ (1,0) [0|2] "" - //HVP_packCtrsResetRequestRequired : 32|1@1+ (1,0) [0|1] "" - //HVP_dcLinkAllowedToEnergize : 36|1@1+ (1,0) [0|1] "" Receiver - //HVP_fcContNegativeAuxOpen : 7|1@1+ (1,0) [0|1] "" Receiver - //HVP_fcContNegativeState : 12|3@1+ (1,0) [0|7] "" Receiver - //HVP_fcContPositiveAuxOpen : 6|1@1+ (1,0) [0|1] "" Receiver - //HVP_fcContPositiveState : 16|3@1+ (1,0) [0|7] "" Receiver - //HVP_fcContactorSetState : 19|4@1+ (1,0) [0|9] "" Receiver - //HVP_fcCtrsClosingAllowed : 29|1@1+ (1,0) [0|1] "" Receiver - //HVP_fcCtrsOpenNowRequested : 27|1@1+ (1,0) [0|1] "" Receiver - //HVP_fcCtrsOpenRequested : 28|1@1+ (1,0) [0|1] "" Receiver - //HVP_fcCtrsRequestStatus : 24|2@1+ (1,0) [0|2] "" Receiver - //HVP_fcCtrsResetRequestRequired : 26|1@1+ (1,0) [0|1] "" Receiver - //HVP_fcLinkAllowedToEnergize : 44|2@1+ (1,0) [0|2] "" Receiver + case 0x20A: //522 HVP_contactorState: + battery_packContNegativeState = + (rx_frame.data.u8[0] & 0x07); //(_d[0] & (0x07U)); 0|3@1+ (1,0) [0|7] //to datalayer_extended + battery_packContPositiveState = + (rx_frame.data.u8[0] & 0x38) >> 3; //((_d[0] >> 3) & (0x07U)); 3|3@1+ (1,0) [0|7] //to datalayer_extended + battery_contactor = (rx_frame.data.u8[1] & 0x0F); // 8|4@1+ (1,0) [0|9] //to datalayer_extended + battery_packContactorSetState = + (rx_frame.data.u8[1] & 0x0F); //(_d[1] & (0x0FU)); 8|4@1+ (1,0) [0|9] //to datalayer_extended + battery_packCtrsClosingAllowed = + (rx_frame.data.u8[4] & 0x08) >> 3; //((_d[4] >> 3) & (0x01U)); 35|1@1+ (1,0) [0|1] //to datalayer_extended + battery_pyroTestInProgress = + (rx_frame.data.u8[4] & 0x20) >> 5; //((_d[4] >> 5) & (0x01U));//37|1@1+ (1,0) [0|1] //to datalayer_extended + battery_hvil_status = + (rx_frame.data.u8[5] & 0x0F); //(_d[5] & (0x0FU)); //40|4@1+ (1,0) [0|9] //to datalayer_extended + battery_packCtrsOpenNowRequested = + ((rx_frame.data.u8[4] >> 1) & (0x01U)); //33|1@1+ (1,0) [0|1] //to datalayer_extended + battery_packCtrsOpenRequested = + ((rx_frame.data.u8[4] >> 2) & (0x01U)); //34|1@1+ (1,0) [0|1] //to datalayer_extended + battery_packCtrsRequestStatus = + ((rx_frame.data.u8[3] >> 6) & (0x03U)); //30|2@1+ (1,0) [0|2] //to datalayer_extended + battery_packCtrsResetRequestRequired = + (rx_frame.data.u8[4] & (0x01U)); //32|1@1+ (1,0) [0|1] //to datalayer_extended + battery_dcLinkAllowedToEnergize = + ((rx_frame.data.u8[4] >> 4) & (0x01U)); //36|1@1+ (1,0) [0|1] //to datalayer_extended + battery_fcContNegativeAuxOpen = ((rx_frame.data.u8[0] >> 7) & (0x01U)); //7|1@1+ (1,0) [0|1] "" Receiver + battery_fcContNegativeState = ((rx_frame.data.u8[1] >> 4) & (0x07U)); //12|3@1+ (1,0) [0|7] "" Receiver + battery_fcContPositiveAuxOpen = ((rx_frame.data.u8[0] >> 6) & (0x01U)); //6|1@1+ (1,0) [0|1] "" Receiver + battery_fcContPositiveState = (rx_frame.data.u8[2] & (0x07U)); //16|3@1+ (1,0) [0|7] "" Receiver + battery_fcContactorSetState = ((rx_frame.data.u8[2] >> 3) & (0x0FU)); //19|4@1+ (1,0) [0|9] "" Receiver + battery_fcCtrsClosingAllowed = ((rx_frame.data.u8[3] >> 5) & (0x01U)); //29|1@1+ (1,0) [0|1] "" Receiver + battery_fcCtrsOpenNowRequested = ((rx_frame.data.u8[3] >> 3) & (0x01U)); //27|1@1+ (1,0) [0|1] "" Receiver + battery_fcCtrsOpenRequested = ((rx_frame.data.u8[3] >> 4) & (0x01U)); //28|1@1+ (1,0) [0|1] "" Receiver + battery_fcCtrsRequestStatus = (rx_frame.data.u8[3] & (0x03U)); //24|2@1+ (1,0) [0|2] "" Receiver + battery_fcCtrsResetRequestRequired = ((rx_frame.data.u8[3] >> 2) & (0x01U)); //26|1@1+ (1,0) [0|1] "" Receiver + battery_fcLinkAllowedToEnergize = ((rx_frame.data.u8[5] >> 4) & (0x03U)); //44|2@1+ (1,0) [0|2] "" Receiver break; - case 0x252: //Limit //BMS_powerAvailable252: - battery_regenerative_limit = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]) * - 0.01; //0|16@1+ (0.01,0) [0|655.35] "kW" //Example 4715 * 0.01 = 47.15kW - battery_discharge_limit = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]) * - 0.013; //16|16@1+ (0.013,0) [0|655.35] "kW" //Example 2009 * 0.013 = 26.117??? - battery_max_heat_park = (((rx_frame.data.u8[5] & 0x03) << 8) | rx_frame.data.u8[4]) * - 0.01; //32|10@1+ (0.01,0) [0|10.23] "kW" //Example 500 * 0.01 = 5kW - battery_hvac_max_power = (((rx_frame.data.u8[7] << 6) | ((rx_frame.data.u8[6] & 0xFC) >> 2))) * - 0.02; //50|10@1+ (0.02,0) [0|20.46] "kW" //Example 1000 * 0.02 = 20kW? - //BMS_notEnoughPowerForHeatPump : 42|1@1+ (1,0) [0|1] "" Receiver - //BMS_powerLimitsState : 48|1@1+ (1,0) [0|1] "" Receiver + case 0x212: //530 BMS_status: 8 + battery_BMS_hvacPowerRequest = (rx_frame.data.u8[0] & (0x01U)); + battery_BMS_notEnoughPowerForDrive = ((rx_frame.data.u8[0] >> 1) & (0x01U)); + battery_BMS_notEnoughPowerForSupport = ((rx_frame.data.u8[0] >> 2) & (0x01U)); + battery_BMS_preconditionAllowed = ((rx_frame.data.u8[0] >> 3) & (0x01U)); + battery_BMS_updateAllowed = ((rx_frame.data.u8[0] >> 4) & (0x01U)); + battery_BMS_activeHeatingWorthwhile = ((rx_frame.data.u8[0] >> 5) & (0x01U)); + battery_BMS_cpMiaOnHvs = ((rx_frame.data.u8[0] >> 6) & (0x01U)); + battery_BMS_contactorState = + (rx_frame.data.u8[1] & + (0x07U)); //0 "SNA" 1 "OPEN" 2 "OPENING" 3 "CLOSING" 4 "CLOSED" 5 "WELDED" 6 "BLOCKED" ; + battery_BMS_state = + ((rx_frame.data.u8[1] >> 3) & + (0x0FU)); //0 "STANDBY" 1 "DRIVE" 2 "SUPPORT" 3 "CHARGE" 4 "FEIM" 5 "CLEAR_FAULT" 6 "FAULT" 7 "WELD" 8 "TEST" 9 "SNA" ; + battery_BMS_hvState = + (rx_frame.data.u8[2] & + (0x07U)); //0 "DOWN" 1 "COMING_UP" 2 "GOING_DOWN" 3 "UP_FOR_DRIVE" 4 "UP_FOR_CHARGE" 5 "UP_FOR_DC_CHARGE" 6 "UP" ; + battery_BMS_isolationResistance = + ((rx_frame.data.u8[3] & (0x1FU)) << 5) | + ((rx_frame.data.u8[2] >> 3) & (0x1FU)); //19|10@1+ (10,0) [0|0] "kOhm"/to datalayer_extended + battery_BMS_chargeRequest = ((rx_frame.data.u8[3] >> 5) & (0x01U)); + battery_BMS_keepWarmRequest = ((rx_frame.data.u8[3] >> 6) & (0x01U)); + battery_BMS_uiChargeStatus = + (rx_frame.data.u8[4] & + (0x07U)); // 0 "DISCONNECTED" 1 "NO_POWER" 2 "ABOUT_TO_CHARGE" 3 "CHARGING" 4 "CHARGE_COMPLETE" 5 "CHARGE_STOPPED" ; + battery_BMS_diLimpRequest = ((rx_frame.data.u8[4] >> 3) & (0x01U)); + battery_BMS_okToShipByAir = ((rx_frame.data.u8[4] >> 4) & (0x01U)); + battery_BMS_okToShipByLand = ((rx_frame.data.u8[4] >> 5) & (0x01U)); + battery_BMS_chgPowerAvailable = ((rx_frame.data.u8[6] & (0x01U)) << 10) | ((rx_frame.data.u8[5] & (0xFFU)) << 2) | + ((rx_frame.data.u8[4] >> 6) & (0x03U)); //38|11@1+ (0.125,0) [0|0] "kW" + battery_BMS_chargeRetryCount = ((rx_frame.data.u8[6] >> 1) & (0x0FU)); + battery_BMS_pcsPwmEnabled = ((rx_frame.data.u8[6] >> 5) & (0x01U)); + battery_BMS_ecuLogUploadRequest = ((rx_frame.data.u8[6] >> 6) & (0x03U)); + battery_BMS_minPackTemperature = (rx_frame.data.u8[7] & (0xFFU)); //56|8@1+ (0.5,-40) [0|0] "DegC + break; + case 0x224: //548 PCS_dcdcStatus: + battery_PCS_dcdcPrechargeStatus = (rx_frame.data.u8[0] & (0x03U)); //0 "IDLE" 1 "ACTIVE" 2 "FAULTED" ; + battery_PCS_dcdc12VSupportStatus = ((rx_frame.data.u8[0] >> 2) & (0x03U)); //0 "IDLE" 1 "ACTIVE" 2 "FAULTED" + battery_PCS_dcdcHvBusDischargeStatus = ((rx_frame.data.u8[0] >> 4) & (0x03U)); //0 "IDLE" 1 "ACTIVE" 2 "FAULTED" + battery_PCS_dcdcMainState = + ((rx_frame.data.u8[1] & (0x03U)) << 2) | + ((rx_frame.data.u8[0] >> 6) & + (0x03U)); //0 "STANDBY" 1 "12V_SUPPORT_ACTIVE" 2 "PRECHARGE_STARTUP" 3 "PRECHARGE_ACTIVE" 4 "DIS_HVBUS_ACTIVE" 5 "SHUTDOWN" 6 "FAULTED" ; + battery_PCS_dcdcSubState = + ((rx_frame.data.u8[1] >> 2) & + (0x1FU)); //0 "PWR_UP_INIT" 1 "STANDBY" 2 "12V_SUPPORT_ACTIVE" 3 "DIS_HVBUS" 4 "PCHG_FAST_DIS_HVBUS" 5 "PCHG_SLOW_DIS_HVBUS" 6 "PCHG_DWELL_CHARGE" 7 "PCHG_DWELL_WAIT" 8 "PCHG_DI_RECOVERY_WAIT" 9 "PCHG_ACTIVE" 10 "PCHG_FLT_FAST_DIS_HVBUS" 11 "SHUTDOWN" 12 "12V_SUPPORT_FAULTED" 13 "DIS_HVBUS_FAULTED" 14 "PCHG_FAULTED" 15 "CLEAR_FAULTS" 16 "FAULTED" 17 "NUM" ; + battery_PCS_dcdcFaulted = ((rx_frame.data.u8[1] >> 7) & (0x01U)); + battery_PCS_dcdcOutputIsLimited = ((rx_frame.data.u8[3] >> 4) & (0x01U)); + battery_PCS_dcdcMaxOutputCurrentAllowed = ((rx_frame.data.u8[5] & (0x01U)) << 11) | + ((rx_frame.data.u8[4] & (0xFFU)) << 3) | + ((rx_frame.data.u8[3] >> 5) & (0x07U)); //29|12@1+ (0.1,0) [0|0] "A" + battery_PCS_dcdcPrechargeRtyCnt = ((rx_frame.data.u8[5] >> 1) & (0x07U)); + battery_PCS_dcdc12VSupportRtyCnt = ((rx_frame.data.u8[5] >> 4) & (0x0FU)); + battery_PCS_dcdcDischargeRtyCnt = (rx_frame.data.u8[6] & (0x0FU)); + battery_PCS_dcdcPwmEnableLine = ((rx_frame.data.u8[6] >> 4) & (0x01U)); + battery_PCS_dcdcSupportingFixedLvTarget = ((rx_frame.data.u8[6] >> 5) & (0x01U)); + battery_PCS_ecuLogUploadRequest = ((rx_frame.data.u8[6] >> 6) & (0x03U)); + battery_PCS_dcdcPrechargeRestartCnt = (rx_frame.data.u8[7] & (0x07U)); + battery_PCS_dcdcInitialPrechargeSubState = + ((rx_frame.data.u8[7] >> 3) & + (0x1FU)); //0 "PWR_UP_INIT" 1 "STANDBY" 2 "12V_SUPPORT_ACTIVE" 3 "DIS_HVBUS" 4 "PCHG_FAST_DIS_HVBUS" 5 "PCHG_SLOW_DIS_HVBUS" 6 "PCHG_DWELL_CHARGE" 7 "PCHG_DWELL_WAIT" 8 "PCHG_DI_RECOVERY_WAIT" 9 "PCHG_ACTIVE" 10 "PCHG_FLT_FAST_DIS_HVBUS" 11 "SHUTDOWN" 12 "12V_SUPPORT_FAULTED" 13 "DIS_HVBUS_FAULTED" 14 "PCHG_FAULTED" 15 "CLEAR_FAULTS" 16 "FAULTED" 17 "NUM" ; + break; + case 0x252: //Limit //594 BMS_powerAvailable: + BMS_maxRegenPower = ((rx_frame.data.u8[1] << 8) | + rx_frame.data.u8[0]); //0|16@1+ (0.01,0) [0|655.35] "kW" //Example 4715 * 0.01 = 47.15kW + BMS_maxDischargePower = + ((rx_frame.data.u8[3] << 8) | + rx_frame.data.u8[2]); //16|16@1+ (0.013,0) [0|655.35] "kW" //Example 2009 * 0.013 = 26.117??? + BMS_maxStationaryHeatPower = + (((rx_frame.data.u8[5] & 0x03) << 8) | + rx_frame.data.u8[4]); //32|10@1+ (0.01,0) [0|10.23] "kW" //Example 500 * 0.01 = 5kW + BMS_hvacPowerBudget = + (((rx_frame.data.u8[7] << 6) | + ((rx_frame.data.u8[6] & 0xFC) >> 2))); //50|10@1+ (0.02,0) [0|20.46] "kW" //Example 1000 * 0.02 = 20kW? + BMS_notEnoughPowerForHeatPump = + ((rx_frame.data.u8[5] >> 2) & (0x01U)); //BMS_notEnoughPowerForHeatPump : 42|1@1+ (1,0) [0|1] "" Receiver + BMS_powerLimitState = + (rx_frame.data.u8[6] & + (0x01U)); //BMS_powerLimitsState : 48|1@1+ (1,0) [0|1] 0 "NOT_CALCULATED_FOR_DRIVE" 1 "CALCULATED_FOR_DRIVE" + BMS_inverterTQF = ((rx_frame.data.u8[7] >> 4) & (0x03U)); break; case 0x132: //battery amps/volts //HVBattAmpVolt battery_volts = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]) * @@ -584,26 +1348,122 @@ void receive_can_battery(CAN_frame rx_frame) { temp = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]); temp = (temp & 0xFFF); battery_cell_min_v = temp * 2; - battery_max_vno = 1 + (rx_frame.data.u8[4] & 0x7F); //This cell has highest voltage - battery_min_vno = 1 + (rx_frame.data.u8[5] & 0x7F); //This cell has lowest voltage + cellvoltagesRead = true; + //BattBrickVoltageMax m1 : 2|12@1+ (0.002,0) [0|0] "V" Receiver ((_d[1] & (0x3FU)) << 6) | ((_d[0] >> 2) & (0x3FU)); + battery_BrickVoltageMax = + ((rx_frame.data.u8[1] & (0x3F)) << 6) | ((rx_frame.data.u8[0] >> 2) & (0x3F)); //to datalayer_extended + //BattBrickVoltageMin m1 : 16|12@1+ (0.002,0) [0|0] "V" Receiver ((_d[3] & (0x0FU)) << 8) | (_d[2] & (0xFFU)); + battery_BrickVoltageMin = + ((rx_frame.data.u8[3] & (0x0F)) << 8) | (rx_frame.data.u8[2] & (0xFF)); //to datalayer_extended + //BattBrickVoltageMaxNum m1 : 32|7@1+ (1,1) [0|0] "" Receiver + battery_BrickVoltageMaxNum = + 1 + (rx_frame.data.u8[4] & 0x7F); //(_d[4] & (0x7FU)); //This cell has highest voltage + //BattBrickVoltageMinNum m1 : 40|7@1+ (1,1) [0|0] "" Receiver + battery_BrickVoltageMinNum = + 1 + (rx_frame.data.u8[5] & 0x7F); //(_d[5] & (0x7FU)); //This cell has lowest voltage } if (mux == 0) //Temperature sensors - { + { //BattBrickTempMax m0 : 16|8@1+ (0.5,-40) [0|0] "C" (_d[2] & (0xFFU)); battery_max_temp = (rx_frame.data.u8[2] * 5) - 400; //Temperature values have 40.0*C offset, 0.5*C /bit + //BattBrickTempMin m0 : 24|8@1+ (0.5,-40) [0|0] "C" (_d[3] & (0xFFU)); battery_min_temp = (rx_frame.data.u8[3] * 5) - 400; //Multiply by 5 and remove offset to get C+1 (0x61*5=485-400=8.5*C) + //BattBrickTempMaxNum m0 : 2|4@1+ (1,0) [0|0] "" ((_d[0] >> 2) & (0x0FU)); + battery_BrickTempMaxNum = ((rx_frame.data.u8[0] >> 2) & (0x0F)); //to datalayer_extended + //BattBrickTempMinNum m0 : 8|4@1+ (1,0) [0|0] "" (_d[1] & (0x0FU)); + battery_BrickTempMinNum = (rx_frame.data.u8[1] & (0x0F)); //to datalayer_extended + //BattBrickModelTMax m0 : 32|8@1+ (0.5,-40) [0|0] "C" (_d[4] & (0xFFU)); + battery_BrickModelTMax = (rx_frame.data.u8[4] & (0xFFU)); //to datalayer_extended + //BattBrickModelTMin m0 : 40|8@1+ (0.5,-40) [0|0] "C" (_d[5] & (0xFFU)); + battery_BrickModelTMin = (rx_frame.data.u8[5] & (0xFFU)); //to datalayer_extended + } + break; + case 0x312: // 786 BMS_thermalStatus + BMS_powerDissipation = + ((rx_frame.data.u8[1] & (0x03U)) << 8) | (rx_frame.data.u8[0] & (0xFFU)); //0|10@1+ (0.02,0) [0|0] "kW" + BMS_flowRequest = ((rx_frame.data.u8[2] & (0x01U)) << 6) | + ((rx_frame.data.u8[1] >> 2) & (0x3FU)); //10|7@1+ (0.3,0) [0|0] "LPM" + BMS_inletActiveCoolTargetT = ((rx_frame.data.u8[3] & (0x03U)) << 7) | + ((rx_frame.data.u8[2] >> 1) & (0x7FU)); //17|9@1+ (0.25,-25) [0|0] "DegC" + BMS_inletPassiveTargetT = ((rx_frame.data.u8[4] & (0x07U)) << 6) | + ((rx_frame.data.u8[3] >> 2) & (0x3FU)); //26|9@1+ (0.25,-25) [0|0] "DegC" X + BMS_inletActiveHeatTargetT = ((rx_frame.data.u8[5] & (0x0FU)) << 5) | + ((rx_frame.data.u8[4] >> 3) & (0x1FU)); //35|9@1+ (0.25,-25) [0|0] "DegC" + BMS_packTMin = ((rx_frame.data.u8[6] & (0x1FU)) << 4) | + ((rx_frame.data.u8[5] >> 4) & (0x0FU)); //44|9@1+ (0.25,-25) [-25|100] "DegC" + BMS_packTMax = ((rx_frame.data.u8[7] & (0x3FU)) << 3) | + ((rx_frame.data.u8[6] >> 5) & (0x07U)); //53|9@1+ (0.25,-25) [-25|100] "DegC" + BMS_pcsNoFlowRequest = ((rx_frame.data.u8[7] >> 6) & (0x01U)); // 62|1@1+ (1,0) [0|0] "" + BMS_noFlowRequest = ((rx_frame.data.u8[7] >> 7) & (0x01U)); //63|1@1+ (1,0) [0|0] "" + break; + case 0x2A4: //676 PCS_thermalStatus + PCS_chgPhATemp = + ((rx_frame.data.u8[1] & (0x07U)) << 8) | (rx_frame.data.u8[0] & (0xFFU)); //0|11@1- (0.1,40) [0|0] "C + PCS_chgPhBTemp = + ((rx_frame.data.u8[2] & (0x3FU)) << 5) | ((rx_frame.data.u8[1] >> 3) & (0x1FU)); //11|11@1- (0.1,40) [0|0] "C + PCS_chgPhCTemp = + ((rx_frame.data.u8[4] & (0x07U)) << 8) | (rx_frame.data.u8[3] & (0xFFU)); //24|11@1- (0.1,40) [0|0] "C" + PCS_dcdcTemp = ((rx_frame.data.u8[5] & (0x3FU)) << 5) | + ((rx_frame.data.u8[4] >> 3) & (0x1FU)); //35|11@1- (0.1,40) [0|0] "C" + PCS_ambientTemp = + ((rx_frame.data.u8[7] & (0x07U)) << 8) | (rx_frame.data.u8[6] & (0xFFU)); //48|11@1- (0.1,40) [0|0] "C" + break; + case 0x2C4: // 708 PCS_logging: not all frames are listed, just ones relating to dcdc + mux = (rx_frame.data.u8[0] & (0x1FU)); + //PCS_logMessageSelect = (rx_frame.data.u8[0] & (0x1FU)); //0|5@1+ (1,0) [0|0] "" + if (mux == 6) { + PCS_dcdcMaxLvOutputCurrent = ((rx_frame.data.u8[4] & (0xFFU)) << 4) | + ((rx_frame.data.u8[3] >> 4) & (0x0FU)); //m6 : 28|12@1+ (0.1,0) [0|0] "A" X + PCS_dcdcCurrentLimit = ((rx_frame.data.u8[6] & (0x0FU)) << 8) | + (rx_frame.data.u8[5] & (0xFFU)); //m6 : 40|12@1+ (0.1,0) [0|0] "A" X + PCS_dcdcLvOutputCurrentTempLimit = ((rx_frame.data.u8[7] & (0xFFU)) << 4) | + ((rx_frame.data.u8[6] >> 4) & (0x0FU)); //m6 : 52|12@1+ (0.1,0) [0|0] "A" X + } + if (mux == 7) { + PCS_dcdcUnifiedCommand = ((rx_frame.data.u8[1] & (0x7FU)) << 3) | + ((rx_frame.data.u8[0] >> 5) & (0x07U)); //m7 : 5|10@1+ (0.001,0) [0|0] "1" X + PCS_dcdcCLAControllerOutput = ((rx_frame.data.u8[3] & (0x03U)) << 8) | + (rx_frame.data.u8[2] & (0xFFU)); //m7 : 16|10@1+ (0.001,0) [0|0] "1" X + PCS_dcdcTankVoltage = ((rx_frame.data.u8[4] & (0x1FU)) << 6) | + ((rx_frame.data.u8[3] >> 2) & (0x3FU)); //m7 : 26|11@1- (1,0) [0|0] "V" X + PCS_dcdcTankVoltageTarget = ((rx_frame.data.u8[5] & (0x7FU)) << 3) | + ((rx_frame.data.u8[4] >> 5) & (0x07U)); // m7 : 37|10@1+ (1,0) [0|0] "V" X + PCS_dcdcClaCurrentFreq = ((rx_frame.data.u8[7] & (0x0FU)) << 8) | + (rx_frame.data.u8[6] & (0xFFU)); //P m7 : 48|12@1+ (0.0976563,0) [0|0] "kHz" X + } + if (mux == 8) { + PCS_dcdcTCommMeasured = ((rx_frame.data.u8[2] & (0xFFU)) << 8) | + (rx_frame.data.u8[1] & (0xFFU)); // m8 : 8|16@1- (0.00195313,0) [0|0] "us" X + PCS_dcdcShortTimeUs = ((rx_frame.data.u8[4] & (0xFFU)) << 8) | + (rx_frame.data.u8[3] & (0xFFU)); // m8 : 24|16@1+ (0.000488281,0) [0|0] "us" X + PCS_dcdcHalfPeriodUs = ((rx_frame.data.u8[6] & (0xFFU)) << 8) | + (rx_frame.data.u8[5] & (0xFFU)); // m8 : 40|16@1+ (0.000488281,0) [0|0] "us" X + } + if (mux == 18) { + PCS_dcdcIntervalMaxFrequency = ((rx_frame.data.u8[2] & (0x0FU)) << 8) | + (rx_frame.data.u8[1] & (0xFFU)); // m18 : 8|12@1+ (1,0) [0|0] "kHz" X + PCS_dcdcIntervalMaxHvBusVolt = ((rx_frame.data.u8[4] & (0x1FU)) << 8) | + (rx_frame.data.u8[3] & (0xFFU)); //m18 : 24|13@1+ (0.1,0) [0|0] "V" X + PCS_dcdcIntervalMaxLvBusVolt = ((rx_frame.data.u8[5] & (0x3FU)) << 3) | + ((rx_frame.data.u8[4] >> 5) & (0x07U)); // m18 : 37|9@1+ (0.1,0) [0|0] "V" X + PCS_dcdcIntervalMaxLvOutputCurr = ((rx_frame.data.u8[7] & (0x0FU)) << 8) | + (rx_frame.data.u8[6] & (0xFFU)); //m18 : 48|12@1+ (1,0) [0|0] "A" X + } + if (mux == 19) { + PCS_dcdcIntervalMinFrequency = ((rx_frame.data.u8[2] & (0x0FU)) << 8) | + (rx_frame.data.u8[1] & (0xFFU)); //m19 : 8|12@1+ (1,0) [0|0] "kHz" X + PCS_dcdcIntervalMinHvBusVolt = ((rx_frame.data.u8[4] & (0x1FU)) << 8) | + (rx_frame.data.u8[3] & (0xFFU)); //m19 : 24|13@1+ (0.1,0) [0|0] "V" X + PCS_dcdcIntervalMinLvBusVolt = ((rx_frame.data.u8[5] & (0x3FU)) << 3) | + ((rx_frame.data.u8[4] >> 5) & (0x07U)); //m19 : 37|9@1+ (0.1,0) [0|0] "V" X + PCS_dcdcIntervalMinLvOutputCurr = ((rx_frame.data.u8[7] & (0x0FU)) << 8) | + (rx_frame.data.u8[6] & (0xFFU)); // m19 : 48|12@1+ (1,0) [0|0] "A" X + } + if (mux == 22) { + PCS_dcdc12vSupportLifetimekWh = ((rx_frame.data.u8[3] & (0xFFU)) << 16) | + ((rx_frame.data.u8[2] & (0xFFU)) << 8) | + (rx_frame.data.u8[1] & (0xFFU)); // m22 : 8|24@1+ (0.01,0) [0|0] "kWh" X } - //BattBrickMultiplexer M : 0|2@1+ (1,0) [0|0] "" Receiver - //BattBrickTempMaxNum m0 : 2|4@1+ (1,0) [0|0] "" Receiver - //BattBrickTempMinNum m0 : 8|4@1+ (1,0) [0|0] "" Receiver - //BattBrickTempMax m0 : 16|8@1+ (0.5,-40) [0|0] "C" Receiver - //BattBrickTempMin m0 : 24|8@1+ (0.5,-40) [0|0] "C" Receiver - //BattBrickModelTMax m0 : 32|8@1+ (0.5,-40) [0|0] "C" Receiver - //BattBrickModelTMin m0 : 40|8@1+ (0.5,-40) [0|0] "C" Receiver - //BattBrickVoltageMax m1 : 2|12@1+ (0.002,0) [0|0] "V" Receiver - //BattBrickVoltageMin m1 : 16|12@1+ (0.002,0) [0|0] "V" Receiver - //BattBrickVoltageMaxNum m1 : 32|7@1+ (1,1) [0|0] "" Receiver - //BattBrickVoltageMinNum m1 : 40|7@1+ (1,1) [0|0] "" Receiver break; case 0x401: // Cell stats //BrickVoltages mux = (rx_frame.data.u8[0]); //MultiplexSelector M : 0|8@1+ (1,0) [0|0] "" @@ -677,13 +1537,114 @@ void receive_can_battery(CAN_frame rx_frame) { mux = (rx_frame.data.u8[0] & (0xFF)); if (mux == 1) { battery_packConfigMultiplexer = (rx_frame.data.u8[0] & (0xff)); //0|8@1+ (1,0) [0|1] "" - battery_moduleType = (rx_frame.data.u8[1] & (0x07)); //8|3@1+ (1,0) [0|4] "" - battery_packMass = (rx_frame.data.u8[2]) + 300; //16|8@1+ (1,300) [342|469] "kg" + battery_moduleType = + (rx_frame.data.u8[1] & + (0x07)); //8|3@1+ (1,0) [0|4] ""//0 "UNKNOWN" 1 "E3_NCT" 2 "E1_NCT" 3 "E3_CT" 4 "E1_CT" 5 "E1_CP" ;//to datalayer_extended + battery_packMass = (rx_frame.data.u8[2]) + 300; //16|8@1+ (1,300) [342|469] "kg" battery_platformMaxBusVoltage = (((rx_frame.data.u8[4] & 0x03) << 8) | (rx_frame.data.u8[3])); //24|10@1+ (0.1,375) [0|0] "V" } if (mux == 0) { - battery_reservedConfig = (rx_frame.data.u8[1] & (0x1F)); //8|5@1+ (1,0) [0|31] "" + battery_reservedConfig = + (rx_frame.data.u8[1] & + (0x1F)); //8|5@1+ (1,0) [0|31] ""//0 "BMS_CONFIG_0" 1 "BMS_CONFIG_1" 10 "BMS_CONFIG_10" 11 "BMS_CONFIG_11" 12 "BMS_CONFIG_12" 13 "BMS_CONFIG_13" 14 "BMS_CONFIG_14" 15 "BMS_CONFIG_15" 16 "BMS_CONFIG_16" 17 "BMS_CONFIG_17" 18 "BMS_CONFIG_18" 19 "BMS_CONFIG_19" 2 "BMS_CONFIG_2" 20 "BMS_CONFIG_20" 21 "BMS_CONFIG_21" 22 "BMS_CONFIG_22" 23 "BMS_CONFIG_23" 24 "BMS_CONFIG_24" 25 "BMS_CONFIG_25" 26 "BMS_CONFIG_26" 27 "BMS_CONFIG_27" 28 "BMS_CONFIG_28" 29 "BMS_CONFIG_29" 3 "BMS_CONFIG_3" 30 "BMS_CONFIG_30" 31 "BMS_CONFIG_31" 4 "BMS_CONFIG_4" 5 "BMS_CONFIG_5" 6 "BMS_CONFIG_6" 7 "BMS_CONFIG_7" 8 "BMS_CONFIG_8" 9 "BMS_CONFIG_9" ; + } + break; + case 0x7AA: //1962 HVP_debugMessage: + mux = (rx_frame.data.u8[0] & (0x0FU)); + //HVP_debugMessageMultiplexer = (rx_frame.data.u8[0] & (0x0FU)); //0|4@1+ (1,0) [0|6] "" + if (mux == 0) { + HVP_gpioPassivePyroDepl = ((rx_frame.data.u8[0] >> 4) & (0x01U)); //: 4|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioPyroIsoEn = ((rx_frame.data.u8[0] >> 5) & (0x01U)); //: 5|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioCpFaultIn = ((rx_frame.data.u8[0] >> 6) & (0x01U)); //: 6|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioPackContPowerEn = ((rx_frame.data.u8[0] >> 7) & (0x01U)); //: 7|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioHvCablesOk = (rx_frame.data.u8[1] & (0x01U)); //: 8|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioHvpSelfEnable = ((rx_frame.data.u8[1] >> 1) & (0x01U)); //: 9|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioLed = ((rx_frame.data.u8[1] >> 2) & (0x01U)); //: 10|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioCrashSignal = ((rx_frame.data.u8[1] >> 3) & (0x01U)); //: 11|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioShuntDataReady = ((rx_frame.data.u8[1] >> 4) & (0x01U)); //: 12|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioFcContPosAux = ((rx_frame.data.u8[1] >> 5) & (0x01U)); //: 13|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioFcContNegAux = ((rx_frame.data.u8[1] >> 6) & (0x01U)); //: 14|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioBmsEout = ((rx_frame.data.u8[1] >> 7) & (0x01U)); //: 15|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioCpFaultOut = (rx_frame.data.u8[2] & (0x01U)); //: 16|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioPyroPor = ((rx_frame.data.u8[2] >> 1) & (0x01U)); //: 17|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioShuntEn = ((rx_frame.data.u8[2] >> 2) & (0x01U)); //: 18|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioHvpVerEn = ((rx_frame.data.u8[2] >> 3) & (0x01U)); //: 19|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioPackCoontPosFlywheel = ((rx_frame.data.u8[2] >> 4) & (0x01U)); //: 20|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioCpLatchEnable = ((rx_frame.data.u8[2] >> 5) & (0x01U)); //: 21|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioPcsEnable = ((rx_frame.data.u8[2] >> 6) & (0x01U)); //: 22|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioPcsDcdcPwmEnable = ((rx_frame.data.u8[2] >> 7) & (0x01U)); //: 23|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioPcsChargePwmEnable = (rx_frame.data.u8[3] & (0x01U)); //: 24|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioFcContPowerEnable = ((rx_frame.data.u8[3] >> 1) & (0x01U)); //: 25|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioHvilEnable = ((rx_frame.data.u8[3] >> 2) & (0x01U)); //: 26|1@1+ (1,0) [0|1] "" Receiver + HVP_gpioSecDrdy = ((rx_frame.data.u8[3] >> 3) & (0x01U)); //: 27|1@1+ (1,0) [0|1] "" Receiver + HVP_hvp1v5Ref = ((rx_frame.data.u8[4] & (0xFFU)) << 4) | + ((rx_frame.data.u8[3] >> 4) & (0x0FU)); //: 28|12@1+ (0.1,0) [0|3] "V" Receiver + HVP_shuntCurrentDebug = ((rx_frame.data.u8[6] & (0xFFU)) << 8) | + (rx_frame.data.u8[5] & (0xFFU)); //: 40|16@1- (0.1,0) [-3276.8|3276.7] "A" Receiver + HVP_packCurrentMia = (rx_frame.data.u8[7] & (0x01U)); //: 56|1@1+ (1,0) [0|1] "" Receiver + HVP_auxCurrentMia = ((rx_frame.data.u8[7] >> 1) & (0x01U)); //: 57|1@1+ (1,0) [0|1] "" Receiver + HVP_currentSenseMia = ((rx_frame.data.u8[7] >> 2) & (0x03U)); //: 58|1@1+ (1,0) [0|1] "" Receiver + HVP_shuntRefVoltageMismatch = ((rx_frame.data.u8[7] >> 3) & (0x01U)); //: 59|1@1+ (1,0) [0|1] "" Receiver + HVP_shuntThermistorMia = ((rx_frame.data.u8[7] >> 4) & (0x01U)); //: 60|1@1+ (1,0) [0|1] "" Receiver + HVP_shuntHwMia = ((rx_frame.data.u8[7] >> 5) & (0x01U)); //: 61|1@1+ (1,0) [0|1] "" Receiver + } + if (mux == 1) { + HVP_dcLinkVoltage = ((rx_frame.data.u8[2] & (0xFFU)) << 8) | + (rx_frame.data.u8[1] & (0xFFU)); //: 8|16@1- (0.1,0) [-3276.8|3276.7] "V" Receiver + HVP_packVoltage = ((rx_frame.data.u8[4] & (0xFFU)) << 8) | + (rx_frame.data.u8[3] & (0xFFU)); //: 24|16@1- (0.1,0) [-3276.8|3276.7] "V" Receiver + HVP_fcLinkVoltage = ((rx_frame.data.u8[6] & (0xFFU)) << 8) | + (rx_frame.data.u8[5] & (0xFFU)); //: 40|16@1- (0.1,0) [-3276.8|3276.7] "V" Receiver + } + if (mux == 2) { + HVP_packContVoltage = ((rx_frame.data.u8[1] & (0xFFU)) << 4) | + ((rx_frame.data.u8[0] >> 4) & (0x0FU)); //: 4|12@1+ (0.1,0) [0|30] "V" Receiver + HVP_packNegativeV = ((rx_frame.data.u8[3] & (0xFFU)) << 8) | + (rx_frame.data.u8[2] & (0xFFU)); //: 16|16@1- (0.1,0) [-550|550] "V" Receiver + HVP_packPositiveV = ((rx_frame.data.u8[5] & (0xFFU)) << 8) | + (rx_frame.data.u8[4] & (0xFFU)); //: 32|16@1- (0.1,0) [-550|550] "V" Receiver + HVP_pyroAnalog = ((rx_frame.data.u8[7] & (0x0FU)) << 8) | + (rx_frame.data.u8[6] & (0xFFU)); //: 48|12@1+ (0.1,0) [0|3] "V" Receiver + } + if (mux == 3) { + HVP_dcLinkNegativeV = ((rx_frame.data.u8[2] & (0xFFU)) << 8) | + (rx_frame.data.u8[1] & (0xFFU)); //: 8|16@1- (0.1,0) [-550|550] "V" Receiver + HVP_dcLinkPositiveV = ((rx_frame.data.u8[4] & (0xFFU)) << 8) | + (rx_frame.data.u8[3] & (0xFFU)); //: 24|16@1- (0.1,0) [-550|550] "V" Receiver + HVP_fcLinkNegativeV = ((rx_frame.data.u8[6] & (0xFFU)) << 8) | + (rx_frame.data.u8[5] & (0xFFU)); //: 40|16@1- (0.1,0) [-550|550] "V" Receiver + } + if (mux == 4) { + HVP_fcContCoilCurrent = ((rx_frame.data.u8[1] & (0xFFU)) << 4) | + ((rx_frame.data.u8[0] >> 4) & (0x0FU)); //: 4|12@1+ (0.1,0) [0|7.5] "A" Receiver + HVP_fcContVoltage = ((rx_frame.data.u8[3] & (0x0FU)) << 8) | + (rx_frame.data.u8[2] & (0xFFU)); //: 16|12@1+ (0.1,0) [0|30] "V" Receiver + HVP_hvilInVoltage = ((rx_frame.data.u8[4] & (0xFFU)) << 4) | + ((rx_frame.data.u8[3] >> 4) & (0x0FU)); //: 28|12@1+ (0.1,0) [0|30] "V" Receiver + HVP_hvilOutVoltage = ((rx_frame.data.u8[6] & (0x0FU)) << 8) | + (rx_frame.data.u8[5] & (0xFFU)); //: 40|12@1+ (0.1,0) [0|30] "V" Receiver + } + if (mux == 5) { + HVP_fcLinkPositiveV = ((rx_frame.data.u8[2] & (0xFFU)) << 8) | + (rx_frame.data.u8[1] & (0xFFU)); //: 8|16@1- (0.1,0) [-550|550] "V" Receiver + HVP_packContCoilCurrent = ((rx_frame.data.u8[4] & (0x0FU)) << 8) | + (rx_frame.data.u8[3] & (0xFFU)); //: 24|12@1+ (0.1,0) [0|7.5] "A" Receiver + HVP_battery12V = ((rx_frame.data.u8[5] & (0xFFU)) << 4) | + ((rx_frame.data.u8[4] >> 4) & (0x0FU)); //: 36|12@1+ (0.1,0) [0|30] "V" Receiver + HVP_shuntRefVoltageDbg = ((rx_frame.data.u8[7] & (0xFFU)) << 8) | + (rx_frame.data.u8[6] & (0xFFU)); //: 48|16@1- (0.001,0) [-32.768|32.767] "V" Receiver + } + if (mux == 6) { + HVP_shuntAuxCurrentDbg = ((rx_frame.data.u8[2] & (0xFFU)) << 8) | + (rx_frame.data.u8[1] & (0xFFU)); //: 8|16@1- (0.1,0) [-3276.8|3276.7] "A" Receiver + HVP_shuntBarTempDbg = ((rx_frame.data.u8[4] & (0xFFU)) << 8) | + (rx_frame.data.u8[3] & (0xFFU)); //: 24|16@1- (0.01,0) [-327.67|327.67] "C" Receiver + HVP_shuntAsicTempDbg = ((rx_frame.data.u8[6] & (0xFFU)) << 8) | + (rx_frame.data.u8[5] & (0xFFU)); //: 40|16@1- (0.01,0) [-327.67|327.67] "C" Receiver + HVP_shuntAuxCurrentStatus = (rx_frame.data.u8[7] & (0x03U)); //: 56|2@1+ (1,0) [0|3] "" Receiver + HVP_shuntBarTempStatus = ((rx_frame.data.u8[7] >> 2) & (0x03U)); //: 58|2@1+ (1,0) [0|3] "" Receiver + HVP_shuntAsicTempStatus = ((rx_frame.data.u8[7] >> 4) & (0x03U)); //: 60|2@1+ (1,0) [0|3] "" Receiver } break; case 0x3aa: //HVP_alertMatrix1 @@ -739,14 +1700,118 @@ void receive_can_battery(CAN_frame rx_frame) { battery_fcCtrCloseFailed = ((rx_frame.data.u8[6] & 0x02) >> 1); battery_shuntThermistorMia = ((rx_frame.data.u8[6] & 0x04) >> 2); break; + case 0x320: //800 BMS_alertMatrix //BMS_alertMatrix 800 BMS_alertMatrix: 8 VEH + mux = (rx_frame.data.u8[0] & (0x0F)); + if (mux == 0) + ; + { //mux0 + battery_BMS_matrixIndex = (rx_frame.data.u8[0] & (0x0F)); // 0|4@1+ (1,0) [0|0] "" X + battery_BMS_a017_SW_Brick_OV = ((rx_frame.data.u8[2] >> 4) & (0x01)); //20|1@1+ (1,0) [0|0] "" X + battery_BMS_a018_SW_Brick_UV = ((rx_frame.data.u8[2] >> 5) & (0x01)); //21|1@1+ (1,0) [0|0] "" X + battery_BMS_a019_SW_Module_OT = ((rx_frame.data.u8[2] >> 6) & (0x01)); //22|1@1+ (1,0) [0|0] "" X + battery_BMS_a021_SW_Dr_Limits_Regulation = (rx_frame.data.u8[3] & (0x01U)); //24|1@1+ (1,0) [0|0] "" X + battery_BMS_a022_SW_Over_Current = ((rx_frame.data.u8[3] >> 1) & (0x01U)); //25|1@1+ (1,0) [0|0] "" X + battery_BMS_a023_SW_Stack_OV = ((rx_frame.data.u8[3] >> 2) & (0x01U)); //26|1@1+ (1,0) [0|0] "" X + battery_BMS_a024_SW_Islanded_Brick = ((rx_frame.data.u8[3] >> 3) & (0x01U)); //27|1@1+ (1,0) [0|0] "" X + battery_BMS_a025_SW_PwrBalance_Anomaly = ((rx_frame.data.u8[3] >> 4) & (0x01U)); //28|1@1+ (1,0) [0|0] "" X + battery_BMS_a026_SW_HFCurrent_Anomaly = ((rx_frame.data.u8[3] >> 5) & (0x01U)); //29|1@1+ (1,0) [0|0] "" X + battery_BMS_a034_SW_Passive_Isolation = ((rx_frame.data.u8[4] >> 5) & (0x01U)); //37|1@1+ (1,0) [0|0] "" X ? + battery_BMS_a035_SW_Isolation = ((rx_frame.data.u8[4] >> 6) & (0x01U)); //38|1@1+ (1,0) [0|0] "" X + battery_BMS_a036_SW_HvpHvilFault = ((rx_frame.data.u8[4] >> 6) & (0x01U)); //39|1@1+ (1,0) [0|0] "" X + battery_BMS_a037_SW_Flood_Port_Open = (rx_frame.data.u8[5] & (0x01U)); //40|1@1+ (1,0) [0|0] "" X + battery_BMS_a039_SW_DC_Link_Over_Voltage = ((rx_frame.data.u8[5] >> 2) & (0x01U)); //42|1@1+ (1,0) [0|0] "" X + battery_BMS_a041_SW_Power_On_Reset = ((rx_frame.data.u8[5] >> 4) & (0x01U)); //44|1@1+ (1,0) [0|0] "" X + battery_BMS_a042_SW_MPU_Error = ((rx_frame.data.u8[5] >> 5) & (0x01U)); //45|1@1+ (1,0) [0|0] "" X + battery_BMS_a043_SW_Watch_Dog_Reset = ((rx_frame.data.u8[5] >> 6) & (0x01U)); //46|1@1+ (1,0) [0|0] "" X + battery_BMS_a044_SW_Assertion = ((rx_frame.data.u8[5] >> 7) & (0x01U)); //47|1@1+ (1,0) [0|0] "" X + battery_BMS_a045_SW_Exception = (rx_frame.data.u8[6] & (0x01U)); //48|1@1+ (1,0) [0|0] "" X + battery_BMS_a046_SW_Task_Stack_Usage = ((rx_frame.data.u8[6] >> 1) & (0x01U)); //49|1@1+ (1,0) [0|0] "" X + battery_BMS_a047_SW_Task_Stack_Overflow = ((rx_frame.data.u8[6] >> 2) & (0x01U)); //50|1@1+ (1,0) [0|0] "" X + battery_BMS_a048_SW_Log_Upload_Request = ((rx_frame.data.u8[6] >> 3) & (0x01U)); //51|1@1+ (1,0) [0|0] "" X + battery_BMS_a050_SW_Brick_Voltage_MIA = ((rx_frame.data.u8[6] >> 5) & (0x01U)); //53|1@1+ (1,0) [0|0] "" X + battery_BMS_a051_SW_HVC_Vref_Bad = ((rx_frame.data.u8[6] >> 6) & (0x01U)); //54|1@1+ (1,0) [0|0] "" X + battery_BMS_a052_SW_PCS_MIA = ((rx_frame.data.u8[6] >> 7) & (0x01U)); //55|1@1+ (1,0) [0|0] "" X + battery_BMS_a053_SW_ThermalModel_Sanity = (rx_frame.data.u8[7] & (0x01U)); //56|1@1+ (1,0) [0|0] "" X + battery_BMS_a054_SW_Ver_Supply_Fault = ((rx_frame.data.u8[7] >> 1) & (0x01U)); //57|1@1+ (1,0) [0|0] "" X + battery_BMS_a059_SW_Pack_Voltage_Sensing = ((rx_frame.data.u8[7] >> 6) & (0x01U)); //62|1@1+ (1,0) [0|0] "" X + battery_BMS_a060_SW_Leakage_Test_Failure = ((rx_frame.data.u8[7] >> 7) & (0x01U)); //63|1@1+ (1,0) [0|0] "" X + } + if (mux == 1) { //mux1 + battery_BMS_a061_robinBrickOverVoltage = ((rx_frame.data.u8[0] >> 4) & (0x01U)); //4|1@1+ (1,0) [0|0] "" X + battery_BMS_a062_SW_BrickV_Imbalance = ((rx_frame.data.u8[0] >> 5) & (0x01U)); //5|1@1+ (1,0) [0|0] "" X + battery_BMS_a063_SW_ChargePort_Fault = ((rx_frame.data.u8[0] >> 6) & (0x01U)); //6|1@1+ (1,0) [0|0] "" X + battery_BMS_a064_SW_SOC_Imbalance = ((rx_frame.data.u8[0] >> 7) & (0x01U)); //7|1@1+ (1,0) [0|0] "" X + battery_BMS_a069_SW_Low_Power = ((rx_frame.data.u8[1] >> 4) & (0x01U)); //12|1@1+ (1,0) [0|0] "" X + battery_BMS_a071_SW_SM_TransCon_Not_Met = ((rx_frame.data.u8[1] >> 6) & (0x01U)); //14|1@1+ (1,0) [0|0] "" X + battery_BMS_a075_SW_Chg_Disable_Failure = ((rx_frame.data.u8[2] >> 2) & (0x01U)); //18|1@1+ (1,0) [0|0] "" X + battery_BMS_a076_SW_Dch_While_Charging = ((rx_frame.data.u8[2] >> 3) & (0x01U)); //19|1@1+ (1,0) [0|0] "" X + battery_BMS_a077_SW_Charger_Regulation = ((rx_frame.data.u8[2] >> 4) & (0x01U)); //20|1@1+ (1,0) [0|0] "" X + battery_BMS_a081_SW_Ctr_Close_Blocked = (rx_frame.data.u8[3] & (0x01U)); //24|1@1+ (1,0) [0|0] "" X + battery_BMS_a082_SW_Ctr_Force_Open = ((rx_frame.data.u8[3] >> 1) & (0x01U)); //25|1@1+ (1,0) [0|0] "" X + battery_BMS_a083_SW_Ctr_Close_Failure = ((rx_frame.data.u8[3] >> 2) & (0x01U)); //26|1@1+ (1,0) [0|0] "" X + battery_BMS_a084_SW_Sleep_Wake_Aborted = ((rx_frame.data.u8[3] >> 3) & (0x01U)); //27|1@1+ (1,0) [0|0] "" X + battery_BMS_a087_SW_Feim_Test_Blocked = ((rx_frame.data.u8[3] >> 6) & (0x01U)); //30|1@1+ (1,0) [0|0] "" X + battery_BMS_a088_SW_VcFront_MIA_InDrive = ((rx_frame.data.u8[3] >> 7) & (0x01U)); //31|1@1+ (1,0) [0|0] "" X + battery_BMS_a089_SW_VcFront_MIA = (rx_frame.data.u8[4] & (0x01U)); //32|1@1+ (1,0) [0|0] "" X + battery_BMS_a090_SW_Gateway_MIA = ((rx_frame.data.u8[4] >> 1) & (0x01U)); //33|1@1+ (1,0) [0|0] "" X + battery_BMS_a091_SW_ChargePort_MIA = ((rx_frame.data.u8[4] >> 2) & (0x01U)); //34|1@1+ (1,0) [0|0] "" X + battery_BMS_a092_SW_ChargePort_Mia_On_Hv = ((rx_frame.data.u8[4] >> 3) & (0x01U)); //35|1@1+ (1,0) [0|0] "" X + battery_BMS_a094_SW_Drive_Inverter_MIA = ((rx_frame.data.u8[4] >> 5) & (0x01U)); //37|1@1+ (1,0) [0|0] "" X + battery_BMS_a099_SW_BMB_Communication = ((rx_frame.data.u8[5] >> 2) & (0x01U)); //42|1@1+ (1,0) [0|0] "" X + battery_BMS_a105_SW_One_Module_Tsense = (rx_frame.data.u8[6] & (0x01U)); //48|1@1+ (1,0) [0|0] "" X + battery_BMS_a106_SW_All_Module_Tsense = ((rx_frame.data.u8[6] >> 1) & (0x01U)); //49|1@1+ (1,0) [0|0] "" X + battery_BMS_a107_SW_Stack_Voltage_MIA = ((rx_frame.data.u8[6] >> 2) & (0x01U)); //50|1@1+ (1,0) [0|0] "" X + } + if (mux == 2) { //mux2 + battery_BMS_a121_SW_NVRAM_Config_Error = ((rx_frame.data.u8[0] >> 4) & (0x01U)); // 4|1@1+ (1,0) [0|0] "" X + battery_BMS_a122_SW_BMS_Therm_Irrational = ((rx_frame.data.u8[0] >> 5) & (0x01U)); //5|1@1+ (1,0) [0|0] "" X + battery_BMS_a123_SW_Internal_Isolation = ((rx_frame.data.u8[0] >> 6) & (0x01U)); //6|1@1+ (1,0) [0|0] "" X + battery_BMS_a127_SW_shunt_SNA = ((rx_frame.data.u8[1] >> 2) & (0x01U)); //10|1@1+ (1,0) [0|0] "" X + battery_BMS_a128_SW_shunt_MIA = ((rx_frame.data.u8[1] >> 3) & (0x01U)); //11|1@1+ (1,0) [0|0] "" X + battery_BMS_a129_SW_VSH_Failure = ((rx_frame.data.u8[1] >> 4) & (0x01U)); //12|1@1+ (1,0) [0|0] "" X + battery_BMS_a130_IO_CAN_Error = ((rx_frame.data.u8[1] >> 5) & (0x01U)); //13|1@1+ (1,0) [0|0] "" X + battery_BMS_a131_Bleed_FET_Failure = ((rx_frame.data.u8[1] >> 6) & (0x01U)); //14|1@1+ (1,0) [0|0] "" X + battery_BMS_a132_HW_BMB_OTP_Uncorrctbl = ((rx_frame.data.u8[1] >> 7) & (0x01U)); //15|1@1+ (1,0) [0|0] "" X + battery_BMS_a134_SW_Delayed_Ctr_Off = ((rx_frame.data.u8[2] >> 1) & (0x01U)); //17|1@1+ (1,0) [0|0] "" X + battery_BMS_a136_SW_Module_OT_Warning = ((rx_frame.data.u8[2] >> 3) & (0x01U)); //19|1@1+ (1,0) [0|0] "" X + battery_BMS_a137_SW_Brick_UV_Warning = ((rx_frame.data.u8[2] >> 4) & (0x01U)); //20|1@1+ (1,0) [0|0] "" X + battery_BMS_a138_SW_Brick_OV_Warning = ((rx_frame.data.u8[2] >> 5) & (0x01U)); //21|1@1+ (1,0) [0|0] "" X + battery_BMS_a139_SW_DC_Link_V_Irrational = ((rx_frame.data.u8[2] >> 6) & (0x01U)); //22|1@1+ (1,0) [0|0] "" X + battery_BMS_a141_SW_BMB_Status_Warning = (rx_frame.data.u8[3] & (0x01U)); //24|1@1+ (1,0) [0|0] "" X + battery_BMS_a144_Hvp_Config_Mismatch = ((rx_frame.data.u8[3] >> 3) & (0x01U)); //27|1@1+ (1,0) [0|0] "" X + battery_BMS_a145_SW_SOC_Change = ((rx_frame.data.u8[3] >> 4) & (0x01U)); //28|1@1+ (1,0) [0|0] "" X + battery_BMS_a146_SW_Brick_Overdischarged = ((rx_frame.data.u8[3] >> 5) & (0x01U)); //29|1@1+ (1,0) [0|0] "" X + battery_BMS_a149_SW_Missing_Config_Block = (rx_frame.data.u8[4] & (0x01U)); //32|1@1+ (1,0) [0|0] "" X + battery_BMS_a151_SW_external_isolation = ((rx_frame.data.u8[4] >> 2) & (0x01U)); //34|1@1+ (1,0) [0|0] "" X + battery_BMS_a156_SW_BMB_Vref_bad = ((rx_frame.data.u8[4] >> 7) & (0x01U)); //39|1@1+ (1,0) [0|0] "" X + battery_BMS_a157_SW_HVP_HVS_Comms = (rx_frame.data.u8[5] & (0x01U)); //40|1@1+ (1,0) [0|0] "" X + battery_BMS_a158_SW_HVP_HVI_Comms = ((rx_frame.data.u8[5] >> 1) & (0x01U)); //41|1@1+ (1,0) [0|0] "" X + battery_BMS_a159_SW_HVP_ECU_Error = ((rx_frame.data.u8[5] >> 2) & (0x01U)); //42|1@1+ (1,0) [0|0] "" X + battery_BMS_a161_SW_DI_Open_Request = ((rx_frame.data.u8[5] >> 4) & (0x01U)); //44|1@1+ (1,0) [0|0] "" X + battery_BMS_a162_SW_No_Power_For_Support = ((rx_frame.data.u8[5] >> 5) & (0x01U)); //45|1@1+ (1,0) [0|0] "" X + battery_BMS_a163_SW_Contactor_Mismatch = ((rx_frame.data.u8[5] >> 6) & (0x01U)); //46|1@1+ (1,0) [0|0] "" X + battery_BMS_a164_SW_Uncontrolled_Regen = ((rx_frame.data.u8[5] >> 7) & (0x01U)); //47|1@1+ (1,0) [0|0] "" X + battery_BMS_a165_SW_Pack_Partial_Weld = (rx_frame.data.u8[6] & (0x01U)); //48|1@1+ (1,0) [0|0] "" X + battery_BMS_a166_SW_Pack_Full_Weld = ((rx_frame.data.u8[6] >> 1) & (0x01U)); //49|1@1+ (1,0) [0|0] "" X + battery_BMS_a167_SW_FC_Partial_Weld = ((rx_frame.data.u8[6] >> 2) & (0x01U)); //50|1@1+ (1,0) [0|0] "" X + battery_BMS_a168_SW_FC_Full_Weld = ((rx_frame.data.u8[6] >> 3) & (0x01U)); //51|1@1+ (1,0) [0|0] "" X + battery_BMS_a169_SW_FC_Pack_Weld = ((rx_frame.data.u8[6] >> 4) & (0x01U)); //52|1@1+ (1,0) [0|0] "" X + battery_BMS_a170_SW_Limp_Mode = ((rx_frame.data.u8[6] >> 5) & (0x01U)); //53|1@1+ (1,0) [0|0] "" X + battery_BMS_a171_SW_Stack_Voltage_Sense = ((rx_frame.data.u8[6] >> 6) & (0x01U)); //54|1@1+ (1,0) [0|0] "" X + battery_BMS_a174_SW_Charge_Failure = ((rx_frame.data.u8[7] >> 1) & (0x01U)); //57|1@1+ (1,0) [0|0] "" X + battery_BMS_a176_SW_GracefulPowerOff = ((rx_frame.data.u8[7] >> 3) & (0x01U)); //59|1@1+ (1,0) [0|0] "" X + battery_BMS_a179_SW_Hvp_12V_Fault = ((rx_frame.data.u8[7] >> 6) & (0x01U)); //62|1@1+ (1,0) [0|0] "" X + battery_BMS_a180_SW_ECU_reset_blocked = ((rx_frame.data.u8[7] >> 7) & (0x01U)); //63|1@1+ (1,0) [0|0] "" X + } + break; default: break; } } -#ifdef DOUBLE_BATTERY +#ifdef DOUBLE_BATTERY //Need to update battery2 -void receive_can_battery2(CAN_frame rx_frame) { +void handle_incoming_can_frame_battery2(CAN_frame rx_frame) { static uint8_t mux = 0; static uint16_t temp = 0; @@ -779,24 +1844,23 @@ void receive_can_battery2(CAN_frame rx_frame) { if (mux == 2) {} // Additional information needed on this mux, example frame: 02 26 02 20 02 80 00 00 doesn't change // older BMS <2021 without mux - //battery2_nominal_full_pack_energy = //BMS_nominalFullPackEnergy : 0|11@1+ (0.1,0) [0|204.6] "KWh" //((_d[1] & (0x07U)) << 8) | (_d[0] & (0xFFU)); - (((rx_frame.data.u8[1] & 0x07) << 8) | (rx_frame.data.u8[0])); //Example 752 (75.2kWh) - //battery2_nominal_energy_remaining = //BMS_nominalEnergyRemaining : 11|11@1+ (0.1,0) [0|204.6] "KWh" //((_d[2] & (0x3FU)) << 5) | ((_d[1] >> 3) & (0x1FU)); - (((rx_frame.data.u8[2] & 0x3F) << 5) | ((rx_frame.data.u8[1] & 0x1F) >> 3)); //Example 1247 * 0.1 = 124.7kWh - //battery2_expected_energy_remaining = //BMS_expectedEnergyRemaining : 22|11@1+ (0.1,0) [0|204.6] "KWh"// ((_d[4] & (0x01U)) << 10) | ((_d[3] & (0xFFU)) << 2) | ((_d[2] >> 6) & (0x03U)); - (((rx_frame.data.u8[4] & 0x01) << 10) | (rx_frame.data.u8[3] << 2) | - ((rx_frame.data.u8[2] & 0x03) >> 6)); //Example 622 (62.2kWh) - //battery2_ideal_energy_remaining = //BMS_idealEnergyRemaining : 33|11@1+ (0.1,0) [0|204.6] "KWh" //((_d[5] & (0x0FU)) << 7) | ((_d[4] >> 1) & (0x7FU)); - (((rx_frame.data.u8[5] & 0x0F) << 7) | ((rx_frame.data.u8[4] & 0x7F) >> 1)); //Example 311 * 0.1 = 31.1kWh - //battery2_energy_to_charge_complete = // BMS_energyToChargeComplete : 44|11@1+ (0.1,0) [0|204.6] "KWh"// ((_d[6] & (0x7FU)) << 4) | ((_d[5] >> 4) & (0x0FU)); - (((rx_frame.data.u8[6] & 0x7F) << 4) | ((rx_frame.data.u8[5] & 0x0F) << 4)); //Example 147 * 0.1 = 14.7kWh - //battery2_energy_buffer = //BMS_energyBuffer : 55|8@1+ (0.1,0) [0|25.4] "KWh"// ((_d[7] & (0x7FU)) << 1) | ((_d[6] >> 7) & (0x01U)); - (((rx_frame.data.u8[7] & 0x7F) << 1) | ((rx_frame.data.u8[6] & 0x01) >> 7)); //Example 1 * 0.1 = 0 - //battery2_full_charge_complete = //BMS_fullChargeComplete : 63|1@1+ (1,0) [0|1] ""//((_d[7] >> 7) & (0x01U)); - ((rx_frame.data.u8[7] & 0x01) >> 7); + battery2_nominal_full_pack_energy = //BMS_nominalFullPackEnergy : 0|11@1+ (0.1,0) [0|204.6] "KWh" //((_d[1] & (0x07U)) << 8) | (_d[0] & (0xFFU)); + (((rx_frame.data.u8[1] & 0x07) << 8) | (rx_frame.data.u8[0])); //Example 752 (75.2kWh) + battery2_nominal_energy_remaining = //BMS_nominalEnergyRemaining : 11|11@1+ (0.1,0) [0|204.6] "KWh" //((_d[2] & (0x3FU)) << 5) | ((_d[1] >> 3) & (0x1FU)); + (((rx_frame.data.u8[2] & 0x3F) << 5) | ((rx_frame.data.u8[1] & 0x1F) >> 3)); //Example 1247 * 0.1 = 124.7kWh + battery2_expected_energy_remaining = //BMS_expectedEnergyRemaining : 22|11@1+ (0.1,0) [0|204.6] "KWh"// ((_d[4] & (0x01U)) << 10) | ((_d[3] & (0xFFU)) << 2) | ((_d[2] >> 6) & (0x03U)); + (((rx_frame.data.u8[4] & 0x01) << 10) | (rx_frame.data.u8[3] << 2) | + ((rx_frame.data.u8[2] & 0x03) >> 6)); //Example 622 (62.2kWh) + battery2_ideal_energy_remaining = //BMS_idealEnergyRemaining : 33|11@1+ (0.1,0) [0|204.6] "KWh" //((_d[5] & (0x0FU)) << 7) | ((_d[4] >> 1) & (0x7FU)); + (((rx_frame.data.u8[5] & 0x0F) << 7) | ((rx_frame.data.u8[4] & 0x7F) >> 1)); //Example 311 * 0.1 = 31.1kWh + battery2_energy_to_charge_complete = // BMS_energyToChargeComplete : 44|11@1+ (0.1,0) [0|204.6] "KWh"// ((_d[6] & (0x7FU)) << 4) | ((_d[5] >> 4) & (0x0FU)); + (((rx_frame.data.u8[6] & 0x7F) << 4) | ((rx_frame.data.u8[5] & 0x0F) << 4)); //Example 147 * 0.1 = 14.7kWh + battery2_energy_buffer = //BMS_energyBuffer : 55|8@1+ (0.1,0) [0|25.4] "KWh"// ((_d[7] & (0x7FU)) << 1) | ((_d[6] >> 7) & (0x01U)); + (((rx_frame.data.u8[7] & 0x7F) << 1) | ((rx_frame.data.u8[6] & 0x01) >> 7)); //Example 1 * 0.1 = 0 + battery2_full_charge_complete = //BMS_fullChargeComplete : 63|1@1+ (1,0) [0|1] ""//((_d[7] >> 7) & (0x01U)); + ((rx_frame.data.u8[7] & 0x01) >> 7); break; - case 0x20A: - //Contactor state + case 0x20A: //522 HVP_contactorState: battery2_packContNegativeState = (rx_frame.data.u8[0] & 0x07); battery2_packContPositiveState = (rx_frame.data.u8[0] & 0x38) >> 3; battery2_contactor = (rx_frame.data.u8[1] & 0x0F); @@ -804,22 +1868,90 @@ void receive_can_battery2(CAN_frame rx_frame) { battery2_packCtrsClosingAllowed = (rx_frame.data.u8[4] & 0x08) >> 3; battery2_pyroTestInProgress = (rx_frame.data.u8[4] & 0x20) >> 5; battery2_hvil_status = (rx_frame.data.u8[5] & 0x0F); - //HVP_packCtrsOpenNowRequested : 33|1@1+ (1,0) [0|1] "" - //HVP_packCtrsOpenRequested : 34|1@1+ (1,0) [0|1] "" - //HVP_packCtrsRequestStatus : 30|2@1+ (1,0) [0|2] "" - //HVP_packCtrsResetRequestRequired : 32|1@1+ (1,0) [0|1] "" - //HVP_dcLinkAllowedToEnergize : 36|1@1+ (1,0) [0|1] "" Receiver - //HVP_fcContNegativeAuxOpen : 7|1@1+ (1,0) [0|1] "" Receiver - //HVP_fcContNegativeState : 12|3@1+ (1,0) [0|7] "" Receiver - //HVP_fcContPositiveAuxOpen : 6|1@1+ (1,0) [0|1] "" Receiver - //HVP_fcContPositiveState : 16|3@1+ (1,0) [0|7] "" Receiver - //HVP_fcContactorSetState : 19|4@1+ (1,0) [0|9] "" Receiver - //HVP_fcCtrsClosingAllowed : 29|1@1+ (1,0) [0|1] "" Receiver - //HVP_fcCtrsOpenNowRequested : 27|1@1+ (1,0) [0|1] "" Receiver - //HVP_fcCtrsOpenRequested : 28|1@1+ (1,0) [0|1] "" Receiver - //HVP_fcCtrsRequestStatus : 24|2@1+ (1,0) [0|2] "" Receiver - //HVP_fcCtrsResetRequestRequired : 26|1@1+ (1,0) [0|1] "" Receiver - //HVP_fcLinkAllowedToEnergize : 44|2@1+ (1,0) [0|2] "" Receiver + battery2_packCtrsOpenNowRequested = + ((rx_frame.data.u8[4] >> 1) & (0x01U)); //33|1@1+ (1,0) [0|1] //to datalayer_extended + battery2_packCtrsOpenRequested = + ((rx_frame.data.u8[4] >> 2) & (0x01U)); //34|1@1+ (1,0) [0|1] //to datalayer_extended + battery2_packCtrsRequestStatus = + ((rx_frame.data.u8[3] >> 6) & (0x03U)); //30|2@1+ (1,0) [0|2] //to datalayer_extended + battery2_packCtrsResetRequestRequired = + (rx_frame.data.u8[4] & (0x01U)); //32|1@1+ (1,0) [0|1] //to datalayer_extended + battery2_dcLinkAllowedToEnergize = + ((rx_frame.data.u8[4] >> 4) & (0x01U)); //36|1@1+ (1,0) [0|1] //to datalayer_extended + battery2_fcContNegativeAuxOpen = ((rx_frame.data.u8[0] >> 7) & (0x01U)); //7|1@1+ (1,0) [0|1] "" Receiver + battery2_fcContNegativeState = ((rx_frame.data.u8[1] >> 4) & (0x07U)); //12|3@1+ (1,0) [0|7] "" Receiver + battery2_fcContPositiveAuxOpen = ((rx_frame.data.u8[0] >> 6) & (0x01U)); //6|1@1+ (1,0) [0|1] "" Receiver + battery2_fcContPositiveState = (rx_frame.data.u8[2] & (0x07U)); //16|3@1+ (1,0) [0|7] "" Receiver + battery2_fcContactorSetState = ((rx_frame.data.u8[2] >> 3) & (0x0FU)); //19|4@1+ (1,0) [0|9] "" Receiver + battery2_fcCtrsClosingAllowed = ((rx_frame.data.u8[3] >> 5) & (0x01U)); //29|1@1+ (1,0) [0|1] "" Receiver + battery2_fcCtrsOpenNowRequested = ((rx_frame.data.u8[3] >> 3) & (0x01U)); //27|1@1+ (1,0) [0|1] "" Receiver + battery2_fcCtrsOpenRequested = ((rx_frame.data.u8[3] >> 4) & (0x01U)); //28|1@1+ (1,0) [0|1] "" Receiver + battery2_fcCtrsRequestStatus = (rx_frame.data.u8[3] & (0x03U)); //24|2@1+ (1,0) [0|2] "" Receiver + battery2_fcCtrsResetRequestRequired = ((rx_frame.data.u8[3] >> 2) & (0x01U)); //26|1@1+ (1,0) [0|1] "" Receiver + battery2_fcLinkAllowedToEnergize = ((rx_frame.data.u8[5] >> 4) & (0x03U)); //44|2@1+ (1,0) [0|2] "" Receiver + break; + case 0x212: //530 BMS_status: 8 + battery2_BMS_hvacPowerRequest = (rx_frame.data.u8[0] & (0x01U)); + battery2_BMS_notEnoughPowerForDrive = ((rx_frame.data.u8[0] >> 1) & (0x01U)); + battery2_BMS_notEnoughPowerForSupport = ((rx_frame.data.u8[0] >> 2) & (0x01U)); + battery2_BMS_preconditionAllowed = ((rx_frame.data.u8[0] >> 3) & (0x01U)); + battery2_BMS_updateAllowed = ((rx_frame.data.u8[0] >> 4) & (0x01U)); + battery2_BMS_activeHeatingWorthwhile = ((rx_frame.data.u8[0] >> 5) & (0x01U)); + battery2_BMS_cpMiaOnHvs = ((rx_frame.data.u8[0] >> 6) & (0x01U)); + battery2_BMS_contactorState = + (rx_frame.data.u8[1] & + (0x07U)); //0 "SNA" 1 "OPEN" 2 "OPENING" 3 "CLOSING" 4 "CLOSED" 5 "WELDED" 6 "BLOCKED" ; + battery2_BMS_state = + ((rx_frame.data.u8[1] >> 3) & + (0x0FU)); //0 "STANDBY" 1 "DRIVE" 2 "SUPPORT" 3 "CHARGE" 4 "FEIM" 5 "CLEAR_FAULT" 6 "FAULT" 7 "WELD" 8 "TEST" 9 "SNA" ; + battery2_BMS_hvState = + (rx_frame.data.u8[2] & + (0x07U)); //0 "DOWN" 1 "COMING_UP" 2 "GOING_DOWN" 3 "UP_FOR_DRIVE" 4 "UP_FOR_CHARGE" 5 "UP_FOR_DC_CHARGE" 6 "UP" ; + battery2_BMS_isolationResistance = + ((rx_frame.data.u8[3] & (0x1FU)) << 5) | + ((rx_frame.data.u8[2] >> 3) & (0x1FU)); //19|10@1+ (10,0) [0|0] "kOhm"/to datalayer_extended + battery2_BMS_chargeRequest = ((rx_frame.data.u8[3] >> 5) & (0x01U)); + battery2_BMS_keepWarmRequest = ((rx_frame.data.u8[3] >> 6) & (0x01U)); + battery2_BMS_uiChargeStatus = + (rx_frame.data.u8[4] & + (0x07U)); // 0 "DISCONNECTED" 1 "NO_POWER" 2 "ABOUT_TO_CHARGE" 3 "CHARGING" 4 "CHARGE_COMPLETE" 5 "CHARGE_STOPPED" ; + battery2_BMS_diLimpRequest = ((rx_frame.data.u8[4] >> 3) & (0x01U)); + battery2_BMS_okToShipByAir = ((rx_frame.data.u8[4] >> 4) & (0x01U)); + battery2_BMS_okToShipByLand = ((rx_frame.data.u8[4] >> 5) & (0x01U)); + battery2_BMS_chgPowerAvailable = ((rx_frame.data.u8[6] & (0x01U)) << 10) | + ((rx_frame.data.u8[5] & (0xFFU)) << 2) | + ((rx_frame.data.u8[4] >> 6) & (0x03U)); //38|11@1+ (0.125,0) [0|0] "kW" + battery2_BMS_chargeRetryCount = ((rx_frame.data.u8[6] >> 1) & (0x0FU)); + battery2_BMS_pcsPwmEnabled = ((rx_frame.data.u8[6] >> 5) & (0x01U)); + battery2_BMS_ecuLogUploadRequest = ((rx_frame.data.u8[6] >> 6) & (0x03U)); + battery2_BMS_minPackTemperature = (rx_frame.data.u8[7] & (0xFFU)); //56|8@1+ (0.5,-40) [0|0] "DegC + break; + case 0x224: //548 PCS_dcdcStatus: + battery2_PCS_dcdcPrechargeStatus = (rx_frame.data.u8[0] & (0x03U)); //0 "IDLE" 1 "ACTIVE" 2 "FAULTED" ; + battery2_PCS_dcdc12VSupportStatus = ((rx_frame.data.u8[0] >> 2) & (0x03U)); //0 "IDLE" 1 "ACTIVE" 2 "FAULTED" + battery2_PCS_dcdcHvBusDischargeStatus = ((rx_frame.data.u8[0] >> 4) & (0x03U)); //0 "IDLE" 1 "ACTIVE" 2 "FAULTED" + battery2_PCS_dcdcMainState = + ((rx_frame.data.u8[1] & (0x03U)) << 2) | + ((rx_frame.data.u8[0] >> 6) & + (0x03U)); //0 "STANDBY" 1 "12V_SUPPORT_ACTIVE" 2 "PRECHARGE_STARTUP" 3 "PRECHARGE_ACTIVE" 4 "DIS_HVBUS_ACTIVE" 5 "SHUTDOWN" 6 "FAULTED" ; + battery2_PCS_dcdcSubState = + ((rx_frame.data.u8[1] >> 2) & + (0x1FU)); //0 "PWR_UP_INIT" 1 "STANDBY" 2 "12V_SUPPORT_ACTIVE" 3 "DIS_HVBUS" 4 "PCHG_FAST_DIS_HVBUS" 5 "PCHG_SLOW_DIS_HVBUS" 6 "PCHG_DWELL_CHARGE" 7 "PCHG_DWELL_WAIT" 8 "PCHG_DI_RECOVERY_WAIT" 9 "PCHG_ACTIVE" 10 "PCHG_FLT_FAST_DIS_HVBUS" 11 "SHUTDOWN" 12 "12V_SUPPORT_FAULTED" 13 "DIS_HVBUS_FAULTED" 14 "PCHG_FAULTED" 15 "CLEAR_FAULTS" 16 "FAULTED" 17 "NUM" ; + battery2_PCS_dcdcFaulted = ((rx_frame.data.u8[1] >> 7) & (0x01U)); + battery2_PCS_dcdcOutputIsLimited = ((rx_frame.data.u8[3] >> 4) & (0x01U)); + battery2_PCS_dcdcMaxOutputCurrentAllowed = ((rx_frame.data.u8[5] & (0x01U)) << 11) | + ((rx_frame.data.u8[4] & (0xFFU)) << 3) | + ((rx_frame.data.u8[3] >> 5) & (0x07U)); //29|12@1+ (0.1,0) [0|0] "A" + battery2_PCS_dcdcPrechargeRtyCnt = ((rx_frame.data.u8[5] >> 1) & (0x07U)); + battery2_PCS_dcdc12VSupportRtyCnt = ((rx_frame.data.u8[5] >> 4) & (0x0FU)); + battery2_PCS_dcdcDischargeRtyCnt = (rx_frame.data.u8[6] & (0x0FU)); + battery2_PCS_dcdcPwmEnableLine = ((rx_frame.data.u8[6] >> 4) & (0x01U)); + battery2_PCS_dcdcSupportingFixedLvTarget = ((rx_frame.data.u8[6] >> 5) & (0x01U)); + battery2_PCS_ecuLogUploadRequest = ((rx_frame.data.u8[6] >> 6) & (0x03U)); + battery2_PCS_dcdcPrechargeRestartCnt = (rx_frame.data.u8[7] & (0x07U)); + battery2_PCS_dcdcInitialPrechargeSubState = + ((rx_frame.data.u8[7] >> 3) & + (0x1FU)); //0 "PWR_UP_INIT" 1 "STANDBY" 2 "12V_SUPPORT_ACTIVE" 3 "DIS_HVBUS" 4 "PCHG_FAST_DIS_HVBUS" 5 "PCHG_SLOW_DIS_HVBUS" 6 "PCHG_DWELL_CHARGE" 7 "PCHG_DWELL_WAIT" 8 "PCHG_DI_RECOVERY_WAIT" 9 "PCHG_ACTIVE" 10 "PCHG_FLT_FAST_DIS_HVBUS" 11 "SHUTDOWN" 12 "12V_SUPPORT_FAULTED" 13 "DIS_HVBUS_FAULTED" 14 "PCHG_FAULTED" 15 "CLEAR_FAULTS" 16 "FAULTED" 17 "NUM" ; break; case 0x252: //Limits @@ -842,10 +1974,8 @@ void receive_can_battery2(CAN_frame rx_frame) { if (battery2_charge_time_remaining == 4095) { battery2_charge_time_remaining = 0; } - break; - case 0x3D2: - // total charge/discharge kwh + case 0x3D2: // total charge/discharge kwh battery2_total_discharge = ((rx_frame.data.u8[3] << 24) | (rx_frame.data.u8[2] << 16) | (rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]) * 0.001; @@ -853,8 +1983,7 @@ void receive_can_battery2(CAN_frame rx_frame) { rx_frame.data.u8[4]) * 0.001; break; - case 0x332: - //min/max hist values + case 0x332: //min/max hist values //BattBrickMinMax: mux = (rx_frame.data.u8[0] & 0x03); if (mux == 1) //Cell voltages @@ -865,14 +1994,118 @@ void receive_can_battery2(CAN_frame rx_frame) { temp = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]); temp = (temp & 0xFFF); battery2_cell_min_v = temp * 2; - battery2_max_vno = 1 + (rx_frame.data.u8[4] & 0x7F); //This cell has highest voltage - battery2_min_vno = 1 + (rx_frame.data.u8[5] & 0x7F); //This cell has lowest voltage + battery2_cellvoltagesRead = true; + //BattBrickVoltageMax m1 : 2|12@1+ (0.002,0) [0|0] "V" Receiver ((_d[1] & (0x3FU)) << 6) | ((_d[0] >> 2) & (0x3FU)); + battery2_BrickVoltageMax = + ((rx_frame.data.u8[1] & (0x3F)) << 6) | ((rx_frame.data.u8[0] >> 2) & (0x3F)); //to datalayer_extended + //BattBrickVoltageMin m1 : 16|12@1+ (0.002,0) [0|0] "V" Receiver ((_d[3] & (0x0FU)) << 8) | (_d[2] & (0xFFU)); + battery2_BrickVoltageMin = + ((rx_frame.data.u8[3] & (0x0F)) << 8) | (rx_frame.data.u8[2] & (0xFF)); //to datalayer_extended + //BattBrickVoltageMaxNum m1 : 32|7@1+ (1,1) [0|0] "" Receiver + battery2_BrickVoltageMaxNum = 1 + (rx_frame.data.u8[4] & 0x7F); //This cell has highest voltage + battery2_BrickVoltageMinNum = 1 + (rx_frame.data.u8[5] & 0x7F); //This cell has lowest voltage } if (mux == 0) //Temperature sensors { battery2_max_temp = (rx_frame.data.u8[2] * 5) - 400; //Temperature values have 40.0*C offset, 0.5*C /bit battery2_min_temp = (rx_frame.data.u8[3] * 5) - 400; //Multiply by 5 and remove offset to get C+1 (0x61*5=485-400=8.5*C) + //BattBrickTempMaxNum m0 : 2|4@1+ (1,0) [0|0] "" ((_d[0] >> 2) & (0x0FU)); + battery2_BrickTempMaxNum = ((rx_frame.data.u8[0] >> 2) & (0x0F)); //to datalayer_extended + //BattBrickTempMinNum m0 : 8|4@1+ (1,0) [0|0] "" (_d[1] & (0x0FU)); + battery2_BrickTempMinNum = (rx_frame.data.u8[1] & (0x0F)); //to datalayer_extended + //BattBrickModelTMax m0 : 32|8@1+ (0.5,-40) [0|0] "C" (_d[4] & (0xFFU)); + battery2_BrickModelTMax = (rx_frame.data.u8[4] & (0xFFU)); //to datalayer_extended + //BattBrickModelTMin m0 : 40|8@1+ (0.5,-40) [0|0] "C" (_d[5] & (0xFFU)); + battery2_BrickModelTMin = (rx_frame.data.u8[5] & (0xFFU)); //to datalayer_extended + } + break; + case 0x312: // 786 BMS_thermalStatus + BMS2_powerDissipation = + ((rx_frame.data.u8[1] & (0x03U)) << 8) | (rx_frame.data.u8[0] & (0xFFU)); //0|10@1+ (0.02,0) [0|0] "kW" + BMS2_flowRequest = ((rx_frame.data.u8[2] & (0x01U)) << 6) | + ((rx_frame.data.u8[1] >> 2) & (0x3FU)); //10|7@1+ (0.3,0) [0|0] "LPM" + BMS2_inletActiveCoolTargetT = ((rx_frame.data.u8[3] & (0x03U)) << 7) | + ((rx_frame.data.u8[2] >> 1) & (0x7FU)); //17|9@1+ (0.25,-25) [0|0] "DegC" + BMS2_inletPassiveTargetT = ((rx_frame.data.u8[4] & (0x07U)) << 6) | + ((rx_frame.data.u8[3] >> 2) & (0x3FU)); //26|9@1+ (0.25,-25) [0|0] "DegC" X + BMS2_inletActiveHeatTargetT = ((rx_frame.data.u8[5] & (0x0FU)) << 5) | + ((rx_frame.data.u8[4] >> 3) & (0x1FU)); //35|9@1+ (0.25,-25) [0|0] "DegC" + BMS2_packTMin = ((rx_frame.data.u8[6] & (0x1FU)) << 4) | + ((rx_frame.data.u8[5] >> 4) & (0x0FU)); //44|9@1+ (0.25,-25) [-25|100] "DegC" + BMS2_packTMax = ((rx_frame.data.u8[7] & (0x3FU)) << 3) | + ((rx_frame.data.u8[6] >> 5) & (0x07U)); //53|9@1+ (0.25,-25) [-25|100] "DegC" + BMS2_pcsNoFlowRequest = ((rx_frame.data.u8[7] >> 6) & (0x01U)); // 62|1@1+ (1,0) [0|0] "" + BMS2_noFlowRequest = ((rx_frame.data.u8[7] >> 7) & (0x01U)); //63|1@1+ (1,0) [0|0] "" + break; + case 0x2A4: //676 PCS_thermalStatus + PCS2_chgPhATemp = + ((rx_frame.data.u8[1] & (0x07U)) << 8) | (rx_frame.data.u8[0] & (0xFFU)); //0|11@1- (0.1,40) [0|0] "C + PCS2_chgPhBTemp = + ((rx_frame.data.u8[2] & (0x3FU)) << 5) | ((rx_frame.data.u8[1] >> 3) & (0x1FU)); //11|11@1- (0.1,40) [0|0] "C + PCS2_chgPhCTemp = + ((rx_frame.data.u8[4] & (0x07U)) << 8) | (rx_frame.data.u8[3] & (0xFFU)); //24|11@1- (0.1,40) [0|0] "C" + PCS2_dcdcTemp = ((rx_frame.data.u8[5] & (0x3FU)) << 5) | + ((rx_frame.data.u8[4] >> 3) & (0x1FU)); //35|11@1- (0.1,40) [0|0] "C" + PCS2_ambientTemp = + ((rx_frame.data.u8[7] & (0x07U)) << 8) | (rx_frame.data.u8[6] & (0xFFU)); //48|11@1- (0.1,40) [0|0] "C" + break; + case 0x2C4: // 708 PCS_logging: not all frames are listed, just ones relating to dcdc + mux = (rx_frame.data.u8[0] & (0x1FU)); + //PCS_logMessageSelect = (rx_frame.data.u8[0] & (0x1FU)); //0|5@1+ (1,0) [0|0] "" + if (mux == 6) { + PCS2_dcdcMaxLvOutputCurrent = ((rx_frame.data.u8[4] & (0xFFU)) << 4) | + ((rx_frame.data.u8[3] >> 4) & (0x0FU)); //m6 : 28|12@1+ (0.1,0) [0|0] "A" X + PCS2_dcdcCurrentLimit = ((rx_frame.data.u8[6] & (0x0FU)) << 8) | + (rx_frame.data.u8[5] & (0xFFU)); //m6 : 40|12@1+ (0.1,0) [0|0] "A" X + PCS2_dcdcLvOutputCurrentTempLimit = + ((rx_frame.data.u8[7] & (0xFFU)) << 4) | + ((rx_frame.data.u8[6] >> 4) & (0x0FU)); //m6 : 52|12@1+ (0.1,0) [0|0] "A" X + } + if (mux == 7) { + PCS2_dcdcUnifiedCommand = ((rx_frame.data.u8[1] & (0x7FU)) << 3) | + ((rx_frame.data.u8[0] >> 5) & (0x07U)); //m7 : 5|10@1+ (0.001,0) [0|0] "1" X + PCS2_dcdcCLAControllerOutput = ((rx_frame.data.u8[3] & (0x03U)) << 8) | + (rx_frame.data.u8[2] & (0xFFU)); //m7 : 16|10@1+ (0.001,0) [0|0] "1" X + PCS2_dcdcTankVoltage = ((rx_frame.data.u8[4] & (0x1FU)) << 6) | + ((rx_frame.data.u8[3] >> 2) & (0x3FU)); //m7 : 26|11@1- (1,0) [0|0] "V" X + PCS2_dcdcTankVoltageTarget = ((rx_frame.data.u8[5] & (0x7FU)) << 3) | + ((rx_frame.data.u8[4] >> 5) & (0x07U)); // m7 : 37|10@1+ (1,0) [0|0] "V" X + PCS2_dcdcClaCurrentFreq = ((rx_frame.data.u8[7] & (0x0FU)) << 8) | + (rx_frame.data.u8[6] & (0xFFU)); //P m7 : 48|12@1+ (0.0976563,0) [0|0] "kHz" X + } + if (mux == 8) { + PCS2_dcdcTCommMeasured = ((rx_frame.data.u8[2] & (0xFFU)) << 8) | + (rx_frame.data.u8[1] & (0xFFU)); // m8 : 8|16@1- (0.00195313,0) [0|0] "us" X + PCS2_dcdcShortTimeUs = ((rx_frame.data.u8[4] & (0xFFU)) << 8) | + (rx_frame.data.u8[3] & (0xFFU)); // m8 : 24|16@1+ (0.000488281,0) [0|0] "us" X + PCS2_dcdcHalfPeriodUs = ((rx_frame.data.u8[6] & (0xFFU)) << 8) | + (rx_frame.data.u8[5] & (0xFFU)); // m8 : 40|16@1+ (0.000488281,0) [0|0] "us" X + } + if (mux == 18) { + PCS2_dcdcIntervalMaxFrequency = ((rx_frame.data.u8[2] & (0x0FU)) << 8) | + (rx_frame.data.u8[1] & (0xFFU)); // m18 : 8|12@1+ (1,0) [0|0] "kHz" X + PCS2_dcdcIntervalMaxHvBusVolt = ((rx_frame.data.u8[4] & (0x1FU)) << 8) | + (rx_frame.data.u8[3] & (0xFFU)); //m18 : 24|13@1+ (0.1,0) [0|0] "V" X + PCS2_dcdcIntervalMaxLvBusVolt = ((rx_frame.data.u8[5] & (0x3FU)) << 3) | + ((rx_frame.data.u8[4] >> 5) & (0x07U)); // m18 : 37|9@1+ (0.1,0) [0|0] "V" X + PCS2_dcdcIntervalMaxLvOutputCurr = ((rx_frame.data.u8[7] & (0x0FU)) << 8) | + (rx_frame.data.u8[6] & (0xFFU)); //m18 : 48|12@1+ (1,0) [0|0] "A" X + } + if (mux == 19) { + PCS2_dcdcIntervalMinFrequency = ((rx_frame.data.u8[2] & (0x0FU)) << 8) | + (rx_frame.data.u8[1] & (0xFFU)); //m19 : 8|12@1+ (1,0) [0|0] "kHz" X + PCS2_dcdcIntervalMinHvBusVolt = ((rx_frame.data.u8[4] & (0x1FU)) << 8) | + (rx_frame.data.u8[3] & (0xFFU)); //m19 : 24|13@1+ (0.1,0) [0|0] "V" X + PCS2_dcdcIntervalMinLvBusVolt = ((rx_frame.data.u8[5] & (0x3FU)) << 3) | + ((rx_frame.data.u8[4] >> 5) & (0x07U)); //m19 : 37|9@1+ (0.1,0) [0|0] "V" X + PCS2_dcdcIntervalMinLvOutputCurr = ((rx_frame.data.u8[7] & (0x0FU)) << 8) | + (rx_frame.data.u8[6] & (0xFFU)); // m19 : 48|12@1+ (1,0) [0|0] "A" X + } + if (mux == 22) { + PCS2_dcdc12vSupportLifetimekWh = ((rx_frame.data.u8[3] & (0xFFU)) << 16) | + ((rx_frame.data.u8[2] & (0xFFU)) << 8) | + (rx_frame.data.u8[1] & (0xFFU)); // m22 : 8|24@1+ (0.01,0) [0|0] "kWh" X } break; case 0x401: // Cell stats @@ -943,6 +2176,104 @@ void receive_can_battery2(CAN_frame rx_frame) { battery2_reservedConfig = (rx_frame.data.u8[1] & (0x1F)); } break; + case 0x7AA: //1962 HVP_debugMessage: + mux = (rx_frame.data.u8[0] & (0x0FU)); + //HVP_debugMessageMultiplexer = (rx_frame.data.u8[0] & (0x0FU)); //0|4@1+ (1,0) [0|6] "" + if (mux == 0) { + HVP2_gpioPassivePyroDepl = ((rx_frame.data.u8[0] >> 4) & (0x01U)); //: 4|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioPyroIsoEn = ((rx_frame.data.u8[0] >> 5) & (0x01U)); //: 5|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioCpFaultIn = ((rx_frame.data.u8[0] >> 6) & (0x01U)); //: 6|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioPackContPowerEn = ((rx_frame.data.u8[0] >> 7) & (0x01U)); //: 7|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioHvCablesOk = (rx_frame.data.u8[1] & (0x01U)); //: 8|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioHvpSelfEnable = ((rx_frame.data.u8[1] >> 1) & (0x01U)); //: 9|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioLed = ((rx_frame.data.u8[1] >> 2) & (0x01U)); //: 10|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioCrashSignal = ((rx_frame.data.u8[1] >> 3) & (0x01U)); //: 11|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioShuntDataReady = ((rx_frame.data.u8[1] >> 4) & (0x01U)); //: 12|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioFcContPosAux = ((rx_frame.data.u8[1] >> 5) & (0x01U)); //: 13|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioFcContNegAux = ((rx_frame.data.u8[1] >> 6) & (0x01U)); //: 14|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioBmsEout = ((rx_frame.data.u8[1] >> 7) & (0x01U)); //: 15|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioCpFaultOut = (rx_frame.data.u8[2] & (0x01U)); //: 16|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioPyroPor = ((rx_frame.data.u8[2] >> 1) & (0x01U)); //: 17|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioShuntEn = ((rx_frame.data.u8[2] >> 2) & (0x01U)); //: 18|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioHvpVerEn = ((rx_frame.data.u8[2] >> 3) & (0x01U)); //: 19|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioPackCoontPosFlywheel = ((rx_frame.data.u8[2] >> 4) & (0x01U)); //: 20|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioCpLatchEnable = ((rx_frame.data.u8[2] >> 5) & (0x01U)); //: 21|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioPcsEnable = ((rx_frame.data.u8[2] >> 6) & (0x01U)); //: 22|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioPcsDcdcPwmEnable = ((rx_frame.data.u8[2] >> 7) & (0x01U)); //: 23|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioPcsChargePwmEnable = (rx_frame.data.u8[3] & (0x01U)); //: 24|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioFcContPowerEnable = ((rx_frame.data.u8[3] >> 1) & (0x01U)); //: 25|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioHvilEnable = ((rx_frame.data.u8[3] >> 2) & (0x01U)); //: 26|1@1+ (1,0) [0|1] "" Receiver + HVP2_gpioSecDrdy = ((rx_frame.data.u8[3] >> 3) & (0x01U)); //: 27|1@1+ (1,0) [0|1] "" Receiver + HVP2_hvp1v5Ref = ((rx_frame.data.u8[4] & (0xFFU)) << 4) | + ((rx_frame.data.u8[3] >> 4) & (0x0FU)); //: 28|12@1+ (0.1,0) [0|3] "V" Receiver + HVP2_shuntCurrentDebug = ((rx_frame.data.u8[6] & (0xFFU)) << 8) | + (rx_frame.data.u8[5] & (0xFFU)); //: 40|16@1- (0.1,0) [-3276.8|3276.7] "A" Receiver + HVP2_packCurrentMia = (rx_frame.data.u8[7] & (0x01U)); //: 56|1@1+ (1,0) [0|1] "" Receiver + HVP2_auxCurrentMia = ((rx_frame.data.u8[7] >> 1) & (0x01U)); //: 57|1@1+ (1,0) [0|1] "" Receiver + HVP2_currentSenseMia = ((rx_frame.data.u8[7] >> 2) & (0x03U)); //: 58|1@1+ (1,0) [0|1] "" Receiver + HVP2_shuntRefVoltageMismatch = ((rx_frame.data.u8[7] >> 3) & (0x01U)); //: 59|1@1+ (1,0) [0|1] "" Receiver + HVP2_shuntThermistorMia = ((rx_frame.data.u8[7] >> 4) & (0x01U)); //: 60|1@1+ (1,0) [0|1] "" Receiver + HVP2_shuntHwMia = ((rx_frame.data.u8[7] >> 5) & (0x01U)); //: 61|1@1+ (1,0) [0|1] "" Receiver + } + if (mux == 1) { + HVP2_dcLinkVoltage = ((rx_frame.data.u8[2] & (0xFFU)) << 8) | + (rx_frame.data.u8[1] & (0xFFU)); //: 8|16@1- (0.1,0) [-3276.8|3276.7] "V" Receiver + HVP2_packVoltage = ((rx_frame.data.u8[4] & (0xFFU)) << 8) | + (rx_frame.data.u8[3] & (0xFFU)); //: 24|16@1- (0.1,0) [-3276.8|3276.7] "V" Receiver + HVP2_fcLinkVoltage = ((rx_frame.data.u8[6] & (0xFFU)) << 8) | + (rx_frame.data.u8[5] & (0xFFU)); //: 40|16@1- (0.1,0) [-3276.8|3276.7] "V" Receiver + } + if (mux == 2) { + HVP2_packContVoltage = ((rx_frame.data.u8[1] & (0xFFU)) << 4) | + ((rx_frame.data.u8[0] >> 4) & (0x0FU)); //: 4|12@1+ (0.1,0) [0|30] "V" Receiver + HVP2_packNegativeV = ((rx_frame.data.u8[3] & (0xFFU)) << 8) | + (rx_frame.data.u8[2] & (0xFFU)); //: 16|16@1- (0.1,0) [-550|550] "V" Receiver + HVP2_packPositiveV = ((rx_frame.data.u8[5] & (0xFFU)) << 8) | + (rx_frame.data.u8[4] & (0xFFU)); //: 32|16@1- (0.1,0) [-550|550] "V" Receiver + HVP2_pyroAnalog = ((rx_frame.data.u8[7] & (0x0FU)) << 8) | + (rx_frame.data.u8[6] & (0xFFU)); //: 48|12@1+ (0.1,0) [0|3] "V" Receiver + } + if (mux == 3) { + HVP2_dcLinkNegativeV = ((rx_frame.data.u8[2] & (0xFFU)) << 8) | + (rx_frame.data.u8[1] & (0xFFU)); //: 8|16@1- (0.1,0) [-550|550] "V" Receiver + HVP2_dcLinkPositiveV = ((rx_frame.data.u8[4] & (0xFFU)) << 8) | + (rx_frame.data.u8[3] & (0xFFU)); //: 24|16@1- (0.1,0) [-550|550] "V" Receiver + HVP2_fcLinkNegativeV = ((rx_frame.data.u8[6] & (0xFFU)) << 8) | + (rx_frame.data.u8[5] & (0xFFU)); //: 40|16@1- (0.1,0) [-550|550] "V" Receiver + } + if (mux == 4) { + HVP2_fcContCoilCurrent = ((rx_frame.data.u8[1] & (0xFFU)) << 4) | + ((rx_frame.data.u8[0] >> 4) & (0x0FU)); //: 4|12@1+ (0.1,0) [0|7.5] "A" Receiver + HVP2_fcContVoltage = ((rx_frame.data.u8[3] & (0x0FU)) << 8) | + (rx_frame.data.u8[2] & (0xFFU)); //: 16|12@1+ (0.1,0) [0|30] "V" Receiver + HVP2_hvilInVoltage = ((rx_frame.data.u8[4] & (0xFFU)) << 4) | + ((rx_frame.data.u8[3] >> 4) & (0x0FU)); //: 28|12@1+ (0.1,0) [0|30] "V" Receiver + HVP2_hvilOutVoltage = ((rx_frame.data.u8[6] & (0x0FU)) << 8) | + (rx_frame.data.u8[5] & (0xFFU)); //: 40|12@1+ (0.1,0) [0|30] "V" Receiver + } + if (mux == 5) { + HVP2_fcLinkPositiveV = ((rx_frame.data.u8[2] & (0xFFU)) << 8) | + (rx_frame.data.u8[1] & (0xFFU)); //: 8|16@1- (0.1,0) [-550|550] "V" Receiver + HVP2_packContCoilCurrent = ((rx_frame.data.u8[4] & (0x0FU)) << 8) | + (rx_frame.data.u8[3] & (0xFFU)); //: 24|12@1+ (0.1,0) [0|7.5] "A" Receiver + HVP2_battery12V = ((rx_frame.data.u8[5] & (0xFFU)) << 4) | + ((rx_frame.data.u8[4] >> 4) & (0x0FU)); //: 36|12@1+ (0.1,0) [0|30] "V" Receiver + HVP2_shuntRefVoltageDbg = + ((rx_frame.data.u8[7] & (0xFFU)) << 8) | + (rx_frame.data.u8[6] & (0xFFU)); //: 48|16@1- (0.001,0) [-32.768|32.767] "V" Receiver + } + if (mux == 6) { + HVP2_shuntAuxCurrentDbg = ((rx_frame.data.u8[2] & (0xFFU)) << 8) | + (rx_frame.data.u8[1] & (0xFFU)); //: 8|16@1- (0.1,0) [-3276.8|3276.7] "A" Receiver + HVP2_shuntBarTempDbg = ((rx_frame.data.u8[4] & (0xFFU)) << 8) | + (rx_frame.data.u8[3] & (0xFFU)); //: 24|16@1- (0.01,0) [-327.67|327.67] "C" Receiver + HVP2_shuntAsicTempDbg = ((rx_frame.data.u8[6] & (0xFFU)) << 8) | + (rx_frame.data.u8[5] & (0xFFU)); //: 40|16@1- (0.01,0) [-327.67|327.67] "C" Receiver + HVP2_shuntAuxCurrentStatus = (rx_frame.data.u8[7] & (0x03U)); //: 56|2@1+ (1,0) [0|3] "" Receiver + HVP2_shuntBarTempStatus = ((rx_frame.data.u8[7] >> 2) & (0x03U)); //: 58|2@1+ (1,0) [0|3] "" Receiver + HVP2_shuntAsicTempStatus = ((rx_frame.data.u8[7] >> 4) & (0x03U)); //: 60|2@1+ (1,0) [0|3] "" Receiver + } + break; case 0x3aa: //HVP_alertMatrix1 battery2_WatchdogReset = (rx_frame.data.u8[0] & 0x01); battery2_PowerLossReset = ((rx_frame.data.u8[0] & 0x02) >> 1); @@ -996,6 +2327,110 @@ void receive_can_battery2(CAN_frame rx_frame) { battery2_fcCtrCloseFailed = ((rx_frame.data.u8[6] & 0x02) >> 1); battery2_shuntThermistorMia = ((rx_frame.data.u8[6] & 0x04) >> 2); break; + case 0x320: //800 BMS_alertMatrix //BMS_alertMatrix 800 BMS_alertMatrix: 8 VEH + mux = (rx_frame.data.u8[0] & (0x0F)); + if (mux == 0) + ; + { //mux0 + battery2_BMS_matrixIndex = (rx_frame.data.u8[0] & (0x0F)); // 0|4@1+ (1,0) [0|0] "" X + battery2_BMS_a017_SW_Brick_OV = ((rx_frame.data.u8[2] >> 4) & (0x01)); //20|1@1+ (1,0) [0|0] "" X + battery2_BMS_a018_SW_Brick_UV = ((rx_frame.data.u8[2] >> 5) & (0x01)); //21|1@1+ (1,0) [0|0] "" X + battery2_BMS_a019_SW_Module_OT = ((rx_frame.data.u8[2] >> 6) & (0x01)); //22|1@1+ (1,0) [0|0] "" X + battery2_BMS_a021_SW_Dr_Limits_Regulation = (rx_frame.data.u8[3] & (0x01U)); //24|1@1+ (1,0) [0|0] "" X + battery2_BMS_a022_SW_Over_Current = ((rx_frame.data.u8[3] >> 1) & (0x01U)); //25|1@1+ (1,0) [0|0] "" X + battery2_BMS_a023_SW_Stack_OV = ((rx_frame.data.u8[3] >> 2) & (0x01U)); //26|1@1+ (1,0) [0|0] "" X + battery2_BMS_a024_SW_Islanded_Brick = ((rx_frame.data.u8[3] >> 3) & (0x01U)); //27|1@1+ (1,0) [0|0] "" X + battery2_BMS_a025_SW_PwrBalance_Anomaly = ((rx_frame.data.u8[3] >> 4) & (0x01U)); //28|1@1+ (1,0) [0|0] "" X + battery2_BMS_a026_SW_HFCurrent_Anomaly = ((rx_frame.data.u8[3] >> 5) & (0x01U)); //29|1@1+ (1,0) [0|0] "" X + battery2_BMS_a034_SW_Passive_Isolation = ((rx_frame.data.u8[4] >> 5) & (0x01U)); //37|1@1+ (1,0) [0|0] "" X ? + battery2_BMS_a035_SW_Isolation = ((rx_frame.data.u8[4] >> 6) & (0x01U)); //38|1@1+ (1,0) [0|0] "" X + battery2_BMS_a036_SW_HvpHvilFault = ((rx_frame.data.u8[4] >> 6) & (0x01U)); //39|1@1+ (1,0) [0|0] "" X + battery2_BMS_a037_SW_Flood_Port_Open = (rx_frame.data.u8[5] & (0x01U)); //40|1@1+ (1,0) [0|0] "" X + battery2_BMS_a039_SW_DC_Link_Over_Voltage = ((rx_frame.data.u8[5] >> 2) & (0x01U)); //42|1@1+ (1,0) [0|0] "" X + battery2_BMS_a041_SW_Power_On_Reset = ((rx_frame.data.u8[5] >> 4) & (0x01U)); //44|1@1+ (1,0) [0|0] "" X + battery2_BMS_a042_SW_MPU_Error = ((rx_frame.data.u8[5] >> 5) & (0x01U)); //45|1@1+ (1,0) [0|0] "" X + battery2_BMS_a043_SW_Watch_Dog_Reset = ((rx_frame.data.u8[5] >> 6) & (0x01U)); //46|1@1+ (1,0) [0|0] "" X + battery2_BMS_a044_SW_Assertion = ((rx_frame.data.u8[5] >> 7) & (0x01U)); //47|1@1+ (1,0) [0|0] "" X + battery2_BMS_a045_SW_Exception = (rx_frame.data.u8[6] & (0x01U)); //48|1@1+ (1,0) [0|0] "" X + battery2_BMS_a046_SW_Task_Stack_Usage = ((rx_frame.data.u8[6] >> 1) & (0x01U)); //49|1@1+ (1,0) [0|0] "" X + battery2_BMS_a047_SW_Task_Stack_Overflow = ((rx_frame.data.u8[6] >> 2) & (0x01U)); //50|1@1+ (1,0) [0|0] "" X + battery2_BMS_a048_SW_Log_Upload_Request = ((rx_frame.data.u8[6] >> 3) & (0x01U)); //51|1@1+ (1,0) [0|0] "" X + battery2_BMS_a050_SW_Brick_Voltage_MIA = ((rx_frame.data.u8[6] >> 5) & (0x01U)); //53|1@1+ (1,0) [0|0] "" X + battery2_BMS_a051_SW_HVC_Vref_Bad = ((rx_frame.data.u8[6] >> 6) & (0x01U)); //54|1@1+ (1,0) [0|0] "" X + battery2_BMS_a052_SW_PCS_MIA = ((rx_frame.data.u8[6] >> 7) & (0x01U)); //55|1@1+ (1,0) [0|0] "" X + battery2_BMS_a053_SW_ThermalModel_Sanity = (rx_frame.data.u8[7] & (0x01U)); //56|1@1+ (1,0) [0|0] "" X + battery2_BMS_a054_SW_Ver_Supply_Fault = ((rx_frame.data.u8[7] >> 1) & (0x01U)); //57|1@1+ (1,0) [0|0] "" X + battery2_BMS_a059_SW_Pack_Voltage_Sensing = ((rx_frame.data.u8[7] >> 6) & (0x01U)); //62|1@1+ (1,0) [0|0] "" X + battery2_BMS_a060_SW_Leakage_Test_Failure = ((rx_frame.data.u8[7] >> 7) & (0x01U)); //63|1@1+ (1,0) [0|0] "" X + } + if (mux == 1) { //mux1 + battery2_BMS_a061_robinBrickOverVoltage = ((rx_frame.data.u8[0] >> 4) & (0x01U)); //4|1@1+ (1,0) [0|0] "" X + battery2_BMS_a062_SW_BrickV_Imbalance = ((rx_frame.data.u8[0] >> 5) & (0x01U)); //5|1@1+ (1,0) [0|0] "" X + battery2_BMS_a063_SW_ChargePort_Fault = ((rx_frame.data.u8[0] >> 6) & (0x01U)); //6|1@1+ (1,0) [0|0] "" X + battery2_BMS_a064_SW_SOC_Imbalance = ((rx_frame.data.u8[0] >> 7) & (0x01U)); //7|1@1+ (1,0) [0|0] "" X + battery2_BMS_a069_SW_Low_Power = ((rx_frame.data.u8[1] >> 4) & (0x01U)); //12|1@1+ (1,0) [0|0] "" X + battery2_BMS_a071_SW_SM_TransCon_Not_Met = ((rx_frame.data.u8[1] >> 6) & (0x01U)); //14|1@1+ (1,0) [0|0] "" X + battery2_BMS_a075_SW_Chg_Disable_Failure = ((rx_frame.data.u8[2] >> 2) & (0x01U)); //18|1@1+ (1,0) [0|0] "" X + battery2_BMS_a076_SW_Dch_While_Charging = ((rx_frame.data.u8[2] >> 3) & (0x01U)); //19|1@1+ (1,0) [0|0] "" X + battery2_BMS_a077_SW_Charger_Regulation = ((rx_frame.data.u8[2] >> 4) & (0x01U)); //20|1@1+ (1,0) [0|0] "" X + battery2_BMS_a081_SW_Ctr_Close_Blocked = (rx_frame.data.u8[3] & (0x01U)); //24|1@1+ (1,0) [0|0] "" X + battery2_BMS_a082_SW_Ctr_Force_Open = ((rx_frame.data.u8[3] >> 1) & (0x01U)); //25|1@1+ (1,0) [0|0] "" X + battery2_BMS_a083_SW_Ctr_Close_Failure = ((rx_frame.data.u8[3] >> 2) & (0x01U)); //26|1@1+ (1,0) [0|0] "" X + battery2_BMS_a084_SW_Sleep_Wake_Aborted = ((rx_frame.data.u8[3] >> 3) & (0x01U)); //27|1@1+ (1,0) [0|0] "" X + battery2_BMS_a087_SW_Feim_Test_Blocked = ((rx_frame.data.u8[3] >> 6) & (0x01U)); //30|1@1+ (1,0) [0|0] "" X + battery2_BMS_a088_SW_VcFront_MIA_InDrive = ((rx_frame.data.u8[3] >> 7) & (0x01U)); //31|1@1+ (1,0) [0|0] "" X + battery2_BMS_a089_SW_VcFront_MIA = (rx_frame.data.u8[4] & (0x01U)); //32|1@1+ (1,0) [0|0] "" X + battery2_BMS_a090_SW_Gateway_MIA = ((rx_frame.data.u8[4] >> 1) & (0x01U)); //33|1@1+ (1,0) [0|0] "" X + battery2_BMS_a091_SW_ChargePort_MIA = ((rx_frame.data.u8[4] >> 2) & (0x01U)); //34|1@1+ (1,0) [0|0] "" X + battery2_BMS_a092_SW_ChargePort_Mia_On_Hv = ((rx_frame.data.u8[4] >> 3) & (0x01U)); //35|1@1+ (1,0) [0|0] "" X + battery2_BMS_a094_SW_Drive_Inverter_MIA = ((rx_frame.data.u8[4] >> 5) & (0x01U)); //37|1@1+ (1,0) [0|0] "" X + battery2_BMS_a099_SW_BMB_Communication = ((rx_frame.data.u8[5] >> 2) & (0x01U)); //42|1@1+ (1,0) [0|0] "" X + battery2_BMS_a105_SW_One_Module_Tsense = (rx_frame.data.u8[6] & (0x01U)); //48|1@1+ (1,0) [0|0] "" X + battery2_BMS_a106_SW_All_Module_Tsense = ((rx_frame.data.u8[6] >> 1) & (0x01U)); //49|1@1+ (1,0) [0|0] "" X + battery2_BMS_a107_SW_Stack_Voltage_MIA = ((rx_frame.data.u8[6] >> 2) & (0x01U)); //50|1@1+ (1,0) [0|0] "" X + } + if (mux == 2) { //mux2 + battery2_BMS_a121_SW_NVRAM_Config_Error = ((rx_frame.data.u8[0] >> 4) & (0x01U)); // 4|1@1+ (1,0) [0|0] "" X + battery2_BMS_a122_SW_BMS_Therm_Irrational = ((rx_frame.data.u8[0] >> 5) & (0x01U)); //5|1@1+ (1,0) [0|0] "" X + battery2_BMS_a123_SW_Internal_Isolation = ((rx_frame.data.u8[0] >> 6) & (0x01U)); //6|1@1+ (1,0) [0|0] "" X + battery2_BMS_a127_SW_shunt_SNA = ((rx_frame.data.u8[1] >> 2) & (0x01U)); //10|1@1+ (1,0) [0|0] "" X + battery2_BMS_a128_SW_shunt_MIA = ((rx_frame.data.u8[1] >> 3) & (0x01U)); //11|1@1+ (1,0) [0|0] "" X + battery2_BMS_a129_SW_VSH_Failure = ((rx_frame.data.u8[1] >> 4) & (0x01U)); //12|1@1+ (1,0) [0|0] "" X + battery2_BMS_a130_IO_CAN_Error = ((rx_frame.data.u8[1] >> 5) & (0x01U)); //13|1@1+ (1,0) [0|0] "" X + battery2_BMS_a131_Bleed_FET_Failure = ((rx_frame.data.u8[1] >> 6) & (0x01U)); //14|1@1+ (1,0) [0|0] "" X + battery2_BMS_a132_HW_BMB_OTP_Uncorrctbl = ((rx_frame.data.u8[1] >> 7) & (0x01U)); //15|1@1+ (1,0) [0|0] "" X + battery2_BMS_a134_SW_Delayed_Ctr_Off = ((rx_frame.data.u8[2] >> 1) & (0x01U)); //17|1@1+ (1,0) [0|0] "" X + battery2_BMS_a136_SW_Module_OT_Warning = ((rx_frame.data.u8[2] >> 3) & (0x01U)); //19|1@1+ (1,0) [0|0] "" X + battery2_BMS_a137_SW_Brick_UV_Warning = ((rx_frame.data.u8[2] >> 4) & (0x01U)); //20|1@1+ (1,0) [0|0] "" X + battery2_BMS_a138_SW_Brick_OV_Warning = ((rx_frame.data.u8[2] >> 5) & (0x01U)); //21|1@1+ (1,0) [0|0] "" X + battery2_BMS_a139_SW_DC_Link_V_Irrational = ((rx_frame.data.u8[2] >> 6) & (0x01U)); //22|1@1+ (1,0) [0|0] "" X + battery2_BMS_a141_SW_BMB_Status_Warning = (rx_frame.data.u8[3] & (0x01U)); //24|1@1+ (1,0) [0|0] "" X + battery2_BMS_a144_Hvp_Config_Mismatch = ((rx_frame.data.u8[3] >> 3) & (0x01U)); //27|1@1+ (1,0) [0|0] "" X + battery2_BMS_a145_SW_SOC_Change = ((rx_frame.data.u8[3] >> 4) & (0x01U)); //28|1@1+ (1,0) [0|0] "" X + battery2_BMS_a146_SW_Brick_Overdischarged = ((rx_frame.data.u8[3] >> 5) & (0x01U)); //29|1@1+ (1,0) [0|0] "" X + battery2_BMS_a149_SW_Missing_Config_Block = (rx_frame.data.u8[4] & (0x01U)); //32|1@1+ (1,0) [0|0] "" X + battery2_BMS_a151_SW_external_isolation = ((rx_frame.data.u8[4] >> 2) & (0x01U)); //34|1@1+ (1,0) [0|0] "" X + battery2_BMS_a156_SW_BMB_Vref_bad = ((rx_frame.data.u8[4] >> 7) & (0x01U)); //39|1@1+ (1,0) [0|0] "" X + battery2_BMS_a157_SW_HVP_HVS_Comms = (rx_frame.data.u8[5] & (0x01U)); //40|1@1+ (1,0) [0|0] "" X + battery2_BMS_a158_SW_HVP_HVI_Comms = ((rx_frame.data.u8[5] >> 1) & (0x01U)); //41|1@1+ (1,0) [0|0] "" X + battery2_BMS_a159_SW_HVP_ECU_Error = ((rx_frame.data.u8[5] >> 2) & (0x01U)); //42|1@1+ (1,0) [0|0] "" X + battery2_BMS_a161_SW_DI_Open_Request = ((rx_frame.data.u8[5] >> 4) & (0x01U)); //44|1@1+ (1,0) [0|0] "" X + battery2_BMS_a162_SW_No_Power_For_Support = ((rx_frame.data.u8[5] >> 5) & (0x01U)); //45|1@1+ (1,0) [0|0] "" X + battery2_BMS_a163_SW_Contactor_Mismatch = ((rx_frame.data.u8[5] >> 6) & (0x01U)); //46|1@1+ (1,0) [0|0] "" X + battery2_BMS_a164_SW_Uncontrolled_Regen = ((rx_frame.data.u8[5] >> 7) & (0x01U)); //47|1@1+ (1,0) [0|0] "" X + battery2_BMS_a165_SW_Pack_Partial_Weld = (rx_frame.data.u8[6] & (0x01U)); //48|1@1+ (1,0) [0|0] "" X + battery2_BMS_a166_SW_Pack_Full_Weld = ((rx_frame.data.u8[6] >> 1) & (0x01U)); //49|1@1+ (1,0) [0|0] "" X + battery2_BMS_a167_SW_FC_Partial_Weld = ((rx_frame.data.u8[6] >> 2) & (0x01U)); //50|1@1+ (1,0) [0|0] "" X + battery2_BMS_a168_SW_FC_Full_Weld = ((rx_frame.data.u8[6] >> 3) & (0x01U)); //51|1@1+ (1,0) [0|0] "" X + battery2_BMS_a169_SW_FC_Pack_Weld = ((rx_frame.data.u8[6] >> 4) & (0x01U)); //52|1@1+ (1,0) [0|0] "" X + battery2_BMS_a170_SW_Limp_Mode = ((rx_frame.data.u8[6] >> 5) & (0x01U)); //53|1@1+ (1,0) [0|0] "" X + battery2_BMS_a171_SW_Stack_Voltage_Sense = ((rx_frame.data.u8[6] >> 6) & (0x01U)); //54|1@1+ (1,0) [0|0] "" X + battery2_BMS_a174_SW_Charge_Failure = ((rx_frame.data.u8[7] >> 1) & (0x01U)); //57|1@1+ (1,0) [0|0] "" X + battery2_BMS_a176_SW_GracefulPowerOff = ((rx_frame.data.u8[7] >> 3) & (0x01U)); //59|1@1+ (1,0) [0|0] "" X + battery2_BMS_a179_SW_Hvp_12V_Fault = ((rx_frame.data.u8[7] >> 6) & (0x01U)); //62|1@1+ (1,0) [0|0] "" X + battery2_BMS_a180_SW_ECU_reset_blocked = ((rx_frame.data.u8[7] >> 7) & (0x01U)); //63|1@1+ (1,0) [0|0] "" X + } + break; default: break; } @@ -1087,69 +2522,69 @@ void update_values_battery2() { //This function maps all the values fetched via } #endif // TESLA_MODEL_3Y_BATTERY -#ifdef DEBUG_VIA_USB +#ifdef DEBUG_LOG printFaultCodesIfActive_battery2(); - Serial.print("STATUS: Contactor: "); - Serial.print(contactorText[battery2_contactor]); //Display what state the contactor is in - Serial.print(", HVIL: "); - Serial.print(hvilStatusState[battery2_hvil_status]); - Serial.print(", NegativeState: "); - Serial.print(contactorState[battery2_packContNegativeState]); - Serial.print(", PositiveState: "); - Serial.print(contactorState[battery2_packContPositiveState]); - Serial.print(", setState: "); - Serial.print(contactorState[battery2_packContactorSetState]); - Serial.print(", close allowed: "); - Serial.print(battery2_packCtrsClosingAllowed); - Serial.print(", Pyrotest: "); - Serial.println(battery2_pyroTestInProgress); + logging.print("STATUS: Contactor: "); + logging.print(contactorText[battery2_contactor]); //Display what state the contactor is in + logging.print(", HVIL: "); + logging.print(hvilStatusState[battery2_hvil_status]); + logging.print(", NegativeState: "); + logging.print(contactorState[battery2_packContNegativeState]); + logging.print(", PositiveState: "); + logging.print(contactorState[battery2_packContPositiveState]); + logging.print(", setState: "); + logging.print(contactorState[battery2_packContactorSetState]); + logging.print(", close allowed: "); + logging.print(battery2_packCtrsClosingAllowed); + logging.print(", Pyrotest: "); + logging.println(battery2_pyroTestInProgress); - Serial.print("Battery2 values: "); - Serial.print("Real SOC: "); - Serial.print(battery2_soc_ui / 10.0, 1); + logging.print("Battery2 values: "); + logging.print("Real SOC: "); + logging.print(battery2_soc_ui / 10.0, 1); print_int_with_units(", Battery2 voltage: ", battery2_volts, "V"); print_int_with_units(", Battery2 HV current: ", (battery2_amps * 0.1), "A"); - Serial.print(", Fully charged?: "); + logging.print(", Fully charged?: "); if (battery2_full_charge_complete) - Serial.print("YES, "); + logging.print("YES, "); else - Serial.print("NO, "); + logging.print("NO, "); if (datalayer.battery2.info.chemistry == battery_chemistry_enum::LFP) { - Serial.print("LFP chemistry detected!"); + logging.print("LFP chemistry detected!"); } - Serial.println(""); - Serial.print("Cellstats, Max: "); - Serial.print(battery2_cell_max_v); - Serial.print("mV (cell "); - Serial.print(battery2_max_vno); - Serial.print("), Min: "); - Serial.print(battery2_cell_min_v); - Serial.print("mV (cell "); - Serial.print(battery2_min_vno); - Serial.print("), Imbalance: "); - Serial.print(battery2_cell_deviation_mV); - Serial.println("mV."); + logging.println(""); + logging.print("Cellstats, Max: "); + logging.print(battery2_cell_max_v); + logging.print("mV (cell "); + logging.print(battery2_max_vno); + logging.print("), Min: "); + logging.print(battery2_cell_min_v); + logging.print("mV (cell "); + logging.print(battery2_min_vno); + logging.print("), Imbalance: "); + logging.print(battery2_cell_deviation_mV); + logging.println("mV."); print_int_with_units("High Voltage Output Pins: ", battery2_dcdcHvBusVolt, "V"); - Serial.print(", "); + logging.print(", "); print_int_with_units("Low Voltage: ", battery2_dcdcLvBusVolt, "V"); - Serial.println(""); + logging.println(""); print_int_with_units("DC/DC 12V current: ", battery2_dcdcLvOutputCurrent, "A"); - Serial.println(""); + logging.println(""); - Serial.println("Values passed to the inverter: "); + logging.println("Values passed to the inverter: "); print_SOC(" SOC: ", datalayer.battery2.status.reported_soc); print_int_with_units(" Max discharge power: ", datalayer.battery2.status.max_discharge_power_W, "W"); - Serial.print(", "); + logging.print(", "); print_int_with_units(" Max charge power: ", datalayer.battery2.status.max_charge_power_W, "W"); - Serial.println(""); + logging.println(""); print_int_with_units(" Max temperature: ", ((int16_t)datalayer.battery2.status.temperature_min_dC * 0.1), "°C"); - Serial.print(", "); + logging.print(", "); print_int_with_units(" Min temperature: ", ((int16_t)datalayer.battery2.status.temperature_max_dC * 0.1), "°C"); - Serial.println(""); -#endif // DEBUG_VIA_USB + logging.println(""); +#endif // DEBUG_LOG } #endif //DOUBLE_BATTERY @@ -1190,7 +2625,7 @@ int index_1CF = 0; int index_118 = 0; #endif //defined(TESLA_MODEL_SX_BATTERY) || defined(EXP_TESLA_BMS_DIGITAL_HVIL) -void send_can_battery() { +void transmit_can_battery() { /*From bielec: My fist 221 message, to close the contactors is 0x41, 0x11, 0x01, 0x00, 0x00, 0x00, 0x20, 0x96 and then, to cause "hv_up_for_drive" I send an additional 221 message 0x61, 0x15, 0x01, 0x00, 0x00, 0x00, 0x20, 0xBA so two 221 messages are being continuously transmitted. When I want to shut down, I stop the second message and only send @@ -1198,13 +2633,17 @@ the first, for a few cycles, then stop all messages which causes the contactor unsigned long currentMillis = millis(); + if (!cellvoltagesRead) { + return; //All cellvoltages not read yet, do not proceed with contactor closing + } + #if defined(TESLA_MODEL_SX_BATTERY) || defined(EXP_TESLA_BMS_DIGITAL_HVIL) if ((datalayer.system.status.inverter_allows_contactor_closing) && (datalayer.battery.status.bms_status != FAULT)) { if (currentMillis - lastSend1CF >= 10) { - transmit_can(&can_msg_1CF[index_1CF], can_config.battery); + transmit_can_frame(&can_msg_1CF[index_1CF], can_config.battery); #ifdef DOUBLE_BATTERY - transmit_can(&can_msg_1CF[index_1CF], can_config.battery_double); + transmit_can_frame(&can_msg_1CF[index_1CF], can_config.battery_double); #endif // DOUBLE_BATTERY index_1CF = (index_1CF + 1) % 8; @@ -1212,9 +2651,9 @@ the first, for a few cycles, then stop all messages which causes the contactor } if (currentMillis - lastSend118 >= 10) { - transmit_can(&can_msg_118[index_118], can_config.battery); + transmit_can_frame(&can_msg_118[index_118], can_config.battery); #ifdef DOUBLE_BATTERY - transmit_can(&can_msg_1CF[index_1CF], can_config.battery_double); + transmit_can_frame(&can_msg_1CF[index_1CF], can_config.battery_double); #endif //DOUBLE_BATTERY index_118 = (index_118 + 1) % 16; @@ -1227,33 +2666,33 @@ the first, for a few cycles, then stop all messages which causes the contactor #endif //defined(TESLA_MODEL_SX_BATTERY) || defined(EXP_TESLA_BMS_DIGITAL_HVIL) //Send 30ms message - if (currentMillis - previousMillis30 >= INTERVAL_30_MS) { + if (currentMillis - previousMillis50 >= INTERVAL_50_MS) { // Check if sending of CAN messages has been delayed too much. - if ((currentMillis - previousMillis30 >= INTERVAL_30_MS_DELAYED) && (currentMillis > BOOTUP_TIME)) { - set_event(EVENT_CAN_OVERRUN, (currentMillis - previousMillis30)); + if ((currentMillis - previousMillis50 >= INTERVAL_50_MS_DELAYED) && (currentMillis > BOOTUP_TIME)) { + set_event(EVENT_CAN_OVERRUN, (currentMillis - previousMillis50)); } else { clear_event(EVENT_CAN_OVERRUN); } - previousMillis30 = currentMillis; + previousMillis50 = currentMillis; if ((datalayer.system.status.inverter_allows_contactor_closing == true) && (datalayer.battery.status.bms_status != FAULT)) { sendContactorClosingMessagesStill = 300; - transmit_can(&TESLA_221_1, can_config.battery); - transmit_can(&TESLA_221_2, can_config.battery); + transmit_can_frame(&TESLA_221_1, can_config.battery); + transmit_can_frame(&TESLA_221_2, can_config.battery); #ifdef DOUBLE_BATTERY if (datalayer.system.status.battery2_allows_contactor_closing) { - transmit_can(&TESLA_221_1, can_config.battery_double); - transmit_can(&TESLA_221_2, can_config.battery_double); + transmit_can_frame(&TESLA_221_1, can_config.battery_double); + transmit_can_frame(&TESLA_221_2, can_config.battery_double); } #endif //DOUBLE_BATTERY } else { // Faulted state, or inverter blocks contactor closing if (sendContactorClosingMessagesStill > 0) { - transmit_can(&TESLA_221_1, can_config.battery); + transmit_can_frame(&TESLA_221_1, can_config.battery); sendContactorClosingMessagesStill--; #ifdef DOUBLE_BATTERY - transmit_can(&TESLA_221_1, can_config.battery_double); + transmit_can_frame(&TESLA_221_1, can_config.battery_double); #endif //DOUBLE_BATTERY } } @@ -1261,38 +2700,39 @@ the first, for a few cycles, then stop all messages which causes the contactor } void print_int_with_units(char* header, int value, char* units) { - Serial.print(header); - Serial.print(value); - Serial.print(units); + logging.print(header); + logging.print(value); + logging.print(units); } void print_SOC(char* header, int SOC) { - Serial.print(header); - Serial.print(SOC / 100); - Serial.print("."); + logging.print(header); + logging.print(SOC / 100); + logging.print("."); int hundredth = SOC % 100; if (hundredth < 10) - Serial.print(0); - Serial.print(hundredth); - Serial.println("%"); + logging.print(0); + logging.print(hundredth); + logging.println("pct"); } void printFaultCodesIfActive() { if (battery_packCtrsClosingAllowed == 0) { - Serial.println( + logging.println( "ERROR: Check high voltage connectors and interlock circuit! Closing contactor not allowed! Values: "); } if (battery_pyroTestInProgress == 1) { - Serial.println("ERROR: Please wait for Pyro Connection check to finish, HV cables successfully seated!"); + logging.println("ERROR: Please wait for Pyro Connection check to finish, HV cables successfully seated!"); } if (datalayer.system.status.inverter_allows_contactor_closing == false) { - Serial.println( + logging.println( "ERROR: Solar inverter does not allow for contactor closing. Check communication connection to the inverter " "OR " "disable the inverter protocol to proceed with contactor closing"); } // Check each symbol and print debug information if its value is 1 - printDebugIfActive(battery_WatchdogReset, "ERROR: The processor has experienced a reset due to watchdog reset"); + // 0X3AA: 938 HVP_alertMatrix1 + //printDebugIfActive(battery_WatchdogReset, "ERROR: The processor has experienced a reset due to watchdog reset"); //Uncommented due to not affecting usage printDebugIfActive(battery_PowerLossReset, "ERROR: The processor has experienced a reset due to power loss"); printDebugIfActive(battery_SwAssertion, "ERROR: An internal software assertion has failed"); printDebugIfActive(battery_CrashEvent, "ERROR: crash signal is detected by HVP"); @@ -1350,25 +2790,117 @@ void printFaultCodesIfActive() { printDebugIfActive(battery_packCtrCloseFailed, "ERROR: packCtrCloseFailed is active"); printDebugIfActive(battery_fcCtrCloseFailed, "ERROR: fcCtrCloseFailed is active"); printDebugIfActive(battery_shuntThermistorMia, "ERROR: shuntThermistorMia is active"); + // 0x320 800 BMS_alertMatrix + printDebugIfActive(battery_BMS_a017_SW_Brick_OV, "ERROR: BMS_a017_SW_Brick_OV"); + printDebugIfActive(battery_BMS_a018_SW_Brick_UV, "ERROR: BMS_a018_SW_Brick_UV"); + printDebugIfActive(battery_BMS_a019_SW_Module_OT, "ERROR: BMS_a019_SW_Module_OT"); + printDebugIfActive(battery_BMS_a021_SW_Dr_Limits_Regulation, "ERROR: BMS_a021_SW_Dr_Limits_Regulation"); + printDebugIfActive(battery_BMS_a022_SW_Over_Current, "ERROR: BMS_a022_SW_Over_Current"); + printDebugIfActive(battery_BMS_a023_SW_Stack_OV, "ERROR: BMS_a023_SW_Stack_OV"); + printDebugIfActive(battery_BMS_a024_SW_Islanded_Brick, "ERROR: BMS_a024_SW_Islanded_Brick"); + printDebugIfActive(battery_BMS_a025_SW_PwrBalance_Anomaly, "ERROR: BMS_a025_SW_PwrBalance_Anomaly"); + printDebugIfActive(battery_BMS_a026_SW_HFCurrent_Anomaly, "ERROR: BMS_a026_SW_HFCurrent_Anomaly"); + printDebugIfActive(battery_BMS_a034_SW_Passive_Isolation, "ERROR: BMS_a034_SW_Passive_Isolation"); + printDebugIfActive(battery_BMS_a035_SW_Isolation, "ERROR: BMS_a035_SW_Isolation"); + printDebugIfActive(battery_BMS_a036_SW_HvpHvilFault, "ERROR: BMS_a036_SW_HvpHvilFault"); + printDebugIfActive(battery_BMS_a037_SW_Flood_Port_Open, "ERROR: BMS_a037_SW_Flood_Port_Open"); + printDebugIfActive(battery_BMS_a039_SW_DC_Link_Over_Voltage, "ERROR: BMS_a039_SW_DC_Link_Over_Voltage"); + printDebugIfActive(battery_BMS_a041_SW_Power_On_Reset, "ERROR: BMS_a041_SW_Power_On_Reset"); + printDebugIfActive(battery_BMS_a042_SW_MPU_Error, "ERROR: BMS_a042_SW_MPU_Error"); + printDebugIfActive(battery_BMS_a043_SW_Watch_Dog_Reset, "ERROR: BMS_a043_SW_Watch_Dog_Reset"); + printDebugIfActive(battery_BMS_a044_SW_Assertion, "ERROR: BMS_a044_SW_Assertion"); + printDebugIfActive(battery_BMS_a045_SW_Exception, "ERROR: BMS_a045_SW_Exception"); + printDebugIfActive(battery_BMS_a046_SW_Task_Stack_Usage, "ERROR: BMS_a046_SW_Task_Stack_Usage"); + printDebugIfActive(battery_BMS_a047_SW_Task_Stack_Overflow, "ERROR: BMS_a047_SW_Task_Stack_Overflow"); + printDebugIfActive(battery_BMS_a048_SW_Log_Upload_Request, "ERROR: BMS_a048_SW_Log_Upload_Request"); + printDebugIfActive(battery_BMS_a050_SW_Brick_Voltage_MIA, "ERROR: BMS_a050_SW_Brick_Voltage_MIA"); + printDebugIfActive(battery_BMS_a051_SW_HVC_Vref_Bad, "ERROR: BMS_a051_SW_HVC_Vref_Bad"); + printDebugIfActive(battery_BMS_a052_SW_PCS_MIA, "ERROR: BMS_a052_SW_PCS_MIA"); + printDebugIfActive(battery_BMS_a053_SW_ThermalModel_Sanity, "ERROR: BMS_a053_SW_ThermalModel_Sanity"); + printDebugIfActive(battery_BMS_a054_SW_Ver_Supply_Fault, "ERROR: BMS_a054_SW_Ver_Supply_Fault"); + printDebugIfActive(battery_BMS_a059_SW_Pack_Voltage_Sensing, "ERROR: BMS_a059_SW_Pack_Voltage_Sensing"); + printDebugIfActive(battery_BMS_a060_SW_Leakage_Test_Failure, "ERROR: BMS_a060_SW_Leakage_Test_Failure"); + printDebugIfActive(battery_BMS_a061_robinBrickOverVoltage, "ERROR: BMS_a061_robinBrickOverVoltage"); + printDebugIfActive(battery_BMS_a062_SW_BrickV_Imbalance, "ERROR: BMS_a062_SW_BrickV_Imbalance"); + printDebugIfActive(battery_BMS_a063_SW_ChargePort_Fault, "ERROR: BMS_a063_SW_ChargePort_Fault"); + printDebugIfActive(battery_BMS_a064_SW_SOC_Imbalance, "ERROR: BMS_a064_SW_SOC_Imbalance"); + printDebugIfActive(battery_BMS_a069_SW_Low_Power, "ERROR: BMS_a069_SW_Low_Power"); + printDebugIfActive(battery_BMS_a071_SW_SM_TransCon_Not_Met, "ERROR: BMS_a071_SW_SM_TransCon_Not_Met"); + printDebugIfActive(battery_BMS_a075_SW_Chg_Disable_Failure, "ERROR: BMS_a075_SW_Chg_Disable_Failure"); + printDebugIfActive(battery_BMS_a076_SW_Dch_While_Charging, "ERROR: BMS_a076_SW_Dch_While_Charging"); + printDebugIfActive(battery_BMS_a077_SW_Charger_Regulation, "ERROR: BMS_a077_SW_Charger_Regulation"); + printDebugIfActive(battery_BMS_a081_SW_Ctr_Close_Blocked, "ERROR: BMS_a081_SW_Ctr_Close_Blocked"); + printDebugIfActive(battery_BMS_a082_SW_Ctr_Force_Open, "ERROR: BMS_a082_SW_Ctr_Force_Open"); + printDebugIfActive(battery_BMS_a083_SW_Ctr_Close_Failure, "ERROR: BMS_a083_SW_Ctr_Close_Failure"); + printDebugIfActive(battery_BMS_a084_SW_Sleep_Wake_Aborted, "ERROR: BMS_a084_SW_Sleep_Wake_Aborted"); + printDebugIfActive(battery_BMS_a087_SW_Feim_Test_Blocked, "ERROR: BMS_a087_SW_Feim_Test_Blocked"); + printDebugIfActive(battery_BMS_a088_SW_VcFront_MIA_InDrive, "ERROR: BMS_a088_SW_VcFront_MIA_InDrive"); + printDebugIfActive(battery_BMS_a089_SW_VcFront_MIA, "ERROR: BMS_a089_SW_VcFront_MIA"); + printDebugIfActive(battery_BMS_a090_SW_Gateway_MIA, "ERROR: BMS_a090_SW_Gateway_MIA"); + printDebugIfActive(battery_BMS_a091_SW_ChargePort_MIA, "ERROR: BMS_a091_SW_ChargePort_MIA"); + printDebugIfActive(battery_BMS_a092_SW_ChargePort_Mia_On_Hv, "ERROR: BMS_a092_SW_ChargePort_Mia_On_Hv"); + printDebugIfActive(battery_BMS_a094_SW_Drive_Inverter_MIA, "ERROR: BMS_a094_SW_Drive_Inverter_MIA"); + printDebugIfActive(battery_BMS_a099_SW_BMB_Communication, "ERROR: BMS_a099_SW_BMB_Communication"); + printDebugIfActive(battery_BMS_a105_SW_One_Module_Tsense, "ERROR: BMS_a105_SW_One_Module_Tsense"); + printDebugIfActive(battery_BMS_a106_SW_All_Module_Tsense, "ERROR: BMS_a106_SW_All_Module_Tsense"); + printDebugIfActive(battery_BMS_a107_SW_Stack_Voltage_MIA, "ERROR: BMS_a107_SW_Stack_Voltage_MIA"); + printDebugIfActive(battery_BMS_a121_SW_NVRAM_Config_Error, "ERROR: BMS_a121_SW_NVRAM_Config_Error"); + printDebugIfActive(battery_BMS_a122_SW_BMS_Therm_Irrational, "ERROR: BMS_a122_SW_BMS_Therm_Irrational"); + printDebugIfActive(battery_BMS_a123_SW_Internal_Isolation, "ERROR: BMS_a123_SW_Internal_Isolation"); + printDebugIfActive(battery_BMS_a127_SW_shunt_SNA, "ERROR: BMS_a127_SW_shunt_SNA"); + printDebugIfActive(battery_BMS_a128_SW_shunt_MIA, "ERROR: BMS_a128_SW_shunt_MIA"); + printDebugIfActive(battery_BMS_a129_SW_VSH_Failure, "ERROR: BMS_a129_SW_VSH_Failure"); + printDebugIfActive(battery_BMS_a130_IO_CAN_Error, "ERROR: BMS_a130_IO_CAN_Error"); + printDebugIfActive(battery_BMS_a131_Bleed_FET_Failure, "ERROR: BMS_a131_Bleed_FET_Failure"); + printDebugIfActive(battery_BMS_a132_HW_BMB_OTP_Uncorrctbl, "ERROR: BMS_a132_HW_BMB_OTP_Uncorrctbl"); + printDebugIfActive(battery_BMS_a134_SW_Delayed_Ctr_Off, "ERROR: BMS_a134_SW_Delayed_Ctr_Off"); + printDebugIfActive(battery_BMS_a136_SW_Module_OT_Warning, "ERROR: BMS_a136_SW_Module_OT_Warning"); + printDebugIfActive(battery_BMS_a137_SW_Brick_UV_Warning, "ERROR: BMS_a137_SW_Brick_UV_Warning"); + printDebugIfActive(battery_BMS_a139_SW_DC_Link_V_Irrational, "ERROR: BMS_a139_SW_DC_Link_V_Irrational"); + printDebugIfActive(battery_BMS_a141_SW_BMB_Status_Warning, "ERROR: BMS_a141_SW_BMB_Status_Warning"); + printDebugIfActive(battery_BMS_a144_Hvp_Config_Mismatch, "ERROR: BMS_a144_Hvp_Config_Mismatch"); + printDebugIfActive(battery_BMS_a145_SW_SOC_Change, "ERROR: BMS_a145_SW_SOC_Change"); + printDebugIfActive(battery_BMS_a146_SW_Brick_Overdischarged, "ERROR: BMS_a146_SW_Brick_Overdischarged"); + printDebugIfActive(battery_BMS_a149_SW_Missing_Config_Block, "ERROR: BMS_a149_SW_Missing_Config_Block"); + printDebugIfActive(battery_BMS_a151_SW_external_isolation, "ERROR: BMS_a151_SW_external_isolation"); + printDebugIfActive(battery_BMS_a156_SW_BMB_Vref_bad, "ERROR: BMS_a156_SW_BMB_Vref_bad"); + printDebugIfActive(battery_BMS_a157_SW_HVP_HVS_Comms, "ERROR: BMS_a157_SW_HVP_HVS_Comms"); + printDebugIfActive(battery_BMS_a158_SW_HVP_HVI_Comms, "ERROR: BMS_a158_SW_HVP_HVI_Comms"); + printDebugIfActive(battery_BMS_a159_SW_HVP_ECU_Error, "ERROR: BMS_a159_SW_HVP_ECU_Error"); + printDebugIfActive(battery_BMS_a161_SW_DI_Open_Request, "ERROR: BMS_a161_SW_DI_Open_Request"); + printDebugIfActive(battery_BMS_a162_SW_No_Power_For_Support, "ERROR: BMS_a162_SW_No_Power_For_Support"); + printDebugIfActive(battery_BMS_a163_SW_Contactor_Mismatch, "ERROR: BMS_a163_SW_Contactor_Mismatch"); + printDebugIfActive(battery_BMS_a164_SW_Uncontrolled_Regen, "ERROR: BMS_a164_SW_Uncontrolled_Regen"); + printDebugIfActive(battery_BMS_a165_SW_Pack_Partial_Weld, "ERROR: BMS_a165_SW_Pack_Partial_Weld"); + printDebugIfActive(battery_BMS_a166_SW_Pack_Full_Weld, "ERROR: BMS_a166_SW_Pack_Full_Weld"); + printDebugIfActive(battery_BMS_a167_SW_FC_Partial_Weld, "ERROR: BMS_a167_SW_FC_Partial_Weld"); + printDebugIfActive(battery_BMS_a168_SW_FC_Full_Weld, "ERROR: BMS_a168_SW_FC_Full_Weld"); + printDebugIfActive(battery_BMS_a169_SW_FC_Pack_Weld, "ERROR: BMS_a169_SW_FC_Pack_Weld"); + printDebugIfActive(battery_BMS_a170_SW_Limp_Mode, "ERROR: BMS_a170_SW_Limp_Mode"); + printDebugIfActive(battery_BMS_a171_SW_Stack_Voltage_Sense, "ERROR: BMS_a171_SW_Stack_Voltage_Sense"); + printDebugIfActive(battery_BMS_a174_SW_Charge_Failure, "ERROR: BMS_a174_SW_Charge_Failure"); + printDebugIfActive(battery_BMS_a176_SW_GracefulPowerOff, "ERROR: BMS_a176_SW_GracefulPowerOff"); + printDebugIfActive(battery_BMS_a179_SW_Hvp_12V_Fault, "ERROR: BMS_a179_SW_Hvp_12V_Fault"); + printDebugIfActive(battery_BMS_a180_SW_ECU_reset_blocked, "ERROR: BMS_a180_SW_ECU_reset_blocked"); } -#ifdef DOUBLE_BATTERY +#ifdef DOUBLE_BATTERY //need to update battery2 void printFaultCodesIfActive_battery2() { if (battery2_packCtrsClosingAllowed == 0) { - Serial.println( + logging.println( "ERROR: Check high voltage connectors and interlock circuit! Closing contactor not allowed! Values: "); } if (battery2_pyroTestInProgress == 1) { - Serial.println("ERROR: Please wait for Pyro Connection check to finish, HV cables successfully seated!"); + logging.println("ERROR: Please wait for Pyro Connection check to finish, HV cables successfully seated!"); } if (datalayer.system.status.inverter_allows_contactor_closing == false) { - Serial.println( + logging.println( "ERROR: Solar inverter does not allow for contactor closing. Check communication connection to the inverter " "OR " "disable the inverter protocol to proceed with contactor closing"); } // Check each symbol and print debug information if its value is 1 - printDebugIfActive(battery2_WatchdogReset, "ERROR: The processor has experienced a reset due to watchdog reset"); + //printDebugIfActive(battery2_WatchdogReset, "ERROR: The processor has experienced a reset due to watchdog reset"); //Uncommented due to not affecting usage printDebugIfActive(battery2_PowerLossReset, "ERROR: The processor has experienced a reset due to power loss"); printDebugIfActive(battery2_SwAssertion, "ERROR: An internal software assertion has failed"); printDebugIfActive(battery2_CrashEvent, "ERROR: crash signal is detected by HVP"); @@ -1428,12 +2960,104 @@ void printFaultCodesIfActive_battery2() { printDebugIfActive(battery2_packCtrCloseFailed, "ERROR: packCtrCloseFailed is active"); printDebugIfActive(battery2_fcCtrCloseFailed, "ERROR: fcCtrCloseFailed is active"); printDebugIfActive(battery2_shuntThermistorMia, "ERROR: shuntThermistorMia is active"); + // 0x320 800 BMS_alertMatrix + printDebugIfActive(battery2_BMS_a017_SW_Brick_OV, "ERROR: BMS_a017_SW_Brick_OV"); + printDebugIfActive(battery2_BMS_a018_SW_Brick_UV, "ERROR: BMS_a018_SW_Brick_UV"); + printDebugIfActive(battery2_BMS_a019_SW_Module_OT, "ERROR: BMS_a019_SW_Module_OT"); + printDebugIfActive(battery2_BMS_a021_SW_Dr_Limits_Regulation, "ERROR: BMS_a021_SW_Dr_Limits_Regulation"); + printDebugIfActive(battery2_BMS_a022_SW_Over_Current, "ERROR: BMS_a022_SW_Over_Current"); + printDebugIfActive(battery2_BMS_a023_SW_Stack_OV, "ERROR: BMS_a023_SW_Stack_OV"); + printDebugIfActive(battery2_BMS_a024_SW_Islanded_Brick, "ERROR: BMS_a024_SW_Islanded_Brick"); + printDebugIfActive(battery2_BMS_a025_SW_PwrBalance_Anomaly, "ERROR: BMS_a025_SW_PwrBalance_Anomaly"); + printDebugIfActive(battery2_BMS_a026_SW_HFCurrent_Anomaly, "ERROR: BMS_a026_SW_HFCurrent_Anomaly"); + printDebugIfActive(battery2_BMS_a034_SW_Passive_Isolation, "ERROR: BMS_a034_SW_Passive_Isolation"); + printDebugIfActive(battery2_BMS_a035_SW_Isolation, "ERROR: BMS_a035_SW_Isolation"); + printDebugIfActive(battery2_BMS_a036_SW_HvpHvilFault, "ERROR: BMS_a036_SW_HvpHvilFault"); + printDebugIfActive(battery2_BMS_a037_SW_Flood_Port_Open, "ERROR: BMS_a037_SW_Flood_Port_Open"); + printDebugIfActive(battery2_BMS_a039_SW_DC_Link_Over_Voltage, "ERROR: BMS_a039_SW_DC_Link_Over_Voltage"); + printDebugIfActive(battery2_BMS_a041_SW_Power_On_Reset, "ERROR: BMS_a041_SW_Power_On_Reset"); + printDebugIfActive(battery2_BMS_a042_SW_MPU_Error, "ERROR: BMS_a042_SW_MPU_Error"); + printDebugIfActive(battery2_BMS_a043_SW_Watch_Dog_Reset, "ERROR: BMS_a043_SW_Watch_Dog_Reset"); + printDebugIfActive(battery2_BMS_a044_SW_Assertion, "ERROR: BMS_a044_SW_Assertion"); + printDebugIfActive(battery2_BMS_a045_SW_Exception, "ERROR: BMS_a045_SW_Exception"); + printDebugIfActive(battery2_BMS_a046_SW_Task_Stack_Usage, "ERROR: BMS_a046_SW_Task_Stack_Usage"); + printDebugIfActive(battery2_BMS_a047_SW_Task_Stack_Overflow, "ERROR: BMS_a047_SW_Task_Stack_Overflow"); + printDebugIfActive(battery2_BMS_a048_SW_Log_Upload_Request, "ERROR: BMS_a048_SW_Log_Upload_Request"); + printDebugIfActive(battery2_BMS_a050_SW_Brick_Voltage_MIA, "ERROR: BMS_a050_SW_Brick_Voltage_MIA"); + printDebugIfActive(battery2_BMS_a051_SW_HVC_Vref_Bad, "ERROR: BMS_a051_SW_HVC_Vref_Bad"); + printDebugIfActive(battery2_BMS_a052_SW_PCS_MIA, "ERROR: BMS_a052_SW_PCS_MIA"); + printDebugIfActive(battery2_BMS_a053_SW_ThermalModel_Sanity, "ERROR: BMS_a053_SW_ThermalModel_Sanity"); + printDebugIfActive(battery2_BMS_a054_SW_Ver_Supply_Fault, "ERROR: BMS_a054_SW_Ver_Supply_Fault"); + printDebugIfActive(battery2_BMS_a059_SW_Pack_Voltage_Sensing, "ERROR: BMS_a059_SW_Pack_Voltage_Sensing"); + printDebugIfActive(battery2_BMS_a060_SW_Leakage_Test_Failure, "ERROR: BMS_a060_SW_Leakage_Test_Failure"); + printDebugIfActive(battery2_BMS_a061_robinBrickOverVoltage, "ERROR: BMS_a061_robinBrickOverVoltage"); + printDebugIfActive(battery2_BMS_a062_SW_BrickV_Imbalance, "ERROR: BMS_a062_SW_BrickV_Imbalance"); + printDebugIfActive(battery2_BMS_a063_SW_ChargePort_Fault, "ERROR: BMS_a063_SW_ChargePort_Fault"); + printDebugIfActive(battery2_BMS_a064_SW_SOC_Imbalance, "ERROR: BMS_a064_SW_SOC_Imbalance"); + printDebugIfActive(battery2_BMS_a069_SW_Low_Power, "ERROR: BMS_a069_SW_Low_Power"); + printDebugIfActive(battery2_BMS_a071_SW_SM_TransCon_Not_Met, "ERROR: BMS_a071_SW_SM_TransCon_Not_Met"); + printDebugIfActive(battery2_BMS_a075_SW_Chg_Disable_Failure, "ERROR: BMS_a075_SW_Chg_Disable_Failure"); + printDebugIfActive(battery2_BMS_a076_SW_Dch_While_Charging, "ERROR: BMS_a076_SW_Dch_While_Charging"); + printDebugIfActive(battery2_BMS_a077_SW_Charger_Regulation, "ERROR: BMS_a077_SW_Charger_Regulation"); + printDebugIfActive(battery2_BMS_a081_SW_Ctr_Close_Blocked, "ERROR: BMS_a081_SW_Ctr_Close_Blocked"); + printDebugIfActive(battery2_BMS_a082_SW_Ctr_Force_Open, "ERROR: BMS_a082_SW_Ctr_Force_Open"); + printDebugIfActive(battery2_BMS_a083_SW_Ctr_Close_Failure, "ERROR: BMS_a083_SW_Ctr_Close_Failure"); + printDebugIfActive(battery2_BMS_a084_SW_Sleep_Wake_Aborted, "ERROR: BMS_a084_SW_Sleep_Wake_Aborted"); + printDebugIfActive(battery2_BMS_a087_SW_Feim_Test_Blocked, "ERROR: BMS_a087_SW_Feim_Test_Blocked"); + printDebugIfActive(battery2_BMS_a088_SW_VcFront_MIA_InDrive, "ERROR: BMS_a088_SW_VcFront_MIA_InDrive"); + printDebugIfActive(battery2_BMS_a089_SW_VcFront_MIA, "ERROR: BMS_a089_SW_VcFront_MIA"); + printDebugIfActive(battery2_BMS_a090_SW_Gateway_MIA, "ERROR: BMS_a090_SW_Gateway_MIA"); + printDebugIfActive(battery2_BMS_a091_SW_ChargePort_MIA, "ERROR: BMS_a091_SW_ChargePort_MIA"); + printDebugIfActive(battery2_BMS_a092_SW_ChargePort_Mia_On_Hv, "ERROR: BMS_a092_SW_ChargePort_Mia_On_Hv"); + printDebugIfActive(battery2_BMS_a094_SW_Drive_Inverter_MIA, "ERROR: BMS_a094_SW_Drive_Inverter_MIA"); + printDebugIfActive(battery2_BMS_a099_SW_BMB_Communication, "ERROR: BMS_a099_SW_BMB_Communication"); + printDebugIfActive(battery2_BMS_a105_SW_One_Module_Tsense, "ERROR: BMS_a105_SW_One_Module_Tsense"); + printDebugIfActive(battery2_BMS_a106_SW_All_Module_Tsense, "ERROR: BMS_a106_SW_All_Module_Tsense"); + printDebugIfActive(battery2_BMS_a107_SW_Stack_Voltage_MIA, "ERROR: BMS_a107_SW_Stack_Voltage_MIA"); + printDebugIfActive(battery2_BMS_a121_SW_NVRAM_Config_Error, "ERROR: BMS_a121_SW_NVRAM_Config_Error"); + printDebugIfActive(battery2_BMS_a122_SW_BMS_Therm_Irrational, "ERROR: BMS_a122_SW_BMS_Therm_Irrational"); + printDebugIfActive(battery2_BMS_a123_SW_Internal_Isolation, "ERROR: BMS_a123_SW_Internal_Isolation"); + printDebugIfActive(battery2_BMS_a127_SW_shunt_SNA, "ERROR: BMS_a127_SW_shunt_SNA"); + printDebugIfActive(battery2_BMS_a128_SW_shunt_MIA, "ERROR: BMS_a128_SW_shunt_MIA"); + printDebugIfActive(battery2_BMS_a129_SW_VSH_Failure, "ERROR: BMS_a129_SW_VSH_Failure"); + printDebugIfActive(battery2_BMS_a130_IO_CAN_Error, "ERROR: BMS_a130_IO_CAN_Error"); + printDebugIfActive(battery2_BMS_a131_Bleed_FET_Failure, "ERROR: BMS_a131_Bleed_FET_Failure"); + printDebugIfActive(battery2_BMS_a132_HW_BMB_OTP_Uncorrctbl, "ERROR: BMS_a132_HW_BMB_OTP_Uncorrctbl"); + printDebugIfActive(battery2_BMS_a134_SW_Delayed_Ctr_Off, "ERROR: BMS_a134_SW_Delayed_Ctr_Off"); + printDebugIfActive(battery2_BMS_a136_SW_Module_OT_Warning, "ERROR: BMS_a136_SW_Module_OT_Warning"); + printDebugIfActive(battery2_BMS_a137_SW_Brick_UV_Warning, "ERROR: BMS_a137_SW_Brick_UV_Warning"); + printDebugIfActive(battery2_BMS_a139_SW_DC_Link_V_Irrational, "ERROR: BMS_a139_SW_DC_Link_V_Irrational"); + printDebugIfActive(battery2_BMS_a141_SW_BMB_Status_Warning, "ERROR: BMS_a141_SW_BMB_Status_Warning"); + printDebugIfActive(battery2_BMS_a144_Hvp_Config_Mismatch, "ERROR: BMS_a144_Hvp_Config_Mismatch"); + printDebugIfActive(battery2_BMS_a145_SW_SOC_Change, "ERROR: BMS_a145_SW_SOC_Change"); + printDebugIfActive(battery2_BMS_a146_SW_Brick_Overdischarged, "ERROR: BMS_a146_SW_Brick_Overdischarged"); + printDebugIfActive(battery2_BMS_a149_SW_Missing_Config_Block, "ERROR: BMS_a149_SW_Missing_Config_Block"); + printDebugIfActive(battery2_BMS_a151_SW_external_isolation, "ERROR: BMS_a151_SW_external_isolation"); + printDebugIfActive(battery2_BMS_a156_SW_BMB_Vref_bad, "ERROR: BMS_a156_SW_BMB_Vref_bad"); + printDebugIfActive(battery2_BMS_a157_SW_HVP_HVS_Comms, "ERROR: BMS_a157_SW_HVP_HVS_Comms"); + printDebugIfActive(battery2_BMS_a158_SW_HVP_HVI_Comms, "ERROR: BMS_a158_SW_HVP_HVI_Comms"); + printDebugIfActive(battery2_BMS_a159_SW_HVP_ECU_Error, "ERROR: BMS_a159_SW_HVP_ECU_Error"); + printDebugIfActive(battery2_BMS_a161_SW_DI_Open_Request, "ERROR: BMS_a161_SW_DI_Open_Request"); + printDebugIfActive(battery2_BMS_a162_SW_No_Power_For_Support, "ERROR: BMS_a162_SW_No_Power_For_Support"); + printDebugIfActive(battery2_BMS_a163_SW_Contactor_Mismatch, "ERROR: BMS_a163_SW_Contactor_Mismatch"); + printDebugIfActive(battery2_BMS_a164_SW_Uncontrolled_Regen, "ERROR: BMS_a164_SW_Uncontrolled_Regen"); + printDebugIfActive(battery2_BMS_a165_SW_Pack_Partial_Weld, "ERROR: BMS_a165_SW_Pack_Partial_Weld"); + printDebugIfActive(battery2_BMS_a166_SW_Pack_Full_Weld, "ERROR: BMS_a166_SW_Pack_Full_Weld"); + printDebugIfActive(battery2_BMS_a167_SW_FC_Partial_Weld, "ERROR: BMS_a167_SW_FC_Partial_Weld"); + printDebugIfActive(battery2_BMS_a168_SW_FC_Full_Weld, "ERROR: BMS_a168_SW_FC_Full_Weld"); + printDebugIfActive(battery2_BMS_a169_SW_FC_Pack_Weld, "ERROR: BMS_a169_SW_FC_Pack_Weld"); + printDebugIfActive(battery2_BMS_a170_SW_Limp_Mode, "ERROR: BMS_a170_SW_Limp_Mode"); + printDebugIfActive(battery2_BMS_a171_SW_Stack_Voltage_Sense, "ERROR: BMS_a171_SW_Stack_Voltage_Sense"); + printDebugIfActive(battery2_BMS_a174_SW_Charge_Failure, "ERROR: BMS_a174_SW_Charge_Failure"); + printDebugIfActive(battery2_BMS_a176_SW_GracefulPowerOff, "ERROR: BMS_a176_SW_GracefulPowerOff"); + printDebugIfActive(battery2_BMS_a179_SW_Hvp_12V_Fault, "ERROR: BMS_a179_SW_Hvp_12V_Fault"); + printDebugIfActive(battery2_BMS_a180_SW_ECU_reset_blocked, "ERROR: BMS_a180_SW_ECU_reset_blocked"); } #endif //DOUBLE_BATTERY void printDebugIfActive(uint8_t symbol, const char* message) { if (symbol == 1) { - Serial.println(message); + logging.println(message); } } diff --git a/Software/src/battery/TESLA-BATTERY.h b/Software/src/battery/TESLA-BATTERY.h index 4f6c1689..817ca1f6 100644 --- a/Software/src/battery/TESLA-BATTERY.h +++ b/Software/src/battery/TESLA-BATTERY.h @@ -35,7 +35,7 @@ void printDebugIfActive(uint8_t symbol, const char* message); void print_int_with_units(char* header, int value, char* units); void print_SOC(char* header, int SOC); void setup_battery(void); -void transmit_can(CAN_frame* tx_frame, int interface); +void transmit_can_frame(CAN_frame* tx_frame, int interface); #ifdef DOUBLE_BATTERY void printFaultCodesIfActive_battery2(); #endif //DOUBLE_BATTERY diff --git a/Software/src/battery/TEST-FAKE-BATTERY.cpp b/Software/src/battery/TEST-FAKE-BATTERY.cpp index 30d9119d..234726fc 100644 --- a/Software/src/battery/TEST-FAKE-BATTERY.cpp +++ b/Software/src/battery/TEST-FAKE-BATTERY.cpp @@ -15,9 +15,9 @@ CAN_frame TEST = {.FD = false, .data = {0x10, 0x64, 0x00, 0xB0, 0x00, 0x1E, 0x00, 0x8F}}; void print_units(char* header, int value, char* units) { - Serial.print(header); - Serial.print(value); - Serial.print(units); + logging.print(header); + logging.print(value); + logging.print(units); } void update_values_battery() { /* This function puts fake values onto the parameters sent towards the inverter */ @@ -54,10 +54,10 @@ void update_values_battery() { /* This function puts fake values onto the parame datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; /*Finally print out values to serial if configured to do so*/ -#ifdef DEBUG_VIA_USB - Serial.println("FAKE Values going to inverter"); - print_units("SOH%: ", (datalayer.battery.status.soh_pptt * 0.01), "% "); - print_units(", SOC%: ", (datalayer.battery.status.reported_soc * 0.01), "% "); +#ifdef DEBUG_LOG + logging.println("FAKE Values going to inverter"); + print_units("SOH: ", (datalayer.battery.status.soh_pptt * 0.01), "pct "); + print_units(", SOC: ", (datalayer.battery.status.reported_soc * 0.01), "pct "); print_units(", Voltage: ", (datalayer.battery.status.voltage_dV * 0.1), "V "); print_units(", Max discharge power: ", datalayer.battery.status.max_discharge_power_W, "W "); print_units(", Max charge power: ", datalayer.battery.status.max_charge_power_W, "W "); @@ -65,7 +65,7 @@ void update_values_battery() { /* This function puts fake values onto the parame print_units(", Min temp: ", (datalayer.battery.status.temperature_min_dC * 0.1), "°C "); print_units(", Max cell voltage: ", datalayer.battery.status.cell_max_voltage_mV, "mV "); print_units(", Min cell voltage: ", datalayer.battery.status.cell_min_voltage_mV, "mV "); - Serial.println(""); + logging.println(""); #endif } @@ -107,10 +107,10 @@ void update_values_battery2() { // Handle the values coming in from battery #2 datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE; /*Finally print out values to serial if configured to do so*/ -#ifdef DEBUG_VIA_USB - Serial.println("FAKE Values battery 2 going to inverter"); - print_units("SOH 2 %: ", (datalayer.battery2.status.soh_pptt * 0.01), "% "); - print_units(", SOC 2 %: ", (datalayer.battery2.status.reported_soc * 0.01), "% "); +#ifdef DEBUG_LOG + logging.println("FAKE Values battery 2 going to inverter"); + print_units("SOH 2: ", (datalayer.battery2.status.soh_pptt * 0.01), "pct "); + print_units(", SOC 2: ", (datalayer.battery2.status.reported_soc * 0.01), "pct "); print_units(", Voltage 2: ", (datalayer.battery2.status.voltage_dV * 0.1), "V "); print_units(", Max discharge power 2: ", datalayer.battery2.status.max_discharge_power_W, "W "); print_units(", Max charge power 2: ", datalayer.battery2.status.max_charge_power_W, "W "); @@ -118,25 +118,25 @@ void update_values_battery2() { // Handle the values coming in from battery #2 print_units(", Min temp 2: ", (datalayer.battery2.status.temperature_min_dC * 0.1), "°C "); print_units(", Max cell voltage 2: ", datalayer.battery2.status.cell_max_voltage_mV, "mV "); print_units(", Min cell voltage 2: ", datalayer.battery2.status.cell_min_voltage_mV, "mV "); - Serial.println(""); + logging.println(""); #endif } -void receive_can_battery2(CAN_frame rx_frame) { +void handle_incoming_can_frame_battery2(CAN_frame rx_frame) { datalayer.battery2.status.CAN_battery_still_alive = CAN_STILL_ALIVE; } #endif // DOUBLE_BATTERY -void receive_can_battery(CAN_frame rx_frame) { +void handle_incoming_can_frame_battery(CAN_frame rx_frame) { datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; } -void send_can_battery() { +void transmit_can_battery() { unsigned long currentMillis = millis(); // Send 100ms CAN Message if (currentMillis - previousMillis100 >= INTERVAL_100_MS) { previousMillis100 = currentMillis; // Put fake messages here incase you want to test sending CAN - //transmit_can(&TEST, can_config.battery); + //transmit_can_frame(&TEST, can_config.battery); } } diff --git a/Software/src/battery/TEST-FAKE-BATTERY.h b/Software/src/battery/TEST-FAKE-BATTERY.h index 27b56fe2..c54f1577 100644 --- a/Software/src/battery/TEST-FAKE-BATTERY.h +++ b/Software/src/battery/TEST-FAKE-BATTERY.h @@ -6,6 +6,6 @@ #define MAX_CELL_DEVIATION_MV 9999 void setup_battery(void); -void transmit_can(CAN_frame* tx_frame, int interface); +void transmit_can_frame(CAN_frame* tx_frame, int interface); #endif diff --git a/Software/src/battery/VOLVO-SPA-BATTERY.cpp b/Software/src/battery/VOLVO-SPA-BATTERY.cpp index 839665c8..15c3c7b8 100644 --- a/Software/src/battery/VOLVO-SPA-BATTERY.cpp +++ b/Software/src/battery/VOLVO-SPA-BATTERY.cpp @@ -94,53 +94,53 @@ void update_values_battery() { //This function maps all the values fetched via datalayer.battery.status.cell_voltages_mV[i] = cell_voltages[i]; } -#ifdef DEBUG_VIA_USB - Serial.print("BMS reported SOC%: "); - Serial.println(SOC_BMS); - Serial.print("Calculated SOC%: "); - Serial.println(SOC_CALC); - Serial.print("Rescaled SOC%: "); - Serial.println(datalayer.battery.status.reported_soc / 100); - Serial.print("Battery current: "); - Serial.println(BATT_I); - Serial.print("Battery voltage: "); - Serial.println(BATT_U); - Serial.print("Battery maximum voltage limit: "); - Serial.println(MAX_U); - Serial.print("Battery minimum voltage limit: "); - Serial.println(MIN_U); - Serial.print("Remaining Energy: "); - Serial.println(remaining_capacity); - Serial.print("Discharge limit: "); - Serial.println(HvBattPwrLimDchaSoft); - Serial.print("Battery Error Indication: "); - Serial.println(BATT_ERR_INDICATION); - Serial.print("Maximum battery temperature: "); - Serial.println(BATT_T_MAX / 10); - Serial.print("Minimum battery temperature: "); - Serial.println(BATT_T_MIN / 10); - Serial.print("Average battery temperature: "); - Serial.println(BATT_T_AVG / 10); - Serial.print("BMS Highest cell voltage: "); - Serial.println(CELL_U_MAX * 10); - Serial.print("BMS Lowest cell voltage: "); - Serial.println(CELL_U_MIN * 10); - Serial.print("BMS Highest cell nr: "); - Serial.println(CELL_ID_U_MAX); - Serial.print("Highest cell voltage: "); - Serial.println(min_max_voltage[1]); - Serial.print("Lowest cell voltage: "); - Serial.println(min_max_voltage[0]); - Serial.print("Cell voltage,"); +#ifdef DEBUG_LOG + logging.print("BMS reported SOC: "); + logging.println(SOC_BMS); + logging.print("Calculated SOC: "); + logging.println(SOC_CALC); + logging.print("Rescaled SOC: "); + logging.println(datalayer.battery.status.reported_soc / 100); + logging.print("Battery current: "); + logging.println(BATT_I); + logging.print("Battery voltage: "); + logging.println(BATT_U); + logging.print("Battery maximum voltage limit: "); + logging.println(MAX_U); + logging.print("Battery minimum voltage limit: "); + logging.println(MIN_U); + logging.print("Remaining Energy: "); + logging.println(remaining_capacity); + logging.print("Discharge limit: "); + logging.println(HvBattPwrLimDchaSoft); + logging.print("Battery Error Indication: "); + logging.println(BATT_ERR_INDICATION); + logging.print("Maximum battery temperature: "); + logging.println(BATT_T_MAX / 10); + logging.print("Minimum battery temperature: "); + logging.println(BATT_T_MIN / 10); + logging.print("Average battery temperature: "); + logging.println(BATT_T_AVG / 10); + logging.print("BMS Highest cell voltage: "); + logging.println(CELL_U_MAX * 10); + logging.print("BMS Lowest cell voltage: "); + logging.println(CELL_U_MIN * 10); + logging.print("BMS Highest cell nr: "); + logging.println(CELL_ID_U_MAX); + logging.print("Highest cell voltage: "); + logging.println(min_max_voltage[1]); + logging.print("Lowest cell voltage: "); + logging.println(min_max_voltage[0]); + logging.print("Cell voltage,"); while (cnt < 108) { - Serial.print(cell_voltages[cnt++]); - Serial.print(","); + logging.print(cell_voltages[cnt++]); + logging.print(","); } - Serial.println(";"); + logging.println(";"); #endif } -void receive_can_battery(CAN_frame rx_frame) { +void handle_incoming_can_frame_battery(CAN_frame rx_frame) { datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; switch (rx_frame.ID) { case 0x3A: @@ -148,8 +148,8 @@ void receive_can_battery(CAN_frame rx_frame) { BATT_I = (0 - ((((rx_frame.data.u8[6] & 0x7F) * 256.0 + rx_frame.data.u8[7]) * 0.1) - 1638)); else { BATT_I = 0; -#ifdef DEBUG_VIA_USB - Serial.println("BATT_I not valid"); +#ifdef DEBUG_LOG + logging.println("BATT_I not valid"); #endif } @@ -157,22 +157,22 @@ void receive_can_battery(CAN_frame rx_frame) { MAX_U = (((rx_frame.data.u8[2] & 0x07) * 256.0 + rx_frame.data.u8[3]) * 0.25); else { //MAX_U = 0; - //Serial.println("MAX_U not valid"); // Value toggles between true/false from BMS + //logging.println("MAX_U not valid"); // Value toggles between true/false from BMS } if ((rx_frame.data.u8[4] & 0x08) == 0x08) MIN_U = (((rx_frame.data.u8[4] & 0x07) * 256.0 + rx_frame.data.u8[5]) * 0.25); else { //MIN_U = 0; - //Serial.println("MIN_U not valid"); // Value toggles between true/false from BMS + //logging.println("MIN_U not valid"); // Value toggles between true/false from BMS } if ((rx_frame.data.u8[0] & 0x08) == 0x08) BATT_U = (((rx_frame.data.u8[0] & 0x07) * 256.0 + rx_frame.data.u8[1]) * 0.25); else { BATT_U = 0; -#ifdef DEBUG_VIA_USB - Serial.println("BATT_U not valid"); +#ifdef DEBUG_LOG + logging.println("BATT_U not valid"); #endif } break; @@ -189,8 +189,8 @@ void receive_can_battery(CAN_frame rx_frame) { BATT_ERR_INDICATION = ((rx_frame.data.u8[0] & 0x40) >> 6); else { BATT_ERR_INDICATION = 0; -#ifdef DEBUG_VIA_USB - Serial.println("BATT_ERR_INDICATION not valid"); +#ifdef DEBUG_LOG + logging.println("BATT_ERR_INDICATION not valid"); #endif } if ((rx_frame.data.u8[0] & 0x20) == 0x20) { @@ -201,8 +201,8 @@ void receive_can_battery(CAN_frame rx_frame) { BATT_T_MAX = 0; BATT_T_MIN = 0; BATT_T_AVG = 0; -#ifdef DEBUG_VIA_USB - Serial.println("BATT_T not valid"); +#ifdef DEBUG_LOG + logging.println("BATT_T not valid"); #endif } break; @@ -211,8 +211,8 @@ void receive_can_battery(CAN_frame rx_frame) { HvBattPwrLimDchaSoft = (((rx_frame.data.u8[6] & 0x03) * 256 + rx_frame.data.u8[6]) >> 2); } else { HvBattPwrLimDchaSoft = 0; -#ifdef DEBUG_VIA_USB - Serial.println("HvBattPwrLimDchaSoft not valid"); +#ifdef DEBUG_LOG + logging.println("HvBattPwrLimDchaSoft not valid"); #endif } break; @@ -221,8 +221,8 @@ void receive_can_battery(CAN_frame rx_frame) { SOC_BMS = ((rx_frame.data.u8[6] & 0x03) * 256 + rx_frame.data.u8[7]); } else { SOC_BMS = 0; -#ifdef DEBUG_VIA_USB - Serial.println("SOC_BMS not valid"); +#ifdef DEBUG_LOG + logging.println("SOC_BMS not valid"); #endif } @@ -230,8 +230,8 @@ void receive_can_battery(CAN_frame rx_frame) { CELL_U_MAX = ((rx_frame.data.u8[2] & 0x01) * 256 + rx_frame.data.u8[3]); else { CELL_U_MAX = 0; -#ifdef DEBUG_VIA_USB - Serial.println("CELL_U_MAX not valid"); +#ifdef DEBUG_LOG + logging.println("CELL_U_MAX not valid"); #endif } @@ -239,8 +239,8 @@ void receive_can_battery(CAN_frame rx_frame) { CELL_U_MIN = ((rx_frame.data.u8[0] & 0x01) * 256.0 + rx_frame.data.u8[1]); else { CELL_U_MIN = 0; -#ifdef DEBUG_VIA_USB - Serial.println("CELL_U_MIN not valid"); +#ifdef DEBUG_LOG + logging.println("CELL_U_MIN not valid"); #endif } @@ -248,8 +248,8 @@ void receive_can_battery(CAN_frame rx_frame) { CELL_ID_U_MAX = ((rx_frame.data.u8[4] & 0x01) * 256.0 + rx_frame.data.u8[5]); else { CELL_ID_U_MAX = 0; -#ifdef DEBUG_VIA_USB - Serial.println("CELL_ID_U_MAX not valid"); +#ifdef DEBUG_LOG + logging.println("CELL_ID_U_MAX not valid"); #endif } break; @@ -263,7 +263,7 @@ void receive_can_battery(CAN_frame rx_frame) { { cell_voltages[battery_request_idx++] = ((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6]); cell_voltages[battery_request_idx] = (rx_frame.data.u8[7] << 8); - transmit_can(&VOLVO_FlowControl, can_config.battery); // Send flow control + transmit_can_frame(&VOLVO_FlowControl, can_config.battery); // Send flow control rxConsecutiveFrames = 1; } else if ((rx_frame.data.u8[0] == 0x21) && (rxConsecutiveFrames == 1)) { cell_voltages[battery_request_idx++] = cell_voltages[battery_request_idx] | rx_frame.data.u8[1]; @@ -273,7 +273,7 @@ void receive_can_battery(CAN_frame rx_frame) { if (batteryModuleNumber <= 0x2A) // Run until last pack is read { VOLVO_CELL_U_Req.data.u8[3] = batteryModuleNumber++; - transmit_can(&VOLVO_CELL_U_Req, can_config.battery); //Send cell voltage read request for next module + transmit_can_frame(&VOLVO_CELL_U_Req, can_config.battery); //Send cell voltage read request for next module } else { min_max_voltage[0] = 9999; min_max_voltage[1] = 0; @@ -284,7 +284,7 @@ void receive_can_battery(CAN_frame rx_frame) { min_max_voltage[1] = cell_voltages[cellcounter]; } - transmit_can(&VOLVO_SOH_Req, can_config.battery); //Send SOH read request + transmit_can_frame(&VOLVO_SOH_Req, can_config.battery); //Send SOH read request } rxConsecutiveFrames = 0; } @@ -299,10 +299,10 @@ void readCellVoltages() { batteryModuleNumber = 0x10; rxConsecutiveFrames = 0; VOLVO_CELL_U_Req.data.u8[3] = batteryModuleNumber++; - transmit_can(&VOLVO_CELL_U_Req, can_config.battery); //Send cell voltage read request for first module + transmit_can_frame(&VOLVO_CELL_U_Req, can_config.battery); //Send cell voltage read request for first module } -void send_can_battery() { +void transmit_can_battery() { unsigned long currentMillis = millis(); // Send 100ms CAN Message if (currentMillis - previousMillis100 >= INTERVAL_100_MS) { @@ -314,8 +314,8 @@ void send_can_battery() { } previousMillis100 = currentMillis; - transmit_can(&VOLVO_536, can_config.battery); //Send 0x536 Network managing frame to keep BMS alive - transmit_can(&VOLVO_372, can_config.battery); //Send 0x372 ECMAmbientTempCalculated + transmit_can_frame(&VOLVO_536, can_config.battery); //Send 0x536 Network managing frame to keep BMS alive + transmit_can_frame(&VOLVO_372, can_config.battery); //Send 0x372 ECMAmbientTempCalculated if (datalayer.battery.status.bms_status == ACTIVE) { datalayer.system.status.battery_allows_contactor_closing = true; diff --git a/Software/src/battery/VOLVO-SPA-BATTERY.h b/Software/src/battery/VOLVO-SPA-BATTERY.h index 76c28074..6dcda0e7 100644 --- a/Software/src/battery/VOLVO-SPA-BATTERY.h +++ b/Software/src/battery/VOLVO-SPA-BATTERY.h @@ -11,6 +11,6 @@ #define MIN_CELL_VOLTAGE_MV 2700 //Battery is put into emergency stop if one cell goes below this value void setup_battery(void); -void transmit_can(CAN_frame* tx_frame, int interface); +void transmit_can_frame(CAN_frame* tx_frame, int interface); #endif diff --git a/Software/src/charger/CHARGERS.h b/Software/src/charger/CHARGERS.h index 7aa68c77..a41b5bc9 100644 --- a/Software/src/charger/CHARGERS.h +++ b/Software/src/charger/CHARGERS.h @@ -10,7 +10,7 @@ #include "NISSAN-LEAF-CHARGER.h" #endif -void receive_can_charger(CAN_frame rx_frame); -void send_can_charger(); +void map_can_frame_to_variable_charger(CAN_frame rx_frame); +void transmit_can_charger(); #endif diff --git a/Software/src/charger/CHEVY-VOLT-CHARGER.cpp b/Software/src/charger/CHEVY-VOLT-CHARGER.cpp index 75cfd021..849e219e 100644 --- a/Software/src/charger/CHEVY-VOLT-CHARGER.cpp +++ b/Software/src/charger/CHEVY-VOLT-CHARGER.cpp @@ -56,7 +56,7 @@ static CAN_frame charger_set_targets = { .data = {0x40, 0x00, 0x00, 0x00}}; // data[0] is a static value, meaning unknown /* We are mostly sending out not receiving */ -void receive_can_charger(CAN_frame rx_frame) { +void map_can_frame_to_variable_charger(CAN_frame rx_frame) { uint16_t charger_stat_HVcur_temp = 0; uint16_t charger_stat_HVvol_temp = 0; uint16_t charger_stat_LVcur_temp = 0; @@ -101,14 +101,11 @@ void receive_can_charger(CAN_frame rx_frame) { case 0x308: break; default: -#ifdef DEBUG_VIA_USB - Serial.printf("CAN Rcv unknown frame MsgID=%x\n", rx_frame.MsgID); -#endif break; } } -void send_can_charger() { +void transmit_can_charger() { unsigned long currentMillis = millis(); uint16_t Vol_temp = 0; @@ -137,7 +134,7 @@ void send_can_charger() { charger_keepalive_frame.data.u8[0] = charger_mode; - transmit_can(&charger_keepalive_frame, can_config.charger); + transmit_can_frame(&charger_keepalive_frame, can_config.charger); } /* Send current targets every 200ms */ @@ -174,18 +171,18 @@ void send_can_charger() { /* LSB of the voltage command. Then MSB LSB is divided by 2 */ charger_set_targets.data.u8[3] = lowByte(Vol_temp); - transmit_can(&charger_set_targets, can_config.charger); + transmit_can_frame(&charger_set_targets, can_config.charger); } -#ifdef DEBUG_VIA_USB +#ifdef DEBUG_LOG /* Serial echo every 5s of charger stats */ if (currentMillis - previousMillis5000ms >= INTERVAL_5_S) { previousMillis5000ms = currentMillis; - Serial.printf("Charger AC in IAC=%fA VAC=%fV\n", charger_stat_ACcur, charger_stat_ACvol); - Serial.printf("Charger HV out IDC=%fA VDC=%fV\n", charger_stat_HVcur, charger_stat_HVvol); - Serial.printf("Charger LV out IDC=%fA VDC=%fV\n", charger_stat_LVcur, charger_stat_LVvol); - Serial.printf("Charger mode=%s\n", (charger_mode > MODE_DISABLED) ? "Enabled" : "Disabled"); - Serial.printf("Charger HVset=%uV,%uA finishCurrent=%uA\n", setpoint_HV_VDC, setpoint_HV_IDC, setpoint_HV_IDC_END); + logging.printf("Charger AC in IAC=%fA VAC=%fV\n", charger_stat_ACcur, charger_stat_ACvol); + logging.printf("Charger HV out IDC=%fA VDC=%fV\n", charger_stat_HVcur, charger_stat_HVvol); + logging.printf("Charger LV out IDC=%fA VDC=%fV\n", charger_stat_LVcur, charger_stat_LVvol); + logging.printf("Charger mode=%s\n", (charger_mode > MODE_DISABLED) ? "Enabled" : "Disabled"); + logging.printf("Charger HVset=%uV,%uA finishCurrent=%uA\n", setpoint_HV_VDC, setpoint_HV_IDC, setpoint_HV_IDC_END); } #endif } diff --git a/Software/src/charger/NISSAN-LEAF-CHARGER.cpp b/Software/src/charger/NISSAN-LEAF-CHARGER.cpp index 0c756cf9..104e6a9b 100644 --- a/Software/src/charger/NISSAN-LEAF-CHARGER.cpp +++ b/Software/src/charger/NISSAN-LEAF-CHARGER.cpp @@ -129,7 +129,7 @@ static uint8_t calculate_checksum_nibble(CAN_frame* frame) { return sum; } -void receive_can_charger(CAN_frame rx_frame) { +void map_can_frame_to_variable_charger(CAN_frame rx_frame) { switch (rx_frame.ID) { case 0x679: // This message fires once when charging cable is plugged in @@ -166,7 +166,7 @@ void receive_can_charger(CAN_frame rx_frame) { } } -void send_can_charger() { +void transmit_can_charger() { unsigned long currentMillis = millis(); /* Send keepalive with mode every 10ms */ @@ -182,13 +182,13 @@ void send_can_charger() { #ifndef NISSAN_LEAF_BATTERY // VCM message, containing info if battery should sleep or stay awake - transmit_can(&LEAF_50B, can_config.charger); // HCM_WakeUpSleepCommand == 11b == WakeUp, and CANMASK = 1 + transmit_can_frame(&LEAF_50B, can_config.charger); // HCM_WakeUpSleepCommand == 11b == WakeUp, and CANMASK = 1 LEAF_1DB.data.u8[7] = calculate_CRC_Nissan(&LEAF_1DB); - transmit_can(&LEAF_1DB, can_config.charger); + transmit_can_frame(&LEAF_1DB, can_config.charger); LEAF_1DC.data.u8[7] = calculate_CRC_Nissan(&LEAF_1DC); - transmit_can(&LEAF_1DC, can_config.charger); + transmit_can_frame(&LEAF_1DC, can_config.charger); #endif OBCpowerSetpoint = ((charger_setpoint_HV_IDC * 4) + 0x64); @@ -233,8 +233,9 @@ void send_can_charger() { LEAF_1F2.data.u8[6] = mprun10; LEAF_1F2.data.u8[7] = calculate_checksum_nibble(&LEAF_1F2); - transmit_can(&LEAF_1F2, - can_config.charger); // Sending of 1F2 message is halted in LEAF-BATTERY function incase used here + transmit_can_frame( + &LEAF_1F2, + can_config.charger); // Sending of 1F2 message is halted in LEAF-BATTERY function incase used here } /* Send messages every 100ms here */ @@ -252,11 +253,11 @@ void send_can_charger() { LEAF_55B.data.u8[6] = ((0x1 << 4) | (mprun100)); LEAF_55B.data.u8[7] = calculate_CRC_Nissan(&LEAF_55B); - transmit_can(&LEAF_55B, can_config.charger); + transmit_can_frame(&LEAF_55B, can_config.charger); - transmit_can(&LEAF_59E, can_config.charger); + transmit_can_frame(&LEAF_59E, can_config.charger); - transmit_can(&LEAF_5BC, can_config.charger); + transmit_can_frame(&LEAF_5BC, can_config.charger); #endif } } diff --git a/Software/src/communication/can/comm_can.cpp b/Software/src/communication/can/comm_can.cpp index ac92faba..e4997826 100644 --- a/Software/src/communication/can/comm_can.cpp +++ b/Software/src/communication/can/comm_can.cpp @@ -1,5 +1,6 @@ #include "comm_can.h" #include "../../include.h" +#include "src/devboard/sdcard/sdcard.h" // Parameters @@ -9,11 +10,13 @@ volatile bool send_ok = 0; #ifdef CAN_ADDON static const uint32_t QUARTZ_FREQUENCY = CRYSTAL_FREQUENCY_MHZ * 1000000UL; //MHZ configured in USER_SETTINGS.h -ACAN2515 can(MCP2515_CS, SPI, MCP2515_INT); +SPIClass SPI2515; +ACAN2515 can(MCP2515_CS, SPI2515, MCP2515_INT); static ACAN2515_Buffer16 gBuffer; #endif //CAN_ADDON #ifdef CANFD_ADDON -ACAN2517FD canfd(MCP2517_CS, SPI, MCP2517_INT); +SPIClass SPI2517; +ACAN2517FD canfd(MCP2517_CS, SPI2517, MCP2517_INT); #endif //CANFD_ADDON // Initialization functions @@ -35,78 +38,100 @@ void init_CAN() { ESP32Can.CANInit(); #ifdef CAN_ADDON -#ifdef DEBUG_VIA_USB - Serial.println("Dual CAN Bus (ESP32+MCP2515) selected"); -#endif // DEBUG_VIA_USB +#ifdef DEBUG_LOG + logging.println("Dual CAN Bus (ESP32+MCP2515) selected"); +#endif // DEBUG_LOG gBuffer.initWithSize(25); - SPI.begin(MCP2515_SCK, MCP2515_MISO, MCP2515_MOSI); - ACAN2515Settings settings(QUARTZ_FREQUENCY, 500UL * 1000UL); // CAN bit rate 500 kb/s - settings.mRequestedMode = ACAN2515Settings::NormalMode; - const uint16_t errorCodeMCP = can.begin(settings, [] { can.isr(); }); - if (errorCodeMCP == 0) { -#ifdef DEBUG_VIA_USB - Serial.println("Can ok"); -#endif // DEBUG_VIA_USB + SPI2515.begin(MCP2515_SCK, MCP2515_MISO, MCP2515_MOSI); + ACAN2515Settings settings2515(QUARTZ_FREQUENCY, 500UL * 1000UL); // CAN bit rate 500 kb/s + settings2515.mRequestedMode = ACAN2515Settings::NormalMode; + const uint16_t errorCode2515 = can.begin(settings2515, [] { can.isr(); }); + if (errorCode2515 == 0) { +#ifdef DEBUG_LOG + logging.println("Can ok"); +#endif // DEBUG_LOG } else { -#ifdef DEBUG_VIA_USB - Serial.print("Error Can: 0x"); - Serial.println(errorCodeMCP, HEX); -#endif // DEBUG_VIA_USB - set_event(EVENT_CANMCP_INIT_FAILURE, (uint8_t)errorCodeMCP); +#ifdef DEBUG_LOG + logging.print("Error Can: 0x"); + logging.println(errorCode2515, HEX); +#endif // DEBUG_LOG + set_event(EVENT_CANMCP2515_INIT_FAILURE, (uint8_t)errorCode2515); } #endif // CAN_ADDON #ifdef CANFD_ADDON -#ifdef DEBUG_VIA_USB - Serial.println("CAN FD add-on (ESP32+MCP2517) selected"); -#endif // DEBUG_VIA_USB - SPI.begin(MCP2517_SCK, MCP2517_SDO, MCP2517_SDI); - ACAN2517FDSettings settings(CANFD_ADDON_CRYSTAL_FREQUENCY_MHZ, 500 * 1000, - DataBitRateFactor::x4); // Arbitration bit rate: 500 kbit/s, data bit rate: 2 Mbit/s +#ifdef DEBUG_LOG + logging.println("CAN FD add-on (ESP32+MCP2517) selected"); +#endif // DEBUG_LOG + SPI2517.begin(MCP2517_SCK, MCP2517_SDO, MCP2517_SDI); + ACAN2517FDSettings settings2517(CANFD_ADDON_CRYSTAL_FREQUENCY_MHZ, 500 * 1000, + DataBitRateFactor::x4); // Arbitration bit rate: 500 kbit/s, data bit rate: 2 Mbit/s #ifdef USE_CANFD_INTERFACE_AS_CLASSIC_CAN - settings.mRequestedMode = ACAN2517FDSettings::Normal20B; // ListenOnly / Normal20B / NormalFD -#else // not USE_CANFD_INTERFACE_AS_CLASSIC_CAN - settings.mRequestedMode = ACAN2517FDSettings::NormalFD; // ListenOnly / Normal20B / NormalFD -#endif // USE_CANFD_INTERFACE_AS_CLASSIC_CAN - const uint32_t errorCode = canfd.begin(settings, [] { canfd.isr(); }); + settings2517.mRequestedMode = ACAN2517FDSettings::Normal20B; // ListenOnly / Normal20B / NormalFD +#else // not USE_CANFD_INTERFACE_AS_CLASSIC_CAN + settings2517.mRequestedMode = ACAN2517FDSettings::NormalFD; // ListenOnly / Normal20B / NormalFD +#endif // USE_CANFD_INTERFACE_AS_CLASSIC_CAN + const uint32_t errorCode2517 = canfd.begin(settings2517, [] { canfd.isr(); }); canfd.poll(); - if (errorCode == 0) { -#ifdef DEBUG_VIA_USB - Serial.print("Bit Rate prescaler: "); - Serial.println(settings.mBitRatePrescaler); - Serial.print("Arbitration Phase segment 1: "); - Serial.println(settings.mArbitrationPhaseSegment1); - Serial.print("Arbitration Phase segment 2: "); - Serial.println(settings.mArbitrationPhaseSegment2); - Serial.print("Arbitration SJW:"); - Serial.println(settings.mArbitrationSJW); - Serial.print("Actual Arbitration Bit Rate: "); - Serial.print(settings.actualArbitrationBitRate()); - Serial.println(" bit/s"); - Serial.print("Exact Arbitration Bit Rate ? "); - Serial.println(settings.exactArbitrationBitRate() ? "yes" : "no"); - Serial.print("Arbitration Sample point: "); - Serial.print(settings.arbitrationSamplePointFromBitStart()); - Serial.println("%"); -#endif // DEBUG_VIA_USB + if (errorCode2517 == 0) { +#ifdef DEBUG_LOG + logging.print("Bit Rate prescaler: "); + logging.println(settings2517.mBitRatePrescaler); + logging.print("Arbitration Phase segment 1: "); + logging.print(settings2517.mArbitrationPhaseSegment1); + logging.print(" segment 2: "); + logging.print(settings2517.mArbitrationPhaseSegment2); + logging.print(" SJW: "); + logging.println(settings2517.mArbitrationSJW); + logging.print("Actual Arbitration Bit Rate: "); + logging.print(settings2517.actualArbitrationBitRate()); + logging.print(" bit/s"); + logging.print(" (Exact:"); + logging.println(settings2517.exactArbitrationBitRate() ? "yes)" : "no)"); + logging.print("Arbitration Sample point: "); + logging.print(settings2517.arbitrationSamplePointFromBitStart()); + logging.println("pct"); +#endif // DEBUG_LOG } else { -#ifdef DEBUG_VIA_USB - Serial.print("CAN-FD Configuration error 0x"); - Serial.println(errorCode, HEX); -#endif // DEBUG_VIA_USB - set_event(EVENT_CANFD_INIT_FAILURE, (uint8_t)errorCode); +#ifdef DEBUG_LOG + logging.print("CAN-FD Configuration error 0x"); + logging.println(errorCode2517, HEX); +#endif // DEBUG_LOG + set_event(EVENT_CANMCP2517FD_INIT_FAILURE, (uint8_t)errorCode2517); } #endif // CANFD_ADDON } // Transmit functions +void transmit_can() { + if (!allowed_to_send_CAN) { + return; + } + transmit_can_battery(); -void transmit_can(CAN_frame* tx_frame, int interface) { +#ifdef CAN_INVERTER_SELECTED + transmit_can_inverter(); +#endif // CAN_INVERTER_SELECTED + +#ifdef CHARGER_SELECTED + transmit_can_charger(); +#endif // CHARGER_SELECTED + +#ifdef CAN_SHUNT_SELECTED + transmit_can_shunt(); +#endif // CAN_SHUNT_SELECTED +} + +void transmit_can_frame(CAN_frame* tx_frame, int interface) { if (!allowed_to_send_CAN) { return; } print_can_frame(*tx_frame, frameDirection(MSG_TX)); +#ifdef LOG_CAN_TO_SD + add_can_frame_to_buffer(*tx_frame, frameDirection(MSG_TX)); +#endif + switch (interface) { case CAN_NATIVE: CAN_frame_t frame; @@ -153,6 +178,8 @@ void transmit_can(CAN_frame* tx_frame, int interface) { send_ok = canfd.tryToSend(MCP2518Frame); if (!send_ok) { set_event(EVENT_CANFD_BUFFER_FULL, interface); + } else { + clear_event(EVENT_CANFD_BUFFER_FULL); } #else // Interface not compiled, and settings try to use it set_event(EVENT_INTERFACE_MISSING, interface); @@ -164,58 +191,18 @@ void transmit_can(CAN_frame* tx_frame, int interface) { } } -void send_can() { - if (!allowed_to_send_CAN) { - return; - } - send_can_battery(); - -#ifdef CAN_INVERTER_SELECTED - send_can_inverter(); -#endif // CAN_INVERTER_SELECTED - -#ifdef CHARGER_SELECTED - send_can_charger(); -#endif // CHARGER_SELECTED -#ifdef CAN_SHUNT_SELECTED - send_can_shunt(); -#endif // CAN_SHUNT_SELECTED -} - // Receive functions - -void receive_can(CAN_frame* rx_frame, int interface) { - print_can_frame(*rx_frame, frameDirection(MSG_RX)); - - if (interface == can_config.battery) { - receive_can_battery(*rx_frame); -#ifdef CHADEMO_BATTERY - ISA_handleFrame(rx_frame); -#endif - } - if (interface == can_config.inverter) { -#ifdef CAN_INVERTER_SELECTED - receive_can_inverter(*rx_frame); -#endif - } - if (interface == can_config.battery_double) { -#ifdef DOUBLE_BATTERY - receive_can_battery2(*rx_frame); -#endif - } - if (interface == can_config.charger) { -#ifdef CHARGER_SELECTED - receive_can_charger(*rx_frame); -#endif - } - if (interface == can_config.shunt) { -#ifdef CAN_SHUNT_SELECTED - receive_can_shunt(*rx_frame); -#endif - } +void receive_can() { + receive_frame_can_native(); // Receive CAN messages from native CAN port +#ifdef CAN_ADDON + receive_frame_can_addon(); // Receive CAN messages on add-on MCP2515 chip +#endif // CAN_ADDON +#ifdef CANFD_ADDON + receive_frame_canfd_addon(); // Receive CAN-FD messages. +#endif // CANFD_ADDON } -void receive_can_native() { // This section checks if we have a complete CAN message incoming on native CAN port +void receive_frame_can_native() { // This section checks if we have a complete CAN message incoming on native CAN port CAN_frame_t rx_frame_native; if (xQueueReceive(CAN_cfg.rx_queue, &rx_frame_native, 0) == pdTRUE) { CAN_frame rx_frame; @@ -230,47 +217,46 @@ void receive_can_native() { // This section checks if we have a complete CAN me rx_frame.data.u8[i] = rx_frame_native.data.u8[i]; } //message incoming, pass it on to the handler - receive_can(&rx_frame, CAN_NATIVE); + map_can_frame_to_variable(&rx_frame, CAN_NATIVE); } } #ifdef CAN_ADDON -void receive_can_addon() { // This section checks if we have a complete CAN message incoming on add-on CAN port - CAN_frame rx_frame; // Struct with our CAN format - CANMessage MCP2515Frame; // Struct with ACAN2515 library format, needed to use the MCP2515 library +void receive_frame_can_addon() { // This section checks if we have a complete CAN message incoming on add-on CAN port + CAN_frame rx_frame; // Struct with our CAN format + CANMessage MCP2515frame; // Struct with ACAN2515 library format, needed to use the MCP2515 library if (can.available()) { - can.receive(MCP2515Frame); + can.receive(MCP2515frame); - rx_frame.ID = MCP2515Frame.id; - rx_frame.ext_ID = MCP2515Frame.ext ? CAN_frame_ext : CAN_frame_std; - rx_frame.DLC = MCP2515Frame.len; - for (uint8_t i = 0; i < MCP2515Frame.len && i < 8; i++) { - rx_frame.data.u8[i] = MCP2515Frame.data[i]; + rx_frame.ID = MCP2515frame.id; + rx_frame.ext_ID = MCP2515frame.ext ? CAN_frame_ext : CAN_frame_std; + rx_frame.DLC = MCP2515frame.len; + for (uint8_t i = 0; i < MCP2515frame.len && i < 8; i++) { + rx_frame.data.u8[i] = MCP2515frame.data[i]; } //message incoming, pass it on to the handler - receive_can(&rx_frame, CAN_ADDON_MCP2515); + map_can_frame_to_variable(&rx_frame, CAN_ADDON_MCP2515); } } #endif // CAN_ADDON #ifdef CANFD_ADDON -// Functions -void receive_canfd_addon() { // This section checks if we have a complete CAN-FD message incoming - CANFDMessage frame; +void receive_frame_canfd_addon() { // This section checks if we have a complete CAN-FD message incoming + CANFDMessage MCP2518frame; int count = 0; while (canfd.available() && count++ < 16) { - canfd.receive(frame); + canfd.receive(MCP2518frame); CAN_frame rx_frame; - rx_frame.ID = frame.id; - rx_frame.ext_ID = frame.ext; - rx_frame.DLC = frame.len; - memcpy(rx_frame.data.u8, frame.data, MIN(rx_frame.DLC, 64)); + rx_frame.ID = MCP2518frame.id; + rx_frame.ext_ID = MCP2518frame.ext; + rx_frame.DLC = MCP2518frame.len; + memcpy(rx_frame.data.u8, MCP2518frame.data, MIN(rx_frame.DLC, 64)); //message incoming, pass it on to the handler - receive_can(&rx_frame, CANFD_ADDON_MCP2518); - receive_can(&rx_frame, CANFD_NATIVE); + map_can_frame_to_variable(&rx_frame, CANFD_ADDON_MCP2518); + map_can_frame_to_variable(&rx_frame, CANFD_NATIVE); } } #endif // CANFD_ADDON @@ -330,3 +316,38 @@ void print_can_frame(CAN_frame frame, frameDirection msgDir) { datalayer.system.info.logged_can_messages_offset = offset; // Update offset in buffer } } + +void map_can_frame_to_variable(CAN_frame* rx_frame, int interface) { + print_can_frame(*rx_frame, frameDirection(MSG_RX)); + +#ifdef LOG_CAN_TO_SD + add_can_frame_to_buffer(*rx_frame, frameDirection(MSG_RX)); +#endif + + if (interface == can_config.battery) { + handle_incoming_can_frame_battery(*rx_frame); +#ifdef CHADEMO_BATTERY + ISA_handleFrame(rx_frame); +#endif + } + if (interface == can_config.inverter) { +#ifdef CAN_INVERTER_SELECTED + map_can_frame_to_variable_inverter(*rx_frame); +#endif + } + if (interface == can_config.battery_double) { +#ifdef DOUBLE_BATTERY + handle_incoming_can_frame_battery2(*rx_frame); +#endif + } + if (interface == can_config.charger) { +#ifdef CHARGER_SELECTED + map_can_frame_to_variable_charger(*rx_frame); +#endif + } + if (interface == can_config.shunt) { +#ifdef CAN_SHUNT_SELECTED + map_can_frame_to_variable_shunt(*rx_frame); +#endif + } +} diff --git a/Software/src/communication/can/comm_can.h b/Software/src/communication/can/comm_can.h index 48e3c9c3..a5117f16 100644 --- a/Software/src/communication/can/comm_can.h +++ b/Software/src/communication/can/comm_can.h @@ -15,8 +15,6 @@ #include "../../lib/pierremolinaro-ACAN2517FD/ACAN2517FD.h" #endif //CANFD_ADDON -enum frameDirection { MSG_RX, MSG_TX }; //RX = 0, TX = 1 - /** * @brief Initialization function for CAN. * @@ -34,7 +32,7 @@ void init_CAN(); * * @return void */ -void transmit_can(); +void transmit_can_frame(); /** * @brief Send CAN messages to all components @@ -43,7 +41,7 @@ void transmit_can(); * * @return void */ -void send_can(); +void transmit_can(); /** * @brief Receive CAN messages from all interfaces @@ -61,7 +59,7 @@ void receive_can(); * * @return void */ -void receive_can_native(); +void receive_frame_can_native(); /** * @brief Receive CAN messages from CAN addon chip @@ -70,7 +68,7 @@ void receive_can_native(); * * @return void */ -void receive_can_addon(); +void receive_frame_can_addon(); /** * @brief Receive CAN messages from CANFD addon chip @@ -79,7 +77,7 @@ void receive_can_addon(); * * @return void */ -void receive_canfd_addon(); +void receive_frame_canfd_addon(); /** * @brief print CAN frames via USB @@ -90,4 +88,14 @@ void receive_canfd_addon(); */ void print_can_frame(CAN_frame frame, frameDirection msgDir); +/** + * @brief Map CAN frame from specified interface to variable + * + * @param[in] CAN_frame* rx_frame + * @param[in] int interface + * + * @return void + */ +void map_can_frame_to_variable(CAN_frame* rx_frame, int interface); + #endif diff --git a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp index c09e6c17..b45aec89 100644 --- a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp +++ b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp @@ -90,9 +90,9 @@ void init_contactors() { // Main functions void handle_contactors() { -#ifdef BYD_SMA +#if defined(SMA_BYD_H_CAN) || defined(SMA_BYD_HVS_CAN) || defined(SMA_TRIPOWER_CAN) datalayer.system.status.inverter_allows_contactor_closing = digitalRead(INVERTER_CONTACTOR_ENABLE_PIN); -#endif // BYD_SMA +#endif #ifdef CONTACTOR_CONTROL_DOUBLE_BATTERY handle_contactors_battery2(); diff --git a/Software/src/datalayer/datalayer.h b/Software/src/datalayer/datalayer.h index 6be174c1..7fce0122 100644 --- a/Software/src/datalayer/datalayer.h +++ b/Software/src/datalayer/datalayer.h @@ -147,7 +147,7 @@ typedef struct { /** True if the contactor controlled by battery-emulator is closed */ bool contactors_engaged = false; /** True if shunt communication ok **/ - bool available=false; + bool available = false; } DATALAYER_SHUNT_TYPE; typedef struct { diff --git a/Software/src/datalayer/datalayer_extended.h b/Software/src/datalayer/datalayer_extended.h index 0d9b2d3f..19064035 100644 --- a/Software/src/datalayer/datalayer_extended.h +++ b/Software/src/datalayer/datalayer_extended.h @@ -3,6 +3,42 @@ #include "../include.h" +typedef struct { + /** uint16_t */ + /** PID polling parameters */ + uint16_t battery_5V_ref = 0; + int16_t battery_module_temp_1 = 0; + int16_t battery_module_temp_2 = 0; + int16_t battery_module_temp_3 = 0; + int16_t battery_module_temp_4 = 0; + int16_t battery_module_temp_5 = 0; + int16_t battery_module_temp_6 = 0; + uint16_t battery_cell_average_voltage = 0; + uint16_t battery_cell_average_voltage_2 = 0; + uint16_t battery_terminal_voltage = 0; + uint16_t battery_ignition_power_mode = 0; + int16_t battery_current_7E7 = 0; + uint16_t battery_capacity_my17_18 = 0; + uint16_t battery_capacity_my19plus = 0; + uint16_t battery_SOC_display = 0; + uint16_t battery_SOC_raw_highprec = 0; + uint16_t battery_max_temperature = 0; + uint16_t battery_min_temperature = 0; + uint16_t battery_max_cell_voltage = 0; + uint16_t battery_min_cell_voltage = 0; + uint16_t battery_lowest_cell = 0; + uint16_t battery_highest_cell = 0; + uint16_t battery_internal_resistance = 0; + uint16_t battery_voltage_polled = 0; + uint16_t battery_vehicle_isolation = 0; + uint16_t battery_isolation_kohm = 0; + uint16_t battery_HV_locked = 0; + uint16_t battery_crash_event = 0; + uint16_t battery_HVIL = 0; + uint16_t battery_HVIL_status = 0; + int16_t battery_current_7E4 = 0; +} DATALAYER_INFO_BOLTAMPERA; + typedef struct { /** uint16_t */ /** Terminal 30 - 12V SME Supply Voltage */ @@ -179,7 +215,12 @@ typedef struct { uint8_t packCtrsClosingAllowed = 0; /** uint8_t */ /** Pyro test in progress */ - uint8_t pyroTestInProgress = 0; + bool pyroTestInProgress = false; + bool battery_packCtrsOpenNowRequested = false; + bool battery_packCtrsOpenRequested = false; + uint8_t battery_packCtrsRequestStatus = 0; + bool battery_packCtrsResetRequestRequired = false; + bool battery_dcLinkAllowedToEnergize = false; uint8_t battery_beginning_of_life = 0; uint8_t battery_battTempPct = 0; uint16_t battery_dcdcLvBusVolt = 0; @@ -195,10 +236,20 @@ typedef struct { uint16_t battery_energy_to_charge_complete_m1 = 0; uint16_t battery_energy_buffer = 0; uint16_t battery_energy_buffer_m1 = 0; - uint16_t battery_full_charge_complete = 0; - uint8_t battery_fully_charged = 0; + uint16_t battery_expected_energy_remaining = 0; + uint16_t battery_expected_energy_remaining_m1 = 0; + bool battery_full_charge_complete = false; + bool battery_fully_charged = false; uint16_t battery_total_discharge = 0; uint16_t battery_total_charge = 0; + uint16_t battery_BrickVoltageMax = 0; + uint16_t battery_BrickVoltageMin = 0; + uint8_t battery_BrickVoltageMaxNum = 0; + uint8_t battery_BrickVoltageMinNum = 0; + uint8_t battery_BrickTempMaxNum = 0; + uint8_t battery_BrickTempMinNum = 0; + uint8_t battery_BrickModelTMax = 0; + uint8_t battery_BrickModelTMin = 0; uint16_t battery_packConfigMultiplexer = 0; uint16_t battery_moduleType = 0; uint16_t battery_reservedConfig = 0; @@ -212,6 +263,123 @@ typedef struct { uint32_t battery_soc_max = 0; uint32_t battery_soc_ave = 0; uint32_t battery_soc_ui = 0; + uint8_t battery_BMS_contactorState = 0; + uint8_t battery_BMS_state = 0; + uint8_t battery_BMS_hvState = 0; + uint16_t battery_BMS_isolationResistance = 0; + uint8_t battery_BMS_uiChargeStatus = 0; + bool battery_BMS_diLimpRequest = false; + uint16_t battery_BMS_chgPowerAvailable = 0; + bool battery_BMS_pcsPwmEnabled = false; + uint8_t battery_PCS_dcdcPrechargeStatus = 0; + uint8_t battery_PCS_dcdc12VSupportStatus = 0; + uint8_t battery_PCS_dcdcHvBusDischargeStatus = 0; + uint8_t battery_PCS_dcdcMainState = 0; + uint8_t battery_PCS_dcdcSubState = 0; + bool battery_PCS_dcdcFaulted = false; + bool battery_PCS_dcdcOutputIsLimited = false; + uint16_t battery_PCS_dcdcMaxOutputCurrentAllowed = 0; + uint8_t battery_PCS_dcdcPrechargeRtyCnt = 0; + uint8_t battery_PCS_dcdc12VSupportRtyCnt = 0; + uint8_t battery_PCS_dcdcDischargeRtyCnt = 0; + uint8_t battery_PCS_dcdcPwmEnableLine = 0; + uint8_t battery_PCS_dcdcSupportingFixedLvTarget = 0; + uint8_t battery_PCS_dcdcPrechargeRestartCnt = 0; + uint8_t battery_PCS_dcdcInitialPrechargeSubState = 0; + uint16_t BMS_maxRegenPower = 0; + uint16_t BMS_maxDischargePower = 0; + uint16_t BMS_maxStationaryHeatPower = 0; + uint16_t BMS_hvacPowerBudget = 0; + uint8_t BMS_notEnoughPowerForHeatPump = 0; + uint8_t BMS_powerLimitState = 0; + uint8_t BMS_inverterTQF = 0; + uint16_t BMS_powerDissipation = 0; + uint8_t BMS_flowRequest = 0; + uint16_t BMS_inletActiveCoolTargetT = 0; + uint16_t BMS_inletPassiveTargetT = 0; + uint16_t BMS_inletActiveHeatTargetT = 0; + uint16_t BMS_packTMin = 0; + uint16_t BMS_packTMax = 0; + bool BMS_pcsNoFlowRequest = false; + bool BMS_noFlowRequest = false; + uint16_t PCS_dcdcTemp = 0; + uint16_t PCS_ambientTemp = 0; + uint16_t PCS_dcdcMaxLvOutputCurrent = 0; + uint16_t PCS_dcdcCurrentLimit = 0; + uint16_t PCS_dcdcLvOutputCurrentTempLimit = 0; + uint16_t PCS_dcdcUnifiedCommand = 0; + uint16_t PCS_dcdcCLAControllerOutput = 0; + uint16_t PCS_dcdcTankVoltage = 0; + uint16_t PCS_dcdcTankVoltageTarget = 0; + uint16_t PCS_dcdcClaCurrentFreq = 0; + uint16_t PCS_dcdcTCommMeasured = 0; + uint16_t PCS_dcdcShortTimeUs = 0; + uint16_t PCS_dcdcHalfPeriodUs = 0; + uint16_t PCS_dcdcIntervalMaxFrequency = 0; + uint16_t PCS_dcdcIntervalMaxHvBusVolt = 0; + uint16_t PCS_dcdcIntervalMaxLvBusVolt = 0; + uint16_t PCS_dcdcIntervalMaxLvOutputCurr = 0; + uint16_t PCS_dcdcIntervalMinFrequency = 0; + uint16_t PCS_dcdcIntervalMinHvBusVolt = 0; + uint16_t PCS_dcdcIntervalMinLvBusVolt = 0; + uint16_t PCS_dcdcIntervalMinLvOutputCurr = 0; + uint32_t PCS_dcdc12vSupportLifetimekWh = 0; + bool HVP_gpioPassivePyroDepl = false; + bool HVP_gpioPyroIsoEn = false; + bool HVP_gpioCpFaultIn = false; + bool HVP_gpioPackContPowerEn = false; + bool HVP_gpioHvCablesOk = false; + bool HVP_gpioHvpSelfEnable = false; + bool HVP_gpioLed = false; + bool HVP_gpioCrashSignal = false; + bool HVP_gpioShuntDataReady = false; + bool HVP_gpioFcContPosAux = false; + bool HVP_gpioFcContNegAux = false; + bool HVP_gpioBmsEout = false; + bool HVP_gpioCpFaultOut = false; + bool HVP_gpioPyroPor = false; + bool HVP_gpioShuntEn = false; + bool HVP_gpioHvpVerEn = false; + bool HVP_gpioPackCoontPosFlywheel = false; + bool HVP_gpioCpLatchEnable = false; + bool HVP_gpioPcsEnable = false; + bool HVP_gpioPcsDcdcPwmEnable = false; + bool HVP_gpioPcsChargePwmEnable = false; + bool HVP_gpioFcContPowerEnable = false; + bool HVP_gpioHvilEnable = false; + bool HVP_gpioSecDrdy = false; + uint16_t HVP_hvp1v5Ref = 0; + uint16_t HVP_shuntCurrentDebug = 0; + bool HVP_packCurrentMia = false; + bool HVP_auxCurrentMia = false; + bool HVP_currentSenseMia = false; + bool HVP_shuntRefVoltageMismatch = false; + bool HVP_shuntThermistorMia = false; + uint8_t HVP_shuntHwMia = 0; + uint16_t HVP_dcLinkVoltage = 0; + uint16_t HVP_packVoltage = 0; + uint16_t HVP_fcLinkVoltage = 0; + uint16_t HVP_packContVoltage = 0; + uint16_t HVP_packNegativeV = 0; + uint16_t HVP_packPositiveV = 0; + uint16_t HVP_pyroAnalog = 0; + uint16_t HVP_dcLinkNegativeV = 0; + uint16_t HVP_dcLinkPositiveV = 0; + uint16_t HVP_fcLinkNegativeV = 0; + uint16_t HVP_fcContCoilCurrent = 0; + uint16_t HVP_fcContVoltage = 0; + uint16_t HVP_hvilInVoltage = 0; + uint16_t HVP_hvilOutVoltage = 0; + uint16_t HVP_fcLinkPositiveV = 0; + uint16_t HVP_packContCoilCurrent = 0; + uint16_t HVP_battery12V = 0; + uint16_t HVP_shuntRefVoltageDbg = 0; + uint16_t HVP_shuntAuxCurrentDbg = 0; + uint16_t HVP_shuntBarTempDbg = 0; + uint16_t HVP_shuntAsicTempDbg = 0; + uint8_t HVP_shuntAuxCurrentStatus = 0; + uint8_t HVP_shuntBarTempStatus = 0; + uint8_t HVP_shuntAsicTempStatus = 0; } DATALAYER_INFO_TESLA; typedef struct { @@ -403,6 +571,7 @@ typedef struct { class DataLayerExtended { public: + DATALAYER_INFO_BOLTAMPERA boltampera; DATALAYER_INFO_BMWIX bmwix; DATALAYER_INFO_BMWI3 bmwi3; DATALAYER_INFO_BYDATTO3 bydAtto3; diff --git a/Software/src/devboard/hal/hal.h b/Software/src/devboard/hal/hal.h index dc3240ce..667fdb19 100644 --- a/Software/src/devboard/hal/hal.h +++ b/Software/src/devboard/hal/hal.h @@ -9,6 +9,8 @@ #include "hw_stark.h" #elif defined(HW_3LB) #include "hw_3LB.h" +#elif defined(HW_DEVKIT) +#include "hw_devkit.h" #endif #endif diff --git a/Software/src/devboard/hal/hw_3LB.h b/Software/src/devboard/hal/hw_3LB.h index f4883be7..5fd8ef6f 100644 --- a/Software/src/devboard/hal/hw_3LB.h +++ b/Software/src/devboard/hal/hw_3LB.h @@ -72,6 +72,14 @@ // Equipment stop pin #define EQUIPMENT_STOP_PIN 35 +// BMW_I3_BATTERY wake up pin +#ifdef BMW_I3_BATTERY +#define WUP_PIN1 GPIO_NUM_25 // Wake up pin for battery 1 +#ifdef DOUBLE_BATTERY +#define WUP_PIN2 GPIO_NUM_32 // Wake up pin for battery 2 +#endif // DOUBLE_BATTERY +#endif // BMW_I3_BATTERY + /* ----- Error checks below, don't change (can't be moved to separate file) ----- */ #ifndef HW_CONFIGURED #define HW_CONFIGURED @@ -98,9 +106,12 @@ #endif #ifdef BMW_I3_BATTERY -#ifdef CONTACTOR_CONTROL +#if defined(CONTACTOR_CONTROL) && defined(WUP_PIN1) #error GPIO PIN 25 cannot be used for both BMWi3 Wakeup and contactor control. Disable CONTACTOR_CONTROL #endif +#if defined(CONTACTOR_CONTROL) && defined(WUP_PIN2) +#error GPIO PIN 32 cannot be used for both BMWi3 Wakeup and contactor control. Disable CONTACTOR_CONTROL +#endif #endif #endif diff --git a/Software/src/devboard/hal/hw_devkit.h b/Software/src/devboard/hal/hw_devkit.h new file mode 100644 index 00000000..c16621b5 --- /dev/null +++ b/Software/src/devboard/hal/hw_devkit.h @@ -0,0 +1,93 @@ +#ifndef __HW_DEVKIT_H__ +#define __HW_DEVKIT_H__ + +/* +ESP32 DevKit V1 development board with 30 pins. +For more information, see: https://lastminuteengineers.com/esp32-pinout-reference/. + +The pin layout below supports the following: +- 1x RS485 +- 2x CAN (1x via SN65HVD230 (UART), 1x via MCP2515 (SPI)) +- 1x CANFD (via MCP2518FD (SPI)) +*/ + +// Board boot-up time +#define BOOTUP_TIME 1000 // Time in ms it takes before system is considered fully started up + +// Core assignment +#define CORE_FUNCTION_CORE 1 +#define MODBUS_CORE 0 +#define WIFI_CORE 0 + +// RS485 +#define RS485_TX_PIN GPIO_NUM_1 +#define RS485_RX_PIN GPIO_NUM_3 + +// CAN settings +#define CAN_1_TYPE ESP32CAN +//#define CAN_2_TYPE MCP2515 +//#define CAN_3_TYPE MCP2518FD + +// CAN1 PIN mappings, do not change these unless you are adding on extra hardware to the PCB +#define CAN_TX_PIN GPIO_NUM_27 +#define CAN_RX_PIN GPIO_NUM_26 + +// CAN_ADDON defines +#define MCP2515_SCK GPIO_NUM_22 // SCK input of MCP2515 +#define MCP2515_MOSI GPIO_NUM_21 // SDI input of MCP2515 +#define MCP2515_MISO GPIO_NUM_19 // SDO output of MCP2515 +#define MCP2515_CS GPIO_NUM_18 // CS input of MCP2515 +#define MCP2515_INT GPIO_NUM_23 // INT output of MCP2515 + +// CANFD_ADDON defines +#define MCP2517_SCK GPIO_NUM_33 // SCK input of MCP2517 +#define MCP2517_SDI GPIO_NUM_32 // SDI input of MCP2517 +#define MCP2517_SDO GPIO_NUM_35 // SDO output of MCP2517 | Pin 35 is input only, without pullup/down resistors +#define MCP2517_CS GPIO_NUM_25 // CS input of MCP2517 +#define MCP2517_INT GPIO_NUM_34 // INT output of MCP2517 | Pin 34 is input only, without pullup/down resistors + +// Contactor handling +#define POSITIVE_CONTACTOR_PIN GPIO_NUM_5 +#define NEGATIVE_CONTACTOR_PIN GPIO_NUM_16 +#define PRECHARGE_PIN GPIO_NUM_17 + +// SMA CAN contactor pins +#define INVERTER_CONTACTOR_ENABLE_PIN GPIO_NUM_14 + +// LED +#define LED_PIN GPIO_NUM_4 +#define LED_MAX_BRIGHTNESS 40 +#define INVERTER_CONTACTOR_ENABLE_LED_PIN GPIO_NUM_2 + +// Equipment stop pin +#define EQUIPMENT_STOP_PIN GPIO_NUM_12 + +// BMW_I3_BATTERY wake up pin +#ifdef BMW_I3_BATTERY +#define WUP_PIN1 GPIO_NUM_25 // Wake up pin for battery 1 +#ifdef DOUBLE_BATTERY +#define WUP_PIN2 GPIO_NUM_32 // Wake up pin for battery 2 +#endif // DOUBLE_BATTERY +#endif // BMW_I3_BATTERY + +/* ----- Error checks below, don't change (can't be moved to separate file) ----- */ +#ifndef HW_CONFIGURED +#define HW_CONFIGURED +#else +#error Multiple HW defined! Please select a single HW +#endif // HW_CONFIGURED + +#ifdef CHADEMO_BATTERY +#error CHADEMO pins are not defined for this hardware. +#endif // CHADEMO_BATTERY + +#ifdef BMW_I3_BATTERY +#if defined(WUP_PIN1) && defined(CANFD_ADDON) +#error GPIO PIN 25 cannot be used for both BMWi3 Wakeup and a CANFD addon board using these pins. Choose between BMW_I3_BATTERY and CANFD_ADDON +#endif // defined(WUP_PIN1) && defined(CANFD_ADDON) +#if defined(WUP_PIN2) && defined(CANFD_ADDON) +#error GPIO PIN 32 cannot be used for both BMWi3 Wakeup and a CANFD addon board using these pins. Choose between BMW_I3_BATTERY and CANFD_ADDON +#endif // defined(WUP_PIN2) && defined(CANFD_ADDON) +#endif // BMW_I3_BATTERY + +#endif // __HW_DEVKIT_H__ diff --git a/Software/src/devboard/hal/hw_lilygo.h b/Software/src/devboard/hal/hw_lilygo.h index 2ea8d260..6ffcd34e 100644 --- a/Software/src/devboard/hal/hw_lilygo.h +++ b/Software/src/devboard/hal/hw_lilygo.h @@ -68,6 +68,14 @@ // Equipment stop pin #define EQUIPMENT_STOP_PIN 35 +// BMW_I3_BATTERY wake up pin +#ifdef BMW_I3_BATTERY +#define WUP_PIN1 GPIO_NUM_25 // Wake up pin for battery 1 +#ifdef DOUBLE_BATTERY +#define WUP_PIN2 GPIO_NUM_32 // Wake up pin for battery 2 +#endif // DOUBLE_BATTERY +#endif // BMW_I3_BATTERY + /* ----- Error checks below, don't change (can't be moved to separate file) ----- */ #ifndef HW_CONFIGURED #define HW_CONFIGURED @@ -75,6 +83,11 @@ #error Multiple HW defined! Please select a single HW #endif +#if defined(CAN_ADDON) && defined(CANFD_ADDON) +// Check that user did not try to use dual can and fd-can on same hardware pins +#error CAN_ADDON AND CANFD_ADDON CANNOT BE USED SIMULTANEOUSLY +#endif + #ifdef CHADEMO_BATTERY #ifdef CAN_ADDON #error CHADEMO and CAN_ADDON cannot coexist due to overlapping GPIO pin usage @@ -94,9 +107,12 @@ #endif #ifdef BMW_I3_BATTERY -#ifdef CONTACTOR_CONTROL +#if defined(CONTACTOR_CONTROL) && defined(WUP_PIN1) #error GPIO PIN 25 cannot be used for both BMWi3 Wakeup and contactor control. Disable CONTACTOR_CONTROL #endif +#if defined(CONTACTOR_CONTROL) && defined(WUP_PIN2) +#error GPIO PIN 32 cannot be used for both BMWi3 Wakeup and contactor control. Disable CONTACTOR_CONTROL +#endif #endif #endif diff --git a/Software/src/devboard/hal/hw_stark.h b/Software/src/devboard/hal/hw_stark.h index f12ea84a..064db9da 100644 --- a/Software/src/devboard/hal/hw_stark.h +++ b/Software/src/devboard/hal/hw_stark.h @@ -61,11 +61,28 @@ GPIOs on extra header // Equipment stop pin #define EQUIPMENT_STOP_PIN 2 +// BMW_I3_BATTERY wake up pin +#ifdef BMW_I3_BATTERY +#define WUP_PIN1 GPIO_NUM_25 // Wake up pin for battery 1 +#ifdef DOUBLE_BATTERY +#define WUP_PIN2 GPIO_NUM_32 // Wake up pin for battery 2 +#endif // DOUBLE_BATTERY +#endif // BMW_I3_BATTERY + /* ----- Error checks below, don't change (can't be moved to separate file) ----- */ #ifndef HW_CONFIGURED #define HW_CONFIGURED #else #error Multiple HW defined! Please select a single HW -#endif +#endif // HW_CONFIGURED +#ifdef BMW_I3_BATTERY +#if defined(CONTACTOR_CONTROL) && defined(WUP_PIN1) +#error GPIO PIN 25 cannot be used for both BMWi3 Wakeup and contactor control. Disable CONTACTOR_CONTROL #endif +#if defined(CONTACTOR_CONTROL) && defined(WUP_PIN2) +#error GPIO PIN 32 cannot be used for both BMWi3 Wakeup and contactor control. Disable CONTACTOR_CONTROL +#endif +#endif // BMW_I3_BATTERY + +#endif // __HW_STARK_H__ diff --git a/Software/src/devboard/mqtt/mqtt.cpp b/Software/src/devboard/mqtt/mqtt.cpp index 95f5444a..2797db3b 100644 --- a/Software/src/devboard/mqtt/mqtt.cpp +++ b/Software/src/devboard/mqtt/mqtt.cpp @@ -2,6 +2,7 @@ #include #include #include +#include "../../../USER_SECRETS.h" #include "../../../USER_SETTINGS.h" #include "../../battery/BATTERIES.h" #include "../../datalayer/datalayer.h" @@ -194,9 +195,9 @@ static void publish_common_info(void) { #endif // DOUBLE_BATTERY serializeJson(doc, mqtt_msg); if (!mqtt_publish(state_topic.c_str(), mqtt_msg, false)) { -#ifdef DEBUG_VIA_USB - Serial.println("Common info MQTT msg could not be sent"); -#endif // DEBUG_VIA_USB +#ifdef DEBUG_LOG + logging.println("Common info MQTT msg could not be sent"); +#endif // DEBUG_LOG } doc.clear(); #ifdef HA_AUTODISCOVERY @@ -292,9 +293,9 @@ static void publish_cell_voltages(void) { serializeJson(doc, mqtt_msg, sizeof(mqtt_msg)); if (!mqtt_publish(state_topic.c_str(), mqtt_msg, false)) { -#ifdef DEBUG_VIA_USB - Serial.println("Cell voltage MQTT msg could not be sent"); -#endif // DEBUG_VIA_USB +#ifdef DEBUG_LOG + logging.println("Cell voltage MQTT msg could not be sent"); +#endif // DEBUG_LOG } doc.clear(); } @@ -312,9 +313,9 @@ static void publish_cell_voltages(void) { serializeJson(doc, mqtt_msg, sizeof(mqtt_msg)); if (!mqtt_publish(state_topic_2.c_str(), mqtt_msg, false)) { -#ifdef DEBUG_VIA_USB - Serial.println("Cell voltage MQTT msg could not be sent"); -#endif // DEBUG_VIA_USB +#ifdef DEBUG_LOG + logging.println("Cell voltage MQTT msg could not be sent"); +#endif // DEBUG_LOG } doc.clear(); } @@ -384,9 +385,9 @@ void publish_events() { serializeJson(doc, mqtt_msg); if (!mqtt_publish(state_topic.c_str(), mqtt_msg, false)) { -#ifdef DEBUG_VIA_USB - Serial.println("Common info MQTT msg could not be sent"); -#endif // DEBUG_VIA_USB +#ifdef DEBUG_LOG + logging.println("Common info MQTT msg could not be sent"); +#endif // DEBUG_LOG } else { set_event_MQTTpublished(event_handle); } @@ -402,9 +403,9 @@ void publish_events() { /* If we lose the connection, get it back */ static bool reconnect() { // attempt one reconnection -#ifdef DEBUG_VIA_USB - Serial.print("Attempting MQTT connection... "); -#endif // DEBUG_VIA_USB +#ifdef DEBUG_LOG + logging.print("Attempting MQTT connection... "); +#endif // DEBUG_LOG char clientId[64]; // Adjust the size as needed snprintf(clientId, sizeof(clientId), "BatteryEmulatorClient-%s", WiFi.getHostname()); // Attempt to connect @@ -413,19 +414,19 @@ static bool reconnect() { clear_event(EVENT_MQTT_DISCONNECT); set_event(EVENT_MQTT_CONNECT, 0); reconnectAttempts = 0; // Reset attempts on successful connection -#ifdef DEBUG_VIA_USB - Serial.println("connected"); -#endif // DEBUG_VIA_USB +#ifdef DEBUG_LOG + logging.println("connected"); +#endif // DEBUG_LOG clear_event(EVENT_MQTT_CONNECT); } else { if (connected_once) set_event(EVENT_MQTT_DISCONNECT, 0); reconnectAttempts++; // Count failed attempts -#ifdef DEBUG_VIA_USB - Serial.print("failed, rc="); - Serial.print(client.state()); - Serial.println(" try again in 5 seconds"); -#endif // DEBUG_VIA_USB +#ifdef DEBUG_LOG + logging.print("failed, rc="); + logging.print(client.state()); + logging.println(" try again in 5 seconds"); +#endif // DEBUG_LOG // Wait 5 seconds before retrying } return client.connected(); @@ -449,9 +450,9 @@ void init_mqtt(void) { #endif client.setServer(MQTT_SERVER, MQTT_PORT); -#ifdef DEBUG_VIA_USB - Serial.println("MQTT initialized"); -#endif // DEBUG_VIA_USB +#ifdef DEBUG_LOG + logging.println("MQTT initialized"); +#endif // DEBUG_LOG client.setKeepAlive(30); // Increase keepalive to manage network latency better. default is 15 @@ -478,8 +479,8 @@ void mqtt_loop(void) { if (reconnect()) { lastReconnectAttempt = 0; } else if (reconnectAttempts >= maxReconnectAttempts) { -#ifdef DEBUG_VIA_USB - Serial.println("Too many failed reconnect attempts, restarting client."); +#ifdef DEBUG_LOG + logging.println("Too many failed reconnect attempts, restarting client."); #endif client.disconnect(); // Force close the MQTT client connection reconnectAttempts = 0; // Reset attempts to avoid infinite loop diff --git a/Software/src/devboard/safety/safety.cpp b/Software/src/devboard/safety/safety.cpp index 39f4b133..f662adfe 100644 --- a/Software/src/devboard/safety/safety.cpp +++ b/Software/src/devboard/safety/safety.cpp @@ -283,12 +283,12 @@ void setBatteryPause(bool pause_battery, bool pause_CAN, bool equipment_stop, bo } //immediate check if we can send CAN messages - emulator_pause_state_send_CAN_battery(); + emulator_pause_state_transmit_can_battery(); } /// @brief handle emulator pause status /// @return true if CAN messages should be sent to battery, false if not -void emulator_pause_state_send_CAN_battery() { +void emulator_pause_state_transmit_can_battery() { bool previous_allowed_to_send_CAN = allowed_to_send_CAN; if (emulator_pause_status == NORMAL) { diff --git a/Software/src/devboard/safety/safety.h b/Software/src/devboard/safety/safety.h index 32ae0ab8..8fa98a3d 100644 --- a/Software/src/devboard/safety/safety.h +++ b/Software/src/devboard/safety/safety.h @@ -22,7 +22,7 @@ void update_machineryprotection(); //battery pause status begin void setBatteryPause(bool pause_battery, bool pause_CAN, bool equipment_stop = false, bool store_settings = true); -void emulator_pause_state_send_CAN_battery(); +void emulator_pause_state_transmit_can_battery(); std::string get_emulator_pause_status(); //battery pause status end diff --git a/Software/src/devboard/sdcard/sdcard.cpp b/Software/src/devboard/sdcard/sdcard.cpp new file mode 100644 index 00000000..b6b755ab --- /dev/null +++ b/Software/src/devboard/sdcard/sdcard.cpp @@ -0,0 +1,155 @@ +#include "sdcard.h" +#include "freertos/ringbuf.h" + +#if defined(SD_CS_PIN) && defined(SD_SCLK_PIN) && defined(SD_MOSI_PIN) && \ + defined(SD_MISO_PIN) // ensure code is only compiled if all SD card pins are defined + +File can_log_file; +RingbufHandle_t can_bufferHandle; + +bool can_logging_paused = false; +bool can_file_open = false; +bool delete_can_file = false; +bool sd_card_active = false; + +void delete_can_log() { + can_logging_paused = true; + delete_can_file = true; +} + +void resume_can_writing() { + can_logging_paused = false; + can_log_file = SD.open(CAN_LOG_FILE, FILE_APPEND); + can_file_open = true; +} + +void pause_can_writing() { + can_logging_paused = true; +} + +void add_can_frame_to_buffer(CAN_frame frame, frameDirection msgDir) { + + if (!sd_card_active) + return; + + CAN_log_frame log_frame = {frame, msgDir}; + if (xRingbufferSend(can_bufferHandle, &log_frame, sizeof(log_frame), 0) != pdTRUE) { + Serial.println("Failed to send CAN frame to ring buffer!"); + return; + } +} + +void write_can_frame_to_sdcard() { + + if (!sd_card_active) + return; + + size_t receivedMessageSize; + CAN_log_frame* log_frame = + (CAN_log_frame*)xRingbufferReceive(can_bufferHandle, &receivedMessageSize, pdMS_TO_TICKS(10)); + + if (log_frame != NULL) { + + if (can_logging_paused) { + if (can_file_open) { + can_log_file.close(); + can_file_open = false; + } + if (delete_can_file) { + SD.remove(CAN_LOG_FILE); + delete_can_file = false; + can_logging_paused = false; + } + vRingbufferReturnItem(can_bufferHandle, (void*)log_frame); + return; + } + + if (can_file_open == false) { + can_log_file = SD.open(CAN_LOG_FILE, FILE_APPEND); + can_file_open = true; + } + + uint8_t i = 0; + can_log_file.print("("); + can_log_file.print(millis() / 1000.0); + (log_frame->direction == MSG_RX) ? can_log_file.print(") RX0 ") : can_log_file.print(") TX1 "); + can_log_file.print(log_frame->frame.ID, HEX); + can_log_file.print(" ["); + can_log_file.print(log_frame->frame.DLC); + can_log_file.print("] "); + for (i = 0; i < log_frame->frame.DLC; i++) { + can_log_file.print(log_frame->frame.data.u8[i] < 16 ? "0" : ""); + can_log_file.print(log_frame->frame.data.u8[i], HEX); + if (i < log_frame->frame.DLC - 1) + can_log_file.print(" "); + } + can_log_file.println(""); + + vRingbufferReturnItem(can_bufferHandle, (void*)log_frame); + } +} + +void init_logging_buffer() { + can_bufferHandle = xRingbufferCreate(64 * 1024, RINGBUF_TYPE_BYTEBUF); + if (can_bufferHandle == NULL) { + Serial.println("Failed to create CAN ring buffer!"); + return; + } +} + +void init_sdcard() { + + pinMode(SD_CS_PIN, OUTPUT); + digitalWrite(SD_CS_PIN, HIGH); + pinMode(SD_SCLK_PIN, OUTPUT); + pinMode(SD_MOSI_PIN, OUTPUT); + pinMode(SD_MISO_PIN, INPUT); + + SPI.begin(SD_SCLK_PIN, SD_MISO_PIN, SD_MOSI_PIN, SD_CS_PIN); + if (!SD.begin(SD_CS_PIN)) { + Serial.println("SD Card initialization failed!"); + return; + } + + Serial.println("SD Card initialization successful."); + sd_card_active = true; + + print_sdcard_details(); +} + +void print_sdcard_details() { + + Serial.print("SD Card Type: "); + switch (SD.cardType()) { + case CARD_MMC: + Serial.println("MMC"); + break; + case CARD_SD: + Serial.println("SD"); + break; + case CARD_SDHC: + Serial.println("SDHC"); + break; + case CARD_UNKNOWN: + Serial.println("UNKNOWN"); + break; + case CARD_NONE: + Serial.println("No SD Card found"); + break; + } + + if (SD.cardType() != CARD_NONE) { + Serial.print("SD Card Size: "); + Serial.print(SD.cardSize() / 1024 / 1024); + Serial.println(" MB"); + + Serial.print("Total space: "); + Serial.print(SD.totalBytes() / 1024 / 1024); + Serial.println(" MB"); + + Serial.print("Used space: "); + Serial.print(SD.usedBytes() / 1024 / 1024); + Serial.println(" MB"); + } +} +#endif // defined(SD_CS_PIN) && defined(SD_SCLK_PIN) && defined(SD_MOSI_PIN) && defined(SD_MISO_PIN) diff --git a/Software/src/devboard/sdcard/sdcard.h b/Software/src/devboard/sdcard/sdcard.h new file mode 100644 index 00000000..8dffeec2 --- /dev/null +++ b/Software/src/devboard/sdcard/sdcard.h @@ -0,0 +1,26 @@ +#ifndef SDCARD_H +#define SDCARD_H + +#include +#include +#include "../../communication/can/comm_can.h" +#include "../hal/hal.h" + +#if defined(SD_CS_PIN) && defined(SD_SCLK_PIN) && defined(SD_MOSI_PIN) && \ + defined(SD_MISO_PIN) // ensure code is only compiled if all SD card pins are defined +#define CAN_LOG_FILE "/canlog.txt" + +void init_logging_buffer(); + +void init_sdcard(); +void print_sdcard_details(); + +void add_can_frame_to_buffer(CAN_frame frame, frameDirection msgDir); +void write_can_frame_to_sdcard(); + +void pause_can_writing(); +void resume_can_writing(); +void delete_can_log(); +#endif // defined(SD_CS_PIN) && defined(SD_SCLK_PIN) && defined(SD_MOSI_PIN) && defined(SD_MISO_PIN) + +#endif // SDCARD_H diff --git a/Software/src/devboard/utils/events.cpp b/Software/src/devboard/utils/events.cpp index d51bd1c4..88546af3 100644 --- a/Software/src/devboard/utils/events.cpp +++ b/Software/src/devboard/utils/events.cpp @@ -118,15 +118,15 @@ void init_events(void) { // Push changes to eeprom EEPROM.commit(); -#ifdef DEBUG_VIA_USB - Serial.println("EEPROM wasn't ready"); +#ifdef DEBUG_LOG + logging.println("EEPROM wasn't ready"); #endif } else { events.event_log_head_index = EEPROM.readUShort(EE_EVENT_LOG_HEAD_INDEX_ADDRESS); events.event_log_tail_index = EEPROM.readUShort(EE_EVENT_LOG_TAIL_INDEX_ADDRESS); -#ifdef DEBUG_VIA_USB - Serial.println("EEPROM was initialized for event logging"); - Serial.println("head: " + String(events.event_log_head_index) + ", tail: " + String(events.event_log_tail_index)); +#ifdef DEBUG_LOG + logging.println("EEPROM was initialized for event logging"); + logging.println("head: " + String(events.event_log_head_index) + ", tail: " + String(events.event_log_tail_index)); #endif print_event_log(); } @@ -140,8 +140,8 @@ void init_events(void) { events.entries[i].MQTTpublished = false; // Not published by default } - events.entries[EVENT_CANFD_INIT_FAILURE].level = EVENT_LEVEL_WARNING; - events.entries[EVENT_CANMCP_INIT_FAILURE].level = EVENT_LEVEL_WARNING; + events.entries[EVENT_CANMCP2517FD_INIT_FAILURE].level = EVENT_LEVEL_WARNING; + events.entries[EVENT_CANMCP2515_INIT_FAILURE].level = EVENT_LEVEL_WARNING; events.entries[EVENT_CANFD_BUFFER_FULL].level = EVENT_LEVEL_WARNING; events.entries[EVENT_CAN_OVERRUN].level = EVENT_LEVEL_INFO; events.entries[EVENT_CANFD_RX_OVERRUN].level = EVENT_LEVEL_WARNING; @@ -264,9 +264,9 @@ void set_event_MQTTpublished(EVENTS_ENUM_TYPE event) { const char* get_event_message_string(EVENTS_ENUM_TYPE event) { switch (event) { - case EVENT_CANFD_INIT_FAILURE: + case EVENT_CANMCP2517FD_INIT_FAILURE: return "CAN-FD initialization failed. Check hardware or bitrate settings"; - case EVENT_CANMCP_INIT_FAILURE: + case EVENT_CANMCP2515_INIT_FAILURE: return "CAN-MCP addon initialization failed. Check hardware"; case EVENT_CANFD_BUFFER_FULL: return "CAN-FD buffer overflowed. Some CAN messages were not sent. Contact developers."; @@ -471,6 +471,10 @@ static void set_event(EVENTS_ENUM_TYPE event, uint8_t data, bool latched) { if (events.entries[event].log) { log_event(event, events.entries[event].millisrolloverCount, events.entries[event].timestamp, data); } +#ifdef DEBUG_LOG + logging.print("Event: "); + logging.println(get_event_message_string(event)); +#endif } // We should set the event, update event info @@ -484,10 +488,6 @@ static void set_event(EVENTS_ENUM_TYPE event, uint8_t data, bool latched) { events.level = max(events.level, events.entries[event].level); update_bms_status(); - -#ifdef DEBUG_VIA_USB - Serial.println(get_event_message_string(event)); -#endif } static void update_bms_status(void) { @@ -561,8 +561,8 @@ static void log_event(EVENTS_ENUM_TYPE event, uint8_t millisrolloverCount, uint3 // Store the new indices EEPROM.writeUShort(EE_EVENT_LOG_HEAD_INDEX_ADDRESS, events.event_log_head_index); EEPROM.writeUShort(EE_EVENT_LOG_TAIL_INDEX_ADDRESS, events.event_log_tail_index); - //Serial.println("Wrote event " + String(event) + " to " + String(entry_address)); - //Serial.println("head: " + String(events.event_log_head_index) + ", tail: " + String(events.event_log_tail_index)); + //logging.println("Wrote event " + String(event) + " to " + String(entry_address)); + //logging.println("head: " + String(events.event_log_head_index) + ", tail: " + String(events.event_log_tail_index)); // We don't need the exact number, it's just for deciding to store or not events.nof_logged_events += (events.nof_logged_events < 255) ? 1 : 0; @@ -571,8 +571,8 @@ static void log_event(EVENTS_ENUM_TYPE event, uint8_t millisrolloverCount, uint3 static void print_event_log(void) { // If the head actually points to the tail, the log is probably blank if (events.event_log_head_index == events.event_log_tail_index) { -#ifdef DEBUG_VIA_USB - Serial.println("No events in log"); +#ifdef DEBUG_LOG + logging.println("No events in log"); #endif return; } @@ -588,9 +588,9 @@ static void print_event_log(void) { // The entry is a blank that has been left behind somehow continue; } -#ifdef DEBUG_VIA_USB - Serial.println("Event: " + String(get_event_enum_string(entry.event)) + ", data: " + String(entry.data) + - ", time: " + String(entry.timestamp)); +#ifdef DEBUG_LOG + logging.println("Event: " + String(get_event_enum_string(entry.event)) + ", data: " + String(entry.data) + + ", time: " + String(entry.timestamp)); #endif if (index == events.event_log_head_index) { break; diff --git a/Software/src/devboard/utils/events.h b/Software/src/devboard/utils/events.h index d410d66f..972842fd 100644 --- a/Software/src/devboard/utils/events.h +++ b/Software/src/devboard/utils/events.h @@ -26,8 +26,8 @@ */ #define EVENTS_ENUM_TYPE(XX) \ - XX(EVENT_CANFD_INIT_FAILURE) \ - XX(EVENT_CANMCP_INIT_FAILURE) \ + XX(EVENT_CANMCP2517FD_INIT_FAILURE) \ + XX(EVENT_CANMCP2515_INIT_FAILURE) \ XX(EVENT_CANFD_BUFFER_FULL) \ XX(EVENT_CAN_OVERRUN) \ XX(EVENT_CANFD_RX_OVERRUN) \ diff --git a/Software/src/devboard/utils/events_test_on_target.cpp b/Software/src/devboard/utils/events_test_on_target.cpp index 9f91e8df..980c3f1f 100644 --- a/Software/src/devboard/utils/events_test_on_target.cpp +++ b/Software/src/devboard/utils/events_test_on_target.cpp @@ -25,9 +25,9 @@ void run_sequence_on_target(void) { case ETOT_INIT: timer.set_interval(10000); events_test_state = ETOT_FIRST_WAIT; - Serial.println("Events test: initialized"); - Serial.print("datalayer.battery.status.bms_status: "); - Serial.println(datalayer.battery.status.bms_status); + logging.println("Events test: initialized"); + logging.print("datalayer.battery.status.bms_status: "); + logging.println(datalayer.battery.status.bms_status); break; case ETOT_FIRST_WAIT: if (timer.elapsed()) { @@ -35,9 +35,9 @@ void run_sequence_on_target(void) { events_test_state = ETOT_INFO; set_event(EVENT_DUMMY_INFO, 123); set_event(EVENT_DUMMY_INFO, 234); // 234 should show, occurrence 1 - Serial.println("Events test: info event set, data: 234"); - Serial.print("datalayer.battery.status.bms_status: "); - Serial.println(datalayer.battery.status.bms_status); + logging.println("Events test: info event set, data: 234"); + logging.print("datalayer.battery.status.bms_status: "); + logging.println(datalayer.battery.status.bms_status); } break; case ETOT_INFO: @@ -45,9 +45,9 @@ void run_sequence_on_target(void) { timer.set_interval(8000); clear_event(EVENT_DUMMY_INFO); events_test_state = ETOT_INFO_CLEAR; - Serial.println("Events test : info event cleared"); - Serial.print("datalayer.battery.status.bms_status: "); - Serial.println(datalayer.battery.status.bms_status); + logging.println("Events test : info event cleared"); + logging.print("datalayer.battery.status.bms_status: "); + logging.println(datalayer.battery.status.bms_status); } break; case ETOT_INFO_CLEAR: @@ -56,9 +56,9 @@ void run_sequence_on_target(void) { events_test_state = ETOT_DEBUG; set_event(EVENT_DUMMY_DEBUG, 111); set_event(EVENT_DUMMY_DEBUG, 222); // 222 should show, occurrence 1 - Serial.println("Events test : debug event set, data: 222"); - Serial.print("datalayer.battery.status.bms_status: "); - Serial.println(datalayer.battery.status.bms_status); + logging.println("Events test : debug event set, data: 222"); + logging.print("datalayer.battery.status.bms_status: "); + logging.println(datalayer.battery.status.bms_status); } break; case ETOT_DEBUG: @@ -66,9 +66,9 @@ void run_sequence_on_target(void) { timer.set_interval(8000); clear_event(EVENT_DUMMY_DEBUG); events_test_state = ETOT_DEBUG_CLEAR; - Serial.println("Events test : info event cleared"); - Serial.print("datalayer.battery.status.bms_status: "); - Serial.println(datalayer.battery.status.bms_status); + logging.println("Events test : info event cleared"); + logging.print("datalayer.battery.status.bms_status: "); + logging.println(datalayer.battery.status.bms_status); } break; case ETOT_DEBUG_CLEAR: @@ -77,9 +77,9 @@ void run_sequence_on_target(void) { events_test_state = ETOT_WARNING; set_event(EVENT_DUMMY_WARNING, 234); set_event(EVENT_DUMMY_WARNING, 121); // 121 should show, occurrence 1 - Serial.println("Events test : warning event set, data: 121"); - Serial.print("datalayer.battery.status.bms_status: "); - Serial.println(datalayer.battery.status.bms_status); + logging.println("Events test : warning event set, data: 121"); + logging.print("datalayer.battery.status.bms_status: "); + logging.println(datalayer.battery.status.bms_status); } break; case ETOT_WARNING: @@ -87,9 +87,9 @@ void run_sequence_on_target(void) { timer.set_interval(8000); clear_event(EVENT_DUMMY_WARNING); events_test_state = ETOT_WARNING_CLEAR; - Serial.println("Events test : warning event cleared"); - Serial.print("datalayer.battery.status.bms_status: "); - Serial.println(datalayer.battery.status.bms_status); + logging.println("Events test : warning event cleared"); + logging.print("datalayer.battery.status.bms_status: "); + logging.println(datalayer.battery.status.bms_status); } break; case ETOT_WARNING_CLEAR: @@ -98,9 +98,9 @@ void run_sequence_on_target(void) { events_test_state = ETOT_ERROR; set_event(EVENT_DUMMY_ERROR, 221); set_event(EVENT_DUMMY_ERROR, 133); // 133 should show, occurrence 1 - Serial.println("Events test : error event set, data: 133"); - Serial.print("datalayer.battery.status.bms_status: "); - Serial.println(datalayer.battery.status.bms_status); + logging.println("Events test : error event set, data: 133"); + logging.print("datalayer.battery.status.bms_status: "); + logging.println(datalayer.battery.status.bms_status); } break; case ETOT_ERROR: @@ -108,9 +108,9 @@ void run_sequence_on_target(void) { timer.set_interval(8000); clear_event(EVENT_DUMMY_ERROR); events_test_state = ETOT_ERROR_CLEAR; - Serial.println("Events test : error event cleared"); - Serial.print("datalayer.battery.status.bms_status: "); - Serial.println(datalayer.battery.status.bms_status); + logging.println("Events test : error event cleared"); + logging.print("datalayer.battery.status.bms_status: "); + logging.println(datalayer.battery.status.bms_status); } break; case ETOT_ERROR_CLEAR: @@ -119,9 +119,9 @@ void run_sequence_on_target(void) { events_test_state = ETOT_ERROR_LATCHED; set_event_latched(EVENT_DUMMY_ERROR, 221); set_event_latched(EVENT_DUMMY_ERROR, 133); // 133 should show, occurrence 1 - Serial.println("Events test : latched error event set, data: 133"); - Serial.print("datalayer.battery.status.bms_status: "); - Serial.println(datalayer.battery.status.bms_status); + logging.println("Events test : latched error event set, data: 133"); + logging.print("datalayer.battery.status.bms_status: "); + logging.println(datalayer.battery.status.bms_status); } break; case ETOT_ERROR_LATCHED: @@ -129,9 +129,9 @@ void run_sequence_on_target(void) { timer.set_interval(8000); clear_event(EVENT_DUMMY_ERROR); events_test_state = ETOT_DONE; - Serial.println("Events test : latched error event cleared?"); - Serial.print("datalayer.battery.status.bms_status: "); - Serial.println(datalayer.battery.status.bms_status); + logging.println("Events test : latched error event cleared?"); + logging.print("datalayer.battery.status.bms_status: "); + logging.println(datalayer.battery.status.bms_status); } break; case ETOT_DONE: diff --git a/Software/src/devboard/utils/logging.cpp b/Software/src/devboard/utils/logging.cpp new file mode 100644 index 00000000..0f78956f --- /dev/null +++ b/Software/src/devboard/utils/logging.cpp @@ -0,0 +1,86 @@ +#include "logging.h" +#include "../../datalayer/datalayer.h" + +size_t Logging::write(const uint8_t* buffer, size_t size) { +#ifdef DEBUG_LOG + char* message_string = datalayer.system.info.logged_can_messages; + int offset = datalayer.system.info.logged_can_messages_offset; // Keeps track of the current position in the buffer + size_t message_string_size = sizeof(datalayer.system.info.logged_can_messages); + unsigned long currentTime = millis(); +#ifdef DEBUG_VIA_USB + size_t n = 0; + while (size--) { + if (Serial.write(*buffer++)) + n++; + else + break; + } + return n; +#endif +#ifdef DEBUG_VIA_WEB + if (datalayer.system.info.can_logging_active) { + return 0; + } + if (offset + size + 13 > sizeof(datalayer.system.info.logged_can_messages)) { + offset = 0; + } + if (buffer[0] != '\r' && buffer[0] != '\n' && + (offset == 0 || message_string[offset - 1] == '\r' || message_string[offset - 1] == '\n')) { + offset += snprintf(message_string + offset, message_string_size - offset - 1, "%8lu.%03lu ", currentTime / 1000, + currentTime % 1000); + } + memcpy(message_string + offset, buffer, size); + datalayer.system.info.logged_can_messages_offset = offset + size; // Update offset in buffer + return size; +#endif // DEBUG_VIA_WEB +#endif // DEBUG_LOG + return 0; +} + +void Logging::printf(const char* fmt, ...) { +#ifdef DEBUG_LOG + char* message_string = datalayer.system.info.logged_can_messages; + int offset = datalayer.system.info.logged_can_messages_offset; // Keeps track of the current position in the buffer + size_t message_string_size = sizeof(datalayer.system.info.logged_can_messages); +#ifdef DEBUG_VIA_USB + static char buf[128]; + message_string = buf; + offset = 0; + message_string_size = sizeof(buf); +#endif +#ifdef DEBUG_VIA_WEB + if (datalayer.system.info.can_logging_active) { + return; + } + message_string = datalayer.system.info.logged_can_messages; + offset = datalayer.system.info.logged_can_messages_offset; // Keeps track of the current position in the buffer + message_string_size = sizeof(datalayer.system.info.logged_can_messages); +#endif + if (offset + 128 > sizeof(datalayer.system.info.logged_can_messages)) { + // Not enough space, reset and start from the beginning + offset = 0; + } + unsigned long currentTime = millis(); + // Add timestamp + offset += snprintf(message_string + offset, message_string_size - offset - 1, "%8lu.%03lu ", currentTime / 1000, + currentTime % 1000); + + va_list(args); + va_start(args, fmt); + offset += vsnprintf(message_string + offset, message_string_size - offset - 1, fmt, args); + va_end(args); + + if (datalayer.system.info.can_logging_active) { + size_t size = offset; + size_t n = 0; + while (size--) { + if (Serial.write(*message_string++)) + n++; + else + break; + } + } else { + datalayer.system.info.logged_can_messages_offset = offset; // Update offset in buffer + } +#endif // DEBUG_LOG +} diff --git a/Software/src/devboard/utils/logging.h b/Software/src/devboard/utils/logging.h new file mode 100644 index 00000000..09b91458 --- /dev/null +++ b/Software/src/devboard/utils/logging.h @@ -0,0 +1,16 @@ +#ifndef __LOGGING_H__ +#define __LOGGING_H__ + +#include +#include "Print.h" + +class Logging : public Print { + public: + virtual size_t write(const uint8_t* buffer, size_t size); + virtual size_t write(uint8_t) { return 0; } + void printf(const char* fmt, ...); + Logging() {} +}; + +extern Logging logging; +#endif // __LOGGING_H__ diff --git a/Software/src/devboard/utils/types.h b/Software/src/devboard/utils/types.h index 126aff26..d5cbf2c7 100644 --- a/Software/src/devboard/utils/types.h +++ b/Software/src/devboard/utils/types.h @@ -51,6 +51,13 @@ typedef struct { } data; } CAN_frame; +enum frameDirection { MSG_RX, MSG_TX }; //RX = 0, TX = 1 + +typedef struct { + CAN_frame frame; + frameDirection direction; +} CAN_log_frame; + std::string getBMSStatus(bms_status_enum status); #endif diff --git a/Software/src/devboard/webserver/advanced_battery_html.cpp b/Software/src/devboard/webserver/advanced_battery_html.cpp index 3f7eec4e..c1569714 100644 --- a/Software/src/devboard/webserver/advanced_battery_html.cpp +++ b/Software/src/devboard/webserver/advanced_battery_html.cpp @@ -20,6 +20,44 @@ String advanced_battery_processor(const String& var) { // Start a new block with a specific background color content += "
"; +#ifdef BOLT_AMPERA_BATTERY + content += "

5V Reference: " + String(datalayer_extended.boltampera.battery_5V_ref) + "

"; + content += "

Module 1 temp: " + String(datalayer_extended.boltampera.battery_module_temp_1) + "

"; + content += "

Module 2 temp: " + String(datalayer_extended.boltampera.battery_module_temp_2) + "

"; + content += "

Module 3 temp: " + String(datalayer_extended.boltampera.battery_module_temp_3) + "

"; + content += "

Module 4 temp: " + String(datalayer_extended.boltampera.battery_module_temp_4) + "

"; + content += "

Module 5 temp: " + String(datalayer_extended.boltampera.battery_module_temp_5) + "

"; + content += "

Module 6 temp: " + String(datalayer_extended.boltampera.battery_module_temp_6) + "

"; + content += + "

Cell average voltage: " + String(datalayer_extended.boltampera.battery_cell_average_voltage) + "

"; + content += + "

Cell average voltage 2: " + String(datalayer_extended.boltampera.battery_cell_average_voltage_2) + "

"; + content += "

Terminal voltage: " + String(datalayer_extended.boltampera.battery_terminal_voltage) + "

"; + content += + "

Ignition power mode: " + String(datalayer_extended.boltampera.battery_ignition_power_mode) + "

"; + content += "

Battery current (7E7): " + String(datalayer_extended.boltampera.battery_current_7E7) + "

"; + content += "

Capacity MY17-18: " + String(datalayer_extended.boltampera.battery_capacity_my17_18) + "

"; + content += "

Capacity MY19+: " + String(datalayer_extended.boltampera.battery_capacity_my19plus) + "

"; + content += "

SOC Display: " + String(datalayer_extended.boltampera.battery_SOC_display) + "

"; + content += "

SOC Raw highprec: " + String(datalayer_extended.boltampera.battery_SOC_raw_highprec) + "

"; + content += "

Max temp: " + String(datalayer_extended.boltampera.battery_max_temperature) + "

"; + content += "

Min temp: " + String(datalayer_extended.boltampera.battery_min_temperature) + "

"; + content += "

Cell max mV: " + String(datalayer_extended.boltampera.battery_max_cell_voltage) + "

"; + content += "

Cell min mV: " + String(datalayer_extended.boltampera.battery_min_cell_voltage) + "

"; + content += "

Lowest cell: " + String(datalayer_extended.boltampera.battery_lowest_cell) + "

"; + content += "

Highest cell: " + String(datalayer_extended.boltampera.battery_highest_cell) + "

"; + content += + "

Internal resistance: " + String(datalayer_extended.boltampera.battery_internal_resistance) + "

"; + content += "

Voltage: " + String(datalayer_extended.boltampera.battery_voltage_polled) + "

"; + content += "

Isolation Ohm: " + String(datalayer_extended.boltampera.battery_vehicle_isolation) + "

"; + content += "

Isolation kOhm: " + String(datalayer_extended.boltampera.battery_isolation_kohm) + "

"; + content += "

HV locked: " + String(datalayer_extended.boltampera.battery_HV_locked) + "

"; + content += "

Crash event: " + String(datalayer_extended.boltampera.battery_crash_event) + "

"; + content += "

HVIL: " + String(datalayer_extended.boltampera.battery_HVIL) + "

"; + content += "

HVIL status: " + String(datalayer_extended.boltampera.battery_HVIL_status) + "

"; + content += "

Current (7E4): " + String(datalayer_extended.boltampera.battery_current_7E4) + "

"; +#endif //BOLT_AMPERA_BATTERY + #ifdef BMW_IX_BATTERY content += "

Battery Voltage after Contactor: " + String(datalayer_extended.bmwix.battery_voltage_after_contactor) + @@ -311,6 +349,8 @@ String advanced_battery_processor(const String& var) { static_cast(datalayer_extended.tesla.battery_energy_to_charge_complete_m1) * 0.02; float energy_buffer = static_cast(datalayer_extended.tesla.battery_energy_buffer) * 0.1; float energy_buffer_m1 = static_cast(datalayer_extended.tesla.battery_energy_buffer_m1) * 0.01; + float expected_energy_remaining_m1 = + static_cast(datalayer_extended.tesla.battery_expected_energy_remaining_m1) * 0.02; float total_discharge = static_cast(datalayer_extended.tesla.battery_total_discharge); float total_charge = static_cast(datalayer_extended.tesla.battery_total_charge); float packMass = static_cast(datalayer_extended.tesla.battery_packMass); @@ -324,50 +364,85 @@ String advanced_battery_processor(const String& var) { float soc_max = static_cast(datalayer_extended.tesla.battery_soc_max) * 0.1; float soc_min = static_cast(datalayer_extended.tesla.battery_soc_min) * 0.1; float soc_ui = static_cast(datalayer_extended.tesla.battery_soc_ui) * 0.1; - - // Comment what data you would like to dislay, order can be changed. - content += "

Battery Beginning of Life: " + String(beginning_of_life) + " kWh

"; - content += "

BattTempPct: " + String(battTempPct) + "

"; - content += "

PCS Lv Bus: " + String(dcdcLvBusVolt) + " V

"; - content += "

PCS Hv Bus: " + String(dcdcHvBusVolt) + " V

"; - content += "

PCS Lv Output: " + String(dcdcLvOutputCurrent) + " A

"; - - //if using older BMS <2021 and comment 0x352 without MUX - //content += "

Nominal Full Pack Energy: " + String(nominal_full_pack_energy) + " kWh

"; - //content += "

Nominal Energy Remaining: " + String(nominal_energy_remaining) + " kWh

"; - //content += "

Ideal Energy Remaining: " + String(ideal_energy_remaining) + " kWh

"; - //content += "

Energy to Charge Complete: " + String(energy_to_charge_complete) + " kWh

"; - //content += "

Energy Buffer: " + String(energy_buffer) + " kWh

"; - - //if using newer BMS >2021 and comment 0x352 with MUX - content += "

Nominal Full Pack Energy m0: " + String(nominal_full_pack_energy_m0) + " kWh

"; - content += "

Nominal Energy Remaining m0: " + String(nominal_energy_remaining_m0) + " kWh

"; - content += "

Ideal Energy Remaining m0: " + String(ideal_energy_remaining_m0) + " kWh

"; - content += "

Energy to Charge Complete m1: " + String(energy_to_charge_complete_m1) + " kWh

"; - content += "

Energy Buffer m1: " + String(energy_buffer_m1) + " kWh

"; - - content += "

packConfigMultiplexer: " + String(datalayer_extended.tesla.battery_packConfigMultiplexer) + "

"; - content += "

moduleType: " + String(datalayer_extended.tesla.battery_moduleType) + "

"; - content += "

reserveConfig: " + String(datalayer_extended.tesla.battery_reservedConfig) + "

"; - content += "

Full Charge Complete: " + String(datalayer_extended.tesla.battery_full_charge_complete) + "

"; - content += "

Total Discharge: " + String(total_discharge) + " kWh

"; - content += "

Total Charge: " + String(total_charge) + " kWh

"; - content += "

Battery Pack Mass: " + String(packMass) + " KG

"; - content += "

Platform Max Bus Voltage: " + String(platformMaxBusVoltage) + " V

"; - content += "

BMS Min Voltage: " + String(bms_min_voltage) + " V

"; - content += "

BMS Max Voltage: " + String(bms_max_voltage) + " V

"; - content += "

Max Charge Current: " + String(max_charge_current) + " A

"; - content += "

Max Discharge Current: " + String(max_discharge_current) + " A

"; - content += "

Battery SOC Ave: " + String(soc_ave) + "

"; - content += "

Battery SOC Max: " + String(soc_max) + "

"; - content += "

Battery SOC Min: " + String(soc_min) + "

"; - content += "

Battery SOC UI: " + String(soc_ui) + "

"; + float BrickVoltageMax = static_cast(datalayer_extended.tesla.battery_BrickVoltageMax) * 0.002; + float BrickVoltageMin = static_cast(datalayer_extended.tesla.battery_BrickVoltageMin) * 0.002; + float BrickModelTMax = static_cast(datalayer_extended.tesla.battery_BrickTempMinNum) * 0.5 - 40; + float BrickModelTMin = static_cast(datalayer_extended.tesla.battery_BrickModelTMin) * 0.5 - 40; + float isolationResistance = static_cast(datalayer_extended.tesla.battery_BMS_isolationResistance) * 10; + float PCS_dcdcMaxOutputCurrentAllowed = + static_cast(datalayer_extended.tesla.battery_PCS_dcdcMaxOutputCurrentAllowed) * 0.1; + float PCS_dcdcTemp = static_cast(datalayer_extended.tesla.PCS_dcdcTemp) * 0.1 - 40; + float PCS_ambientTemp = static_cast(datalayer_extended.tesla.PCS_ambientTemp) * 0.1 - 40; + float BMS_maxRegenPower = static_cast(datalayer_extended.tesla.BMS_maxRegenPower) * 0.01; + float BMS_maxDischargePower = static_cast(datalayer_extended.tesla.BMS_maxDischargePower) * 0.013; + float BMS_maxStationaryHeatPower = static_cast(datalayer_extended.tesla.BMS_maxStationaryHeatPower) * 0.01; + float BMS_hvacPowerBudget = static_cast(datalayer_extended.tesla.BMS_hvacPowerBudget) * 0.02; + float BMS_powerDissipation = static_cast(datalayer_extended.tesla.BMS_powerDissipation) * 0.02; + float BMS_flowRequest = static_cast(datalayer_extended.tesla.BMS_flowRequest) * 0.3; + float BMS_inletActiveCoolTargetT = + static_cast(datalayer_extended.tesla.BMS_inletActiveCoolTargetT) * 0.25 - 25; + float BMS_inletPassiveTargetT = static_cast(datalayer_extended.tesla.BMS_inletPassiveTargetT) * 0.25 - 25; + float BMS_inletActiveHeatTargetT = + static_cast(datalayer_extended.tesla.BMS_inletActiveHeatTargetT) * 0.25 - 25; + float BMS_packTMin = static_cast(datalayer_extended.tesla.BMS_packTMin) * 0.25 - 25; + float BMS_packTMax = static_cast(datalayer_extended.tesla.BMS_packTMax) * 0.25 - 25; + float PCS_dcdcMaxLvOutputCurrent = static_cast(datalayer_extended.tesla.PCS_dcdcMaxLvOutputCurrent) * 0.1; + float PCS_dcdcCurrentLimit = static_cast(datalayer_extended.tesla.PCS_dcdcCurrentLimit) * 0.1; + float PCS_dcdcLvOutputCurrentTempLimit = + static_cast(datalayer_extended.tesla.PCS_dcdcLvOutputCurrentTempLimit) * 0.1; + float PCS_dcdcUnifiedCommand = static_cast(datalayer_extended.tesla.PCS_dcdcUnifiedCommand) * 0.001; + float PCS_dcdcCLAControllerOutput = + static_cast(datalayer_extended.tesla.PCS_dcdcCLAControllerOutput * 0.001); + float PCS_dcdcTankVoltage = static_cast(datalayer_extended.tesla.PCS_dcdcTankVoltage); + float PCS_dcdcTankVoltageTarget = static_cast(datalayer_extended.tesla.PCS_dcdcTankVoltageTarget); + float PCS_dcdcClaCurrentFreq = static_cast(datalayer_extended.tesla.PCS_dcdcClaCurrentFreq) * 0.0976563; + float PCS_dcdcTCommMeasured = static_cast(datalayer_extended.tesla.PCS_dcdcTCommMeasured) * 0.00195313; + float PCS_dcdcShortTimeUs = static_cast(datalayer_extended.tesla.PCS_dcdcShortTimeUs) * 0.000488281; + float PCS_dcdcHalfPeriodUs = static_cast(datalayer_extended.tesla.PCS_dcdcHalfPeriodUs) * 0.000488281; + float PCS_dcdcIntervalMaxFrequency = static_cast(datalayer_extended.tesla.PCS_dcdcIntervalMaxFrequency); + float PCS_dcdcIntervalMaxHvBusVolt = + static_cast(datalayer_extended.tesla.PCS_dcdcIntervalMaxHvBusVolt) * 0.1; + float PCS_dcdcIntervalMaxLvBusVolt = + static_cast(datalayer_extended.tesla.PCS_dcdcIntervalMaxLvBusVolt) * 0.1; + float PCS_dcdcIntervalMaxLvOutputCurr = + static_cast(datalayer_extended.tesla.PCS_dcdcIntervalMaxLvOutputCurr); + float PCS_dcdcIntervalMinFrequency = static_cast(datalayer_extended.tesla.PCS_dcdcIntervalMinFrequency); + float PCS_dcdcIntervalMinHvBusVolt = + static_cast(datalayer_extended.tesla.PCS_dcdcIntervalMinHvBusVolt) * 0.1; + float PCS_dcdcIntervalMinLvBusVolt = + static_cast(datalayer_extended.tesla.PCS_dcdcIntervalMinLvBusVolt) * 0.1; + float PCS_dcdcIntervalMinLvOutputCurr = + static_cast(datalayer_extended.tesla.PCS_dcdcIntervalMinLvOutputCurr); + float PCS_dcdc12vSupportLifetimekWh = + static_cast(datalayer_extended.tesla.PCS_dcdc12vSupportLifetimekWh) * 0.01; + float HVP_hvp1v5Ref = static_cast(datalayer_extended.tesla.HVP_hvp1v5Ref) * 0.1; + float HVP_shuntCurrentDebug = static_cast(datalayer_extended.tesla.HVP_shuntCurrentDebug) * 0.1; + float HVP_dcLinkVoltage = static_cast(datalayer_extended.tesla.HVP_dcLinkVoltage) * 0.1; + float HVP_packVoltage = static_cast(datalayer_extended.tesla.HVP_packVoltage) * 0.1; + float HVP_fcLinkVoltage = static_cast(datalayer_extended.tesla.HVP_fcLinkVoltage) * 0.1; + float HVP_packContVoltage = static_cast(datalayer_extended.tesla.HVP_packContVoltage) * 0.1; + float HVP_packNegativeV = static_cast(datalayer_extended.tesla.HVP_packNegativeV) * 0.1; + float HVP_packPositiveV = static_cast(datalayer_extended.tesla.HVP_packPositiveV) * 0.1; + float HVP_pyroAnalog = static_cast(datalayer_extended.tesla.HVP_pyroAnalog) * 0.1; + float HVP_dcLinkNegativeV = static_cast(datalayer_extended.tesla.HVP_dcLinkNegativeV) * 0.1; + float HVP_dcLinkPositiveV = static_cast(datalayer_extended.tesla.HVP_dcLinkPositiveV) * 0.1; + float HVP_fcLinkNegativeV = static_cast(datalayer_extended.tesla.HVP_fcLinkNegativeV) * 0.1; + float HVP_fcContCoilCurrent = static_cast(datalayer_extended.tesla.HVP_fcContCoilCurrent) * 0.1; + float HVP_fcContVoltage = static_cast(datalayer_extended.tesla.HVP_fcContVoltage) * 0.1; + float HVP_hvilInVoltage = static_cast(datalayer_extended.tesla.HVP_hvilInVoltage) * 0.1; + float HVP_hvilOutVoltage = static_cast(datalayer_extended.tesla.HVP_hvilOutVoltage) * 0.1; + float HVP_fcLinkPositiveV = static_cast(datalayer_extended.tesla.HVP_fcLinkPositiveV) * 0.1; + float HVP_packContCoilCurrent = static_cast(datalayer_extended.tesla.HVP_packContCoilCurrent) * 0.1; + float HVP_battery12V = static_cast(datalayer_extended.tesla.HVP_battery12V) * 0.1; + float HVP_shuntRefVoltageDbg = static_cast(datalayer_extended.tesla.HVP_shuntRefVoltageDbg) * 0.001; + float HVP_shuntAuxCurrentDbg = static_cast(datalayer_extended.tesla.HVP_shuntAuxCurrentDbg) * 0.1; + float HVP_shuntBarTempDbg = static_cast(datalayer_extended.tesla.HVP_shuntBarTempDbg) * 0.01; + float HVP_shuntAsicTempDbg = static_cast(datalayer_extended.tesla.HVP_shuntAsicTempDbg) * 0.01; static const char* contactorText[] = {"UNKNOWN(0)", "OPEN", "CLOSING", "BLOCKED", "OPENING", "CLOSED", "UNKNOWN(6)", "WELDED", "POS_CL", "NEG_CL", "UNKNOWN(10)", "UNKNOWN(11)", "UNKNOWN(12)"}; - content += "

Contactor Status: " + String(contactorText[datalayer_extended.tesla.status_contactor]) + "

"; - static const char* hvilStatusState[] = {"NOT OK", + static const char* hvilStatusState[] = {"NOT Ok", "STATUS_OK", "CURRENT_SOURCE_FAULT", "INTERNAL_OPEN_FAULT", @@ -383,17 +458,292 @@ String advanced_battery_processor(const String& var) { "UNKNOWN(13)", "UNKNOWN(14)", "UNKNOWN(15)"}; - content += "

HVIL: " + String(hvilStatusState[datalayer_extended.tesla.hvil_status]) + "

"; static const char* contactorState[] = {"SNA", "OPEN", "PRECHARGE", "BLOCKED", "PULLED_IN", "OPENING", "ECONOMIZED", "WELDED", "UNKNOWN(8)", "UNKNOWN(9)", "UNKNOWN(10)", "UNKNOWN(11)"}; + static const char* BMS_state[] = {"STANDBY", "DRIVE", "SUPPORT", "CHARGE", "FEIM", + "CLEAR_FAULT", "FAULT", "WELD", "TEST", "SNA"}; + static const char* BMS_contactorState[] = {"SNA", "OPEN", "OPENING", "CLOSING", "CLOSED", "WELDED", "BLOCKED"}; + static const char* BMS_hvState[] = {"DOWN", "COMING_UP", "GOING_DOWN", "UP_FOR_DRIVE", + "UP_FOR_CHARGE", "UP_FOR_DC_CHARGE", "UP"}; + static const char* BMS_uiChargeStatus[] = {"DISCONNECTED", "NO_POWER", "ABOUT_TO_CHARGE", + "CHARGING", "CHARGE_COMPLETE", "CHARGE_STOPPED"}; + static const char* PCS_dcdcStatus[] = {"IDLE", "ACTIVE", "FAULTED"}; + static const char* PCS_dcdcMainState[] = {"STANDBY", "12V_SUPPORT_ACTIVE", "PRECHARGE_STARTUP", + "PRECHARGE_ACTIVE", "DIS_HVBUS_ACTIVE", "SHUTDOWN", + "FAULTED"}; + static const char* PCS_dcdcSubState[] = {"PWR_UP_INIT", + "STANDBY", + "12V_SUPPORT_ACTIVE", + "DIS_HVBUS", + "PCHG_FAST_DIS_HVBUS", + "PCHG_SLOW_DIS_HVBUS", + "PCHG_DWELL_CHARGE", + "PCHG_DWELL_WAIT", + "PCHG_DI_RECOVERY_WAIT", + "PCHG_ACTIVE", + "PCHG_FLT_FAST_DIS_HVBUS", + "SHUTDOWN", + "12V_SUPPORT_FAULTED", + "DIS_HVBUS_FAULTED", + "PCHG_FAULTED", + "CLEAR_FAULTS", + "FAULTED", + "NUM"}; + static const char* BMS_powerLimitState[] = {"NOT_CALCULATED_FOR_DRIVE", "CALCULATED_FOR_DRIVE"}; + static const char* HVP_status[] = {"INVALID", "NOT_AVAILABLE", "STALE", "VALID"}; + static const char* HVP_contactor[] = {"NOT_ACTIVE", "ACTIVE", "COMPLETED"}; + static const char* falseTrue[] = {"False", "True"}; + static const char* noYes[] = {"No", "Yes"}; + static const char* Fault[] = {"NOT_ACTIVE", "ACTIVE"}; + //0x20A 522 HVP_contatorState + content += "

Contactor Status: " + String(contactorText[datalayer_extended.tesla.status_contactor]) + "

"; + content += "

HVIL: " + String(hvilStatusState[datalayer_extended.tesla.hvil_status]) + "

"; content += "

Negative contactor: " + String(contactorState[datalayer_extended.tesla.packContNegativeState]) + "

"; content += "

Positive contactor: " + String(contactorState[datalayer_extended.tesla.packContPositiveState]) + "

"; - static const char* falseTrue[] = {"False", "True"}; - content += "

Closing allowed?: " + String(falseTrue[datalayer_extended.tesla.packCtrsClosingAllowed]) + "

"; - content += "

Pyrotest: " + String(falseTrue[datalayer_extended.tesla.pyroTestInProgress]) + "

"; + content += + "

Closing allowed?: " + String(noYes[datalayer_extended.tesla.packCtrsClosingAllowed]) + "

"; //bool + content += + "

Pyrotest in Progress: " + String(noYes[datalayer_extended.tesla.pyroTestInProgress]) + "

"; //bool + content += "

Contactors Open Now Requested: " + + String(noYes[datalayer_extended.tesla.battery_packCtrsOpenNowRequested]) + "

"; //bool + content += + "

Contactors Open Requested: " + String(noYes[datalayer_extended.tesla.battery_packCtrsOpenRequested]) + + "

"; //bool + content += "

Contactors Request Status: " + + String(HVP_contactor[datalayer_extended.tesla.battery_packCtrsRequestStatus]) + "

"; + content += "

Contactors Reset Request Required: " + + String(noYes[datalayer_extended.tesla.battery_packCtrsResetRequestRequired]) + "

"; //bool + content += + "

DC Link Allowed to Energize: " + String(noYes[datalayer_extended.tesla.battery_dcLinkAllowedToEnergize]) + + "

"; //bool + // Comment what data you would like to dislay, order can be changed. + //0x292 658 BMS_socStates + content += "

Battery Beginning of Life: " + String(beginning_of_life) + " KWh

"; + content += "

BattTempPct: " + String(battTempPct) + "

"; + content += "

Battery SOC Ave: " + String(soc_ave) + "

"; + content += "

Battery SOC Max: " + String(soc_max) + "

"; + content += "

Battery SOC Min: " + String(soc_min) + "

"; + content += "

Battery SOC UI: " + String(soc_ui) + "

"; + //0x2B4 PCS_dcdcRailStatus + content += "

PCS Lv Bus: " + String(dcdcLvBusVolt) + " V

"; + content += "

PCS Hv Bus: " + String(dcdcHvBusVolt) + " V

"; + content += "

PCS Lv Output: " + String(dcdcLvOutputCurrent) + " A

"; + //0x2A4 676 PCS_thermalStatus + content += "

PCS dcdc Temp: " + String(PCS_dcdcTemp) + " DegC

"; + content += "

PCS Ambient Temp: " + String(PCS_ambientTemp) + " DegC

"; + //0x224 548 PCS_dcdcStatus + content += + "

Precharge Status: " + String(PCS_dcdcStatus[datalayer_extended.tesla.battery_PCS_dcdcPrechargeStatus]) + + "

"; + content += + "

12V Support Status: " + String(PCS_dcdcStatus[datalayer_extended.tesla.battery_PCS_dcdc12VSupportStatus]) + + "

"; + content += "

HV Bus Discharge Status: " + + String(PCS_dcdcStatus[datalayer_extended.tesla.battery_PCS_dcdcHvBusDischargeStatus]) + "

"; + content += + "

Main State: " + String(PCS_dcdcMainState[datalayer_extended.tesla.battery_PCS_dcdcMainState]) + "

"; + content += + "

Sub State: " + String(PCS_dcdcSubState[datalayer_extended.tesla.battery_PCS_dcdcSubState]) + "

"; + content += "

PCS Faulted: " + String(Fault[datalayer_extended.tesla.battery_PCS_dcdcFaulted]) + "

"; //bool + content += "

Output Is Limited: " + String(Fault[datalayer_extended.tesla.battery_PCS_dcdcOutputIsLimited]) + + "

"; //bool + content += "

Max Output Current Allowed: " + String(PCS_dcdcMaxOutputCurrentAllowed) + " A

"; + content += "

Precharge Rty Cnt: " + String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdcPrechargeRtyCnt]) + + "

"; //bool + content += + "

12V Support Rty Cnt: " + String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdc12VSupportRtyCnt]) + + "

"; // bool + content += "

Discharge Rty Cnt: " + String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdcDischargeRtyCnt]) + + "

"; //bool + content += "

PWM Enable Line: " + String(Fault[datalayer_extended.tesla.battery_PCS_dcdcPwmEnableLine]) + + "

"; //bool + content += "

Supporting Fixed LV Target: " + + String(Fault[datalayer_extended.tesla.battery_PCS_dcdcSupportingFixedLvTarget]) + "

"; //bool + content += "

Precharge Restart Cnt: " + + String(falseTrue[datalayer_extended.tesla.battery_PCS_dcdcPrechargeRestartCnt]) + "

"; //bool + content += "

Initial Precharge Substate: " + + String(PCS_dcdcSubState[datalayer_extended.tesla.battery_PCS_dcdcInitialPrechargeSubState]) + "

"; + //0x2C4 708 PCS_logging + content += "

PCS_dcdcMaxLvOutputCurrent: " + String(PCS_dcdcMaxLvOutputCurrent) + " A

"; + content += "

PCS_dcdcCurrentLimit: " + String(PCS_dcdcCurrentLimit) + " A

"; + content += "

PCS_dcdcLvOutputCurrentTempLimit: " + String(PCS_dcdcLvOutputCurrentTempLimit) + " A

"; + content += "

PCS_dcdcUnifiedCommand: " + String(PCS_dcdcUnifiedCommand) + "

"; + content += "

PCS_dcdcCLAControllerOutput: " + String(PCS_dcdcCLAControllerOutput) + "

"; + content += "

PCS_dcdcTankVoltage: " + String(PCS_dcdcTankVoltage) + " V

"; + content += "

PCS_dcdcTankVoltageTarget: " + String(PCS_dcdcTankVoltageTarget) + " V

"; + content += "

PCS_dcdcClaCurrentFreq: " + String(PCS_dcdcClaCurrentFreq) + " kHz

"; + content += "

PCS_dcdcTCommMeasured: " + String(PCS_dcdcTCommMeasured) + " us

"; + content += "

PCS_dcdcShortTimeUs: " + String(PCS_dcdcShortTimeUs) + " us

"; + content += "

PCS_dcdcHalfPeriodUs: " + String(PCS_dcdcHalfPeriodUs) + " us

"; + content += "

PCS_dcdcIntervalMaxFrequency: " + String(PCS_dcdcIntervalMaxFrequency) + " kHz

"; + content += "

PCS_dcdcIntervalMaxHvBusVolt: " + String(PCS_dcdcIntervalMaxHvBusVolt) + " V

"; + content += "

PCS_dcdcIntervalMaxLvBusVolt: " + String(PCS_dcdcIntervalMaxLvBusVolt) + " V

"; + content += "

PCS_dcdcIntervalMaxLvOutputCurr: " + String(PCS_dcdcIntervalMaxLvOutputCurr) + " A

"; + content += "

PCS_dcdcIntervalMinFrequency: " + String(PCS_dcdcIntervalMinFrequency) + " kHz

"; + content += "

PCS_dcdcIntervalMinHvBusVolt: " + String(PCS_dcdcIntervalMinHvBusVolt) + " V

"; + content += "

PCS_dcdcIntervalMinLvBusVolt: " + String(PCS_dcdcIntervalMinLvBusVolt) + " V

"; + content += "

PCS_dcdcIntervalMinLvOutputCurr: " + String(PCS_dcdcIntervalMinLvOutputCurr) + " A

"; + content += "

PCS_dcdc12vSupportLifetimekWh: " + String(PCS_dcdc12vSupportLifetimekWh) + " kWh

"; + //0x3D2 978 BMS_kwhCounter + content += "

Total Discharge: " + String(total_discharge) + " KWh

"; + content += "

Total Charge: " + String(total_charge) + " KWh

"; + //0x212 530 BMS_status + content += "

Isolation Resistance: " + String(isolationResistance) + " kOhms

"; + content += + "

BMS Contactor State: " + String(BMS_contactorState[datalayer_extended.tesla.battery_BMS_contactorState]) + + "

"; + content += "

BMS State: " + String(BMS_state[datalayer_extended.tesla.battery_BMS_state]) + "

"; + content += "

BMS HV State: " + String(BMS_hvState[datalayer_extended.tesla.battery_BMS_hvState]) + "

"; + content += "

BMS UI Charge Status: " + String(BMS_uiChargeStatus[datalayer_extended.tesla.battery_BMS_hvState]) + + "

"; + content += "

BMS PCS PWM Enabled: " + String(Fault[datalayer_extended.tesla.battery_BMS_pcsPwmEnabled]) + + "

"; //bool + //0x352 850 BMS_energyStatus + content += "

Early BMS 0x352:

"; //if using older BMS <2021 and comment 0x352 without MUX + content += "

Calculated SOH: " + String(nominal_full_pack_energy * 100 / beginning_of_life) + "

"; + content += "

Nominal Full Pack Energy: " + String(nominal_full_pack_energy) + " KWh

"; + content += "

Nominal Energy Remaining: " + String(nominal_energy_remaining) + " KWh

"; + content += "

Ideal Energy Remaining: " + String(ideal_energy_remaining) + " KWh

"; + content += "

Energy to Charge Complete: " + String(energy_to_charge_complete) + " KWh

"; + content += "

Energy Buffer: " + String(energy_buffer) + " KWh

"; + content += "

Full Charge Complete: " + String(noYes[datalayer_extended.tesla.battery_full_charge_complete]) + + "

"; //bool + //0x352 850 BMS_energyStatus + content += "

Late BMS 0x352 with Mux:

"; //if using newer BMS >2021 and comment 0x352 with MUX + content += "

Calculated SOH: " + String(nominal_full_pack_energy_m0 * 100 / beginning_of_life) + "

"; + content += "

Nominal Full Pack Energy: " + String(nominal_full_pack_energy_m0) + " KWh

"; + content += "

Nominal Energy Remaining: " + String(nominal_energy_remaining_m0) + " KWh

"; + content += "

Ideal Energy Remaining: " + String(ideal_energy_remaining_m0) + " KWh

"; + content += "

Energy to Charge Complete: " + String(energy_to_charge_complete_m1) + " KWh

"; + content += "

Energy Buffer: " + String(energy_buffer_m1) + " KWh

"; + content += "

Expected Energy Remaining: " + String(expected_energy_remaining_m1) + " KWh

"; + content += "

Fully Charged: " + String(noYes[datalayer_extended.tesla.battery_fully_charged]) + "

"; //bool + //0x392 BMS_packConfig + //content += "

packConfigMultiplexer: " + String(datalayer_extended.tesla.battery_packConfigMultiplexer) + "

"; + //content += "

moduleType: " + String(datalayer_extended.tesla.battery_moduleType) + "

"; + //content += "

reserveConfig: " + String(datalayer_extended.tesla.battery_reservedConfig) + "

"; + content += "

Battery Pack Mass: " + String(packMass) + " KG

"; + content += "

Platform Max Bus Voltage: " + String(platformMaxBusVoltage) + " V

"; + //0x2D2 722 BMSVAlimits + content += "

BMS Min Voltage: " + String(bms_min_voltage) + " V

"; + content += "

BMS Max Voltage: " + String(bms_max_voltage) + " V

"; + content += "

Max Charge Current: " + String(max_charge_current) + " A

"; + content += "

Max Discharge Current: " + String(max_discharge_current) + " A

"; + //0x332 818 BMS_bmbMinMax + content += "

Brick Voltage Max: " + String(BrickVoltageMax) + " V

"; + content += "

Brick Voltage Min: " + String(BrickVoltageMin) + " V

"; + content += "

Brick Temp Max Num: " + String(datalayer_extended.tesla.battery_BrickTempMaxNum) + "

"; + content += "

Brick Temp Min Num: " + String(datalayer_extended.tesla.battery_BrickTempMinNum) + "

"; + content += "

Brick Model Temp Max: " + String(BrickModelTMax) + " C

"; + content += "

Brick Model Temp Min: " + String(BrickModelTMin) + " C

"; + //0x252 594 BMS_powerAvailable + content += "

Max Regen Power: " + String(BMS_maxRegenPower) + " KW

"; + content += "

Max Discharge Power: " + String(BMS_maxDischargePower) + " KW

"; + content += "

Max Stationary Heat Power: " + String(BMS_maxStationaryHeatPower) + " KWh

"; + content += "

HVAC Power Budget: " + String(BMS_hvacPowerBudget) + " KW

"; + content += "

Not Enough Power For Heat Pump: " + + String(falseTrue[datalayer_extended.tesla.BMS_notEnoughPowerForHeatPump]) + "

"; //bool + content += + "

Power Limit State: " + String(BMS_powerLimitState[datalayer_extended.tesla.BMS_powerLimitState]) + "

"; + content += "

Inverter TQF: " + String(datalayer_extended.tesla.BMS_inverterTQF) + "

"; + //0x312 786 BMS_thermalStatus + content += "

Power Dissipation: " + String(BMS_powerDissipation) + " kW

"; + content += "

Flow Request: " + String(BMS_flowRequest) + " LPM

"; + content += "

Inlet Active Cool Target Temp: " + String(BMS_inletActiveCoolTargetT) + " DegC

"; + content += "

Inlet Passive Target Temp: " + String(BMS_inletPassiveTargetT) + " DegC

"; + content += "

Inlet Active Heat Target Temp: " + String(BMS_inletActiveHeatTargetT) + " DegC

"; + content += "

Pack Temp Min: " + String(BMS_packTMin) + " DegC

"; + content += "

Pack Temp Max: " + String(BMS_packTMax) + " DegC

"; + content += + "

PCS No Flow Request: " + String(Fault[datalayer_extended.tesla.BMS_pcsNoFlowRequest]) + "

"; //bool + content += + "

BMS No Flow Request: " + String(Fault[datalayer_extended.tesla.BMS_noFlowRequest]) + "

"; //bool + //0x7AA 1962 HVP_debugMessage + content += "

HVP_gpioPassivePyroDepl: " + String(Fault[datalayer_extended.tesla.HVP_gpioPassivePyroDepl]) + + "

"; //bool + content += "

HVP_gpioPyroIsoEn: " + String(Fault[datalayer_extended.tesla.HVP_gpioPyroIsoEn]) + "

"; //bool + content += "

HVP_gpioCpFaultIn: " + String(Fault[datalayer_extended.tesla.HVP_gpioCpFaultIn]) + "

"; //bool + content += "

HVP_gpioPackContPowerEn: " + String(Fault[datalayer_extended.tesla.HVP_gpioPackContPowerEn]) + + "

"; //bool + content += + "

HVP_gpioHvCablesOk: " + String(Fault[datalayer_extended.tesla.HVP_gpioHvCablesOk]) + "

"; //bool + content += + "

HVP_gpioHvpSelfEnable: " + String(Fault[datalayer_extended.tesla.HVP_gpioHvpSelfEnable]) + "

"; //bool + content += "

HVP_gpioLed: " + String(Fault[datalayer_extended.tesla.HVP_gpioLed]) + "

"; //bool + content += + "

HVP_gpioCrashSignal: " + String(Fault[datalayer_extended.tesla.HVP_gpioCrashSignal]) + "

"; //bool + content += "

HVP_gpioShuntDataReady: " + String(Fault[datalayer_extended.tesla.HVP_gpioShuntDataReady]) + + "

"; //bool + content += + "

HVP_gpioFcContPosAux: " + String(Fault[datalayer_extended.tesla.HVP_gpioFcContPosAux]) + "

"; //bool + content += + "

HVP_gpioFcContNegAux: " + String(Fault[datalayer_extended.tesla.HVP_gpioFcContNegAux]) + "

"; //bool + content += "

HVP_gpioBmsEout: " + String(Fault[datalayer_extended.tesla.HVP_gpioBmsEout]) + "

"; //bool + content += + "

HVP_gpioCpFaultOut: " + String(Fault[datalayer_extended.tesla.HVP_gpioCpFaultOut]) + "

"; //bool + content += "

HVP_gpioPyroPor: " + String(Fault[datalayer_extended.tesla.HVP_gpioPyroPor]) + "

"; //bool + content += "

HVP_gpioShuntEn: " + String(Fault[datalayer_extended.tesla.HVP_gpioShuntEn]) + "

"; //bool + content += "

HVP_gpioHvpVerEn: " + String(Fault[datalayer_extended.tesla.HVP_gpioHvpVerEn]) + "

"; //bool + content += + "

HVP_gpioPackCoontPosFlywheel: " + String(Fault[datalayer_extended.tesla.HVP_gpioPackCoontPosFlywheel]) + + "

"; //bool + content += + "

HVP_gpioCpLatchEnable: " + String(Fault[datalayer_extended.tesla.HVP_gpioCpLatchEnable]) + "

"; //bool + content += "

HVP_gpioPcsEnable: " + String(Fault[datalayer_extended.tesla.HVP_gpioPcsEnable]) + "

"; //bool + content += "

HVP_gpioPcsDcdcPwmEnable: " + String(Fault[datalayer_extended.tesla.HVP_gpioPcsDcdcPwmEnable]) + + "

"; //bool + content += "

HVP_gpioPcsChargePwmEnable: " + String(Fault[datalayer_extended.tesla.HVP_gpioPcsChargePwmEnable]) + + "

"; //bool + content += "

HVP_gpioFcContPowerEnable: " + String(Fault[datalayer_extended.tesla.HVP_gpioFcContPowerEnable]) + + "

"; //bool + content += + "

HVP_gpioHvilEnable: " + String(Fault[datalayer_extended.tesla.HVP_gpioHvilEnable]) + "

"; //bool + content += "

HVP_gpioSecDrdy: " + String(Fault[datalayer_extended.tesla.HVP_gpioSecDrdy]) + "

"; //bool + content += "

HVP_hvp1v5Ref: " + String(HVP_hvp1v5Ref) + " V

"; + content += "

HVP_shuntCurrentDebug: " + String(HVP_shuntCurrentDebug) + " A

"; + content += + "

HVP_packCurrentMia: " + String(noYes[datalayer_extended.tesla.HVP_packCurrentMia]) + "

"; //bool + content += "

HVP_auxCurrentMia: " + String(noYes[datalayer_extended.tesla.HVP_auxCurrentMia]) + "

"; //bool + content += + "

HVP_currentSenseMia: " + String(noYes[datalayer_extended.tesla.HVP_currentSenseMia]) + "

"; //bool + content += + "

HVP_shuntRefVoltageMismatch: " + String(noYes[datalayer_extended.tesla.HVP_shuntRefVoltageMismatch]) + + "

"; //bool + content += "

HVP_shuntThermistorMia: " + String(noYes[datalayer_extended.tesla.HVP_shuntThermistorMia]) + + "

"; //bool + content += "

HVP_shuntHwMia: " + String(noYes[datalayer_extended.tesla.HVP_shuntHwMia]) + "

"; //bool + content += "

HVP_dcLinkVoltage: " + String(HVP_dcLinkVoltage) + " V

"; + content += "

HVP_packVoltage: " + String(HVP_packVoltage) + " V

"; + content += "

HVP_fcLinkVoltage: " + String(HVP_fcLinkVoltage) + " V

"; + content += "

HVP_packContVoltage: " + String(HVP_packContVoltage) + " V

"; + content += "

HVP_packNegativeV: " + String(HVP_packNegativeV) + " V

"; + content += "

HVP_packPositiveV: " + String(HVP_packPositiveV) + " V

"; + content += "

HVP_pyroAnalog: " + String(HVP_pyroAnalog) + " V

"; + content += "

HVP_dcLinkNegativeV: " + String(HVP_dcLinkNegativeV) + " V

"; + content += "

HVP_dcLinkPositiveV: " + String(HVP_dcLinkPositiveV) + " V

"; + content += "

HVP_fcLinkNegativeV: " + String(HVP_fcLinkNegativeV) + " V

"; + content += "

HVP_fcContCoilCurrent: " + String(HVP_fcContCoilCurrent) + " A

"; + content += "

HVP_fcContVoltage: " + String(HVP_fcContVoltage) + " V

"; + content += "

HVP_hvilInVoltage: " + String(HVP_hvilInVoltage) + " V

"; + content += "

HVP_hvilOutVoltage: " + String(HVP_hvilOutVoltage) + " V

"; + content += "

HVP_fcLinkPositiveV: " + String(HVP_fcLinkPositiveV) + " V

"; + content += "

HVP_packContCoilCurrent: " + String(HVP_packContCoilCurrent) + " A

"; + content += "

HVP_battery12V: " + String(HVP_battery12V) + " V

"; + content += "

HVP_shuntRefVoltageDbg: " + String(HVP_shuntRefVoltageDbg) + " V

"; + content += "

HVP_shuntAuxCurrentDbg: " + String(HVP_shuntAuxCurrentDbg) + " A

"; + content += "

HVP_shuntBarTempDbg: " + String(HVP_shuntBarTempDbg) + " DegC

"; + content += "

HVP_shuntAsicTempDbg: " + String(HVP_shuntAsicTempDbg) + " DegC

"; + content += + "

HVP_shuntAuxCurrentStatus: " + String(HVP_status[datalayer_extended.tesla.HVP_shuntAuxCurrentStatus]) + + "

"; + content += + "

HVP_shuntBarTempStatus: " + String(HVP_status[datalayer_extended.tesla.HVP_shuntBarTempStatus]) + "

"; + content += "

HVP_shuntAsicTempStatus: " + String(HVP_status[datalayer_extended.tesla.HVP_shuntAsicTempStatus]) + + "

"; + #endif #ifdef NISSAN_LEAF_BATTERY @@ -680,9 +1030,10 @@ String advanced_battery_processor(const String& var) { content += "

soc max: " + String(datalayer_extended.zoePH2.battery_soc_max) + "

"; #endif //RENAULT_ZOE_GEN2_BATTERY -#if !defined(TESLA_BATTERY) && !defined(NISSAN_LEAF_BATTERY) && !defined(BMW_I3_BATTERY) && \ - !defined(BYD_ATTO_3_BATTERY) && !defined(RENAULT_ZOE_GEN2_BATTERY) && !defined(CELLPOWER_BMS) && \ - !defined(MEB_BATTERY) //Only the listed types have extra info +#if !defined(BMW_IX_BATTERY) && !defined(BOLT_AMPERA_BATTERY) && !defined(TESLA_BATTERY) && \ + !defined(NISSAN_LEAF_BATTERY) && !defined(BMW_I3_BATTERY) && !defined(BYD_ATTO_3_BATTERY) && \ + !defined(RENAULT_ZOE_GEN2_BATTERY) && !defined(CELLPOWER_BMS) && \ + !defined(MEB_BATTERY) // Only the listed types have extra info content += "No extra information available for this battery type"; #endif diff --git a/Software/src/devboard/webserver/can_logging_html.cpp b/Software/src/devboard/webserver/can_logging_html.cpp index 59f03823..e64de232 100644 --- a/Software/src/devboard/webserver/can_logging_html.cpp +++ b/Software/src/devboard/webserver/can_logging_html.cpp @@ -4,6 +4,10 @@ String can_logger_processor(const String& var) { if (var == "X") { + if (!datalayer.system.info.can_logging_active) { + datalayer.system.info.logged_can_messages_offset = 0; + datalayer.system.info.logged_can_messages[0] = '\0'; + } datalayer.system.info.can_logging_active = true; // Signal to main loop that we should log messages. Disabled by default for performance reasons String content = ""; @@ -19,7 +23,10 @@ String can_logger_processor(const String& var) { "monospace; }"; content += ""; content += " "; - content += " "; + content += " "; +#ifdef LOG_CAN_TO_SD + content += " "; +#endif content += ""; // Start a new block for the CAN messages @@ -47,9 +54,12 @@ String can_logger_processor(const String& var) { // Add JavaScript for navigation content += ""; return content; diff --git a/Software/src/devboard/webserver/debug_logging_html.cpp b/Software/src/devboard/webserver/debug_logging_html.cpp new file mode 100644 index 00000000..7dd9ede4 --- /dev/null +++ b/Software/src/devboard/webserver/debug_logging_html.cpp @@ -0,0 +1,36 @@ +#include "debug_logging_html.h" +#include +#include "../../datalayer/datalayer.h" + +#ifdef DEBUG_VIA_WEB +String debug_logger_processor(const String& var) { + String content = ""; + // Page format + content += ""; + content += " "; + content += " "; + content += ""; + + // Start a new block for the debug log messages + content += "
";
+  content += String(datalayer.system.info.logged_can_messages);
+  content += "
"; + + // Add JavaScript for navigation + content += ""; + return content; +} +#endif // DEBUG_VIA_WEB diff --git a/Software/src/devboard/webserver/debug_logging_html.h b/Software/src/devboard/webserver/debug_logging_html.h new file mode 100644 index 00000000..0b6ebc69 --- /dev/null +++ b/Software/src/devboard/webserver/debug_logging_html.h @@ -0,0 +1,16 @@ +#ifndef DEBUGLOGGER_H +#define DEBUGLOGGER_H + +#include +#include + +/** + * @brief Replaces placeholder with content section in web page + * + * @param[in] var + * + * @return String + */ +String debug_logger_processor(const String& var); + +#endif diff --git a/Software/src/devboard/webserver/events_html.cpp b/Software/src/devboard/webserver/events_html.cpp index 3cb3edbe..a602b938 100644 --- a/Software/src/devboard/webserver/events_html.cpp +++ b/Software/src/devboard/webserver/events_html.cpp @@ -39,11 +39,11 @@ String events_processor(const String& var) { for (const auto& event : order_events) { EVENTS_ENUM_TYPE event_handle = event.event_handle; event_pointer = event.event_pointer; -#ifdef DEBUG_VIA_USB - Serial.println("Event: " + String(get_event_enum_string(event_handle)) + - " count: " + String(event_pointer->occurences) + " seconds: " + String(event_pointer->timestamp) + - " data: " + String(event_pointer->data) + - " level: " + String(get_event_level_string(event_handle))); +#ifdef DEBUG_LOG + logging.println("Showing Event: " + String(get_event_enum_string(event_handle)) + + " count: " + String(event_pointer->occurences) + " seconds: " + String(event_pointer->timestamp) + + " data: " + String(event_pointer->data) + + " level: " + String(get_event_level_string(event_handle))); #endif content.concat("
"); content.concat("
" + String(get_event_enum_string(event_handle)) + "
"); diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index b2233ae8..61c28f30 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -1,9 +1,11 @@ #include "webserver.h" #include #include +#include "../../../USER_SECRETS.h" #include "../../datalayer/datalayer.h" #include "../../datalayer/datalayer_extended.h" #include "../../lib/bblanchon-ArduinoJson/ArduinoJson.h" +#include "../sdcard/sdcard.h" #include "../utils/events.h" #include "../utils/led_handler.h" #include "../utils/timer.h" @@ -17,6 +19,7 @@ unsigned long ota_progress_millis = 0; #include "advanced_battery_html.h" #include "can_logging_html.h" #include "cellmonitor_html.h" +#include "debug_logging_html.h" #include "events_html.h" #include "index_html.cpp" #include "settings_html.h" @@ -63,14 +66,22 @@ void init_webserver() { request->send_P(200, "text/html", index_html, can_logger_processor); }); - // Define the handler to stop logging - server.on("/stop_logging", HTTP_GET, [](AsyncWebServerRequest* request) { +#ifdef DEBUG_VIA_WEB + // Route for going to debug logging web page + server.on("/log", HTTP_GET, [](AsyncWebServerRequest* request) { + request->send_P(200, "text/html", index_html, debug_logger_processor); + }); +#endif // DEBUG_VIA_WEB + + // Define the handler to stop can logging + server.on("/stop_can_logging", HTTP_GET, [](AsyncWebServerRequest* request) { datalayer.system.info.can_logging_active = false; request->send_P(200, "text/plain", "Logging stopped"); }); - // Define the handler to export logs - server.on("/export_logs", HTTP_GET, [](AsyncWebServerRequest* request) { +#ifndef LOG_CAN_TO_SD + // Define the handler to export can log + server.on("/export_can_log", HTTP_GET, [](AsyncWebServerRequest* request) { String logs = String(datalayer.system.info.logged_can_messages); if (logs.length() == 0) { logs = "No logs available."; @@ -95,6 +106,49 @@ void init_webserver() { response->addHeader("Content-Disposition", String("attachment; filename=\"") + String(filename) + "\""); request->send(response); }); +#endif + +#ifdef LOG_CAN_TO_SD + // Define the handler to export can log + server.on("/export_can_log", HTTP_GET, [](AsyncWebServerRequest* request) { + pause_can_writing(); + request->send(SD, CAN_LOG_FILE, String(), true); + resume_can_writing(); + }); + + // Define the handler to delete can log + server.on("/delete_can_log", HTTP_GET, [](AsyncWebServerRequest* request) { + delete_can_log(); + request->send_P(200, "text/plain", "Log file deleted"); + }); +#endif + + // Define the handler to export debug log + server.on("/export_log", HTTP_GET, [](AsyncWebServerRequest* request) { + String logs = String(datalayer.system.info.logged_can_messages); + if (logs.length() == 0) { + logs = "No logs available."; + } + + // Get the current time + time_t now = time(nullptr); + struct tm timeinfo; + localtime_r(&now, &timeinfo); + + // Ensure time retrieval was successful + char filename[32]; + if (strftime(filename, sizeof(filename), "log_%H-%M-%S.txt", &timeinfo)) { + // Valid filename created + } else { + // Fallback filename if automatic timestamping failed + strcpy(filename, "battery_emulator_log.txt"); + } + + // Use request->send with dynamic headers + AsyncWebServerResponse* response = request->beginResponse(200, "text/plain", logs); + response->addHeader("Content-Disposition", String("attachment; filename=\"") + String(filename) + "\""); + request->send(response); + }); // Route for going to cellmonitor web page server.on("/cellmonitor", HTTP_GET, [](AsyncWebServerRequest* request) { @@ -509,7 +563,10 @@ String get_firmware_info_processor(const String& var) { #endif // HW_STARK #ifdef HW_3LB doc["hardware"] = "3LB board"; -#endif // HW_STARK +#endif // HW_3LB +#ifdef HW_DEVKIT + doc["hardware"] = "ESP32 DevKit V1"; +#endif // HW_DEVKIT doc["firmware"] = String(version_number); serializeJson(doc, content); @@ -535,14 +592,15 @@ String processor(const String& var) { content += "
"; // Show version number - content += "

Software: " + String(version_number) + "

"; + content += "

Software: " + String(version_number); // Show hardware used: #ifdef HW_LILYGO - content += "

Hardware: LilyGo T-CAN485

"; + content += " Hardware: LilyGo T-CAN485"; #endif // HW_LILYGO #ifdef HW_STARK - content += "

Hardware: Stark CMR Module

"; + content += " Hardware: Stark CMR Module"; #endif // HW_STARK + content += "

"; content += "

Uptime: " + uptime_formatter::getUptime() + "

"; #ifdef FUNCTION_TIME_MEASUREMENT // Load information @@ -566,11 +624,14 @@ String processor(const String& var) { wl_status_t status = WiFi.status(); // Display ssid of network connected to and, if connected to the WiFi, its own IP - content += "

SSID: " + String(ssid.c_str()) + "

"; + content += "

SSID: " + String(ssid.c_str()); + if (status == WL_CONNECTED) { + // Get and display the signal strength (RSSI) and channel + content += " RSSI:" + String(WiFi.RSSI()) + " dBm Ch: " + String(WiFi.channel()); + } + content += "

"; if (status == WL_CONNECTED) { content += "

IP: " + WiFi.localIP().toString() + "

"; - // Get and display the signal strength (RSSI) and channel - content += "

Signal strength: " + String(WiFi.RSSI()) + " dBm, at channel " + String(WiFi.channel()) + "

"; } else { content += "

Wifi state: " + getConnectResultString(status) + "

"; } @@ -698,13 +759,30 @@ String processor(const String& var) { } content += "

Temperature max: " + String(tempMaxFloat, 1) + " C

"; content += "

Temperature min: " + String(tempMinFloat, 1) + " C

"; - if (datalayer.battery.status.bms_status == ACTIVE) { - content += "

System status: OK

"; - } else if (datalayer.battery.status.bms_status == UPDATING) { - content += "

System status: UPDATING

"; - } else { - content += "

System status: FAULT

"; + + content += "

System status: "; + switch (datalayer.battery.status.bms_status) { + case ACTIVE: + content += String("OK"); + break; + case UPDATING: + content += String("UPDATING"); + break; + case FAULT: + content += String("FAULT"); + break; + case INACTIVE: + content += String("INACTIVE"); + break; + case STANDBY: + content += String("STANDBY"); + break; + default: + content += String("??"); + break; } + content += "

"; + if (datalayer.battery.status.current_dA == 0) { content += "

Battery idle

"; } else if (datalayer.battery.status.current_dA < 0) { @@ -983,6 +1061,9 @@ String processor(const String& var) { content += " "; content += " "; content += " "; +#ifdef DEBUG_VIA_WEB + content += " "; +#endif // DEBUG_VIA_WEB content += " "; content += " "; content += ""; @@ -1008,6 +1089,7 @@ String processor(const String& var) { content += "function Settings() { window.location.href = '/settings'; }"; content += "function Advanced() { window.location.href = '/advanced'; }"; content += "function CANlog() { window.location.href = '/canlog'; }"; + content += "function Log() { window.location.href = '/log'; }"; content += "function Events() { window.location.href = '/events'; }"; content += "function askReboot() { if (window.confirm('Are you sure you want to reboot the emulator? NOTE: If " @@ -1068,9 +1150,9 @@ void onOTAProgress(size_t current, size_t final) { // Log every 1 second if (millis() - ota_progress_millis > 1000) { ota_progress_millis = millis(); -#ifdef DEBUG_VIA_USB - Serial.printf("OTA Progress Current: %u bytes, Final: %u bytes\n", current, final); -#endif // DEBUG_VIA_USB +#ifdef DEBUG_LOG + logging.printf("OTA Progress Current: %u bytes, Final: %u bytes\n", current, final); +#endif // DEBUG_LOG // Reset the "watchdog" ota_timeout_timer.reset(); } @@ -1087,13 +1169,13 @@ void onOTAEnd(bool success) { // Max Charge/Discharge = 0; CAN = stop; contactors = open setBatteryPause(true, true, true, false); // a reboot will be done by the OTA library. no need to do anything here -#ifdef DEBUG_VIA_USB - Serial.println("OTA update finished successfully!"); -#endif // DEBUG_VIA_USB +#ifdef DEBUG_LOG + logging.println("OTA update finished successfully!"); +#endif // DEBUG_LOG } else { -#ifdef DEBUG_VIA_USB - Serial.println("There was an error during OTA update!"); -#endif // DEBUG_VIA_USB +#ifdef DEBUG_LOG + logging.println("There was an error during OTA update!"); +#endif // DEBUG_LOG //try to Resume the battery pause and CAN communication setBatteryPause(false, false); } diff --git a/Software/src/devboard/webserver/webserver.h b/Software/src/devboard/webserver/webserver.h index 86b5a763..a75ef8fb 100644 --- a/Software/src/devboard/webserver/webserver.h +++ b/Software/src/devboard/webserver/webserver.h @@ -6,7 +6,7 @@ #include "../../include.h" #include "../../lib/YiannisBourkelis-Uptime-Library/src/uptime_formatter.h" #include "../../lib/ayushsharma82-ElegantOTA/src/ElegantOTA.h" -#include "../../lib/mathieucarbou-AsyncTCP/src/AsyncTCP.h" +#include "../../lib/me-no-dev-AsyncTCP/src/AsyncTCP.h" #include "../../lib/me-no-dev-ESPAsyncWebServer/src/ESPAsyncWebServer.h" #include "../../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" diff --git a/Software/src/devboard/wifi/wifi.cpp b/Software/src/devboard/wifi/wifi.cpp index 91862e2a..7ebcc9c3 100644 --- a/Software/src/devboard/wifi/wifi.cpp +++ b/Software/src/devboard/wifi/wifi.cpp @@ -29,12 +29,8 @@ static bool connected_once = false; void init_WiFi() { #ifdef WIFIAP - if (AccessPointEnabled) { - WiFi.mode(WIFI_AP_STA); // Simultaneous WiFi AP and Router connection - init_WiFi_AP(); - } else { - WiFi.mode(WIFI_STA); // Only Router connection - } + WiFi.mode(WIFI_AP_STA); // Simultaneous WiFi AP and Router connection + init_WiFi_AP(); #else WiFi.mode(WIFI_STA); // Only Router connection #endif // WIFIAP @@ -72,28 +68,28 @@ void wifi_monitor() { // Increase the current check interval if it's not at the maximum if (current_check_interval + STEP_WIFI_CHECK_INTERVAL <= MAX_STEP_WIFI_CHECK_INTERVAL) current_check_interval += STEP_WIFI_CHECK_INTERVAL; -#ifdef DEBUG_VIA_USB - Serial.println("Wi-Fi not connected, attempting to reconnect..."); +#ifdef DEBUG_LOG + logging.println("Wi-Fi not connected, attempting to reconnect..."); #endif // Try WiFi.reconnect() if it was successfully connected at least once if (hasConnectedBefore) { lastReconnectAttempt = millis(); // Reset reconnection attempt timer -#ifdef DEBUG_VIA_USB - Serial.println("Wi-Fi reconnect attempt..."); +#ifdef DEBUG_LOG + logging.println("Wi-Fi reconnect attempt..."); #endif if (WiFi.reconnect()) { -#ifdef DEBUG_VIA_USB - Serial.println("Wi-Fi reconnect attempt sucess..."); +#ifdef DEBUG_LOG + logging.println("Wi-Fi reconnect attempt sucess..."); #endif reconnectAttempts = 0; // Reset the attempt counter on successful reconnect } else { -#ifdef DEBUG_VIA_USB - Serial.println("Wi-Fi reconnect attempt error..."); +#ifdef DEBUG_LOG + logging.println("Wi-Fi reconnect attempt error..."); #endif reconnectAttempts++; if (reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) { -#ifdef DEBUG_VIA_USB - Serial.println("Failed to reconnect multiple times, forcing a full connection attempt..."); +#ifdef DEBUG_LOG + logging.println("Failed to reconnect multiple times, forcing a full connection attempt..."); #endif FullReconnectToWiFi(); } @@ -101,8 +97,8 @@ void wifi_monitor() { } else { // If no previous connection, force a full connection attempt if (currentMillis - lastReconnectAttempt > current_full_reconnect_interval) { -#ifdef DEBUG_VIA_USB - Serial.println("No previous OK connection, force a full connection attempt..."); +#ifdef DEBUG_LOG + logging.println("No previous OK connection, force a full connection attempt..."); #endif FullReconnectToWiFi(); } @@ -127,13 +123,13 @@ static void FullReconnectToWiFi() { static void connectToWiFi() { if (WiFi.status() != WL_CONNECTED) { lastReconnectAttempt = millis(); // Reset the reconnect attempt timer -#ifdef DEBUG_VIA_USB - Serial.println("Connecting to Wi-Fi..."); +#ifdef DEBUG_LOG + logging.println("Connecting to Wi-Fi..."); #endif WiFi.begin(ssid.c_str(), password.c_str(), wifi_channel); } else { -#ifdef DEBUG_VIA_USB - Serial.println("Wi-Fi already connected."); +#ifdef DEBUG_LOG + logging.println("Wi-Fi already connected."); #endif } } @@ -143,10 +139,11 @@ static void onWifiConnect(WiFiEvent_t event, WiFiEventInfo_t info) { clear_event(EVENT_WIFI_DISCONNECT); set_event(EVENT_WIFI_CONNECT, 0); connected_once = true; -#ifdef DEBUG_VIA_USB - Serial.println("Wi-Fi connected."); - Serial.print("IP address: "); - Serial.println(WiFi.localIP()); +#ifdef DEBUG_LOG + logging.print("Wi-Fi connected. RSSI: "); + logging.print(-WiFi.RSSI()); + logging.print(" dBm, IP address: "); + logging.println(WiFi.localIP().toString()); #endif hasConnectedBefore = true; // Mark as successfully connected at least once reconnectAttempts = 0; // Reset the attempt counter @@ -159,10 +156,10 @@ static void onWifiConnect(WiFiEvent_t event, WiFiEventInfo_t info) { static void onWifiGotIP(WiFiEvent_t event, WiFiEventInfo_t info) { //clear disconnects events if we got a IP clear_event(EVENT_WIFI_DISCONNECT); -#ifdef DEBUG_VIA_USB - Serial.println("Wi-Fi Got IP."); - Serial.print("IP address: "); - Serial.println(WiFi.localIP()); +#ifdef DEBUG_LOG + logging.print("Wi-Fi Got IP. "); + logging.print("IP address: "); + logging.println(WiFi.localIP().toString()); #endif } @@ -170,8 +167,8 @@ static void onWifiGotIP(WiFiEvent_t event, WiFiEventInfo_t info) { static void onWifiDisconnect(WiFiEvent_t event, WiFiEventInfo_t info) { if (connected_once) set_event(EVENT_WIFI_DISCONNECT, 0); -#ifdef DEBUG_VIA_USB - Serial.println("Wi-Fi disconnected."); +#ifdef DEBUG_LOG + logging.println("Wi-Fi disconnected."); #endif //we dont do anything here, the reconnect will be handled by the monitor //too many events received when the connection is lost @@ -188,8 +185,8 @@ void init_mDNS() { // Initialize mDNS .local resolution if (!MDNS.begin(mdnsHost)) { -#ifdef DEBUG_VIA_USB - Serial.println("Error setting up MDNS responder!"); +#ifdef DEBUG_LOG + logging.println("Error setting up MDNS responder!"); #endif } else { // Advertise via bonjour the service so we can auto discover these battery emulators on the local network. @@ -200,16 +197,16 @@ void init_mDNS() { #ifdef WIFIAP void init_WiFi_AP() { -#ifdef DEBUG_VIA_USB - Serial.println("Creating Access Point: " + String(ssidAP)); - Serial.println("With password: " + String(passwordAP)); +#ifdef DEBUG_LOG + logging.println("Creating Access Point: " + String(ssidAP)); + logging.println("With password: " + String(passwordAP)); #endif WiFi.softAP(ssidAP, passwordAP); IPAddress IP = WiFi.softAPIP(); -#ifdef DEBUG_VIA_USB - Serial.println("Access Point created."); - Serial.print("IP address: "); - Serial.println(IP); +#ifdef DEBUG_LOG + logging.println("Access Point created."); + logging.print("IP address: "); + logging.println(IP); #endif } #endif // WIFIAP diff --git a/Software/src/include.h b/Software/src/include.h index 5d5520d8..1d88550a 100644 --- a/Software/src/include.h +++ b/Software/src/include.h @@ -9,6 +9,7 @@ #include "devboard/hal/hal.h" #include "devboard/safety/safety.h" +#include "devboard/utils/logging.h" #include "devboard/utils/time_meas.h" #include "devboard/utils/types.h" @@ -19,12 +20,7 @@ /* - ERROR CHECKS BELOW, DON'T TOUCH - */ #if !defined(HW_CONFIGURED) -#error You must select a HW to run on! -#endif - -#if defined(CAN_ADDON) && defined(CANFD_ADDON) -// Check that user did not try to use dual can and fd-can on same hardware pins -#error CAN_ADDON AND CANFD_ADDON CANNOT BE USED SIMULTANEOUSLY +#error You must select a target hardware in the USER_SERTTINGS.h file! #endif #ifdef USE_CANFD_INTERFACE_AS_CLASSIC_CAN @@ -52,4 +48,10 @@ #error No battery selected! Choose one from the USER_SETTINGS.h file #endif +#ifdef LOG_CAN_TO_SD +#if !defined(HW_LILYGO) +#error The SD card logging feature is only available on LilyGo hardware +#endif +#endif + #endif diff --git a/Software/src/inverter/AFORE-CAN.cpp b/Software/src/inverter/AFORE-CAN.cpp index a8d551d7..d9037d2c 100644 --- a/Software/src/inverter/AFORE-CAN.cpp +++ b/Software/src/inverter/AFORE-CAN.cpp @@ -200,7 +200,7 @@ void update_values_can_inverter() { //This function maps all the values fetched */ } -void receive_can_inverter(CAN_frame rx_frame) { +void map_can_frame_to_variable_inverter(CAN_frame rx_frame) { switch (rx_frame.ID) { case 0x305: // Every 1s from inverter datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; @@ -217,19 +217,19 @@ void receive_can_inverter(CAN_frame rx_frame) { } } -void send_can_inverter() { +void transmit_can_inverter() { if (time_to_send_info) { // Set every 1s if we get message from inverter - transmit_can(&AFORE_350, can_config.inverter); - transmit_can(&AFORE_351, can_config.inverter); - transmit_can(&AFORE_352, can_config.inverter); - transmit_can(&AFORE_353, can_config.inverter); - transmit_can(&AFORE_354, can_config.inverter); - transmit_can(&AFORE_355, can_config.inverter); - transmit_can(&AFORE_356, can_config.inverter); - transmit_can(&AFORE_357, can_config.inverter); - transmit_can(&AFORE_358, can_config.inverter); - transmit_can(&AFORE_359, can_config.inverter); - transmit_can(&AFORE_35A, can_config.inverter); + transmit_can_frame(&AFORE_350, can_config.inverter); + transmit_can_frame(&AFORE_351, can_config.inverter); + transmit_can_frame(&AFORE_352, can_config.inverter); + transmit_can_frame(&AFORE_353, can_config.inverter); + transmit_can_frame(&AFORE_354, can_config.inverter); + transmit_can_frame(&AFORE_355, can_config.inverter); + transmit_can_frame(&AFORE_356, can_config.inverter); + transmit_can_frame(&AFORE_357, can_config.inverter); + transmit_can_frame(&AFORE_358, can_config.inverter); + transmit_can_frame(&AFORE_359, can_config.inverter); + transmit_can_frame(&AFORE_35A, can_config.inverter); time_to_send_info = false; } } diff --git a/Software/src/inverter/AFORE-CAN.h b/Software/src/inverter/AFORE-CAN.h index 9829befc..87550279 100644 --- a/Software/src/inverter/AFORE-CAN.h +++ b/Software/src/inverter/AFORE-CAN.h @@ -4,7 +4,7 @@ #define CAN_INVERTER_SELECTED -void transmit_can(CAN_frame* tx_frame, int interface); +void transmit_can_frame(CAN_frame* tx_frame, int interface); void setup_inverter(void); #endif diff --git a/Software/src/inverter/BYD-CAN.cpp b/Software/src/inverter/BYD-CAN.cpp index d7a4028f..477fbf2a 100644 --- a/Software/src/inverter/BYD-CAN.cpp +++ b/Software/src/inverter/BYD-CAN.cpp @@ -153,18 +153,18 @@ void update_values_can_inverter() { //This function maps all the values fetched BYD_210.data.u8[2] = (datalayer.battery.status.temperature_min_dC >> 8); BYD_210.data.u8[3] = (datalayer.battery.status.temperature_min_dC & 0x00FF); -#ifdef DEBUG_VIA_USB +#ifdef DEBUG_LOG if (inverter_name[0] != 0) { - Serial.print("Detected inverter: "); + logging.print("Detected inverter: "); for (uint8_t i = 0; i < 7; i++) { - Serial.print((char)inverter_name[i]); + logging.print((char)inverter_name[i]); } - Serial.println(); + logging.println(); } #endif } -void receive_can_inverter(CAN_frame rx_frame) { +void map_can_frame_to_variable_inverter(CAN_frame rx_frame) { switch (rx_frame.ID) { case 0x151: //Message originating from BYD HVS compatible inverter. Reply with CAN identifier! datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; @@ -196,7 +196,7 @@ void receive_can_inverter(CAN_frame rx_frame) { } } -void send_can_inverter() { +void transmit_can_inverter() { unsigned long currentMillis = millis(); // Send initial CAN data once on bootup if (!initialDataSent) { @@ -208,32 +208,32 @@ void send_can_inverter() { if (currentMillis - previousMillis2s >= INTERVAL_2_S) { previousMillis2s = currentMillis; - transmit_can(&BYD_110, can_config.inverter); + transmit_can_frame(&BYD_110, can_config.inverter); } // Send 10s CAN Message if (currentMillis - previousMillis10s >= INTERVAL_10_S) { previousMillis10s = currentMillis; - transmit_can(&BYD_150, can_config.inverter); - transmit_can(&BYD_1D0, can_config.inverter); - transmit_can(&BYD_210, can_config.inverter); + transmit_can_frame(&BYD_150, can_config.inverter); + transmit_can_frame(&BYD_1D0, can_config.inverter); + transmit_can_frame(&BYD_210, can_config.inverter); } //Send 60s message if (currentMillis - previousMillis60s >= INTERVAL_60_S) { previousMillis60s = currentMillis; - transmit_can(&BYD_190, can_config.inverter); + transmit_can_frame(&BYD_190, can_config.inverter); } } void send_intial_data() { - transmit_can(&BYD_250, can_config.inverter); - transmit_can(&BYD_290, can_config.inverter); - transmit_can(&BYD_2D0, can_config.inverter); - transmit_can(&BYD_3D0_0, can_config.inverter); - transmit_can(&BYD_3D0_1, can_config.inverter); - transmit_can(&BYD_3D0_2, can_config.inverter); - transmit_can(&BYD_3D0_3, can_config.inverter); + transmit_can_frame(&BYD_250, can_config.inverter); + transmit_can_frame(&BYD_290, can_config.inverter); + transmit_can_frame(&BYD_2D0, can_config.inverter); + transmit_can_frame(&BYD_3D0_0, can_config.inverter); + transmit_can_frame(&BYD_3D0_1, can_config.inverter); + transmit_can_frame(&BYD_3D0_2, can_config.inverter); + transmit_can_frame(&BYD_3D0_3, can_config.inverter); } void setup_inverter(void) { // Performs one time setup at startup over CAN bus strncpy(datalayer.system.info.inverter_protocol, "BYD Battery-Box Premium HVS over CAN Bus", 63); diff --git a/Software/src/inverter/BYD-CAN.h b/Software/src/inverter/BYD-CAN.h index 5a90d6ba..91d82d39 100644 --- a/Software/src/inverter/BYD-CAN.h +++ b/Software/src/inverter/BYD-CAN.h @@ -7,7 +7,7 @@ #define FW_MINOR_VERSION 0x29 void send_intial_data(); -void transmit_can(CAN_frame* tx_frame, int interface); +void transmit_can_frame(CAN_frame* tx_frame, int interface); void setup_inverter(void); #endif diff --git a/Software/src/inverter/FOXESS-CAN.cpp b/Software/src/inverter/FOXESS-CAN.cpp index e23f9006..da6d5d45 100644 --- a/Software/src/inverter/FOXESS-CAN.cpp +++ b/Software/src/inverter/FOXESS-CAN.cpp @@ -583,7 +583,7 @@ void update_values_can_inverter() { //This function maps all the CAN values fet // So do we really need to map the same two values over and over to 32 places? } -void send_can_inverter() { // This function loops as fast as possible +void transmit_can_inverter() { // This function loops as fast as possible if (send_cellvoltages) { unsigned long currentMillis = millis(); // Get the current time @@ -595,68 +595,68 @@ void send_can_inverter() { // This function loops as fast as possible // Send a subset of messages per iteration to avoid overloading the CAN bus / transmit buffer switch (can_message_cellvolt_index) { case 0: -#ifdef DEBUG_VIA_USB - Serial.println("Sending large batch"); +#ifdef DEBUG_LOG + logging.println("Sending large batch"); #endif - transmit_can(&FOXESS_0C1D, can_config.inverter); - transmit_can(&FOXESS_0C21, can_config.inverter); - transmit_can(&FOXESS_0C29, can_config.inverter); - transmit_can(&FOXESS_0C2D, can_config.inverter); - transmit_can(&FOXESS_0C31, can_config.inverter); + transmit_can_frame(&FOXESS_0C1D, can_config.inverter); + transmit_can_frame(&FOXESS_0C21, can_config.inverter); + transmit_can_frame(&FOXESS_0C29, can_config.inverter); + transmit_can_frame(&FOXESS_0C2D, can_config.inverter); + transmit_can_frame(&FOXESS_0C31, can_config.inverter); break; case 1: - transmit_can(&FOXESS_0C35, can_config.inverter); - transmit_can(&FOXESS_0C39, can_config.inverter); - transmit_can(&FOXESS_0C3D, can_config.inverter); - transmit_can(&FOXESS_0C41, can_config.inverter); - transmit_can(&FOXESS_0C45, can_config.inverter); + transmit_can_frame(&FOXESS_0C35, can_config.inverter); + transmit_can_frame(&FOXESS_0C39, can_config.inverter); + transmit_can_frame(&FOXESS_0C3D, can_config.inverter); + transmit_can_frame(&FOXESS_0C41, can_config.inverter); + transmit_can_frame(&FOXESS_0C45, can_config.inverter); break; case 2: - transmit_can(&FOXESS_0C49, can_config.inverter); - transmit_can(&FOXESS_0C4D, can_config.inverter); - transmit_can(&FOXESS_0C51, can_config.inverter); - transmit_can(&FOXESS_0C55, can_config.inverter); - transmit_can(&FOXESS_0C59, can_config.inverter); + transmit_can_frame(&FOXESS_0C49, can_config.inverter); + transmit_can_frame(&FOXESS_0C4D, can_config.inverter); + transmit_can_frame(&FOXESS_0C51, can_config.inverter); + transmit_can_frame(&FOXESS_0C55, can_config.inverter); + transmit_can_frame(&FOXESS_0C59, can_config.inverter); break; case 3: - transmit_can(&FOXESS_0C5D, can_config.inverter); - transmit_can(&FOXESS_0C61, can_config.inverter); - transmit_can(&FOXESS_0C65, can_config.inverter); - transmit_can(&FOXESS_0C69, can_config.inverter); - transmit_can(&FOXESS_0C6D, can_config.inverter); + transmit_can_frame(&FOXESS_0C5D, can_config.inverter); + transmit_can_frame(&FOXESS_0C61, can_config.inverter); + transmit_can_frame(&FOXESS_0C65, can_config.inverter); + transmit_can_frame(&FOXESS_0C69, can_config.inverter); + transmit_can_frame(&FOXESS_0C6D, can_config.inverter); break; case 4: - transmit_can(&FOXESS_0C71, can_config.inverter); - transmit_can(&FOXESS_0C75, can_config.inverter); - transmit_can(&FOXESS_0C79, can_config.inverter); - transmit_can(&FOXESS_0C7D, can_config.inverter); - transmit_can(&FOXESS_0C81, can_config.inverter); + transmit_can_frame(&FOXESS_0C71, can_config.inverter); + transmit_can_frame(&FOXESS_0C75, can_config.inverter); + transmit_can_frame(&FOXESS_0C79, can_config.inverter); + transmit_can_frame(&FOXESS_0C7D, can_config.inverter); + transmit_can_frame(&FOXESS_0C81, can_config.inverter); break; case 5: - transmit_can(&FOXESS_0C85, can_config.inverter); - transmit_can(&FOXESS_0C89, can_config.inverter); - transmit_can(&FOXESS_0C8D, can_config.inverter); - transmit_can(&FOXESS_0C91, can_config.inverter); - transmit_can(&FOXESS_0C95, can_config.inverter); + transmit_can_frame(&FOXESS_0C85, can_config.inverter); + transmit_can_frame(&FOXESS_0C89, can_config.inverter); + transmit_can_frame(&FOXESS_0C8D, can_config.inverter); + transmit_can_frame(&FOXESS_0C91, can_config.inverter); + transmit_can_frame(&FOXESS_0C95, can_config.inverter); break; case 6: - transmit_can(&FOXESS_0C99, can_config.inverter); - transmit_can(&FOXESS_0C9D, can_config.inverter); - transmit_can(&FOXESS_0CA1, can_config.inverter); - transmit_can(&FOXESS_0CA5, can_config.inverter); - transmit_can(&FOXESS_0CA9, can_config.inverter); + transmit_can_frame(&FOXESS_0C99, can_config.inverter); + transmit_can_frame(&FOXESS_0C9D, can_config.inverter); + transmit_can_frame(&FOXESS_0CA1, can_config.inverter); + transmit_can_frame(&FOXESS_0CA5, can_config.inverter); + transmit_can_frame(&FOXESS_0CA9, can_config.inverter); break; case 7: //Celltemperatures - transmit_can(&FOXESS_0D21, can_config.inverter); - transmit_can(&FOXESS_0D29, can_config.inverter); - transmit_can(&FOXESS_0D31, can_config.inverter); - transmit_can(&FOXESS_0D39, can_config.inverter); - transmit_can(&FOXESS_0D41, can_config.inverter); - transmit_can(&FOXESS_0D49, can_config.inverter); - transmit_can(&FOXESS_0D51, can_config.inverter); - transmit_can(&FOXESS_0D59, can_config.inverter); -#ifdef DEBUG_VIA_USB - Serial.println("Sending completed"); + transmit_can_frame(&FOXESS_0D21, can_config.inverter); + transmit_can_frame(&FOXESS_0D29, can_config.inverter); + transmit_can_frame(&FOXESS_0D31, can_config.inverter); + transmit_can_frame(&FOXESS_0D39, can_config.inverter); + transmit_can_frame(&FOXESS_0D41, can_config.inverter); + transmit_can_frame(&FOXESS_0D49, can_config.inverter); + transmit_can_frame(&FOXESS_0D51, can_config.inverter); + transmit_can_frame(&FOXESS_0D59, can_config.inverter); +#ifdef DEBUG_LOG + logging.println("Sending completed"); #endif send_cellvoltages = false; break; @@ -672,67 +672,68 @@ void send_can_inverter() { // This function loops as fast as possible } } -void receive_can_inverter(CAN_frame rx_frame) { +void map_can_frame_to_variable_inverter(CAN_frame rx_frame) { if (rx_frame.ID == 0x1871) { datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; if (rx_frame.data.u8[0] == 0x03) { //0x1871 [0x03, 0x06, 0x17, 0x05, 0x09, 0x09, 0x28, 0x22] //This message is sent by the inverter every '6' seconds (0.5s after the pack serial numbers) //and contains a timestamp in bytes 2-7 i.e. ,,
,,, -#ifdef DEBUG_VIA_USB - Serial.println("Inverter sends current time and date"); +#ifdef DEBUG_LOG + logging.println("Inverter sends current time and date"); #endif } else if (rx_frame.data.u8[0] == 0x01) { if (rx_frame.data.u8[4] == 0x00) { // Inverter wants to know bms info (every 1s) -#ifdef DEBUG_VIA_USB - Serial.println("Inverter requests 1s BMS info, we reply"); +#ifdef DEBUG_LOG + logging.println("Inverter requests 1s BMS info, we reply"); #endif - transmit_can(&FOXESS_1872, can_config.inverter); - transmit_can(&FOXESS_1873, can_config.inverter); - transmit_can(&FOXESS_1874, can_config.inverter); - transmit_can(&FOXESS_1875, can_config.inverter); - transmit_can(&FOXESS_1876, can_config.inverter); - transmit_can(&FOXESS_1877, can_config.inverter); - transmit_can(&FOXESS_1878, can_config.inverter); - transmit_can(&FOXESS_1879, can_config.inverter); + transmit_can_frame(&FOXESS_1872, can_config.inverter); + transmit_can_frame(&FOXESS_1873, can_config.inverter); + transmit_can_frame(&FOXESS_1874, can_config.inverter); + transmit_can_frame(&FOXESS_1875, can_config.inverter); + transmit_can_frame(&FOXESS_1876, can_config.inverter); + transmit_can_frame(&FOXESS_1877, can_config.inverter); + transmit_can_frame(&FOXESS_1878, can_config.inverter); + transmit_can_frame(&FOXESS_1879, can_config.inverter); } else if (rx_frame.data.u8[4] == 0x01) { // b4 0x01 , 0x1871 [0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00] //Inverter wants to know all individual cellvoltages (occurs 6 seconds after valid BMS reply) -#ifdef DEBUG_VIA_USB - Serial.println("Inverter requests individual battery pack status, we reply"); +#ifdef DEBUG_LOG + logging.println("Inverter requests individual battery pack status, we reply"); #endif - transmit_can(&FOXESS_0C05, can_config.inverter); //TODO, should we limit this incase NUMBER_OF_PACKS =! 8? - transmit_can(&FOXESS_0C06, can_config.inverter); - transmit_can(&FOXESS_0C07, can_config.inverter); - transmit_can(&FOXESS_0C08, can_config.inverter); - transmit_can(&FOXESS_0C09, can_config.inverter); - transmit_can(&FOXESS_0C0A, can_config.inverter); - transmit_can(&FOXESS_0C0B, can_config.inverter); - transmit_can(&FOXESS_0C0C, can_config.inverter); + transmit_can_frame(&FOXESS_0C05, + can_config.inverter); //TODO, should we limit this incase NUMBER_OF_PACKS =! 8? + transmit_can_frame(&FOXESS_0C06, can_config.inverter); + transmit_can_frame(&FOXESS_0C07, can_config.inverter); + transmit_can_frame(&FOXESS_0C08, can_config.inverter); + transmit_can_frame(&FOXESS_0C09, can_config.inverter); + transmit_can_frame(&FOXESS_0C0A, can_config.inverter); + transmit_can_frame(&FOXESS_0C0B, can_config.inverter); + transmit_can_frame(&FOXESS_0C0C, can_config.inverter); } else if (rx_frame.data.u8[4] == 0x04) { // b4 0x01 , 0x1871 [0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00] //Inverter wants to know all individual cellvoltages (occurs 6 seconds after valid BMS reply) -#ifdef DEBUG_VIA_USB - Serial.println("Inverter requests cellvoltages and temps, we reply"); +#ifdef DEBUG_LOG + logging.println("Inverter requests cellvoltages and temps, we reply"); #endif send_cellvoltages = true; } } else if (rx_frame.data.u8[0] == 0x02) { //0x1871 [0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00] // Ack message -#ifdef DEBUG_VIA_USB - Serial.println("Inverter acks, no reply needed"); +#ifdef DEBUG_LOG + logging.println("Inverter acks, no reply needed"); #endif } else if (rx_frame.data.u8[0] == 0x05) { //0x1871 [0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00] -#ifdef DEBUG_VIA_USB - Serial.println("Inverter wants to know serial numbers, we reply"); +#ifdef DEBUG_LOG + logging.println("Inverter wants to know serial numbers, we reply"); #endif for (uint8_t i = 0; i < (NUMBER_OF_PACKS + 1); i++) { FOXESS_1881.data.u8[0] = (uint8_t)i; FOXESS_1882.data.u8[0] = (uint8_t)i; FOXESS_1883.data.u8[0] = (uint8_t)i; //TODO, should we add something to serial number field? - transmit_can(&FOXESS_1881, can_config.inverter); - transmit_can(&FOXESS_1882, can_config.inverter); - transmit_can(&FOXESS_1883, can_config.inverter); + transmit_can_frame(&FOXESS_1881, can_config.inverter); + transmit_can_frame(&FOXESS_1882, can_config.inverter); + transmit_can_frame(&FOXESS_1883, can_config.inverter); } } } diff --git a/Software/src/inverter/FOXESS-CAN.h b/Software/src/inverter/FOXESS-CAN.h index 365a559d..456d5c83 100644 --- a/Software/src/inverter/FOXESS-CAN.h +++ b/Software/src/inverter/FOXESS-CAN.h @@ -4,7 +4,7 @@ #define CAN_INVERTER_SELECTED -void transmit_can(CAN_frame* tx_frame, int interface); +void transmit_can_frame(CAN_frame* tx_frame, int interface); void setup_inverter(void); #endif diff --git a/Software/src/inverter/INVERTERS.h b/Software/src/inverter/INVERTERS.h index a5c4252d..8d379d7d 100644 --- a/Software/src/inverter/INVERTERS.h +++ b/Software/src/inverter/INVERTERS.h @@ -15,10 +15,6 @@ #include "BYD-MODBUS.h" #endif -#ifdef BYD_SMA -#include "BYD-SMA.h" -#endif - #ifdef BYD_KOSTAL_RS485 #include "KOSTAL-RS485.h" #endif @@ -39,8 +35,12 @@ #include "SCHNEIDER-CAN.h" #endif -#ifdef SMA_CAN -#include "SMA-CAN.h" +#ifdef SMA_BYD_H_CAN +#include "SMA-BYD-H-CAN.h" +#endif + +#ifdef SMA_BYD_HVS_CAN +#include "SMA-BYD-HVS-CAN.h" #endif #ifdef SMA_LV_CAN @@ -65,8 +65,8 @@ #ifdef CAN_INVERTER_SELECTED void update_values_can_inverter(); -void receive_can_inverter(CAN_frame rx_frame); -void send_can_inverter(); +void map_can_frame_to_variable_inverter(CAN_frame rx_frame); +void transmit_can_inverter(); #endif #ifdef MODBUS_INVERTER_SELECTED diff --git a/Software/src/inverter/KOSTAL-RS485.cpp b/Software/src/inverter/KOSTAL-RS485.cpp index 7df23ff1..fc45c1b9 100644 --- a/Software/src/inverter/KOSTAL-RS485.cpp +++ b/Software/src/inverter/KOSTAL-RS485.cpp @@ -119,15 +119,15 @@ void float2frameMSB(byte* arr, float value, byte framepointer) { void send_kostal(byte* arr, int alen) { #ifdef DEBUG_KOSTAL_RS485_DATA - Serial.print("TX: "); + logging.print("TX: "); for (int i = 0; i < alen; i++) { if (arr[i] < 0x10) { - Serial.print("0"); + logging.print("0"); } - Serial.print(arr[i], HEX); - Serial.print(" "); + logging.print(arr[i], HEX); + logging.print(" "); } - Serial.println("\n"); + logging.println("\n"); #endif Serial2.write(arr, alen); } @@ -274,12 +274,12 @@ void receive_RS485() // Runs as fast as possible to handle the serial stream if (RS485_RXFRAME[rx_index - 1] == 0x00) { if ((rx_index == 10) && (RS485_RXFRAME[0] == 0x09) && register_content_ok) { #ifdef DEBUG_KOSTAL_RS485_DATA - Serial.print("RX: "); + logging.print("RX: "); for (uint8_t i = 0; i < 10; i++) { - Serial.print(RS485_RXFRAME[i], HEX); - Serial.print(" "); + logging.print(RS485_RXFRAME[i], HEX); + logging.print(" "); } - Serial.println(""); + logging.println(""); #endif rx_index = 0; if (check_kostal_frame_crc()) { diff --git a/Software/src/inverter/PYLON-CAN.cpp b/Software/src/inverter/PYLON-CAN.cpp index 2145b3e7..a4a6bb2f 100644 --- a/Software/src/inverter/PYLON-CAN.cpp +++ b/Software/src/inverter/PYLON-CAN.cpp @@ -422,7 +422,7 @@ void update_values_can_inverter() { //This function maps all the values fetched } } -void receive_can_inverter(CAN_frame rx_frame) { +void map_can_frame_to_variable_inverter(CAN_frame rx_frame) { switch (rx_frame.ID) { case 0x4200: //Message originating from inverter. Depending on which data is required, act accordingly datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; @@ -438,43 +438,43 @@ void receive_can_inverter(CAN_frame rx_frame) { } } -void send_can_inverter() { +void transmit_can_inverter() { // No periodic sending, we only react on received can messages } void send_setup_info() { //Ensemble information #ifdef SEND_0 - transmit_can(&PYLON_7310, can_config.inverter); - transmit_can(&PYLON_7320, can_config.inverter); + transmit_can_frame(&PYLON_7310, can_config.inverter); + transmit_can_frame(&PYLON_7320, can_config.inverter); #endif #ifdef SEND_1 - transmit_can(&PYLON_7311, can_config.inverter); - transmit_can(&PYLON_7321, can_config.inverter); + transmit_can_frame(&PYLON_7311, can_config.inverter); + transmit_can_frame(&PYLON_7321, can_config.inverter); #endif } void send_system_data() { //System equipment information #ifdef SEND_0 - transmit_can(&PYLON_4210, can_config.inverter); - transmit_can(&PYLON_4220, can_config.inverter); - transmit_can(&PYLON_4230, can_config.inverter); - transmit_can(&PYLON_4240, can_config.inverter); - transmit_can(&PYLON_4250, can_config.inverter); - transmit_can(&PYLON_4260, can_config.inverter); - transmit_can(&PYLON_4270, can_config.inverter); - transmit_can(&PYLON_4280, can_config.inverter); - transmit_can(&PYLON_4290, can_config.inverter); + transmit_can_frame(&PYLON_4210, can_config.inverter); + transmit_can_frame(&PYLON_4220, can_config.inverter); + transmit_can_frame(&PYLON_4230, can_config.inverter); + transmit_can_frame(&PYLON_4240, can_config.inverter); + transmit_can_frame(&PYLON_4250, can_config.inverter); + transmit_can_frame(&PYLON_4260, can_config.inverter); + transmit_can_frame(&PYLON_4270, can_config.inverter); + transmit_can_frame(&PYLON_4280, can_config.inverter); + transmit_can_frame(&PYLON_4290, can_config.inverter); #endif #ifdef SEND_1 - transmit_can(&PYLON_4211, can_config.inverter); - transmit_can(&PYLON_4221, can_config.inverter); - transmit_can(&PYLON_4231, can_config.inverter); - transmit_can(&PYLON_4241, can_config.inverter); - transmit_can(&PYLON_4251, can_config.inverter); - transmit_can(&PYLON_4261, can_config.inverter); - transmit_can(&PYLON_4271, can_config.inverter); - transmit_can(&PYLON_4281, can_config.inverter); - transmit_can(&PYLON_4291, can_config.inverter); + transmit_can_frame(&PYLON_4211, can_config.inverter); + transmit_can_frame(&PYLON_4221, can_config.inverter); + transmit_can_frame(&PYLON_4231, can_config.inverter); + transmit_can_frame(&PYLON_4241, can_config.inverter); + transmit_can_frame(&PYLON_4251, can_config.inverter); + transmit_can_frame(&PYLON_4261, can_config.inverter); + transmit_can_frame(&PYLON_4271, can_config.inverter); + transmit_can_frame(&PYLON_4281, can_config.inverter); + transmit_can_frame(&PYLON_4291, can_config.inverter); #endif } void setup_inverter(void) { // Performs one time setup at startup over CAN bus diff --git a/Software/src/inverter/PYLON-CAN.h b/Software/src/inverter/PYLON-CAN.h index 6b39afcd..bbe9b80d 100644 --- a/Software/src/inverter/PYLON-CAN.h +++ b/Software/src/inverter/PYLON-CAN.h @@ -6,7 +6,7 @@ void send_system_data(); void send_setup_info(); -void transmit_can(CAN_frame* tx_frame, int interface); +void transmit_can_frame(CAN_frame* tx_frame, int interface); void setup_inverter(void); #endif diff --git a/Software/src/inverter/PYLON-LV-CAN.cpp b/Software/src/inverter/PYLON-LV-CAN.cpp index e5eb2e87..ddc2ce5a 100644 --- a/Software/src/inverter/PYLON-LV-CAN.cpp +++ b/Software/src/inverter/PYLON-LV-CAN.cpp @@ -108,7 +108,7 @@ void update_values_can_inverter() { // PYLON_35E is pre-filled with the manufacturer name } -void receive_can_inverter(CAN_frame rx_frame) { +void map_can_frame_to_variable_inverter(CAN_frame rx_frame) { switch (rx_frame.ID) { case 0x305: //Message originating from inverter. // according to the spec, this message includes only 0-bytes @@ -119,18 +119,18 @@ void receive_can_inverter(CAN_frame rx_frame) { } } -void send_can_inverter() { +void transmit_can_inverter() { unsigned long currentMillis = millis(); if (currentMillis - previousMillis1000ms >= 1000) { previousMillis1000ms = currentMillis; - transmit_can(&PYLON_351, can_config.inverter); - transmit_can(&PYLON_355, can_config.inverter); - transmit_can(&PYLON_356, can_config.inverter); - transmit_can(&PYLON_359, can_config.inverter); - transmit_can(&PYLON_35C, can_config.inverter); - transmit_can(&PYLON_35E, can_config.inverter); + transmit_can_frame(&PYLON_351, can_config.inverter); + transmit_can_frame(&PYLON_355, can_config.inverter); + transmit_can_frame(&PYLON_356, can_config.inverter); + transmit_can_frame(&PYLON_359, can_config.inverter); + transmit_can_frame(&PYLON_35C, can_config.inverter); + transmit_can_frame(&PYLON_35E, can_config.inverter); } } void setup_inverter(void) { // Performs one time setup at startup over CAN bus diff --git a/Software/src/inverter/PYLON-LV-CAN.h b/Software/src/inverter/PYLON-LV-CAN.h index ca6922eb..e38f5506 100644 --- a/Software/src/inverter/PYLON-LV-CAN.h +++ b/Software/src/inverter/PYLON-LV-CAN.h @@ -11,7 +11,7 @@ void send_system_data(); void send_setup_info(); -void transmit_can(CAN_frame* tx_frame, int interface); +void transmit_can_frame(CAN_frame* tx_frame, int interface); void setup_inverter(void); #endif diff --git a/Software/src/inverter/SCHNEIDER-CAN.cpp b/Software/src/inverter/SCHNEIDER-CAN.cpp index 68021ef0..38cf1ed9 100644 --- a/Software/src/inverter/SCHNEIDER-CAN.cpp +++ b/Software/src/inverter/SCHNEIDER-CAN.cpp @@ -255,7 +255,7 @@ void update_values_can_inverter() { //This function maps all the values fetched SE_320.data.u8[1] = 0x02; } -void receive_can_inverter(CAN_frame rx_frame) { +void map_can_frame_to_variable_inverter(CAN_frame rx_frame) { switch (rx_frame.ID) { case 0x310: // Still alive message from inverter, every 1s datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; @@ -265,35 +265,35 @@ void receive_can_inverter(CAN_frame rx_frame) { } } -void send_can_inverter() { +void transmit_can_inverter() { unsigned long currentMillis = millis(); // Send 500ms CAN Message if (currentMillis - previousMillis500ms >= INTERVAL_500_MS) { previousMillis500ms = currentMillis; - transmit_can(&SE_321, can_config.inverter); - transmit_can(&SE_322, can_config.inverter); - transmit_can(&SE_323, can_config.inverter); - transmit_can(&SE_324, can_config.inverter); - transmit_can(&SE_325, can_config.inverter); + transmit_can_frame(&SE_321, can_config.inverter); + transmit_can_frame(&SE_322, can_config.inverter); + transmit_can_frame(&SE_323, can_config.inverter); + transmit_can_frame(&SE_324, can_config.inverter); + transmit_can_frame(&SE_325, can_config.inverter); } // Send 2s CAN Message if (currentMillis - previousMillis2s >= INTERVAL_2_S) { previousMillis2s = currentMillis; - transmit_can(&SE_320, can_config.inverter); - transmit_can(&SE_326, can_config.inverter); - transmit_can(&SE_327, can_config.inverter); + transmit_can_frame(&SE_320, can_config.inverter); + transmit_can_frame(&SE_326, can_config.inverter); + transmit_can_frame(&SE_327, can_config.inverter); } // Send 10s CAN Message if (currentMillis - previousMillis10s >= INTERVAL_10_S) { previousMillis10s = currentMillis; - transmit_can(&SE_328, can_config.inverter); - transmit_can(&SE_330, can_config.inverter); - transmit_can(&SE_331, can_config.inverter); - transmit_can(&SE_332, can_config.inverter); - transmit_can(&SE_333, can_config.inverter); + transmit_can_frame(&SE_328, can_config.inverter); + transmit_can_frame(&SE_330, can_config.inverter); + transmit_can_frame(&SE_331, can_config.inverter); + transmit_can_frame(&SE_332, can_config.inverter); + transmit_can_frame(&SE_333, can_config.inverter); } } diff --git a/Software/src/inverter/SCHNEIDER-CAN.h b/Software/src/inverter/SCHNEIDER-CAN.h index 83e7c87a..d576308c 100644 --- a/Software/src/inverter/SCHNEIDER-CAN.h +++ b/Software/src/inverter/SCHNEIDER-CAN.h @@ -27,7 +27,7 @@ #define COMMAND_CHARGE_AND_DISCHARGE_ALLOWED 0x06 #define COMMAND_STOP 0x08 -void transmit_can(CAN_frame* tx_frame, int interface); +void transmit_can_frame(CAN_frame* tx_frame, int interface); void setup_inverter(void); #endif diff --git a/Software/src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.cpp b/Software/src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.cpp index a61ea7dc..35772e4a 100644 --- a/Software/src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.cpp +++ b/Software/src/inverter/SERIAL-LINK-TRANSMITTER-INVERTER.cpp @@ -60,8 +60,8 @@ void manageSerialLinkTransmitter() { } bool sendError = dataLinkTransmit.checkTransmissionError(true); if (sendError) { - Serial.print(currentTime); - Serial.println(" - ERROR: Serial Data Link - SEND Error"); + logging.print(currentTime); + logging.println(" - ERROR: Serial Data Link - SEND Error"); lasterror = true; transmitGoodSince = currentTime; } @@ -82,17 +82,17 @@ void manageSerialLinkTransmitter() { if (lasterror && (ackReceived > 0)) { lasterror = false; - Serial.print(currentTime); - Serial.println(" - RECOVERY: Serial Data Link - Send GOOD"); + logging.print(currentTime); + logging.println(" - RECOVERY: Serial Data Link - Send GOOD"); } //--- reporting every 60 seconds that transmission is good if (currentTime - transmitGoodSince > INTERVAL_60_S) { transmitGoodSince = currentTime; - Serial.print(currentTime); - Serial.println(" - Transmit Good"); + logging.print(currentTime); + logging.println(" - Transmit Good"); // printUsefullData(); -#ifdef DEBUG_VIA_USB +#ifdef DEBUG_LOG void printSendingValues(); #endif } @@ -100,13 +100,13 @@ void manageSerialLinkTransmitter() { //--- report that Errors been ocurring for > 60 seconds if (currentTime - lastGood > INTERVAL_60_S) { lastGood = currentTime; - Serial.print(currentTime); - Serial.println(" - Transmit Failed : 60 seconds"); + logging.print(currentTime); + logging.println(" - Transmit Failed : 60 seconds"); // print the max_ data - Serial.println("SerialDataLink : bms_status=4"); - Serial.println("SerialDataLink : LEDcolor = RED"); - Serial.println("SerialDataLink : max_target_discharge_power = 0"); - Serial.println("SerialDataLink : max_target_charge_power = 0"); + logging.println("SerialDataLink : bms_status=4"); + logging.println("SerialDataLink : LEDcolor = RED"); + logging.println("SerialDataLink : max_target_discharge_power = 0"); + logging.println("SerialDataLink : max_target_charge_power = 0"); datalayer.battery.status.max_discharge_power_W = 0; datalayer.battery.status.max_charge_power_W = 0; @@ -117,8 +117,8 @@ void manageSerialLinkTransmitter() { // lastMessageReceived from CAN bus (Battery) if (currentTime - lastMessageReceived > (5 * 60000) ) // 5 minutes { - Serial.print(millis()); - Serial.println(" - Data Stale : 5 minutes"); + logging.print(millis()); + logging.println(" - Data Stale : 5 minutes"); // throw error // stop transmitting until fresh @@ -154,42 +154,42 @@ void manageSerialLinkTransmitter() { } void printSendingValues() { - Serial.println("Values from battery: "); - Serial.print("SOC: "); - Serial.print(datalayer.battery.status.real_soc); - Serial.print(" SOH: "); - Serial.print(datalayer.battery.status.soh_pptt); - Serial.print(" Voltage: "); - Serial.print(datalayer.battery.status.voltage_dV); - Serial.print(" Current: "); - Serial.print(datalayer.battery.status.current_dA); - Serial.print(" Capacity: "); - Serial.print(datalayer.battery.info.total_capacity_Wh); - Serial.print(" Remain cap: "); - Serial.print(datalayer.battery.status.remaining_capacity_Wh); - Serial.print(" Max discharge W: "); - Serial.print(datalayer.battery.status.max_discharge_power_W); - Serial.print(" Max charge W: "); - Serial.print(datalayer.battery.status.max_charge_power_W); - Serial.print(" BMS status: "); - Serial.print(datalayer.battery.status.bms_status); - Serial.print(" Power: "); - Serial.print(datalayer.battery.status.active_power_W); - Serial.print(" Temp min: "); - Serial.print(datalayer.battery.status.temperature_min_dC); - Serial.print(" Temp max: "); - Serial.print(datalayer.battery.status.temperature_max_dC); - Serial.print(" Cell max: "); - Serial.print(datalayer.battery.status.cell_max_voltage_mV); - Serial.print(" Cell min: "); - Serial.print(datalayer.battery.status.cell_min_voltage_mV); - Serial.print(" LFP : "); - Serial.print(datalayer.battery.info.chemistry); - Serial.print(" Battery Allows Contactor Closing: "); - Serial.print(datalayer.system.status.battery_allows_contactor_closing); - Serial.print(" Inverter Allows Contactor Closing: "); - Serial.print(datalayer.system.status.inverter_allows_contactor_closing); + logging.println("Values from battery: "); + logging.print("SOC: "); + logging.print(datalayer.battery.status.real_soc); + logging.print(" SOH: "); + logging.print(datalayer.battery.status.soh_pptt); + logging.print(" Voltage: "); + logging.print(datalayer.battery.status.voltage_dV); + logging.print(" Current: "); + logging.print(datalayer.battery.status.current_dA); + logging.print(" Capacity: "); + logging.print(datalayer.battery.info.total_capacity_Wh); + logging.print(" Remain cap: "); + logging.print(datalayer.battery.status.remaining_capacity_Wh); + logging.print(" Max discharge W: "); + logging.print(datalayer.battery.status.max_discharge_power_W); + logging.print(" Max charge W: "); + logging.print(datalayer.battery.status.max_charge_power_W); + logging.print(" BMS status: "); + logging.print(datalayer.battery.status.bms_status); + logging.print(" Power: "); + logging.print(datalayer.battery.status.active_power_W); + logging.print(" Temp min: "); + logging.print(datalayer.battery.status.temperature_min_dC); + logging.print(" Temp max: "); + logging.print(datalayer.battery.status.temperature_max_dC); + logging.print(" Cell max: "); + logging.print(datalayer.battery.status.cell_max_voltage_mV); + logging.print(" Cell min: "); + logging.print(datalayer.battery.status.cell_min_voltage_mV); + logging.print(" LFP : "); + logging.print(datalayer.battery.info.chemistry); + logging.print(" Battery Allows Contactor Closing: "); + logging.print(datalayer.system.status.battery_allows_contactor_closing); + logging.print(" Inverter Allows Contactor Closing: "); + logging.print(datalayer.system.status.inverter_allows_contactor_closing); - Serial.println(""); + logging.println(""); } #endif diff --git a/Software/src/inverter/SMA-CAN.cpp b/Software/src/inverter/SMA-BYD-H-CAN.cpp similarity index 74% rename from Software/src/inverter/SMA-CAN.cpp rename to Software/src/inverter/SMA-BYD-H-CAN.cpp index 5831406d..5bd68f8d 100644 --- a/Software/src/inverter/SMA-CAN.cpp +++ b/Software/src/inverter/SMA-BYD-H-CAN.cpp @@ -1,14 +1,48 @@ #include "../include.h" -#ifdef SMA_CAN +#ifdef SMA_BYD_H_CAN #include "../datalayer/datalayer.h" -#include "SMA-CAN.h" +#include "SMA-BYD-H-CAN.h" /* TODO: Map error bits in 0x158 */ /* Do not change code below unless you are sure what you are doing */ static unsigned long previousMillis100ms = 0; +static uint32_t inverter_time = 0; +static uint16_t inverter_voltage = 0; +static int16_t inverter_current = 0; + //Actual content messages +CAN_frame SMA_158 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x158, + .data = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x6A, 0xAA, 0xAA}}; +CAN_frame SMA_358 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x358, + .data = {0x0F, 0x6C, 0x06, 0x20, 0x00, 0x00, 0x00, 0x00}}; +CAN_frame SMA_3D8 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x3D8, + .data = {0x04, 0x10, 0x27, 0x10, 0x00, 0x18, 0xF9, 0x00}}; +CAN_frame SMA_458 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x458, + .data = {0x00, 0x00, 0x06, 0x75, 0x00, 0x00, 0x05, 0xD6}}; +CAN_frame SMA_4D8 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x4D8, + .data = {0x09, 0xFD, 0x00, 0x00, 0x00, 0xA8, 0x02, 0x08}}; +CAN_frame SMA_518 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x518, + .data = {0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF}}; CAN_frame SMA_558 = {.FD = false, .ext_ID = false, .DLC = 8, @@ -39,43 +73,12 @@ CAN_frame SMA_618_3 = {.FD = false, .DLC = 8, .ID = 0x618, .data = {0x02, 0x2E, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00}}; //2 - 0 -CAN_frame SMA_358 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x358, - .data = {0x0F, 0x6C, 0x06, 0x20, 0x00, 0x00, 0x00, 0x00}}; -CAN_frame SMA_3D8 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x3D8, - .data = {0x04, 0x10, 0x27, 0x10, 0x00, 0x18, 0xF9, 0x00}}; -CAN_frame SMA_458 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x458, - .data = {0x00, 0x00, 0x06, 0x75, 0x00, 0x00, 0x05, 0xD6}}; -CAN_frame SMA_518 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x518, - .data = {0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF}}; -CAN_frame SMA_4D8 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x4D8, - .data = {0x09, 0xFD, 0x00, 0x00, 0x00, 0xA8, 0x02, 0x08}}; -CAN_frame SMA_158 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x158, - .data = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x6A, 0xAA, 0xAA}}; static int16_t temperature_average = 0; static uint16_t ampere_hours_remaining = 0; -void update_values_can_inverter() { //This function maps all the values fetched from battery CAN to the correct CAN messages - //Calculate values - +void update_values_can_inverter() { //This function maps all the values fetched from battery CAN to the inverter CAN + // Update values temperature_average = ((datalayer.battery.status.temperature_max_dC + datalayer.battery.status.temperature_min_dC) / 2); @@ -86,6 +89,7 @@ void update_values_can_inverter() { //This function maps all the values fetched } //Map values to CAN messages + //Maxvoltage (eg 400.0V = 4000 , 16bits long) SMA_358.data.u8[0] = (datalayer.battery.info.max_design_voltage_dV >> 8); SMA_358.data.u8[1] = (datalayer.battery.info.max_design_voltage_dV & 0x00FF); @@ -127,10 +131,18 @@ void update_values_can_inverter() { //This function maps all the values fetched } //Error bits - if (!datalayer.system.status.inverter_allows_contactor_closing) { - SMA_158.data.u8[2] = 0x6A; - } else { + if (datalayer.system.status.inverter_allows_contactor_closing) { SMA_158.data.u8[2] = 0xAA; +#ifdef INVERTER_CONTACTOR_ENABLE_LED_PIN + digitalWrite(INVERTER_CONTACTOR_ENABLE_LED_PIN, + HIGH); // Turn on LED to indicate that SMA inverter allows contactor closing +#endif // INVERTER_CONTACTOR_ENABLE_LED_PIN + } else { + SMA_158.data.u8[2] = 0x6A; +#ifdef INVERTER_CONTACTOR_ENABLE_LED_PIN + digitalWrite(INVERTER_CONTACTOR_ENABLE_LED_PIN, + LOW); // Turn off LED to indicate that SMA inverter allows contactor closing +#endif // INVERTER_CONTACTOR_ENABLE_LED_PIN } /* @@ -184,12 +196,12 @@ void update_values_can_inverter() { //This function maps all the values fetched */ } -void receive_can_inverter(CAN_frame rx_frame) { +void map_can_frame_to_variable_inverter(CAN_frame rx_frame) { switch (rx_frame.ID) { case 0x360: //Message originating from SMA inverter - Voltage and current datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; - //Frame0-1 Voltage - //Frame2-3 Current + inverter_voltage = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + inverter_current = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; break; case 0x3E0: //Message originating from SMA inverter - ? datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; @@ -198,60 +210,73 @@ void receive_can_inverter(CAN_frame rx_frame) { datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; //Frame0-3 Timestamp /* - transmit_can(&SMA_158, can_config.inverter); - transmit_can(&SMA_358, can_config.inverter); - transmit_can(&SMA_3D8, can_config.inverter); - transmit_can(&SMA_458, can_config.inverter); - transmit_can(&SMA_518, can_config.inverter); - transmit_can(&SMA_4D8, can_config.inverter); + transmit_can_frame(&SMA_158, can_config.inverter); + transmit_can_frame(&SMA_358, can_config.inverter); + transmit_can_frame(&SMA_3D8, can_config.inverter); + transmit_can_frame(&SMA_458, can_config.inverter); + transmit_can_frame(&SMA_518, can_config.inverter); + transmit_can_frame(&SMA_4D8, can_config.inverter); */ - break; - case 0x5E0: //Message originating from SMA inverter - String - datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; + inverter_time = + (rx_frame.data.u8[0] << 24) | (rx_frame.data.u8[1] << 16) | (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; break; case 0x560: //Message originating from SMA inverter - Init datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; break; + case 0x5E0: //Message originating from SMA inverter - String + datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; + //Inverter brand (frame1-3 = 0x53 0x4D 0x41) = SMA + break; case 0x5E7: //Pairing request datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; - transmit_can(&SMA_558, can_config.inverter); - transmit_can(&SMA_598, can_config.inverter); - transmit_can(&SMA_5D8, can_config.inverter); - transmit_can(&SMA_618_1, can_config.inverter); - transmit_can(&SMA_618_2, can_config.inverter); - transmit_can(&SMA_618_3, can_config.inverter); - transmit_can(&SMA_158, can_config.inverter); - transmit_can(&SMA_358, can_config.inverter); - transmit_can(&SMA_3D8, can_config.inverter); - transmit_can(&SMA_458, can_config.inverter); - transmit_can(&SMA_518, can_config.inverter); - transmit_can(&SMA_4D8, can_config.inverter); + transmit_can_init(); break; default: break; } } -void send_can_inverter() { +void transmit_can_inverter() { unsigned long currentMillis = millis(); - // Send CAN Message every 100ms if Enable line is HIGH + // Send CAN Message every 100ms if inverter allows contactor closing if (datalayer.system.status.inverter_allows_contactor_closing) { if (currentMillis - previousMillis100ms >= 100) { previousMillis100ms = currentMillis; - transmit_can(&SMA_158, can_config.inverter); - transmit_can(&SMA_358, can_config.inverter); - transmit_can(&SMA_3D8, can_config.inverter); - transmit_can(&SMA_458, can_config.inverter); - transmit_can(&SMA_518, can_config.inverter); - transmit_can(&SMA_4D8, can_config.inverter); + transmit_can_frame(&SMA_158, can_config.inverter); + transmit_can_frame(&SMA_358, can_config.inverter); + transmit_can_frame(&SMA_3D8, can_config.inverter); + transmit_can_frame(&SMA_458, can_config.inverter); + transmit_can_frame(&SMA_518, can_config.inverter); + transmit_can_frame(&SMA_4D8, can_config.inverter); } } } +void transmit_can_init() { + transmit_can_frame(&SMA_558, can_config.inverter); + transmit_can_frame(&SMA_598, can_config.inverter); + transmit_can_frame(&SMA_5D8, can_config.inverter); + transmit_can_frame(&SMA_618_1, can_config.inverter); + transmit_can_frame(&SMA_618_2, can_config.inverter); + transmit_can_frame(&SMA_618_3, can_config.inverter); + transmit_can_frame(&SMA_158, can_config.inverter); + transmit_can_frame(&SMA_358, can_config.inverter); + transmit_can_frame(&SMA_3D8, can_config.inverter); + transmit_can_frame(&SMA_458, can_config.inverter); + transmit_can_frame(&SMA_518, can_config.inverter); + transmit_can_frame(&SMA_4D8, can_config.inverter); +} + void setup_inverter(void) { // Performs one time setup at startup over CAN bus strncpy(datalayer.system.info.inverter_protocol, "SMA CAN", 63); datalayer.system.info.inverter_protocol[63] = '\0'; + datalayer.system.status.inverter_allows_contactor_closing = false; // The inverter needs to allow first + pinMode(INVERTER_CONTACTOR_ENABLE_PIN, INPUT); +#ifdef INVERTER_CONTACTOR_ENABLE_LED_PIN + pinMode(INVERTER_CONTACTOR_ENABLE_LED_PIN, OUTPUT); + digitalWrite(INVERTER_CONTACTOR_ENABLE_LED_PIN, LOW); // Turn LED off, until inverter allows contactor closing +#endif // INVERTER_CONTACTOR_ENABLE_LED_PIN } #endif diff --git a/Software/src/inverter/BYD-SMA.h b/Software/src/inverter/SMA-BYD-H-CAN.h similarity index 51% rename from Software/src/inverter/BYD-SMA.h rename to Software/src/inverter/SMA-BYD-H-CAN.h index e787191d..8e9413c5 100644 --- a/Software/src/inverter/BYD-SMA.h +++ b/Software/src/inverter/SMA-BYD-H-CAN.h @@ -1,5 +1,5 @@ -#ifndef BYD_SMA_H -#define BYD_SMA_H +#ifndef SMA_BYD_H_CAN_H +#define SMA_BYD_H_CAN_H #include "../include.h" #define CAN_INVERTER_SELECTED @@ -7,7 +7,8 @@ #define READY_STATE 0x03 #define STOP_STATE 0x02 -void transmit_can(CAN_frame* tx_frame, int interface); +void transmit_can_frame(CAN_frame* tx_frame, int interface); +void transmit_can_init(); void setup_inverter(void); #endif diff --git a/Software/src/inverter/BYD-SMA.cpp b/Software/src/inverter/SMA-BYD-HVS-CAN.cpp similarity index 75% rename from Software/src/inverter/BYD-SMA.cpp rename to Software/src/inverter/SMA-BYD-HVS-CAN.cpp index 34e33063..a5df8bee 100644 --- a/Software/src/inverter/BYD-SMA.cpp +++ b/Software/src/inverter/SMA-BYD-HVS-CAN.cpp @@ -1,14 +1,23 @@ #include "../include.h" -#ifdef BYD_SMA +#ifdef SMA_BYD_HVS_CAN #include "../datalayer/datalayer.h" -#include "BYD-SMA.h" +#include "SMA-BYD-HVS-CAN.h" /* TODO: Map error bits in 0x158 */ /* Do not change code below unless you are sure what you are doing */ static unsigned long previousMillis100ms = 0; +static uint32_t inverter_time = 0; +static uint16_t inverter_voltage = 0; +static int16_t inverter_current = 0; + //Actual content messages +CAN_frame SMA_158 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x158, // All 0xAA, no faults active + .data = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA}}; CAN_frame SMA_358 = {.FD = false, .ext_ID = false, .DLC = 8, @@ -24,21 +33,16 @@ CAN_frame SMA_458 = {.FD = false, .DLC = 8, .ID = 0x458, .data = {0x00, 0x00, 0x11, 0xC8, 0x00, 0x00, 0x0E, 0xF4}}; -CAN_frame SMA_518 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x518, - .data = {0x01, 0x4A, 0x01, 0x25, 0xFF, 0xFF, 0xFF, 0xFF}}; CAN_frame SMA_4D8 = {.FD = false, .ext_ID = false, .DLC = 8, .ID = 0x4D8, .data = {0x10, 0x62, 0x00, 0x16, 0x01, 0x68, 0x03, 0x08}}; -CAN_frame SMA_158 = {.FD = false, +CAN_frame SMA_518 = {.FD = false, .ext_ID = false, .DLC = 8, - .ID = 0x158, // All 0xAA, no faults active - .data = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA}}; + .ID = 0x518, + .data = {0x01, 0x4A, 0x01, 0x25, 0xFF, 0xFF, 0xFF, 0xFF}}; // Pairing/Battery setup information @@ -78,8 +82,8 @@ static int16_t charge_current = 0; static int16_t temperature_average = 0; static uint16_t ampere_hours_remaining = 0; -void update_values_can_inverter() { //This function maps all the values fetched from battery CAN to the correct CAN messages - //Calculate values +void update_values_can_inverter() { //This function maps all the values fetched from battery CAN to the inverter CAN + // Update values temperature_average = ((datalayer.battery.status.temperature_max_dC + datalayer.battery.status.temperature_min_dC) / 2); @@ -90,6 +94,7 @@ void update_values_can_inverter() { //This function maps all the values fetched } //Map values to CAN messages + //Maxvoltage (eg 400.0V = 4000 , 16bits long) SMA_358.data.u8[0] = (datalayer.battery.info.max_design_voltage_dV >> 8); SMA_358.data.u8[1] = (datalayer.battery.info.max_design_voltage_dV & 0x00FF); @@ -130,10 +135,18 @@ void update_values_can_inverter() { //This function maps all the values fetched } //Error bits - if (!datalayer.system.status.inverter_allows_contactor_closing) { - SMA_158.data.u8[2] = 0x6A; - } else { + if (datalayer.system.status.inverter_allows_contactor_closing) { SMA_158.data.u8[2] = 0xAA; +#ifdef INVERTER_CONTACTOR_ENABLE_LED_PIN + digitalWrite(INVERTER_CONTACTOR_ENABLE_LED_PIN, + HIGH); // Turn on LED to indicate that SMA inverter allows contactor closing +#endif // INVERTER_CONTACTOR_ENABLE_LED_PIN + } else { + SMA_158.data.u8[2] = 0x6A; +#ifdef INVERTER_CONTACTOR_ENABLE_LED_PIN + digitalWrite(INVERTER_CONTACTOR_ENABLE_LED_PIN, + LOW); // Turn off LED to indicate that SMA inverter allows contactor closing +#endif // INVERTER_CONTACTOR_ENABLE_LED_PIN } /* @@ -187,12 +200,12 @@ void update_values_can_inverter() { //This function maps all the values fetched */ } -void receive_can_inverter(CAN_frame rx_frame) { +void map_can_frame_to_variable_inverter(CAN_frame rx_frame) { switch (rx_frame.ID) { case 0x360: //Message originating from SMA inverter - Voltage and current datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; - //Frame0-1 Voltage - //Frame2-3 Current + inverter_voltage = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + inverter_current = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; break; case 0x3E0: //Message originating from SMA inverter - ? datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; @@ -201,60 +214,72 @@ void receive_can_inverter(CAN_frame rx_frame) { datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; //Frame0-3 Timestamp /* - transmit_can(&SMA_158, can_config.inverter); - transmit_can(&SMA_358, can_config.inverter); - transmit_can(&SMA_3D8, can_config.inverter); - transmit_can(&SMA_458, can_config.inverter); - transmit_can(&SMA_518, can_config.inverter); - transmit_can(&SMA_4D8, can_config.inverter); + transmit_can_frame(&SMA_158, can_config.inverter); + transmit_can_frame(&SMA_358, can_config.inverter); + transmit_can_frame(&SMA_3D8, can_config.inverter); + transmit_can_frame(&SMA_458, can_config.inverter); + transmit_can_frame(&SMA_518, can_config.inverter); + transmit_can_frame(&SMA_4D8, can_config.inverter); */ - break; - case 0x5E0: //Message originating from SMA inverter - String - datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; + inverter_time = + (rx_frame.data.u8[0] << 24) | (rx_frame.data.u8[1] << 16) | (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; break; case 0x560: //Message originating from SMA inverter - Init datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; break; + case 0x5E0: //Message originating from SMA inverter - String + datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; + //Inverter brand (frame1-3 = 0x53 0x4D 0x41) = SMA + break; case 0x5E7: //Pairing request datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; - transmit_can(&SMA_558, can_config.inverter); - transmit_can(&SMA_598, can_config.inverter); - transmit_can(&SMA_5D8, can_config.inverter); - transmit_can(&SMA_618_1, can_config.inverter); - transmit_can(&SMA_618_2, can_config.inverter); - transmit_can(&SMA_618_3, can_config.inverter); - transmit_can(&SMA_158, can_config.inverter); - transmit_can(&SMA_358, can_config.inverter); - transmit_can(&SMA_3D8, can_config.inverter); - transmit_can(&SMA_458, can_config.inverter); - transmit_can(&SMA_518, can_config.inverter); - transmit_can(&SMA_4D8, can_config.inverter); + transmit_can_init(); break; default: break; } } -void send_can_inverter() { +void transmit_can_inverter() { unsigned long currentMillis = millis(); - // Send CAN Message every 100ms if we're enabled + // Send CAN Message every 100ms if inverter allows contactor closing if (datalayer.system.status.inverter_allows_contactor_closing) { if (currentMillis - previousMillis100ms >= 100) { previousMillis100ms = currentMillis; - transmit_can(&SMA_158, can_config.inverter); - transmit_can(&SMA_358, can_config.inverter); - transmit_can(&SMA_3D8, can_config.inverter); - transmit_can(&SMA_458, can_config.inverter); - transmit_can(&SMA_518, can_config.inverter); - transmit_can(&SMA_4D8, can_config.inverter); + transmit_can_frame(&SMA_158, can_config.inverter); + transmit_can_frame(&SMA_358, can_config.inverter); + transmit_can_frame(&SMA_3D8, can_config.inverter); + transmit_can_frame(&SMA_458, can_config.inverter); + transmit_can_frame(&SMA_518, can_config.inverter); + transmit_can_frame(&SMA_4D8, can_config.inverter); } } } + +void transmit_can_init() { + transmit_can_frame(&SMA_558, can_config.inverter); + transmit_can_frame(&SMA_598, can_config.inverter); + transmit_can_frame(&SMA_5D8, can_config.inverter); + transmit_can_frame(&SMA_618_1, can_config.inverter); + transmit_can_frame(&SMA_618_2, can_config.inverter); + transmit_can_frame(&SMA_618_3, can_config.inverter); + transmit_can_frame(&SMA_158, can_config.inverter); + transmit_can_frame(&SMA_358, can_config.inverter); + transmit_can_frame(&SMA_3D8, can_config.inverter); + transmit_can_frame(&SMA_458, can_config.inverter); + transmit_can_frame(&SMA_518, can_config.inverter); + transmit_can_frame(&SMA_4D8, can_config.inverter); +} + void setup_inverter(void) { // Performs one time setup at startup over CAN bus strncpy(datalayer.system.info.inverter_protocol, "BYD Battery-Box HVS over SMA CAN", 63); datalayer.system.info.inverter_protocol[63] = '\0'; datalayer.system.status.inverter_allows_contactor_closing = false; // The inverter needs to allow first pinMode(INVERTER_CONTACTOR_ENABLE_PIN, INPUT); +#ifdef INVERTER_CONTACTOR_ENABLE_LED_PIN + pinMode(INVERTER_CONTACTOR_ENABLE_LED_PIN, OUTPUT); + digitalWrite(INVERTER_CONTACTOR_ENABLE_LED_PIN, LOW); // Turn LED off, until inverter allows contactor closing +#endif // INVERTER_CONTACTOR_ENABLE_LED_PIN } #endif diff --git a/Software/src/inverter/SMA-CAN.h b/Software/src/inverter/SMA-BYD-HVS-CAN.h similarity index 50% rename from Software/src/inverter/SMA-CAN.h rename to Software/src/inverter/SMA-BYD-HVS-CAN.h index 111044a4..615def83 100644 --- a/Software/src/inverter/SMA-CAN.h +++ b/Software/src/inverter/SMA-BYD-HVS-CAN.h @@ -1,5 +1,5 @@ -#ifndef SMA_CAN_H -#define SMA_CAN_H +#ifndef SMA_BYD_HVS_CAN_H +#define SMA_BYD_HVS_CAN_H #include "../include.h" #define CAN_INVERTER_SELECTED @@ -7,7 +7,8 @@ #define READY_STATE 0x03 #define STOP_STATE 0x02 -void transmit_can(CAN_frame* tx_frame, int interface); +void transmit_can_frame(CAN_frame* tx_frame, int interface); +void transmit_can_init(); void setup_inverter(void); #endif diff --git a/Software/src/inverter/SMA-LV-CAN.cpp b/Software/src/inverter/SMA-LV-CAN.cpp index 77d3c429..eff1598c 100644 --- a/Software/src/inverter/SMA-LV-CAN.cpp +++ b/Software/src/inverter/SMA-LV-CAN.cpp @@ -16,6 +16,11 @@ static unsigned long previousMillis100ms = 0; #define MIN_VOLTAGE_DV 41 //Actual content messages +CAN_frame SMA_00F = {.FD = false, // Emergency stop message + .ext_ID = false, + .DLC = 8, //Documentation unclear, should message even have any content? + .ID = 0x00F, + .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; CAN_frame SMA_351 = {.FD = false, // Battery charge voltage, charge/discharge limit, min discharge voltage .ext_ID = false, .DLC = 8, @@ -51,21 +56,16 @@ CAN_frame SMA_35F = {.FD = false, // Battery Type, version, capacity, ID .DLC = 8, .ID = 0x35F, .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; -CAN_frame SMA_00F = {.FD = false, // Emergency stop message - .ext_ID = false, - .DLC = 8, //Documentation unclear, should message even have any content? - .ID = 0x00F, - .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; static int16_t temperature_average = 0; void update_values_can_inverter() { //This function maps all the values fetched from battery CAN to the correct CAN messages - //Calculate values - + // Update values temperature_average = ((datalayer.battery.status.temperature_max_dC + datalayer.battery.status.temperature_min_dC) / 2); //Map values to CAN messages + //Battery charge voltage (eg 400.0V = 4000 , 16bits long) (MIN 41V, MAX 63V, default 54V) SMA_351.data.u8[0] = ((datalayer.battery.info.max_design_voltage_dV - VOLTAGE_OFFSET_DV) >> 8); SMA_351.data.u8[1] = ((datalayer.battery.info.max_design_voltage_dV - VOLTAGE_OFFSET_DV) & 0x00FF); @@ -114,7 +114,7 @@ void update_values_can_inverter() { //This function maps all the values fetched //TODO: Map error/warnings in 0x35A } -void receive_can_inverter(CAN_frame rx_frame) { +void map_can_frame_to_variable_inverter(CAN_frame rx_frame) { switch (rx_frame.ID) { case 0x305: datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; @@ -136,23 +136,23 @@ void receive_can_inverter(CAN_frame rx_frame) { } } -void send_can_inverter() { +void transmit_can_inverter() { unsigned long currentMillis = millis(); if (currentMillis - previousMillis100ms >= INTERVAL_100_MS) { previousMillis100ms = currentMillis; - transmit_can(&SMA_351, can_config.inverter); - transmit_can(&SMA_355, can_config.inverter); - transmit_can(&SMA_356, can_config.inverter); - transmit_can(&SMA_35A, can_config.inverter); - transmit_can(&SMA_35B, can_config.inverter); - transmit_can(&SMA_35E, can_config.inverter); - transmit_can(&SMA_35F, can_config.inverter); + transmit_can_frame(&SMA_351, can_config.inverter); + transmit_can_frame(&SMA_355, can_config.inverter); + transmit_can_frame(&SMA_356, can_config.inverter); + transmit_can_frame(&SMA_35A, can_config.inverter); + transmit_can_frame(&SMA_35B, can_config.inverter); + transmit_can_frame(&SMA_35E, can_config.inverter); + transmit_can_frame(&SMA_35F, can_config.inverter); //Remote quick stop (optional) if (datalayer.battery.status.bms_status == FAULT) { - transmit_can(&SMA_00F, can_config.inverter); + transmit_can_frame(&SMA_00F, can_config.inverter); //After receiving this message, Sunny Island will immediately go into standby. //Please send start command, to start again. Manual start is also possible. } diff --git a/Software/src/inverter/SMA-LV-CAN.h b/Software/src/inverter/SMA-LV-CAN.h index a1c6e7e9..29164eb6 100644 --- a/Software/src/inverter/SMA-LV-CAN.h +++ b/Software/src/inverter/SMA-LV-CAN.h @@ -7,7 +7,7 @@ #define READY_STATE 0x03 #define STOP_STATE 0x02 -void transmit_can(CAN_frame* tx_frame, int interface); +void transmit_can_frame(CAN_frame* tx_frame, int interface); void setup_inverter(void); #endif diff --git a/Software/src/inverter/SMA-TRIPOWER-CAN.cpp b/Software/src/inverter/SMA-TRIPOWER-CAN.cpp index 7a242dae..9828dd7c 100644 --- a/Software/src/inverter/SMA-TRIPOWER-CAN.cpp +++ b/Software/src/inverter/SMA-TRIPOWER-CAN.cpp @@ -4,325 +4,262 @@ #include "SMA-TRIPOWER-CAN.h" /* TODO: -- Figure out the manufacturer info needed in send_tripower_init() CAN messages +- Figure out the manufacturer info needed in transmit_can_init() CAN messages - CAN logs from real system might be needed - Figure out how cellvoltages need to be displayed -- Figure out if sending send_tripower_init() like we do now is OK +- Figure out if sending transmit_can_init() like we do now is OK - Figure out how to send the non-cyclic messages when needed */ /* Do not change code below unless you are sure what you are doing */ -static unsigned long previousMillis500ms = 0; // will store last time a 100ms CAN Message was send +static unsigned long previousMillis250ms = 0; // will store last time a 250ms CAN Message was send +static unsigned long previousMillis500ms = 0; // will store last time a 500ms CAN Message was send +static unsigned long previousMillis2s = 0; // will store last time a 2s CAN Message was send +static unsigned long previousMillis10s = 0; // will store last time a 10s CAN Message was send +static unsigned long previousMillis60s = 0; // will store last time a 60s CAN Message was send -//Actual content messages -CAN_frame SMA_00D = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x00D, - .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; -CAN_frame SMA_00F = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x00F, - .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; -CAN_frame SMA_011 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x011, - .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; -CAN_frame SMA_013 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x013, - .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; -CAN_frame SMA_014 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x014, - .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; -CAN_frame SMA_005 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x005, - .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; -CAN_frame SMA_007 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x007, - .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; -CAN_frame SMA_006 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x006, - .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; -CAN_frame SMA_008 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x008, - .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; -CAN_frame SMA_015 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x015, - .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; -CAN_frame SMA_016 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x016, - .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; -CAN_frame SMA_017 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x017, - .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; -CAN_frame SMA_018 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x018, - .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +typedef struct { + CAN_frame* frame; + void (*callback)(); +} Frame; +static unsigned short listLength = 0; +static Frame framesToSend[20]; + +static uint32_t inverter_time = 0; +static uint16_t inverter_voltage = 0; +static int16_t inverter_current = 0; +static bool pairing_completed = false; static int16_t temperature_average = 0; static uint16_t ampere_hours_remaining = 0; -static uint16_t ampere_hours_max = 0; -static bool batteryAlarm = false; -static bool BMSevent = false; -enum BatteryState { NA, INIT, BAT_STANDBY, OPERATE, WARNING, FAULTED, UPDATE, BAT_UPDATE }; -BatteryState batteryState = OPERATE; -enum InverterControlFlags { - EMG_CHARGE_REQUEST, - EMG_DISCHARGE_REQUEST, - NOT_ENOUGH_ENERGY_FOR_START, - INVERTER_STAY_ON, - FORCED_BATTERY_SHUTDOWN, - RESERVED, - BATTERY_UPDATE_AVAILABLE, - NO_BATTERY_UPDATED_BY_INV -}; -InverterControlFlags inverterControlFlags = BATTERY_UPDATE_AVAILABLE; -enum Events0 { - START_SOC_CALIBRATE, - STOP_SOC_CALIBRATE, - START_POWERLIMIT, - STOP_POWERLIMIT, - PREVENTATIVE_BAT_SHUTDOWN, - THERMAL_MANAGEMENT, - START_BALANCING, - STOP_BALANCING -}; -Events0 events0 = START_BALANCING; -enum Events1 { START_BATTERY_SELFTEST, STOP_BATTERY_SELFTEST }; -Events1 events1 = START_BATTERY_SELFTEST; -enum Command2Battery { IDLE, RUN, NOT_USED1, NOT_USED2, SHUTDOWN, FIRMWARE_UPDATE, BATSELFUPDATE, NOT_USED3 }; -Command2Battery command2Battery = RUN; -enum InvInitState { SYSTEM_FREQUENCY, XPHASE_SYSTEM, BLACKSTART_OPERATION }; -InvInitState invInitState = SYSTEM_FREQUENCY; +//Actual content messages +CAN_frame SMA_358 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x358, + .data = {0x12, 0x40, 0x0C, 0x80, 0x01, 0x00, 0x01, 0x00}}; +CAN_frame SMA_3D8 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x3D8, + .data = {0x04, 0x06, 0x27, 0x10, 0x00, 0x19, 0x00, 0xFA}}; +CAN_frame SMA_458 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x458, + .data = {0x00, 0x00, 0x73, 0xAE, 0x00, 0x00, 0x64, 0x64}}; +CAN_frame SMA_4D8 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x4D8, + .data = {0x10, 0x62, 0x00, 0x00, 0x00, 0x78, 0x02, 0x08}}; +CAN_frame SMA_518 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x518, + .data = {0x00, 0x96, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00}}; +CAN_frame SMA_558 = {.FD = false, //Pairing first message + .ext_ID = false, + .DLC = 8, + .ID = 0x558, // BYD HVS 10.2 kWh (0x66 might be kWh) + .data = {0x03, 0x24, 0x00, 0x04, 0x00, 0x66, 0x04, 0x09}}; //Amount of modules? Vendor ID? +CAN_frame SMA_598 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x598, + .data = {0x12, 0xD6, 0x43, 0xA4, 0x00, 0x00, 0x00, 0x00}}; //B0-4 Serial 301100932 +CAN_frame SMA_5D8 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x5D8, + .data = {0x00, 0x42, 0x59, 0x44, 0x00, 0x00, 0x00, 0x00}}; //B Y D +CAN_frame SMA_618_0 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x618, + .data = {0x00, 0x42, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79}}; //BATTERY +CAN_frame SMA_618_1 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x618, + .data = {0x01, 0x2D, 0x42, 0x6F, 0x78, 0x20, 0x50, 0x72}}; //-Box Pr +CAN_frame SMA_618_2 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x618, + .data = {0x02, 0x65, 0x6D, 0x69, 0x75, 0x6D, 0x20, 0x48}}; //emium H +CAN_frame SMA_618_3 = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x618, + .data = {0x03, 0x56, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00}}; //VS void update_values_can_inverter() { //This function maps all the values fetched from battery CAN to the inverter CAN - //Calculate values - + // Update values temperature_average = ((datalayer.battery.status.temperature_max_dC + datalayer.battery.status.temperature_min_dC) / 2); - ampere_hours_remaining = - ((datalayer.battery.status.reported_remaining_capacity_Wh / datalayer.battery.status.voltage_dV) * - 100); //(WH[10000] * V+1[3600])*100 = 270 (27.0Ah) - ampere_hours_max = ((datalayer.battery.info.total_capacity_Wh / datalayer.battery.status.voltage_dV) * - 100); //(WH[10000] * V+1[3600])*100 = 270 (27.0Ah) - - batteryState = OPERATE; - inverterControlFlags = INVERTER_STAY_ON; + if (datalayer.battery.status.voltage_dV > 10) { // Only update value when we have voltage available to avoid div0 + ampere_hours_remaining = + ((datalayer.battery.status.reported_remaining_capacity_Wh / datalayer.battery.status.voltage_dV) * + 100); //(WH[10000] * V+1[3600])*100 = 270 (27.0Ah) + } //Map values to CAN messages - // Battery Limits - //Battery Max Charge Voltage (eg 400.0V = 4000 , 16bits long) - SMA_00D.data.u8[0] = (datalayer.battery.info.max_design_voltage_dV >> 8); - SMA_00D.data.u8[1] = (datalayer.battery.info.max_design_voltage_dV & 0x00FF); - //Battery Min Discharge Voltage (eg 300.0V = 3000 , 16bits long) - SMA_00D.data.u8[2] = (datalayer.battery.info.min_design_voltage_dV >> 8); - SMA_00D.data.u8[3] = (datalayer.battery.info.min_design_voltage_dV & 0x00FF); + + //Maxvoltage (eg 400.0V = 4000 , 16bits long) + SMA_358.data.u8[0] = (datalayer.battery.info.max_design_voltage_dV >> 8); + SMA_358.data.u8[1] = (datalayer.battery.info.max_design_voltage_dV & 0x00FF); + //Minvoltage (eg 300.0V = 3000 , 16bits long) + SMA_358.data.u8[2] = (datalayer.battery.info.min_design_voltage_dV >> 8); + SMA_358.data.u8[3] = (datalayer.battery.info.min_design_voltage_dV & 0x00FF); //Discharge limited current, 500 = 50A, (0.1, A) - SMA_00D.data.u8[4] = (datalayer.battery.status.max_discharge_current_dA >> 8); - SMA_00D.data.u8[5] = (datalayer.battery.status.max_discharge_current_dA & 0x00FF); + SMA_358.data.u8[4] = (datalayer.battery.status.max_discharge_current_dA >> 8); + SMA_358.data.u8[5] = (datalayer.battery.status.max_discharge_current_dA & 0x00FF); //Charge limited current, 125 =12.5A (0.1, A) - SMA_00D.data.u8[6] = (datalayer.battery.status.max_charge_current_dA >> 8); - SMA_00D.data.u8[7] = (datalayer.battery.status.max_charge_current_dA & 0x00FF); + SMA_358.data.u8[6] = (datalayer.battery.status.max_charge_current_dA >> 8); + SMA_358.data.u8[7] = (datalayer.battery.status.max_charge_current_dA & 0x00FF); - // Battery State //SOC (100.00%) - SMA_00F.data.u8[0] = (datalayer.battery.status.reported_soc >> 8); - SMA_00F.data.u8[1] = (datalayer.battery.status.reported_soc & 0x00FF); + SMA_3D8.data.u8[0] = (datalayer.battery.status.reported_soc >> 8); + SMA_3D8.data.u8[1] = (datalayer.battery.status.reported_soc & 0x00FF); //StateOfHealth (100.00%) - SMA_00F.data.u8[2] = (datalayer.battery.status.soh_pptt >> 8); - SMA_00F.data.u8[3] = (datalayer.battery.status.soh_pptt & 0x00FF); + SMA_3D8.data.u8[2] = (datalayer.battery.status.soh_pptt >> 8); + SMA_3D8.data.u8[3] = (datalayer.battery.status.soh_pptt & 0x00FF); //State of charge (AH, 0.1) - SMA_00F.data.u8[4] = (ampere_hours_remaining >> 8); - SMA_00F.data.u8[5] = (ampere_hours_remaining & 0x00FF); - //Fully charged (AH, 0.1) - SMA_00F.data.u8[6] = (ampere_hours_max >> 8); - SMA_00F.data.u8[7] = (ampere_hours_max & 0x00FF); + SMA_3D8.data.u8[4] = (ampere_hours_remaining >> 8); + SMA_3D8.data.u8[5] = (ampere_hours_remaining & 0x00FF); - // Battery Energy - //Charged Energy Counter TODO: are these needed? - //SMA_011.data.u8[0] = (X >> 8); - //SMA_011.data.u8[1] = (X & 0x00FF); - //SMA_011.data.u8[2] = (X >> 8); - //SMA_011.data.u8[3] = (X & 0x00FF); - //Discharged Energy Counter TODO: are these needed? - //SMA_011.data.u8[4] = (X >> 8); - //SMA_011.data.u8[5] = (X & 0x00FF); - //SMA_011.data.u8[6] = (X >> 8); - //SMA_011.data.u8[7] = (X & 0x00FF); - - // Battery Measurements //Voltage (370.0) - SMA_013.data.u8[0] = (datalayer.battery.status.voltage_dV >> 8); - SMA_013.data.u8[1] = (datalayer.battery.status.voltage_dV & 0x00FF); + SMA_4D8.data.u8[0] = (datalayer.battery.status.voltage_dV >> 8); + SMA_4D8.data.u8[1] = (datalayer.battery.status.voltage_dV & 0x00FF); //Current (TODO: signed OK?) - SMA_013.data.u8[2] = (datalayer.battery.status.current_dA >> 8); - SMA_013.data.u8[3] = (datalayer.battery.status.current_dA & 0x00FF); + SMA_4D8.data.u8[2] = (datalayer.battery.status.current_dA >> 8); + SMA_4D8.data.u8[3] = (datalayer.battery.status.current_dA & 0x00FF); //Temperature average - SMA_013.data.u8[4] = (temperature_average >> 8); - SMA_013.data.u8[5] = (temperature_average & 0x00FF); - //Battery state - SMA_013.data.u8[6] = batteryState; - SMA_013.data.u8[6] = inverterControlFlags; - - // Battery Temperature and Cellvoltages - // Battery max temperature - SMA_014.data.u8[0] = (datalayer.battery.status.temperature_max_dC >> 8); - SMA_014.data.u8[1] = (datalayer.battery.status.temperature_max_dC & 0x00FF); - // Battery min temperature - SMA_014.data.u8[2] = (datalayer.battery.status.temperature_min_dC >> 8); - SMA_014.data.u8[3] = (datalayer.battery.status.temperature_min_dC & 0x00FF); - // Battery Cell Voltage (sum) - //SMA_014.data.u8[4] = (??? >> 8); //TODO scaling? - //SMA_014.data.u8[5] = (??? & 0x00FF); //TODO scaling? - // Cell voltage min - //SMA_014.data.u8[6] = (??? >> 8); //TODO scaling? 0-255 - // Cell voltage max - //SMA_014.data.u8[7] = (??? >> 8); //TODO scaling? 0-255 - - //SMA_006.data.u8[0] = (ErrorCode >> 8); - //SMA_006.data.u8[1] = (ErrorCode & 0x00FF); - //SMA_006.data.u8[2] = ModuleNumber; - //SMA_006.data.u8[3] = ErrorLevel; - //SMA_008.data.u8[0] = Events0; - //SMA_008.data.u8[1] = Events1; - - //SMA_005.data.u8[0] = BMSalarms0; - //SMA_005.data.u8[1] = BMSalarms1; - //SMA_005.data.u8[2] = BMSalarms2; - //SMA_005.data.u8[3] = BMSalarms3; - //SMA_005.data.u8[4] = BMSalarms4; - //SMA_005.data.u8[5] = BMSalarms5; - //SMA_005.data.u8[6] = BMSalarms6; - //SMA_005.data.u8[7] = BMSalarms7; - - //SMA_007.data.u8[0] = DCDCalarms0; - //SMA_007.data.u8[1] = DCDCalarms1; - //SMA_007.data.u8[2] = DCDCalarms2; - //SMA_007.data.u8[3] = DCDCalarms3; - //SMA_007.data.u8[4] = DCDCwarnings0; - //SMA_007.data.u8[5] = DCDCwarnings1; - //SMA_007.data.u8[6] = DCDCwarnings2; - //SMA_007.data.u8[7] = DCDCwarnings3; - - //SMA_015.data.u8[0] = BatterySystemVersion; - //SMA_015.data.u8[1] = BatterySystemVersion; - //SMA_015.data.u8[2] = BatterySystemVersion; - //SMA_015.data.u8[3] = BatterySystemVersion; - //SMA_015.data.u8[4] = BatteryCapacity; - //SMA_015.data.u8[5] = BatteryCapacity; - //SMA_015.data.u8[6] = NumberOfModules; - //SMA_015.data.u8[7] = BatteryManufacturerID; - - //SMA_016.data.u8[0] = SerialNumber; - //SMA_016.data.u8[1] = SerialNumber; - //SMA_016.data.u8[2] = SerialNumber; - //SMA_016.data.u8[3] = SerialNumber; - //SMA_016.data.u8[4] = ManufacturingDate; - //SMA_016.data.u8[5] = ManufacturingDate; - //SMA_016.data.u8[6] = ManufacturingDate; - //SMA_016.data.u8[7] = ManufacturingDate; - - //SMA_017.data.u8[0] = Multiplex; - //SMA_017.data.u8[1] = ManufacturerName; - //SMA_017.data.u8[2] = ManufacturerName; - //SMA_017.data.u8[3] = ManufacturerName; - //SMA_017.data.u8[4] = ManufacturerName; - //SMA_017.data.u8[5] = ManufacturerName; - //SMA_017.data.u8[6] = ManufacturerName; - //SMA_017.data.u8[7] = ManufacturerName; - - //SMA_018.data.u8[0] = Multiplex; - //SMA_018.data.u8[1] = BatteryName; - //SMA_018.data.u8[2] = BatteryName; - //SMA_018.data.u8[3] = BatteryName; - //SMA_018.data.u8[4] = BatteryName; - //SMA_018.data.u8[5] = BatteryName; - //SMA_018.data.u8[6] = BatteryName; - //SMA_018.data.u8[7] = BatteryName; + SMA_4D8.data.u8[4] = (temperature_average >> 8); + SMA_4D8.data.u8[5] = (temperature_average & 0x00FF); + //Battery ready + if (datalayer.battery.status.bms_status == FAULT) { + SMA_4D8.data.u8[6] = STOP_STATE; + } else { + SMA_4D8.data.u8[6] = READY_STATE; + } } -void receive_can_inverter(CAN_frame rx_frame) { +void map_can_frame_to_variable_inverter(CAN_frame rx_frame) { switch (rx_frame.ID) { - case 0x00D: //Inverter Measurements + case 0x360: //Message originating from SMA inverter - Voltage and current + datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; + inverter_voltage = (rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]; + inverter_current = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + break; + case 0x3E0: //Message originating from SMA inverter - ? datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; break; - case 0x00F: //Inverter Feedback + case 0x420: //Message originating from SMA inverter - Timestamp + datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; + inverter_time = + (rx_frame.data.u8[0] << 24) | (rx_frame.data.u8[1] << 16) | (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + break; + case 0x560: //Message originating from SMA inverter - Init datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; break; - case 0x010: //Time from inverter + case 0x5E0: //Message originating from SMA inverter - String datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; + //Inverter brand (frame1-3 = 0x53 0x4D 0x41) = SMA break; - case 0x015: //Initialization message from inverter + case 0x660: //Message originating from SMA inverter - Pairing request datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; - send_tripower_init(); - break; - case 0x017: //Initialization message from inverter 2 - datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; - //send_tripower_init(); + transmit_can_init(); break; default: break; } } -void send_can_inverter() { +void pushFrame(CAN_frame* frame, void (*callback)() = NULL) { + if (listLength >= 20) { + return; //TODO: scream. + } + framesToSend[listLength] = { + .frame = frame, + .callback = callback, + }; + listLength++; +} + +void transmit_can_inverter() { unsigned long currentMillis = millis(); - // Send CAN Message every 500ms - if (currentMillis - previousMillis500ms >= INTERVAL_500_MS) { - previousMillis500ms = currentMillis; - - transmit_can(&SMA_00D, can_config.inverter); //Battery limits - transmit_can(&SMA_00F, can_config.inverter); // Battery state - transmit_can(&SMA_011, can_config.inverter); // Battery Energy - transmit_can(&SMA_013, can_config.inverter); // Battery Measurements - transmit_can(&SMA_014, can_config.inverter); // Battery Temperatures and cellvoltages + // Send CAN Message only if we're enabled by inverter + if (!datalayer.system.status.inverter_allows_contactor_closing) { + return; } - if (batteryAlarm) { //Non-cyclic - transmit_can(&SMA_005, can_config.inverter); // Battery Alarms 1 - transmit_can(&SMA_007, can_config.inverter); // Battery Alarms 2 + if (listLength > 0 && currentMillis - previousMillis250ms >= INTERVAL_250_MS) { + previousMillis250ms = currentMillis; + // Send next frame. + Frame frame = framesToSend[0]; + transmit_can_frame(frame.frame, can_config.inverter); + if (frame.callback != NULL) { + frame.callback(); + } + for (int i = 0; i < listLength - 1; i++) { + framesToSend[i] = framesToSend[i + 1]; + } + listLength--; } - if (BMSevent) { //Non-cyclic - transmit_can(&SMA_006, can_config.inverter); // Battery Errorcode - transmit_can(&SMA_008, can_config.inverter); // Battery Events + if (!pairing_completed) { + return; + } + + // Send CAN Message every 2s + if (currentMillis - previousMillis2s >= INTERVAL_2_S) { + previousMillis2s = currentMillis; + pushFrame(&SMA_358); + } + // Send CAN Message every 10s + if (currentMillis - previousMillis10s >= INTERVAL_10_S) { + previousMillis10s = currentMillis; + pushFrame(&SMA_518); + pushFrame(&SMA_4D8); + pushFrame(&SMA_3D8); } } -void send_tripower_init() { - transmit_can(&SMA_015, can_config.inverter); // Battery Data 1 - transmit_can(&SMA_016, can_config.inverter); // Battery Data 2 - transmit_can(&SMA_017, can_config.inverter); // Battery Manufacturer - transmit_can(&SMA_018, can_config.inverter); // Battery Name +void completePairing() { + pairing_completed = true; +} + +void transmit_can_init() { + listLength = 0; // clear all frames + + pushFrame(&SMA_558); //Pairing start - Vendor + pushFrame(&SMA_598); //Serial + pushFrame(&SMA_5D8); //BYD + pushFrame(&SMA_618_0); //BATTERY + pushFrame(&SMA_618_1); //-Box Pr + pushFrame(&SMA_618_2); //emium H + pushFrame(&SMA_618_3); //VS + pushFrame(&SMA_358); + pushFrame(&SMA_3D8); + pushFrame(&SMA_458); + pushFrame(&SMA_4D8); + pushFrame(&SMA_518, completePairing); } void setup_inverter(void) { // Performs one time setup at startup over CAN bus strncpy(datalayer.system.info.inverter_protocol, "SMA Tripower CAN", 63); datalayer.system.info.inverter_protocol[63] = '\0'; + datalayer.system.status.inverter_allows_contactor_closing = false; // The inverter needs to allow first + pinMode(INVERTER_CONTACTOR_ENABLE_PIN, INPUT); +#ifdef INVERTER_CONTACTOR_ENABLE_LED_PIN + pinMode(INVERTER_CONTACTOR_ENABLE_LED_PIN, OUTPUT); + digitalWrite(INVERTER_CONTACTOR_ENABLE_LED_PIN, LOW); // Turn LED off, until inverter allows contactor closing +#endif // INVERTER_CONTACTOR_ENABLE_LED_PIN } + #endif diff --git a/Software/src/inverter/SMA-TRIPOWER-CAN.h b/Software/src/inverter/SMA-TRIPOWER-CAN.h index 90967001..d868fbb1 100644 --- a/Software/src/inverter/SMA-TRIPOWER-CAN.h +++ b/Software/src/inverter/SMA-TRIPOWER-CAN.h @@ -4,8 +4,11 @@ #define CAN_INVERTER_SELECTED -void send_tripower_init(); -void transmit_can(CAN_frame* tx_frame, int interface); +#define READY_STATE 0x03 +#define STOP_STATE 0x02 + +void transmit_can_frame(CAN_frame* tx_frame, int interface); +void transmit_can_init(); void setup_inverter(void); #endif diff --git a/Software/src/inverter/SOFAR-CAN.cpp b/Software/src/inverter/SOFAR-CAN.cpp index 838ebf93..bd6916dd 100644 --- a/Software/src/inverter/SOFAR-CAN.cpp +++ b/Software/src/inverter/SOFAR-CAN.cpp @@ -230,7 +230,7 @@ void update_values_can_inverter() { //This function maps all the values fetched SOFAR_356.data.u8[3] = (datalayer.battery.status.temperature_max_dC & 0x00FF); } -void receive_can_inverter(CAN_frame rx_frame) { +void map_can_frame_to_variable_inverter(CAN_frame rx_frame) { switch (rx_frame.ID) { //In here we need to respond to the inverter. TODO: make logic case 0x605: datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; @@ -247,20 +247,20 @@ void receive_can_inverter(CAN_frame rx_frame) { } } -void send_can_inverter() { +void transmit_can_inverter() { unsigned long currentMillis = millis(); // Send 100ms CAN Message if (currentMillis - previousMillis100 >= INTERVAL_100_MS) { previousMillis100 = currentMillis; //Frames actively reported by BMS - transmit_can(&SOFAR_351, can_config.inverter); - transmit_can(&SOFAR_355, can_config.inverter); - transmit_can(&SOFAR_356, can_config.inverter); - transmit_can(&SOFAR_30F, can_config.inverter); - transmit_can(&SOFAR_359, can_config.inverter); - transmit_can(&SOFAR_35E, can_config.inverter); - transmit_can(&SOFAR_35F, can_config.inverter); - transmit_can(&SOFAR_35A, can_config.inverter); + transmit_can_frame(&SOFAR_351, can_config.inverter); + transmit_can_frame(&SOFAR_355, can_config.inverter); + transmit_can_frame(&SOFAR_356, can_config.inverter); + transmit_can_frame(&SOFAR_30F, can_config.inverter); + transmit_can_frame(&SOFAR_359, can_config.inverter); + transmit_can_frame(&SOFAR_35E, can_config.inverter); + transmit_can_frame(&SOFAR_35F, can_config.inverter); + transmit_can_frame(&SOFAR_35A, can_config.inverter); } } diff --git a/Software/src/inverter/SOFAR-CAN.h b/Software/src/inverter/SOFAR-CAN.h index 7a80bf62..dfbe2ef7 100644 --- a/Software/src/inverter/SOFAR-CAN.h +++ b/Software/src/inverter/SOFAR-CAN.h @@ -4,7 +4,7 @@ #define CAN_INVERTER_SELECTED -void transmit_can(CAN_frame* tx_frame, int interface); +void transmit_can_frame(CAN_frame* tx_frame, int interface); void setup_inverter(void); #endif diff --git a/Software/src/inverter/SOLAX-CAN.cpp b/Software/src/inverter/SOLAX-CAN.cpp index da036517..e4aa6274 100644 --- a/Software/src/inverter/SOLAX-CAN.cpp +++ b/Software/src/inverter/SOLAX-CAN.cpp @@ -68,7 +68,7 @@ CAN_frame SOLAX_187E = {.FD = false, //Needed for Ultra .ext_ID = true, .DLC = 8, .ID = 0x187E, - .data = {0x0, 0x2D, 0x0, 0x0, 0x0, 0x5F, 0x0, 0x0}}; + .data = {0x60, 0xEA, 0x0, 0x0, 0x64, 0x0, 0x0, 0x0}}; CAN_frame SOLAX_187D = {.FD = false, //Needed for Ultra .ext_ID = true, .DLC = 8, @@ -88,7 +88,7 @@ CAN_frame SOLAX_187A = {.FD = false, //Needed for Ultra .ext_ID = true, .DLC = 8, .ID = 0x187A, - .data = {0x01, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}; + .data = {0x01, 0x50, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}; CAN_frame SOLAX_1881 = {.FD = false, .ext_ID = true, .DLC = 8, @@ -190,13 +190,20 @@ void update_values_can_inverter() { //This function maps all the values fetched SOLAX_1801.data.u8[0] = 2; SOLAX_1801.data.u8[2] = 1; SOLAX_1801.data.u8[4] = 1; + + //Ultra messages + SOLAX_187E.data.u8[0] = (uint8_t)capped_remaining_capacity_Wh; + SOLAX_187E.data.u8[1] = (capped_remaining_capacity_Wh >> 8); + SOLAX_187E.data.u8[2] = 0; + SOLAX_187E.data.u8[3] = 0; + SOLAX_187E.data.u8[5] = (uint8_t)(datalayer.battery.status.reported_soc / 100); } -void send_can_inverter() { +void transmit_can_inverter() { // No periodic sending used on this protocol, we react only on incoming CAN messages! } -void receive_can_inverter(CAN_frame rx_frame) { +void map_can_frame_to_variable_inverter(CAN_frame rx_frame) { if (rx_frame.ID == 0x1871) { datalayer.system.status.CAN_inverter_still_alive = CAN_STILL_ALIVE; @@ -207,21 +214,23 @@ void receive_can_inverter(CAN_frame rx_frame) { LastFrameTime = millis(); switch (STATE) { case (BATTERY_ANNOUNCE): -#ifdef DEBUG_VIA_USB - Serial.println("Solax Battery State: Announce"); +#ifdef DEBUG_LOG + logging.println("Solax Battery State: Announce"); #endif datalayer.system.status.inverter_allows_contactor_closing = false; SOLAX_1875.data.u8[4] = (0x00); // Inform Inverter: Contactor 0=off, 1=on. - for (int i = 0; i <= number_of_batteries; i++) { - transmit_can(&SOLAX_1872, can_config.inverter); - transmit_can(&SOLAX_1873, can_config.inverter); - transmit_can(&SOLAX_1874, can_config.inverter); - transmit_can(&SOLAX_1875, can_config.inverter); - transmit_can(&SOLAX_1876, can_config.inverter); - transmit_can(&SOLAX_1877, can_config.inverter); - transmit_can(&SOLAX_1878, can_config.inverter); + for (uint8_t i = 0; i <= number_of_batteries; i++) { + transmit_can_frame(&SOLAX_187E, can_config.inverter); + transmit_can_frame(&SOLAX_187A, can_config.inverter); + transmit_can_frame(&SOLAX_1872, can_config.inverter); + transmit_can_frame(&SOLAX_1873, can_config.inverter); + transmit_can_frame(&SOLAX_1874, can_config.inverter); + transmit_can_frame(&SOLAX_1875, can_config.inverter); + transmit_can_frame(&SOLAX_1876, can_config.inverter); + transmit_can_frame(&SOLAX_1877, can_config.inverter); + transmit_can_frame(&SOLAX_1878, can_config.inverter); } - transmit_can(&SOLAX_100A001, can_config.inverter); //BMS Announce + transmit_can_frame(&SOLAX_100A001, can_config.inverter); //BMS Announce // Message from the inverter to proceed to contactor closing // Byte 4 changes from 0 to 1 if (rx_frame.data.u64 == Contactor_Close_Payload) @@ -230,30 +239,34 @@ void receive_can_inverter(CAN_frame rx_frame) { case (WAITING_FOR_CONTACTOR): SOLAX_1875.data.u8[4] = (0x00); // Inform Inverter: Contactor 0=off, 1=on. - transmit_can(&SOLAX_1872, can_config.inverter); - transmit_can(&SOLAX_1873, can_config.inverter); - transmit_can(&SOLAX_1874, can_config.inverter); - transmit_can(&SOLAX_1875, can_config.inverter); - transmit_can(&SOLAX_1876, can_config.inverter); - transmit_can(&SOLAX_1877, can_config.inverter); - transmit_can(&SOLAX_1878, can_config.inverter); - transmit_can(&SOLAX_1801, can_config.inverter); // Announce that the battery will be connected - STATE = CONTACTOR_CLOSED; // Jump to Contactor Closed State -#ifdef DEBUG_VIA_USB - Serial.println("Solax Battery State: Contactor Closed"); + transmit_can_frame(&SOLAX_187E, can_config.inverter); + transmit_can_frame(&SOLAX_187A, can_config.inverter); + transmit_can_frame(&SOLAX_1872, can_config.inverter); + transmit_can_frame(&SOLAX_1873, can_config.inverter); + transmit_can_frame(&SOLAX_1874, can_config.inverter); + transmit_can_frame(&SOLAX_1875, can_config.inverter); + transmit_can_frame(&SOLAX_1876, can_config.inverter); + transmit_can_frame(&SOLAX_1877, can_config.inverter); + transmit_can_frame(&SOLAX_1878, can_config.inverter); + transmit_can_frame(&SOLAX_1801, can_config.inverter); // Announce that the battery will be connected + STATE = CONTACTOR_CLOSED; // Jump to Contactor Closed State +#ifdef DEBUG_LOG + logging.println("Solax Battery State: Contactor Closed"); #endif break; case (CONTACTOR_CLOSED): datalayer.system.status.inverter_allows_contactor_closing = true; SOLAX_1875.data.u8[4] = (0x01); // Inform Inverter: Contactor 0=off, 1=on. - transmit_can(&SOLAX_1872, can_config.inverter); - transmit_can(&SOLAX_1873, can_config.inverter); - transmit_can(&SOLAX_1874, can_config.inverter); - transmit_can(&SOLAX_1875, can_config.inverter); - transmit_can(&SOLAX_1876, can_config.inverter); - transmit_can(&SOLAX_1877, can_config.inverter); - transmit_can(&SOLAX_1878, can_config.inverter); + transmit_can_frame(&SOLAX_187E, can_config.inverter); + transmit_can_frame(&SOLAX_187A, can_config.inverter); + transmit_can_frame(&SOLAX_1872, can_config.inverter); + transmit_can_frame(&SOLAX_1873, can_config.inverter); + transmit_can_frame(&SOLAX_1874, can_config.inverter); + transmit_can_frame(&SOLAX_1875, can_config.inverter); + transmit_can_frame(&SOLAX_1876, can_config.inverter); + transmit_can_frame(&SOLAX_1877, can_config.inverter); + transmit_can_frame(&SOLAX_1878, can_config.inverter); // Message from the inverter to open contactor // Byte 4 changes from 1 to 0 if (rx_frame.data.u64 == Contactor_Open_Payload) { @@ -265,15 +278,15 @@ void receive_can_inverter(CAN_frame rx_frame) { } if (rx_frame.ID == 0x1871 && rx_frame.data.u64 == __builtin_bswap64(0x0500010000000000)) { - transmit_can(&SOLAX_1881, can_config.inverter); - transmit_can(&SOLAX_1882, can_config.inverter); -#ifdef DEBUG_VIA_USB - Serial.println("1871 05-frame received from inverter"); + transmit_can_frame(&SOLAX_1881, can_config.inverter); + transmit_can_frame(&SOLAX_1882, can_config.inverter); +#ifdef DEBUG_LOG + logging.println("1871 05-frame received from inverter"); #endif } if (rx_frame.ID == 0x1871 && rx_frame.data.u8[0] == (0x03)) { -#ifdef DEBUG_VIA_USB - Serial.println("1871 03-frame received from inverter"); +#ifdef DEBUG_LOG + logging.println("1871 03-frame received from inverter"); #endif } } @@ -281,12 +294,5 @@ void setup_inverter(void) { // Performs one time setup at startup strncpy(datalayer.system.info.inverter_protocol, "SolaX Triple Power LFP over CAN bus", 63); datalayer.system.info.inverter_protocol[63] = '\0'; datalayer.system.status.inverter_allows_contactor_closing = false; // The inverter needs to allow first - - // Sending these messages once towards the inverter makes SOC% work on the Ultra variant - transmit_can(&SOLAX_187E, can_config.inverter); - transmit_can(&SOLAX_187D, can_config.inverter); - transmit_can(&SOLAX_187C, can_config.inverter); - transmit_can(&SOLAX_187B, can_config.inverter); - transmit_can(&SOLAX_187A, can_config.inverter); } #endif diff --git a/Software/src/inverter/SOLAX-CAN.h b/Software/src/inverter/SOLAX-CAN.h index 68373ec2..614e4245 100644 --- a/Software/src/inverter/SOLAX-CAN.h +++ b/Software/src/inverter/SOLAX-CAN.h @@ -14,7 +14,7 @@ #define FAULT_SOLAX 3 #define UPDATING_FW 4 -void transmit_can(CAN_frame* tx_frame, int interface); +void transmit_can_frame(CAN_frame* tx_frame, int interface); void setup_inverter(void); #endif diff --git a/Software/src/lib/ayushsharma82-ElegantOTA/src/ElegantOTA.h b/Software/src/lib/ayushsharma82-ElegantOTA/src/ElegantOTA.h index 48833d99..f8770a07 100644 --- a/Software/src/lib/ayushsharma82-ElegantOTA/src/ElegantOTA.h +++ b/Software/src/lib/ayushsharma82-ElegantOTA/src/ElegantOTA.h @@ -64,7 +64,7 @@ _____ _ _ ___ _____ _ #include "Update.h" #include "StreamString.h" #if ELEGANTOTA_USE_ASYNC_WEBSERVER == 1 - #include "../../mathieucarbou-AsyncTCP/src/AsyncTCP.h" + #include "../../me-no-dev-AsyncTCP/src/AsyncTCP.h" #include "../../me-no-dev-ESPAsyncWebServer/src/ESPAsyncWebServer.h" #define ELEGANTOTA_WEBSERVER AsyncWebServer #else diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/CODE_OF_CONDUCT.md b/Software/src/lib/mathieucarbou-AsyncTCP/CODE_OF_CONDUCT.md deleted file mode 100644 index 0a5f9141..00000000 --- a/Software/src/lib/mathieucarbou-AsyncTCP/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,129 +0,0 @@ - -# Contributor Covenant Code of Conduct - -## Our Pledge - -We as members, contributors, and leaders pledge to make participation in our -community a harassment-free experience for everyone, regardless of age, body -size, visible or invisible disability, ethnicity, sex characteristics, gender -identity and expression, level of experience, education, socio-economic status, -nationality, personal appearance, race, religion, or sexual identity -and orientation. - -We pledge to act and interact in ways that contribute to an open, welcoming, -diverse, inclusive, and healthy community. - -## Our Standards - -Examples of behavior that contributes to a positive environment for our -community include: - -* Demonstrating empathy and kindness toward other people -* Being respectful of differing opinions, viewpoints, and experiences -* Giving and gracefully accepting constructive feedback -* Accepting responsibility and apologizing to those affected by our mistakes, - and learning from the experience -* Focusing on what is best not just for us as individuals, but for the - overall community - -Examples of unacceptable behavior include: - -* The use of sexualized language or imagery, and sexual attention or - advances of any kind -* Trolling, insulting or derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or email - address, without their explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Enforcement Responsibilities - -Community leaders are responsible for clarifying and enforcing our standards of -acceptable behavior and will take appropriate and fair corrective action in -response to any behavior that they deem inappropriate, threatening, offensive, -or harmful. - -Community leaders have the right and responsibility to remove, edit, or reject -comments, commits, code, wiki edits, issues, and other contributions that are -not aligned to this Code of Conduct, and will communicate reasons for moderation -decisions when appropriate. - -## Scope - -This Code of Conduct applies within all community spaces, and also applies when -an individual is officially representing the community in public spaces. -Examples of representing our community include using an official e-mail address, -posting via an official social media account, or acting as an appointed -representative at an online or offline event. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported to the community leaders responsible for enforcement at -https://sidweb.nl/cms3/en/contact. -All complaints will be reviewed and investigated promptly and fairly. - -All community leaders are obligated to respect the privacy and security of the -reporter of any incident. - -## Enforcement Guidelines - -Community leaders will follow these Community Impact Guidelines in determining -the consequences for any action they deem in violation of this Code of Conduct: - -### 1. Correction - -**Community Impact**: Use of inappropriate language or other behavior deemed -unprofessional or unwelcome in the community. - -**Consequence**: A private, written warning from community leaders, providing -clarity around the nature of the violation and an explanation of why the -behavior was inappropriate. A public apology may be requested. - -### 2. Warning - -**Community Impact**: A violation through a single incident or series -of actions. - -**Consequence**: A warning with consequences for continued behavior. No -interaction with the people involved, including unsolicited interaction with -those enforcing the Code of Conduct, for a specified period of time. This -includes avoiding interactions in community spaces as well as external channels -like social media. Violating these terms may lead to a temporary or -permanent ban. - -### 3. Temporary Ban - -**Community Impact**: A serious violation of community standards, including -sustained inappropriate behavior. - -**Consequence**: A temporary ban from any sort of interaction or public -communication with the community for a specified period of time. No public or -private interaction with the people involved, including unsolicited interaction -with those enforcing the Code of Conduct, is allowed during this period. -Violating these terms may lead to a permanent ban. - -### 4. Permanent Ban - -**Community Impact**: Demonstrating a pattern of violation of community -standards, including sustained inappropriate behavior, harassment of an -individual, or aggression toward or disparagement of classes of individuals. - -**Consequence**: A permanent ban from any sort of public interaction within -the community. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], -version 2.0, available at -https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. - -Community Impact Guidelines were inspired by [Mozilla's code of conduct -enforcement ladder](https://github.com/mozilla/diversity). - -[homepage]: https://www.contributor-covenant.org - -For answers to common questions about this code of conduct, see the FAQ at -https://www.contributor-covenant.org/faq. Translations are available at -https://www.contributor-covenant.org/translations. diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/README.md b/Software/src/lib/mathieucarbou-AsyncTCP/README.md deleted file mode 100644 index d90814a1..00000000 --- a/Software/src/lib/mathieucarbou-AsyncTCP/README.md +++ /dev/null @@ -1,62 +0,0 @@ -# AsyncTCP - -[![License: LGPL 3.0](https://img.shields.io/badge/License-LGPL%203.0-yellow.svg)](https://opensource.org/license/lgpl-3-0/) -[![Continuous Integration](https://github.com/mathieucarbou/AsyncTCP/actions/workflows/ci.yml/badge.svg)](https://github.com/mathieucarbou/AsyncTCP/actions/workflows/ci.yml) -[![PlatformIO Registry](https://badges.registry.platformio.org/packages/mathieucarbou/library/AsyncTCP.svg)](https://registry.platformio.org/libraries/mathieucarbou/AsyncTCP) - -A fork of the [AsyncTCP](https://github.com/me-no-dev/AsyncTCP) library by [@me-no-dev](https://github.com/me-no-dev). - -### Async TCP Library for ESP32 Arduino - -This is a fully asynchronous TCP library, aimed at enabling trouble-free, multi-connection network environment for Espressif's ESP32 MCUs. - -This library is the base for [ESPAsyncWebServer](https://github.com/mathieucarbou/ESPAsyncWebServer) - -## AsyncClient and AsyncServer - -The base classes on which everything else is built. They expose all possible scenarios, but are really raw and require more skills to use. - -## Changes in this fork - -- Based on [ESPHome fork](https://github.com/esphome/AsyncTCP) - -- `library.properties` for Arduino IDE users -- Add `CONFIG_ASYNC_TCP_MAX_ACK_TIME` -- Add `CONFIG_ASYNC_TCP_PRIORITY` -- Add `CONFIG_ASYNC_TCP_QUEUE_SIZE` -- Add `setKeepAlive()` -- Arduino 3 / ESP-IDF 5 compatibility -- Better CI -- Better example -- Customizable macros -- Fix for "Required to lock TCPIP core functionality". Ref: https://github.com/mathieucarbou/AsyncTCP/issues/27 and https://github.com/espressif/arduino-esp32/issues/10526 -- Fix for "ack timeout 4" client disconnects. -- Fix from https://github.com/me-no-dev/AsyncTCP/pull/173 (partially applied) -- Fix from https://github.com/me-no-dev/AsyncTCP/pull/184 -- IPv6 -- LIBRETINY support -- LibreTuya -- Reduce logging of non critical messages -- Use IPADDR6_INIT() macro to set connecting IPv6 address -- xTaskCreateUniversal function - -## Coordinates - -``` -mathieucarbou/AsyncTCP @ ^3.3.1 -``` - -## Important recommendations - -Most of the crashes are caused by improper configuration of the library for the project. -Here are some recommendations to avoid them. - -I personally use the following configuration in my projects: - -```c++ - -D CONFIG_ASYNC_TCP_MAX_ACK_TIME=5000 // (keep default) - -D CONFIG_ASYNC_TCP_PRIORITY=10 // (keep default) - -D CONFIG_ASYNC_TCP_QUEUE_SIZE=64 // (keep default) - -D CONFIG_ASYNC_TCP_RUNNING_CORE=1 // force async_tcp task to be on same core as the app (default is core 0) - -D CONFIG_ASYNC_TCP_STACK_SIZE=4096 // reduce the stack size (default is 16K) -``` diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/library.json b/Software/src/lib/mathieucarbou-AsyncTCP/library.json deleted file mode 100644 index 5d6e228b..00000000 --- a/Software/src/lib/mathieucarbou-AsyncTCP/library.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "name": "AsyncTCP", - "version": "3.3.1", - "description": "Asynchronous TCP Library for ESP32", - "keywords": "async,tcp", - "repository": { - "type": "git", - "url": "https://github.com/mathieucarbou/AsyncTCP.git" - }, - "authors": [ - { - "name": "Hristo Gochkov" - }, - { - "name": "Mathieu Carbou", - "maintainer": true - } - ], - "license": "LGPL-3.0", - "frameworks": "arduino", - "platforms": [ - "espressif32", - "libretiny" - ], - "build": { - "libCompatMode": 2 - }, - "export": { - "include": [ - "examples", - "src", - "library.json", - "library.properties", - "LICENSE", - "README.md" - ] - } -} \ No newline at end of file diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/library.properties b/Software/src/lib/mathieucarbou-AsyncTCP/library.properties deleted file mode 100644 index dd945f8d..00000000 --- a/Software/src/lib/mathieucarbou-AsyncTCP/library.properties +++ /dev/null @@ -1,10 +0,0 @@ -name=Async TCP -includes=AsyncTCP.h -version=3.3.1 -author=Me-No-Dev -maintainer=Mathieu Carbou -sentence=Async TCP Library for ESP32 -paragraph=Async TCP Library for ESP32 -category=Other -url=https://github.com/mathieucarbou/AsyncTCP.git -architectures=* diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/platformio.ini b/Software/src/lib/mathieucarbou-AsyncTCP/platformio.ini deleted file mode 100644 index ec65a367..00000000 --- a/Software/src/lib/mathieucarbou-AsyncTCP/platformio.ini +++ /dev/null @@ -1,43 +0,0 @@ -[platformio] -default_envs = arduino-2, arduino-3, arduino-310 -lib_dir = . -src_dir = examples/Client - -[env] -framework = arduino -build_flags = - -Wall -Wextra - -D CONFIG_ASYNC_TCP_MAX_ACK_TIME=5000 - -D CONFIG_ASYNC_TCP_PRIORITY=10 - -D CONFIG_ASYNC_TCP_QUEUE_SIZE=64 - -D CONFIG_ASYNC_TCP_RUNNING_CORE=1 - -D CONFIG_ASYNC_TCP_STACK_SIZE=4096 - -D CONFIG_ARDUHAL_LOG_COLORS - -D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG -upload_protocol = esptool -monitor_speed = 115200 -monitor_filters = esp32_exception_decoder, log2file -board = esp32dev - -[env:arduino-2] -platform = espressif32@6.9.0 - -[env:arduino-3] -platform = https://github.com/pioarduino/platform-espressif32/releases/download/51.03.05/platform-espressif32.zip - -[env:arduino-310] -platform = https://github.com/pioarduino/platform-espressif32/releases/download/53.03.10-rc3/platform-espressif32.zip - -; CI - -[env:ci-arduino-2] -platform = espressif32@6.9.0 -board = ${sysenv.PIO_BOARD} - -[env:ci-arduino-3] -platform = https://github.com/pioarduino/platform-espressif32/releases/download/51.03.05/platform-espressif32.zip -board = ${sysenv.PIO_BOARD} - -[env:ci-arduino-310] -platform = https://github.com/pioarduino/platform-espressif32/releases/download/53.03.10-rc3/platform-espressif32.zip -board = ${sysenv.PIO_BOARD} diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/src/AsyncTCP.cpp b/Software/src/lib/mathieucarbou-AsyncTCP/src/AsyncTCP.cpp deleted file mode 100644 index 9addb135..00000000 --- a/Software/src/lib/mathieucarbou-AsyncTCP/src/AsyncTCP.cpp +++ /dev/null @@ -1,1661 +0,0 @@ -/* - Asynchronous TCP library for Espressif MCUs - - Copyright (c) 2016 Hristo Gochkov. All rights reserved. - This file is part of the esp8266 core for Arduino environment. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "Arduino.h" - -#include "AsyncTCP.h" - -extern "C" { -#include "lwip/dns.h" -#include "lwip/err.h" -#include "lwip/inet.h" -#include "lwip/opt.h" -#include "lwip/tcp.h" -} - -#if CONFIG_ASYNC_TCP_USE_WDT - #include "esp_task_wdt.h" -#endif - -// Required for: -// https://github.com/espressif/arduino-esp32/blob/3.0.3/libraries/Network/src/NetworkInterface.cpp#L37-L47 -#if ESP_IDF_VERSION_MAJOR >= 5 - #include -#endif - -#define TAG "AsyncTCP" - -// https://github.com/espressif/arduino-esp32/issues/10526 -#ifdef CONFIG_LWIP_TCPIP_CORE_LOCKING - #define TCP_MUTEX_LOCK() \ - if (!sys_thread_tcpip(LWIP_CORE_LOCK_QUERY_HOLDER)) { \ - LOCK_TCPIP_CORE(); \ - } - - #define TCP_MUTEX_UNLOCK() \ - if (sys_thread_tcpip(LWIP_CORE_LOCK_QUERY_HOLDER)) { \ - UNLOCK_TCPIP_CORE(); \ - } -#else // CONFIG_LWIP_TCPIP_CORE_LOCKING - #define TCP_MUTEX_LOCK() - #define TCP_MUTEX_UNLOCK() -#endif // CONFIG_LWIP_TCPIP_CORE_LOCKING - -#define INVALID_CLOSED_SLOT -1 - -/* - TCP poll interval is specified in terms of the TCP coarse timer interval, which is called twice a second - https://github.com/espressif/esp-lwip/blob/2acf959a2bb559313cd2bf9306c24612ba3d0e19/src/core/tcp.c#L1895 -*/ -#define CONFIG_ASYNC_TCP_POLL_TIMER 1 - -/* - * TCP/IP Event Task - * */ - -typedef enum { - LWIP_TCP_SENT, - LWIP_TCP_RECV, - LWIP_TCP_FIN, - LWIP_TCP_ERROR, - LWIP_TCP_POLL, - LWIP_TCP_CLEAR, - LWIP_TCP_ACCEPT, - LWIP_TCP_CONNECTED, - LWIP_TCP_DNS -} lwip_event_t; - -typedef struct { - lwip_event_t event; - void* arg; - union { - struct { - tcp_pcb* pcb; - int8_t err; - } connected; - struct { - int8_t err; - } error; - struct { - tcp_pcb* pcb; - uint16_t len; - } sent; - struct { - tcp_pcb* pcb; - pbuf* pb; - int8_t err; - } recv; - struct { - tcp_pcb* pcb; - int8_t err; - } fin; - struct { - tcp_pcb* pcb; - } poll; - struct { - AsyncClient* client; - } accept; - struct { - const char* name; - ip_addr_t addr; - } dns; - }; -} lwip_event_packet_t; - -static QueueHandle_t _async_queue; -static TaskHandle_t _async_service_task_handle = NULL; - -SemaphoreHandle_t _slots_lock; -const int _number_of_closed_slots = CONFIG_LWIP_MAX_ACTIVE_TCP; -static uint32_t _closed_slots[_number_of_closed_slots]; -static uint32_t _closed_index = []() { - _slots_lock = xSemaphoreCreateBinary(); - xSemaphoreGive(_slots_lock); - for (int i = 0; i < _number_of_closed_slots; ++i) { - _closed_slots[i] = 1; - } - return 1; -}(); - -static inline bool _init_async_event_queue() { - if (!_async_queue) { - _async_queue = xQueueCreate(CONFIG_ASYNC_TCP_QUEUE_SIZE, sizeof(lwip_event_packet_t*)); - if (!_async_queue) { - return false; - } - } - return true; -} - -static inline bool _send_async_event(lwip_event_packet_t** e, TickType_t wait = portMAX_DELAY) { - return _async_queue && xQueueSend(_async_queue, e, wait) == pdPASS; -} - -static inline bool _prepend_async_event(lwip_event_packet_t** e, TickType_t wait = portMAX_DELAY) { - return _async_queue && xQueueSendToFront(_async_queue, e, wait) == pdPASS; -} - -static inline bool _get_async_event(lwip_event_packet_t** e) { - if (!_async_queue) { - return false; - } - -#if CONFIG_ASYNC_TCP_USE_WDT - // need to return periodically to feed the dog - if (xQueueReceive(_async_queue, e, pdMS_TO_TICKS(1000)) != pdPASS) - return false; -#else - if (xQueueReceive(_async_queue, e, portMAX_DELAY) != pdPASS) - return false; -#endif - - if ((*e)->event != LWIP_TCP_POLL) - return true; - - /* - Let's try to coalesce two (or more) consecutive poll events into one - this usually happens with poor implemented user-callbacks that are runs too long and makes poll events to stack in the queue - if consecutive user callback for a same connection runs longer that poll time then it will fill the queue with events until it deadlocks. - This is a workaround to mitigate such poor designs and won't let other events/connections to starve the task time. - It won't be effective if user would run multiple simultaneous long running callbacks due to message interleaving. - todo: implement some kind of fair dequeing or (better) simply punish user for a bad designed callbacks by resetting hog connections - */ - lwip_event_packet_t* next_pkt = NULL; - while (xQueuePeek(_async_queue, &next_pkt, 0) == pdPASS) { - if (next_pkt->arg == (*e)->arg && next_pkt->event == LWIP_TCP_POLL) { - if (xQueueReceive(_async_queue, &next_pkt, 0) == pdPASS) { - free(next_pkt); - next_pkt = NULL; - log_d("coalescing polls, network congestion or async callbacks might be too slow!"); - continue; - } - } - - // quit while loop if next event can't be discarded - break; - } - - /* - now we have to decide if to proceed with poll callback handler or discard it? - poor designed apps using asynctcp without proper dataflow control could flood the queue with interleaved pool/ack events. - I.e. on each poll app would try to generate more data to send, which in turn results in additional ack event triggering chain effect - for long connections. Or poll callback could take long time starving other connections. Anyway our goal is to keep the queue length - grows under control (if possible) and poll events are the safest to discard. - Let's discard poll events processing using linear-increasing probability curve when queue size grows over 3/4 - Poll events are periodic and connection could get another chance next time - */ - if (uxQueueMessagesWaiting(_async_queue) > (rand() % CONFIG_ASYNC_TCP_QUEUE_SIZE / 4 + CONFIG_ASYNC_TCP_QUEUE_SIZE * 3 / 4)) { - free(*e); - *e = NULL; - log_d("discarding poll due to queue congestion"); - // evict next event from a queue - return _get_async_event(e); - } - - // last resort return - return true; -} - -static bool _remove_events_with_arg(void* arg) { - if (!_async_queue) { - return false; - } - - lwip_event_packet_t* first_packet = NULL; - lwip_event_packet_t* packet = NULL; - - // figure out which is the first non-matching packet so we can keep the order - while (!first_packet) { - if (xQueueReceive(_async_queue, &first_packet, 0) != pdPASS) { - return false; - } - // discard packet if matching - if ((int)first_packet->arg == (int)arg) { - free(first_packet); - first_packet = NULL; - } else if (xQueueSend(_async_queue, &first_packet, 0) != pdPASS) { - // try to return first packet to the back of the queue - // we can't wait here if queue is full, because this call has been done from the only consumer task of this queue - // otherwise it would deadlock, we have to discard the event - free(first_packet); - first_packet = NULL; - return false; - } - } - - while (xQueuePeek(_async_queue, &packet, 0) == pdPASS && packet != first_packet) { - if (xQueueReceive(_async_queue, &packet, 0) != pdPASS) { - return false; - } - if ((int)packet->arg == (int)arg) { - // remove matching event - free(packet); - packet = NULL; - // otherwise try to requeue it - } else if (xQueueSend(_async_queue, &packet, 0) != pdPASS) { - // we can't wait here if queue is full, because this call has been done from the only consumer task of this queue - // otherwise it would deadlock, we have to discard the event - free(packet); - packet = NULL; - return false; - } - } - return true; -} - -static void _handle_async_event(lwip_event_packet_t* e) { - if (e->arg == NULL) { - // do nothing when arg is NULL - // ets_printf("event arg == NULL: 0x%08x\n", e->recv.pcb); - } else if (e->event == LWIP_TCP_CLEAR) { - _remove_events_with_arg(e->arg); - } else if (e->event == LWIP_TCP_RECV) { - // ets_printf("-R: 0x%08x\n", e->recv.pcb); - AsyncClient::_s_recv(e->arg, e->recv.pcb, e->recv.pb, e->recv.err); - } else if (e->event == LWIP_TCP_FIN) { - // ets_printf("-F: 0x%08x\n", e->fin.pcb); - AsyncClient::_s_fin(e->arg, e->fin.pcb, e->fin.err); - } else if (e->event == LWIP_TCP_SENT) { - // ets_printf("-S: 0x%08x\n", e->sent.pcb); - AsyncClient::_s_sent(e->arg, e->sent.pcb, e->sent.len); - } else if (e->event == LWIP_TCP_POLL) { - // ets_printf("-P: 0x%08x\n", e->poll.pcb); - AsyncClient::_s_poll(e->arg, e->poll.pcb); - } else if (e->event == LWIP_TCP_ERROR) { - // ets_printf("-E: 0x%08x %d\n", e->arg, e->error.err); - AsyncClient::_s_error(e->arg, e->error.err); - } else if (e->event == LWIP_TCP_CONNECTED) { - // ets_printf("C: 0x%08x 0x%08x %d\n", e->arg, e->connected.pcb, e->connected.err); - AsyncClient::_s_connected(e->arg, e->connected.pcb, e->connected.err); - } else if (e->event == LWIP_TCP_ACCEPT) { - // ets_printf("A: 0x%08x 0x%08x\n", e->arg, e->accept.client); - AsyncServer::_s_accepted(e->arg, e->accept.client); - } else if (e->event == LWIP_TCP_DNS) { - // ets_printf("D: 0x%08x %s = %s\n", e->arg, e->dns.name, ipaddr_ntoa(&e->dns.addr)); - AsyncClient::_s_dns_found(e->dns.name, &e->dns.addr, e->arg); - } - free((void*)(e)); -} - -static void _async_service_task(void* pvParameters) { -#if CONFIG_ASYNC_TCP_USE_WDT - if (esp_task_wdt_add(NULL) != ESP_OK) { - log_w("Failed to add async task to WDT"); - } -#endif - lwip_event_packet_t* packet = NULL; - for (;;) { - if (_get_async_event(&packet)) { - _handle_async_event(packet); - } -#if CONFIG_ASYNC_TCP_USE_WDT - esp_task_wdt_reset(); -#endif - } -#if CONFIG_ASYNC_TCP_USE_WDT - esp_task_wdt_delete(NULL); -#endif - vTaskDelete(NULL); - _async_service_task_handle = NULL; -} -/* -static void _stop_async_task(){ - if(_async_service_task_handle){ - vTaskDelete(_async_service_task_handle); - _async_service_task_handle = NULL; - } -} -*/ - -static bool customTaskCreateUniversal( - TaskFunction_t pxTaskCode, - const char* const pcName, - const uint32_t usStackDepth, - void* const pvParameters, - UBaseType_t uxPriority, - TaskHandle_t* const pxCreatedTask, - const BaseType_t xCoreID) { -#ifndef CONFIG_FREERTOS_UNICORE - if (xCoreID >= 0 && xCoreID < 2) { - return xTaskCreatePinnedToCore(pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask, xCoreID); - } else { -#endif - return xTaskCreate(pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask); -#ifndef CONFIG_FREERTOS_UNICORE - } -#endif -} - -static bool _start_async_task() { - if (!_init_async_event_queue()) { - return false; - } - if (!_async_service_task_handle) { - customTaskCreateUniversal(_async_service_task, "async_tcp", CONFIG_ASYNC_TCP_STACK_SIZE, NULL, TASK_CONNECTIVITY_PRIO, &_async_service_task_handle, CONFIG_ASYNC_TCP_RUNNING_CORE); - if (!_async_service_task_handle) { - return false; - } - } - return true; -} - -/* - * LwIP Callbacks - * */ - -static int8_t _tcp_clear_events(void* arg) { - lwip_event_packet_t* e = (lwip_event_packet_t*)malloc(sizeof(lwip_event_packet_t)); - e->event = LWIP_TCP_CLEAR; - e->arg = arg; - if (!_prepend_async_event(&e)) { - free((void*)(e)); - } - return ERR_OK; -} - -static int8_t _tcp_connected(void* arg, tcp_pcb* pcb, int8_t err) { - // ets_printf("+C: 0x%08x\n", pcb); - lwip_event_packet_t* e = (lwip_event_packet_t*)malloc(sizeof(lwip_event_packet_t)); - e->event = LWIP_TCP_CONNECTED; - e->arg = arg; - e->connected.pcb = pcb; - e->connected.err = err; - if (!_prepend_async_event(&e)) { - free((void*)(e)); - } - return ERR_OK; -} - -static int8_t _tcp_poll(void* arg, struct tcp_pcb* pcb) { - // throttle polling events queing when event queue is getting filled up, let it handle _onack's - // log_d("qs:%u", uxQueueMessagesWaiting(_async_queue)); - if (uxQueueMessagesWaiting(_async_queue) > (rand() % CONFIG_ASYNC_TCP_QUEUE_SIZE / 2 + CONFIG_ASYNC_TCP_QUEUE_SIZE / 4)) { - log_d("throttling"); - return ERR_OK; - } - - // ets_printf("+P: 0x%08x\n", pcb); - lwip_event_packet_t* e = (lwip_event_packet_t*)malloc(sizeof(lwip_event_packet_t)); - e->event = LWIP_TCP_POLL; - e->arg = arg; - e->poll.pcb = pcb; - // poll events are not critical 'cause those are repetitive, so we may not wait the queue in any case - if (!_send_async_event(&e, 0)) { - free((void*)(e)); - } - return ERR_OK; -} - -static int8_t _tcp_recv(void* arg, struct tcp_pcb* pcb, struct pbuf* pb, int8_t err) { - lwip_event_packet_t* e = (lwip_event_packet_t*)malloc(sizeof(lwip_event_packet_t)); - e->arg = arg; - if (pb) { - // ets_printf("+R: 0x%08x\n", pcb); - e->event = LWIP_TCP_RECV; - e->recv.pcb = pcb; - e->recv.pb = pb; - e->recv.err = err; - } else { - // ets_printf("+F: 0x%08x\n", pcb); - e->event = LWIP_TCP_FIN; - e->fin.pcb = pcb; - e->fin.err = err; - // close the PCB in LwIP thread - AsyncClient::_s_lwip_fin(e->arg, e->fin.pcb, e->fin.err); - } - if (!_send_async_event(&e)) { - free((void*)(e)); - } - return ERR_OK; -} - -static int8_t _tcp_sent(void* arg, struct tcp_pcb* pcb, uint16_t len) { - // ets_printf("+S: 0x%08x\n", pcb); - lwip_event_packet_t* e = (lwip_event_packet_t*)malloc(sizeof(lwip_event_packet_t)); - e->event = LWIP_TCP_SENT; - e->arg = arg; - e->sent.pcb = pcb; - e->sent.len = len; - if (!_send_async_event(&e)) { - free((void*)(e)); - } - return ERR_OK; -} - -static void _tcp_error(void* arg, int8_t err) { - // ets_printf("+E: 0x%08x\n", arg); - lwip_event_packet_t* e = (lwip_event_packet_t*)malloc(sizeof(lwip_event_packet_t)); - e->event = LWIP_TCP_ERROR; - e->arg = arg; - e->error.err = err; - if (!_send_async_event(&e)) { - free((void*)(e)); - } -} - -static void _tcp_dns_found(const char* name, struct ip_addr* ipaddr, void* arg) { - lwip_event_packet_t* e = (lwip_event_packet_t*)malloc(sizeof(lwip_event_packet_t)); - // ets_printf("+DNS: name=%s ipaddr=0x%08x arg=%x\n", name, ipaddr, arg); - e->event = LWIP_TCP_DNS; - e->arg = arg; - e->dns.name = name; - if (ipaddr) { - memcpy(&e->dns.addr, ipaddr, sizeof(struct ip_addr)); - } else { - memset(&e->dns.addr, 0, sizeof(e->dns.addr)); - } - if (!_send_async_event(&e)) { - free((void*)(e)); - } -} - -// Used to switch out from LwIP thread -static int8_t _tcp_accept(void* arg, AsyncClient* client) { - lwip_event_packet_t* e = (lwip_event_packet_t*)malloc(sizeof(lwip_event_packet_t)); - e->event = LWIP_TCP_ACCEPT; - e->arg = arg; - e->accept.client = client; - if (!_prepend_async_event(&e)) { - free((void*)(e)); - } - return ERR_OK; -} - -/* - * TCP/IP API Calls - * */ - -#include "lwip/priv/tcpip_priv.h" - -typedef struct { - struct tcpip_api_call_data call; - tcp_pcb* pcb; - int8_t closed_slot; - int8_t err; - union { - struct { - const char* data; - size_t size; - uint8_t apiflags; - } write; - size_t received; - struct { - ip_addr_t* addr; - uint16_t port; - tcp_connected_fn cb; - } connect; - struct { - ip_addr_t* addr; - uint16_t port; - } bind; - uint8_t backlog; - }; -} tcp_api_call_t; - -static err_t _tcp_output_api(struct tcpip_api_call_data* api_call_msg) { - tcp_api_call_t* msg = (tcp_api_call_t*)api_call_msg; - msg->err = ERR_CONN; - if (msg->closed_slot == INVALID_CLOSED_SLOT || !_closed_slots[msg->closed_slot]) { - msg->err = tcp_output(msg->pcb); - } - return msg->err; -} - -static esp_err_t _tcp_output(tcp_pcb* pcb, int8_t closed_slot) { - if (!pcb) { - return ERR_CONN; - } - tcp_api_call_t msg; - msg.pcb = pcb; - msg.closed_slot = closed_slot; - tcpip_api_call(_tcp_output_api, (struct tcpip_api_call_data*)&msg); - return msg.err; -} - -static err_t _tcp_write_api(struct tcpip_api_call_data* api_call_msg) { - tcp_api_call_t* msg = (tcp_api_call_t*)api_call_msg; - msg->err = ERR_CONN; - if (msg->closed_slot == INVALID_CLOSED_SLOT || !_closed_slots[msg->closed_slot]) { - msg->err = tcp_write(msg->pcb, msg->write.data, msg->write.size, msg->write.apiflags); - } - return msg->err; -} - -static esp_err_t _tcp_write(tcp_pcb* pcb, int8_t closed_slot, const char* data, size_t size, uint8_t apiflags) { - if (!pcb) { - return ERR_CONN; - } - tcp_api_call_t msg; - msg.pcb = pcb; - msg.closed_slot = closed_slot; - msg.write.data = data; - msg.write.size = size; - msg.write.apiflags = apiflags; - tcpip_api_call(_tcp_write_api, (struct tcpip_api_call_data*)&msg); - return msg.err; -} - -static err_t _tcp_recved_api(struct tcpip_api_call_data* api_call_msg) { - tcp_api_call_t* msg = (tcp_api_call_t*)api_call_msg; - msg->err = ERR_CONN; - if (msg->closed_slot == INVALID_CLOSED_SLOT || !_closed_slots[msg->closed_slot]) { - // if(msg->closed_slot != INVALID_CLOSED_SLOT && !_closed_slots[msg->closed_slot]) { - // if(msg->closed_slot != INVALID_CLOSED_SLOT) { - msg->err = 0; - tcp_recved(msg->pcb, msg->received); - } - return msg->err; -} - -static esp_err_t _tcp_recved(tcp_pcb* pcb, int8_t closed_slot, size_t len) { - if (!pcb) { - return ERR_CONN; - } - tcp_api_call_t msg; - msg.pcb = pcb; - msg.closed_slot = closed_slot; - msg.received = len; - tcpip_api_call(_tcp_recved_api, (struct tcpip_api_call_data*)&msg); - return msg.err; -} - -static err_t _tcp_close_api(struct tcpip_api_call_data* api_call_msg) { - tcp_api_call_t* msg = (tcp_api_call_t*)api_call_msg; - msg->err = ERR_CONN; - if (msg->closed_slot == INVALID_CLOSED_SLOT || !_closed_slots[msg->closed_slot]) { - msg->err = tcp_close(msg->pcb); - } - return msg->err; -} - -static esp_err_t _tcp_close(tcp_pcb* pcb, int8_t closed_slot) { - if (!pcb) { - return ERR_CONN; - } - tcp_api_call_t msg; - msg.pcb = pcb; - msg.closed_slot = closed_slot; - tcpip_api_call(_tcp_close_api, (struct tcpip_api_call_data*)&msg); - return msg.err; -} - -static err_t _tcp_abort_api(struct tcpip_api_call_data* api_call_msg) { - tcp_api_call_t* msg = (tcp_api_call_t*)api_call_msg; - msg->err = ERR_CONN; - if (msg->closed_slot == INVALID_CLOSED_SLOT || !_closed_slots[msg->closed_slot]) { - tcp_abort(msg->pcb); - } - return msg->err; -} - -static esp_err_t _tcp_abort(tcp_pcb* pcb, int8_t closed_slot) { - if (!pcb) { - return ERR_CONN; - } - tcp_api_call_t msg; - msg.pcb = pcb; - msg.closed_slot = closed_slot; - tcpip_api_call(_tcp_abort_api, (struct tcpip_api_call_data*)&msg); - return msg.err; -} - -static err_t _tcp_connect_api(struct tcpip_api_call_data* api_call_msg) { - tcp_api_call_t* msg = (tcp_api_call_t*)api_call_msg; - msg->err = tcp_connect(msg->pcb, msg->connect.addr, msg->connect.port, msg->connect.cb); - return msg->err; -} - -static esp_err_t _tcp_connect(tcp_pcb* pcb, int8_t closed_slot, ip_addr_t* addr, uint16_t port, tcp_connected_fn cb) { - if (!pcb) { - return ESP_FAIL; - } - tcp_api_call_t msg; - msg.pcb = pcb; - msg.closed_slot = closed_slot; - msg.connect.addr = addr; - msg.connect.port = port; - msg.connect.cb = cb; - tcpip_api_call(_tcp_connect_api, (struct tcpip_api_call_data*)&msg); - return msg.err; -} - -static err_t _tcp_bind_api(struct tcpip_api_call_data* api_call_msg) { - tcp_api_call_t* msg = (tcp_api_call_t*)api_call_msg; - msg->err = tcp_bind(msg->pcb, msg->bind.addr, msg->bind.port); - return msg->err; -} - -static esp_err_t _tcp_bind(tcp_pcb* pcb, ip_addr_t* addr, uint16_t port) { - if (!pcb) { - return ESP_FAIL; - } - tcp_api_call_t msg; - msg.pcb = pcb; - msg.closed_slot = -1; - msg.bind.addr = addr; - msg.bind.port = port; - tcpip_api_call(_tcp_bind_api, (struct tcpip_api_call_data*)&msg); - return msg.err; -} - -static err_t _tcp_listen_api(struct tcpip_api_call_data* api_call_msg) { - tcp_api_call_t* msg = (tcp_api_call_t*)api_call_msg; - msg->err = 0; - msg->pcb = tcp_listen_with_backlog(msg->pcb, msg->backlog); - return msg->err; -} - -static tcp_pcb* _tcp_listen_with_backlog(tcp_pcb* pcb, uint8_t backlog) { - if (!pcb) { - return NULL; - } - tcp_api_call_t msg; - msg.pcb = pcb; - msg.closed_slot = -1; - msg.backlog = backlog ? backlog : 0xFF; - tcpip_api_call(_tcp_listen_api, (struct tcpip_api_call_data*)&msg); - return msg.pcb; -} - -/* - Async TCP Client - */ - -AsyncClient::AsyncClient(tcp_pcb* pcb) - : _connect_cb(0), _connect_cb_arg(0), _discard_cb(0), _discard_cb_arg(0), _sent_cb(0), _sent_cb_arg(0), _error_cb(0), _error_cb_arg(0), _recv_cb(0), _recv_cb_arg(0), _pb_cb(0), _pb_cb_arg(0), _timeout_cb(0), _timeout_cb_arg(0), _ack_pcb(true), _tx_last_packet(0), _rx_timeout(0), _rx_last_ack(0), _ack_timeout(CONFIG_ASYNC_TCP_MAX_ACK_TIME), _connect_port(0), prev(NULL), next(NULL) { - _pcb = pcb; - _closed_slot = INVALID_CLOSED_SLOT; - if (_pcb) { - _rx_last_packet = millis(); - tcp_arg(_pcb, this); - tcp_recv(_pcb, &_tcp_recv); - tcp_sent(_pcb, &_tcp_sent); - tcp_err(_pcb, &_tcp_error); - tcp_poll(_pcb, &_tcp_poll, CONFIG_ASYNC_TCP_POLL_TIMER); - if (!_allocate_closed_slot()) { - _close(); - } - } -} - -AsyncClient::~AsyncClient() { - if (_pcb) { - _close(); - } - _free_closed_slot(); -} - -/* - * Operators - * */ - -AsyncClient& AsyncClient::operator=(const AsyncClient& other) { - if (_pcb) { - _close(); - } - - _pcb = other._pcb; - _closed_slot = other._closed_slot; - if (_pcb) { - _rx_last_packet = millis(); - tcp_arg(_pcb, this); - tcp_recv(_pcb, &_tcp_recv); - tcp_sent(_pcb, &_tcp_sent); - tcp_err(_pcb, &_tcp_error); - tcp_poll(_pcb, &_tcp_poll, CONFIG_ASYNC_TCP_POLL_TIMER); - } - return *this; -} - -bool AsyncClient::operator==(const AsyncClient& other) { - return _pcb == other._pcb; -} - -AsyncClient& AsyncClient::operator+=(const AsyncClient& other) { - if (next == NULL) { - next = (AsyncClient*)(&other); - next->prev = this; - } else { - AsyncClient* c = next; - while (c->next != NULL) { - c = c->next; - } - c->next = (AsyncClient*)(&other); - c->next->prev = c; - } - return *this; -} - -/* - * Callback Setters - * */ - -void AsyncClient::onConnect(AcConnectHandler cb, void* arg) { - _connect_cb = cb; - _connect_cb_arg = arg; -} - -void AsyncClient::onDisconnect(AcConnectHandler cb, void* arg) { - _discard_cb = cb; - _discard_cb_arg = arg; -} - -void AsyncClient::onAck(AcAckHandler cb, void* arg) { - _sent_cb = cb; - _sent_cb_arg = arg; -} - -void AsyncClient::onError(AcErrorHandler cb, void* arg) { - _error_cb = cb; - _error_cb_arg = arg; -} - -void AsyncClient::onData(AcDataHandler cb, void* arg) { - _recv_cb = cb; - _recv_cb_arg = arg; -} - -void AsyncClient::onPacket(AcPacketHandler cb, void* arg) { - _pb_cb = cb; - _pb_cb_arg = arg; -} - -void AsyncClient::onTimeout(AcTimeoutHandler cb, void* arg) { - _timeout_cb = cb; - _timeout_cb_arg = arg; -} - -void AsyncClient::onPoll(AcConnectHandler cb, void* arg) { - _poll_cb = cb; - _poll_cb_arg = arg; -} - -/* - * Main Public Methods - * */ - -bool AsyncClient::_connect(ip_addr_t addr, uint16_t port) { - if (_pcb) { - log_d("already connected, state %d", _pcb->state); - return false; - } - if (!_start_async_task()) { - log_e("failed to start task"); - return false; - } - - if (!_allocate_closed_slot()) { - log_e("failed to allocate: closed slot full"); - return false; - } - - TCP_MUTEX_LOCK(); - tcp_pcb* pcb = tcp_new_ip_type(addr.type); - if (!pcb) { - TCP_MUTEX_UNLOCK(); - log_e("pcb == NULL"); - return false; - } - tcp_arg(pcb, this); - tcp_err(pcb, &_tcp_error); - tcp_recv(pcb, &_tcp_recv); - tcp_sent(pcb, &_tcp_sent); - tcp_poll(pcb, &_tcp_poll, CONFIG_ASYNC_TCP_POLL_TIMER); - TCP_MUTEX_UNLOCK(); - - esp_err_t err = _tcp_connect(pcb, _closed_slot, &addr, port, (tcp_connected_fn)&_tcp_connected); - return err == ESP_OK; -} - -bool AsyncClient::connect(const IPAddress& ip, uint16_t port) { - ip_addr_t addr; -#if ESP_IDF_VERSION_MAJOR < 5 - addr.u_addr.ip4.addr = ip; - addr.type = IPADDR_TYPE_V4; -#else - ip.to_ip_addr_t(&addr); -#endif - - return _connect(addr, port); -} - -#if LWIP_IPV6 && ESP_IDF_VERSION_MAJOR < 5 -bool AsyncClient::connect(const IPv6Address& ip, uint16_t port) { - auto ipaddr = static_cast(ip); - ip_addr_t addr = IPADDR6_INIT(ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); - - return _connect(addr, port); -} -#endif - -bool AsyncClient::connect(const char* host, uint16_t port) { - ip_addr_t addr; - - if (!_start_async_task()) { - log_e("failed to start task"); - return false; - } - - TCP_MUTEX_LOCK(); - err_t err = dns_gethostbyname(host, &addr, (dns_found_callback)&_tcp_dns_found, this); - TCP_MUTEX_UNLOCK(); - if (err == ERR_OK) { -#if ESP_IDF_VERSION_MAJOR < 5 - #if LWIP_IPV6 - if (addr.type == IPADDR_TYPE_V6) { - return connect(IPv6Address(addr.u_addr.ip6.addr), port); - } - return connect(IPAddress(addr.u_addr.ip4.addr), port); - #else - return connect(IPAddress(addr.addr), port); - #endif -#else - return _connect(addr, port); -#endif - } else if (err == ERR_INPROGRESS) { - _connect_port = port; - return true; - } - log_d("error: %d", err); - return false; -} - -void AsyncClient::close(bool now) { - if (_pcb) { - _tcp_recved(_pcb, _closed_slot, _rx_ack_len); - } - _close(); -} - -int8_t AsyncClient::abort() { - if (_pcb) { - _tcp_abort(_pcb, _closed_slot); - _pcb = NULL; - } - return ERR_ABRT; -} - -size_t AsyncClient::space() { - if ((_pcb != NULL) && (_pcb->state == ESTABLISHED)) { - return tcp_sndbuf(_pcb); - } - return 0; -} - -size_t AsyncClient::add(const char* data, size_t size, uint8_t apiflags) { - if (!_pcb || size == 0 || data == NULL) { - return 0; - } - size_t room = space(); - if (!room) { - return 0; - } - size_t will_send = (room < size) ? room : size; - int8_t err = ERR_OK; - err = _tcp_write(_pcb, _closed_slot, data, will_send, apiflags); - if (err != ERR_OK) { - return 0; - } - return will_send; -} - -bool AsyncClient::send() { - auto backup = _tx_last_packet; - _tx_last_packet = millis(); - if (_tcp_output(_pcb, _closed_slot) == ERR_OK) { - return true; - } - _tx_last_packet = backup; - return false; -} - -size_t AsyncClient::ack(size_t len) { - if (len > _rx_ack_len) - len = _rx_ack_len; - if (len) { - _tcp_recved(_pcb, _closed_slot, len); - } - _rx_ack_len -= len; - return len; -} - -void AsyncClient::ackPacket(struct pbuf* pb) { - if (!pb) { - return; - } - _tcp_recved(_pcb, _closed_slot, pb->len); - pbuf_free(pb); -} - -/* - * Main Private Methods - * */ - -int8_t AsyncClient::_close() { - // ets_printf("X: 0x%08x\n", (uint32_t)this); - int8_t err = ERR_OK; - if (_pcb) { - TCP_MUTEX_LOCK(); - tcp_arg(_pcb, NULL); - tcp_sent(_pcb, NULL); - tcp_recv(_pcb, NULL); - tcp_err(_pcb, NULL); - tcp_poll(_pcb, NULL, 0); - TCP_MUTEX_UNLOCK(); - _tcp_clear_events(this); - err = _tcp_close(_pcb, _closed_slot); - if (err != ERR_OK) { - err = abort(); - } - _free_closed_slot(); - _pcb = NULL; - if (_discard_cb) { - _discard_cb(_discard_cb_arg, this); - } - } - return err; -} - -bool AsyncClient::_allocate_closed_slot() { - if (_closed_slot != INVALID_CLOSED_SLOT) { - return true; - } - xSemaphoreTake(_slots_lock, portMAX_DELAY); - uint32_t closed_slot_min_index = 0; - for (int i = 0; i < _number_of_closed_slots; ++i) { - if ((_closed_slot == INVALID_CLOSED_SLOT || _closed_slots[i] <= closed_slot_min_index) && _closed_slots[i] != 0) { - closed_slot_min_index = _closed_slots[i]; - _closed_slot = i; - } - } - if (_closed_slot != INVALID_CLOSED_SLOT) { - _closed_slots[_closed_slot] = 0; - } - xSemaphoreGive(_slots_lock); - return (_closed_slot != INVALID_CLOSED_SLOT); -} - -void AsyncClient::_free_closed_slot() { - xSemaphoreTake(_slots_lock, portMAX_DELAY); - if (_closed_slot != INVALID_CLOSED_SLOT) { - _closed_slots[_closed_slot] = _closed_index; - _closed_slot = INVALID_CLOSED_SLOT; - ++_closed_index; - } - xSemaphoreGive(_slots_lock); -} - -/* - * Private Callbacks - * */ - -int8_t AsyncClient::_connected(tcp_pcb* pcb, int8_t err) { - _pcb = reinterpret_cast(pcb); - if (_pcb) { - _rx_last_packet = millis(); - } - if (_connect_cb) { - _connect_cb(_connect_cb_arg, this); - } - return ERR_OK; -} - -void AsyncClient::_error(int8_t err) { - if (_pcb) { - TCP_MUTEX_LOCK(); - tcp_arg(_pcb, NULL); - if (_pcb->state == LISTEN) { - tcp_sent(_pcb, NULL); - tcp_recv(_pcb, NULL); - tcp_err(_pcb, NULL); - tcp_poll(_pcb, NULL, 0); - } - TCP_MUTEX_UNLOCK(); - _free_closed_slot(); - _pcb = NULL; - } - if (_error_cb) { - _error_cb(_error_cb_arg, this, err); - } - if (_discard_cb) { - _discard_cb(_discard_cb_arg, this); - } -} - -// In LwIP Thread -int8_t AsyncClient::_lwip_fin(tcp_pcb* pcb, int8_t err) { - if (!_pcb || pcb != _pcb) { - log_d("0x%08x != 0x%08x", (uint32_t)pcb, (uint32_t)_pcb); - return ERR_OK; - } - tcp_arg(_pcb, NULL); - if (_pcb->state == LISTEN) { - tcp_sent(_pcb, NULL); - tcp_recv(_pcb, NULL); - tcp_err(_pcb, NULL); - tcp_poll(_pcb, NULL, 0); - } - if (tcp_close(_pcb) != ERR_OK) { - tcp_abort(_pcb); - } - _free_closed_slot(); - _pcb = NULL; - return ERR_OK; -} - -// In Async Thread -int8_t AsyncClient::_fin(tcp_pcb* pcb, int8_t err) { - _tcp_clear_events(this); - if (_discard_cb) { - _discard_cb(_discard_cb_arg, this); - } - return ERR_OK; -} - -int8_t AsyncClient::_sent(tcp_pcb* pcb, uint16_t len) { - _rx_last_ack = _rx_last_packet = millis(); - if (_sent_cb) { - _sent_cb(_sent_cb_arg, this, len, (_rx_last_packet - _tx_last_packet)); - } - return ERR_OK; -} - -int8_t AsyncClient::_recv(tcp_pcb* pcb, pbuf* pb, int8_t err) { - while (pb != NULL) { - _rx_last_packet = millis(); - // we should not ack before we assimilate the data - _ack_pcb = true; - pbuf* b = pb; - pb = b->next; - b->next = NULL; - if (_pb_cb) { - _pb_cb(_pb_cb_arg, this, b); - } else { - if (_recv_cb) { - _recv_cb(_recv_cb_arg, this, b->payload, b->len); - } - if (!_ack_pcb) { - _rx_ack_len += b->len; - } else if (_pcb) { - _tcp_recved(_pcb, _closed_slot, b->len); - } - } - pbuf_free(b); - } - return ERR_OK; -} - -int8_t AsyncClient::_poll(tcp_pcb* pcb) { - if (!_pcb) { - // log_d("pcb is NULL"); - return ERR_OK; - } - if (pcb != _pcb) { - log_d("0x%08x != 0x%08x", (uint32_t)pcb, (uint32_t)_pcb); - return ERR_OK; - } - - uint32_t now = millis(); - - // ACK Timeout - if (_ack_timeout) { - const uint32_t one_day = 86400000; - bool last_tx_is_after_last_ack = (_rx_last_ack - _tx_last_packet + one_day) < one_day; - if (last_tx_is_after_last_ack && (now - _tx_last_packet) >= _ack_timeout) { - log_d("ack timeout %d", pcb->state); - if (_timeout_cb) - _timeout_cb(_timeout_cb_arg, this, (now - _tx_last_packet)); - return ERR_OK; - } - } - // RX Timeout - if (_rx_timeout && (now - _rx_last_packet) >= (_rx_timeout * 1000)) { - log_d("rx timeout %d", pcb->state); - _close(); - return ERR_OK; - } - // Everything is fine - if (_poll_cb) { - _poll_cb(_poll_cb_arg, this); - } - return ERR_OK; -} - -void AsyncClient::_dns_found(struct ip_addr* ipaddr) { -#if ESP_IDF_VERSION_MAJOR < 5 - if (ipaddr && IP_IS_V4(ipaddr)) { - connect(IPAddress(ip_addr_get_ip4_u32(ipaddr)), _connect_port); - #if LWIP_IPV6 - } else if (ipaddr && ipaddr->u_addr.ip6.addr) { - connect(IPv6Address(ipaddr->u_addr.ip6.addr), _connect_port); - #endif -#else - if (ipaddr) { - IPAddress ip; - ip.from_ip_addr_t(ipaddr); - connect(ip, _connect_port); -#endif - } else { - if (_error_cb) { - _error_cb(_error_cb_arg, this, -55); - } - if (_discard_cb) { - _discard_cb(_discard_cb_arg, this); - } - } -} - -/* - * Public Helper Methods - * */ - -bool AsyncClient::free() { - if (!_pcb) { - return true; - } - if (_pcb->state == CLOSED || _pcb->state > ESTABLISHED) { - return true; - } - return false; -} - -size_t AsyncClient::write(const char* data, size_t size, uint8_t apiflags) { - size_t will_send = add(data, size, apiflags); - if (!will_send || !send()) { - return 0; - } - return will_send; -} - -void AsyncClient::setRxTimeout(uint32_t timeout) { - _rx_timeout = timeout; -} - -uint32_t AsyncClient::getRxTimeout() { - return _rx_timeout; -} - -uint32_t AsyncClient::getAckTimeout() { - return _ack_timeout; -} - -void AsyncClient::setAckTimeout(uint32_t timeout) { - _ack_timeout = timeout; -} - -void AsyncClient::setNoDelay(bool nodelay) { - if (!_pcb) { - return; - } - if (nodelay) { - tcp_nagle_disable(_pcb); - } else { - tcp_nagle_enable(_pcb); - } -} - -bool AsyncClient::getNoDelay() { - if (!_pcb) { - return false; - } - return tcp_nagle_disabled(_pcb); -} - -void AsyncClient::setKeepAlive(uint32_t ms, uint8_t cnt) { - if (ms != 0) { - _pcb->so_options |= SOF_KEEPALIVE; // Turn on TCP Keepalive for the given pcb - // Set the time between keepalive messages in milli-seconds - _pcb->keep_idle = ms; - _pcb->keep_intvl = ms; - _pcb->keep_cnt = cnt; // The number of unanswered probes required to force closure of the socket - } else { - _pcb->so_options &= ~SOF_KEEPALIVE; // Turn off TCP Keepalive for the given pcb - } -} - -uint16_t AsyncClient::getMss() { - if (!_pcb) { - return 0; - } - return tcp_mss(_pcb); -} - -uint32_t AsyncClient::getRemoteAddress() { - if (!_pcb) { - return 0; - } -#if LWIP_IPV4 && LWIP_IPV6 - return _pcb->remote_ip.u_addr.ip4.addr; -#else - return _pcb->remote_ip.addr; -#endif -} - -#if LWIP_IPV6 -ip6_addr_t AsyncClient::getRemoteAddress6() { - if (!_pcb) { - ip6_addr_t nulladdr; - ip6_addr_set_zero(&nulladdr); - return nulladdr; - } - return _pcb->remote_ip.u_addr.ip6; -} - -ip6_addr_t AsyncClient::getLocalAddress6() { - if (!_pcb) { - ip6_addr_t nulladdr; - ip6_addr_set_zero(&nulladdr); - return nulladdr; - } - return _pcb->local_ip.u_addr.ip6; -} - #if ESP_IDF_VERSION_MAJOR < 5 -IPv6Address AsyncClient::remoteIP6() { - return IPv6Address(getRemoteAddress6().addr); -} - -IPv6Address AsyncClient::localIP6() { - return IPv6Address(getLocalAddress6().addr); -} - #else -IPAddress AsyncClient::remoteIP6() { - if (!_pcb) { - return IPAddress(IPType::IPv6); - } - IPAddress ip; - ip.from_ip_addr_t(&(_pcb->remote_ip)); - return ip; -} - -IPAddress AsyncClient::localIP6() { - if (!_pcb) { - return IPAddress(IPType::IPv6); - } - IPAddress ip; - ip.from_ip_addr_t(&(_pcb->local_ip)); - return ip; -} - #endif -#endif - -uint16_t AsyncClient::getRemotePort() { - if (!_pcb) { - return 0; - } - return _pcb->remote_port; -} - -uint32_t AsyncClient::getLocalAddress() { - if (!_pcb) { - return 0; - } -#if LWIP_IPV4 && LWIP_IPV6 - return _pcb->local_ip.u_addr.ip4.addr; -#else - return _pcb->local_ip.addr; -#endif -} - -uint16_t AsyncClient::getLocalPort() { - if (!_pcb) { - return 0; - } - return _pcb->local_port; -} - -IPAddress AsyncClient::remoteIP() { -#if ESP_IDF_VERSION_MAJOR < 5 - return IPAddress(getRemoteAddress()); -#else - if (!_pcb) { - return IPAddress(); - } - IPAddress ip; - ip.from_ip_addr_t(&(_pcb->remote_ip)); - return ip; -#endif -} - -uint16_t AsyncClient::remotePort() { - return getRemotePort(); -} - -IPAddress AsyncClient::localIP() { -#if ESP_IDF_VERSION_MAJOR < 5 - return IPAddress(getLocalAddress()); -#else - if (!_pcb) { - return IPAddress(); - } - IPAddress ip; - ip.from_ip_addr_t(&(_pcb->local_ip)); - return ip; -#endif -} - -uint16_t AsyncClient::localPort() { - return getLocalPort(); -} - -uint8_t AsyncClient::state() { - if (!_pcb) { - return 0; - } - return _pcb->state; -} - -bool AsyncClient::connected() { - if (!_pcb) { - return false; - } - return _pcb->state == ESTABLISHED; -} - -bool AsyncClient::connecting() { - if (!_pcb) { - return false; - } - return _pcb->state > CLOSED && _pcb->state < ESTABLISHED; -} - -bool AsyncClient::disconnecting() { - if (!_pcb) { - return false; - } - return _pcb->state > ESTABLISHED && _pcb->state < TIME_WAIT; -} - -bool AsyncClient::disconnected() { - if (!_pcb) { - return true; - } - return _pcb->state == CLOSED || _pcb->state == TIME_WAIT; -} - -bool AsyncClient::freeable() { - if (!_pcb) { - return true; - } - return _pcb->state == CLOSED || _pcb->state > ESTABLISHED; -} - -bool AsyncClient::canSend() { - return space() > 0; -} - -const char* AsyncClient::errorToString(int8_t error) { - switch (error) { - case ERR_OK: - return "OK"; - case ERR_MEM: - return "Out of memory error"; - case ERR_BUF: - return "Buffer error"; - case ERR_TIMEOUT: - return "Timeout"; - case ERR_RTE: - return "Routing problem"; - case ERR_INPROGRESS: - return "Operation in progress"; - case ERR_VAL: - return "Illegal value"; - case ERR_WOULDBLOCK: - return "Operation would block"; - case ERR_USE: - return "Address in use"; - case ERR_ALREADY: - return "Already connected"; - case ERR_CONN: - return "Not connected"; - case ERR_IF: - return "Low-level netif error"; - case ERR_ABRT: - return "Connection aborted"; - case ERR_RST: - return "Connection reset"; - case ERR_CLSD: - return "Connection closed"; - case ERR_ARG: - return "Illegal argument"; - case -55: - return "DNS failed"; - default: - return "UNKNOWN"; - } -} - -const char* AsyncClient::stateToString() { - switch (state()) { - case 0: - return "Closed"; - case 1: - return "Listen"; - case 2: - return "SYN Sent"; - case 3: - return "SYN Received"; - case 4: - return "Established"; - case 5: - return "FIN Wait 1"; - case 6: - return "FIN Wait 2"; - case 7: - return "Close Wait"; - case 8: - return "Closing"; - case 9: - return "Last ACK"; - case 10: - return "Time Wait"; - default: - return "UNKNOWN"; - } -} - -/* - * Static Callbacks (LwIP C2C++ interconnect) - * */ - -void AsyncClient::_s_dns_found(const char* name, struct ip_addr* ipaddr, void* arg) { - reinterpret_cast(arg)->_dns_found(ipaddr); -} - -int8_t AsyncClient::_s_poll(void* arg, struct tcp_pcb* pcb) { - return reinterpret_cast(arg)->_poll(pcb); -} - -int8_t AsyncClient::_s_recv(void* arg, struct tcp_pcb* pcb, struct pbuf* pb, int8_t err) { - return reinterpret_cast(arg)->_recv(pcb, pb, err); -} - -int8_t AsyncClient::_s_fin(void* arg, struct tcp_pcb* pcb, int8_t err) { - return reinterpret_cast(arg)->_fin(pcb, err); -} - -int8_t AsyncClient::_s_lwip_fin(void* arg, struct tcp_pcb* pcb, int8_t err) { - return reinterpret_cast(arg)->_lwip_fin(pcb, err); -} - -int8_t AsyncClient::_s_sent(void* arg, struct tcp_pcb* pcb, uint16_t len) { - return reinterpret_cast(arg)->_sent(pcb, len); -} - -void AsyncClient::_s_error(void* arg, int8_t err) { - reinterpret_cast(arg)->_error(err); -} - -int8_t AsyncClient::_s_connected(void* arg, struct tcp_pcb* pcb, int8_t err) { - return reinterpret_cast(arg)->_connected(pcb, err); -} - -/* - Async TCP Server - */ - -AsyncServer::AsyncServer(IPAddress addr, uint16_t port) - : _port(port) -#if ESP_IDF_VERSION_MAJOR < 5 - , - _bind4(true), _bind6(false) -#else - , - _bind4(addr.type() != IPType::IPv6), _bind6(addr.type() == IPType::IPv6) -#endif - , - _addr(addr), _noDelay(false), _pcb(0), _connect_cb(0), _connect_cb_arg(0) { -} - -#if ESP_IDF_VERSION_MAJOR < 5 -AsyncServer::AsyncServer(IPv6Address addr, uint16_t port) - : _port(port), _bind4(false), _bind6(true), _addr6(addr), _noDelay(false), _pcb(0), _connect_cb(0), _connect_cb_arg(0) {} -#endif - -AsyncServer::AsyncServer(uint16_t port) - : _port(port), _bind4(true), _bind6(false), _addr((uint32_t)IPADDR_ANY) -#if ESP_IDF_VERSION_MAJOR < 5 - , - _addr6() -#endif - , - _noDelay(false), _pcb(0), _connect_cb(0), _connect_cb_arg(0) { -} - -AsyncServer::~AsyncServer() { - end(); -} - -void AsyncServer::onClient(AcConnectHandler cb, void* arg) { - _connect_cb = cb; - _connect_cb_arg = arg; -} - -void AsyncServer::begin() { - if (_pcb) { - return; - } - - if (!_start_async_task()) { - log_e("failed to start task"); - return; - } - int8_t err; - TCP_MUTEX_LOCK(); - _pcb = tcp_new_ip_type(_bind4 && _bind6 ? IPADDR_TYPE_ANY : (_bind6 ? IPADDR_TYPE_V6 : IPADDR_TYPE_V4)); - TCP_MUTEX_UNLOCK(); - if (!_pcb) { - log_e("_pcb == NULL"); - return; - } - - ip_addr_t local_addr; -#if ESP_IDF_VERSION_MAJOR < 5 - if (_bind6) { // _bind6 && _bind4 both at the same time is not supported on Arduino 2 in this lib API - local_addr.type = IPADDR_TYPE_V6; - memcpy(local_addr.u_addr.ip6.addr, static_cast(_addr6), sizeof(uint32_t) * 4); - } else { - local_addr.type = IPADDR_TYPE_V4; - local_addr.u_addr.ip4.addr = _addr; - } -#else - _addr.to_ip_addr_t(&local_addr); -#endif - err = _tcp_bind(_pcb, &local_addr, _port); - - if (err != ERR_OK) { - _tcp_close(_pcb, -1); - log_e("bind error: %d", err); - return; - } - - static uint8_t backlog = 5; - _pcb = _tcp_listen_with_backlog(_pcb, backlog); - if (!_pcb) { - log_e("listen_pcb == NULL"); - return; - } - TCP_MUTEX_LOCK(); - tcp_arg(_pcb, (void*)this); - tcp_accept(_pcb, &_s_accept); - TCP_MUTEX_UNLOCK(); -} - -void AsyncServer::end() { - if (_pcb) { - TCP_MUTEX_LOCK(); - tcp_arg(_pcb, NULL); - tcp_accept(_pcb, NULL); - if (tcp_close(_pcb) != ERR_OK) { - TCP_MUTEX_UNLOCK(); - _tcp_abort(_pcb, -1); - } else { - TCP_MUTEX_UNLOCK(); - } - _pcb = NULL; - } -} - -// runs on LwIP thread -int8_t AsyncServer::_accept(tcp_pcb* pcb, int8_t err) { - // ets_printf("+A: 0x%08x\n", pcb); - if (_connect_cb) { - AsyncClient* c = new AsyncClient(pcb); - if (c) { - c->setNoDelay(_noDelay); - return _tcp_accept(this, c); - } - } - if (tcp_close(pcb) != ERR_OK) { - tcp_abort(pcb); - } - log_d("FAIL"); - return ERR_OK; -} - -int8_t AsyncServer::_accepted(AsyncClient* client) { - if (_connect_cb) { - _connect_cb(_connect_cb_arg, client); - } - return ERR_OK; -} - -void AsyncServer::setNoDelay(bool nodelay) { - _noDelay = nodelay; -} - -bool AsyncServer::getNoDelay() { - return _noDelay; -} - -uint8_t AsyncServer::status() { - if (!_pcb) { - return 0; - } - return _pcb->state; -} - -int8_t AsyncServer::_s_accept(void* arg, tcp_pcb* pcb, int8_t err) { - return reinterpret_cast(arg)->_accept(pcb, err); -} - -int8_t AsyncServer::_s_accepted(void* arg, AsyncClient* client) { - return reinterpret_cast(arg)->_accepted(client); -} diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/src/AsyncTCP.h b/Software/src/lib/mathieucarbou-AsyncTCP/src/AsyncTCP.h deleted file mode 100644 index c909d051..00000000 --- a/Software/src/lib/mathieucarbou-AsyncTCP/src/AsyncTCP.h +++ /dev/null @@ -1,347 +0,0 @@ -/* - Asynchronous TCP library for Espressif MCUs - - Copyright (c) 2016 Hristo Gochkov. All rights reserved. - This file is part of the esp8266 core for Arduino environment. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef ASYNCTCP_H_ -#define ASYNCTCP_H_ - -#define ASYNCTCP_VERSION "3.3.1" -#define ASYNCTCP_VERSION_MAJOR 3 -#define ASYNCTCP_VERSION_MINOR 3 -#define ASYNCTCP_VERSION_REVISION 1 -#define ASYNCTCP_FORK_mathieucarbou - -#include "../../../devboard/hal/hal.h" -#include "../../../system_settings.h" - -#include "IPAddress.h" -#if ESP_IDF_VERSION_MAJOR < 5 - #include "IPv6Address.h" -#endif -#include "lwip/ip6_addr.h" -#include "lwip/ip_addr.h" -#include - -#ifndef LIBRETINY - #include "sdkconfig.h" -extern "C" { - #include "freertos/semphr.h" - #include "lwip/pbuf.h" -} -#else -extern "C" { - #include - #include -} - #define CONFIG_ASYNC_TCP_RUNNING_CORE WIFI_CORE -#endif - -// If core is not defined, then we are running in Arduino or PIO -#ifndef CONFIG_ASYNC_TCP_RUNNING_CORE - #define CONFIG_ASYNC_TCP_RUNNING_CORE WIFI_CORE -#endif - -// guard AsyncTCP task with watchdog -#ifndef CONFIG_ASYNC_TCP_USE_WDT - #define CONFIG_ASYNC_TCP_USE_WDT 0 -#endif - -#ifndef CONFIG_ASYNC_TCP_STACK_SIZE - #define CONFIG_ASYNC_TCP_STACK_SIZE 8192 * 2 -#endif - -#ifndef CONFIG_ASYNC_TCP_PRIORITY - #define CONFIG_ASYNC_TCP_PRIORITY 10 -#endif - -#ifndef CONFIG_ASYNC_TCP_QUEUE_SIZE - #define CONFIG_ASYNC_TCP_QUEUE_SIZE 64 -#endif - -#ifndef CONFIG_ASYNC_TCP_MAX_ACK_TIME - #define CONFIG_ASYNC_TCP_MAX_ACK_TIME 5000 -#endif - -class AsyncClient; - -#define ASYNC_WRITE_FLAG_COPY 0x01 // will allocate new buffer to hold the data while sending (else will hold reference to the data given) -#define ASYNC_WRITE_FLAG_MORE 0x02 // will not send PSH flag, meaning that there should be more data to be sent before the application should react. - -typedef std::function AcConnectHandler; -typedef std::function AcAckHandler; -typedef std::function AcErrorHandler; -typedef std::function AcDataHandler; -typedef std::function AcPacketHandler; -typedef std::function AcTimeoutHandler; - -struct tcp_pcb; -struct ip_addr; - -class AsyncClient { - public: - AsyncClient(tcp_pcb* pcb = 0); - ~AsyncClient(); - - AsyncClient& operator=(const AsyncClient& other); - AsyncClient& operator+=(const AsyncClient& other); - - bool operator==(const AsyncClient& other); - - bool operator!=(const AsyncClient& other) { - return !(*this == other); - } - bool connect(const IPAddress& ip, uint16_t port); -#if ESP_IDF_VERSION_MAJOR < 5 - bool connect(const IPv6Address& ip, uint16_t port); -#endif - bool connect(const char* host, uint16_t port); - /** - * @brief close connection - * - * @param now - ignored - */ - void close(bool now = false); - // same as close() - void stop() { close(false); }; - int8_t abort(); - bool free(); - - // ack is not pending - bool canSend(); - // TCP buffer space available - size_t space(); - - /** - * @brief add data to be send (but do not send yet) - * @note add() would call lwip's tcp_write() - By default apiflags=ASYNC_WRITE_FLAG_COPY - You could try to use apiflags with this flag unset to pass data by reference and avoid copy to socket buffer, - but looks like it does not work for Arduino's lwip in ESP32/IDF at least - it is enforced in https://github.com/espressif/esp-lwip/blob/0606eed9d8b98a797514fdf6eabb4daf1c8c8cd9/src/core/tcp_out.c#L422C5-L422C30 - if LWIP_NETIF_TX_SINGLE_PBUF is set, and it is set indeed in IDF - https://github.com/espressif/esp-idf/blob/a0f798cfc4bbd624aab52b2c194d219e242d80c1/components/lwip/port/include/lwipopts.h#L744 - * - * @param data - * @param size - * @param apiflags - * @return size_t amount of data that has been copied - */ - size_t add(const char* data, size_t size, uint8_t apiflags = ASYNC_WRITE_FLAG_COPY); - - /** - * @brief send data previously add()'ed - * - * @return true on success - * @return false on error - */ - bool send(); - - /** - * @brief add and enqueue data for sending - * @note it is same as add() + send() - * @note only make sense when canSend() == true - * - * @param data - * @param size - * @param apiflags - * @return size_t - */ - size_t write(const char* data, size_t size, uint8_t apiflags = ASYNC_WRITE_FLAG_COPY); - - /** - * @brief add and enque data for sending - * @note treats data as null-terminated string - * - * @param data - * @return size_t - */ - size_t write(const char* data) { return data == NULL ? 0 : write(data, strlen(data)); }; - - uint8_t state(); - bool connecting(); - bool connected(); - bool disconnecting(); - bool disconnected(); - - // disconnected or disconnecting - bool freeable(); - - uint16_t getMss(); - - uint32_t getRxTimeout(); - // no RX data timeout for the connection in seconds - void setRxTimeout(uint32_t timeout); - - uint32_t getAckTimeout(); - // no ACK timeout for the last sent packet in milliseconds - void setAckTimeout(uint32_t timeout); - - void setNoDelay(bool nodelay); - bool getNoDelay(); - - void setKeepAlive(uint32_t ms, uint8_t cnt); - - uint32_t getRemoteAddress(); - uint16_t getRemotePort(); - uint32_t getLocalAddress(); - uint16_t getLocalPort(); -#if LWIP_IPV6 - ip6_addr_t getRemoteAddress6(); - ip6_addr_t getLocalAddress6(); - #if ESP_IDF_VERSION_MAJOR < 5 - IPv6Address remoteIP6(); - IPv6Address localIP6(); - #else - IPAddress remoteIP6(); - IPAddress localIP6(); - #endif -#endif - - // compatibility - IPAddress remoteIP(); - uint16_t remotePort(); - IPAddress localIP(); - uint16_t localPort(); - - // set callback - on successful connect - void onConnect(AcConnectHandler cb, void* arg = 0); - // set callback - disconnected - void onDisconnect(AcConnectHandler cb, void* arg = 0); - // set callback - ack received - void onAck(AcAckHandler cb, void* arg = 0); - // set callback - unsuccessful connect or error - void onError(AcErrorHandler cb, void* arg = 0); - // set callback - data received (called if onPacket is not used) - void onData(AcDataHandler cb, void* arg = 0); - // set callback - data received - void onPacket(AcPacketHandler cb, void* arg = 0); - // set callback - ack timeout - void onTimeout(AcTimeoutHandler cb, void* arg = 0); - // set callback - every 125ms when connected - void onPoll(AcConnectHandler cb, void* arg = 0); - - // ack pbuf from onPacket - void ackPacket(struct pbuf* pb); - // ack data that you have not acked using the method below - size_t ack(size_t len); - // will not ack the current packet. Call from onData - void ackLater() { _ack_pcb = false; } - - static const char* errorToString(int8_t error); - const char* stateToString(); - - // internal callbacks - Do NOT call any of the functions below in user code! - static int8_t _s_poll(void* arg, struct tcp_pcb* tpcb); - static int8_t _s_recv(void* arg, struct tcp_pcb* tpcb, struct pbuf* pb, int8_t err); - static int8_t _s_fin(void* arg, struct tcp_pcb* tpcb, int8_t err); - static int8_t _s_lwip_fin(void* arg, struct tcp_pcb* tpcb, int8_t err); - static void _s_error(void* arg, int8_t err); - static int8_t _s_sent(void* arg, struct tcp_pcb* tpcb, uint16_t len); - static int8_t _s_connected(void* arg, struct tcp_pcb* tpcb, int8_t err); - static void _s_dns_found(const char* name, struct ip_addr* ipaddr, void* arg); - - int8_t _recv(tcp_pcb* pcb, pbuf* pb, int8_t err); - tcp_pcb* pcb() { return _pcb; } - - protected: - bool _connect(ip_addr_t addr, uint16_t port); - - tcp_pcb* _pcb; - int8_t _closed_slot; - - AcConnectHandler _connect_cb; - void* _connect_cb_arg; - AcConnectHandler _discard_cb; - void* _discard_cb_arg; - AcAckHandler _sent_cb; - void* _sent_cb_arg; - AcErrorHandler _error_cb; - void* _error_cb_arg; - AcDataHandler _recv_cb; - void* _recv_cb_arg; - AcPacketHandler _pb_cb; - void* _pb_cb_arg; - AcTimeoutHandler _timeout_cb; - void* _timeout_cb_arg; - AcConnectHandler _poll_cb; - void* _poll_cb_arg; - - bool _ack_pcb; - uint32_t _tx_last_packet; - uint32_t _rx_ack_len; - uint32_t _rx_last_packet; - uint32_t _rx_timeout; - uint32_t _rx_last_ack; - uint32_t _ack_timeout; - uint16_t _connect_port; - - int8_t _close(); - void _free_closed_slot(); - bool _allocate_closed_slot(); - int8_t _connected(tcp_pcb* pcb, int8_t err); - void _error(int8_t err); - int8_t _poll(tcp_pcb* pcb); - int8_t _sent(tcp_pcb* pcb, uint16_t len); - int8_t _fin(tcp_pcb* pcb, int8_t err); - int8_t _lwip_fin(tcp_pcb* pcb, int8_t err); - void _dns_found(struct ip_addr* ipaddr); - - public: - AsyncClient* prev; - AsyncClient* next; -}; - -class AsyncServer { - public: - AsyncServer(IPAddress addr, uint16_t port); -#if ESP_IDF_VERSION_MAJOR < 5 - AsyncServer(IPv6Address addr, uint16_t port); -#endif - AsyncServer(uint16_t port); - ~AsyncServer(); - void onClient(AcConnectHandler cb, void* arg); - void begin(); - void end(); - void setNoDelay(bool nodelay); - bool getNoDelay(); - uint8_t status(); - - // Do not use any of the functions below! - static int8_t _s_accept(void* arg, tcp_pcb* newpcb, int8_t err); - static int8_t _s_accepted(void* arg, AsyncClient* client); - - protected: - uint16_t _port; - bool _bind4 = false; - bool _bind6 = false; - IPAddress _addr; -#if ESP_IDF_VERSION_MAJOR < 5 - IPv6Address _addr6; -#endif - bool _noDelay; - tcp_pcb* _pcb; - AcConnectHandler _connect_cb; - void* _connect_cb_arg; - - int8_t _accept(tcp_pcb* newpcb, int8_t err); - int8_t _accepted(AsyncClient* client); -}; - -#endif /* ASYNCTCP_H_ */ diff --git a/Software/src/lib/me-no-dev-AsyncTCP/.gitignore b/Software/src/lib/me-no-dev-AsyncTCP/.gitignore new file mode 100644 index 00000000..9bea4330 --- /dev/null +++ b/Software/src/lib/me-no-dev-AsyncTCP/.gitignore @@ -0,0 +1,2 @@ + +.DS_Store diff --git a/Software/src/lib/me-no-dev-AsyncTCP/.travis.yml b/Software/src/lib/me-no-dev-AsyncTCP/.travis.yml new file mode 100644 index 00000000..dbfc064a --- /dev/null +++ b/Software/src/lib/me-no-dev-AsyncTCP/.travis.yml @@ -0,0 +1,34 @@ +sudo: false +language: python +os: + - linux + +git: + depth: false + +stages: + - build + +jobs: + include: + + - name: "Arduino Build" + if: tag IS blank AND (type = pull_request OR (type = push AND branch = master)) + stage: build + script: bash $TRAVIS_BUILD_DIR/.github/scripts/on-push.sh + + - name: "PlatformIO Build" + if: tag IS blank AND (type = pull_request OR (type = push AND branch = master)) + stage: build + script: bash $TRAVIS_BUILD_DIR/.github/scripts/on-push.sh 1 1 + +notifications: + email: + on_success: change + on_failure: change + webhooks: + urls: + - https://webhooks.gitter.im/e/60e65d0c78ea0a920347 + on_success: change # options: [always|never|change] default: always + on_failure: always # options: [always|never|change] default: always + on_start: false # default: false diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/CMakeLists.txt b/Software/src/lib/me-no-dev-AsyncTCP/CMakeLists.txt similarity index 100% rename from Software/src/lib/mathieucarbou-AsyncTCP/CMakeLists.txt rename to Software/src/lib/me-no-dev-AsyncTCP/CMakeLists.txt diff --git a/Software/src/lib/me-no-dev-AsyncTCP/Kconfig.projbuild b/Software/src/lib/me-no-dev-AsyncTCP/Kconfig.projbuild new file mode 100644 index 00000000..17749264 --- /dev/null +++ b/Software/src/lib/me-no-dev-AsyncTCP/Kconfig.projbuild @@ -0,0 +1,30 @@ +menu "AsyncTCP Configuration" + +choice ASYNC_TCP_RUNNING_CORE + bool "Core on which AsyncTCP's thread is running" + default ASYNC_TCP_RUN_CORE1 + help + Select on which core AsyncTCP is running + + config ASYNC_TCP_RUN_CORE0 + bool "CORE 0" + config ASYNC_TCP_RUN_CORE1 + bool "CORE 1" + config ASYNC_TCP_RUN_NO_AFFINITY + bool "BOTH" + +endchoice + +config ASYNC_TCP_RUNNING_CORE + int + default 0 if ASYNC_TCP_RUN_CORE0 + default 1 if ASYNC_TCP_RUN_CORE1 + default -1 if ASYNC_TCP_RUN_NO_AFFINITY + +config ASYNC_TCP_USE_WDT + bool "Enable WDT for the AsyncTCP task" + default "y" + help + Enable WDT for the AsyncTCP task, so it will trigger if a handler is locking the thread. + +endmenu diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/LICENSE b/Software/src/lib/me-no-dev-AsyncTCP/LICENSE similarity index 100% rename from Software/src/lib/mathieucarbou-AsyncTCP/LICENSE rename to Software/src/lib/me-no-dev-AsyncTCP/LICENSE diff --git a/Software/src/lib/me-no-dev-AsyncTCP/README.md b/Software/src/lib/me-no-dev-AsyncTCP/README.md new file mode 100644 index 00000000..79ffa9ef --- /dev/null +++ b/Software/src/lib/me-no-dev-AsyncTCP/README.md @@ -0,0 +1,15 @@ +This is commit ca8ac5f from https://github.com/me-no-dev/AsyncTCP + +# AsyncTCP +[![Build Status](https://travis-ci.org/me-no-dev/AsyncTCP.svg?branch=master)](https://travis-ci.org/me-no-dev/AsyncTCP) ![](https://github.com/me-no-dev/AsyncTCP/workflows/Async%20TCP%20CI/badge.svg) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/2f7e4d1df8b446d192cbfec6dc174d2d)](https://www.codacy.com/manual/me-no-dev/AsyncTCP?utm_source=github.com&utm_medium=referral&utm_content=me-no-dev/AsyncTCP&utm_campaign=Badge_Grade) + +### Async TCP Library for ESP32 Arduino + +[![Join the chat at https://gitter.im/me-no-dev/ESPAsyncWebServer](https://badges.gitter.im/me-no-dev/ESPAsyncWebServer.svg)](https://gitter.im/me-no-dev/ESPAsyncWebServer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + +This is a fully asynchronous TCP library, aimed at enabling trouble-free, multi-connection network environment for Espressif's ESP32 MCUs. + +This library is the base for [ESPAsyncWebServer](https://github.com/me-no-dev/ESPAsyncWebServer) + +## AsyncClient and AsyncServer +The base classes on which everything else is built. They expose all possible scenarios, but are really raw and require more skills to use. diff --git a/Software/src/lib/mathieucarbou-AsyncTCP/component.mk b/Software/src/lib/me-no-dev-AsyncTCP/component.mk similarity index 100% rename from Software/src/lib/mathieucarbou-AsyncTCP/component.mk rename to Software/src/lib/me-no-dev-AsyncTCP/component.mk diff --git a/Software/src/lib/me-no-dev-AsyncTCP/library.json b/Software/src/lib/me-no-dev-AsyncTCP/library.json new file mode 100644 index 00000000..89f90e4e --- /dev/null +++ b/Software/src/lib/me-no-dev-AsyncTCP/library.json @@ -0,0 +1,22 @@ +{ + "name":"AsyncTCP", + "description":"Asynchronous TCP Library for ESP32", + "keywords":"async,tcp", + "authors": + { + "name": "Hristo Gochkov", + "maintainer": true + }, + "repository": + { + "type": "git", + "url": "https://github.com/me-no-dev/AsyncTCP.git" + }, + "version": "1.1.1", + "license": "LGPL-3.0", + "frameworks": "arduino", + "platforms": "espressif32", + "build": { + "libCompatMode": 2 + } +} diff --git a/Software/src/lib/me-no-dev-AsyncTCP/library.properties b/Software/src/lib/me-no-dev-AsyncTCP/library.properties new file mode 100644 index 00000000..eb4e26e9 --- /dev/null +++ b/Software/src/lib/me-no-dev-AsyncTCP/library.properties @@ -0,0 +1,9 @@ +name=AsyncTCP +version=1.1.1 +author=Me-No-Dev +maintainer=Me-No-Dev +sentence=Async TCP Library for ESP32 +paragraph=Async TCP Library for ESP32 +category=Other +url=https://github.com/me-no-dev/AsyncTCP +architectures=* diff --git a/Software/src/lib/me-no-dev-AsyncTCP/src/AsyncTCP.cpp b/Software/src/lib/me-no-dev-AsyncTCP/src/AsyncTCP.cpp new file mode 100644 index 00000000..acd89639 --- /dev/null +++ b/Software/src/lib/me-no-dev-AsyncTCP/src/AsyncTCP.cpp @@ -0,0 +1,1387 @@ +/* + Asynchronous TCP library for Espressif MCUs + + Copyright (c) 2016 Hristo Gochkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "Arduino.h" + +#include "AsyncTCP.h" +extern "C"{ +#include "lwip/opt.h" +#include "lwip/tcp.h" +#include "lwip/inet.h" +#include "lwip/dns.h" +#include "lwip/err.h" +} +#include "esp_task_wdt.h" + +/* + * TCP/IP Event Task + * */ + +#define TAG "AsyncTCP" + +// https://github.com/espressif/arduino-esp32/issues/10526 +#ifdef CONFIG_LWIP_TCPIP_CORE_LOCKING +#define TCP_MUTEX_LOCK() \ + if (!sys_thread_tcpip(LWIP_CORE_LOCK_QUERY_HOLDER)) { \ + LOCK_TCPIP_CORE(); \ + } + +#define TCP_MUTEX_UNLOCK() \ + if (sys_thread_tcpip(LWIP_CORE_LOCK_QUERY_HOLDER)) { \ + UNLOCK_TCPIP_CORE(); \ + } +#else // CONFIG_LWIP_TCPIP_CORE_LOCKING +#define TCP_MUTEX_LOCK() +#define TCP_MUTEX_UNLOCK() +#endif // CONFIG_LWIP_TCPIP_CORE_LOCKING + +typedef enum { + LWIP_TCP_SENT, LWIP_TCP_RECV, LWIP_TCP_FIN, LWIP_TCP_ERROR, LWIP_TCP_POLL, LWIP_TCP_CLEAR, LWIP_TCP_ACCEPT, LWIP_TCP_CONNECTED, LWIP_TCP_DNS +} lwip_event_t; + +typedef struct { + lwip_event_t event; + void *arg; + union { + struct { + void * pcb; + int8_t err; + } connected; + struct { + int8_t err; + } error; + struct { + tcp_pcb * pcb; + uint16_t len; + } sent; + struct { + tcp_pcb * pcb; + pbuf * pb; + int8_t err; + } recv; + struct { + tcp_pcb * pcb; + int8_t err; + } fin; + struct { + tcp_pcb * pcb; + } poll; + struct { + AsyncClient * client; + } accept; + struct { + const char * name; + ip_addr_t addr; + } dns; + }; +} lwip_event_packet_t; + +static xQueueHandle _async_queue; +static TaskHandle_t _async_service_task_handle = NULL; + + +SemaphoreHandle_t _slots_lock; +const int _number_of_closed_slots = CONFIG_LWIP_MAX_ACTIVE_TCP; +static uint32_t _closed_slots[_number_of_closed_slots]; +static uint32_t _closed_index = []() { + _slots_lock = xSemaphoreCreateBinary(); + xSemaphoreGive(_slots_lock); + for (int i = 0; i < _number_of_closed_slots; ++ i) { + _closed_slots[i] = 1; + } + return 1; +}(); + + +static inline bool _init_async_event_queue(){ + if(!_async_queue){ + _async_queue = xQueueCreate(32, sizeof(lwip_event_packet_t *)); + if(!_async_queue){ + return false; + } + } + return true; +} + +static inline bool _send_async_event(lwip_event_packet_t ** e){ + return _async_queue && xQueueSend(_async_queue, e, portMAX_DELAY) == pdPASS; +} + +static inline bool _prepend_async_event(lwip_event_packet_t ** e){ + return _async_queue && xQueueSendToFront(_async_queue, e, portMAX_DELAY) == pdPASS; +} + +static inline bool _get_async_event(lwip_event_packet_t ** e){ + return _async_queue && xQueueReceive(_async_queue, e, portMAX_DELAY) == pdPASS; +} + +static bool _remove_events_with_arg(void * arg){ + lwip_event_packet_t * first_packet = NULL; + lwip_event_packet_t * packet = NULL; + + if(!_async_queue){ + return false; + } + //figure out which is the first packet so we can keep the order + while(!first_packet){ + if(xQueueReceive(_async_queue, &first_packet, 0) != pdPASS){ + return false; + } + //discard packet if matching + if((int)first_packet->arg == (int)arg){ + free(first_packet); + first_packet = NULL; + //return first packet to the back of the queue + } else if(xQueueSend(_async_queue, &first_packet, portMAX_DELAY) != pdPASS){ + return false; + } + } + + while(xQueuePeek(_async_queue, &packet, 0) == pdPASS && packet != first_packet){ + if(xQueueReceive(_async_queue, &packet, 0) != pdPASS){ + return false; + } + if((int)packet->arg == (int)arg){ + free(packet); + packet = NULL; + } else if(xQueueSend(_async_queue, &packet, portMAX_DELAY) != pdPASS){ + return false; + } + } + return true; +} + +static void _handle_async_event(lwip_event_packet_t * e){ + if(e->arg == NULL){ + // do nothing when arg is NULL + //ets_printf("event arg == NULL: 0x%08x\n", e->recv.pcb); + } else if(e->event == LWIP_TCP_CLEAR){ + _remove_events_with_arg(e->arg); + } else if(e->event == LWIP_TCP_RECV){ + //ets_printf("-R: 0x%08x\n", e->recv.pcb); + AsyncClient::_s_recv(e->arg, e->recv.pcb, e->recv.pb, e->recv.err); + } else if(e->event == LWIP_TCP_FIN){ + //ets_printf("-F: 0x%08x\n", e->fin.pcb); + AsyncClient::_s_fin(e->arg, e->fin.pcb, e->fin.err); + } else if(e->event == LWIP_TCP_SENT){ + //ets_printf("-S: 0x%08x\n", e->sent.pcb); + AsyncClient::_s_sent(e->arg, e->sent.pcb, e->sent.len); + } else if(e->event == LWIP_TCP_POLL){ + //ets_printf("-P: 0x%08x\n", e->poll.pcb); + AsyncClient::_s_poll(e->arg, e->poll.pcb); + } else if(e->event == LWIP_TCP_ERROR){ + //ets_printf("-E: 0x%08x %d\n", e->arg, e->error.err); + AsyncClient::_s_error(e->arg, e->error.err); + } else if(e->event == LWIP_TCP_CONNECTED){ + //ets_printf("C: 0x%08x 0x%08x %d\n", e->arg, e->connected.pcb, e->connected.err); + AsyncClient::_s_connected(e->arg, e->connected.pcb, e->connected.err); + } else if(e->event == LWIP_TCP_ACCEPT){ + //ets_printf("A: 0x%08x 0x%08x\n", e->arg, e->accept.client); + AsyncServer::_s_accepted(e->arg, e->accept.client); + } else if(e->event == LWIP_TCP_DNS){ + //ets_printf("D: 0x%08x %s = %s\n", e->arg, e->dns.name, ipaddr_ntoa(&e->dns.addr)); + AsyncClient::_s_dns_found(e->dns.name, &e->dns.addr, e->arg); + } + free((void*)(e)); +} + +static void _async_service_task(void *pvParameters){ + lwip_event_packet_t * packet = NULL; + for (;;) { + if(_get_async_event(&packet)){ +#if CONFIG_ASYNC_TCP_USE_WDT + if(esp_task_wdt_add(NULL) != ESP_OK){ + log_e("Failed to add async task to WDT"); + } +#endif + _handle_async_event(packet); +#if CONFIG_ASYNC_TCP_USE_WDT + if(esp_task_wdt_delete(NULL) != ESP_OK){ + log_e("Failed to remove loop task from WDT"); + } +#endif + } + } + vTaskDelete(NULL); + _async_service_task_handle = NULL; +} +/* +static void _stop_async_task(){ + if(_async_service_task_handle){ + vTaskDelete(_async_service_task_handle); + _async_service_task_handle = NULL; + } +} +*/ +static bool _start_async_task(){ + if(!_init_async_event_queue()){ + return false; + } + if(!_async_service_task_handle){ + xTaskCreateUniversal(_async_service_task, "async_tcp", 8192 * 2, NULL, TASK_CONNECTIVITY_PRIO, &_async_service_task_handle, CONFIG_ASYNC_TCP_RUNNING_CORE); + if(!_async_service_task_handle){ + return false; + } + } + return true; +} + +/* + * LwIP Callbacks + * */ + +static int8_t _tcp_clear_events(void * arg) { + lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t)); + e->event = LWIP_TCP_CLEAR; + e->arg = arg; + if (!_prepend_async_event(&e)) { + free((void*)(e)); + } + return ERR_OK; +} + +static int8_t _tcp_connected(void * arg, tcp_pcb * pcb, int8_t err) { + //ets_printf("+C: 0x%08x\n", pcb); + lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t)); + e->event = LWIP_TCP_CONNECTED; + e->arg = arg; + e->connected.pcb = pcb; + e->connected.err = err; + if (!_prepend_async_event(&e)) { + free((void*)(e)); + } + return ERR_OK; +} + +static int8_t _tcp_poll(void * arg, struct tcp_pcb * pcb) { + //ets_printf("+P: 0x%08x\n", pcb); + lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t)); + e->event = LWIP_TCP_POLL; + e->arg = arg; + e->poll.pcb = pcb; + if (!_send_async_event(&e)) { + free((void*)(e)); + } + return ERR_OK; +} + +static int8_t _tcp_recv(void * arg, struct tcp_pcb * pcb, struct pbuf *pb, int8_t err) { + lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t)); + e->arg = arg; + if(pb){ + //ets_printf("+R: 0x%08x\n", pcb); + e->event = LWIP_TCP_RECV; + e->recv.pcb = pcb; + e->recv.pb = pb; + e->recv.err = err; + } else { + //ets_printf("+F: 0x%08x\n", pcb); + e->event = LWIP_TCP_FIN; + e->fin.pcb = pcb; + e->fin.err = err; + //close the PCB in LwIP thread + AsyncClient::_s_lwip_fin(e->arg, e->fin.pcb, e->fin.err); + } + if (!_send_async_event(&e)) { + free((void*)(e)); + } + return ERR_OK; +} + +static int8_t _tcp_sent(void * arg, struct tcp_pcb * pcb, uint16_t len) { + //ets_printf("+S: 0x%08x\n", pcb); + lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t)); + e->event = LWIP_TCP_SENT; + e->arg = arg; + e->sent.pcb = pcb; + e->sent.len = len; + if (!_send_async_event(&e)) { + free((void*)(e)); + } + return ERR_OK; +} + +static void _tcp_error(void * arg, int8_t err) { + //ets_printf("+E: 0x%08x\n", arg); + lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t)); + e->event = LWIP_TCP_ERROR; + e->arg = arg; + e->error.err = err; + if (!_send_async_event(&e)) { + free((void*)(e)); + } +} + +static void _tcp_dns_found(const char * name, struct ip_addr * ipaddr, void * arg) { + lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t)); + //ets_printf("+DNS: name=%s ipaddr=0x%08x arg=%x\n", name, ipaddr, arg); + e->event = LWIP_TCP_DNS; + e->arg = arg; + e->dns.name = name; + if (ipaddr) { + memcpy(&e->dns.addr, ipaddr, sizeof(struct ip_addr)); + } else { + memset(&e->dns.addr, 0, sizeof(e->dns.addr)); + } + if (!_send_async_event(&e)) { + free((void*)(e)); + } +} + +//Used to switch out from LwIP thread +static int8_t _tcp_accept(void * arg, AsyncClient * client) { + lwip_event_packet_t * e = (lwip_event_packet_t *)malloc(sizeof(lwip_event_packet_t)); + e->event = LWIP_TCP_ACCEPT; + e->arg = arg; + e->accept.client = client; + if (!_prepend_async_event(&e)) { + free((void*)(e)); + } + return ERR_OK; +} + +/* + * TCP/IP API Calls + * */ + +#include "lwip/priv/tcpip_priv.h" + +typedef struct { + struct tcpip_api_call_data call; + tcp_pcb * pcb; + int8_t closed_slot; + int8_t err; + union { + struct { + const char* data; + size_t size; + uint8_t apiflags; + } write; + size_t received; + struct { + ip_addr_t * addr; + uint16_t port; + tcp_connected_fn cb; + } connect; + struct { + ip_addr_t * addr; + uint16_t port; + } bind; + uint8_t backlog; + }; +} tcp_api_call_t; + +static err_t _tcp_output_api(struct tcpip_api_call_data *api_call_msg){ + tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; + msg->err = ERR_CONN; + if(msg->closed_slot == -1 || !_closed_slots[msg->closed_slot]) { + msg->err = tcp_output(msg->pcb); + } + return msg->err; +} + +static esp_err_t _tcp_output(tcp_pcb * pcb, int8_t closed_slot) { + if(!pcb){ + return ERR_CONN; + } + tcp_api_call_t msg; + msg.pcb = pcb; + msg.closed_slot = closed_slot; + tcpip_api_call(_tcp_output_api, (struct tcpip_api_call_data*)&msg); + return msg.err; +} + +static err_t _tcp_write_api(struct tcpip_api_call_data *api_call_msg){ + tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; + msg->err = ERR_CONN; + if(msg->closed_slot == -1 || !_closed_slots[msg->closed_slot]) { + msg->err = tcp_write(msg->pcb, msg->write.data, msg->write.size, msg->write.apiflags); + } + return msg->err; +} + +static esp_err_t _tcp_write(tcp_pcb * pcb, int8_t closed_slot, const char* data, size_t size, uint8_t apiflags) { + if(!pcb){ + return ERR_CONN; + } + tcp_api_call_t msg; + msg.pcb = pcb; + msg.closed_slot = closed_slot; + msg.write.data = data; + msg.write.size = size; + msg.write.apiflags = apiflags; + tcpip_api_call(_tcp_write_api, (struct tcpip_api_call_data*)&msg); + return msg.err; +} + +static err_t _tcp_recved_api(struct tcpip_api_call_data *api_call_msg){ + tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; + msg->err = ERR_CONN; + if(msg->closed_slot == -1 || !_closed_slots[msg->closed_slot]) { + msg->err = 0; + tcp_recved(msg->pcb, msg->received); + } + return msg->err; +} + +static esp_err_t _tcp_recved(tcp_pcb * pcb, int8_t closed_slot, size_t len) { + if(!pcb){ + return ERR_CONN; + } + tcp_api_call_t msg; + msg.pcb = pcb; + msg.closed_slot = closed_slot; + msg.received = len; + tcpip_api_call(_tcp_recved_api, (struct tcpip_api_call_data*)&msg); + return msg.err; +} + +static err_t _tcp_close_api(struct tcpip_api_call_data *api_call_msg){ + tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; + msg->err = ERR_CONN; + if(msg->closed_slot == -1 || !_closed_slots[msg->closed_slot]) { + msg->err = tcp_close(msg->pcb); + } + return msg->err; +} + +static esp_err_t _tcp_close(tcp_pcb * pcb, int8_t closed_slot) { + if(!pcb){ + return ERR_CONN; + } + tcp_api_call_t msg; + msg.pcb = pcb; + msg.closed_slot = closed_slot; + tcpip_api_call(_tcp_close_api, (struct tcpip_api_call_data*)&msg); + return msg.err; +} + +static err_t _tcp_abort_api(struct tcpip_api_call_data *api_call_msg){ + tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; + msg->err = ERR_CONN; + if(msg->closed_slot == -1 || !_closed_slots[msg->closed_slot]) { + tcp_abort(msg->pcb); + } + return msg->err; +} + +static esp_err_t _tcp_abort(tcp_pcb * pcb, int8_t closed_slot) { + if(!pcb){ + return ERR_CONN; + } + tcp_api_call_t msg; + msg.pcb = pcb; + msg.closed_slot = closed_slot; + tcpip_api_call(_tcp_abort_api, (struct tcpip_api_call_data*)&msg); + return msg.err; +} + +static err_t _tcp_connect_api(struct tcpip_api_call_data *api_call_msg){ + tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; + msg->err = tcp_connect(msg->pcb, msg->connect.addr, msg->connect.port, msg->connect.cb); + return msg->err; +} + +static esp_err_t _tcp_connect(tcp_pcb * pcb, int8_t closed_slot, ip_addr_t * addr, uint16_t port, tcp_connected_fn cb) { + if(!pcb){ + return ESP_FAIL; + } + tcp_api_call_t msg; + msg.pcb = pcb; + msg.closed_slot = closed_slot; + msg.connect.addr = addr; + msg.connect.port = port; + msg.connect.cb = cb; + tcpip_api_call(_tcp_connect_api, (struct tcpip_api_call_data*)&msg); + return msg.err; +} + +static err_t _tcp_bind_api(struct tcpip_api_call_data *api_call_msg){ + tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; + msg->err = tcp_bind(msg->pcb, msg->bind.addr, msg->bind.port); + return msg->err; +} + +static esp_err_t _tcp_bind(tcp_pcb * pcb, ip_addr_t * addr, uint16_t port) { + if(!pcb){ + return ESP_FAIL; + } + tcp_api_call_t msg; + msg.pcb = pcb; + msg.closed_slot = -1; + msg.bind.addr = addr; + msg.bind.port = port; + tcpip_api_call(_tcp_bind_api, (struct tcpip_api_call_data*)&msg); + return msg.err; +} + +static err_t _tcp_listen_api(struct tcpip_api_call_data *api_call_msg){ + tcp_api_call_t * msg = (tcp_api_call_t *)api_call_msg; + msg->err = 0; + msg->pcb = tcp_listen_with_backlog(msg->pcb, msg->backlog); + return msg->err; +} + +static tcp_pcb * _tcp_listen_with_backlog(tcp_pcb * pcb, uint8_t backlog) { + if(!pcb){ + return NULL; + } + tcp_api_call_t msg; + msg.pcb = pcb; + msg.closed_slot = -1; + msg.backlog = backlog?backlog:0xFF; + tcpip_api_call(_tcp_listen_api, (struct tcpip_api_call_data*)&msg); + return msg.pcb; +} + + + +/* + Async TCP Client + */ + +AsyncClient::AsyncClient(tcp_pcb* pcb) +: _connect_cb(0) +, _connect_cb_arg(0) +, _discard_cb(0) +, _discard_cb_arg(0) +, _sent_cb(0) +, _sent_cb_arg(0) +, _error_cb(0) +, _error_cb_arg(0) +, _recv_cb(0) +, _recv_cb_arg(0) +, _pb_cb(0) +, _pb_cb_arg(0) +, _timeout_cb(0) +, _timeout_cb_arg(0) +, _pcb_busy(false) +, _pcb_sent_at(0) +, _ack_pcb(true) +, _rx_last_packet(0) +, _rx_since_timeout(0) +, _ack_timeout(ASYNC_MAX_ACK_TIME) +, _connect_port(0) +, prev(NULL) +, next(NULL) +{ + _pcb = pcb; + _closed_slot = -1; + if(_pcb){ + _allocate_closed_slot(); + _rx_last_packet = millis(); + tcp_arg(_pcb, this); + tcp_recv(_pcb, &_tcp_recv); + tcp_sent(_pcb, &_tcp_sent); + tcp_err(_pcb, &_tcp_error); + tcp_poll(_pcb, &_tcp_poll, 1); + } +} + +AsyncClient::~AsyncClient(){ + if(_pcb) { + _close(); + } + _free_closed_slot(); +} + +/* + * Operators + * */ + +AsyncClient& AsyncClient::operator=(const AsyncClient& other){ + if (_pcb) { + _close(); + } + + _pcb = other._pcb; + _closed_slot = other._closed_slot; + if (_pcb) { + _rx_last_packet = millis(); + tcp_arg(_pcb, this); + tcp_recv(_pcb, &_tcp_recv); + tcp_sent(_pcb, &_tcp_sent); + tcp_err(_pcb, &_tcp_error); + tcp_poll(_pcb, &_tcp_poll, 1); + } + return *this; +} + +bool AsyncClient::operator==(const AsyncClient &other) { + return _pcb == other._pcb; +} + +AsyncClient & AsyncClient::operator+=(const AsyncClient &other) { + if(next == NULL){ + next = (AsyncClient*)(&other); + next->prev = this; + } else { + AsyncClient *c = next; + while(c->next != NULL) { + c = c->next; + } + c->next =(AsyncClient*)(&other); + c->next->prev = c; + } + return *this; +} + +/* + * Callback Setters + * */ + +void AsyncClient::onConnect(AcConnectHandler cb, void* arg){ + _connect_cb = cb; + _connect_cb_arg = arg; +} + +void AsyncClient::onDisconnect(AcConnectHandler cb, void* arg){ + _discard_cb = cb; + _discard_cb_arg = arg; +} + +void AsyncClient::onAck(AcAckHandler cb, void* arg){ + _sent_cb = cb; + _sent_cb_arg = arg; +} + +void AsyncClient::onError(AcErrorHandler cb, void* arg){ + _error_cb = cb; + _error_cb_arg = arg; +} + +void AsyncClient::onData(AcDataHandler cb, void* arg){ + _recv_cb = cb; + _recv_cb_arg = arg; +} + +void AsyncClient::onPacket(AcPacketHandler cb, void* arg){ + _pb_cb = cb; + _pb_cb_arg = arg; +} + +void AsyncClient::onTimeout(AcTimeoutHandler cb, void* arg){ + _timeout_cb = cb; + _timeout_cb_arg = arg; +} + +void AsyncClient::onPoll(AcConnectHandler cb, void* arg){ + _poll_cb = cb; + _poll_cb_arg = arg; +} + +/* + * Main Public Methods + * */ + +bool AsyncClient::connect(IPAddress ip, uint16_t port){ + if (_pcb){ + log_w("already connected, state %d", _pcb->state); + return false; + } + if(!_start_async_task()){ + log_e("failed to start task"); + return false; + } + + ip_addr_t addr; + addr.type = IPADDR_TYPE_V4; + addr.u_addr.ip4.addr = ip; + + TCP_MUTEX_LOCK(); + tcp_pcb* pcb = tcp_new_ip_type(IPADDR_TYPE_V4); + if (!pcb){ + TCP_MUTEX_UNLOCK(); + log_e("pcb == NULL"); + return false; + } + + tcp_arg(pcb, this); + tcp_err(pcb, &_tcp_error); + tcp_recv(pcb, &_tcp_recv); + tcp_sent(pcb, &_tcp_sent); + tcp_poll(pcb, &_tcp_poll, 1); + TCP_MUTEX_UNLOCK(); + //_tcp_connect(pcb, &addr, port,(tcp_connected_fn)&_s_connected); + _tcp_connect(pcb, _closed_slot, &addr, port,(tcp_connected_fn)&_tcp_connected); + return true; +} + +bool AsyncClient::connect(const char* host, uint16_t port){ + ip_addr_t addr; + + if(!_start_async_task()){ + log_e("failed to start task"); + return false; + } + TCP_MUTEX_LOCK(); + err_t err = dns_gethostbyname(host, &addr, (dns_found_callback)&_tcp_dns_found, this); + TCP_MUTEX_UNLOCK(); + if(err == ERR_OK) { + return connect(IPAddress(addr.u_addr.ip4.addr), port); + } else if(err == ERR_INPROGRESS) { + _connect_port = port; + return true; + } + log_e("error: %d", err); + return false; +} + +void AsyncClient::close(bool now){ + if(_pcb){ + _tcp_recved(_pcb, _closed_slot, _rx_ack_len); + } + _close(); +} + +int8_t AsyncClient::abort(){ + if(_pcb) { + _tcp_abort(_pcb, _closed_slot ); + _pcb = NULL; + } + return ERR_ABRT; +} + +size_t AsyncClient::space(){ + if((_pcb != NULL) && (_pcb->state == 4)){ + return tcp_sndbuf(_pcb); + } + return 0; +} + +size_t AsyncClient::add(const char* data, size_t size, uint8_t apiflags) { + if(!_pcb || size == 0 || data == NULL) { + return 0; + } + size_t room = space(); + if(!room) { + return 0; + } + size_t will_send = (room < size) ? room : size; + int8_t err = ERR_OK; + err = _tcp_write(_pcb, _closed_slot, data, will_send, apiflags); + if(err != ERR_OK) { + return 0; + } + return will_send; +} + +bool AsyncClient::send(){ + int8_t err = ERR_OK; + err = _tcp_output(_pcb, _closed_slot); + if(err == ERR_OK){ + _pcb_busy = true; + _pcb_sent_at = millis(); + return true; + } + return false; +} + +size_t AsyncClient::ack(size_t len){ + if(len > _rx_ack_len) + len = _rx_ack_len; + if(len){ + _tcp_recved(_pcb, _closed_slot, len); + } + _rx_ack_len -= len; + return len; +} + +void AsyncClient::ackPacket(struct pbuf * pb){ + if(!pb){ + return; + } + _tcp_recved(_pcb, _closed_slot, pb->len); + pbuf_free(pb); +} + +/* + * Main Private Methods + * */ + +int8_t AsyncClient::_close(){ + //ets_printf("X: 0x%08x\n", (uint32_t)this); + int8_t err = ERR_OK; + if(_pcb) { + //log_i(""); + TCP_MUTEX_LOCK(); + tcp_arg(_pcb, NULL); + tcp_sent(_pcb, NULL); + tcp_recv(_pcb, NULL); + tcp_err(_pcb, NULL); + tcp_poll(_pcb, NULL, 0); + TCP_MUTEX_UNLOCK(); + _tcp_clear_events(this); + err = _tcp_close(_pcb, _closed_slot); + if(err != ERR_OK) { + err = abort(); + } + _pcb = NULL; + if(_discard_cb) { + _discard_cb(_discard_cb_arg, this); + } + } + return err; +} + +void AsyncClient::_allocate_closed_slot(){ + xSemaphoreTake(_slots_lock, portMAX_DELAY); + uint32_t closed_slot_min_index = 0; + for (int i = 0; i < _number_of_closed_slots; ++ i) { + if ((_closed_slot == -1 || _closed_slots[i] <= closed_slot_min_index) && _closed_slots[i] != 0) { + closed_slot_min_index = _closed_slots[i]; + _closed_slot = i; + } + } + if (_closed_slot != -1) { + _closed_slots[_closed_slot] = 0; + } + xSemaphoreGive(_slots_lock); +} + +void AsyncClient::_free_closed_slot(){ + if (_closed_slot != -1) { + _closed_slots[_closed_slot] = _closed_index; + _closed_slot = -1; + ++ _closed_index; + } +} + +/* + * Private Callbacks + * */ + +int8_t AsyncClient::_connected(void* pcb, int8_t err){ + _pcb = reinterpret_cast(pcb); + if(_pcb){ + _rx_last_packet = millis(); + _pcb_busy = false; +// tcp_recv(_pcb, &_tcp_recv); +// tcp_sent(_pcb, &_tcp_sent); +// tcp_poll(_pcb, &_tcp_poll, 1); + } + if(_connect_cb) { + _connect_cb(_connect_cb_arg, this); + } + return ERR_OK; +} + +void AsyncClient::_error(int8_t err) { + if(_pcb){ + tcp_arg(_pcb, NULL); + if(_pcb->state == LISTEN) { + tcp_sent(_pcb, NULL); + tcp_recv(_pcb, NULL); + tcp_err(_pcb, NULL); + tcp_poll(_pcb, NULL, 0); + } + _pcb = NULL; + } + if(_error_cb) { + _error_cb(_error_cb_arg, this, err); + } + if(_discard_cb) { + _discard_cb(_discard_cb_arg, this); + } +} + +//In LwIP Thread +int8_t AsyncClient::_lwip_fin(tcp_pcb* pcb, int8_t err) { + if(!_pcb || pcb != _pcb){ + log_e("0x%08x != 0x%08x", (uint32_t)pcb, (uint32_t)_pcb); + return ERR_OK; + } + tcp_arg(_pcb, NULL); + if(_pcb->state == LISTEN) { + tcp_sent(_pcb, NULL); + tcp_recv(_pcb, NULL); + tcp_err(_pcb, NULL); + tcp_poll(_pcb, NULL, 0); + } + if(tcp_close(_pcb) != ERR_OK) { + tcp_abort(_pcb); + } + _free_closed_slot(); + _pcb = NULL; + return ERR_OK; +} + +//In Async Thread +int8_t AsyncClient::_fin(tcp_pcb* pcb, int8_t err) { + _tcp_clear_events(this); + if(_discard_cb) { + _discard_cb(_discard_cb_arg, this); + } + return ERR_OK; +} + +int8_t AsyncClient::_sent(tcp_pcb* pcb, uint16_t len) { + _rx_last_packet = millis(); + //log_i("%u", len); + _pcb_busy = false; + if(_sent_cb) { + _sent_cb(_sent_cb_arg, this, len, (millis() - _pcb_sent_at)); + } + return ERR_OK; +} + +int8_t AsyncClient::_recv(tcp_pcb* pcb, pbuf* pb, int8_t err) { + while(pb != NULL) { + _rx_last_packet = millis(); + //we should not ack before we assimilate the data + _ack_pcb = true; + pbuf *b = pb; + pb = b->next; + b->next = NULL; + if(_pb_cb){ + _pb_cb(_pb_cb_arg, this, b); + } else { + if(_recv_cb) { + _recv_cb(_recv_cb_arg, this, b->payload, b->len); + } + if(!_ack_pcb) { + _rx_ack_len += b->len; + } else if(_pcb) { + _tcp_recved(_pcb, _closed_slot, b->len); + } + pbuf_free(b); + } + } + return ERR_OK; +} + +int8_t AsyncClient::_poll(tcp_pcb* pcb){ + if(!_pcb){ + log_w("pcb is NULL"); + return ERR_OK; + } + if(pcb != _pcb){ + log_e("0x%08x != 0x%08x", (uint32_t)pcb, (uint32_t)_pcb); + return ERR_OK; + } + + uint32_t now = millis(); + + // ACK Timeout + if(_pcb_busy && _ack_timeout && (now - _pcb_sent_at) >= _ack_timeout){ + _pcb_busy = false; + log_w("ack timeout %d", pcb->state); + if(_timeout_cb) + _timeout_cb(_timeout_cb_arg, this, (now - _pcb_sent_at)); + return ERR_OK; + } + // RX Timeout + if(_rx_since_timeout && (now - _rx_last_packet) >= (_rx_since_timeout * 1000)){ + log_w("rx timeout %d", pcb->state); + _close(); + return ERR_OK; + } + // Everything is fine + if(_poll_cb) { + _poll_cb(_poll_cb_arg, this); + } + return ERR_OK; +} + +void AsyncClient::_dns_found(struct ip_addr *ipaddr){ + if(ipaddr && ipaddr->u_addr.ip4.addr){ + connect(IPAddress(ipaddr->u_addr.ip4.addr), _connect_port); + } else { + if(_error_cb) { + _error_cb(_error_cb_arg, this, -55); + } + if(_discard_cb) { + _discard_cb(_discard_cb_arg, this); + } + } +} + +/* + * Public Helper Methods + * */ + +void AsyncClient::stop() { + close(false); +} + +bool AsyncClient::free(){ + if(!_pcb) { + return true; + } + if(_pcb->state == 0 || _pcb->state > 4) { + return true; + } + return false; +} + +size_t AsyncClient::write(const char* data) { + if(data == NULL) { + return 0; + } + return write(data, strlen(data)); +} + +size_t AsyncClient::write(const char* data, size_t size, uint8_t apiflags) { + size_t will_send = add(data, size, apiflags); + if(!will_send || !send()) { + return 0; + } + return will_send; +} + +void AsyncClient::setRxTimeout(uint32_t timeout){ + _rx_since_timeout = timeout; +} + +uint32_t AsyncClient::getRxTimeout(){ + return _rx_since_timeout; +} + +uint32_t AsyncClient::getAckTimeout(){ + return _ack_timeout; +} + +void AsyncClient::setAckTimeout(uint32_t timeout){ + _ack_timeout = timeout; +} + +void AsyncClient::setNoDelay(bool nodelay){ + if(!_pcb) { + return; + } + if(nodelay) { + tcp_nagle_disable(_pcb); + } else { + tcp_nagle_enable(_pcb); + } +} + +bool AsyncClient::getNoDelay(){ + if(!_pcb) { + return false; + } + return tcp_nagle_disabled(_pcb); +} + +uint16_t AsyncClient::getMss(){ + if(!_pcb) { + return 0; + } + return tcp_mss(_pcb); +} + +uint32_t AsyncClient::getRemoteAddress() { + if(!_pcb) { + return 0; + } + return _pcb->remote_ip.u_addr.ip4.addr; +} + +uint16_t AsyncClient::getRemotePort() { + if(!_pcb) { + return 0; + } + return _pcb->remote_port; +} + +uint32_t AsyncClient::getLocalAddress() { + if(!_pcb) { + return 0; + } + return _pcb->local_ip.u_addr.ip4.addr; +} + +uint16_t AsyncClient::getLocalPort() { + if(!_pcb) { + return 0; + } + return _pcb->local_port; +} + +IPAddress AsyncClient::remoteIP() { + return IPAddress(getRemoteAddress()); +} + +uint16_t AsyncClient::remotePort() { + return getRemotePort(); +} + +IPAddress AsyncClient::localIP() { + return IPAddress(getLocalAddress()); +} + +uint16_t AsyncClient::localPort() { + return getLocalPort(); +} + +uint8_t AsyncClient::state() { + if(!_pcb) { + return 0; + } + return _pcb->state; +} + +bool AsyncClient::connected(){ + if (!_pcb) { + return false; + } + return _pcb->state == 4; +} + +bool AsyncClient::connecting(){ + if (!_pcb) { + return false; + } + return _pcb->state > 0 && _pcb->state < 4; +} + +bool AsyncClient::disconnecting(){ + if (!_pcb) { + return false; + } + return _pcb->state > 4 && _pcb->state < 10; +} + +bool AsyncClient::disconnected(){ + if (!_pcb) { + return true; + } + return _pcb->state == 0 || _pcb->state == 10; +} + +bool AsyncClient::freeable(){ + if (!_pcb) { + return true; + } + return _pcb->state == 0 || _pcb->state > 4; +} + +bool AsyncClient::canSend(){ + return space() > 0; +} + +const char * AsyncClient::errorToString(int8_t error){ + switch(error){ + case ERR_OK: return "OK"; + case ERR_MEM: return "Out of memory error"; + case ERR_BUF: return "Buffer error"; + case ERR_TIMEOUT: return "Timeout"; + case ERR_RTE: return "Routing problem"; + case ERR_INPROGRESS: return "Operation in progress"; + case ERR_VAL: return "Illegal value"; + case ERR_WOULDBLOCK: return "Operation would block"; + case ERR_USE: return "Address in use"; + case ERR_ALREADY: return "Already connected"; + case ERR_CONN: return "Not connected"; + case ERR_IF: return "Low-level netif error"; + case ERR_ABRT: return "Connection aborted"; + case ERR_RST: return "Connection reset"; + case ERR_CLSD: return "Connection closed"; + case ERR_ARG: return "Illegal argument"; + case -55: return "DNS failed"; + default: return "UNKNOWN"; + } +} + +const char * AsyncClient::stateToString(){ + switch(state()){ + case 0: return "Closed"; + case 1: return "Listen"; + case 2: return "SYN Sent"; + case 3: return "SYN Received"; + case 4: return "Established"; + case 5: return "FIN Wait 1"; + case 6: return "FIN Wait 2"; + case 7: return "Close Wait"; + case 8: return "Closing"; + case 9: return "Last ACK"; + case 10: return "Time Wait"; + default: return "UNKNOWN"; + } +} + +/* + * Static Callbacks (LwIP C2C++ interconnect) + * */ + +void AsyncClient::_s_dns_found(const char * name, struct ip_addr * ipaddr, void * arg){ + reinterpret_cast(arg)->_dns_found(ipaddr); +} + +int8_t AsyncClient::_s_poll(void * arg, struct tcp_pcb * pcb) { + return reinterpret_cast(arg)->_poll(pcb); +} + +int8_t AsyncClient::_s_recv(void * arg, struct tcp_pcb * pcb, struct pbuf *pb, int8_t err) { + return reinterpret_cast(arg)->_recv(pcb, pb, err); +} + +int8_t AsyncClient::_s_fin(void * arg, struct tcp_pcb * pcb, int8_t err) { + return reinterpret_cast(arg)->_fin(pcb, err); +} + +int8_t AsyncClient::_s_lwip_fin(void * arg, struct tcp_pcb * pcb, int8_t err) { + return reinterpret_cast(arg)->_lwip_fin(pcb, err); +} + +int8_t AsyncClient::_s_sent(void * arg, struct tcp_pcb * pcb, uint16_t len) { + return reinterpret_cast(arg)->_sent(pcb, len); +} + +void AsyncClient::_s_error(void * arg, int8_t err) { + reinterpret_cast(arg)->_error(err); +} + +int8_t AsyncClient::_s_connected(void * arg, void * pcb, int8_t err){ + return reinterpret_cast(arg)->_connected(pcb, err); +} + +/* + Async TCP Server + */ + +AsyncServer::AsyncServer(IPAddress addr, uint16_t port) +: _port(port) +, _addr(addr) +, _noDelay(false) +, _pcb(0) +, _connect_cb(0) +, _connect_cb_arg(0) +{} + +AsyncServer::AsyncServer(uint16_t port) +: _port(port) +, _addr((uint32_t) IPADDR_ANY) +, _noDelay(false) +, _pcb(0) +, _connect_cb(0) +, _connect_cb_arg(0) +{} + +AsyncServer::~AsyncServer(){ + end(); +} + +void AsyncServer::onClient(AcConnectHandler cb, void* arg){ + _connect_cb = cb; + _connect_cb_arg = arg; +} + +void AsyncServer::begin(){ + if(_pcb) { + return; + } + + if(!_start_async_task()){ + log_e("failed to start task"); + return; + } + int8_t err; + TCP_MUTEX_LOCK(); + _pcb = tcp_new_ip_type(IPADDR_TYPE_V4); + TCP_MUTEX_UNLOCK(); + if (!_pcb){ + log_e("_pcb == NULL"); + return; + } + + ip_addr_t local_addr; + local_addr.type = IPADDR_TYPE_V4; + local_addr.u_addr.ip4.addr = (uint32_t) _addr; + err = _tcp_bind(_pcb, &local_addr, _port); + + if (err != ERR_OK) { + _tcp_close(_pcb, -1); + log_e("bind error: %d", err); + return; + } + + static uint8_t backlog = 5; + _pcb = _tcp_listen_with_backlog(_pcb, backlog); + if (!_pcb) { + log_e("listen_pcb == NULL"); + return; + } + TCP_MUTEX_LOCK(); + tcp_arg(_pcb, (void*) this); + tcp_accept(_pcb, &_s_accept); + TCP_MUTEX_UNLOCK(); +} + +void AsyncServer::end(){ + if(_pcb){ + TCP_MUTEX_LOCK(); + tcp_arg(_pcb, NULL); + tcp_accept(_pcb, NULL); + TCP_MUTEX_UNLOCK(); + if(tcp_close(_pcb) != ERR_OK){ + _tcp_abort(_pcb, -1); + } + _pcb = NULL; + } +} + +//runs on LwIP thread +int8_t AsyncServer::_accept(tcp_pcb* pcb, int8_t err){ + //ets_printf("+A: 0x%08x\n", pcb); + if(_connect_cb){ + AsyncClient *c = new AsyncClient(pcb); + if(c){ + c->setNoDelay(_noDelay); + return _tcp_accept(this, c); + } + } + if(tcp_close(pcb) != ERR_OK){ + tcp_abort(pcb); + } + log_e("FAIL"); + return ERR_OK; +} + +int8_t AsyncServer::_accepted(AsyncClient* client){ + if(_connect_cb){ + _connect_cb(_connect_cb_arg, client); + } + return ERR_OK; +} + +void AsyncServer::setNoDelay(bool nodelay){ + _noDelay = nodelay; +} + +bool AsyncServer::getNoDelay(){ + return _noDelay; +} + +uint8_t AsyncServer::status(){ + if (!_pcb) { + return 0; + } + return _pcb->state; +} + +int8_t AsyncServer::_s_accept(void * arg, tcp_pcb * pcb, int8_t err){ + return reinterpret_cast(arg)->_accept(pcb, err); +} + +int8_t AsyncServer::_s_accepted(void *arg, AsyncClient* client){ + return reinterpret_cast(arg)->_accepted(client); +} diff --git a/Software/src/lib/me-no-dev-AsyncTCP/src/AsyncTCP.h b/Software/src/lib/me-no-dev-AsyncTCP/src/AsyncTCP.h new file mode 100644 index 00000000..b89fb122 --- /dev/null +++ b/Software/src/lib/me-no-dev-AsyncTCP/src/AsyncTCP.h @@ -0,0 +1,220 @@ +/* + Asynchronous TCP library for Espressif MCUs + + Copyright (c) 2016 Hristo Gochkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef ASYNCTCP_H_ +#define ASYNCTCP_H_ + +#include "IPAddress.h" +#include "sdkconfig.h" +#include +extern "C" { + #include "freertos/semphr.h" + #include "lwip/pbuf.h" +} + +#include "../../../system_settings.h" +#include "../../../devboard/hal/hal.h" + +//If core is not defined, then we are running in Arduino or PIO +#ifndef CONFIG_ASYNC_TCP_RUNNING_CORE +#define CONFIG_ASYNC_TCP_RUNNING_CORE WIFI_CORE //any available core +#define CONFIG_ASYNC_TCP_USE_WDT 0 //if enabled, adds between 33us and 200us per event +#endif + +class AsyncClient; + +#define ASYNC_MAX_ACK_TIME 5000 +#define ASYNC_WRITE_FLAG_COPY 0x01 //will allocate new buffer to hold the data while sending (else will hold reference to the data given) +#define ASYNC_WRITE_FLAG_MORE 0x02 //will not send PSH flag, meaning that there should be more data to be sent before the application should react. + +typedef std::function AcConnectHandler; +typedef std::function AcAckHandler; +typedef std::function AcErrorHandler; +typedef std::function AcDataHandler; +typedef std::function AcPacketHandler; +typedef std::function AcTimeoutHandler; + +struct tcp_pcb; +struct ip_addr; + +class AsyncClient { + public: + AsyncClient(tcp_pcb* pcb = 0); + ~AsyncClient(); + + AsyncClient & operator=(const AsyncClient &other); + AsyncClient & operator+=(const AsyncClient &other); + + bool operator==(const AsyncClient &other); + + bool operator!=(const AsyncClient &other) { + return !(*this == other); + } + bool connect(IPAddress ip, uint16_t port); + bool connect(const char* host, uint16_t port); + void close(bool now = false); + void stop(); + int8_t abort(); + bool free(); + + bool canSend();//ack is not pending + size_t space();//space available in the TCP window + size_t add(const char* data, size_t size, uint8_t apiflags=ASYNC_WRITE_FLAG_COPY);//add for sending + bool send();//send all data added with the method above + + //write equals add()+send() + size_t write(const char* data); + size_t write(const char* data, size_t size, uint8_t apiflags=ASYNC_WRITE_FLAG_COPY); //only when canSend() == true + + uint8_t state(); + bool connecting(); + bool connected(); + bool disconnecting(); + bool disconnected(); + bool freeable();//disconnected or disconnecting + + uint16_t getMss(); + + uint32_t getRxTimeout(); + void setRxTimeout(uint32_t timeout);//no RX data timeout for the connection in seconds + + uint32_t getAckTimeout(); + void setAckTimeout(uint32_t timeout);//no ACK timeout for the last sent packet in milliseconds + + void setNoDelay(bool nodelay); + bool getNoDelay(); + + uint32_t getRemoteAddress(); + uint16_t getRemotePort(); + uint32_t getLocalAddress(); + uint16_t getLocalPort(); + + //compatibility + IPAddress remoteIP(); + uint16_t remotePort(); + IPAddress localIP(); + uint16_t localPort(); + + void onConnect(AcConnectHandler cb, void* arg = 0); //on successful connect + void onDisconnect(AcConnectHandler cb, void* arg = 0); //disconnected + void onAck(AcAckHandler cb, void* arg = 0); //ack received + void onError(AcErrorHandler cb, void* arg = 0); //unsuccessful connect or error + void onData(AcDataHandler cb, void* arg = 0); //data received (called if onPacket is not used) + void onPacket(AcPacketHandler cb, void* arg = 0); //data received + void onTimeout(AcTimeoutHandler cb, void* arg = 0); //ack timeout + void onPoll(AcConnectHandler cb, void* arg = 0); //every 125ms when connected + + void ackPacket(struct pbuf * pb);//ack pbuf from onPacket + size_t ack(size_t len); //ack data that you have not acked using the method below + void ackLater(){ _ack_pcb = false; } //will not ack the current packet. Call from onData + + const char * errorToString(int8_t error); + const char * stateToString(); + + //Do not use any of the functions below! + static int8_t _s_poll(void *arg, struct tcp_pcb *tpcb); + static int8_t _s_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *pb, int8_t err); + static int8_t _s_fin(void *arg, struct tcp_pcb *tpcb, int8_t err); + static int8_t _s_lwip_fin(void *arg, struct tcp_pcb *tpcb, int8_t err); + static void _s_error(void *arg, int8_t err); + static int8_t _s_sent(void *arg, struct tcp_pcb *tpcb, uint16_t len); + static int8_t _s_connected(void* arg, void* tpcb, int8_t err); + static void _s_dns_found(const char *name, struct ip_addr *ipaddr, void *arg); + + int8_t _recv(tcp_pcb* pcb, pbuf* pb, int8_t err); + tcp_pcb * pcb(){ return _pcb; } + + protected: + tcp_pcb* _pcb; + int8_t _closed_slot; + + AcConnectHandler _connect_cb; + void* _connect_cb_arg; + AcConnectHandler _discard_cb; + void* _discard_cb_arg; + AcAckHandler _sent_cb; + void* _sent_cb_arg; + AcErrorHandler _error_cb; + void* _error_cb_arg; + AcDataHandler _recv_cb; + void* _recv_cb_arg; + AcPacketHandler _pb_cb; + void* _pb_cb_arg; + AcTimeoutHandler _timeout_cb; + void* _timeout_cb_arg; + AcConnectHandler _poll_cb; + void* _poll_cb_arg; + + bool _pcb_busy; + uint32_t _pcb_sent_at; + bool _ack_pcb; + uint32_t _rx_ack_len; + uint32_t _rx_last_packet; + uint32_t _rx_since_timeout; + uint32_t _ack_timeout; + uint16_t _connect_port; + + int8_t _close(); + void _free_closed_slot(); + void _allocate_closed_slot(); + int8_t _connected(void* pcb, int8_t err); + void _error(int8_t err); + int8_t _poll(tcp_pcb* pcb); + int8_t _sent(tcp_pcb* pcb, uint16_t len); + int8_t _fin(tcp_pcb* pcb, int8_t err); + int8_t _lwip_fin(tcp_pcb* pcb, int8_t err); + void _dns_found(struct ip_addr *ipaddr); + + public: + AsyncClient* prev; + AsyncClient* next; +}; + +class AsyncServer { + public: + AsyncServer(IPAddress addr, uint16_t port); + AsyncServer(uint16_t port); + ~AsyncServer(); + void onClient(AcConnectHandler cb, void* arg); + void begin(); + void end(); + void setNoDelay(bool nodelay); + bool getNoDelay(); + uint8_t status(); + + //Do not use any of the functions below! + static int8_t _s_accept(void *arg, tcp_pcb* newpcb, int8_t err); + static int8_t _s_accepted(void *arg, AsyncClient* client); + + protected: + uint16_t _port; + IPAddress _addr; + bool _noDelay; + tcp_pcb* _pcb; + AcConnectHandler _connect_cb; + void* _connect_cb_arg; + + int8_t _accept(tcp_pcb* newpcb, int8_t err); + int8_t _accepted(AsyncClient* client); +}; + + +#endif /* ASYNCTCP_H_ */ diff --git a/Software/src/lib/me-no-dev-ESPAsyncWebServer/src/AsyncEventSource.h b/Software/src/lib/me-no-dev-ESPAsyncWebServer/src/AsyncEventSource.h index 94a0c51e..d3d1b1d4 100644 --- a/Software/src/lib/me-no-dev-ESPAsyncWebServer/src/AsyncEventSource.h +++ b/Software/src/lib/me-no-dev-ESPAsyncWebServer/src/AsyncEventSource.h @@ -22,7 +22,7 @@ #include #ifdef ESP32 -#include "../../mathieucarbou-AsyncTCP/src/AsyncTCP.h" +#include "../../me-no-dev-AsyncTCP/src/AsyncTCP.h" #define SSE_MAX_QUEUED_MESSAGES 32 #else #include diff --git a/Software/src/lib/me-no-dev-ESPAsyncWebServer/src/AsyncWebSocket.h b/Software/src/lib/me-no-dev-ESPAsyncWebServer/src/AsyncWebSocket.h index 2ef8f9ec..747399b8 100644 --- a/Software/src/lib/me-no-dev-ESPAsyncWebServer/src/AsyncWebSocket.h +++ b/Software/src/lib/me-no-dev-ESPAsyncWebServer/src/AsyncWebSocket.h @@ -23,7 +23,7 @@ #include #ifdef ESP32 -#include "../../mathieucarbou-AsyncTCP/src/AsyncTCP.h" +#include "../../me-no-dev-AsyncTCP/src/AsyncTCP.h" #define WS_MAX_QUEUED_MESSAGES 32 #else #include diff --git a/Software/src/lib/me-no-dev-ESPAsyncWebServer/src/ESPAsyncWebServer.h b/Software/src/lib/me-no-dev-ESPAsyncWebServer/src/ESPAsyncWebServer.h index 7731a14c..664c0a5c 100644 --- a/Software/src/lib/me-no-dev-ESPAsyncWebServer/src/ESPAsyncWebServer.h +++ b/Software/src/lib/me-no-dev-ESPAsyncWebServer/src/ESPAsyncWebServer.h @@ -30,10 +30,10 @@ #ifdef ESP32 #include -#include "../../mathieucarbou-AsyncTCP/src/AsyncTCP.h" +#include "../../me-no-dev-AsyncTCP/src/AsyncTCP.h" #elif defined(ESP8266) #include -#include "../../mathieucarbou-AsyncTCP/src/AsyncTCP.h" +#include "../../me-no-dev-AsyncTCP/src/AsyncTCP.h" #else #error Platform not supported #endif