From c7911e2e6c9918f5d28a282bffd2da2dfa0d816e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20J=C3=A4ger?= Date: Fri, 23 Jun 2023 19:13:05 +0200 Subject: [PATCH] Switch to ThingSet SDK --- app/Kconfig | 60 - app/prj.conf | 14 +- app/src/CMakeLists.txt | 4 +- app/src/data_objects.cpp | 1991 +++++++++----------- app/src/data_objects.h | 58 +- app/src/data_storage.cpp | 289 --- app/src/data_storage.h | 33 - app/src/dcdc.cpp | 7 +- app/src/ext/CMakeLists.txt | 7 - app/src/ext/README.md | 3 - app/src/ext/can.cpp | 260 --- app/src/ext/serial.cpp | 164 -- app/src/main.cpp | 5 +- app/src/{ext => }/oled.cpp | 0 app/src/setup.cpp | 1 - app/src/setup.h | 2 - boards/arm/mppt_1210_hus/mppt_1210_hus.dts | 3 +- boards/arm/mppt_2420_hpx/mppt_2420_hpx.dts | 2 +- west.yml | 7 +- 19 files changed, 934 insertions(+), 1976 deletions(-) delete mode 100644 app/src/data_storage.cpp delete mode 100644 app/src/data_storage.h delete mode 100644 app/src/ext/CMakeLists.txt delete mode 100644 app/src/ext/README.md delete mode 100644 app/src/ext/can.cpp delete mode 100644 app/src/ext/serial.cpp rename app/src/{ext => }/oled.cpp (100%) diff --git a/app/Kconfig b/app/Kconfig index e93dc8dc..6a47a93d 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -325,64 +325,8 @@ config UEXT_OLED_BRIGHTNESS range 1 255 default 1 -config UEXT_SERIAL_THINGSET - depends on THINGSET_SERIAL - bool "Use UEXT serial for ThingSet interface" - default y - help - If the ThingSet interface is not attached to the serial port in the UEXT connector, the - serial in the LS.one port or the debug connector is used (if existing). - endmenu # UEXT port - -menu "ThingSet interfaces" - -config THINGSET_SERIAL - bool "ThingSet serial interface" - -config THINGSET_SERIAL_RX_BUF_SIZE - depends on THINGSET_SERIAL - int "ThingSet serial RX buffer size" - range 64 2048 - default 512 - -config THINGSET_SERIAL_TX_BUF_SIZE - depends on THINGSET_SERIAL - int "ThingSet serial TX buffer size" - range 256 2048 - default 1024 - -config THINGSET_SERIAL_PUB_DEFAULT - bool "Enable serial publication messages at startup" - depends on THINGSET_SERIAL - default y - -config THINGSET_CAN - depends on CAN - bool "ThingSet CAN interface" - -config THINGSET_CAN_PUB_DEFAULT - bool "Enable CAN publication messages at startup" - depends on THINGSET_CAN - default y - -config THINGSET_CAN_DEFAULT_NODE_ID - depends on THINGSET_CAN - int "ThingSet CAN default node ID" - range 0 255 - default 20 - -config THINGSET_EXPERT_PASSWORD - string "ThingSet expert user password" - default "expert123" - -config THINGSET_MAKER_PASSWORD - string "ThingSet maker password" - default "maker456" - -endmenu # ThingSet interfaces - menu "Logging setup" config CAN_LOG_LEVEL @@ -473,9 +417,5 @@ endif # include custom Kconfig if existing orsource "../src/custom/Kconfig" -#if 0 -#orsource "modules/thingset/zephyr/Kconfig.thingset" -#endif - # include main Zephyr menu entries from Zephyr root directory source "Kconfig.zephyr" diff --git a/app/prj.conf b/app/prj.conf index 6a2755c2..121cd03b 100644 --- a/app/prj.conf +++ b/app/prj.conf @@ -27,16 +27,16 @@ CONFIG_LOG=y CONFIG_LOG_MODE_MINIMAL=y CONFIG_THINGSET=y -CONFIG_THINGSET_NESTED_JSON=y - -# ThingSet protocol interface via UART serial +CONFIG_THINGSET_SDK=y +CONFIG_THINGSET_STORAGE=y CONFIG_THINGSET_SERIAL=y +CONFIG_THINGSET_STORAGE_DATA_VERSION=6 +CONFIG_THINGSET_NODE_NAME="Libre Solar MPPT" -# Uncomment to disable regular data publication on ThingSet serial at startup -#CONFIG_THINGSET_SERIAL_PUB_DEFAULT=n +# Must be lower than LED thread to avoid flickering in boards with charlieplexing +CONFIG_THINGSET_SDK_THREAD_PRIORITY=6 -# Uncomment to use LS.one or debug RX/TX connector instead of UEXT serial for ThingSet -#CONFIG_UEXT_SERIAL_THINGSET=n +#CONFIG_THINGSET_REPORTING_LIVE_ENABLE_PRESET=n # Uncomment to enable I2C OLED display in UEXT connector #CONFIG_UEXT_OLED_DISPLAY=y diff --git a/app/src/CMakeLists.txt b/app/src/CMakeLists.txt index dae10cf6..0d338efb 100644 --- a/app/src/CMakeLists.txt +++ b/app/src/CMakeLists.txt @@ -5,13 +5,13 @@ zephyr_include_directories(.) target_sources(app PRIVATE bat_charger.cpp data_objects.cpp - data_storage.cpp daq.cpp daq_driver.c device_status.cpp dcdc.cpp half_bridge.c hardware.cpp + oled.cpp leds.cpp load.cpp load_driver.c @@ -22,8 +22,6 @@ target_sources(app PRIVATE setup.cpp ) -add_subdirectory(ext) - if(${CONFIG_CUSTOM_DATA_OBJECTS_FILE}) target_sources(app PRIVATE data_objects_custom.cpp) endif() diff --git a/app/src/data_objects.cpp b/app/src/data_objects.cpp index 6d1766ac..fffef244 100644 --- a/app/src/data_objects.cpp +++ b/app/src/data_objects.cpp @@ -19,12 +19,14 @@ #include #include -#include "data_storage.h" #include "dcdc.h" #include "hardware.h" #include "helper.h" #include "setup.h" -#include "thingset.h" + +#include +#include +#include LOG_MODULE_REGISTER(data_objects, CONFIG_DATA_OBJECTS_LOG_LEVEL); @@ -32,12 +34,11 @@ LOG_MODULE_REGISTER(data_objects, CONFIG_DATA_OBJECTS_LOG_LEVEL); // (e.g. data_objects_custom.cpp) #ifndef CONFIG_CUSTOM_DATA_OBJECTS_FILE -const char manufacturer[] = "Libre Solar"; -const char metadata_url[] = - "https://files.libre.solar/tsm/cc-" STRINGIFY(DATA_OBJECTS_VERSION) ".json"; -const char device_type[] = DT_PROP(DT_PATH(pcb), type); -const char hardware_version[] = DT_PROP(DT_PATH(pcb), version_str); -const char firmware_version[] = FIRMWARE_VERSION_ID; +char manufacturer[] = "Libre Solar"; +char metadata_url[] = "https://files.libre.solar/tsm/cc-" STRINGIFY(DATA_OBJECTS_VERSION) ".json"; +char device_type[] = DT_PROP(DT_PATH(pcb), type); +char hardware_version[] = DT_PROP(DT_PATH(pcb), version_str); +char firmware_version[] = FIRMWARE_VERSION_ID; char device_id[9]; #ifdef CONFIG_SOC_FAMILY_STM32 @@ -48,7 +49,7 @@ uint32_t flash_size = 128; uint32_t flash_page_size = 0x800; #endif -static char auth_password[11]; +// static char auth_password[11]; #if CONFIG_LV_TERMINAL_BATTERY #define bat_bus lv_bus @@ -62,1089 +63,964 @@ static char auth_password[11]; #define solar_bus lv_bus #endif -bool pub_serial_enable = IS_ENABLED(CONFIG_THINGSET_SERIAL_PUB_DEFAULT); - -#if CONFIG_THINGSET_CAN -bool pub_can_enable = IS_ENABLED(CONFIG_THINGSET_CAN_PUB_DEFAULT); -uint16_t can_node_addr = CONFIG_THINGSET_CAN_DEFAULT_NODE_ID; -#endif - /** * Thing Set Data Objects (see thingset.io for specification) */ /* clang-format off */ -static ThingSetDataObject data_objects[] = { - - /////////////////////////////////////////////////////////////////////////////////////////////// - - /*{ - "title": { - "en": "ThingSet Node ID", - "de": "ThingSet Knoten-ID" - } - }*/ - TS_ITEM_STRING(0x1D, "cNodeID", device_id, sizeof(device_id), - ID_ROOT, TS_ANY_R | TS_MKR_W, SUBSET_NVM), - - /*{ - "title": { - "en": "ThingSet Metadata URL", - "de": "ThingSet Metadata URL" - } - }*/ - TS_ITEM_STRING(0x18, "cMetadataURL", metadata_url, sizeof(metadata_url), - ID_ROOT, TS_ANY_R, 0), - - /////////////////////////////////////////////////////////////////////////////////////////////// - - TS_GROUP(ID_DEVICE, "Device", TS_NO_CALLBACK, ID_ROOT), - - /*{ - "title": { - "en": "Manufacturer", - "de": "Hersteller" - } - }*/ - TS_ITEM_STRING(0x20, "cManufacturer", manufacturer, 0, - ID_DEVICE, TS_ANY_R, 0), - - /*{ - "title": { - "en": "Device Type", - "de": "Gerätetyp" - } - }*/ - TS_ITEM_STRING(0x21, "cType", device_type, 0, - ID_DEVICE, TS_ANY_R, 0), - - /*{ - "title": { - "en": "Hardware Version", - "de": "Hardware-Version" - } - }*/ - TS_ITEM_STRING(0x22, "cHardwareVersion", hardware_version, 0, - ID_DEVICE, TS_ANY_R, 0), - - /*{ - "title": { - "en": "Firmware Version", - "de": "Firmware-Version" - } - }*/ - TS_ITEM_STRING(0x23, "cFirmwareVersion", firmware_version, 0, - ID_DEVICE, TS_ANY_R, 0), - - /*{ - "title": { - "en": "Time since last reset", - "de": "Zeit seit Systemstart" - } - }*/ - TS_ITEM_UINT32(0x30, "rUptime_s", ×tamp, - ID_DEVICE, TS_ANY_R, SUBSET_SER), - - /*{ - "title": { - "en": "Error Flags", - "de": "Fehlercode" - } - }*/ - TS_ITEM_UINT32(0x5F, "rErrorFlags", &dev_stat.error_flags, - ID_DEVICE, TS_ANY_R, SUBSET_SER | SUBSET_CAN), - - /*{ - "title": { - "en": "Internal Temperature", - "de": "Interne Temperatur" - } - }*/ - TS_ITEM_FLOAT(0x36, "rIntTemp_degC", &dev_stat.internal_temp, 1, - ID_DEVICE, TS_ANY_R, 0), - - /*{ - "title": { - "en": "Peak Internal Temperature (all-time)", - "de": "Interne Maximaltemperatur (gesamt)" - } - }*/ - TS_ITEM_INT16(0x79, "pIntTempMax_degC", &dev_stat.int_temp_max, - ID_DEVICE, TS_ANY_R | TS_MKR_W, SUBSET_NVM), - - /*{ - "title": { - "en": "Day Counter", - "de": "Tagzähler" - } - }*/ - TS_ITEM_UINT32(0x71, "pDayCount", &dev_stat.day_counter, - ID_DEVICE, TS_ANY_R | TS_MKR_W, SUBSET_NVM), + +/////////////////////////////////////////////////////////////////////////////////////////////// + +THINGSET_ADD_GROUP(TS_ID_ROOT, ID_DEVICE, "Device", THINGSET_NO_CALLBACK); + +/*{ + "title": { + "en": "Manufacturer", + "de": "Hersteller" + } +}*/ +THINGSET_ADD_ITEM_STRING(ID_DEVICE, 0x420, "cManufacturer", manufacturer, 0, + THINGSET_ANY_R, 0); + +/*{ + "title": { + "en": "Device Type", + "de": "Gerätetyp" + } +}*/ +THINGSET_ADD_ITEM_STRING(ID_DEVICE, 0x421, "cType", device_type, 0, + THINGSET_ANY_R, 0); + +/*{ + "title": { + "en": "Hardware Version", + "de": "Hardware-Version" + } +}*/ +THINGSET_ADD_ITEM_STRING(ID_DEVICE, 0x422, "cHardwareVersion", hardware_version, 0, + THINGSET_ANY_R, 0); + +/*{ + "title": { + "en": "Firmware Version", + "de": "Firmware-Version" + } +}*/ +THINGSET_ADD_ITEM_STRING(ID_DEVICE, 0x423, "cFirmwareVersion", firmware_version, 0, + THINGSET_ANY_R, 0); + +/*{ + "title": { + "en": "Time since last reset", + "de": "Zeit seit Systemstart" + } +}*/ +THINGSET_ADD_ITEM_UINT32(ID_DEVICE, 0x430, "rUptime_s", ×tamp, + THINGSET_ANY_R, TS_SUBSET_LIVE); + +/*{ + "title": { + "en": "Error Flags", + "de": "Fehlercode" + } +}*/ +THINGSET_ADD_ITEM_UINT32(ID_DEVICE, 0x431, "rErrorFlags", &dev_stat.error_flags, + THINGSET_ANY_R, TS_SUBSET_LIVE); + +/*{ + "title": { + "en": "Internal Temperature", + "de": "Interne Temperatur" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_DEVICE, 0x436, "rIntTemp_degC", &dev_stat.internal_temp, 1, + THINGSET_ANY_R, 0); + +/*{ + "title": { + "en": "Peak Internal Temperature (all-time)", + "de": "Interne Maximaltemperatur (gesamt)" + } +}*/ +THINGSET_ADD_ITEM_INT16(ID_DEVICE, 0x479, "pIntTempMax_degC", &dev_stat.int_temp_max, + THINGSET_ANY_R | THINGSET_MFR_W, TS_SUBSET_NVM); + +/*{ + "title": { + "en": "Day Counter", + "de": "Tagzähler" + } +}*/ +THINGSET_ADD_ITEM_UINT32(ID_DEVICE, 0x471, "pDayCount", &dev_stat.day_counter, + THINGSET_ANY_R | THINGSET_MFR_W, TS_SUBSET_NVM); #if CONFIG_THINGSET_CAN - /*{ - "title": { - "en": "CAN Node Address", - "de": "CAN Node-Adresse" - } - }*/ - TS_ITEM_UINT16(0xBE, "sCANAddress", &can_node_addr, - ID_DEVICE, TS_ANY_R | TS_ANY_W, SUBSET_NVM), +/*{ + "title": { + "en": "CAN Node Address", + "de": "CAN Node-Adresse" + } +}*/ +THINGSET_ADD_ITEM_UINT16(ID_DEVICE, 0x4BE, "sCANAddress", &can_node_addr, + THINGSET_ANY_R | THINGSET_ANY_W, TS_SUBSET_NVM); #endif - /*{ - "title": { - "en": "Reset the Device", - "de": "Gerät zurücksetzen" - } - }*/ - TS_FN_VOID(0xE0, "xReset", &reset_device, ID_DEVICE, TS_ANY_RW), - - /* 0xE2 reserved (previously used for bootloader-stm) */ - - /*{ - "title": { - "en": "Save data to EEPROM", - "de": "Daten ins EEPROM schreiben" - } - }*/ - TS_FN_VOID(0xE1, "xStoreData", &data_storage_write, ID_DEVICE, TS_ANY_RW), - - /*{ - "title": { - "en": "Thingset Authentication", - "de": "Thingset Anmeldung" - } - }*/ - TS_FN_VOID(0xEE, "xAuth", &thingset_auth, ID_DEVICE, TS_ANY_RW), - TS_ITEM_STRING(0xEF, "Password", auth_password, sizeof(auth_password), 0xEE, TS_ANY_RW, 0), - - /////////////////////////////////////////////////////////////////////////////////////////////// - - TS_GROUP(ID_BATTERY, "Battery", TS_NO_CALLBACK, ID_ROOT), - - /*{ - "title": { - "en": "Battery Voltage", - "de": "Batterie-Spannung" - } - }*/ - TS_ITEM_FLOAT(0x31, "rVoltage_V", &bat_bus.voltage, 2, - ID_BATTERY, TS_ANY_R, SUBSET_SER | SUBSET_CAN), - - /*{ - "title": { - "en": "Battery Current", - "de": "Batterie-Strom" - } - }*/ - TS_ITEM_FLOAT(0x32, "rCurrent_A", &bat_terminal.current, 2, - ID_BATTERY, TS_ANY_R, SUBSET_SER | SUBSET_CAN), - - /*{ - "title": { - "en": "Battery Power", - "de": "Batterie-Leistung" - } - }*/ - TS_ITEM_FLOAT(0x33, "rPower_W", &bat_terminal.power, 2, - ID_BATTERY, TS_ANY_R, 0), +/*{ + "title": { + "en": "Reset the Device", + "de": "Gerät zurücksetzen" + } +}*/ +THINGSET_ADD_FN_VOID(ID_DEVICE, 0x4E0, "xReset", &reset_device, THINGSET_ANY_RW); + +/////////////////////////////////////////////////////////////////////////////////////////////// + +THINGSET_ADD_GROUP(TS_ID_ROOT, ID_BATTERY, "Battery", THINGSET_NO_CALLBACK); + +/*{ + "title": { + "en": "Battery Voltage", + "de": "Batterie-Spannung" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_BATTERY, 0x531, "rVoltage_V", &bat_bus.voltage, 2, + THINGSET_ANY_R, TS_SUBSET_LIVE); + +/*{ + "title": { + "en": "Battery Current", + "de": "Batterie-Strom" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_BATTERY, 0x532, "rCurrent_A", &bat_terminal.current, 2, + THINGSET_ANY_R, TS_SUBSET_LIVE); + +/*{ + "title": { + "en": "Battery Power", + "de": "Batterie-Leistung" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_BATTERY, 0x533, "rPower_W", &bat_terminal.power, 2, + THINGSET_ANY_R, TS_SUBSET_LIVE); #if BOARD_HAS_TEMP_BAT - /*{ - "title": { - "en": "Battery Temperature", - "de": "Batterie-Temperatur" - } - }*/ - TS_ITEM_FLOAT(0x34, "rTemperature_degC", &charger.bat_temperature, 1, - ID_BATTERY, TS_ANY_R, 0), - - /*{ - "title": { - "en": "External Temperature Sensor", - "de": "Externer Temperatursensor" - } - }*/ - TS_ITEM_BOOL(0x35, "rExtTempSensor", &charger.ext_temp_sensor, - ID_BATTERY, TS_ANY_R, 0), +/*{ + "title": { + "en": "Battery Temperature", + "de": "Batterie-Temperatur" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_BATTERY, 0x534, "rTemperature_degC", &charger.bat_temperature, 1, + THINGSET_ANY_R, 0); + +/*{ + "title": { + "en": "External Temperature Sensor", + "de": "Externer Temperatursensor" + } +}*/ +THINGSET_ADD_ITEM_BOOL(ID_BATTERY, 0x535, "rExtTempSensor", &charger.ext_temp_sensor, + THINGSET_ANY_R, 0); #endif - /*{ - "title": { - "en": "State of Charge", - "de": "Batterie-Ladezustand" - } - }*/ - TS_ITEM_UINT16(0x40, "rSOC_pct", &charger.soc, // output will be uint8_t - ID_BATTERY, TS_ANY_R, SUBSET_SER | SUBSET_CAN), - - /*{ - "title": { - "en": "Number of Batteries", - "de": "Anzahl Batterien" - } - }*/ - TS_ITEM_INT16(0x53, "rNumBatteries", &lv_bus.series_multiplier, - ID_BATTERY, TS_ANY_R, 0), - - /*{ - "title": { - "en": "Estimated Usable Battery Capacity", - "de": "Geschätzte nutzbare Batterie-Kapazität" - } - }*/ - TS_ITEM_FLOAT(0x64, "pCapacityEstimation_Ah", &charger.usable_capacity, 1, - ID_BATTERY, TS_ANY_R | TS_MKR_W, SUBSET_SER | SUBSET_NVM), - - /*{ - "title": { - "en": "Battery State of Health", - "de": "Batterie-Gesundheitszustand" - } - }*/ - TS_ITEM_UINT16(0x70, "pSOH_pct", &charger.soh, // output will be uint8_t - ID_BATTERY, TS_ANY_R | TS_MKR_W, 0), - - /*{ - "title": { - "en": "Battery Peak Voltage (total)", - "de": "Maximalspannung Batterie (gesamt)" - } - }*/ - TS_ITEM_FLOAT(0x74, "pMaxTotalVoltage_V", &dev_stat.battery_voltage_max, 2, - ID_BATTERY, TS_ANY_R | TS_MKR_W, SUBSET_NVM), - - /*{ - "title": { - "en": "Battery Peak Temperature (all-time)", - "de": "Maximaltemperatur Batterie (gesamt)" - } - }*/ - TS_ITEM_INT16(0x78, "pMaxTotalTemp_degC", &dev_stat.bat_temp_max, - ID_BATTERY, TS_ANY_R | TS_MKR_W, SUBSET_NVM), - - /*{ - "title": { - "en": "Charged Energy (today)", - "de": "Geladene Energie (heute)" - } - }*/ - TS_ITEM_FLOAT(0x69, "pChgEnergyToday_Wh", &bat_terminal.pos_energy_Wh, 2, - ID_BATTERY, TS_ANY_R | TS_MKR_W, SUBSET_SER | SUBSET_CAN), - - /*{ - "title": { - "en": "Charged Energy (total)", - "de": "Energiedurchsatz Ladung (gesamt)" - } - }*/ - TS_ITEM_UINT32(0x60, "pChgEnergyTotal_Wh", &dev_stat.bat_chg_total_Wh, - ID_BATTERY, TS_ANY_R | TS_MKR_W, SUBSET_NVM), - - /*{ - "title": { - "en": "Full Charge Counter", - "de": "Zähler Vollladezyklen" - } - }*/ - TS_ITEM_UINT16(0x62, "pFullChgCount", &charger.num_full_charges, - ID_BATTERY, TS_ANY_R | TS_MKR_W, SUBSET_NVM), - - /*{ - "title": { - "en": "Discharged Energy (today)", - "de": "Entladene Energie (heute)" - } - }*/ - TS_ITEM_FLOAT(0x6A, "pDisEnergyToday_Wh", &bat_terminal.neg_energy_Wh, 2, - ID_BATTERY, TS_ANY_R | TS_MKR_W, SUBSET_SER | SUBSET_CAN), - - /*{ - "title": { - "en": "Discharged Energy (total)", - "de": "Energiedurchsatz Entladung (gesamt)" - } - }*/ - TS_ITEM_UINT32(0x61, "pDisEnergyTotal_Wh", &dev_stat.bat_dis_total_Wh, - ID_BATTERY, TS_ANY_R | TS_MKR_W, SUBSET_NVM), - - /*{ - "title": { - "en": "Deep Discharge Counter", - "de": "Zähler Tiefentladungen" - } - }*/ - TS_ITEM_UINT16(0x63, "pDeepDisCount", &charger.num_deep_discharges, - ID_BATTERY, TS_ANY_R | TS_MKR_W, SUBSET_SER | SUBSET_NVM), - - /*{ - "title": { - "en": "Discharged Battery Capacity", - "de": "Entladene Batterie-Kapazität" - } - }*/ - TS_ITEM_FLOAT(0x6B, "pDisCapacity_Ah", &charger.discharged_Ah, 0, // coulomb counter - ID_BATTERY, TS_ANY_R | TS_MKR_W, SUBSET_SER | SUBSET_CAN), - - /*{ - "title": { - "en": "Nominal Battery Capacity", - "de": "Nominelle Batteriekapazität" - }, - "min": 1, - "max": 1000 - }*/ - TS_ITEM_FLOAT(0xA0, "sNominalCapacity_Ah", &bat_conf_user.nominal_capacity, 1, - ID_BATTERY, TS_ANY_R | TS_ANY_W, SUBSET_NVM), - - /*{ - "title": { - "en": "Battery Internal Resistance", - "de": "Innenwiderstand Batterie" - } - }*/ - TS_ITEM_FLOAT(0xB1, "sIntResistance_Ohm", &bat_conf_user.internal_resistance, 3, - ID_BATTERY, TS_ANY_R | TS_ANY_W, SUBSET_NVM), - - /*{ - "title": { - "en": "Battery Wire Resistance", - "de": "Kabelwiderstand Batterie" - } - }*/ - TS_ITEM_FLOAT(0xB2, "sWireResistance_Ohm", &bat_conf_user.wire_resistance, 3, - ID_BATTERY, TS_ANY_R | TS_ANY_W, SUBSET_NVM), - - /////////////////////////////////////////////////////////////////////////////////////////////// - - TS_GROUP(ID_CHARGER, "Charger", TS_NO_CALLBACK, ID_ROOT), - - /*{ - "title": { - "en": "Charger State", - "de": "Ladegerät-Zustand" - } - }*/ - TS_ITEM_UINT32(0x50, "rState", &charger.state, - ID_CHARGER, TS_ANY_R, SUBSET_SER | SUBSET_CAN), - - /*{ - "title": { - "en": "Control Target Voltage", - "de": "Spannungs-Sollwert" - } - }*/ - TS_ITEM_FLOAT(0x51, "rControlTargetVoltage_V", &bat_bus.sink_voltage_intercept, 2, - ID_CHARGER, TS_ANY_R, 0), - - /*{ - "title": { - "en": "Control Target Current", - "de": "Strom-Sollwert" - } - }*/ - TS_ITEM_FLOAT(0x52, "rControlTargetCurrent_A", &bat_terminal.pos_current_limit, 2, - ID_CHARGER, TS_ANY_R, 0), +/*{ + "title": { + "en": "State of Charge", + "de": "Batterie-Ladezustand" + } +}*/ +THINGSET_ADD_ITEM_UINT16(ID_BATTERY, 0x540, "rSOC_pct", &charger.soc, // output will be uint8_t + THINGSET_ANY_R, TS_SUBSET_LIVE); + +/*{ + "title": { + "en": "Number of Batteries", + "de": "Anzahl Batterien" + } +}*/ +THINGSET_ADD_ITEM_INT16(ID_BATTERY, 0x553, "rNumBatteries", &lv_bus.series_multiplier, + THINGSET_ANY_R, 0); + +/*{ + "title": { + "en": "Estimated Usable Battery Capacity", + "de": "Geschätzte nutzbare Batterie-Kapazität" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_BATTERY, 0x564, "pCapacityEstimation_Ah", &charger.usable_capacity, 1, + THINGSET_ANY_R | THINGSET_MFR_W, TS_SUBSET_LIVE | TS_SUBSET_NVM); + +/*{ + "title": { + "en": "Battery State of Health", + "de": "Batterie-Gesundheitszustand" + } +}*/ +THINGSET_ADD_ITEM_UINT16(ID_BATTERY, 0x570, "pSOH_pct", &charger.soh, // output will be uint8_t + THINGSET_ANY_R | THINGSET_MFR_W, 0); + +/*{ + "title": { + "en": "Battery Peak Voltage (total)", + "de": "Maximalspannung Batterie (gesamt)" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_BATTERY, 0x574, "pMaxTotalVoltage_V", &dev_stat.battery_voltage_max, 2, + THINGSET_ANY_R | THINGSET_MFR_W, TS_SUBSET_NVM); + +/*{ + "title": { + "en": "Battery Peak Temperature (all-time)", + "de": "Maximaltemperatur Batterie (gesamt)" + } +}*/ +THINGSET_ADD_ITEM_INT16(ID_BATTERY, 0x578, "pMaxTotalTemp_degC", &dev_stat.bat_temp_max, + THINGSET_ANY_R | THINGSET_MFR_W, TS_SUBSET_NVM); + +/*{ + "title": { + "en": "Charged Energy (today)", + "de": "Geladene Energie (heute)" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_BATTERY, 0x569, "pChgEnergyToday_Wh", &bat_terminal.pos_energy_Wh, 2, + THINGSET_ANY_R | THINGSET_MFR_W, TS_SUBSET_LIVE); + +/*{ + "title": { + "en": "Charged Energy (total)", + "de": "Energiedurchsatz Ladung (gesamt)" + } +}*/ +THINGSET_ADD_ITEM_UINT32(ID_BATTERY, 0x560, "pChgEnergyTotal_Wh", &dev_stat.bat_chg_total_Wh, + THINGSET_ANY_R | THINGSET_MFR_W, TS_SUBSET_NVM); + +/*{ + "title": { + "en": "Full Charge Counter", + "de": "Zähler Vollladezyklen" + } +}*/ +THINGSET_ADD_ITEM_UINT16(ID_BATTERY, 0x562, "pFullChgCount", &charger.num_full_charges, + THINGSET_ANY_R | THINGSET_MFR_W, TS_SUBSET_NVM); + +/*{ + "title": { + "en": "Discharged Energy (today)", + "de": "Entladene Energie (heute)" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_BATTERY, 0x56A, "pDisEnergyToday_Wh", &bat_terminal.neg_energy_Wh, 2, + THINGSET_ANY_R | THINGSET_MFR_W, TS_SUBSET_LIVE); + +/*{ + "title": { + "en": "Discharged Energy (total)", + "de": "Energiedurchsatz Entladung (gesamt)" + } +}*/ +THINGSET_ADD_ITEM_UINT32(ID_BATTERY, 0x561, "pDisEnergyTotal_Wh", &dev_stat.bat_dis_total_Wh, + THINGSET_ANY_R | THINGSET_MFR_W, TS_SUBSET_NVM); + +/*{ + "title": { + "en": "Deep Discharge Counter", + "de": "Zähler Tiefentladungen" + } +}*/ +THINGSET_ADD_ITEM_UINT16(ID_BATTERY, 0x563, "pDeepDisCount", &charger.num_deep_discharges, + THINGSET_ANY_R | THINGSET_MFR_W, TS_SUBSET_LIVE | TS_SUBSET_NVM); + +/*{ + "title": { + "en": "Discharged Battery Capacity", + "de": "Entladene Batterie-Kapazität" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_BATTERY, 0x56B, "pDisCapacity_Ah", &charger.discharged_Ah, 0, // coulomb counter + THINGSET_ANY_R | THINGSET_MFR_W, TS_SUBSET_LIVE); + +/*{ + "title": { + "en": "Nominal Battery Capacity", + "de": "Nominelle Batteriekapazität" + }, + "min": 1, + "max": 1000 +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_BATTERY, 0x5A0, "sNominalCapacity_Ah", &bat_conf_user.nominal_capacity, 1, + THINGSET_ANY_R | THINGSET_ANY_W, TS_SUBSET_NVM); + +/*{ + "title": { + "en": "Battery Internal Resistance", + "de": "Innenwiderstand Batterie" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_BATTERY, 0x5B1, "sIntResistance_Ohm", &bat_conf_user.internal_resistance, 3, + THINGSET_ANY_R | THINGSET_ANY_W, TS_SUBSET_NVM); + +/*{ + "title": { + "en": "Battery Wire Resistance", + "de": "Kabelwiderstand Batterie" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_BATTERY, 0x5B2, "sWireResistance_Ohm", &bat_conf_user.wire_resistance, 3, + THINGSET_ANY_R | THINGSET_ANY_W, TS_SUBSET_NVM); + +/////////////////////////////////////////////////////////////////////////////////////////////// + +THINGSET_ADD_GROUP(TS_ID_ROOT, ID_CHARGER, "Charger", THINGSET_NO_CALLBACK); + +/*{ + "title": { + "en": "Charger State", + "de": "Ladegerät-Zustand" + } +}*/ +THINGSET_ADD_ITEM_UINT32(ID_CHARGER, 0x650, "rState", &charger.state, + THINGSET_ANY_R, TS_SUBSET_LIVE); + +/*{ + "title": { + "en": "Control Target Voltage", + "de": "Spannungs-Sollwert" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_CHARGER, 0x651, "rControlTargetVoltage_V", &bat_bus.sink_voltage_intercept, 2, + THINGSET_ANY_R, 0); + +/*{ + "title": { + "en": "Control Target Current", + "de": "Strom-Sollwert" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_CHARGER, 0x652, "rControlTargetCurrent_A", &bat_terminal.pos_current_limit, 2, + THINGSET_ANY_R, 0); #if BOARD_HAS_DCDC - /*{ - "title": { - "en": "DC/DC State", - "de": "DC/DC-Zustand" - } - }*/ - TS_ITEM_UINT16(0x54, "rDCDCState", &dcdc.state, - ID_CHARGER, TS_ANY_R, SUBSET_SER | SUBSET_CAN), - - /*{ - "title": { - "en": "Enable DC/DC", - "de": "DC/DC einschalten" - } - }*/ - TS_ITEM_BOOL(0x82, "wDCDCEnable", &dcdc.enable, - ID_CHARGER, TS_ANY_R | TS_ANY_W, 0), - - /*{ - "title": { - "en": "DC/DC Peak Current (all-time)", - "de": "Maximalstrom DC/DC (gesamt)" - } - }*/ - TS_ITEM_FLOAT(0x76, "pDCDCMaxTotalCurrent_A", &dev_stat.dcdc_current_max, 2, - ID_CHARGER, TS_ANY_R | TS_MKR_W, SUBSET_NVM), +/*{ + "title": { + "en": "DC/DC State", + "de": "DC/DC-Zustand" + } +}*/ +THINGSET_ADD_ITEM_UINT16(ID_CHARGER, 0x654, "rDCDCState", &dcdc.state, + THINGSET_ANY_R, TS_SUBSET_LIVE); + +/*{ + "title": { + "en": "Enable DC/DC", + "de": "DC/DC einschalten" + } +}*/ +THINGSET_ADD_ITEM_BOOL(ID_CHARGER, 0x682, "wDCDCEnable", &dcdc.enable, + THINGSET_ANY_R | THINGSET_ANY_W, 0); + +/*{ + "title": { + "en": "DC/DC Peak Current (all-time)", + "de": "Maximalstrom DC/DC (gesamt)" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_CHARGER, 0x676, "pDCDCMaxTotalCurrent_A", &dev_stat.dcdc_current_max, 2, + THINGSET_ANY_R | THINGSET_MFR_W, TS_SUBSET_NVM); #endif #if BOARD_HAS_PWM_PORT - /*{ - "title": { - "en": "Enable PWM Solar Input", - "de": "PWM Solar-Eingang einschalten" - } - }*/ - TS_ITEM_BOOL(0x83, "wPWMEnable", &pwm_switch.enable, - ID_CHARGER, TS_ANY_R | TS_ANY_W, 0), +/*{ + "title": { + "en": "Enable PWM Solar Input", + "de": "PWM Solar-Eingang einschalten" + } +}*/ +THINGSET_ADD_ITEM_BOOL(ID_CHARGER, 0x683, "wPWMEnable", &pwm_switch.enable, + THINGSET_ANY_R | THINGSET_ANY_W, 0); #endif #if BOARD_HAS_TEMP_FETS - /*{ - "title": { - "en": "MOSFET Temperature", - "de": "MOSFET-Temperatur" - } - }*/ - TS_ITEM_FLOAT(0x37, "rMosfetTemp_degC", &dcdc.temp_mosfets, 1, - ID_CHARGER, TS_ANY_R, 0), - - /*{ - "title": { - "en": "Peak MOSFET Temperature (all-time)", - "de": "MOSFET Maximaltemperatur (gesamt)" - } - }*/ - TS_ITEM_INT16(0x7A, "pMosfetTempMax_degC", &dev_stat.mosfet_temp_max, - ID_CHARGER, TS_ANY_R | TS_MKR_W, SUBSET_NVM), +/*{ + "title": { + "en": "MOSFET Temperature", + "de": "MOSFET-Temperatur" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_CHARGER, 0x637, "rMosfetTemp_degC", &dcdc.temp_mosfets, 1, + THINGSET_ANY_R, 0); + +/*{ + "title": { + "en": "Peak MOSFET Temperature (all-time)", + "de": "MOSFET Maximaltemperatur (gesamt)" + } +}*/ +THINGSET_ADD_ITEM_INT16(ID_CHARGER, 0x67A, "pMosfetTempMax_degC", &dev_stat.mosfet_temp_max, + THINGSET_ANY_R | THINGSET_MFR_W, TS_SUBSET_NVM); #endif - /*{ - "title": { - "en": "Battery Maximum Charge Current (bulk)", - "de": "Maximaler Batterie-Ladestrom (bulk)" - }, - "min": 10.0, - "max": 30.0 - }*/ - TS_ITEM_FLOAT(0xA1, "sChgCurrentLimit_A", &bat_conf_user.charge_current_max, 1, - ID_CHARGER, TS_ANY_R | TS_ANY_W, SUBSET_NVM), - - /*{ - "title": { - "en": "Battery Charge Voltage (topping)", - "de": "Batterie-Ladespannung (topping)" - }, - "min": 10.0, - "max": 30.0 - }*/ - TS_ITEM_FLOAT(0xA2, "sChgVoltage_V", &bat_conf_user.topping_voltage, 2, - ID_CHARGER, TS_ANY_R | TS_ANY_W, SUBSET_NVM), - - /*{ - "title": { - "en": "Topping Cut-off Current", - "de": "Abschaltstrom Vollladung" - }, - "min": 0.0, - "max": 20.0 - }*/ - TS_ITEM_FLOAT(0xA3, "sChgCutoffCurrent_A", &bat_conf_user.topping_cutoff_current, 1, - ID_CHARGER, TS_ANY_R | TS_ANY_W, SUBSET_NVM), - - /*{ - "title": { - "en": "Topping Time Limit", - "de": "Zeitbregrenzung Vollladung" - } - }*/ - TS_ITEM_UINT32(0xA4, "sChgCutoffTime_s", &bat_conf_user.topping_duration, - ID_CHARGER, TS_ANY_R | TS_ANY_W, SUBSET_NVM), - - /*{ - "title": { - "en": "Enable Float Charging", - "de": "Erhaltungsladung einschalten" - } - }*/ - TS_ITEM_BOOL(0xA5, "sFloatChgEnable", &bat_conf_user.float_enabled, - ID_CHARGER, TS_ANY_R | TS_ANY_W, SUBSET_NVM), - - /*{ - "title": { - "en": "Float Voltage", - "de": "Spannung Erhaltungsladung" - } - }*/ - TS_ITEM_FLOAT(0xA6, "sFloatChgVoltage_V", &bat_conf_user.float_voltage, 2, - ID_CHARGER, TS_ANY_R | TS_ANY_W, SUBSET_NVM), - - /*{ - "title": { - "en": "Float Recharge Time", - "de": "Wiedereinschaltdauer Erhaltungsladung" - } - }*/ - TS_ITEM_UINT32(0xA7, "sFloatRechgTime_s", &bat_conf_user.float_recharge_time, - ID_CHARGER, TS_ANY_R | TS_ANY_W, SUBSET_NVM), - - /*{ - "title": { - "en": "Enable Equalization Charging", - "de": "Ausgleichsladung einschalten" - } - }*/ - TS_ITEM_BOOL(0xA8, "sEqlChgEnable", &bat_conf_user.equalization_enabled, - ID_CHARGER, TS_ANY_R | TS_ANY_W, SUBSET_NVM), - - /*{ - "title": { - "en": "Equalization Voltage", - "de": "Spannung Ausgleichsladung" - } - }*/ - TS_ITEM_FLOAT(0xA9, "sEqlChgVoltage_V", &bat_conf_user.equalization_voltage, 2, - ID_CHARGER, TS_ANY_R | TS_ANY_W, SUBSET_NVM), - - /*{ - "title": { - "en": "Equalization Current Limit", - "de": "Maximalstrom Ausgleichsladung" - } - }*/ - TS_ITEM_FLOAT(0xAA, "sEqlChgCurrent_A", &bat_conf_user.equalization_current_limit, 2, - ID_CHARGER, TS_ANY_R | TS_ANY_W, SUBSET_NVM), - - /*{ - "title": { - "en": "Equalization Duration", - "de": "Zeitbegrenzung Ausgleichsladung" - } - }*/ - TS_ITEM_UINT32(0xAB, "sEqlDuration_s", &bat_conf_user.equalization_duration, - ID_CHARGER, TS_ANY_R | TS_ANY_W, SUBSET_NVM), - - /*{ - "title": { - "en": "Maximum Equalization Interval", - "de": "Max. Intervall zwischen Ausgleichsladungen" - } - }*/ - TS_ITEM_UINT32(0xAC, "sEqlMaxInterval_d", &bat_conf_user.equalization_trigger_days, - ID_CHARGER, TS_ANY_R | TS_ANY_W, SUBSET_NVM), - - /*{ - "title": { - "en": "Maximum Deep Discharges for Equalization", - "de": "Max. Tiefenentladungszyklen zwischen Ausgleichsladungen" - } - }*/ - TS_ITEM_UINT32(0xAD, "sEqlDeepDisTrigger", &bat_conf_user.equalization_trigger_deep_cycles, - ID_CHARGER, TS_ANY_R | TS_ANY_W, SUBSET_NVM), - - /*{ - "title": { - "en": "Battery Recharge Voltage", - "de": "Batterie-Nachladespannung" - }, - "min": 10.0, - "max": 30.0 - }*/ - TS_ITEM_FLOAT(0xAE, "sRechgVoltage_V", &bat_conf_user.recharge_voltage, 2, - ID_CHARGER, TS_ANY_R | TS_ANY_W, SUBSET_NVM), - - /*{ - "title": { - "en": "Battery Minimum Voltage", - "de": "Batterie-Minimalspannung" - }, - "min": 8.0, - "max": 30.0 - }*/ - TS_ITEM_FLOAT(0xAF, "sAbsMinVoltage_V", &bat_conf_user.absolute_min_voltage, 2, - ID_CHARGER, TS_ANY_R | TS_ANY_W, SUBSET_NVM), - - /*{ - "title": { - "en": "Temperature Compensation", - "de": "Temperaturausgleich" - } - }*/ - TS_ITEM_FLOAT(0xB0, "sTempCompensation_mV_K", &bat_conf_user.temperature_compensation, 3, - ID_CHARGER, TS_ANY_R | TS_ANY_W, SUBSET_NVM), - - /*{ - "title": { - "en": "Maximum Charge Temperature", - "de": "Maximale Ladetemperatur" - } - }*/ - TS_ITEM_FLOAT(0xB3, "sChgMaxTemp_degC", &bat_conf_user.charge_temp_max, 1, - ID_CHARGER, TS_ANY_R | TS_ANY_W, SUBSET_NVM), - - /*{ - "title": { - "en": "Minimum Charge Temperature", - "de": "Minimale Ladetemperatur" - } - }*/ - TS_ITEM_FLOAT(0xB4, "sChgMinTemp_degC", &bat_conf_user.charge_temp_min, 1, - ID_CHARGER, TS_ANY_R | TS_ANY_W, SUBSET_NVM), +/*{ + "title": { + "en": "Battery Maximum Charge Current (bulk)", + "de": "Maximaler Batterie-Ladestrom (bulk)" + }, + "min": 10.0, + "max": 30.0 +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_CHARGER, 0x6A1, "sChgCurrentLimit_A", &bat_conf_user.charge_current_max, 1, + THINGSET_ANY_R | THINGSET_ANY_W, TS_SUBSET_NVM); + +/*{ + "title": { + "en": "Battery Charge Voltage (topping)", + "de": "Batterie-Ladespannung (topping)" + }, + "min": 10.0, + "max": 30.0 +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_CHARGER, 0x6A2, "sChgVoltage_V", &bat_conf_user.topping_voltage, 2, + THINGSET_ANY_R | THINGSET_ANY_W, TS_SUBSET_NVM); + +/*{ + "title": { + "en": "Topping Cut-off Current", + "de": "Abschaltstrom Vollladung" + }, + "min": 0.0, + "max": 20.0 +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_CHARGER, 0x6A3, "sChgCutoffCurrent_A", &bat_conf_user.topping_cutoff_current, 1, + THINGSET_ANY_R | THINGSET_ANY_W, TS_SUBSET_NVM); + +/*{ + "title": { + "en": "Topping Time Limit", + "de": "Zeitbregrenzung Vollladung" + } +}*/ +THINGSET_ADD_ITEM_UINT32(ID_CHARGER, 0x6A4, "sChgCutoffTime_s", &bat_conf_user.topping_duration, + THINGSET_ANY_R | THINGSET_ANY_W, TS_SUBSET_NVM); + +/*{ + "title": { + "en": "Enable Float Charging", + "de": "Erhaltungsladung einschalten" + } +}*/ +THINGSET_ADD_ITEM_BOOL(ID_CHARGER, 0x6A5, "sFloatChgEnable", &bat_conf_user.float_enabled, + THINGSET_ANY_R | THINGSET_ANY_W, TS_SUBSET_NVM); + +/*{ + "title": { + "en": "Float Voltage", + "de": "Spannung Erhaltungsladung" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_CHARGER, 0x6A6, "sFloatChgVoltage_V", &bat_conf_user.float_voltage, 2, + THINGSET_ANY_R | THINGSET_ANY_W, TS_SUBSET_NVM); + +/*{ + "title": { + "en": "Float Recharge Time", + "de": "Wiedereinschaltdauer Erhaltungsladung" + } +}*/ +THINGSET_ADD_ITEM_UINT32(ID_CHARGER, 0x6A7, "sFloatRechgTime_s", &bat_conf_user.float_recharge_time, + THINGSET_ANY_R | THINGSET_ANY_W, TS_SUBSET_NVM); + +/*{ + "title": { + "en": "Enable Equalization Charging", + "de": "Ausgleichsladung einschalten" + } +}*/ +THINGSET_ADD_ITEM_BOOL(ID_CHARGER, 0x6A8, "sEqlChgEnable", &bat_conf_user.equalization_enabled, + THINGSET_ANY_R | THINGSET_ANY_W, TS_SUBSET_NVM); + +/*{ + "title": { + "en": "Equalization Voltage", + "de": "Spannung Ausgleichsladung" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_CHARGER, 0x6A9, "sEqlChgVoltage_V", &bat_conf_user.equalization_voltage, 2, + THINGSET_ANY_R | THINGSET_ANY_W, TS_SUBSET_NVM); + +/*{ + "title": { + "en": "Equalization Current Limit", + "de": "Maximalstrom Ausgleichsladung" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_CHARGER, 0x6AA, "sEqlChgCurrent_A", &bat_conf_user.equalization_current_limit, 2, + THINGSET_ANY_R | THINGSET_ANY_W, TS_SUBSET_NVM); + +/*{ + "title": { + "en": "Equalization Duration", + "de": "Zeitbegrenzung Ausgleichsladung" + } +}*/ +THINGSET_ADD_ITEM_UINT32(ID_CHARGER, 0x6AB, "sEqlDuration_s", &bat_conf_user.equalization_duration, + THINGSET_ANY_R | THINGSET_ANY_W, TS_SUBSET_NVM); + +/*{ + "title": { + "en": "Maximum Equalization Interval", + "de": "Max. Intervall zwischen Ausgleichsladungen" + } +}*/ +THINGSET_ADD_ITEM_UINT32(ID_CHARGER, 0x6AC, "sEqlMaxInterval_d", &bat_conf_user.equalization_trigger_days, + THINGSET_ANY_R | THINGSET_ANY_W, TS_SUBSET_NVM); + +/*{ + "title": { + "en": "Maximum Deep Discharges for Equalization", + "de": "Max. Tiefenentladungszyklen zwischen Ausgleichsladungen" + } +}*/ +THINGSET_ADD_ITEM_UINT32(ID_CHARGER, 0x6AD, "sEqlDeepDisTrigger", &bat_conf_user.equalization_trigger_deep_cycles, + THINGSET_ANY_R | THINGSET_ANY_W, TS_SUBSET_NVM); + +/*{ + "title": { + "en": "Battery Recharge Voltage", + "de": "Batterie-Nachladespannung" + }, + "min": 10.0, + "max": 30.0 +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_CHARGER, 0x6AE, "sRechgVoltage_V", &bat_conf_user.recharge_voltage, 2, + THINGSET_ANY_R | THINGSET_ANY_W, TS_SUBSET_NVM); + +/*{ + "title": { + "en": "Battery Minimum Voltage", + "de": "Batterie-Minimalspannung" + }, + "min": 8.0, + "max": 30.0 +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_CHARGER, 0x6AF, "sAbsMinVoltage_V", &bat_conf_user.absolute_min_voltage, 2, + THINGSET_ANY_R | THINGSET_ANY_W, TS_SUBSET_NVM); + +/*{ + "title": { + "en": "Temperature Compensation", + "de": "Temperaturausgleich" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_CHARGER, 0x6B0, "sTempCompensation_mV_K", &bat_conf_user.temperature_compensation, 3, + THINGSET_ANY_R | THINGSET_ANY_W, TS_SUBSET_NVM); + +/*{ + "title": { + "en": "Maximum Charge Temperature", + "de": "Maximale Ladetemperatur" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_CHARGER, 0x6B3, "sChgMaxTemp_degC", &bat_conf_user.charge_temp_max, 1, + THINGSET_ANY_R | THINGSET_ANY_W, TS_SUBSET_NVM); + +/*{ + "title": { + "en": "Minimum Charge Temperature", + "de": "Minimale Ladetemperatur" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_CHARGER, 0x6B4, "sChgMinTemp_degC", &bat_conf_user.charge_temp_min, 1, + THINGSET_ANY_R | THINGSET_ANY_W, TS_SUBSET_NVM); #if BOARD_HAS_DCDC - /*{ - "title": { - "en": "DC/DC minimum output power w/o shutdown", - "de": "DC/DC Mindest-Leistung vor Abschaltung" - } - }*/ - TS_ITEM_FLOAT(0xD0, "sDCDCMinPower_W", &dcdc.output_power_min, 1, - ID_CHARGER, TS_MKR_RW, SUBSET_NVM), - - /*{ - "title": { - "en": "DC/DC Restart Interval", - "de": "DC/DC Restart Intervall" - } - }*/ - TS_ITEM_UINT32(0xD2, "sDCDCRestartInterval_s", &dcdc.restart_interval, - ID_CHARGER, TS_MKR_RW, SUBSET_NVM), +/*{ + "title": { + "en": "DC/DC minimum output power w/o shutdown", + "de": "DC/DC Mindest-Leistung vor Abschaltung" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_CHARGER, 0x6D0, "sDCDCMinPower_W", &dcdc.output_power_min, 1, + THINGSET_MFR_RW, TS_SUBSET_NVM); + +/*{ + "title": { + "en": "DC/DC Restart Interval", + "de": "DC/DC Restart Intervall" + } +}*/ +THINGSET_ADD_ITEM_UINT32(ID_CHARGER, 0x6D2, "sDCDCRestartInterval_s", &dcdc.restart_interval, + THINGSET_MFR_RW, TS_SUBSET_NVM); #endif - /////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// #if CONFIG_HV_TERMINAL_SOLAR || CONFIG_LV_TERMINAL_SOLAR || CONFIG_PWM_TERMINAL_SOLAR - TS_GROUP(ID_SOLAR, "Solar", TS_NO_CALLBACK, ID_ROOT), +THINGSET_ADD_GROUP(TS_ID_ROOT, ID_SOLAR, "Solar", THINGSET_NO_CALLBACK); #if CONFIG_PWM_TERMINAL_SOLAR - /*{ - "title": { - "en": "Solar Voltage", - "de": "Solar-Spannung" - } - }*/ - TS_ITEM_FLOAT(0x38, "rVoltage_V", &pwm_switch.ext_voltage, 2, - ID_SOLAR, TS_ANY_R, SUBSET_SER | SUBSET_CAN), +/*{ + "title": { + "en": "Solar Voltage", + "de": "Solar-Spannung" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_SOLAR, 0x738, "rVoltage_V", &pwm_switch.ext_voltage, 2, + THINGSET_ANY_R, TS_SUBSET_LIVE); #else - TS_ITEM_FLOAT(0x38, "rVoltage_V", &solar_bus.voltage, 2, - ID_SOLAR, TS_ANY_R, SUBSET_SER | SUBSET_CAN), +THINGSET_ADD_ITEM_FLOAT(ID_SOLAR, 0x738, "rVoltage_V", &solar_bus.voltage, 2, + THINGSET_ANY_R, TS_SUBSET_LIVE); #endif - /*{ - "title": { - "en": "Solar Current", - "de": "Solar-Strom" - } - }*/ - TS_ITEM_FLOAT(0x39, "rCurrent_A", &solar_terminal.current, 2, - ID_SOLAR, TS_ANY_R, SUBSET_SER | SUBSET_CAN), - - /*{ - "title": { - "en": "Solar Power", - "de": "Solar-Leistung" - } - }*/ - TS_ITEM_FLOAT(0x3A, "rPower_W", &solar_terminal.power, 2, - ID_SOLAR, TS_ANY_R, 0), - - /*{ - "title": { - "en": "Solar Energy (today)", - "de": "Solar-Ertrag (heute)" - } - }*/ - TS_ITEM_FLOAT(0x6C, "pInputToday_Wh", &solar_terminal.neg_energy_Wh, 2, - ID_SOLAR, TS_ANY_R | TS_MKR_W, SUBSET_SER | SUBSET_CAN), - - /*{ - "title": { - "en": "Solar Energy (total)", - "de": "Solar-Energie (gesamt)" - } - }*/ - TS_ITEM_UINT32(0x65, "pInputTotal_Wh", &dev_stat.solar_in_total_Wh, - ID_SOLAR, TS_ANY_R | TS_MKR_W, SUBSET_NVM), - - /*{ - "title": { - "en": "Peak Solar Power (today)", - "de": "Maximale Solarleistung (heute)" - } - }*/ - TS_ITEM_UINT16(0x6E, "pPowerMaxToday_W", &dev_stat.solar_power_max_day, - ID_SOLAR, TS_ANY_R | TS_MKR_W, 0), - - /*{ - "title": { - "en": "Solar Peak Power (total)", - "de": "Maximalleistung Solar (gesamt)" - } - }*/ - TS_ITEM_UINT16(0x72, "pPowerMaxTotal_W", &dev_stat.solar_power_max_total, - ID_SOLAR, TS_ANY_R | TS_MKR_W, SUBSET_NVM), - - /*{ - "title": { - "en": "Solar Peak Voltage (all-time)", - "de": "Maximalspannung Solar (gesamt)" - } - }*/ - TS_ITEM_FLOAT(0x75, "pVoltageMaxTotal_V", &dev_stat.solar_voltage_max, 2, - ID_SOLAR, TS_ANY_R | TS_MKR_W, SUBSET_NVM), +/*{ + "title": { + "en": "Solar Current", + "de": "Solar-Strom" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_SOLAR, 0x739, "rCurrent_A", &solar_terminal.current, 2, + THINGSET_ANY_R, TS_SUBSET_LIVE); + +/*{ + "title": { + "en": "Solar Power", + "de": "Solar-Leistung" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_SOLAR, 0x73A, "rPower_W", &solar_terminal.power, 2, + THINGSET_ANY_R, TS_SUBSET_LIVE); + +/*{ + "title": { + "en": "Solar Energy (today)", + "de": "Solar-Ertrag (heute)" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_SOLAR, 0x76C, "pInputToday_Wh", &solar_terminal.neg_energy_Wh, 2, + THINGSET_ANY_R | THINGSET_MFR_W, TS_SUBSET_LIVE); + +/*{ + "title": { + "en": "Solar Energy (total)", + "de": "Solar-Energie (gesamt)" + } +}*/ +THINGSET_ADD_ITEM_UINT32(ID_SOLAR, 0x765, "pInputTotal_Wh", &dev_stat.solar_in_total_Wh, + THINGSET_ANY_R | THINGSET_MFR_W, TS_SUBSET_NVM); + +/*{ + "title": { + "en": "Peak Solar Power (today)", + "de": "Maximale Solarleistung (heute)" + } +}*/ +THINGSET_ADD_ITEM_UINT16(ID_SOLAR, 0x76E, "pPowerMaxToday_W", &dev_stat.solar_power_max_day, + THINGSET_ANY_R | THINGSET_MFR_W, 0); + +/*{ + "title": { + "en": "Solar Peak Power (total)", + "de": "Maximalleistung Solar (gesamt)" + } +}*/ +THINGSET_ADD_ITEM_UINT16(ID_SOLAR, 0x772, "pPowerMaxTotal_W", &dev_stat.solar_power_max_total, + THINGSET_ANY_R | THINGSET_MFR_W, TS_SUBSET_NVM); + +/*{ + "title": { + "en": "Solar Peak Voltage (all-time)", + "de": "Maximalspannung Solar (gesamt)" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_SOLAR, 0x775, "pVoltageMaxTotal_V", &dev_stat.solar_voltage_max, 2, + THINGSET_ANY_R | THINGSET_MFR_W, TS_SUBSET_NVM); #if BOARD_HAS_DCDC - /*{ - "title": { - "en": "Absolute Maximum Solar Voltage", - "de": "Maximal erlaubte Solar-Spannung" - } - }*/ - TS_ITEM_FLOAT(0xD1, "pSolarVoltageLimit_V", &dcdc.hs_voltage_max, 1, - ID_SOLAR, TS_MKR_RW, SUBSET_NVM), +/*{ + "title": { + "en": "Absolute Maximum Solar Voltage", + "de": "Maximal erlaubte Solar-Spannung" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_SOLAR, 0x7D1, "pSolarVoltageLimit_V", &dcdc.hs_voltage_max, 1, + THINGSET_MFR_RW, TS_SUBSET_NVM); #endif /* BOARD_HAS_DCDC */ #endif /* SOLAR */ - /////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// #if BOARD_HAS_LOAD_OUTPUT - TS_GROUP(ID_LOAD, "Load", TS_NO_CALLBACK, ID_ROOT), - - /*{ - "title": { - "en": "Load Outupt Current", - "de": "Lastausgangs-Strom" - } - }*/ - TS_ITEM_FLOAT(0x3B, "rCurrent_A", &load.current, 2, - ID_LOAD, TS_ANY_R, SUBSET_SER | SUBSET_CAN), - - /*{ - "title": { - "en": "Load Output Power", - "de": "Lastausgangs-Leistung" - } - }*/ - TS_ITEM_FLOAT(0x3C, "rPower_W", &load.power, 2, - ID_LOAD, TS_ANY_R, 0), - - /*{ - "title": { - "en": "Load State", - "de": "Last-Zustand" - } - }*/ - TS_ITEM_INT32(0x55, "rState", &load.info, - ID_LOAD, TS_ANY_R, SUBSET_SER | SUBSET_CAN), - - /*{ - "title": { - "en": "Load Output Energy (today)", - "de": "Energie Last-Ausgang (heute)" - } - }*/ - TS_ITEM_FLOAT(0x6D, "pOutputToday_Wh", &load.pos_energy_Wh, 2, - ID_LOAD, TS_ANY_R | TS_MKR_W, SUBSET_SER | SUBSET_CAN), - - /*{ - "title": { - "en": "Load Output Energy (total)", - "de": "Energiedurchsatz Lastausgang (gesamt)" - } - }*/ - TS_ITEM_UINT32(0x66, "pOutputTotal_Wh", &dev_stat.load_out_total_Wh, - ID_LOAD, TS_ANY_R | TS_MKR_W, SUBSET_NVM), - - /*{ - "title": { - "en": "Peak Load Power (today)", - "de": "Maximale Lastleistung (heute)" - } - }*/ - TS_ITEM_UINT16(0x6F, "pPowerMaxToday_W", &dev_stat.load_power_max_day, - ID_LOAD, TS_ANY_R | TS_MKR_W, 0), - - /*{ - "title": { - "en": "Load Peak Power (total)", - "de": "Maximalleistung Last-Ausgang (gesamt)" - } - }*/ - TS_ITEM_UINT16(0x73, "pPowerMaxTotal_W", &dev_stat.load_power_max_total, - ID_LOAD, TS_ANY_R | TS_MKR_W, SUBSET_NVM), - - /*{ - "title": { - "en": "Load Peak Current (all-time)", - "de": "Maximalstrom Lastausgang (gesamt)" - } - }*/ - TS_ITEM_FLOAT(0x77, "pCurrentMaxTotal_A", &dev_stat.load_current_max, 2, - ID_LOAD, TS_ANY_R | TS_MKR_W, SUBSET_NVM), - - /*{ - "title": { - "en": "Enable Load", - "de": "Last einschalten" - } - }*/ - TS_ITEM_BOOL(0x80, "wEnable", &load.enable, - ID_LOAD, TS_ANY_R | TS_ANY_W, 0), - - /*{ - "title": { - "en": "Automatic Load Output Enable", - "de": "Last-Ausgang automatisch einschalten" - } - }*/ - TS_ITEM_BOOL(0xB7, "sEnableDefault", &load.enable, - ID_LOAD, TS_ANY_R | TS_ANY_W, SUBSET_NVM), - - /*{ - "title": { - "en": "Load Disconnect Voltage ", - "de": "Abschaltspannung Lastausgang" - } - }*/ - TS_ITEM_FLOAT(0xB8, "sDisconnectVoltage_V", &bat_conf_user.load_disconnect_voltage, 2, - ID_LOAD, TS_ANY_R | TS_ANY_W, SUBSET_NVM), - - /*{ - "title": { - "en": "Load Reconnect Voltage", - "de": "Wiedereinschalt-Spannung Lastausgang" - } - }*/ - TS_ITEM_FLOAT(0xB9, "sReconnectVoltage_V", &bat_conf_user.load_reconnect_voltage, 2, - ID_LOAD, TS_ANY_R | TS_ANY_W, SUBSET_NVM), - - /*{ - "title": { - "en": "Overcurrent Recovery Delay", - "de": "Wiedereinschalt-Verzögerung nach Überstrom" - } - }*/ - TS_ITEM_UINT32(0xBA, "sOvercurrentRecoveryDelay_s", &load.oc_recovery_delay, - ID_LOAD, TS_ANY_R | TS_ANY_W, SUBSET_NVM), - - /*{ - "title": { - "en": "Low Voltage Disconnect Recovery Delay", - "de": "Wiedereinschalt-Verzögerung nach Unterspannung" - } - }*/ - TS_ITEM_UINT32(0xBB, "sUndervoltageRecoveryDelay_s", &load.lvd_recovery_delay, - ID_LOAD, TS_ANY_R | TS_ANY_W, SUBSET_NVM), - - /*{ - "title": { - "en": "Maximum Discharge Temperature", - "de": "Maximale Entladetemperatur" - } - }*/ - TS_ITEM_FLOAT(0xB5, "sDisMaxTemperature_degC", &bat_conf_user.discharge_temp_max, 1, - ID_LOAD, TS_ANY_R | TS_ANY_W, SUBSET_NVM), - - /*{ - "title": { - "en": "Minimum Discharge Temperature", - "de": "Minimale Entladetemperatur" - } - }*/ - TS_ITEM_FLOAT(0xB6, "sDisMinTemperature_degC", &bat_conf_user.discharge_temp_min, 1, - ID_LOAD, TS_ANY_R | TS_ANY_W, SUBSET_NVM), +THINGSET_ADD_GROUP(TS_ID_ROOT, ID_LOAD, "Load", THINGSET_NO_CALLBACK); + +/*{ + "title": { + "en": "Load Outupt Current", + "de": "Lastausgangs-Strom" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_LOAD, 0x83B, "rCurrent_A", &load.current, 2, + THINGSET_ANY_R, TS_SUBSET_LIVE); + +/*{ + "title": { + "en": "Load Output Power", + "de": "Lastausgangs-Leistung" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_LOAD, 0x83C, "rPower_W", &load.power, 2, + THINGSET_ANY_R, TS_SUBSET_LIVE); + +/*{ + "title": { + "en": "Load State", + "de": "Last-Zustand" + } +}*/ +THINGSET_ADD_ITEM_INT32(ID_LOAD, 0x855, "rState", &load.info, + THINGSET_ANY_R, TS_SUBSET_LIVE); + +/*{ + "title": { + "en": "Load Output Energy (today)", + "de": "Energie Last-Ausgang (heute)" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_LOAD, 0x86D, "pOutputToday_Wh", &load.pos_energy_Wh, 2, + THINGSET_ANY_R | THINGSET_MFR_W, TS_SUBSET_LIVE); + +/*{ + "title": { + "en": "Load Output Energy (total)", + "de": "Energiedurchsatz Lastausgang (gesamt)" + } +}*/ +THINGSET_ADD_ITEM_UINT32(ID_LOAD, 0x866, "pOutputTotal_Wh", &dev_stat.load_out_total_Wh, + THINGSET_ANY_R | THINGSET_MFR_W, TS_SUBSET_NVM); + +/*{ + "title": { + "en": "Peak Load Power (today)", + "de": "Maximale Lastleistung (heute)" + } +}*/ +THINGSET_ADD_ITEM_UINT16(ID_LOAD, 0x86F, "pPowerMaxToday_W", &dev_stat.load_power_max_day, + THINGSET_ANY_R | THINGSET_MFR_W, 0); + +/*{ + "title": { + "en": "Load Peak Power (total)", + "de": "Maximalleistung Last-Ausgang (gesamt)" + } +}*/ +THINGSET_ADD_ITEM_UINT16(ID_LOAD, 0x873, "pPowerMaxTotal_W", &dev_stat.load_power_max_total, + THINGSET_ANY_R | THINGSET_MFR_W, TS_SUBSET_NVM); + +/*{ + "title": { + "en": "Load Peak Current (all-time)", + "de": "Maximalstrom Lastausgang (gesamt)" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_LOAD, 0x877, "pCurrentMaxTotal_A", &dev_stat.load_current_max, 2, + THINGSET_ANY_R | THINGSET_MFR_W, TS_SUBSET_NVM); + +/*{ + "title": { + "en": "Enable Load", + "de": "Last einschalten" + } +}*/ +THINGSET_ADD_ITEM_BOOL(ID_LOAD, 0x880, "wEnable", &load.enable, + THINGSET_ANY_R | THINGSET_ANY_W, 0); + +/*{ + "title": { + "en": "Automatic Load Output Enable", + "de": "Last-Ausgang automatisch einschalten" + } +}*/ +THINGSET_ADD_ITEM_BOOL(ID_LOAD, 0x8B7, "sEnableDefault", &load.enable, + THINGSET_ANY_R | THINGSET_ANY_W, TS_SUBSET_NVM); + +/*{ + "title": { + "en": "Load Disconnect Voltage ", + "de": "Abschaltspannung Lastausgang" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_LOAD, 0xB8, "sDisconnectVoltage_V", &bat_conf_user.load_disconnect_voltage, 2, + THINGSET_ANY_R | THINGSET_ANY_W, TS_SUBSET_NVM); + +/*{ + "title": { + "en": "Load Reconnect Voltage", + "de": "Wiedereinschalt-Spannung Lastausgang" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_LOAD, 0x8B9, "sReconnectVoltage_V", &bat_conf_user.load_reconnect_voltage, 2, + THINGSET_ANY_R | THINGSET_ANY_W, TS_SUBSET_NVM); + +/*{ + "title": { + "en": "Overcurrent Recovery Delay", + "de": "Wiedereinschalt-Verzögerung nach Überstrom" + } +}*/ +THINGSET_ADD_ITEM_UINT32(ID_LOAD, 0x8BA, "sOvercurrentRecoveryDelay_s", &load.oc_recovery_delay, + THINGSET_ANY_R | THINGSET_ANY_W, TS_SUBSET_NVM); + +/*{ + "title": { + "en": "Low Voltage Disconnect Recovery Delay", + "de": "Wiedereinschalt-Verzögerung nach Unterspannung" + } +}*/ +THINGSET_ADD_ITEM_UINT32(ID_LOAD, 0x8BB, "sUndervoltageRecoveryDelay_s", &load.lvd_recovery_delay, + THINGSET_ANY_R | THINGSET_ANY_W, TS_SUBSET_NVM); + +/*{ + "title": { + "en": "Maximum Discharge Temperature", + "de": "Maximale Entladetemperatur" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_LOAD, 0x8B5, "sDisMaxTemperature_degC", &bat_conf_user.discharge_temp_max, 1, + THINGSET_ANY_R | THINGSET_ANY_W, TS_SUBSET_NVM); + +/*{ + "title": { + "en": "Minimum Discharge Temperature", + "de": "Minimale Entladetemperatur" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_LOAD, 0x8B6, "sDisMinTemperature_degC", &bat_conf_user.discharge_temp_min, 1, + THINGSET_ANY_R | THINGSET_ANY_W, TS_SUBSET_NVM); #endif /* BOARD_HAS_LOAD_OUTPUT */ - /////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// #if BOARD_HAS_USB_OUTPUT - TS_GROUP(ID_USB, "USB", TS_NO_CALLBACK, ID_ROOT), - - /*{ - "title": { - "en": "USB State", - "de": "USB-Zustand" - } - }*/ - TS_ITEM_INT32(0x56, "rState", &usb_pwr.info, - ID_USB, TS_ANY_R, SUBSET_SER | SUBSET_CAN), - - /*{ - "title": { - "en": "Enable USB", - "de": "USB einschalten" - } - }*/ - TS_ITEM_BOOL(0x81, "wEnable", &usb_pwr.enable, - ID_USB, TS_ANY_R | TS_ANY_W, 0), - - /*{ - "title": { - "en": "Automatic USB Power Output Enable", - "de": "USB Ladeport automatisch einschalten" - } - }*/ - TS_ITEM_BOOL(0xBC, "sEnableDefault", &usb_pwr.enable, - ID_USB, TS_ANY_R | TS_ANY_W, SUBSET_NVM), - - /*{ - "title": { - "en": "USB low voltage disconnect recovery delay", - "de": "Wiedereinschalt-Verzögerung USB nach Unterspannung" - } - }*/ - TS_ITEM_UINT32(0xBD, "sUndervoltageRecoveryDelay_s", &usb_pwr.lvd_recovery_delay, - ID_USB, TS_ANY_R | TS_ANY_W, SUBSET_NVM), +THINGSET_ADD_GROUP(TS_ID_ROOT, ID_USB, "USB", THINGSET_NO_CALLBACK); + +/*{ + "title": { + "en": "USB State", + "de": "USB-Zustand" + } +}*/ +THINGSET_ADD_ITEM_INT32(ID_USB, 0x956, "rState", &usb_pwr.info, + THINGSET_ANY_R, TS_SUBSET_LIVE); + +/*{ + "title": { + "en": "Enable USB", + "de": "USB einschalten" + } +}*/ +THINGSET_ADD_ITEM_BOOL(ID_USB, 0x981, "wEnable", &usb_pwr.enable, + THINGSET_ANY_R | THINGSET_ANY_W, 0); + +/*{ + "title": { + "en": "Automatic USB Power Output Enable", + "de": "USB Ladeport automatisch einschalten" + } +}*/ +THINGSET_ADD_ITEM_BOOL(ID_USB, 0x9BC, "sEnableDefault", &usb_pwr.enable, + THINGSET_ANY_R | THINGSET_ANY_W, TS_SUBSET_NVM); + +/*{ + "title": { + "en": "USB low voltage disconnect recovery delay", + "de": "Wiedereinschalt-Verzögerung USB nach Unterspannung" + } +}*/ +THINGSET_ADD_ITEM_UINT32(ID_USB, 0x9BD, "sUndervoltageRecoveryDelay_s", &usb_pwr.lvd_recovery_delay, + THINGSET_ANY_R | THINGSET_ANY_W, TS_SUBSET_NVM); #endif /* BOARD_HAS_USB_OUTPUT */ - /////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// #if CONFIG_HV_TERMINAL_NANOGRID - TS_GROUP(ID_NANOGRID, "Nanogrid", TS_NO_CALLBACK, ID_ROOT), - - /*{ - "title": { - "en": "DC Grid Voltage", - "de": "Spannung DC-Netz" - } - }*/ - TS_ITEM_FLOAT(0x3D, "rVoltage_V", &hv_bus.voltage, 2, - ID_NANOGRID, TS_ANY_R, SUBSET_SER | SUBSET_CAN), - - /*{ - "title": { - "en": "DC Grid Current", - "de": "Strom DC-Netz" - } - }*/ - TS_ITEM_FLOAT(0x3E, "rCurrent_A", &hv_terminal.current, 2, - ID_NANOGRID, TS_ANY_R, SUBSET_SER | SUBSET_CAN), - - /*{ - "title": { - "en": "DC Grid Power", - "de": "Leistung DC-Grid" - } - }*/ - TS_ITEM_FLOAT(0x3F, "rPower_W", &hv_terminal.power, 2, - ID_NANOGRID, TS_ANY_R, SUBSET_SER | SUBSET_CAN), - - /*{ - "title": { - "en": "Grid Imported Energy (total)", - "de": "Energie-Import DC-Netz (gesamt)" - } - }*/ - TS_ITEM_UINT32(0x67, "pImportTotalEnergy_Wh", &dev_stat.grid_import_total_Wh, - ID_NANOGRID, TS_ANY_R | TS_MKR_W, SUBSET_NVM), - - /*{ - "title": { - "en": "Grid Exported Energy (total)", - "de": "Energie-Export DC-Netz (gesamt)" - } - }*/ - TS_ITEM_UINT32(0x68, "pExportTotalEnergy_Wh", &dev_stat.grid_export_total_Wh, - ID_NANOGRID, TS_ANY_R | TS_MKR_W, SUBSET_NVM), - - /*{ - "title": { - "en": "DC Grid Export Voltage", - "de": "DC-Grid Export-Spannung" - } - }*/ - TS_ITEM_FLOAT(0x84, "wGridSinkVoltage_V", &hv_bus.sink_voltage_intercept, 2, - ID_NANOGRID, TS_ANY_R | TS_ANY_W, 0), - - /*{ - "title": { - "en": "DC Grid Import Voltage", - "de": "DC-Grid Import-Spannung" - } - }*/ - TS_ITEM_FLOAT(0x85, "wGridSrcVoltage_V", &hv_bus.src_voltage_intercept, 2, - ID_NANOGRID, TS_ANY_R | TS_ANY_W, 0), +THINGSET_ADD_GROUP(ID_NANOGRID, "Nanogrid", THINGSET_NO_CALLBACK); -#endif /* CONFIG_HV_TERMINAL_NANOGRID */ - - /////////////////////////////////////////////////////////////////////////////////////////////// - - TS_GROUP(ID_DFU, "DFU", TS_NO_CALLBACK, ID_ROOT), - - /*{ - "title": { - "en": "Start the Bootloader", - "de": "Bootloader starten" - } - }*/ - TS_FN_VOID(0xF0, "xBootloaderSTM", &start_stm32_bootloader, ID_DFU, TS_ANY_RW), - - /*{ - "title": { - "en": "Flash Memory Size", - "de": "Flash-Speicher Gesamtgröße" - } - }*/ - TS_ITEM_UINT32(0xF1, "rFlashSize_KiB", &flash_size, ID_DFU, TS_ANY_R, 0), - - /*{ - "title": { - "en": "Flash Memory Page Size", - "de": "Flash-Speicher Seitengröße" - } - }*/ - TS_ITEM_UINT32(0xF2, "rFlashPageSize_B", &flash_page_size, ID_DFU, TS_ANY_R, 0), - - /////////////////////////////////////////////////////////////////////////////////////////////// - - TS_SUBSET(0x0A, "mSerial", SUBSET_SER, ID_ROOT, TS_ANY_RW), -#if CONFIG_THINGSET_CAN - TS_SUBSET(0x0B, "mCAN", SUBSET_CAN, ID_ROOT, TS_ANY_RW), -#endif - - TS_GROUP(ID_PUB, "_Pub", TS_NO_CALLBACK, ID_ROOT), - - TS_GROUP(0x101, "mSerial", NULL, ID_PUB), - - /*{ - "title": { - "en": "Enable/Disable serial publications", - "de": "Serielle Publikation (de)aktivieren" - } - }*/ - TS_ITEM_BOOL(0x102, "wEnable", &pub_serial_enable, 0x101, TS_ANY_RW, 0), - -#if CONFIG_THINGSET_CAN - TS_GROUP(0x103, "mCAN", TS_NO_CALLBACK, ID_PUB), - - /*{ - "title": { - "en": "Enable/Disable CAN publications", - "de": "CAN Publikation (de)aktivieren" - } - }*/ - TS_ITEM_BOOL(0x104, "wEnable", &pub_can_enable, 0x103, TS_ANY_RW, 0), -#endif +/*{ + "title": { + "en": "DC Grid Voltage", + "de": "Spannung DC-Netz" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_NANOGRID, 0xA3D, "rVoltage_V", &hv_bus.voltage, 2, + THINGSET_ANY_R, TS_SUBSET_LIVE); + +/*{ + "title": { + "en": "DC Grid Current", + "de": "Strom DC-Netz" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_NANOGRID, 0xA3E, "rCurrent_A", &hv_terminal.current, 2, + THINGSET_ANY_R, TS_SUBSET_LIVE); + +/*{ + "title": { + "en": "DC Grid Power", + "de": "Leistung DC-Grid" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_NANOGRID, 0xA3F, "rPower_W", &hv_terminal.power, 2, + THINGSET_ANY_R, TS_SUBSET_LIVE); + +/*{ + "title": { + "en": "Grid Imported Energy (total)", + "de": "Energie-Import DC-Netz (gesamt)" + } +}*/ +THINGSET_ADD_ITEM_UINT32(ID_NANOGRID, 0xA67, "pImportTotalEnergy_Wh", &dev_stat.grid_import_total_Wh, + THINGSET_ANY_R | THINGSET_MFR_W, TS_SUBSET_NVM); + +/*{ + "title": { + "en": "Grid Exported Energy (total)", + "de": "Energie-Export DC-Netz (gesamt)" + } +}*/ +THINGSET_ADD_ITEM_UINT32(ID_NANOGRID, 0xA68, "pExportTotalEnergy_Wh", &dev_stat.grid_export_total_Wh, + THINGSET_ANY_R | THINGSET_MFR_W, TS_SUBSET_NVM); + +/*{ + "title": { + "en": "DC Grid Export Voltage", + "de": "DC-Grid Export-Spannung" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_NANOGRID, 0xA84, "wGridSinkVoltage_V", &hv_bus.sink_voltage_intercept, 2, + THINGSET_ANY_R | THINGSET_ANY_W, 0); + +/*{ + "title": { + "en": "DC Grid Import Voltage", + "de": "DC-Grid Import-Spannung" + } +}*/ +THINGSET_ADD_ITEM_FLOAT(ID_NANOGRID, 0xA85, "wGridSrcVoltage_V", &hv_bus.src_voltage_intercept, 2, + THINGSET_ANY_R | THINGSET_ANY_W, 0); - /////////////////////////////////////////////////////////////////////////////////////////////// - - /* - * Control parameters (IDs >= 0x8000) - * - * Temporarily choosing free IDs >= 0x7000 for testing. - */ - TS_GROUP(ID_CTRL, "Control", TS_NO_CALLBACK, ID_ROOT), - - /*{ - "title": { - "en": "Current control target", - "de": "Sollwert Strom-Regelung" - } - }*/ - TS_ITEM_FLOAT(0x7001, "zCtrlTarget_A", &charger.target_current_control, 1, - ID_CTRL, TS_ANY_RW, SUBSET_CTRL), -}; +#endif /* CONFIG_HV_TERMINAL_NANOGRID */ /* clang-format on */ -ThingSet ts(data_objects, sizeof(data_objects) / sizeof(ThingSetDataObject)); void data_objects_update_conf() { bool changed; + if (battery_conf_check(&bat_conf_user)) { LOG_INF("New config valid and activated."); battery_conf_overwrite(&bat_conf_user, &bat_conf, &charger); @@ -1164,23 +1040,12 @@ void data_objects_update_conf() changed = true; // temporary hack if (changed) { - data_storage_write(); + thingset_storage_save_queued(); } } void data_objects_init() { -#ifndef UNIT_TEST - uint8_t buf[12]; - hwinfo_get_device_id(buf, sizeof(buf)); - - uint64_t id64 = crc32_ieee(buf, sizeof(buf)); - id64 += ((uint64_t)CONFIG_LIBRE_SOLAR_TYPE_ID) << 32; - - uint64_to_base32(id64, device_id, sizeof(device_id), alphabet_crockford); -#endif - - data_storage_read(); if (battery_conf_check(&bat_conf_user)) { battery_conf_overwrite(&bat_conf_user, &bat_conf, &charger); } @@ -1188,49 +1053,7 @@ void data_objects_init() battery_conf_overwrite(&bat_conf, &bat_conf_user); } - ts.set_update_callback(SUBSET_NVM, data_objects_update_conf); -} - -void thingset_auth() -{ - static const char pass_exp[] = CONFIG_THINGSET_EXPERT_PASSWORD; - static const char pass_mkr[] = CONFIG_THINGSET_MAKER_PASSWORD; - - if (strlen(pass_exp) == strlen(auth_password) - && strncmp(auth_password, pass_exp, strlen(pass_exp)) == 0) - { - LOG_INF("Authenticated as expert user."); - ts.set_authentication(TS_EXP_MASK | TS_USR_MASK); - } - else if (strlen(pass_mkr) == strlen(auth_password) - && strncmp(auth_password, pass_mkr, strlen(pass_mkr)) == 0) - { - LOG_INF("Authenticated as maker."); - ts.set_authentication(TS_MKR_MASK | TS_USR_MASK); - } - else { - LOG_INF("Reset authentication."); - ts.set_authentication(TS_USR_MASK); - } -} - -void uint64_to_base32(uint64_t in, char *out, size_t size, const char *alphabet) -{ - // 13 is the maximum number of characters needed to encode 64-bit variable to base32 - int len = (size > 13) ? 13 : size; - - // find out actual length of output string - for (int i = 0; i < len; i++) { - if ((in >> (i * 5)) == 0) { - len = i; - break; - } - } - - for (int i = 0; i < len; i++) { - out[len - i - 1] = alphabet[(in >> (i * 5)) % 32]; - } - out[len] = '\0'; + thingset_set_update_callback(&ts, TS_SUBSET_NVM, data_objects_update_conf); } void update_control() diff --git a/app/src/data_objects.h b/app/src/data_objects.h index a6c83231..6867f715 100644 --- a/app/src/data_objects.h +++ b/app/src/data_objects.h @@ -19,35 +19,13 @@ * Groups / first layer data object IDs */ #define ID_ROOT 0x00 -#define ID_DEVICE 0x01 -#define ID_BATTERY 0x02 -#define ID_CHARGER 0x03 -#define ID_SOLAR 0x04 -#define ID_LOAD 0x05 -#define ID_USB 0x06 -#define ID_NANOGRID 0x07 -#define ID_DFU 0x0F -#define ID_PUB 0x100 -#define ID_CTRL 0x8000 - -/* - * Subset definitions for statements and publish/subscribe - */ -#define SUBSET_SER (1U << 0) // UART serial -#define SUBSET_CAN (1U << 1) // CAN bus -#define SUBSET_NVM (1U << 2) // data that should be stored in EEPROM -#define SUBSET_CTRL (1U << 3) // control data sent and received via CAN - -/* - * Data object versioning for EEPROM - * - * Increment the version number each time any data object IDs stored in NVM are changed. Otherwise - * data might get corrupted. - */ -#define DATA_OBJECTS_VERSION 05 - -extern bool pub_serial_enable; -extern bool pub_can_enable; +#define ID_DEVICE 0x04 +#define ID_BATTERY 0x05 +#define ID_CHARGER 0x06 +#define ID_SOLAR 0x07 +#define ID_LOAD 0x08 +#define ID_USB 0x09 +#define ID_NANOGRID 0x0A /** * Callback function to be called when conf values were changed @@ -59,26 +37,4 @@ void data_objects_update_conf(); */ void data_objects_init(); -/** - * Callback to provide authentication mechanism via ThingSet - */ -void thingset_auth(); - -/** - * Alphabet used for base32 encoding - * - * https://en.wikipedia.org/wiki/Base32#Crockford's_Base32 - */ -const char alphabet_crockford[] = "0123456789abcdefghjkmnpqrstvwxyz"; - -/** - * Convert numeric device ID to base32 string - */ -void uint64_to_base32(uint64_t in, char *out, size_t size, const char *alphabet); - -/** - * Update control values received via CAN - */ -void update_control(); - #endif /* DATA_OBJECTS_H */ diff --git a/app/src/data_storage.cpp b/app/src/data_storage.cpp deleted file mode 100644 index 46e79da4..00000000 --- a/app/src/data_storage.cpp +++ /dev/null @@ -1,289 +0,0 @@ -/* - * Copyright (c) The Libre Solar Project Contributors - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "data_storage.h" - -#include - -#include "data_objects.h" -#include "helper.h" -#include "mcu.h" -#include "thingset.h" - -#include - -#ifdef CONFIG_SOC_FAMILY_STM32 - -#include -#include - -LOG_MODULE_REGISTER(nvs, CONFIG_DATA_STORAGE_LOG_LEVEL); - -K_MUTEX_DEFINE(data_buf_lock); - -// Buffer used by store and restore functions (must be word-aligned for hardware CRC calculation) -static uint8_t buf[512] __aligned(sizeof(uint32_t)); - -extern ThingSet ts; - -uint32_t _calc_crc(const uint8_t *buf, size_t len) -{ - LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_CRC); - - // we keep standard polynomial 0x04C11DB7 (same for STM32L0 and STM32F0) - // and we don't care for endianness here - CRC->CR |= CRC_CR_RESET; - for (size_t i = 0; i < len; i += 4) { - // printf("CRC buf: %.8x, CRC->DR: %.8x\n", *((uint32_t*)&buf[i]), CRC->DR); - size_t remaining_bytes = len - i; - if (remaining_bytes >= 4) { - CRC->DR = *((uint32_t *)&buf[i]); - } - else { - // ignore bytes >= len if len is not a multiple of 4 - CRC->DR = *((uint32_t *)&buf[i]) & (0xFFFFFFFFU >> (32 - remaining_bytes * 8)); - } - } - - LL_AHB1_GRP1_DisableClock(LL_AHB1_GRP1_PERIPH_CRC); - - return CRC->DR; -} - -#endif /* UNIT_TEST */ - -#ifdef CONFIG_EEPROM - -#include - -/* - * EEPROM header bytes: - * - 0-1: Data objects version number - * - 2-3: Number of data bytes - * - 4-7: CRC32 - * - * Data starts from byte 8 - */ -#define EEPROM_HEADER_SIZE 8 - -static const struct device *eeprom_dev = DEVICE_DT_GET(DT_NODELABEL(eeprom)); - -void data_storage_read() -{ - int err; - - if (!device_is_ready(eeprom_dev)) { - LOG_ERR("EEPROM device not ready"); - return; - } - - uint8_t buf_header[EEPROM_HEADER_SIZE] = {}; - err = eeprom_read(eeprom_dev, 0, buf_header, EEPROM_HEADER_SIZE); - if (err != 0) { - LOG_ERR("EEPROM read error %d", err); - return; - } - uint16_t version = *((uint16_t *)&buf_header[0]); - uint16_t len = *((uint16_t *)&buf_header[2]); - uint32_t crc = *((uint32_t *)&buf_header[4]); - - LOG_DBG("EEPROM header restore: ver %d, len %d, CRC %.8x", version, len, (unsigned int)crc); - LOG_DBG("Header: %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x", buf_header[0], buf_header[1], - buf_header[2], buf_header[3], buf_header[4], buf_header[5], buf_header[6], - buf_header[7]); - - if (version == DATA_OBJECTS_VERSION && len <= sizeof(buf)) { - k_mutex_lock(&data_buf_lock, K_FOREVER); - err = eeprom_read(eeprom_dev, EEPROM_HEADER_SIZE, buf, len); - - // printf("Data (len=%d): ", len); - // for (int i = 0; i < len; i++) printf("%.2x ", buf[i]); - - if (_calc_crc(buf, len) == crc) { - int status = ts.bin_import(buf, sizeof(buf), TS_WRITE_MASK, SUBSET_NVM); - LOG_INF("EEPROM read and data objects updated, ThingSet result: 0x%x", status); - } - else { - LOG_ERR("EEPROM data CRC invalid, expected 0x%x (data_len = %d)", (unsigned int)crc, - len); - } - k_mutex_unlock(&data_buf_lock); - } - else { - LOG_INF("EEPROM empty or data layout version changed"); - } -} - -void data_storage_write() -{ - int err; - - if (!device_is_ready(eeprom_dev)) { - LOG_ERR("EEPROM device not ready"); - return; - } - - k_mutex_lock(&data_buf_lock, K_FOREVER); - - int len = ts.bin_export(buf + EEPROM_HEADER_SIZE, sizeof(buf) - EEPROM_HEADER_SIZE, SUBSET_NVM); - uint32_t crc = _calc_crc(buf + EEPROM_HEADER_SIZE, len); - - *((uint16_t *)&buf[0]) = (uint16_t)DATA_OBJECTS_VERSION; - *((uint16_t *)&buf[2]) = (uint16_t)(len); - *((uint32_t *)&buf[4]) = crc; - - // printf("Data (len=%d): ", len); - // for (int i = 0; i < len; i++) printf("%.2x ", buf[i + EEPROM_HEADER_SIZE]); - - LOG_DBG("Header: %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x", buf[0], buf[1], buf[2], buf[3], - buf[4], buf[5], buf[6], buf[7]); - - if (len == 0) { - LOG_ERR("EEPROM data could not be stored. ThingSet error (len = %d)", len); - } - else { - err = eeprom_write(eeprom_dev, 0, buf, len + EEPROM_HEADER_SIZE); - if (err == 0) { - LOG_INF("EEPROM data successfully stored"); - } - else { - LOG_ERR("EEPROM write error %d", err); - } - } - k_mutex_unlock(&data_buf_lock); -} - -#elif defined(CONFIG_NVS) - -#include -#include -#include - -/* - * NVS header bytes: - * - 0-1: Data objects version number - * - * Data starts from byte 2 - */ -#define NVS_HEADER_SIZE 2 - -#define NVS_PARTITION storage_partition - -#define THINGSET_DATA_ID 1 - -static struct nvs_fs fs; -static bool nvs_initialized = false; - -static int data_storage_init() -{ - int err; - struct flash_pages_info page_info; - - fs.flash_device = FIXED_PARTITION_DEVICE(NVS_PARTITION); - if (!device_is_ready(fs.flash_device)) { - LOG_ERR("Flash device not ready"); - return -ENODEV; - } - fs.offset = FIXED_PARTITION_OFFSET(NVS_PARTITION); - err = flash_get_page_info_by_offs(fs.flash_device, fs.offset, &page_info); - if (err) { - LOG_ERR("Unable to get flash page info"); - return err; - } - fs.sector_size = page_info.size; - fs.sector_count = FIXED_PARTITION_SIZE(NVS_PARTITION) / page_info.size; - - err = nvs_mount(&fs); - if (err) { - LOG_ERR("NVS mount failed: %d", err); - return err; - } - - nvs_initialized = true; - return 0; -} - -void data_storage_read() -{ - if (!nvs_initialized) { - int err = data_storage_init(); - if (err) { - return; - } - } - - int num_bytes = nvs_read(&fs, THINGSET_DATA_ID, &buf, sizeof(buf)); - - if (num_bytes < 0) { - LOG_INF("NVS empty (read error %d)", num_bytes); - return; - } - - uint16_t version = *((uint16_t *)&buf[0]); - - if (version == DATA_OBJECTS_VERSION) { - k_mutex_lock(&data_buf_lock, K_FOREVER); - - int status = ts.bin_import(buf + NVS_HEADER_SIZE, num_bytes - NVS_HEADER_SIZE, - TS_WRITE_MASK, SUBSET_NVM); - LOG_INF("NVS read and data objects updated, ThingSet result: 0x%x", status); - - k_mutex_unlock(&data_buf_lock); - } - else { - LOG_INF("NVS data layout version changed"); - } -} - -void data_storage_write() -{ - if (!nvs_initialized) { - int err = data_storage_init(); - if (err) { - return; - } - } - - k_mutex_lock(&data_buf_lock, K_FOREVER); - - *((uint16_t *)&buf[0]) = (uint16_t)DATA_OBJECTS_VERSION; - - int len = ts.bin_export(buf + NVS_HEADER_SIZE, sizeof(buf) - NVS_HEADER_SIZE, SUBSET_NVM); - - if (len == 0) { - LOG_ERR("NVS data could not be stored. ThingSet error (len = %d)", len); - } - else { - int ret = nvs_write(&fs, THINGSET_DATA_ID, &buf, len + NVS_HEADER_SIZE); - if (ret == len + NVS_HEADER_SIZE) { - LOG_DBG("NVS data successfully stored"); - } - else if (ret == 0) { - LOG_DBG("NVS data unchanged"); - } - else { - LOG_ERR("NVS write error %d", ret); - } - } - - k_mutex_unlock(&data_buf_lock); -} - -#else - -void data_storage_write() -{} -void data_storage_read() -{} - -#endif - -void data_storage_update() -{ - if (uptime() % DATA_UPDATE_INTERVAL == 0 && uptime() > 0) { - data_storage_write(); - } -} diff --git a/app/src/data_storage.h b/app/src/data_storage.h deleted file mode 100644 index 2a31b59b..00000000 --- a/app/src/data_storage.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) The Libre Solar Project Contributors - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef DATA_STORAGE_H_ -#define DATA_STORAGE_H_ - -#define DATA_UPDATE_INTERVAL (6 * 60 * 60) // update every 6 hours - -/** - * @file - * - * @brief Handling of internal or external EEPROM to store device configuration - */ - -/** - * Store current charge controller data to EEPROM - */ -void data_storage_write(); - -/** - * Restore charge controller data from EEPROM and write to variables in RAM - */ -void data_storage_read(); - -/** - * Stores data to EEPROM every 6 hours (can be called regularly) - */ -void data_storage_update(); - -#endif /* DATA_STORAGE_H_ */ diff --git a/app/src/dcdc.cpp b/app/src/dcdc.cpp index 14444363..35d2eafc 100644 --- a/app/src/dcdc.cpp +++ b/app/src/dcdc.cpp @@ -15,12 +15,15 @@ #include #include // for min/max function -#include "data_storage.h" #include "device_status.h" #include "half_bridge.h" #include "helper.h" #include "setup.h" +#include +#include +#include + LOG_MODULE_REGISTER(dcdc, CONFIG_DCDC_LOG_LEVEL); #if BOARD_HAS_DCDC @@ -360,7 +363,7 @@ void Dcdc::fuse_destruction() if (counter > 20) { // wait 20s to be able to send out data LOG_ERR("Charge controller fuse destruction called!\n"); - data_storage_write(); + thingset_storage_save(); half_bridge_stop(); half_bridge_init(50, 0, 0, 0.98); // reset safety limits to allow 0% duty cycle half_bridge_set_duty_cycle(0); diff --git a/app/src/ext/CMakeLists.txt b/app/src/ext/CMakeLists.txt deleted file mode 100644 index 5b594d15..00000000 --- a/app/src/ext/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 - -target_sources(app PRIVATE - oled.cpp - serial.cpp - can.cpp -) diff --git a/app/src/ext/README.md b/app/src/ext/README.md deleted file mode 100644 index b25d4b2d..00000000 --- a/app/src/ext/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Folder src/ext - -This folder contains code for all **ext**ensions (displays etc. connected to UEXT port) and **ext**ernal communication interfaces (UART or CAN). diff --git a/app/src/ext/can.cpp b/app/src/ext/can.cpp deleted file mode 100644 index 6ea44c47..00000000 --- a/app/src/ext/can.cpp +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Copyright (c) The Libre Solar Project Contributors - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#if CONFIG_THINGSET_CAN - -#include -#include -#include -#include -#include - -#ifdef CONFIG_ISOTP -#include -#endif - -#include -LOG_MODULE_REGISTER(ext_can, CONFIG_CAN_LOG_LEVEL); - -#include "bat_charger.h" -#include "data_objects.h" -#include "hardware.h" -#include "helper.h" -#include "thingset.h" - -#if DT_NODE_EXISTS(DT_CHILD(DT_PATH(outputs), can_en)) -#define CAN_EN_GPIO DT_CHILD(DT_PATH(outputs), can_en) -#endif - -extern ThingSet ts; -extern uint16_t can_node_addr; -extern Charger charger; - -static const struct device *can_dev = DEVICE_DT_GET(DT_NODELABEL(can1)); - -#ifdef CONFIG_ISOTP - -#define RX_THREAD_STACK_SIZE 1024 -#define RX_THREAD_PRIORITY 2 - -const struct isotp_fc_opts fc_opts = { - .bs = 8, // block size - .stmin = 1, // minimum separation time = 100 ms -}; - -struct isotp_msg_id rx_addr = { - .id_type = CAN_EXTENDED_IDENTIFIER, - .use_ext_addr = 0, // Normal ISO-TP addressing (using only CAN ID) - .use_fixed_addr = 1, // enable SAE J1939 compatible addressing -}; - -struct isotp_msg_id tx_addr = { - .id_type = CAN_EXTENDED_IDENTIFIER, - .use_ext_addr = 0, // Normal ISO-TP addressing (using only CAN ID) - .use_fixed_addr = 1, // enable SAE J1939 compatible addressing -}; - -static struct isotp_recv_ctx recv_ctx; -static struct isotp_send_ctx send_ctx; - -void send_complete_cb(int error_nr, void *arg) -{ - ARG_UNUSED(arg); - LOG_DBG("TX complete callback, err: %d", error_nr); -} - -void can_isotp_thread() -{ - int ret, rem_len, resp_len; - unsigned int req_len; - struct net_buf *buf; - static uint8_t rx_buffer[600]; // large enough to receive a 512k flash page for DFU - static uint8_t tx_buffer[1000]; - - if (!device_is_ready(can_dev)) { - return; - } - - while (1) { - /* re-assign address in every loop as it may have been changed via ThingSet */ - rx_addr.ext_id = - TS_CAN_TYPE_REQRESP | TS_CAN_PRIO_REQRESP | TS_CAN_TARGET_SET(can_node_addr); - tx_addr.ext_id = - TS_CAN_TYPE_REQRESP | TS_CAN_PRIO_REQRESP | TS_CAN_SOURCE_SET(can_node_addr); - - ret = isotp_bind(&recv_ctx, can_dev, &rx_addr, &tx_addr, &fc_opts, K_FOREVER); - if (ret != ISOTP_N_OK) { - LOG_DBG("Failed to bind to rx ID %d [%d]", rx_addr.ext_id, ret); - return; - } - - req_len = 0; - do { - rem_len = isotp_recv_net(&recv_ctx, &buf, K_FOREVER); - if (rem_len < 0) { - LOG_DBG("Receiving error [%d]", rem_len); - break; - } - if (req_len + buf->len <= sizeof(rx_buffer)) { - memcpy(&rx_buffer[req_len], buf->data, buf->len); - } - req_len += buf->len; - net_buf_unref(buf); - } while (rem_len); - - // we need to unbind the receive ctx so that control frames are received in the send ctx - isotp_unbind(&recv_ctx); - - if (req_len > sizeof(rx_buffer)) { - LOG_DBG("RX buffer too small"); - tx_buffer[0] = TS_STATUS_REQUEST_TOO_LARGE; - resp_len = 1; - } - else if (req_len > 0 && rem_len == 0) { - LOG_INF("Got %d bytes via ISO-TP. Processing ThingSet message.", req_len); - resp_len = ts.process(rx_buffer, req_len, tx_buffer, sizeof(tx_buffer)); - LOG_DBG("TX buf: %x %x %x %x", tx_buffer[0], tx_buffer[1], tx_buffer[2], tx_buffer[3]); - } - else { - tx_buffer[0] = TS_STATUS_INTERNAL_SERVER_ERR; - resp_len = 1; - } - - if (resp_len > 0) { - ret = isotp_send(&send_ctx, can_dev, tx_buffer, resp_len, &recv_ctx.tx_addr, - &recv_ctx.rx_addr, send_complete_cb, NULL); - if (ret != ISOTP_N_OK) { - LOG_DBG("Error while sending data to ID %d [%d]", tx_addr.ext_id, ret); - } - } - } -} - -K_THREAD_DEFINE(can_isotp, RX_THREAD_STACK_SIZE, can_isotp_thread, NULL, NULL, NULL, - RX_THREAD_PRIORITY, 0, 1500); - -#endif /* CONFIG_ISOTP */ - -// below defines should go into the ThingSet library -#define TS_CAN_SOURCE_GET(id) (((uint32_t)id & TS_CAN_SOURCE_MASK) >> TS_CAN_SOURCE_POS) -#define TS_CAN_DATA_ID_GET(id) (((uint32_t)id & TS_CAN_DATA_ID_MASK) >> TS_CAN_DATA_ID_POS) - -CAN_MSGQ_DEFINE(sub_msgq, 10); - -const struct can_filter ctrl_filter = { - .id = TS_CAN_TYPE_PUBSUB, - .rtr = CAN_DATAFRAME, - .id_type = CAN_EXTENDED_IDENTIFIER, - .id_mask = TS_CAN_TYPE_MASK, - .rtr_mask = 1, -}; - -void can_pub_isr(const struct device *dev, int error, void *user_data) -{ - // Do nothing. Publication messages are fire and forget. -} - -void can_pub_send(uint32_t can_id, uint8_t can_data[8], uint8_t data_len) -{ - struct can_frame frame = { 0 }; - frame.id_type = CAN_EXTENDED_IDENTIFIER; - frame.rtr = CAN_DATAFRAME; - frame.id = can_id; - memcpy(frame.data, can_data, 8); - - if (data_len >= 0) { - frame.dlc = data_len; - - if (can_send(can_dev, &frame, K_MSEC(10), can_pub_isr, NULL) != 0) { - LOG_DBG("Error sending CAN frame"); - } - } -} - -void can_pubsub_thread() -{ - int wdt_channel = task_wdt_add(2000, task_wdt_callback, (void *)k_current_get()); - - unsigned int can_id; - uint8_t can_data[8]; - struct can_frame rx_frame; - - if (!device_is_ready(can_dev)) { - return; - } - - int filter_id = can_add_rx_filter_msgq(can_dev, &sub_msgq, &ctrl_filter); - if (filter_id < 0) { - LOG_ERR("Unable to attach ISR [%d]", filter_id); - return; - } - - int64_t next_pub = k_uptime_get(); - uint32_t count = 0; - - while (1) { - - task_wdt_feed(wdt_channel); - - if (pub_can_enable) { - int data_len = 0; - int start_pos = 0; - while (count % 10 == 0) { - // normal objects: only every second - data_len = ts.bin_pub_can(start_pos, SUBSET_CAN, can_node_addr, can_id, can_data); - if (data_len < 0) { - // finished with all IDs - break; - } - else { - can_pub_send(can_id, can_data, data_len); - } - } - - data_len = 0; - start_pos = 0; - while (true) { - // control objects: every 100 ms - data_len = ts.bin_pub_can(start_pos, SUBSET_CTRL, can_node_addr, can_id, can_data); - if (data_len < 0) { - break; - } - else { - can_pub_send(can_id, can_data, data_len); - } - } - } - - // wait for incoming messages until the next pub message has to be sent out - while (k_msgq_get(&sub_msgq, &rx_frame, K_TIMEOUT_ABS_MS(next_pub)) != -EAGAIN) { - // process message - uint16_t data_id = TS_CAN_DATA_ID_GET(rx_frame.id); - uint8_t sender_addr = TS_CAN_SOURCE_GET(rx_frame.id); - - // control message received? - if (data_id > 0x8000 && sender_addr < can_node_addr) { - uint8_t buf[4 + 8]; // ThingSet bin headers + CAN frame payload - buf[0] = 0xA1; // CBOR: map with 1 element - buf[1] = 0x19; // CBOR: uint16 follows - buf[2] = data_id >> 8; - buf[3] = data_id; - memcpy(&buf[4], rx_frame.data, 8); - - int status = ts.bin_import(buf, 4 + rx_frame.dlc, TS_WRITE_MASK, SUBSET_CTRL); - if (status == TS_STATUS_CHANGED) { - charger.time_last_ctrl_msg = uptime(); - } - } - } - - next_pub += 100; // 100 ms period (currently fixed) - count++; - } -} - -K_THREAD_DEFINE(can_pubsub, 1024, can_pubsub_thread, NULL, NULL, NULL, 6, 0, 1000); - -#endif /* CONFIG_THINGSET_CAN */ diff --git a/app/src/ext/serial.cpp b/app/src/ext/serial.cpp deleted file mode 100644 index 41e46a84..00000000 --- a/app/src/ext/serial.cpp +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (c) The Libre Solar Project Contributors - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#if CONFIG_THINGSET_SERIAL - -#include -#include - -#include -#include -#include -#include - -#include "data_objects.h" -#include "hardware.h" -#include "thingset.h" - -#if CONFIG_UEXT_SERIAL_THINGSET -#define UART_DEVICE_NODE DT_ALIAS(uart_uext) -#elif DT_NODE_EXISTS(DT_ALIAS(uart_dbg)) -#define UART_DEVICE_NODE DT_ALIAS(uart_dbg) -#else -// cppcheck-suppress preprocessorErrorDirective -#error "No UART for ThingSet serial defined." -#endif - -static const struct device *uart_dev = DEVICE_DT_GET(UART_DEVICE_NODE); - -static char tx_buf[CONFIG_THINGSET_SERIAL_TX_BUF_SIZE]; -static char rx_buf[CONFIG_THINGSET_SERIAL_RX_BUF_SIZE]; - -static volatile size_t rx_buf_pos = 0; -static bool discard_buffer; - -static struct k_sem command_flag; // used as an event to signal a received command -static struct k_sem rx_buf_mutex; // binary semaphore used as mutex in ISR context - -extern ThingSet ts; - -const char serial_subset_path[] = "mSerial"; -static ThingSetDataObject *serial_subset; - -void serial_pub_msg() -{ - if (pub_serial_enable) { - int len = ts.txt_statement(tx_buf, sizeof(tx_buf), serial_subset); - for (int i = 0; i < len; i++) { - uart_poll_out(uart_dev, tx_buf[i]); - } - uart_poll_out(uart_dev, '\n'); - } -} - -void serial_process_command() -{ - // commands must have 2 or more characters - if (rx_buf_pos > 0) { - printf("Received Request (%d bytes): %s\n", strlen(rx_buf), rx_buf); - - int len = ts.process((uint8_t *)rx_buf, strlen(rx_buf), (uint8_t *)tx_buf, sizeof(tx_buf)); - - for (int i = 0; i < len; i++) { - uart_poll_out(uart_dev, tx_buf[i]); - } - uart_poll_out(uart_dev, '\n'); - } - - // release buffer and start waiting for new commands - rx_buf_pos = 0; - k_sem_give(&rx_buf_mutex); -} - -/* - * Read characters from stream until line end \n is detected, afterwards signal available command. - */ -void serial_cb(const struct device *dev, void *user_data) -{ - uint8_t c; - - if (!uart_irq_update(uart_dev)) { - return; - } - - while (uart_irq_rx_ready(uart_dev)) { - - uart_fifo_read(uart_dev, &c, 1); - - if (k_sem_take(&rx_buf_mutex, K_NO_WAIT) != 0) { - // buffer not available: drop character - discard_buffer = true; - continue; - } - - // \r\n and \n are markers for line end, i.e. command end - // we accept this at any time, even if the buffer is 'full', since - // there is always one last character left for the \0 - if (c == '\n') { - if (rx_buf_pos > 0 && rx_buf[rx_buf_pos - 1] == '\r') { - rx_buf[rx_buf_pos - 1] = '\0'; - } - else { - rx_buf[rx_buf_pos] = '\0'; - } - if (discard_buffer) { - rx_buf_pos = 0; - discard_buffer = false; - k_sem_give(&rx_buf_mutex); - } - else { - // start processing command and keep the rx_buf_mutex locked - k_sem_give(&command_flag); - } - return; - } - // backspace allowed if there is something in the buffer already - else if (rx_buf_pos > 0 && c == '\b') { - rx_buf_pos--; - } - // Fill the buffer up to all but 1 character (the last character is reserved for '\0') - // Characters beyond the size of the buffer are dropped. - else if (rx_buf_pos < (sizeof(rx_buf) - 1)) { - rx_buf[rx_buf_pos++] = c; - } - - k_sem_give(&rx_buf_mutex); - } -} - -void serial_thread() -{ - k_sem_init(&command_flag, 0, 1); - k_sem_init(&rx_buf_mutex, 1, 1); - - __ASSERT_NO_MSG(device_is_ready(uart_dev)); - - uart_irq_callback_user_data_set(uart_dev, serial_cb, NULL); - uart_irq_rx_enable(uart_dev); - - serial_subset = ts.get_endpoint(serial_subset_path, strlen(serial_subset_path)); - - // below process loop should be run at least once per sec, setting watchdog timeout to 1.5s - int wdt_channel = task_wdt_add(1500, task_wdt_callback, (void *)k_current_get()); - - int64_t t_start = k_uptime_get(); - - while (true) { - if (k_sem_take(&command_flag, K_TIMEOUT_ABS_MS(t_start)) == 0) { - serial_process_command(); - } - else { - // semaphore timed out (should happen exactly every 1 second) - t_start += 1000; - serial_pub_msg(); - } - task_wdt_feed(wdt_channel); - } -} - -K_THREAD_DEFINE(serial_thread_id, 1280, serial_thread, NULL, NULL, NULL, 6, 0, 1000); - -#endif /* CONFIG_THINGSET_SERIAL */ diff --git a/app/src/main.cpp b/app/src/main.cpp index cfc8a8a5..6238f1d0 100644 --- a/app/src/main.cpp +++ b/app/src/main.cpp @@ -19,7 +19,6 @@ #include "bat_charger.h" // battery settings and charger state machine #include "daq.h" // ADC using DMA and conversion to measurement values #include "data_objects.h" // for access to internal data via ThingSet -#include "data_storage.h" // non-volatile data storage (e.g. EEPROM) #include "dcdc.h" // DC/DC converter control (hardware independent) #include "device_status.h" // log data (error memory, min/max measurements, etc.) #include "half_bridge.h" // PWM generation for DC/DC converter @@ -53,7 +52,7 @@ int main(void) grid_terminal.init_nanogrid(); #endif - // read custom configuration from EEPROM + // make sure loaded configuration is valid data_objects_init(); // Data Acquisition (DAQ) setup @@ -122,8 +121,6 @@ int main(void) leds_update_soc(charger.soc, false); #endif - data_storage_update(); - t_start += 1000; k_sleep(K_TIMEOUT_ABS_MS(t_start)); } diff --git a/app/src/ext/oled.cpp b/app/src/oled.cpp similarity index 100% rename from app/src/ext/oled.cpp rename to app/src/oled.cpp diff --git a/app/src/setup.cpp b/app/src/setup.cpp index 7c60ad1c..af4cc1f1 100644 --- a/app/src/setup.cpp +++ b/app/src/setup.cpp @@ -17,7 +17,6 @@ #include "board.h" #include "daq.h" // ADC using DMA and conversion to measurement values #include "data_objects.h" // for access to internal data via ThingSet -#include "data_storage.h" // external I2C EEPROM #include "dcdc.h" // DC/DC converter control (hardware independent) #include "device_status.h" // log data (error memory, min/max measurements, etc.) #include "half_bridge.h" // PWM generation for DC/DC converter diff --git a/app/src/setup.h b/app/src/setup.h index d68c4e90..4ae1a2d8 100644 --- a/app/src/setup.h +++ b/app/src/setup.h @@ -46,8 +46,6 @@ extern LoadOutput load; extern LoadOutput usb_pwr; #endif -extern ThingSet ts; // defined in data_objects.cpp - extern uint32_t timestamp; /** diff --git a/boards/arm/mppt_1210_hus/mppt_1210_hus.dts b/boards/arm/mppt_1210_hus/mppt_1210_hus.dts index a5e4de7a..6d3c518d 100644 --- a/boards/arm/mppt_1210_hus/mppt_1210_hus.dts +++ b/boards/arm/mppt_1210_hus/mppt_1210_hus.dts @@ -23,6 +23,7 @@ }; chosen { + thingset,serial = &usart2; zephyr,console = &usart1; zephyr,shell-uart = &usart1; zephyr,sram = &sram0; @@ -124,8 +125,6 @@ }; aliases { - uart-dbg = &usart1; - uart-uext = &usart2; spi-uext = &spi1; i2c-uext = &i2c1; }; diff --git a/boards/arm/mppt_2420_hpx/mppt_2420_hpx.dts b/boards/arm/mppt_2420_hpx/mppt_2420_hpx.dts index a9e385e9..13246459 100644 --- a/boards/arm/mppt_2420_hpx/mppt_2420_hpx.dts +++ b/boards/arm/mppt_2420_hpx/mppt_2420_hpx.dts @@ -25,6 +25,7 @@ }; chosen { + thingset,serial = &usart3; zephyr,console = &usart1; zephyr,shell-uart = &usart1; zephyr,sram = &sram0; @@ -133,7 +134,6 @@ }; aliases { - uart-dbg = &usart1; uart-uext = &usart3; spi-uext = &spi1; i2c-uext = &i2c1; diff --git a/west.yml b/west.yml index 8c5bfa98..cffa534b 100644 --- a/west.yml +++ b/west.yml @@ -21,10 +21,11 @@ manifest: remote: libresolar revision: 523b26c103de56714fcda655702d600870a671bc path: modules/oled-display - - name: thingset-device-library + - name: thingset-zephyr-sdk remote: thingset - revision: 9630a357de071ac63bfbbaf9d91c6c937663601f - path: modules/thingset + revision: a85cec42835d05e75125fd723f1d7cb273eacec0 + path: thingset-zephyr-sdk + import: true - name: unity remote: throwtheswitch revision: 74cde089e65c3435ce9aa87d5c69f4f16b7f6ade