diff --git a/.github/workflows/compile-all-batteries.yml b/.github/workflows/compile-all-batteries.yml
deleted file mode 100644
index edfa7f6a..00000000
--- a/.github/workflows/compile-all-batteries.yml
+++ /dev/null
@@ -1,121 +0,0 @@
-# This is the name of the workflow, visible on GitHub UI.
-name: 🔋 Compile All Batteries
-
-# 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.
- build-batteries:
- 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:
- - BMW_I3_BATTERY
- - BMW_IX_BATTERY
- - BMW_PHEV_BATTERY
- - BYD_ATTO_3_BATTERY
- - CELLPOWER_BMS
- - CHADEMO_BATTERY
- - CMFA_EV_BATTERY
- - DALY_BMS
- - FOXESS_BATTERY
- - GEELY_GEOMETRY_C_BATTERY
- - HYUNDAI_IONIQ_28_BATTERY
- - IMIEV_CZERO_ION_BATTERY
- - JAGUAR_IPACE_BATTERY
- - KIA_E_GMP_BATTERY
- - KIA_HYUNDAI_64_BATTERY
- - KIA_HYUNDAI_HYBRID_BATTERY
- - MEB_BATTERY
- - MG_5_BATTERY
- - NISSAN_LEAF_BATTERY
- - ORION_BMS
- - PYLON_BATTERY
- - RJXZS_BMS
- - RANGE_ROVER_PHEV_BATTERY
- - RENAULT_KANGOO_BATTERY
- - RENAULT_TWIZY_BATTERY
- - 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
- - TEST_FAKE_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
-
- # 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.partitions=min_spiffs --build-property upload.maximum_size=1966080 --build-property "build.extra_flags=-Wall -Wextra -Wpedantic -Werror -DESP32 -D${{ matrix.battery}} -D${{ matrix.inverter}} -D${{ matrix.hardware}}" ./Software
-
\ No newline at end of file
diff --git a/.github/workflows/compile-all-combinations.yml b/.github/workflows/compile-all-combinations.yml
deleted file mode 100644
index 57e4860d..00000000
--- a/.github/workflows/compile-all-combinations.yml
+++ /dev/null
@@ -1,291 +0,0 @@
-# This is the name of the workflow, visible on GitHub UI.
-name: 🔌🔋💫 Compile All Combinations
-
-# Here we tell GitHub when to run the workflow.
-on:
- # This allows you to run this workflow manually from the
- # GitHub Actions tab.
- workflow_dispatch:
- # The workflow is run upon creating, editing,
- # pre-releasing, releasing and publishing a release
- release:
- types: [published]
-
-# 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-matrix-batteries-A-to-J: # we split this matrix into multiple parts, to prevent en error that is triggered when the matrix expansion exeeds 255
- 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:
- - BMW_I3_BATTERY
- - BMW_IX_BATTERY
- - BMW_PHEV_BATTERY
- - BYD_ATTO_3_BATTERY
- - CELLPOWER_BMS
- - CHADEMO_BATTERY
- - FOXESS_BATTERY
- - IMIEV_CZERO_ION_BATTERY
- - JAGUAR_IPACE_BATTERY
- # These are the emulated inverter communication protocols for which the code will be compiled.
- inverter:
- - AFORE_CAN
- - BYD_CAN
- - BYD_KOSTAL_RS485
- - BYD_MODBUS
- - FERROAMP_CAN
- - FOXESS_CAN
- - GROWATT_HV_CAN
- - GROWATT_LV_CAN
- - PYLON_CAN
- - PYLON_LV_CAN
- - SCHNEIDER_CAN
- - SMA_BYD_H_CAN
- - SMA_BYD_HVS_CAN
- - SMA_LV_CAN
- - SMA_TRIPOWER_CAN
- - SOFAR_CAN
- - SOLAX_CAN
- - SUNGROW_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
-
- # 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 -Wextra -Wpedantic -Werror -DESP32 -D${{ matrix.battery}} -D${{ matrix.inverter}} -D${{ matrix.hardware}}" ./Software
-
-
- # This is the name of the job.
- build-matrix-batteries-K-to-P:
- 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:
- - KIA_E_GMP_BATTERY
- - KIA_HYUNDAI_64_BATTERY
- - KIA_HYUNDAI_HYBRID_BATTERY
- - MEB_BATTERY
- - MG_5_BATTERY
- - NISSAN_LEAF_BATTERY
- - ORION_BMS
- - PYLON_BATTERY
- # These are the emulated inverter communication protocols for which the code will be compiled.
- inverter:
- - AFORE_CAN
- - BYD_CAN
- - BYD_KOSTAL_RS485
- - BYD_MODBUS
- - FERROAMP_CAN
- - FOXESS_CAN
- - GROWATT_HV_CAN
- - GROWATT_LV_CAN
- - PYLON_CAN
- - PYLON_LV_CAN
- - SCHNEIDER_CAN
- - SMA_BYD_H_CAN
- - SMA_BYD_HVS_CAN
- - SMA_LV_CAN
- - SMA_TRIPOWER_CAN
- - SOFAR_CAN
- - SOLAX_CAN
- - SUNGROW_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
-
- # 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 -Wextra -Wpedantic -Werror -DESP32 -D${{ matrix.battery}} -D${{ matrix.inverter}} -D${{ matrix.hardware}}" ./Software
-
- # This is the name of the job.
- build-matrix-batteries-R-to-Z:
- 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:
- - RANGE_ROVER_PHEV_BATTERY
- - RENAULT_KANGOO_BATTERY
- - RENAULT_TWIZY_BATTERY
- - RENAULT_ZOE_GEN1_BATTERY
- - RENAULT_ZOE_GEN2_BATTERY
- - RJXZS_BMS
- - SANTA_FE_PHEV_BATTERY
- - STELLANTIS_ECMP_BATTERY
- - TESLA_MODEL_3Y_BATTERY
- - TESLA_MODEL_SX_BATTERY
- - VOLVO_SPA_BATTERY
- - TEST_FAKE_BATTERY
- # These are the emulated inverter communication protocols for which the code will be compiled.
- inverter:
- - AFORE_CAN
- - BYD_CAN
- - BYD_KOSTAL_RS485
- - BYD_MODBUS
- - FERROAMP_CAN
- - FOXESS_CAN
- - GROWATT_HV_CAN
- - GROWATT_LV_CAN
- - PYLON_CAN
- - PYLON_LV_CAN
- - SCHNEIDER_CAN
- - SMA_BYD_H_CAN
- - SMA_BYD_HVS_CAN
- - SMA_LV_CAN
- - SMA_TRIPOWER_CAN
- - SOFAR_CAN
- - SOLAX_CAN
- - SUNGROW_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
-
- # 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.partitions=min_spiffs --build-property upload.maximum_size=1966080 --build-property "build.extra_flags=-Wall -Wextra -Wpedantic -Werror -DESP32 -D${{ matrix.battery}} -D${{ matrix.inverter}} -D${{ matrix.hardware}}" ./Software
diff --git a/.github/workflows/compile-all-double-batteries.yml b/.github/workflows/compile-all-double-batteries.yml
deleted file mode 100644
index f5807acf..00000000
--- a/.github/workflows/compile-all-double-batteries.yml
+++ /dev/null
@@ -1,94 +0,0 @@
-# This is the name of the workflow, visible on GitHub UI.
-name: 🔋🔋 Compile All Double Batteries
-
-# 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.
- build-batteries:
- 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:
- - BMW_I3_BATTERY
- - BYD_ATTO_3_BATTERY
- - KIA_HYUNDAI_64_BATTERY
- - PYLON_BATTERY
- - SANTA_FE_PHEV_BATTERY
- - TEST_FAKE_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
-
- # 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.partitions=min_spiffs --build-property upload.maximum_size=1966080 --build-property "build.extra_flags=-Wall -Wextra -Wpedantic -Werror -DESP32 -DDOUBLE_BATTERY -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
deleted file mode 100644
index 2bd79df2..00000000
--- a/.github/workflows/compile-all-inverters.yml
+++ /dev/null
@@ -1,108 +0,0 @@
-# This is the name of the workflow, visible on GitHub UI.
-name: 🔌 Compile All Inverters
-
-# 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-inverters:
- 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:
- - AFORE_CAN
- - BYD_CAN
- - BYD_KOSTAL_RS485
- - BYD_MODBUS
- - FERROAMP_CAN
- - FOXESS_CAN
- - GROWATT_HV_CAN
- - GROWATT_LV_CAN
- - PYLON_CAN
- - PYLON_LV_CAN
- - SCHNEIDER_CAN
- - SMA_BYD_H_CAN
- - SMA_BYD_HVS_CAN
- - SMA_LV_CAN
- - SMA_TRIPOWER_CAN
- - SOFAR_CAN
- - SOLAX_CAN
- - SUNGROW_CAN
- - 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
-
- # 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.partitions=min_spiffs --build-property upload.maximum_size=1966080 --build-property "build.extra_flags=-Wall -Wextra -Wpedantic -Werror -DESP32 -D${{ matrix.battery}} -D${{ matrix.inverter}} -D${{ matrix.hardware}}" ./Software
diff --git a/.github/workflows/compile-common-image-lilygo-logging.yml b/.github/workflows/compile-common-image-lilygo-logging.yml
deleted file mode 100644
index a84381e5..00000000
--- a/.github/workflows/compile-common-image-lilygo-logging.yml
+++ /dev/null
@@ -1,58 +0,0 @@
-# This is the name of the workflow, visible on GitHub UI.
-name: 🔋 Compile Common Image for Lilygo with debug logging
-
-# Here we tell GitHub when to run the workflow.
-on:
- # The workflow is run when a commit is pushed or for a
- # Pull Request.
- - push
- - pull_request
-
-# This is the list of jobs that will be run concurrently.
-jobs:
- # This pre-job is run to skip workflows in case a workflow is already run, i.e. because the workflow is triggered by both push and pull_request
- skip-duplicate-actions:
- runs-on: ubuntu-latest
- # Map a step output to a job output
- outputs:
- should_skip: ${{ steps.skip_check.outputs.should_skip }}
- steps:
- - id: skip_check
- uses: fkirc/skip-duplicate-actions@v5
- with:
- # All of these options are optional, so you can remove them if you are happy with the defaults
- concurrent_skipping: 'never'
- skip_after_successful_duplicate: 'true'
- do_not_skip: '["pull_request", "workflow_dispatch", "schedule"]'
-
- build-common-image:
- # This is the platform GitHub will use to run our workflow.
- runs-on: ubuntu-latest
-
- steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- # Copy USER_SECRETS.TEMPLATE.h to USER_SECRETS.h
- - name: Copy USER_SECRETS.TEMPLATE.h to USER_SECRETS.h
- run: cp ./Software/USER_SECRETS.TEMPLATE.h ./Software/USER_SECRETS.h
-
- # We use the `arduino/setup-arduino-cli` action to install and
- # configure the Arduino CLI on the system.
- - name: Setup Arduino CLI
- uses: arduino/setup-arduino-cli@v2
-
- # We then install the platform.
- - name: Install platform
- run: |
- arduino-cli core update-index
- arduino-cli core install esp32:esp32
-
- - name: Compile Sketch
- run: arduino-cli compile --output-dir ./ --fqbn esp32:esp32:esp32 --build-property build.partitions=min_spiffs --build-property upload.maximum_size=1966080 --build-property "build.extra_flags=-Wall -Wextra -Wpedantic -Werror -DESP32 -DDEBUG_VIA_USB -DCOMMON_IMAGE -DHW_LILYGO" ./Software
-
- - name: Upload artifact
- uses: actions/upload-artifact@v4
- with:
- name: battery-emulator-lilygo-debug.bin
- path: Software.ino.bin
diff --git a/.github/workflows/compile-common-image-lilygo.yml b/.github/workflows/compile-common-image-lilygo.yml
index 02fd25f5..33c3e5ba 100644
--- a/.github/workflows/compile-common-image-lilygo.yml
+++ b/.github/workflows/compile-common-image-lilygo.yml
@@ -1,7 +1,5 @@
-# This is the name of the workflow, visible on GitHub UI.
name: 🔋 Compile Common Image for Lilygo
-# Here we tell GitHub when to run the workflow.
on:
# The workflow is run when a commit is pushed or for a
# Pull Request.
@@ -30,29 +28,31 @@ jobs:
runs-on: ubuntu-latest
steps:
- - name: Checkout
- uses: actions/checkout@v4
-
+ - uses: actions/checkout@v4
+ name: Checkout code
+
+ - uses: actions/cache@v4
+ with:
+ path: |
+ ~/.cache/pip
+ ~/.platformio/.cache
+ key: ${{ runner.os }}-pio
+
+ - uses: actions/setup-python@v5
+ with:
+ python-version: '3.11'
+ - name: Install PlatformIO Core
+ run: pip install --upgrade platformio
+
# 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
+ - 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
+ - name: Build image for Lilygo
+ run: pio run -e lilygo_330
- # We then install the platform.
- - name: Install platform
- run: |
- arduino-cli core update-index
- arduino-cli core install esp32:esp32
-
- - name: Compile Sketch
- run: arduino-cli compile --output-dir ./ --fqbn esp32:esp32:esp32 --build-property build.partitions=min_spiffs --build-property upload.maximum_size=1966080 --build-property "build.extra_flags=-Wall -Wextra -Wpedantic -Werror -DESP32 -DCOMMON_IMAGE -DHW_LILYGO" ./Software
-
- - name: Upload artifact
- uses: actions/upload-artifact@v4
- with:
- name: battery-emulator-lilygo.bin
- path: Software.ino.bin
+ - name: Upload artifact
+ uses: actions/upload-artifact@v4
+ with:
+ name: battery-emulator-lilygo.bin
+ path: .pio/build/lilygo_330/firmware.bin
diff --git a/.github/workflows/compile-common-image-stark.yml b/.github/workflows/compile-common-image-stark.yml
new file mode 100644
index 00000000..00b2c01c
--- /dev/null
+++ b/.github/workflows/compile-common-image-stark.yml
@@ -0,0 +1,58 @@
+name: 🔋 Compile Common Image for Stark CMR
+
+on:
+ # The workflow is run when a commit is pushed or for a
+ # Pull Request.
+ - push
+ - pull_request
+
+# This is the list of jobs that will be run concurrently.
+jobs:
+ # This pre-job is run to skip workflows in case a workflow is already run, i.e. because the workflow is triggered by both push and pull_request
+ skip-duplicate-actions:
+ runs-on: ubuntu-latest
+ # Map a step output to a job output
+ outputs:
+ should_skip: ${{ steps.skip_check.outputs.should_skip }}
+ steps:
+ - id: skip_check
+ uses: fkirc/skip-duplicate-actions@v5
+ with:
+ # All of these options are optional, so you can remove them if you are happy with the defaults
+ concurrent_skipping: 'never'
+ skip_after_successful_duplicate: 'true'
+ do_not_skip: '["pull_request", "workflow_dispatch", "schedule"]'
+
+ build-common-image:
+ # This is the platform GitHub will use to run our workflow.
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+ name: Checkout code
+
+ - uses: actions/cache@v4
+ with:
+ path: |
+ ~/.cache/pip
+ ~/.platformio/.cache
+ key: ${{ runner.os }}-pio
+
+ - uses: actions/setup-python@v5
+ with:
+ python-version: '3.11'
+ - name: Install PlatformIO Core
+ run: pip install --upgrade platformio
+
+ # 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
+
+ - name: Build image for Stark CMR
+ run: pio run -e stark_330
+
+ - name: Upload artifact
+ uses: actions/upload-artifact@v4
+ with:
+ name: battery-emulator-stark.bin
+ path: .pio/build/stark_330/firmware.bin
diff --git a/README.md b/README.md
index 2184126e..b441253f 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@



