diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5480c70ff9..f4c15f37ee 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -145,32 +145,40 @@ jobs: id: date run: | echo "builddate=$(date +'%Y%m%d')" >> $GITHUB_OUTPUT - - name: Download all artifacts + - name: Download all successfully compiled artifacts uses: actions/download-artifact@v4 with: - path: artifacts/Binaries/bin/ + path: artifacts/bin/ pattern: Bin-* merge-multiple: true + - name: Download dist and docs zip files + uses: actions/download-artifact@v4 + with: + path: distribution/ + name: Distribution - name: Repackage for release upload run: | ls -R sudo apt install zipmerge zip - cd artifacts/Binaries - find . -not -name '*ESP32*' -print | zip -@ ../../ESPEasy_ESP82xx.zip + cd artifacts + # ESP8266 and ESP8285 + find . -not -name '*ESP32*' -print | zip -@ ../ESPEasy_ESP82xx.zip # ESP32 and derived chips # TODO if/when available: ESP32h2 - find . -name '*ESP32s2*' -print | zip -@ ../../ESPEasy_ESP32s2.zip - find . -name '*ESP32c3*' -print | zip -@ ../../ESPEasy_ESP32c3.zip - find . -name '*ESP32s3*' -print | zip -@ ../../ESPEasy_ESP32s3.zip - find . -name '*ESP32c2*' -print | zip -@ ../../ESPEasy_ESP32c2.zip - find . -name '*ESP32c6*' -print | zip -@ ../../ESPEasy_ESP32c6.zip - find . -name '*ESP32solo1*' -print | zip -@ ../../ESPEasy_ESP32solo1.zip - find . -name '*ESP32_*' -print | zip -@ ../../ESPEasy_ESP32.zip - cd ../.. - mv artifacts/Distribution/ESPEasy_dist* . - cp ESPEasy_dist.zip ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP82xx_binaries.zip + find . -name '*ESP32s2*' -print | zip -@ ../ESPEasy_ESP32s2.zip + find . -name '*ESP32c3*' -print | zip -@ ../ESPEasy_ESP32c3.zip + find . -name '*ESP32s3*' -print | zip -@ ../ESPEasy_ESP32s3.zip + find . -name '*ESP32c2*' -print | zip -@ ../ESPEasy_ESP32c2.zip + find . -name '*ESP32c6*' -print | zip -@ ../ESPEasy_ESP32c6.zip + find . -name '*ESP32solo1*' -print | zip -@ ../ESPEasy_ESP32solo1.zip + find . -name '*ESP32_*' -print | zip -@ ../ESPEasy_ESP32.zip + cd .. + # Add dist tools to each package, after removing some unneeded files + # Copy dist zip for ESP82xx use + cp distribution/ESPEasy_dist.zip ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP82xx_binaries.zip zip -d ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP82xx_binaries.zip "bin/blank_8MB.bin" - mv ESPEasy_dist.zip ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32_binaries.zip + # Move dist zip for ESP32 use + mv distribution/ESPEasy_dist.zip ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32_binaries.zip zip -d ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32_binaries.zip "bin/blank_1MB.bin" "bin/blank_2MB.bin" "bin/ESPEasy_2step_UploaderMega_1024.bin" zipmerge ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP82xx_binaries.zip ESPEasy_ESP82xx.zip # TODO if/when available: ESP32h2 @@ -183,8 +191,8 @@ jobs: zipmerge ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32_binaries.zip ESPEasy_ESP32.zip - uses: ncipollo/release-action@v1 with: - # Include all separately supported CPU models + # Upload all separately supported CPU models and the docs zip # TODO if/when available: ESP32h2 - artifacts: "ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP82xx_binaries.zip,ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32_binaries.zip,ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32solo1_binaries.zip,ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32s2_binaries.zip,ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32c3_binaries.zip,ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32s3_binaries.zip,ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32c2_binaries.zip,ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32c6_binaries.zip,artifacts/Distribution/*.zip" + artifacts: "ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP82xx_binaries.zip,ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32_binaries.zip,ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32solo1_binaries.zip,ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32s2_binaries.zip,ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32c3_binaries.zip,ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32s3_binaries.zip,ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32c2_binaries.zip,ESPEasy_mega_${{ steps.date.outputs.builddate }}_ESP32c6_binaries.zip,distribution/*.zip" body: ${{ needs.prepare-notes.outputs.notes }} token: ${{ secrets.GITHUB_TOKEN }} diff --git a/README.md b/README.md index 5479149996..54602e24c5 100644 --- a/README.md +++ b/README.md @@ -140,7 +140,7 @@ ESPEasy_mega-20230822_max_ESP32s3_8M1M_LittleFS_OPI_PSRAM_CDC.bin | ESP32-S3 8MB ESPEasy_mega-20230822_max_ESP32_16M1M.bin | ESP32 with 16MB flash | All available plugins | ESPEasy_mega-20230822_max_ESP32_16M8M_LittleFS.bin | ESP32 with 16MB flash | All available plugins | -NB: Since 2023-05-10 the binary files for the different ESP32 variants (S2, C3, S3, 'Classic') are available in separate archives. +The binary files for the different ESP32 variants (S2, C3, S3, C2, C6, 'Classic') are available in separate archives. To see what plugins are included in which collection set, you can find that on the [ESPEasy Plugin overview page](https://espeasy.readthedocs.io/en/latest/Plugin/_Plugin.html) diff --git a/boards/esp32c6cdc-16M.json b/boards/esp32c6cdc-16M.json new file mode 100644 index 0000000000..efa16120c3 --- /dev/null +++ b/boards/esp32c6cdc-16M.json @@ -0,0 +1,40 @@ +{ + "build": { + "arduino":{ + "ldscript": "esp32c6_out.ld" + }, + "core": "esp32", + "extra_flags": "-DARDUINO_TASMOTA -DARDUINO_USB_MODE=1 -DUSE_USB_CDC_CONSOLE -DESP32_16M -DESP32C6 -DARDUINO_USB_CDC_ON_BOOT=1", + "f_cpu": "160000000L", + "f_flash": "80000000L", + "flash_mode": "qio", + "mcu": "esp32c6", + "variant": "esp32c6", + "partitions": "boards/partitions/esp32_partition_app4096k_spiffs8124k.csv" + }, + "connectivity": [ + "wifi", + "bluetooth" + ], + "debug": { + "default_tool": "esp-builtin", + "onboard_tools": [ + "esp-builtin" + ], + "openocd_target": "esp32c6.cfg" + }, + "frameworks": [ + "arduino", + "espidf" + ], + "name": "Espressif Generic ESP32-C6 16M Flash, ESPEasy 4096k Code/OTA 8M FS", + "upload": { + "flash_size": "16MB", + "maximum_ram_size": 327680, + "maximum_size": 16777216, + "require_upload_port": true, + "speed": 460800 + }, + "url": "https://docs.espressif.com/projects/espressif-esp-dev-kits/en/latest/esp32c6/esp32-c6-devkitc-1/index.html", + "vendor": "Espressif" + } diff --git a/boards/esp32c6cdc-8M.json b/boards/esp32c6cdc-8M.json new file mode 100644 index 0000000000..9bfc4e34c0 --- /dev/null +++ b/boards/esp32c6cdc-8M.json @@ -0,0 +1,40 @@ +{ + "build": { + "arduino":{ + "ldscript": "esp32c6_out.ld" + }, + "core": "esp32", + "extra_flags": "-DARDUINO_TASMOTA -DARDUINO_USB_MODE=1 -DUSE_USB_CDC_CONSOLE -DESP32_8M -DESP32C6 -DARDUINO_USB_CDC_ON_BOOT=1", + "f_cpu": "160000000L", + "f_flash": "80000000L", + "flash_mode": "qio", + "mcu": "esp32c6", + "variant": "esp32c6", + "partitions": "boards/partitions/esp32_partition_app3520k_spiffs1088k.csv" + }, + "connectivity": [ + "wifi", + "bluetooth" + ], + "debug": { + "default_tool": "esp-builtin", + "onboard_tools": [ + "esp-builtin" + ], + "openocd_target": "esp32c6.cfg" + }, + "frameworks": [ + "arduino", + "espidf" + ], + "name": "Espressif Generic ESP32-C6 >= 8M Flash, ESPEasy 3520k Code/OTA 1088k FS", + "upload": { + "flash_size": "8MB", + "maximum_ram_size": 327680, + "maximum_size": 8388608, + "require_upload_port": true, + "speed": 460800 + }, + "url": "https://docs.espressif.com/projects/espressif-esp-dev-kits/en/latest/esp32c6/esp32-c6-devkitc-1/index.html", + "vendor": "Espressif" + } diff --git a/dist/Release_notes.txt b/dist/Release_notes.txt index 8c24445237..94f29ea101 100644 --- a/dist/Release_notes.txt +++ b/dist/Release_notes.txt @@ -1,3 +1,94 @@ +------------------------------------------------- +Changes in release mega-20240414 (since mega-20240401) +------------------------------------------------- + +Release date: Sun Apr 14 03:08:46 PM CEST 2024 + +TD-er (16): + [HWCDC] Revert to older ESP-IDF/Arduino build + [Time] Fix updating %sunrise% and %sunset% when no NTP available + [HWCDC] Fix bootloop on ESP32-C3/C6 + [HWCDC] Cleanup unused test code + [ESP-IDF5.1] Move to newly network refactored code + [ESP-IDF5.x] Fix build issue + [ESP-IDF5.x] Fix building ESP32-solo1 builds + [Ethernet[ Fix crashes when using Ethernet + IPv6 on LittleFS builds + [Ethernet] Fix getting DNS from DHCP switch from WiFi to Ethernet + [ESP-IDF5.x] Fix LittleFS builds without Ethernet + [IMPROV] Fix provisioning WiFi via web flasher + [ESP-IDF5.1] Update to latest 2024.04.11 platform build + [SPI ETH] Fix SPI selection to actual SPI bus for Ethernet + [SPI Eth] Fix build on ESP32-C3 + [HWCDC] Tweak HWCDC to be more stable + [Build] Revert unintended change of default PIO env. + +Ton Huisman (2): + [Dist] Update Espressif Flash Download tool 3.9.6 + [JSON] Add extra data in `/json` output + + +------------------------------------------------- +Changes in release mega-20240401 (since mega-20240331) +------------------------------------------------- + +Release date: Mon Apr 1 12:13:54 AM CEST 2024 + +Ton Huisman (1): + [Bugfix] Release script fixes and simplifications + + +------------------------------------------------- +Changes in release mega-20240331 (since mega-20240229) +------------------------------------------------- + +Release date: Sun Mar 31 03:40:08 PM CEST 2024 + +Ernest (ErNis) (1): + INA219 26V 8A range added + +Jason2866 (1): + small refactor + +TD-er (13): + [JL1101] Fix JL1101 Ethernet + update to latest ESP-IDF5.1 code + [PlatformIO] Fix installing pygit2 + [ESP8266 WiFi] Initialize flags for AP capabilities + [ESP8266] Get rid of several union structs which may cause weird issues + [ESP8266] Remove use of union due to issues on ESP8266 + [ESP-IDF5.1] Revert to older SDK code due to issues with HWCDC + [Build] Reduce build size regarding WiFi AP Candidate duplicate code + [HWCDC] Test for ESP32-C3/C6/S3 HWCDC issues + [CUL Reader] Cherry pick code from ESPEasy_NOW pull request + [CUL Reader] Fix not being able to set flags + [Save Settings] Fix issue where data may get corrupted saving task + [Display] Reduce ESP8266 'display' build size + [MQTT] Fix crash and disconnect sending to MQTT using formula + +Ton Huisman (22): + [P087] Add serialproxy_test command and Get the parsed data + [P087] Fix typo + [P087] Documentation clarification + [P087] Apply log-string and code optimizations + [P087] Always process Global Match so values can be retrieved + [Bugfix] Release.yml shouldn't try to move a non-existing file + [Build] Add ESP32-C6 MAX builds (preliminary) + [Docs] Update ESP chip info + [Docs] Update ESP chip info + [P116] Add alternative model selections for ST7789 + [Bugfix] Remove duplicate define in Custom-sample.h + [Build] Custom IR ESP32 configurations not using the pre_custom_esp32_IR.py Python script + [P116] Add alternative model selection for ST7735 + [P029][C002] Add option Invert On/Off value + [Docs] Update P029 documentation with new option + [C002] Reduce .bin size (slightly) + [P116] Fine-tuning the rotation column-offset for ST7735 135x240 display + [P116] Documentation improvement. + [P095] Documentation improvement. + [P116] Update documentation for supported displays + [Build] Disable Notifiers in full binaries + [Build] Fix typo + + ------------------------------------------------- Changes in release mega-20240229 (since mega-20231225) ------------------------------------------------- diff --git a/dist/flash_download_tool_3.9.5/doc/Flash_Download_Tool__cn.pdf b/dist/flash_download_tool_3.9.5/doc/Flash_Download_Tool__cn.pdf deleted file mode 100644 index a8a19d7983..0000000000 Binary files a/dist/flash_download_tool_3.9.5/doc/Flash_Download_Tool__cn.pdf and /dev/null differ diff --git a/dist/flash_download_tool_3.9.6/configure/esp32/multi_download.conf b/dist/flash_download_tool_3.9.6/configure/esp32/multi_download.conf new file mode 100644 index 0000000000..2649596759 --- /dev/null +++ b/dist/flash_download_tool_3.9.6/configure/esp32/multi_download.conf @@ -0,0 +1,161 @@ +[EFUSE CHECK] +efuse_mode = 1 +efuse_err_halt = 1 + +[MULTI_UI_CONFIG] +multi_col = 2 + +[DOWNLOAD PATH] +file_sel0 = 0 +file_path0 = +file_flag0 = False +file_offset0 = +file_sel1 = 0 +file_path1 = +file_flag1 = False +file_offset1 = +file_sel2 = 0 +file_path2 = +file_flag2 = False +file_offset2 = +file_sel3 = 0 +file_path3 = +file_flag3 = False +file_offset3 = +file_sel4 = 0 +file_path4 = +file_flag4 = False +file_offset4 = +file_sel5 = 0 +file_path5 = +file_flag5 = False +file_offset5 = +file_sel6 = 0 +file_path6 = +file_flag6 = False +file_offset6 = +file_sel7 = 0 +file_path7 = +file_flag7 = False +file_offset7 = +file_sel8 = 0 +file_path8 = +file_flag8 = False +file_offset8 = +file_sel9 = 0 +file_path9 = +file_flag9 = False +file_offset9 = +file_sel10 = 0 +file_path10 = +file_flag10 = False +file_offset10 = +file_sel11 = 0 +file_path11 = +file_flag11 = False +file_offset11 = +file_sel12 = 0 +file_path12 = +file_flag12 = False +file_offset12 = +file_sel13 = 0 +file_path13 = +file_flag13 = False +file_offset13 = +default_path = ./bin/ + +[LOCK] +lock_setting_password = + +[FLASH_CRYSTAL] +spicfgdis = 1 +spispeed = 0 +spimode = 2 + +[DOWNLOAD] +erase_button_en = True +autostart1 = 0 +com_port1 = +baudrate1 = 0 +checkmac1 = 1 +autostart2 = 0 +com_port2 = +baudrate2 = 0 +checkmac2 = 1 +autostart3 = 0 +com_port3 = +baudrate3 = 0 +checkmac3 = 1 +autostart4 = 0 +com_port4 = +baudrate4 = 0 +checkmac4 = 1 +autostart5 = 0 +com_port5 = +baudrate5 = 0 +checkmac5 = 1 +autostart6 = 0 +com_port6 = +baudrate6 = 0 +checkmac6 = 1 +autostart7 = 0 +com_port7 = +baudrate7 = 0 +checkmac7 = 1 +autostart8 = 0 +com_port8 = +baudrate8 = 0 +checkmac8 = 1 +autostart9 = 0 +com_port9 = +baudrate9 = 0 +checkmac9 = 1 +autostart10 = 0 +com_port10 = +baudrate10 = 0 +checkmac10 = 1 + +[LOG_CHECK] +log_check_enable = False +log_check_baud = 115200 +log_check_str = 1.0.0 +log_check_delaytime = 3 +log_check_timeout = 3 +log_check_cmd_str = AT+GMR +log_check_enable_cmd = False + +[MAC_SAVE] +mac_save_enable = False + +[ESPTOOL_PARAM] +after = no_reset +before = default_reset +compress = True +flash_size = keep +no_stub = False +verify = True +flash_freq = keep +flash_mode = keep + +[STATISTICS] +pass1 = 0 +fail1 = 0 +pass2 = 0 +fail2 = 0 +pass3 = 0 +fail3 = 0 +pass4 = 0 +fail4 = 0 +pass5 = 0 +fail5 = 0 +pass6 = 0 +fail6 = 0 +pass7 = 0 +fail7 = 0 +pass8 = 0 +fail8 = 0 +pass9 = 0 +fail9 = 0 +pass10 = 0 +fail10 = 0 + diff --git a/dist/flash_download_tool_3.9.6/configure/esp32/security.conf b/dist/flash_download_tool_3.9.6/configure/esp32/security.conf new file mode 100644 index 0000000000..95bb20a11e --- /dev/null +++ b/dist/flash_download_tool_3.9.6/configure/esp32/security.conf @@ -0,0 +1,25 @@ +[SECURE BOOT] +secure_boot_en = False +secure_boot_version = 1 +public_key_digest_path = .\secure\public_key_digest.bin + +[FLASH ENCRYPTION] +flash_encryption_en = False +reserved_burn_times = 0 + +[SECURE OTHER CONFIG] +flash_encryption_use_customer_key_enable = False +flash_encryption_use_customer_key_path = .\secure\flash_encrypt_key.bin +flash_force_write_enable = False + +[FLASH ENCRYPTION KEYS LOCAL SAVE] +keys_save_enable = False +encrypt_keys_enable = False +encrypt_keys_aeskey_path = + +[ESP32 EFUSE BIT CONFIG] +jtag_disable = False +dl_encrypt_disable = False +dl_decrypt_disable = False +dl_cache_disable = False + diff --git a/dist/flash_download_tool_3.9.6/configure/esp32/spi_download.conf b/dist/flash_download_tool_3.9.6/configure/esp32/spi_download.conf new file mode 100644 index 0000000000..ebc596813d --- /dev/null +++ b/dist/flash_download_tool_3.9.6/configure/esp32/spi_download.conf @@ -0,0 +1,100 @@ +[EFUSE CHECK] +efuse_mode = 1 +efuse_err_halt = 1 + +[MULTI_UI_CONFIG] +multi_col = 2 + +[DOWNLOAD PATH] +file_sel0 = 0 +file_path0 = +file_flag0 = False +file_offset0 = +file_sel1 = 0 +file_path1 = +file_flag1 = False +file_offset1 = +file_sel2 = 0 +file_path2 = +file_flag2 = False +file_offset2 = +file_sel3 = 0 +file_path3 = +file_flag3 = False +file_offset3 = +file_sel4 = 0 +file_path4 = +file_flag4 = False +file_offset4 = +file_sel5 = 0 +file_path5 = +file_flag5 = False +file_offset5 = +file_sel6 = 0 +file_path6 = +file_flag6 = False +file_offset6 = +file_sel7 = 0 +file_path7 = +file_flag7 = False +file_offset7 = +file_sel8 = 0 +file_path8 = +file_flag8 = False +file_offset8 = +file_sel9 = 0 +file_path9 = +file_flag9 = False +file_offset9 = +file_sel10 = 0 +file_path10 = +file_flag10 = False +file_offset10 = +file_sel11 = 0 +file_path11 = +file_flag11 = False +file_offset11 = +file_sel12 = 0 +file_path12 = +file_flag12 = False +file_offset12 = +file_sel13 = 0 +file_path13 = +file_flag13 = False +file_offset13 = +default_path = D:\DOWNLOAD_TOOL\ÏÂÔع¤¾ß\release\3.9.6 + +[FLASH_CRYSTAL] +spicfgdis = 1 +spispeed = 0 +spimode = 2 + +[DOWNLOAD] +erase_button_en = True +autostart1 = 0 +com_port1 = +baudrate1 = 0 +checkmac1 = 1 + +[LOG_CHECK] +log_check_enable = False +log_check_baud = 115200 +log_check_str = 1.0.0 +log_check_delaytime = 3 +log_check_timeout = 3 +log_check_cmd_str = AT+GMR +log_check_enable_cmd = False + +[MAC_SAVE] +mac_save_enable = False + +[ESPTOOL_PARAM] +after = no_reset +before = default_reset +compress = True +flash_size = keep +no_stub = False +verify = True +flash_freq = keep +flash_mode = keep + diff --git a/dist/flash_download_tool_3.9.6/configure/esp32/utility.conf b/dist/flash_download_tool_3.9.6/configure/esp32/utility.conf new file mode 100644 index 0000000000..8f8e1facfc --- /dev/null +++ b/dist/flash_download_tool_3.9.6/configure/esp32/utility.conf @@ -0,0 +1,16 @@ +[LOG_LEVEL] +utility_log_level = ERROR +spi_log_level = ERROR +multi_log_level = ERROR + +[MAC_SAVE] +mac_save_enable = False + +[SECTOR_PROTECT] +sector_protect_enable = False +sector_protect_start = 0xe000 +sector_protect_end = 0x3000 + +[ESP32_EFUSE_CONFIG] +config_voltage = OFF + diff --git a/dist/flash_download_tool_3.9.6/configure/esp32c2/multi_download.conf b/dist/flash_download_tool_3.9.6/configure/esp32c2/multi_download.conf new file mode 100644 index 0000000000..2649596759 --- /dev/null +++ b/dist/flash_download_tool_3.9.6/configure/esp32c2/multi_download.conf @@ -0,0 +1,161 @@ +[EFUSE CHECK] +efuse_mode = 1 +efuse_err_halt = 1 + +[MULTI_UI_CONFIG] +multi_col = 2 + +[DOWNLOAD PATH] +file_sel0 = 0 +file_path0 = +file_flag0 = False +file_offset0 = +file_sel1 = 0 +file_path1 = +file_flag1 = False +file_offset1 = +file_sel2 = 0 +file_path2 = +file_flag2 = False +file_offset2 = +file_sel3 = 0 +file_path3 = +file_flag3 = False +file_offset3 = +file_sel4 = 0 +file_path4 = +file_flag4 = False +file_offset4 = +file_sel5 = 0 +file_path5 = +file_flag5 = False +file_offset5 = +file_sel6 = 0 +file_path6 = +file_flag6 = False +file_offset6 = +file_sel7 = 0 +file_path7 = +file_flag7 = False +file_offset7 = +file_sel8 = 0 +file_path8 = +file_flag8 = False +file_offset8 = +file_sel9 = 0 +file_path9 = +file_flag9 = False +file_offset9 = +file_sel10 = 0 +file_path10 = +file_flag10 = False +file_offset10 = +file_sel11 = 0 +file_path11 = +file_flag11 = False +file_offset11 = +file_sel12 = 0 +file_path12 = +file_flag12 = False +file_offset12 = +file_sel13 = 0 +file_path13 = +file_flag13 = False +file_offset13 = +default_path = ./bin/ + +[LOCK] +lock_setting_password = + +[FLASH_CRYSTAL] +spicfgdis = 1 +spispeed = 0 +spimode = 2 + +[DOWNLOAD] +erase_button_en = True +autostart1 = 0 +com_port1 = +baudrate1 = 0 +checkmac1 = 1 +autostart2 = 0 +com_port2 = +baudrate2 = 0 +checkmac2 = 1 +autostart3 = 0 +com_port3 = +baudrate3 = 0 +checkmac3 = 1 +autostart4 = 0 +com_port4 = +baudrate4 = 0 +checkmac4 = 1 +autostart5 = 0 +com_port5 = +baudrate5 = 0 +checkmac5 = 1 +autostart6 = 0 +com_port6 = +baudrate6 = 0 +checkmac6 = 1 +autostart7 = 0 +com_port7 = +baudrate7 = 0 +checkmac7 = 1 +autostart8 = 0 +com_port8 = +baudrate8 = 0 +checkmac8 = 1 +autostart9 = 0 +com_port9 = +baudrate9 = 0 +checkmac9 = 1 +autostart10 = 0 +com_port10 = +baudrate10 = 0 +checkmac10 = 1 + +[LOG_CHECK] +log_check_enable = False +log_check_baud = 115200 +log_check_str = 1.0.0 +log_check_delaytime = 3 +log_check_timeout = 3 +log_check_cmd_str = AT+GMR +log_check_enable_cmd = False + +[MAC_SAVE] +mac_save_enable = False + +[ESPTOOL_PARAM] +after = no_reset +before = default_reset +compress = True +flash_size = keep +no_stub = False +verify = True +flash_freq = keep +flash_mode = keep + +[STATISTICS] +pass1 = 0 +fail1 = 0 +pass2 = 0 +fail2 = 0 +pass3 = 0 +fail3 = 0 +pass4 = 0 +fail4 = 0 +pass5 = 0 +fail5 = 0 +pass6 = 0 +fail6 = 0 +pass7 = 0 +fail7 = 0 +pass8 = 0 +fail8 = 0 +pass9 = 0 +fail9 = 0 +pass10 = 0 +fail10 = 0 + diff --git a/dist/flash_download_tool_3.9.6/configure/esp32c2/security.conf b/dist/flash_download_tool_3.9.6/configure/esp32c2/security.conf new file mode 100644 index 0000000000..fd93e1068f --- /dev/null +++ b/dist/flash_download_tool_3.9.6/configure/esp32c2/security.conf @@ -0,0 +1,25 @@ +[SECURE BOOT] +secure_boot_en = False +public_key_digest_path = .\secure\public_key_digest.bin +public_key_digest_block_index = 0 + +[FLASH ENCRYPTION] +flash_encryption_en = False +reserved_burn_times = 0 +flash_encrypt_key_block_index = 0 + +[SECURE OTHER CONFIG] +flash_encryption_use_customer_key_enable = False +flash_encryption_use_customer_key_path = .\secure\flash_encrypt_key.bin +flash_force_write_enable = False + +[FLASH ENCRYPTION KEYS LOCAL SAVE] +keys_save_enable = False +encrypt_keys_enable = False +encrypt_keys_aeskey_path = + +[ESP32C* EFUSE BIT CONFIG] +dis_pad_jtag = False +dis_direct_boot = False +dis_download_icache = False + diff --git a/dist/flash_download_tool_3.9.6/configure/esp32c2/spi_download.conf b/dist/flash_download_tool_3.9.6/configure/esp32c2/spi_download.conf new file mode 100644 index 0000000000..ebc596813d --- /dev/null +++ b/dist/flash_download_tool_3.9.6/configure/esp32c2/spi_download.conf @@ -0,0 +1,100 @@ +[EFUSE CHECK] +efuse_mode = 1 +efuse_err_halt = 1 + +[MULTI_UI_CONFIG] +multi_col = 2 + +[DOWNLOAD PATH] +file_sel0 = 0 +file_path0 = +file_flag0 = False +file_offset0 = +file_sel1 = 0 +file_path1 = +file_flag1 = False +file_offset1 = +file_sel2 = 0 +file_path2 = +file_flag2 = False +file_offset2 = +file_sel3 = 0 +file_path3 = +file_flag3 = False +file_offset3 = +file_sel4 = 0 +file_path4 = +file_flag4 = False +file_offset4 = +file_sel5 = 0 +file_path5 = +file_flag5 = False +file_offset5 = +file_sel6 = 0 +file_path6 = +file_flag6 = False +file_offset6 = +file_sel7 = 0 +file_path7 = +file_flag7 = False +file_offset7 = +file_sel8 = 0 +file_path8 = +file_flag8 = False +file_offset8 = +file_sel9 = 0 +file_path9 = +file_flag9 = False +file_offset9 = +file_sel10 = 0 +file_path10 = +file_flag10 = False +file_offset10 = +file_sel11 = 0 +file_path11 = +file_flag11 = False +file_offset11 = +file_sel12 = 0 +file_path12 = +file_flag12 = False +file_offset12 = +file_sel13 = 0 +file_path13 = +file_flag13 = False +file_offset13 = +default_path = D:\DOWNLOAD_TOOL\ÏÂÔع¤¾ß\release\3.9.6 + +[FLASH_CRYSTAL] +spicfgdis = 1 +spispeed = 0 +spimode = 2 + +[DOWNLOAD] +erase_button_en = True +autostart1 = 0 +com_port1 = +baudrate1 = 0 +checkmac1 = 1 + +[LOG_CHECK] +log_check_enable = False +log_check_baud = 115200 +log_check_str = 1.0.0 +log_check_delaytime = 3 +log_check_timeout = 3 +log_check_cmd_str = AT+GMR +log_check_enable_cmd = False + +[MAC_SAVE] +mac_save_enable = False + +[ESPTOOL_PARAM] +after = no_reset +before = default_reset +compress = True +flash_size = keep +no_stub = False +verify = True +flash_freq = keep +flash_mode = keep + diff --git a/dist/flash_download_tool_3.9.6/configure/esp32c2/utility.conf b/dist/flash_download_tool_3.9.6/configure/esp32c2/utility.conf new file mode 100644 index 0000000000..8f8e1facfc --- /dev/null +++ b/dist/flash_download_tool_3.9.6/configure/esp32c2/utility.conf @@ -0,0 +1,16 @@ +[LOG_LEVEL] +utility_log_level = ERROR +spi_log_level = ERROR +multi_log_level = ERROR + +[MAC_SAVE] +mac_save_enable = False + +[SECTOR_PROTECT] +sector_protect_enable = False +sector_protect_start = 0xe000 +sector_protect_end = 0x3000 + +[ESP32_EFUSE_CONFIG] +config_voltage = OFF + diff --git a/dist/flash_download_tool_3.9.6/configure/esp32c3/multi_download.conf b/dist/flash_download_tool_3.9.6/configure/esp32c3/multi_download.conf new file mode 100644 index 0000000000..2649596759 --- /dev/null +++ b/dist/flash_download_tool_3.9.6/configure/esp32c3/multi_download.conf @@ -0,0 +1,161 @@ +[EFUSE CHECK] +efuse_mode = 1 +efuse_err_halt = 1 + +[MULTI_UI_CONFIG] +multi_col = 2 + +[DOWNLOAD PATH] +file_sel0 = 0 +file_path0 = +file_flag0 = False +file_offset0 = +file_sel1 = 0 +file_path1 = +file_flag1 = False +file_offset1 = +file_sel2 = 0 +file_path2 = +file_flag2 = False +file_offset2 = +file_sel3 = 0 +file_path3 = +file_flag3 = False +file_offset3 = +file_sel4 = 0 +file_path4 = +file_flag4 = False +file_offset4 = +file_sel5 = 0 +file_path5 = +file_flag5 = False +file_offset5 = +file_sel6 = 0 +file_path6 = +file_flag6 = False +file_offset6 = +file_sel7 = 0 +file_path7 = +file_flag7 = False +file_offset7 = +file_sel8 = 0 +file_path8 = +file_flag8 = False +file_offset8 = +file_sel9 = 0 +file_path9 = +file_flag9 = False +file_offset9 = +file_sel10 = 0 +file_path10 = +file_flag10 = False +file_offset10 = +file_sel11 = 0 +file_path11 = +file_flag11 = False +file_offset11 = +file_sel12 = 0 +file_path12 = +file_flag12 = False +file_offset12 = +file_sel13 = 0 +file_path13 = +file_flag13 = False +file_offset13 = +default_path = ./bin/ + +[LOCK] +lock_setting_password = + +[FLASH_CRYSTAL] +spicfgdis = 1 +spispeed = 0 +spimode = 2 + +[DOWNLOAD] +erase_button_en = True +autostart1 = 0 +com_port1 = +baudrate1 = 0 +checkmac1 = 1 +autostart2 = 0 +com_port2 = +baudrate2 = 0 +checkmac2 = 1 +autostart3 = 0 +com_port3 = +baudrate3 = 0 +checkmac3 = 1 +autostart4 = 0 +com_port4 = +baudrate4 = 0 +checkmac4 = 1 +autostart5 = 0 +com_port5 = +baudrate5 = 0 +checkmac5 = 1 +autostart6 = 0 +com_port6 = +baudrate6 = 0 +checkmac6 = 1 +autostart7 = 0 +com_port7 = +baudrate7 = 0 +checkmac7 = 1 +autostart8 = 0 +com_port8 = +baudrate8 = 0 +checkmac8 = 1 +autostart9 = 0 +com_port9 = +baudrate9 = 0 +checkmac9 = 1 +autostart10 = 0 +com_port10 = +baudrate10 = 0 +checkmac10 = 1 + +[LOG_CHECK] +log_check_enable = False +log_check_baud = 115200 +log_check_str = 1.0.0 +log_check_delaytime = 3 +log_check_timeout = 3 +log_check_cmd_str = AT+GMR +log_check_enable_cmd = False + +[MAC_SAVE] +mac_save_enable = False + +[ESPTOOL_PARAM] +after = no_reset +before = default_reset +compress = True +flash_size = keep +no_stub = False +verify = True +flash_freq = keep +flash_mode = keep + +[STATISTICS] +pass1 = 0 +fail1 = 0 +pass2 = 0 +fail2 = 0 +pass3 = 0 +fail3 = 0 +pass4 = 0 +fail4 = 0 +pass5 = 0 +fail5 = 0 +pass6 = 0 +fail6 = 0 +pass7 = 0 +fail7 = 0 +pass8 = 0 +fail8 = 0 +pass9 = 0 +fail9 = 0 +pass10 = 0 +fail10 = 0 + diff --git a/dist/flash_download_tool_3.9.6/configure/esp32c3/security.conf b/dist/flash_download_tool_3.9.6/configure/esp32c3/security.conf new file mode 100644 index 0000000000..b2a1f86c6c --- /dev/null +++ b/dist/flash_download_tool_3.9.6/configure/esp32c3/security.conf @@ -0,0 +1,27 @@ +[SECURE BOOT] +secure_boot_en = False +public_key_digest_path = .\secure\public_key_digest.bin +public_key_digest_block_index = 0 + +[FLASH ENCRYPTION] +flash_encryption_en = False +reserved_burn_times = 0 +flash_encrypt_key_block_index = 1 + +[SECURE OTHER CONFIG] +flash_encryption_use_customer_key_enable = False +flash_encryption_use_customer_key_path = .\secure\flash_encrypt_key.bin +flash_force_write_enable = False + +[FLASH ENCRYPTION KEYS LOCAL SAVE] +keys_save_enable = False +encrypt_keys_enable = False +encrypt_keys_aeskey_path = + +[ESP32C* EFUSE BIT CONFIG] +dis_usb_jtag = False +dis_pad_jtag = False +soft_dis_jtag = 7 +dis_direct_boot = False +dis_download_icache = False + diff --git a/dist/flash_download_tool_3.9.6/configure/esp32c3/spi_download.conf b/dist/flash_download_tool_3.9.6/configure/esp32c3/spi_download.conf new file mode 100644 index 0000000000..ebc596813d --- /dev/null +++ b/dist/flash_download_tool_3.9.6/configure/esp32c3/spi_download.conf @@ -0,0 +1,100 @@ +[EFUSE CHECK] +efuse_mode = 1 +efuse_err_halt = 1 + +[MULTI_UI_CONFIG] +multi_col = 2 + +[DOWNLOAD PATH] +file_sel0 = 0 +file_path0 = +file_flag0 = False +file_offset0 = +file_sel1 = 0 +file_path1 = +file_flag1 = False +file_offset1 = +file_sel2 = 0 +file_path2 = +file_flag2 = False +file_offset2 = +file_sel3 = 0 +file_path3 = +file_flag3 = False +file_offset3 = +file_sel4 = 0 +file_path4 = +file_flag4 = False +file_offset4 = +file_sel5 = 0 +file_path5 = +file_flag5 = False +file_offset5 = +file_sel6 = 0 +file_path6 = +file_flag6 = False +file_offset6 = +file_sel7 = 0 +file_path7 = +file_flag7 = False +file_offset7 = +file_sel8 = 0 +file_path8 = +file_flag8 = False +file_offset8 = +file_sel9 = 0 +file_path9 = +file_flag9 = False +file_offset9 = +file_sel10 = 0 +file_path10 = +file_flag10 = False +file_offset10 = +file_sel11 = 0 +file_path11 = +file_flag11 = False +file_offset11 = +file_sel12 = 0 +file_path12 = +file_flag12 = False +file_offset12 = +file_sel13 = 0 +file_path13 = +file_flag13 = False +file_offset13 = +default_path = D:\DOWNLOAD_TOOL\ÏÂÔع¤¾ß\release\3.9.6 + +[FLASH_CRYSTAL] +spicfgdis = 1 +spispeed = 0 +spimode = 2 + +[DOWNLOAD] +erase_button_en = True +autostart1 = 0 +com_port1 = +baudrate1 = 0 +checkmac1 = 1 + +[LOG_CHECK] +log_check_enable = False +log_check_baud = 115200 +log_check_str = 1.0.0 +log_check_delaytime = 3 +log_check_timeout = 3 +log_check_cmd_str = AT+GMR +log_check_enable_cmd = False + +[MAC_SAVE] +mac_save_enable = False + +[ESPTOOL_PARAM] +after = no_reset +before = default_reset +compress = True +flash_size = keep +no_stub = False +verify = True +flash_freq = keep +flash_mode = keep + diff --git a/dist/flash_download_tool_3.9.6/configure/esp32c3/utility.conf b/dist/flash_download_tool_3.9.6/configure/esp32c3/utility.conf new file mode 100644 index 0000000000..8f8e1facfc --- /dev/null +++ b/dist/flash_download_tool_3.9.6/configure/esp32c3/utility.conf @@ -0,0 +1,16 @@ +[LOG_LEVEL] +utility_log_level = ERROR +spi_log_level = ERROR +multi_log_level = ERROR + +[MAC_SAVE] +mac_save_enable = False + +[SECTOR_PROTECT] +sector_protect_enable = False +sector_protect_start = 0xe000 +sector_protect_end = 0x3000 + +[ESP32_EFUSE_CONFIG] +config_voltage = OFF + diff --git a/dist/flash_download_tool_3.9.6/configure/esp32c6/multi_download.conf b/dist/flash_download_tool_3.9.6/configure/esp32c6/multi_download.conf new file mode 100644 index 0000000000..2649596759 --- /dev/null +++ b/dist/flash_download_tool_3.9.6/configure/esp32c6/multi_download.conf @@ -0,0 +1,161 @@ +[EFUSE CHECK] +efuse_mode = 1 +efuse_err_halt = 1 + +[MULTI_UI_CONFIG] +multi_col = 2 + +[DOWNLOAD PATH] +file_sel0 = 0 +file_path0 = +file_flag0 = False +file_offset0 = +file_sel1 = 0 +file_path1 = +file_flag1 = False +file_offset1 = +file_sel2 = 0 +file_path2 = +file_flag2 = False +file_offset2 = +file_sel3 = 0 +file_path3 = +file_flag3 = False +file_offset3 = +file_sel4 = 0 +file_path4 = +file_flag4 = False +file_offset4 = +file_sel5 = 0 +file_path5 = +file_flag5 = False +file_offset5 = +file_sel6 = 0 +file_path6 = +file_flag6 = False +file_offset6 = +file_sel7 = 0 +file_path7 = +file_flag7 = False +file_offset7 = +file_sel8 = 0 +file_path8 = +file_flag8 = False +file_offset8 = +file_sel9 = 0 +file_path9 = +file_flag9 = False +file_offset9 = +file_sel10 = 0 +file_path10 = +file_flag10 = False +file_offset10 = +file_sel11 = 0 +file_path11 = +file_flag11 = False +file_offset11 = +file_sel12 = 0 +file_path12 = +file_flag12 = False +file_offset12 = +file_sel13 = 0 +file_path13 = +file_flag13 = False +file_offset13 = +default_path = ./bin/ + +[LOCK] +lock_setting_password = + +[FLASH_CRYSTAL] +spicfgdis = 1 +spispeed = 0 +spimode = 2 + +[DOWNLOAD] +erase_button_en = True +autostart1 = 0 +com_port1 = +baudrate1 = 0 +checkmac1 = 1 +autostart2 = 0 +com_port2 = +baudrate2 = 0 +checkmac2 = 1 +autostart3 = 0 +com_port3 = +baudrate3 = 0 +checkmac3 = 1 +autostart4 = 0 +com_port4 = +baudrate4 = 0 +checkmac4 = 1 +autostart5 = 0 +com_port5 = +baudrate5 = 0 +checkmac5 = 1 +autostart6 = 0 +com_port6 = +baudrate6 = 0 +checkmac6 = 1 +autostart7 = 0 +com_port7 = +baudrate7 = 0 +checkmac7 = 1 +autostart8 = 0 +com_port8 = +baudrate8 = 0 +checkmac8 = 1 +autostart9 = 0 +com_port9 = +baudrate9 = 0 +checkmac9 = 1 +autostart10 = 0 +com_port10 = +baudrate10 = 0 +checkmac10 = 1 + +[LOG_CHECK] +log_check_enable = False +log_check_baud = 115200 +log_check_str = 1.0.0 +log_check_delaytime = 3 +log_check_timeout = 3 +log_check_cmd_str = AT+GMR +log_check_enable_cmd = False + +[MAC_SAVE] +mac_save_enable = False + +[ESPTOOL_PARAM] +after = no_reset +before = default_reset +compress = True +flash_size = keep +no_stub = False +verify = True +flash_freq = keep +flash_mode = keep + +[STATISTICS] +pass1 = 0 +fail1 = 0 +pass2 = 0 +fail2 = 0 +pass3 = 0 +fail3 = 0 +pass4 = 0 +fail4 = 0 +pass5 = 0 +fail5 = 0 +pass6 = 0 +fail6 = 0 +pass7 = 0 +fail7 = 0 +pass8 = 0 +fail8 = 0 +pass9 = 0 +fail9 = 0 +pass10 = 0 +fail10 = 0 + diff --git a/dist/flash_download_tool_3.9.6/configure/esp32c6/security.conf b/dist/flash_download_tool_3.9.6/configure/esp32c6/security.conf new file mode 100644 index 0000000000..b2a1f86c6c --- /dev/null +++ b/dist/flash_download_tool_3.9.6/configure/esp32c6/security.conf @@ -0,0 +1,27 @@ +[SECURE BOOT] +secure_boot_en = False +public_key_digest_path = .\secure\public_key_digest.bin +public_key_digest_block_index = 0 + +[FLASH ENCRYPTION] +flash_encryption_en = False +reserved_burn_times = 0 +flash_encrypt_key_block_index = 1 + +[SECURE OTHER CONFIG] +flash_encryption_use_customer_key_enable = False +flash_encryption_use_customer_key_path = .\secure\flash_encrypt_key.bin +flash_force_write_enable = False + +[FLASH ENCRYPTION KEYS LOCAL SAVE] +keys_save_enable = False +encrypt_keys_enable = False +encrypt_keys_aeskey_path = + +[ESP32C* EFUSE BIT CONFIG] +dis_usb_jtag = False +dis_pad_jtag = False +soft_dis_jtag = 7 +dis_direct_boot = False +dis_download_icache = False + diff --git a/dist/flash_download_tool_3.9.6/configure/esp32c6/spi_download.conf b/dist/flash_download_tool_3.9.6/configure/esp32c6/spi_download.conf new file mode 100644 index 0000000000..ebc596813d --- /dev/null +++ b/dist/flash_download_tool_3.9.6/configure/esp32c6/spi_download.conf @@ -0,0 +1,100 @@ +[EFUSE CHECK] +efuse_mode = 1 +efuse_err_halt = 1 + +[MULTI_UI_CONFIG] +multi_col = 2 + +[DOWNLOAD PATH] +file_sel0 = 0 +file_path0 = +file_flag0 = False +file_offset0 = +file_sel1 = 0 +file_path1 = +file_flag1 = False +file_offset1 = +file_sel2 = 0 +file_path2 = +file_flag2 = False +file_offset2 = +file_sel3 = 0 +file_path3 = +file_flag3 = False +file_offset3 = +file_sel4 = 0 +file_path4 = +file_flag4 = False +file_offset4 = +file_sel5 = 0 +file_path5 = +file_flag5 = False +file_offset5 = +file_sel6 = 0 +file_path6 = +file_flag6 = False +file_offset6 = +file_sel7 = 0 +file_path7 = +file_flag7 = False +file_offset7 = +file_sel8 = 0 +file_path8 = +file_flag8 = False +file_offset8 = +file_sel9 = 0 +file_path9 = +file_flag9 = False +file_offset9 = +file_sel10 = 0 +file_path10 = +file_flag10 = False +file_offset10 = +file_sel11 = 0 +file_path11 = +file_flag11 = False +file_offset11 = +file_sel12 = 0 +file_path12 = +file_flag12 = False +file_offset12 = +file_sel13 = 0 +file_path13 = +file_flag13 = False +file_offset13 = +default_path = D:\DOWNLOAD_TOOL\ÏÂÔع¤¾ß\release\3.9.6 + +[FLASH_CRYSTAL] +spicfgdis = 1 +spispeed = 0 +spimode = 2 + +[DOWNLOAD] +erase_button_en = True +autostart1 = 0 +com_port1 = +baudrate1 = 0 +checkmac1 = 1 + +[LOG_CHECK] +log_check_enable = False +log_check_baud = 115200 +log_check_str = 1.0.0 +log_check_delaytime = 3 +log_check_timeout = 3 +log_check_cmd_str = AT+GMR +log_check_enable_cmd = False + +[MAC_SAVE] +mac_save_enable = False + +[ESPTOOL_PARAM] +after = no_reset +before = default_reset +compress = True +flash_size = keep +no_stub = False +verify = True +flash_freq = keep +flash_mode = keep + diff --git a/dist/flash_download_tool_3.9.6/configure/esp32c6/utility.conf b/dist/flash_download_tool_3.9.6/configure/esp32c6/utility.conf new file mode 100644 index 0000000000..8f8e1facfc --- /dev/null +++ b/dist/flash_download_tool_3.9.6/configure/esp32c6/utility.conf @@ -0,0 +1,16 @@ +[LOG_LEVEL] +utility_log_level = ERROR +spi_log_level = ERROR +multi_log_level = ERROR + +[MAC_SAVE] +mac_save_enable = False + +[SECTOR_PROTECT] +sector_protect_enable = False +sector_protect_start = 0xe000 +sector_protect_end = 0x3000 + +[ESP32_EFUSE_CONFIG] +config_voltage = OFF + diff --git a/dist/flash_download_tool_3.9.6/configure/esp32h2/multi_download.conf b/dist/flash_download_tool_3.9.6/configure/esp32h2/multi_download.conf new file mode 100644 index 0000000000..2649596759 --- /dev/null +++ b/dist/flash_download_tool_3.9.6/configure/esp32h2/multi_download.conf @@ -0,0 +1,161 @@ +[EFUSE CHECK] +efuse_mode = 1 +efuse_err_halt = 1 + +[MULTI_UI_CONFIG] +multi_col = 2 + +[DOWNLOAD PATH] +file_sel0 = 0 +file_path0 = +file_flag0 = False +file_offset0 = +file_sel1 = 0 +file_path1 = +file_flag1 = False +file_offset1 = +file_sel2 = 0 +file_path2 = +file_flag2 = False +file_offset2 = +file_sel3 = 0 +file_path3 = +file_flag3 = False +file_offset3 = +file_sel4 = 0 +file_path4 = +file_flag4 = False +file_offset4 = +file_sel5 = 0 +file_path5 = +file_flag5 = False +file_offset5 = +file_sel6 = 0 +file_path6 = +file_flag6 = False +file_offset6 = +file_sel7 = 0 +file_path7 = +file_flag7 = False +file_offset7 = +file_sel8 = 0 +file_path8 = +file_flag8 = False +file_offset8 = +file_sel9 = 0 +file_path9 = +file_flag9 = False +file_offset9 = +file_sel10 = 0 +file_path10 = +file_flag10 = False +file_offset10 = +file_sel11 = 0 +file_path11 = +file_flag11 = False +file_offset11 = +file_sel12 = 0 +file_path12 = +file_flag12 = False +file_offset12 = +file_sel13 = 0 +file_path13 = +file_flag13 = False +file_offset13 = +default_path = ./bin/ + +[LOCK] +lock_setting_password = + +[FLASH_CRYSTAL] +spicfgdis = 1 +spispeed = 0 +spimode = 2 + +[DOWNLOAD] +erase_button_en = True +autostart1 = 0 +com_port1 = +baudrate1 = 0 +checkmac1 = 1 +autostart2 = 0 +com_port2 = +baudrate2 = 0 +checkmac2 = 1 +autostart3 = 0 +com_port3 = +baudrate3 = 0 +checkmac3 = 1 +autostart4 = 0 +com_port4 = +baudrate4 = 0 +checkmac4 = 1 +autostart5 = 0 +com_port5 = +baudrate5 = 0 +checkmac5 = 1 +autostart6 = 0 +com_port6 = +baudrate6 = 0 +checkmac6 = 1 +autostart7 = 0 +com_port7 = +baudrate7 = 0 +checkmac7 = 1 +autostart8 = 0 +com_port8 = +baudrate8 = 0 +checkmac8 = 1 +autostart9 = 0 +com_port9 = +baudrate9 = 0 +checkmac9 = 1 +autostart10 = 0 +com_port10 = +baudrate10 = 0 +checkmac10 = 1 + +[LOG_CHECK] +log_check_enable = False +log_check_baud = 115200 +log_check_str = 1.0.0 +log_check_delaytime = 3 +log_check_timeout = 3 +log_check_cmd_str = AT+GMR +log_check_enable_cmd = False + +[MAC_SAVE] +mac_save_enable = False + +[ESPTOOL_PARAM] +after = no_reset +before = default_reset +compress = True +flash_size = keep +no_stub = False +verify = True +flash_freq = keep +flash_mode = keep + +[STATISTICS] +pass1 = 0 +fail1 = 0 +pass2 = 0 +fail2 = 0 +pass3 = 0 +fail3 = 0 +pass4 = 0 +fail4 = 0 +pass5 = 0 +fail5 = 0 +pass6 = 0 +fail6 = 0 +pass7 = 0 +fail7 = 0 +pass8 = 0 +fail8 = 0 +pass9 = 0 +fail9 = 0 +pass10 = 0 +fail10 = 0 + diff --git a/dist/flash_download_tool_3.9.6/configure/esp32h2/security.conf b/dist/flash_download_tool_3.9.6/configure/esp32h2/security.conf new file mode 100644 index 0000000000..d1070b7d85 --- /dev/null +++ b/dist/flash_download_tool_3.9.6/configure/esp32h2/security.conf @@ -0,0 +1,26 @@ +[SECURE BOOT] +secure_boot_en = False +public_key_digest_path = .\secure\public_key_digest.bin +public_key_digest_block_index = 0 + +[FLASH ENCRYPTION] +flash_encryption_en = False +reserved_burn_times = 0 +flash_encrypt_key_block_index = 1 + +[SECURE OTHER CONFIG] +flash_encryption_use_customer_key_enable = False +flash_encryption_use_customer_key_path = .\secure\flash_encrypt_key.bin +flash_force_write_enable = False + +[FLASH ENCRYPTION KEYS LOCAL SAVE] +keys_save_enable = False +encrypt_keys_enable = False +encrypt_keys_aeskey_path = + +[ESP32H2 EFUSE BIT CONFIG] +dis_direct_boot = False +soft_dis_jtag = False +dis_pad_jtag = False +dis_usb_jtag = False + diff --git a/dist/flash_download_tool_3.9.6/configure/esp32h2/spi_download.conf b/dist/flash_download_tool_3.9.6/configure/esp32h2/spi_download.conf new file mode 100644 index 0000000000..ebc596813d --- /dev/null +++ b/dist/flash_download_tool_3.9.6/configure/esp32h2/spi_download.conf @@ -0,0 +1,100 @@ +[EFUSE CHECK] +efuse_mode = 1 +efuse_err_halt = 1 + +[MULTI_UI_CONFIG] +multi_col = 2 + +[DOWNLOAD PATH] +file_sel0 = 0 +file_path0 = +file_flag0 = False +file_offset0 = +file_sel1 = 0 +file_path1 = +file_flag1 = False +file_offset1 = +file_sel2 = 0 +file_path2 = +file_flag2 = False +file_offset2 = +file_sel3 = 0 +file_path3 = +file_flag3 = False +file_offset3 = +file_sel4 = 0 +file_path4 = +file_flag4 = False +file_offset4 = +file_sel5 = 0 +file_path5 = +file_flag5 = False +file_offset5 = +file_sel6 = 0 +file_path6 = +file_flag6 = False +file_offset6 = +file_sel7 = 0 +file_path7 = +file_flag7 = False +file_offset7 = +file_sel8 = 0 +file_path8 = +file_flag8 = False +file_offset8 = +file_sel9 = 0 +file_path9 = +file_flag9 = False +file_offset9 = +file_sel10 = 0 +file_path10 = +file_flag10 = False +file_offset10 = +file_sel11 = 0 +file_path11 = +file_flag11 = False +file_offset11 = +file_sel12 = 0 +file_path12 = +file_flag12 = False +file_offset12 = +file_sel13 = 0 +file_path13 = +file_flag13 = False +file_offset13 = +default_path = D:\DOWNLOAD_TOOL\ÏÂÔع¤¾ß\release\3.9.6 + +[FLASH_CRYSTAL] +spicfgdis = 1 +spispeed = 0 +spimode = 2 + +[DOWNLOAD] +erase_button_en = True +autostart1 = 0 +com_port1 = +baudrate1 = 0 +checkmac1 = 1 + +[LOG_CHECK] +log_check_enable = False +log_check_baud = 115200 +log_check_str = 1.0.0 +log_check_delaytime = 3 +log_check_timeout = 3 +log_check_cmd_str = AT+GMR +log_check_enable_cmd = False + +[MAC_SAVE] +mac_save_enable = False + +[ESPTOOL_PARAM] +after = no_reset +before = default_reset +compress = True +flash_size = keep +no_stub = False +verify = True +flash_freq = keep +flash_mode = keep + diff --git a/dist/flash_download_tool_3.9.6/configure/esp32h2/utility.conf b/dist/flash_download_tool_3.9.6/configure/esp32h2/utility.conf new file mode 100644 index 0000000000..8f8e1facfc --- /dev/null +++ b/dist/flash_download_tool_3.9.6/configure/esp32h2/utility.conf @@ -0,0 +1,16 @@ +[LOG_LEVEL] +utility_log_level = ERROR +spi_log_level = ERROR +multi_log_level = ERROR + +[MAC_SAVE] +mac_save_enable = False + +[SECTOR_PROTECT] +sector_protect_enable = False +sector_protect_start = 0xe000 +sector_protect_end = 0x3000 + +[ESP32_EFUSE_CONFIG] +config_voltage = OFF + diff --git a/dist/flash_download_tool_3.9.6/configure/esp32s2/multi_download.conf b/dist/flash_download_tool_3.9.6/configure/esp32s2/multi_download.conf new file mode 100644 index 0000000000..2649596759 --- /dev/null +++ b/dist/flash_download_tool_3.9.6/configure/esp32s2/multi_download.conf @@ -0,0 +1,161 @@ +[EFUSE CHECK] +efuse_mode = 1 +efuse_err_halt = 1 + +[MULTI_UI_CONFIG] +multi_col = 2 + +[DOWNLOAD PATH] +file_sel0 = 0 +file_path0 = +file_flag0 = False +file_offset0 = +file_sel1 = 0 +file_path1 = +file_flag1 = False +file_offset1 = +file_sel2 = 0 +file_path2 = +file_flag2 = False +file_offset2 = +file_sel3 = 0 +file_path3 = +file_flag3 = False +file_offset3 = +file_sel4 = 0 +file_path4 = +file_flag4 = False +file_offset4 = +file_sel5 = 0 +file_path5 = +file_flag5 = False +file_offset5 = +file_sel6 = 0 +file_path6 = +file_flag6 = False +file_offset6 = +file_sel7 = 0 +file_path7 = +file_flag7 = False +file_offset7 = +file_sel8 = 0 +file_path8 = +file_flag8 = False +file_offset8 = +file_sel9 = 0 +file_path9 = +file_flag9 = False +file_offset9 = +file_sel10 = 0 +file_path10 = +file_flag10 = False +file_offset10 = +file_sel11 = 0 +file_path11 = +file_flag11 = False +file_offset11 = +file_sel12 = 0 +file_path12 = +file_flag12 = False +file_offset12 = +file_sel13 = 0 +file_path13 = +file_flag13 = False +file_offset13 = +default_path = ./bin/ + +[LOCK] +lock_setting_password = + +[FLASH_CRYSTAL] +spicfgdis = 1 +spispeed = 0 +spimode = 2 + +[DOWNLOAD] +erase_button_en = True +autostart1 = 0 +com_port1 = +baudrate1 = 0 +checkmac1 = 1 +autostart2 = 0 +com_port2 = +baudrate2 = 0 +checkmac2 = 1 +autostart3 = 0 +com_port3 = +baudrate3 = 0 +checkmac3 = 1 +autostart4 = 0 +com_port4 = +baudrate4 = 0 +checkmac4 = 1 +autostart5 = 0 +com_port5 = +baudrate5 = 0 +checkmac5 = 1 +autostart6 = 0 +com_port6 = +baudrate6 = 0 +checkmac6 = 1 +autostart7 = 0 +com_port7 = +baudrate7 = 0 +checkmac7 = 1 +autostart8 = 0 +com_port8 = +baudrate8 = 0 +checkmac8 = 1 +autostart9 = 0 +com_port9 = +baudrate9 = 0 +checkmac9 = 1 +autostart10 = 0 +com_port10 = +baudrate10 = 0 +checkmac10 = 1 + +[LOG_CHECK] +log_check_enable = False +log_check_baud = 115200 +log_check_str = 1.0.0 +log_check_delaytime = 3 +log_check_timeout = 3 +log_check_cmd_str = AT+GMR +log_check_enable_cmd = False + +[MAC_SAVE] +mac_save_enable = False + +[ESPTOOL_PARAM] +after = no_reset +before = default_reset +compress = True +flash_size = keep +no_stub = False +verify = True +flash_freq = keep +flash_mode = keep + +[STATISTICS] +pass1 = 0 +fail1 = 0 +pass2 = 0 +fail2 = 0 +pass3 = 0 +fail3 = 0 +pass4 = 0 +fail4 = 0 +pass5 = 0 +fail5 = 0 +pass6 = 0 +fail6 = 0 +pass7 = 0 +fail7 = 0 +pass8 = 0 +fail8 = 0 +pass9 = 0 +fail9 = 0 +pass10 = 0 +fail10 = 0 + diff --git a/dist/flash_download_tool_3.9.6/configure/esp32s2/security.conf b/dist/flash_download_tool_3.9.6/configure/esp32s2/security.conf new file mode 100644 index 0000000000..1b934d45f2 --- /dev/null +++ b/dist/flash_download_tool_3.9.6/configure/esp32s2/security.conf @@ -0,0 +1,28 @@ +[SECURE BOOT] +secure_boot_en = False +public_key_digest_path = .\secure\public_key_digest.bin +public_key_digest_block_index = 0 + +[FLASH ENCRYPTION] +flash_encryption_en = False +reserved_burn_times = 0 +flash_encrypt_key_block_index = 1 + +[SECURE OTHER CONFIG] +flash_encryption_use_customer_key_enable = False +flash_encryption_use_customer_key_path = .\secure\flash_encrypt_key.bin +flash_force_write_enable = False + +[FLASH ENCRYPTION KEYS LOCAL SAVE] +keys_save_enable = False +encrypt_keys_enable = False +encrypt_keys_aeskey_path = + +[ESP32S2 EFUSE BIT CONFIG] +hard_dis_jtag = False +soft_dis_jtag = False +dis_legacy_spi_boot = False +dis_boot_remap = False +dis_download_icache = False +dis_download_dcache = False + diff --git a/dist/flash_download_tool_3.9.6/configure/esp32s2/spi_download.conf b/dist/flash_download_tool_3.9.6/configure/esp32s2/spi_download.conf new file mode 100644 index 0000000000..ebc596813d --- /dev/null +++ b/dist/flash_download_tool_3.9.6/configure/esp32s2/spi_download.conf @@ -0,0 +1,100 @@ +[EFUSE CHECK] +efuse_mode = 1 +efuse_err_halt = 1 + +[MULTI_UI_CONFIG] +multi_col = 2 + +[DOWNLOAD PATH] +file_sel0 = 0 +file_path0 = +file_flag0 = False +file_offset0 = +file_sel1 = 0 +file_path1 = +file_flag1 = False +file_offset1 = +file_sel2 = 0 +file_path2 = +file_flag2 = False +file_offset2 = +file_sel3 = 0 +file_path3 = +file_flag3 = False +file_offset3 = +file_sel4 = 0 +file_path4 = +file_flag4 = False +file_offset4 = +file_sel5 = 0 +file_path5 = +file_flag5 = False +file_offset5 = +file_sel6 = 0 +file_path6 = +file_flag6 = False +file_offset6 = +file_sel7 = 0 +file_path7 = +file_flag7 = False +file_offset7 = +file_sel8 = 0 +file_path8 = +file_flag8 = False +file_offset8 = +file_sel9 = 0 +file_path9 = +file_flag9 = False +file_offset9 = +file_sel10 = 0 +file_path10 = +file_flag10 = False +file_offset10 = +file_sel11 = 0 +file_path11 = +file_flag11 = False +file_offset11 = +file_sel12 = 0 +file_path12 = +file_flag12 = False +file_offset12 = +file_sel13 = 0 +file_path13 = +file_flag13 = False +file_offset13 = +default_path = D:\DOWNLOAD_TOOL\ÏÂÔع¤¾ß\release\3.9.6 + +[FLASH_CRYSTAL] +spicfgdis = 1 +spispeed = 0 +spimode = 2 + +[DOWNLOAD] +erase_button_en = True +autostart1 = 0 +com_port1 = +baudrate1 = 0 +checkmac1 = 1 + +[LOG_CHECK] +log_check_enable = False +log_check_baud = 115200 +log_check_str = 1.0.0 +log_check_delaytime = 3 +log_check_timeout = 3 +log_check_cmd_str = AT+GMR +log_check_enable_cmd = False + +[MAC_SAVE] +mac_save_enable = False + +[ESPTOOL_PARAM] +after = no_reset +before = default_reset +compress = True +flash_size = keep +no_stub = False +verify = True +flash_freq = keep +flash_mode = keep + diff --git a/dist/flash_download_tool_3.9.6/configure/esp32s2/utility.conf b/dist/flash_download_tool_3.9.6/configure/esp32s2/utility.conf new file mode 100644 index 0000000000..8f8e1facfc --- /dev/null +++ b/dist/flash_download_tool_3.9.6/configure/esp32s2/utility.conf @@ -0,0 +1,16 @@ +[LOG_LEVEL] +utility_log_level = ERROR +spi_log_level = ERROR +multi_log_level = ERROR + +[MAC_SAVE] +mac_save_enable = False + +[SECTOR_PROTECT] +sector_protect_enable = False +sector_protect_start = 0xe000 +sector_protect_end = 0x3000 + +[ESP32_EFUSE_CONFIG] +config_voltage = OFF + diff --git a/dist/flash_download_tool_3.9.6/configure/esp32s3/multi_download.conf b/dist/flash_download_tool_3.9.6/configure/esp32s3/multi_download.conf new file mode 100644 index 0000000000..2649596759 --- /dev/null +++ b/dist/flash_download_tool_3.9.6/configure/esp32s3/multi_download.conf @@ -0,0 +1,161 @@ +[EFUSE CHECK] +efuse_mode = 1 +efuse_err_halt = 1 + +[MULTI_UI_CONFIG] +multi_col = 2 + +[DOWNLOAD PATH] +file_sel0 = 0 +file_path0 = +file_flag0 = False +file_offset0 = +file_sel1 = 0 +file_path1 = +file_flag1 = False +file_offset1 = +file_sel2 = 0 +file_path2 = +file_flag2 = False +file_offset2 = +file_sel3 = 0 +file_path3 = +file_flag3 = False +file_offset3 = +file_sel4 = 0 +file_path4 = +file_flag4 = False +file_offset4 = +file_sel5 = 0 +file_path5 = +file_flag5 = False +file_offset5 = +file_sel6 = 0 +file_path6 = +file_flag6 = False +file_offset6 = +file_sel7 = 0 +file_path7 = +file_flag7 = False +file_offset7 = +file_sel8 = 0 +file_path8 = +file_flag8 = False +file_offset8 = +file_sel9 = 0 +file_path9 = +file_flag9 = False +file_offset9 = +file_sel10 = 0 +file_path10 = +file_flag10 = False +file_offset10 = +file_sel11 = 0 +file_path11 = +file_flag11 = False +file_offset11 = +file_sel12 = 0 +file_path12 = +file_flag12 = False +file_offset12 = +file_sel13 = 0 +file_path13 = +file_flag13 = False +file_offset13 = +default_path = ./bin/ + +[LOCK] +lock_setting_password = + +[FLASH_CRYSTAL] +spicfgdis = 1 +spispeed = 0 +spimode = 2 + +[DOWNLOAD] +erase_button_en = True +autostart1 = 0 +com_port1 = +baudrate1 = 0 +checkmac1 = 1 +autostart2 = 0 +com_port2 = +baudrate2 = 0 +checkmac2 = 1 +autostart3 = 0 +com_port3 = +baudrate3 = 0 +checkmac3 = 1 +autostart4 = 0 +com_port4 = +baudrate4 = 0 +checkmac4 = 1 +autostart5 = 0 +com_port5 = +baudrate5 = 0 +checkmac5 = 1 +autostart6 = 0 +com_port6 = +baudrate6 = 0 +checkmac6 = 1 +autostart7 = 0 +com_port7 = +baudrate7 = 0 +checkmac7 = 1 +autostart8 = 0 +com_port8 = +baudrate8 = 0 +checkmac8 = 1 +autostart9 = 0 +com_port9 = +baudrate9 = 0 +checkmac9 = 1 +autostart10 = 0 +com_port10 = +baudrate10 = 0 +checkmac10 = 1 + +[LOG_CHECK] +log_check_enable = False +log_check_baud = 115200 +log_check_str = 1.0.0 +log_check_delaytime = 3 +log_check_timeout = 3 +log_check_cmd_str = AT+GMR +log_check_enable_cmd = False + +[MAC_SAVE] +mac_save_enable = False + +[ESPTOOL_PARAM] +after = no_reset +before = default_reset +compress = True +flash_size = keep +no_stub = False +verify = True +flash_freq = keep +flash_mode = keep + +[STATISTICS] +pass1 = 0 +fail1 = 0 +pass2 = 0 +fail2 = 0 +pass3 = 0 +fail3 = 0 +pass4 = 0 +fail4 = 0 +pass5 = 0 +fail5 = 0 +pass6 = 0 +fail6 = 0 +pass7 = 0 +fail7 = 0 +pass8 = 0 +fail8 = 0 +pass9 = 0 +fail9 = 0 +pass10 = 0 +fail10 = 0 + diff --git a/dist/flash_download_tool_3.9.6/configure/esp32s3/security.conf b/dist/flash_download_tool_3.9.6/configure/esp32s3/security.conf new file mode 100644 index 0000000000..acc04f562d --- /dev/null +++ b/dist/flash_download_tool_3.9.6/configure/esp32s3/security.conf @@ -0,0 +1,29 @@ +[SECURE BOOT] +secure_boot_en = False +public_key_digest_path = .\secure\public_key_digest.bin +public_key_digest_block_index = 0 + +[FLASH ENCRYPTION] +flash_encryption_en = False +reserved_burn_times = 0 +flash_encrypt_key_block_index = 1 + +[SECURE OTHER CONFIG] +flash_encryption_use_customer_key_enable = False +flash_encryption_use_customer_key_path = .\secure\flash_encrypt_key.bin +flash_force_write_enable = False + +[FLASH ENCRYPTION KEYS LOCAL SAVE] +keys_save_enable = False +encrypt_keys_enable = False +encrypt_keys_aeskey_path = + +[ESP32S3 EFUSE BIT CONFIG] +dis_usb_jtag = False +hard_dis_jtag = False +soft_dis_jtag = 7 +dis_usb_otg_download_mode = False +dis_direct_boot = False +dis_download_icache = False +dis_download_dcache = False + diff --git a/dist/flash_download_tool_3.9.6/configure/esp32s3/spi_download.conf b/dist/flash_download_tool_3.9.6/configure/esp32s3/spi_download.conf new file mode 100644 index 0000000000..ebc596813d --- /dev/null +++ b/dist/flash_download_tool_3.9.6/configure/esp32s3/spi_download.conf @@ -0,0 +1,100 @@ +[EFUSE CHECK] +efuse_mode = 1 +efuse_err_halt = 1 + +[MULTI_UI_CONFIG] +multi_col = 2 + +[DOWNLOAD PATH] +file_sel0 = 0 +file_path0 = +file_flag0 = False +file_offset0 = +file_sel1 = 0 +file_path1 = +file_flag1 = False +file_offset1 = +file_sel2 = 0 +file_path2 = +file_flag2 = False +file_offset2 = +file_sel3 = 0 +file_path3 = +file_flag3 = False +file_offset3 = +file_sel4 = 0 +file_path4 = +file_flag4 = False +file_offset4 = +file_sel5 = 0 +file_path5 = +file_flag5 = False +file_offset5 = +file_sel6 = 0 +file_path6 = +file_flag6 = False +file_offset6 = +file_sel7 = 0 +file_path7 = +file_flag7 = False +file_offset7 = +file_sel8 = 0 +file_path8 = +file_flag8 = False +file_offset8 = +file_sel9 = 0 +file_path9 = +file_flag9 = False +file_offset9 = +file_sel10 = 0 +file_path10 = +file_flag10 = False +file_offset10 = +file_sel11 = 0 +file_path11 = +file_flag11 = False +file_offset11 = +file_sel12 = 0 +file_path12 = +file_flag12 = False +file_offset12 = +file_sel13 = 0 +file_path13 = +file_flag13 = False +file_offset13 = +default_path = D:\DOWNLOAD_TOOL\ÏÂÔع¤¾ß\release\3.9.6 + +[FLASH_CRYSTAL] +spicfgdis = 1 +spispeed = 0 +spimode = 2 + +[DOWNLOAD] +erase_button_en = True +autostart1 = 0 +com_port1 = +baudrate1 = 0 +checkmac1 = 1 + +[LOG_CHECK] +log_check_enable = False +log_check_baud = 115200 +log_check_str = 1.0.0 +log_check_delaytime = 3 +log_check_timeout = 3 +log_check_cmd_str = AT+GMR +log_check_enable_cmd = False + +[MAC_SAVE] +mac_save_enable = False + +[ESPTOOL_PARAM] +after = no_reset +before = default_reset +compress = True +flash_size = keep +no_stub = False +verify = True +flash_freq = keep +flash_mode = keep + diff --git a/dist/flash_download_tool_3.9.6/configure/esp32s3/utility.conf b/dist/flash_download_tool_3.9.6/configure/esp32s3/utility.conf new file mode 100644 index 0000000000..8f8e1facfc --- /dev/null +++ b/dist/flash_download_tool_3.9.6/configure/esp32s3/utility.conf @@ -0,0 +1,16 @@ +[LOG_LEVEL] +utility_log_level = ERROR +spi_log_level = ERROR +multi_log_level = ERROR + +[MAC_SAVE] +mac_save_enable = False + +[SECTOR_PROTECT] +sector_protect_enable = False +sector_protect_start = 0xe000 +sector_protect_end = 0x3000 + +[ESP32_EFUSE_CONFIG] +config_voltage = OFF + diff --git a/dist/flash_download_tool_3.9.6/configure/esp8266/hspi_download.conf b/dist/flash_download_tool_3.9.6/configure/esp8266/hspi_download.conf new file mode 100644 index 0000000000..c65baad167 --- /dev/null +++ b/dist/flash_download_tool_3.9.6/configure/esp8266/hspi_download.conf @@ -0,0 +1,100 @@ +[EFUSE CHECK] +efuse_mode = 1 +efuse_err_halt = 1 + +[MULTI_UI_CONFIG] +multi_col = 2 + +[DOWNLOAD PATH] +file_sel0 = 0 +file_path0 = +file_flag0 = False +file_offset0 = +file_sel1 = 0 +file_path1 = +file_flag1 = False +file_offset1 = +file_sel2 = 0 +file_path2 = +file_flag2 = False +file_offset2 = +file_sel3 = 0 +file_path3 = +file_flag3 = False +file_offset3 = +file_sel4 = 0 +file_path4 = +file_flag4 = False +file_offset4 = +file_sel5 = 0 +file_path5 = +file_flag5 = False +file_offset5 = +file_sel6 = 0 +file_path6 = +file_flag6 = False +file_offset6 = +file_sel7 = 0 +file_path7 = +file_flag7 = False +file_offset7 = +file_sel8 = 0 +file_path8 = +file_flag8 = False +file_offset8 = +file_sel9 = 0 +file_path9 = +file_flag9 = False +file_offset9 = +file_sel10 = 0 +file_path10 = +file_flag10 = False +file_offset10 = +file_sel11 = 0 +file_path11 = +file_flag11 = False +file_offset11 = +file_sel12 = 0 +file_path12 = +file_flag12 = False +file_offset12 = +file_sel13 = 0 +file_path13 = +file_flag13 = False +file_offset13 = +default_path = D:\DOWNLOAD_TOOL\ÏÂÔع¤¾ß\release\3.9.6 + +[FLASH_CRYSTAL] +spicfgdis = 1 +spispeed = 0 +spimode = 0 + +[DOWNLOAD] +erase_button_en = True +autostart1 = 0 +com_port1 = +baudrate1 = 0 +checkmac1 = 1 + +[LOG_CHECK] +log_check_enable = False +log_check_baud = 115200 +log_check_str = 1.0.0 +log_check_delaytime = 3 +log_check_timeout = 3 +log_check_cmd_str = AT+GMR +log_check_enable_cmd = False + +[MAC_SAVE] +mac_save_enable = False + +[ESPTOOL_PARAM] +after = no_reset +before = default_reset +compress = True +flash_size = keep +no_stub = False +verify = True +flash_freq = keep +flash_mode = keep + diff --git a/dist/flash_download_tool_3.9.6/configure/esp8266/multi_download.conf b/dist/flash_download_tool_3.9.6/configure/esp8266/multi_download.conf new file mode 100644 index 0000000000..689dcd2060 --- /dev/null +++ b/dist/flash_download_tool_3.9.6/configure/esp8266/multi_download.conf @@ -0,0 +1,161 @@ +[EFUSE CHECK] +efuse_mode = 1 +efuse_err_halt = 1 + +[MULTI_UI_CONFIG] +multi_col = 2 + +[DOWNLOAD PATH] +file_sel0 = 0 +file_path0 = +file_flag0 = False +file_offset0 = +file_sel1 = 0 +file_path1 = +file_flag1 = False +file_offset1 = +file_sel2 = 0 +file_path2 = +file_flag2 = False +file_offset2 = +file_sel3 = 0 +file_path3 = +file_flag3 = False +file_offset3 = +file_sel4 = 0 +file_path4 = +file_flag4 = False +file_offset4 = +file_sel5 = 0 +file_path5 = +file_flag5 = False +file_offset5 = +file_sel6 = 0 +file_path6 = +file_flag6 = False +file_offset6 = +file_sel7 = 0 +file_path7 = +file_flag7 = False +file_offset7 = +file_sel8 = 0 +file_path8 = +file_flag8 = False +file_offset8 = +file_sel9 = 0 +file_path9 = +file_flag9 = False +file_offset9 = +file_sel10 = 0 +file_path10 = +file_flag10 = False +file_offset10 = +file_sel11 = 0 +file_path11 = +file_flag11 = False +file_offset11 = +file_sel12 = 0 +file_path12 = +file_flag12 = False +file_offset12 = +file_sel13 = 0 +file_path13 = +file_flag13 = False +file_offset13 = +default_path = ./bin/ + +[LOCK] +lock_setting_password = + +[FLASH_CRYSTAL] +spicfgdis = 1 +spispeed = 0 +spimode = 0 + +[DOWNLOAD] +erase_button_en = True +autostart1 = 0 +com_port1 = +baudrate1 = 0 +checkmac1 = 1 +autostart2 = 0 +com_port2 = +baudrate2 = 0 +checkmac2 = 1 +autostart3 = 0 +com_port3 = +baudrate3 = 0 +checkmac3 = 1 +autostart4 = 0 +com_port4 = +baudrate4 = 0 +checkmac4 = 1 +autostart5 = 0 +com_port5 = +baudrate5 = 0 +checkmac5 = 1 +autostart6 = 0 +com_port6 = +baudrate6 = 0 +checkmac6 = 1 +autostart7 = 0 +com_port7 = +baudrate7 = 0 +checkmac7 = 1 +autostart8 = 0 +com_port8 = +baudrate8 = 0 +checkmac8 = 1 +autostart9 = 0 +com_port9 = +baudrate9 = 0 +checkmac9 = 1 +autostart10 = 0 +com_port10 = +baudrate10 = 0 +checkmac10 = 1 + +[LOG_CHECK] +log_check_enable = False +log_check_baud = 115200 +log_check_str = 1.0.0 +log_check_delaytime = 3 +log_check_timeout = 3 +log_check_cmd_str = AT+GMR +log_check_enable_cmd = False + +[MAC_SAVE] +mac_save_enable = False + +[ESPTOOL_PARAM] +after = no_reset +before = default_reset +compress = True +flash_size = keep +no_stub = False +verify = True +flash_freq = keep +flash_mode = keep + +[STATISTICS] +pass1 = 0 +fail1 = 0 +pass2 = 0 +fail2 = 0 +pass3 = 0 +fail3 = 0 +pass4 = 0 +fail4 = 0 +pass5 = 0 +fail5 = 0 +pass6 = 0 +fail6 = 0 +pass7 = 0 +fail7 = 0 +pass8 = 0 +fail8 = 0 +pass9 = 0 +fail9 = 0 +pass10 = 0 +fail10 = 0 + diff --git a/dist/flash_download_tool_3.9.6/configure/esp8266/spi_download.conf b/dist/flash_download_tool_3.9.6/configure/esp8266/spi_download.conf new file mode 100644 index 0000000000..c65baad167 --- /dev/null +++ b/dist/flash_download_tool_3.9.6/configure/esp8266/spi_download.conf @@ -0,0 +1,100 @@ +[EFUSE CHECK] +efuse_mode = 1 +efuse_err_halt = 1 + +[MULTI_UI_CONFIG] +multi_col = 2 + +[DOWNLOAD PATH] +file_sel0 = 0 +file_path0 = +file_flag0 = False +file_offset0 = +file_sel1 = 0 +file_path1 = +file_flag1 = False +file_offset1 = +file_sel2 = 0 +file_path2 = +file_flag2 = False +file_offset2 = +file_sel3 = 0 +file_path3 = +file_flag3 = False +file_offset3 = +file_sel4 = 0 +file_path4 = +file_flag4 = False +file_offset4 = +file_sel5 = 0 +file_path5 = +file_flag5 = False +file_offset5 = +file_sel6 = 0 +file_path6 = +file_flag6 = False +file_offset6 = +file_sel7 = 0 +file_path7 = +file_flag7 = False +file_offset7 = +file_sel8 = 0 +file_path8 = +file_flag8 = False +file_offset8 = +file_sel9 = 0 +file_path9 = +file_flag9 = False +file_offset9 = +file_sel10 = 0 +file_path10 = +file_flag10 = False +file_offset10 = +file_sel11 = 0 +file_path11 = +file_flag11 = False +file_offset11 = +file_sel12 = 0 +file_path12 = +file_flag12 = False +file_offset12 = +file_sel13 = 0 +file_path13 = +file_flag13 = False +file_offset13 = +default_path = D:\DOWNLOAD_TOOL\ÏÂÔع¤¾ß\release\3.9.6 + +[FLASH_CRYSTAL] +spicfgdis = 1 +spispeed = 0 +spimode = 0 + +[DOWNLOAD] +erase_button_en = True +autostart1 = 0 +com_port1 = +baudrate1 = 0 +checkmac1 = 1 + +[LOG_CHECK] +log_check_enable = False +log_check_baud = 115200 +log_check_str = 1.0.0 +log_check_delaytime = 3 +log_check_timeout = 3 +log_check_cmd_str = AT+GMR +log_check_enable_cmd = False + +[MAC_SAVE] +mac_save_enable = False + +[ESPTOOL_PARAM] +after = no_reset +before = default_reset +compress = True +flash_size = keep +no_stub = False +verify = True +flash_freq = keep +flash_mode = keep + diff --git a/dist/flash_download_tool_3.9.6/configure/esp8266/utility.conf b/dist/flash_download_tool_3.9.6/configure/esp8266/utility.conf new file mode 100644 index 0000000000..fb5988fb99 --- /dev/null +++ b/dist/flash_download_tool_3.9.6/configure/esp8266/utility.conf @@ -0,0 +1,14 @@ +[LOG_LEVEL] +utility_log_level = ERROR +spi_log_level = ERROR +hspi_log_level = ERROR +multi_log_level = ERROR + +[MAC_SAVE] +mac_save_enable = False + +[SECTOR_PROTECT] +sector_protect_enable = False +sector_protect_start = 0xe000 +sector_protect_end = 0x3000 + diff --git a/dist/flash_download_tool_3.9.6/doc/Flash_Download_Tool__cn.pdf b/dist/flash_download_tool_3.9.6/doc/Flash_Download_Tool__cn.pdf new file mode 100644 index 0000000000..b25d319ff5 Binary files /dev/null and b/dist/flash_download_tool_3.9.6/doc/Flash_Download_Tool__cn.pdf differ diff --git a/dist/flash_download_tool_3.9.5/doc/Flash_Download_Tool__en.pdf b/dist/flash_download_tool_3.9.6/doc/Flash_Download_Tool__en.pdf similarity index 100% rename from dist/flash_download_tool_3.9.5/doc/Flash_Download_Tool__en.pdf rename to dist/flash_download_tool_3.9.6/doc/Flash_Download_Tool__en.pdf diff --git a/dist/flash_download_tool_3.9.5/doc/release_note.txt b/dist/flash_download_tool_3.9.6/doc/release_note.txt similarity index 61% rename from dist/flash_download_tool_3.9.5/doc/release_note.txt rename to dist/flash_download_tool_3.9.6/doc/release_note.txt index 5f96d588d0..e296315dd0 100644 --- a/dist/flash_download_tool_3.9.5/doc/release_note.txt +++ b/dist/flash_download_tool_3.9.6/doc/release_note.txt @@ -1,3 +1,8 @@ +3.9.6: +* support ESP32/ESP32H2/ESP32C6/ESP32C2/ESP32S2 secure boot version2 and flash encryption +* config DUT number in multiconfig file ,up to 20pcs +* update secure config file, see docs in detail + 3.9.5: * support esp32-h2 * support erase button disable diff --git a/dist/flash_download_tool_3.9.5/flash_download_tool_3.9.5.exe b/dist/flash_download_tool_3.9.6/flash_download_tool_3.9.6.exe similarity index 70% rename from dist/flash_download_tool_3.9.5/flash_download_tool_3.9.5.exe rename to dist/flash_download_tool_3.9.6/flash_download_tool_3.9.6.exe index 2ea17a6e10..3895e175ed 100644 Binary files a/dist/flash_download_tool_3.9.5/flash_download_tool_3.9.5.exe and b/dist/flash_download_tool_3.9.6/flash_download_tool_3.9.6.exe differ diff --git a/docs/source/ESPEasy/ESPchips.rst b/docs/source/ESPEasy/ESPchips.rst index 4b0754c137..f821ea9b2a 100644 --- a/docs/source/ESPEasy/ESPchips.rst +++ b/docs/source/ESPEasy/ESPchips.rst @@ -10,8 +10,8 @@ ESPEasy does support a number of variants of the processors manufactured by Espr * **ESP32-S2** Has more GPIO pins than the ESP32, but only 1 CPU core. Initial support in ESPEasy added since 2021-09-19. * **ESP32-S3** Support added: 2023-05-03 * **ESP32-C3 / ESP8685** Support added: 2023-05-03 -* **ESP32-C2 / ESP8684** Not yet supported -* **ESP32-C6** Not yet supported +* **ESP32-C2 / ESP8684** Support added: 2023-11-10 +* **ESP32-C6** Support added: 2023-11-10 * **ESP32-H2** Not yet supported @@ -83,7 +83,7 @@ ESPEasy does support a number of variants of the processors manufactured by Espr - 2022 - 2021 - 2021 - * - Status (2023/05) + * - Status (2024/03) - NRND - Mass Production (solo1: NRND) - NRND @@ -91,7 +91,7 @@ ESPEasy does support a number of variants of the processors manufactured by Espr - Mass Production - Mass Production - Mass Production - - Sample + - Mass Production * - Wi-Fi - IEEE 802.11 b/g/n; 2.4 GHz; HT20; up to 72 Mbps - IEEE 802.11 b/g/n; 2.4 GHz; HT20/40; up to 150 Mbps @@ -328,12 +328,12 @@ ESPEasy does support a number of variants of the processors manufactured by Espr - 0 * - Ethernet - 0 - - 1 (RMII) - - 0 - - 0 - - 0 - - 0 - - 0 + - 1 (RMII and SPI) + - 1 (SPI) + - 1 (SPI) + - 1 (SPI) + - 1 (SPI) + - 1 (SPI) - 0 * - TWAI (CAN) - 0 @@ -683,7 +683,7 @@ ESP32-C2/ESP8684 Added: 2023/11/10 -The ESP32-C2 is only available with embedded flash and can only be found labelled as "ESP8684". +The ESP32-C2 is only available with embedded flash and can also be found labeled as "ESP8684". It looks like it is aimed to be used in single purpose devices, due to its low GPIO count and only requiring a bare minimum of external parts. @@ -700,9 +700,9 @@ Added: 2023/11/10 The ESP32-C6 seems to be aimed at being used as a gateway for the new Thread protocol and Wi-Fi. -It is the more powerful version of the ESP32-H2 and also includes not only the traditional 2.4 GHz Wi-Fi, but also the new Wi-Fi6 standard on 2.4 GHz. +It is the more powerful version of the ESP32-H2 and also includes not only the traditional 2.4 GHz Wi-Fi, but also the new Wi-Fi6 standard on 2.4 GHz and IEEE 802.15.4 (Zigbee/Thread). Zigbee/Thread not yet supported by ESPEasy (March 2024). -.. note:: Labelled as "unstable" by the Arduino team (as of Nov 2023), preliminary support in ESPEasy +.. note:: Labeled as "unstable" by the Arduino team (as of Nov 2023), preliminary support in ESPEasy ESP32-H2 ======== diff --git a/docs/source/Participate/ProjectStructure.rst b/docs/source/Participate/ProjectStructure.rst index b25676a9cb..8e7b61199c 100644 --- a/docs/source/Participate/ProjectStructure.rst +++ b/docs/source/Participate/ProjectStructure.rst @@ -29,7 +29,7 @@ Below a list of the most important directories and files used in this project. * ``platformio.ini`` Configuration file for PlatformIO to define various build setups. * ``uncrustify.cfg`` Configuration file for Uncrustify, to format source code using some uniform formatting rules. * ``requirements.txt`` List of used Python libraries and their version (result of ``pip freeze`` with Virtual env active) -* ``esp32_partition_app1810k_spiffs316k.csv`` Used partition layout in ESP32 builds. +* ``boards/partitions/esp32_partition_app1810k_spiffs316k.csv`` Used partition layout in ESP32 4M builds. ESPEasy src dir @@ -90,11 +90,11 @@ The filename is quite descriptive: Build Type ---------- -Build type can be: (differ in included plugins) +Build type can be: (differences in included plugins) -* normal => Only Stable plugins and controllers -* test => Stable + Testing (split into multiple sets, A/B/C/D) -* max => All available plugins +* normal => Only Stable plugins and controllers +* collection => Stable + Collection (split into multiple sets, A/B/C/D/E/F/G) +* max => All available plugins and features There is also a number of special builds: @@ -111,8 +111,10 @@ ESP Chip Type * ``ESP8285`` Supported in ``ESP8266`` builds. Used in some Sonoff modules. This chip has embedded flash, so no extra flash chip. * ``ESP32`` Allows for more memory and more GPIO pins. * ``ESP32-S2`` Newer version of ESP32. Has even more GPIO pins, but some specific features of ESP32 were removed. -* ``ESP32-S3`` Not yet available. -* ``ESP32-C3`` Support will be added soon. +* ``ESP32-S3`` Newer version of ESP32 and ESP32-S2. Has even more GPIO pins, some specific features of ESP32 were removed, and some design choices of ESP32-S2 are reverted and implemented differently. +* ``ESP32-C2`` Preliminary supported. Cheaper variant of ESP32-C3, and also an ESP8266 replacement. Available as pin-compatible module for ESP8266. Single core, and max 120 MHz clock speed. +* ``ESP32-C3`` Intended as a replacement for ESP8266, using ESP32 technology, though single-core and with limited clock speed (160 MHz, some models 120 MHz). +* ``ESP32-C6`` Preliminary supported. Will allow connectivity with IEEE 802.15.4 (Thread/Zigbee) wireless protocol. Memory Size and Partitioning ---------------------------- @@ -124,23 +126,27 @@ Memory Size and Partitioning * ``4M1M`` 4 MB flash modules with 1 MB filesystem (usually SPIFFS) * ``4M2M`` 4 MB flash modules with 2 MB filesystem (usually SPIFFS) * ``4M316k`` 4 MB flash modules using 1.8 MB sketch size, with 316 kB filesystem (usually SPIFFS) (for ESP32) +* ``8M1M`` 8 MB flash modules using 3.5MB sketch size, with 1 MB filesystem (LittleFS) (ESP32 only a.t.m.) * ``16M1M`` 16 MB flash modules using 4MB sketch size, with 1 MB filesystem (usually SPIFFS) (ESP32 only a.t.m.) -* ``16M2M`` 16 MB flash modules using 4MB sketch size, with 2 MB filesystem (LittleFS) (ESP32 only a.t.m.) * ``16M8M`` 16 MB flash modules using 4MB sketch size, with 8 MB filesystem (LittleFS) (ESP32 only a.t.m.) Optional build options ---------------------- -* ``LittleFS`` Use LittleFS instead of SPIFFS filesystem (SPIFFS is unstable > 2 MB) +* ``LittleFS`` Use LittleFS instead of SPIFFS filesystem (SPIFFS is unstable \> 2 MB and no longer available from IDF 5.x) * ``VCC`` Analog input configured to measure VCC voltage * ``OTA`` Arduino OTA (Over The Air) update feature enabled * ``Domoticz`` Only Domoticz controllers (HTTP+MQTT) and plugins included * ``FHEM_HA`` Only FHEM/OpenHAB/Home Assistant (MQTT) controllers and plugins included * ``lolin_d32_pro`` Specific Lolin hardware options enabled +* ``PSRAM`` Additional PSRAM support (ESP32 only) +* ``OPI`` Flash via OPI protocol support (ESP32 only) +* ``QIO`` Flash via QIO protocol support (ESP32 only) +* ``CDC`` CDC Serial (built-in USB) support (ESP32 only) * ``ETH`` Ethernet interface enabled (ESP32 only) -Please note that the performance of 14MB SPIFFS (16M flash modules) is really slow. +Please note that the performance of 14MB SPIFFS (16M flash ESP8266 modules) is really slow. All file access takes a lot longer and since the settings are also read from flash, the entire node will perform slower. See `Arduino issue - SPIFFS file access slow on 16/14M flash config `_ @@ -150,7 +156,7 @@ Special memory partitioning: * ``2M256`` 2 MB flash modules (e.g. Shelly1/WROOM02) with 256k SPIFFS (only core 2.5.0 or newer) * ``4M316k`` For ESP32 with 4MB flash, sketch size is set to 1.8 MByte (default: 1.4 MByte) -* ``4M1M`` 4MB flash, 1 MB SPIFFS. Default layout for 4MB flash. +* ``4M1M`` 4MB flash, 1 MB SPIFFS. Default layout for ESP8266 4MB flash. * ``4M2M`` 4MB flash, 2 MB SPIFFS. Introduced in October 2019. Only possible with core 2.5.2 or newer. .. warning:: @@ -165,7 +171,7 @@ Difference between .bin and .bin.gz Starting on esp8266/Arduino core 2.7.0, it is possible to flash images that have been compressed using GZip. -Please note that this only can be used on installs already running a very recent build. +Please note that this only can be used on installs already running a recent build. This also means we still need to update the 2-step updater to support .bin.gz files. @@ -182,17 +188,17 @@ There are several builds for ESP32: * ``normal_ESP32_4M316k`` Build using the "stable" set of plugins for ESP32 * ``normal_ESP32_4M316k_ETH`` Build using the "stable" set of plugins for ESP32, with support for an on-board Ethernet controller * ``custom_ESP32_4M316k`` Build template using either the plugin set defined in ``Custom.h`` or ``tools/pio/pre_custom_esp32.py`` -* ``test_A_ESP32_4M316k`` Build using the "testing" set "A" of plugins for ESP32 -* ``test_B_ESP32_4M316k`` Build using the "testing" set "B" of plugins for ESP32 -* ``test_C_ESP32_4M316k`` Build using the "testing" set "C" of plugins for ESP32 -* ``test_D_ESP32_4M316k`` Build using the "testing" set "D" of plugins for ESP32 -* ``test_A_ESP32-wrover-kit_4M316k`` A build for ESP32 including build flags for the official WRover test kit. +* ``collection_A_ESP32_4M316k`` Build using the "Collection" set "A" of plugins for ESP32 +* ``collection_B_ESP32_4M316k`` Build using the "Collection" set "B" of plugins for ESP32 +* ``collection_C_ESP32_4M316k`` Build using the "Collection" set "C" of plugins for ESP32 +* ``collection_D_ESP32_4M316k`` Build using the "Collection" set "D" of plugins for ESP32 +* ``collection_A_ESP32-wrover-kit_4M316k`` A build for ESP32 including build flags for the official WRover test kit. * ``max_ESP32_16M8M_LittleFS`` Build using all available plugins and controllers for ESP32 with 16 MB flash (some lolin_d32_pro boards) Since ESP32 does have its flash partitioned in several blocks, we have 2 bin files of each ESP32 build, f.e.: -* ``test_D_ESP32_4M316k.bin`` Use for OTA upgrades. -* ``test_D_ESP32_4M316k.factory.bin`` Use on clean nodes as initial inistall. +* ``collection_D_ESP32_4M316k.bin`` Use for OTA upgrades. +* ``collection_D_ESP32_4M316k.factory.bin`` Use on clean nodes as initial inistall. The binary with ``.factory`` in the name must be flashed on a new node, via the serial interface of the board. This flash must be started at address 0. @@ -208,7 +214,8 @@ To help recover from a bad flash, there are also blank images included. * ``blank_1MB.bin`` * ``blank_2MB.bin`` * ``blank_4MB.bin`` +* ``blank_8MB.bin`` * ``blank_16MB.bin`` When the wrong image is flashed, or the module behaves unstable, or is in a reboot loop, -flash these images first and then the right image for the module. +flash these images first to clear out any remaining or hidden settings (Arduino framework...) and then the right image for the module. diff --git a/docs/source/Plugin/P029.rst b/docs/source/Plugin/P029.rst index ee0b397f94..cd57c4c6ac 100644 --- a/docs/source/Plugin/P029.rst +++ b/docs/source/Plugin/P029.rst @@ -113,6 +113,7 @@ Relevant Settings: * Plugin: Output - Domoticz MQTT Helper * 1st GPIO: 12 (the relay) * IDX: 475 +* Invert On/Off value: To ease the use of this plugin, without the need for rules, an Invert option has been added. This will cause the GPIO pin (and ``Output`` value) to be set to 1 when the Domoticz device is in Off state, and 0 for the On state. Rules @@ -184,6 +185,8 @@ Change log .. versionchanged:: 2.0 ... + |added| 2024-03: Add Invert On/Off value option. + |added| Major overhaul for 2.0 release. diff --git a/docs/source/Plugin/P029_Domoticz_Helper.png b/docs/source/Plugin/P029_Domoticz_Helper.png index bdc10673b2..afc6c614ea 100644 Binary files a/docs/source/Plugin/P029_Domoticz_Helper.png and b/docs/source/Plugin/P029_Domoticz_Helper.png differ diff --git a/docs/source/Plugin/P087.rst b/docs/source/Plugin/P087.rst index 721a197527..4582df69d8 100644 --- a/docs/source/Plugin/P087.rst +++ b/docs/source/Plugin/P087.rst @@ -48,7 +48,7 @@ This section only shows settings when the plugin is configured and enabled. .. image:: P087_FilteringConfiguration.png -* **RegEx**: Specify a regular expression to apply to the received data before it is accepted as acceptable data. +* **RegEx**: Specify a regular expression to apply to the received data before it is accepted as acceptable data. This regular expression is based on the Lua script language, and is documented here: http://www.lua.org/manual/5.2/manual.html#6.4.1 * **Nr Chars use in RegEx**: Limit the length of the data to be checked using the **RegEx** regular expression filter. When set to 0 all data is checked. @@ -109,6 +109,13 @@ Commands available .. include:: P087_commands.repl +Get Config Values +^^^^^^^^^^^^^^^^^ + +Get Config Values retrieves values or settings from the sensor or plugin, and can be used in Rules, Display plugins, Formula's etc. The square brackets **are** part of the variable. Replace ```` by the **Name** of the task. + +.. include:: P087_config_values.repl + Change log ---------- @@ -116,6 +123,8 @@ Change log .. versionchanged:: 2.0 ... + |added| 2024-02-25 Add support for ``serialproxy_test`` command and retrieving the separate groups from parsed regex. + |added| 2023-03-22 Add support for writing any binary data out via the serial port. |added| 2020-02-22 diff --git a/docs/source/Plugin/P087_commands.repl b/docs/source/Plugin/P087_commands.repl index 60effc0a9c..ca2b9f1c8d 100644 --- a/docs/source/Plugin/P087_commands.repl +++ b/docs/source/Plugin/P087_commands.repl @@ -26,3 +26,12 @@ ``'0xXXxx XX,xx-XX:xx'``: A sequence of hexadecimal values (range: 0x00..0xFF), that *can* be separated by a space, comma, dash, colon, semicolon or period, or are just entered adjecent. Only the first 2 characters should be ``0x`` or ``0X``, the rest is interpreted as hex bytes, and appended to the data to send. Quotes are only required if space or comma separators are used. Using this command, either from rules, via http or mqtt, the text that is provided as content is completely sent to the serial port. No extra data is added, other than any (system) variables that are included, being replaced. " + " + ``serialproxy_test,'[,...]'`` + + ````: Some text to be processed as if it was received via the serial port. + "," + This command is intended for testing the regular expression and filtering. + + The sentence provided with this command is handed over for processing as if it was received via the serial port, so it will be processed and filtered, and an event will be generated if it's matched. + " diff --git a/docs/source/Plugin/P087_config_values.repl b/docs/source/Plugin/P087_config_values.repl new file mode 100644 index 0000000000..b386e5d20a --- /dev/null +++ b/docs/source/Plugin/P087_config_values.repl @@ -0,0 +1,70 @@ +.. csv-table:: + :header: "Config value", "Information" + :widths: 20, 30 + + " + ``[#group,]`` + "," + Get the contents from groupnr after processing received data. + + NB: The regular expression parsen uses 0-based group numbers (where most other regex parsers use 1-based group numbers!) + " + " + ``[#next,]`` + "," + Get the value of the next group that holds ````. + + Example: + + Regular expression: ``((node)=(%d+);?)((weight)=(%d+);?)((temp%d?)=(%-?%d+);?)((rssi)=(%-?%d+);?)`` + + Received data: ``node=1;weight=40;temp1=20;rssi=-30`` + + This will result in these groups: + + .. list-table:: + :widths: 20, 50, 200 + :header-rows: 1 + + * - Group + - Data + - + * - 0 + - node=1 + - + * - 1 + - node + - + * - 2 + - 1 + - + * - 3 + - weight=40 + - + * - 4 + - weight + - + * - 5 + - 40 + - + * - 6 + - temp1=20 + - + * - 7 + - temp1 + - + * - 8 + - 20 + - + * - 9 + - rssi=-30 + - + * - 10 + - rssi + - + * - 11 + - -30 + - + + Requesting ``[SerialProxy#next,weight]`` will return the value ``40``. + " diff --git a/docs/source/Plugin/P095_commands.repl b/docs/source/Plugin/P095_commands.repl index e88f9821ec..98b3cf2ddf 100644 --- a/docs/source/Plugin/P095_commands.repl +++ b/docs/source/Plugin/P095_commands.repl @@ -31,7 +31,7 @@ " | ``tftcmd,clear`` "," - | Clear the display, using the default background color. + | Clear the display, using the **default** background color. For clearing with a custom background color see the ``,clear[,]`` command. " " | ``tftcmd,backlight,`` diff --git a/docs/source/Plugin/P116.rst b/docs/source/Plugin/P116.rst index 6e2a42d139..afddf033a0 100644 --- a/docs/source/Plugin/P116.rst +++ b/docs/source/Plugin/P116.rst @@ -28,7 +28,7 @@ The ST7735, ST7789 and ST7796 chip families drive color TFT displays in various This plugin supports these display models: -* **ST7735** with resolutions 128 x 128, 128 x 160 and 80 x 160 pixels +* **ST7735** with resolutions 128 x 128, 128 x 160, 80 x 160 and 135 x 240 pixels * **ST7789** with resolutions 240 x 320, 240 x 240, 240 x 280 and 135 x 240 pixels * **ST7796** with resolution of 320 x 480 pixels. @@ -140,6 +140,7 @@ Available options: * *ST7735 128 x 160px* Allows 16 lines of text in the smallest font scaling setting. * *ST7735 80 x 160px* Allows 16 lines of text in the smallest font scaling setting. * *ST7735 80 x 160px (Color inverted)* Special color inverted configuration as used in f.e. M5Stack StickC. +* *ST7735 135 x 240px* Added to support a revision of the TTGO T-Display 16MB Flash module, that won't work with the ST7789 driver, the seller is claiming to use, but does work with this specially crafted ST7735 driver. * *ST7789 240 x 320px* Allows 32 lines of text in the smallest font scaling setting. Predefined text only goes to 24, extra lines can be displayed from rules or external commands. * *ST7789 240 x 240px* Allows 24 lines of text in the smallest font scaling setting. * *ST7789 240 x 280px* Allows 28 lines of text in the smallest font scaling setting. Predefined text only goes to 24, extra lines can be displayed from rules or external commands. @@ -260,6 +261,10 @@ Change log .. versionadded:: 2.0 ... + |added| 2024-03-26 Add support for ST7735, 135x240 resolution + + |added| 2022-07-06 Add support for ST7735 (Color inverted), for M5StickC support + |added| 2021-11-06 Add support for ST7796 displays |added| 2021-08 Moved from an external forum to ESPEasy. diff --git a/docs/source/Plugin/P116_TFTDisplayModelOptions.png b/docs/source/Plugin/P116_TFTDisplayModelOptions.png index a17199a9ce..6719b106c6 100644 Binary files a/docs/source/Plugin/P116_TFTDisplayModelOptions.png and b/docs/source/Plugin/P116_TFTDisplayModelOptions.png differ diff --git a/docs/source/Plugin/P116_commands.repl b/docs/source/Plugin/P116_commands.repl index 50d2b90622..6a6702d432 100644 --- a/docs/source/Plugin/P116_commands.repl +++ b/docs/source/Plugin/P116_commands.repl @@ -28,7 +28,7 @@ " | ``st77xxcmd,clear`` "," - | Clear the display, using the default background color. + | Clear the display, using the **default** background color. For clearing with a custom background color see the ``,clear[,]`` command. " " | ``st77xxcmd,backlight,`` diff --git a/lib/Adafruit_NeoMatrix/examples/MatrixGFXDemo/MatrixGFXDemo.ino b/lib/Adafruit_NeoMatrix/examples/MatrixGFXDemo/MatrixGFXDemo.ino index 1960215b6f..30b19b2191 100644 --- a/lib/Adafruit_NeoMatrix/examples/MatrixGFXDemo/MatrixGFXDemo.ino +++ b/lib/Adafruit_NeoMatrix/examples/MatrixGFXDemo/MatrixGFXDemo.ino @@ -150,56 +150,56 @@ static const uint8_t PROGMEM mono_bmp[][8] = { { // 0: checkered 1 - B10101010, - B01010101, - B10101010, - B01010101, - B10101010, - B01010101, - B10101010, - B01010101, + 0b10101010, + 0b01010101, + 0b10101010, + 0b01010101, + 0b10101010, + 0b01010101, + 0b10101010, + 0b01010101, }, { // 1: checkered 2 - B01010101, - B10101010, - B01010101, - B10101010, - B01010101, - B10101010, - B01010101, - B10101010, + 0b01010101, + 0b10101010, + 0b01010101, + 0b10101010, + 0b01010101, + 0b10101010, + 0b01010101, + 0b10101010, }, { // 2: smiley - B00111100, - B01000010, - B10100101, - B10000001, - B10100101, - B10011001, - B01000010, - B00111100 }, + 0b00111100, + 0b01000010, + 0b10100101, + 0b10000001, + 0b10100101, + 0b10011001, + 0b01000010, + 0b00111100 }, { // 3: neutral - B00111100, - B01000010, - B10100101, - B10000001, - B10111101, - B10000001, - B01000010, - B00111100 }, + 0b00111100, + 0b01000010, + 0b10100101, + 0b10000001, + 0b10111101, + 0b10000001, + 0b01000010, + 0b00111100 }, { // 4; frowny - B00111100, - B01000010, - B10100101, - B10000001, - B10011001, - B10100101, - B01000010, - B00111100 }, + 0b00111100, + 0b01000010, + 0b10100101, + 0b10000001, + 0b10011001, + 0b10100101, + 0b01000010, + 0b00111100 }, }; static const uint16_t PROGMEM diff --git a/lib/Adafruit_ST77xx/Adafruit_ST7735.cpp b/lib/Adafruit_ST77xx/Adafruit_ST7735.cpp index 2ddd4e2429..4f688a90f2 100644 --- a/lib/Adafruit_ST77xx/Adafruit_ST7735.cpp +++ b/lib/Adafruit_ST77xx/Adafruit_ST7735.cpp @@ -181,6 +181,17 @@ static const uint8_t PROGMEM 0x00, 0x00, // XSTART = 0 0x00, 0x9F }, // XEND = 159 + #if ST7735_EXTRA_INIT + Rcmd2black135x240[] = { // 7735R init, part 2 (mini 160x80) + 2, // 2 commands in list: + ST77XX_CASET, 4, // 1: Column addr set, 4 args, no delay: + 0x00, 0x00, // XSTART = 0 + 0x00, 135, // XEND = 135 + ST77XX_RASET, 4, // 2: Row addr set, 4 args, no delay: + 0x00, 0x00, // XSTART = 0 + 240 >> 8, 240 & 0xFF }, // XEND = 240 + #endif // if ST7735_EXTRA_INIT + Rcmd3[] = { // 7735R init, part 3 (red or green tab) 4, // 4 commands in list: ST7735_GMCTRP1, 16 , // 1: Gamma Adjustments (pos. polarity), 16 args + delay: @@ -243,6 +254,15 @@ void Adafruit_ST7735::initR(uint8_t options) { sendCommand(ST77XX_INVON, &data, 0); // Write twice... _colstart = 26; _rowstart = 1; + #if ST7735_EXTRA_INIT + } else if (options == INITR_BLACKTAB135x240) { + _height = ST7735_TFTHEIGHT_240; + _width = ST7735_TFTWIDTH_135; + displayInit(Rcmd2black135x240); + const uint8_t data = 0x00; + sendCommand(ST77XX_INVON, &data, 0); + sendCommand(ST77XX_INVON, &data, 0); // Write twice... + #endif // if ST7735_EXTRA_INIT } else { // colstart, rowstart left at default '0' values displayInit(Rcmd2red); @@ -288,6 +308,10 @@ void Adafruit_ST7735::setRotation(uint8_t m) { case 0: if ((tabcolor == INITR_BLACKTAB) || (tabcolor == INITR_MINI160x80)) { madctl = ST77XX_MADCTL_MX | ST77XX_MADCTL_MY | ST77XX_MADCTL_RGB; + #if ST7735_EXTRA_INIT + } else if (tabcolor == INITR_BLACKTAB135x240) { + madctl = ST77XX_MADCTL_MY | ST77XX_MADCTL_MV | ST77XX_MADCTL_RGB; + #endif // if ST7735_EXTRA_INIT } else { madctl = ST77XX_MADCTL_MX | ST77XX_MADCTL_MY | ST7735_MADCTL_BGR; } @@ -298,6 +322,13 @@ void Adafruit_ST7735::setRotation(uint8_t m) { } else if (tabcolor == INITR_MINI160x80) { _height = ST7735_TFTHEIGHT_160; _width = ST7735_TFTWIDTH_80; + #if ST7735_EXTRA_INIT + } else if (tabcolor == INITR_BLACKTAB135x240) { + _height = ST7735_TFTHEIGHT_240; + _width = ST7735_TFTWIDTH_135; + _colstart = 53; + _rowstart = 40; + #endif // if ST7735_EXTRA_INIT } else { _height = ST7735_TFTHEIGHT_160; _width = ST7735_TFTWIDTH_128; @@ -308,6 +339,10 @@ void Adafruit_ST7735::setRotation(uint8_t m) { case 1: if ((tabcolor == INITR_BLACKTAB) || (tabcolor == INITR_MINI160x80)) { madctl = ST77XX_MADCTL_MY | ST77XX_MADCTL_MV | ST77XX_MADCTL_RGB; + #if ST7735_EXTRA_INIT + } else if (tabcolor == INITR_BLACKTAB135x240) { + madctl = ST77XX_MADCTL_MX | ST77XX_MADCTL_MY | ST77XX_MADCTL_RGB; + #endif // if ST7735_EXTRA_INIT } else { madctl = ST77XX_MADCTL_MY | ST77XX_MADCTL_MV | ST7735_MADCTL_BGR; } @@ -318,6 +353,13 @@ void Adafruit_ST7735::setRotation(uint8_t m) { } else if (tabcolor == INITR_MINI160x80) { _width = ST7735_TFTHEIGHT_160; _height = ST7735_TFTWIDTH_80; + #if ST7735_EXTRA_INIT + } else if (tabcolor == INITR_BLACKTAB135x240) { + _width = ST7735_TFTHEIGHT_240; + _height = ST7735_TFTWIDTH_135; + _colstart = 52; + _rowstart = 40; + #endif // if ST7735_EXTRA_INIT } else { _width = ST7735_TFTHEIGHT_160; _height = ST7735_TFTWIDTH_128; @@ -328,6 +370,10 @@ void Adafruit_ST7735::setRotation(uint8_t m) { case 2: if ((tabcolor == INITR_BLACKTAB) || (tabcolor == INITR_MINI160x80)) { madctl = ST77XX_MADCTL_RGB; + #if ST7735_EXTRA_INIT + } else if (tabcolor == INITR_BLACKTAB135x240) { + madctl = ST77XX_MADCTL_MX | ST77XX_MADCTL_MV | ST77XX_MADCTL_RGB; + #endif // if ST7735_EXTRA_INIT } else { madctl = ST7735_MADCTL_BGR; } @@ -338,6 +384,13 @@ void Adafruit_ST7735::setRotation(uint8_t m) { } else if (tabcolor == INITR_MINI160x80) { _height = ST7735_TFTHEIGHT_160; _width = ST7735_TFTWIDTH_80; + #if ST7735_EXTRA_INIT + } else if (tabcolor == INITR_BLACKTAB135x240) { + _height = ST7735_TFTHEIGHT_240; + _width = ST7735_TFTWIDTH_135; + _colstart = 52; + _rowstart = 40; + #endif // if ST7735_EXTRA_INIT } else { _height = ST7735_TFTHEIGHT_160; _width = ST7735_TFTWIDTH_128; @@ -348,6 +401,10 @@ void Adafruit_ST7735::setRotation(uint8_t m) { case 3: if ((tabcolor == INITR_BLACKTAB) || (tabcolor == INITR_MINI160x80)) { madctl = ST77XX_MADCTL_MX | ST77XX_MADCTL_MV | ST77XX_MADCTL_RGB; + #if ST7735_EXTRA_INIT + } else if (tabcolor == INITR_BLACKTAB135x240) { + madctl = ST77XX_MADCTL_RGB; + #endif // if ST7735_EXTRA_INIT } else { madctl = ST77XX_MADCTL_MX | ST77XX_MADCTL_MV | ST7735_MADCTL_BGR; } @@ -358,6 +415,13 @@ void Adafruit_ST7735::setRotation(uint8_t m) { } else if (tabcolor == INITR_MINI160x80) { _width = ST7735_TFTHEIGHT_160; _height = ST7735_TFTWIDTH_80; + #if ST7735_EXTRA_INIT + } else if (tabcolor == INITR_BLACKTAB135x240) { + _width = ST7735_TFTHEIGHT_240; + _height = ST7735_TFTWIDTH_135; + _colstart = 53; + _rowstart = 40; + #endif // if ST7735_EXTRA_INIT } else { _width = ST7735_TFTHEIGHT_160; _height = ST7735_TFTWIDTH_128; diff --git a/lib/Adafruit_ST77xx/Adafruit_ST7735.h b/lib/Adafruit_ST77xx/Adafruit_ST7735.h index 6d138bce3c..935dda4e30 100644 --- a/lib/Adafruit_ST77xx/Adafruit_ST7735.h +++ b/lib/Adafruit_ST77xx/Adafruit_ST7735.h @@ -3,6 +3,22 @@ #include "Adafruit_ST77xx.h" +/** + * 2024-03-17 tonhuisman: Add additional initialization sequences for ST7735 displays, with the intention to get 'm working + * on some devices that seem to use peculiarly configured hardware like LiliGO TTGO T-Display (16MB flash), + * and possibly the T-Display S3 + * By default only enabled on ESP32, unless -D ST7735_EXTRA_INIT=1 is defined, f.e. via the build script + */ + +#ifndef ST7735_EXTRA_INIT // Enable setting from 'outside', like Platformio.ini +# ifdef ESP8266 +# define ST7735_EXTRA_INIT 0 +# endif // ifdef ESP8266 +# ifdef ESP32 +# define ST7735_EXTRA_INIT 1 +# endif // ifdef ESP32 +#endif + // some flags for initR() :( #define INITR_GREENTAB 0x00 #define INITR_REDTAB 0x01 @@ -14,6 +30,7 @@ #define INITR_MINI160x80 0x04 #define INITR_HALLOWING 0x05 #define INITR_GREENTAB160x80 0x06 +#define INITR_BLACKTAB135x240 0x07 // Some register settings #define ST7735_MADCTL_BGR 0x08 diff --git a/lib/Adafruit_ST77xx/Adafruit_ST7789.cpp b/lib/Adafruit_ST77xx/Adafruit_ST7789.cpp index 9fd2f00e41..6467aeb53b 100644 --- a/lib/Adafruit_ST77xx/Adafruit_ST7789.cpp +++ b/lib/Adafruit_ST77xx/Adafruit_ST7789.cpp @@ -76,6 +76,167 @@ static const uint8_t PROGMEM ST77XX_DISPON , ST_CMD_DELAY, // 9: Main screen turn on, no args, delay 10 }; // 10 ms delay +#if ST7789_EXTRA_INIT +static const uint8_t PROGMEM // Source: https://github.com/Xinyuan-LilyGO/TTGO-T-Display + alt1_st7789[] = { // Init commands for 7789 screens Alternative 1 + 21, // 21 commands in list: + ST77XX_SLPOUT, ST_CMD_DELAY, // 1: Out of sleep mode, no args, w/delay + 120, // 120 ms delay + ST77XX_NORON, ST_CMD_DELAY, // 2: Normal display on, no args, w/delay + 10, // 10 ms delay + ST77XX_MADCTL, 1, // 3: Mem access ctrl (directions), 1 arg: + 0x08, // Row/col addr, bottom-top refresh + 0xB6, 2, // 4: ?JXL240 datasheet? + 0x0A, 0x82, + ST77XX_COLMOD, 1+ ST_CMD_DELAY, // 5: Set color mode, 1 arg + delay: + 0x55, // 16-bit color + 10, // 10 ms delay + ST77XX_PORCTRL, 5, // 6: Porch control, Framerate setting + 0x0c, 0x0c, 0x00, 0x33, 0x33, + ST77XX_GCTRL, 1, // 7: Gate control, Voltages VGH/VGL + 0x35, + ST77XX_VCOMS, 1, // 8: Power settings + 0x28, + ST77XX_LCMCTRL, 1, // 9: LCM Control + 0x0C, + ST77XX_VDVVRHEN, 2, // 10: VDV & VRH command enable + 0x01, 0xFF, + ST77XX_VRHS, 1, // 11: VRH set + 0x10, + ST77XX_VDVSET, 1, // 12: VDV set + 0x20, + ST77XX_FRCTR2, 1, // 13: FR Control 2 + 0x0F, + ST77XX_PWCTRL1, 2, // 14: Power Control 1 + 0xA4, 0xA1, + ST77XX_PVGAMCTRL, 14, // 15: Positive Voltage Gamma control + 0xD0, 0x00, 0x02, 0x07, 0x0A, 0x28, 0x32, 0x44, 0x42, 0x06, 0x0E, 0x12, 0x14, 0x17, + ST77XX_NVGAMCTRL, 14, // 16: Negative Voltage Gamma control + 0xD0, 0x00, 0x02, 0x07, 0x0A, 0x28, 0x31, 0x54, 0x47, 0x0E, 0x1C, 0x17, 0x1B, 0x1E, + ST77XX_INVON, ST_CMD_DELAY, // 17: hack + 10, + ST77XX_CASET , 4, // 18: Column addr set, 4 args, no delay: + 0x00, + 0, // XSTART = 0 + 0, + 240, // XEND = 240 + ST77XX_RASET , 4, // 19: Row addr set, 4 args, no delay: + 0x00, + 0, // YSTART = 0 + 320>>8, + 320&0xFF, // YEND = 320 + ST77XX_INVON, ST_CMD_DELAY, // 20: Normal display on, no args, w/delay + 10, // 10 ms delay + ST77XX_DISPON, ST_CMD_DELAY, // 21: Main screen turn on, no args, delay + 255 // 120 ms delay + }; + +static const uint8_t PROGMEM // Source: https://github.com/Bodmer/TFT_eSPI (ST7789_init.h, _NOT_ INIT_SEQUENCE_3) + alt2_st7789[] = { // Init commands for 7789 screens Alternative 2 + 21, // 21 commands in list: + ST77XX_SLPOUT, ST_CMD_DELAY, // 1: Out of sleep mode, no args, w/delay + 120, // 120 ms delay + ST77XX_NORON, ST_CMD_DELAY, // 2: Normal display on, no args, w/delay + 10, // 10 ms delay + ST77XX_MADCTL, 1, // 3: Mem access ctrl (directions), 1 arg: + 0x08, // Row/col addr, bottom-top refresh + 0xB6, 2, // 4: ?JXL240 datasheet? + 0x0A, 0x82, + ST77XX_RAMCTRL, 2, // 5: RAM control + 0x00, 0xE0, // 5 to 6-bit conversion: r0 = r5, b0 = b5 + ST77XX_COLMOD, 1+ ST_CMD_DELAY, // 6: Set color mode, 1 arg + delay: + 0x55, // 16-bit color + 10, // 10 ms delay + ST77XX_PORCTRL, 5, // 7: Porch control, Framerate setting + 0x0c, 0x0c, 0x00, 0x33, 0x33, + ST77XX_GCTRL, 1, // 8: Gate control, Voltages VGH/VGL + 0x35, + ST77XX_VCOMS, 1, // 9: Power settings + 0x28, + ST77XX_LCMCTRL, 1, // 10: LCM Control + 0x0C, + ST77XX_VDVVRHEN, 2, // 11: VDV & VRH command enable + 0x01, 0xFF, + ST77XX_VRHS, 1, // 12: VRH set + 0x10, + ST77XX_VDVSET, 1, // 13: VDV set + 0x20, + ST77XX_FRCTR2, 1, // 14: FR Control 2 + 0x0F, + ST77XX_PWCTRL1, 2, // 15: Power Control 1 + 0xA4, 0xA1, + ST77XX_PVGAMCTRL, 14, // 16: Positive Voltage Gamma control + 0xD0, 0x00, 0x02, 0x07, 0x0A, 0x28, 0x32, 0x44, 0x42, 0x06, 0x0E, 0x12, 0x14, 0x17, + ST77XX_NVGAMCTRL, 14, // 17: Negative Voltage Gamma control + 0xD0, 0x00, 0x02, 0x07, 0x0A, 0x28, 0x31, 0x54, 0x47, 0x0E, 0x1C, 0x17, 0x1B, 0x1E, + ST77XX_INVON, ST_CMD_DELAY, // 18: hack + 10, + ST77XX_CASET , 4, // 19: Column addr set, 4 args, no delay: + 0x00, + 0, // XSTART = 0 + 0, + 239, // XEND = 239 + ST77XX_RASET , 4, // 20: Row addr set, 4 args, no delay: + 0x00, + 0, // YSTART = 0 + 319>>8, + 319&0xFF, // YEND = 319 + ST77XX_DISPON, ST_CMD_DELAY, // 21: Main screen turn on, no args, delay + 120 // 120 ms delay + }; + +static const uint8_t PROGMEM // Source: https://github.com/Bodmer/TFT_eSPI (ST7789_init.h, _WITH_ INIT_SEQUENCE_3) + alt3_st7789[] = { // Init commands for 7789 screens Alternative 2 + 18, // 18 commands in list: + ST77XX_SLPOUT, ST_CMD_DELAY, // 1: Out of sleep mode, no args, w/delay + 120, // 120 ms delay + ST77XX_NORON, ST_CMD_DELAY, // 2: Normal display on, no args, w/delay + 10, // 10 ms delay + ST77XX_MADCTL, 1, // 3: Mem access ctrl (directions), 1 arg: + 0x08, // Row/col addr, bottom-top refresh + 0xB6, 2, // 4: ?JXL240 datasheet? + 0x0A, 0x82, + ST77XX_COLMOD, 1+ ST_CMD_DELAY, // 5: Set color mode, 1 arg + delay: + 0x55, // 16-bit color + 10, // 10 ms delay + ST77XX_PORCTRL, 5, // 6: Porch control, Framerate setting + 0x0c, 0x0c, 0x00, 0x33, 0x33, + ST77XX_GCTRL, 1, // 7: Gate control, Voltages VGH/VGL + 0x75, + ST77XX_VCOMS, 1, // 8: Power settings + 0x28, + ST77XX_LCMCTRL, 1, // 9: LCM Control + 0x2C, + ST77XX_VDVVRHEN, 1, // 10: VDV & VRH command enable + 0x01, + ST77XX_VRHS, 1, // 11: VRH set + 0x1F, + ST77XX_FRCTR2, 1, // 12: FR Control 2 + 0x13, + ST77XX_PWCTRL1, 1, // 13: Power Control 1 + 0xA7, + ST77XX_PWCTRL1, 2, // 14: Power Control 1 + 0xA4, 0xA1, + 0xD6, 1, // 15: ? + 0xA1, + ST77XX_PVGAMCTRL, 14, // 16: Positive Voltage Gamma control + 0xF0, 0x05, 0x0A, 0x06, 0x06, 0x03, 0x2B, 0x32, 0x43, 0x36, 0x11, 0x10, 0x2B, 0x32, + ST77XX_NVGAMCTRL, 14, // 17: Negative Voltage Gamma control + 0xF0, 0x08, 0x0C, 0x0B, 0x09, 0x24, 0x2B, 0x22, 0x43, 0x38, 0x15, 0x16, 0x2F, 0x37, + // ST77XX_CASET , 4, // 18: Column addr set, 4 args, no delay: + // 0x00, + // 0, // XSTART = 0 + // 0, + // 239, // XEND = 239 + // ST77XX_RASET , 4, // 19: Row addr set, 4 args, no delay: + // 0x00, + // 0, // YSTART = 0 + // 319>>8, + // 319&0xFF, // YEND = 319 + ST77XX_DISPON, ST_CMD_DELAY, // 18: Main screen turn on, no args, delay + 120 // 120 ms delay + }; +#endif // if ST7789_EXTRA_INIT // clang-format on /**************************************************************************/ @@ -88,7 +249,7 @@ static const uint8_t PROGMEM the defines only, the values are NOT the same!) */ /**************************************************************************/ -void Adafruit_ST7789::init(uint16_t width, uint16_t height, uint8_t mode) { +void Adafruit_ST7789::init(uint16_t width, uint16_t height, uint8_t mode, uint8_t init_seq) { // Save SPI data mode. commonInit() calls begin() (in Adafruit_ST77xx.cpp), // which in turn calls initSPI() (in Adafruit_SPITFT.cpp), passing it the // value of spiMode. It's done this way because begin() really should not @@ -101,6 +262,8 @@ void Adafruit_ST7789::init(uint16_t width, uint16_t height, uint8_t mode) { // (Might get added similarly to other display types as needed on a // case-by-case basis.) + _init_seq = init_seq; + commonInit(NULL); if (width < 240) { @@ -123,7 +286,18 @@ void Adafruit_ST7789::init(uint16_t width, uint16_t height, uint8_t mode) { windowWidth = width; windowHeight = height; - displayInit(generic_st7789); + const uint8_t *init_ = generic_st7789; + + #if ST7789_EXTRA_INIT + if (1 == _init_seq) { + init_ = alt1_st7789; + } else if (2 == _init_seq) { + init_ = alt2_st7789; + } else if (3 == _init_seq) { + init_ = alt3_st7789; + } + #endif // if ST7789_EXTRA_INIT + displayInit(init_); setRotation(0); } @@ -140,28 +314,64 @@ void Adafruit_ST7789::setRotation(uint8_t m) { switch (rotation) { case 0: - madctl = ST77XX_MADCTL_MX | ST77XX_MADCTL_MY | ST77XX_MADCTL_RGB; + #if ST7789_EXTRA_INIT + if (_init_seq > 0) { + madctl = ST77XX_MADCTL_BGR; + _colstart = 52; + _rowstart = 40; + } else + #endif // if ST7789_EXTRA_INIT + { + madctl = ST77XX_MADCTL_MX | ST77XX_MADCTL_MY | ST77XX_MADCTL_RGB; + } _xstart = _colstart; _ystart = _rowstart; _width = windowWidth; _height = windowHeight; break; case 1: - madctl = ST77XX_MADCTL_MY | ST77XX_MADCTL_MV | ST77XX_MADCTL_RGB; + #if ST7789_EXTRA_INIT + if (_init_seq > 0) { + madctl = ST77XX_MADCTL_MX | ST77XX_MADCTL_MV | ST77XX_MADCTL_BGR; + _colstart = 40; + _rowstart = 53; + } else + #endif // if ST7789_EXTRA_INIT + { + madctl = ST77XX_MADCTL_MY | ST77XX_MADCTL_MV | ST77XX_MADCTL_RGB; + } _xstart = _rowstart; _ystart = _colstart; _height = windowWidth; _width = windowHeight; break; case 2: - madctl = ST77XX_MADCTL_RGB; + #if ST7789_EXTRA_INIT + if (_init_seq > 0) { + madctl = ST77XX_MADCTL_MX | ST77XX_MADCTL_MY | ST77XX_MADCTL_RGB; + _colstart2 = 53; + _rowstart2 = 40; + } else + #endif // if ST7789_EXTRA_INIT + { + madctl = ST77XX_MADCTL_RGB; + } _xstart = _colstart2; _ystart = _rowstart2; _width = windowWidth; _height = windowHeight; break; case 3: - madctl = ST77XX_MADCTL_MX | ST77XX_MADCTL_MV | ST77XX_MADCTL_RGB; + #if ST7789_EXTRA_INIT + if (_init_seq > 0) { + madctl = ST77XX_MADCTL_MV | ST77XX_MADCTL_MY | ST77XX_MADCTL_BGR; + _colstart2 = 40; + _rowstart2 = 52; + } else + #endif // if ST7789_EXTRA_INIT + { + madctl = ST77XX_MADCTL_MX | ST77XX_MADCTL_MV | ST77XX_MADCTL_RGB; + } _xstart = _rowstart2; _ystart = _colstart2; _height = windowWidth; diff --git a/lib/Adafruit_ST77xx/Adafruit_ST7789.h b/lib/Adafruit_ST77xx/Adafruit_ST7789.h index 7fe09d6f02..4714a9968d 100644 --- a/lib/Adafruit_ST77xx/Adafruit_ST7789.h +++ b/lib/Adafruit_ST77xx/Adafruit_ST7789.h @@ -3,6 +3,22 @@ #include "Adafruit_ST77xx.h" +/** + * 2024-03-09 tonhuisman: Add additional initialization sequences for ST7789 displays, with the intention to get 'm working + * on some devices that seem to use peculiarly configured hardware like LiliGO TTGO T-Display (16MB flash), + * and possibly the T-Display S3 + * By default only enabled on ESP32, unless -D ST7789_EXTRA_INIT=1 is defined, f.e. via the build script + */ + +#ifndef ST7789_EXTRA_INIT // Enable setting from 'outside', like Platformio.ini +# ifdef ESP8266 +# define ST7789_EXTRA_INIT 0 +# endif // ifdef ESP8266 +# ifdef ESP32 +# define ST7789_EXTRA_INIT 1 +# endif // ifdef ESP32 +#endif + /// Subclass of ST77XX type display for ST7789 TFT Driver class Adafruit_ST7789 : public Adafruit_ST77xx { public: @@ -14,7 +30,7 @@ class Adafruit_ST7789 : public Adafruit_ST77xx { #endif // end !ESP8266 void setRotation(uint8_t m); - void init(uint16_t width, uint16_t height, uint8_t spiMode = SPI_MODE0); + void init(uint16_t width, uint16_t height, uint8_t spiMode = SPI_MODE0, uint8_t init_seq = 0u); protected: uint8_t _colstart2 = 0, ///< Offset from the right @@ -23,6 +39,7 @@ class Adafruit_ST7789 : public Adafruit_ST77xx { private: uint16_t windowWidth; uint16_t windowHeight; + uint8_t _init_seq = 0u; }; #endif // _ADAFRUIT_ST7789H_ diff --git a/lib/Adafruit_ST77xx/Adafruit_ST77xx.h b/lib/Adafruit_ST77xx/Adafruit_ST77xx.h index fcf0c6f6e8..9a299b51f9 100644 --- a/lib/Adafruit_ST77xx/Adafruit_ST77xx.h +++ b/lib/Adafruit_ST77xx/Adafruit_ST77xx.h @@ -33,8 +33,10 @@ #define ST7735_TFTWIDTH_128 128 // for 1.44 and mini #define ST7735_TFTWIDTH_80 80 // for mini +#define ST7735_TFTWIDTH_135 135 #define ST7735_TFTHEIGHT_128 128 // for 1.44" display #define ST7735_TFTHEIGHT_160 160 // for 1.8" and mini display +#define ST7735_TFTHEIGHT_240 240 #define ST_CMD_DELAY 0x80 // special signifier for command lists @@ -63,11 +65,48 @@ #define ST77XX_MADCTL 0x36 #define ST77XX_COLMOD 0x3A +#define ST77XX_RAMCTRL 0xB0 // RAM control +#define ST77XX_RGBCTRL 0xB1 // RGB control +#define ST77XX_PORCTRL 0xB2 // Porch control +#define ST77XX_FRCTRL1 0xB3 // Frame rate control +#define ST77XX_PARCTRL 0xB5 // Partial mode control +#define ST77XX_GCTRL 0xB7 // Gate control +#define ST77XX_GTADJ 0xB8 // Gate on timing adjustment +#define ST77XX_DGMEN 0xBA // Digital gamma enable +#define ST77XX_VCOMS 0xBB // VCOMS setting +#define ST77XX_LCMCTRL 0xC0 // LCM control +#define ST77XX_IDSET 0xC1 // ID setting +#define ST77XX_VDVVRHEN 0xC2 // VDV and VRH command enable +#define ST77XX_VRHS 0xC3 // VRH set +#define ST77XX_VDVSET 0xC4 // VDV setting +#define ST77XX_VCMOFSET 0xC5 // VCOMS offset set +#define ST77XX_FRCTR2 0xC6 // FR Control 2 +#define ST77XX_CABCCTRL 0xC7 // CABC control +#define ST77XX_REGSEL1 0xC8 // Register value section 1 +#define ST77XX_REGSEL2 0xCA // Register value section 2 +#define ST77XX_PWMFRSEL 0xCC // PWM frequency selection +#define ST77XX_PWCTRL1 0xD0 // Power control 1 +#define ST77XX_VAPVANEN 0xD2 // Enable VAP/VAN signal output +#define ST77XX_CMD2EN 0xDF // Command 2 enable +#define ST77XX_PVGAMCTRL 0xE0 // Positive voltage gamma control +#define ST77XX_NVGAMCTRL 0xE1 // Negative voltage gamma control +#define ST77XX_DGMLUTR 0xE2 // Digital gamma look-up table for red +#define ST77XX_DGMLUTB 0xE3 // Digital gamma look-up table for blue +#define ST77XX_GATECTRL 0xE4 // Gate control +#define ST77XX_SPI2EN 0xE7 // SPI2 enable +#define ST77XX_PWCTRL2 0xE8 // Power control 2 +#define ST77XX_EQCTRL 0xE9 // Equalize time control +#define ST77XX_PROMCTRL 0xEC // Program control +#define ST77XX_PROMEN 0xFA // Program mode enable +#define ST77XX_NVMSET 0xFC // NVM setting +#define ST77XX_PROMACT 0xFE // Program action + #define ST77XX_MADCTL_MY 0x80 #define ST77XX_MADCTL_MX 0x40 #define ST77XX_MADCTL_MV 0x20 #define ST77XX_MADCTL_ML 0x10 #define ST77XX_MADCTL_RGB 0x00 +#define ST77XX_MADCTL_BGR 0x08 #define ST77XX_RDID1 0xDA #define ST77XX_RDID2 0xDB diff --git a/lib/ESPEasySerial/Port_ESPEasySerial_USB_HWCDC.cpp b/lib/ESPEasySerial/Port_ESPEasySerial_USB_HWCDC.cpp index 9d4870f52e..5c6fa8bdbc 100644 --- a/lib/ESPEasySerial/Port_ESPEasySerial_USB_HWCDC.cpp +++ b/lib/ESPEasySerial/Port_ESPEasySerial_USB_HWCDC.cpp @@ -58,40 +58,46 @@ Port_ESPEasySerial_USB_HWCDC_t::Port_ESPEasySerial_USB_HWCDC_t(const ESPEasySeri // USB.begin(); if (_hwcdc_serial != nullptr) { - _config.rxBuffSize = _hwcdc_serial->setRxBufferSize(_config.rxBuffSize); - _config.txBuffSize = _hwcdc_serial->setRxBufferSize(_config.txBuffSize); + // _hwcdc_serial->end(); + + // _config.rxBuffSize = _hwcdc_serial->setRxBufferSize(_config.rxBuffSize); + // _config.txBuffSize = _hwcdc_serial->setTxBufferSize(_config.txBuffSize); // See: https://github.com/espressif/arduino-esp32/issues/9043 - _hwcdc_serial->setTxTimeoutMs(0); // sets no timeout when trying to write to USB HW CDC + // _hwcdc_serial->setTxTimeoutMs(0); // sets no timeout when trying to write to USB HW CDC - _hwcdc_serial->begin(); + // _hwcdc_serial->begin(); // _hwcdc_serial->onEvent(hwcdcEventCallback); } } -Port_ESPEasySerial_USB_HWCDC_t::~Port_ESPEasySerial_USB_HWCDC_t() {} +Port_ESPEasySerial_USB_HWCDC_t::~Port_ESPEasySerial_USB_HWCDC_t() { + if (_hwcdc_serial != nullptr) { + // _hwcdc_serial->end(); + } +} void Port_ESPEasySerial_USB_HWCDC_t::begin(unsigned long baud) { _config.baud = baud; - /* - if (_hwcdc_serial != nullptr) { - _config.rxBuffSize = _hwcdc_serial->setRxBufferSize(_config.rxBuffSize); - _config.txBuffSize = _hwcdc_serial->setRxBufferSize(_config.txBuffSize); - _hwcdc_serial->begin(); - delay(10); - _hwcdc_serial->onEvent(hwcdcEventCallback); - delay(1); - } - */ + + if (_hwcdc_serial != nullptr) { + _config.rxBuffSize = _hwcdc_serial->setRxBufferSize(_config.rxBuffSize); + _config.txBuffSize = _hwcdc_serial->setTxBufferSize(_config.txBuffSize); + _hwcdc_serial->begin(); + delay(10); + + // _hwcdc_serial->onEvent(hwcdcEventCallback); + delay(1); + } } void Port_ESPEasySerial_USB_HWCDC_t::end() { // Disabled for now // See: https://github.com/espressif/arduino-esp32/issues/8224 if (_hwcdc_serial != nullptr) { - _hwcdc_serial->end(); + // _hwcdc_serial->end(); } } @@ -204,5 +210,4 @@ bool Port_ESPEasySerial_USB_HWCDC_t::setRS485Mode(int8_t rtsPin, bool enableColl return false; } - #endif // if USES_HWCDC diff --git a/lib/ESPEasySerial/Port_ESPEasySerial_USB_HWCDC.h b/lib/ESPEasySerial/Port_ESPEasySerial_USB_HWCDC.h index b9801fe8cf..a71bfd411c 100644 --- a/lib/ESPEasySerial/Port_ESPEasySerial_USB_HWCDC.h +++ b/lib/ESPEasySerial/Port_ESPEasySerial_USB_HWCDC.h @@ -13,7 +13,7 @@ class Port_ESPEasySerial_USB_HWCDC_t : public Port_ESPEasySerial_base { public: - Port_ESPEasySerial_USB_HWCDC_t(const ESPEasySerialConfig& config); + explicit Port_ESPEasySerial_USB_HWCDC_t(const ESPEasySerialConfig& config); virtual ~Port_ESPEasySerial_USB_HWCDC_t(); @@ -44,11 +44,7 @@ class Port_ESPEasySerial_USB_HWCDC_t : public Port_ESPEasySerial_base { private: -# if ARDUINO_USB_CDC_ON_BOOT // Serial used for USB CDC - HWCDC *_hwcdc_serial = &Serial; -# else // if ARDUINO_USB_CDC_ON_BOOT - HWCDC *_hwcdc_serial = &USBSerial; -# endif // if ARDUINO_USB_CDC_ON_BOOT + HWCDC *_hwcdc_serial= nullptr; }; diff --git a/lib/HeatpumpIR/ZHJG01HeatpumpIR.cpp b/lib/HeatpumpIR/ZHJG01HeatpumpIR.cpp index 1a37066d5a..5d440caa3e 100644 --- a/lib/HeatpumpIR/ZHJG01HeatpumpIR.cpp +++ b/lib/HeatpumpIR/ZHJG01HeatpumpIR.cpp @@ -108,16 +108,16 @@ void ZHJG01HeatpumpIR::sendZHJG01(IRSender& IR, /******************************************************************************** * Byte[0]: Turbo, Eco, Fan, Vertical Swing - * TURBO ON: B0x1xxxxx - * ECO ON: B0x0xxxxx - * TURBO/ECO OFF: B1xxxxxxx - * FAN1: Bx00xxxxx - * FAN2: Bx01xxxxx - * FAN3: Bx10xxxxx - * FAN AUTO: Bx11xxxxx - * VERTICAL FIXED: Bxxx01xxx - * VERTICAL SWING: Bxxx10xxx - * VERTICAL WIND: Bxxx11xxx + * TURBO ON: 0b0x1xxxxx + * ECO ON: 0b0x0xxxxx + * TURBO/ECO OFF: 0b1xxxxxxx + * FAN1: 0bx00xxxxx + * FAN2: 0bx01xxxxx + * FAN3: 0bx10xxxxx + * FAN AUTO: 0bx11xxxxx + * VERTICAL FIXED: 0bxxx01xxx + * VERTICAL SWING: 0bxxx10xxx + * VERTICAL WIND: 0bxxx11xxx *******************************************************************************/ ZHJG01Template[1] = fanSpeed | swingV; ZHJG01Template[0] = ~ ZHJG01Template[1]; @@ -125,13 +125,13 @@ void ZHJG01HeatpumpIR::sendZHJG01(IRSender& IR, /******************************************************************************** * Byte[2]: Temp, Power, Mode * TEMP: Bttttxxxx - * POWER ON: Bxxxx0xxx - * POWER OFF: Bxxxx1xxx - * MODE HEAT: Bxxxxx011 - * MODE VENT: Bxxxxx100 - * MODE DRY: Bxxxxx101 - * MODE COOL: Bxxxxx110 - * MODE AUTO: Bxxxxx111 + * POWER ON: 0bxxxx0xxx + * POWER OFF: 0bxxxx1xxx + * MODE HEAT: 0bxxxxx011 + * MODE VENT: 0bxxxxx100 + * MODE DRY: 0bxxxxx101 + * MODE COOL: 0bxxxxx110 + * MODE AUTO: 0bxxxxx111 *******************************************************************************/ uint8_t tempBits = ((temperature - 17) << 4) & 0b11110000; diff --git a/lib/HeatpumpIR/ZHJG01HeatpumpIR.h b/lib/HeatpumpIR/ZHJG01HeatpumpIR.h index c91f2d007e..e88d66fdd6 100644 --- a/lib/HeatpumpIR/ZHJG01HeatpumpIR.h +++ b/lib/HeatpumpIR/ZHJG01HeatpumpIR.h @@ -22,14 +22,14 @@ * Every UNeven Byte (01,03,05,07 and 09) hold a checksum of the corresponding * command by inverting the bits, for example: * - * The identifier byte[0] = 0xD5 = B1101 0101 - * The checksum byte[1] = 0x2A = B0010 1010 + * The identifier byte[0] = 0xD5 = 0b1101 0101 + * The checksum byte[1] = 0x2A = 0b0010 1010 * * So, you can check the message by: * - inverting the bits of the checksum byte with the corresponding command, they * should be the same, or * - Summing up the checksum byte and the corresponding command, - * they should always add up to 0xFF = B11111111 = 255 + * they should always add up to 0xFF = 0b11111111 = 255 * * ****************************************************************************** * Written by: Abílio Costa diff --git a/lib/HeatpumpIR/ZHLT01HeatpumpIR.cpp b/lib/HeatpumpIR/ZHLT01HeatpumpIR.cpp index 3030183e8a..e1902d1bea 100644 --- a/lib/HeatpumpIR/ZHLT01HeatpumpIR.cpp +++ b/lib/HeatpumpIR/ZHLT01HeatpumpIR.cpp @@ -149,29 +149,29 @@ void ZHLT01HeatpumpIR::sendZHLT01(IRSender& IR, uint8_t powerMode, /******************************************************************************** * Byte[07]: POWER, FAN, SLEEP, HORIZONTAL, VERTICAL - * POWER ON: B0xxxxx1x - * POWER OFF: B0xxxxx0x - * VERTICAL SWING: B0xxx01xx - * VERTICAL WIND: B0xxx00xx - * VERTICAL FIXED: B0xxx10xx - * HORIZONTAL SWING: B0xx0xxxx - * HORIZONTAL OFF: B0xx1xxxx - * FAN AUTO: B000xxxx0 - * FAN SILENT: B000xxxx1 - * FAN3: B001xxxx0 - * FAN2: B010xxxx0 - * FAN1: B011xxxx0 + * POWER ON: 0b0xxxxx1x + * POWER OFF: 0b0xxxxx0x + * VERTICAL SWING: 0b0xxx01xx + * VERTICAL WIND: 0b0xxx00xx + * VERTICAL FIXED: 0b0xxx10xx + * HORIZONTAL SWING: 0b0xx0xxxx + * HORIZONTAL OFF: 0b0xx1xxxx + * FAN AUTO: 0b000xxxx0 + * FAN SILENT: 0b000xxxx1 + * FAN3: 0b001xxxx0 + * FAN2: 0b010xxxx0 + * FAN1: 0b011xxxx0 *******************************************************************************/ ZHLT01Template[7] = fanSpeed | powerMode | swingV | swingH; ZHLT01Template[6] = ~ ZHLT01Template[7]; /******************************************************************************** * Byte[09]: Mode, Temperature - * MODE AUTO: B000xxxxx - * MODE COOL: B001xxxxx - * MODE VENT: B011xxxxx - * MODE DRY: B010xxxxx - * MODE HEAT: B100xxxxx + * MODE AUTO: 0b000xxxxx + * MODE COOL: 0b001xxxxx + * MODE VENT: 0b011xxxxx + * MODE DRY: 0b010xxxxx + * MODE HEAT: 0b100xxxxx * Temperature is determined by bit0-4: * 0x00 = 16C * 0x10 = 32C diff --git a/lib/HeatpumpIR/ZHLT01HeatpumpIR.h b/lib/HeatpumpIR/ZHLT01HeatpumpIR.h index 33e9623e4c..d402afd876 100644 --- a/lib/HeatpumpIR/ZHLT01HeatpumpIR.h +++ b/lib/HeatpumpIR/ZHLT01HeatpumpIR.h @@ -41,14 +41,14 @@ * Every EVEN Byte (00,02,04,06,08 and 10) holds a checksum of the corresponding * command-, or identifier-byte by _inverting_ the bits, for example: * - * The identifier byte[11] = 0xD5 = B1101 0101 - * The checksum byte[10] = 0x2A = B0010 1010 + * The identifier byte[11] = 0xD5 = 0b1101 0101 + * The checksum byte[10] = 0x2A = 0b0010 1010 * * So, you can check the message by: * - inverting the bits of the checksum byte with the corresponding command-, or * identifier byte, they should me the same, or * - Summing up the checksum byte and the corresponding command-, or identifier byte, - * they should always add up to 0xFF = B11111111 = 255 + * they should always add up to 0xFF = 0b11111111 = 255 * * Control bytes: * [01] - Timer (1-24 hours, Off) diff --git a/lib/IRremoteESP8266/examples/LGACSend/LGACSend.ino b/lib/IRremoteESP8266/examples/LGACSend/LGACSend.ino index 9139983c91..1625232eee 100644 --- a/lib/IRremoteESP8266/examples/LGACSend/LGACSend.ino +++ b/lib/IRremoteESP8266/examples/LGACSend/LGACSend.ino @@ -75,7 +75,7 @@ void Ac_Activate(unsigned int temperature, unsigned int air_flow, // calculating using other values unsigned int ac_msbits7 = (ac_msbits3 + ac_msbits4 + ac_msbits5 + - ac_msbits6) & B00001111; + ac_msbits6) & 0b00001111; ac_code_to_sent = ac_msbits1 << 4; ac_code_to_sent = (ac_code_to_sent + ac_msbits2) << 4; ac_code_to_sent = (ac_code_to_sent + ac_msbits3) << 4; diff --git a/lib/IRremoteESP8266/src/ir_Gree.cpp b/lib/IRremoteESP8266/src/ir_Gree.cpp index 2c44cfe523..38c0325fcf 100644 --- a/lib/IRremoteESP8266/src/ir_Gree.cpp +++ b/lib/IRremoteESP8266/src/ir_Gree.cpp @@ -715,7 +715,7 @@ bool IRrecv::decodeGree(decode_results* results, uint16_t offset, if (used == 0) return false; offset += used; - // Block #1 footer (3 bits, B010) + // Block #1 footer (3 bits, 0b010) match_result_t data_result; data_result = matchData(&(results->rawbuf[offset]), kGreeBlockFooterBits, kGreeBitMark, kGreeOneSpace, kGreeBitMark, diff --git a/lib/IRremoteESP8266/src/ir_Kelvinator.cpp b/lib/IRremoteESP8266/src/ir_Kelvinator.cpp index c44f7c6839..9d23384dbf 100644 --- a/lib/IRremoteESP8266/src/ir_Kelvinator.cpp +++ b/lib/IRremoteESP8266/src/ir_Kelvinator.cpp @@ -540,7 +540,7 @@ bool IRrecv::decodeKelvinator(decode_results *results, uint16_t offset, offset += used; pos += 4; - // Command data footer (3 bits, B010) + // Command data footer (3 bits, 0b010) data_result = matchData( &(results->rawbuf[offset]), kKelvinatorCmdFooterBits, kKelvinatorBitMark, kKelvinatorOneSpace, diff --git a/lib/ImprovWiFi/src/ImprovTypes.h b/lib/ImprovWiFi/src/ImprovTypes.h index 1a8a6abebc..3e77a7cf3b 100644 --- a/lib/ImprovWiFi/src/ImprovTypes.h +++ b/lib/ImprovWiFi/src/ImprovTypes.h @@ -32,6 +32,8 @@ enum Error : uint8_t { ERROR_UNKNOWN_RPC = 0x02, ERROR_UNABLE_TO_CONNECT = 0x03, ERROR_NOT_AUTHORIZED = 0x04, + ERROR_INVALID_CHECKSUM = 0x05, + ERROR_EMPTY_SSID = 0x06, ERROR_UNKNOWN = 0xFF, }; diff --git a/lib/ImprovWiFi/src/ImprovWiFiLibrary.cpp b/lib/ImprovWiFi/src/ImprovWiFiLibrary.cpp index 68e240f4ca..790ab47f9c 100644 --- a/lib/ImprovWiFi/src/ImprovWiFiLibrary.cpp +++ b/lib/ImprovWiFi/src/ImprovWiFiLibrary.cpp @@ -71,7 +71,7 @@ bool ImprovWiFi::onCommandCallback(ImprovTypes::ImprovCommand cmd) { if (cmd.ssid.empty()) { - setError(ImprovTypes::Error::ERROR_INVALID_RPC); + setError(ImprovTypes::Error::ERROR_EMPTY_SSID); break; } @@ -298,17 +298,19 @@ ImprovTypes::ParseState ImprovWiFi::parseImprovSerial(size_t position, uint8_t b if (position == (8u + data_len + 1u)) { + /* if (computeChecksum(buffer, position - 1) != byte) { _position = 0; - onErrorCallback(ImprovTypes::Error::ERROR_INVALID_RPC); + onErrorCallback(ImprovTypes::Error::ERROR_INVALID_CHECKSUM); return ImprovTypes::ParseState::INVALID; } + */ if (type == ImprovTypes::ImprovSerialType::TYPE_RPC) { _position = 0; - auto command = parseImprovData(&buffer[9], data_len, false); + auto command = parseImprovData(&buffer[9], data_len + 1, false); return onCommandCallback(command) ? ImprovTypes::ParseState::VALID_COMPLETE : ImprovTypes::ParseState::INVALID; } } @@ -332,19 +334,23 @@ ImprovTypes::ImprovCommand ImprovWiFi::parseImprovData(const uint8_t *data, size } const ImprovTypes::Command command = (ImprovTypes::Command)data[0]; const uint8_t data_length = data[1]; + const uint8_t data_start = 2; + const size_t data_end = data_start + data_length; +// if (data_end >= length) if (data_length != (length - 2 - check_checksum)) { - return improv_command; +// return improv_command; } if (check_checksum) { - const uint8_t checksum = data[length - 1]; + const uint8_t checksum = data[data_end]; - if (computeChecksum(data, length - 1) != checksum) + if (computeChecksum(data, data_end - 1) != checksum) { improv_command.command = ImprovTypes::Command::BAD_CHECKSUM; + setError(ImprovTypes::Error::ERROR_INVALID_CHECKSUM); return improv_command; } } @@ -363,7 +369,7 @@ ImprovTypes::ImprovCommand ImprovWiFi::parseImprovData(const uint8_t *data, size const size_t pass_start = ssid_end + 1; const size_t pass_end = pass_start + pass_length; - if (pass_end >= length) { + if (pass_end > length) { return improv_command; } @@ -394,6 +400,7 @@ void ImprovWiFi::setError(ImprovTypes::Error error) const std::vector response = { error }; send(ImprovTypes::TYPE_ERROR_STATE, response); + onErrorCallback(error); } void ImprovWiFi::sendResponse(const std::vector& response) diff --git a/lib/LiquidCrystal_I2C/LiquidCrystal_I2C.h b/lib/LiquidCrystal_I2C/LiquidCrystal_I2C.h index f7c7d132c3..5f82ae504d 100755 --- a/lib/LiquidCrystal_I2C/LiquidCrystal_I2C.h +++ b/lib/LiquidCrystal_I2C/LiquidCrystal_I2C.h @@ -48,9 +48,9 @@ #define LCD_BACKLIGHT 0x08 #define LCD_NOBACKLIGHT 0x00 -#define En B00000100 // Enable bit -#define Rw B00000010 // Read/Write bit -#define Rs B00000001 // Register select bit +#define En 0b00000100 // Enable bit +#define Rw 0b00000010 // Read/Write bit +#define Rs 0b00000001 // Register select bit class LiquidCrystal_I2C : public Print { public: diff --git a/lib/RAK12019_LTR390/src/UVlight_LTR390.cpp b/lib/RAK12019_LTR390/src/UVlight_LTR390.cpp index e06a2fec03..31a8c17e9d 100644 --- a/lib/RAK12019_LTR390/src/UVlight_LTR390.cpp +++ b/lib/RAK12019_LTR390/src/UVlight_LTR390.cpp @@ -96,7 +96,7 @@ bool UVlight_LTR390::init(bool doReset) { bool UVlight_LTR390::reset(void) { uint8_t readData = readRegister(LTR390_MAIN_CTRL); - readData |= B00010000; + readData |= 0b00010000; writeRegister(LTR390_MAIN_CTRL, readData); delay(10); diff --git a/lib/SparkFun_ADXL345_Arduino_Library/src/SparkFun_ADXL345.cpp b/lib/SparkFun_ADXL345_Arduino_Library/src/SparkFun_ADXL345.cpp index 928d8d3309..36e14a92bf 100644 --- a/lib/SparkFun_ADXL345_Arduino_Library/src/SparkFun_ADXL345.cpp +++ b/lib/SparkFun_ADXL345_Arduino_Library/src/SparkFun_ADXL345.cpp @@ -199,7 +199,7 @@ void ADXL345::getRangeSetting(byte *rangeSetting) { byte _b; readFrom(ADXL345_DATA_FORMAT, 1, &_b); - *rangeSetting = _b & B00000011; + *rangeSetting = _b & 0b00000011; } void ADXL345::setRangeSetting(int val) { @@ -208,22 +208,22 @@ void ADXL345::setRangeSetting(int val) { switch (val) { case 2: - _s = B00000000; + _s = 0b00000000; break; case 4: - _s = B00000001; + _s = 0b00000001; break; case 8: - _s = B00000010; + _s = 0b00000010; break; case 16: - _s = B00000011; + _s = 0b00000011; break; default: - _s = B00000000; + _s = 0b00000000; } readFrom(ADXL345_DATA_FORMAT, 1, &_b); - _s |= (_b & B11101100); + _s |= (_b & 0b11101100); writeTo(ADXL345_DATA_FORMAT, _s); } @@ -700,7 +700,7 @@ double ADXL345::getRate() { byte _b; readFrom(ADXL345_BW_RATE, 1, &_b); - _b &= B00001111; + _b &= 0b00001111; return (pow(2, ((int)_b) - 6)) * 6.25; } @@ -716,7 +716,7 @@ void ADXL345::setRate(double rate) { if (r <= 9) { readFrom(ADXL345_BW_RATE, 1, &_b); - _s = (byte)(r + 6) | (_b & B11110000); + _s = (byte)(r + 6) | (_b & 0b11110000); writeTo(ADXL345_BW_RATE, _s); } } diff --git a/lib/esp8266-oled-ssd1306/OLED_SSD1306_SH1106_images.h b/lib/esp8266-oled-ssd1306/OLED_SSD1306_SH1106_images.h index 3595e65609..7e9d95bb8c 100644 --- a/lib/esp8266-oled-ssd1306/OLED_SSD1306_SH1106_images.h +++ b/lib/esp8266-oled-ssd1306/OLED_SSD1306_SH1106_images.h @@ -14,25 +14,25 @@ const char espeasy_logo_bits[] PROGMEM= { 0x3e, 0x3c, 0x00, 0x3f, 0x1e, 0x1c, 0x00, 0x1e, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; const char activeSymbole[] PROGMEM = { - B00000000, - B00000000, - B00011000, - B00100100, - B01000010, - B01000010, - B00100100, - B00011000 + 0b00000000, + 0b00000000, + 0b00011000, + 0b00100100, + 0b01000010, + 0b01000010, + 0b00100100, + 0b00011000 }; const char inactiveSymbole[] PROGMEM = { - B00000000, - B00000000, - B00000000, - B00000000, - B00011000, - B00011000, - B00000000, - B00000000 + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00011000, + 0b00011000, + 0b00000000, + 0b00000000 }; #endif diff --git a/platformio.ini b/platformio.ini index 1024041df2..0a26179810 100644 --- a/platformio.ini +++ b/platformio.ini @@ -29,6 +29,7 @@ extra_configs = ;default_envs = normal_ESP32_4M default_envs = max_ESP32_16M8M_LittleFS +;default_envs = normal_ESP32c6_4M316k_LittleFS_CDC ; default_envs = custom_ESP8266_4M1M ;default_envs = normal_ESP8266_4M1M @@ -75,7 +76,8 @@ build_flags = build_flags = -DMQTT_MAX_PACKET_SIZE=1024 [extra_scripts_default] -extra_scripts = pre:tools/pio/set-ci-defines.py +extra_scripts = pre:tools/pio/install-requirements.py + pre:tools/pio/set-ci-defines.py pre:tools/pio/generate-compiletime-defines.py tools/pio/copy_files.py diff --git a/platformio_core_defs.ini b/platformio_core_defs.ini index 70c35edabd..7b4f2798fc 100644 --- a/platformio_core_defs.ini +++ b/platformio_core_defs.ini @@ -208,16 +208,24 @@ lib_ignore = ; ESP_IDF 5.1 [core_esp32_IDF5_1__3_0_0] -;platform = https://github.com/Jason2866/platform-espressif32.git -platform = https://github.com/tasmota/platform-espressif32/releases/download/2024.02.10/platform-espressif32.zip +;platform = https://github.com/tasmota/platform-espressif32/releases/download/2024.02.10/platform-espressif32.zip ;platform_packages = -platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/2036/framework-arduinoespressif32-release_v5.1-246cad0.zip +;platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/2119/framework-arduinoespressif32-release_v5.1-a28d368.zip +;platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/2180/framework-arduinoespressif32-all-release_v5.1-735d740.zip +;platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/2189/framework-arduinoespressif32-all-release_v5.1-be1a568.zip +; Build with HWCDC fix. +;platform = https://github.com/Jason2866/platform-espressif32.git +;platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/2261/framework-arduinoespressif32-all-release_v5.1-11140aa.zip +platform = https://github.com/tasmota/platform-espressif32/releases/download/2024.04.11/platform-espressif32.zip +;platform_packages = +platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/2286/framework-arduinoespressif32-all-release_v5.1-11140aa.zip build_flags = -DESP32_STAGE -DESP_IDF_VERSION_MAJOR=5 -DLIBRARIES_NO_LOG=1 -DDISABLE_SC16IS752_SPI -DCONFIG_PM_ENABLE - -DCONFIG_LWIP_L2_TO_L3_COPY +; -DCONFIG_LWIP_L2_TO_L3_COPY +; -DETH_SPI_SUPPORTS_NO_IRQ=1 -DCONFIG_FREERTOS_USE_TICKLESS_IDLE=1 -DCONFIG_FREERTOS_IDLE_TIME_BEFORE_SLEEP=3 -DNEOPIXEL_ESP32_RMT_DEFAULT diff --git a/platformio_esp32_envs.ini b/platformio_esp32_envs.ini index cb558c0f08..6c24456eab 100644 --- a/platformio_esp32_envs.ini +++ b/platformio_esp32_envs.ini @@ -333,9 +333,9 @@ build_flags = ${esp32_custom_base_LittleFS.build_flags} [env:custom_IR_ESP32_4M316k_ETH] extends = env:custom_IR_ESP32_4M316k -build_flags = ${env:custom_ESP32_4M316k.build_flags} +build_flags = ${env:custom_IR_ESP32_4M316k.build_flags} -DFEATURE_ETHERNET=1 -extra_scripts = ${env:custom_ESP32_4M316k.extra_scripts} +extra_scripts = ${env:custom_IR_ESP32_4M316k.extra_scripts} [env:custom_IR_ESP32_16M8M_LittleFS_ETH] extends = esp32_common_LittleFS @@ -349,7 +349,7 @@ lib_ignore = ${esp32_always.lib_ignore} ESP32_ping ${esp32_common_LittleFS.lib_ignore} extra_scripts = ${esp32_common.extra_scripts} - pre:tools/pio/pre_custom_esp32.py + pre:tools/pio/pre_custom_esp32_IR.py pre:tools/pio/ir_build_check.py [env:normal_ESP32_4M316k_ETH] diff --git a/platformio_esp32_solo1.ini b/platformio_esp32_solo1.ini index 61afb5b4e8..0886c119dd 100644 --- a/platformio_esp32_solo1.ini +++ b/platformio_esp32_solo1.ini @@ -18,7 +18,7 @@ build_unflags = ${esp32_base.build_unflags} ; IDF 5.1.2 [esp32_solo1_common_LittleFS] extends = esp32_base_idf5 -platform_packages = framework-arduino-solo1 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/2038/framework-arduinoespressif32-solo1-release_v5.1-246cad0.zip +;platform_packages = framework-arduino-solo1 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/2038/framework-arduinoespressif32-solo1-release_v5.1-246cad0.zip build_flags = ${esp32_base_idf5.build_flags} -DFEATURE_ARDUINO_OTA=1 -DUSE_LITTLEFS diff --git a/platformio_esp32c3_envs.ini b/platformio_esp32c3_envs.ini index 36983a99c1..abffc558e6 100644 --- a/platformio_esp32c3_envs.ini +++ b/platformio_esp32c3_envs.ini @@ -44,7 +44,7 @@ build_flags = ${esp32c3_common.build_flags} lib_ignore = ${esp32_always.lib_ignore} ESP32_ping extra_scripts = ${esp32c3_common.extra_scripts} - pre:tools/pio/pre_custom_esp32.py + pre:tools/pio/pre_custom_esp32_IR.py pre:tools/pio/ir_build_check.py [env:custom_ESP32c3_4M316k_LittleFS_CDC] diff --git a/platformio_esp32c6_envs.ini b/platformio_esp32c6_envs.ini index 4d07f4a115..2889771b92 100644 --- a/platformio_esp32c6_envs.ini +++ b/platformio_esp32c6_envs.ini @@ -11,9 +11,6 @@ build_unflags = ${esp32_base_idf5.build_unflags} -fexceptions board_build.filesystem = littlefs lib_ignore = ${esp32_base_idf5.lib_ignore} - NeoPixelBus - NeoPixelBus_wrapper - Adafruit NeoMatrix via NeoPixelBus board = esp32c6cdc @@ -29,3 +26,27 @@ extra_scripts = ${esp32c6_common_LittleFS.extra_scripts} extends = esp32c6_common_LittleFS lib_ignore = ${esp32c6_common_LittleFS.lib_ignore} ${no_ir.lib_ignore} + + +[env:max_ESP32c6_8M1M_LittleFS_CDC_ETH] +extends = esp32c6_common_LittleFS +board = esp32c6cdc-8M +build_flags = ${esp32c6_common_LittleFS.build_flags} + -DFEATURE_ETHERNET=1 + -DFEATURE_ARDUINO_OTA=1 + -DPLUGIN_BUILD_MAX_ESP32 + -DPLUGIN_BUILD_IR_EXTENDED +extra_scripts = ${esp32c6_common_LittleFS.extra_scripts} + + +[env:max_ESP32c6_16M8M_LittleFS_CDC_ETH] +extends = esp32c6_common_LittleFS +board = esp32c6cdc-16M +build_flags = ${esp32c6_common_LittleFS.build_flags} + -DFEATURE_ETHERNET=1 + -DFEATURE_ARDUINO_OTA=1 + -DPLUGIN_BUILD_MAX_ESP32 + -DPLUGIN_BUILD_IR_EXTENDED +extra_scripts = ${esp32c6_common_LittleFS.extra_scripts} + + diff --git a/platformio_esp32s2_envs.ini b/platformio_esp32s2_envs.ini index 20fdaf4689..d97fd66415 100644 --- a/platformio_esp32s2_envs.ini +++ b/platformio_esp32s2_envs.ini @@ -62,7 +62,7 @@ build_flags = ${esp32s2_common.build_flags} lib_ignore = ${esp32_always.lib_ignore} ESP32_ping extra_scripts = ${esp32s2_common.extra_scripts} - pre:tools/pio/pre_custom_esp32.py + pre:tools/pio/pre_custom_esp32_IR.py pre:tools/pio/ir_build_check.py diff --git a/platformio_esp32s3_envs.ini b/platformio_esp32s3_envs.ini index a771e96ce1..284b717885 100644 --- a/platformio_esp32s3_envs.ini +++ b/platformio_esp32s3_envs.ini @@ -49,7 +49,7 @@ build_flags = ${esp32s3_common.build_flags} lib_ignore = ${esp32_always.lib_ignore} ESP32_ping extra_scripts = ${esp32s3_common.extra_scripts} - pre:tools/pio/pre_custom_esp32.py + pre:tools/pio/pre_custom_esp32_IR.py pre:tools/pio/ir_build_check.py diff --git a/src/Custom-sample.h b/src/Custom-sample.h index fb806bb7d9..50a2a44b4a 100644 --- a/src/Custom-sample.h +++ b/src/Custom-sample.h @@ -272,7 +272,6 @@ -#define FEATURE_SSDP 1 /* ####################################################################################################### diff --git a/src/_C002.cpp b/src/_C002.cpp index fb51027424..6e96c6c983 100644 --- a/src/_C002.cpp +++ b/src/_C002.cpp @@ -7,6 +7,11 @@ // ########################### Controller Plugin 002: Domoticz MQTT ###################################### // ####################################################################################################### +/** Changelog: + * 2024-03-24 tonhuisman: Add support for 'Invert On/Off value' in P029 - Domoticz MQTT Helper + * 2024-03-24 tonhuisman: Start Changelog (newest on top) + */ + # define CPLUGIN_002 # define CPLUGIN_ID_002 2 # define CPLUGIN_NAME_002 "Domoticz MQTT" @@ -85,15 +90,16 @@ bool CPlugin_002(CPlugin::Function function, struct EventStruct *event, String& constexpr pluginID_t PLUGIN_ID_DOMOTICZ_HELPER(29); # if defined(USES_P088) constexpr pluginID_t PLUGIN_ID_HEATPUMP_IR(88); - # endif + # endif // if defined(USES_P088) + if (Settings.TaskDeviceEnabled[x] && (Settings.TaskDeviceSendData[ControllerID][x] - || (Settings.getPluginID_for_task(x) == PLUGIN_ID_DOMOTICZ_HELPER) // Domoticz helper doesn't have controller checkboxes... + || (Settings.getPluginID_for_task(x) == PLUGIN_ID_DOMOTICZ_HELPER) // Domoticz helper doesn't have controller checkboxes... # if defined(USES_P088) - || (Settings.getPluginID_for_task(x) == PLUGIN_ID_HEATPUMP_IR) // Heatpump IR doesn't have controller checkboxes... + || (Settings.getPluginID_for_task(x) == PLUGIN_ID_HEATPUMP_IR) // Heatpump IR doesn't have controller checkboxes... # endif // if defined(USES_P088) ) && - (Settings.TaskDeviceID[ControllerID][x] == idx)) // get idx for our controller index + (Settings.TaskDeviceID[ControllerID][x] == idx)) // get idx for our controller index { String action; bool mustSendEvent = false; @@ -101,7 +107,7 @@ bool CPlugin_002(CPlugin::Function function, struct EventStruct *event, String& switch (Settings.getPluginID_for_task(x).value) { case 1: // temp solution, if input switch, update state { - action = strformat(F("inputSwitchState,%u,%.2f"), x, nvalue); + action = strformat(F("gpio,%d,%d"), x, static_cast(nvalue)); break; } case 29: // temp solution, if plugin 029, set gpio @@ -114,7 +120,7 @@ bool CPlugin_002(CPlugin::Function function, struct EventStruct *event, String& switch (static_cast(nvalue)) { case 0: // Off - pwmValue = 0; + pwmValue = 0; UserVar.setFloat(x, 0, pwmValue); break; case 1: // On @@ -132,20 +138,25 @@ bool CPlugin_002(CPlugin::Function function, struct EventStruct *event, String& action = strformat(F("pwm,%d,%d"), Settings.TaskDevicePin1[x], pwmValue); } } else { - mustSendEvent = true; - UserVar.setFloat(x, 0, nvalue); + mustSendEvent = true; + int ivalue = static_cast(nvalue); + + if (1 == Settings.TaskDevicePluginConfig[x][0]) { // PCONFIG(0) = Invert On/Off value + ivalue = (1 == ivalue ? 0 : 1); + } + UserVar.setFloat(x, 0, ivalue); if (checkValidPortRange(PLUGIN_GPIO, Settings.TaskDevicePin1[x])) { - action = strformat(F("gpio,%d,%d"), Settings.TaskDevicePin1[x], static_cast(nvalue)); + action = strformat(F("gpio,%d,%d"), Settings.TaskDevicePin1[x], ivalue); } } break; } -# if defined(USES_P088) // || defined(USES_P115) - case 88: // Send heatpump IR (P088) if IDX matches +# if defined(USES_P088) // || defined(USES_P115) + case 88: // Send heatpump IR (P088) if IDX matches // case 115: // Send heatpump IR (P115) if IDX matches { - action = concat(F("heatpumpir,"),svalue1); // svalue1 is like 'gree,1,1,0,22,0,0' + action = concat(F("heatpumpir,"), svalue1); // svalue1 is like 'gree,1,1,0,22,0,0' break; } # endif // USES_P088 || USES_P115 @@ -160,11 +171,11 @@ bool CPlugin_002(CPlugin::Function function, struct EventStruct *event, String& // Try plugin and internal ExecuteCommandArgs args( - x, - EventValueSource::Enum::VALUE_SOURCE_MQTT, - action.c_str(), - true, - true, + x, + EventValueSource::Enum::VALUE_SOURCE_MQTT, + action.c_str(), + true, + true, false); ExecuteCommand(std::move(args), true); } diff --git a/src/_P001_Switch.ino b/src/_P001_Switch.ino index 01ca45ab15..474af67183 100644 --- a/src/_P001_Switch.ino +++ b/src/_P001_Switch.ino @@ -132,10 +132,10 @@ boolean Plugin_001(uint8_t function, struct EventStruct *event, String& string) } { - const __FlashStringHelper *options[2] = { F("Switch"), F("Dimmer") }; - int optionValues[2] = { PLUGIN_001_TYPE_SWITCH, PLUGIN_001_TYPE_DIMMER }; - const uint8_t switchtype = P001_getSwitchType(event); - addFormSelector(F("Switch Type"), F("type"), 2, options, optionValues, switchtype); + const __FlashStringHelper *options[] = { F("Switch"), F("Dimmer") }; + int optionValues[] = { PLUGIN_001_TYPE_SWITCH, PLUGIN_001_TYPE_DIMMER }; + const uint8_t switchtype = P001_getSwitchType(event); + addFormSelector(F("Switch Type"), F("type"), NR_ELEMENTS(optionValues), options, optionValues, switchtype); if (switchtype == PLUGIN_001_TYPE_DIMMER) { @@ -145,10 +145,10 @@ boolean Plugin_001(uint8_t function, struct EventStruct *event, String& string) { uint8_t choice = PCONFIG(2); - const __FlashStringHelper *buttonOptions[3] = { F("Normal Switch"), F("Push Button Active Low"), F("Push Button Active High") }; - int buttonOptionValues[3] = + const __FlashStringHelper *buttonOptions[] = { F("Normal Switch"), F("Push Button Active Low"), F("Push Button Active High") }; + int buttonOptionValues[] = { PLUGIN_001_BUTTON_TYPE_NORMAL_SWITCH, PLUGIN_001_BUTTON_TYPE_PUSH_ACTIVE_LOW, PLUGIN_001_BUTTON_TYPE_PUSH_ACTIVE_HIGH }; - addFormSelector(F("Switch Button Type"), F("button"), 3, buttonOptions, buttonOptionValues, choice); + addFormSelector(F("Switch Button Type"), F("button"), NR_ELEMENTS(buttonOptionValues), buttonOptions, buttonOptionValues, choice); } SwitchWebformLoad( diff --git a/src/_P027_INA219.ino b/src/_P027_INA219.ino index 1af9ab7aa6..7592264dd3 100644 --- a/src/_P027_INA219.ino +++ b/src/_P027_INA219.ino @@ -105,9 +105,9 @@ boolean Plugin_027(uint8_t function, struct EventStruct *event, String& string) case PLUGIN_WEBFORM_LOAD: { { - const __FlashStringHelper *optionsMode[] = { F("32V, 2A"), F("32V, 1A"), F("16V, 0.4A") }; - const int optionValuesMode[] = { 0, 1, 2 }; - addFormSelector(F("Measure range"), F("range"), 3, optionsMode, optionValuesMode, PCONFIG(0)); + const __FlashStringHelper *optionsMode[] = { F("32V, 2A"), F("32V, 1A"), F("16V, 0.4A"), F("26V, 8A") }; + const int optionValuesMode[] = { 0, 1, 2, 3 }; + addFormSelector(F("Measure range"), F("range"), 4, optionsMode, optionValuesMode, PCONFIG(0)); } { const __FlashStringHelper *options[] = { F("Voltage"), F("Current"), F("Power"), F("Voltage/Current/Power") }; @@ -169,6 +169,14 @@ boolean Plugin_027(uint8_t function, struct EventStruct *event, String& string) P027_data->setCalibration_16V_400mA(); break; } + case 3: + { + if (mustLog) { + log += F("26V, 8A"); + } + P027_data->setCalibration_26V_8A(); + break; + } } if (mustLog) { diff --git a/src/_P029_Output.ino b/src/_P029_Output.ino index 9f737f33be..1acbbc552f 100644 --- a/src/_P029_Output.ino +++ b/src/_P029_Output.ino @@ -1,74 +1,93 @@ #include "_Plugin_Helper.h" #ifdef USES_P029 -//####################################################################################################### -//#################################### Plugin 029: Output ############################################### -//####################################################################################################### +// ####################################################################################################### +// #################################### Plugin 029: Output ############################################### +// ####################################################################################################### + +/** Changelog: + * 2024-03-24 tonhuisman: Reformat source (Uncrustify), add option 'Invert On/Off value' + * 2024-03-24 tonhuisman: Start Changelog (newest on top) + */ + +# define PLUGIN_029 +# define PLUGIN_ID_029 29 +# define PLUGIN_NAME_029 "Output - Domoticz MQTT Helper" +# define PLUGIN_VALUENAME1_029 "Output" + +# define P029_INVERTED PCONFIG(0) -#define PLUGIN_029 -#define PLUGIN_ID_029 29 -#define PLUGIN_NAME_029 "Output - Domoticz MQTT Helper" -#define PLUGIN_VALUENAME1_029 "Output" boolean Plugin_029(uint8_t function, struct EventStruct *event, String& string) { boolean success = false; switch (function) { - case PLUGIN_DEVICE_ADD: - { - Device[++deviceCount].Number = PLUGIN_ID_029; - Device[deviceCount].Type = DEVICE_TYPE_SINGLE; // FIXME TD-er: Does this need a pin? Seems not to be used - Device[deviceCount].VType = Sensor_VType::SENSOR_TYPE_SWITCH; - Device[deviceCount].Ports = 0; - Device[deviceCount].PullUpOption = false; - Device[deviceCount].InverseLogicOption = false; - Device[deviceCount].FormulaOption = false; - Device[deviceCount].ValueCount = 1; - Device[deviceCount].SendDataOption = false; - break; - } + { + Device[++deviceCount].Number = PLUGIN_ID_029; + Device[deviceCount].Type = DEVICE_TYPE_SINGLE; + Device[deviceCount].VType = Sensor_VType::SENSOR_TYPE_SWITCH; + Device[deviceCount].Ports = 0; + Device[deviceCount].PullUpOption = false; + Device[deviceCount].InverseLogicOption = false; + Device[deviceCount].FormulaOption = false; + Device[deviceCount].ValueCount = 1; + Device[deviceCount].SendDataOption = false; + break; + } case PLUGIN_GET_DEVICENAME: - { - string = F(PLUGIN_NAME_029); - break; - } + { + string = F(PLUGIN_NAME_029); + break; + } case PLUGIN_GET_DEVICEVALUENAMES: - { - strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_029)); - ExtraTaskSettings.TaskDeviceValueDecimals[0] = 0; - break; - } + { + strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_029)); + ExtraTaskSettings.TaskDeviceValueDecimals[0] = 0; + break; + } case PLUGIN_WEBFORM_LOAD: - { - // We need the index of the controller we are: 0-CONTROLLER_MAX - uint8_t controllerNr = 0; - for (controllerIndex_t i=0; i < CONTROLLER_MAX; i++) - { -// if (Settings.Protocol[i] == CPLUGIN_ID_002) { controllerNr = i; } -> error: 'CPLUGIN_ID_002' was not declared in this scope - if (Settings.Protocol[i] == 2) { controllerNr = i; } - } + { + // We need the index of the controller we are: 0-CONTROLLER_MAX + uint8_t controllerNr = 0; - addRowLabel(F("IDX")); - addNumericBox( - concat(F("TDID"), controllerNr + 1), //="taskdeviceid" - Settings.TaskDeviceID[controllerNr][event->TaskIndex], - 0, - DOMOTICZ_MAX_IDX); - success = true; - break; + for (controllerIndex_t i = 0; i < CONTROLLER_MAX; i++) + { + // if (Settings.Protocol[i] == CPLUGIN_ID_002) { controllerNr = i; } -> error: 'CPLUGIN_ID_002' was not declared in + // this scope + if (Settings.Protocol[i] == 2) { controllerNr = i; } } + addRowLabel(F("IDX")); + addNumericBox( + concat(F("TDID"), controllerNr + 1), // ="taskdeviceid" + Settings.TaskDeviceID[controllerNr][event->TaskIndex], + 0, + DOMOTICZ_MAX_IDX); + + addFormCheckBox(F("Invert On/Off value"), F("inverted"), P029_INVERTED == 1); + + success = true; + break; + } + + case PLUGIN_WEBFORM_SAVE: + { + P029_INVERTED = isFormItemChecked(F("inverted")) ? 1 : 0; + success = true; + break; + } case PLUGIN_INIT: - { - success = true; - break; - } + { + success = true; + break; + } } return success; } + #endif // USES_P029 diff --git a/src/_P073_7DGT.ino b/src/_P073_7DGT.ino index ac50107feb..1e3102f1b7 100644 --- a/src/_P073_7DGT.ino +++ b/src/_P073_7DGT.ino @@ -1071,7 +1071,7 @@ void tm1637_i2cWrite(uint8_t clk_pin, for (i = 0; i < 8; i++) { CLK_LOW(); - if (bytetoprint & B00000001) { + if (bytetoprint & 0b00000001) { DIO_HIGH(); } else { DIO_LOW(); diff --git a/src/_P087_SerialProxy.ino b/src/_P087_SerialProxy.ino index 0fb2a02987..d816b7b854 100644 --- a/src/_P087_SerialProxy.ino +++ b/src/_P087_SerialProxy.ino @@ -11,6 +11,12 @@ /** * Changelog: + * 2024-02-27 tonhuisman: Always process the regular expression like 'Global Match' to enable retrieving the available values + * 2024-02-26 tonhuisman: Apply log-string and other code optimizations + * 2024-02-25 tonhuisman: Add command serialproxy_test, to test as if serial data was received + * Add Get Config Value support for retrieving the last regex-parsed data: + * - By group: [#group,] (groupnr is 0-base!) + * - By name: [#next,] if the is found, the next group-data is returned * 2023-03-25 tonhuisman: Change serialproxy_writemix to handle 0x00 also, by implementing parseHexTextData() * 2023-03-22 tonhuisman: Add command serialproxy_writemix to handle mixed hex characters and text to send * using parseHexTextString() @@ -144,7 +150,7 @@ boolean Plugin_087(uint8_t function, struct EventStruct *event, String& string) { addFormNumericBox(F("Baudrate"), P087_BAUDRATE_LABEL, P087_BAUDRATE, 300, 115200); addUnit(F("baud")); - uint8_t serialConfChoice = serialHelper_convertOldSerialConfig(P087_SERIAL_CONFIG); + const uint8_t serialConfChoice = serialHelper_convertOldSerialConfig(P087_SERIAL_CONFIG); serialHelper_serialconfig_webformLoad(event, serialConfChoice); break; } @@ -168,7 +174,7 @@ boolean Plugin_087(uint8_t function, struct EventStruct *event, String& string) static_cast(getPluginTaskData(event->TaskIndex)); if (nullptr != P087_data) { - for (uint8_t varNr = 0; varNr < P87_Nlines; varNr++) + for (uint8_t varNr = 0; varNr < P87_Nlines; ++varNr) { P087_data->setLine(varNr, webArg(getPluginCustomArgName(varNr))); } @@ -225,14 +231,13 @@ boolean Plugin_087(uint8_t function, struct EventStruct *event, String& string) if ((nullptr != P087_data) && P087_data->getSentence(event->String2)) { if (Plugin_087_match_all(event->TaskIndex, event->String2)) { // sendData(event); -# ifndef BUILD_NO_DEBUG + # ifndef BUILD_NO_DEBUG addLog(LOG_LEVEL_DEBUG, event->String2); -# endif // ifndef BUILD_NO_DEBUG + # endif // ifndef BUILD_NO_DEBUG success = true; } } - if ((nullptr != P087_data)) {} break; } @@ -240,26 +245,49 @@ boolean Plugin_087(uint8_t function, struct EventStruct *event, String& string) P087_data_struct *P087_data = static_cast(getPluginTaskData(event->TaskIndex)); - if ((nullptr != P087_data)) { - String cmd = parseString(string, 1); + if (nullptr != P087_data) { + const String cmd = parseString(string, 1); if (equals(cmd, F("serialproxy_write"))) { - String param1 = parseStringKeepCase(string, 2, ',', false); // Don't trim off white-space - parseSystemVariables(param1, false); // FIXME tonhuisman: Doesn't seem to be needed? + String param1 = parseStringKeepCaseNoTrim(string, 2); // Don't trim off white-space + parseSystemVariables(param1, false); // FIXME tonhuisman: Doesn't seem to be needed? P087_data->sendString(param1); - addLogMove(LOG_LEVEL_INFO, param1); // FIXME tonhuisman: Should we always want to write to the log? + addLogMove(LOG_LEVEL_INFO, param1); // FIXME tonhuisman: Should we always want to write to the log? success = true; } else if (equals(cmd, F("serialproxy_writemix"))) { std::vector param1 = parseHexTextData(string); - if (param1.size()) + + if (param1.size()) { P087_data->sendData(¶m1[0], param1.size()); + } + success = true; + } else + if (equals(cmd, F("serialproxy_test"))) { // Test-parse data as if received via serial + const String param1 = parseStringKeepCaseNoTrim(string, 2); + + if (!param1.isEmpty()) { + P087_data->setLastSentence(param1); + Scheduler.schedule_task_device_timer(event->TaskIndex, millis() + 10); + delay(0); // Processing a full sentence may take a while, run some background tasks. + } success = true; } } break; } + + case PLUGIN_GET_CONFIG_VALUE: + { + P087_data_struct *P087_data = + static_cast(getPluginTaskData(event->TaskIndex)); + + if (nullptr != P087_data) { + success = P087_data->plugin_get_config_value(event, string); + } + break; + } } return success; } @@ -279,7 +307,7 @@ bool Plugin_087_match_all(taskIndex_t taskIndex, String& received) return true; } - bool res = P087_data->matchRegexp(received); + const bool res = P087_data->matchRegexp(received); if (P087_data->invertMatch()) { addLog(LOG_LEVEL_INFO, F("Serial Proxy: invert filter")); @@ -292,7 +320,7 @@ String Plugin_087_valuename(uint8_t value_nr, bool displayString) { switch (value_nr) { case P087_QUERY_VALUE: return displayString ? F("Value") : F("v"); } - return ""; + return EMPTY_STRING; } void P087_html_show_matchForms(struct EventStruct *event) { @@ -342,7 +370,7 @@ void P087_html_show_matchForms(struct EventStruct *event) { for (uint8_t varNr = P087_FIRST_FILTER_POS; varNr < P87_Nlines; ++varNr) { - String id = getPluginCustomArgName(varNr); + const String id = getPluginCustomArgName(varNr); switch (varNr % 3) { case 0: @@ -350,10 +378,7 @@ void P087_html_show_matchForms(struct EventStruct *event) { // Label + first parameter filter = P087_data->getFilter(lineNr, capture, comparator); ++lineNr; - String label; - label = F("Capture Filter "); - label += String(lineNr); - addRowLabel_tr_id(label, id); + addRowLabel_tr_id(concat(F("Capture Filter "), lineNr), id); addNumericBox(id, capture, -1, P87_MAX_CAPTURE_INDEX); break; @@ -364,7 +389,7 @@ void P087_html_show_matchForms(struct EventStruct *event) { const __FlashStringHelper *options[2]; options[P087_Filter_Comp::Equal] = F("=="); options[P087_Filter_Comp::NotEqual] = F("!="); - int optionValues[2] = { P087_Filter_Comp::Equal, P087_Filter_Comp::NotEqual }; + const int optionValues[2] = { P087_Filter_Comp::Equal, P087_Filter_Comp::NotEqual }; addSelector(id, 2, options, optionValues, nullptr, static_cast(comparator), false, true, F("")); break; } @@ -395,13 +420,9 @@ void P087_html_show_stats(struct EventStruct *event) { { addRowLabel(F("Sentences (pass/fail)")); - String chksumStats; uint32_t success, error, length_last; P087_data->getSentencesReceived(success, error, length_last); - chksumStats = success; - chksumStats += '/'; - chksumStats += error; - addHtml(chksumStats); + addHtml(strformat(F("%d/%d"), success, error)); addRowLabel(F("Length Last Sentence")); addHtmlInt(length_last); } diff --git a/src/_P094_CULReader.ino b/src/_P094_CULReader.ino index d07d8c3599..b2cae7b197 100644 --- a/src/_P094_CULReader.ino +++ b/src/_P094_CULReader.ino @@ -9,34 +9,26 @@ // Allows to control the mode of the CUL receiver // +# include "src/ESPEasyCore/ESPEasyNetwork.h" -#include "src/Helpers/ESPEasy_Storage.h" -#include "src/Helpers/StringConverter.h" -#include "src/PluginStructs/P094_data_struct.h" +# include "src/Helpers/ESPEasy_Storage.h" +# include "src/Helpers/StringConverter.h" +# include "src/PluginStructs/P094_data_struct.h" -#include +# include -#define PLUGIN_094 -#define PLUGIN_ID_094 94 -#define PLUGIN_NAME_094 "Communication - CUL Reader" +# define PLUGIN_094 +# define PLUGIN_ID_094 94 +# define PLUGIN_NAME_094 "Communication - CUL Reader" +# define PLUGIN_VALUENAME1_094 "v" -#define P094_BAUDRATE PCONFIG_LONG(0) -#define P094_BAUDRATE_LABEL PCONFIG_LABEL(0) - -#define P094_DEBUG_SENTENCE_LENGTH PCONFIG_LONG(1) -#define P094_DEBUG_SENTENCE_LABEL PCONFIG_LABEL(1) - -#define P094_APPEND_RECEIVE_SYSTIME PCONFIG(0) - -#define P094_QUERY_VALUE 0 // Temp placement holder until we know what selectors are needed. -#define P094_NR_OUTPUT_OPTIONS 1 - -#define P094_NR_OUTPUT_VALUES 1 -#define P094_QUERY1_CONFIG_POS 3 - -#define P094_DEFAULT_BAUDRATE 38400 +bool Plugin_094_match_all(taskIndex_t taskIndex, + const String& received, + const String& source, + bool fromCUL); +void Plugin_094_setFlags(struct EventStruct *event); // Plugin settings: // Validate: @@ -64,6 +56,7 @@ boolean Plugin_094(uint8_t function, struct EventStruct *event, String& string) Device[++deviceCount].Number = PLUGIN_ID_094; Device[deviceCount].Type = DEVICE_TYPE_SERIAL; Device[deviceCount].VType = Sensor_VType::SENSOR_TYPE_STRING; + Device[deviceCount].OutputDataType = Output_Data_type_t::Default; Device[deviceCount].Ports = 0; Device[deviceCount].PullUpOption = false; Device[deviceCount].InverseLogicOption = false; @@ -73,8 +66,9 @@ boolean Plugin_094(uint8_t function, struct EventStruct *event, String& string) Device[deviceCount].TimerOption = true; Device[deviceCount].GlobalSyncOption = false; Device[deviceCount].DuplicateDetection = true; + // FIXME TD-er: Not sure if access to any existing task data is needed when saving - Device[deviceCount].ExitTaskBeforeSave = false; + Device[deviceCount].ExitTaskBeforeSave = true; break; } @@ -83,16 +77,9 @@ boolean Plugin_094(uint8_t function, struct EventStruct *event, String& string) break; } - case PLUGIN_GET_DEVICEVALUENAMES: { - for (uint8_t i = 0; i < VARS_PER_TASK; ++i) { - if (i < P094_NR_OUTPUT_VALUES) { - const uint8_t pconfigIndex = i + P094_QUERY1_CONFIG_POS; - uint8_t choice = PCONFIG(pconfigIndex); - ExtraTaskSettings.setTaskDeviceValueName(i, Plugin_094_valuename(choice, false)); - } else { - ExtraTaskSettings.clearTaskDeviceValueName(i); - } - } + case PLUGIN_GET_DEVICEVALUENAMES: + { + strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_094)); break; } @@ -121,7 +108,7 @@ boolean Plugin_094(uint8_t function, struct EventStruct *event, String& string) case PLUGIN_SET_DEFAULTS: { - P094_BAUDRATE = P094_DEFAULT_BAUDRATE; + P094_BAUDRATE = P094_DEFAULT_BAUDRATE; P094_DEBUG_SENTENCE_LENGTH = 0; success = true; @@ -142,47 +129,74 @@ boolean Plugin_094(uint8_t function, struct EventStruct *event, String& string) break; } - case PLUGIN_WEBFORM_LOAD: + case PLUGIN_WEBFORM_LOAD: { + addFormCheckBox(F("Append system time"), F("systime"), P094_GET_APPEND_RECEIVE_SYSTIME); + +# if P094_DEBUG_OPTIONS + addFormSubHeader(F("Debug Options")); + addFormNumericBox(F("(debug) Generated length"), P094_DEBUG_SENTENCE_LABEL, P094_DEBUG_SENTENCE_LENGTH, 0, 1024); + addFormCheckBox(F("(debug) Generate CUL data"), F("debug_data"), P094_GET_GENERATE_DEBUG_CUL_DATA); +# endif // if P094_DEBUG_OPTIONS + addFormSubHeader(F("Filtering")); + addFormCheckBox(F("Mute Messages"), F("mute"), P094_GET_MUTE_MESSAGES); P094_html_show_matchForms(event); + addFormCheckBox(F("Enable Interval Filter"), F("interval_filter"), P094_GET_INTERVAL_FILTER); addFormSubHeader(F("Statistics")); - P094_html_show_stats(event); + addFormCheckBox(F("Collect W-MBus Stats"), F("collect_stats"), P094_GET_COLLECT_STATS); + addFormNote(F("Collect reception statistics of W-MBus devices received by the CUL reader")); - addFormNumericBox(F("(debug) Generated length"), P094_DEBUG_SENTENCE_LABEL, P094_DEBUG_SENTENCE_LENGTH, 0, 1024); - addFormCheckBox(F("Append system time"), F("systime"), P094_APPEND_RECEIVE_SYSTIME); + P094_html_show_stats(event); success = true; break; } case PLUGIN_WEBFORM_SAVE: { - P094_BAUDRATE = getFormItemInt(P094_BAUDRATE_LABEL); + P094_BAUDRATE = getFormItemInt(P094_BAUDRATE_LABEL); P094_DEBUG_SENTENCE_LENGTH = getFormItemInt(P094_DEBUG_SENTENCE_LABEL); + P094_DISABLE_WINDOW_TIME_MS = getFormItemInt(F("disableTime")); + P094_NR_FILTERS = getFormItemInt(F("nrfilters")); + + + P094_SET_APPEND_RECEIVE_SYSTIME(isFormItemChecked(F("systime"))); +# if P094_DEBUG_OPTIONS + P094_SET_GENERATE_DEBUG_CUL_DATA(isFormItemChecked(F("debug_data"))); +# endif // if P094_DEBUG_OPTIONS + P094_SET_INTERVAL_FILTER(isFormItemChecked(F("interval_filter"))); + P094_SET_MUTE_MESSAGES(isFormItemChecked(F("mute"))); + P094_SET_COLLECT_STATS(isFormItemChecked(F("collect_stats"))); + + P094_data_struct *P094_data = static_cast(getPluginTaskData(event->TaskIndex)); - if (nullptr != P094_data) { - for (uint8_t varNr = 0; varNr < P94_Nlines; varNr++) - { - P094_data->setLine(varNr, webArg(getPluginCustomArgName(varNr))); - } - addHtmlError(SaveCustomTaskSettings(event->TaskIndex, P094_data->_lines, P94_Nlines, 0)); - success = true; + const bool localAllocated = nullptr == P094_data; + + if (localAllocated) { + P094_data = new (std::nothrow) P094_data_struct(); } - P094_APPEND_RECEIVE_SYSTIME = isFormItemChecked(F("systime")); + if ((nullptr != P094_data)) { + P094_data->WebformSaveFilters(event, P094_NR_FILTERS); + success = true; + + if (localAllocated) { + delete P094_data; + } + } break; } case PLUGIN_INIT: { - const int16_t serial_rx = CONFIG_PIN1; - const int16_t serial_tx = CONFIG_PIN2; + const int16_t serial_rx = CONFIG_PIN1; + const int16_t serial_tx = CONFIG_PIN2; const ESPEasySerialPort port = static_cast(CONFIG_PORT); initPluginTaskData(event->TaskIndex, new (std::nothrow) P094_data_struct()); P094_data_struct *P094_data = @@ -192,9 +206,20 @@ boolean Plugin_094(uint8_t function, struct EventStruct *event, String& string) return success; } - if (P094_data->init(port, serial_rx, serial_tx, P094_BAUDRATE)) { - LoadCustomTaskSettings(event->TaskIndex, P094_data->_lines, P94_Nlines, 0); - P094_data->post_init(); + if (P094_data->init( + port, + serial_rx, + serial_tx, + P094_BAUDRATE)) { + P094_data->setFlags( + P094_DISABLE_WINDOW_TIME_MS, + P094_GET_INTERVAL_FILTER, + P094_GET_MUTE_MESSAGES, + P094_GET_COLLECT_STATS); + P094_data->loadFilters(event, P094_NR_FILTERS); +# if P094_DEBUG_OPTIONS + P094_data->setGenerate_DebugCulData(P094_GET_GENERATE_DEBUG_CUL_DATA); +# endif // if P094_DEBUG_OPTIONS success = true; serialHelper_log_GpioDescription(port, serial_rx, serial_tx); @@ -204,6 +229,27 @@ boolean Plugin_094(uint8_t function, struct EventStruct *event, String& string) break; } + case PLUGIN_ONCE_A_SECOND: + { + P094_data_struct *P094_data = + static_cast(getPluginTaskData(event->TaskIndex)); + + if (nullptr != P094_data) { + P094_data->interval_filter_purgeExpired(); + + if (P094_data->dump_next_stats(event->String2)) { + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + addLogMove(LOG_LEVEL_INFO, concat(F("CUL Reader: "), event->String2)); + } + + // Do not create events for dumping stats. + const bool sendEvents = false; + sendData(event, sendEvents); + } + } + break; + } + case PLUGIN_FIFTY_PER_SECOND: { if (Settings.TaskDeviceEnabled[event->TaskIndex]) { P094_data_struct *P094_data = @@ -213,15 +259,20 @@ boolean Plugin_094(uint8_t function, struct EventStruct *event, String& string) // Scheduler.schedule_task_device_timer(event->TaskIndex, millis() + 10); delay(0); // Processing a full sentence may take a while, run some // background tasks. - P094_data->getSentence(event->String2, P094_APPEND_RECEIVE_SYSTIME); + P094_data->getSentence(event->String2, P094_GET_APPEND_RECEIVE_SYSTIME); if (event->String2.length() > 0) { - if (Plugin_094_match_all(event->TaskIndex, event->String2)) { + const bool fromCUL = true; + const String source = NetworkGetHostname(); + + if (Plugin_094_match_all(event->TaskIndex, event->String2, source, fromCUL)) { if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log; + if (log.reserve(128)) { log = F("CUL Reader: Sending: "); const size_t messageLength = event->String2.length(); + if (messageLength < 100) { log += event->String2; } else { @@ -233,10 +284,12 @@ boolean Plugin_094(uint8_t function, struct EventStruct *event, String& string) addLogMove(LOG_LEVEL_INFO, log); } } + // Filter length options: - // - 22 char, for hash-value then we filter the exact meter including serial and meter type, (that will also prevent very quit sending meters, which normaly is a fault) + // - 22 char, for hash-value then we filter the exact meter including serial and meter type, (that will also prevent very quit + // sending meters, which normaly is a fault) // - 38 char, The exact message, because we have 2 uint8_t from the value payload - //sendData_checkDuplicates(event, event->String2.substring(0, 22)); + // sendData_checkDuplicates(event, event->String2.substring(0, 22)); sendData(event); } } @@ -252,53 +305,169 @@ boolean Plugin_094(uint8_t function, struct EventStruct *event, String& string) static_cast(getPluginTaskData(event->TaskIndex)); if ((nullptr != P094_data)) { + # if P094_DEBUG_OPTIONS const uint32_t debug_count = P094_data->getDebugCounter(); event->String2.reserve(P094_DEBUG_SENTENCE_LENGTH); event->String2 += String(debug_count); event->String2 += '_'; const char c = '0' + debug_count % 10; + for (long i = event->String2.length(); i < P094_DEBUG_SENTENCE_LENGTH; ++i) { event->String2 += c; } + # endif // if P094_DEBUG_OPTIONS + if (loglevelActiveFor(LOG_LEVEL_INFO)) { String log = F("CUL Reader: Sending: "); log += event->String2.substring(0, 20); log += F("..."); addLogMove(LOG_LEVEL_INFO, log); } -// sendData_checkDuplicates(event, event->String2.substring(0, 22)); + + // sendData_checkDuplicates(event, event->String2.substring(0, 22)); sendData(event); } } break; } + case PLUGIN_GET_CONFIG_VALUE: + { + const String command = parseString(string, 1); + + P094_data_struct *P094_data = + static_cast(getPluginTaskData(event->TaskIndex)); + + if (nullptr != P094_data) { + if (equals(command, F("getfiltermd5"))) { + // to output a MD5 of the currently active filters. + string = P094_data->getFiltersMD5(); + success = true; + } else if (equals(command, F("getfilterenabled"))) { + string = P094_GET_INTERVAL_FILTER; + success = true; + } else if (equals(command, F("getmuteenabled"))) { + string = P094_GET_MUTE_MESSAGES; + success = true; + } + } + break; + } + + case PLUGIN_WRITE: { - String cmd = parseString(string, 1); + const String cmd = parseString(string, 1); + const String subcmd = parseString(string, 2); if (cmd.startsWith(F("culreader"))) { - if (equals(cmd, F("culreader_write"))) { - P094_data_struct *P094_data = - static_cast(getPluginTaskData(event->TaskIndex)); + P094_data_struct *P094_data = + static_cast(getPluginTaskData(event->TaskIndex)); - if ((nullptr != P094_data)) { + if (equals(subcmd, F("enablefilter"))) { + // culreader,enablefilter + P094_SET_INTERVAL_FILTER(1); + success = true; + } else if (equals(subcmd, F("disablefilter"))) { + // culreader,disablefilter + P094_SET_INTERVAL_FILTER(0); + success = true; + } else if (equals(subcmd, F("mute"))) { + // culreader,mute + P094_SET_MUTE_MESSAGES(1); + success = true; + } else if (equals(subcmd, F("unmute"))) { + // culreader,unmute + P094_SET_MUTE_MESSAGES(0); + success = true; + } else if ((nullptr != P094_data)) { + if (equals(cmd, F("culreader_write")) || + equals(subcmd, F("write"))) { + // culreader,write, String param1 = parseStringKeepCase(string, 2); parseSystemVariables(param1, false); P094_data->sendString(param1); addLogMove(LOG_LEVEL_INFO, param1); success = true; + } else if (equals(subcmd, F("dumpstats"))) { + // culreader,dumpstats + P094_data->prepare_dump_stats(); + success = true; + } else if (equals(subcmd, F("clearfilters"))) { + // culreader,clearfilters + P094_data->clearFilters(); + success = true; + } else if (equals(subcmd, F("savefilters"))) { + // culreader,savefilters + P094_data->saveFilters(event); + SaveSettings(); + success = true; + } else if (equals(subcmd, F("addfilter"))) { + // culreader,addfilter, + // Examples for a filter definition + // EBZ.02.12345678;all + // *.02.*;15m + // TCH.44.*;once + // *.*.*;5m + success = true; + P094_data->addFilter(event, parseString(string, 3)); + } else if (equals(subcmd, F("setfilters"))) { + // culreader,setfilters,|...| + // Examples for a filter definition + // culreader,setfilters,EBZ.02.12345678;all|*.02.*;15m|TCH.44.*;once|*.*.*;5m + success = true; + P094_data->clearFilters(); + const String argument = parseString(string, 3); + + if (!argument.isEmpty()) { + int argNr = 1; + + while (argNr > 0) { + const String filter = parseString(argument, argNr, '|'); + + if (!filter.isEmpty()) + { + P094_data->addFilter(event, filter); + ++argNr; + } else { + argNr = 0; + } + } + } + P094_data->saveFilters(event); + SaveSettings(); } } + + if (success) { + Plugin_094_setFlags(event); + } } break; } +#ifdef USES_ESPEASY_NOW + case PLUGIN_FILTEROUT_CONTROLLER_DATA: + { + // event->String1 => topic; + // event->String2 => payload; + if (Settings.TaskDeviceEnabled[event->TaskIndex]) { + const bool fromCUL = false; + + if (!Plugin_094_match_all(event->TaskIndex, event->String2, event->String1, fromCUL)) { + // Inverse as we check for filtering 'out' the messages. + success = true; + } + } + + break; + } +#endif } return success; } -bool Plugin_094_match_all(taskIndex_t taskIndex, const String& received) +bool Plugin_094_match_all(taskIndex_t taskIndex, const String& received, const String& source, bool fromCUL) { P094_data_struct *P094_data = static_cast(getPluginTaskData(taskIndex)); @@ -307,133 +476,79 @@ bool Plugin_094_match_all(taskIndex_t taskIndex, const String& received) return false; } - if (P094_data->disableFilterWindowActive()) { addLog(LOG_LEVEL_INFO, F("CUL Reader: Disable Filter Window active")); return true; } - bool res = P094_data->parsePacket(received); + mBusPacket_t packet; + bool res = P094_data->parsePacket(received, packet); - if (P094_data->invertMatch()) { - addLog(LOG_LEVEL_INFO, F("CUL Reader: invert filter")); - return !res; - } - return res; + # ifdef ESP8266 + + if (res && fromCUL) { + # endif // ifdef ESP8266 + + // Only collect stats from the actual CUL receiver, not when processing forwarded packets. + // On ESP8266: only collect stats on the filtered nodes or else we will likely run out of memory + P094_data->collect_stats_add(packet, source); + # ifdef ESP8266 } -String Plugin_094_valuename(uint8_t value_nr, bool displayString) { - switch (value_nr) { - case P094_QUERY_VALUE: return displayString ? F("Value") : F("v"); - } - return EMPTY_STRING; + # endif // ifdef ESP8266 + + return res; } -void P094_html_show_matchForms(struct EventStruct *event) { +void Plugin_094_setFlags(struct EventStruct *event) +{ P094_data_struct *P094_data = static_cast(getPluginTaskData(event->TaskIndex)); - if ((nullptr != P094_data)) { - addFormNumericBox(F("Filter Off Window after send"), - getPluginCustomArgName(P094_FILTER_OFF_WINDOW_POS), - P094_data->getFilterOffWindowTime(), - 0, - 60000); - addUnit(F("msec")); - addFormNote(F("0 = Do not turn off filter after sending to the connected device.")); + if (nullptr != P094_data) { + P094_data->setFlags( + P094_DISABLE_WINDOW_TIME_MS, + P094_GET_INTERVAL_FILTER, + P094_GET_MUTE_MESSAGES, + P094_GET_COLLECT_STATS); + } +} - { - const __FlashStringHelper * options[P094_Match_Type_NR_ELEMENTS]; - int optionValues[P094_Match_Type_NR_ELEMENTS]; +void P094_html_show_matchForms(struct EventStruct *event) { + addFormNumericBox(F("Filter Off Window after send"), + F("disableTime"), + P094_DISABLE_WINDOW_TIME_MS, + 0, + 60000); + addUnit(F("msec")); + addFormNote(F("0 = Do not turn off filter after sending to the connected device.")); + + addFormNumericBox( + F("Nr Filters"), + F("nrfilters"), + P094_NR_FILTERS, + 0, + P094_MAX_NR_FILTERS); - for (int i = 0; i < P094_Match_Type_NR_ELEMENTS; ++i) { - P094_Match_Type matchType = static_cast(i); - options[i] = P094_data_struct::MatchType_toString(matchType); - optionValues[i] = matchType; - } - P094_Match_Type choice = P094_data->getMatchType(); - addFormSelector(F("Filter Mode"), - getPluginCustomArgName(P094_MATCH_TYPE_POS), - P094_Match_Type_NR_ELEMENTS, - options, - optionValues, - choice, - false); - } + P094_data_struct *P094_data = + static_cast(getPluginTaskData(event->TaskIndex)); - uint8_t filterSet = 0; - uint32_t optional = 0; - P094_Filter_Value_Type capture = P094_Filter_Value_Type::P094_packet_length; - P094_Filter_Comp comparator = P094_Filter_Comp::P094_Equal_OR; - String filter; + const bool localAllocated = nullptr == P094_data; - for (uint8_t filterLine = 0; filterLine < P094_NR_FILTERS; ++filterLine) - { - // Filter parameter number on a filter line. - bool newLine = (filterLine % P094_AND_FILTER_BLOCK) == 0; - - for (uint8_t filterLinePar = 0; filterLinePar < P094_ITEMS_PER_FILTER; ++filterLinePar) - { - String id = getPluginCustomArgName(P094_data_struct::P094_Get_filter_base_index(filterLine) + filterLinePar); - - switch (filterLinePar) { - case 0: - { - filter = P094_data->getFilter(filterLine, capture, optional, comparator); - - if (newLine) { - // Label + first parameter - ++filterSet; - addRowLabel_tr_id(concat(F("Filter "), static_cast(filterSet)), id); - } else { - html_B(F("AND")); - html_BR(); - } + if (localAllocated) { + P094_data = new (std::nothrow) P094_data_struct(); - // Combo box with filter types - { - const __FlashStringHelper * options[P094_FILTER_VALUE_Type_NR_ELEMENTS]; - int optionValues[P094_FILTER_VALUE_Type_NR_ELEMENTS]; + if (nullptr != P094_data) { + P094_data->loadFilters(event, P094_NR_FILTERS); + } + } - for (int i = 0; i < P094_FILTER_VALUE_Type_NR_ELEMENTS; ++i) { - P094_Filter_Value_Type filterValueType = static_cast(i); - options[i] = P094_data_struct::P094_FilterValueType_toString(filterValueType); - optionValues[i] = filterValueType; - } - addSelector(id, P094_FILTER_VALUE_Type_NR_ELEMENTS, options, optionValues, nullptr, capture, false, true, F("")); - } + if ((nullptr != P094_data)) { + P094_data->WebformLoadFilters(P094_NR_FILTERS); - break; - } - case 1: - { - // Optional numerical value - addNumericBox(id, optional, 0, 1024); - break; - } - case 2: - { - // Comparator - const __FlashStringHelper * options[P094_FILTER_COMP_NR_ELEMENTS]; - int optionValues[P094_FILTER_COMP_NR_ELEMENTS]; - - for (int i = 0; i < P094_FILTER_COMP_NR_ELEMENTS; ++i) { - P094_Filter_Comp enumValue = static_cast(i); - options[i] = P094_data_struct::P094_FilterComp_toString(enumValue); - optionValues[i] = enumValue; - } - addSelector(id, P094_FILTER_COMP_NR_ELEMENTS, options, optionValues, nullptr, comparator, false, true, F("")); - break; - } - case 3: - { - // Compare with - addTextBox(id, filter, 8, false, false, EMPTY_STRING, F("")); - break; - } - } - } + if (localAllocated) { + delete P094_data; } } } @@ -445,6 +560,11 @@ void P094_html_show_stats(struct EventStruct *event) { if ((nullptr == P094_data) || !P094_data->isInitialized()) { return; } + + P094_data->html_show_interval_filter_stats(); + + P094_data->html_show_mBus_stats(); + { addRowLabel(F("Current Sentence")); addHtml(P094_data->peekSentence()); @@ -462,4 +582,4 @@ void P094_html_show_stats(struct EventStruct *event) { } } -#endif // USES_P094 \ No newline at end of file +#endif // USES_P094 diff --git a/src/_P116_ST77xx.ino b/src/_P116_ST77xx.ino index ef010cd917..ac85828e88 100644 --- a/src/_P116_ST77xx.ino +++ b/src/_P116_ST77xx.ino @@ -8,6 +8,13 @@ // History: +// 2024-03-17 tonhuisman: Add support for another alternative initialization for ST7735 displays, as the display controller +// used on the LilyGO TTGO T-Display (16 MB) seems to be a ST7735, despite being documented as ST7789 +// By default (also) only enabled on ESP32 builds +// Disabled the ST7789 alternatives for now, as that's not verified on any hardware +// 2024-03-09 tonhuisman: Add support for alternative initialization sequences for ST7789 displays, like used on +// some LilyGO models like the TTGO T-Display (16 MB Flash), and possibly the T-Display S3 +// By default only enabled on ESP32 builds // 2023-02-27 tonhuisman: Implement support for getting config values, see AdafruitGFX_Helper.h changelog for details // 2022-07-06 tonhuisman: Add support for ST7735sv M5Stack StickC (Inverted colors) // 2021-11-16 tonhuisman: P116: Change state from Development to Testing @@ -80,16 +87,16 @@ boolean Plugin_116(uint8_t function, struct EventStruct *event, String& string) case PLUGIN_WEBFORM_SHOW_GPIO_DESCR: { - const char* separator = event->String1.c_str(); // contains the NewLine sequence + const char *separator = event->String1.c_str(); // contains the NewLine sequence string = strformat( F("CS: %s%sDC: %s%s RES: %s%sBtn: %s%sBckl: : %s"), - formatGpioLabel(PIN(0), false).c_str(), + formatGpioLabel(PIN(0), false).c_str(), separator, - formatGpioLabel(PIN(1), false).c_str(), + formatGpioLabel(PIN(1), false).c_str(), separator, - formatGpioLabel(PIN(2), false).c_str(), + formatGpioLabel(PIN(2), false).c_str(), separator, - formatGpioLabel(P116_CONFIG_BUTTON_PIN, false).c_str(), + formatGpioLabel(P116_CONFIG_BUTTON_PIN, false).c_str(), separator, formatGpioLabel(P116_CONFIG_BACKLIGHT_PIN, false).c_str()); success = true; @@ -142,10 +149,18 @@ boolean Plugin_116(uint8_t function, struct EventStruct *event, String& string) ST77xx_type_toString(ST77xx_type_e::ST7735s_128x160), ST77xx_type_toString(ST77xx_type_e::ST7735s_80x160), ST77xx_type_toString(ST77xx_type_e::ST7735s_80x160_M5), + # if P116_EXTRA_ST7735 + ST77xx_type_toString(ST77xx_type_e::ST7735s_135x240), + # endif // if P116_EXTRA_ST7735 ST77xx_type_toString(ST77xx_type_e::ST7789vw_240x320), ST77xx_type_toString(ST77xx_type_e::ST7789vw_240x240), ST77xx_type_toString(ST77xx_type_e::ST7789vw_240x280), ST77xx_type_toString(ST77xx_type_e::ST7789vw_135x240), + # if P116_EXTRA_ST7789 + ST77xx_type_toString(ST77xx_type_e::ST7789vw1_135x240), + ST77xx_type_toString(ST77xx_type_e::ST7789vw2_135x240), + ST77xx_type_toString(ST77xx_type_e::ST7789vw3_135x240), + # endif // if P116_EXTRA_ST7789 ST77xx_type_toString(ST77xx_type_e::ST7796s_320x480) }; const int optionValues4[] = { @@ -153,13 +168,21 @@ boolean Plugin_116(uint8_t function, struct EventStruct *event, String& string) static_cast(ST77xx_type_e::ST7735s_128x160), static_cast(ST77xx_type_e::ST7735s_80x160), static_cast(ST77xx_type_e::ST7735s_80x160_M5), + # if P116_EXTRA_ST7735 + static_cast(ST77xx_type_e::ST7735s_135x240), + # endif // if P116_EXTRA_ST7735 static_cast(ST77xx_type_e::ST7789vw_240x320), static_cast(ST77xx_type_e::ST7789vw_240x240), static_cast(ST77xx_type_e::ST7789vw_240x280), static_cast(ST77xx_type_e::ST7789vw_135x240), + # if P116_EXTRA_ST7789 + static_cast(ST77xx_type_e::ST7789vw1_135x240), + static_cast(ST77xx_type_e::ST7789vw2_135x240), + static_cast(ST77xx_type_e::ST7789vw3_135x240), + # endif // if P116_EXTRA_ST7789 static_cast(ST77xx_type_e::ST7796s_320x480) }; - constexpr int optCount4 = sizeof(optionValues4) / sizeof(optionValues4[0]); + constexpr int optCount4 = NR_ELEMENTS(optionValues4); addFormSelector(F("TFT display model"), F("type"), optCount4, diff --git a/src/src/CustomBuild/define_plugin_sets.h b/src/src/CustomBuild/define_plugin_sets.h index 5091c64f4a..f0ee7eec64 100644 --- a/src/src/CustomBuild/define_plugin_sets.h +++ b/src/src/CustomBuild/define_plugin_sets.h @@ -1463,6 +1463,12 @@ To create/register a plugin, you have to : #ifndef NOTIFIER_SET_NONE #define NOTIFIER_SET_NONE #endif + #ifdef USES_N001 + #undef USES_N001 // Email + #endif + #ifdef USES_N002 + #undef USES_N002 // Buzzer + #endif // Do not include large blobs but fetch them from CDN #ifndef WEBSERVER_USE_CDN_JS_CSS @@ -1701,6 +1707,19 @@ To create/register a plugin, you have to : #ifndef PLUGIN_BUILD_MAX_ESP32 #define LIMIT_BUILD_SIZE // Reduce buildsize (on ESP8266 / pre-IDF4.x) to fit in all Display plugins #define KEEP_I2C_MULTIPLEXER + #ifndef P036_LIMIT_BUILD_SIZE + #define P036_LIMIT_BUILD_SIZE // Reduce build size for P036 (FramedOLED) only + #endif + #ifndef P037_LIMIT_BUILD_SIZE + #define P037_LIMIT_BUILD_SIZE // Reduce build size for P037 (MQTT Import) only + #endif + #define NOTIFIER_SET_NONE + #ifdef USES_N001 + #undef USES_N001 // Email + #endif + #ifdef USES_N002 + #undef USES_N002 // Buzzer + #endif #endif #endif #if defined(ESP8266) @@ -3251,8 +3270,8 @@ To create/register a plugin, you have to : # endif #endif -// Incompatible plugins with ESP32-C2/C6 -#if defined(ESP32C2) || defined(ESP32C6) +// Incompatible plugins with ESP32-C2 // (C6 seems to work as intended) +#if defined(ESP32C2) // || defined(ESP32C6) #define DISABLE_NEOPIXEL_PLUGINS 1 #endif diff --git a/src/src/DataStructs/Caches.cpp b/src/src/DataStructs/Caches.cpp index 017cee9ae5..d8e81269d4 100644 --- a/src/src/DataStructs/Caches.cpp +++ b/src/src/DataStructs/Caches.cpp @@ -357,7 +357,7 @@ void Caches::updateExtraTaskSettingsCache() } #endif // ifdef ESP32 - extraTaskSettings_cache[TaskIndex] = tmp; + extraTaskSettings_cache.emplace(std::make_pair(TaskIndex, std::move(tmp))); } } diff --git a/src/src/DataStructs/ControllerSettingsStruct.cpp b/src/src/DataStructs/ControllerSettingsStruct.cpp index 9a6bf6e490..7587379a0c 100644 --- a/src/src/DataStructs/ControllerSettingsStruct.cpp +++ b/src/src/DataStructs/ControllerSettingsStruct.cpp @@ -25,16 +25,25 @@ void ControllerSettingsStruct::reset() { // Otherwise the checksum will fail and settings will be saved too often. memset(this, 0, sizeof(ControllerSettingsStruct)); - UseDNS = DEFAULT_SERVER_USEDNS; - Port = DEFAULT_PORT; - MinimalTimeBetweenMessages = CONTROLLER_DELAY_QUEUE_DELAY_DFLT; - MaxQueueDepth = CONTROLLER_DELAY_QUEUE_DEPTH_DFLT; - MaxRetry = CONTROLLER_DELAY_QUEUE_RETRY_DFLT; - DeleteOldest = DEFAULT_CONTROLLER_DELETE_OLDEST; - ClientTimeout = CONTROLLER_CLIENTTIMEOUT_DFLT; - MustCheckReply = DEFAULT_CONTROLLER_MUST_CHECK_REPLY ; - SampleSetInitiator = INVALID_TASK_INDEX; - VariousFlags = 0; + UseDNS = DEFAULT_SERVER_USEDNS; + Port = DEFAULT_PORT; + MinimalTimeBetweenMessages = CONTROLLER_DELAY_QUEUE_DELAY_DFLT; + MaxQueueDepth = CONTROLLER_DELAY_QUEUE_DEPTH_DFLT; + MaxRetry = CONTROLLER_DELAY_QUEUE_RETRY_DFLT; + DeleteOldest = DEFAULT_CONTROLLER_DELETE_OLDEST; + ClientTimeout = CONTROLLER_CLIENTTIMEOUT_DFLT; + MustCheckReply = DEFAULT_CONTROLLER_MUST_CHECK_REPLY; + SampleSetInitiator = INVALID_TASK_INDEX; + VariousBits1.mqtt_cleanSession = 0; + VariousBits1.mqtt_not_sendLWT = 0; + VariousBits1.mqtt_not_willRetain = 0; + VariousBits1.mqtt_uniqueMQTTclientIdReconnect = 0; + VariousBits1.mqtt_retainFlag = 0; + VariousBits1.useExtendedCredentials = 0; + VariousBits1.sendBinary = 0; + VariousBits1.allowExpire = 0; + VariousBits1.deduplicate = 0; + VariousBits1.useLocalSystemTime = 0; safe_strncpy(ClientID, F(CONTROLLER_DEFAULT_CLIENTID), sizeof(ClientID)); } @@ -72,7 +81,6 @@ void ControllerSettingsStruct::validate() { ZERO_TERMINATE(LWTMessageDisconnect); } - String ControllerSettingsStruct::getHost() const { if (UseDNS) { return HostName; @@ -90,6 +98,7 @@ bool ControllerSettingsStruct::checkHostReachable(bool quick) { // No IP/hostname set return false; } + if (!NetworkConnected(10)) { return false; // Not connected, so no use in wasting time to connect to a host. } @@ -111,7 +120,7 @@ bool ControllerSettingsStruct::connectToHost(WiFiClient& client) { return false; // Host not reachable } uint8_t retry = 2; - bool connected = false; + bool connected = false; while (retry > 0 && !connected) { --retry; @@ -125,16 +134,19 @@ bool ControllerSettingsStruct::connectToHost(WiFiClient& client) { } return false; } + #endif // FEATURE_HTTP_CLIENT bool ControllerSettingsStruct::beginPacket(WiFiUDP& client) { if (!checkHostReachable(true)) { return false; // Host not reachable } - uint8_t retry = 2; + uint8_t retry = 2; + while (retry > 0) { --retry; FeedSW_watchdog(); + if (client.beginPacket(getIP(), Port) == 1) { return true; } @@ -181,101 +193,101 @@ bool ControllerSettingsStruct::updateIPcache() { /* bool ControllerSettingsStruct::mqtt_cleanSession() const { - return bitRead(VariousFlags, 1); -} - -void ControllerSettingsStruct::mqtt_cleanSession(bool value) -{ - bitWrite(VariousFlags, 1, value); -} - -bool ControllerSettingsStruct::mqtt_sendLWT() const -{ - return !bitRead(VariousFlags, 2); -} - -void ControllerSettingsStruct::mqtt_sendLWT(bool value) -{ - bitWrite(VariousFlags, 2, !value); -} - -bool ControllerSettingsStruct::mqtt_willRetain() const -{ - return !bitRead(VariousFlags, 3); -} - -void ControllerSettingsStruct::mqtt_willRetain(bool value) -{ - bitWrite(VariousFlags, 3, !value); -} - -bool ControllerSettingsStruct::mqtt_uniqueMQTTclientIdReconnect() const -{ - return bitRead(VariousFlags, 4); -} - -void ControllerSettingsStruct::mqtt_uniqueMQTTclientIdReconnect(bool value) -{ - bitWrite(VariousFlags, 4, value); -} - -bool ControllerSettingsStruct::mqtt_retainFlag() const -{ - return bitRead(VariousFlags, 5); -} - -void ControllerSettingsStruct::mqtt_retainFlag(bool value) -{ - bitWrite(VariousFlags, 5, value); -} - -bool ControllerSettingsStruct::useExtendedCredentials() const -{ - return bitRead(VariousFlags, 6); -} - -void ControllerSettingsStruct::useExtendedCredentials(bool value) -{ - bitWrite(VariousFlags, 6, value); -} - -bool ControllerSettingsStruct::sendBinary() const -{ - return bitRead(VariousFlags, 7); -} - -void ControllerSettingsStruct::sendBinary(bool value) -{ - bitWrite(VariousFlags, 7, value); -} - -bool ControllerSettingsStruct::allowExpire() const -{ - return bitRead(VariousFlags, 9); -} - -void ControllerSettingsStruct::allowExpire(bool value) -{ - bitWrite(VariousFlags, 9, value); -} - -bool ControllerSettingsStruct::deduplicate() const -{ - return bitRead(VariousFlags, 10); -} - -void ControllerSettingsStruct::deduplicate(bool value) -{ - bitWrite(VariousFlags, 10, value); -} - -bool ControllerSettingsStruct::useLocalSystemTime() const -{ - return bitRead(VariousFlags, 11); -} - -void ControllerSettingsStruct::useLocalSystemTime(bool value) -{ + return bitRead(VariousFlags, 1); + } + + void ControllerSettingsStruct::mqtt_cleanSession(bool value) + { + bitWrite(VariousFlags, 1, value); + } + + bool ControllerSettingsStruct::mqtt_sendLWT() const + { + return !bitRead(VariousFlags, 2); + } + + void ControllerSettingsStruct::mqtt_sendLWT(bool value) + { + bitWrite(VariousFlags, 2, !value); + } + + bool ControllerSettingsStruct::mqtt_willRetain() const + { + return !bitRead(VariousFlags, 3); + } + + void ControllerSettingsStruct::mqtt_willRetain(bool value) + { + bitWrite(VariousFlags, 3, !value); + } + + bool ControllerSettingsStruct::mqtt_uniqueMQTTclientIdReconnect() const + { + return bitRead(VariousFlags, 4); + } + + void ControllerSettingsStruct::mqtt_uniqueMQTTclientIdReconnect(bool value) + { + bitWrite(VariousFlags, 4, value); + } + + bool ControllerSettingsStruct::mqtt_retainFlag() const + { + return bitRead(VariousFlags, 5); + } + + void ControllerSettingsStruct::mqtt_retainFlag(bool value) + { + bitWrite(VariousFlags, 5, value); + } + + bool ControllerSettingsStruct::useExtendedCredentials() const + { + return bitRead(VariousFlags, 6); + } + + void ControllerSettingsStruct::useExtendedCredentials(bool value) + { + bitWrite(VariousFlags, 6, value); + } + + bool ControllerSettingsStruct::sendBinary() const + { + return bitRead(VariousFlags, 7); + } + + void ControllerSettingsStruct::sendBinary(bool value) + { + bitWrite(VariousFlags, 7, value); + } + + bool ControllerSettingsStruct::allowExpire() const + { + return bitRead(VariousFlags, 9); + } + + void ControllerSettingsStruct::allowExpire(bool value) + { + bitWrite(VariousFlags, 9, value); + } + + bool ControllerSettingsStruct::deduplicate() const + { + return bitRead(VariousFlags, 10); + } + + void ControllerSettingsStruct::deduplicate(bool value) + { + bitWrite(VariousFlags, 10, value); + } + + bool ControllerSettingsStruct::useLocalSystemTime() const + { + return bitRead(VariousFlags, 11); + } + + void ControllerSettingsStruct::useLocalSystemTime(bool value) + { bitWrite(VariousFlags, 11, value); } */ \ No newline at end of file diff --git a/src/src/DataStructs/ControllerSettingsStruct.h b/src/src/DataStructs/ControllerSettingsStruct.h index f11825751e..ff45d4fd21 100644 --- a/src/src/DataStructs/ControllerSettingsStruct.h +++ b/src/src/DataStructs/ControllerSettingsStruct.h @@ -124,7 +124,7 @@ struct ControllerSettingsStruct String getHostPortString() const; - // VariousFlags defaults to 0, keep in mind when adding bit lookups. + // VariousBits1 defaults to 0, keep in mind when adding bit lookups. bool mqtt_cleanSession() const { return VariousBits1.mqtt_cleanSession; } void mqtt_cleanSession(bool value) { VariousBits1.mqtt_cleanSession = value; } @@ -172,43 +172,40 @@ struct ControllerSettingsStruct bool MustCheckReply; // When set to false, a sent message is considered always successful. taskIndex_t SampleSetInitiator; // The first task to start a sample set. - union { - struct { - uint32_t unused_00 : 1; // Bit 00 - uint32_t mqtt_cleanSession : 1; // Bit 01 - uint32_t mqtt_not_sendLWT : 1; // Bit 02, !value, default enabled - uint32_t mqtt_not_willRetain : 1; // Bit 03, !value, default enabled - uint32_t mqtt_uniqueMQTTclientIdReconnect : 1; // Bit 04 - uint32_t mqtt_retainFlag : 1; // Bit 05 - uint32_t useExtendedCredentials : 1; // Bit 06 - uint32_t sendBinary : 1; // Bit 07 - uint32_t unused_08 : 1; // Bit 08 - uint32_t allowExpire : 1; // Bit 09 - uint32_t deduplicate : 1; // Bit 10 - uint32_t useLocalSystemTime : 1; // Bit 11 - uint32_t unused_12 : 1; // Bit 12 - uint32_t unused_13 : 1; // Bit 13 - uint32_t unused_14 : 1; // Bit 14 - uint32_t unused_15 : 1; // Bit 15 - uint32_t unused_16 : 1; // Bit 16 - uint32_t unused_17 : 1; // Bit 17 - uint32_t unused_18 : 1; // Bit 18 - uint32_t unused_19 : 1; // Bit 19 - uint32_t unused_20 : 1; // Bit 20 - uint32_t unused_21 : 1; // Bit 21 - uint32_t unused_22 : 1; // Bit 22 - uint32_t unused_23 : 1; // Bit 23 - uint32_t unused_24 : 1; // Bit 24 - uint32_t unused_25 : 1; // Bit 25 - uint32_t unused_26 : 1; // Bit 26 - uint32_t unused_27 : 1; // Bit 27 - uint32_t unused_28 : 1; // Bit 28 - uint32_t unused_29 : 1; // Bit 29 - uint32_t unused_30 : 1; // Bit 30 - uint32_t unused_31 : 1; // Bit 31 - } VariousBits1; - uint32_t VariousFlags; // Various flags - }; + struct { + uint32_t unused_00 : 1; // Bit 00 + uint32_t mqtt_cleanSession : 1; // Bit 01 + uint32_t mqtt_not_sendLWT : 1; // Bit 02, !value, default enabled + uint32_t mqtt_not_willRetain : 1; // Bit 03, !value, default enabled + uint32_t mqtt_uniqueMQTTclientIdReconnect : 1; // Bit 04 + uint32_t mqtt_retainFlag : 1; // Bit 05 + uint32_t useExtendedCredentials : 1; // Bit 06 + uint32_t sendBinary : 1; // Bit 07 + uint32_t unused_08 : 1; // Bit 08 + uint32_t allowExpire : 1; // Bit 09 + uint32_t deduplicate : 1; // Bit 10 + uint32_t useLocalSystemTime : 1; // Bit 11 + uint32_t unused_12 : 1; // Bit 12 + uint32_t unused_13 : 1; // Bit 13 + uint32_t unused_14 : 1; // Bit 14 + uint32_t unused_15 : 1; // Bit 15 + uint32_t unused_16 : 1; // Bit 16 + uint32_t unused_17 : 1; // Bit 17 + uint32_t unused_18 : 1; // Bit 18 + uint32_t unused_19 : 1; // Bit 19 + uint32_t unused_20 : 1; // Bit 20 + uint32_t unused_21 : 1; // Bit 21 + uint32_t unused_22 : 1; // Bit 22 + uint32_t unused_23 : 1; // Bit 23 + uint32_t unused_24 : 1; // Bit 24 + uint32_t unused_25 : 1; // Bit 25 + uint32_t unused_26 : 1; // Bit 26 + uint32_t unused_27 : 1; // Bit 27 + uint32_t unused_28 : 1; // Bit 28 + uint32_t unused_29 : 1; // Bit 29 + uint32_t unused_30 : 1; // Bit 30 + uint32_t unused_31 : 1; // Bit 31 + } VariousBits1; char ClientID[65]; // Used to define the Client ID used by the controller private: diff --git a/src/src/DataStructs/EthernetEventData.cpp b/src/src/DataStructs/EthernetEventData.cpp index 9699e0f8d4..62acc93bf0 100644 --- a/src/src/DataStructs/EthernetEventData.cpp +++ b/src/src/DataStructs/EthernetEventData.cpp @@ -176,17 +176,25 @@ void EthernetEventData_t::markDisconnect() { } lastConnectMoment.clear(); processedDisconnect = false; +#if ESP_IDF_VERSION_MAJOR >= 5 + WiFi.STA.setDefault(); +#endif } void EthernetEventData_t::markConnected() { lastConnectMoment.setNow(); processedConnect = false; +#if ESP_IDF_VERSION_MAJOR >= 5 + ETH.setDefault(); +#endif + #if FEATURE_USE_IPV6 ETH.enableIPv6(true); + /* // workaround for the race condition in LWIP, see https://github.com/espressif/arduino-esp32/pull/9016#discussion_r1451774885 { uint32_t i = 5; // try 5 times only - while (esp_netif_create_ip6_linklocal(get_esp_interface_netif(ESP_IF_ETH)) != ESP_OK) { + while (esp_netif_create_ip6_linklocal(ETH.netif()) != ESP_OK) { delay(1); if (i-- == 0) { // addLog(LOG_LEVEL_ERROR, ">>>> HELP"); @@ -194,6 +202,7 @@ void EthernetEventData_t::markConnected() { } } } + */ #endif } diff --git a/src/src/DataStructs/PluginStats_Config.cpp b/src/src/DataStructs/PluginStats_Config.cpp index 9df1b78d66..2e8fa78bdb 100644 --- a/src/src/DataStructs/PluginStats_Config.cpp +++ b/src/src/DataStructs/PluginStats_Config.cpp @@ -6,7 +6,7 @@ PluginStats_Config_t & PluginStats_Config_t::operator=(const PluginStats_Config_t& other) { - stored = other.stored; + setStored(other.getStored()); return *this; } diff --git a/src/src/DataStructs/PluginStats_Config.h b/src/src/DataStructs/PluginStats_Config.h index 115bcf330d..2be9235f16 100644 --- a/src/src/DataStructs/PluginStats_Config.h +++ b/src/src/DataStructs/PluginStats_Config.h @@ -12,9 +12,13 @@ struct PluginStats_Config_t { Right }; - PluginStats_Config_t() : stored(0) {} + PluginStats_Config_t() { + setStored(0); + } - PluginStats_Config_t(uint8_t stored_value) : stored(stored_value) {} + PluginStats_Config_t(uint8_t stored_value) { + setStored(stored_value); + } PluginStats_Config_t& operator=(const PluginStats_Config_t& other); @@ -37,7 +41,7 @@ struct PluginStats_Config_t { } uint8_t getStoredBits() const { - return stored & ~0x02; // Mask unused_01 + return getStored() & ~0x02; // Mask unused_01 } bool isEnabled() const { @@ -58,18 +62,27 @@ struct PluginStats_Config_t { private: - union { - struct { - uint8_t enabled : 1; // Bit 00 - uint8_t unused_01 : 1; // Bit 01 Used by isDefaultTaskVarName in ExtraTaskSettingsStruct - uint8_t hidden : 1; // Bit 02 Hidden/Displayed state on initial showing of the chart - uint8_t chartAxisIndex : 2; // Bit 03 ... 04 - uint8_t chartAxisPosition : 1; // Bit 05 - uint8_t unused_06 : 1; // Bit 06 - uint8_t unused_07 : 1; // Bit 07 - } bits; - uint8_t stored{}; - }; + uint8_t getStored() const { + uint8_t res{}; + memcpy(&res, &bits, sizeof(uint8_t)); + return res; + } + + // Needs to be inline in the header file as it is used in the constructor + void setStored(uint8_t value) { + memcpy(&bits, &value, sizeof(uint8_t)); + } + + struct { + uint8_t enabled : 1; // Bit 00 + uint8_t unused_01 : 1; // Bit 01 Used by isDefaultTaskVarName in ExtraTaskSettingsStruct + uint8_t hidden : 1; // Bit 02 Hidden/Displayed state on initial showing of the chart + uint8_t chartAxisIndex : 2; // Bit 03 ... 04 + uint8_t chartAxisPosition : 1; // Bit 05 + uint8_t unused_06 : 1; // Bit 06 + uint8_t unused_07 : 1; // Bit 07 + } bits; + }; #endif // if FEATURE_PLUGIN_STATS diff --git a/src/src/DataStructs/ProtocolStruct.h b/src/src/DataStructs/ProtocolStruct.h index 290ea97839..4acc2c98a6 100644 --- a/src/src/DataStructs/ProtocolStruct.h +++ b/src/src/DataStructs/ProtocolStruct.h @@ -20,26 +20,23 @@ struct ProtocolStruct } uint16_t defaultPort{}; - union { - struct { - uint16_t usesMQTT : 1; - uint16_t usesAccount : 1; - uint16_t usesPassword : 1; - uint16_t usesTemplate : 1; // When set, the protocol will pre-load some templates like default MQTT topics - uint16_t usesID : 1; // Whether a controller supports sending an IDX value sent along with plugin data - uint16_t Custom : 1; // When set, the controller has to define all parameters on the controller setup page - uint16_t usesHost : 1; - uint16_t usesPort : 1; - uint16_t usesQueue : 1; - uint16_t usesCheckReply : 1; - uint16_t usesTimeout : 1; - uint16_t usesSampleSets : 1; - uint16_t usesExtCreds : 1; - uint16_t needsNetwork : 1; - uint16_t allowsExpire : 1; - uint16_t allowLocalSystemTime : 1; - }; - uint16_t bits{}; + struct { + uint16_t usesMQTT : 1; + uint16_t usesAccount : 1; + uint16_t usesPassword : 1; + uint16_t usesTemplate : 1; // When set, the protocol will pre-load some templates like default MQTT topics + uint16_t usesID : 1; // Whether a controller supports sending an IDX value sent along with plugin data + uint16_t Custom : 1; // When set, the controller has to define all parameters on the controller setup page + uint16_t usesHost : 1; + uint16_t usesPort : 1; + uint16_t usesQueue : 1; + uint16_t usesCheckReply : 1; + uint16_t usesTimeout : 1; + uint16_t usesSampleSets : 1; + uint16_t usesExtCreds : 1; + uint16_t needsNetwork : 1; + uint16_t allowsExpire : 1; + uint16_t allowLocalSystemTime : 1; }; // uint8_t Number{}; diff --git a/src/src/DataStructs/ProvisioningStruct.h b/src/src/DataStructs/ProvisioningStruct.h index ba8007b300..25a959721b 100644 --- a/src/src/DataStructs/ProvisioningStruct.h +++ b/src/src/DataStructs/ProvisioningStruct.h @@ -39,21 +39,16 @@ struct ProvisioningStruct char pass[64] = { 0 }; char url[128] = { 0 }; - union { - uint16_t allowed{}; - struct { - uint16_t allowFetchFirmware :1; - uint16_t allowFetchConfigDat :1; - uint16_t allowFetchSecurityDat :1; - uint16_t allowFetchNotificationDat :1; - uint16_t allowFetchProvisioningDat :1; - uint16_t allowFetchRules :4; - - uint16_t unused :7; // Add to use full 16 bit. - } allowedFlags; - }; - - + struct { + uint16_t allowFetchFirmware :1; + uint16_t allowFetchConfigDat :1; + uint16_t allowFetchSecurityDat :1; + uint16_t allowFetchNotificationDat :1; + uint16_t allowFetchProvisioningDat :1; + uint16_t allowFetchRules :4; + + uint16_t unused :7; // Add to use full 16 bit. + } allowedFlags; }; typedef std::shared_ptr ProvisioningStruct_ptr_type; diff --git a/src/src/DataStructs/SchedulerTimerID.cpp b/src/src/DataStructs/SchedulerTimerID.cpp index 1424061033..9cacd4c2bf 100644 --- a/src/src/DataStructs/SchedulerTimerID.cpp +++ b/src/src/DataStructs/SchedulerTimerID.cpp @@ -1,6 +1,23 @@ #include "../DataStructs/SchedulerTimerID.h" +#include "../Helpers/Misc.h" + SchedulerTimerID::SchedulerTimerID(SchedulerTimerType_e timerType) { - timer_type = static_cast(timerType); + set4BitToUL(mixed_id, 0, static_cast(timerType)); +} + +void SchedulerTimerID::setTimerType(SchedulerTimerType_e timerType) +{ + set4BitToUL(mixed_id, 0, static_cast(timerType)); +} + +SchedulerTimerType_e SchedulerTimerID::getTimerType() const +{ + return static_cast(get4BitFromUL(mixed_id, 0)); +} + +uint32_t SchedulerTimerID::getId() const +{ + return mixed_id >> 4; } diff --git a/src/src/DataStructs/SchedulerTimerID.h b/src/src/DataStructs/SchedulerTimerID.h index 42d61fceb5..c1cd05dae2 100644 --- a/src/src/DataStructs/SchedulerTimerID.h +++ b/src/src/DataStructs/SchedulerTimerID.h @@ -11,24 +11,22 @@ struct SchedulerTimerID { explicit SchedulerTimerID(uint32_t mixedID) : mixed_id(mixedID) {} - union { - struct { - uint32_t id : 28; - uint32_t timer_type : 4; // Change this when SchedulerTimerType_e needs more bits - }; + virtual ~SchedulerTimerID() {} - uint32_t mixed_id{}; - }; + void setTimerType(SchedulerTimerType_e timerType); + SchedulerTimerType_e getTimerType() const; - void setTimerType(SchedulerTimerType_e timerType) - { - timer_type = static_cast(timerType); - } - SchedulerTimerType_e getTimerType() const + uint32_t getId() const; + + // Have setId in the header file as it is used in the constructor of derived classes + // Thus it should be inline as we otherwise cannot call member functions of base class in the constructor in a derived class + void setId(uint32_t id) { - return static_cast(timer_type); + mixed_id = (id << 4) | (mixed_id & 0x0f); } + + uint32_t mixed_id{}; }; diff --git a/src/src/DataStructs/Scheduler_ConstIntervalTimerID.h b/src/src/DataStructs/Scheduler_ConstIntervalTimerID.h index a5eb92b943..17d175c6e1 100644 --- a/src/src/DataStructs/Scheduler_ConstIntervalTimerID.h +++ b/src/src/DataStructs/Scheduler_ConstIntervalTimerID.h @@ -9,12 +9,12 @@ struct ConstIntervalTimerID : SchedulerTimerID { ConstIntervalTimerID(SchedulerIntervalTimer_e timer) : SchedulerTimerID(SchedulerTimerType_e::ConstIntervalTimer) { - id = static_cast(timer); + setId(static_cast(timer)); } SchedulerIntervalTimer_e getIntervalTimer() const { - return static_cast(id); + return static_cast(getId()); } #ifndef BUILD_NO_DEBUG diff --git a/src/src/DataStructs/Scheduler_GPIOTimerID.cpp b/src/src/DataStructs/Scheduler_GPIOTimerID.cpp index 0900ebb900..10416ecf52 100644 --- a/src/src/DataStructs/Scheduler_GPIOTimerID.cpp +++ b/src/src/DataStructs/Scheduler_GPIOTimerID.cpp @@ -5,7 +5,7 @@ GPIOTimerID::GPIOTimerID(uint8_t GPIOType, uint8_t pinNumber, int Par1) : SchedulerTimerID(SchedulerTimerType_e::GPIO_timer) { - id = (Par1 << 16) + (pinNumber << 8) + GPIOType; + setId((Par1 << 16) + (pinNumber << 8) + GPIOType); } diff --git a/src/src/DataStructs/Scheduler_GPIOTimerID.h b/src/src/DataStructs/Scheduler_GPIOTimerID.h index 588617fa9a..41f5fd169f 100644 --- a/src/src/DataStructs/Scheduler_GPIOTimerID.h +++ b/src/src/DataStructs/Scheduler_GPIOTimerID.h @@ -8,18 +8,20 @@ * Special timer to handle timed GPIO actions \*********************************************************************************************/ struct GPIOTimerID : SchedulerTimerID { - GPIOTimerID(uint8_t GPIOType, uint8_t pinNumber, int Par1); + GPIOTimerID(uint8_t GPIOType, + uint8_t pinNumber, + int Par1); uint8_t getGPIO_type() const { - return static_cast((id) & 0xFF); + return static_cast((getId()) & 0xFF); } uint8_t getPinNumber() const { - return static_cast((id >> 8) & 0xFF); + return static_cast((getId() >> 8) & 0xFF); } uint8_t getPinStateValue() const { - return static_cast((id >> 16) & 0xFF); + return static_cast((getId() >> 16) & 0xFF); } #ifndef BUILD_NO_DEBUG diff --git a/src/src/DataStructs/Scheduler_IntendedRebootTimerID.cpp b/src/src/DataStructs/Scheduler_IntendedRebootTimerID.cpp index 8013bde6e3..2611b31686 100644 --- a/src/src/DataStructs/Scheduler_IntendedRebootTimerID.cpp +++ b/src/src/DataStructs/Scheduler_IntendedRebootTimerID.cpp @@ -4,6 +4,6 @@ IntendedRebootTimerID::IntendedRebootTimerID(IntendedRebootReason_e reason) : SchedulerTimerID(SchedulerTimerType_e::IntendedReboot) { - id = static_cast(reason); + setId(static_cast(reason)); } diff --git a/src/src/DataStructs/Scheduler_IntendedRebootTimerID.h b/src/src/DataStructs/Scheduler_IntendedRebootTimerID.h index afffb312c8..8df8ddd880 100644 --- a/src/src/DataStructs/Scheduler_IntendedRebootTimerID.h +++ b/src/src/DataStructs/Scheduler_IntendedRebootTimerID.h @@ -10,7 +10,7 @@ struct IntendedRebootTimerID : SchedulerTimerID { IntendedRebootReason_e getReason() const { - return static_cast(id); + return static_cast(getId()); } #ifndef BUILD_NO_DEBUG diff --git a/src/src/DataStructs/Scheduler_PluginDeviceTimerID.cpp b/src/src/DataStructs/Scheduler_PluginDeviceTimerID.cpp index 019677eb9d..979dba5dd9 100644 --- a/src/src/DataStructs/Scheduler_PluginDeviceTimerID.cpp +++ b/src/src/DataStructs/Scheduler_PluginDeviceTimerID.cpp @@ -14,7 +14,7 @@ PluginDeviceTimerID::PluginDeviceTimerID(pluginID_t pluginID, int Par1) : // FIXME TD-er: Must add a constexpr function with nr of included plugins. const unsigned nrBits = getNrBitsDeviceIndex(); const unsigned mask = MASK_BITS(nrBits); - id = (deviceIndex.value & mask) | (Par1 << nrBits); + setId((deviceIndex.value & mask) | (Par1 << nrBits)); } } @@ -22,7 +22,7 @@ deviceIndex_t PluginDeviceTimerID::get_deviceIndex() const { const unsigned nrBits = getNrBitsDeviceIndex(); const unsigned mask = MASK_BITS(nrBits); - return deviceIndex_t::toDeviceIndex(id & mask); + return deviceIndex_t::toDeviceIndex(getId() & mask); } #ifndef BUILD_NO_DEBUG @@ -33,7 +33,7 @@ String PluginDeviceTimerID::decode() const if (validDeviceIndex(deviceIndex)) { return getPluginNameFromDeviceIndex(deviceIndex); } - return String(id); + return String(getId()); } #endif // ifndef BUILD_NO_DEBUG diff --git a/src/src/DataStructs/Scheduler_PluginTaskTimerID.cpp b/src/src/DataStructs/Scheduler_PluginTaskTimerID.cpp index c0500ede38..5f0c3885eb 100644 --- a/src/src/DataStructs/Scheduler_PluginTaskTimerID.cpp +++ b/src/src/DataStructs/Scheduler_PluginTaskTimerID.cpp @@ -14,9 +14,9 @@ PluginTaskTimerID::PluginTaskTimerID(taskIndex_t taskIndex, constexpr unsigned mask_function = MASK_BITS(nrBitsPluginFunction); if (validTaskIndex(taskIndex)) { - id = (taskIndex & mask_taskIndex) | + setId((taskIndex & mask_taskIndex) | ((function & mask_function) << nrBitsTaskIndex) | - (Par1 << (nrBitsTaskIndex + nrBitsPluginFunction)); + (Par1 << (nrBitsTaskIndex + nrBitsPluginFunction))); } } @@ -25,7 +25,7 @@ taskIndex_t PluginTaskTimerID::getTaskIndex() const constexpr unsigned nrBitsTaskIndex = NR_BITS(TASKS_MAX); constexpr unsigned mask_taskIndex = MASK_BITS(nrBitsTaskIndex); - return static_cast(id & mask_taskIndex); + return static_cast(getId() & mask_taskIndex); } PluginFunctions_e PluginTaskTimerID::getFunction() const @@ -34,7 +34,7 @@ PluginFunctions_e PluginTaskTimerID::getFunction() const constexpr unsigned nrBitsPluginFunction = NrBitsPluginFunctions; constexpr unsigned mask_function = MASK_BITS(nrBitsPluginFunction); - return static_cast((id >> nrBitsTaskIndex) & mask_function); + return static_cast((getId() >> nrBitsTaskIndex) & mask_function); } #ifndef BUILD_NO_DEBUG @@ -45,7 +45,7 @@ String PluginTaskTimerID::decode() const if (validTaskIndex(taskIndex)) { return getTaskDeviceName(taskIndex); } - return String(id); + return String(getId()); } #endif // ifndef BUILD_NO_DEBUG diff --git a/src/src/DataStructs/Scheduler_RulesTimerID.cpp b/src/src/DataStructs/Scheduler_RulesTimerID.cpp index 5ee8dfc720..b5f3c2929c 100644 --- a/src/src/DataStructs/Scheduler_RulesTimerID.cpp +++ b/src/src/DataStructs/Scheduler_RulesTimerID.cpp @@ -5,13 +5,13 @@ RulesTimerID::RulesTimerID(unsigned int timerIndex) : SchedulerTimerID(SchedulerTimerType_e::RulesTimer) { - id = timerIndex; + setId(timerIndex); } #ifndef BUILD_NO_DEBUG String RulesTimerID::decode() const { - return concat(F("Rules#Timer="), id); + return concat(F("Rules#Timer="), getId()); } #endif // ifndef BUILD_NO_DEBUG diff --git a/src/src/DataStructs/Scheduler_SystemEventQueueTimerID.cpp b/src/src/DataStructs/Scheduler_SystemEventQueueTimerID.cpp index e111b545f3..a241920c4f 100644 --- a/src/src/DataStructs/Scheduler_SystemEventQueueTimerID.cpp +++ b/src/src/DataStructs/Scheduler_SystemEventQueueTimerID.cpp @@ -7,9 +7,9 @@ SystemEventQueueTimerID::SystemEventQueueTimerID(SchedulerPluginPtrType_e ptr_type, uint8_t Index, uint8_t Function) : SchedulerTimerID(SchedulerTimerType_e::SystemEventQueue) { - id = (static_cast(ptr_type) << 16) + + setId((static_cast(ptr_type) << 16) + (Index << 8) + - Function; + Function); } diff --git a/src/src/DataStructs/Scheduler_SystemEventQueueTimerID.h b/src/src/DataStructs/Scheduler_SystemEventQueueTimerID.h index 7dff58adac..10ceafed43 100644 --- a/src/src/DataStructs/Scheduler_SystemEventQueueTimerID.h +++ b/src/src/DataStructs/Scheduler_SystemEventQueueTimerID.h @@ -16,15 +16,15 @@ struct SystemEventQueueTimerID : SchedulerTimerID { uint8_t Function); uint8_t getFunction() const { - return static_cast((id) & 0xFF); + return static_cast((getId()) & 0xFF); } uint8_t getIndex() const { - return static_cast((id >> 8) & 0xFF); + return static_cast((getId() >> 8) & 0xFF); } SchedulerPluginPtrType_e getPtrType() const { - return static_cast((id >> 16) & 0xFF); + return static_cast((getId() >> 16) & 0xFF); } #ifndef BUILD_NO_DEBUG diff --git a/src/src/DataStructs/Scheduler_TaskDeviceTimerID.cpp b/src/src/DataStructs/Scheduler_TaskDeviceTimerID.cpp index 3363fef4f1..fa12d1e369 100644 --- a/src/src/DataStructs/Scheduler_TaskDeviceTimerID.cpp +++ b/src/src/DataStructs/Scheduler_TaskDeviceTimerID.cpp @@ -6,7 +6,7 @@ TaskDeviceTimerID::TaskDeviceTimerID(taskIndex_t taskIndex) : SchedulerTimerID(SchedulerTimerType_e::TaskDeviceTimer) { - id = static_cast(taskIndex); + setId(static_cast(taskIndex)); } #ifndef BUILD_NO_DEBUG @@ -16,7 +16,7 @@ String TaskDeviceTimerID::decode() const return concat(F("Task "), validTaskIndex(taskIndex) ? getTaskDeviceName(taskIndex) - : String(id)); + : String(getId())); } #endif // ifndef BUILD_NO_DEBUG diff --git a/src/src/DataStructs/Scheduler_TaskDeviceTimerID.h b/src/src/DataStructs/Scheduler_TaskDeviceTimerID.h index 6da5407bf2..6f539f07d8 100644 --- a/src/src/DataStructs/Scheduler_TaskDeviceTimerID.h +++ b/src/src/DataStructs/Scheduler_TaskDeviceTimerID.h @@ -14,7 +14,7 @@ struct TaskDeviceTimerID : SchedulerTimerID { taskIndex_t getTaskIndex() const { - return static_cast(id); + return static_cast(getId()); } #ifndef BUILD_NO_DEBUG diff --git a/src/src/DataStructs/SettingsStruct.h b/src/src/DataStructs/SettingsStruct.h index 10a46b06c2..1fc8af9090 100644 --- a/src/src/DataStructs/SettingsStruct.h +++ b/src/src/DataStructs/SettingsStruct.h @@ -11,7 +11,7 @@ #include "../DataTypes/NetworkMedium.h" #include "../DataTypes/NPluginID.h" #include "../DataTypes/PluginID.h" -#include "../DataTypes/TaskEnabledState.h" +//#include "../DataTypes/TaskEnabledState.h" #include "../DataTypes/TimeSource.h" #include "../Globals/Plugins.h" @@ -321,6 +321,26 @@ class SettingsStruct_tmpl void forceSave() { memset(md5, 0, 16); } + uint32_t getVariousBits1() const { + uint32_t res; + memcpy(&res, &VariousBits_1, sizeof(VariousBits_1)); + return res; + } + + void setVariousBits1(uint32_t value) { + memcpy(&VariousBits_1, &value, sizeof(VariousBits_1)); + } + + uint32_t getVariousBits2() const { + uint32_t res; + memcpy(&res, &VariousBits_2, sizeof(VariousBits_2)); + return res; + } + + void setVariousBits2(uint32_t value) { + memcpy(&VariousBits_2, &value, sizeof(VariousBits_2)); + } + unsigned long PID = 0; int Version = 0; @@ -368,6 +388,9 @@ class SettingsStruct_tmpl // FIXME TD-er: Must change to pluginID_t, but then also another check must be added since changing the pluginID_t will also render settings incompatible uint8_t TaskDeviceNumber[N_TASKS] = {0}; // The "plugin number" set at as task (e.g. 4 for P004_dallas) unsigned int OLD_TaskDeviceID[N_TASKS] = {0}; //UNUSED: this can be reused + + // FIXME TD-er: When used on ESP8266, this conversion union may not work + // It might work as it is 32-bit in size. union { struct { int8_t TaskDevicePin1[N_TASKS]; @@ -381,6 +404,9 @@ class SettingsStruct_tmpl int16_t TaskDevicePluginConfig[N_TASKS][PLUGIN_CONFIGVAR_MAX]{}; boolean TaskDevicePin1Inversed[N_TASKS] = {0}; float TaskDevicePluginConfigFloat[N_TASKS][PLUGIN_CONFIGFLOATVAR_MAX]{}; + + // FIXME TD-er: When used on ESP8266, this conversion union may not work + // It might work as it is 32-bit in size. union { int32_t TaskDevicePluginConfigLong[N_TASKS][PLUGIN_CONFIGLONGVAR_MAX]; uint32_t TaskDevicePluginConfigULong[N_TASKS][PLUGIN_CONFIGLONGVAR_MAX]{}; @@ -411,45 +437,43 @@ class SettingsStruct_tmpl //TODO: document config.dat somewhere here float Latitude = 0.0f; float Longitude = 0.0f; - union { - // VariousBits1 defaults to 0, keep in mind when adding bit lookups. - struct { - uint32_t unused_00 : 1; // Bit 00 - uint32_t appendUnitToHostname : 1; // Bit 01 Inverted - uint32_t unused_02 : 1; // Bit 02 uniqueMQTTclientIdReconnect_unused - uint32_t OldRulesEngine : 1; // Bit 03 Inverted - uint32_t ForceWiFi_bg_mode : 1; // Bit 04 - uint32_t WiFiRestart_connection_lost : 1; // Bit 05 - uint32_t EcoPowerMode : 1; // Bit 06 - uint32_t WifiNoneSleep : 1; // Bit 07 - uint32_t gratuitousARP : 1; // Bit 08 Inverted - uint32_t TolerantLastArgParse : 1; // Bit 09 - uint32_t SendToHttp_ack : 1; // Bit 10 - uint32_t UseESPEasyNow : 1; // Bit 11 - uint32_t IncludeHiddenSSID : 1; // Bit 12 - uint32_t UseMaxTXpowerForSending : 1; // Bit 13 - uint32_t ApDontForceSetup : 1; // Bit 14 - uint32_t unused_15 : 1; // Bit 15 was used by PeriodicalScanWiFi - uint32_t JSONBoolWithoutQuotes : 1; // Bit 16 - uint32_t DoNotStartAP : 1; // Bit 17 - uint32_t UseAlternativeDeepSleep : 1; // Bit 18 - uint32_t UseLastWiFiFromRTC : 1; // Bit 19 - uint32_t EnableTimingStats : 1; // Bit 20 - uint32_t AllowTaskValueSetAllPlugins : 1; // Bit 21 - uint32_t EnableClearHangingI2Cbus : 1; // Bit 22 - uint32_t EnableRAMTracking : 1; // Bit 23 - uint32_t EnableRulesCaching : 1; // Bit 24 Inverted - uint32_t EnableRulesEventReorder : 1; // Bit 25 Inverted - uint32_t AllowOTAUnlimited : 1; // Bit 26 - uint32_t SendToHTTP_follow_redirects : 1; // Bit 27 - uint32_t CssMode : 2; // Bit 28 + + // VariousBits_1 defaults to 0, keep in mind when adding bit lookups. + struct { + uint32_t unused_00 : 1; // Bit 00 + uint32_t appendUnitToHostname : 1; // Bit 01 Inverted + uint32_t unused_02 : 1; // Bit 02 uniqueMQTTclientIdReconnect_unused + uint32_t OldRulesEngine : 1; // Bit 03 Inverted + uint32_t ForceWiFi_bg_mode : 1; // Bit 04 + uint32_t WiFiRestart_connection_lost : 1; // Bit 05 + uint32_t EcoPowerMode : 1; // Bit 06 + uint32_t WifiNoneSleep : 1; // Bit 07 + uint32_t gratuitousARP : 1; // Bit 08 Inverted + uint32_t TolerantLastArgParse : 1; // Bit 09 + uint32_t SendToHttp_ack : 1; // Bit 10 + uint32_t UseESPEasyNow : 1; // Bit 11 + uint32_t IncludeHiddenSSID : 1; // Bit 12 + uint32_t UseMaxTXpowerForSending : 1; // Bit 13 + uint32_t ApDontForceSetup : 1; // Bit 14 + uint32_t unused_15 : 1; // Bit 15 was used by PeriodicalScanWiFi + uint32_t JSONBoolWithoutQuotes : 1; // Bit 16 + uint32_t DoNotStartAP : 1; // Bit 17 + uint32_t UseAlternativeDeepSleep : 1; // Bit 18 + uint32_t UseLastWiFiFromRTC : 1; // Bit 19 + uint32_t EnableTimingStats : 1; // Bit 20 + uint32_t AllowTaskValueSetAllPlugins : 1; // Bit 21 + uint32_t EnableClearHangingI2Cbus : 1; // Bit 22 + uint32_t EnableRAMTracking : 1; // Bit 23 + uint32_t EnableRulesCaching : 1; // Bit 24 Inverted + uint32_t EnableRulesEventReorder : 1; // Bit 25 Inverted + uint32_t AllowOTAUnlimited : 1; // Bit 26 + uint32_t SendToHTTP_follow_redirects : 1; // Bit 27 + uint32_t CssMode : 2; // Bit 28 // uint32_t unused_29 : 1; // Bit 29 - uint32_t CheckI2Cdevice : 1; // Bit 30 Inverted - uint32_t DoNotUse_31 : 1; // Bit 31 Was used to detect whether various bits were even set + uint32_t CheckI2Cdevice : 1; // Bit 30 Inverted + uint32_t DoNotUse_31 : 1; // Bit 31 Was used to detect whether various bits were even set - } VariousBits_1; - uint32_t VariousBits1 = 0; - }; + } VariousBits_1; uint32_t ResetFactoryDefaultPreference = 0; // Do not clear this one in the clearAll() uint32_t I2C_clockSpeed = 400000; @@ -488,46 +512,43 @@ class SettingsStruct_tmpl // Do not rename or move this checksum. // Checksum calculation will work "around" this uint8_t md5[16]{}; // Store checksum of the settings. - union { - // VariousBits2 defaults to 0, keep in mind when adding bit lookups. - struct { - uint32_t WaitWiFiConnect : 1; // Bit 00 - uint32_t SDK_WiFi_autoreconnect : 1; // Bit 01 - uint32_t DisableRulesCodeCompletion : 1; // Bit 02 - uint32_t HiddenSSID_SlowConnectPerBSSID : 1; // Bit 03 // inverted - uint32_t unused_04 : 1; // Bit 04 - uint32_t unused_05 : 1; // Bit 05 - uint32_t unused_06 : 1; // Bit 06 - uint32_t unused_07 : 1; // Bit 07 - uint32_t unused_08 : 1; // Bit 08 - uint32_t unused_09 : 1; // Bit 09 - uint32_t unused_10 : 1; // Bit 10 - uint32_t unused_11 : 1; // Bit 11 - uint32_t unused_12 : 1; // Bit 12 - uint32_t unused_13 : 1; // Bit 13 - uint32_t unused_14 : 1; // Bit 14 - uint32_t unused_15 : 1; // Bit 15 - uint32_t unused_16 : 1; // Bit 16 - uint32_t unused_17 : 1; // Bit 17 - uint32_t unused_18 : 1; // Bit 18 - uint32_t unused_19 : 1; // Bit 19 - uint32_t unused_20 : 1; // Bit 20 - uint32_t unused_21 : 1; // Bit 21 - uint32_t unused_22 : 1; // Bit 22 - uint32_t unused_23 : 1; // Bit 23 - uint32_t unused_24 : 1; // Bit 24 - uint32_t unused_25 : 1; // Bit 25 - uint32_t unused_26 : 1; // Bit 26 - uint32_t unused_27 : 1; // Bit 27 - uint32_t unused_28 : 1; // Bit 28 - uint32_t unused_29 : 1; // Bit 29 - uint32_t unused_30 : 1; // Bit 30 - uint32_t unused_31 : 1; // Bit 31 - - } VariousBits_2; - uint32_t VariousBits2 = 0; - }; + // VariousBits_2 defaults to 0, keep in mind when adding bit lookups. + struct { + uint32_t WaitWiFiConnect : 1; // Bit 00 + uint32_t SDK_WiFi_autoreconnect : 1; // Bit 01 + uint32_t DisableRulesCodeCompletion : 1; // Bit 02 + uint32_t HiddenSSID_SlowConnectPerBSSID : 1; // Bit 03 // inverted + uint32_t unused_04 : 1; // Bit 04 + uint32_t unused_05 : 1; // Bit 05 + uint32_t unused_06 : 1; // Bit 06 + uint32_t unused_07 : 1; // Bit 07 + uint32_t unused_08 : 1; // Bit 08 + uint32_t unused_09 : 1; // Bit 09 + uint32_t unused_10 : 1; // Bit 10 + uint32_t unused_11 : 1; // Bit 11 + uint32_t unused_12 : 1; // Bit 12 + uint32_t unused_13 : 1; // Bit 13 + uint32_t unused_14 : 1; // Bit 14 + uint32_t unused_15 : 1; // Bit 15 + uint32_t unused_16 : 1; // Bit 16 + uint32_t unused_17 : 1; // Bit 17 + uint32_t unused_18 : 1; // Bit 18 + uint32_t unused_19 : 1; // Bit 19 + uint32_t unused_20 : 1; // Bit 20 + uint32_t unused_21 : 1; // Bit 21 + uint32_t unused_22 : 1; // Bit 22 + uint32_t unused_23 : 1; // Bit 23 + uint32_t unused_24 : 1; // Bit 24 + uint32_t unused_25 : 1; // Bit 25 + uint32_t unused_26 : 1; // Bit 26 + uint32_t unused_27 : 1; // Bit 27 + uint32_t unused_28 : 1; // Bit 28 + uint32_t unused_29 : 1; // Bit 29 + uint32_t unused_30 : 1; // Bit 30 + uint32_t unused_31 : 1; // Bit 31 + + } VariousBits_2; uint8_t console_serial_port = DEFAULT_CONSOLE_PORT; int8_t console_serial_rxpin = DEFAULT_CONSOLE_PORT_RXPIN; diff --git a/src/src/DataStructs/UserVarStruct.cpp b/src/src/DataStructs/UserVarStruct.cpp index f44869f65e..96064df05d 100644 --- a/src/src/DataStructs/UserVarStruct.cpp +++ b/src/src/DataStructs/UserVarStruct.cpp @@ -329,24 +329,31 @@ uint32_t UserVarStruct::compute_CRC32() const void UserVarStruct::clear_computed(taskIndex_t taskIndex) { - if (!Cache.hasFormula(taskIndex)) { - auto it = _computed.find(taskIndex); + auto it = _computed.find(taskIndex); - if (it != _computed.end()) { - _computed.erase(it); - } + if (it != _computed.end()) { + _computed.erase(it); } -#ifndef LIMIT_BUILD_SIZE for (taskVarIndex_t varNr = 0; validTaskVarIndex(varNr); ++varNr) { const uint16_t key = makeWord(taskIndex, varNr); - auto it = _preprocessedFormula.find(key); +#ifndef LIMIT_BUILD_SIZE + { + auto it = _preprocessedFormula.find(key); - if (it != _preprocessedFormula.end()) { - _preprocessedFormula.erase(it); + if (it != _preprocessedFormula.end()) { + _preprocessedFormula.erase(it); + } } - } #endif // ifndef LIMIT_BUILD_SIZE + { + auto it = _prevValue.find(key); + + if (it != _prevValue.end()) { + _prevValue.erase(it); + } + } + } } void UserVarStruct::markPluginRead(taskIndex_t taskIndex) @@ -403,7 +410,9 @@ bool UserVarStruct::applyFormula(taskIndex_t taskIndex, return false; } - if (!applyNow && !Cache.hasFormula_with_prevValue(taskIndex, varNr)) { + const bool formula_has_prevvalue = Cache.hasFormula_with_prevValue(taskIndex, varNr); + + if (!applyNow && !formula_has_prevvalue) { // Must check whether we can delay calculations until it is read for the first time. auto it = _computed.find(taskIndex); @@ -422,15 +431,23 @@ bool UserVarStruct::applyFormula(taskIndex_t taskIndex, { START_TIMER; + formula.replace(F("%value%"), value); + // TD-er: Should we use the set nr of decimals here, or not round at all? // See: https://github.com/letscontrolit/ESPEasy/issues/3721#issuecomment-889649437 - if (formula.indexOf(F("%pvalue%")) != -1) { + if (formula_has_prevvalue) { const String prev_str = getPreviousValue(taskIndex, varNr, sensorType); formula.replace(F("%pvalue%"), prev_str.isEmpty() ? value : prev_str); + /* + addLog(LOG_LEVEL_INFO, + strformat( + F("pvalue: %s, value: %s, formula: %s"), + prev_str.c_str(), + value.c_str(), + formula.c_str())); + */ } - formula.replace(F("%value%"), value); - ESPEASY_RULES_FLOAT_TYPE result{}; if (!isError(Calculate_preProcessed(parseTemplate(formula), result))) { @@ -482,7 +499,11 @@ String UserVarStruct::getPreprocessedFormula(taskIndex_t taskIndex, taskVarIndex auto it = _preprocessedFormula.find(key); if (it == _preprocessedFormula.end()) { - _preprocessedFormula[key] = RulesCalculate_t::preProces(Cache.getTaskDeviceFormula(taskIndex, varNr)); + _preprocessedFormula.emplace( + std::make_pair( + key, + RulesCalculate_t::preProces(Cache.getTaskDeviceFormula(taskIndex, varNr)) + )); } return _preprocessedFormula[key]; #else // ifndef LIMIT_BUILD_SIZE diff --git a/src/src/DataStructs/UserVarStruct.h b/src/src/DataStructs/UserVarStruct.h index 71d0eb58cd..2c8568f253 100644 --- a/src/src/DataStructs/UserVarStruct.h +++ b/src/src/DataStructs/UserVarStruct.h @@ -29,7 +29,7 @@ struct TaskValues_Data_cache { } TaskValues_Data_t values{}; - uint8_t values_set_map{}; + uint32_t values_set_map{}; }; struct UserVarStruct { diff --git a/src/src/DataStructs/WiFi_AP_Candidate.cpp b/src/src/DataStructs/WiFi_AP_Candidate.cpp index b6fe853060..9c1f41e982 100644 --- a/src/src/DataStructs/WiFi_AP_Candidate.cpp +++ b/src/src/DataStructs/WiFi_AP_Candidate.cpp @@ -19,9 +19,17 @@ #define WIFI_AP_CANDIDATE_MAX_AGE 300000 // 5 minutes in msec +WiFi_AP_Candidate::WiFi_AP_Candidate() : + last_seen(0), rssi(0), channel(0), index(0), enc_type(0) +{ + memset(&bits, 0, sizeof(bits)); +} + WiFi_AP_Candidate::WiFi_AP_Candidate(uint8_t index_c, const String& ssid_c) : - last_seen(0), rssi(0), channel(0), index(index_c), flags(0) + last_seen(0), rssi(0), channel(0), index(index_c), enc_type(0) { + memset(&bits, 0, sizeof(bits)); + const size_t ssid_length = ssid_c.length(); if ((ssid_length == 0) || equals(ssid_c, F("ssid"))) { @@ -33,38 +41,46 @@ WiFi_AP_Candidate::WiFi_AP_Candidate(uint8_t index_c, const String& ssid_c) : ssid = ssid_c; } -WiFi_AP_Candidate::WiFi_AP_Candidate(uint8_t networkItem) : index(0), flags(0) { - ssid = WiFi.SSID(networkItem); - rssi = WiFi.RSSI(networkItem); - channel = WiFi.channel(networkItem); - bssid = WiFi.BSSID(networkItem); +WiFi_AP_Candidate::WiFi_AP_Candidate(uint8_t networkItem) : index(0) { + // Need to make sure the phy isn't known as we can't get this information from the AP + // See: https://github.com/letscontrolit/ESPEasy/issues/4996 + // Not sure why this makes any difference as the flags should already have been set to 0. + memset(&bits, 0, sizeof(bits)); + + ssid = WiFi.SSID(networkItem); + rssi = WiFi.RSSI(networkItem); + channel = WiFi.channel(networkItem); + bssid = WiFi.BSSID(networkItem); enc_type = WiFi.encryptionType(networkItem); #ifdef ESP8266 - isHidden = WiFi.isHidden(networkItem); - #ifdef CORE_POST_3_0_0 - const bss_info* it = reinterpret_cast(WiFi.getScanInfoByIndex(networkItem)); + bits.isHidden = WiFi.isHidden(networkItem); + # ifdef CORE_POST_3_0_0 + const bss_info *it = reinterpret_cast(WiFi.getScanInfoByIndex(networkItem)); + if (it) { - phy_11b = it->phy_11b; - phy_11g = it->phy_11g; - phy_11n = it->phy_11n; - wps = it->wps; + bits.phy_11b = it->phy_11b; + bits.phy_11g = it->phy_11g; + bits.phy_11n = it->phy_11n; + bits.wps = it->wps; } - #endif + # endif // ifdef CORE_POST_3_0_0 #endif // ifdef ESP8266 #ifdef ESP32 - isHidden = ssid.isEmpty(); - wifi_ap_record_t* it = reinterpret_cast(WiFi.getScanInfoByIndex(networkItem)); + bits.isHidden = ssid.isEmpty(); + wifi_ap_record_t *it = reinterpret_cast(WiFi.getScanInfoByIndex(networkItem)); + if (it) { - phy_11b = it->phy_11b; - phy_11g = it->phy_11g; - phy_11n = it->phy_11n; - phy_lr = it->phy_lr; -#if ESP_IDF_VERSION_MAJOR >= 5 - phy_11ax = it->phy_11ax; - ftm_initiator = it->ftm_initiator; - ftm_responder = it->ftm_responder; -#endif - wps = it->wps; + bits.phy_11b = it->phy_11b; + bits.phy_11g = it->phy_11g; + bits.phy_11n = it->phy_11n; + bits.phy_lr = it->phy_lr; +# if ESP_IDF_VERSION_MAJOR >= 5 + bits.phy_11ax = it->phy_11ax; + bits.ftm_initiator = it->ftm_initiator; + bits.ftm_responder = it->ftm_responder; +# endif // if ESP_IDF_VERSION_MAJOR >= 5 + bits.wps = it->wps; + // FIXME TD-er: Maybe also add other info like 2nd channel, ftm and phy_lr support? } #endif // ifdef ESP32 @@ -72,45 +88,51 @@ WiFi_AP_Candidate::WiFi_AP_Candidate(uint8_t networkItem) : index(0), flags(0) { } #ifdef ESP8266 -#if FEATURE_ESP8266_DIRECT_WIFI_SCAN +# if FEATURE_ESP8266_DIRECT_WIFI_SCAN WiFi_AP_Candidate::WiFi_AP_Candidate(const bss_info& ap) : - rssi(ap.rssi), channel(ap.channel), bssid(ap.bssid), + rssi(ap.rssi), channel(ap.channel), bssid(ap.bssid), index(0), enc_type(0), isHidden(ap.is_hidden), phy_11b(ap.phy_11b), phy_11g(ap.phy_11g), phy_11n(ap.phy_11n), wps(ap.wps) { + memset(&bits, 0, sizeof(bits)); + last_seen = millis(); - switch(ap.authmode) { - case AUTH_OPEN: enc_type = ENC_TYPE_NONE; break; - case AUTH_WEP: enc_type = ENC_TYPE_WEP; break; - case AUTH_WPA_PSK: enc_type = ENC_TYPE_TKIP; break; - case AUTH_WPA2_PSK: enc_type = ENC_TYPE_CCMP; break; + switch (ap.authmode) { + case AUTH_OPEN: enc_type = ENC_TYPE_NONE; break; + case AUTH_WEP: enc_type = ENC_TYPE_WEP; break; + case AUTH_WPA_PSK: enc_type = ENC_TYPE_TKIP; break; + case AUTH_WPA2_PSK: enc_type = ENC_TYPE_CCMP; break; case AUTH_WPA_WPA2_PSK: enc_type = ENC_TYPE_AUTO; break; case AUTH_MAX: break; } - char tmp[33]; //ssid can be up to 32chars, => plus null term + char tmp[33]; // ssid can be up to 32chars, => plus null term const size_t ssid_len = std::min(static_cast(ap.ssid_len), sizeof(ap.ssid)); + memcpy(tmp, ap.ssid, ssid_len); tmp[ssid_len] = 0; // nullterm marking end of string - ssid = String(reinterpret_cast(tmp)); + ssid = String(reinterpret_cast(tmp)); } -#endif -#endif + +# endif // if FEATURE_ESP8266_DIRECT_WIFI_SCAN +#endif // ifdef ESP8266 bool WiFi_AP_Candidate::operator<(const WiFi_AP_Candidate& other) const { - if (isEmergencyFallback != other.isEmergencyFallback) { - return isEmergencyFallback; + if (bits.isEmergencyFallback != other.bits.isEmergencyFallback) { + return bits.isEmergencyFallback; } - if (lowPriority != other.lowPriority) { - return !lowPriority; + + if (bits.lowPriority != other.bits.lowPriority) { + return !bits.lowPriority; } + // Prefer non hidden over hidden. - if (isHidden != other.isHidden) { - return !isHidden; + if (bits.isHidden != other.bits.isHidden) { + return !bits.isHidden; } // RSSI values >= 0 are invalid @@ -125,19 +147,21 @@ bool WiFi_AP_Candidate::operator<(const WiFi_AP_Candidate& other) const { bool WiFi_AP_Candidate::usable() const { // Allow for empty pass // if (key.isEmpty()) return false; - if (isEmergencyFallback) { + if (bits.isEmergencyFallback) { int allowedUptimeMinutes = 10; #ifdef CUSTOM_EMERGENCY_FALLBACK_ALLOW_MINUTES_UPTIME allowedUptimeMinutes = CUSTOM_EMERGENCY_FALLBACK_ALLOW_MINUTES_UPTIME; - #endif - if (getUptimeMinutes() > allowedUptimeMinutes || - !SecuritySettings.hasWiFiCredentials() || + #endif // ifdef CUSTOM_EMERGENCY_FALLBACK_ALLOW_MINUTES_UPTIME + + if ((getUptimeMinutes() > allowedUptimeMinutes) || + !SecuritySettings.hasWiFiCredentials() || WiFiEventData.performedClearWiFiCredentials || - lastBootCause != BOOT_CAUSE_COLD_BOOT) { + (lastBootCause != BOOT_CAUSE_COLD_BOOT)) { return false; } } - if (!isHidden && (ssid.isEmpty())) { return false; } + + if (!bits.isHidden && (ssid.isEmpty())) { return false; } return !expired(); } @@ -149,12 +173,12 @@ bool WiFi_AP_Candidate::expired() const { return timePassedSince(last_seen) > WIFI_AP_CANDIDATE_MAX_AGE; } - String WiFi_AP_Candidate::toString(const String& separator) const { String result = ssid; htmlEscape(result); - if (isHidden) { + + if (bits.isHidden) { result += F("#Hidden#"); } result += strformat( @@ -171,18 +195,25 @@ String WiFi_AP_Candidate::toString(const String& separator) const { } result += encryption_type(); + if (phy_known()) { String phy_str; - - if (phy_11b) phy_str += 'b'; - if (phy_11g) phy_str += 'g'; - if (phy_11n) phy_str += 'n'; + + if (bits.phy_11b) { phy_str += 'b'; } + + if (bits.phy_11g) { phy_str += 'g'; } + + if (bits.phy_11n) { phy_str += 'n'; } #ifdef ESP32 - if (phy_11ax) phy_str += F("/ax"); - if (phy_lr) phy_str += F("/lr"); - if (ftm_initiator) phy_str += F("/FTM_i"); - if (ftm_responder) phy_str += F("/FTM_r"); -#endif + + if (bits.phy_11ax) { phy_str += F("/ax"); } + + if (bits.phy_lr) { phy_str += F("/lr"); } + + if (bits.ftm_initiator) { phy_str += F("/FTM_i"); } + + if (bits.ftm_responder) { phy_str += F("/FTM_r"); } +#endif // ifdef ESP32 if (phy_str.length()) { result += strformat(F(" (%s)"), phy_str.c_str()); diff --git a/src/src/DataStructs/WiFi_AP_Candidate.h b/src/src/DataStructs/WiFi_AP_Candidate.h index ce93d4cbf4..b3ce8f8c35 100644 --- a/src/src/DataStructs/WiFi_AP_Candidate.h +++ b/src/src/DataStructs/WiFi_AP_Candidate.h @@ -5,32 +5,32 @@ #include "../DataStructs/MAC_address.h" struct WiFi_AP_Candidate { + WiFi_AP_Candidate(); + WiFi_AP_Candidate(const WiFi_AP_Candidate& other) = default; + + // Construct from stored credentials // @param index The index of the stored credentials // @param ssid_c SSID of the credentials // @param pass Password/key of the credentials - WiFi_AP_Candidate(uint8_t index, + WiFi_AP_Candidate(uint8_t index, const String& ssid_c); // Construct using index from WiFi scan result WiFi_AP_Candidate(uint8_t networkItem); #ifdef ESP8266 - #if FEATURE_ESP8266_DIRECT_WIFI_SCAN + # if FEATURE_ESP8266_DIRECT_WIFI_SCAN WiFi_AP_Candidate(const bss_info& ap); - #endif - #endif - - - WiFi_AP_Candidate() = default; - WiFi_AP_Candidate(const WiFi_AP_Candidate& other) = default; + # endif // if FEATURE_ESP8266_DIRECT_WIFI_SCAN + #endif // ifdef ESP8266 // Return true when this one is preferred over 'other'. - bool operator<(const WiFi_AP_Candidate& other) const; + bool operator<(const WiFi_AP_Candidate& other) const; - bool operator==(const WiFi_AP_Candidate& other) const { - return bssid_match(other.bssid) && ssid.equals(other.ssid);// && key.equals(other.key); + bool operator==(const WiFi_AP_Candidate& other) const { + return bssid_match(other.bssid) && ssid.equals(other.ssid); // && key.equals(other.key); } WiFi_AP_Candidate& operator=(const WiFi_AP_Candidate& other) = default; @@ -42,50 +42,57 @@ struct WiFi_AP_Candidate { bool expired() const; // For quick connection the channel and BSSID are needed - bool allowQuickConnect() const { return (channel != 0) && bssid_set(); } + bool allowQuickConnect() const { + return (channel != 0) && bssid_set(); + } // Check to see if the BSSID is set - bool bssid_set() const { return !bssid.all_zero(); } + bool bssid_set() const { + return !bssid.all_zero(); + } + + bool bssid_match(const uint8_t bssid_c[6]) const { + return bssid == bssid_c; + } - bool bssid_match(const uint8_t bssid_c[6]) const { return bssid == bssid_c; } - bool bssid_match(const MAC_address& other) const { return bssid == other; } + bool bssid_match(const MAC_address& other) const { + return bssid == other; + } // Create a formatted string - String toString(const String& separator = " ") const; + String toString(const String& separator = " ") const; + + String encryption_type() const; - String encryption_type() const; + bool phy_known() const { + return bits.phy_11b || bits.phy_11g || bits.phy_11n; + } - bool phy_known() const { return phy_11b || phy_11g || phy_11n; } + String ssid; - String ssid; -// String key; + // String key; unsigned long last_seen = 0u; MAC_address bssid; int8_t rssi{}; uint8_t channel{}; - uint8_t index{}; // Index of the matching credentials - uint8_t enc_type{}; // Encryption used (e.g. WPA2) - union - { - struct { - uint16_t isHidden:1; // Hidden SSID - uint16_t lowPriority:1; // Try as last attempt - uint16_t isEmergencyFallback:1; - uint16_t phy_11b:1; - uint16_t phy_11g:1; - uint16_t phy_11n:1; - uint16_t phy_lr:1; - uint16_t phy_11ax:1; - uint16_t wps:1; - uint16_t ftm_responder:1; - uint16_t ftm_initiator:1; - - uint16_t unused:5; - }; - uint16_t flags{}; - }; - + uint8_t index{}; // Index of the matching credentials + uint8_t enc_type{}; // Encryption used (e.g. WPA2) + struct { + uint16_t isHidden : 1; // Hidden SSID + uint16_t lowPriority : 1; // Try as last attempt + uint16_t isEmergencyFallback : 1; + uint16_t phy_11b : 1; + uint16_t phy_11g : 1; + uint16_t phy_11n : 1; + uint16_t phy_lr : 1; + uint16_t phy_11ax : 1; + uint16_t wps : 1; + uint16_t ftm_responder : 1; + uint16_t ftm_initiator : 1; + + uint16_t unused : 5; + } bits; }; #endif // ifndef DATASTRUCTS_WIFI_AP_CANDIDATES_H diff --git a/src/src/DataStructs/mBusPacket.cpp b/src/src/DataStructs/mBusPacket.cpp new file mode 100644 index 0000000000..4e0a5537a6 --- /dev/null +++ b/src/src/DataStructs/mBusPacket.cpp @@ -0,0 +1,428 @@ +#include "../DataStructs/mBusPacket.h" + +#include "../Helpers/CRC_functions.h" +#include "../Helpers/StringConverter.h" + +#define FRAME_FORMAT_A_FIRST_BLOCK_LENGTH 10 +#define FRAME_FORMAT_A_OTHER_BLOCK_LENGTH 16 + + +mBusPacket_header_t::mBusPacket_header_t() +{ + _manufacturer = mBus_packet_wildcard_manufacturer; + _meterType = mBus_packet_wildcard_metertype; + _serialNr = mBus_packet_wildcard_serial; + _length = 0u; +} + +String mBusPacket_header_t::decodeManufacturerID(int id) +{ + String res; + int shift = 15; + + for (int i = 0; i < 3; ++i) { + shift -= 5; + res += static_cast(((id >> shift) & 0x1f) + 64); + } + return res; +} + +int mBusPacket_header_t::encodeManufacturerID(const String& id_str) +{ + int res = 0; + int nrChars = id_str.length(); + + if (nrChars > 3) { nrChars = 3; } + + int i = 0; + + while (i < nrChars) { + res <<= 5; + const int c = static_cast(toUpperCase(id_str[i])) - 64; + + if (c >= 0) { + res += c & 0x1f; + } + ++i; + } + return res; +} + +String mBusPacket_header_t::getManufacturerId() const +{ + return decodeManufacturerID(_manufacturer); +} + +String mBusPacket_header_t::toString() const +{ + String res = decodeManufacturerID(_manufacturer); + + res += '.'; + res += formatToHex_no_prefix(_meterType, 2); + res += '.'; + res += formatToHex_no_prefix(_serialNr, 8); + return res; +} + +uint64_t mBusPacket_header_t::encode_toUInt64() const +{ + if (!isValid()) { return 0ull; } + mBusPacket_header_t tmp(*this); + + tmp._length = 0; + return tmp._encodedValue; +} + +void mBusPacket_header_t::decode_fromUint64(uint64_t encodedValue) +{ + _encodedValue = encodedValue; + _length = 1; // To pass isValid() check +} + +bool mBusPacket_header_t::isValid() const +{ + return + _manufacturer != mBus_packet_wildcard_manufacturer && + _meterType != mBus_packet_wildcard_metertype && + _serialNr != mBus_packet_wildcard_serial && + _length > 0; +} + +void mBusPacket_header_t::clear() +{ + _manufacturer = mBus_packet_wildcard_manufacturer; + _meterType = mBus_packet_wildcard_metertype; + _serialNr = mBus_packet_wildcard_serial; + _length = 0; +} + +bool mBusPacket_header_t::matchSerial(uint32_t serialNr) const +{ + return isValid() && (_serialNr == serialNr); +} + +const mBusPacket_header_t * mBusPacket_t::getDeviceHeader() const +{ + // FIXME TD-er: Which deviceID is the device and which the wrapper? + if (_deviceId1.isValid()) { return &_deviceId1; } + + if (_deviceId2.isValid()) { return &_deviceId2; } + + return nullptr; +} + +uint32_t mBusPacket_t::getDeviceSerial() const +{ + const mBusPacket_header_t *header = getDeviceHeader(); + + if (header == nullptr) { return 0u; } + return header->_serialNr; +} + +uint32_t mBusPacket_t::deviceID_to_map_key() const +{ + return deviceID_to_map_key(_deviceId1._encodedValue, _deviceId2._encodedValue); +} + +uint32_t mBusPacket_t::deviceID_to_map_key_no_length() const { + return deviceID_to_map_key(_deviceId1.encode_toUInt64(), _deviceId2.encode_toUInt64()); +} + +uint32_t mBusPacket_t::deviceID_to_map_key(uint64_t id1, uint64_t id2) +{ + uint32_t res = 0; + + if (id1 != 0ull) { + res ^= calc_CRC32((const uint8_t *)(&id1), sizeof(uint64_t)); + } + + if (id2 != 0ull) { + // There is a forwarding device. + // To prevent issues when the forwarding device is the same as the forwarded device, alter the already existing checksum. + res ^= calc_CRC32((const uint8_t *)(&res), sizeof(res)); + res ^= calc_CRC32((const uint8_t *)(&id2), sizeof(uint64_t)); + } + + return res; +} + +bool mBusPacket_t::parse(const String& payload) +{ + if (payload[0] != 'b') { return false; } + + _checksum = 0; + mBusPacket_data payloadWithoutChecksums; + + if (payload[1] == 'Y') { + // Start with "bY" + payloadWithoutChecksums = removeChecksumsFrameB(payload, _checksum); + } else { + payloadWithoutChecksums = removeChecksumsFrameA(payload, _checksum); + } + + if (payloadWithoutChecksums.size() < 10) { return false; } + + int pos_semicolon = payload.indexOf(';'); + + if (pos_semicolon == -1) { pos_semicolon = payload.length(); } + + _lqi_rssi = hexToUL(payload, pos_semicolon - 4, 4); + return parseHeaders(payloadWithoutChecksums); +} + +int16_t mBusPacket_t::decode_LQI_RSSI(uint16_t lqi_rssi, uint8_t& LQI) +{ + LQI = (lqi_rssi >> 8) & 0x7f; // Bit 7 = CRC OK Bit + + int rssi = lqi_rssi & 0xFF; + + if (rssi >= 128) { + rssi -= 256; // 2-complement + } + return (rssi / 2) - 74; +} + +bool mBusPacket_t::matchSerial(uint32_t serialNr) const +{ + return _deviceId1.matchSerial(serialNr) || _deviceId2.matchSerial(serialNr); +} + +bool mBusPacket_t::parseHeaders(const mBusPacket_data& payloadWithoutChecksums) +{ + const int payloadSize = payloadWithoutChecksums.size(); + + _deviceId1.clear(); + _deviceId2.clear(); + + if (payloadSize < 10) { return false; } + int offset = 0; + + // 1st block is a static DataLinkLayer of 10 bytes + { + _deviceId1._manufacturer = makeWord(payloadWithoutChecksums[offset + 3], payloadWithoutChecksums[offset + 2]); + + // Type (offset + 9; convert to hex) + _deviceId1._meterType = payloadWithoutChecksums[offset + 9]; + + // Serial (offset + 4; 4 Bytes; least significant first; converted to hex) + _deviceId1._serialNr = 0; + + for (int i = 0; i < 4; ++i) { + const uint32_t val = payloadWithoutChecksums[offset + 4 + i]; + _deviceId1._serialNr += val << (i * 8); + } + offset += 10; + _deviceId1._length = payloadWithoutChecksums[0]; + } + + // next blocks can be anything. we skip known blocks of no interest, parse known blocks if interest and stop on onknown blocks + while (offset < payloadSize) { + switch (static_cast(payloadWithoutChecksums[offset])) { + case 0x8C: // ELL short + offset += 3; // fixed length + _deviceId1._length = payloadSize - offset; + break; + case 0x90: // AFL + offset++; + offset += (payloadWithoutChecksums[offset] & 0xff); // dynamic length with length in 1st byte + offset++; // length byte + _deviceId1._length = payloadSize - offset; + break; + case 0x72: // TPL_RESPONSE_MBUS_LONG_HEADER + _deviceId2 = _deviceId1; + + // note that serial/manufacturer are swapped !! + + _deviceId1._manufacturer = makeWord(payloadWithoutChecksums[offset + 6], payloadWithoutChecksums[offset + 5]); + + // Type (offset + 9; convert to hex) + _deviceId1._meterType = payloadWithoutChecksums[offset + 8]; + + // Serial (offset + 4; 4 Bytes; least significant first; converted to hex) + _deviceId1._serialNr = 0; + + + for (int i = 0; i < 4; ++i) { + const uint32_t val = payloadWithoutChecksums[offset + 1 + i]; + _deviceId1._serialNr += val << (i * 8); + } + + // We're done + offset = payloadSize; + break; + default: + // We're done + // addLog(LOG_LEVEL_ERROR, concat(F("CUL : offset "), offset) + F(" Data: ") + formatToHex(payloadWithoutChecksums[offset])); + offset = payloadSize; + break; + } + } + + if (_deviceId1.isValid() && _deviceId2.isValid() && _deviceId1.toString().startsWith(F("ITW.30."))) { + // ITW does not follow the spec and puts the redio converter behind the actual meter. Need to swap both + std::swap(_deviceId1, _deviceId2); + } + + return _deviceId1.isValid(); +} + +String mBusPacket_t::toString() const +{ + static size_t expectedSize = 96; + String res; + + if (res.reserve(expectedSize)) { + if (_deviceId1.isValid()) { + res += F(" deviceId1: "); + res += _deviceId1.toString(); + res += '('; + res += static_cast(_deviceId1._length); + res += ')'; + } + + if (_deviceId2.isValid()) { + res += F(" deviceId2: "); + res += _deviceId2.toString(); + res += '('; + res += static_cast(_deviceId2._length); + res += ')'; + } + res += F(" chksum: "); + res += formatToHex(_checksum, 8); + + uint8_t LQI = 0; + const int16_t rssi = decode_LQI_RSSI(_lqi_rssi, LQI); + res += F(" LQI: "); + res += LQI; + res += F(" RSSI: "); + res += rssi; + } + + if (res.length() > expectedSize) { expectedSize = res.length(); } + + return res; +} + +uint8_t mBusPacket_t::hexToByte(const String& str, size_t index) +{ + // Need to have at least 2 HEX nibbles + if ((index + 1) >= str.length()) { return 0; } + return hexToUL(str, index, 2); +} + +/** + * Format: + * [10 bytes message] + [2 bytes CRC] + * [16 bytes message] + [2 bytes CRC] + * [16 bytes message] + [2 bytes CRC] + * ... + * (last block can be < 16 bytes) + */ +mBusPacket_data mBusPacket_t::removeChecksumsFrameA(const String& payload, uint32_t& checksum) +{ + mBusPacket_data result; + const int payloadLength = payload.length(); + + if (payloadLength < 4) { return result; } + + int sourceIndex = 1; // Starts with "b" + int targetIndex = 0; + + // 1st byte contains length of data (excuding 1st byte and excluding CRC) + const int expectedMessageSize = hexToByte(payload, sourceIndex) + 1; + + if (payloadLength < (2 * expectedMessageSize)) { + // Not an exact check, but close enough to fail early on packets which are seriously too short. + return result; + } + + result.reserve(expectedMessageSize); + + while (targetIndex < expectedMessageSize) { + // end index is start index + block size + 2 byte checksums + int blockSize = (sourceIndex == 1) ? FRAME_FORMAT_A_FIRST_BLOCK_LENGTH : FRAME_FORMAT_A_OTHER_BLOCK_LENGTH; + + if ((targetIndex + blockSize) > expectedMessageSize) { // last block + blockSize = expectedMessageSize - targetIndex; + } + + // FIXME: handle truncated source messages + for (int i = 0; i < blockSize; ++i) { + result.push_back(hexToByte(payload, sourceIndex)); + sourceIndex += 2; // 2 hex chars + } + + // [2 bytes CRC] + checksum <<= 8; + checksum ^= hexToUL(payload, sourceIndex, 4); + sourceIndex += 4; // Skip 2 bytes CRC => 4 hex chars + targetIndex += blockSize; + } + return result; +} + +/** + * Format: + * [126 bytes message] + [2 bytes CRC] + * [125 bytes message] + [2 bytes CRC] + * (if message length <=126 bytes, only the 1st block exists) + * (last block can be < 125 bytes) + */ +mBusPacket_data mBusPacket_t::removeChecksumsFrameB(const String& payload, uint32_t& checksum) +{ + mBusPacket_data result; + const int payloadLength = payload.length(); + + if (payloadLength < 4) { return result; } + + int sourceIndex = 2; // Starts with "bY" + + // 1st byte contains length of data (excuding 1st byte BUT INCLUDING CRC) + int expectedMessageSize = hexToByte(payload, sourceIndex) + 1; + + if (payloadLength < (2 * expectedMessageSize)) { + return result; + } + + expectedMessageSize -= 2; // CRC of 1st block + + if (expectedMessageSize > 128) { + expectedMessageSize -= 2; // CRC of 2nd block + } + + result.reserve(expectedMessageSize); + + // FIXME: handle truncated source messages + + const int block1Size = expectedMessageSize < 126 ? expectedMessageSize : 126; + + for (int i = 0; i < block1Size; ++i) { + result.push_back(hexToByte(payload, sourceIndex)); + sourceIndex += 2; // 2 hex chars + } + + // [2 bytes CRC] + checksum <<= 8; + checksum ^= hexToUL(payload, sourceIndex, 4); + sourceIndex += 4; // Skip 2 bytes CRC => 4 hex chars + + if (expectedMessageSize > 126) { + int block2Size = expectedMessageSize - 127; + + if (block2Size > 124) { block2Size = 124; } + + for (int i = 0; i < block2Size; ++i) { + result.push_back(hexToByte(payload, sourceIndex)); + sourceIndex += 2; // 2 hex chars + } + + // [2 bytes CRC] + checksum <<= 8; + checksum ^= hexToUL(payload, sourceIndex, 4); + } + + // remove the checksums and the 1st byte from the actual message length, so that the meaning of this byte is the same as in Frame A + result[0] = static_cast((expectedMessageSize - 1) & 0xff); + + return result; +} diff --git a/src/src/DataStructs/mBusPacket.h b/src/src/DataStructs/mBusPacket.h new file mode 100644 index 0000000000..3a6b9ac75b --- /dev/null +++ b/src/src/DataStructs/mBusPacket.h @@ -0,0 +1,120 @@ +#ifndef DATASTRUCTS_MBUSPACKET_H +#define DATASTRUCTS_MBUSPACKET_H + +#include "../../ESPEasy_common.h" + +#include + + +// 0 is sometimes used ("@@@") +// 0xFFFF does not seem to be used ("___") +#define mBus_packet_wildcard_manufacturer 0xFFFF + +// 0 is a valid meter type and 0xFF seems to be reserved +#define mBus_packet_wildcard_metertype 0xFE + +// 0 is a valid serial and 0xFFFFFFFF seems to be reserved +#define mBus_packet_wildcard_serial 0xFFFFFFFE + + +typedef std::vector mBusPacket_data; + +struct mBusPacket_header_t { + mBusPacket_header_t(); + + static String decodeManufacturerID(int id); + static int encodeManufacturerID(const String& id_str); + + String getManufacturerId() const; + + String toString() const; + + uint64_t encode_toUInt64() const; + + void decode_fromUint64(uint64_t encodedValue); + + bool isValid() const; + + bool matchSerial(uint32_t serialNr) const; + + void clear(); + + // Use for stats as key: + union { + uint64_t _encodedValue{}; + struct { + uint64_t _serialNr : 32; + uint64_t _manufacturer : 16; + uint64_t _meterType : 8; + + // Use for filtering + uint64_t _length : 8; + }; + }; +}; + +struct mBusPacket_t { +public: + + bool parse(const String& payload); + + // Get the header of the actual device, not the forwarding device (if present) + const mBusPacket_header_t* getDeviceHeader() const; + + static int16_t decode_LQI_RSSI(uint16_t lqi_rssi, + uint8_t& LQI); + + bool matchSerial(uint32_t serialNr) const; + + uint32_t getDeviceSerial() const; + + String toString() const; + + // 32 bit value used to generate a map key for filtering + // Essentially the XOR of the first 32-bit with the second 32-bit of + // serial, manufacturer, metertype and length. + uint32_t deviceID_to_map_key() const; + + uint32_t deviceID_to_map_key_no_length() const; + +private: + + static uint32_t deviceID_to_map_key(uint64_t id1, uint64_t id2); + + static uint8_t hexToByte(const String& str, + size_t index); + + static mBusPacket_data removeChecksumsFrameA(const String& payload, + uint32_t & checksum); + static mBusPacket_data removeChecksumsFrameB(const String& payload, + uint32_t & checksum); + + bool parseHeaders(const mBusPacket_data& payloadWithoutChecksums); + +public: + + mBusPacket_header_t _deviceId1; + mBusPacket_header_t _deviceId2; + uint16_t _lqi_rssi{}; + + + /* + // Statistics: + // Key: + deviceID1: + - manufacturer + - metertype + - serialnr + + // Value: + - message count + - rssi + - lqi??? + */ + + + // Checksum based on the XOR of all removed checksums from the message + uint32_t _checksum = 0; +}; + +#endif // ifndef DATASTRUCTS_MBUSPACKET_H diff --git a/src/src/DataStructs_templ/SettingsStruct.cpp b/src/src/DataStructs_templ/SettingsStruct.cpp index 09215d9493..891f704355 100644 --- a/src/src/DataStructs_templ/SettingsStruct.cpp +++ b/src/src/DataStructs_templ/SettingsStruct.cpp @@ -450,7 +450,7 @@ void SettingsStruct_tmpl::validate() { if ((Longitude < -180.0f) || (Longitude > 180.0f)) { Longitude = 0.0f; } - if (VariousBits1 > (1u << 31)) { VariousBits1 = 0; } // FIXME: Check really needed/useful? + if (getVariousBits1() > (1u << 31)) { setVariousBits1(0); } // FIXME: Check really needed/useful? ZERO_TERMINATE(Name); ZERO_TERMINATE(NTPHost); @@ -612,14 +612,14 @@ void SettingsStruct_tmpl::clearMisc() { Pin_Reset = -1; StructSize = sizeof(SettingsStruct_tmpl); MQTTUseUnitNameAsClientId_unused = 0; - VariousBits1 = 0; + setVariousBits1(0); + setVariousBits2(0); console_serial_port = DEFAULT_CONSOLE_PORT; console_serial_rxpin = DEFAULT_CONSOLE_PORT_RXPIN; console_serial_txpin = DEFAULT_CONSOLE_PORT_TXPIN; console_serial0_fallback = DEFAULT_CONSOLE_SER0_FALLBACK; - OldRulesEngine(DEFAULT_RULES_OLDENGINE); ForceWiFi_bg_mode(DEFAULT_WIFI_FORCE_BG_MODE); WiFiRestart_connection_lost(DEFAULT_WIFI_RESTART_WIFI_CONN_LOST); @@ -882,24 +882,24 @@ spi_host_device_t SettingsStruct_tmpl::getSPI_host() const switch (SPI_selection) { case SPI_Options_e::Vspi_Fspi: { - #if CONFIG_IDF_TARGET_ESP32 - return static_cast(VSPI); + #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 + return static_cast(FSPI_HOST); #else - return static_cast(FSPI); + return static_cast(VSPI_HOST); #endif } #ifdef ESP32_CLASSIC case SPI_Options_e::Hspi: { - return static_cast(HSPI); + return static_cast(HSPI_HOST); } #endif case SPI_Options_e::UserDefined: { - #if CONFIG_IDF_TARGET_ESP32 - return static_cast(VSPI); + #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 + return static_cast(FSPI_HOST); #else - return static_cast(FSPI); + return static_cast(VSPI_HOST); #endif } case SPI_Options_e::None: @@ -908,10 +908,10 @@ spi_host_device_t SettingsStruct_tmpl::getSPI_host() const } #if ESP_IDF_VERSION_MAJOR < 5 - #if CONFIG_IDF_TARGET_ESP32 - return static_cast(VSPI); + #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 + return static_cast(FSPI_HOST); #else - return static_cast(FSPI); + return static_cast(VSPI_HOST); #endif #else return spi_host_device_t::SPI_HOST_MAX; diff --git a/src/src/DataTypes/ESPEasy_plugin_functions.h b/src/src/DataTypes/ESPEasy_plugin_functions.h index f94648b8f3..0952da261b 100644 --- a/src/src/DataTypes/ESPEasy_plugin_functions.h +++ b/src/src/DataTypes/ESPEasy_plugin_functions.h @@ -62,6 +62,9 @@ enum PluginFunctions_e { PLUGIN_PRIORITY_INIT_ALL , // Pre-initialize all plugins that are set to PowerManager priority (not implemented in plugins) PLUGIN_PRIORITY_INIT , // Pre-initialize a singe plugins that is set to PowerManager priority PLUGIN_WEBFORM_LOAD_ALWAYS , // Loaded *after* PLUGIN_WEBFORM_LOAD, also shown for remote data-feed devices +#ifdef USES_ESPEASY_NOW + PLUGIN_FILTEROUT_CONTROLLER_DATA , // Can be called from the controller to query a task whether the data should be processed further. +#endif PLUGIN_WEBFORM_PRE_SERIAL_PARAMS , // Before serial parameters, convert additional parameters like baudrate or specific serial config PLUGIN_MAX_FUNCTION // Leave as last one. diff --git a/src/src/DataTypes/TaskValues_Data.cpp b/src/src/DataTypes/TaskValues_Data.cpp index 9fa84188e9..c4d97b717e 100644 --- a/src/src/DataTypes/TaskValues_Data.cpp +++ b/src/src/DataTypes/TaskValues_Data.cpp @@ -28,22 +28,25 @@ void TaskValues_Data_t::copyValue(const TaskValues_Data_t& other, uint8_t varNr, if (sensorType != Sensor_VType::SENSOR_TYPE_STRING) { if (is32bitOutputDataType(sensorType)) { if (varNr < VARS_PER_TASK) { - uint32s[varNr] = other.uint32s[varNr]; + constexpr unsigned int size_32bit = sizeof(float); + memcpy(binary + (varNr * size_32bit), other.binary + (varNr * size_32bit), size_32bit); } + } #if FEATURE_EXTENDED_TASK_VALUE_TYPES - } else { + else { if ((varNr < (VARS_PER_TASK / 2))) { - uint64s[varNr] = other.uint64s[varNr]; + constexpr unsigned int size_64bit = sizeof(uint64_t); + memcpy(binary + (varNr * size_64bit), other.binary + (varNr * size_64bit), size_64bit); } -#endif } +#endif } } unsigned long TaskValues_Data_t::getSensorTypeLong() const { - const uint16_t low = floats[0]; - const uint16_t high = floats[1]; + const uint16_t low = getFloat(0); + const uint16_t high = getFloat(1); unsigned long value = high; value <<= 16; @@ -53,8 +56,8 @@ unsigned long TaskValues_Data_t::getSensorTypeLong() const void TaskValues_Data_t::setSensorTypeLong(unsigned long value) { - floats[0] = value & 0xFFFF; - floats[1] = (value >> 16) & 0xFFFF; + setFloat(0, value & 0xFFFF); + setFloat(1, (value >> 16) & 0xFFFF); } #if FEATURE_EXTENDED_TASK_VALUE_TYPES @@ -62,7 +65,10 @@ void TaskValues_Data_t::setSensorTypeLong(unsigned long value) int32_t TaskValues_Data_t::getInt32(uint8_t varNr) const { if (varNr < VARS_PER_TASK) { - return int32s[varNr]; + int32_t res{}; + constexpr unsigned int size_32bit = sizeof(float); + memcpy(&res, binary + (varNr * size_32bit), size_32bit); + return res; } return 0; } @@ -70,7 +76,8 @@ int32_t TaskValues_Data_t::getInt32(uint8_t varNr) const void TaskValues_Data_t::setInt32(uint8_t varNr, int32_t value) { if (varNr < VARS_PER_TASK) { - int32s[varNr] = value; + constexpr unsigned int size_32bit = sizeof(float); + memcpy(binary + (varNr * size_32bit), &value, size_32bit); } } #endif @@ -78,7 +85,10 @@ void TaskValues_Data_t::setInt32(uint8_t varNr, int32_t value) uint32_t TaskValues_Data_t::getUint32(uint8_t varNr) const { if (varNr < VARS_PER_TASK) { - return uint32s[varNr]; + uint32_t res{}; + constexpr unsigned int size_32bit = sizeof(float); + memcpy(&res, binary + (varNr * size_32bit), size_32bit); + return res; } return 0u; } @@ -86,7 +96,8 @@ uint32_t TaskValues_Data_t::getUint32(uint8_t varNr) const void TaskValues_Data_t::setUint32(uint8_t varNr, uint32_t value) { if (varNr < VARS_PER_TASK) { - uint32s[varNr] = value; + constexpr unsigned int size_32bit = sizeof(float); + memcpy(binary + (varNr * size_32bit), &value, size_32bit); } } @@ -95,7 +106,10 @@ void TaskValues_Data_t::setUint32(uint8_t varNr, uint32_t value) int64_t TaskValues_Data_t::getInt64(uint8_t varNr) const { if ((varNr < (VARS_PER_TASK / 2))) { - return int64s[varNr]; + int64_t res{}; + constexpr unsigned int size_64bit = sizeof(uint64_t); + memcpy(&res, binary + (varNr * size_64bit), size_64bit); + return res; } return 0; } @@ -103,14 +117,18 @@ int64_t TaskValues_Data_t::getInt64(uint8_t varNr) const void TaskValues_Data_t::setInt64(uint8_t varNr, int64_t value) { if ((varNr < (VARS_PER_TASK / 2))) { - int64s[varNr] = value; + constexpr unsigned int size_64bit = sizeof(uint64_t); + memcpy(binary + (varNr * size_64bit), &value, size_64bit); } } uint64_t TaskValues_Data_t::getUint64(uint8_t varNr) const { if ((varNr < (VARS_PER_TASK / 2))) { - return uint64s[varNr]; + uint64_t res{}; + constexpr unsigned int size_64bit = sizeof(uint64_t); + memcpy(&res, binary + (varNr * size_64bit), size_64bit); + return res; } return 0u; } @@ -118,7 +136,8 @@ uint64_t TaskValues_Data_t::getUint64(uint8_t varNr) const void TaskValues_Data_t::setUint64(uint8_t varNr, uint64_t value) { if ((varNr < (VARS_PER_TASK / 2))) { - uint64s[varNr] = value; + constexpr unsigned int size_64bit = sizeof(uint64_t); + memcpy(binary + (varNr * size_64bit), &value, size_64bit); } } #endif @@ -126,7 +145,10 @@ void TaskValues_Data_t::setUint64(uint8_t varNr, uint64_t value) float TaskValues_Data_t::getFloat(uint8_t varNr) const { if (varNr < VARS_PER_TASK) { - return floats[varNr]; + float res{}; + constexpr unsigned int size_32bit = sizeof(float); + memcpy(&res, binary + (varNr * size_32bit), size_32bit); + return res; } return 0.0f; } @@ -134,7 +156,8 @@ float TaskValues_Data_t::getFloat(uint8_t varNr) const void TaskValues_Data_t::setFloat(uint8_t varNr, float value) { if (varNr < VARS_PER_TASK) { - floats[varNr] = value; + constexpr unsigned int size_32bit = sizeof(float); + memcpy(binary + (varNr * size_32bit), &value, size_32bit); } } @@ -143,7 +166,10 @@ void TaskValues_Data_t::setFloat(uint8_t varNr, float value) double TaskValues_Data_t::getDouble(uint8_t varNr) const { if ((varNr < (VARS_PER_TASK / 2))) { - return doubles[varNr]; + double res{}; + constexpr unsigned int size_64bit = sizeof(uint64_t); + memcpy(&res, binary + (varNr * size_64bit), size_64bit); + return res; } return 0.0; } @@ -151,7 +177,8 @@ double TaskValues_Data_t::getDouble(uint8_t varNr) const void TaskValues_Data_t::setDouble(uint8_t varNr, double value) { if ((varNr < (VARS_PER_TASK / 2))) { - doubles[varNr] = value; + constexpr unsigned int size_64bit = sizeof(uint64_t); + memcpy(binary + (varNr * size_64bit), &value, size_64bit); } } #endif diff --git a/src/src/DataTypes/TaskValues_Data.h b/src/src/DataTypes/TaskValues_Data.h index dbfe5e443c..9d46fac4ea 100644 --- a/src/src/DataTypes/TaskValues_Data.h +++ b/src/src/DataTypes/TaskValues_Data.h @@ -65,20 +65,7 @@ struct __attribute__((__packed__)) TaskValues_Data_t { String getAsString(uint8_t varNr, Sensor_VType sensorType, uint8_t nrDecimals = 0) const; - - union { - uint8_t binary[VARS_PER_TASK * sizeof(float)]; - float floats[VARS_PER_TASK]; - uint32_t uint32s[VARS_PER_TASK]; -#if FEATURE_EXTENDED_TASK_VALUE_TYPES - int32_t int32s[VARS_PER_TASK]; - uint64_t uint64s[VARS_PER_TASK / 2]; - int64_t int64s[VARS_PER_TASK / 2]; -#if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE - double doubles[VARS_PER_TASK / 2]; -#endif -#endif - }; + uint8_t binary[VARS_PER_TASK * sizeof(float)]{}; }; #endif // ifndef DATATYPES_TASKVALUES_DATA_H diff --git a/src/src/ESPEasyCore/Controller.cpp b/src/src/ESPEasyCore/Controller.cpp index 2a5e5214ee..063b0cd8b2 100644 --- a/src/src/ESPEasyCore/Controller.cpp +++ b/src/src/ESPEasyCore/Controller.cpp @@ -36,7 +36,7 @@ constexpr pluginID_t PLUGIN_ID_MQTT_IMPORT(37); // ******************************************************************************** // Interface for Sending to Controllers // ******************************************************************************** -void sendData(struct EventStruct *event) +void sendData(struct EventStruct *event, bool sendEvents) { START_TIMER; #ifndef BUILD_NO_RAM_TRACKER @@ -44,7 +44,7 @@ void sendData(struct EventStruct *event) #endif // ifndef BUILD_NO_RAM_TRACKER // LoadTaskSettings(event->TaskIndex); - if (Settings.UseRules) { + if (Settings.UseRules && sendEvents) { createRuleEvents(event); } diff --git a/src/src/ESPEasyCore/Controller.h b/src/src/ESPEasyCore/Controller.h index 7c2f405ca8..4dd08e996e 100644 --- a/src/src/ESPEasyCore/Controller.h +++ b/src/src/ESPEasyCore/Controller.h @@ -9,7 +9,7 @@ // ******************************************************************************** // Interface for Sending to Controllers // ******************************************************************************** -void sendData(struct EventStruct *event); +void sendData(struct EventStruct *event, bool sendEvents = true); bool validUserVar(struct EventStruct *event); diff --git a/src/src/ESPEasyCore/ESPEasyEth_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyEth_ProcessEvent.cpp index 75e86eb092..50e35132c6 100644 --- a/src/src/ESPEasyCore/ESPEasyEth_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyEth_ProcessEvent.cpp @@ -17,6 +17,7 @@ # include "../Globals/NetworkState.h" # include "../Globals/Settings.h" +# include "../Helpers/LongTermTimer.h" # include "../Helpers/Network.h" # include "../Helpers/Networking.h" # include "../Helpers/PeriodicalActions.h" @@ -164,14 +165,19 @@ void processEthernetGotIP() { IPAddress dns0 = ETH.dnsIP(0); IPAddress dns1 = ETH.dnsIP(1); const LongTermTimer::Duration dhcp_duration = EthEventData.lastConnectMoment.timeDiff(EthEventData.lastGetIPmoment); - - if (!dns0 && !dns1) { - addLog(LOG_LEVEL_ERROR, F("ETH : No DNS server received via DHCP, use cached DNS IP")); - setDNS(0, EthEventData.dns0_cache); - setDNS(1, EthEventData.dns1_cache); - } else { - EthEventData.dns0_cache = dns0; - EthEventData.dns1_cache = dns1; + #if ESP_IDF_VERSION_MAJOR >= 5 + const bool mustRequestDHCP = (!dns0 && !dns1) && !ethUseStaticIP(); + #endif + + if (!ethUseStaticIP()) { + if (!dns0 && !dns1) { + addLog(LOG_LEVEL_ERROR, F("ETH : No DNS server received via DHCP, use cached DNS IP")); + if (EthEventData.dns0_cache) setDNS(0, EthEventData.dns0_cache); + if (EthEventData.dns1_cache) setDNS(1, EthEventData.dns1_cache); + } else { + EthEventData.dns0_cache = dns0; + EthEventData.dns1_cache = dns1; + } } if (loglevelActiveFor(LOG_LEVEL_INFO)) @@ -244,6 +250,14 @@ void processEthernetGotIP() { logConnectionStatus(); EthEventData.processedGotIP = true; +#if ESP_IDF_VERSION_MAJOR >= 5 + if (mustRequestDHCP /*&& EthEventData.lastConnectMoment.millisPassedSince() < 10000*/) { + // FIXME TD-er: Must add some check other than fixed timeout here to not constantly make DHCP requests. + // Force new DHCP request. + ETH.config(); + } +#endif + EthEventData.setEthGotIP(); CheckRunningServices(); } diff --git a/src/src/ESPEasyCore/ESPEasyNetwork.cpp b/src/src/ESPEasyCore/ESPEasyNetwork.cpp index 8a3b05959f..addcb54fe8 100644 --- a/src/src/ESPEasyCore/ESPEasyNetwork.cpp +++ b/src/src/ESPEasyCore/ESPEasyNetwork.cpp @@ -46,6 +46,9 @@ void setNetworkMedium(NetworkMedium_t new_medium) { // ETH.end(); if (new_medium == NetworkMedium_t::WIFI) { WiFiEventData.clearAll(); +#if ESP_IDF_VERSION_MAJOR >= 5 + WiFi.STA.setDefault(); +#endif } #endif break; @@ -53,6 +56,11 @@ void setNetworkMedium(NetworkMedium_t new_medium) { WiFiEventData.timerAPoff.setMillisFromNow(WIFI_AP_OFF_TIMER_DURATION); WiFiEventData.timerAPstart.clear(); if (new_medium == NetworkMedium_t::Ethernet) { +#if ESP_IDF_VERSION_MAJOR >= 5 +#if FEATURE_ETHERNET + ETH.setDefault(); +#endif +#endif WifiDisconnect(); } break; diff --git a/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp b/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp index dd70788ac3..4390c50e7f 100644 --- a/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWiFiEvent.cpp @@ -28,8 +28,7 @@ #ifdef ESP32 -void WiFi_Access_Static_IP::set_use_static_ip(bool enabled) { - _useStaticIp = enabled; +void setUseStaticIP(bool enabled) { } #endif // ifdef ESP32 @@ -37,16 +36,16 @@ void WiFi_Access_Static_IP::set_use_static_ip(bool enabled) { void WiFi_Access_Static_IP::set_use_static_ip(bool enabled) { _useStaticIp = enabled; } - -#endif // ifdef ESP8266 - - void setUseStaticIP(bool enabled) { WiFi_Access_Static_IP tmp_wifi; tmp_wifi.set_use_static_ip(enabled); } +#endif // ifdef ESP8266 + + + // ******************************************************************************** // Functions called on events. @@ -143,7 +142,12 @@ void WiFiEvent(WiFiEvent_t event, arduino_event_info_t info) { WiFiEventData.markDisconnect(static_cast(info.wifi_sta_disconnected.reason)); if (info.wifi_sta_disconnected.reason == WIFI_REASON_AUTH_EXPIRE) { // See: https://github.com/espressif/arduino-esp32/issues/8877#issuecomment-1807677897 + #if ESP_IDF_VERSION_MAJOR >= 5 + // FIXME TD-er: Should no longer be needed. + WiFi.STA._setStatus(WL_CONNECTION_LOST); + #else WiFiSTAClass::_setStatus(WL_CONNECTION_LOST); + #endif } #else WiFiEventData.markDisconnect(static_cast(info.disconnected.reason)); diff --git a/src/src/ESPEasyCore/ESPEasyWifi.cpp b/src/src/ESPEasyCore/ESPEasyWifi.cpp index b0738bfded..46f88667d0 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi.cpp @@ -497,13 +497,13 @@ void AttemptWiFiConnect() { WiFi.enableIPv6(true); #endif - if ((Settings.HiddenSSID_SlowConnectPerBSSID() || !candidate.isHidden) + if ((Settings.HiddenSSID_SlowConnectPerBSSID() || !candidate.bits.isHidden) && candidate.allowQuickConnect()) { WiFi.begin(candidate.ssid.c_str(), key.c_str(), candidate.channel, candidate.bssid.mac); } else { WiFi.begin(candidate.ssid.c_str(), key.c_str()); } - if (Settings.WaitWiFiConnect() || candidate.isHidden) { + if (Settings.WaitWiFiConnect() || candidate.bits.isHidden) { // WiFi.waitForConnectResult(candidate.isHidden ? 3000 : 1000); // https://github.com/arendst/Tasmota/issues/14985 WiFi.waitForConnectResult(1000); // https://github.com/arendst/Tasmota/issues/14985 } @@ -1396,7 +1396,7 @@ void setWifiMode(WiFiMode_t new_mode) { SetWiFiTXpower(); #endif if (WifiIsSTA(new_mode)) { - WiFi.setAutoConnect(Settings.SDK_WiFi_autoreconnect()); +// WiFi.setAutoConnect(Settings.SDK_WiFi_autoreconnect()); WiFi.setAutoReconnect(Settings.SDK_WiFi_autoreconnect()); } delay(100); // Must allow for some time to init. @@ -1460,11 +1460,11 @@ void setConnectionSpeed() { WiFiPhyMode_t phyMode = (Settings.ForceWiFi_bg_mode() || forcedByAPmode) ? WIFI_PHY_MODE_11G : WIFI_PHY_MODE_11N; if (!forcedByAPmode) { const WiFi_AP_Candidate candidate = WiFi_AP_Candidates.getCurrent(); - if (candidate.phy_known() && (candidate.phy_11g != candidate.phy_11n)) { - if ((WIFI_PHY_MODE_11G == phyMode) && !candidate.phy_11g) { + if (candidate.phy_known() && (candidate.bits.phy_11g != candidate.bits.phy_11n)) { + if ((WIFI_PHY_MODE_11G == phyMode) && !candidate.bits.phy_11g) { phyMode = WIFI_PHY_MODE_11N; addLog(LOG_LEVEL_INFO, F("WIFI : AP is set to 802.11n only")); - } else if ((WIFI_PHY_MODE_11N == phyMode) && !candidate.phy_11n) { + } else if ((WIFI_PHY_MODE_11N == phyMode) && !candidate.bits.phy_11n) { phyMode = WIFI_PHY_MODE_11G; addLog(LOG_LEVEL_INFO, F("WIFI : AP is set to 802.11g only")); } @@ -1522,14 +1522,14 @@ void setConnectionSpeed() { if (candidate.phy_known()) { // Check to see if the access point is set to "N-only" if ((protocol & WIFI_PROTOCOL_11N) == 0) { - if (!candidate.phy_11b && !candidate.phy_11g && candidate.phy_11n) { - if (candidate.phy_11n) { + if (!candidate.bits.phy_11b && !candidate.bits.phy_11g && candidate.bits.phy_11n) { + if (candidate.bits.phy_11n) { // Set to use BGN protocol |= WIFI_PROTOCOL_11N; addLog(LOG_LEVEL_INFO, F("WIFI : AP is set to 802.11n only")); } #ifdef ESP32C6 - if (candidate.phy_11ax) { + if (candidate.bits.phy_11ax) { // Set to use WiFi6 protocol |= WIFI_PROTOCOL_11AX; addLog(LOG_LEVEL_INFO, F("WIFI : AP is set to 802.11ax")); diff --git a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp index 7e81f864fe..0453dc0497 100644 --- a/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp +++ b/src/src/ESPEasyCore/ESPEasyWifi_ProcessEvent.cpp @@ -308,7 +308,7 @@ void processConnect() { WiFiEventData.setWiFiConnected(); ++WiFiEventData.wifi_reconnects; - if (WiFi_AP_Candidates.getCurrent().isEmergencyFallback) { + if (WiFi_AP_Candidates.getCurrent().bits.isEmergencyFallback) { #ifdef CUSTOM_EMERGENCY_FALLBACK_RESET_CREDENTIALS const bool mustResetCredentials = CUSTOM_EMERGENCY_FALLBACK_RESET_CREDENTIALS; #else diff --git a/src/src/ESPEasyCore/ESPEasy_Console.cpp b/src/src/ESPEasyCore/ESPEasy_Console.cpp index ab23476ad0..056bb5261f 100644 --- a/src/src/ESPEasyCore/ESPEasy_Console.cpp +++ b/src/src/ESPEasyCore/ESPEasy_Console.cpp @@ -149,10 +149,22 @@ void EspEasy_Console_t::reInit() HeapSelectDram ephemeral; # endif // ifdef USE_SECOND_HEAP + unsigned int buffsize = 128; + + const ESPEasySerialPort mainSerialPort = static_cast(_console_serial_port); + +#if USES_HWCDC + if (mainSerialPort == ESPEasySerialPort::usb_hw_cdc) { + buffsize = 2048; + } +#endif // if USES_HWCDC + _mainSerial._serial = new (std::nothrow) ESPeasySerial( - static_cast(_console_serial_port), + mainSerialPort, _console_serial_rxpin, - _console_serial_txpin); + _console_serial_txpin, + false, + buffsize); somethingChanged = true; } # if USES_ESPEASY_CONSOLE_FALLBACK_PORT diff --git a/src/src/ESPEasyCore/ESPEasy_Console_Port.cpp b/src/src/ESPEasyCore/ESPEasy_Console_Port.cpp index d29323dda4..91f39d59ba 100644 --- a/src/src/ESPEasyCore/ESPEasy_Console_Port.cpp +++ b/src/src/ESPEasyCore/ESPEasy_Console_Port.cpp @@ -24,10 +24,12 @@ EspEasy_Console_Port::~EspEasy_Console_Port() { +#if FEATURE_DEFINE_SERIAL_CONSOLE_PORT if (_serial != nullptr) { delete _serial; _serial = nullptr; } +#endif } EspEasy_Console_Port::operator bool() const diff --git a/src/src/Globals/Plugins.cpp b/src/src/Globals/Plugins.cpp index 7b93b9e1ab..9da15070cc 100644 --- a/src/src/Globals/Plugins.cpp +++ b/src/src/Globals/Plugins.cpp @@ -283,6 +283,7 @@ bool PluginCallForTask(taskIndex_t taskIndex, uint8_t Function, EventStruct *Tem if (Settings.TaskDeviceDataFeed[taskIndex] == 0) // these calls only to tasks with local feed { if (Function == PLUGIN_INIT) { + UserVar.clear_computed(taskIndex); LoadTaskSettings(taskIndex); } TempEvent->setTaskIndex(taskIndex); @@ -602,6 +603,7 @@ bool PluginCall(uint8_t Function, struct EventStruct *event, String& str) bool retval = PluginCallForTask(taskIndex, Function, &TempEvent, str, event); if (Function == PLUGIN_INIT) { + UserVar.clear_computed(taskIndex); if (!retval && Settings.TaskDeviceDataFeed[taskIndex] == 0) { // Disable temporarily as PLUGIN_INIT failed // FIXME TD-er: Should reschedule call to PLUGIN_INIT???? @@ -690,6 +692,9 @@ bool PluginCall(uint8_t Function, struct EventStruct *event, String& str) if (!Settings.TaskDeviceEnabled[event->TaskIndex]) { return false; } + if (Function == PLUGIN_INIT) { + UserVar.clear_computed(event->TaskIndex); + } } const deviceIndex_t DeviceIndex = getDeviceIndex_from_TaskIndex(event->TaskIndex); @@ -818,6 +823,7 @@ bool PluginCall(uint8_t Function, struct EventStruct *event, String& str) } } if (Function == PLUGIN_EXIT) { + UserVar.clear_computed(event->TaskIndex); clearPluginTaskData(event->TaskIndex); // initSerial(); queueTaskEvent(F("TaskExit"), event->TaskIndex, retval); @@ -854,6 +860,9 @@ bool PluginCall(uint8_t Function, struct EventStruct *event, String& str) case PLUGIN_I2C_HAS_ADDRESS: case PLUGIN_WEBFORM_SHOW_ERRORSTATE_OPT: case PLUGIN_INIT_VALUE_RANGES: + #ifdef USES_ESPEASY_NOW + case PLUGIN_FILTEROUT_CONTROLLER_DATA: + #endif // PLUGIN_MQTT_xxx functions are directly called from the scheduler. //case PLUGIN_MQTT_CONNECTION_STATE: @@ -899,7 +908,6 @@ bool PluginCall(uint8_t Function, struct EventStruct *event, String& str) // Each of these may update ExtraTaskSettings, but it may not have been saved yet. // Thus update the cache just in case something from it is requested from the cache. Cache.updateExtraTaskSettingsCache(); - UserVar.clear_computed(event->TaskIndex); } if (Function == PLUGIN_SET_DEFAULTS) { saveUserVarToRTC(); diff --git a/src/src/Helpers/CUL_interval_filter.cpp b/src/src/Helpers/CUL_interval_filter.cpp new file mode 100644 index 0000000000..6cc2d860e8 --- /dev/null +++ b/src/src/Helpers/CUL_interval_filter.cpp @@ -0,0 +1,101 @@ +#include "../Helpers/CUL_interval_filter.h" + + +#ifdef USES_P094 + +# include "../ESPEasyCore/ESPEasy_Log.h" +# include "../Globals/ESPEasy_time.h" +# include "../Globals/TimeZone.h" +# include "../Helpers/ESPEasy_time_calc.h" +# include "../Helpers/StringConverter.h" + + +CUL_time_filter_struct::CUL_time_filter_struct(uint32_t checksum, unsigned long UnixTimeExpiration) + : _checksum(checksum), _UnixTimeExpiration(UnixTimeExpiration) {} + +String CUL_interval_filter_getExpiration_log_str(const P094_filter& filter) +{ + const unsigned long expiration = filter.computeUnixTimeExpiration(); + + if ((expiration != 0) && (expiration != 0xFFFFFFFF)) { + struct tm exp_tm; + breakTime(time_zone.toLocal(expiration), exp_tm); + + return concat(F(" Expiration: "), formatDateTimeString(exp_tm)); + } + return EMPTY_STRING; +} + +bool CUL_interval_filter::filter(const mBusPacket_t& packet, const P094_filter& filter) +{ + if (!enabled) { + return true; + } + + if (filter.getFilterWindow() == P094_Filter_Window::None) { + // Will always be rejected, so no need to keep track of the message + return false; + } + + if (filter.getFilterWindow() == P094_Filter_Window::All) { + // Will always be allowed, so no need to keep track of the message + return true; + } + + const uint32_t key = packet.deviceID_to_map_key(); + auto it = _mBusFilterMap.find(key); + + if (it != _mBusFilterMap.end()) { + // Already present + if (node_time.getUnixTime() < it->second._UnixTimeExpiration) { + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = concat(F("CUL : Interval filtered: "), packet.toString()); + log += CUL_interval_filter_getExpiration_log_str(filter); + addLogMove(LOG_LEVEL_INFO, log); + } + return false; + } + + if (packet._checksum == it->second._checksum) { + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + addLogMove(LOG_LEVEL_INFO, concat(F("CUL : Interval Same Checksum: "), packet.toString())); + } + return false; + } + + // Has expired, so remove from filter map + _mBusFilterMap.erase(it); + } + + const unsigned long expiration = filter.computeUnixTimeExpiration(); + + CUL_time_filter_struct item(packet._checksum, expiration); + + _mBusFilterMap[key] = item; + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + String log = concat(F("CUL : Add to IntervalFilter: "), packet.toString()); + log += CUL_interval_filter_getExpiration_log_str(filter); + + addLogMove(LOG_LEVEL_INFO, log); + } + + return true; +} + +void CUL_interval_filter::purgeExpired() +{ + auto it = _mBusFilterMap.begin(); + + const unsigned long currentTime = node_time.getUnixTime(); + + for (; it != _mBusFilterMap.end();) { + if (currentTime > it->second._UnixTimeExpiration) { + it = _mBusFilterMap.erase(it); + } else { + ++it; + } + } +} + +#endif // ifdef USES_P094 diff --git a/src/src/Helpers/CUL_interval_filter.h b/src/src/Helpers/CUL_interval_filter.h new file mode 100644 index 0000000000..b68f3cb958 --- /dev/null +++ b/src/src/Helpers/CUL_interval_filter.h @@ -0,0 +1,42 @@ +#ifndef DATASTRUCTS_P094_CUL_TIME_FILTER_STRUCT_H +#define DATASTRUCTS_P094_CUL_TIME_FILTER_STRUCT_H + +#include "../../ESPEasy_common.h" +#ifdef USES_P094 + +# include "../DataStructs/mBusPacket.h" +# include "../PluginStructs/P094_Filter.h" + +# include + + +struct CUL_time_filter_struct { + CUL_time_filter_struct() = default; + CUL_time_filter_struct(uint32_t checksum, + unsigned long UnixTimeExpiration); + + uint32_t _checksum{}; + unsigned long _UnixTimeExpiration{}; +}; + +typedef uint32_t mBusSerial; + +typedef std::map mBusFilterMap; + + +struct CUL_interval_filter { + // Return true when packet wasn't already present. + bool filter(const mBusPacket_t& packet, + const P094_filter & filter); + + // Remove packets that have expired. + void purgeExpired(); + + + mBusFilterMap _mBusFilterMap; + + bool enabled = false; +}; + +#endif // ifdef USES_P094 +#endif // ifndef DATASTRUCTS_P094_CUL_TIME_FILTER_STRUCT_H diff --git a/src/src/Helpers/CUL_stats.cpp b/src/src/Helpers/CUL_stats.cpp new file mode 100644 index 0000000000..b857bda1dc --- /dev/null +++ b/src/src/Helpers/CUL_stats.cpp @@ -0,0 +1,135 @@ +#include "../Helpers/CUL_stats.h" + +#ifdef USES_P094 + +# include "../ESPEasyCore/ESPEasy_Log.h" +# include "../Globals/ESPEasy_time.h" +# include "../Helpers/CRC_functions.h" +# include "../Helpers/ESPEasy_time_calc.h" +# include "../Helpers/StringConverter.h" + +# include "../WebServer/Markup.h" +# include "../WebServer/HTML_wrappers.h" + +String CUL_Stats::toString(const CUL_Stats_struct& element) const +{ + uint8_t LQI = 0; + const int16_t rssi = mBusPacket_t::decode_LQI_RSSI(element._lqi_rssi, LQI); + + // e.g.: THC.02.12345678;1674030412;1674031412;123;101,-36 + static size_t estimated_length = 52; + + String res; + + res.reserve(estimated_length); + { + auto it = _mBusStatsSourceMap.find(element._sourceHash); + if (element._sourceHash != 0u && it != _mBusStatsSourceMap.end()) { + res += it->second; + } else { + res += '-'; + } + } + res += ';'; + + if (element._id1 != 0u) { + mBusPacket_header_t deviceID; + deviceID.decode_fromUint64(element._id1); + res += deviceID.toString(); + } else { + res += '-'; + } + res += ';'; + + if (element._id2 != 0u) { + mBusPacket_header_t deviceID; + deviceID.decode_fromUint64(element._id2); + res += deviceID.toString(); + } else { + res += '-'; + } + res += ';'; + + res += element._UnixTimeFirstSeen; + res += ';'; + res += element._UnixTimeLastSeen; + res += ';'; + res += element._count; + res += ';'; + res += LQI; + res += ';'; + res += rssi; + + if (res.length() > estimated_length) { + estimated_length = res.length(); + } + return res; +} + +bool CUL_Stats::add(const mBusPacket_t& packet) +{ + const CUL_stats_hash sourceHash{}; + return add(packet, packet.deviceID_to_map_key_no_length(), sourceHash); +} + + +bool CUL_Stats::add(const mBusPacket_t& packet, const String& source) +{ + CUL_stats_hash key = packet.deviceID_to_map_key_no_length(); + CUL_stats_hash sourceHash{}; + + if (!source.isEmpty()) { + sourceHash = calc_CRC32((const uint8_t *)(source.c_str()), source.length()); + _mBusStatsSourceMap[sourceHash] = source; + key ^= sourceHash; + } + + return add(packet, key, sourceHash); +} + +bool CUL_Stats::add(const mBusPacket_t& packet, CUL_stats_hash key, CUL_stats_hash sourceHash) +{ + if (key == 0) { return false; } + + auto it = _mBusStatsMap.find(key); + + if (it == _mBusStatsMap.end()) { + CUL_Stats_struct tmp; + tmp._count = 1; + tmp._id1 = packet._deviceId1.encode_toUInt64(); + tmp._id2 = packet._deviceId2.encode_toUInt64(); + tmp._lqi_rssi = packet._lqi_rssi; + tmp._UnixTimeFirstSeen = node_time.now(); + tmp._UnixTimeLastSeen = tmp._UnixTimeFirstSeen; + tmp._sourceHash = sourceHash; + _mBusStatsMap[key] = tmp; + return true; + } + it->second._count++; + it->second._lqi_rssi = packet._lqi_rssi; + it->second._UnixTimeLastSeen = node_time.now(); + return false; +} + +String CUL_Stats::getFront() +{ + auto it = _mBusStatsMap.begin(); + + if (it == _mBusStatsMap.end()) { return EMPTY_STRING; } + const String res = toString(it->second); + + _mBusStatsMap.erase(it); + return res; +} + +void CUL_Stats::toHtml() const +{ + addRowLabel(F("CUL stats")); + + for (auto it = _mBusStatsMap.begin(); it != _mBusStatsMap.end(); ++it) { + addHtml(toString(it->second)); + addHtml(F("
")); + } +} + +#endif // ifdef USES_P094 diff --git a/src/src/Helpers/CUL_stats.h b/src/src/Helpers/CUL_stats.h new file mode 100644 index 0000000000..4c131f96e4 --- /dev/null +++ b/src/src/Helpers/CUL_stats.h @@ -0,0 +1,59 @@ +#ifndef DATASTRUCTS_P094_CUL_STATS_H +#define DATASTRUCTS_P094_CUL_STATS_H + +#include "../../ESPEasy_common.h" +#ifdef USES_P094 + +# include "../DataStructs/mBusPacket.h" + +# include + + +typedef uint64_t mBus_EncodedDeviceID; + +typedef uint32_t CUL_stats_hash; + + +struct CUL_Stats_struct { + mBus_EncodedDeviceID _id1{}; + mBus_EncodedDeviceID _id2{}; + uint32_t _UnixTimeFirstSeen{}; + uint32_t _UnixTimeLastSeen{}; + uint16_t _lqi_rssi{}; + uint16_t _count{}; + CUL_stats_hash _sourceHash{}; +}; + + +typedef std::map mBusStatsMap; +typedef std::map mBusStatsSourceMap; + + +struct CUL_Stats { + // Create a string like this: + // mBus device ID;UNIX time first;UNIX time last;count;LQI;RSSI + // THC.02.12345678;1674030412;1674031412;123;101,-36 + String toString(const CUL_Stats_struct& element) const; + + + // Return true when packet wasn't already present. + bool add(const mBusPacket_t& packet); + bool add(const mBusPacket_t& packet, const String& source); + +private: + + bool add(const mBusPacket_t& packet, CUL_stats_hash key, CUL_stats_hash sourceHash); + +public: + + // Create string from front element and remove from map + String getFront(); + + void toHtml() const; + + mBusStatsMap _mBusStatsMap; + mBusStatsSourceMap _mBusStatsSourceMap; +}; + +#endif // ifdef USES_P094 +#endif // ifndef DATASTRUCTS_P094_CUL_STATS_H diff --git a/src/src/Helpers/Dallas1WireHelper.cpp b/src/src/Helpers/Dallas1WireHelper.cpp index 37c625bc13..c8d55f7132 100644 --- a/src/src/Helpers/Dallas1WireHelper.cpp +++ b/src/src/Helpers/Dallas1WireHelper.cpp @@ -117,11 +117,15 @@ void Dallas_addr_selector_webform_load(taskIndex_t TaskIndex, int8_t gpio_pin_rx uint64_t tmpAddr_64 = Dallas_addr_to_uint64(tmpAddress); if (tmpAddr_64 != 0) { - addr_task_map[tmpAddr_64] = strformat( - F(" (task %d [%s#%s])") - , task + 1 - , getTaskDeviceName(task).c_str() - , getTaskValueName(task, var_index).c_str()); + addr_task_map.emplace( + std::make_pair( + tmpAddr_64, + strformat( + F(" (task %d [%s#%s])") + , task + 1 + , getTaskDeviceName(task).c_str() + , getTaskValueName(task, var_index).c_str()) + )); } } } diff --git a/src/src/Helpers/ESPEasy_Storage.cpp b/src/src/Helpers/ESPEasy_Storage.cpp index 424920049f..80a20633f6 100644 --- a/src/src/Helpers/ESPEasy_Storage.cpp +++ b/src/src/Helpers/ESPEasy_Storage.cpp @@ -152,7 +152,10 @@ bool fileExists(const String& fname) { if (res || !isCacheFile(patched_fname)) #endif { - Cache.fileExistsMap[patched_fname] = res; + Cache.fileExistsMap.emplace( + std::make_pair( + patched_fname, + res)); } if (Cache.fileCacheClearMoment == 0) { if (node_time.timeSource == timeSource_t::No_time_source) { @@ -404,7 +407,7 @@ bool BuildFixes() } // Remove PeriodicalScanWiFi // Reset to default 0 for future use. - bitWrite(Settings.VariousBits1, 15, 0); + Settings.VariousBits_1.unused_15 = 0; } #endif @@ -1103,6 +1106,7 @@ String SaveTaskSettings(taskIndex_t TaskIndex) err = checkTaskSettings(TaskIndex); } #endif + // FIXME TD-er: Is this still needed as it is also cleared on PLUGIN_INIT and PLUGIN_EXIT? UserVar.clear_computed(ExtraTaskSettings.TaskIndex); } #ifndef LIMIT_BUILD_SIZE @@ -1163,7 +1167,6 @@ String LoadTaskSettings(taskIndex_t TaskIndex) ExtraTaskSettings.validate(); Cache.updateExtraTaskSettingsCache_afterLoad_Save(); - UserVar.clear_computed(ExtraTaskSettings.TaskIndex); STOP_TIMER(LOAD_TASK_SETTINGS); return result; diff --git a/src/src/Helpers/ESPEasy_time.cpp b/src/src/Helpers/ESPEasy_time.cpp index 7739ffa6bf..7302c3d98f 100644 --- a/src/src/Helpers/ESPEasy_time.cpp +++ b/src/src/Helpers/ESPEasy_time.cpp @@ -17,6 +17,11 @@ #include "../Globals/Settings.h" #include "../Globals/TimeZone.h" +#ifdef USES_ESPEASY_NOW +#include "../Globals/ESPEasy_now_handler.h" +#endif + + #include "../Helpers/Convert.h" #include "../Helpers/Hardware.h" #include "../Helpers/Hardware_I2C.h" @@ -299,9 +304,8 @@ unsigned long ESPEasy_time::now() { uint32_t localSystime = time_zone.toLocal(sysTime); breakTime(localSystime, local_tm); + calcSunRiseAndSet(timeSynced); if (timeSynced) { - calcSunRiseAndSet(); - if (loglevelActiveFor(LOG_LEVEL_INFO)) { addLog(LOG_LEVEL_INFO, strformat( F("Local time: %s"), @@ -446,7 +450,7 @@ bool ESPEasy_time::getNtpTime(double& unixTime_d) udp.endPacket(); - uint32_t beginWait = millis(); + const uint32_t beginWait = millis(); while (!timeOutReached(beginWait + 1000)) { int size = udp.parsePacket(); @@ -744,13 +748,19 @@ int ESPEasy_time::dayOfYear(int year, int month, int day) { return j - k + 1; } -void ESPEasy_time::calcSunRiseAndSet() { - int doy = dayOfYear(local_tm.tm_year, local_tm.tm_mon + 1, local_tm.tm_mday); - float eqt = equationOfTime(doy); - float dec = sunDeclination(doy); - float da = diurnalArc(dec, Settings.Latitude); - float rise = 12 - da - eqt; - float set = 12 + da - eqt; +void ESPEasy_time::calcSunRiseAndSet(bool timeSynced) { + if (!timeSynced && + (tsSet.tm_mday == local_tm.tm_mday)) { + // No need to recalculate if already calculated for this day + return; + } + + const int doy = dayOfYear(local_tm.tm_year, local_tm.tm_mon + 1, local_tm.tm_mday); + const float eqt = equationOfTime(doy); + const float dec = sunDeclination(doy); + const float da = diurnalArc(dec, Settings.Latitude); + const float rise = 12 - da - eqt; + const float set = 12 + da - eqt; tsRise.tm_hour = rise; tsRise.tm_min = (rise - static_cast(rise)) * 60.0f; @@ -761,7 +771,7 @@ void ESPEasy_time::calcSunRiseAndSet() { tsRise.tm_year = tsSet.tm_year = local_tm.tm_year; // Now apply the longitude - int secOffset_longitude = -1.0f * (Settings.Longitude / 15.0f) * 3600; + const int secOffset_longitude = -1.0f * (Settings.Longitude / 15.0f) * 3600; tsSet = addSeconds(tsSet, secOffset_longitude, false); tsRise = addSeconds(tsRise, secOffset_longitude, false); @@ -855,9 +865,9 @@ bool ESPEasy_time::ExtRTC_get(uint32_t& unixtime) } if (unixtime != 0) { - String log = F("ExtRTC: Read external time source: "); - log += unixtime; - addLogMove(LOG_LEVEL_INFO, log); + addLogMove(LOG_LEVEL_INFO, concat( + F("ExtRTC: Read external time source: "), + unixtime)); return true; } addLog(LOG_LEVEL_ERROR, F("ExtRTC: Cannot get time from external time source")); diff --git a/src/src/Helpers/ESPEasy_time.h b/src/src/Helpers/ESPEasy_time.h index e2f32376b2..20c0808e7d 100644 --- a/src/src/Helpers/ESPEasy_time.h +++ b/src/src/Helpers/ESPEasy_time.h @@ -176,7 +176,7 @@ class ESPEasy_time { int month, int day); - void calcSunRiseAndSet(); + void calcSunRiseAndSet(bool timeSynced); struct tm getSunRise(int secOffset) const; struct tm getSunSet(int secOffset) const; diff --git a/src/src/Helpers/ESPEasy_time_calc.cpp b/src/src/Helpers/ESPEasy_time_calc.cpp index 2a156d56e8..9b144d8b00 100644 --- a/src/src/Helpers/ESPEasy_time_calc.cpp +++ b/src/src/Helpers/ESPEasy_time_calc.cpp @@ -28,6 +28,10 @@ uint8_t getMonthDays(int year, uint8_t month) { return monthDays[month]; } +uint8_t getMonthDays(const struct tm& tm) { + return getMonthDays(tm.tm_year + 1900, tm.tm_mon); +} + /********************************************************************************************\ Unix Time computations \*********************************************************************************************/ @@ -408,4 +412,4 @@ bool matchClockEvent(unsigned long clockEvent, unsigned long clockSet) } return (clockEvent == clockSet); -} +} \ No newline at end of file diff --git a/src/src/Helpers/ESPEasy_time_calc.h b/src/src/Helpers/ESPEasy_time_calc.h index 03cad24336..6aaef59916 100644 --- a/src/src/Helpers/ESPEasy_time_calc.h +++ b/src/src/Helpers/ESPEasy_time_calc.h @@ -65,6 +65,7 @@ bool isLeapYear(int year); // Get number of days in a month. // Month starts at 0 for January. uint8_t getMonthDays(int year, uint8_t month); +uint8_t getMonthDays(const struct tm& tm); uint32_t makeTime(const struct tm& tm); diff --git a/src/src/Helpers/Hardware.cpp b/src/src/Helpers/Hardware.cpp index 19c9dba5dd..6a98338519 100644 --- a/src/src/Helpers/Hardware.cpp +++ b/src/src/Helpers/Hardware.cpp @@ -114,6 +114,10 @@ # include "../Helpers/Hardware_ADC_cali.h" +#if FEATURE_ETHERNET +#include +#endif + #endif // ifdef ESP32 diff --git a/src/src/Helpers/Improv_Helper.cpp b/src/src/Helpers/Improv_Helper.cpp index 66b7eeb644..c646fa0876 100644 --- a/src/src/Helpers/Improv_Helper.cpp +++ b/src/src/Helpers/Improv_Helper.cpp @@ -17,13 +17,14 @@ void OnImprovError(ImprovTypes::Error error) String log = F("IMPROV : "); switch (error) { + case ImprovTypes::Error::ERROR_NONE: return; case ImprovTypes::Error::ERROR_INVALID_RPC: log += F("Invalid RPC"); break; case ImprovTypes::Error::ERROR_UNKNOWN_RPC: log += F("Unkown RPC"); break; case ImprovTypes::Error::ERROR_UNABLE_TO_CONNECT: log += F("Unable to connect"); break; case ImprovTypes::Error::ERROR_NOT_AUTHORIZED: log += F("Not Authorized"); break; + case ImprovTypes::Error::ERROR_INVALID_CHECKSUM: log += F("Invalid Checksum"); break; + case ImprovTypes::Error::ERROR_EMPTY_SSID: log += F("Empty SSID"); break; case ImprovTypes::Error::ERROR_UNKNOWN: log += F("Unknown"); break; - default: - return; } addLogMove(LOG_LEVEL_ERROR, log); } @@ -34,16 +35,28 @@ void OnImprovConnected(const char *ssid, const char *password) safe_strncpy( SecuritySettings.WifiSSID, ssid, - sizeof(SecuritySettings.WifiSSID2)); + sizeof(SecuritySettings.WifiSSID)); safe_strncpy( SecuritySettings.WifiKey, password, sizeof(SecuritySettings.WifiKey)); - SaveSettings(); + SaveSecuritySettings(); } bool OnImprovESPEasyConnectWiFi(const char *ssid, const char *password) { +// addLog(LOG_LEVEL_INFO, strformat(F("IMPROV WiFi connect: SSID: %s, Pass: %s"), ssid, password)); +/* + safe_strncpy( + SecuritySettings.WifiSSID, + ssid, + sizeof(SecuritySettings.WifiSSID)); + safe_strncpy( + SecuritySettings.WifiKey, + password, + sizeof(SecuritySettings.WifiKey)); + */ + return false; } @@ -56,7 +69,7 @@ void Improv_Helper_t::init() _improv.onImprovConnected(OnImprovConnected); // FIXME TD-er: Implement callback to use ESPEasy functions to connect to WiFi - // _improv.setCustomTryConnectToWiFi(OnImprovESPEasyConnectWiFi); +// _improv.setCustomTryConnectToWiFi(OnImprovESPEasyConnectWiFi); String firmwareName = get_binary_filename(); const String buildString = getSystemBuildString(); @@ -111,7 +124,29 @@ bool Improv_Helper_t::handle(uint8_t b, Stream *serialForWrite) _tmpbuffer.push_back(b); - switch (_improv.handleSerial(b, serialForWrite)) { + const ImprovTypes::ParseState state = _improv.handleSerial(b, serialForWrite); + +#ifndef BUILD_NO_DEBUG + + if (loglevelActiveFor(LOG_LEVEL_DEBUG) && + state != ImprovTypes::ParseState::VALID_INCOMPLETE) + { + String log = F("IMPROVDEBUG: "); + for (auto it = _tmpbuffer.begin(); it != _tmpbuffer.end(); ++it) { + if (isAlphaNumeric(*it)) + log += static_cast(*it); + else { + log += strformat(F("_%d_"), *it); + } + } + if (state == ImprovTypes::ParseState::INVALID) { + log += F(" (invalid)"); + } + addLog(LOG_LEVEL_DEBUG, log); + } +#endif + + switch (state) { case ImprovTypes::ParseState::VALID_INCOMPLETE: _mustDumpBuffer = false; return true; diff --git a/src/src/Helpers/Modbus_RTU.cpp b/src/src/Helpers/Modbus_RTU.cpp index 96d63d7a77..159a3afab6 100644 --- a/src/src/Helpers/Modbus_RTU.cpp +++ b/src/src/Helpers/Modbus_RTU.cpp @@ -541,13 +541,10 @@ uint32_t ModbusRTU_struct::read_32b_HoldingRegister(short address) { } float ModbusRTU_struct::read_float_HoldingRegister(short address) { - union { - uint32_t ival; - float fval; - } conversion; - - conversion.ival = read_32b_HoldingRegister(address); - return conversion.fval; + const uint32_t ival = read_32b_HoldingRegister(address); + float fval{}; + memcpy(&fval, &ival, sizeof(ival)); + return fval; // uint32_t ival = read_32b_HoldingRegister(address); // float fval = *reinterpret_cast(&ival); diff --git a/src/src/Helpers/Rules_calculate.cpp b/src/src/Helpers/Rules_calculate.cpp index 1a93ecb76a..3e63a53ac4 100644 --- a/src/src/Helpers/Rules_calculate.cpp +++ b/src/src/Helpers/Rules_calculate.cpp @@ -651,10 +651,13 @@ String RulesCalculate_t::preProces(const String& input) for (size_t i = 0; i < nrOperators; ++i) { const UnaryOperator op = operators[i]; +#if FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES if (op == UnaryOperator::ArcSin && preprocessed.indexOf(F("sin")) == -1) i += 3; else if (op == UnaryOperator::ArcCos && preprocessed.indexOf(F("cos")) == -1) i += 3; else if (op == UnaryOperator::ArcTan && preprocessed.indexOf(F("tan")) == -1) i += 3; - else { + else +#endif + { preProcessReplace(preprocessed, op); } } diff --git a/src/src/Helpers/Scheduler_decodeTimer.cpp b/src/src/Helpers/Scheduler_decodeTimer.cpp index 2582ec73b8..805b4d2710 100644 --- a/src/src/Helpers/Scheduler_decodeTimer.cpp +++ b/src/src/Helpers/Scheduler_decodeTimer.cpp @@ -62,6 +62,6 @@ String ESPEasy_Scheduler::decodeSchedulerId(SchedulerTimerID timerID) { #endif // ifndef BUILD_NO_DEBUG result += F(" timer, id: "); - result += timerID.id; + result += timerID.getId(); return result; } diff --git a/src/src/Helpers/SerialWriteBuffer.cpp b/src/src/Helpers/SerialWriteBuffer.cpp index ca4364f971..750a6c4bb4 100644 --- a/src/src/Helpers/SerialWriteBuffer.cpp +++ b/src/src/Helpers/SerialWriteBuffer.cpp @@ -57,11 +57,6 @@ void SerialWriteBuffer_t::clear() _buffer.clear(); } -int SerialWriteBuffer_t::availableForWrite() const -{ - return _buffer.size(); -} - size_t SerialWriteBuffer_t::write(Stream& stream, size_t nrBytesToWrite) { size_t bytesWritten = 0; @@ -77,14 +72,43 @@ size_t SerialWriteBuffer_t::write(Stream& stream, size_t nrBytesToWrite) } while (nrBytesToWrite > 0 && !_buffer.empty()) { - const char c = _buffer.front(); + uint8_t tmpBuffer[16]{}; + + size_t tmpBufferUsed = 0; + + auto it = _buffer.begin(); + + bool done = false; + + for (; tmpBufferUsed < sizeof(tmpBuffer) && + !done && + it != _buffer.end();) { + tmpBuffer[tmpBufferUsed] = (uint8_t)(*it); + + if ((*it == '\n') || + (tmpBufferUsed >= nrBytesToWrite)) { + done = true; + } + ++tmpBufferUsed; + ++it; + } + + // done = false; + const size_t written = (tmpBufferUsed == 0) ? 0 : stream.write(tmpBuffer, tmpBufferUsed); + + if (written < tmpBufferUsed) { + done = true; + } + + for (size_t i = 0; i < written; ++i) { + _buffer.pop_front(); + --nrBytesToWrite; + ++bytesWritten; + } - if (stream.write((uint8_t)c) == 0) { + if (done) { return bytesWritten; } - _buffer.pop_front(); - --nrBytesToWrite; - ++bytesWritten; } } return bytesWritten; diff --git a/src/src/Helpers/SerialWriteBuffer.h b/src/src/Helpers/SerialWriteBuffer.h index f2bd1ed33e..7e5932df4f 100644 --- a/src/src/Helpers/SerialWriteBuffer.h +++ b/src/src/Helpers/SerialWriteBuffer.h @@ -28,9 +28,6 @@ class SerialWriteBuffer_t { void clear(); - - int availableForWrite() const; - size_t write(Stream& stream, size_t nrBytesToWrite); diff --git a/src/src/Helpers/StringParser.cpp b/src/src/Helpers/StringParser.cpp index 55c83b9df6..d1ca5bc60c 100644 --- a/src/src/Helpers/StringParser.cpp +++ b/src/src/Helpers/StringParser.cpp @@ -625,7 +625,10 @@ taskIndex_t findTaskIndexByName(String deviceName, bool allowDisabled) // Use entered taskDeviceName can have any case, so compare case insensitive. if (deviceName.equalsIgnoreCase(taskDeviceName)) { - Cache.taskIndexName[deviceName] = taskIndex; + Cache.taskIndexName.emplace( + std::make_pair( + std::move(deviceName), + taskIndex)); return taskIndex; } } @@ -668,7 +671,10 @@ uint8_t findDeviceValueIndexByName(const String& valueName, taskIndex_t taskInde // Check case insensitive, since the user entered value name can have any case. if (valueName.equalsIgnoreCase(getTaskValueName(taskIndex, valueNr))) { - Cache.taskIndexValueName[cache_valueName] = valueNr; + Cache.taskIndexValueName.emplace( + std::make_pair( + std::move(cache_valueName), + valueNr)); return valueNr; } } diff --git a/src/src/Helpers/WiFi_AP_CandidatesList.cpp b/src/src/Helpers/WiFi_AP_CandidatesList.cpp index 6deadfce4d..7627d0f5b9 100644 --- a/src/src/Helpers/WiFi_AP_CandidatesList.cpp +++ b/src/src/Helpers/WiFi_AP_CandidatesList.cpp @@ -62,9 +62,9 @@ void WiFi_AP_CandidatesList::load_knownCredentials() { known.emplace_back(index, ssid); if (SettingsIndexMatchCustomCredentials(index)) { if (SettingsIndexMatchEmergencyFallback(index)) { - known.back().isEmergencyFallback = true; + known.back().bits.isEmergencyFallback = true; } else { - known.back().lowPriority = true; + known.back().bits.lowPriority = true; } } ++index; @@ -155,7 +155,7 @@ bool WiFi_AP_CandidatesList::getNext(bool scanAllowed) { currentCandidate = candidates.front(); bool mustPop = true; - if (currentCandidate.isHidden) { + if (currentCandidate.bits.isHidden) { // Iterate over the known credentials to try them all // Hidden SSID stations do not broadcast their SSID, so we must fill it in ourselves. if (known_it != known.end()) { @@ -171,9 +171,9 @@ bool WiFi_AP_CandidatesList::getNext(bool scanAllowed) { if (mustPop) { if (attemptsLeft == 0) { - if (currentCandidate.isHidden) { + if (currentCandidate.bits.isHidden) { // We tried to connect to hidden SSIDs in 1 run, so pop all hidden candidates. - for (auto cand_it = candidates.begin(); cand_it != candidates.end() && cand_it->isHidden; ) { + for (auto cand_it = candidates.begin(); cand_it != candidates.end() && cand_it->bits.isHidden; ) { cand_it = candidates.erase(cand_it); } } else { @@ -334,7 +334,7 @@ void WiFi_AP_CandidatesList::loadCandidatesFromScanned() { if (scan->expired()) { scan = scanned.erase(scan); } else { - if (scan->isHidden) { + if (scan->bits.isHidden) { if (Settings.IncludeHiddenSSID()) { if (SecuritySettings.hasWiFiCredentials()) { candidates.push_back(*scan); @@ -345,8 +345,8 @@ void WiFi_AP_CandidatesList::loadCandidatesFromScanned() { if (scan->ssid.equals(kn_it->ssid)) { WiFi_AP_Candidate tmp = *scan; tmp.index = kn_it->index; - tmp.lowPriority = kn_it->lowPriority; - tmp.isEmergencyFallback = kn_it->isEmergencyFallback; + tmp.bits.lowPriority = kn_it->bits.lowPriority; + tmp.bits.isEmergencyFallback = kn_it->bits.isEmergencyFallback; if (tmp.usable()) { candidates.push_back(tmp); diff --git a/src/src/Helpers/_Plugin_SensorTypeHelper.cpp b/src/src/Helpers/_Plugin_SensorTypeHelper.cpp index c42b7eddac..d51c4dd4b6 100644 --- a/src/src/Helpers/_Plugin_SensorTypeHelper.cpp +++ b/src/src/Helpers/_Plugin_SensorTypeHelper.cpp @@ -10,7 +10,7 @@ -void sensorTypeHelper_webformLoad_allTypes(struct EventStruct *event, uint8_t pconfigIndex) +void sensorTypeHelper_webformLoad_allTypes(struct EventStruct *event, int pconfigIndex) { const uint8_t optionValues[] { static_cast(Sensor_VType::SENSOR_TYPE_SINGLE), @@ -48,7 +48,7 @@ void sensorTypeHelper_webformLoad_allTypes(struct EventStruct *event, uint8_t pc sensorTypeHelper_webformLoad(event, pconfigIndex, optionCount, optionValues); } -void sensorTypeHelper_webformLoad_simple(struct EventStruct *event, uint8_t pconfigIndex) +void sensorTypeHelper_webformLoad_simple(struct EventStruct *event, int pconfigIndex) { const uint8_t optionValues[] { static_cast(Sensor_VType::SENSOR_TYPE_SINGLE), @@ -61,29 +61,31 @@ void sensorTypeHelper_webformLoad_simple(struct EventStruct *event, uint8_t pcon sensorTypeHelper_webformLoad(event, pconfigIndex, optionCount, optionValues); } -void sensorTypeHelper_webformLoad(struct EventStruct *event, uint8_t pconfigIndex, int optionCount, const uint8_t options[]) +void sensorTypeHelper_webformLoad(struct EventStruct *event, int pconfigIndex, int optionCount, const uint8_t options[]) { addFormSubHeader(F("Output Configuration")); - if (pconfigIndex >= PLUGIN_CONFIGVAR_MAX) { + if (pconfigIndex < 0 || pconfigIndex >= PLUGIN_CONFIGVAR_MAX) { return; } Sensor_VType choice = static_cast(PCONFIG(pconfigIndex)); const deviceIndex_t DeviceIndex = getDeviceIndex_from_TaskIndex(event->TaskIndex); if (!validDeviceIndex(DeviceIndex)) { + // FIXME TD-er: Should we even continue here? choice = Sensor_VType::SENSOR_TYPE_NONE; PCONFIG(pconfigIndex) = static_cast(choice); } else if (getValueCountFromSensorType(choice) != getValueCountForTask(event->TaskIndex)) { // Invalid value - checkDeviceVTypeForTask(event); - choice = event->sensorType; - PCONFIG(pconfigIndex) = static_cast(choice); + if (checkDeviceVTypeForTask(event) >= 0) { + choice = event->sensorType; + PCONFIG(pconfigIndex) = static_cast(choice); + } } const __FlashStringHelper *outputTypeLabel = F("Output Data Type"); - if (Device[DeviceIndex].OutputDataType == Output_Data_type_t::Simple) { + if (validDeviceIndex(DeviceIndex) && Device[DeviceIndex].OutputDataType == Output_Data_type_t::Simple) { if (!isSimpleOutputDataType(event->sensorType)) { choice = Device[DeviceIndex].VType; @@ -92,7 +94,7 @@ void sensorTypeHelper_webformLoad(struct EventStruct *event, uint8_t pconfigInde outputTypeLabel = F("Number Output Values"); } addRowLabel(outputTypeLabel); - addSelector_Head(PCONFIG_LABEL(pconfigIndex)); + addSelector_Head(sensorTypeHelper_webformID(pconfigIndex)); for (uint8_t x = 0; x < optionCount; x++) { @@ -114,7 +116,7 @@ void sensorTypeHelper_webformLoad(struct EventStruct *event, uint8_t pconfigInde PluginCall(PLUGIN_WEBFORM_LOAD_OUTPUT_SELECTOR, event, dummy); } -void sensorTypeHelper_saveOutputSelector(struct EventStruct *event, uint8_t pconfigIndex, uint8_t valueIndex, const String& defaultValueName) +void sensorTypeHelper_saveOutputSelector(struct EventStruct *event, int pconfigIndex, uint8_t valueIndex, const String& defaultValueName) { const bool isDefault = defaultValueName.equals(ExtraTaskSettings.TaskDeviceValueNames[valueIndex]); if (isDefault) { @@ -124,18 +126,26 @@ void sensorTypeHelper_saveOutputSelector(struct EventStruct *event, uint8_t pcon pconfig_webformSave(event, pconfigIndex); } -void pconfig_webformSave(struct EventStruct *event, uint8_t pconfigIndex) +void pconfig_webformSave(struct EventStruct *event, int pconfigIndex) { - PCONFIG(pconfigIndex) = getFormItemInt(PCONFIG_LABEL(pconfigIndex), PCONFIG(pconfigIndex)); + if (pconfigIndex < 0 || pconfigIndex >= PLUGIN_CONFIGVAR_MAX) { + return; + } + + PCONFIG(pconfigIndex) = getFormItemInt(sensorTypeHelper_webformID(pconfigIndex), PCONFIG(pconfigIndex)); } void sensorTypeHelper_loadOutputSelector( - struct EventStruct *event, uint8_t pconfigIndex, uint8_t valuenr, + struct EventStruct *event, int pconfigIndex, uint8_t valuenr, int optionCount, const __FlashStringHelper *options[], const int indices[]) { + if (pconfigIndex < 0 || pconfigIndex >= PLUGIN_CONFIGVAR_MAX) { + return; + } + addFormSelector( concat(F("Value "), valuenr + 1), - PCONFIG_LABEL(pconfigIndex), + sensorTypeHelper_webformID(pconfigIndex), optionCount, options, indices, @@ -143,14 +153,26 @@ void sensorTypeHelper_loadOutputSelector( } void sensorTypeHelper_loadOutputSelector( - struct EventStruct *event, uint8_t pconfigIndex, uint8_t valuenr, + struct EventStruct *event, int pconfigIndex, uint8_t valuenr, int optionCount, const String options[], const int indices[]) { + if (pconfigIndex < 0 || pconfigIndex >= PLUGIN_CONFIGVAR_MAX) { + return; + } + addFormSelector( concat(F("Value "), valuenr + 1), - PCONFIG_LABEL(pconfigIndex), + sensorTypeHelper_webformID(pconfigIndex), optionCount, options, indices, PCONFIG(pconfigIndex)); } + +String sensorTypeHelper_webformID(int pconfigIndex) +{ + if (pconfigIndex >= 0 && pconfigIndex < PLUGIN_CONFIGVAR_MAX) { + return concat(F("pconfigIndex_"), pconfigIndex); + } + return F("error"); +} \ No newline at end of file diff --git a/src/src/Helpers/_Plugin_SensorTypeHelper.h b/src/src/Helpers/_Plugin_SensorTypeHelper.h index 165322c262..262d42fe32 100644 --- a/src/src/Helpers/_Plugin_SensorTypeHelper.h +++ b/src/src/Helpers/_Plugin_SensorTypeHelper.h @@ -5,23 +5,24 @@ #include "../DataStructs/DeviceStruct.h" -void sensorTypeHelper_webformLoad_allTypes(struct EventStruct *event, uint8_t pconfigIndex); +void sensorTypeHelper_webformLoad_allTypes(struct EventStruct *event, int pconfigIndex); -void sensorTypeHelper_webformLoad_simple(struct EventStruct *event, uint8_t pconfigIndex); +void sensorTypeHelper_webformLoad_simple(struct EventStruct *event, int pconfigIndex); -void sensorTypeHelper_webformLoad(struct EventStruct *event, uint8_t pconfigIndex, int optionCount, const uint8_t options[]); +void sensorTypeHelper_webformLoad(struct EventStruct *event, int pconfigIndex, int optionCount, const uint8_t options[]); -void sensorTypeHelper_saveOutputSelector(struct EventStruct *event, uint8_t pconfigIndex, uint8_t valueIndex, const String& defaultValueName); +void sensorTypeHelper_saveOutputSelector(struct EventStruct *event, int pconfigIndex, uint8_t valueIndex, const String& defaultValueName); -void pconfig_webformSave(struct EventStruct *event, uint8_t pconfigIndex); +void pconfig_webformSave(struct EventStruct *event, int pconfigIndex); void sensorTypeHelper_loadOutputSelector( - struct EventStruct *event, uint8_t pconfigIndex, uint8_t valuenr, + struct EventStruct *event, int pconfigIndex, uint8_t valuenr, int optionCount, const __FlashStringHelper * options[], const int indices[] = nullptr); void sensorTypeHelper_loadOutputSelector( - struct EventStruct *event, uint8_t pconfigIndex, uint8_t valuenr, + struct EventStruct *event, int pconfigIndex, uint8_t valuenr, int optionCount, const String options[], const int indices[] = nullptr); +String sensorTypeHelper_webformID(int pconfigIndex); #endif // HELPER_CPLUGIN_SENSORTYPEHELPER_H \ No newline at end of file diff --git a/src/src/PluginStructs/P014_data_struct.cpp b/src/src/PluginStructs/P014_data_struct.cpp index 084ebf8653..b1eaa53c39 100644 --- a/src/src/PluginStructs/P014_data_struct.cpp +++ b/src/src/PluginStructs/P014_data_struct.cpp @@ -424,7 +424,7 @@ bool P014_data_struct::enablePowerForADC(uint8_t i2caddr){ if (i2caddr == SI7013_I2C_ADDRESS_AD0_1){ - ok = I2C_write8_reg(i2caddr,SI7013_WRITE_REG2, (reg & B11111000) | (2+4+64) );//set last three bits (VIN bufered, Vref=VDD, VOUT=GND) and No-Hold for bit 6 + ok = I2C_write8_reg(i2caddr,SI7013_WRITE_REG2, (reg & 0b11111000) | (2+4+64) );//set last three bits (VIN bufered, Vref=VDD, VOUT=GND) and No-Hold for bit 6 }else{ ok = I2C_write8_reg(i2caddr,SI7013_WRITE_REG2,reg | (1+2+4+64) );//set last three bits to 1 (VIN bufered, Vref=VDD, VOUT=VDD) and No-Hold for bit 6 } @@ -455,7 +455,7 @@ bool P014_data_struct::disablePowerForADC(uint8_t i2caddr){ if (i2caddr == SI7013_I2C_ADDRESS_AD0_1){ ok = I2C_write8_reg(i2caddr,SI7013_WRITE_REG2,reg | (1+2+4+64) );//set last three bits to 1 (VIN bufered, Vref=VDD, VOUT=VDD) and No-Hold for bit 6 }else{ - ok = I2C_write8_reg(i2caddr,SI7013_WRITE_REG2, (reg & B11111000) | (2+4+64) );//set last three bits (VIN bufered, Vref=VDD, VOUT=GND) and No-Hold for bit 6 + ok = I2C_write8_reg(i2caddr,SI7013_WRITE_REG2, (reg & 0b11111000) | (2+4+64) );//set last three bits (VIN bufered, Vref=VDD, VOUT=GND) and No-Hold for bit 6 } if (!ok){ addLog(LOG_LEVEL_ERROR, F("SI7013: Could not write REG2!")); diff --git a/src/src/PluginStructs/P014_data_struct.h b/src/src/PluginStructs/P014_data_struct.h index ddb2971fc5..19b426755d 100644 --- a/src/src/PluginStructs/P014_data_struct.h +++ b/src/src/PluginStructs/P014_data_struct.h @@ -18,7 +18,7 @@ # define SI70xx_RESOLUTION_13T_10RH 0x80 // 10 bits RH / 13 bits Temp # define SI70xx_RESOLUTION_12T_08RH 0x01 // 8 bits RH / 12 bits Temp # define SI70xx_RESOLUTION_11T_11RH 0x81 // 11 bits RH / 11 bits Temp -# define SI70xx_RESOLUTION_MASK B01111110 +# define SI70xx_RESOLUTION_MASK 0b01111110 @@ -40,7 +40,7 @@ #define SI7013_READ_ADC 0xEE #define SI7013_READ_REG2 0x10 #define SI7013_WRITE_REG2 0x50 -#define SI7013_REG2_DEFAULT B01000110 // (MeasureMode=10) No-Hold master with no thermistor correction ; 7ms conversion; (VIN bufered, Vref=VDD, VOUT=GND) +#define SI7013_REG2_DEFAULT 0b01000110 // (MeasureMode=10) No-Hold master with no thermistor correction ; 7ms conversion; (VIN bufered, Vref=VDD, VOUT=GND) #define SI70xx_CMD_ID1 0xFA0F /**< Read Electronic ID SNA Bytes */ #define SI70xx_CMD_ID2 0xFCC9 /**< Read Electronic ID SNB Bytes */ diff --git a/src/src/PluginStructs/P022_data_struct.cpp b/src/src/PluginStructs/P022_data_struct.cpp index e0359870f9..d4c4295736 100644 --- a/src/src/PluginStructs/P022_data_struct.cpp +++ b/src/src/PluginStructs/P022_data_struct.cpp @@ -107,7 +107,7 @@ void P022_data_struct::Plugin_022_initialize(int address) // default mode is open drain output, drive leds connected to VCC Plugin_022_writeRegister(i2cAddress, PLUGIN_022_PCA9685_MODE1, (uint8_t)0x01); // reset the device delay(1); - Plugin_022_writeRegister(i2cAddress, PLUGIN_022_PCA9685_MODE1, (uint8_t)B10100000); // set up for auto increment + Plugin_022_writeRegister(i2cAddress, PLUGIN_022_PCA9685_MODE1, (uint8_t)0b10100000); // set up for auto increment // Plugin_022_writeRegister(i2cAddress, PCA9685_MODE2, (uint8_t)0x10); // set to output p022_set_init(address); } diff --git a/src/src/PluginStructs/P025_data_struct.cpp b/src/src/PluginStructs/P025_data_struct.cpp index 4f68ba8836..b58a0a5e07 100644 --- a/src/src/PluginStructs/P025_data_struct.cpp +++ b/src/src/PluginStructs/P025_data_struct.cpp @@ -9,6 +9,16 @@ # define P025_CONFIG_REGISTER 0x01 +P025_VARIOUS_BITS_t::P025_VARIOUS_BITS_t(int16_t value) { + memcpy(this, &value, sizeof(int16_t)); +} + +int16_t P025_VARIOUS_BITS_t::pconfigvalue() const { + int16_t value{}; + memcpy(&value, this, sizeof(int16_t)); + return value; +} + const __FlashStringHelper* Plugin_025_valuename(uint8_t value_nr, bool displayString) { const __FlashStringHelper *strings[] { F("AIN0 - AIN1 (Differential)"), F("AIN0_1"), @@ -36,7 +46,7 @@ const __FlashStringHelper* toString(P025_sensorType sensorType) F("ADS1015") : F("ADS1115"); } -union P025_config_register { +struct P025_config_register { struct { uint16_t comp_que : 2; uint16_t comp_lat : 1; @@ -48,14 +58,24 @@ union P025_config_register { uint16_t MUX : 3; uint16_t operatingStatus : 1; }; - uint16_t _regval = 0x8000; + P025_config_register(uint16_t regval) { + memcpy(this, ®val, sizeof(uint16_t)); + } + + void setRegval(uint16_t regval) { + memcpy(this, ®val, sizeof(uint16_t)); + } - P025_config_register(uint16_t regval) : _regval(regval) {} + uint16_t getRegval() const { + uint16_t regval{}; + memcpy(®val, this, sizeof(uint16_t)); + return regval; + } String toString() const { return strformat(F("reg: %X OS: %d MUX: %d PGA: %d mode: %d DR: %d"), - _regval, operatingStatus, MUX, PGA, mode, datarate + getRegval(), operatingStatus, MUX, PGA, mode, datarate ); } }; @@ -78,7 +98,7 @@ P025_data_struct::P025_data_struct(struct EventStruct *event) { reg.datarate = p025_variousBits.getSampleRate(); reg.PGA = P025_GAIN; - _configRegisterValue = reg._regval; + _configRegisterValue = reg.getRegval(); _fullScaleFactor = 1.0f; @@ -105,11 +125,11 @@ bool P025_data_struct::read(float& value, taskVarIndex_t index) const { reg.MUX = _mux[index]; - if (!startMeasurement(_i2cAddress, reg._regval)) { + if (!startMeasurement(_i2cAddress, reg.getRegval())) { return false; } - if (!I2C_write16_reg(_i2cAddress, P025_CONFIG_REGISTER, reg._regval)) { + if (!I2C_write16_reg(_i2cAddress, P025_CONFIG_REGISTER, reg.getRegval())) { # ifndef BUILD_NO_DEBUG if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { @@ -261,7 +281,7 @@ long P025_data_struct::waitReady025(uint8_t i2cAddress) delay(0); // Address Pointer Register is the same, so only need to read bytes again - reg._regval = I2C_read16(i2cAddress, &is_ok); + reg.setRegval(I2C_read16(i2cAddress, &is_ok)); } # ifndef BUILD_NO_DEBUG @@ -366,7 +386,7 @@ bool P025_data_struct::webformSave(struct EventStruct *event) p025_variousBits.setSampleRate(getFormItemInt(F("sps"))); p025_variousBits.outputVolt = isFormItemChecked(F("volt")); p025_variousBits.cal = isFormItemChecked(F("cal")); - P025_VARIOUS_BITS = p025_variousBits.pconfigvalue; + P025_VARIOUS_BITS = p025_variousBits.pconfigvalue(); P025_CAL_ADC1 = getFormItemInt(F("adc1")); P025_CAL_OUT1 = getFormItemFloat(F("out1")); diff --git a/src/src/PluginStructs/P025_data_struct.h b/src/src/PluginStructs/P025_data_struct.h index 85c2780cdc..6730a0ff59 100644 --- a/src/src/PluginStructs/P025_data_struct.h +++ b/src/src/PluginStructs/P025_data_struct.h @@ -5,7 +5,7 @@ #ifdef USES_P025 -union P025_VARIOUS_BITS_t { +struct P025_VARIOUS_BITS_t { struct { uint16_t cal : 1; uint16_t outputVolt : 1; @@ -13,9 +13,10 @@ union P025_VARIOUS_BITS_t { uint16_t sampleRate : 3; uint16_t unused : 10; }; - int16_t pconfigvalue{}; - P025_VARIOUS_BITS_t(int16_t value) : pconfigvalue(value) {} + P025_VARIOUS_BITS_t(int16_t value); + + int16_t pconfigvalue() const; uint16_t getSampleRate() const { if (sampleRateSet) { return sampleRate; } diff --git a/src/src/PluginStructs/P027_data_struct.cpp b/src/src/PluginStructs/P027_data_struct.cpp index 4e61bf196b..07f9370090 100644 --- a/src/src/PluginStructs/P027_data_struct.cpp +++ b/src/src/PluginStructs/P027_data_struct.cpp @@ -112,6 +112,25 @@ void P027_data_struct::setCalibration_16V_400mA() { wireWriteRegister(INA219_REG_CONFIG, config); } +void P027_data_struct::setCalibration_26V_8A() { + calValue = 4096; + + // Set multipliers to convert raw current/power values + currentDivider_mA = 1; + + // Set Calibration register to 'Cal' calculated above + wireWriteRegister(INA219_REG_CALIBRATION, calValue); + + // Set Config register to take into account the settings above + uint16_t config = INA219_CONFIG_BVOLTAGERANGE_32V | + INA219_CONFIG_GAIN_8_320MV | + INA219_CONFIG_BADCRES_12BIT | + INA219_CONFIG_SADCRES_12BIT_128S_69MS | + INA219_CONFIG_MODE_SANDBVOLT_CONTINUOUS; + + wireWriteRegister(INA219_REG_CONFIG, config); +} + int16_t P027_data_struct::getBusVoltage_raw() { uint16_t value; diff --git a/src/src/PluginStructs/P027_data_struct.h b/src/src/PluginStructs/P027_data_struct.h index adf514773f..c00d5f977f 100644 --- a/src/src/PluginStructs/P027_data_struct.h +++ b/src/src/PluginStructs/P027_data_struct.h @@ -30,6 +30,11 @@ struct P027_data_struct : public PluginTaskData_base { // **************************************************************************/ void setCalibration_16V_400mA(); + // **************************************************************************/ + // Configures to INA219 to be able to measure up to 26V and 8A + // **************************************************************************/ + void setCalibration_26V_8A(); + private: // **************************************************************************/ diff --git a/src/src/PluginStructs/P031_data_struct.h b/src/src/PluginStructs/P031_data_struct.h index ab78b665ea..4a1e2c1217 100644 --- a/src/src/PluginStructs/P031_data_struct.h +++ b/src/src/PluginStructs/P031_data_struct.h @@ -23,10 +23,10 @@ class P031_data_struct : public PluginTaskData_base { public: enum { - SHT1X_CMD_MEASURE_TEMP = B00000011, - SHT1X_CMD_MEASURE_RH = B00000101, - SHT1X_CMD_READ_STATUS = B00000111, - SHT1X_CMD_SOFT_RESET = B00011110 + SHT1X_CMD_MEASURE_TEMP = 0b00000011, + SHT1X_CMD_MEASURE_RH = 0b00000101, + SHT1X_CMD_READ_STATUS = 0b00000111, + SHT1X_CMD_SOFT_RESET = 0b00011110 }; P031_data_struct() = default; diff --git a/src/src/PluginStructs/P036_data_struct.cpp b/src/src/PluginStructs/P036_data_struct.cpp index 483501fb91..431adef6d8 100644 --- a/src/src/PluginStructs/P036_data_struct.cpp +++ b/src/src/PluginStructs/P036_data_struct.cpp @@ -146,7 +146,7 @@ const __FlashStringHelper * tFontSettings::FontName() const { // This is very precious memory, so we must find something other way to define this. /* *INDENT-OFF* */ -const tFontSizes FontSizes[P36_MaxFontCount] = { +const tFontSizes FontSizes[] = { { getArialMT_Plain_24(), 24, 28 }, // 9643 # ifndef P036_LIMIT_BUILD_SIZE { getDialog_plain_18(), 19, 22 }, // 7399 @@ -159,7 +159,7 @@ const tFontSizes FontSizes[P36_MaxFontCount] = { }; /* *INDENT-ON* */ -constexpr tSizeSettings SizeSettings[P36_MaxSizesCount] = { +constexpr tSizeSettings SizeSettings[] = { { P36_MaxDisplayWidth, P36_MaxDisplayHeight, 0, // 128x64 4, // max. line count 113, 15 // WiFi indicator @@ -178,7 +178,7 @@ constexpr tSizeSettings SizeSettings[P36_MaxSizesCount] = { const tSizeSettings& P036_data_struct::getDisplaySizeSettings(p036_resolution disp_resolution) { int index = static_cast(disp_resolution); - if ((index < 0) || (index >= P36_MaxSizesCount)) { index = 0; } + if ((index < 0) || (index >= static_cast(NR_ELEMENTS(SizeSettings)))) { index = 0; } return SizeSettings[index]; } @@ -1019,7 +1019,7 @@ tIndividualFontSettings P036_data_struct::CalculateIndividualFontSettings(uint8_ for (uint8_t i = LineNo; i < P36_Nlines; ++i) { // calculate individual font settings - int8_t lFontIndex = FontIndex; + uint8_t lFontIndex = FontIndex; const eModifyFont iModifyFont = static_cast(get3BitFromUL(LineContent->DisplayLinesV1[i].ModifyLayout, P036_FLAG_ModifyLayout_Font)); @@ -1028,9 +1028,11 @@ tIndividualFontSettings P036_data_struct::CalculateIndividualFontSettings(uint8_ if (ScrollingPages.linesPerFrameDef > 1) { // Font can only be enlarged if more than 1 line is displayed - lFontIndex--; - - if (lFontIndex < IdxForBiggestFont) { lFontIndex = IdxForBiggestFont; } + if (lFontIndex > IdxForBiggestFont) { + lFontIndex--; + } else { + lFontIndex = IdxForBiggestFont; + } result.IdxForBiggestFontUsed = lFontIndex; } break; @@ -1045,12 +1047,12 @@ tIndividualFontSettings P036_data_struct::CalculateIndividualFontSettings(uint8_ case eModifyFont::eReduce: lFontIndex++; - if (lFontIndex > (P36_MaxFontCount - 1)) { - lFontIndex = P36_MaxFontCount - 1; + if (lFontIndex >= NR_ELEMENTS(FontSizes)) { + lFontIndex = NR_ELEMENTS(FontSizes) - 1; } break; case eModifyFont::eMinimize: - lFontIndex = P36_MaxFontCount - 1; + lFontIndex = NR_ELEMENTS(FontSizes) - 1; break; case eModifyFont::eNone: lFontIndex = FontIndex; @@ -1090,7 +1092,7 @@ tIndividualFontSettings P036_data_struct::CalculateIndividualFontSettings(uint8_ lSpace = -1; // allow overlapping by 1 pix if (deltaHeight < (-1 * (lLinesPerFrame - 1))) { - if ((result.IdxForBiggestFontUsed == (P36_MaxFontCount - 1)) && + if ((result.IdxForBiggestFontUsed == (NR_ELEMENTS(FontSizes) - 1)) && (LinesPerFrame == SizeSettings[static_cast(disp_resolution)].MaxLines)) { // max lines for used display and smallest font reached -> use special space between the lines and return 'fits' // overlapping (lSpace<0) depends on the absolute display height @@ -1187,7 +1189,7 @@ tFontSettings P036_data_struct::CalculateFontSettings(uint8_t lDefaultLines) { log1.reserve(80); # endif // ifdef P036_FONT_CALC_LOG - for (i = 0; i < P36_MaxFontCount - 1; ++i) { + for (i = 0; i < NR_ELEMENTS(FontSizes) - 1; ++i) { // check available fonts for the line setting # ifdef P036_FONT_CALC_LOG @@ -1246,7 +1248,7 @@ tFontSettings P036_data_struct::CalculateFontSettings(uint8_t lDefaultLines) { case p036_resolution::pix64x48: result.Space = -1; break; } - iFontIndex = P36_MaxFontCount - 1; + iFontIndex = NR_ELEMENTS(FontSizes) - 1; } if (lDefaultLines == 0) { diff --git a/src/src/PluginStructs/P036_data_struct.h b/src/src/PluginStructs/P036_data_struct.h index 800b128714..cb7091c9c6 100644 --- a/src/src/PluginStructs/P036_data_struct.h +++ b/src/src/PluginStructs/P036_data_struct.h @@ -85,12 +85,6 @@ # define P36_Nlines 12 // The number of different lines which can be displayed - each line is 64 chars max # define P36_NcharsV0 32 // max chars per line up to 22.11.2019 (V0) # define P36_NcharsV1 64 // max chars per line from 22.11.2019 (V1) -# define P36_MaxSizesCount 3 // number of different OLED sizes -# ifdef P036_LIMIT_BUILD_SIZE -# define P36_MaxFontCount 3 // number of different fonts -# else // ifdef P036_LIMIT_BUILD_SIZE -# define P36_MaxFontCount 5 // number of different fonts -# endif // ifdef P036_LIMIT_BUILD_SIZE # define P36_MaxDisplayWidth 128 # define P36_MaxDisplayHeight 64 diff --git a/src/src/PluginStructs/P073_data_struct.h b/src/src/PluginStructs/P073_data_struct.h index 065232dd9a..868e43da11 100644 --- a/src/src/PluginStructs/P073_data_struct.h +++ b/src/src/PluginStructs/P073_data_struct.h @@ -40,8 +40,8 @@ # undef P073_SUPPRESS_ZERO // Optionally activate if .bin file space is really problematic, to remove the Suppress leading zero feature # endif // ifndef PLUGIN_SET_COLLECTION -# define TM1637_POWER_ON B10001000 -# define TM1637_POWER_OFF B10000000 +# define TM1637_POWER_ON 0b10001000 +# define TM1637_POWER_OFF 0b10000000 # define TM1637_CLOCKDELAY 40 # define TM1637_4DIGIT 4 # define TM1637_6DIGIT 2 @@ -57,13 +57,13 @@ // - pos 15 - underscore "_" // - pos 16-41 - Letters from A to Z static const uint8_t DefaultCharTable[42] PROGMEM = { - B01111110, B00110000, B01101101, B01111001, B00110011, B01011011, - B01011111, B01110000, B01111111, B01111011, B00000000, B00000001, - B01100011, B00001001, B01001001, B00001000, B01110111, B00011111, - B01001110, B00111101, B01001111, B01000111, B01011110, B00110111, - B00000110, B00111100, B01010111, B00001110, B01010100, B01110110, - B01111110, B01100111, B01101011, B01100110, B01011011, B00001111, - B00111110, B00111110, B00101010, B00110111, B00111011, B01101101 }; + 0b01111110, 0b00110000, 0b01101101, 0b01111001, 0b00110011, 0b01011011, + 0b01011111, 0b01110000, 0b01111111, 0b01111011, 0b00000000, 0b00000001, + 0b01100011, 0b00001001, 0b01001001, 0b00001000, 0b01110111, 0b00011111, + 0b01001110, 0b00111101, 0b01001111, 0b01000111, 0b01011110, 0b00110111, + 0b00000110, 0b00111100, 0b01010111, 0b00001110, 0b01010100, 0b01110110, + 0b01111110, 0b01100111, 0b01101011, 0b01100110, 0b01011011, 0b00001111, + 0b00111110, 0b00111110, 0b00101010, 0b00110111, 0b00111011, 0b01101101 }; # ifdef P073_EXTRA_FONTS @@ -78,46 +78,46 @@ static const uint8_t DefaultCharTable[42] PROGMEM = { // - pos 14 - slash "/" // - pos 15 - underscore "_" // - pos 16-40 - Special characters not handled yet -- MAX7219 -- -- TM1637 -- -// - pos 16 - percent "%" B00010010 -// - pos 17 - at "@" B01110100 -// - pos 18 - period "." B00000100 -// - pos 10 - comma "," B00011000 -// - pos 20 - semicolon ";" B00101000 -// - pos 21 - colon ":" B01001000 -// - pos 22 - plus "+" B00110001 -// - pos 23 - asterisk "*" B01001001 -// - pos 24 - hash "#" B00110110 -// - pos 25 - exclamation mark "!" B01101011 -// - pos 26 - question mark "?" B01101001 -// - pos 27 - single quote "'" B00000010 -// - pos 28 - double quote '"' B00100010 -// - pos 29 - left sharp bracket "<" B01000010 -// - pos 30 - right sharp bracket ">" B01100000 -// - pos 31 - backslash "\" B00010011 -// - pos 32 - left round bracket "(" B01001110 -// - pos 33 - right round bracket ")" B01111000 -// - pos 34 - overscore "|" (the top-most line) B01000000 -// - pos 35 - uppercase C "C" (optionally enabled) B01001110 -// - pos 36 - uppercase H "H" B00110111 -// - pos 37 - uppercase N "N" B01110110 -// - pos 38 - uppercase O "O" B01111110 -// - pos 39 - uppercase R "R" B01100110 -// - pos 40 - uppercase U "U" B00111110 -// - pos 41 - uppercase X "X" B00110111 +// - pos 16 - percent "%" 0b00010010 +// - pos 17 - at "@" 0b01110100 +// - pos 18 - period "." 0b00000100 +// - pos 10 - comma "," 0b00011000 +// - pos 20 - semicolon ";" 0b00101000 +// - pos 21 - colon ":" 0b01001000 +// - pos 22 - plus "+" 0b00110001 +// - pos 23 - asterisk "*" 0b01001001 +// - pos 24 - hash "#" 0b00110110 +// - pos 25 - exclamation mark "!" 0b01101011 +// - pos 26 - question mark "?" 0b01101001 +// - pos 27 - single quote "'" 0b00000010 +// - pos 28 - double quote '"' 0b00100010 +// - pos 29 - left sharp bracket "<" 0b01000010 +// - pos 30 - right sharp bracket ">" 0b01100000 +// - pos 31 - backslash "\" 0b00010011 +// - pos 32 - left round bracket "(" 0b01001110 +// - pos 33 - right round bracket ")" 0b01111000 +// - pos 34 - overscore "|" (the top-most line) 0b01000000 +// - pos 35 - uppercase C "C" (optionally enabled) 0b01001110 +// - pos 36 - uppercase H "H" 0b00110111 +// - pos 37 - uppercase N "N" 0b01110110 +// - pos 38 - uppercase O "O" 0b01111110 +// - pos 39 - uppercase R "R" 0b01100110 +// - pos 40 - uppercase U "U" 0b00111110 +// - pos 41 - uppercase X "X" 0b00110111 // - pos 42-67 - Letters from A to Z Siekoo style static const uint8_t SiekooCharTable[68] PROGMEM = { - B01111110, B00110000, B01101101, B01111001, B00110011, B01011011, - B01011111, B01110000, B01111111, B01111011, B00000000, B00000001, - B01100011, B00001001, B00100101, B00001000, B00010010, B01110100, - B00000100, B00011000, B00101000, B01001000, B00110001, B01001001, - B00110110, B01101011, B01101001, B00000010, B00100010, B01000010, - B01100000, B00010011, B01001110, B01111000, B01000000, B01001110, - B00110111, B01110110, B01111110, B01100110, B00111110, B00110111, - B01111101, B00011111, B00001101, B00111101, B01001111, B01000111, /* ABCDEF */ - B01011110, B00010111, B01000100, B01011000, B01010111, B00001110, - B01010101, B00010101, B00011101, B01100111, B01110011, B00000101, - B01011010, B00001111, B00011100, B00101010, B00101011, B00010100, - B00111011, B01101100 }; + 0b01111110, 0b00110000, 0b01101101, 0b01111001, 0b00110011, 0b01011011, + 0b01011111, 0b01110000, 0b01111111, 0b01111011, 0b00000000, 0b00000001, + 0b01100011, 0b00001001, 0b00100101, 0b00001000, 0b00010010, 0b01110100, + 0b00000100, 0b00011000, 0b00101000, 0b01001000, 0b00110001, 0b01001001, + 0b00110110, 0b01101011, 0b01101001, 0b00000010, 0b00100010, 0b01000010, + 0b01100000, 0b00010011, 0b01001110, 0b01111000, 0b01000000, 0b01001110, + 0b00110111, 0b01110110, 0b01111110, 0b01100110, 0b00111110, 0b00110111, + 0b01111101, 0b00011111, 0b00001101, 0b00111101, 0b01001111, 0b01000111, /* ABCDEF */ + 0b01011110, 0b00010111, 0b01000100, 0b01011000, 0b01010111, 0b00001110, + 0b01010101, 0b00010101, 0b00011101, 0b01100111, 0b01110011, 0b00000101, + 0b01011010, 0b00001111, 0b00011100, 0b00101010, 0b00101011, 0b00010100, + 0b00111011, 0b01101100 }; // dSEG7 https://www.keshikan.net/fonts-e.html // specials: @@ -130,13 +130,13 @@ static const uint8_t SiekooCharTable[68] PROGMEM = { // - pos 15 - underscore "_" // - pos 16-41 - Letters from A to Z dSEG7 style static const uint8_t Dseg7CharTable[42] PROGMEM = { - B01111110, B00110000, B01101101, B01111001, B00110011, B01011011, - B01011111, B01110000, B01111111, B01111011, B00000000, B00000001, - B01100011, B00001001, B01001001, B00001000, B01110111, B00011111, /* AB */ - B00001101, B00111101, B01001111, B01000111, B01011110, B00010111, - B00010000, B00111100, B01010111, B00001110, B01110110, B00010101, - B00011101, B01100111, B01110011, B00000101, B00011011, B00001111, - B00011100, B00111110, B00111111, B00110111, B00111011, B01101100 }; + 0b01111110, 0b00110000, 0b01101101, 0b01111001, 0b00110011, 0b01011011, + 0b01011111, 0b01110000, 0b01111111, 0b01111011, 0b00000000, 0b00000001, + 0b01100011, 0b00001001, 0b01001001, 0b00001000, 0b01110111, 0b00011111, /* AB */ + 0b00001101, 0b00111101, 0b01001111, 0b01000111, 0b01011110, 0b00010111, + 0b00010000, 0b00111100, 0b01010111, 0b00001110, 0b01110110, 0b00010101, + 0b00011101, 0b01100111, 0b01110011, 0b00000101, 0b00011011, 0b00001111, + 0b00011100, 0b00111110, 0b00111111, 0b00110111, 0b00111011, 0b01101100 }; # endif // P073_EXTRA_FONTS diff --git a/src/src/PluginStructs/P078_data_struct.cpp b/src/src/PluginStructs/P078_data_struct.cpp index f4a50c5ebc..11478262e1 100644 --- a/src/src/PluginStructs/P078_data_struct.cpp +++ b/src/src/PluginStructs/P078_data_struct.cpp @@ -211,7 +211,7 @@ void SDM_loadOutputSelector(struct EventStruct *event, uint8_t pconfigIndex, uin { const SDM_MODEL model = static_cast(P078_MODEL); const String label = concat(F("Value "), valuenr + 1); - const String id = PCONFIG_LABEL(pconfigIndex); + const String id = sensorTypeHelper_webformID(pconfigIndex); addRowLabel_tr_id(label, id); do_addSelector_Head(id, F("wide"), EMPTY_STRING, false); diff --git a/src/src/PluginStructs/P087_data_struct.cpp b/src/src/PluginStructs/P087_data_struct.cpp index fad12222c2..76228036ce 100644 --- a/src/src/PluginStructs/P087_data_struct.cpp +++ b/src/src/PluginStructs/P087_data_struct.cpp @@ -13,17 +13,13 @@ P087_data_struct::~P087_data_struct() { - if (easySerial != nullptr) { - delete easySerial; - easySerial = nullptr; - } + delete easySerial; + easySerial = nullptr; } void P087_data_struct::reset() { - if (easySerial != nullptr) { - delete easySerial; - easySerial = nullptr; - } + delete easySerial; + easySerial = nullptr; } bool P087_data_struct::init(ESPEasySerialPort port, const int16_t serial_rx, const int16_t serial_tx, unsigned long baudrate, @@ -62,10 +58,7 @@ void P087_data_struct::post_init() { // Index is negative when not used. if ((index >= 0) && (index < P87_MAX_CAPTURE_INDEX) && (_lines[i * 3 + P087_FIRST_FILTER_POS + 2].length() > 0)) { # ifndef BUILD_NO_DEBUG - log += ' '; - log += String(i); - log += ':'; - log += String(index); + log += strformat(F(" %d:%d"), i, index); # endif // ifndef BUILD_NO_DEBUG capture_index[i] = index; capture_index_used[index] = true; @@ -86,9 +79,7 @@ void P087_data_struct::sendString(const String& data) { easySerial->write(data.c_str()); if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F("Proxy: Sending: "); - log += data; - addLogMove(LOG_LEVEL_INFO, log); + addLogMove(LOG_LEVEL_INFO, concat(F("Proxy: Sending: "), data)); } } } @@ -99,10 +90,7 @@ void P087_data_struct::sendData(uint8_t *data, size_t size) { easySerial->write(data, size); if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F("Proxy: Sending "); - log += size; - log += F(" bytes."); - addLogMove(LOG_LEVEL_INFO, log); + addLogMove(LOG_LEVEL_INFO, strformat(F("Proxy: Sending %d bytes."), size)); } } } @@ -134,7 +122,7 @@ bool P087_data_struct::loop() { for (size_t i = 0; i < length && valid; ++i) { if ((sentence_part[i] > 127) || (sentence_part[i] < 32)) { - sentence_part = String(); + sentence_part = EMPTY_STRING; ++sentences_received_error; valid = false; } @@ -143,7 +131,7 @@ bool P087_data_struct::loop() { if (valid) { fullSentenceReceived = true; last_sentence = sentence_part; - sentence_part = String(); + sentence_part = EMPTY_STRING; } break; } @@ -173,7 +161,7 @@ bool P087_data_struct::getSentence(String& string) { if (string.isEmpty()) { return false; } - last_sentence = String(); + last_sentence = EMPTY_STRING; return true; } @@ -241,10 +229,10 @@ String P087_data_struct::getFilter(uint8_t lineNr, uint8_t& capture, P087_Filter { uint8_t varNr = lineNr * 3 + P087_FIRST_FILTER_POS; - if ((varNr + 3) > P87_Nlines) { return ""; } + if ((varNr + 3) > P87_Nlines) { return EMPTY_STRING; } capture = _lines[varNr++].toInt(); - comparator = _lines[varNr++] == "1" ? P087_Filter_Comp::NotEqual : P087_Filter_Comp::Equal; + comparator = equals(_lines[varNr++], '1') ? P087_Filter_Comp::NotEqual : P087_Filter_Comp::Equal; return _lines[varNr]; } @@ -295,7 +283,7 @@ bool P087_data_struct::matchRegexp(String& received) const { } - uint32_t regexp_match_length = getRegExpMatchLength(); + const uint32_t regexp_match_length = getRegExpMatchLength(); if ((regexp_match_length > 0) && (strlength > regexp_match_length)) { strlength = regexp_match_length; @@ -307,9 +295,10 @@ bool P087_data_struct::matchRegexp(String& received) const { bool match_result = false; + capture_vector.clear(); + ms.GlobalMatch(getRegEx().c_str(), match_callback); // To allow the matched values be retrieved also when not using Global Match option + if (globalMatch()) { - capture_vector.clear(); - ms.GlobalMatch(_lines[P087_REGEX_POS].c_str(), match_callback); const uint8_t vectorlength = capture_vector.size(); for (uint8_t i = 0; i < vectorlength; ++i) { @@ -320,13 +309,10 @@ bool P087_data_struct::matchRegexp(String& received) const { if ((capture_index[n] == capture_vector[i].first) && !(_lines[lines_index].isEmpty())) { String log; log.reserve(32); - log = F("P087: Index: "); - log += capture_vector[i].first; - log += F(" Found "); - log += capture_vector[i].second; + log = strformat(F("P087: Index: %d Found %s"), capture_vector[i].first, capture_vector[i].second.c_str()); // Found a Capture Filter with this capture index. - if (capture_vector[i].second == _lines[lines_index]) { + if (capture_vector[i].second.equals(_lines[lines_index])) { log += F(" Matches"); // Found a match. Now check if it is supposed to be one or not. @@ -342,10 +328,11 @@ bool P087_data_struct::matchRegexp(String& received) const { log += F(" No Match"); if (capture_index_must_not_match[n]) { - log += F(" (!=) "); + log += F(" (!=)"); } else { - log += F(" (==) "); + log += F(" (==)"); } + log += ' '; log += _lines[lines_index]; } addLogMove(LOG_LEVEL_INFO, log); @@ -353,19 +340,16 @@ bool P087_data_struct::matchRegexp(String& received) const { } } } - capture_vector.clear(); + + // capture_vector.clear(); // KEEP so we can use plugin_get_config_value to retrieve the values } else { - char result = ms.Match(_lines[P087_REGEX_POS].c_str()); + char result = ms.Match(getRegEx().c_str()); if (result == REGEXP_MATCHED) { # ifndef BUILD_NO_DEBUG if (loglevelActiveFor(LOG_LEVEL_DEBUG)) { - String log = F("Match at: "); - log += ms.MatchStart; - log += F(" Match Length: "); - log += ms.MatchLength; - addLogMove(LOG_LEVEL_DEBUG, log); + addLogMove(LOG_LEVEL_DEBUG, strformat(F("Match at: %d Match Length: %d"), ms.MatchStart, ms.MatchLength)); } # endif // ifndef BUILD_NO_DEBUG match_result = true; @@ -391,4 +375,62 @@ bool P087_data_struct::max_length_reached() const { return sentence_part.length() >= max_length; } +void P087_data_struct::setLastSentence(String string) { + last_sentence = string; +} + +bool P087_data_struct::plugin_get_config_value(struct EventStruct *event, + String & string) { + bool success = false; + const uint8_t vectorlength = capture_vector.size(); + const String cmd = parseString(string, 1); + + # ifndef BUILD_NO_DEBUG + addLog(LOG_LEVEL_DEBUG, concat(F("P087: Before GetConfig: "), string)); + # endif // ifndef BUILD_NO_DEBUG + + if (equals(cmd, F("group"))) { + int32_t par2; + + if (validIntFromString(parseString(string, 2), par2) && + (par2 >= 0)) { + for (uint8_t i = 0; i < vectorlength && !success; ++i) { // Stop when we find the requested group + # ifndef BUILD_NO_DEBUG + addLog(LOG_LEVEL_DEBUG, strformat(F("P087: get group: %d = %s"), + capture_vector[i].first, + capture_vector[i].second.c_str())); + # endif // ifndef BUILD_NO_DEBUG + + if (par2 == capture_vector[i].first) { + string = capture_vector[i].second; + success = true; + } + } + } + } else + if (equals(cmd, F("next"))) { // Get next group value after matching name + const String name_ = parseString(string, 2); + + for (uint8_t i = 0; i < (vectorlength - 1) && !success; ++i) { // Stop when we find the requested name + // Loops until 1 BEFORE the end of the vector! + # ifndef BUILD_NO_DEBUG + addLog(LOG_LEVEL_DEBUG, strformat(F("P087: get next: %d = %s => %s"), + capture_vector[i].first, + capture_vector[i].second.c_str(), + capture_vector[i + 1].second.c_str())); + # endif // ifndef BUILD_NO_DEBUG + + if (name_.equalsIgnoreCase(capture_vector[i].second)) { + string = capture_vector[i + 1].second; // Take NEXT value + success = true; + } + } + } // else... + # ifndef BUILD_NO_DEBUG + addLog(LOG_LEVEL_DEBUG, concat(F("P087: After GetConfig: "), string)); + # endif // ifndef BUILD_NO_DEBUG + + return success; +} + #endif // USES_P087 diff --git a/src/src/PluginStructs/P087_data_struct.h b/src/src/PluginStructs/P087_data_struct.h index a96eeed129..031e88a52b 100644 --- a/src/src/PluginStructs/P087_data_struct.h +++ b/src/src/PluginStructs/P087_data_struct.h @@ -67,6 +67,7 @@ struct P087_data_struct : public PluginTaskData_base { // Get the received sentence // @retval true when the string is not empty. bool getSentence(String& string); + void setLastSentence(String string); void getSentencesReceived(uint32_t& succes, uint32_t& error, @@ -110,6 +111,10 @@ struct P087_data_struct : public PluginTaskData_base { // Made public so we don't have to copy the values when loading/saving. String _lines[P87_Nlines]; + // Plugin handler functions: + bool plugin_get_config_value(struct EventStruct *event, + String & string); + private: bool max_length_reached() const; diff --git a/src/src/PluginStructs/P094_Filter.cpp b/src/src/PluginStructs/P094_Filter.cpp new file mode 100644 index 0000000000..1111cc1cea --- /dev/null +++ b/src/src/PluginStructs/P094_Filter.cpp @@ -0,0 +1,463 @@ +#include "../PluginStructs/P094_Filter.h" + +#ifdef USES_P094 + + +# include "../DataStructs/mBusPacket.h" + +# include "../Globals/ESPEasy_time.h" +# include "../Globals/TimeZone.h" +# include "../Helpers/ESPEasy_Storage.h" +# include "../Helpers/StringConverter.h" + + +// *INDENT-OFF* +# define P094_FILTER_WEBARG_LABEL(x) getPluginCustomArgName((x * 10) + 10) +# define P094_FILTER_WEBARG_MANUFACTURER(x) getPluginCustomArgName((x * 10) + 11) +# define P094_FILTER_WEBARG_METERTYPE(x) getPluginCustomArgName((x * 10) + 12) +# define P094_FILTER_WEBARG_SERIAL(x) getPluginCustomArgName((x * 10) + 13) +# define P094_FILTER_WEBARG_FILTER_WINDOW(x) getPluginCustomArgName((x * 10) + 14) +// *INDENT-ON* + +const char P094_Filter_Window_names[] PROGMEM = "none|all|1m|5m|15m|1h|day|month|once"; + +P094_Filter_Window get_FilterWindow(const String& str) +{ + char tmp[10]{}; + const int command_i = GetCommandCode(tmp, sizeof(tmp), str.c_str(), P094_Filter_Window_names); + + if (command_i == -1) { + // No match found + return P094_Filter_Window::None; + } + return static_cast(command_i); +} + +String Filter_WindowToString(P094_Filter_Window filterWindow) +{ + char tmp[10]{}; + String res(GetTextIndexed(tmp, sizeof(tmp), static_cast(filterWindow), P094_Filter_Window_names)); + + return res; +} + +P094_filter::P094_filter() { + _filter._manufacturer = mBus_packet_wildcard_manufacturer; + _filter._meterType = mBus_packet_wildcard_metertype; + _filter._serialNr = mBus_packet_wildcard_serial; + _filter._filterWindow = static_cast(P094_Filter_Window::None); +} + +void P094_filter::fromString(String str) +{ + // Set everything to wildcards + _filter._manufacturer = mBus_packet_wildcard_manufacturer; + _filter._meterType = mBus_packet_wildcard_metertype; + _filter._serialNr = mBus_packet_wildcard_serial; + _filter._filterWindow = static_cast(P094_Filter_Window::None); + + const int semicolonPos = str.indexOf(';'); + + if (semicolonPos != -1) { + _filter._filterWindow = static_cast(get_FilterWindow(str.substring(semicolonPos + 1))); + str = str.substring(0, semicolonPos); + } + + for (size_t i = 0; i < 3; ++i) { + String tmp; + + if (GetArgv(str.c_str(), tmp, (i + 1), '.')) { + if (!(tmp.isEmpty() || tmp.startsWith(F("*")))) { + if (i != 0) { + // Make sure the numerical values are parsed as HEX + if (!tmp.startsWith(F("0x")) && !tmp.startsWith(F("0X"))) { + tmp = concat(F("0x"), tmp); + } + } + + switch (i) { + case 0: // Manufacturer + _filter._manufacturer = mBusPacket_header_t::encodeManufacturerID(tmp); + break; + case 1: // Meter type + { + int32_t metertype = mBus_packet_wildcard_metertype; + + if (validIntFromString(tmp, metertype)) { + _filter._meterType = metertype; + } + break; + } + case 2: // Serial + { + int32_t serial = mBus_packet_wildcard_serial; + + if (validIntFromString(tmp, serial)) { + _filter._serialNr = serial; + } + break; + } + } + } + } + } +} + +String P094_filter::toString() const +{ + String res; + + res += getManufacturer(); + res += '.'; + + res += getMeterType(); + res += '.'; + + res += getSerial(); + res += ';'; + + res += Filter_WindowToString(getFilterWindow()); + + return res; +} + +const uint8_t * P094_filter::toBinary(size_t& size) const +{ + size = getBinarySize(); + return (uint8_t *)this; +} + +size_t P094_filter::fromBinary(const uint8_t *data) +{ + memcpy(this, data, getBinarySize()); + return getBinarySize(); +} + +bool P094_filter::isValid() const +{ + if ((_filter._manufacturer == 0) && + (_filter._meterType == 0) && + (_filter._serialNr == 0) && + (getFilterWindow() == P094_Filter_Window::None)) { + return false; + } + return + !isWildcardManufacturer() || + !isWildcardMeterType() || + !isWildcardSerial() || + getFilterWindow() != P094_Filter_Window::None; +} + +bool P094_filter::operator<(const P094_filter& rhs) const +{ + if (isValid() != rhs.isValid()) { + return isValid(); + } +/* + // Disable sorting, only sort by having valid filters at top. + if (isWildcardManufacturer() != rhs.isWildcardManufacturer()) { + return rhs.isWildcardManufacturer(); + } + + if (isWildcardMeterType() != rhs.isWildcardMeterType()) { + return rhs.isWildcardMeterType(); + } + + if (isWildcardSerial() != rhs.isWildcardSerial()) { + return rhs.isWildcardSerial(); + } + + if (!isWildcardManufacturer() && (_filter._manufacturer != rhs._filter._manufacturer)) { + return _filter._manufacturer < rhs._filter._manufacturer; + } + + if (!isWildcardMeterType() && (_filter._meterType != rhs._filter._meterType)) { + return _filter._meterType < rhs._filter._meterType; + } + + if (!isWildcardSerial() && (_filter._serialNr != rhs._filter._serialNr)) { + return _filter._serialNr < rhs._filter._serialNr; + } +*/ + return false; +} + +bool P094_filter::operator==(const P094_filter& rhs) const +{ + return equals(*this, rhs); +} + +bool P094_filter::operator!=(const P094_filter& rhs) const +{ + return !equals(*this, rhs); +} + +bool P094_filter::equals(const P094_filter& lhs, const P094_filter& rhs) +{ + if (!lhs.isValid() && !rhs.isValid()) { return true; } + + return lhs.toString() == rhs.toString(); +} + +size_t P094_filter::getBinarySize() +{ + // Only store the filter + constexpr size_t P094_filter_size = sizeof(_filter); + + return P094_filter_size; +} + +bool P094_filter::matches(const mBusPacket_header_t& other) const +{ + if (!isWildcardManufacturer()) { + if (_filter._manufacturer != other._manufacturer) { return false; } + } + + if (!isWildcardMeterType()) { + if (_filter._meterType != other._meterType) { return false; } + } + + if (!isWildcardSerial()) { + if (_filter._serialNr != other._serialNr) { return false; } + } + + return true; +} + +unsigned long P094_filter::computeUnixTimeExpiration() const +{ + // Match the interval window. + const P094_Filter_Window filterWindow = getFilterWindow(); + + if ((filterWindow == P094_Filter_Window::None) || + (filterWindow == P094_Filter_Window::Once)) { + // Return date infinitely far in the future + return 0xFFFFFFFF; + } + + if (filterWindow == P094_Filter_Window::All) { + // Return timestamp in the past + return 0; + } + + // Using UnixTime + const unsigned long currentTime = node_time.getUnixTime(); + unsigned long window_max = currentTime; + + if ((filterWindow == P094_Filter_Window::One_hour) || + (filterWindow == P094_Filter_Window::Day) || + (filterWindow == P094_Filter_Window::Month)) + { + // Create time struct in local time. + struct tm tm_max; + breakTime(time_zone.toLocal(currentTime), tm_max); + tm_max.tm_sec = 59; + tm_max.tm_min = 59; + + if (filterWindow == P094_Filter_Window::Day) { + // Using local time, thus incl. timezone and DST. + if (tm_max.tm_hour < 23) { + // Either: + // - between 00:00 and 12:00 => Max: 11:59:59 + // - between 12:00 and 23:00 => Max: 22:59:59 + + tm_max.tm_hour = (tm_max.tm_hour < 12) ? 11 : 22; + } else { + // between 23:00 and 00:00 => Max: 23:59:59 + tm_max.tm_hour = 23; + } + } else if (filterWindow == P094_Filter_Window::Month) { + // First set minute to midnight of today => Max: 23:59:59 + tm_max.tm_hour = 23; + + if (tm_max.tm_mday < 15) { + // - between 1st of month 00:00:00 and 15th of month 00:00:00 + tm_max.tm_mday = 14; + } else { + // Check if this is the last day of the month. + // Add 24h to the time and see if it is still the same month. + const uint8_t maxMonthDay = getMonthDays(tm_max); + + if (tm_max.tm_mday < maxMonthDay) { + // - between 15th of month 00:00:00 and last of month 00:00:00 + // So we must subtract one day. + tm_max.tm_mday = maxMonthDay - 1; + } else { + // - between last of month 00:00:00 and 1st of next month 00:00:00 + // Thus do not change the date as it is already at the last day of the month + } + } + } + + // Convert from local time. + window_max = time_zone.fromLocal(makeTime(tm_max)); + } else { + switch (filterWindow) { + case P094_Filter_Window::One_minute: + window_max = currentTime - (currentTime % (1 * 60)) + (1 * 60 - 1); + break; + case P094_Filter_Window::Five_minutes: + window_max = currentTime - (currentTime % (5 * 60)) + (5 * 60 - 1); + break; + case P094_Filter_Window::Fifteen_minutes: + window_max = currentTime - (currentTime % (15 * 60)) + (15 * 60 - 1); + break; + + default: + break; + } + } + return window_max; +} + +void P094_filter::WebformLoad(uint8_t filterIndex) const +{ + addRowLabel_tr_id( + concat(F("Filter "), static_cast(filterIndex + 1)), + P094_FILTER_WEBARG_LABEL(filterIndex)); + + // Manufacturer + addTextBox( + P094_FILTER_WEBARG_MANUFACTURER(filterIndex), + getManufacturer(), + 3, false, false, EMPTY_STRING, F("widenumber") +# if FEATURE_TOOLTIPS + , F("Manufacturer") +# endif // if FEATURE_TOOLTIPS + ); + + // Meter Type + addTextBox( + P094_FILTER_WEBARG_METERTYPE(filterIndex), + getMeterType(), + 4, false, false, EMPTY_STRING, F("widenumber") +# if FEATURE_TOOLTIPS + , F("Meter Type (HEX)") +# endif // if FEATURE_TOOLTIPS + ); + + // Serial nr + addTextBox( + P094_FILTER_WEBARG_SERIAL(filterIndex), + getSerial(), + 10, false, false, EMPTY_STRING, F("widenumber") +# if FEATURE_TOOLTIPS + , F("Serial (HEX)") +# endif // if FEATURE_TOOLTIPS + ); + + { + // Filter Window + const int optionValues[] = { + static_cast(P094_Filter_Window::All), + static_cast(P094_Filter_Window::One_minute), + static_cast(P094_Filter_Window::Five_minutes), + static_cast(P094_Filter_Window::Fifteen_minutes), + static_cast(P094_Filter_Window::One_hour), + static_cast(P094_Filter_Window::Day), + static_cast(P094_Filter_Window::Month), + static_cast(P094_Filter_Window::Once), + static_cast(P094_Filter_Window::None) + }; + + constexpr size_t nrOptions = sizeof(optionValues) / sizeof(optionValues[0]); + + String options[nrOptions]; + + for (size_t i = 0; i < nrOptions; ++i) { + const P094_Filter_Window filterWindow = static_cast(optionValues[i]); + options[i] = Filter_WindowToString(filterWindow); + } + addSelector(P094_FILTER_WEBARG_FILTER_WINDOW(filterIndex), + nrOptions, + options, + optionValues, + nullptr, + _filter._filterWindow, + false, + true, + F("widenumber") +# if FEATURE_TOOLTIPS + , F("Filter Window") +# endif // if FEATURE_TOOLTIPS + ); + } +} + +String P094_WebformSave_GetWebArg(const String& id) { + String webarg_str = webArg(id); + + if (webarg_str.isEmpty()) { + webarg_str = '*'; + } + return webarg_str; +} + +bool P094_filter::WebformSave(uint8_t filterIndex) +{ + String filterString; + + // Manufacturer + filterString += P094_WebformSave_GetWebArg(P094_FILTER_WEBARG_MANUFACTURER(filterIndex)); + filterString += '.'; + + // Meter Type + filterString += P094_WebformSave_GetWebArg(P094_FILTER_WEBARG_METERTYPE(filterIndex)); + filterString += '.'; + + // Serial nr + filterString += P094_WebformSave_GetWebArg(P094_FILTER_WEBARG_SERIAL(filterIndex)); + + fromString(filterString); + + // Filter Window + _filter._filterWindow = getFormItemInt( + P094_FILTER_WEBARG_FILTER_WINDOW(filterIndex), + 0); + + return isValid(); +} + +String P094_filter::getManufacturer() const +{ + String manufacturer; + + if (isWildcardManufacturer()) { + manufacturer = '*'; + } else { + manufacturer = mBusPacket_header_t::decodeManufacturerID(_filter._manufacturer); + } + return manufacturer; +} + +String P094_filter::getMeterType() const +{ + String metertype; + + if (isWildcardMeterType()) { + metertype = '*'; + } else { + metertype = formatToHex_no_prefix(_filter._meterType, 2); + } + return metertype; +} + +String P094_filter::getSerial() const +{ + String serial; + + if (isWildcardSerial()) { + serial = '*'; + } else { + serial = formatToHex_no_prefix(_filter._serialNr, 8); + } + return serial; +} + +P094_Filter_Window P094_filter::getFilterWindow() const +{ + return static_cast(_filter._filterWindow); +} + + +#endif // ifdef USES_P094 \ No newline at end of file diff --git a/src/src/PluginStructs/P094_Filter.h b/src/src/PluginStructs/P094_Filter.h new file mode 100644 index 0000000000..952b32b0cd --- /dev/null +++ b/src/src/PluginStructs/P094_Filter.h @@ -0,0 +1,95 @@ +#ifndef PLUGINSTRUCTS_P094_FILTER_H +#define PLUGINSTRUCTS_P094_FILTER_H + +#include "../../_Plugin_Helper.h" +#ifdef USES_P094 + +# include "../DataStructs/mBusPacket.h" + +// Is stored, so do not change the int values. +enum class P094_Filter_Window : uint8_t { + None = 0, // no messages pass the filter + All = 1, // Realtime, every message passes the filter + One_minute = 2, // a message passes the filter every 1 minutes, aligned to time (00:00:00, 00:01:00, ...) + Five_minutes = 3, // a message passes the filter every 5 minutes, aligned to time (00:00:00, 00:05:00, ...) + Fifteen_minutes = 4, // a message passes the filter every 15 minutes, aligned to time + One_hour = 5, // a message passes the filter every hour, aligned to time + Day = 6, // a message passes the filter once every day + // - between 00:00 and 12:00, + // - between 12:00 and 23:00 and + // - between 23:00 and 00:00 + Month = 7, // a message passes the filter + // - between 1st of month 00:00:00 and 15th of month 00:00:00 + // - between 15th of month 00:00:00 and last of month 00:00:00 + // - between last of month 00:00:00 and 1st of next month 00:00:00 + Once = 8 // only one message passes the filter until next reboot +}; + + +// Examples for a filter definition list +// EBZ.02.12345678;all +// *.02.*;15m +// TCH.44.*;Once +// *.*.*;5m + +struct P094_filter { + P094_filter(); + + void fromString(String str); + String toString() const; + + const uint8_t* toBinary(size_t& size) const; + size_t fromBinary(const uint8_t *data); + + // Is valid when it doesn't match: *.*.*;none + bool isValid() const; + + bool operator<(const P094_filter& rhs) const; + bool operator==(const P094_filter& rhs) const; + bool operator!=(const P094_filter& rhs) const; + + static bool equals(const P094_filter& lhs, const P094_filter& rhs); + + static size_t getBinarySize(); + + + // Check to see if the manufacturer, metertype and serial matches. + bool matches(const mBusPacket_header_t& other) const; + + // Compute expiration UnixTime + unsigned long computeUnixTimeExpiration() const; + + void WebformLoad(uint8_t filterIndex) const; + bool WebformSave(uint8_t filterIndex); + + bool isWildcardManufacturer() const { + return _filter._manufacturer == mBus_packet_wildcard_manufacturer; + } + + bool isWildcardMeterType() const { + return _filter._meterType == mBus_packet_wildcard_metertype; + } + + bool isWildcardSerial() const { + return _filter._serialNr == mBus_packet_wildcard_serial; + } + + String getManufacturer() const; + String getMeterType() const; + String getSerial() const; + P094_Filter_Window getFilterWindow() const; + + // Keep this order of members as this is how it will be stored. + struct { + uint64_t _serialNr : 32; + uint64_t _manufacturer : 16; + uint64_t _meterType : 8; + + // Use for filtering + uint64_t _filterWindow : 8; + } _filter; +}; + +#endif // ifdef USES_P094 + +#endif // ifndef PLUGINSTRUCTS_P094_FILTER_H \ No newline at end of file diff --git a/src/src/PluginStructs/P094_data_struct.cpp b/src/src/PluginStructs/P094_data_struct.cpp index 30a8449a71..bca4243549 100644 --- a/src/src/PluginStructs/P094_data_struct.cpp +++ b/src/src/PluginStructs/P094_data_struct.cpp @@ -2,22 +2,24 @@ #ifdef USES_P094 -// Needed also here for PlatformIO's library finder as the .h file +// Needed also here for PlatformIO's library finder as the .h file // is in a directory which is excluded in the src_filter -#include +# include -#include +# include -#include "../Globals/ESPEasy_time.h" -#include "../Helpers/StringConverter.h" +#include +# include "../DataStructs/mBusPacket.h" +# include "../Globals/MQTT.h" + +// # include "../Globals/ESPEasy_time.h" +// # include "../Globals/TimeZone.h" +// # include "../Helpers/ESPEasy_Storage.h" +// # include "../Helpers/StringConverter.h" -P094_data_struct::P094_data_struct() : easySerial(nullptr) { - for (int i = 0; i < P094_NR_FILTERS; ++i) { - valueType_index[i] = P094_Filter_Value_Type::P094_not_used; - filter_comp[i] = P094_Filter_Comp::P094_Equal_OR; - } -} + +P094_data_struct::P094_data_struct() : easySerial(nullptr) {} P094_data_struct::~P094_data_struct() { if (easySerial != nullptr) { @@ -33,46 +35,222 @@ void P094_data_struct::reset() { } } -bool P094_data_struct::init(ESPEasySerialPort port, - const int16_t serial_rx, - const int16_t serial_tx, - unsigned long baudrate) { +bool P094_data_struct::init(ESPEasySerialPort port, + const int16_t serial_rx, + const int16_t serial_tx, + unsigned long baudrate) { if ((serial_rx < 0) && (serial_tx < 0)) { return false; } reset(); easySerial = new (std::nothrow) ESPeasySerial(port, serial_rx, serial_tx); - if (isInitialized()) { - easySerial->begin(baudrate); - return true; + if (easySerial == nullptr) { + return false; } - return false; + easySerial->begin(baudrate); + return true; +} + +void P094_data_struct::setFlags(unsigned long filterOffWindowTime_ms, + bool intervalFilterEnabled, + bool mute, + bool collectStats) +{ + filterOffWindowTime = filterOffWindowTime_ms; + interval_filter.enabled = intervalFilterEnabled; + collect_stats = collectStats; + mute_messages = mute; } -void P094_data_struct::post_init() { - for (uint8_t i = 0; i < P094_FILTER_VALUE_Type_NR_ELEMENTS; ++i) { - valueType_used[i] = false; + +void P094_data_struct::loadFilters(struct EventStruct *event, uint8_t nrFilters) +{ + int offset_in_block = 0; + + + const size_t chunkSize = P094_filter::getBinarySize(); + const size_t maxNrFilters = 1024u / chunkSize; + + if (nrFilters > maxNrFilters) { nrFilters = maxNrFilters; } + + _filters.clear(); + + size_t nrChunks = 8; + + if (nrFilters < nrChunks) { + nrChunks = nrFilters; } - for (uint8_t i = 0; i < P094_NR_FILTERS; ++i) { - size_t lines_baseindex = P094_Get_filter_base_index(i); - int index = _lines[lines_baseindex].toInt(); - int tmp_filter_comp = _lines[lines_baseindex + 2].toInt(); - const bool filter_string_notempty = _lines[lines_baseindex + 3].length() > 0; - const bool valid_index = index >= 0 && index < P094_FILTER_VALUE_Type_NR_ELEMENTS; - const bool valid_filter_comp = tmp_filter_comp >= 0 && tmp_filter_comp < P094_FILTER_COMP_NR_ELEMENTS; + const size_t bufferSize = nrChunks * chunkSize; - valueType_index[i] = P094_not_used; + while (nrFilters > 0) { + uint8_t buffer[bufferSize]; + ZERO_FILL(buffer); + + LoadCustomTaskSettings(event->TaskIndex, buffer, bufferSize, offset_in_block); + offset_in_block += bufferSize; + + uint8_t *readPos = buffer; + + for (size_t i = 0; i < nrChunks && nrFilters > 0; ++i) { + P094_filter filter; + filter.fromBinary(readPos); + + if (filter.isValid()) { + _filters.push_back(filter); + } - if (valid_index && valid_filter_comp && filter_string_notempty) { - valueType_used[index] = true; - valueType_index[i] = static_cast(index); - filter_comp[i] = static_cast(tmp_filter_comp); + --nrFilters; + readPos += chunkSize; } } } +String P094_data_struct::saveFilters(struct EventStruct *event) const +{ + int offset_in_block = 0; + + String res; + const size_t nrFilters = _filters.size(); + size_t currentFilter = 0; + const size_t chunkSize = P094_filter::getBinarySize(); + const size_t nrChunks = 8; + #ifdef ESP32 + const size_t bufferSize = 1024; + #else + const size_t bufferSize = 256; + #endif + + std::vector buffer; + buffer.resize(bufferSize); + + + while ((offset_in_block + bufferSize) <= 1024 && res.isEmpty()) { + for (auto it = buffer.begin(); it != buffer.end(); ++it) { + *it = 0; + } + + uint8_t *writePos = &buffer[0]; + size_t writeSize = 0; + + while (writeSize < bufferSize && currentFilter < nrFilters) { + if (_filters[currentFilter].isValid()) { + size_t size{}; + const uint8_t *binaryData = _filters[currentFilter].toBinary(size); + memcpy(writePos, binaryData, size); + writePos += size; + writeSize += size; + } + ++currentFilter; + } + res = SaveCustomTaskSettings(event->TaskIndex, &buffer[0], bufferSize, offset_in_block); + offset_in_block += bufferSize; + } + return res; +} + +void P094_data_struct::clearFilters() +{ + _filters.clear(); +} + +bool P094_data_struct::addFilter(struct EventStruct *event, const String& filter) +{ + P094_filter f; + + f.fromString(filter); + + if (!f.isValid()) { + return false; + } + + if (isDuplicate(f)) { + if (loglevelActiveFor(LOG_LEVEL_ERROR)) { + addLogMove(LOG_LEVEL_ERROR, concat(F("CUL Reader : Duplicate filter found: "), f.toString())); + } + + return false; + } + + _filters.push_back(f); + + std::sort(_filters.begin(), _filters.end()); + + if (P094_NR_FILTERS < _filters.size()) { + P094_NR_FILTERS = _filters.size(); + } + return true; +} + +String P094_data_struct::getFiltersMD5() const +{ + if (mute_messages) { + return F("blockall"); + } + + MD5Builder md5; + uint8_t checksum[16]{}; + md5.begin(); + + uint8_t nrFiltersAdded = 0; + const char separator[] = {'|', 0}; + for (auto it = _filters.begin(); it != _filters.end(); ++it) { + if (it->isValid()) { + if (nrFiltersAdded != 0) { + md5.add(separator); + } + md5.add(it->toString().c_str()); + ++nrFiltersAdded; + } + } + + if (nrFiltersAdded == 0) { + // No filters, thus all messages will just pass + return F("pass"); + } + + md5.calculate(); + md5.getBytes(checksum); + + return formatToHex_array(checksum, sizeof(checksum)); +} + +void P094_data_struct::WebformLoadFilters(uint8_t nrFilters) const +{ + if (nrFilters > 0) { + addFormNote(F("Filter Fields: Manufacturer, Meter Type, Serial, Filter Window")); + } + + for (uint8_t filterLine = 0; filterLine < nrFilters; ++filterLine) + { + if (filterLine < _filters.size()) { + _filters[filterLine].WebformLoad(filterLine); + } else { + P094_filter dummy; + dummy.WebformLoad(filterLine); + } + } +} + +void P094_data_struct::WebformSaveFilters(struct EventStruct *event, uint8_t nrFilters) +{ + _filters.clear(); + + for (uint8_t filterLine = 0; filterLine < nrFilters; ++filterLine) + { + P094_filter dummy; + + if (dummy.WebformSave(filterLine)) { + // Filter with filled in values, worth storing + if (!isDuplicate(dummy)) { + _filters.push_back(dummy); + } + } + } + addHtmlError(saveFilters(event)); +} + bool P094_data_struct::isInitialized() const { return easySerial != nullptr; } @@ -84,14 +262,301 @@ void P094_data_struct::sendString(const String& data) { easySerial->write(data.c_str()); if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log = F("Proxy: Sending: "); - log += data; - addLogMove(LOG_LEVEL_INFO, log); + addLogMove(LOG_LEVEL_INFO, concat(F("Proxy: Sending: "), data)); } } } } +# if P094_DEBUG_OPTIONS + +const __FlashStringHelper* getDebugSentences(int& count) { + // *INDENT-OFF* + switch (count) { + case 1: return F("b3C449344369291352337D55472593107009344230A920000200C0538ECE32625004C0527262500426CBF2CCC0805BDF032262500C2086CDF21326CFFFF046D26BB1103DA22B4E093E2"); break; //QDS.0A.00073159"); break; //QDS.37.35919236 + case 2: return F("b9644A732260729700A0AB8487A4E10002002747D00046D030AC1270CB02E0600000000446D3B17BF2C4C0600000083410084016D3B17DE268C010600000000CC190B0106000000008C020600000000CC0206B190000000008C030600000000CC030600008B9400008C040600000000CC04060000000099348C050600000000CC0506000000008C0673DA0600000000CC0606000000008C070600E0F80000003C22030402000F841001245C84E7"); break; //LUG.0A.70290726 + case 3: return F("bCE44A8153132000801022ADC7F6900C005098D2F2D70E24F3E43458739FD572B2DB7CB22EA563C57F3017308E093A4CBC662DF70F000A2E2B18215FC7098DBC7DC8A2ABAD8202F700C5A7D8B0FC89094823FC6B54565730369E73039146898536381B5DE8B8F3A5377A807EB30383ACC0176176C6C18265932082844F0B5A3F69B0A66FD0E35FAED9A53B825E073FC1E67193A727C97BC1025229C87421FA0381443A5F2F2897AE44D383FE125614F08BABEC6B46DF0FFCB910DAD1B3CD53B44AA83726492D845F840A2D20B738E9FB212D5C74FF91FD2796A22D669CBF0B0FEC1BAFA171A65FFB165B2E9"); break; //EMH.02.08003231 + case 4: return F("b5344E2306291001500030F388C30A7900F002C2583AE010032E1E493C32BEF51CDA37A430030071027A19EE14B0BBCAD656D0783516CCB7CFBC6AAFAECDCAD70020FE3DA54FCBC8EC2AED88DFD0972C55CF9336E1683574ABADBD046BB53623F8013"); break; //LGB.03.15009162 + case 5: return F("b5344A732806139690404B70A8C2063900F002C25923338000C8BC361CE2EE050FD3B7A6340300710DEC49523134391877289A80A53A505655A833F754F221E619D08FB4DB5AD773EAB16B545B306C69D1493CD851012BBF4624A5DDA556AF07E83E5"); break; //LUG.04.69396180 + case 6: return F("b9644A732460335700A043C1F7ACD0000200274DE02046D030D94250C804C0623000000446D3B177F2C4C060000005D610084016D3B179E248C010600000000CCB81D0106000000008C020600000000CC0206B190000000008C030600000000CC030600008B9400008C040600000000CC04060000000099348C050600000000CC0506000000008C0673DA0600000000CC0606000000008C070600E0F80000003C22000000000F0010004FF980F9"); break; //LUG.04.70350346 + case 7: return F("b13440000000000DA00DAA8CF7101FD0C3A02FD171101CB938032"); break; //@@@.DA.DA000000 + case 8: return F("b63445A146699750001026CE68C20D7900F002C25D7CE0C000B7C13179B38522166CE7AD700400710CDEF8D2A82F77DD15E367871F1E04261AAFAC430C2B55C1DED4A3148306D4C296CF10D72C9E79310A47DD73FDBFDF2CEA6490B6CA12A30EE5D64621A90B5E71F75D50D24C87B10E2ADDF802E"); break; //EBZ.02.00759966 + case 9: return F("b5E44496A3680003888049D2D7A1D0050053FBA7B54810C548AC112ECFC76CE753AF07A625248C05827C843371AB5DC6C6C8D5D457E845B4B67FB4CEFF06720EA7A9112BFD0A96BC7E97D49FB9BBD59155D109433F0C4823DEA7A13E5281C00E4945F5B05D7518CE085EC8BFE738122"); break; //ZRI.04.38008036 + case 10 : return F("b1B44A5110301808238379BA77241022436931581038A88000002A7184A0AD900E327803A"); break; //ELS.03.36240241"); break; //DME.37.82800103 + case 11 : return F("b3E44B405399098502E0439DC7A0F70300530C7144B5962760A55DE8BA4E49C37676B0CD702698B5FBCE59E35E33D33F736AE13FB1C31DD43ADDC3FE7FF8E1EDC01D749974884BBF96580FE"); break; //AMT.04.50989039 + case 12 : return F("b5B4479169014216130377E5B8C2034900F002C256448000029E1A134984E32773DF97289000047791611023400302CBD0710FF4380B4AE49A140E94F319BE97049FDA8DDC96A8DC437F3BFB02ADC86082E9507934C7ED4FC6F4F678D613F25C09A1DDE927D817F5A824A8012"); break; //ESY.02.47000089"); break; //ESY.37.61211490 + case 13 : return F("b7B445A1415200000023724958C20A0900F002C25B4F60800C0E1D417100AD1BB6EDC72324371005A140102A00050F9B10710112A08DB9869998DE2C0D8614F76213F8682D10A8EF2951413C839461E8E3139EA62193E02B1584E6EC8EDB082AB70C6504F1ADF9E6ABD270E96FE8745AEB93C454FC3C9EAA2D5FCD6679E8A38A3E0818D4B6652993CEE5F8E514867801D"); break; //EBZ.02.00714332"); break; //EBZ.37.00002015 + case 14 : return F("b49449344100549253508227F780DFF5F3500824600007E0007B06EFF2BE9FF000000007F2C000000009E24000000DAC000008000800080008000800080000000E9F10000000000000000002F046D010E8625249880E6"); break; //QDS.08.25490510 + case 15 : return F("b9644A732370335700A045D187A440000200274DD02046D071189260C33FD0638010000446D3B177F2C4C06000000DFDD0084016D3B179F258C010641000000CC0DBA0106000000008C020600000000CC0206B190000000008C030600000000CC030600008B9400008C040600000000CC04060000000099348C050600000000CC0506000000008C0673DA0600000000CC0606000000008C070600E0F80000003C22000000000F0010004FF980E0"); break; //LUG.04.70350337 + case 16 : return F("b4806AC1956030015020363917256030015AC190203D8000000466D00AC9200118625000D78113131363533303030619C3531343530303030308940FD1A014C933B263A494700004C130546000001FD67030D9A8057"); break; //FML.03.15000356"); break; //FML.03.15000356 + case 17 : return F("b9E44A815242292070102881F7F4B0098050B0E989C939C3479F8904137236FE582B853DCACDD8DB48A717A6B42935CB977102079E6397B07AAD2A648E5B65E44D97F9A020B2BFAE433FA37FCB2A2C32711A5986B301D2F6E4A424C1144D808CE9D592C316B117C572689AC6C1322CC05E81F590CAAF457390F6B39DACC946FA314F8E8A34268157AC4338781C3EF5807F9221394DD1FAB5165E1261614B8B85758851295334DF52D9A4DCE2E1E17A555A21007D2DA802B"); break; //EMH.02.07922224 + case 18 : return F("b2E44B05C99010100021B65BE7AC30000002F2F0A6605020AFB1A33041AA002FD971D00002F2F2F2F2F2F2F2F2F2FDF772F2F2F2F2F25EE8008"); break; //WEP.1B.00010199 + case 19 : return F("b2E44B05C75000000041B8EF87A510000002F2F0A6661010AFB1A8905449802FD971D00002F2F2F2F2F2F2F2F2F2FDF772F2F2F2F2F25EE80F8"); break; //WEP.1B.00000075 + case 20 : return F("b1E44C418EA76010001034ECB7A820010A5597AB1CCF2014088590E64BCAB21DC1CC068DAA08035"); break; //FFD.03.000176EA + case 21 : return F("b4E442423245450514A07545F7AC6004005BDB5EDF3750DF41725EE867C3E39750E20B9F5FB092089B6A5DC7AA586101778BCD5EAD4995B102AC639F0FB4D12403EFE3554F72CAE4F5D348CC374F571CCE4A98634318027AAF3E7DD8600"); break; //HYD.07.51505424 + case 22 : return F("b4344A511031008667607CFF48C0031900F002C2531D311006D980E9CC8D28524C6417AE570210710CFF2DB65BFE77C51602690DAEB954A5455A2ABED621B74AC56A79D81390EBFCADC9D3D34F5928DDC"); break; //DME.07.66081003 + case 23 : return F("b4344A511031008667607CFF48C0031900F002C2532D31100BC55A548A0082663A6FC7AE670210710C7B178D748F610E2CB16DE82C823EF83334EF1A0C383FB42DF7BED1846323211FC25DCC1EBF085DE"); break; //DME.07.66081003 + case 24 : return F("b4344A511031008667607CFF48C0031900F002C2533D311004E0C2E86D68C08F425747AE77021071013F9284E0CB5896FFB27D33882716D09F7EC8175FD04516AAE9122E584095D6441E14E5B4ED189DD"); break; //DME.07.66081003 + case 25 : return F("b6E44A511825169584004B8737AB500600554B11A7F9F7DDCAC35695A3191EA83FD79D1876F378419D5AB37CA1BD857243492B6379B258A4831015F9F0D4B7098218D7E7C44421422FCABC0770F0E67C16EFA13ABEE798D58062CDB0F06AA312592C085F046D29B64F7031FE17CC7EC8B44D61FB5E2F37301ACA7AAC025666C802C"); break; //DME.04.58695182 + case 26 : return F("b4944C51402203571000451A77A090001202F2F046D2E299926040687ED7214000001FD17000413F6670400043B009378000000042B00000000025B1900025F1986B90002610A0003FD0C05000002FD0B3011F52BA393"); break; //EFE.04.71352002 + case 27 : return F("b2844C5146427807103073D877234626016C5140007D72000202F2F04DD1C6D2F3498260413B96E010001FD1700066080E7"); break; //EFE.07.16606234"); break; //EFE.07.71802764 + case 28 : return F("bA644C514960080900307DABF7296008090C5140007ED0000202F2F426E8D6C7E2944133C08000001FD1700840113039188130000C40113D611000084021324108D5A0000C40213A70F00008403132C0F00003550C403137B0E0000840413C0080000C404749913650800008405133C080000C40513AD831B07000084061380050000C406138401006999008407133A000000C407133A00000084286B081300000000046D332A8F260413A7137132000003FD0C02032102FD0B01114D8480FA"); break; //EFE.07.90800096"); break; //EFE.07.90800096 + case 29 : return F("b5E442515695800000C1A452E7A590050252502B45C2E823EF856FABFC4775E28D2904492FB74BA65A843BA7E63BC698D83279AE2BE04B957699517818F7B33F8E58001A7C9CE0E73C5769487247954D0A000E811754BAB1CED0E61567EB1FE504B091E0C7DCF4632E3FAC31618804D"); break; //EIE.1A.00005869 + case 30 : return F("b4806AC1956030015020363917256030015AC19020323000000466D0009780004872B000D7811313136353330303028633531343530303030308940FD1A014C933B263A494700004C130546000001FD67030D9A8030"); break; //FML.03.15000356"); break; //FML.03.15000356 + case 31 : return F("bY5044972608062002001A7AC90340A517F5A8F83D78281AEFF06FDBDEDEF842336FA663F292D6EEACB0F54CA02FB47C8F587862B352ED30166FEE61753998230C38444F845C9FCC364D3C614095F92D14A28010"); break; //ITW.1A.02200608 + case 32 : return F("bY5E449726900634160004728499181897A60030BA0040A53FB81E378B33F9E23FEDF6A0B1B381F4972C2842041CC7EC8D74D675CE56222039CE82385073750F2B695CBEC9B0E8A48EC3F09B74C26E4194A06B7974203DDD0C7976874216E0D282DE"); break; //ITW.04.16340690"); break; //ITW.30.18189984 + case 33 : return F("bY50449726141331160007728499181897A600307E0030A5500A4109842EF76DD4A2DEDF6722CCB4D0746C8505086D91ED34B41AFD24FED0111715A21E549191B1529EE2AE8229E50E7900000000000070208AD8"); break; //ITW.07.16311314"); break; //ITW.30.18189984 + case 34 : return F("bY5044972625353893071A7A0B0040A5B12EC2E009C467CAD2AF0A38712684FE764C6181D2969A7F0F7B076CB9719FEB21C32E48161EEA5A1E6E92F354FED894994C368F17E6F68E2E6AA1D7C289E3FD7A908015"); break; //ITW.1A.93383525 + case 35 : return F("b2E449726606670194107A6AB8CB0D47ABF0000A00413E84B070004FD3442178001C00004933C00000000333B00000A2D00325A0000CD2E801C"); break; //ITW.07.19706660 + case 36 : return F("bY50449726141331160007728499181897A600307E0030A5500A4109842EF76DD4A2DEDF6722CCB4D0746C8505086D91ED34B41AFD24FED0111715A21E549191B1529EE2AE8229E50E7900000000000070208AD8"); break; //ITW.07.16311314"); break; //ITW.30.18189984 + case 37 : return F("b314493447236379635085D337A040000200B6E3103004B6E070300420D0E6C7F2CCB086E310300C2086C9E24326C1422FFFF046D240E86250E4E80E2"); break; //QDS.08.96373672 + case 38 : return F("b494493447236379635083FD9780DFF5F350082030000F00007B06EFFC6F5FF310300007F2C070300009E24310300E13000008000800000000000001F007300A145C9006BFF64003D000C002F046D200E86255AA081DF"); break; //QDS.08.96373672 + case 39 : return F("b494493447153871216062D53780DFF5F350082DA00007F0007C113FF8331FF969799997F2C279899999F2596979988C999000000000000FFFF000000000000008B35000000FFFFFEFF00002F046D25068C2608D2803F"); break; //QDS.06.12875371 + case 40 : return F("b344493447153871216069A667A8000082004ED3926096C2701FD0C110157046D17138F2602FD3CC2010DFF5F0C005FC50861FF000006130701FFFC138B803F"); break; //QDS.06.12875371 + case 41 : return F("b3D44934417196746221AD6FF7AA210000081027C034955230182026CAC3BB62181037C034C41230082036CFFFF0238E2FD171000326CFFFF046D0311B62102FDFE8FAC7E19004F33802D"); break; //QDS.1A.46671917 + case 42 : return F("b3744934417196746221A40247AA310002081027C034955230182026C5AE5B62181037C034C41230082036CFFFF0238E2FD171000326CFFFF046D0311B621AD04802B"); break; //QDS.1A.46671917 + case 43 : return F("b39449344775149131706E1D57A680000200C13750000004C1300000010FC00426CFFFFCC081358000000C2086C9F61212502BB560000326CFFFF046D070B8A268D5880FA"); break; //QDS.06.13495177 + case 44 : return F("b4944934477514913170662C2780DFF5F3500827B0000810007C113FF5A69FF75000000FFFF000000009F255800004659000080008000800080008000800080009B248001000000000004002F046D1F0D8A266CB280FA"); break; //QDS.06.13495177 + case 45 : return F("b3744934484145047231AAE907A9600002081027C034955230082026CD1DAFFFF81037C034C41230082036CFFFF02DDAAFD170000326CFFFF046D0503AD21AB3580D9"); break; //QDS.1A.47501484 + case 46 : return F("b39449344843350131707BA4A7AF00000200C13000100004C13000000C11300426CFFFFCC081361000000C2086C9F6DF62502BB560000326CFFFF046D370A8A26486681E6"); break; //QDS.07.13503384 + case 47 : return F("b49449344843350131707395D780DFF5F350082000000EE0007C113FF4BC0FF00010000FFFF000000009F256100009FB5000080008000800080008000800080009B248001000000000005002F046D020D8A263BD880E7"); break; //QDS.07.13503384 + case 48 : return F("b3C4493440989323533372A78728903252493443307C50000200C133698392007004C1331430400426C7F2CCC081319DD26200700C2086C9F25326CFFFF046D058B67079026F78582DC"); break; //QDS.07.24250389"); break; //QDS.37.35328909 + case 49 : return F("b2C449344098932353337D4E7728903252493443307C000082004ED39ACEB2C06702501FD0C10046D1C06902602FD705D3CC20189FB81DA"); break; //QDS.07.24250389"); break; //QDS.37.35328909 + case 50 : return F("b5344934409893235333714F478077989032524934433070DFF5F3500D11E82CE0000100007C113FFFF362007007FCFC92C314304009F252620070020029102810C8E02730241023902940287023F0254029062770227012F046D14108D26710885D5"); break; //QDS.37.35328909 + case 51 : return F("b1F44685034025063591B28F57AE100000001FD17000265EF070F6A18DFC253E0F351D0900E8180F9"); break; //TCH.1B.63500234 + case 52 : return F("b294468501904601473F0AE14A0009F27EDA5B130CA280080770001045667006BA1007CB2008DC3009ED4000FE50096BA80EB"); break; //TCH.F0.14600419 + case 53 : return F("b294468508220285376F0F19BA0009F27A1280028A128000033000006BC4C006BA1007CB2008DC3009ED4000FE50096BA80DC"); break; //TCH.F0.53282082 + case 54 : return F("b50446850920420745937163972612600006850FE036B0000200415CC4CB0551F0084041552FC1C0082046C7C228D92D804951F1E72FE000000006F1BF114A212D1B377124C1EA62E83430E5006511443943F9B47F52901FD17002F1F2F800E"); break; //TCH.03.00002661"); break; //TCH.37.74200492 + case 55 : return F("b3644685005012040714351C0A004372900000060DA4E029B5FBAC4123A84170DBBFBF13D06000000000000000000AE3800000000000000000000000000FFFF94A6"); break; //TCH.43.40200105 + case 56 : return F("b3644685005012040714351C0A0009F298F560290E10101A40000FFF719F04E99E7B2F9E2E512000000000000000042B000000000000000000000000000FFFF95A6"); break; //TCH.43.40200105 + case 57 : return F("b8E44A81524229207010276807F680080056E68ED762185BEDAB68F79E2A8BF6562ED1C21105B74E82AA9D1B5E79311AB713DC2F86C785D18F6E470067B86284E8A9D1AF9F36330FE18968F826F8D1B21E99F1C08D45FB9CDBF04B37136E2FC1CED74FF3186482FA3058F6F1BD712BBE20098CCB0C72D51F6013CBB974678706CF2F4D6D0D07A793FE1EC8EAF701AD2BEE5922E69F72C356AC1B009A0E0646B0413DD45802B"); break; //EMH.02.07922224 + case 58 : return F("b374465B2118222001604DDD67A26140000046D1107152A01FD0C06326E796CFFFF0DFF5F0C00083D300001061308131C0BFFFC02FD1700140C7896145559D9FF8032"); break; //LSE.04.00228211 + case 59 : return F("b4BC465B251A16000F193DC2CA083110049244E01394465324604401311FC17067A4F0000000C13714800004C1310BC7A000000426C7F2C02BB560000326CFFFF420A046D2009912682046C9F258C04136643DF650000FFFF80DE"); break; //LSE.00.00000000 + case 60 : return F("b4BC465B251A18000F1950519A08311009E2423003944653252044013781E17067A500000000C13063401004C1310623C000000426C7F2C02BB560000326CFFFF420A046D330E912682046C9F258C04138720452E01000B2780DD"); break; //LSE.00.00000000 + case 61 : return F("b43C465B251A12001F0DDDD95A08310008A2460013144653221587296186735087A4F0000000B6E9102004B6E000041BB00426CFFFF326CFFFF046D2108912682BC3E046C9F258B046E9102000B2A80DD"); break; //LSE.00.00000000 + case 62 : return F("b25C465B251A0000AF1033454A2653205834710290E862400005F3573BB1B9A276422A2271D001D0004C9253580E4"); break; //LSE.00.00000000 + case 63 : return F("b4344A511031008667607CFF48C0031900F002C2531D311006D980E9CC8D28524C6417AE570210710CFF2DB65BFE77C51602690DAEB954A5455A2ABED621B74AC56A79D81390EBFCADC9D3D34F5928DDC"); break; //DME.07.66081003 + case 64 : return F("b4344A511031008667607CFF48C0031900F002C2532D31100BC55A548A0082663A6FC7AE670210710C7B178D748F610E2CB16DE82C823EF83334EF1A0C383FB42DF7BED1846323211FC25DCC1EBF085DE"); break; //DME.07.66081003 + case 65 : return F("b4344A511031008667607CFF48C0031900F002C2533D311004E0C2E86D68C08F425747AE77021071013F9284E0CB5896FFB27D33882716D09F7EC8175FD04516AAE9122E584095D6441E14E5B4ED189DD"); break; //DME.07.66081003 + case 66 : return F("b6E44A511825169584004B8737AB500600554B11A7F9F7DDCAC35695A3191EA83FD79D1876F378419D5AB37CA1BD857243492B6379B258A4831015F9F0D4B7098218D7E7C44421422FCABC0770F0E67C16EFA13ABEE798D58062CDB0F06AA312592C085F046D29B64F7031FE17CC7EC8B44D61FB5E2F37301ACA7AAC025666C802C"); break; //DME.04.58695182 + case 67 : return F("bYB04424341931031950067A800000002F2F0413F1570000046D092EC52504FD17004000000E780000000000004413184B0000426CBF2C840113F057000082016CDE24D3013B4E0400C4016D3128692C8104FD280182046CDE24840413F0570000C40413FD560000840513D1530000C40513CC4F0000840613184B0000C40678D313EA47000084071323430000C40713153F0000840813FD3B0000C4081393380000840913A3340000C4091311310000271081D7"); break; //MAD.06.19033119 + case 68 : return F("b4E44A5113748906370076F917A570040053A66831E6B6C8F06FB2C7CC1F60A673B63ACBF2F6A8D3347D34DE4BBDD4677E5DEC850D5CBBDF5B0AA7095B415EFCD93A124AC3B884FAF226845C439DBF3A2EB486CBE7D8D845383E3E480ED"); break; //DME.07.63904837 + case 69 : return F("b5344A511292535727507858F8C000E900F002C25823E090045AF7EFEDB43FBE691577A82003107105692A21A8C0C7531EEEAC3AA631D6BD790CA1B271C7E3C8860A189DA37AE30E89AB63AD316663EB4AD472596156E592602F8A016E51A5E0D8753"); break; //DME.07.72352529 + case 70 : return F("b5344A5117157367276075A048C00B0900F002C25218501000C373A89C912675F09407A2100310710DEF25F58D772CBD51AD6D2B487ED868B6B086976F51AE52E65D877F0310E9DCA942F4E7F94196DD2821329E662FD4E4C9F20A1A8829C54328EEC"); break; //DME.07.72365771 + case 71 : return F("b2E44A511880110827B0780AF7A4573200592F4DF44D5F258DF39AB376DD4A5BC338BBB2493257A98DC52C5E6299029DC79C01ED377C7F48028"); break; //DME.07.82100188 + case 72 : return F("b3644E61E95413900010E89957212517615E61E3C074230206593240B570397DF6230FBC015B276D63CD694FA79B17D1436E0E9FA1003C0763761BD8FBD67B73A8D"); break; //GWF.07.15765112"); break; //GWF.0E.00394195 + case 73 : return F("b9644FA12237704190007308E7AA8000020046D1E2B862B0413D1EA01F9CA0002FD17000001FD481D426C7F2C4413455C9E8A000084011370E50100C40113A0C200F70100840213EA9E0100C4021349870100735F8403130A700100C40313595301008404C386139F2B0100C4041345FA0000840513BABE2BCD0000C40513DEAA00008406139E8A00A1F700C40613D966000084071390400000C4F6040713E11C00008408136200000087F382DE"); break; //DWZ.07.19047723 + case 74 : return F("bA944FA1283211320020766737A6B009025ADD27B2058B2ADAAE5B5D2C8B11BD295CE460BD1ECA50B533A58FF19F7F9DEC291893DA502B763E7C80CEF440B899C92DE87D5548838FC2C9FF3873927441B0B17222FB14545D2E5A0CF81216074B3DF0911CB99BD20A558F2D873A9A649092F3C7B01BA2BEBCC26A58C0FD99ABC2E5E0E5AFC241A27B8C0863C571C3D586B7E2A06044B792CFE021C21BB1B71BCEE4D5D84E75C3FC0624DF07C8C8832C82140086903FD0C08000002FD0B011116A380EF"); break; //DWZ.07.20132183 + case 75 : return F("b3944934419504913170628617A660000200C13480900004C130000007BBF00426CFFFFCC081315020000C2086C9FC6D42A02BB560000326CFFFF046D1316952B82B084D3"); break; //QDS.06.13495019 + case 76 : return F("b2E446850915944496262C568A0009F276D03B017BC0000060A0A0809A71C0908090706070A0A09090A0B0B080708CB640A060A07071EA586E2"); break; //TCH.62.49445991 + case 77 : return F("b2E446850573060566562ADA6A0007E293200C0191400001400000000CC37000000000000000001010101010101023FB20101010001328686E1"); break; //TCH.62.56603057 + case 78 : return F("b2E4468505162250070628CD3A0009F277D00600A0B00000001010101002A010302010101020102010101010101018F6C0001010102AF7786F8"); break; //TCH.62.00256251 + case 79 : return F("b2F446850302976627462A01BA2064D280000600A240004000307070747EA0706060000000000000000000000000077A2000000000000FFFF80F6"); break; //TCH.62.62762930 + case 80 : return F("b2F446850370321809562C217A2069F270C00A00E0700000001000001B0E800000100010100000101000100000100B1AD000101010001328680F9"); break; //TCH.62.80210337 + case 81 : return F("b2D44653277993613170784017ABA0000000C13196100004C131100003AE500426C7F2C02BB560000326CFFFF046D2ACD2E068527CCD580DF"); break; //LSE.07.13369977 + case 82 : return F("bY24442D2C394864681D168D20AE91BF1622CC255857FE7B524DD67C4944CD428FBE5E0DFAB98021"); break; //KAM.16.68644839 + case 83 : return F("b2D446532490340131706417B7AB20000000C13814000004C13100000A12600426C7F2C02BB560000326CFFFF046D2ACD3B168327AC23800F"); break; //LSE.06.13400349 + case 84 : return F("b3644E61E08106100020E7F627236090021AE4C01071B0020A56EE84D172DF9648D9C4409131B88D3FD85BFD022BCB54971CACB714D617E5563719B95E9B2059A59"); break; //SEN.07.21000936"); break; //GWF.0E.00611008 + case 85 : return F("b3E44FA1287530019011691D07AC6002025D541F7DE1D910813127884F7DF4D80BF600A4323BD730B4639E4E0EA8B86129BDE9DD71D0F800C000109002487721866530201310101B10187CE"); break; //DWZ.16.19005387 + case 86 : return F("b9644FA1261281221000689447AB9000020046D302BAF2704136300009A0E0002FD17000001FD481C426C000044130E9B0000000084011300000000C4011300002A2D000084021300000000C402130000000098F984031300000000C40313000000008404B0D51300000000C404130000000084051300A00E000000C4051300000000840613000000B5CF00C406130000000084071300000000C4E74A071300000000840813000000009995812A"); break; //DWZ.06.21122861 + case 87 : return F("b3E44FA12336300190106617D7A81002025F1114AE0F19A04778065DD02E84809E9F7163157F05FB2506D26A3835904CED370FBCA9E0F800C00010900E10E03000A70207F3101013FFE80E3"); break; //DWZ.06.19006333 + case 88 : return F("b4C44B40968440303170787F77A3F0000000C1305000000046D1A2EAAA19F250F8F00010000000000000000000000D5BD00000000000000000000000000000000FFFF00000000000000000000000000000000FFFF000000FFFF80EE"); break; //BMT.07.03034468 + case 89 : return F("bY29442D2C394864681D168D20B3B0BF162236090AB83DFCC84216131495B5A2DF59242760EDECA043AF20801F"); break; //KAM.16.68644839 + case 90 : return F("b2844C51473278071030605C97237253816C5140006612000202F2F0464E66D243498260413070B010001FD1700146B80DD"); break; //EFE.06.16382537"); break; //EFE.06.71802773 + case 91 : return F("b39449344715387121606AE447AD40000200C13969799994C132798998CC999426C7F2CCC081396979999C2086C9F18DC2502BB560000326CFFFF046D2E0D8D261542803D"); break; //QDS.06.12875371 + case 92 : return F("b39449344724733131706336E7A270000200C13330600004C13100000218B00426C7F2CCC081382010000C2086C9FF2142A02BB560000326CFFFF046D1116952BF4D081DC"); break; //QDS.06.13334772 + case 93 : return F("b3944934451926513180637967A7D0000200C13110000004C13000000B0B100426CFFFFCC081311000000C2086C9F52D52A02BB560000326CFFFF046D3A0B862B28D08027"); break; //QDS.06.13659251 + case 94 : return F("bY5444A85C3281262703077AA90040254A1AED9189683FF741015BCF9C9FD17914758544A14121969793DAA718C7C091F9E26BF16197828BD514A4E66C5460849605A64ACFBD3D3167332F6AF040711E426CBF237DD6802A"); break; //WEH.07.27268132 + case 95 : return F("b394493444993671216075B197AD00000200C13850441004C13286138A3F900426CBF2CCC081345574000C2086CDF284D2302BB560000326CFFFF046D330BD62497B485F8"); break; //QDS.07.12679349 + case 96 : return F("b39449344782049131707F5A37A480000200C13121902004C13000000D42000426CFFFFCC081353750100C2086C9F077F2A02BB560000326CFFFF046D0716952B9ADF80EA"); break; //QDS.07.13492078 + case 97 : return F("b3944934462526513180768437A880000200C13060400004C13000000950300426CFFFFCC081398000000C2086C9F0D7D2A02BB560000326CFFFF046D320B862BCC358012"); break; //QDS.07.13655262 + case 98 : return F("b3C4493440989323533372A78728903252493443307C50000200C133698392007004C1331430400426C7F2CCC081319DD26200700C2086C9F25326CFFFF046D058B67079026F78582DC"); break; //QDS.07.24250389"); break; //QDS.37.35328909 + case 99 : return F("b6644496A721102551437F5C77224831715496A000726005005827161FD1AB240AE86C2A6D7F691E4C8531E4530AE4FC8A294BE87862FDDDCE843D7679005C55E082A744BC18EA87FF12298AE4258EE9D89B1F9511318B8D7152464FB11007F5CEB827893513C954A6E9735185FE268124771D567A080E8"); break; //ZRI.07.15178324"); break; //ZRI.37.55021172 + case 100 : return F("bY50449726041331160007728499181897A60030E10030A59E74DF73596296EE08CF3F1BA88B47A3A264C30177EC921B750B03B99F992A0EEB064560EFAD6C5EC7CCA1009D72C63B0E79000000000000697E801E"); break; //ITW.07.16311304"); break; //ITW.30.18189984 + case 101 : return F("b2F44090773754205100794947ADD100000046D070DBB2404130F000029E0000259F0D834FD17010000000424132B5729820001FD7462313A802A"); break; //AXI.07.05427573 + case 102 : return F("bAE44EE4D449858203C07C8B87A0100A0257AB76440C2E16196857D0FAC3205AFB9D036CD7885C1F60C61095F2300D08DF56026E74FFB2F876BD89D27F65B3EA3729F53B26A48F2A5684EDD67A16177F8DD127C2CD8FE1C42CD5035E7EE110515C7369DB07AA59D5954E077C30AA29423D12429C77F6A7DEF679B3A90D7FD075AB7ED262466ECB4FDB66C609FC5DCBEA89FBCEB7BAA4EB8C312CF1A242B39A696A25E81CF0B5994B25CBDC06749D29F5B0F9E9F98476FFF9ED428840C0082459878C8FCEBA90EC380F7"); break; //SON.07.20589844 + case 103 : return F("b4344010648020780011656A78C001D900F002C2561675D61AD80F90FDEC404B8CAB47A80032007100A387268EF9F9CC8106E5D7FEE6E9D41D7E8780E2B18C2F71743F96AC442C6191D9B8E8E2AEE85F1"); break; //APA.16.80070248 + case 104 : return F("b2E44685017467703627254FFA0009F299A23A02C3A000008060605050B45060504020407060412140C0F0F100E111BFE070B0A0908C0EC81DC"); break; //TCH.72.03774617 + case 105 : return F("b2E446850812896626572C47AA0009F290D1620272200060001018DE4606A430F1101000701010302010403020403DC700002050302E7F581EE"); break; //TCH.72.62962881 + case 106 : return F("b2E44685007457014707281B0A0009F270400600A0100000000000001A1A60000000000010000000000000000010086A10000000000FFFF8007"); break; //TCH.72.14704507 + case 107 : return F("b2F4468509851603374725693A2069F27CE00600A600000000409090A8C140B090C0C0F0E070F0C0D0F0E0E0B0F0A640F09090D0E1009932C80FB"); break; //TCH.72.33605198 + case 108 : return F("b2F446850396450729572A1CAA2069F27FC09800D3E0200000238383EF87E353F3A3B3A2C2E1E2B3830111E2A181FA0AB2432273805208FCC86D2"); break; //TCH.72.72506439 + case 109 : return F("b76447916987435614037E4C2729646866079161102FC0060058CA7D7567090FFC84CBDE4FE2996BF8080E6A2C41D6DF46D8921894C814CC0BB36C550312F03A2734512ED7A69349DE3C349CFC079B62A3AD93BAA84A087C739785EFC9A415F6AF0662B05401FD0C4C9D4A676DA7FC1F6C592823EA6B6DFCAA3DDB2E4D5B6E87C5EA1B92E903D62"); break; //ESY.02.60864696"); break; //ESY.37.61357498 + case 110 : return F("bCE44A8154457060801022C397FDE00C005F4FEE3A225126DE3E8344CEACB8502C615B4F7EE9D9CA99F2E3AB5AEA9B3417ABD2B8DF835C0A8C31510DC184ACC8E261E24B717F51C01887D9B39D57965A4004CB68B65206E173F7374489CCBBAB63D4F4B33B488DE06DD33C93EB719BDD805E331238755D22C7E94ECD3636C1CCD965CF4E6DC37123EA8D95771BBCD12431AD12B646EBD21FCB77BD2D100C9CCCE7546268B3AF080DEC8F6B61BCC209013295A74A2730D9CB11E52056D0C0879EA29A2CE24210EAF58587855A790FF343CF82914E0164ED08C70FD54DB800BD9B1C0F2431883324E43A1D293"); break; //EMH.02.08065744 + case 111 : return F("bCE44A8153132000801022ADC7F9000C00546CF1AA7C3268079B9F3A0D8D2FA9AE941DDCDA1D0D8CFA6358FB9FDAD0AF38BB344D954ADD742E77428CA48DD918F361E23D5805BA6BB4CD2470016F66B92CF5D2AF69C7751F1FD2D887A10F26865E6AD95F58754980416935DA7A6C669823CDA9A3CF4D0EBE233D7F706DA6ECFD8209C8F140A7666B9AB2D9ED8C0D5AE04C3600B0899207B54AA98FABF9D14F773F41A53378E9A5678516B95EDEDED334821972EC196927F794E72725C78300FE65155E4E49B43A329EE44AD6FD90070548499CCFFD9FB71ACB4183B4B14DEF7D8B99BF02B754E651850960D80F6"); break; //EMH.02.08003231 + case 112 : return F("b7B445A1415200000023724958C2049900F002C259D7515009EC6163C4A7CB4E8935772324371005A140102490050646D0710FDE80DD548AA00BBCFEB3152BF11CDD91D4D31F1C73144BBB17696622104EB91D19A32FF7CA939126767495134EE598AF96AC9F0081A83B4D7EAF7A497981C15604C85E4E3B9FBA393BDAD8E0DED15EED4BA887D9970D17797849FE68045"); break; //EBZ.02.00714332"); break; //EBZ.37.00002015 + case 113 : return F("b5B445A14152000000237E4CE8C2048900F002C259C751500003AD02FC41ACF50E92F72324371005A140102480030E8FC8710B2BC8D30DC227AD803ED24F3B6FCC6E5131442E65A7F5CC4589D51AE2FB2690E9457810BDAAAC81988A3E5E81E6CDA24BE256218D907511C8044"); break; //EBZ.02.00714332"); break; //EBZ.37.00002015 + case 114 : return F("b1E44C418557901000102E4437ADB00108561D52810CD237CA87FB7C5A2F62A65C25C457BF78028"); break; //FFD.02.00017955 + case 115 : return F("bY4344471325798761013672193170604713010210000000000004788F419E030DFD110E39313133303730363030475A4431060200000000000006823C0000000000004E88"); break; //DZG.02.60703119"); break; //DZG.36.61877925 + case 116 : return F("b7B447916419806613037A83A8C204C900F002C25B4AA0000CC2128E94C8F3D946F737210552961791611024C00500ACF0710FCFB475BDA1FD49D52FF6FB45E833D5D97609373AB3EB562E01CE23D1389FFEC7EE41D4E7B20D35D8B80581C289834F4E3C542C09B0C37331332A321B79DAF7F60CDB028452AE3A26291EFD25C87DDC9EACF462C7B441510340F755C800B"); break; //ESY.02.61295510"); break; //ESY.37.61069841 + case 117 : return F("b6B44791641980661303756A58C204B900F002C25B3AA0000ABEB03EC47E933C072B97210552961791611024B00400536871036D216BF2B74E11F1952539F406B7D4DB7721B1154E21C36F0F55BD4B5B5FF9977572BCD27D93A909347A0D84AE9E804C361E9E6D98F9BE296F76E3A5100357CDD3FA09AABE44103EB508044"); break; //ESY.02.61295510"); break; //ESY.37.61069841 + case 118 : return F("b73447916856565601002F8DC8C0037900F012C25809A62002B5C02299AC829AD82267A370050471010A9AE87B893A51E226DD3203AD775D84E2B2E04D96F85DA0CD258EBC10912241ACAEB1406433A637F6C70811B7FC99565C388A0365A9B57F94E0380317F5CA1052D6FE55C7BE3118A4D1CD05AABC646F5D288B129D7934E68CF030A"); break; //ESY.02.60656585 + case 119 : return F("b7B447916419806613037A83A8C20EC900F002C259EB10000F76F8B1B2D9E402B9498721055296179161102EC00508B8E0710072DE1601CB75C3C9C30E9E037024B1D516151D3724CCF1654B2AC7707B5B41F2BBE3F2C19E9467A0740AB6A4F7F03F5E764FCCECC689EEA66BB4A9A6F25FDDCE8A60E9D998A43936B8A3B2EB57A8F667B476D1ED1CD2381D0ABF6118033"); break; //ESY.02.61295510"); break; //ESY.37.61069841 + case 120 : return F("b6344FA30883161560002C10A8C2042900F002C2549030000BC2C8A72651D570AEB967AA7004007103CB056B91B8007B8882351411FD19256641A220725C724891287445B85FDFDA2DB638B542BB7FC7209833DE16EDCBB90FA686C10076EED63BD40AB0EE3EBCDFDF40032F5C0DCD66322BE804A"); break; //LGZ.02.56613188 + case 121 : return F("b6B445A14043300000237C1FB8C200E900F002C250E000000F96A649A04D7DC457E8972807759005A1401020E0040A6D20710A07B663F2ED91A0DEA4515C0C1D4A296569A7C4DC27AE724F38CF0E518949AFAA9C3AA8703638F5305E2A333941756C4F5BF4703A411B7FE92F58D7F2724E31E10DCDCBF2C7EE18CD4738043"); break; //EBZ.02.00597780"); break; //EBZ.37.00003304 + case 122 : return F("b5B445A14043300000237FF3F8C2001900F002C2501000000574262230ACE2FB2FB5072807759005A140102010030303C8710DD05806D5E2EFB0ACD9DA1964A191D7BADA8E1A508EE7CFA86336B14B1C756AA1E20FA5CE029D2CE99CC84BFA0CAFD723A5D0BC20E6FECC585FF"); break; //EBZ.02.00597780"); break; //EBZ.37.00003304 + case 123 : return F("b4E447916110000600702D8607A99004005860F4BADF0716289AEE56290239E4549E908B33CF4C280DEDD3382DF293865824ADFA25EBDDDF28DB046A59DA2A4C2DB62CF177F2E77EF3E62D6A67DEA6BBD01BEA1DFB9ED3DC8743E2E"); break; //ESY.02.60000011 + case 124 : return F("bD344A815394643100002D3DD8C2003900F002C25741E0000A17997475A31870EDCF27A0300B007101E6BCA68B34F4603824A04FC0B87A398438300B31366E3B94F45C0EEBFF210719F87A8382509BC329B59A4031ECAC4CA734374B06825329A3665EAA2C626DA096C8E50002E95443D540F92C90EE305931E8E066BB8A76AA2DDE94042B90B94E9D3174612DBF8755145BBA760A85B7C84DDF075950FFDE6EEB4EF76A664F4A474CE050E12021434806BB9C4CDDA5CA8F13DDE8010C5DB0EAD57FD5E6DF042A1C0AE83DA23EB2B8C3444A11D8A6F6274072E516F42DA449DC460D14C1D9E12F95CAE43112976493AD493F0"); break; //EMH.02.10434639 + case 125 : return F("b8E44A815262292070102C8F57FED00800592BC9808524F745DE09733D6B862F1FEF9AC816CCD59B730C0BC8D173E7B1B187735C505768A284780C3B7E53CCF252EC84F44DF2A8949DB12139FD80D000930321F57E73C8F22B44AB57C03F93C35B02B853E45A0960F0FCD326F4760CA76945EADF6F294356AC8308DE284EEBCECB57EDF9BB63BCC5D424A764348B2D40E86C812AEA58CA14B652DD3853BEF5BDF56A27F8031"); break; //EMH.02.07922226 + case 126 : return F("b5344A81594176710020267788C20D7900F002C256A000000E4D7497D043A0EE5B2A47AD7003007102F390C301AD7CB52A6B8633CA25AA26BDE4FDF94F3230E43CCBF66EEC0D4C0C7A6E66310DC6376768FE891C0CA84DD365D3FBF23690BB55E812B"); break; //EMH.02.10671794 + case 127 : return F("b2644AC482711000050378A347201271100AC4850021B0000002F2F0C01C103895936002F2F2F2F2F2F2F2F84F48029"); break; //REL.02.00112701"); break; //REL.37.00001127 + case 128 : return F("b7C44361C120001000002CA9C8C203F7A3F00000004050000000004FBCBA782750000000004FB82F53C000000000412B22A0000000004FB140000000004FB943C59F00000000004FDD9FC010000000004FDD954D8FC020000000004FDD9FC030000000004CF6EFDC8FC012909000004FDC8FC02F10400CDDC0004FDC8FC03F104000002FB2EF40101DC37FD1700DE8C80FE"); break; //GAV.02.00010012 + case 129 : return F("b3244361C373601000102603A8C20457A4500000004050900000004FBDA3482750800000004FB82F53C0000000004C3AE2A2415000001FD17001EB2801B"); break; //GAV.02.00013637 + case 130 : return F("bY394447135523636001027A830000000478232D9D030DFD110E35353332333630363030475A44310602ED8B0000000006823C00000000000004E4802B"); break; //DZG.02.60632355 + case 131 : return F("b314493447236379635085D337A040000200B6E3103004B6E070300420D0E6C7F2CCB086E310300C2086C9E24326C1422FFFF046D240E86250E4E80E2"); break; //QDS.08.96373672 + case 132 : return F("b494493447236379635083FD9780DFF5F350082030000F00007B06EFFC6F5FF310300007F2C070300009E24310300E13000008000800000000000001F007300A145C9006BFF64003D000C002F046D200E86255AA081DF"); break; //QDS.08.96373672 + case 133 : return F("b494493447153871216062D53780DFF5F350082DA00007F0007C113FF8331FF969799997F2C279899999F2596979988C999000000000000FFFF000000000000008B35000000FFFFFEFF00002F046D25068C2608D2803F"); break; //QDS.06.12875371 + case 134 : return F("b344493447153871216069A667A8000082004ED3926096C2701FD0C110157046D17138F2602FD3CC2010DFF5F0C005FC50861FF000006130701FFFC138B803F"); break; //QDS.06.12875371 + case 135 : return F("b3D44934417196746221AD6FF7AA210000081027C034955230182026CAC3BB62181037C034C41230082036CFFFF0238E2FD171000326CFFFF046D0311B62102FDFE8FAC7E19004F33802D"); break; //QDS.1A.46671917 + case 136 : return F("b3744934417196746221A40247AA310002081027C034955230182026C5AE5B62181037C034C41230082036CFFFF0238E2FD171000326CFFFF046D0311B621AD04802B"); break; //QDS.1A.46671917 + case 137 : return F("b39449344775149131706E1D57A680000200C13750000004C1300000010FC00426CFFFFCC081358000000C2086C9F61212502BB560000326CFFFF046D070B8A268D5880FA"); break; //QDS.06.13495177 + case 138 : return F("b4944934477514913170662C2780DFF5F3500827B0000810007C113FF5A69FF75000000FFFF000000009F255800004659000080008000800080008000800080009B248001000000000004002F046D1F0D8A266CB280FA"); break; //QDS.06.13495177 + case 139 : return F("b3744934484145047231AAE907A9600002081027C034955230082026CD1DAFFFF81037C034C41230082036CFFFF02DDAAFD170000326CFFFF046D0503AD21AB3580D9"); break; //QDS.1A.47501484 + case 140 : return F("b39449344843350131707BA4A7AF00000200C13000100004C13000000C11300426CFFFFCC081361000000C2086C9F6DF62502BB560000326CFFFF046D370A8A26486681E6"); break; //QDS.07.13503384 + case 141 : return F("b49449344843350131707395D780DFF5F350082000000EE0007C113FF4BC0FF00010000FFFF000000009F256100009FB5000080008000800080008000800080009B248001000000000005002F046D020D8A263BD880E7"); break; //QDS.07.13503384 + case 142 : return F("b3C4493440989323533372A78728903252493443307C50000200C133698392007004C1331430400426C7F2CCC081319DD26200700C2086C9F25326CFFFF046D058B67079026F78582DC"); break; //QDS.07.24250389"); break; //QDS.37.35328909 + case 143 : return F("b2C449344098932353337D4E7728903252493443307C000082004ED39ACEB2C06702501FD0C10046D1C06902602FD705D3CC20189FB81DA"); break; //QDS.07.24250389"); break; //QDS.37.35328909 + case 144 : return F("b5344934409893235333714F478077989032524934433070DFF5F3500D11E82CE0000100007C113FFFF362007007FCFC92C314304009F252620070020029102810C8E02730241023902940287023F0254029062770227012F046D14108D26710885D5"); break; //QDS.37.35328909 + case 145 : return F("b624468501509651494085A758C002A900F002C25DECE080028421E778E39B0665A707ADE0030071080A1255F4529D6628D1BD017B641EF0A8046B680C77DAB285B3C2A943522663000821E48556555C93D048F5DF327EFA4BECCA1914A1C0F9EFCE6532756F5E9BF68B0E01E8802D91270"); break; //TCH.08.14650915 + case 146 : return F("b31449344401892903408DFBB7A9B0000200B6E4800004B6E14010042A7D46CBF2CCB086E480000C2086CDF23326CB9BCFFFF046D0E0BD624CF16800B"); break; //QDS.08.90921840 + case 147 : return F("b314493447236379635085D337A040000200B6E3103004B6E070300420D0E6C7F2CCB086E310300C2086C9E24326C1422FFFF046D240E86250E4E80E2"); break; //QDS.08.96373672 + case 148 : return F("b3444EE4D774933221608D1BB7AF7000000046D280DBB24036EEB000059A9426CE1F7436E00000002FF2C000002598620C80B0265F10802FD66A000779E80EA"); break; //SON.08.22334977 + case 149 : return F("b2E44B00971280018540843227A0E0000202F2F036E0000000F1000016F1B8563822A0000E70A812A000000000000AF010000000000FFFF81DD"); break; //BMP.08.18002871 + case 150 : return F("b2E44B00971280018540843227A0E0000002F2F0F0000000000000000718D00000000000000000000000000000000FFFF0B2A00002FF97381DE"); break; //BMP.08.18002871 + case 151 : return F("b26446532392238253508D6A07AAF0000000B6E0000004B6E000000422F866C7F2C326CFFFF046D2D0A83279B6780E8"); break; //LSE.08.25382239 + case 152 : return F("b62446850189272149408C4E28C00CF900F002C2564B20800A81E8BCCCA14532696097A6400300710F61F531C03426B9317EAD69912E862AC2017148D8C179D50E133470B7A04CD063D00E6FB1C522DDDC80A3300335E26FE16F9D339A61C0F41BC1ACF4A0A8A29310674536C344CA64D7D"); break; //TCH.08.14729218 + case 153 : return F("b434468501892721494083F2A8C20CD900F002C255FB20800903D2653461ABE7080E57A5F002007103032214C1915B7A16175B00F90B8EB889A4C280207D9C74F5A4088C584D951BDB20851C3DF9E"); break; //TCH.08.14729218 + case 154 : return F("bY2F44C5145935816213087A080000202F2F046D0F2EBB24036E000000426C9F25436E000000317F00346D00200000F1458737"); break; //EFE.08.62813559 + case 155 : return F("b3E44F536861202000108F54A7A9B0020250A86DF3204D8B7DAFBD62C57159092FFCBB77F612E656C59AD065C96CC24B353B024A6930F800C00010900E10E03005DC1207F1B05074A5380F2"); break; //MWU.08.00021286 + case 156 : return F("b2E446850844616516180E459A0015C284604600A7200003900341D9A5C477E9ABC873D05000000000000000000019BB4000406456E897887DD"); break; //TCH.80.51164684 + case 157 : return F("b2E4468506974806164805122A001DE26EB02900D570200000000040D21820D4E301126353030334B44170B0A01004EE40000000000FFFF83D9"); break; //TCH.80.61807469 + case 158 : return F("b324468500441169269802F7CA0119F272F01600A3B00C8082F09000007730000000500000220140B1807030000007111000000000000000001C29A85D5"); break; //TCH.80.92164104 + case 159 : return F("b33446850710351129480ABE9A20F9F270000D00E03000128090B0900DA3600000000000000000000000100020000274800000000000000000000FFFF80E3"); break; //TCH.80.12510371 + case 160 : return F("b4944C51402203571000451A77A090001202F2F046D2E299926040687ED7214000001FD17000413F6670400043B009378000000042B00000000025B1900025F1986B90002610A0003FD0C05000002FD0B3011F52BA393"); break; //EFE.04.71352002 + case 161 : return F("b2844C5146427807103073D877234626016C5140007D72000202F2F04DD1C6D2F3498260413B96E010001FD1700066080E7"); break; //EFE.07.16606234"); break; //EFE.07.71802764 + case 162 : return F("bA644C514960080900307DABF7296008090C5140007ED0000202F2F426E8D6C7E2944133C08000001FD1700840113039188130000C40113D611000084021324108D5A0000C40213A70F00008403132C0F00003550C403137B0E0000840413C0080000C404749913650800008405133C080000C40513AD831B07000084061380050000C406138401006999008407133A000000C407133A00000084286B081300000000046D332A8F260413A7137132000003FD0C02032102FD0B01114D8480FA"); break; //EFE.07.90800096"); break; //EFE.07.90800096 + case 163 : return F("b4806AC1956030015020363917256030015AC19020323000000466D0009780004872B000D7811313136353330303028633531343530303030308940FD1A014C933B263A494700004C130546000001FD67030D9A8030"); break; //FML.03.15000356"); break; //FML.03.15000356 + case 164 : return F("b3644A511621280223837CE5E7241022436931581038C002005A8F458578136DF07A14CE37F82BA702DF936647F231F18C961CF7A6CE31CFAACE57153A8888B"); break; //ELS.03.36240241"); break; //DME.37.22801262 + case 165 : return F("b1F44685034025063591B28F57AE100000001FD17000265EF070F6A18DFC253E0F351D0900E8180F9"); break; //TCH.1B.63500234 + case 166 : return F("b294468501904601473F0AE14A0009F27EDA5B130CA280080770001045667006BA1007CB2008DC3009ED4000FE50096BA80EB"); break; //TCH.F0.14600419 + case 167 : return F("b294468508220285376F0F19BA0009F27A1280028A128000033000006BC4C006BA1007CB2008DC3009ED4000FE50096BA80DC"); break; //TCH.F0.53282082 + case 168 : return F("b50446850920420745937163972612600006850FE036B0000200415CC4CB0551F0084041552FC1C0082046C7C228D92D804951F1E72FE000000006F1BF114A212D1B377124C1EA62E83430E5006511443943F9B47F52901FD17002F1F2F800E"); break; //TCH.03.00002661"); break; //TCH.37.74200492 + case 169 : return F("b3644685005012040714351C0A004372900000060DA4E029B5FBAC4123A84170DBBFBF13D06000000000000000000AE3800000000000000000000000000FFFF94A6"); break; //TCH.43.40200105 + case 170 : return F("b3644685005012040714351C0A0009F298F560290E10101A40000FFF719F04E99E7B2F9E2E512000000000000000042B000000000000000000000000000FFFF95A6"); break; //TCH.43.40200105 + case 171 : return F("b5E44496A973430000D1AFCF97AF7CB50057AB6BD92ED8A65D4DB8A19DDA1B6D3CD164A0F600C93485BCFC48263B255C4FC57033B6114A4DD1590F6E3B22855F7161BBFB100973B49CDB3593DEC5164ECF04F1CAB0311E89B873ECECCD7FBF0D60D125734B551865D12F7D012748025"); break; //ZRI.1A.00303497 + case 172 : return F("b4E449344492512971437674F72090328039344141A7510002081027CB4ED034955230F82026C8927C1027C0354466C2C230FC4026D2C0E892781037C034C412307BC3282036C892702FD171000326CFFFF048C536D2809BA22ECC883DC"); break; //QDS.1A.03280309"); break; //QDS.37.97122549 + case 173 : return F("b4E449344505427971537894372380266079344151A6203002081027C8B4A034955230282026CFFFFC1027C035446B3DE2302C4026D1107632681037C034C41234AE90082036CFFFF02FD170008326CFFFF0469C16D000BB822FEF28024"); break; //QDS.1A.07660238"); break; //QDS.37.97275450 + case 174 : return F("b3E44934435188745211A19F67801FD080D81027C034955230182026CF8CB932381037C034C41230082036CFFFF0359F5FD17300010326CFFFF046D060A8428027576FDAC7E5F0192628012"); break; //QDS.1A.45871835 + case 175 : return F("b3E44934455319745221A29607801FD088A81027C034955230F82026CB7439C2381037C034C41230082036CFFFF037174FD17500010326CFFFF046D260B862B02842AFDAC7E8200271080FB"); break; //QDS.1A.45973155 + case 176 : return F("b3E44934404155047231ABDD57801FD084C81027C034955230082026CCC02FFFF81037C034C41230082036CFFFF03E0CFFD17000000326CFFFF046D080DAC2102EA18FDAC7E11005C3E80E0"); break; //QDS.1A.47501504 + case 177 : return F("bY60442515485001000C1A7A23005025568AED71E43AF834900BEC738E08C4FA2637B8915FB401FD6296F19C3AEECEEBC3164B967CD5445E6AAFE90F416314191CB1839210B7CD2EFE168911FD465DAB56CCDA9C82862B90F29353AB57532B49E67E"); break; //EIE.1A.00015048 + case 178 : return F("bY75442515639716000C1A8C208A900F002C25A7000000DDCE55D203E089D07AA800500710760097C0A7F24E9681882D62EFF802EC33146C9B3828FD5B2026432F40E7098DA78C4538579DDE260B2DCCE933093DA312A2C499D4473F150422121279632724B2FCB44A2110D2A2DA87B8C084512CDD698F"); break; //EIE.1A.00169763 + case 179 : return F("b5E442515954400000C1AA17A7A74005025F6B841CED5F1892796E8217F31F08E864EF5C0BBBDFE640AE3711C34C4B5B8AE3B821F1F0F3FF81C8259CBDABD6D05A0A751305C3399E9450DE8E86BE0BDB2D7AFA79BB10179B7EB1F37983CB8C7F10746888DFA54B4CD95AB8C78018025"); break; //EIE.1A.00004495 + case 180 : return F("b5E442515695800000C1A452E7AF200502547F361FEDBED8040998A4AF106CE368D0D469CFE69DD1983E5D5A84078AB4F4F2AFD97FD57668A660038C14F4B79CC3CAB703C3C4ADB6B19AE027E25C4E157B23E9A4D5A7CF24F4962BD29591A73F3E3BD13C9F26D15826364C2DFB28051"); break; //EIE.1A.00005869 + case 181 : return F("b37449344981002451F1AF6837AC418002081027C034955230082026C7CB5FFFF81037C034C41230282036C6D2A027047FD178400326C962A046D080FA623CD2B8AD1"); break; //QDS.1A.45021098 + case 182 : return F("bY5844972642631092001A727299291897A60030B21340A5C84E203CFF62E039C2A1F61CF679A05B7DA7F31E4F0AAA0F30EFFECF4AC176AC9E173C426799C618D50A4B285CBB9074CDF78FA733C7AEC4F66C45D760FDFEE2327E8016"); break; //ITW.1A.92106342"); break; //ITW.30.18299972 + case 183 : return F("b3E449344981002451F1A2CED7801FD08FB81027C034955230082026C61FAFFFF81037C034C41230282036C6D2A034D22FD17840018326C962A046D0A0EA523028B4BFDAC7EF0002E078AD5"); break; //QDS.1A.45021098 + case 184 : return F("bY5044972694376092001A7A3E1340A553D753D0583A78B2BC306DF80BA1DBF6FC88DAFCD83AF7D955EC6196B643A571494B99AE831F8894A4726042E23EA5C474411A585EEEEE8E84A15F54562C31168159804D"); break; //ITW.1A.92603794 + case 185 : return F("bY5044972625353893071A7AE40040A517031B1A58F312C641E1E45D19F6DD3EA9B61FC929D70F39747F6A8A3BA53D7ED25B2A86C741728467DADC3652D54F40660B397E72F60CE3434006A1D843B3248D9C8016"); break; //ITW.1A.93383525 + case 186 : return F("b1744242349075722754982E471F202000001FD0C6202FD173000CFB38EF8"); break; //HYD.49.22570749 + case 187 : return F("b1744242349075722754982E471F602000001FD0C6202FD17300044308CEF"); break; //HYD.49.22570749 + case 188 : return F("b1744242349075722754982E471FC02000001FD0C6202FD173000B52092F0"); break; //HYD.49.22570749 + case 189 : return F("b1744242349075722754982E4711402000001FD0C6202FD17300084489CF0"); break; //HYD.49.22570749 + case 190 : return F("b63442D2C272951803504DCB48C2064900F002C251664000038AA5E8D66325C253B6B7A6400400710EDD4746D6402CF31496EE7AE09E634270E5701ED9E5D16E7A5A22EBC15B0CB6AC0EF980F73E5AD3BF6E658AFC24F614AFBF844AD1EC8CA21C0FCF8FC2E9E64C0B28542EE8C7EA37B444A8036"); break; //KAM.04.80512927 + case 191 : return F("b5E44A7329022226704041EDE7A7500502599F38B5BB9B53F705A6B158D76D3C33F390AE5F6E48A051680C3B866F317F4DBC781E920051DB2619F768DA54EB632DA8746E483A5569A9D8C0E16905ED61857D1B9A07C6EB6AE501B22E0D55A7DD4AF67DB88D6DDCCA5B78E5B88528014"); break; //LUG.04.67222290 + case 192 : return F("b60446850090510825937364F8C0039900F002C2584340D0063667A2334810387B25C72989280612423FE048500307DA907106591F67C43C0B36FCA410346B6A06E7CAADE06D06CF2911ED2775E3297F20105876C245C9309EC93EA0F68B3F9FA466371C73B4A39B80FEBAD1F9C40758028"); break; //HYD.04.61809298"); break; //TCH.37.82100509 + case 193 : return F("b62446850189272149408C4E28C00CF900F002C2564B20800A81E8BCCCA14532696097A6400300710F61F531C03426B9317EAD69912E862AC2017148D8C179D50E133470B7A04CD063D00E6FB1C522DDDC80A3300335E26FE16F9D339A61C0F41BC1ACF4A0A8A29310674536C344CA64D7D"); break; //TCH.08.14729218 + case 194 : return F("b434468501892721494083F2A8C20CD900F002C255FB20800903D2653461ABE7080E57A5F002007103032214C1915B7A16175B00F90B8EB889A4C280207D9C74F5A4088C584D951BDB20851C3DF9E"); break; //TCH.08.14729218 + case 195 : return F("b48442423240756341200933E7AA0303A31A074C27AB1B79A4BF71E2818DAA788D064B94612F5AED2C06E10F1A022615C7EA6E4E97D999D450C33C358340DCB3D948F7F9B58E2B922ED1A580BA905B4E34388A184D5"); break; //HYD.00.34560724 + case 196 : return F("bY5044972670314082001A7A120040A5AE9E0AFE53E0E5216516C41E94CCEA4220BC25A8A5CCF38635E315900BA6BEB0CB5E343BF419524FFED59CD28D106314AC875F9812782700A8267FFCDB4A24251099804A"); break; //ITW.1A.82403170 + case 197 : return F("bY5044972670314082000A7A7A0040A5CE2F908D1B6C7FAB19CF06F0EE140BB44A84C7FF54BDA05D33D6EE45686D054984A4467283EDA6514E8094E361082D9555BD043A64D3F593BAE29C577984921E3CBC92D7"); break; //ITW.0A.82403170 + case 198 : return F("b3B44931536000000013721968C30AA900F002C25BBD101005A558A6E08987D124F027212334938931581036C0010657B0710B23E83B33BD1C8F5A3AB0DAFCEFB35C1D44718C68011"); break; //ELS.03.38493312"); break; //ELS.37.00000036 + case 199 : return F("b2E44B05C95720000021B556C7A500020059C8692AAFADBDBCAA36875B54901F2E32655B735A59AB899223306CD8402A02D189C816E86BB8061"); break; //WEP.1B.00007295 + case 200 : return F("b3B449526564412004237BD198C20E7900F002C25641C00002B7452AB08B6F3843AA6725644120095264203E700108D660710B78BE5BE2867BD38DCE24619A59D0A6BB9384E3A80E2"); break; //ITU.03.00124456"); break; //ITU.37.00124456 + case 201 : return F("b2E44A5111863054230037FB57A30002105DE7DCE381F74E06136FEB49A5B3D45B688341DDCF387CC0D6344DF5BF60078C7A596B1A0D3BE8020"); break; //DME.03.42056318 + case 202 : return F("b1B44A5110301808238379BA77241022436931581038A88000002A7184A0AD900E327803A"); break; //ELS.03.36240241"); break; //DME.37.82800103 + case 203 : return F("b2644AC488437000050379BF37201843700AC485003210000002F2F0CFB6E16038161002F2F2F2F2F2F2F2F2C138057"); break; //REL.03.00378401"); break; //REL.37.00003784 + case 204 : return F("b3644496A855900500537290F7285590000496A0103CC002025CF5138AEB21021CE8339724700D0AF89B3CDDAAE2BAD28479AC27ADBE1E3C3B849269E632772E54C"); break; //ZRI.03.00005985"); break; //ZRI.37.50005985 + case 205 : return F("b1B44A5110301808238379BA77241022436931581038F88000002A7183766D900E3278003"); break; //ELS.03.36240241"); break; //DME.37.82800103 + case 206 : return F("b3B449526404107004237CE7B8C2076900F002C25832C020029B8AE8C5A07F337A5EF72046318043041000375001016F10710C9B050BA32F8730DFCC9465A1C3385BA84D8190D801B"); break; //PIP.03.04186304"); break; //ITU.37.00074140 + case 207 : return F("b3B4493154809000001379A2E8C2028900F002C252907000090080FACAA513D7A7B7B729549120430413A03CB001054A107101672D7C39DD223F7A8D3C4FFF7E9CA294237B1AD83DE"); break; //PIP.03.04124995"); break; //ELS.37.00000948 + case 208 : return F("b1944C418637901000103C9CE7A690000A00414EE75620202FD08EAF2A1B38039"); break; //FFD.03.00017963 + case 209 : return F("b3B449526544412004237036C8C2065900F002C25943B00000CC9351967A937062362723991270492262203650810BBE30710483A983059AFE3C21836C683F23BA2B5A04EBAE38021"); break; //ITR.03.04279139"); break; //ITU.37.00124454 + case 210 : return F("b3B4493154909000001375BA68C20BD900F002C25BE0200004F4E34B29075C9986ACB722009210493150003B10010E2D407103C75563866FAC12EBCE6FC5829323547A3CC9A488057"); break; //ELS.03.04210920"); break; //ELS.37.00000949 + case 211 : return F("b3B44931558130000013727848C20DD900F002C25DE0C0000ADFB2D6B2E02C73267AF72011713419315250339001037AB0710A68555FAD7A29A1A875EE33FD26D13EAE33A7AF08035"); break; //ELS.03.41131701"); break; //ELS.37.00001358 + case 212 : return F("b3644A511870350133837198E7280409628931580038F002105F09DD43A485B949F2AB07122E6A6CB3E4BDF9055A351316D145C3EF8522BDF56D9D12495B281D5B0"); break; //ELS.03.28964080"); break; //DME.37.13500387 + case 213 : return F("b3644A511621280223837CE5E724102243693158103850020050075969BAC2F21DD6DEDFFDBDDCF9F0E9A7E066046DF920DF3BFE4DA1174DE1943F173A93C0E2A5B"); break; //ELS.03.36240241"); break; //DME.37.22801262 + case 214 : return F("b1B44A5110301808238379BA77241022436931581038F88000002A7183766D900E3278003"); break; //ELS.03.36240241"); break; //DME.37.82800103 + case 215 : return F("b2E44B05C10130000021B34137A490000002F2F0A6653020AFB1A5105E7D102FD971D00002F2F2F2F2F2F2F2F2F2FDF772F2F2F2F2F25EE8016"); break; //WEP.1B.00001310 + case 216 : return F("b2E44B05C77010000041B1E0B7AE60000002F2F0A6641020AFB1A8103251802FD971D00002F2F2F2F2F2F2F2F2F2FDF772F2F2F2F2F25EE80F9"); break; //WEP.1B.00000177 + case 217 : return F("b4E44333081400004032AF18B7A03004005E5AEF57BA739B9789BD9AAFAE16068AFF9FB85A70613B3800B85D28B409B5BDD9607BE2A1450EEE20137C663FB522F4E6B9E914E8E3795C577BFB32D6E0152C21EB0358C41DD6D9F76498020"); break; //LAS.2A.04004081 + case 218 : return F("b1E443330886102001E1B8E9A7A180000202F2F026584030778281E18ADDC240B0000AB01768017"); break; //LAS.1B.00026188 + case 219 : return F("b2E443330603903003C1B18AF7A77002025BB29E575E63C4AA6174A82CED44D5497FA0207F44D4518D8CFA53CD7024276A675D4E0621C0F80E5"); break; //LAS.1B.00033960 + case 220 : return F("b7044B40908794920101B6F8B7A320000000265490A42651F0A8201650BCEB9072265D70912655F0A62659905526576FB4F0A02FB1ABD0142FB1ABB018201FB1A36B6C60122FB1AB90112FB1ABC0162FB1AC24B1C0152FB1ACF01066D3B1D2EAA25000FFFBE95FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA00FFFFFFFFFFFFFF7B5382DE"); break; //BMT.1B.20497908 + case 221 : return F("b60449615347810630C1BE5957A8C0000202F2F026505094265F908822DF20165880822658C081265680A62655808B1785265680A02FB1A880142FB1A95018201130DFB1AE00122FB1A660112FB1A100262FB491D1A660152FB1A1F0202FD1B60030DFD0F817605302E302E340F6C04"); break; //ELV.1B.63107834 + case 222 : return F("bY2944961565181468201B7A140000202F2F0265E20842659A0802FD1B30030DFD0F05302E302E340F5E46"); break; //ELV.1B.68141865 + case 223 : return F("b1644AF4C40020041011B788C7A0A0000000266F3000266F10026FE800F"); break; //SEO.1B.41000240 + case 224 : return F("b5E442515695800000C1A452E7A590050252502B45C2E823EF856FABFC4775E28D2904492FB74BA65A843BA7E63BC698D83279AE2BE04B957699517818F7B33F8E58001A7C9CE0E73C5769487247954D0A000E811754BAB1CED0E61567EB1FE504B091E0C7DCF4632E3FAC31618804D"); break; //EIE.1A.00005869 + case 225 : return F("b5344E2306291001500030F388C30A7900F002C2583AE010032E1E493C32BEF51CDA37A430030071027A19EE14B0BBCAD656D0783516CCB7CFBC6AAFAECDCAD70020FE3DA54FCBC8EC2AED88DFD0972C55CF9336E1683574ABADBD046BB53623F8013"); break; //LGB.03.15009162 + case 226 : return F("b5344A732806139690404B70A8C2063900F002C25923338000C8BC361CE2EE050FD3B7A6340300710DEC49523134391877289A80A53A505655A833F754F221E619D08FB4DB5AD773EAB16B545B306C69D1493CD851012BBF4624A5DDA556AF07E83E5"); break; //LUG.04.69396180 + case 227 : return F("b9644A732460335700A043C1F7ACD0000200274DE02046D030D94250C804C0623000000446D3B177F2C4C060000005D610084016D3B179E248C010600000000CCB81D0106000000008C020600000000CC0206B190000000008C030600000000CC030600008B9400008C040600000000CC04060000000099348C050600000000CC0506000000008C0673DA0600000000CC0606000000008C070600E0F80000003C22000000000F0010004FF980F9"); break; //LUG.04.70350346 + case 228 : return F("b13440000000000DA00DAA8CF7101FD0C3A02FD171101CB938032"); break; //@@@.DA.DA000000 + case 229 : return F("b63445A146699750001026CE68C20D7900F002C25D7CE0C000B7C13179B38522166CE7AD700400710CDEF8D2A82F77DD15E367871F1E04261AAFAC430C2B55C1DED4A3148306D4C296CF10D72C9E79310A47DD73FDBFDF2CEA6490B6CA12A30EE5D64621A90B5E71F75D50D24C87B10E2ADDF802E"); break; //EBZ.02.00759966 + case 230 : return F("b5E44496A3680003888049D2D7A1D0050053FBA7B54810C548AC112ECFC76CE753AF07A625248C05827C843371AB5DC6C6C8D5D457E845B4B67FB4CEFF06720EA7A9112BFD0A96BC7E97D49FB9BBD59155D109433F0C4823DEA7A13E5281C00E4945F5B05D7518CE085EC8BFE738122"); break; //ZRI.04.38008036 + case 231 : return F("b1B44A5110301808238379BA77241022436931581038A88000002A7184A0AD900E327803A"); break; //ELS.03.36240241"); break; //DME.37.82800103 + case 232 : return F("b3E44B405399098502E0439DC7A0F70300530C7144B5962760A55DE8BA4E49C37676B0CD702698B5FBCE59E35E33D33F736AE13FB1C31DD43ADDC3FE7FF8E1EDC01D749974884BBF96580FE"); break; //AMT.04.50989039 + case 233 : return F("b5B4479169014216130377E5B8C2034900F002C256448000029E1A134984E32773DF97289000047791611023400302CBD0710FF4380B4AE49A140E94F319BE97049FDA8DDC96A8DC437F3BFB02ADC86082E9507934C7ED4FC6F4F678D613F25C09A1DDE927D817F5A824A8012"); break; //ESY.02.47000089"); break; //ESY.37.61211490 + case 234 : return F("b7B445A1415200000023724958C20A0900F002C25B4F60800C0E1D417100AD1BB6EDC72324371005A140102A00050F9B10710112A08DB9869998DE2C0D8614F76213F8682D10A8EF2951413C839461E8E3139EA62193E02B1584E6EC8EDB082AB70C6504F1ADF9E6ABD270E96FE8745AEB93C454FC3C9EAA2D5FCD6679E8A38A3E0818D4B6652993CEE5F8E514867801D"); break; //EBZ.02.00714332"); break; //EBZ.37.00002015 + case 235 : return F("b49449344100549253508227F780DFF5F3500824600007E0007B06EFF2BE9FF000000007F2C000000009E24000000DAC000008000800080008000800080000000E9F10000000000000000002F046D010E8625249880E6"); break; //QDS.08.25490510 + case 236 : return F("b9644A732370335700A045D187A440000200274DD02046D071189260C33FD0638010000446D3B177F2C4C06000000DFDD0084016D3B179F258C010641000000CC0DBA0106000000008C020600000000CC0206B190000000008C030600000000CC030600008B9400008C040600000000CC04060000000099348C050600000000CC0506000000008C0673DA0600000000CC0606000000008C070600E0F80000003C22000000000F0010004FF980E0"); break; //LUG.04.70350337 + case 237 : return F("b4806AC1956030015020363917256030015AC190203D8000000466D00AC9200118625000D78113131363533303030619C3531343530303030308940FD1A014C933B263A494700004C130546000001FD67030D9A8057"); break; //FML.03.15000356"); break; //FML.03.15000356 + case 238 : return F("b9E44A815242292070102881F7F4B0098050B0E989C939C3479F8904137236FE582B853DCACDD8DB48A717A6B42935CB977102079E6397B07AAD2A648E5B65E44D97F9A020B2BFAE433FA37FCB2A2C32711A5986B301D2F6E4A424C1144D808CE9D592C316B117C572689AC6C1322CC05E81F590CAAF457390F6B39DACC946FA314F8E8A34268157AC4338781C3EF5807F9221394DD1FAB5165E1261614B8B85758851295334DF52D9A4DCE2E1E17A555A21007D2DA802B"); break; //EMH.02.07922224 + case 239 : return F("b2E44B05C99010100021B65BE7AC30000002F2F0A6605020AFB1A33041AA002FD971D00002F2F2F2F2F2F2F2F2F2FDF772F2F2F2F2F25EE8008"); break; //WEP.1B.00010199 + case 240 : return F("b2E44B05C75000000041B8EF87A510000002F2F0A6661010AFB1A8905449802FD971D00002F2F2F2F2F2F2F2F2F2FDF772F2F2F2F2F25EE80F8"); break; //WEP.1B.00000075 + case 241 : return F("b1E44C418EA76010001034ECB7A820010A5597AB1CCF2014088590E64BCAB21DC1CC068DAA08035"); break; //FFD.03.000176EA + case 242 : return F("b4E442423245450514A07545F7AC6004005BDB5EDF3750DF41725EE867C3E39750E20B9F5FB092089B6A5DC7AA586101778BCD5EAD4995B102AC639F0FB4D12403EFE3554F72CAE4F5D348CC374F571CCE4A98634318027AAF3E7DD8600"); break; //HYD.07.51505424 + case 243 : return F("b3C449344454392352337ABFC727972126793442304FF0000200C050321648206004C0530240500426CBF2CCC0805098875630600C2086CDF23326CFFFF046D177FEA11D3242E1F830C"); break; //QDS.04.67127279"); break; //QDS.37.35924345 + case 244 : return F("bY5E449726900634160004728499181897A60030D30040A5D20022C396367C6A868B05FE2E9F70B6878070839C62E69DDC79CB409EBCAD68E950A6958B9B92FE6D1B700065B8BD52CB3035B93653FFDA3C3EF3EF6BBB1B450C7976874216AD188011"); break; //ITW.04.16340690"); break; //ITW.30.18189984 + case 245 : return F("b3444A73228188269040439327A370000202F2F0974040970080C06348AF03500000C14040301000B2D6207000B3BDD4A2322000A5A05090A5E0506F29780E8"); break; //LUG.04.69821828 + case 246 : return F("b9644A732170135700A0476A67A2F00002002747501046D3315952B0C3CF20637000000446D3B177F2C4C06000000F4640084016D3B179F2A8C010636000000CCB85A0106330000008C020633000000CC02067E6A330000008C030633000000CC030600009A1900008C040600000000CC04060000000099348C050600000000CC0506000000008C0673DA0600000000CC0606000000008C070600E0F80000003C22890200000F001000C94A80E8"); break; //LUG.04.70350117 + case 247 : return F("b5E44496A044550108804533A7A19005005B14A145C0EEC7C6FC18A85582753BE2BD08B6F0F9320809C5F28436A3388BB09145DF69DA51ED00DCCFE7BA2D6F86936D17E654489390BB7511CC4DA27A576A9612B1243151C634899A74D3EBDB2CA578CA4444F5740D74D3EC766628013"); break; //ZRI.04.10504504 + case 248 : return F("bD6440186669601001637060C7215067071010660047400C0251CE72725D9364386C4BF8A15AF4C722115F38B66DDE9F4B800D05A14F870E74492B8F57CB2282388B864D71416FDE0A74CA84735B59D1806BBBF8483B6B14AB580F0D5257E8CC06889EBA80AFB032BCEECD849E7E6A4639B5649B0BF5CBB57BF0993AE16EF7D88D784ADD9CE09284880D14D1502967798901C9E24ED6A04A3B26AE580B5D2AEC46804DEC1CBEDCB1E0B3FE1F84679620FD59E297FE8E67374EE9C34CA5A7F45B4B3709C6BD4E0B546F706DDC571C6469CFA90602C0E339A054CDE1D0A0E071651FD49FEBD485D8E561BB36AF7BED2741D35BBC88051"); break; //APA.04.71700615"); break; //APA.37.00019666 + case 249 : return F("bA944C514381355920004A5FC7A3D0090257403AC17355186FF933BAF0D0820041595970BD168489A746DF337AB01D1DBBA3EF7D486D74CCCEE777E57BD12A15D22B89AB4B4266D84B9C5C1DDBC437CD64807AF0B2B232E3A3C1B4DA568C9F8BA39FDF4565C170ACEF1918655B45D82E8BAAD769B88FA917E82542CAD596AB2145433599FFDDD3FCE889F657A8AC07FE5CED3F184244475B59710CFDCA44D7C3AE00CC021FA6EE3F49B77939529B49279FC526803FD0C05010002FD0B01111E248025"); break; //EFE.04.92551338 + case 250 : return F("b6E44A511485268614004B97F7A86006005B8D6D972C8E06EFB5AEC0FC750DB9DFFE62BB59DA183A5709DFC5029CEB2E44FEAF475DD2F3CF6D90544F29372A5C027DACA08536B2457CDEDEB76E36B281F4A0FD4A203FE9F7DFD337BDEA15D02F53A21CB281A3EF01E15D779B3018A99D0E3EF2FF946A63F419E56644BBDF8FB8010"); break; //DME.04.61685248 + case 251 : return F("b3E44A51159351969A004761E7A030030050F0020FC830AABCA7CEE4EC8E44524D98802ED5CA2EF3C89774FF800730951E02569BF91C156331EC9C29730FE2F437128D7E574D29C4E808047"); break; //DME.04.69193559 + case 252 : return F("b7144685009022004593720EB8C00EE900F002C252CA40100F5CDA57367A4436D244E72791670692423FE040600407D7C07108660CA27A4DD53871B12F96FFEF0F84E0CA88A2201BD794859D35CCD051F34327D04EAAE8772675F8E7F28DE2E515FBC9AF3A40E72C078304158D453511F2CF39DBF98DBE1EAD84F0F2CAD975EDDCC4F"); break; //HYD.04.69701679"); break; //TCH.37.04200209 + case 253 : return F("bA944C514381355920004A5FC7A670090251913406458376E6F9CEB817ABA85D9F26E5867EBA222FDFF496F2C8A312E593C80C0604576D7B5269B4A25BD15B314C0598FE3395611400AA7ADB705EE2120686208A449BDC5EE828FF048F669516585611337839C0A40A308F4DE619997F29D2438CE9EC263574FC60D42197CFA7B47528574792BFFF54AFF9193CA678242653A97DEBCB5E5333687846A875A69C4B7371C762C03A2DB5AB738D92623907896AEBF03FD0C05010002FD0B0111C6E48020"); break; //EFE.04.92551338 + case 254 : return F("b5E44C51475051512010425417A1C004025EEA5F744D756D853BB606F5DBB33DD7B26896D7370BD9C50990E605CE03F8F16DEE8AA36EF2C87E3902F933DDD87E1D383B7C647E8D2236E5FF5E1BE6742D65511FE1629B5CD3F6F0F800C000109002F680300035E2001020A0901C98008"); break; //EFE.04.12150575 + case 255 : return F("b5344A5115158536941043C9D8C00CC900F002C25986B0110B13D74311F4D1ACF88797A7E7031071066DEA0D815DFAC31E07763666D4C46C2DEA856FCEC34F2B5CCF3750F72BD8F924544E73C51D7DBC11A1AE31049E5D0E121CE0053AEB8E018805B"); break; //DME.04.69535851 + case 256 : return F("bA944C514381355920004A5FC7A79009025E37121BAC0ACF1A216281AE7A85DA20DF90613A83417418BD9BA7B0F09C192713A65DECD3ECB2DFC5299683A5B2669EE70851493FC9944D7579F7FCD44CCC839E432D498E40EFDF1614BD9B7E6F1B4AD96CC16939C9D061434790765D3883275B80DE0508393A0F00C1B1590A66F94D920BD5E80125C610F7C0B0346D8D0CFE8DD4E8A14370077D90A7BCFA59345DB13D7134E80D5F2F1D50B3B043075126DF42C2A03FD0C05010002FD0B0111ABC78028"); break; //EFE.04.92551338 + case 257 : return F("b4E44EE4D557648251B048F777ABE004025D84601014EEA5EDCC08B007BC8BB1EBB266BADDEC127897EDA4296EEB8EB05A57DFCA5190F54B41C05B1BF0F5EF82B719CD27EA6242263DFB94F589F38843A1146916B872141977275BD8035"); break; //SON.04.25487655 + case 258 : return F("b2644AC488137000050371BF47201813700AC485000D90000002F2F0C32C60E569405002F2F2F2F2F2F2F2FB90E8059"); break; //REL.00.00378101"); break; //REL.37.00003781 + case 259 : return F("b2644AC488137000050371BF47202813700AC48500CE20000002F2F0C068D16635640002F2F2F2F2F2F2F2F72188058"); break; //REL.0C.00378102"); break; //REL.37.00003781 + case 260 : return F("b36446850790133512243C21BA1009F29793C0088230200007E0E4FFD476370544E2D33280000000000000000000CC8A2608214298C81CD45160105964E203B372E"); break; //TCH.43.51330179 + case 261 : return F("b3744685029069372274351B5A2129F27995400305C1200000007400B69792D4C914447BB7D4A2AC86CB37BFAFD59EEC7971B1F070D00000000002C0040004FD085CC"); break; //TCH.43.72930629 + case 262 : return F("b37446850715221622843FE7BA2129F29F827008800000080800D0000DE060000E00739EF48B3861639BC2044115A10CB0C6283102F1830C0080AD861D24C1E8F80E1"); break; //TCH.43.62215271 + case 263 : return F("b374468508475676739430ECDA2109F27793500287F15000000D34D95907D550ADB32A24C9AAAA9922ED6A76075D51C1F7937DB8D4B95F20E4C63EDC5997041E280FA"); break; //TCH.43.67677584 + case 264 : return F("b36446850442620514543A443A1009F279E180038CC0400803680000286DB08F0C00727FCF0C82F92E8128D31165D722873C60C1568910103062C700107EF3F912E"); break; //TCH.43.51202644 + case 265 : return F("b3744685060478860574395F9A20D9F29820500A00000000100060000E34A00000000000000000000000000000000FFFF0000000000000000000000000000FFFF80D4"); break; //TCH.43.60884760 + case 266 : return F("b3644685005012040714351C0A0009F298F560290E10101A40000FFF719F04E99E7B2F9E2E512000000000000000042B000000000000000000000000000FFFF95A6"); break; //TCH.43.40200105 + case 267 : return F("b364468504200545145444FE0A1009F29CA6900B0F00D008023001A68BB4748D28D4F7685755095534E09E187ADE5A7B903D03027041000000100008002CF41D570"); break; //TCH.44.51540042 + case 268 : return F("b37446850341929625744B280A20D9F27C9350058395A00000169848B3EDF2ECEF8A17F008A875B80FCB947E0914351334E69E4A14D72A8E296375279E286AB9B8008"); break; //TCH.44.62291934 + case 269 : return F("b36446850060670527144C1AAA0009F29C41F0190DE0F0081A5A1BF2595D38ABA9F512E89A3471D67F8F0C6206308383B6288298BD0A3D68424A228A9907F8B34B2"); break; //TCH.44.52700606 + case 270 : return F("bY5044972608062002001A7AC90340A517F5A8F83D78281AEFF06FDBDEDEF842336FA663F292D6EEACB0F54CA02FB47C8F587862B352ED30166FEE61753998230C38444F845C9FCC364D3C614095F92D14A28010"); break; //ITW.1A.02200608 + case 271 : return F("bY5E449726900634160004728499181897A60030BA0040A53FB81E378B33F9E23FEDF6A0B1B381F4972C2842041CC7EC8D74D675CE56222039CE82385073750F2B695CBEC9B0E8A48EC3F09B74C26E4194A06B7974203DDD0C7976874216E0D282DE"); break; //ITW.04.16340690"); break; //ITW.30.18189984 + case 272 : return F("bY50449726141331160007728499181897A600307E0030A5500A4109842EF76DD4A2DEDF6722CCB4D0746C8505086D91ED34B41AFD24FED0111715A21E549191B1529EE2AE8229E50E7900000000000070208AD8"); break; //ITW.07.16311314"); break; //ITW.30.18189984 + case 273 : return F("bY5044972625353893071A7A0B0040A5B12EC2E009C467CAD2AF0A38712684FE764C6181D2969A7F0F7B076CB9719FEB21C32E48161EEA5A1E6E92F354FED894994C368F17E6F68E2E6AA1D7C289E3FD7A908015"); break; //ITW.1A.93383525 + case 274 : return F("b2E449726606670194107A6AB8CB0D47ABF0000A00413E84B070004FD3442178001C00004933C00000000333B00000A2D00325A0000CD2E801C"); break; //ITW.07.19706660 + case 275 : return F("bY50449726141331160007728499181897A600307E0030A5500A4109842EF76DD4A2DEDF6722CCB4D0746C8505086D91ED34B41AFD24FED0111715A21E549191B1529EE2AE8229E50E7900000000000070208AD8"); break; //ITW.07.16311314"); break; //ITW.30.18189984 + + } + // *INDENT-ON* + count = 0; + return F(""); +} + +# endif // if P094_DEBUG_OPTIONS + bool P094_data_struct::loop() { if (!isInitialized()) { return false; @@ -128,6 +593,7 @@ bool P094_data_struct::loop() { valid = false; } } + if (valid) { fullSentenceReceived = true; } @@ -138,7 +604,8 @@ bool P094_data_struct::loop() { // Ignore LF break; default: - if (c >= 32 && c < 127) { + + if ((c >= 32) && (c < 127)) { sentence_part += c; } else { current_sentence_errored = true; @@ -154,6 +621,23 @@ bool P094_data_struct::loop() { ++sentences_received; length_last_received = sentence_part.length(); } +# if P094_DEBUG_OPTIONS + else { + if (debug_generate_CUL_data && (sentence_part.length() == 0)) { + static uint32_t last_test_sentence = 0; + static int count = 0; + + if (timePassedSince(last_test_sentence) > 1000) { + count++; + + // sentence_part = F("b2644AC48585300005037FAB97201585300AC485003150000202F2F0C0AF314213993002F2F2F2F2F2F2F2FAFCA8046"); + sentence_part = getDebugSentences(count); + fullSentenceReceived = true; + last_test_sentence = millis(); + } + } + } +# endif // if P094_DEBUG_OPTIONS return fullSentenceReceived; } @@ -162,8 +646,9 @@ const String& P094_data_struct::peekSentence() const { } void P094_data_struct::getSentence(String& string, bool appendSysTime) { - string = std::move(sentence_part); + string = std::move(sentence_part); sentence_part = String(); // FIXME TD-er: Should not be needed as move already cleared it. + if (appendSysTime) { // Unix timestamp = 10 decimals + separator if (string.reserve(sentence_part.length() + 11)) { @@ -184,54 +669,8 @@ void P094_data_struct::setMaxLength(uint16_t maxlenght) { max_length = maxlenght; } -void P094_data_struct::setLine(uint8_t varNr, const String& line) { - if (varNr < P94_Nlines) { - _lines[varNr] = line; - } -} - uint32_t P094_data_struct::getFilterOffWindowTime() const { - return _lines[P094_FILTER_OFF_WINDOW_POS].toInt(); -} - -P094_Match_Type P094_data_struct::getMatchType() const { - return static_cast(_lines[P094_MATCH_TYPE_POS].toInt()); -} - -bool P094_data_struct::invertMatch() const { - switch (getMatchType()) { - case P094_Regular_Match: - break; - case P094_Regular_Match_inverted: - return true; - case P094_Filter_Disabled: - break; - } - return false; -} - -bool P094_data_struct::filterUsed(uint8_t lineNr) const -{ - if (valueType_index[lineNr] == P094_Filter_Value_Type::P094_not_used) { return false; } - uint8_t varNr = P094_Get_filter_base_index(lineNr); - return _lines[varNr + 3].length() > 0; -} - -String P094_data_struct::getFilter(uint8_t lineNr, P094_Filter_Value_Type& filterValueType, uint32_t& optional, - P094_Filter_Comp& comparator) const -{ - uint8_t varNr = P094_Get_filter_base_index(lineNr); - - filterValueType = P094_Filter_Value_Type::P094_not_used; - - if ((varNr + 3) >= P94_Nlines) { return ""; } - optional = _lines[varNr + 1].toInt(); - filterValueType = valueType_index[lineNr]; - comparator = filter_comp[lineNr]; - - // filterValueType = static_cast(_lines[varNr].toInt()); - // comparator = static_cast(_lines[varNr + 2].toInt()); - return _lines[varNr + 3]; + return filterOffWindowTime; } void P094_data_struct::setDisableFilterWindowTimer() { @@ -253,175 +692,72 @@ bool P094_data_struct::disableFilterWindowActive() const { return false; } -bool P094_data_struct::parsePacket(const String& received) const { - size_t strlength = received.length(); +bool P094_data_struct::parsePacket(const String& received, mBusPacket_t& packet) { + const size_t strlength = received.length(); if (strlength == 0) { return false; } + const char firstChar = received[0]; - if (getMatchType() == P094_Filter_Disabled) { - return true; - } - - bool match_result = false; - - // FIXME TD-er: For now added '$' to test with GPS. - if ((received[0] == 'b') || (received[0] == '$')) { + if ((firstChar == 'b')) { // Received a data packet in CUL format. if (strlength < 21) { return false; } // Decoded packet + if (!packet.parse(received)) { return false; } - unsigned long packet_header[P094_FILTER_VALUE_Type_NR_ELEMENTS]; - packet_header[P094_packet_length] = hexToUL(received, 1, 2); - packet_header[P094_unknown1] = hexToUL(received, 3, 2); - packet_header[P094_manufacturer] = hexToUL(received, 5, 4); - packet_header[P094_serial_number] = hexToUL(received, 9, 8); - packet_header[P094_unknown2] = hexToUL(received, 17, 2); - packet_header[P094_meter_type] = hexToUL(received, 19, 2); + const mBusPacket_header_t *header = packet.getDeviceHeader(); - // FIXME TD-er: Is this also correct? - packet_header[P094_rssi] = hexToUL(received, strlength - 4, 4); - - // FIXME TD-er: Is this correct? - // match_result = packet_length == (strlength - 21) / 2; - - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log; - if (log.reserve(128)) { - log = F("CUL Reader: "); - log += F(" length: "); - log += packet_header[P094_packet_length]; - log += F(" (header: "); - log += strlength - (packet_header[P094_packet_length] * 2); - log += F(") manu: "); - log += formatToHex_decimal(packet_header[P094_manufacturer]); - log += F(" serial: "); - log += formatToHex_decimal(packet_header[P094_serial_number]); - log += F(" mType: "); - log += formatToHex_decimal(packet_header[P094_meter_type]); - log += F(" RSSI: "); - log += formatToHex_decimal(packet_header[P094_rssi]); - addLogMove(LOG_LEVEL_INFO, log); + if (header == nullptr) { + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + addLogMove(LOG_LEVEL_INFO, concat(F("CUL Filter: NO Header "), packet.toString())); } - } - bool filter_matches[P094_NR_FILTERS]; - - for (unsigned int f = 0; f < P094_NR_FILTERS; ++f) { - filter_matches[f] = false; + return false; } - // Do not check for "not used" (0) - for (unsigned int i = 1; i < P094_FILTER_VALUE_Type_NR_ELEMENTS; ++i) { - if (valueType_used[i]) { - for (unsigned int f = 0; f < P094_NR_FILTERS; ++f) { - if (valueType_index[f] == i) { - // Have a matching filter - - uint32_t optional; - P094_Filter_Value_Type filterValueType; - P094_Filter_Comp comparator; - bool match = false; - String inputString; - String valueString; - - if (i == P094_Filter_Value_Type::P094_position) { - valueString = getFilter(f, filterValueType, optional, comparator); - - if (received.length() >= (optional + valueString.length())) { - // received string is long enough to fit the expression. - inputString = received.substring(optional, optional + valueString.length()); - match = inputString.equalsIgnoreCase(valueString); - } - } else { - unsigned long value = hexToUL(getFilter(f, filterValueType, optional, comparator)); - match = (value == packet_header[i]); - inputString = formatToHex_decimal(packet_header[i]); - valueString = formatToHex_decimal(value); - } - - - if (loglevelActiveFor(LOG_LEVEL_INFO)) { - String log; - if (log.reserve(64)) { - log += F("CUL Reader: "); - log += P094_FilterValueType_toString(valueType_index[f]); - log += F(": in:"); - log += inputString; - log += ' '; - log += P094_FilterComp_toString(comparator); - log += ' '; - log += valueString; - - switch (comparator) { - case P094_Filter_Comp::P094_Equal_OR: - case P094_Filter_Comp::P094_Equal_MUST: - - if (match) { log += F(" expected MATCH"); } - break; - case P094_Filter_Comp::P094_NotEqual_OR: - case P094_Filter_Comp::P094_NotEqual_MUST: - - if (!match) { log += F(" expected NO MATCH"); } - break; - } - addLogMove(LOG_LEVEL_INFO, log); - } - } - - switch (comparator) { - case P094_Filter_Comp::P094_Equal_OR: - - if (match) { filter_matches[f] = true; } - break; - case P094_Filter_Comp::P094_NotEqual_OR: - - if (!match) { filter_matches[f] = true; } - break; - - case P094_Filter_Comp::P094_Equal_MUST: - - if (!match) { return false; } - break; + if (mute_messages) { + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + addLogMove(LOG_LEVEL_INFO, concat(F("CUL Filter: Muted "), packet.toString())); + } - case P094_Filter_Comp::P094_NotEqual_MUST: + return false; // Mute all messages + } - if (match) { return false; } - break; - } - } - } + if (!interval_filter.enabled || (_filters.size() == 0)) { + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + addLogMove(LOG_LEVEL_INFO, concat(F("CUL Filter: NO Filter "), packet.toString())); } + + return true; // No filtering } - // Now we have to check if all rows per filter line in filter_matches[f] are true or not used. - int nrMatches = 0; - int nrNotUsed = 0; + for (unsigned int f = 0; f < _filters.size(); ++f) { + if (_filters[f].matches(*header)) { + const bool res = interval_filter.filter(packet, _filters[f]); - for (unsigned int f = 0; !match_result && f < P094_NR_FILTERS; ++f) { - if (f % P094_AND_FILTER_BLOCK == 0) { - if ((nrMatches > 0) && ((nrMatches + nrNotUsed) == P094_AND_FILTER_BLOCK)) { - match_result = true; + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + addLogMove(LOG_LEVEL_INFO, concat(F("CUL Filter: Match "), _filters[f].toString())); + addLogMove(LOG_LEVEL_INFO, concat(res ? F("CUL Filter: Pass ") : F("CUL Filter: Reject "), header->toString())); } - nrMatches = 0; - nrNotUsed = 0; - } - if (filter_matches[f]) { - ++nrMatches; - } else { - if (!filterUsed(f)) { - ++nrNotUsed; - } + return res; } } + + if (loglevelActiveFor(LOG_LEVEL_INFO)) { + addLogMove(LOG_LEVEL_INFO, concat(F("CUL Filter: NO Match "), header->toString())); + } + + // No matching filter, so consider fall-through filter to be: + // *.*.*;none + return false; } else { - switch (received[0]) { + switch (firstChar) { case 'C': // CMODE case 'S': // SMODE case 'T': // TMODE @@ -429,51 +765,60 @@ bool P094_data_struct::parsePacket(const String& received) const { case 'V': // Version info // FIXME TD-er: Must test the result of the other possible answers. - match_result = true; - break; + return true; } } - return match_result; + return false; } -const __FlashStringHelper * P094_data_struct::MatchType_toString(P094_Match_Type matchType) { - switch (matchType) - { - case P094_Match_Type::P094_Regular_Match: return F("Regular Match"); - case P094_Match_Type::P094_Regular_Match_inverted: return F("Regular Match inverted"); - case P094_Match_Type::P094_Filter_Disabled: return F("Filter Disabled"); - } - return F(""); +void P094_data_struct::interval_filter_purgeExpired() { + interval_filter.purgeExpired(); } -const __FlashStringHelper * P094_data_struct::P094_FilterValueType_toString(P094_Filter_Value_Type valueType) +void P094_data_struct::html_show_interval_filter_stats() const { - switch (valueType) { - case P094_Filter_Value_Type::P094_not_used: return F("---"); - case P094_Filter_Value_Type::P094_packet_length: return F("Packet Length"); - case P094_Filter_Value_Type::P094_unknown1: return F("unknown1"); - case P094_Filter_Value_Type::P094_manufacturer: return F("Manufacturer"); - case P094_Filter_Value_Type::P094_serial_number: return F("Serial Number"); - case P094_Filter_Value_Type::P094_unknown2: return F("unknown2"); - case P094_Filter_Value_Type::P094_meter_type: return F("Meter Type"); - case P094_Filter_Value_Type::P094_rssi: return F("RSSI"); - case P094_Filter_Value_Type::P094_position: return F("Position"); - - // default: break; + if (interval_filter._mBusFilterMap.empty()) { return; } + + addRowLabel(F("Interval Filter Entries")); + addHtmlInt(interval_filter._mBusFilterMap.size()); + + addFormNote(F("Non expired W-MBus device filters")); +} + +bool P094_data_struct::collect_stats_add(const mBusPacket_t& packet, const String& source) { + if (collect_stats) { + return mBus_stats[firstStatsIndexActive ? 0 : 1].add(packet, source); } - return F("unknown"); + return false; +} + +void P094_data_struct::prepare_dump_stats() { + firstStatsIndexActive = !firstStatsIndexActive; } -const __FlashStringHelper * P094_data_struct::P094_FilterComp_toString(P094_Filter_Comp comparator) +bool P094_data_struct::dump_next_stats(String& str) { + const uint8_t dumpStatsIndex = firstStatsIndexActive ? 1 : 0; + + if (mBus_stats[dumpStatsIndex]._mBusStatsMap.empty()) { return false; } + + str = concat(F("stats;"), mBus_stats[dumpStatsIndex].getFront()); + + return true; +} + +void P094_data_struct::html_show_mBus_stats() const { - switch (comparator) { - case P094_Filter_Comp::P094_Equal_OR: return F("=="); - case P094_Filter_Comp::P094_NotEqual_OR: return F("!="); - case P094_Filter_Comp::P094_Equal_MUST: return F("== (must)"); - case P094_Filter_Comp::P094_NotEqual_MUST: return F("!= (must)"); - } - return F(""); + const uint8_t dumpStatsIndex = firstStatsIndexActive ? 0 : 1; + + if (mBus_stats[dumpStatsIndex]._mBusStatsMap.empty()) { return; } + + addRowLabel(F("W-MBus Devices")); + addHtmlInt(mBus_stats[dumpStatsIndex]._mBusStatsMap.size()); + + addFormNote(F("Devices received since last culreader,dumpstats")); + + mBus_stats[dumpStatsIndex].toHtml(); } bool P094_data_struct::max_length_reached() const { @@ -481,12 +826,23 @@ bool P094_data_struct::max_length_reached() const { return sentence_part.length() >= max_length; } -size_t P094_data_struct::P094_Get_filter_base_index(size_t filterLine) { - return filterLine * P094_ITEMS_PER_FILTER + P094_FIRST_FILTER_POS; +bool P094_data_struct::isDuplicate(const P094_filter& other) const +{ + const String f_str = other.toString(); + + for (auto it = _filters.begin(); it != _filters.end(); ++it) { + if (f_str.equals(it->toString())) { + return true; + } + } + return false; } +# if P094_DEBUG_OPTIONS uint32_t P094_data_struct::getDebugCounter() { return debug_counter++; } -#endif // USES_P094 \ No newline at end of file +# endif // if P094_DEBUG_OPTIONS + +#endif // USES_P094 \ No newline at end of file diff --git a/src/src/PluginStructs/P094_data_struct.h b/src/src/PluginStructs/P094_data_struct.h index 9fdcd9db2a..0e6bb12227 100644 --- a/src/src/PluginStructs/P094_data_struct.h +++ b/src/src/PluginStructs/P094_data_struct.h @@ -4,53 +4,63 @@ #include "../../_Plugin_Helper.h" #ifdef USES_P094 -#include -#include +# include "../Helpers/CUL_interval_filter.h" +# include "../Helpers/CUL_stats.h" +# include "../PluginStructs/P094_Filter.h" -# define P094_REGEX_POS 0 -# define P094_NR_CHAR_USE_POS 1 -# define P094_FILTER_OFF_WINDOW_POS 2 -# define P094_MATCH_TYPE_POS 3 +# include +# include -# define P094_FIRST_FILTER_POS 10 +# ifndef P094_DEBUG_OPTIONS +# define P094_DEBUG_OPTIONS 0 +# endif // ifndef P094_DEBUG_OPTIONS -# define P094_ITEMS_PER_FILTER 4 -# define P094_AND_FILTER_BLOCK 3 -# define P094_NR_FILTERS (7 * P094_AND_FILTER_BLOCK) -# define P94_Nlines (P094_FIRST_FILTER_POS + (P094_ITEMS_PER_FILTER * (P094_NR_FILTERS))) -# define P94_Nchars 128 -# define P94_MAX_CAPTURE_INDEX 32 +# define P094_BAUDRATE PCONFIG_LONG(0) +# define P094_BAUDRATE_LABEL PCONFIG_LABEL(0) -enum P094_Match_Type { - P094_Regular_Match = 0, - P094_Regular_Match_inverted = 1, - P094_Filter_Disabled = 2 -}; -# define P094_Match_Type_NR_ELEMENTS 3 - -enum P094_Filter_Value_Type { - P094_not_used = 0, - P094_packet_length = 1, - P094_unknown1 = 2, - P094_manufacturer = 3, - P094_serial_number = 4, - P094_unknown2 = 5, - P094_meter_type = 6, - P094_rssi = 7, - P094_position = 8 -}; -# define P094_FILTER_VALUE_Type_NR_ELEMENTS 9 +# define P094_DEBUG_SENTENCE_LENGTH PCONFIG_LONG(1) +# define P094_DEBUG_SENTENCE_LABEL PCONFIG_LABEL(1) -enum P094_Filter_Comp { - P094_Equal_OR = 0, - P094_NotEqual_OR = 1, - P094_Equal_MUST = 2, - P094_NotEqual_MUST = 3 -}; +# define P094_DISABLE_WINDOW_TIME_MS PCONFIG_LONG(2) + +# define P094_GET_APPEND_RECEIVE_SYSTIME bitRead(PCONFIG(0), 0) +# define P094_SET_APPEND_RECEIVE_SYSTIME(X) bitWrite(PCONFIG(0), 0, X) + +# if P094_DEBUG_OPTIONS +# define P094_GET_GENERATE_DEBUG_CUL_DATA bitRead(PCONFIG(0), 1) +# define P094_SET_GENERATE_DEBUG_CUL_DATA(X) bitWrite(PCONFIG(0), 1, X) +# endif // if P094_DEBUG_OPTIONS + +# define P094_GET_INTERVAL_FILTER bitRead(PCONFIG(0), 2) +# define P094_SET_INTERVAL_FILTER(X) bitWrite(PCONFIG(0), 2, X) + +# define P094_GET_COLLECT_STATS bitRead(PCONFIG(0), 3) +# define P094_SET_COLLECT_STATS(X) bitWrite(PCONFIG(0), 3, X) + +# define P094_GET_MUTE_MESSAGES bitRead(PCONFIG(0), 4) +# define P094_SET_MUTE_MESSAGES(X) bitWrite(PCONFIG(0), 4, X) -# define P094_FILTER_COMP_NR_ELEMENTS 4 +# define P094_NR_FILTERS PCONFIG(1) + +# ifdef ESP8266 +# define P094_MAX_NR_FILTERS 25 +# endif // ifdef ESP8266 +# ifdef ESP32 +# define P094_MAX_NR_FILTERS 100 +# endif // ifdef ESP32 + + +# ifdef ESP8266 +# define P094_MAX_MSG_LENGTH 550 +# endif // ifdef ESP8266 +# ifdef ESP32 +# define P094_MAX_MSG_LENGTH 1024 +# endif // ifdef ESP32 + + +# define P094_DEFAULT_BAUDRATE 38400 struct P094_data_struct : public PluginTaskData_base { @@ -62,85 +72,123 @@ struct P094_data_struct : public PluginTaskData_base { void reset(); - bool init(ESPEasySerialPort port, - const int16_t serial_rx, - const int16_t serial_tx, - unsigned long baudrate); + bool init(ESPEasySerialPort port, + const int16_t serial_rx, + const int16_t serial_tx, + unsigned long baudrate); - void post_init(); + void setFlags(unsigned long filterOffWindowTime_ms, + bool intervalFilterEnabled, + bool mute, + bool collectStats); - bool isInitialized() const; - void sendString(const String& data); + void loadFilters(struct EventStruct *event, + uint8_t nrFilters); - bool loop(); + String saveFilters(struct EventStruct *event) const; - const String& peekSentence() const; - void getSentence(String& string, bool appendSysTime); + void clearFilters(); + + bool addFilter(struct EventStruct *event, const String& filter); - void getSentencesReceived(uint32_t& succes, - uint32_t& error, - uint32_t& length_last) const; + String getFiltersMD5() const; - void setMaxLength(uint16_t maxlenght); + void WebformLoadFilters(uint8_t nrFilters) const; - void setLine(uint8_t varNr, - const String& line); + void WebformSaveFilters(struct EventStruct *event, + uint8_t nrFilters); + bool isInitialized() const; - uint32_t getFilterOffWindowTime() const; + void sendString(const String& data); - P094_Match_Type getMatchType() const; + bool loop(); - bool invertMatch() const; + const String& peekSentence() const; + + void getSentence(String& string, + bool appendSysTime); - bool filterUsed(uint8_t lineNr) const; + void getSentencesReceived(uint32_t& succes, + uint32_t& error, + uint32_t& length_last) const; - String getFilter(uint8_t lineNr, - P094_Filter_Value_Type& capture, - uint32_t & optional, - P094_Filter_Comp & comparator) const; + void setMaxLength(uint16_t maxlenght); - void setDisableFilterWindowTimer(); + void setLine(uint8_t varNr, + const String& line); - bool disableFilterWindowActive() const; + uint32_t getFilterOffWindowTime() const; - bool parsePacket(const String& received) const; + bool filterUsed(uint8_t lineNr) const; - static const __FlashStringHelper * MatchType_toString(P094_Match_Type matchType); - static const __FlashStringHelper * P094_FilterValueType_toString(P094_Filter_Value_Type valueType); - static const __FlashStringHelper * P094_FilterComp_toString(P094_Filter_Comp comparator); + void setDisableFilterWindowTimer(); + bool disableFilterWindowActive() const; - // Made public so we don't have to copy the values when loading/saving. - String _lines[P94_Nlines]; + bool parsePacket(const String& received, + mBusPacket_t& packet); - static size_t P094_Get_filter_base_index(size_t filterLine); + +# if P094_DEBUG_OPTIONS // Get (and increment) debug counter uint32_t getDebugCounter(); + void setGenerate_DebugCulData(bool value) { + debug_generate_CUL_data = value; + } + +# endif // if P094_DEBUG_OPTIONS + + void interval_filter_purgeExpired(); + + void html_show_interval_filter_stats() const; + + + bool collect_stats_add(const mBusPacket_t& packet, const String& source); + void prepare_dump_stats(); + bool dump_next_stats(String& str); + + void html_show_mBus_stats() const; + private: bool max_length_reached() const; + bool isDuplicate(const P094_filter& other) const; + + std::vector_filters; + ESPeasySerial *easySerial = nullptr; String sentence_part; - uint16_t max_length = 550; + uint16_t max_length = P094_MAX_MSG_LENGTH; + uint16_t nrFilters{}; + unsigned long filterOffWindowTime = 0; uint32_t sentences_received = 0; uint32_t sentences_received_error = 0; bool current_sentence_errored = false; uint32_t length_last_received = 0; unsigned long disable_filter_window = 0; - uint32_t debug_counter = 0; - bool valueType_used[P094_FILTER_VALUE_Type_NR_ELEMENTS] = {0}; - P094_Filter_Value_Type valueType_index[P094_NR_FILTERS]; - P094_Filter_Comp filter_comp[P094_NR_FILTERS]; + # if P094_DEBUG_OPTIONS + uint32_t debug_counter = 0; + bool debug_generate_CUL_data = false; + # endif // if P094_DEBUG_OPTIONS + bool collect_stats = false; + bool mute_messages = false; + + bool firstStatsIndexActive = false; + + CUL_interval_filter interval_filter; + + // Alternating stats, one being flushed, the other used to collect new stats + CUL_Stats mBus_stats[2]; }; #endif // USES_P094 -#endif // PLUGINSTRUCTS_P094_DATA_STRUCT_H \ No newline at end of file +#endif // PLUGINSTRUCTS_P094_DATA_STRUCT_H diff --git a/src/src/PluginStructs/P116_data_struct.cpp b/src/src/PluginStructs/P116_data_struct.cpp index 3e88fcf499..1aa994c334 100644 --- a/src/src/PluginStructs/P116_data_struct.cpp +++ b/src/src/PluginStructs/P116_data_struct.cpp @@ -11,10 +11,18 @@ const __FlashStringHelper* ST77xx_type_toString(const ST77xx_type_e& device) { case ST77xx_type_e::ST7735s_128x160: return F("ST7735 128 x 160px"); case ST77xx_type_e::ST7735s_80x160: return F("ST7735 80 x 160px"); case ST77xx_type_e::ST7735s_80x160_M5: return F("ST7735 80 x 160px (Color inverted)"); + # if P116_EXTRA_ST7735 + case ST77xx_type_e::ST7735s_135x240: return F("ST7735 135 x 240px"); + # endif // if P116_EXTRA_ST7735 case ST77xx_type_e::ST7789vw_240x320: return F("ST7789 240 x 320px"); case ST77xx_type_e::ST7789vw_240x240: return F("ST7789 240 x 240px"); case ST77xx_type_e::ST7789vw_240x280: return F("ST7789 240 x 280px"); case ST77xx_type_e::ST7789vw_135x240: return F("ST7789 135 x 240px"); + # if P116_EXTRA_ST7789 + case ST77xx_type_e::ST7789vw1_135x240: return F("ST7789 135 x 240px (alt1)"); + case ST77xx_type_e::ST7789vw2_135x240: return F("ST7789 135 x 240px (alt2)"); + case ST77xx_type_e::ST7789vw3_135x240: return F("ST7789 135 x 240px (alt3)"); + # endif // if P116_EXTRA_ST7789 case ST77xx_type_e::ST7796s_320x480: return F("ST7796 320 x 480px"); } return F("Unsupported type!"); @@ -53,6 +61,14 @@ void ST77xx_type_toResolution(const ST77xx_type_e& device, y = 280; break; case ST77xx_type_e::ST7789vw_135x240: + # if P116_EXTRA_ST7789 + case ST77xx_type_e::ST7789vw1_135x240: + case ST77xx_type_e::ST7789vw2_135x240: + case ST77xx_type_e::ST7789vw3_135x240: + # endif // if P116_EXTRA_ST7789 + # if P116_EXTRA_ST7735 + case ST77xx_type_e::ST7735s_135x240: + # endif // if P116_EXTRA_ST7735 x = 135; y = 240; break; @@ -144,7 +160,16 @@ bool P116_data_struct::plugin_init(struct EventStruct *event) { initRoptions = INITR_GREENTAB160x80; // 80x160px ST7735sv, inverted (M5Stack StickC) } - // fall through + // fall through + # if P116_EXTRA_ST7735 + case ST77xx_type_e::ST7735s_135x240: + + if (initRoptions == 0xFF) { + initRoptions = INITR_BLACKTAB135x240; // 135x240px + } + + // fall through + # endif // if P116_EXTRA_ST7735 case ST77xx_type_e::ST7735s_80x160: { if (initRoptions == 0xFF) { @@ -163,11 +188,28 @@ bool P116_data_struct::plugin_init(struct EventStruct *event) { case ST77xx_type_e::ST7789vw_240x240: case ST77xx_type_e::ST7789vw_240x280: case ST77xx_type_e::ST7789vw_135x240: + # if P116_EXTRA_ST7789 + case ST77xx_type_e::ST7789vw1_135x240: + case ST77xx_type_e::ST7789vw2_135x240: + case ST77xx_type_e::ST7789vw3_135x240: + # endif // if P116_EXTRA_ST7789 { st7789 = new (std::nothrow) Adafruit_ST7789(PIN(0), PIN(1), PIN(2)); if (nullptr != st7789) { - st7789->init(_xpix, _ypix, SPI_MODE2); + uint8_t init_seq = 0; // Default/original initialisation + + # if P116_EXTRA_ST7789 + + if (ST77xx_type_e::ST7789vw1_135x240 == _device) { + init_seq = 1; + } else if (ST77xx_type_e::ST7789vw2_135x240 == _device) { + init_seq = 2; + } else if (ST77xx_type_e::ST7789vw3_135x240 == _device) { + init_seq = 3; + } + # endif // if P116_EXTRA_ST7789 + st7789->init(_xpix, _ypix, SPI_MODE2, init_seq); st77xx = st7789; } break; @@ -330,7 +372,7 @@ bool P116_data_struct::plugin_read(struct EventStruct *event) { gfxHelper->setColumnRowMode(bitRead(P116_CONFIG_FLAGS, P116_CONFIG_FLAG_USE_COL_ROW)); // Restore column mode int16_t curX, curY; gfxHelper->getCursorXY(curX, curY); // Get current X and Y coordinates, - UserVar.setFloat(event->TaskIndex, 0, curX); // and put into Values + UserVar.setFloat(event->TaskIndex, 0, curX); // and put into Values UserVar.setFloat(event->TaskIndex, 1, curY); } } @@ -385,8 +427,8 @@ bool P116_data_struct::plugin_write(struct EventStruct *event, st77xx->fillScreen(_bgcolor); } else if (equals(arg1, F("backlight"))) { - String arg2 = parseString(string, 3); - int32_t nArg2{}; + String arg2 = parseString(string, 3); + int32_t nArg2{}; if ((P116_CONFIG_BACKLIGHT_PIN != -1) && // All is valid? validIntFromString(arg2, nArg2) && diff --git a/src/src/PluginStructs/P116_data_struct.h b/src/src/PluginStructs/P116_data_struct.h index 2144ebd8ff..675102456e 100644 --- a/src/src/PluginStructs/P116_data_struct.h +++ b/src/src/PluginStructs/P116_data_struct.h @@ -4,11 +4,30 @@ #include "../../_Plugin_Helper.h" #ifdef USES_P116 -# include // include Adafruit graphics library -# include // include Adafruit ST77xx TFT library -# include // include Adafruit ST7735 TFT library -# include // include Adafruit ST7789 TFT library -# include // include Adafruit ST7796 TFT library +# include // include Adafruit graphics library +# include // include Adafruit ST77xx TFT library +# include // include Adafruit ST7735 TFT library +# include // include Adafruit ST7789 TFT library +# include // include Adafruit ST7796 TFT library + +# if defined(ST7789_EXTRA_INIT) && !ST7789_EXTRA_INIT +# define P116_EXTRA_ST7789 0 // This will get disabled for ESP8266 in Adafruit_ST7789.h +# endif // if defined(ST7789_EXTRA_INIT) && !ST7789_EXTRA_INIT +# if defined(LIMIT_BUILD_SIZE) and !defined(P116_EXTRA_ST7789) +# define P116_EXTRA_ST7789 0 +# endif // if defined(LIMIT_BUILD_SIZE) and !defined(P116_EXTRA_ST7789) +# ifndef P116_EXTRA_ST7789 +# define P116_EXTRA_ST7789 0 // Disabled by default (not verified on any hardware yet) +# endif // ifndef P116_EXTRA_ST7789 +# if defined(ST7735_EXTRA_INIT) && !ST7735_EXTRA_INIT +# define P116_EXTRA_ST7735 0 // This will get disabled for ESP8266 in Adafruit_ST7735.h +# endif // if defined(ST7735_EXTRA_INIT) && !ST7735_EXTRA_INIT +# if defined(LIMIT_BUILD_SIZE) and !defined(P116_EXTRA_ST7789) +# define P116_EXTRA_ST7735 0 +# endif // if defined(LIMIT_BUILD_SIZE) and !defined(P116_EXTRA_ST7735) +# ifndef P116_EXTRA_ST7735 +# define P116_EXTRA_ST7735 1 +# endif // ifndef P116_EXTRA_ST7735 # include "../Helpers/AdafruitGFX_helper.h" // Use Adafruit graphics helper object # include "../CustomBuild/StorageLayout.h" @@ -74,6 +93,14 @@ enum class ST77xx_type_e : uint8_t { ST7789vw_135x240 = 6u, ST7796s_320x480 = 7u, ST7735s_80x160_M5 = 8u, + # if P116_EXTRA_ST7789 + ST7789vw1_135x240 = 9u, + ST7789vw2_135x240 = 10u, + ST7789vw3_135x240 = 11u, + # endif // if P116_EXTRA_ST7789 + # if P116_EXTRA_ST7735 + ST7735s_135x240 = 12u, + # endif // if P116_EXTRA_ST7735 }; enum class P116_CommandTrigger : uint8_t { diff --git a/src/src/PluginStructs/P148_data_struct.cpp b/src/src/PluginStructs/P148_data_struct.cpp index 35d75cb537..9faa757a23 100644 --- a/src/src/PluginStructs/P148_data_struct.cpp +++ b/src/src/PluginStructs/P148_data_struct.cpp @@ -88,6 +88,10 @@ uint8_t P148_data_struct::TM1621GetFontCharacter(char character, bool firstrow) return 0u; } + +// FIXME TD-er: When used on ESP8266, this conversion union may not work +// However this is probably only used on ESP32 Sonoff units with display. + // Do not change the order of these as it is stored. union MonitorTaskValue_conversion { struct { diff --git a/src/src/PluginStructs/P151_data_struct.cpp b/src/src/PluginStructs/P151_data_struct.cpp index a990d1022e..20376b09fb 100644 --- a/src/src/PluginStructs/P151_data_struct.cpp +++ b/src/src/PluginStructs/P151_data_struct.cpp @@ -6,6 +6,8 @@ P151_data_struct::~P151_data_struct() {} bool P151_data_struct::plugin_read(struct EventStruct *event) { + // FIXME TD-er: When used on ESP8266, this conversion union may not work + // It might work as it is 32-bit in size. union Honeywell_struct { struct { uint32_t dummy : 5; diff --git a/src/src/WebServer/DevicesPage.cpp b/src/src/WebServer/DevicesPage.cpp index 1b8440178e..3c4cda1cd6 100644 --- a/src/src/WebServer/DevicesPage.cpp +++ b/src/src/WebServer/DevicesPage.cpp @@ -169,7 +169,6 @@ void handle_devices() { // N.B. When calling delete, the settings were already saved. if (nosave) { Cache.updateExtraTaskSettingsCache(); - UserVar.clear_computed(taskIndex); } else { addHtmlError(SaveTaskSettings(taskIndex)); addHtmlError(SaveSettings()); @@ -318,7 +317,7 @@ void handle_devices_CopySubmittedSettings(taskIndex_t taskIndex, pluginID_t task Sensor_VType VType = TempEvent.sensorType; if ((pconfigIndex >= 0) && (pconfigIndex < PLUGIN_CONFIGVAR_MAX)) { - VType = static_cast(getFormItemInt(PCONFIG_LABEL(pconfigIndex), 0)); + VType = static_cast(getFormItemInt(sensorTypeHelper_webformID(pconfigIndex), 0)); Settings.TaskDevicePluginConfig[taskIndex][pconfigIndex] = static_cast(VType); } ExtraTaskSettings.clearUnusedValueNames(getValueCountFromSensorType(VType)); @@ -436,8 +435,10 @@ void handle_devices_CopySubmittedSettings(taskIndex_t taskIndex, pluginID_t task // Store all PCONFIG values on the web page // Must be done after PLUGIN_WEBFORM_SAVE, to allow tasks to clear the default task value names // Output type selectors are typically stored in PCONFIG - for (int pconfigIndex = 0; pconfigIndex < PLUGIN_CONFIGVAR_MAX; ++pconfigIndex) { - pconfig_webformSave(&TempEvent, pconfigIndex); + if (device.OutputDataType != Output_Data_type_t::Default) { + for (int pconfigIndex = 0; pconfigIndex < PLUGIN_CONFIGVAR_MAX; ++pconfigIndex) { + pconfig_webformSave(&TempEvent, pconfigIndex); + } } // ExtraTaskSettings may have changed during PLUGIN_WEBFORM_SAVE, so again update the cache. Cache.updateExtraTaskSettingsCache(); @@ -458,6 +459,7 @@ void handle_devices_CopySubmittedSettings(taskIndex_t taskIndex, pluginID_t task CPluginCall(ProtocolIndex, CPlugin::Function::CPLUGIN_TASK_CHANGE_NOTIFICATION, &TempEvent, dummy); } } + // FIXME TD-er: Is this still needed as it is also cleared on PLUGIN_INIT and PLUGIN_EXIT? UserVar.clear_computed(taskIndex); } diff --git a/src/src/WebServer/JSON.cpp b/src/src/WebServer/JSON.cpp index bc2ea01b46..000400aaef 100644 --- a/src/src/WebServer/JSON.cpp +++ b/src/src/WebServer/JSON.cpp @@ -210,6 +210,13 @@ void handle_json() #ifdef ESP32 LabelType::ESP_CHIP_REVISION, #endif // ifdef ESP32 + LabelType::FLASH_CHIP_ID, + LabelType::FLASH_CHIP_VENDOR, + LabelType::FLASH_CHIP_MODEL, + LabelType::FLASH_CHIP_REAL_SIZE, + LabelType::FLASH_CHIP_SPEED, + LabelType::FLASH_IDE_MODE, + LabelType::FS_SIZE, LabelType::SUNRISE, LabelType::SUNSET, diff --git a/src/src/WebServer/Markup_Forms.cpp b/src/src/WebServer/Markup_Forms.cpp index f634dcba26..30f8ff05ca 100644 --- a/src/src/WebServer/Markup_Forms.cpp +++ b/src/src/WebServer/Markup_Forms.cpp @@ -480,7 +480,7 @@ void addFormSelectorI2C(const String& id, #endif // if FEATURE_TOOLTIPS ); - for (uint8_t x = 0; x < addressCount; x++) + for (int x = 0; x < addressCount; x++) { String option = formatToHex_decimal(addresses[x]); @@ -653,9 +653,9 @@ void addFormSelector_YesNo(const __FlashStringHelper * label, int selectedIndex, bool reloadonchange) { - const __FlashStringHelper *optionsNoYes[2] = { F("No"), F("Yes") }; - int optionValuesNoYes[2] = { 0, 1 }; - addFormSelector(label, id, 2, optionsNoYes, optionValuesNoYes, selectedIndex, reloadonchange); + const __FlashStringHelper *optionsNoYes[] = { F("No"), F("Yes") }; + int optionValuesNoYes[] = { 0, 1 }; + addFormSelector(label, id, NR_ELEMENTS(optionValuesNoYes), optionsNoYes, optionValuesNoYes, selectedIndex, reloadonchange); } diff --git a/src/src/WebServer/SetupPage.cpp b/src/src/WebServer/SetupPage.cpp index 496471948c..ef94bf0f14 100644 --- a/src/src/WebServer/SetupPage.cpp +++ b/src/src/WebServer/SetupPage.cpp @@ -266,7 +266,7 @@ void handle_setup_scan_and_show(const String& ssid, const String& other, const S addHtml('>'); addHtml(F("ssid; diff --git a/tools/pio/copy_files.py b/tools/pio/copy_files.py index 82fc546914..755c271ebf 100644 --- a/tools/pio/copy_files.py +++ b/tools/pio/copy_files.py @@ -21,11 +21,11 @@ def get_max_bin_size(env_name, file_suffix): if "4M316k" in env_name or "_ESP32_4M2M" in env_name: # ESP32 with 1800k of sketch space. max_bin_size = 1900544 - if "_ESP32_" in env_name or "_ESP32s2_" in env_name or "_ESP32s3_" in env_name: + if "_ESP32_" in env_name or "_ESP32c6_" in env_name or "_ESP32s2_" in env_name or "_ESP32s3_" in env_name: if "_8M1M" in env_name: # ESP32 with 3520k of sketch space. max_bin_size = 3604480 - if "_ESP32_" in env_name or "_ESP32c3_" in env_name or "_ESP32s2_" in env_name or "_ESP32s3_" in env_name: + if "_ESP32_" in env_name or "_ESP32c3_" in env_name or "_ESP32c6_" in env_name or "_ESP32s2_" in env_name or "_ESP32s3_" in env_name: if "_16M8M" in env_name or "_16M2M" in env_name or "_16M1M" in env_name: # ESP32 with 4096k of sketch space. max_bin_size = 4194304 diff --git a/tools/pio/install-requirements.py b/tools/pio/install-requirements.py new file mode 100644 index 0000000000..1ea4839572 --- /dev/null +++ b/tools/pio/install-requirements.py @@ -0,0 +1,10 @@ +Import("env") + + +# ToDo: Use suggested code by Jason2866 +# https://github.com/letscontrolit/ESPEasy/issues/4943#issuecomment-1986831198 + +try: + from pygit2 import Repository +except ImportError: + env.Execute("$PYTHONEXE -m pip install -r requirements.txt") diff --git a/tools/pio/post_esp32.py b/tools/pio/post_esp32.py index 458f143801..d75e918f8e 100644 --- a/tools/pio/post_esp32.py +++ b/tools/pio/post_esp32.py @@ -37,15 +37,10 @@ def esp32_create_combined_bin(source, target, env): sections = env.subst(env.get("FLASH_EXTRA_IMAGES")) firmware_name = env.subst("$BUILD_DIR/${PROGNAME}.bin") chip = env.get("BOARD_MCU") - flash_size = env.BoardConfig().get("upload.flash_size") - flash_freq = env.BoardConfig().get("build.f_flash", '40m') - flash_freq = flash_freq.replace('000000L', 'm') - flash_mode = env.BoardConfig().get("build.flash_mode", "dio") - memory_type = env.BoardConfig().get("build.arduino.memory_type", "qio_qspi") - if flash_mode == "qio" or flash_mode == "qout": - flash_mode = "dio" - if memory_type == "opi_opi" or memory_type == "opi_qspi": - flash_mode = "dout" + flash_size = env.BoardConfig().get("upload.flash_size", "4MB") + flash_mode = env["__get_board_flash_mode"](env) + flash_freq = env["__get_board_f_flash"](env) + cmd = [ "--chip", chip,