-
+

## What is Battery Emulator?
diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h
index 474908de..b806ef90 100644
--- a/Software/USER_SETTINGS.h
+++ b/Software/USER_SETTINGS.h
@@ -40,6 +40,7 @@
//#define RENAULT_ZOE_GEN1_BATTERY
//#define RENAULT_ZOE_GEN2_BATTERY
//#define SONO_BATTERY
+//#define SAMSUNG_SDI_LV_BATTERY
//#define SANTA_FE_PHEV_BATTERY
//#define SIMPBMS_BATTERY
//#define STELLANTIS_ECMP_BATTERY
diff --git a/Software/src/battery/BATTERIES.cpp b/Software/src/battery/BATTERIES.cpp
index 0eb67d1e..354a4686 100644
--- a/Software/src/battery/BATTERIES.cpp
+++ b/Software/src/battery/BATTERIES.cpp
@@ -116,6 +116,8 @@ const char* name_for_battery_type(BatteryType type) {
return RenaultZoeGen1Battery::Name;
case BatteryType::RenaultZoe2:
return RenaultZoeGen2Battery::Name;
+ case BatteryType::SamsungSdiLv:
+ return SamsungSdiLVBattery::Name;
case BatteryType::SantaFePhev:
return SantaFePhevBattery::Name;
case BatteryType::SimpBms:
@@ -215,6 +217,8 @@ Battery* create_battery(BatteryType type) {
return new RenaultZoeGen1Battery();
case BatteryType::RenaultZoe2:
return new RenaultZoeGen2Battery();
+ case BatteryType::SamsungSdiLv:
+ return new SamsungSdiLVBattery();
case BatteryType::SantaFePhev:
return new SantaFePhevBattery();
case BatteryType::SimpBms:
diff --git a/Software/src/battery/BATTERIES.h b/Software/src/battery/BATTERIES.h
index b7fe961e..1f357a93 100644
--- a/Software/src/battery/BATTERIES.h
+++ b/Software/src/battery/BATTERIES.h
@@ -44,6 +44,7 @@ void setup_can_shunt();
#include "RENAULT-ZOE-GEN1-BATTERY.h"
#include "RENAULT-ZOE-GEN2-BATTERY.h"
#include "RJXZS-BMS.h"
+#include "SAMSUNG-SDI-LV-BATTERY.h"
#include "SANTA-FE-PHEV-BATTERY.h"
#include "SIMPBMS-BATTERY.h"
#include "SONO-BATTERY.h"
diff --git a/Software/src/battery/Battery.h b/Software/src/battery/Battery.h
index e0fd42e5..7f556188 100644
--- a/Software/src/battery/Battery.h
+++ b/Software/src/battery/Battery.h
@@ -43,7 +43,8 @@ enum class BatteryType {
VolvoSpa = 35,
VolvoSpaHybrid = 36,
MgHsPhev = 37,
- HyundaiIoniq28 = 38,
+ SamsungSdiLv = 38,
+ HyundaiIoniq28 = 39,
Highest
};
diff --git a/Software/src/battery/ECMP-BATTERY.cpp b/Software/src/battery/ECMP-BATTERY.cpp
index 4b25c079..536f4b90 100644
--- a/Software/src/battery/ECMP-BATTERY.cpp
+++ b/Software/src/battery/ECMP-BATTERY.cpp
@@ -123,6 +123,7 @@ void EcmpBattery::update_values() {
datalayer_extended.stellantisECMP.pid_time_spent_over_55c = pid_time_spent_over_55c;
datalayer_extended.stellantisECMP.pid_contactor_closing_counter = pid_contactor_closing_counter;
datalayer_extended.stellantisECMP.pid_date_of_manufacture = pid_date_of_manufacture;
+ datalayer_extended.stellantisECMP.pid_SOH_cell_1 = pid_SOH_cell_1;
if (battery_InterlockOpen) {
set_event(EVENT_HVIL_FAILURE, 0);
@@ -135,6 +136,12 @@ void EcmpBattery::update_values() {
} else {
clear_event(EVENT_12V_LOW);
}
+
+ if (pid_reason_open == 7) { //Invalid status
+ set_event(EVENT_CONTACTOR_OPEN, 0);
+ } else {
+ clear_event(EVENT_CONTACTOR_OPEN);
+ }
}
void EcmpBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
@@ -578,8 +585,7 @@ void EcmpBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
(rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]);
break;
case PID_ENERGY_CAPACITY:
- pid_energy_capacity = ((rx_frame.data.u8[4] << 24) | (rx_frame.data.u8[5] << 16) |
- (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]);
+ pid_energy_capacity = (rx_frame.data.u8[4] << 16) | (rx_frame.data.u8[5] << 8) | (rx_frame.data.u8[6]);
break;
case PID_HIGH_CELL_NUM:
pid_highest_cell_voltage_num = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
@@ -720,6 +726,33 @@ void EcmpBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
switch (incoming_poll) //Multiframe responses
{
+ case PID_ALL_CELL_SOH:
+ switch (rx_frame.data.u8[0]) {
+ case 0x10:
+ pid_SOH_cell_1 = ((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6]);
+ break;
+ case 0x21:
+ break;
+ case 0x22:
+ break;
+ case 0x23:
+ break;
+ case 0x24:
+ break;
+ case 0x25:
+ break;
+ case 0x26:
+ break;
+ case 0x27:
+ break;
+ case 0x28:
+ break;
+ case 0x29:
+ break;
+ default:
+ break;
+ }
+ break;
case PID_ALL_CELL_VOLTAGES:
switch (rx_frame.data.u8[0]) {
case 0x10:
@@ -1291,6 +1324,11 @@ void EcmpBattery::transmit_can(unsigned long currentMillis) {
case PID_DATE_OF_MANUFACTURE:
ECMP_POLL.data.u8[2] = (uint8_t)((PID_DATE_OF_MANUFACTURE & 0xFF00) >> 8);
ECMP_POLL.data.u8[3] = (uint8_t)(PID_DATE_OF_MANUFACTURE & 0x00FF);
+ poll_state = PID_ALL_CELL_SOH;
+ break;
+ case PID_ALL_CELL_SOH:
+ ECMP_POLL.data.u8[2] = (uint8_t)((PID_ALL_CELL_SOH & 0xFF00) >> 8);
+ ECMP_POLL.data.u8[3] = (uint8_t)(PID_ALL_CELL_SOH & 0x00FF);
poll_state = PID_WELD_CHECK; // Loop back to beginning
break;
default:
diff --git a/Software/src/battery/ECMP-BATTERY.h b/Software/src/battery/ECMP-BATTERY.h
index 2003d5cd..66219b7c 100644
--- a/Software/src/battery/ECMP-BATTERY.h
+++ b/Software/src/battery/ECMP-BATTERY.h
@@ -136,6 +136,7 @@ class EcmpBattery : public CanBattery {
uint32_t pid_time_spent_over_55c = NOT_SAMPLED_YET;
uint32_t pid_contactor_closing_counter = NOT_SAMPLED_YET;
uint32_t pid_date_of_manufacture = NOT_SAMPLED_YET;
+ uint16_t pid_SOH_cell_1 = NOT_SAMPLED_YET;
unsigned long previousMillis10 = 0; // will store last time a 10ms CAN Message was sent
unsigned long previousMillis20 = 0; // will store last time a 20ms CAN Message was sent
@@ -197,7 +198,7 @@ class EcmpBattery : public CanBattery {
static const uint16_t PID_SW_VERSION_NUM = 0xF195; //Not supported on all batteris
static const uint16_t PID_FACTORY_MODE_CONTROL = 0xD900;
static const uint16_t PID_BATTERY_SERIAL = 0xD901;
- static const uint16_t PID_ALL_CELL_SOH = 0xD4B5; //Very long message reply, too much data for this integration
+ static const uint16_t PID_ALL_CELL_SOH = 0xD4B5;
static const uint16_t PID_AUX_FUSE_STATE = 0xD86C;
static const uint16_t PID_BATTERY_STATE = 0xD811;
static const uint16_t PID_PRECHARGE_SHORT_CIRCUIT = 0xD4D8;
diff --git a/Software/src/battery/ECMP-HTML.h b/Software/src/battery/ECMP-HTML.h
index 7a98a42a..3a43427f 100644
--- a/Software/src/battery/ECMP-HTML.h
+++ b/Software/src/battery/ECMP-HTML.h
@@ -376,6 +376,11 @@ class EcmpHtmlRenderer : public BatteryHtmlRenderer {
? "N/A"
: String(datalayer_extended.stellantisECMP.pid_contactor_closing_counter)) +
" cycles";
+ content += "
State of Health Cell-1: " +
+ (datalayer_extended.stellantisECMP.pid_SOH_cell_1 == 255
+ ? "N/A"
+ : String(datalayer_extended.stellantisECMP.pid_SOH_cell_1)) +
+ "
";
return content;
}
diff --git a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp
index 4b0cb2f6..bc499862 100644
--- a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp
+++ b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp
@@ -48,66 +48,19 @@ void KiaHyundai64Battery::
datalayer_battery_extended->batteryManagementMode = batteryManagementMode;
datalayer_battery_extended->BMS_ign = BMS_ign;
datalayer_battery_extended->batteryRelay = batteryRelay;
-
- //Perform logging if configured to do so
-#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("% | SOC Display: ");
- logging.print((uint16_t)SOC_Display / 10.0, 1);
- logging.print("% | SOH ");
- logging.print((uint16_t)batterySOH / 10.0, 1);
- logging.println("%");
- 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) {
- logging.print(" | BmsIgnition ON");
- } else {
- logging.print(" | BmsIgnition OFF");
- }
-
- if (bitRead((uint8_t)batteryRelay, 0) == 1) {
- logging.print(" | PowerRelay ON");
- } else {
- logging.print(" | PowerRelay OFF");
- }
- logging.print(" | Inverter ");
- logging.print(inverterVoltage);
- logging.println(" Volts");
-#endif
+ datalayer_battery_extended->inverterVoltage = inverterVoltage;
+ memcpy(datalayer_battery_extended->ecu_serial_number, ecu_serial_number, sizeof(ecu_serial_number));
+ memcpy(datalayer_battery_extended->ecu_version_number, ecu_version_number, sizeof(ecu_version_number));
+ datalayer_battery_extended->cumulative_charge_current_ah = cumulative_charge_current_ah;
+ datalayer_battery_extended->cumulative_discharge_current_ah = cumulative_discharge_current_ah;
+ datalayer_battery_extended->cumulative_energy_charged_kWh = cumulative_energy_charged_kWh;
+ datalayer_battery_extended->cumulative_energy_discharged_kWh = cumulative_energy_discharged_kWh;
+ datalayer_battery_extended->powered_on_total_time = powered_on_total_time;
+ datalayer_battery_extended->isolation_resistance_kOhm = isolation_resistance_kOhm;
+ datalayer_battery_extended->number_of_standard_charging_sessions = number_of_standard_charging_sessions;
+ datalayer_battery_extended->number_of_fastcharging_sessions = number_of_fastcharging_sessions;
+ datalayer_battery_extended->accumulated_normal_charging_energy_kWh = accumulated_normal_charging_energy_kWh;
+ datalayer_battery_extended->accumulated_fastcharging_energy_kWh = accumulated_fastcharging_energy_kWh;
}
void KiaHyundai64Battery::update_number_of_cells() {
@@ -129,6 +82,7 @@ void KiaHyundai64Battery::update_number_of_cells() {
void KiaHyundai64Battery::handle_incoming_can_frame(CAN_frame rx_frame) {
switch (rx_frame.ID) {
case 0x4DE:
+ datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE;
startedUp = true;
break;
case 0x542: //BMS SOC
@@ -168,65 +122,118 @@ void KiaHyundai64Battery::handle_incoming_can_frame(CAN_frame rx_frame) {
case 0x5D8:
startedUp = true;
- //PID data is polled after last message sent from battery every other time:
+ //PID data is polled after last message sent from battery every other time this 0x5D8 message arrives:
if (holdPidCounter == true) {
holdPidCounter = false;
} else {
holdPidCounter = true;
- if (poll_data_pid >= 6) { //polling one of six PIDs at 100ms*2, resolution = 1200ms
- poll_data_pid = 0;
- }
+
poll_data_pid++;
if (poll_data_pid == 1) {
- transmit_can_frame(&KIA64_7E4_id1);
+ KIA64_7E4_poll.data.u8[2] = (uint8_t)((POLL_GROUP_1 & 0xFF00) >> 8);
+ KIA64_7E4_poll.data.u8[3] = (uint8_t)(POLL_GROUP_1 & 0x00FF);
} else if (poll_data_pid == 2) {
- transmit_can_frame(&KIA64_7E4_id2);
+ KIA64_7E4_poll.data.u8[2] = (uint8_t)((POLL_GROUP_2 & 0xFF00) >> 8);
+ KIA64_7E4_poll.data.u8[3] = (uint8_t)(POLL_GROUP_2 & 0x00FF);
} else if (poll_data_pid == 3) {
- transmit_can_frame(&KIA64_7E4_id3);
+ KIA64_7E4_poll.data.u8[2] = (uint8_t)((POLL_GROUP_3 & 0xFF00) >> 8);
+ KIA64_7E4_poll.data.u8[3] = (uint8_t)(POLL_GROUP_3 & 0x00FF);
} else if (poll_data_pid == 4) {
- transmit_can_frame(&KIA64_7E4_id4);
+ KIA64_7E4_poll.data.u8[2] = (uint8_t)((POLL_GROUP_4 & 0xFF00) >> 8);
+ KIA64_7E4_poll.data.u8[3] = (uint8_t)(POLL_GROUP_4 & 0x00FF);
} else if (poll_data_pid == 5) {
- transmit_can_frame(&KIA64_7E4_id5);
+ KIA64_7E4_poll.data.u8[2] = (uint8_t)((POLL_GROUP_5 & 0xFF00) >> 8);
+ KIA64_7E4_poll.data.u8[3] = (uint8_t)(POLL_GROUP_5 & 0x00FF);
} else if (poll_data_pid == 6) {
- transmit_can_frame(&KIA64_7E4_id6);
+ KIA64_7E4_poll.data.u8[2] = (uint8_t)((POLL_GROUP_6 & 0xFF00) >> 8);
+ KIA64_7E4_poll.data.u8[3] = (uint8_t)(POLL_GROUP_6 & 0x00FF);
+ } else if (poll_data_pid == 7) {
+ KIA64_7E4_poll.data.u8[2] = (uint8_t)((POLL_GROUP_11 & 0xFF00) >> 8);
+ KIA64_7E4_poll.data.u8[3] = (uint8_t)(POLL_GROUP_11 & 0x00FF);
+ } else if (poll_data_pid == 8) {
+ KIA64_7E4_poll.data.u8[2] = (uint8_t)((POLL_ECU_SERIAL & 0xFF00) >> 8);
+ KIA64_7E4_poll.data.u8[3] = (uint8_t)(POLL_ECU_SERIAL & 0x00FF);
+ } else if (poll_data_pid == 9) {
+ KIA64_7E4_poll.data.u8[2] = (uint8_t)((POLL_ECU_VERSION & 0xFF00) >> 8);
+ KIA64_7E4_poll.data.u8[3] = (uint8_t)(POLL_ECU_VERSION & 0x00FF);
+ poll_data_pid = 0;
}
+ transmit_can_frame(&KIA64_7E4_poll);
}
break;
case 0x7EC: //Data From polled PID group, BigEndian
- switch (rx_frame.data.u8[0]) {
- case 0x10: //"PID Header"
- if (rx_frame.data.u8[4] == poll_data_pid) {
- transmit_can_frame(&KIA64_7E4_ack); //Send ack to BMS if the same frame is sent as polled
+
+ if (rx_frame.data.u8[0] < 0x10) { //One line response
+ pid_reply = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3];
+ }
+
+ if (rx_frame.data.u8[0] == 0x10) { //Multiframe response, send ACK
+ transmit_can_frame(&KIA64_7E4_ack);
+ pid_reply = (rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4];
+ }
+
+ switch (rx_frame.data.u8[0]) { //Multiframe responses
+ case 0x10: //Header frame sometimes has data
+ if (pid_reply == POLL_ECU_SERIAL) {
+ ecu_serial_number[0] = rx_frame.data.u8[5];
+ ecu_serial_number[1] = rx_frame.data.u8[6];
+ ecu_serial_number[2] = rx_frame.data.u8[7];
+ } else if (pid_reply == POLL_ECU_VERSION) {
+ ecu_version_number[0] = rx_frame.data.u8[5];
+ ecu_version_number[1] = rx_frame.data.u8[6];
+ ecu_version_number[2] = rx_frame.data.u8[7];
}
break;
case 0x21: //First frame in PID group
- if (poll_data_pid == 1) {
+ if (pid_reply == POLL_GROUP_1) {
batteryRelay = rx_frame.data.u8[7];
- } else if (poll_data_pid == 2) {
+ } else if (pid_reply == POLL_GROUP_2) {
cellvoltages_mv[0] = (rx_frame.data.u8[2] * 20);
cellvoltages_mv[1] = (rx_frame.data.u8[3] * 20);
cellvoltages_mv[2] = (rx_frame.data.u8[4] * 20);
cellvoltages_mv[3] = (rx_frame.data.u8[5] * 20);
cellvoltages_mv[4] = (rx_frame.data.u8[6] * 20);
cellvoltages_mv[5] = (rx_frame.data.u8[7] * 20);
- } else if (poll_data_pid == 3) {
+ } else if (pid_reply == POLL_GROUP_3) {
cellvoltages_mv[32] = (rx_frame.data.u8[2] * 20);
cellvoltages_mv[33] = (rx_frame.data.u8[3] * 20);
cellvoltages_mv[34] = (rx_frame.data.u8[4] * 20);
cellvoltages_mv[35] = (rx_frame.data.u8[5] * 20);
cellvoltages_mv[36] = (rx_frame.data.u8[6] * 20);
cellvoltages_mv[37] = (rx_frame.data.u8[7] * 20);
- } else if (poll_data_pid == 4) {
+ } else if (pid_reply == POLL_GROUP_4) {
cellvoltages_mv[64] = (rx_frame.data.u8[2] * 20);
cellvoltages_mv[65] = (rx_frame.data.u8[3] * 20);
cellvoltages_mv[66] = (rx_frame.data.u8[4] * 20);
cellvoltages_mv[67] = (rx_frame.data.u8[5] * 20);
cellvoltages_mv[68] = (rx_frame.data.u8[6] * 20);
cellvoltages_mv[69] = (rx_frame.data.u8[7] * 20);
+ } else if (pid_reply == POLL_GROUP_11) {
+ number_of_standard_charging_sessions = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]);
+ } else if (pid_reply == POLL_ECU_SERIAL) {
+ ecu_serial_number[3] = rx_frame.data.u8[1];
+ ecu_serial_number[4] = rx_frame.data.u8[2];
+ ecu_serial_number[5] = rx_frame.data.u8[3];
+ ecu_serial_number[6] = rx_frame.data.u8[4];
+ ecu_serial_number[7] = rx_frame.data.u8[5];
+ ecu_serial_number[8] = rx_frame.data.u8[6];
+ ecu_serial_number[9] = rx_frame.data.u8[7];
+ } else if (pid_reply == POLL_ECU_VERSION) {
+ ecu_version_number[3] = rx_frame.data.u8[1];
+ ecu_version_number[4] = rx_frame.data.u8[2];
+ ecu_version_number[5] = rx_frame.data.u8[3];
+ ecu_version_number[6] = rx_frame.data.u8[4];
+ ecu_version_number[7] = rx_frame.data.u8[5];
+ ecu_version_number[8] = rx_frame.data.u8[6];
+ ecu_version_number[9] = rx_frame.data.u8[7];
}
break;
case 0x22: //Second datarow in PID group
- if (poll_data_pid == 2) {
+ if (pid_reply == POLL_GROUP_1) {
+ //battery_max_temperature = rx_frame.data.u8[5];
+ //battery_min_temperature = rx_frame.data.u8[6];
+ //module_1_temperature = rx_frame.data.u8[7];
+ } else if (pid_reply == POLL_GROUP_2) {
cellvoltages_mv[6] = (rx_frame.data.u8[1] * 20);
cellvoltages_mv[7] = (rx_frame.data.u8[2] * 20);
cellvoltages_mv[8] = (rx_frame.data.u8[3] * 20);
@@ -234,7 +241,7 @@ void KiaHyundai64Battery::handle_incoming_can_frame(CAN_frame rx_frame) {
cellvoltages_mv[10] = (rx_frame.data.u8[5] * 20);
cellvoltages_mv[11] = (rx_frame.data.u8[6] * 20);
cellvoltages_mv[12] = (rx_frame.data.u8[7] * 20);
- } else if (poll_data_pid == 3) {
+ } else if (pid_reply == POLL_GROUP_3) {
cellvoltages_mv[38] = (rx_frame.data.u8[1] * 20);
cellvoltages_mv[39] = (rx_frame.data.u8[2] * 20);
cellvoltages_mv[40] = (rx_frame.data.u8[3] * 20);
@@ -242,7 +249,7 @@ void KiaHyundai64Battery::handle_incoming_can_frame(CAN_frame rx_frame) {
cellvoltages_mv[42] = (rx_frame.data.u8[5] * 20);
cellvoltages_mv[43] = (rx_frame.data.u8[6] * 20);
cellvoltages_mv[44] = (rx_frame.data.u8[7] * 20);
- } else if (poll_data_pid == 4) {
+ } else if (pid_reply == POLL_GROUP_4) {
cellvoltages_mv[70] = (rx_frame.data.u8[1] * 20);
cellvoltages_mv[71] = (rx_frame.data.u8[2] * 20);
cellvoltages_mv[72] = (rx_frame.data.u8[3] * 20);
@@ -250,15 +257,35 @@ void KiaHyundai64Battery::handle_incoming_can_frame(CAN_frame rx_frame) {
cellvoltages_mv[74] = (rx_frame.data.u8[5] * 20);
cellvoltages_mv[75] = (rx_frame.data.u8[6] * 20);
cellvoltages_mv[76] = (rx_frame.data.u8[7] * 20);
- } else if (poll_data_pid == 6) {
+ } else if (pid_reply == POLL_GROUP_6) {
batteryManagementMode = rx_frame.data.u8[5];
+ } else if (pid_reply == POLL_GROUP_11) {
+ number_of_fastcharging_sessions = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]);
+ accumulated_normal_charging_energy_kWh = ((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6]);
+ } else if (pid_reply == POLL_ECU_SERIAL) {
+ ecu_serial_number[10] = rx_frame.data.u8[1];
+ ecu_serial_number[11] = rx_frame.data.u8[2];
+ ecu_serial_number[12] = rx_frame.data.u8[3];
+ ecu_serial_number[13] = rx_frame.data.u8[4];
+ ecu_serial_number[14] = rx_frame.data.u8[5];
+ ecu_serial_number[15] = rx_frame.data.u8[6];
+ } else if (pid_reply == POLL_ECU_VERSION) {
+ ecu_version_number[10] = rx_frame.data.u8[1];
+ ecu_version_number[11] = rx_frame.data.u8[2];
+ ecu_version_number[12] = rx_frame.data.u8[3];
+ ecu_version_number[13] = rx_frame.data.u8[4];
+ ecu_version_number[14] = rx_frame.data.u8[5];
+ ecu_version_number[15] = rx_frame.data.u8[6];
}
break;
case 0x23: //Third datarow in PID group
- if (poll_data_pid == 1) {
+ if (pid_reply == POLL_GROUP_1) {
+ //module_2_temperature = rx_frame.data.u8[1];
+ //module_3_temperature = rx_frame.data.u8[2];
+ //module_4_temperature = rx_frame.data.u8[3];
temperature_water_inlet = rx_frame.data.u8[6];
CellVoltMax_mV = (rx_frame.data.u8[7] * 20); //(volts *50) *20 =mV
- } else if (poll_data_pid == 2) {
+ } else if (pid_reply == POLL_GROUP_2) {
cellvoltages_mv[13] = (rx_frame.data.u8[1] * 20);
cellvoltages_mv[14] = (rx_frame.data.u8[2] * 20);
cellvoltages_mv[15] = (rx_frame.data.u8[3] * 20);
@@ -266,7 +293,7 @@ void KiaHyundai64Battery::handle_incoming_can_frame(CAN_frame rx_frame) {
cellvoltages_mv[17] = (rx_frame.data.u8[5] * 20);
cellvoltages_mv[18] = (rx_frame.data.u8[6] * 20);
cellvoltages_mv[19] = (rx_frame.data.u8[7] * 20);
- } else if (poll_data_pid == 3) {
+ } else if (pid_reply == POLL_GROUP_3) {
cellvoltages_mv[45] = (rx_frame.data.u8[1] * 20);
cellvoltages_mv[46] = (rx_frame.data.u8[2] * 20);
cellvoltages_mv[47] = (rx_frame.data.u8[3] * 20);
@@ -274,7 +301,7 @@ void KiaHyundai64Battery::handle_incoming_can_frame(CAN_frame rx_frame) {
cellvoltages_mv[49] = (rx_frame.data.u8[5] * 20);
cellvoltages_mv[50] = (rx_frame.data.u8[6] * 20);
cellvoltages_mv[51] = (rx_frame.data.u8[7] * 20);
- } else if (poll_data_pid == 4) {
+ } else if (pid_reply == POLL_GROUP_4) {
cellvoltages_mv[77] = (rx_frame.data.u8[1] * 20);
cellvoltages_mv[78] = (rx_frame.data.u8[2] * 20);
cellvoltages_mv[79] = (rx_frame.data.u8[3] * 20);
@@ -282,16 +309,18 @@ void KiaHyundai64Battery::handle_incoming_can_frame(CAN_frame rx_frame) {
cellvoltages_mv[81] = (rx_frame.data.u8[5] * 20);
cellvoltages_mv[82] = (rx_frame.data.u8[6] * 20);
cellvoltages_mv[83] = (rx_frame.data.u8[7] * 20);
- } else if (poll_data_pid == 5) {
+ } else if (pid_reply == POLL_GROUP_5) {
heatertemp = rx_frame.data.u8[7];
+ } else if (pid_reply == POLL_GROUP_11) {
+ accumulated_fastcharging_energy_kWh = ((rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]);
}
break;
case 0x24: //Fourth datarow in PID group
- if (poll_data_pid == 1) {
+ if (pid_reply == POLL_GROUP_1) {
CellVmaxNo = rx_frame.data.u8[1];
CellVminNo = rx_frame.data.u8[3];
CellVoltMin_mV = (rx_frame.data.u8[2] * 20); //(volts *50) *20 =mV
- } else if (poll_data_pid == 2) {
+ } else if (pid_reply == POLL_GROUP_2) {
cellvoltages_mv[20] = (rx_frame.data.u8[1] * 20);
cellvoltages_mv[21] = (rx_frame.data.u8[2] * 20);
cellvoltages_mv[22] = (rx_frame.data.u8[3] * 20);
@@ -299,7 +328,7 @@ void KiaHyundai64Battery::handle_incoming_can_frame(CAN_frame rx_frame) {
cellvoltages_mv[24] = (rx_frame.data.u8[5] * 20);
cellvoltages_mv[25] = (rx_frame.data.u8[6] * 20);
cellvoltages_mv[26] = (rx_frame.data.u8[7] * 20);
- } else if (poll_data_pid == 3) {
+ } else if (pid_reply == POLL_GROUP_3) {
cellvoltages_mv[52] = (rx_frame.data.u8[1] * 20);
cellvoltages_mv[53] = (rx_frame.data.u8[2] * 20);
cellvoltages_mv[54] = (rx_frame.data.u8[3] * 20);
@@ -307,7 +336,7 @@ void KiaHyundai64Battery::handle_incoming_can_frame(CAN_frame rx_frame) {
cellvoltages_mv[56] = (rx_frame.data.u8[5] * 20);
cellvoltages_mv[57] = (rx_frame.data.u8[6] * 20);
cellvoltages_mv[58] = (rx_frame.data.u8[7] * 20);
- } else if (poll_data_pid == 4) {
+ } else if (pid_reply == POLL_GROUP_4) {
cellvoltages_mv[84] = (rx_frame.data.u8[1] * 20);
cellvoltages_mv[85] = (rx_frame.data.u8[2] * 20);
cellvoltages_mv[86] = (rx_frame.data.u8[3] * 20);
@@ -317,25 +346,30 @@ void KiaHyundai64Battery::handle_incoming_can_frame(CAN_frame rx_frame) {
if (rx_frame.data.u8[7] > 4) { // Data only valid on 98S
cellvoltages_mv[90] = (rx_frame.data.u8[7] * 20); // Perform extra checks
}
- } else if (poll_data_pid == 5) {
+ } else if (pid_reply == POLL_GROUP_5) {
batterySOH = ((rx_frame.data.u8[2] << 8) + rx_frame.data.u8[3]);
}
break;
case 0x25: //Fifth datarow in PID group
- if (poll_data_pid == 2) {
+ if (pid_reply == POLL_GROUP_1) {
+ cumulative_charge_current_ah =
+ ((rx_frame.data.u8[1] << 16) | (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]);
+ cumulative_discharge_current_ah =
+ ((rx_frame.data.u8[5] << 16) | (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]);
+ } else if (pid_reply == POLL_GROUP_2) {
cellvoltages_mv[27] = (rx_frame.data.u8[1] * 20);
cellvoltages_mv[28] = (rx_frame.data.u8[2] * 20);
cellvoltages_mv[29] = (rx_frame.data.u8[3] * 20);
cellvoltages_mv[30] = (rx_frame.data.u8[4] * 20);
cellvoltages_mv[31] = (rx_frame.data.u8[5] * 20);
- } else if (poll_data_pid == 3) {
+ } else if (pid_reply == POLL_GROUP_3) {
cellvoltages_mv[59] = (rx_frame.data.u8[1] * 20);
cellvoltages_mv[60] = (rx_frame.data.u8[2] * 20);
cellvoltages_mv[61] = (rx_frame.data.u8[3] * 20);
cellvoltages_mv[62] = (rx_frame.data.u8[4] * 20);
cellvoltages_mv[63] = (rx_frame.data.u8[5] * 20);
- } else if (poll_data_pid == 4) { // Data only valid on 98S
- if (rx_frame.data.u8[1] > 4) { // Perform extra checks
+ } else if (pid_reply == POLL_GROUP_4) { // Data only valid on 98S
+ if (rx_frame.data.u8[1] > 4) { // Perform extra checks
cellvoltages_mv[91] = (rx_frame.data.u8[1] * 20);
}
if (rx_frame.data.u8[2] > 4) { // Perform extra checks
@@ -350,8 +384,8 @@ void KiaHyundai64Battery::handle_incoming_can_frame(CAN_frame rx_frame) {
if (rx_frame.data.u8[5] > 4) { // Perform extra checks
cellvoltages_mv[95] = (rx_frame.data.u8[5] * 20);
}
- } else if (poll_data_pid == 5) { // Data only valid on 98S
- if (rx_frame.data.u8[4] > 4) { // Perform extra checks
+ } else if (pid_reply == POLL_GROUP_5) { // Data only valid on 98S
+ if (rx_frame.data.u8[4] > 4) { // Perform extra checks
cellvoltages_mv[96] = (rx_frame.data.u8[4] * 20);
}
if (rx_frame.data.u8[5] > 4) { // Perform extra checks
@@ -360,7 +394,11 @@ void KiaHyundai64Battery::handle_incoming_can_frame(CAN_frame rx_frame) {
}
break;
case 0x26: //Sixth datarow in PID group
- if (poll_data_pid == 5) {
+ if (pid_reply == POLL_GROUP_1) {
+ cumulative_energy_charged_kWh =
+ ((rx_frame.data.u8[2] << 16) | (rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4]);
+ cumulative_energy_discharged_HIGH_BYTE = ((rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]);
+ } else if (pid_reply == POLL_GROUP_5) {
//We have read all cells, check that content is valid:
for (uint8_t i = 85; i < 97; ++i) {
if (cellvoltages_mv[i] < 300) { // Zero the value if it's below 300
@@ -374,17 +412,24 @@ void KiaHyundai64Battery::handle_incoming_can_frame(CAN_frame rx_frame) {
}
break;
case 0x27: //Seventh datarow in PID group
- if (poll_data_pid == 1) {
+ if (pid_reply == POLL_GROUP_1) {
+ cumulative_energy_discharged_kWh = ((cumulative_energy_discharged_HIGH_BYTE << 8) | rx_frame.data.u8[1]);
+ powered_on_total_time = ((rx_frame.data.u8[2] << 24) | (rx_frame.data.u8[3] << 16) |
+ (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]);
BMS_ign = rx_frame.data.u8[6];
inverterVoltageFrameHigh = rx_frame.data.u8[7];
}
break;
case 0x28: //Eighth datarow in PID group
- if (poll_data_pid == 1) {
+ if (pid_reply == POLL_GROUP_1) {
inverterVoltage = (inverterVoltageFrameHigh << 8) + rx_frame.data.u8[1];
+ isolation_resistance_kOhm = ((rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]);
}
break;
+ default:
+ break;
}
+
break;
default:
break;
@@ -401,7 +446,8 @@ void KiaHyundai64Battery::transmit_can(unsigned long currentMillis) {
if (currentMillis - previousMillis100 >= INTERVAL_100_MS) {
previousMillis100 = currentMillis;
- if (contactor_closing_allowed == nullptr || *contactor_closing_allowed) {
+ if ((contactor_closing_allowed == nullptr || *contactor_closing_allowed) &&
+ datalayer.system.status.inverter_allows_contactor_closing) {
transmit_can_frame(&KIA64_553);
transmit_can_frame(&KIA64_57F);
transmit_can_frame(&KIA64_2A1);
@@ -412,7 +458,8 @@ void KiaHyundai64Battery::transmit_can(unsigned long currentMillis) {
if (currentMillis - previousMillis10 >= INTERVAL_10_MS) {
previousMillis10 = currentMillis;
- if (contactor_closing_allowed == nullptr || *contactor_closing_allowed) {
+ if ((contactor_closing_allowed == nullptr || *contactor_closing_allowed) &&
+ datalayer.system.status.inverter_allows_contactor_closing) {
switch (counter_200) {
case 0:
diff --git a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.h b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.h
index 60505cb6..7f8e6e06 100644
--- a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.h
+++ b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.h
@@ -79,7 +79,8 @@ class KiaHyundai64Battery : public CanBattery {
int16_t batteryAmps = 0;
int16_t temperatureMax = 0;
int16_t temperatureMin = 0;
- int16_t poll_data_pid = 0;
+ uint8_t poll_data_pid = 0;
+ uint16_t pid_reply = 0;
bool holdPidCounter = false;
uint8_t CellVmaxNo = 0;
uint8_t CellVminNo = 0;
@@ -92,6 +93,19 @@ class KiaHyundai64Battery : public CanBattery {
int8_t heatertemp = 0;
int8_t powerRelayTemperature = 0;
bool startedUp = false;
+ uint8_t ecu_serial_number[16] = {0};
+ uint8_t ecu_version_number[16] = {0};
+ uint32_t cumulative_charge_current_ah = 0;
+ uint32_t cumulative_discharge_current_ah = 0;
+ uint32_t cumulative_energy_charged_kWh = 0;
+ uint16_t cumulative_energy_discharged_HIGH_BYTE = 0;
+ uint32_t cumulative_energy_discharged_kWh = 0;
+ uint32_t powered_on_total_time = 0;
+ uint16_t isolation_resistance_kOhm = 0;
+ uint16_t number_of_standard_charging_sessions = 0;
+ uint16_t number_of_fastcharging_sessions = 0;
+ uint16_t accumulated_normal_charging_energy_kWh = 0;
+ uint16_t accumulated_fastcharging_energy_kWh = 0;
CAN_frame KIA_HYUNDAI_200 = {.FD = false,
.ext_ID = false,
@@ -126,42 +140,26 @@ class KiaHyundai64Battery : public CanBattery {
.DLC = 8,
.ID = 0x2A1,
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
- CAN_frame KIA64_7E4_id1 = {.FD = false,
- .ext_ID = false,
- .DLC = 8,
- .ID = 0x7E4,
- .data = {0x03, 0x22, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00}}; //Poll PID 03 22 01 01
- CAN_frame KIA64_7E4_id2 = {.FD = false,
- .ext_ID = false,
- .DLC = 8,
- .ID = 0x7E4,
- .data = {0x03, 0x22, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00}}; //Poll PID 03 22 01 02
- CAN_frame KIA64_7E4_id3 = {.FD = false,
- .ext_ID = false,
- .DLC = 8,
- .ID = 0x7E4,
- .data = {0x03, 0x22, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00}}; //Poll PID 03 22 01 03
- CAN_frame KIA64_7E4_id4 = {.FD = false,
- .ext_ID = false,
- .DLC = 8,
- .ID = 0x7E4,
- .data = {0x03, 0x22, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00}}; //Poll PID 03 22 01 04
- CAN_frame KIA64_7E4_id5 = {.FD = false,
- .ext_ID = false,
- .DLC = 8,
- .ID = 0x7E4,
- .data = {0x03, 0x22, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00}}; //Poll PID 03 22 01 05
- CAN_frame KIA64_7E4_id6 = {.FD = false,
- .ext_ID = false,
- .DLC = 8,
- .ID = 0x7E4,
- .data = {0x03, 0x22, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00}}; //Poll PID 03 22 01 06
+ CAN_frame KIA64_7E4_poll = {.FD = false,
+ .ext_ID = false,
+ .DLC = 8,
+ .ID = 0x7E4,
+ .data = {0x03, 0x22, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00}};
CAN_frame KIA64_7E4_ack = {
.FD = false,
.ext_ID = false,
.DLC = 8,
.ID = 0x7E4,
- .data = {0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; //Ack frame, correct PID is returned
+ .data = {0x30, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00}}; //Ack frame, correct PID is returned
+ static const int POLL_GROUP_1 = 0x0101;
+ static const int POLL_GROUP_2 = 0x0102;
+ static const int POLL_GROUP_3 = 0x0103;
+ static const int POLL_GROUP_4 = 0x0104;
+ static const int POLL_GROUP_5 = 0x0105;
+ static const int POLL_GROUP_6 = 0x0106;
+ static const int POLL_GROUP_11 = 0x0111;
+ static const int POLL_ECU_SERIAL = 0xF18C;
+ static const int POLL_ECU_VERSION = 0xF191;
};
#endif
diff --git a/Software/src/battery/KIA-HYUNDAI-64-HTML.h b/Software/src/battery/KIA-HYUNDAI-64-HTML.h
index 23d5916e..d96c447a 100644
--- a/Software/src/battery/KIA-HYUNDAI-64-HTML.h
+++ b/Software/src/battery/KIA-HYUNDAI-64-HTML.h
@@ -11,16 +11,45 @@ class KiaHyundai64HtmlRenderer : public BatteryHtmlRenderer {
String get_status_html() {
String content;
-
auto print_hyundai = [&content](DATALAYER_INFO_KIAHYUNDAI64& data) {
- content += "Cells: " + String(data.total_cell_count) + "S
";
- content += "12V voltage: " + String(data.battery_12V / 10.0, 1) + "
";
- content += "Waterleakage: " + String(data.waterleakageSensor) + "
";
- content += "Temperature, water inlet: " + String(data.temperature_water_inlet) + "
";
- content += "Temperature, power relay: " + String(data.powerRelayTemperature) + "
";
+ char readableSerialNumber[17]; // One extra space for null terminator
+ memcpy(readableSerialNumber, data.ecu_serial_number, sizeof(data.ecu_serial_number));
+ readableSerialNumber[16] = '\0'; // Null terminate the string
+ char readableVersionNumber[17]; // One extra space for null terminator
+ memcpy(readableVersionNumber, data.ecu_version_number, sizeof(data.ecu_version_number));
+ readableVersionNumber[16] = '\0'; // Null terminate the string
+
+ content += "BMS serial number: " + String(readableSerialNumber) + "
";
+ content += "BMS software version: " + String(readableVersionNumber) + "
";
+ content += "Cells: " + String(data.total_cell_count) + " S
";
+ content += "12V voltage: " + String(data.battery_12V / 10.0, 1) + " V
";
+ content += "Waterleakage: ";
+ if (data.waterleakageSensor == 0) {
+ content += " LEAK DETECTED
";
+ } else if (data.waterleakageSensor == 164) {
+ content += " No leakage";
+ } else {
+ content += String(data.waterleakageSensor) + "";
+ }
+ content += "Temperature, water inlet: " + String(data.temperature_water_inlet) + " °C
";
+ content += "Temperature, power relay: " + String(data.powerRelayTemperature) + " °C
";
content += "Batterymanagement mode: " + String(data.batteryManagementMode) + "
";
content += "BMS ignition: " + String(data.BMS_ign) + "
";
content += "Battery relay: " + String(data.batteryRelay) + "
";
+ content += "Inverter voltage: " + String(data.inverterVoltage) + " V
";
+ content += "Isolation resistance: " + String(data.isolation_resistance_kOhm) + " kOhm
";
+ content += "Power on total time: " + String(data.powered_on_total_time) + " s
";
+ content += "Fastcharging sessions: " + String(data.number_of_fastcharging_sessions) + " x
";
+ content += "Slowcharging sessions: " + String(data.number_of_standard_charging_sessions) + " x
";
+ content +=
+ "Normal charged energy amount: " + String(data.accumulated_normal_charging_energy_kWh) + " kWh
";
+ content += "Fastcharged energy amount: " + String(data.accumulated_fastcharging_energy_kWh) + " kWh
";
+ content += "Total amount charged energy: " + String(data.cumulative_energy_charged_kWh / 10.0) + " kWh
";
+ content +=
+ "Total amount discharged energy: " + String(data.cumulative_energy_discharged_kWh / 10.0) + " kWh
";
+ content += "Cumulative charge current: " + String(data.cumulative_charge_current_ah / 10.0) + " Ah
";
+ content +=
+ "Cumulative discharge current: " + String(data.cumulative_discharge_current_ah / 10.0) + " Ah
";
};
print_hyundai(*kia_datalayer);
diff --git a/Software/src/battery/SAMSUNG-SDI-LV-BATTERY.cpp b/Software/src/battery/SAMSUNG-SDI-LV-BATTERY.cpp
new file mode 100644
index 00000000..06149f3e
--- /dev/null
+++ b/Software/src/battery/SAMSUNG-SDI-LV-BATTERY.cpp
@@ -0,0 +1,102 @@
+#include "SAMSUNG-SDI-LV-BATTERY.h"
+#include "../communication/can/comm_can.h"
+#include "../datalayer/datalayer.h"
+#include "../devboard/utils/events.h"
+
+/*
+- Baud rate: 500kbps
+- Format: CAN2.0A 11 bit identifier
+- Data Length: 8byte
+- CAN data is transmitted with encoding in little endian – low byte first – unless stated otherwise.
+- Broadcasting period: 500ms
+
+TODO: Implement the error bit handling for easier visualization if the battery stops operating
+- alarms_frame0
+- alarms_frame1
+- protection_frame2
+- protection_frame3
+
+*/
+
+void SamsungSdiLVBattery::update_values() {
+
+ datalayer.battery.status.real_soc = system_SOC * 100;
+
+ datalayer.battery.status.remaining_capacity_Wh = static_cast(
+ (static_cast(datalayer.battery.status.real_soc) / 10000) * datalayer.battery.info.total_capacity_Wh);
+
+ datalayer.battery.status.soh_pptt = system_SOH * 100;
+
+ datalayer.battery.status.voltage_dV = system_voltage / 10;
+
+ datalayer.battery.status.current_dA = system_current * 10;
+
+ datalayer.battery.status.max_charge_power_W = system_voltage * charge_current_limit;
+
+ datalayer.battery.status.max_discharge_power_W = system_voltage * discharge_current_limit;
+
+ datalayer.battery.status.temperature_min_dC = (int16_t)(minimum_cell_temperature * 10);
+
+ datalayer.battery.status.temperature_max_dC = (int16_t)(maximum_cell_temperature * 10);
+
+ datalayer.battery.status.cell_max_voltage_mV = maximum_cell_voltage;
+
+ datalayer.battery.status.cell_min_voltage_mV = minimum_cell_voltage;
+
+ datalayer.battery.info.max_design_voltage_dV = battery_charge_voltage;
+
+ datalayer.battery.info.min_design_voltage_dV = battery_discharge_voltage;
+}
+
+void SamsungSdiLVBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
+ switch (rx_frame.ID) {
+ case 0x500: //Voltage, current, SOC, SOH
+ datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
+ system_voltage = ((rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]);
+ system_current = ((rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]);
+ system_SOC = rx_frame.data.u8[4];
+ system_SOH = rx_frame.data.u8[5];
+ break;
+ case 0x501:
+ alarms_frame0 = rx_frame.data.u8[0];
+ alarms_frame1 = rx_frame.data.u8[1];
+ protection_frame2 = rx_frame.data.u8[2];
+ protection_frame3 = rx_frame.data.u8[3];
+ break;
+ case 0x502:
+ battery_charge_voltage = ((rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]);
+ charge_current_limit = ((rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]);
+ discharge_current_limit = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]);
+ battery_discharge_voltage = ((rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]);
+ break;
+ case 0x503:
+ maximum_cell_voltage = ((rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]);
+ minimum_cell_voltage = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]);
+ break;
+ case 0x504:
+ maximum_cell_temperature = rx_frame.data.u8[5];
+ minimum_cell_temperature = rx_frame.data.u8[6];
+ break;
+ case 0x505:
+ system_permanent_failure_status_dry_contact = rx_frame.data.u8[2];
+ system_permanent_failure_status_fuse_open = rx_frame.data.u8[3];
+ break;
+ default:
+ break;
+ }
+}
+
+void SamsungSdiLVBattery::transmit_can(unsigned long currentMillis) {
+ //No periodic sending required
+}
+
+void SamsungSdiLVBattery::setup(void) { // Performs one time setup at startup
+ strncpy(datalayer.system.info.battery_protocol, Name, 63);
+ datalayer.system.info.battery_protocol[63] = '\0';
+ datalayer.system.status.battery_allows_contactor_closing = true;
+ 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.total_capacity_Wh = 5000;
+}
diff --git a/Software/src/battery/SAMSUNG-SDI-LV-BATTERY.h b/Software/src/battery/SAMSUNG-SDI-LV-BATTERY.h
new file mode 100644
index 00000000..61da5b9f
--- /dev/null
+++ b/Software/src/battery/SAMSUNG-SDI-LV-BATTERY.h
@@ -0,0 +1,46 @@
+#ifndef SAMSUNG_SDI_LV_BATTERY_H
+#define SAMSUNG_SDI_LV_BATTERY_H
+#include
+#include "../datalayer/datalayer.h"
+#include "CanBattery.h"
+
+#ifdef SAMSUNG_SDI_LV_BATTERY
+#define SELECTED_BATTERY_CLASS SamsungSdiLVBattery
+#endif
+
+class SamsungSdiLVBattery : public CanBattery {
+ public:
+ virtual void setup(void);
+ virtual void handle_incoming_can_frame(CAN_frame rx_frame);
+ virtual void update_values();
+ virtual void transmit_can(unsigned long currentMillis);
+ static constexpr const char* Name = "Samsung SDI LV Battery";
+
+ private:
+ static const int MAX_PACK_VOLTAGE_DV = 600; //5000 = 500.0V
+ static const int MIN_PACK_VOLTAGE_DV = 300;
+ static const int MAX_CELL_DEVIATION_MV = 250;
+ static const int MAX_CELL_VOLTAGE_MV = 4200;
+ static const int MIN_CELL_VOLTAGE_MV = 3000;
+
+ uint16_t system_voltage = 50000;
+ int16_t system_current = 0;
+ uint8_t system_SOC = 50;
+ uint8_t system_SOH = 99;
+ uint16_t battery_charge_voltage = 9999;
+ uint16_t charge_current_limit = 0;
+ uint16_t discharge_current_limit = 0;
+ uint16_t battery_discharge_voltage = 0;
+ uint8_t alarms_frame0 = 0;
+ uint8_t alarms_frame1 = 0;
+ uint8_t protection_frame2 = 0;
+ uint8_t protection_frame3 = 0;
+ uint16_t maximum_cell_voltage = 3700;
+ uint16_t minimum_cell_voltage = 3700;
+ int8_t maximum_cell_temperature = 0;
+ int8_t minimum_cell_temperature = 0;
+ uint8_t system_permanent_failure_status_dry_contact = 0;
+ uint8_t system_permanent_failure_status_fuse_open = 0;
+};
+
+#endif
diff --git a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp
index d0e62216..ac38a525 100644
--- a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp
+++ b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp
@@ -75,7 +75,6 @@ unsigned long currentTime = 0;
unsigned long lastPowerRemovalTime = 0;
unsigned long bmsPowerOnTime = 0;
const unsigned long powerRemovalInterval = 24 * 60 * 60 * 1000; // 24 hours in milliseconds
-const unsigned long powerRemovalDuration = 30000; // 30 seconds in milliseconds
const unsigned long bmsWarmupDuration = 3000;
void set(uint8_t pin, bool direction, uint32_t pwm_freq = 0xFFFF) {
@@ -306,8 +305,9 @@ void handle_BMSpower() {
}
}
- // If power has been removed for 30 seconds, restore the power
- if (datalayer.system.status.BMS_reset_in_progress && currentTime - lastPowerRemovalTime >= powerRemovalDuration) {
+ // If power has been removed for user configured interval (1-59 seconds), restore the power
+ if (datalayer.system.status.BMS_reset_in_progress &&
+ currentTime - lastPowerRemovalTime >= datalayer.battery.settings.user_set_bms_reset_duration_ms) {
// Reapply power to the BMS
digitalWrite(bms_power_pin, HIGH);
bmsPowerOnTime = currentTime;
diff --git a/Software/src/communication/nvm/comm_nvm.cpp b/Software/src/communication/nvm/comm_nvm.cpp
index 8fbe85a9..a7ec7e2d 100644
--- a/Software/src/communication/nvm/comm_nvm.cpp
+++ b/Software/src/communication/nvm/comm_nvm.cpp
@@ -79,6 +79,10 @@ void init_stored_settings() {
if (temp < 16) {
datalayer.battery.settings.sofar_user_specified_battery_id = temp;
}
+ temp = settings.getUInt("BMSRESETDUR", false);
+ if (temp != 0) {
+ datalayer.battery.settings.user_set_bms_reset_duration_ms = temp;
+ }
#ifdef COMMON_IMAGE
user_selected_battery_type = (BatteryType)settings.getUInt("BATTTYPE", (int)BatteryType::None);
@@ -187,6 +191,9 @@ void store_settings() {
if (!settings.putUInt("SOFAR_ID", datalayer.battery.settings.sofar_user_specified_battery_id)) {
set_event(EVENT_PERSISTENT_SAVE_INFO, 12);
}
+ if (!settings.putUInt("BMSRESETDUR", datalayer.battery.settings.sofar_user_specified_battery_id)) {
+ set_event(EVENT_PERSISTENT_SAVE_INFO, 13);
+ }
settings.end(); // Close preferences handle
}
diff --git a/Software/src/datalayer/datalayer.h b/Software/src/datalayer/datalayer.h
index 6f6b6c2b..af524267 100644
--- a/Software/src/datalayer/datalayer.h
+++ b/Software/src/datalayer/datalayer.h
@@ -139,6 +139,9 @@ typedef struct {
/** The user specified maximum allowed discharge voltage, in deciVolt. 3000 = 300.0 V */
uint16_t max_user_set_discharge_voltage_dV = BATTERY_MAX_DISCHARGE_VOLTAGE;
+ /** The user specified BMS reset period. Keeps track on how many milliseconds should we keep power off during daily BMS reset */
+ uint16_t user_set_bms_reset_duration_ms = 30000;
+
/** Parameters for keeping track of the limiting factor in the system */
bool user_settings_limit_discharge = false;
bool user_settings_limit_charge = false;
diff --git a/Software/src/datalayer/datalayer_extended.h b/Software/src/datalayer/datalayer_extended.h
index d4ad098e..5b0a26ac 100644
--- a/Software/src/datalayer/datalayer_extended.h
+++ b/Software/src/datalayer/datalayer_extended.h
@@ -312,6 +312,7 @@ typedef struct {
uint32_t pid_time_spent_over_55c = 0;
uint32_t pid_contactor_closing_counter = 0;
uint32_t pid_date_of_manufacture = 0;
+ uint16_t pid_SOH_cell_1 = 0;
} DATALAYER_INFO_ECMP;
typedef struct {
@@ -350,6 +351,19 @@ typedef struct {
uint8_t batteryManagementMode = 0;
uint8_t BMS_ign = 0;
uint8_t batteryRelay = 0;
+ uint16_t inverterVoltage = 0;
+ uint8_t ecu_serial_number[16] = {0};
+ uint8_t ecu_version_number[16] = {0};
+ uint32_t cumulative_charge_current_ah = 0;
+ uint32_t cumulative_discharge_current_ah = 0;
+ uint32_t cumulative_energy_charged_kWh = 0;
+ uint32_t cumulative_energy_discharged_kWh = 0;
+ uint32_t powered_on_total_time = 0;
+ uint16_t isolation_resistance_kOhm = 0;
+ uint16_t number_of_standard_charging_sessions = 0;
+ uint16_t number_of_fastcharging_sessions = 0;
+ uint16_t accumulated_normal_charging_energy_kWh = 0;
+ uint16_t accumulated_fastcharging_energy_kWh = 0;
} DATALAYER_INFO_KIAHYUNDAI64;
typedef struct {
@@ -750,7 +764,7 @@ typedef struct {
uint16_t BECMsupplyVoltage = 0;
uint16_t BECMBatteryVoltage = 0;
- uint16_t BECMBatteryCurrent = 0;
+ int16_t BECMBatteryCurrent = 0;
uint16_t BECMUDynMaxLim = 0;
uint16_t BECMUDynMinLim = 0;
diff --git a/Software/src/devboard/hal/hal.h b/Software/src/devboard/hal/hal.h
index 1bb48d97..b96fc574 100644
--- a/Software/src/devboard/hal/hal.h
+++ b/Software/src/devboard/hal/hal.h
@@ -59,16 +59,31 @@ class Esp32Hal {
return alloc_pins(name, pins[Is]...);
}
+ // Base case: no more pins
+ inline bool alloc_pins_ignore_unused_impl(const char* name) {
+ return alloc_pins(name); // Call with 0 pins
+ }
+
+ // Recursive case: process one pin at a time
+ template
+ bool alloc_pins_ignore_unused_impl(const char* name, gpio_num_t first, Rest... rest) {
+ if (first == GPIO_NUM_NC) {
+ return alloc_pins_ignore_unused_impl(name, rest...);
+ } else {
+ return call_alloc_pins_filtered(name, first, rest...);
+ }
+ }
+
+ // This helper just forwards pins after filtering is done
+ template
+ bool call_alloc_pins_filtered(const char* name, Pins... pins) {
+ return alloc_pins(name, pins...);
+ }
+
+ // Entry point
template
bool alloc_pins_ignore_unused(const char* name, Pins... pins) {
- std::vector valid_pins;
- for (gpio_num_t pin : std::vector{static_cast(pins)...}) {
- if (pin != GPIO_NUM_NC) {
- valid_pins.push_back(pin);
- }
- }
-
- return alloc_pins_from_vector(name, valid_pins, std::make_index_sequence{});
+ return alloc_pins_ignore_unused_impl(name, static_cast(pins)...);
}
virtual bool always_enable_bms_power() { return false; }
diff --git a/Software/src/devboard/safety/safety.cpp b/Software/src/devboard/safety/safety.cpp
index ea98e94c..36137fba 100644
--- a/Software/src/devboard/safety/safety.cpp
+++ b/Software/src/devboard/safety/safety.cpp
@@ -130,7 +130,8 @@ void update_machineryprotection() {
// Battery is fully charged. Dont allow any more power into it
// Normally the BMS will send 0W allowed, but this acts as an additional layer of safety
- if (datalayer.battery.status.reported_soc == 10000) //Scaled SOC% value is 100.00%
+ if (datalayer.battery.status.reported_soc == 10000 ||
+ datalayer.battery.status.real_soc == 10000) //Either Scaled OR Real SOC% value is 100.00%
{
if (!battery_full_event_fired) {
set_event(EVENT_BATTERY_FULL, 0);
@@ -145,7 +146,8 @@ void update_machineryprotection() {
// Battery is empty. Do not allow further discharge.
// Normally the BMS will send 0W allowed, but this acts as an additional layer of safety
if (datalayer.battery.status.bms_status == ACTIVE) {
- if (datalayer.battery.status.reported_soc == 0) { //Scaled SOC% value is 0.00%
+ if (datalayer.battery.status.reported_soc == 0 ||
+ datalayer.battery.status.real_soc == 0) { //Either Scaled OR Real SOC% value is 0.00%, time to stop
if (!battery_empty_event_fired) {
set_event(EVENT_BATTERY_EMPTY, 0);
battery_empty_event_fired = true;
diff --git a/Software/src/devboard/utils/events.cpp b/Software/src/devboard/utils/events.cpp
index f4c62038..12a6e0d3 100644
--- a/Software/src/devboard/utils/events.cpp
+++ b/Software/src/devboard/utils/events.cpp
@@ -40,6 +40,7 @@ void init_events(void) {
events.entries[EVENT_CAN_CHARGER_MISSING].level = EVENT_LEVEL_INFO;
events.entries[EVENT_CAN_INVERTER_MISSING].level = EVENT_LEVEL_WARNING;
events.entries[EVENT_CONTACTOR_WELDED].level = EVENT_LEVEL_WARNING;
+ events.entries[EVENT_CONTACTOR_OPEN].level = EVENT_LEVEL_WARNING;
events.entries[EVENT_CPU_OVERHEATING].level = EVENT_LEVEL_WARNING;
events.entries[EVENT_CPU_OVERHEATED].level = EVENT_LEVEL_ERROR;
events.entries[EVENT_WATER_INGRESS].level = EVENT_LEVEL_ERROR;
@@ -191,6 +192,8 @@ String get_event_message_string(EVENTS_ENUM_TYPE event) {
return "Inverter not sending messages via CAN for the last 60 seconds. Check wiring!";
case EVENT_CONTACTOR_WELDED:
return "Contactors sticking/welded. Inspect battery with caution!";
+ case EVENT_CONTACTOR_OPEN:
+ return "Battery decided to open contactors. Inspect battery!";
case EVENT_CPU_OVERHEATING:
return "Battery-Emulator CPU overheating! Increase airflow/cooling to increase hardware lifespan!";
case EVENT_CPU_OVERHEATED:
diff --git a/Software/src/devboard/utils/events.h b/Software/src/devboard/utils/events.h
index 3dc6f147..3b26cf04 100644
--- a/Software/src/devboard/utils/events.h
+++ b/Software/src/devboard/utils/events.h
@@ -22,6 +22,7 @@
XX(EVENT_CAN_NATIVE_TX_FAILURE) \
XX(EVENT_CHARGE_LIMIT_EXCEEDED) \
XX(EVENT_CONTACTOR_WELDED) \
+ XX(EVENT_CONTACTOR_OPEN) \
XX(EVENT_CPU_OVERHEATING) \
XX(EVENT_CPU_OVERHEATED) \
XX(EVENT_DISCHARGE_LIMIT_EXCEEDED) \
diff --git a/Software/src/devboard/utils/logging.h b/Software/src/devboard/utils/logging.h
index dcc53340..f76dc3ff 100644
--- a/Software/src/devboard/utils/logging.h
+++ b/Software/src/devboard/utils/logging.h
@@ -2,6 +2,7 @@
#define __LOGGING_H__
#include
+#include "../../../USER_SETTINGS.h"
#include "Print.h"
#include "types.h"
diff --git a/Software/src/devboard/webserver/debug_logging_html.cpp b/Software/src/devboard/webserver/debug_logging_html.cpp
index eff74dd4..f9657f9a 100644
--- a/Software/src/devboard/webserver/debug_logging_html.cpp
+++ b/Software/src/devboard/webserver/debug_logging_html.cpp
@@ -4,8 +4,45 @@
#include "index_html.h"
#if defined(DEBUG_VIA_WEB) || defined(LOG_TO_SD)
+char* strnchr(const char* s, int c, size_t n) {
+ // Like strchr, but only searches the first 'n' bytes of the string.
+
+ if (s == NULL) {
+ return NULL;
+ }
+
+ // Iterate through the string up to 'n' characters or until a null terminator is found.
+ for (size_t i = 0; i < n && s[i] != '\0'; ++i) {
+ if (s[i] == c) {
+ // Character found, return a pointer to it.
+ return (char*)&s[i];
+ }
+ }
+
+ // If the character to be found is the null terminator, and we haven't exceeded
+ // 'n' bytes, check if the null terminator is at the current position.
+ if (c == '\0') {
+ for (size_t i = 0; i < n; ++i) {
+ if (s[i] == '\0') {
+ return (char*)&s[i];
+ }
+ }
+ }
+
+ // Character not found within the first 'n' bytes.
+ return NULL;
+}
+
String debug_logger_processor(void) {
- String content = String(index_html_header);
+ String content = String();
+ // Reserve enough space for the content to avoid reallocations.
+ if (!content.reserve(1000 + sizeof(datalayer.system.info.logged_can_messages))) {
+ if (content.reserve(15)) {
+ content += "Out of memory.";
+ }
+ return content;
+ }
+ content += index_html_header;
// Page format
content += "