From 571502114c580a0d768b0d1e0f4a5f28d1dcfb09 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Wed, 14 Dec 2022 14:46:08 +0100 Subject: [PATCH 001/262] Bump version v12.3.0.1 --- CHANGELOG.md | 27 +++++++++----- RELEASENOTES.md | 61 ++----------------------------- tasmota/include/tasmota_version.h | 2 +- 3 files changed, 22 insertions(+), 68 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 72b3e6dab..bcb28d49c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,15 +3,30 @@ All notable changes to this project will be documented in this file. ## [Unreleased] - Development -## [12.2.0.6] +## [12.3.0.1] + +### Added + +### Breaking Changed + +### Changed + +### Fixed + +### Removed + +## [Released] + +## [12.3.0] 20221215 +- Release Percy + +## [12.2.0.6] 20221215 ### Added - Serial Modbus transmit enable GPIOs to all modbus energy drivers and modbus bridge (#17247) - Berry crypto module, with AES_GCM by default and EC_CC25519 optional - IPv6 support for Ethernet (ESP32) - Support for ME007-ULS narrow FoV ultrasonic distance sensor by Mathias Buder (#17376) -### Breaking Changed - ### Changed - TasmotaSerial library from v3.5.0 to v3.6.0 - Removed leading spaces on commands ``(S)SerialSend1 to 6`` but keep on duplicate commands ``(S)SerialSend11 to 16`` (#16723) @@ -25,8 +40,6 @@ All notable changes to this project will be documented in this file. - Analog MQ exception 28 on restart (#17271) - ESP32 fix ``Ping`` (#17373) -### Removed - ## [12.2.0.5] 20221129 ### Added - ESP32 DS18x20 parasitic power usage when defining W1_PARASITE_POWER (#17112) @@ -72,8 +85,6 @@ All notable changes to this project will be documented in this file. ### Fixed - SenseAir S8 module detection (#17033) -### Removed - ## [12.2.0.3] 20221109 ### Added - Support for BP1658CJ RGBCW led bulbs like Orein OS0100411267 by Cossid (#17011) @@ -126,8 +137,6 @@ All notable changes to this project will be documented in this file. ### Fixed - BP5758D red channel corruption regression from v12.1.1.6 (#16850) -## [Released] - ## [12.2.0] 20221017 - Release Patrick diff --git a/RELEASENOTES.md b/RELEASENOTES.md index b946f6ae3..a0232063f 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -72,7 +72,7 @@ Latest released binaries can be downloaded from - http://ota.tasmota.com/tasmota/release Historical binaries can be downloaded from -- http://ota.tasmota.com/tasmota/release-12.2.0 +- http://ota.tasmota.com/tasmota/release-12.3.0 The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmota.com/tasmota/release/tasmota.bin.gz`` @@ -97,7 +97,7 @@ Latest released binaries can be downloaded from - http://ota.tasmota.com/tasmota32/release Historical binaries can be downloaded from -- http://ota.tasmota.com/tasmota32/release-12.2.0 +- http://ota.tasmota.com/tasmota32/release-12.3.0 The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmota.com/tasmota32/release/tasmota32.bin`` @@ -107,69 +107,14 @@ The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmo [Complete list](BUILDS.md) of available feature and sensors. -## Changelog v12.2.0.6 +## Changelog v12.3.0.1 ### Added -- Command ``SetOption35 0..255`` to skip number of received messages in Serial Bridge (default 0) [#17140](https://github.com/arendst/Tasmota/issues/17140) -- Command ``SetOption47 1..255`` to delay power on relay state in seconds reducing power surge. ``SO47 1`` delays until network connected. ``SO47 2`` delays until mqtt connected -- Command ``RgxClients`` for range extender clients list [#17048](https://github.com/arendst/Tasmota/issues/17048) -- Command ``RgxPort [tcp|udp], gateway_port, client_mac, client_port`` for range extender port forwardings [#17092](https://github.com/arendst/Tasmota/issues/17092) -- Command ``SSerialBuffer 256..SERIAL_BRIDGE_BUFFER_SIZE`` to change serial bridge rx buffer size [#17120](https://github.com/arendst/Tasmota/issues/17120) -- Command ``SwitchMode 16`` sending only MQTT message on inverted switch change [#17028](https://github.com/arendst/Tasmota/issues/17028) -- Command NeoPool ``NPFiltration 2`` toggle [#16859](https://github.com/arendst/Tasmota/issues/16859) -- Optional define ``SERIAL_BRIDGE_BUFFER_SIZE`` to set Serial Bridge internal buffer size (Default ESP8266 = 256, ESP32 = 800) -- Support for two phase power calibration using commands ``PowerSet2``, ``VoltageSet2`` and ``CurrentSet2`` -- Support for HLK-LD2410 24GHz smart wave motion sensor -- Support for Shelly Pro 1/1PM and 2/2PM [#16773](https://github.com/arendst/Tasmota/issues/16773) -- Support for up to four DS18x20 GPIOs by md5sum-as [#16833](https://github.com/arendst/Tasmota/issues/16833) -- Support for Digital Addressable Lighting Interface (DALI) by Andrei Kazmirtsuk [#16938](https://github.com/arendst/Tasmota/issues/16938) -- Support for NTAG2xx tags read and write on PN532 NFC reader [#16939](https://github.com/arendst/Tasmota/issues/16939) -- Support for Plantower PMSx003T AQI models with temperature and humidity [#16971](https://github.com/arendst/Tasmota/issues/16971) -- Support for BP1658CJ RGBCW led bulbs like Orein OS0100411267 by Cossid [#17011](https://github.com/arendst/Tasmota/issues/17011) -- Support for Dingtian x595 shift register based relay boards by Barbudor [#17032](https://github.com/arendst/Tasmota/issues/17032) -- Support for HMC5883L 3-Axis Digital Compass sensor by Andreas Achtzehn [#17069](https://github.com/arendst/Tasmota/issues/17069) -- Support for ME007-ULS narrow FoV ultrasonic distance sensor by Mathias Buder [#17376](https://github.com/arendst/Tasmota/issues/17376) -- WS2812 and Light ArtNet DMX control over UDP port 6454 [#17059](https://github.com/arendst/Tasmota/issues/17059) -- Teleinfo TEMPO (BBR) contract [#17160](https://github.com/arendst/Tasmota/issues/17160) -- Serial Modbus transmit enable GPIOs to all modbus energy drivers and modbus bridge [#17247](https://github.com/arendst/Tasmota/issues/17247) -- Berry ``bytes().setbytes()`` method [#16892](https://github.com/arendst/Tasmota/issues/16892) -- Berry ``bytes().reverse()`` method [#16977](https://github.com/arendst/Tasmota/issues/16977) -- Berry ``mdns`` module [#17202](https://github.com/arendst/Tasmota/issues/17202) -- Zigbee router firmware for Sonoff ZBBridgePro [#16900](https://github.com/arendst/Tasmota/issues/16900) -- ESP32 Support for DMX ArtNet Led matrix animations [#16984](https://github.com/arendst/Tasmota/issues/16984) -- ESP32 DS18x20 parasitic power usage when defining W1_PARASITE_POWER [#17112](https://github.com/arendst/Tasmota/issues/17112) ### Breaking Changed -- Redesign distance sensors VL53LXX, TOF10120, HRXL and DYP to use cm instead of mm [#17021](https://github.com/arendst/Tasmota/issues/17021) ### Changed -- TasmotaSerial library from v3.5.0 to v3.6.0 -- ESP32 Framework (Core) from v2.0.5 to v2.0.5.3 -- ESP32 LVGL library from v8.3.2 to v8.3.3 (no functional change) -- ESP32 NimBLE library from v1.4.0 to v1.4.1 [#16775](https://github.com/arendst/Tasmota/issues/16775) -- Serial Bridge default internal serial rx buffer size from 64 to 256 [#17120](https://github.com/arendst/Tasmota/issues/17120) -- DS18x20 ``DS18Alias`` to ``DS18Sens`` [#16833](https://github.com/arendst/Tasmota/issues/16833) -- Compiling with reduced boards manifests in favour of Autoconfig [#16848](https://github.com/arendst/Tasmota/issues/16848) -- ADE7953 monitoring from instant power to accumulated energy [#16941](https://github.com/arendst/Tasmota/issues/16941) - TuyaMcu rewrite by btsimonh [#17051](https://github.com/arendst/Tasmota/issues/17051) -- WS2812 sends signal to only ``Pixels`` leds instead of sending to 512 leds [#17055](https://github.com/arendst/Tasmota/issues/17055) -- AC PWM dimmer lineair power distribution [#17177](https://github.com/arendst/Tasmota/issues/17177) -- Zigbee improved Aqara plug support and completed cluster 0x0702 [#17073](https://github.com/arendst/Tasmota/issues/17073) -- Removed leading spaces on commands ``(S)SerialSend1 to 6`` but keep on duplicate commands ``(S)SerialSend11 to 16`` [#16723](https://github.com/arendst/Tasmota/issues/16723 -- Shutter bug fixes and functionality upgrade [#17380](https://github.com/arendst/Tasmota/issues/17380 -- MQTT now uses Tasmota's DNS resolver instead of LWIP [#17387](https://github.com/arendst/Tasmota/issues/17387 ### Fixed -- TasmotaSerial ``read(buffer, size)`` regression from v9.3.0 -- Serial bridge default serial configuration from 5N1 to 8N1 regression from v10.1.0.3 -- BP5758D red channel corruption regression from v12.1.1.6 [#16850](https://github.com/arendst/Tasmota/issues/16850) -- Deduplicate code and fix %timer n% rule regression from v12.2.0 [#16914](https://github.com/arendst/Tasmota/issues/16914) -- Serial initialization for baudrate and config [#16970](https://github.com/arendst/Tasmota/issues/16970) -- ModbusBridge buffer overflow [#16979](https://github.com/arendst/Tasmota/issues/16979) -- ModbusBridge baudrates over 76500 baud [#17106](https://github.com/arendst/Tasmota/issues/17106) -- SenseAir S8 module detection [#17033](https://github.com/arendst/Tasmota/issues/17033) -- Analog MQ exception 28 on restart [#17271](https://github.com/arendst/Tasmota/issues/17271) -- RCSwitch exception 0/6 on some protocols [#17285](https://github.com/arendst/Tasmota/issues/17285) -- ESP32 exception 28 when RtcNtpServer is enabled on restart [#17338](https://github.com/arendst/Tasmota/issues/17338) ### Removed -- Define ``USE_PN532_DATA_RAW`` from NFC reader [#16939](https://github.com/arendst/Tasmota/issues/16939) diff --git a/tasmota/include/tasmota_version.h b/tasmota/include/tasmota_version.h index f73a6a902..d80d04c05 100644 --- a/tasmota/include/tasmota_version.h +++ b/tasmota/include/tasmota_version.h @@ -20,6 +20,6 @@ #ifndef _TASMOTA_VERSION_H_ #define _TASMOTA_VERSION_H_ -const uint32_t VERSION = 0x0C020006; // 12.2.0.6 +const uint32_t VERSION = 0x0C030001; // 12.3.0.1 #endif // _TASMOTA_VERSION_H_ From bca659adf7b6c6f0b614efd2cc9c21e37cd43ec3 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Wed, 14 Dec 2022 15:04:15 +0100 Subject: [PATCH 002/262] Bump version v12.3.0.1 --- FIRMWARE.md | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/FIRMWARE.md b/FIRMWARE.md index 98cb9e02d..6be055328 100644 --- a/FIRMWARE.md +++ b/FIRMWARE.md @@ -18,7 +18,7 @@ See [CHANGELOG.md](https://github.com/arendst/Tasmota/blob/development/tasmota/C ## Development -[![Dev Version](https://img.shields.io/badge/development%20version-v12.2.x.x-blue.svg)](https://github.com/arendst/Tasmota) +[![Dev Version](https://img.shields.io/badge/development%20version-v12.3.x.x-blue.svg)](https://github.com/arendst/Tasmota) [![Download Dev](https://img.shields.io/badge/download-development-yellow.svg)](http://ota.tasmota.com/tasmota/) [![Tasmota CI](https://github.com/arendst/Tasmota/workflows/Tasmota%20CI/badge.svg)](https://github.com/arendst/Tasmota/actions?query=workflow%3A%22Tasmota+CI%22) [![Tasmota ESP32 CI](https://github.com/arendst/Tasmota/workflows/Tasmota%20ESP32%20CI/badge.svg)](https://github.com/arendst/Tasmota/actions?query=workflow%3A%22Tasmota+ESP32+CI%22) diff --git a/README.md b/README.md index 48a099409..c414ba828 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Firmware binaries can be downloaded from http://ota.tasmota.com/tasmota/release/ ## Development -[![Dev Version](https://img.shields.io/badge/development%20version-v12.2.x.x-blue.svg)](https://github.com/arendst/Tasmota) +[![Dev Version](https://img.shields.io/badge/development%20version-v12.3.x.x-blue.svg)](https://github.com/arendst/Tasmota) [![Download Dev](https://img.shields.io/badge/download-development-yellow.svg)](http://ota.tasmota.com/tasmota/) [![Tasmota CI](https://github.com/arendst/Tasmota/actions/workflows/build_all_the_things.yml/badge.svg)](https://github.com/arendst/Tasmota/actions/workflows/build_all_the_things.yml) [![Build_development](https://github.com/arendst/Tasmota/actions/workflows/Tasmota_build_devel.yml/badge.svg)](https://github.com/arendst/Tasmota/actions/workflows/Tasmota_build_devel.yml) From d2068b1c42c971508d484f18fc4aa136a006016a Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Wed, 14 Dec 2022 15:14:14 +0100 Subject: [PATCH 003/262] Add safeboot firmware to release (#17392) --- .github/workflows/Tasmota_build_master.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/Tasmota_build_master.yml b/.github/workflows/Tasmota_build_master.yml index 40f3baec2..901a06bea 100644 --- a/.github/workflows/Tasmota_build_master.yml +++ b/.github/workflows/Tasmota_build_master.yml @@ -180,10 +180,16 @@ jobs: continue-on-error: true steps: - uses: actions/checkout@v3 - - uses: actions/download-artifact@v3 + - name: Download Tasmota firmwares + uses: actions/download-artifact@v3 with: name: firmware path: ./mv_firmware + - name: Download safeboot firmwares + uses: actions/download-artifact@v3 + with: + name: firmware_safeboot + path: ./mv_firmware - name: Display structure of downloaded files run: ls -R ./mv_firmware/ - name: Release From 673966df099ef550310efc052788f15676e09125 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Wed, 14 Dec 2022 17:12:27 +0100 Subject: [PATCH 004/262] Use latest devel IPv6 frameworks (#17396) --- platformio_override_sample.ini | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/platformio_override_sample.ini b/platformio_override_sample.ini index 5f36e32f4..3dcff4fae 100644 --- a/platformio_override_sample.ini +++ b/platformio_override_sample.ini @@ -97,10 +97,10 @@ lib_extra_dirs = ${library.lib_extra_dirs} [env:tasmota32_base] ; *** Uncomment next lines ";" to enable development Tasmota Arduino version ESP32 -;platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.5.1/platform-espressif32-2.0.5.1.zip -;platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/1008/framework-arduinoespressif32-IDF_Arduino-d772747b2.zip -; framework-arduino-solo1 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/1014/framework-arduinoespressif32-solo1-IDF_Arduino-d772747b2.zip -; framework-arduino-ITEAD @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/1013/framework-arduinoespressif32-ITEAD-IDF_Arduino-d772747b2.zip +;platform = https://github.com/tasmota/platform-espressif32.git +;platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/1088/framework-arduinoespressif32-release_v4.4-a0113c7bfe.zip +; framework-arduino-solo1 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/1092/framework-arduinoespressif32-solo1-release_v4.4-a0113c7bfe.zip +; framework-arduino-ITEAD @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/1091/framework-arduinoespressif32-ITEAD-release_v4.4-a0113c7bfe.zip ;build_unflags = ${esp32_defaults.build_unflags} ;build_flags = ${esp32_defaults.build_flags} ;board = esp32 From 6658c8d269d13b1553ca6700126ef58192ad414f Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Thu, 15 Dec 2022 18:17:39 +0100 Subject: [PATCH 005/262] use `https` for esp32x for OTA (#17404) --- tasmota/my_user_config.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index 8d2a50a6e..0b879687f 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -99,15 +99,15 @@ #endif // ESP8266 #ifdef ESP32 #ifdef CONFIG_IDF_TARGET_ESP32C3 -#define OTA_URL "http://ota.tasmota.com/tasmota32/release/tasmota32c3.bin" // [OtaUrl] +#define OTA_URL "https://ota.tasmota.com/tasmota32/release/tasmota32c3.bin" // [OtaUrl] #elif defined(CONFIG_IDF_TARGET_ESP32S2) -#define OTA_URL "http://ota.tasmota.com/tasmota32/release/tasmota32s2.bin" // [OtaUrl] +#define OTA_URL "https://ota.tasmota.com/tasmota32/release/tasmota32s2.bin" // [OtaUrl] #elif defined(CONFIG_IDF_TARGET_ESP32S3) -#define OTA_URL "http://ota.tasmota.com/tasmota32/release/tasmota32s3.bin" // [OtaUrl] +#define OTA_URL "https://ota.tasmota.com/tasmota32/release/tasmota32s3.bin" // [OtaUrl] #elif defined(CORE32SOLO1) -#define OTA_URL "http://ota.tasmota.com/tasmota32/release/tasmota32solo1.bin" // [OtaUrl] +#define OTA_URL "https://ota.tasmota.com/tasmota32/release/tasmota32solo1.bin" // [OtaUrl] #else -#define OTA_URL "http://ota.tasmota.com/tasmota32/release/tasmota32.bin" // [OtaUrl] +#define OTA_URL "https://ota.tasmota.com/tasmota32/release/tasmota32.bin" // [OtaUrl] #endif // CONFIG_IDF_TARGET_ESP32C3 #endif // ESP32 From f8b56e105867624b8acb256697a208a810c7cd13 Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Thu, 15 Dec 2022 22:52:19 +0100 Subject: [PATCH 006/262] Zigbee fix crash on ESP8266 #17397 (#17405) --- CHANGELOG.md | 1 + tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_7_7_plugin.ino | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bcb28d49c..a89f01896 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ All notable changes to this project will be documented in this file. ### Changed ### Fixed +- Zigbee fix crash on ESP8266 #17397 ### Removed diff --git a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_7_7_plugin.ino b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_7_7_plugin.ino index 75adbc203..f6cc778d5 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_7_7_plugin.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_7_7_plugin.ino @@ -165,8 +165,8 @@ bool ZbLoad_inner(const char *filename, File &fp) { if (filename_imported == nullptr) { // allocate only once the filename for multiple entries // freed only by `ZbUnload` - filename_imported = (char*) malloc(strlen(filename)+1); - strcpy(filename_imported, filename); + filename_imported = (char*) malloc(strlen_P(filename)+1); + strcpy_P(filename_imported, filename); } // there is a non-empty line, containing no space/tab/crlf From 4e5c1f7a2d418c0cd48b91503c1260381523500f Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 16 Dec 2022 10:20:51 +0100 Subject: [PATCH 007/262] Bump version to v12.3.1.1 --- CHANGELOG.md | 14 +++++++++++--- RELEASENOTES.md | 10 +++++----- tasmota/include/tasmota_version.h | 2 +- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a89f01896..378d5f44a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,8 +3,7 @@ All notable changes to this project will be documented in this file. ## [Unreleased] - Development -## [12.3.0.1] - +## [12.3.1.1] 20221216 ### Added ### Breaking Changed @@ -12,12 +11,21 @@ All notable changes to this project will be documented in this file. ### Changed ### Fixed -- Zigbee fix crash on ESP8266 #17397 ### Removed ## [Released] +## [12.3.1] 20221216 +- Release Percy + +## [12.3.0.1] 20221216 +### Changed +- ESP32 initial otaurl from http to https + +### Fixed +- ESP8266 zigbee exception 3 regression from v12.3.0 (#17397) + ## [12.3.0] 20221215 - Release Percy diff --git a/RELEASENOTES.md b/RELEASENOTES.md index a0232063f..3fc43908f 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -72,7 +72,7 @@ Latest released binaries can be downloaded from - http://ota.tasmota.com/tasmota/release Historical binaries can be downloaded from -- http://ota.tasmota.com/tasmota/release-12.3.0 +- http://ota.tasmota.com/tasmota/release-12.3.1 The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmota.com/tasmota/release/tasmota.bin.gz`` @@ -94,12 +94,12 @@ The following binary downloads have been compiled with ESP32/Arduino library cor Latest released binaries can be downloaded from - https://github.com/arendst/Tasmota-firmware/tree/main/release-firmware -- http://ota.tasmota.com/tasmota32/release +- https://ota.tasmota.com/tasmota32/release Historical binaries can be downloaded from -- http://ota.tasmota.com/tasmota32/release-12.3.0 +- https://ota.tasmota.com/tasmota32/release-12.3.1 -The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmota.com/tasmota32/release/tasmota32.bin`` +The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasmota.com/tasmota32/release/tasmota32.bin`` ## Additional information @@ -107,7 +107,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmo [Complete list](BUILDS.md) of available feature and sensors. -## Changelog v12.3.0.1 +## Changelog v12.3.1.1 ### Added ### Breaking Changed diff --git a/tasmota/include/tasmota_version.h b/tasmota/include/tasmota_version.h index d80d04c05..498e76d8f 100644 --- a/tasmota/include/tasmota_version.h +++ b/tasmota/include/tasmota_version.h @@ -20,6 +20,6 @@ #ifndef _TASMOTA_VERSION_H_ #define _TASMOTA_VERSION_H_ -const uint32_t VERSION = 0x0C030001; // 12.3.0.1 +const uint32_t VERSION = 0x0C030101; // 12.3.1.1 #endif // _TASMOTA_VERSION_H_ From 458c0cfe0ec8b2efc47cc69c94802a52c95ee060 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Fri, 16 Dec 2022 12:00:33 +0100 Subject: [PATCH 008/262] fix needed depend. base32-images --- .github/workflows/Tasmota_build_master.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Tasmota_build_master.yml b/.github/workflows/Tasmota_build_master.yml index 901a06bea..8bd536243 100644 --- a/.github/workflows/Tasmota_build_master.yml +++ b/.github/workflows/Tasmota_build_master.yml @@ -175,7 +175,7 @@ jobs: path: ./build_output Upload: - needs: [base-images, language-images] + needs: [base-images, base32-images, language-images] runs-on: ubuntu-latest continue-on-error: true steps: From 72c9bca4d3d546ade8656fba765ae349be758d11 Mon Sep 17 00:00:00 2001 From: sedderz Date: Fri, 16 Dec 2022 16:30:59 +0000 Subject: [PATCH 009/262] ArtNet DMX - Added RGBWW support for single lights (#17398) * ArtNet DMX - Added RGBWW support for single lights * ArtNet DMX - Fix offset for single light Co-authored-by: sedgi --- .../xdrv_04_light_artnet.ino | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_04_light_artnet.ino b/tasmota/tasmota_xdrv_driver/xdrv_04_light_artnet.ino index 00259f326..49ebf6ddf 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_04_light_artnet.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_04_light_artnet.ino @@ -139,9 +139,9 @@ void ArtNetProcessPacket(uint8_t * buf, size_t len) { // AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("DMX: opcode=0x%04X procotol=%i universe=%i datalen=%i univ_start=%i univ_end=%i"), opcode, protocol, universe, datalen, artnet_conf.univ, artnet_conf.univ + artnet_conf.rows); if (opcode != 0x5000 || protocol != 14) { return; } - if (len + 18 < datalen) { - AddLog(LOG_LEVEL_DEBUG, PSTR("DMX: packet is truncated, ignoring packet")); - } +// if (len + 18 < datalen) { +// AddLog(LOG_LEVEL_DEBUG, PSTR("DMX: packet is truncated. Expected: %u Bytes, Received: %u Bytes."), datalen, len + 18); +// } if (universe < artnet_conf.univ || universe >= artnet_conf.univ + artnet_conf.rows) { return; } // universe is not ours, ignore size_t idx = 18; // start of payload data in the UDP frame @@ -194,14 +194,24 @@ void ArtNetProcessPacket(uint8_t * buf, size_t len) { Ws2812CopyPixels(&buf[idx], datalen, offset_in_matrix); } else { // single light - uint8_t r8 = buf[idx+1]; - uint8_t g8 = buf[idx]; - uint8_t b8 = buf[idx+2]; - uint16_t dimmer10 = changeUIntScale(artnet_conf.dimm, 0, 100, 0, 1023); + size_t offsidx = artnet_conf.offs + idx; + uint8_t r8 = buf[offsidx+1]; + uint8_t g8 = buf[offsidx]; + uint8_t b8 = buf[offsidx+2]; + uint8_t w8 = buf[offsidx+3]; + uint8_t ww8 = buf[offsidx+4]; + // scale dimmer values to RGBWWTable calibration + uint16_t r_dimmer = changeUIntScale(artnet_conf.dimm, 0, 100, 0, Settings->rgbwwTable[0]) * 4; + uint16_t g_dimmer = changeUIntScale(artnet_conf.dimm, 0, 100, 0, Settings->rgbwwTable[1]) * 4; + uint16_t b_dimmer = changeUIntScale(artnet_conf.dimm, 0, 100, 0, Settings->rgbwwTable[2]) * 4; + uint16_t w_dimmer = changeUIntScale(artnet_conf.dimm, 0, 100, 0, Settings->rgbwwTable[3]) * 4; + uint16_t ww_dimmer = changeUIntScale(artnet_conf.dimm, 0, 100, 0, Settings->rgbwwTable[4]) * 4; uint16_t color[LST_MAX] = {0}; - color[0] = changeUIntScale(r8, 0, 255, 0, dimmer10); - color[1] = changeUIntScale(g8, 0, 255, 0, dimmer10); - color[2] = changeUIntScale(b8, 0, 255, 0, dimmer10); + color[0] = changeUIntScale(r8, 0, 255, 0, r_dimmer); + color[1] = changeUIntScale(g8, 0, 255, 0, g_dimmer); + color[2] = changeUIntScale(b8, 0, 255, 0, b_dimmer); + color[3] = changeUIntScale(w8, 0, 255, 0, w_dimmer); + color[4] = changeUIntScale(ww8, 0, 255, 0, ww_dimmer); // AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("DMX: %02X-%02X-%02X univ=%i rows=%i max_univ=%i"), buf[idx+1], buf[idx], buf[idx+2], universe, row, artnet_conf.univ + artnet_conf.rows); LightSetOutputs(color); } From ebf87bdfc89f2c8589eb034a6bd0100ce47cbcb3 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Fri, 16 Dec 2022 18:10:57 +0100 Subject: [PATCH 010/262] changes FS for Arduino stage (#17413) --- .../Zip-readonly-FS/src/ZipReadFS.cpp | 43 ++++++++++++++++--- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/lib/libesp32/Zip-readonly-FS/src/ZipReadFS.cpp b/lib/libesp32/Zip-readonly-FS/src/ZipReadFS.cpp index 4cfc6dbd2..278802e9b 100644 --- a/lib/libesp32/Zip-readonly-FS/src/ZipReadFS.cpp +++ b/lib/libesp32/Zip-readonly-FS/src/ZipReadFS.cpp @@ -59,7 +59,7 @@ time_t dos2unixtime(uint32_t dostime) /******************************************************************** ** Zip file parser -** +** ********************************************************************/ template class LList; @@ -119,7 +119,7 @@ protected: /******************************************************************** ** Neutral file overlay -** +** ********************************************************************/ class ZipReadFileImpl; @@ -175,13 +175,29 @@ public: return true; } + #if ESP_ARDUINO_VERSION > ESP_ARDUINO_VERSION_VAL(2, 0, 5) + bool seekDir(long position){ + if(!_f){ + return false; + } + return _f.seekDir(position); + } + String getNextFileName(void) + { + if (!_f) { + return ""; + } + return _f.getNextFileName(); + } + #endif + protected: File _f; }; /******************************************************************** ** Subfile implementation -** +** ** Takes a `File` object of the ZIP archive ** First byte in archive and len ********************************************************************/ @@ -285,6 +301,23 @@ public: return nullptr; // TODO } + #if ESP_ARDUINO_VERSION > ESP_ARDUINO_VERSION_VAL(2, 0, 5) + bool seekDir(long position){ + if(!_f){ + return false; + } + return _f.seekDir(position); + } + + String getNextFileName(void) + { + if (!_f) { + return ""; + } + return _f.getNextFileName(); + } + #endif + void rewindDirectory(void) { // ignore } @@ -390,7 +423,7 @@ bool ZipArchive::parse(void) { /******************************************************************** ** Encapsulation of FS and File to piggyback on Arduino -** +** ********************************************************************/ /* get the FS corresponding to the prefix, typically /sd/ for sdcard */ @@ -491,4 +524,4 @@ bool ZipReadFSImpl::exists(const char* path) { ZipReadFSImpl::~ZipReadFSImpl() {}; -#endif // ESP32 \ No newline at end of file +#endif // ESP32 From 9abe7b1af92617737b7f8bb0475ea982a141f1e5 Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Sat, 17 Dec 2022 10:08:35 +0100 Subject: [PATCH 011/262] Support for IPv6 DNS records (AAAA) and IPv6 ``Ping`` for ESP32 and ESP8266 (#17417) --- CHANGELOG.md | 1 + lib/default/DnsClient/library.properties | 7 - lib/default/DnsClient/src/DnsClient.cpp | 334 ------------------ lib/default/DnsClient/src/DnsClient.h | 42 --- .../ESP32-to-ESP8266-compat/src/ESP32Wifi.cpp | 140 +++++++- .../ESP32-to-ESP8266-compat/src/ESP8266WiFi.h | 14 +- tasmota/include/tasmota_types.h | 2 +- tasmota/tasmota.ino | 3 - tasmota/tasmota_support/support_command.ino | 1 - tasmota/tasmota_support/support_wifi.ino | 76 ++-- tasmota/tasmota_xdrv_driver/xdrv_38_ping.ino | 91 ++++- .../xdrv_82_esp32_ethernet.ino | 1 + 12 files changed, 280 insertions(+), 432 deletions(-) delete mode 100644 lib/default/DnsClient/library.properties delete mode 100644 lib/default/DnsClient/src/DnsClient.cpp delete mode 100644 lib/default/DnsClient/src/DnsClient.h diff --git a/CHANGELOG.md b/CHANGELOG.md index 378d5f44a..a709ac006 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file. ## [12.3.1.1] 20221216 ### Added +- Support for IPv6 DNS records (AAAA) and IPv6 ``Ping`` for ESP32 and ESP8266 ### Breaking Changed diff --git a/lib/default/DnsClient/library.properties b/lib/default/DnsClient/library.properties deleted file mode 100644 index 7ac2d2393..000000000 --- a/lib/default/DnsClient/library.properties +++ /dev/null @@ -1,7 +0,0 @@ -name=DnsClient -version=1.0 -author=MCQN Ltd, Theo Arends -maintainer=Theo -sentence=Dns client allowing timeout selection. -paragraph=This class uses WifiUdp. -architectures=esp8266,esp32 diff --git a/lib/default/DnsClient/src/DnsClient.cpp b/lib/default/DnsClient/src/DnsClient.cpp deleted file mode 100644 index 19bc4444d..000000000 --- a/lib/default/DnsClient/src/DnsClient.cpp +++ /dev/null @@ -1,334 +0,0 @@ -/* - DnsClient.cpp - DNS client for Arduino - - SPDX-FileCopyrightText: 2009-2010 MCQN Ltd. and Theo Arends - - SPDX-License-Identifier: GPL-3.0-only -*/ - -// Arduino DNS client for WizNet5100-based Ethernet shield -// (c) Copyright 2009-2010 MCQN Ltd. -// Released under Apache License, version 2.0 - -#include "DnsClient.h" - -// Various flags and header field values for a DNS message -#define UDP_HEADER_SIZE 8 -#define DNS_HEADER_SIZE 12 -#define TTL_SIZE 4 -#define QUERY_FLAG (0) -#define RESPONSE_FLAG (1<<15) -#define QUERY_RESPONSE_MASK (1<<15) -#define OPCODE_STANDARD_QUERY (0) -#define OPCODE_INVERSE_QUERY (1<<11) -#define OPCODE_STATUS_REQUEST (2<<11) -#define OPCODE_MASK (15<<11) -#define AUTHORITATIVE_FLAG (1<<10) -#define TRUNCATION_FLAG (1<<9) -#define RECURSION_DESIRED_FLAG (1<<8) -#define RECURSION_AVAILABLE_FLAG (1<<7) -#define RESP_NO_ERROR (0) -#define RESP_FORMAT_ERROR (1) -#define RESP_SERVER_FAILURE (2) -#define RESP_NAME_ERROR (3) -#define RESP_NOT_IMPLEMENTED (4) -#define RESP_REFUSED (5) -#define RESP_MASK (15) -#define TYPE_A (0x0001) -#define CLASS_IN (0x0001) -#define LABEL_COMPRESSION_MASK (0xC0) -// Port number that DNS servers listen on -#define DNS_PORT 53 - -// Possible return codes from ProcessResponse -#define SUCCESS 1 -#define TIMED_OUT -1 -#define INVALID_SERVER -2 -#define TRUNCATED -3 -#define INVALID_RESPONSE -4 - -#ifndef htons -#define htons(x) ( ((x)<< 8 & 0xFF00) | ((x)>> 8 & 0x00FF) ) -#endif - -void DNSClient::begin(const IPAddress& aDNSServer) { - iDNSServer = aDNSServer; - iRequestId = 0; -} - -void DNSClient::setTimeout(uint32_t aTimeout) { - iTimeout = aTimeout; -} - -int DNSClient::getHostByName(const char* aHostname, IPAddress& aResult) { - // See if it's a numeric IP address - if (aResult.fromString(aHostname)) { - // It is, our work here is done - return SUCCESS; - } - - // Check we've got a valid DNS server to use - if ((0xFFFFFFFF == (uint32_t)iDNSServer) || (0 == (uint32_t)iDNSServer)) { - return INVALID_SERVER; - } - - int ret = 0; - // Find a socket to use - if (iUdp.begin(1024+(millis() & 0xF)) == 1) { - // Try up to three times - int retries = 0; -// while ((retries < 3) && (ret <= 0)) { - // Send DNS request - ret = iUdp.beginPacket(iDNSServer, DNS_PORT); - if (ret != 0) { - // Now output the request data - ret = BuildRequest(aHostname); - if (ret != 0) { - // And finally send the request - ret = iUdp.endPacket(); - if (ret != 0) { - // Now wait for a response - int wait_retries = 0; - ret = TIMED_OUT; - while ((wait_retries < 3) && (ret == TIMED_OUT)) { - ret = ProcessResponse(iTimeout, aResult); - wait_retries++; - } - } - } - } - retries++; -// } - // We're done with the socket now - iUdp.stop(); - } - return ret; -} - -int DNSClient::BuildRequest(const char* aName) { - // Build header - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - // | ID | - // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - // |QR| Opcode |AA|TC|RD|RA| Z | RCODE | - // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - // | QDCOUNT | - // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - // | ANCOUNT | - // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - // | NSCOUNT | - // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - // | ARCOUNT | - // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - // As we only support one request at a time at present, we can simplify - // some of this header - iRequestId = millis(); // generate a random ID - uint16_t twoByteBuffer; - - // FIXME We should also check that there's enough space available to write to, rather - // FIXME than assume there's enough space (as the code does at present) - iUdp.write((uint8_t*)&iRequestId, sizeof(iRequestId)); - - twoByteBuffer = htons(QUERY_FLAG | OPCODE_STANDARD_QUERY | RECURSION_DESIRED_FLAG); - iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); - - twoByteBuffer = htons(1); // One question record - iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); - - twoByteBuffer = 0; // Zero answer records - iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); - - iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); - // and zero additional records - iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); - - // Build question - const char* start =aName; - const char* end =start; - uint8_t len; - // Run through the name being requested - while (*end) { - // Find out how long this section of the name is - end = start; - while (*end && (*end != '.') ) { - end++; - } - - if (end-start > 0) { - // Write out the size of this section - len = end-start; - iUdp.write(&len, sizeof(len)); - // And then write out the section - iUdp.write((uint8_t*)start, end-start); - } - start = end+1; - } - - // We've got to the end of the question name, so terminate it with a zero-length section - len = 0; - iUdp.write(&len, sizeof(len)); - // Finally the type and class of question - twoByteBuffer = htons(TYPE_A); - iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); - - twoByteBuffer = htons(CLASS_IN); // Internet class of question - iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); - // Success! Everything buffered okay - return SUCCESS; -} - -int DNSClient::ProcessResponse(uint32_t aTimeout, IPAddress& aAddress) { - uint32_t startTime = millis(); - - // Wait for a response packet - while(iUdp.parsePacket() <= 0) { - if ((millis() - startTime) > aTimeout) { - return TIMED_OUT; - } - delay(20); - } - - // We've had a reply! - // Read the UDP header - uint8_t header[DNS_HEADER_SIZE]; // Enough space to reuse for the DNS header - // Check that it's a response from the right server and the right port - if ( (iDNSServer != iUdp.remoteIP()) || (iUdp.remotePort() != DNS_PORT) ) { - // It's not from who we expected - return INVALID_SERVER; - } - - // Read through the rest of the response - if (iUdp.available() < DNS_HEADER_SIZE) { - return TRUNCATED; - } - iUdp.read(header, DNS_HEADER_SIZE); - - uint16_t staging; // Staging used to avoid type-punning warnings - memcpy(&staging, &header[2], sizeof(uint16_t)); - uint16_t header_flags = htons(staging); - memcpy(&staging, &header[0], sizeof(uint16_t)); - // Check that it's a response to this request - if ( (iRequestId != staging) || ((header_flags & QUERY_RESPONSE_MASK) != (uint16_t)RESPONSE_FLAG) ) { - // Mark the entire packet as read - iUdp.flush(); - return INVALID_RESPONSE; - } - // Check for any errors in the response (or in our request) - // although we don't do anything to get round these - if ( (header_flags & TRUNCATION_FLAG) || (header_flags & RESP_MASK) ) { - // Mark the entire packet as read - iUdp.flush(); - return -5; // INVALID_RESPONSE; - } - - // And make sure we've got (at least) one answer - memcpy(&staging, &header[6], sizeof(uint16_t)); - uint16_t answerCount = htons(staging); - if (answerCount == 0 ) { - // Mark the entire packet as read - iUdp.flush(); - return -6; // INVALID_RESPONSE; - } - - // Skip over any questions - memcpy(&staging, &header[4], sizeof(uint16_t)); - for (uint32_t i = 0; i < htons(staging); i++) { - // Skip over the name - uint8_t len; - do { - iUdp.read(&len, sizeof(len)); - if (len > 0) { - // Don't need to actually read the data out for the string, just - // advance ptr to beyond it - while(len--) { - iUdp.read(); // we don't care about the returned byte - } - } - } while (len != 0); - - // Now jump over the type and class - for (uint32_t i = 0; i < 4; i++) { - iUdp.read(); // we don't care about the returned byte - } - } - - // Now we're up to the bit we're interested in, the answer - // There might be more than one answer (although we'll just use the first - // type A answer) and some authority and additional resource records but - // we're going to ignore all of them. - - for (uint32_t i = 0; i < answerCount; i++) { - // Skip the name - uint8_t len; - do { - iUdp.read(&len, sizeof(len)); - if ((len & LABEL_COMPRESSION_MASK) == 0) { - // It's just a normal label - if (len > 0) { - // And it's got a length - // Don't need to actually read the data out for the string, - // just advance ptr to beyond it - while(len--) { - iUdp.read(); // we don't care about the returned byte - } - } - } else { - // This is a pointer to a somewhere else in the message for the - // rest of the name. We don't care about the name, and RFC1035 - // says that a name is either a sequence of labels ended with a - // 0 length octet or a pointer or a sequence of labels ending in - // a pointer. Either way, when we get here we're at the end of - // the name - // Skip over the pointer - iUdp.read(); // we don't care about the returned byte - // And set len so that we drop out of the name loop - len = 0; - } - } while (len != 0); - - // Check the type and class - uint16_t answerType; - uint16_t answerClass; - iUdp.read((uint8_t*)&answerType, sizeof(answerType)); - iUdp.read((uint8_t*)&answerClass, sizeof(answerClass)); - - // Ignore the Time-To-Live as we don't do any caching - for (uint32_t i = 0; i < TTL_SIZE; i++) { - iUdp.read(); // We don't care about the returned byte - } - - // And read out the length of this answer - // Don't need header_flags anymore, so we can reuse it here - iUdp.read((uint8_t*)&header_flags, sizeof(header_flags)); - - if ( (htons(answerType) == TYPE_A) && (htons(answerClass) == CLASS_IN) ) { - if (htons(header_flags) != 4) { - // It's a weird size - // Mark the entire packet as read - iUdp.flush(); - return -9; // INVALID_RESPONSE; - } - iUdp.read(aAddress.raw_address(), 4); -// uint32_t address; -// iUdp.read((uint8_t*)&address, sizeof(address)); -// aAddress = (IPAddress)address; - - // Check we've got a valid address - if ((0xFFFFFFFF != (uint32_t)aAddress) && (0 != (uint32_t)aAddress)) { - return SUCCESS; - } - } else { - // This isn't an answer type we're after, move onto the next one - for (uint32_t i = 0; i < htons(header_flags); i++) { - iUdp.read(); // we don't care about the returned byte - } - } - } - - // Mark the entire packet as read - iUdp.flush(); - - // If we get here then we haven't found an answer - return -10; // INVALID_RESPONSE; -} diff --git a/lib/default/DnsClient/src/DnsClient.h b/lib/default/DnsClient/src/DnsClient.h deleted file mode 100644 index 42f29b190..000000000 --- a/lib/default/DnsClient/src/DnsClient.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - DnsClient.h - DNS client for Arduino - - SPDX-FileCopyrightText: 2009-2010 MCQN Ltd. and Theo Arends - - SPDX-License-Identifier: GPL-3.0-only -*/ - -// Arduino DNS client for WizNet5100-based Ethernet shield -// (c) Copyright 2009-2010 MCQN Ltd. -// Released under Apache License, version 2.0 - -#ifndef DNSClient_h -#define DNSClient_h - -#include -#include -#include - -class DNSClient { -public: - void begin(const IPAddress& aDNSServer); - void setTimeout(uint32_t aTimeout = 1000); - - /* Resolve the given hostname to an IP address. - @param aHostname Name to be resolved - @param aResult IPAddress structure to store the returned IP address - @result 1 if aIPAddrString was successfully converted to an IP address, else error code - */ - int getHostByName(const char* aHostname, IPAddress& aResult); - -protected: - int BuildRequest(const char* aName); - int ProcessResponse(uint32_t aTimeout, IPAddress& aAddress); - - IPAddress iDNSServer; - uint16_t iRequestId; - uint16_t iTimeout = 1000; - WiFiUDP iUdp; -}; - -#endif diff --git a/lib/libesp32/ESP32-to-ESP8266-compat/src/ESP32Wifi.cpp b/lib/libesp32/ESP32-to-ESP8266-compat/src/ESP32Wifi.cpp index 43ec90479..030ec6321 100644 --- a/lib/libesp32/ESP32-to-ESP8266-compat/src/ESP32Wifi.cpp +++ b/lib/libesp32/ESP32-to-ESP8266-compat/src/ESP32Wifi.cpp @@ -28,6 +28,55 @@ #undef WiFi #endif +#include "tasmota_options.h" +#include "lwip/dns.h" + +wl_status_t WiFiClass32::begin(const char* wpa2_ssid, wpa2_auth_method_t method, const char* wpa2_identity, const char* wpa2_username, const char *wpa2_password, const char* ca_pem, const char* client_crt, const char* client_key, int32_t channel, const uint8_t* bssid, bool connect) { + saveDNS(); + wl_status_t ret = WiFiClass::begin(wpa2_ssid, method, wpa2_identity, wpa2_username, wpa2_password, ca_pem, client_crt, client_key, channel, bssid, connect); + restoreDNS(); + return ret; +} + +wl_status_t WiFiClass32::begin(const char* ssid, const char *passphrase, int32_t channel, const uint8_t* bssid, bool connect) { + saveDNS(); + wl_status_t ret = WiFiClass::begin(ssid, passphrase, channel, bssid, connect); + restoreDNS(); + return ret; +} + +wl_status_t WiFiClass32::begin(char* ssid, char *passphrase, int32_t channel, const uint8_t* bssid, bool connect) { + saveDNS(); + wl_status_t ret = WiFiClass::begin(ssid, passphrase, channel, bssid, connect); + restoreDNS(); + return ret; +} +wl_status_t WiFiClass32::begin() { + saveDNS(); + wl_status_t ret = WiFiClass::begin(); + restoreDNS(); + return ret; +} + +void WiFiClass32::saveDNS(void) { + // save the DNS servers + for (uint32_t i=0; i", IPAddress(ipaddr).toString().c_str(), (int) callback_arg, ip_addr_counter); + uint32_t cb_counter = (uint32_t) callback_arg; + if (cb_counter != ip_addr_counter) { return; } // the response is from a previous request, ignore + + if (ipaddr != nullptr) { + dns_ipaddr = *ipaddr; + } else { + dns_ipaddr = *IP4_ADDR_ANY; // set to IPv4 0.0.0.0 + } + WiFiClass32::dnsDone(); + // AddLog(LOG_LEVEL_DEBUG, "WIF: dns_found=%s", ipaddr ? IPAddress(*ipaddr).toString().c_str() : ""); +} +// We need this helper method to access protected methods from WiFiGeneric +void WiFiClass32::dnsDone(void) { + setStatusBits(WIFI_DNS_DONE_BIT); +} + +/** + * Resolve the given hostname to an IP address. + * @param aHostname Name to be resolved + * @param aResult IPAddress structure to store the returned IP address + * @return 1 if aIPAddrString was successfully converted to an IP address, + * else error code + */ +int WiFiClass32::hostByName(const char* aHostname, IPAddress& aResult, int32_t timer_ms) +{ + ip_addr_t addr; + aResult = (uint32_t) 0; // by default set to IPv4 0.0.0.0 + dns_ipaddr = *IP4_ADDR_ANY; // by default set to IPv4 0.0.0.0 + + ip_addr_counter++; // increase counter, from now ignore previous responses + clearStatusBits(WIFI_DNS_IDLE_BIT | WIFI_DNS_DONE_BIT); + uint8_t v4v6priority = LWIP_DNS_ADDRTYPE_IPV4; +#ifdef USE_IPV6 + v4v6priority = WifiDNSGetIPv6Priority() ? LWIP_DNS_ADDRTYPE_IPV6_IPV4 : LWIP_DNS_ADDRTYPE_IPV4_IPV6; +#endif // USE_IPV6 + err_t err = dns_gethostbyname_addrtype(aHostname, &dns_ipaddr, &wifi32_dns_found_callback, (void*) ip_addr_counter, v4v6priority); + // Serial.printf("DNS: dns_gethostbyname_addrtype errg=%i counter=%i\n", err, ip_addr_counter); + if(err == ERR_OK && !ip_addr_isany_val(dns_ipaddr)) { +#ifdef USE_IPV6 + aResult = dns_ipaddr; +#else // USE_IPV6 + aResult = ip_addr_get_ip4_u32(&dns_ipaddr); +#endif // USE_IPV6 + } else if(err == ERR_INPROGRESS) { + waitStatusBits(WIFI_DNS_DONE_BIT, timer_ms); //real internal timeout in lwip library is 14[s] + clearStatusBits(WIFI_DNS_DONE_BIT); + } + + if (!ip_addr_isany_val(dns_ipaddr)) { +#ifdef USE_IPV6 + aResult = dns_ipaddr; +#else // USE_IPV6 + aResult = ip_addr_get_ip4_u32(&dns_ipaddr); +#endif // USE_IPV6 + return true; + } + return false; +} + +int WiFiClass32::hostByName(const char* aHostname, IPAddress& aResult) +{ + return hostByName(aHostname, aResult, WifiDNSGetTimeout()); } void wifi_station_disconnect() { diff --git a/lib/libesp32/ESP32-to-ESP8266-compat/src/ESP8266WiFi.h b/lib/libesp32/ESP32-to-ESP8266-compat/src/ESP8266WiFi.h index 1c1630b4c..d0274733d 100644 --- a/lib/libesp32/ESP32-to-ESP8266-compat/src/ESP8266WiFi.h +++ b/lib/libesp32/ESP32-to-ESP8266-compat/src/ESP8266WiFi.h @@ -37,6 +37,11 @@ typedef enum WiFiPhyMode class WiFiClass32 : public WiFiClass { public: + wl_status_t begin(const char* wpa2_ssid, wpa2_auth_method_t method, const char* wpa2_identity=NULL, const char* wpa2_username=NULL, const char *wpa2_password=NULL, const char* ca_pem=NULL, const char* client_crt=NULL, const char* client_key=NULL, int32_t channel=0, const uint8_t* bssid=0, bool connect=true); + wl_status_t begin(const char* ssid, const char *passphrase = NULL, int32_t channel = 0, const uint8_t* bssid = NULL, bool connect = true); + wl_status_t begin(char* ssid, char *passphrase = NULL, int32_t channel = 0, const uint8_t* bssid = NULL, bool connect = true); + wl_status_t begin(); + static void hostname(const char* aHostname) { WiFi.setHostname(aHostname); @@ -51,7 +56,14 @@ public: static void forceSleepWake(); static bool getNetworkInfo(uint8_t i, String &ssid, uint8_t &encType, int32_t &rssi, uint8_t* &bssid, int32_t &channel, bool &hidden_scan); - bool IPv6(bool state); // make sure it always exists even with older Arduino framework + static void dnsDone(void); // used by the callback to stop the dns timer + int hostByName(const char* aHostname, IPAddress& aResult, int32_t timer_ms); + int hostByName(const char* aHostname, IPAddress& aResult); + + void saveDNS(void); + void restoreDNS(void); +protected: + ip_addr_t dns_save[DNS_MAX_SERVERS] = {}; }; void wifi_station_disconnect(); diff --git a/tasmota/include/tasmota_types.h b/tasmota/include/tasmota_types.h index 4ee133e04..5a268a666 100644 --- a/tasmota/include/tasmota_types.h +++ b/tasmota/include/tasmota_types.h @@ -182,7 +182,7 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu uint32_t use_esp32_temperature : 1; // bit 0 (v12.1.1.1) - SetOption146 - (ESP32) Show ESP32 internal temperature sensor uint32_t mqtt_disable_sserialrec : 1; // bit 1 (v12.1.1.2) - SetOption147 - (MQTT) Disable publish SSerialReceived MQTT messages, you must use event trigger rules instead. uint32_t artnet_autorun : 1; // bit 2 (v12.2.0.4) - SetOption148 - (Light) start DMX ArtNet at boot, listen to UDP port as soon as network is up - uint32_t spare03 : 1; // bit 3 + uint32_t dns_ipv6_priority : 1; // bit 3 (v12.2.0.6) - SetOption149 - (Wifi) prefer IPv6 DNS resolution to IPv4 address when available. Requires `#define USE_IPV6` uint32_t spare04 : 1; // bit 4 uint32_t spare05 : 1; // bit 5 uint32_t spare06 : 1; // bit 6 diff --git a/tasmota/tasmota.ino b/tasmota/tasmota.ino index 479dce33a..67bf25cd5 100644 --- a/tasmota/tasmota.ino +++ b/tasmota/tasmota.ino @@ -42,7 +42,6 @@ // Libraries #include // Ota #include // Ota -#include // Any getHostByName #ifdef ESP32 #ifdef USE_TLS #include "HTTPUpdateLight.h" // Ota over HTTPS for ESP32 @@ -193,7 +192,6 @@ struct XDRVMAILBOX { char *command; } XdrvMailbox; -DNSClient DnsClient; WiFiUDP PortUdp; // UDP Syslog and Alexa #ifdef ESP32 @@ -634,7 +632,6 @@ void setup(void) { TasmotaGlobal.init_state = INIT_GPIOS; SetPowerOnState(); - DnsClient.setTimeout(Settings->dns_timeout); WifiConnect(); AddLog(LOG_LEVEL_INFO, PSTR(D_PROJECT " %s - %s " D_VERSION " %s%s-" ARDUINO_CORE_RELEASE "(%s)"), diff --git a/tasmota/tasmota_support/support_command.ino b/tasmota/tasmota_support/support_command.ino index 07fba6fe4..ca5ec268a 100644 --- a/tasmota/tasmota_support/support_command.ino +++ b/tasmota/tasmota_support/support_command.ino @@ -2516,7 +2516,6 @@ void CmndDnsTimeout(void) { // Set timeout between 100 and 20000 mSec if ((XdrvMailbox.payload >= 100) && (XdrvMailbox.payload <= 20000)) { Settings->dns_timeout = XdrvMailbox.payload; - DnsClient.setTimeout(Settings->dns_timeout); } ResponseCmndNumber(Settings->dns_timeout); } diff --git a/tasmota/tasmota_support/support_wifi.ino b/tasmota/tasmota_support/support_wifi.ino index cc03a8fde..4d8867573 100644 --- a/tasmota/tasmota_support/support_wifi.ino +++ b/tasmota/tasmota_support/support_wifi.ino @@ -500,6 +500,7 @@ void CreateLinkLocalIPv6(void) } // +#include "lwip/dns.h" void WifiDumpAddressesIPv6(void) { for (netif* intf = netif_list; intf != nullptr; intf = intf->next) { @@ -511,6 +512,8 @@ void WifiDumpAddressesIPv6(void) ip_addr_islinklocal(&intf->ip6_addr[i]) ? "local" : ""); } } + AddLog(LOG_LEVEL_DEBUG, "WIF: DNS(0): %s", IPAddress(dns_getserver(0)).toString().c_str()); + AddLog(LOG_LEVEL_DEBUG, "WIF: DNS(1): %s", IPAddress(dns_getserver(1)).toString().c_str()); } #endif // USE_IPV6 @@ -890,37 +893,56 @@ void wifiKeepAlive(void) { } #endif // ESP8266 +// expose a function to be called by WiFi32 +int32_t WifiDNSGetTimeout(void) { + return Settings->dns_timeout; +} +// read Settings for DNS IPv6 priority +bool WifiDNSGetIPv6Priority(void) { +#ifdef USE_IPV6 + // we prioritize IPv6 only if a global IPv6 address is available, otherwise revert to IPv4 if we have one as well + // Any change in logic needs to clear the DNS cache + static bool had_v6prio = false; + + const ip_addr_t &local_ip = (ip_addr_t)WiFi.localIP(); + bool has_v4 = !ip_addr_isany_val(local_ip) && IP_IS_V4_VAL(local_ip); + bool has_v6 = WifiGetIPv6().length() != 0; +#ifdef USE_ETHERNET + const ip_addr_t &local_ip_eth = (ip_addr_t)EthernetLocalIP(); + has_v4 = has_v4 || (!ip_addr_isany_val(local_ip_eth) && IP_IS_V4_VAL(local_ip_eth)); + has_v6 = has_v6 || EthernetGetIPv6().length() != 0; +#endif + + bool v6prio = Settings->flag6.dns_ipv6_priority; + // AddLog(LOG_LEVEL_DEBUG, "WIF: v6 priority was %i, now is %i, has_v4=%i has_v6=%i", had_v6prio, v6prio, has_v4, has_v6); + + if (has_v4 && !has_v6 && v6prio) { + v6prio = false; // revert to IPv4 first + } + + // any change of state requires a dns cache clear + if (had_v6prio != v6prio) { + dns_clear_cache(); + had_v6prio = v6prio; + } + + return v6prio; +#endif // USE_IPV6 + return false; +} + bool WifiHostByName(const char* aHostname, IPAddress& aResult) { -#ifdef ESP8266 - if (WiFi.hostByName(aHostname, aResult, Settings->dns_timeout)) { + uint32_t dns_start = millis(); + bool success = WiFi.hostByName(aHostname, aResult, Settings->dns_timeout); + uint32_t dns_end = millis(); + if (success) { // Host name resolved if (0xFFFFFFFF != (uint32_t)aResult) { + AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_WIFI "DNS resolved '%s' (%s) in %i ms"), aHostname, aResult.toString().c_str(), dns_end - dns_start); return true; } } -#else - // DnsClient can't do one-shot mDNS queries so use WiFi.hostByName() for *.local - aResult = (uint32_t) 0x00000000L; // indirectly force to be IPv4, since the client touches the binary format later - size_t hostname_len = strlen(aHostname); - if (strstr_P(aHostname, PSTR(".local")) == &aHostname[hostname_len] - 6) { - if (WiFi.hostByName(aHostname, aResult)) { - // Host name resolved - if (0xFFFFFFFF != (uint32_t)aResult) { - AddLog(LOG_LEVEL_DEBUG, "WIF: Resolving '%s' (%s)", aHostname, aResult.toString().c_str()); - return true; - } - } - } else { - // Use this instead of WiFi.hostByName or connect(host_name,.. to block less if DNS server is not found - uint32_t dns_address = (!TasmotaGlobal.global_state.eth_down) ? Settings->eth_ipv4_address[3] : Settings->ipv4_address[3]; - DnsClient.begin((IPAddress)dns_address); - if (1 == DnsClient.getHostByName(aHostname, aResult)) { - AddLog(LOG_LEVEL_DEBUG, "WIF: Resolving '%s' (%s)", aHostname, aResult.toString().c_str()); - return true; - } - } -#endif - AddLog(LOG_LEVEL_DEBUG, PSTR("DNS: Unable to resolve '%s'"), aHostname); + AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_WIFI "DNS failed for %s after %i ms"), aHostname, dns_end - dns_start); return false; } @@ -1091,6 +1113,7 @@ void WifiEvents(arduino_event_t *event) { AddLog(LOG_LEVEL_DEBUG, PSTR("%s: IPv6 %s %s"), event->event_id == ARDUINO_EVENT_ETH_GOT_IP6 ? "ETH" : "WIF", addr.isLocal() ? PSTR("Local") : PSTR("Global"), addr.toString().c_str()); + WiFi.saveDNS(); // internal calls to reconnect can zero the DNS servers, save DNS for future use } break; #endif // USE_IPV6 @@ -1104,7 +1127,7 @@ void WifiEvents(arduino_event_t *event) { event->event_info.got_ip.ip_info.ip.addr, event->event_info.got_ip.ip_info.netmask.addr, event->event_info.got_ip.ip_info.gw.addr); - + WiFi.saveDNS(); // internal calls to reconnect can zero the DNS servers, save DNS for future use } break; @@ -1114,6 +1137,7 @@ void WifiEvents(arduino_event_t *event) { break; case ARDUINO_EVENT_WIFI_STA_DISCONNECTED: case ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE: + WiFi.restoreDNS(); // internal calls to reconnect can zero the DNS servers, restore the previous values Wifi.ipv6_local_link_called = false; break; diff --git a/tasmota/tasmota_xdrv_driver/xdrv_38_ping.ino b/tasmota/tasmota_xdrv_driver/xdrv_38_ping.ino index de9cfb61f..ba7914c5f 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_38_ping.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_38_ping.ino @@ -64,6 +64,9 @@ extern "C" { // globals Ping_t *ping_head = nullptr; // head of the Linked List for ping objects struct raw_pcb *t_ping_pcb = nullptr; // registered with first ping, deregistered after last ping, the same pcb is used for all packets +#ifdef USE_IPV6 + struct raw_pcb *t_ping6_pcb = nullptr; // IPv6 version, registered with first ping, deregistered after last ping, the same pcb is used for all packets +#endif // USE_IPV6 // ================================================================================ // Find the Ping object indexed by IP address @@ -75,7 +78,6 @@ extern "C" { Ping_t *ping = ping_head; while (ping != nullptr) { if (ip_addr_cmp(&ping->ip, ip)) { - // if (ping->ip == ip) { return ping; } ping = ping->next; @@ -119,6 +121,31 @@ extern "C" { iecho->chksum = inet_chksum(iecho, len); } + +#ifdef USE_IPV6 + // Prepare a echo ICMP6 request + // + void t_ping_prepare_echo6(struct icmp6_echo_hdr *iecho6, uint16_t len, Ping_t *ping) { + // TODO + size_t data_len = len - sizeof(struct icmp6_echo_hdr); + + iecho6->type = ICMP6_TYPE_EREQ; + iecho6->code = 0; + iecho6->chksum = 0; + iecho6->id = Ping_ID; + ping->seq_num++; + if (ping->seq_num == 0x7fff) { ping->seq_num = 0; } + + iecho6->seqno = htons(ping->seq_num); + + /* fill the additional data buffer with some data */ + for (uint32_t i = 0; i < data_len; i++) { + ((char*)iecho6)[sizeof(struct icmp6_echo_hdr) + i] = (char)i; + } + // checksum is calculated by lwip + } +#endif // USE_IPV6 + // // send the ICMP packet // @@ -130,11 +157,31 @@ extern "C" { p = pbuf_alloc(PBUF_IP, ping_size, PBUF_RAM); if (!p) { return; } if ((p->len == p->tot_len) && (p->next == nullptr)) { - struct icmp_echo_hdr *iecho; - iecho = (struct icmp_echo_hdr *) p->payload; - t_ping_prepare_echo(iecho, ping_size, ping); - raw_sendto(raw, p, &ping->ip); +#ifdef USE_IPV6 + // different format for IPv4 and IPv6 packets + if (IP_IS_V6_VAL(ping->ip)) { + // IPv6 + struct icmp6_echo_hdr *iecho6; + iecho6 = (struct icmp6_echo_hdr *) p->payload; + t_ping_prepare_echo6(iecho6, ping_size, ping); + // set parameters for checksum handling + t_ping6_pcb->chksum_reqd = 1; + t_ping6_pcb->chksum_offset = offsetof(icmp6_echo_hdr, chksum); + + // AddLog(LOG_LEVEL_DEBUG, "PNG: sending ICMP6(%i-%i)=%*_H", p->len, ping_size, p->len, p->payload); + raw_sendto(t_ping6_pcb, p, &ping->ip); + // AddLog(LOG_LEVEL_DEBUG, "PNG: sending ICMP6(%i-%i)=%*_H", p->len, ping_size, p->len, p->payload); + } else +#endif // USE_IPV6 + { + // IPv4 + struct icmp_echo_hdr *iecho; + iecho = (struct icmp_echo_hdr *) p->payload; + t_ping_prepare_echo(iecho, ping_size, ping); + raw_sendto(t_ping_pcb, p, &ping->ip); + // AddLog(LOG_LEVEL_DEBUG, "PNG: sending ICMP4(%i-%i)=%*_H", p->len, ping_size, p->len, p->payload); + } } pbuf_free(p); } @@ -148,7 +195,7 @@ extern "C" { if (ping->to_send_count > 0) { ping->to_send_count--; // have we sent all packets? - t_ping_send(t_ping_pcb, ping); + t_ping_send(t_ping_pcb, ping); // ICMP can also send ICMP6 sys_timeout(Ping_timeout_ms, t_ping_timeout, ping); sys_timeout(Ping_coarse, t_ping_coarse_tmr, ping); @@ -165,17 +212,31 @@ extern "C" { // Reveived packet // static uint8_t ICACHE_FLASH_ATTR t_ping_recv(void *arg, struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *addr) { + // AddLog(LOG_LEVEL_DEBUG, "PNG: from %s pub(%i)=%*_H", IPAddress(*addr).toString().c_str(), p->len, p->len, p->payload); Ping_t *ping = t_ping_find(addr); if (nullptr == ping) { // unknown source address return 0; // don't eat the packet and ignore it } - if (pbuf_header( p, -PBUF_TRANSPORT_HLEN)==0) { + size_t pbuf_header_len = PBUF_TRANSPORT_HLEN; + bool ipv6 = false; +#ifdef USE_IPV6 + if (pcb == t_ping6_pcb) { + pbuf_header_len = PBUF_IP_HLEN; + ipv6 = true; + } +#endif // USE_IPV6 + if (pbuf_header(p, -pbuf_header_len)==0) { + // AddLog(LOG_LEVEL_DEBUG, "PNG: received(%i)=%*_H", p->len, p->len, p->payload); struct icmp_echo_hdr *iecho; iecho = (struct icmp_echo_hdr *)p->payload; - if ((iecho->id == Ping_ID) && (iecho->seqno == htons(ping->seq_num)) && iecho->type == ICMP_ER) { + uint8_t icmp_resp_type = ICMP_ER; +#ifdef USE_IPV6 + icmp_resp_type = (ipv6 ? ICMP6_TYPE_EREP : ICMP_ER); +#endif // USE_IPV6 + if ((iecho->id == Ping_ID) && (iecho->seqno == htons(ping->seq_num)) && iecho->type == icmp_resp_type) { if (iecho->seqno != ping->seqno){ // debounce already received packet /* do some ping result processing */ @@ -212,8 +273,16 @@ extern "C" { t_ping_pcb = raw_new(IP_PROTO_ICMP); raw_recv(t_ping_pcb, t_ping_recv, nullptr); // we cannot register data structure here as we can only register one - raw_bind(t_ping_pcb, IP_ADDR_ANY); + raw_bind(t_ping_pcb, IP4_ADDR_ANY); } +#ifdef USE_IPV6 + if (nullptr == t_ping6_pcb) { + t_ping6_pcb = raw_new(IP6_NEXTH_ICMP6); + + raw_recv(t_ping6_pcb, t_ping_recv, nullptr); // we cannot register data structure here as we can only register one + raw_bind(t_ping6_pcb, IP6_ADDR_ANY); + } +#endif // USE_IPV6 } // we have finsihed a ping series, deallocated if no more ongoing @@ -221,6 +290,10 @@ extern "C" { if (nullptr == ping_head) { // deregister only if no ping is flying raw_remove(t_ping_pcb); t_ping_pcb = nullptr; +#ifdef USE_IPV6 + raw_remove(t_ping6_pcb); + t_ping6_pcb = nullptr; +#endif // USE_IPV6 } } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_82_esp32_ethernet.ino b/tasmota/tasmota_xdrv_driver/xdrv_82_esp32_ethernet.ino index 406d3f94f..c7f193536 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_82_esp32_ethernet.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_82_esp32_ethernet.ino @@ -116,6 +116,7 @@ void EthernetEvent(arduino_event_t *event) { } TasmotaGlobal.rules_flag.eth_connected = 1; TasmotaGlobal.global_state.eth_down = 0; + WiFi.saveDNS(); // internal calls to reconnect can zero the DNS servers, save DNS for future use break; case ARDUINO_EVENT_ETH_DISCONNECTED: From 8cedee3a625f7a3417a220d465617ffdeb615e76 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Sat, 17 Dec 2022 15:16:35 +0100 Subject: [PATCH 012/262] Revert "CI: Delay start of Linux builds (#17316)" (#17423) This reverts commit eee86f01a7b5288da45c095fd5f0d014043a7bb6. --- .github/workflows/build_all_the_things.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/build_all_the_things.yml b/.github/workflows/build_all_the_things.yml index a91217bac..15b07ba1b 100644 --- a/.github/workflows/build_all_the_things.yml +++ b/.github/workflows/build_all_the_things.yml @@ -113,10 +113,6 @@ jobs: - tasmota32s3-safeboot - tasmota32s3cdc-safeboot steps: - - name: Sleep a while, try to start MacOS / Windows CI env first - uses: jakejarvis/wait-action@master - with: - time: '1m' - uses: actions/checkout@v3 - name: Set up Python uses: actions/setup-python@v4 From 176e886e815f2b0c76c30c8415975d7e6986d4c2 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Sat, 17 Dec 2022 16:24:44 +0100 Subject: [PATCH 013/262] Tasmota ESP32 core 2.0.5.4 (#17422) * core 2.0.5.4 * enable IPv6 for all ESP32x builds --- platformio_tasmota32.ini | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/platformio_tasmota32.ini b/platformio_tasmota32.ini index 38c0209d4..f14fe7d74 100644 --- a/platformio_tasmota32.ini +++ b/platformio_tasmota32.ini @@ -10,6 +10,8 @@ build_unflags = ${esp_defaults.build_unflags} -fno-lto -Wpointer-arith build_flags = ${esp_defaults.build_flags} + ; comment next line to disable IPv6 support + -DUSE_IPV6 -Wno-switch-unreachable -Wno-stringop-overflow -fno-exceptions @@ -40,7 +42,7 @@ extra_scripts = pre:pio-tools/add_c_flags.py ${esp_defaults.extra_scripts} [core32] -platform = https://github.com/tasmota/platform-espressif32/releases/download/v.2.0.5/platform-espressif32-v.2.0.5.zip +platform = https://github.com/tasmota/platform-espressif32/releases/download/2022.12.0/platform-espressif32.zip platform_packages = build_unflags = ${esp32_defaults.build_unflags} build_flags = ${esp32_defaults.build_flags} From 509ce597a0215039ad103739a231f97ad69fb5b9 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Sat, 17 Dec 2022 16:28:16 +0100 Subject: [PATCH 014/262] ESP32 Core 2.0.5.4 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a709ac006..e4981bc39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ All notable changes to this project will be documented in this file. ### Breaking Changed ### Changed +- ESP32 Framework (Core) from v2.0.5.3 to v2.0.5.4 (IPv6 support) ### Fixed From 1b3eedd63568af8cf802e0aaea1ff55c162e2c6c Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Sat, 17 Dec 2022 19:28:25 +0100 Subject: [PATCH 015/262] reduce memory footprint for MI32 builds (#17426) by disabling (default) Ethernet support --- tasmota/include/tasmota_configurations_ESP32.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tasmota/include/tasmota_configurations_ESP32.h b/tasmota/include/tasmota_configurations_ESP32.h index 0219dc4bc..51cbfba49 100644 --- a/tasmota/include/tasmota_configurations_ESP32.h +++ b/tasmota/include/tasmota_configurations_ESP32.h @@ -260,13 +260,12 @@ #undef USE_MI_HOMEKIT #endif // disable USE_MI_HOMEKIT #else + #define USE_ETHERNET // Add support for ethernet (+20k code) #define USE_BLE_ESP32 // Enable full BLE driver #define USE_EQ3_ESP32 #define USE_MI_ESP32 // (ESP32 only) Add support for ESP32 as a BLE-bridge (+9k2 mem, +292k flash) #endif // enable USE_MI_HOMEKIT -#define USE_ETHERNET // Add support for ethernet (+20k code - #endif // FIRMWARE_BLUETOOTH /*********************************************************************************************\ From c908dc289e748f5e4975c6c9b446ffeb3ac481d4 Mon Sep 17 00:00:00 2001 From: blakadder Date: Sat, 17 Dec 2022 21:52:12 +0100 Subject: [PATCH 016/262] remove manual upload port and switch to autodiscovery in platformio (#17427) --- platformio.ini | 3 +-- platformio_override_sample.ini | 12 ++++++------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/platformio.ini b/platformio.ini index 3a77eb1a1..0f9034f8d 100644 --- a/platformio.ini +++ b/platformio.ini @@ -35,10 +35,9 @@ custom_unpack_dir = unpacked_littlefs build_unflags = ${core.build_unflags} build_flags = ${core.build_flags} monitor_speed = 115200 -monitor_port = COM5 ; *** Upload Serial reset method for Wemos and NodeMCU upload_resetmethod = nodemcu -upload_port = COM5 +upload_port = /dev/cu.SLAB_USBtoUART extra_scripts = ${esp_defaults.extra_scripts} lib_ldf_mode = chain lib_compat_mode = strict diff --git a/platformio_override_sample.ini b/platformio_override_sample.ini index 3dcff4fae..0c5af9cb3 100644 --- a/platformio_override_sample.ini +++ b/platformio_override_sample.ini @@ -70,9 +70,9 @@ board = ${common.board} ;board = esp8266_4M2M ;board_build.f_cpu = 160000000L ;board_build.f_flash = 40000000L -;monitor_speed = 115200 -; *** Serial port used for erasing/flashing the ESP82xx -;upload_port = COM5 +; *** Define serial port used for erasing/flashing/terminal +upload_port = +monitor_port = ${env.upload_port} extra_scripts = ${esp_defaults.extra_scripts} ; pio-tools/obj-dump.py lib_ignore = @@ -111,12 +111,12 @@ lib_extra_dirs = ${library.lib_extra_dirs} ;board_upload.maximum_size = 8388608 ;board_upload.arduino.flash_extra_images = ;board_build.partitions = partitions/esp32_partition_app2944k_fs2M.csv -monitor_speed = 115200 ; *** Serial port used for erasing/flashing the ESP32 -;upload_port = ${common.upload_port} -upload_port = COM4 +upload_port = ;upload_speed = 115200 +monitor_port = ${env.upload_port} upload_resetmethod = ${common.upload_resetmethod} +monitor_speed = 115200 extra_scripts = ${esp32_defaults.extra_scripts} ; pio-tools/obj-dump.py lib_ignore = From 5048777e06025c41cbcdc4846e7aa41d7470de4e Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Sat, 17 Dec 2022 22:41:21 +0100 Subject: [PATCH 017/262] Fix IPV6 compilation on ESP8266 (#17429) --- tasmota/my_user_config.h | 5 ++--- tasmota/tasmota_support/support_wifi.ino | 4 +++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index 0b879687f..6ca0fa850 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -407,9 +407,8 @@ // -- IPv6 support ------------------------------- // #define USE_IPV6 // Enable IPv6 support (if the underlying esp-idf is also configured to support it) - // Code size increase: - // ESP8266: tbd - // ESP32: tbd + // Code size increase: ESP8266: +34.5kb + // Enabled by default on ESP32 and variants // -- ESP-NOW ------------------------------------- //#define USE_TASMESH // Enable Tasmota Mesh using ESP-NOW (+11k code) diff --git a/tasmota/tasmota_support/support_wifi.ino b/tasmota/tasmota_support/support_wifi.ino index 4d8867573..d03b55699 100644 --- a/tasmota/tasmota_support/support_wifi.ino +++ b/tasmota/tasmota_support/support_wifi.ino @@ -922,7 +922,9 @@ bool WifiDNSGetIPv6Priority(void) { // any change of state requires a dns cache clear if (had_v6prio != v6prio) { - dns_clear_cache(); +#ifdef ESP32 + dns_clear_cache(); // this function doesn't exist in LWIP used by ESP8266 +#endif had_v6prio = v6prio; } From 30ace5a3f39fa2a463b29eab329fd8de55a92bbb Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Sat, 17 Dec 2022 23:38:57 +0100 Subject: [PATCH 018/262] Berry support for `crypto.SHA256` (#17430) --- CHANGELOG.md | 1 + .../berry_tasmota/src/be_crypto_lib.c | 14 ++++ tasmota/my_user_config.h | 1 + .../xdrv_52_3_berry_crypto.ino | 77 +++++++++++++++++++ 4 files changed, 93 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e4981bc39..b7736a4eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file. ## [12.3.1.1] 20221216 ### Added - Support for IPv6 DNS records (AAAA) and IPv6 ``Ping`` for ESP32 and ESP8266 +- Berry support for ``crypto.SHA256`` ### Breaking Changed diff --git a/lib/libesp32/berry_tasmota/src/be_crypto_lib.c b/lib/libesp32/berry_tasmota/src/be_crypto_lib.c index 5e6818a00..3889e750c 100644 --- a/lib/libesp32/berry_tasmota/src/be_crypto_lib.c +++ b/lib/libesp32/berry_tasmota/src/be_crypto_lib.c @@ -15,8 +15,13 @@ extern int m_aes_gcm_tag(bvm *vm); extern int m_ec_c25519_pubkey(bvm *vm); extern int m_ec_c25519_sharedkey(bvm *vm); +extern int m_hash_sha256_init(bvm *vm); +extern int m_hash_sha256_update(bvm *vm); +extern int m_hash_sha256_out(bvm *vm); + #include "be_fixed_be_class_aes_gcm.h" #include "be_fixed_be_class_ec_c25519.h" +#include "be_fixed_be_class_sha256.h" #include "be_fixed_crypto.h" /* @const_object_info_begin @@ -36,9 +41,18 @@ class be_class_ec_c25519 (scope: global, name: EC_C25519) { shared_key, func(m_ec_c25519_sharedkey) } +class be_class_sha256 (scope: global, name: SHA256) { + .p, var + + init, func(m_hash_sha256_init) + update, func(m_hash_sha256_update) + out, func(m_hash_sha256_out) +} + module crypto (scope: global) { AES_GCM, class(be_class_aes_gcm) EC_C25519, class(be_class_ec_c25519) + SHA256, class(be_class_sha256) } @const_object_info_end */ diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index 6ca0fa850..f00cc476a 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -1107,6 +1107,7 @@ // Berry crypto extensions below: #define USE_BERRY_CRYPTO_AES_GCM // enable AES GCM 256 bits // #define USE_BERRY_CRYPTO_EC_C25519 // enable Elliptic Curve C C25519 + #define USE_BERRY_CRYPTO_SHA256 // enable SHA256 hash function #define USE_CSE7761 // Add support for CSE7761 Energy monitor as used in Sonoff Dual R3 // -- LVGL Graphics Library --------------------------------- diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino index 2c89fb30a..83094ff5d 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino @@ -158,6 +158,83 @@ extern "C" { #endif // USE_BERRY_CRYPTO_AES_GCM } } +/*********************************************************************************************\ + * SHA256 class + * +\*********************************************************************************************/ +extern "C" { + + // `SHA256.init() -> nil` + int32_t m_hash_sha256_init(struct bvm *vm); + int32_t m_hash_sha256_init(struct bvm *vm) { +#ifdef USE_BERRY_CRYPTO_SHA256 + // Initialize a SHA256 context + br_sha256_context * ctx = (br_sha256_context *) be_os_malloc(sizeof(br_sha256_context)); + if (!ctx) { + be_throw(vm, BE_MALLOC_FAIL); + } + br_sha256_init(ctx); + + be_newcomobj(vm, ctx, &be_commonobj_destroy_generic); + be_setmember(vm, 1, ".p"); + be_return_nil(vm); +#else // USE_BERRY_CRYPTO_SHA256 + be_raise(vm, "Not implemented", nullptr); +#endif // USE_BERRY_CRYPTO_SHA256 + } + + // `.update(content:bytes()) -> nil` + // + // Add raw bytes to the hash calculation + int32_t m_hash_sha256_update(struct bvm *vm); + int32_t m_hash_sha256_update(struct bvm *vm) { +#ifdef USE_BERRY_CRYPTO_SHA256 + int32_t argc = be_top(vm); // Get the number of arguments + if (argc >= 2 && be_isinstance(vm, 2)) { + do { + be_getglobal(vm, "bytes"); /* get the bytes class */ /* TODO eventually replace with be_getbuiltin */ + if (!be_isderived(vm, 2)) break; + size_t length = 0; + const void * bytes = be_tobytes(vm, 2, &length); + if (!bytes) break; + + be_getmember(vm, 1, ".p"); + br_sha256_context * ctx; + ctx = (br_sha256_context *) be_tocomptr(vm, -1); + if (!ctx) break; + + if (length > 0) { + br_sha256_update(ctx, bytes, length); + } + be_return_nil(vm); + // success + } while (0); + } + be_raise(vm, "value_error", NULL); +#else // USE_BERRY_CRYPTO_SHA256 + be_raise(vm, "Not implemented", nullptr); +#endif // USE_BERRY_CRYPTO_SHA256 + } + + // `.finish() -> bytes()` + // + // Add raw bytes to the MD5 calculation + int32_t m_hash_sha256_out(struct bvm *vm); + int32_t m_hash_sha256_out(struct bvm *vm) { +#ifdef USE_BERRY_CRYPTO_SHA256 + be_getmember(vm, 1, ".p"); + br_sha256_context * ctx; + ctx = (br_sha256_context *) be_tocomptr(vm, -1); + + uint8_t output[32]; + br_sha256_out(ctx, output); + be_pushbytes(vm, output, sizeof(output)); + be_return(vm); +#else // USE_BERRY_CRYPTO_SHA256 + be_raise(vm, "Not implemented", nullptr); +#endif // USE_BERRY_CRYPTO_SHA256 + } +} /*********************************************************************************************\ * EC C25519 class From 93ee524de1cce28ab50e3d4a877bec3eb1ababa2 Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Sat, 17 Dec 2022 23:40:41 +0100 Subject: [PATCH 019/262] Berry support for `crypto.SHA256` (#17430) From a6602249a378867e34a85927929de04fd4301d69 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 18 Dec 2022 14:05:31 +0100 Subject: [PATCH 020/262] Update changelogs --- CHANGELOG.md | 4 ++-- RELEASENOTES.md | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b7736a4eb..e13370fe6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,8 @@ All notable changes to this project will be documented in this file. ## [12.3.1.1] 20221216 ### Added -- Support for IPv6 DNS records (AAAA) and IPv6 ``Ping`` for ESP32 and ESP8266 -- Berry support for ``crypto.SHA256`` +- Support for IPv6 DNS records (AAAA) and IPv6 ``Ping`` for ESP32 and ESP8266 (#17417) +- Berry support for ``crypto.SHA256`` (#17430) ### Breaking Changed diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 3fc43908f..3d628b985 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -77,7 +77,7 @@ Historical binaries can be downloaded from The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmota.com/tasmota/release/tasmota.bin.gz`` ### ESP32, ESP32-C3, ESP32-S2 and ESP32-S3 based -The following binary downloads have been compiled with ESP32/Arduino library core version **2.0.5.3**. +The following binary downloads have been compiled with ESP32/Arduino library core version **2.0.5.4**. - **tasmota32.bin** = The Tasmota version with most drivers including additional sensors and KNX for 4M+ flash. **RECOMMENDED RELEASE BINARY** - **tasmota32xy.bin** = The Tasmota version with most drivers including additional sensors and KNX for ESP32-C3/S2/S3 and 4M+ flash. @@ -109,10 +109,13 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm ## Changelog v12.3.1.1 ### Added +- Support for IPv6 DNS records (AAAA) and IPv6 ``Ping`` for ESP32 and ESP8266 [#17417](https://github.com/arendst/Tasmota/issues/17417) +- Berry support for ``crypto.SHA256`` [#17430](https://github.com/arendst/Tasmota/issues/17430) ### Breaking Changed ### Changed +- ESP32 Framework (Core) from v2.0.5.3 to v2.0.5.4 (IPv6 support) - TuyaMcu rewrite by btsimonh [#17051](https://github.com/arendst/Tasmota/issues/17051) ### Fixed From 1cdd5c3f0848a845c689bb17382c64d4cc799f22 Mon Sep 17 00:00:00 2001 From: gemu Date: Sun, 18 Dec 2022 14:06:04 +0100 Subject: [PATCH 021/262] Udisplay support for rgb displays (#17414) * add gt911 * add rgb display mode * add gt911 * add gt911 * add gt911 * add sunton descriptor * fix divide by zero crash with sunton --- lib/lib_display/GT911/GT911.cpp | 290 ++++++++++++++ lib/lib_display/GT911/GT911.h | 179 +++++++++ lib/lib_display/UDisplay/uDisplay.cpp | 362 +++++++++++++++++- lib/lib_display/UDisplay/uDisplay.h | 63 ++- tasmota/displaydesc/ST7262_rgb16_display.ini | 5 + tasmota/tasmota_support/support_esp.ino | 5 +- .../tasmota_xdrv_driver/xdrv_10_scripter.ino | 2 +- tasmota/tasmota_xdrv_driver/xdrv_55_touch.ino | 49 ++- .../xdsp_17_universal.ino | 69 +++- 9 files changed, 985 insertions(+), 39 deletions(-) create mode 100755 lib/lib_display/GT911/GT911.cpp create mode 100755 lib/lib_display/GT911/GT911.h create mode 100644 tasmota/displaydesc/ST7262_rgb16_display.ini diff --git a/lib/lib_display/GT911/GT911.cpp b/lib/lib_display/GT911/GT911.cpp new file mode 100755 index 000000000..37dbd72c0 --- /dev/null +++ b/lib/lib_display/GT911/GT911.cpp @@ -0,0 +1,290 @@ +#include +#include +#include "GT911.h" + +#undef log_d +#define log_d +#undef log_e +#define log_e + +#ifdef ESP8266 +#define ESP_OK 0 +#define ESP_FAIL -1 +#endif + +//#define log_d Serial.printf + +GT911::GT911() {} + +volatile uint8_t gt911_irq_trigger = 0; +void ICACHE_RAM_ATTR ___GT911IRQ___() +{ + noInterrupts(); + gt911_irq_trigger = 1; + interrupts(); +} + +int32_t GT911::begin(TwoWire *use_wire, int8_t pin_int, int8_t pin_res, uint16_t xs, uint16_t ys) +{ + log_d("GT911: Initialization"); + + if (pin_int >= 0) { + pinMode(pin_int, INPUT); // Startup sequence PIN part + } + if (pin_res >= 0) { + pinMode(pin_res, OUTPUT); // Startup sequence PIN part + digitalWrite(pin_res, 0); + delay(1); + digitalWrite(pin_res, 1); + } + delay(100); + wire = use_wire; + + wire->beginTransmission(0x14); + if (wire->endTransmission()) + { + wire->beginTransmission(0x5D); + if (wire->endTransmission()) + { + log_e("Touch screen IIC connection error"); + return ESP_FAIL; + } + _iic_addr = 0x5D; + } + + if (pin_int >= 0) { + attachInterrupt(pin_int, ___GT911IRQ___, FALLING); + } + + readBlockData(configBuf, GT911_CONFIG_START, GT911_CONFIG_SIZE); + + uint16_t curx = configBuf[GT911_X_OUTPUT_MAX_LOW - GT911_CONFIG_START] | (configBuf[GT911_X_OUTPUT_MAX_HIGH - GT911_CONFIG_START] << 8); + uint16_t cury = configBuf[GT911_Y_OUTPUT_MAX_LOW - GT911_CONFIG_START] | (configBuf[GT911_Y_OUTPUT_MAX_HIGH - GT911_CONFIG_START] << 8); + + if (curx != xs || cury != ys) { + setResolution(xs, ys); + } + + log_d("GT911: initialized"); + + return ESP_OK; +} + + +void GT911::write(uint16_t addr, uint8_t data) +{ + wire->beginTransmission(_iic_addr); + wire->write((uint8_t)(addr >> 8)); + wire->write((uint8_t)addr); + wire->write(data); + wire->endTransmission(true); +} + +void GT911::write(uint16_t addr, const uint8_t *data, uint16_t len) +{ + wire->beginTransmission(_iic_addr); + wire->write((uint8_t)(addr >> 8)); + wire->write((uint8_t)addr); + wire->write(data, len); + wire->endTransmission(true); +} + +uint8_t GT911::read(uint16_t addr) +{ + wire->flush(); + wire->beginTransmission(_iic_addr); + wire->write((uint8_t)(addr >> 8)); + wire->write((uint8_t)addr); + wire->endTransmission(false); + wire->requestFrom((uint8_t)_iic_addr, (uint8_t)1); + return wire->read(); +} + +void GT911::read(uint16_t addr, uint8_t *buf, uint16_t len) +{ + wire->flush(); + wire->beginTransmission(_iic_addr); + wire->write((uint8_t)(addr >> 8)); + wire->write((uint8_t)addr); + wire->endTransmission(false); + wire->requestFrom((int)_iic_addr, (int)len); + wire->readBytes(buf, len); +} + +void GT911::readBlockData(uint8_t *buf, uint16_t reg, uint8_t size) { + wire->beginTransmission(_iic_addr); + wire->write(highByte(reg)); + wire->write(lowByte(reg)); + wire->endTransmission(); + wire->requestFrom(_iic_addr, size); + for (uint8_t i = 0; i < size; i++) { + buf[i] = wire->read(); + } +} + + +void GT911::calculateChecksum() { + uint8_t checksum = 0; + for (uint8_t i = 0; i < GT911_CONFIG_SIZE - 1 ; i++) { + checksum += configBuf[i]; + } + checksum = (~checksum) + 1; + configBuf[GT911_CONFIG_CHKSUM - GT911_CONFIG_START] = checksum; +} + +void GT911::reflashConfig() { + calculateChecksum(); + write(GT911_X_OUTPUT_MAX_LOW, configBuf[GT911_X_OUTPUT_MAX_LOW - GT911_CONFIG_START]); + write(GT911_X_OUTPUT_MAX_HIGH, configBuf[GT911_X_OUTPUT_MAX_HIGH - GT911_CONFIG_START]); + write(GT911_Y_OUTPUT_MAX_LOW, configBuf[GT911_Y_OUTPUT_MAX_LOW - GT911_CONFIG_START]); + write(GT911_Y_OUTPUT_MAX_HIGH, configBuf[GT911_Y_OUTPUT_MAX_HIGH - GT911_CONFIG_START]); + write(GT911_CONFIG_CHKSUM, configBuf[GT911_CONFIG_CHKSUM - GT911_CONFIG_START]); + write(GT911_CONFIG_FRESH, 1); +} + +void GT911::setResolution(uint16_t _width, uint16_t _height) { + configBuf[GT911_X_OUTPUT_MAX_LOW - GT911_CONFIG_START] = lowByte(_width); + configBuf[GT911_X_OUTPUT_MAX_HIGH - GT911_CONFIG_START] = highByte(_width); + configBuf[GT911_Y_OUTPUT_MAX_LOW - GT911_CONFIG_START] = lowByte(_height); + configBuf[GT911_Y_OUTPUT_MAX_HIGH - GT911_CONFIG_START] = highByte(_height); + reflashConfig(); +} + +bool GT911::avaliable() +{ + if(gt911_irq_trigger == 1) + { + gt911_irq_trigger = 0; + return true; + } + return false; +} + +void GT911::flush(void) +{ + write(0x814E, 0x00); + gt911_irq_trigger = 0; + _num = 0; + _is_finger_up = 0; +} + +void GT911::update() +{ + uint8_t r814e = read(0x814E); + uint8_t num = r814e & 0x0F; + if(r814e & 0x80) + { + if(num != 0) + { + _is_finger_up = false; + _num = num; + uint8_t data[num * 8]; + read(0x8150, data, num * 8); + for(int j = 0; j < num; j++) + { + uint8_t *buf = data + j * 8; + + if(_rotate == ROTATE_0) + { + _fingers[j].x = (buf[3] << 8) | buf[2]; + _fingers[j].y = 540 - ((buf[1] << 8) | buf[0]); + } + else if(_rotate == ROTATE_180) + { + _fingers[j].x = 960 - ((buf[3] << 8) | buf[2]); + _fingers[j].y = (buf[1] << 8) | buf[0]; + } + else if(_rotate == ROTATE_270) + { + _fingers[j].x = 540 - ((buf[1] << 8) | buf[0]); + _fingers[j].y = 960 - ((buf[3] << 8) | buf[2]); + } + else + { + _fingers[j].x = (buf[1] << 8) | buf[0]; + _fingers[j].y = (buf[3] << 8) | buf[2]; + } + + _fingers[j].size = (buf[5] << 8) | buf[4]; + _fingers[j].id = buf[7]; + } + } + else + { + _is_finger_up = true; + } + write(0x814E, 0x00); + } + else + { + _is_finger_up = 1; + } +} + +bool GT911::isFingerUp(void) +{ + if(_is_finger_up == 1) + { + _is_finger_up = 0; + return true; + } + return false; +} + +void GT911::SetRotation(uint16_t rotate) +{ + if(rotate < 4) + { + this->_rotate = rotate; + } + else if(rotate < 90) + { + this->_rotate = ROTATE_0; + } + else if(rotate < 180) + { + this->_rotate = ROTATE_90; + } + else if(rotate < 270) + { + this->_rotate = ROTATE_180; + } + else + { + this->_rotate = ROTATE_270; + } +} + +tp_finger_t GT911::readFinger(uint8_t num) +{ + if(num > 2) + { + num = 1; + } + return this->_fingers[num]; +} + +uint16_t GT911::readFingerID(uint8_t num) +{ + return this->_fingers[num].id; +} + +uint16_t GT911::readFingerSize(uint8_t num) +{ + return this->_fingers[num].size; +} + +uint16_t GT911::readFingerX(uint8_t num) +{ + return this->_fingers[num].x; +} + +uint16_t GT911::readFingerY(uint8_t num) +{ + return this->_fingers[num].y; +} + +uint8_t GT911::getFingerNum(void) +{ + return _num; +} diff --git a/lib/lib_display/GT911/GT911.h b/lib/lib_display/GT911/GT911.h new file mode 100755 index 000000000..65da24cd7 --- /dev/null +++ b/lib/lib_display/GT911/GT911.h @@ -0,0 +1,179 @@ +#ifndef GT911_H +#define GT911_H + +#include +#include + + +// Real-time command (Write only) +#define GT911_COMMAND (uint16_t)0x8040 +#define GT911_ESD_CHECK (uint16_t)0x8041 +#define GT911_COMMAND_CHECK (uint16_t)0x8046 + +// Configuration information (R/W) +#define GT911_CONFIG_START (uint16_t)0x8047 +#define GT911_CONFIG_VERSION (uint16_t)0x8047 +#define GT911_X_OUTPUT_MAX_LOW (uint16_t)0x8048 +#define GT911_X_OUTPUT_MAX_HIGH (uint16_t)0x8049 +#define GT911_Y_OUTPUT_MAX_LOW (uint16_t)0x804A +#define GT911_Y_OUTPUT_MAX_HIGH (uint16_t)0x804B +#define GT911_TOUCH_NUMBER (uint16_t)0x804C +#define GT911_MODULE_SWITCH_1 (uint16_t)0x804D +#define GT911_MODULE_SWITCH_2 (uint16_t)0x804E +#define GT911_SHAKE_COUNT (uint16_t)0x804F +#define GT911_FILTER (uint16_t)0x8050 +#define GT911_LARGE_TOUCH (uint16_t)0x8051 +#define GT911_NOISE_REDUCTION (uint16_t)0x8052 +#define GT911_SCREEN_TOUCH_LEVEL (uint16_t)0x8053 +#define GT911_SCREEN_RELEASE_LEVEL (uint16_t)0x8054 +#define GT911_LOW_POWER_CONTROL (uint16_t)0x8055 +#define GT911_REFRESH_RATE (uint16_t)0x8056 +#define GT911_X_THRESHOLD (uint16_t)0x8057 +#define GT911_Y_THRESHOLD (uint16_t)0x8058 +#define GT911_X_SPEED_LIMIT (uint16_t)0x8059 //Reserve +#define GT911_Y_SPEED_LIMIT (uint16_t)0x805A //Reserve +#define GT911_SPACE_TOP_BOTTOM (uint16_t)0x805B +#define GT911_SPACE_LEFT_RIGHT (uint16_t)0x805C +#define GT911_MINI_FILTER (uint16_t)0x805D +#define GT911_STRETCH_R0 (uint16_t)0x805E +#define GT911_STRETCH_R1 (uint16_t)0x805F +#define GT911_STRETCH_R2 (uint16_t)0x8060 +#define GT911_STRETCH_RM (uint16_t)0x8061 +#define GT911_DRV_GROUPA_NUM (uint16_t)0x8062 +#define GT911_DRV_GROUPB_NUM (uint16_t)0x8063 +#define GT911_SENSOR_NUM (uint16_t)0x8064 +#define GT911_FREQ_A_FACTOR (uint16_t)0x8065 +#define GT911_FREQ_B_FACTOR (uint16_t)0x8066 +#define GT911_PANEL_BIT_FREQ_L (uint16_t)0x8067 +#define GT911_PANEL_BIT_FREQ_H (uint16_t)0x8068 +#define GT911_PANEL_SENSOR_TIME_L (uint16_t)0x8069 //Reserve +#define GT911_PANEL_SENSOR_TIME_H (uint16_t)0x806A +#define GT911_PANEL_TX_GAIN (uint16_t)0x806B +#define GT911_PANEL_RX_GAIN (uint16_t)0x806C +#define GT911_PANEL_DUMP_SHIFT (uint16_t)0x806D +#define GT911_DRV_FRAME_CONTROL (uint16_t)0x806E +#define GT911_CHARGING_LEVEL_UP (uint16_t)0x806F +#define GT911_MODULE_SWITCH3 (uint16_t)0x8070 +#define GT911_GESTURE_DIS (uint16_t)0X8071 +#define GT911_GESTURE_LONG_PRESS_TIME (uint16_t)0x8072 +#define GT911_X_Y_SLOPE_ADJUST (uint16_t)0X8073 +#define GT911_GESTURE_CONTROL (uint16_t)0X8074 +#define GT911_GESTURE_SWITCH1 (uint16_t)0X8075 +#define GT911_GESTURE_SWITCH2 (uint16_t)0X8076 +#define GT911_GESTURE_REFRESH_RATE (uint16_t)0x8077 +#define GT911_GESTURE_TOUCH_LEVEL (uint16_t)0x8078 +#define GT911_NEWGREENWAKEUPLEVEL (uint16_t)0x8079 +#define GT911_FREQ_HOPPING_START (uint16_t)0x807A +#define GT911_FREQ_HOPPING_END (uint16_t)0X807B +#define GT911_NOISE_DETECT_TIMES (uint16_t)0x807C +#define GT911_HOPPING_FLAG (uint16_t)0X807D +#define GT911_HOPPING_THRESHOLD (uint16_t)0X807E +#define GT911_NOISE_THRESHOLD (uint16_t)0X807F //Reserve +#define GT911_NOISE_MIN_THRESHOLD (uint16_t)0X8080 +#define GT911_HOPPING_SENSOR_GROUP (uint16_t)0X8082 +#define GT911_HOPPING_SEG1_NORMALIZE (uint16_t)0X8083 +#define GT911_HOPPING_SEG1_FACTOR (uint16_t)0X8084 +#define GT911_MAIN_CLOCK_AJDUST (uint16_t)0X8085 +#define GT911_HOPPING_SEG2_NORMALIZE (uint16_t)0X8086 +#define GT911_HOPPING_SEG2_FACTOR (uint16_t)0X8087 +#define GT911_HOPPING_SEG3_NORMALIZE (uint16_t)0X8089 +#define GT911_HOPPING_SEG3_FACTOR (uint16_t)0X808A +#define GT911_HOPPING_SEG4_NORMALIZE (uint16_t)0X808C +#define GT911_HOPPING_SEG4_FACTOR (uint16_t)0X808D +#define GT911_HOPPING_SEG5_NORMALIZE (uint16_t)0X808F +#define GT911_HOPPING_SEG5_FACTOR (uint16_t)0X8090 +#define GT911_HOPPING_SEG6_NORMALIZE (uint16_t)0X8092 +#define GT911_KEY_1 (uint16_t)0X8093 +#define GT911_KEY_2 (uint16_t)0X8094 +#define GT911_KEY_3 (uint16_t)0X8095 +#define GT911_KEY_4 (uint16_t)0X8096 +#define GT911_KEY_AREA (uint16_t)0X8097 +#define GT911_KEY_TOUCH_LEVEL (uint16_t)0X8098 +#define GT911_KEY_LEAVE_LEVEL (uint16_t)0X8099 +#define GT911_KEY_SENS_1_2 (uint16_t)0X809A +#define GT911_KEY_SENS_3_4 (uint16_t)0X809B +#define GT911_KEY_RESTRAIN (uint16_t)0X809C +#define GT911_KEY_RESTRAIN_TIME (uint16_t)0X809D +#define GT911_GESTURE_LARGE_TOUCH (uint16_t)0X809E +#define GT911_HOTKNOT_NOISE_MAP (uint16_t)0X80A1 +#define GT911_LINK_THRESHOLD (uint16_t)0X80A2 +#define GT911_PXY_THRESHOLD (uint16_t)0X80A3 +#define GT911_GHOT_DUMP_SHIFT (uint16_t)0X80A4 +#define GT911_GHOT_RX_GAIN (uint16_t)0X80A5 +#define GT911_FREQ_GAIN0 (uint16_t)0X80A6 +#define GT911_FREQ_GAIN1 (uint16_t)0X80A7 +#define GT911_FREQ_GAIN2 (uint16_t)0X80A8 +#define GT911_FREQ_GAIN3 (uint16_t)0X80A9 +#define GT911_COMBINE_DIS (uint16_t)0X80B3 +#define GT911_SPLIT_SET (uint16_t)0X80B4 +#define GT911_SENSOR_CH0 (uint16_t)0X80B7 +#define GT911_DRIVER_CH0 (uint16_t)0X80D5 +#define GT911_CONFIG_CHKSUM (uint16_t)0X80FF +#define GT911_CONFIG_FRESH (uint16_t)0X8100 +#define GT911_CONFIG_SIZE (uint16_t)0xFF-0x46 +// Coordinate information +#define GT911_PRODUCT_ID (uint16_t)0X8140 +#define GT911_FIRMWARE_VERSION (uint16_t)0X8140 +#define GT911_RESOLUTION (uint16_t)0X8140 +#define GT911_VENDOR_ID (uint16_t)0X8140 +#define GT911_IMFORMATION (uint16_t)0X8140 +#define GT911_POINT_INFO (uint16_t)0X814E +#define GT911_POINT_1 (uint16_t)0X814F +#define GT911_POINT_2 (uint16_t)0X8157 +#define GT911_POINT_3 (uint16_t)0X815F +#define GT911_POINT_4 (uint16_t)0X8167 +#define GT911_POINT_5 (uint16_t)0X816F +#define GT911_POINTS_REG {GT911_POINT_1, GT911_POINT_2, GT911_POINT_3, GT911_POINT_4, GT911_POINT_5} + +typedef struct +{ + uint16_t x; + uint16_t y; + uint16_t id; + uint16_t size; +}tp_finger_t; + +class GT911 +{ +public: + static const uint8_t ROTATE_0 = 0; + static const uint8_t ROTATE_90 = 1; + static const uint8_t ROTATE_180 = 2; + static const uint8_t ROTATE_270 = 3; + +public: + GT911(); + int32_t begin(TwoWire *use_wire, int8_t pin_int, int8_t pin_res, uint16_t xs, uint16_t ys); + bool avaliable(); + void update(); + void SetRotation(uint16_t rotate); + tp_finger_t readFinger(uint8_t num); + uint16_t readFingerX(uint8_t num); + uint16_t readFingerY(uint8_t num); + uint16_t readFingerID(uint8_t num); + uint16_t readFingerSize(uint8_t num); + uint8_t getFingerNum(void); + bool isFingerUp(void); + void flush(void); + +private: + void write(uint16_t addr, uint8_t data); + void write(uint16_t addr, const uint8_t *data, uint16_t len); + uint8_t read(uint16_t addr); + void read(uint16_t addr, uint8_t *buf, uint16_t len); + uint8_t calcChecksum(const uint8_t *buf, uint8_t len); + void reflashConfig(); + void calculateChecksum(); + void setResolution(uint16_t _width, uint16_t _height); + void readBlockData(uint8_t *buf, uint16_t reg, uint8_t size); + + bool _is_finger_up = false; + uint8_t _num = 0; + uint8_t _rotate = ROTATE_90; + tp_finger_t _fingers[2]; + uint8_t _iic_addr = 0x14; + TwoWire *wire; + uint8_t configBuf[GT911_CONFIG_SIZE]; +}; + +#endif diff --git a/lib/lib_display/UDisplay/uDisplay.cpp b/lib/lib_display/UDisplay/uDisplay.cpp index d3b55316e..d9e2b5310 100755 --- a/lib/lib_display/UDisplay/uDisplay.cpp +++ b/lib/lib_display/UDisplay/uDisplay.cpp @@ -24,8 +24,14 @@ #include "esp8266toEsp32.h" #endif + +extern int Cache_WriteBack_Addr(uint32_t addr, uint32_t size); + + //#define UDSP_DEBUG +#define renderer_swap(a, b) { int16_t t = a; a = b; b = t; } + const uint16_t udisp_colors[]={UDISP_BLACK,UDISP_WHITE,UDISP_RED,UDISP_GREEN,UDISP_BLUE,UDISP_CYAN,UDISP_MAGENTA,\ UDISP_YELLOW,UDISP_NAVY,UDISP_DARKGREEN,UDISP_DARKCYAN,UDISP_MAROON,UDISP_PURPLE,UDISP_OLIVE,\ UDISP_LIGHTGREY,UDISP_DARKGREY,UDISP_ORANGE,UDISP_GREENYELLOW,UDISP_PINK}; @@ -93,6 +99,10 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) { lut_num = 0; lvgl_param.data = 0; lvgl_param.fluslines = 40; + rot_t[0] = 0; + rot_t[1] = 1; + rot_t[2] = 2; + rot_t[3] = 3; for (uint32_t cnt = 0; cnt < 5; cnt++) { lut_cnt[cnt] = 0; @@ -199,6 +209,26 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) { } } spi_speed = next_val(&lp1); +#endif // USE_ESP32_S3 + section = 0; + } else if (!strncmp(ibuff, "RGB", 3)) { +#ifdef USE_ESP32_S3 + interface = _UDSP_RGB; + + de = next_val(&lp1); + vsync = next_val(&lp1); + hsync = next_val(&lp1); + pclk = next_val(&lp1); + bpanel = next_val(&lp1); + + for (uint32_t cnt = 0; cnt < 8; cnt ++) { + par_dbl[cnt] = next_val(&lp1); + } + + for (uint32_t cnt = 0; cnt < 8; cnt ++) { + par_dbh[cnt] = next_val(&lp1); + } + spi_speed = next_val(&lp1); #endif // USE_ESP32_S3 section = 0; } @@ -236,9 +266,23 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) { } } break; +#ifdef USE_ESP32_S3 + case 'V': + hsync_polarity = next_val(&lp1); + hsync_front_porch = next_val(&lp1); + hsync_pulse_width = next_val(&lp1); + hsync_back_porch = next_val(&lp1); + vsync_polarity = next_val(&lp1); + vsync_front_porch = next_val(&lp1); + vsync_pulse_width = next_val(&lp1); + vsync_back_porch = next_val(&lp1); + pclk_active_neg = next_val(&lp1); + break; +#endif // USE_ESP32_S3 case 'o': dsp_off = next_hex(&lp1); break; + case 'O': dsp_on = next_hex(&lp1); break; @@ -247,27 +291,35 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) { startline = next_hex(&lp1); break; case '0': - rot[0] = next_hex(&lp1); - x_addr_offs[0] = next_hex(&lp1); - y_addr_offs[0] = next_hex(&lp1); + if (interface != _UDSP_RGB) { + rot[0] = next_hex(&lp1); + x_addr_offs[0] = next_hex(&lp1); + y_addr_offs[0] = next_hex(&lp1); + } rot_t[0] = next_hex(&lp1); break; case '1': - rot[1] = next_hex(&lp1); - x_addr_offs[1] = next_hex(&lp1); - y_addr_offs[1] = next_hex(&lp1); + if (interface != _UDSP_RGB) { + rot[1] = next_hex(&lp1); + x_addr_offs[1] = next_hex(&lp1); + y_addr_offs[1] = next_hex(&lp1); + } rot_t[1] = next_hex(&lp1); break; case '2': - rot[2] = next_hex(&lp1); - x_addr_offs[2] = next_hex(&lp1); - y_addr_offs[2] = next_hex(&lp1); + if (interface != _UDSP_RGB) { + rot[2] = next_hex(&lp1); + x_addr_offs[2] = next_hex(&lp1); + y_addr_offs[2] = next_hex(&lp1); + } rot_t[2] = next_hex(&lp1); break; case '3': - rot[3] = next_hex(&lp1); - x_addr_offs[3] = next_hex(&lp1); - y_addr_offs[3] = next_hex(&lp1); + if (interface != _UDSP_RGB) { + rot[3] = next_hex(&lp1); + x_addr_offs[3] = next_hex(&lp1); + y_addr_offs[3] = next_hex(&lp1); + } rot_t[3] = next_hex(&lp1); break; case 'A': @@ -449,9 +501,39 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) { #endif // USE_ESP32_S3 } -#endif -} + if (interface == _UDSP_RGB) { +#ifdef USE_ESP32_S3 + Serial.printf("rgb de: %d\n", de); + Serial.printf("rgb vsync: %d\n", vsync); + Serial.printf("rgb hsync : %d\n", hsync); + Serial.printf("rgb pclk : %d\n", pclk); + Serial.printf("rgb bp : %d\n", bpanel); + + for (uint32_t cnt = 0; cnt < 8; cnt ++) { + Serial.printf("rgb d%d: %d\n", cnt, par_dbl[cnt]); + } + for (uint32_t cnt = 0; cnt < 8; cnt ++) { + Serial.printf("rgb d%d: %d\n", cnt + 8, par_dbh[cnt]); + } + + Serial.printf("rgb freq : %d\n", spi_speed); + + Serial.printf("rgb hsync_polarity: %d\n", hsync_polarity); + Serial.printf("rgb hsync_front_porch: %d\n", hsync_front_porch); + Serial.printf("rgb hsync_pulse_width : %d\n", hsync_pulse_width); + Serial.printf("rgb hsync_back_porch : %d\n", hsync_back_porch); + Serial.printf("rgb vsync_polarity : %d\n", vsync_polarity); + Serial.printf("rgb vsync_front_porch : %d\n", vsync_front_porch); + Serial.printf("rgb vsync_pulse_width : %d\n", vsync_pulse_width); + Serial.printf("rgb vsync_back_porch : %d\n", vsync_back_porch); + Serial.printf("rgb pclk_active_neg : %d\n", pclk_active_neg); + +#endif // USE_ESP32_S3 + } +#endif + +} Renderer *uDisplay::Init(void) { extern bool UsePSRAM(void); @@ -553,7 +635,6 @@ Renderer *uDisplay::Init(void) { spiSettings = SPISettings((uint32_t)spi_speed*1000000, MSBFIRST, SPI_MODE3); SPI_BEGIN_TRANSACTION - if (reset >= 0) { pinMode(reset, OUTPUT); digitalWrite(reset, HIGH); @@ -612,6 +693,69 @@ Renderer *uDisplay::Init(void) { } + if (interface == _UDSP_RGB) { +#ifdef USE_ESP32_S3 + + if (bpanel >= 0) { + analogWrite(bpanel, 32); + } + esp_lcd_rgb_panel_config_t *_panel_config = (esp_lcd_rgb_panel_config_t *)heap_caps_calloc(1, sizeof(esp_lcd_rgb_panel_config_t), MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL); + + _panel_config->clk_src = LCD_CLK_SRC_PLL160M; + + if (spi_speed > 14) { + spi_speed = 14; + } + _panel_config->timings.pclk_hz = spi_speed*1000000; + _panel_config->timings.h_res = gxs; + _panel_config->timings.v_res = gys; + + _panel_config->timings.hsync_pulse_width = hsync_pulse_width; + _panel_config->timings.hsync_back_porch = hsync_back_porch; + _panel_config->timings.hsync_front_porch = hsync_front_porch; + _panel_config->timings.vsync_pulse_width = vsync_pulse_width; + _panel_config->timings.vsync_back_porch = vsync_back_porch; + _panel_config->timings.vsync_front_porch = vsync_front_porch; + _panel_config->timings.flags.hsync_idle_low = (hsync_polarity == 0) ? 1 : 0; + _panel_config->timings.flags.vsync_idle_low = (vsync_polarity == 0) ? 1 : 0; + _panel_config->timings.flags.de_idle_high = 0; + _panel_config->timings.flags.pclk_active_neg = pclk_active_neg; + _panel_config->timings.flags.pclk_idle_high = 0; + + _panel_config->data_width = 16; // RGB565 in parallel mode, thus 16bit in width + _panel_config->sram_trans_align = 8; + _panel_config->psram_trans_align = 64; + _panel_config->hsync_gpio_num = hsync; + _panel_config->vsync_gpio_num = vsync; + _panel_config->de_gpio_num = de; + _panel_config->pclk_gpio_num = pclk; + + for (uint32_t cnt = 0; cnt < 8; cnt ++) { + _panel_config->data_gpio_nums[cnt] = par_dbh[cnt]; + } + for (uint32_t cnt = 0; cnt < 8; cnt ++) { + _panel_config->data_gpio_nums[cnt + 8] = par_dbl[cnt]; + } + _panel_config->disp_gpio_num = GPIO_NUM_NC; + + _panel_config->flags.disp_active_low = 0; + _panel_config->flags.relax_on_idle = 0; + _panel_config->flags.fb_in_psram = 1; // allocate frame buffer in PSRAM + + ESP_ERROR_CHECK(esp_lcd_new_rgb_panel(_panel_config, &_panel_handle)); + ESP_ERROR_CHECK(esp_lcd_panel_reset(_panel_handle)); + ESP_ERROR_CHECK(esp_lcd_panel_init(_panel_handle)); + + uint16_t color = random(0xffff); + ESP_ERROR_CHECK(_panel_handle->draw_bitmap(_panel_handle, 0, 0, 1, 1, &color)); + + _rgb_panel = __containerof(_panel_handle, esp_rgb_panel_t, base); + + rgb_fb = (uint16_t *)_rgb_panel->fb; + +#endif // USE_ESP32_S3 + } + if (interface == _UDSP_PAR8 || interface == _UDSP_PAR16) { #ifdef USE_ESP32_S3 @@ -760,10 +904,14 @@ Renderer *uDisplay::Init(void) { if (ep_mode == 1) Init_EPD(DISPLAY_INIT_PARTIAL); } +#ifdef UDSP_DEBUG + Serial.printf("Dsp Init 1 complete \n"); +#endif return this; } + void uDisplay::DisplayInit(int8_t p, int8_t size, int8_t rot, int8_t font) { if (p != DISPLAY_INIT_MODE && ep_mode) { if (p == DISPLAY_INIT_PARTIAL) { @@ -800,7 +948,7 @@ void uDisplay::DisplayInit(int8_t p, int8_t size, int8_t rot, int8_t font) { } #ifdef UDSP_DEBUG - Serial.printf("Dsp Init complete \n"); + Serial.printf("Dsp Init 2 complete \n"); #endif } } @@ -960,6 +1108,10 @@ void uDisplay::i2c_command(uint8_t val) { void uDisplay::Updateframe(void) { + if (interface == _UDSP_RGB) { + return; + } + if (ep_mode) { Updateframe_EPD(); return; @@ -1070,6 +1222,7 @@ void uDisplay::Updateframe(void) { void uDisplay::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) { + if (ep_mode) { drawFastVLine_EPD(x, y, h, color); return; @@ -1084,6 +1237,29 @@ void uDisplay::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) { if ((x >= _width) || (y >= _height)) return; if ((y + h - 1) >= _height) h = _height - y; + + if (interface == _UDSP_RGB) { + #ifdef USE_ESP32_S3 + if (cur_rot > 0) { + while (h--) { + drawPixel_RGB(x , y , color); + y++; + } + } else { + uint16_t *fb = rgb_fb; + fb += (int32_t)y * _width; + fb += x; + while (h--) { + *fb = color; + Cache_WriteBack_Addr((uint32_t)fb, 2); + fb+=_width; + y++; + } + } + #endif + return; + } + SPI_BEGIN_TRANSACTION SPI_CS_LOW @@ -1129,7 +1305,30 @@ void uDisplay::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) { // Rudimentary clipping if((x >= _width) || (y >= _height)) return; - if((x+w-1) >= _width) w = _width-x; + if((x + w - 1) >= _width) w = _width - x; + + + if (interface == _UDSP_RGB) { +#ifdef USE_ESP32_S3 + if (cur_rot > 0) { + while (w--) { + drawPixel_RGB(x , y , color); + x++; + } + } else { + uint16_t *fb = rgb_fb; + fb += (int32_t)y * _width; + fb += x; + while (w--) { + *fb = color; + Cache_WriteBack_Addr((uint32_t)fb, 2); + fb++; + x++; + } + } + #endif + return; + } SPI_BEGIN_TRANSACTION @@ -1174,6 +1373,13 @@ void uDisplay::fillScreen(uint16_t color) { // fill a rectangle void uDisplay::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) { + if (interface == _UDSP_RGB) { + for (uint32_t yp = y; yp < y + h; yp++) { + drawFastHLine(x, yp, w, color); + } + return; + } + if (ep_mode) { fillRect_EPD(x, y, w, h, color); @@ -1266,7 +1472,7 @@ void uDisplay::Splash(void) { void uDisplay::setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { - if (bpp != 16) { + if (bpp != 16 || interface == _UDSP_RGB) { // just save params or update frame if (!x0 && !y0 && !x1 && !y1) { if (!ep_mode) { @@ -1282,6 +1488,10 @@ void uDisplay::setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) return; } + if (interface == _UDSP_RGB) { + return; + } + if (!x0 && !y0 && !x1 && !y1) { SPI_CS_HIGH SPI_END_TRANSACTION @@ -1295,6 +1505,11 @@ void uDisplay::setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) #define udisp_swap(a, b) (((a) ^= (b)), ((b) ^= (a)), ((a) ^= (b))) ///< No-temp-var swap operation void uDisplay::setAddrWindow_int(uint16_t x, uint16_t y, uint16_t w, uint16_t h) { + + if (interface == _UDSP_RGB) { + return; + } + x += x_addr_offs[cur_rot]; y += y_addr_offs[cur_rot]; @@ -1388,9 +1603,43 @@ void uDisplay::pushColors(uint16_t *data, uint16_t len, boolean not_swapped) { not_swapped = !not_swapped; } - //Serial.printf("push %x - %d - %d - %d\n", (uint32_t)data, len, not_swapped,lvgl_param.data); + //Serial.printf("push %x - %d - %d - %d\n", (uint32_t)data, len, not_swapped, lvgl_param.data); if (not_swapped == false) { // called from LVGL bytes are swapped + if (interface == _UDSP_RGB) { +#ifdef USE_ESP32_S3 + if (cur_rot > 0) { + for (uint32_t y = seta_yp1; y < seta_yp2; y++) { + seta_yp1++; + for (uint32_t x = seta_xp1; x < seta_xp2; x++) { + uint16_t color = *data++; + color = color << 8 | color >> 8; + drawPixel_RGB(x, y, color); + len--; + if (!len) return; // failsafe - exist if len (pixel number) is exhausted + } + } + } else { + for (uint32_t y = seta_yp1; y < seta_yp2; y++) { + seta_yp1++; + uint16_t *fb = rgb_fb; + fb += (int32_t)y * _width; + fb += seta_xp1; + for (uint32_t x = seta_xp1; x < seta_xp2; x++) { + uint16_t color = *data++; + color = color << 8 | color >> 8; + *fb = color; + Cache_WriteBack_Addr((uint32_t)fb, 2); + fb++; + len--; + if (!len) return; // failsafe - exist if len (pixel number) is exhausted + } + } + } +#endif + return; + } + if (bpp != 16) { // lvgl_color_swap(data, len); -- no need to swap anymore, we have inverted the mask pushColorsMono(data, len, true); @@ -1464,6 +1713,36 @@ void uDisplay::pushColors(uint16_t *data, uint16_t len, boolean not_swapped) { } } else { // called from displaytext, no byte swap, currently no dma here + if (interface == _UDSP_RGB) { +#ifdef USE_ESP32_S3 + if (cur_rot > 0) { + for (uint32_t y = seta_yp1; y < seta_yp2; y++) { + seta_yp1++; + for (uint32_t x = seta_xp1; x < seta_xp2; x++) { + drawPixel_RGB(x, y, *data++); + len--; + if (!len) return; // failsafe - exist if len (pixel number) is exhausted + } + } + } else { + for (uint32_t y = seta_yp1; y < seta_yp2; y++) { + seta_yp1++; + uint16_t *fb = rgb_fb; + fb += (int32_t)y * _width; + fb += seta_xp1; + for (uint32_t x = seta_xp1; x < seta_xp2; x++) { + *fb = *data++; + Cache_WriteBack_Addr((uint32_t)fb, 2); + fb++; + len--; + if (!len) return; // failsafe - exist if len (pixel number) is exhausted + } + } + } +#endif + return; + } + if (bpp != 16) { pushColorsMono(data, len); return; @@ -1512,8 +1791,49 @@ void uDisplay::WriteColor(uint16_t color) { } } +#ifdef USE_ESP32_S3 +void uDisplay::drawPixel_RGB(int16_t x, int16_t y, uint16_t color) { +int16_t w = _width, h = _height; + + if ((x < 0) || (x >= w) || (y < 0) || (y >= h)) { + return; + } + + // check rotation, move pixel around if necessary + switch (cur_rot) { + case 1: + renderer_swap(w, h); + renderer_swap(x, y); + x = w - x - 1; + break; + case 2: + x = w - x - 1; + y = h - y - 1; + break; + case 3: + renderer_swap(w, h); + renderer_swap(x, y); + y = h - y - 1; + break; + } + + uint16_t *fb = rgb_fb; + fb += (int32_t)y * w; + fb += x; + *fb = color; + Cache_WriteBack_Addr((uint32_t)fb, 2); + +} +#endif // USE_ESP32_S3 + void uDisplay::drawPixel(int16_t x, int16_t y, uint16_t color) { +#ifdef USE_ESP32_S3 + if (interface == _UDSP_RGB) { + drawPixel_RGB(x, y, color); + return; + } +#endif if (ep_mode) { drawPixel_EPD(x, y, color); @@ -2172,7 +2492,7 @@ void uDisplay::SetFrameMemory( } #define IF_INVERT_COLOR 1 -#define renderer_swap(a, b) { int16_t t = a; a = b; b = t; } + /** * @brief: this draws a pixel by absolute coordinates. * this function won't be affected by the rotate parameter. @@ -2791,6 +3111,8 @@ uint32_t uDisplay::get_sr_touch(uint32_t _xp, uint32_t _xm, uint32_t _yp, uint32 } + + #if 0 void TFT_eSPI::startWrite(void) { diff --git a/lib/lib_display/UDisplay/uDisplay.h b/lib/lib_display/UDisplay/uDisplay.h index 8d79bc8bc..25a27bab7 100755 --- a/lib/lib_display/UDisplay/uDisplay.h +++ b/lib/lib_display/UDisplay/uDisplay.h @@ -31,12 +31,19 @@ static inline volatile uint32_t* get_gpio_lo_reg(int_fast8_t pin) { return (pin static inline bool gpio_in(int_fast8_t pin) { return ((pin & 32) ? GPIO.in1.data : GPIO.in) & (1 << (pin & 31)); } static inline void gpio_hi(int_fast8_t pin) { if (pin >= 0) *get_gpio_hi_reg(pin) = 1 << (pin & 31); } // ESP_LOGI("LGFX", "gpio_hi: %d", pin); } static inline void gpio_lo(int_fast8_t pin) { if (pin >= 0) *get_gpio_lo_reg(pin) = 1 << (pin & 31); } // ESP_LOGI("LGFX", "gpio_lo: %d", pin); } -#endif +#include "esp_lcd_panel_interface.h" +#include "esp_lcd_panel_rgb.h" +#include "esp_pm.h" +#include "esp_lcd_panel_ops.h" +#include +#include +#endif // USE_ESP32_S3 #define _UDSP_I2C 1 #define _UDSP_SPI 2 #define _UDSP_PAR8 3 #define _UDSP_PAR16 4 +#define _UDSP_RGB 5 #define UDISP1_WHITE 1 #define UDISP1_BLACK 0 @@ -115,6 +122,39 @@ struct esp_lcd_i80_bus_t { size_t resolution_hz; // LCD_CLK resolution, determined by selected clock source gdma_channel_handle_t dma_chan; // DMA channel handle }; + +// extract from esp-idf esp_lcd_rgb_panel.c +struct esp_rgb_panel_t +{ + esp_lcd_panel_t base; // Base class of generic lcd panel + int panel_id; // LCD panel ID + lcd_hal_context_t hal; // Hal layer object + size_t data_width; // Number of data lines (e.g. for RGB565, the data width is 16) + size_t sram_trans_align; // Alignment for framebuffer that allocated in SRAM + size_t psram_trans_align; // Alignment for framebuffer that allocated in PSRAM + int disp_gpio_num; // Display control GPIO, which is used to perform action like "disp_off" + intr_handle_t intr; // LCD peripheral interrupt handle + esp_pm_lock_handle_t pm_lock; // Power management lock + size_t num_dma_nodes; // Number of DMA descriptors that used to carry the frame buffer + uint8_t *fb; // Frame buffer + size_t fb_size; // Size of frame buffer + int data_gpio_nums[SOC_LCD_RGB_DATA_WIDTH]; // GPIOs used for data lines, we keep these GPIOs for action like "invert_color" + size_t resolution_hz; // Peripheral clock resolution + esp_lcd_rgb_timing_t timings; // RGB timing parameters (e.g. pclk, sync pulse, porch width) + gdma_channel_handle_t dma_chan; // DMA channel handle + esp_lcd_rgb_panel_frame_trans_done_cb_t on_frame_trans_done; // Callback, invoked after frame trans done + void *user_ctx; // Reserved user's data of callback functions + int x_gap; // Extra gap in x coordinate, it's used when calculate the flush window + int y_gap; // Extra gap in y coordinate, it's used when calculate the flush window + struct + { + unsigned int disp_en_level : 1; // The level which can turn on the screen by `disp_gpio_num` + unsigned int stream_mode : 1; // If set, the LCD transfers data continuously, otherwise, it stops refreshing the LCD when transaction done + unsigned int fb_in_psram : 1; // Whether the frame buffer is in PSRAM + } flags; + dma_descriptor_t dma_nodes[]; // DMA descriptor pool of size `num_dma_nodes` +}; + #endif @@ -278,6 +318,26 @@ class uDisplay : public Renderer { int8_t par_dbl[8]; int8_t par_dbh[8]; + int8_t de; + int8_t vsync; + int8_t hsync; + int8_t pclk; + + uint16_t hsync_polarity; + uint16_t hsync_front_porch; + uint16_t hsync_pulse_width; + uint16_t hsync_back_porch; + uint16_t vsync_polarity; + uint16_t vsync_front_porch; + uint16_t vsync_pulse_width; + uint16_t vsync_back_porch; + uint16_t pclk_active_neg; + + esp_lcd_panel_handle_t _panel_handle = NULL; + esp_rgb_panel_t *_rgb_panel; + uint16_t *rgb_fb; + + esp_lcd_i80_bus_handle_t _i80_bus = nullptr; gdma_channel_handle_t _dma_chan; lldesc_t *_dmadesc = nullptr; @@ -304,6 +364,7 @@ class uDisplay : public Renderer { uint8_t _align_data; void cs_control(bool level); uint32_t get_sr_touch(uint32_t xp, uint32_t xm, uint32_t yp, uint32_t ym); + void drawPixel_RGB(int16_t x, int16_t y, uint16_t color); #endif #ifdef ESP32 diff --git a/tasmota/displaydesc/ST7262_rgb16_display.ini b/tasmota/displaydesc/ST7262_rgb16_display.ini new file mode 100644 index 000000000..413af0bb1 --- /dev/null +++ b/tasmota/displaydesc/ST7262_rgb16_display.ini @@ -0,0 +1,5 @@ +:H,ST7262,800,480,16,RGB,40,41,39,42,2,15,16,4,45,48,47,21,14,8,3,46,9,1,5,6,7,14 +:S,2,1,1,0,40,20 +:V,0,8,4,8,0,8,4,8,1 +:TI1,5a,*,*,-1,38 +# diff --git a/tasmota/tasmota_support/support_esp.ino b/tasmota/tasmota_support/support_esp.ino index 30b6129c9..935733baf 100644 --- a/tasmota/tasmota_support/support_esp.ino +++ b/tasmota/tasmota_support/support_esp.ino @@ -623,6 +623,9 @@ uint32_t ESP_getFreeHeap(void) { uint32_t ESP_getMaxAllocHeap(void) { // arduino returns IRAM but we want only DRAM +#ifdef RGB_DISPLAY + return ESP_getFreeHeap(); +#endif uint32_t free_block_size = heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); if (free_block_size > 100) { free_block_size -= 100; } return free_block_size; @@ -1135,4 +1138,4 @@ uint32_t HwRandom(void) { last_ccount = ccount; return result ^ *(volatile uint32_t *)_RAND_ADDR; #undef _RAND_ADDR -} \ No newline at end of file +} diff --git a/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino b/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino index 1f8596ec3..075a6c7b9 100755 --- a/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino @@ -5152,7 +5152,7 @@ extern char *SML_GetSVal(uint32_t index); goto exit; } #endif // USE_TTGO_WATCH -#if defined(USE_FT5206) || defined(USE_XPT2046) || defined(USE_LILYGO47) || defined(USE_M5EPD47) +#if defined(USE_FT5206) || defined(USE_XPT2046) || defined(USE_LILYGO47) || defined(USE_GT911) if (!strncmp(lp, "wtch(", 5)) { lp = GetNumericArgument(lp + 5, OPER_EQU, &fvar, gv); fvar = Touch_Status(fvar); diff --git a/tasmota/tasmota_xdrv_driver/xdrv_55_touch.ino b/tasmota/tasmota_xdrv_driver/xdrv_55_touch.ino index 3a23b965e..69843572b 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_55_touch.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_55_touch.ino @@ -36,7 +36,7 @@ \*******************************************************************************************/ -#if defined(USE_LVGL_TOUCHSCREEN) || defined(USE_FT5206) || defined(USE_XPT2046) || defined(USE_LILYGO47) || defined(USE_TOUCH_BUTTONS) || defined(SIMPLE_RES_TOUCH) +#if defined(USE_LVGL_TOUCHSCREEN) || defined(USE_FT5206) || defined(USE_XPT2046) || defined(USE_GT911) || defined(USE_LILYGO47) || defined(USE_TOUCH_BUTTONS) || defined(SIMPLE_RES_TOUCH) #ifdef USE_DISPLAY_LVGL_ONLY #undef USE_TOUCH_BUTTONS @@ -72,6 +72,7 @@ typedef struct TSGlobal_t { TSGlobal_t TSGlobal; bool FT5206_found = false; +bool GT911_found = false; bool XPT2046_found = false; bool SRES_found = false; @@ -109,7 +110,7 @@ bool Touch_GetStatus(uint8_t* touches, uint16_t* x, uint16_t* y, uint8_t* gestur } uint32_t Touch_Status(int32_t sel) { - if (TSGlobal.external_ts || FT5206_found || XPT2046_found) { + if (TSGlobal.external_ts || FT5206_found || GT911_found || XPT2046_found || SRES_found) { switch (sel) { case 0: return TSGlobal.touched; @@ -196,7 +197,7 @@ bool FT5206_Touch_Init(TwoWire &i2c) { FT5206_found = false; FT5206_touchp = new FT5206_Class(); if (FT5206_touchp->begin(i2c, FT5206_address)) { - I2cSetActiveFound(FT5206_address, "FT5206"); + AddLog(LOG_LEVEL_INFO, PSTR("TI: FT5206")); FT5206_found = true; } //AddLog(LOG_LEVEL_INFO, PSTR("TS: FT5206 %d"),FT5206_found); @@ -216,11 +217,36 @@ int16_t FT5206_y() { } #endif // USE_FT5206 +#ifdef USE_GT911 +#include +// touch panel controller +GT911 *GT911_touchp; + +bool GT911_Touch_Init(TwoWire *i2c, int8_t irq_pin, int8_t rst_pin, uint16_t xs, uint16_t ys) { + GT911_found = false; + GT911_touchp = new GT911(); + if (ESP_OK == GT911_touchp->begin(i2c, irq_pin, rst_pin, xs, ys)) { + AddLog(LOG_LEVEL_INFO, PSTR("TI: GT911")); + GT911_found = true; + } + return GT911_found; +} + +void GT911_CheckTouch(void) { + GT911_touchp->update(); + TSGlobal.touched = !GT911_touchp->isFingerUp(); + if (TSGlobal.touched) { + TSGlobal.raw_touch_xp = GT911_touchp->readFingerX(0); + TSGlobal.raw_touch_yp = GT911_touchp->readFingerY(0); + } +} +#endif // USE_GT911 + + #ifdef USE_XPT2046 #include XPT2046_Touchscreen *XPT2046_touchp; - bool XPT2046_Touch_Init(uint16_t CS) { XPT2046_touchp = new XPT2046_Touchscreen(CS); XPT2046_found = XPT2046_touchp->begin(); @@ -266,6 +292,12 @@ void Touch_Check(void(*rotconvert)(int16_t *x, int16_t *y)) { } #endif // USE_FT5206 +#ifdef USE_GT911 + if (GT911_found) { + GT911_CheckTouch(); + } +#endif // USE_FT5206 + #ifdef USE_XPT2046 if (XPT2046_found) { TSGlobal.touched = XPT2046_touched(); @@ -333,18 +365,17 @@ void Touch_Check(void(*rotconvert)(int16_t *x, int16_t *y)) { } } -extern uint8_t GT911_found; #ifdef USE_TOUCH_BUTTONS void Touch_MQTT(uint8_t index, const char *cp, uint32_t val) { #ifdef USE_FT5206 - if (FT5206_found) ResponseTime_P(PSTR(",\"FT5206\":{\"%s%d\":\"%d\"}}"), cp, index+1, val); + if (FT5206_found) ResponseTime_P(PSTR(",\"FT5206\":{\"%s%d\":\"%d\"}}"), cp, index + 1, val); #endif #ifdef USE_XPT2046 - if (XPT2046_found) ResponseTime_P(PSTR(",\"XPT2046\":{\"%s%d\":\"%d\"}}"), cp, index+1, val); + if (XPT2046_found) ResponseTime_P(PSTR(",\"XPT2046\":{\"%s%d\":\"%d\"}}"), cp, index + 1, val); #endif // USE_XPT2046 #ifdef USE_GT911 - if (GT911_found) ResponseTime_P(PSTR(",\"GT911\":{\"%s%d\":\"%d\"}}"), cp, index+1, val); + if (GT911_found) ResponseTime_P(PSTR(",\"GT911\":{\"%s%d\":\"%d\"}}"), cp, index + 1, val); #endif // USE_XPT2046 MqttPublishTeleSensor(); } @@ -466,7 +497,7 @@ bool Xdrv55(uint32_t function) { case FUNC_INIT: break; case FUNC_EVERY_100_MSECOND: - if (FT5206_found || XPT2046_found || SRES_found) { + if (FT5206_found || XPT2046_found || GT911_found || SRES_found) { Touch_Check(TS_RotConvert); } break; diff --git a/tasmota/tasmota_xdsp_display/xdsp_17_universal.ino b/tasmota/tasmota_xdsp_display/xdsp_17_universal.ino index 3a24870d4..01dd6495a 100644 --- a/tasmota/tasmota_xdsp_display/xdsp_17_universal.ino +++ b/tasmota/tasmota_xdsp_display/xdsp_17_universal.ino @@ -33,6 +33,8 @@ uint8_t ctouch_counter; extern FS *ffsp; #endif +#undef GT911_address +#define GT911_address 0x5D enum {GPIO_DP_RES=GPIO_SENSOR_END-1,GPIO_DP_CS,GPIO_DP_RS,GPIO_DP_WR,GPIO_DP_RD,GPIO_DPAR0,GPIO_DPAR1,GPIO_DPAR2,GPIO_DPAR3,GPIO_DPAR4,GPIO_DPAR5,GPIO_DPAR6,GPIO_DPAR7,GPIO_DPAR8,GPIO_DPAR9,GPIO_DPAR10,GPIO_DPAR11,GPIO_DPAR12,GPIO_DPAR13,GPIO_DPAR14,GPIO_DPAR15}; @@ -231,8 +233,21 @@ int8_t cs; } } + uint16_t xs, ys; + // we need screen size for gt911 touch controler + cp = strstr(ddesc, ":H,"); + if (cp) { + cp += 3; + cp = strchr(cp, ','); + cp++; + xs = strtol(cp, &cp, 10); + cp++; + ys = strtol(cp, &cp, 10); + } + #ifdef CONFIG_IDF_TARGET_ESP32S3 int8_t xp, xm, yp, ym; + cp = strstr(ddesc, "PAR,"); if (cp) { cp += 4; @@ -284,7 +299,7 @@ int8_t cs; udisp = new uDisplay(ddesc); // checck for touch option TI1 or TI2 -#ifdef USE_FT5206 +#if defined(USE_FT5206) || defined(USE_GT911) cp = strstr(ddesc, ":TI"); if (cp) { uint8_t wire_n = 1; @@ -293,9 +308,21 @@ int8_t cs; cp += 2; uint8_t i2caddr = strtol(cp, &cp, 16); - int8_t scl, sda; + int8_t scl, sda, irq = -1, rst = -1; scl = replacepin(&cp, Pin(GPIO_I2C_SCL, wire_n)); sda = replacepin(&cp, Pin(GPIO_I2C_SDA, wire_n)); + if (*(cp - 1) == ',') { + irq = strtol(cp, &cp, 10); + } else { + irq = -1; + } + if (*cp == ',') { + cp++; + rst = strtol(cp, &cp, 10); + } else { + rst = -1; + } + if (wire_n == 0) { I2cBegin(sda, scl); } @@ -304,26 +331,54 @@ int8_t cs; I2c2Begin(sda, scl, 400000); } if (I2cSetDevice(i2caddr, wire_n)) { - I2cSetActiveFound(i2caddr, "FT5206", wire_n); + if (i2caddr == GT911_address) { + I2cSetActiveFound(i2caddr, "GT911", wire_n); + } else { + I2cSetActiveFound(i2caddr, "FT5206", wire_n); + } } #endif // ESP32 #ifdef ESP8266 //AddLog(LOG_LEVEL_INFO, PSTR("DSP: touch %x, %d, %d, %d!"), i2caddr, wire_n, scl, sda); if (I2cSetDevice(i2caddr)) { - I2cSetActiveFound(i2caddr, "FT5206"); + if (i2caddr == GT911_address) { + I2cSetActiveFound(i2caddr, "GT911"); + } else { + I2cSetActiveFound(i2caddr, "FT5206"); + } } #endif // ESP8266 // start digitizer #ifdef ESP32 - if (!wire_n) FT5206_Touch_Init(Wire); - else FT5206_Touch_Init(Wire1); + if (i2caddr == GT911_address) { +#ifdef USE_GT911 + if (!wire_n) GT911_Touch_Init(&Wire, irq, rst, xs, ys); + else GT911_Touch_Init(&Wire1, irq, rst, xs, ys); +#endif + } else { +#ifdef USE_FT5206 + if (!wire_n) FT5206_Touch_Init(Wire); + else FT5206_Touch_Init(Wire1); +#endif + } + #else + + if (i2caddr == GT911_address) { +#ifdef USE_GT911 + if (!wire_n) GT911_Touch_Init(&Wire, irq, rst, xs, ys); +#endif + } else { +#ifdef USE_FT5206 if (!wire_n) FT5206_Touch_Init(Wire); +#endif + } #endif // ESP32 + } -#endif // USE_FT5206 +#endif // USE_FT5206 || GT911 #ifdef USE_XPT2046 cp = strstr(ddesc, ":TS,"); From b33d2d540fdfa83a2492e35009301fdb8861643b Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 18 Dec 2022 14:18:14 +0100 Subject: [PATCH 022/262] Update changelogs --- CHANGELOG.md | 1 + RELEASENOTES.md | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e13370fe6..8a3f61efd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ All notable changes to this project will be documented in this file. ### Added - Support for IPv6 DNS records (AAAA) and IPv6 ``Ping`` for ESP32 and ESP8266 (#17417) - Berry support for ``crypto.SHA256`` (#17430) +- Support for RGB displays (#17414) ### Breaking Changed diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 3d628b985..1c083e5bb 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -109,6 +109,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm ## Changelog v12.3.1.1 ### Added +- Support for RGB displays [#17414](https://github.com/arendst/Tasmota/issues/17414) - Support for IPv6 DNS records (AAAA) and IPv6 ``Ping`` for ESP32 and ESP8266 [#17417](https://github.com/arendst/Tasmota/issues/17417) - Berry support for ``crypto.SHA256`` [#17430](https://github.com/arendst/Tasmota/issues/17430) From 318c83cb36cdd27aa8668ea6ecb3d2abca5612fc Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Sun, 18 Dec 2022 14:28:05 +0100 Subject: [PATCH 023/262] Revert UDP begin() (#17431) --- lib/libesp32/berry_tasmota/src/be_udp_lib.cpp | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/lib/libesp32/berry_tasmota/src/be_udp_lib.cpp b/lib/libesp32/berry_tasmota/src/be_udp_lib.cpp index f6084b049..370993a8c 100644 --- a/lib/libesp32/berry_tasmota/src/be_udp_lib.cpp +++ b/lib/libesp32/berry_tasmota/src/be_udp_lib.cpp @@ -14,7 +14,6 @@ // extern int be_udp_begin_mcast(bvm *vm); #include -#include #include #include "be_mapping.h" @@ -22,6 +21,8 @@ extern void AddLog(uint32_t loglevel, PGM_P formatP, ...); enum LoggingLevels {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE}; +extern bool WifiHostByName(const char* aHostname, IPAddress & aResult); + extern "C" { // init() @@ -41,19 +42,17 @@ extern "C" { return be_call_c_func(vm, (void*) &be_udp_deinit_ntv, "=.p", ""); } - // udp.begin(address:string, port:int) -> bool - int32_t be_udp_begin_ntv(WiFiUDP *udp, int32_t port) { + // udp.begin(interface:string, port:int) -> bool + int32_t be_udp_begin_ntv(WiFiUDP *udp, const char *host, int32_t port) { IPAddress addr; - // AddLog(LOG_LEVEL_DEBUG, "BRY: udp.begin listening to '%s'", addr.toString().c_str()); + // if no host or host is "" then we defult to INADDR_ANY + if(host && (*host != 0) && !WifiHostByName(host, addr)){ + return 0; + } return udp->begin(addr, port); } int32_t be_udp_begin(struct bvm *vm) { - if (be_top(vm) >= 3 && be_isstring(vm, 2)) { - // legacy string parameter, now ignored - return be_call_c_func(vm, (void*) &be_udp_begin_ntv, "b", ".-i"); - } else { - return be_call_c_func(vm, (void*) &be_udp_begin_ntv, "b", ".i"); - } + return be_call_c_func(vm, (void*) &be_udp_begin_ntv, "b", ".si"); } // udp.stop() -> nil @@ -67,7 +66,7 @@ extern "C" { // udp.begin_multicast(address:string, port:int) -> nil int32_t be_udp_begin_mcast_ntv(WiFiUDP *udp, const char *host, int32_t port) { IPAddress addr; - if(!WiFiGenericClass::hostByName(host, addr)){ + if(!WifiHostByName(host, addr)){ return 0; } return udp->WiFiUDP::beginMulticast(addr, port); @@ -79,7 +78,7 @@ extern "C" { // udp.send(address:string, port:int, payload:bytes) -> bool int32_t be_udp_send_ntv(WiFiUDP *udp, const char *host, int32_t port, const uint8_t* buf, int32_t len) { IPAddress addr; - if (!WiFiGenericClass::hostByName(host, addr)){ + if (!WifiHostByName(host, addr)){ return 0; } // AddLog(LOG_LEVEL_DEBUG, "BRY: udp.begin got host '%s'", addr.toString().c_str()); From ff02873af3f6c8b2cd5865b6812389717cc6e9dc Mon Sep 17 00:00:00 2001 From: Barbudor Date: Sun, 18 Dec 2022 17:05:32 +0100 Subject: [PATCH 024/262] fix failure building cenv in linux (#17432) --- platformio_override_sample.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio_override_sample.ini b/platformio_override_sample.ini index 0c5af9cb3..6c8b9bd4a 100644 --- a/platformio_override_sample.ini +++ b/platformio_override_sample.ini @@ -71,7 +71,7 @@ board = ${common.board} ;board_build.f_cpu = 160000000L ;board_build.f_flash = 40000000L ; *** Define serial port used for erasing/flashing/terminal -upload_port = +upload_port = ${common.upload_port} monitor_port = ${env.upload_port} extra_scripts = ${esp_defaults.extra_scripts} ; pio-tools/obj-dump.py @@ -112,7 +112,7 @@ lib_extra_dirs = ${library.lib_extra_dirs} ;board_upload.arduino.flash_extra_images = ;board_build.partitions = partitions/esp32_partition_app2944k_fs2M.csv ; *** Serial port used for erasing/flashing the ESP32 -upload_port = +upload_port = ${common.upload_port} ;upload_speed = 115200 monitor_port = ${env.upload_port} upload_resetmethod = ${common.upload_resetmethod} From 29705c15af475293acd295f2895b6c13ea97d224 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Sun, 18 Dec 2022 17:56:24 +0100 Subject: [PATCH 025/262] revert Platformio changes (#17433) --- platformio.ini | 3 ++- platformio_override_sample.ini | 16 ++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/platformio.ini b/platformio.ini index 0f9034f8d..3a77eb1a1 100644 --- a/platformio.ini +++ b/platformio.ini @@ -35,9 +35,10 @@ custom_unpack_dir = unpacked_littlefs build_unflags = ${core.build_unflags} build_flags = ${core.build_flags} monitor_speed = 115200 +monitor_port = COM5 ; *** Upload Serial reset method for Wemos and NodeMCU upload_resetmethod = nodemcu -upload_port = /dev/cu.SLAB_USBtoUART +upload_port = COM5 extra_scripts = ${esp_defaults.extra_scripts} lib_ldf_mode = chain lib_compat_mode = strict diff --git a/platformio_override_sample.ini b/platformio_override_sample.ini index 6c8b9bd4a..3dcff4fae 100644 --- a/platformio_override_sample.ini +++ b/platformio_override_sample.ini @@ -70,9 +70,9 @@ board = ${common.board} ;board = esp8266_4M2M ;board_build.f_cpu = 160000000L ;board_build.f_flash = 40000000L -; *** Define serial port used for erasing/flashing/terminal -upload_port = ${common.upload_port} -monitor_port = ${env.upload_port} +;monitor_speed = 115200 +; *** Serial port used for erasing/flashing the ESP82xx +;upload_port = COM5 extra_scripts = ${esp_defaults.extra_scripts} ; pio-tools/obj-dump.py lib_ignore = @@ -111,12 +111,12 @@ lib_extra_dirs = ${library.lib_extra_dirs} ;board_upload.maximum_size = 8388608 ;board_upload.arduino.flash_extra_images = ;board_build.partitions = partitions/esp32_partition_app2944k_fs2M.csv -; *** Serial port used for erasing/flashing the ESP32 -upload_port = ${common.upload_port} -;upload_speed = 115200 -monitor_port = ${env.upload_port} -upload_resetmethod = ${common.upload_resetmethod} monitor_speed = 115200 +; *** Serial port used for erasing/flashing the ESP32 +;upload_port = ${common.upload_port} +upload_port = COM4 +;upload_speed = 115200 +upload_resetmethod = ${common.upload_resetmethod} extra_scripts = ${esp32_defaults.extra_scripts} ; pio-tools/obj-dump.py lib_ignore = From 3a98fbbe38b3a41537f8c3e6e1377c5a4775fcc6 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Mon, 19 Dec 2022 15:51:57 +0100 Subject: [PATCH 026/262] rm AutodetectUploadPort (#17442) --- pio-tools/download_fs.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/pio-tools/download_fs.py b/pio-tools/download_fs.py index 4343adee3..0235af850 100644 --- a/pio-tools/download_fs.py +++ b/pio-tools/download_fs.py @@ -13,8 +13,6 @@ import re import sys from os.path import isfile, join from enum import Enum -import typing -from platformio.builder.tools.pioupload import AutodetectUploadPort import os import subprocess import shutil @@ -28,8 +26,6 @@ if env["PIOPLATFORM"] == "espressif32": #print("Replace MKSPIFFSTOOL with mklittlefs") env.Replace( MKSPIFFSTOOL=platform.get_package_dir("tool-mklittlefs") + '/mklittlefs' ) -# needed for later -AutodetectUploadPort(env) class FSType(Enum): SPIFFS="spiffs" @@ -232,7 +228,7 @@ def esp8266_get_esptoolpy_reset_flags(resetmethod): def get_fs_type_start_and_length(): platform = env["PIOPLATFORM"] if platform == "espressif32": - print("Retrieving filesystem info for ESP32. Assuming SPIFFS.") + print("Retrieving filesystem info for ESP32.") print("Partition file: " + str(env.subst("$PARTITIONS_TABLE_CSV"))) esp32_fetch_spiffs_size(env) return SPIFFSInfo(env["SPIFFS_START"], env["SPIFFS_SIZE"], env["SPIFFS_PAGE"], env["SPIFFS_BLOCK"]) @@ -263,7 +259,6 @@ def download_fs(fs_info: FSInfo): fs_file = join(env["PROJECT_DIR"], f"downloaded_fs_{hex(fs_info.start)}_{hex(fs_info.length)}.bin") esptoolpy_flags = [ "--chip", mcu, - "--port", env.subst("$UPLOAD_PORT"), "--baud", env.subst("$UPLOAD_SPEED"), "--before", "default_reset", "--after", "hard_reset", From dbdc2f02d468ef178183f56808d7cea5b80d027e Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Mon, 19 Dec 2022 17:58:32 +0100 Subject: [PATCH 027/262] Fix capitalization (#17446) --- platformio_tasmota_cenv_sample.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio_tasmota_cenv_sample.ini b/platformio_tasmota_cenv_sample.ini index e086b1094..39339e4cc 100644 --- a/platformio_tasmota_cenv_sample.ini +++ b/platformio_tasmota_cenv_sample.ini @@ -27,7 +27,7 @@ board_build.partitions = partitions/esp32_partition_app2944k_fs2M.csv board_upload.arduino.flash_extra_images = ; Example for custom file upload in Tasmota Filesystem custom_files_upload = ${env:tasmota32_base.custom_files_upload} - tasmota/berry/modules/Partition_wizard.tapp + tasmota/berry/modules/Partition_Wizard.tapp https://github.com/tasmota/autoconf/raw/main/esp32s3/DevKitC-1.autoconf [env:tasmota32s3-qio_opi-all] From 59fc09acc40157c0ce00a5c6e1e10451509dcea1 Mon Sep 17 00:00:00 2001 From: stefanbode Date: Mon, 19 Dec 2022 20:31:02 +0100 Subject: [PATCH 028/262] Fix on init procedure (#17447) * fix output * Avoid wrong init parameter #17403 --- tasmota/tasmota_xdrv_driver/xdrv_27_shutter.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_27_shutter.ino b/tasmota/tasmota_xdrv_driver/xdrv_27_shutter.ino index 83b005930..c1a143666 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_27_shutter.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_27_shutter.ino @@ -395,7 +395,7 @@ void ShutterInit(void) Settings->shutter_accuracy = 1; Settings->shutter_mode = ShutterGlobal.position_mode; // initialize MotorStop time with 500ms if not set - Settings->shutter_motorstop = Settings->shutter_motorstop == 0?500:Settings->shutter_motorstop; + Settings->shutter_motorstop = Settings->shutter_motorstop == 0?500:Settings->shutter_motorstop>60000?500:Settings->shutter_motorstop; } } @@ -1754,7 +1754,7 @@ void CmndShutterTiltConfig(void) ShutterInit(); } char setting_chr[30] = "0"; - snprintf_P(setting_chr, sizeof(setting_chr), PSTR("%d %d %d %d %d"), XdrvMailbox.index -1,Shutter[XdrvMailbox.index -1].tilt_config[0], Shutter[XdrvMailbox.index -1].tilt_config[1],Shutter[XdrvMailbox.index -1].tilt_config[2],Shutter[XdrvMailbox.index -1].tilt_config[3],Shutter[XdrvMailbox.index -1].tilt_config[4]); + snprintf_P(setting_chr, sizeof(setting_chr), PSTR("%d %d %d %d %d"), Shutter[XdrvMailbox.index -1].tilt_config[0], Shutter[XdrvMailbox.index -1].tilt_config[1],Shutter[XdrvMailbox.index -1].tilt_config[2],Shutter[XdrvMailbox.index -1].tilt_config[3],Shutter[XdrvMailbox.index -1].tilt_config[4]); ResponseCmndIdxChar(setting_chr); AddLog(LOG_LEVEL_INFO, PSTR("SHT: TiltConfig %d, min: %d, max %d, runtime %d, close_pos: %d, open_pos: %d"), XdrvMailbox.index ,Shutter[XdrvMailbox.index -1].tilt_config[0], Shutter[XdrvMailbox.index -1].tilt_config[1],Shutter[XdrvMailbox.index -1].tilt_config[2],Shutter[XdrvMailbox.index -1].tilt_config[3],Shutter[XdrvMailbox.index -1].tilt_config[4]); } From d670f476ba977990d1f09ec0ebd989ea7a3845cd Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Mon, 19 Dec 2022 22:30:54 +0100 Subject: [PATCH 029/262] Berry add crypto AES_CTR, HDMAC_SHA256, MD5 (#17451) --- CHANGELOG.md | 1 + .../berry_tasmota/src/be_crypto_lib.c | 31 ++++ lib/libesp32/berry_tasmota/src/be_md5_lib.c | 16 +- tasmota/my_user_config.h | 2 + .../xdrv_52_3_berry_crypto.ino | 168 +++++++++++++++++- 5 files changed, 208 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a3f61efd..a17731b8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ All notable changes to this project will be documented in this file. - Support for IPv6 DNS records (AAAA) and IPv6 ``Ping`` for ESP32 and ESP8266 (#17417) - Berry support for ``crypto.SHA256`` (#17430) - Support for RGB displays (#17414) +- Berry add crypto AES_CTR, HDMAC_SHA256, MD5 ### Breaking Changed diff --git a/lib/libesp32/berry_tasmota/src/be_crypto_lib.c b/lib/libesp32/berry_tasmota/src/be_crypto_lib.c index 3889e750c..083a846c9 100644 --- a/lib/libesp32/berry_tasmota/src/be_crypto_lib.c +++ b/lib/libesp32/berry_tasmota/src/be_crypto_lib.c @@ -12,6 +12,10 @@ extern int m_aes_gcm_encryt(bvm *vm); extern int m_aes_gcm_decryt(bvm *vm); extern int m_aes_gcm_tag(bvm *vm); +extern int m_aes_ctr_init(bvm *vm); +extern int m_aes_ctr_run(bvm *vm); +extern int m_aes_ctr_tag(bvm *vm); + extern int m_ec_c25519_pubkey(bvm *vm); extern int m_ec_c25519_sharedkey(bvm *vm); @@ -19,9 +23,17 @@ extern int m_hash_sha256_init(bvm *vm); extern int m_hash_sha256_update(bvm *vm); extern int m_hash_sha256_out(bvm *vm); +extern int m_hmac_sha256_init(bvm *vm); +extern int m_hmac_sha256_update(bvm *vm); +extern int m_hmac_sha256_out(bvm *vm); + +extern const bclass be_class_md5; + #include "be_fixed_be_class_aes_gcm.h" +#include "be_fixed_be_class_aes_ctr.h" #include "be_fixed_be_class_ec_c25519.h" #include "be_fixed_be_class_sha256.h" +#include "be_fixed_be_class_hmac_sha256.h" #include "be_fixed_crypto.h" /* @const_object_info_begin @@ -36,6 +48,14 @@ class be_class_aes_gcm (scope: global, name: AES_GCM) { tag, func(m_aes_gcm_tag) } +class be_class_aes_ctr (scope: global, name: AES_CTR) { + .p1, var + + init, func(m_aes_ctr_init) + encrypt, func(m_aes_ctr_run) + decrypt, func(m_aes_ctr_run) +} + class be_class_ec_c25519 (scope: global, name: EC_C25519) { public_key, func(m_ec_c25519_pubkey) shared_key, func(m_ec_c25519_sharedkey) @@ -49,10 +69,21 @@ class be_class_sha256 (scope: global, name: SHA256) { out, func(m_hash_sha256_out) } +class be_class_hmac_sha256 (scope: global, name: HMAC_SHA256) { + .p, var + + init, func(m_hmac_sha256_init) + update, func(m_hmac_sha256_update) + out, func(m_hmac_sha256_out) +} + module crypto (scope: global) { AES_GCM, class(be_class_aes_gcm) + AES_CTR, class(be_class_aes_ctr) EC_C25519, class(be_class_ec_c25519) SHA256, class(be_class_sha256) + HMAC_SHA256, class(be_class_hmac_sha256) + MD5, class(be_class_md5) } @const_object_info_end */ diff --git a/lib/libesp32/berry_tasmota/src/be_md5_lib.c b/lib/libesp32/berry_tasmota/src/be_md5_lib.c index 3b73940ce..109003422 100644 --- a/lib/libesp32/berry_tasmota/src/be_md5_lib.c +++ b/lib/libesp32/berry_tasmota/src/be_md5_lib.c @@ -11,8 +11,8 @@ #include "esp_rom_md5.h" // `Md5.init() -> ` -int32_t m_md5_init(struct bvm *vm); -int32_t m_md5_init(struct bvm *vm) { +int m_md5_init(bvm *vm); +int m_md5_init(bvm *vm) { md5_context_t * ctx = (md5_context_t *) be_os_malloc(sizeof(md5_context_t)); if (!ctx) { @@ -28,13 +28,11 @@ int32_t m_md5_init(struct bvm *vm) { // `Md5.update(content:bytes()) -> nil` // // Add raw bytes to the MD5 calculation -int32_t m_md5_update(struct bvm *vm); -int32_t m_md5_update(struct bvm *vm) { +int m_md5_update(bvm *vm); +int m_md5_update(bvm *vm) { int32_t argc = be_top(vm); // Get the number of arguments - if (argc >= 2 && be_isinstance(vm, 2)) { + if (argc >= 2 && be_isbytes(vm, 2)) { do { - be_getglobal(vm, "bytes"); /* get the bytes class */ /* TODO eventually replace with be_getbuiltin */ - if (!be_isderived(vm, 2)) break; size_t length = 0; const void * bytes = be_tobytes(vm, 2, &length); if (!bytes) break; @@ -57,8 +55,8 @@ int32_t m_md5_update(struct bvm *vm) { // `Md5.update(content:bytes()) -> nil` // // Add raw bytes to the MD5 calculation -int32_t m_md5_finish(struct bvm *vm); -int32_t m_md5_finish(struct bvm *vm) { +int m_md5_finish(bvm *vm); +int m_md5_finish(bvm *vm) { be_getmember(vm, 1, ".p"); md5_context_t * ctx; ctx = (md5_context_t *) be_tocomptr(vm, -1); diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index f00cc476a..3b147cce7 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -1106,8 +1106,10 @@ // #define USE_BERRY_ULP // Enable ULP (Ultra Low Power) support (+4.9k) // Berry crypto extensions below: #define USE_BERRY_CRYPTO_AES_GCM // enable AES GCM 256 bits + #define USE_BERRY_CRYPTO_AES_CTR // enable AEC CTR 256 bits // #define USE_BERRY_CRYPTO_EC_C25519 // enable Elliptic Curve C C25519 #define USE_BERRY_CRYPTO_SHA256 // enable SHA256 hash function + #define USE_BERRY_CRYPTO_HMAC_SHA256 // enable HMAC SHA256 hash function #define USE_CSE7761 // Add support for CSE7761 Energy monitor as used in Sonoff Dual R3 // -- LVGL Graphics Library --------------------------------- diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino index 83094ff5d..8f5e3613e 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino @@ -25,7 +25,7 @@ #include "be_object.h" /*********************************************************************************************\ - * AES class + * AES_GCM class * \*********************************************************************************************/ extern "C" { @@ -158,6 +158,87 @@ extern "C" { #endif // USE_BERRY_CRYPTO_AES_GCM } } + +/*********************************************************************************************\ + * AES_CTR class + * +\*********************************************************************************************/ +extern "C" { + + // `AES_CTR.init(secret_key:bytes(32)) -> instance` + int32_t m_aes_ctr_init(struct bvm *vm); + int32_t m_aes_ctr_init(struct bvm *vm) { +#ifdef USE_BERRY_CRYPTO_AES_CTR + int32_t argc = be_top(vm); // Get the number of arguments + if (argc >= 2 && be_isbytes(vm, 2)) { + do { + size_t length = 0; + const void * bytes = be_tobytes(vm, 2, &length); + if (!bytes) break; + if (length != 32) { + be_raise(vm, "value_error", "Key size must be 32 bytes"); + } + + // Initialize an AES CTR structure with the secret key + br_aes_small_ctr_keys * ctr_ctx = (br_aes_small_ctr_keys *) be_os_malloc(sizeof(br_aes_small_ctr_keys)); + if (!ctr_ctx) { be_throw(vm, BE_MALLOC_FAIL); } + br_aes_small_ctr_init(ctr_ctx, bytes, length); + be_newcomobj(vm, ctr_ctx, &be_commonobj_destroy_generic); + be_setmember(vm, 1, ".p1"); + + be_return_nil(vm); + // success + } while (0); + } + be_raise(vm, kTypeError, nullptr); +#else // USE_BERRY_CRYPTO_AES_CTR + be_raise(vm, "Not implemented", nullptr); +#endif // USE_BERRY_CRYPTO_AES_CTR + } + + // `.encrypt(content:bytes(), in:bytes(12), counter:int) -> nil` + // `.decrypt(content:bytes(), in:bytes(12), counter:int) -> nil` + int32_t m_aes_ctr_run(bvm *vm); + int32_t m_aes_ctr_run(bvm *vm) { +#ifdef USE_BERRY_CRYPTO_AES_CTR + int32_t argc = be_top(vm); // Get the number of arguments + if (argc >= 4 && be_isbytes(vm, 2) && be_isbytes(vm, 3) && be_isint(vm, 4)) { + do { + // get GCM context + be_getmember(vm, 1, ".p1"); + br_aes_small_ctr_keys * ctx = (br_aes_small_ctr_keys *) be_tocomptr(vm, -1); + be_pop(vm, 1); + + size_t iv_len; + const void * iv = be_tobytes(vm, 3, &iv_len); + if (iv_len != 12) { be_raise(vm, "value_error", "IV size must be 12 bytes"); } + + uint32_t counter = be_toint(vm, 4); + + // copy the input buffer + be_getmember(vm, 2, "copy"); // stack: bytes.copy() + be_pushvalue(vm, 2); // stack: bytes.copy(), bytes instance + be_call(vm, 1); // call copy with self parameter + be_pop(vm, 1); // stack: clone of input bytes + + size_t length = 0; + // we are changing bytes in place + void * bytes = (void*) be_tobytes(vm, -1, &length); + if (!bytes) break; + + uint32_t next_counter = br_aes_small_ctr_run(ctx, iv, counter, bytes, length); + + be_return(vm); + // success + } while (0); + } + be_raise(vm, kTypeError, nullptr); +#else // USE_BERRY_CRYPTO_AES_CTR + be_raise(vm, "Not implemented", nullptr); +#endif // USE_BERRY_CRYPTO_AES_CTR + } +} + /*********************************************************************************************\ * SHA256 class * @@ -236,6 +317,91 @@ extern "C" { } } +/*********************************************************************************************\ + * HMAC_SHA256 class + * +\*********************************************************************************************/ +extern "C" { + + // `HMAC_SHA256.init(key:bytes) -> nil` + int32_t m_hmac_sha256_init(struct bvm *vm); + int32_t m_hmac_sha256_init(struct bvm *vm) { +#ifdef USE_BERRY_CRYPTO_HMAC_SHA256 + int32_t argc = be_top(vm); // Get the number of arguments + if (argc >= 2 && be_isbytes(vm, 2)) { + // Initialize a HMAC context + br_hmac_context * ctx = (br_hmac_context *) be_os_malloc(sizeof(br_hmac_context)); + if (!ctx) { + be_throw(vm, BE_MALLOC_FAIL); + } + br_hmac_key_context keyCtx; // keyCtx can be allocated on stack, it is not needed after `br_hmac_init` + size_t key_len; + const void *key = be_tobytes(vm, 2, &key_len); + br_hmac_key_init(&keyCtx, &br_sha256_vtable, key, key_len); + br_hmac_init(ctx, &keyCtx, 0); // 0 is "natural output length" + + be_newcomobj(vm, ctx, &be_commonobj_destroy_generic); + be_setmember(vm, 1, ".p"); + be_return_nil(vm); + } + be_raise(vm, kTypeError, nullptr); +#else // USE_BERRY_CRYPTO_HMAC_SHA256 + be_raise(vm, "Not implemented", nullptr); +#endif // USE_BERRY_CRYPTO_HMAC_SHA256 + } + + // `.update(content:bytes()) -> nil` + // + // Add raw bytes to the hash calculation + int32_t m_hmac_sha256_update(struct bvm *vm); + int32_t m_hmac_sha256_update(struct bvm *vm) { +#ifdef USE_BERRY_CRYPTO_HMAC_SHA256 + int32_t argc = be_top(vm); // Get the number of arguments + if (argc >= 2 && be_isinstance(vm, 2)) { + do { + if (!be_isbytes(vm, 2)) break; + size_t length = 0; + const void * bytes = be_tobytes(vm, 2, &length); + if (!bytes) break; + + be_getmember(vm, 1, ".p"); + br_hmac_context * ctx; + ctx = (br_hmac_context *) be_tocomptr(vm, -1); + if (!ctx) break; + + if (length > 0) { + br_hmac_update(ctx, bytes, length); + } + be_return_nil(vm); + // success + } while (0); + } + be_raise(vm, "value_error", NULL); +#else // USE_BERRY_CRYPTO_HMAC_SHA256 + be_raise(vm, "Not implemented", nullptr); +#endif // USE_BERRY_CRYPTO_HMAC_SHA256 + } + + // `.finish() -> bytes()` + // + // Add raw bytes to the MD5 calculation + int32_t m_hmac_sha256_out(struct bvm *vm); + int32_t m_hmac_sha256_out(struct bvm *vm) { +#ifdef USE_BERRY_CRYPTO_HMAC_SHA256 + be_getmember(vm, 1, ".p"); + br_hmac_context * ctx; + ctx = (br_hmac_context *) be_tocomptr(vm, -1); + + uint8_t output[32]; + br_hmac_out(ctx, output); + be_pushbytes(vm, output, sizeof(output)); + be_return(vm); +#else // USE_BERRY_CRYPTO_HMAC_SHA256 + be_raise(vm, "Not implemented", nullptr); +#endif // USE_BERRY_CRYPTO_HMAC_SHA256 + } +} + /*********************************************************************************************\ * EC C25519 class * From 9fa29c4f39b8f19222a8dd6c36a4f21609c644ca Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Tue, 20 Dec 2022 09:27:10 +0100 Subject: [PATCH 030/262] rm upload_port defaults (#17443) * rm upload_port defaults --- platformio.ini | 2 -- platformio_override_sample.ini | 12 ++++++------ platformio_tasmota_env.ini | 1 - platformio_tasmota_env32.ini | 1 - 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/platformio.ini b/platformio.ini index 3a77eb1a1..9344e7254 100644 --- a/platformio.ini +++ b/platformio.ini @@ -35,10 +35,8 @@ custom_unpack_dir = unpacked_littlefs build_unflags = ${core.build_unflags} build_flags = ${core.build_flags} monitor_speed = 115200 -monitor_port = COM5 ; *** Upload Serial reset method for Wemos and NodeMCU upload_resetmethod = nodemcu -upload_port = COM5 extra_scripts = ${esp_defaults.extra_scripts} lib_ldf_mode = chain lib_compat_mode = strict diff --git a/platformio_override_sample.ini b/platformio_override_sample.ini index 3dcff4fae..572a595a0 100644 --- a/platformio_override_sample.ini +++ b/platformio_override_sample.ini @@ -70,9 +70,9 @@ board = ${common.board} ;board = esp8266_4M2M ;board_build.f_cpu = 160000000L ;board_build.f_flash = 40000000L -;monitor_speed = 115200 -; *** Serial port used for erasing/flashing the ESP82xx -;upload_port = COM5 +; *** Define serial port used for erasing/flashing/terminal +;upload_port = COM4 +;monitor_port = COM4 extra_scripts = ${esp_defaults.extra_scripts} ; pio-tools/obj-dump.py lib_ignore = @@ -111,11 +111,11 @@ lib_extra_dirs = ${library.lib_extra_dirs} ;board_upload.maximum_size = 8388608 ;board_upload.arduino.flash_extra_images = ;board_build.partitions = partitions/esp32_partition_app2944k_fs2M.csv -monitor_speed = 115200 ; *** Serial port used for erasing/flashing the ESP32 -;upload_port = ${common.upload_port} -upload_port = COM4 +;upload_port = COM4 +;monitor_port = COM4 ;upload_speed = 115200 +monitor_speed = 115200 upload_resetmethod = ${common.upload_resetmethod} extra_scripts = ${esp32_defaults.extra_scripts} ; pio-tools/obj-dump.py diff --git a/platformio_tasmota_env.ini b/platformio_tasmota_env.ini index 65a5490c7..bce085213 100644 --- a/platformio_tasmota_env.ini +++ b/platformio_tasmota_env.ini @@ -7,7 +7,6 @@ board_build.filesystem = ${common.board_build.filesystem} build_unflags = ${common.build_unflags} build_flags = ${common.build_flags} monitor_speed = ${common.monitor_speed} -upload_port = ${common.upload_port} upload_resetmethod = ${common.upload_resetmethod} extra_scripts = ${common.extra_scripts} lib_ldf_mode = ${common.lib_ldf_mode} diff --git a/platformio_tasmota_env32.ini b/platformio_tasmota_env32.ini index 8acfebe40..d68554e80 100644 --- a/platformio_tasmota_env32.ini +++ b/platformio_tasmota_env32.ini @@ -6,7 +6,6 @@ board_build.filesystem = ${common.board_build.filesystem} custom_unpack_dir = ${common.custom_unpack_dir} board = esp32 monitor_speed = 115200 -upload_port = ${common.upload_port} upload_resetmethod = ${common.upload_resetmethod} extra_scripts = ${esp32_defaults.extra_scripts} build_unflags = ${core32.build_unflags} From 3555d88bee0fc84030002c6969b5c42b39ff10fc Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Wed, 21 Dec 2022 15:20:33 +0100 Subject: [PATCH 031/262] Bump version v12.3.1.2 - Fix shutter default motorstop set to 0 (#17403) --- CHANGELOG.md | 20 +++++++++++++------- RELEASENOTES.md | 3 ++- tasmota/include/tasmota_types.h | 3 ++- tasmota/include/tasmota_version.h | 2 +- tasmota/tasmota_support/settings.ino | 3 +++ 5 files changed, 21 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a17731b8c..f385b74bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,22 +3,28 @@ All notable changes to this project will be documented in this file. ## [Unreleased] - Development -## [12.3.1.1] 20221216 +## [12.3.1.2] +### Added + +### Breaking Changed + +### Changed + +### Fixed +- Shutter default motorstop set to 0 (#17403) + +### Removed + +## [12.3.1.1] 20221221 ### Added - Support for IPv6 DNS records (AAAA) and IPv6 ``Ping`` for ESP32 and ESP8266 (#17417) - Berry support for ``crypto.SHA256`` (#17430) - Support for RGB displays (#17414) - Berry add crypto AES_CTR, HDMAC_SHA256, MD5 -### Breaking Changed - ### Changed - ESP32 Framework (Core) from v2.0.5.3 to v2.0.5.4 (IPv6 support) -### Fixed - -### Removed - ## [Released] ## [12.3.1] 20221216 diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 1c083e5bb..1cc51965b 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -107,7 +107,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm [Complete list](BUILDS.md) of available feature and sensors. -## Changelog v12.3.1.1 +## Changelog v12.3.1.2 ### Added - Support for RGB displays [#17414](https://github.com/arendst/Tasmota/issues/17414) - Support for IPv6 DNS records (AAAA) and IPv6 ``Ping`` for ESP32 and ESP8266 [#17417](https://github.com/arendst/Tasmota/issues/17417) @@ -120,5 +120,6 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm - TuyaMcu rewrite by btsimonh [#17051](https://github.com/arendst/Tasmota/issues/17051) ### Fixed +- Shutter default motorstop set to 0 [#17403](https://github.com/arendst/Tasmota/issues/17403) ### Removed diff --git a/tasmota/include/tasmota_types.h b/tasmota/include/tasmota_types.h index 5a268a666..5e7d5cd16 100644 --- a/tasmota/include/tasmota_types.h +++ b/tasmota/include/tasmota_types.h @@ -731,7 +731,8 @@ typedef struct { uint16_t artnet_universe; // 734 uint16_t modbus_sbaudrate; // 736 uint16_t shutter_motorstop; // 738 - uint8_t free_esp32_73A[3]; // 73A + + uint8_t free_73A[3]; // 73A uint8_t novasds_startingoffset; // 73D uint8_t web_color[18][3]; // 73E diff --git a/tasmota/include/tasmota_version.h b/tasmota/include/tasmota_version.h index 498e76d8f..1e40104cd 100644 --- a/tasmota/include/tasmota_version.h +++ b/tasmota/include/tasmota_version.h @@ -20,6 +20,6 @@ #ifndef _TASMOTA_VERSION_H_ #define _TASMOTA_VERSION_H_ -const uint32_t VERSION = 0x0C030101; // 12.3.1.1 +const uint32_t VERSION = 0x0C030102; // 12.3.1.2 #endif // _TASMOTA_VERSION_H_ diff --git a/tasmota/tasmota_support/settings.ino b/tasmota/tasmota_support/settings.ino index 4837cbdaa..f5b568f72 100644 --- a/tasmota/tasmota_support/settings.ino +++ b/tasmota/tasmota_support/settings.ino @@ -1611,6 +1611,9 @@ void SettingsDelta(void) { Settings->modbus_sbaudrate = Settings->ex_modbus_sbaudrate; Settings->param[P_SERIAL_SKIP] = 0; } + if (Settings->version < 0x0C030102) { // 12.3.1.2 + Settings->shutter_motorstop = 0; + } Settings->version = VERSION; SettingsSave(1); From b2d3921778ba31849b01b36b8afde15f90c8e023 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Wed, 21 Dec 2022 15:26:42 +0100 Subject: [PATCH 032/262] Fix shutter logging --- .../tasmota_xdrv_driver/xdrv_27_shutter.ino | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_27_shutter.ino b/tasmota/tasmota_xdrv_driver/xdrv_27_shutter.ino index c1a143666..198a13dea 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_27_shutter.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_27_shutter.ino @@ -309,7 +309,7 @@ void ShutterInit(void) AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Mode undef.. calculate...")); ShutterGlobal.position_mode = SHT_TIME; if (!relay_in_interlock) { - // temporary to maintain old functionality + // temporary to maintain old functionality if (Settings->shutter_mode == SHT_UNDEF) { ShutterGlobal.position_mode = SHT_TIME_UP_DOWN; } @@ -376,16 +376,16 @@ void ShutterInit(void) // Test is the relays are in interlock mode. Disable shuttermode if error if (!relay_in_interlock) { TasmotaGlobal.shutters_present = 0, - AddLog(LOG_LEVEL_ERROR, PSTR("SHT: ERROR: Shtr%d Relays are not in INTERLOCK. Pls read documentation. Shutter DISABLE. Fix and REBOOT"),i+1); + AddLog(LOG_LEVEL_ERROR, PSTR("SHT: ERROR: Shtr%d Relays are not in INTERLOCK. Pls read documentation. Shutter DISABLE. Fix and REBOOT"), i+1); return; - } + } break; } - AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Shtr%d min realpos_chg: %d, min tilt_chg %d"),i+1,Shutter[i].min_realPositionChange,Shutter[i].min_TiltChange); - AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Shtr%d Openvel %d, Closevel: %d"),i, ShutterGlobal.open_velocity_max, Shutter[i].close_velocity_max); + AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Shtr%d min realpos_chg: %d, min tilt_chg %d"), i+1, Shutter[i].min_realPositionChange, Shutter[i].min_TiltChange); + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Shtr%d Openvel %d, Closevel: %d"), i+1, ShutterGlobal.open_velocity_max, Shutter[i].close_velocity_max); AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Shtr%d Init. Pos %d, Inv %d, Locked %d, Endstop enab %d, webButt inv %d, Motordel: %d"), i+1, Shutter[i].real_position, - (Settings->shutter_options[i]&1) ? 1 : 0, (Settings->shutter_options[i]&2) ? 1 : 0, (Settings->shutter_options[i]&4) ? 1 : 0, (Settings->shutter_options[i]&8) ? 1 : 0, Shutter[i].motordelay); + (Settings->shutter_options[i] & 1) ? 1 : 0, (Settings->shutter_options[i] & 2) ? 1 : 0, (Settings->shutter_options[i] & 4) ? 1 : 0, (Settings->shutter_options[i] & 8) ? 1 : 0, Shutter[i].motordelay); } else { // terminate loop at first INVALID Shutter[i]. @@ -395,7 +395,7 @@ void ShutterInit(void) Settings->shutter_accuracy = 1; Settings->shutter_mode = ShutterGlobal.position_mode; // initialize MotorStop time with 500ms if not set - Settings->shutter_motorstop = Settings->shutter_motorstop == 0?500:Settings->shutter_motorstop>60000?500:Settings->shutter_motorstop; + Settings->shutter_motorstop = (Settings->shutter_motorstop == 0) ? 500 : Settings->shutter_motorstop; } } @@ -410,7 +410,7 @@ void ShutterReportPosition(bool always, uint32_t index) shutter_running++; } } - + // Allow function exit if nothing to report (99.9% use case) if (!always && !shutter_running) return; @@ -422,7 +422,7 @@ void ShutterReportPosition(bool always, uint32_t index) } for (i; i < n; i++) { //AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Shtr%d Real Pos %d"), i+1,Shutter[i].real_position); - + if (Shutter[i].direction != 0) { ShutterLogPos(i); shutter_running++; @@ -588,7 +588,7 @@ void ShutterPowerOff(uint8_t i) void ShutterWaitForMotorStop(uint8_t index) { - Shutter[index-1].last_stop_time = millis(); + Shutter[index-1].last_stop_time = millis(); ShutterWaitForMotorStart(index); } @@ -597,7 +597,7 @@ void ShutterWaitForMotorStart(uint8_t index) while (millis() < Shutter[index-1].last_stop_time + Settings->shutter_motorstop) { loop(); } - //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Stoptime done")); + //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Stoptime done")); } void ShutterUpdatePosition(void) @@ -734,7 +734,7 @@ void ShutterStartInit(uint32_t i, int32_t direction, int32_t target_pos) } } //AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Start shtr%d from %d to %d in dir: %d"), i, Shutter[i].start_position, Shutter[i].target_position, direction); - + Shutter[i].direction = direction; // Last action. This causes RTC to start. } @@ -1416,7 +1416,7 @@ void CmndShutterRelay(void) } else { ShutterGlobal.RelayShutterMask ^= 3 << (Settings->shutter_startrelay[XdrvMailbox.index -1] - 1); } - AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: relold:%d index:%d, mode:%d, relaymask: %ld"), + AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: relold:%d index:%d, mode:%d, relaymask: %ld"), Settings->shutter_startrelay[XdrvMailbox.index -1] , XdrvMailbox.index ,Settings->shutter_mode, ShutterGlobal.RelayShutterMask ); if (Settings->shutter_startrelay[XdrvMailbox.index -1] == 0 && XdrvMailbox.index == 1 && Settings->shutter_mode == SHT_UNDEF) { // first shutter was not defined, maybe init From 8ffff8b85710084d6b2cc0c1ee3e3c18881b57ea Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Wed, 21 Dec 2022 17:22:54 +0100 Subject: [PATCH 033/262] Change Tasmota OTA scripts Change Tasmota OTA scripts now support both unzipped and gzipped file uploads (#17378) --- CHANGELOG.md | 1 + RELEASENOTES.md | 1 + api/upload-tasmota.php | 2 +- pio-tools/espupload.py | 24 +++++++++++++++++------- pio-tools/http-uploader.py | 31 +++++++++++++++++++++++-------- 5 files changed, 43 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f385b74bf..09444e224 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ All notable changes to this project will be documented in this file. ### Breaking Changed ### Changed +- Tasmota OTA scripts now support both unzipped and gzipped file uploads (#17378) ### Fixed - Shutter default motorstop set to 0 (#17403) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 1cc51965b..c0a162589 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -118,6 +118,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm ### Changed - ESP32 Framework (Core) from v2.0.5.3 to v2.0.5.4 (IPv6 support) - TuyaMcu rewrite by btsimonh [#17051](https://github.com/arendst/Tasmota/issues/17051) +- Tasmota OTA scripts now support both unzipped and gzipped file uploads [#17378](https://github.com/arendst/Tasmota/issues/17378) ### Fixed - Shutter default motorstop set to 0 [#17403](https://github.com/arendst/Tasmota/issues/17403) diff --git a/api/upload-tasmota.php b/api/upload-tasmota.php index 9bc204288..8b1504f95 100644 --- a/api/upload-tasmota.php +++ b/api/upload-tasmota.php @@ -42,7 +42,7 @@ $target_file = "tasmota/".$image; $hostname = $_SERVER['SERVER_NAME']; if (move_uploaded_file($_FILES["file"]["tmp_name"], $target_file)) { - if (strpos($target_file, "tasmota32")) { + if (strpos($target_file, "tasmota32") | strpos($target_file, ".gz")) { echo "The file $image has been uploaded to OTA server $hostname. \n"; } else { gzCompressFile($target_file); diff --git a/pio-tools/espupload.py b/pio-tools/espupload.py index fa93ba2bc..8b0993a55 100755 --- a/pio-tools/espupload.py +++ b/pio-tools/espupload.py @@ -36,7 +36,7 @@ import shutil import argparse import requests -#HOST_URL = "domus1:80/api/upload-arduino.php" +# Default URL overwritten by [env] and/or [env:tasmota32_base] upload_port HOST_URL = "otaserver/ota/upload-tasmota.php" def main(args): @@ -57,17 +57,27 @@ def main(args): # end if if not os.path.exists(args.image): - print('Sorry: the file %s does not exist', args.image) + print('Sorry: the file {} does not exist'.format(args.image)) return 2 # end if - # copy firmware.bin to tasmota.bin or tasmota32.bin - tname = os.path.normpath(os.path.dirname(args.image)) - new_filename = tname + os.sep + os.path.basename(tname) + '.bin' - shutil.copy2(args.image, new_filename) + if args.image.find("firmware.bin") != -1: + # Legacy support for $SOURCE + # copy firmware.bin to tasmota.bin or tasmota32.bin + # C:\tmp\.pioenvs\tasmota-theo\firmware.bin + tname = os.path.normpath(os.path.dirname(args.image)) + # C:\tmp\.pioenvs\tasmota-theo\tasmota-theo.bin + upload_file = tname + os.sep + os.path.basename(tname) + '.bin' + shutil.copy2(args.image, upload_file) + else: + # Support for bin_file and bin_gz_file + upload_file = args.image + # end if + +# print('Debug filename in {}, upload {}'.format(args.image, upload_file)) url = 'http://%s' % (args.host_url) - files = {'file': open(new_filename, 'rb')} + files = {'file': open(upload_file, 'rb')} req = requests.post(url, files=files) print(req.text) # end main diff --git a/pio-tools/http-uploader.py b/pio-tools/http-uploader.py index 788c886f2..fafbcfe03 100644 --- a/pio-tools/http-uploader.py +++ b/pio-tools/http-uploader.py @@ -1,13 +1,28 @@ +# Original idea by Pascal Gollor at 2022-12-13 + Import("env") import os +import tasmotapiolib -# pio < 4.0.0 -# from base64 import b64decode -# env.Replace(UPLOADER="pio-tools\espupload.py") -# env.Replace(UPLOADERFLAGS="") -# env.Replace(UPLOADCMD="$UPLOADER -u " + b64decode(ARGUMENTS.get("UPLOAD_PORT")) + " -f $SOURCES") +# You need to specify 'upload_port' in platform_override.ini at '[env]' section -# pio >= 4.0.0 -env.Replace(UPLOADER=os.path.join("pio-tools", "espupload.py")) +# clear upload flags env.Replace(UPLOADERFLAGS="") -env.Replace(UPLOADCMD="$PYTHONEXE $UPLOADER -u $UPLOAD_PORT -f $SOURCES") + +# Use espupload.py which supports both unzipped and zipped binaries +env.Replace(UPLOADER=os.path.join("pio-tools", "espupload.py")) + +# unzipped binary location: build_output\firmware\tasmota-theo.bin +bin_file = tasmotapiolib.get_final_bin_path(env) +# zipped binary location: build_output\firmware\tasmota-theo.bin.gz +bin_gz_file = bin_file.with_suffix(".bin.gz") + +if os.path.exists(bin_gz_file): + # Zipped binary file - build_output\firmware\tasmota-theo.bin.gz + env.Replace(UPLOADCMD="$PYTHONEXE $UPLOADER -u $UPLOAD_PORT -f {}".format(bin_gz_file)) +elif os.path.exists(bin_file): + # Unzipped binary file - build_output\firmware\tasmota-theo.bin + env.Replace(UPLOADCMD="$PYTHONEXE $UPLOADER -u $UPLOAD_PORT -f {}".format(bin_file)) +else: + # Unzipped binary file - C:\tmp\.pioenvs\tasmota-theo\firmware.bin + env.Replace(UPLOADCMD="$PYTHONEXE $UPLOADER -u $UPLOAD_PORT -f $SOURCES") From ad97f7b95f5771b9d0ed13e9c9d149bdf694536a Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Wed, 21 Dec 2022 18:11:35 +0100 Subject: [PATCH 034/262] Add NRG_MODBUS datatypes Add NRG_MODBUS datatypes (#17467) --- .../tasmota_xnrg_energy/xnrg_29_modbus.ino | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino b/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino index 7f155d7c2..220fe4b1c 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino @@ -44,6 +44,10 @@ * 2 = 4-byte signed * 3 = 2-byte unsigned * 4 = 4-byte unsigned + * 5 = not used + * 6 = 4-byte signed with swapped words + * 7 = not used + * 8 = 4-byte unsigned with swapped words * M - Divider allowing to devide the read register by 1, 10, 100, 1000 etc. - optional. default = 1 * Current - Current register entered as decimal or hexadecimal for one phase (0x0006) or up to three phases ([0x0006,0x0008,0x000A]) or * See additional defines like voltage. @@ -72,6 +76,10 @@ * 2 = 4-byte signed * 3 = 2-byte unsigned * 4 = 4-byte unsigned + * 5 = not used + * 6 = 4-byte signed with swapped words + * 7 = not used + * 8 = 4-byte unsigned with swapped words * M - Divider allowing to devide the read register by 1, 10, 100, 1000 etc. - optional. default = 1 * J - JSON register name (preferrably without spaces like "PhaseAngle") * G - GUI register name @@ -146,6 +154,10 @@ enum EnergyModbusDataType { NRG_DT_FLOAT, // 4-byte float NRG_DT_S32, // 4-byte signed NRG_DT_U16, // 2-byte unsigned NRG_DT_U32, // 4-byte unsigned + NRG_DT_x16_nu1, + NRG_DT_S32_SW, // 4-byte signed with swapped words + NRG_DT_x16_nu2, + NRG_DT_U32_SW, // 4-byte unsigned with swapped words NRG_DT_MAX }; enum EnergyModbusResolutions { NRG_RES_VOLTAGE = 21, // V @@ -289,11 +301,21 @@ void EnergyModbusLoop(void) { value = (float)value_buff; break; } + case NRG_DT_S32_SW: { + int32_t value_buff = ((int32_t)buffer[5])<<24 | ((uint32_t)buffer[6])<<16 | ((uint32_t)buffer[3])<<8 | buffer[4]; + value = (float)value_buff; + break; + } case NRG_DT_U32: { uint32_t value_buff = ((uint32_t)buffer[3])<<24 | ((uint32_t)buffer[4])<<16 | ((uint32_t)buffer[5])<<8 | buffer[6]; value = (float)value_buff; break; } + case NRG_DT_U32_SW: { + uint32_t value_buff = ((uint32_t)buffer[5])<<24 | ((uint32_t)buffer[6])<<16 | ((uint32_t)buffer[3])<<8 | buffer[4]; + value = (float)value_buff; + break; + } } value /= NrgMbsReg[NrgMbsParam.state].divider; From f06c07996ca6dd7c6441714782f44a974be8dae6 Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Thu, 22 Dec 2022 10:09:13 +0100 Subject: [PATCH 035/262] Berry crypto add ``EC_P256`` and ``PBKDF2_HMAC_SHA256`` algorithms required by Matter protocol (#17473) --- CHANGELOG.md | 1 + .../berry_mapping/src/be_const_members.c | 4 + .../berry_tasmota/src/be_crypto_lib.c | 73 +++- .../src/embedded/crypto_pbkdf2_hmac_sha256.be | 85 +++++ .../solidified_crypto_pbkdf2_hmac_sha256.h | 203 +++++++++++ tasmota/my_user_config.h | 4 +- .../xdrv_52_3_berry_crypto.ino | 343 ++++++++++++++---- 7 files changed, 645 insertions(+), 68 deletions(-) create mode 100644 lib/libesp32/berry_tasmota/src/embedded/crypto_pbkdf2_hmac_sha256.be create mode 100644 lib/libesp32/berry_tasmota/src/solidify/solidified_crypto_pbkdf2_hmac_sha256.h diff --git a/CHANGELOG.md b/CHANGELOG.md index 09444e224..21807b766 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file. ## [12.3.1.2] ### Added +- Berry crypto add ``EC_P256`` and ``PBKDF2_HMAC_SHA256`` algorithms required by Matter protocol ### Breaking Changed diff --git a/lib/libesp32/berry_mapping/src/be_const_members.c b/lib/libesp32/berry_mapping/src/be_const_members.c index 55baa634f..753f30940 100644 --- a/lib/libesp32/berry_mapping/src/be_const_members.c +++ b/lib/libesp32/berry_mapping/src/be_const_members.c @@ -38,6 +38,7 @@ * - `@func` Berry native function * - `*my_func` native function - the function is called and return value passed back. * This allows to create dynamic virtual members that are the result of a call. + * - `/my_class` a Berry class * * The array must be lexically sorted, but the sort function must ignore the prefix `$`, `&`, `*` \*********************************************************************************************/ @@ -63,6 +64,9 @@ static bbool be_const_member_dual(bvm *vm, const be_const_member_t * definitions case '&': // pointer be_pushcomptr(vm, (void*) definitions[idx].value); break; + case '/': + be_pushntvclass(vm, (const struct bclass*) definitions[idx].value); + break; case '*': // call to a native function { bntvfunc f = (bntvfunc) definitions[idx].value; diff --git a/lib/libesp32/berry_tasmota/src/be_crypto_lib.c b/lib/libesp32/berry_tasmota/src/be_crypto_lib.c index 083a846c9..d1e25392e 100644 --- a/lib/libesp32/berry_tasmota/src/be_crypto_lib.c +++ b/lib/libesp32/berry_tasmota/src/be_crypto_lib.c @@ -6,6 +6,9 @@ * Allows to respond to HTTP request *******************************************************************/ #include "be_constobj.h" +#include "be_mapping.h" + +extern int be_class_crypto_member(bvm *vm); extern int m_aes_gcm_init(bvm *vm); extern int m_aes_gcm_encryt(bvm *vm); @@ -16,6 +19,13 @@ extern int m_aes_ctr_init(bvm *vm); extern int m_aes_ctr_run(bvm *vm); extern int m_aes_ctr_tag(bvm *vm); +extern int m_ec_p256_pubkey(bvm *vm); +extern int m_ec_p256_sharedkey(bvm *vm); +extern int m_ec_p256_mod(bvm *vm); +extern int m_ec_p256_neg(bvm *vm); +extern int m_ec_p256_muladd(bvm *vm); +extern int m_ec_p256_mul(bvm *vm); + extern int m_ec_c25519_pubkey(bvm *vm); extern int m_ec_c25519_sharedkey(bvm *vm); @@ -27,15 +37,56 @@ extern int m_hmac_sha256_init(bvm *vm); extern int m_hmac_sha256_update(bvm *vm); extern int m_hmac_sha256_out(bvm *vm); +extern int m_pbkdf2_hmac_sha256_f(bvm *vm); + extern const bclass be_class_md5; +#include "solidify/solidified_crypto_pbkdf2_hmac_sha256.h" + #include "be_fixed_be_class_aes_gcm.h" #include "be_fixed_be_class_aes_ctr.h" +#include "be_fixed_be_class_ec_p256.h" #include "be_fixed_be_class_ec_c25519.h" #include "be_fixed_be_class_sha256.h" #include "be_fixed_be_class_hmac_sha256.h" +#include "be_fixed_be_class_pbkdf2_hmac_sha256.h" #include "be_fixed_crypto.h" +const be_const_member_t be_crypto_members[] = { + // name with prefix '/' indicates a Berry class +#ifdef USE_BERRY_CRYPTO_AES_CTR + { "/AES_CTR", (intptr_t) &be_class_aes_ctr }, +#endif // USE_BERRY_CRYPTO_AES_CTR + +#ifdef USE_BERRY_CRYPTO_AES_GCM + { "/AES_GCM", (intptr_t) &be_class_aes_gcm }, +#endif // USE_BERRY_CRYPTO_AES_GCM + +#ifdef USE_BERRY_CRYPTO_EC_C25519 + { "/EC_C25519", (intptr_t) &be_class_ec_c25519 }, +#endif // USE_BERRY_CRYPTO_EC_C25519 + +#ifdef USE_BERRY_CRYPTO_EC_P256 + { "/EC_P256", (intptr_t) &be_class_ec_p256 }, +#endif // USE_BERRY_CRYPTO_EC_P256 + +#ifdef USE_BERRY_CRYPTO_HMAC_SHA256 + { "/HMAC_SHA256", (intptr_t) &be_class_hmac_sha256 }, +#endif // USE_BERRY_CRYPTO_HMAC_SHA256 + + { "/MD5", (intptr_t) &be_class_md5 }, + +#ifdef USE_BERRY_CRYPTO_PBKDF2_HMAC_SHA256 + { "/PBKDF2_HMAC_SHA256", (intptr_t) &be_class_pbkdf2_hmac_sha256 }, +#endif // USE_BERRY_CRYPTO_PBKDF2_HMAC_SHA256 + +#ifdef USE_BERRY_CRYPTO_SHA256 + { "/SHA256", (intptr_t) &be_class_sha256 }, +#endif // USE_BERRY_CRYPTO_SHA256 +}; +const size_t be_crypto_members_size = sizeof(be_crypto_members)/sizeof(be_crypto_members[0]); + + /* @const_object_info_begin class be_class_aes_gcm (scope: global, name: AES_GCM) { @@ -56,6 +107,15 @@ class be_class_aes_ctr (scope: global, name: AES_CTR) { decrypt, func(m_aes_ctr_run) } +class be_class_ec_p256 (scope: global, name: EC_P256) { + public_key, static_func(m_ec_p256_pubkey) + shared_key, static_func(m_ec_p256_sharedkey) + mod, static_func(m_ec_p256_mod) + neg, static_func(m_ec_p256_neg) + muladd, static_func(m_ec_p256_muladd) + mul, static_func(m_ec_p256_mul) +} + class be_class_ec_c25519 (scope: global, name: EC_C25519) { public_key, func(m_ec_c25519_pubkey) shared_key, func(m_ec_c25519_sharedkey) @@ -77,13 +137,14 @@ class be_class_hmac_sha256 (scope: global, name: HMAC_SHA256) { out, func(m_hmac_sha256_out) } +class be_class_pbkdf2_hmac_sha256 (scope: global, name: PBKDF2_HMAC_SHA256) { + _f, static_func(m_pbkdf2_hmac_sha256_f) + //_f, static_closure(_f_closure) // this is the slow Berry reference version + derive, closure(PBKDF2_HMAC_SHA256_closure) +} + module crypto (scope: global) { - AES_GCM, class(be_class_aes_gcm) - AES_CTR, class(be_class_aes_ctr) - EC_C25519, class(be_class_ec_c25519) - SHA256, class(be_class_sha256) - HMAC_SHA256, class(be_class_hmac_sha256) - MD5, class(be_class_md5) + member, func(be_class_crypto_member) } @const_object_info_end */ diff --git a/lib/libesp32/berry_tasmota/src/embedded/crypto_pbkdf2_hmac_sha256.be b/lib/libesp32/berry_tasmota/src/embedded/crypto_pbkdf2_hmac_sha256.be new file mode 100644 index 000000000..9c28b52c9 --- /dev/null +++ b/lib/libesp32/berry_tasmota/src/embedded/crypto_pbkdf2_hmac_sha256.be @@ -0,0 +1,85 @@ +# crypto.PBKDF2_HMAC_SHA256 +# +# This crypto algorigthm is requires for device pre-provisioning +# +# The code below is slow and should only be used occasionally +# to pre-compute Matter Verifier + + +# unit step of PBKDF2 +# res is bytes(32) -- unchecked +#@ solidify:_f,weak +def _f(password, salt_i, c, res) + # xor in place for bytes a with b + def xor(a, b) + assert(a.size() == b.size()) + var len = a.size() + var i = 0 + while i < len + a[i] = a[i] ^ b[i] + i += 1 + end + end + + import crypto + # iteration 1 + var h = crypto.HMAC_SHA256(password) + h.update(salt_i) + var u = h.out() + res.setbytes(0, u) + + # iterate + var n = 2 + while n <= c + h = crypto.HMAC_SHA256(password) + h.update(u) + u = h.out() + xor(res, u) + n += 1 + tasmota.yield() + end +end + +#@ solidify:PBKDF2_HMAC_SHA256,weak +def PBKDF2_HMAC_SHA256(self, p, s, c, dklen) + if type(p) == 'string' p = bytes().fromstring(p) end + if type(s) == 'string' s = bytes().fromstring(s) end + var r = bytes() + var i = 1 + while r.size() < dklen + # compute salt_i as the ready to use salt+i + var salt_i = s.copy() + salt_i.add(i, -4) # 4 bytes Big Endian + var ri = bytes().resize(32) + self._f(p, salt_i, c, ri) + r += ri + i += 1 + end + return r[0..dklen-1] +end + +#- TEST VECTORS + +# https://github.com/brycx/Test-Vector-Generation/blob/master/PBKDF2/pbkdf2-hmac-sha2-test-vectors.md +import crypto +kd = crypto.PBKDF2_HMAC_SHA256() +print(kd.derive("password", "salt", 1, 20)) +# bytes('120FB6CFFCF8B32C43E7225256C4F837A86548C9') +# 120fb6cffcf8b32c43e7225256c4f837a86548c9 + +print(kd.derive("password", "salt", 2, 20)) +# bytes('AE4D0C95AF6B46D32D0ADFF928F06DD02A303F8E') +# ae4d0c95af6b46d32d0adff928f06dd02a303f8e + +print(kd.derive("password", "salt", 3, 20)) +# bytes('AD35240AC683FEBFAF3CD49D845473FBBBAA2437') +# ad35240ac683febfaf3cd49d845473fbbbaa2437 + +var now=tasmota.millis() +print(kd.derive("password", "salt", 4096, 20)) +print("Done in",tasmota.millis()-now,"ms") +# bytes('C5E478D59288C841AA530DB6845C4C8D962893A0') +# c5e478d59288c841aa530db6845c4c8d962893a0 +# Done in 205 ms + +-# diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_crypto_pbkdf2_hmac_sha256.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_crypto_pbkdf2_hmac_sha256.h new file mode 100644 index 000000000..365a97a07 --- /dev/null +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_crypto_pbkdf2_hmac_sha256.h @@ -0,0 +1,203 @@ +/* Solidification of crypto_pbkdf2_hmac_sha256.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +/******************************************************************** +** Solidified function: _f +********************************************************************/ +be_local_closure(_f, /* name */ + be_nested_proto( + 12, /* nstack */ + 4, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 1, /* has sup protos */ + ( &(const struct bproto*[ 1]) { + be_nested_proto( + 6, /* nstack */ + 2, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(size), + /* K1 */ be_const_int(0), + /* K2 */ be_const_int(1), + }), + be_str_weak(xor), + &be_const_str_solidified, + ( &(const binstruction[19]) { /* code */ + 0x60080000, // 0000 GETGBL R2 G0 + 0x8C0C0100, // 0001 GETMET R3 R0 K0 + 0x7C0C0200, // 0002 CALL R3 1 + 0x8C100300, // 0003 GETMET R4 R1 K0 + 0x7C100200, // 0004 CALL R4 1 + 0x1C0C0604, // 0005 EQ R3 R3 R4 + 0x7C080200, // 0006 CALL R2 1 + 0x8C080100, // 0007 GETMET R2 R0 K0 + 0x7C080200, // 0008 CALL R2 1 + 0x580C0001, // 0009 LDCONST R3 K1 + 0x14100602, // 000A LT R4 R3 R2 + 0x78120005, // 000B JMPF R4 #0012 + 0x94100003, // 000C GETIDX R4 R0 R3 + 0x94140203, // 000D GETIDX R5 R1 R3 + 0x34100805, // 000E XOR R4 R4 R5 + 0x98000604, // 000F SETIDX R0 R3 R4 + 0x000C0702, // 0010 ADD R3 R3 K2 + 0x7001FFF7, // 0011 JMP #000A + 0x80000000, // 0012 RET 0 + }) + ), + }), + 1, /* has constants */ + ( &(const bvalue[10]) { /* constants */ + /* K0 */ be_nested_str_weak(crypto), + /* K1 */ be_nested_str_weak(HMAC_SHA256), + /* K2 */ be_nested_str_weak(update), + /* K3 */ be_nested_str_weak(out), + /* K4 */ be_nested_str_weak(setbytes), + /* K5 */ be_const_int(0), + /* K6 */ be_const_int(2), + /* K7 */ be_const_int(1), + /* K8 */ be_nested_str_weak(tasmota), + /* K9 */ be_nested_str_weak(yield), + }), + be_str_weak(_f), + &be_const_str_solidified, + ( &(const binstruction[37]) { /* code */ + 0x84100000, // 0000 CLOSURE R4 P0 + 0xA4160000, // 0001 IMPORT R5 K0 + 0x8C180B01, // 0002 GETMET R6 R5 K1 + 0x5C200000, // 0003 MOVE R8 R0 + 0x7C180400, // 0004 CALL R6 2 + 0x8C1C0D02, // 0005 GETMET R7 R6 K2 + 0x5C240200, // 0006 MOVE R9 R1 + 0x7C1C0400, // 0007 CALL R7 2 + 0x8C1C0D03, // 0008 GETMET R7 R6 K3 + 0x7C1C0200, // 0009 CALL R7 1 + 0x8C200704, // 000A GETMET R8 R3 K4 + 0x58280005, // 000B LDCONST R10 K5 + 0x5C2C0E00, // 000C MOVE R11 R7 + 0x7C200600, // 000D CALL R8 3 + 0x58200006, // 000E LDCONST R8 K6 + 0x18241002, // 000F LE R9 R8 R2 + 0x78260012, // 0010 JMPF R9 #0024 + 0x8C240B01, // 0011 GETMET R9 R5 K1 + 0x5C2C0000, // 0012 MOVE R11 R0 + 0x7C240400, // 0013 CALL R9 2 + 0x5C181200, // 0014 MOVE R6 R9 + 0x8C240D02, // 0015 GETMET R9 R6 K2 + 0x5C2C0E00, // 0016 MOVE R11 R7 + 0x7C240400, // 0017 CALL R9 2 + 0x8C240D03, // 0018 GETMET R9 R6 K3 + 0x7C240200, // 0019 CALL R9 1 + 0x5C1C1200, // 001A MOVE R7 R9 + 0x5C240800, // 001B MOVE R9 R4 + 0x5C280600, // 001C MOVE R10 R3 + 0x5C2C0E00, // 001D MOVE R11 R7 + 0x7C240400, // 001E CALL R9 2 + 0x00201107, // 001F ADD R8 R8 K7 + 0xB8261000, // 0020 GETNGBL R9 K8 + 0x8C241309, // 0021 GETMET R9 R9 K9 + 0x7C240200, // 0022 CALL R9 1 + 0x7001FFEA, // 0023 JMP #000F + 0x80000000, // 0024 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: PBKDF2_HMAC_SHA256 +********************************************************************/ +be_local_closure(PBKDF2_HMAC_SHA256, /* name */ + be_nested_proto( + 15, /* nstack */ + 5, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 9]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(fromstring), + /* K2 */ be_const_int(1), + /* K3 */ be_nested_str_weak(size), + /* K4 */ be_nested_str_weak(copy), + /* K5 */ be_nested_str_weak(add), + /* K6 */ be_nested_str_weak(resize), + /* K7 */ be_nested_str_weak(_f), + /* K8 */ be_const_int(0), + }), + be_str_weak(PBKDF2_HMAC_SHA256), + &be_const_str_solidified, + ( &(const binstruction[53]) { /* code */ + 0x60140004, // 0000 GETGBL R5 G4 + 0x5C180200, // 0001 MOVE R6 R1 + 0x7C140200, // 0002 CALL R5 1 + 0x1C140B00, // 0003 EQ R5 R5 K0 + 0x78160005, // 0004 JMPF R5 #000B + 0x60140015, // 0005 GETGBL R5 G21 + 0x7C140000, // 0006 CALL R5 0 + 0x8C140B01, // 0007 GETMET R5 R5 K1 + 0x5C1C0200, // 0008 MOVE R7 R1 + 0x7C140400, // 0009 CALL R5 2 + 0x5C040A00, // 000A MOVE R1 R5 + 0x60140004, // 000B GETGBL R5 G4 + 0x5C180400, // 000C MOVE R6 R2 + 0x7C140200, // 000D CALL R5 1 + 0x1C140B00, // 000E EQ R5 R5 K0 + 0x78160005, // 000F JMPF R5 #0016 + 0x60140015, // 0010 GETGBL R5 G21 + 0x7C140000, // 0011 CALL R5 0 + 0x8C140B01, // 0012 GETMET R5 R5 K1 + 0x5C1C0400, // 0013 MOVE R7 R2 + 0x7C140400, // 0014 CALL R5 2 + 0x5C080A00, // 0015 MOVE R2 R5 + 0x60140015, // 0016 GETGBL R5 G21 + 0x7C140000, // 0017 CALL R5 0 + 0x58180002, // 0018 LDCONST R6 K2 + 0x8C1C0B03, // 0019 GETMET R7 R5 K3 + 0x7C1C0200, // 001A CALL R7 1 + 0x141C0E04, // 001B LT R7 R7 R4 + 0x781E0013, // 001C JMPF R7 #0031 + 0x8C1C0504, // 001D GETMET R7 R2 K4 + 0x7C1C0200, // 001E CALL R7 1 + 0x8C200F05, // 001F GETMET R8 R7 K5 + 0x5C280C00, // 0020 MOVE R10 R6 + 0x542DFFFB, // 0021 LDINT R11 -4 + 0x7C200600, // 0022 CALL R8 3 + 0x60200015, // 0023 GETGBL R8 G21 + 0x7C200000, // 0024 CALL R8 0 + 0x8C201106, // 0025 GETMET R8 R8 K6 + 0x542A001F, // 0026 LDINT R10 32 + 0x7C200400, // 0027 CALL R8 2 + 0x8C240107, // 0028 GETMET R9 R0 K7 + 0x5C2C0200, // 0029 MOVE R11 R1 + 0x5C300E00, // 002A MOVE R12 R7 + 0x5C340600, // 002B MOVE R13 R3 + 0x5C381000, // 002C MOVE R14 R8 + 0x7C240A00, // 002D CALL R9 5 + 0x00140A08, // 002E ADD R5 R5 R8 + 0x00180D02, // 002F ADD R6 R6 K2 + 0x7001FFE7, // 0030 JMP #0019 + 0x041C0902, // 0031 SUB R7 R4 K2 + 0x401E1007, // 0032 CONNECT R7 K8 R7 + 0x941C0A07, // 0033 GETIDX R7 R5 R7 + 0x80040E00, // 0034 RET 1 R7 + }) + ) +); +/*******************************************************************/ + +/********************************************************************/ +/* End of solidification */ diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index 3b147cce7..ff9b1c9a9 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -1106,10 +1106,12 @@ // #define USE_BERRY_ULP // Enable ULP (Ultra Low Power) support (+4.9k) // Berry crypto extensions below: #define USE_BERRY_CRYPTO_AES_GCM // enable AES GCM 256 bits - #define USE_BERRY_CRYPTO_AES_CTR // enable AEC CTR 256 bits + // #define USE_BERRY_CRYPTO_AES_CTR // enable AEC CTR 256 bits + // #define USE_BERRY_CRYPTO_EC_P256 // enable EC P256r1 // #define USE_BERRY_CRYPTO_EC_C25519 // enable Elliptic Curve C C25519 #define USE_BERRY_CRYPTO_SHA256 // enable SHA256 hash function #define USE_BERRY_CRYPTO_HMAC_SHA256 // enable HMAC SHA256 hash function + // #define USE_BERRY_CRYPTO_PBKDF2_HMAC_SHA256 // PBKDF2 with HMAC SHA256, used in Matter protocol #define USE_CSE7761 // Add support for CSE7761 Energy monitor as used in Sonoff Dual R3 // -- LVGL Graphics Library --------------------------------- diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino index 8f5e3613e..21f1553b4 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino @@ -24,6 +24,21 @@ #include "be_mem.h" #include "be_object.h" +/*********************************************************************************************\ + * members class + * +\*********************************************************************************************/ +extern "C" { + extern const be_const_member_t be_crypto_members[]; + extern const size_t be_crypto_members_size; + // virtual member + int be_class_crypto_member(bvm *vm); + int be_class_crypto_member(bvm *vm) { + be_const_module_member_raise(vm, be_crypto_members, be_crypto_members_size); + be_return(vm); + } +} + /*********************************************************************************************\ * AES_GCM class * @@ -33,7 +48,6 @@ extern "C" { // `AES_GCM.init(secret_key:bytes(32), iv:bytes(12)) -> instance` int32_t m_aes_gcm_init(struct bvm *vm); int32_t m_aes_gcm_init(struct bvm *vm) { -#ifdef USE_BERRY_CRYPTO_AES_GCM int32_t argc = be_top(vm); // Get the number of arguments if (argc >= 3 && be_isinstance(vm, 2) && be_isinstance(vm, 3)) { do { @@ -77,15 +91,11 @@ extern "C" { } while (0); } be_raise(vm, kTypeError, nullptr); -#else // USE_BERRY_CRYPTO_AES_GCM - be_raise(vm, "Not implemented", nullptr); -#endif // USE_BERRY_CRYPTO_AES_GCM } int32_t m_aes_gcm_encryt(bvm *vm); int32_t m_aes_gcm_decryt(bvm *vm); int32_t m_aes_gcm_encrypt_or_decryt(bvm *vm, int encrypt) { -#ifdef USE_BERRY_CRYPTO_AES_GCM int32_t argc = be_top(vm); // Get the number of arguments if (argc >= 2 && be_isinstance(vm, 2)) { do { @@ -115,27 +125,15 @@ extern "C" { } while (0); } be_raise(vm, kTypeError, nullptr); -#else // USE_BERRY_CRYPTO_AES_GCM - be_raise(vm, "Not implemented", nullptr); -#endif // USE_BERRY_CRYPTO_AES_GCM } int32_t m_aes_gcm_encryt(bvm *vm) { -#ifdef USE_BERRY_CRYPTO_AES_GCM return m_aes_gcm_encrypt_or_decryt(vm, 1); -#else // USE_BERRY_CRYPTO_AES_GCM - be_raise(vm, "Not implemented", nullptr); -#endif // USE_BERRY_CRYPTO_AES_GCM } int32_t m_aes_gcm_decryt(bvm *vm) { -#ifdef USE_BERRY_CRYPTO_AES_GCM return m_aes_gcm_encrypt_or_decryt(vm, 0); -#else // USE_BERRY_CRYPTO_AES_GCM - be_raise(vm, "Not implemented", nullptr); -#endif // USE_BERRY_CRYPTO_AES_GCM } int32_t m_aes_gcm_tag(bvm *vm) { -#ifdef USE_BERRY_CRYPTO_AES_GCM do { be_getglobal(vm, "bytes"); /* get the bytes class */ /* TODO eventually replace with be_getbuiltin */ @@ -153,9 +151,6 @@ extern "C" { // success } while (0); be_raise(vm, kTypeError, nullptr); -#else // USE_BERRY_CRYPTO_AES_GCM - be_raise(vm, "Not implemented", nullptr); -#endif // USE_BERRY_CRYPTO_AES_GCM } } @@ -168,7 +163,6 @@ extern "C" { // `AES_CTR.init(secret_key:bytes(32)) -> instance` int32_t m_aes_ctr_init(struct bvm *vm); int32_t m_aes_ctr_init(struct bvm *vm) { -#ifdef USE_BERRY_CRYPTO_AES_CTR int32_t argc = be_top(vm); // Get the number of arguments if (argc >= 2 && be_isbytes(vm, 2)) { do { @@ -191,16 +185,12 @@ extern "C" { } while (0); } be_raise(vm, kTypeError, nullptr); -#else // USE_BERRY_CRYPTO_AES_CTR - be_raise(vm, "Not implemented", nullptr); -#endif // USE_BERRY_CRYPTO_AES_CTR } // `.encrypt(content:bytes(), in:bytes(12), counter:int) -> nil` // `.decrypt(content:bytes(), in:bytes(12), counter:int) -> nil` int32_t m_aes_ctr_run(bvm *vm); int32_t m_aes_ctr_run(bvm *vm) { -#ifdef USE_BERRY_CRYPTO_AES_CTR int32_t argc = be_top(vm); // Get the number of arguments if (argc >= 4 && be_isbytes(vm, 2) && be_isbytes(vm, 3) && be_isint(vm, 4)) { do { @@ -233,9 +223,6 @@ extern "C" { } while (0); } be_raise(vm, kTypeError, nullptr); -#else // USE_BERRY_CRYPTO_AES_CTR - be_raise(vm, "Not implemented", nullptr); -#endif // USE_BERRY_CRYPTO_AES_CTR } } @@ -248,7 +235,6 @@ extern "C" { // `SHA256.init() -> nil` int32_t m_hash_sha256_init(struct bvm *vm); int32_t m_hash_sha256_init(struct bvm *vm) { -#ifdef USE_BERRY_CRYPTO_SHA256 // Initialize a SHA256 context br_sha256_context * ctx = (br_sha256_context *) be_os_malloc(sizeof(br_sha256_context)); if (!ctx) { @@ -259,9 +245,6 @@ extern "C" { be_newcomobj(vm, ctx, &be_commonobj_destroy_generic); be_setmember(vm, 1, ".p"); be_return_nil(vm); -#else // USE_BERRY_CRYPTO_SHA256 - be_raise(vm, "Not implemented", nullptr); -#endif // USE_BERRY_CRYPTO_SHA256 } // `.update(content:bytes()) -> nil` @@ -269,7 +252,6 @@ extern "C" { // Add raw bytes to the hash calculation int32_t m_hash_sha256_update(struct bvm *vm); int32_t m_hash_sha256_update(struct bvm *vm) { -#ifdef USE_BERRY_CRYPTO_SHA256 int32_t argc = be_top(vm); // Get the number of arguments if (argc >= 2 && be_isinstance(vm, 2)) { do { @@ -292,9 +274,6 @@ extern "C" { } while (0); } be_raise(vm, "value_error", NULL); -#else // USE_BERRY_CRYPTO_SHA256 - be_raise(vm, "Not implemented", nullptr); -#endif // USE_BERRY_CRYPTO_SHA256 } // `.finish() -> bytes()` @@ -302,7 +281,6 @@ extern "C" { // Add raw bytes to the MD5 calculation int32_t m_hash_sha256_out(struct bvm *vm); int32_t m_hash_sha256_out(struct bvm *vm) { -#ifdef USE_BERRY_CRYPTO_SHA256 be_getmember(vm, 1, ".p"); br_sha256_context * ctx; ctx = (br_sha256_context *) be_tocomptr(vm, -1); @@ -311,9 +289,6 @@ extern "C" { br_sha256_out(ctx, output); be_pushbytes(vm, output, sizeof(output)); be_return(vm); -#else // USE_BERRY_CRYPTO_SHA256 - be_raise(vm, "Not implemented", nullptr); -#endif // USE_BERRY_CRYPTO_SHA256 } } @@ -326,7 +301,6 @@ extern "C" { // `HMAC_SHA256.init(key:bytes) -> nil` int32_t m_hmac_sha256_init(struct bvm *vm); int32_t m_hmac_sha256_init(struct bvm *vm) { -#ifdef USE_BERRY_CRYPTO_HMAC_SHA256 int32_t argc = be_top(vm); // Get the number of arguments if (argc >= 2 && be_isbytes(vm, 2)) { // Initialize a HMAC context @@ -345,9 +319,6 @@ extern "C" { be_return_nil(vm); } be_raise(vm, kTypeError, nullptr); -#else // USE_BERRY_CRYPTO_HMAC_SHA256 - be_raise(vm, "Not implemented", nullptr); -#endif // USE_BERRY_CRYPTO_HMAC_SHA256 } // `.update(content:bytes()) -> nil` @@ -355,7 +326,6 @@ extern "C" { // Add raw bytes to the hash calculation int32_t m_hmac_sha256_update(struct bvm *vm); int32_t m_hmac_sha256_update(struct bvm *vm) { -#ifdef USE_BERRY_CRYPTO_HMAC_SHA256 int32_t argc = be_top(vm); // Get the number of arguments if (argc >= 2 && be_isinstance(vm, 2)) { do { @@ -377,9 +347,6 @@ extern "C" { } while (0); } be_raise(vm, "value_error", NULL); -#else // USE_BERRY_CRYPTO_HMAC_SHA256 - be_raise(vm, "Not implemented", nullptr); -#endif // USE_BERRY_CRYPTO_HMAC_SHA256 } // `.finish() -> bytes()` @@ -387,7 +354,6 @@ extern "C" { // Add raw bytes to the MD5 calculation int32_t m_hmac_sha256_out(struct bvm *vm); int32_t m_hmac_sha256_out(struct bvm *vm) { -#ifdef USE_BERRY_CRYPTO_HMAC_SHA256 be_getmember(vm, 1, ".p"); br_hmac_context * ctx; ctx = (br_hmac_context *) be_tocomptr(vm, -1); @@ -396,9 +362,221 @@ extern "C" { br_hmac_out(ctx, output); be_pushbytes(vm, output, sizeof(output)); be_return(vm); -#else // USE_BERRY_CRYPTO_HMAC_SHA256 - be_raise(vm, "Not implemented", nullptr); -#endif // USE_BERRY_CRYPTO_HMAC_SHA256 + } +} + +/*********************************************************************************************\ + * EC_P256 class + * +\*********************************************************************************************/ +#define BR_EC_P256_IMPL br_ec_p256_m15 // BearSSL implementation for Curve P256 +extern "C" { + // crypto.EC_P256().public_key(private_key:bytes(32)) -> bytes(32) + // Computes the public key from a completely random private key of 32 bytes + int32_t m_ec_p256_pubkey(bvm *vm); + int32_t m_ec_p256_pubkey(bvm *vm) { + int32_t argc = be_top(vm); // Get the number of arguments + if (argc >= 1 && be_isbytes(vm, 1)) { + size_t sk_len = 0; + uint8_t * sk = (uint8_t*) be_tobytes(vm, 1, &sk_len); + if (sk_len == 32) { + br_ec_private_key br_sk = { BR_EC_secp256r1, sk, 32 }; // TODO + + uint8_t pk_buf[80]; + size_t ret = br_ec_compute_pub(&BR_EC_P256_IMPL, nullptr, pk_buf, &br_sk); + if (ret > 0) { + be_pushbytes(vm, pk_buf, ret); + be_return(vm); + } + } + be_raise(vm, "value_error", "invalid input"); + } + be_raise(vm, kTypeError, nullptr); + } + + // crypto.EC_P256().shared_key(my_private_key:bytes(32), their_public_key:bytes(32)) -> bytes(32) + // Computes the shared pre-key. Normally this shared pre-key is hashed with another algorithm. + int32_t m_ec_p256_sharedkey(bvm *vm); + int32_t m_ec_p256_sharedkey(bvm *vm) { + int32_t argc = be_top(vm); // Get the number of arguments + if (argc >= 2 && be_isbytes(vm, 1) && be_isbytes(vm, 2)) { + size_t sk_len = 0; + const uint8_t * sk = (const uint8_t*) be_tobytes(vm, 1, &sk_len); + size_t pk_len = 0; + const uint8_t * pk_const = (const uint8_t*) be_tobytes(vm, 2, &pk_len); + if (sk_len != 32 || pk_len == 0 || pk_len > 65) { + be_raise(vm, "value_error", "Key size invalid"); + } + uint8_t pk[pk_len]; + memmove(pk, pk_const, pk_len); /* copy to a non-const variable to receive the result */ + + if (BR_EC_P256_IMPL.mul(pk, pk_len, sk, sk_len, BR_EC_secp256r1)) { + /* return value (xoff is one, length is 32) */ + be_pushbytes(vm, pk + 1, 32); + be_return(vm); + } else { + be_raise(vm, "internal_error", "internal bearssl error in mul()"); + } + be_raise(vm, "value_error", "invalid input"); + } + be_raise(vm, kTypeError, nullptr); + } + + // We have generated the P256 order as a i15 encoding using + // static const unsigned char P256_N[] PROGMEM = { + // 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + // 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + // 0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84, + // 0xF3, 0xB9, 0xCA, 0xC2^, 0xFC, 0x63, 0x25, 0x51 + // }; + // uint16_t m[20] = {}; + // br_i15_decode(m, P256_N, sizeof(P256_N)); + // AddLog(LOG_LEVEL_INFO, ">>>: mod=%*_H", sizeof(m), m); + // 11015125C6780B2BCE1D4F68F362692B7D73BC7FFF7FFF7FFF7FFF0F00000040FF7FFF7F0100 + + // N=bytes('11015125C6780B2BCE1D4F68F362692B7D73BC7FFF7FFF7FFF7FFF0F00000040FF7FFF7F0100') + // import string + // s = '' + // while size(N) > 0 + // var n = N.get(0, 2) + // s += string.format("0x%04X, ", n) + // N = N[2..] + // end + // print(s) + static const uint16_t P256_N_I15[] PROGMEM = { + 0x0111, + 0x2551, 0x78C6, 0x2B0B, 0x1DCE, 0x684F, 0x62F3, 0x2B69, 0x737D, + 0x7FBC, 0x7FFF, 0x7FFF, 0x7FFF, 0x0FFF, 0x0000, 0x4000, 0x7FFF, + 0x7FFF, 0x0001, + }; + extern void br_i15_decode(uint16_t *x, const void *src, size_t len); + extern void br_i15_decode_reduce(uint16_t *x, const void *src, size_t len, const uint16_t *m); + extern void br_i15_encode(void *dst, size_t len, const uint16_t *x); + extern uint32_t br_i15_sub(uint16_t *a, const uint16_t *b, uint32_t ctl); + // crypto.EC_P256().mod(data:bytes()) -> bytes(32) + // Reduces the big int to the modulus of P256 curve + int32_t m_ec_p256_mod(bvm *vm); + int32_t m_ec_p256_mod(bvm *vm) { + int32_t argc = be_top(vm); // Get the number of arguments + if (argc >= 1 && be_isbytes(vm, 1)) { + size_t data_len = 0; + uint8_t * data = (uint8_t*) be_tobytes(vm, 1, &data_len); + if (data_len == 0) { be_raise(vm, "value_error", "data must not be empty"); } + + uint16_t data0[20] = {}; + br_i15_decode_reduce(data0, data, data_len, P256_N_I15); + // AddLog(LOG_LEVEL_INFO, ">>>: data0=%*_H", sizeof(data0), data0); + + uint8_t out[32] = {}; + br_i15_encode(out, sizeof(out), data0); + // AddLog(LOG_LEVEL_INFO, ">>>: out=%*_H", sizeof(out), out); + // void br_i15_encode(void *dst, size_t len, const uint16_t *x); + + be_pushbytes(vm, out, sizeof(out)); + be_return(vm); + } + be_raise(vm, kTypeError, nullptr); + } + + // crypto.EC_P256().neg(data:bytes(32)) -> bytes(32) + // Negate a point coordinate modulus the order + int32_t m_ec_p256_neg(bvm *vm); + int32_t m_ec_p256_neg(bvm *vm) { + int32_t argc = be_top(vm); // Get the number of arguments + if (argc >= 1 && be_isbytes(vm, 1)) { + size_t data_len = 0; + uint8_t * data = (uint8_t*) be_tobytes(vm, 1, &data_len); + if (data_len == 0) { be_raise(vm, "value_error", "data must not be empty"); } + + uint16_t data0[20] = {}; + br_i15_decode_reduce(data0, data, data_len, P256_N_I15); + // AddLog(LOG_LEVEL_INFO, ">>>: data0=%*_H", sizeof(data0), data0); + + uint16_t a[sizeof(P256_N_I15)/sizeof(uint16_t)]; + memcpy(a, P256_N_I15, sizeof(P256_N_I15)); // copy generator to a + + uint32_t carry = br_i15_sub(a, data0, 1); // carry is always zero since the number if taken modulus the generator + // AddLog(LOG_LEVEL_INFO, ">>>: carry=%i data0=%*_H", carry, sizeof(data0), data0); + + uint8_t out[32] = {}; + br_i15_encode(out, sizeof(out), a); + // AddLog(LOG_LEVEL_INFO, ">>>: out=%*_H", sizeof(out), out); + // void br_i15_encode(void *dst, size_t len, const uint16_t *x); + + be_pushbytes(vm, out, sizeof(out)); + be_return(vm); + } + be_raise(vm, kTypeError, nullptr); + } + + uint32_t (*muladd)(unsigned char *A, const unsigned char *B, size_t len, + const unsigned char *x, size_t xlen, + const unsigned char *y, size_t ylen, int curve); + + // crypto.EC_P256().mul(x:bytes(), A:bytes(65)) -> bytes(65)` + // + // The point `x*A` is computed. + // `x` is unsigned and MUST be lower than order (use mod if not sure) + // `A` must be bytes(65) and unencoded (starting with 0x04) + int32_t m_ec_p256_mul(bvm *vm); + int32_t m_ec_p256_mul(bvm *vm) { + int32_t argc = be_top(vm); // Get the number of arguments + if (argc >= 2 && be_isbytes(vm, 1) && be_isbytes(vm, 2)) { + size_t x_len = 0; + const uint8_t * x = (const uint8_t*) be_tobytes(vm, 1, &x_len); + if (x_len == 0) { be_raise(vm, "value_error", "x must not be empty"); } + + size_t A_len = 0; + const uint8_t * A = (const uint8_t*) be_tobytes(vm, 2, &A_len); + if (A_len != 65 || (A_len > 0 && A[0] != 0x04)) { be_raise(vm, "value_error", "invalid A point"); } + + uint8_t res[65]; + memcpy(res, A, sizeof(res)); // copy A to res which will hold the result + uint32_t ret = BR_EC_P256_IMPL.mul(res, 65, x, x_len, BR_EC_secp256r1); + if (ret == 0) { be_raise(vm, "value_error", "muladd failed"); } + + be_pushbytes(vm, res, sizeof(res)); + be_return(vm); + } + be_raise(vm, kTypeError, nullptr); + } + // crypto.EC_P256().muladd(x:bytes(), A:bytes(65), y:bytes(), B;bytes(65) or bytes(0)) -> bytes(65)` + // + // The point `x*A + y*B` is computed. + // If `B` is empty, the Generator is taken instead. + // `x` and `y` are unsigned and MUST be lower than order (use mod if not sure) + // `A` and `B` must be bytes(65) and unencoded (starting with 0x04) + int32_t m_ec_p256_muladd(bvm *vm); + int32_t m_ec_p256_muladd(bvm *vm) { + int32_t argc = be_top(vm); // Get the number of arguments + if (argc >= 4 && be_isbytes(vm, 1) && be_isbytes(vm, 2) && be_isbytes(vm, 3) && be_isbytes(vm, 4)) { + size_t x_len = 0; + const uint8_t * x = (const uint8_t*) be_tobytes(vm, 1, &x_len); + if (x_len == 0) { be_raise(vm, "value_error", "x must not be empty"); } + size_t y_len = 0; + const uint8_t * y = (const uint8_t*) be_tobytes(vm, 3, &y_len); + if (y_len == 0) { be_raise(vm, "value_error", "y must not be empty"); } + + size_t A_len = 0; + const uint8_t * A = (const uint8_t*) be_tobytes(vm, 2, &A_len); + if (A_len != 65 || (A_len > 0 && A[0] != 0x04)) { be_raise(vm, "value_error", "invalid A point"); } + size_t B_len = 0; + const uint8_t * B = (const uint8_t*) be_tobytes(vm, 4, &B_len); + if (B_len == 0) { + B = nullptr; // generator + } else { + if (B_len != 65 || (B_len > 0 && B[0] != 0x04)) { be_raise(vm, "value_error", "invalid A point"); } + } + + uint8_t res[65]; + memcpy(res, A, sizeof(res)); // copy A to res which will hold the result + uint32_t ret = BR_EC_P256_IMPL.muladd(res, B, 65, x, x_len, y, y_len, BR_EC_secp256r1); + if (ret == 0) { be_raise(vm, "value_error", "muladd failed"); } + + be_pushbytes(vm, res, sizeof(res)); + be_return(vm); + } + be_raise(vm, kTypeError, nullptr); } } @@ -413,7 +591,6 @@ extern "C" { // Computes the public key from a completely random private key of 32 bytes int32_t m_ec_c25519_pubkey(bvm *vm); int32_t m_ec_c25519_pubkey(bvm *vm) { -#ifdef USE_BERRY_CRYPTO_EC_C25519 int32_t argc = be_top(vm); // Get the number of arguments if (argc >= 2 && be_isbytes(vm, 2)) { size_t buf_len = 0; @@ -436,16 +613,12 @@ extern "C" { be_raise(vm, "value_error", "invalid input"); } be_raise(vm, kTypeError, nullptr); -#else // USE_BERRY_CRYPTO_EC_C25519 - be_raise(vm, "Not implemented", nullptr); -#endif // USE_BERRY_CRYPTO_EC_C25519 } // crypto.EC_C25519().shared_key(my_private_key:bytes(32), their_public_key:bytes(32)) -> bytes(32) // Computes the shared pre-key. Normally this shared pre-key is hashed with another algorithm. int32_t m_ec_c25519_sharedkey(bvm *vm); int32_t m_ec_c25519_sharedkey(bvm *vm) { -#ifdef USE_BERRY_CRYPTO_EC_C25519 int32_t argc = be_top(vm); // Get the number of arguments if (argc >= 3 && be_isbytes(vm, 2) && be_isbytes(vm, 3)) { size_t sk_len = 0; @@ -465,16 +638,64 @@ extern "C" { be_pushbytes(vm, pk, pk_len); be_return(vm); } else { - be_raise(vm, "internal_error", "internal bearssl error in 519_m15.mul()"); + be_raise(vm, "internal_error", "internal bearssl error in mul()"); } } be_raise(vm, "value_error", "invalid input"); } be_raise(vm, kTypeError, nullptr); -#else // USE_BERRY_CRYPTO_EC_C25519 - be_raise(vm, "Not implemented", nullptr); -#endif // USE_BERRY_CRYPTO_EC_C25519 } } +/*********************************************************************************************\ + * PBKDF2_HMAC_SHA256 + * + * accelerate _f function +\*********************************************************************************************/ +extern "C" { + // _f(password:bytes(), salt_i:bytes(), c:int, res:bytes(32)) -> nil + int32_t m_pbkdf2_hmac_sha256_f(bvm *vm); + int32_t m_pbkdf2_hmac_sha256_f(bvm *vm) { + int32_t argc = be_top(vm); // Get the number of arguments + if (argc >= 4 && be_isbytes(vm, 1) && be_isbytes(vm, 2) && be_isint(vm, 3) && be_isbytes(vm, 4)) { + size_t passwd_len; + const void * passwd = be_tobytes(vm, 1, &passwd_len); + if (passwd_len == 0) { be_raise(vm, "value_error", "passwd must not be empty"); } + + size_t salt_len; + const void * salt = be_tobytes(vm, 2, &salt_len); + if (salt_len == 0) { be_raise(vm, "value_error", "salt must not be empty"); } + + int32_t count = be_toint(vm, 3); + if (count < 1 || count > 10000) { be_raise(vm, "value_error", "invalid iterations number"); } + + size_t res_len; + uint8_t * res = (uint8_t*) be_tobytes(vm, 4, &res_len); + if (res_len != 32) { be_raise(vm, "value_error", "res must be 32 bytes"); } + + br_hmac_context ctx; + br_hmac_key_context keyCtx; // keyCtx can be allocated on stack, it is not needed after `br_hmac_init` + br_hmac_key_init(&keyCtx, &br_sha256_vtable, passwd, passwd_len); + br_hmac_init(&ctx, &keyCtx, 0); // 0 is "natural output length" + + // iteration 1 + br_hmac_update(&ctx, salt, salt_len); + br_hmac_out(&ctx, res); + uint8_t u[32]; // rolling buffer + memcpy(u, res, 32); // copy res into u + + // further iterations + for (uint32_t i = 2; i <= count; i++) { + br_hmac_init(&ctx, &keyCtx, 0); // reinit HMAC + br_hmac_update(&ctx, u, sizeof(u)); + br_hmac_out(&ctx, u); + for (uint32_t j=0; j<32; j++) { + res[j] = res[j] ^ u[j]; + } + } + be_return_nil(vm); + } + be_raise(vm, kTypeError, nullptr); + } +} #endif // USE_BERRY From 163456c3fc37f46f3b28e3a52fb2e290d2918bad Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Thu, 22 Dec 2022 11:12:45 +0100 Subject: [PATCH 036/262] Pio: Target: Erase and Upload (#17474) --- platformio.ini | 2 +- platformio_tasmota32.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio.ini b/platformio.ini index 9344e7254..cdd096875 100644 --- a/platformio.ini +++ b/platformio.ini @@ -111,7 +111,7 @@ build_flags = ${esp_defaults.build_flags} [core] ; *** Esp8266 Tasmota modified Arduino core based on core 2.7.4. Added Backport for PWM selection -platform = https://github.com/tasmota/platform-espressif8266/releases/download/v2.7.4/platform-espressif8266-2.7.4.zip +platform = https://github.com/tasmota/platform-espressif8266/releases/download/2022.12.0/platform-espressif8266.zip platform_packages = build_unflags = ${esp_defaults.build_unflags} build_flags = ${esp82xx_defaults.build_flags} diff --git a/platformio_tasmota32.ini b/platformio_tasmota32.ini index f14fe7d74..a654964ce 100644 --- a/platformio_tasmota32.ini +++ b/platformio_tasmota32.ini @@ -42,7 +42,7 @@ extra_scripts = pre:pio-tools/add_c_flags.py ${esp_defaults.extra_scripts} [core32] -platform = https://github.com/tasmota/platform-espressif32/releases/download/2022.12.0/platform-espressif32.zip +platform = https://github.com/tasmota/platform-espressif32/releases/download/2022.12.1/platform-espressif32.zip platform_packages = build_unflags = ${esp32_defaults.build_unflags} build_flags = ${esp32_defaults.build_flags} From b3f12476ccc06440b55570225af555049f2b7638 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Thu, 22 Dec 2022 16:09:41 +0100 Subject: [PATCH 037/262] Remove debug logging --- tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino b/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino index 065cabc5e..46322656b 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino @@ -1110,13 +1110,13 @@ void EnergySnsInit(void) XnrgCall(FUNC_INIT); if (TasmotaGlobal.energy_driver) { - +/* AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Rtc valid %d, kWhtoday_ph Rtc %d/%d/%d, Set %d/%d/%d"), RtcSettingsValid(), RtcSettings.energy_kWhtoday_ph[0],RtcSettings.energy_kWhtoday_ph[1],RtcSettings.energy_kWhtoday_ph[2], Settings->energy_kWhtoday_ph[0],Settings->energy_kWhtoday_ph[1],Settings->energy_kWhtoday_ph[2] ); - +*/ for (uint32_t i = 0; i < 3; i++) { // Energy.kWhtoday_offset[i] = 0; // Reset by EnergyDrvInit() // 20220805 - Change from https://github.com/arendst/Tasmota/issues/16118 From 3c1531bf1cf5de447b0d4b7235547c4d99a341fb Mon Sep 17 00:00:00 2001 From: stefanbode Date: Thu, 22 Dec 2022 17:02:01 +0100 Subject: [PATCH 038/262] shuttermotorstop init value, new max 5000 (#17484) new max value (5 seconds) shuttertilt logic check (avoid Theo's indefinite running shutter) --- tasmota/tasmota_xdrv_driver/xdrv_27_shutter.ino | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_27_shutter.ino b/tasmota/tasmota_xdrv_driver/xdrv_27_shutter.ino index 198a13dea..fa4c6b1e2 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_27_shutter.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_27_shutter.ino @@ -110,8 +110,8 @@ struct SHUTTER { uint16_t venetian_delay = 0; // Delay in steps before venetian shutter start physical moving. Based on tilt position uint16_t min_realPositionChange = 0; // minimum change of the position before the shutter operates. different for PWM and time based operations uint16_t min_TiltChange = 0; // minimum change of the tilt before the shutter operates. different for PWM and time based operations - uint16_t last_reported_time =0; - uint32_t last_stop_time = 0; // record the last time the relay was switched off + uint16_t last_reported_time = 0; // get information on skipped 50ms loop() slots + uint32_t last_stop_time = 0; // record the last time the relay was switched off } Shutter[MAX_SHUTTERS]; struct SHUTTERGLOBAL { @@ -351,9 +351,16 @@ void ShutterInit(void) Shutter[i].lastdirection = (50 < Settings->shutter_position[i]) ? 1 : -1; // Venetian Blind + // ensure min is smaller than max + Settings->shutter_tilt_config[2][i] = Settings->shutter_tilt_config[0][i] >= Settings->shutter_tilt_config[1][i]?0:Settings->shutter_tilt_config[2][i]; + //copy config to shutter for (uint8_t k=0; k<5; k++) { Shutter[i].tilt_config[k] = Settings->shutter_tilt_config[k][i]; } + // wipe open/close position if duration is 0 + if (Shutter[i].tilt_config[2]==0) { + Shutter[i].tilt_config[3] = Shutter[i].tilt_config[4] = 0; + } Shutter[i].tilt_target_pos = Shutter[i].tilt_real_pos = Settings->shutter_tilt_pos[i]; Shutter[i].tilt_velocity = Shutter[i].tilt_config[2] > 0 ? ((Shutter[i].tilt_config[1]-Shutter[i].tilt_config[0])/Shutter[i].tilt_config[2])+1 : 1; @@ -395,7 +402,7 @@ void ShutterInit(void) Settings->shutter_accuracy = 1; Settings->shutter_mode = ShutterGlobal.position_mode; // initialize MotorStop time with 500ms if not set - Settings->shutter_motorstop = (Settings->shutter_motorstop == 0) ? 500 : Settings->shutter_motorstop; + Settings->shutter_motorstop = (Settings->shutter_motorstop == 0) ? 500 : tmin(5000,Settings->shutter_motorstop); } } @@ -1776,6 +1783,7 @@ void CmndShutterMotorStop(void) if (!XdrvMailbox.usridx) { if ((XdrvMailbox.payload >= 0) ) { Settings->shutter_motorstop = XdrvMailbox.payload; + ShutterInit(); } ResponseCmndNumber(Settings->shutter_motorstop); } From c574e24cad3460ee484c9ad0fee07d92e2707e5c Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Thu, 22 Dec 2022 17:50:40 +0100 Subject: [PATCH 039/262] minor clean up in scripts (#17483) --- pio-tools/gen-berry-structures.py | 3 +-- pio-tools/gzip-firmware.py | 2 +- pio-tools/http-uploader.py | 1 + pio-tools/name-firmware.py | 4 +--- pio-tools/override_copy.py | 7 ++++--- pio-tools/pre_source_dir.py | 4 ++-- 6 files changed, 10 insertions(+), 11 deletions(-) diff --git a/pio-tools/gen-berry-structures.py b/pio-tools/gen-berry-structures.py index 622ebbd53..de975a8e5 100644 --- a/pio-tools/gen-berry-structures.py +++ b/pio-tools/gen-berry-structures.py @@ -1,6 +1,5 @@ Import("env") -env = DefaultEnvironment() -platform = env.PioPlatform() + import os import glob import subprocess diff --git a/pio-tools/gzip-firmware.py b/pio-tools/gzip-firmware.py index a497e03fb..e03418262 100644 --- a/pio-tools/gzip-firmware.py +++ b/pio-tools/gzip-firmware.py @@ -1,7 +1,7 @@ Import("env") + import os import shutil -import pathlib import tasmotapiolib import gzip diff --git a/pio-tools/http-uploader.py b/pio-tools/http-uploader.py index fafbcfe03..b9442e1f6 100644 --- a/pio-tools/http-uploader.py +++ b/pio-tools/http-uploader.py @@ -1,6 +1,7 @@ # Original idea by Pascal Gollor at 2022-12-13 Import("env") + import os import tasmotapiolib diff --git a/pio-tools/name-firmware.py b/pio-tools/name-firmware.py index dcb1e9d30..d6a310337 100644 --- a/pio-tools/name-firmware.py +++ b/pio-tools/name-firmware.py @@ -1,9 +1,7 @@ Import("env") -Import("projenv") -import os + import shutil import pathlib - import tasmotapiolib diff --git a/pio-tools/override_copy.py b/pio-tools/override_copy.py index 4f17079b2..53a2762a5 100644 --- a/pio-tools/override_copy.py +++ b/pio-tools/override_copy.py @@ -1,21 +1,22 @@ Import('env') + import os import shutil # copy tasmota/user_config_override_sample.h to tasmota/user_config_override.h if os.path.isfile("tasmota/user_config_override.h"): print ("*** use provided user_config_override.h as planned ***") -else: +else: shutil.copy("tasmota/user_config_override_sample.h", "tasmota/user_config_override.h") # copy platformio_override_sample.ini to platformio_override.ini if os.path.isfile("platformio_override.ini"): print ("*** use provided platformio_override.ini as planned ***") -else: +else: shutil.copy("platformio_override_sample.ini", "platformio_override.ini") # copy platformio_tasmota_cenv_sample.ini to platformio_tasmota_cenv.ini if os.path.isfile("platformio_tasmota_cenv.ini"): print ("*** use provided platformio_tasmota_cenv.ini as planned ***") -else: +else: shutil.copy("platformio_tasmota_cenv_sample.ini", "platformio_tasmota_cenv.ini") diff --git a/pio-tools/pre_source_dir.py b/pio-tools/pre_source_dir.py index 660f5df0a..6027d2ba9 100644 --- a/pio-tools/pre_source_dir.py +++ b/pio-tools/pre_source_dir.py @@ -1,8 +1,8 @@ +Import("env") + import glob import os -Import("env") - def FindInoNodes(env): src_dir = glob.escape(env.subst("$PROJECT_SRC_DIR")) return env.Glob(os.path.join(src_dir, "*.ino")) + env.Glob( From 23e0bc27e7a4c226c29cf349b0e6708602cca6f7 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Thu, 22 Dec 2022 17:54:54 +0100 Subject: [PATCH 040/262] Update changelogs --- CHANGELOG.md | 3 +- RELEASENOTES.md | 2 + .../tasmota_xnrg_energy/xnrg_29_modbus.ino | 67 +++++++++++++------ 3 files changed, 52 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21807b766..85f43610b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. ## [12.3.1.2] ### Added -- Berry crypto add ``EC_P256`` and ``PBKDF2_HMAC_SHA256`` algorithms required by Matter protocol +- Berry crypto add ``EC_P256`` and ``PBKDF2_HMAC_SHA256`` algorithms required by Matter protocol (#17473) ### Breaking Changed @@ -14,6 +14,7 @@ All notable changes to this project will be documented in this file. ### Fixed - Shutter default motorstop set to 0 (#17403) +- Shutter default tilt configuration (#17484) ### Removed diff --git a/RELEASENOTES.md b/RELEASENOTES.md index c0a162589..ba466d12c 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -112,6 +112,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm - Support for RGB displays [#17414](https://github.com/arendst/Tasmota/issues/17414) - Support for IPv6 DNS records (AAAA) and IPv6 ``Ping`` for ESP32 and ESP8266 [#17417](https://github.com/arendst/Tasmota/issues/17417) - Berry support for ``crypto.SHA256`` [#17430](https://github.com/arendst/Tasmota/issues/17430) +- Berry crypto add ``EC_P256`` and ``PBKDF2_HMAC_SHA256`` algorithms required by Matter protocol [#17473](https://github.com/arendst/Tasmota/issues/17473) ### Breaking Changed @@ -122,5 +123,6 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm ### Fixed - Shutter default motorstop set to 0 [#17403](https://github.com/arendst/Tasmota/issues/17403) +- Shutter default tilt configuration [#17484](https://github.com/arendst/Tasmota/issues/17484) ### Removed diff --git a/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino b/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino index 220fe4b1c..be66be989 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino @@ -48,7 +48,7 @@ * 6 = 4-byte signed with swapped words * 7 = not used * 8 = 4-byte unsigned with swapped words - * M - Divider allowing to devide the read register by 1, 10, 100, 1000 etc. - optional. default = 1 + * M - Multiply, if negative, or divide, if positive, the read register by 1 to 10000 - optional. default = 1 * Current - Current register entered as decimal or hexadecimal for one phase (0x0006) or up to three phases ([0x0006,0x0008,0x000A]) or * See additional defines like voltage. * Power - Active power register entered as decimal or hexadecimal for one phase (0x000C) or up to three phases ([0x000C,0x000E,0x0010]) or @@ -80,7 +80,7 @@ * 6 = 4-byte signed with swapped words * 7 = not used * 8 = 4-byte unsigned with swapped words - * M - Divider allowing to devide the read register by 1, 10, 100, 1000 etc. - optional. default = 1 + * M - Multiply, if negative, or divide, if positive, the read register by 1 to 10000 - optional. default = 1 * J - JSON register name (preferrably without spaces like "PhaseAngle") * G - GUI register name * U - GUI unit name @@ -105,6 +105,7 @@ * rule3 on file#modbus do {"Name":"SDM120","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":0,"Current":6,"Power":12,"ApparentPower":18,"ReactivePower":24,"Factor":30,"Frequency":70,"Total":342,"ExportActive":0x004A,"User":[{"R":0x0048,"J":"ImportActive","G":"Import Active","U":"kWh","D":24},{"R":0x004E,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":24},{"R":0x004C,"J":"ImportReactive","G":"Import Reactive","U":"kVArh","D":24},{"R":0x0024,"J":"PhaseAngle","G":"Phase Angle","U":"Deg","D":2}]} endon * rule3 on file#modbus do {"Name":"SDM230 with two user registers","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":0,"Current":6,"Power":12,"ApparentPower":18,"ReactivePower":24,"Factor":30,"Frequency":70,"Total":342,"ExportActive":0x004A,"User":[{"R":0x004E,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":3},{"R":0x0024,"J":"PhaseAngle","G":"Phase Angle","U":"Deg","D":2}]} endon * rule3 on file#modbus do {"Name":"SDM630","Baud":9600,"Config":8N1","Address":1,"Function":4,"Voltage":[0,2,4],"Current":[6,8,10],"Power":[12,14,16],"ApparentPower":[18,20,22],"ReactivePower":[24,26,28],"Factor":[30,32,34],"Frequency":70,"Total":342,"ExportActive":[352,354,356],"User":{"R":[346,348,350],"J":"ImportActive","G":"Import Active","U":"kWh","D":24}} endon + * rule3 on file#modbus do {"Name":"X3MIC","Baud":9600,"Config":8N1","Address":1,"Function":4,"Voltage":{"R":0x0404,"T":3,"M":10},"Power":{"R":0x040e,"T":3,"M":1},"Total":{"R":0x0423,"T":8,"M":1000}} endon * * Note: * - To enter long rules using the serial console and solve error "Serial buffer overrun" you might need to enlarge the serial input buffer with command serialbuffer 800 @@ -215,7 +216,7 @@ struct NRGMBSPARAM { typedef struct NRGMBSREGISTER { uint16_t address[ENERGY_MAX_PHASES]; - uint16_t divider; + int16_t divider; uint32_t datatype; } NrgMbsRegister_t; NrgMbsRegister_t *NrgMbsReg = nullptr; @@ -272,52 +273,80 @@ void EnergyModbusLoop(void) { */ AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Modbus error %d"), error); } else { + /* Modbus protocol format: + * SA = Device Address + * FC = Function Code + * BC = Byte count + * Fh = First or High word MSB + * Fl = First or High word LSB + * Sh = Second or Low word MSB + * Sl = Second or Low word LSB + * Cl = CRC lsb + * Ch = CRC msb + */ Energy.data_valid[NrgMbsParam.phase] = 0; - // 0 1 2 3 4 5 6 7 8 - // SA FC BC Fh Fl Sh Sl Cl Ch - // 01 04 04 43 66 33 34 1B 38 = 230.2 Volt float value; switch (NrgMbsReg[NrgMbsParam.state].datatype) { - case NRG_DT_FLOAT: { + case NRG_DT_FLOAT: { // 0 + // 0 1 2 3 4 5 6 7 8 + // SA FC BC Fh Fl Sh Sl Cl Ch + // 01 04 04 43 66 33 34 1B 38 = 230.2 Volt ((uint8_t*)&value)[3] = buffer[3]; // Get float values ((uint8_t*)&value)[2] = buffer[4]; ((uint8_t*)&value)[1] = buffer[5]; ((uint8_t*)&value)[0] = buffer[6]; break; } - case NRG_DT_S16: { + case NRG_DT_S16: { // 1 + // 0 1 2 3 4 5 6 + // SA FC BC Fh Fl Cl Ch int16_t value_buff = ((int16_t)buffer[3])<<8 | buffer[4]; value = (float)value_buff; break; } - case NRG_DT_U16: { + case NRG_DT_U16: { // 3 + // 0 1 2 3 4 5 6 + // SA FC BC Fh Fl Cl Ch uint16_t value_buff = ((uint16_t)buffer[3])<<8 | buffer[4]; value = (float)value_buff; break; } - case NRG_DT_S32: { + case NRG_DT_S32: { // 2 + // 0 1 2 3 4 5 6 7 8 + // SA FC BC Fh Fl Sh Sl Cl Ch int32_t value_buff = ((int32_t)buffer[3])<<24 | ((uint32_t)buffer[4])<<16 | ((uint32_t)buffer[5])<<8 | buffer[6]; value = (float)value_buff; break; } - case NRG_DT_S32_SW: { + case NRG_DT_S32_SW: { // 6 + // 0 1 2 3 4 5 6 7 8 + // SA FC BC Sh Sl Fh Fl Cl Ch int32_t value_buff = ((int32_t)buffer[5])<<24 | ((uint32_t)buffer[6])<<16 | ((uint32_t)buffer[3])<<8 | buffer[4]; value = (float)value_buff; break; } - case NRG_DT_U32: { + case NRG_DT_U32: { // 4 + // 0 1 2 3 4 5 6 7 8 + // SA FC BC Fh Fl Sh Sl Cl Ch uint32_t value_buff = ((uint32_t)buffer[3])<<24 | ((uint32_t)buffer[4])<<16 | ((uint32_t)buffer[5])<<8 | buffer[6]; value = (float)value_buff; break; } - case NRG_DT_U32_SW: { + case NRG_DT_U32_SW: { // 8 + // 0 1 2 3 4 5 6 7 8 + // SA FC BC Sh Sl Fh Fl Cl Ch + // 01 04 04 EB EC 00 0E 8E 51 = 977.9000 (Solax protocol X1&X3) uint32_t value_buff = ((uint32_t)buffer[5])<<24 | ((uint32_t)buffer[6])<<16 | ((uint32_t)buffer[3])<<8 | buffer[4]; value = (float)value_buff; break; } } - value /= NrgMbsReg[NrgMbsParam.state].divider; + if (NrgMbsReg[NrgMbsParam.state].divider < 1) { + value *= (NrgMbsReg[NrgMbsParam.state].divider * -1); + } else { + value /= NrgMbsReg[NrgMbsParam.state].divider; + } switch (NrgMbsParam.state) { case NRG_MBS_VOLTAGE: @@ -416,8 +445,8 @@ bool EnergyModbusReadUserRegisters(JsonParserObject user_add_value, uint32_t add } val = user_add_value[PSTR("M")]; // Register divider if (val) { - // "M":1 - NrgMbsReg[reg_index].divider = val.getUInt(); + // "M":1 or "M":-10 + NrgMbsReg[reg_index].divider = val.getInt(); } val = user_add_value[PSTR("J")]; // JSON value name if (val) { @@ -575,8 +604,8 @@ bool EnergyModbusReadRegisters(void) { } val = register_add_values[PSTR("M")]; // Register divider if (val) { - // "M":1 - NrgMbsReg[names].divider = val.getUInt(); + // "M":1 or "M":-10 + NrgMbsReg[names].divider = val.getInt(); } } else if (val.isArray()) { // "Voltage":[0,0,0] @@ -658,7 +687,7 @@ bool EnergyModbusReadRegisters(void) { if (NrgMbsReg[i].datatype >= NRG_DT_MAX) { NrgMbsReg[i].datatype = ENERGY_MODBUS_DATATYPE; } - if (NrgMbsReg[i].divider < 1) { + if (0 == NrgMbsReg[i].divider) { NrgMbsReg[i].divider = ENERGY_MODBUS_DIVIDER; } } From 970e36f44daa3ba323f2819255ddce80e0136cc4 Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Thu, 22 Dec 2022 18:57:20 +0100 Subject: [PATCH 041/262] Berry crypto add ``random`` to generate series of random bytes (#17482) --- CHANGELOG.md | 3 ++- .../berry_tasmota/src/be_crypto_lib.c | 2 ++ .../xdrv_52_3_berry_crypto.ino | 26 +++++++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 85f43610b..4d25f57a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,8 @@ All notable changes to this project will be documented in this file. ## [12.3.1.2] ### Added -- Berry crypto add ``EC_P256`` and ``PBKDF2_HMAC_SHA256`` algorithms required by Matter protocol (#17473) +- Berry crypto add ``EC_P256`` and ``PBKDF2_HMAC_SHA256`` algorithms required by Matter protocol +- Berry crypto add ``random`` to generate series of random bytes ### Breaking Changed diff --git a/lib/libesp32/berry_tasmota/src/be_crypto_lib.c b/lib/libesp32/berry_tasmota/src/be_crypto_lib.c index d1e25392e..525f9b359 100644 --- a/lib/libesp32/berry_tasmota/src/be_crypto_lib.c +++ b/lib/libesp32/berry_tasmota/src/be_crypto_lib.c @@ -9,6 +9,7 @@ #include "be_mapping.h" extern int be_class_crypto_member(bvm *vm); +extern int m_crypto_random(bvm *vm); extern int m_aes_gcm_init(bvm *vm); extern int m_aes_gcm_encryt(bvm *vm); @@ -145,6 +146,7 @@ class be_class_pbkdf2_hmac_sha256 (scope: global, name: PBKDF2_HMAC_SHA256) { module crypto (scope: global) { member, func(be_class_crypto_member) + random, func(m_crypto_random) } @const_object_info_end */ diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino index 21f1553b4..d9672d5ba 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino @@ -39,6 +39,32 @@ extern "C" { } } +/*********************************************************************************************\ + * Random bytes generator + * + * As long as Wifi or BLE is enable, it uses a hardware source for true randomnesss + * +\*********************************************************************************************/ +extern "C" { + // `crypto.random(num_bytes:int) -> bytes(num_bytes)` + // + // Generates a series of random bytes + int m_crypto_random(bvm *vm); + int m_crypto_random(bvm *vm) { + int32_t argc = be_top(vm); // Get the number of arguments + if (argc >= 1 && be_isint(vm, 1)) { + int32_t n = be_toint(vm, 1); + if (n < 0 || n > 4096) { be_raise(vm, "value_error", ""); } + + uint8_t rand_bytes[n]; + esp_fill_random(rand_bytes, n); + be_pushbytes(vm, rand_bytes, n); + be_return(vm); + } + be_raise(vm, kTypeError, nullptr); + } +} + /*********************************************************************************************\ * AES_GCM class * From 42e3862970f51151ef25232f1eeec14fdfed6bfb Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Thu, 22 Dec 2022 22:39:06 +0100 Subject: [PATCH 042/262] Berry hkdf (#17487) * Berry crypto add `HKDF_HMAC_SHA256` * add HKDF option --- CHANGELOG.md | 1 + .../berry_tasmota/src/be_crypto_lib.c | 12 ++++ tasmota/my_user_config.h | 1 + .../xdrv_52_3_berry_crypto.ino | 69 +++++++++++++++++++ 4 files changed, 83 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d25f57a0..234ca510c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ All notable changes to this project will be documented in this file. ### Added - Berry crypto add ``EC_P256`` and ``PBKDF2_HMAC_SHA256`` algorithms required by Matter protocol - Berry crypto add ``random`` to generate series of random bytes +- Berry crypto add ``HKDF_HMAC_SHA256`` ### Breaking Changed diff --git a/lib/libesp32/berry_tasmota/src/be_crypto_lib.c b/lib/libesp32/berry_tasmota/src/be_crypto_lib.c index 525f9b359..b38c3c092 100644 --- a/lib/libesp32/berry_tasmota/src/be_crypto_lib.c +++ b/lib/libesp32/berry_tasmota/src/be_crypto_lib.c @@ -40,6 +40,8 @@ extern int m_hmac_sha256_out(bvm *vm); extern int m_pbkdf2_hmac_sha256_f(bvm *vm); +extern int m_hkdf_hmac_sha256_derive(bvm *vm); + extern const bclass be_class_md5; #include "solidify/solidified_crypto_pbkdf2_hmac_sha256.h" @@ -51,10 +53,12 @@ extern const bclass be_class_md5; #include "be_fixed_be_class_sha256.h" #include "be_fixed_be_class_hmac_sha256.h" #include "be_fixed_be_class_pbkdf2_hmac_sha256.h" +#include "be_fixed_be_class_hkdf_hmac_sha256.h" #include "be_fixed_crypto.h" const be_const_member_t be_crypto_members[] = { // name with prefix '/' indicates a Berry class + // entries need to be sorted (ignoring the prefix char) #ifdef USE_BERRY_CRYPTO_AES_CTR { "/AES_CTR", (intptr_t) &be_class_aes_ctr }, #endif // USE_BERRY_CRYPTO_AES_CTR @@ -71,6 +75,10 @@ const be_const_member_t be_crypto_members[] = { { "/EC_P256", (intptr_t) &be_class_ec_p256 }, #endif // USE_BERRY_CRYPTO_EC_P256 +#ifdef USE_BERRY_CRYPTO_HKDF_HMAC_SHA256 + { "/HKDF_HMAC_SHA256", (intptr_t) &be_class_hkdf_hmac_sha256 }, +#endif // USE_BERRY_CRYPTO_HKDF_HMAC_SHA256 + #ifdef USE_BERRY_CRYPTO_HMAC_SHA256 { "/HMAC_SHA256", (intptr_t) &be_class_hmac_sha256 }, #endif // USE_BERRY_CRYPTO_HMAC_SHA256 @@ -144,6 +152,10 @@ class be_class_pbkdf2_hmac_sha256 (scope: global, name: PBKDF2_HMAC_SHA256) { derive, closure(PBKDF2_HMAC_SHA256_closure) } +class be_class_hkdf_hmac_sha256 (scope: global, name: HKDF_HMAC_SHA256) { + derive, static_func(m_hkdf_hmac_sha256_derive) +} + module crypto (scope: global) { member, func(be_class_crypto_member) random, func(m_crypto_random) diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index ff9b1c9a9..feea40b0f 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -1112,6 +1112,7 @@ #define USE_BERRY_CRYPTO_SHA256 // enable SHA256 hash function #define USE_BERRY_CRYPTO_HMAC_SHA256 // enable HMAC SHA256 hash function // #define USE_BERRY_CRYPTO_PBKDF2_HMAC_SHA256 // PBKDF2 with HMAC SHA256, used in Matter protocol + // #define USE_BERRY_CRYPTO_HKDF_HMAC_SHA256 // HKDF with HMAC SHA256, used in Matter protocol #define USE_CSE7761 // Add support for CSE7761 Energy monitor as used in Sonoff Dual R3 // -- LVGL Graphics Library --------------------------------- diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino index d9672d5ba..a07e5a649 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino @@ -673,6 +673,75 @@ extern "C" { } } +/*********************************************************************************************\ + * HKDF_HMAC_SHA256 + * +\*********************************************************************************************/ +extern "C" { + // crypto.HKDF_HMAC_SHA256().derive(ikm:bytes(), salt:bytes(), info:bytes(), out_bytes:int) -> bytes(out_bytes) + // Derive key with HKDF based on HMAC SHA256 + int32_t m_hkdf_hmac_sha256_derive(bvm *vm); + int32_t m_hkdf_hmac_sha256_derive(bvm *vm) { + int32_t argc = be_top(vm); // Get the number of arguments + if (argc >= 4 && be_isbytes(vm, 1) && be_isbytes(vm, 2) && be_isbytes(vm, 3) && be_isint(vm, 4)) { + size_t ikm_len; + const void * ikm = be_tobytes(vm, 1, &ikm_len); + if (ikm_len == 0) { be_raise(vm, "value_error", "ikm must not be empty"); } + + size_t salt_len; + const void * salt = be_tobytes(vm, 2, &salt_len); + if (salt_len == 0) { salt = &br_hkdf_no_salt; } + + size_t info_len; + const void * info = be_tobytes(vm, 3, &info_len); + + int32_t out_bytes = be_toint(vm, 4); + if (out_bytes < 1 || out_bytes > 256) { be_raise(vm, "value_error", "invalid out_bytes"); } + + br_hkdf_context hc; + br_hkdf_init(&hc, &br_sha256_vtable, salt, salt_len); + br_hkdf_inject(&hc, ikm, ikm_len); + br_hkdf_flip(&hc); + uint8_t out[out_bytes]; + br_hkdf_produce(&hc, info, info_len, out, out_bytes); + + be_pushbytes(vm, out, out_bytes); + be_return(vm); + } + be_raise(vm, kTypeError, nullptr); + } +/* Test vectors +# https://www.rfc-editor.org/rfc/rfc5869 + +import crypto + +# Test Case 1 +hk = crypto.HKDF_HMAC_SHA256() +ikm = bytes("0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B") +salt = bytes("000102030405060708090A0B0C") +info = bytes("F0F1F2F3F4F5F6F7F8F9") +k = hk.derive(ikm, salt, info, 42) +assert(k == bytes("3CB25F25FAACD57A90434F64D0362F2A2D2D0A90CF1A5A4C5DB02D56ECC4C5BF34007208D5B887185865")) + +# Test Case 2 +hk = crypto.HKDF_HMAC_SHA256() +ikm = bytes("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f") +salt = bytes("606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf") +info = bytes("b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff") +k = hk.derive(ikm, salt, info, 82) +assert(k == bytes("b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c59045a99cac7827271cb41c65e590e09da3275600c2f09b8367793a9aca3db71cc30c58179ec3e87c14c01d5c1f3434f1d87")) + +# Test Case 3 +hk = crypto.HKDF_HMAC_SHA256() +ikm = bytes("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b") +salt = bytes() +info = bytes() +k = hk.derive(ikm, salt, info, 42) +assert(k == bytes("8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8")) + +*/ +} + /*********************************************************************************************\ * PBKDF2_HMAC_SHA256 * From 0c588f2ff4e1605ee278489d36f5a592fb4c8da4 Mon Sep 17 00:00:00 2001 From: stefanbode Date: Fri, 23 Dec 2022 09:53:10 +0100 Subject: [PATCH 043/262] better fix on init (#17488) try to avoid get 5000 if the init value is 65535. More focus on setting the standard of 500 on nearly any case --- tasmota/tasmota_xdrv_driver/xdrv_27_shutter.ino | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_27_shutter.ino b/tasmota/tasmota_xdrv_driver/xdrv_27_shutter.ino index fa4c6b1e2..356042d32 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_27_shutter.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_27_shutter.ino @@ -402,7 +402,10 @@ void ShutterInit(void) Settings->shutter_accuracy = 1; Settings->shutter_mode = ShutterGlobal.position_mode; // initialize MotorStop time with 500ms if not set - Settings->shutter_motorstop = (Settings->shutter_motorstop == 0) ? 500 : tmin(5000,Settings->shutter_motorstop); + // typical not set start values are 0 and 65535 + if (Settings->shutter_motorstop > 5000 || Settings->shutter_motorstop == 0) { + Settings->shutter_motorstop = 500; + } } } From 768820061b77ee19e9d6527253d8286f1ea00f0b Mon Sep 17 00:00:00 2001 From: StoyanDimitrov Date: Fri, 23 Dec 2022 08:53:53 +0000 Subject: [PATCH 044/262] Update bg_BG.h (#17485) --- tasmota/language/bg_BG.h | 82 ++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/tasmota/language/bg_BG.h b/tasmota/language/bg_BG.h index ff00e7b10..eacd7b06b 100644 --- a/tasmota/language/bg_BG.h +++ b/tasmota/language/bg_BG.h @@ -75,12 +75,12 @@ #define D_CORS_DOMAIN "Домейн на CORS" #define D_COUNT "Брой" #define D_COUNTER "Брояч" -#define D_CT_POWER "CT Power" +#define D_CT_POWER "ТТ Мощност" #define D_CURRENT "Ток" // As in Voltage and Current -#define D_CURRENT_NEUTRAL "Current Neutral" +#define D_CURRENT_NEUTRAL "Ток по нулата" #define D_DATA "Данни" #define D_DARKLIGHT "Тъмна" -#define D_DEBUG "Дебъгване" +#define D_DEBUG "Премахване на дефекти" #define D_DEWPOINT "Температура на оросяване" #define D_DISABLED "Забранено" #define D_MOVING_DISTANCE "Moving Distance" @@ -104,8 +104,8 @@ #define D_FALSE "Невярно" #define D_FILE "Файл" #define D_FLOW_RATE "Дебит" -#define D_FRAGMENTATION "frag." // Lower case abbreviated version of fragmentation used in "memory fragmentation" -#define D_FRAME_RATE "Честота на опресняване" +#define D_FRAGMENTATION "фраг." // Lower case abbreviated version of fragmentation used in "memory fragmentation" +#define D_FRAME_RATE "Кадъра в секунда" #define D_FREE_MEMORY "Свободна памет" #define D_PSR_MAX_MEMORY "PS-RAM Memory" #define D_PSR_FREE_MEMORY "PS-RAM free Memory" @@ -267,7 +267,7 @@ #define D_CONFIGURATION "Настройки" #define D_INFORMATION "Информация" #define D_FIRMWARE_UPGRADE "Обновяване на софтуера" -#define D_MANAGEMENT "Consoles" +#define D_MANAGEMENT "Терминали" #define D_CONSOLE "Терминал" #define D_CONFIRM_RESTART "Потвърдете рестартиране" @@ -275,7 +275,7 @@ #define D_CONFIGURE_WIFI "Настройки на WiFi" #define D_CONFIGURE_MQTT "Настройки на MQTT" #define D_CONFIGURE_DOMOTICZ "Настройки на Domoticz" -#define D_CONFIGURE_LOGGING "Настройки на дневниците" +#define D_CONFIGURE_LOGGING "Настройки на дневници" #define D_CONFIGURE_OTHER "Други настройки" #define D_CONFIRM_RESET_CONFIGURATION "Потвърдете нулирането на настройките" #define D_RESET_CONFIGURATION "Нулиране на настройки" @@ -390,7 +390,7 @@ #define D_UPLOAD_ERR_3 "Недействителен подпис на файла" #define D_UPLOAD_ERR_4 "Размерът на програмата е по-голям от размера на флаш-паметта" #define D_UPLOAD_ERR_5 "Грешка при сравняване на буфери" -#define D_UPLOAD_ERR_6 "Грешка при качване. Включено е съдържание 3 на дневника" +#define D_UPLOAD_ERR_6 "Грешка при качване. Избрана е стойност 3 на дневника" #define D_UPLOAD_ERR_7 "Качването е прекъснато" #define D_UPLOAD_ERR_8 "Файлът е невалиден" #define D_UPLOAD_ERR_9 "Файлът е твърде голям" @@ -402,7 +402,7 @@ #define D_UPLOAD_ERROR_CODE "Код на грешка при качване" #define D_ENTER_COMMAND "Въвеждане на команда" -#define D_ENABLE_WEBLOG_FOR_RESPONSE "Ако очаквате отговор изберете съдържание 2 на дневника за уеб" +#define D_ENABLE_WEBLOG_FOR_RESPONSE "Ако очаквате отговор изберете стойност 2 на дневника за уеб" #define D_NEED_USER_AND_PASSWORD "Необходими параметри: user=&password=" // xdrv_01_mqtt.ino @@ -919,11 +919,11 @@ #define D_SENSOR_ME007_RX "ME007 Rx" // Units -#define D_UNIT_AMPERE "A" -#define D_UNIT_CELSIUS "Ц" +#define D_UNIT_AMPERE "А" +#define D_UNIT_CELSIUS "C" #define D_UNIT_CENTIMETER "см" #define D_UNIT_DEGREE "°" -#define D_UNIT_FAHRENHEIT "Ф" +#define D_UNIT_FAHRENHEIT "F" #define D_UNIT_FPS "Кадъра в секунда" #define D_UNIT_HERTZ "Хц" #define D_UNIT_HOUR "ч" @@ -932,11 +932,11 @@ #define D_UNIT_KILOGRAM "кг" #define D_UNIT_INCH_MERCURY "inHg" #define D_UNIT_INCREMENTS "инч" -#define D_UNIT_KELVIN "К" +#define D_UNIT_KELVIN "K" #define D_UNIT_KILOMETER "км" #define D_UNIT_KILOMETER_PER_HOUR "км/ч" #define D_UNIT_KILOOHM "кΩ" -#define D_UNIT_KILOWATTHOUR "кВ/ч" +#define D_UNIT_KILOWATTHOUR "кВт/ч" #define D_UNIT_LITERS "л" #define D_UNIT_LITERS_PER_MIN "л/м" #define D_UNIT_LUX "лукс" @@ -945,7 +945,7 @@ #define D_UNIT_MICROSECOND "µс" #define D_UNIT_MICROSIEMENS_PER_CM "µS/см" #define D_UNIT_MICROTESLA "µТ" -#define D_UNIT_MILLIAMPERE "mА" +#define D_UNIT_MILLIAMPERE "мА" #define D_UNIT_MILLILITERS "мл" #define D_UNIT_MILLIMETER "мм" #define D_UNIT_MILLIMETER_MERCURY "mmHg" @@ -957,15 +957,15 @@ #define D_UNIT_PARTS_PER_MILLION "ppm" #define D_UNIT_MILIGRAMS_PER_LITER "мг/л" #define D_UNIT_PERCENT "%%" -#define D_UNIT_PRESSURE "hPa" +#define D_UNIT_PRESSURE "хПа" #define D_UNIT_SECOND "с" #define D_UNIT_SECTORS "сектора" -#define D_UNIT_VA "VA" -#define D_UNIT_VAR "VAr" -#define D_UNIT_VOLT "V" -#define D_UNIT_WATT "W" -#define D_UNIT_WATTHOUR "W/ч" -#define D_UNIT_WATT_METER_QUADRAT "W/м²" +#define D_UNIT_VA "ВА" +#define D_UNIT_VAR "ВАр" +#define D_UNIT_VOLT "В" +#define D_UNIT_WATT "Вт" +#define D_UNIT_WATTHOUR "Вт/ч" +#define D_UNIT_WATT_METER_QUADRAT "Вт/м²" #define D_UNIT_LITER_PER_MINUTE "л/мин" #define D_UNIT_CUBICMETER_PER_HOUR "м³/ч" #define D_UNIT_CUBIC_METER "м³" @@ -983,18 +983,18 @@ #define D_IMPORT_REACTIVE "Входна реактивна мощност" #define D_EXPORT_REACTIVE "Изходна реактивна мощност" #define D_TOTAL_REACTIVE "Общо реактивна мощност" -#define D_UNIT_KWARH "kVArh" +#define D_UNIT_KWARH "кВАр/ч" #define D_UNIT_ANGLE "°" #define D_TOTAL_ACTIVE "Общо активна мощност" -#define D_RESETTABLE_TOTAL_ACTIVE "Общо активна мощност (RST)" +#define D_RESETTABLE_TOTAL_ACTIVE "Общо активна мощност" //SOLAXX1 -#define D_PV1_VOLTAGE "Напрежение на PV1" -#define D_PV1_CURRENT "Ток на PV1" -#define D_PV1_POWER "Мощност на PV1" -#define D_PV2_VOLTAGE "Напрежение на PV2" -#define D_PV2_CURRENT "Ток на PV2" -#define D_PV2_POWER "Мощност на PV2" +#define D_PV1_VOLTAGE "Напрежение на ФВ1" +#define D_PV1_CURRENT "Ток на ФВ1" +#define D_PV1_POWER "Мощност на ФВ1" +#define D_PV2_VOLTAGE "Напрежение на ФВ2" +#define D_PV2_CURRENT "Ток на ФВ2" +#define D_PV2_POWER "Мощност на ФВ2" #define D_SOLAR_POWER "Слънчева мощност" #define D_INVERTER_POWER "Мощност на инвертора" #define D_STATUS "Състояние" @@ -1009,7 +1009,7 @@ #define D_SOLAX_ERROR_1 "Грешка - загуба на мрежата" #define D_SOLAX_ERROR_2 "Грешка - мрежово напрежение" #define D_SOLAX_ERROR_3 "Грешка - мрежова честота" -#define D_SOLAX_ERROR_4 "Грешка - напрежение на Pv" +#define D_SOLAX_ERROR_4 "Грешка - напрежение на ФВ" #define D_SOLAX_ERROR_5 "Грешка - проблем с изолацията" #define D_SOLAX_ERROR_6 "Грешка - прегряване" #define D_SOLAX_ERROR_7 "Грешка - вентилатор" @@ -1017,26 +1017,26 @@ //xdrv_10_scripter.ino #define D_CONFIGURE_SCRIPT "Промяна на скрипт" -#define D_SCRIPT "редактиране на скрипт" -#define D_SDCARD_UPLOAD "изпращане на файл" +#define D_SCRIPT "променяне на скрипт" +#define D_SDCARD_UPLOAD "качване на файл" #define D_UFSDIR "папка на картата на UFS" #define D_UPL_DONE "Готово" #define D_SCRIPT_CHARS_LEFT "оставащи символи" -#define D_SCRIPT_CHARS_NO_MORE "няма повече символи" +#define D_SCRIPT_CHARS_NO_MORE "не остават повече символи" #define D_SCRIPT_DOWNLOAD "Изтегляне" #define D_SCRIPT_ENABLE "включване на скрипт" #define D_SCRIPT_UPLOAD "Качване" #define D_SCRIPT_UPLOAD_FILES "Качване на файлове" //xdrv_50_filesystem.ino -#define D_MANAGE_FILE_SYSTEM "Управление на файлова система" +#define D_MANAGE_FILE_SYSTEM "Файлова система" #define D_FS_SIZE "Размер" #define D_FS_FREE "Свободни" #define D_NEW_FILE "newfile.txt" -#define D_CREATE_NEW_FILE "Създаване и промяна на нов файл" +#define D_CREATE_NEW_FILE "Създаване на файл" #define D_EDIT_FILE "Промяна на файл" -#define D_CONFIRM_FILE_DEL "Потвърждаване на изтриване на файл" -#define D_SHOW_HIDDEN_FILES "Показване на скритите файлове" +#define D_CONFIRM_FILE_DEL "Потвърждаване премахването на файл" +#define D_SHOW_HIDDEN_FILES "Показване на скрити файлове" //xsns_67_as3935.ino #define D_AS3935_GAIN "усилване:" @@ -1158,9 +1158,9 @@ #define D_NEOPOOL_RELAY_AUX "Aux" #define D_NEOPOOL_TIME "Време" #define D_NEOPOOL_FILT_MODE "Филтриране" -#define D_NEOPOOL_CELL_RUNTIME "Cell runtime" +#define D_NEOPOOL_CELL_RUNTIME "Време на работа" #define D_NEOPOOL_POLARIZATION "Pol" // Sensor status -#define D_NEOPOOL_PR_OFF "PrOff" +#define D_NEOPOOL_PR_OFF "Изкл" #define D_NEOPOOL_SETPOINT_OK "Ok" #define D_NEOPOOL_COVER "Капак" #define D_NEOPOOL_SHOCK "Boost" @@ -1168,7 +1168,7 @@ #define D_NEOPOOL_STATUS_OFF "ИЗКЛ" #define D_NEOPOOL_STATUS_WAIT "ЧАКА" #define D_NEOPOOL_STATUS_TANK "РЕЗЕРВОАР" -#define D_NEOPOOL_STATUS_FLOW "Flow" +#define D_NEOPOOL_STATUS_FLOW "Тече" #define D_NEOPOOL_LOW "Ниско" #define D_NEOPOOL_FLOW1 "FL1" #define D_NEOPOOL_FLOW2 "FL2" From 0dc3b8d7e1d698b1079242d5b8948f93aaf6d0ca Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 23 Dec 2022 11:39:13 +0100 Subject: [PATCH 045/262] Add fieldpair "F" replacing "M" --- .../tasmota_xnrg_energy/xnrg_29_modbus.ino | 105 ++++++++++++------ 1 file changed, 74 insertions(+), 31 deletions(-) diff --git a/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino b/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino index be66be989..0b06da4ca 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino @@ -36,7 +36,7 @@ * Voltage - Voltage register entered as decimal or hexadecimal for one phase (0x0000) or up to three phases ([0x0000,0x0002,0x0004]) or * Additional defined parameters * Value pair description: - * {"R":0,"T":0,"M":1} + * {"R":0,"T":0,"F":0} * R - Modbus register entered as decimal or hexadecimal for one phase (0x0160) or up to three phases ([0x0160,0x0162,0x0164]) * T - Datatype - optional. default is 0 - float: * 0 - float @@ -48,7 +48,17 @@ * 6 = 4-byte signed with swapped words * 7 = not used * 8 = 4-byte unsigned with swapped words - * M - Multiply, if negative, or divide, if positive, the read register by 1 to 10000 - optional. default = 1 + * F - Register factor positive for multiplication or negative for division - optional. default is 0 - no action + * -4 - divide by 10000 + * -3 - divide by 1000 + * -2 - divide by 100 + * -1 - divide by 10 + * 0 - no action + * 1 - multiply by 10 + * 2 - multiply by 100 + * 3 - multiply by 1000 + * 4 - multiply by 10000 + * M - [LEGACY - replaced by "F"] Divide register by 1 to 10000 - optional. default = 0 (no action) * Current - Current register entered as decimal or hexadecimal for one phase (0x0006) or up to three phases ([0x0006,0x0008,0x000A]) or * See additional defines like voltage. * Power - Active power register entered as decimal or hexadecimal for one phase (0x000C) or up to three phases ([0x000C,0x000E,0x0010]) or @@ -68,7 +78,7 @@ * Optional user defined registers: * User - Additional user defined registers * Value pair description: - * "User":{"R":0x0024,"T":0,"M":1,"J":"PhaseAngle","G":"Phase Angle","U":"Deg","D":2} + * "User":{"R":0x0024,"T":0,"F":0,"J":"PhaseAngle","G":"Phase Angle","U":"Deg","D":2} * R - Modbus register entered as decimal or hexadecimal for one phase (0x0160) or up to three phases ([0x0160,0x0162,0x0164]) * T - Datatype - optional. default is 0 - float: * 0 - float @@ -80,7 +90,17 @@ * 6 = 4-byte signed with swapped words * 7 = not used * 8 = 4-byte unsigned with swapped words - * M - Multiply, if negative, or divide, if positive, the read register by 1 to 10000 - optional. default = 1 + * F - Register factor positive for multiplication or negative for division - optional. default is 0 - no action + * -4 - divide by 10000 + * -3 - divide by 1000 + * -2 - divide by 100 + * -1 - divide by 10 + * 0 - no action + * 1 - multiply by 10 + * 2 - multiply by 100 + * 3 - multiply by 1000 + * 4 - multiply by 10000 + * M - [LEGACY - replaced by "F"] Divide register by 1 to 10000 - optional. default = 0 (no action) * J - JSON register name (preferrably without spaces like "PhaseAngle") * G - GUI register name * U - GUI unit name @@ -105,7 +125,7 @@ * rule3 on file#modbus do {"Name":"SDM120","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":0,"Current":6,"Power":12,"ApparentPower":18,"ReactivePower":24,"Factor":30,"Frequency":70,"Total":342,"ExportActive":0x004A,"User":[{"R":0x0048,"J":"ImportActive","G":"Import Active","U":"kWh","D":24},{"R":0x004E,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":24},{"R":0x004C,"J":"ImportReactive","G":"Import Reactive","U":"kVArh","D":24},{"R":0x0024,"J":"PhaseAngle","G":"Phase Angle","U":"Deg","D":2}]} endon * rule3 on file#modbus do {"Name":"SDM230 with two user registers","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":0,"Current":6,"Power":12,"ApparentPower":18,"ReactivePower":24,"Factor":30,"Frequency":70,"Total":342,"ExportActive":0x004A,"User":[{"R":0x004E,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":3},{"R":0x0024,"J":"PhaseAngle","G":"Phase Angle","U":"Deg","D":2}]} endon * rule3 on file#modbus do {"Name":"SDM630","Baud":9600,"Config":8N1","Address":1,"Function":4,"Voltage":[0,2,4],"Current":[6,8,10],"Power":[12,14,16],"ApparentPower":[18,20,22],"ReactivePower":[24,26,28],"Factor":[30,32,34],"Frequency":70,"Total":342,"ExportActive":[352,354,356],"User":{"R":[346,348,350],"J":"ImportActive","G":"Import Active","U":"kWh","D":24}} endon - * rule3 on file#modbus do {"Name":"X3MIC","Baud":9600,"Config":8N1","Address":1,"Function":4,"Voltage":{"R":0x0404,"T":3,"M":10},"Power":{"R":0x040e,"T":3,"M":1},"Total":{"R":0x0423,"T":8,"M":1000}} endon + * rule3 on file#modbus do {"Name":"X3MIC","Baud":9600,"Config":8N1","Address":1,"Function":4,"Voltage":{"R":0x0404,"T":3,"F":-1},"Power":{"R":0x040e,"T":3,"F":0},"Total":{"R":0x0423,"T":8,"F":-3}} endon * * Note: * - To enter long rules using the serial console and solve error "Serial buffer overrun" you might need to enlarge the serial input buffer with command serialbuffer 800 @@ -128,7 +148,7 @@ * rule3 on file#modbus do {"Name":"SDM120 test1","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":0,"Current":6,"Power":12,"ApparentPower":18,"ReactivePower":24,"Factor":30,"Frequency":70,"Total":342,"ExportActive":0x004A,"User":[{"R":0x0048,"J":"ImportActive","G":"Import Active","U":"kWh","D":24},{"R":0x004E,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":24},{"R":0x004C,"J":"ImportReactive","G":"Import Reactive","U":"kVArh","D":24},{"R":0x0024,"J":"PhaseAngle","G":"Phase Angle","U":"Deg","D":2}]} endon * * rule3 on file#modbus do {"Name":"SDM230 test6","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":{"R":0,"T":0,"M":1},"Current":{"R":6,"T":0,"M":1},"Power":{"R":12,"T":0,"M":1},"Frequency":70,"Total":342} endon - * rule3 on file#modbus do {"Name":"SDM230 test6","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":{"R":0,"T":0,"M":1},"Current":{"R":6,"T":0,"M":1},"Power":{"R":12,"T":0,"M":1},"Frequency":70,"Total":342,"User":{"R":0x0048,"T":0,"M":10,"J":"ImportActive","G":"Import Active","U":"kWh","D":24}} endon + * rule3 on file#modbus do {"Name":"SDM230 test6","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":{"R":0,"T":0,"F":0},"Current":{"R":6,"T":0,"F":0},"Power":{"R":12,"T":0,"F":0},"Frequency":70,"Total":342,"User":{"R":0x0048,"T":0,"F":-1,"J":"ImportActive","G":"Import Active","U":"kWh","D":24}} endon \*********************************************************************************************/ #define XNRG_29 29 @@ -139,8 +159,6 @@ #define ENERGY_MODBUS_FUNC 0x04 // Default Modbus function code #define ENERGY_MODBUS_DATATYPE 0 // Default Modbus datatype is 4-byte float -#define ENERGY_MODBUS_DIVIDER 1 // Default Modbus data divider - #define ENERGY_MODBUS_DECIMALS 0 // Default user decimal resolution #define ENERGY_MODBUS_TICKER // Enable for ESP8266 when using softwareserial solving most modbus serial retries @@ -216,7 +234,7 @@ struct NRGMBSPARAM { typedef struct NRGMBSREGISTER { uint16_t address[ENERGY_MAX_PHASES]; - int16_t divider; + int16_t factor; uint32_t datatype; } NrgMbsRegister_t; NrgMbsRegister_t *NrgMbsReg = nullptr; @@ -342,10 +360,17 @@ void EnergyModbusLoop(void) { break; } } - if (NrgMbsReg[NrgMbsParam.state].divider < 1) { - value *= (NrgMbsReg[NrgMbsParam.state].divider * -1); + uint32_t factor = 1; + // 1 = 10, 2 = 100, 3 = 1000, 4 = 10000 + uint32_t scaler = abs(NrgMbsReg[NrgMbsParam.state].factor); + while (scaler) { + factor *= 10; + scaler--; + } + if (NrgMbsReg[NrgMbsParam.state].factor < 0) { + value /= factor; } else { - value /= NrgMbsReg[NrgMbsParam.state].divider; + value *= factor; } switch (NrgMbsParam.state) { @@ -417,7 +442,7 @@ void EnergyModbusLoop(void) { #ifdef USE_RULES bool EnergyModbusReadUserRegisters(JsonParserObject user_add_value, uint32_t add_index) { - // {"R":0x004E,"T":0,"M":1,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":3} + // {"R":0x004E,"T":0,"F":0,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":3} uint32_t reg_index = NRG_MBS_MAX_REGS + add_index; JsonParserToken val; val = user_add_value[PSTR("R")]; // Register address @@ -443,10 +468,21 @@ bool EnergyModbusReadUserRegisters(JsonParserObject user_add_value, uint32_t add // "T":0 NrgMbsReg[reg_index].datatype = val.getUInt(); } - val = user_add_value[PSTR("M")]; // Register divider + val = user_add_value[PSTR("F")]; // Register factor if (val) { - // "M":1 or "M":-10 - NrgMbsReg[reg_index].divider = val.getInt(); + // "F":1 or "F":-2 + NrgMbsReg[reg_index].factor = val.getInt(); + } + val = user_add_value[PSTR("M")]; // [LEGACY] Register divider + if (val) { + // "M":1 + int32_t divider = val.getUInt(); + int factor = 0; + while (divider > 1) { + divider /= 10; + factor--; + } + NrgMbsReg[reg_index].factor = factor; } val = user_add_value[PSTR("J")]; // JSON value name if (val) { @@ -472,13 +508,13 @@ bool EnergyModbusReadUserRegisters(JsonParserObject user_add_value, uint32_t add } #ifdef ENERGY_MODBUS_DEBUG - AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Idx %d, R [%04X,%04X,%04X], T %d, M %d, J '%s', G '%s', U '%s', D %d"), + AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Idx %d, R [%04X,%04X,%04X], T %d, F %d, J '%s', G '%s', U '%s', D %d"), add_index, NrgMbsReg[reg_index].address[0], NrgMbsReg[reg_index].address[1], NrgMbsReg[reg_index].address[2], NrgMbsReg[reg_index].datatype, - NrgMbsReg[reg_index].divider, + NrgMbsReg[reg_index].factor, NrgMbsUser[add_index].json_name, NrgMbsUser[add_index].gui_name, NrgMbsUser[add_index].gui_unit, @@ -529,7 +565,6 @@ bool EnergyModbusReadRegisters(void) { // Init defaults for (uint32_t i = 0; i < NrgMbsParam.total_regs; i++) { NrgMbsReg[i].datatype = ENERGY_MODBUS_DATATYPE; - NrgMbsReg[i].divider = ENERGY_MODBUS_DIVIDER; for (uint32_t j = 0; j < ENERGY_MAX_PHASES; j++) { NrgMbsReg[i].address[j] = nrg_mbs_reg_not_used; } @@ -576,12 +611,12 @@ bool EnergyModbusReadRegisters(void) { if (val) { // "Voltage":0 // "Voltage":[0,0,0] - // "Voltage":{"R":0,"T":0,"M":1} - // "Voltage":{"R":[0,0,0],"T":0,"M":1} + // "Voltage":{"R":0,"T":0,"F":0} + // "Voltage":{"R":[0,0,0],"T":0,"F":0} uint32_t phase = 0; if (val.isObject()) { - // "Voltage":{"R":0,"T":0,"M":1} - // "Voltage":{"R":[0,0,0],"T":0,"M":1} + // "Voltage":{"R":0,"T":0,"F":0} + // "Voltage":{"R":[0,0,0],"T":0,"F":0} JsonParserObject register_add_values = val.getObject(); val = register_add_values[PSTR("R")]; // Register address if (val.isArray()) { @@ -602,10 +637,21 @@ bool EnergyModbusReadRegisters(void) { // "T":0 NrgMbsReg[names].datatype = val.getUInt(); } - val = register_add_values[PSTR("M")]; // Register divider + val = register_add_values[PSTR("F")]; // Register factor if (val) { - // "M":1 or "M":-10 - NrgMbsReg[names].divider = val.getInt(); + // "F":1 or "F":-2 + NrgMbsReg[names].factor = val.getInt(); + } + val = register_add_values[PSTR("M")]; // [LEGACY] Register divider + if (val) { + // "M":1 + int32_t divider = val.getUInt(); + int factor = 0; + while (divider > 1) { + divider /= 10; + factor--; + } + NrgMbsReg[names].factor = factor; } } else if (val.isArray()) { // "Voltage":[0,0,0] @@ -644,13 +690,13 @@ bool EnergyModbusReadRegisters(void) { } #ifdef ENERGY_MODBUS_DEBUG - AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Idx %d, R [%04X,%04X,%04X], T %d, M %d"), + AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Idx %d, R [%04X,%04X,%04X], T %d, F %d"), names, NrgMbsReg[names].address[0], NrgMbsReg[names].address[1], NrgMbsReg[names].address[2], NrgMbsReg[names].datatype, - NrgMbsReg[names].divider); + NrgMbsReg[names].factor); #endif } @@ -687,9 +733,6 @@ bool EnergyModbusReadRegisters(void) { if (NrgMbsReg[i].datatype >= NRG_DT_MAX) { NrgMbsReg[i].datatype = ENERGY_MODBUS_DATATYPE; } - if (0 == NrgMbsReg[i].divider) { - NrgMbsReg[i].divider = ENERGY_MODBUS_DIVIDER; - } } #ifdef ENERGY_MODBUS_DEBUG From 940d2397fa092a4b8ec6efcf3d5a24cc21f18ec1 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 23 Dec 2022 14:26:25 +0100 Subject: [PATCH 046/262] Fix addressed register 1 - Add example for PZEM-0014 --- .../tasmota_xnrg_energy/xnrg_29_modbus.ino | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino b/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino index 0b06da4ca..ade3ef466 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino @@ -119,25 +119,27 @@ * rule3 on file#modbus do {"Name":"SDM230","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":0,"Current":6,"Power":12,"ApparentPower":18,"ReactivePower":24,"Factor":30,"Frequency":70,"Total":342,"ExportActive":0x004A} endon * rule3 on file#modbus do {"Name":"SDM230 with hex registers","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":0x0000,"Current":0x0006,"Power":0x000C,"ApparentPower":0x0012,"ReactivePower":0x0018,"Factor":0x001E,"Frequency":0x0046,"Total":0x0156,"ExportActive":0x004A} endon * rule3 on file#modbus do {"Name":"DDSU666","Baud":9600,"Config":8N1","Address":1,"Function":4,"Voltage":0x2000,"Current":0x2002,"Power":0x2004,"ReactivePower":0x2006,"Factor":0x200A,"Frequency":0x200E,"Total":0x4000,"ExportActive":0x400A} endon + * rule3 on file#modbus do {"Name":"PZEM014","Baud":9600,"Config":8N1","Address":1,"Function":4,"Voltage":{"R":0,"T":3,"F":-1},"Current":{"R":1,"T":8,"F":-3},"Power":{"R":3,"T":8,"F":-1},"Factor":{"R":8,"T":3,"F":-2},"Frequency":{"R":7,"T":3,"F":-1},"Total":{"R":5,"T":8,"F":-3}} endon + * rule3 on file#modbus do {"Name":"Solax X3MIC","Baud":9600,"Config":8N1","Address":1,"Function":4,"Voltage":{"R":0x0404,"T":3,"F":-1},"Power":{"R":0x040e,"T":3,"F":0},"Total":{"R":0x0423,"T":8,"F":-3}} endon * * Example using default Energy registers and some user defined registers: * rule3 on file#modbus do {"Name":"SDM72","Baud":9600,"Config":8N1","Address":0x01,"Function":0x04,"Power":0x0034,"Total":0x0156,"ExportActive":0x004A,"User":[{"R":0x0502,"J":"ImportActive","G":"Import Active","U":"kWh","D":24},{"R":0x0502,"J":"ExportPower","G":"Export Power","U":"W","D":23},{"R":0x0500,"J":"ImportPower","G":"Import Power","U":"W","D":23}]} endon * rule3 on file#modbus do {"Name":"SDM120","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":0,"Current":6,"Power":12,"ApparentPower":18,"ReactivePower":24,"Factor":30,"Frequency":70,"Total":342,"ExportActive":0x004A,"User":[{"R":0x0048,"J":"ImportActive","G":"Import Active","U":"kWh","D":24},{"R":0x004E,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":24},{"R":0x004C,"J":"ImportReactive","G":"Import Reactive","U":"kVArh","D":24},{"R":0x0024,"J":"PhaseAngle","G":"Phase Angle","U":"Deg","D":2}]} endon * rule3 on file#modbus do {"Name":"SDM230 with two user registers","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":0,"Current":6,"Power":12,"ApparentPower":18,"ReactivePower":24,"Factor":30,"Frequency":70,"Total":342,"ExportActive":0x004A,"User":[{"R":0x004E,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":3},{"R":0x0024,"J":"PhaseAngle","G":"Phase Angle","U":"Deg","D":2}]} endon * rule3 on file#modbus do {"Name":"SDM630","Baud":9600,"Config":8N1","Address":1,"Function":4,"Voltage":[0,2,4],"Current":[6,8,10],"Power":[12,14,16],"ApparentPower":[18,20,22],"ReactivePower":[24,26,28],"Factor":[30,32,34],"Frequency":70,"Total":342,"ExportActive":[352,354,356],"User":{"R":[346,348,350],"J":"ImportActive","G":"Import Active","U":"kWh","D":24}} endon - * rule3 on file#modbus do {"Name":"X3MIC","Baud":9600,"Config":8N1","Address":1,"Function":4,"Voltage":{"R":0x0404,"T":3,"F":-1},"Power":{"R":0x040e,"T":3,"F":0},"Total":{"R":0x0423,"T":8,"F":-3}} endon * * Note: * - To enter long rules using the serial console and solve error "Serial buffer overrun" you might need to enlarge the serial input buffer with command serialbuffer 800 * - Changes to rule file are only executed on restart * * Restrictions: - * - Supports Modbus floating point registers + * - Supports Modbus single and double integer registers in addition to floating point registers * - Max number of user defined registers is defined by one rule buffer (511 characters uncompressed, around 800 characters compressed) * * To do: * - Support all three rule slots * - Support other modbus register like integers + * - Support multiple devices on modbus * * Test set: * rule3 on file#modbus do {"Name":"SDM230 test1","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":[0,0,0],"Current":[6,6,6],"Power":[12,12,12],"ApparentPower":[18,18,18],"ReactivePower":[24,24,24],"Factor":[30,30,30],"Frequency":[70,70,70],"Total":[342,342,342]} endon @@ -166,17 +168,17 @@ //#define ENERGY_MODBUS_DEBUG //#define ENERGY_MODBUS_DEBUG_SHOW -const uint16_t nrg_mbs_reg_not_used = 1; // Odd number 1 is unused register +const uint16_t nrg_mbs_reg_not_used = 0xFFFF; // Odd number 65535 is unused register -enum EnergyModbusDataType { NRG_DT_FLOAT, // 4-byte float - NRG_DT_S16, // 2-byte signed - NRG_DT_S32, // 4-byte signed - NRG_DT_U16, // 2-byte unsigned - NRG_DT_U32, // 4-byte unsigned - NRG_DT_x16_nu1, - NRG_DT_S32_SW, // 4-byte signed with swapped words - NRG_DT_x16_nu2, - NRG_DT_U32_SW, // 4-byte unsigned with swapped words +enum EnergyModbusDataType { NRG_DT_FLOAT, // 0 = 4-byte float + NRG_DT_S16, // 1 = 2-byte signed + NRG_DT_S32, // 2 = 4-byte signed + NRG_DT_U16, // 3 = 2-byte unsigned + NRG_DT_U32, // 4 = 4-byte unsigned + NRG_DT_x16_nu1, // 5 = + NRG_DT_S32_SW, // 6 = 4-byte signed with swapped words + NRG_DT_x16_nu2, // 7 = + NRG_DT_U32_SW, // 8 = 4-byte unsigned with swapped words NRG_DT_MAX }; enum EnergyModbusResolutions { NRG_RES_VOLTAGE = 21, // V From 234d6e20e0d09e93153997e0c5a1512cb4df7ddd Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 23 Dec 2022 16:56:18 +0100 Subject: [PATCH 047/262] Extent Generic Energy Modbus Driver - Add support for up to 3 single phase modbus energy monitoring device using generic Energy Modbus driver --- CHANGELOG.md | 1 + RELEASENOTES.md | 2 +- .../tasmota_xnrg_energy/xnrg_29_modbus.ino | 76 +++++++++++++++---- 3 files changed, 65 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 234ca510c..d108e9e54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ All notable changes to this project will be documented in this file. - Berry crypto add ``EC_P256`` and ``PBKDF2_HMAC_SHA256`` algorithms required by Matter protocol - Berry crypto add ``random`` to generate series of random bytes - Berry crypto add ``HKDF_HMAC_SHA256`` +- Support for up to 3 single phase modbus energy monitoring device using generic Energy Modbus driver ### Breaking Changed diff --git a/RELEASENOTES.md b/RELEASENOTES.md index ba466d12c..cd293173a 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -109,7 +109,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm ## Changelog v12.3.1.2 ### Added -- Support for RGB displays [#17414](https://github.com/arendst/Tasmota/issues/17414) +- Support for up to 3 single phase modbus energy monitoring device using generic Energy Modbus driver- Support for RGB displays [#17414](https://github.com/arendst/Tasmota/issues/17414) - Support for IPv6 DNS records (AAAA) and IPv6 ``Ping`` for ESP32 and ESP8266 [#17417](https://github.com/arendst/Tasmota/issues/17417) - Berry support for ``crypto.SHA256`` [#17430](https://github.com/arendst/Tasmota/issues/17430) - Berry crypto add ``EC_P256`` and ``PBKDF2_HMAC_SHA256`` algorithms required by Matter protocol [#17473](https://github.com/arendst/Tasmota/issues/17473) diff --git a/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino b/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino index ade3ef466..6cf554af4 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino @@ -22,16 +22,17 @@ /*********************************************************************************************\ * Generic Modbus energy meter * - * Using a rule file called modbus allows to easy configure modbus energy monitor devices up to three phases. + * - Supports single three phase device or three single phase devices of same model on bus. + * - Uses a rule file called modbus allowing for easy configuration of modbus energy monitor device(s). * * Value pair description: * {"Name":"SDM230","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":0,"Current":6,"Power":12,"ApparentPower":18,"ReactivePower":24,"Factor":30,"Frequency":70,"Total":342,"ExportActive":0x004A} * Modbus config parameters: - * Name - Name of energy monitoring device + * Name - Name of energy monitoring device(s) * Baud - Baudrate of device modbus interface - optional. default is 9600 * Config - Serial config parameters like 8N1 - 8 databits, No parity, 1 stop bit - * Address - Modbus device address entered as decimal (1) or hexadecimal (0x01)) - optional default = 1 - * Function - Modbus function code to access two registers - optional. default = 4 + * Address - Modbus device address entered as decimal (1) or hexadecimal (0x01) or up to three addresses ([1,2,3]) - optional. default = 1 + * Function - Modbus function code to access registers - optional. default = 4 * Tasmota default embedded register names: * Voltage - Voltage register entered as decimal or hexadecimal for one phase (0x0000) or up to three phases ([0x0000,0x0002,0x0004]) or * Additional defined parameters @@ -120,6 +121,7 @@ * rule3 on file#modbus do {"Name":"SDM230 with hex registers","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":0x0000,"Current":0x0006,"Power":0x000C,"ApparentPower":0x0012,"ReactivePower":0x0018,"Factor":0x001E,"Frequency":0x0046,"Total":0x0156,"ExportActive":0x004A} endon * rule3 on file#modbus do {"Name":"DDSU666","Baud":9600,"Config":8N1","Address":1,"Function":4,"Voltage":0x2000,"Current":0x2002,"Power":0x2004,"ReactivePower":0x2006,"Factor":0x200A,"Frequency":0x200E,"Total":0x4000,"ExportActive":0x400A} endon * rule3 on file#modbus do {"Name":"PZEM014","Baud":9600,"Config":8N1","Address":1,"Function":4,"Voltage":{"R":0,"T":3,"F":-1},"Current":{"R":1,"T":8,"F":-3},"Power":{"R":3,"T":8,"F":-1},"Factor":{"R":8,"T":3,"F":-2},"Frequency":{"R":7,"T":3,"F":-1},"Total":{"R":5,"T":8,"F":-3}} endon + * rule3 on file#modbus do {"Name":"3 x PZEM014","Baud":9600,"Config":8N1","Address":[1,2,3],"Function":4,"Voltage":{"R":0,"T":3,"F":-1},"Current":{"R":1,"T":8,"F":-3},"Power":{"R":3,"T":8,"F":-1},"Factor":{"R":8,"T":3,"F":-2},"Frequency":{"R":7,"T":3,"F":-1},"Total":{"R":5,"T":8,"F":-3}} endon * rule3 on file#modbus do {"Name":"Solax X3MIC","Baud":9600,"Config":8N1","Address":1,"Function":4,"Voltage":{"R":0x0404,"T":3,"F":-1},"Power":{"R":0x040e,"T":3,"F":0},"Total":{"R":0x0423,"T":8,"F":-3}} endon * * Example using default Energy registers and some user defined registers: @@ -139,9 +141,9 @@ * To do: * - Support all three rule slots * - Support other modbus register like integers - * - Support multiple devices on modbus * * Test set: + * rule3 on file#modbus do {"Name":"3 x PZEM014","Baud":9600,"Config":8N1","Address":[1,1],"Function":4,"Voltage":{"R":0,"T":3,"F":-1},"Current":{"R":1,"T":8,"F":-3},"Power":{"R":3,"T":8,"F":-1},"Factor":{"R":8,"T":3,"F":-2},"Frequency":{"R":7,"T":3,"F":-1},"Total":{"R":5,"T":8,"F":-3}} endon * rule3 on file#modbus do {"Name":"SDM230 test1","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":[0,0,0],"Current":[6,6,6],"Power":[12,12,12],"ApparentPower":[18,18,18],"ReactivePower":[24,24,24],"Factor":[30,30,30],"Frequency":[70,70,70],"Total":[342,342,342]} endon * rule3 on file#modbus do {"Name":"SDM230 test2","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":[0,0,0],"Current":[6,6,6],"Power":[12,12,12],"ApparentPower":[18,18,18],"ReactivePower":[24,24,24],"Factor":[30,30,30],"Frequency":70,"Total":[342,342,342]} endon * rule3 on file#modbus do {"Name":"SDM230 test3","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":0,"Current":[6,6,6],"Power":[12,12,12],"ApparentPower":[18,18,18],"ReactivePower":[24,24,24],"Factor":[30,30,30],"Frequency":70,"Total":[342,342,342]} endon @@ -159,6 +161,7 @@ #define ENERGY_MODBUS_CONFIG TS_SERIAL_8N1 // Default Modbus serial configuration #define ENERGY_MODBUS_ADDR 1 // Default Modbus device_address #define ENERGY_MODBUS_FUNC 0x04 // Default Modbus function code +#define ENERGY_MODBUS_MAX_DEVICES ENERGY_MAX_PHASES // Support up to three single phase devices as three phases #define ENERGY_MODBUS_DATATYPE 0 // Default Modbus datatype is 4-byte float #define ENERGY_MODBUS_DECIMALS 0 // Default user decimal resolution @@ -170,14 +173,15 @@ const uint16_t nrg_mbs_reg_not_used = 0xFFFF; // Odd number 65535 is unused register +// Even data type is single (2-byte) register, Odd data type is double (4-byte) registers enum EnergyModbusDataType { NRG_DT_FLOAT, // 0 = 4-byte float NRG_DT_S16, // 1 = 2-byte signed NRG_DT_S32, // 2 = 4-byte signed NRG_DT_U16, // 3 = 2-byte unsigned NRG_DT_U32, // 4 = 4-byte unsigned - NRG_DT_x16_nu1, // 5 = + NRG_DT_x16_nu1, // 5 = 2-byte NRG_DT_S32_SW, // 6 = 4-byte signed with swapped words - NRG_DT_x16_nu2, // 7 = + NRG_DT_x16_nu2, // 7 = 2-byte NRG_DT_U32_SW, // 8 = 4-byte unsigned with swapped words NRG_DT_MAX }; @@ -224,7 +228,8 @@ Ticker ticker_energy_modbus; struct NRGMBSPARAM { uint32_t serial_bps; uint32_t serial_config; - uint8_t device_address; + uint8_t device_address[ENERGY_MODBUS_MAX_DEVICES]; + uint8_t devices; uint8_t function; uint8_t total_regs; uint8_t user_adds; @@ -267,6 +272,7 @@ void EnergyModbusLoop(void) { if (data_ready) { uint8_t buffer[15]; // At least 5 + (2 * 2) = 9 + // Even data type is single register, Odd data type is double registers register_count = 2 - (NrgMbsReg[NrgMbsParam.state].datatype & 1); uint32_t error = EnergyModbus->ReceiveBuffer(buffer, register_count); @@ -409,6 +415,7 @@ void EnergyModbusLoop(void) { } } + uint32_t phase = 0; do { NrgMbsParam.phase++; if (NrgMbsParam.phase >= Energy.phase_count) { @@ -422,19 +429,34 @@ void EnergyModbusLoop(void) { } } delay(0); - } while (NrgMbsReg[NrgMbsParam.state].address[NrgMbsParam.phase] == nrg_mbs_reg_not_used); + if (NrgMbsParam.devices == 1) { + phase = NrgMbsParam.phase; + } + } while (NrgMbsReg[NrgMbsParam.state].address[phase] == nrg_mbs_reg_not_used); } } // end data ready + + uint32_t address = 0; + uint32_t phase = NrgMbsParam.phase; + if (NrgMbsParam.devices > 1) { + address = NrgMbsParam.phase; + phase = 0; + } if (0 == NrgMbsParam.retry || data_ready) { NrgMbsParam.retry = 1; + // Even data type is single register, Odd data type is double registers register_count = 2 - (NrgMbsReg[NrgMbsParam.state].datatype & 1); - EnergyModbus->Send(NrgMbsParam.device_address, NrgMbsParam.function, NrgMbsReg[NrgMbsParam.state].address[NrgMbsParam.phase], register_count); + EnergyModbus->Send(NrgMbsParam.device_address[address], NrgMbsParam.function, NrgMbsReg[NrgMbsParam.state].address[phase], register_count); } else { NrgMbsParam.retry--; #ifdef ENERGY_MODBUS_DEBUG - AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Modbus state %d retry %d"), NrgMbsParam.state, NrgMbsParam.retry); + if (NrgMbsParam.devices > 1) { + AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Modbus retry device %d state %d"), NrgMbsParam.device_address[address], NrgMbsParam.state); + } else { + AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Modbus retry state %d phase %d"), NrgMbsParam.state, NrgMbsParam.phase); + } #endif } @@ -463,6 +485,7 @@ bool EnergyModbusReadUserRegisters(JsonParserObject user_add_value, uint32_t add return false; } if (phase > Energy.phase_count) { + NrgMbsParam.devices = 1; Energy.phase_count = phase; } val = user_add_value[PSTR("T")]; // Register data type @@ -544,9 +567,11 @@ bool EnergyModbusReadRegisters(void) { if (!root) { return false; } // Invalid JSON // Init defaults + Energy.phase_count = 1; NrgMbsParam.serial_bps = ENERGY_MODBUS_SPEED; NrgMbsParam.serial_config = ENERGY_MODBUS_CONFIG; - NrgMbsParam.device_address = ENERGY_MODBUS_ADDR; + NrgMbsParam.device_address[0] = ENERGY_MODBUS_ADDR; + NrgMbsParam.devices = 1; NrgMbsParam.function = ENERGY_MODBUS_FUNC; NrgMbsParam.user_adds = 0; @@ -598,7 +623,23 @@ bool EnergyModbusReadRegisters(void) { } val = root[PSTR("Address")]; if (val) { - NrgMbsParam.device_address = val.getUInt(); // 1 + +// NrgMbsParam.device_address = val.getUInt(); // 1 + + NrgMbsParam.devices = 0; + if (val.isArray()) { + // "Address":[1,2,3] + JsonParserArray arr = val.getArray(); + for (auto value : arr) { + NrgMbsParam.device_address[NrgMbsParam.devices] = value.getUInt(); // 1 + NrgMbsParam.devices++; + if (NrgMbsParam.devices >= ENERGY_MODBUS_MAX_DEVICES) { break; } + } + } else if (val) { + // "Address":1 + NrgMbsParam.device_address[0] = val.getUInt(); + NrgMbsParam.devices++; + } } val = root[PSTR("Function")]; if (val) { @@ -669,6 +710,7 @@ bool EnergyModbusReadRegisters(void) { phase++; } if (phase > Energy.phase_count) { + NrgMbsParam.devices = 1; Energy.phase_count = phase; } switch(names) { @@ -736,8 +778,16 @@ bool EnergyModbusReadRegisters(void) { NrgMbsReg[i].datatype = ENERGY_MODBUS_DATATYPE; } } + if (NrgMbsParam.devices > 1) { + Energy.phase_count = NrgMbsParam.devices; + Energy.voltage_common = false; // Use no common voltage + Energy.frequency_common = false; // Use no common frequency + Settings->flag5.energy_phase = 1; // SetOption129 - (Energy) Show phase information + } #ifdef ENERGY_MODBUS_DEBUG + AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Devices %d"), NrgMbsParam.devices); + AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: RAM usage %d + %d + %d"), sizeof(NrgMbsParam), NrgMbsParam.total_regs * sizeof(NrgMbsRegister_t), NrgMbsParam.user_adds * sizeof(NrgMbsUser_t)); #endif From f5f7ff4fb8f7c30fa2c3bf07e19daeb8872f54d9 Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Fri, 23 Dec 2022 18:31:19 +0100 Subject: [PATCH 048/262] Minor changes to Berry crypto (#17494) --- .../berry_tasmota/src/be_crypto_lib.c | 14 +++---- lib/libesp32/berry_tasmota/src/be_md5_lib.c | 5 ++- tasmota/my_user_config.h | 2 +- .../xdrv_52_3_berry_crypto.ino | 38 +++++++++---------- 4 files changed, 29 insertions(+), 30 deletions(-) diff --git a/lib/libesp32/berry_tasmota/src/be_crypto_lib.c b/lib/libesp32/berry_tasmota/src/be_crypto_lib.c index b38c3c092..3f790bd4e 100644 --- a/lib/libesp32/berry_tasmota/src/be_crypto_lib.c +++ b/lib/libesp32/berry_tasmota/src/be_crypto_lib.c @@ -40,7 +40,7 @@ extern int m_hmac_sha256_out(bvm *vm); extern int m_pbkdf2_hmac_sha256_f(bvm *vm); -extern int m_hkdf_hmac_sha256_derive(bvm *vm); +extern int m_hkdf_sha256_derive(bvm *vm); extern const bclass be_class_md5; @@ -53,7 +53,7 @@ extern const bclass be_class_md5; #include "be_fixed_be_class_sha256.h" #include "be_fixed_be_class_hmac_sha256.h" #include "be_fixed_be_class_pbkdf2_hmac_sha256.h" -#include "be_fixed_be_class_hkdf_hmac_sha256.h" +#include "be_fixed_be_class_hkdf_sha256.h" #include "be_fixed_crypto.h" const be_const_member_t be_crypto_members[] = { @@ -75,9 +75,9 @@ const be_const_member_t be_crypto_members[] = { { "/EC_P256", (intptr_t) &be_class_ec_p256 }, #endif // USE_BERRY_CRYPTO_EC_P256 -#ifdef USE_BERRY_CRYPTO_HKDF_HMAC_SHA256 - { "/HKDF_HMAC_SHA256", (intptr_t) &be_class_hkdf_hmac_sha256 }, -#endif // USE_BERRY_CRYPTO_HKDF_HMAC_SHA256 +#ifdef USE_BERRY_CRYPTO_HKDF_SHA256 + { "/HKDF_SHA256", (intptr_t) &be_class_hkdf_sha256 }, +#endif // USE_BERRY_CRYPTO_HKDF_SHA256 #ifdef USE_BERRY_CRYPTO_HMAC_SHA256 { "/HMAC_SHA256", (intptr_t) &be_class_hmac_sha256 }, @@ -152,8 +152,8 @@ class be_class_pbkdf2_hmac_sha256 (scope: global, name: PBKDF2_HMAC_SHA256) { derive, closure(PBKDF2_HMAC_SHA256_closure) } -class be_class_hkdf_hmac_sha256 (scope: global, name: HKDF_HMAC_SHA256) { - derive, static_func(m_hkdf_hmac_sha256_derive) +class be_class_hkdf_sha256 (scope: global, name: HKDF_SHA256) { + derive, static_func(m_hkdf_sha256_derive) } module crypto (scope: global) { diff --git a/lib/libesp32/berry_tasmota/src/be_md5_lib.c b/lib/libesp32/berry_tasmota/src/be_md5_lib.c index 109003422..b800cc37c 100644 --- a/lib/libesp32/berry_tasmota/src/be_md5_lib.c +++ b/lib/libesp32/berry_tasmota/src/be_md5_lib.c @@ -25,7 +25,7 @@ int m_md5_init(bvm *vm) { be_return_nil(vm); } -// `Md5.update(content:bytes()) -> nil` +// `Md5.update(content:bytes()) -> self` // // Add raw bytes to the MD5 calculation int m_md5_update(bvm *vm); @@ -45,7 +45,8 @@ int m_md5_update(bvm *vm) { if (length > 0) { esp_rom_md5_update(ctx, (const uint8_t*) bytes, length); } - be_return_nil(vm); + be_pushvalue(vm, 1); + be_return(vm); // success } while (0); } diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index feea40b0f..ac6d4372f 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -1112,7 +1112,7 @@ #define USE_BERRY_CRYPTO_SHA256 // enable SHA256 hash function #define USE_BERRY_CRYPTO_HMAC_SHA256 // enable HMAC SHA256 hash function // #define USE_BERRY_CRYPTO_PBKDF2_HMAC_SHA256 // PBKDF2 with HMAC SHA256, used in Matter protocol - // #define USE_BERRY_CRYPTO_HKDF_HMAC_SHA256 // HKDF with HMAC SHA256, used in Matter protocol + // #define USE_BERRY_CRYPTO_HKDF_SHA256 // HKDF with HMAC SHA256, used in Matter protocol #define USE_CSE7761 // Add support for CSE7761 Energy monitor as used in Sonoff Dual R3 // -- LVGL Graphics Library --------------------------------- diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino index a07e5a649..6eba535ab 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino @@ -213,8 +213,8 @@ extern "C" { be_raise(vm, kTypeError, nullptr); } - // `.encrypt(content:bytes(), in:bytes(12), counter:int) -> nil` - // `.decrypt(content:bytes(), in:bytes(12), counter:int) -> nil` + // `.encrypt(content:bytes(), in:bytes(12), counter:int) -> bytes()` + // `.decrypt(content:bytes(), in:bytes(12), counter:int) -> bytes()` int32_t m_aes_ctr_run(bvm *vm); int32_t m_aes_ctr_run(bvm *vm) { int32_t argc = be_top(vm); // Get the number of arguments @@ -273,7 +273,7 @@ extern "C" { be_return_nil(vm); } - // `.update(content:bytes()) -> nil` + // `.update(content:bytes()) -> self` // // Add raw bytes to the hash calculation int32_t m_hash_sha256_update(struct bvm *vm); @@ -295,7 +295,8 @@ extern "C" { if (length > 0) { br_sha256_update(ctx, bytes, length); } - be_return_nil(vm); + be_pushvalue(vm, 1); // return self + be_return(vm); // success } while (0); } @@ -347,7 +348,7 @@ extern "C" { be_raise(vm, kTypeError, nullptr); } - // `.update(content:bytes()) -> nil` + // `.update(content:bytes()) -> self` // // Add raw bytes to the hash calculation int32_t m_hmac_sha256_update(struct bvm *vm); @@ -368,7 +369,8 @@ extern "C" { if (length > 0) { br_hmac_update(ctx, bytes, length); } - be_return_nil(vm); + be_pushvalue(vm, 1); // return self + be_return(vm); // success } while (0); } @@ -397,7 +399,7 @@ extern "C" { \*********************************************************************************************/ #define BR_EC_P256_IMPL br_ec_p256_m15 // BearSSL implementation for Curve P256 extern "C" { - // crypto.EC_P256().public_key(private_key:bytes(32)) -> bytes(32) + // crypto.EC_P256().public_key(private_key:bytes(32)) -> bytes(65) // Computes the public key from a completely random private key of 32 bytes int32_t m_ec_p256_pubkey(bvm *vm); int32_t m_ec_p256_pubkey(bvm *vm) { @@ -420,7 +422,7 @@ extern "C" { be_raise(vm, kTypeError, nullptr); } - // crypto.EC_P256().shared_key(my_private_key:bytes(32), their_public_key:bytes(32)) -> bytes(32) + // crypto.EC_P256().shared_key(my_private_key:bytes(32), their_public_key:bytes(65)) -> bytes(32) // Computes the shared pre-key. Normally this shared pre-key is hashed with another algorithm. int32_t m_ec_p256_sharedkey(bvm *vm); int32_t m_ec_p256_sharedkey(bvm *vm) { @@ -535,10 +537,6 @@ extern "C" { be_raise(vm, kTypeError, nullptr); } - uint32_t (*muladd)(unsigned char *A, const unsigned char *B, size_t len, - const unsigned char *x, size_t xlen, - const unsigned char *y, size_t ylen, int curve); - // crypto.EC_P256().mul(x:bytes(), A:bytes(65)) -> bytes(65)` // // The point `x*A` is computed. @@ -674,14 +672,14 @@ extern "C" { } /*********************************************************************************************\ - * HKDF_HMAC_SHA256 + * HKDF_SHA256 * \*********************************************************************************************/ extern "C" { - // crypto.HKDF_HMAC_SHA256().derive(ikm:bytes(), salt:bytes(), info:bytes(), out_bytes:int) -> bytes(out_bytes) - // Derive key with HKDF based on HMAC SHA256 - int32_t m_hkdf_hmac_sha256_derive(bvm *vm); - int32_t m_hkdf_hmac_sha256_derive(bvm *vm) { + // crypto.HKDF_SHA256().derive(ikm:bytes(), salt:bytes(), info:bytes(), out_bytes:int) -> bytes(out_bytes) + // Derive key with HKDF based on SHA256 + int32_t m_hkdf_sha256_derive(bvm *vm); + int32_t m_hkdf_sha256_derive(bvm *vm) { int32_t argc = be_top(vm); // Get the number of arguments if (argc >= 4 && be_isbytes(vm, 1) && be_isbytes(vm, 2) && be_isbytes(vm, 3) && be_isint(vm, 4)) { size_t ikm_len; @@ -716,7 +714,7 @@ extern "C" { import crypto # Test Case 1 -hk = crypto.HKDF_HMAC_SHA256() +hk = crypto.HKDF_SHA256() ikm = bytes("0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B") salt = bytes("000102030405060708090A0B0C") info = bytes("F0F1F2F3F4F5F6F7F8F9") @@ -724,7 +722,7 @@ k = hk.derive(ikm, salt, info, 42) assert(k == bytes("3CB25F25FAACD57A90434F64D0362F2A2D2D0A90CF1A5A4C5DB02D56ECC4C5BF34007208D5B887185865")) # Test Case 2 -hk = crypto.HKDF_HMAC_SHA256() +hk = crypto.HKDF_SHA256() ikm = bytes("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f") salt = bytes("606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf") info = bytes("b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff") @@ -732,7 +730,7 @@ k = hk.derive(ikm, salt, info, 82) assert(k == bytes("b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c59045a99cac7827271cb41c65e590e09da3275600c2f09b8367793a9aca3db71cc30c58179ec3e87c14c01d5c1f3434f1d87")) # Test Case 3 -hk = crypto.HKDF_HMAC_SHA256() +hk = crypto.HKDF_SHA256() ikm = bytes("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b") salt = bytes() info = bytes() From 1832c4b2f0c436612326369490479de6540921cc Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Fri, 23 Dec 2022 19:40:12 +0100 Subject: [PATCH 049/262] Berry crypto add ``SPAKE2P_Matter`` for Matter support (#17497) --- CHANGELOG.md | 1 + .../berry_tasmota/src/be_crypto_lib.c | 16 + .../src/embedded/crypto_spake2p_matter.be | 210 ++++++ .../solidified_crypto_spake2p_matter.h | 657 ++++++++++++++++++ tasmota/my_user_config.h | 1 + 5 files changed, 885 insertions(+) create mode 100644 lib/libesp32/berry_tasmota/src/embedded/crypto_spake2p_matter.be create mode 100644 lib/libesp32/berry_tasmota/src/solidify/solidified_crypto_spake2p_matter.h diff --git a/CHANGELOG.md b/CHANGELOG.md index d108e9e54..269a775d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ All notable changes to this project will be documented in this file. - Berry crypto add ``random`` to generate series of random bytes - Berry crypto add ``HKDF_HMAC_SHA256`` - Support for up to 3 single phase modbus energy monitoring device using generic Energy Modbus driver +- Berry crypto add ``SPAKE2P_Matter`` for Matter support ### Breaking Changed diff --git a/lib/libesp32/berry_tasmota/src/be_crypto_lib.c b/lib/libesp32/berry_tasmota/src/be_crypto_lib.c index 3f790bd4e..43122303e 100644 --- a/lib/libesp32/berry_tasmota/src/be_crypto_lib.c +++ b/lib/libesp32/berry_tasmota/src/be_crypto_lib.c @@ -45,6 +45,7 @@ extern int m_hkdf_sha256_derive(bvm *vm); extern const bclass be_class_md5; #include "solidify/solidified_crypto_pbkdf2_hmac_sha256.h" +#include "solidify/solidified_crypto_spake2p_matter.h" #include "be_fixed_be_class_aes_gcm.h" #include "be_fixed_be_class_aes_ctr.h" @@ -56,6 +57,16 @@ extern const bclass be_class_md5; #include "be_fixed_be_class_hkdf_sha256.h" #include "be_fixed_crypto.h" +// Enable all the crypto required by Matter +#ifdef USE_BERRY_CRYPTO_SPAKE2P_MATTER + #undef USE_BERRY_CRYPTO_EC_P256 + #define USE_BERRY_CRYPTO_EC_P256 + #undef USE_BERRY_CRYPTO_HMAC_SHA256 + #define USE_BERRY_CRYPTO_HMAC_SHA256 + #undef USE_BERRY_CRYPTO_HKDF_SHA256 + #define USE_BERRY_CRYPTO_HKDF_SHA256 +#endif + const be_const_member_t be_crypto_members[] = { // name with prefix '/' indicates a Berry class // entries need to be sorted (ignoring the prefix char) @@ -92,6 +103,11 @@ const be_const_member_t be_crypto_members[] = { #ifdef USE_BERRY_CRYPTO_SHA256 { "/SHA256", (intptr_t) &be_class_sha256 }, #endif // USE_BERRY_CRYPTO_SHA256 + +#ifdef USE_BERRY_CRYPTO_SPAKE2P_MATTER + { "/SPAKE2P_Matter", (intptr_t) &be_class_SPAKE2P_Matter }, +#endif // USE_BERRY_CRYPTO_SPAKE2P_MATTER + }; const size_t be_crypto_members_size = sizeof(be_crypto_members)/sizeof(be_crypto_members[0]); diff --git a/lib/libesp32/berry_tasmota/src/embedded/crypto_spake2p_matter.be b/lib/libesp32/berry_tasmota/src/embedded/crypto_spake2p_matter.be new file mode 100644 index 000000000..4a58aad0d --- /dev/null +++ b/lib/libesp32/berry_tasmota/src/embedded/crypto_spake2p_matter.be @@ -0,0 +1,210 @@ +# SPAKE2+ with Matter 1.0 specification +# +# Real name is SPAKE2+-P256-SHA256-HKDF-SHA256-HMAC-SHA256 +# but we'll use SPAKE2P_Matter as a shorter name +# +# To start SPAKE2+, we need either w0/w1 for the prover (Matter Gateway) +# or w0/L for the verifier (end-device). +# The end-device can store in flash pre-computed values for w0/L. +# +# In this class we consider w0/w1/L to be computerd before using this class + +#@ solidify:SPAKE2P_Matter,weak +class SPAKE2P_Matter + # computed values from above + var w0 # w0 + var w1 + var L + var pA, pB, Z, V + var x, y + # var TT + var Kmain + var KcA, KcB, K_shared + var cA, cB + # Matter values for key generation + var A, B, Context + # values from the Matter specification + static var CRYPTO_GROUP_SIZE_BYTES = 32 + static var CRYPTO_W_SIZE_BYTES = 40 # CRYPTO_GROUP_SIZE_BYTES + 8 + static var spake_M_hex = "04886e2f97ace46e55ba9dd7242579f2993b64e16ef3dcab95afd497333d8fa12f5ff355163e43ce224e0b0e65ff02ac8e5c7be09419c785e0ca547d55a12e2d20" + static var spake_N_hex = "04d8bbd6c639c62937b04d997f38c3770719c629d7014d49a24b4f98baa1292b4907d60aa6bfade45008a636337f5168c64d9bd36034808cd564490b1e656edbe7" + var M, N # due to the nature of solification, we can't solidify the bytes versions nor store as static variable + + # Initialize the SPAKE2+ class with required value. + # We need either w0/w1 for the gateway or w0/L for the end-device + def init(w0, w1, L) + self.M = bytes().fromhex(self.spake_M_hex) + self.N = bytes().fromhex(self.spake_N_hex) + # set w0/w1/L + self.w0 = w0 + self.w1 = w1 + self.L = L +end + + # compute the shared values pA (done by Matter gateway) + # w0 must be known + # x is a random 32 bytes vector. It does not need to be lower than the order (we take the modulus anyways) + # + # if `x` is nil, we take a random vector, otherwise it must be byytes(32) + def compute_pA(x) + import crypto + if x == nil x = crypto.random(32) end + var ec = crypto.EC_P256() + self.x = ec.mod(x) + self.pA = ec.muladd(self.w0, self.M, self.x, bytes() #- empty means generator -#) # compute x*P+w0*M + end + + # compute the shared values pB (done by Matter end-device) + # w0 must be known + # y is a random 32 bytes vector. It does not need to be lower than the order (we take the modulus anyways) + def compute_pB(y) + import crypto + if y == nil y = crypto.random(32) end + var ec = crypto.EC_P256() + self.y = ec.mod(y) + self.pB = ec.muladd(self.w0, self.N, self.y, bytes() #- empty means generator -#) # compute y*P+w0*M + end + + # compute Z and V for the Prover (Gateway), receiving pB from the verifier (end-device) + # pB must be bytes(65) + # x must be known + def compute_ZV_prover(pB) + import crypto + var ec = crypto.EC_P256() + self.pB = pB + # we are supposed to check that the point is on the curve -- TODO + # we need a substraction so we negate w0 + var w0_neg = ec.neg(self.w0) + var t_inner = ec.muladd(bytes("01"), self.pB, w0_neg, self.N) # compute 1*pB-w0*N + self.Z = ec.mul(self.x, t_inner) + self.V = ec.mul(self.w1, t_inner) + end + + # compute Z and V for the Verifier (end-device), receiving pA from the prover (Gateway) + # pA must be bytes(65) + # y must be known + def compute_ZV_verifier(pA) + import crypto + var ec = crypto.EC_P256() + self.pA = pA + # we are supposed to check that the point is on the curve -- TODO + # we need a substraction so we negate w0 + var w0_neg = ec.neg(self.w0) + var t_inner = ec.muladd(bytes("01"), self.pA, w0_neg, self.M) # compute 1*pA-w0*M + self.Z = ec.mul(self.y, t_inner) + self.V = ec.mul(self.y, self.L) + end + + # Set context, prover and verifier identitites (last 2 can be empty) + def set_context(context, prover, verifier) + if prover == nil prover = bytes() end + if verifier == nil verifier = bytes() end + self.Context = context + self.A = prover + self.B = verifier + end + + # Need to know "Context, pA, pB, Z, V, w0" + # + def compute_TT_hash() + class SPAKE_Hasher + var hash + # var complete # complete value for the bytes -- will be removed in production code + def init() + import crypto + self.hash = crypto.SHA256() + # self.complete = bytes() + end + # add v (bytes) to the hash + def add_item(v) + var len = v.size() + var len_bin = bytes().add(len, 4).add(0, 4) + # self.complete += len_bin + # self.complete += v + self.hash.update(len_bin) + self.hash.update(v) + end + def out() + return self.hash.out() + end + end + import crypto + var hasher = SPAKE_Hasher() + + # Context + hasher.add_item(self.Context) + hasher.add_item(self.A) + hasher.add_item(self.B) + hasher.add_item(self.M) + hasher.add_item(self.N) + hasher.add_item(self.pA) + hasher.add_item(self.pB) + hasher.add_item(self.Z) + hasher.add_item(self.V) + hasher.add_item(self.w0) + + # self.TT = hasher.complete + self.Kmain = hasher.out() + + # compute KcA and KcB + var kdf = crypto.HKDF_SHA256() + var KPV = kdf.derive(self.Kmain, bytes(), bytes().fromstring("ConfirmationKeys"), 64) + self.KcA = KPV[0..31] + self.KcB = KPV[32..63] + self.K_shared = kdf.derive(self.Kmain, bytes(), bytes().fromstring("SharedKey"), 32) + + self.cA = crypto.HMAC_SHA256(self.KcA).update(self.pB).out() + self.cB = crypto.HMAC_SHA256(self.KcB).update(self.pA).out() + end +end + + +#- +# ====================================================================== +# Example from SPAKE2P test vectors +# https://chris-wood.github.io/draft-bar-cfrg-spake2plus/draft-bar-cfrg-spake2plus.html + +import crypto +var w0 = bytes("bb8e1bbcf3c48f62c08db243652ae55d3e5586053fca77102994f23ad95491b3") +var w1 = bytes("7e945f34d78785b8a3ef44d0df5a1a97d6b3b460409a345ca7830387a74b1dba") +var L = bytes("04eb7c9db3d9a9eb1f8adab81b5794c1f13ae3e225efbe91ea487425854c7fc00f00bfedcbd09b2400142d40a14f2064ef31dfaa903b91d1faea7093d835966efd") +var spake_matter = crypto.SPAKE2P_Matter(w0, w1, L) + +# context values +var Context = bytes().fromstring('SPAKE2+-P256-SHA256-HKDF-SHA256-HMAC-SHA256 Test Vectors') +var Prover = bytes().fromstring('client') +var Verifier = bytes().fromstring('server') +spake_matter.set_context(Context, Prover, Verifier) + +# x is supposed to be random 32 bytes, test vector sets it +var x = bytes("d1232c8e8693d02368976c174e2088851b8365d0d79a9eee709c6a05a2fad539") +spake_matter.compute_pA(x) +assert(spake_matter.pA == bytes('04EF3BD051BF78A2234EC0DF197F7828060FE9856503579BB1733009042C15C0C1DE127727F418B5966AFADFDD95A6E4591D171056B333DAB97A79C7193E341727')) + +# y is supposed to be random 32 bytes, test vector sets it +var y = bytes("717a72348a182085109c8d3917d6c43d59b224dc6a7fc4f0483232fa6516d8b3") +spake_matter.compute_pB(y) +assert(spake_matter.pB == bytes('04C0F65DA0D11927BDF5D560C69E1D7D939A05B0E88291887D679FCADEA75810FB5CC1CA7494DB39E82FF2F50665255D76173E09986AB46742C798A9A68437B048')) + +spake_matter.compute_ZV_prover(spake_matter.pB) +assert(spake_matter.Z == bytes('04BBFCE7DD7F277819C8DA21544AFB7964705569BDF12FB92AA388059408D50091A0C5F1D3127F56813B5337F9E4E67E2CA633117A4FBD559946AB474356C41839')) +assert(spake_matter.V == bytes('0458BF27C6BCA011C9CE1930E8984A797A3419797B936629A5A937CF2F11C8B9514B82B993DA8A46E664F23DB7C01EDC87FAA530DB01C2EE405230B18997F16B68')) + +spake_matter.compute_ZV_verifier(spake_matter.pA) +assert(spake_matter.Z == bytes('04BBFCE7DD7F277819C8DA21544AFB7964705569BDF12FB92AA388059408D50091A0C5F1D3127F56813B5337F9E4E67E2CA633117A4FBD559946AB474356C41839')) +assert(spake_matter.V == bytes('0458BF27C6BCA011C9CE1930E8984A797A3419797B936629A5A937CF2F11C8B9514B82B993DA8A46E664F23DB7C01EDC87FAA530DB01C2EE405230B18997F16B68')) + +spake_matter.compute_TT_hash() + +assert(spake_matter.Kmain == bytes('4c59e1ccf2cfb961aa31bd9434478a1089b56cd11542f53d3576fb6c2a438a29')) + +assert(spake_matter.KcA == bytes('871ae3f7b78445e34438fb284504240239031c39d80ac23eb5ab9be5ad6db58a')) +assert(spake_matter.KcB == bytes('ccd53c7c1fa37b64a462b40db8be101cedcf838950162902054e644b400f1680')) + +assert(spake_matter.cA == bytes('926cc713504b9b4d76c9162ded04b5493e89109f6d89462cd33adc46fda27527')) +assert(spake_matter.cB == bytes('9747bcc4f8fe9f63defee53ac9b07876d907d55047e6ff2def2e7529089d3e68')) +assert(spake_matter.K_shared == bytes('0c5f8ccd1413423a54f6c1fb26ff01534a87f893779c6e68666d772bfd91f3e7')) + +print("SPAKE2P Matter all tests passed") + +-# \ No newline at end of file diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_crypto_spake2p_matter.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_crypto_spake2p_matter.h new file mode 100644 index 000000000..25cc77c07 --- /dev/null +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_crypto_spake2p_matter.h @@ -0,0 +1,657 @@ +/* Solidification of crypto_spake2p_matter.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +/******************************************************************** +** Solidified function: set_context +********************************************************************/ +be_local_closure(SPAKE2P_Matter_set_context, /* name */ + be_nested_proto( + 5, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(Context), + /* K1 */ be_nested_str_weak(A), + /* K2 */ be_nested_str_weak(B), + }), + be_str_weak(set_context), + &be_const_str_solidified, + ( &(const binstruction[16]) { /* code */ + 0x4C100000, // 0000 LDNIL R4 + 0x1C100404, // 0001 EQ R4 R2 R4 + 0x78120002, // 0002 JMPF R4 #0006 + 0x60100015, // 0003 GETGBL R4 G21 + 0x7C100000, // 0004 CALL R4 0 + 0x5C080800, // 0005 MOVE R2 R4 + 0x4C100000, // 0006 LDNIL R4 + 0x1C100604, // 0007 EQ R4 R3 R4 + 0x78120002, // 0008 JMPF R4 #000C + 0x60100015, // 0009 GETGBL R4 G21 + 0x7C100000, // 000A CALL R4 0 + 0x5C0C0800, // 000B MOVE R3 R4 + 0x90020001, // 000C SETMBR R0 K0 R1 + 0x90020202, // 000D SETMBR R0 K1 R2 + 0x90020403, // 000E SETMBR R0 K2 R3 + 0x80000000, // 000F RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: compute_ZV_prover +********************************************************************/ +be_local_closure(SPAKE2P_Matter_compute_ZV_prover, /* name */ + be_nested_proto( + 11, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[13]) { /* constants */ + /* K0 */ be_nested_str_weak(crypto), + /* K1 */ be_nested_str_weak(EC_P256), + /* K2 */ be_nested_str_weak(pB), + /* K3 */ be_nested_str_weak(neg), + /* K4 */ be_nested_str_weak(w0), + /* K5 */ be_nested_str_weak(muladd), + /* K6 */ be_nested_str_weak(01), + /* K7 */ be_nested_str_weak(N), + /* K8 */ be_nested_str_weak(Z), + /* K9 */ be_nested_str_weak(mul), + /* K10 */ be_nested_str_weak(x), + /* K11 */ be_nested_str_weak(V), + /* K12 */ be_nested_str_weak(w1), + }), + be_str_weak(compute_ZV_prover), + &be_const_str_solidified, + ( &(const binstruction[26]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0x8C0C0501, // 0001 GETMET R3 R2 K1 + 0x7C0C0200, // 0002 CALL R3 1 + 0x90020401, // 0003 SETMBR R0 K2 R1 + 0x8C100703, // 0004 GETMET R4 R3 K3 + 0x88180104, // 0005 GETMBR R6 R0 K4 + 0x7C100400, // 0006 CALL R4 2 + 0x8C140705, // 0007 GETMET R5 R3 K5 + 0x601C0015, // 0008 GETGBL R7 G21 + 0x58200006, // 0009 LDCONST R8 K6 + 0x7C1C0200, // 000A CALL R7 1 + 0x88200102, // 000B GETMBR R8 R0 K2 + 0x5C240800, // 000C MOVE R9 R4 + 0x88280107, // 000D GETMBR R10 R0 K7 + 0x7C140A00, // 000E CALL R5 5 + 0x8C180709, // 000F GETMET R6 R3 K9 + 0x8820010A, // 0010 GETMBR R8 R0 K10 + 0x5C240A00, // 0011 MOVE R9 R5 + 0x7C180600, // 0012 CALL R6 3 + 0x90021006, // 0013 SETMBR R0 K8 R6 + 0x8C180709, // 0014 GETMET R6 R3 K9 + 0x8820010C, // 0015 GETMBR R8 R0 K12 + 0x5C240A00, // 0016 MOVE R9 R5 + 0x7C180600, // 0017 CALL R6 3 + 0x90021606, // 0018 SETMBR R0 K11 R6 + 0x80000000, // 0019 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(SPAKE_Hasher_init, /* name */ + be_nested_proto( + 4, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(crypto), + /* K1 */ be_nested_str_weak(hash), + /* K2 */ be_nested_str_weak(SHA256), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x8C080302, // 0001 GETMET R2 R1 K2 + 0x7C080200, // 0002 CALL R2 1 + 0x90020202, // 0003 SETMBR R0 K1 R2 + 0x80000000, // 0004 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: add_item +********************************************************************/ +be_local_closure(SPAKE_Hasher_add_item, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(size), + /* K1 */ be_nested_str_weak(add), + /* K2 */ be_const_int(0), + /* K3 */ be_nested_str_weak(hash), + /* K4 */ be_nested_str_weak(update), + }), + be_str_weak(add_item), + &be_const_str_solidified, + ( &(const binstruction[21]) { /* code */ + 0x8C080300, // 0000 GETMET R2 R1 K0 + 0x7C080200, // 0001 CALL R2 1 + 0x600C0015, // 0002 GETGBL R3 G21 + 0x7C0C0000, // 0003 CALL R3 0 + 0x8C0C0701, // 0004 GETMET R3 R3 K1 + 0x5C140400, // 0005 MOVE R5 R2 + 0x541A0003, // 0006 LDINT R6 4 + 0x7C0C0600, // 0007 CALL R3 3 + 0x8C0C0701, // 0008 GETMET R3 R3 K1 + 0x58140002, // 0009 LDCONST R5 K2 + 0x541A0003, // 000A LDINT R6 4 + 0x7C0C0600, // 000B CALL R3 3 + 0x88100103, // 000C GETMBR R4 R0 K3 + 0x8C100904, // 000D GETMET R4 R4 K4 + 0x5C180600, // 000E MOVE R6 R3 + 0x7C100400, // 000F CALL R4 2 + 0x88100103, // 0010 GETMBR R4 R0 K3 + 0x8C100904, // 0011 GETMET R4 R4 K4 + 0x5C180200, // 0012 MOVE R6 R1 + 0x7C100400, // 0013 CALL R4 2 + 0x80000000, // 0014 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: out +********************************************************************/ +be_local_closure(SPAKE_Hasher_out, /* name */ + be_nested_proto( + 3, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(hash), + /* K1 */ be_nested_str_weak(out), + }), + be_str_weak(out), + &be_const_str_solidified, + ( &(const binstruction[ 4]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0x7C040200, // 0002 CALL R1 1 + 0x80040200, // 0003 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: SPAKE_Hasher +********************************************************************/ +be_local_class(SPAKE_Hasher, + 1, + NULL, + be_nested_map(4, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(out, -1), be_const_closure(SPAKE_Hasher_out_closure) }, + { be_const_key_weak(hash, -1), be_const_var(0) }, + { be_const_key_weak(add_item, -1), be_const_closure(SPAKE_Hasher_add_item_closure) }, + { be_const_key_weak(init, 0), be_const_closure(SPAKE_Hasher_init_closure) }, + })), + be_str_weak(SPAKE_Hasher) +); + +/******************************************************************** +** Solidified function: compute_TT_hash +********************************************************************/ +be_local_closure(SPAKE2P_Matter_compute_TT_hash, /* name */ + be_nested_proto( + 13, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[28]) { /* constants */ + /* K0 */ be_const_class(be_class_SPAKE_Hasher), + /* K1 */ be_nested_str_weak(crypto), + /* K2 */ be_nested_str_weak(add_item), + /* K3 */ be_nested_str_weak(Context), + /* K4 */ be_nested_str_weak(A), + /* K5 */ be_nested_str_weak(B), + /* K6 */ be_nested_str_weak(M), + /* K7 */ be_nested_str_weak(N), + /* K8 */ be_nested_str_weak(pA), + /* K9 */ be_nested_str_weak(pB), + /* K10 */ be_nested_str_weak(Z), + /* K11 */ be_nested_str_weak(V), + /* K12 */ be_nested_str_weak(w0), + /* K13 */ be_nested_str_weak(Kmain), + /* K14 */ be_nested_str_weak(out), + /* K15 */ be_nested_str_weak(HKDF_SHA256), + /* K16 */ be_nested_str_weak(derive), + /* K17 */ be_nested_str_weak(fromstring), + /* K18 */ be_nested_str_weak(ConfirmationKeys), + /* K19 */ be_nested_str_weak(KcA), + /* K20 */ be_const_int(0), + /* K21 */ be_nested_str_weak(KcB), + /* K22 */ be_nested_str_weak(K_shared), + /* K23 */ be_nested_str_weak(SharedKey), + /* K24 */ be_nested_str_weak(cA), + /* K25 */ be_nested_str_weak(HMAC_SHA256), + /* K26 */ be_nested_str_weak(update), + /* K27 */ be_nested_str_weak(cB), + }), + be_str_weak(compute_TT_hash), + &be_const_str_solidified, + ( &(const binstruction[91]) { /* code */ + 0x58040000, // 0000 LDCONST R1 K0 + 0xB4000000, // 0001 CLASS K0 + 0xA40A0200, // 0002 IMPORT R2 K1 + 0x5C0C0200, // 0003 MOVE R3 R1 + 0x7C0C0000, // 0004 CALL R3 0 + 0x8C100702, // 0005 GETMET R4 R3 K2 + 0x88180103, // 0006 GETMBR R6 R0 K3 + 0x7C100400, // 0007 CALL R4 2 + 0x8C100702, // 0008 GETMET R4 R3 K2 + 0x88180104, // 0009 GETMBR R6 R0 K4 + 0x7C100400, // 000A CALL R4 2 + 0x8C100702, // 000B GETMET R4 R3 K2 + 0x88180105, // 000C GETMBR R6 R0 K5 + 0x7C100400, // 000D CALL R4 2 + 0x8C100702, // 000E GETMET R4 R3 K2 + 0x88180106, // 000F GETMBR R6 R0 K6 + 0x7C100400, // 0010 CALL R4 2 + 0x8C100702, // 0011 GETMET R4 R3 K2 + 0x88180107, // 0012 GETMBR R6 R0 K7 + 0x7C100400, // 0013 CALL R4 2 + 0x8C100702, // 0014 GETMET R4 R3 K2 + 0x88180108, // 0015 GETMBR R6 R0 K8 + 0x7C100400, // 0016 CALL R4 2 + 0x8C100702, // 0017 GETMET R4 R3 K2 + 0x88180109, // 0018 GETMBR R6 R0 K9 + 0x7C100400, // 0019 CALL R4 2 + 0x8C100702, // 001A GETMET R4 R3 K2 + 0x8818010A, // 001B GETMBR R6 R0 K10 + 0x7C100400, // 001C CALL R4 2 + 0x8C100702, // 001D GETMET R4 R3 K2 + 0x8818010B, // 001E GETMBR R6 R0 K11 + 0x7C100400, // 001F CALL R4 2 + 0x8C100702, // 0020 GETMET R4 R3 K2 + 0x8818010C, // 0021 GETMBR R6 R0 K12 + 0x7C100400, // 0022 CALL R4 2 + 0x8C10070E, // 0023 GETMET R4 R3 K14 + 0x7C100200, // 0024 CALL R4 1 + 0x90021A04, // 0025 SETMBR R0 K13 R4 + 0x8C10050F, // 0026 GETMET R4 R2 K15 + 0x7C100200, // 0027 CALL R4 1 + 0x8C140910, // 0028 GETMET R5 R4 K16 + 0x881C010D, // 0029 GETMBR R7 R0 K13 + 0x60200015, // 002A GETGBL R8 G21 + 0x7C200000, // 002B CALL R8 0 + 0x60240015, // 002C GETGBL R9 G21 + 0x7C240000, // 002D CALL R9 0 + 0x8C241311, // 002E GETMET R9 R9 K17 + 0x582C0012, // 002F LDCONST R11 K18 + 0x7C240400, // 0030 CALL R9 2 + 0x542A003F, // 0031 LDINT R10 64 + 0x7C140A00, // 0032 CALL R5 5 + 0x541A001E, // 0033 LDINT R6 31 + 0x401A2806, // 0034 CONNECT R6 K20 R6 + 0x94180A06, // 0035 GETIDX R6 R5 R6 + 0x90022606, // 0036 SETMBR R0 K19 R6 + 0x541A001F, // 0037 LDINT R6 32 + 0x541E003E, // 0038 LDINT R7 63 + 0x40180C07, // 0039 CONNECT R6 R6 R7 + 0x94180A06, // 003A GETIDX R6 R5 R6 + 0x90022A06, // 003B SETMBR R0 K21 R6 + 0x8C180910, // 003C GETMET R6 R4 K16 + 0x8820010D, // 003D GETMBR R8 R0 K13 + 0x60240015, // 003E GETGBL R9 G21 + 0x7C240000, // 003F CALL R9 0 + 0x60280015, // 0040 GETGBL R10 G21 + 0x7C280000, // 0041 CALL R10 0 + 0x8C281511, // 0042 GETMET R10 R10 K17 + 0x58300017, // 0043 LDCONST R12 K23 + 0x7C280400, // 0044 CALL R10 2 + 0x542E001F, // 0045 LDINT R11 32 + 0x7C180A00, // 0046 CALL R6 5 + 0x90022C06, // 0047 SETMBR R0 K22 R6 + 0x8C180519, // 0048 GETMET R6 R2 K25 + 0x88200113, // 0049 GETMBR R8 R0 K19 + 0x7C180400, // 004A CALL R6 2 + 0x8C180D1A, // 004B GETMET R6 R6 K26 + 0x88200109, // 004C GETMBR R8 R0 K9 + 0x7C180400, // 004D CALL R6 2 + 0x8C180D0E, // 004E GETMET R6 R6 K14 + 0x7C180200, // 004F CALL R6 1 + 0x90023006, // 0050 SETMBR R0 K24 R6 + 0x8C180519, // 0051 GETMET R6 R2 K25 + 0x88200115, // 0052 GETMBR R8 R0 K21 + 0x7C180400, // 0053 CALL R6 2 + 0x8C180D1A, // 0054 GETMET R6 R6 K26 + 0x88200108, // 0055 GETMBR R8 R0 K8 + 0x7C180400, // 0056 CALL R6 2 + 0x8C180D0E, // 0057 GETMET R6 R6 K14 + 0x7C180200, // 0058 CALL R6 1 + 0x90023606, // 0059 SETMBR R0 K27 R6 + 0x80000000, // 005A RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: compute_pA +********************************************************************/ +be_local_closure(SPAKE2P_Matter_compute_pA, /* name */ + be_nested_proto( + 10, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 9]) { /* constants */ + /* K0 */ be_nested_str_weak(crypto), + /* K1 */ be_nested_str_weak(random), + /* K2 */ be_nested_str_weak(EC_P256), + /* K3 */ be_nested_str_weak(x), + /* K4 */ be_nested_str_weak(mod), + /* K5 */ be_nested_str_weak(pA), + /* K6 */ be_nested_str_weak(muladd), + /* K7 */ be_nested_str_weak(w0), + /* K8 */ be_nested_str_weak(M), + }), + be_str_weak(compute_pA), + &be_const_str_solidified, + ( &(const binstruction[23]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0x4C0C0000, // 0001 LDNIL R3 + 0x1C0C0203, // 0002 EQ R3 R1 R3 + 0x780E0003, // 0003 JMPF R3 #0008 + 0x8C0C0501, // 0004 GETMET R3 R2 K1 + 0x5416001F, // 0005 LDINT R5 32 + 0x7C0C0400, // 0006 CALL R3 2 + 0x5C040600, // 0007 MOVE R1 R3 + 0x8C0C0502, // 0008 GETMET R3 R2 K2 + 0x7C0C0200, // 0009 CALL R3 1 + 0x8C100704, // 000A GETMET R4 R3 K4 + 0x5C180200, // 000B MOVE R6 R1 + 0x7C100400, // 000C CALL R4 2 + 0x90020604, // 000D SETMBR R0 K3 R4 + 0x8C100706, // 000E GETMET R4 R3 K6 + 0x88180107, // 000F GETMBR R6 R0 K7 + 0x881C0108, // 0010 GETMBR R7 R0 K8 + 0x88200103, // 0011 GETMBR R8 R0 K3 + 0x60240015, // 0012 GETGBL R9 G21 + 0x7C240000, // 0013 CALL R9 0 + 0x7C100A00, // 0014 CALL R4 5 + 0x90020A04, // 0015 SETMBR R0 K5 R4 + 0x80000000, // 0016 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(SPAKE2P_Matter_init, /* name */ + be_nested_proto( + 7, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(M), + /* K1 */ be_nested_str_weak(fromhex), + /* K2 */ be_nested_str_weak(spake_M_hex), + /* K3 */ be_nested_str_weak(N), + /* K4 */ be_nested_str_weak(spake_N_hex), + /* K5 */ be_nested_str_weak(w0), + /* K6 */ be_nested_str_weak(w1), + /* K7 */ be_nested_str_weak(L), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[16]) { /* code */ + 0x60100015, // 0000 GETGBL R4 G21 + 0x7C100000, // 0001 CALL R4 0 + 0x8C100901, // 0002 GETMET R4 R4 K1 + 0x88180102, // 0003 GETMBR R6 R0 K2 + 0x7C100400, // 0004 CALL R4 2 + 0x90020004, // 0005 SETMBR R0 K0 R4 + 0x60100015, // 0006 GETGBL R4 G21 + 0x7C100000, // 0007 CALL R4 0 + 0x8C100901, // 0008 GETMET R4 R4 K1 + 0x88180104, // 0009 GETMBR R6 R0 K4 + 0x7C100400, // 000A CALL R4 2 + 0x90020604, // 000B SETMBR R0 K3 R4 + 0x90020A01, // 000C SETMBR R0 K5 R1 + 0x90020C02, // 000D SETMBR R0 K6 R2 + 0x90020E03, // 000E SETMBR R0 K7 R3 + 0x80000000, // 000F RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: compute_ZV_verifier +********************************************************************/ +be_local_closure(SPAKE2P_Matter_compute_ZV_verifier, /* name */ + be_nested_proto( + 11, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[13]) { /* constants */ + /* K0 */ be_nested_str_weak(crypto), + /* K1 */ be_nested_str_weak(EC_P256), + /* K2 */ be_nested_str_weak(pA), + /* K3 */ be_nested_str_weak(neg), + /* K4 */ be_nested_str_weak(w0), + /* K5 */ be_nested_str_weak(muladd), + /* K6 */ be_nested_str_weak(01), + /* K7 */ be_nested_str_weak(M), + /* K8 */ be_nested_str_weak(Z), + /* K9 */ be_nested_str_weak(mul), + /* K10 */ be_nested_str_weak(y), + /* K11 */ be_nested_str_weak(V), + /* K12 */ be_nested_str_weak(L), + }), + be_str_weak(compute_ZV_verifier), + &be_const_str_solidified, + ( &(const binstruction[26]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0x8C0C0501, // 0001 GETMET R3 R2 K1 + 0x7C0C0200, // 0002 CALL R3 1 + 0x90020401, // 0003 SETMBR R0 K2 R1 + 0x8C100703, // 0004 GETMET R4 R3 K3 + 0x88180104, // 0005 GETMBR R6 R0 K4 + 0x7C100400, // 0006 CALL R4 2 + 0x8C140705, // 0007 GETMET R5 R3 K5 + 0x601C0015, // 0008 GETGBL R7 G21 + 0x58200006, // 0009 LDCONST R8 K6 + 0x7C1C0200, // 000A CALL R7 1 + 0x88200102, // 000B GETMBR R8 R0 K2 + 0x5C240800, // 000C MOVE R9 R4 + 0x88280107, // 000D GETMBR R10 R0 K7 + 0x7C140A00, // 000E CALL R5 5 + 0x8C180709, // 000F GETMET R6 R3 K9 + 0x8820010A, // 0010 GETMBR R8 R0 K10 + 0x5C240A00, // 0011 MOVE R9 R5 + 0x7C180600, // 0012 CALL R6 3 + 0x90021006, // 0013 SETMBR R0 K8 R6 + 0x8C180709, // 0014 GETMET R6 R3 K9 + 0x8820010A, // 0015 GETMBR R8 R0 K10 + 0x8824010C, // 0016 GETMBR R9 R0 K12 + 0x7C180600, // 0017 CALL R6 3 + 0x90021606, // 0018 SETMBR R0 K11 R6 + 0x80000000, // 0019 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: compute_pB +********************************************************************/ +be_local_closure(SPAKE2P_Matter_compute_pB, /* name */ + be_nested_proto( + 10, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 9]) { /* constants */ + /* K0 */ be_nested_str_weak(crypto), + /* K1 */ be_nested_str_weak(random), + /* K2 */ be_nested_str_weak(EC_P256), + /* K3 */ be_nested_str_weak(y), + /* K4 */ be_nested_str_weak(mod), + /* K5 */ be_nested_str_weak(pB), + /* K6 */ be_nested_str_weak(muladd), + /* K7 */ be_nested_str_weak(w0), + /* K8 */ be_nested_str_weak(N), + }), + be_str_weak(compute_pB), + &be_const_str_solidified, + ( &(const binstruction[23]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0x4C0C0000, // 0001 LDNIL R3 + 0x1C0C0203, // 0002 EQ R3 R1 R3 + 0x780E0003, // 0003 JMPF R3 #0008 + 0x8C0C0501, // 0004 GETMET R3 R2 K1 + 0x5416001F, // 0005 LDINT R5 32 + 0x7C0C0400, // 0006 CALL R3 2 + 0x5C040600, // 0007 MOVE R1 R3 + 0x8C0C0502, // 0008 GETMET R3 R2 K2 + 0x7C0C0200, // 0009 CALL R3 1 + 0x8C100704, // 000A GETMET R4 R3 K4 + 0x5C180200, // 000B MOVE R6 R1 + 0x7C100400, // 000C CALL R4 2 + 0x90020604, // 000D SETMBR R0 K3 R4 + 0x8C100706, // 000E GETMET R4 R3 K6 + 0x88180107, // 000F GETMBR R6 R0 K7 + 0x881C0108, // 0010 GETMBR R7 R0 K8 + 0x88200103, // 0011 GETMBR R8 R0 K3 + 0x60240015, // 0012 GETGBL R9 G21 + 0x7C240000, // 0013 CALL R9 0 + 0x7C100A00, // 0014 CALL R4 5 + 0x90020A04, // 0015 SETMBR R0 K5 R4 + 0x80000000, // 0016 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: SPAKE2P_Matter +********************************************************************/ +be_local_class(SPAKE2P_Matter, + 20, + NULL, + be_nested_map(31, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(pA, 23), be_const_var(3) }, + { be_const_key_weak(set_context, 28), be_const_closure(SPAKE2P_Matter_set_context_closure) }, + { be_const_key_weak(KcA, -1), be_const_var(10) }, + { be_const_key_weak(cA, -1), be_const_var(13) }, + { be_const_key_weak(K_shared, -1), be_const_var(12) }, + { be_const_key_weak(A, 9), be_const_var(15) }, + { be_const_key_weak(V, -1), be_const_var(6) }, + { be_const_key_weak(compute_TT_hash, -1), be_const_closure(SPAKE2P_Matter_compute_TT_hash_closure) }, + { be_const_key_weak(Kmain, -1), be_const_var(9) }, + { be_const_key_weak(w0, -1), be_const_var(0) }, + { be_const_key_weak(N, -1), be_const_var(19) }, + { be_const_key_weak(x, -1), be_const_var(7) }, + { be_const_key_weak(Context, 20), be_const_var(17) }, + { be_const_key_weak(compute_pA, -1), be_const_closure(SPAKE2P_Matter_compute_pA_closure) }, + { be_const_key_weak(w1, -1), be_const_var(1) }, + { be_const_key_weak(B, 22), be_const_var(16) }, + { be_const_key_weak(L, 25), be_const_var(2) }, + { be_const_key_weak(cB, 10), be_const_var(14) }, + { be_const_key_weak(spake_M_hex, -1), be_nested_str_weak(04886e2f97ace46e55ba9dd7242579f2993b64e16ef3dcab95afd497333d8fa12f5ff355163e43ce224e0b0e65ff02ac8e5c7be09419c785e0ca547d55a12e2d20) }, + { be_const_key_weak(spake_N_hex, -1), be_nested_str_weak(04d8bbd6c639c62937b04d997f38c3770719c629d7014d49a24b4f98baa1292b4907d60aa6bfade45008a636337f5168c64d9bd36034808cd564490b1e656edbe7) }, + { be_const_key_weak(CRYPTO_GROUP_SIZE_BYTES, 7), be_const_int(32) }, + { be_const_key_weak(CRYPTO_W_SIZE_BYTES, 6), be_const_int(40) }, + { be_const_key_weak(pB, 8), be_const_var(4) }, + { be_const_key_weak(M, -1), be_const_var(18) }, + { be_const_key_weak(compute_ZV_verifier, -1), be_const_closure(SPAKE2P_Matter_compute_ZV_verifier_closure) }, + { be_const_key_weak(KcB, 19), be_const_var(11) }, + { be_const_key_weak(y, -1), be_const_var(8) }, + { be_const_key_weak(Z, -1), be_const_var(5) }, + { be_const_key_weak(compute_ZV_prover, 2), be_const_closure(SPAKE2P_Matter_compute_ZV_prover_closure) }, + { be_const_key_weak(init, 5), be_const_closure(SPAKE2P_Matter_init_closure) }, + { be_const_key_weak(compute_pB, -1), be_const_closure(SPAKE2P_Matter_compute_pB_closure) }, + })), + be_str_weak(SPAKE2P_Matter) +); +/*******************************************************************/ + +void be_load_SPAKE2P_Matter_class(bvm *vm) { + be_pushntvclass(vm, &be_class_SPAKE2P_Matter); + be_setglobal(vm, "SPAKE2P_Matter"); + be_pop(vm, 1); +} +/********************************************************************/ +/* End of solidification */ diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index ac6d4372f..f9e52499a 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -1113,6 +1113,7 @@ #define USE_BERRY_CRYPTO_HMAC_SHA256 // enable HMAC SHA256 hash function // #define USE_BERRY_CRYPTO_PBKDF2_HMAC_SHA256 // PBKDF2 with HMAC SHA256, used in Matter protocol // #define USE_BERRY_CRYPTO_HKDF_SHA256 // HKDF with HMAC SHA256, used in Matter protocol + // #define USE_BERRY_CRYPTO_SPAKE2P_MATTER // SPAKE2+ used in Matter 1.0, complete name is SPAKE2+-P256-SHA256-HKDF-SHA256-HMAC-SHA256 #define USE_CSE7761 // Add support for CSE7761 Energy monitor as used in Sonoff Dual R3 // -- LVGL Graphics Library --------------------------------- From 9f23151f7854b4575352624ff45f6933b398a6d1 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Fri, 23 Dec 2022 20:03:58 +0100 Subject: [PATCH 050/262] Fix tasmota32-zbbrdgpro compile with core 2.0.6 (#17496) * Fix tasmota32-zbbrdgpro compile with core 2.0.6 * only ESP32 --- .../xdrv_23_zigbee_7_6_flash_fs.ino | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_7_6_flash_fs.ino b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_7_6_flash_fs.ino index 034a2ff64..347fd0cad 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_7_6_flash_fs.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_7_6_flash_fs.ino @@ -27,7 +27,7 @@ /******************************************************************** ** Subfile implementation -** +** ** Takes a string point in Flash and turn it to a read-only file ********************************************************************/ @@ -107,6 +107,18 @@ public: return ""; } + #ifdef ESP32 + #if ESP_ARDUINO_VERSION > ESP_ARDUINO_VERSION_VAL(2, 0, 5) + bool seekDir(long position){ + // ignore + } + String getNextFileName(void) + { + // ignore + } + #endif + #endif // ESP32 + const char* name() const { return ""; } From 4a47514a2566c558d9e7b1cbd10dbe7da8455e5c Mon Sep 17 00:00:00 2001 From: Barbudor Date: Fri, 23 Dec 2022 21:17:24 +0100 Subject: [PATCH 051/262] PCF8574 input pin initialization fix (#17499) * step1 - quick test patch * mistake, pullup should be disabled * 2nd test version * refactoring * final --- tasmota/tasmota_xdrv_driver/xdrv_28_pcf8574.ino | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_28_pcf8574.ino b/tasmota/tasmota_xdrv_driver/xdrv_28_pcf8574.ino index 25e0018fc..907329992 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_28_pcf8574.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_28_pcf8574.ino @@ -123,7 +123,9 @@ void Pcf8574Init(void) Pcf8574.max_connected_ports = 0; // reset no of devices to avoid duplicate ports on duplicate init. for (uint32_t idx = 0; idx < Pcf8574.max_devices; idx++) { // suport up to 8 boards PCF8574 uint8_t gpio = Pcf8574Read(idx); - Pcf8574.pin_mask[idx] = gpio; + // Insure the input pins are actually writen a 1 for proper input operation + Pcf8574.pin_mask[idx] = gpio | ~Settings->pcf8574_config[idx]; + Pcf8574Write(idx); // Write back to the register #ifdef USE_PCF8574_MQTTINPUT Pcf8574.last_input[idx] = gpio & ~Settings->pcf8574_config[idx]; #endif // #ifdef USE_PCF8574_MQTTINPUT From c1ce983bef810093f22ca93d771765c99b2a0cc2 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sat, 24 Dec 2022 15:59:29 +0100 Subject: [PATCH 052/262] Reduce code size by removing duplicate code --- .../tasmota_xnrg_energy/xnrg_29_modbus.ino | 189 +++++++++--------- 1 file changed, 97 insertions(+), 92 deletions(-) diff --git a/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino b/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino index 6cf554af4..4dac9ce76 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino @@ -31,6 +31,7 @@ * Name - Name of energy monitoring device(s) * Baud - Baudrate of device modbus interface - optional. default is 9600 * Config - Serial config parameters like 8N1 - 8 databits, No parity, 1 stop bit + * Poll - Time between modbus requests - optional. default is 200 milliseconds * Address - Modbus device address entered as decimal (1) or hexadecimal (0x01) or up to three addresses ([1,2,3]) - optional. default = 1 * Function - Modbus function code to access registers - optional. default = 4 * Tasmota default embedded register names: @@ -143,13 +144,15 @@ * - Support other modbus register like integers * * Test set: - * rule3 on file#modbus do {"Name":"3 x PZEM014","Baud":9600,"Config":8N1","Address":[1,1],"Function":4,"Voltage":{"R":0,"T":3,"F":-1},"Current":{"R":1,"T":8,"F":-3},"Power":{"R":3,"T":8,"F":-1},"Factor":{"R":8,"T":3,"F":-2},"Frequency":{"R":7,"T":3,"F":-1},"Total":{"R":5,"T":8,"F":-3}} endon + * rule3 on file#modbus do {"Name":"GROWATT","Baud":9600,"Config":8N1","Address":11,"Function":4,"Voltage":{"R":[4110,4114,4118],"T":3,"F":-1},"Current":{"R":[4111,4115,4119],"T":3,"F":-1},"Power":{"R":[4112,4116,4120],"T":8,"F":-1},"Frequency":{"R":4109,"T":3,"F":-2},"Total":{"R":4124,"T":8,"F":-1},"User":[{"R":[4099,4103],"J":"VoltagePV","G":"Voltage PV","U":"V","D":21,"T":3,"F":-1},{"R":[4100,4104],"J":"CurrentPV","G":"Current PV","U":"A","D":22,"T":3,"F":-1},{"R":[4101,4105],"J":"PowerPV","G":"Power PV","U":"W","D":23,"T":8,"F":-1}]} endon + * rule3 on file#modbus do {"Name":"2 x PZEM014","Baud":9600,"Config":8N1","Address":[1,1],"Function":4,"Voltage":{"R":0,"T":3,"F":-1},"Current":{"R":1,"T":8,"F":-3},"Power":{"R":3,"T":8,"F":-1},"Factor":{"R":8,"T":3,"F":-2},"Frequency":{"R":7,"T":3,"F":-1},"Total":{"R":5,"T":8,"F":-3}} endon * rule3 on file#modbus do {"Name":"SDM230 test1","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":[0,0,0],"Current":[6,6,6],"Power":[12,12,12],"ApparentPower":[18,18,18],"ReactivePower":[24,24,24],"Factor":[30,30,30],"Frequency":[70,70,70],"Total":[342,342,342]} endon * rule3 on file#modbus do {"Name":"SDM230 test2","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":[0,0,0],"Current":[6,6,6],"Power":[12,12,12],"ApparentPower":[18,18,18],"ReactivePower":[24,24,24],"Factor":[30,30,30],"Frequency":70,"Total":[342,342,342]} endon * rule3 on file#modbus do {"Name":"SDM230 test3","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":0,"Current":[6,6,6],"Power":[12,12,12],"ApparentPower":[18,18,18],"ReactivePower":[24,24,24],"Factor":[30,30,30],"Frequency":70,"Total":[342,342,342]} endon * rule3 on file#modbus do {"Name":"SDM230 test4","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":0,"Current":6,"Power":12,"ApparentPower":18,"ReactivePower":24,"Factor":30,"Frequency":70,"Total":342,"ExportActive":0x004A,"User":[{"R":0x004E,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":24},{"R":0x0024,"J":"PhaseAngle","G":"Phase Angle","U":"Deg","D":2}]} endon * rule3 on file#modbus do {"Name":"SDM230 test5","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":[0,0,0],"Current":6,"Power":12,"ApparentPower":18,"ReactivePower":24,"Factor":30,"Frequency":70,"Total":342,"ExportActive":0x004A,"User":[{"R":[0x004E,0x004E,0x004E],"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":3},{"R":0x0024,"J":"PhaseAngle","G":"Phase Angle","U":"Deg","D":2}]} endon * rule3 on file#modbus do {"Name":"SDM120 test1","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":0,"Current":6,"Power":12,"ApparentPower":18,"ReactivePower":24,"Factor":30,"Frequency":70,"Total":342,"ExportActive":0x004A,"User":[{"R":0x0048,"J":"ImportActive","G":"Import Active","U":"kWh","D":24},{"R":0x004E,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":24},{"R":0x004C,"J":"ImportReactive","G":"Import Reactive","U":"kVArh","D":24},{"R":0x0024,"J":"PhaseAngle","G":"Phase Angle","U":"Deg","D":2}]} endon + * rule3 on file#modbus do {"Name":"PZEM014 test1","Baud":9600,"Config":8N1","Address":1,"Function":4,"Voltage":{"R":0,"T":3,"F":-1},"Current":{"R":1,"T":8,"F":-3},"Power":{"R":3,"T":8,"F":-1},"Factor":{"R":8,"T":3,"F":-2},"Frequency":{"R":7,"T":3,"F":-1},"Total":{"R":5,"T":8,"F":-3},"User":{"R":0,"J":"VoltageTest","G":"Voltage test","U":"V","D":21,"T":3,"F":-1}} endon * * rule3 on file#modbus do {"Name":"SDM230 test6","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":{"R":0,"T":0,"M":1},"Current":{"R":6,"T":0,"M":1},"Power":{"R":12,"T":0,"M":1},"Frequency":70,"Total":342} endon * rule3 on file#modbus do {"Name":"SDM230 test6","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":{"R":0,"T":0,"F":0},"Current":{"R":6,"T":0,"F":0},"Power":{"R":12,"T":0,"F":0},"Frequency":70,"Total":342,"User":{"R":0x0048,"T":0,"F":-1,"J":"ImportActive","G":"Import Active","U":"kWh","D":24}} endon @@ -167,6 +170,7 @@ #define ENERGY_MODBUS_DECIMALS 0 // Default user decimal resolution #define ENERGY_MODBUS_TICKER // Enable for ESP8266 when using softwareserial solving most modbus serial retries +#define ENERGY_MODBUS_TICKER_POLL 200 // Modbus poll time in ms between read register requests //#define ENERGY_MODBUS_DEBUG //#define ENERGY_MODBUS_DEBUG_SHOW @@ -185,15 +189,15 @@ enum EnergyModbusDataType { NRG_DT_FLOAT, // 0 = 4-byte float NRG_DT_U32_SW, // 8 = 4-byte unsigned with swapped words NRG_DT_MAX }; -enum EnergyModbusResolutions { NRG_RES_VOLTAGE = 21, // V - NRG_RES_CURRENT, // A - NRG_RES_POWER, // W, VA, VAr - NRG_RES_ENERGY, // kWh, kVAh, kVArh - NRG_RES_FREQUENCY, // Hz - NRG_RES_TEMPERATURE, // C, F - NRG_RES_HUMIDITY, // % - NRG_RES_PRESSURE, // hPa, mmHg - NRG_RES_WEIGHT }; // Kg +enum EnergyModbusResolutions { NRG_RES_VOLTAGE = 21, // 21 = V + NRG_RES_CURRENT, // 22 = A + NRG_RES_POWER, // 23 = W, VA, VAr + NRG_RES_ENERGY, // 24 = kWh, kVAh, kVArh + NRG_RES_FREQUENCY, // 25 = Hz + NRG_RES_TEMPERATURE, // 26 = C, F + NRG_RES_HUMIDITY, // 27 = % + NRG_RES_PRESSURE, // 28 = hPa, mmHg + NRG_RES_WEIGHT }; // 29 = Kg enum EnergyModbusRegisters { NRG_MBS_VOLTAGE, NRG_MBS_CURRENT, @@ -228,6 +232,7 @@ Ticker ticker_energy_modbus; struct NRGMBSPARAM { uint32_t serial_bps; uint32_t serial_config; + uint16_t ticker_poll; uint8_t device_address[ENERGY_MODBUS_MAX_DEVICES]; uint8_t devices; uint8_t function; @@ -436,7 +441,6 @@ void EnergyModbusLoop(void) { } } // end data ready - uint32_t address = 0; uint32_t phase = NrgMbsParam.phase; if (NrgMbsParam.devices > 1) { @@ -465,13 +469,15 @@ void EnergyModbusLoop(void) { } #ifdef USE_RULES -bool EnergyModbusReadUserRegisters(JsonParserObject user_add_value, uint32_t add_index) { - // {"R":0x004E,"T":0,"F":0,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":3} - uint32_t reg_index = NRG_MBS_MAX_REGS + add_index; - JsonParserToken val; - val = user_add_value[PSTR("R")]; // Register address +uint32_t EnergyModbusReadRegisterInfo(JsonParserObject add_value, uint32_t reg_index) { + // {"R":0,"T":0,"F":0} + // {"R":[0,2,4],"T":0,"F":0} + // {"R":[0,2,4],"T":0,"M":10} - [LEGACY] uint32_t phase = 0; + JsonParserToken val; + val = add_value[PSTR("R")]; // Register address if (val.isArray()) { + // [0,2,4] JsonParserArray address_arr = val.getArray(); for (auto value : address_arr) { NrgMbsReg[reg_index].address[phase] = value.getUInt(); @@ -479,28 +485,23 @@ bool EnergyModbusReadUserRegisters(JsonParserObject user_add_value, uint32_t add if (phase >= ENERGY_MAX_PHASES) { break; } } } else if (val) { + // 0 NrgMbsReg[reg_index].address[0] = val.getUInt(); phase++; - } else { - return false; } - if (phase > Energy.phase_count) { - NrgMbsParam.devices = 1; - Energy.phase_count = phase; - } - val = user_add_value[PSTR("T")]; // Register data type + val = add_value[PSTR("T")]; // Register data type if (val) { - // "T":0 + // 0 NrgMbsReg[reg_index].datatype = val.getUInt(); } - val = user_add_value[PSTR("F")]; // Register factor + val = add_value[PSTR("F")]; // Register factor if (val) { - // "F":1 or "F":-2 + // 1 or -2 NrgMbsReg[reg_index].factor = val.getInt(); } - val = user_add_value[PSTR("M")]; // [LEGACY] Register divider + val = add_value[PSTR("M")]; // [LEGACY] Register divider if (val) { - // "M":1 + // 1 int32_t divider = val.getUInt(); int factor = 0; while (divider > 1) { @@ -509,6 +510,27 @@ bool EnergyModbusReadUserRegisters(JsonParserObject user_add_value, uint32_t add } NrgMbsReg[reg_index].factor = factor; } + return phase; +} + +bool EnergyModbusReadUserRegisters(JsonParserObject user_add_value, uint32_t add_index) { + // {"R":0x004E,"T":0,"F":0,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":3,"T":0,"F":0} + // {"R":[0,2,4],"T":0,"F":0,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":3,"T":0,"F":0} + uint32_t reg_index = NRG_MBS_MAX_REGS + add_index; + + // {"R":0,"T":0,"F":0} + // {"R":[0,2,4],"T":0,"F":0} + // {"R":[0,2,4],"T":0,"M":10} - [LEGACY] + uint32_t phase = EnergyModbusReadRegisterInfo(user_add_value, reg_index); + if (!phase) { + return false; // No register entered so skip + } + if (phase > Energy.phase_count) { + Energy.phase_count = phase; + NrgMbsParam.devices = 1; // Only one device allowed with multiple phases + } + + JsonParserToken val; val = user_add_value[PSTR("J")]; // JSON value name if (val) { NrgMbsUser[add_index].json_name = SetStr(val.getStr()); @@ -533,8 +555,8 @@ bool EnergyModbusReadUserRegisters(JsonParserObject user_add_value, uint32_t add } #ifdef ENERGY_MODBUS_DEBUG - AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Idx %d, R [%04X,%04X,%04X], T %d, F %d, J '%s', G '%s', U '%s', D %d"), - add_index, + AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Idx %d (%s), R [%04X,%04X,%04X], T %d, F %d, J '%s', G '%s', U '%s', D %d"), + add_index, NrgMbsUser[add_index].json_name, NrgMbsReg[reg_index].address[0], NrgMbsReg[reg_index].address[1], NrgMbsReg[reg_index].address[2], @@ -570,25 +592,28 @@ bool EnergyModbusReadRegisters(void) { Energy.phase_count = 1; NrgMbsParam.serial_bps = ENERGY_MODBUS_SPEED; NrgMbsParam.serial_config = ENERGY_MODBUS_CONFIG; + NrgMbsParam.ticker_poll = ENERGY_MODBUS_TICKER_POLL; NrgMbsParam.device_address[0] = ENERGY_MODBUS_ADDR; NrgMbsParam.devices = 1; NrgMbsParam.function = ENERGY_MODBUS_FUNC; NrgMbsParam.user_adds = 0; + // Detect buffer allocation JsonParserToken val; val = root[PSTR("User")]; if (val) { if (val.isArray()) { - // "User":[{"R":0x004E,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":3},{"R":0x0024,"J":"PhaseAngle","G":"Phase Angle","U":"Deg","D":2}] + // [{"R":0x004E,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":3},{"R":0x0024,"J":"PhaseAngle","G":"Phase Angle","U":"Deg","D":2}] NrgMbsParam.user_adds = val.size(); } else { - // "User":{"R":0x004E,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":3} + // {"R":0x004E,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":3} NrgMbsParam.user_adds = 1; } } NrgMbsParam.total_regs = NRG_MBS_MAX_REGS + NrgMbsParam.user_adds; NrgMbsReg = (NrgMbsRegister_t*)calloc(NrgMbsParam.total_regs, sizeof(NrgMbsRegister_t)); if (NrgMbsReg == nullptr) { return false; } // Unable to allocate variables on heap + // Init defaults for (uint32_t i = 0; i < NrgMbsParam.total_regs; i++) { NrgMbsReg[i].datatype = ENERGY_MODBUS_DATATYPE; @@ -612,23 +637,28 @@ bool EnergyModbusReadRegisters(void) { } } + // Get global parameters val = root[PSTR("Baud")]; if (val) { - NrgMbsParam.serial_bps = val.getInt(); // 2400 + NrgMbsParam.serial_bps = val.getInt(); // 2400 } val = root[PSTR("Config")]; if (val) { const char *serial_config = val.getStr(); // 8N1 NrgMbsParam.serial_config = ConvertSerialConfig(ParseSerialConfig(serial_config)); } + val = root[PSTR("Poll")]; + if (val) { + NrgMbsParam.ticker_poll = val.getUInt(); // 200 + if (NrgMbsParam.ticker_poll < 100) { // Below 100 ms makes no sense as the comms usually is 9600bps + NrgMbsParam.ticker_poll = ENERGY_MODBUS_TICKER_POLL; + } + } val = root[PSTR("Address")]; if (val) { - -// NrgMbsParam.device_address = val.getUInt(); // 1 - NrgMbsParam.devices = 0; if (val.isArray()) { - // "Address":[1,2,3] + // [1,2,3] JsonParserArray arr = val.getArray(); for (auto value : arr) { NrgMbsParam.device_address[NrgMbsParam.devices] = value.getUInt(); // 1 @@ -636,16 +666,17 @@ bool EnergyModbusReadRegisters(void) { if (NrgMbsParam.devices >= ENERGY_MODBUS_MAX_DEVICES) { break; } } } else if (val) { - // "Address":1 - NrgMbsParam.device_address[0] = val.getUInt(); + // 1 + NrgMbsParam.device_address[0] = val.getUInt(); // 1 NrgMbsParam.devices++; } } val = root[PSTR("Function")]; if (val) { - NrgMbsParam.function = val.getUInt(); // 4 + NrgMbsParam.function = val.getUInt(); // 4 } + // Get default energy registers char register_name[32]; Energy.voltage_available = false; // Disable voltage is measured Energy.current_available = false; // Disable current is measured @@ -653,51 +684,17 @@ bool EnergyModbusReadRegisters(void) { val = root[GetTextIndexed(register_name, sizeof(register_name), names, kEnergyModbusValues)]; if (val) { // "Voltage":0 - // "Voltage":[0,0,0] + // "Voltage":[0,2,4] // "Voltage":{"R":0,"T":0,"F":0} - // "Voltage":{"R":[0,0,0],"T":0,"F":0} + // "Voltage":{"R":[0,2,4],"T":0,"F":0} uint32_t phase = 0; if (val.isObject()) { - // "Voltage":{"R":0,"T":0,"F":0} - // "Voltage":{"R":[0,0,0],"T":0,"F":0} - JsonParserObject register_add_values = val.getObject(); - val = register_add_values[PSTR("R")]; // Register address - if (val.isArray()) { - // "R":[0,0,0] - JsonParserArray address_arr = val.getArray(); - for (auto value : address_arr) { - NrgMbsReg[names].address[phase] = value.getUInt(); - phase++; - if (phase >= ENERGY_MAX_PHASES) { break; } - } - } else if (val) { - // "R":0 - NrgMbsReg[names].address[0] = val.getUInt(); - phase++; - } - val = register_add_values[PSTR("T")]; // Register data type - if (val) { - // "T":0 - NrgMbsReg[names].datatype = val.getUInt(); - } - val = register_add_values[PSTR("F")]; // Register factor - if (val) { - // "F":1 or "F":-2 - NrgMbsReg[names].factor = val.getInt(); - } - val = register_add_values[PSTR("M")]; // [LEGACY] Register divider - if (val) { - // "M":1 - int32_t divider = val.getUInt(); - int factor = 0; - while (divider > 1) { - divider /= 10; - factor--; - } - NrgMbsReg[names].factor = factor; - } + // {"R":0,"T":0,"F":0} + // {"R":[0,2,4],"T":0,"F":0} + // {"R":[0,2,4],"T":0,"M":10} - [LEGACY] + phase = EnergyModbusReadRegisterInfo(val.getObject(), names); } else if (val.isArray()) { - // "Voltage":[0,0,0] + // [0,2,4] JsonParserArray arr = val.getArray(); for (auto value : arr) { NrgMbsReg[names].address[phase] = value.getUInt(); @@ -705,14 +702,15 @@ bool EnergyModbusReadRegisters(void) { if (phase >= ENERGY_MAX_PHASES) { break; } } } else if (val) { - // "Voltage":0 + // 0 NrgMbsReg[names].address[0] = val.getUInt(); phase++; } if (phase > Energy.phase_count) { - NrgMbsParam.devices = 1; Energy.phase_count = phase; + NrgMbsParam.devices = 1; // Only one device allowed with multiple phases } + switch(names) { case NRG_MBS_VOLTAGE: Energy.voltage_available = true; // Enable if voltage is measured @@ -734,8 +732,8 @@ bool EnergyModbusReadRegisters(void) { } #ifdef ENERGY_MODBUS_DEBUG - AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Idx %d, R [%04X,%04X,%04X], T %d, F %d"), - names, + AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Idx %d (%s), R [%04X,%04X,%04X], T %d, F %d"), + names, register_name, NrgMbsReg[names].address[0], NrgMbsReg[names].address[1], NrgMbsReg[names].address[2], @@ -746,11 +744,13 @@ bool EnergyModbusReadRegisters(void) { } } - // "User":{"R":0x004E,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":3} - // "User":[{"R":0x004E,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":3},{"R":0x0024,"J":"PhaseAngle","G":"Phase Angle","U":"Deg","D":2}] + // Get user defined registers + // "User":{"R":0x004E,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":3,"T":0,"F":0} + // "User":[{"R":0x004E,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":3,"T":0,"F":0},{"R":0x0024,"J":"PhaseAngle","G":"Phase Angle","U":"Deg","D":2,"T":0,"F":0}] val = root[PSTR("User")]; if (val) { if (val.isArray()) { + // [{"R":0x004E,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":3,"T":0,"F":0},{"R":0x0024,"J":"PhaseAngle","G":"Phase Angle","U":"Deg","D":2,"T":0,"F":0}] JsonParserArray user_adds_arr = val.getArray(); uint32_t add_index = 0; for (auto user_add_values : user_adds_arr) { @@ -763,6 +763,7 @@ bool EnergyModbusReadRegisters(void) { } } } else if (val) { + // {"R":0x004E,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":3,"T":0,"F":0} if (val.isObject()) { if (!EnergyModbusReadUserRegisters(val.getObject(), 0)) { AddLog(LOG_LEVEL_INFO, PSTR("NRG: Dropped JSON user input")); @@ -773,12 +774,14 @@ bool EnergyModbusReadRegisters(void) { NrgMbsParam.total_regs = NRG_MBS_MAX_REGS + NrgMbsParam.user_adds; } + // Fix variable boundaries for (uint32_t i = 0; i < NrgMbsParam.total_regs; i++) { if (NrgMbsReg[i].datatype >= NRG_DT_MAX) { NrgMbsReg[i].datatype = ENERGY_MODBUS_DATATYPE; } } if (NrgMbsParam.devices > 1) { + // Multiple devices have no common values Energy.phase_count = NrgMbsParam.devices; Energy.voltage_common = false; // Use no common voltage Energy.frequency_common = false; // Use no common frequency @@ -786,9 +789,11 @@ bool EnergyModbusReadRegisters(void) { } #ifdef ENERGY_MODBUS_DEBUG - AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Devices %d"), NrgMbsParam.devices); - - AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: RAM usage %d + %d + %d"), sizeof(NrgMbsParam), NrgMbsParam.total_regs * sizeof(NrgMbsRegister_t), NrgMbsParam.user_adds * sizeof(NrgMbsUser_t)); + AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Devices %d, RAM usage %d + %d + %d"), + NrgMbsParam.devices, + sizeof(NrgMbsParam), + NrgMbsParam.total_regs * sizeof(NrgMbsRegister_t), + NrgMbsParam.user_adds * sizeof(NrgMbsUser_t)); #endif // NrgMbsParam.state = 0; // Set by calloc() @@ -803,7 +808,7 @@ bool EnergyModbusRegisters(void) { if (EnergyModbusReadRegisters()) { return true; } - AddLog(LOG_LEVEL_INFO, PSTR("NRG: No valid modbus data")); + AddLog(LOG_LEVEL_INFO, PSTR("NRG: No valid modbus rule data")); return false; } @@ -815,7 +820,7 @@ void EnergyModbusSnsInit(void) { if (2 == result) { ClaimSerial(); } #ifdef ENERGY_MODBUS_TICKER - ticker_energy_modbus.attach_ms(200, EnergyModbusLoop); + ticker_energy_modbus.attach_ms(NrgMbsParam.ticker_poll, EnergyModbusLoop); #endif // ENERGY_MODBUS_TICKER return; From bd4fe7877591ac6faaa5d6d222a2d6e54fb81e18 Mon Sep 17 00:00:00 2001 From: Barbudor Date: Tue, 27 Dec 2022 12:07:37 +0100 Subject: [PATCH 053/262] fix typo (#17511) --- .../tasmota_xdrv_driver/xdrv_90_esp32_dingtian_relay.ino | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_90_esp32_dingtian_relay.ino b/tasmota/tasmota_xdrv_driver/xdrv_90_esp32_dingtian_relay.ino index 5ef54642b..459775dba 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_90_esp32_dingtian_relay.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_90_esp32_dingtian_relay.ino @@ -99,10 +99,10 @@ void DingtianInit(void) { Dingtian->first = TasmotaGlobal.devices_present; TasmotaGlobal.devices_present += Dingtian->count; - if (TasGlobal.devices_present > POWER_SIZE) { - TasGlobal.devices_present = POWER_SIZE; + if (TasmotaGlobal.devices_present > POWER_SIZE) { + TasmotaGlobal.devices_present = POWER_SIZE; } - AddLog(LOG_LEVEL_DEBUG, PSTR("DNGT: Dingtian relays: POWER%d to POWER%d"), Dingtian->first + 1, TasGlobal.devices_present); + AddLog(LOG_LEVEL_DEBUG, PSTR("DNGT: Dingtian relays: POWER%d to POWER%d"), Dingtian->first + 1, TasmotaGlobal.devices_present); } } } From 1f8a303faf5ee84435980edaab5ff5452b23301d Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Tue, 27 Dec 2022 17:57:21 +0100 Subject: [PATCH 054/262] Add SO177 for debugging (#17500) --- tasmota/tasmota.ino | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/tasmota/tasmota.ino b/tasmota/tasmota.ino index 67bf25cd5..b494ed303 100644 --- a/tasmota/tasmota.ino +++ b/tasmota/tasmota.ino @@ -688,10 +688,18 @@ void BacklogLoop(void) { void SleepDelay(uint32_t mseconds) { if (!TasmotaGlobal.backlog_nodelay && mseconds) { uint32_t wait = millis() + mseconds; - while (!TimeReached(wait) && !Serial.available()) { // We need to service serial buffer ASAP as otherwise we get uart buffer overrun - XdrvXsnsCall(FUNC_SLEEP_LOOP); // Main purpose is reacting ASAP on serial data availability or interrupt handling (ADE7880) - delay(1); + + if (Settings->flag6.spare31) { // SetOption177 - (Debug) Disable FUNC_SLEEP_LOOP + while (!TimeReached(wait) && !Serial.available()) { // We need to service serial buffer ASAP as otherwise we get uart buffer overrun + delay(1); + } + } else { + while (!TimeReached(wait) && !Serial.available()) { // We need to service serial buffer ASAP as otherwise we get uart buffer overrun + XdrvXsnsCall(FUNC_SLEEP_LOOP); // Main purpose is reacting ASAP on serial data availability or interrupt handling (ADE7880) + delay(1); + } } + } else { delay(0); } From 1ae8b381bafeb2008f90b8ab3b6a42586837cd6c Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Tue, 27 Dec 2022 20:55:51 +0100 Subject: [PATCH 055/262] Fix warnings when compiling Zigbee (#17524) --- tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_7_6_flash_fs.ino | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_7_6_flash_fs.ino b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_7_6_flash_fs.ino index 347fd0cad..1900e7122 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_7_6_flash_fs.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_7_6_flash_fs.ino @@ -110,10 +110,12 @@ public: #ifdef ESP32 #if ESP_ARDUINO_VERSION > ESP_ARDUINO_VERSION_VAL(2, 0, 5) bool seekDir(long position){ + return false; // ignore } String getNextFileName(void) { + return ""; // ignore } #endif From 790b6feae6757dee8125c5944b585da49f748303 Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Tue, 27 Dec 2022 20:59:56 +0100 Subject: [PATCH 056/262] Change NTP default servers to dual-stack (IPv4/IPv6) (#17525) --- CHANGELOG.md | 1 + tasmota/my_user_config.h | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 269a775d4..a9795865a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ All notable changes to this project will be documented in this file. ### Changed - Tasmota OTA scripts now support both unzipped and gzipped file uploads (#17378) +- Change NTP default servers to dual-stack (IPv4/IPv6) ### Fixed - Shutter default motorstop set to 0 (#17403) diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index f9e52499a..9ecf5ce2e 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -248,9 +248,11 @@ #define MDNS_ENABLED false // [SetOption55] Use mDNS (false = Disable, true = Enable) // -- Time - Up to three NTP servers in your region -#define NTP_SERVER1 "pool.ntp.org" // [NtpServer1] Select first NTP server by name or IP address (129.250.35.250) -#define NTP_SERVER2 "nl.pool.ntp.org" // [NtpServer2] Select second NTP server by name or IP address (5.39.184.5) -#define NTP_SERVER3 "0.nl.pool.ntp.org" // [NtpServer3] Select third NTP server by name or IP address (93.94.224.67) +#define NTP_SERVER1 "2.pool.ntp.org" // [NtpServer1] Select first NTP server by name or IP address (135.125.104.101, 2001:418:3ff::53) +#define NTP_SERVER2 "2.europe.pool.ntp.org" // [NtpServer2] Select second NTP server by name or IP address (192.36.143.134, 2a00:2381:19c6::100) +#define NTP_SERVER3 "2.nl.pool.ntp.org" // [NtpServer3] Select third NTP server by name or IP address (46.249.42.13, 2603:c022:c003:c900::4) + // To manually set: + // BackLog NtpServer1 2.pool.ntp.org; NtpServer2 2.europe.pool.ntp.org; NtpServer3 2.nl.pool.ntp.org // -- Time - Start Daylight Saving Time and timezone offset from UTC in minutes #define TIME_DST_HEMISPHERE North // [TimeDst] Hemisphere (0 or North, 1 or South) From ef1211b51f5ef255a1bb3f3e3477c66aef6e5dbf Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Tue, 27 Dec 2022 21:27:03 +0100 Subject: [PATCH 057/262] Change compile options for ESP8266 IPv6 (#17526) --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index cdd096875..611ffbb11 100644 --- a/platformio.ini +++ b/platformio.ini @@ -99,7 +99,7 @@ build_flags = ${esp_defaults.build_flags} ; NONOSDK22x_190703 = 2.2.2-dev(38a443e) -DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_190703 -DPIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH_LOW_FLASH - ; -DPIO_FRAMEWORK_ARDUINO_LWIP2_IPV6_HIGHER_BANDWIDTH ; enables IPv6 + ; -DPIO_FRAMEWORK_ARDUINO_LWIP2_IPV6_HIGHER_BANDWIDTH -DUSE_IPV6 ; enables IPv6 ; VTABLES in Flash -DVTABLES_IN_FLASH ; remove the 4-bytes alignment for PSTR() From ef4138bdaabad976eba1a2c29f981ab96e38284b Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Tue, 27 Dec 2022 21:59:34 +0100 Subject: [PATCH 058/262] Support for IPv6 only networks on Ethernet (not yet Wifi) (#17527) --- CHANGELOG.md | 1 + .../ESP32-to-ESP8266-compat/src/ESP32Wifi.cpp | 94 +++-- .../ESP32-to-ESP8266-compat/src/ESP8266WiFi.h | 8 +- tasmota/tasmota_support/support_command.ino | 45 ++- tasmota/tasmota_support/support_tasmota.ino | 8 +- tasmota/tasmota_support/support_wifi.ino | 339 +++++++++++++++--- .../xdrv_01_9_webserver.ino | 52 +-- .../tasmota_xdrv_driver/xdrv_02_9_mqtt.ino | 4 +- .../xdrv_52_3_berry_tasmota.ino | 8 +- .../xdrv_82_esp32_ethernet.ino | 71 +++- 10 files changed, 492 insertions(+), 138 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a9795865a..569c21eb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ All notable changes to this project will be documented in this file. - Berry crypto add ``HKDF_HMAC_SHA256`` - Support for up to 3 single phase modbus energy monitoring device using generic Energy Modbus driver - Berry crypto add ``SPAKE2P_Matter`` for Matter support +- Support for IPv6 only networks on Ethernet (not yet Wifi) ### Breaking Changed diff --git a/lib/libesp32/ESP32-to-ESP8266-compat/src/ESP32Wifi.cpp b/lib/libesp32/ESP32-to-ESP8266-compat/src/ESP32Wifi.cpp index 030ec6321..e2522942d 100644 --- a/lib/libesp32/ESP32-to-ESP8266-compat/src/ESP32Wifi.cpp +++ b/lib/libesp32/ESP32-to-ESP8266-compat/src/ESP32Wifi.cpp @@ -21,6 +21,9 @@ #include #include +extern void AddLog(uint32_t loglevel, PGM_P formatP, ...); +enum LoggingLevels {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE}; + // // Wifi // @@ -32,49 +35,97 @@ #include "lwip/dns.h" wl_status_t WiFiClass32::begin(const char* wpa2_ssid, wpa2_auth_method_t method, const char* wpa2_identity, const char* wpa2_username, const char *wpa2_password, const char* ca_pem, const char* client_crt, const char* client_key, int32_t channel, const uint8_t* bssid, bool connect) { - saveDNS(); + scrubDNS(); wl_status_t ret = WiFiClass::begin(wpa2_ssid, method, wpa2_identity, wpa2_username, wpa2_password, ca_pem, client_crt, client_key, channel, bssid, connect); - restoreDNS(); + scrubDNS(); return ret; } wl_status_t WiFiClass32::begin(const char* ssid, const char *passphrase, int32_t channel, const uint8_t* bssid, bool connect) { - saveDNS(); + scrubDNS(); wl_status_t ret = WiFiClass::begin(ssid, passphrase, channel, bssid, connect); - restoreDNS(); + scrubDNS(); return ret; } wl_status_t WiFiClass32::begin(char* ssid, char *passphrase, int32_t channel, const uint8_t* bssid, bool connect) { - saveDNS(); + scrubDNS(); wl_status_t ret = WiFiClass::begin(ssid, passphrase, channel, bssid, connect); - restoreDNS(); + scrubDNS(); return ret; } wl_status_t WiFiClass32::begin() { - saveDNS(); + scrubDNS(); wl_status_t ret = WiFiClass::begin(); - restoreDNS(); + scrubDNS(); return ret; } -void WiFiClass32::saveDNS(void) { - // save the DNS servers - for (uint32_t i=0; i: DNS: from(%s %s) to (%s %s) has4/6:%i-%i", dns_entry0.c_str(), dns_entry1.c_str(), IPAddress(dns_getserver(0)).toString().c_str(), IPAddress(dns_getserver(1)).toString().c_str(), has_v4, has_v6); } void WiFiClass32::setSleepMode(int iSleepMode) { @@ -190,6 +241,7 @@ int WiFiClass32::hostByName(const char* aHostname, IPAddress& aResult, int32_t t aResult = (uint32_t) 0; // by default set to IPv4 0.0.0.0 dns_ipaddr = *IP4_ADDR_ANY; // by default set to IPv4 0.0.0.0 + scrubDNS(); // internal calls to reconnect can zero the DNS servers, save DNS for future use ip_addr_counter++; // increase counter, from now ignore previous responses clearStatusBits(WIFI_DNS_IDLE_BIT | WIFI_DNS_DONE_BIT); uint8_t v4v6priority = LWIP_DNS_ADDRTYPE_IPV4; diff --git a/lib/libesp32/ESP32-to-ESP8266-compat/src/ESP8266WiFi.h b/lib/libesp32/ESP32-to-ESP8266-compat/src/ESP8266WiFi.h index d0274733d..0206b0ec5 100644 --- a/lib/libesp32/ESP32-to-ESP8266-compat/src/ESP8266WiFi.h +++ b/lib/libesp32/ESP32-to-ESP8266-compat/src/ESP8266WiFi.h @@ -60,10 +60,12 @@ public: int hostByName(const char* aHostname, IPAddress& aResult, int32_t timer_ms); int hostByName(const char* aHostname, IPAddress& aResult); - void saveDNS(void); - void restoreDNS(void); + void scrubDNS(void); protected: - ip_addr_t dns_save[DNS_MAX_SERVERS] = {}; + ip_addr_t dns_save4[DNS_MAX_SERVERS] = {}; // IPv4 DNS servers +#ifdef USE_IPV6 + ip_addr_t dns_save6[DNS_MAX_SERVERS] = {}; // IPv6 DNS servers +#endif // USE_IPV6 }; void wifi_station_disconnect(); diff --git a/tasmota/tasmota_support/support_command.ino b/tasmota/tasmota_support/support_command.ino index ca5ec268a..56ef3213f 100644 --- a/tasmota/tasmota_support/support_command.ino +++ b/tasmota/tasmota_support/support_command.ino @@ -804,44 +804,51 @@ void CmndStatus(void) if ((0 == payload) || (5 == payload)) { #ifdef USE_IPV6 if (5 == payload) { WifiDumpAddressesIPv6(); } -#endif // USE_IPV6 + Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS5_NETWORK "\":{\"" D_CMND_HOSTNAME "\":\"%s\",\"" + D_CMND_IPADDRESS "\":\"%_I\",\"" D_JSON_GATEWAY "\":\"%_I\",\"" D_JSON_SUBNETMASK "\":\"%_I\",\"" + D_JSON_DNSSERVER "1\":\"%s\",\"" D_JSON_DNSSERVER "2\":\"%s\",\"" + D_JSON_MAC "\":\"%s\"" + ",\"" D_JSON_IP6_GLOBAL "\":\"%s\",\"" D_JSON_IP6_LOCAL "\":\"%s\""), + TasmotaGlobal.hostname, + (uint32_t)WiFi.localIP(), Settings->ipv4_address[1], Settings->ipv4_address[2], + DNSGetIPStr(0).c_str(), DNSGetIPStr(1).c_str(), + WiFi.macAddress().c_str() + ,WifiGetIPv6Str().c_str(), WifiGetIPv6LinkLocalStr().c_str()); +#else // USE_IPV6 Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS5_NETWORK "\":{\"" D_CMND_HOSTNAME "\":\"%s\",\"" D_CMND_IPADDRESS "\":\"%_I\",\"" D_JSON_GATEWAY "\":\"%_I\",\"" D_JSON_SUBNETMASK "\":\"%_I\",\"" D_JSON_DNSSERVER "1\":\"%_I\",\"" D_JSON_DNSSERVER "2\":\"%_I\",\"" - D_JSON_MAC "\":\"%s\"" -#ifdef USE_IPV6 - ",\"" D_JSON_IP6_GLOBAL "\":\"%s\",\"" D_JSON_IP6_LOCAL "\":\"%s\"" -#endif // USE_IPV6 - ), + D_JSON_MAC "\":\"%s\""), TasmotaGlobal.hostname, (uint32_t)WiFi.localIP(), Settings->ipv4_address[1], Settings->ipv4_address[2], Settings->ipv4_address[3], Settings->ipv4_address[4], - WiFi.macAddress().c_str() -#ifdef USE_IPV6 - ,WifiGetIPv6().c_str(), WifiGetIPv6LinkLocal().c_str() + WiFi.macAddress().c_str()); #endif // USE_IPV6 - ); #ifdef USE_TASMESH ResponseAppend_P(PSTR(",\"SoftAPMac\":\"%s\""), WiFi.softAPmacAddress().c_str()); #endif // USE_TASMESH #if defined(ESP32) && CONFIG_IDF_TARGET_ESP32 && defined(USE_ETHERNET) +#ifdef USE_IPV6 + ResponseAppend_P(PSTR(",\"Ethernet\":{\"" D_CMND_HOSTNAME "\":\"%s\",\"" + D_CMND_IPADDRESS "\":\"%_I\",\"" D_JSON_GATEWAY "\":\"%_I\",\"" D_JSON_SUBNETMASK "\":\"%_I\",\"" + D_JSON_DNSSERVER "1\":\"%s\",\"" D_JSON_DNSSERVER "2\":\"%s\",\"" + D_JSON_MAC "\":\"%s\",\"" D_JSON_IP6_GLOBAL "\":\"%s\",\"" D_JSON_IP6_LOCAL "\":\"%s\"}"), + EthernetHostname(), + (uint32_t)EthernetLocalIP(), Settings->eth_ipv4_address[1], Settings->eth_ipv4_address[2], + DNSGetIPStr(0).c_str(), DNSGetIPStr(1).c_str(), + EthernetMacAddress().c_str(), + EthernetGetIPv6Str().c_str(), EthernetGetIPv6LinkLocalStr().c_str()); +#else // USE_IPV6 ResponseAppend_P(PSTR(",\"Ethernet\":{\"" D_CMND_HOSTNAME "\":\"%s\",\"" D_CMND_IPADDRESS "\":\"%_I\",\"" D_JSON_GATEWAY "\":\"%_I\",\"" D_JSON_SUBNETMASK "\":\"%_I\",\"" D_JSON_DNSSERVER "1\":\"%_I\",\"" D_JSON_DNSSERVER "2\":\"%_I\",\"" - D_JSON_MAC "\":\"%s\"" - -#ifdef USE_IPV6 - ",\"" D_JSON_IP6_GLOBAL "\":\"%s\",\"" D_JSON_IP6_LOCAL "\":\"%s\"" -#endif // USE_IPV6 - "}"), + D_JSON_MAC "\":\"%s\"}"), EthernetHostname(), (uint32_t)EthernetLocalIP(), Settings->eth_ipv4_address[1], Settings->eth_ipv4_address[2], Settings->eth_ipv4_address[3], Settings->eth_ipv4_address[4], EthernetMacAddress().c_str() -#ifdef USE_IPV6 - ,EthernetGetIPv6().c_str(), EthernetGetIPv6LinkLocal().c_str() + #endif // USE_IPV6 - ); #endif // USE_ETHERNET ResponseAppend_P(PSTR(",\"" D_CMND_WEBSERVER "\":%d,\"HTTP_API\":%d,\"" D_CMND_WIFICONFIG "\":%d,\"" D_CMND_WIFIPOWER "\":%s}}"), Settings->webserver, Settings->flag5.disable_referer_chk, Settings->sta_config, WifiGetOutputPower().c_str()); diff --git a/tasmota/tasmota_support/support_tasmota.ino b/tasmota/tasmota_support/support_tasmota.ino index f8234b9d3..f5da6c033 100644 --- a/tasmota/tasmota_support/support_tasmota.ino +++ b/tasmota/tasmota_support/support_tasmota.ino @@ -1576,14 +1576,10 @@ void Every250mSeconds(void) if (Settings->webserver) { #ifdef ESP8266 - if (!WifiIsInManagerMode()) { StartWebserver(Settings->webserver, WiFi.localIP()); } + if (!WifiIsInManagerMode()) { StartWebserver(Settings->webserver); } #endif // ESP8266 #ifdef ESP32 -#ifdef USE_ETHERNET - StartWebserver(Settings->webserver, (EthernetLocalIP()) ? EthernetLocalIP() : WiFi.localIP()); -#else - StartWebserver(Settings->webserver, WiFi.localIP()); -#endif + StartWebserver(Settings->webserver); #endif // ESP32 #ifdef USE_DISCOVERY diff --git a/tasmota/tasmota_support/support_wifi.ino b/tasmota/tasmota_support/support_wifi.ino index d03b55699..1baa6652a 100644 --- a/tasmota/tasmota_support/support_wifi.ino +++ b/tasmota/tasmota_support/support_wifi.ino @@ -41,6 +41,7 @@ const uint8_t WIFI_CHECK_SEC = 20; // seconds const uint8_t WIFI_RETRY_OFFSET_SEC = WIFI_RETRY_SECONDS; // seconds #include // Wifi, MQTT, Ota, WifiManager +#include "lwip/dns.h" int WifiGetRssiAsQuality(int rssi) { int quality = 0; @@ -458,37 +459,110 @@ void WifiSetState(uint8_t state) } } +/*****************************************************************************************************\ + * IP detection revised for full IPv4 / IPv6 support + * + * In general, each interface (Wifi/Eth) can have 1x IPv4 and + * 2x IPv6 (Global routable address and Link-Local starting witn fe80:...) + * + * We always use an IPv4 address if one is assigned, and revert to + * IPv6 only on networks that are v6 only. + * Ethernet calls can be safely used even if the USE_ETHERNET is not enabled + * + * New APIs: + * - general form is: + * `bool XXXGetIPYYY(IPAddress*)` returns `true` if the address exists and copies the address + * if the pointer is non-null. + * `bool XXXHasIPYYY()` same as above but only returns `true` or `false` + * `String XXXGetIPYYYStr()` returns the IP as a `String` or empty `String` if none + * + * `XXX` can be `Wifi` or `Eth` + * `YYY` can be `` for any address, `v6` for IPv6 global address or `v6LinkLocal` for Link-local + * + * - Legacy `Wifi.localIP()` and `ETH.localIP()` always return IPv4 and nothing on IPv6 only networks + * + * - v4/v6: + * `WifiGetIP`, `WifiGetIPStr`, `WifiHasIP`: get preferred v4/v6 address for Wifi + * `EthernetGetIP`, `EthernetGetIPStr`, `EthernetHasIP`: get preferred v4/v6 for Ethernet + * + * - Main IP to be used dual stack v4/v6 + * `hasIP`, `IPGetListeningAddress`, `IPGetListeningAddressStr`: any IP to listen to for Web Server + * IPv4 is always preferred, and Eth is preferred over Wifi. + * `IPForUrl`: converts v4/v6 to use in URL, enclosing v6 in [] + * + * - v6 only: + * `WifiGetIPv6`, `WifiGetIPv6Str`, `WifiHasIPv6` + * `WifiGetIPv6LinkLocal`, `WifiGetIPv6LinkLocalStr` + * `EthernetGetIPv6, `EthernetHasIPv6`, `EthernetGetIPv6Str` + * `EthernetGetIPv6LinkLocal`, `EthernetGetIPv6LinkLocalStr` + * + * - v4 only: + * `WifiGetIPv4`, `WifiGetIPv4Str`, `WifiHasIPv4` + * `EthernetGetIPv4`, `EthernetGetIPv4Str`, `EthernetHasIPv4` + * + * - DNS reporting actual values used (not the Settings): + * `DNSGetIP(n)`, `DNSGetIPStr(n)` with n=`0`/`1` (same dns for Wifi and Eth) +\*****************************************************************************************************/ +// IPv4 for Wifi +// Returns only IPv6 global address (no loopback and no link-local) +bool WifiGetIPv4(IPAddress *ip) +{ + uint32_t wifi_uint = (uint32_t) WiFi.localIP(); + if (ip != nullptr) { *ip = wifi_uint; } + return wifi_uint != 0; +} +bool WifiHasIPv4(void) +{ + return WifiGetIPv4(nullptr); +} +String WifiGetIPv4Str(void) +{ + IPAddress ip; + return WifiGetIPv4(&ip) ? ip.toString() : String(); +} + +bool EthernetGetIPv4(IPAddress *ip) +{ +#if defined(ESP32) && CONFIG_IDF_TARGET_ESP32 && defined(USE_ETHERNET) + uint32_t wifi_uint = (uint32_t) EthernetLocalIP(); + if (ip != nullptr) { *ip = wifi_uint; } + return wifi_uint != 0; +#else + if (ip != nullptr) { *ip = (uint32_t)0; } + return false; +#endif +} +bool EthernetHasIPv4(void) +{ + return EthernetGetIPv4(nullptr); +} +String EthernetGetIPv4Str(void) +{ + IPAddress ip; + return EthernetGetIPv4(&ip) ? ip.toString() : String(); +} + #ifdef USE_IPV6 // // Scan through all interfaces to find a global or local IPv6 address // Arg: // is_local: is the address Link-Local (true) or Global (false) // if_type: possible values are "st" for Wifi STA, "en" for Ethernet, "lo" for localhost (not useful) -static String WifiFindIPv6(bool is_local, const char * if_type = "st") { +// Returns `true` if found +bool WifiFindIPv6(IPAddress *ip, bool is_local, const char * if_type = "st") { for (netif* intf = netif_list; intf != nullptr; intf = intf->next) { if (intf->name[0] == if_type[0] && intf->name[1] == if_type[1]) { for (uint32_t i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { ip_addr_t *ipv6 = &intf->ip6_addr[i]; if (IP_IS_V6_VAL(*ipv6) && !ip_addr_isloopback(ipv6) && !ip_addr_isany(ipv6) && ((bool)ip_addr_islinklocal(ipv6) == is_local)) { - return IPAddress(ipv6).toString(); + if (ip != nullptr) { *ip = *ipv6; } + return true; } } } } - return String(); + return false; } - -// Returns only IPv6 global address (no loopback and no link-local) -String WifiGetIPv6(void) -{ - return WifiFindIPv6(false, "st"); -} - -String WifiGetIPv6LinkLocal(void) -{ - return WifiFindIPv6(true, "st"); -} - // add an IPv6 link-local address to all netif void CreateLinkLocalIPv6(void) { @@ -499,6 +573,81 @@ void CreateLinkLocalIPv6(void) #endif // ESP32 } + +// Returns only IPv6 global address (no loopback and no link-local) +bool WifiGetIPv6(IPAddress *ip) +{ + return WifiFindIPv6(ip, false, "st"); +} +bool WifiHasIPv6(void) +{ + return WifiGetIPv6(nullptr); +} +String WifiGetIPv6Str(void) +{ + IPAddress ip; + return WifiGetIPv6(&ip) ? ip.toString() : String(); +} + +bool WifiGetIPv6LinkLocal(IPAddress *ip) +{ + return WifiFindIPv6(ip, true, "st"); +} +String WifiGetIPv6LinkLocalStr(void) +{ + IPAddress ip; + return WifiGetIPv6LinkLocal(&ip) ? ip.toString() : String(); +} + + +// Returns only IPv6 global address (no loopback and no link-local) +bool EthernetGetIPv6(IPAddress *ip) +{ + return WifiFindIPv6(ip, false, "en"); +} +bool EthernetHasIPv6(void) +{ + return EthernetGetIPv6(nullptr); +} +String EthernetGetIPv6Str(void) +{ + IPAddress ip; + return EthernetGetIPv6(&ip) ? ip.toString() : String(); +} + +bool EthernetGetIPv6LinkLocal(IPAddress *ip) +{ + return WifiFindIPv6(ip, true, "en"); +} +bool EthernetHasIPv6LinkLocal(void) +{ + return EthernetGetIPv6LinkLocal(nullptr); +} +String EthernetGetIPv6LinkLocalStr(void) +{ + IPAddress ip; + return EthernetGetIPv6LinkLocal(&ip) ? ip.toString() : String(); +} + +bool DNSGetIP(IPAddress *ip, uint32_t idx) +{ +#ifdef ESP32 + WiFi.scrubDNS(); // internal calls to reconnect can zero the DNS servers, restore the previous values +#endif + const ip_addr_t *ip_dns = dns_getserver(idx); + if (!ip_addr_isany(ip_dns)) { + if (ip != nullptr) { *ip = *ip_dns; } + return true; + } + *ip = *IP4_ADDR_ANY; + return false; +} +String DNSGetIPStr(uint32_t idx) +{ + IPAddress ip; + return DNSGetIP(&ip, idx) ? ip.toString() : String(F("0.0.0.0")); +} + // #include "lwip/dns.h" void WifiDumpAddressesIPv6(void) @@ -507,31 +656,144 @@ void WifiDumpAddressesIPv6(void) if (!ip_addr_isany_val(intf->ip_addr)) AddLog(LOG_LEVEL_DEBUG, "WIF: '%c%c' IPv4 %s", intf->name[0], intf->name[1], IPAddress(intf->ip_addr).toString().c_str()); for (uint32_t i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (!ip_addr_isany_val(intf->ip6_addr[i])) - AddLog(LOG_LEVEL_DEBUG, "WIF: '%c%c' IPv6 %s %s", intf->name[0], intf->name[1], + AddLog(LOG_LEVEL_DEBUG, "IP : '%c%c' IPv6 %s %s", intf->name[0], intf->name[1], IPAddress(intf->ip6_addr[i]).toString().c_str(), ip_addr_islinklocal(&intf->ip6_addr[i]) ? "local" : ""); } } - AddLog(LOG_LEVEL_DEBUG, "WIF: DNS(0): %s", IPAddress(dns_getserver(0)).toString().c_str()); - AddLog(LOG_LEVEL_DEBUG, "WIF: DNS(1): %s", IPAddress(dns_getserver(1)).toString().c_str()); + AddLog(LOG_LEVEL_DEBUG, "IP : DNS: %s %s", IPAddress(dns_getserver(0)).toString().c_str(), IPAddress(dns_getserver(1)).toString().c_str()); + AddLog(LOG_LEVEL_DEBUG, "WIF: v4IP: %_I v6IP: %s mainIP: %s", (uint32_t) WiFi.localIP(), WifiGetIPv6Str().c_str(), WifiGetIPStr().c_str()); +#if defined(ESP32) && CONFIG_IDF_TARGET_ESP32 && defined(USE_ETHERNET) + AddLog(LOG_LEVEL_DEBUG, "ETH: v4IP %_I v6IP: %s mainIP: %s", (uint32_t) EthernetLocalIP(), EthernetGetIPv6Str().c_str(), EthernetGetIPStr().c_str()); +#endif + AddLog(LOG_LEVEL_DEBUG, "IP : ListeningIP %s", IPGetListeningAddressStr().c_str()); } #endif // USE_IPV6 -// Check to see if we have any routable IP address -bool WifiHasIP(void) { +// Returns the IP address on which we listen (used for Web UI mainly) +// +// If IPv4 is set, it is preferred. +// If only IPv6, return the routable global address +bool IPGetListeningAddress(IPAddress * ip) +{ + if (ip == nullptr) return HasIP(); // no value added for this method if no parameter + #ifdef USE_IPV6 -#ifdef ESP32 - return !WiFi.localIP().isAny(); -#else // ESP32 - const ip_addr_t &ipaddr = (ip_addr_t)WiFi.localIP(); - return !ip_addr_isany_val(ipaddr); -#endif // ESP32 + // collect both Wifi and Eth IPs and choose an IPv4 if any (Eth has priority) + IPAddress ip_wifi; + bool has_wifi = WifiGetIP(&ip_wifi); + +#if defined(ESP32) && CONFIG_IDF_TARGET_ESP32 && defined(USE_ETHERNET) + IPAddress ip_eth; + bool has_eth = EthernetGetIP(&ip_eth); + if (has_wifi && has_eth) { + if (ip_eth.isV4()) { *ip = ip_eth; return true; } + if (ip_wifi.isV4()) { *ip = ip_wifi; return true; } + // both addresses are v6, return ETH + *ip = ip_eth; + return true; + } + // from here only wifi or eth may be valid + if (has_eth) { *ip = ip_eth; return true; } +#endif + + if (has_wifi) { *ip = ip_wifi; return true; } + + *ip = IPAddress(); + return false; +#else // USE_IPV6 +#if defined(ESP32) && CONFIG_IDF_TARGET_ESP32 && defined(USE_ETHERNET) + if (EthernetGetIP(ip)) { return true; } +#endif + if (WifiGetIP(ip)) { return true; } + *ip = IPAddress(); + return false; +#endif // USE_IPV6 +} + +String IPGetListeningAddressStr(void) +{ + IPAddress ip; + if (IPGetListeningAddress(&ip)) { + return ip.toString(); + } else { + return String(); + } +} + +// Because of IPv6, we can't test an IP address agains (uint32_t)0L anymore +// This test would work only for IPv4 assigned addresses. +// We must now use the following instead +inline bool IPIsValid(const IPAddress & ip) +{ +#ifdef USE_IPV6 + return !ip_addr_isany_val((const ip_addr_t &)ip); +#else + return static_cast(ip) != 0; +#endif +} + +// Because of IPv6, URL encoding of IP address needs to be adapted +// IPv4: address is "x.x.x.x" +// IPv6: address is enclosed in brackets "[x.x::x.x...]" +String IPForUrl(const IPAddress & ip) +{ +#ifdef USE_IPV6 + if (ip.isV4()) { + return ip.toString().c_str(); + } else { + String s('['); + s += ip.toString().c_str(); + s += ']'; + return s; + } +#else + return ip.toString().c_str(); +#endif +} + +// Check to see if we have any routable IP address +// IPv4 has always priority +// Copy the value of the IP if pointer provided (optional) +bool WifiGetIP(IPAddress *ip) { +#ifdef USE_IPV6 + if ((uint32_t)WiFi.localIP() != 0) { + if (ip != nullptr) { *ip = WiFi.localIP(); } + return true; + } + IPAddress lip; + if (WifiGetIPv6(&lip)) { + if (ip != nullptr) { *ip = lip; } + return true; + } + if (ip != nullptr) { *ip = IPAddress(); } + return false; #else // IPv4 only + if (ip != nullptr) { *ip = WiFi.localIP(); } return (uint32_t)WiFi.localIP() != 0; #endif // USE_IPV6 } +bool WifiHasIP(void) { + return WifiGetIP(nullptr); +} + +String WifiGetIPStr(void) +{ + IPAddress ip; + return WifiGetIP(&ip) ? ip.toString() : String(); +} + +// Has a routable IP, whether IPv4 or IPv6, Wifi or Ethernet +bool HasIP(void) { + if (WifiHasIP()) return true; +#if defined(ESP32) && CONFIG_IDF_TARGET_ESP32 && defined(USE_ETHERNET) + if (EthernetHasIP()) return true; +#endif + return false; +} + void WifiCheckIp(void) { #ifdef USE_IPV6 if (WL_CONNECTED == WiFi.status()) { @@ -904,20 +1166,14 @@ bool WifiDNSGetIPv6Priority(void) { // Any change in logic needs to clear the DNS cache static bool had_v6prio = false; - const ip_addr_t &local_ip = (ip_addr_t)WiFi.localIP(); - bool has_v4 = !ip_addr_isany_val(local_ip) && IP_IS_V4_VAL(local_ip); - bool has_v6 = WifiGetIPv6().length() != 0; -#ifdef USE_ETHERNET - const ip_addr_t &local_ip_eth = (ip_addr_t)EthernetLocalIP(); - has_v4 = has_v4 || (!ip_addr_isany_val(local_ip_eth) && IP_IS_V4_VAL(local_ip_eth)); - has_v6 = has_v6 || EthernetGetIPv6().length() != 0; -#endif - + bool has_v4 = WifiHasIPv4() || EthernetHasIPv4(); + bool has_v6 = WifiHasIPv6() || EthernetHasIPv6(); bool v6prio = Settings->flag6.dns_ipv6_priority; - // AddLog(LOG_LEVEL_DEBUG, "WIF: v6 priority was %i, now is %i, has_v4=%i has_v6=%i", had_v6prio, v6prio, has_v4, has_v6); - if (has_v4 && !has_v6 && v6prio) { + if (has_v4 && !has_v6) { v6prio = false; // revert to IPv4 first + } else if (has_v6 && !has_v4) { + v6prio = true; // only IPv6 is available } // any change of state requires a dns cache clear @@ -1107,7 +1363,6 @@ void WifiEvents(arduino_event_t *event) { #ifdef USE_IPV6 case ARDUINO_EVENT_WIFI_STA_GOT_IP6: - case ARDUINO_EVENT_ETH_GOT_IP6: { ip_addr_t ip_addr6; ip_addr_copy_from_ip6(ip_addr6, event->event_info.got_ip6.ip6_info.ip); @@ -1115,21 +1370,17 @@ void WifiEvents(arduino_event_t *event) { AddLog(LOG_LEVEL_DEBUG, PSTR("%s: IPv6 %s %s"), event->event_id == ARDUINO_EVENT_ETH_GOT_IP6 ? "ETH" : "WIF", addr.isLocal() ? PSTR("Local") : PSTR("Global"), addr.toString().c_str()); - WiFi.saveDNS(); // internal calls to reconnect can zero the DNS servers, save DNS for future use } break; #endif // USE_IPV6 case ARDUINO_EVENT_WIFI_STA_GOT_IP: - case ARDUINO_EVENT_ETH_GOT_IP: { ip_addr_t ip_addr4; ip_addr_copy_from_ip4(ip_addr4, event->event_info.got_ip.ip_info.ip); - AddLog(LOG_LEVEL_DEBUG, PSTR("%s: IPv4 %_I, mask %_I, gateway %_I"), - event->event_id == ARDUINO_EVENT_ETH_GOT_IP ? "ETH" : "WIF", + AddLog(LOG_LEVEL_DEBUG, PSTR("WIF: IPv4 %_I, mask %_I, gateway %_I"), event->event_info.got_ip.ip_info.ip.addr, event->event_info.got_ip.ip_info.netmask.addr, event->event_info.got_ip.ip_info.gw.addr); - WiFi.saveDNS(); // internal calls to reconnect can zero the DNS servers, save DNS for future use } break; @@ -1139,12 +1390,12 @@ void WifiEvents(arduino_event_t *event) { break; case ARDUINO_EVENT_WIFI_STA_DISCONNECTED: case ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE: - WiFi.restoreDNS(); // internal calls to reconnect can zero the DNS servers, restore the previous values Wifi.ipv6_local_link_called = false; break; default: break; } + WiFi.scrubDNS(); // internal calls to reconnect can zero the DNS servers, restore the previous values } #endif // ESP32 diff --git a/tasmota/tasmota_xdrv_driver/xdrv_01_9_webserver.ino b/tasmota/tasmota_xdrv_driver/xdrv_01_9_webserver.ino index 94eaf5d27..de4a3a498 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_01_9_webserver.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_01_9_webserver.ino @@ -570,7 +570,8 @@ void WebServer_on(const char * prefix, void (*func)(void), uint8_t method = HTTP #endif // ESP32 } -void StartWebserver(int type, IPAddress ipweb) +// Always listens to all interfaces, so we don't need an IP address anymore +void StartWebserver(int type) { if (!Settings->web_refresh) { Settings->web_refresh = HTTP_REFRESH_TIME; } if (!Web.state) { @@ -610,19 +611,8 @@ void StartWebserver(int type, IPAddress ipweb) Webserver->begin(); // Web server start } if (Web.state != type) { -#ifdef USE_IPV6 - String ipv6_addr = WifiGetIPv6(); - if (ipv6_addr!="") { - AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %_I and IPv6 global address %s "), - NetworkHostname(), (Mdns.begun) ? PSTR(".local") : "", (uint32_t)ipweb, ipv6_addr.c_str()); - } else { - AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %_I"), - NetworkHostname(), (Mdns.begun) ? PSTR(".local") : "", (uint32_t)ipweb); - } -#else - AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %_I"), - NetworkHostname(), (Mdns.begun) ? PSTR(".local") : "", (uint32_t)ipweb); -#endif // USE_IPV6 + AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %s"), + NetworkHostname(), (Mdns.begun) ? PSTR(".local") : "", IPGetListeningAddressStr().c_str()); TasmotaGlobal.rules_flag.http_init = 1; Web.state = type; } @@ -663,7 +653,7 @@ void WifiManagerBegin(bool reset_only) DnsServer->setErrorReplyCode(DNSReplyCode::NoError); DnsServer->start(DNS_PORT, "*", WiFi.softAPIP()); - StartWebserver((reset_only ? HTTP_MANAGER_RESET_ONLY : HTTP_MANAGER), WiFi.softAPIP()); + StartWebserver((reset_only ? HTTP_MANAGER_RESET_ONLY : HTTP_MANAGER)); } void PollDnsWebserver(void) @@ -700,12 +690,14 @@ bool HttpCheckPriviledgedAccess(bool autorequestauth = true) referer.toUpperCase(); String hostname = TasmotaGlobal.hostname; hostname.toUpperCase(); + // TODO rework if IPv6 if ((referer.indexOf(hostname) == 7) || (referer.indexOf(WiFi.localIP().toString()) == 7)) { return true; } #if defined(ESP32) && CONFIG_IDF_TARGET_ESP32 && defined(USE_ETHERNET) hostname = EthernetHostname(); hostname.toUpperCase(); + // TODO rework if IPv6 if ((referer.indexOf(hostname) == 7) || (referer.indexOf(EthernetLocalIP().toString()) == 7)) { return true; } @@ -898,7 +890,7 @@ void WSContentSendStyle_P(const char* formatP, ...) { #else if ( Settings->flag3.gui_hostname_ip || ( (WiFi.getMode() == WIFI_AP_STA) && (!Web.initial_config) ) ) { #endif - bool lip = (static_cast(WiFi.localIP()) != 0); + bool lip = WifiHasIP(); bool sip = (static_cast(WiFi.softAPIP()) != 0); bool eip = false; if (lip || sip) { @@ -910,7 +902,7 @@ void WSContentSendStyle_P(const char* formatP, ...) { (sip) ? WiFi.softAPIP().toString().c_str() : ""); } #if defined(ESP32) && CONFIG_IDF_TARGET_ESP32 && defined(USE_ETHERNET) - eip = (static_cast(EthernetLocalIP()) != 0); + eip = EthernetHasIP(); if (eip) { WSContentSend_P(PSTR("%s%s%s (%s)"), // tasmota-eth.local (192.168.2.13) (lip || sip) ? PSTR("
") : PSTR("

"), @@ -1015,8 +1007,8 @@ void WebRestart(uint32_t type) { #if ((RESTART_AFTER_INITIAL_WIFI_CONFIG) && (AFTER_INITIAL_WIFI_CONFIG_GO_TO_NEW_IP)) // In case of type 3 (New network has been configured) go to the new device's IP in the new Network if (3 == type) { - WSContentSend_P("setTimeout(function(){location.href='http://%_I';},%d);", - (uint32_t)WiFi.localIP(), + WSContentSend_P("setTimeout(function(){location.href='http://%s';},%d);", + IPForUrl(WiFi.localIP()).c_str(), HTTP_RESTART_RECONNECT_TIME ); } else { @@ -2360,11 +2352,11 @@ void HandleInformation(void) WSContentSend_P(PSTR("}1" D_AP "%d " D_SSID " (" D_RSSI ")}2%s (%d%%, %d dBm) 11%c"), Settings->sta_active +1, HtmlEscape(SettingsText(SET_STASSID1 + Settings->sta_active)).c_str(), WifiGetRssiAsQuality(rssi), rssi, pgm_read_byte(&kWifiPhyMode[WiFi.getPhyMode() & 0x3]) ); WSContentSend_P(PSTR("}1" D_HOSTNAME "}2%s%s"), TasmotaGlobal.hostname, (Mdns.begun) ? PSTR(".local") : ""); #ifdef USE_IPV6 - String ipv6_addr = WifiGetIPv6(); + String ipv6_addr = WifiGetIPv6Str(); if (ipv6_addr != "") { WSContentSend_P(PSTR("}1 IPv6 Global (wifi)}2%s"), ipv6_addr.c_str()); } - ipv6_addr = WifiGetIPv6LinkLocal(); + ipv6_addr = WifiGetIPv6LinkLocalStr(); if (ipv6_addr != "") { WSContentSend_P(PSTR("}1 IPv6 Local (wifi)}2%s"), ipv6_addr.c_str()); } @@ -2378,21 +2370,26 @@ void HandleInformation(void) if (!TasmotaGlobal.global_state.wifi_down) { WSContentSend_P(PSTR("}1" D_GATEWAY "}2%_I"), Settings->ipv4_address[1]); WSContentSend_P(PSTR("}1" D_SUBNET_MASK "}2%_I"), Settings->ipv4_address[2]); +#ifdef USE_IPV6 + WSContentSend_P(PSTR("}1" D_DNS_SERVER "1}2%s"), DNSGetIPStr(0).c_str()); + WSContentSend_P(PSTR("}1" D_DNS_SERVER "2}2%s"), DNSGetIPStr(1).c_str()); +#else // USE_IPV6 WSContentSend_P(PSTR("}1" D_DNS_SERVER "1}2%_I"), Settings->ipv4_address[3]); WSContentSend_P(PSTR("}1" D_DNS_SERVER "2}2%_I"), Settings->ipv4_address[4]); +#endif // USE_IPV6 } #if defined(ESP32) && CONFIG_IDF_TARGET_ESP32 && defined(USE_ETHERNET) - if (static_cast(EthernetLocalIP()) != 0) { + if (EthernetHasIP()) { if (show_hr) { WSContentSend_P(PSTR("}1
}2
")); } WSContentSend_P(PSTR("}1" D_HOSTNAME "}2%s%s"), EthernetHostname(), (Mdns.begun) ? PSTR(".local") : ""); #ifdef USE_IPV6 - String ipv6_eth_addr = EthernetGetIPv6(); + String ipv6_eth_addr = EthernetGetIPv6Str(); if (ipv6_eth_addr != "") { WSContentSend_P(PSTR("}1 IPv6 Global (eth)}2%s"), ipv6_eth_addr.c_str()); } - ipv6_eth_addr = EthernetGetIPv6LinkLocal(); + ipv6_eth_addr = EthernetGetIPv6LinkLocalStr(); if (ipv6_eth_addr != "") { WSContentSend_P(PSTR("}1 IPv6 Local (eth)}2%s"), ipv6_eth_addr.c_str()); } @@ -2403,8 +2400,13 @@ void HandleInformation(void) if (!TasmotaGlobal.global_state.eth_down) { WSContentSend_P(PSTR("}1" D_GATEWAY "}2%_I"), Settings->eth_ipv4_address[1]); WSContentSend_P(PSTR("}1" D_SUBNET_MASK "}2%_I"), Settings->eth_ipv4_address[2]); +#ifdef USE_IPV6 + WSContentSend_P(PSTR("}1" D_DNS_SERVER "1}2%s"), DNSGetIPStr(0).c_str()); + WSContentSend_P(PSTR("}1" D_DNS_SERVER "2}2%s"), DNSGetIPStr(1).c_str()); +#else // USE_IPV6 WSContentSend_P(PSTR("}1" D_DNS_SERVER "1}2%_I"), Settings->eth_ipv4_address[3]); WSContentSend_P(PSTR("}1" D_DNS_SERVER "2}2%_I"), Settings->eth_ipv4_address[4]); +#endif // USE_IPV6 } #endif // USE_ETHERNET WSContentSend_P(PSTR("}1}2 ")); // Empty line @@ -3724,7 +3726,7 @@ bool Xdrv01(uint32_t function) Wifi.wifi_test_AP_TIMEOUT = false; Wifi.wifi_test_counter = 0; Wifi.wifiTest = WIFI_TEST_FINISHED; - AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_WIFI D_CMND_SSID " %s: " D_CONNECTED " - " D_IP_ADDRESS " %_I"), SettingsText(Wifi.wifi_Test_Save_SSID2 ? SET_STASSID2 : SET_STASSID1), (uint32_t)WiFi.localIP()); + AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_WIFI D_CMND_SSID " %s: " D_CONNECTED " - " D_IP_ADDRESS " %s"), SettingsText(Wifi.wifi_Test_Save_SSID2 ? SET_STASSID2 : SET_STASSID1), WiFi.localIP().toString().c_str()); // TasmotaGlobal.blinks = 255; // Signal wifi connection with blinks if (MAX_WIFI_OPTION != Wifi.old_wificonfig) { TasmotaGlobal.wifi_state_flag = Settings->sta_config = Wifi.old_wificonfig; diff --git a/tasmota/tasmota_xdrv_driver/xdrv_02_9_mqtt.ino b/tasmota/tasmota_xdrv_driver/xdrv_02_9_mqtt.ino index b4407804d..849220e0f 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_02_9_mqtt.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_02_9_mqtt.ino @@ -972,8 +972,8 @@ void MqttConnected(void) { ResponseAppend_P(PSTR(",\"" D_CMND_HOSTNAME "\":\"%s\",\"" D_CMND_IPADDRESS "\":\"%_I\""), TasmotaGlobal.hostname, (uint32_t)WiFi.localIP()); #ifdef USE_IPV6 - ResponseAppend_P(PSTR(",\"" D_JSON_IP6_GLOBAL "\":\"%s\""), WifiGetIPv6().c_str()); - ResponseAppend_P(PSTR(",\"" D_JSON_IP6_LOCAL "\":\"%s\""), WifiGetIPv6LinkLocal().c_str()); + ResponseAppend_P(PSTR(",\"" D_JSON_IP6_GLOBAL "\":\"%s\""), WifiGetIPv6Str().c_str()); + ResponseAppend_P(PSTR(",\"" D_JSON_IP6_LOCAL "\":\"%s\""), WifiGetIPv6LinkLocalStr().c_str()); #endif // USE_IPV6 } #if defined(ESP32) && CONFIG_IDF_TARGET_ESP32 && defined(USE_ETHERNET) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota.ino index c42f6e003..015d505e7 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota.ino @@ -215,12 +215,12 @@ extern "C" { int32_t rssi = WiFi.RSSI(); bool show_rssi = false; #ifdef USE_IPV6 - String ipv6_addr = WifiGetIPv6(); + String ipv6_addr = WifiGetIPv6Str(); if (ipv6_addr != "") { be_map_insert_str(vm, "ip6", ipv6_addr.c_str()); show_rssi = true; } - ipv6_addr = WifiGetIPv6LinkLocal(); + ipv6_addr = WifiGetIPv6LinkLocalStr(); if (ipv6_addr != "") { be_map_insert_str(vm, "ip6local", ipv6_addr.c_str()); show_rssi = true; @@ -255,11 +255,11 @@ extern "C" { be_map_insert_str(vm, "ip", IPAddress((uint32_t)EthernetLocalIP()).toString().c_str()); // quick fix for IPAddress bug } #ifdef USE_IPV6 - String ipv6_addr = EthernetGetIPv6(); + String ipv6_addr = EthernetGetIPv6Str(); if (ipv6_addr != "") { be_map_insert_str(vm, "ip6", ipv6_addr.c_str()); } - ipv6_addr = EthernetGetIPv6LinkLocal(); + ipv6_addr = EthernetGetIPv6LinkLocalStr(); if (ipv6_addr != "") { be_map_insert_str(vm, "ip6local", ipv6_addr.c_str()); } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_82_esp32_ethernet.ino b/tasmota/tasmota_xdrv_driver/xdrv_82_esp32_ethernet.ino index c7f193536..a34c8cf0b 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_82_esp32_ethernet.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_82_esp32_ethernet.ino @@ -116,9 +116,31 @@ void EthernetEvent(arduino_event_t *event) { } TasmotaGlobal.rules_flag.eth_connected = 1; TasmotaGlobal.global_state.eth_down = 0; - WiFi.saveDNS(); // internal calls to reconnect can zero the DNS servers, save DNS for future use + AddLog(LOG_LEVEL_DEBUG, PSTR("ETH: IPv4 %_I, mask %_I, gateway %_I"), + event->event_info.got_ip.ip_info.ip.addr, + event->event_info.got_ip.ip_info.netmask.addr, + event->event_info.got_ip.ip_info.gw.addr); + WiFi.scrubDNS(); // internal calls to reconnect can zero the DNS servers, save DNS for future use break; +#ifdef USE_IPV6 + case ARDUINO_EVENT_ETH_GOT_IP6: + { + ip_addr_t ip_addr6; + ip_addr_copy_from_ip6(ip_addr6, event->event_info.got_ip6.ip6_info.ip); + IPAddress addr(ip_addr6); + AddLog(LOG_LEVEL_DEBUG, PSTR("%s: IPv6 %s %s"), + event->event_id == ARDUINO_EVENT_ETH_GOT_IP6 ? "ETH" : "WIF", + addr.isLocal() ? PSTR("Local") : PSTR("Global"), addr.toString().c_str()); + if (!addr.isLocal()) { // declare network up on IPv6 + TasmotaGlobal.rules_flag.eth_connected = 1; + TasmotaGlobal.global_state.eth_down = 0; + } + WiFi.scrubDNS(); // internal calls to reconnect can zero the DNS servers, save DNS for future use + } + break; +#endif // USE_IPV6 + case ARDUINO_EVENT_ETH_DISCONNECTED: AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_ETH "Disconnected")); TasmotaGlobal.rules_flag.eth_disconnected = 1; @@ -144,19 +166,6 @@ void EthernetSetIp(void) { Settings->eth_ipv4_address[4]); // IPAddress dns2 } -#ifdef USE_IPV6 -// Returns only IPv6 global address (no loopback and no link-local) -String EthernetGetIPv6(void) -{ - return WifiFindIPv6(false, "en"); -} - -String EthernetGetIPv6LinkLocal(void) -{ - return WifiFindIPv6(true, "en"); -} -#endif // USE_IPV6 - void EthernetInit(void) { if (!Settings->flag4.network_ethernet) { return; } if (!PinUsed(GPIO_ETH_PHY_MDC) && !PinUsed(GPIO_ETH_PHY_MDIO)) { @@ -220,6 +229,40 @@ IPAddress EthernetLocalIP(void) { return ETH.localIP(); } +// Check to see if we have any routable IP address +// IPv4 has always priority +// Copy the value of the IP if pointer provided (optional) +bool EthernetGetIP(IPAddress *ip) { +#ifdef USE_IPV6 + if ((uint32_t)ETH.localIP() != 0) { + if (ip != nullptr) { *ip = ETH.localIP(); } + return true; + } + IPAddress lip; + if (EthernetGetIPv6(&lip)) { + if (ip != nullptr) { *ip = lip; } + return true; + } + *ip = IPAddress(); + return false; +#else + // IPv4 only + if (ip != nullptr) { *ip = ETH.localIP(); } + return (uint32_t)ETH.localIP() != 0; +#endif // USE_IPV6 +} +bool EthernetHasIP(void) { + return EthernetGetIP(nullptr); +} +String EthernetGetIPStr(void) { + IPAddress ip; + if (EthernetGetIP(&ip)) { + return ip.toString(); + } else { + return String(); + } +} + char* EthernetHostname(void) { return eth_hostname; } From 2fd63ff01faab81fe91d02495151db968b7fcb34 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Wed, 28 Dec 2022 14:07:30 +0100 Subject: [PATCH 059/262] Fix Modbus transmit enable GPIO Fix Modbus transmit enable GPIO enabled once during write buffer --- CHANGELOG.md | 1 + RELEASENOTES.md | 5 +++++ .../TasmotaSerial-3.6.0/src/TasmotaSerial.cpp | 9 +++------ .../TasmotaSerial-3.6.0/src/TasmotaSerial.h | 1 - .../TasmotaModbus-3.6.0/src/TasmotaModbus.cpp | 15 ++++++++++++++- .../TasmotaModbus-3.6.0/src/TasmotaModbus.h | 1 + 6 files changed, 24 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 569c21eb8..36db85b30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ All notable changes to this project will be documented in this file. ### Fixed - Shutter default motorstop set to 0 (#17403) - Shutter default tilt configuration (#17484) +- Modbus transmit enable GPIO enabled once during write buffer ### Removed diff --git a/RELEASENOTES.md b/RELEASENOTES.md index cd293173a..064b3f00f 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -111,8 +111,12 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm ### Added - Support for up to 3 single phase modbus energy monitoring device using generic Energy Modbus driver- Support for RGB displays [#17414](https://github.com/arendst/Tasmota/issues/17414) - Support for IPv6 DNS records (AAAA) and IPv6 ``Ping`` for ESP32 and ESP8266 [#17417](https://github.com/arendst/Tasmota/issues/17417) +- Support for IPv6 only networks on Ethernet (not yet Wifi) - Berry support for ``crypto.SHA256`` [#17430](https://github.com/arendst/Tasmota/issues/17430) - Berry crypto add ``EC_P256`` and ``PBKDF2_HMAC_SHA256`` algorithms required by Matter protocol [#17473](https://github.com/arendst/Tasmota/issues/17473) +- Berry crypto add ``random`` to generate series of random bytes +- Berry crypto add ``HKDF_HMAC_SHA256`` +- Berry crypto add ``SPAKE2P_Matter`` for Matter support ### Breaking Changed @@ -122,6 +126,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm - Tasmota OTA scripts now support both unzipped and gzipped file uploads [#17378](https://github.com/arendst/Tasmota/issues/17378) ### Fixed +- Modbus transmit enable GPIO enabled once during write buffer - Shutter default motorstop set to 0 [#17403](https://github.com/arendst/Tasmota/issues/17403) - Shutter default tilt configuration [#17484](https://github.com/arendst/Tasmota/issues/17484) diff --git a/lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.cpp b/lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.cpp index f334073a5..d690c62eb 100644 --- a/lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.cpp +++ b/lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.cpp @@ -46,7 +46,6 @@ static uint32_t tasmota_serial_uart_bitmap = 0; // Assigned UARTs TasmotaSerial::TasmotaSerial(int receive_pin, int transmit_pin, int hardware_fallback, int nwmode, int buffer_size) { m_valid = false; - m_tx_enable_valid = false; m_hardserial = false; m_hardswap = false; m_overflow = false; @@ -56,6 +55,7 @@ TasmotaSerial::TasmotaSerial(int receive_pin, int transmit_pin, int hardware_fal serial_buffer_size = buffer_size; m_rx_pin = receive_pin; m_tx_pin = transmit_pin; + m_tx_enable_pin = -1; m_in_pos = 0; m_out_pos = 0; #ifdef ESP8266 @@ -134,12 +134,9 @@ bool TasmotaSerial::isValidGPIOpin(int pin) { void TasmotaSerial::setTransmitEnablePin(int tx_enable_pin) { if ((tx_enable_pin > -1) && isValidGPIOpin(tx_enable_pin)) { - m_tx_enable_valid = true; m_tx_enable_pin = tx_enable_pin; pinMode(m_tx_enable_pin, OUTPUT); digitalWrite(m_tx_enable_pin, LOW); - } else { - m_tx_enable_valid = false; } } @@ -425,7 +422,7 @@ void IRAM_ATTR TasmotaSerial::_fast_write(uint8_t b) { size_t TasmotaSerial::write(uint8_t b) { if (!m_hardserial && (-1 == m_tx_pin)) { return 0; } - if (m_tx_enable_valid) { + if (m_tx_enable_pin > -1) { digitalWrite(m_tx_enable_pin, HIGH); } size_t size = 0; @@ -462,7 +459,7 @@ size_t TasmotaSerial::write(uint8_t b) { } size = 1; } - if (m_tx_enable_valid) { + if (m_tx_enable_pin > -1) { delay(1); digitalWrite(m_tx_enable_pin, LOW); } diff --git a/lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.h b/lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.h index cf93f3443..c41282004 100644 --- a/lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.h +++ b/lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.h @@ -95,7 +95,6 @@ class TasmotaSerial : public Stream { uint32_t m_out_pos; uint32_t serial_buffer_size = TM_SERIAL_BUFFER_SIZE; bool m_valid; - bool m_tx_enable_valid; bool m_nwmode; bool m_hardserial; bool m_hardswap; diff --git a/lib/lib_basic/TasmotaModbus-3.6.0/src/TasmotaModbus.cpp b/lib/lib_basic/TasmotaModbus-3.6.0/src/TasmotaModbus.cpp index 4860e6b84..baf66f8b0 100644 --- a/lib/lib_basic/TasmotaModbus-3.6.0/src/TasmotaModbus.cpp +++ b/lib/lib_basic/TasmotaModbus-3.6.0/src/TasmotaModbus.cpp @@ -29,7 +29,13 @@ enum LoggingLevels {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_D TasmotaModbus::TasmotaModbus(int receive_pin, int transmit_pin, int tx_enable_pin) : TasmotaSerial(receive_pin, transmit_pin, 2) { - setTransmitEnablePin(tx_enable_pin); +// setTransmitEnablePin(tx_enable_pin); + mb_tx_enable_pin = tx_enable_pin; + if (mb_tx_enable_pin > -1) { + pinMode(mb_tx_enable_pin, OUTPUT); + digitalWrite(mb_tx_enable_pin, LOW); + } + mb_address = 0; } @@ -150,7 +156,14 @@ uint8_t TasmotaModbus::Send(uint8_t device_address, uint8_t function_code, uint1 #endif flush(); + if (mb_tx_enable_pin > -1) { + digitalWrite(mb_tx_enable_pin, HIGH); + } write(frame, framepointer); + if (mb_tx_enable_pin > -1) { + delay(1); + digitalWrite(mb_tx_enable_pin, LOW); + } free(frame); return 0; } diff --git a/lib/lib_basic/TasmotaModbus-3.6.0/src/TasmotaModbus.h b/lib/lib_basic/TasmotaModbus-3.6.0/src/TasmotaModbus.h index ced5fb969..7997ae329 100644 --- a/lib/lib_basic/TasmotaModbus-3.6.0/src/TasmotaModbus.h +++ b/lib/lib_basic/TasmotaModbus-3.6.0/src/TasmotaModbus.h @@ -66,6 +66,7 @@ class TasmotaModbus : public TasmotaSerial { uint8_t ReceiveCount(void) { return mb_len; } private: + int mb_tx_enable_pin; uint8_t mb_address; uint8_t mb_len; }; From fa466d91ff92c70a38b90a48cfa5fc019e6ff610 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Wed, 28 Dec 2022 14:10:45 +0100 Subject: [PATCH 060/262] Tasmota core 2.0.6 (#17493) * Tasmota core 2.0.6 * PR template core 2.0.6 --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- platformio_tasmota32.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 88dc78c9d..5ba7951ba 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -7,7 +7,7 @@ - [ ] Only relevant files were touched - [ ] Only one feature/fix was added per PR and the code change compiles without warnings - [ ] The code change is tested and works with Tasmota core ESP8266 V.2.7.4.9 - - [ ] The code change is tested and works with Tasmota core ESP32 V.2.0.5 + - [ ] The code change is tested and works with Tasmota core ESP32 V.2.0.6 - [ ] I accept the [CLA](https://github.com/arendst/Tasmota/blob/development/CONTRIBUTING.md#contributor-license-agreement-cla). _NOTE: The code change must pass CI tests. **Your PR cannot be merged unless tests pass**_ diff --git a/platformio_tasmota32.ini b/platformio_tasmota32.ini index a654964ce..d4d0c7cfa 100644 --- a/platformio_tasmota32.ini +++ b/platformio_tasmota32.ini @@ -42,7 +42,7 @@ extra_scripts = pre:pio-tools/add_c_flags.py ${esp_defaults.extra_scripts} [core32] -platform = https://github.com/tasmota/platform-espressif32/releases/download/2022.12.1/platform-espressif32.zip +platform = https://github.com/tasmota/platform-espressif32/releases/download/2022.12.2/platform-espressif32.zip platform_packages = build_unflags = ${esp32_defaults.build_unflags} build_flags = ${esp32_defaults.build_flags} From 2e1f8fd7561cc7ba2188cd5744b4f8def9b9b359 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Wed, 28 Dec 2022 14:31:49 +0100 Subject: [PATCH 061/262] Update changelogs Change ESP32 Framework (Core) from v2.0.5.4 to v2.0.6 (IPv6 support) --- CHANGELOG.md | 1 + RELEASENOTES.md | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 36db85b30..cf26a7a3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ All notable changes to this project will be documented in this file. ### Breaking Changed ### Changed +- ESP32 Framework (Core) from v2.0.5.4 to v2.0.6 (IPv6 support) - Tasmota OTA scripts now support both unzipped and gzipped file uploads (#17378) - Change NTP default servers to dual-stack (IPv4/IPv6) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 064b3f00f..510405625 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -33,9 +33,9 @@ While fallback or downgrading is common practice it was never supported due to S This release will be supported from ESP8266/Arduino library Core version **2.7.4.9** due to reported security and stability issues on previous Core version. This will also support gzipped binaries. -This release will be supported from ESP32/Arduino library Core version **2.0.5.3**. +This release will be supported from ESP32/Arduino library Core version **2.0.6**. -Support of ESP8266 Core versions before 2.7.4.9 and ESP32 Core versions before 2.0.5.3 have been removed. +Support of ESP8266 Core versions before 2.7.4.9 and ESP32 Core versions before 2.0.6 have been removed. ## Support of TLS @@ -77,7 +77,7 @@ Historical binaries can be downloaded from The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmota.com/tasmota/release/tasmota.bin.gz`` ### ESP32, ESP32-C3, ESP32-S2 and ESP32-S3 based -The following binary downloads have been compiled with ESP32/Arduino library core version **2.0.5.4**. +The following binary downloads have been compiled with ESP32/Arduino library core version **2.0.6**. - **tasmota32.bin** = The Tasmota version with most drivers including additional sensors and KNX for 4M+ flash. **RECOMMENDED RELEASE BINARY** - **tasmota32xy.bin** = The Tasmota version with most drivers including additional sensors and KNX for ESP32-C3/S2/S3 and 4M+ flash. @@ -121,7 +121,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm ### Breaking Changed ### Changed -- ESP32 Framework (Core) from v2.0.5.3 to v2.0.5.4 (IPv6 support) +- ESP32 Framework (Core) from v2.0.5.3 to v2.0.6 (IPv6 support) - TuyaMcu rewrite by btsimonh [#17051](https://github.com/arendst/Tasmota/issues/17051) - Tasmota OTA scripts now support both unzipped and gzipped file uploads [#17378](https://github.com/arendst/Tasmota/issues/17378) From c1484f761c9827cb9e3904641f958eefd10d5810 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Wed, 28 Dec 2022 15:19:09 +0100 Subject: [PATCH 062/262] Fix exception 9 when modbus tx enable is used --- lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.cpp | 2 +- .../TasmotaModbus-3.6.0/src/TasmotaModbus.cpp | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.cpp b/lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.cpp index d690c62eb..20654b05f 100644 --- a/lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.cpp +++ b/lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.cpp @@ -460,7 +460,7 @@ size_t TasmotaSerial::write(uint8_t b) { size = 1; } if (m_tx_enable_pin > -1) { - delay(1); + delayMicroseconds(800); // delay(1) will exception here digitalWrite(m_tx_enable_pin, LOW); } return size; diff --git a/lib/lib_basic/TasmotaModbus-3.6.0/src/TasmotaModbus.cpp b/lib/lib_basic/TasmotaModbus-3.6.0/src/TasmotaModbus.cpp index baf66f8b0..0fb316bd3 100644 --- a/lib/lib_basic/TasmotaModbus-3.6.0/src/TasmotaModbus.cpp +++ b/lib/lib_basic/TasmotaModbus-3.6.0/src/TasmotaModbus.cpp @@ -31,11 +31,6 @@ TasmotaModbus::TasmotaModbus(int receive_pin, int transmit_pin, int tx_enable_pi { // setTransmitEnablePin(tx_enable_pin); mb_tx_enable_pin = tx_enable_pin; - if (mb_tx_enable_pin > -1) { - pinMode(mb_tx_enable_pin, OUTPUT); - digitalWrite(mb_tx_enable_pin, LOW); - } - mb_address = 0; } @@ -64,6 +59,10 @@ int TasmotaModbus::Begin(long speed, uint32_t config) if (begin(speed, config)) { result = 1; if (hardwareSerial()) { result = 2; } + if (mb_tx_enable_pin > -1) { + pinMode(mb_tx_enable_pin, OUTPUT); + digitalWrite(mb_tx_enable_pin, LOW); + } } return result; } @@ -161,7 +160,7 @@ uint8_t TasmotaModbus::Send(uint8_t device_address, uint8_t function_code, uint1 } write(frame, framepointer); if (mb_tx_enable_pin > -1) { - delay(1); + delayMicroseconds(800); // delay(1) will exception here digitalWrite(mb_tx_enable_pin, LOW); } free(frame); From 35b4bfcb3f7555bf4d1a7dc6ac2c5f4d14693663 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Wed, 28 Dec 2022 17:06:54 +0100 Subject: [PATCH 063/262] Fix initial user added modbus field:value pair --- .../tasmota_xnrg_energy/xnrg_29_modbus.ino | 63 ++++++++++--------- 1 file changed, 34 insertions(+), 29 deletions(-) diff --git a/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino b/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino index 4dac9ce76..94171fe13 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino @@ -238,9 +238,9 @@ struct NRGMBSPARAM { uint8_t function; uint8_t total_regs; uint8_t user_adds; - uint8_t phase; uint8_t state; uint8_t retry; + int8_t phase; bool mutex; } NrgMbsParam; @@ -419,45 +419,50 @@ void EnergyModbusLoop(void) { NrgMbsUser[NrgMbsParam.state - NRG_MBS_MAX_REGS].data[NrgMbsParam.phase] = value; } } - - uint32_t phase = 0; - do { - NrgMbsParam.phase++; - if (NrgMbsParam.phase >= Energy.phase_count) { - NrgMbsParam.phase = 0; - NrgMbsParam.state++; - if (NrgMbsParam.state >= NrgMbsParam.total_regs) { - NrgMbsParam.state = 0; - NrgMbsParam.phase = 0; - EnergyUpdateTotal(); // update every cycle after all registers have been read - break; - } - } - delay(0); - if (NrgMbsParam.devices == 1) { - phase = NrgMbsParam.phase; - } - } while (NrgMbsReg[NrgMbsParam.state].address[phase] == nrg_mbs_reg_not_used); } } // end data ready - uint32_t address = 0; - uint32_t phase = NrgMbsParam.phase; - if (NrgMbsParam.devices > 1) { - address = NrgMbsParam.phase; - phase = 0; - } if (0 == NrgMbsParam.retry || data_ready) { NrgMbsParam.retry = 1; + + uint32_t address = 0; + uint32_t phase = 0; + do { + NrgMbsParam.phase++; + if (NrgMbsParam.phase >= Energy.phase_count) { + NrgMbsParam.phase = 0; + NrgMbsParam.state++; + if (NrgMbsParam.state >= NrgMbsParam.total_regs) { + NrgMbsParam.state = 0; + NrgMbsParam.phase = 0; + EnergyUpdateTotal(); // update every cycle after all registers have been read + } + } + delay(0); + if (NrgMbsParam.devices == 1) { + phase = NrgMbsParam.phase; + } else { + address = NrgMbsParam.phase; + } + } while (NrgMbsReg[NrgMbsParam.state].address[phase] == nrg_mbs_reg_not_used); + // Even data type is single register, Odd data type is double registers register_count = 2 - (NrgMbsReg[NrgMbsParam.state].datatype & 1); + +#ifdef ENERGY_MODBUS_DEBUG + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("NRG: Modbus send Device %d, Function %d, Register %04X (%d/%d), Size %d"), + NrgMbsParam.device_address[address], NrgMbsParam.function, + NrgMbsReg[NrgMbsParam.state].address[phase], NrgMbsParam.state, phase, + register_count); +#endif + EnergyModbus->Send(NrgMbsParam.device_address[address], NrgMbsParam.function, NrgMbsReg[NrgMbsParam.state].address[phase], register_count); } else { NrgMbsParam.retry--; #ifdef ENERGY_MODBUS_DEBUG if (NrgMbsParam.devices > 1) { - AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Modbus retry device %d state %d"), NrgMbsParam.device_address[address], NrgMbsParam.state); + AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Modbus retry device %d state %d"), NrgMbsParam.device_address[NrgMbsParam.phase], NrgMbsParam.state); } else { AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Modbus retry state %d phase %d"), NrgMbsParam.state, NrgMbsParam.phase); } @@ -556,7 +561,7 @@ bool EnergyModbusReadUserRegisters(JsonParserObject user_add_value, uint32_t add #ifdef ENERGY_MODBUS_DEBUG AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Idx %d (%s), R [%04X,%04X,%04X], T %d, F %d, J '%s', G '%s', U '%s', D %d"), - add_index, NrgMbsUser[add_index].json_name, + reg_index, NrgMbsUser[add_index].json_name, NrgMbsReg[reg_index].address[0], NrgMbsReg[reg_index].address[1], NrgMbsReg[reg_index].address[2], @@ -797,7 +802,7 @@ bool EnergyModbusReadRegisters(void) { #endif // NrgMbsParam.state = 0; // Set by calloc() -// NrgMbsParam.phase = 0; + NrgMbsParam.phase = -1; return true; #endif // USE_RULES From 31a53148c6c8259beb8110188c3d95a6c90350bb Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Wed, 28 Dec 2022 17:45:13 +0100 Subject: [PATCH 064/262] Add NRG modbus features - User JSON name needs to be different from embedded register names - If no user GUI name is given it will only show in JSON --- .../tasmota_xnrg_energy/xnrg_29_modbus.ino | 33 +++++++++---------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino b/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino index 94171fe13..75bfa8227 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino @@ -103,9 +103,9 @@ * 3 - multiply by 1000 * 4 - multiply by 10000 * M - [LEGACY - replaced by "F"] Divide register by 1 to 10000 - optional. default = 0 (no action) - * J - JSON register name (preferrably without spaces like "PhaseAngle") - * G - GUI register name - * U - GUI unit name + * J - JSON register name (preferrably without spaces like "PhaseAngle") - mandatory. It needs to be different from the Tasmota default embedded register names + * G - GUI register name - optional. If not defined the register will not be shown in the GUI + * U - GUI unit name - optional. default is none * D - Number of decimals for floating point presentation (0 to 20) or a code correspondig to Tasmota resolution command settings: * 21 - VoltRes (V) * 22 - AmpRes (A) @@ -539,20 +539,17 @@ bool EnergyModbusReadUserRegisters(JsonParserObject user_add_value, uint32_t add val = user_add_value[PSTR("J")]; // JSON value name if (val) { NrgMbsUser[add_index].json_name = SetStr(val.getStr()); + char json_name[32]; + if (GetCommandCode(json_name, sizeof(json_name), NrgMbsUser[add_index].json_name, kEnergyModbusValues) > -1) { + return false; // Duplicate JSON name + } } else { - return false; + return false; // No mandatory JSON name } val = user_add_value[PSTR("G")]; // GUI value name - if (val) { - NrgMbsUser[add_index].gui_name = SetStr(val.getStr()); - } else { - return false; - } - NrgMbsUser[add_index].gui_unit = EmptyStr; + NrgMbsUser[add_index].gui_name = (val) ? SetStr(val.getStr()) : EmptyStr; val = user_add_value[PSTR("U")]; // GUI value Unit - if (val) { - NrgMbsUser[add_index].gui_unit = SetStr(val.getStr()); - } + NrgMbsUser[add_index].gui_unit = (val) ? SetStr(val.getStr()) : EmptyStr; NrgMbsUser[add_index].resolution = ENERGY_MODBUS_DECIMALS; val = user_add_value[PSTR("D")]; // Decimal resolution if (val) { @@ -916,10 +913,12 @@ void EnergyModbusShow(bool json) { ResponseAppend_P(PSTR(",\"%s\":%s"), NrgMbsUser[i].json_name, EnergyFormat(value_chr, values, resolution, single)); #ifdef USE_WEBSERVER } else { - WSContentSend_PD(PSTR("{s}%s{m}%s %s{e}"), - NrgMbsUser[i].gui_name, - WebEnergyFormat(value_chr, values, resolution, single), - NrgMbsUser[i].gui_unit); + if (strlen(NrgMbsUser[i].gui_name)) { // Skip empty GUI names + WSContentSend_PD(PSTR("{s}%s{m}%s %s{e}"), + NrgMbsUser[i].gui_name, + WebEnergyFormat(value_chr, values, resolution, single), + NrgMbsUser[i].gui_unit); + } #endif // USE_WEBSERVER } } From ff3d90c36d13cc412d388e26dfa1b4aa0ebdb19b Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Thu, 29 Dec 2022 14:02:48 +0100 Subject: [PATCH 065/262] Fix teleperiod PUSH_IGNORE_INV Fix teleperiod PUSH_IGNORE_INV (#17028) --- tasmota/tasmota_support/support_switch.ino | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tasmota/tasmota_support/support_switch.ino b/tasmota/tasmota_support/support_switch.ino index 6bf59bbcb..5b66f301b 100644 --- a/tasmota/tasmota_support/support_switch.ino +++ b/tasmota/tasmota_support/support_switch.ino @@ -84,7 +84,8 @@ bool SwitchState(uint32_t index) { (PUSHBUTTONHOLD_INV == switchmode) || (FOLLOWMULTI_INV == switchmode) || (PUSHHOLDMULTI_INV == switchmode) || - (PUSHON_INV == switchmode) + (PUSHON_INV == switchmode) || + (PUSH_IGNORE_INV == switchmode) ) ^ Switch.last_state[index]; } From 4ee6aee35e88a5e2aa4225442091036bad82eb62 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Thu, 29 Dec 2022 14:46:34 +0100 Subject: [PATCH 066/262] Fix ESP8266 relay power on spikes Fix ESP8266 set GPIO's to input on power on fixing relay spikes (#17531) --- CHANGELOG.md | 1 + RELEASENOTES.md | 1 + tasmota/tasmota_support/support_cores.ino | 63 ----------------------- tasmota/tasmota_support/support_esp.ino | 48 +++++++++++++++++ 4 files changed, 50 insertions(+), 63 deletions(-) delete mode 100644 tasmota/tasmota_support/support_cores.ino diff --git a/CHANGELOG.md b/CHANGELOG.md index cf26a7a3a..755e1e9b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ All notable changes to this project will be documented in this file. - Shutter default motorstop set to 0 (#17403) - Shutter default tilt configuration (#17484) - Modbus transmit enable GPIO enabled once during write buffer +- ESP8266 set GPIO's to input on power on fixing relay spikes (#17531) ### Removed diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 510405625..341ef87c1 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -127,6 +127,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm ### Fixed - Modbus transmit enable GPIO enabled once during write buffer +- ESP8266 set GPIO's to input on power on fixing relay spikes [#17531](https://github.com/arendst/Tasmota/issues/17531) - Shutter default motorstop set to 0 [#17403](https://github.com/arendst/Tasmota/issues/17403) - Shutter default tilt configuration [#17484](https://github.com/arendst/Tasmota/issues/17484) diff --git a/tasmota/tasmota_support/support_cores.ino b/tasmota/tasmota_support/support_cores.ino deleted file mode 100644 index 547b776dc..000000000 --- a/tasmota/tasmota_support/support_cores.ino +++ /dev/null @@ -1,63 +0,0 @@ -/* - support_cores.ino - Arduino core support for Tasmota - - Copyright (C) 2021 Theo Arends - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -/*********************************************************************************************\ - * Core overrides -\*********************************************************************************************/ - -// Add below line to tasmota_globals.h -// extern "C" void resetPins(); -void resetPins() -{ -/* - for (int i = 0; i <= 5; ++i) { - pinMode(i, INPUT); - } - // pins 6-11 are used for the SPI flash interface - for (int i = 12; i <= 16; ++i) { - pinMode(i, INPUT); - } -*/ -} - -/*********************************************************************************************\ - * Hardware related -\*********************************************************************************************/ - -#ifdef ESP8266 - -void HwWdtDisable(void) { - *((volatile uint32_t*) 0x60000900) &= ~(1); // Hardware WDT OFF -} - -void HwWdtEnable(void) { - *((volatile uint32_t*) 0x60000900) |= 1; // Hardware WDT ON -} - -void WdtDisable(void) { - ESP.wdtDisable(); - HwWdtDisable(); -} - -void WdtEnable(void) { - HwWdtEnable(); - ESP.wdtEnable(0); -} - -#endif // ESP8266 diff --git a/tasmota/tasmota_support/support_esp.ino b/tasmota/tasmota_support/support_esp.ino index 935733baf..b272e852b 100644 --- a/tasmota/tasmota_support/support_esp.ino +++ b/tasmota/tasmota_support/support_esp.ino @@ -33,6 +33,54 @@ extern "C" { extern struct rst_info resetInfo; } +/*********************************************************************************************\ + * Core overrides executed directly by core +\*********************************************************************************************/ + +// Add below line to tasmota_globals.h +// extern "C" void resetPins(); +// This function is executed by core init() (as initPins()) in core_esp8266_wiring.cpp +// 20221229 - Re-enabled with additional check to execute on power on only fixing short relay power on/off +// 20?????? - Disabled for unknown reason +void resetPins() { + if ((resetInfo.reason == REASON_DEFAULT_RST) || (resetInfo.reason == REASON_EXT_SYS_RST)) { + // Only perform at power on + for (int i = 0; i <= 5; ++i) { + pinMode(i, INPUT); + } + // pins 6-11 are used for the SPI flash interface + for (int i = 12; i <= 16; ++i) { + pinMode(i, INPUT); + } + } +} + +/*********************************************************************************************\ + * Hardware related +\*********************************************************************************************/ + +void HwWdtDisable(void) { + *((volatile uint32_t*) 0x60000900) &= ~(1); // Hardware WDT OFF +} + +void HwWdtEnable(void) { + *((volatile uint32_t*) 0x60000900) |= 1; // Hardware WDT ON +} + +void WdtDisable(void) { + ESP.wdtDisable(); + HwWdtDisable(); +} + +void WdtEnable(void) { + HwWdtEnable(); + ESP.wdtEnable(0); +} + +/*********************************************************************************************\ + * ESP8266 specifics +\*********************************************************************************************/ + uint32_t ESP_ResetInfoReason(void) { return resetInfo.reason; } From d9be488885cfee351be15c0cf7fea7e429759629 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Thu, 29 Dec 2022 16:10:41 +0100 Subject: [PATCH 067/262] Update comments --- tasmota/tasmota_support/support_esp.ino | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tasmota/tasmota_support/support_esp.ino b/tasmota/tasmota_support/support_esp.ino index b272e852b..699b13208 100644 --- a/tasmota/tasmota_support/support_esp.ino +++ b/tasmota/tasmota_support/support_esp.ino @@ -34,21 +34,23 @@ extern struct rst_info resetInfo; } /*********************************************************************************************\ - * Core overrides executed directly by core + * Core overrides executed by core \*********************************************************************************************/ // Add below line to tasmota_globals.h // extern "C" void resetPins(); -// This function is executed by core init() (as initPins()) in core_esp8266_wiring.cpp -// 20221229 - Re-enabled with additional check to execute on power on only fixing short relay power on/off -// 20?????? - Disabled for unknown reason +// +// This function overrules __resetPins() which is executed by core init() as initPins() in core_esp8266_wiring.cpp +// +// 20221229 - (v12.3.1.2) Enabled with additional check to execute on power on only to fix relay clicks on power on +// 20200321 - (v8.2.0.1) Disable core functionality to fix relay clicks on restart after OTA - make function return without setting pinMode void resetPins() { if ((resetInfo.reason == REASON_DEFAULT_RST) || (resetInfo.reason == REASON_EXT_SYS_RST)) { // Only perform at power on for (int i = 0; i <= 5; ++i) { pinMode(i, INPUT); } - // pins 6-11 are used for the SPI flash interface + // pins 6-11 are used for the SPI flash interface ESP8266 for (int i = 12; i <= 16; ++i) { pinMode(i, INPUT); } From 99d33e3023f17437c9e9b7b83ca1b8a1221b3be2 Mon Sep 17 00:00:00 2001 From: Barbudor Date: Thu, 29 Dec 2022 21:55:28 +0100 Subject: [PATCH 068/262] PCF8574 Overridable address ranges (#17539) * pcf8574 overridable address ranges * fix comment * better test on USE_MCP230xx * missing change --- I2CDEVICES.md | 4 +- tasmota/my_user_config.h | 6 ++- .../tasmota_xdrv_driver/xdrv_28_pcf8574.ino | 47 +++++++++++++++---- 3 files changed, 45 insertions(+), 12 deletions(-) diff --git a/I2CDEVICES.md b/I2CDEVICES.md index 3ef236eeb..69551ee2e 100644 --- a/I2CDEVICES.md +++ b/I2CDEVICES.md @@ -9,8 +9,8 @@ The following table lists the supported I2C devices Index | Define | Driver | Device | Address(es) | Description ------|---------------------|----------|----------|-------------|----------------------------------------------- 1 | USE_PCA9685 | xdrv_15 | PCA9685 | 0x40 - 0x47 | 16-channel 12-bit pwm driver - 2 | USE_PCF8574 | xdrv_28 | PCF8574 | 0x20 - 0x26 | 8-bit I/O expander - 2 | USE_PCF8574 | xdrv_28 | PCF8574A | 0x39 - 0x3F | 8-bit I/O expander + 2 | USE_PCF8574 | xdrv_28 | PCF8574 | 0x20 - 0x26 | 8-bit I/O expander (address range overridable) + 2 | USE_PCF8574 | xdrv_28 | PCF8574A | 0x39 - 0x3F | 8-bit I/O expander (address range overridable) 3 | USE_DISPLAY_LCD | xdsp_01 | | 0x27, 0x3F | LCD display 4 | USE_DISPLAY_SSD1306 | xdsp_02 | SSD1306 | 0x3C - 0x3D | Oled display 5 | USE_DISPLAY_MATRIX | xdsp_03 | HT16K33 | 0x70 - 0x77 | 8x8 led matrix diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index 9ecf5ce2e..35296863d 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -251,7 +251,7 @@ #define NTP_SERVER1 "2.pool.ntp.org" // [NtpServer1] Select first NTP server by name or IP address (135.125.104.101, 2001:418:3ff::53) #define NTP_SERVER2 "2.europe.pool.ntp.org" // [NtpServer2] Select second NTP server by name or IP address (192.36.143.134, 2a00:2381:19c6::100) #define NTP_SERVER3 "2.nl.pool.ntp.org" // [NtpServer3] Select third NTP server by name or IP address (46.249.42.13, 2603:c022:c003:c900::4) - // To manually set: + // To manually set: // BackLog NtpServer1 2.pool.ntp.org; NtpServer2 2.europe.pool.ntp.org; NtpServer3 2.nl.pool.ntp.org // -- Time - Start Daylight Saving Time and timezone offset from UTC in minutes @@ -657,6 +657,10 @@ // #define USE_PCF8574_SENSOR // enable PCF8574 inputs and outputs in SENSOR message // #define USE_PCF8574_DISPLAYINPUT // enable PCF8574 inputs display in Web page // #define USE_PCF8574_MQTTINPUT // enable MQTT message & rule process on input change detection : stat/%topic%/PCF8574_INP = {"Time":"2021-03-07T16:19:23+01:00","PCF8574-1_INP":{"D1":1}} +// #define PCF8574_ADDR1 0x20 // First address to search for PCF8574 +// #define PCF8574_ADDR1_COUNT 7 // Number of addresses to search for PCF8574 - Default to 0x20 to 0x26 +// #define PCF8574_ADDR2 0x39 // First address to search for PCF8574A +// #define PCF8574_ADDR2_COUNT 6 // Number of addresses to search for PCF8574A - Default to 0x39 to 0x3E // #define USE_HIH6 // [I2cDriver36] Enable Honeywell HIH Humidity and Temperature sensor (I2C address 0x27) (+0k6) // #define USE_DHT12 // [I2cDriver41] Enable DHT12 humidity and temperature sensor (I2C address 0x5C) (+0k7 code) // #define USE_DS1624 // [I2cDriver42] Enable DS1624, DS1621 temperature sensor (I2C addresses 0x48 - 0x4F) (+1k2 code) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_28_pcf8574.ino b/tasmota/tasmota_xdrv_driver/xdrv_28_pcf8574.ino index 907329992..891e07f44 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_28_pcf8574.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_28_pcf8574.ino @@ -29,8 +29,37 @@ #define XDRV_28 28 #define XI2C_02 2 // See I2CDEVICES.md -#define PCF8574_ADDR1 0x20 // PCF8574 -#define PCF8574_ADDR2 0x38 // PCF8574A +// Start address and count can be overriden in user_config_override.h to allow better +// sharing of the I2C address space. Still the covered range must remains valid. +// A count of 0 can be used totaly disable any of the 2 ranges. +// By default, the following addresses are explicitly excluded (as per the docs) : +// - 0x27 and 0x37 are reserved for USE_DISPLAY_LCD in xdsp_01_lcd.ino +// - 0X38 is reserved for other sensors +// If the respective drivers are not used, overrides allows to recover those addresses +// If defined, USE_MCP230xx_ADDR is also always excluded + +// PCF8574 address range from 0x20 to 0x26 +#ifndef PCF8574_ADDR1 +#define PCF8574_ADDR1 0x20 // PCF8574 +#endif +#ifndef PCF8574_ADDR1_COUNT +#define PCF8574_ADDR1_COUNT 7 +#endif +// PCF8574A address range from 0x39 to 0x3E +#ifndef PCF8574_ADDR2 +#define PCF8574_ADDR2 0x39 // PCF8574A +#endif +#ifndef PCF8574_ADDR2_COUNT +#define PCF8574_ADDR2_COUNT 6 +#endif + +// Consitency tests - Checked across the complete range for the PCF8574/PCF8574A to allow override +#if (PCF8574_ADDR1 < 0x20) || ((PCF8574_ADDR1 + PCF8574_ADDR1_COUNT - 1) > 0x27) +#error PCF8574_ADDR1 and/or PCF8574_ADDR1_COUNT badly overriden. Fix your user_config_override +#endif +#if (PCF8574_ADDR2 < 0x38) || ((PCF8574_ADDR2 + PCF8574_ADDR2_COUNT - 1) > 0x3F) +#error PCF8574_ADDR2 and/or PCF8574_ADDR2_COUNT badly overriden. Fix your user_config_override. +#endif struct PCF8574 { int error; @@ -82,15 +111,15 @@ void Pcf8574SwitchRelay(void) void Pcf8574Init(void) { - uint8_t pcf8574_address = PCF8574_ADDR1; - while ((Pcf8574.max_devices < MAX_PCF8574) && (pcf8574_address < PCF8574_ADDR2 +8)) { + uint8_t pcf8574_address = (PCF8574_ADDR1_COUNT > 0) ? PCF8574_ADDR1 : PCF8574_ADDR2; + while ((Pcf8574.max_devices < MAX_PCF8574) && (pcf8574_address < PCF8574_ADDR2 +PCF8574_ADDR2_COUNT)) { -#ifdef USE_MCP230xx_ADDR +#if defined(USE_MCP230xx) && defined(USE_MCP230xx_ADDR) if (USE_MCP230xx_ADDR == pcf8574_address) { AddLog(LOG_LEVEL_INFO, PSTR("PCF: Address 0x%02x reserved for MCP320xx skipped"), pcf8574_address); pcf8574_address++; - if ((PCF8574_ADDR1 +7) == pcf8574_address) { // Support I2C addresses 0x20 to 0x26 and 0x39 to 0x3F - pcf8574_address = PCF8574_ADDR2 +1; + if ((PCF8574_ADDR1 +PCF8574_ADDR1_COUNT) == pcf8574_address) { // See comment on allowed addresses and overrides + pcf8574_address = PCF8574_ADDR2; } } #endif @@ -111,8 +140,8 @@ void Pcf8574Init(void) } pcf8574_address++; - if ((PCF8574_ADDR1 +7) == pcf8574_address) { // Support I2C addresses 0x20 to 0x26 and 0x39 to 0x3F - pcf8574_address = PCF8574_ADDR2 +1; + if ((PCF8574_ADDR1 +PCF8574_ADDR1_COUNT) == pcf8574_address) { // Support I2C addresses 0x20 to 0x26 and 0x39 to 0x3F + pcf8574_address = PCF8574_ADDR2; } } if (Pcf8574.type) { From 22803e3e3d6ad16e3d050cd32f693eb0d1209c3e Mon Sep 17 00:00:00 2001 From: gemu Date: Fri, 30 Dec 2022 08:41:54 +0100 Subject: [PATCH 069/262] Sml update (#17541) * fix sysvarsbug, update sml * major rewrite --- .../tasmota_xdrv_driver/xdrv_10_scripter.ino | 76 +- tasmota/tasmota_xsns_sensor/xsns_53_sml.ino | 2844 ++++++++--------- 2 files changed, 1321 insertions(+), 1599 deletions(-) mode change 100644 => 100755 tasmota/tasmota_xsns_sensor/xsns_53_sml.ino diff --git a/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino b/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino index 075a6c7b9..3be9f834c 100755 --- a/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino @@ -52,6 +52,14 @@ keywords if then else endif, or, and are better readable for beginners (others m #endif #define MAXNVARS MAXVARS-MAXSVARS +#ifdef USE_SML_M +#ifndef NO_USE_SML_SCRIPT_CMD +// allows several sml cmds from scripts, as well as access to sml registers +#undef USE_SML_SCRIPT_CMD +#define USE_SML_SCRIPT_CMD +#endif +#endif // USE_SML_M + #ifndef MAXFILT #define MAXFILT 5 #endif @@ -2645,6 +2653,7 @@ chknext: } #endif //USE_SCRIPT_TASK #endif //ESP32 + #ifdef USE_ANGLE_FUNC if (!strncmp(lp, "cos(", 4)) { lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, gv); @@ -4309,8 +4318,18 @@ extern char *SML_GetSVal(uint32_t index); SCRIPT_SKIP_SPACES lp++; len = 0; - if (sp) strlcpy(sp, SML_GetSVal(fvar), glob_script_mem.max_ssize); - goto strexit;; + if (fvar > 0) { + if (sp) strlcpy(sp, SML_GetSVal(fvar), glob_script_mem.max_ssize); + } else { + char sbuff[SCRIPT_MAXSSIZE]; + fvar = fabs(fvar); + if (fvar < 1) { + fvar = 1; + } + dtostrfd(SML_GetVal(fvar), glob_script_mem.script_dprec, sbuff); + if (sp) strlcpy(sp, sbuff, glob_script_mem.max_ssize); + } + goto strexit; } if (!strncmp(lp, "sml(", 4)) { float fvar1; @@ -6064,7 +6083,8 @@ int16_t retval; #define SCRIPT_LOOP_NEST 3 int16_t Run_script_sub(const char *type, int8_t tlen, struct GVARS *gv) { - uint8_t vtype = 0, sindex, xflg, globvindex, fromscriptcmd = 0; + uint8_t vtype = 0, sindex, xflg, fromscriptcmd = 0; + int16_t globvindex; // 22 bytes per nested loop uint8_t floop[SCRIPT_LOOP_NEST] = {0, 0, 0}; int8_t loopdepth = -1; @@ -6682,6 +6702,7 @@ getnext: dfvar = &sysvar; if (ind.bits.settable) { sysv_type = ind.index; + globvindex = -1; } else { sysv_type = 0; } @@ -6759,33 +6780,36 @@ getnext: break; } // var was changed - SetChanged(globvindex); + if (globvindex >= 0) SetChanged(globvindex); #ifdef USE_SCRIPT_GLOBVARS - if (glob_script_mem.type[globvindex].bits.global) { - script_udp_sendvar(varname, dfvar, 0); + if (globvindex >= 0 ) { + if (glob_script_mem.type[globvindex].bits.global) { + script_udp_sendvar(varname, dfvar, 0); + } } #endif //USE_SCRIPT_GLOBVARS - if (glob_script_mem.type[globvindex].bits.is_filter) { - if (globaindex >= 0) { - Set_MFVal(glob_script_mem.type[globvindex].index, globaindex, *dfvar); - } else { - if (glob_script_mem.arres == 2) { - // fetch var preset - lp++; - while (*lp && *lp != SCRIPT_EOL) { - if (*lp == '}') { - lp++; - break; + if (globvindex >= 0) { + if (glob_script_mem.type[globvindex].bits.is_filter) { + if (globaindex >= 0) { + Set_MFVal(glob_script_mem.type[globvindex].index, globaindex, *dfvar); + } else { + if (glob_script_mem.arres == 2) { + // fetch var preset + lp++; + while (*lp && *lp != SCRIPT_EOL) { + if (*lp == '}') { + lp++; + break; + } + lp = GetNumericArgument(lp, OPER_EQU, &fvar, gv); + Set_MFilter(glob_script_mem.type[globvindex].index, fvar); } - lp = GetNumericArgument(lp, OPER_EQU, &fvar, gv); - Set_MFilter(glob_script_mem.type[globvindex].index, fvar); - } - } else { + } else { Set_MFilter(glob_script_mem.type[globvindex].index, *dfvar); + } } } } - if (sysv_type) { switch (sysv_type) { case SCRIPT_LOGLEVEL: @@ -6845,10 +6869,12 @@ getnext: #endif if (!glob_script_mem.var_not_found) { // var was changed - SetChanged(globvindex); + if (globvindex >= 0) SetChanged(globvindex); #ifdef USE_SCRIPT_GLOBVARS - if (glob_script_mem.type[globvindex].bits.global) { - script_udp_sendvar(varname, 0, str); + if (globvindex >= 0) { + if (glob_script_mem.type[globvindex].bits.global) { + script_udp_sendvar(varname, 0, str); + } } #endif //USE_SCRIPT_GLOBVARS if (saindex >= 0) { diff --git a/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino b/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino old mode 100644 new mode 100755 index 707c9e6b0..fdcea8b38 --- a/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino @@ -25,22 +25,13 @@ #define XSNS_53 53 -// default baudrate of D0 output -#define SML_BAUDRATE 9600 +// this driver depends on use USE_SCRIPT !!! -// send this every N seconds (for meters that only send data on demand) -// not longer supported, use scripting instead -//#define SML_SEND_SEQ // debug counter input to led for counter1 and 2 //#define DEBUG_CNT_LED1 2 //#define DEBUG_CNT_LED1 2 -// use analog optical counter sensor with AD Converter ADS1115 (not yet functional) -//#define ANALOG_OPTO_SENSOR -// fototransistor with pullup at A0, A1 of ADS1115 A3 and +3.3V -// level and amplification are automatically set - #include @@ -49,594 +40,91 @@ #define SPECIAL_SS #endif -#ifndef TMSBSIZ -#define TMSBSIZ 256 -#endif - -//#define MODBUS_DEBUG - -// addresses a bug in meter DWS74 -//#define DWS74_BUG - -// JSON Strings do not translate -// max 23 char -#define DJ_TPWRIN "Total_in" -#define DJ_TPWRIN0 "Total_in_0" -#define DJ_TPWRIN1 "Total_in_1" -#define DJ_TPWROUT "Total_out" -#define DJ_TPWRCURR "Power_curr" -#define DJ_TPWRCURR1 "Power_p1" -#define DJ_TPWRCURR2 "Power_p2" -#define DJ_TPWRCURR3 "Power_p3" -#define DJ_CURR1 "Curr_p1" -#define DJ_CURR2 "Curr_p2" -#define DJ_CURR3 "Curr_p3" -#define DJ_VOLT1 "Volt_p1" -#define DJ_VOLT2 "Volt_p2" -#define DJ_VOLT3 "Volt_p3" -#define DJ_METERNR "Meter_number" -#define DJ_METERSID "Meter_id" -#define DJ_CSUM "Curr_summ" -#define DJ_VAVG "Volt_avg" -#define DJ_COUNTER "Count" - -typedef union { - uint8_t data; - struct { - uint8_t trxenpol : 1; // string or number - uint8_t trxen : 1; - uint8_t trxenpin : 6; - }; -} TRX_EN_TYPE; - -struct METER_DESC { - int8_t srcpin; - uint8_t type; - uint16_t flag; - int32_t params; - char prefix[8]; - int8_t trxpin; - uint8_t tsecs; - char *txmem; - uint8_t index; - uint8_t max_index; - char *script_str; - uint8_t sopt; - TRX_EN_TYPE trx_en; -#ifdef USE_SML_SPECOPT - uint32_t so_obis1; - uint32_t so_obis2; - uint8_t so_fcode1; - uint8_t so_bpos1; - uint8_t so_fcode2; - uint8_t so_bpos2; -#endif -}; - // max number of meters , may be adjusted #ifndef MAX_METERS #define MAX_METERS 5 #endif -#ifdef USE_SCRIPT -struct METER_DESC script_meter_desc[MAX_METERS]; -uint8_t *script_meter; + +/* additional defines + USE_ESP32_SW_SERIAL + default off, uses a special combo driver that allows more then 3 serial ports on ESP32. + define rec pins as negativ to use software serial +*/ + +// if you have to save more RAM you may disable these options by defines in user_config_override + +#ifndef NO_SML_REPLACE_VARS +// allows to replace values in decoder section with script string variables +#undef SML_REPLACE_VARS +#define SML_REPLACE_VARS #endif - - -// this descriptor method is no longer supported -// but still functional for simple meters -// use scripting method instead -// meter list , enter new meters here -//===================================================== -#define EHZ161_0 1 -#define EHZ161_1 2 -#define EHZ363 3 -#define EHZH 4 -#define EDL300 5 -#define Q3B 6 -#define COMBO3 7 -#define COMBO2 8 -#define COMBO3a 9 -#define Q3B_V1 10 -#define EHZ363_2 11 -#define COMBO3b 12 -#define WGS_COMBO 13 -#define EBZD_G 14 -#define SML_NO_OP 15 -#define Q3C 16 - -// select this meter -// SML_NO_OP ignores hardcoded interface -#define METER SML_NO_OP -//#define METER EHZ161_1 - -#if METER==SML_NO_OP -#undef METERS_USED -#define METERS_USED 0 -struct METER_DESC const meter_desc[]={}; -const uint8_t meter[]=""; +#ifndef NO_USE_SML_SPECOPT +// allows to define special option 1 for meters that use a direction bit +#undef USE_SML_SPECOPT +#define USE_SML_SPECOPT #endif - -#if METER==EHZ161_0 -#undef METERS_USED -#define METERS_USED 1 -struct METER_DESC const meter_desc[METERS_USED]={ - [0]={3,'o',0,SML_BAUDRATE,"OBIS",-1,1,0}}; -const uint8_t meter[]= -"1,1-0:1.8.0*255(@1," D_TPWRIN ",kWh," DJ_TPWRIN ",4|" -"1,1-0:2.8.0*255(@1," D_TPWROUT ",kWh," DJ_TPWROUT ",4|" -"1,1-0:21.7.0*255(@1," D_TPWRCURR1 ",W," DJ_TPWRCURR1 ",0|" -"1,1-0:41.7.0*255(@1," D_TPWRCURR2 ",W," DJ_TPWRCURR2 ",0|" -"1,1-0:61.7.0*255(@1," D_TPWRCURR3 ",W," DJ_TPWRCURR3 ",0|" -"1,=m 3+4+5 @1," D_TPWRCURR ",W," DJ_TPWRCURR ",0|" -"1,1-0:0.0.0*255(@#)," D_METERNR ",," DJ_METERNR ",0"; - +#ifndef NO_USE_SML_SCRIPT_CMD +// allows several sml cmds from scripts, as well as access to sml registers +#undef USE_SML_SCRIPT_CMD +#define USE_SML_SCRIPT_CMD #endif -//===================================================== - -#if METER==EHZ161_1 -#undef METERS_USED -#define METERS_USED 1 -struct METER_DESC const meter_desc[METERS_USED]={ - [0]={3,'o',0,SML_BAUDRATE,"OBIS",-1,1,0}}; -const uint8_t meter[]= -"1,1-0:1.8.1*255(@1," D_TPWRIN ",kWh," DJ_TPWRIN ",4|" -"1,1-0:2.8.1*255(@1," D_TPWROUT ",kWh," DJ_TPWROUT ",4|" -"1,=d 2 10 @1," D_TPWRCURR ",W," DJ_TPWRCURR ",0|" -"1,1-0:0.0.0*255(@#)," D_METERNR ",," DJ_METERNR ",0"; +#ifndef NO_USE_SML_DECRYPT +// allows 256 bit AES decryption +#define USE_SML_DECRYPT #endif -//===================================================== - -#if METER==EHZ363 -#undef METERS_USED -#define METERS_USED 1 -struct METER_DESC const meter_desc[METERS_USED]={ - [0]={3,'s',0,SML_BAUDRATE,"SML",-1,1,0}}; -// 2 Richtungszähler EHZ SML 8 bit 9600 baud, binär -const uint8_t meter[]= -//0x77,0x07,0x01,0x00,0x01,0x08,0x00,0xff -"1,77070100010800ff@1000," D_TPWRIN ",kWh," DJ_TPWRIN ",4|" -//0x77,0x07,0x01,0x00,0x02,0x08,0x00,0xff -"1,77070100020800ff@1000," D_TPWROUT ",kWh," DJ_TPWROUT ",4|" -//0x77,0x07,0x01,0x00,0x10,0x07,0x00,0xff -"1,77070100100700ff@1," D_TPWRCURR ",W," DJ_TPWRCURR ",0|" -//0x77,0x07,0x01,0x00,0x00,0x00,0x09,0xff -"1,77070100000009ff@#," D_METERNR ",," DJ_METERNR ",0"; -#endif - -//===================================================== - -#if METER==EHZH -#undef METERS_USED -#define METERS_USED 1 -struct METER_DESC const meter_desc[METERS_USED]={ - [0]={3,'s',0,SML_BAUDRATE,"SML",-1,1,0}}; -// 2 Richtungszähler EHZ SML 8 bit 9600 baud, binär -// verbrauch total -const uint8_t meter[]= -//0x77,0x07,0x01,0x00,0x01,0x08,0x00,0xff -"1,77070100010800ff@1000," D_TPWRIN ",kWh," DJ_TPWRIN ",4|" -//0x77,0x07,0x01,0x00,0x01,0x08,0x01,0xff -"1,77070100020800ff@1000," D_TPWROUT ",kWh," DJ_TPWROUT ",4|" -//0x77,0x07,0x01,0x00,0x0f,0x07,0x00,0xff -"1,770701000f0700ff@1," D_TPWRCURR ",W," DJ_TPWRCURR ",0"; -#endif - -//===================================================== - -#if METER==EDL300 -#undef METERS_USED -#define METERS_USED 1 -struct METER_DESC const meter_desc[METERS_USED]={ - [0]={3,'s',0,SML_BAUDRATE,"SML",-1,1,0}}; -// 2 Richtungszähler EHZ SML 8 bit 9600 baud, binär -// verbrauch total -const uint8_t meter[]= -//0x77,0x07,0x01,0x00,0x01,0x08,0x00,0xff -"1,77070100010800ff@1000," D_TPWRIN ",kWh," DJ_TPWRIN ",4|" -//0x77,0x07,0x01,0x00,0x01,0x08,0x01,0xff -"1,77070100020801ff@1000," D_TPWROUT ",kWh," DJ_TPWROUT ",4|" -//0x77,0x07,0x01,0x00,0x0f,0x07,0x00,0xff -"1,770701000f0700ff@1," D_TPWRCURR ",W," DJ_TPWRCURR ",0"; -#endif - -#if METER==EBZD_G -#undef METERS_USED -#define METERS_USED 1 -struct METER_DESC const meter_desc[METERS_USED]={ - [0]={3,'s',0,SML_BAUDRATE,"strom",-1,1,0}}; -const uint8_t meter[]= -//0x77,0x07,0x01,0x00,0x01,0x08,0x00,0xff -"1,77070100010800ff@1000," D_TPWRIN ",kWh," DJ_TPWRIN ",4|" -// .. -"1,77070100020800ff@1000," D_TPWROUT ",kWh," DJ_TPWROUT ",4|" -//0x77,0x07,0x01,0x00,0x01,0x08,0x01,0xff -"1,77070100010801ff@1000," D_TPWRCURR1 ",kWh," DJ_TPWRCURR1 ",4|" -//0x77,0x07,0x01,0x00,0x01,0x08,0x02,0xff -"1,77070100010802ff@1000," D_TPWRCURR2 ",kWh," DJ_TPWRCURR2 ",4|" -// 77 07 01 00 10 07 00 FF -"1,77070100100700ff@1," D_TPWRCURR ",W," DJ_TPWRCURR ",0|" -// .. -"1,77070100600100ff@#," D_METERNR ",," DJ_METERNR ",0"; -#endif - - -//===================================================== - -#if METER==Q3B -#undef METERS_USED -#define METERS_USED 1 -struct METER_DESC const meter_desc[METERS_USED]={ - [0]={3,'s',0,SML_BAUDRATE,"SML",-1,1,0}}; -const uint8_t meter[]= -//0x77,0x07,0x01,0x00,0x01,0x08,0x01,0xff -"1,77070100010800ff@1000," D_TPWRIN ",kWh," DJ_TPWRIN ",4|" -//0x77,0x07,0x01,0x00,0x02,0x08,0x01,0xff -"1,77070100020801ff@1000," D_TPWROUT ",kWh," DJ_TPWROUT ",4|" -//0x77,0x07,0x01,0x00,0x01,0x07,0x00,0xff -"1,77070100010700ff@1," D_TPWRCURR ",W," DJ_TPWRCURR ",0"; -#endif - -#if METER==COMBO3 -// 3 Zähler Beispiel -#undef METERS_USED -#define METERS_USED 3 - -struct METER_DESC const meter_desc[METERS_USED]={ - [0]={3,'o',0,SML_BAUDRATE,"OBIS",-1,1,0}, // harware serial RX pin - [1]={14,'s',0,SML_BAUDRATE,"SML",-1,1,0}, // GPIO14 software serial - [2]={4,'o',0,SML_BAUDRATE,"OBIS2",-1,1,0}}; // GPIO4 software serial - -// 3 Zähler definiert -const uint8_t meter[]= -"1,1-0:1.8.0*255(@1," D_TPWRIN ",kWh," DJ_TPWRIN ",4|" -"1,1-0:2.8.0*255(@1," D_TPWROUT ",kWh," DJ_TPWROUT ",4|" -"1,1-0:21.7.0*255(@1," D_TPWRCURR1 ",W," DJ_TPWRCURR1 ",0|" -"1,1-0:41.7.0*255(@1," D_TPWRCURR2 ",W," DJ_TPWRCURR2 ",0|" -"1,1-0:61.7.0*255(@1," D_TPWRCURR3 ",W," DJ_TPWRCURR3 ",0|" -"1,=m 3+4+5 @1," D_TPWRCURR ",W," DJ_TPWRCURR ",0|" -"1,1-0:0.0.0*255(@#)," D_METERNR ",," DJ_METERNR ",0|" -"2,77070100010800ff@1000," D_TPWRIN ",kWh," DJ_TPWRIN ",4|" -"2,77070100020800ff@1000," D_TPWROUT ",kWh," DJ_TPWROUT ",4|" -"2,77070100100700ff@1," D_TPWRCURR ",W," DJ_TPWRCURR ",0|" -"3,1-0:1.8.1*255(@1," D_TPWRIN ",kWh," DJ_TPWRIN ",4|" -"3,1-0:2.8.1*255(@1," D_TPWROUT ",kWh," DJ_TPWROUT ",4|" -"3,=d 2 10 @1," D_TPWRCURR ",W," DJ_TPWRCURR ",0|" -"3,1-0:0.0.0*255(@#)," D_METERNR ",," DJ_METERNR ",0"; - -#endif - -#if METER==COMBO2 -// 2 Zähler Beispiel -#undef METERS_USED -#define METERS_USED 2 - -struct METER_DESC const meter_desc[METERS_USED]={ - [0]={3,'o',0,SML_BAUDRATE,"OBIS1",-1,1,0}, // harware serial RX pin - [1]={14,'o',0,SML_BAUDRATE,"OBIS2",-1,1,0}}; // GPIO14 software serial - -// 2 Zähler definiert -const uint8_t meter[]= -"1,1-0:1.8.1*255(@1," D_TPWRIN ",kWh," DJ_TPWRIN ",4|" -"1,1-0:2.8.1*255(@1," D_TPWROUT ",kWh," DJ_TPWROUT ",4|" -"1,=d 2 10 @1," D_TPWRCURR ",W," DJ_TPWRCURR ",0|" -"1,1-0:0.0.0*255(@#)," D_METERNR ",," DJ_METERNR ",0|" - -"2,1-0:1.8.1*255(@1," D_TPWRIN ",kWh," DJ_TPWRIN ",4|" -"2,1-0:2.8.1*255(@1," D_TPWROUT ",kWh," DJ_TPWROUT ",4|" -"2,=d 6 10 @1," D_TPWRCURR ",W," DJ_TPWRCURR ",0|" -"2,1-0:0.0.0*255(@#)," D_METERNR ",," DJ_METERNR ",0"; - -#endif - -#if METER==COMBO3a -#undef METERS_USED -#define METERS_USED 3 - -struct METER_DESC const meter_desc[METERS_USED]={ - [0]={3,'o',0,SML_BAUDRATE,"OBIS1",-1,1,0}, // harware serial RX pin - [1]={14,'o',0,SML_BAUDRATE,"OBIS2",-1,1,0}, - [2]={1,'o',0,SML_BAUDRATE,"OBIS3",-1,1,0}}; - -// 3 Zähler definiert -const uint8_t meter[]= -"1,=h --- Zähler Nr 1 ---|" -"1,1-0:1.8.1*255(@1," D_TPWRIN ",kWh," DJ_TPWRIN ",4|" -"1,1-0:2.8.1*255(@1," D_TPWROUT ",kWh," DJ_TPWROUT ",4|" -"1,=d 2 10 @1," D_TPWRCURR ",W," DJ_TPWRCURR ",0|" -"1,1-0:0.0.0*255(@#)," D_METERNR ",," DJ_METERNR ",0|" -"2,=h --- Zähler Nr 2 ---|" -"2,1-0:1.8.1*255(@1," D_TPWRIN ",kWh," DJ_TPWRIN ",4|" -"2,1-0:2.8.1*255(@1," D_TPWROUT ",kWh," DJ_TPWROUT ",4|" -"2,=d 6 10 @1," D_TPWRCURR ",W," DJ_TPWRCURR ",0|" -"2,1-0:0.0.0*255(@#)," D_METERNR ",," DJ_METERNR ",0|" -"3,=h --- Zähler Nr 3 ---|" -"3,1-0:1.8.1*255(@1," D_TPWRIN ",kWh," DJ_TPWRIN ",4|" -"3,1-0:2.8.1*255(@1," D_TPWROUT ",kWh," DJ_TPWROUT ",4|" -"3,=d 10 10 @1," D_TPWRCURR ",W," DJ_TPWRCURR ",0|" -"3,1-0:0.0.0*255(@#)," D_METERNR ",," DJ_METERNR ",0"; - -#endif - -//===================================================== - -#if METER==Q3B_V1 -#undef METERS_USED -#define METERS_USED 1 -struct METER_DESC const meter_desc[METERS_USED]={ -[0]={3,'o',0,SML_BAUDRATE,"OBIS",-1,1,0}}; -const uint8_t meter[]= -"1,1-0:1.8.1*255(@1," D_TPWRIN ",kWh," DJ_TPWRIN ",4|" -"1,=d 1 10 @1," D_TPWRCURR ",W," DJ_TPWRCURR ",0|" -"1,1-0:0.0.0*255(@#)," D_METERNR ",," DJ_METERNR ",0"; -#endif - -//===================================================== - -#if METER==EHZ363_2 -#undef METERS_USED -#define METERS_USED 1 -struct METER_DESC const meter_desc[METERS_USED]={ -[0]={3,'s',0,SML_BAUDRATE,"SML",-1,1,0}}; -// 2 direction meter EHZ SML 8 bit 9600 baud, binary -const uint8_t meter[]= -//0x77,0x07,0x01,0x00,0x01,0x08,0x00,0xff -"1,77070100010800ff@1000," D_TPWRIN ",kWh," DJ_TPWRIN ",4|" -//0x77,0x07,0x01,0x00,0x02,0x08,0x00,0xff -"1,77070100020800ff@1000," D_TPWROUT ",kWh," DJ_TPWROUT ",4|" -//0x77,0x07,0x01,0x00,0x01,0x08,0x01,0xff -"1,77070100010801ff@1000," D_TPWRCURR1 ",kWh," DJ_TPWRCURR1 ",4|" -//0x77,0x07,0x01,0x00,0x01,0x08,0x02,0xff -"1,77070100010802ff@1000," D_TPWRCURR2 ",kWh," DJ_TPWRCURR2 ",4|" -//0x77,0x07,0x01,0x00,0x10,0x07,0x00,0xff -"1,77070100100700ff@1," D_TPWRCURR ",W," DJ_TPWRCURR ",0|" -//0x77,0x07,0x01,0x00,0x00,0x00,0x09,0xff -"1,77070100000009ff@#," D_METERNR ",," DJ_METERNR ",0"; -#endif - -// example OBIS power meter + gas and water counter -#if METER==COMBO3b -#undef METERS_USED -#define METERS_USED 3 -struct METER_DESC const meter_desc[METERS_USED]={ - [0]={3,'o',0,SML_BAUDRATE,"OBIS",-1,1,0}, // harware serial RX pin - [1]={14,'c',0,50,"Gas"}, // GPIO14 gas counter - [2]={1,'c',0,10,"Wasser"}}; // water counter - -// 3 meters defined -const uint8_t meter[]= -"1,1-0:1.8.1*255(@1," D_TPWRIN ",kWh," DJ_TPWRIN ",4|" -"1,1-0:2.8.1*255(@1," D_TPWROUT ",kWh," DJ_TPWROUT ",4|" -"1,=d 2 10 @1," D_TPWRCURR ",W," DJ_TPWRCURR ",0|" -"1,1-0:0.0.0*255(@#)," D_METERNR ",," DJ_METERNR ",0|" - -// with counters the comparison string must be exactly this string -"2,1-0:1.8.0*255(@100," D_GasIN ",cbm," DJ_COUNTER ",2|" - -"3,1-0:1.8.0*255(@100," D_H2oIN ",cbm," DJ_COUNTER ",2"; -#endif - - -#if METER==WGS_COMBO -#undef METERS_USED -#define METERS_USED 3 - -struct METER_DESC const meter_desc[METERS_USED]={ - [0]={1,'c',0,10,"H20",-1,1,0}, // GPIO1 water counter - [1]={4,'c',0,50,"GAS",-1,1,0}, // GPIO4 gas counter - [2]={3,'s',0,SML_BAUDRATE,"SML",-1,1,0}}; // SML harware serial RX pin - -const uint8_t meter[]= -//----------------------------Wasserzähler--sensor53 c1------------------------------------ -//"1,=h==================|" -"1,1-0:1.8.0*255(@10000," D_H2oIN ",cbm," DJ_COUNTER ",4|" // 1 -//----------------------------Gaszähler-----sensor53 c2------------------------------------ -// bei gaszählern (countern) muss der Vergleichsstring so aussehen wie hier -"2,=h==================|" -"2,1-0:1.8.0*255(@100," D_GasIN ",cbm," DJ_COUNTER ",3|" // 2 -//----------------------------Stromzähler-EHZ363W5--sensor53 d0---------------------------- -"3,=h==================|" -//0x77,0x07,0x01,0x00,0x01,0x08,0x00,0xff -"3,77070100010800ff@1000," D_TPWRIN ",kWh," DJ_TPWRIN ",3|" // 3 Zählerstand Total -"3,=h==================|" -//0x77,0x07,0x01,0x00,0x10,0x07,0x00,0xff -"3,77070100100700ff@1," D_TPWRCURR ",W," DJ_TPWRCURR ",2|" // 4 Aktuelle Leistung -"3,=h -------------------------------|" -"3,=m 10+11+12 @100," D_StL1L2L3 ",A," DJ_CSUM ",2|" // 5 Summe Aktuelle Ströme -//"3,=h -------------------------------|" -"3,=m 13+14+15/#3 @100," D_SpL1L2L3 ",V," DJ_VAVG ",2|" // 6 Mittelwert Spannungen -"3,=h==================|" -//0x77,0x07,0x01,0x00,0x24,0x07,0x00,0xff -"3,77070100240700ff@1," D_TPWRCURR1 ",W," DJ_TPWRCURR1 ",2|" // 7 Wirkleistung L1 -//0x77,0x07,0x01,0x00,0x38,0x07,0x00,0xff -"3,77070100380700ff@1," D_TPWRCURR2 ",W," DJ_TPWRCURR2 ",2|" // 8 Wirkleistung L2 -//0x77,0x07,0x01,0x00,0x4c,0x07,0x00,0xff -"3,770701004c0700ff@1," D_TPWRCURR3 ",W," DJ_TPWRCURR3 ",2|" // 9 Wirkleistung L3 -"3,=h -------------------------------|" -//0x77,0x07,0x01,0x00,0x1f,0x07,0x00,0xff -"3,770701001f0700ff@100," D_Strom_L1 ",A," DJ_CURR1 ",2|" // 10 Strom L1 -//0x77,0x07,0x01,0x00,0x33,0x07,0x00,0xff -"3,77070100330700ff@100," D_Strom_L2 ",A," DJ_CURR2 ",2|" // 11 Strom L2 -//0x77,0x07,0x01,0x00,0x47,0x07,0x00,0xff -"3,77070100470700ff@100," D_Strom_L3 ",A," DJ_CURR3 ",2|" // 12 Strom L3 -"3,=h -------------------------------|" -//0x77,0x07,0x01,0x00,0x20,0x07,0x00,0xff -"3,77070100200700ff@100," D_Spannung_L1 ",V," DJ_VOLT1 ",2|" // 13 Spannung L1 -//0x77,0x07,0x01,0x00,0x34,0x07,0x00,0xff -"3,77070100340700ff@100," D_Spannung_L2 ",V," DJ_VOLT2 ",2|" // 14 Spannung L2 -//0x77,0x07,0x01,0x00,0x48,0x07,0x00,0xff -"3,77070100480700ff@100," D_Spannung_L3 ",V," DJ_VOLT3 ",2|" // 15 Spannung L3 -"3,=h==================|" -//0x77,0x07,0x01,0x00,0x00,0x00,0x09,0xff -"3,77070100000009ff@#," D_METERSID ",," DJ_METERSID ",0|" // 16 Service ID -"3,=h--------------------------------"; // letzte Zeile -#endif - - -#if METER==Q3C -#undef METERS_USED -#define METERS_USED 1 -struct METER_DESC const meter_desc[METERS_USED]={ - [0]={3,'s',0,SML_BAUDRATE,"SML",-1,1,0}}; -const uint8_t meter[]= -//0x77,0x07,0x01,0x00,0x01,0x08,0x01,0xff -"1,77070101010800ff@1000," D_TPWRIN0 ",kWh," DJ_TPWRIN0 ",2|" // Verbrauch T0 -//0x77,0x07,0x01,0x00,0x01,0x08,0x01,0xff -"1,77070101010801ff@1000," D_TPWRIN1 ",kWh," DJ_TPWRIN1 ",2|" // Verbrauch T1 -//0x77,0x07,0x01,0x00,0x01,0x07,0x00,0xff -"1,77070100010700ff@1," D_TPWRCURR ",W," DJ_TPWRCURR ",0|" // Strom Gesamt -//0x77,0x07,0x01,0x00,0x01,0x07,0x00,0xff -"1,77070100150700ff@1," D_TPWRCURR1 ",W," DJ_TPWRCURR1 ",0|" // Strom L1 -//0x77,0x07,0x01,0x00,0x01,0x07,0x00,0xff -"1,77070100290700ff@1," D_TPWRCURR2 ",W," DJ_TPWRCURR2 ",0|" // Strom L2 -//0x77,0x07,0x01,0x00,0x01,0x07,0x00,0xff -"1,770701003D0700ff@1," D_TPWRCURR3 ",W," DJ_TPWRCURR3 ",0"; // Strom L3 -#endif - -// this driver uses double because meter vars would not fit in float -//===================================================== - // median filter eliminates outliers, but uses much RAM and CPU cycles // 672 bytes extra RAM with SML_MAX_VARS = 16 // default compile on, but must be enabled by descriptor flag 16 // may be undefined if RAM must be saved -#ifndef SML_NO_MEDIAN_FILTER +#ifndef NO_USE_SML_MEDIAN_FILTER +#undef USE_SML_MEDIAN_FILTER #define USE_SML_MEDIAN_FILTER #endif -// max number of vars , may be adjusted -#ifndef SML_MAX_VARS -#define SML_MAX_VARS 20 -#endif +/* special options per meter +1: +special binary SML option for meters that use a bit in the status register to sign import or export like ED300L, AS2020 or DTZ541 +a. obis code that holds the direction bit, +b. Flag identifier, +c. direction bit, +d. second Flag identifier (some meters use 2 different flags), +e. second bit, +f. obis code of value to be inverted on direction bit. +e.g. 1,=so1,00010800,65,11,65,11,00100700 for DTZ541 +2: +flags, currently only bit 0 and 1 +if 1 fix DWS74 bug +if 2 use asci obis line compare instead a pattern compare +e.g. 1,=so2,2 set obis line mode on meter 1 -double meter_vars[SML_MAX_VARS]; -// calulate deltas -#define MAX_DVARS MAX_METERS*2 -double dvalues[MAX_DVARS]; -uint32_t dtimes[MAX_DVARS]; -uint8_t meters_used; -uint8_t dvalid[SML_MAX_VARS]; +3: +serial buffers +a. serial buffer size +b. serial irq buffer size +e.g. 1,=so3,256,256 set serial buffers on meter 1 -struct METER_DESC const *meter_desc_p; -const uint8_t *meter_p; -uint16_t meter_spos[MAX_METERS]; +4: +decrytion key, 16 bytes hex btw 32 chars without spaces or commas +defining key switches decryption mode on -// software serial pointers -#ifdef ESP8266 -TasmotaSerial *meter_ss[MAX_METERS]; -#endif // ESP8266 +*/ +//#define MODBUS_DEBUG -// serial buffers, may be made larger depending on telegram lenght -#ifndef SML_BSIZ -#define SML_BSIZ 48 -#endif -uint8_t smltbuf[MAX_METERS][SML_BSIZ]; - -// meter nr as string -#define METER_ID_SIZE 24 -char meter_id[MAX_METERS][METER_ID_SIZE]; - -#define VBUS_SYNC 0xaa -#define SML_SYNC 0x77 -#define EBUS_SYNC 0xaa -#define EBUS_ESC 0xa9 - -uint8_t sml_send_blocks; -uint8_t sml_100ms_cnt; -uint8_t sml_desc_cnt; - -#define SML_OPTIONS_JSON_ENABLE 1 -#define SML_OPTIONS_OBIS_LINE 2 -uint8_t sml_options = SML_OPTIONS_JSON_ENABLE; - - -#ifdef USE_SML_MEDIAN_FILTER -// median filter, should be odd size -#define MEDIAN_SIZE 5 -struct SML_MEDIAN_FILTER { -double buffer[MEDIAN_SIZE]; -int8_t index; -} sml_mf[SML_MAX_VARS]; - -#ifndef FLT_MAX -#define FLT_MAX 99999999 -#endif - -double sml_median_array(double *array,uint8_t len) { - uint8_t ind[len]; - uint8_t mind=0,index=0,flg; - double min=FLT_MAX; - - for (uint8_t hcnt=0; hcntbuffer[mf->index]=in; - mf->index++; - if (mf->index>=MEDIAN_SIZE) mf->index=0; - - return sml_median_array(mf->buffer,MEDIAN_SIZE); -/* - // sort list and take median - memmove(tbuff,mf->buffer,sizeof(tbuff)); - for (byte ocnt=0; ocnttbuff[count+1]) { - tmp=tbuff[count]; - tbuff[count]=tbuff[count+1]; - tbuff[count+1]=tmp; - flag=1; - } - } - if (!flag) break; - } - return tbuff[MEDIAN_SIZE/2]; - */ -} -#endif - - -// ESP32 software serial read only +// ESP32 combined hardware and software serial driver, software read only #ifdef ESP32 #ifdef USE_ESP32_SW_SERIAL - #ifndef ESP32_SWS_BUFFER_SIZE #define ESP32_SWS_BUFFER_SIZE 256 #endif - class SML_ESP32_SERIAL : public Stream { public: SML_ESP32_SERIAL(uint32_t uart_index); @@ -650,6 +138,7 @@ public: void setRxBufferSize(uint32_t size); void updateBaudRate(uint32_t baud); void rxRead(void); + void end(); using Print::write; private: // Member variables @@ -681,6 +170,7 @@ SML_ESP32_SERIAL::SML_ESP32_SERIAL(uint32_t index) { SML_ESP32_SERIAL::~SML_ESP32_SERIAL(void) { if (hws) { hws->end(); + delete(hws); } else { detachInterrupt(m_rx_pin); if (m_buffer) { @@ -693,6 +183,11 @@ void SML_ESP32_SERIAL::setbaud(uint32_t speed) { m_bit_time = ESP.getCpuFreqMHz() * 1000000 / speed; } +void SML_ESP32_SERIAL::end(void) { + if (m_buffer) { + free(m_buffer); + } +} bool SML_ESP32_SERIAL::begin(uint32_t speed, uint32_t smode, int32_t recpin, int32_t trxpin) { if (!m_valid) { return false; } @@ -704,7 +199,7 @@ bool SML_ESP32_SERIAL::begin(uint32_t speed, uint32_t smode, int32_t recpin, int serial_buffer_size = ESP32_SWS_BUFFER_SIZE; m_buffer = (uint8_t*)malloc(serial_buffer_size); if (m_buffer == NULL) return false; - pinMode(m_rx_pin, INPUT); + pinMode(m_rx_pin, INPUT_PULLUP); attachInterruptArg(m_rx_pin, sml_callRxRead, this, CHANGE); m_in_pos = m_out_pos = 0; hws = nullptr; @@ -743,7 +238,7 @@ int32_t SML_ESP32_SERIAL::read(void) { } else { if (m_in_pos == m_out_pos) return -1; uint32_t ch = m_buffer[m_out_pos]; - m_out_pos = (m_out_pos +1) % serial_buffer_size; + m_out_pos = (m_out_pos + 1) % serial_buffer_size; return ch; } } @@ -841,316 +336,336 @@ void IRAM_ATTR SML_ESP32_SERIAL::rxRead(void) { #endif // USE_ESP32_SW_SERIAL #endif // ESP32 + +typedef union { + uint8_t data; + struct { + uint8_t trxenpol : 1; // string or number + uint8_t trxen : 1; + uint8_t trxenpin : 6; + }; +} TRX_EN_TYPE; + +#ifndef TMSBSIZ +#define TMSBSIZ 256 +#endif + +#define SO_DWS74_BUG 1 +#define SO_OBIS_LINE 2 + +#define METER_ID_SIZE 24 + +#define SML_CRYPT_SIZE 16 + +struct METER_DESC { + int8_t srcpin; + uint8_t type; + uint16_t flag; + int32_t params; + char prefix[8]; + int8_t trxpin; + uint8_t tsecs; + char *txmem; + uint8_t index; + uint8_t max_index; + char *script_str; + uint8_t sopt; + TRX_EN_TYPE trx_en; + bool shift_mode; + uint16_t sbsiz; + uint8_t *sbuff; + uint16_t spos; + uint16_t sibsiz; + uint8_t so_flags; + char meter_id[METER_ID_SIZE]; +#ifdef USE_SML_SPECOPT + uint32_t so_obis1; + uint32_t so_obis2; + uint8_t so_fcode1; + uint8_t so_bpos1; + uint8_t so_fcode2; + uint8_t so_bpos2; +#endif #ifdef ESP32 #ifndef USE_ESP32_SW_SERIAL -HardwareSerial *meter_ss[MAX_METERS]; + HardwareSerial *meter_ss; #else -SML_ESP32_SERIAL *meter_ss[MAX_METERS]; + SML_ESP32_SERIAL *meter_ss; #endif #endif // ESP32 - - -#ifdef ANALOG_OPTO_SENSOR -// sensor over ADS1115 with i2c Bus -uint8_t ads1115_up; - -// ads1115 driver -#define SAMPLE_BIT (0x8000) - -#define ADS1115_COMP_QUEUE_SHIFT 0 -#define ADS1115_COMP_LATCH_SHIFT 2 -#define ADS1115_COMP_POLARITY_SHIFT 3 -#define ADS1115_COMP_MODE_SHIFT 4 -#define ADS1115_DATA_RATE_SHIFT 5 -#define ADS1115_MODE_SHIFT 8 -#define ADS1115_PGA_SHIFT 9 -#define ADS1115_MUX_SHIFT 12 - -enum ads1115_comp_queue { - ADS1115_COMP_QUEUE_AFTER_ONE = 0, - ADS1115_COMP_QUEUE_AFTER_TWO = 0x1 << ADS1115_COMP_QUEUE_SHIFT, - ADS1115_COMP_QUEUE_AFTER_FOUR = 0x2 << ADS1115_COMP_QUEUE_SHIFT, - ADS1115_COMP_QUEUE_DISABLE = 0x3 << ADS1115_COMP_QUEUE_SHIFT, - ADS1115_COMP_QUEUE_MASK = 0x3 << ADS1115_COMP_QUEUE_SHIFT, -}; - -enum ads1115_comp_latch { - ADS1115_COMP_LATCH_NO = 0, - ADS1115_COMP_LATCH_YES = 1 << ADS1115_COMP_LATCH_SHIFT, - ADS1115_COMP_LATCH_MASK = 1 << ADS1115_COMP_LATCH_SHIFT, -}; - -enum ads1115_comp_polarity { - ADS1115_COMP_POLARITY_ACTIVE_LOW = 0, - ADS1115_COMP_POLARITY_ACTIVE_HIGH = 1 << ADS1115_COMP_POLARITY_SHIFT, - ADS1115_COMP_POLARITY_MASK = 1 << ADS1115_COMP_POLARITY_SHIFT, -}; - -enum ads1115_comp_mode { - ADS1115_COMP_MODE_WINDOW = 0, - ADS1115_COMP_MODE_HYSTERESIS = 1 << ADS1115_COMP_MODE_SHIFT, - ADS1115_COMP_MODE_MASK = 1 << ADS1115_COMP_MODE_SHIFT, -}; - -enum ads1115_data_rate { - ADS1115_DATA_RATE_8_SPS = 0, - ADS1115_DATA_RATE_16_SPS = 0x1 << ADS1115_DATA_RATE_SHIFT, - ADS1115_DATA_RATE_32_SPS = 0x2 << ADS1115_DATA_RATE_SHIFT, - ADS1115_DATA_RATE_64_SPS = 0x3 << ADS1115_DATA_RATE_SHIFT, - ADS1115_DATA_RATE_128_SPS = 0x4 << ADS1115_DATA_RATE_SHIFT, - ADS1115_DATA_RATE_250_SPS = 0x5 << ADS1115_DATA_RATE_SHIFT, - ADS1115_DATA_RATE_475_SPS = 0x6 << ADS1115_DATA_RATE_SHIFT, - ADS1115_DATA_RATE_860_SPS = 0x7 << ADS1115_DATA_RATE_SHIFT, - ADS1115_DATA_RATE_MASK = 0x7 << ADS1115_DATA_RATE_SHIFT, -}; - -enum ads1115_mode { - ADS1115_MODE_CONTINUOUS = 0, - ADS1115_MODE_SINGLE_SHOT = 1 << ADS1115_MODE_SHIFT, - ADS1115_MODE_MASK = 1 << ADS1115_MODE_SHIFT, -}; - -enum ads1115_pga { - ADS1115_PGA_TWO_THIRDS = 0, //±6.144 V - ADS1115_PGA_ONE = 0x1 << ADS1115_PGA_SHIFT, //±4.096 V - ADS1115_PGA_TWO = 0x2 << ADS1115_PGA_SHIFT, //±2.048 V - ADS1115_PGA_FOUR = 0x3 << ADS1115_PGA_SHIFT, //±1.024 V - ADS1115_PGA_EIGHT = 0x4 << ADS1115_PGA_SHIFT, //±0.512 V - ADS1115_PGA_SIXTEEN = 0x5 << ADS1115_PGA_SHIFT, //±0.256 V - ADS1115_PGA_MASK = 0x7 << ADS1115_PGA_SHIFT, +// software serial pointers +#ifdef ESP8266 + TasmotaSerial *meter_ss; +#endif // ESP8266 +#ifdef USE_SML_DECRYPT + bool use_crypt; + uint8_t last_iob; + uint8_t key[SML_CRYPT_SIZE]; +#endif }; -enum ads1115_mux { - ADS1115_MUX_DIFF_AIN0_AIN1 = 0, - ADS1115_MUX_DIFF_AIN0_AIN3 = 0x1 << ADS1115_MUX_SHIFT, - ADS1115_MUX_DIFF_AIN1_AIN3 = 0x2 << ADS1115_MUX_SHIFT, - ADS1115_MUX_DIFF_AIN2_AIN3 = 0x3 << ADS1115_MUX_SHIFT, - ADS1115_MUX_GND_AIN0 = 0x4 << ADS1115_MUX_SHIFT, - ADS1115_MUX_GND_AIN1 = 0x5 << ADS1115_MUX_SHIFT, - ADS1115_MUX_GND_AIN2 = 0x6 << ADS1115_MUX_SHIFT, - ADS1115_MUX_GND_AIN3 = 0x7 << ADS1115_MUX_SHIFT, - ADS1115_MUX_MASK = 0x7 << ADS1115_MUX_SHIFT, -}; - -class ADS1115 { -public: - ADS1115(uint8_t address = 0x48); - - void begin(); - uint8_t trigger_sample(); - uint8_t reset(); - bool is_sample_in_progress(); - int16_t read_sample(); - float sample_to_float(int16_t val); - float read_sample_float(); - - void set_comp_queue(enum ads1115_comp_queue val) { set_config(val, ADS1115_COMP_QUEUE_MASK); } - void set_comp_latching(enum ads1115_comp_latch val) { set_config(val, ADS1115_COMP_LATCH_MASK); } - void set_comp_polarity(enum ads1115_comp_polarity val) { set_config(val, ADS1115_COMP_POLARITY_MASK); } - void set_comp_mode(enum ads1115_comp_mode val) { set_config(val, ADS1115_COMP_MODE_MASK); } - void set_data_rate(enum ads1115_data_rate val) { set_config(val, ADS1115_DATA_RATE_MASK); } - void set_mode(enum ads1115_mode val) { set_config(val, ADS1115_MODE_MASK); } - void set_pga(enum ads1115_pga val) { set_config(val, ADS1115_PGA_MASK); m_voltage_range = val >> ADS1115_PGA_SHIFT; } - void set_mux(enum ads1115_mux val) { set_config(val, ADS1115_MUX_MASK); } - -private: - void set_config(uint16_t val, uint16_t mask) { - m_config = (m_config & ~mask) | val; - } - - uint8_t write_register(uint8_t reg, uint16_t val); - uint16_t read_register(uint8_t reg); - - uint8_t m_address; - uint16_t m_config; - int m_voltage_range; -}; +struct METER_DESC meter_desc[MAX_METERS]; -enum ads1115_register { - ADS1115_REGISTER_CONVERSION = 0, - ADS1115_REGISTER_CONFIG = 1, - ADS1115_REGISTER_LOW_THRESH = 2, - ADS1115_REGISTER_HIGH_THRESH = 3, -}; - -#define FACTOR 32768.0 -static float ranges[] = { 6.144 / FACTOR, 4.096 / FACTOR, 2.048 / FACTOR, 1.024 / FACTOR, 0.512 / FACTOR, 0.256 / FACTOR}; - -ADS1115::ADS1115(uint8_t address) -{ - m_address = address; - m_config = ADS1115_COMP_QUEUE_AFTER_ONE | - ADS1115_COMP_LATCH_NO | - ADS1115_COMP_POLARITY_ACTIVE_LOW | - ADS1115_COMP_MODE_WINDOW | - ADS1115_DATA_RATE_128_SPS | - ADS1115_MODE_SINGLE_SHOT | - ADS1115_MUX_GND_AIN0; - set_pga(ADS1115_PGA_ONE); -} - -uint8_t ADS1115::write_register(uint8_t reg, uint16_t val) -{ - Wire.beginTransmission(m_address); - Wire.write(reg); - Wire.write(val>>8); - Wire.write(val & 0xFF); - return Wire.endTransmission(); -} - -uint16_t ADS1115::read_register(uint8_t reg) -{ - Wire.beginTransmission(m_address); - Wire.write(reg); - Wire.endTransmission(); - - uint8_t result = Wire.requestFrom((int)m_address, 2, 1); - if (result != 2) { - return 0; - } - - uint16_t val; - - val = Wire.read() << 8; - val |= Wire.read(); - return val; -} - -void ADS1115::begin() -{ - Wire.begin(); -} - -uint8_t ADS1115::trigger_sample() -{ - return write_register(ADS1115_REGISTER_CONFIG, m_config | SAMPLE_BIT); -} - -uint8_t ADS1115::reset() -{ - Wire.beginTransmission(0); - Wire.write(0x6); - return Wire.endTransmission(); -} - -bool ADS1115::is_sample_in_progress() -{ - uint16_t val = read_register(ADS1115_REGISTER_CONFIG); - return (val & SAMPLE_BIT) == 0; -} - -int16_t ADS1115::read_sample() -{ - return read_register(ADS1115_REGISTER_CONVERSION); -} - -float ADS1115::sample_to_float(int16_t val) -{ - return val * ranges[m_voltage_range]; -} - -float ADS1115::read_sample_float() -{ - return sample_to_float(read_sample()); -} - -ADS1115 adc; - -void ADS1115_init(void) { - - ads1115_up=0; - if (!TasmotaGlobal.i2c_enabled) return; - - adc.begin(); - adc.set_data_rate(ADS1115_DATA_RATE_128_SPS); - adc.set_mode(ADS1115_MODE_CONTINUOUS); - adc.set_mux(ADS1115_MUX_DIFF_AIN0_AIN3); - adc.set_pga(ADS1115_PGA_TWO); - - int16_t val = adc.read_sample(); - ads1115_up=1; -} +// this driver uses double because some meter vars would not fit in float +//===================================================== +// serial buffers, may be made larger depending on telegram lenght +#ifndef SML_BSIZ +#define SML_BSIZ 48 #endif -char sml_start; -uint8_t dump2log=0; +#define VBUS_SYNC 0xaa +#define SML_SYNC 0x77 +#define SML_CRYPT_SYNC1 0x7e +#define SML_CRYPT_SYNC2 0xa0 +#define EBUS_SYNC 0xaa +#define EBUS_ESC 0xa9 + + +// calulate deltas +#define MAX_DVARS MAX_METERS*2 + +#ifndef SML_DUMP_SIZE +#define SML_DUMP_SIZE 128 +#endif + +// median filter, should be odd size +#define MEDIAN_SIZE 5 +struct SML_MEDIAN_FILTER { +double buffer[MEDIAN_SIZE]; +int8_t index; +}; + + +struct SML_GLOBS { + uint8_t sml_send_blocks; + uint8_t sml_100ms_cnt; + uint8_t sml_desc_cnt; + uint8_t meters_used; + uint8_t maxvars; + uint8_t *meter_p; + double *meter_vars; + uint8_t *dvalid; + double dvalues[MAX_DVARS]; + uint32_t dtimes[MAX_DVARS]; + char sml_start; + uint8_t dump2log = 0; + uint8_t ser_act_LED_pin = 255; + uint8_t ser_act_meter_num = 0; + uint16_t sml_logindex; + char *log_data; +#if defined(ED300L) || defined(AS2020) || defined(DTZ541) || defined(USE_SML_SPECOPT) + uint8_t sml_status[MAX_METERS]; + uint8_t g_mindex; +#endif +#ifdef USE_SML_MEDIAN_FILTER + struct SML_MEDIAN_FILTER *sml_mf; +#endif + uint8_t *script_meter; + struct METER_DESC *mp; + bool ready; +} sml_globs; + + + +#define SML_OPTIONS_JSON_ENABLE 1 +uint8_t sml_options = SML_OPTIONS_JSON_ENABLE; + +#ifdef USE_SML_MEDIAN_FILTER + +#ifndef FLT_MAX +#define FLT_MAX 99999999 +#endif + +double sml_median_array(double *array, uint8_t len) { + uint8_t ind[len]; + uint8_t mind = 0, index = 0, flg; + double min = FLT_MAX; + + for (uint8_t hcnt = 0; hcnt < len / 2 + 1; hcnt++) { + for (uint8_t mcnt = 0; mcnt < len; mcnt++) { + flg = 0; + for (uint8_t icnt = 0; icnt < index; icnt++) { + if (ind[icnt] == mcnt) { + flg = 1; + } + } + if (!flg) { + if (array[mcnt] < min) { + min = array[mcnt]; + mind = mcnt; + } + } + } + ind[index] = mind; + index++; + min = FLT_MAX; + } + return array[ind[len / 2]]; + } + + +// calc median +double sml_median(struct SML_MEDIAN_FILTER* mf, double in) { + //double tbuff[MEDIAN_SIZE],tmp; + //uint8_t flag; + mf->buffer[mf->index] = in; + mf->index++; + if (mf->index >= MEDIAN_SIZE) mf->index = 0; + + return sml_median_array(mf->buffer, MEDIAN_SIZE); +/* + // sort list and take median + memmove(tbuff,mf->buffer,sizeof(tbuff)); + for (byte ocnt=0; ocnttbuff[count+1]) { + tmp=tbuff[count]; + tbuff[count]=tbuff[count+1]; + tbuff[count+1]=tmp; + flag=1; + } + } + if (!flag) break; + } + return tbuff[MEDIAN_SIZE/2]; + */ +} +#endif + + -uint8_t ser_act_LED_pin=255; -uint8_t ser_act_meter_num=0; #define SML_SAVAILABLE Serial_available() #define SML_SREAD Serial_read() #define SML_SPEAK Serial_peek() bool Serial_available() { - uint8_t num=dump2log&7; - if (num<1 || num>meters_used) num=1; - if (!meter_ss[num-1]) return 0; - return meter_ss[num-1]->available(); + uint8_t num = sml_globs.dump2log & 7; + if (num < 1 || num > sml_globs.meters_used) num = 1; + if (!meter_desc[num - 1].meter_ss) return 0; + return meter_desc[num - 1].meter_ss->available(); } uint8_t Serial_read() { - uint8_t num=dump2log&7; - if (num<1 || num>meters_used) num=1; - if (!meter_ss[num-1]) return 0; - return meter_ss[num-1]->read(); + uint8_t num = sml_globs.dump2log & 7; + if (num < 1 || num > sml_globs.meters_used) num = 1; + if (!meter_desc[num - 1].meter_ss) return 0; + return meter_desc[num - 1].meter_ss->read(); } uint8_t Serial_peek() { - uint8_t num=dump2log&7; - if (num<1 || num>meters_used) num=1; - if (!meter_ss[num-1]) return 0; - return meter_ss[num-1]->peek(); + uint8_t num = sml_globs.dump2log & 7; + if (num < 1 || num > sml_globs.meters_used) num = 1; + if (!meter_desc[num - 1].meter_ss) return 0; + return meter_desc[num - 1].meter_ss->peek(); } -#ifndef SML_DUMP_SIZE -#define SML_DUMP_SIZE 128 -#endif - -uint16_t sml_logindex; -char log_data[SML_DUMP_SIZE]; #define SML_EBUS_SKIP_SYNC_DUMPS +uint8_t *hdlc_decode(uint8_t *data, uint32_t dlen, uint8_t *key, uint16_t *size); -void Dump2log(void) { +void dump2log(void) { int16_t index = 0, hcnt = 0; uint32_t d_lastms; uint8_t dchars[16]; - uint8_t type = meter_desc_p[(dump2log&7) - 1].type; + uint8_t meter = (sml_globs.dump2log & 7) - 1; + uint8_t type = sml_globs.mp[meter].type; //if (!SML_SAVAILABLE) return; + if (!sml_globs.log_data) return; - if (dump2log&8) { +#ifdef USE_SML_DECRYPT + struct METER_DESC *mp = &meter_desc[meter]; + if (mp->use_crypt == true) { + d_lastms = millis(); + sml_globs.log_data[0] = ':'; + sml_globs.log_data[1] = ' '; + sml_globs.sml_logindex = 2; + while ((millis() - d_lastms) < 40) { + while (SML_SAVAILABLE) { + uint8_t iob = SML_SREAD; + sprintf(&sml_globs.log_data[sml_globs.sml_logindex], "%02x ", iob); + if (sml_globs.sml_logindex < SML_DUMP_SIZE - 7) { + sml_globs.sml_logindex += 3; + } + // fill raw serial buffer + mp->sbuff[mp->spos] = iob; + mp->spos++; + if (mp->spos >= mp->sbsiz) { + mp->spos = mp->sbsiz - 1; + } + if (iob == SML_CRYPT_SYNC2 && mp->last_iob == SML_CRYPT_SYNC1) { + // frame start + mp->spos = 2; + mp->sbuff[0] = SML_CRYPT_SYNC1; + mp->sbuff[1] = SML_CRYPT_SYNC2; + } + mp->last_iob = iob; + uint16_t logsiz; + uint8_t *fbuff = hdlc_decode(mp->sbuff, mp->spos, meter_desc[meter].key, &logsiz); + if (fbuff) { + // we decoded a valid frame + AddLog(LOG_LEVEL_INFO, PSTR(">> decrypted block: %d bytes"), logsiz); + uint16_t index = 0; + while (logsiz) { + sml_globs.log_data[0] = ':'; + sml_globs.log_data[1] = '>'; + sml_globs.sml_logindex = 2; + for (uint16_t cnt = 0; cnt < 16; cnt++) { + sprintf(&sml_globs.log_data[sml_globs.sml_logindex], "%02x ", fbuff[index++]); + if (sml_globs.sml_logindex < SML_DUMP_SIZE - 7) { + sml_globs.sml_logindex += 3; + } + logsiz--; + if (!logsiz) { + break; + } + } + AddLogData(LOG_LEVEL_INFO, sml_globs.log_data); + } + } + } + } + if (sml_globs.sml_logindex > 2) { + sml_globs.log_data[sml_globs.sml_logindex] = 0; + AddLogData(LOG_LEVEL_INFO, sml_globs.log_data); + } + return; + } +#endif + + if (sml_globs.dump2log & 8) { // combo mode while (SML_SAVAILABLE) { - log_data[index] = ':'; + sml_globs.log_data[index] = ':'; index++; - log_data[index] = ' '; + sml_globs.log_data[index] = ' '; index++; d_lastms = millis(); while ((millis() - d_lastms) < 40) { if (SML_SAVAILABLE) { uint8_t c = SML_SREAD; - sprintf(&log_data[index], "%02x ", c); + sprintf(&sml_globs.log_data[index], "%02x ", c); dchars[hcnt] = c; index += 3; hcnt++; if (hcnt > 15) { // line complete, build asci chars - log_data[index] = '='; + sml_globs.log_data[index] = '='; index++; - log_data[index] = '>'; + sml_globs.log_data[index] = '>'; index++; - log_data[index] = ' '; + sml_globs.log_data[index] = ' '; index++; for (uint8_t ccnt = 0; ccnt < 16; ccnt++) { if (isprint(dchars[ccnt])) { - log_data[index] = dchars[ccnt]; + sml_globs.log_data[index] = dchars[ccnt]; } else { - log_data[index] = ' '; + sml_globs.log_data[index] = ' '; } index++; } @@ -1159,8 +674,8 @@ void Dump2log(void) { } } if (index > 0) { - log_data[index] = 0; - AddLogData(LOG_LEVEL_INFO, log_data); + sml_globs.log_data[index] = 0; + AddLogData(LOG_LEVEL_INFO, sml_globs.log_data); index = 0; hcnt = 0; } @@ -1171,18 +686,18 @@ void Dump2log(void) { while (SML_SAVAILABLE) { char c = SML_SREAD&0x7f; if (c == '\n' || c == '\r') { - if (sml_logindex > 2) { - log_data[sml_logindex] = 0; - AddLogData(LOG_LEVEL_INFO, log_data); - log_data[0] = ':'; - log_data[1] = ' '; - sml_logindex = 2; + if (sml_globs.sml_logindex > 2) { + sml_globs.log_data[sml_globs.sml_logindex] = 0; + AddLogData(LOG_LEVEL_INFO, sml_globs.log_data); + sml_globs.log_data[0] = ':'; + sml_globs.log_data[1] = ' '; + sml_globs.sml_logindex = 2; } continue; } - log_data[sml_logindex] = c; - if (sml_logindex < sizeof(log_data) - 2) { - sml_logindex++; + sml_globs.log_data[sml_globs.sml_logindex] = c; + if (sml_globs.sml_logindex < SML_DUMP_SIZE - 2) { + sml_globs.sml_logindex++; } } } else if (type == 'v') { @@ -1191,15 +706,15 @@ void Dump2log(void) { while (SML_SAVAILABLE) { c = SML_SREAD; if (c == VBUS_SYNC) { - log_data[sml_logindex] = 0; - AddLogData(LOG_LEVEL_INFO, log_data); - log_data[0] = ':'; - log_data[1] = ' '; - sml_logindex = 2; + sml_globs.log_data[sml_globs.sml_logindex] = 0; + AddLogData(LOG_LEVEL_INFO, sml_globs.log_data); + sml_globs.log_data[0] = ':'; + sml_globs.log_data[1] = ' '; + sml_globs.sml_logindex = 2; } - sprintf(&log_data[sml_logindex], "%02x ", c); - if (sml_logindex < sizeof(log_data) - 7) { - sml_logindex += 3; + sprintf(&sml_globs.log_data[sml_globs.sml_logindex], "%02x ", c); + if (sml_globs.sml_logindex < SML_DUMP_SIZE - 7) { + sml_globs.sml_logindex += 3; } } } else if (type == 'e') { @@ -1209,18 +724,18 @@ void Dump2log(void) { c = SML_SREAD; if (c == EBUS_SYNC) { p = SML_SPEAK; - if (p != EBUS_SYNC && sml_logindex > 5) { + if (p != EBUS_SYNC && sml_globs.sml_logindex > 5) { // new packet, plot last one - log_data[sml_logindex] = 0; - AddLogData(LOG_LEVEL_INFO, log_data); - strcpy(&log_data[0], ": aa "); - sml_logindex = 5; + sml_globs.log_data[sml_globs.sml_logindex] = 0; + AddLogData(LOG_LEVEL_INFO, sml_globs.log_data); + strcpy(&sml_globs.log_data[0], ": aa "); + sml_globs.sml_logindex = 5; } continue; } - sprintf(&log_data[sml_logindex], "%02x ", c); - if (sml_logindex < sizeof(log_data) - 7) { - sml_logindex += 3; + sprintf(&sml_globs.log_data[sml_globs.sml_logindex], "%02x ", c); + if (sml_globs.sml_logindex < SML_DUMP_SIZE - 7) { + sml_globs.sml_logindex += 3; } } } else if (type == 's') { @@ -1229,32 +744,34 @@ void Dump2log(void) { while (SML_SAVAILABLE) { c = SML_SREAD; if (c == SML_SYNC) { - log_data[sml_logindex] = 0; - AddLogData(LOG_LEVEL_INFO, log_data); - log_data[0] = ':'; - log_data[1] = ' '; - sml_logindex = 2; + sml_globs.log_data[0] = ':'; + sml_globs.log_data[1] = ' '; + sml_globs.sml_logindex = 2; } - sprintf(&log_data[sml_logindex], "%02x ", c); - if (sml_logindex < sizeof(log_data) - 7) { - sml_logindex += 3; + sprintf(&sml_globs.log_data[sml_globs.sml_logindex], "%02x ", c); + if (sml_globs.sml_logindex < SML_DUMP_SIZE - 7) { + sml_globs.sml_logindex += 3; } } } else { // raw dump d_lastms = millis(); - log_data[0] = ':'; - log_data[1] = ' '; - sml_logindex = 2; + sml_globs.log_data[0] = ':'; + sml_globs.log_data[1] = ' '; + sml_globs.sml_logindex = 2; while ((millis() - d_lastms) < 40) { while (SML_SAVAILABLE) { - sprintf(&log_data[sml_logindex], "%02x ", SML_SREAD); - sml_logindex += 3; + sprintf(&sml_globs.log_data[sml_globs.sml_logindex], "%02x ", SML_SREAD); + if (sml_globs.sml_logindex < SML_DUMP_SIZE - 7) { + sml_globs.sml_logindex += 3; + } else { + break; + } } } - if (sml_logindex > 2) { - log_data[sml_logindex] = 0; - AddLogData(LOG_LEVEL_INFO, log_data); + if (sml_globs.sml_logindex > 2) { + sml_globs.log_data[sml_globs.sml_logindex] = 0; + AddLogData(LOG_LEVEL_INFO, sml_globs.log_data); } } } @@ -1272,10 +789,8 @@ void Hexdump(uint8_t *sbuff, uint32_t slen) { AddLogData(LOG_LEVEL_INFO, cbuff); } -#if defined(ED300L) || defined(AS2020) || defined(DTZ541) || defined(USE_SML_SPECOPT) -uint8_t sml_status[MAX_METERS]; -uint8_t g_mindex; -#endif +#define DOUBLE2CHAR dtostrfd + // skip sml entries uint8_t *skip_sml(uint8_t *cp,int16_t *res) { @@ -1301,7 +816,7 @@ uint8_t *skip_sml(uint8_t *cp,int16_t *res) { // get sml binary value // not defined for unsigned >0x7fff ffff ffff ffff (should never happen) -double sml_getvalue(unsigned char *cp,uint8_t index) { +double sml_getvalue(unsigned char *cp, uint8_t index) { uint8_t len,unit,type; int16_t scaler,result; int64_t value; @@ -1313,173 +828,173 @@ double dval; unsigned char *cpx=cp-5; // decode OBIS 0180 amd extract direction info if (*cp==0x64 && *cpx==0 && *(cpx+1)==0x01 && *(cpx+2)==0x08 && *(cpx+3)==0) { - sml_status[g_mindex]=*(cp+3); + sml_globs.sml_status[sml_globs.g_mindex]=*(cp+3); } if (*cp==0x63 && *cpx==0 && *(cpx+1)==0x01 && *(cpx+2)==0x08 && *(cpx+3)==0) { - sml_status[g_mindex]=*(cp+2); + sml_globs.sml_status[sml_globs.g_mindex]=*(cp+2); } #endif #ifdef AS2020 unsigned char *cpx=cp-5; // decode OBIS 0180 amd extract direction info if (*cp==0x64 && *cpx==0 && *(cpx+1)==0x01 && *(cpx+2)==0x08 && *(cpx+3)==0) { - sml_status[g_mindex]=*(cp+2); + sml_globs.sml_status[sml_globs.g_mindex]=*(cp+2); } if (*cp==0x63 && *cpx==0 && *(cpx+1)==0x01 && *(cpx+2)==0x08 && *(cpx+3)==0) { - sml_status[g_mindex]=*(cp+1); + sml_globs.sml_status[sml_globs.g_mindex]=*(cp+1); } #endif #ifdef DTZ541 unsigned char *cpx=cp-5; // decode OBIS 0180 amd extract direction info if (*cp==0x65 && *cpx==0 && *(cpx+1)==0x01 && *(cpx+2)==0x08 && *(cpx+3)==0) { - sml_status[g_mindex]=*(cp+3); + sml_globs.sml_status[sml_globs.g_mindex]=*(cp+3); } #endif #ifdef USE_SML_SPECOPT unsigned char *cpx = cp - 5; - uint32_t ocode = (*(cpx+0)<<24) | (*(cpx+1)<<16) | (*(cpx+2)<<8) | (*(cpx+3)<<0); + uint32_t ocode = (*(cpx + 0) << 24) | (*(cpx + 1) << 16) | (*(cpx + 2) << 8) | (*(cpx + 3) << 0); - if (ocode == script_meter_desc[g_mindex].so_obis1) { - sml_status[g_mindex]&=0xfe; + if (ocode == meter_desc[sml_globs.g_mindex].so_obis1) { + sml_globs.sml_status[sml_globs.g_mindex] &= 0xfe; uint32_t flag = 0; uint16_t bytes = 0; - if (*cp == script_meter_desc[g_mindex].so_fcode1) { + if (*cp == meter_desc[sml_globs.g_mindex].so_fcode1) { cpx = cp + 1; - bytes = (script_meter_desc[g_mindex].so_fcode1 & 0xf) - 1; + bytes = (meter_desc[sml_globs.g_mindex].so_fcode1 & 0xf) - 1; for (uint16_t cnt = 0; cnt < bytes; cnt++) { flag <<= 8; flag |= *cpx++; } - if (flag & (1 << script_meter_desc[g_mindex].so_bpos1)) { - sml_status[g_mindex]|=1; + if (flag & (1 << meter_desc[sml_globs.g_mindex].so_bpos1)) { + sml_globs.sml_status[sml_globs.g_mindex] |= 1; } } - if (*cp == script_meter_desc[g_mindex].so_fcode2) { + if (*cp == meter_desc[sml_globs.g_mindex].so_fcode2) { cpx = cp + 1; - bytes = (script_meter_desc[g_mindex].so_fcode2 & 0xf) - 1; + bytes = (meter_desc[sml_globs.g_mindex].so_fcode2 & 0xf) - 1; for (uint16_t cnt = 0; cnt < bytes; cnt++) { flag <<= 8; flag |= *cpx++; } - if (flag & (1 << script_meter_desc[g_mindex].so_bpos1)) { - sml_status[g_mindex]|=1; + if (flag & (1 << meter_desc[sml_globs.g_mindex].so_bpos1)) { + sml_globs.sml_status[sml_globs.g_mindex] |= 1; } } } #endif - cp=skip_sml(cp,&result); + cp = skip_sml(cp, &result); // check time - cp=skip_sml(cp,&result); + cp = skip_sml(cp, &result); // check unit - cp=skip_sml(cp,&result); + cp = skip_sml(cp, &result); // check scaler - cp=skip_sml(cp,&result); - scaler=result; + cp = skip_sml(cp, &result); + scaler = result; // get value - type=*cp&0x70; - len=*cp&0x0f; + type = *cp & 0x70; + len = *cp & 0x0f; cp++; - if (type==0x50 || type==0x60) { + if (type == 0x50 || type == 0x60) { // shift into 64 bit - uint64_t uvalue=0; - uint8_t nlen=len; + uint64_t uvalue = 0; + uint8_t nlen = len; while (--nlen) { - uvalue<<=8; - uvalue|=*cp++; + uvalue <<= 8; + uvalue |= *cp++; } - if (type==0x50) { + if (type == 0x50) { // signed - switch (len-1) { + switch (len - 1) { case 1: // byte - value=(signed char)uvalue; + value = (signed char)uvalue; break; case 2: // signed 16 bit -#ifdef DWS74_BUG - if (scaler==-2) { - value=(uint32_t)uvalue; + if (meter_desc[index].so_flags & SO_DWS74_BUG) { + if (scaler == -2) { + value = (uint32_t)uvalue; + } else { + value = (int16_t)uvalue; + } } else { - value=(int16_t)uvalue; + value = (int16_t)uvalue; } -#else - value=(int16_t)uvalue; -#endif break; case 3: // signed 24 bit - value=(int32_t)(uvalue<<8); - value/=256; + value = (int32_t)(uvalue << 8); + value /= 256; break; case 4: // signed 32 bit - value=(int32_t)uvalue; + value = (int32_t)uvalue; break; case 5: case 6: case 7: case 8: // signed 64 bit - value=(int64_t)uvalue; + value = (int64_t)uvalue; break; } } else { // unsigned - value=uvalue; + value = uvalue; } } else { - if (!(type&0xf0)) { + if (!(type & 0xf0)) { // octet string serial number // no coding found on the net // up to now 2 types identified on Hager - if (len==9) { + if (len == 9) { // serial number on hager => 24 bit - 24 bit cp++; uint32_t s1,s2; - s1=*cp<<16|*(cp+1)<<8|*(cp+2); - cp+=4; - s2=*cp<<16|*(cp+1)<<8|*(cp+2); - sprintf(&meter_id[index][0],"%u-%u",s1,s2); + s1 = *cp << 16 | *(cp + 1) <<8 | *(cp + 2); + cp += 4; + s2 = *cp << 16 | *(cp + 1) <<8 | *(cp + 2); + sprintf(&meter_desc[index].meter_id[0], "%u-%u", s1, s2); } else { // server id on hager - char *str=&meter_id[index][0]; - for (type=0; typeavailable()) { - meter_ss[meters]->read(); + while (meter_desc[meters].meter_ss->available()) { + meter_desc[meters].meter_ss->read(); } } - -void sml_shift_in(uint32_t meters,uint32_t shard) { +void sml_shift_in(uint32_t meters, uint32_t shard) { uint32_t count; -#ifdef SML_OBIS_LINE - sml_options |= SML_OPTIONS_OBIS_LINE; + struct METER_DESC *mp = &meter_desc[meters]; + + if (!mp->sbuff) return; + +#ifdef USE_SML_DECRYPT + if (mp->use_crypt) { + uint8_t iob = (uint8_t)mp->meter_ss->read(); + if (mp->spos < mp->sbsiz) { + mp->sbuff[mp->spos] = iob; + } + mp->spos++; + + if (iob == SML_CRYPT_SYNC2 && mp->last_iob == SML_CRYPT_SYNC1) { + // frame start + mp->spos = 2; + mp->sbuff[0] = SML_CRYPT_SYNC1; + mp->sbuff[1] = SML_CRYPT_SYNC2; + } + mp->last_iob = iob; + + uint16_t logsiz; + uint8_t *db = hdlc_decode(mp->sbuff, mp->spos, mp->key, &logsiz); + if (db) { + // we decoded a valid frame + memmove(mp->sbuff, db, logsiz); + AddLog(LOG_LEVEL_INFO, PSTR(">> decrypted block: %d bytes"), logsiz); + SML_Decode(meters); + } + return; + } #endif - bool shift; - if (!(sml_options & SML_OPTIONS_OBIS_LINE)) { - shift = (meter_desc_p[meters].type != 'e' && meter_desc_p[meters].type != 'k' && meter_desc_p[meters].type != 'm' && meter_desc_p[meters].type != 'M' && meter_desc_p[meters].type != 'p' && meter_desc_p[meters].type != 'R' && meter_desc_p[meters].type != 'v'); - } else { - shift = (meter_desc_p[meters].type != 'o' && meter_desc_p[meters].type != 'e' && meter_desc_p[meters].type != 'k' && meter_desc_p[meters].type != 'm' && meter_desc_p[meters].type != 'M' && meter_desc_p[meters].type != 'p' && meter_desc_p[meters].type != 'R' && meter_desc_p[meters].type != 'v'); - } - - if (shift) { + if (mp->shift_mode) { // shift in - for (count = 0; count < SML_BSIZ - 1; count++) { - smltbuf[meters][count] = smltbuf[meters][count + 1]; + for (count = 0; count < mp->sbsiz - 1; count++) { + mp->sbuff[count] = mp->sbuff[count + 1]; } } - uint8_t iob = (uint8_t)meter_ss[meters]->read(); + uint8_t iob = (uint8_t)mp->meter_ss->read(); - if (meter_desc_p[meters].type == 'o') { - if (!(sml_options & SML_OPTIONS_OBIS_LINE)) { - smltbuf[meters][SML_BSIZ-1] = iob & 0x7f; - } else { - iob &= 0x7f; - smltbuf[meters][meter_spos[meters]] = iob; - meter_spos[meters]++; - if (meter_spos[meters] >= SML_BSIZ) { - meter_spos[meters] = 0; + switch (mp->type) { + case 'o': + // asci obis + if (!(mp->so_flags & SO_OBIS_LINE)) { + mp->sbuff[mp->sbsiz - 1] = iob & 0x7f; + } else { + iob &= 0x7f; + mp->sbuff[mp->spos] = iob; + mp->spos++; + if (mp->spos >= mp->sbsiz) { + mp->spos = 0; + } + if ((iob == 0x0a) || (iob == 0x0d)) { + SML_Decode(meters); + mp->spos = 0; + } } - if ((iob == 0x0a) || (iob == 0x0d)) { - SML_Decode(meters); - meter_spos[meters] = 0; + break; + case 's': + // binary obis = sml + mp->sbuff[mp->sbsiz - 1] = iob; + break; + case 'r': + // raw with shift + mp->sbuff[mp->sbsiz - 1] = iob; + break; + case 'R': + // raw without shift + mp->sbuff[mp->spos] = iob; + mp->spos++; + if (mp->spos > mp->sbsiz) { + mp->spos = 0; } - } - } else if (meter_desc_p[meters].type=='s') { - smltbuf[meters][SML_BSIZ-1]=iob; - } else if (meter_desc_p[meters].type=='r') { - smltbuf[meters][SML_BSIZ-1]=iob; - } else if (meter_desc_p[meters].type=='m' || meter_desc_p[meters].type=='M' || meter_desc_p[meters].type=='k') { - - if (meter_desc_p[meters].type=='k') { + break; + case 'k': // Kamstrup if (iob == 0x40) { - meter_spos[meters] = 0; + mp->spos = 0; } else if (iob == 0x0d) { uint8_t index = 0; - uint8_t *ucp = &smltbuf[meters][0]; - for (uint16_t cnt = 0; cnt < meter_spos[meters]; cnt++) { - uint8_t iob = smltbuf[meters][cnt]; + uint8_t *ucp = &mp->sbuff[0]; + for (uint16_t cnt = 0; cnt < mp->spos; cnt++) { + uint8_t iob = mp->sbuff[cnt] ; if (iob == 0x1b) { - *ucp++ = smltbuf[meters][cnt + 1] ^ 0xff; + *ucp++ = mp->sbuff[cnt + 1] ^ 0xff; cnt++; } else { *ucp++ = iob; } index++; } - uint16_t crc = KS_calculateCRC(&smltbuf[meters][0],index); + uint16_t crc = KS_calculateCRC(&mp->sbuff[0], index); if (!crc) { SML_Decode(meters); } sml_empty_receiver(meters); - meter_spos[meters] = 0; + mp->spos = 0; } else { - smltbuf[meters][meter_spos[meters]] = iob; - meter_spos[meters]++; - if (meter_spos[meters] >= SML_BSIZ) { - meter_spos[meters] = 0; + mp->sbuff[mp->spos] = iob; + mp->spos++; + if (mp->spos >= mp->sbsiz) { + mp->spos = 0; } } - } else { - smltbuf[meters][meter_spos[meters]] = iob; - meter_spos[meters]++; - if (meter_spos[meters] >= SML_BSIZ) { - meter_spos[meters] = 0; - } + break; + case 'm': + case 'M': // modbus - if (meter_spos[meters] >= 3) { - uint32_t mlen = smltbuf[meters][2] + 5; - if (mlen > SML_BSIZ) mlen = SML_BSIZ; - if (meter_spos[meters] >= mlen) { + mp->sbuff[mp->spos] = iob; + mp->spos++; + if (mp->spos >= mp->sbsiz) { + mp->spos = 0; + } + if (mp->spos >= 3) { + uint32_t mlen = mp->sbuff[2] + 5; + if (mlen > mp->sbsiz) mlen = mp->sbsiz; + if (mp->spos >= mlen) { #ifdef MODBUS_DEBUG - AddLog(LOG_LEVEL_INFO, PSTR("receive index >> %d"),meter_desc_p[meters].index); - Hexdump(smltbuf[meters], 10); + AddLog(LOG_LEVEL_INFO, PSTR("receive index >> %d"), mp->index); + Hexdump(mp->sbuff, 10); #endif SML_Decode(meters); sml_empty_receiver(meters); - meter_spos[meters] = 0; + mp->spos = 0; } } - } - } else if (meter_desc_p[meters].type == 'p') { - smltbuf[meters][meter_spos[meters]] = iob; - meter_spos[meters]++; - if (meter_spos[meters] >= 7) { - SML_Decode(meters); - sml_empty_receiver(meters); - meter_spos[meters] = 0; - } - } else if (meter_desc_p[meters].type == 'R') { - smltbuf[meters][meter_spos[meters]] = iob; - meter_spos[meters]++; - if (meter_spos[meters] >= SML_BSIZ) { - meter_spos[meters] = 0; - } - } else if (meter_desc_p[meters].type == 'v') { - if (iob == EBUS_SYNC) { - sb_counter = 0; - SML_Decode(meters); - smltbuf[meters][0] = iob; - meter_spos[meters] = 1; - } else { - if (meter_spos[meters] < SML_BSIZ) { - smltbuf[meters][meter_spos[meters]] = iob; - meter_spos[meters]++; + break; + case 'p': + // pzem + mp->sbuff[mp->spos] = iob; + mp->spos++; + if (mp->spos >= 7) { + SML_Decode(meters); + sml_empty_receiver(meters); + mp->spos = 0; } - } - } - else { - if (iob == EBUS_SYNC) { - // should be end of telegramm - // QQ,ZZ,PB,SB,NN ..... CRC, ACK SYNC - if (meter_spos[meters] > 4 + 5) { - // get telegramm lenght - uint16_t tlen = smltbuf[meters][4] + 5; - // test crc - if (smltbuf[meters][tlen] = ebus_CalculateCRC(smltbuf[meters], tlen)) { - ebus_esc(smltbuf[meters], tlen); - SML_Decode(meters); - } else { - // crc error - //AddLog(LOG_LEVEL_INFO, PSTR("ebus crc error")); + break; + case 'v': + // vbus + if (iob == EBUS_SYNC) { + sb_counter = 0; + SML_Decode(meters); + mp->sbuff[0] = iob; + mp->spos = 1; + } else { + if (mp->spos < mp->sbsiz) { + mp->sbuff[mp->spos] = iob; + mp->spos++; } } - meter_spos[meters] = 0; - return; - } - smltbuf[meters][meter_spos[meters]] = iob; - meter_spos[meters]++; - if (meter_spos[meters] >= SML_BSIZ) { - meter_spos[meters] = 0; - } + break; + case 'e': + // ebus + if (iob == EBUS_SYNC) { + // should be end of telegramm + // QQ,ZZ,PB,SB,NN ..... CRC, ACK SYNC + if (mp->spos > 4 + 5) { + // get telegramm lenght + uint16_t tlen = mp->sbuff[4] + 5; + // test crc + if (mp->sbuff[tlen] = ebus_CalculateCRC(mp->sbuff, tlen)) { + ebus_esc(mp->sbuff, tlen); + SML_Decode(meters); + } else { + // crc error + //AddLog(LOG_LEVEL_INFO, PSTR("ebus crc error")); + } + } + mp->spos = 0; + return; + } + mp->sbuff[mp->spos] = iob; + mp->spos++; + if (mp->spos >= mp->sbsiz) { + mp->spos = 0; + } + break; } sb_counter++; - if (shift) { + if (mp->shift_mode) { SML_Decode(meters); } } @@ -1782,14 +1331,14 @@ void sml_shift_in(uint32_t meters,uint32_t shard) { void SML_Poll(void) { uint32_t meters; - for (meters = 0; meters < meters_used; meters++) { - if (meter_desc_p[meters].type != 'c') { + for (meters = 0; meters < sml_globs.meters_used; meters++) { + if (sml_globs.mp[meters].type != 'c') { // poll for serial input - if (!meter_ss[meters]) continue; - if (ser_act_LED_pin != 255 && (ser_act_meter_num == 0 || ser_act_meter_num - 1 == meters)) { - digitalWrite(ser_act_LED_pin, meter_ss[meters]->available() && !digitalRead(ser_act_LED_pin)); // Invert LED, if queue is continuously full + if (!meter_desc[meters].meter_ss) continue; + if (sml_globs.ser_act_LED_pin != 255 && (sml_globs.ser_act_meter_num == 0 || sml_globs.ser_act_meter_num - 1 == meters)) { + digitalWrite(sml_globs.ser_act_LED_pin, meter_desc[meters].meter_ss->available() && !digitalRead(sml_globs.ser_act_LED_pin)); // Invert LED, if queue is continuously full } - while (meter_ss[meters]->available()) { + while (meter_desc[meters].meter_ss->available()) { sml_shift_in(meters, 0); } } @@ -1842,12 +1391,16 @@ char *skip_double(char *cp) { void SML_Decode(uint8_t index) { - const char *mp=(const char*)meter_p; + const char *mp = (const char*)sml_globs.meter_p; int8_t mindex; uint8_t *cp; uint8_t dindex = 0, vindex = 0; delay(0); + if (!sml_globs.ready) { + return; + } + while (mp != NULL) { // check list of defines if (*mp == 0) break; @@ -1855,7 +1408,7 @@ void SML_Decode(uint8_t index) { // new section mindex = ((*mp) & 7) - 1; - if (mindex < 0 || mindex >= meters_used) mindex = 0; + if (mindex < 0 || mindex >= sml_globs.meters_used) mindex = 0; mp += 2; if (*mp == '=' && *(mp+1) == 'h') { mp = strchr(mp, '|'); @@ -1876,10 +1429,10 @@ void SML_Decode(uint8_t index) { } } - if (index!=mindex) goto nextsect; + if (index != mindex) goto nextsect; // start of serial source buffer - cp = &smltbuf[mindex][0]; + cp = meter_desc[mindex].sbuff; // compare if (*mp == '=') { @@ -1897,13 +1450,13 @@ void SML_Decode(uint8_t index) { uint8_t mind; int32_t ind; mind = strtol((char*)mp, (char**)&mp, 10); - if (mind < 1 || mind > SML_MAX_VARS) mind = 1; - dvar = meter_vars[mind - 1]; + if (mind < 1 || mind > sml_globs.maxvars) mind = 1; + dvar = sml_globs.meter_vars[mind - 1]; while (*mp==' ') mp++; for (uint8_t p = 0; p < 8; p++) { if (*mp == '@') { // store result - meter_vars[vindex] = dvar; + sml_globs.meter_vars[vindex] = dvar; mp++; break; } @@ -1916,37 +1469,37 @@ void SML_Decode(uint8_t index) { } ind = strtol((char*)mp, (char**)&mp, 10); mind = ind; - if (mind < 1 || mind > SML_MAX_VARS) mind = 1; + if (mind < 1 || mind > sml_globs.maxvars) mind = 1; switch (opr) { case '+': if (iflg) dvar += ind; - else dvar += meter_vars[mind - 1]; + else dvar += sml_globs.meter_vars[mind - 1]; break; case '-': if (iflg) dvar -= ind; - else dvar -= meter_vars[mind - 1]; + else dvar -= sml_globs.meter_vars[mind - 1]; break; case '*': if (iflg) dvar *= ind; - else dvar *= meter_vars[mind - 1]; + else dvar *= sml_globs.meter_vars[mind - 1]; break; case '/': if (iflg) dvar /= ind; - else dvar /= meter_vars[mind - 1]; + else dvar /= sml_globs.meter_vars[mind - 1]; break; } while (*mp==' ') mp++; if (*mp == '@') { // store result - meter_vars[vindex] = dvar; + sml_globs.meter_vars[vindex] = dvar; mp++; break; } } double fac = CharToDouble((char*)mp); - meter_vars[vindex] /= fac; + sml_globs.meter_vars[vindex] /= fac; SML_Immediate_MQTT((const char*)mp, vindex, mindex); - dvalid[vindex] = 1; + sml_globs.dvalid[vindex] = 1; // get sfac } else if (*mp=='d') { // calc deltas d ind 10 (eg every 10 secs) @@ -1956,40 +1509,40 @@ void SML_Decode(uint8_t index) { while (*mp == ' ') mp++; uint8_t ind = atoi(mp); while (*mp >= '0' && *mp <= '9') mp++; - if (ind < 1 || ind > SML_MAX_VARS) ind = 1; + if (ind < 1 || ind > sml_globs.maxvars) ind = 1; uint32_t delay = atoi(mp) * 1000; - uint32_t dtime = millis() - dtimes[dindex]; + uint32_t dtime = millis() - sml_globs.dtimes[dindex]; if (dtime > delay) { // calc difference - dtimes[dindex] = millis(); - double vdiff = meter_vars[ind - 1] - dvalues[dindex]; - dvalues[dindex] = meter_vars[ind - 1]; + sml_globs.dtimes[dindex] = millis(); + double vdiff = sml_globs.meter_vars[ind - 1] - sml_globs.dvalues[dindex]; + sml_globs.dvalues[dindex] = sml_globs.meter_vars[ind - 1]; double dres = (double)360000.0 * vdiff / ((double)dtime / 10000.0); - dvalid[vindex] += 1; + sml_globs.dvalid[vindex] += 1; - if (dvalid[vindex] >= 2) { + if (sml_globs.dvalid[vindex] >= 2) { // differece is only valid after 2. calculation - dvalid[vindex] = 2; + sml_globs.dvalid[vindex] = 2; #ifdef USE_SML_MEDIAN_FILTER - if (meter_desc_p[mindex].flag & 16) { - meter_vars[vindex] = sml_median(&sml_mf[vindex], dres); + if (sml_globs.mp[mindex].flag & 16) { + sml_globs.meter_vars[vindex] = sml_median(&sml_globs.sml_mf[vindex], dres); } else { - meter_vars[vindex] = dres; + sml_globs.meter_vars[vindex] = dres; } #else - meter_vars[vindex] = dres; + sml_globs.meter_vars[vindex] = dres; #endif } mp=strchr(mp,'@'); if (mp) { mp++; double fac = CharToDouble((char*)mp); - meter_vars[vindex] /= fac; + sml_globs.meter_vars[vindex] /= fac; SML_Immediate_MQTT((const char*)mp, vindex, mindex); } } - //dvalid[vindex] = 1; + //sml_globs.dvalid[vindex] = 1; dindex++; } } else if (*mp == 'h') { @@ -2009,12 +1562,12 @@ void SML_Decode(uint8_t index) { double ebus_dval = 99; double mbus_dval = 99; while (*mp != '@') { - if (meter_desc_p[mindex].type == 'o' || meter_desc_p[mindex].type == 'c') { + if (sml_globs.mp[mindex].type == 'o' || sml_globs.mp[mindex].type == 'c') { if (*mp++ != *cp++) { found=0; } } else { - if (meter_desc_p[mindex].type == 's') { + if (sml_globs.mp[mindex].type == 's') { // sml uint8_t val = hexnibble(*mp++) << 4; val |= hexnibble(*mp++); @@ -2272,7 +1825,7 @@ void SML_Decode(uint8_t index) { } else { time = vbus_get_septet(cp) & 0xffff; } - sprintf(&meter_id[mindex][0], "%02d:%02d", time / 60, time % 60); + sprintf(&meter_desc[index].meter_id[0], "%02d:%02d", time / 60, time % 60); } break; } @@ -2281,8 +1834,8 @@ void SML_Decode(uint8_t index) { else { uint8_t val = hexnibble(*mp++) << 4; val |= hexnibble(*mp++); - if (val!=*cp++) { - found=0; + if (val != *cp++) { + found = 0; } } } @@ -2290,42 +1843,44 @@ void SML_Decode(uint8_t index) { } if (found) { // matches, get value - dvalid[vindex] = 1; + sml_globs.dvalid[vindex] = 1; mp++; #if defined(ED300L) || defined(AS2020) || defined(DTZ541) || defined(USE_SML_SPECOPT) - g_mindex = mindex; + sml_globs.g_mindex = mindex; #endif if (*mp == '#') { // get string value getstr: mp++; - if (meter_desc_p[mindex].type != 'v') { - if (meter_desc_p[mindex].type == 'o') { + if (sml_globs.mp[mindex].type != 'v') { + if (sml_globs.mp[mindex].type == 'o') { uint32_t p; for (p = 0; p < METER_ID_SIZE - 2; p++) { if (*cp == *mp) { break; } - meter_id[mindex][p] = *cp++; + meter_desc[mindex].meter_id[p] = *cp++; } - meter_id[mindex][p] = 0; - } else if (meter_desc_p[mindex].type == 'k') { + meter_desc[mindex].meter_id[p] = 0; + + } else if (sml_globs.mp[mindex].type == 'k') { // 220901 uint32_t date = mbus_dval; uint8_t year = date / 10000; // = 22 date -= year * 10000; uint8_t month = date / 100; // = 09 uint8_t day = date % 100; // = 01 - sprintf(&meter_id[mindex][0],"%02d.%02d.%02d",day, month, year); + sprintf(&meter_desc[mindex].meter_id[0],"%02d.%02d.%02d",day, month, year); } else { - sml_getvalue(cp,mindex); + sml_getvalue(cp, mindex); } } } else { double dval; - if (meter_desc_p[mindex].type!='e' && meter_desc_p[mindex].type!='r' && meter_desc_p[mindex].type!='m' && meter_desc_p[mindex].type!='M' && meter_desc_p[mindex].type!='k' && meter_desc_p[mindex].type!='p' && meter_desc_p[mindex].type!='v') { + char type = sml_globs.mp[mindex].type; + if (type != 'e' && type != 'r' && type != 'm' && type != 'M' && type != 'k' && type != 'p' && type != 'v') { // get numeric values - if (meter_desc_p[mindex].type=='o' || meter_desc_p[mindex].type=='c') { + if (type == 'o' || type == 'c') { if (*mp == '(') { mp++; // skip this number of brackets @@ -2343,51 +1898,51 @@ void SML_Decode(uint8_t index) { lcp = bp; } } - if (*mp=='#') { + if (*mp == '#') { cp = (uint8_t*)lcp; goto getstr; } - dval=CharToDouble((char*)lcp); + dval = CharToDouble((char*)lcp); } else { - dval=CharToDouble((char*)cp); + dval = CharToDouble((char*)cp); } } else { - dval = sml_getvalue(cp,mindex); + dval = sml_getvalue(cp, mindex); } } else { // ebus pzem vbus or mbus or raw if (*mp == 'b') { mp++; uint8_t shift = *mp&7; - ebus_dval = (uint32_t)ebus_dval>>shift; - ebus_dval = (uint32_t)ebus_dval&1; + ebus_dval = (uint32_t)ebus_dval >> shift; + ebus_dval = (uint32_t)ebus_dval & 1; mp+=2; } if (*mp == 'i') { // mbus index mp++; uint8_t mb_index = strtol((char*)mp, (char**)&mp, 10); - if (mb_index != meter_desc_p[mindex].index) { + if (mb_index != sml_globs.mp[mindex].index) { goto nextsect; } - if (meter_desc_p[mindex].type == 'k') { + if (sml_globs.mp[mindex].type == 'k') { // crc is already checked, get float value dval = mbus_dval; mp++; } else { - uint16_t pos = smltbuf[mindex][2] + 3; - if (pos > (SML_BSIZ-2)) pos = SML_BSIZ-2; - uint16_t crc = MBUS_calculateCRC(&smltbuf[mindex][0], pos, 0xFFFF); - if (lowByte(crc) != smltbuf[mindex][pos]) goto nextsect; - if (highByte(crc) != smltbuf[mindex][pos + 1]) goto nextsect; + uint16_t pos = meter_desc[mindex].sbuff[2] + 3; + if (pos > (meter_desc[mindex].sbsiz - 2)) pos = meter_desc[mindex].sbsiz - 2; + uint16_t crc = MBUS_calculateCRC(&meter_desc[mindex].sbuff[0], pos, 0xFFFF); + if (lowByte(crc) != meter_desc[mindex].sbuff[pos]) goto nextsect; + if (highByte(crc) != meter_desc[mindex].sbuff[pos + 1]) goto nextsect; dval = mbus_dval; //AddLog(LOG_LEVEL_INFO, PSTR(">> %s"),mp); mp++; } } else { - if (meter_desc_p[mindex].type == 'p') { - uint8_t crc = SML_PzemCrc(&smltbuf[mindex][0],6); - if (crc != smltbuf[mindex][6]) goto nextsect; + if (sml_globs.mp[mindex].type == 'p') { + uint8_t crc = SML_PzemCrc(&meter_desc[mindex].sbuff[0],6); + if (crc != meter_desc[mindex].sbuff[6]) goto nextsect; dval = mbus_dval; } else { dval = ebus_dval; @@ -2396,13 +1951,13 @@ void SML_Decode(uint8_t index) { } #ifdef USE_SML_MEDIAN_FILTER - if (meter_desc_p[mindex].flag & 16) { - meter_vars[vindex] = sml_median(&sml_mf[vindex], dval); + if (sml_globs.mp[mindex].flag & 16) { + sml_globs.meter_vars[vindex] = sml_median(&sml_globs.sml_mf[vindex], dval); } else { - meter_vars[vindex] = dval; + sml_globs.meter_vars[vindex] = dval; } #else - meter_vars[vindex] = dval; + sml_globs.meter_vars[vindex] = dval; #endif //AddLog(LOG_LEVEL_INFO, PSTR(">> %s"),mp); @@ -2412,9 +1967,9 @@ void SML_Decode(uint8_t index) { char *cp = skip_double((char*)mp); if (cp && (*cp == '+' || *cp == '-')) { double offset = CharToDouble(cp); - meter_vars[vindex] += offset; + sml_globs.meter_vars[vindex] += offset; } - meter_vars[vindex] /= fac; + sml_globs.meter_vars[vindex] /= fac; SML_Immediate_MQTT((const char*)mp, vindex, mindex); } } @@ -2422,7 +1977,7 @@ void SML_Decode(uint8_t index) { } nextsect: // next section - if (vindex= meters_used) lastmind = 0; + if (lastmind < 0 || lastmind >= sml_globs.meters_used) lastmind = 0; while (mp != NULL) { if (*mp == 0) break; // setup sections mindex = ((*mp) & 7) - 1; - if (mindex < 0 || mindex >= meters_used) mindex = 0; - if (meter_desc_p[mindex].prefix[0] == '*' && meter_desc_p[mindex].prefix[1] == 0) { + if (mindex < 0 || mindex >= sml_globs.meters_used) mindex = 0; + if (sml_globs.mp[mindex].prefix[0] == '*' && sml_globs.mp[mindex].prefix[1] == 0) { nojson = 1; } else { nojson = 0; } mp += 2; - if (*mp == '=' && *(mp+1) == 'h') { + if (*mp == '=' && *(mp + 1) == 'h') { mp += 2; // html tag if (json) { @@ -2537,11 +2092,11 @@ void SML_Show(boolean json) { // convert hex to asci sml_hex_asci(mindex, tpowstr); } else { - sprintf(tpowstr,"\"%s\"", &meter_id[mindex][0]); + sprintf(tpowstr,"\"%s\"", &meter_desc[mindex].meter_id[0]); } mid = 1; } else if (*cp == '(') { - if (meter_desc_p[mindex].type == 'o') { + if (sml_globs.mp[mindex].type == 'o') { cp++; strtol((char*)cp,(char**)&cp, 10); cp++; @@ -2552,7 +2107,7 @@ void SML_Show(boolean json) { } else if (*cp == 'b') { // bit value #ifdef SML_BIT_TEXT - sprintf_P(tpowstr, PSTR("\"%s\""), (uint8_t)meter_vars[index]?D_ON:D_OFF); + sprintf_P(tpowstr, PSTR("\"%s\""), (uint8_t)sml_globs.meter_vars[index]?D_ON:D_OFF); mid = 2; #endif } else { @@ -2593,19 +2148,19 @@ void SML_Show(boolean json) { if (!mid) { uint8_t dp = atoi(cp) & 0xf; - dtostrfd(meter_vars[index], dp, tpowstr); + DOUBLE2CHAR(sml_globs.meter_vars[index], dp, tpowstr); } if (json) { - //if (dvalid[index]) { + //if (sml_globs.dvalid[index]) { //AddLog(LOG_LEVEL_INFO, PSTR("not yet valid line %d"), index); //} // json export if (index == 0) { - //snprintf_P(b_mqtt_data, sizeof(b_mqtt_data), "%s,\"%s\":{\"%s\":%s", b_mqtt_data,meter_desc_p[mindex].prefix,jname,tpowstr); + //snprintf_P(b_mqtt_data, sizeof(b_mqtt_data), "%s,\"%s\":{\"%s\":%s", b_mqtt_data,sml_globs.mp[mindex].prefix,jname,tpowstr); if (!nojson) { - ResponseAppend_P(PSTR(",\"%s\":{\"%s\":%s"), meter_desc_p[mindex].prefix, jname, tpowstr); + ResponseAppend_P(PSTR(",\"%s\":{\"%s\":%s"), sml_globs.mp[mindex].prefix, jname, tpowstr); } } else { @@ -2616,9 +2171,9 @@ void SML_Show(boolean json) { ResponseAppend_P(PSTR("}")); } // and open new - //snprintf_P(b_mqtt_data, sizeof(b_mqtt_data), "%s,\"%s\":{\"%s\":%s", b_mqtt_data,meter_desc_p[mindex].prefix,jname,tpowstr); + //snprintf_P(b_mqtt_data, sizeof(b_mqtt_data), "%s,\"%s\":{\"%s\":%s", b_mqtt_data,sml_globs.mp[mindex].prefix,jname,tpowstr); if (!nojson) { - ResponseAppend_P(PSTR(",\"%s\":{\"%s\":%s"), meter_desc_p[mindex].prefix, jname, tpowstr); + ResponseAppend_P(PSTR(",\"%s\":{\"%s\":%s"), sml_globs.mp[mindex].prefix, jname, tpowstr); } lastmind = mindex; } else { @@ -2632,11 +2187,11 @@ void SML_Show(boolean json) { } else { // web ui export //snprintf_P(b_mqtt_data, sizeof(b_mqtt_data), "%s{s}%s %s: {m}%s %s{e}", b_mqtt_data,meter_desc[mindex].prefix,name,tpowstr,unit); - if (strcmp(name, "*")) WSContentSend_PD(PSTR("{s}%s %s {m}%s %s{e}"), meter_desc_p[mindex].prefix, name,tpowstr, unit); + if (strcmp(name, "*")) WSContentSend_PD(PSTR("{s}%s %s {m}%s %s{e}"), sml_globs.mp[mindex].prefix, name,tpowstr, unit); } } } - if (index < SML_MAX_VARS - 1) { + if (index < sml_globs.maxvars - 1) { index++; } // next section @@ -2658,11 +2213,11 @@ void SML_Show(boolean json) { #ifdef USE_DOMOTICZ if (json && !TasmotaGlobal.tele_period) { char str[16]; - dtostrfd(meter_vars[0], 1, str); - DomoticzSensorPowerEnergy(meter_vars[1], str); // PowerUsage, EnergyToday - dtostrfd(meter_vars[2], 1, str); + DOUBLE2CHAR(sml_globs.meter_vars[0], 1, str); + DomoticzSensorPowerEnergy(sml_globs.meter_vars[1], str); // PowerUsage, EnergyToday + DOUBLE2CHAR(sml_globs.meter_vars[2], 1, str); DomoticzSensor(DZ_VOLTAGE, str); // Voltage - dtostrfd(meter_vars[3], 1, str); + DOUBLE2CHAR(sml_globs.meter_vars[3], 1, str); DomoticzSensor(DZ_CURRENT, str); // Current } #endif // USE_DOMOTICZ @@ -2678,26 +2233,18 @@ struct SML_COUNTER { uint32_t sml_counter_pulsewidth; uint16_t sml_debounce; uint8_t sml_cnt_updated; - -#ifdef ANALOG_OPTO_SENSOR - int16_t ana_curr; - int16_t ana_max; - int16_t ana_min; - int16_t ana_cmpl; - int16_t ana_cmph; -#endif } sml_counters[MAX_COUNTERS]; uint8_t sml_counter_pinstate; - uint8_t sml_cnt_index[MAX_COUNTERS] = { 0, 1, 2, 3 }; + void IRAM_ATTR SML_CounterIsr(void *arg) { -uint32_t index = *static_cast(arg); + uint32_t index = *static_cast(arg); -uint32_t time = millis(); -uint32_t debounce_time; + uint32_t time = millis(); + uint32_t debounce_time; - if (digitalRead(meter_desc_p[sml_counters[index].sml_cnt_old_state].srcpin) == bitRead(sml_counter_pinstate, index)) { + if (digitalRead(sml_globs.mp[sml_counters[index].sml_cnt_old_state].srcpin) == bitRead(sml_counter_pinstate, index)) { return; } @@ -2722,7 +2269,6 @@ uint32_t debounce_time; #endif - #ifdef SML_REPLACE_VARS #ifndef SML_SRCBSIZE @@ -2767,7 +2313,7 @@ uint32_t SML_getscriptsize(char *lp) { //AddLog(LOG_LEVEL_INFO, PSTR("len=%d"),mlen); return mlen; } -#endif +#endif // SML_REPLACE_VARS bool Gpio_used(uint8_t gpiopin) { if ((gpiopin < nitems(TasmotaGlobal.gpio_pin)) && (TasmotaGlobal.gpio_pin[gpiopin] > 0)) { @@ -2776,106 +2322,244 @@ bool Gpio_used(uint8_t gpiopin) { return false; } +#define SML_MINSB 64 +char *SpecOptions(char *cp, uint32_t mnum) { +// special option + switch (*cp) { + case '1': + cp++; #ifdef USE_SML_SPECOPT -void SML_GetSpecOpt(char *cp, uint32_t mnum) { -// special option 1 -// we need 2 obis codes -// 2 flag codes + bit positions -// 1,=so1,00010800,63,7,64,11,00100700 + if (*cp == ',') { + cp++; + meter_desc[mnum].so_obis1 = strtol(cp, &cp, 16); + } + if (*cp == ',') { + cp++; + meter_desc[mnum].so_fcode1 = strtol(cp, &cp, 16); + } + if (*cp == ',') { + cp++; + meter_desc[mnum].so_bpos1 = strtol(cp, &cp, 10); + } + if (*cp == ',') { + cp++; + meter_desc[mnum].so_fcode2 = strtol(cp, &cp, 16); + } + if (*cp == ',') { + cp++; + meter_desc[mnum].so_bpos2 = strtol(cp, &cp, 10); + } + if (*cp == ',') { + cp++; + meter_desc[mnum].so_obis2 = strtol(cp, &cp, 16); + } +#endif + break; + case '2': + cp += 2; + meter_desc[mnum].so_flags = strtol(cp, &cp, 16); + break; + case '3': + cp += 2; + meter_desc[mnum].sbsiz = strtol(cp, &cp, 10); + if (*cp == ',') { + cp++; + meter_desc[mnum].sibsiz = strtol(cp, &cp, 10); + if (meter_desc[mnum].sibsiz < SML_MINSB) { + meter_desc[mnum].sibsiz = SML_MINSB; + } + } + break; + case '4': + cp += 2; +#ifdef USE_SML_DECRYPT + meter_desc[mnum].use_crypt = true; + for (uint8_t cnt = 0; cnt < (SML_CRYPT_SIZE * 2); cnt += 2) { + meter_desc[mnum].key[cnt / 2] = (sml_hexnibble(cp[cnt]) << 4) | sml_hexnibble(cp[cnt + 1]); + } +#endif + break; + } + return cp; +} - if (*cp == ',') { - cp++; - script_meter_desc[mnum].so_obis1 = strtol(cp, &cp, 16); +#ifdef USE_SML_DECRYPT + +//// calculate crc16 CCITT +uint16_t hdlc_crc16(const uint8_t *dp, uint8_t len) { +#define POLY 0x8408 + uint8_t i; + uint16_t data; + uint16_t crc = 0xffff; + + if (len == 0) { + return (~crc); + } + do { + data = (unsigned int)0xff & *dp++; + for (i = 0; i < 8; i++) { + if ((crc & 0x0001) ^ (data & 0x0001)) { + crc = (crc >> 1) ^ POLY; + } else { + crc >>= 1; + } + data >>= 1; + } + } while (--len); + + crc = ~crc; + data = crc; + crc = (crc << 8) | (data >> 8 & 0xff); + return crc; +} + +uint8_t *hdlc_decode(uint8_t *data, uint32_t dlen, uint8_t *key, uint16_t *size) { + if (dlen < 31) { + return 0; + } + uint16_t crc = hdlc_crc16(data + 1, dlen - 4); + uint16_t dcrc = data[dlen - 3] << 8 | data[dlen - 2]; + if (crc != dcrc) { + return 0; + } + + // crc OK + uint8_t ivec[12]; + uint8_t index = 0; + for (uint8_t cnt = 14; cnt < 14+8; cnt++) { + ivec[index] = data[cnt]; + index++; } - if (*cp == ',') { - cp++; - script_meter_desc[mnum].so_fcode1 = strtol(cp, &cp, 16); - } - if (*cp == ',') { - cp++; - script_meter_desc[mnum].so_bpos1 = strtol(cp, &cp, 10); - } - if (*cp == ',') { - cp++; - script_meter_desc[mnum].so_fcode2 = strtol(cp, &cp, 16); - } - if (*cp == ',') { - cp++; - script_meter_desc[mnum].so_bpos2 = strtol(cp, &cp, 10); - } - if (*cp == ',') { - cp++; - script_meter_desc[mnum].so_obis2 = strtol(cp, &cp, 16); + for (uint8_t cnt = 24; cnt < 24+4; cnt++) { + ivec[index] = data[cnt]; + index++; } + + br_gcm_context gcm_ctx; + br_aes_small_ctr_keys ctr_ctx; + br_aes_small_ctr_init(&ctr_ctx, key, 16); + br_gcm_init(&gcm_ctx, &ctr_ctx.vtable, &br_ghash_ctmul32); + br_gcm_reset(&gcm_ctx, ivec, 12); + br_gcm_flip(&gcm_ctx); + br_gcm_run(&gcm_ctx, 0, data + 28 , dlen - 31); + *size = dlen - 31; + return data + 28; } #endif -void SML_Init(void) { - meters_used = METERS_USED; - meter_desc_p = meter_desc; - meter_p = meter; - - sml_desc_cnt = 0; - - for (uint32_t cnt = 0; cnt < SML_MAX_VARS; cnt++) { - meter_vars[cnt] = 0; - dvalid[cnt] = 0; - } - - for (uint32_t cnt = 0; cnt < MAX_METERS; cnt++) { - meter_spos[cnt] = 0; - } +void reset_sml_vars(uint16_t maxmeters) { + for (uint32_t meters = 0; meters < maxmeters; meters++) { + meter_desc[meters].spos = 0; + meter_desc[meters].sbsiz = SML_BSIZ; + meter_desc[meters].sibsiz = TMSBSIZ; + if (meter_desc[meters].sbuff) { + free(meter_desc[meters].sbuff); + meter_desc[meters].sbuff = 0; + } #ifdef USE_SML_SPECOPT - for (uint32_t cnt = 0; cnt < MAX_METERS; cnt++) { - script_meter_desc[cnt].so_obis1 = 0; - script_meter_desc[cnt].so_obis2 = 0; - } + meter_desc[meters].so_obis1 = 0; + meter_desc[meters].so_obis2 = 0; +#endif + meter_desc[meters].so_flags = 0; + // addresses a bug in meter DWS74 +#ifdef DWS74_BUG + meter_desc[meters].so_flags |= SO_DWS74_BUG; #endif -#ifdef USE_SCRIPT - - for (uint32_t cnt = 0; cnt < MAX_METERS; cnt++) { - if (script_meter_desc[cnt].txmem) { - free(script_meter_desc[cnt].txmem); +#ifdef SML_OBIS_LINE + meter_desc[meters].so_flags |= SO_OBIS_LINE; +#endif + if (meter_desc[meters].txmem) { + free(meter_desc[meters].txmem); + meter_desc[meters].txmem = 0; } - script_meter_desc[cnt].txmem = 0; - script_meter_desc[cnt].trxpin = -1; - - if (meter_ss[cnt]) { - delete meter_ss[cnt]; - meter_ss[cnt] = NULL; + meter_desc[meters].txmem = 0; + meter_desc[meters].trxpin = -1; + if (meter_desc[meters].meter_ss) { + delete meter_desc[meters].meter_ss; + meter_desc[meters].meter_ss = NULL; } + } +} + +void SML_Init(void) { + + sml_globs.ready = false; + + if (!bitRead(Settings->rule_enabled, 0)) { + return; } - if (bitRead(Settings->rule_enabled, 0)) { + sml_globs.mp = meter_desc; - uint8_t meter_script=Run_Scripter(">M", -2, 0); - if (meter_script == 99) { - // use script definition - if (script_meter) free(script_meter); - script_meter = 0; - uint8_t *tp = 0; - uint16_t index = 0; - uint8_t section = 0; - int8_t srcpin = 0; - uint8_t dec_line = 0; - char *lp = glob_script_mem.scriptptr; - sml_send_blocks = 0; - while (lp) { + uint8_t meter_script = Run_Scripter(">M", -2, 0); + if (meter_script != 99) { + AddLog(LOG_LEVEL_INFO, PSTR("no meter section found!")); + return; + } + + char *lp = glob_script_mem.section_ptr; + uint8_t new_meters_used; + + // use script definition + if (sml_globs.script_meter) { + // restart condition + free(sml_globs.script_meter); + if (sml_globs.meter_vars) { + free(sml_globs.meter_vars); + sml_globs.meter_vars = 0; + } + if (sml_globs.dvalid) { + free(sml_globs.dvalid); + sml_globs.dvalid = 0; + } +#ifdef USE_SML_MEDIAN_FILTER + if (sml_globs.sml_mf) { + free(sml_globs.sml_mf); + sml_globs.sml_mf = 0; + } +#endif + reset_sml_vars(sml_globs.meters_used); + } + + if (*lp == '>' && *(lp + 1) == 'M') { + lp += 2; + sml_globs.meters_used = strtol(lp, &lp, 10); + } else { + return; + } + + sml_globs.maxvars = 0; + + reset_sml_vars(sml_globs.meters_used); + + sml_globs.sml_desc_cnt = 0; + + sml_globs.script_meter = 0; + uint8_t *tp = 0; + uint16_t index = 0; + uint8_t section = 0; + int8_t srcpin = 0; + uint32_t mlen; + uint16_t memory = 0; + + sml_globs.sml_send_blocks = 0; + lp = glob_script_mem.section_ptr; + while (lp) { if (!section) { - if (*lp == '>' && *(lp+1) == 'M') { + if (*lp == '>' && *(lp + 1) == 'M') { lp += 2; - meters_used = strtol(lp, 0, 10); section = 1; - uint32_t mlen = SML_getscriptsize(lp); + mlen = SML_getscriptsize(lp); if (mlen == 0) return; // missing end # - script_meter = (uint8_t*)calloc(mlen, 1); - if (!script_meter) { + sml_globs.script_meter = (uint8_t*)calloc(mlen, 1); + memory += mlen; + if (!sml_globs.script_meter) { goto dddef_exit; } - tp = script_meter; + tp = sml_globs.script_meter; goto next_line; } } @@ -2890,7 +2574,7 @@ void SML_Init(void) { lp++; index = *lp & 7; lp += 2; - if (index < 1 || index > meters_used) { + if (index < 1 || index > sml_globs.meters_used) { AddLog(LOG_LEVEL_INFO, PSTR("illegal meter number!")); goto next_line; } @@ -2899,61 +2583,60 @@ void SML_Init(void) { if (Gpio_used(abs(srcpin))) { AddLog(LOG_LEVEL_INFO, PSTR("SML: Error: Duplicate GPIO %d defined. Not usable for RX in meter number %d"), abs(srcpin), index + 1); dddef_exit: - if (script_meter) free(script_meter); - script_meter = 0; - meters_used = METERS_USED; - goto init10; + if (sml_globs.script_meter) free(sml_globs.script_meter); + sml_globs.script_meter = 0; + return; } - script_meter_desc[index].srcpin = srcpin; + meter_desc[index].srcpin = srcpin; if (*lp != ',') goto next_line; lp++; - script_meter_desc[index].type = *lp; + meter_desc[index].type = *lp; lp++; if (*lp != ',') { switch (*lp) { case 'N': lp++; - script_meter_desc[index].sopt = 0x10 | (*lp & 3); + meter_desc[index].sopt = 0x10 | (*lp & 3); lp++; break; case 'E': lp++; - script_meter_desc[index].sopt = 0x20 | (*lp & 3); + meter_desc[index].sopt = 0x20 | (*lp & 3); lp++; break; case 'O': lp++; - script_meter_desc[index].sopt = 0x30 | (*lp & 3); + meter_desc[index].sopt = 0x30 | (*lp & 3); lp++; break; default: - script_meter_desc[index].sopt = *lp&7; + meter_desc[index].sopt = *lp&7; lp++; } } else { - script_meter_desc[index].sopt = 0; + meter_desc[index].sopt = 0; } lp++; - script_meter_desc[index].flag = strtol(lp, &lp, 10); + meter_desc[index].flag = strtol(lp, &lp, 10); if (*lp != ',') goto next_line; lp++; - script_meter_desc[index].params = strtol(lp, &lp, 10); + meter_desc[index].params = strtol(lp, &lp, 10); if (*lp != ',') goto next_line; lp++; - script_meter_desc[index].prefix[7] = 0; + meter_desc[index].prefix[7] = 0; for (uint32_t cnt = 0; cnt < 8; cnt++) { if (*lp == SCRIPT_EOL || *lp == ',') { - script_meter_desc[index].prefix[cnt] = 0; + meter_desc[index].prefix[cnt] = 0; break; } - script_meter_desc[index].prefix[cnt] = *lp++; + meter_desc[index].prefix[cnt] = *lp++; } if (*lp == ',') { lp++; // get TRX pin - script_meter_desc[index].trxpin = strtol(lp, &lp, 10); - if (Gpio_used(script_meter_desc[index].trxpin)) { - AddLog(LOG_LEVEL_INFO, PSTR("SML: Error: Duplicate GPIO %d defined. Not usable for TX in meter number %d"), script_meter_desc[index].trxpin, index + 1); + meter_desc[index].trxpin = strtol(lp, &lp, 10); + if (Gpio_used(meter_desc[index].trxpin)) { + AddLog(LOG_LEVEL_INFO, PSTR("SML: Error: Duplicate GPIO %d defined. Not usable for TX in meter number %d"), meter_desc[index].trxpin, index + 1); goto dddef_exit; } // optional transmit enable pin @@ -2961,31 +2644,30 @@ dddef_exit: lp++; if (*lp == 'i') { lp++; - script_meter_desc[index].trx_en.trxenpol = 1; + meter_desc[index].trx_en.trxenpol = 1; } else { - script_meter_desc[index].trx_en.trxenpol = 0; + meter_desc[index].trx_en.trxenpol = 0; } - script_meter_desc[index].trx_en.trxenpin = strtol(lp, &lp, 10); + meter_desc[index].trx_en.trxenpin = strtol(lp, &lp, 10); if (*lp != ')') { goto dddef_exit; } lp++; - if (Gpio_used(script_meter_desc[index].trx_en.trxenpin)) { - AddLog(LOG_LEVEL_INFO, PSTR("SML: Error: Duplicate GPIO %d defined. Not usable for TX enable in meter number %d"), script_meter_desc[index].trx_en.trxenpin, index + 1); + if (Gpio_used(meter_desc[index].trx_en.trxenpin)) { + AddLog(LOG_LEVEL_INFO, PSTR("SML: Error: Duplicate GPIO %d defined. Not usable for TX enable in meter number %d"), meter_desc[index].trx_en.trxenpin, index + 1); goto dddef_exit; } - script_meter_desc[index].trx_en.trxen = 1; - pinMode(script_meter_desc[index].trx_en.trxenpin, OUTPUT); - digitalWrite(script_meter_desc[index].trx_en.trxenpin, script_meter_desc[index].trx_en.trxenpol); + meter_desc[index].trx_en.trxen = 1; + pinMode(meter_desc[index].trx_en.trxenpin, OUTPUT); + digitalWrite(meter_desc[index].trx_en.trxenpin, meter_desc[index].trx_en.trxenpol); } else { - script_meter_desc[index].trx_en.trxen = 0; + meter_desc[index].trx_en.trxen = 0; } if (*lp != ',') goto next_line; lp++; - script_meter_desc[index].tsecs = strtol(lp, &lp, 10); + meter_desc[index].tsecs = strtol(lp, &lp, 10); if (*lp == ',') { lp++; -#if 1 // look ahead uint16_t txlen = 0; uint16_t tx_entries = 1; @@ -3007,8 +2689,9 @@ dddef_exit: txlen++; } if (txlen) { - script_meter_desc[index].txmem = (char*)calloc(txlen + 2, 1); - if (script_meter_desc[index].txmem) { + meter_desc[index].txmem = (char*)calloc(txlen + 2, 1); + memory += txlen + 2; + if (meter_desc[index].txmem) { // now copy send blocks char *txp = lp; uint16_t tind = 0; @@ -3016,77 +2699,52 @@ dddef_exit: if (*txp == SCRIPT_EOL) { txp++; } else { - script_meter_desc[index].txmem[tind] = *txp++; + meter_desc[index].txmem[tind] = *txp++; tind++; } } } - //AddLog(LOG_LEVEL_INFO, PSTR(">>> %s - %d"), script_meter_desc[index].txmem, txlen); - script_meter_desc[index].index = 0; - script_meter_desc[index].max_index = tx_entries; - sml_send_blocks++; + //AddLog(LOG_LEVEL_INFO, PSTR(">>> %s - %d"), meter_desc[index].txmem, txlen); + meter_desc[index].index = 0; + meter_desc[index].max_index = tx_entries; + sml_globs.sml_send_blocks++; lp += txlen; } -#else - char txbuff[SML_SRCBSIZE]; - uint32_t txlen = 0, tx_entries = 1; - for (uint32_t cnt = 0; cnt < sizeof(txbuff); cnt++) { - if (*lp == SCRIPT_EOL && *(lp - 1) != ',' ) { - txbuff[cnt] = 0; - txlen = cnt; - break; - } - if (*lp == ',') tx_entries++; - txbuff[cnt] = *lp++; - } - if (txlen) { - script_meter_desc[index].txmem = (char*)calloc(txlen + 2, 1); - if (script_meter_desc[index].txmem) { - strcpy(script_meter_desc[index].txmem, txbuff); - } - script_meter_desc[index].index = 0; - script_meter_desc[index].max_index = tx_entries; - sml_send_blocks++; - } -#endif } } if (*lp == SCRIPT_EOL) lp--; goto next_line; } + char *lp1; #ifdef SML_REPLACE_VARS char dstbuf[SML_SRCBSIZE*2]; - Replace_Cmd_Vars(lp, 1, dstbuf,sizeof(dstbuf)); + Replace_Cmd_Vars(lp, 1, dstbuf, sizeof(dstbuf)); lp += SML_getlinelen(lp); + lp1 = dstbuf; +#else + lp1 = lp; + lp += SML_getlinelen(lp); +#endif // SML_REPLACE_VARS + //AddLog(LOG_LEVEL_INFO, PSTR("%s"),dstbuf); - char *lp1 = dstbuf; if (*lp1 == '-' || isdigit(*lp1)) { //toLogEOL(">>",lp); // add meters line -1,1-0:1.8.0*255(@10000,H2OIN,cbm,COUNTER,4| if (*lp1 == '-') lp1++; uint8_t mnum = strtol(lp1, 0, 10); - if (mnum < 1 || mnum > meters_used) { + if (mnum < 1 || mnum > sml_globs.meters_used) { AddLog(LOG_LEVEL_INFO, PSTR("illegal meter number!")); goto next_line; } // 1,=h————————————— - if (strncmp(lp1 + 1, ",=h", 3)) { - dec_line++; - if (dec_line >= SML_MAX_VARS) { - AddLog(LOG_LEVEL_INFO, PSTR("too many decode lines: %d !"), dec_line); - goto next_line; + if (!strncmp(lp1 + 1, ",=h", 3) || !strncmp(lp1 + 1, ",=so", 4)) { + if (!strncmp(lp1 + 1, ",=so", 4)) { + SpecOptions(lp1 + 5, mnum - 1); } + } else { + sml_globs.maxvars++; } -#ifdef USE_SML_SPECOPT - if (!strncmp(lp1 + 1, ",=so", 4)) { - // special option - char *cp = lp1 + 5; - if (*cp == '1') { - cp++; - SML_GetSpecOpt(cp, mnum - 1); - } - } -#endif + while (1) { if (*lp1 == 0) { *tp++ = '|'; @@ -3097,47 +2755,6 @@ dddef_exit: if (index >= METER_DEF_SIZE) break; } } -#else - - if (*lp == '-' || isdigit(*lp)) { - //toLogEOL(">>",lp); - // add meters line -1,1-0:1.8.0*255(@10000,H2OIN,cbm,COUNTER,4| - if (*lp == '-') lp++; - uint8_t mnum = strtol(lp,0,10); - if (mnum < 1 || mnum > meters_used) { - AddLog(LOG_LEVEL_INFO, PSTR("illegal meter number!")); - goto next_line; - } - if (strncmp(lp + 1, ",=h", 3)) { - dec_line++; - if (dec_line >= SML_MAX_VARS) { - AddLog(LOG_LEVEL_INFO, PSTR("too many decode lines: %d !"), dec_line); - goto next_line; - } - } -#ifdef USE_SML_SPECOPT - if (!strncmp(lp + 1, ",=so", 4)) { - // special option - char *cp = lp + 5; - if (*cp == '1') { - cp++; - SML_GetSpecOpt(cp, mnum - 1); - } - } -#endif - while (1) { - if (*lp == SCRIPT_EOL) { - if (*(tp-1) != '|') *tp++ = '|'; - goto next_line; - } - *tp++ = *lp++; - index++; - if (index >= METER_DEF_SIZE) break; - } - - } -#endif - } next_line: @@ -3150,47 +2767,47 @@ next_line: } } *tp = 0; - meter_desc_p = script_meter_desc; - meter_p = script_meter; - } - } -#endif + sml_globs.meter_p = sml_globs.script_meter; -init10: + // set serial buffers + for (uint32_t meters = 0; meters < sml_globs.meters_used; meters++ ) { + struct METER_DESC *mp = &meter_desc[meters]; + if (mp->sbsiz) { + mp->sbuff = (uint8_t*)calloc(mp->sbsiz, 1); + memory += mp->sbsiz; + } + } + + // initialize hardware typedef void (*function)(); uint8_t cindex = 0; // preloud counters - for (byte i = 0; i < MAX_COUNTERS; i++) { + for (uint8_t i = 0; i < MAX_COUNTERS; i++) { RtcSettings.pulse_counter[i] = Settings->pulse_counter[i]; sml_counters[i].sml_cnt_last_ts = millis(); } - #ifdef ESP32 +#ifdef ESP32 uint32_t uart_index = SOC_UART_NUM - 1; - #endif - sml_counter_pinstate = 0; - for (uint8_t meters = 0; meters < meters_used; meters++) { - if (meter_desc_p[meters].type == 'c') { - if (meter_desc_p[meters].flag & 2) { - // analog mode -#ifdef ANALOG_OPTO_SENSOR - ADS1115_init(); - sml_counters[cindex].ana_max=-32768; - sml_counters[cindex].ana_min=+32767; #endif + sml_counter_pinstate = 0; + for (uint8_t meters = 0; meters < sml_globs.meters_used; meters++) { + if (sml_globs.mp[meters].type == 'c') { + if (sml_globs.mp[meters].flag & 2) { + } else { // counters, set to input with pullup - if (meter_desc_p[meters].flag & 1) { - pinMode(meter_desc_p[meters].srcpin, INPUT_PULLUP); + if (sml_globs.mp[meters].flag & 1) { + pinMode(sml_globs.mp[meters].srcpin, INPUT_PULLUP); } else { - pinMode(meter_desc_p[meters].srcpin, INPUT); + pinMode(sml_globs.mp[meters].srcpin, INPUT); } // check for irq mode - if (meter_desc_p[meters].params <= 0) { + if (sml_globs.mp[meters].params <= 0) { // init irq mode sml_counters[cindex].sml_cnt_old_state = meters; - sml_counters[cindex].sml_debounce = -meter_desc_p[meters].params; - attachInterruptArg(meter_desc_p[meters].srcpin, SML_CounterIsr, &sml_cnt_index[cindex], CHANGE); - if (digitalRead(meter_desc_p[meters].srcpin) > 0) { + sml_counters[cindex].sml_debounce = -sml_globs.mp[meters].params; + attachInterruptArg(sml_globs.mp[meters].srcpin, SML_CounterIsr, &sml_cnt_index[cindex], CHANGE); + if (digitalRead(sml_globs.mp[meters].srcpin) > 0) { sml_counter_pinstate |= (1 << cindex); } sml_counters[cindex].sml_counter_ltime = millis(); @@ -3202,192 +2819,267 @@ init10: } } else { // serial input, init +#ifdef ESP8266 #ifdef SPECIAL_SS - if (meter_desc_p[meters].type=='m' || meter_desc_p[meters].type=='M' || meter_desc_p[meters].type=='k' || meter_desc_p[meters].type=='p' || meter_desc_p[meters].type=='R' || meter_desc_p[meters].type=='v') { - meter_ss[meters] = new TasmotaSerial(meter_desc_p[meters].srcpin,meter_desc_p[meters].trxpin,1,0,TMSBSIZ); + char type = sml_globs.mp[meters].type; + if (type=='m' || type=='M' || type=='k' || type=='p' || type=='R' || type=='v') { + meter_desc[meters].meter_ss = new TasmotaSerial(sml_globs.mp[meters].srcpin,sml_globs.mp[meters].trxpin, 1, 0, meter_desc[meters].sibsiz); } else { - meter_ss[meters] = new TasmotaSerial(meter_desc_p[meters].srcpin,meter_desc_p[meters].trxpin,1,1,TMSBSIZ); + meter_desc[meters].meter_ss = new TasmotaSerial(sml_globs.mp[meters].srcpin,sml_globs.mp[meters].trxpin, 1, 1, meter_desc[meters].sibsiz); } #else -#ifdef ESP8266 - meter_ss[meters] = new TasmotaSerial(meter_desc_p[meters].srcpin,meter_desc_p[meters].trxpin,1,0,TMSBSIZ); -#endif // ESP8266 + meter_desc[meters].meter_ss = new TasmotaSerial(sml_globs.mp[meters].srcpin,sml_globs.mp[meters].trxpin, 1, 0, meter_desc[meters].sibsiz); +#endif // SPECIAL_SS +#endif // ESP8266 + #ifdef ESP32 // use hardware serial #ifdef USE_ESP32_SW_SERIAL - meter_ss[meters] = new SML_ESP32_SERIAL(uart_index); - if (meter_desc_p[meters].srcpin >= 0) { + meter_desc[meters].meter_ss = new SML_ESP32_SERIAL(uart_index); + if (sml_globs.mp[meters].srcpin >= 0) { if (uart_index == 0) { ClaimSerial(); } uart_index--; if (uart_index < 0) uart_index = 0; } #else - meter_ss[meters] = new HardwareSerial(uart_index); + meter_desc[meters].meter_ss = new HardwareSerial(uart_index); if (uart_index == 0) { ClaimSerial(); } uart_index--; if (uart_index < 0) uart_index = 0; - meter_ss[meters]->setRxBufferSize(TMSBSIZ); + meter_desc[meters].meter_ss->setRxBufferSize(meter_desc[meters].sibsiz); #endif // USE_ESP32_SW_SERIAL #endif // ESP32 -#endif // SPECIAL_SS SerialConfig smode = SERIAL_8N1; - if (meter_desc_p[meters].sopt & 0xf0) { + if (sml_globs.mp[meters].sopt & 0xf0) { // new serial config - switch (meter_desc_p[meters].sopt >> 4) { + switch (sml_globs.mp[meters].sopt >> 4) { case 1: - if ((meter_desc_p[meters].sopt & 1) == 1) smode = SERIAL_8N1; + if ((sml_globs.mp[meters].sopt & 1) == 1) smode = SERIAL_8N1; else smode = SERIAL_8N2; break; case 2: - if ((meter_desc_p[meters].sopt & 1) == 1) smode = SERIAL_8E1; + if ((sml_globs.mp[meters].sopt & 1) == 1) smode = SERIAL_8E1; else smode = SERIAL_8E2; break; case 3: - if ((meter_desc_p[meters].sopt & 1) == 1) smode = SERIAL_8O1; + if ((sml_globs.mp[meters].sopt & 1) == 1) smode = SERIAL_8O1; else smode = SERIAL_8O2; break; } } else { - // depecated serial config - if (meter_desc_p[meters].sopt == 2) { + // deprecated serial config + if (sml_globs.mp[meters].sopt == 2) { smode = SERIAL_8N2; } - if (meter_desc_p[meters].type=='M') { + if (sml_globs.mp[meters].type=='M') { smode = SERIAL_8E1; - if (meter_desc_p[meters].sopt == 2) { + if (sml_globs.mp[meters].sopt == 2) { smode = SERIAL_8E2; } } } #ifdef ESP8266 - if (meter_ss[meters]->begin(meter_desc_p[meters].params)) { - meter_ss[meters]->flush(); + if (meter_desc[meters].meter_ss->begin(sml_globs.mp[meters].params)) { + meter_desc[meters].meter_ss->flush(); } - if (meter_ss[meters]->hardwareSerial()) { - Serial.begin(meter_desc_p[meters].params, smode); + if (meter_desc[meters].meter_ss->hardwareSerial()) { + Serial.begin(sml_globs.mp[meters].params, smode); ClaimSerial(); //Serial.setRxBufferSize(512); } #endif // ESP8266 + #ifdef ESP32 - meter_ss[meters]->begin(meter_desc_p[meters].params, smode, meter_desc_p[meters].srcpin, meter_desc_p[meters].trxpin); - //meter_ss[meters]->setRxBufferSize(TMSBSIZ); + meter_desc[meters].meter_ss->begin(sml_globs.mp[meters].params, smode, sml_globs.mp[meters].srcpin, sml_globs.mp[meters].trxpin); +#ifdef USE_ESP32_SW_SERIAL + meter_desc[meters].meter_ss->setRxBufferSize(meter_desc[meters].sibsiz); +#endif #endif // ESP32 } } + + sml_globs.meter_vars = (double*)calloc(sml_globs.maxvars, sizeof(double)); + sml_globs.dvalid = (uint8_t*)calloc(sml_globs.maxvars, sizeof(uint8_t)); + +#ifdef USE_SML_MEDIAN_FILTER + sml_globs.sml_mf = (struct SML_MEDIAN_FILTER*)calloc(sml_globs.maxvars, sizeof(struct SML_MEDIAN_FILTER)); +#endif + + if (!sml_globs.maxvars || !sml_globs.meter_vars || !sml_globs.dvalid || !sml_globs.sml_mf) { + AddLog(LOG_LEVEL_INFO, PSTR("sml memory error!")); + return; + } + + memory += sizeof(sml_globs) + sizeof(meter_desc) + sml_globs.maxvars * (sizeof(double) + sizeof(uint8_t) + sizeof(struct SML_MEDIAN_FILTER)); + + AddLog(LOG_LEVEL_INFO, PSTR("meters: %d , decode lines: %d, memory used: %d bytes"), sml_globs.meters_used, sml_globs.maxvars, memory); + + +// speed optimize shift flag + for (uint32_t meters = 0; meters < sml_globs.meters_used; meters++ ) { + struct METER_DESC *mp = &meter_desc[meters]; + char type = mp->type; + + if (!(mp->so_flags & SO_OBIS_LINE)) { + mp->shift_mode = (type != 'e' && type != 'k' && type != 'm' && type != 'M' && type != 'p' && type != 'R' && type != 'v'); + } else { + mp->shift_mode = (type != 'o' && type != 'e' && type != 'k' && type != 'm' && type != 'M' && type != 'p' && type != 'R' && type != 'v'); + } + } + + sml_globs.ready = true; } #ifdef USE_SML_SCRIPT_CMD -uint32_t sml_getv(uint32_t sel) { - if (!sel) { - for (uint8_t cnt = 0; cnt < SML_MAX_VARS; cnt++) { - dvalid[cnt] = 0; - } - sel = 0; - } else { - if (sel < 1) sel = 1; - sel = dvalid[sel - 1]; - } - return sel; -} + uint32_t SML_SetBaud(uint32_t meter, uint32_t br) { - if (meter < 1 || meter > meters_used) return 0; + if (sml_globs.ready == false) return 0; + if (meter < 1 || meter > sml_globs.meters_used) return 0; meter--; - if (!meter_ss[meter]) return 0; + if (!meter_desc[meter].meter_ss) return 0; #ifdef ESP8266 - if (meter_ss[meter]->begin(br)) { - meter_ss[meter]->flush(); + if (meter_desc[meter].meter_ss->begin(br)) { + meter_desc[meter].meter_ss->flush(); } - if (meter_ss[meter]->hardwareSerial()) { - if (meter_desc_p[meter].type=='M') { + if (meter_desc[meter].meter_ss->hardwareSerial()) { + if (sml_globs.mp[meter].type=='M') { Serial.begin(br, SERIAL_8E1); } } #endif // ESP8266 #ifdef ESP32 - meter_ss[meter]->flush(); - meter_ss[meter]->updateBaudRate(br); + meter_desc[meter].meter_ss->flush(); + meter_desc[meter].meter_ss->updateBaudRate(br); /* - if (meter_desc_p[meter].type=='M') { - meter_ss[meter]->begin(br,SERIAL_8E1,meter_desc_p[meter].srcpin,meter_desc_p[meter].trxpin); + if (sml_globs.mp[meter].type=='M') { + meter_desc.meter_ss[meter]->begin(br,SERIAL_8E1,sml_globs.mp[meter].srcpin,sml_globs.mp[meter].trxpin); } else { - meter_ss[meter]->begin(br,SERIAL_8N1,meter_desc_p[meter].srcpin,meter_desc_p[meter].trxpin); + meter_desc.meter_ss[meter]->begin(br,SERIAL_8N1,sml_globs.mp[meter].srcpin,sml_globs.mp[meter].trxpin); }*/ #endif // ESP32 return 1; } -uint32_t SML_Status(uint32_t meter) { - if (meter < 1 || meter > meters_used) return 0; +uint32_t sml_status(uint32_t meter) { + if (sml_globs.ready == false) return 0; + if (meter < 1 || meter > sml_globs.meters_used) return 0; meter--; #if defined(ED300L) || defined(AS2020) || defined(DTZ541) || defined(USE_SML_SPECOPT) - return sml_status[meter]; + return sml_globs.sml_status[meter]; #else return 0; #endif } - - -uint32_t SML_Write(uint32_t meter,char *hstr) { - if (meter < 1 || meter > meters_used) return 0; +uint32_t SML_Write(int32_t meter, char *hstr) { + if (sml_globs.ready == false) return 0; + int8_t flag = meter; + meter = abs(meter); + if (meter < 1 || meter > sml_globs.meters_used) return 0; meter--; - if (!meter_ss[meter]) return 0; - SML_Send_Seq(meter, hstr); + if (!meter_desc[meter].meter_ss) return 0; + if (flag > 0) { + SML_Send_Seq(meter, hstr); + } else { + // 9600:8E1, only hardware serial + uint32_t baud = strtol(hstr, &hstr, 10); + hstr++; + // currently only 8 bits and ignore stopbits + hstr++; + SerialConfig smode; + switch (*hstr) { + case 'N': + smode = SERIAL_8N1; + break; + case 'E': + smode = SERIAL_8E1; + break; + case 'O': + smode = SERIAL_8O1; + break; + } + +#ifdef ESP8266 + Serial.begin(baud, smode); +#else + meter_desc[meter].meter_ss->begin(baud, smode, sml_globs.mp[meter].srcpin, sml_globs.mp[meter].trxpin); +#endif + } return 1; } -uint32_t SML_Read(int32_t meter,char *str, uint32_t slen) { -uint8_t hflg = 0; +uint32_t SML_Read(int32_t meter, char *str, uint32_t slen) { + if (sml_globs.ready == false) return 0; + + uint8_t hflg = 0; if (meter < 0) { meter = abs(meter); hflg = 1; } - if (meter < 1 || meter > meters_used) return 0; + if (meter < 1 || meter > sml_globs.meters_used) return 0; meter--; - if (!meter_ss[meter]) return 0; + if (!meter_desc[meter].meter_ss) return 0; - if (!meter_spos[meter]) { + struct METER_DESC *mp = &meter_desc[meter]; + + if (!mp->spos) { return 0; } - smltbuf[meter][meter_spos[meter]] = 0; + mp->sbuff[mp->spos] = 0; if (!hflg) { - strlcpy(str, (char*)&smltbuf[meter][0], slen); + strlcpy(str, (char*)&mp->sbuff[0], slen); } else { uint32_t index = 0; - for (uint32_t cnt = 0; cnt < meter_spos[meter]; cnt++) { - sprintf(str,"%02x", smltbuf[meter][cnt]); + for (uint32_t cnt = 0; cnt < mp->spos; cnt++) { + sprintf(str,"%02x", mp->sbuff[cnt]); str += 2; index += 2; if (index >= slen - 2) break; } } - meter_spos[meter] = 0; + mp->spos = 0; return 1; } -float SML_GetVal(uint32_t index) { - if (index < 1 || index > SML_MAX_VARS) { index = 1;} - return meter_vars[index - 1]; +uint32_t sml_getv(uint32_t sel) { + if (sml_globs.ready == false) return 0; + if (!sel) { + for (uint8_t cnt = 0; cnt < sml_globs.maxvars; cnt++) { + sml_globs.dvalid[cnt] = 0; + } + sel = 0; + } else { + if (sel < 1 || sel > sml_globs.maxvars) { sel = 1;} + sel = sml_globs.dvalid[sel - 1]; + } + return sel; +} + +double SML_GetVal(uint32_t index) { + if (sml_globs.ready == false) return 0; + if (index < 1 || index > sml_globs.maxvars) { index = 1;} + return sml_globs.meter_vars[index - 1]; } char *SML_GetSVal(uint32_t index) { - if (index < 1 || index > MAX_METERS) { index = 1;} - return &meter_id[index - 1][0]; + if (sml_globs.ready == false) return 0; + if (index < 1 || index > sml_globs.meters_used) { index = 1;} + return (char*)meter_desc[index - 1].meter_id; } int32_t SML_Set_WStr(uint32_t meter, char *hstr) { - if (meter < 1 || meter > meters_used) return -1; + if (sml_globs.ready == false) return 0; + if (meter < 1 || meter > sml_globs.meters_used) return -1; meter--; - if (!meter_ss[meter]) return -2; - script_meter_desc[meter].script_str = hstr; + if (!meter_desc[meter].meter_ss) return -2; + meter_desc[meter].script_str = hstr; return 0; } @@ -3408,29 +3100,20 @@ void SML_Counter_Poll(void) { uint16_t meters, cindex = 0; uint32_t ctime = millis(); - for (meters = 0; meters < meters_used; meters++) { - if (meter_desc_p[meters].type == 'c') { + for (meters = 0; meters < sml_globs.meters_used; meters++) { + if (sml_globs.mp[meters].type == 'c') { // poll for counters and debouce - if (meter_desc_p[meters].params > 0) { - if (ctime - sml_counters[cindex].sml_cnt_last_ts > meter_desc_p[meters].params) { + if (sml_globs.mp[meters].params > 0) { + if (ctime - sml_counters[cindex].sml_cnt_last_ts > sml_globs.mp[meters].params) { sml_counters[cindex].sml_cnt_last_ts = ctime; - if (meter_desc_p[meters].flag & 2) { + if (sml_globs.mp[meters].flag & 2) { // analog mode, get next value -#ifdef ANALOG_OPTO_SENSOR - if (ads1115_up) { - int16_t val = adc.read_sample(); - if (val>sml_counters[cindex].ana_max) sml_counters[cindex].ana_max = val; - if (val 10) { sml_counters[cindex].sml_cnt_last_ts = ctime; #ifdef DEBUG_CNT_LED1 - if (cindex == 0) SetDBGLed(meter_desc_p[meters].srcpin, DEBUG_CNT_LED1); + if (cindex == 0) SetDBGLed(sml_globs.mp[meters].srcpin, DEBUG_CNT_LED1); #endif #ifdef DEBUG_CNT_LED2 - if (cindex == 1) SetDBGLed(meter_desc_p[meters].srcpin, DEBUG_CNT_LED2); + if (cindex == 1) SetDBGLed(sml_globs.mp[meters].srcpin, DEBUG_CNT_LED2); #endif } @@ -3497,52 +3180,52 @@ char *SML_Get_Sequence(char *cp,uint32_t index) { } void SML_Check_Send(void) { - sml_100ms_cnt++; + sml_globs.sml_100ms_cnt++; char *cp; - for (uint32_t cnt = sml_desc_cnt; cnt < meters_used; cnt++) { - if (script_meter_desc[cnt].trxpin >= 0 && script_meter_desc[cnt].txmem) { - //AddLog(LOG_LEVEL_INFO, PSTR("100 ms>> %d - %s - %d"),sml_desc_cnt,script_meter_desc[cnt].txmem,script_meter_desc[cnt].tsecs); - if ((sml_100ms_cnt >= script_meter_desc[cnt].tsecs)) { - sml_100ms_cnt = 0; + for (uint32_t cnt = sml_globs.sml_desc_cnt; cnt < sml_globs.meters_used; cnt++) { + if (meter_desc[cnt].trxpin >= 0 && meter_desc[cnt].txmem) { + //AddLog(LOG_LEVEL_INFO, PSTR("100 ms>> %d - %s - %d"),sml_globs.sml_desc_cnt,meter_desc[cnt].txmem,meter_desc[cnt].tsecs); + if ((sml_globs.sml_100ms_cnt >= meter_desc[cnt].tsecs)) { + sml_globs.sml_100ms_cnt = 0; // check for scriptsync extra output - if (script_meter_desc[cnt].script_str) { - cp = script_meter_desc[cnt].script_str; - script_meter_desc[cnt].script_str = 0; + if (meter_desc[cnt].script_str) { + cp = meter_desc[cnt].script_str; + meter_desc[cnt].script_str = 0; } else { //AddLog(LOG_LEVEL_INFO, PSTR("100 ms>> 2"),cp); - if (script_meter_desc[cnt].max_index > 1) { - script_meter_desc[cnt].index++; - if (script_meter_desc[cnt].index >= script_meter_desc[cnt].max_index) { - script_meter_desc[cnt].index = 0; - sml_desc_cnt++; + if (meter_desc[cnt].max_index > 1) { + meter_desc[cnt].index++; + if (meter_desc[cnt].index >= meter_desc[cnt].max_index) { + meter_desc[cnt].index = 0; + sml_globs.sml_desc_cnt++; } - cp = SML_Get_Sequence(script_meter_desc[cnt].txmem, script_meter_desc[cnt].index); + cp = SML_Get_Sequence(meter_desc[cnt].txmem, meter_desc[cnt].index); //SML_Send_Seq(cnt,cp); } else { - cp = script_meter_desc[cnt].txmem; + cp = meter_desc[cnt].txmem; //SML_Send_Seq(cnt,cp); - sml_desc_cnt++; + sml_globs.sml_desc_cnt++; } } //AddLog(LOG_LEVEL_INFO, PSTR(">> %s"),cp); SML_Send_Seq(cnt,cp); - if (sml_desc_cnt >= meters_used) { - sml_desc_cnt = 0; + if (sml_globs.sml_desc_cnt >= sml_globs.meters_used) { + sml_globs.sml_desc_cnt = 0; } break; } } else { - sml_desc_cnt++; + sml_globs.sml_desc_cnt++; } - if (sml_desc_cnt >= meters_used) { - sml_desc_cnt = 0; + if (sml_globs.sml_desc_cnt >= sml_globs.meters_used) { + sml_globs.sml_desc_cnt = 0; } } } void sml_hex_asci(uint32_t mindex, char *tpowstr) { - char *cp = &meter_id[mindex][0]; + char *cp = meter_desc[mindex].meter_id; uint16_t slen = strlen(cp); slen &= 0xfffe; uint16_t cnt; @@ -3586,8 +3269,8 @@ void SML_Send_Seq(uint32_t meter,char *seq) { slen++; if (slen >= sizeof(sbuff)-6) break; // leave space for checksum } - if (script_meter_desc[meter].type == 'm' || script_meter_desc[meter].type == 'M' || script_meter_desc[meter].type == 'k') { - if (script_meter_desc[meter].type == 'k') { + if (meter_desc[meter].type == 'm' || meter_desc[meter].type == 'M' || meter_desc[meter].type == 'k') { + if (meter_desc[meter].type == 'k') { // kamstrup, append crc, cr *ucp++ = 0; *ucp++ = 0; @@ -3630,12 +3313,12 @@ void SML_Send_Seq(uint32_t meter,char *seq) { } } - if (script_meter_desc[meter].type == 'o') { + if (meter_desc[meter].type == 'o') { for (uint32_t cnt = 0; cnt < slen; cnt++) { sbuff[cnt] |= (CalcEvenParity(sbuff[cnt]) << 7); } } - if (script_meter_desc[meter].type == 'p') { + if (meter_desc[meter].type == 'p') { *ucp++ = 0xc0; *ucp++ = 0xa8; *ucp++ = 1; @@ -3645,23 +3328,23 @@ void SML_Send_Seq(uint32_t meter,char *seq) { slen += 6; } - if (script_meter_desc[meter].trx_en.trxen) { - digitalWrite(script_meter_desc[meter].trx_en.trxenpin, script_meter_desc[meter].trx_en.trxenpol ^ 1); + if (meter_desc[meter].trx_en.trxen) { + digitalWrite(meter_desc[meter].trx_en.trxenpin, meter_desc[meter].trx_en.trxenpol ^ 1); } - meter_ss[meter]->flush(); - meter_ss[meter]->write(sbuff, slen); + meter_desc[meter].meter_ss->flush(); + meter_desc[meter].meter_ss->write(sbuff, slen); - if (script_meter_desc[meter].trx_en.trxen) { + if (meter_desc[meter].trx_en.trxen) { // must wait for all data sent - meter_ss[meter]->flush(); - digitalWrite(script_meter_desc[meter].trx_en.trxenpin, script_meter_desc[meter].trx_en.trxenpol); + meter_desc[meter].meter_ss->flush(); + digitalWrite(meter_desc[meter].trx_en.trxenpin, meter_desc[meter].trx_en.trxenpol); } - if (dump2log) { + if (sml_globs.dump2log) { #ifdef SML_DUMP_OUT_ALL Hexdump(sbuff, slen); #else - uint8_t type = meter_desc_p[(dump2log&7) - 1].type; + uint8_t type = sml_globs.mp[(sml_globs.dump2log&7) - 1].type; if (type == 'm' || type == 'M' || type == 'k') { Hexdump(sbuff, slen); } @@ -3669,9 +3352,9 @@ void SML_Send_Seq(uint32_t meter,char *seq) { } #ifdef MODBUS_DEBUG - uint8_t type = script_meter_desc[meter].type; - if (!dump2log && (type == 'm' || type == 'M' || type == 'k')) { - AddLog(LOG_LEVEL_INFO, PSTR("transmit index >> %d"),meter_desc_p[meter].index); + uint8_t type = meter_desc[meter].type; + if (!sml_globs.dump2log && (type == 'm' || type == 'M' || type == 'k')) { + AddLog(LOG_LEVEL_INFO, PSTR("transmit index >> %d"),sml_globs.mp[meter].index); Hexdump(sbuff, slen); } #endif @@ -3753,12 +3436,20 @@ bool XSNS_53_cmd(void) { // set dump mode cp++; uint8_t index = atoi(cp); - if ((index & 7) > meters_used) index = 1; - if (index > 0 && meter_desc_p[(index & 7) - 1].type == 'c') { + if ((index & 7) > sml_globs.meters_used) index = 1; + if (index > 0 && sml_globs.mp[(index & 7) - 1].type == 'c') { index = 0; } - dump2log = index; - ResponseTime_P(PSTR(",\"SML\":{\"CMD\":\"dump: %d\"}}"), dump2log); + if (sml_globs.log_data) { + free(sml_globs.log_data); + sml_globs.log_data = 0; + } + + if (index > 0) { + sml_globs.log_data = (char*)calloc(SML_DUMP_SIZE, sizeof(char)); + } + sml_globs.dump2log = index; + ResponseTime_P(PSTR(",\"SML\":{\"CMD\":\"dump: %d\"}}"), sml_globs.dump2log); } else if (*cp == 'c') { // set counter cp++; @@ -3771,8 +3462,8 @@ bool XSNS_53_cmd(void) { while (isdigit(*cp)) cp++; RtcSettings.pulse_counter[index - 1] = cval; uint8_t cindex = 0; - for (uint8_t meters = 0; meters < meters_used; meters++) { - if (meter_desc_p[meters].type == 'c') { + for (uint8_t meters = 0; meters < sml_globs.meters_used; meters++) { + if (sml_globs.mp[meters].type == 'c') { InjektCounterValue(meters,RtcSettings.pulse_counter[cindex], 0.0); cindex++; } @@ -3788,26 +3479,26 @@ bool XSNS_53_cmd(void) { // meter number for serial activity cp++; if (!isdigit(*cp)) { - ResponseTime_P(PSTR(",\"SML\":{\"CMD\":\"ser_act_meter_num: %d\"}}"),ser_act_meter_num); + ResponseTime_P(PSTR(",\"SML\":{\"CMD\":\"sml_globs.ser_act_meter_num: %d\"}}"),sml_globs.ser_act_meter_num); } else { - ser_act_meter_num=atoi(cp); - ResponseTime_P(PSTR(",\"SML\":{\"CMD\":\"ser_act_meter_num: %d\"}}"),ser_act_meter_num); + sml_globs.ser_act_meter_num=atoi(cp); + ResponseTime_P(PSTR(",\"SML\":{\"CMD\":\"sml_globs.ser_act_meter_num: %d\"}}"),sml_globs.ser_act_meter_num); } } else if (*cp=='l') { // serial activity LED-GPIO cp++; if (!isdigit(*cp)) { - ResponseTime_P(PSTR(",\"SML\":{\"CMD\":\"ser_act_LED_pin: %d\"}}"),ser_act_LED_pin); + ResponseTime_P(PSTR(",\"SML\":{\"CMD\":\"sml_globs.ser_act_LED_pin: %d\"}}"),sml_globs.ser_act_LED_pin); } else { - ser_act_LED_pin=atoi(cp); - if (Gpio_used(ser_act_LED_pin)) { - AddLog(LOG_LEVEL_INFO, PSTR("SML: Error: Duplicate GPIO %d defined. Not usable for LED."),ser_act_LED_pin); - ser_act_LED_pin=255; + sml_globs.ser_act_LED_pin=atoi(cp); + if (Gpio_used(sml_globs.ser_act_LED_pin)) { + AddLog(LOG_LEVEL_INFO, PSTR("SML: Error: Duplicate GPIO %d defined. Not usable for LED."),sml_globs.ser_act_LED_pin); + sml_globs.ser_act_LED_pin=255; } - if (ser_act_LED_pin!=255) { - pinMode(ser_act_LED_pin, OUTPUT); + if (sml_globs.ser_act_LED_pin!=255) { + pinMode(sml_globs.ser_act_LED_pin, OUTPUT); } - ResponseTime_P(PSTR(",\"SML\":{\"CMD\":\"ser_act_LED_pin: %d\"}}"),ser_act_LED_pin); + ResponseTime_P(PSTR(",\"SML\":{\"CMD\":\"sml_globs.ser_act_LED_pin: %d\"}}"),sml_globs.ser_act_LED_pin); } } else { serviced=false; @@ -3820,10 +3511,10 @@ void InjektCounterValue(uint8_t meter, uint32_t counter, float rate) { int dec = (int)rate; int frac = (int)((rate - (float)dec) * 1000.0); - snprintf((char*)&smltbuf[meter][0], SML_BSIZ, "1-0:1.8.0*255(%d)", counter); + snprintf((char*)&meter_desc[meter].sbuff[0], meter_desc[meter].sbsiz, "1-0:1.8.0*255(%d)", counter); SML_Decode(meter); - snprintf((char*)&smltbuf[meter][0], SML_BSIZ, "1-0:1.7.0*255(%d.%d)", dec, frac); + snprintf((char*)&meter_desc[meter].sbuff[0], meter_desc[meter].sbsiz, "1-0:1.7.0*255(%d.%d)", dec, frac); SML_Decode(meter); } @@ -3834,8 +3525,6 @@ void SML_CounterSaveState(void) { } - - /*********************************************************************************************\ * Interface \*********************************************************************************************/ @@ -3847,31 +3536,36 @@ bool Xsns53(uint32_t function) { SML_Init(); break; case FUNC_LOOP: - SML_Counter_Poll(); - if (dump2log) Dump2log(); - else { - SML_Poll(); + if (sml_globs.ready) { + SML_Counter_Poll(); + if (sml_globs.dump2log) { + dump2log(); + } else { + SML_Poll(); + } } break; - // case FUNC_EVERY_50_MSECOND: - // if (dump2log) Dump2log(); - // else SML_Poll(); - // break; #ifdef USE_SCRIPT case FUNC_EVERY_100_MSECOND: if (bitRead(Settings->rule_enabled, 0)) { - SML_Check_Send(); + if (sml_globs.ready) { + SML_Check_Send(); + } } break; #endif // USE_SCRIPT case FUNC_JSON_APPEND: - if (sml_options & SML_OPTIONS_JSON_ENABLE) { - SML_Show(1); + if (sml_globs.ready) { + if (sml_options & SML_OPTIONS_JSON_ENABLE) { + SML_Show(1); + } } break; #ifdef USE_WEBSERVER case FUNC_WEB_SENSOR: - SML_Show(0); + if (sml_globs.ready) { + SML_Show(0); + } break; #endif // USE_WEBSERVER case FUNC_COMMAND_SENSOR: @@ -3881,7 +3575,9 @@ bool Xsns53(uint32_t function) { break; case FUNC_SAVE_BEFORE_RESTART: case FUNC_SAVE_AT_MIDNIGHT: - SML_CounterSaveState(); + if (sml_globs.ready) { + SML_CounterSaveState(); + } break; } return result; From 587e8299d69e20c180afcb1994b4436b015112e9 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 30 Dec 2022 16:56:36 +0100 Subject: [PATCH 070/262] Add debugging info to modbus.ino --- tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino | 1 + tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino | 12 ++++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino b/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino index 46322656b..c934e4217 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino @@ -319,6 +319,7 @@ void EnergyUpdateTotal(void) { if ((Energy.total[i] < (Energy.import_active[i] - 0.01f)) && // We subtract a little offset to avoid continuous updates Settings->flag3.hardware_energy_total) { // SetOption72 - Enable hardware energy total counter as reference (#6561) + // The following calculation allows total usage (Energy.import_active[i]) up to +/-21474 kWh RtcSettings.energy_kWhtotal_ph[i] = (int32_t)((Energy.import_active[i] * 100000) - Energy.kWhtoday_offset[i] - Energy.kWhtoday[i]); Settings->energy_kWhtotal_ph[i] = RtcSettings.energy_kWhtotal_ph[i]; Energy.total[i] = (float)(RtcSettings.energy_kWhtotal_ph[i] + Energy.kWhtoday_offset[i] + Energy.kWhtoday[i]) / 100000; diff --git a/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino b/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino index 75bfa8227..27f208616 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino @@ -280,10 +280,6 @@ void EnergyModbusLoop(void) { // Even data type is single register, Odd data type is double registers register_count = 2 - (NrgMbsReg[NrgMbsParam.state].datatype & 1); uint32_t error = EnergyModbus->ReceiveBuffer(buffer, register_count); - - AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("NRG: Modbus register %d, phase %d, rcvd %*_H"), - NrgMbsParam.state, NrgMbsParam.phase, EnergyModbus->ReceiveCount(), buffer); - if (error) { /* Return codes from TasmotaModbus.h: * 0 = No error @@ -302,6 +298,10 @@ void EnergyModbusLoop(void) { * 13 = Register data not specified * 14 = To many registers */ +#ifdef ENERGY_MODBUS_DEBUG + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("NRG: Modbus register %d, phase %d, rcvd %*_H"), + NrgMbsParam.state, NrgMbsParam.phase, EnergyModbus->ReceiveCount(), buffer); +#endif AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Modbus error %d"), error); } else { /* Modbus protocol format: @@ -386,6 +386,10 @@ void EnergyModbusLoop(void) { value *= factor; } + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("NRG: Modbus register %d, phase %d, rcvd %*_H, T %d, F %d, value %4_f"), + NrgMbsParam.state, NrgMbsParam.phase, EnergyModbus->ReceiveCount(), buffer, + NrgMbsReg[NrgMbsParam.state].datatype, NrgMbsReg[NrgMbsParam.state].factor, &value); + switch (NrgMbsParam.state) { case NRG_MBS_VOLTAGE: Energy.voltage[NrgMbsParam.phase] = value; // 230.2 V From e5fd35ba854131fd370102af91e53d6e6c55528a Mon Sep 17 00:00:00 2001 From: Stefan Oskamp <57906326+stefan-oskamp@users.noreply.github.com> Date: Sat, 31 Dec 2022 09:19:53 +0100 Subject: [PATCH 071/262] Added: Driver xdsp_20_tm1650 for I2C-based seven-segment LED controller TM1650. (#17549) Co-authored-by: Stefan Oskamp --- I2CDEVICES.md | 1 + tasmota/tasmota_support/support_features.ino | 4 +- .../tasmota_xdsp_display/xdsp_20_tm1650.ino | 331 ++++++++++++++++++ 3 files changed, 335 insertions(+), 1 deletion(-) create mode 100644 tasmota/tasmota_xdsp_display/xdsp_20_tm1650.ino diff --git a/I2CDEVICES.md b/I2CDEVICES.md index 69551ee2e..744c3ccbf 100644 --- a/I2CDEVICES.md +++ b/I2CDEVICES.md @@ -108,3 +108,4 @@ Index | Define | Driver | Device | Address(es) | Description 71 | USE_QMC5883L | xsns_33 | QMC5883L | 0x0D | Magnetic Field Sensor 72 | USE_INA3221 | xsns_100 | INA3221 | 0x40-0x43 | 3-channels Voltage and Current sensor 73 | USE_HMC5883L | xsns_101 | HMC5883L | 0x1E | 3-channels Magnetic Field Sensor + 74 | USE_DISPLAY_TM1650 | xdsp_20 | TM1650 | 0x24 - 0x27, 0x34 - 0x37 | Four-digit seven-segment LED controller diff --git a/tasmota/tasmota_support/support_features.ino b/tasmota/tasmota_support/support_features.ino index fa6b4c336..bf698bbbb 100644 --- a/tasmota/tasmota_support/support_features.ino +++ b/tasmota/tasmota_support/support_features.ino @@ -861,8 +861,10 @@ void ResponseAppendFeatures(void) #ifdef USE_ME007 feature9 |= 0x00000800; // xsns_23_me007.ino #endif +#if defined(USE_I2C) && defined(USE_DISPLAY) && defined(USE_DISPLAY_TM1650) + feature9 |= 0x00001000; // xdsp_20_tm1650.ino +#endif -// feature9 |= 0x00001000; // feature9 |= 0x00002000; // feature9 |= 0x00004000; // feature9 |= 0x00008000; diff --git a/tasmota/tasmota_xdsp_display/xdsp_20_tm1650.ino b/tasmota/tasmota_xdsp_display/xdsp_20_tm1650.ino new file mode 100644 index 000000000..2b2e3799a --- /dev/null +++ b/tasmota/tasmota_xdsp_display/xdsp_20_tm1650.ino @@ -0,0 +1,331 @@ +/* + xdsp_20_tm1650.ino - TM1650 four-digit seven-segment LED display controller support for Tasmota + + Copyright (C) 2021 Stefan Oskamp, Theo Arends, Anatoli Arkhipenko + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/* + The TM1650 chip is a controller for a four digit seven-segment (plus dot) LED display. + It uses eight I2C addresses; four to control the digits and four to display content. + The addresses are not configurable: 0x24...0x27, 0x34...0x37 + There is a Chinese datasheet on the Internet and a machine translation to English. + The Controller also supports reading a keyboard matrix of 4 x 8 keys. This is not + supported by this driver. + The TM1650 is found in clocks with seven-segment LED displays, e.g., the "XY-Clock". + In this clock, the dots of the display are connected to the controller in an unintuitive + way. While digits are counted from left to right, the associated dots on the display + are: 0 = rightmost dot, 1 = dot after third digit, 2 = upper half of the colon + 3 = lower half of the column. The dots after the first and second digits are not + connected. This wiring of the XY-Clock has been reflected in the time format. Other + clocks using a TM1650 might be wired differently. +*/ +#ifdef USE_I2C +#ifdef USE_DISPLAY +#ifdef USE_DISPLAY_TM1650 + +#include + +#define XDSP_20 20 +#define XI2C_74 74 // See I2CDEVICES.md + +#define TM1650_CONTROL_BASE 0x24 // I2C address to control left-most digit. +#define TM1650_DISPLAY_BASE 0x34 // I2C address to display something in the left-most digit. +#define TM1650_DIGITS 4 // One TM1650 can only control modules with up to four digits. + +// TM1650 Display bits: +#define TM1650_DISPLAY_DOT 7 + +// TM1650 Control bits: +#define TM1650_CONTROL_ON 0 +#define TM1650_CONTROL_RESERVED1 1 +#define TM1650_CONTROL_RESERVED2 2 +#define TM1650_CONTROL_DOT 3 // Dots can be switched on/off with both control and display. +#define TM1650_CONTROL_BRIGHTNESS 4 // Bits 4...6 +#define TM1650_CONTROL_RESERVED3 7 + + +static unsigned char TM1650Control[TM1650_DIGITS] = {0, 0, 0, 0}; +static unsigned char TM1650Display[TM1650_DIGITS] = {0, 0, 0, 0}; + +static const byte TM1650Font[128] { +//0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x00 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x10 + 0x00, 0x82, 0x21, 0x00, 0x00, 0x00, 0x00, 0x02, 0x39, 0x0F, 0x00, 0x00, 0x00, 0x40, 0x80, 0x00, // 0x20 + 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7f, 0x6f, 0x00, 0x00, 0x00, 0x48, 0x00, 0x53, // 0x30 + 0x00, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71, 0x6F, 0x76, 0x06, 0x1E, 0x00, 0x38, 0x00, 0x54, 0x3F, // 0x40 + 0x73, 0x67, 0x50, 0x6D, 0x78, 0x3E, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x39, 0x00, 0x0F, 0x00, 0x08, // 0x50 + 0x63, 0x5F, 0x7C, 0x58, 0x5E, 0x7B, 0x71, 0x6F, 0x74, 0x02, 0x1E, 0x00, 0x06, 0x00, 0x54, 0x5C, // 0x60 + 0x73, 0x67, 0x50, 0x6D, 0x78, 0x1C, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x39, 0x30, 0x0F, 0x00, 0x00 // 0x70 +}; + + +/*********************************************************************************************/ + +void TM1650InitMode(void) +{ + TM1650Dim(); + TM1650Clear(); +} // void TM1650InitMode(void) + +void TM1650Init(uint8_t mode) +{ + switch(mode) { + case DISPLAY_INIT_MODE: + TM1650InitMode(); + break; + case DISPLAY_INIT_PARTIAL: + case DISPLAY_INIT_FULL: + TM1650InitMode(); + break; + } +} // void TM1650Init(uint8_t mode) + +void TM1650InitDriver(void) +{ + // AddLog(LOG_LEVEL_DEBUG, PSTR("M1650InitDriver()")); + if (!TasmotaGlobal.i2c_enabled) { + return; + } + + if (!Settings->display_model) { + if (I2cSetDevice(TM1650_CONTROL_BASE)) { + Settings->display_address[0] = TM1650_CONTROL_BASE; + Settings->display_model = XDSP_20; + } + } + + if (XDSP_20 == Settings->display_model) { + I2cSetActiveFound(Settings->display_address[0], "TM1650"); + + Settings->display_cols[0] = 4; + Settings->display_cols[0] = 1; + Settings->display_width = Settings->display_cols[0]; + Settings->display_height = Settings->display_rows; + + TM1650InitMode(); + + AddLog(LOG_LEVEL_INFO, PSTR("DSP: TM1650")); + } +} // void TM1650InitDriver(void) + +void TM1650DisplayOn () +{ + // AddLog(LOG_LEVEL_DEBUG, PSTR("TM1650DisplayOn()")); + for (int i = 0; i < TM1650_DIGITS; i++) { + TM1650Control[i] |= _BV(TM1650_CONTROL_ON); + Wire.beginTransmission(TM1650_CONTROL_BASE + i); + Wire.write(TM1650Control[i]); + Wire.endTransmission(); + } +} // void TM1650DisplayOn () + +void TM1650DisplayOff () +{ + // AddLog(LOG_LEVEL_DEBUG, PSTR("TM1650DisplayOff()")); + for (int i = 0; i < TM1650_DIGITS; i++) { + TM1650Control[i] &= ~_BV(TM1650_CONTROL_ON); + Wire.beginTransmission(TM1650_CONTROL_BASE + i); + Wire.write(TM1650Control[i]); + Wire.endTransmission(); + } +} // void TM1650DisplayOff () + +void TM1650DisplayOnOff() +{ + if (disp_power) { + TM1650DisplayOn(); + } + else { + TM1650DisplayOff(); + } +} // void TM1650DisplayOnOff() + +void TM1650SetBrightness (unsigned int level) +{ + // AddLog(LOG_LEVEL_DEBUG, PSTR("TM1650SetBrightness()")); + if (level > 0b111) level = 0b111; + + for (int i = 0; i < TM1650_DIGITS; i++) { + TM1650Control[i] = TM1650Control[i] & ~(0b111 << TM1650_CONTROL_BRIGHTNESS) | level << TM1650_CONTROL_BRIGHTNESS; + Wire.beginTransmission(TM1650_CONTROL_BASE + i); + Wire.write(TM1650Control[i]); + Wire.endTransmission(); + } +} // void TM1650SetBrightness (unsigned int level) + +void TM1650Dim(void) +{ + int b = GetDisplayDimmer16(); + if (b < 2) { + TM1650DisplayOff(); + } + else if (b > 14) { + TM1650DisplayOn(); + TM1650SetBrightness(0); // In TM1650, brightness 0 means max brightness (level 8). + TM1650DisplayOn(); + } + else { + // Map 2...14 to 1...7: + TM1650SetBrightness(b >> 1); + TM1650DisplayOn(); + } +} // void TM1650Dim(void) + +void TM1650Clear (void) +{ + // AddLog(LOG_LEVEL_DEBUG, PSTR("TM1650Clear()")); + for (int i = 0; i < TM1650_DIGITS; i++) { + TM1650Display[i] = 0; + Wire.beginTransmission(TM1650_DISPLAY_BASE + i); + Wire.write(TM1650Display[i]); + Wire.endTransmission(); + } +} // void TM1650Clear (void) + +void TM1650DisplayText (char *text) // Text shall match regex (([^.]?\.?){0,4}\0), e.g., 123.4 +{ + // AddLog(LOG_LEVEL_DEBUG, PSTR("TM1650DisplayText(\"%s\")"), text); + for (int i = 0; i < TM1650_DIGITS; i++) { + if (*text != 0) { + if (*text == '.') { + TM1650Display[i] = 0; // Blank this digit, set the dot below. + } + else { // Something to display. + char c = *text++; + TM1650Display[i] = TM1650Font[c & ~_BV(TM1650_DISPLAY_DOT)]; + } + + if (*text == '.') { + char c = *text++; + TM1650Display[i] |= _BV(TM1650_DISPLAY_DOT); + } + } // if (not at end of text) + else { // No more text. + TM1650Display[i] = 0; // Clear digits after the text. + } + Wire.beginTransmission(TM1650_DISPLAY_BASE + i); + Wire.write(TM1650Display[i]); + Wire.endTransmission(); + } // for (all digits) +} // void TM1650DisplayText (char *text) + +void TM1650Time(void) +{ + // AddLog(LOG_LEVEL_DEBUG, PSTR("TM1650Time()")); + char text[TM1650_DIGITS + 2 + 1]; + int i = 0; + + text[i++] = '0' + RtcTime.hour / 10; + text[i++] = '0' + RtcTime.hour % 10; + text[i++] = '0' + RtcTime.minute / 10; + text[i++] = '.'; // Lower half of the colon, depending on how the LEDs are connected to the TM1650 in the XY-Clock. + text[i++] = '0' + RtcTime.minute % 10; + text[i++] = '.'; // Upper half of the colon. + text[i++] = 0; + + TM1650DisplayText(text); +} // void TM1650Time(void) + +void TM1650Refresh(void) // Every second +{ + if (Settings->display_mode) { // Mode 0 is User text + switch (Settings->display_mode) { + case 1: // Time + TM1650Time(); + break; + case 2: // Local + case 4: // Mqtt + // TM1650PrintLog(); + break; + case 3: // Local + case 5: +// // Mqtt +// if (!TM1650PrintLog()) { +// TM1650Time(); +// } + break; + } + } +} // void TM1650Refresh(void) + + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xdsp20(uint32_t function) +{ + if (!I2cEnabled(XI2C_74)) { return false; } + + bool result = false; + + if (FUNC_DISPLAY_INIT_DRIVER == function) { + TM1650InitDriver(); + } + else if (XDSP_20 == Settings->display_model) { + switch (function) { + case FUNC_DISPLAY_MODEL: + result = true; + break; + case FUNC_DISPLAY_INIT: + TM1650Init(dsp_init); + break; + case FUNC_DISPLAY_POWER: + TM1650DisplayOnOff(); + break; + case FUNC_DISPLAY_DIM: + TM1650Dim(); + break; + case FUNC_DISPLAY_CLEAR: + TM1650Clear(); + break; + case FUNC_DISPLAY_DRAW_STRING: + TM1650DisplayText(dsp_str); + break; +#ifdef USE_DISPLAY_MODES1TO5 + case FUNC_DISPLAY_EVERY_SECOND: + TM1650Refresh(); + break; +#endif // USE_DISPLAY_MODES1TO5 +// case FUNC_DISPLAY_DRAW_HLINE: +// break; +// case FUNC_DISPLAY_DRAW_VLINE: +// break; +// case FUNC_DISPLAY_DRAW_CIRCLE: +// break; +// case FUNC_DISPLAY_FILL_CIRCLE: +// break; +// case FUNC_DISPLAY_DRAW_RECTANGLE: +// break; +// case FUNC_DISPLAY_FILL_RECTANGLE: +// break; +// case FUNC_DISPLAY_DRAW_FRAME: +// break; +// case FUNC_DISPLAY_TEXT_SIZE: +// break; +// case FUNC_DISPLAY_FONT_SIZE: +// break; +// case FUNC_DISPLAY_ROTATION: +// break; + } // switch (function) + } // else if (display model matches) + return result; +} // bool Xdsp20(uint32_t function) + +#endif // USE_DISPLAY_TM1650 +#endif // USE_DISPLAY +#endif // USE_I2C From 04c90dc67d96da4b219e4b043cf32bf1e1c1ddc3 Mon Sep 17 00:00:00 2001 From: Alexey Baturin Date: Sat, 31 Dec 2022 12:45:59 +0100 Subject: [PATCH 072/262] Add alternative wiring of TM1650 (#17556) 303WIFILC01 model of clock used different wiring which needs remapping --- .../tasmota_xdsp_display/xdsp_20_tm1650.ino | 39 ++++++++++++++++--- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/tasmota/tasmota_xdsp_display/xdsp_20_tm1650.ino b/tasmota/tasmota_xdsp_display/xdsp_20_tm1650.ino index 2b2e3799a..1d7540895 100644 --- a/tasmota/tasmota_xdsp_display/xdsp_20_tm1650.ino +++ b/tasmota/tasmota_xdsp_display/xdsp_20_tm1650.ino @@ -72,6 +72,24 @@ static const byte TM1650Font[128] { 0x73, 0x67, 0x50, 0x6D, 0x78, 0x1C, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x39, 0x30, 0x0F, 0x00, 0x00 // 0x70 }; +const uint8_t TM1650Remap[] = { + 0x00, 0x20, 0x80, 0xA0, 0x04, 0x24, 0x84, 0xA4, 0x08, 0x28, 0x88, 0xA8, 0x0C, 0x2C, 0x8C, 0xAC, + 0x10, 0x30, 0x90, 0xB0, 0x14, 0x34, 0x94, 0xB4, 0x18, 0x38, 0x98, 0xB8, 0x1C, 0x3C, 0x9C, 0xBC, + 0x40, 0x60, 0xC0, 0xE0, 0x44, 0x64, 0xC4, 0xE4, 0x48, 0x68, 0xC8, 0xE8, 0x4C, 0x6C, 0xCC, 0xEC, + 0x50, 0x70, 0xD0, 0xF0, 0x54, 0x74, 0xD4, 0xF4, 0x58, 0x78, 0xD8, 0xF8, 0x5C, 0x7C, 0xDC, 0xFC, + 0x02, 0x22, 0x82, 0xA2, 0x06, 0x26, 0x86, 0xA6, 0x0A, 0x2A, 0x8A, 0xAA, 0x0E, 0x2E, 0x8E, 0xAE, + 0x12, 0x32, 0x92, 0xB2, 0x16, 0x36, 0x96, 0xB6, 0x1A, 0x3A, 0x9A, 0xBA, 0x1E, 0x3E, 0x9E, 0xBE, + 0x42, 0x62, 0xC2, 0xE2, 0x46, 0x66, 0xC6, 0xE6, 0x4A, 0x6A, 0xCA, 0xEA, 0x4E, 0x6E, 0xCE, 0xEE, + 0x52, 0x72, 0xD2, 0xF2, 0x56, 0x76, 0xD6, 0xF6, 0x5A, 0x7A, 0xDA, 0xFA, 0x5E, 0x7E, 0xDE, 0xFE, + 0x01, 0x21, 0x81, 0xA1, 0x05, 0x25, 0x85, 0xA5, 0x09, 0x29, 0x89, 0xA9, 0x0D, 0x2D, 0x8D, 0xAD, + 0x11, 0x31, 0x91, 0xB1, 0x15, 0x35, 0x95, 0xB5, 0x19, 0x39, 0x99, 0xB9, 0x1D, 0x3D, 0x9D, 0xBD, + 0x41, 0x61, 0xC1, 0xE1, 0x45, 0x65, 0xC5, 0xE5, 0x49, 0x69, 0xC9, 0xE9, 0x4D, 0x6D, 0xCD, 0xED, + 0x51, 0x71, 0xD1, 0xF1, 0x55, 0x75, 0xD5, 0xF5, 0x59, 0x79, 0xD9, 0xF9, 0x5D, 0x7D, 0xDD, 0xFD, + 0x03, 0x23, 0x83, 0xA3, 0x07, 0x27, 0x87, 0xA7, 0x0B, 0x2B, 0x8B, 0xAB, 0x0F, 0x2F, 0x8F, 0xAF, + 0x13, 0x33, 0x93, 0xB3, 0x17, 0x37, 0x97, 0xB7, 0x1B, 0x3B, 0x9B, 0xBB, 0x1F, 0x3F, 0x9F, 0xBF, + 0x43, 0x63, 0xC3, 0xE3, 0x47, 0x67, 0xC7, 0xE7, 0x4B, 0x6B, 0xCB, 0xEB, 0x4F, 0x6F, 0xCF, 0xEF, + 0x53, 0x73, 0xD3, 0xF3, 0x57, 0x77, 0xD7, 0xF7, 0x5B, 0x7B, 0xDB, 0xFB, 0x5F, 0x7F, 0xDF, 0xFF +}; /*********************************************************************************************/ @@ -213,6 +231,10 @@ void TM1650DisplayText (char *text) // Text shall match regex (([^.]?\.?){0,4}\ char c = *text++; TM1650Display[i] |= _BV(TM1650_DISPLAY_DOT); } + + if (Settings->display_options.type == 2) { + TM1650Display[i] = TM1650Remap[TM1650Display[i]]; // 303WIFILC01 board has special wiring + } } // if (not at end of text) else { // No more text. TM1650Display[i] = 0; // Clear digits after the text. @@ -231,11 +253,18 @@ void TM1650Time(void) text[i++] = '0' + RtcTime.hour / 10; text[i++] = '0' + RtcTime.hour % 10; - text[i++] = '0' + RtcTime.minute / 10; - text[i++] = '.'; // Lower half of the colon, depending on how the LEDs are connected to the TM1650 in the XY-Clock. - text[i++] = '0' + RtcTime.minute % 10; - text[i++] = '.'; // Upper half of the colon. - text[i++] = 0; + + if (Settings->display_options.type == 2) { + text[i++] = '.'; // Colon for 303WIFILC01 + text[i++] = '0' + RtcTime.minute / 10; + text[i++] = '0' + RtcTime.minute % 10; + } + else { + text[i++] = '0' + RtcTime.minute / 10; + text[i++] = '.'; // Lower half of the colon, depending on how the LEDs are connected to the TM1650 in the XY-Clock. + text[i++] = '0' + RtcTime.minute % 10; + text[i++] = '.'; // Upper half of the colon. + } TM1650DisplayText(text); } // void TM1650Time(void) From 20a50ffc2e43e929be3f363413497f05d964ddc1 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sat, 31 Dec 2022 16:08:59 +0100 Subject: [PATCH 073/262] Revert Tuya rewrite - Update changelogs --- BUILDS.md | 1 + CHANGELOG.md | 4 +++- RELEASENOTES.md | 1 + tasmota/include/tasmota_configurations.h | 3 ++- tasmota/my_user_config.h | 3 ++- tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v1.ino | 2 +- tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v2.ino | 2 +- tools/decode-status.py | 4 ++-- 8 files changed, 13 insertions(+), 7 deletions(-) diff --git a/BUILDS.md b/BUILDS.md index f724c74bd..d17b57901 100644 --- a/BUILDS.md +++ b/BUILDS.md @@ -246,6 +246,7 @@ Note: `minimal` variant is not listed as it shouldn't be used outside of the [up | USE_DISPLAY_ST7789 | - | - / - | - | - | - | x | | USE_DISPLAY_TM1637 | - | - / - | - | - | - | x | | USE_DISPLAY_TM1621_SONOFF | - | - / x | - | - | - | - | +| USE_DISPLAY_TM1650 | - | - / - | - | - | - | - | | | | | | | | | | USE_FT5206 | - | - / - | - | - | - | - | | USE_FTC532 | - | - / - | - | - | - | - | diff --git a/CHANGELOG.md b/CHANGELOG.md index 755e1e9b2..352670ca5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,13 +11,15 @@ All notable changes to this project will be documented in this file. - Support for up to 3 single phase modbus energy monitoring device using generic Energy Modbus driver - Berry crypto add ``SPAKE2P_Matter`` for Matter support - Support for IPv6 only networks on Ethernet (not yet Wifi) +- Support for TM1650 display as used in some clocks by Stefan Oskamp (#17594) ### Breaking Changed ### Changed - ESP32 Framework (Core) from v2.0.5.4 to v2.0.6 (IPv6 support) - Tasmota OTA scripts now support both unzipped and gzipped file uploads (#17378) -- Change NTP default servers to dual-stack (IPv4/IPv6) +- NTP default servers to dual-stack (IPv4/IPv6) +- Revert TuyaMcu rewrite by btsimonh as lack of support ### Fixed - Shutter default motorstop set to 0 (#17403) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 341ef87c1..7a76319aa 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -112,6 +112,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm - Support for up to 3 single phase modbus energy monitoring device using generic Energy Modbus driver- Support for RGB displays [#17414](https://github.com/arendst/Tasmota/issues/17414) - Support for IPv6 DNS records (AAAA) and IPv6 ``Ping`` for ESP32 and ESP8266 [#17417](https://github.com/arendst/Tasmota/issues/17417) - Support for IPv6 only networks on Ethernet (not yet Wifi) +- Support for TM1650 display as used in some clocks by Stefan Oskamp [#17594](https://github.com/arendst/Tasmota/issues/17594) - Berry support for ``crypto.SHA256`` [#17430](https://github.com/arendst/Tasmota/issues/17430) - Berry crypto add ``EC_P256`` and ``PBKDF2_HMAC_SHA256`` algorithms required by Matter protocol [#17473](https://github.com/arendst/Tasmota/issues/17473) - Berry crypto add ``random`` to generate series of random bytes diff --git a/tasmota/include/tasmota_configurations.h b/tasmota/include/tasmota_configurations.h index e425b018a..57de1b8ab 100644 --- a/tasmota/include/tasmota_configurations.h +++ b/tasmota/include/tasmota_configurations.h @@ -330,7 +330,7 @@ #define USE_DISPLAY // Add Display Support (+2k code) #define USE_DISPLAY_TM1637 // [DisplayModel 15] Enable TM1637 module - #define USE_DISPLAY_MAX7219 // [DisplayModel 16] Enable MAX7219 7-segment module + #define USE_DISPLAY_MAX7219 // [DisplayModel 19] Enable MAX7219 7-segment module #define USE_I2C // I2C using library wire (+10k code, 0k2 mem, 124 iram) #define USE_DISPLAY_MODES1TO5 // Enable display mode 1 to 5 in addition to mode 0 @@ -339,6 +339,7 @@ #define USE_DISPLAY_MATRIX // [DisplayModel 3] Enable 8x8 Matrix display (I2C adresseses see below) (+11k code) #define USE_DISPLAY_SEVENSEG // [DisplayModel 11] [I2cDriver47] Enable sevenseg display (I2C addresses 0x70 - 0x77) (<+11k code) #define USE_DISPLAY_SH1106 // [DisplayModel 7] Enable SH1106 Oled 128x64 display (I2C addresses 0x3C and 0x3D) +// #define USE_DISPLAY_TM1650 // [DisplayModel 20] [I2cDriver74] Enable TM1650 display (I2C addresses 0x24 - 0x27 and 0x34 - 0x37) #define USE_SPI // Hardware SPI using GPIO12(MISO), GPIO13(MOSI) and GPIO14(CLK) in addition to two user selectable GPIOs(CS and DC) #define USE_DISPLAY_ILI9341 // [DisplayModel 4] Enable ILI9341 Tft 480x320 display (+19k code) diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index 35296863d..4fe411b69 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -738,6 +738,7 @@ // Reference: https://cdn-learn.adafruit.com/downloads/pdf/adafruit-led-backpack.pdf // #define SEVENSEG_ADDRESS1 0x70 // No longer used. Use MTX_ADDRESS1 - MTX_ADDRESS8 instead to specify I2C address of sevenseg displays // #define USE_DISPLAY_SH1106 // [DisplayModel 7] [I2cDriver6] Enable SH1106 Oled 128x64 display (I2C addresses 0x3C and 0x3D) +// #define USE_DISPLAY_TM1650 // [DisplayModel 20] [I2cDriver74] Enable TM1650 display (I2C addresses 0x24 - 0x27 and 0x34 - 0x37) // #define USE_DT_VARS // Display variables that are exposed in JSON MQTT strings e.g. in TelePeriod messages. // #define MAX_DT_VARS 16 // Defaults to 7 // #define USE_GRAPH // Enable line charts with displays @@ -747,7 +748,7 @@ // #define USE_DISPLAY // Add I2C/TM1637/MAX7219 Display Support (+2k code) // #define USE_DISPLAY_TM1637 // [DisplayModel 15] Enable TM1637 Module -// #define USE_DISPLAY_MAX7219 // [DisplayModel 15] Enable MAX7219 Module +// #define USE_DISPLAY_MAX7219 // [DisplayModel 19] Enable MAX7219 Module // -- Universal Display Driver --------------------------------- // #define USE_UNIVERSAL_DISPLAY // New universal display driver for both I2C and SPI diff --git a/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v1.ino b/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v1.ino index 6bd5a655e..e4bb6b01a 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v1.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v1.ino @@ -18,7 +18,7 @@ */ #ifdef USE_LIGHT -#ifdef USE_TUYA_MCU_V1 +#ifdef USE_TUYA_MCU /*********************************************************************************************\ * Tuya MCU V1 \*********************************************************************************************/ diff --git a/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v2.ino b/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v2.ino index 969235e71..b0bc5e6aa 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v2.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v2.ino @@ -18,7 +18,7 @@ */ #ifdef USE_LIGHT -#ifdef USE_TUYA_MCU +#ifdef USE_TUYA_MCU_V2 /*********************************************************************************************\ * Tuya MCU V2 diff --git a/tools/decode-status.py b/tools/decode-status.py index a67a9f617..64177ba48 100755 --- a/tools/decode-status.py +++ b/tools/decode-status.py @@ -289,7 +289,7 @@ a_features = [[ "USE_SGP40","USE_LUXV30B","USE_CANSNIFFER","USE_QMC5883L", "USE_MODBUS_ENERGY","USE_SHELLY_PRO","USE_DALI","USE_BP1658CJ", "USE_DINGTIAN_RELAY","USE_HMC5883L","USE_LD2410","USE_ME007", - "","","","", + "USE_DISPLAY_TM1650","","","", "","","","", "","","","", "","","","", @@ -321,7 +321,7 @@ else: obj = json.load(fp) def StartDecode(): - print ("\n*** decode-status.py v12.2.0.5 by Theo Arends and Jacek Ziolkowski ***") + print ("\n*** decode-status.py v12.3.1.2 by Theo Arends and Jacek Ziolkowski ***") # print("Decoding\n{}".format(obj)) From a334826906f5146dc4f50baa603003b500fedf99 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Sat, 31 Dec 2022 16:51:53 +0100 Subject: [PATCH 074/262] fix board type --- platformio_tasmota_cenv_sample.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio_tasmota_cenv_sample.ini b/platformio_tasmota_cenv_sample.ini index 39339e4cc..40d9afadf 100644 --- a/platformio_tasmota_cenv_sample.ini +++ b/platformio_tasmota_cenv_sample.ini @@ -168,7 +168,7 @@ monitor_filters = esp32_exception_decoder [env:tasmota32c3cdc-ocd] build_type = debug extends = env:tasmota32c3 -board = esp32c3cdc-qio_opi +board = esp32c3cdc debug_tool = esp-builtin upload_protocol = esp-builtin debug_init_break = tbreak setup From ca82877362baf44906e578024f3024c700e93ee7 Mon Sep 17 00:00:00 2001 From: gemu Date: Sun, 1 Jan 2023 09:54:17 +0100 Subject: [PATCH 075/262] fix multiple subscribes (#17567) --- tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino | 5 +- .../tasmota_xdrv_driver/xdrv_10_scripter.ino | 89 ++----------------- 2 files changed, 9 insertions(+), 85 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino b/tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino index 6f9003d70..4b3848e50 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino @@ -1159,11 +1159,14 @@ bool RulesMqttData(void) } bool serviced = false; String sTopic = XdrvMailbox.topic; - String sData = XdrvMailbox.data; + String buData = XdrvMailbox.data; //AddLog(LOG_LEVEL_DEBUG, PSTR("RUL: MQTT Topic %s, Event %s"), XdrvMailbox.topic, XdrvMailbox.data); MQTT_Subscription event_item; //Looking for matched topic for (uint32_t index = 0; index < subscriptions.size(); index++) { + + String sData = buData; + event_item = subscriptions.get(index); //AddLog(LOG_LEVEL_DEBUG, PSTR("RUL: Match MQTT message Topic %s with subscription topic %s"), sTopic.c_str(), event_item.Topic.c_str()); diff --git a/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino b/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino index 3be9f834c..1e60baf1f 100755 --- a/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino @@ -8260,7 +8260,7 @@ bool ScriptCommand(void) { Response_P(S_JSON_COMMAND_SVALUE, command, result.c_str()); #ifdef DEBUG_MQTT_EVENT } else if (CMND_SUBTEST == command_code) { - XdrvMailbox.topic = (char*)"tele"; + XdrvMailbox.topic = (char*)"stat/tasmota/SENSOR"; ScriptMqttData(); serviced = true; #endif @@ -8291,92 +8291,12 @@ void dateTime(uint16_t* date, uint16_t* time) { #ifdef SUPPORT_MQTT_EVENT -/* -//#define DEBUG_MQTT_EVENT -// parser object, source keys, delimiter, float result or NULL, string result or NULL, string size -uint32_t JsonParsePath(JsonParserObject *jobj, const char *spath, char delim, float *nres, char *sres, uint32_t slen) { - uint32_t res = 0; - const char *cp = spath; -#ifdef DEBUG_JSON_PARSE_PATH - AddLog(LOG_LEVEL_INFO, PSTR("JSON: parsing json key: %s from json: %s"), cp, jpath); -#endif - JsonParserObject obj = *jobj; - JsonParserObject lastobj = obj; - char selem[32]; - uint8_t aindex = 0; - String value = ""; - while (1) { - // read next element - for (uint32_t sp=0; sp>> 1"); //toLog(XdrvMailbox.data); @@ -8396,7 +8315,7 @@ bool ScriptMqttData(void) return false; } String sTopic = XdrvMailbox.topic; - String sData = XdrvMailbox.data; + String buData = XdrvMailbox.data; #ifdef DEBUG_MQTT_EVENT AddLog(LOG_LEVEL_INFO, PSTR("Script: MQTT Topic %s, Event %s"), XdrvMailbox.topic, XdrvMailbox.data); @@ -8408,6 +8327,8 @@ bool ScriptMqttData(void) event_item = subscriptions.get(index); uint8_t json_valid = 0; + String sData = buData; + #ifdef DEBUG_MQTT_EVENT AddLog(LOG_LEVEL_INFO, PSTR("Script: Match MQTT message Topic %s with subscription topic %s and key %s"), sTopic.c_str(), event_item.Topic.c_str(),event_item.Key.c_str()); #endif From c63919d7831950463a158263cb9fc772f3166b5d Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 1 Jan 2023 11:32:30 +0100 Subject: [PATCH 076/262] Change Energy totals max supported value - Change Energy totals max supported value from +/-21474.83647 to +/-2147483.647 kWh - Bump version to v12.3.1.3 --- CHANGELOG.md | 18 +++-- RELEASENOTES.md | 3 +- tasmota/include/tasmota_version.h | 2 +- tasmota/tasmota_support/settings.ino | 14 ++++ .../tasmota_xdrv_driver/xdrv_03_energy.ino | 66 +++++++++---------- 5 files changed, 63 insertions(+), 40 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 352670ca5..aa65860d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,19 @@ All notable changes to this project will be documented in this file. ## [Unreleased] - Development -## [12.3.1.2] +## [12.3.1.3] +### Added + +### Breaking Changed + +### Changed +- Energy totals max supported value from +/-21474.83647 to +/-2147483.647 kWh + +### Fixed + +### Removed + +## [12.3.1.2] 20221231 ### Added - Berry crypto add ``EC_P256`` and ``PBKDF2_HMAC_SHA256`` algorithms required by Matter protocol - Berry crypto add ``random`` to generate series of random bytes @@ -13,8 +25,6 @@ All notable changes to this project will be documented in this file. - Support for IPv6 only networks on Ethernet (not yet Wifi) - Support for TM1650 display as used in some clocks by Stefan Oskamp (#17594) -### Breaking Changed - ### Changed - ESP32 Framework (Core) from v2.0.5.4 to v2.0.6 (IPv6 support) - Tasmota OTA scripts now support both unzipped and gzipped file uploads (#17378) @@ -27,8 +37,6 @@ All notable changes to this project will be documented in this file. - Modbus transmit enable GPIO enabled once during write buffer - ESP8266 set GPIO's to input on power on fixing relay spikes (#17531) -### Removed - ## [12.3.1.1] 20221221 ### Added - Support for IPv6 DNS records (AAAA) and IPv6 ``Ping`` for ESP32 and ESP8266 (#17417) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 7a76319aa..45d675c60 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -107,7 +107,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm [Complete list](BUILDS.md) of available feature and sensors. -## Changelog v12.3.1.2 +## Changelog v12.3.1.3 ### Added - Support for up to 3 single phase modbus energy monitoring device using generic Energy Modbus driver- Support for RGB displays [#17414](https://github.com/arendst/Tasmota/issues/17414) - Support for IPv6 DNS records (AAAA) and IPv6 ``Ping`` for ESP32 and ESP8266 [#17417](https://github.com/arendst/Tasmota/issues/17417) @@ -123,6 +123,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm ### Changed - ESP32 Framework (Core) from v2.0.5.3 to v2.0.6 (IPv6 support) +- Energy totals max supported value from +/-21474.83647 to +/-2147483.647 kWh - TuyaMcu rewrite by btsimonh [#17051](https://github.com/arendst/Tasmota/issues/17051) - Tasmota OTA scripts now support both unzipped and gzipped file uploads [#17378](https://github.com/arendst/Tasmota/issues/17378) diff --git a/tasmota/include/tasmota_version.h b/tasmota/include/tasmota_version.h index 1e40104cd..ff08a85fb 100644 --- a/tasmota/include/tasmota_version.h +++ b/tasmota/include/tasmota_version.h @@ -20,6 +20,6 @@ #ifndef _TASMOTA_VERSION_H_ #define _TASMOTA_VERSION_H_ -const uint32_t VERSION = 0x0C030102; // 12.3.1.2 +const uint32_t VERSION = 0x0C030103; // 12.3.1.3 #endif // _TASMOTA_VERSION_H_ diff --git a/tasmota/tasmota_support/settings.ino b/tasmota/tasmota_support/settings.ino index f5b568f72..cbc88be95 100644 --- a/tasmota/tasmota_support/settings.ino +++ b/tasmota/tasmota_support/settings.ino @@ -1614,6 +1614,20 @@ void SettingsDelta(void) { if (Settings->version < 0x0C030102) { // 12.3.1.2 Settings->shutter_motorstop = 0; } + if (Settings->version < 0x0C030103) { // 12.3.1.3 + for (uint32_t i = 0; i < 3; i++) { + RtcSettings.energy_kWhtotal_ph[i] /= 100; + Settings->energy_kWhtotal_ph[i] /= 100; + RtcSettings.energy_kWhexport_ph[i] /= 100; + Settings->energy_kWhexport_ph[i] /= 100; + RtcSettings.energy_usage.usage1_kWhtotal /= 100; + RtcSettings.energy_usage.usage2_kWhtotal /= 100; + RtcSettings.energy_usage.return1_kWhtotal /= 100; + RtcSettings.energy_usage.return2_kWhtotal /= 100; + RtcSettings.energy_usage.last_return_kWhtotal /= 100; + RtcSettings.energy_usage.last_usage_kWhtotal /= 100; + } + } Settings->version = VERSION; SettingsSave(1); diff --git a/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino b/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino index c934e4217..18c81a0c1 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino @@ -252,15 +252,15 @@ void EnergyUpdateToday(void) { Energy.kWhtoday_delta[i] -= (delta * 1000); Energy.kWhtoday[i] += delta; if (delta < 0) { // Export energy - RtcSettings.energy_kWhexport_ph[i] += (delta *-1); + RtcSettings.energy_kWhexport_ph[i] += ((delta / 100) *-1); } } RtcSettings.energy_kWhtoday_ph[i] = Energy.kWhtoday_offset[i] + Energy.kWhtoday[i]; Energy.daily[i] = (float)(RtcSettings.energy_kWhtoday_ph[i]) / 100000; - Energy.total[i] = (float)(RtcSettings.energy_kWhtotal_ph[i] + RtcSettings.energy_kWhtoday_ph[i]) / 100000; + Energy.total[i] = ((float)(RtcSettings.energy_kWhtotal_ph[i]) / 1000) + ((float)(RtcSettings.energy_kWhtoday_ph[i]) / 100000); if (Energy.local_energy_active_export) { - Energy.export_active[i] = (float)(RtcSettings.energy_kWhexport_ph[i]) / 100000; + Energy.export_active[i] = (float)(RtcSettings.energy_kWhexport_ph[i]) / 1000; } Energy.total_sum += Energy.total[i]; @@ -276,13 +276,13 @@ void EnergyUpdateToday(void) { if (RtcTime.valid){ // We calc the difference only if we have a valid RTC time. - uint32_t energy_diff = (uint32_t)(Energy.total_sum * 100000) - RtcSettings.energy_usage.last_usage_kWhtotal; - RtcSettings.energy_usage.last_usage_kWhtotal = (uint32_t)(Energy.total_sum * 100000); + uint32_t energy_diff = (uint32_t)(Energy.total_sum * 1000) - RtcSettings.energy_usage.last_usage_kWhtotal; + RtcSettings.energy_usage.last_usage_kWhtotal = (uint32_t)(Energy.total_sum * 1000); uint32_t return_diff = 0; if (!isnan(Energy.export_active[0])) { -// return_diff = (uint32_t)(Energy.export_active * 100000) - RtcSettings.energy_usage.last_return_kWhtotal; -// RtcSettings.energy_usage.last_return_kWhtotal = (uint32_t)(Energy.export_active * 100000); +// return_diff = (uint32_t)(Energy.export_active * 1000) - RtcSettings.energy_usage.last_return_kWhtotal; +// RtcSettings.energy_usage.last_return_kWhtotal = (uint32_t)(Energy.export_active * 1000); float export_active = 0.0f; for (uint32_t i = 0; i < Energy.phase_count; i++) { @@ -290,8 +290,8 @@ void EnergyUpdateToday(void) { export_active += Energy.export_active[i]; } } - return_diff = (uint32_t)(export_active * 100000) - RtcSettings.energy_usage.last_return_kWhtotal; - RtcSettings.energy_usage.last_return_kWhtotal = (uint32_t)(export_active * 100000); + return_diff = (uint32_t)(export_active * 1000) - RtcSettings.energy_usage.last_return_kWhtotal; + RtcSettings.energy_usage.last_return_kWhtotal = (uint32_t)(export_active * 1000); } if (EnergyTariff1Active()) { // Tarrif1 = Off-Peak @@ -311,18 +311,18 @@ void EnergyUpdateTotal(void) { AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("NRG: EnergyTotal[%d] %4_f kWh"), i, &Energy.import_active[i]); if (0 == Energy.start_energy[i] || (Energy.import_active[i] < Energy.start_energy[i])) { - Energy.start_energy[i] = Energy.import_active[i]; // Init after restart and handle roll-over if any + Energy.start_energy[i] = Energy.import_active[i]; // Init after restart and handle roll-over if any } else if (Energy.import_active[i] != Energy.start_energy[i]) { Energy.kWhtoday[i] = (int32_t)((Energy.import_active[i] - Energy.start_energy[i]) * 100000); } if ((Energy.total[i] < (Energy.import_active[i] - 0.01f)) && // We subtract a little offset to avoid continuous updates - Settings->flag3.hardware_energy_total) { // SetOption72 - Enable hardware energy total counter as reference (#6561) - // The following calculation allows total usage (Energy.import_active[i]) up to +/-21474 kWh - RtcSettings.energy_kWhtotal_ph[i] = (int32_t)((Energy.import_active[i] * 100000) - Energy.kWhtoday_offset[i] - Energy.kWhtoday[i]); + Settings->flag3.hardware_energy_total) { // SetOption72 - Enable hardware energy total counter as reference (#6561) + // The following calculation allows total usage (Energy.import_active[i]) up to +/-2147483.647 kWh + RtcSettings.energy_kWhtotal_ph[i] = (int32_t)((Energy.import_active[i] * 1000) - ((Energy.kWhtoday_offset[i] + Energy.kWhtoday[i]) / 100)); Settings->energy_kWhtotal_ph[i] = RtcSettings.energy_kWhtotal_ph[i]; - Energy.total[i] = (float)(RtcSettings.energy_kWhtotal_ph[i] + Energy.kWhtoday_offset[i] + Energy.kWhtoday[i]) / 100000; + Energy.total[i] = Energy.import_active[i]; Settings->energy_kWhtotal_time = (!Energy.kWhtoday_offset[i]) ? LocalTime() : Midnight(); // AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Energy Total updated with hardware value")); } @@ -357,7 +357,7 @@ void Energy200ms(void) for (uint32_t i = 0; i < 3; i++) { Settings->energy_kWhyesterday_ph[i] = RtcSettings.energy_kWhtoday_ph[i]; - RtcSettings.energy_kWhtotal_ph[i] += RtcSettings.energy_kWhtoday_ph[i]; + RtcSettings.energy_kWhtotal_ph[i] += (RtcSettings.energy_kWhtoday_ph[i] / 100); Settings->energy_kWhtotal_ph[i] = RtcSettings.energy_kWhtotal_ph[i]; Settings->energy_kWhexport_ph[i] = RtcSettings.energy_kWhexport_ph[i]; @@ -652,9 +652,9 @@ void ResponseCmndEnergyTotalYesterdayToday(void) { float energy_yesterday_ph[3]; for (uint32_t i = 0; i < Energy.phase_count; i++) { energy_yesterday_ph[i] = (float)Settings->energy_kWhyesterday_ph[i] / 100000; - Energy.total[i] = (float)(RtcSettings.energy_kWhtotal_ph[i] + Energy.kWhtoday_offset[i] + Energy.kWhtoday[i]) / 100000; + Energy.total[i] = ((float)(RtcSettings.energy_kWhtotal_ph[i]) / 1000) + ((float)(Energy.kWhtoday_offset[i] + Energy.kWhtoday[i]) / 100000); if (Energy.local_energy_active_export) { - Energy.export_active[i] = (float)(RtcSettings.energy_kWhexport_ph[i]) / 100000; + Energy.export_active[i] = (float)(RtcSettings.energy_kWhexport_ph[i]) / 1000; } } @@ -677,7 +677,7 @@ void CmndEnergyTotal(void) { if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= Energy.phase_count) && (params > 0)) { uint32_t phase = XdrvMailbox.index -1; // Reset Energy Total - RtcSettings.energy_kWhtotal_ph[phase] = values[0] * 100; + RtcSettings.energy_kWhtotal_ph[phase] = values[0]; Settings->energy_kWhtotal_ph[phase] = RtcSettings.energy_kWhtotal_ph[phase]; if (params > 1) { Settings->energy_kWhtotal_time = values[1]; @@ -739,7 +739,7 @@ void CmndEnergyExportActive(void) { if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= Energy.phase_count) && (params > 0)) { uint32_t phase = XdrvMailbox.index -1; // Reset Energy Export Active - RtcSettings.energy_kWhexport_ph[phase] = values[0] * 100; + RtcSettings.energy_kWhexport_ph[phase] = values[0]; Settings->energy_kWhexport_ph[phase] = RtcSettings.energy_kWhexport_ph[phase]; if (params > 1) { Settings->energy_kWhtotal_time = values[1]; @@ -750,10 +750,10 @@ void CmndEnergyExportActive(void) { } void ResponseCmndEnergyUsageExport(void) { - float usage1_kWhtotal = (float)Settings->energy_usage.usage1_kWhtotal / 100000; - float usage2_kWhtotal = (float)Settings->energy_usage.usage2_kWhtotal / 100000; - float return1_kWhtotal = (float)Settings->energy_usage.return1_kWhtotal / 100000; - float return2_kWhtotal = (float)Settings->energy_usage.return2_kWhtotal / 100000; + float usage1_kWhtotal = (float)Settings->energy_usage.usage1_kWhtotal / 1000; + float usage2_kWhtotal = (float)Settings->energy_usage.usage2_kWhtotal / 1000; + float return1_kWhtotal = (float)Settings->energy_usage.return1_kWhtotal / 1000; + float return2_kWhtotal = (float)Settings->energy_usage.return2_kWhtotal / 1000; Response_P(PSTR("{\"%s\":{\"" D_JSON_USAGE "\":[%*_f,%*_f],\"" D_JSON_EXPORT "\":[%*_f,%*_f]}}"), XdrvMailbox.command, @@ -768,9 +768,9 @@ void CmndEnergyUsage(void) { uint32_t params = ParseParameters(2, values); if (params > 0) { // Reset energy_usage.usage totals - RtcSettings.energy_usage.usage1_kWhtotal = values[0] * 100; + RtcSettings.energy_usage.usage1_kWhtotal = values[0]; if (params > 1) { - RtcSettings.energy_usage.usage2_kWhtotal = values[1] * 100; + RtcSettings.energy_usage.usage2_kWhtotal = values[1]; } Settings->energy_usage.usage1_kWhtotal = RtcSettings.energy_usage.usage1_kWhtotal; Settings->energy_usage.usage2_kWhtotal = RtcSettings.energy_usage.usage2_kWhtotal; @@ -1214,10 +1214,10 @@ void EnergyShow(bool json) { float energy_usage[2]; float energy_return[2]; if (Settings->tariff[0][0] != Settings->tariff[1][0]) { - energy_usage[0] = (float)RtcSettings.energy_usage.usage1_kWhtotal / 100000; // Tariff1 - energy_usage[1] = (float)RtcSettings.energy_usage.usage2_kWhtotal / 100000; // Tariff2 - energy_return[0] = (float)RtcSettings.energy_usage.return1_kWhtotal / 100000; // Tariff1 - energy_return[1] = (float)RtcSettings.energy_usage.return2_kWhtotal / 100000; // Tariff2 + energy_usage[0] = (float)RtcSettings.energy_usage.usage1_kWhtotal / 1000; // Tariff1 + energy_usage[1] = (float)RtcSettings.energy_usage.usage2_kWhtotal / 1000; // Tariff2 + energy_return[0] = (float)RtcSettings.energy_usage.return1_kWhtotal / 1000; // Tariff1 + energy_return[1] = (float)RtcSettings.energy_usage.return2_kWhtotal / 1000; // Tariff2 energy_tariff = true; } @@ -1316,10 +1316,10 @@ void EnergyShow(bool json) { char energy_usage_chr[2][FLOATSZ]; char energy_return_chr[2][FLOATSZ]; - dtostrfd((float)RtcSettings.energy_usage.usage1_kWhtotal / 100, 1, energy_usage_chr[0]); // Tariff1 - dtostrfd((float)RtcSettings.energy_usage.usage2_kWhtotal / 100, 1, energy_usage_chr[1]); // Tariff2 - dtostrfd((float)RtcSettings.energy_usage.return1_kWhtotal / 100, 1, energy_return_chr[0]); - dtostrfd((float)RtcSettings.energy_usage.return2_kWhtotal / 100, 1, energy_return_chr[1]); + dtostrfd((float)RtcSettings.energy_usage.usage1_kWhtotal, 1, energy_usage_chr[0]); // Tariff1 + dtostrfd((float)RtcSettings.energy_usage.usage2_kWhtotal, 1, energy_usage_chr[1]); // Tariff2 + dtostrfd((float)RtcSettings.energy_usage.return1_kWhtotal, 1, energy_return_chr[0]); + dtostrfd((float)RtcSettings.energy_usage.return2_kWhtotal, 1, energy_return_chr[1]); DomoticzSensorP1SmartMeter(energy_usage_chr[0], energy_usage_chr[1], energy_return_chr[0], energy_return_chr[1], (int)active_power_sum); } From 32a51da43d064447a5e1d0b1c67990de7f8945a9 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 1 Jan 2023 14:01:18 +0100 Subject: [PATCH 077/262] Fix PUSH_IGNORE_INV once more --- tasmota/tasmota_support/support_switch.ino | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tasmota/tasmota_support/support_switch.ino b/tasmota/tasmota_support/support_switch.ino index 5b66f301b..f00160131 100644 --- a/tasmota/tasmota_support/support_switch.ino +++ b/tasmota/tasmota_support/support_switch.ino @@ -407,12 +407,10 @@ void SwitchHandler(uint32_t mode) { } break; case PUSH_IGNORE: + case PUSH_IGNORE_INV: Switch.last_state[i] = button; // Update switch state before publishing MqttPublishSensor(); break; - case PUSH_IGNORE_INV: - MqttPublishSensor(); // Publishing before update - break; } Switch.last_state[i] = button; } From 25b40402836e0526f7876db99930b0bb89062278 Mon Sep 17 00:00:00 2001 From: kaedwen Date: Sun, 1 Jan 2023 14:02:22 +0100 Subject: [PATCH 078/262] Light driver for PCA9632 (#17557) * added PCA9632 driver * compiling * added BUILD and DEVICES section * added PCA9632 module * use I2C_SDA/SCL * light driver working * bulk write and pin mapping * remove debugging * remove debugging * adjust comments Co-authored-by: Pascal Heinrich --- BUILDS.md | 1 + I2CDEVICES.md | 1 + tasmota/my_user_config.h | 6 + .../tasmota_xdrv_driver/xdrv_91_pca9632.ino | 275 ++++++++++++++++++ .../tasmota_xlgt_light/xlgt_11_pca9632.ino | 79 +++++ 5 files changed, 362 insertions(+) create mode 100644 tasmota/tasmota_xdrv_driver/xdrv_91_pca9632.ino create mode 100644 tasmota/tasmota_xlgt_light/xlgt_11_pca9632.ino diff --git a/BUILDS.md b/BUILDS.md index d17b57901..21c27b038 100644 --- a/BUILDS.md +++ b/BUILDS.md @@ -121,6 +121,7 @@ Note: `minimal` variant is not listed as it shouldn't be used outside of the [up | USE_LM75AD | - | - / x | - | x | - | - | | USE_APDS9960 | - | - / - | - | - | - | - | | USE_MCP230xx | - | - / - | - | - | - | - | +| USE_PCA9632 | - | - / - | - | - | - | - | | USE_PCA9685 | - | - / - | - | - | - | - | | USE_MPR121 | - | - / - | - | - | - | - | | USE_CCS811 | - | - / - | - | x | - | - | diff --git a/I2CDEVICES.md b/I2CDEVICES.md index 744c3ccbf..9c9da3c0d 100644 --- a/I2CDEVICES.md +++ b/I2CDEVICES.md @@ -109,3 +109,4 @@ Index | Define | Driver | Device | Address(es) | Description 72 | USE_INA3221 | xsns_100 | INA3221 | 0x40-0x43 | 3-channels Voltage and Current sensor 73 | USE_HMC5883L | xsns_101 | HMC5883L | 0x1E | 3-channels Magnetic Field Sensor 74 | USE_DISPLAY_TM1650 | xdsp_20 | TM1650 | 0x24 - 0x27, 0x34 - 0x37 | Four-digit seven-segment LED controller + 75 | USE_PCA9632 | xdrv_91 | PCA9632 | 0x60 | 4-channel 4-bit pwm driver diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index 4fe411b69..e95f42e14 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -632,6 +632,12 @@ // #define USE_PCA9685 // [I2cDriver1] Enable PCA9685 I2C HW PWM Driver - Must define I2C Address in #define USE_PCA9685_ADDR below - range 0x40 - 0x47 (+1k4 code) // #define USE_PCA9685_ADDR 0x40 // Enable PCA9685 I2C Address to use (Must be within range 0x40 through 0x47 - set according to your wired setup) // #define USE_PCA9685_FREQ 50 // Define default PWM frequency in Hz to be used (must be within 24 to 1526) - If other value is used, it will rever to 50Hz +// #define USE_PCA9632 // [I2cDriver75] Enable PCA9632 I2C HW PWM Driver +// #define USE_PCA9632_ADDR 0x60 // Define PCA9685 I2C Address to use (Must be within range 0x60 through 0x63 - set according to your wired setup) +// #define USE_PCA9632_CM_0 0 // Mapping for channel 0 +// #define USE_PCA9632_CM_1 1 // Mapping for channel 1 +// #define USE_PCA9632_CM_2 2 // Mapping for channel 2 +// #define USE_PCA9632_CM_3 3 // Mapping for channel 3 // #define USE_MPR121 // [I2cDriver23] Enable MPR121 controller (I2C addresses 0x5A, 0x5B, 0x5C and 0x5D) in input mode for touch buttons (+1k3 code) // #define USE_CCS811 // [I2cDriver24] Enable CCS811 sensor (I2C address 0x5A) (+2k2 code) // #define USE_CCS811_V2 // [I2cDriver24] Enable CCS811 sensor (I2C addresses 0x5A and 0x5B) (+2k8 code) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_91_pca9632.ino b/tasmota/tasmota_xdrv_driver/xdrv_91_pca9632.ino new file mode 100644 index 000000000..acf7d1c60 --- /dev/null +++ b/tasmota/tasmota_xdrv_driver/xdrv_91_pca9632.ino @@ -0,0 +1,275 @@ +/* + xdrv_91_pca9632.ino - Support for I2C PCA9632 4-channel 8-bit hardware PWM driver on Tasmota + + Copyright (C) 2022 Pascal Heinrich + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifdef USE_I2C +#ifdef USE_PCA9632 +/*********************************************************************************************\ + * PCA9632 - 4-channel 8-bit pwm driver + * + * I2C Address: 0x60 .. 0x63 +\*********************************************************************************************/ + +#define XDRV_91 91 +#define XI2C_75 75 // See I2CDEVICES.md + +#define PCA9632_REG_MODE1 0x00 +#define PCA9632_REG_MODE2 0x01 +#define PCA9632_REG_PWM_BASE 0x02 +#define PCA9632_REG_PWM_1 PCA9632_REG_PWM_BASE + 0 +#define PCA9632_REG_PWM_2 PCA9632_REG_PWM_BASE + 1 +#define PCA9632_REG_PWM_3 PCA9632_REG_PWM_BASE + 2 +#define PCA9632_REG_PWM_4 PCA9632_REG_PWM_BASE + 3 +#define PCA9632_REG_GRPPWM 0x06 +#define PCA9632_REG_GRPGREQ 0x07 +#define PCA9632_REG_LEDOUT 0x08 +#define PCA9632_AUTO_INC 0x80 + +#ifndef USE_PCA9632_ADDR + #define USE_PCA9632_ADDR 0x62 +#endif + +#ifndef USE_PCA9632_CM_0 + #define USE_PCA9632_CM_0 0 +#endif + +#ifndef USE_PCA9632_CM_1 + #define USE_PCA9632_CM_1 1 +#endif + +#ifndef USE_PCA9632_CM_2 + #define USE_PCA9632_CM_2 2 +#endif + +#ifndef USE_PCA9632_CM_3 + #define USE_PCA9632_CM_3 3 +#endif + +bool pca9632_inverted = false; // invert PWM for open-collector load +bool pca9632_detected = false; +uint8_t pca9632_pin_pwm_value[4]; + +bool PCA9632_Detect(void) { + if (I2cSetDevice(USE_PCA9632_ADDR)) { + uint8_t buffer; + if (I2cValidRead8(&buffer, USE_PCA9632_ADDR, PCA9632_REG_MODE1)) { + I2cWrite8(USE_PCA9632_ADDR, PCA9632_REG_MODE1, 0x10); + if (I2cValidRead8(&buffer, USE_PCA9632_ADDR, PCA9632_REG_MODE1)) { + if (0x10 == buffer) { + I2cSetActiveFound(USE_PCA9632_ADDR, "PCA9632"); + PCA9632_Reset(); // Reset the controller + return pca9632_detected = true; + } + } + } + } + + return false; +} + +void PCA9632_Init(void) { + // configure none inverted and totem pole + I2cWrite8(USE_PCA9632_ADDR, PCA9632_REG_MODE2, 0x14); + + // turn off sleep mode + I2cWrite8(USE_PCA9632_ADDR, PCA9632_REG_MODE1, 0x1); +} + +void PCA9632_Reset(void) { + I2cWrite8(USE_PCA9632_ADDR, PCA9632_REG_MODE1, 0x6); + pca9632_inverted = false; + for (uint8_t pin = 0; pin < 4; pin++) { + PCA9632_SetPWM(pin, 0); + pca9632_pin_pwm_value[pin] = 0; + } + Response_P(PSTR("{\"PCA9632\":{\"RESET\":\"OK\"}}")); +} + +bool PCA9632_SetInvert(bool on) { + uint8_t buffer; + if(I2cValidRead8(&buffer, USE_PCA9632_ADDR, PCA9632_REG_MODE2)) { + I2cWrite8(USE_PCA9632_ADDR, PCA9632_REG_MODE2, buffer | ((on ? 1 : 0) >> 4)); + } + return on; +} + +bool PCA9632_SetPWM(uint8_t pin, uint8_t pwm) { + + uint8_t pin_mapping = PCA9632_PinMapping(pin); + I2cWrite8(USE_PCA9632_ADDR, PCA9632_REG_PWM_BASE + pin_mapping, pwm); + pca9632_pin_pwm_value[pin_mapping] = pwm; + + return pwm > 0; + +} + +bool PCA9632_SetPWM_Bulk(uint8_t *pwm, uint16_t len) { + uint8_t buffer[4]; + + // map the pwm values to the final pins + for (uint8_t pin = 0; pin < 4; pin++) { + uint8_t pin_mapping = PCA9632_PinMapping(pin); + buffer[pin_mapping] = pwm[pin]; + } + + I2cWriteBuffer(USE_PCA9632_ADDR, PCA9632_REG_PWM_BASE | PCA9632_AUTO_INC, buffer, len); + + // set the pwm values for later use + bool enable = false; + for (uint8_t pin = 0; pin < 4; pin++) { + uint8_t value = buffer[pin]; + + pca9632_pin_pwm_value[pin] = value; + + if (value > 0) { + enable |= true; + } + } + + return enable; +} + +void PCA9632_Enable(bool enable) { + DEBUG_TRACE_LOG(PSTR("DRV: PCA9632 enable %d"), enable); + I2cWrite8(USE_PCA9632_ADDR, PCA9632_REG_LEDOUT, enable ? 0xFF : 0x0); +} + +bool PCA9632_Command(void) { + bool serviced = true; + bool validpin = false; + uint8_t paramcount = 0; + if (XdrvMailbox.data_len > 0) { + paramcount = 1; + } else { + serviced = false; + return serviced; + } + char argument[XdrvMailbox.data_len]; + for (uint32_t ca = 0; ca < XdrvMailbox.data_len; ca++) { + if ((' ' == XdrvMailbox.data[ca]) || ('=' == XdrvMailbox.data[ca])) { XdrvMailbox.data[ca] = ','; } + if (',' == XdrvMailbox.data[ca]) { paramcount++; } + } + UpperCase(XdrvMailbox.data, XdrvMailbox.data); + + if (!strcmp(ArgV(argument, 1),"RESET")) { PCA9632_Reset(); return serviced; } + + if (!strcmp(ArgV(argument, 1),"STATUS")) { PCA9632_OutputTelemetry(false); return serviced; } + + if (!strcmp(ArgV(argument, 1),"INVERT")) { + if (paramcount > 1) { + pca9632_inverted = PCA9632_SetInvert(1 == atoi(ArgV(argument, 2))); + Response_P(PSTR("{\"PCA9632\":{\"INVERT\":%i, \"Result\":\"OK\"}}"), pca9632_inverted); + return serviced; + } else { // No parameter was given for invert, so we return current setting + Response_P(PSTR("{\"PCA9632\":{\"INVERT\":%i}}"), pca9632_inverted); + return serviced; + } + } + if (!strcmp(ArgV(argument, 1),"PWM")) { + if (paramcount > 1) { + uint8_t pin = atoi(ArgV(argument, 2)); + if (paramcount > 2) { + if (!strcmp(ArgV(argument, 3), "ON")) { + PCA9632_SetPWM(pin, 255); + Response_P(PSTR("{\"PCA9632\":{\"PIN\":%i,\"PWM\":%i}}"), pin, 255); + serviced = true; + return serviced; + } + if (!strcmp(ArgV(argument, 3), "OFF")) { + PCA9632_SetPWM(pin, 0); + Response_P(PSTR("{\"PCA9632\":{\"PIN\":%i,\"PWM\":%i}}"), pin, 0); + serviced = true; + return serviced; + } + uint16_t pwm = atoi(ArgV(argument, 3)); + if ((pin >= 0 && pin <= 3) && (pwm >= 0 && pwm <= 255)) { + PCA9632_SetPWM(pin, pwm); + Response_P(PSTR("{\"PCA9632\":{\"PIN\":%i,\"PWM\":%i}}"), pin, pwm); + serviced = true; + return serviced; + } + } + } + } + if (!strcmp(ArgV(argument, 1),"ENABLE")) { + PCA9632_Enable(true); + Response_P(PSTR("{\"PCA9632\":{\"ENABLE\":true}}")); + } + if (!strcmp(ArgV(argument, 1),"DISABLE")) { + PCA9632_Enable(false); + Response_P(PSTR("{\"PCA9632\":{\"ENABLE\":false}}")); + } + return serviced; +} + +void PCA9632_OutputTelemetry(bool telemetry) { + ResponseAppend_P(PSTR("\"INVERT\":%i,"), pca9632_inverted?1:0); + for (uint32_t pin = 0; pin < 4; pin++) { + uint8_t pin_mapping = PCA9632_PinMapping(pin); + ResponseAppend_P(PSTR("\"PWM%i\":%i,"), pin_mapping, pca9632_pin_pwm_value[pin_mapping]); + } + ResponseAppend_P(PSTR("\"END\":1}}")); + if (telemetry) { + MqttPublishTeleSensor(); + } +} + +uint8_t PCA9632_PinMapping(uint8_t pin) { + switch(pin) { + case 0: + return USE_PCA9632_CM_0; + case 1: + return USE_PCA9632_CM_1; + case 2: + return USE_PCA9632_CM_2; + case 3: + return USE_PCA9632_CM_3; + default: + return USE_PCA9632_CM_0; + } +} + +bool Xdrv91(uint32_t function) { + if (!I2cEnabled(XI2C_75)) { return false; } + + bool result = false; + + if (FUNC_INIT == function) { + if (PCA9632_Detect()) { + PCA9632_Init(); + } + } + else if (pca9632_detected) { + switch (function) { + case FUNC_EVERY_SECOND: + if (TasmotaGlobal.tele_period == 0) { + PCA9632_OutputTelemetry(true); + } + break; + case FUNC_COMMAND_DRIVER: + if (XDRV_91 == XdrvMailbox.index) { + result = PCA9632_Command(); + } + break; + } + } + return result; +} + +#endif // USE_PCA9632 +#endif // USE_IC2 diff --git a/tasmota/tasmota_xlgt_light/xlgt_11_pca9632.ino b/tasmota/tasmota_xlgt_light/xlgt_11_pca9632.ino new file mode 100644 index 000000000..5d408a607 --- /dev/null +++ b/tasmota/tasmota_xlgt_light/xlgt_11_pca9632.ino @@ -0,0 +1,79 @@ +/* + xlgt_11_pca9632.ino - pca9632 four channel led support for Tasmota + + Copyright (C) 2021 Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifdef USE_LIGHT +#ifdef USE_PCA9632 +/*********************************************************************************************\ + * PCA9632 - Controlling RGBW over I2C + * Copyright (C) 2022 Pascal Heinrich + * +\*********************************************************************************************/ + +#define XLGT_11 11 + +/********************************************************************************************/ + +bool PCA9632_SetChannels(void) { + uint8_t *cur_col = (uint8_t*)XdrvMailbox.data; + + DEBUG_TRACE_LOG(PSTR("LGT: PCA9632 %d - %d - %d - %d"), cur_col[0], cur_col[1], cur_col[2], cur_col[3]); + + PCA9632_Enable(PCA9632_SetPWM_Bulk(cur_col, 4)); + + return true; +} + +bool PCA9632_ModuleSelected(void) { + DEBUG_TRACE_LOG(PSTR("LGT: PCA9632 ModuleSelected")); + + if (PCA9632_Detect()) { + PCA9632_Init(); + + TasmotaGlobal.light_type += LST_RGBW; // Add RGBW to be controlled by PCA9632 + TasmotaGlobal.light_driver = XLGT_11; + + AddLog(LOG_LEVEL_INFO, PSTR("LGT: PCA9632 Found")); + + return true; + } + + return false; +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xlgt11(uint32_t function) { + bool result = false; + + switch (function) { + case FUNC_SET_CHANNELS: + result = PCA9632_SetChannels(); + break; + case FUNC_MODULE_INIT: + result = PCA9632_ModuleSelected(); + break; + } + return result; +} + +#endif // USE_PCA9632 +#endif // USE_LIGHT + From 14ee8decf7dab46940e57ac2a6a708e0a40e6bcb Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 1 Jan 2023 14:29:41 +0100 Subject: [PATCH 079/262] Update changelogs Add support for PCA9632 4-channel 8-bit PWM driver as light driver by Pascal Heinrich (#17557) --- CHANGELOG.md | 1 + CODE_OWNERS.md | 1 + I2CDEVICES.md | 2 +- RELEASENOTES.md | 1 + tasmota/my_user_config.h | 2 +- tasmota/tasmota_support/support_features.ino | 5 +++-- .../{xdrv_91_pca9632.ino => xdrv_64_pca9632.ino} | 12 ++++++------ tools/decode-status.py | 5 +++-- 8 files changed, 17 insertions(+), 12 deletions(-) rename tasmota/tasmota_xdrv_driver/{xdrv_91_pca9632.ino => xdrv_64_pca9632.ino} (97%) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa65860d4..40027b536 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file. ## [12.3.1.3] ### Added +- Support for PCA9632 4-channel 8-bit PWM driver as light driver by Pascal Heinrich (#17557) ### Breaking Changed diff --git a/CODE_OWNERS.md b/CODE_OWNERS.md index b2c3231cb..b5c0577fc 100644 --- a/CODE_OWNERS.md +++ b/CODE_OWNERS.md @@ -72,6 +72,7 @@ In addition to @arendst the following code is mainly owned by: | xdrv_61_ds3502 | f-reiling | xdrv_62_improv | @arendst | xdrv_63_modbus_bridge | @jeroenst +| xdrv_64_pca9632 | Pascal Heinrich | | | xdrv_79_esp32_ble | @staars, @btsimonh | xdrv_81_esp32_webcam | @gemu, @philrich diff --git a/I2CDEVICES.md b/I2CDEVICES.md index 9c9da3c0d..6523d9117 100644 --- a/I2CDEVICES.md +++ b/I2CDEVICES.md @@ -109,4 +109,4 @@ Index | Define | Driver | Device | Address(es) | Description 72 | USE_INA3221 | xsns_100 | INA3221 | 0x40-0x43 | 3-channels Voltage and Current sensor 73 | USE_HMC5883L | xsns_101 | HMC5883L | 0x1E | 3-channels Magnetic Field Sensor 74 | USE_DISPLAY_TM1650 | xdsp_20 | TM1650 | 0x24 - 0x27, 0x34 - 0x37 | Four-digit seven-segment LED controller - 75 | USE_PCA9632 | xdrv_91 | PCA9632 | 0x60 | 4-channel 4-bit pwm driver + 75 | USE_PCA9632 | xdrv_64 | PCA9632 | 0x60 | 4-channel 4-bit pwm driver diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 45d675c60..7c2b9fbde 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -113,6 +113,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm - Support for IPv6 DNS records (AAAA) and IPv6 ``Ping`` for ESP32 and ESP8266 [#17417](https://github.com/arendst/Tasmota/issues/17417) - Support for IPv6 only networks on Ethernet (not yet Wifi) - Support for TM1650 display as used in some clocks by Stefan Oskamp [#17594](https://github.com/arendst/Tasmota/issues/17594) +- Support for PCA9632 4-channel 8-bit PWM driver as light driver by Pascal Heinrich [#17557](https://github.com/arendst/Tasmota/issues/17557) - Berry support for ``crypto.SHA256`` [#17430](https://github.com/arendst/Tasmota/issues/17430) - Berry crypto add ``EC_P256`` and ``PBKDF2_HMAC_SHA256`` algorithms required by Matter protocol [#17473](https://github.com/arendst/Tasmota/issues/17473) - Berry crypto add ``random`` to generate series of random bytes diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index e95f42e14..4216d088d 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -632,7 +632,7 @@ // #define USE_PCA9685 // [I2cDriver1] Enable PCA9685 I2C HW PWM Driver - Must define I2C Address in #define USE_PCA9685_ADDR below - range 0x40 - 0x47 (+1k4 code) // #define USE_PCA9685_ADDR 0x40 // Enable PCA9685 I2C Address to use (Must be within range 0x40 through 0x47 - set according to your wired setup) // #define USE_PCA9685_FREQ 50 // Define default PWM frequency in Hz to be used (must be within 24 to 1526) - If other value is used, it will rever to 50Hz -// #define USE_PCA9632 // [I2cDriver75] Enable PCA9632 I2C HW PWM Driver +// #define USE_PCA9632 // [I2cDriver75] Enable PCA9632 I2C HW PWM Driver (+1k8 code) // #define USE_PCA9632_ADDR 0x60 // Define PCA9685 I2C Address to use (Must be within range 0x60 through 0x63 - set according to your wired setup) // #define USE_PCA9632_CM_0 0 // Mapping for channel 0 // #define USE_PCA9632_CM_1 1 // Mapping for channel 1 diff --git a/tasmota/tasmota_support/support_features.ino b/tasmota/tasmota_support/support_features.ino index bf698bbbb..78a1d7d74 100644 --- a/tasmota/tasmota_support/support_features.ino +++ b/tasmota/tasmota_support/support_features.ino @@ -864,8 +864,9 @@ void ResponseAppendFeatures(void) #if defined(USE_I2C) && defined(USE_DISPLAY) && defined(USE_DISPLAY_TM1650) feature9 |= 0x00001000; // xdsp_20_tm1650.ino #endif - -// feature9 |= 0x00002000; +#if defined(USE_I2C) && defined(USE_PCA9632) + feature9 |= 0x00002000; +#endif // feature9 |= 0x00004000; // feature9 |= 0x00008000; diff --git a/tasmota/tasmota_xdrv_driver/xdrv_91_pca9632.ino b/tasmota/tasmota_xdrv_driver/xdrv_64_pca9632.ino similarity index 97% rename from tasmota/tasmota_xdrv_driver/xdrv_91_pca9632.ino rename to tasmota/tasmota_xdrv_driver/xdrv_64_pca9632.ino index acf7d1c60..7c36c6ab3 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_91_pca9632.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_64_pca9632.ino @@ -1,5 +1,5 @@ /* - xdrv_91_pca9632.ino - Support for I2C PCA9632 4-channel 8-bit hardware PWM driver on Tasmota + xdrv_64_pca9632.ino - Support for I2C PCA9632 4-channel 8-bit hardware PWM driver on Tasmota Copyright (C) 2022 Pascal Heinrich @@ -25,7 +25,7 @@ * I2C Address: 0x60 .. 0x63 \*********************************************************************************************/ -#define XDRV_91 91 +#define XDRV_64 64 #define XI2C_75 75 // See I2CDEVICES.md #define PCA9632_REG_MODE1 0x00 @@ -41,7 +41,7 @@ #define PCA9632_AUTO_INC 0x80 #ifndef USE_PCA9632_ADDR - #define USE_PCA9632_ADDR 0x62 + #define USE_PCA9632_ADDR 0x60 #endif #ifndef USE_PCA9632_CM_0 @@ -109,7 +109,7 @@ bool PCA9632_SetInvert(bool on) { } bool PCA9632_SetPWM(uint8_t pin, uint8_t pwm) { - + uint8_t pin_mapping = PCA9632_PinMapping(pin); I2cWrite8(USE_PCA9632_ADDR, PCA9632_REG_PWM_BASE + pin_mapping, pwm); pca9632_pin_pwm_value[pin_mapping] = pwm; @@ -244,7 +244,7 @@ uint8_t PCA9632_PinMapping(uint8_t pin) { } } -bool Xdrv91(uint32_t function) { +bool Xdrv64(uint32_t function) { if (!I2cEnabled(XI2C_75)) { return false; } bool result = false; @@ -262,7 +262,7 @@ bool Xdrv91(uint32_t function) { } break; case FUNC_COMMAND_DRIVER: - if (XDRV_91 == XdrvMailbox.index) { + if (XDRV_64 == XdrvMailbox.index) { result = PCA9632_Command(); } break; diff --git a/tools/decode-status.py b/tools/decode-status.py index 64177ba48..efc5d0d48 100755 --- a/tools/decode-status.py +++ b/tools/decode-status.py @@ -203,7 +203,8 @@ a_setoption = [[ ],[ "(ESP32) Show ESP32 internal temperature sensor", "(MQTT) Disable publish SSerialReceived MQTT messages, you must use event trigger rules instead", - "","", + "(Light) start DMX ArtNet at boot, listen to UDP port as soon as network is up", + "(Wifi) prefer IPv6 DNS resolution to IPv4 address when available. Requires `#define USE_IPV6`", "","","","", "","","","", "","","","", @@ -289,7 +290,7 @@ a_features = [[ "USE_SGP40","USE_LUXV30B","USE_CANSNIFFER","USE_QMC5883L", "USE_MODBUS_ENERGY","USE_SHELLY_PRO","USE_DALI","USE_BP1658CJ", "USE_DINGTIAN_RELAY","USE_HMC5883L","USE_LD2410","USE_ME007", - "USE_DISPLAY_TM1650","","","", + "USE_DISPLAY_TM1650","USE_PCA9632","","", "","","","", "","","","", "","","","", From ed0b7d69b6061931afc562b59e0e5d326c1b0354 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 1 Jan 2023 15:12:15 +0100 Subject: [PATCH 080/262] Tune Tx Enable timing --- lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.cpp | 3 ++- lib/lib_basic/TasmotaModbus-3.6.0/src/TasmotaModbus.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.cpp b/lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.cpp index 20654b05f..b30ec296c 100644 --- a/lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.cpp +++ b/lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.cpp @@ -424,6 +424,7 @@ size_t TasmotaSerial::write(uint8_t b) { if (m_tx_enable_pin > -1) { digitalWrite(m_tx_enable_pin, HIGH); + delayMicroseconds(10); // delay(1) will exception here } size_t size = 0; if (m_hardserial) { @@ -460,7 +461,7 @@ size_t TasmotaSerial::write(uint8_t b) { size = 1; } if (m_tx_enable_pin > -1) { - delayMicroseconds(800); // delay(1) will exception here + delayMicroseconds(10); // delay(1) will exception here digitalWrite(m_tx_enable_pin, LOW); } return size; diff --git a/lib/lib_basic/TasmotaModbus-3.6.0/src/TasmotaModbus.cpp b/lib/lib_basic/TasmotaModbus-3.6.0/src/TasmotaModbus.cpp index 0fb316bd3..98773a285 100644 --- a/lib/lib_basic/TasmotaModbus-3.6.0/src/TasmotaModbus.cpp +++ b/lib/lib_basic/TasmotaModbus-3.6.0/src/TasmotaModbus.cpp @@ -157,10 +157,11 @@ uint8_t TasmotaModbus::Send(uint8_t device_address, uint8_t function_code, uint1 flush(); if (mb_tx_enable_pin > -1) { digitalWrite(mb_tx_enable_pin, HIGH); + delayMicroseconds(10); // delay(1) will exception here } write(frame, framepointer); if (mb_tx_enable_pin > -1) { - delayMicroseconds(800); // delay(1) will exception here + delayMicroseconds(10); // delay(1) will exception here digitalWrite(mb_tx_enable_pin, LOW); } free(frame); From cb6dd75d8b75f21472989c5498d46d0e1fff03b5 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 2 Jan 2023 09:50:21 +0100 Subject: [PATCH 081/262] Fix Orno-we-517 serial config Fix Orno-we-517 serial config on esp32 --- tasmota/tasmota_xnrg_energy/xnrg_17_ornowe517.ino | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tasmota/tasmota_xnrg_energy/xnrg_17_ornowe517.ino b/tasmota/tasmota_xnrg_energy/xnrg_17_ornowe517.ino index 2a115712d..3d1edf4e5 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_17_ornowe517.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_17_ornowe517.ino @@ -183,14 +183,13 @@ void WE517Every250ms(void) } } -void We517SnsInit(void) -{ +void We517SnsInit(void) { We517Modbus = new TasmotaModbus(Pin(GPIO_WE517_RX), Pin(GPIO_WE517_TX), Pin(GPIO_NRG_MBS_TX_ENA)); - uint8_t result = We517Modbus->Begin(WE517_SPEED); + uint8_t result = We517Modbus->Begin(WE517_SPEED, SERIAL_8E1); if (result) { if (2 == result) { - AddLog(LOG_LEVEL_DEBUG, PSTR("ORNO: WE517 HW serial init 8E1 at %d baud"), WE517_SPEED); - Serial.begin(WE517_SPEED, SERIAL_8E1); +// AddLog(LOG_LEVEL_DEBUG, PSTR("ORNO: WE517 HW serial init 8E1 at %d baud"), WE517_SPEED); +// Serial.begin(WE517_SPEED, SERIAL_8E1); ClaimSerial(); } Energy.phase_count = 3; From 404589c860e6af0a860d5b4324a11c0dc91c30c9 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 2 Jan 2023 11:38:08 +0100 Subject: [PATCH 082/262] Enable USE_WE517 in tasmota32.bin --- BUILDS.md | 3 ++- tasmota/include/tasmota_configurations.h | 5 +++++ tasmota/include/tasmota_configurations_ESP32.h | 3 ++- tasmota/my_user_config.h | 1 + 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/BUILDS.md b/BUILDS.md index 21c27b038..12802b096 100644 --- a/BUILDS.md +++ b/BUILDS.md @@ -89,7 +89,8 @@ Note: `minimal` variant is not listed as it shouldn't be used outside of the [up | USE_BL09XX | - | x / x | x | x | - | - | | USE_TELEINFO | - | - / - | - | - | - | - | | USE_IEM3000 | - | - / - | - | - | - | - | -| USE_WE517 | - | - / - | - | - | - | - | +| USE_WE517 | - | - / x | - | - | - | - | +| USE_MODBUS_ENERGY | - | - / x | - | - | - | - | | | | | | | | | | USE_ADC_VCC | x | - / - | - | - | x | - | | USE_COUNTER | - | x / x | x | x | - | x | diff --git a/tasmota/include/tasmota_configurations.h b/tasmota/include/tasmota_configurations.h index 57de1b8ab..b787e1dcd 100644 --- a/tasmota/include/tasmota_configurations.h +++ b/tasmota/include/tasmota_configurations.h @@ -219,6 +219,7 @@ //#define USE_LE01MR // Add support for F&F LE-01MR modbus energy meter (+2k code) //#define USE_TELEINFO // Add support for French Energy Provider metering telemetry (+5k2 code, +168 RAM + SmartMeter LinkedList Values RAM) //#define USE_WE517 // Add support for Orno WE517-Modbus energy monitor (+1k code) +//#define USE_MODBUS_ENERGY // Add support for generic modbus energy monitor using a user file in rule space (+5k) #define USE_DHT // Add support for DHT11, AM2301 (DHT21, DHT22, AM2302, AM2321) and SI7021 Temperature and Humidity sensor #define USE_MAX31855 // Add support for MAX31855 K-Type thermocouple sensor using softSPI @@ -325,6 +326,7 @@ #undef USE_TELEINFO // Disable support for French Energy Provider metering telemetry #undef USE_IEM3000 // Disable support for Schneider Electric iEM3000-Modbus series energy monitor (+0k8 code) #undef USE_WE517 // Disable support for Orno WE517-Modbus energy monitor (+1k code) + #undef USE_MODBUS_ENERGY // Disable support for generic modbus energy monitor using a user file in rule space (+5k) #undef USE_BLE_ESP32 // (ESP32 only) Disable support for native BLE on ESP32 - use new driver #undef USE_MI_ESP32 // (ESP32 only) Disable support for ESP32 as a BLE-bridge (+9k2 mem, +292k flash) @@ -437,6 +439,7 @@ #undef USE_TELEINFO // Disable support for French Energy Provider metering telemetry #undef USE_IEM3000 // Disable support for Schneider Electric iEM3000-Modbus series energy monitor (+0k8 code) #undef USE_WE517 // Disable support for Orno WE517-Modbus energy monitor (+1k code) + #undef USE_MODBUS_ENERGY // Disable support for generic modbus energy monitor using a user file in rule space (+5k) //#undef USE_DS18x20 // Disable support for DS18x20 sensors with id sort, single scan and read retry (+1k3 code) @@ -621,6 +624,7 @@ #undef USE_TELEINFO // Disable support for French Energy Provider metering telemetry #undef USE_IEM3000 // Disable support for Schneider Electric iEM3000-Modbus series energy monitor (+0k8 code) #undef USE_WE517 // Disable support for Orno WE517-Modbus energy monitor (+1k code) +#undef USE_MODBUS_ENERGY // Disable support for generic modbus energy monitor using a user file in rule space (+5k) #undef USE_DHT // Disable support for DHT11, AM2301 (DHT21, DHT22, AM2302, AM2321) and SI7021 Temperature and Humidity sensor #undef USE_MAX31855 // Disable MAX31855 K-Type thermocouple sensor using softSPI @@ -775,6 +779,7 @@ #undef USE_IEM3000 // Disable support for Schneider Electric iEM3000-Modbus series energy monitor (+0k8 code) #undef USE_BL6523 // Disable support for BL6523 based energy monitor (+7k code) #undef USE_WE517 // Disable support for Orno WE517-Modbus energy monitor (+1k code) +#undef USE_MODBUS_ENERGY // Disable support for generic modbus energy monitor using a user file in rule space (+5k) #undef USE_DHT // Disable support for DHT11, AM2301 (DHT21, DHT22, AM2302, AM2321) and SI7021 Temperature and Humidity sensor #undef USE_MAX31855 // Disable MAX31855 K-Type thermocouple sensor using softSPI diff --git a/tasmota/include/tasmota_configurations_ESP32.h b/tasmota/include/tasmota_configurations_ESP32.h index 51cbfba49..9360a109c 100644 --- a/tasmota/include/tasmota_configurations_ESP32.h +++ b/tasmota/include/tasmota_configurations_ESP32.h @@ -706,8 +706,9 @@ //#define USE_SOLAX_X1 // Add support for Solax X1 series Modbus log info (+3k1 code) //#define USE_LE01MR // Add support for F&F LE-01MR modbus energy meter (+2k code) //#define USE_TELEINFO // Add support for French Energy Provider metering telemetry (+5k2 code, +168 RAM + SmartMeter LinkedList Values RAM) -//#define USE_WE517 // Add support for Orno WE517-Modbus energy monitor (+1k code) +#define USE_WE517 // Add support for Orno WE517-Modbus energy monitor (+1k code) #define USE_SONOFF_SPM // Add support for ESP32 based Sonoff Smart Stackable Power Meter (+11k code) +#define USE_MODBUS_ENERGY // Add support for generic modbus energy monitor using a user file in rule space (+5k code) #define USE_DHT // Add support for DHT11, AM2301 (DHT21, DHT22, AM2302, AM2321) and SI7021 Temperature and Humidity sensor #define USE_MAX31855 // Add support for MAX31855 K-Type thermocouple sensor using softSPI diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index 4216d088d..6c6c6f60b 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -874,6 +874,7 @@ #define IEM3000_ADDR 1 // iEM3000-Modbus modbus address (default: 0x01) // #define IEM3000_IEM3155 // Compatibility fix for Iem3155 (changes Power and Energy total readout) //#define USE_WE517 // Add support for Orno WE517-Modbus energy monitor (+1k code) +//#define USE_MODBUS_ENERGY // Add support for generic modbus energy monitor using a user file in rule space (+5k) // -- Low level interface devices ----------------- #define USE_DHT // Add support for DHT11, AM2301 (DHT21, DHT22, AM2302, AM2321) and SI7021 Temperature and Humidity sensor (1k6 code) From 10af47f8f41c5cd01f4ddef2329969b169afef57 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 2 Jan 2023 12:26:40 +0100 Subject: [PATCH 083/262] Fix swapped voltage/power in energy dummy --- tasmota/tasmota_xnrg_energy/xnrg_30_dummy.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tasmota/tasmota_xnrg_energy/xnrg_30_dummy.ino b/tasmota/tasmota_xnrg_energy/xnrg_30_dummy.ino index 8a1abd304..1a661b91a 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_30_dummy.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_30_dummy.ino @@ -61,10 +61,10 @@ void NrgDummyEverySecond(void) { float current_calibration = (float)EnergyGetCalibration(channel, ENERGY_CURRENT_CALIBRATION) / 100000; float frequency_calibration = (float)EnergyGetCalibration(channel, ENERGY_FREQUENCY_CALIBRATION) / 100; - Energy.voltage[channel] = power_calibration; // V + Energy.voltage[channel] = voltage_calibration; // V Energy.frequency[channel] = frequency_calibration; // Hz if (bitRead(TasmotaGlobal.power, channel)) { // Emulate power read only if device is powered on - Energy.active_power[channel] = (NrgDummy.power[channel]) ? ((float)NrgDummy.power[channel] / 1000) : voltage_calibration; // W + Energy.active_power[channel] = (NrgDummy.power[channel]) ? ((float)NrgDummy.power[channel] / 1000) : power_calibration; // W if (0 == Energy.active_power[channel]) { Energy.current[channel] = 0; } else { From e375448090c38210407730c3348ce24c4641942a Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 2 Jan 2023 12:31:46 +0100 Subject: [PATCH 084/262] Update change logs --- CHANGELOG.md | 1 + RELEASENOTES.md | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 40027b536..119ada0af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ All notable changes to this project will be documented in this file. - Energy totals max supported value from +/-21474.83647 to +/-2147483.647 kWh ### Fixed +- Energy dummy switched voltage and power regression from v12.2.0.2 ### Removed diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 7c2b9fbde..0d4803065 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -130,6 +130,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm ### Fixed - Modbus transmit enable GPIO enabled once during write buffer +- Energy dummy switched voltage and power regression from v12.2.0.2 - ESP8266 set GPIO's to input on power on fixing relay spikes [#17531](https://github.com/arendst/Tasmota/issues/17531) - Shutter default motorstop set to 0 [#17403](https://github.com/arendst/Tasmota/issues/17403) - Shutter default tilt configuration [#17484](https://github.com/arendst/Tasmota/issues/17484) From ea6a5a2d4e3978ae87078b8eba62fd90ad23f9bb Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 2 Jan 2023 15:08:40 +0100 Subject: [PATCH 085/262] Removed delays in TasmotaSerial and TasmotaModbus Tx enable switching --- CHANGELOG.md | 2 ++ RELEASENOTES.md | 2 ++ .../TasmotaSerial-3.6.0/src/TasmotaSerial.cpp | 2 -- .../TasmotaModbus-3.6.0/src/TasmotaModbus.cpp | 20 ++++++++++++++----- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 119ada0af..0f8e98bc7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,9 +11,11 @@ All notable changes to this project will be documented in this file. ### Changed - Energy totals max supported value from +/-21474.83647 to +/-2147483.647 kWh +- Removed delays in TasmotaSerial and TasmotaModbus Tx enable switching ### Fixed - Energy dummy switched voltage and power regression from v12.2.0.2 +- Orno WE517 modbus serial config 8E1 setting (#17545) ### Removed diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 0d4803065..d1ad2cc54 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -125,6 +125,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm ### Changed - ESP32 Framework (Core) from v2.0.5.3 to v2.0.6 (IPv6 support) - Energy totals max supported value from +/-21474.83647 to +/-2147483.647 kWh +- Removed delays in TasmotaSerial and TasmotaModbus Tx enable switching - TuyaMcu rewrite by btsimonh [#17051](https://github.com/arendst/Tasmota/issues/17051) - Tasmota OTA scripts now support both unzipped and gzipped file uploads [#17378](https://github.com/arendst/Tasmota/issues/17378) @@ -134,5 +135,6 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm - ESP8266 set GPIO's to input on power on fixing relay spikes [#17531](https://github.com/arendst/Tasmota/issues/17531) - Shutter default motorstop set to 0 [#17403](https://github.com/arendst/Tasmota/issues/17403) - Shutter default tilt configuration [#17484](https://github.com/arendst/Tasmota/issues/17484) +- Orno WE517 modbus serial config 8E1 setting [#17545](https://github.com/arendst/Tasmota/issues/17545) ### Removed diff --git a/lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.cpp b/lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.cpp index b30ec296c..a233422be 100644 --- a/lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.cpp +++ b/lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.cpp @@ -424,7 +424,6 @@ size_t TasmotaSerial::write(uint8_t b) { if (m_tx_enable_pin > -1) { digitalWrite(m_tx_enable_pin, HIGH); - delayMicroseconds(10); // delay(1) will exception here } size_t size = 0; if (m_hardserial) { @@ -461,7 +460,6 @@ size_t TasmotaSerial::write(uint8_t b) { size = 1; } if (m_tx_enable_pin > -1) { - delayMicroseconds(10); // delay(1) will exception here digitalWrite(m_tx_enable_pin, LOW); } return size; diff --git a/lib/lib_basic/TasmotaModbus-3.6.0/src/TasmotaModbus.cpp b/lib/lib_basic/TasmotaModbus-3.6.0/src/TasmotaModbus.cpp index 98773a285..4319c5d8a 100644 --- a/lib/lib_basic/TasmotaModbus-3.6.0/src/TasmotaModbus.cpp +++ b/lib/lib_basic/TasmotaModbus-3.6.0/src/TasmotaModbus.cpp @@ -27,10 +27,15 @@ enum LoggingLevels {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_D //#define TASMOTAMODBUSDEBUG +#define TASMOTA_MODBUS_TX_ENABLE // Use local Tx enable on write buffer + TasmotaModbus::TasmotaModbus(int receive_pin, int transmit_pin, int tx_enable_pin) : TasmotaSerial(receive_pin, transmit_pin, 2) { -// setTransmitEnablePin(tx_enable_pin); - mb_tx_enable_pin = tx_enable_pin; +#ifdef TASMOTA_MODBUS_TX_ENABLE + mb_tx_enable_pin = tx_enable_pin; // Use local Tx enable on write buffer +#else + setTransmitEnablePin(tx_enable_pin); // Use TasmotaSerial Tx enable on write byte +#endif // TASMOTA_MODBUS_TX_ENABLE mb_address = 0; } @@ -59,10 +64,12 @@ int TasmotaModbus::Begin(long speed, uint32_t config) if (begin(speed, config)) { result = 1; if (hardwareSerial()) { result = 2; } +#ifdef TASMOTA_MODBUS_TX_ENABLE if (mb_tx_enable_pin > -1) { pinMode(mb_tx_enable_pin, OUTPUT); digitalWrite(mb_tx_enable_pin, LOW); } +#endif // TASMOTA_MODBUS_TX_ENABLE } return result; } @@ -148,22 +155,25 @@ uint8_t TasmotaModbus::Send(uint8_t device_address, uint8_t function_code, uint1 buf = (uint8_t *)malloc(bufsize); memset(buf, 0, bufsize); uint16_t i; - for (i = 0; i < framepointer;i++) + for (i = 0; i < framepointer;i++) { snprintf((char *)&buf[i*3], (bufsize-i*3), "%02X ",frame[i]); + } AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("MBS: Serial Send: %s"), buf); free(buf); #endif flush(); +#ifdef TASMOTA_MODBUS_TX_ENABLE if (mb_tx_enable_pin > -1) { digitalWrite(mb_tx_enable_pin, HIGH); - delayMicroseconds(10); // delay(1) will exception here } +#endif // TASMOTA_MODBUS_TX_ENABLE write(frame, framepointer); +#ifdef TASMOTA_MODBUS_TX_ENABLE if (mb_tx_enable_pin > -1) { - delayMicroseconds(10); // delay(1) will exception here digitalWrite(mb_tx_enable_pin, LOW); } +#endif // TASMOTA_MODBUS_TX_ENABLE free(frame); return 0; } From 555b434361d6d6be12209d368f83c6ac03f40272 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 2 Jan 2023 17:48:51 +0100 Subject: [PATCH 086/262] Fix Energy single column values --- .../tasmota_xdrv_driver/xdrv_03_energy.ino | 16 +++++-- .../tasmota_xnrg_energy/xnrg_29_modbus.ino | 47 ++++++++++--------- 2 files changed, 37 insertions(+), 26 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino b/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino index 18c81a0c1..839568bcc 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino @@ -152,7 +152,9 @@ char* EnergyFormat(char* result, float* input, uint32_t resolution, uint32_t sin if (single > 1) { if (!Settings->flag5.energy_phase) { // SetOption129 - (Energy) Show phase information for (uint32_t i = 0; i < Energy.phase_count; i++) { - input_sum += input[i]; + if (!isnan(input[i])) { + input_sum += input[i]; + } } input = &input_sum; } else { @@ -176,7 +178,9 @@ char* WebEnergyFormat(char* result, float* input, uint32_t resolution, uint32_t if (single > 1) { // Sum and/or Single column if (!Settings->flag5.energy_phase) { // SetOption129 - (Energy) Show phase information for (uint32_t i = 0; i < Energy.phase_count; i++) { - input_sum += input[i]; + if (!isnan(input[i])) { + input_sum += input[i]; + } } input = &input_sum; } else { @@ -317,7 +321,7 @@ void EnergyUpdateTotal(void) { Energy.kWhtoday[i] = (int32_t)((Energy.import_active[i] - Energy.start_energy[i]) * 100000); } - if ((Energy.total[i] < (Energy.import_active[i] - 0.01f)) && // We subtract a little offset to avoid continuous updates + if ((Energy.total[i] < (Energy.import_active[i] - 0.01f)) && // We subtract a little offset of 10Wh to avoid continuous updates Settings->flag3.hardware_energy_total) { // SetOption72 - Enable hardware energy total counter as reference (#6561) // The following calculation allows total usage (Energy.import_active[i]) up to +/-2147483.647 kWh RtcSettings.energy_kWhtotal_ph[i] = (int32_t)((Energy.import_active[i] * 1000) - ((Energy.kWhtoday_offset[i] + Energy.kWhtoday[i]) / 100)); @@ -1255,10 +1259,11 @@ void EnergyShow(bool json) { */ if (!isnan(Energy.export_active[0])) { + uint32_t single = (!isnan(Energy.export_active[1]) && !isnan(Energy.export_active[2])) ? 0 : 1; ResponseAppend_P(PSTR(",\"" D_JSON_TODAY_SUM_IMPORT "\":%s,\"" D_JSON_TODAY_SUM_EXPORT "\":%s,\"" D_JSON_EXPORT_ACTIVE "\":%s"), EnergyFormat(value_chr, &Energy.daily_sum_import_balanced, Settings->flag2.energy_resolution, 1), EnergyFormat(value2_chr, &Energy.daily_sum_export_balanced, Settings->flag2.energy_resolution, 1), - EnergyFormat(value3_chr, Energy.export_active, Settings->flag2.energy_resolution)); + EnergyFormat(value3_chr, Energy.export_active, Settings->flag2.energy_resolution, single)); if (energy_tariff) { ResponseAppend_P(PSTR(",\"" D_JSON_EXPORT D_CMND_TARIFF "\":%s"), EnergyFormat(value_chr, energy_return, Settings->flag2.energy_resolution, 6)); @@ -1380,7 +1385,8 @@ void EnergyShow(bool json) { WebEnergyFormat(value2_chr, energy_yesterday_ph, Settings->flag2.energy_resolution, 2), WebEnergyFormat(value3_chr, Energy.total, Settings->flag2.energy_resolution, 2)); if (!isnan(Energy.export_active[0])) { - WSContentSend_PD(HTTP_ENERGY_SNS3, WebEnergyFormat(value_chr, Energy.export_active, Settings->flag2.energy_resolution, 2)); + uint32_t single = (!isnan(Energy.export_active[1]) && !isnan(Energy.export_active[2])) ? 2 : 1; + WSContentSend_PD(HTTP_ENERGY_SNS3, WebEnergyFormat(value_chr, Energy.export_active, Settings->flag2.energy_resolution, single)); } #ifdef USE_ENERGY_COLUMN_GUI XnrgCall(FUNC_WEB_COL_SENSOR); diff --git a/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino b/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino index 27f208616..9c5891b3a 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino @@ -118,18 +118,19 @@ * 29 - WeightRes (Kg) * * Example using default Energy registers: - * rule3 on file#modbus do {"Name":"SDM230","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":0,"Current":6,"Power":12,"ApparentPower":18,"ReactivePower":24,"Factor":30,"Frequency":70,"Total":342,"ExportActive":0x004A} endon - * rule3 on file#modbus do {"Name":"SDM230 with hex registers","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":0x0000,"Current":0x0006,"Power":0x000C,"ApparentPower":0x0012,"ReactivePower":0x0018,"Factor":0x001E,"Frequency":0x0046,"Total":0x0156,"ExportActive":0x004A} endon - * rule3 on file#modbus do {"Name":"DDSU666","Baud":9600,"Config":8N1","Address":1,"Function":4,"Voltage":0x2000,"Current":0x2002,"Power":0x2004,"ReactivePower":0x2006,"Factor":0x200A,"Frequency":0x200E,"Total":0x4000,"ExportActive":0x400A} endon - * rule3 on file#modbus do {"Name":"PZEM014","Baud":9600,"Config":8N1","Address":1,"Function":4,"Voltage":{"R":0,"T":3,"F":-1},"Current":{"R":1,"T":8,"F":-3},"Power":{"R":3,"T":8,"F":-1},"Factor":{"R":8,"T":3,"F":-2},"Frequency":{"R":7,"T":3,"F":-1},"Total":{"R":5,"T":8,"F":-3}} endon - * rule3 on file#modbus do {"Name":"3 x PZEM014","Baud":9600,"Config":8N1","Address":[1,2,3],"Function":4,"Voltage":{"R":0,"T":3,"F":-1},"Current":{"R":1,"T":8,"F":-3},"Power":{"R":3,"T":8,"F":-1},"Factor":{"R":8,"T":3,"F":-2},"Frequency":{"R":7,"T":3,"F":-1},"Total":{"R":5,"T":8,"F":-3}} endon - * rule3 on file#modbus do {"Name":"Solax X3MIC","Baud":9600,"Config":8N1","Address":1,"Function":4,"Voltage":{"R":0x0404,"T":3,"F":-1},"Power":{"R":0x040e,"T":3,"F":0},"Total":{"R":0x0423,"T":8,"F":-3}} endon + * rule3 on file#modbus do {"Name":"SDM230","Baud":2400,"Config":"8N1","Address":1,"Function":4,"Voltage":0,"Current":6,"Power":12,"ApparentPower":18,"ReactivePower":24,"Factor":30,"Frequency":70,"Total":342,"ExportActive":0x004A} endon + * rule3 on file#modbus do {"Name":"SDM230 with hex registers","Baud":2400,"Config":"8N1","Address":1,"Function":4,"Voltage":0x0000,"Current":0x0006,"Power":0x000C,"ApparentPower":0x0012,"ReactivePower":0x0018,"Factor":0x001E,"Frequency":0x0046,"Total":0x0156,"ExportActive":0x004A} endon + * rule3 on file#modbus do {"Name":"DDSU666","Baud":9600,"Config":"8N1","Address":1,"Function":4,"Voltage":0x2000,"Current":0x2002,"Power":0x2004,"ReactivePower":0x2006,"Factor":0x200A,"Frequency":0x200E,"Total":0x4000,"ExportActive":0x400A} endon + * rule3 on file#modbus do {"Name":"PZEM014","Baud":9600,"Config":"8N1","Address":1,"Function":4,"Voltage":{"R":0,"T":3,"F":-1},"Current":{"R":1,"T":8,"F":-3},"Power":{"R":3,"T":8,"F":-1},"Factor":{"R":8,"T":3,"F":-2},"Frequency":{"R":7,"T":3,"F":-1},"Total":{"R":5,"T":8,"F":-3}} endon + * rule3 on file#modbus do {"Name":"3 x PZEM014","Baud":9600,"Config":"8N1","Address":[1,2,3],"Function":4,"Voltage":{"R":0,"T":3,"F":-1},"Current":{"R":1,"T":8,"F":-3},"Power":{"R":3,"T":8,"F":-1},"Factor":{"R":8,"T":3,"F":-2},"Frequency":{"R":7,"T":3,"F":-1},"Total":{"R":5,"T":8,"F":-3}} endon + * rule3 on file#modbus do {"Name":"Solax X3MIC","Baud":9600,"Config":"8N1","Address":1,"Function":4,"Voltage":{"R":0x0404,"T":3,"F":-1},"Power":{"R":0x040e,"T":3,"F":0},"Total":{"R":0x0423,"T":8,"F":-3}} endon * * Example using default Energy registers and some user defined registers: - * rule3 on file#modbus do {"Name":"SDM72","Baud":9600,"Config":8N1","Address":0x01,"Function":0x04,"Power":0x0034,"Total":0x0156,"ExportActive":0x004A,"User":[{"R":0x0502,"J":"ImportActive","G":"Import Active","U":"kWh","D":24},{"R":0x0502,"J":"ExportPower","G":"Export Power","U":"W","D":23},{"R":0x0500,"J":"ImportPower","G":"Import Power","U":"W","D":23}]} endon - * rule3 on file#modbus do {"Name":"SDM120","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":0,"Current":6,"Power":12,"ApparentPower":18,"ReactivePower":24,"Factor":30,"Frequency":70,"Total":342,"ExportActive":0x004A,"User":[{"R":0x0048,"J":"ImportActive","G":"Import Active","U":"kWh","D":24},{"R":0x004E,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":24},{"R":0x004C,"J":"ImportReactive","G":"Import Reactive","U":"kVArh","D":24},{"R":0x0024,"J":"PhaseAngle","G":"Phase Angle","U":"Deg","D":2}]} endon - * rule3 on file#modbus do {"Name":"SDM230 with two user registers","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":0,"Current":6,"Power":12,"ApparentPower":18,"ReactivePower":24,"Factor":30,"Frequency":70,"Total":342,"ExportActive":0x004A,"User":[{"R":0x004E,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":3},{"R":0x0024,"J":"PhaseAngle","G":"Phase Angle","U":"Deg","D":2}]} endon - * rule3 on file#modbus do {"Name":"SDM630","Baud":9600,"Config":8N1","Address":1,"Function":4,"Voltage":[0,2,4],"Current":[6,8,10],"Power":[12,14,16],"ApparentPower":[18,20,22],"ReactivePower":[24,26,28],"Factor":[30,32,34],"Frequency":70,"Total":342,"ExportActive":[352,354,356],"User":{"R":[346,348,350],"J":"ImportActive","G":"Import Active","U":"kWh","D":24}} endon + * rule3 on file#modbus do {"Name":"SDM72","Baud":9600,"Config":"8N1","Address":0x01,"Function":0x04,"Power":0x0034,"Total":0x0156,"ExportActive":0x004A,"User":[{"R":0x0502,"J":"ImportActive","G":"Import Active","U":"kWh","D":24},{"R":0x0502,"J":"ExportPower","G":"Export Power","U":"W","D":23},{"R":0x0500,"J":"ImportPower","G":"Import Power","U":"W","D":23}]} endon + * rule3 on file#modbus do {"Name":"SDM120","Baud":2400,"Config":"8N1","Address":1,"Function":4,"Voltage":0,"Current":6,"Power":12,"ApparentPower":18,"ReactivePower":24,"Factor":30,"Frequency":70,"Total":342,"ExportActive":0x004A,"User":[{"R":0x0048,"J":"ImportActive","G":"Import Active","U":"kWh","D":24},{"R":0x004E,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":24},{"R":0x004C,"J":"ImportReactive","G":"Import Reactive","U":"kVArh","D":24},{"R":0x0024,"J":"PhaseAngle","G":"Phase Angle","U":"Deg","D":2}]} endon + * rule3 on file#modbus do {"Name":"SDM230 with two user registers","Baud":2400,"Config":"8N1","Address":1,"Function":4,"Voltage":0,"Current":6,"Power":12,"ApparentPower":18,"ReactivePower":24,"Factor":30,"Frequency":70,"Total":342,"ExportActive":0x004A,"User":[{"R":0x004E,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":3},{"R":0x0024,"J":"PhaseAngle","G":"Phase Angle","U":"Deg","D":2}]} endon + * rule3 on file#modbus do {"Name":"SDM630","Baud":9600,"Config":"8N1","Address":1,"Function":4,"Voltage":[0,2,4],"Current":[6,8,10],"Power":[12,14,16],"ApparentPower":[18,20,22],"ReactivePower":[24,26,28],"Factor":[30,32,34],"Frequency":70,"Total":342,"ExportActive":[352,354,356],"User":{"R":[346,348,350],"J":"ImportActive","G":"Import Active","U":"kWh","D":24}} endon + * rule3 on file#modbus do {"Name":"WE517","Baud":9600,"Config":"8E1","Address":1,"Function":3,"Voltage":[0xE,0x10,0x12],"Current":[0x16,0x18,0x1A],"Power":[0x1E,0x20,0x22],"ReactivePower":[0x26,0x28,0x2A],"Factor":[0x36,0x38,0x3A],"Frequency":0x14,"Total":0x100,"ExportActive":0x110,"User":[{"J":"ImportActive","G":"Import Active","R":0x108,"U":"kWh","D":24},{"J":"TotalPower","G":"Active Power Total","R":0x1C,"U":"W","D":23}]} endon * * Note: * - To enter long rules using the serial console and solve error "Serial buffer overrun" you might need to enlarge the serial input buffer with command serialbuffer 800 @@ -144,18 +145,22 @@ * - Support other modbus register like integers * * Test set: - * rule3 on file#modbus do {"Name":"GROWATT","Baud":9600,"Config":8N1","Address":11,"Function":4,"Voltage":{"R":[4110,4114,4118],"T":3,"F":-1},"Current":{"R":[4111,4115,4119],"T":3,"F":-1},"Power":{"R":[4112,4116,4120],"T":8,"F":-1},"Frequency":{"R":4109,"T":3,"F":-2},"Total":{"R":4124,"T":8,"F":-1},"User":[{"R":[4099,4103],"J":"VoltagePV","G":"Voltage PV","U":"V","D":21,"T":3,"F":-1},{"R":[4100,4104],"J":"CurrentPV","G":"Current PV","U":"A","D":22,"T":3,"F":-1},{"R":[4101,4105],"J":"PowerPV","G":"Power PV","U":"W","D":23,"T":8,"F":-1}]} endon - * rule3 on file#modbus do {"Name":"2 x PZEM014","Baud":9600,"Config":8N1","Address":[1,1],"Function":4,"Voltage":{"R":0,"T":3,"F":-1},"Current":{"R":1,"T":8,"F":-3},"Power":{"R":3,"T":8,"F":-1},"Factor":{"R":8,"T":3,"F":-2},"Frequency":{"R":7,"T":3,"F":-1},"Total":{"R":5,"T":8,"F":-3}} endon - * rule3 on file#modbus do {"Name":"SDM230 test1","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":[0,0,0],"Current":[6,6,6],"Power":[12,12,12],"ApparentPower":[18,18,18],"ReactivePower":[24,24,24],"Factor":[30,30,30],"Frequency":[70,70,70],"Total":[342,342,342]} endon - * rule3 on file#modbus do {"Name":"SDM230 test2","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":[0,0,0],"Current":[6,6,6],"Power":[12,12,12],"ApparentPower":[18,18,18],"ReactivePower":[24,24,24],"Factor":[30,30,30],"Frequency":70,"Total":[342,342,342]} endon - * rule3 on file#modbus do {"Name":"SDM230 test3","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":0,"Current":[6,6,6],"Power":[12,12,12],"ApparentPower":[18,18,18],"ReactivePower":[24,24,24],"Factor":[30,30,30],"Frequency":70,"Total":[342,342,342]} endon - * rule3 on file#modbus do {"Name":"SDM230 test4","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":0,"Current":6,"Power":12,"ApparentPower":18,"ReactivePower":24,"Factor":30,"Frequency":70,"Total":342,"ExportActive":0x004A,"User":[{"R":0x004E,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":24},{"R":0x0024,"J":"PhaseAngle","G":"Phase Angle","U":"Deg","D":2}]} endon - * rule3 on file#modbus do {"Name":"SDM230 test5","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":[0,0,0],"Current":6,"Power":12,"ApparentPower":18,"ReactivePower":24,"Factor":30,"Frequency":70,"Total":342,"ExportActive":0x004A,"User":[{"R":[0x004E,0x004E,0x004E],"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":3},{"R":0x0024,"J":"PhaseAngle","G":"Phase Angle","U":"Deg","D":2}]} endon - * rule3 on file#modbus do {"Name":"SDM120 test1","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":0,"Current":6,"Power":12,"ApparentPower":18,"ReactivePower":24,"Factor":30,"Frequency":70,"Total":342,"ExportActive":0x004A,"User":[{"R":0x0048,"J":"ImportActive","G":"Import Active","U":"kWh","D":24},{"R":0x004E,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":24},{"R":0x004C,"J":"ImportReactive","G":"Import Reactive","U":"kVArh","D":24},{"R":0x0024,"J":"PhaseAngle","G":"Phase Angle","U":"Deg","D":2}]} endon - * rule3 on file#modbus do {"Name":"PZEM014 test1","Baud":9600,"Config":8N1","Address":1,"Function":4,"Voltage":{"R":0,"T":3,"F":-1},"Current":{"R":1,"T":8,"F":-3},"Power":{"R":3,"T":8,"F":-1},"Factor":{"R":8,"T":3,"F":-2},"Frequency":{"R":7,"T":3,"F":-1},"Total":{"R":5,"T":8,"F":-3},"User":{"R":0,"J":"VoltageTest","G":"Voltage test","U":"V","D":21,"T":3,"F":-1}} endon + * rule3 on file#modbus do {"Name":"GROWATT","Baud":9600,"Config":"8N1","Address":1,"Function":4,"Voltage":{"R":[4110,4114,4118],"T":3,"F":-1},"Current":{"R":[4111,4115,4119],"T":3,"F":-1},"Power":{"R":[4112,4116,4120],"T":8,"F":-1},"Frequency":{"R":4109,"T":3,"F":-2},"Total":{"R":4124,"T":8,"F":-1},"User":[{"R":[4099,4103],"J":"VoltagePV","G":"Voltage PV","U":"V","D":21,"T":3,"F":-1},{"R":[4100,4104],"J":"CurrentPV","G":"Current PV","U":"A","D":22,"T":3,"F":-1},{"R":[4101,4105],"J":"PowerPV","G":"Power PV","U":"W","D":23,"T":8,"F":-1}]} endon + * rule3 on file#modbus do {"Name":"2 x PZEM014","Baud":9600,"Config":"8N1","Address":[1,1],"Function":4,"Voltage":{"R":0,"T":3,"F":-1},"Current":{"R":1,"T":8,"F":-3},"Power":{"R":3,"T":8,"F":-1},"Factor":{"R":8,"T":3,"F":-2},"Frequency":{"R":7,"T":3,"F":-1},"Total":{"R":5,"T":8,"F":-3}} endon + * rule3 on file#modbus do {"Name":"SDM230 test1","Baud":2400,"Config":"8N1","Address":1,"Function":4,"Voltage":[0,0,0],"Current":[6,6,6],"Power":[12,12,12],"ApparentPower":[18,18,18],"ReactivePower":[24,24,24],"Factor":[30,30,30],"Frequency":[70,70,70],"Total":[342,342,342]} endon + * rule3 on file#modbus do {"Name":"SDM230 test2","Baud":2400,"Config":"8N1","Address":1,"Function":4,"Voltage":[0,0,0],"Current":[6,6,6],"Power":[12,12,12],"ApparentPower":[18,18,18],"ReactivePower":[24,24,24],"Factor":[30,30,30],"Frequency":70,"Total":[342,342,342]} endon + * rule3 on file#modbus do {"Name":"SDM230 test3","Baud":2400,"Config":"8N1","Address":1,"Function":4,"Voltage":0,"Current":[6,6,6],"Power":[12,12,12],"ApparentPower":[18,18,18],"ReactivePower":[24,24,24],"Factor":[30,30,30],"Frequency":70,"Total":[342,342,342]} endon + * rule3 on file#modbus do {"Name":"SDM230 test4","Baud":2400,"Config":"8N1","Address":1,"Function":4,"Voltage":0,"Current":6,"Power":12,"ApparentPower":18,"ReactivePower":24,"Factor":30,"Frequency":70,"Total":342,"ExportActive":0x004A,"User":[{"R":0x004E,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":24},{"R":0x0024,"J":"PhaseAngle","G":"Phase Angle","U":"Deg","D":2}]} endon + * rule3 on file#modbus do {"Name":"SDM230 test5","Baud":2400,"Config":"8N1","Address":1,"Function":4,"Voltage":[0,0,0],"Current":6,"Power":12,"ApparentPower":18,"ReactivePower":24,"Factor":30,"Frequency":70,"Total":342,"ExportActive":0x004A,"User":[{"R":[0x004E,0x004E,0x004E],"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":3},{"R":0x0024,"J":"PhaseAngle","G":"Phase Angle","U":"Deg","D":2}]} endon + * rule3 on file#modbus do {"Name":"SDM230 test6","Baud":2400,"Config":"8N1","Address":1,"Function":4,"Voltage":[0,0,0],"Current":[6,6,6],"Power":[12,12,12],"ApparentPower":[18,18,18],"ReactivePower":[24,24,24],"Factor":[30,30,30],"Frequency":[70,70,70],"Total":[342,342,342],"ExportActive":0x004A} endon + * rule3 on file#modbus do {"Name":"SDM230 test7","Baud":2400,"Config":"8N1","Address":1,"Function":4,"Voltage":[0,0,0],"Current":[6,6,6],"Power":[12,12,12],"ApparentPower":[18,18,18],"ReactivePower":[24,24,24],"Factor":[30,30,30],"Frequency":[70,70,70],"Total":[342,342,342],"ExportActive":0x004A,"User":{"J":"PhaseAngle","G":"Phase Angle","R":0x0024,"U":"Deg","D":2}} endon + * rule3 on file#modbus do {"Name":"SDM230 test8","Baud":2400,"Config":"8N1","Address":1,"Function":4,"Voltage":[0,0,0],"Current":[6,6,6],"Power":[12,12,12],"ApparentPower":[18,18,18],"ReactivePower":[24,24,24],"Factor":[30,30,30],"Frequency":[70,70,70],"Total":[342,342,342],"ExportActive":0x004A,"User":{"J":"PhaseAngle","G":"Phase Angle","R":[0x24,0x24,0x24],"U":"Deg","D":2}} endon * - * rule3 on file#modbus do {"Name":"SDM230 test6","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":{"R":0,"T":0,"M":1},"Current":{"R":6,"T":0,"M":1},"Power":{"R":12,"T":0,"M":1},"Frequency":70,"Total":342} endon - * rule3 on file#modbus do {"Name":"SDM230 test6","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":{"R":0,"T":0,"F":0},"Current":{"R":6,"T":0,"F":0},"Power":{"R":12,"T":0,"F":0},"Frequency":70,"Total":342,"User":{"R":0x0048,"T":0,"F":-1,"J":"ImportActive","G":"Import Active","U":"kWh","D":24}} endon + * rule3 on file#modbus do {"Name":"SDM120 test1","Baud":2400,"Config":"8N1","Address":1,"Function":4,"Voltage":0,"Current":6,"Power":12,"ApparentPower":18,"ReactivePower":24,"Factor":30,"Frequency":70,"Total":342,"ExportActive":0x004A,"User":[{"R":0x0048,"J":"ImportActive","G":"Import Active","U":"kWh","D":24},{"R":0x004E,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":24},{"R":0x004C,"J":"ImportReactive","G":"Import Reactive","U":"kVArh","D":24},{"R":0x0024,"J":"PhaseAngle","G":"Phase Angle","U":"Deg","D":2}]} endon + * rule3 on file#modbus do {"Name":"PZEM014 test1","Baud":9600,"Config":"8N1","Address":1,"Function":4,"Voltage":{"R":0,"T":3,"F":-1},"Current":{"R":1,"T":8,"F":-3},"Power":{"R":3,"T":8,"F":-1},"Factor":{"R":8,"T":3,"F":-2},"Frequency":{"R":7,"T":3,"F":-1},"Total":{"R":5,"T":8,"F":-3},"User":{"R":0,"J":"VoltageTest","G":"Voltage test","U":"V","D":21,"T":3,"F":-1}} endon + * + * rule3 on file#modbus do {"Name":"SDM230 test6","Baud":2400,"Config":"8N1","Address":1,"Function":4,"Voltage":{"R":0,"T":0,"M":1},"Current":{"R":6,"T":0,"M":1},"Power":{"R":12,"T":0,"M":1},"Frequency":70,"Total":342} endon + * rule3 on file#modbus do {"Name":"SDM230 test6","Baud":2400,"Config":"8N1","Address":1,"Function":4,"Voltage":{"R":0,"T":0,"F":0},"Current":{"R":6,"T":0,"F":0},"Power":{"R":12,"T":0,"F":0},"Frequency":70,"Total":342,"User":{"R":0x0048,"T":0,"F":-1,"J":"ImportActive","G":"Import Active","U":"kWh","D":24}} endon \*********************************************************************************************/ #define XNRG_29 29 From dfc01cd3a4f3d74f900f4c27ef1a942b7329c7ce Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Tue, 3 Jan 2023 09:33:31 +0100 Subject: [PATCH 087/262] Fix crash when getting IP address (#17576) --- tasmota/tasmota_support/support_wifi.ino | 2 +- tasmota/tasmota_xdrv_driver/xdrv_82_esp32_ethernet.ino | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tasmota/tasmota_support/support_wifi.ino b/tasmota/tasmota_support/support_wifi.ino index 1baa6652a..6d946e3cd 100644 --- a/tasmota/tasmota_support/support_wifi.ino +++ b/tasmota/tasmota_support/support_wifi.ino @@ -639,7 +639,7 @@ bool DNSGetIP(IPAddress *ip, uint32_t idx) if (ip != nullptr) { *ip = *ip_dns; } return true; } - *ip = *IP4_ADDR_ANY; + if (ip != nullptr) { *ip = *IP4_ADDR_ANY; } return false; } String DNSGetIPStr(uint32_t idx) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_82_esp32_ethernet.ino b/tasmota/tasmota_xdrv_driver/xdrv_82_esp32_ethernet.ino index a34c8cf0b..b9d795759 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_82_esp32_ethernet.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_82_esp32_ethernet.ino @@ -243,7 +243,7 @@ bool EthernetGetIP(IPAddress *ip) { if (ip != nullptr) { *ip = lip; } return true; } - *ip = IPAddress(); + if (ip != nullptr) { *ip = IPAddress(); } return false; #else // IPv4 only From 3810b78ef8436959ec6f47402847fbd1e93cf8a1 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Tue, 3 Jan 2023 12:24:34 +0100 Subject: [PATCH 088/262] Add energy var update at power on next day --- tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino b/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino index 839568bcc..f2cb3b462 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino @@ -350,14 +350,17 @@ void Energy200ms(void) if (RtcTime.valid) { if (!Energy.kWhtoday_offset_init && (RtcTime.day_of_year == Settings->energy_kWhdoy)) { + Energy.kWhtoday_offset_init = true; for (uint32_t i = 0; i < 3; i++) { Energy.kWhtoday_offset[i] = Settings->energy_kWhtoday_ph[i]; // RtcSettings.energy_kWhtoday_ph[i] = 0; } - Energy.kWhtoday_offset_init = true; } - if (LocalTime() == Midnight()) { + if ((LocalTime() == Midnight()) || (RtcTime.day_of_year > Settings->energy_kWhdoy)) { + Energy.kWhtoday_offset_init = true; + Settings->energy_kWhdoy = RtcTime.day_of_year; + for (uint32_t i = 0; i < 3; i++) { Settings->energy_kWhyesterday_ph[i] = RtcSettings.energy_kWhtoday_ph[i]; From 18c38ec05d07662828bb03f85008ab6fa8390efe Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Tue, 3 Jan 2023 15:10:05 +0100 Subject: [PATCH 089/262] Add support for filesystem file modbus.json --- .../tasmota_xnrg_energy/xnrg_29_modbus.ino | 37 +++++++++++++++---- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino b/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino index 9c5891b3a..59d7520c5 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino @@ -23,7 +23,9 @@ * Generic Modbus energy meter * * - Supports single three phase device or three single phase devices of same model on bus. - * - Uses a rule file called modbus allowing for easy configuration of modbus energy monitor device(s). + * - For easy configuration of modbus energy monitor device(s) use: + * - a rule file called modbus + * - a filesystem file called modbus.json * * Value pair description: * {"Name":"SDM230","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":0,"Current":6,"Power":12,"ApparentPower":18,"ReactivePower":24,"Factor":30,"Frequency":70,"Total":342,"ExportActive":0x004A} @@ -124,6 +126,7 @@ * rule3 on file#modbus do {"Name":"PZEM014","Baud":9600,"Config":"8N1","Address":1,"Function":4,"Voltage":{"R":0,"T":3,"F":-1},"Current":{"R":1,"T":8,"F":-3},"Power":{"R":3,"T":8,"F":-1},"Factor":{"R":8,"T":3,"F":-2},"Frequency":{"R":7,"T":3,"F":-1},"Total":{"R":5,"T":8,"F":-3}} endon * rule3 on file#modbus do {"Name":"3 x PZEM014","Baud":9600,"Config":"8N1","Address":[1,2,3],"Function":4,"Voltage":{"R":0,"T":3,"F":-1},"Current":{"R":1,"T":8,"F":-3},"Power":{"R":3,"T":8,"F":-1},"Factor":{"R":8,"T":3,"F":-2},"Frequency":{"R":7,"T":3,"F":-1},"Total":{"R":5,"T":8,"F":-3}} endon * rule3 on file#modbus do {"Name":"Solax X3MIC","Baud":9600,"Config":"8N1","Address":1,"Function":4,"Voltage":{"R":0x0404,"T":3,"F":-1},"Power":{"R":0x040e,"T":3,"F":0},"Total":{"R":0x0423,"T":8,"F":-3}} endon + * rule3 on file#modbus do {"Name":"WE517","Baud":9600,"Config":"8E1","Address":1,"Function":3,"Voltage":[0xE,0x10,0x12],"Current":[0x16,0x18,0x1A],"Power":[0x1E,0x20,0x22],"ReactivePower":[0x26,0x28,0x2A],"Factor":[0x36,0x38,0x3A],"Frequency":0x14,"Total":0x100} endon * * Example using default Energy registers and some user defined registers: * rule3 on file#modbus do {"Name":"SDM72","Baud":9600,"Config":"8N1","Address":0x01,"Function":0x04,"Power":0x0034,"Total":0x0156,"ExportActive":0x004A,"User":[{"R":0x0502,"J":"ImportActive","G":"Import Active","U":"kWh","D":24},{"R":0x0502,"J":"ExportPower","G":"Export Power","U":"W","D":23},{"R":0x0500,"J":"ImportPower","G":"Import Power","U":"W","D":23}]} endon @@ -180,6 +183,9 @@ //#define ENERGY_MODBUS_DEBUG //#define ENERGY_MODBUS_DEBUG_SHOW +#define ENERGY_MODBUS_FILE "/modbus.json" // Modbus parameter file name used by filesystem +#define ENERGY_MODBUS_MAX_FSIZE 1024 // Modbus parameter file max size + const uint16_t nrg_mbs_reg_not_used = 0xFFFF; // Odd number 65535 is unused register // Even data type is single (2-byte) register, Odd data type is double (4-byte) registers @@ -482,7 +488,6 @@ void EnergyModbusLoop(void) { NrgMbsParam.mutex = 0; } -#ifdef USE_RULES uint32_t EnergyModbusReadRegisterInfo(JsonParserObject add_value, uint32_t reg_index) { // {"R":0,"T":0,"F":0} // {"R":[0,2,4],"T":0,"F":0} @@ -581,11 +586,31 @@ bool EnergyModbusReadUserRegisters(JsonParserObject user_add_value, uint32_t add return true; } -#endif // USE_RULES bool EnergyModbusReadRegisters(void) { + String modbus = ""; + +#ifdef USE_UFILESYS + const size_t file_size = ENERGY_MODBUS_MAX_FSIZE; + char *modbus_file = (char*)calloc(file_size, 1); + if (modbus_file) { + if (TfsLoadFile(ENERGY_MODBUS_FILE, (uint8_t*)modbus_file, file_size -1)) { + if (strlen(modbus_file) < ENERGY_MODBUS_MAX_FSIZE) { + modbus = modbus_file; + AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Load from file")); + } + } + free(modbus_file); + } +#endif // USE_UFILESYS + #ifdef USE_RULES - String modbus = RuleLoadFile("MODBUS"); + if (!modbus.length()) { + modbus = RuleLoadFile("MODBUS"); + AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Load from rule")); + } +#endif // USE_RULES + if (!modbus.length()) { return false; } // File not found // AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: File '%s'"), modbus.c_str()); @@ -811,15 +836,13 @@ bool EnergyModbusReadRegisters(void) { NrgMbsParam.phase = -1; return true; -#endif // USE_RULES - return false; } bool EnergyModbusRegisters(void) { if (EnergyModbusReadRegisters()) { return true; } - AddLog(LOG_LEVEL_INFO, PSTR("NRG: No valid modbus rule data")); + AddLog(LOG_LEVEL_INFO, PSTR("NRG: No valid modbus data")); return false; } From 65476c3b3258db5acc66e5c545e575f722332de6 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Tue, 3 Jan 2023 17:05:18 +0100 Subject: [PATCH 090/262] Add energy modbus configs --- .../energy_modbus_configs/configurations.md | 43 +++++++ .../value_pairs_description.md | 100 +++++++++++++++ .../tasmota_xnrg_energy/xnrg_29_modbus.ino | 116 +----------------- 3 files changed, 146 insertions(+), 113 deletions(-) create mode 100644 tasmota/energy_modbus_configs/configurations.md create mode 100644 tasmota/energy_modbus_configs/value_pairs_description.md diff --git a/tasmota/energy_modbus_configs/configurations.md b/tasmota/energy_modbus_configs/configurations.md new file mode 100644 index 000000000..15266c92b --- /dev/null +++ b/tasmota/energy_modbus_configs/configurations.md @@ -0,0 +1,43 @@ +# Modbus JSON configurations + +Modbus JSON configuration data for use with generic Energy Modbus driver. + +## Options to select modbus JSON data + +1. Rule driven - copy the required JSON content to any rule buffer preceded with ``rule3 on file#modbus do `` and + followed with `` endon``. +2. File system driven - if a file system is present (every ESP32) create a file called ``modbus.json`` and copy the required JSON + content to it. + +## Notes + - To enter long rules using the serial console and solve error "Serial buffer overrun" you might need to enlarge the serial input buffer with command ``serialbuffer 800`` + - Changes to configurations are activated only after command ``restart`` + +## Default configurations + +``` +DDSU6666 {"Name":"DDSU666","Baud":9600,"Config":"8N1","Address":1,"Function":4,"Voltage":0x2000,"Current":0x2002,"Power":0x2004,"ReactivePower":0x2006,"Factor":0x200A,"Frequency":0x200E,"Total":0x4000,"ExportActive":0x400A} + +PZEM014 {"Name":"PZEM014","Baud":9600,"Config":"8N1","Address":1,"Function":4,"Voltage":{"R":0,"T":3,"F":-1},"Current":{"R":1,"T":8,"F":-3},"Power":{"R":3,"T":8,"F":-1},"Factor":{"R":8,"T":3,"F":-2},"Frequency":{"R":7,"T":3,"F":-1},"Total":{"R":5,"T":8,"F":-3}} + +3 x PZEM014 {"Name":"3 x PZEM014","Baud":9600,"Config":"8N1","Address":[1,2,3],"Function":4,"Voltage":{"R":0,"T":3,"F":-1},"Current":{"R":1,"T":8,"F":-3},"Power":{"R":3,"T":8,"F":-1},"Factor":{"R":8,"T":3,"F":-2},"Frequency":{"R":7,"T":3,"F":-1},"Total":{"R":5,"T":8,"F":-3}} + +SDM230 {"Name":"SDM230","Baud":2400,"Config":"8N1","Address":1,"Function":4,"Voltage":0,"Current":6,"Power":12,"ApparentPower":18,"ReactivePower":24,"Factor":30,"Frequency":70,"Total":342,"ExportActive":0x004A} + +Solax X3MIC {"Name":"Solax X3MIC","Baud":9600,"Config":"8N1","Address":1,"Function":4,"Voltage":{"R":0x0404,"T":3,"F":-1},"Power":{"R":0x040e,"T":3,"F":0},"Total":{"R":0x0423,"T":8,"F":-3}} + +WE517 {"Name":"WE517","Baud":9600,"Config":"8E1","Address":1,"Function":3,"Voltage":[0xE,0x10,0x12],"Current":[0x16,0x18,0x1A],"Power":[0x1E,0x20,0x22],"ReactivePower":[0x26,0x28,0x2A],"Factor":[0x36,0x38,0x3A],"Frequency":0x14,"Total":0x100} +``` + +## Extended configurations +``` +SDM72 {"Name":"SDM72","Baud":9600,"Config":"8N1","Address":0x01,"Function":0x04,"Power":0x0034,"Total":0x0156,"ExportActive":0x004A,"User":[{"R":0x0502,"J":"ImportActive","G":"Import Active","U":"kWh","D":24},{"R":0x0502,"J":"ExportPower","G":"Export Power","U":"W","D":23},{"R":0x0500,"J":"ImportPower","G":"Import Power","U":"W","D":23}]} + +SDM120 {"Name":"SDM120","Baud":2400,"Config":"8N1","Address":1,"Function":4,"Voltage":0,"Current":6,"Power":12,"ApparentPower":18,"ReactivePower":24,"Factor":30,"Frequency":70,"Total":342,"ExportActive":0x004A,"User":[{"R":0x0048,"J":"ImportActive","G":"Import Active","U":"kWh","D":24},{"R":0x004E,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":24},{"R":0x004C,"J":"ImportReactive","G":"Import Reactive","U":"kVArh","D":24},{"R":0x0024,"J":"PhaseAngle","G":"Phase Angle","U":"Deg","D":2}]} + +SDM230 {"Name":"SDM230 with two user registers","Baud":2400,"Config":"8N1","Address":1,"Function":4,"Voltage":0,"Current":6,"Power":12,"ApparentPower":18,"ReactivePower":24,"Factor":30,"Frequency":70,"Total":342,"ExportActive":0x004A,"User":[{"R":0x004E,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":3},{"R":0x0024,"J":"PhaseAngle","G":"Phase Angle","U":"Deg","D":2}]} + +SDM630 {"Name":"SDM630","Baud":9600,"Config":"8N1","Address":1,"Function":4,"Voltage":[0,2,4],"Current":[6,8,10],"Power":[12,14,16],"ApparentPower":[18,20,22],"ReactivePower":[24,26,28],"Factor":[30,32,34],"Frequency":70,"Total":342,"ExportActive":[352,354,356],"User":{"R":[346,348,350],"J":"ImportActive","G":"Import Active","U":"kWh","D":24}} + +WE517 {"Name":"WE517","Baud":9600,"Config":"8E1","Address":1,"Function":3,"Voltage":[0xE,0x10,0x12],"Current":[0x16,0x18,0x1A],"Power":[0x1E,0x20,0x22],"ReactivePower":[0x26,0x28,0x2A],"Factor":[0x36,0x38,0x3A],"Frequency":0x14,"Total":0x100,"ExportActive":0x110,"User":[{"J":"ImportActive","G":"Import Active","R":0x108,"U":"kWh","D":24},{"J":"TotalPower","G":"Active Power Total","R":0x1C,"U":"W","D":23}]} +``` \ No newline at end of file diff --git a/tasmota/energy_modbus_configs/value_pairs_description.md b/tasmota/energy_modbus_configs/value_pairs_description.md new file mode 100644 index 000000000..67a73dee2 --- /dev/null +++ b/tasmota/energy_modbus_configs/value_pairs_description.md @@ -0,0 +1,100 @@ +# JSON value pair description + +## Example +``` +{"Name":"SDM230","Baud":2400,"Config":"8N1","Address":1,"Function":4,"Voltage":0,"Current":6,"Power":12,"ApparentPower":18,"ReactivePower":24,"Factor":30,"Frequency":70,"Total":342,"ExportActive":0x004A} +``` + +## Modbus config parameters +``` + Name - Name of energy monitoring device(s) + Baud - Baudrate of device modbus interface - optional. default is 9600 + Config - Serial config parameters like 8N1 - 8 databits, No parity, 1 stop bit + Poll - Time between modbus requests - optional. default is 200 milliseconds + Address - Modbus device address entered as decimal (1) or hexadecimal (0x01) or up to three addresses ([1,2,3]) - optional. default = 1 + Function - Modbus function code to access registers - optional. default = 4 +``` +## Tasmota default embedded register names +``` + Voltage - Voltage register entered as decimal or hexadecimal for one phase (0x0000) or up to three phases ([0x0000,0x0002,0x0004]) or + Additional defined parameters + Value pair description: + {"R":0,"T":0,"F":0} + R - Modbus register entered as decimal or hexadecimal for one phase (0x0160) or up to three phases ([0x0160,0x0162,0x0164]) + T - Datatype - optional. default is 0 - float: + 0 - float + 1 = 2-byte signed + 2 = 4-byte signed + 3 = 2-byte unsigned + 4 = 4-byte unsigned + 5 = not used + 6 = 4-byte signed with swapped words + 7 = not used + 8 = 4-byte unsigned with swapped words + F - Register factor positive for multiplication or negative for division - optional. default is 0 - no action + -4 - divide by 10000 + -3 - divide by 1000 + -2 - divide by 100 + -1 - divide by 10 + 0 - no action + 1 - multiply by 10 + 2 - multiply by 100 + 3 - multiply by 1000 + 4 - multiply by 10000 + Current - Current register entered as decimal or hexadecimal for one phase (0x0006) or up to three phases ([0x0006,0x0008,0x000A]) or + See additional defines like voltage. + Power - Active power register entered as decimal or hexadecimal for one phase (0x000C) or up to three phases ([0x000C,0x000E,0x0010]) or + See additional defines like voltage. + ApparentPower - Apparent power register entered as decimal or hexadecimal for one phase (0x000C) or up to three phases ([0x000C,0x000E,0x0010]) or + See additional defines like voltage. + ReactivePower - Reactive power register entered as decimal or hexadecimal for one phase (0x0018) or up to three phases ([0x0018,0x001A,0x001C]) or + See additional defines like voltage. + Factor - Power factor register entered as decimal or hexadecimal for one phase (0x001E) or up to three phases ([0x001E,0x0020,0x0022]) or + See additional defines like voltage. + Frequency - Frequency register entered as decimal or hexadecimal for one phase (0x0046) or up to three phases ([0x0046,0x0048,0x004A]) or + See additional defines like voltage. + Total - Total active energy register entered as decimal or hexadecimal for one phase (0x0156) or up to three phases ([0x015A,0x015C,0x015E]) or + See additional defines like voltage. + ExportActive - Export active energy register entered as decimal or hexadecimal for one phase (0x0160) or up to three phases ([0x0160,0x0162,0x0164]) or + See additional defines like voltage. +``` +## Optional user defined registers +``` + User - Additional user defined registers + Value pair description: + "User":{"R":0x0024,"T":0,"F":0,"J":"PhaseAngle","G":"Phase Angle","U":"Deg","D":2} + R - Modbus register entered as decimal or hexadecimal for one phase (0x0160) or up to three phases ([0x0160,0x0162,0x0164]) + T - Datatype - optional. default is 0 - float: + 0 - float + 1 = 2-byte signed + 2 = 4-byte signed + 3 = 2-byte unsigned + 4 = 4-byte unsigned + 5 = not used + 6 = 4-byte signed with swapped words + 7 = not used + 8 = 4-byte unsigned with swapped words + F - Register factor positive for multiplication or negative for division - optional. default is 0 - no action + -4 - divide by 10000 + -3 - divide by 1000 + -2 - divide by 100 + -1 - divide by 10 + 0 - no action + 1 - multiply by 10 + 2 - multiply by 100 + 3 - multiply by 1000 + 4 - multiply by 10000 + J - JSON register name (preferrably without spaces like "PhaseAngle") - mandatory. It needs to be different from the Tasmota default embedded register names + G - GUI register name - optional. If not defined the register will not be shown in the GUI + U - GUI unit name - optional. default is none + D - Number of decimals for floating point presentation (0 to 20) or a code correspondig to Tasmota resolution command settings: + 21 - VoltRes (V) + 22 - AmpRes (A) + 23 - WattRes (W, VA, VAr) + 24 - EnergyRes (kWh, kVAh, kVArh) + 25 - FreqRes (Hz) + 26 - TempRes (C, F) + 27 - HumRes (%) + 28 - PressRes (hPa, mmHg) + 29 - WeightRes (Kg) +``` \ No newline at end of file diff --git a/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino b/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino index 59d7520c5..074a31801 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino @@ -27,117 +27,7 @@ * - a rule file called modbus * - a filesystem file called modbus.json * - * Value pair description: - * {"Name":"SDM230","Baud":2400,"Config":8N1","Address":1,"Function":4,"Voltage":0,"Current":6,"Power":12,"ApparentPower":18,"ReactivePower":24,"Factor":30,"Frequency":70,"Total":342,"ExportActive":0x004A} - * Modbus config parameters: - * Name - Name of energy monitoring device(s) - * Baud - Baudrate of device modbus interface - optional. default is 9600 - * Config - Serial config parameters like 8N1 - 8 databits, No parity, 1 stop bit - * Poll - Time between modbus requests - optional. default is 200 milliseconds - * Address - Modbus device address entered as decimal (1) or hexadecimal (0x01) or up to three addresses ([1,2,3]) - optional. default = 1 - * Function - Modbus function code to access registers - optional. default = 4 - * Tasmota default embedded register names: - * Voltage - Voltage register entered as decimal or hexadecimal for one phase (0x0000) or up to three phases ([0x0000,0x0002,0x0004]) or - * Additional defined parameters - * Value pair description: - * {"R":0,"T":0,"F":0} - * R - Modbus register entered as decimal or hexadecimal for one phase (0x0160) or up to three phases ([0x0160,0x0162,0x0164]) - * T - Datatype - optional. default is 0 - float: - * 0 - float - * 1 = 2-byte signed - * 2 = 4-byte signed - * 3 = 2-byte unsigned - * 4 = 4-byte unsigned - * 5 = not used - * 6 = 4-byte signed with swapped words - * 7 = not used - * 8 = 4-byte unsigned with swapped words - * F - Register factor positive for multiplication or negative for division - optional. default is 0 - no action - * -4 - divide by 10000 - * -3 - divide by 1000 - * -2 - divide by 100 - * -1 - divide by 10 - * 0 - no action - * 1 - multiply by 10 - * 2 - multiply by 100 - * 3 - multiply by 1000 - * 4 - multiply by 10000 - * M - [LEGACY - replaced by "F"] Divide register by 1 to 10000 - optional. default = 0 (no action) - * Current - Current register entered as decimal or hexadecimal for one phase (0x0006) or up to three phases ([0x0006,0x0008,0x000A]) or - * See additional defines like voltage. - * Power - Active power register entered as decimal or hexadecimal for one phase (0x000C) or up to three phases ([0x000C,0x000E,0x0010]) or - * See additional defines like voltage. - * ApparentPower - Apparent power register entered as decimal or hexadecimal for one phase (0x000C) or up to three phases ([0x000C,0x000E,0x0010]) or - * See additional defines like voltage. - * ReactivePower - Reactive power register entered as decimal or hexadecimal for one phase (0x0018) or up to three phases ([0x0018,0x001A,0x001C]) or - * See additional defines like voltage. - * Factor - Power factor register entered as decimal or hexadecimal for one phase (0x001E) or up to three phases ([0x001E,0x0020,0x0022]) or - * See additional defines like voltage. - * Frequency - Frequency register entered as decimal or hexadecimal for one phase (0x0046) or up to three phases ([0x0046,0x0048,0x004A]) or - * See additional defines like voltage. - * Total - Total active energy register entered as decimal or hexadecimal for one phase (0x0156) or up to three phases ([0x015A,0x015C,0x015E]) or - * See additional defines like voltage. - * ExportActive - Export active energy register entered as decimal or hexadecimal for one phase (0x0160) or up to three phases ([0x0160,0x0162,0x0164]) or - * See additional defines like voltage. - * Optional user defined registers: - * User - Additional user defined registers - * Value pair description: - * "User":{"R":0x0024,"T":0,"F":0,"J":"PhaseAngle","G":"Phase Angle","U":"Deg","D":2} - * R - Modbus register entered as decimal or hexadecimal for one phase (0x0160) or up to three phases ([0x0160,0x0162,0x0164]) - * T - Datatype - optional. default is 0 - float: - * 0 - float - * 1 = 2-byte signed - * 2 = 4-byte signed - * 3 = 2-byte unsigned - * 4 = 4-byte unsigned - * 5 = not used - * 6 = 4-byte signed with swapped words - * 7 = not used - * 8 = 4-byte unsigned with swapped words - * F - Register factor positive for multiplication or negative for division - optional. default is 0 - no action - * -4 - divide by 10000 - * -3 - divide by 1000 - * -2 - divide by 100 - * -1 - divide by 10 - * 0 - no action - * 1 - multiply by 10 - * 2 - multiply by 100 - * 3 - multiply by 1000 - * 4 - multiply by 10000 - * M - [LEGACY - replaced by "F"] Divide register by 1 to 10000 - optional. default = 0 (no action) - * J - JSON register name (preferrably without spaces like "PhaseAngle") - mandatory. It needs to be different from the Tasmota default embedded register names - * G - GUI register name - optional. If not defined the register will not be shown in the GUI - * U - GUI unit name - optional. default is none - * D - Number of decimals for floating point presentation (0 to 20) or a code correspondig to Tasmota resolution command settings: - * 21 - VoltRes (V) - * 22 - AmpRes (A) - * 23 - WattRes (W, VA, VAr) - * 24 - EnergyRes (kWh, kVAh, kVArh) - * 25 - FreqRes (Hz) - * 26 - TempRes (C, F) - * 27 - HumRes (%) - * 28 - PressRes (hPa, mmHg) - * 29 - WeightRes (Kg) - * - * Example using default Energy registers: - * rule3 on file#modbus do {"Name":"SDM230","Baud":2400,"Config":"8N1","Address":1,"Function":4,"Voltage":0,"Current":6,"Power":12,"ApparentPower":18,"ReactivePower":24,"Factor":30,"Frequency":70,"Total":342,"ExportActive":0x004A} endon - * rule3 on file#modbus do {"Name":"SDM230 with hex registers","Baud":2400,"Config":"8N1","Address":1,"Function":4,"Voltage":0x0000,"Current":0x0006,"Power":0x000C,"ApparentPower":0x0012,"ReactivePower":0x0018,"Factor":0x001E,"Frequency":0x0046,"Total":0x0156,"ExportActive":0x004A} endon - * rule3 on file#modbus do {"Name":"DDSU666","Baud":9600,"Config":"8N1","Address":1,"Function":4,"Voltage":0x2000,"Current":0x2002,"Power":0x2004,"ReactivePower":0x2006,"Factor":0x200A,"Frequency":0x200E,"Total":0x4000,"ExportActive":0x400A} endon - * rule3 on file#modbus do {"Name":"PZEM014","Baud":9600,"Config":"8N1","Address":1,"Function":4,"Voltage":{"R":0,"T":3,"F":-1},"Current":{"R":1,"T":8,"F":-3},"Power":{"R":3,"T":8,"F":-1},"Factor":{"R":8,"T":3,"F":-2},"Frequency":{"R":7,"T":3,"F":-1},"Total":{"R":5,"T":8,"F":-3}} endon - * rule3 on file#modbus do {"Name":"3 x PZEM014","Baud":9600,"Config":"8N1","Address":[1,2,3],"Function":4,"Voltage":{"R":0,"T":3,"F":-1},"Current":{"R":1,"T":8,"F":-3},"Power":{"R":3,"T":8,"F":-1},"Factor":{"R":8,"T":3,"F":-2},"Frequency":{"R":7,"T":3,"F":-1},"Total":{"R":5,"T":8,"F":-3}} endon - * rule3 on file#modbus do {"Name":"Solax X3MIC","Baud":9600,"Config":"8N1","Address":1,"Function":4,"Voltage":{"R":0x0404,"T":3,"F":-1},"Power":{"R":0x040e,"T":3,"F":0},"Total":{"R":0x0423,"T":8,"F":-3}} endon - * rule3 on file#modbus do {"Name":"WE517","Baud":9600,"Config":"8E1","Address":1,"Function":3,"Voltage":[0xE,0x10,0x12],"Current":[0x16,0x18,0x1A],"Power":[0x1E,0x20,0x22],"ReactivePower":[0x26,0x28,0x2A],"Factor":[0x36,0x38,0x3A],"Frequency":0x14,"Total":0x100} endon - * - * Example using default Energy registers and some user defined registers: - * rule3 on file#modbus do {"Name":"SDM72","Baud":9600,"Config":"8N1","Address":0x01,"Function":0x04,"Power":0x0034,"Total":0x0156,"ExportActive":0x004A,"User":[{"R":0x0502,"J":"ImportActive","G":"Import Active","U":"kWh","D":24},{"R":0x0502,"J":"ExportPower","G":"Export Power","U":"W","D":23},{"R":0x0500,"J":"ImportPower","G":"Import Power","U":"W","D":23}]} endon - * rule3 on file#modbus do {"Name":"SDM120","Baud":2400,"Config":"8N1","Address":1,"Function":4,"Voltage":0,"Current":6,"Power":12,"ApparentPower":18,"ReactivePower":24,"Factor":30,"Frequency":70,"Total":342,"ExportActive":0x004A,"User":[{"R":0x0048,"J":"ImportActive","G":"Import Active","U":"kWh","D":24},{"R":0x004E,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":24},{"R":0x004C,"J":"ImportReactive","G":"Import Reactive","U":"kVArh","D":24},{"R":0x0024,"J":"PhaseAngle","G":"Phase Angle","U":"Deg","D":2}]} endon - * rule3 on file#modbus do {"Name":"SDM230 with two user registers","Baud":2400,"Config":"8N1","Address":1,"Function":4,"Voltage":0,"Current":6,"Power":12,"ApparentPower":18,"ReactivePower":24,"Factor":30,"Frequency":70,"Total":342,"ExportActive":0x004A,"User":[{"R":0x004E,"J":"ExportReactive","G":"Export Reactive","U":"kVArh","D":3},{"R":0x0024,"J":"PhaseAngle","G":"Phase Angle","U":"Deg","D":2}]} endon - * rule3 on file#modbus do {"Name":"SDM630","Baud":9600,"Config":"8N1","Address":1,"Function":4,"Voltage":[0,2,4],"Current":[6,8,10],"Power":[12,14,16],"ApparentPower":[18,20,22],"ReactivePower":[24,26,28],"Factor":[30,32,34],"Frequency":70,"Total":342,"ExportActive":[352,354,356],"User":{"R":[346,348,350],"J":"ImportActive","G":"Import Active","U":"kWh","D":24}} endon - * rule3 on file#modbus do {"Name":"WE517","Baud":9600,"Config":"8E1","Address":1,"Function":3,"Voltage":[0xE,0x10,0x12],"Current":[0x16,0x18,0x1A],"Power":[0x1E,0x20,0x22],"ReactivePower":[0x26,0x28,0x2A],"Factor":[0x36,0x38,0x3A],"Frequency":0x14,"Total":0x100,"ExportActive":0x110,"User":[{"J":"ImportActive","G":"Import Active","R":0x108,"U":"kWh","D":24},{"J":"TotalPower","G":"Active Power Total","R":0x1C,"U":"W","D":23}]} endon - * - * Note: - * - To enter long rules using the serial console and solve error "Serial buffer overrun" you might need to enlarge the serial input buffer with command serialbuffer 800 - * - Changes to rule file are only executed on restart + * See files configurations.md and value_pair_description.md in folder energy_modbus_configs * * Restrictions: * - Supports Modbus single and double integer registers in addition to floating point registers @@ -597,7 +487,7 @@ bool EnergyModbusReadRegisters(void) { if (TfsLoadFile(ENERGY_MODBUS_FILE, (uint8_t*)modbus_file, file_size -1)) { if (strlen(modbus_file) < ENERGY_MODBUS_MAX_FSIZE) { modbus = modbus_file; - AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Load from file")); + AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Loaded from File")); } } free(modbus_file); @@ -607,7 +497,7 @@ bool EnergyModbusReadRegisters(void) { #ifdef USE_RULES if (!modbus.length()) { modbus = RuleLoadFile("MODBUS"); - AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Load from rule")); + AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Loaded from Rule")); } #endif // USE_RULES From 82ed5f0d06e817b373ee7acff24d4a3d066a69b2 Mon Sep 17 00:00:00 2001 From: gemu Date: Tue, 3 Jan 2023 17:41:37 +0100 Subject: [PATCH 091/262] Modbus section (#17583) * modbus section * Update xnrg_29_modbus.ino * Update xnrg_29_modbus.ino * Update xnrg_29_modbus.ino --- .../tasmota_xdrv_driver/xdrv_10_scripter.ino | 78 +++++++++++++++++-- .../tasmota_xnrg_energy/xnrg_29_modbus.ino | 7 ++ 2 files changed, 77 insertions(+), 8 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino b/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino index 1e60baf1f..bac7dd575 100755 --- a/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino @@ -2564,6 +2564,37 @@ chknext: } goto nfuncexit; } + if (!strncmp(lp, "ap(", 3)) { + //TasmotaGlobal.restart_flag = 216; + lp = GetNumericArgument(lp + 3, OPER_EQU, &fvar, gv); + switch ((uint8_t)fvar) { + case 0: + { char ssid[SCRIPT_MAXSSIZE]; + lp = GetStringArgument(lp, OPER_EQU, ssid, 0); + char pw[SCRIPT_MAXSSIZE]; + lp = GetStringArgument(lp, OPER_EQU, pw, 0); + IPAddress local_IP(192,168,189,1); + IPAddress gateway(192,168,189,1); + IPAddress subnet(255,255,255,0); + // Begin Access Point + WiFi.softAPConfig(local_IP, gateway, subnet); + fvar = WiFi.softAP(ssid, pw); + } + break; + case 1: + fvar = WiFi.softAPdisconnect(true); + break; + case 2: + fvar = WiFi.disconnect(true); + break; + } + + //Web.state = HTTP_ADMIN; + // 192.168.4.1 + // WiFi.softAPIP(); + + goto nfuncexit; + } break; case 'b': @@ -10290,6 +10321,25 @@ void ScriptJsonAppend(void) { } #endif //USE_SCRIPT_JSON_EXPORT +// returns section as string +String ScriptLoadSection(const char *sect) { + uint16_t slen = strlen(sect); + if (Run_Scripter1(sect, -slen, 0) == 99) { + char *spo = glob_script_mem.section_ptr + slen; + char *sp = spo; + while (*sp) { + if (*sp == '#') { + *sp = 0; + String str = spo; + *sp = '#'; + return str; + } + sp++; + } + } + return ""; +} + bool RulesProcessEvent(const char *json_event) { if (bitRead(Settings->rule_enabled, 0)) { @@ -10737,7 +10787,7 @@ void cpy2lf(char *dst, uint32_t dstlen, char *src) { #ifdef USE_SCRIPT_I2C uint8_t script_i2c_addr; TwoWire *script_i2c_wire; -uint32_t script_i2c(uint8_t sel, uint32_t val, uint32_t val1) { +uint32_t script_i2c(uint8_t sel, uint16_t val, uint32_t val1) { uint32_t rval = 0; uint8_t bytes = 1; @@ -10755,9 +10805,11 @@ uint32_t script_i2c(uint8_t sel, uint32_t val, uint32_t val1) { break; case 2: // read 1..4 bytes - script_i2c_wire->beginTransmission(script_i2c_addr); - script_i2c_wire->write(val); - script_i2c_wire->endTransmission(); + if ((val & 0x8000) == 0) { + script_i2c_wire->beginTransmission(script_i2c_addr); + script_i2c_wire->write(val); + script_i2c_wire->endTransmission(); + } script_i2c_wire->requestFrom((int)script_i2c_addr, (int)val1); for (uint8_t cnt = 0; cnt < val1; cnt++) { @@ -10773,10 +10825,20 @@ uint32_t script_i2c(uint8_t sel, uint32_t val, uint32_t val1) { // write 1 .. 4 bytes bytes = sel - 9; script_i2c_wire->beginTransmission(script_i2c_addr); - script_i2c_wire->write(val); - for (uint8_t cnt = 0; cnt < bytes; cnt++) { - script_i2c_wire->write(val1); - val1 >>= 8; + if ((val & 0x8000) == 0) { + script_i2c_wire->write(val); + } + if ((val & 0x4000) == 0) { + for (uint8_t cnt = 0; cnt < bytes; cnt++) { + script_i2c_wire->write(val1); + val1 >>= 8; + } + } else { + uint32_t wval = 0; + for (uint8_t cnt = 0; cnt < bytes; cnt++) { + wval = val1 >> ((bytes - 1 - cnt) * 8); + script_i2c_wire->write(wval); + } } script_i2c_wire->endTransmission(); break; diff --git a/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino b/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino index 074a31801..2d98c29e4 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino @@ -501,6 +501,13 @@ bool EnergyModbusReadRegisters(void) { } #endif // USE_RULES +#ifdef USE_SCRIPT + if (!modbus.length()) { + modbus = ScriptLoadSection(">y"); + AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Loaded from script")); + } +#endif // USE_SCRIPT + if (!modbus.length()) { return false; } // File not found // AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: File '%s'"), modbus.c_str()); From 481cc63bf41b209401c0c99243d7405583178c57 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Tue, 3 Jan 2023 17:50:39 +0100 Subject: [PATCH 092/262] Add script support to Energy Modbus --- tasmota/energy_modbus_configs/configurations.md | 4 +++- tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/tasmota/energy_modbus_configs/configurations.md b/tasmota/energy_modbus_configs/configurations.md index 15266c92b..68084c46c 100644 --- a/tasmota/energy_modbus_configs/configurations.md +++ b/tasmota/energy_modbus_configs/configurations.md @@ -6,7 +6,9 @@ Modbus JSON configuration data for use with generic Energy Modbus driver. 1. Rule driven - copy the required JSON content to any rule buffer preceded with ``rule3 on file#modbus do `` and followed with `` endon``. -2. File system driven - if a file system is present (every ESP32) create a file called ``modbus.json`` and copy the required JSON +2. Script driven - copy the required JSON content to a script preceded with ``>y`` and + followed with ``#``. +3. File system driven - if a file system is present (every ESP32) create a file called ``modbus.json`` and copy the required JSON content to it. ## Notes diff --git a/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino b/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino index 2d98c29e4..a95f65f8a 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino @@ -25,6 +25,7 @@ * - Supports single three phase device or three single phase devices of same model on bus. * - For easy configuration of modbus energy monitor device(s) use: * - a rule file called modbus + * - a script using >y * - a filesystem file called modbus.json * * See files configurations.md and value_pair_description.md in folder energy_modbus_configs @@ -481,10 +482,9 @@ bool EnergyModbusReadRegisters(void) { String modbus = ""; #ifdef USE_UFILESYS - const size_t file_size = ENERGY_MODBUS_MAX_FSIZE; - char *modbus_file = (char*)calloc(file_size, 1); + char *modbus_file = (char*)calloc(ENERGY_MODBUS_MAX_FSIZE, 1); if (modbus_file) { - if (TfsLoadFile(ENERGY_MODBUS_FILE, (uint8_t*)modbus_file, file_size -1)) { + if (TfsLoadFile(ENERGY_MODBUS_FILE, (uint8_t*)modbus_file, ENERGY_MODBUS_MAX_FSIZE -1)) { if (strlen(modbus_file) < ENERGY_MODBUS_MAX_FSIZE) { modbus = modbus_file; AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Loaded from File")); @@ -504,7 +504,7 @@ bool EnergyModbusReadRegisters(void) { #ifdef USE_SCRIPT if (!modbus.length()) { modbus = ScriptLoadSection(">y"); - AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Loaded from script")); + AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Loaded from Script")); } #endif // USE_SCRIPT From f570dcc91352ca73c6e9962b0c97a5c1d08fe03e Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Tue, 3 Jan 2023 19:43:41 +0100 Subject: [PATCH 093/262] Berry `bytes()` now evaluates to `false` if empty (#17585) --- CHANGELOG.md | 1 + lib/libesp32/berry/src/be_byteslib.c | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f8e98bc7..684ede3d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file. ## [12.3.1.3] ### Added - Support for PCA9632 4-channel 8-bit PWM driver as light driver by Pascal Heinrich (#17557) +- Berry `bytes()` now evaluates to `false` if empty ### Breaking Changed diff --git a/lib/libesp32/berry/src/be_byteslib.c b/lib/libesp32/berry/src/be_byteslib.c index 6fcd457db..665d630f3 100644 --- a/lib/libesp32/berry/src/be_byteslib.c +++ b/lib/libesp32/berry/src/be_byteslib.c @@ -1125,6 +1125,13 @@ static int m_size(bvm *vm) be_return(vm); } +static int m_tobool(bvm *vm) +{ + buf_impl attr = m_read_attributes(vm, 1); + be_pushbool(vm, attr.len > 0 ? 1 : 0); + be_return(vm); +} + static int m_resize(bvm *vm) { int argc = be_top(vm); @@ -1668,6 +1675,7 @@ void be_load_byteslib(bvm *vm) { "deinit", m_deinit }, { "tostring", m_tostring }, { "asstring", m_asstring }, + { "tobool", m_tobool }, { "fromstring", m_fromstring }, { "tob64", m_tob64 }, { "fromb64", m_fromb64 }, @@ -1714,6 +1722,7 @@ class be_class_bytes (scope: global, name: bytes) { deinit, func(m_deinit) tostring, func(m_tostring) asstring, func(m_asstring) + tobool, func(m_tobool) fromstring, func(m_fromstring) tob64, func(m_tob64) fromb64, func(m_fromb64) From d59caa7203ab3bc79227eb2c6bb7ccd26115a9e6 Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Tue, 3 Jan 2023 20:26:46 +0100 Subject: [PATCH 094/262] Berry ``crypto.AES_CCM`` (required by Matter protocol) (#17586) --- CHANGELOG.md | 1 + .../berry_tasmota/src/be_crypto_lib.c | 22 ++++ tasmota/my_user_config.h | 3 +- .../xdrv_52_3_berry_crypto.ino | 116 ++++++++++++++++++ 4 files changed, 141 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 684ede3d7..1e013ce67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ All notable changes to this project will be documented in this file. ### Added - Support for PCA9632 4-channel 8-bit PWM driver as light driver by Pascal Heinrich (#17557) - Berry `bytes()` now evaluates to `false` if empty +- Berry ``crypto.AES_CCM`` (required by Matter protocol) ### Breaking Changed diff --git a/lib/libesp32/berry_tasmota/src/be_crypto_lib.c b/lib/libesp32/berry_tasmota/src/be_crypto_lib.c index 43122303e..59518e120 100644 --- a/lib/libesp32/berry_tasmota/src/be_crypto_lib.c +++ b/lib/libesp32/berry_tasmota/src/be_crypto_lib.c @@ -11,6 +11,11 @@ extern int be_class_crypto_member(bvm *vm); extern int m_crypto_random(bvm *vm); +extern int m_aes_ccm_init(bvm *vm); +extern int m_aes_ccm_encryt(bvm *vm); +extern int m_aes_ccm_decryt(bvm *vm); +extern int m_aes_ccm_tag(bvm *vm); + extern int m_aes_gcm_init(bvm *vm); extern int m_aes_gcm_encryt(bvm *vm); extern int m_aes_gcm_decryt(bvm *vm); @@ -47,6 +52,7 @@ extern const bclass be_class_md5; #include "solidify/solidified_crypto_pbkdf2_hmac_sha256.h" #include "solidify/solidified_crypto_spake2p_matter.h" +#include "be_fixed_be_class_aes_ccm.h" #include "be_fixed_be_class_aes_gcm.h" #include "be_fixed_be_class_aes_ctr.h" #include "be_fixed_be_class_ec_p256.h" @@ -65,11 +71,17 @@ extern const bclass be_class_md5; #define USE_BERRY_CRYPTO_HMAC_SHA256 #undef USE_BERRY_CRYPTO_HKDF_SHA256 #define USE_BERRY_CRYPTO_HKDF_SHA256 + #undef USE_BERRY_CRYPTO_AES_CCM + #define USE_BERRY_CRYPTO_AES_CCM #endif const be_const_member_t be_crypto_members[] = { // name with prefix '/' indicates a Berry class // entries need to be sorted (ignoring the prefix char) +#ifdef USE_BERRY_CRYPTO_AES_CCM + { "/AES_CCM", (intptr_t) &be_class_aes_ccm }, +#endif // USE_BERRY_CRYPTO_AES_CTR + #ifdef USE_BERRY_CRYPTO_AES_CTR { "/AES_CTR", (intptr_t) &be_class_aes_ctr }, #endif // USE_BERRY_CRYPTO_AES_CTR @@ -114,6 +126,16 @@ const size_t be_crypto_members_size = sizeof(be_crypto_members)/sizeof(be_crypto /* @const_object_info_begin +class be_class_aes_ccm (scope: global, name: AES_CCM) { + .p1, var + .p2, var + + init, func(m_aes_ccm_init) + encrypt, func(m_aes_ccm_encryt) + decrypt, func(m_aes_ccm_decryt) + tag, func(m_aes_ccm_tag) +} + class be_class_aes_gcm (scope: global, name: AES_GCM) { .p1, var .p2, var diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index 6c6c6f60b..2c0e749f2 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -1120,7 +1120,8 @@ // #define USE_BERRY_ULP // Enable ULP (Ultra Low Power) support (+4.9k) // Berry crypto extensions below: #define USE_BERRY_CRYPTO_AES_GCM // enable AES GCM 256 bits - // #define USE_BERRY_CRYPTO_AES_CTR // enable AEC CTR 256 bits + // #define USE_BERRY_CRYPTO_AES_CCM // enable AES CCM 128 bits + // #define USE_BERRY_CRYPTO_AES_CTR // enable AES CTR 256 bits // #define USE_BERRY_CRYPTO_EC_P256 // enable EC P256r1 // #define USE_BERRY_CRYPTO_EC_C25519 // enable Elliptic Curve C C25519 #define USE_BERRY_CRYPTO_SHA256 // enable SHA256 hash function diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino index 6eba535ab..40261e22b 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino @@ -180,6 +180,122 @@ extern "C" { } } +/*********************************************************************************************\ + * AES_CCM class + * +\*********************************************************************************************/ +extern "C" { + + // `AES_CCM.init(secret_key:bytes(16 or 32), iv:bytes(7..13), aad:bytes(), data_len:int, tag_len:int) -> instance` + // + int32_t m_aes_ccm_init(struct bvm *vm); + int32_t m_aes_ccm_init(struct bvm *vm) { + int32_t argc = be_top(vm); // Get the number of arguments + if (argc >= 6 && be_isbytes(vm, 2) && be_isbytes(vm, 3) && be_isbytes(vm, 4) && be_isint(vm, 5) && be_isint(vm, 6)) { + do { + size_t key_len = 0; + const void * key = be_tobytes(vm, 2, &key_len); + if (key_len != 32 && key_len != 16) { + be_raise(vm, "value_error", "Key size must be 16 or 32 bytes"); + } + + size_t nonce_len = 0; + const void * nonce = be_tobytes(vm, 3, &nonce_len); + if (nonce_len < 7 || nonce_len > 13) { + be_raise(vm, "value_error", "Nonce size must be 7..13"); + } + + size_t aad_len = 0; + const void * aad = be_tobytes(vm, 4, &aad_len); + + int32_t data_len = be_toint(vm, 5); + + int32_t tag_len = be_toint(vm, 6); + if (tag_len < 4 || tag_len > 16) { + be_raise(vm, "value_error", "Tag size must be 4..16"); + } + + // Initialize an AES CCM structure with the secret key + br_ccm_context * ccm_ctx = (br_ccm_context *) be_os_malloc(sizeof(br_ccm_context)); + if (!ccm_ctx) { be_throw(vm, BE_MALLOC_FAIL); } + + be_newcomobj(vm, ccm_ctx, &be_commonobj_destroy_generic); + be_setmember(vm, 1, ".p1"); + + br_aes_small_ctrcbc_keys * key_ctx = (br_aes_small_ctrcbc_keys *) be_os_malloc(sizeof(br_aes_small_ctrcbc_keys)); + if (!key_ctx) { be_throw(vm, BE_MALLOC_FAIL); } + br_aes_small_ctrcbc_init(key_ctx, key, key_len); + be_newcomobj(vm, key_ctx, &be_commonobj_destroy_generic); + be_setmember(vm, 1, ".p2"); + + br_ccm_init(ccm_ctx, &key_ctx->vtable); + int ret = br_ccm_reset(ccm_ctx, nonce, nonce_len, aad_len, data_len, tag_len); + if (ret == 0) { be_raise(vm, "value_error", "br_ccm_reset failed"); } + + br_ccm_aad_inject(ccm_ctx, aad, aad_len); + br_ccm_flip(ccm_ctx); + + be_return_nil(vm); + // success + } while (0); + } + be_raise(vm, kTypeError, nullptr); + } + + // Finish injection of authentication data + int32_t m_aes_ccm_encrypt_or_decryt(bvm *vm, int encrypt); + int32_t m_aes_ccm_encryt(bvm *vm) { return m_aes_ccm_encrypt_or_decryt(vm, 1); } + int32_t m_aes_ccm_decryt(bvm *vm) { return m_aes_ccm_encrypt_or_decryt(vm, 0); } + int32_t m_aes_ccm_encrypt_or_decryt(bvm *vm, int encrypt) { + int32_t argc = be_top(vm); // Get the number of arguments + if (argc >= 2 && be_isbytes(vm, 2)) { + do { + // get CCM context + be_getmember(vm, 1, ".p1"); + br_ccm_context * ccm_ctx = (br_ccm_context *) be_tocomptr(vm, -1); + be_pop(vm, 1); + + // copy the input buffer + be_getmember(vm, 2, "copy"); // stack: bytes.copy() + be_pushvalue(vm, 2); // stack: bytes.copy(), bytes instance + be_call(vm, 1); // call copy with self parameter + be_pop(vm, 1); // stack: clone of input bytes + + size_t length = 0; + // we are changing bytes in place + void * bytes = (void*) be_tobytes(vm, -1, &length); + if (!bytes) break; + + br_ccm_run(ccm_ctx, encrypt, bytes, length); + + be_return(vm); + // success + } while (0); + } + be_raise(vm, kTypeError, nullptr); + } + + int32_t m_aes_ccm_tag(bvm *vm) { + do { + be_getglobal(vm, "bytes"); /* get the bytes class */ /* TODO eventually replace with be_getbuiltin */ + + // get CCM context + be_getmember(vm, 1, ".p1"); + br_ccm_context * ccm_ctx = (br_ccm_context *) be_tocomptr(vm, -1); + be_pop(vm, 1); + + // create a bytes buffer of 16 bytes + uint8_t tag[16] = {}; + br_ccm_get_tag(ccm_ctx, tag); + be_pushbytes(vm, tag, sizeof(tag)); + + be_return(vm); + // success + } while (0); + be_raise(vm, kTypeError, nullptr); + } +} + /*********************************************************************************************\ * AES_CTR class * From cd182a5814521965153531709c3a4037e2aa8c01 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Wed, 4 Jan 2023 12:00:09 +0100 Subject: [PATCH 095/262] Add TfsLoadString() --- .../xdrv_50_filesystem.ino | 25 ++++++++++++++----- .../tasmota_xnrg_energy/xnrg_29_modbus.ino | 18 ++++--------- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_50_filesystem.ino b/tasmota/tasmota_xdrv_driver/xdrv_50_filesystem.ino index db60d2e74..fc7ca39b8 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_50_filesystem.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_50_filesystem.ino @@ -306,6 +306,16 @@ bool TfsFileExists(const char *fname){ return yes; } +size_t TfsFileSize(const char *fname){ + if (!ffs_type) { return 0; } + + File file = ffsp->open(fname, "r"); + if (!file) { return 0; } + size_t flen = file.size(); + file.close(); + return flen; +} + bool TfsSaveFile(const char *fname, const uint8_t *buf, uint32_t len) { if (!ffs_type) { return false; } #ifdef USE_WEBCAM @@ -362,7 +372,6 @@ bool TfsInitFile(const char *fname, uint32_t len, uint8_t init_value) { bool TfsLoadFile(const char *fname, uint8_t *buf, uint32_t len) { if (!ffs_type) { return false; } - if (!TfsFileExists(fname)) { return false; } File file = ffsp->open(fname, "r"); if (!file) { @@ -371,15 +380,19 @@ bool TfsLoadFile(const char *fname, uint8_t *buf, uint32_t len) { } size_t flen = file.size(); - if (len > flen){ - len = flen; - } - + if (len > flen) { len = flen; } // Adjust requested length to smaller file length file.read(buf, len); file.close(); return true; } +String TfsLoadString(const char *fname) { + // Use a reasonable amount of stack space considering 4k/8k available on ESP8266/ESP32 and manageable string length + char buf[2048] = { 0 }; // Prepare empty string of max 2047 characters on stack + TfsLoadFile(fname, (uint8_t*)buf, 2047); // Leave last position as end of string ('\0') + return String(buf); // Received string or empty on error +} + bool TfsDeleteFile(const char *fname) { if (!ffs_type) { return false; } @@ -825,7 +838,7 @@ void UfsListDir(char *path, uint8_t depth) { editpath[0]=0; #endif // GUI_TRASH_FILE ext_snprintf_P(npath, sizeof(npath), UFS_FORM_SDC_HREF, ppe, epe); - WSContentSend_P(UFS_FORM_SDC_DIRb, hiddable ? UFS_FORM_SDC_DIR_HIDDABLE : UFS_FORM_SDC_DIR_NORMAL, npath, epe, + WSContentSend_P(UFS_FORM_SDC_DIRb, hiddable ? UFS_FORM_SDC_DIR_HIDDABLE : UFS_FORM_SDC_DIR_NORMAL, npath, epe, HtmlEscape(name).c_str(), tstr.c_str(), entry.size(), delpath, editpath); } entry.close(); diff --git a/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino b/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino index a95f65f8a..a98f94fe2 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino @@ -75,7 +75,6 @@ //#define ENERGY_MODBUS_DEBUG_SHOW #define ENERGY_MODBUS_FILE "/modbus.json" // Modbus parameter file name used by filesystem -#define ENERGY_MODBUS_MAX_FSIZE 1024 // Modbus parameter file max size const uint16_t nrg_mbs_reg_not_used = 0xFFFF; // Odd number 65535 is unused register @@ -482,15 +481,9 @@ bool EnergyModbusReadRegisters(void) { String modbus = ""; #ifdef USE_UFILESYS - char *modbus_file = (char*)calloc(ENERGY_MODBUS_MAX_FSIZE, 1); - if (modbus_file) { - if (TfsLoadFile(ENERGY_MODBUS_FILE, (uint8_t*)modbus_file, ENERGY_MODBUS_MAX_FSIZE -1)) { - if (strlen(modbus_file) < ENERGY_MODBUS_MAX_FSIZE) { - modbus = modbus_file; - AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Loaded from File")); - } - } - free(modbus_file); + modbus = TfsLoadString(ENERGY_MODBUS_FILE); + if (modbus.length()) { + AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Loaded from File")); } #endif // USE_UFILESYS @@ -508,13 +501,12 @@ bool EnergyModbusReadRegisters(void) { } #endif // USE_SCRIPT - if (!modbus.length()) { return false; } // File not found + if (modbus.length() < 7) { return false; } // File not found or Invalid JSON + // AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: File '%s'"), modbus.c_str()); const char* json = modbus.c_str(); uint32_t len = strlen(json) +1; - if (len < 7) { return false; } // Invalid JSON - char json_buffer[len]; memcpy(json_buffer, json, len); // Keep original safe JsonParser parser(json_buffer); From ff8291f77dd30aa5724f5d4e9ea748a83f4fadd3 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Wed, 4 Jan 2023 15:00:43 +0100 Subject: [PATCH 096/262] Add support for filesystem calib.dat --- tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino | 11 +++++++++-- tasmota/tasmota_xnrg_energy/xnrg_23_ade7880.ino | 10 ++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino b/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino index f30619274..c5f282bef 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino @@ -608,14 +608,21 @@ void Ade7953Defaults(void) { } } } + + String calib = ""; +#ifdef USE_UFILESYS + calib = TfsLoadString("/calib.dat"); +#endif // USE_UFILESYS #ifdef USE_RULES // rule3 on file#calib.dat do {"angles":{"angle0":180,"angle1":176}} endon - String calib = RuleLoadFile("CALIB.DAT"); + if (!calib.length()) { + calib = RuleLoadFile("CALIB.DAT"); + } +#endif // USE_RULES if (calib.length()) { // AddLog(LOG_LEVEL_DEBUG, PSTR("ADE: File '%s'"), calib.c_str()); Ade7953SetDefaults(calib.c_str()); } -#endif // USE_RULES } void Ade7953DrvInit(void) { diff --git a/tasmota/tasmota_xnrg_energy/xnrg_23_ade7880.ino b/tasmota/tasmota_xnrg_energy/xnrg_23_ade7880.ino index 37d157d16..a11ab38f0 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_23_ade7880.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_23_ade7880.ino @@ -633,14 +633,20 @@ void Ade7880Defaults(void) { Ade7880.calib_angle[1] = ADE7880_BPHCAL_INIT; Ade7880.calib_angle[2] = ADE7880_CPHCAL_INIT; + String calib = ""; +#ifdef USE_UFILESYS + calib = TfsLoadString("/calib.dat"); +#endif // USE_UFILESYS #ifdef USE_RULES // rule3 on file#calib.dat do {"rms":{"current_a":3166385,"current_b":3125691,"current_c":3131983,"current_s":1756557,"voltage_a":-767262,"voltage_b":-763439,"voltage_c":-749854},"angles":{"angle0":180,"angle1":176,"angle2":176},"powers":{"totactive": {"a":-1345820,"b":-1347328,"c":-1351979}},"freq":0} endon - String calib = RuleLoadFile("CALIB.DAT"); + if (!calib.length()) { + calib = RuleLoadFile("CALIB.DAT"); + } +#endif // USE_RULES if (calib.length()) { // AddLog(LOG_LEVEL_DEBUG, PSTR("A78: File '%s'"), calib.c_str()); Ade7880SetDefaults(calib.c_str()); } -#endif // USE_RULES } void Ade7880DrvInit(void) { From ae1c38aea8a7d33c498fe4fe877e04ab45cad501 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Wed, 4 Jan 2023 15:29:27 +0100 Subject: [PATCH 097/262] Removed SetOption177 debugging (#17500) --- tasmota/tasmota.ino | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/tasmota/tasmota.ino b/tasmota/tasmota.ino index b494ed303..67bf25cd5 100644 --- a/tasmota/tasmota.ino +++ b/tasmota/tasmota.ino @@ -688,18 +688,10 @@ void BacklogLoop(void) { void SleepDelay(uint32_t mseconds) { if (!TasmotaGlobal.backlog_nodelay && mseconds) { uint32_t wait = millis() + mseconds; - - if (Settings->flag6.spare31) { // SetOption177 - (Debug) Disable FUNC_SLEEP_LOOP - while (!TimeReached(wait) && !Serial.available()) { // We need to service serial buffer ASAP as otherwise we get uart buffer overrun - delay(1); - } - } else { - while (!TimeReached(wait) && !Serial.available()) { // We need to service serial buffer ASAP as otherwise we get uart buffer overrun - XdrvXsnsCall(FUNC_SLEEP_LOOP); // Main purpose is reacting ASAP on serial data availability or interrupt handling (ADE7880) - delay(1); - } + while (!TimeReached(wait) && !Serial.available()) { // We need to service serial buffer ASAP as otherwise we get uart buffer overrun + XdrvXsnsCall(FUNC_SLEEP_LOOP); // Main purpose is reacting ASAP on serial data availability or interrupt handling (ADE7880) + delay(1); } - } else { delay(0); } From 7104d10d61a52e2e2f55f90ed4c95a1c556c9ae9 Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Wed, 4 Jan 2023 21:22:07 +0100 Subject: [PATCH 098/262] Berry add spake2+ mods needed for Matter (#17598) --- .../src/embedded/crypto_spake2p_matter.be | 17 +- .../solidified_crypto_spake2p_matter.h | 661 +++++++++--------- 2 files changed, 358 insertions(+), 320 deletions(-) diff --git a/lib/libesp32/berry_tasmota/src/embedded/crypto_spake2p_matter.be b/lib/libesp32/berry_tasmota/src/embedded/crypto_spake2p_matter.be index 4a58aad0d..eb6a9c82e 100644 --- a/lib/libesp32/berry_tasmota/src/embedded/crypto_spake2p_matter.be +++ b/lib/libesp32/berry_tasmota/src/embedded/crypto_spake2p_matter.be @@ -20,6 +20,7 @@ class SPAKE2P_Matter # var TT var Kmain var KcA, KcB, K_shared + var Ke # specific to Matter var cA, cB # Matter values for key generation var A, B, Context @@ -52,6 +53,7 @@ end var ec = crypto.EC_P256() self.x = ec.mod(x) self.pA = ec.muladd(self.w0, self.M, self.x, bytes() #- empty means generator -#) # compute x*P+w0*M + return self.pA end # compute the shared values pB (done by Matter end-device) @@ -63,6 +65,7 @@ end var ec = crypto.EC_P256() self.y = ec.mod(y) self.pB = ec.muladd(self.w0, self.N, self.y, bytes() #- empty means generator -#) # compute y*P+w0*M + return self.pB end # compute Z and V for the Prover (Gateway), receiving pB from the verifier (end-device) @@ -106,7 +109,10 @@ end # Need to know "Context, pA, pB, Z, V, w0" # - def compute_TT_hash() + # Arg: + # matter_specific: if set to `true`, uses only half of the hash as implemented + # in reference code, but not compliant with SPAKE2+ + def compute_TT_hash(matter_specific) class SPAKE_Hasher var hash # var complete # complete value for the bytes -- will be removed in production code @@ -145,13 +151,18 @@ end # self.TT = hasher.complete self.Kmain = hasher.out() + if matter_specific + self.Ke = self.Kmain[16..31] + self.Kmain = self.Kmain[0..15] + end # compute KcA and KcB var kdf = crypto.HKDF_SHA256() var KPV = kdf.derive(self.Kmain, bytes(), bytes().fromstring("ConfirmationKeys"), 64) - self.KcA = KPV[0..31] - self.KcB = KPV[32..63] + self.KcA = matter_specific ? KPV[0..15] : KPV[0..31] + self.KcB = matter_specific ? KPV[16..31] : KPV[32..63] self.K_shared = kdf.derive(self.Kmain, bytes(), bytes().fromstring("SharedKey"), 32) + # if matter_specific self.K_shared = self.K_shared[0..15] end self.cA = crypto.HMAC_SHA256(self.KcA).update(self.pB).out() self.cB = crypto.HMAC_SHA256(self.KcB).update(self.pA).out() diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_crypto_spake2p_matter.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_crypto_spake2p_matter.h index 25cc77c07..993c99b8c 100644 --- a/lib/libesp32/berry_tasmota/src/solidify/solidified_crypto_spake2p_matter.h +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_crypto_spake2p_matter.h @@ -5,54 +5,11 @@ #include "be_constobj.h" /******************************************************************** -** Solidified function: set_context +** Solidified function: compute_pB ********************************************************************/ -be_local_closure(SPAKE2P_Matter_set_context, /* name */ +be_local_closure(SPAKE2P_Matter_compute_pB, /* name */ be_nested_proto( - 5, /* nstack */ - 4, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_nested_str_weak(Context), - /* K1 */ be_nested_str_weak(A), - /* K2 */ be_nested_str_weak(B), - }), - be_str_weak(set_context), - &be_const_str_solidified, - ( &(const binstruction[16]) { /* code */ - 0x4C100000, // 0000 LDNIL R4 - 0x1C100404, // 0001 EQ R4 R2 R4 - 0x78120002, // 0002 JMPF R4 #0006 - 0x60100015, // 0003 GETGBL R4 G21 - 0x7C100000, // 0004 CALL R4 0 - 0x5C080800, // 0005 MOVE R2 R4 - 0x4C100000, // 0006 LDNIL R4 - 0x1C100604, // 0007 EQ R4 R3 R4 - 0x78120002, // 0008 JMPF R4 #000C - 0x60100015, // 0009 GETGBL R4 G21 - 0x7C100000, // 000A CALL R4 0 - 0x5C0C0800, // 000B MOVE R3 R4 - 0x90020001, // 000C SETMBR R0 K0 R1 - 0x90020202, // 000D SETMBR R0 K1 R2 - 0x90020403, // 000E SETMBR R0 K2 R3 - 0x80000000, // 000F RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: compute_ZV_prover -********************************************************************/ -be_local_closure(SPAKE2P_Matter_compute_ZV_prover, /* name */ - be_nested_proto( - 11, /* nstack */ + 10, /* nstack */ 2, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -60,50 +17,44 @@ be_local_closure(SPAKE2P_Matter_compute_ZV_prover, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[13]) { /* constants */ + ( &(const bvalue[ 9]) { /* constants */ /* K0 */ be_nested_str_weak(crypto), - /* K1 */ be_nested_str_weak(EC_P256), - /* K2 */ be_nested_str_weak(pB), - /* K3 */ be_nested_str_weak(neg), - /* K4 */ be_nested_str_weak(w0), - /* K5 */ be_nested_str_weak(muladd), - /* K6 */ be_nested_str_weak(01), - /* K7 */ be_nested_str_weak(N), - /* K8 */ be_nested_str_weak(Z), - /* K9 */ be_nested_str_weak(mul), - /* K10 */ be_nested_str_weak(x), - /* K11 */ be_nested_str_weak(V), - /* K12 */ be_nested_str_weak(w1), + /* K1 */ be_nested_str_weak(random), + /* K2 */ be_nested_str_weak(EC_P256), + /* K3 */ be_nested_str_weak(y), + /* K4 */ be_nested_str_weak(mod), + /* K5 */ be_nested_str_weak(pB), + /* K6 */ be_nested_str_weak(muladd), + /* K7 */ be_nested_str_weak(w0), + /* K8 */ be_nested_str_weak(N), }), - be_str_weak(compute_ZV_prover), + be_str_weak(compute_pB), &be_const_str_solidified, - ( &(const binstruction[26]) { /* code */ + ( &(const binstruction[24]) { /* code */ 0xA40A0000, // 0000 IMPORT R2 K0 - 0x8C0C0501, // 0001 GETMET R3 R2 K1 - 0x7C0C0200, // 0002 CALL R3 1 - 0x90020401, // 0003 SETMBR R0 K2 R1 - 0x8C100703, // 0004 GETMET R4 R3 K3 - 0x88180104, // 0005 GETMBR R6 R0 K4 - 0x7C100400, // 0006 CALL R4 2 - 0x8C140705, // 0007 GETMET R5 R3 K5 - 0x601C0015, // 0008 GETGBL R7 G21 - 0x58200006, // 0009 LDCONST R8 K6 - 0x7C1C0200, // 000A CALL R7 1 - 0x88200102, // 000B GETMBR R8 R0 K2 - 0x5C240800, // 000C MOVE R9 R4 - 0x88280107, // 000D GETMBR R10 R0 K7 - 0x7C140A00, // 000E CALL R5 5 - 0x8C180709, // 000F GETMET R6 R3 K9 - 0x8820010A, // 0010 GETMBR R8 R0 K10 - 0x5C240A00, // 0011 MOVE R9 R5 - 0x7C180600, // 0012 CALL R6 3 - 0x90021006, // 0013 SETMBR R0 K8 R6 - 0x8C180709, // 0014 GETMET R6 R3 K9 - 0x8820010C, // 0015 GETMBR R8 R0 K12 - 0x5C240A00, // 0016 MOVE R9 R5 - 0x7C180600, // 0017 CALL R6 3 - 0x90021606, // 0018 SETMBR R0 K11 R6 - 0x80000000, // 0019 RET 0 + 0x4C0C0000, // 0001 LDNIL R3 + 0x1C0C0203, // 0002 EQ R3 R1 R3 + 0x780E0003, // 0003 JMPF R3 #0008 + 0x8C0C0501, // 0004 GETMET R3 R2 K1 + 0x5416001F, // 0005 LDINT R5 32 + 0x7C0C0400, // 0006 CALL R3 2 + 0x5C040600, // 0007 MOVE R1 R3 + 0x8C0C0502, // 0008 GETMET R3 R2 K2 + 0x7C0C0200, // 0009 CALL R3 1 + 0x8C100704, // 000A GETMET R4 R3 K4 + 0x5C180200, // 000B MOVE R6 R1 + 0x7C100400, // 000C CALL R4 2 + 0x90020604, // 000D SETMBR R0 K3 R4 + 0x8C100706, // 000E GETMET R4 R3 K6 + 0x88180107, // 000F GETMBR R6 R0 K7 + 0x881C0108, // 0010 GETMBR R7 R0 K8 + 0x88200103, // 0011 GETMBR R8 R0 K3 + 0x60240015, // 0012 GETGBL R9 G21 + 0x7C240000, // 0013 CALL R9 0 + 0x7C100A00, // 0014 CALL R4 5 + 0x90020A04, // 0015 SETMBR R0 K5 R4 + 0x88100105, // 0016 GETMBR R4 R0 K5 + 0x80040800, // 0017 RET 1 R4 }) ) ); @@ -243,15 +194,15 @@ be_local_class(SPAKE_Hasher, ********************************************************************/ be_local_closure(SPAKE2P_Matter_compute_TT_hash, /* name */ be_nested_proto( - 13, /* nstack */ - 1, /* argc */ + 14, /* nstack */ + 2, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[28]) { /* constants */ + ( &(const bvalue[29]) { /* constants */ /* K0 */ be_const_class(be_class_SPAKE_Hasher), /* K1 */ be_nested_str_weak(crypto), /* K2 */ be_nested_str_weak(add_item), @@ -267,170 +218,138 @@ be_local_closure(SPAKE2P_Matter_compute_TT_hash, /* name */ /* K12 */ be_nested_str_weak(w0), /* K13 */ be_nested_str_weak(Kmain), /* K14 */ be_nested_str_weak(out), - /* K15 */ be_nested_str_weak(HKDF_SHA256), - /* K16 */ be_nested_str_weak(derive), - /* K17 */ be_nested_str_weak(fromstring), - /* K18 */ be_nested_str_weak(ConfirmationKeys), - /* K19 */ be_nested_str_weak(KcA), - /* K20 */ be_const_int(0), - /* K21 */ be_nested_str_weak(KcB), - /* K22 */ be_nested_str_weak(K_shared), - /* K23 */ be_nested_str_weak(SharedKey), - /* K24 */ be_nested_str_weak(cA), - /* K25 */ be_nested_str_weak(HMAC_SHA256), - /* K26 */ be_nested_str_weak(update), - /* K27 */ be_nested_str_weak(cB), + /* K15 */ be_nested_str_weak(Ke), + /* K16 */ be_const_int(0), + /* K17 */ be_nested_str_weak(HKDF_SHA256), + /* K18 */ be_nested_str_weak(derive), + /* K19 */ be_nested_str_weak(fromstring), + /* K20 */ be_nested_str_weak(ConfirmationKeys), + /* K21 */ be_nested_str_weak(KcA), + /* K22 */ be_nested_str_weak(KcB), + /* K23 */ be_nested_str_weak(K_shared), + /* K24 */ be_nested_str_weak(SharedKey), + /* K25 */ be_nested_str_weak(cA), + /* K26 */ be_nested_str_weak(HMAC_SHA256), + /* K27 */ be_nested_str_weak(update), + /* K28 */ be_nested_str_weak(cB), }), be_str_weak(compute_TT_hash), &be_const_str_solidified, - ( &(const binstruction[91]) { /* code */ - 0x58040000, // 0000 LDCONST R1 K0 + ( &(const binstruction[114]) { /* code */ + 0x58080000, // 0000 LDCONST R2 K0 0xB4000000, // 0001 CLASS K0 - 0xA40A0200, // 0002 IMPORT R2 K1 - 0x5C0C0200, // 0003 MOVE R3 R1 - 0x7C0C0000, // 0004 CALL R3 0 - 0x8C100702, // 0005 GETMET R4 R3 K2 - 0x88180103, // 0006 GETMBR R6 R0 K3 - 0x7C100400, // 0007 CALL R4 2 - 0x8C100702, // 0008 GETMET R4 R3 K2 - 0x88180104, // 0009 GETMBR R6 R0 K4 - 0x7C100400, // 000A CALL R4 2 - 0x8C100702, // 000B GETMET R4 R3 K2 - 0x88180105, // 000C GETMBR R6 R0 K5 - 0x7C100400, // 000D CALL R4 2 - 0x8C100702, // 000E GETMET R4 R3 K2 - 0x88180106, // 000F GETMBR R6 R0 K6 - 0x7C100400, // 0010 CALL R4 2 - 0x8C100702, // 0011 GETMET R4 R3 K2 - 0x88180107, // 0012 GETMBR R6 R0 K7 - 0x7C100400, // 0013 CALL R4 2 - 0x8C100702, // 0014 GETMET R4 R3 K2 - 0x88180108, // 0015 GETMBR R6 R0 K8 - 0x7C100400, // 0016 CALL R4 2 - 0x8C100702, // 0017 GETMET R4 R3 K2 - 0x88180109, // 0018 GETMBR R6 R0 K9 - 0x7C100400, // 0019 CALL R4 2 - 0x8C100702, // 001A GETMET R4 R3 K2 - 0x8818010A, // 001B GETMBR R6 R0 K10 - 0x7C100400, // 001C CALL R4 2 - 0x8C100702, // 001D GETMET R4 R3 K2 - 0x8818010B, // 001E GETMBR R6 R0 K11 - 0x7C100400, // 001F CALL R4 2 - 0x8C100702, // 0020 GETMET R4 R3 K2 - 0x8818010C, // 0021 GETMBR R6 R0 K12 - 0x7C100400, // 0022 CALL R4 2 - 0x8C10070E, // 0023 GETMET R4 R3 K14 - 0x7C100200, // 0024 CALL R4 1 - 0x90021A04, // 0025 SETMBR R0 K13 R4 - 0x8C10050F, // 0026 GETMET R4 R2 K15 - 0x7C100200, // 0027 CALL R4 1 - 0x8C140910, // 0028 GETMET R5 R4 K16 - 0x881C010D, // 0029 GETMBR R7 R0 K13 - 0x60200015, // 002A GETGBL R8 G21 - 0x7C200000, // 002B CALL R8 0 - 0x60240015, // 002C GETGBL R9 G21 - 0x7C240000, // 002D CALL R9 0 - 0x8C241311, // 002E GETMET R9 R9 K17 - 0x582C0012, // 002F LDCONST R11 K18 - 0x7C240400, // 0030 CALL R9 2 - 0x542A003F, // 0031 LDINT R10 64 - 0x7C140A00, // 0032 CALL R5 5 - 0x541A001E, // 0033 LDINT R6 31 - 0x401A2806, // 0034 CONNECT R6 K20 R6 - 0x94180A06, // 0035 GETIDX R6 R5 R6 - 0x90022606, // 0036 SETMBR R0 K19 R6 - 0x541A001F, // 0037 LDINT R6 32 - 0x541E003E, // 0038 LDINT R7 63 - 0x40180C07, // 0039 CONNECT R6 R6 R7 - 0x94180A06, // 003A GETIDX R6 R5 R6 - 0x90022A06, // 003B SETMBR R0 K21 R6 - 0x8C180910, // 003C GETMET R6 R4 K16 - 0x8820010D, // 003D GETMBR R8 R0 K13 - 0x60240015, // 003E GETGBL R9 G21 - 0x7C240000, // 003F CALL R9 0 - 0x60280015, // 0040 GETGBL R10 G21 - 0x7C280000, // 0041 CALL R10 0 - 0x8C281511, // 0042 GETMET R10 R10 K17 - 0x58300017, // 0043 LDCONST R12 K23 - 0x7C280400, // 0044 CALL R10 2 - 0x542E001F, // 0045 LDINT R11 32 - 0x7C180A00, // 0046 CALL R6 5 - 0x90022C06, // 0047 SETMBR R0 K22 R6 - 0x8C180519, // 0048 GETMET R6 R2 K25 - 0x88200113, // 0049 GETMBR R8 R0 K19 - 0x7C180400, // 004A CALL R6 2 - 0x8C180D1A, // 004B GETMET R6 R6 K26 - 0x88200109, // 004C GETMBR R8 R0 K9 - 0x7C180400, // 004D CALL R6 2 - 0x8C180D0E, // 004E GETMET R6 R6 K14 - 0x7C180200, // 004F CALL R6 1 - 0x90023006, // 0050 SETMBR R0 K24 R6 - 0x8C180519, // 0051 GETMET R6 R2 K25 - 0x88200115, // 0052 GETMBR R8 R0 K21 - 0x7C180400, // 0053 CALL R6 2 - 0x8C180D1A, // 0054 GETMET R6 R6 K26 - 0x88200108, // 0055 GETMBR R8 R0 K8 - 0x7C180400, // 0056 CALL R6 2 - 0x8C180D0E, // 0057 GETMET R6 R6 K14 - 0x7C180200, // 0058 CALL R6 1 - 0x90023606, // 0059 SETMBR R0 K27 R6 - 0x80000000, // 005A RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: compute_pA -********************************************************************/ -be_local_closure(SPAKE2P_Matter_compute_pA, /* name */ - be_nested_proto( - 10, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 9]) { /* constants */ - /* K0 */ be_nested_str_weak(crypto), - /* K1 */ be_nested_str_weak(random), - /* K2 */ be_nested_str_weak(EC_P256), - /* K3 */ be_nested_str_weak(x), - /* K4 */ be_nested_str_weak(mod), - /* K5 */ be_nested_str_weak(pA), - /* K6 */ be_nested_str_weak(muladd), - /* K7 */ be_nested_str_weak(w0), - /* K8 */ be_nested_str_weak(M), - }), - be_str_weak(compute_pA), - &be_const_str_solidified, - ( &(const binstruction[23]) { /* code */ - 0xA40A0000, // 0000 IMPORT R2 K0 - 0x4C0C0000, // 0001 LDNIL R3 - 0x1C0C0203, // 0002 EQ R3 R1 R3 - 0x780E0003, // 0003 JMPF R3 #0008 - 0x8C0C0501, // 0004 GETMET R3 R2 K1 - 0x5416001F, // 0005 LDINT R5 32 - 0x7C0C0400, // 0006 CALL R3 2 - 0x5C040600, // 0007 MOVE R1 R3 - 0x8C0C0502, // 0008 GETMET R3 R2 K2 - 0x7C0C0200, // 0009 CALL R3 1 - 0x8C100704, // 000A GETMET R4 R3 K4 - 0x5C180200, // 000B MOVE R6 R1 - 0x7C100400, // 000C CALL R4 2 - 0x90020604, // 000D SETMBR R0 K3 R4 - 0x8C100706, // 000E GETMET R4 R3 K6 - 0x88180107, // 000F GETMBR R6 R0 K7 - 0x881C0108, // 0010 GETMBR R7 R0 K8 - 0x88200103, // 0011 GETMBR R8 R0 K3 - 0x60240015, // 0012 GETGBL R9 G21 - 0x7C240000, // 0013 CALL R9 0 - 0x7C100A00, // 0014 CALL R4 5 - 0x90020A04, // 0015 SETMBR R0 K5 R4 - 0x80000000, // 0016 RET 0 + 0xA40E0200, // 0002 IMPORT R3 K1 + 0x5C100400, // 0003 MOVE R4 R2 + 0x7C100000, // 0004 CALL R4 0 + 0x8C140902, // 0005 GETMET R5 R4 K2 + 0x881C0103, // 0006 GETMBR R7 R0 K3 + 0x7C140400, // 0007 CALL R5 2 + 0x8C140902, // 0008 GETMET R5 R4 K2 + 0x881C0104, // 0009 GETMBR R7 R0 K4 + 0x7C140400, // 000A CALL R5 2 + 0x8C140902, // 000B GETMET R5 R4 K2 + 0x881C0105, // 000C GETMBR R7 R0 K5 + 0x7C140400, // 000D CALL R5 2 + 0x8C140902, // 000E GETMET R5 R4 K2 + 0x881C0106, // 000F GETMBR R7 R0 K6 + 0x7C140400, // 0010 CALL R5 2 + 0x8C140902, // 0011 GETMET R5 R4 K2 + 0x881C0107, // 0012 GETMBR R7 R0 K7 + 0x7C140400, // 0013 CALL R5 2 + 0x8C140902, // 0014 GETMET R5 R4 K2 + 0x881C0108, // 0015 GETMBR R7 R0 K8 + 0x7C140400, // 0016 CALL R5 2 + 0x8C140902, // 0017 GETMET R5 R4 K2 + 0x881C0109, // 0018 GETMBR R7 R0 K9 + 0x7C140400, // 0019 CALL R5 2 + 0x8C140902, // 001A GETMET R5 R4 K2 + 0x881C010A, // 001B GETMBR R7 R0 K10 + 0x7C140400, // 001C CALL R5 2 + 0x8C140902, // 001D GETMET R5 R4 K2 + 0x881C010B, // 001E GETMBR R7 R0 K11 + 0x7C140400, // 001F CALL R5 2 + 0x8C140902, // 0020 GETMET R5 R4 K2 + 0x881C010C, // 0021 GETMBR R7 R0 K12 + 0x7C140400, // 0022 CALL R5 2 + 0x8C14090E, // 0023 GETMET R5 R4 K14 + 0x7C140200, // 0024 CALL R5 1 + 0x90021A05, // 0025 SETMBR R0 K13 R5 + 0x7806000A, // 0026 JMPF R1 #0032 + 0x5416000F, // 0027 LDINT R5 16 + 0x541A001E, // 0028 LDINT R6 31 + 0x40140A06, // 0029 CONNECT R5 R5 R6 + 0x8818010D, // 002A GETMBR R6 R0 K13 + 0x94140C05, // 002B GETIDX R5 R6 R5 + 0x90021E05, // 002C SETMBR R0 K15 R5 + 0x5416000E, // 002D LDINT R5 15 + 0x40162005, // 002E CONNECT R5 K16 R5 + 0x8818010D, // 002F GETMBR R6 R0 K13 + 0x94140C05, // 0030 GETIDX R5 R6 R5 + 0x90021A05, // 0031 SETMBR R0 K13 R5 + 0x8C140711, // 0032 GETMET R5 R3 K17 + 0x7C140200, // 0033 CALL R5 1 + 0x8C180B12, // 0034 GETMET R6 R5 K18 + 0x8820010D, // 0035 GETMBR R8 R0 K13 + 0x60240015, // 0036 GETGBL R9 G21 + 0x7C240000, // 0037 CALL R9 0 + 0x60280015, // 0038 GETGBL R10 G21 + 0x7C280000, // 0039 CALL R10 0 + 0x8C281513, // 003A GETMET R10 R10 K19 + 0x58300014, // 003B LDCONST R12 K20 + 0x7C280400, // 003C CALL R10 2 + 0x542E003F, // 003D LDINT R11 64 + 0x7C180A00, // 003E CALL R6 5 + 0x78060003, // 003F JMPF R1 #0044 + 0x541E000E, // 0040 LDINT R7 15 + 0x401E2007, // 0041 CONNECT R7 K16 R7 + 0x941C0C07, // 0042 GETIDX R7 R6 R7 + 0x70020002, // 0043 JMP #0047 + 0x541E001E, // 0044 LDINT R7 31 + 0x401E2007, // 0045 CONNECT R7 K16 R7 + 0x941C0C07, // 0046 GETIDX R7 R6 R7 + 0x90022A07, // 0047 SETMBR R0 K21 R7 + 0x78060004, // 0048 JMPF R1 #004E + 0x541E000F, // 0049 LDINT R7 16 + 0x5422001E, // 004A LDINT R8 31 + 0x401C0E08, // 004B CONNECT R7 R7 R8 + 0x941C0C07, // 004C GETIDX R7 R6 R7 + 0x70020003, // 004D JMP #0052 + 0x541E001F, // 004E LDINT R7 32 + 0x5422003E, // 004F LDINT R8 63 + 0x401C0E08, // 0050 CONNECT R7 R7 R8 + 0x941C0C07, // 0051 GETIDX R7 R6 R7 + 0x90022C07, // 0052 SETMBR R0 K22 R7 + 0x8C1C0B12, // 0053 GETMET R7 R5 K18 + 0x8824010D, // 0054 GETMBR R9 R0 K13 + 0x60280015, // 0055 GETGBL R10 G21 + 0x7C280000, // 0056 CALL R10 0 + 0x602C0015, // 0057 GETGBL R11 G21 + 0x7C2C0000, // 0058 CALL R11 0 + 0x8C2C1713, // 0059 GETMET R11 R11 K19 + 0x58340018, // 005A LDCONST R13 K24 + 0x7C2C0400, // 005B CALL R11 2 + 0x5432001F, // 005C LDINT R12 32 + 0x7C1C0A00, // 005D CALL R7 5 + 0x90022E07, // 005E SETMBR R0 K23 R7 + 0x8C1C071A, // 005F GETMET R7 R3 K26 + 0x88240115, // 0060 GETMBR R9 R0 K21 + 0x7C1C0400, // 0061 CALL R7 2 + 0x8C1C0F1B, // 0062 GETMET R7 R7 K27 + 0x88240109, // 0063 GETMBR R9 R0 K9 + 0x7C1C0400, // 0064 CALL R7 2 + 0x8C1C0F0E, // 0065 GETMET R7 R7 K14 + 0x7C1C0200, // 0066 CALL R7 1 + 0x90023207, // 0067 SETMBR R0 K25 R7 + 0x8C1C071A, // 0068 GETMET R7 R3 K26 + 0x88240116, // 0069 GETMBR R9 R0 K22 + 0x7C1C0400, // 006A CALL R7 2 + 0x8C1C0F1B, // 006B GETMET R7 R7 K27 + 0x88240108, // 006C GETMBR R9 R0 K8 + 0x7C1C0400, // 006D CALL R7 2 + 0x8C1C0F0E, // 006E GETMET R7 R7 K14 + 0x7C1C0200, // 006F CALL R7 1 + 0x90023807, // 0070 SETMBR R0 K28 R7 + 0x80000000, // 0071 RET 0 }) ) ); @@ -485,6 +404,106 @@ be_local_closure(SPAKE2P_Matter_init, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: compute_pA +********************************************************************/ +be_local_closure(SPAKE2P_Matter_compute_pA, /* name */ + be_nested_proto( + 10, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 9]) { /* constants */ + /* K0 */ be_nested_str_weak(crypto), + /* K1 */ be_nested_str_weak(random), + /* K2 */ be_nested_str_weak(EC_P256), + /* K3 */ be_nested_str_weak(x), + /* K4 */ be_nested_str_weak(mod), + /* K5 */ be_nested_str_weak(pA), + /* K6 */ be_nested_str_weak(muladd), + /* K7 */ be_nested_str_weak(w0), + /* K8 */ be_nested_str_weak(M), + }), + be_str_weak(compute_pA), + &be_const_str_solidified, + ( &(const binstruction[24]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0x4C0C0000, // 0001 LDNIL R3 + 0x1C0C0203, // 0002 EQ R3 R1 R3 + 0x780E0003, // 0003 JMPF R3 #0008 + 0x8C0C0501, // 0004 GETMET R3 R2 K1 + 0x5416001F, // 0005 LDINT R5 32 + 0x7C0C0400, // 0006 CALL R3 2 + 0x5C040600, // 0007 MOVE R1 R3 + 0x8C0C0502, // 0008 GETMET R3 R2 K2 + 0x7C0C0200, // 0009 CALL R3 1 + 0x8C100704, // 000A GETMET R4 R3 K4 + 0x5C180200, // 000B MOVE R6 R1 + 0x7C100400, // 000C CALL R4 2 + 0x90020604, // 000D SETMBR R0 K3 R4 + 0x8C100706, // 000E GETMET R4 R3 K6 + 0x88180107, // 000F GETMBR R6 R0 K7 + 0x881C0108, // 0010 GETMBR R7 R0 K8 + 0x88200103, // 0011 GETMBR R8 R0 K3 + 0x60240015, // 0012 GETGBL R9 G21 + 0x7C240000, // 0013 CALL R9 0 + 0x7C100A00, // 0014 CALL R4 5 + 0x90020A04, // 0015 SETMBR R0 K5 R4 + 0x88100105, // 0016 GETMBR R4 R0 K5 + 0x80040800, // 0017 RET 1 R4 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_context +********************************************************************/ +be_local_closure(SPAKE2P_Matter_set_context, /* name */ + be_nested_proto( + 5, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(Context), + /* K1 */ be_nested_str_weak(A), + /* K2 */ be_nested_str_weak(B), + }), + be_str_weak(set_context), + &be_const_str_solidified, + ( &(const binstruction[16]) { /* code */ + 0x4C100000, // 0000 LDNIL R4 + 0x1C100404, // 0001 EQ R4 R2 R4 + 0x78120002, // 0002 JMPF R4 #0006 + 0x60100015, // 0003 GETGBL R4 G21 + 0x7C100000, // 0004 CALL R4 0 + 0x5C080800, // 0005 MOVE R2 R4 + 0x4C100000, // 0006 LDNIL R4 + 0x1C100604, // 0007 EQ R4 R3 R4 + 0x78120002, // 0008 JMPF R4 #000C + 0x60100015, // 0009 GETGBL R4 G21 + 0x7C100000, // 000A CALL R4 0 + 0x5C0C0800, // 000B MOVE R3 R4 + 0x90020001, // 000C SETMBR R0 K0 R1 + 0x90020202, // 000D SETMBR R0 K1 R2 + 0x90020403, // 000E SETMBR R0 K2 R3 + 0x80000000, // 000F RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: compute_ZV_verifier ********************************************************************/ @@ -549,11 +568,11 @@ be_local_closure(SPAKE2P_Matter_compute_ZV_verifier, /* name */ /******************************************************************** -** Solidified function: compute_pB +** Solidified function: compute_ZV_prover ********************************************************************/ -be_local_closure(SPAKE2P_Matter_compute_pB, /* name */ +be_local_closure(SPAKE2P_Matter_compute_ZV_prover, /* name */ be_nested_proto( - 10, /* nstack */ + 11, /* nstack */ 2, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -561,43 +580,50 @@ be_local_closure(SPAKE2P_Matter_compute_pB, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 9]) { /* constants */ + ( &(const bvalue[13]) { /* constants */ /* K0 */ be_nested_str_weak(crypto), - /* K1 */ be_nested_str_weak(random), - /* K2 */ be_nested_str_weak(EC_P256), - /* K3 */ be_nested_str_weak(y), - /* K4 */ be_nested_str_weak(mod), - /* K5 */ be_nested_str_weak(pB), - /* K6 */ be_nested_str_weak(muladd), - /* K7 */ be_nested_str_weak(w0), - /* K8 */ be_nested_str_weak(N), + /* K1 */ be_nested_str_weak(EC_P256), + /* K2 */ be_nested_str_weak(pB), + /* K3 */ be_nested_str_weak(neg), + /* K4 */ be_nested_str_weak(w0), + /* K5 */ be_nested_str_weak(muladd), + /* K6 */ be_nested_str_weak(01), + /* K7 */ be_nested_str_weak(N), + /* K8 */ be_nested_str_weak(Z), + /* K9 */ be_nested_str_weak(mul), + /* K10 */ be_nested_str_weak(x), + /* K11 */ be_nested_str_weak(V), + /* K12 */ be_nested_str_weak(w1), }), - be_str_weak(compute_pB), + be_str_weak(compute_ZV_prover), &be_const_str_solidified, - ( &(const binstruction[23]) { /* code */ + ( &(const binstruction[26]) { /* code */ 0xA40A0000, // 0000 IMPORT R2 K0 - 0x4C0C0000, // 0001 LDNIL R3 - 0x1C0C0203, // 0002 EQ R3 R1 R3 - 0x780E0003, // 0003 JMPF R3 #0008 - 0x8C0C0501, // 0004 GETMET R3 R2 K1 - 0x5416001F, // 0005 LDINT R5 32 - 0x7C0C0400, // 0006 CALL R3 2 - 0x5C040600, // 0007 MOVE R1 R3 - 0x8C0C0502, // 0008 GETMET R3 R2 K2 - 0x7C0C0200, // 0009 CALL R3 1 - 0x8C100704, // 000A GETMET R4 R3 K4 - 0x5C180200, // 000B MOVE R6 R1 - 0x7C100400, // 000C CALL R4 2 - 0x90020604, // 000D SETMBR R0 K3 R4 - 0x8C100706, // 000E GETMET R4 R3 K6 - 0x88180107, // 000F GETMBR R6 R0 K7 - 0x881C0108, // 0010 GETMBR R7 R0 K8 - 0x88200103, // 0011 GETMBR R8 R0 K3 - 0x60240015, // 0012 GETGBL R9 G21 - 0x7C240000, // 0013 CALL R9 0 - 0x7C100A00, // 0014 CALL R4 5 - 0x90020A04, // 0015 SETMBR R0 K5 R4 - 0x80000000, // 0016 RET 0 + 0x8C0C0501, // 0001 GETMET R3 R2 K1 + 0x7C0C0200, // 0002 CALL R3 1 + 0x90020401, // 0003 SETMBR R0 K2 R1 + 0x8C100703, // 0004 GETMET R4 R3 K3 + 0x88180104, // 0005 GETMBR R6 R0 K4 + 0x7C100400, // 0006 CALL R4 2 + 0x8C140705, // 0007 GETMET R5 R3 K5 + 0x601C0015, // 0008 GETGBL R7 G21 + 0x58200006, // 0009 LDCONST R8 K6 + 0x7C1C0200, // 000A CALL R7 1 + 0x88200102, // 000B GETMBR R8 R0 K2 + 0x5C240800, // 000C MOVE R9 R4 + 0x88280107, // 000D GETMBR R10 R0 K7 + 0x7C140A00, // 000E CALL R5 5 + 0x8C180709, // 000F GETMET R6 R3 K9 + 0x8820010A, // 0010 GETMBR R8 R0 K10 + 0x5C240A00, // 0011 MOVE R9 R5 + 0x7C180600, // 0012 CALL R6 3 + 0x90021006, // 0013 SETMBR R0 K8 R6 + 0x8C180709, // 0014 GETMET R6 R3 K9 + 0x8820010C, // 0015 GETMBR R8 R0 K12 + 0x5C240A00, // 0016 MOVE R9 R5 + 0x7C180600, // 0017 CALL R6 3 + 0x90021606, // 0018 SETMBR R0 K11 R6 + 0x80000000, // 0019 RET 0 }) ) ); @@ -608,41 +634,42 @@ be_local_closure(SPAKE2P_Matter_compute_pB, /* name */ ** Solidified class: SPAKE2P_Matter ********************************************************************/ be_local_class(SPAKE2P_Matter, - 20, + 21, NULL, - be_nested_map(31, + be_nested_map(32, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(pA, 23), be_const_var(3) }, - { be_const_key_weak(set_context, 28), be_const_closure(SPAKE2P_Matter_set_context_closure) }, - { be_const_key_weak(KcA, -1), be_const_var(10) }, - { be_const_key_weak(cA, -1), be_const_var(13) }, - { be_const_key_weak(K_shared, -1), be_const_var(12) }, - { be_const_key_weak(A, 9), be_const_var(15) }, - { be_const_key_weak(V, -1), be_const_var(6) }, - { be_const_key_weak(compute_TT_hash, -1), be_const_closure(SPAKE2P_Matter_compute_TT_hash_closure) }, - { be_const_key_weak(Kmain, -1), be_const_var(9) }, - { be_const_key_weak(w0, -1), be_const_var(0) }, - { be_const_key_weak(N, -1), be_const_var(19) }, - { be_const_key_weak(x, -1), be_const_var(7) }, - { be_const_key_weak(Context, 20), be_const_var(17) }, - { be_const_key_weak(compute_pA, -1), be_const_closure(SPAKE2P_Matter_compute_pA_closure) }, - { be_const_key_weak(w1, -1), be_const_var(1) }, - { be_const_key_weak(B, 22), be_const_var(16) }, - { be_const_key_weak(L, 25), be_const_var(2) }, - { be_const_key_weak(cB, 10), be_const_var(14) }, - { be_const_key_weak(spake_M_hex, -1), be_nested_str_weak(04886e2f97ace46e55ba9dd7242579f2993b64e16ef3dcab95afd497333d8fa12f5ff355163e43ce224e0b0e65ff02ac8e5c7be09419c785e0ca547d55a12e2d20) }, - { be_const_key_weak(spake_N_hex, -1), be_nested_str_weak(04d8bbd6c639c62937b04d997f38c3770719c629d7014d49a24b4f98baa1292b4907d60aa6bfade45008a636337f5168c64d9bd36034808cd564490b1e656edbe7) }, - { be_const_key_weak(CRYPTO_GROUP_SIZE_BYTES, 7), be_const_int(32) }, - { be_const_key_weak(CRYPTO_W_SIZE_BYTES, 6), be_const_int(40) }, - { be_const_key_weak(pB, 8), be_const_var(4) }, - { be_const_key_weak(M, -1), be_const_var(18) }, - { be_const_key_weak(compute_ZV_verifier, -1), be_const_closure(SPAKE2P_Matter_compute_ZV_verifier_closure) }, - { be_const_key_weak(KcB, 19), be_const_var(11) }, - { be_const_key_weak(y, -1), be_const_var(8) }, - { be_const_key_weak(Z, -1), be_const_var(5) }, - { be_const_key_weak(compute_ZV_prover, 2), be_const_closure(SPAKE2P_Matter_compute_ZV_prover_closure) }, - { be_const_key_weak(init, 5), be_const_closure(SPAKE2P_Matter_init_closure) }, + { be_const_key_weak(compute_ZV_prover, 21), be_const_closure(SPAKE2P_Matter_compute_ZV_prover_closure) }, + { be_const_key_weak(cA, -1), be_const_var(14) }, + { be_const_key_weak(CRYPTO_W_SIZE_BYTES, -1), be_const_int(40) }, + { be_const_key_weak(Kmain, 14), be_const_var(9) }, { be_const_key_weak(compute_pB, -1), be_const_closure(SPAKE2P_Matter_compute_pB_closure) }, + { be_const_key_weak(B, 31), be_const_var(17) }, + { be_const_key_weak(K_shared, -1), be_const_var(12) }, + { be_const_key_weak(x, -1), be_const_var(7) }, + { be_const_key_weak(CRYPTO_GROUP_SIZE_BYTES, -1), be_const_int(32) }, + { be_const_key_weak(V, 1), be_const_var(6) }, + { be_const_key_weak(pA, -1), be_const_var(3) }, + { be_const_key_weak(KcB, 27), be_const_var(11) }, + { be_const_key_weak(A, -1), be_const_var(16) }, + { be_const_key_weak(Z, 4), be_const_var(5) }, + { be_const_key_weak(spake_M_hex, -1), be_nested_str_weak(04886e2f97ace46e55ba9dd7242579f2993b64e16ef3dcab95afd497333d8fa12f5ff355163e43ce224e0b0e65ff02ac8e5c7be09419c785e0ca547d55a12e2d20) }, + { be_const_key_weak(compute_ZV_verifier, -1), be_const_closure(SPAKE2P_Matter_compute_ZV_verifier_closure) }, + { be_const_key_weak(compute_TT_hash, 0), be_const_closure(SPAKE2P_Matter_compute_TT_hash_closure) }, + { be_const_key_weak(N, -1), be_const_var(20) }, + { be_const_key_weak(w0, -1), be_const_var(0) }, + { be_const_key_weak(init, -1), be_const_closure(SPAKE2P_Matter_init_closure) }, + { be_const_key_weak(compute_pA, 25), be_const_closure(SPAKE2P_Matter_compute_pA_closure) }, + { be_const_key_weak(cB, -1), be_const_var(15) }, + { be_const_key_weak(set_context, -1), be_const_closure(SPAKE2P_Matter_set_context_closure) }, + { be_const_key_weak(pB, 22), be_const_var(4) }, + { be_const_key_weak(M, -1), be_const_var(19) }, + { be_const_key_weak(y, -1), be_const_var(8) }, + { be_const_key_weak(spake_N_hex, 15), be_nested_str_weak(04d8bbd6c639c62937b04d997f38c3770719c629d7014d49a24b4f98baa1292b4907d60aa6bfade45008a636337f5168c64d9bd36034808cd564490b1e656edbe7) }, + { be_const_key_weak(L, -1), be_const_var(2) }, + { be_const_key_weak(Context, 8), be_const_var(18) }, + { be_const_key_weak(Ke, -1), be_const_var(13) }, + { be_const_key_weak(KcA, -1), be_const_var(10) }, + { be_const_key_weak(w1, -1), be_const_var(1) }, })), be_str_weak(SPAKE2P_Matter) ); From 6b5f0e4e7c9bd8d3b989bcc76f7cbea9277dd7c6 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Thu, 5 Jan 2023 13:04:06 +0100 Subject: [PATCH 099/262] Prepare support for JL1101 PHY (#17607) --- tasmota/tasmota_xdrv_driver/xdrv_82_esp32_ethernet.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_82_esp32_ethernet.ino b/tasmota/tasmota_xdrv_driver/xdrv_82_esp32_ethernet.ino index b9d795759..ddb1a0e5c 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_82_esp32_ethernet.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_82_esp32_ethernet.ino @@ -319,7 +319,7 @@ void CmndEthAddress(void) { } void CmndEthType(void) { - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 2)) { + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 8)) { Settings->eth_type = XdrvMailbox.payload; TasmotaGlobal.restart_flag = 2; } From 8275cb776e4f7f7731d5f9058ba85b6b01256101 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Thu, 5 Jan 2023 15:02:55 +0100 Subject: [PATCH 100/262] Fix rule mqtt subscribe payload size Increase rule event buffer from 100 to 256 characters (#16943) --- CHANGELOG.md | 1 + RELEASENOTES.md | 1 + tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino | 4 ++-- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e013ce67..0cbc31475 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ All notable changes to this project will be documented in this file. ### Changed - Energy totals max supported value from +/-21474.83647 to +/-2147483.647 kWh - Removed delays in TasmotaSerial and TasmotaModbus Tx enable switching +- Increase rule event buffer from 100 to 256 characters (#16943) ### Fixed - Energy dummy switched voltage and power regression from v12.2.0.2 diff --git a/RELEASENOTES.md b/RELEASENOTES.md index d1ad2cc54..5a621fc88 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -126,6 +126,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm - ESP32 Framework (Core) from v2.0.5.3 to v2.0.6 (IPv6 support) - Energy totals max supported value from +/-21474.83647 to +/-2147483.647 kWh - Removed delays in TasmotaSerial and TasmotaModbus Tx enable switching +- Increase rule event buffer from 100 to 256 characters [#16943](https://github.com/arendst/Tasmota/issues/16943) - TuyaMcu rewrite by btsimonh [#17051](https://github.com/arendst/Tasmota/issues/17051) - Tasmota OTA scripts now support both unzipped and gzipped file uploads [#17378](https://github.com/arendst/Tasmota/issues/17378) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino b/tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino index 4b3848e50..f99856144 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino @@ -186,7 +186,7 @@ struct RULES { bool busy = false; bool no_execute = false; // Don't actually execute rule commands - char event_data[100]; + char event_data[256]; } Rules; char rules_vars[MAX_RULE_VARS][33] = {{ 0 }}; @@ -936,7 +936,7 @@ void RulesInit(void) void RulesEvery50ms(void) { if ((Settings->rule_enabled || BERRY_RULES) && !Rules.busy) { // Any rule enabled - char json_event[120]; + char json_event[300]; if (-1 == Rules.new_power) { Rules.new_power = TasmotaGlobal.power; } if (Rules.new_power != Rules.old_power) { From 7d94a2c89eea0d0a93bdebd9df406a92841f00a5 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 6 Jan 2023 10:15:12 +0100 Subject: [PATCH 101/262] Fix Slovak language Id --- tasmota/language/sk_SK.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasmota/language/sk_SK.h b/tasmota/language/sk_SK.h index 01859df42..697020c42 100644 --- a/tasmota/language/sk_SK.h +++ b/tasmota/language/sk_SK.h @@ -33,7 +33,7 @@ //#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) -#define LANGUAGE_LCID 1029 +#define LANGUAGE_LCID 1051 // HTML (ISO 639-1) Language Code #define D_HTML_LANGUAGE "sk" From 33d6dbed3dccaf729a8587c7d3b959962de4c461 Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Fri, 6 Jan 2023 14:03:16 +0100 Subject: [PATCH 102/262] No IP address shown when in AP moode (#17599) (#17619) --- CHANGELOG.md | 1 + tasmota/tasmota_support/support_wifi.ino | 4 ++++ tasmota/tasmota_xdrv_driver/xdrv_01_9_webserver.ino | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0cbc31475..d50926f05 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ All notable changes to this project will be documented in this file. ### Fixed - Energy dummy switched voltage and power regression from v12.2.0.2 - Orno WE517 modbus serial config 8E1 setting (#17545) +- No IP address shown when in AP moode (#17599) ### Removed diff --git a/tasmota/tasmota_support/support_wifi.ino b/tasmota/tasmota_support/support_wifi.ino index 6d946e3cd..fe2b63cf2 100644 --- a/tasmota/tasmota_support/support_wifi.ino +++ b/tasmota/tasmota_support/support_wifi.ino @@ -761,6 +761,10 @@ bool WifiGetIP(IPAddress *ip) { if (ip != nullptr) { *ip = WiFi.localIP(); } return true; } + if ((uint32_t)WiFi.softAPIP() != 0) { + if (ip != nullptr) { *ip = WiFi.softAPIP(); } + return true; + } IPAddress lip; if (WifiGetIPv6(&lip)) { if (ip != nullptr) { *ip = lip; } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_01_9_webserver.ino b/tasmota/tasmota_xdrv_driver/xdrv_01_9_webserver.ino index de4a3a498..f1a85b69b 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_01_9_webserver.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_01_9_webserver.ino @@ -3209,7 +3209,7 @@ bool CaptivePortal(void) if ((WifiIsInManagerMode()) && !ValidIpAddress(Webserver->hostHeader().c_str())) { AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_REDIRECTED)); - Webserver->sendHeader(F("Location"), String(F("http://")) + Webserver->client().localIP().toString(), true); + Webserver->sendHeader(F("Location"), String(F("http://")) + IPGetListeningAddressStr(), true); WSSend(302, CT_PLAIN, ""); // Empty content inhibits Content-length header so we have to close the socket ourselves. Webserver->client().stop(); // Stop is needed because we sent no content length return true; From af733afbe5ea3a5e6af2915b7d26fbe841e8ce3b Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 6 Jan 2023 14:58:19 +0100 Subject: [PATCH 103/262] Fix PID-Control parameter destruction Fix PID-Control parameter destruction and replace all atof() by CharToFloat() saving 8k code size (#17618) --- .../tasmota_xdrv_driver/xdrv_48_timeprop.ino | 2 +- tasmota/tasmota_xdrv_driver/xdrv_49_pid.ino | 69 ++++++++++++------- .../tasmota_xdsp_display/xdsp_11_sevenseg.ino | 4 +- .../tasmota_xdsp_display/xdsp_15_tm1637.ino | 4 +- .../tasmota_xsns_sensor/xsns_69_opentherm.ino | 4 +- 5 files changed, 53 insertions(+), 30 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_48_timeprop.ino b/tasmota/tasmota_xdrv_driver/xdrv_48_timeprop.ino index ab11f6c52..22f25623f 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_48_timeprop.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_48_timeprop.ino @@ -205,7 +205,7 @@ bool TimepropCommand() (XdrvMailbox.data_len >= 0 ? XdrvMailbox.data : "")); */ if (XdrvMailbox.index >=0 && XdrvMailbox.index < TIMEPROP_NUM_OUTPUTS) { - timeprops[XdrvMailbox.index].setPower( atof(XdrvMailbox.data), Tprop.current_time_secs ); + timeprops[XdrvMailbox.index].setPower( CharToFloat(XdrvMailbox.data), Tprop.current_time_secs ); } Response_P(PSTR("{\"" D_CMND_TIMEPROP D_CMND_TIMEPROP_SETPOWER "%d\":\"%s\"}"), XdrvMailbox.index, XdrvMailbox.data); } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_49_pid.ino b/tasmota/tasmota_xdrv_driver/xdrv_49_pid.ino index dcc226cd2..b2d48a2cd 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_49_pid.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_49_pid.ino @@ -105,7 +105,7 @@ // with just one relay then this will be 1. // USE_TIMEPROP will be automativally included. You must set the output as // explained in xdrv_48_timeprop.ino - // To disable, override to false in user_config_override.h. If USE_TIMEPROP is + // To disable, override to false in user_config_override.h. If USE_TIMEPROP is // not explicitly defined, then it will not be added by default. #define PID_USE_LOCAL_SENSOR // If defined then the local sensor will be used for pv. Leave undefined if @@ -266,58 +266,78 @@ void PIDShowSensor() { void CmndSetPv(void) { Pid.last_pv_update_secs = Pid.current_time_secs; - Pid.pid.setPv(atof(XdrvMailbox.data), Pid.last_pv_update_secs); + if (XdrvMailbox.data_len > 0) { + Pid.pid.setPv(CharToFloat(XdrvMailbox.data), Pid.last_pv_update_secs); + } // also trigger running the pid algorithm if we have been told to run it each pv sample if (Pid.update_secs == 0) { // this runs it at the next second Pid.run_pid_now = true; } - ResponseCmndFloat(atof(XdrvMailbox.data), 1); + ResponseCmndFloat(Pid.pid.getPv(), 1); } void CmndSetSp(void) { - Pid.pid.setSp(atof(XdrvMailbox.data)); - ResponseCmndFloat(atof(XdrvMailbox.data), 1); + if (XdrvMailbox.data_len > 0) { + Pid.pid.setSp(CharToFloat(XdrvMailbox.data)); + } + ResponseCmndFloat(Pid.pid.getSp(), 1); } void CmndSetPb(void) { - Pid.pid.setPb(atof(XdrvMailbox.data)); - ResponseCmndFloat(atof(XdrvMailbox.data), 1); + if (XdrvMailbox.data_len > 0) { + Pid.pid.setPb(CharToFloat(XdrvMailbox.data)); + } + ResponseCmndFloat(Pid.pid.getPb(), 1); } void CmndSetTi(void) { - Pid.pid.setTi(atof(XdrvMailbox.data)); - ResponseCmndFloat(atof(XdrvMailbox.data), 1); + if (XdrvMailbox.data_len > 0) { + Pid.pid.setTi(CharToFloat(XdrvMailbox.data)); + } + ResponseCmndFloat(Pid.pid.getTi(), 1); } void CmndSetTd(void) { - Pid.pid.setTd(atof(XdrvMailbox.data)); - ResponseCmndFloat(atof(XdrvMailbox.data), 1); + if (XdrvMailbox.data_len > 0) { + Pid.pid.setTd(CharToFloat(XdrvMailbox.data)); + } + ResponseCmndFloat(Pid.pid.getTd(), 1); } void CmndSetInitialInt(void) { - Pid.pid.setInitialInt(atof(XdrvMailbox.data)); - ResponseCmndNumber(atof(XdrvMailbox.data)); + if (XdrvMailbox.data_len > 0) { + Pid.pid.setInitialInt(CharToFloat(XdrvMailbox.data)); + } + ResponseCmndNumber(Pid.pid.getInitialInt()); } void CmndSetDSmooth(void) { - Pid.pid.setDSmooth(atof(XdrvMailbox.data)); - ResponseCmndFloat(atof(XdrvMailbox.data), 1); + if (XdrvMailbox.data_len > 0) { + Pid.pid.setDSmooth(CharToFloat(XdrvMailbox.data)); + } + ResponseCmndFloat(Pid.pid.getDSmooth(), 1); } void CmndSetAuto(void) { - Pid.pid.setAuto(atoi(XdrvMailbox.data)); - ResponseCmndNumber(atoi(XdrvMailbox.data)); + if (XdrvMailbox.payload >= 0) { + Pid.pid.setAuto(XdrvMailbox.payload); + } + ResponseCmndNumber(Pid.pid.getAuto()); } void CmndSetManualPower(void) { - Pid.pid.setManualPower(atof(XdrvMailbox.data)); - ResponseCmndFloat(atof(XdrvMailbox.data), 1); + if (XdrvMailbox.data_len > 0) { + Pid.pid.setManualPower(CharToFloat(XdrvMailbox.data)); + } + ResponseCmndFloat(Pid.pid.getManualPower(), 1); } void CmndSetMaxInterval(void) { - Pid.pid.setMaxInterval(atoi(XdrvMailbox.data)); - ResponseCmndNumber(atoi(XdrvMailbox.data)); + if (XdrvMailbox.payload >= 0) { + Pid.pid.setMaxInterval(XdrvMailbox.payload); + } + ResponseCmndNumber(Pid.pid.getMaxInterval()); } // case CMND_PID_SETUPDATE_SECS: @@ -325,9 +345,12 @@ void CmndSetMaxInterval(void) { // if (Pid.update_secs < 0) // Pid.update_secs = 0; void CmndSetUpdateSecs(void) { - Pid.update_secs = (atoi(XdrvMailbox.data)); - if (Pid.update_secs < 0) + if (XdrvMailbox.payload >= 0) { + Pid.update_secs = (XdrvMailbox.payload); + } + if (Pid.update_secs < 0) { Pid.update_secs = 0; + } ResponseCmndNumber(Pid.update_secs); } diff --git a/tasmota/tasmota_xdsp_display/xdsp_11_sevenseg.ino b/tasmota/tasmota_xdsp_display/xdsp_11_sevenseg.ino index bb8792259..faeb738d0 100644 --- a/tasmota/tasmota_xdsp_display/xdsp_11_sevenseg.ino +++ b/tasmota/tasmota_xdsp_display/xdsp_11_sevenseg.ino @@ -91,7 +91,7 @@ void SevensegLog(void) if (strchr( value_level2, '.') == NULL) { sevenseg[unit]->print(atoi(value_level2), DEC); } else { - sevenseg[unit]->printFloat(atof(value_level2), 1, DEC); + sevenseg[unit]->printFloat(CharToFloat(value_level2), 1, DEC); } sevenseg[unit]->writeDisplay(); unit++; @@ -266,7 +266,7 @@ void SevensegDrawStringAt(uint16_t x, uint16_t y, char *str, uint16_t color, uin hasnumber= true; if (outnumtype == FLOAT) { // Floating point number is given - numberf = atof(str+i); + numberf = CharToFloat(str+i); // Find number of fractional digits buf= str+i; char *cp= strchr(buf, '.'); diff --git a/tasmota/tasmota_xdsp_display/xdsp_15_tm1637.ino b/tasmota/tasmota_xdsp_display/xdsp_15_tm1637.ino index 0deb8d4a8..b2ec1e80a 100644 --- a/tasmota/tasmota_xdsp_display/xdsp_15_tm1637.ino +++ b/tasmota/tasmota_xdsp_display/xdsp_15_tm1637.ino @@ -351,7 +351,7 @@ bool CmndTM1637Number(bool clear) position = atoi(sPosition); case 1: subStr(sNum, XdrvMailbox.data, ",", 1); - num = atof(sNum); + num = CharToFloat(sNum); } if ((position < 0) || (position > (Settings->display_width - 1))) @@ -450,7 +450,7 @@ bool CmndTM1637Float(bool clear) position = atoi(sPosition); case 1: subStr(sNum, XdrvMailbox.data, ",", 1); - fnum = atof(sNum); + fnum = CharToFloat(sNum); } if ((position < 0) || (position > (Settings->display_width - 1))) diff --git a/tasmota/tasmota_xsns_sensor/xsns_69_opentherm.ino b/tasmota/tasmota_xsns_sensor/xsns_69_opentherm.ino index d18f51635..f919ebdfb 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_69_opentherm.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_69_opentherm.ino @@ -500,7 +500,7 @@ void sns_opentherm_boiler_setpoint_cmd(void) bool query = strlen(XdrvMailbox.data) == 0; if (!query) { - sns_ot_boiler_status.m_boilerSetpoint = atof(XdrvMailbox.data); + sns_ot_boiler_status.m_boilerSetpoint = CharToFloat(XdrvMailbox.data); } ResponseCmndFloat(sns_ot_boiler_status.m_boilerSetpoint, Settings->flag2.temperature_resolution); } @@ -510,7 +510,7 @@ void sns_opentherm_hot_water_setpoint_cmd(void) bool query = strlen(XdrvMailbox.data) == 0; if (!query) { - sns_ot_boiler_status.m_hotWaterSetpoint = atof(XdrvMailbox.data); + sns_ot_boiler_status.m_hotWaterSetpoint = CharToFloat(XdrvMailbox.data); } ResponseCmndFloat(sns_ot_boiler_status.m_hotWaterSetpoint, Settings->flag2.temperature_resolution); } From 0b3c237627fa32b9cdc5e5bf978dbdbf040be2f4 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 6 Jan 2023 15:28:44 +0100 Subject: [PATCH 104/262] Change strtod() into CharToFloat() saving 8k code Change strtod() into CharToFloat() saving 8k code --- .../xdrv_25_A4988_Stepper.ino | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_25_A4988_Stepper.ino b/tasmota/tasmota_xdrv_driver/xdrv_25_A4988_Stepper.ino index ca8a2a421..d72c51545 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_25_A4988_Stepper.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_25_A4988_Stepper.ino @@ -69,49 +69,56 @@ void (* const A4988Command[])(void) PROGMEM = { &CmndDoMove,&CmndDoRotate,&CmndDoTurn,&CmndSetMIS,&CmndSetSPR,&CmndSetRPM}; void CmndDoMove(void) { + // Move the motor the given number of steps (positive values: clockwise, negative values: counterclockwise) if (XdrvMailbox.data_len > 0) { - long stepsPlease = strtoul(XdrvMailbox.data,nullptr,10); + long stepsPlease = strtol(XdrvMailbox.data, nullptr, 10); myA4988->doMove(stepsPlease); ResponseCmndDone(); } } void CmndDoRotate(void) { + // Rotate the motor the given number of degrees (positive values: clockwise, negative values: counterclockwise) if (XdrvMailbox.data_len > 0) { - long degrsPlease = strtoul(XdrvMailbox.data,nullptr,10); + long degrsPlease = strtol(XdrvMailbox.data, nullptr, 10); myA4988->doRotate(degrsPlease); ResponseCmndDone(); } } void CmndDoTurn(void) { + // Spin the motor the given number of turns (positive values: clockwise, negative values: counterclockwise) if (XdrvMailbox.data_len > 0) { - float turnsPlease = strtod(XdrvMailbox.data,nullptr); +// float turnsPlease = strtod(XdrvMailbox.data,nullptr); + float turnsPlease = CharToFloat(XdrvMailbox.data); // Save 8k code size over strtod() myA4988->doTurn(turnsPlease); ResponseCmndDone(); } } void CmndSetMIS(void) { - if (PinUsed(GPIO_A4988_MS1) && PinUsed(GPIO_A4988_MS1, 1) && PinUsed(GPIO_A4988_MS1, 2) && (XdrvMailbox.data_len > 0)) { - short newMIS = strtoul(XdrvMailbox.data,nullptr,10); - myA4988->setMIS(newMIS); + // 1,2,4,8,16 Set micro stepping increment - 1/1 (full steps) to 1/16 (default = 1) + if (PinUsed(GPIO_A4988_MS1) && PinUsed(GPIO_A4988_MS1, 1) && PinUsed(GPIO_A4988_MS1, 2) && (XdrvMailbox.payload > 0)) { +// short newMIS = strtoul(XdrvMailbox.data,nullptr,10); + myA4988->setMIS(XdrvMailbox.payload); ResponseCmndDone(); } } void CmndSetSPR(void) { - if (XdrvMailbox.data_len > 0) { - int newSPR = strtoul(XdrvMailbox.data,nullptr,10); - myA4988->setSPR(newSPR); + // Set the number of steps the given motor needs for one revolution (default = 200) + if (XdrvMailbox.payload > 0) { +// int newSPR = strtoul(XdrvMailbox.data,nullptr,10); + myA4988->setSPR(XdrvMailbox.payload); ResponseCmndDone(); } } void CmndSetRPM(void) { - if (XdrvMailbox.data_len > 0) { - short newRPM = strtoul(XdrvMailbox.data,nullptr,10); - myA4988->setRPM(newRPM); + // Set revolutions per minute (default = 30) + if (XdrvMailbox.payload > 0) { +// short newRPM = strtoul(XdrvMailbox.data,nullptr,10); + myA4988->setRPM(XdrvMailbox.payload); ResponseCmndDone(); } } From 0b2a375deeda53de76951381f8867571e0c8a680 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 6 Jan 2023 16:04:04 +0100 Subject: [PATCH 105/262] Update changelogs --- CHANGELOG.md | 3 ++- README.md | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d50926f05..92614722a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,11 +15,12 @@ All notable changes to this project will be documented in this file. - Energy totals max supported value from +/-21474.83647 to +/-2147483.647 kWh - Removed delays in TasmotaSerial and TasmotaModbus Tx enable switching - Increase rule event buffer from 100 to 256 characters (#16943) +- All calls to atof() into CharToFloat() reducing code size by 8k ### Fixed - Energy dummy switched voltage and power regression from v12.2.0.2 - Orno WE517 modbus serial config 8E1 setting (#17545) -- No IP address shown when in AP moode (#17599) +- No IP address shown when in AP mode regression from v12.3.1.1 (#17599) ### Removed diff --git a/README.md b/README.md index c414ba828..04fa89f36 100644 --- a/README.md +++ b/README.md @@ -126,6 +126,8 @@ You can contribute to Tasmota by [![donate](https://img.shields.io/badge/donate-PayPal-blue.svg)](https://paypal.me/tasmota) + + ## Credits People helping to keep the show on the road: From edc7cd5bc372ac275e2428f132086ba92ae8be22 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 6 Jan 2023 17:08:53 +0100 Subject: [PATCH 106/262] Add a coffee --- FIRMWARE.md | 1 + README.md | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/FIRMWARE.md b/FIRMWARE.md index 6be055328..e7ea33291 100644 --- a/FIRMWARE.md +++ b/FIRMWARE.md @@ -13,6 +13,7 @@ If you like **Tasmota**, give it a star, or fork it and contribute! [![GitHub stars](https://img.shields.io/github/stars/arendst/Tasmota.svg?style=social&label=Star)](https://github.com/arendst/Tasmota/stargazers) [![GitHub forks](https://img.shields.io/github/forks/arendst/Tasmota.svg?style=social&label=Fork)](https://github.com/arendst/Tasmota/network) [![donate](https://img.shields.io/badge/donate-PayPal-blue.svg)](https://paypal.me/tasmota) +[![donate](https://img.shields.io/badge/donate-buy%20me%20a%20coffee-yellow.svg)](https://www.buymeacoffee.com/tasmota) See [CHANGELOG.md](https://github.com/arendst/Tasmota/blob/development/tasmota/CHANGELOG.md) for changes since last release. diff --git a/README.md b/README.md index 04fa89f36..11c447a81 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ If you like **Tasmota**, give it a star, or fork it and contribute! [![GitHub stars](https://img.shields.io/github/stars/arendst/Tasmota.svg?style=social&label=Star)](https://github.com/arendst/Tasmota/stargazers) [![GitHub forks](https://img.shields.io/github/forks/arendst/Tasmota.svg?style=social&label=Fork)](https://github.com/arendst/Tasmota/network) [![donate](https://img.shields.io/badge/donate-PayPal-blue.svg)](https://paypal.me/tasmota) +[![donate](https://img.shields.io/badge/donate-buy%20me%20a%20coffee-yellow.svg)](https://www.buymeacoffee.com/tasmota) See [RELEASENOTES.md](https://github.com/arendst/Tasmota/blob/master/RELEASENOTES.md) for release information. @@ -125,8 +126,7 @@ You can contribute to Tasmota by - Contributing missing [documentation](https://tasmota.github.io/docs) for features and devices [![donate](https://img.shields.io/badge/donate-PayPal-blue.svg)](https://paypal.me/tasmota) - - +[![donate](https://img.shields.io/badge/donate-buy%20me%20a%20coffee-yellow.svg)](https://www.buymeacoffee.com/tasmota) ## Credits From 5e89578403a86fd09d251e33635251cbe050622c Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Fri, 6 Jan 2023 19:03:07 +0100 Subject: [PATCH 107/262] Extend fix #17619 to non-IPv6 (#17621) --- tasmota/tasmota_support/support_wifi.ino | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tasmota/tasmota_support/support_wifi.ino b/tasmota/tasmota_support/support_wifi.ino index fe2b63cf2..fe5b8fb0e 100644 --- a/tasmota/tasmota_support/support_wifi.ino +++ b/tasmota/tasmota_support/support_wifi.ino @@ -756,7 +756,6 @@ String IPForUrl(const IPAddress & ip) // IPv4 has always priority // Copy the value of the IP if pointer provided (optional) bool WifiGetIP(IPAddress *ip) { -#ifdef USE_IPV6 if ((uint32_t)WiFi.localIP() != 0) { if (ip != nullptr) { *ip = WiFi.localIP(); } return true; @@ -765,18 +764,15 @@ bool WifiGetIP(IPAddress *ip) { if (ip != nullptr) { *ip = WiFi.softAPIP(); } return true; } +#ifdef USE_IPV6 IPAddress lip; if (WifiGetIPv6(&lip)) { if (ip != nullptr) { *ip = lip; } return true; } if (ip != nullptr) { *ip = IPAddress(); } - return false; -#else - // IPv4 only - if (ip != nullptr) { *ip = WiFi.localIP(); } - return (uint32_t)WiFi.localIP() != 0; #endif // USE_IPV6 + return false; } bool WifiHasIP(void) { From 2f1e36e1bfc80c645d9857d523878752f2e19dd9 Mon Sep 17 00:00:00 2001 From: gemu Date: Sat, 7 Jan 2023 11:31:48 +0100 Subject: [PATCH 108/262] Epaper29 v2 (#17627) * support for v2 * Update ST7262_rgb16_display.ini --- .../Epaper_29-gemu-1.0/epd2in9.cpp | 150 +++++++++++++++++- lib/lib_display/Epaper_29-gemu-1.0/epd2in9.h | 2 + tasmota/displaydesc/ST7262_rgb16_display.ini | 6 +- 3 files changed, 156 insertions(+), 2 deletions(-) diff --git a/lib/lib_display/Epaper_29-gemu-1.0/epd2in9.cpp b/lib/lib_display/Epaper_29-gemu-1.0/epd2in9.cpp index 434a14b89..96b83645e 100644 --- a/lib/lib_display/Epaper_29-gemu-1.0/epd2in9.cpp +++ b/lib/lib_display/Epaper_29-gemu-1.0/epd2in9.cpp @@ -28,6 +28,8 @@ #include "epd2in9.h" +#define EPD_29_V2 + Epd::Epd(int16_t width, int16_t height) : Paint(width,height) { } @@ -126,6 +128,32 @@ int Epd::Init(const unsigned char* lut) { width = EPD_WIDTH; height = EPD_HEIGHT; +#ifdef EPD_29_V2 + /* EPD hardware init start */ + WaitUntilIdle(); + SendCommand(0x12); //SWRESET + WaitUntilIdle(); + + SendCommand(0x01); //Driver output control + SendData(0x27); + SendData(0x01); + SendData(0x00); + + SendCommand(0x11); //data entry mode + SendData(0x03); + + SetMemoryArea(0, 0, width-1, height-1); + + SendCommand(0x21); // Display update control + SendData(0x00); + SendData(0x80); + + SetMemoryPointer(0, 0); + WaitUntilIdle(); + + SetLut_by_host(lut_full_update); + +#else /* EPD hardware init start */ this->lut = lut; Reset(); @@ -146,6 +174,7 @@ int Epd::Init(const unsigned char* lut) { SendCommand(DATA_ENTRY_MODE_SETTING); SendData(0x03); // X increment; Y increment SetLut(this->lut); +#endif /* EPD hardware init end */ return 0; } @@ -172,6 +201,11 @@ void Epd::SendData(unsigned char data) { * @brief: Wait until the busy_pin goes LOW */ void Epd::WaitUntilIdle(void) { + +#ifdef EPD_29_V2 + delay(100); +#endif + return; //while(DigitalRead(busy_pin) == HIGH) { //LOW: idle, HIGH: busy // DelayMs(100); @@ -190,6 +224,34 @@ void Epd::Reset(void) { //delay(200); } +#ifdef EPD_29_V2 +void Epd::SetLut(const unsigned char *lut) { + unsigned char count; + SendCommand(0x32); + for(count=0; count<153; count++) + SendData(lut[count]); + WaitUntilIdle(); +} + + +void Epd::SetLut_by_host(const unsigned char *lut) { + SetLut((unsigned char *)lut); + SendCommand(0x3f); + SendData(*(lut+153)); + SendCommand(0x03); // gate voltage + SendData(*(lut+154)); + SendCommand(0x04); // source voltage + SendData(*(lut+155)); // VSH + SendData(*(lut+156)); // VSH2 + SendData(*(lut+157)); // VSL + SendCommand(0x2c); // VCOM + SendData(*(lut+158)); +} +#else + +void Epd::SetLut_by_host(const unsigned char *lut) { + +} /** * @brief: set the look-up table register */ @@ -201,6 +263,7 @@ void Epd::SetLut(const unsigned char* lut) { SendData(this->lut[i]); } } +#endif /** * @brief: put an image buffer to the frame memory. @@ -310,6 +373,23 @@ void Epd::DisplayFrame(void) { WaitUntilIdle(); } + +#ifdef EPD_29_V2 +/** + * @brief: private function to specify the memory area for data R/W + */ +void Epd::SetMemoryArea(int x_start, int y_start, int x_end, int y_end) { + SendCommand(0x44); + /* x point must be the multiple of 8 or the last 3 bits will be ignored */ + SendData((x_start >> 3) & 0xFF); + SendData((x_end >> 3) & 0xFF); + SendCommand(0x45); + SendData(y_start & 0xFF); + SendData((y_start >> 8) & 0xFF); + SendData(y_end & 0xFF); + SendData((y_end >> 8) & 0xFF); +} +#else /** * @brief: private function to specify the memory area for data R/W */ @@ -324,7 +404,24 @@ void Epd::SetMemoryArea(int x_start, int y_start, int x_end, int y_end) { SendData(y_end & 0xFF); SendData((y_end >> 8) & 0xFF); } +#endif + +#ifdef EPD_29_V2 + +/** + * @brief: private function to specify the start point for data R/W + */ +void Epd::SetMemoryPointer(int x, int y) { + SendCommand(0x4E); + /* x point must be the multiple of 8 or the last 3 bits will be ignored */ + SendData((x >> 3) & 0xFF); + SendCommand(0x4F); + SendData(y & 0xFF); + SendData((y >> 8) & 0xFF); + WaitUntilIdle(); +} +#else /** * @brief: private function to specify the start point for data R/W */ @@ -337,6 +434,7 @@ void Epd::SetMemoryPointer(int x, int y) { SendData((y >> 8) & 0xFF); WaitUntilIdle(); } +#endif /** * @brief: After this command is transmitted, the chip would enter the @@ -349,6 +447,56 @@ void Epd::Sleep() { WaitUntilIdle(); } +#ifdef EPD_29_V2 + +const unsigned char lut_partial_update[159] = +{ +0x0,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x80,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x40,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0A,0x0,0x0,0x0,0x0,0x0,0x2, +0x1,0x0,0x0,0x0,0x0,0x0,0x0, +0x1,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x22,0x22,0x22,0x22,0x22,0x22,0x0,0x0,0x0, +0x22,0x17,0x41,0xB0,0x32,0x36, +}; + +const unsigned char lut_full_update[159] = +{ +0x80, 0x66, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, +0x10, 0x66, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, +0x80, 0x66, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, +0x10, 0x66, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x14, 0x8, 0x0, 0x0, 0x0, 0x0, 0x1, +0xA, 0xA, 0x0, 0xA, 0xA, 0x0, 0x1, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x14, 0x8, 0x0, 0x1, 0x0, 0x0, 0x1, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x0, 0x0, 0x0, +0x22, 0x17, 0x41, 0x0, 0x32, 0x36 +}; + +#else + const unsigned char lut_full_update[] = { 0x02, 0x02, 0x01, 0x11, 0x12, 0x12, 0x22, 0x22, @@ -364,7 +512,7 @@ const unsigned char lut_partial_update[] = 0x00, 0x00, 0x00, 0x00, 0x13, 0x14, 0x44, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - +#endif // EPD_29_V2 #define PIN_OUT_SET 0x60000304 #define PIN_OUT_CLEAR 0x60000308 diff --git a/lib/lib_display/Epaper_29-gemu-1.0/epd2in9.h b/lib/lib_display/Epaper_29-gemu-1.0/epd2in9.h index bf0863cd0..3be3071ec 100644 --- a/lib/lib_display/Epaper_29-gemu-1.0/epd2in9.h +++ b/lib/lib_display/Epaper_29-gemu-1.0/epd2in9.h @@ -106,6 +106,8 @@ private: void SetLut(const unsigned char* lut); void SetMemoryArea(int x_start, int y_start, int x_end, int y_end); void SetMemoryPointer(int x, int y); + void SetLut_by_host(const unsigned char* lut); + //void fastSPIwrite(uint8_t d,uint8_t dc); }; diff --git a/tasmota/displaydesc/ST7262_rgb16_display.ini b/tasmota/displaydesc/ST7262_rgb16_display.ini index 413af0bb1..80b210600 100644 --- a/tasmota/displaydesc/ST7262_rgb16_display.ini +++ b/tasmota/displaydesc/ST7262_rgb16_display.ini @@ -1,5 +1,9 @@ :H,ST7262,800,480,16,RGB,40,41,39,42,2,15,16,4,45,48,47,21,14,8,3,46,9,1,5,6,7,14 :S,2,1,1,0,40,20 :V,0,8,4,8,0,8,4,8,1 -:TI1,5a,*,*,-1,38 +:0,00 +:1,01 +:2,02 +:3,03 +:TI1,5d,*,*,-1,38 # From 7465ff0c7f3341555d11c219e0a6b5f60c7ff6e8 Mon Sep 17 00:00:00 2001 From: gemu Date: Sat, 7 Jan 2023 11:32:26 +0100 Subject: [PATCH 109/262] some fixes on counters (#17628) --- tasmota/tasmota_xsns_sensor/xsns_53_sml.ino | 45 ++++++++++++++++----- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino b/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino index fdcea8b38..c65b1fbd3 100755 --- a/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino @@ -2822,7 +2822,7 @@ next_line: #ifdef ESP8266 #ifdef SPECIAL_SS char type = sml_globs.mp[meters].type; - if (type=='m' || type=='M' || type=='k' || type=='p' || type=='R' || type=='v') { + if (type == 'm' || type == 'M' || type == 'k' || type == 'p' || type == 'R' || type == 'v') { meter_desc[meters].meter_ss = new TasmotaSerial(sml_globs.mp[meters].srcpin,sml_globs.mp[meters].trxpin, 1, 0, meter_desc[meters].sibsiz); } else { meter_desc[meters].meter_ss = new TasmotaSerial(sml_globs.mp[meters].srcpin,sml_globs.mp[meters].trxpin, 1, 1, meter_desc[meters].sibsiz); @@ -3095,6 +3095,18 @@ void SetDBGLed(uint8_t srcpin, uint8_t ledpin) { } } +// force channel math on counters +void SML_Counter_Poll_1s(void) { + for (uint32_t meter = 0; meter < sml_globs.meters_used; meter++) { + if (sml_globs.mp[meter].type == 'c') { + SML_Decode(meter); + } + } +} + +#define CNT_PULSE_TIMEOUT 5000 + + // fast counter polling void SML_Counter_Poll(void) { uint16_t meters, cindex = 0; @@ -3152,10 +3164,15 @@ uint32_t ctime = millis(); } if (sml_counters[cindex].sml_cnt_updated) { - InjektCounterValue(sml_counters[cindex].sml_cnt_old_state, RtcSettings.pulse_counter[cindex], 60000.0 / (float)sml_counters[cindex].sml_counter_pulsewidth); + InjektCounterValue(meters, RtcSettings.pulse_counter[cindex], 60000.0 / (float)sml_counters[cindex].sml_counter_pulsewidth); sml_counters[cindex].sml_cnt_updated = 0; } - + // check timeout + uint32_t time = millis(); + if ((time - sml_counters[cindex].sml_counter_lfalltime) > CNT_PULSE_TIMEOUT) { + InjektCounterValue(meters, RtcSettings.pulse_counter[cindex], 0); + sml_counters[cindex].sml_counter_lfalltime = time; + } } cindex++; } @@ -3464,12 +3481,12 @@ bool XSNS_53_cmd(void) { uint8_t cindex = 0; for (uint8_t meters = 0; meters < sml_globs.meters_used; meters++) { if (sml_globs.mp[meters].type == 'c') { - InjektCounterValue(meters,RtcSettings.pulse_counter[cindex], 0.0); + InjektCounterValue(meters, RtcSettings.pulse_counter[cindex], 0.0); cindex++; } } } - ResponseTime_P(PSTR(",\"SML\":{\"CMD\":\"counter%d: %d\"}}"), index,RtcSettings.pulse_counter[index - 1]); + ResponseTime_P(PSTR(",\"SML\":{\"CMD\":\"counter%d: %d\"}}"), index, RtcSettings.pulse_counter[index - 1]); } else if (*cp=='r') { // restart ResponseTime_P(PSTR(",\"SML\":{\"CMD\":\"restart\"}}")); @@ -3508,13 +3525,16 @@ bool XSNS_53_cmd(void) { } void InjektCounterValue(uint8_t meter, uint32_t counter, float rate) { - int dec = (int)rate; - int frac = (int)((rate - (float)dec) * 1000.0); snprintf((char*)&meter_desc[meter].sbuff[0], meter_desc[meter].sbsiz, "1-0:1.8.0*255(%d)", counter); SML_Decode(meter); - snprintf((char*)&meter_desc[meter].sbuff[0], meter_desc[meter].sbsiz, "1-0:1.7.0*255(%d.%d)", dec, frac); + char freq[16]; + freq[0] = 0; + if (rate) { + DOUBLE2CHAR(rate, 4, freq); + } + snprintf((char*)&meter_desc[meter].sbuff[0], meter_desc[meter].sbsiz, "1-0:1.7.0*255(%s)", freq); SML_Decode(meter); } @@ -3545,7 +3565,6 @@ bool Xsns53(uint32_t function) { } } break; -#ifdef USE_SCRIPT case FUNC_EVERY_100_MSECOND: if (bitRead(Settings->rule_enabled, 0)) { if (sml_globs.ready) { @@ -3553,7 +3572,13 @@ bool Xsns53(uint32_t function) { } } break; -#endif // USE_SCRIPT + case FUNC_EVERY_SECOND: + if (bitRead(Settings->rule_enabled, 0)) { + if (sml_globs.ready) { + SML_Counter_Poll_1s(); + } + } + break; case FUNC_JSON_APPEND: if (sml_globs.ready) { if (sml_options & SML_OPTIONS_JSON_ENABLE) { From 2e7496a052ae4009df84033029f4b48dde250d47 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sat, 7 Jan 2023 15:37:52 +0100 Subject: [PATCH 110/262] Keep webserver enabled on command ``upload`` --- CHANGELOG.md | 1 + RELEASENOTES.md | 1 + tasmota/include/tasmota.h | 2 +- tasmota/tasmota_support/support.ino | 18 +++++++++++- tasmota/tasmota_support/support_tasmota.ino | 25 +++++----------- .../xdrv_01_9_webserver.ino | 29 ++----------------- .../tasmota_xdrv_driver/xdrv_26_ariluxrf.ino | 6 ++++ .../tasmota_xdrv_driver/xdrv_79_esp32_ble.ino | 7 +++++ .../tasmota_xsns_sensor/xsns_01_counter.ino | 6 ++++ .../tasmota_xsns_sensor/xsns_62_esp32_mi.ino | 5 ++++ 10 files changed, 53 insertions(+), 47 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 92614722a..2dcebb4ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ All notable changes to this project will be documented in this file. - Removed delays in TasmotaSerial and TasmotaModbus Tx enable switching - Increase rule event buffer from 100 to 256 characters (#16943) - All calls to atof() into CharToFloat() reducing code size by 8k +- Keep webserver enabled on command ``upload`` ### Fixed - Energy dummy switched voltage and power regression from v12.2.0.2 diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 5a621fc88..7d1a23e47 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -126,6 +126,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm - ESP32 Framework (Core) from v2.0.5.3 to v2.0.6 (IPv6 support) - Energy totals max supported value from +/-21474.83647 to +/-2147483.647 kWh - Removed delays in TasmotaSerial and TasmotaModbus Tx enable switching +- Keep webserver enabled on command ``upload`` - Increase rule event buffer from 100 to 256 characters [#16943](https://github.com/arendst/Tasmota/issues/16943) - TuyaMcu rewrite by btsimonh [#17051](https://github.com/arendst/Tasmota/issues/17051) - Tasmota OTA scripts now support both unzipped and gzipped file uploads [#17378](https://github.com/arendst/Tasmota/issues/17378) diff --git a/tasmota/include/tasmota.h b/tasmota/include/tasmota.h index 911df0171..fdc87cc1d 100644 --- a/tasmota/include/tasmota.h +++ b/tasmota/include/tasmota.h @@ -388,7 +388,7 @@ enum LightTypes { LT_BASIC, LT_PWM1, LT_PWM2, LT_PWM3, LT_PWM4, LT enum XsnsFunctions {FUNC_SETTINGS_OVERRIDE, FUNC_PIN_STATE, FUNC_I2C_INIT, FUNC_MODULE_INIT, FUNC_PRE_INIT, FUNC_INIT, FUNC_LOOP, FUNC_SLEEP_LOOP, FUNC_EVERY_50_MSECOND, FUNC_EVERY_100_MSECOND, FUNC_EVERY_200_MSECOND, FUNC_EVERY_250_MSECOND, FUNC_EVERY_SECOND, - FUNC_SAVE_SETTINGS, FUNC_SAVE_AT_MIDNIGHT, FUNC_SAVE_BEFORE_RESTART, + FUNC_SAVE_SETTINGS, FUNC_SAVE_AT_MIDNIGHT, FUNC_SAVE_BEFORE_RESTART, FUNC_INTERRUPT_STOP, FUNC_INTERRUPT_START, FUNC_AFTER_TELEPERIOD, FUNC_JSON_APPEND, FUNC_WEB_SENSOR, FUNC_WEB_COL_SENSOR, FUNC_COMMAND, FUNC_COMMAND_SENSOR, FUNC_COMMAND_DRIVER, FUNC_MQTT_SUBSCRIBE, FUNC_MQTT_INIT, FUNC_MQTT_DATA, FUNC_SET_POWER, FUNC_SET_DEVICE_POWER, FUNC_SHOW_SENSOR, FUNC_ANY_KEY, FUNC_LED_LINK, diff --git a/tasmota/tasmota_support/support.ino b/tasmota/tasmota_support/support.ino index 716e578bc..489961737 100755 --- a/tasmota/tasmota_support/support.ino +++ b/tasmota/tasmota_support/support.ino @@ -1029,7 +1029,7 @@ const char kOptions[] PROGMEM = "OFF|" D_OFF "|FALSE|" D_FALSE "|STOP|" D_STOP " "TOGGLE|" D_TOGGLE "|" D_ADMIN "|" // 2 "BLINK|" D_BLINK "|" // 3 "BLINKOFF|" D_BLINKOFF "|" // 4 - "UP|" D_OPEN "|" // 100 + "UP|" D_OPEN "|" // 100 "ALL" ; // 255 const uint8_t sNumbers[] PROGMEM = { 0,0,0,0,0,0,0,0,0, @@ -1128,6 +1128,22 @@ uint32_t WebColor(uint32_t i) return tcolor; } +void AllowInterrupts(bool state) { + if (!state) { // Stop interrupts + XdrvXsnsCall(FUNC_INTERRUPT_STOP); + +#ifdef USE_EMULATION + UdpDisconnect(); +#endif // USE_EMULATION + } else { // Start interrupts +#ifdef USE_EMULATION + UdpConnect(); +#endif // USE_EMULATION + + XdrvXsnsCall(FUNC_INTERRUPT_START); + } +} + /*********************************************************************************************\ * Response data handling \*********************************************************************************************/ diff --git a/tasmota/tasmota_support/support_tasmota.ino b/tasmota/tasmota_support/support_tasmota.ino index f5da6c033..f33390e97 100644 --- a/tasmota/tasmota_support/support_tasmota.ino +++ b/tasmota/tasmota_support/support_tasmota.ino @@ -1219,11 +1219,6 @@ void Every100mSeconds(void) * Every 0.25 second \*-------------------------------------------------------------------------------------------*/ -#ifdef USE_BLE_ESP32 - // declare the fn - int ExtStopBLE(); -#endif // USE_BLE_ESP32 - bool CommandsReady(void) { bool ready = BACKLOG_EMPTY ; #ifdef USE_UFILESYS @@ -1303,18 +1298,11 @@ void Every250mSeconds(void) SettingsSave(1); // Free flash for OTA update } if (TasmotaGlobal.ota_state_flag <= 0) { -#ifdef USE_BLE_ESP32 - ExtStopBLE(); -#endif // USE_BLE_ESP32 -#ifdef USE_COUNTER - CounterInterruptDisable(true); // Prevent OTA failures on 100Hz counter interrupts -#endif // USE_COUNTER + AllowInterrupts(0); #ifdef USE_WEBSERVER - if (Settings->webserver) StopWebserver(); +// if (Settings->webserver) StopWebserver(); // 20230107 No more need for disabling webserver during OTA #endif // USE_WEBSERVER -#ifdef USE_ARILUX_RF - AriluxRfDisable(); // Prevent restart exception on Arilux Interrupt routine -#endif // USE_ARILUX_RF + TasmotaGlobal.ota_state_flag = 92; ota_result = 0; char full_ota_url[200]; @@ -1440,9 +1428,12 @@ void Every250mSeconds(void) ResponseAppend_P(PSTR("\"}")); // TasmotaGlobal.restart_flag = 2; // Restart anyway to keep memory clean webserver MqttPublishPrefixTopicRulesProcess_P(STAT, PSTR(D_CMND_UPGRADE)); + AllowInterrupts(1); +/* #ifdef USE_COUNTER CounterInterruptDisable(false); #endif // USE_COUNTER +*/ } } break; @@ -1642,9 +1633,7 @@ void ArduinoOTAInit(void) #ifdef USE_WEBSERVER if (Settings->webserver) { StopWebserver(); } #endif // USE_WEBSERVER -#ifdef USE_ARILUX_RF - AriluxRfDisable(); // Prevent restart exception on Arilux Interrupt routine -#endif // USE_ARILUX_RF + AllowInterrupts(0); if (Settings->flag.mqtt_enabled) { MqttDisconnect(); // SetOption3 - Enable MQTT } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_01_9_webserver.ino b/tasmota/tasmota_xdrv_driver/xdrv_01_9_webserver.ino index f1a85b69b..91b140e48 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_01_9_webserver.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_01_9_webserver.ino @@ -2670,11 +2670,6 @@ void HandleUploadDone(void) { WSContentStop(); } -#if defined(USE_BLE_ESP32) || defined(USE_MI_ESP32) - // declare the fn - int ExtStopBLE(); -#endif - void UploadServices(uint32_t start_service) { if (Web.upload_services_stopped != start_service) { return; } Web.upload_services_stopped = !start_service; @@ -2685,31 +2680,11 @@ void UploadServices(uint32_t start_service) { /* MqttRetryCounter(0); */ -#ifdef USE_ARILUX_RF - AriluxRfInit(); -#endif // USE_ARILUX_RF -#ifdef USE_COUNTER - CounterInterruptDisable(false); -#endif // USE_COUNTER -#ifdef USE_EMULATION - UdpConnect(); -#endif // USE_EMULATION - + AllowInterrupts(1); } else { // AddLog(LOG_LEVEL_DEBUG, PSTR("UPL: Services disabled")); -#ifdef USE_BLE_ESP32 - ExtStopBLE(); -#endif -#ifdef USE_EMULATION - UdpDisconnect(); -#endif // USE_EMULATION -#ifdef USE_COUNTER - CounterInterruptDisable(true); // Prevent OTA failures on 100Hz counter interrupts -#endif // USE_COUNTER -#ifdef USE_ARILUX_RF - AriluxRfDisable(); // Prevent restart exception on Arilux Interrupt routine -#endif // USE_ARILUX_RF + AllowInterrupts(0); /* MqttRetryCounter(60); if (Settings->flag.mqtt_enabled) { // SetOption3 - Enable MQTT diff --git a/tasmota/tasmota_xdrv_driver/xdrv_26_ariluxrf.ino b/tasmota/tasmota_xdrv_driver/xdrv_26_ariluxrf.ino index 8cad4cf56..ede03b44c 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_26_ariluxrf.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_26_ariluxrf.ino @@ -181,6 +181,12 @@ bool Xdrv26(uint32_t function) case FUNC_EVERY_SECOND: if (10 == TasmotaGlobal.uptime) { AriluxRfInit(); } // Needs rest before enabling RF interrupts break; + case FUNC_INTERRUPT_STOP: + AriluxRfDisable(); + break; + case FUNC_INTERRUPT_START: + AriluxRfInit(); + break; } return result; } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_79_esp32_ble.ino b/tasmota/tasmota_xdrv_driver/xdrv_79_esp32_ble.ino index 7060671a6..fabcf916e 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_79_esp32_ble.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_79_esp32_ble.ino @@ -3619,6 +3619,13 @@ bool Xdrv79(uint32_t function) BLE_ESP32::BLEPublishDevices = 1; // mqtt publish as 'TELE' break; + case FUNC_INTERRUPT_STOP: + ExtStopBLE(); + break; +/* + case FUNC_INTERRUPT_START: + break; +*/ #ifdef USE_WEBSERVER case FUNC_WEB_ADD_BUTTON: WSContentSend_P(BLE_ESP32::HTTP_BTN_MENU_BLE); diff --git a/tasmota/tasmota_xsns_sensor/xsns_01_counter.ino b/tasmota/tasmota_xsns_sensor/xsns_01_counter.ino index 42ac79295..d427cc7db 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_01_counter.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_01_counter.ino @@ -423,6 +423,12 @@ bool Xsns01(uint32_t function) case FUNC_COMMAND: result = DecodeCommand(kCounterCommands, CounterCommand); break; + case FUNC_INTERRUPT_STOP: + CounterInterruptDisable(true); + break; + case FUNC_INTERRUPT_START: + CounterInterruptDisable(false); + break; } } else { switch (function) { diff --git a/tasmota/tasmota_xsns_sensor/xsns_62_esp32_mi.ino b/tasmota/tasmota_xsns_sensor/xsns_62_esp32_mi.ino index 0b8c2eb26..9a85c149b 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_62_esp32_mi.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_62_esp32_mi.ino @@ -2357,11 +2357,16 @@ bool Xsns62(uint32_t function) MI32EverySecond(false); break; case FUNC_SAVE_BEFORE_RESTART: + case FUNC_INTERRUPT_STOP: ExtStopBLE(); break; case FUNC_COMMAND: result = DecodeCommand(kMI32_Commands, MI32_Commands); break; +/* + case FUNC_INTERRUPT_START: + break; +*/ case FUNC_JSON_APPEND: MI32Show(1); break; From dad059737d34015eeae594211d17bf6250866c79 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sat, 7 Jan 2023 16:11:30 +0100 Subject: [PATCH 111/262] Change PID temperature update (#17636) --- tasmota/tasmota_xdrv_driver/xdrv_49_pid.ino | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_49_pid.ino b/tasmota/tasmota_xdrv_driver/xdrv_49_pid.ino index b2d48a2cd..8ef523f35 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_49_pid.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_49_pid.ino @@ -230,6 +230,9 @@ void PIDEverySecond() { // run the pid algorithm if Pid.run_pid_now is true or if the right number of seconds has passed or if too long has // elapsed since last pv update. If too long has elapsed the the algorithm will deal with that. if (Pid.run_pid_now || Pid.current_time_secs - Pid.last_pv_update_secs > Pid.max_interval || (Pid.update_secs != 0 && sec_counter++ % Pid.update_secs == 0)) { + if (!Pid.run_pid_now) { + PIDShowSensor(); // set actual process value + } PIDRun(); Pid.run_pid_now = false; } From 2b0234c29996f48812f46d7f7ebfa4df6be95de3 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Sat, 7 Jan 2023 17:13:22 +0100 Subject: [PATCH 112/262] Tasmota VSCode settings.json (#336) (#17640) * Tasmota VSC custom menu --- .gitignore | 1 + .vscode/settings.json | 49 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 .vscode/settings.json diff --git a/.gitignore b/.gitignore index e7ee0a81d..3a575e21a 100644 --- a/.gitignore +++ b/.gitignore @@ -34,5 +34,6 @@ lib/libesp32/berry/berry .vscode/.browse.c_cpp.db* .vscode/c_cpp_properties.json .vscode/launch.json +.vscode/settings.json *.bak *.code-workspace diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..330a1092f --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,49 @@ +{ + "platformio-ide.toolbar": [ + { + "text": "$(trash)", + "commands": [ + { + "id": "workbench.action.tasks.runTask", + "args": "PlatformIO: Clean All" + } + ] + }, + { + "text": "$(check)", + "commands": [ + { + "id": "workbench.action.tasks.runTask", + "args": "PlatformIO: Build" + } + ] + }, + { + "text": "$(zap)", + "commands": [ + { + "id": "workbench.action.tasks.runTask", + "args": "PlatformIO: Upload" + } + ] + }, + { + "text": "$(flame)", + "commands": [ + { + "id": "platformio-ide.runPIOCoreCommand", + "args": "pio run -t erase_upload" + } + ] + }, + { + "text": "$(device-desktop)", + "commands": [ + { + "id": "workbench.action.tasks.runTask", + "args": "PlatformIO: Monitor" + } + ] + } + ] +} From 95690ab1b9b031ea40399cd50fbcf9a21930f372 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sat, 7 Jan 2023 17:31:10 +0100 Subject: [PATCH 113/262] Add recursive rule MQTT subscribe support (#16943) --- tasmota/tasmota_support/support_tasmota.ino | 5 ---- tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino | 27 ++++++++++++++----- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/tasmota/tasmota_support/support_tasmota.ino b/tasmota/tasmota_support/support_tasmota.ino index f33390e97..85055969f 100644 --- a/tasmota/tasmota_support/support_tasmota.ino +++ b/tasmota/tasmota_support/support_tasmota.ino @@ -1429,11 +1429,6 @@ void Every250mSeconds(void) // TasmotaGlobal.restart_flag = 2; // Restart anyway to keep memory clean webserver MqttPublishPrefixTopicRulesProcess_P(STAT, PSTR(D_CMND_UPGRADE)); AllowInterrupts(1); -/* -#ifdef USE_COUNTER - CounterInterruptDisable(false); -#endif // USE_COUNTER -*/ } } break; diff --git a/tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino b/tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino index f99856144..0454646a0 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino @@ -66,7 +66,15 @@ * RuleTimer2 100 \*********************************************************************************************/ -#define XDRV_10 10 +#define XDRV_10 10 + +#ifndef RULE_MAX_EVENTSZ +#define RULE_MAX_EVENTSZ 100 +#endif + +#ifndef RULE_MAX_MQTT_EVENTSZ +#define RULE_MAX_MQTT_EVENTSZ 256 +#endif //#define DEBUG_RULES @@ -186,7 +194,7 @@ struct RULES { bool busy = false; bool no_execute = false; // Don't actually execute rule commands - char event_data[256]; + char event_data[RULE_MAX_EVENTSZ]; } Rules; char rules_vars[MAX_RULE_VARS][33] = {{ 0 }}; @@ -936,7 +944,7 @@ void RulesInit(void) void RulesEvery50ms(void) { if ((Settings->rule_enabled || BERRY_RULES) && !Rules.busy) { // Any rule enabled - char json_event[300]; + char json_event[RULE_MAX_EVENTSZ +16]; // Add 16 chars for {"Event": .. } if (-1 == Rules.new_power) { Rules.new_power = TasmotaGlobal.power; } if (Rules.new_power != Rules.old_power) { @@ -1152,9 +1160,8 @@ void RulesSetPower(void) * true - The message is consumed. * false - The message is not in our list. */ -bool RulesMqttData(void) -{ - if (XdrvMailbox.data_len < 1 || XdrvMailbox.data_len > 256) { +bool RulesMqttData(void) { + if ((XdrvMailbox.data_len < 1) || (XdrvMailbox.data_len > RULE_MAX_MQTT_EVENTSZ)) { return false; } bool serviced = false; @@ -1163,6 +1170,7 @@ bool RulesMqttData(void) //AddLog(LOG_LEVEL_DEBUG, PSTR("RUL: MQTT Topic %s, Event %s"), XdrvMailbox.topic, XdrvMailbox.data); MQTT_Subscription event_item; //Looking for matched topic + char json_event[RULE_MAX_MQTT_EVENTSZ +32]; // Add chars for {"Event":{"": .. } for (uint32_t index = 0; index < subscriptions.size(); index++) { String sData = buData; @@ -1201,8 +1209,15 @@ bool RulesMqttData(void) } } value.trim(); + +/* //Create an new event. Cannot directly call RulesProcessEvent(). snprintf_P(Rules.event_data, sizeof(Rules.event_data), PSTR("%s=%s"), event_item.Event.c_str(), value.c_str()); + // 20230107 Superseded by the following code +*/ + bool quotes = (value[0] != '{'); + snprintf_P(json_event, sizeof(json_event), PSTR("{\"Event\":{\"%s\":%s%s%s}}"), event_item.Event.c_str(), (quotes)?"\"":"", value.c_str(), (quotes)?"\"":""); + RulesProcessEvent(json_event); } } return serviced; From 12d76517585d5cb7867818866812e12dafee70ba Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 8 Jan 2023 14:35:09 +0100 Subject: [PATCH 114/262] Fix shutter JSON responses --- tasmota/tasmota_xdrv_driver/xdrv_27_shutter.ino | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_27_shutter.ino b/tasmota/tasmota_xdrv_driver/xdrv_27_shutter.ino index 356042d32..235cdc8b8 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_27_shutter.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_27_shutter.ino @@ -1373,9 +1373,12 @@ void CmndShutterOpenTime(void) Settings->shutter_opentime[XdrvMailbox.index -1] = (uint16_t)(10 * CharToFloat(XdrvMailbox.data)); ShutterInit(); } +/* char time_chr[10]; dtostrfd((float)(Settings->shutter_opentime[XdrvMailbox.index -1]) / 10, 1, time_chr); ResponseCmndIdxChar(time_chr); +*/ + ResponseCmndIdxFloat((float)(Settings->shutter_opentime[XdrvMailbox.index -1]) / 10, 1); } } @@ -1386,9 +1389,12 @@ void CmndShutterCloseTime(void) Settings->shutter_closetime[XdrvMailbox.index -1] = (uint16_t)(10 * CharToFloat(XdrvMailbox.data)); ShutterInit(); } +/* char time_chr[10]; dtostrfd((float)(Settings->shutter_closetime[XdrvMailbox.index -1]) / 10, 1, time_chr); ResponseCmndIdxChar(time_chr); +*/ + ResponseCmndIdxFloat((float)(Settings->shutter_closetime[XdrvMailbox.index -1]) / 10, 1); } } @@ -1400,9 +1406,12 @@ void CmndShutterMotorDelay(void) ShutterInit(); //AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Shtr Init1. realdelay %d"),Shutter[XdrvMailbox.index -1].motordelay); } +/* char time_chr[10]; dtostrfd((float)(Shutter[XdrvMailbox.index -1].motordelay) / STEPS_PER_SECOND, 2, time_chr); ResponseCmndIdxChar(time_chr); +*/ + ResponseCmndIdxFloat((float)(Shutter[XdrvMailbox.index -1].motordelay) / STEPS_PER_SECOND, 2); } } @@ -1443,7 +1452,7 @@ void CmndShutterRelay(void) // {"ShutterRelay1":"1","ShutterRelay2":"3","ShutterRelay3":"5"} Response_P(PSTR("{")); for (uint32_t i = start; i < end; i++) { - ResponseAppend_P(PSTR("%s\"" D_PRFX_SHUTTER D_CMND_SHUTTER_RELAY "%d\":\"%d\""), (i>start)?",":"", i+1,Settings->shutter_startrelay[i]); + ResponseAppend_P(PSTR("%s\"" D_PRFX_SHUTTER D_CMND_SHUTTER_RELAY "%d\":%d"), (i>start)?",":"", i+1, Settings->shutter_startrelay[i]); } ResponseAppend_P(PSTR("}")); } From d80b763f979c5f0d2af0962e8ddbe9eb0660e6a0 Mon Sep 17 00:00:00 2001 From: Ralph Maschotta Date: Sun, 8 Jan 2023 15:57:34 +0100 Subject: [PATCH 115/262] Enable more than two and up to four BMP/BME sensors on two I2C buses for ESP32 (only two addresses (76, 77) per I2C bus are possible). (enhancement of #10827,#1049, #2707) (#17643) --- tasmota/tasmota_support/support.ino | 205 ++++++++++++-------- tasmota/tasmota_xsns_sensor/xsns_09_bmp.ino | 152 ++++++++++----- 2 files changed, 227 insertions(+), 130 deletions(-) diff --git a/tasmota/tasmota_support/support.ino b/tasmota/tasmota_support/support.ino index 489961737..38d35d094 100755 --- a/tasmota/tasmota_support/support.ino +++ b/tasmota/tasmota_support/support.ino @@ -2179,6 +2179,9 @@ bool TimeReachedUsec(uint32_t timer) const uint8_t I2C_RETRY_COUNTER = 3; uint32_t i2c_active[4] = { 0 }; +#ifdef ESP32 +uint32_t i2c_active_bus2[4] = { 0 }; // ESP32 can have two I2C buses +#endif uint32_t i2c_buffer = 0; bool I2cBegin(int sda, int scl, uint32_t frequency = 100000); @@ -2208,12 +2211,9 @@ bool I2c2Begin(int sda, int scl, uint32_t frequency) { // AddLog(LOG_LEVEL_DEBUG, PSTR("I2C: Bus2 %d"), result); return result; } - -bool I2cValidRead(uint8_t addr, uint8_t reg, uint8_t size, uint32_t bus = 0); -bool I2cValidRead(uint8_t addr, uint8_t reg, uint8_t size, uint32_t bus) -#else -bool I2cValidRead(uint8_t addr, uint8_t reg, uint8_t size) #endif + +bool I2cValidRead(uint8_t addr, uint8_t reg, uint8_t size, uint8_t bus = 0) { uint8_t retry = I2C_RETRY_COUNTER; bool status = false; @@ -2243,102 +2243,85 @@ bool I2cValidRead(uint8_t addr, uint8_t reg, uint8_t size) return status; } -bool I2cValidRead8(uint8_t *data, uint8_t addr, uint8_t reg) +bool I2cValidRead8(uint8_t *data, uint8_t addr, uint8_t reg, uint8_t bus = 0) { - bool status = I2cValidRead(addr, reg, 1); + bool status = I2cValidRead(addr, reg, 1,bus); *data = (uint8_t)i2c_buffer; return status; } - -bool I2cValidRead16(uint16_t *data, uint8_t addr, uint8_t reg) +bool I2cValidRead16(uint16_t *data, uint8_t addr, uint8_t reg, uint8_t bus = 0) { - bool status = I2cValidRead(addr, reg, 2); + bool status = I2cValidRead(addr, reg, 2,bus); *data = (uint16_t)i2c_buffer; return status; } - -bool I2cValidReadS16(int16_t *data, uint8_t addr, uint8_t reg) +bool I2cValidReadS16(int16_t *data, uint8_t addr, uint8_t reg, uint8_t bus = 0) { - bool status = I2cValidRead(addr, reg, 2); + bool status = I2cValidRead(addr, reg, 2, bus); *data = (int16_t)i2c_buffer; return status; } - -bool I2cValidRead16LE(uint16_t *data, uint8_t addr, uint8_t reg) +bool I2cValidRead16LE(uint16_t *data, uint8_t addr, uint8_t reg, uint8_t bus = 0) { uint16_t ldata; - bool status = I2cValidRead16(&ldata, addr, reg); + bool status = I2cValidRead16(&ldata, addr, reg, bus); *data = (ldata >> 8) | (ldata << 8); return status; } - -bool I2cValidReadS16_LE(int16_t *data, uint8_t addr, uint8_t reg) +bool I2cValidReadS16_LE(int16_t *data, uint8_t addr, uint8_t reg, uint8_t bus = 0) { uint16_t ldata; - bool status = I2cValidRead16LE(&ldata, addr, reg); + bool status = I2cValidRead16LE(&ldata, addr, reg, bus); *data = (int16_t)ldata; return status; } - -bool I2cValidRead24(int32_t *data, uint8_t addr, uint8_t reg) +bool I2cValidRead24(int32_t *data, uint8_t addr, uint8_t reg, uint8_t bus = 0) { - bool status = I2cValidRead(addr, reg, 3); + bool status = I2cValidRead(addr, reg, 3, bus); *data = i2c_buffer; return status; } - -uint8_t I2cRead8(uint8_t addr, uint8_t reg) +uint8_t I2cRead8(uint8_t addr, uint8_t reg, uint8_t bus = 0) { - I2cValidRead(addr, reg, 1); + I2cValidRead(addr, reg, 1, bus); return (uint8_t)i2c_buffer; } - -uint16_t I2cRead16(uint8_t addr, uint8_t reg) +uint16_t I2cRead16(uint8_t addr, uint8_t reg, uint8_t bus = 0) { - I2cValidRead(addr, reg, 2); + I2cValidRead(addr, reg, 2, bus); return (uint16_t)i2c_buffer; } - -int16_t I2cReadS16(uint8_t addr, uint8_t reg) +int16_t I2cReadS16(uint8_t addr, uint8_t reg, uint8_t bus = 0) { - I2cValidRead(addr, reg, 2); + I2cValidRead(addr, reg, 2, bus); return (int16_t)i2c_buffer; } - -uint16_t I2cRead16LE(uint8_t addr, uint8_t reg) +uint16_t I2cRead16LE(uint8_t addr, uint8_t reg, uint8_t bus = 0) { - I2cValidRead(addr, reg, 2); + I2cValidRead(addr, reg, 2, bus); uint16_t temp = (uint16_t)i2c_buffer; return (temp >> 8) | (temp << 8); } - -int16_t I2cReadS16_LE(uint8_t addr, uint8_t reg) +int16_t I2cReadS16_LE(uint8_t addr, uint8_t reg, uint8_t bus = 0) { - return (int16_t)I2cRead16LE(addr, reg); + return (int16_t)I2cRead16LE(addr, reg, bus); } - -int32_t I2cRead24(uint8_t addr, uint8_t reg) +int32_t I2cRead24(uint8_t addr, uint8_t reg, uint8_t bus = 0) { - I2cValidRead(addr, reg, 3); + I2cValidRead(addr, reg, 3, bus); return i2c_buffer; } -#ifdef ESP32 -bool I2cWrite(uint8_t addr, uint8_t reg, uint32_t val, uint8_t size, uint32_t bus = 0); -bool I2cWrite(uint8_t addr, uint8_t reg, uint32_t val, uint8_t size, uint32_t bus) -#else -bool I2cWrite(uint8_t addr, uint8_t reg, uint32_t val, uint8_t size) -#endif +bool I2cWrite(uint8_t addr, uint8_t reg, uint32_t val, uint8_t size, uint8_t bus = 0) { uint8_t x = I2C_RETRY_COUNTER; - #ifdef ESP32 if (!TasmotaGlobal.i2c_enabled_2) { bus = 0; } TwoWire & myWire = (bus == 0) ? Wire : Wire1; #else + if(0!=bus) {return false;} // second I2c bus ESP32 only TwoWire & myWire = Wire; #endif - do { myWire.beginTransmission((uint8_t)addr); // start transmission to device myWire.write(reg); // sends register address to write to @@ -2350,46 +2333,59 @@ bool I2cWrite(uint8_t addr, uint8_t reg, uint32_t val, uint8_t size) } while (myWire.endTransmission(true) != 0 && x != 0); // end transmission return (x); } - -bool I2cWrite8(uint8_t addr, uint8_t reg, uint16_t val) +bool I2cWrite8(uint8_t addr, uint8_t reg, uint32_t val, uint8_t bus = 0) { - return I2cWrite(addr, reg, val, 1); + return I2cWrite(addr, reg, val, 1,bus); } -bool I2cWrite16(uint8_t addr, uint8_t reg, uint16_t val) +bool I2cWrite16(uint8_t addr, uint8_t reg, uint32_t val, uint8_t bus = 0) { - return I2cWrite(addr, reg, val, 2); + return I2cWrite(addr, reg, val, 2,bus); } -int8_t I2cReadBuffer(uint8_t addr, uint8_t reg, uint8_t *reg_data, uint16_t len) +bool I2cReadBuffer(uint8_t addr, uint8_t reg, uint8_t *reg_data, uint16_t len, uint8_t bus = 0) { - Wire.beginTransmission((uint8_t)addr); - Wire.write((uint8_t)reg); - Wire.endTransmission(); - if (len != Wire.requestFrom((uint8_t)addr, (uint8_t)len)) { +#ifdef ESP32 + if (!TasmotaGlobal.i2c_enabled_2) { bus = 0; } + TwoWire & myWire = (bus == 0) ? Wire : Wire1; +#else + if(0!=bus) {return false;} // second I2c bus ESP32 only + TwoWire & myWire = Wire; +#endif + myWire.beginTransmission((uint8_t)addr); + myWire.write((uint8_t)reg); + myWire.endTransmission(); + if (len != myWire.requestFrom((uint8_t)addr, (uint8_t)len)) { return 1; } while (len--) { - *reg_data = (uint8_t)Wire.read(); + *reg_data = (uint8_t)myWire.read(); reg_data++; } return 0; } -int8_t I2cWriteBuffer(uint8_t addr, uint8_t reg, uint8_t *reg_data, uint16_t len) +int8_t I2cWriteBuffer(uint8_t addr, uint8_t reg, uint8_t *reg_data, uint16_t len, uint8_t bus = 0) { - Wire.beginTransmission((uint8_t)addr); - Wire.write((uint8_t)reg); +#ifdef ESP32 + if (!TasmotaGlobal.i2c_enabled_2) { bus = 0; } + TwoWire & myWire = (bus == 0) ? Wire : Wire1; +#else + if(0!=bus) {return false;} // second I2c bus ESP32 only + TwoWire & myWire = Wire; +#endif + myWire.beginTransmission((uint8_t)addr); + myWire.write((uint8_t)reg); while (len--) { - Wire.write(*reg_data); + myWire.write(*reg_data); reg_data++; } - Wire.endTransmission(); + myWire.endTransmission(); return 0; } -void I2cScan(uint32_t bus = 0); -void I2cScan(uint32_t bus) { +void I2cScan(uint8_t bus = 0) +{ // Return error codes defined in twi.h and core_esp8266_si2c.c // I2C_OK 0 // I2C_SCL_HELD_LOW 1 = SCL held low by another device, no procedure available to recover @@ -2415,17 +2411,22 @@ void I2cScan(uint32_t bus) { if (!TasmotaGlobal.i2c_enabled_2) { bus = 0; } TwoWire & myWire = (bus == 0) ? Wire : Wire1; #else + if(0!=bus) {return;} // second I2c bus ESP32 only TwoWire & myWire = Wire; #endif myWire.beginTransmission(address); error = myWire.endTransmission(); if (0 == error) { any = 1; +#ifdef ESP32 + ResponseAppend_P(PSTR(" 0x%02x:%d"), address, bus); +#else ResponseAppend_P(PSTR(" 0x%02x"), address); +#endif } else if (error != 2) { // Seems to happen anyway using this scan any = 2; - Response_P(PSTR("{\"" D_CMND_I2CSCAN "\":\"Error %d at 0x%02x"), error, address); + Response_P(PSTR("{\"" D_CMND_I2CSCAN "\":\"Error %d at 0x%02x bus %d"), error, address, bus); break; } } @@ -2437,31 +2438,55 @@ void I2cScan(uint32_t bus) { } } -void I2cResetActive(uint32_t addr, uint32_t count = 1) +void I2cResetActive(uint32_t addr, uint32_t count = 1, uint8_t bus = 0) { addr &= 0x7F; // Max I2C address is 127 count &= 0x7F; // Max 4 x 32 bits available - while (count-- && (addr < 128)) { - i2c_active[addr / 32] &= ~(1 << (addr % 32)); + while (count-- && (addr < 128)) + { +#ifdef ESP32 + if(0==bus) + { +#endif + i2c_active[addr / 32] &= ~(1 << (addr % 32)); +#ifdef ESP32 + } + else + { + i2c_active_bus2[addr / 32] &= ~(1 << (addr % 32)); + } +#endif addr++; } // AddLog(LOG_LEVEL_DEBUG, PSTR("I2C: Active %08X,%08X,%08X,%08X"), i2c_active[0], i2c_active[1], i2c_active[2], i2c_active[3]); } -void I2cSetActive(uint32_t addr, uint32_t count = 1) +void I2cSetActive(uint32_t addr, uint32_t count = 1, uint8_t bus = 0) { addr &= 0x7F; // Max I2C address is 127 count &= 0x7F; // Max 4 x 32 bits available - while (count-- && (addr < 128)) { - i2c_active[addr / 32] |= (1 << (addr % 32)); + while (count-- && (addr < 128)) + { +#ifdef ESP32 + if(0==bus) + { +#endif + i2c_active[addr / 32] |= (1 << (addr % 32)); +#ifdef ESP32 + } + else + { + i2c_active_bus2[addr / 32] |= (1 << (addr % 32)); + } +#endif addr++; } // AddLog(LOG_LEVEL_DEBUG, PSTR("I2C: Active %08X,%08X,%08X,%08X"), i2c_active[0], i2c_active[1], i2c_active[2], i2c_active[3]); } -void I2cSetActiveFound(uint32_t addr, const char *types, uint32_t bus = 0); -void I2cSetActiveFound(uint32_t addr, const char *types, uint32_t bus) { - I2cSetActive(addr); +void I2cSetActiveFound(uint32_t addr, const char *types, uint8_t bus = 0) +{ + I2cSetActive(addr,bus); #ifdef ESP32 if (0 == bus) { AddLog(LOG_LEVEL_INFO, S_LOG_I2C_FOUND_AT, types, addr); @@ -2472,18 +2497,30 @@ void I2cSetActiveFound(uint32_t addr, const char *types, uint32_t bus) { AddLog(LOG_LEVEL_INFO, S_LOG_I2C_FOUND_AT, types, addr); #endif // ESP32 } - -bool I2cActive(uint32_t addr) +bool I2cActive(uint32_t addr, uint8_t bus = 0) { +#ifdef ESP32 + if(0==bus) + { +#endif + addr &= 0x7F; // Max I2C address is 127 + if (i2c_active[addr / 32] & (1 << (addr % 32))) { + return true; + } + return false; +#ifdef ESP32 + } + // else addr &= 0x7F; // Max I2C address is 127 - if (i2c_active[addr / 32] & (1 << (addr % 32))) { + if (i2c_active_bus2[addr / 32] & (1 << (addr % 32))) { return true; } return false; +#endif } -bool I2cSetDevice(uint32_t addr, uint32_t bus = 0); -bool I2cSetDevice(uint32_t addr, uint32_t bus) { +bool I2cSetDevice(uint32_t addr, uint8_t bus = 0) +{ #ifdef ESP32 if (!TasmotaGlobal.i2c_enabled_2) { bus = 0; } TwoWire & myWire = (bus == 0) ? Wire : Wire1; @@ -2491,14 +2528,18 @@ bool I2cSetDevice(uint32_t addr, uint32_t bus) { TwoWire & myWire = Wire; #endif addr &= 0x7F; // Max I2C address is 127 - if (I2cActive(addr)) { + if (I2cActive(addr,bus)) { return false; // If already active report as not present; } myWire.beginTransmission((uint8_t)addr); // return (0 == myWire.endTransmission()); uint32_t err = myWire.endTransmission(); if (err && (err != 2)) { +#ifdef ESP32 + AddLog(LOG_LEVEL_DEBUG, PSTR("I2C: Error %d at 0x%02x bus &d"), err, addr,bus); +#else AddLog(LOG_LEVEL_DEBUG, PSTR("I2C: Error %d at 0x%02x"), err, addr); +#endif } return (0 == err); } diff --git a/tasmota/tasmota_xsns_sensor/xsns_09_bmp.ino b/tasmota/tasmota_xsns_sensor/xsns_09_bmp.ino index 503b8ff3e..adeda6696 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_09_bmp.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_09_bmp.ino @@ -48,7 +48,11 @@ #define BMP_CMND_RESET 0xB6 // I2C Parameter for RESET to put BMP into reset state -#define BMP_MAX_SENSORS 2 +#ifdef ESP32 + #define BMP_MAX_SENSORS 4 +#else + #define BMP_MAX_SENSORS 2 +#endif const char kBmpTypes[] PROGMEM = "BMP180|BMP280|BME280|BME680"; @@ -66,7 +70,7 @@ typedef struct { float bmp_humidity; } bmp_sensors_t; -uint8_t bmp_addresses[] = { BMP_ADDR1, BMP_ADDR2 }; +uint8_t bmp_addresses[] = { BMP_ADDR1, BMP_ADDR2, BMP_ADDR1, BMP_ADDR2}; uint8_t bmp_count = 0; uint8_t bmp_once = 1; @@ -116,18 +120,17 @@ bool Bmp180Calibration(uint8_t bmp_idx) bmp180_cal_data = (bmp180_cal_data_t*)malloc(BMP_MAX_SENSORS * sizeof(bmp180_cal_data_t)); } if (!bmp180_cal_data) { return false; } - - bmp180_cal_data[bmp_idx].cal_ac1 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_AC1); - bmp180_cal_data[bmp_idx].cal_ac2 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_AC2); - bmp180_cal_data[bmp_idx].cal_ac3 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_AC3); - bmp180_cal_data[bmp_idx].cal_ac4 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_AC4); - bmp180_cal_data[bmp_idx].cal_ac5 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_AC5); - bmp180_cal_data[bmp_idx].cal_ac6 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_AC6); - bmp180_cal_data[bmp_idx].cal_b1 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_VB1); - bmp180_cal_data[bmp_idx].cal_b2 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_VB2); - bmp180_cal_data[bmp_idx].cal_mc = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_MC); - bmp180_cal_data[bmp_idx].cal_md = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_MD); - + uint8_t bus= (bmp_idx>=2) ? 1 : 0; // first two BMP's at bus 0, additional at bus 1 (ESP32 32 only) + bmp180_cal_data[bmp_idx].cal_ac1 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_AC1,bus); + bmp180_cal_data[bmp_idx].cal_ac2 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_AC2,bus); + bmp180_cal_data[bmp_idx].cal_ac3 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_AC3,bus); + bmp180_cal_data[bmp_idx].cal_ac4 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_AC4,bus); + bmp180_cal_data[bmp_idx].cal_ac5 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_AC5,bus); + bmp180_cal_data[bmp_idx].cal_ac6 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_AC6,bus); + bmp180_cal_data[bmp_idx].cal_b1 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_VB1,bus); + bmp180_cal_data[bmp_idx].cal_b2 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_VB2,bus); + bmp180_cal_data[bmp_idx].cal_mc = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_MC,bus); + bmp180_cal_data[bmp_idx].cal_md = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_MD,bus); // Check for Errors in calibration data. Value never is 0x0000 or 0xFFFF if (!bmp180_cal_data[bmp_idx].cal_ac1 | !bmp180_cal_data[bmp_idx].cal_ac2 | @@ -160,18 +163,30 @@ bool Bmp180Calibration(uint8_t bmp_idx) void Bmp180Read(uint8_t bmp_idx) { if (!bmp180_cal_data) { return; } - +#ifdef ESP32 + uint8_t bus= (bmp_idx>=2) ? 1 : 0; // first two BMP's at bus 0, additional at bus 1 + I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BMP180_REG_CONTROL, BMP180_TEMPERATURE,bus); + delay(5); // 5ms conversion time + int ut = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_REG_RESULT,bus); +#else I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BMP180_REG_CONTROL, BMP180_TEMPERATURE); delay(5); // 5ms conversion time int ut = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_REG_RESULT); +#endif int32_t xt1 = (ut - (int32_t)bmp180_cal_data[bmp_idx].cal_ac6) * ((int32_t)bmp180_cal_data[bmp_idx].cal_ac5) >> 15; int32_t xt2 = ((int32_t)bmp180_cal_data[bmp_idx].cal_mc << 11) / (xt1 + (int32_t)bmp180_cal_data[bmp_idx].cal_md); int32_t bmp180_b5 = xt1 + xt2; bmp_sensors[bmp_idx].bmp_temperature = ((bmp180_b5 + 8) >> 4) / 10.0f; +#ifdef ESP32 + I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BMP180_REG_CONTROL, BMP180_PRESSURE3,bus); // Highest resolution + delay(2 + (4 << BMP180_OSS)); // 26ms conversion time at ultra high resolution + uint32_t up = I2cRead24(bmp_sensors[bmp_idx].bmp_address, BMP180_REG_RESULT,bus); +#else I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BMP180_REG_CONTROL, BMP180_PRESSURE3); // Highest resolution delay(2 + (4 << BMP180_OSS)); // 26ms conversion time at ultra high resolution uint32_t up = I2cRead24(bmp_sensors[bmp_idx].bmp_address, BMP180_REG_RESULT); +#endif up >>= (8 - BMP180_OSS); int32_t b6 = bmp180_b5 - 4000; @@ -264,34 +279,34 @@ bool Bmx280Calibrate(uint8_t bmp_idx) } if (!Bme280CalibrationData) { return false; } - Bme280CalibrationData[bmp_idx].dig_T1 = I2cRead16LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_T1); - Bme280CalibrationData[bmp_idx].dig_T2 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_T2); - Bme280CalibrationData[bmp_idx].dig_T3 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_T3); - Bme280CalibrationData[bmp_idx].dig_P1 = I2cRead16LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P1); - Bme280CalibrationData[bmp_idx].dig_P2 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P2); - Bme280CalibrationData[bmp_idx].dig_P3 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P3); - Bme280CalibrationData[bmp_idx].dig_P4 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P4); - Bme280CalibrationData[bmp_idx].dig_P5 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P5); - Bme280CalibrationData[bmp_idx].dig_P6 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P6); - Bme280CalibrationData[bmp_idx].dig_P7 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P7); - Bme280CalibrationData[bmp_idx].dig_P8 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P8); - Bme280CalibrationData[bmp_idx].dig_P9 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P9); + uint8_t bus= (bmp_idx>=2) ? 1 : 0; // first two BMP's at bus 0, additional at bus 1 (ESP32 32 only) + Bme280CalibrationData[bmp_idx].dig_T1 = I2cRead16LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_T1,bus); + Bme280CalibrationData[bmp_idx].dig_T2 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_T2,bus); + Bme280CalibrationData[bmp_idx].dig_T3 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_T3,bus); + Bme280CalibrationData[bmp_idx].dig_P1 = I2cRead16LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P1,bus); + Bme280CalibrationData[bmp_idx].dig_P2 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P2,bus); + Bme280CalibrationData[bmp_idx].dig_P3 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P3,bus); + Bme280CalibrationData[bmp_idx].dig_P4 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P4,bus); + Bme280CalibrationData[bmp_idx].dig_P5 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P5,bus); + Bme280CalibrationData[bmp_idx].dig_P6 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P6,bus); + Bme280CalibrationData[bmp_idx].dig_P7 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P7,bus); + Bme280CalibrationData[bmp_idx].dig_P8 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P8,bus); + Bme280CalibrationData[bmp_idx].dig_P9 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P9,bus); if (BME280_CHIPID == bmp_sensors[bmp_idx].bmp_type) { // #1051 - Bme280CalibrationData[bmp_idx].dig_H1 = I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H1); - Bme280CalibrationData[bmp_idx].dig_H2 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H2); - Bme280CalibrationData[bmp_idx].dig_H3 = I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H3); - Bme280CalibrationData[bmp_idx].dig_H4 = (I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H4) << 4) | (I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H4 + 1) & 0xF); - Bme280CalibrationData[bmp_idx].dig_H5 = (I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H5 + 1) << 4) | (I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H5) >> 4); - Bme280CalibrationData[bmp_idx].dig_H6 = (int8_t)I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H6); - I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONTROL, 0x00); // sleep mode since writes to config can be ignored in normal mode (Datasheet 5.4.5/6 page 27) + Bme280CalibrationData[bmp_idx].dig_H1 = I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H1,bus); + Bme280CalibrationData[bmp_idx].dig_H2 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H2,bus); + Bme280CalibrationData[bmp_idx].dig_H3 = I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H3,bus); + Bme280CalibrationData[bmp_idx].dig_H4 = (I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H4,bus) << 4) | (I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H4 + 1,bus) & 0xF); + Bme280CalibrationData[bmp_idx].dig_H5 = (I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H5 + 1,bus) << 4) | (I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H5,bus>>1) >> 4); + Bme280CalibrationData[bmp_idx].dig_H6 = (int8_t)I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H6,bus); + I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONTROL, 0x00,bus); // sleep mode since writes to config can be ignored in normal mode (Datasheet 5.4.5/6 page 27) // Set before CONTROL_meas (DS 5.4.3) - I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONTROLHUMID, 0x01); // 1x oversampling - I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONFIG, 0xA0); // 1sec standby between measurements (to limit self heating), IIR filter off - I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONTROL, 0x27); // 1x oversampling, normal mode + I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONTROLHUMID, 0x01,bus); // 1x oversampling + I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONFIG, 0xA0,bus); // 1sec standby between measurements (to limit self heating), IIR filter off + I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONTROL, 0x27,bus); // 1x oversampling, normal mode } else { - I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONTROL, 0xB7); // 16x oversampling, normal mode (Adafruit) + I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONTROL, 0xB7,bus); // 16x oversampling, normal mode (Adafruit) } - return true; } @@ -299,7 +314,11 @@ void Bme280Read(uint8_t bmp_idx) { if (!Bme280CalibrationData) { return; } +#ifdef ESP32 + int32_t adc_T = I2cRead24(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_TEMPDATA,bmp_idx>>1); +#else int32_t adc_T = I2cRead24(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_TEMPDATA); +#endif adc_T >>= 4; int32_t vart1 = ((((adc_T >> 3) - ((int32_t)Bme280CalibrationData[bmp_idx].dig_T1 << 1))) * ((int32_t)Bme280CalibrationData[bmp_idx].dig_T2)) >> 11; @@ -308,8 +327,11 @@ void Bme280Read(uint8_t bmp_idx) int32_t t_fine = vart1 + vart2; float T = (t_fine * 5 + 128) >> 8; bmp_sensors[bmp_idx].bmp_temperature = T / 100.0f; - +#ifdef ESP32 + int32_t adc_P = I2cRead24(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_PRESSUREDATA,bmp_idx>>1); +#else int32_t adc_P = I2cRead24(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_PRESSUREDATA); +#endif adc_P >>= 4; int64_t var1 = ((int64_t)t_fine) - 128000; @@ -329,9 +351,11 @@ void Bme280Read(uint8_t bmp_idx) bmp_sensors[bmp_idx].bmp_pressure = (float)p / 25600.0f; if (BMP280_CHIPID == bmp_sensors[bmp_idx].bmp_type) { return; } - +#ifdef ESP32 + int32_t adc_H = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_HUMIDDATA,bmp_idx>>1); +#else int32_t adc_H = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_HUMIDDATA); - +#endif int32_t v_x1_u32r = (t_fine - ((int32_t)76800)); v_x1_u32r = (((((adc_H << 14) - (((int32_t)Bme280CalibrationData[bmp_idx].dig_H4) << 20) - (((int32_t)Bme280CalibrationData[bmp_idx].dig_H5) * v_x1_u32r)) + ((int32_t)16384)) >> 15) * @@ -362,12 +386,10 @@ struct bme68x_heatr_conf *bme_heatr_conf = nullptr; static void Bme68x_Delayus(uint32_t period, void *intf_ptr) { delayMicroseconds(period); } - int8_t Bme68x_i2c_read(uint8_t reg_addr, uint8_t *reg_data, uint32_t len, void *intf_ptr) { uint8_t dev_addr = *(uint8_t*)intf_ptr; return I2cReadBuffer(dev_addr, reg_addr, reg_data, (uint16_t)len); } - int8_t Bme68x_i2c_write(uint8_t reg_addr, const uint8_t *reg_data, uint32_t len, void *intf_ptr) { uint8_t dev_addr = *(uint8_t*)intf_ptr; return I2cWriteBuffer(dev_addr, reg_addr, (uint8_t *)reg_data, (uint16_t)len); @@ -475,14 +497,21 @@ void BmpDetect(void) if (!bmp_sensors) { return; } memset(bmp_sensors, 0, bmp_sensor_size); // Init defaults to 0 - for (uint32_t i = 0; i < BMP_MAX_SENSORS; i++) { + for (uint32_t i = 0; i < BMP_MAX_SENSORS; i++) + { +#ifdef ESP32 + uint8_t bmp_type =0; + uint8_t bus= (i>=2) ? 1 : 0; + if (!I2cSetDevice(bmp_addresses[i], bus)) { continue; } + bmp_type = I2cRead8(bmp_addresses[i], BMP_REGISTER_CHIPID, bus); +#else if (!I2cSetDevice(bmp_addresses[i])) { continue; } - uint8_t bmp_type = I2cRead8(bmp_addresses[i], BMP_REGISTER_CHIPID); + bmp_type = I2cRead8(bmp_addresses[i], BMP_REGISTER_CHIPID)); +#endif if (bmp_type) { bmp_sensors[bmp_count].bmp_address = bmp_addresses[i]; bmp_sensors[bmp_count].bmp_type = bmp_type; bmp_sensors[bmp_count].bmp_model = 0; - bool success = false; switch (bmp_type) { case BMP180_CHIPID: @@ -503,7 +532,11 @@ void BmpDetect(void) } if (success) { GetTextIndexed(bmp_sensors[bmp_count].bmp_name, sizeof(bmp_sensors[bmp_count].bmp_name), bmp_sensors[bmp_count].bmp_model, kBmpTypes); +#ifdef ESP32 + I2cSetActiveFound(bmp_sensors[bmp_count].bmp_address, bmp_sensors[bmp_count].bmp_name,bus); +#else I2cSetActiveFound(bmp_sensors[bmp_count].bmp_address, bmp_sensors[bmp_count].bmp_name); +#endif bmp_count++; } } @@ -537,12 +570,30 @@ void BmpShow(bool json) float bmp_sealevel = ConvertPressureForSeaLevel(bmp_sensors[bmp_idx].bmp_pressure); float bmp_temperature = ConvertTemp(bmp_sensors[bmp_idx].bmp_temperature); float bmp_pressure = ConvertPressure(bmp_sensors[bmp_idx].bmp_pressure); - +#ifdef ESP32 + char name[12]; + if (TasmotaGlobal.i2c_enabled_2) + { + strlcpy(name, bmp_sensors[bmp_idx].bmp_name, sizeof(bmp_sensors[bmp_idx].bmp_name)); + uint8_t bus= (bmp_idx>=2) ? 1 : 0; + if (bmp_count > 1) { + snprintf_P(name, sizeof(name), PSTR("%s%c%02X%c%1d"), name, IndexSeparator(), bmp_sensors[bmp_idx].bmp_address,IndexSeparator(),bus); // BMXXXX-XX-X + } + } + else + { + strlcpy(name, bmp_sensors[bmp_idx].bmp_name, sizeof(bmp_sensors[bmp_idx].bmp_name)); + if (bmp_count > 1) { + snprintf_P(name, sizeof(name), PSTR("%s%c%02X"), name, IndexSeparator(), bmp_sensors[bmp_idx].bmp_address); // BMXXXX-XX + } + } +#else char name[10]; strlcpy(name, bmp_sensors[bmp_idx].bmp_name, sizeof(name)); if (bmp_count > 1) { snprintf_P(name, sizeof(name), PSTR("%s%c%02X"), name, IndexSeparator(), bmp_sensors[bmp_idx].bmp_address); // BMXXXX-XX } +#endif char pressure[33]; dtostrfd(bmp_pressure, Settings->flag2.pressure_resolution, pressure); @@ -630,7 +681,12 @@ void BMP_EnterSleep(void) case BMP180_CHIPID: case BMP280_CHIPID: case BME280_CHIPID: +#ifdef ESP32 + uint8_t bus= (bmp_idx>=2) ? 1 : 0; + I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BMP_REGISTER_RESET, BMP_CMND_RESET,bus); +#else I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BMP_REGISTER_RESET, BMP_CMND_RESET); +#endif break; default: break; From 0781192c87e758bab8eba5f7e271a78fc41c8e8d Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 8 Jan 2023 16:04:58 +0100 Subject: [PATCH 116/262] Extract I2C support - Fix BMP compilation on ESP8266 --- tasmota/tasmota_support/support.ino | 374 ------------------- tasmota/tasmota_support/support_a_i2c.ino | 381 ++++++++++++++++++++ tasmota/tasmota_xsns_sensor/xsns_09_bmp.ino | 25 +- 3 files changed, 393 insertions(+), 387 deletions(-) create mode 100644 tasmota/tasmota_support/support_a_i2c.ino diff --git a/tasmota/tasmota_support/support.ino b/tasmota/tasmota_support/support.ino index 38d35d094..d978316d6 100755 --- a/tasmota/tasmota_support/support.ino +++ b/tasmota/tasmota_support/support.ino @@ -2171,380 +2171,6 @@ bool TimeReachedUsec(uint32_t timer) return (passed >= 0); } -/*********************************************************************************************\ - * Basic I2C routines -\*********************************************************************************************/ - -#ifdef USE_I2C -const uint8_t I2C_RETRY_COUNTER = 3; - -uint32_t i2c_active[4] = { 0 }; -#ifdef ESP32 -uint32_t i2c_active_bus2[4] = { 0 }; // ESP32 can have two I2C buses -#endif -uint32_t i2c_buffer = 0; - -bool I2cBegin(int sda, int scl, uint32_t frequency = 100000); -bool I2cBegin(int sda, int scl, uint32_t frequency) { - bool result = true; -#ifdef ESP8266 - Wire.begin(sda, scl); -#endif -#ifdef ESP32 -#if ESP_IDF_VERSION_MAJOR > 3 // Core 2.x uses a different I2C library - static bool reinit = false; - if (reinit) { Wire.end(); } -#endif // ESP_IDF_VERSION_MAJOR > 3 - result = Wire.begin(sda, scl, frequency); -#if ESP_IDF_VERSION_MAJOR > 3 // Core 2.x uses a different I2C library - reinit = result; -#endif // ESP_IDF_VERSION_MAJOR > 3 -#endif -// AddLog(LOG_LEVEL_DEBUG, PSTR("I2C: Bus1 %d"), result); - return result; -} - -#ifdef ESP32 -bool I2c2Begin(int sda, int scl, uint32_t frequency = 100000); -bool I2c2Begin(int sda, int scl, uint32_t frequency) { - bool result = Wire1.begin(sda, scl, frequency); -// AddLog(LOG_LEVEL_DEBUG, PSTR("I2C: Bus2 %d"), result); - return result; -} -#endif - -bool I2cValidRead(uint8_t addr, uint8_t reg, uint8_t size, uint8_t bus = 0) -{ - uint8_t retry = I2C_RETRY_COUNTER; - bool status = false; -#ifdef ESP32 - if (!TasmotaGlobal.i2c_enabled_2) { bus = 0; } - TwoWire & myWire = (bus == 0) ? Wire : Wire1; -#else - TwoWire & myWire = Wire; -#endif - - i2c_buffer = 0; - while (!status && retry) { - myWire.beginTransmission(addr); // start transmission to device - myWire.write(reg); // sends register address to read from - if (0 == myWire.endTransmission(false)) { // Try to become I2C Master, send data and collect bytes, keep master status for next request... - myWire.requestFrom((int)addr, (int)size); // send data n-bytes read - if (myWire.available() == size) { - for (uint32_t i = 0; i < size; i++) { - i2c_buffer = i2c_buffer << 8 | myWire.read(); // receive DATA - } - status = true; - } - } - retry--; - } - if (!retry) myWire.endTransmission(); - return status; -} - -bool I2cValidRead8(uint8_t *data, uint8_t addr, uint8_t reg, uint8_t bus = 0) -{ - bool status = I2cValidRead(addr, reg, 1,bus); - *data = (uint8_t)i2c_buffer; - return status; -} -bool I2cValidRead16(uint16_t *data, uint8_t addr, uint8_t reg, uint8_t bus = 0) -{ - bool status = I2cValidRead(addr, reg, 2,bus); - *data = (uint16_t)i2c_buffer; - return status; -} -bool I2cValidReadS16(int16_t *data, uint8_t addr, uint8_t reg, uint8_t bus = 0) -{ - bool status = I2cValidRead(addr, reg, 2, bus); - *data = (int16_t)i2c_buffer; - return status; -} -bool I2cValidRead16LE(uint16_t *data, uint8_t addr, uint8_t reg, uint8_t bus = 0) -{ - uint16_t ldata; - bool status = I2cValidRead16(&ldata, addr, reg, bus); - *data = (ldata >> 8) | (ldata << 8); - return status; -} -bool I2cValidReadS16_LE(int16_t *data, uint8_t addr, uint8_t reg, uint8_t bus = 0) -{ - uint16_t ldata; - bool status = I2cValidRead16LE(&ldata, addr, reg, bus); - *data = (int16_t)ldata; - return status; -} -bool I2cValidRead24(int32_t *data, uint8_t addr, uint8_t reg, uint8_t bus = 0) -{ - bool status = I2cValidRead(addr, reg, 3, bus); - *data = i2c_buffer; - return status; -} -uint8_t I2cRead8(uint8_t addr, uint8_t reg, uint8_t bus = 0) -{ - I2cValidRead(addr, reg, 1, bus); - return (uint8_t)i2c_buffer; -} -uint16_t I2cRead16(uint8_t addr, uint8_t reg, uint8_t bus = 0) -{ - I2cValidRead(addr, reg, 2, bus); - return (uint16_t)i2c_buffer; -} -int16_t I2cReadS16(uint8_t addr, uint8_t reg, uint8_t bus = 0) -{ - I2cValidRead(addr, reg, 2, bus); - return (int16_t)i2c_buffer; -} -uint16_t I2cRead16LE(uint8_t addr, uint8_t reg, uint8_t bus = 0) -{ - I2cValidRead(addr, reg, 2, bus); - uint16_t temp = (uint16_t)i2c_buffer; - return (temp >> 8) | (temp << 8); -} -int16_t I2cReadS16_LE(uint8_t addr, uint8_t reg, uint8_t bus = 0) -{ - return (int16_t)I2cRead16LE(addr, reg, bus); -} -int32_t I2cRead24(uint8_t addr, uint8_t reg, uint8_t bus = 0) -{ - I2cValidRead(addr, reg, 3, bus); - return i2c_buffer; -} - -bool I2cWrite(uint8_t addr, uint8_t reg, uint32_t val, uint8_t size, uint8_t bus = 0) -{ - uint8_t x = I2C_RETRY_COUNTER; -#ifdef ESP32 - if (!TasmotaGlobal.i2c_enabled_2) { bus = 0; } - TwoWire & myWire = (bus == 0) ? Wire : Wire1; -#else - if(0!=bus) {return false;} // second I2c bus ESP32 only - TwoWire & myWire = Wire; -#endif - do { - myWire.beginTransmission((uint8_t)addr); // start transmission to device - myWire.write(reg); // sends register address to write to - uint8_t bytes = size; - while (bytes--) { - myWire.write((val >> (8 * bytes)) & 0xFF); // write data - } - x--; - } while (myWire.endTransmission(true) != 0 && x != 0); // end transmission - return (x); -} -bool I2cWrite8(uint8_t addr, uint8_t reg, uint32_t val, uint8_t bus = 0) -{ - return I2cWrite(addr, reg, val, 1,bus); -} - -bool I2cWrite16(uint8_t addr, uint8_t reg, uint32_t val, uint8_t bus = 0) -{ - return I2cWrite(addr, reg, val, 2,bus); -} - -bool I2cReadBuffer(uint8_t addr, uint8_t reg, uint8_t *reg_data, uint16_t len, uint8_t bus = 0) -{ -#ifdef ESP32 - if (!TasmotaGlobal.i2c_enabled_2) { bus = 0; } - TwoWire & myWire = (bus == 0) ? Wire : Wire1; -#else - if(0!=bus) {return false;} // second I2c bus ESP32 only - TwoWire & myWire = Wire; -#endif - myWire.beginTransmission((uint8_t)addr); - myWire.write((uint8_t)reg); - myWire.endTransmission(); - if (len != myWire.requestFrom((uint8_t)addr, (uint8_t)len)) { - return 1; - } - while (len--) { - *reg_data = (uint8_t)myWire.read(); - reg_data++; - } - return 0; -} - -int8_t I2cWriteBuffer(uint8_t addr, uint8_t reg, uint8_t *reg_data, uint16_t len, uint8_t bus = 0) -{ -#ifdef ESP32 - if (!TasmotaGlobal.i2c_enabled_2) { bus = 0; } - TwoWire & myWire = (bus == 0) ? Wire : Wire1; -#else - if(0!=bus) {return false;} // second I2c bus ESP32 only - TwoWire & myWire = Wire; -#endif - myWire.beginTransmission((uint8_t)addr); - myWire.write((uint8_t)reg); - while (len--) { - myWire.write(*reg_data); - reg_data++; - } - myWire.endTransmission(); - return 0; -} - -void I2cScan(uint8_t bus = 0) -{ - // Return error codes defined in twi.h and core_esp8266_si2c.c - // I2C_OK 0 - // I2C_SCL_HELD_LOW 1 = SCL held low by another device, no procedure available to recover - // I2C_SCL_HELD_LOW_AFTER_READ 2 = I2C bus error. SCL held low beyond client clock stretch time - // I2C_SDA_HELD_LOW 3 = I2C bus error. SDA line held low by client/another_master after n bits - // I2C_SDA_HELD_LOW_AFTER_INIT 4 = line busy. SDA again held low by another device. 2nd master? - // 5 = bus busy. Timeout - // https://www.arduino.cc/reference/en/language/functions/communication/wire/endtransmission/ - // 0: success - // 1: data too long to fit in transmit buffer - // 2: received NACK on transmit of address - // 3: received NACK on transmit of data - // 4: other error - // 5: timeout - - uint8_t error = 0; - uint8_t address = 0; - uint8_t any = 0; - - Response_P(PSTR("{\"" D_CMND_I2CSCAN "\":\"" D_JSON_I2CSCAN_DEVICES_FOUND_AT)); - for (address = 1; address <= 127; address++) { -#ifdef ESP32 - if (!TasmotaGlobal.i2c_enabled_2) { bus = 0; } - TwoWire & myWire = (bus == 0) ? Wire : Wire1; -#else - if(0!=bus) {return;} // second I2c bus ESP32 only - TwoWire & myWire = Wire; -#endif - myWire.beginTransmission(address); - error = myWire.endTransmission(); - if (0 == error) { - any = 1; -#ifdef ESP32 - ResponseAppend_P(PSTR(" 0x%02x:%d"), address, bus); -#else - ResponseAppend_P(PSTR(" 0x%02x"), address); -#endif - } - else if (error != 2) { // Seems to happen anyway using this scan - any = 2; - Response_P(PSTR("{\"" D_CMND_I2CSCAN "\":\"Error %d at 0x%02x bus %d"), error, address, bus); - break; - } - } - if (any) { - ResponseAppend_P(PSTR("\"}")); - } - else { - Response_P(PSTR("{\"" D_CMND_I2CSCAN "\":\"" D_JSON_I2CSCAN_NO_DEVICES_FOUND "\"}")); - } -} - -void I2cResetActive(uint32_t addr, uint32_t count = 1, uint8_t bus = 0) -{ - addr &= 0x7F; // Max I2C address is 127 - count &= 0x7F; // Max 4 x 32 bits available - while (count-- && (addr < 128)) - { -#ifdef ESP32 - if(0==bus) - { -#endif - i2c_active[addr / 32] &= ~(1 << (addr % 32)); -#ifdef ESP32 - } - else - { - i2c_active_bus2[addr / 32] &= ~(1 << (addr % 32)); - } -#endif - addr++; - } -// AddLog(LOG_LEVEL_DEBUG, PSTR("I2C: Active %08X,%08X,%08X,%08X"), i2c_active[0], i2c_active[1], i2c_active[2], i2c_active[3]); -} - -void I2cSetActive(uint32_t addr, uint32_t count = 1, uint8_t bus = 0) -{ - addr &= 0x7F; // Max I2C address is 127 - count &= 0x7F; // Max 4 x 32 bits available - while (count-- && (addr < 128)) - { -#ifdef ESP32 - if(0==bus) - { -#endif - i2c_active[addr / 32] |= (1 << (addr % 32)); -#ifdef ESP32 - } - else - { - i2c_active_bus2[addr / 32] |= (1 << (addr % 32)); - } -#endif - addr++; - } -// AddLog(LOG_LEVEL_DEBUG, PSTR("I2C: Active %08X,%08X,%08X,%08X"), i2c_active[0], i2c_active[1], i2c_active[2], i2c_active[3]); -} - -void I2cSetActiveFound(uint32_t addr, const char *types, uint8_t bus = 0) -{ - I2cSetActive(addr,bus); -#ifdef ESP32 - if (0 == bus) { - AddLog(LOG_LEVEL_INFO, S_LOG_I2C_FOUND_AT, types, addr); - } else { - AddLog(LOG_LEVEL_INFO, S_LOG_I2C_FOUND_AT_PORT, types, addr, bus); - } -#else - AddLog(LOG_LEVEL_INFO, S_LOG_I2C_FOUND_AT, types, addr); -#endif // ESP32 -} -bool I2cActive(uint32_t addr, uint8_t bus = 0) -{ -#ifdef ESP32 - if(0==bus) - { -#endif - addr &= 0x7F; // Max I2C address is 127 - if (i2c_active[addr / 32] & (1 << (addr % 32))) { - return true; - } - return false; -#ifdef ESP32 - } - // else - addr &= 0x7F; // Max I2C address is 127 - if (i2c_active_bus2[addr / 32] & (1 << (addr % 32))) { - return true; - } - return false; -#endif -} - -bool I2cSetDevice(uint32_t addr, uint8_t bus = 0) -{ -#ifdef ESP32 - if (!TasmotaGlobal.i2c_enabled_2) { bus = 0; } - TwoWire & myWire = (bus == 0) ? Wire : Wire1; -#else - TwoWire & myWire = Wire; -#endif - addr &= 0x7F; // Max I2C address is 127 - if (I2cActive(addr,bus)) { - return false; // If already active report as not present; - } - myWire.beginTransmission((uint8_t)addr); -// return (0 == myWire.endTransmission()); - uint32_t err = myWire.endTransmission(); - if (err && (err != 2)) { -#ifdef ESP32 - AddLog(LOG_LEVEL_DEBUG, PSTR("I2C: Error %d at 0x%02x bus &d"), err, addr,bus); -#else - AddLog(LOG_LEVEL_DEBUG, PSTR("I2C: Error %d at 0x%02x"), err, addr); -#endif - } - return (0 == err); -} -#endif // USE_I2C - /*********************************************************************************************\ * Syslog * diff --git a/tasmota/tasmota_support/support_a_i2c.ino b/tasmota/tasmota_support/support_a_i2c.ino new file mode 100644 index 000000000..e1c128592 --- /dev/null +++ b/tasmota/tasmota_support/support_a_i2c.ino @@ -0,0 +1,381 @@ +/* + support_a_i2c.ino - I2C support for Tasmota + + SPDX-FileCopyrightText: 2022 Theo Arends + + SPDX-License-Identifier: GPL-3.0-only +*/ + +#ifdef USE_I2C +/*********************************************************************************************\ + * Basic I2C routines +\*********************************************************************************************/ + +const uint8_t I2C_RETRY_COUNTER = 3; + +uint32_t i2c_active[4] = { 0 }; +#ifdef ESP32 +uint32_t i2c_active_bus2[4] = { 0 }; // ESP32 can have two I2C buses +#endif +uint32_t i2c_buffer = 0; + +bool I2cBegin(int sda, int scl, uint32_t frequency = 100000); +bool I2cBegin(int sda, int scl, uint32_t frequency) { + bool result = true; +#ifdef ESP8266 + Wire.begin(sda, scl); +#endif +#ifdef ESP32 +#if ESP_IDF_VERSION_MAJOR > 3 // Core 2.x uses a different I2C library + static bool reinit = false; + if (reinit) { Wire.end(); } +#endif // ESP_IDF_VERSION_MAJOR > 3 + result = Wire.begin(sda, scl, frequency); +#if ESP_IDF_VERSION_MAJOR > 3 // Core 2.x uses a different I2C library + reinit = result; +#endif // ESP_IDF_VERSION_MAJOR > 3 +#endif +// AddLog(LOG_LEVEL_DEBUG, PSTR("I2C: Bus1 %d"), result); + return result; +} + +#ifdef ESP32 +bool I2c2Begin(int sda, int scl, uint32_t frequency = 100000); +bool I2c2Begin(int sda, int scl, uint32_t frequency) { + bool result = Wire1.begin(sda, scl, frequency); +// AddLog(LOG_LEVEL_DEBUG, PSTR("I2C: Bus2 %d"), result); + return result; +} +#endif + +bool I2cValidRead(uint8_t addr, uint8_t reg, uint8_t size, uint8_t bus = 0) +{ + uint8_t retry = I2C_RETRY_COUNTER; + bool status = false; +#ifdef ESP32 + if (!TasmotaGlobal.i2c_enabled_2) { bus = 0; } + TwoWire & myWire = (bus == 0) ? Wire : Wire1; +#else + TwoWire & myWire = Wire; +#endif + + i2c_buffer = 0; + while (!status && retry) { + myWire.beginTransmission(addr); // start transmission to device + myWire.write(reg); // sends register address to read from + if (0 == myWire.endTransmission(false)) { // Try to become I2C Master, send data and collect bytes, keep master status for next request... + myWire.requestFrom((int)addr, (int)size); // send data n-bytes read + if (myWire.available() == size) { + for (uint32_t i = 0; i < size; i++) { + i2c_buffer = i2c_buffer << 8 | myWire.read(); // receive DATA + } + status = true; + } + } + retry--; + } + if (!retry) myWire.endTransmission(); + return status; +} + +bool I2cValidRead8(uint8_t *data, uint8_t addr, uint8_t reg, uint8_t bus = 0) +{ + bool status = I2cValidRead(addr, reg, 1,bus); + *data = (uint8_t)i2c_buffer; + return status; +} +bool I2cValidRead16(uint16_t *data, uint8_t addr, uint8_t reg, uint8_t bus = 0) +{ + bool status = I2cValidRead(addr, reg, 2,bus); + *data = (uint16_t)i2c_buffer; + return status; +} +bool I2cValidReadS16(int16_t *data, uint8_t addr, uint8_t reg, uint8_t bus = 0) +{ + bool status = I2cValidRead(addr, reg, 2, bus); + *data = (int16_t)i2c_buffer; + return status; +} +bool I2cValidRead16LE(uint16_t *data, uint8_t addr, uint8_t reg, uint8_t bus = 0) +{ + uint16_t ldata; + bool status = I2cValidRead16(&ldata, addr, reg, bus); + *data = (ldata >> 8) | (ldata << 8); + return status; +} +bool I2cValidReadS16_LE(int16_t *data, uint8_t addr, uint8_t reg, uint8_t bus = 0) +{ + uint16_t ldata; + bool status = I2cValidRead16LE(&ldata, addr, reg, bus); + *data = (int16_t)ldata; + return status; +} +bool I2cValidRead24(int32_t *data, uint8_t addr, uint8_t reg, uint8_t bus = 0) +{ + bool status = I2cValidRead(addr, reg, 3, bus); + *data = i2c_buffer; + return status; +} +uint8_t I2cRead8(uint8_t addr, uint8_t reg, uint8_t bus = 0) +{ + I2cValidRead(addr, reg, 1, bus); + return (uint8_t)i2c_buffer; +} +uint16_t I2cRead16(uint8_t addr, uint8_t reg, uint8_t bus = 0) +{ + I2cValidRead(addr, reg, 2, bus); + return (uint16_t)i2c_buffer; +} +int16_t I2cReadS16(uint8_t addr, uint8_t reg, uint8_t bus = 0) +{ + I2cValidRead(addr, reg, 2, bus); + return (int16_t)i2c_buffer; +} +uint16_t I2cRead16LE(uint8_t addr, uint8_t reg, uint8_t bus = 0) +{ + I2cValidRead(addr, reg, 2, bus); + uint16_t temp = (uint16_t)i2c_buffer; + return (temp >> 8) | (temp << 8); +} +int16_t I2cReadS16_LE(uint8_t addr, uint8_t reg, uint8_t bus = 0) +{ + return (int16_t)I2cRead16LE(addr, reg, bus); +} +int32_t I2cRead24(uint8_t addr, uint8_t reg, uint8_t bus = 0) +{ + I2cValidRead(addr, reg, 3, bus); + return i2c_buffer; +} + +bool I2cWrite(uint8_t addr, uint8_t reg, uint32_t val, uint8_t size, uint8_t bus = 0) +{ + uint8_t x = I2C_RETRY_COUNTER; +#ifdef ESP32 + if (!TasmotaGlobal.i2c_enabled_2) { bus = 0; } + TwoWire & myWire = (bus == 0) ? Wire : Wire1; +#else + if(0!=bus) {return false;} // second I2c bus ESP32 only + TwoWire & myWire = Wire; +#endif + do { + myWire.beginTransmission((uint8_t)addr); // start transmission to device + myWire.write(reg); // sends register address to write to + uint8_t bytes = size; + while (bytes--) { + myWire.write((val >> (8 * bytes)) & 0xFF); // write data + } + x--; + } while (myWire.endTransmission(true) != 0 && x != 0); // end transmission + return (x); +} +bool I2cWrite8(uint8_t addr, uint8_t reg, uint32_t val, uint8_t bus = 0) +{ + return I2cWrite(addr, reg, val, 1,bus); +} + +bool I2cWrite16(uint8_t addr, uint8_t reg, uint32_t val, uint8_t bus = 0) +{ + return I2cWrite(addr, reg, val, 2,bus); +} + +bool I2cReadBuffer(uint8_t addr, uint8_t reg, uint8_t *reg_data, uint16_t len, uint8_t bus = 0) +{ +#ifdef ESP32 + if (!TasmotaGlobal.i2c_enabled_2) { bus = 0; } + TwoWire & myWire = (bus == 0) ? Wire : Wire1; +#else + if(0!=bus) {return false;} // second I2c bus ESP32 only + TwoWire & myWire = Wire; +#endif + myWire.beginTransmission((uint8_t)addr); + myWire.write((uint8_t)reg); + myWire.endTransmission(); + if (len != myWire.requestFrom((uint8_t)addr, (uint8_t)len)) { + return 1; + } + while (len--) { + *reg_data = (uint8_t)myWire.read(); + reg_data++; + } + return 0; +} + +int8_t I2cWriteBuffer(uint8_t addr, uint8_t reg, uint8_t *reg_data, uint16_t len, uint8_t bus = 0) +{ +#ifdef ESP32 + if (!TasmotaGlobal.i2c_enabled_2) { bus = 0; } + TwoWire & myWire = (bus == 0) ? Wire : Wire1; +#else + if(0!=bus) {return false;} // second I2c bus ESP32 only + TwoWire & myWire = Wire; +#endif + myWire.beginTransmission((uint8_t)addr); + myWire.write((uint8_t)reg); + while (len--) { + myWire.write(*reg_data); + reg_data++; + } + myWire.endTransmission(); + return 0; +} + +void I2cScan(uint8_t bus = 0) +{ + // Return error codes defined in twi.h and core_esp8266_si2c.c + // I2C_OK 0 + // I2C_SCL_HELD_LOW 1 = SCL held low by another device, no procedure available to recover + // I2C_SCL_HELD_LOW_AFTER_READ 2 = I2C bus error. SCL held low beyond client clock stretch time + // I2C_SDA_HELD_LOW 3 = I2C bus error. SDA line held low by client/another_master after n bits + // I2C_SDA_HELD_LOW_AFTER_INIT 4 = line busy. SDA again held low by another device. 2nd master? + // 5 = bus busy. Timeout + // https://www.arduino.cc/reference/en/language/functions/communication/wire/endtransmission/ + // 0: success + // 1: data too long to fit in transmit buffer + // 2: received NACK on transmit of address + // 3: received NACK on transmit of data + // 4: other error + // 5: timeout + + uint8_t error = 0; + uint8_t address = 0; + uint8_t any = 0; + + Response_P(PSTR("{\"" D_CMND_I2CSCAN "\":\"" D_JSON_I2CSCAN_DEVICES_FOUND_AT)); + for (address = 1; address <= 127; address++) { +#ifdef ESP32 + if (!TasmotaGlobal.i2c_enabled_2) { bus = 0; } + TwoWire & myWire = (bus == 0) ? Wire : Wire1; +#else + if(0!=bus) {return;} // second I2c bus ESP32 only + TwoWire & myWire = Wire; +#endif + myWire.beginTransmission(address); + error = myWire.endTransmission(); + if (0 == error) { + any = 1; +#ifdef ESP32 + ResponseAppend_P(PSTR(" 0x%02x:%d"), address, bus); +#else + ResponseAppend_P(PSTR(" 0x%02x"), address); +#endif + } + else if (error != 2) { // Seems to happen anyway using this scan + any = 2; + Response_P(PSTR("{\"" D_CMND_I2CSCAN "\":\"Error %d at 0x%02x bus %d"), error, address, bus); + break; + } + } + if (any) { + ResponseAppend_P(PSTR("\"}")); + } + else { + Response_P(PSTR("{\"" D_CMND_I2CSCAN "\":\"" D_JSON_I2CSCAN_NO_DEVICES_FOUND "\"}")); + } +} + +void I2cResetActive(uint32_t addr, uint32_t count = 1, uint8_t bus = 0) +{ + addr &= 0x7F; // Max I2C address is 127 + count &= 0x7F; // Max 4 x 32 bits available + while (count-- && (addr < 128)) + { +#ifdef ESP32 + if(0==bus) + { +#endif + i2c_active[addr / 32] &= ~(1 << (addr % 32)); +#ifdef ESP32 + } + else + { + i2c_active_bus2[addr / 32] &= ~(1 << (addr % 32)); + } +#endif + addr++; + } +// AddLog(LOG_LEVEL_DEBUG, PSTR("I2C: Active %08X,%08X,%08X,%08X"), i2c_active[0], i2c_active[1], i2c_active[2], i2c_active[3]); +} + +void I2cSetActive(uint32_t addr, uint32_t count = 1, uint8_t bus = 0) +{ + addr &= 0x7F; // Max I2C address is 127 + count &= 0x7F; // Max 4 x 32 bits available + while (count-- && (addr < 128)) + { +#ifdef ESP32 + if(0==bus) + { +#endif + i2c_active[addr / 32] |= (1 << (addr % 32)); +#ifdef ESP32 + } + else + { + i2c_active_bus2[addr / 32] |= (1 << (addr % 32)); + } +#endif + addr++; + } +// AddLog(LOG_LEVEL_DEBUG, PSTR("I2C: Active %08X,%08X,%08X,%08X"), i2c_active[0], i2c_active[1], i2c_active[2], i2c_active[3]); +} + +void I2cSetActiveFound(uint32_t addr, const char *types, uint8_t bus = 0) +{ + I2cSetActive(addr,bus); +#ifdef ESP32 + if (0 == bus) { + AddLog(LOG_LEVEL_INFO, S_LOG_I2C_FOUND_AT, types, addr); + } else { + AddLog(LOG_LEVEL_INFO, S_LOG_I2C_FOUND_AT_PORT, types, addr, bus); + } +#else + AddLog(LOG_LEVEL_INFO, S_LOG_I2C_FOUND_AT, types, addr); +#endif // ESP32 +} +bool I2cActive(uint32_t addr, uint8_t bus = 0) +{ +#ifdef ESP32 + if(0==bus) + { +#endif + addr &= 0x7F; // Max I2C address is 127 + if (i2c_active[addr / 32] & (1 << (addr % 32))) { + return true; + } + return false; +#ifdef ESP32 + } + // else + addr &= 0x7F; // Max I2C address is 127 + if (i2c_active_bus2[addr / 32] & (1 << (addr % 32))) { + return true; + } + return false; +#endif +} + +bool I2cSetDevice(uint32_t addr, uint8_t bus = 0) +{ +#ifdef ESP32 + if (!TasmotaGlobal.i2c_enabled_2) { bus = 0; } + TwoWire & myWire = (bus == 0) ? Wire : Wire1; +#else + TwoWire & myWire = Wire; +#endif + addr &= 0x7F; // Max I2C address is 127 + if (I2cActive(addr,bus)) { + return false; // If already active report as not present; + } + myWire.beginTransmission((uint8_t)addr); +// return (0 == myWire.endTransmission()); + uint32_t err = myWire.endTransmission(); + if (err && (err != 2)) { +#ifdef ESP32 + AddLog(LOG_LEVEL_DEBUG, PSTR("I2C: Error %d at 0x%02x bus &d"), err, addr,bus); +#else + AddLog(LOG_LEVEL_DEBUG, PSTR("I2C: Error %d at 0x%02x"), err, addr); +#endif + } + return (0 == err); +} +#endif // USE_I2C \ No newline at end of file diff --git a/tasmota/tasmota_xsns_sensor/xsns_09_bmp.ino b/tasmota/tasmota_xsns_sensor/xsns_09_bmp.ino index adeda6696..3b55d4b88 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_09_bmp.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_09_bmp.ino @@ -168,7 +168,7 @@ void Bmp180Read(uint8_t bmp_idx) I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BMP180_REG_CONTROL, BMP180_TEMPERATURE,bus); delay(5); // 5ms conversion time int ut = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_REG_RESULT,bus); -#else +#else I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BMP180_REG_CONTROL, BMP180_TEMPERATURE); delay(5); // 5ms conversion time int ut = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_REG_RESULT); @@ -318,7 +318,7 @@ void Bme280Read(uint8_t bmp_idx) int32_t adc_T = I2cRead24(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_TEMPDATA,bmp_idx>>1); #else int32_t adc_T = I2cRead24(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_TEMPDATA); -#endif +#endif adc_T >>= 4; int32_t vart1 = ((((adc_T >> 3) - ((int32_t)Bme280CalibrationData[bmp_idx].dig_T1 << 1))) * ((int32_t)Bme280CalibrationData[bmp_idx].dig_T2)) >> 11; @@ -329,9 +329,9 @@ void Bme280Read(uint8_t bmp_idx) bmp_sensors[bmp_idx].bmp_temperature = T / 100.0f; #ifdef ESP32 int32_t adc_P = I2cRead24(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_PRESSUREDATA,bmp_idx>>1); -#else +#else int32_t adc_P = I2cRead24(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_PRESSUREDATA); -#endif +#endif adc_P >>= 4; int64_t var1 = ((int64_t)t_fine) - 128000; @@ -497,16 +497,15 @@ void BmpDetect(void) if (!bmp_sensors) { return; } memset(bmp_sensors, 0, bmp_sensor_size); // Init defaults to 0 - for (uint32_t i = 0; i < BMP_MAX_SENSORS; i++) - { + for (uint32_t i = 0; i < BMP_MAX_SENSORS; i++) { + uint8_t bmp_type = 0; #ifdef ESP32 - uint8_t bmp_type =0; - uint8_t bus= (i>=2) ? 1 : 0; + uint8_t bus = (i>=2) ? 1 : 0; if (!I2cSetDevice(bmp_addresses[i], bus)) { continue; } bmp_type = I2cRead8(bmp_addresses[i], BMP_REGISTER_CHIPID, bus); #else if (!I2cSetDevice(bmp_addresses[i])) { continue; } - bmp_type = I2cRead8(bmp_addresses[i], BMP_REGISTER_CHIPID)); + bmp_type = I2cRead8(bmp_addresses[i], BMP_REGISTER_CHIPID); #endif if (bmp_type) { bmp_sensors[bmp_count].bmp_address = bmp_addresses[i]; @@ -536,7 +535,7 @@ void BmpDetect(void) I2cSetActiveFound(bmp_sensors[bmp_count].bmp_address, bmp_sensors[bmp_count].bmp_name,bus); #else I2cSetActiveFound(bmp_sensors[bmp_count].bmp_address, bmp_sensors[bmp_count].bmp_name); -#endif +#endif bmp_count++; } } @@ -572,7 +571,7 @@ void BmpShow(bool json) float bmp_pressure = ConvertPressure(bmp_sensors[bmp_idx].bmp_pressure); #ifdef ESP32 char name[12]; - if (TasmotaGlobal.i2c_enabled_2) + if (TasmotaGlobal.i2c_enabled_2) { strlcpy(name, bmp_sensors[bmp_idx].bmp_name, sizeof(bmp_sensors[bmp_idx].bmp_name)); uint8_t bus= (bmp_idx>=2) ? 1 : 0; @@ -681,12 +680,12 @@ void BMP_EnterSleep(void) case BMP180_CHIPID: case BMP280_CHIPID: case BME280_CHIPID: -#ifdef ESP32 +#ifdef ESP32 uint8_t bus= (bmp_idx>=2) ? 1 : 0; I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BMP_REGISTER_RESET, BMP_CMND_RESET,bus); #else I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BMP_REGISTER_RESET, BMP_CMND_RESET); -#endif +#endif break; default: break; From 9073fe01c121f173a4ff90af98801c1968b2b394 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 8 Jan 2023 17:19:08 +0100 Subject: [PATCH 117/262] Add ESP32 support for BMPxxx sensors on two I2C busses Add ESP32 support for BMPxxx sensors on two I2C busses (#17643) --- CHANGELOG.md | 1 + RELEASENOTES.md | 1 + tasmota/tasmota_support/support_a_i2c.ino | 194 ++++++++------------ tasmota/tasmota_xsns_sensor/xsns_09_bmp.ino | 175 +++++++----------- 4 files changed, 136 insertions(+), 235 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2dcebb4ac..ed9962a35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ All notable changes to this project will be documented in this file. - Support for PCA9632 4-channel 8-bit PWM driver as light driver by Pascal Heinrich (#17557) - Berry `bytes()` now evaluates to `false` if empty - Berry ``crypto.AES_CCM`` (required by Matter protocol) +- ESP32 support for BMPxxx sensors on two I2C busses (#17643) ### Breaking Changed diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 7d1a23e47..8637d2ae9 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -119,6 +119,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm - Berry crypto add ``random`` to generate series of random bytes - Berry crypto add ``HKDF_HMAC_SHA256`` - Berry crypto add ``SPAKE2P_Matter`` for Matter support +- ESP32 support for BMPxxx sensors on two I2C busses [#17643](https://github.com/arendst/Tasmota/issues/17643) ### Breaking Changed diff --git a/tasmota/tasmota_support/support_a_i2c.ino b/tasmota/tasmota_support/support_a_i2c.ino index e1c128592..ebe9606c4 100644 --- a/tasmota/tasmota_support/support_a_i2c.ino +++ b/tasmota/tasmota_support/support_a_i2c.ino @@ -8,15 +8,12 @@ #ifdef USE_I2C /*********************************************************************************************\ - * Basic I2C routines + * Basic I2C routines supporting two busses \*********************************************************************************************/ const uint8_t I2C_RETRY_COUNTER = 3; -uint32_t i2c_active[4] = { 0 }; -#ifdef ESP32 -uint32_t i2c_active_bus2[4] = { 0 }; // ESP32 can have two I2C buses -#endif +uint32_t i2c_active[2][4] = { 0 }; uint32_t i2c_buffer = 0; bool I2cBegin(int sda, int scl, uint32_t frequency = 100000); @@ -48,8 +45,7 @@ bool I2c2Begin(int sda, int scl, uint32_t frequency) { } #endif -bool I2cValidRead(uint8_t addr, uint8_t reg, uint8_t size, uint8_t bus = 0) -{ +bool I2cValidRead(uint8_t addr, uint8_t reg, uint8_t size, uint8_t bus = 0) { uint8_t retry = I2C_RETRY_COUNTER; bool status = false; #ifdef ESP32 @@ -58,7 +54,6 @@ bool I2cValidRead(uint8_t addr, uint8_t reg, uint8_t size, uint8_t bus = 0) #else TwoWire & myWire = Wire; #endif - i2c_buffer = 0; while (!status && retry) { myWire.beginTransmission(addr); // start transmission to device @@ -78,83 +73,81 @@ bool I2cValidRead(uint8_t addr, uint8_t reg, uint8_t size, uint8_t bus = 0) return status; } -bool I2cValidRead8(uint8_t *data, uint8_t addr, uint8_t reg, uint8_t bus = 0) -{ - bool status = I2cValidRead(addr, reg, 1,bus); +bool I2cValidRead8(uint8_t *data, uint8_t addr, uint8_t reg, uint8_t bus = 0) { + bool status = I2cValidRead(addr, reg, 1, bus); *data = (uint8_t)i2c_buffer; return status; } -bool I2cValidRead16(uint16_t *data, uint8_t addr, uint8_t reg, uint8_t bus = 0) -{ - bool status = I2cValidRead(addr, reg, 2,bus); + +bool I2cValidRead16(uint16_t *data, uint8_t addr, uint8_t reg, uint8_t bus = 0) { + bool status = I2cValidRead(addr, reg, 2, bus); *data = (uint16_t)i2c_buffer; return status; } -bool I2cValidReadS16(int16_t *data, uint8_t addr, uint8_t reg, uint8_t bus = 0) -{ + +bool I2cValidReadS16(int16_t *data, uint8_t addr, uint8_t reg, uint8_t bus = 0) { bool status = I2cValidRead(addr, reg, 2, bus); *data = (int16_t)i2c_buffer; return status; } -bool I2cValidRead16LE(uint16_t *data, uint8_t addr, uint8_t reg, uint8_t bus = 0) -{ + +bool I2cValidRead16LE(uint16_t *data, uint8_t addr, uint8_t reg, uint8_t bus = 0) { uint16_t ldata; bool status = I2cValidRead16(&ldata, addr, reg, bus); *data = (ldata >> 8) | (ldata << 8); return status; } -bool I2cValidReadS16_LE(int16_t *data, uint8_t addr, uint8_t reg, uint8_t bus = 0) -{ + +bool I2cValidReadS16_LE(int16_t *data, uint8_t addr, uint8_t reg, uint8_t bus = 0) { uint16_t ldata; bool status = I2cValidRead16LE(&ldata, addr, reg, bus); *data = (int16_t)ldata; return status; } -bool I2cValidRead24(int32_t *data, uint8_t addr, uint8_t reg, uint8_t bus = 0) -{ + +bool I2cValidRead24(int32_t *data, uint8_t addr, uint8_t reg, uint8_t bus = 0) { bool status = I2cValidRead(addr, reg, 3, bus); *data = i2c_buffer; return status; } -uint8_t I2cRead8(uint8_t addr, uint8_t reg, uint8_t bus = 0) -{ + +uint8_t I2cRead8(uint8_t addr, uint8_t reg, uint8_t bus = 0) { I2cValidRead(addr, reg, 1, bus); return (uint8_t)i2c_buffer; } -uint16_t I2cRead16(uint8_t addr, uint8_t reg, uint8_t bus = 0) -{ + +uint16_t I2cRead16(uint8_t addr, uint8_t reg, uint8_t bus = 0) { I2cValidRead(addr, reg, 2, bus); return (uint16_t)i2c_buffer; } -int16_t I2cReadS16(uint8_t addr, uint8_t reg, uint8_t bus = 0) -{ + +int16_t I2cReadS16(uint8_t addr, uint8_t reg, uint8_t bus = 0) { I2cValidRead(addr, reg, 2, bus); return (int16_t)i2c_buffer; } -uint16_t I2cRead16LE(uint8_t addr, uint8_t reg, uint8_t bus = 0) -{ + +uint16_t I2cRead16LE(uint8_t addr, uint8_t reg, uint8_t bus = 0) { I2cValidRead(addr, reg, 2, bus); uint16_t temp = (uint16_t)i2c_buffer; return (temp >> 8) | (temp << 8); } -int16_t I2cReadS16_LE(uint8_t addr, uint8_t reg, uint8_t bus = 0) -{ + +int16_t I2cReadS16_LE(uint8_t addr, uint8_t reg, uint8_t bus = 0) { return (int16_t)I2cRead16LE(addr, reg, bus); } -int32_t I2cRead24(uint8_t addr, uint8_t reg, uint8_t bus = 0) -{ + +int32_t I2cRead24(uint8_t addr, uint8_t reg, uint8_t bus = 0) { I2cValidRead(addr, reg, 3, bus); return i2c_buffer; } -bool I2cWrite(uint8_t addr, uint8_t reg, uint32_t val, uint8_t size, uint8_t bus = 0) -{ +bool I2cWrite(uint8_t addr, uint8_t reg, uint32_t val, uint8_t size, uint8_t bus = 0) { uint8_t x = I2C_RETRY_COUNTER; #ifdef ESP32 if (!TasmotaGlobal.i2c_enabled_2) { bus = 0; } TwoWire & myWire = (bus == 0) ? Wire : Wire1; #else - if(0!=bus) {return false;} // second I2c bus ESP32 only + if (bus != 0) { return false; } // Second I2c bus ESP32 only TwoWire & myWire = Wire; #endif do { @@ -168,23 +161,21 @@ bool I2cWrite(uint8_t addr, uint8_t reg, uint32_t val, uint8_t size, uint8_t bus } while (myWire.endTransmission(true) != 0 && x != 0); // end transmission return (x); } -bool I2cWrite8(uint8_t addr, uint8_t reg, uint32_t val, uint8_t bus = 0) -{ - return I2cWrite(addr, reg, val, 1,bus); + +bool I2cWrite8(uint8_t addr, uint8_t reg, uint32_t val, uint8_t bus = 0) { + return I2cWrite(addr, reg, val, 1, bus); } -bool I2cWrite16(uint8_t addr, uint8_t reg, uint32_t val, uint8_t bus = 0) -{ - return I2cWrite(addr, reg, val, 2,bus); +bool I2cWrite16(uint8_t addr, uint8_t reg, uint32_t val, uint8_t bus = 0) { + return I2cWrite(addr, reg, val, 2, bus); } -bool I2cReadBuffer(uint8_t addr, uint8_t reg, uint8_t *reg_data, uint16_t len, uint8_t bus = 0) -{ +bool I2cReadBuffer(uint8_t addr, uint8_t reg, uint8_t *reg_data, uint16_t len, uint8_t bus = 0) { #ifdef ESP32 if (!TasmotaGlobal.i2c_enabled_2) { bus = 0; } TwoWire & myWire = (bus == 0) ? Wire : Wire1; #else - if(0!=bus) {return false;} // second I2c bus ESP32 only + if (bus != 0) { return false; } // Second I2c bus ESP32 only TwoWire & myWire = Wire; #endif myWire.beginTransmission((uint8_t)addr); @@ -200,13 +191,12 @@ bool I2cReadBuffer(uint8_t addr, uint8_t reg, uint8_t *reg_data, uint16_t len, u return 0; } -int8_t I2cWriteBuffer(uint8_t addr, uint8_t reg, uint8_t *reg_data, uint16_t len, uint8_t bus = 0) -{ +int8_t I2cWriteBuffer(uint8_t addr, uint8_t reg, uint8_t *reg_data, uint16_t len, uint8_t bus = 0) { #ifdef ESP32 if (!TasmotaGlobal.i2c_enabled_2) { bus = 0; } TwoWire & myWire = (bus == 0) ? Wire : Wire1; #else - if(0!=bus) {return false;} // second I2c bus ESP32 only + if (bus != 0) { return false; } // Second I2c bus ESP32 only TwoWire & myWire = Wire; #endif myWire.beginTransmission((uint8_t)addr); @@ -219,8 +209,7 @@ int8_t I2cWriteBuffer(uint8_t addr, uint8_t reg, uint8_t *reg_data, uint16_t len return 0; } -void I2cScan(uint8_t bus = 0) -{ +void I2cScan(uint8_t bus = 0) { // Return error codes defined in twi.h and core_esp8266_si2c.c // I2C_OK 0 // I2C_SCL_HELD_LOW 1 = SCL held low by another device, no procedure available to recover @@ -246,7 +235,7 @@ void I2cScan(uint8_t bus = 0) if (!TasmotaGlobal.i2c_enabled_2) { bus = 0; } TwoWire & myWire = (bus == 0) ? Wire : Wire1; #else - if(0!=bus) {return;} // second I2c bus ESP32 only + if (bus != 0) { return; } // Second I2c bus ESP32 only TwoWire & myWire = Wire; #endif myWire.beginTransmission(address); @@ -267,95 +256,56 @@ void I2cScan(uint8_t bus = 0) } if (any) { ResponseAppend_P(PSTR("\"}")); - } - else { + } else { Response_P(PSTR("{\"" D_CMND_I2CSCAN "\":\"" D_JSON_I2CSCAN_NO_DEVICES_FOUND "\"}")); } } -void I2cResetActive(uint32_t addr, uint32_t count = 1, uint8_t bus = 0) -{ +void I2cResetActive(uint32_t addr, uint32_t count = 1, uint8_t bus = 0) { +#ifdef ESP8266 + bus = 0; +#endif addr &= 0x7F; // Max I2C address is 127 count &= 0x7F; // Max 4 x 32 bits available - while (count-- && (addr < 128)) - { -#ifdef ESP32 - if(0==bus) - { -#endif - i2c_active[addr / 32] &= ~(1 << (addr % 32)); -#ifdef ESP32 - } - else - { - i2c_active_bus2[addr / 32] &= ~(1 << (addr % 32)); - } -#endif + while (count-- && (addr < 128)) { + i2c_active[bus][addr / 32] &= ~(1 << (addr % 32)); addr++; } -// AddLog(LOG_LEVEL_DEBUG, PSTR("I2C: Active %08X,%08X,%08X,%08X"), i2c_active[0], i2c_active[1], i2c_active[2], i2c_active[3]); +// AddLog(LOG_LEVEL_DEBUG, PSTR("I2C: Active %08X,%08X,%08X,%08X"), i2c_active[bus][0], i2c_active[bus][1], i2c_active[bus][2], i2c_active[bus][3]); } -void I2cSetActive(uint32_t addr, uint32_t count = 1, uint8_t bus = 0) -{ +void I2cSetActive(uint32_t addr, uint32_t count = 1, uint8_t bus = 0) { +#ifdef ESP8266 + bus = 0; +#endif addr &= 0x7F; // Max I2C address is 127 count &= 0x7F; // Max 4 x 32 bits available - while (count-- && (addr < 128)) - { -#ifdef ESP32 - if(0==bus) - { -#endif - i2c_active[addr / 32] |= (1 << (addr % 32)); -#ifdef ESP32 - } - else - { - i2c_active_bus2[addr / 32] |= (1 << (addr % 32)); - } -#endif + while (count-- && (addr < 128)) { + i2c_active[bus][addr / 32] |= (1 << (addr % 32)); addr++; } -// AddLog(LOG_LEVEL_DEBUG, PSTR("I2C: Active %08X,%08X,%08X,%08X"), i2c_active[0], i2c_active[1], i2c_active[2], i2c_active[3]); +// AddLog(LOG_LEVEL_DEBUG, PSTR("I2C: Active %08X,%08X,%08X,%08X"), i2c_active[bus][0], i2c_active[bus][1], i2c_active[bus][2], i2c_active[bus][3]); } -void I2cSetActiveFound(uint32_t addr, const char *types, uint8_t bus = 0) -{ - I2cSetActive(addr,bus); +void I2cSetActiveFound(uint32_t addr, const char *types, uint8_t bus = 0) { + I2cSetActive(addr, bus); #ifdef ESP32 - if (0 == bus) { - AddLog(LOG_LEVEL_INFO, S_LOG_I2C_FOUND_AT, types, addr); - } else { + if (1 == bus) { AddLog(LOG_LEVEL_INFO, S_LOG_I2C_FOUND_AT_PORT, types, addr, bus); - } -#else - AddLog(LOG_LEVEL_INFO, S_LOG_I2C_FOUND_AT, types, addr); + } else #endif // ESP32 -} -bool I2cActive(uint32_t addr, uint8_t bus = 0) -{ -#ifdef ESP32 - if(0==bus) - { -#endif - addr &= 0x7F; // Max I2C address is 127 - if (i2c_active[addr / 32] & (1 << (addr % 32))) { - return true; - } - return false; -#ifdef ESP32 - } - // else - addr &= 0x7F; // Max I2C address is 127 - if (i2c_active_bus2[addr / 32] & (1 << (addr % 32))) { - return true; - } - return false; -#endif + AddLog(LOG_LEVEL_INFO, S_LOG_I2C_FOUND_AT, types, addr); } -bool I2cSetDevice(uint32_t addr, uint8_t bus = 0) -{ +bool I2cActive(uint32_t addr, uint8_t bus = 0) { +#ifdef ESP8266 + bus = 0; +#endif + addr &= 0x7F; // Max I2C address is 127 + return (i2c_active[bus][addr / 32] & (1 << (addr % 32))); +} + +bool I2cSetDevice(uint32_t addr, uint8_t bus = 0) { #ifdef ESP32 if (!TasmotaGlobal.i2c_enabled_2) { bus = 0; } TwoWire & myWire = (bus == 0) ? Wire : Wire1; @@ -363,7 +313,7 @@ bool I2cSetDevice(uint32_t addr, uint8_t bus = 0) TwoWire & myWire = Wire; #endif addr &= 0x7F; // Max I2C address is 127 - if (I2cActive(addr,bus)) { + if (I2cActive(addr, bus)) { return false; // If already active report as not present; } myWire.beginTransmission((uint8_t)addr); @@ -371,7 +321,7 @@ bool I2cSetDevice(uint32_t addr, uint8_t bus = 0) uint32_t err = myWire.endTransmission(); if (err && (err != 2)) { #ifdef ESP32 - AddLog(LOG_LEVEL_DEBUG, PSTR("I2C: Error %d at 0x%02x bus &d"), err, addr,bus); + AddLog(LOG_LEVEL_DEBUG, PSTR("I2C: Error %d at 0x%02x bus %d"), err, addr, bus); #else AddLog(LOG_LEVEL_DEBUG, PSTR("I2C: Error %d at 0x%02x"), err, addr); #endif diff --git a/tasmota/tasmota_xsns_sensor/xsns_09_bmp.ino b/tasmota/tasmota_xsns_sensor/xsns_09_bmp.ino index 3b55d4b88..cc43154fd 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_09_bmp.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_09_bmp.ino @@ -44,14 +44,14 @@ #define BMP_REGISTER_CHIPID 0xD0 -#define BMP_REGISTER_RESET 0xE0 // Register to reset to power on defaults (used for sleep) +#define BMP_REGISTER_RESET 0xE0 // Register to reset to power on defaults (used for sleep) -#define BMP_CMND_RESET 0xB6 // I2C Parameter for RESET to put BMP into reset state +#define BMP_CMND_RESET 0xB6 // I2C Parameter for RESET to put BMP into reset state #ifdef ESP32 - #define BMP_MAX_SENSORS 4 + #define BMP_MAX_SENSORS 4 // 2 busses #else - #define BMP_MAX_SENSORS 2 + #define BMP_MAX_SENSORS 2 #endif const char kBmpTypes[] PROGMEM = "BMP180|BMP280|BME280|BME680"; @@ -114,8 +114,7 @@ typedef struct { bmp180_cal_data_t *bmp180_cal_data = nullptr; -bool Bmp180Calibration(uint8_t bmp_idx) -{ +bool Bmp180Calibration(uint8_t bmp_idx) { if (!bmp180_cal_data) { bmp180_cal_data = (bmp180_cal_data_t*)malloc(BMP_MAX_SENSORS * sizeof(bmp180_cal_data_t)); } @@ -160,33 +159,21 @@ bool Bmp180Calibration(uint8_t bmp_idx) return true; } -void Bmp180Read(uint8_t bmp_idx) -{ +void Bmp180Read(uint8_t bmp_idx) { if (!bmp180_cal_data) { return; } -#ifdef ESP32 - uint8_t bus= (bmp_idx>=2) ? 1 : 0; // first two BMP's at bus 0, additional at bus 1 - I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BMP180_REG_CONTROL, BMP180_TEMPERATURE,bus); + + uint8_t bus = bmp_idx >>1; // First two BMP's at bus 0, additional at bus 1 + I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BMP180_REG_CONTROL, BMP180_TEMPERATURE, bus); delay(5); // 5ms conversion time - int ut = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_REG_RESULT,bus); -#else - I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BMP180_REG_CONTROL, BMP180_TEMPERATURE); - delay(5); // 5ms conversion time - int ut = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_REG_RESULT); -#endif + int ut = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_REG_RESULT, bus); int32_t xt1 = (ut - (int32_t)bmp180_cal_data[bmp_idx].cal_ac6) * ((int32_t)bmp180_cal_data[bmp_idx].cal_ac5) >> 15; int32_t xt2 = ((int32_t)bmp180_cal_data[bmp_idx].cal_mc << 11) / (xt1 + (int32_t)bmp180_cal_data[bmp_idx].cal_md); int32_t bmp180_b5 = xt1 + xt2; bmp_sensors[bmp_idx].bmp_temperature = ((bmp180_b5 + 8) >> 4) / 10.0f; -#ifdef ESP32 - I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BMP180_REG_CONTROL, BMP180_PRESSURE3,bus); // Highest resolution + I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BMP180_REG_CONTROL, BMP180_PRESSURE3, bus); // Highest resolution delay(2 + (4 << BMP180_OSS)); // 26ms conversion time at ultra high resolution - uint32_t up = I2cRead24(bmp_sensors[bmp_idx].bmp_address, BMP180_REG_RESULT,bus); -#else - I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BMP180_REG_CONTROL, BMP180_PRESSURE3); // Highest resolution - delay(2 + (4 << BMP180_OSS)); // 26ms conversion time at ultra high resolution - uint32_t up = I2cRead24(bmp_sensors[bmp_idx].bmp_address, BMP180_REG_RESULT); -#endif + uint32_t up = I2cRead24(bmp_sensors[bmp_idx].bmp_address, BMP180_REG_RESULT, bus); up >>= (8 - BMP180_OSS); int32_t b6 = bmp180_b5 - 4000; @@ -270,8 +257,7 @@ typedef struct { Bme280CalibrationData_t *Bme280CalibrationData = nullptr; -bool Bmx280Calibrate(uint8_t bmp_idx) -{ +bool Bmx280Calibrate(uint8_t bmp_idx) { // if (I2cRead8(bmp_address, BMP_REGISTER_CHIPID) != BME280_CHIPID) return false; if (!Bme280CalibrationData) { @@ -279,46 +265,42 @@ bool Bmx280Calibrate(uint8_t bmp_idx) } if (!Bme280CalibrationData) { return false; } - uint8_t bus= (bmp_idx>=2) ? 1 : 0; // first two BMP's at bus 0, additional at bus 1 (ESP32 32 only) - Bme280CalibrationData[bmp_idx].dig_T1 = I2cRead16LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_T1,bus); - Bme280CalibrationData[bmp_idx].dig_T2 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_T2,bus); - Bme280CalibrationData[bmp_idx].dig_T3 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_T3,bus); - Bme280CalibrationData[bmp_idx].dig_P1 = I2cRead16LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P1,bus); - Bme280CalibrationData[bmp_idx].dig_P2 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P2,bus); - Bme280CalibrationData[bmp_idx].dig_P3 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P3,bus); - Bme280CalibrationData[bmp_idx].dig_P4 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P4,bus); - Bme280CalibrationData[bmp_idx].dig_P5 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P5,bus); - Bme280CalibrationData[bmp_idx].dig_P6 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P6,bus); - Bme280CalibrationData[bmp_idx].dig_P7 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P7,bus); - Bme280CalibrationData[bmp_idx].dig_P8 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P8,bus); - Bme280CalibrationData[bmp_idx].dig_P9 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P9,bus); + uint8_t bus = bmp_idx >>1; // First two BMP's at bus 0, additional at bus 1 + Bme280CalibrationData[bmp_idx].dig_T1 = I2cRead16LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_T1, bus); + Bme280CalibrationData[bmp_idx].dig_T2 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_T2, bus); + Bme280CalibrationData[bmp_idx].dig_T3 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_T3, bus); + Bme280CalibrationData[bmp_idx].dig_P1 = I2cRead16LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P1, bus); + Bme280CalibrationData[bmp_idx].dig_P2 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P2, bus); + Bme280CalibrationData[bmp_idx].dig_P3 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P3, bus); + Bme280CalibrationData[bmp_idx].dig_P4 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P4, bus); + Bme280CalibrationData[bmp_idx].dig_P5 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P5, bus); + Bme280CalibrationData[bmp_idx].dig_P6 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P6, bus); + Bme280CalibrationData[bmp_idx].dig_P7 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P7, bus); + Bme280CalibrationData[bmp_idx].dig_P8 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P8, bus); + Bme280CalibrationData[bmp_idx].dig_P9 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P9, bus); if (BME280_CHIPID == bmp_sensors[bmp_idx].bmp_type) { // #1051 - Bme280CalibrationData[bmp_idx].dig_H1 = I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H1,bus); - Bme280CalibrationData[bmp_idx].dig_H2 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H2,bus); - Bme280CalibrationData[bmp_idx].dig_H3 = I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H3,bus); - Bme280CalibrationData[bmp_idx].dig_H4 = (I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H4,bus) << 4) | (I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H4 + 1,bus) & 0xF); - Bme280CalibrationData[bmp_idx].dig_H5 = (I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H5 + 1,bus) << 4) | (I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H5,bus>>1) >> 4); - Bme280CalibrationData[bmp_idx].dig_H6 = (int8_t)I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H6,bus); - I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONTROL, 0x00,bus); // sleep mode since writes to config can be ignored in normal mode (Datasheet 5.4.5/6 page 27) + Bme280CalibrationData[bmp_idx].dig_H1 = I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H1, bus); + Bme280CalibrationData[bmp_idx].dig_H2 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H2, bus); + Bme280CalibrationData[bmp_idx].dig_H3 = I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H3, bus); + Bme280CalibrationData[bmp_idx].dig_H4 = (I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H4, bus) << 4) | (I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H4 + 1,bus) & 0xF); + Bme280CalibrationData[bmp_idx].dig_H5 = (I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H5 + 1, bus) << 4) | (I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H5,bus>>1) >> 4); + Bme280CalibrationData[bmp_idx].dig_H6 = (int8_t)I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H6, bus); + I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONTROL, 0x00, bus); // sleep mode since writes to config can be ignored in normal mode (Datasheet 5.4.5/6 page 27) // Set before CONTROL_meas (DS 5.4.3) - I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONTROLHUMID, 0x01,bus); // 1x oversampling - I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONFIG, 0xA0,bus); // 1sec standby between measurements (to limit self heating), IIR filter off - I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONTROL, 0x27,bus); // 1x oversampling, normal mode + I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONTROLHUMID, 0x01, bus); // 1x oversampling + I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONFIG, 0xA0, bus); // 1sec standby between measurements (to limit self heating), IIR filter off + I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONTROL, 0x27, bus); // 1x oversampling, normal mode } else { - I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONTROL, 0xB7,bus); // 16x oversampling, normal mode (Adafruit) + I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONTROL, 0xB7, bus); // 16x oversampling, normal mode (Adafruit) } return true; } -void Bme280Read(uint8_t bmp_idx) -{ +void Bme280Read(uint8_t bmp_idx) { if (!Bme280CalibrationData) { return; } -#ifdef ESP32 - int32_t adc_T = I2cRead24(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_TEMPDATA,bmp_idx>>1); -#else - int32_t adc_T = I2cRead24(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_TEMPDATA); -#endif + uint8_t bus = bmp_idx >>1; // First two BMP's at bus 0, additional at bus 1 + int32_t adc_T = I2cRead24(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_TEMPDATA, bus); adc_T >>= 4; int32_t vart1 = ((((adc_T >> 3) - ((int32_t)Bme280CalibrationData[bmp_idx].dig_T1 << 1))) * ((int32_t)Bme280CalibrationData[bmp_idx].dig_T2)) >> 11; @@ -327,11 +309,8 @@ void Bme280Read(uint8_t bmp_idx) int32_t t_fine = vart1 + vart2; float T = (t_fine * 5 + 128) >> 8; bmp_sensors[bmp_idx].bmp_temperature = T / 100.0f; -#ifdef ESP32 - int32_t adc_P = I2cRead24(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_PRESSUREDATA,bmp_idx>>1); -#else - int32_t adc_P = I2cRead24(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_PRESSUREDATA); -#endif + + int32_t adc_P = I2cRead24(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_PRESSUREDATA, bus); adc_P >>= 4; int64_t var1 = ((int64_t)t_fine) - 128000; @@ -351,11 +330,9 @@ void Bme280Read(uint8_t bmp_idx) bmp_sensors[bmp_idx].bmp_pressure = (float)p / 25600.0f; if (BMP280_CHIPID == bmp_sensors[bmp_idx].bmp_type) { return; } -#ifdef ESP32 - int32_t adc_H = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_HUMIDDATA,bmp_idx>>1); -#else - int32_t adc_H = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_HUMIDDATA); -#endif + + int32_t adc_H = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_HUMIDDATA, bus); + int32_t v_x1_u32r = (t_fine - ((int32_t)76800)); v_x1_u32r = (((((adc_H << 14) - (((int32_t)Bme280CalibrationData[bmp_idx].dig_H4) << 20) - (((int32_t)Bme280CalibrationData[bmp_idx].dig_H5) * v_x1_u32r)) + ((int32_t)16384)) >> 15) * @@ -440,8 +417,7 @@ bool Bme680Init(uint8_t bmp_idx) { return true; } -void Bme680Read(uint8_t bmp_idx) -{ +void Bme680Read(uint8_t bmp_idx) { if (!bme_dev) { return; } int8_t rslt = BME68X_OK; @@ -488,8 +464,7 @@ void Bme680Read(uint8_t bmp_idx) /********************************************************************************************/ -void BmpDetect(void) -{ +void BmpDetect(void) { int bmp_sensor_size = BMP_MAX_SENSORS * sizeof(bmp_sensors_t); if (!bmp_sensors) { bmp_sensors = (bmp_sensors_t*)malloc(bmp_sensor_size); @@ -498,19 +473,14 @@ void BmpDetect(void) memset(bmp_sensors, 0, bmp_sensor_size); // Init defaults to 0 for (uint32_t i = 0; i < BMP_MAX_SENSORS; i++) { - uint8_t bmp_type = 0; -#ifdef ESP32 - uint8_t bus = (i>=2) ? 1 : 0; + uint8_t bus = i >>1; if (!I2cSetDevice(bmp_addresses[i], bus)) { continue; } - bmp_type = I2cRead8(bmp_addresses[i], BMP_REGISTER_CHIPID, bus); -#else - if (!I2cSetDevice(bmp_addresses[i])) { continue; } - bmp_type = I2cRead8(bmp_addresses[i], BMP_REGISTER_CHIPID); -#endif + uint8_t bmp_type = I2cRead8(bmp_addresses[i], BMP_REGISTER_CHIPID, bus); if (bmp_type) { bmp_sensors[bmp_count].bmp_address = bmp_addresses[i]; bmp_sensors[bmp_count].bmp_type = bmp_type; bmp_sensors[bmp_count].bmp_model = 0; + bool success = false; switch (bmp_type) { case BMP180_CHIPID: @@ -531,19 +501,14 @@ void BmpDetect(void) } if (success) { GetTextIndexed(bmp_sensors[bmp_count].bmp_name, sizeof(bmp_sensors[bmp_count].bmp_name), bmp_sensors[bmp_count].bmp_model, kBmpTypes); -#ifdef ESP32 - I2cSetActiveFound(bmp_sensors[bmp_count].bmp_address, bmp_sensors[bmp_count].bmp_name,bus); -#else - I2cSetActiveFound(bmp_sensors[bmp_count].bmp_address, bmp_sensors[bmp_count].bmp_name); -#endif + I2cSetActiveFound(bmp_sensors[bmp_count].bmp_address, bmp_sensors[bmp_count].bmp_name, bus); bmp_count++; } } } } -void BmpRead(void) -{ +void BmpRead(void) { for (uint32_t bmp_idx = 0; bmp_idx < bmp_count; bmp_idx++) { switch (bmp_sensors[bmp_idx].bmp_type) { case BMP180_CHIPID: @@ -569,30 +534,20 @@ void BmpShow(bool json) float bmp_sealevel = ConvertPressureForSeaLevel(bmp_sensors[bmp_idx].bmp_pressure); float bmp_temperature = ConvertTemp(bmp_sensors[bmp_idx].bmp_temperature); float bmp_pressure = ConvertPressure(bmp_sensors[bmp_idx].bmp_pressure); -#ifdef ESP32 + char name[12]; - if (TasmotaGlobal.i2c_enabled_2) - { - strlcpy(name, bmp_sensors[bmp_idx].bmp_name, sizeof(bmp_sensors[bmp_idx].bmp_name)); - uint8_t bus= (bmp_idx>=2) ? 1 : 0; + strlcpy(name, bmp_sensors[bmp_idx].bmp_name, sizeof(bmp_sensors[bmp_idx].bmp_name)); +#ifdef ESP32 + if (TasmotaGlobal.i2c_enabled_2) { + uint8_t bus = bmp_idx >>1; if (bmp_count > 1) { - snprintf_P(name, sizeof(name), PSTR("%s%c%02X%c%1d"), name, IndexSeparator(), bmp_sensors[bmp_idx].bmp_address,IndexSeparator(),bus); // BMXXXX-XX-X + snprintf_P(name, sizeof(name), PSTR("%s%c%02X%c%1d"), name, IndexSeparator(), bmp_sensors[bmp_idx].bmp_address, IndexSeparator(), bus); // BMXXXX-XX-X } - } - else - { - strlcpy(name, bmp_sensors[bmp_idx].bmp_name, sizeof(bmp_sensors[bmp_idx].bmp_name)); - if (bmp_count > 1) { - snprintf_P(name, sizeof(name), PSTR("%s%c%02X"), name, IndexSeparator(), bmp_sensors[bmp_idx].bmp_address); // BMXXXX-XX - } - } -#else - char name[10]; - strlcpy(name, bmp_sensors[bmp_idx].bmp_name, sizeof(name)); + } else +#endif if (bmp_count > 1) { snprintf_P(name, sizeof(name), PSTR("%s%c%02X"), name, IndexSeparator(), bmp_sensors[bmp_idx].bmp_address); // BMXXXX-XX } -#endif char pressure[33]; dtostrfd(bmp_pressure, Settings->flag2.pressure_resolution, pressure); @@ -672,20 +627,14 @@ void BmpShow(bool json) #ifdef USE_DEEPSLEEP -void BMP_EnterSleep(void) -{ +void BMP_EnterSleep(void) { if (DeepSleepEnabled()) { for (uint32_t bmp_idx = 0; bmp_idx < bmp_count; bmp_idx++) { switch (bmp_sensors[bmp_idx].bmp_type) { case BMP180_CHIPID: case BMP280_CHIPID: case BME280_CHIPID: -#ifdef ESP32 - uint8_t bus= (bmp_idx>=2) ? 1 : 0; - I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BMP_REGISTER_RESET, BMP_CMND_RESET,bus); -#else - I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BMP_REGISTER_RESET, BMP_CMND_RESET); -#endif + I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BMP_REGISTER_RESET, BMP_CMND_RESET, bmp_idx >>1); break; default: break; From 17d68750d9f24059fb45b621d80ca8d6a6a0334c Mon Sep 17 00:00:00 2001 From: David Gwynne Date: Mon, 9 Jan 2023 02:35:45 +1000 Subject: [PATCH 118/262] WIP Tuya MCU Bridge driver alternative to the TuyaMCU driver (#17626) * WIP Tuya MCU Bridge driver alternative to the TuyaMCU driver The main difference is this driver does not try and wire MCU data points (Dps) into the tasmota power/light/etc controls. Instead each Dp ends up being relayed directly to MQTT and the rules subsystem. If you want to change the state of something wired up to the MCU, you send tuyamcu specific commands to manipulate the Dp. Each Dp gets a type and id specific topic that is sent to MQTT. eg, Dp id 1 type bool looks like tele/%topic%/TUYAMCUBOOL1. To change state you send a TuyaMCUBool1 command (ie, the command index value is used as the DpId, which is nice and symmetrical) with the new value. Currently Rules operate on TuyaMCU#TypeDpid things, eg, "rule1 on TuyaMCU#Bool1 do power %value% endon" toggle the power on the tasmota device when the state of the thing on the MCU changes too. The most obviously missing stuff at the moment is: - better relaying of the wifi/mqtt status to the MCU - handling wifi reset requests from the MCU - low power stuff? - support for sending status updates and device info queries. - restarting the tuya mcu state machine? - restarting the rx state machine when no bytes are rxed for a period of time - time sync * shorten the log prefix to TYB (3 chars). requested by arendst * use the local definition for the SET_DP command. reaching back to the existing tuyamcu code isnt reliable. pointed out by arendst * put the todo list in the code so it can be tracked * check the wifi/mqtt state every second and update the mcu if it changes. * fix rule processing when Dp state is changed from a cmnd. rule processing was done as part of publishing the state, but publishing the state when it was updated by a command only happened if So59 was set. split rule processing out of publish and call them separately as needed. publish is now called from teleperiod, status updates from the MCU, and from cmnds if so59 is set. rules are called from status updates from the MCU and from cmnds. Co-authored-by: David Gwynne --- tasmota/berry/include/be_gpio_defines.h | 2 + tasmota/include/tasmota_configurations.h | 1 + tasmota/include/tasmota_template.h | 6 + tasmota/language/af_AF.h | 2 + tasmota/language/bg_BG.h | 2 + tasmota/language/ca_AD.h | 2 + tasmota/language/cs_CZ.h | 2 + tasmota/language/de_DE.h | 2 + tasmota/language/el_GR.h | 2 + tasmota/language/en_GB.h | 2 + tasmota/language/es_ES.h | 2 + tasmota/language/fr_FR.h | 2 + tasmota/language/fy_NL.h | 2 + tasmota/language/he_HE.h | 2 + tasmota/language/hu_HU.h | 2 + tasmota/language/it_IT.h | 2 + tasmota/language/ko_KO.h | 2 + tasmota/language/nl_NL.h | 2 + tasmota/language/pl_PL.h | 2 + tasmota/language/pt_BR.h | 2 + tasmota/language/pt_PT.h | 2 + tasmota/language/ro_RO.h | 2 + tasmota/language/ru_RU.h | 2 + tasmota/language/sk_SK.h | 2 + tasmota/language/sv_SE.h | 2 + tasmota/language/tr_TR.h | 2 + tasmota/language/uk_UA.h | 2 + tasmota/language/vi_VN.h | 2 + tasmota/language/zh_CN.h | 2 + tasmota/language/zh_TW.h | 2 + tasmota/my_user_config.h | 2 + tasmota/tasmota_support/support_features.ino | 5 +- .../.xdrv_65_tuyamcubr.ino.swp | Bin 0 -> 32768 bytes .../tasmota_xdrv_driver/xdrv_44_miel_hvac.ino | 4 + .../tasmota_xdrv_driver/xdrv_65_tuyamcubr.ino | 980 ++++++++++++++++++ tools/decode-status.py | 2 +- tools/lv_gpio/lv_gpio_enum.h | 2 + 37 files changed, 1056 insertions(+), 2 deletions(-) create mode 100644 tasmota/tasmota_xdrv_driver/.xdrv_65_tuyamcubr.ino.swp create mode 100644 tasmota/tasmota_xdrv_driver/xdrv_65_tuyamcubr.ino diff --git a/tasmota/berry/include/be_gpio_defines.h b/tasmota/berry/include/be_gpio_defines.h index ff68ac354..f037d9480 100644 --- a/tasmota/berry/include/be_gpio_defines.h +++ b/tasmota/berry/include/be_gpio_defines.h @@ -294,6 +294,8 @@ const be_const_member_t lv_gpio_constants[] = { { "TM1638STB", (int32_t) GPIO_TM1638STB }, { "TUYA_RX", (int32_t) GPIO_TUYA_RX }, { "TUYA_TX", (int32_t) GPIO_TUYA_TX }, + { "TUYAMCUBR_RX", (int32_t) GPIO_TUYAMCUBR_RX }, + { "TUYAMCUBR_TX", (int32_t) GPIO_TUYAMCUBR_TX }, { "TX2X_TXD_BLACK", (int32_t) GPIO_TX2X_TXD_BLACK }, { "TXD", (int32_t) GPIO_TXD }, { "VINDRIKTNING_RX", (int32_t) GPIO_VINDRIKTNING_RX }, diff --git a/tasmota/include/tasmota_configurations.h b/tasmota/include/tasmota_configurations.h index b787e1dcd..1ed060c54 100644 --- a/tasmota/include/tasmota_configurations.h +++ b/tasmota/include/tasmota_configurations.h @@ -41,6 +41,7 @@ #ifndef TUYA_DIMMER_ID #define TUYA_DIMMER_ID 0 // Default dimmer Id #endif +#define USE_TUYAMCUBR #undef USE_ARMTRONIX_DIMMERS // Disable support for Armtronix Dimmers (+1k4 code) #undef USE_PS_16_DZ // Disable support for PS-16-DZ Dimmer (+2k code) #undef USE_SONOFF_IFAN // Disable support for Sonoff iFan02 and iFan03 (+2k code) diff --git a/tasmota/include/tasmota_template.h b/tasmota/include/tasmota_template.h index 60a85240a..047e6766a 100644 --- a/tasmota/include/tasmota_template.h +++ b/tasmota/include/tasmota_template.h @@ -204,6 +204,7 @@ enum UserSelectablePins { GPIO_LD2410_TX, GPIO_LD2410_RX, // HLK-LD2410 GPIO_MBR_TX_ENA, GPIO_NRG_MBS_TX_ENA, // Modbus Bridge Serial Transmit Enable GPIO_ME007_TRIG, GPIO_ME007_RX, // ME007 Serial/Trigger interface + GPIO_TUYAMCUBR_TX, GPIO_TUYAMCUBR_RX, // TuyaMCU Bridge GPIO_SENSOR_END }; // Error as warning to rethink GPIO usage with max 2045 @@ -455,6 +456,7 @@ const char kSensorNames[] PROGMEM = D_SENSOR_LD2410_TX "|" D_SENSOR_LD2410_RX "|" D_SENSOR_MBR_TX_ENA "|" D_SENSOR_NRG_MBS_TX_ENA "|" D_SENSOR_ME007_TRIG "|" D_SENSOR_ME007_RX "|" + D_SENSOR_TUYAMCUBR_TX "|" D_SENSOR_TUYAMCUBR_RX "|" ; const char kSensorNamesFixed[] PROGMEM = @@ -1056,6 +1058,10 @@ const uint16_t kGpioNiceList[] PROGMEM = { AGPIO(GPIO_MIEL_HVAC_TX), // Mitsubishi Electric HVAC TX pin AGPIO(GPIO_MIEL_HVAC_RX), // Mitsubishi Electric HVAC RX pin #endif +#ifdef USE_TUYAMCUBR + AGPIO(GPIO_TUYAMCUBR_TX), + AGPIO(GPIO_TUYAMCUBR_RX), +#endif #ifdef USE_WIEGAND AGPIO(GPIO_WIEGAND_D0), // Date line D0 of Wiegand devices AGPIO(GPIO_WIEGAND_D1), // Date line D1 of Wiegand devices diff --git a/tasmota/language/af_AF.h b/tasmota/language/af_AF.h index 90d1cc897..7d1c464f1 100644 --- a/tasmota/language/af_AF.h +++ b/tasmota/language/af_AF.h @@ -917,6 +917,8 @@ #define D_SENSOR_FLOWRATEMETER "Flowrate" #define D_SENSOR_ME007_TRIG "ME007 Tri" #define D_SENSOR_ME007_RX "ME007 Rx" +#define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" +#define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/bg_BG.h b/tasmota/language/bg_BG.h index eacd7b06b..dfb0a19f2 100644 --- a/tasmota/language/bg_BG.h +++ b/tasmota/language/bg_BG.h @@ -917,6 +917,8 @@ #define D_SENSOR_FLOWRATEMETER "Дебитомер" #define D_SENSOR_ME007_TRIG "ME007 Tri" #define D_SENSOR_ME007_RX "ME007 Rx" +#define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" +#define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" // Units #define D_UNIT_AMPERE "А" diff --git a/tasmota/language/ca_AD.h b/tasmota/language/ca_AD.h index cd7303851..3a3fca3fd 100644 --- a/tasmota/language/ca_AD.h +++ b/tasmota/language/ca_AD.h @@ -917,6 +917,8 @@ #define D_SENSOR_FLOWRATEMETER "Cabal" #define D_SENSOR_ME007_TRIG "ME007 Tri" #define D_SENSOR_ME007_RX "ME007 Rx" +#define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" +#define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/cs_CZ.h b/tasmota/language/cs_CZ.h index 2dda6f462..3aa103e51 100644 --- a/tasmota/language/cs_CZ.h +++ b/tasmota/language/cs_CZ.h @@ -917,6 +917,8 @@ #define D_SENSOR_FLOWRATEMETER "Flowrate" #define D_SENSOR_ME007_TRIG "ME007 Tri" #define D_SENSOR_ME007_RX "ME007 Rx" +#define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" +#define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/de_DE.h b/tasmota/language/de_DE.h index a655df3ed..ed4d18686 100644 --- a/tasmota/language/de_DE.h +++ b/tasmota/language/de_DE.h @@ -917,6 +917,8 @@ #define D_SENSOR_FLOWRATEMETER "Flowrate" #define D_SENSOR_ME007_TRIG "ME007 Tri" #define D_SENSOR_ME007_RX "ME007 Rx" +#define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" +#define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/el_GR.h b/tasmota/language/el_GR.h index 25a808e28..9b885d832 100644 --- a/tasmota/language/el_GR.h +++ b/tasmota/language/el_GR.h @@ -917,6 +917,8 @@ #define D_SENSOR_FLOWRATEMETER "Flowrate" #define D_SENSOR_ME007_TRIG "ME007 Tri" #define D_SENSOR_ME007_RX "ME007 Rx" +#define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" +#define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/en_GB.h b/tasmota/language/en_GB.h index 805cefd30..8bcdab91d 100644 --- a/tasmota/language/en_GB.h +++ b/tasmota/language/en_GB.h @@ -917,6 +917,8 @@ #define D_SENSOR_FLOWRATEMETER "Flowrate" #define D_SENSOR_ME007_TRIG "ME007 Tri" #define D_SENSOR_ME007_RX "ME007 Rx" +#define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" +#define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/es_ES.h b/tasmota/language/es_ES.h index 68d8da907..d5b64734e 100644 --- a/tasmota/language/es_ES.h +++ b/tasmota/language/es_ES.h @@ -917,6 +917,8 @@ #define D_SENSOR_FLOWRATEMETER "Flowrate" #define D_SENSOR_ME007_TRIG "ME007 Tri" #define D_SENSOR_ME007_RX "ME007 Rx" +#define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" +#define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/fr_FR.h b/tasmota/language/fr_FR.h index 917389ff3..c1d2b1c72 100644 --- a/tasmota/language/fr_FR.h +++ b/tasmota/language/fr_FR.h @@ -917,6 +917,8 @@ #define D_SENSOR_FLOWRATEMETER "Flowrate" #define D_SENSOR_ME007_TRIG "ME007 Tri" #define D_SENSOR_ME007_RX "ME007 Rx" +#define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" +#define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/fy_NL.h b/tasmota/language/fy_NL.h index 70a30215b..cc4329c89 100644 --- a/tasmota/language/fy_NL.h +++ b/tasmota/language/fy_NL.h @@ -917,6 +917,8 @@ #define D_SENSOR_FLOWRATEMETER "Flowrate" #define D_SENSOR_ME007_TRIG "ME007 Tri" #define D_SENSOR_ME007_RX "ME007 Rx" +#define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" +#define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/he_HE.h b/tasmota/language/he_HE.h index 33360d150..de30f6352 100644 --- a/tasmota/language/he_HE.h +++ b/tasmota/language/he_HE.h @@ -917,6 +917,8 @@ #define D_SENSOR_FLOWRATEMETER "Flowrate" #define D_SENSOR_ME007_TRIG "ME007 Tri" #define D_SENSOR_ME007_RX "ME007 Rx" +#define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" +#define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/hu_HU.h b/tasmota/language/hu_HU.h index 52f536ec4..00da79687 100644 --- a/tasmota/language/hu_HU.h +++ b/tasmota/language/hu_HU.h @@ -917,6 +917,8 @@ #define D_SENSOR_FLOWRATEMETER "Flowrate" #define D_SENSOR_ME007_TRIG "ME007 Tri" #define D_SENSOR_ME007_RX "ME007 Rx" +#define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" +#define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/it_IT.h b/tasmota/language/it_IT.h index a962827bd..19a763846 100644 --- a/tasmota/language/it_IT.h +++ b/tasmota/language/it_IT.h @@ -917,6 +917,8 @@ #define D_SENSOR_FLOWRATEMETER "Portata" #define D_SENSOR_ME007_TRIG "ME007 - Tri" #define D_SENSOR_ME007_RX "ME007 - RX" +#define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" +#define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/ko_KO.h b/tasmota/language/ko_KO.h index d09b81e03..dcd06089e 100644 --- a/tasmota/language/ko_KO.h +++ b/tasmota/language/ko_KO.h @@ -917,6 +917,8 @@ #define D_SENSOR_FLOWRATEMETER "Flowrate" #define D_SENSOR_ME007_TRIG "ME007 Tri" #define D_SENSOR_ME007_RX "ME007 Rx" +#define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" +#define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/nl_NL.h b/tasmota/language/nl_NL.h index 7d0624efb..ea9130f0f 100644 --- a/tasmota/language/nl_NL.h +++ b/tasmota/language/nl_NL.h @@ -917,6 +917,8 @@ #define D_SENSOR_FLOWRATEMETER "Flowrate" #define D_SENSOR_ME007_TRIG "ME007 Tri" #define D_SENSOR_ME007_RX "ME007 Rx" +#define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" +#define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/pl_PL.h b/tasmota/language/pl_PL.h index 10c0b3b68..0e0415fb0 100644 --- a/tasmota/language/pl_PL.h +++ b/tasmota/language/pl_PL.h @@ -917,6 +917,8 @@ #define D_SENSOR_FLOWRATEMETER "Flowrate" #define D_SENSOR_ME007_TRIG "ME007 Tri" #define D_SENSOR_ME007_RX "ME007 Rx" +#define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" +#define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/pt_BR.h b/tasmota/language/pt_BR.h index 1fce258ee..c7ee07fe3 100644 --- a/tasmota/language/pt_BR.h +++ b/tasmota/language/pt_BR.h @@ -917,6 +917,8 @@ #define D_SENSOR_FLOWRATEMETER "Flowrate" #define D_SENSOR_ME007_TRIG "ME007 Tri" #define D_SENSOR_ME007_RX "ME007 Rx" +#define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" +#define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/pt_PT.h b/tasmota/language/pt_PT.h index af1763dc8..74ae4e72e 100644 --- a/tasmota/language/pt_PT.h +++ b/tasmota/language/pt_PT.h @@ -917,6 +917,8 @@ #define D_SENSOR_FLOWRATEMETER "Flowrate" #define D_SENSOR_ME007_TRIG "ME007 Tri" #define D_SENSOR_ME007_RX "ME007 Rx" +#define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" +#define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/ro_RO.h b/tasmota/language/ro_RO.h index 0dd99d363..1e2f6f992 100644 --- a/tasmota/language/ro_RO.h +++ b/tasmota/language/ro_RO.h @@ -917,6 +917,8 @@ #define D_SENSOR_FLOWRATEMETER "Flowrate" #define D_SENSOR_ME007_TRIG "ME007 Tri" #define D_SENSOR_ME007_RX "ME007 Rx" +#define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" +#define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/ru_RU.h b/tasmota/language/ru_RU.h index 8de5385e5..893693054 100644 --- a/tasmota/language/ru_RU.h +++ b/tasmota/language/ru_RU.h @@ -917,6 +917,8 @@ #define D_SENSOR_FLOWRATEMETER "Flowrate" #define D_SENSOR_ME007_TRIG "ME007 Tri" #define D_SENSOR_ME007_RX "ME007 Rx" +#define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" +#define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" // Units #define D_UNIT_AMPERE "А" diff --git a/tasmota/language/sk_SK.h b/tasmota/language/sk_SK.h index 697020c42..9ede0cf21 100644 --- a/tasmota/language/sk_SK.h +++ b/tasmota/language/sk_SK.h @@ -917,6 +917,8 @@ #define D_SENSOR_FLOWRATEMETER "Flowrate" #define D_SENSOR_ME007_TRIG "ME007 Tri" #define D_SENSOR_ME007_RX "ME007 Rx" +#define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" +#define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/sv_SE.h b/tasmota/language/sv_SE.h index d0607da30..1145c3f2c 100644 --- a/tasmota/language/sv_SE.h +++ b/tasmota/language/sv_SE.h @@ -917,6 +917,8 @@ #define D_SENSOR_FLOWRATEMETER "Flowrate" #define D_SENSOR_ME007_TRIG "ME007 Tri" #define D_SENSOR_ME007_RX "ME007 Rx" +#define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" +#define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/tr_TR.h b/tasmota/language/tr_TR.h index dcb243c02..b43eaf75c 100644 --- a/tasmota/language/tr_TR.h +++ b/tasmota/language/tr_TR.h @@ -917,6 +917,8 @@ #define D_SENSOR_FLOWRATEMETER "Flowrate" #define D_SENSOR_ME007_TRIG "ME007 Tri" #define D_SENSOR_ME007_RX "ME007 Rx" +#define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" +#define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/uk_UA.h b/tasmota/language/uk_UA.h index cc5c3de2f..1c72ce490 100644 --- a/tasmota/language/uk_UA.h +++ b/tasmota/language/uk_UA.h @@ -917,6 +917,8 @@ #define D_SENSOR_FLOWRATEMETER "Flowrate" #define D_SENSOR_ME007_TRIG "ME007 Tri" #define D_SENSOR_ME007_RX "ME007 Rx" +#define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" +#define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" // Units #define D_UNIT_AMPERE "А" diff --git a/tasmota/language/vi_VN.h b/tasmota/language/vi_VN.h index ef0035a26..1ca96fd17 100644 --- a/tasmota/language/vi_VN.h +++ b/tasmota/language/vi_VN.h @@ -917,6 +917,8 @@ #define D_SENSOR_FLOWRATEMETER "Flowrate" #define D_SENSOR_ME007_TRIG "ME007 Tri" #define D_SENSOR_ME007_RX "ME007 Rx" +#define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" +#define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/zh_CN.h b/tasmota/language/zh_CN.h index b3f8cf5fe..5690e5018 100644 --- a/tasmota/language/zh_CN.h +++ b/tasmota/language/zh_CN.h @@ -917,6 +917,8 @@ #define D_SENSOR_FLOWRATEMETER "Flowrate" #define D_SENSOR_ME007_TRIG "ME007 Tri" #define D_SENSOR_ME007_RX "ME007 Rx" +#define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" +#define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/zh_TW.h b/tasmota/language/zh_TW.h index a4fd10115..9f9e1959a 100644 --- a/tasmota/language/zh_TW.h +++ b/tasmota/language/zh_TW.h @@ -917,6 +917,8 @@ #define D_SENSOR_FLOWRATEMETER "Flowrate" #define D_SENSOR_ME007_TRIG "ME007 Tri" #define D_SENSOR_ME007_RX "ME007 Rx" +#define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" +#define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" // Units #define D_UNIT_AMPERE "安培" diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index 2c0e749f2..7933a9343 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -533,6 +533,7 @@ #define USE_TUYA_MCU // Add support for Tuya Serial MCU #define TUYA_DIMMER_ID 0 // Default dimmer Id #define USE_TUYA_TIME // Add support for Set Time in Tuya MCU +#define USE_TUYAMCUBR // Add support for TuyaMCU Bridge #define USE_ARMTRONIX_DIMMERS // Add support for Armtronix Dimmers (+1k4 code) #define USE_PS_16_DZ // Add support for PS-16-DZ Dimmer (+2k code) #define USE_SONOFF_IFAN // Add support for Sonoff iFan02 and iFan03 (+2k code) @@ -822,6 +823,7 @@ #define USE_TASMOTA_CLIENT_SERIAL_SPEED 57600 // Depends on the sketch that is running on the Uno/Pro Mini //#define USE_OPENTHERM // Add support for OpenTherm (+15k code) //#define USE_MIEL_HVAC // Add support for Mitsubishi Electric HVAC serial interface (+5k code) +//#define USE_TUYAMCUBR // Add support for TuyaMCU Bridge //#define USE_PROJECTOR_CTRL // Add support for LCD/DLP Projector serial control interface (+2k code) // #define USE_PROJECTOR_CTRL_NEC // Use codes for NEC // #define USE_PROJECTOR_CTRL_OPTOMA // Use codes for OPTOMA diff --git a/tasmota/tasmota_support/support_features.ino b/tasmota/tasmota_support/support_features.ino index 78a1d7d74..8f52b111e 100644 --- a/tasmota/tasmota_support/support_features.ino +++ b/tasmota/tasmota_support/support_features.ino @@ -867,7 +867,10 @@ void ResponseAppendFeatures(void) #if defined(USE_I2C) && defined(USE_PCA9632) feature9 |= 0x00002000; #endif -// feature9 |= 0x00004000; +#ifdef USE_TUYAMCUBR + feature9 |= 0x00004000; // xdrv_65_tuyamcubr.ino +#endif + // feature9 |= 0x00008000; // feature9 |= 0x00010000; diff --git a/tasmota/tasmota_xdrv_driver/.xdrv_65_tuyamcubr.ino.swp b/tasmota/tasmota_xdrv_driver/.xdrv_65_tuyamcubr.ino.swp new file mode 100644 index 0000000000000000000000000000000000000000..e97c202883be5731cc8c3788b63298369f39053e GIT binary patch literal 32768 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 AnE(I) literal 0 HcmV?d00001 diff --git a/tasmota/tasmota_xdrv_driver/xdrv_44_miel_hvac.ino b/tasmota/tasmota_xdrv_driver/xdrv_44_miel_hvac.ino index 60ea83e5a..65ab1ecdd 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_44_miel_hvac.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_44_miel_hvac.ino @@ -24,10 +24,14 @@ #define XDRV_44 44 +#ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) +#endif +#ifndef CTASSERT #define CTASSERT(x) extern char _ctassert[(x) ? 1 : -1 ] \ __attribute__((__unused__)) +#endif #define MIEL_HVAC_LOGNAME "MiElHVAC" diff --git a/tasmota/tasmota_xdrv_driver/xdrv_65_tuyamcubr.ino b/tasmota/tasmota_xdrv_driver/xdrv_65_tuyamcubr.ino new file mode 100644 index 000000000..c51c3daac --- /dev/null +++ b/tasmota/tasmota_xdrv_driver/xdrv_65_tuyamcubr.ino @@ -0,0 +1,980 @@ +/* + * xdrv_65_tuyamcubr.ino - TuyaMCU Bridge support for Tasmota + */ + +/* + * Copyright (C) 2023 David Gwynne + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifdef USE_TUYAMCUBR + +/* + * Tuya MCU Bridge + */ + +/* + * TODO: + * + * - handling wifi reset requests from the MCU + * - low power stuff? + * - support for (re)sending status updates and device info queries + * - supporting the raw and string Dp types + * - restarting the tuya mcu state machine? + * - restarting the rx state machine when no bytes are rxed for a while + * - time sync + */ + +#define XDRV_65 65 + +#ifndef nitems +#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) +#endif + +#ifndef CTASSERT +#define CTASSERT(x) extern char _ctassert[(x) ? 1 : -1 ] \ + __attribute__((__unused__)) +#endif + +#define TUYAMCUBR_LOGNAME "TYB" +#define TUYAMCUBR_FMT(_fmt) PSTR(TUYAMCUBR_LOGNAME ": " _fmt) + +#define D_CMND_TUYAMCUBR_PREFIX "TuyaMCU" + +#define D_CMND_TUYAMCUBR_DATA_RAW "Raw" +#define D_CMND_TUYAMCUBR_DATA_BOOL "Bool" +#define D_CMND_TUYAMCUBR_DATA_VALUE "Value" +#define D_CMND_TUYAMCUBR_DATA_STRING "String" +#define D_CMND_TUYAMCUBR_DATA_ENUM "Enum" + +#include + +struct tuyamcubr_header { + uint8_t header[2]; +#define TUYAMCUBR_H_ONE 0x55 +#define TUYAMCUBR_H_TWO 0xaa + uint8_t version; + uint8_t command; + uint16_t datalen; +}; + +CTASSERT(sizeof(struct tuyamcubr_header) == 6); + +#define TUYAMCUBR_CMD_HEARTBEAT 0x00 +#define TUYAMCUBR_CMD_PRODUCT 0x01 +#define TUYAMCUBR_CMD_MODE 0x02 +#define TUYAMCUBR_CMD_WIFI_STATE 0x03 +#define TUYAMCUBR_CMD_WIFI_RESET 0x04 +#define TUYAMCUBR_CMD_WIFI_SELECT 0x05 +#define TUYAMCUBR_CMD_SET_DP 0x06 +#define TUYAMCUBR_CMD_STATE 0x07 +#define TUYAMCUBR_CMD_QUERY_STATE 0x08 +#define TUYAMCUBR_CMD_INIT_UPGRADE 0x0a +#define TUYAMCUBR_CMD_UPGRADE_PKG 0x0b +#define TUYAMCUBR_CMD_SET_TIME 0x1c + +/* wifi state */ + +#define TUYAMCUBR_NETWORK_STATUS_1 0x00 /* pairing in EZ mode */ +#define TUYAMCUBR_NETWORK_STATUS_2 0x01 /* pairing in AP mode */ +#define TUYAMCUBR_NETWORK_STATUS_3 0x02 /* WiFi */ +#define TUYAMCUBR_NETWORK_STATUS_4 0x03 /* WiFi + router */ +#define TUYAMCUBR_NETWORK_STATUS_5 0x04 /* WiFi + router + cloud*/ +#define TUYAMCUBR_NETWORK_STATUS_6 0x05 /* low power mode */ +#define TUYAMCUBR_NETWORK_STATUS_7 0x06 /* pairing in EZ+AP mode */ + +/* set dp */ + +struct tuyamcubr_data_header { + uint8_t dpid; + uint8_t type; + uint16_t len; + + /* followed by len bytes */ +}; + +CTASSERT(sizeof(struct tuyamcubr_data_header) == 4); + +#define TUYAMCUBR_DATA_TYPE_RAW 0x00 +#define TUYAMCUBR_DATA_TYPE_BOOL 0x01 +#define TUYAMCUBR_DATA_TYPE_VALUE 0x02 +#define TUYAMCUBR_DATA_TYPE_STRING 0x03 +#define TUYAMCUBR_DATA_TYPE_ENUM 0x04 + +struct tuyamcubr_data_type { + const char *t_name; + int t_len; + uint32_t t_max; + uint32_t (*t_rd)(const uint8_t *); + void (*t_wr)(uint8_t *, uint32_t); +}; + +static uint32_t +tuyamcubr_rd_u8(const uint8_t *b) +{ + return (*b); +} + +static void +tuyamcubr_wr_u8(uint8_t *b, uint32_t v) +{ + *b = v; +} + +static uint32_t +tuyamcubr_rd_u32(const uint8_t *b) +{ + uint32_t be32; + memcpy(&be32, b, sizeof(be32)); + return (ntohl(be32)); +} + +static void +tuyamcubr_wr_u32(uint8_t *b, uint32_t v) +{ + uint32_t be32 = htonl(v); + memcpy(b, &be32, sizeof(be32)); +} + +static const struct tuyamcubr_data_type tuyamcubr_data_types[] = { + [TUYAMCUBR_DATA_TYPE_RAW] = { + .t_name = D_CMND_TUYAMCUBR_DATA_RAW, + .t_len = -1, + }, + [TUYAMCUBR_DATA_TYPE_BOOL] = { + .t_name = D_CMND_TUYAMCUBR_DATA_BOOL, + .t_len = 1, + .t_max = 1, + .t_rd = tuyamcubr_rd_u8, + .t_wr = tuyamcubr_wr_u8, + }, + [TUYAMCUBR_DATA_TYPE_VALUE] = { + .t_name = D_CMND_TUYAMCUBR_DATA_VALUE, + .t_len = sizeof(uint32_t), + .t_max = 0xffffffff, + .t_rd = tuyamcubr_rd_u32, + .t_wr = tuyamcubr_wr_u32, + }, + [TUYAMCUBR_DATA_TYPE_STRING] = { + .t_name = D_CMND_TUYAMCUBR_DATA_STRING, + .t_len = -1, + }, + [TUYAMCUBR_DATA_TYPE_ENUM] = { + .t_name = D_CMND_TUYAMCUBR_DATA_ENUM, + .t_len = 1, + .t_max = 0xff, + .t_rd = tuyamcubr_rd_u8, + .t_wr = tuyamcubr_wr_u8, + }, +}; + +static inline const struct tuyamcubr_data_type * +tuyamcubr_find_data_type(uint8_t type) +{ + const struct tuyamcubr_data_type *dt; + + if (type > nitems(tuyamcubr_data_types)) + return (NULL); + + dt = &tuyamcubr_data_types[type]; + if (dt->t_name == NULL) + return (NULL); + + return (dt); +} + +static inline uint8_t +tuyamcubr_cksum_fini(uint8_t sum) +{ + /* + * "Start from the header, add up all the bytes, and then divide + * the sum by 256 to get the remainder." + * + * If we accumulate bytes in a uint8_t, we get this for free. + */ + + return (sum); +} + +enum tuyamcubr_parser_state { + TUYAMCUBR_P_START, + TUYAMCUBR_P_HEADER, + TUYAMCUBR_P_VERSION, + TUYAMCUBR_P_COMMAND, + TUYAMCUBR_P_LEN1, + TUYAMCUBR_P_LEN2, + TUYAMCUBR_P_DATA, + TUYAMCUBR_P_CKSUM, + + TUYAMCUBR_P_SKIP, + TUYAMCUBR_P_SKIP_CKSUM, +}; + +//#ifdef ESP8266 +//#define TUYAMCUBR_BUFLEN 256 +//#else +#define TUYAMCUBR_BUFLEN 1024 +//#endif + +struct tuyamcubr_parser { + enum tuyamcubr_parser_state p_state; + unsigned int p_deadline; + + uint8_t p_version; + uint8_t p_command; + uint8_t p_sum; + + uint16_t p_len; + uint8_t p_off; + uint8_t p_data[TUYAMCUBR_BUFLEN]; +}; + +struct tuyamcubr_dp { + STAILQ_ENTRY(tuyamcubr_dp) dp_entry; + uint8_t dp_id; + uint8_t dp_type; + + uint32_t dp_value; +}; +STAILQ_HEAD(tuyamcubr_dps, tuyamcubr_dp); + +enum tuyamcubr_state { + TUYAMCUBR_S_START, + TUYAMCUBR_S_PROD_INFO, + TUYAMCUBR_S_MODE, + TUYAMCUBR_S_NET_STATUS, + TUYAMCUBR_S_RUNNING, +}; + +struct tuyamcubr_softc { + TasmotaSerial *sc_serial; + struct tuyamcubr_parser sc_parser; + + enum tuyamcubr_state sc_state; + unsigned int sc_deadline; + unsigned int sc_waiting; + uint8_t sc_network_status; + + unsigned int sc_clock; + struct tuyamcubr_dps sc_dps; +}; + +static struct tuyamcubr_softc *tuyamcubr_sc = nullptr; + +struct tuyamcubr_recv_command { + uint8_t r_command; + void (*r_func)(struct tuyamcubr_softc *, uint8_t, + const uint8_t *, size_t); +}; + +static void tuyamcubr_recv_heartbeat(struct tuyamcubr_softc *, uint8_t, + const uint8_t *, size_t); +static void tuyamcubr_recv_product_info(struct tuyamcubr_softc *, uint8_t, + const uint8_t *, size_t); +static void tuyamcubr_recv_mode(struct tuyamcubr_softc *, uint8_t, + const uint8_t *, size_t); +static void tuyamcubr_recv_net_status(struct tuyamcubr_softc *, uint8_t, + const uint8_t *, size_t); +static void tuyamcubr_recv_status(struct tuyamcubr_softc *, uint8_t, + const uint8_t *, size_t); + +static const struct tuyamcubr_recv_command tuyamcubr_recv_commands[] = { + { TUYAMCUBR_CMD_HEARTBEAT, tuyamcubr_recv_heartbeat }, + { TUYAMCUBR_CMD_PRODUCT, tuyamcubr_recv_product_info }, + { TUYAMCUBR_CMD_MODE, tuyamcubr_recv_mode }, + { TUYAMCUBR_CMD_WIFI_STATE, tuyamcubr_recv_net_status }, + { TUYAMCUBR_CMD_STATE, tuyamcubr_recv_status }, +}; + +static void +tuyamcubr_recv(struct tuyamcubr_softc *sc, const struct tuyamcubr_parser *p) +{ + const struct tuyamcubr_recv_command *r; + const uint8_t *data = p->p_data; + size_t len = p->p_len; + size_t i; + + if (len > 0) { + AddLog(LOG_LEVEL_DEBUG, + TUYAMCUBR_FMT("recv version 0x%02x command 0x%02x: %*_H"), + p->p_version, p->p_command, len, data); + } else { + AddLog(LOG_LEVEL_DEBUG, + TUYAMCUBR_FMT("recv version 0x%02x command 0x%02x"), + p->p_version, p->p_command); + } + + for (i = 0; i < nitems(tuyamcubr_recv_commands); i++) { + r = &tuyamcubr_recv_commands[i]; + + if (r->r_command == p->p_command) { + r->r_func(sc, p->p_version, data, len); + return; + } + } + + /* unhandled command? */ +} + +static enum tuyamcubr_parser_state +tuyamcubr_parse(struct tuyamcubr_softc *sc, uint8_t byte) +{ + struct tuyamcubr_parser *p = &sc->sc_parser; + enum tuyamcubr_parser_state nstate = p->p_state; + + switch (p->p_state) { + case TUYAMCUBR_P_START: + if (byte != TUYAMCUBR_H_ONE) + return (TUYAMCUBR_P_START); + + /* reset state */ + p->p_sum = 0; + + nstate = TUYAMCUBR_P_HEADER; + break; + case TUYAMCUBR_P_HEADER: + if (byte != TUYAMCUBR_H_TWO) + return (TUYAMCUBR_P_START); + + nstate = TUYAMCUBR_P_VERSION; + break; + case TUYAMCUBR_P_VERSION: + p->p_version = byte; + nstate = TUYAMCUBR_P_COMMAND; + break; + case TUYAMCUBR_P_COMMAND: + p->p_command = byte; + nstate = TUYAMCUBR_P_LEN1; + break; + + case TUYAMCUBR_P_LEN1: + p->p_len = (uint16_t)byte << 8; + nstate = TUYAMCUBR_P_LEN2; + break; + case TUYAMCUBR_P_LEN2: + p->p_len |= (uint16_t)byte; + p->p_off = 0; + + if (p->p_len > sizeof(p->p_data)) { + AddLog(LOG_LEVEL_DEBUG, + TUYAMCUBR_FMT("skipping command %02x" + ", too much data %zu/%zu"), p->p_command, + p->p_len, sizeof(p->p_data)); + return (TUYAMCUBR_P_SKIP); + } + + nstate = (p->p_len > 0) ? TUYAMCUBR_P_DATA : TUYAMCUBR_P_CKSUM; + break; + + case TUYAMCUBR_P_DATA: + p->p_data[p->p_off++] = byte; + if (p->p_off >= p->p_len) + nstate = TUYAMCUBR_P_CKSUM; + break; + + case TUYAMCUBR_P_CKSUM: + if (tuyamcubr_cksum_fini(p->p_sum) != byte) { + AddLog(LOG_LEVEL_DEBUG, + TUYAMCUBR_FMT("checksum failed, skipping")); + return (TUYAMCUBR_P_START); + } + + tuyamcubr_recv(sc, p); + + /* this message is done, wait for another */ + return (TUYAMCUBR_P_START); + + case TUYAMCUBR_P_SKIP: + if (++p->p_off >= p->p_len) + return (TUYAMCUBR_P_SKIP_CKSUM); + return (nstate); + case TUYAMCUBR_P_SKIP_CKSUM: + return (TUYAMCUBR_P_START); + } + + p->p_sum += byte; + + return (nstate); +} + +static uint8_t +tuyamcubr_write(struct tuyamcubr_softc *sc, const void *data, size_t len) +{ + TasmotaSerial *serial = sc->sc_serial; + const uint8_t *bytes = (const uint8_t *)data; + uint8_t cksum = 0; + size_t i; + + for (i = 0; i < len; i++) { + uint8_t b = bytes[i]; + serial->write(b); + cksum += b; + } + + return (cksum); +} + +static void +tuyamcubr_send(struct tuyamcubr_softc *sc, uint8_t command, + const void *data, size_t len) +{ + TasmotaSerial *serial = sc->sc_serial; + struct tuyamcubr_header h = { + .header = { TUYAMCUBR_H_ONE, TUYAMCUBR_H_TWO }, + .version = 0x00, + .command = command, + .datalen = htons(len), + }; + uint8_t cksum = 0; + + if (len) { + AddLog(LOG_LEVEL_DEBUG, + TUYAMCUBR_FMT("send version 0x%02x command 0x%02x: %*_H"), + h.version, h.command, len, data); + } else { + AddLog(LOG_LEVEL_DEBUG, + TUYAMCUBR_FMT("send version 0x%02x command 0x%02x"), + h.version, h.command); + } + + cksum += tuyamcubr_write(sc, &h, sizeof(h)); + if (len > 0) + cksum += tuyamcubr_write(sc, data, len); + cksum = tuyamcubr_cksum_fini(cksum); + serial->write(cksum); + serial->flush(); +} + +/* if we have polymorphic funcions then we may as well (ab)use them */ +static void +tuyamcubr_send(struct tuyamcubr_softc *sc, uint8_t command) +{ + tuyamcubr_send(sc, command, NULL, 0); +} + +static void +tuyamcubr_heartbeat(struct tuyamcubr_softc *sc, unsigned int deadline) +{ + sc->sc_deadline += deadline; + tuyamcubr_send(sc, TUYAMCUBR_CMD_HEARTBEAT); +} + +static struct tuyamcubr_dp * +tuyamcubr_find_dp(struct tuyamcubr_softc *sc, uint32_t index, uint8_t type) +{ + struct tuyamcubr_dp *dp; + + if (index > 0xff) + return (NULL); + + STAILQ_FOREACH(dp, &sc->sc_dps, dp_entry) { + if (dp->dp_id == index && + dp->dp_type == type) + return (dp); + } + + return (NULL); +} + +static void +tuyamcubr_cmnd_data(struct tuyamcubr_softc *sc, uint8_t type) +{ + const struct tuyamcubr_data_type *dt = &tuyamcubr_data_types[type]; + struct { + struct tuyamcubr_data_header h; + uint8_t value[4]; /* only up to 4 bytes */ + } data; + size_t len = sizeof(data.h) + dt->t_len; + struct tuyamcubr_dp *dp; + + dp = tuyamcubr_find_dp(sc, XdrvMailbox.index, type); + if (dp == NULL) { + ResponseCmndChar_P(PSTR("Unknown DpId")); + return; + } + + if (XdrvMailbox.data_len == 0) { + ResponseCmndNumber(dp->dp_value); + return; + } + + if (XdrvMailbox.payload < 0x00 || XdrvMailbox.payload > dt->t_max) { + ResponseCmndChar_P(PSTR("Invalid")); + return; + } + + dp->dp_value = XdrvMailbox.payload; + + data.h.dpid = dp->dp_id; + data.h.type = dp->dp_type; + data.h.len = htons(dt->t_len); + dt->t_wr(data.value, dp->dp_value); + + tuyamcubr_send(sc, TUYAMCUBR_CMD_SET_DP, &data, len); + tuyamcubr_rule_dp(sc, dp); + + ResponseCmndNumber(dp->dp_value); + + /* SetOption59 */ + if (Settings->flag3.hass_tele_on_power) + tuyamcubr_publish_dp(sc, dp); +} + +static void +tuyamcubr_cmnd_data_bool(void) +{ + tuyamcubr_cmnd_data(tuyamcubr_sc, TUYAMCUBR_DATA_TYPE_BOOL); +} + +static void +tuyamcubr_cmnd_data_value(void) +{ + tuyamcubr_cmnd_data(tuyamcubr_sc, TUYAMCUBR_DATA_TYPE_VALUE); +} + +static void +tuyamcubr_cmnd_data_enum(void) +{ + tuyamcubr_cmnd_data(tuyamcubr_sc, TUYAMCUBR_DATA_TYPE_ENUM); +} + +static void +tuyamcubr_rule_dp(struct tuyamcubr_softc *sc, const struct tuyamcubr_dp *dp) +{ + const struct tuyamcubr_data_type *dt = + &tuyamcubr_data_types[dp->dp_type]; + + /* XXX this only handles numeric types */ + + Response_P(PSTR("{\"%s\":{\"%s%u\":%u}}"), + D_CMND_TUYAMCUBR_PREFIX, + dt->t_name, dp->dp_id, + dp->dp_value); + XdrvRulesProcess(0); +} + +static void +tuyamcubr_publish_dp(struct tuyamcubr_softc *sc, const struct tuyamcubr_dp *dp) +{ + const struct tuyamcubr_data_type *dt = + &tuyamcubr_data_types[dp->dp_type]; + char topic[64]; /* how long is a (bit of) string? */ + + /* XXX this only handles numeric types */ + + snprintf(topic, sizeof(topic), PSTR("%s%s%u"), + D_CMND_TUYAMCUBR_PREFIX, dt->t_name, dp->dp_id); + Response_P(PSTR("%u"), dp->dp_value); + MqttPublishPrefixTopic_P(TELE, topic); +} + +static void +tuyamcubr_publish(struct tuyamcubr_softc *sc) +{ + struct tuyamcubr_dp *dp; + + STAILQ_FOREACH(dp, &sc->sc_dps, dp_entry) + tuyamcubr_publish_dp(sc, dp); +} + +static void +tuyamcubr_send_heartbeat(struct tuyamcubr_softc *sc, unsigned int deadline) +{ + sc->sc_deadline += deadline; + tuyamcubr_send(sc, TUYAMCUBR_CMD_HEARTBEAT); +} + +static void +tuyamcubr_recv_heartbeat(struct tuyamcubr_softc *sc, uint8_t v, + const uint8_t *data, size_t datalen) +{ + /* check the data? */ + + switch (sc->sc_state) { + case TUYAMCUBR_S_START: + sc->sc_state = TUYAMCUBR_S_PROD_INFO; + tuyamcubr_send(sc, TUYAMCUBR_CMD_PRODUCT); + break; + case TUYAMCUBR_S_RUNNING: + sc->sc_waiting = 0; + break; + default: + AddLog(LOG_LEVEL_ERROR, + TUYAMCUBR_FMT("unexpected heartbeat in state %u"), + sc->sc_state); + break; + } +} + +static void +tuyamcubr_recv_product_info(struct tuyamcubr_softc *sc, uint8_t v, + const uint8_t *data, size_t datalen) +{ + AddLog(LOG_LEVEL_INFO, TUYAMCUBR_FMT("MCU Product ID: %.*s"), + datalen, data); + + switch (sc->sc_state) { + case TUYAMCUBR_S_PROD_INFO: + sc->sc_state = TUYAMCUBR_S_MODE; + tuyamcubr_send(sc, TUYAMCUBR_CMD_MODE); + break; + default: + AddLog(LOG_LEVEL_ERROR, + TUYAMCUBR_FMT("unexpected product info in state %u"), + sc->sc_state); + break; + } +} + +static void +tuyamcubr_recv_mode(struct tuyamcubr_softc *sc, uint8_t v, + const uint8_t *data, size_t datalen) +{ + switch (sc->sc_state) { + case TUYAMCUBR_S_MODE: + switch (datalen) { + case 0: + AddLog(LOG_LEVEL_INFO, + TUYAMCUBR_FMT("MCU Mode: Coordinated")); + break; + case 2: + AddLog(LOG_LEVEL_INFO, TUYAMCUBR_FMT("MCU Mode" + ": Status GPIO%u, Reset GPIO%u"), + data[0], data[1]); + + sc->sc_state = TUYAMCUBR_S_RUNNING; + tuyamcubr_send(sc, TUYAMCUBR_CMD_QUERY_STATE); + return; + default: + AddLog(LOG_LEVEL_ERROR, TUYAMCUBR_FMT("MCU Mode" + ": unexpected data length %zu"), datalen); + break; + } + + sc->sc_state = TUYAMCUBR_S_NET_STATUS; + tuyamcubr_send(sc, TUYAMCUBR_CMD_WIFI_STATE, + &sc->sc_network_status, sizeof(sc->sc_network_status)); + break; + default: + AddLog(LOG_LEVEL_ERROR, + TUYAMCUBR_FMT("unexpected product info in state %u"), + sc->sc_state); + break; + } +} + +static void +tuyamcubr_recv_net_status(struct tuyamcubr_softc *sc, uint8_t v, + const uint8_t *data, size_t datalen) +{ + switch (sc->sc_state) { + case TUYAMCUBR_S_NET_STATUS: + sc->sc_state = TUYAMCUBR_S_RUNNING; + tuyamcubr_send(sc, TUYAMCUBR_CMD_QUERY_STATE); + break; + default: + AddLog(LOG_LEVEL_ERROR, + TUYAMCUBR_FMT("unexpected product info in state %u"), + sc->sc_state); + break; + } +} + +static void +tuyamcubr_recv_status(struct tuyamcubr_softc *sc, uint8_t v, + const uint8_t *data, size_t datalen) +{ + const struct tuyamcubr_data_type *dt; + struct tuyamcubr_dp *dp; + struct tuyamcubr_data_header h; + size_t len; + const uint8_t *b; + uint32_t value; + + /* take dp status updates at any time */ + + do { + if (datalen < sizeof(h)) { + AddLog(LOG_LEVEL_ERROR, + TUYAMCUBR_FMT("status header short %zu<%zu"), + datalen, sizeof(h)); + return; + } + + memcpy(&h, data, sizeof(h)); + data += sizeof(h); + datalen -= sizeof(h); + + len = ntohs(h.len); + if (datalen < len) { + AddLog(LOG_LEVEL_ERROR, + TUYAMCUBR_FMT("status data short %zu<%zu"), + datalen, len); + return; + } + + b = data; + data += len; + datalen -= len; + + dt = tuyamcubr_find_data_type(h.type); + if (dt == NULL || + dt->t_len == -1) { /* XXX revisit this */ + AddLog(LOG_LEVEL_INFO, + TUYAMCUBR_FMT("DpId %u unsupported type 0x%02x"), + h.dpid, h.type); + continue; + } + + if (len != dt->t_len) { + AddLog(LOG_LEVEL_ERROR, + TUYAMCUBR_FMT("%s%s%u: unexpected len %zu"), + D_CMND_TUYAMCUBR_PREFIX, dt->t_name, len); + continue; + } + + value = dt->t_rd(b); + if (value > dt->t_max) { + AddLog(LOG_LEVEL_ERROR, + TUYAMCUBR_FMT("%s%s%u: unexpected value %u>%u"), + D_CMND_TUYAMCUBR_PREFIX, dt->t_name, value, + dt->t_max); + continue; + } + + dp = tuyamcubr_find_dp(sc, h.dpid, h.type); + if (dp == NULL) { + dp = (struct tuyamcubr_dp *)malloc(sizeof(*dp)); + if (dp == NULL) { + AddLog(LOG_LEVEL_ERROR, + TUYAMCUBR_FMT("%s%s%u no memory"), + D_CMND_TUYAMCUBR_PREFIX, + tuyamcubr_data_types[h.type], h.dpid); + continue; + } + + dp->dp_id = h.dpid; + dp->dp_type = h.type; + STAILQ_INSERT_TAIL(&sc->sc_dps, dp, dp_entry); + } else if (dp->dp_value == value) { + /* nop */ + continue; + } + + dp->dp_value = value; + tuyamcubr_rule_dp(sc, dp); + tuyamcubr_publish_dp(sc, dp); + } while (datalen > 0); +} + +static void +tuyamcubr_tick(struct tuyamcubr_softc *sc, unsigned int ms) +{ + int diff; + + sc->sc_clock += ms; + + diff = sc->sc_clock - sc->sc_deadline; + if (diff < 0) { + /* deadline hasn't been reached, nothing to do */ + return; + } + + switch (sc->sc_state) { + case TUYAMCUBR_S_START: + tuyamcubr_send_heartbeat(sc, 3000); + break; + case TUYAMCUBR_S_RUNNING: + tuyamcubr_send_heartbeat(sc, 15000); + if (sc->sc_waiting) { + AddLog(LOG_LEVEL_ERROR, + TUYAMCUBR_FMT("no heartbeat response")); + /* XXX restart? */ + } + sc->sc_waiting = 1; + break; + } +} + +static void +tuyamcubr_every_1sec(struct tuyamcubr_softc *sc) +{ + /* start with the assumption that wifi is configured */ + uint8_t network_status = TUYAMCUBR_NETWORK_STATUS_3; + + if (MqttIsConnected()) { + /* the device is connected to the "cloud" */ + network_status = TUYAMCUBR_NETWORK_STATUS_5; + } else { + switch (WifiState()) { + case WIFI_MANAGER: + /* Pairing in AP mode */ + network_status = TUYAMCUBR_NETWORK_STATUS_2; + break; + case WIFI_RESTART: + /* WiFi + router */ + network_status = TUYAMCUBR_NETWORK_STATUS_4; + break; + } + } + + if (sc->sc_network_status != network_status) { + sc->sc_network_status = network_status; + + if (sc->sc_state == TUYAMCUBR_S_RUNNING) { + tuyamcubr_send(sc, TUYAMCUBR_CMD_WIFI_STATE, + &network_status, sizeof(network_status)); + } + } +} + +static void +tuyamcubr_pre_init(void) +{ + struct tuyamcubr_softc *sc; + int baudrate; + + /* + * SetOption97 - Set Baud rate for TuyaMCU serial communication + * (0 = 9600 or 1 = 115200) + */ + baudrate = (Settings->flag4.tuyamcu_baudrate) ? 115200 : 9600; + + if (!PinUsed(GPIO_TUYAMCUBR_TX) || !PinUsed(GPIO_TUYAMCUBR_RX)) + return; + + sc = (struct tuyamcubr_softc *)calloc(1, sizeof(*sc)); + if (sc == NULL) { + AddLog(LOG_LEVEL_ERROR, + TUYAMCUBR_FMT("unable to allocate state")); + return; + } + + sc->sc_parser.p_state = TUYAMCUBR_P_START; + + sc->sc_state = TUYAMCUBR_S_START; + sc->sc_clock = 0; + sc->sc_network_status = (WifiState() == WIFI_MANAGER) ? + TUYAMCUBR_NETWORK_STATUS_2 : TUYAMCUBR_NETWORK_STATUS_3; + STAILQ_INIT(&sc->sc_dps); + + sc->sc_serial = new TasmotaSerial(Pin(GPIO_TUYAMCUBR_RX), + Pin(GPIO_TUYAMCUBR_TX), 2); + if (!sc->sc_serial->begin(baudrate)) { + AddLog(LOG_LEVEL_ERROR, + TUYAMCUBR_FMT("unable to begin serial (baudrate %d)"), + baudrate); + goto del; + } + + if (sc->sc_serial->hardwareSerial()) + ClaimSerial(); + + /* commit */ + tuyamcubr_sc = sc; + + /* kick the state machine off */ + tuyamcubr_tick(sc, 0); + return; +del: + delete sc->sc_serial; +free: + free(sc); +} + +static void +tuyamcubr_loop(struct tuyamcubr_softc *sc) +{ + TasmotaSerial *serial = sc->sc_serial; + + while (serial->available()) { + yield(); + sc->sc_parser.p_state = tuyamcubr_parse(sc, serial->read()); + } +} + +/* + * Interface + */ + +static const char tuyamcubr_cmnd_names[] PROGMEM = + D_CMND_TUYAMCUBR_PREFIX + "|" D_CMND_TUYAMCUBR_DATA_BOOL + "|" D_CMND_TUYAMCUBR_DATA_VALUE + "|" D_CMND_TUYAMCUBR_DATA_ENUM + ; + +static void (*const tuyamcubr_cmnds[])(void) PROGMEM = { + &tuyamcubr_cmnd_data_bool, + &tuyamcubr_cmnd_data_value, + &tuyamcubr_cmnd_data_enum, +}; + +bool +Xdrv65(uint32_t function) +{ + bool result = false; + struct tuyamcubr_softc *sc; + + switch (function) { + case FUNC_PRE_INIT: + tuyamcubr_pre_init(); + return (false); + } + + sc = tuyamcubr_sc; + if (sc == NULL) + return (false); + + switch (function) { + case FUNC_LOOP: + tuyamcubr_loop(sc); + break; + +#if 0 + case FUNC_SET_DEVICE_POWER: + result = tuyamcubr_set_power(sc); + break; +#endif + + case FUNC_EVERY_100_MSECOND: + tuyamcubr_tick(sc, 100); + break; + + case FUNC_EVERY_50_MSECOND: + case FUNC_EVERY_200_MSECOND: + case FUNC_EVERY_250_MSECOND: + break; + case FUNC_EVERY_SECOND: + tuyamcubr_every_1sec(sc); + break; + +#if 0 + case FUNC_JSON_APPEND: + tuyamcubr_sensor(sc); + break; +#endif + case FUNC_AFTER_TELEPERIOD: + tuyamcubr_publish(sc); + break; + + case FUNC_COMMAND: + result = DecodeCommand(tuyamcubr_cmnd_names, tuyamcubr_cmnds); + break; + } + + return (result); +} + +#endif // USE_TUYAMCUBR diff --git a/tools/decode-status.py b/tools/decode-status.py index efc5d0d48..843a2d0e8 100755 --- a/tools/decode-status.py +++ b/tools/decode-status.py @@ -290,7 +290,7 @@ a_features = [[ "USE_SGP40","USE_LUXV30B","USE_CANSNIFFER","USE_QMC5883L", "USE_MODBUS_ENERGY","USE_SHELLY_PRO","USE_DALI","USE_BP1658CJ", "USE_DINGTIAN_RELAY","USE_HMC5883L","USE_LD2410","USE_ME007", - "USE_DISPLAY_TM1650","USE_PCA9632","","", + "USE_DISPLAY_TM1650","USE_PCA9632","USE_TUYAMCUBR","", "","","","", "","","","", "","","","", diff --git a/tools/lv_gpio/lv_gpio_enum.h b/tools/lv_gpio/lv_gpio_enum.h index d57740364..70b297099 100644 --- a/tools/lv_gpio/lv_gpio_enum.h +++ b/tools/lv_gpio/lv_gpio_enum.h @@ -209,6 +209,8 @@ ZIGBEE_RST = GPIO_ZIGBEE_RST DYP_RX = GPIO_DYP_RX MIEL_HVAC_TX = GPIO_MIEL_HVAC_TX MIEL_HVAC_RX = GPIO_MIEL_HVAC_RX +TUYAMCUBR_TX = GPIO_TUYAMCUBR_TX +TUYAMCUBR_RX = GPIO_TUYAMCUBR_RX WE517_TX = GPIO_WE517_TX WE517_RX = GPIO_WE517_RX AS608_TX = GPIO_AS608_TX From 9f8c8efac19f3ed9384d1bdf69b6681440f3f0c3 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 8 Jan 2023 17:37:23 +0100 Subject: [PATCH 119/262] Delete .xdrv_65_tuyamcubr.ino.swp --- .../.xdrv_65_tuyamcubr.ino.swp | Bin 32768 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 tasmota/tasmota_xdrv_driver/.xdrv_65_tuyamcubr.ino.swp diff --git a/tasmota/tasmota_xdrv_driver/.xdrv_65_tuyamcubr.ino.swp b/tasmota/tasmota_xdrv_driver/.xdrv_65_tuyamcubr.ino.swp deleted file mode 100644 index e97c202883be5731cc8c3788b63298369f39053e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32768 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 AnE(I) From 24105a74b24e1acd8eb51f9425d95ead85d146a5 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 8 Jan 2023 17:51:17 +0100 Subject: [PATCH 120/262] Save some RAM on ESP8266 --- tasmota/my_user_config.h | 2 +- tasmota/tasmota_support/support_a_i2c.ino | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index 7933a9343..e4455347e 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -533,7 +533,7 @@ #define USE_TUYA_MCU // Add support for Tuya Serial MCU #define TUYA_DIMMER_ID 0 // Default dimmer Id #define USE_TUYA_TIME // Add support for Set Time in Tuya MCU -#define USE_TUYAMCUBR // Add support for TuyaMCU Bridge +//#define USE_TUYAMCUBR // Add support for TuyaMCU Bridge #define USE_ARMTRONIX_DIMMERS // Add support for Armtronix Dimmers (+1k4 code) #define USE_PS_16_DZ // Add support for PS-16-DZ Dimmer (+2k code) #define USE_SONOFF_IFAN // Add support for Sonoff iFan02 and iFan03 (+2k code) diff --git a/tasmota/tasmota_support/support_a_i2c.ino b/tasmota/tasmota_support/support_a_i2c.ino index ebe9606c4..25d81427c 100644 --- a/tasmota/tasmota_support/support_a_i2c.ino +++ b/tasmota/tasmota_support/support_a_i2c.ino @@ -13,7 +13,11 @@ const uint8_t I2C_RETRY_COUNTER = 3; +#ifdef ESP8266 +uint32_t i2c_active[1][4] = { 0 }; +#else uint32_t i2c_active[2][4] = { 0 }; +#endif uint32_t i2c_buffer = 0; bool I2cBegin(int sda, int scl, uint32_t frequency = 100000); From a4fe1b88f98a3212a8420adb2f15139d8893d3cc Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 9 Jan 2023 11:04:52 +0100 Subject: [PATCH 121/262] Add HLW8032 8N1 --- tasmota/include/tasmota_template.h | 2 +- .../tasmota_xnrg_energy/xnrg_02_cse7766.ino | 18 ++++++++++++------ .../tasmota_xnrg_energy/xnrg_17_ornowe517.ino | 2 +- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/tasmota/include/tasmota_template.h b/tasmota/include/tasmota_template.h index 047e6766a..99358e81c 100644 --- a/tasmota/include/tasmota_template.h +++ b/tasmota/include/tasmota_template.h @@ -825,7 +825,7 @@ const uint16_t kGpioNiceList[] PROGMEM = { #endif #ifdef USE_CSE7766 AGPIO(GPIO_CSE7766_TX), // CSE7766 Serial interface (S31 and Pow R2) - AGPIO(GPIO_CSE7766_RX), // CSE7766 Serial interface (S31 and Pow R2) + AGPIO(GPIO_CSE7766_RX) + 2, // CSE7766 Serial interface (S31 and Pow R2) (1 = RX1 (8E1), 2 = RX2 (8N1)) #endif #ifdef USE_MCP39F501 AGPIO(GPIO_MCP39F5_TX), // MCP39F501 Serial interface (Shelly2) diff --git a/tasmota/tasmota_xnrg_energy/xnrg_02_cse7766.ino b/tasmota/tasmota_xnrg_energy/xnrg_02_cse7766.ino index fd2ccc11e..472f04cbc 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_02_cse7766.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_02_cse7766.ino @@ -225,11 +225,17 @@ void CseEverySecond(void) { void CseSnsInit(void) { // Software serial init needs to be done here as earlier (serial) interrupts may lead to Exceptions -// CseSerial = new TasmotaSerial(Pin(GPIO_CSE7766_RX), Pin(GPIO_CSE7766_TX), 1); - CseSerial = new TasmotaSerial(Pin(GPIO_CSE7766_RX), -1, 1); - if (CseSerial->begin(4800, SERIAL_8E1)) { + uint32_t pin_rx = Pin(GPIO_CSE7766_RX, GPIO_ANY); +// CseSerial = new TasmotaSerial(pin_rx, Pin(GPIO_CSE7766_TX), 1); + CseSerial = new TasmotaSerial(pin_rx, -1, 1); + + // 0 (1 = RX1 (8E1)), 1 (2 = RX2 (8N1)) + uint32_t option = GetPin(pin_rx) - AGPIO(GPIO_CSE7766_RX); + uint32_t config = (1 == option) ? SERIAL_8N1 : SERIAL_8E1; + if (CseSerial->begin(4800, config)) { if (CseSerial->hardwareSerial()) { - SetSerial(4800, TS_SERIAL_8E1); + config = (1 == option) ? TS_SERIAL_8N1 : TS_SERIAL_8E1; + SetSerial(4800, config); ClaimSerial(); } if (0 == Settings->param[P_CSE7766_INVALID_POWER]) { @@ -243,8 +249,8 @@ void CseSnsInit(void) { } void CseDrvInit(void) { -// if (PinUsed(GPIO_CSE7766_RX) && PinUsed(GPIO_CSE7766_TX)) { - if (PinUsed(GPIO_CSE7766_RX)) { +// if (PinUsed(GPIO_CSE7766_RX, GPIO_ANY) && PinUsed(GPIO_CSE7766_TX)) { + if (PinUsed(GPIO_CSE7766_RX, GPIO_ANY)) { Cse.rx_buffer = (uint8_t*)(malloc(CSE_BUFFER_SIZE)); if (Cse.rx_buffer != nullptr) { TasmotaGlobal.energy_driver = XNRG_02; diff --git a/tasmota/tasmota_xnrg_energy/xnrg_17_ornowe517.ino b/tasmota/tasmota_xnrg_energy/xnrg_17_ornowe517.ino index 3d1edf4e5..cbdb90d0f 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_17_ornowe517.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_17_ornowe517.ino @@ -189,7 +189,7 @@ void We517SnsInit(void) { if (result) { if (2 == result) { // AddLog(LOG_LEVEL_DEBUG, PSTR("ORNO: WE517 HW serial init 8E1 at %d baud"), WE517_SPEED); -// Serial.begin(WE517_SPEED, SERIAL_8E1); + Serial.begin(WE517_SPEED, SERIAL_8E1); ClaimSerial(); } Energy.phase_count = 3; From 8b70608e58f168ceeeae5cf92c26926ab8db0380 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 9 Jan 2023 13:53:07 +0100 Subject: [PATCH 122/262] Add more ESP32 logging --- tasmota/tasmota_xnrg_energy/xnrg_02_cse7766.ino | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tasmota/tasmota_xnrg_energy/xnrg_02_cse7766.ino b/tasmota/tasmota_xnrg_energy/xnrg_02_cse7766.ino index 472f04cbc..5b34b7668 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_02_cse7766.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_02_cse7766.ino @@ -233,11 +233,15 @@ void CseSnsInit(void) { uint32_t option = GetPin(pin_rx) - AGPIO(GPIO_CSE7766_RX); uint32_t config = (1 == option) ? SERIAL_8N1 : SERIAL_8E1; if (CseSerial->begin(4800, config)) { + config = (1 == option) ? TS_SERIAL_8N1 : TS_SERIAL_8E1; if (CseSerial->hardwareSerial()) { - config = (1 == option) ? TS_SERIAL_8N1 : TS_SERIAL_8E1; SetSerial(4800, config); ClaimSerial(); } +#ifdef ESP32 + AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Serial UART%d set to %s 4800 bit/s"), CseSerial->getUart(), GetSerialConfig(config).c_str()); +#endif + if (0 == Settings->param[P_CSE7766_INVALID_POWER]) { Settings->param[P_CSE7766_INVALID_POWER] = CSE_MAX_INVALID_POWER; // SetOption39 1..255 } From de900e17bb1dd20bf9d4df9e0ccc065b1d301f34 Mon Sep 17 00:00:00 2001 From: Barbudor Date: Mon, 9 Jan 2023 13:55:06 +0100 Subject: [PATCH 123/262] add CCS811_V2 in I2CDevices list (#17651) --- I2CDEVICES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/I2CDEVICES.md b/I2CDEVICES.md index 6523d9117..171b04fd7 100644 --- a/I2CDEVICES.md +++ b/I2CDEVICES.md @@ -45,6 +45,7 @@ Index | Define | Driver | Device | Address(es) | Description 22 | USE_MCP230xx | xsns_29 | MCP23017 | 0x20 - 0x26 | 16-bit I/O expander 23 | USE_MPR121 | xsns_30 | MPR121 | 0x5A - 0x5D | Proximity capacitive touch sensor 24 | USE_CCS811 | xsns_31 | CCS811 | 0x5A | Gas (TVOC) and air quality sensor + 24' | USE_CCS811_V2 | xsns_31 | CCS811 | 0x5A - 0x5B | Gas (TVOC) and air quality sensor 25 | USE_MPU6050 | xsns_32 | MPU6050 | 0x68 - 0x69 | 3-axis gyroscope and temperature sensor 26 | USE_DS3231 | xsns_33 | DS3231 | 0x68 | Real time clock 27 | USE_MGC3130 | xsns_36 | MGC3130 | 0x42 | Electric field sensor From 12b2dd2e505564e02c57a931e8d13e3a94827aed Mon Sep 17 00:00:00 2001 From: bovirus <1262554+bovirus@users.noreply.github.com> Date: Tue, 10 Jan 2023 08:58:52 +0100 Subject: [PATCH 124/262] Update italian language (#17662) --- tasmota/language/it_IT.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tasmota/language/it_IT.h b/tasmota/language/it_IT.h index 19a763846..a7b12b8de 100644 --- a/tasmota/language/it_IT.h +++ b/tasmota/language/it_IT.h @@ -28,7 +28,7 @@ * Use online command StateText to translate ON, OFF, HOLD and TOGGLE. * Use online command Prefix to translate cmnd, stat and tele. * - * Updated until v9.4.0.1 - Last update 07.12.2022 + * Updated until v9.4.0.1 - Last update 09.01.2023 \*********************************************************************/ #define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -917,8 +917,8 @@ #define D_SENSOR_FLOWRATEMETER "Portata" #define D_SENSOR_ME007_TRIG "ME007 - Tri" #define D_SENSOR_ME007_RX "ME007 - RX" -#define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" -#define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" +#define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr - TX" +#define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr - RX" // Units #define D_UNIT_AMPERE "A" From b0094a0ddf2d2710efd4604eadeb5f25c17ae4a9 Mon Sep 17 00:00:00 2001 From: Ralph Maschotta Date: Tue, 10 Jan 2023 08:59:33 +0100 Subject: [PATCH 125/262] fix (PR #17643) BMP/BME sensors on two I2C buses: copy/paste typo (#17663) --- tasmota/tasmota_xsns_sensor/xsns_09_bmp.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasmota/tasmota_xsns_sensor/xsns_09_bmp.ino b/tasmota/tasmota_xsns_sensor/xsns_09_bmp.ino index cc43154fd..136d4e912 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_09_bmp.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_09_bmp.ino @@ -283,7 +283,7 @@ bool Bmx280Calibrate(uint8_t bmp_idx) { Bme280CalibrationData[bmp_idx].dig_H2 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H2, bus); Bme280CalibrationData[bmp_idx].dig_H3 = I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H3, bus); Bme280CalibrationData[bmp_idx].dig_H4 = (I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H4, bus) << 4) | (I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H4 + 1,bus) & 0xF); - Bme280CalibrationData[bmp_idx].dig_H5 = (I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H5 + 1, bus) << 4) | (I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H5,bus>>1) >> 4); + Bme280CalibrationData[bmp_idx].dig_H5 = (I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H5 + 1, bus) << 4) | (I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H5,bus) >> 4); Bme280CalibrationData[bmp_idx].dig_H6 = (int8_t)I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H6, bus); I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONTROL, 0x00, bus); // sleep mode since writes to config can be ignored in normal mode (Datasheet 5.4.5/6 page 27) // Set before CONTROL_meas (DS 5.4.3) From f9177dfa3ac24a960851db5fab6a96170f585a86 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Tue, 10 Jan 2023 09:48:49 +0100 Subject: [PATCH 126/262] Revert CSE7766 8N1 support - not needed --- tasmota/include/tasmota_template.h | 4 ++-- .../tasmota_xnrg_energy/xnrg_02_cse7766.ino | 22 +++++-------------- 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/tasmota/include/tasmota_template.h b/tasmota/include/tasmota_template.h index 99358e81c..700481241 100644 --- a/tasmota/include/tasmota_template.h +++ b/tasmota/include/tasmota_template.h @@ -204,7 +204,7 @@ enum UserSelectablePins { GPIO_LD2410_TX, GPIO_LD2410_RX, // HLK-LD2410 GPIO_MBR_TX_ENA, GPIO_NRG_MBS_TX_ENA, // Modbus Bridge Serial Transmit Enable GPIO_ME007_TRIG, GPIO_ME007_RX, // ME007 Serial/Trigger interface - GPIO_TUYAMCUBR_TX, GPIO_TUYAMCUBR_RX, // TuyaMCU Bridge + GPIO_TUYAMCUBR_TX, GPIO_TUYAMCUBR_RX, // TuyaMCU Bridge GPIO_SENSOR_END }; // Error as warning to rethink GPIO usage with max 2045 @@ -825,7 +825,7 @@ const uint16_t kGpioNiceList[] PROGMEM = { #endif #ifdef USE_CSE7766 AGPIO(GPIO_CSE7766_TX), // CSE7766 Serial interface (S31 and Pow R2) - AGPIO(GPIO_CSE7766_RX) + 2, // CSE7766 Serial interface (S31 and Pow R2) (1 = RX1 (8E1), 2 = RX2 (8N1)) + AGPIO(GPIO_CSE7766_RX), // CSE7766 Serial interface (S31 and Pow R2) #endif #ifdef USE_MCP39F501 AGPIO(GPIO_MCP39F5_TX), // MCP39F501 Serial interface (Shelly2) diff --git a/tasmota/tasmota_xnrg_energy/xnrg_02_cse7766.ino b/tasmota/tasmota_xnrg_energy/xnrg_02_cse7766.ino index 5b34b7668..fd2ccc11e 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_02_cse7766.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_02_cse7766.ino @@ -225,23 +225,13 @@ void CseEverySecond(void) { void CseSnsInit(void) { // Software serial init needs to be done here as earlier (serial) interrupts may lead to Exceptions - uint32_t pin_rx = Pin(GPIO_CSE7766_RX, GPIO_ANY); -// CseSerial = new TasmotaSerial(pin_rx, Pin(GPIO_CSE7766_TX), 1); - CseSerial = new TasmotaSerial(pin_rx, -1, 1); - - // 0 (1 = RX1 (8E1)), 1 (2 = RX2 (8N1)) - uint32_t option = GetPin(pin_rx) - AGPIO(GPIO_CSE7766_RX); - uint32_t config = (1 == option) ? SERIAL_8N1 : SERIAL_8E1; - if (CseSerial->begin(4800, config)) { - config = (1 == option) ? TS_SERIAL_8N1 : TS_SERIAL_8E1; +// CseSerial = new TasmotaSerial(Pin(GPIO_CSE7766_RX), Pin(GPIO_CSE7766_TX), 1); + CseSerial = new TasmotaSerial(Pin(GPIO_CSE7766_RX), -1, 1); + if (CseSerial->begin(4800, SERIAL_8E1)) { if (CseSerial->hardwareSerial()) { - SetSerial(4800, config); + SetSerial(4800, TS_SERIAL_8E1); ClaimSerial(); } -#ifdef ESP32 - AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Serial UART%d set to %s 4800 bit/s"), CseSerial->getUart(), GetSerialConfig(config).c_str()); -#endif - if (0 == Settings->param[P_CSE7766_INVALID_POWER]) { Settings->param[P_CSE7766_INVALID_POWER] = CSE_MAX_INVALID_POWER; // SetOption39 1..255 } @@ -253,8 +243,8 @@ void CseSnsInit(void) { } void CseDrvInit(void) { -// if (PinUsed(GPIO_CSE7766_RX, GPIO_ANY) && PinUsed(GPIO_CSE7766_TX)) { - if (PinUsed(GPIO_CSE7766_RX, GPIO_ANY)) { +// if (PinUsed(GPIO_CSE7766_RX) && PinUsed(GPIO_CSE7766_TX)) { + if (PinUsed(GPIO_CSE7766_RX)) { Cse.rx_buffer = (uint8_t*)(malloc(CSE_BUFFER_SIZE)); if (Cse.rx_buffer != nullptr) { TasmotaGlobal.energy_driver = XNRG_02; From 922fd6ca5ce2554ab4650b0d5851000aeee07c69 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Tue, 10 Jan 2023 15:39:31 +0100 Subject: [PATCH 127/262] add Tooltipps and more Commands --- .vscode/settings.json | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/.vscode/settings.json b/.vscode/settings.json index 330a1092f..0188fe67c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,7 +1,18 @@ { "platformio-ide.toolbar": [ + { + "text": "$(home)", + "tooltip": "PlatformIO: Home", + "commands": [ + { + "id": "platformio-ide.runPIOCoreCommand", + "args": "pio home" + } + ] + }, { "text": "$(trash)", + "tooltip": "PlatformIO: Clean All", "commands": [ { "id": "workbench.action.tasks.runTask", @@ -11,6 +22,7 @@ }, { "text": "$(check)", + "tooltip": "PlatformIO: Build", "commands": [ { "id": "workbench.action.tasks.runTask", @@ -20,6 +32,7 @@ }, { "text": "$(zap)", + "tooltip": "PlatformIO: Build and Upload", "commands": [ { "id": "workbench.action.tasks.runTask", @@ -29,6 +42,7 @@ }, { "text": "$(flame)", + "tooltip": "PlatformIO: Build, Erase and Upload", "commands": [ { "id": "platformio-ide.runPIOCoreCommand", @@ -38,12 +52,24 @@ }, { "text": "$(device-desktop)", + "tooltip": "PlatformIO: Serial Monitor", "commands": [ { "id": "workbench.action.tasks.runTask", "args": "PlatformIO: Monitor" } ] + }, + { + "text": "$(refresh)", + "tooltip": "PlatformIO: Rebuild IntelliSense Index", + "commands": [ + { + "id": "workbench.action.tasks.runTask", + "args": "PlatformIO: Rebuild IntelliSense Index" + } + ] } ] } + From 0a0c8c6efdcf188f3ab3115f9d0af34006dbdfb8 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Tue, 10 Jan 2023 17:28:56 +0100 Subject: [PATCH 128/262] Rename tasmota4MB to tasmota-4MB (#17674) --- .github/workflows/Tasmota_build_devel.yml | 4 ++-- .github/workflows/Tasmota_build_master.yml | 4 ++-- .github/workflows/build_all_the_things.yml | 2 +- platformio_tasmota_env.ini | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/Tasmota_build_devel.yml b/.github/workflows/Tasmota_build_devel.yml index 30502be32..e60c45f7b 100644 --- a/.github/workflows/Tasmota_build_devel.yml +++ b/.github/workflows/Tasmota_build_devel.yml @@ -58,7 +58,7 @@ jobs: matrix: variant: - tasmota - - tasmota4M + - tasmota-4M - tasmota-minimal - tasmota-display - tasmota-ir @@ -200,7 +200,7 @@ jobs: mkdir -p ./firmware/map [ ! -f ./mv_firmware/map/* ] || mv ./mv_firmware/map/* ./firmware/map/ [ ! -f ./mv_firmware/firmware/tasmota.* ] || mv ./mv_firmware/firmware/tasmota.* ./firmware/tasmota/ - [ ! -f ./mv_firmware/firmware/tasmota4M.* ] || mv ./mv_firmware/firmware/tasmota4M.* ./firmware/tasmota/ + [ ! -f ./mv_firmware/firmware/tasmota-4M.* ] || mv ./mv_firmware/firmware/tasmota-4M.* ./firmware/tasmota/ [ ! -f ./mv_firmware/firmware/tasmota-sensors.* ] || mv ./mv_firmware/firmware/tasmota-sensors.* ./firmware/tasmota/ [ ! -f ./mv_firmware/firmware/tasmota-minimal.bin.gz ] || mv ./mv_firmware/firmware/tasmota-minimal.bin.gz ./firmware/tasmota/ [ ! -f ./mv_firmware/firmware/tasmota-lite.* ] || mv ./mv_firmware/firmware/tasmota-lite.* ./firmware/tasmota/ diff --git a/.github/workflows/Tasmota_build_master.yml b/.github/workflows/Tasmota_build_master.yml index 8bd536243..2a9955b7d 100644 --- a/.github/workflows/Tasmota_build_master.yml +++ b/.github/workflows/Tasmota_build_master.yml @@ -57,7 +57,7 @@ jobs: matrix: variant: - tasmota - - tasmota4M + - tasmota-4M - tasmota-minimal - tasmota-display - tasmota-ir @@ -208,7 +208,7 @@ jobs: mkdir -p ./release-firmware/map [ ! -f ./mv_firmware/map/* ] || mv ./mv_firmware/map/* ./release-firmware/map/ [ ! -f ./mv_firmware/firmware/tasmota.* ] || mv ./mv_firmware/firmware/tasmota.* ./release-firmware/tasmota/ - [ ! -f ./mv_firmware/firmware/tasmota4M.* ] || mv ./mv_firmware/firmware/tasmota4M.* ./release-firmware/tasmota/ + [ ! -f ./mv_firmware/firmware/tasmota-4M.* ] || mv ./mv_firmware/firmware/tasmota-4M.* ./release-firmware/tasmota/ [ ! -f ./mv_firmware/firmware/tasmota-sensors.* ] || mv ./mv_firmware/firmware/tasmota-sensors.* ./release-firmware/tasmota/ [ ! -f ./mv_firmware/firmware/tasmota-minimal.bin.gz ] || mv ./mv_firmware/firmware/tasmota-minimal.bin.gz ./release-firmware/tasmota/ [ ! -f ./mv_firmware/firmware/tasmota-lite.* ] || mv ./mv_firmware/firmware/tasmota-lite.* ./release-firmware/tasmota/ diff --git a/.github/workflows/build_all_the_things.yml b/.github/workflows/build_all_the_things.yml index 15b07ba1b..3f89214e3 100644 --- a/.github/workflows/build_all_the_things.yml +++ b/.github/workflows/build_all_the_things.yml @@ -81,7 +81,7 @@ jobs: matrix: variant: - tasmota - - tasmota4M + - tasmota-4M - tasmota-display - tasmota-ir - tasmota-knx diff --git a/platformio_tasmota_env.ini b/platformio_tasmota_env.ini index bce085213..a7cf65cea 100644 --- a/platformio_tasmota_env.ini +++ b/platformio_tasmota_env.ini @@ -33,7 +33,7 @@ lib_ignore = [env:tasmota] -[env:tasmota4M] +[env:tasmota-4M] board = esp8266_4M2M [env:tasmota-minimal] From f1763d34cf250c7d2f9ff4d75f8694e8258e9b16 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Wed, 11 Jan 2023 10:31:39 +0100 Subject: [PATCH 129/262] Update changelogs --- CHANGELOG.md | 1 + RELEASENOTES.md | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed9962a35..c27879a10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ All notable changes to this project will be documented in this file. - Energy dummy switched voltage and power regression from v12.2.0.2 - Orno WE517 modbus serial config 8E1 setting (#17545) - No IP address shown when in AP mode regression from v12.3.1.1 (#17599) +- Rename ``tasmota4M.bin`` to ``tasmota-4M.bin`` to solve use of ``tasmota-minimal.bin`` (#17674) ### Removed diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 8637d2ae9..9aa0b4f61 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -55,7 +55,7 @@ Easy initial installation of Tasmota can be performed using the [Tasmota WebInst The following binary downloads have been compiled with ESP8266/Arduino library core version **2.7.4.9**. - **tasmota.bin** = The Tasmota version with most drivers for 1M+ flash. **RECOMMENDED RELEASE BINARY** -- **tasmota4M.bin** = The Tasmota version with most drivers and filesystem for 4M+ flash. +- **tasmota-4M.bin** = The Tasmota version with most drivers and filesystem for 4M+ flash. - **tasmota-AD.bin** to **tasmota-VN.bin** = The Tasmota version in different languages for 1M+ flash. - **tasmota-lite.bin** = The Lite version without most drivers and sensors for 1M+ flash. - **tasmota-knx.bin** = The Knx version without some features but adds KNX support for 1M+ flash. @@ -139,5 +139,6 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm - Shutter default motorstop set to 0 [#17403](https://github.com/arendst/Tasmota/issues/17403) - Shutter default tilt configuration [#17484](https://github.com/arendst/Tasmota/issues/17484) - Orno WE517 modbus serial config 8E1 setting [#17545](https://github.com/arendst/Tasmota/issues/17545) +- Rename ``tasmota4M.bin`` to ``tasmota-4M.bin`` to solve use of ``tasmota-minimal.bin`` [#17674](https://github.com/arendst/Tasmota/issues/17674) ### Removed From ef3d30c44f5fbc310053fb8d39c2565fc3926a8c Mon Sep 17 00:00:00 2001 From: Reinhard Date: Wed, 11 Jan 2023 11:50:16 +0100 Subject: [PATCH 130/262] Update xsns_47_max31865.ino (#17661) MAX31865 - make use of the already defined element 'ErrorCode' to transport the MAX31865 Fault Status Register to the JSON element 'Error' --- tasmota/tasmota_xsns_sensor/xsns_47_max31865.ino | 1 + 1 file changed, 1 insertion(+) diff --git a/tasmota/tasmota_xsns_sensor/xsns_47_max31865.ino b/tasmota/tasmota_xsns_sensor/xsns_47_max31865.ino index 6388f311c..38d387eb0 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_47_max31865.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_47_max31865.ino @@ -346,6 +346,7 @@ void MAX31865_GetResult(void) { uint16_t rtd; rtd = max31865[i].readRTD(); + MAX31865_Result[i].ErrorCode = max31865[i].readFault(); MAX31865_Result[i].Rtd = rtd; MAX31865_Result[i].PtdResistance = max31865[i].rtd_to_resistance(rtd, RefRes[i]); MAX31865_Result[i].PtdTemp = ConvertTemp(max31865[i].rtd_to_temperature(rtd, PtdRes[i], RefRes[i]) + PtdBias[i]); From 1acd9b867c6656ee12733dff52a44f268e020a95 Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Wed, 11 Jan 2023 22:59:07 +0100 Subject: [PATCH 131/262] Berry add implicit _class parameter to static methods (#17683) * Berry add implicit ``_class`` parameter to static methods * Handle bytecode --- CHANGELOG.md | 1 + lib/libesp32/berry/src/be_bytecode.c | 20 ++++++++++++++++++-- lib/libesp32/berry/src/be_code.c | 10 ++++++++++ lib/libesp32/berry/src/be_code.h | 1 + lib/libesp32/berry/src/be_object.h | 5 +++-- lib/libesp32/berry/src/be_parser.c | 17 +++++++++++++---- lib/libesp32/berry/src/be_solidifylib.c | 8 ++++++-- 7 files changed, 52 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c27879a10..ba3ec5ac0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ All notable changes to this project will be documented in this file. - Berry `bytes()` now evaluates to `false` if empty - Berry ``crypto.AES_CCM`` (required by Matter protocol) - ESP32 support for BMPxxx sensors on two I2C busses (#17643) +- Berry add implicit ``_class`` parameter to static methods ### Breaking Changed diff --git a/lib/libesp32/berry/src/be_bytecode.c b/lib/libesp32/berry/src/be_bytecode.c index 14599441d..a87b28fb8 100644 --- a/lib/libesp32/berry/src/be_bytecode.c +++ b/lib/libesp32/berry/src/be_bytecode.c @@ -206,7 +206,15 @@ static void save_constants(bvm *vm, void *fp, bproto *proto) bvalue *v = proto->ktab, *end; save_long(fp, proto->nconst); /* constants count */ for (end = v + proto->nconst; v < end; ++v) { - save_value(vm, fp, v); + if ((v == proto->ktab) && (proto->varg & BE_VA_STATICMETHOD) && (v->type == BE_CLASS)) { + /* implicit `_class` parameter, output nil */ + bvalue v_nil; + v_nil.v.i = 0; + v_nil.type = BE_NIL; + save_value(vm, fp, &v_nil); + } else { + save_value(vm, fp, v); + } } } @@ -428,7 +436,15 @@ static void load_class(bvm *vm, void *fp, bvalue *v, int version) be_incrtop(vm); if (load_proto(vm, fp, (bproto**)&var_toobj(value), -3, version)) { /* actual method */ - bbool is_method = ((bproto*)var_toobj(value))->varg & BE_VA_METHOD; + bproto *proto = (bproto*)var_toobj(value); + bbool is_method = proto->varg & BE_VA_METHOD; + if (!is_method) { + if ((proto->nconst > 0) && (proto->ktab->type == BE_NIL)) { + /* The first argument is nil so we replace with the class as implicit '_class' */ + proto->ktab->type = BE_CLASS; + proto->ktab->v.p = c; + } + } be_class_method_bind(vm, c, name, var_toobj(value), !is_method); } else { /* no proto, static member set to nil */ diff --git a/lib/libesp32/berry/src/be_code.c b/lib/libesp32/berry/src/be_code.c index 40e067265..1a890390e 100644 --- a/lib/libesp32/berry/src/be_code.c +++ b/lib/libesp32/berry/src/be_code.c @@ -927,4 +927,14 @@ void be_code_raise(bfuncinfo *finfo, bexpdesc *e1, bexpdesc *e2) free_expreg(finfo, e2); } +void be_code_implicit_class(bfuncinfo *finfo, bexpdesc *e, bclass *c) +{ + bvalue k; + k.type = BE_CLASS; + k.v.p = c; + int idx = newconst(finfo, &k); /* create new constant */ + e->type = ETCONST; /* new type is constant by index */ + e->v.idx = setK(idx); +} + #endif diff --git a/lib/libesp32/berry/src/be_code.h b/lib/libesp32/berry/src/be_code.h index 54d0c317c..cc45d4e06 100644 --- a/lib/libesp32/berry/src/be_code.h +++ b/lib/libesp32/berry/src/be_code.h @@ -39,5 +39,6 @@ void be_code_import(bfuncinfo *finfo, bexpdesc *m, bexpdesc *v); int be_code_exblk(bfuncinfo *finfo, int depth); void be_code_catch(bfuncinfo *finfo, int base, int ecnt, int vcnt, int *jmp); void be_code_raise(bfuncinfo *finfo, bexpdesc *e1, bexpdesc *e2); +void be_code_implicit_class(bfuncinfo *finfo, bexpdesc *e, bclass *c); #endif diff --git a/lib/libesp32/berry/src/be_object.h b/lib/libesp32/berry/src/be_object.h index dbde8317f..ac6e940bf 100644 --- a/lib/libesp32/berry/src/be_object.h +++ b/lib/libesp32/berry/src/be_object.h @@ -43,8 +43,9 @@ #define func_clearstatic(o) ((o)->type &= ~BE_STATIC) /* values for bproto.varg */ -#define BE_VA_VARARG (1 << 0) /* function has variable number of arguments */ -#define BE_VA_METHOD (1 << 1) /* function is a method (this is only a hint) */ +#define BE_VA_VARARG (1 << 0) /* function has variable number of arguments */ +#define BE_VA_METHOD (1 << 1) /* function is a method (this is only a hint) */ +#define BE_VA_STATICMETHOD (1 << 2) /* the function is a static method and has the class as implicit '_class' variable */ #define array_count(a) (sizeof(a) / sizeof((a)[0])) #define bcommon_header \ diff --git a/lib/libesp32/berry/src/be_parser.c b/lib/libesp32/berry/src/be_parser.c index 08b64899c..b3988fa60 100644 --- a/lib/libesp32/berry/src/be_parser.c +++ b/lib/libesp32/berry/src/be_parser.c @@ -29,6 +29,7 @@ #define FUNC_METHOD 1 #define FUNC_ANONYMOUS 2 +#define FUNC_STATIC 4 #if BE_INTGER_TYPE == 0 /* int */ #define M_IMAX INT_MAX @@ -608,7 +609,7 @@ static void func_varlist(bparser *parser) /* Parse a function includind arg list and body */ /* Given name and type (function or method) */ /* Returns `bproto` object */ -static bproto* funcbody(bparser *parser, bstring *name, int type) +static bproto* funcbody(bparser *parser, bstring *name, bclass *c, int type) { bfuncinfo finfo; bblockinfo binfo; @@ -621,6 +622,14 @@ static bproto* funcbody(bparser *parser, bstring *name, int type) finfo.proto->varg |= BE_VA_METHOD; } func_varlist(parser); /* parse arg list */ + if ((type & FUNC_STATIC) && (c != NULL)) { /* If static method, add an implicit local variable `_class` */ + bexpdesc e1, e2; + new_var(parser, parser_newstr(parser, "_class"), &e1); /* new implicit variable '_class' */ + init_exp(&e2, ETCONST, 0); + be_code_implicit_class(parser->finfo, &e2, c); + be_code_setvar(parser->finfo, &e1, &e2); + finfo.proto->varg |= BE_VA_STATICMETHOD; + } stmtlist(parser); /* parse statement without final `end` */ end_func(parser); /* close function context */ match_token(parser, KeyEnd); /* skip 'end' */ @@ -635,7 +644,7 @@ static void anon_func(bparser *parser, bexpdesc *e) bstring *name = parser_newstr(parser, "_anonymous_"); /* 'def' ID '(' varlist ')' block 'end' */ scan_next_token(parser); /* skip 'def' */ - proto = funcbody(parser, name, FUNC_ANONYMOUS); + proto = funcbody(parser, name, NULL, FUNC_ANONYMOUS); init_exp(e, ETPROTO, be_code_proto(parser->finfo, proto)); be_stackpop(parser->vm, 1); } @@ -1371,7 +1380,7 @@ static void def_stmt(bparser *parser) bfuncinfo *finfo = parser->finfo; /* 'def' ID '(' varlist ')' block 'end' */ scan_next_token(parser); /* skip 'def' */ - proto = funcbody(parser, func_name(parser, &e, 0), 0); + proto = funcbody(parser, func_name(parser, &e, 0), NULL, 0); be_code_closure(finfo, &e, be_code_proto(finfo, proto)); be_stackpop(parser->vm, 1); } @@ -1443,7 +1452,7 @@ static void classdef_stmt(bparser *parser, bclass *c, bbool is_static) scan_next_token(parser); /* skip 'def' */ name = func_name(parser, &e, 1); check_class_attr(parser, c, name); - proto = funcbody(parser, name, is_static ? 0 : FUNC_METHOD); + proto = funcbody(parser, name, c, is_static ? FUNC_STATIC : FUNC_METHOD); be_class_method_bind(parser->vm, c, proto->name, proto, is_static); be_stackpop(parser->vm, 1); } diff --git a/lib/libesp32/berry/src/be_solidifylib.c b/lib/libesp32/berry/src/be_solidifylib.c index 4cec95f99..9a9f45fe3 100644 --- a/lib/libesp32/berry/src/be_solidifylib.c +++ b/lib/libesp32/berry/src/be_solidifylib.c @@ -282,8 +282,12 @@ static void m_solidify_proto_inner_class(bvm *vm, bbool str_literal, bproto *pr, if (pr->nconst > 0) { for (int k = 0; k < pr->nconst; k++) { if (var_type(&pr->ktab[k]) == BE_CLASS) { - // output the class - m_solidify_subclass(vm, str_literal, (bclass*) var_toobj(&pr->ktab[k]), fout); + if ((k == 0) && (pr->varg & BE_VA_STATICMETHOD)) { + // it is the implicit '_class' variable from a static method, don't dump the class + } else { + // output the class + m_solidify_subclass(vm, str_literal, (bclass*) var_toobj(&pr->ktab[k]), fout); + } } } } From 9ba3c26a8a6550fc634da077c1c0b2202ed407b6 Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Thu, 12 Jan 2023 22:51:43 +0100 Subject: [PATCH 132/262] Berry fix crash when generating bytecode of empty class (#17688) --- lib/libesp32/berry/src/be_bytecode.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/libesp32/berry/src/be_bytecode.c b/lib/libesp32/berry/src/be_bytecode.c index a87b28fb8..14a5950fc 100644 --- a/lib/libesp32/berry/src/be_bytecode.c +++ b/lib/libesp32/berry/src/be_bytecode.c @@ -160,17 +160,19 @@ static bstring** save_members(bvm *vm, void *fp, bclass *c, int nvar) static void save_class(bvm *vm, void *fp, bclass *c) { bstring **vars; - int i, count = be_map_count(c->members); + int i, count = c->members ? be_map_count(c->members) : 0; int nvar = c->nvar - be_class_closure_count(c); save_string(fp, c->name); save_long(fp, nvar); /* member variables count */ save_long(fp, count - nvar); /* method count */ - vars = save_members(vm, fp, c, nvar); - if (vars != NULL) { - for (i = 0; i < nvar; ++i) { - save_string(fp, vars[i]); + if (count > 0) { + vars = save_members(vm, fp, c, nvar); + if (vars != NULL) { + for (i = 0; i < nvar; ++i) { + save_string(fp, vars[i]); + } + be_free(vm, vars, sizeof(bstring *) * nvar); } - be_free(vm, vars, sizeof(bstring *) * nvar); } } From 1a9e86a6b3bb1391c2c133e61d11c2f7b23b374c Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 13 Jan 2023 11:30:30 +0100 Subject: [PATCH 133/262] Fix ESP32 safeboot propagating upload --- tasmota/tasmota_support/support_tasmota.ino | 10 +++++++--- tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_flash.ino | 3 ++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/tasmota/tasmota_support/support_tasmota.ino b/tasmota/tasmota_support/support_tasmota.ino index 85055969f..0e8f7f7fd 100644 --- a/tasmota/tasmota_support/support_tasmota.ino +++ b/tasmota/tasmota_support/support_tasmota.ino @@ -1290,7 +1290,8 @@ void Every250mSeconds(void) if (TasmotaGlobal.ota_state_flag && CommandsReady()) { TasmotaGlobal.ota_state_flag--; if (2 == TasmotaGlobal.ota_state_flag) { -#ifdef CONFIG_IDF_TARGET_ESP32C3 +//#ifdef CONFIG_IDF_TARGET_ESP32C3 +#ifdef ESP32 OtaFactoryWrite(false); #endif RtcSettings.ota_loader = 0; // Try requested image first @@ -1372,7 +1373,8 @@ void Every250mSeconds(void) } else #endif // USE_WEBCLIENT_HTTPS if (EspSingleOtaPartition()) { -#ifdef CONFIG_IDF_TARGET_ESP32C3 +//#ifdef CONFIG_IDF_TARGET_ESP32C3 +#ifdef ESP32 OtaFactoryWrite(true); #endif RtcSettings.ota_loader = 1; // Try safeboot image next @@ -1542,10 +1544,12 @@ void Every250mSeconds(void) { if (!TasmotaGlobal.global_state.network_down) { #ifdef FIRMWARE_MINIMAL -#ifdef CONFIG_IDF_TARGET_ESP32C3 +//#ifdef CONFIG_IDF_TARGET_ESP32C3 +#ifdef ESP32 if (OtaFactoryRead()) { OtaFactoryWrite(false); TasmotaGlobal.ota_state_flag = 3; + AddLog(LOG_LEVEL_DEBUG, PSTR("OTA: Propagating upload")); } #endif if (1 == RtcSettings.ota_loader) { diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_flash.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_flash.ino index c1df40a33..ca0af5319 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_flash.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_flash.ino @@ -157,7 +157,8 @@ extern "C" { esp_partition_erase_range(otadata_partition, 0, SPI_FLASH_SEC_SIZE * 2); } if (force_ota) { -#ifdef CONFIG_IDF_TARGET_ESP32C3 +//#ifdef CONFIG_IDF_TARGET_ESP32C3 +#ifdef ESP32 OtaFactoryWrite(true); #endif RtcSettings.ota_loader = 1; // force OTA at next reboot From 094f45fe7ed2116f6515519630c41caf0a32f3c9 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 13 Jan 2023 11:47:58 +0100 Subject: [PATCH 134/262] Fix compilation without USE_IPV6 --- tasmota/tasmota_support/support_command.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasmota/tasmota_support/support_command.ino b/tasmota/tasmota_support/support_command.ino index 56ef3213f..3b08e1d16 100644 --- a/tasmota/tasmota_support/support_command.ino +++ b/tasmota/tasmota_support/support_command.ino @@ -846,7 +846,7 @@ void CmndStatus(void) EthernetHostname(), (uint32_t)EthernetLocalIP(), Settings->eth_ipv4_address[1], Settings->eth_ipv4_address[2], Settings->eth_ipv4_address[3], Settings->eth_ipv4_address[4], - EthernetMacAddress().c_str() + EthernetMacAddress().c_str()); #endif // USE_IPV6 #endif // USE_ETHERNET From 3bddbdc5c05f4784573e36168efca41f2b9697cc Mon Sep 17 00:00:00 2001 From: gemu Date: Fri, 13 Jan 2023 13:23:25 +0100 Subject: [PATCH 135/262] fix sml dumpmode (#17690) --- tasmota/tasmota_xsns_sensor/xsns_53_sml.ino | 195 +++++++++++--------- 1 file changed, 103 insertions(+), 92 deletions(-) diff --git a/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino b/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino index c65b1fbd3..3dbfe9e38 100755 --- a/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino @@ -681,98 +681,109 @@ void dump2log(void) { } } } else { - if (type == 'o') { - // obis - while (SML_SAVAILABLE) { - char c = SML_SREAD&0x7f; - if (c == '\n' || c == '\r') { - if (sml_globs.sml_logindex > 2) { - sml_globs.log_data[sml_globs.sml_logindex] = 0; - AddLogData(LOG_LEVEL_INFO, sml_globs.log_data); - sml_globs.log_data[0] = ':'; - sml_globs.log_data[1] = ' '; - sml_globs.sml_logindex = 2; - } - continue; - } - sml_globs.log_data[sml_globs.sml_logindex] = c; - if (sml_globs.sml_logindex < SML_DUMP_SIZE - 2) { - sml_globs.sml_logindex++; - } - } - } else if (type == 'v') { - // vbus - uint8_t c; - while (SML_SAVAILABLE) { - c = SML_SREAD; - if (c == VBUS_SYNC) { - sml_globs.log_data[sml_globs.sml_logindex] = 0; - AddLogData(LOG_LEVEL_INFO, sml_globs.log_data); - sml_globs.log_data[0] = ':'; - sml_globs.log_data[1] = ' '; - sml_globs.sml_logindex = 2; - } - sprintf(&sml_globs.log_data[sml_globs.sml_logindex], "%02x ", c); - if (sml_globs.sml_logindex < SML_DUMP_SIZE - 7) { - sml_globs.sml_logindex += 3; - } - } - } else if (type == 'e') { - // ebus - uint8_t c, p; - while (SML_SAVAILABLE) { - c = SML_SREAD; - if (c == EBUS_SYNC) { - p = SML_SPEAK; - if (p != EBUS_SYNC && sml_globs.sml_logindex > 5) { - // new packet, plot last one - sml_globs.log_data[sml_globs.sml_logindex] = 0; - AddLogData(LOG_LEVEL_INFO, sml_globs.log_data); - strcpy(&sml_globs.log_data[0], ": aa "); - sml_globs.sml_logindex = 5; - } - continue; - } - sprintf(&sml_globs.log_data[sml_globs.sml_logindex], "%02x ", c); - if (sml_globs.sml_logindex < SML_DUMP_SIZE - 7) { - sml_globs.sml_logindex += 3; - } - } - } else if (type == 's') { - // sml - uint8_t c; - while (SML_SAVAILABLE) { - c = SML_SREAD; - if (c == SML_SYNC) { - sml_globs.log_data[0] = ':'; - sml_globs.log_data[1] = ' '; - sml_globs.sml_logindex = 2; - } - sprintf(&sml_globs.log_data[sml_globs.sml_logindex], "%02x ", c); - if (sml_globs.sml_logindex < SML_DUMP_SIZE - 7) { - sml_globs.sml_logindex += 3; - } - } - } else { - // raw dump - d_lastms = millis(); - sml_globs.log_data[0] = ':'; - sml_globs.log_data[1] = ' '; - sml_globs.sml_logindex = 2; - while ((millis() - d_lastms) < 40) { - while (SML_SAVAILABLE) { - sprintf(&sml_globs.log_data[sml_globs.sml_logindex], "%02x ", SML_SREAD); - if (sml_globs.sml_logindex < SML_DUMP_SIZE - 7) { - sml_globs.sml_logindex += 3; - } else { - break; - } - } - } - if (sml_globs.sml_logindex > 2) { - sml_globs.log_data[sml_globs.sml_logindex] = 0; - AddLogData(LOG_LEVEL_INFO, sml_globs.log_data); - } + switch (type) { + case 'o': + // obis + while (SML_SAVAILABLE) { + char c = SML_SREAD&0x7f; + if (c == '\n' || c == '\r') { + if (sml_globs.sml_logindex > 2) { + sml_globs.log_data[sml_globs.sml_logindex] = 0; + AddLogData(LOG_LEVEL_INFO, sml_globs.log_data); + sml_globs.log_data[0] = ':'; + sml_globs.log_data[1] = ' '; + sml_globs.sml_logindex = 2; + } + continue; + } + sml_globs.log_data[sml_globs.sml_logindex] = c; + if (sml_globs.sml_logindex < SML_DUMP_SIZE - 2) { + sml_globs.sml_logindex++; + } + } + break; + case 'v': + // vbus + { uint8_t c; + while (SML_SAVAILABLE) { + c = SML_SREAD; + if (c == VBUS_SYNC) { + sml_globs.log_data[sml_globs.sml_logindex] = 0; + AddLogData(LOG_LEVEL_INFO, sml_globs.log_data); + sml_globs.log_data[0] = ':'; + sml_globs.log_data[1] = ' '; + sml_globs.sml_logindex = 2; + } + sprintf(&sml_globs.log_data[sml_globs.sml_logindex], "%02x ", c); + if (sml_globs.sml_logindex < SML_DUMP_SIZE - 7) { + sml_globs.sml_logindex += 3; + } + } + } + break; + case 'e': + // ebus + { uint8_t c, p; + while (SML_SAVAILABLE) { + c = SML_SREAD; + if (c == EBUS_SYNC) { + p = SML_SPEAK; + if (p != EBUS_SYNC && sml_globs.sml_logindex > 5) { + // new packet, plot last one + sml_globs.log_data[sml_globs.sml_logindex] = 0; + AddLogData(LOG_LEVEL_INFO, sml_globs.log_data); + strcpy(&sml_globs.log_data[0], ": aa "); + sml_globs.sml_logindex = 5; + } + continue; + } + sprintf(&sml_globs.log_data[sml_globs.sml_logindex], "%02x ", c); + if (sml_globs.sml_logindex < SML_DUMP_SIZE - 7) { + sml_globs.sml_logindex += 3; + } + } + } + break; + case 's': + // sml + { uint8_t c; + while (SML_SAVAILABLE) { + c = SML_SREAD; + if (c == SML_SYNC) { + sml_globs.log_data[sml_globs.sml_logindex] = 0; + AddLogData(LOG_LEVEL_INFO, sml_globs.log_data); + sml_globs.log_data[0] = ':'; + sml_globs.log_data[1] = ' '; + sml_globs.sml_logindex = 2; + } + sprintf(&sml_globs.log_data[sml_globs.sml_logindex], "%02x ", c); + if (sml_globs.sml_logindex < SML_DUMP_SIZE - 7) { + sml_globs.sml_logindex += 3; + } + } + } + break; + default: + // raw dump + d_lastms = millis(); + sml_globs.log_data[0] = ':'; + sml_globs.log_data[1] = ' '; + sml_globs.sml_logindex = 2; + while ((millis() - d_lastms) < 40) { + while (SML_SAVAILABLE) { + sprintf(&sml_globs.log_data[sml_globs.sml_logindex], "%02x ", SML_SREAD); + if (sml_globs.sml_logindex < SML_DUMP_SIZE - 7) { + sml_globs.sml_logindex += 3; + } else { + break; + } + } + } + if (sml_globs.sml_logindex > 2) { + sml_globs.log_data[sml_globs.sml_logindex] = 0; + AddLogData(LOG_LEVEL_INFO, sml_globs.log_data); + } + break; } } } From ce5e1df673b3f7c05274f4ac527503943c49797e Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 13 Jan 2023 17:06:16 +0100 Subject: [PATCH 136/262] Fix DNS lookup for ``upload`` Fix DNS lookup for ``upload`` from ota server using http regression from v12.3.1.1 --- CHANGELOG.md | 1 + .../src/HttpClientLight.cpp | 19 ++++++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ba3ec5ac0..a663d6195 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ All notable changes to this project will be documented in this file. - Orno WE517 modbus serial config 8E1 setting (#17545) - No IP address shown when in AP mode regression from v12.3.1.1 (#17599) - Rename ``tasmota4M.bin`` to ``tasmota-4M.bin`` to solve use of ``tasmota-minimal.bin`` (#17674) +- DNS lookup for ``upload`` from ota server using http regression from v12.3.1.1 ### Removed diff --git a/lib/libesp32/Berry-HttpClientLight/src/HttpClientLight.cpp b/lib/libesp32/Berry-HttpClientLight/src/HttpClientLight.cpp index d8c85b2ac..3b66ca539 100644 --- a/lib/libesp32/Berry-HttpClientLight/src/HttpClientLight.cpp +++ b/lib/libesp32/Berry-HttpClientLight/src/HttpClientLight.cpp @@ -39,6 +39,7 @@ #include #include "HttpClientLight.h" +#include "ESP8266WiFi.h" #ifdef USE_WEBCLIENT_HTTPS #include "WiFiClientSecureLightBearSSL.h" @@ -1158,9 +1159,21 @@ bool HTTPClientLight::connect(void) return false; } #endif - if(!_client->connect(_host.c_str(), _port, _connectTimeout)) { - log_d("failed connect to %s:%u", _host.c_str(), _port); - return false; + if (_protocol == "https") { + if(!_client->connect(_host.c_str(), _port, _connectTimeout)) { + log_d("failed connect to %s:%u", _host.c_str(), _port); + return false; + } + } else { + IPAddress remote_addr; + // Add include "ESP8266WiFi.h" for this to work + if (!WiFi.hostByName(_host.c_str(), remote_addr)) { + return false; + } + if(!_client->connect(remote_addr, _port, _connectTimeout)) { + log_d("failed connect to %s:%u", _host.c_str(), _port); + return false; + } } // set Timeout for WiFiClient and for Stream::readBytesUntil() and Stream::readStringUntil() From 13c16fd37b83be470a0725dbc089378d6053fe6d Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 13 Jan 2023 17:19:14 +0100 Subject: [PATCH 137/262] Fix xdrv_122_file_settings_demo (#17692) --- .../xdrv_122_file_settings_demo.ino | 62 +++++++++---------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_122_file_settings_demo.ino b/tasmota/tasmota_xdrv_driver/xdrv_122_file_settings_demo.ino index 8be544611..4406f0360 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_122_file_settings_demo.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_122_file_settings_demo.ino @@ -18,7 +18,7 @@ */ // Enable this define to use this demo -//#define USE_DRV_FILE_DEMO +#define USE_DRV_FILE_DEMO #ifdef USE_DRV_FILE_DEMO /*********************************************************************************************\ @@ -30,11 +30,11 @@ \*********************************************************************************************/ #warning **** USE_DRV_FILE_DEMO is enabled **** -#define XDRV_98 98 +#define XDRV_122 122 -#define DRV98_MAX_DRV_TEXT 16 +#define DRV_DEMO_MAX_DRV_TEXT 16 -const uint32_t DRV98_VERSION = 0x01010101; // Latest driver version (See settings deltas below) +const uint32_t DRV_DEMO_VERSION = 0x01010101; // Latest driver version (See settings deltas below) // Demo command line commands const char kDrvDemoCommands[] PROGMEM = "Drv|" // Prefix @@ -47,29 +47,29 @@ void (* const DrvDemoCommand[])(void) PROGMEM = { struct { uint32_t crc32; // To detect file changes uint32_t version; // To detect driver function changes - char drv_text[DRV98_MAX_DRV_TEXT -1][10]; -} Drv98Settings; + char drv_text[DRV_DEMO_MAX_DRV_TEXT -1][10]; +} DrvDemoSettings; // Global structure containing driver non-saved variables struct { uint32_t any_value; -} Drv98Global; +} DrvDemoGlobal; void CmndDrvText(void) { - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= DRV98_MAX_DRV_TEXT)) { + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= DRV_DEMO_MAX_DRV_TEXT)) { if (!XdrvMailbox.usridx) { // Command DrvText - for (uint32_t i = 0; i < DRV98_MAX_DRV_TEXT; i++) { - AddLog(LOG_LEVEL_DEBUG, PSTR("DRV: DrvText%02d %s"), i, Drv98Settings.drv_text[i]); + for (uint32_t i = 0; i < DRV_DEMO_MAX_DRV_TEXT; i++) { + AddLog(LOG_LEVEL_DEBUG, PSTR("DRV: DrvText%02d %s"), i, DrvDemoSettings.drv_text[i]); } ResponseCmndDone(); } else { // Command DrvText uint32_t index = XdrvMailbox.index -1; if (XdrvMailbox.data_len > 0) { - snprintf_P(Drv98Settings.drv_text[index], sizeof(Drv98Settings.drv_text[index]), XdrvMailbox.data); + snprintf_P(DrvDemoSettings.drv_text[index], sizeof(DrvDemoSettings.drv_text[index]), XdrvMailbox.data); } - ResponseCmndIdxChar(Drv98Settings.drv_text[index]); + ResponseCmndIdxChar(DrvDemoSettings.drv_text[index]); } } } @@ -80,7 +80,7 @@ void CmndDrvText(void) { uint32_t DrvDemoSettingsCrc32(void) { // Use Tasmota CRC calculation function - return GetCfgCrc32((uint8_t*)&Drv98Settings +4, sizeof(Drv98Settings) -4); // Skip crc32 + return GetCfgCrc32((uint8_t*)&DrvDemoSettings +4, sizeof(DrvDemoSettings) -4); // Skip crc32 } void DrvDemoSettingsDefault(void) { @@ -88,16 +88,16 @@ void DrvDemoSettingsDefault(void) { AddLog(LOG_LEVEL_INFO, PSTR("DRV: " D_USE_DEFAULTS)); - memset(&Drv98Settings, 0x00, sizeof(Drv98Settings)); - Drv98Settings.version = DRV98_VERSION; - // Init any other parameter in struct Drv98Settings - snprintf_P(Drv98Settings.drv_text[0], sizeof(Drv98Settings.drv_text[0]), PSTR("Azalea")); + memset(&DrvDemoSettings, 0x00, sizeof(DrvDemoSettings)); + DrvDemoSettings.version = DRV_DEMO_VERSION; + // Init any other parameter in struct DrvDemoSettings + snprintf_P(DrvDemoSettings.drv_text[0], sizeof(DrvDemoSettings.drv_text[0]), PSTR("Azalea")); } void DrvDemoSettingsDelta(void) { // Fix possible setting deltas - if (Drv98Settings.version != DRV98_VERSION) { // Fix version dependent changes + if (DrvDemoSettings.version != DRV_DEMO_VERSION) { // Fix version dependent changes if (Settings->version < 0x01010100) { AddLog(LOG_LEVEL_INFO, PSTR("DRV: Update oldest version restore")); @@ -109,7 +109,7 @@ void DrvDemoSettingsDelta(void) { } // Set current version and save settings - Drv98Settings.version = DRV98_VERSION; + DrvDemoSettings.version = DRV_DEMO_VERSION; DrvDemoSettingsSave(); } } @@ -120,17 +120,17 @@ void DrvDemoSettingsLoad(void) { // Init default values in case file is not found DrvDemoSettingsDefault(); - // Try to load file /.drvset098 + // Try to load file /.drvset122 char filename[20]; // Use for sensors: -// snprintf_P(filename, sizeof(filename), PSTR(TASM_FILE_SENSOR), XSNS_98); +// snprintf_P(filename, sizeof(filename), PSTR(TASM_FILE_SENSOR), XSNS_122); // Use for drivers: - snprintf_P(filename, sizeof(filename), PSTR(TASM_FILE_DRIVER), XDRV_98); + snprintf_P(filename, sizeof(filename), PSTR(TASM_FILE_DRIVER), XDRV_122); AddLog(LOG_LEVEL_INFO, PSTR("DRV: About to load settings from file %s"), filename); #ifdef USE_UFILESYS - if (TfsLoadFile(filename, (uint8_t*)&Drv98Settings, sizeof(Drv98Settings))) { + if (TfsLoadFile(filename, (uint8_t*)&DrvDemoSettings, sizeof(DrvDemoSettings))) { // Fix possible setting deltas DrvDemoSettingsDelta(); } else { @@ -141,26 +141,26 @@ void DrvDemoSettingsLoad(void) { AddLog(LOG_LEVEL_INFO, PSTR("DRV: ERROR File system not enabled")); #endif // USE_UFILESYS - Drv98Settings.crc32 = DrvDemoSettingsCrc32(); + DrvDemoSettings.crc32 = DrvDemoSettingsCrc32(); } void DrvDemoSettingsSave(void) { // Called from FUNC_SAVE_SETTINGS every SaveData second and at restart - if (DrvDemoSettingsCrc32() != Drv98Settings.crc32) { - // Try to save file /.drvset098 - Drv98Settings.crc32 = DrvDemoSettingsCrc32(); + if (DrvDemoSettingsCrc32() != DrvDemoSettings.crc32) { + // Try to save file /.drvset122 + DrvDemoSettings.crc32 = DrvDemoSettingsCrc32(); char filename[20]; // Use for sensors: -// snprintf_P(filename, sizeof(filename), PSTR(TASM_FILE_SENSOR), XSNS_98); +// snprintf_P(filename, sizeof(filename), PSTR(TASM_FILE_SENSOR), XSNS_122); // Use for drivers: - snprintf_P(filename, sizeof(filename), PSTR(TASM_FILE_DRIVER), XDRV_98); + snprintf_P(filename, sizeof(filename), PSTR(TASM_FILE_DRIVER), XDRV_122); AddLog(LOG_LEVEL_INFO, PSTR("DRV: About to save settings to file %s"), filename); #ifdef USE_UFILESYS - if (!TfsSaveFile(filename, (const uint8_t*)&Drv98Settings, sizeof(Drv98Settings))) { + if (!TfsSaveFile(filename, (const uint8_t*)&DrvDemoSettings, sizeof(DrvDemoSettings))) { // File system not ready: No flash space reserved for file system AddLog(LOG_LEVEL_INFO, PSTR("DRV: ERROR File system not ready or unable to save file")); } @@ -174,7 +174,7 @@ void DrvDemoSettingsSave(void) { * Interface \*********************************************************************************************/ -bool Xdrv98(uint32_t function) { +bool Xdrv122(uint32_t function) { bool result = false; switch (function) { From 6c04cf7076045b95f07a51a9e5d25982ae2b5661 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 13 Jan 2023 17:19:46 +0100 Subject: [PATCH 138/262] Update xdrv_122_file_settings_demo.ino --- tasmota/tasmota_xdrv_driver/xdrv_122_file_settings_demo.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_122_file_settings_demo.ino b/tasmota/tasmota_xdrv_driver/xdrv_122_file_settings_demo.ino index 4406f0360..117bebc83 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_122_file_settings_demo.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_122_file_settings_demo.ino @@ -18,7 +18,7 @@ */ // Enable this define to use this demo -#define USE_DRV_FILE_DEMO +//#define USE_DRV_FILE_DEMO #ifdef USE_DRV_FILE_DEMO /*********************************************************************************************\ From 4e60bd746542458478c47bedb7f12f34a004de95 Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Sat, 14 Jan 2023 11:38:51 +0100 Subject: [PATCH 139/262] Berry add `static class` to declare inner classes (#17699) --- CHANGELOG.md | 1 + lib/libesp32/berry/src/be_parser.c | 36 ++- lib/libesp32/berry/src/be_solidifylib.c | 3 + lib/libesp32/berry_tasmota/solidify_all.be | 4 +- .../src/solidify/solidified_animate_module.h | 12 + .../src/solidify/solidified_autoconf_module.h | 2 + .../solidified_crypto_spake2p_matter.h | 4 + .../src/solidify/solidified_driver_class.h | 2 + .../src/solidify/solidified_dyn.h | 2 + .../src/solidify/solidified_hue_bridge.h | 2 + .../src/solidify/solidified_i2c_axp192.h | 2 + .../src/solidify/solidified_i2c_axp202.h | 2 + .../src/solidify/solidified_i2c_driver.h | 2 + .../src/solidify/solidified_i2c_ft3663.h | 2 + .../src/solidify/solidified_leds.h | 228 +++++++++--------- .../src/solidify/solidified_leds_animator.h | 2 + .../src/solidify/solidified_lv_tasmota.h | 2 + .../solidify/solidified_lv_tasmota_widgets.h | 16 ++ .../src/solidify/solidified_mqtt.h | 4 + .../src/solidify/solidified_partition_core.h | 178 +++++++------- .../src/solidify/solidified_persist.h | 2 + .../src/solidify/solidified_tapp.h | 2 + .../src/solidify/solidified_tasmota_class.h | 2 + .../src/solidify/solidified_trigger_class.h | 2 + .../src/solidify/solidified_zigbee_zb_coord.h | 2 + .../solidified_zigbee_zcl_attribute.h | 6 + .../solidify/solidified_zigbee_zcl_frame.h | 2 + 27 files changed, 329 insertions(+), 195 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a663d6195..b4f8c20e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ All notable changes to this project will be documented in this file. - Berry ``crypto.AES_CCM`` (required by Matter protocol) - ESP32 support for BMPxxx sensors on two I2C busses (#17643) - Berry add implicit ``_class`` parameter to static methods +- Berry add ``static class`` to declare inner classes ### Breaking Changed diff --git a/lib/libesp32/berry/src/be_parser.c b/lib/libesp32/berry/src/be_parser.c index b3988fa60..5e58df6cc 100644 --- a/lib/libesp32/berry/src/be_parser.c +++ b/lib/libesp32/berry/src/be_parser.c @@ -407,7 +407,7 @@ static int new_localvar(bparser *parser, bstring *name) if (reg == -1) { bvalue *var; if (comp_is_strict(parser->vm)) { - if (find_localvar(finfo, name, 0) >= 0 && str(name)[0] != '.') { /* we do accept nested redifinition of internal variables starting with ':' */ + if (find_localvar(finfo, name, 0) >= 0 && str(name)[0] != '.') { /* we do accept nested redifinition of internal variables starting with '.' */ push_error(parser, "strict: redefinition of '%s' from outer scope", str(name)); } } @@ -1457,6 +1457,8 @@ static void classdef_stmt(bparser *parser, bclass *c, bbool is_static) be_stackpop(parser->vm, 1); } +static void classstaticclass_stmt(bparser *parser, bclass *c_out, bexpdesc *e_out); + static void classstatic_stmt(bparser *parser, bclass *c, bexpdesc *e) { bstring *name; @@ -1465,6 +1467,8 @@ static void classstatic_stmt(bparser *parser, bclass *c, bexpdesc *e) scan_next_token(parser); /* skip 'static' */ if (next_type(parser) == KeyDef) { /* 'static' 'def' ... */ classdef_stmt(parser, c, btrue); + } else if (next_type(parser) == KeyClass) { /* 'static' 'class' ... */ + classstaticclass_stmt(parser, c, e); } else { if (next_type(parser) == KeyVar) { scan_next_token(parser); /* skip 'var' if any */ @@ -1535,6 +1539,36 @@ static void class_stmt(bparser *parser) } } +static void classstaticclass_stmt(bparser *parser, bclass *c_out, bexpdesc *e_out) +{ + bstring *name; + /* [preceding 'static'] 'class' ID [':' ID] class_block 'end' */ + scan_next_token(parser); /* skip 'class' */ + if (match_id(parser, name) != NULL) { + bexpdesc e_class; /* new class object */ + check_class_attr(parser, c_out, name); /* check that the class names does not collide with another member */ + be_class_member_bind(parser->vm, c_out, name, bfalse); /* add the member slot as static */ + /* create the class object */ + bclass *c = be_newclass(parser->vm, name, NULL); + new_var(parser, name, &e_class); /* add a local var to the static initialization code for static members */ + be_code_class(parser->finfo, &e_class, c); + class_inherit(parser, &e_class); + class_block(parser, c, &e_class); + be_class_compress(parser->vm, c); /* compress class size */ + match_token(parser, KeyEnd); /* skip 'end' */ + /* add the code to copy the class object to the static member */ + bexpdesc e1 = *e_out; /* copy the class description */ + bexpdesc key; /* build the member key */ + init_exp(&key, ETSTRING, 0); + key.v.s = name; + /* assign the class to the static member */ + be_code_member(parser->finfo, &e1, &key); /* compute member accessor */ + be_code_setvar(parser->finfo, &e1, &e_class); /* set member */ + } else { + parser_error(parser, "class name error"); + } +} + static void import_stmt(bparser *parser) { bstring *name; /* variable name */ diff --git a/lib/libesp32/berry/src/be_solidifylib.c b/lib/libesp32/berry/src/be_solidifylib.c index 9a9f45fe3..58501e059 100644 --- a/lib/libesp32/berry/src/be_solidifylib.c +++ b/lib/libesp32/berry/src/be_solidifylib.c @@ -420,6 +420,9 @@ static void m_solidify_subclass(bvm *vm, bbool str_literal, bclass *cl, void* fo { const char * class_name = str(cl->name); + /* pre-declare class to support '_class' implicit variable */ + logfmt("\nextern const bclass be_class_%s;\n", class_name); + /* iterate on members to dump closures */ if (cl->members) { bmapnode *node; diff --git a/lib/libesp32/berry_tasmota/solidify_all.be b/lib/libesp32/berry_tasmota/solidify_all.be index 256632e75..7bfeae9dd 100755 --- a/lib/libesp32/berry_tasmota/solidify_all.be +++ b/lib/libesp32/berry_tasmota/solidify_all.be @@ -10,8 +10,8 @@ import solidify import string import re -# import sys -# sys.path().push('src/embedded') # allow to import from src/embedded +import sys +sys.path().push('src/embedded') # allow to import from src/embedded # globals that need to exist to make compilation succeed var globs = "path,ctypes_bytes_dyn,tasmota,ccronexpr,gpio,light,webclient,load,MD5,lv,light_state," diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_animate_module.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_animate_module.h index 30f7a47a0..4eea694a5 100644 --- a/lib/libesp32/berry_tasmota/src/solidify/solidified_animate_module.h +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_animate_module.h @@ -4,6 +4,8 @@ \********************************************************************/ #include "be_constobj.h" +extern const bclass be_class_Animate_rotate; + /******************************************************************** ** Solidified function: init ********************************************************************/ @@ -75,6 +77,8 @@ be_local_class(Animate_rotate, (bstring*) &be_const_str_Animate_rotate ); +extern const bclass be_class_Animate_from_to; + /******************************************************************** ** Solidified function: init ********************************************************************/ @@ -135,6 +139,8 @@ be_local_class(Animate_from_to, (bstring*) &be_const_str_Animate_from_to ); +extern const bclass be_class_Animate_back_forth; + /******************************************************************** ** Solidified function: init ********************************************************************/ @@ -216,6 +222,8 @@ be_local_class(Animate_back_forth, (bstring*) &be_const_str_Animate_back_forth ); +extern const bclass be_class_Animate_ins_goto; + /******************************************************************** ** Solidified function: init ********************************************************************/ @@ -263,6 +271,8 @@ be_local_class(Animate_ins_goto, (bstring*) &be_const_str_Animate_ins_goto ); +extern const bclass be_class_Animate_ins_ramp; + /******************************************************************** ** Solidified function: init ********************************************************************/ @@ -310,6 +320,8 @@ be_local_class(Animate_ins_ramp, (bstring*) &be_const_str_Animate_ins_ramp ); +extern const bclass be_class_Animate_engine; + /******************************************************************** ** Solidified function: run ********************************************************************/ diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_autoconf_module.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_autoconf_module.h index 16d3089dd..7e11b1145 100644 --- a/lib/libesp32/berry_tasmota/src/solidify/solidified_autoconf_module.h +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_autoconf_module.h @@ -4,6 +4,8 @@ \********************************************************************/ #include "be_constobj.h" +extern const bclass be_class_Autoconf; + /******************************************************************** ** Solidified function: page_autoconf_ctl ********************************************************************/ diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_crypto_spake2p_matter.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_crypto_spake2p_matter.h index 993c99b8c..5d430efaa 100644 --- a/lib/libesp32/berry_tasmota/src/solidify/solidified_crypto_spake2p_matter.h +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_crypto_spake2p_matter.h @@ -4,6 +4,8 @@ \********************************************************************/ #include "be_constobj.h" +extern const bclass be_class_SPAKE2P_Matter; + /******************************************************************** ** Solidified function: compute_pB ********************************************************************/ @@ -61,6 +63,8 @@ be_local_closure(SPAKE2P_Matter_compute_pB, /* name */ /*******************************************************************/ +extern const bclass be_class_SPAKE_Hasher; + /******************************************************************** ** Solidified function: init ********************************************************************/ diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_driver_class.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_driver_class.h index f36429f81..75351ee0c 100644 --- a/lib/libesp32/berry_tasmota/src/solidify/solidified_driver_class.h +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_driver_class.h @@ -4,6 +4,8 @@ \********************************************************************/ #include "be_constobj.h" +extern const bclass be_class_Driver; + /******************************************************************** ** Solidified function: add_cmd ********************************************************************/ diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_dyn.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_dyn.h index ccb1c98e5..ee7c762ca 100644 --- a/lib/libesp32/berry_tasmota/src/solidify/solidified_dyn.h +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_dyn.h @@ -4,6 +4,8 @@ \********************************************************************/ #include "be_constobj.h" +extern const bclass be_class_dyn; + /******************************************************************** ** Solidified function: tostring ********************************************************************/ diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_hue_bridge.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_hue_bridge.h index 8a7c11685..14f64cfa5 100644 --- a/lib/libesp32/berry_tasmota/src/solidify/solidified_hue_bridge.h +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_hue_bridge.h @@ -4,6 +4,8 @@ \********************************************************************/ #include "be_constobj.h" +extern const bclass be_class_hue_bridge_monad; + /******************************************************************** ** Solidified function: full_status ********************************************************************/ diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_i2c_axp192.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_i2c_axp192.h index 095930baf..2ef43a553 100644 --- a/lib/libesp32/berry_tasmota/src/solidify/solidified_i2c_axp192.h +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_i2c_axp192.h @@ -4,6 +4,8 @@ \********************************************************************/ #include "be_constobj.h" +extern const bclass be_class_AXP192; + /******************************************************************** ** Solidified function: set_dcdc_enable ********************************************************************/ diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_i2c_axp202.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_i2c_axp202.h index 1ec7a268b..a912b0660 100644 --- a/lib/libesp32/berry_tasmota/src/solidify/solidified_i2c_axp202.h +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_i2c_axp202.h @@ -4,6 +4,8 @@ \********************************************************************/ #include "be_constobj.h" +extern const bclass be_class_AXP202; + /******************************************************************** ** Solidified function: set_shutdown_time ********************************************************************/ diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_i2c_driver.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_i2c_driver.h index d63588613..e4ff81021 100644 --- a/lib/libesp32/berry_tasmota/src/solidify/solidified_i2c_driver.h +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_i2c_driver.h @@ -4,6 +4,8 @@ \********************************************************************/ #include "be_constobj.h" +extern const bclass be_class_I2C_Driver; + /******************************************************************** ** Solidified function: read32 ********************************************************************/ diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_i2c_ft3663.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_i2c_ft3663.h index 676e5299a..abfc6a453 100644 --- a/lib/libesp32/berry_tasmota/src/solidify/solidified_i2c_ft3663.h +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_i2c_ft3663.h @@ -4,6 +4,8 @@ \********************************************************************/ #include "be_constobj.h" +extern const bclass be_class_FT3663; + /******************************************************************** ** Solidified function: every_100ms ********************************************************************/ diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_leds.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_leds.h index d7ca9b0bd..13b452935 100644 --- a/lib/libesp32/berry_tasmota/src/solidify/solidified_leds.h +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_leds.h @@ -4,6 +4,8 @@ \********************************************************************/ #include "be_constobj.h" +extern const bclass be_class_Leds; + /******************************************************************** ** Solidified function: pixel_count ********************************************************************/ @@ -170,39 +172,43 @@ be_local_closure(Leds_clear, /* name */ ********************************************************************/ be_local_closure(Leds_matrix, /* name */ be_nested_proto( - 10, /* nstack */ + 11, /* nstack */ 4, /* argc */ - 0, /* varg */ + 4, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_nested_str(Leds), - /* K1 */ be_nested_str(create_matrix), - /* K2 */ be_const_int(0), + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_const_class(be_class_Leds), + /* K1 */ be_nested_str(Leds), + /* K2 */ be_nested_str(create_matrix), + /* K3 */ be_const_int(0), }), &be_const_str_matrix, &be_const_str_solidified, - ( &(const binstruction[11]) { /* code */ - 0xB8120000, // 0000 GETNGBL R4 K0 - 0x08140001, // 0001 MUL R5 R0 R1 - 0x5C180400, // 0002 MOVE R6 R2 - 0x5C1C0600, // 0003 MOVE R7 R3 - 0x7C100600, // 0004 CALL R4 3 - 0x8C140901, // 0005 GETMET R5 R4 K1 - 0x5C1C0000, // 0006 MOVE R7 R0 - 0x5C200200, // 0007 MOVE R8 R1 - 0x58240002, // 0008 LDCONST R9 K2 - 0x7C140800, // 0009 CALL R5 4 - 0x80040A00, // 000A RET 1 R5 + ( &(const binstruction[12]) { /* code */ + 0x58100000, // 0000 LDCONST R4 K0 + 0xB8160200, // 0001 GETNGBL R5 K1 + 0x08180001, // 0002 MUL R6 R0 R1 + 0x5C1C0400, // 0003 MOVE R7 R2 + 0x5C200600, // 0004 MOVE R8 R3 + 0x7C140600, // 0005 CALL R5 3 + 0x8C180B02, // 0006 GETMET R6 R5 K2 + 0x5C200000, // 0007 MOVE R8 R0 + 0x5C240200, // 0008 MOVE R9 R1 + 0x58280003, // 0009 LDCONST R10 K3 + 0x7C180800, // 000A CALL R6 4 + 0x80040C00, // 000B RET 1 R6 }) ) ); /*******************************************************************/ +extern const bclass be_class_Leds_segment; + /******************************************************************** ** Solidified function: get_pixel_color ********************************************************************/ @@ -735,6 +741,8 @@ be_local_closure(Leds_is_dirty, /* name */ /*******************************************************************/ +extern const bclass be_class_Leds_matrix; + /******************************************************************** ** Solidified function: pixels_buffer ********************************************************************/ @@ -1621,106 +1629,108 @@ be_local_closure(Leds_get_pixel_color, /* name */ ********************************************************************/ be_local_closure(Leds_assign_rmt, /* name */ be_nested_proto( - 8, /* nstack */ + 9, /* nstack */ 1, /* argc */ - 0, /* varg */ + 4, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[16]) { /* constants */ - /* K0 */ be_const_int(0), - /* K1 */ be_nested_str(value_error), - /* K2 */ be_nested_str(invalid_X20GPIO_X20number), - /* K3 */ be_nested_str(global), - /* K4 */ be_nested_str(contains), - /* K5 */ be_nested_str(_rmt), - /* K6 */ be_nested_str(gpio), - /* K7 */ be_nested_str(MAX_RMT), - /* K8 */ be_const_int(1), - /* K9 */ be_nested_str(push), - /* K10 */ be_nested_str(stop_iteration), - /* K11 */ be_nested_str(pin_used), - /* K12 */ be_nested_str(WS2812), - /* K13 */ be_nested_str(pin), - /* K14 */ be_nested_str(internal_error), - /* K15 */ be_nested_str(no_X20more_X20RMT_X20channel_X20available), + ( &(const bvalue[17]) { /* constants */ + /* K0 */ be_const_class(be_class_Leds), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str(value_error), + /* K3 */ be_nested_str(invalid_X20GPIO_X20number), + /* K4 */ be_nested_str(global), + /* K5 */ be_nested_str(contains), + /* K6 */ be_nested_str(_rmt), + /* K7 */ be_nested_str(gpio), + /* K8 */ be_nested_str(MAX_RMT), + /* K9 */ be_const_int(1), + /* K10 */ be_nested_str(push), + /* K11 */ be_nested_str(stop_iteration), + /* K12 */ be_nested_str(pin_used), + /* K13 */ be_nested_str(WS2812), + /* K14 */ be_nested_str(pin), + /* K15 */ be_nested_str(internal_error), + /* K16 */ be_nested_str(no_X20more_X20RMT_X20channel_X20available), }), &be_const_str_assign_rmt, &be_const_str_solidified, - ( &(const binstruction[71]) { /* code */ - 0x60040009, // 0000 GETGBL R1 G9 - 0x5C080000, // 0001 MOVE R2 R0 - 0x7C040200, // 0002 CALL R1 1 - 0x5C000200, // 0003 MOVE R0 R1 - 0x14040100, // 0004 LT R1 R0 K0 - 0x78060000, // 0005 JMPF R1 #0007 - 0xB0060302, // 0006 RAISE 1 K1 K2 - 0xA4060600, // 0007 IMPORT R1 K3 - 0x4C080000, // 0008 LDNIL R2 - 0x8C0C0304, // 0009 GETMET R3 R1 K4 - 0x58140005, // 000A LDCONST R5 K5 - 0x7C0C0400, // 000B CALL R3 2 - 0x740E0021, // 000C JMPT R3 #002F - 0x600C0012, // 000D GETGBL R3 G18 - 0x7C0C0000, // 000E CALL R3 0 - 0x5C080600, // 000F MOVE R2 R3 - 0x90060A02, // 0010 SETMBR R1 K5 R2 - 0x600C0010, // 0011 GETGBL R3 G16 - 0xB8120C00, // 0012 GETNGBL R4 K6 - 0x88100907, // 0013 GETMBR R4 R4 K7 - 0x04100908, // 0014 SUB R4 R4 K8 - 0x40120004, // 0015 CONNECT R4 K0 R4 - 0x7C0C0200, // 0016 CALL R3 1 - 0xA8020005, // 0017 EXBLK 0 #001E - 0x5C100600, // 0018 MOVE R4 R3 - 0x7C100000, // 0019 CALL R4 0 - 0x8C140509, // 001A GETMET R5 R2 K9 - 0x541DFFFE, // 001B LDINT R7 -1 - 0x7C140400, // 001C CALL R5 2 - 0x7001FFF9, // 001D JMP #0018 - 0x580C000A, // 001E LDCONST R3 K10 - 0xAC0C0200, // 001F CATCH R3 1 0 - 0xB0080000, // 0020 RAISE 2 R0 R0 - 0xB80E0C00, // 0021 GETNGBL R3 K6 - 0x8C0C070B, // 0022 GETMET R3 R3 K11 - 0xB8160C00, // 0023 GETNGBL R5 K6 - 0x88140B0C, // 0024 GETMBR R5 R5 K12 - 0x58180000, // 0025 LDCONST R6 K0 - 0x7C0C0600, // 0026 CALL R3 3 - 0x780E0006, // 0027 JMPF R3 #002F - 0xB80E0C00, // 0028 GETNGBL R3 K6 - 0x8C0C070D, // 0029 GETMET R3 R3 K13 - 0xB8160C00, // 002A GETNGBL R5 K6 - 0x88140B0C, // 002B GETMBR R5 R5 K12 - 0x58180000, // 002C LDCONST R6 K0 - 0x7C0C0600, // 002D CALL R3 3 - 0x980A0003, // 002E SETIDX R2 K0 R3 - 0x88080305, // 002F GETMBR R2 R1 K5 - 0x580C0000, // 0030 LDCONST R3 K0 - 0x5411FFFE, // 0031 LDINT R4 -1 - 0xB8160C00, // 0032 GETNGBL R5 K6 - 0x88140B07, // 0033 GETMBR R5 R5 K7 - 0x14140605, // 0034 LT R5 R3 R5 - 0x7816000A, // 0035 JMPF R5 #0041 - 0x94140403, // 0036 GETIDX R5 R2 R3 - 0x1C180A00, // 0037 EQ R6 R5 R0 - 0x781A0000, // 0038 JMPF R6 #003A - 0x80040600, // 0039 RET 1 R3 - 0x14180B00, // 003A LT R6 R5 K0 - 0x781A0002, // 003B JMPF R6 #003F - 0x14180900, // 003C LT R6 R4 K0 - 0x781A0000, // 003D JMPF R6 #003F - 0x5C100600, // 003E MOVE R4 R3 - 0x000C0708, // 003F ADD R3 R3 K8 - 0x7001FFF0, // 0040 JMP #0032 - 0x28140900, // 0041 GE R5 R4 K0 - 0x78160001, // 0042 JMPF R5 #0045 - 0x98080800, // 0043 SETIDX R2 R4 R0 - 0x80040800, // 0044 RET 1 R4 - 0xB0061D0F, // 0045 RAISE 1 K14 K15 - 0x80000000, // 0046 RET 0 + ( &(const binstruction[72]) { /* code */ + 0x58040000, // 0000 LDCONST R1 K0 + 0x60080009, // 0001 GETGBL R2 G9 + 0x5C0C0000, // 0002 MOVE R3 R0 + 0x7C080200, // 0003 CALL R2 1 + 0x5C000400, // 0004 MOVE R0 R2 + 0x14080101, // 0005 LT R2 R0 K1 + 0x780A0000, // 0006 JMPF R2 #0008 + 0xB0060503, // 0007 RAISE 1 K2 K3 + 0xA40A0800, // 0008 IMPORT R2 K4 + 0x4C0C0000, // 0009 LDNIL R3 + 0x8C100505, // 000A GETMET R4 R2 K5 + 0x58180006, // 000B LDCONST R6 K6 + 0x7C100400, // 000C CALL R4 2 + 0x74120021, // 000D JMPT R4 #0030 + 0x60100012, // 000E GETGBL R4 G18 + 0x7C100000, // 000F CALL R4 0 + 0x5C0C0800, // 0010 MOVE R3 R4 + 0x900A0C03, // 0011 SETMBR R2 K6 R3 + 0x60100010, // 0012 GETGBL R4 G16 + 0xB8160E00, // 0013 GETNGBL R5 K7 + 0x88140B08, // 0014 GETMBR R5 R5 K8 + 0x04140B09, // 0015 SUB R5 R5 K9 + 0x40160205, // 0016 CONNECT R5 K1 R5 + 0x7C100200, // 0017 CALL R4 1 + 0xA8020005, // 0018 EXBLK 0 #001F + 0x5C140800, // 0019 MOVE R5 R4 + 0x7C140000, // 001A CALL R5 0 + 0x8C18070A, // 001B GETMET R6 R3 K10 + 0x5421FFFE, // 001C LDINT R8 -1 + 0x7C180400, // 001D CALL R6 2 + 0x7001FFF9, // 001E JMP #0019 + 0x5810000B, // 001F LDCONST R4 K11 + 0xAC100200, // 0020 CATCH R4 1 0 + 0xB0080000, // 0021 RAISE 2 R0 R0 + 0xB8120E00, // 0022 GETNGBL R4 K7 + 0x8C10090C, // 0023 GETMET R4 R4 K12 + 0xB81A0E00, // 0024 GETNGBL R6 K7 + 0x88180D0D, // 0025 GETMBR R6 R6 K13 + 0x581C0001, // 0026 LDCONST R7 K1 + 0x7C100600, // 0027 CALL R4 3 + 0x78120006, // 0028 JMPF R4 #0030 + 0xB8120E00, // 0029 GETNGBL R4 K7 + 0x8C10090E, // 002A GETMET R4 R4 K14 + 0xB81A0E00, // 002B GETNGBL R6 K7 + 0x88180D0D, // 002C GETMBR R6 R6 K13 + 0x581C0001, // 002D LDCONST R7 K1 + 0x7C100600, // 002E CALL R4 3 + 0x980E0204, // 002F SETIDX R3 K1 R4 + 0x880C0506, // 0030 GETMBR R3 R2 K6 + 0x58100001, // 0031 LDCONST R4 K1 + 0x5415FFFE, // 0032 LDINT R5 -1 + 0xB81A0E00, // 0033 GETNGBL R6 K7 + 0x88180D08, // 0034 GETMBR R6 R6 K8 + 0x14180806, // 0035 LT R6 R4 R6 + 0x781A000A, // 0036 JMPF R6 #0042 + 0x94180604, // 0037 GETIDX R6 R3 R4 + 0x1C1C0C00, // 0038 EQ R7 R6 R0 + 0x781E0000, // 0039 JMPF R7 #003B + 0x80040800, // 003A RET 1 R4 + 0x141C0D01, // 003B LT R7 R6 K1 + 0x781E0002, // 003C JMPF R7 #0040 + 0x141C0B01, // 003D LT R7 R5 K1 + 0x781E0000, // 003E JMPF R7 #0040 + 0x5C140800, // 003F MOVE R5 R4 + 0x00100909, // 0040 ADD R4 R4 K9 + 0x7001FFF0, // 0041 JMP #0033 + 0x28180B01, // 0042 GE R6 R5 K1 + 0x781A0001, // 0043 JMPF R6 #0046 + 0x980C0A00, // 0044 SETIDX R3 R5 R0 + 0x80040A00, // 0045 RET 1 R5 + 0xB0061F10, // 0046 RAISE 1 K15 K16 + 0x80000000, // 0047 RET 0 }) ) ); diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_leds_animator.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_leds_animator.h index 4d6d70726..992fae52b 100644 --- a/lib/libesp32/berry_tasmota/src/solidify/solidified_leds_animator.h +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_leds_animator.h @@ -4,6 +4,8 @@ \********************************************************************/ #include "be_constobj.h" +extern const bclass be_class_Leds_animator; + /******************************************************************** ** Solidified function: init ********************************************************************/ diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_lv_tasmota.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_lv_tasmota.h index 37b7046f2..31a6267d5 100644 --- a/lib/libesp32/berry_tasmota/src/solidify/solidified_lv_tasmota.h +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_lv_tasmota.h @@ -114,6 +114,8 @@ be_local_closure(lv_tasmota_init, /* name */ /*******************************************************************/ +extern const bclass be_class_splash_runner; + /******************************************************************** ** Solidified function: init ********************************************************************/ diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_lv_tasmota_widgets.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_lv_tasmota_widgets.h index 5c2787cc0..bd85dbbb2 100644 --- a/lib/libesp32/berry_tasmota/src/solidify/solidified_lv_tasmota_widgets.h +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_lv_tasmota_widgets.h @@ -4,6 +4,8 @@ \********************************************************************/ #include "be_constobj.h" +extern const bclass be_class_lv_clock; + /******************************************************************** ** Solidified function: set_time ********************************************************************/ @@ -270,6 +272,8 @@ void be_load_lv_clock_class(bvm *vm) { be_pop(vm, 1); } +extern const bclass be_class_lv_clock_icon; + /******************************************************************** ** Solidified function: init ********************************************************************/ @@ -391,6 +395,8 @@ void be_load_lv_clock_icon_class(bvm *vm) { be_pop(vm, 1); } +extern const bclass be_class_lv_signal_arcs; + /******************************************************************** ** Solidified function: set_percentage ********************************************************************/ @@ -804,6 +810,8 @@ void be_load_lv_signal_arcs_class(bvm *vm) { be_pop(vm, 1); } +extern const bclass be_class_lv_wifi_arcs; + /******************************************************************** ** Solidified function: before_del ********************************************************************/ @@ -955,6 +963,8 @@ void be_load_lv_wifi_arcs_class(bvm *vm) { be_pop(vm, 1); } +extern const bclass be_class_lv_wifi_arcs_icon; + /******************************************************************** ** Solidified function: init ********************************************************************/ @@ -1085,6 +1095,8 @@ void be_load_lv_wifi_arcs_icon_class(bvm *vm) { be_pop(vm, 1); } +extern const bclass be_class_lv_signal_bars; + /******************************************************************** ** Solidified function: set_percentage ********************************************************************/ @@ -1468,6 +1480,8 @@ void be_load_lv_signal_bars_class(bvm *vm) { be_pop(vm, 1); } +extern const bclass be_class_lv_wifi_bars; + /******************************************************************** ** Solidified function: before_del ********************************************************************/ @@ -1619,6 +1633,8 @@ void be_load_lv_wifi_bars_class(bvm *vm) { be_pop(vm, 1); } +extern const bclass be_class_lv_wifi_bars_icon; + /******************************************************************** ** Solidified function: init ********************************************************************/ diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_mqtt.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_mqtt.h index e1ec4506a..48d49ae2e 100644 --- a/lib/libesp32/berry_tasmota/src/solidify/solidified_mqtt.h +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_mqtt.h @@ -4,6 +4,8 @@ \********************************************************************/ #include "be_constobj.h" +extern const bclass be_class_MQTT; + /******************************************************************** ** Solidified function: mqtt_data ********************************************************************/ @@ -259,6 +261,8 @@ be_local_closure(MQTT_mqtt_connect, /* name */ /*******************************************************************/ +extern const bclass be_class_mqtt_listener; + /******************************************************************** ** Solidified function: tostring ********************************************************************/ diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_partition_core.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_partition_core.h index c298260ac..2f0cb689d 100644 --- a/lib/libesp32/berry_tasmota/src/solidify/solidified_partition_core.h +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_partition_core.h @@ -4,6 +4,8 @@ \********************************************************************/ #include "be_constobj.h" +extern const bclass be_class_Partition_otadata; + /******************************************************************** ** Solidified function: save ********************************************************************/ @@ -319,33 +321,35 @@ be_local_closure(Partition_otadata_load, /* name */ ********************************************************************/ be_local_closure(Partition_otadata_crc32_ota_seq, /* name */ be_nested_proto( - 9, /* nstack */ + 10, /* nstack */ 1, /* argc */ - 0, /* varg */ + 4, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_nested_str(crc), - /* K1 */ be_nested_str(crc32), - /* K2 */ be_nested_str(add), + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_const_class(be_class_Partition_otadata), + /* K1 */ be_nested_str(crc), + /* K2 */ be_nested_str(crc32), + /* K3 */ be_nested_str(add), }), &be_const_str_crc32_ota_seq, &be_const_str_solidified, - ( &(const binstruction[11]) { /* code */ - 0xA4060000, // 0000 IMPORT R1 K0 - 0x8C080301, // 0001 GETMET R2 R1 K1 - 0x5411FFFE, // 0002 LDINT R4 -1 - 0x60140015, // 0003 GETGBL R5 G21 - 0x7C140000, // 0004 CALL R5 0 - 0x8C140B02, // 0005 GETMET R5 R5 K2 - 0x5C1C0000, // 0006 MOVE R7 R0 - 0x54220003, // 0007 LDINT R8 4 - 0x7C140600, // 0008 CALL R5 3 - 0x7C080600, // 0009 CALL R2 3 - 0x80040400, // 000A RET 1 R2 + ( &(const binstruction[12]) { /* code */ + 0x58040000, // 0000 LDCONST R1 K0 + 0xA40A0200, // 0001 IMPORT R2 K1 + 0x8C0C0502, // 0002 GETMET R3 R2 K2 + 0x5415FFFE, // 0003 LDINT R5 -1 + 0x60180015, // 0004 GETGBL R6 G21 + 0x7C180000, // 0005 CALL R6 0 + 0x8C180D03, // 0006 GETMET R6 R6 K3 + 0x5C200000, // 0007 MOVE R8 R0 + 0x54260003, // 0008 LDINT R9 4 + 0x7C180600, // 0009 CALL R6 3 + 0x7C0C0600, // 000A CALL R3 3 + 0x80040600, // 000B RET 1 R3 }) ) ); @@ -498,6 +502,8 @@ be_local_class(Partition_otadata, (bstring*) &be_const_str_Partition_otadata ); +extern const bclass be_class_Partition; + /******************************************************************** ** Solidified function: save ********************************************************************/ @@ -928,50 +934,52 @@ be_local_closure(Partition_resize_max_flash_size_k, /* name */ ********************************************************************/ be_local_closure(Partition_get_flash_definition_sector, /* name */ be_nested_proto( - 8, /* nstack */ + 9, /* nstack */ 0, /* argc */ - 0, /* varg */ + 4, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 6]) { /* constants */ - /* K0 */ be_nested_str(flash), - /* K1 */ be_const_int(0), - /* K2 */ be_const_int(1), - /* K3 */ be_nested_str(read), - /* K4 */ be_nested_str(E9), - /* K5 */ be_nested_str(stop_iteration), + ( &(const bvalue[ 7]) { /* constants */ + /* K0 */ be_const_class(be_class_Partition), + /* K1 */ be_nested_str(flash), + /* K2 */ be_const_int(0), + /* K3 */ be_const_int(1), + /* K4 */ be_nested_str(read), + /* K5 */ be_nested_str(E9), + /* K6 */ be_nested_str(stop_iteration), }), &be_const_str_get_flash_definition_sector, &be_const_str_solidified, - ( &(const binstruction[25]) { /* code */ - 0xA4020000, // 0000 IMPORT R0 K0 - 0x60040010, // 0001 GETGBL R1 G16 - 0x400A0302, // 0002 CONNECT R2 K1 K2 - 0x7C040200, // 0003 CALL R1 1 - 0xA802000F, // 0004 EXBLK 0 #0015 - 0x5C080200, // 0005 MOVE R2 R1 - 0x7C080000, // 0006 CALL R2 0 - 0x540E0FFF, // 0007 LDINT R3 4096 - 0x080C0403, // 0008 MUL R3 R2 R3 - 0x8C100103, // 0009 GETMET R4 R0 K3 - 0x5C180600, // 000A MOVE R6 R3 - 0x581C0002, // 000B LDCONST R7 K2 - 0x7C100600, // 000C CALL R4 3 - 0x60140015, // 000D GETGBL R5 G21 - 0x58180004, // 000E LDCONST R6 K4 - 0x7C140200, // 000F CALL R5 1 - 0x1C100805, // 0010 EQ R4 R4 R5 - 0x78120001, // 0011 JMPF R4 #0014 - 0xA8040001, // 0012 EXBLK 1 1 - 0x80040600, // 0013 RET 1 R3 - 0x7001FFEF, // 0014 JMP #0005 - 0x58040005, // 0015 LDCONST R1 K5 - 0xAC040200, // 0016 CATCH R1 1 0 - 0xB0080000, // 0017 RAISE 2 R0 R0 - 0x80000000, // 0018 RET 0 + ( &(const binstruction[26]) { /* code */ + 0x58000000, // 0000 LDCONST R0 K0 + 0xA4060200, // 0001 IMPORT R1 K1 + 0x60080010, // 0002 GETGBL R2 G16 + 0x400E0503, // 0003 CONNECT R3 K2 K3 + 0x7C080200, // 0004 CALL R2 1 + 0xA802000F, // 0005 EXBLK 0 #0016 + 0x5C0C0400, // 0006 MOVE R3 R2 + 0x7C0C0000, // 0007 CALL R3 0 + 0x54120FFF, // 0008 LDINT R4 4096 + 0x08100604, // 0009 MUL R4 R3 R4 + 0x8C140304, // 000A GETMET R5 R1 K4 + 0x5C1C0800, // 000B MOVE R7 R4 + 0x58200003, // 000C LDCONST R8 K3 + 0x7C140600, // 000D CALL R5 3 + 0x60180015, // 000E GETGBL R6 G21 + 0x581C0005, // 000F LDCONST R7 K5 + 0x7C180200, // 0010 CALL R6 1 + 0x1C140A06, // 0011 EQ R5 R5 R6 + 0x78160001, // 0012 JMPF R5 #0015 + 0xA8040001, // 0013 EXBLK 1 1 + 0x80040800, // 0014 RET 1 R4 + 0x7001FFEF, // 0015 JMP #0006 + 0x58080006, // 0016 LDCONST R2 K6 + 0xAC080200, // 0017 CATCH R2 1 0 + 0xB0080000, // 0018 RAISE 2 R0 R0 + 0x80000000, // 0019 RET 0 }) ) ); @@ -1660,6 +1668,8 @@ be_local_class(Partition, (bstring*) &be_const_str_Partition ); +extern const bclass be_class_Partition_info; + /******************************************************************** ** Solidified function: is_factory ********************************************************************/ @@ -2165,45 +2175,47 @@ be_local_closure(Partition_info_tobytes, /* name */ ********************************************************************/ be_local_closure(Partition_info_remove_trailing_zeroes, /* name */ be_nested_proto( - 7, /* nstack */ + 8, /* nstack */ 1, /* argc */ - 0, /* varg */ + 4, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_const_int(0), - /* K1 */ be_const_int(1), - /* K2 */ be_nested_str(resize), + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_const_class(be_class_Partition_info), + /* K1 */ be_const_int(0), + /* K2 */ be_const_int(1), + /* K3 */ be_nested_str(resize), }), &be_const_str_remove_trailing_zeroes, &be_const_str_solidified, - ( &(const binstruction[23]) { /* code */ - 0x6004000C, // 0000 GETGBL R1 G12 - 0x5C080000, // 0001 MOVE R2 R0 - 0x7C040200, // 0002 CALL R1 1 - 0x58080000, // 0003 LDCONST R2 K0 - 0x140C0401, // 0004 LT R3 R2 R1 - 0x780E0007, // 0005 JMPF R3 #000E - 0x540DFFFE, // 0006 LDINT R3 -1 - 0x040C0602, // 0007 SUB R3 R3 R2 - 0x940C0003, // 0008 GETIDX R3 R0 R3 - 0x200C0700, // 0009 NE R3 R3 K0 - 0x780E0000, // 000A JMPF R3 #000C - 0x70020001, // 000B JMP #000E - 0x00080501, // 000C ADD R2 R2 K1 - 0x7001FFF5, // 000D JMP #0004 - 0x240C0500, // 000E GT R3 R2 K0 - 0x780E0005, // 000F JMPF R3 #0016 - 0x8C0C0102, // 0010 GETMET R3 R0 K2 - 0x6014000C, // 0011 GETGBL R5 G12 - 0x5C180000, // 0012 MOVE R6 R0 - 0x7C140200, // 0013 CALL R5 1 - 0x04140A02, // 0014 SUB R5 R5 R2 - 0x7C0C0400, // 0015 CALL R3 2 - 0x80040000, // 0016 RET 1 R0 + ( &(const binstruction[24]) { /* code */ + 0x58040000, // 0000 LDCONST R1 K0 + 0x6008000C, // 0001 GETGBL R2 G12 + 0x5C0C0000, // 0002 MOVE R3 R0 + 0x7C080200, // 0003 CALL R2 1 + 0x580C0001, // 0004 LDCONST R3 K1 + 0x14100602, // 0005 LT R4 R3 R2 + 0x78120007, // 0006 JMPF R4 #000F + 0x5411FFFE, // 0007 LDINT R4 -1 + 0x04100803, // 0008 SUB R4 R4 R3 + 0x94100004, // 0009 GETIDX R4 R0 R4 + 0x20100901, // 000A NE R4 R4 K1 + 0x78120000, // 000B JMPF R4 #000D + 0x70020001, // 000C JMP #000F + 0x000C0702, // 000D ADD R3 R3 K2 + 0x7001FFF5, // 000E JMP #0005 + 0x24100701, // 000F GT R4 R3 K1 + 0x78120005, // 0010 JMPF R4 #0017 + 0x8C100103, // 0011 GETMET R4 R0 K3 + 0x6018000C, // 0012 GETGBL R6 G12 + 0x5C1C0000, // 0013 MOVE R7 R0 + 0x7C180200, // 0014 CALL R6 1 + 0x04180C03, // 0015 SUB R6 R6 R3 + 0x7C100400, // 0016 CALL R4 2 + 0x80040000, // 0017 RET 1 R0 }) ) ); diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_persist.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_persist.h index 6427e760c..aed177dfa 100644 --- a/lib/libesp32/berry_tasmota/src/solidify/solidified_persist.h +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_persist.h @@ -4,6 +4,8 @@ \********************************************************************/ #include "be_constobj.h" +extern const bclass be_class_Persist; + /******************************************************************** ** Solidified function: json_fdump_map ********************************************************************/ diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_tapp.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_tapp.h index 573d08b6d..67cacbde3 100644 --- a/lib/libesp32/berry_tasmota/src/solidify/solidified_tapp.h +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_tapp.h @@ -4,6 +4,8 @@ \********************************************************************/ #include "be_constobj.h" +extern const bclass be_class_Tapp; + /******************************************************************** ** Solidified function: init ********************************************************************/ diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_tasmota_class.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_tasmota_class.h index 04f04a82c..af2a338d1 100644 --- a/lib/libesp32/berry_tasmota/src/solidify/solidified_tasmota_class.h +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_tasmota_class.h @@ -4,6 +4,8 @@ \********************************************************************/ #include "be_constobj.h" +extern const bclass be_class_Tasmota; + /******************************************************************** ** Solidified function: exec_rules ********************************************************************/ diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_trigger_class.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_trigger_class.h index f86aaa349..5a42d66bf 100644 --- a/lib/libesp32/berry_tasmota/src/solidify/solidified_trigger_class.h +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_trigger_class.h @@ -4,6 +4,8 @@ \********************************************************************/ #include "be_constobj.h" +extern const bclass be_class_Trigger; + /******************************************************************** ** Solidified function: init ********************************************************************/ diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_zigbee_zb_coord.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_zigbee_zb_coord.h index fb16c25e2..10dc93c33 100644 --- a/lib/libesp32/berry_tasmota/src/solidify/solidified_zigbee_zb_coord.h +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_zigbee_zb_coord.h @@ -4,6 +4,8 @@ \********************************************************************/ #include "be_constobj.h" +extern const bclass be_class_zb_coord; + /******************************************************************** ** Solidified function: init ********************************************************************/ diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_zigbee_zcl_attribute.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_zigbee_zcl_attribute.h index ebb0e438d..d2e4cc847 100644 --- a/lib/libesp32/berry_tasmota/src/solidify/solidified_zigbee_zcl_attribute.h +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_zigbee_zcl_attribute.h @@ -4,6 +4,8 @@ \********************************************************************/ #include "be_constobj.h" +extern const bclass be_class_zcl_attribute; + /******************************************************************** ** Solidified function: tomap ********************************************************************/ @@ -571,6 +573,8 @@ void be_load_zcl_attribute_class(bvm *vm) { be_pop(vm, 1); } +extern const bclass be_class_zcl_attribute_list; + /******************************************************************** ** Solidified function: member ********************************************************************/ @@ -914,6 +918,8 @@ void be_load_zcl_attribute_list_class(bvm *vm) { be_pop(vm, 1); } +extern const bclass be_class_zcl_attributes; + /******************************************************************** ** Solidified function: init ********************************************************************/ diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_zigbee_zcl_frame.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_zigbee_zcl_frame.h index 1e10ccc93..f979a3066 100644 --- a/lib/libesp32/berry_tasmota/src/solidify/solidified_zigbee_zcl_frame.h +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_zigbee_zcl_frame.h @@ -4,6 +4,8 @@ \********************************************************************/ #include "be_constobj.h" +extern const bclass be_class_zcl_frame; + /******************************************************************** ** Solidified function: member ********************************************************************/ From f71465a18268a9c41f40fc992384febcb1cfbf20 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sat, 14 Jan 2023 15:39:54 +0100 Subject: [PATCH 140/262] Repurpose SO39 for import active bandwidth Repurpose SO39 for import active bandwidth (#17659) --- tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino b/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino index f2cb3b462..70fca2527 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino @@ -314,6 +314,19 @@ void EnergyUpdateTotal(void) { for (uint32_t i = 0; i < Energy.phase_count; i++) { AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("NRG: EnergyTotal[%d] %4_f kWh"), i, &Energy.import_active[i]); + // Try to fix instable input by verifying allowed bandwidth (#17659) + if ((Energy.start_energy[i] != 0) && + (Settings->param[P_CSE7766_INVALID_POWER] > 0) && + (Settings->param[P_CSE7766_INVALID_POWER] < 128)) { // SetOption39 1..127 kWh + int total = abs((int)Energy.total[i]); // We only use kWh + int import_active = abs((int)Energy.import_active[i]); + if ((import_active < (total - Settings->param[P_CSE7766_INVALID_POWER])) || + (import_active > (total + Settings->param[P_CSE7766_INVALID_POWER]))) { + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("NRG: Outside bandwidth")); + continue; // No valid energy value received + } + } + if (0 == Energy.start_energy[i] || (Energy.import_active[i] < Energy.start_energy[i])) { Energy.start_energy[i] = Energy.import_active[i]; // Init after restart and handle roll-over if any } From e0b17af3072d37db2b51edf460d7e8332727c21a Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sat, 14 Jan 2023 16:11:08 +0100 Subject: [PATCH 141/262] Fix first sensor in case GlobalTemp is set wrong Fix first of two sensors in case GlobalTemp is set wrong (#17694) --- tasmota/tasmota_xdrv_driver/xdrv_87_esp32_sonoff_tm1621.ino | 1 + 1 file changed, 1 insertion(+) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_87_esp32_sonoff_tm1621.ino b/tasmota/tasmota_xdrv_driver/xdrv_87_esp32_sonoff_tm1621.ino index 70926f5ff..d8b315063 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_87_esp32_sonoff_tm1621.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_87_esp32_sonoff_tm1621.ino @@ -459,6 +459,7 @@ void TM1621Show(void) { temperature = TM1621GetTemperatureValues(Tm1621.temp_sensors_rotate); ext_snprintf_P(Tm1621.row[1], sizeof(Tm1621.row[1]), PSTR("%d"), Tm1621.temp_sensors_rotate); } else { + temperature = TM1621GetTemperatureValues(1); // Fix in case GlobalTemp is set wrong (#17694) float temperature2 = TM1621GetTemperatureValues(2); ext_snprintf_P(Tm1621.row[1], sizeof(Tm1621.row[1]), PSTR("%1_f"), &temperature2); } From 2d1d49504b3b08b19f9fc39a305d267f287342ce Mon Sep 17 00:00:00 2001 From: Barbudor Date: Sun, 15 Jan 2023 16:20:35 +0100 Subject: [PATCH 142/262] fix free() too early (#17710) --- tasmota/tasmota_xdrv_driver/xdrv_50_filesystem.ino | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_50_filesystem.ino b/tasmota/tasmota_xdrv_driver/xdrv_50_filesystem.ino index fc7ca39b8..93ed23ed1 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_50_filesystem.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_50_filesystem.ino @@ -925,7 +925,7 @@ uint8_t UfsDownloadFile(char *file) { UfsData.download_busy = true; char *path = (char*)malloc(128); strcpy(path,file); - BaseType_t ret = xTaskCreatePinnedToCore(donload_task, "DT", 6000, (void*)path, 3, nullptr, 1); + BaseType_t ret = xTaskCreatePinnedToCore(download_task, "DT", 6000, (void*)path, 3, nullptr, 1); if (ret != pdPASS) AddLog(LOG_LEVEL_INFO, PSTR("UFS: Download task failed with %d"), ret); yield(); @@ -939,14 +939,12 @@ uint8_t UfsDownloadFile(char *file) { #ifndef DOWNLOAD_SIZE #define DOWNLOAD_SIZE 4096 #endif // DOWNLOAD_SIZE -void donload_task(void *path) { +void download_task(void *path) { File download_file; WiFiClient download_Client; char *file = (char*) path; download_file = dfsp->open(file, UFS_FILE_READ); - free(file); - uint32_t flen = download_file.size(); download_Client = Webserver->client(); @@ -960,6 +958,8 @@ void donload_task(void *path) { break; } } + //snprintf_P(attachment, sizeof(attachment), PSTR("download file '%s' as '%s'"), file, cp); + //Webserver->sendHeader(F("X-Tasmota-Debug"), attachment); snprintf_P(attachment, sizeof(attachment), PSTR("attachment; filename=%s"), cp); Webserver->sendHeader(F("Content-Disposition"), attachment); WSSend(200, CT_APP_STREAM, ""); @@ -978,6 +978,7 @@ void donload_task(void *path) { download_Client.stop(); UfsData.download_busy = false; vTaskDelete( NULL ); + free(path); } #endif // ESP32_DOWNLOAD_TASK From 7a97fa4a19a5d6622c68081fd1de0f1b6b6b27ad Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 15 Jan 2023 17:14:54 +0100 Subject: [PATCH 143/262] Fix BMP support on two busses Fix BMP support on two busses (#17643) --- tasmota/include/i18n.h | 4 - tasmota/tasmota_support/support_a_i2c.ino | 76 ++++++----- tasmota/tasmota_xsns_sensor/xsns_09_bmp.ino | 139 +++++++++++--------- 3 files changed, 119 insertions(+), 100 deletions(-) diff --git a/tasmota/include/i18n.h b/tasmota/include/i18n.h index e228989e1..8cb8a5da1 100644 --- a/tasmota/include/i18n.h +++ b/tasmota/include/i18n.h @@ -100,9 +100,6 @@ #define D_JSON_OTHER_HTTP_ERROR "Other http error" #define D_JSON_HSBCOLOR "HSBColor" #define D_JSON_HUMIDITY "Humidity" -#define D_JSON_I2CSCAN_DEVICES_FOUND_AT "Device(s) found at" -#define D_JSON_I2CSCAN_UNKNOWN_ERROR_AT "Unknown error at" -#define D_JSON_I2CSCAN_NO_DEVICES_FOUND "No devices found" #define D_JSON_ID "Id" #define D_JSON_ILLUMINANCE "Illuminance" #define D_JSON_IMPORT_ACTIVE "ImportActive" @@ -868,7 +865,6 @@ const char JSON_SNS_RANGE[] PROGMEM = ",\"%s\":{\"" D_JSON_RANGE "\":%d}"; const char JSON_SNS_GNGPM[] PROGMEM = ",\"%s\":{\"" D_JSON_TOTAL_USAGE "\":%s,\"" D_JSON_FLOWRATE "\":%s}"; const char S_LOG_I2C_FOUND_AT[] PROGMEM = D_LOG_I2C "%s " D_FOUND_AT " 0x%x"; -const char S_LOG_I2C_FOUND_AT_PORT[] PROGMEM = D_LOG_I2C "%s " D_FOUND_AT " 0x%x (" D_PORT " %d)"; const char S_RSLT_POWER[] PROGMEM = D_RSLT_POWER; const char S_RSLT_RESULT[] PROGMEM = D_RSLT_RESULT; diff --git a/tasmota/tasmota_support/support_a_i2c.ino b/tasmota/tasmota_support/support_a_i2c.ino index 25d81427c..a3fef3c2f 100644 --- a/tasmota/tasmota_support/support_a_i2c.ino +++ b/tasmota/tasmota_support/support_a_i2c.ino @@ -50,15 +50,16 @@ bool I2c2Begin(int sda, int scl, uint32_t frequency) { #endif bool I2cValidRead(uint8_t addr, uint8_t reg, uint8_t size, uint8_t bus = 0) { - uint8_t retry = I2C_RETRY_COUNTER; - bool status = false; + i2c_buffer = 0; #ifdef ESP32 - if (!TasmotaGlobal.i2c_enabled_2) { bus = 0; } + if (bus && !TasmotaGlobal.i2c_enabled_2) { return false; } // Error TwoWire & myWire = (bus == 0) ? Wire : Wire1; #else + if (bus) { return false; } // Second I2c bus ESP32 only TwoWire & myWire = Wire; #endif - i2c_buffer = 0; + uint8_t retry = I2C_RETRY_COUNTER; + bool status = false; while (!status && retry) { myWire.beginTransmission(addr); // start transmission to device myWire.write(reg); // sends register address to read from @@ -146,14 +147,14 @@ int32_t I2cRead24(uint8_t addr, uint8_t reg, uint8_t bus = 0) { } bool I2cWrite(uint8_t addr, uint8_t reg, uint32_t val, uint8_t size, uint8_t bus = 0) { - uint8_t x = I2C_RETRY_COUNTER; #ifdef ESP32 - if (!TasmotaGlobal.i2c_enabled_2) { bus = 0; } + if (bus && !TasmotaGlobal.i2c_enabled_2) { return false; } // Error TwoWire & myWire = (bus == 0) ? Wire : Wire1; #else - if (bus != 0) { return false; } // Second I2c bus ESP32 only + if (bus) { return false; } // Second I2c bus ESP32 only TwoWire & myWire = Wire; #endif + uint8_t x = I2C_RETRY_COUNTER; do { myWire.beginTransmission((uint8_t)addr); // start transmission to device myWire.write(reg); // sends register address to write to @@ -176,31 +177,31 @@ bool I2cWrite16(uint8_t addr, uint8_t reg, uint32_t val, uint8_t bus = 0) { bool I2cReadBuffer(uint8_t addr, uint8_t reg, uint8_t *reg_data, uint16_t len, uint8_t bus = 0) { #ifdef ESP32 - if (!TasmotaGlobal.i2c_enabled_2) { bus = 0; } + if (bus && !TasmotaGlobal.i2c_enabled_2) { return true; } // Error TwoWire & myWire = (bus == 0) ? Wire : Wire1; #else - if (bus != 0) { return false; } // Second I2c bus ESP32 only + if (bus) { return true; } // Second I2c bus ESP32 only TwoWire & myWire = Wire; #endif myWire.beginTransmission((uint8_t)addr); myWire.write((uint8_t)reg); myWire.endTransmission(); if (len != myWire.requestFrom((uint8_t)addr, (uint8_t)len)) { - return 1; + return true; // Error } while (len--) { *reg_data = (uint8_t)myWire.read(); reg_data++; } - return 0; + return false; // OK } int8_t I2cWriteBuffer(uint8_t addr, uint8_t reg, uint8_t *reg_data, uint16_t len, uint8_t bus = 0) { #ifdef ESP32 - if (!TasmotaGlobal.i2c_enabled_2) { bus = 0; } + if (bus && !TasmotaGlobal.i2c_enabled_2) { return 1; } // Error TwoWire & myWire = (bus == 0) ? Wire : Wire1; #else - if (bus != 0) { return false; } // Second I2c bus ESP32 only + if (bus) { return 1; } // Second I2c bus ESP32 only TwoWire & myWire = Wire; #endif myWire.beginTransmission((uint8_t)addr); @@ -210,7 +211,7 @@ int8_t I2cWriteBuffer(uint8_t addr, uint8_t reg, uint8_t *reg_data, uint16_t len reg_data++; } myWire.endTransmission(); - return 0; + return 0; // OK } void I2cScan(uint8_t bus = 0) { @@ -229,39 +230,40 @@ void I2cScan(uint8_t bus = 0) { // 4: other error // 5: timeout +#ifdef ESP32 + if (bus && !TasmotaGlobal.i2c_enabled_2) { return; } + TwoWire & myWire = (bus == 0) ? Wire : Wire1; + Response_P(PSTR("{\"" D_CMND_I2CSCAN "\":\"Device(s) found on bus%d at"), bus +1); +#else + if (bus) { return; } // Second I2c bus ESP32 only + TwoWire & myWire = Wire; + Response_P(PSTR("{\"" D_CMND_I2CSCAN "\":\"Device(s) found at")); +#endif uint8_t error = 0; uint8_t address = 0; uint8_t any = 0; - - Response_P(PSTR("{\"" D_CMND_I2CSCAN "\":\"" D_JSON_I2CSCAN_DEVICES_FOUND_AT)); for (address = 1; address <= 127; address++) { -#ifdef ESP32 - if (!TasmotaGlobal.i2c_enabled_2) { bus = 0; } - TwoWire & myWire = (bus == 0) ? Wire : Wire1; -#else - if (bus != 0) { return; } // Second I2c bus ESP32 only - TwoWire & myWire = Wire; -#endif myWire.beginTransmission(address); error = myWire.endTransmission(); if (0 == error) { any = 1; -#ifdef ESP32 - ResponseAppend_P(PSTR(" 0x%02x:%d"), address, bus); -#else ResponseAppend_P(PSTR(" 0x%02x"), address); -#endif } else if (error != 2) { // Seems to happen anyway using this scan any = 2; - Response_P(PSTR("{\"" D_CMND_I2CSCAN "\":\"Error %d at 0x%02x bus %d"), error, address, bus); + Response_P(PSTR("{\"" D_CMND_I2CSCAN "\":\"Error %d at 0x%02x"), error, address); +#ifdef ESP32 + if (bus) { + ResponseAppend_P(PSTR(" (bus2)")); + } +#endif break; } } if (any) { ResponseAppend_P(PSTR("\"}")); } else { - Response_P(PSTR("{\"" D_CMND_I2CSCAN "\":\"" D_JSON_I2CSCAN_NO_DEVICES_FOUND "\"}")); + Response_P(PSTR("{\"" D_CMND_I2CSCAN "\":\"No devices found\"}")); } } @@ -294,11 +296,11 @@ void I2cSetActive(uint32_t addr, uint32_t count = 1, uint8_t bus = 0) { void I2cSetActiveFound(uint32_t addr, const char *types, uint8_t bus = 0) { I2cSetActive(addr, bus); #ifdef ESP32 - if (1 == bus) { - AddLog(LOG_LEVEL_INFO, S_LOG_I2C_FOUND_AT_PORT, types, addr, bus); + if (bus) { + AddLog(LOG_LEVEL_INFO, PSTR("I2C: %s found at 0x%02x (bus2)"), types, addr); } else #endif // ESP32 - AddLog(LOG_LEVEL_INFO, S_LOG_I2C_FOUND_AT, types, addr); + AddLog(LOG_LEVEL_INFO, PSTR("I2C: %s found at 0x%02x"), types, addr); } bool I2cActive(uint32_t addr, uint8_t bus = 0) { @@ -311,9 +313,10 @@ bool I2cActive(uint32_t addr, uint8_t bus = 0) { bool I2cSetDevice(uint32_t addr, uint8_t bus = 0) { #ifdef ESP32 - if (!TasmotaGlobal.i2c_enabled_2) { bus = 0; } + if (bus && !TasmotaGlobal.i2c_enabled_2) { return false; } // If no second bus report as not present; TwoWire & myWire = (bus == 0) ? Wire : Wire1; #else + bus = 0; TwoWire & myWire = Wire; #endif addr &= 0x7F; // Max I2C address is 127 @@ -325,10 +328,11 @@ bool I2cSetDevice(uint32_t addr, uint8_t bus = 0) { uint32_t err = myWire.endTransmission(); if (err && (err != 2)) { #ifdef ESP32 - AddLog(LOG_LEVEL_DEBUG, PSTR("I2C: Error %d at 0x%02x bus %d"), err, addr, bus); -#else - AddLog(LOG_LEVEL_DEBUG, PSTR("I2C: Error %d at 0x%02x"), err, addr); + if (bus) { + AddLog(LOG_LEVEL_DEBUG, PSTR("I2C: Error %d at 0x%02x (bus2)"), err, addr); + } else #endif + AddLog(LOG_LEVEL_DEBUG, PSTR("I2C: Error %d at 0x%02x"), err, addr); } return (0 == err); } diff --git a/tasmota/tasmota_xsns_sensor/xsns_09_bmp.ino b/tasmota/tasmota_xsns_sensor/xsns_09_bmp.ino index 136d4e912..bc8f588f0 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_09_bmp.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_09_bmp.ino @@ -57,7 +57,8 @@ const char kBmpTypes[] PROGMEM = "BMP180|BMP280|BME280|BME680"; typedef struct { - uint8_t bmp_address; // I2C bus address + uint8_t bmp_address; // I2C address + uint8_t bmp_bus; // I2C bus char bmp_name[7]; // Sensor name - "BMPXXX" uint8_t bmp_type; uint8_t bmp_model; @@ -119,17 +120,19 @@ bool Bmp180Calibration(uint8_t bmp_idx) { bmp180_cal_data = (bmp180_cal_data_t*)malloc(BMP_MAX_SENSORS * sizeof(bmp180_cal_data_t)); } if (!bmp180_cal_data) { return false; } - uint8_t bus= (bmp_idx>=2) ? 1 : 0; // first two BMP's at bus 0, additional at bus 1 (ESP32 32 only) - bmp180_cal_data[bmp_idx].cal_ac1 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_AC1,bus); - bmp180_cal_data[bmp_idx].cal_ac2 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_AC2,bus); - bmp180_cal_data[bmp_idx].cal_ac3 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_AC3,bus); - bmp180_cal_data[bmp_idx].cal_ac4 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_AC4,bus); - bmp180_cal_data[bmp_idx].cal_ac5 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_AC5,bus); - bmp180_cal_data[bmp_idx].cal_ac6 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_AC6,bus); - bmp180_cal_data[bmp_idx].cal_b1 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_VB1,bus); - bmp180_cal_data[bmp_idx].cal_b2 = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_VB2,bus); - bmp180_cal_data[bmp_idx].cal_mc = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_MC,bus); - bmp180_cal_data[bmp_idx].cal_md = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_MD,bus); + + uint8_t address = bmp_sensors[bmp_idx].bmp_address; + uint8_t bus = bmp_sensors[bmp_idx].bmp_bus; + bmp180_cal_data[bmp_idx].cal_ac1 = I2cRead16(address, BMP180_AC1, bus); + bmp180_cal_data[bmp_idx].cal_ac2 = I2cRead16(address, BMP180_AC2, bus); + bmp180_cal_data[bmp_idx].cal_ac3 = I2cRead16(address, BMP180_AC3, bus); + bmp180_cal_data[bmp_idx].cal_ac4 = I2cRead16(address, BMP180_AC4, bus); + bmp180_cal_data[bmp_idx].cal_ac5 = I2cRead16(address, BMP180_AC5, bus); + bmp180_cal_data[bmp_idx].cal_ac6 = I2cRead16(address, BMP180_AC6, bus); + bmp180_cal_data[bmp_idx].cal_b1 = I2cRead16(address, BMP180_VB1, bus); + bmp180_cal_data[bmp_idx].cal_b2 = I2cRead16(address, BMP180_VB2, bus); + bmp180_cal_data[bmp_idx].cal_mc = I2cRead16(address, BMP180_MC, bus); + bmp180_cal_data[bmp_idx].cal_md = I2cRead16(address, BMP180_MD, bus); // Check for Errors in calibration data. Value never is 0x0000 or 0xFFFF if (!bmp180_cal_data[bmp_idx].cal_ac1 | !bmp180_cal_data[bmp_idx].cal_ac2 | @@ -162,18 +165,19 @@ bool Bmp180Calibration(uint8_t bmp_idx) { void Bmp180Read(uint8_t bmp_idx) { if (!bmp180_cal_data) { return; } - uint8_t bus = bmp_idx >>1; // First two BMP's at bus 0, additional at bus 1 - I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BMP180_REG_CONTROL, BMP180_TEMPERATURE, bus); + uint8_t address = bmp_sensors[bmp_idx].bmp_address; + uint8_t bus = bmp_sensors[bmp_idx].bmp_bus; + I2cWrite8(address, BMP180_REG_CONTROL, BMP180_TEMPERATURE, bus); delay(5); // 5ms conversion time - int ut = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BMP180_REG_RESULT, bus); + int ut = I2cRead16(address, BMP180_REG_RESULT, bus); int32_t xt1 = (ut - (int32_t)bmp180_cal_data[bmp_idx].cal_ac6) * ((int32_t)bmp180_cal_data[bmp_idx].cal_ac5) >> 15; int32_t xt2 = ((int32_t)bmp180_cal_data[bmp_idx].cal_mc << 11) / (xt1 + (int32_t)bmp180_cal_data[bmp_idx].cal_md); int32_t bmp180_b5 = xt1 + xt2; bmp_sensors[bmp_idx].bmp_temperature = ((bmp180_b5 + 8) >> 4) / 10.0f; - I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BMP180_REG_CONTROL, BMP180_PRESSURE3, bus); // Highest resolution + I2cWrite8(address, BMP180_REG_CONTROL, BMP180_PRESSURE3, bus); // Highest resolution delay(2 + (4 << BMP180_OSS)); // 26ms conversion time at ultra high resolution - uint32_t up = I2cRead24(bmp_sensors[bmp_idx].bmp_address, BMP180_REG_RESULT, bus); + uint32_t up = I2cRead24(address, BMP180_REG_RESULT, bus); up >>= (8 - BMP180_OSS); int32_t b6 = bmp180_b5 - 4000; @@ -265,33 +269,34 @@ bool Bmx280Calibrate(uint8_t bmp_idx) { } if (!Bme280CalibrationData) { return false; } - uint8_t bus = bmp_idx >>1; // First two BMP's at bus 0, additional at bus 1 - Bme280CalibrationData[bmp_idx].dig_T1 = I2cRead16LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_T1, bus); - Bme280CalibrationData[bmp_idx].dig_T2 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_T2, bus); - Bme280CalibrationData[bmp_idx].dig_T3 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_T3, bus); - Bme280CalibrationData[bmp_idx].dig_P1 = I2cRead16LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P1, bus); - Bme280CalibrationData[bmp_idx].dig_P2 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P2, bus); - Bme280CalibrationData[bmp_idx].dig_P3 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P3, bus); - Bme280CalibrationData[bmp_idx].dig_P4 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P4, bus); - Bme280CalibrationData[bmp_idx].dig_P5 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P5, bus); - Bme280CalibrationData[bmp_idx].dig_P6 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P6, bus); - Bme280CalibrationData[bmp_idx].dig_P7 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P7, bus); - Bme280CalibrationData[bmp_idx].dig_P8 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P8, bus); - Bme280CalibrationData[bmp_idx].dig_P9 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_P9, bus); + uint8_t address = bmp_sensors[bmp_idx].bmp_address; + uint8_t bus = bmp_sensors[bmp_idx].bmp_bus; + Bme280CalibrationData[bmp_idx].dig_T1 = I2cRead16LE(address, BME280_REGISTER_DIG_T1, bus); + Bme280CalibrationData[bmp_idx].dig_T2 = I2cReadS16_LE(address, BME280_REGISTER_DIG_T2, bus); + Bme280CalibrationData[bmp_idx].dig_T3 = I2cReadS16_LE(address, BME280_REGISTER_DIG_T3, bus); + Bme280CalibrationData[bmp_idx].dig_P1 = I2cRead16LE(address, BME280_REGISTER_DIG_P1, bus); + Bme280CalibrationData[bmp_idx].dig_P2 = I2cReadS16_LE(address, BME280_REGISTER_DIG_P2, bus); + Bme280CalibrationData[bmp_idx].dig_P3 = I2cReadS16_LE(address, BME280_REGISTER_DIG_P3, bus); + Bme280CalibrationData[bmp_idx].dig_P4 = I2cReadS16_LE(address, BME280_REGISTER_DIG_P4, bus); + Bme280CalibrationData[bmp_idx].dig_P5 = I2cReadS16_LE(address, BME280_REGISTER_DIG_P5, bus); + Bme280CalibrationData[bmp_idx].dig_P6 = I2cReadS16_LE(address, BME280_REGISTER_DIG_P6, bus); + Bme280CalibrationData[bmp_idx].dig_P7 = I2cReadS16_LE(address, BME280_REGISTER_DIG_P7, bus); + Bme280CalibrationData[bmp_idx].dig_P8 = I2cReadS16_LE(address, BME280_REGISTER_DIG_P8, bus); + Bme280CalibrationData[bmp_idx].dig_P9 = I2cReadS16_LE(address, BME280_REGISTER_DIG_P9, bus); if (BME280_CHIPID == bmp_sensors[bmp_idx].bmp_type) { // #1051 - Bme280CalibrationData[bmp_idx].dig_H1 = I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H1, bus); - Bme280CalibrationData[bmp_idx].dig_H2 = I2cReadS16_LE(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H2, bus); - Bme280CalibrationData[bmp_idx].dig_H3 = I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H3, bus); - Bme280CalibrationData[bmp_idx].dig_H4 = (I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H4, bus) << 4) | (I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H4 + 1,bus) & 0xF); - Bme280CalibrationData[bmp_idx].dig_H5 = (I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H5 + 1, bus) << 4) | (I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H5,bus) >> 4); - Bme280CalibrationData[bmp_idx].dig_H6 = (int8_t)I2cRead8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_DIG_H6, bus); - I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONTROL, 0x00, bus); // sleep mode since writes to config can be ignored in normal mode (Datasheet 5.4.5/6 page 27) + Bme280CalibrationData[bmp_idx].dig_H1 = I2cRead8(address, BME280_REGISTER_DIG_H1, bus); + Bme280CalibrationData[bmp_idx].dig_H2 = I2cReadS16_LE(address, BME280_REGISTER_DIG_H2, bus); + Bme280CalibrationData[bmp_idx].dig_H3 = I2cRead8(address, BME280_REGISTER_DIG_H3, bus); + Bme280CalibrationData[bmp_idx].dig_H4 = (I2cRead8(address, BME280_REGISTER_DIG_H4, bus) << 4) | (I2cRead8(address, BME280_REGISTER_DIG_H4 + 1, bus) & 0xF); + Bme280CalibrationData[bmp_idx].dig_H5 = (I2cRead8(address, BME280_REGISTER_DIG_H5 + 1, bus) << 4) | (I2cRead8(address, BME280_REGISTER_DIG_H5, bus) >> 4); + Bme280CalibrationData[bmp_idx].dig_H6 = (int8_t)I2cRead8(address, BME280_REGISTER_DIG_H6, bus); + I2cWrite8(address, BME280_REGISTER_CONTROL, 0x00, bus); // sleep mode since writes to config can be ignored in normal mode (Datasheet 5.4.5/6 page 27) // Set before CONTROL_meas (DS 5.4.3) - I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONTROLHUMID, 0x01, bus); // 1x oversampling - I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONFIG, 0xA0, bus); // 1sec standby between measurements (to limit self heating), IIR filter off - I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONTROL, 0x27, bus); // 1x oversampling, normal mode + I2cWrite8(address, BME280_REGISTER_CONTROLHUMID, 0x01, bus); // 1x oversampling + I2cWrite8(address, BME280_REGISTER_CONFIG, 0xA0, bus); // 1sec standby between measurements (to limit self heating), IIR filter off + I2cWrite8(address, BME280_REGISTER_CONTROL, 0x27, bus); // 1x oversampling, normal mode } else { - I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_CONTROL, 0xB7, bus); // 16x oversampling, normal mode (Adafruit) + I2cWrite8(address, BME280_REGISTER_CONTROL, 0xB7, bus); // 16x oversampling, normal mode (Adafruit) } return true; } @@ -299,8 +304,9 @@ bool Bmx280Calibrate(uint8_t bmp_idx) { void Bme280Read(uint8_t bmp_idx) { if (!Bme280CalibrationData) { return; } - uint8_t bus = bmp_idx >>1; // First two BMP's at bus 0, additional at bus 1 - int32_t adc_T = I2cRead24(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_TEMPDATA, bus); + uint8_t address = bmp_sensors[bmp_idx].bmp_address; + uint8_t bus = bmp_sensors[bmp_idx].bmp_bus; + int32_t adc_T = I2cRead24(address, BME280_REGISTER_TEMPDATA, bus); adc_T >>= 4; int32_t vart1 = ((((adc_T >> 3) - ((int32_t)Bme280CalibrationData[bmp_idx].dig_T1 << 1))) * ((int32_t)Bme280CalibrationData[bmp_idx].dig_T2)) >> 11; @@ -310,7 +316,7 @@ void Bme280Read(uint8_t bmp_idx) { float T = (t_fine * 5 + 128) >> 8; bmp_sensors[bmp_idx].bmp_temperature = T / 100.0f; - int32_t adc_P = I2cRead24(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_PRESSUREDATA, bus); + int32_t adc_P = I2cRead24(address, BME280_REGISTER_PRESSUREDATA, bus); adc_P >>= 4; int64_t var1 = ((int64_t)t_fine) - 128000; @@ -331,7 +337,7 @@ void Bme280Read(uint8_t bmp_idx) { if (BMP280_CHIPID == bmp_sensors[bmp_idx].bmp_type) { return; } - int32_t adc_H = I2cRead16(bmp_sensors[bmp_idx].bmp_address, BME280_REGISTER_HUMIDDATA, bus); + int32_t adc_H = I2cRead16(address, BME280_REGISTER_HUMIDDATA, bus); int32_t v_x1_u32r = (t_fine - ((int32_t)76800)); v_x1_u32r = (((((adc_H << 14) - (((int32_t)Bme280CalibrationData[bmp_idx].dig_H4) << 20) - @@ -360,19 +366,24 @@ struct bme68x_dev *bme_dev = nullptr; struct bme68x_conf *bme_conf = nullptr; struct bme68x_heatr_conf *bme_heatr_conf = nullptr; +uint8_t bmp68x_bus = 0; + +// bme68x callbacks static void Bme68x_Delayus(uint32_t period, void *intf_ptr) { delayMicroseconds(period); } int8_t Bme68x_i2c_read(uint8_t reg_addr, uint8_t *reg_data, uint32_t len, void *intf_ptr) { uint8_t dev_addr = *(uint8_t*)intf_ptr; - return I2cReadBuffer(dev_addr, reg_addr, reg_data, (uint16_t)len); + return I2cReadBuffer(dev_addr, reg_addr, reg_data, (uint16_t)len, bmp68x_bus); } int8_t Bme68x_i2c_write(uint8_t reg_addr, const uint8_t *reg_data, uint32_t len, void *intf_ptr) { uint8_t dev_addr = *(uint8_t*)intf_ptr; - return I2cWriteBuffer(dev_addr, reg_addr, (uint8_t *)reg_data, (uint16_t)len); + return I2cWriteBuffer(dev_addr, reg_addr, (uint8_t *)reg_data, (uint16_t)len, bmp68x_bus); } bool Bme680Init(uint8_t bmp_idx) { + bmp68x_bus = bmp_sensors[bmp_idx].bmp_bus; + if (!bme_dev) { bme_heatr_conf = (bme68x_heatr_conf*)malloc(BMP_MAX_SENSORS * sizeof(bme68x_heatr_conf)); bme_conf = (bme68x_conf*)malloc(BMP_MAX_SENSORS * sizeof(bme68x_conf)); @@ -420,6 +431,8 @@ bool Bme680Init(uint8_t bmp_idx) { void Bme680Read(uint8_t bmp_idx) { if (!bme_dev) { return; } + bmp68x_bus = bmp_sensors[bmp_idx].bmp_bus; + int8_t rslt = BME68X_OK; if (BME680_CHIPID == bmp_sensors[bmp_idx].bmp_type) { @@ -478,6 +491,7 @@ void BmpDetect(void) { uint8_t bmp_type = I2cRead8(bmp_addresses[i], BMP_REGISTER_CHIPID, bus); if (bmp_type) { bmp_sensors[bmp_count].bmp_address = bmp_addresses[i]; + bmp_sensors[bmp_count].bmp_bus = bus; bmp_sensors[bmp_count].bmp_type = bmp_type; bmp_sensors[bmp_count].bmp_model = 0; @@ -501,7 +515,7 @@ void BmpDetect(void) { } if (success) { GetTextIndexed(bmp_sensors[bmp_count].bmp_name, sizeof(bmp_sensors[bmp_count].bmp_name), bmp_sensors[bmp_count].bmp_model, kBmpTypes); - I2cSetActiveFound(bmp_sensors[bmp_count].bmp_address, bmp_sensors[bmp_count].bmp_name, bus); + I2cSetActiveFound(bmp_sensors[bmp_count].bmp_address, bmp_sensors[bmp_count].bmp_name, bmp_sensors[bmp_count].bmp_bus); bmp_count++; } } @@ -527,26 +541,31 @@ void BmpRead(void) { } } -void BmpShow(bool json) -{ +void BmpShow(bool json) { for (uint32_t bmp_idx = 0; bmp_idx < bmp_count; bmp_idx++) { if (bmp_sensors[bmp_idx].bmp_type) { float bmp_sealevel = ConvertPressureForSeaLevel(bmp_sensors[bmp_idx].bmp_pressure); float bmp_temperature = ConvertTemp(bmp_sensors[bmp_idx].bmp_temperature); float bmp_pressure = ConvertPressure(bmp_sensors[bmp_idx].bmp_pressure); - char name[12]; + char name[16]; + // BMP280 strlcpy(name, bmp_sensors[bmp_idx].bmp_name, sizeof(bmp_sensors[bmp_idx].bmp_name)); -#ifdef ESP32 - if (TasmotaGlobal.i2c_enabled_2) { - uint8_t bus = bmp_idx >>1; - if (bmp_count > 1) { - snprintf_P(name, sizeof(name), PSTR("%s%c%02X%c%1d"), name, IndexSeparator(), bmp_sensors[bmp_idx].bmp_address, IndexSeparator(), bus); // BMXXXX-XX-X - } - } else -#endif if (bmp_count > 1) { - snprintf_P(name, sizeof(name), PSTR("%s%c%02X"), name, IndexSeparator(), bmp_sensors[bmp_idx].bmp_address); // BMXXXX-XX + // BMP280-77 + snprintf_P(name, sizeof(name), PSTR("%s%c%02X"), name, IndexSeparator(), bmp_sensors[bmp_idx].bmp_address); +#ifdef ESP32 + if (TasmotaGlobal.i2c_enabled_2) { // Second bus enabled + uint8_t bus = bmp_sensors[0].bmp_bus; + for (uint32_t i = 1; i < bmp_count; i++) { + if (bus != bmp_sensors[i].bmp_bus) { // Different busses + // BMP280-77-1 + snprintf_P(name, sizeof(name), PSTR("%s%c%1d"), name, IndexSeparator(), bmp_sensors[bmp_idx].bmp_bus +1); + break; + } + } + } +#endif } char pressure[33]; From 82b6d1ee9102b350bdfe545f0033527def1b18f4 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 15 Jan 2023 17:45:59 +0100 Subject: [PATCH 144/262] Bump version to v12.3.1.4 --- CHANGELOG.md | 18 ++++++++++++------ RELEASENOTES.md | 2 +- tasmota/include/tasmota_version.h | 2 +- tasmota/tasmota_xsns_sensor/xsns_09_bmp.ino | 10 +++++----- 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b4f8c20e1..70dd1dee9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,16 +3,24 @@ All notable changes to this project will be documented in this file. ## [Unreleased] - Development -## [12.3.1.3] +## [12.3.1.4] +### Added + +### Breaking Changed + +### Changed + +### Fixed + +### Removed + +## [12.3.1.3] 20230115 ### Added - Support for PCA9632 4-channel 8-bit PWM driver as light driver by Pascal Heinrich (#17557) - Berry `bytes()` now evaluates to `false` if empty - Berry ``crypto.AES_CCM`` (required by Matter protocol) - ESP32 support for BMPxxx sensors on two I2C busses (#17643) - Berry add implicit ``_class`` parameter to static methods -- Berry add ``static class`` to declare inner classes - -### Breaking Changed ### Changed - Energy totals max supported value from +/-21474.83647 to +/-2147483.647 kWh @@ -28,8 +36,6 @@ All notable changes to this project will be documented in this file. - Rename ``tasmota4M.bin`` to ``tasmota-4M.bin`` to solve use of ``tasmota-minimal.bin`` (#17674) - DNS lookup for ``upload`` from ota server using http regression from v12.3.1.1 -### Removed - ## [12.3.1.2] 20221231 ### Added - Berry crypto add ``EC_P256`` and ``PBKDF2_HMAC_SHA256`` algorithms required by Matter protocol diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 9aa0b4f61..a35c8136a 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -107,7 +107,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm [Complete list](BUILDS.md) of available feature and sensors. -## Changelog v12.3.1.3 +## Changelog v12.3.1.4 ### Added - Support for up to 3 single phase modbus energy monitoring device using generic Energy Modbus driver- Support for RGB displays [#17414](https://github.com/arendst/Tasmota/issues/17414) - Support for IPv6 DNS records (AAAA) and IPv6 ``Ping`` for ESP32 and ESP8266 [#17417](https://github.com/arendst/Tasmota/issues/17417) diff --git a/tasmota/include/tasmota_version.h b/tasmota/include/tasmota_version.h index ff08a85fb..39ddb7b90 100644 --- a/tasmota/include/tasmota_version.h +++ b/tasmota/include/tasmota_version.h @@ -20,6 +20,6 @@ #ifndef _TASMOTA_VERSION_H_ #define _TASMOTA_VERSION_H_ -const uint32_t VERSION = 0x0C030103; // 12.3.1.3 +const uint32_t VERSION = 0x0C030104; // 12.3.1.4 #endif // _TASMOTA_VERSION_H_ diff --git a/tasmota/tasmota_xsns_sensor/xsns_09_bmp.ino b/tasmota/tasmota_xsns_sensor/xsns_09_bmp.ino index bc8f588f0..c2f17bfd8 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_09_bmp.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_09_bmp.ino @@ -71,7 +71,7 @@ typedef struct { float bmp_humidity; } bmp_sensors_t; -uint8_t bmp_addresses[] = { BMP_ADDR1, BMP_ADDR2, BMP_ADDR1, BMP_ADDR2}; +uint8_t bmp_addresses[] = { BMP_ADDR1, BMP_ADDR2 }; uint8_t bmp_count = 0; uint8_t bmp_once = 1; @@ -487,10 +487,10 @@ void BmpDetect(void) { for (uint32_t i = 0; i < BMP_MAX_SENSORS; i++) { uint8_t bus = i >>1; - if (!I2cSetDevice(bmp_addresses[i], bus)) { continue; } - uint8_t bmp_type = I2cRead8(bmp_addresses[i], BMP_REGISTER_CHIPID, bus); + if (!I2cSetDevice(bmp_addresses[i &1], bus)) { continue; } + uint8_t bmp_type = I2cRead8(bmp_addresses[i &1], BMP_REGISTER_CHIPID, bus); if (bmp_type) { - bmp_sensors[bmp_count].bmp_address = bmp_addresses[i]; + bmp_sensors[bmp_count].bmp_address = bmp_addresses[i &1]; bmp_sensors[bmp_count].bmp_bus = bus; bmp_sensors[bmp_count].bmp_type = bmp_type; bmp_sensors[bmp_count].bmp_model = 0; @@ -560,7 +560,7 @@ void BmpShow(bool json) { for (uint32_t i = 1; i < bmp_count; i++) { if (bus != bmp_sensors[i].bmp_bus) { // Different busses // BMP280-77-1 - snprintf_P(name, sizeof(name), PSTR("%s%c%1d"), name, IndexSeparator(), bmp_sensors[bmp_idx].bmp_bus +1); + snprintf_P(name, sizeof(name), PSTR("%s%c%d"), name, IndexSeparator(), bmp_sensors[bmp_idx].bmp_bus +1); break; } } From 044606d8b8fc9ce77e2f54ca7e3b3f232e473229 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 16 Jan 2023 13:32:44 +0100 Subject: [PATCH 145/262] Fix BMP deepsleep regression --- tasmota/tasmota_xsns_sensor/xsns_09_bmp.ino | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tasmota/tasmota_xsns_sensor/xsns_09_bmp.ino b/tasmota/tasmota_xsns_sensor/xsns_09_bmp.ino index c2f17bfd8..f394e8dd2 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_09_bmp.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_09_bmp.ino @@ -262,7 +262,7 @@ typedef struct { Bme280CalibrationData_t *Bme280CalibrationData = nullptr; bool Bmx280Calibrate(uint8_t bmp_idx) { - // if (I2cRead8(bmp_address, BMP_REGISTER_CHIPID) != BME280_CHIPID) return false; + // if (I2cRead8(bmp_address, BMP_REGISTER_CHIPID, bus) != BME280_CHIPID) return false; if (!Bme280CalibrationData) { Bme280CalibrationData = (Bme280CalibrationData_t*)malloc(BMP_MAX_SENSORS * sizeof(Bme280CalibrationData_t)); @@ -653,7 +653,7 @@ void BMP_EnterSleep(void) { case BMP180_CHIPID: case BMP280_CHIPID: case BME280_CHIPID: - I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BMP_REGISTER_RESET, BMP_CMND_RESET, bmp_idx >>1); + I2cWrite8(bmp_sensors[bmp_idx].bmp_address, BMP_REGISTER_RESET, BMP_CMND_RESET, bmp_sensors[bmp_idx].bmp_bus); break; default: break; @@ -668,8 +668,7 @@ void BMP_EnterSleep(void) { * Interface \*********************************************************************************************/ -bool Xsns09(uint32_t function) -{ +bool Xsns09(uint32_t function) { if (!I2cEnabled(XI2C_10)) { return false; } bool result = false; From e2c9a71c3b2e18ece4f2298ec1d68b858921cc94 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 16 Jan 2023 18:29:51 +0100 Subject: [PATCH 146/262] Prep virtual button handler --- tasmota/tasmota_support/support_button_v3.ino | 14 +++++++++++--- tasmota/tasmota_support/support_switch.ino | 4 ++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/tasmota/tasmota_support/support_button_v3.ino b/tasmota/tasmota_support/support_button_v3.ino index b12ef5714..5fbfdff94 100644 --- a/tasmota/tasmota_support/support_button_v3.ino +++ b/tasmota/tasmota_support/support_button_v3.ino @@ -83,6 +83,14 @@ void ButtonTouchFlag(uint32_t button_bit) { } #endif // ESP32 SOC_TOUCH_VERSION_1 or SOC_TOUCH_VERSION_2 +uint32_t ButtonGetVirtualOffset(void) { + return Button.present; +} + +void ButtonSetVirtual(uint32_t index, uint32_t state) { + Button.virtual_state[index] = state; +} + /*********************************************************************************************/ void ButtonProbe(void) { @@ -275,7 +283,7 @@ uint8_t ButtonSerial(uint8_t serial_in_byte) { * SetOption73 (0) - Decouple button from relay and send just mqtt topic \*********************************************************************************************/ -void ButtonHandler(void) { +void ButtonHandler(uint32_t mode) { if (TasmotaGlobal.uptime < 4) { return; } // Block GPIO for 4 seconds after poweron to workaround Wemos D1 / Obi RTS circuit uint8_t hold_time_extent = IMMINENT_RESET_FACTOR; // Extent hold time factor in case of iminnent Reset command @@ -300,7 +308,7 @@ void ButtonHandler(void) { } } else #endif // ESP8266 - if (PinUsed(GPIO_KEY1, button_index)) { + if (PinUsed(GPIO_KEY1, button_index) || (mode)) { #if defined(SOC_TOUCH_VERSION_1) || defined(SOC_TOUCH_VERSION_2) if (bitRead(TouchButton.touch_mask, button_index) && bitRead(TouchButton.calibration, button_index +1)) { // Touch @@ -528,7 +536,7 @@ void ButtonLoop(void) { if (Button.present) { if (TimeReached(Button.debounce)) { SetNextTimeInterval(Button.debounce, Settings->button_debounce); // ButtonDebounce (50) - ButtonHandler(); + ButtonHandler(0); } } } diff --git a/tasmota/tasmota_support/support_switch.ino b/tasmota/tasmota_support/support_switch.ino index f00160131..0f4eaf9c9 100644 --- a/tasmota/tasmota_support/support_switch.ino +++ b/tasmota/tasmota_support/support_switch.ino @@ -65,6 +65,10 @@ void SwitchPulldownFlag(uint32 switch_bit) { bitSet(Switch.pulldown_mask, switch_bit); } +uint32_t SwitchGetVirtualOffset(void) { + return Switch.present; +} + void SwitchSetVirtual(uint32_t index, uint32_t state) { Switch.virtual_state[index] = state; } From 457f706d1726c9dfa2ab1b566ae546ad4e0d2c6c Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Mon, 16 Jan 2023 21:48:28 +0100 Subject: [PATCH 147/262] Berry ``crypto.EC_P256`` ECDSA signature (required by Matter protocol) (#17723) --- CHANGELOG.md | 1 + .../berry_tasmota/src/be_crypto_lib.c | 4 + .../xdrv_52_3_berry_crypto.ino | 76 +++++++++++++++++++ 3 files changed, 81 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 70dd1dee9..d30ad9a6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file. ## [12.3.1.4] ### Added +- Berry ``crypto.EC_P256`` ECDSA signature (required by Matter protocol) ### Breaking Changed diff --git a/lib/libesp32/berry_tasmota/src/be_crypto_lib.c b/lib/libesp32/berry_tasmota/src/be_crypto_lib.c index 59518e120..079a9249a 100644 --- a/lib/libesp32/berry_tasmota/src/be_crypto_lib.c +++ b/lib/libesp32/berry_tasmota/src/be_crypto_lib.c @@ -27,6 +27,8 @@ extern int m_aes_ctr_tag(bvm *vm); extern int m_ec_p256_pubkey(bvm *vm); extern int m_ec_p256_sharedkey(bvm *vm); +extern int m_ec_p256_ecdsa_sign_sha256(bvm *vm); +extern int m_ec_p256_ecdsa_verify_sha256(bvm *vm); extern int m_ec_p256_mod(bvm *vm); extern int m_ec_p256_neg(bvm *vm); extern int m_ec_p256_muladd(bvm *vm); @@ -157,6 +159,8 @@ class be_class_aes_ctr (scope: global, name: AES_CTR) { class be_class_ec_p256 (scope: global, name: EC_P256) { public_key, static_func(m_ec_p256_pubkey) shared_key, static_func(m_ec_p256_sharedkey) + ecdsa_sign_sha256, static_func(m_ec_p256_ecdsa_sign_sha256) + ecdsa_verify_sha256, static_func(m_ec_p256_ecdsa_verify_sha256) mod, static_func(m_ec_p256_mod) neg, static_func(m_ec_p256_neg) muladd, static_func(m_ec_p256_muladd) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino index 40261e22b..f739b090c 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino @@ -566,6 +566,82 @@ extern "C" { be_raise(vm, kTypeError, nullptr); } + // crypto.EC_P256().ecdsa_sign_sha256(my_private_key:bytes(32), message:bytes()) -> bytes(64) + // Sign with ECDSA SHA256 + int32_t m_ec_p256_ecdsa_sign_sha256(bvm *vm); + int32_t m_ec_p256_ecdsa_sign_sha256(bvm *vm) { + int32_t argc = be_top(vm); // Get the number of arguments + if (argc >= 2 && be_isbytes(vm, 1) && be_isbytes(vm, 2)) { + size_t sk_len = 0; + uint8_t * sk = (uint8_t*) be_tobytes(vm, 1, &sk_len); + size_t msg_len = 0; + const uint8_t * msg = (const uint8_t*) be_tobytes(vm, 2, &msg_len); + if (sk_len != 32) { + be_raise(vm, "value_error", "Key size invalid"); + } + + // first compute SHA-256 hash on the message + uint8_t hash[32]; + br_sha256_context ctx; + br_sha256_init(&ctx); + br_sha256_update(&ctx, msg, msg_len); + br_sha256_out(&ctx, hash); + + // run ECDSA on hash + uint8_t sign[64]; // hard limit for ECDSA SHA256 + br_ec_private_key br_sk = { BR_EC_secp256r1, sk, 32 }; + size_t sign_len = br_ecdsa_i15_sign_raw(&BR_EC_P256_IMPL, &br_sha256_vtable, hash, &br_sk, sign); + + be_pushbytes(vm, sign, sign_len); + be_return(vm); + } + be_raise(vm, kTypeError, nullptr); + } + + // `crypto.EC_P256().ecdsa_verify_sha256(public_key:bytes(65), message:bytes(), hash:bytes()) -> bool` + // Verify signature with ECDSA SHA256 + int32_t m_ec_p256_ecdsa_verify_sha256(bvm *vm); + int32_t m_ec_p256_ecdsa_verify_sha256(bvm *vm) { + int32_t argc = be_top(vm); // Get the number of arguments + if (argc >= 3 && be_isbytes(vm, 1) && be_isbytes(vm, 2) && be_isbytes(vm, 3)) { + size_t pk_len = 0; + uint8_t * pk = (uint8_t*) be_tobytes(vm, 1, &pk_len); + size_t msg_len = 0; + const uint8_t * msg = (const uint8_t*) be_tobytes(vm, 2, &msg_len); + if (pk_len != 65) { + be_raise(vm, "value_error", "Key size invalid"); + } + size_t sig_len = 0; + const uint8_t * sig = (const uint8_t*) be_tobytes(vm, 3, &sig_len); + + // first compute SHA-256 hash on the message + uint8_t hash[32]; + br_sha256_context ctx; + br_sha256_init(&ctx); + br_sha256_update(&ctx, msg, msg_len); + br_sha256_out(&ctx, hash); + + // run ECDSA on hash + br_ec_public_key br_pk = { BR_EC_secp256r1, pk, pk_len }; + uint32_t ret = br_ecdsa_i15_vrfy_raw(&BR_EC_P256_IMPL, hash, sizeof(hash), &br_pk, sig, sig_len); + + be_pushbool(vm, ret); + be_return(vm); + } + be_raise(vm, kTypeError, nullptr); + } + /* Test values + import crypto + var priv = bytes('D42A43989B67211031FF194FBA791B5C3E03F9EC10ED561A4DEB2AA7BADB4772') + # var priv = crypto.random(32) + var pub = crypto.EC_P256().public_key(priv) + var msg = bytes().fromstring("Tasmota crypto ECDSA SECP256R1 SHA256 test message") + + var sig = crypto.EC_P256().ecdsa_sign_sha256(priv, msg) + var ok = crypto.EC_P256().ecdsa_verify_sha256(pub, msg, sig) + assert(ok == true) + */ + // We have generated the P256 order as a i15 encoding using // static const unsigned char P256_N[] PROGMEM = { // 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, From d904e0aa7f9099e1acd9c126885ea88534eed53b Mon Sep 17 00:00:00 2001 From: Barbudor Date: Tue, 17 Jan 2023 04:46:00 +0100 Subject: [PATCH 148/262] Tuya - WIFI_STRENGTH + Save check on MCU_CONF (#17724) * adding response to command 36 Get Wifi Strength * more logs * poperly check and warn if Mode 2 provide bad GPIOs * final test on gpio --- tasmota/tasmota_support/support.ino | 2 +- .../xdrv_16_tuyamcu_v1.ino | 46 ++++++++++++++++--- 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/tasmota/tasmota_support/support.ino b/tasmota/tasmota_support/support.ino index d978316d6..33b69b51b 100755 --- a/tasmota/tasmota_support/support.ino +++ b/tasmota/tasmota_support/support.ino @@ -1658,7 +1658,7 @@ uint32_t ValidPin(uint32_t pin, uint32_t gpio) { #elif defined(CONFIG_IDF_TARGET_ESP32) // ignore #else // not ESP32C3 and not ESP32S2 - if ((WEMOS == Settings->module) && !Settings->flag3.user_esp8285_enable) { // SetOption51 - Enable ESP8285 user GPIO's + if (((WEMOS == Settings->module) || (TUYA_DIMMER == Settings->module) || (USER_MODULE == Settings->module)) && !Settings->flag3.user_esp8285_enable) { // SetOption51 - Enable ESP8285 user GPIO's if ((9 == pin) || (10 == pin)) { return GPIO_NONE; // Disable possible flash GPIO9 and GPIO10 } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v1.ino b/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v1.ino index e4bb6b01a..2803bd1a5 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v1.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v1.ino @@ -42,6 +42,7 @@ #define TUYA_CMD_INITIATING_UPGRADE 0x0A #define TUYA_CMD_UPGRADE_PACKAGE 0x0B #define TUYA_CMD_SET_TIME 0x1C +#define TUYA_CMD_GET_WIFI_STRENGTH 0x24 #define TUYA_LOW_POWER_CMD_WIFI_STATE 0x02 #define TUYA_LOW_POWER_CMD_WIFI_RESET 0x03 @@ -116,7 +117,7 @@ void (* const TuyaCommand[])(void) PROGMEM = { }; const uint8_t TuyaExcludeCMDsFromMQTT[] PROGMEM = { // don't publish this received commands via MQTT if SetOption66 and SetOption137 is active (can be expanded in the future) - TUYA_CMD_HEARTBEAT, TUYA_CMD_WIFI_STATE, TUYA_CMD_SET_TIME, TUYA_CMD_UPGRADE_PACKAGE + TUYA_CMD_HEARTBEAT, TUYA_CMD_WIFI_STATE, TUYA_CMD_SET_TIME, TUYA_CMD_UPGRADE_PACKAGE, TUYA_CMD_GET_WIFI_STRENGTH }; /*********************************************************************************************\ @@ -1097,23 +1098,42 @@ void TuyaNormalPowerModePacketProcess(void) if (Tuya.buffer[5] == 2) { // Processing by ESP module mode uint8_t led1_gpio = Tuya.buffer[6]; uint8_t key1_gpio = Tuya.buffer[7]; + AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: Mode=2 led:%d, key:%d"), led1_gpio, key1_gpio); bool key1_set = false; bool led1_set = false; + // Check if LED_1 and KEY_1 are not already configured for (uint32_t i = 0; i < nitems(Settings->my_gp.io); i++) { if (Settings->my_gp.io[i] == AGPIO(GPIO_LED1)) led1_set = true; else if (Settings->my_gp.io[i] == AGPIO(GPIO_KEY1)) key1_set = true; } - if (!Settings->my_gp.io[led1_gpio] && !led1_set) { - Settings->my_gp.io[led1_gpio] = AGPIO(GPIO_LED1); - TasmotaGlobal.restart_flag = 2; + // If LED_1 not yet configured + if (!led1_set) { + // Check is the GPIO is not already in use and if it is valid + if (!Settings->my_gp.io[led1_gpio] && ValidPin(led1_gpio,GPIO_LED1)) { + Settings->my_gp.io[led1_gpio] = AGPIO(GPIO_LED1); + TasmotaGlobal.restart_flag = 2; + AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: Set LED1 on gpio%d, will restart"), led1_gpio); + } else { + AddLog(LOG_LEVEL_ERROR, PSTR("TYA: In use or illegal gpio%d for LED1, ignored"), led1_gpio); + } } - if (!Settings->my_gp.io[key1_gpio] && !key1_set) { - Settings->my_gp.io[key1_gpio] = AGPIO(GPIO_KEY1); - TasmotaGlobal.restart_flag = 2; + // If KEY_1 not yet configured + if (!key1_set) { + // Check is the GPIO is not already in use and if it is valid + if (!Settings->my_gp.io[key1_gpio] && ValidPin(key1_gpio,GPIO_KEY1)) { + Settings->my_gp.io[key1_gpio] = AGPIO(GPIO_KEY1); + TasmotaGlobal.restart_flag = 2; + AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: Set KEY1 on gpio%d, will restart"), key1_gpio); + } else { + AddLog(LOG_LEVEL_ERROR, PSTR("TYA: In use or illegal gpio%d for KEY1, ignored"), key1_gpio); + } } } TuyaRequestState(0); break; + case TUYA_CMD_GET_WIFI_STRENGTH: + TuyaSetWifiStrength(); + break; #ifdef USE_TUYA_TIME case TUYA_CMD_SET_TIME: TuyaSetTime(); @@ -1395,6 +1415,18 @@ void TuyaSetWifiLed(void) } } +void TuyaSetWifiStrength(void) { + uint16_t payload_len = 1; + uint8_t payload_buffer[1]; + int32_t rssi = WiFi.RSSI(); + int signal_strength = WifiGetRssiAsQuality(rssi); + + AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: RX MCU Get Wifi Strength -> sending %d"), signal_strength); + payload_buffer[0] = (uint8_t)signal_strength; + + TuyaSendCmd(TUYA_CMD_GET_WIFI_STRENGTH, payload_buffer, payload_len); +} + #ifdef USE_TUYA_TIME void TuyaSetTime(void) { if (!RtcTime.valid) { return; } From beb021210d6f211a78d18fd8ec78568477e324ea Mon Sep 17 00:00:00 2001 From: gemu Date: Tue, 17 Jan 2023 09:06:20 +0100 Subject: [PATCH 149/262] fix shine macros (#17725) --- .../mp3_shine_esp32/src/l3loop.cpp | 6 ++-- .../mp3_shine_esp32/src/l3mdct.cpp | 36 +++++++++---------- .../mp3_shine_esp32/src/l3subband.cpp | 36 +++++++++---------- .../mp3_shine_esp32/src/mult_noarch_gcc.h | 32 ++++++++--------- 4 files changed, 55 insertions(+), 55 deletions(-) diff --git a/lib/libesp32_audio/mp3_shine_esp32/src/l3loop.cpp b/lib/libesp32_audio/mp3_shine_esp32/src/l3loop.cpp index 2d28216d0..0dd25df90 100755 --- a/lib/libesp32_audio/mp3_shine_esp32/src/l3loop.cpp +++ b/lib/libesp32_audio/mp3_shine_esp32/src/l3loop.cpp @@ -138,7 +138,7 @@ void shine_iteration_loop(shine_global_config *config) { */ for (i=GRANULE_SIZE, config->l3loop->xrmax=0; i--;) { - config->l3loop->xrsq[i] = mulsr(config->l3loop->xr[i],config->l3loop->xr[i]); + config->l3loop->xrsq[i] = asm_mulsr(config->l3loop->xr[i],config->l3loop->xr[i]); config->l3loop->xrabs[i] = abs(config->l3loop->xr[i]); if(config->l3loop->xrabs[i]>config->l3loop->xrmax) config->l3loop->xrmax=config->l3loop->xrabs[i]; @@ -408,7 +408,7 @@ int quantize(int ix[GRANULE_SIZE], int stepsize, shine_global_config *config ) /* a quick check to see if ixmax will be less than 8192 */ /* this speeds up the early calls to bin_search_StepSize */ - if((mulr(config->l3loop->xrmax,scalei)) > 165140) /* 8192**(4/3) */ + if((asm_mulr(config->l3loop->xrmax,scalei)) > 165140) /* 8192**(4/3) */ max = 16384; /* no point in continuing, stepsize not big enough */ else for(i=0, max=0;il3loop->xr[i]),scalei); + ln = asm_mulr(abs(config->l3loop->xr[i]),scalei); if(ln<10000) /* ln < 10000 catches most values */ ix[i] = config->l3loop->int2idx[ln]; /* quick look up method */ diff --git a/lib/libesp32_audio/mp3_shine_esp32/src/l3mdct.cpp b/lib/libesp32_audio/mp3_shine_esp32/src/l3mdct.cpp index bbe660675..c51c6b5a9 100755 --- a/lib/libesp32_audio/mp3_shine_esp32/src/l3mdct.cpp +++ b/lib/libesp32_audio/mp3_shine_esp32/src/l3mdct.cpp @@ -98,32 +98,32 @@ void shine_mdct_sub(shine_global_config *config, int stride) { uint32_t vm_lo __attribute__((unused)); #endif - mul0(vm, vm_lo, mdct_in[35], config->mdct.cos_l[k][35]); + asm_mul0(vm, vm_lo, mdct_in[35], config->mdct.cos_l[k][35]); for(j=35; j; j-=7) { - muladd(vm, vm_lo, mdct_in[j-1], config->mdct.cos_l[k][j-1]); - muladd(vm, vm_lo, mdct_in[j-2], config->mdct.cos_l[k][j-2]); - muladd(vm, vm_lo, mdct_in[j-3], config->mdct.cos_l[k][j-3]); - muladd(vm, vm_lo, mdct_in[j-4], config->mdct.cos_l[k][j-4]); - muladd(vm, vm_lo, mdct_in[j-5], config->mdct.cos_l[k][j-5]); - muladd(vm, vm_lo, mdct_in[j-6], config->mdct.cos_l[k][j-6]); - muladd(vm, vm_lo, mdct_in[j-7], config->mdct.cos_l[k][j-7]); + asm_muladd(vm, vm_lo, mdct_in[j-1], config->mdct.cos_l[k][j-1]); + asm_muladd(vm, vm_lo, mdct_in[j-2], config->mdct.cos_l[k][j-2]); + asm_muladd(vm, vm_lo, mdct_in[j-3], config->mdct.cos_l[k][j-3]); + asm_muladd(vm, vm_lo, mdct_in[j-4], config->mdct.cos_l[k][j-4]); + asm_muladd(vm, vm_lo, mdct_in[j-5], config->mdct.cos_l[k][j-5]); + asm_muladd(vm, vm_lo, mdct_in[j-6], config->mdct.cos_l[k][j-6]); + asm_muladd(vm, vm_lo, mdct_in[j-7], config->mdct.cos_l[k][j-7]); } - mulz(vm, vm_lo); + asm_mulz(vm, vm_lo); mdct_enc[band][k] = vm; } /* Perform aliasing reduction butterfly */ - asm ("#cmuls:"); + asm ("#asm_cmuls:"); if (band != 0) { - cmuls(mdct_enc[band][0], mdct_enc[band-1][17-0], mdct_enc[band][0], mdct_enc[band-1][17-0], MDCT_CS0, MDCT_CA0); - cmuls(mdct_enc[band][1], mdct_enc[band-1][17-1], mdct_enc[band][1], mdct_enc[band-1][17-1], MDCT_CS1, MDCT_CA1); - cmuls(mdct_enc[band][2], mdct_enc[band-1][17-2], mdct_enc[band][2], mdct_enc[band-1][17-2], MDCT_CS2, MDCT_CA2); - cmuls(mdct_enc[band][3], mdct_enc[band-1][17-3], mdct_enc[band][3], mdct_enc[band-1][17-3], MDCT_CS3, MDCT_CA3); - cmuls(mdct_enc[band][4], mdct_enc[band-1][17-4], mdct_enc[band][4], mdct_enc[band-1][17-4], MDCT_CS4, MDCT_CA4); - cmuls(mdct_enc[band][5], mdct_enc[band-1][17-5], mdct_enc[band][5], mdct_enc[band-1][17-5], MDCT_CS5, MDCT_CA5); - cmuls(mdct_enc[band][6], mdct_enc[band-1][17-6], mdct_enc[band][6], mdct_enc[band-1][17-6], MDCT_CS6, MDCT_CA6); - cmuls(mdct_enc[band][7], mdct_enc[band-1][17-7], mdct_enc[band][7], mdct_enc[band-1][17-7], MDCT_CS7, MDCT_CA7); + asm_cmuls(mdct_enc[band][0], mdct_enc[band-1][17-0], mdct_enc[band][0], mdct_enc[band-1][17-0], MDCT_CS0, MDCT_CA0); + asm_cmuls(mdct_enc[band][1], mdct_enc[band-1][17-1], mdct_enc[band][1], mdct_enc[band-1][17-1], MDCT_CS1, MDCT_CA1); + asm_cmuls(mdct_enc[band][2], mdct_enc[band-1][17-2], mdct_enc[band][2], mdct_enc[band-1][17-2], MDCT_CS2, MDCT_CA2); + asm_cmuls(mdct_enc[band][3], mdct_enc[band-1][17-3], mdct_enc[band][3], mdct_enc[band-1][17-3], MDCT_CS3, MDCT_CA3); + asm_cmuls(mdct_enc[band][4], mdct_enc[band-1][17-4], mdct_enc[band][4], mdct_enc[band-1][17-4], MDCT_CS4, MDCT_CA4); + asm_cmuls(mdct_enc[band][5], mdct_enc[band-1][17-5], mdct_enc[band][5], mdct_enc[band-1][17-5], MDCT_CS5, MDCT_CA5); + asm_cmuls(mdct_enc[band][6], mdct_enc[band-1][17-6], mdct_enc[band][6], mdct_enc[band-1][17-6], MDCT_CS6, MDCT_CA6); + asm_cmuls(mdct_enc[band][7], mdct_enc[band-1][17-7], mdct_enc[band][7], mdct_enc[band-1][17-7], MDCT_CS7, MDCT_CA7); } } } diff --git a/lib/libesp32_audio/mp3_shine_esp32/src/l3subband.cpp b/lib/libesp32_audio/mp3_shine_esp32/src/l3subband.cpp index e6d8bdaae..683dd2cf1 100755 --- a/lib/libesp32_audio/mp3_shine_esp32/src/l3subband.cpp +++ b/lib/libesp32_audio/mp3_shine_esp32/src/l3subband.cpp @@ -66,15 +66,15 @@ void shine_window_filter_subband(int16_t **buffer, int32_t s[SBLIMIT], int ch, s uint32_t s_value_lo __attribute__((unused)); #endif - mul0 (s_value, s_value_lo, config->subband.x[ch][(config->subband.off[ch] + i + (0<<6)) & (HAN_SIZE-1)], shine_enwindow[i + (0<<6)]); - muladd(s_value, s_value_lo, config->subband.x[ch][(config->subband.off[ch] + i + (1<<6)) & (HAN_SIZE-1)], shine_enwindow[i + (1<<6)]); - muladd(s_value, s_value_lo, config->subband.x[ch][(config->subband.off[ch] + i + (2<<6)) & (HAN_SIZE-1)], shine_enwindow[i + (2<<6)]); - muladd(s_value, s_value_lo, config->subband.x[ch][(config->subband.off[ch] + i + (3<<6)) & (HAN_SIZE-1)], shine_enwindow[i + (3<<6)]); - muladd(s_value, s_value_lo, config->subband.x[ch][(config->subband.off[ch] + i + (4<<6)) & (HAN_SIZE-1)], shine_enwindow[i + (4<<6)]); - muladd(s_value, s_value_lo, config->subband.x[ch][(config->subband.off[ch] + i + (5<<6)) & (HAN_SIZE-1)], shine_enwindow[i + (5<<6)]); - muladd(s_value, s_value_lo, config->subband.x[ch][(config->subband.off[ch] + i + (6<<6)) & (HAN_SIZE-1)], shine_enwindow[i + (6<<6)]); - muladd(s_value, s_value_lo, config->subband.x[ch][(config->subband.off[ch] + i + (7<<6)) & (HAN_SIZE-1)], shine_enwindow[i + (7<<6)]); - mulz (s_value, s_value_lo); + asm_mul0 (s_value, s_value_lo, config->subband.x[ch][(config->subband.off[ch] + i + (0<<6)) & (HAN_SIZE-1)], shine_enwindow[i + (0<<6)]); + asm_muladd(s_value, s_value_lo, config->subband.x[ch][(config->subband.off[ch] + i + (1<<6)) & (HAN_SIZE-1)], shine_enwindow[i + (1<<6)]); + asm_muladd(s_value, s_value_lo, config->subband.x[ch][(config->subband.off[ch] + i + (2<<6)) & (HAN_SIZE-1)], shine_enwindow[i + (2<<6)]); + asm_muladd(s_value, s_value_lo, config->subband.x[ch][(config->subband.off[ch] + i + (3<<6)) & (HAN_SIZE-1)], shine_enwindow[i + (3<<6)]); + asm_muladd(s_value, s_value_lo, config->subband.x[ch][(config->subband.off[ch] + i + (4<<6)) & (HAN_SIZE-1)], shine_enwindow[i + (4<<6)]); + asm_muladd(s_value, s_value_lo, config->subband.x[ch][(config->subband.off[ch] + i + (5<<6)) & (HAN_SIZE-1)], shine_enwindow[i + (5<<6)]); + asm_muladd(s_value, s_value_lo, config->subband.x[ch][(config->subband.off[ch] + i + (6<<6)) & (HAN_SIZE-1)], shine_enwindow[i + (6<<6)]); + asm_muladd(s_value, s_value_lo, config->subband.x[ch][(config->subband.off[ch] + i + (7<<6)) & (HAN_SIZE-1)], shine_enwindow[i + (7<<6)]); + asm_mulz (s_value, s_value_lo); y[i] = s_value; } @@ -88,17 +88,17 @@ void shine_window_filter_subband(int16_t **buffer, int32_t s[SBLIMIT], int ch, s uint32_t s_value_lo __attribute__((unused)); #endif - mul0(s_value, s_value_lo, config->subband.fl[i][63], y[63]); + asm_mul0(s_value, s_value_lo, config->subband.fl[i][63], y[63]); for (j=63; j; j-=7) { - muladd(s_value, s_value_lo, config->subband.fl[i][j-1], y[j-1]); - muladd(s_value, s_value_lo, config->subband.fl[i][j-2], y[j-2]); - muladd(s_value, s_value_lo, config->subband.fl[i][j-3], y[j-3]); - muladd(s_value, s_value_lo, config->subband.fl[i][j-4], y[j-4]); - muladd(s_value, s_value_lo, config->subband.fl[i][j-5], y[j-5]); - muladd(s_value, s_value_lo, config->subband.fl[i][j-6], y[j-6]); - muladd(s_value, s_value_lo, config->subband.fl[i][j-7], y[j-7]); + asm_muladd(s_value, s_value_lo, config->subband.fl[i][j-1], y[j-1]); + asm_muladd(s_value, s_value_lo, config->subband.fl[i][j-2], y[j-2]); + asm_muladd(s_value, s_value_lo, config->subband.fl[i][j-3], y[j-3]); + asm_muladd(s_value, s_value_lo, config->subband.fl[i][j-4], y[j-4]); + asm_muladd(s_value, s_value_lo, config->subband.fl[i][j-5], y[j-5]); + asm_muladd(s_value, s_value_lo, config->subband.fl[i][j-6], y[j-6]); + asm_muladd(s_value, s_value_lo, config->subband.fl[i][j-7], y[j-7]); } - mulz(s_value, s_value_lo); + asm_mulz(s_value, s_value_lo); s[i] = s_value; } } diff --git a/lib/libesp32_audio/mp3_shine_esp32/src/mult_noarch_gcc.h b/lib/libesp32_audio/mp3_shine_esp32/src/mult_noarch_gcc.h index 8a191ca97..e1143f830 100755 --- a/lib/libesp32_audio/mp3_shine_esp32/src/mult_noarch_gcc.h +++ b/lib/libesp32_audio/mp3_shine_esp32/src/mult_noarch_gcc.h @@ -1,9 +1,9 @@ #include -#ifndef mul +#ifndef asm_mul //#define /// mul(a,b) (int32_t) ( ( ((int64_t) a) * ((int64_t) b) ) >>32 ) -#define mul(x,y) \ +#define asm_mul(x,y) \ ({ \ register int32_t result; \ asm ("mulsh %0, %2, %1" : "=r" (result) : "r" (x), "r" (y)); \ @@ -12,8 +12,8 @@ #endif -#ifndef muls //Not sure about this -#define muls(x,y) \ +#ifndef asm_muls //Not sure about this +#define asm_muls(x,y) \ ({ \ register int32_t result; \ asm ( \ @@ -28,8 +28,8 @@ //#define muls(a,b) (int32_t) ( ( ((int64_t) a) * ((int64_t) b) ) >>31 ) #endif -#ifndef mulr //no rounding shortcut -#define mulr(x,y) \ +#ifndef asm_mulr //no rounding shortcut +#define asm_mulr(x,y) \ ({ \ register int32_t result; \ asm ("mulsh %0, %2, %1" : "=r" (result) : "r" (x), "r" (y)); \ @@ -39,8 +39,8 @@ //#define mulr(a,b) (int32_t) ( ( ( ((int64_t) a) * ((int64_t) b)) + 0x80000000LL ) >>32 ) #endif -#ifndef mulsr //no rounding shortcut -#define mulsr(x,y) \ +#ifndef asm_mulsr //no rounding shortcut +#define asm_mulsr(x,y) \ ({ \ register int32_t result; \ asm ( \ @@ -53,11 +53,11 @@ //#define mulsr(a,b) (int32_t) ( ( ( ((int64_t) a) * ((int64_t) b)) + 0x40000000LL ) >>31 ) #endif -#ifndef mul0 -#define mul0(hi,lo,a,b) ((hi) = mul((a), (b))) +#ifndef asm_mul0 +#define asm_mul0(hi,lo,a,b) ((hi) = asm_mul((a), (b))) // This didn't seem to help either -#define muladd(hi, lo, x, y) \ +#define asm_muladd(hi, lo, x, y) \ ({ \ asm ( \ "mulsh a7, %2, %1\n\t" \ @@ -67,8 +67,8 @@ }) -//#define muladd(hi,lo,a,b) ((hi) += mul((a), (b))) - #define mulsub(hi, lo, x, y) \ +//#define asm_muladd(hi,lo,a,b) ((hi) += mul((a), (b))) + #define asm_mulsub(hi, lo, x, y) \ ({ \ asm ( \ "mulsh a8, %2, %1\n\t" \ @@ -77,10 +77,10 @@ : "a8");\ }) //#define mulsub(hi,lo,a,b) ((hi) -= mul((a), (b))) -#define mulz(hi,lo) +#define asm_mulz(hi,lo) #endif -#ifndef cmuls +#ifndef asm_cmuls /* #define cmuls(dre, dim, are, aim, bre, bim) \ do { \ @@ -109,7 +109,7 @@ do { \ } while (0)*/ -#define cmuls(dre, dim, are, aim, bre, bim) \ +#define asm_cmuls(dre, dim, are, aim, bre, bim) \ do { \ int32_t tre; \ (tre) = (int32_t) (((int64_t) (are) * (int64_t) (bre) - (int64_t) (aim) * (int64_t) (bim)) >> 31); \ From 853909cb352a9940b64a42fb15205e459715bdf6 Mon Sep 17 00:00:00 2001 From: gemu Date: Tue, 17 Jan 2023 10:19:06 +0100 Subject: [PATCH 150/262] Epaper update (#17727) * update epaper descriptors * epaper rewrite * add busy invert option * fix v2 partial refresh * prepare for large descriptors --- .../src/renderer.cpp | 4 + .../Display_Renderer-gemu-1.0/src/renderer.h | 3 +- .../Epaper_29-gemu-1.0/epd2in9.cpp | 205 ++++++-- lib/lib_display/Epaper_29-gemu-1.0/epd2in9.h | 16 +- lib/lib_display/UDisplay/uDisplay.cpp | 447 ++++++++++++++---- lib/lib_display/UDisplay/uDisplay.h | 33 +- ...display.ini => WS_epaper29_v1_display.ini} | 19 +- .../displaydesc/WS_epaper29_v2_display.ini | 96 ++++ tasmota/displaydesc/WS_epaper42_display.ini | 25 +- .../xdsp_17_universal.ino | 9 + 10 files changed, 687 insertions(+), 170 deletions(-) rename tasmota/displaydesc/{WS_epaper29_display.ini => WS_epaper29_v1_display.ini} (67%) create mode 100644 tasmota/displaydesc/WS_epaper29_v2_display.ini diff --git a/lib/lib_display/Display_Renderer-gemu-1.0/src/renderer.cpp b/lib/lib_display/Display_Renderer-gemu-1.0/src/renderer.cpp index bcef703a6..7ea9aa0e6 100644 --- a/lib/lib_display/Display_Renderer-gemu-1.0/src/renderer.cpp +++ b/lib/lib_display/Display_Renderer-gemu-1.0/src/renderer.cpp @@ -86,6 +86,10 @@ void Renderer::Begin(int16_t p1,int16_t p2,int16_t p3) { } +void Renderer::Sleep(void) { + +} + void Renderer::Updateframe() { } diff --git a/lib/lib_display/Display_Renderer-gemu-1.0/src/renderer.h b/lib/lib_display/Display_Renderer-gemu-1.0/src/renderer.h index 36196b962..279ab514d 100644 --- a/lib/lib_display/Display_Renderer-gemu-1.0/src/renderer.h +++ b/lib/lib_display/Display_Renderer-gemu-1.0/src/renderer.h @@ -35,7 +35,7 @@ typedef struct LVGL_PARAMS { uint8_t use_dma : 1; uint8_t swap_color : 1; uint8_t async_dma : 1; // force DMA completion before returning, avoid conflict with other devices on same bus. If set you should make sure the display is the only device on the bus - uint8_t resvd_1 : 1; + uint8_t busy_invert : 1; uint8_t resvd_2 : 1; uint8_t resvd_3 : 1; uint8_t resvd_4 : 1; @@ -86,6 +86,7 @@ public: virtual uint16_t bgcol(void); virtual int8_t color_type(void); virtual void Splash(void); + virtual void Sleep(void); virtual char *devname(void); virtual LVGL_PARAMS *lvgl_pars(void); virtual void ep_update_mode(uint8_t mode); diff --git a/lib/lib_display/Epaper_29-gemu-1.0/epd2in9.cpp b/lib/lib_display/Epaper_29-gemu-1.0/epd2in9.cpp index 96b83645e..9f6fe4f74 100644 --- a/lib/lib_display/Epaper_29-gemu-1.0/epd2in9.cpp +++ b/lib/lib_display/Epaper_29-gemu-1.0/epd2in9.cpp @@ -30,6 +30,9 @@ #define EPD_29_V2 +//#define BUSY_PIN 16 + + Epd::Epd(int16_t width, int16_t height) : Paint(width,height) { } @@ -38,30 +41,35 @@ void Epd::DisplayOnff(int8_t on) { } void Epd::Updateframe() { +#ifdef EPD_29_V2 + if (mode == DISPLAY_INIT_PARTIAL) { + SetFrameMemory_Partial(framebuffer, 0, 0, EPD_WIDTH,EPD_HEIGHT); + DisplayFrame_Partial(); + } else { + SetFrameMemory(framebuffer, 0, 0, EPD_WIDTH,EPD_HEIGHT); + DisplayFrame(); + } +#else SetFrameMemory(framebuffer, 0, 0, EPD_WIDTH,EPD_HEIGHT); DisplayFrame(); +#endif //Serial.printf("update\n"); } -#define DISPLAY_INIT_MODE 0 -#define DISPLAY_INIT_PARTIAL 1 -#define DISPLAY_INIT_FULL 2 - - void Epd::DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font) { // ignore update mode - if (p==DISPLAY_INIT_PARTIAL) { + if (p == DISPLAY_INIT_PARTIAL) { Init(lut_partial_update); //ClearFrameMemory(0xFF); // bit set = white, bit reset = black DisplayFrame(); - delay(500); + delay_busy(500); return; //Serial.printf("partial\n"); - } else if (p==DISPLAY_INIT_FULL) { + } else if (p == DISPLAY_INIT_FULL) { Init(lut_full_update); //ClearFrameMemory(0xFF); // bit set = white, bit reset = black DisplayFrame(); - delay(3500); + delay_busy(3500); //Serial.printf("full\n"); return; } else { @@ -80,25 +88,31 @@ void Epd::DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font) { disp_bpp = 1; } -void Epd::Begin(int16_t cs,int16_t mosi,int16_t sclk) { - cs_pin=cs; - mosi_pin=mosi; - sclk_pin=sclk; +void Epd::Begin(int16_t cs,int16_t mosi,int16_t sclk, int16_t rst, int16_t busy) { + cs_pin = cs; + mosi_pin = mosi; + sclk_pin = sclk; + rst_pin = rst; + busy_pin = busy; +#ifdef BUSY_PIN + busy_pin = BUSY_PIN; +#endif } void Epd::Init(int8_t p) { - if (p==DISPLAY_INIT_PARTIAL) { + if (p == DISPLAY_INIT_PARTIAL) { Init(lut_partial_update); } else { Init(lut_full_update); } + mode = p; ClearFrameMemory(0xFF); DisplayFrame(); - if (p==DISPLAY_INIT_PARTIAL) { - delay(350); + if (p == DISPLAY_INIT_PARTIAL) { + delay_busy(350); } else { - delay(3500); + delay_busy(3500); } } @@ -114,6 +128,9 @@ int Epd::Init(const unsigned char* lut) { sclk_pin=pin[GPIO_SSPI_SCLK]; */ + if (framebuffer) { + // free(framebuffer); + } framebuffer = (uint8_t*)malloc(EPD_WIDTH * EPD_HEIGHT / 8); if (!framebuffer) return -1; @@ -125,14 +142,24 @@ int Epd::Init(const unsigned char* lut) { digitalWrite(mosi_pin,LOW); digitalWrite(sclk_pin,LOW); + if (rst_pin >= 0) { + pinMode(rst_pin, OUTPUT); + digitalWrite(rst_pin, HIGH); + } + + if (busy_pin >= 0) { + pinMode(busy_pin, INPUT_PULLUP); + } + width = EPD_WIDTH; height = EPD_HEIGHT; #ifdef EPD_29_V2 /* EPD hardware init start */ - WaitUntilIdle(); + Reset(); + SendCommand(0x12); //SWRESET - WaitUntilIdle(); + delay_busy(100); SendCommand(0x01); //Driver output control SendData(0x27); @@ -149,9 +176,10 @@ int Epd::Init(const unsigned char* lut) { SendData(0x80); SetMemoryPointer(0, 0); - WaitUntilIdle(); + delay_busy(10); SetLut_by_host(lut_full_update); + mode = DISPLAY_INIT_FULL; #else /* EPD hardware init start */ @@ -197,31 +225,33 @@ void Epd::SendData(unsigned char data) { // SpiTransfer(data); } -/** - * @brief: Wait until the busy_pin goes LOW - */ -void Epd::WaitUntilIdle(void) { -#ifdef EPD_29_V2 - delay(100); -#endif - return; - //while(DigitalRead(busy_pin) == HIGH) { //LOW: idle, HIGH: busy - // DelayMs(100); - //} +void Epd::delay_busy(uint32_t wait) { + if (busy_pin >= 0) { + while (digitalRead(busy_pin) == HIGH) { //LOW: idle, HIGH: busy + delay(10); + } + } else { + delay(wait); + } } + /** * @brief: module reset. * often used to awaken the module in deep sleep, * see Epd::Sleep(); */ void Epd::Reset(void) { - //DigitalWrite(reset_pin, LOW); //module reset - //delay(200); - //DigitalWrite(reset_pin, HIGH); - //delay(200); + if (rst_pin >= 0) { + digitalWrite(rst_pin, LOW); //module reset + delay(200); + digitalWrite(rst_pin, HIGH); + delay(200); + } else { + SendCommand(0x12); + } } #ifdef EPD_29_V2 @@ -230,7 +260,7 @@ void Epd::SetLut(const unsigned char *lut) { SendCommand(0x32); for(count=0; count<153; count++) SendData(lut[count]); - WaitUntilIdle(); + delay_busy(50); } @@ -276,6 +306,7 @@ void Epd::SetFrameMemory( uint16_t image_width, uint16_t image_height ) { + uint16_t x_end; uint16_t y_end; @@ -366,15 +397,94 @@ void Epd::ClearFrameMemory(unsigned char color) { * set the other memory area. */ void Epd::DisplayFrame(void) { - SendCommand(DISPLAY_UPDATE_CONTROL_2); + SendCommand(DISPLAY_UPDATE_CONTROL_2); // 0x22 +#ifdef EPD_29_V2 + SendData(0xC7); +#else SendData(0xC4); - SendCommand(MASTER_ACTIVATION); +#endif + SendCommand(MASTER_ACTIVATION); // 0x20 +#ifndef EPD_29_V2 SendCommand(TERMINATE_FRAME_READ_WRITE); - WaitUntilIdle(); +#endif + delay_busy(10); +} + +void Epd::DisplayFrame_Partial(void) { + SendCommand(0x22); + SendData(0x0F); + SendCommand(0x20); + delay_busy(10); +} + +#ifdef EPD_29_V2 + +void Epd::SetFrameMemory_Partial(const unsigned char* image_buffer, int x, int y, int image_width, int image_height) { + int x_end; + int y_end; + + if ( + image_buffer == NULL || + x < 0 || image_width < 0 || + y < 0 || image_height < 0 + ) { + return; + } + /* x point must be the multiple of 8 or the last 3 bits will be ignored */ + x &= 0xF8; + image_width &= 0xF8; + if (x + image_width >= this->width) { + x_end = this->width - 1; + } else { + x_end = x + image_width - 1; + } + if (y + image_height >= this->height) { + y_end = this->height - 1; + } else { + y_end = y + image_height - 1; + } + + if (rst_pin >= 0) { + digitalWrite(rst_pin, LOW); + delay(2); + digitalWrite(rst_pin, HIGH); + delay(2); + } else { + SendCommand(0x12); + } + SetLut(lut_partial_update); + SendCommand(0x37); + SendData(0x00); + SendData(0x00); + SendData(0x00); + SendData(0x00); + SendData(0x00); + SendData(0x40); + SendData(0x00); + SendData(0x00); + SendData(0x00); + SendData(0x00); + + SendCommand(0x3C); //BorderWavefrom + SendData(0x80); + + SendCommand(0x22); + SendData(0xC0); + SendCommand(0x20); + delay_busy(100); + + SetMemoryArea(x, y, x_end, y_end); + SetMemoryPointer(x, y); + SendCommand(0x24); + /* send the image data */ + for (int j = 0; j < y_end - y + 1; j++) { + for (int i = 0; i < (x_end - x + 1) / 8; i++) { + SendData(image_buffer[i + j * (image_width / 8)]^0xff); + } + } } -#ifdef EPD_29_V2 /** * @brief: private function to specify the memory area for data R/W */ @@ -390,6 +500,15 @@ void Epd::SetMemoryArea(int x_start, int y_start, int x_end, int y_end) { SendData((y_end >> 8) & 0xFF); } #else + +void Epd::SetFrameMemory_Partial( + const unsigned char* image_buffer, + int x, + int y, + int image_width, + int image_height +) { +} /** * @brief: private function to specify the memory area for data R/W */ @@ -419,7 +538,7 @@ void Epd::SetMemoryPointer(int x, int y) { SendCommand(0x4F); SendData(y & 0xFF); SendData((y >> 8) & 0xFF); - WaitUntilIdle(); + delay_busy(10); } #else /** @@ -432,7 +551,7 @@ void Epd::SetMemoryPointer(int x, int y) { SendCommand(SET_RAM_Y_ADDRESS_COUNTER); SendData(y & 0xFF); SendData((y >> 8) & 0xFF); - WaitUntilIdle(); + delay_busy(10); } #endif @@ -444,7 +563,7 @@ void Epd::SetMemoryPointer(int x, int y) { */ void Epd::Sleep() { SendCommand(DEEP_SLEEP_MODE); - WaitUntilIdle(); + delay_busy(10); } #ifdef EPD_29_V2 diff --git a/lib/lib_display/Epaper_29-gemu-1.0/epd2in9.h b/lib/lib_display/Epaper_29-gemu-1.0/epd2in9.h index 3be3071ec..1fdba92fd 100644 --- a/lib/lib_display/Epaper_29-gemu-1.0/epd2in9.h +++ b/lib/lib_display/Epaper_29-gemu-1.0/epd2in9.h @@ -30,6 +30,10 @@ #include "epdpaint.h" +#define DISPLAY_INIT_MODE 0 +#define DISPLAY_INIT_PARTIAL 1 +#define DISPLAY_INIT_FULL 2 + // Display resolution #define EPD_WIDTH 128 #define EPD_HEIGHT 296 @@ -91,23 +95,27 @@ public: void DisplayOnff(int8_t on); void DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font); - void Begin(int16_t p1,int16_t p2,int16_t p3); + void Begin(int16_t cs,int16_t mosi,int16_t sclk, int16_t rst = -1, int16_t busy = -1); + void Updateframe(); private: unsigned int reset_pin; unsigned int dc_pin; - unsigned int busy_pin; const unsigned char* lut; unsigned int cs_pin; + signed int rst_pin; + signed int busy_pin; unsigned int mosi_pin; unsigned int sclk_pin; - + unsigned char mode; + void delay_busy(uint32_t wait); void SetLut(const unsigned char* lut); void SetMemoryArea(int x_start, int y_start, int x_end, int y_end); void SetMemoryPointer(int x, int y); void SetLut_by_host(const unsigned char* lut); - + void SetFrameMemory_Partial(const unsigned char* image_buffer,int x,int y,int image_width,int image_height); + void DisplayFrame_Partial(void); //void fastSPIwrite(uint8_t d,uint8_t dc); }; diff --git a/lib/lib_display/UDisplay/uDisplay.cpp b/lib/lib_display/UDisplay/uDisplay.cpp index d9e2b5310..bba40257a 100755 --- a/lib/lib_display/UDisplay/uDisplay.cpp +++ b/lib/lib_display/UDisplay/uDisplay.cpp @@ -66,6 +66,18 @@ uDisplay::~uDisplay(void) { if (_i80_bus) { esp_lcd_del_i80_bus(_i80_bus); } + + if (lut_full) { + free(lut_full); + } + if (lut_partial) { + free(lut_partial); + } + for (uint16_t cnt = 0; cnt < MAX_LUTS; cnt++ ) { + if (lut_array[cnt]) { + free(lut_array[cnt]); + } + } #endif // USE_ESP32_S3 } @@ -86,6 +98,7 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) { lutptime = 35; lutftime = 350; lut3time = 10; + busy_pin = -1; ep_mode = 0; fg_col = 1; bg_col = 0; @@ -96,6 +109,8 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) { startline = 0xA1; uint8_t section = 0; dsp_ncmds = 0; + epc_part_cnt = 0; + epc_full_cnt = 0; lut_num = 0; lvgl_param.data = 0; lvgl_param.fluslines = 40; @@ -103,8 +118,10 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) { rot_t[1] = 1; rot_t[2] = 2; rot_t[3] = 3; + epcoffs_full = 0; + epcoffs_part = 0; - for (uint32_t cnt = 0; cnt < 5; cnt++) { + for (uint32_t cnt = 0; cnt < MAX_LUTS; cnt++) { lut_cnt[cnt] = 0; lut_cmd[cnt] = 0xff; } @@ -135,9 +152,22 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) { } else if (section == 'L') { if (*lp1 >= '1' && *lp1 <= '5') { lut_num = (*lp1 & 0x07); - lp1+=2; + lp1 += 2; + lut_siz[lut_num - 1] = next_val(&lp1); + lut_array[lut_num - 1] = (uint8_t*)malloc(lut_siz[lut_num - 1]); lut_cmd[lut_num - 1] = next_hex(&lp1); + } else { + lut_num = 0; + lp1++; + lut_siz_full = next_val(&lp1); + lut_full = (uint8_t*)malloc(lut_siz_full); + lut_cmd[0] = next_hex(&lp1); } + } else if (section == 'l') { + lp1++; + lut_siz_partial = next_val(&lp1); + lut_partial = (uint8_t*)malloc(lut_siz_partial); + lut_cmd[0] = next_hex(&lp1); } if (*lp1 == ',') lp1++; } @@ -182,7 +212,6 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) { reset = next_val(&lp1); spi_miso = next_val(&lp1); spi_speed = next_val(&lp1); - section = 0; } else if (!strncmp(ibuff, "PAR", 3)) { #ifdef USE_ESP32_S3 @@ -256,13 +285,42 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) { } } else { while (1) { + if (dsp_ncmds >= sizeof(dsp_cmds)) break; if (!str2c(&lp1, ibuff, sizeof(ibuff))) { dsp_cmds[dsp_ncmds++] = strtol(ibuff, 0, 16); } else { break; } - if (dsp_ncmds >= sizeof(dsp_cmds)) break; - + } + } + break; + case 'f': + // epaper full update cmds + if (!epcoffs_full) { + epcoffs_full = dsp_ncmds; + epc_full_cnt = 0; + } + while (1) { + if (epc_full_cnt >= sizeof(dsp_cmds)) break; + if (!str2c(&lp1, ibuff, sizeof(ibuff))) { + dsp_cmds[epcoffs_full + epc_full_cnt++] = strtol(ibuff, 0, 16); + } else { + break; + } + } + break; + case 'p': + // epaper partial update cmds + if (!epcoffs_part) { + epcoffs_part = dsp_ncmds + epc_full_cnt; + epc_part_cnt = 0; + } + while (1) { + if (epc_part_cnt >= sizeof(dsp_cmds)) break; + if (!str2c(&lp1, ibuff, sizeof(ibuff))) { + dsp_cmds[epcoffs_part + epc_part_cnt++] = strtol(ibuff, 0, 16); + } else { + break; } } break; @@ -338,6 +396,11 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) { sa_mode = next_val(&lp1); } break; + case 'a': + saw_1 = next_hex(&lp1); + saw_2 = next_hex(&lp1); + saw_3 = next_hex(&lp1); + break; case 'P': col_mode = next_val(&lp1); break; @@ -350,34 +413,43 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) { break; case 'L': if (!lut_num) { + if (!lut_full) { + break; + } while (1) { if (!str2c(&lp1, ibuff, sizeof(ibuff))) { lut_full[lutfsize++] = strtol(ibuff, 0, 16); } else { break; } - if (lutfsize >= LUTMAXSIZE) break; + if (lutfsize >= lut_siz_full) break; } } else { uint8_t index = lut_num - 1; + if (!lut_array[index]) { + break; + } while (1) { if (!str2c(&lp1, ibuff, sizeof(ibuff))) { - lut_array[lut_cnt[index]++][index] = strtol(ibuff, 0, 16); + lut_array[index][lut_cnt[index]++] = strtol(ibuff, 0, 16); } else { break; } - if (lut_cnt[index] >= LUTMAXSIZE) break; + if (lut_cnt[index] >= lut_siz[index]) break; } } break; case 'l': + if (!lut_partial) { + break; + } while (1) { if (!str2c(&lp1, ibuff, sizeof(ibuff))) { lut_partial[lutpsize++] = strtol(ibuff, 0, 16); } else { break; } - if (lutpsize >= LUTMAXSIZE) break; + if (lutpsize >= lut_siz_partial) break; } break; case 'T': @@ -452,8 +524,8 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) { Serial.printf("Rot 0: %x,%x - %d - %d\n", madctrl, rot[0], x_addr_offs[0], y_addr_offs[0]); if (ep_mode == 1) { - Serial.printf("LUT_Partial : %d\n", lutpsize); - Serial.printf("LUT_Full : %d\n", lutfsize); + Serial.printf("LUT_Partial : %d - %d - %x - %d - %d\n", lut_siz_partial, lutpsize, lut_cmd[0], epcoffs_part, epc_part_cnt); + Serial.printf("LUT_Full : %d - %d - %x - %d - %d\n", lut_siz_full, lutfsize, lut_cmd[0], epcoffs_full, epc_full_cnt); } if (ep_mode == 2) { Serial.printf("LUT_SIZE 1: %d\n", lut_cnt[0]); @@ -533,11 +605,144 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) { } #endif +#ifdef UDSP_DEBUG + Serial.printf("Dsp class init complete\n"); +#endif +} + +void uDisplay::delay_arg(uint32_t args) { + uint32_t delay_ms = 0; + switch (args & 0xE0) { + case 0x80: delay_ms = 150; break; + case 0xA0: delay_ms = 10; break; + case 0xE0: delay_ms = 500; break; + } + if (delay_ms > 0) { + delay(delay_ms); +#ifdef UDSP_DEBUG + Serial.printf("delay %d ms\n", delay_ms); +#endif + } +} + +// epaper pseudo opcodes +#define EP_RESET 0x60 +#define EP_LUT_FULL 0x61 +#define EP_LUT_PARTIAL 0x62 +#define EP_WAITIDLE 0x63 +#define EP_SET_MEM_AREA 0x64 +#define EP_SET_MEM_PTR 0x65 +#define EP_SEND_DATA 0x66 +#define EP_CLR_FRAME 0x67 +#define EP_SEND_FRAME 0x68 + +void uDisplay::send_spi_cmds(uint16_t cmd_offset, uint16_t cmd_size) { +uint16_t index = 0; +#ifdef UDSP_DEBUG + Serial.printf("start send cmd table\n"); +#endif + while (1) { + uint8_t iob; + SPI_CS_LOW + iob = dsp_cmds[cmd_offset++]; + index++; + if (ep_mode == 1 && iob >= EP_RESET) { + // epaper pseudo opcodes + uint8_t args = dsp_cmds[cmd_offset++]; + index++; +#ifdef UDSP_DEBUG + Serial.printf("cmd, args %02x, %d ", iob, args & 0x1f); +#endif + switch (iob) { + case EP_RESET: + if (args & 1) { + iob = dsp_cmds[cmd_offset++]; + index++; + } + reset_pin(iob, iob); + break; + case EP_LUT_FULL: + SetLut(lut_full); + ep_update_mode = DISPLAY_INIT_FULL; + break; + case EP_LUT_PARTIAL: + SetLut(lut_partial); + ep_update_mode = DISPLAY_INIT_PARTIAL; + break; + case EP_WAITIDLE: + if (args & 1) { + iob = dsp_cmds[cmd_offset++]; + index++; + } + //delay(iob * 10); + delay_sync(iob * 10); + break; + case EP_SET_MEM_AREA: + SetMemoryArea(0, 0, gxs - 1, gys - 1); + break; + case EP_SET_MEM_PTR: + SetMemoryPointer(0, 0); + break; + case EP_SEND_DATA: + Send_EP_Data(); + break; + case EP_CLR_FRAME: + ClearFrameMemory(0xFF); + break; + case EP_SEND_FRAME: + SetFrameMemory(framebuffer); + break; + } +#ifdef UDSP_DEBUG + if (args & 1) { + Serial.printf("%02x ", iob ); + } + Serial.printf("\n"); +#endif + if (args & 0x80) { // delay after the command + delay_arg(args); + } + } else { + ulcd_command(iob); + uint8_t args = dsp_cmds[cmd_offset++]; + index++; +#ifdef UDSP_DEBUG + Serial.printf("cmd, args %02x, %d ", iob, args & 0x1f); +#endif + for (uint32_t cnt = 0; cnt < (args & 0x1f); cnt++) { + iob = dsp_cmds[cmd_offset++]; + index++; +#ifdef UDSP_DEBUG + Serial.printf("%02x ", iob ); +#endif + if (!allcmd_mode) { + ulcd_data8(iob); + } else { + ulcd_command(iob); + } + } + SPI_CS_HIGH +#ifdef UDSP_DEBUG + Serial.printf("\n"); +#endif + if (args & 0x80) { // delay after the command + delay_arg(args); + } + } + if (index >= cmd_size) break; + } +#ifdef UDSP_DEBUG + Serial.printf("end send cmd table\n"); +#endif } Renderer *uDisplay::Init(void) { extern bool UsePSRAM(void); + #ifdef UDSP_DEBUG + Serial.printf("Dsp Init 1 start \n"); + #endif + // for any bpp below native 16 bits, we allocate a local framebuffer to copy into if (ep_mode || bpp < 16) { if (framebuffer) free(framebuffer); @@ -549,10 +754,9 @@ Renderer *uDisplay::Init(void) { } else { framebuffer = (uint8_t*)calloc((gxs * gys * bpp) / 8, 1); } - #endif +#endif // ESP8266 } - if (interface == _UDSP_I2C) { if (wire_n == 0) { wire = &Wire; @@ -561,7 +765,7 @@ Renderer *uDisplay::Init(void) { if (wire_n == 1) { wire = &Wire1; } -#endif +#endif // ESP32 wire->begin(i2c_sda, i2c_scl); // TODO: aren't I2C buses already initialized? Shouldn't this be moved to display driver? #ifdef UDSP_DEBUG @@ -604,6 +808,10 @@ Renderer *uDisplay::Init(void) { digitalWrite(spi_clk, LOW); pinMode(spi_mosi, OUTPUT); digitalWrite(spi_mosi, LOW); + if (spi_miso >= 0) { + pinMode(spi_miso, INPUT_PULLUP); + busy_pin = spi_miso; + } } #endif // ESP8266 @@ -628,6 +836,13 @@ Renderer *uDisplay::Init(void) { digitalWrite(spi_clk, LOW); pinMode(spi_mosi, OUTPUT); digitalWrite(spi_mosi, LOW); + if (spi_miso >= 0) { + busy_pin = spi_miso; + pinMode(spi_miso, INPUT_PULLUP); +#ifdef UDSP_DEBUG + Serial.printf("Dsp busy pin: %d\n", busy_pin); +#endif + } } #endif // ESP32 @@ -639,56 +854,11 @@ Renderer *uDisplay::Init(void) { pinMode(reset, OUTPUT); digitalWrite(reset, HIGH); delay(50); - digitalWrite(reset, LOW); - delay(50); - digitalWrite(reset, HIGH); - delay(200); + reset_pin(50, 200); } - uint16_t index = 0; - while (1) { - uint8_t iob; - SPI_CS_LOW + send_spi_cmds(0, dsp_ncmds); - iob = dsp_cmds[index++]; - ulcd_command(iob); - - uint8_t args = dsp_cmds[index++]; -#ifdef UDSP_DEBUG - Serial.printf("cmd, args %02x, %d ", iob, args&0x1f); -#endif - for (uint32_t cnt = 0; cnt < (args & 0x1f); cnt++) { - iob = dsp_cmds[index++]; -#ifdef UDSP_DEBUG - Serial.printf("%02x ", iob ); -#endif - if (!allcmd_mode) { - ulcd_data8(iob); - } else { - ulcd_command(iob); - } - } - SPI_CS_HIGH -#ifdef UDSP_DEBUG - Serial.printf("\n"); -#endif - if (args & 0x80) { // delay after the command - uint32_t delay_ms = 0; - switch (args & 0xE0) { - case 0x80: delay_ms = 150; break; - case 0xA0: delay_ms = 10; break; - case 0xE0: delay_ms = 500; break; - } - if (delay_ms > 0) { - delay(delay_ms); -#ifdef UDSP_DEBUG - Serial.printf("delay %d ms\n", delay_ms); -#endif - } - - } - if (index >= dsp_ncmds) break; - } SPI_END_TRANSACTION } @@ -795,10 +965,7 @@ Renderer *uDisplay::Init(void) { pinMode(reset, OUTPUT); digitalWrite(reset, HIGH); delay(50); - digitalWrite(reset, LOW); - delay(50); - digitalWrite(reset, HIGH); - delay(200); + reset_pin(50, 200); } esp_lcd_i80_bus_config_t bus_config = { @@ -900,8 +1067,8 @@ Renderer *uDisplay::Init(void) { // must init luts on epaper if (ep_mode) { - Init_EPD(DISPLAY_INIT_FULL); - if (ep_mode == 1) Init_EPD(DISPLAY_INIT_PARTIAL); + if (ep_mode == 2) Init_EPD(DISPLAY_INIT_FULL); + //if (ep_mode == 1) Init_EPD(DISPLAY_INIT_PARTIAL); } #ifdef UDSP_DEBUG @@ -910,18 +1077,23 @@ Renderer *uDisplay::Init(void) { return this; } - - void uDisplay::DisplayInit(int8_t p, int8_t size, int8_t rot, int8_t font) { if (p != DISPLAY_INIT_MODE && ep_mode) { + ep_update_mode = p; if (p == DISPLAY_INIT_PARTIAL) { if (lutpsize) { +#ifdef UDSP_DEBUG + Serial.printf("init partial epaper mode\n"); +#endif SetLut(lut_partial); Updateframe_EPD(); - delay(lutptime * 10); + delay_sync(lutptime * 10); } return; } else if (p == DISPLAY_INIT_FULL) { +#ifdef UDSP_DEBUG + Serial.printf("init full epaper mode\n"); +#endif if (lutfsize) { SetLut(lut_full); Updateframe_EPD(); @@ -930,7 +1102,7 @@ void uDisplay::DisplayInit(int8_t p, int8_t size, int8_t rot, int8_t font) { ClearFrame_42(); DisplayFrame_42(); } - delay(lutftime * 10); + delay_sync(lutftime * 10); return; } } else { @@ -953,6 +1125,36 @@ void uDisplay::DisplayInit(int8_t p, int8_t size, int8_t rot, int8_t font) { } } +void uDisplay::reset_pin(int32_t msl, int32_t msh) { + if (reset > 0) { + digitalWrite(reset, LOW); + delay(msl); + digitalWrite(reset, HIGH); + delay(msh); + } +} + +#define UDSP_BUSY_TIMEOUT 3000 +// epaper sync or delay +void uDisplay::delay_sync(int32_t ms) { + uint8_t busy_level = HIGH; + if (lvgl_param.busy_invert) { + busy_level = LOW; + } + uint32_t time = millis(); + if (busy_pin > 0) { + + while (digitalRead(busy_pin) == busy_level) { + delay(1); + if ((millis() - time) > UDSP_BUSY_TIMEOUT) { + break; + } + } + } else { + delay(ms); + } +} + void uDisplay::ulcd_command(uint8_t val) { @@ -1462,12 +1664,16 @@ void uDisplay::Splash(void) { if (ep_mode) { Updateframe(); - delay(lut3time * 10); + delay_sync(lut3time * 10); } setTextFont(splash_font); setTextSize(splash_size); DrawStringAt(splash_xp, splash_yp, dname, fg_col, 0); Updateframe(); + +#ifdef UDSP_DEBUG + Serial.printf("draw splash\n"); +#endif } void uDisplay::setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { @@ -2116,7 +2322,7 @@ uint32_t uDisplay::str2c(char **sp, char *vp, uint32_t len) { } } } else { - uint8_t slen = strlen(lp); + uint16_t slen = strlen(lp); if (slen) { strlcpy(vp, *sp, len); *sp = lp + slen; @@ -2320,9 +2526,9 @@ void uDisplay::Init_EPD(int8_t p) { ClearFrame_42(); } if (p == DISPLAY_INIT_PARTIAL) { - delay(lutptime * 10); + delay_sync(lutptime * 10); } else { - delay(lutftime * 10); + delay_sync(lutftime * 10); } } @@ -2338,58 +2544,66 @@ void uDisplay::ClearFrameMemory(unsigned char color) { void uDisplay::SetLuts(void) { uint8_t index, count; - for (index = 0; index < 5; index++) { - spi_command_EPD(lut_cmd[index]); //vcom + for (index = 0; index < MAX_LUTS; index++) { + spi_command_EPD(lut_cmd[index]); for (count = 0; count < lut_cnt[index]; count++) { - spi_data8_EPD(lut_array[count][index]); + spi_data8_EPD(lut_array[index][count]); } } } void uDisplay::DisplayFrame_42(void) { - uint16_t Width, Height; - Width = (gxs % 8 == 0) ? (gxs / 8 ): (gxs / 8 + 1); - Height = gys; + + spi_command_EPD(saw_1); + for(int i = 0; i < gxs / 8 * gys; i++) { + spi_data8_EPD(0xFF); + } + delay(2); spi_command_EPD(saw_2); - for (uint16_t j = 0; j < Height; j++) { - for (uint16_t i = 0; i < Width; i++) { - spi_data8_EPD(framebuffer[i + j * Width] ^ 0xff); - } + for(int i = 0; i < gxs / 8 * gys; i++) { + spi_data8_EPD(framebuffer[i]^0xff); } + delay(2); + + SetLuts(); + spi_command_EPD(saw_3); - delay(100); + delay_sync(100); + +#ifdef UDSP_DEBUG Serial.printf("EPD Diplayframe\n"); +#endif } -void uDisplay::ClearFrame_42(void) { - uint16_t Width, Height; - Width = (gxs % 8 == 0)? (gxs / 8 ): (gxs / 8 + 1); - Height = gys; + +void uDisplay::ClearFrame_42(void) { spi_command_EPD(saw_1); - for (uint16_t j = 0; j < Height; j++) { - for (uint16_t i = 0; i < Width; i++) { + for (uint16_t j = 0; j < gys; j++) { + for (uint16_t i = 0; i < gxs; i++) { spi_data8_EPD(0xFF); } } spi_command_EPD(saw_2); - for (uint16_t j = 0; j < Height; j++) { - for (uint16_t i = 0; i < Width; i++) { + for (uint16_t j = 0; j < gys; j++) { + for (uint16_t i = 0; i < gxs; i++) { spi_data8_EPD(0xFF); } } spi_command_EPD(saw_3); - delay(100); + delay_sync(100); +#ifdef UDSP_DEBUG Serial.printf("EPD Clearframe\n"); +#endif } - void uDisplay::SetLut(const unsigned char* lut) { - spi_command_EPD(WRITE_LUT_REGISTER); + //spi_command_EPD(WRITE_LUT_REGISTER); + spi_command_EPD(lut_cmd[0]); /* the length of look-up table is 30 bytes */ for (int i = 0; i < lutfsize; i++) { spi_data8_EPD(lut[i]); @@ -2398,8 +2612,21 @@ void uDisplay::SetLut(const unsigned char* lut) { void uDisplay::Updateframe_EPD(void) { if (ep_mode == 1) { - SetFrameMemory(framebuffer, 0, 0, gxs, gys); - DisplayFrame_29(); + switch (ep_update_mode) { + case DISPLAY_INIT_PARTIAL: + if (epc_part_cnt) { + send_spi_cmds(epcoffs_part, epc_part_cnt); + } + break; + case DISPLAY_INIT_FULL: + if (epc_full_cnt) { + send_spi_cmds(epcoffs_full, epc_full_cnt); + } + break; + default: + SetFrameMemory(framebuffer, 0, 0, gxs, gys); + DisplayFrame_29(); + } } else { DisplayFrame_42(); } @@ -2443,6 +2670,28 @@ void uDisplay::SetMemoryPointer(int x, int y) { spi_data8_EPD((y >> 8) & 0xFF); } +#if 0 +void uDisplay::Send_EP_Data() { + for (int i = 0; i < gys / 8 * gys; i++) { + spi_data8_EPD(framebuffer[i]^0xff); + } +} +#else +void uDisplay::Send_EP_Data() { + uint16_t image_width = gxs & 0xFFF8; + uint16_t x = 0; + uint16_t y = 0; + uint16_t x_end = gxs - 1; + uint16_t y_end = gys - 1; + + for (uint16_t j = 0; j < y_end - y + 1; j++) { + for (uint16_t i = 0; i < (x_end - x + 1) / 8; i++) { + spi_data8_EPD(framebuffer[i + j * (image_width / 8)]^0xff); + } + } +} +#endif + void uDisplay::SetFrameMemory( const unsigned char* image_buffer, uint16_t x, diff --git a/lib/lib_display/UDisplay/uDisplay.h b/lib/lib_display/UDisplay/uDisplay.h index 25a27bab7..de5a8479c 100755 --- a/lib/lib_display/UDisplay/uDisplay.h +++ b/lib/lib_display/UDisplay/uDisplay.h @@ -48,6 +48,8 @@ static inline void gpio_lo(int_fast8_t pin) { if (pin >= 0) *get_gpio_lo_reg(pin #define UDISP1_WHITE 1 #define UDISP1_BLACK 0 +#define MAX_LUTS 5 + #define DISPLAY_INIT_MODE 0 #define DISPLAY_INIT_PARTIAL 1 #define DISPLAY_INIT_FULL 2 @@ -107,7 +109,6 @@ enum uColorType { uCOLOR_BW, uCOLOR_COLOR }; #define SPI_DC_LOW if (spi_dc >= 0) GPIO_CLR_SLOW(spi_dc); #define SPI_DC_HIGH if (spi_dc >= 0) GPIO_SET_SLOW(spi_dc); -#define LUTMAXSIZE 64 #ifdef USE_ESP32_S3 struct esp_lcd_i80_bus_t { @@ -245,7 +246,7 @@ class uDisplay : public Renderer { uint8_t i2c_page_start; uint8_t i2c_page_end; int8_t reset; - uint8_t dsp_cmds[128]; + uint8_t dsp_cmds[256]; uint8_t dsp_ncmds; uint8_t dsp_on; uint8_t dsp_off; @@ -289,16 +290,27 @@ class uDisplay : public Renderer { uint8_t dim_op; uint8_t lutfsize; uint8_t lutpsize; - uint16_t lutftime; + int16_t lutftime; + int8_t busy_pin; uint16_t lutptime; uint16_t lut3time; uint16_t lut_num; uint8_t ep_mode; - uint8_t lut_full[LUTMAXSIZE]; - uint8_t lut_partial[LUTMAXSIZE]; - uint8_t lut_array[LUTMAXSIZE][5]; - uint8_t lut_cnt[5]; - uint8_t lut_cmd[5]; + uint8_t ep_update_mode; + uint8_t *lut_full; + uint8_t lut_siz_full; + uint8_t *lut_partial; + uint8_t lut_siz_partial; + + uint8_t epcoffs_full; + uint8_t epc_full_cnt; + uint8_t epcoffs_part; + uint8_t epc_part_cnt; + + uint8_t *lut_array[MAX_LUTS]; + uint8_t lut_cnt[MAX_LUTS]; + uint8_t lut_cmd[MAX_LUTS]; + uint8_t lut_siz[MAX_LUTS]; uint16_t seta_xp1; uint16_t seta_xp2; uint16_t seta_yp1; @@ -308,6 +320,11 @@ class uDisplay : public Renderer { int16_t rotmap_ymin; int16_t rotmap_ymax; void pushColorsMono(uint16_t *data, uint16_t len, bool rgb16_swap = false); + void delay_sync(int32_t time); + void reset_pin(int32_t delayl, int32_t delayh); + void delay_arg(uint32_t arg); + void Send_EP_Data(void); + void send_spi_cmds(uint16_t cmd_offset, uint16_t cmd_size); #ifdef USE_ESP32_S3 int8_t par_cs; diff --git a/tasmota/displaydesc/WS_epaper29_display.ini b/tasmota/displaydesc/WS_epaper29_v1_display.ini similarity index 67% rename from tasmota/displaydesc/WS_epaper29_display.ini rename to tasmota/displaydesc/WS_epaper29_v1_display.ini index 0e63a13b1..e608fb0d0 100644 --- a/tasmota/displaydesc/WS_epaper29_display.ini +++ b/tasmota/displaydesc/WS_epaper29_v1_display.ini @@ -1,4 +1,4 @@ -:H,E-PAPER-29,128,296,1,SPI,1,*,*,*,*,*,*,*,10 +:H,E-PAPER-29-V1,128,296,1,SPI,3,*,*,*,*,*,*,*,10 :S,1,1,1,0,10,10 :I 01,3,27,01,00 @@ -7,10 +7,23 @@ 3A,1,1A 3B,1,08 11,1,03 -:L +62,0 +:f +61,0 +68,0 +22,1,c4 +20,0 +ff,0 +:p +62,0 +68,0 +22,1,c4 +20,0 +ff,0 +:L,30,32 02,02,01,11,12,12,22,22,66,69,69,59,58,99,99 88,00,00,00,00,F8,B4,13,51,35,51,51,19,01,00 -:l +:l,30,32 10,18,18,08,18,18,08,00,00,00,00,00,00,00,00 00,00,00,00,00,13,14,44,12,00,00,00,00,00,00 :T,350,35,10 diff --git a/tasmota/displaydesc/WS_epaper29_v2_display.ini b/tasmota/displaydesc/WS_epaper29_v2_display.ini new file mode 100644 index 000000000..4d0681713 --- /dev/null +++ b/tasmota/displaydesc/WS_epaper29_v2_display.ini @@ -0,0 +1,96 @@ +:H,E-PAPER-29-V2,128,296,1,SPI,4,*,*,*,*,*,*,*,10 +:S,1,1,1,0,10,10 +:I +12,0 +63,1,80 +01,3,27,01,00 +11,1,03 +64,0 +21,2,00,80 +65,0 +63,1,80 +61,0 +63,1,80 +3f,1,22 +03,1,17 +04,3,41,00,32 +2c,1,36 +67,0 +22,1,c7; +20,0 +63,1,80 +24,0 +66,0 +22,1,c7 +20,0 +63,1,80 +62 +:f +64,0 +65,0 +24,0 +66,0 +22,1,c7 +20,0 +63,1,80 +:p +60,1,2 +62,0 +63,1,80 +37,0a,00,00,00,00,00,40,00,00,00,00 +3c,1,80 +22,1,c0 +20,0 +63,1,80 +64,0 +65,0 +24,0 +66,0 +22,1,0f +20,0 +63,1,80 +62,0 + +:L,153,32 +80,66,00,00,00,00,00,00,40,00,00,00 +10,66,00,00,00,00,00,00,20,00,00,00 +80,66,00,00,00,00,00,00,40,00,00,00 +10,66,00,00,00,00,00,00,20,00,00,00 +00,00,00,00,00,00,00,00,00,00,00,00 +14,08,00,00,00,00,01 +0A,0A,00,0A,0A,00,01 +00,00,00,00,00,00,00 +00,00,00,00,00,00,00 +00,00,00,00,00,00,00 +00,00,00,00,00,00,00 +00,00,00,00,00,00,00 +00,00,00,00,00,00,00 +14,08,00,01,00,00,01 +00,00,00,00,00,00,01 +00,00,00,00,00,00,00 +00,00,00,00,00,00,00 +44,44,44,44,44,44,00,00,00 + +:l,153,32 +00,40,00,00,00,00,00,00,00,00,00,00 +80,80,00,00,00,00,00,00,00,00,00,00 +40,40,00,00,00,00,00,00,00,00,00,00 +00,80,00,00,00,00,00,00,00,00,00,00 +00,00,00,00,00,00,00,00,00,00,00,00 +0A,00,00,00,00,00,02 +01,00,00,00,00,00,00 +01,00,00,00,00,00,00 +00,00,00,00,00,00,00 +00,00,00,00,00,00,00 +00,00,00,00,00,00,00 +00,00,00,00,00,00,00 +00,00,00,00,00,00,00 +00,00,00,00,00,00,00 +00,00,00,00,00,00,00 +00,00,00,00,00,00,00 +00,00,00,00,00,00,00 +22,22,22,22,22,22,00,00,00 + + +:T,350,35,10 +# diff --git a/tasmota/displaydesc/WS_epaper42_display.ini b/tasmota/displaydesc/WS_epaper42_display.ini index 56b926116..89190b2be 100644 --- a/tasmota/displaydesc/WS_epaper42_display.ini +++ b/tasmota/displaydesc/WS_epaper42_display.ini @@ -1,25 +1,26 @@ -:H,E-PAPER-42,400,300,1,SPI,1,*,*,*,*,*,*,*,10 +:H,E-PAPER-42,400,300,1,SPI,4,*,*,*,*,*,*,*,10 :S,1,1,1,0,10,10 +:B,60,8 :I -01,5,03,00,2b,2b,03 +01,5,03,00,2b,2b,ff 06,3,17,17,17 04,80 00,1,3F 30,1,3C 61,4,01,90,01,2C -82,1,28 +82,1,12 50,1,97 -:A,10,13,12 +:a,10,13,12 :T,450,10,450 -:L1,20 -00,17,00,00,00,02 +:L1,44,20 +40,17,00,00,00,02 00,17,17,00,00,02 00,0A,01,00,00,01 00,0E,0E,00,00,02 00,00,00,00,00,00 00,00,00,00,00,00 00,00,00,00,00,00,00,00 -:L2,21 +:L2,42,21 40,17,00,00,00,02 90,17,17,00,00,02 40,0A,01,00,00,01 @@ -27,15 +28,15 @@ A0,0E,0E,00,00,02 00,00,00,00,00,00 00,00,00,00,00,00 00,00,00,00,00,00 -:L3,22 +:L3,42,22 40,17,00,00,00,02 90,17,17,00,00,02 -A0,0A,01,00,00,01 -00,0E,0E,00,00,02 +40,0A,01,00,00,01 +A0,0E,0E,00,00,02 00,00,00,00,00,00 00,00,00,00,00,00 00,00,00,00,00,00 -:L4,23 +:L4,42,23 80,17,00,00,00,02 90,17,17,00,00,02 80,0A,01,00,00,01 @@ -43,7 +44,7 @@ A0,0A,01,00,00,01 00,00,00,00,00,00 00,00,00,00,00,00 00,00,00,00,00,00 -:L5,24 +:L5,42,24 80,17,00,00,00,02 90,17,17,00,00,02 80,0A,01,00,00,01 diff --git a/tasmota/tasmota_xdsp_display/xdsp_17_universal.ino b/tasmota/tasmota_xdsp_display/xdsp_17_universal.ino index 01dd6495a..c3154cd60 100644 --- a/tasmota/tasmota_xdsp_display/xdsp_17_universal.ino +++ b/tasmota/tasmota_xdsp_display/xdsp_17_universal.ino @@ -50,7 +50,9 @@ extern uint16_t fg_color; extern uint16_t bg_color; #endif +#ifndef DISPDESC_SIZE #define DISPDESC_SIZE 1000 +#endif void Core2DisplayPower(uint8_t on); void Core2DisplayDim(uint8_t dim); @@ -94,6 +96,11 @@ int8_t cs; fp = ffsp->open(DISP_DESC_FILE, "r"); if (fp > 0) { uint32_t size = fp.size(); + if (size > DISPDESC_SIZE - 50) { + free(fbuff); + fbuff = (char*)calloc(size + 50, 1); + if (!fbuff) return 0; + } fp.read((uint8_t*)fbuff, size); fp.close(); ddesc = fbuff; @@ -148,6 +155,7 @@ int8_t cs; if (fbuff) free(fbuff); return 0; } + // now replace tasmota vars before passing to driver char *cp = strstr(ddesc, "I2C"); if (cp) { @@ -296,6 +304,7 @@ int8_t cs; delete renderer; AddLog(LOG_LEVEL_DEBUG, PSTR("DSP: reinit")); } + udisp = new uDisplay(ddesc); // checck for touch option TI1 or TI2 From bc1b35d2ffc279f454b5854f18e9edbad741e9a8 Mon Sep 17 00:00:00 2001 From: gemu Date: Wed, 18 Jan 2023 08:50:22 +0100 Subject: [PATCH 151/262] Update xdsp_05_epaper_29.ino (#17738) --- tasmota/tasmota_xdsp_display/xdsp_05_epaper_29.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tasmota/tasmota_xdsp_display/xdsp_05_epaper_29.ino b/tasmota/tasmota_xdsp_display/xdsp_05_epaper_29.ino index 46f8dabe2..4c18e219b 100644 --- a/tasmota/tasmota_xdsp_display/xdsp_05_epaper_29.ino +++ b/tasmota/tasmota_xdsp_display/xdsp_05_epaper_29.ino @@ -62,10 +62,10 @@ void EpdInitDriver29(void) { // whiten display with full update, takes 3 seconds if (TasmotaGlobal.soft_spi_enabled) { - epd->Begin(Pin(GPIO_EPAPER29_CS), Pin(GPIO_SSPI_MOSI), Pin(GPIO_SSPI_SCLK)); + epd->Begin(Pin(GPIO_EPAPER29_CS), Pin(GPIO_SSPI_MOSI), Pin(GPIO_SSPI_SCLK), Pin(GPIO_OLED_RESET), Pin(GPIO_SSPI_MISO)); } else if (TasmotaGlobal.spi_enabled) { - epd->Begin(Pin(GPIO_EPAPER29_CS), Pin(GPIO_SPI_MOSI), Pin(GPIO_SPI_CLK)); + epd->Begin(Pin(GPIO_EPAPER29_CS), Pin(GPIO_SPI_MOSI), Pin(GPIO_SPI_CLK), Pin(GPIO_OLED_RESET)); } renderer = epd; From 61be95841f782f993b7932b8b168fe9a98941f30 Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Wed, 18 Jan 2023 20:50:01 +0100 Subject: [PATCH 152/262] Berry crypto.EC_P256 ECDSA signature ASN.1 (#17740) --- .../berry_tasmota/src/be_crypto_lib.c | 4 ++ .../xdrv_52_3_berry_crypto.ino | 65 +++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/lib/libesp32/berry_tasmota/src/be_crypto_lib.c b/lib/libesp32/berry_tasmota/src/be_crypto_lib.c index 079a9249a..90c2ae7c6 100644 --- a/lib/libesp32/berry_tasmota/src/be_crypto_lib.c +++ b/lib/libesp32/berry_tasmota/src/be_crypto_lib.c @@ -29,6 +29,8 @@ extern int m_ec_p256_pubkey(bvm *vm); extern int m_ec_p256_sharedkey(bvm *vm); extern int m_ec_p256_ecdsa_sign_sha256(bvm *vm); extern int m_ec_p256_ecdsa_verify_sha256(bvm *vm); +extern int m_ec_p256_ecdsa_sign_sha256_asn1(bvm *vm); +extern int m_ec_p256_ecdsa_verify_sha256_asn1(bvm *vm); extern int m_ec_p256_mod(bvm *vm); extern int m_ec_p256_neg(bvm *vm); extern int m_ec_p256_muladd(bvm *vm); @@ -161,6 +163,8 @@ class be_class_ec_p256 (scope: global, name: EC_P256) { shared_key, static_func(m_ec_p256_sharedkey) ecdsa_sign_sha256, static_func(m_ec_p256_ecdsa_sign_sha256) ecdsa_verify_sha256, static_func(m_ec_p256_ecdsa_verify_sha256) + ecdsa_sign_sha256_asn1, static_func(m_ec_p256_ecdsa_sign_sha256_asn1) + ecdsa_verify_sha256_asn1, static_func(m_ec_p256_ecdsa_verify_sha256_asn1) mod, static_func(m_ec_p256_mod) neg, static_func(m_ec_p256_neg) muladd, static_func(m_ec_p256_muladd) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino index f739b090c..cc1f278a5 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino @@ -630,6 +630,71 @@ extern "C" { } be_raise(vm, kTypeError, nullptr); } + + // crypto.EC_P256().ecdsa_sign_sha256_asn1(my_private_key:bytes(32), message:bytes()) -> bytes() + // Sign with ECDSA SHA256, result in ASN.1 format for CSR and certificate + int32_t m_ec_p256_ecdsa_sign_sha256_asn1(bvm *vm); + int32_t m_ec_p256_ecdsa_sign_sha256_asn1(bvm *vm) { + int32_t argc = be_top(vm); // Get the number of arguments + if (argc >= 2 && be_isbytes(vm, 1) && be_isbytes(vm, 2)) { + size_t sk_len = 0; + uint8_t * sk = (uint8_t*) be_tobytes(vm, 1, &sk_len); + size_t msg_len = 0; + const uint8_t * msg = (const uint8_t*) be_tobytes(vm, 2, &msg_len); + if (sk_len != 32) { + be_raise(vm, "value_error", "Key size invalid"); + } + + // first compute SHA-256 hash on the message + uint8_t hash[32]; + br_sha256_context ctx; + br_sha256_init(&ctx); + br_sha256_update(&ctx, msg, msg_len); + br_sha256_out(&ctx, hash); + + // run ECDSA on hash + uint8_t sign[72]; // hard limit for ECDSA SHA256 ASN.1 as per bearssl documentation + br_ec_private_key br_sk = { BR_EC_secp256r1, sk, 32 }; + size_t sign_len = br_ecdsa_i15_sign_asn1(&BR_EC_P256_IMPL, &br_sha256_vtable, hash, &br_sk, sign); + + be_pushbytes(vm, sign, sign_len); + be_return(vm); + } + be_raise(vm, kTypeError, nullptr); + } + + // `crypto.EC_P256().ecdsa_verify_sha256_asn1(public_key:bytes(65), message:bytes(), hash:bytes()) -> bool` + // Verify signature with ECDSA SHA256 with signature in ASN.1 format + int32_t m_ec_p256_ecdsa_verify_sha256_asn1(bvm *vm); + int32_t m_ec_p256_ecdsa_verify_sha256_asn1(bvm *vm) { + int32_t argc = be_top(vm); // Get the number of arguments + if (argc >= 3 && be_isbytes(vm, 1) && be_isbytes(vm, 2) && be_isbytes(vm, 3)) { + size_t pk_len = 0; + uint8_t * pk = (uint8_t*) be_tobytes(vm, 1, &pk_len); + size_t msg_len = 0; + const uint8_t * msg = (const uint8_t*) be_tobytes(vm, 2, &msg_len); + if (pk_len != 65) { + be_raise(vm, "value_error", "Key size invalid"); + } + size_t sig_len = 0; + const uint8_t * sig = (const uint8_t*) be_tobytes(vm, 3, &sig_len); + + // first compute SHA-256 hash on the message + uint8_t hash[32]; + br_sha256_context ctx; + br_sha256_init(&ctx); + br_sha256_update(&ctx, msg, msg_len); + br_sha256_out(&ctx, hash); + + // run ECDSA on hash + br_ec_public_key br_pk = { BR_EC_secp256r1, pk, pk_len }; + uint32_t ret = br_ecdsa_i15_vrfy_asn1(&BR_EC_P256_IMPL, hash, sizeof(hash), &br_pk, sig, sig_len); + + be_pushbool(vm, ret); + be_return(vm); + } + be_raise(vm, kTypeError, nullptr); + } /* Test values import crypto var priv = bytes('D42A43989B67211031FF194FBA791B5C3E03F9EC10ED561A4DEB2AA7BADB4772') From e2983f28354a198a2820f01143686cc972a29bde Mon Sep 17 00:00:00 2001 From: TID Date: Fri, 20 Jan 2023 10:03:05 +0100 Subject: [PATCH 153/262] Update pl_PL.h (#17747) Fix traslation --- tasmota/language/pl_PL.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tasmota/language/pl_PL.h b/tasmota/language/pl_PL.h index 0e0415fb0..7906633aa 100644 --- a/tasmota/language/pl_PL.h +++ b/tasmota/language/pl_PL.h @@ -28,7 +28,7 @@ * Use online command StateText to translate ON, OFF, HOLD and TOGGLE. * Use online command Prefix to translate cmnd, stat and tele. * - * Updated until v11.1.0.3 - Last update 17.05.2022 + * Updated until v12.3.1.4 - Last update 19.01.2023 \*********************************************************************/ //#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -110,7 +110,7 @@ #define D_PSR_MAX_MEMORY "Pamięć PS-RAM" #define D_PSR_FREE_MEMORY "Wolna pamięć PS-RAM" #define D_FREQUENCY "Częstotliwość" -#define D_GAS "Gas" +#define D_GAS "Gaz" #define D_GATEWAY "Brama" #define D_GROUP "Grupa" #define D_HOST "Serwer" @@ -620,8 +620,8 @@ #define D_Spannung_L3 "Napięcie L3" #define D_METERNR "Numer licznika" #define D_METERSID "Identyfikator licznika" -#define D_GasIN "Licznik" -#define D_H2oIN "Licznik" +#define D_GasIN "Licznik Gazu" +#define D_H2oIN "Licznik Wody" #define D_StL1L2L3 "Prąd suma" #define D_SpL1L2L3 "Prąd średni" From 51866026d515c43b31ddc41404b3106f94d580c6 Mon Sep 17 00:00:00 2001 From: David Gwynne Date: Fri, 20 Jan 2023 19:07:42 +1000 Subject: [PATCH 154/262] TuyaMCUBr: Handle "Get local time" requests from the MCU (#17750) * handle get local time requests from the MCU. from what i can tell from the tuya serial communication protocol documentation, we only have to send the time if MCU requests it. this is unlike how TUYA_SET_TIME is implementing in xdrv_16, where if USE_TUYA_TIME is enabled it will send unsolicited time updates every minute as well as in response to a request from the MCU. i couldn't find an easy to check flag to see if tasmota was synced to a real clock, so this blindly tells the MCU that our time is valid and copies it over, the same as xdrv_16. the tuya doco also describes a "Get system time in GMT" request and response structure which would be mostly a copy of this code if i knew if and where tasmota keeps track of UTC/GMT. lastly, i'm not convinced RtcTime.day_of_week is right. it's friday here which should be 6 if you start counting sunday as 1, but i read 2 * local time sync is implemented, but not gmtime --- .../tasmota_xdrv_driver/xdrv_65_tuyamcubr.ino | 57 ++++++++++++++++++- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_65_tuyamcubr.ino b/tasmota/tasmota_xdrv_driver/xdrv_65_tuyamcubr.ino index c51c3daac..9c80900d1 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_65_tuyamcubr.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_65_tuyamcubr.ino @@ -33,7 +33,7 @@ * - supporting the raw and string Dp types * - restarting the tuya mcu state machine? * - restarting the rx state machine when no bytes are rxed for a while - * - time sync + * - gmtime sync */ #define XDRV_65 65 @@ -82,7 +82,8 @@ CTASSERT(sizeof(struct tuyamcubr_header) == 6); #define TUYAMCUBR_CMD_QUERY_STATE 0x08 #define TUYAMCUBR_CMD_INIT_UPGRADE 0x0a #define TUYAMCUBR_CMD_UPGRADE_PKG 0x0b -#define TUYAMCUBR_CMD_SET_TIME 0x1c +#define TUYAMCUBR_CMD_GMTIME 0x0c +#define TUYAMCUBR_CMD_TIME 0x1c /* wifi state */ @@ -94,6 +95,35 @@ CTASSERT(sizeof(struct tuyamcubr_header) == 6); #define TUYAMCUBR_NETWORK_STATUS_6 0x05 /* low power mode */ #define TUYAMCUBR_NETWORK_STATUS_7 0x06 /* pairing in EZ+AP mode */ +/* gmtime */ + +struct tuyamcubr_gmtime { + uint8_t valid; + uint8_t year; /* + 2000 */ + uint8_t month; /* 1 to 12 */ + uint8_t day; /* 1 to 31 */ + uint8_t hour; /* 0 to 23 */ + uint8_t minute; /* 0 to 59 */ + uint8_t second; /* 0 to 59 */ +}; + +CTASSERT(sizeof(struct tuyamcubr_gmtime) == 7); + +/* time */ + +struct tuyamcubr_time { + uint8_t valid; + uint8_t year; /* 2000 + */ + uint8_t month; /* 1 to 12 */ + uint8_t day; /* 1 to 31 */ + uint8_t hour; /* 0 to 23 */ + uint8_t minute; /* 0 to 59 */ + uint8_t second; /* 0 to 59 */ + uint8_t weekday; /* 1 (monday) to 7 */ +}; + +CTASSERT(sizeof(struct tuyamcubr_time) == 8); + /* set dp */ struct tuyamcubr_data_header { @@ -288,6 +318,8 @@ static void tuyamcubr_recv_net_status(struct tuyamcubr_softc *, uint8_t, const uint8_t *, size_t); static void tuyamcubr_recv_status(struct tuyamcubr_softc *, uint8_t, const uint8_t *, size_t); +static void tuyamcubr_recv_time(struct tuyamcubr_softc *, uint8_t, + const uint8_t *, size_t); static const struct tuyamcubr_recv_command tuyamcubr_recv_commands[] = { { TUYAMCUBR_CMD_HEARTBEAT, tuyamcubr_recv_heartbeat }, @@ -295,6 +327,7 @@ static const struct tuyamcubr_recv_command tuyamcubr_recv_commands[] = { { TUYAMCUBR_CMD_MODE, tuyamcubr_recv_mode }, { TUYAMCUBR_CMD_WIFI_STATE, tuyamcubr_recv_net_status }, { TUYAMCUBR_CMD_STATE, tuyamcubr_recv_status }, + { TUYAMCUBR_CMD_TIME, tuyamcubr_recv_time }, }; static void @@ -778,6 +811,26 @@ tuyamcubr_recv_status(struct tuyamcubr_softc *sc, uint8_t v, } while (datalen > 0); } +static void +tuyamcubr_recv_time(struct tuyamcubr_softc *sc, uint8_t v, + const uint8_t *data, size_t datalen) +{ + struct tuyamcubr_time tm; + + /* check datalen? should be 0 */ + + tm.valid = 1; /* XXX check whether time is valid */ + tm.year = RtcTime.year % 100; + tm.month = RtcTime.month; + tm.day = RtcTime.day_of_month; + tm.hour = RtcTime.hour; + tm.minute = RtcTime.minute; + tm.second = RtcTime.second; + tm.weekday = (RtcTime.day_of_week - 1) || 7; + + tuyamcubr_send(sc, TUYAMCUBR_CMD_TIME, &tm, sizeof(tm)); +} + static void tuyamcubr_tick(struct tuyamcubr_softc *sc, unsigned int ms) { From 6b4171fef96311390cb83f87b4360da42eb12caf Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Fri, 20 Jan 2023 13:19:38 +0100 Subject: [PATCH 155/262] Shelly has label `fs_1` for spiffs (#17753) * Shelly has label `fs_1` for spiffs --- tasmota/tasmota_xdrv_driver/xdrv_50_filesystem.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_50_filesystem.ino b/tasmota/tasmota_xdrv_driver/xdrv_50_filesystem.ino index 93ed23ed1..4b4e2d8a8 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_50_filesystem.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_50_filesystem.ino @@ -106,7 +106,7 @@ void UfsInitOnce(void) { #ifdef ESP32 // try lfs first ffsp = &LittleFS; - if (!LittleFS.begin(true, "")) { // force empty mount point to make it the fallback FS + if (!LittleFS.begin(true, "") && !LittleFS.begin(true, "", 5, "fs_1")) { // force empty mount point to make it the fallback FS // ffat is second ffsp = &FFat; if (!FFat.begin(true, "")) { From 498b0e55b83f25661b21d645f8b26dfd4914dcb6 Mon Sep 17 00:00:00 2001 From: Benjamin Nestler <101095581+benjaminnestler@users.noreply.github.com> Date: Fri, 20 Jan 2023 13:20:03 +0100 Subject: [PATCH 156/262] Add tuya commands CMD_GET_NETWORK_STATUS and CMD_TEST_WIFI (#17745) * Add tuya commands CMD_GET_NETWORK_STATUS and CMD_TEST_WIFI * Assuming that nobody uses the tuya test wifi ssid, the payload is hardcoded. --- .../xdrv_16_tuyamcu_v1.ino | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v1.ino b/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v1.ino index 2803bd1a5..6013fef3e 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v1.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v1.ino @@ -41,7 +41,9 @@ #define TUYA_CMD_QUERY_STATE 0x08 #define TUYA_CMD_INITIATING_UPGRADE 0x0A #define TUYA_CMD_UPGRADE_PACKAGE 0x0B +#define TUYA_CMD_TEST_WIFI 0x0E #define TUYA_CMD_SET_TIME 0x1C +#define TUYA_CMD_GET_NETWORK_STATUS 0x2B #define TUYA_CMD_GET_WIFI_STRENGTH 0x24 #define TUYA_LOW_POWER_CMD_WIFI_STATE 0x02 @@ -117,7 +119,7 @@ void (* const TuyaCommand[])(void) PROGMEM = { }; const uint8_t TuyaExcludeCMDsFromMQTT[] PROGMEM = { // don't publish this received commands via MQTT if SetOption66 and SetOption137 is active (can be expanded in the future) - TUYA_CMD_HEARTBEAT, TUYA_CMD_WIFI_STATE, TUYA_CMD_SET_TIME, TUYA_CMD_UPGRADE_PACKAGE, TUYA_CMD_GET_WIFI_STRENGTH + TUYA_CMD_HEARTBEAT, TUYA_CMD_WIFI_STATE, TUYA_CMD_SET_TIME, TUYA_CMD_UPGRADE_PACKAGE, TUYA_CMD_GET_WIFI_STRENGTH, TUYA_CMD_GET_NETWORK_STATUS, TUYA_CMD_TEST_WIFI }; /*********************************************************************************************\ @@ -1134,6 +1136,12 @@ void TuyaNormalPowerModePacketProcess(void) case TUYA_CMD_GET_WIFI_STRENGTH: TuyaSetWifiStrength(); break; + case TUYA_CMD_TEST_WIFI: + TuyaCheckTestWifi(); + break; + case TUYA_CMD_GET_NETWORK_STATUS: + TuyaSetNetworkState(); + break; #ifdef USE_TUYA_TIME case TUYA_CMD_SET_TIME: TuyaSetTime(); @@ -1427,6 +1435,23 @@ void TuyaSetWifiStrength(void) { TuyaSendCmd(TUYA_CMD_GET_WIFI_STRENGTH, payload_buffer, payload_len); } +void TuyaCheckTestWifi(void){ + // MCU request the module if whose SSID is 'tuya_mdev_test' and returns the result and the signal strength in percentage. + // Assuming that nobody uses this test wifi, the payload is hardcoded. + uint8_t payload_buffer[2] = { + 0x00, //'tuya_mdev_test' wifi not found + 0x00 //signal strength = 0 + }; + + TuyaSendCmd(TUYA_CMD_TEST_WIFI, payload_buffer, 2); +} + +void TuyaSetNetworkState (void) { + //MCU requests the network state (this state should be consitent to the wifi state) + uint8_t network_state = TuyaGetTuyaWifiState(); + TuyaSendCmd(TUYA_CMD_GET_NETWORK_STATUS, &network_state, 1); +} + #ifdef USE_TUYA_TIME void TuyaSetTime(void) { if (!RtcTime.valid) { return; } From aa78ffb733a89072644a072c8670ef3b2d0bb49d Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 20 Jan 2023 14:28:58 +0100 Subject: [PATCH 157/262] Prep Shelly Pro 4PM --- tasmota/include/tasmota.h | 33 ++++++++++++------- tasmota/include/tasmota_template.h | 2 +- tasmota/tasmota_support/support_button_v3.ino | 14 ++------ ...pport_switch.ino => support_switch_v3.ino} | 4 --- .../tasmota_xx2c_global/xdrv_interface.ino | 16 ++------- .../tasmota_xx2c_global/xsns_interface.ino | 6 ++-- 6 files changed, 30 insertions(+), 45 deletions(-) rename tasmota/tasmota_support/{support_switch.ino => support_switch_v3.ino} (99%) diff --git a/tasmota/include/tasmota.h b/tasmota/include/tasmota.h index fdc87cc1d..f3e9bfbde 100644 --- a/tasmota/include/tasmota.h +++ b/tasmota/include/tasmota.h @@ -386,18 +386,27 @@ enum LightSubtypes { LST_NONE, LST_SINGLE, LST_COLDWARM, LST_RGB, LST_RGBW, LS enum LightTypes { LT_BASIC, LT_PWM1, LT_PWM2, LT_PWM3, LT_PWM4, LT_PWM5, LT_PWM6, LT_PWM7, LT_NU8, LT_SERIAL1, LT_SERIAL2, LT_RGB, LT_RGBW, LT_RGBWC, LT_NU14, LT_NU15 }; // Do not insert new fields -enum XsnsFunctions {FUNC_SETTINGS_OVERRIDE, FUNC_PIN_STATE, FUNC_I2C_INIT, FUNC_MODULE_INIT, FUNC_PRE_INIT, FUNC_INIT, - FUNC_LOOP, FUNC_SLEEP_LOOP, FUNC_EVERY_50_MSECOND, FUNC_EVERY_100_MSECOND, FUNC_EVERY_200_MSECOND, FUNC_EVERY_250_MSECOND, FUNC_EVERY_SECOND, - FUNC_SAVE_SETTINGS, FUNC_SAVE_AT_MIDNIGHT, FUNC_SAVE_BEFORE_RESTART, FUNC_INTERRUPT_STOP, FUNC_INTERRUPT_START, - FUNC_AFTER_TELEPERIOD, FUNC_JSON_APPEND, FUNC_WEB_SENSOR, FUNC_WEB_COL_SENSOR, FUNC_COMMAND, FUNC_COMMAND_SENSOR, FUNC_COMMAND_DRIVER, - FUNC_MQTT_SUBSCRIBE, FUNC_MQTT_INIT, FUNC_MQTT_DATA, - FUNC_SET_POWER, FUNC_SET_DEVICE_POWER, FUNC_SHOW_SENSOR, FUNC_ANY_KEY, FUNC_LED_LINK, - FUNC_ENERGY_EVERY_SECOND, FUNC_ENERGY_RESET, - FUNC_RULES_PROCESS, FUNC_TELEPERIOD_RULES_PROCESS, FUNC_SERIAL, FUNC_FREE_MEM, FUNC_BUTTON_PRESSED, FUNC_BUTTON_MULTI_PRESSED, - FUNC_WEB_ADD_BUTTON, FUNC_WEB_ADD_CONSOLE_BUTTON, FUNC_WEB_ADD_MANAGEMENT_BUTTON, FUNC_WEB_ADD_MAIN_BUTTON, - FUNC_WEB_GET_ARG, FUNC_WEB_ADD_HANDLER, FUNC_SET_CHANNELS, FUNC_SET_SCHEME, FUNC_HOTPLUG_SCAN, FUNC_TIME_SYNCED, - FUNC_DEVICE_GROUP_ITEM, - FUNC_NETWORK_UP, FUNC_NETWORK_DOWN }; +enum XsnsFunctions { FUNC_SETTINGS_OVERRIDE, FUNC_I2C_INIT, FUNC_PRE_INIT, FUNC_INIT, + FUNC_LOOP, FUNC_SLEEP_LOOP, FUNC_EVERY_50_MSECOND, FUNC_EVERY_100_MSECOND, FUNC_EVERY_200_MSECOND, FUNC_EVERY_250_MSECOND, FUNC_EVERY_SECOND, + FUNC_SAVE_SETTINGS, FUNC_SAVE_AT_MIDNIGHT, FUNC_SAVE_BEFORE_RESTART, FUNC_INTERRUPT_STOP, FUNC_INTERRUPT_START, + FUNC_AFTER_TELEPERIOD, FUNC_JSON_APPEND, FUNC_WEB_SENSOR, FUNC_WEB_COL_SENSOR, + FUNC_MQTT_SUBSCRIBE, FUNC_MQTT_INIT, + FUNC_SET_POWER, FUNC_SHOW_SENSOR, FUNC_ANY_KEY, FUNC_LED_LINK, + FUNC_ENERGY_EVERY_SECOND, FUNC_ENERGY_RESET, + FUNC_TELEPERIOD_RULES_PROCESS, FUNC_FREE_MEM, + FUNC_WEB_ADD_BUTTON, FUNC_WEB_ADD_CONSOLE_BUTTON, FUNC_WEB_ADD_MANAGEMENT_BUTTON, FUNC_WEB_ADD_MAIN_BUTTON, + FUNC_WEB_GET_ARG, FUNC_WEB_ADD_HANDLER, FUNC_SET_SCHEME, FUNC_HOTPLUG_SCAN, FUNC_TIME_SYNCED, + FUNC_DEVICE_GROUP_ITEM, + FUNC_NETWORK_UP, FUNC_NETWORK_DOWN, + FUNC_return_result = 200, // Insert function WITHOUT return results before here. Following functions return results + FUNC_PIN_STATE, FUNC_MODULE_INIT, FUNC_ADD_BUTTON, FUNC_ADD_SWITCH, FUNC_BUTTON_PRESSED, FUNC_BUTTON_MULTI_PRESSED, + FUNC_SET_DEVICE_POWER, + FUNC_MQTT_DATA, FUNC_SERIAL, + FUNC_COMMAND, FUNC_COMMAND_SENSOR, FUNC_COMMAND_DRIVER, + FUNC_RULES_PROCESS, + FUNC_SET_CHANNELS, + FUNC_last_function // Insert functions with return results before here + }; enum AddressConfigSteps { ADDR_IDLE, ADDR_RECEIVE, ADDR_SEND }; diff --git a/tasmota/include/tasmota_template.h b/tasmota/include/tasmota_template.h index 700481241..ecd43e1d1 100644 --- a/tasmota/include/tasmota_template.h +++ b/tasmota/include/tasmota_template.h @@ -812,7 +812,7 @@ const uint16_t kGpioNiceList[] PROGMEM = { #endif #ifdef USE_ADE7953 #if defined(USE_I2C) || defined(USE_SPI) - AGPIO(GPIO_ADE7953_IRQ) + 5, // ADE7953 IRQ - (1 = Shelly 2.5, 2 = Shelly EM, 3 = Shelly Plus 2PM, 4 = Shelly Pro 1PM, 5 = Shelly Pro 2PM) + AGPIO(GPIO_ADE7953_IRQ) + 6, // ADE7953 IRQ - (1 = Shelly 2.5, 2 = Shelly EM, 3 = Shelly Plus 2PM, 4 = Shelly Pro 1PM, 5 = Shelly Pro 2PM, 6 = Shelly Pro 4PM) AGPIO(GPIO_ADE7953_RST), // ADE7953 Reset #ifdef USE_SPI AGPIO(GPIO_ADE7953_CS) + 2, // ADE7953 SPI Chip Select (1 = CS1 (1PM, 2PM), 2 = CS2 (2PM)) diff --git a/tasmota/tasmota_support/support_button_v3.ino b/tasmota/tasmota_support/support_button_v3.ino index 5fbfdff94..b12ef5714 100644 --- a/tasmota/tasmota_support/support_button_v3.ino +++ b/tasmota/tasmota_support/support_button_v3.ino @@ -83,14 +83,6 @@ void ButtonTouchFlag(uint32_t button_bit) { } #endif // ESP32 SOC_TOUCH_VERSION_1 or SOC_TOUCH_VERSION_2 -uint32_t ButtonGetVirtualOffset(void) { - return Button.present; -} - -void ButtonSetVirtual(uint32_t index, uint32_t state) { - Button.virtual_state[index] = state; -} - /*********************************************************************************************/ void ButtonProbe(void) { @@ -283,7 +275,7 @@ uint8_t ButtonSerial(uint8_t serial_in_byte) { * SetOption73 (0) - Decouple button from relay and send just mqtt topic \*********************************************************************************************/ -void ButtonHandler(uint32_t mode) { +void ButtonHandler(void) { if (TasmotaGlobal.uptime < 4) { return; } // Block GPIO for 4 seconds after poweron to workaround Wemos D1 / Obi RTS circuit uint8_t hold_time_extent = IMMINENT_RESET_FACTOR; // Extent hold time factor in case of iminnent Reset command @@ -308,7 +300,7 @@ void ButtonHandler(uint32_t mode) { } } else #endif // ESP8266 - if (PinUsed(GPIO_KEY1, button_index) || (mode)) { + if (PinUsed(GPIO_KEY1, button_index)) { #if defined(SOC_TOUCH_VERSION_1) || defined(SOC_TOUCH_VERSION_2) if (bitRead(TouchButton.touch_mask, button_index) && bitRead(TouchButton.calibration, button_index +1)) { // Touch @@ -536,7 +528,7 @@ void ButtonLoop(void) { if (Button.present) { if (TimeReached(Button.debounce)) { SetNextTimeInterval(Button.debounce, Settings->button_debounce); // ButtonDebounce (50) - ButtonHandler(0); + ButtonHandler(); } } } diff --git a/tasmota/tasmota_support/support_switch.ino b/tasmota/tasmota_support/support_switch_v3.ino similarity index 99% rename from tasmota/tasmota_support/support_switch.ino rename to tasmota/tasmota_support/support_switch_v3.ino index 0f4eaf9c9..f00160131 100644 --- a/tasmota/tasmota_support/support_switch.ino +++ b/tasmota/tasmota_support/support_switch_v3.ino @@ -65,10 +65,6 @@ void SwitchPulldownFlag(uint32 switch_bit) { bitSet(Switch.pulldown_mask, switch_bit); } -uint32_t SwitchGetVirtualOffset(void) { - return Switch.present; -} - void SwitchSetVirtual(uint32_t index, uint32_t state) { Switch.virtual_state[index] = state; } diff --git a/tasmota/tasmota_xx2c_global/xdrv_interface.ino b/tasmota/tasmota_xx2c_global/xdrv_interface.ino index 247e7adb2..fda25f067 100644 --- a/tasmota/tasmota_xx2c_global/xdrv_interface.ino +++ b/tasmota/tasmota_xx2c_global/xdrv_interface.ino @@ -1143,24 +1143,14 @@ bool XdrvCall(uint32_t function) { #ifdef USE_PROFILE_FUNCTION #ifdef XFUNC_PTR_IN_ROM - uint32_t index = pgm_read_byte(kXdrvList + x); + uint32_t index = pgm_read_byte(kXdrvList + x); #else - uint32_t index = kXdrvList[x]; + uint32_t index = kXdrvList[x]; #endif PROFILE_FUNCTION("drv", index, function, profile_function_start); #endif // USE_PROFILE_FUNCTION - if (result && ((FUNC_COMMAND == function) || - (FUNC_COMMAND_DRIVER == function) || - (FUNC_MQTT_DATA == function) || - (FUNC_RULES_PROCESS == function) || - (FUNC_BUTTON_PRESSED == function) || - (FUNC_SERIAL == function) || - (FUNC_MODULE_INIT == function) || - (FUNC_SET_CHANNELS == function) || - (FUNC_PIN_STATE == function) || - (FUNC_SET_DEVICE_POWER == function) - )) { + if (result && (function > FUNC_return_result)) { break; } } diff --git a/tasmota/tasmota_xx2c_global/xsns_interface.ino b/tasmota/tasmota_xx2c_global/xsns_interface.ino index 71f3dceb4..acff24be0 100644 --- a/tasmota/tasmota_xx2c_global/xsns_interface.ino +++ b/tasmota/tasmota_xx2c_global/xsns_interface.ino @@ -1135,12 +1135,10 @@ bool XsnsCall(uint32_t function) { PROFILE_FUNCTION("sns", index, function, profile_function_start); #endif // USE_PROFILE_FUNCTION - if (result && ((FUNC_COMMAND == function) || - (FUNC_PIN_STATE == function) || - (FUNC_COMMAND_SENSOR == function) - )) { + if (result && (function > FUNC_return_result)) { break; } + } } From 2605a7158cfc749ba45a342bf05890f531235b98 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Sat, 21 Jan 2023 12:02:39 +0100 Subject: [PATCH 158/262] Build solo1 variant as full Tasmota32 version --- platformio_tasmota_env32.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/platformio_tasmota_env32.ini b/platformio_tasmota_env32.ini index d68554e80..f16b4cc12 100644 --- a/platformio_tasmota_env32.ini +++ b/platformio_tasmota_env32.ini @@ -98,6 +98,7 @@ lib_extra_dirs = lib/libesp32, lib/lib_basic, lib/lib_ssl [env:tasmota32solo1] extends = env:tasmota32_base board = esp32_solo1 +build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_TASMOTA32 [env:tasmota32solo1-safeboot] extends = env:tasmota32_base From 0743b7d2b69a1f73a653ace672ae8d271f950e05 Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Sat, 21 Jan 2023 13:41:36 +0100 Subject: [PATCH 159/262] Berry add up flag to ``tasmota.wifi()`` and ``tasmota.eth()``, always return MAC (#17759) --- CHANGELOG.md | 1 + .../tasmota_xdrv_driver/xdrv_52_3_berry_tasmota.ino | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d30ad9a6c..72221d18c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file. ## [12.3.1.4] ### Added - Berry ``crypto.EC_P256`` ECDSA signature (required by Matter protocol) +- Berry add up flag to ``tasmota.wifi()`` and ``tasmota.eth()``, always return MAC ### Breaking Changed diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota.ino index 015d505e7..b31ed5b99 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota.ino @@ -211,6 +211,8 @@ extern "C" { int32_t top = be_top(vm); // Get the number of arguments if (top == 1) { // no argument (instance only) be_newobject(vm, "map"); + be_map_insert_str(vm, "mac", WiFi.macAddress().c_str()); + be_map_insert_bool(vm, "up", WifiHasIP()); if (Settings->flag4.network_wifi) { int32_t rssi = WiFi.RSSI(); bool show_rssi = false; @@ -227,7 +229,6 @@ extern "C" { } #endif // USE_IPV6 if (static_cast(WiFi.localIP()) != 0) { - be_map_insert_str(vm, "mac", WiFi.macAddress().c_str()); be_map_insert_str(vm, "ip", IPAddress((uint32_t)WiFi.localIP()).toString().c_str()); // quick fix for IPAddress bug show_rssi = true; } @@ -250,8 +251,12 @@ extern "C" { if (top == 1) { // no argument (instance only) be_newobject(vm, "map"); #ifdef USE_ETHERNET + be_map_insert_bool(vm, "up", EthernetHasIP()); + String eth_mac = EthernetMacAddress().c_str(); + if (eth_mac != "00:00:00:00:00:00") { + be_map_insert_str(vm, "mac", eth_mac.c_str()); + } if (static_cast(EthernetLocalIP()) != 0) { - be_map_insert_str(vm, "mac", EthernetMacAddress().c_str()); be_map_insert_str(vm, "ip", IPAddress((uint32_t)EthernetLocalIP()).toString().c_str()); // quick fix for IPAddress bug } #ifdef USE_IPV6 @@ -264,6 +269,8 @@ extern "C" { be_map_insert_str(vm, "ip6local", ipv6_addr.c_str()); } #endif // USE_IPV6 +#else // USE_ETHERNET + be_map_insert_bool(vm, "up", bfalse); #endif // USE_ETHERNET be_pop(vm, 1); be_return(vm); From c85003c67da57458e63935032528603f72663a23 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sat, 21 Jan 2023 14:30:35 +0100 Subject: [PATCH 160/262] Prep Shelly Pro 4PM --- tasmota/include/tasmota.h | 2 +- tasmota/tasmota_support/support_button_v3.ino | 2 +- tasmota/tasmota_support/support_button_v4.ino | 572 ++++++++++++++++++ tasmota/tasmota_support/support_switch_v3.ino | 2 +- tasmota/tasmota_support/support_switch_v4.ino | 490 +++++++++++++++ .../xdrv_52_3_berry_tasmota.ino | 2 +- .../xdrv_88_esp32_shelly_pro.ino | 2 +- .../xdrv_88_esp32_shelly_pro_v2.ino | 501 +++++++++++++++ .../tasmota_xnrg_energy/xnrg_07_ade7953.ino | 90 ++- 9 files changed, 1636 insertions(+), 27 deletions(-) create mode 100644 tasmota/tasmota_support/support_button_v4.ino create mode 100644 tasmota/tasmota_support/support_switch_v4.ino create mode 100644 tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v2.ino diff --git a/tasmota/include/tasmota.h b/tasmota/include/tasmota.h index f3e9bfbde..db4bcec0b 100644 --- a/tasmota/include/tasmota.h +++ b/tasmota/include/tasmota.h @@ -405,7 +405,7 @@ enum XsnsFunctions { FUNC_SETTINGS_OVERRIDE, FUNC_I2C_INIT, FUNC_PRE_INIT, FUNC_ FUNC_COMMAND, FUNC_COMMAND_SENSOR, FUNC_COMMAND_DRIVER, FUNC_RULES_PROCESS, FUNC_SET_CHANNELS, - FUNC_last_function // Insert functions with return results before here + FUNC_last_function // Insert functions WITH return results before here }; enum AddressConfigSteps { ADDR_IDLE, ADDR_RECEIVE, ADDR_SEND }; diff --git a/tasmota/tasmota_support/support_button_v3.ino b/tasmota/tasmota_support/support_button_v3.ino index b12ef5714..92e278ec0 100644 --- a/tasmota/tasmota_support/support_button_v3.ino +++ b/tasmota/tasmota_support/support_button_v3.ino @@ -17,7 +17,7 @@ along with this program. If not, see . */ -#define BUTTON_V3 +//#define BUTTON_V3 #ifdef BUTTON_V3 /*********************************************************************************************\ * Button support with input filter diff --git a/tasmota/tasmota_support/support_button_v4.ino b/tasmota/tasmota_support/support_button_v4.ino new file mode 100644 index 000000000..4de6f9ae5 --- /dev/null +++ b/tasmota/tasmota_support/support_button_v4.ino @@ -0,0 +1,572 @@ +/* + support_button.ino - button support for Tasmota + + Copyright (C) 2022 Federico Leoni and Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#define BUTTON_V4 +#ifdef BUTTON_V4 +/*********************************************************************************************\ + * Button support with input filter + * + * Inspired by (https://github.com/OLIMEX/olimex-iot-firmware-esp8266/blob/master/olimex/user/user_switch2.c) +\*********************************************************************************************/ + +#define MAX_RELAY_BUTTON1 5 // Max number of relay controlled by BUTTON1 + +const uint8_t BUTTON_PROBE_INTERVAL = 10; // Time in milliseconds between button input probe +const uint8_t BUTTON_FAST_PROBE_INTERVAL = 2; // Time in milliseconds between button input probe for AC detection +const uint8_t BUTTON_AC_PERIOD = (20 + BUTTON_FAST_PROBE_INTERVAL - 1) / BUTTON_FAST_PROBE_INTERVAL; // Duration of an AC wave in probe intervals + +const char kMultiPress[] PROGMEM = "|SINGLE|DOUBLE|TRIPLE|QUAD|PENTA|CLEAR|"; + +#include + +Ticker TickerButton; + +struct BUTTON { + uint32_t debounce = 0; // Button debounce timer + uint32_t no_pullup_mask = 0; // key no pullup flag (1 = no pullup) + uint32_t pulldown_mask = 0; // key pulldown flag (1 = pulldown) + uint32_t inverted_mask = 0; // Key inverted flag (1 = inverted) + uint32_t virtual_pin_used = 0; // Key used bitmask + uint32_t virtual_pin = 0; // Key state bitmask + uint16_t hold_timer[MAX_KEYS] = { 0 }; // Timer for button hold + uint16_t dual_code = 0; // Sonoff dual received code + uint8_t state[MAX_KEYS] = { 0 }; + uint8_t last_state[MAX_KEYS]; // Last button states + uint8_t debounced_state[MAX_KEYS]; // Button debounced states + uint8_t window_timer[MAX_KEYS] = { 0 }; // Max time between button presses to record press count + uint8_t press_counter[MAX_KEYS] = { 0 }; // Number of button presses within Button.window_timer + uint8_t dual_receive_count = 0; // Sonoff dual input flag + uint8_t first_change = 0; + uint8_t present = 0; // Number of buttons found flag + bool probe_mutex; +} Button; + +#if defined(SOC_TOUCH_VERSION_1) || defined(SOC_TOUCH_VERSION_2) +struct TOUCH_BUTTON { + uint32_t touch_mask = 0; // Touch flag (1 = enabled) + uint32_t calibration = 0; // Bitfield + uint8_t hits[MAX_KEYS] = { 0 }; // Hits in a row to filter out noise +} TouchButton; +#endif // ESP32 SOC_TOUCH_VERSION_1 or SOC_TOUCH_VERSION_2 + +/********************************************************************************************/ + +void ButtonPullupFlag(uint32_t button_bit) { + bitSet(Button.no_pullup_mask, button_bit); +} + +void ButtonPulldownFlag(uint32_t button_bit) { + bitSet(Button.pulldown_mask, button_bit); +} + +void ButtonInvertFlag(uint32_t button_bit) { + bitSet(Button.inverted_mask, button_bit); +} + +#if defined(SOC_TOUCH_VERSION_1) || defined(SOC_TOUCH_VERSION_2) +void ButtonTouchFlag(uint32_t button_bit) { + bitSet(TouchButton.touch_mask, button_bit); +} +#endif // ESP32 SOC_TOUCH_VERSION_1 or SOC_TOUCH_VERSION_2 + + +void ButtonSetVirtualPinState(uint32_t index, uint32_t state) { + if (!Button.probe_mutex) { + bitWrite(Button.virtual_pin, index, state); + } +} + +/*********************************************************************************************/ + +void ButtonProbe(void) { + if (Button.probe_mutex || (TasmotaGlobal.uptime < 4)) { return; } // Block GPIO for 4 seconds after poweron to workaround Wemos D1 / Obi RTS circuit + Button.probe_mutex = true; + + uint32_t state_filter; + uint32_t first_change = Button.first_change; + uint32_t debounce_flags = Settings->button_debounce % 10; + bool force_high = (debounce_flags &1); // 51, 101, 151 etc + bool force_low = (debounce_flags &2); // 52, 102, 152 etc + bool ac_detect = (debounce_flags == 9); // 39, 49, 59 etc + + if (ac_detect) { + if (Settings->button_debounce < 2 * BUTTON_AC_PERIOD * BUTTON_FAST_PROBE_INTERVAL + 9) { + state_filter = 2 * BUTTON_AC_PERIOD; + } else if (Settings->button_debounce > (0x7f - 2 * BUTTON_AC_PERIOD) * BUTTON_FAST_PROBE_INTERVAL) { + state_filter = 0x7f; + } else { + state_filter = (Settings->button_debounce - 9) / BUTTON_FAST_PROBE_INTERVAL; + } + } else { + state_filter = Settings->button_debounce / BUTTON_PROBE_INTERVAL; // 5, 10, 15 + } + + uint32_t not_activated; + for (uint32_t i = 0; i < MAX_KEYS; i++) { + if (PinUsed(GPIO_KEY1, i)) { +#if defined(SOC_TOUCH_VERSION_1) || defined(SOC_TOUCH_VERSION_2) + if (bitRead(TouchButton.touch_mask, i)) { + if (ac_detect || bitRead(TouchButton.calibration, i +1)) { continue; } // Touch is slow. Takes 21mS to read + uint32_t value = touchRead(Pin(GPIO_KEY1, i)); +#ifdef SOC_TOUCH_VERSION_2 + not_activated = (value < Settings->touch_threshold); // ESPS3 No touch = 24200, Touch > 40000 +#else + not_activated = ((value == 0) || (value > Settings->touch_threshold)); // ESP32 No touch = 74, Touch < 40 +#endif + } else +#endif // ESP32 SOC_TOUCH_VERSION_1 or SOC_TOUCH_VERSION_2 + not_activated = (digitalRead(Pin(GPIO_KEY1, i)) != bitRead(Button.inverted_mask, i)); + } + else if (bitRead(Button.virtual_pin_used, i)) { + not_activated = bitRead(Button.virtual_pin, i); + } + else { continue; } + + if (not_activated) { + + if (ac_detect) { // Enabled with ButtonDebounce x9 + Button.state[i] |= 0x80; + if (Button.state[i] > 0x80) { + Button.state[i]--; + if (0x80 == Button.state[i]) { + Button.debounced_state[i] = 0; + Button.first_change = false; + } + } + } else { + + if (force_high) { // Enabled with ButtonDebounce x1 + if (1 == Button.debounced_state[i]) { + Button.state[i] = state_filter; // With noisy input keep current state 1 unless constant 0 + } + } + + if (Button.state[i] < state_filter) { + Button.state[i]++; + if (state_filter == Button.state[i]) { + Button.debounced_state[i] = 1; + } + } + } + } else { + + if (ac_detect) { // Enabled with ButtonDebounce x9 + /* + * Moes MS-104B and similar devices using an AC detection circuitry + * on their switch inputs generating an ~4 ms long low pulse every + * AC wave. We start the time measurement on the falling edge. + * + * state: bit7: previous state, bit6..0: counter + */ + if (Button.state[i] & 0x80) { + Button.state[i] &= 0x7f; + if (Button.state[i] < state_filter - 2 * BUTTON_AC_PERIOD) { + Button.state[i] += 2 * BUTTON_AC_PERIOD; + } else { + Button.state[i] = state_filter; + Button.debounced_state[i] = 1; + if (first_change) { + Button.last_state[i] = 1; + Button.first_change = false; + } + } + } else { + if (Button.state[i] > 0x00) { + Button.state[i]--; + if (0x00 == Button.state[i]) { + Button.debounced_state[i] = 0; + Button.first_change = false; + } + } + } + } else { + + if (force_low) { // Enabled with ButtonDebounce x2 + if (0 == Button.debounced_state[i]) { + Button.state[i] = 0; // With noisy input keep current state 0 unless constant 1 + } + } + + if (Button.state[i] > 0) { + Button.state[i]--; + if (0 == Button.state[i]) { + Button.debounced_state[i] = 0; + } + } + } + } + } + Button.probe_mutex = false; +} + +void ButtonInit(void) { + bool ac_detect = (Settings->button_debounce % 10 == 9); + + Button.present = 0; + Button.virtual_pin_used = 0; + +#ifdef ESP8266 + if ((SONOFF_DUAL == TasmotaGlobal.module_type) || (CH4 == TasmotaGlobal.module_type)) { + Button.present++; + } +#endif // ESP8266 + + for (uint32_t i = 0; i < MAX_KEYS; i++) { + Button.last_state[i] = NOT_PRESSED; + bool used = false; + + if (PinUsed(GPIO_KEY1, i)) { + Button.present++; +#ifdef ESP8266 + pinMode(Pin(GPIO_KEY1, i), bitRead(Button.no_pullup_mask, i) ? INPUT : ((16 == Pin(GPIO_KEY1, i)) ? INPUT_PULLDOWN_16 : INPUT_PULLUP)); +#endif // ESP8266 +#ifdef ESP32 + pinMode(Pin(GPIO_KEY1, i), bitRead(Button.pulldown_mask, i) ? INPUT_PULLDOWN : bitRead(Button.no_pullup_mask, i) ? INPUT : INPUT_PULLUP); +#endif // ESP32 + // Set global now so doesn't change the saved power state on first button check + Button.last_state[i] = (digitalRead(Pin(GPIO_KEY1, i)) != bitRead(Button.inverted_mask, i)); + used = true; + } +#ifdef USE_ADC + else if (PinUsed(GPIO_ADC_BUTTON, i) || PinUsed(GPIO_ADC_BUTTON_INV, i)) { + Button.present++; + } +#endif // USE_ADC + else { + XdrvMailbox.index = i; + if (XdrvCall(FUNC_ADD_BUTTON)) { + + AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: Add button %d"), i); + + bitSet(Button.virtual_pin_used, i); + Button.present++; + Button.last_state[i] = XdrvMailbox.payload; + used = true; + } + } + + if (used && ac_detect) { + Button.state[i] = 0x80 + 2 * BUTTON_AC_PERIOD; + Button.last_state[i] = 0; // Will set later in the debouncing code + } + Button.debounced_state[i] = Button.last_state[i]; + } + if (Button.present) { + Button.first_change = true; + TickerButton.attach_ms((ac_detect) ? BUTTON_FAST_PROBE_INTERVAL : BUTTON_PROBE_INTERVAL, ButtonProbe); + } +} + +uint8_t ButtonSerial(uint8_t serial_in_byte) { + if (Button.dual_receive_count) { + Button.dual_receive_count--; + if (Button.dual_receive_count) { + Button.dual_code = (Button.dual_code << 8) | serial_in_byte; + serial_in_byte = 0; + } else { + if (serial_in_byte != 0xA1) { + Button.dual_code = 0; // 0xA1 - End of Sonoff dual button code + } + } + } + if (0xA0 == serial_in_byte) { // 0xA0 - Start of Sonoff dual button code + serial_in_byte = 0; + Button.dual_code = 0; + Button.dual_receive_count = 3; + } + + return serial_in_byte; +} + +/*********************************************************************************************\ + * Button handler with single press only or multi-press and hold on all buttons + * + * ButtonDebounce (50) - Debounce time in mSec + * SetOption1 (0) - If set do not execute commands WifiConfig and Reset + * SetOption11 (0) - If set perform single press action on double press and reverse (on two relay devices only) + * SetOption13 (0) - If set act on single press only + * SetOption32 (40) - Button held for factor times longer + * SetOption40 (0) - Do not ignore button hold + * SetOption73 (0) - Decouple button from relay and send just mqtt topic +\*********************************************************************************************/ + +void ButtonHandler(void) { + if (TasmotaGlobal.uptime < 4) { return; } // Block GPIO for 4 seconds after poweron to workaround Wemos D1 / Obi RTS circuit + + uint8_t hold_time_extent = IMMINENT_RESET_FACTOR; // Extent hold time factor in case of iminnent Reset command + uint16_t loops_per_second = 1000 / Settings->button_debounce; // ButtonDebounce (50) + char scmnd[20]; + + for (uint32_t button_index = 0; button_index < MAX_KEYS; button_index++) { + uint8_t button = NOT_PRESSED; + uint8_t button_present = 0; + +#ifdef ESP8266 + if (!button_index && ((SONOFF_DUAL == TasmotaGlobal.module_type) || (CH4 == TasmotaGlobal.module_type))) { + button_present = 1; + if (Button.dual_code) { + AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: Code %04X"), Button.dual_code); + button = PRESSED; + if (0xF500 == Button.dual_code) { // Button hold + Button.hold_timer[button_index] = (loops_per_second * Settings->param[P_HOLD_TIME] / 10) -1; // SetOption32 (40) + hold_time_extent = 1; + } + Button.dual_code = 0; + } + } else +#endif // ESP8266 + if (PinUsed(GPIO_KEY1, button_index)) { + +#if defined(SOC_TOUCH_VERSION_1) || defined(SOC_TOUCH_VERSION_2) + if (bitRead(TouchButton.touch_mask, button_index) && bitRead(TouchButton.calibration, button_index +1)) { // Touch + uint32_t _value = touchRead(Pin(GPIO_KEY1, button_index)); +#ifdef SOC_TOUCH_VERSION_2 + if (_value > Settings->touch_threshold) { // ESPS3 No touch = 24200, Touch = 100000 +#else + if ((_value > 0) && (_value < Settings->touch_threshold)) { // ESP32 No touch = 74, Touch = 20 (Probably read-error (0)) +#endif + TouchButton.hits[button_index]++; + } else { + TouchButton.hits[button_index] = 0; + } + AddLog(LOG_LEVEL_INFO, PSTR("PLOT: %u, %u, %u,"), button_index +1, _value, TouchButton.hits[button_index]); // Button number (1..4), value, continuous hits under threshold + continue; + } else +#endif // ESP32 SOC_TOUCH_VERSION_1 or SOC_TOUCH_VERSION_2 + + button_present = 1; + button = Button.debounced_state[button_index]; + } +#ifdef USE_ADC + else if (PinUsed(GPIO_ADC_BUTTON, button_index)) { + button_present = 1; + button = AdcGetButton(Pin(GPIO_ADC_BUTTON, button_index)); + } + else if (PinUsed(GPIO_ADC_BUTTON_INV, button_index)) { + button_present = 1; + button = AdcGetButton(Pin(GPIO_ADC_BUTTON_INV, button_index)); + } +#endif // USE_ADC + else if (bitRead(Button.virtual_pin_used, button_index)) { + button_present = 1; + button = Button.debounced_state[button_index]; + } + + if (button_present) { + XdrvMailbox.index = button_index; + XdrvMailbox.payload = button; + if (XdrvCall(FUNC_BUTTON_PRESSED)) { + // Serviced + } +#ifdef ESP8266 + else if (SONOFF_4CHPRO == TasmotaGlobal.module_type) { + if (Button.hold_timer[button_index]) { Button.hold_timer[button_index]--; } + + bool button_pressed = false; + if ((PRESSED == button) && (NOT_PRESSED == Button.last_state[button_index])) { + AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: Button%d level 1-0"), button_index +1); + Button.hold_timer[button_index] = loops_per_second; + button_pressed = true; + } + if ((NOT_PRESSED == button) && (PRESSED == Button.last_state[button_index])) { + AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: Button%d level 0-1"), button_index +1); + if (!Button.hold_timer[button_index]) { button_pressed = true; } // Do not allow within 1 second + } + if (button_pressed) { + if (!Settings->flag3.mqtt_buttons) { // SetOption73 (0) - Decouple button from relay and send just mqtt topic + if (!SendKey(KEY_BUTTON, button_index +1, POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set + ExecuteCommandPower(button_index +1, POWER_TOGGLE, SRC_BUTTON); // Execute Toggle command internally + } + } else { + MqttButtonTopic(button_index +1, 1, 0); // SetOption73 (0) - Decouple button from relay and send just mqtt topic + } + } + } +#endif // ESP8266 + else { + if ((PRESSED == button) && (NOT_PRESSED == Button.last_state[button_index])) { + + if (Settings->flag.button_single) { // SetOption13 (0) - Allow only single button press for immediate action, + if (!Settings->flag3.mqtt_buttons) { // SetOption73 (0) - Decouple button from relay and send just mqtt topic + AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: Button%d immediate"), button_index +1); + if (!SendKey(KEY_BUTTON, button_index +1, POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set + ExecuteCommandPower(button_index +1, POWER_TOGGLE, SRC_BUTTON); // Execute Toggle command internally + } + } else { + MqttButtonTopic(button_index +1, 1, 0); // SetOption73 1 - Decouple button from relay and send just mqtt topic + } + } else { + Button.press_counter[button_index] = (Button.window_timer[button_index]) ? Button.press_counter[button_index] +1 : 1; + AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: Button%d multi-press %d"), button_index +1, Button.press_counter[button_index]); + Button.window_timer[button_index] = loops_per_second / 2; // 0.5 second multi press window + } + TasmotaGlobal.blinks = 201; + } + + if (NOT_PRESSED == button) { + Button.hold_timer[button_index] = 0; + if (Settings->flag3.mqtt_buttons && (PRESSED == Button.last_state[button_index]) && !Button.press_counter[button_index]) { // SetOption73 (0) - Decouple button from relay and send just mqtt topic + MqttButtonTopic(button_index +1, 6, 0); + } + } else { + Button.hold_timer[button_index]++; + if (Settings->flag.button_single) { // SetOption13 (0) - Allow only single button press for immediate action + if (Button.hold_timer[button_index] == loops_per_second * hold_time_extent * Settings->param[P_HOLD_TIME] / 10) { // SetOption32 (40) - Button held for factor times longer + snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_SETOPTION "13 0")); // Disable single press only + ExecuteCommand(scmnd, SRC_BUTTON); + } + } else { + if (Button.hold_timer[button_index] == loops_per_second * Settings->param[P_HOLD_TIME] / 10) { // SetOption32 (40) - Button hold + Button.press_counter[button_index] = 0; + if (Settings->flag3.mqtt_buttons) { // SetOption73 (0) - Decouple button from relay and send just mqtt topic + MqttButtonTopic(button_index +1, 3, 1); + } else { + SendKey(KEY_BUTTON, button_index +1, POWER_HOLD); // Execute Hold command via MQTT if ButtonTopic is set + } + } else { + if (Settings->flag.button_restrict) { // SetOption1 (0) - Control button multipress + if (Settings->param[P_HOLD_IGNORE] > 0) { // SetOption40 (0) - Do not ignore button hold + if (Button.hold_timer[button_index] > loops_per_second * Settings->param[P_HOLD_IGNORE] / 10) { + Button.hold_timer[button_index] = 0; // Reset button hold counter to stay below hold trigger + Button.press_counter[button_index] = 0; // Discard button press to disable functionality + } + } + } else { + if ((Button.hold_timer[button_index] == loops_per_second * hold_time_extent * Settings->param[P_HOLD_TIME] / 10)) { // SetOption32 (40) - Button held for factor times longer + Button.press_counter[button_index] = 0; + snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_RESET " 1")); + ExecuteCommand(scmnd, SRC_BUTTON); + } + } + } + } + } + + if (!Settings->flag.button_single) { // SetOption13 (0) - Allow multi-press + if (Button.window_timer[button_index]) { + Button.window_timer[button_index]--; + } else { + if (!TasmotaGlobal.restart_flag && !Button.hold_timer[button_index] && (Button.press_counter[button_index] > 0) && (Button.press_counter[button_index] < 7)) { + + bool single_press = false; + if (Button.press_counter[button_index] < 3) { // Single or Double press +#ifdef ESP8266 + if ((SONOFF_DUAL_R2 == TasmotaGlobal.module_type) || (SONOFF_DUAL == TasmotaGlobal.module_type) || (CH4 == TasmotaGlobal.module_type)) { + single_press = true; + } else +#endif // ESP8266 + { + single_press = (Settings->flag.button_swap +1 == Button.press_counter[button_index]); // SetOption11 (0) + if ((1 == Button.present) && (2 == TasmotaGlobal.devices_present)) { // Single Button with two devices only + if (Settings->flag.button_swap) { // SetOption11 (0) + Button.press_counter[button_index] = (single_press) ? 1 : 2; + } + } + } + } + + XdrvMailbox.index = button_index; + XdrvMailbox.payload = Button.press_counter[button_index]; + if (XdrvCall(FUNC_BUTTON_MULTI_PRESSED)) { + // Serviced + } else + +#ifdef ROTARY_V1 + if (!RotaryButtonPressed(button_index)) { +#endif + if (!Settings->flag3.mqtt_buttons && single_press && SendKey(KEY_BUTTON, button_index + Button.press_counter[button_index], POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set + // Success + } else { + if (Button.press_counter[button_index] < 6) { // Single to Penta press +// if (WifiState() > WIFI_RESTART) { // Wifimanager active +// TasmotaGlobal.restart_flag = 1; +// } + if (!Settings->flag3.mqtt_buttons) { // SetOption73 - Detach buttons from relays and enable MQTT action state for multipress + if (Button.press_counter[button_index] == 1) { // By default first press always send a TOGGLE (2) + ExecuteCommandPower(button_index + Button.press_counter[button_index], POWER_TOGGLE, SRC_BUTTON); + } else { + SendKey(KEY_BUTTON, button_index +1, Button.press_counter[button_index] +9); // 2,3,4 and 5 press send just the key value (11,12,13 and 14) for rules + if (0 == button_index) { // BUTTON1 can toggle up to 5 relays if present. If a relay is not present will send out the key value (2,11,12,13 and 14) for rules + bool valid_relay = PinUsed(GPIO_REL1, Button.press_counter[button_index]-1); +#ifdef ESP8266 + if ((SONOFF_DUAL == TasmotaGlobal.module_type) || (CH4 == TasmotaGlobal.module_type)) { + valid_relay = (Button.press_counter[button_index] <= TasmotaGlobal.devices_present); + } +#endif // ESP8266 +#ifdef USE_SHELLY_PRO + if (TasmotaGlobal.gpio_optiona.shelly_pro) { + valid_relay = (Button.press_counter[button_index] <= TasmotaGlobal.devices_present); + } +#endif // USE_SHELLY_PRO + if ((Button.press_counter[button_index] > 1) && valid_relay && (Button.press_counter[button_index] <= MAX_RELAY_BUTTON1)) { + ExecuteCommandPower(button_index + Button.press_counter[button_index], POWER_TOGGLE, SRC_BUTTON); // Execute Toggle command internally +// AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: Relay%d found on GPIO%d"), Button.press_counter[button_index], Pin(GPIO_REL1, Button.press_counter[button_index]-1)); + } + } + } + } + + } else { // 6 press start wificonfig 2 + if (!Settings->flag.button_restrict) { // SetOption1 - Control button multipress + snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_WIFICONFIG " 2")); + ExecuteCommand(scmnd, SRC_BUTTON); + } + } + if (Settings->flag3.mqtt_buttons) { // SetOption73 (0) - Decouple button from relay and send just mqtt topic + if (Button.press_counter[button_index] >= 1 && Button.press_counter[button_index] <= 5) { + MqttButtonTopic(button_index +1, Button.press_counter[button_index], 0); + } + } + } +#ifdef ROTARY_V1 + } +#endif + Button.press_counter[button_index] = 0; + } + } + } + + } + } + Button.last_state[button_index] = button; + } +} + +void MqttButtonTopic(uint32_t button_id, uint32_t action, uint32_t hold) { + SendKey(KEY_BUTTON, button_id, (hold) ? 3 : action +9); + + if (!Settings->flag.hass_discovery) { // SetOption19 - Control Home Assistant automatic discovery (See SetOption59) + char scommand[10]; + snprintf_P(scommand, sizeof(scommand), PSTR(D_JSON_BUTTON "%d"), button_id); + char mqttstate[7]; + Response_P(S_JSON_SVALUE_ACTION_SVALUE, scommand, (hold) ? SettingsText(SET_STATE_TXT4) : GetTextIndexed(mqttstate, sizeof(mqttstate), action, kMultiPress)); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_STAT, scommand); + } +} + +void ButtonLoop(void) { + if (Button.present) { + if (TimeReached(Button.debounce)) { + SetNextTimeInterval(Button.debounce, Settings->button_debounce); // ButtonDebounce (50) + ButtonHandler(); + } + } +} + +#endif // BUTTON_V3 diff --git a/tasmota/tasmota_support/support_switch_v3.ino b/tasmota/tasmota_support/support_switch_v3.ino index f00160131..392c0afda 100644 --- a/tasmota/tasmota_support/support_switch_v3.ino +++ b/tasmota/tasmota_support/support_switch_v3.ino @@ -17,7 +17,7 @@ along with this program. If not, see . */ -#define SWITCH_V3 +//#define SWITCH_V3 #ifdef SWITCH_V3 /*********************************************************************************************\ * Switch support with input filter diff --git a/tasmota/tasmota_support/support_switch_v4.ino b/tasmota/tasmota_support/support_switch_v4.ino new file mode 100644 index 000000000..9b4a81f72 --- /dev/null +++ b/tasmota/tasmota_support/support_switch_v4.ino @@ -0,0 +1,490 @@ +/* + support_switch.ino - switch support for Tasmota + + Copyright (C) 2021 Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#define SWITCH_V4 +#ifdef SWITCH_V4 +/*********************************************************************************************\ + * Switch support with input filter + * + * Inspired by (https://github.com/OLIMEX/olimex-iot-firmware-esp8266/blob/master/olimex/user/user_switch2.c) +\*********************************************************************************************/ + +const uint8_t SWITCH_PROBE_INTERVAL = 10; // Time in milliseconds between switch input probe +const uint8_t SWITCH_FAST_PROBE_INTERVAL = 2; // Time in milliseconds between switch input probe for AC detection +const uint8_t SWITCH_AC_PERIOD = (20 + SWITCH_FAST_PROBE_INTERVAL - 1) / SWITCH_FAST_PROBE_INTERVAL; // Duration of an AC wave in probe intervals + +// Switch Mode definietions +#define SM_TIMER_MASK 0x3F +#define SM_NO_TIMER_MASK 0xFF +#define SM_FIRST_PRESS 0x40 +#define SM_SECOND_PRESS 0x80 +#define POWER_NONE 99 + +const char kSwitchPressStates[] PROGMEM = + "||||POWER_INCREMENT|POWER_INV|POWER_CLEAR|POWER_RELEASE|POWER_100||POWER_DELAYED"; + +#include + +Ticker TickerSwitch; + +struct SWITCH { + uint32_t debounce = 0; // Switch debounce timer + uint32_t no_pullup_mask = 0; // Switch pull-up bitmask flags + uint32_t pulldown_mask = 0; // Switch pull-down bitmask flags + uint32_t virtual_pin_used = 0; // Switch used bitmask + uint32_t virtual_pin = 0; // Switch state bitmask + uint8_t state[MAX_SWITCHES] = { 0 }; + uint8_t last_state[MAX_SWITCHES]; // Last wall switch states + uint8_t hold_timer[MAX_SWITCHES] = { 0 }; // Timer for wallswitch push button hold + uint8_t debounced_state[MAX_SWITCHES]; // Switch debounced states + uint8_t first_change = 0; + uint8_t present = 0; + bool probe_mutex; +} Switch; + +/********************************************************************************************/ + +void SwitchPullupFlag(uint32 switch_bit) { + bitSet(Switch.no_pullup_mask, switch_bit); +} + +void SwitchPulldownFlag(uint32 switch_bit) { + bitSet(Switch.pulldown_mask, switch_bit); +} + +void SwitchSetVirtualPinState(uint32_t index, uint32_t state) { + if (!Switch.probe_mutex) { + bitWrite(Switch.virtual_pin, index, state); + } +} + +void SwitchSetVirtual(uint32_t index, uint32_t state) { + bitSet(Switch.virtual_pin_used, index); + Switch.debounced_state[index] = state; +} + +uint8_t SwitchGetVirtual(uint32_t index) { + return Switch.debounced_state[index]; +} + +uint8_t SwitchLastState(uint32_t index) { + return Switch.last_state[index]; +} + +bool SwitchState(uint32_t index) { + uint32_t switchmode = Settings->switchmode[index]; + return ((FOLLOW_INV == switchmode) || + (PUSHBUTTON_INV == switchmode) || + (PUSHBUTTONHOLD_INV == switchmode) || + (FOLLOWMULTI_INV == switchmode) || + (PUSHHOLDMULTI_INV == switchmode) || + (PUSHON_INV == switchmode) || + (PUSH_IGNORE_INV == switchmode) + ) ^ Switch.last_state[index]; +} + +/*********************************************************************************************/ + +void SwitchProbe(void) { + if (Switch.probe_mutex || (TasmotaGlobal.uptime < 4)) { return; } // Block GPIO for 4 seconds after poweron to workaround Wemos D1 / Obi RTS circuit + Switch.probe_mutex = true; + + uint32_t state_filter; + uint32_t first_change = Switch.first_change; + uint32_t debounce_flags = Settings->switch_debounce % 10; + bool force_high = (debounce_flags &1); // 51, 101, 151 etc + bool force_low = (debounce_flags &2); // 52, 102, 152 etc + bool ac_detect = (debounce_flags == 9); + + if (ac_detect) { + if (Settings->switch_debounce < 2 * SWITCH_AC_PERIOD * SWITCH_FAST_PROBE_INTERVAL + 9) { + state_filter = 2 * SWITCH_AC_PERIOD; + } else if (Settings->switch_debounce > (0x7f - 2 * SWITCH_AC_PERIOD) * SWITCH_FAST_PROBE_INTERVAL) { + state_filter = 0x7f; + } else { + state_filter = (Settings->switch_debounce - 9) / SWITCH_FAST_PROBE_INTERVAL; + } + } else { + state_filter = Settings->switch_debounce / SWITCH_PROBE_INTERVAL; // 5, 10, 15 + } + + uint32_t not_activated; + for (uint32_t i = 0; i < MAX_SWITCHES; i++) { + if (PinUsed(GPIO_SWT1, i)) { + not_activated = digitalRead(Pin(GPIO_SWT1, i)); + } + else if (bitRead(Switch.virtual_pin_used, i)) { + not_activated = bitRead(Switch.virtual_pin, i); + } + else { continue; } + + // Olimex user_switch2.c code to fix 50Hz induced pulses + if (not_activated) { + + if (ac_detect) { // Enabled with SwitchDebounce x9 + Switch.state[i] |= 0x80; + if (Switch.state[i] > 0x80) { + Switch.state[i]--; + if (0x80 == Switch.state[i]) { + Switch.debounced_state[i] = 0; + Switch.first_change = false; + } + } + } else { + + if (force_high) { // Enabled with SwitchDebounce x1 + if (1 == Switch.debounced_state[i]) { + Switch.state[i] = state_filter; // With noisy input keep current state 1 unless constant 0 + } + } + + if (Switch.state[i] < state_filter) { + Switch.state[i]++; + if (state_filter == Switch.state[i]) { + Switch.debounced_state[i] = 1; + } + } + } + } else { + + if (ac_detect) { // Enabled with SwitchDebounce x9 + /* + * Moes MS-104B and similar devices using an AC detection circuitry + * on their switch inputs generating an ~4 ms long low pulse every + * AC wave. We start the time measurement on the falling edge. + * + * state: bit7: previous state, bit6..0: counter + */ + if (Switch.state[i] & 0x80) { + Switch.state[i] &= 0x7f; + if (Switch.state[i] < state_filter - 2 * SWITCH_AC_PERIOD) { + Switch.state[i] += 2 * SWITCH_AC_PERIOD; + } else { + Switch.state[i] = state_filter; + Switch.debounced_state[i] = 1; + if (first_change) { + Switch.last_state[i] = 1; + Switch.first_change = false; + } + } + } else { + if (Switch.state[i] > 0x00) { + Switch.state[i]--; + if (0x00 == Switch.state[i]) { + Switch.debounced_state[i] = 0; + Switch.first_change = false; + } + } + } + } else { + + if (force_low) { // Enabled with SwitchDebounce x2 + if (0 == Switch.debounced_state[i]) { + Switch.state[i] = 0; // With noisy input keep current state 0 unless constant 1 + } + } + + if (Switch.state[i] > 0) { + Switch.state[i]--; + if (0 == Switch.state[i]) { + Switch.debounced_state[i] = 0; + } + } + } + } + } + + Switch.probe_mutex = false; +} + +void SwitchInit(void) { + bool ac_detect = (Settings->switch_debounce % 10 == 9); + + Switch.present = 0; + Switch.virtual_pin_used = 0; + for (uint32_t i = 0; i < MAX_SWITCHES; i++) { + Switch.last_state[i] = NOT_PRESSED; // Init global to virtual switch state; + bool used = false; + + if (PinUsed(GPIO_SWT1, i)) { + Switch.present++; +#ifdef ESP8266 + pinMode(Pin(GPIO_SWT1, i), bitRead(Switch.no_pullup_mask, i) ? INPUT : ((16 == Pin(GPIO_SWT1, i)) ? INPUT_PULLDOWN_16 : INPUT_PULLUP)); +#endif // ESP8266 +#ifdef ESP32 + pinMode(Pin(GPIO_SWT1, i), bitRead(Switch.pulldown_mask, i) ? INPUT_PULLDOWN : bitRead(Switch.no_pullup_mask, i) ? INPUT : INPUT_PULLUP); +#endif // ESP32 + Switch.last_state[i] = digitalRead(Pin(GPIO_SWT1, i)); // Set global now so doesn't change the saved power state on first switch check + used = true; + } + else { + XdrvMailbox.index = i; + if (XdrvCall(FUNC_ADD_SWITCH)) { + + AddLog(LOG_LEVEL_DEBUG, PSTR("SWT: Add switch %d"), i); + + bitSet(Switch.virtual_pin_used, i); + Switch.present++; + Switch.last_state[i] = XdrvMailbox.payload; + used = true; + } + } + + if (used && ac_detect) { + Switch.state[i] = 0x80 + 2 * SWITCH_AC_PERIOD; + Switch.last_state[i] = 0; // Will set later in the debouncing code + } + Switch.debounced_state[i] = Switch.last_state[i]; + } + if (Switch.present) { + Switch.first_change = true; + TickerSwitch.attach_ms((ac_detect) ? SWITCH_FAST_PROBE_INTERVAL : SWITCH_PROBE_INTERVAL, SwitchProbe); + } +} + +/*********************************************************************************************\ + * Switch handler +\*********************************************************************************************/ + +void SwitchHandler(uint32_t mode) { + if (TasmotaGlobal.uptime < 4) { return; } // Block GPIO for 4 seconds after poweron to workaround Wemos D1 / Obi RTS circuit + + uint32_t loops_per_second = 1000 / Settings->switch_debounce; + + for (uint32_t i = 0; i < MAX_SWITCHES; i++) { + if (PinUsed(GPIO_SWT1, i) || bitRead(Switch.virtual_pin_used, i)) { + uint32_t button = Switch.debounced_state[i]; + uint32_t switchflag = POWER_TOGGLE +1; + uint32_t mqtt_action = POWER_NONE; + uint32_t switchmode = Settings->switchmode[i]; + + if (Switch.hold_timer[i] & (((switchmode == PUSHHOLDMULTI) | (switchmode == PUSHHOLDMULTI_INV)) ? SM_TIMER_MASK: SM_NO_TIMER_MASK)) { + Switch.hold_timer[i]--; + if ((Switch.hold_timer[i] & SM_TIMER_MASK) == loops_per_second * Settings->param[P_HOLD_TIME] / 25) { + if ((switchmode == PUSHHOLDMULTI) | (switchmode == PUSHHOLDMULTI_INV)){ + if (((switchmode == PUSHHOLDMULTI) & (NOT_PRESSED == Switch.last_state[i])) | ((switchmode == PUSHHOLDMULTI_INV) & (PRESSED == Switch.last_state[i]))) { + SendKey(KEY_SWITCH, i +1, POWER_INCREMENT); // Execute command via MQTT + } + else if ((Switch.hold_timer[i] & ~SM_TIMER_MASK) == SM_FIRST_PRESS) { + SendKey(KEY_SWITCH, i +1, POWER_DELAYED); // Execute command via MQTT + mqtt_action = POWER_DELAYED; + Switch.hold_timer[i] = 0; + } + } + } + if (0 == (Switch.hold_timer[i] & (((switchmode == PUSHHOLDMULTI) | (switchmode == PUSHHOLDMULTI_INV)) ? SM_TIMER_MASK: SM_NO_TIMER_MASK))) { + switch (switchmode) { + case TOGGLEMULTI: + switchflag = POWER_TOGGLE; // Toggle after hold + break; + case FOLLOWMULTI: + switchflag = button &1; // Follow wall switch state after hold + break; + case FOLLOWMULTI_INV: + switchflag = ~button &1; // Follow inverted wall switch state after hold + break; + case PUSHHOLDMULTI: + if (NOT_PRESSED == button) { + Switch.hold_timer[i] = loops_per_second * Settings->param[P_HOLD_TIME] / 25; + SendKey(KEY_SWITCH, i +1, POWER_INCREMENT); // Execute command via MQTT + mqtt_action = POWER_INCREMENT; + } else { + Switch.hold_timer[i]= 0; + SendKey(KEY_SWITCH, i +1, POWER_CLEAR); // Execute command via MQTT + mqtt_action = POWER_CLEAR; + } + break; + case PUSHHOLDMULTI_INV: + if (PRESSED == button) { + Switch.hold_timer[i] = loops_per_second * Settings->param[P_HOLD_TIME] / 25; + SendKey(KEY_SWITCH, i +1, POWER_INCREMENT); // Execute command via MQTT + mqtt_action = POWER_INCREMENT; + } else { + Switch.hold_timer[i]= 0; + SendKey(KEY_SWITCH, i +1, POWER_CLEAR); // Execute command via MQTT + mqtt_action = POWER_CLEAR; + } + break; + default: + SendKey(KEY_SWITCH, i +1, POWER_HOLD); // Execute command via MQTT + mqtt_action = POWER_HOLD; + break; + } + } + } + + if (button != Switch.last_state[i]) { // This implies if ((PRESSED == button) then (NOT_PRESSED == Switch.last_state[i])) + switch (switchmode) { + case TOGGLE: + case PUSHBUTTON_TOGGLE: + switchflag = POWER_TOGGLE; // Toggle + break; + case FOLLOW: + switchflag = button &1; // Follow wall switch state + break; + case FOLLOW_INV: + switchflag = ~button &1; // Follow inverted wall switch state + break; + case PUSHBUTTON: + if (PRESSED == button) { + switchflag = POWER_TOGGLE; // Toggle with pushbutton to Gnd + } + break; + case PUSHBUTTON_INV: + if (NOT_PRESSED == button) { + switchflag = POWER_TOGGLE; // Toggle with releasing pushbutton from Gnd + } + break; + case PUSHBUTTONHOLD: + if (PRESSED == button) { + Switch.hold_timer[i] = loops_per_second * Settings->param[P_HOLD_TIME] / 10; // Start timer on button press + } + if ((NOT_PRESSED == button) && (Switch.hold_timer[i])) { + Switch.hold_timer[i] = 0; // Button released and hold timer not expired : stop timer... + switchflag = POWER_TOGGLE; // ...and Toggle + } + break; + case PUSHBUTTONHOLD_INV: + if (NOT_PRESSED == button) { + Switch.hold_timer[i] = loops_per_second * Settings->param[P_HOLD_TIME] / 10; // Start timer on button press... + } + if ((PRESSED == button) && (Switch.hold_timer[i])) { + Switch.hold_timer[i] = 0; // Button released and hold timer not expired : stop timer. + switchflag = POWER_TOGGLE; // ...and Toggle + } + break; + case TOGGLEMULTI: + case FOLLOWMULTI: + case FOLLOWMULTI_INV: + if (Switch.hold_timer[i]) { + Switch.hold_timer[i] = 0; + SendKey(KEY_SWITCH, i +1, POWER_HOLD); // Execute command via MQTT + mqtt_action = POWER_HOLD; + } else { + Switch.hold_timer[i] = loops_per_second / 2; // 0.5 second multi press window + } + break; + case PUSHHOLDMULTI: + if (NOT_PRESSED == button) { + if ((Switch.hold_timer[i] & SM_TIMER_MASK) != 0) { + Switch.hold_timer[i] = ((Switch.hold_timer[i] & ~SM_TIMER_MASK) == SM_FIRST_PRESS) ? SM_SECOND_PRESS : 0; + SendKey(KEY_SWITCH, i +1, POWER_INV); // Execute command via MQTT + mqtt_action = POWER_INV; + } + } else { + if ((Switch.hold_timer[i] & SM_TIMER_MASK) > loops_per_second * Settings->param[P_HOLD_TIME] / 25) { + if ((Switch.hold_timer[i] & ~SM_TIMER_MASK) != SM_SECOND_PRESS) { + Switch.hold_timer[i]= SM_FIRST_PRESS; + switchflag = POWER_TOGGLE; // Toggle with pushbutton + } + else{ + SendKey(KEY_SWITCH, i +1, POWER_100); // Execute command via MQTT + mqtt_action = POWER_100; + Switch.hold_timer[i]= 0; + } + } else { + Switch.hold_timer[i]= 0; + SendKey(KEY_SWITCH, i +1, POWER_RELEASE); // Execute command via MQTT + mqtt_action = POWER_RELEASE; + } + } + Switch.hold_timer[i] = (Switch.hold_timer[i] & ~SM_TIMER_MASK) | loops_per_second * Settings->param[P_HOLD_TIME] / 10; + break; + case PUSHHOLDMULTI_INV: + if (PRESSED == button) { + if ((Switch.hold_timer[i] & SM_TIMER_MASK) != 0) { + Switch.hold_timer[i] = ((Switch.hold_timer[i] & ~SM_TIMER_MASK) == SM_FIRST_PRESS) ? SM_SECOND_PRESS : 0; + SendKey(KEY_SWITCH, i +1, POWER_INV); // Execute command via MQTT + mqtt_action = POWER_INV; + } + } else { + if ((Switch.hold_timer[i] & SM_TIMER_MASK)> loops_per_second * Settings->param[P_HOLD_TIME] / 25) { + if ((Switch.hold_timer[i] & ~SM_TIMER_MASK) != SM_SECOND_PRESS) { + Switch.hold_timer[i]= SM_FIRST_PRESS; + switchflag = POWER_TOGGLE; // Toggle with pushbutton + } + else{ + SendKey(KEY_SWITCH, i +1, POWER_100); // Execute command via MQTT + mqtt_action = POWER_100; + Switch.hold_timer[i]= 0; + } + } else { + Switch.hold_timer[i]= 0; + SendKey(KEY_SWITCH, i +1, POWER_RELEASE); // Execute command via MQTT + mqtt_action = POWER_RELEASE; + } + } + Switch.hold_timer[i] = (Switch.hold_timer[i] & ~SM_TIMER_MASK) | loops_per_second * Settings->param[P_HOLD_TIME] / 10; + break; + case PUSHON: + if (PRESSED == button) { + switchflag = POWER_ON; // Power ON with pushbutton to Gnd + } + break; + case PUSHON_INV: + if (NOT_PRESSED == button) { + switchflag = POWER_ON; // Power ON with releasing pushbutton from Gnd + } + break; + case PUSH_IGNORE: + case PUSH_IGNORE_INV: + Switch.last_state[i] = button; // Update switch state before publishing + MqttPublishSensor(); + break; + } + Switch.last_state[i] = button; + } + if (switchflag <= POWER_TOGGLE) { + if (!Settings->flag5.mqtt_switches) { // SetOption114 (0) - Detach Switches from relays and enable MQTT action state for all the SwitchModes + if (!SendKey(KEY_SWITCH, i +1, switchflag)) { // Execute command via MQTT + ExecuteCommandPower(i +1, switchflag, SRC_SWITCH); // Execute command internally (if i < TasmotaGlobal.devices_present) + } + } else { mqtt_action = switchflag; } + } + if ((mqtt_action != POWER_NONE) && Settings->flag5.mqtt_switches) { // SetOption114 (0) - Detach Switches from relays and enable MQTT action state for all the SwitchModes + if (!Settings->flag.hass_discovery) { // SetOption19 - Control Home Assistant automatic discovery (See SetOption59) + char mqtt_state_str[16]; + char *mqtt_state = mqtt_state_str; + if (mqtt_action <= 3) { + if (mqtt_action != 3) { SendKey(KEY_SWITCH, i +1, mqtt_action); } + mqtt_state = SettingsText(SET_STATE_TXT1 + mqtt_action); + } else { + GetTextIndexed(mqtt_state_str, sizeof(mqtt_state_str), mqtt_action, kSwitchPressStates); + } + Response_P(S_JSON_SVALUE_ACTION_SVALUE, GetSwitchText(i).c_str(), mqtt_state); + char scommand[10]; + snprintf_P(scommand, sizeof(scommand), PSTR(D_JSON_SWITCH "%d"), i +1); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_STAT, scommand); + } + mqtt_action = POWER_NONE; + } + } + } +} + +void SwitchLoop(void) { + if (Switch.present) { + if (TimeReached(Switch.debounce)) { + SetNextTimeInterval(Switch.debounce, Settings->switch_debounce); + SwitchHandler(0); + } + } +} + +#endif // SWITCH_V3 diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota.ino index b31ed5b99..4ac0451d3 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota.ino @@ -580,7 +580,7 @@ extern "C" { be_newobject(vm, "list"); for (uint32_t i = 0; i < MAX_SWITCHES; i++) { if (PinUsed(GPIO_SWT1, i)) { - be_pushbool(vm, Switch.virtual_state[i] == PRESSED); + be_pushbool(vm, SwitchGetVirtual(i) == PRESSED); be_data_push(vm, -2); be_pop(vm, 1); } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro.ino b/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro.ino index 9642163ce..94573422e 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro.ino @@ -19,7 +19,7 @@ #ifdef ESP32 #ifdef USE_SPI -#ifdef USE_SHELLY_PRO +#ifdef USE_SHELLY_PRO_V1 /*********************************************************************************************\ * Shelly Pro support * diff --git a/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v2.ino b/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v2.ino new file mode 100644 index 000000000..2b43768f9 --- /dev/null +++ b/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v2.ino @@ -0,0 +1,501 @@ +/* + xdrv_88_shelly_pro.ino - Shelly pro family support for Tasmota + + Copyright (C) 2022 Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifdef ESP32 +#ifdef USE_SPI +#ifdef USE_SHELLY_PRO +/*********************************************************************************************\ + * Shelly Pro support + * + * {"NAME":"Shelly Pro 1","GPIO":[0,1,0,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,0,0,0,32,4736,0,160,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,10000,10000,3350"} + * {"NAME":"Shelly Pro 1PM","GPIO":[9568,1,9472,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,3459,0,0,32,4736,0,160,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,10000,10000,3350"} + * {"NAME":"Shelly Pro 2","GPIO":[0,1,0,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,0,0,0,32,4736,4737,160,161],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,10000,10000,3350;AdcParam2 2,10000,10000,3350"} + * {"NAME":"Shelly Pro 2PM","GPIO":[9568,1,9472,1,768,0,0,0,672,704,736,9569,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,3460,0,0,32,4736,4737,160,161],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,10000,10000,3350;AdcParam2 2,10000,10000,3350"} + * + * {"NAME":"Shelly Pro 4PM","GPIO":[769,1,1,1,9568,0,0,0,1,705,9569,737,768,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,6214,736,704,3461,0,4736,1,0,672],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350"} + * {"NAME":"Shelly Pro 4PM No display","GPIO":[1,1,1,1,9568,0,0,0,1,1,9569,1,768,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,6214,736,704,3461,0,4736,1,0,672],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350"} + * + * Shelly Pro 1/2 uses SPI to control one 74HC595 for relays/leds and one ADE7953 (1PM) or two ADE7953 (2PM) for energy monitoring + * Shelly Pro 4 uses an SPI to control one MCP23S17 for buttons/switches/relays/leds and two ADE7953 for energy monitoring and a second SPI for the display +\*********************************************************************************************/ + +#define XDRV_88 88 + +#define SHELLY_PRO_PIN_LAN8720_RESET 5 +#define SHELLY_PRO_4_PIN_SPI_CS 16 +#define SHELLY_PRO_4_PIN_MCP23S17_INT 35 +#define SHELLY_PRO_4_MCP23S17_ADDRESS 0x40 + +struct SPro { + uint32_t last_update; + uint32_t probe_pin; + int switch_offset; + int button_offset; + uint8_t last_button[3]; + uint8_t pin_register_cs; + uint8_t pin_mcp23s17_int; + uint8_t ledlink; + uint8_t power; + uint8_t detected; +} SPro; + +/*********************************************************************************************\ + * Shelly Pro MCP23S17 support +\*********************************************************************************************/ + +enum SP4MCP23X17GPIORegisters { + // A side + SP4_MCP23S17_IODIRA = 0x00, + SP4_MCP23S17_IPOLA = 0x02, + SP4_MCP23S17_GPINTENA = 0x04, + SP4_MCP23S17_DEFVALA = 0x06, + SP4_MCP23S17_INTCONA = 0x08, + SP4_MCP23S17_IOCONA = 0x0A, + SP4_MCP23S17_GPPUA = 0x0C, + SP4_MCP23S17_INTFA = 0x0E, + SP4_MCP23S17_INTCAPA = 0x10, + SP4_MCP23S17_GPIOA = 0x12, + SP4_MCP23S17_OLATA = 0x14, + // B side + SP4_MCP23S17_IODIRB = 0x01, + SP4_MCP23S17_IPOLB = 0x03, + SP4_MCP23S17_GPINTENB = 0x05, + SP4_MCP23S17_DEFVALB = 0x07, + SP4_MCP23S17_INTCONB = 0x09, + SP4_MCP23S17_IOCONB = 0x0B, + SP4_MCP23S17_GPPUB = 0x0D, + SP4_MCP23S17_INTFB = 0x0F, + SP4_MCP23S17_INTCAPB = 0x11, + SP4_MCP23S17_GPIOB = 0x13, + SP4_MCP23S17_OLATB = 0x15, +}; + +uint8_t sp4_mcp23s17_olata = 0; +uint8_t sp4_mcp23s17_olatb = 0; + +void SP4Mcp23S17Enable(void) { + SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0)); + digitalWrite(SPro.pin_register_cs, 0); +} + +void SP4Mcp23S17Disable(void) { + SPI.endTransaction(); + digitalWrite(SPro.pin_register_cs, 1); +} + +uint32_t SP4Mcp23S17ReadGpio(void) { + // Read 16-bit gpio registers: (gpiob << 8) | gpioa + SP4Mcp23S17Enable(); + SPI.transfer(SHELLY_PRO_4_MCP23S17_ADDRESS | 1); + SPI.transfer(SP4_MCP23S17_GPIOA); + uint32_t gpio = SPI.transfer(0xFF); // SP4_MCP23S17_GPIOA + gpio |= (SPI.transfer(0xFF) << 8); // SP4_MCP23S17_GPIOB + SP4Mcp23S17Disable(); + return gpio; +} + +bool SP4Mcp23S17Read(uint8_t reg, uint8_t *value) { + SP4Mcp23S17Enable(); + SPI.transfer(SHELLY_PRO_4_MCP23S17_ADDRESS | 1); + SPI.transfer(reg); + *value = SPI.transfer(0xFF); + SP4Mcp23S17Disable(); + return true; +} + +bool SP4Mcp23S17Write(uint8_t reg, uint8_t value) { + SP4Mcp23S17Enable(); + SPI.transfer(SHELLY_PRO_4_MCP23S17_ADDRESS); + SPI.transfer(reg); + SPI.transfer(value); + SP4Mcp23S17Disable(); + return true; +} + +void SP4Mcp23S17Update(uint8_t pin, bool pin_value, uint8_t reg_addr) { + uint8_t bit = pin % 8; + uint8_t reg_value = 0; + if (reg_addr == SP4_MCP23S17_OLATA) { + reg_value = sp4_mcp23s17_olata; + } else if (reg_addr == SP4_MCP23S17_OLATB) { + reg_value = sp4_mcp23s17_olatb; + } else { + SP4Mcp23S17Read(reg_addr, ®_value); + } + if (pin_value) { + reg_value |= 1 << bit; + } else { + reg_value &= ~(1 << bit); + } + SP4Mcp23S17Write(reg_addr, reg_value); + if (reg_addr == SP4_MCP23S17_OLATA) { + sp4_mcp23s17_olata = reg_value; + } else if (reg_addr == SP4_MCP23S17_OLATB) { + sp4_mcp23s17_olatb = reg_value; + } +} + +void SP4Mcp23S17Setup(void) { + SP4Mcp23S17Write(SP4_MCP23S17_IOCONA, 0b01011000); // Enable INT mirror, Slew rate disabled, HAEN pins for addressing + SP4Mcp23S17Write(SP4_MCP23S17_GPINTENA, 0x6F); // Enable interrupt on change + SP4Mcp23S17Write(SP4_MCP23S17_GPINTENB, 0x80); // Enable interrupt on change + + // Read current output register state + SP4Mcp23S17Read(SP4_MCP23S17_OLATA, &sp4_mcp23s17_olata); + SP4Mcp23S17Read(SP4_MCP23S17_OLATB, &sp4_mcp23s17_olatb); +} + +void SP4Mcp23S17PinMode(uint8_t pin, uint8_t flags) { + uint8_t iodir = pin < 8 ? SP4_MCP23S17_IODIRA : SP4_MCP23S17_IODIRB; + uint8_t gppu = pin < 8 ? SP4_MCP23S17_GPPUA : SP4_MCP23S17_GPPUB; + if (flags == INPUT) { + SP4Mcp23S17Update(pin, true, iodir); + SP4Mcp23S17Update(pin, false, gppu); + } else if (flags == (INPUT | PULLUP)) { + SP4Mcp23S17Update(pin, true, iodir); + SP4Mcp23S17Update(pin, true, gppu); + } else if (flags == OUTPUT) { + SP4Mcp23S17Update(pin, false, iodir); + } +} + +bool SP4Mcp23S17DigitalRead(uint8_t pin) { + uint8_t bit = pin % 8; + uint8_t reg_addr = pin < 8 ? SP4_MCP23S17_GPIOA : SP4_MCP23S17_GPIOB; + uint8_t value = 0; + SP4Mcp23S17Read(reg_addr, &value); + return value & (1 << bit); +} + +void SP4Mcp23S17DigitalWrite(uint8_t pin, bool value) { + uint8_t reg_addr = pin < 8 ? SP4_MCP23S17_OLATA : SP4_MCP23S17_OLATB; + SP4Mcp23S17Update(pin, value, reg_addr); +} + +/*********************************************************************************************\ + * Shelly Pro 4 +\*********************************************************************************************/ + +const uint8_t sp4_relay_pin[] = { 8, 13, 14, 12 }; +const uint8_t sp4_switch_pin[] = { 6, 1, 0, 15 }; +const uint8_t sp4_button_pin[] = { 5, 2, 3 }; + +void ShellyPro4Init(void) { + /* + Shelly Pro 4PM MCP23S17 registers + bit 0 = input - Switch3 + bit 1 = input - Switch2 + bit 2 = input, pullup, inverted - Button Down + bit 3 = input, pullup, inverted - Button OK + bit 4 = output - Reset, display, ADE7953 + bit 5 = input, pullup, inverted - Button Up + bit 6 = input - Switch1 + bit 7 + bit 8 = output - Relay O1 + bit 9 + bit 10 + bit 11 + bit 12 = output - Relay O4 + bit 13 = output - Relay O2 + bit 14 = output - Relay O3 + bit 15 = input - Switch4 + */ + SP4Mcp23S17Setup(); + + for (uint32_t i = 0; i < 4; i++) { + SP4Mcp23S17PinMode(sp4_switch_pin[i], INPUT); // Switch1..4 + SP4Mcp23S17PinMode(sp4_relay_pin[i], OUTPUT); // Relay O1..O4 + } + SPro.switch_offset = -1; + + for (uint32_t i = 0; i < 3; i++) { + SP4Mcp23S17PinMode(sp4_button_pin[i], PULLUP); // Button Up, Down, OK + } + SPro.button_offset = -1; + + SP4Mcp23S17PinMode(4, OUTPUT); // Reset display, ADE7943 + SP4Mcp23S17DigitalWrite(4, 1); + +} + +void ShellyPro4Reset(void) { + SP4Mcp23S17DigitalWrite(4, 0); // Reset pin display, ADE7953 + delay(1); // To initiate a hardware reset, this pin must be brought low for a minimum of 10 μs. + SP4Mcp23S17DigitalWrite(4, 1); +} + +bool ShellyProAddButton(void) { + if (SPro.detected != 4) { return false; } + if (SPro.button_offset < 0) { SPro.button_offset = XdrvMailbox.index; } + uint32_t index = XdrvMailbox.index - SPro.button_offset; + if (index > 2) { return false; } + XdrvMailbox.payload = SP4Mcp23S17DigitalRead(sp4_button_pin[index]); + return true; +} + +bool ShellyProAddSwitch(void) { + if (SPro.detected != 4) { return false; } + if (SPro.switch_offset < 0) { SPro.switch_offset = XdrvMailbox.index; } + uint32_t index = XdrvMailbox.index - SPro.switch_offset; + if (index > 3) { return false; } + XdrvMailbox.payload = SP4Mcp23S17DigitalRead(sp4_switch_pin[index]); + return true; +} + +void ShellyProUpdateSwitches(void) { + if (SPro.detected != 4) { return; } + if (digitalRead(SPro.pin_mcp23s17_int)) { return; } + + uint32_t gpio = SP4Mcp23S17ReadGpio(); + + AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Input detected 0x%04X"), gpio); + + // Propagate state + uint32_t state; + for (uint32_t i = 0; i < 4; i++) { + state = (gpio >> sp4_switch_pin[i]) &1; + SwitchSetVirtualPinState(SPro.switch_offset +i, state); + } + for (uint32_t i = 0; i < 3; i++) { + state = (gpio >> sp4_button_pin[i]) &1; + ButtonSetVirtualPinState(SPro.button_offset +i, state); + } +} + +bool ShellyProButton(void) { + if (SPro.detected != 4) { return false; } + + uint32_t button_index = XdrvMailbox.index - SPro.button_offset; + if (button_index > 2) { return false; } // We only support Up, Down, Ok + + bool result = false; + uint32_t button = XdrvMailbox.payload; + if ((PRESSED == button) && (NOT_PRESSED == SPro.last_button[button_index])) { // Button pressed + + AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Button %d pressed"), button_index +1); + + // Do something with the Up,Down,Ok button + switch (button_index) { + case 0: // Up + break; + case 1: // Down + break; + case 2: // Ok + break; + } + result = true; // Disable further button processing + } + SPro.last_button[button_index] = button; + return result; +} + +/*********************************************************************************************\ + * Shelly Pro 1/2 +\*********************************************************************************************/ + +void ShellyProUpdate(void) { + /* + Shelly Pro 1/2/PM 74HC595 register + bit 0 = relay/led 1 + bit 1 = relay/led 2 + bit 2 = wifi led blue + bit 3 = wifi led green + bit 4 = wifi led red + bit 5 - 7 = nc + OE is connected to Gnd with 470 ohm resistor R62 AND a capacitor C81 to 3V3 + - this inhibits output of signals (also relay state) during power on for a few seconds + */ + uint8_t val = SPro.power | SPro.ledlink; + SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0)); + SPI.transfer(val); // Write 74HC595 shift register + SPI.endTransaction(); +// delayMicroseconds(2); // Wait for SPI clock to stop + digitalWrite(SPro.pin_register_cs, 1); // Latch data + delayMicroseconds(1); // Shelly 10mS + digitalWrite(SPro.pin_register_cs, 0); +} + +/*********************************************************************************************\ + * Shelly Pro +\*********************************************************************************************/ + +void ShellyProPreInit(void) { + if ((SPI_MOSI_MISO == TasmotaGlobal.spi_enabled) && + PinUsed(GPIO_SPI_CS) && // 74HC595 rclk / MCP23S17 + TasmotaGlobal.gpio_optiona.shelly_pro) { // Option_A7 + + if (PinUsed(GPIO_SWT1) || PinUsed(GPIO_KEY1)) { + SPro.detected = 1; // Shelly Pro 1 + if (PinUsed(GPIO_SWT1, 1) || PinUsed(GPIO_KEY1, 1)) { + SPro.detected = 2; // Shelly Pro 2 + } + SPro.ledlink = 0x18; // Blue led on - set by first call ShellyProPower() - Shelly 1/2 + } + if (SHELLY_PRO_4_PIN_SPI_CS == Pin(GPIO_SPI_CS)) { + SPro.detected = 4; // Shelly Pro 4PM (No SWT or KEY) + } + + if (SPro.detected) { + TasmotaGlobal.devices_present += SPro.detected; + + SPro.pin_register_cs = Pin(GPIO_SPI_CS); + pinMode(SPro.pin_register_cs, OUTPUT); + // Does nothing if SPI is already initiated (by ADE7953) so no harm done + SPI.begin(Pin(GPIO_SPI_CLK), Pin(GPIO_SPI_MISO), Pin(GPIO_SPI_MOSI), -1); + + if (4 == SPro.detected) { + digitalWrite(SPro.pin_register_cs, 1); + SPro.pin_mcp23s17_int = SHELLY_PRO_4_PIN_MCP23S17_INT; // GPIO35 = MCP23S17 common interrupt + pinMode(SPro.pin_mcp23s17_int, INPUT); + // Init MCP23S17 + ShellyPro4Init(); + } else { + digitalWrite(SPro.pin_register_cs, 0); + } + } + } +} + +void ShellyProInit(void) { + int pin_lan_reset = SHELLY_PRO_PIN_LAN8720_RESET; // GPIO5 = LAN8720 nRST +// delay(30); // (t-purstd) This pin must be brought low for a minimum of 25 mS after power on + digitalWrite(pin_lan_reset, 0); + pinMode(pin_lan_reset, OUTPUT); + delay(1); // (t-rstia) This pin must be brought low for a minimum of 100 uS + digitalWrite(pin_lan_reset, 1); + + AddLog(LOG_LEVEL_INFO, PSTR("HDW: Shelly Pro %d%s initialized"), SPro.detected, (PinUsed(GPIO_ADE7953_CS))?"PM":""); +} + +void ShellyProPower(void) { + if (4 == SPro.detected) { + + AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Set Power 0x%08X"), XdrvMailbox.index); + + power_t rpower = XdrvMailbox.index; + for (uint32_t i = 0; i < 4; i++) { + power_t state = rpower &1; + SP4Mcp23S17DigitalWrite(sp4_relay_pin[i], state); + rpower >>= 1; // Select next power + } + } else { + SPro.power = XdrvMailbox.index &3; + ShellyProUpdate(); + } +} + +void ShellyProUpdateLedLink(uint32_t ledlink) { + if (4 == SPro.detected) { + + + } else { + if (ledlink != SPro.ledlink) { + SPro.ledlink = ledlink; + ShellyProUpdate(); + } + } +} + +void ShellyProLedLink(void) { + if (4 == SPro.detected) { + + + } else { + /* + bit 2 = blue, 3 = green, 4 = red + Shelly Pro documentation + - Blue light indicator will be on if in AP mode. + - Red light indicator will be on if in STA mode and not connected to a Wi-Fi network. + - Yellow light indicator will be on if in STA mode and connected to a Wi-Fi network. + - Green light indicator will be on if in STA mode and connected to a Wi-Fi network and to the Shelly Cloud. + - The light indicator will be flashing Red/Blue if OTA update is in progress. + Tasmota behaviour + - Blue light indicator will blink if no wifi or mqtt. + - Green light indicator will be on if in STA mode and connected to a Wi-Fi network. + */ + SPro.last_update = TasmotaGlobal.uptime; + uint32_t ledlink = 0x1C; // All leds off + if (XdrvMailbox.index) { + ledlink &= 0xFB; // Blue blinks if wifi/mqtt lost + } + else if (!TasmotaGlobal.global_state.wifi_down) { + ledlink &= 0xF7; // Green On + } + ShellyProUpdateLedLink(ledlink); + } +} + +void ShellyProLedLinkWifiOff(void) { + if (4 == SPro.detected) { + + + } else { + /* + bit 2 = blue, 3 = green, 4 = red + - Green light indicator will be on if in STA mode and connected to a Wi-Fi network. + */ + if (SPro.last_update +1 < TasmotaGlobal.uptime) { + ShellyProUpdateLedLink((TasmotaGlobal.global_state.wifi_down) ? 0x1C : 0x14); // Green off if wifi OFF + } + } +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xdrv88(uint32_t function) { + bool result = false; + + if (FUNC_MODULE_INIT == function) { + ShellyProPreInit(); + } else if (SPro.detected) { + switch (function) { + case FUNC_EVERY_50_MSECOND: + ShellyProUpdateSwitches(); + break; + case FUNC_BUTTON_PRESSED: + result = ShellyProButton(); + break; + case FUNC_EVERY_SECOND: + ShellyProLedLinkWifiOff(); + break; + case FUNC_SET_DEVICE_POWER: + ShellyProPower(); + return true; + case FUNC_LED_LINK: + ShellyProLedLink(); + break; + case FUNC_INIT: + ShellyProInit(); + break; + case FUNC_ADD_BUTTON: + result = ShellyProAddButton(); + break; + case FUNC_ADD_SWITCH: + result = ShellyProAddSwitch(); + break; + } + } + return result; +} + +#endif // USE_SHELLY_PRO +#endif // USE_SPI +#endif // ESP32 diff --git a/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino b/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino index c5f282bef..380ef16e8 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino @@ -36,21 +36,21 @@ * Based on datasheet from https://www.analog.com/en/products/ade7953.html * * Model differences: - * Function Model1 Model2 Model3 Model4 Model5 Remark - * ------------------------------ ------- ------- ------- ------ ------ ------------------------------------------------- - * Shelly 2.5 EM Plus2PM Pro1PM Pro2PM - * Processor ESP8266 ESP8266 ESP32 ESP32 ESP32 - * Interface I2C I2C I2C SPI SPI Interface type used - * Number of ADE9753 chips 1 1 1 1 2 Count of ADE9753 chips - * ADE9753 IRQ 1 2 3 4 5 Index defines model number - * Current measurement device shunt CT shunt shunt shunt CT = Current Transformer - * Common voltage Yes Yes Yes No No Show common voltage in GUI/JSON - * Common frequency Yes Yes Yes No No Show common frequency in GUI/JSON - * Swapped channel A/B Yes No No No No Defined by hardware design - Fixed by Tasmota - * Support Export Active No Yes No No No Only EM supports correct negative value detection - * Show negative (reactive) power No Yes No No No Only EM supports correct negative value detection - * Default phase calibration 0 200 0 0 0 CT needs different phase calibration than shunts - * Default reset pin on ESP8266 - 16 - - - Legacy support. Replaced by GPIO ADE7953RST + * Function Model1 Model2 Model3 Model4 Model5 Model6 Remark + * ------------------------------ ------- ------- ------- ------ ------ ------ ------------------------------------------------- + * Shelly 2.5 EM Plus2PM Pro1PM Pro2PM Pro4PM + * Processor ESP8266 ESP8266 ESP32 ESP32 ESP32 ESP32 + * Interface I2C I2C I2C SPI SPI SPI Interface type used + * Number of ADE9753 chips 1 1 1 1 2 2 Count of ADE9753 chips + * ADE9753 IRQ 1 2 3 4 5 6 Index defines model number + * Current measurement device shunt CT shunt shunt shunt shunt CT = Current Transformer + * Common voltage Yes Yes Yes No No No Show common voltage in GUI/JSON + * Common frequency Yes Yes Yes No No No Show common frequency in GUI/JSON + * Swapped channel A/B Yes No No No No No Defined by hardware design - Fixed by Tasmota + * Support Export Active No Yes No No No No Only EM supports correct negative value detection + * Show negative (reactive) power No Yes No No No No Only EM supports correct negative value detection + * Default phase calibration 0 200 0 0 0 0 CT needs different phase calibration than shunts + * Default reset pin on ESP8266 - 16 - - - - Legacy support. Replaced by GPIO ADE7953RST * * I2C Address: 0x38 ********************************************************************************************* @@ -82,7 +82,7 @@ #define ADE7953_PHCAL_DEFAULT 0 // = range -383 to 383 - Default phase calibration for Shunts #define ADE7953_PHCAL_DEFAULT_CT 200 // = range -383 to 383 - Default phase calibration for Current Transformers (Shelly EM) -enum Ade7953Models { ADE7953_SHELLY_25, ADE7953_SHELLY_EM, ADE7953_SHELLY_PLUS_2PM, ADE7953_SHELLY_PRO_1PM, ADE7953_SHELLY_PRO_2PM }; +enum Ade7953Models { ADE7953_SHELLY_25, ADE7953_SHELLY_EM, ADE7953_SHELLY_PLUS_2PM, ADE7953_SHELLY_PRO_1PM, ADE7953_SHELLY_PRO_2PM, ADE7953_SHELLY_PRO_4PM }; enum Ade7953_8BitRegisters { // Register Name Addres R/W Bt Ty Default Description @@ -225,7 +225,7 @@ struct Ade7953 { uint32_t active_power[2] = { 0, 0 }; int32_t calib_data[2][ADE7953_CALIBREGS]; uint8_t init_step = 0; - uint8_t model = 0; // 0 = Shelly 2.5, 1 = Shelly EM, 2 = Shelly Plus 2PM, 3 = Shelly Pro 1PM, 4 = Shelly Pro 2PM + uint8_t model = 0; // 0 = Shelly 2.5, 1 = Shelly EM, 2 = Shelly Plus 2PM, 3 = Shelly Pro 1PM, 4 = Shelly Pro 2PM, 5 = Shelly Pro 4PM uint8_t cs_index; #ifdef USE_ESP32_SPI SPISettings spi_settings; @@ -233,6 +233,8 @@ struct Ade7953 { #endif // USE_ESP32_SPI } Ade7953; +/*********************************************************************************************/ + int Ade7953RegSize(uint16_t reg) { int size = 0; switch ((reg >> 8) & 0x0F) { @@ -250,6 +252,18 @@ int Ade7953RegSize(uint16_t reg) { return size; } +void Ade7953SpiEnable(void) { + digitalWrite(Ade7953.pin_cs[Ade7953.cs_index], 0); + delayMicroseconds(1); // CS 1uS to SCLK edge + SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0)); // Set up SPI at 1MHz, MSB first, Capture at rising edge +} + +void Ade7953SpiDisable(void) { + SPI.endTransaction(); + delayMicroseconds(2); // CS high 1.2uS after SCLK edge (when writing to COMM_LOCK bit) + digitalWrite(Ade7953.pin_cs[Ade7953.cs_index], 1); +} + void Ade7953Write(uint16_t reg, uint32_t val) { int size = Ade7953RegSize(reg); if (size) { @@ -258,6 +272,7 @@ void Ade7953Write(uint16_t reg, uint32_t val) { #ifdef USE_ESP32_SPI if (Ade7953.pin_cs[0] >= 0) { +/* digitalWrite(Ade7953.pin_cs[Ade7953.cs_index], 0); delayMicroseconds(1); // CS 1uS to SCLK edge SPI.beginTransaction(Ade7953.spi_settings); @@ -269,6 +284,15 @@ void Ade7953Write(uint16_t reg, uint32_t val) { SPI.endTransaction(); delayMicroseconds(2); // CS high 1.2uS after SCLK edge (when writing to COMM_LOCK bit) digitalWrite(Ade7953.pin_cs[Ade7953.cs_index], 1); +*/ + Ade7953SpiEnable(); + SPI.transfer16(reg); + SPI.transfer(0x00); // Write + while (size--) { + SPI.transfer((val >> (8 * size)) & 0xFF); // Write data, MSB first + } + Ade7953SpiDisable(); + } else { #endif // USE_ESP32_SPI Wire.beginTransmission(ADE7953_ADDR); @@ -292,6 +316,7 @@ int32_t Ade7953Read(uint16_t reg) { if (size) { #ifdef USE_ESP32_SPI if (Ade7953.pin_cs[0] >= 0) { +/* digitalWrite(Ade7953.pin_cs[Ade7953.cs_index], 0); delayMicroseconds(1); // CS 1uS to SCLK edge SPI.beginTransaction(Ade7953.spi_settings); @@ -302,6 +327,15 @@ int32_t Ade7953Read(uint16_t reg) { } SPI.endTransaction(); digitalWrite(Ade7953.pin_cs[Ade7953.cs_index], 1); +*/ + Ade7953SpiEnable(); + SPI.transfer16(reg); + SPI.transfer(0x80); // Read + while (size--) { + response = response << 8 | SPI.transfer(0xFF); // receive DATA (MSB first) + } + Ade7953SpiDisable(); + } else { #endif // USE_ESP32_SPI Wire.beginTransmission(ADE7953_ADDR); @@ -449,9 +483,16 @@ void Ade7953GetData(void) { #ifdef USE_ESP32_SPI } #endif // USE_ESP32_SPI - AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("ADE: ACCMODE 0x%06X, VRMS %d, %d, Period %d, %d, IRMS %d, %d, WATT %d, %d, VA %d, %d, VAR %d, %d"), - acc_mode, reg[0][4], reg[1][4], reg[0][5], reg[1][5], - reg[0][0], reg[1][0], reg[0][1], reg[1][1], reg[0][2], reg[1][2], reg[0][3], reg[1][3]); + +#ifdef USE_ESP32_SPI + if (1 == Energy.phase_count) { + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("ADE: ACCMODE 0x%06X, VRMS %d, Period %d, IRMS %d, WATT %d, VA %d, VAR %d"), + acc_mode, reg[0][4], reg[0][5], reg[0][0], reg[0][1], reg[0][2], reg[0][3]); + } else +#endif // USE_ESP32_SPI + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("ADE: ACCMODE 0x%06X, VRMS %d, %d, Period %d, %d, IRMS %d, %d, WATT %d, %d, VA %d, %d, VAR %d, %d"), + acc_mode, reg[0][4], reg[1][4], reg[0][5], reg[1][5], + reg[0][0], reg[1][0], reg[0][1], reg[1][1], reg[0][2], reg[1][2], reg[0][3], reg[1][3]); // If the device is initializing, we read the energy registers to reset them, but don't report the values as the first read may be inaccurate if (Ade7953.init_step) { return; } @@ -459,7 +500,7 @@ void Ade7953GetData(void) { uint32_t apparent_power[2] = { 0, 0 }; uint32_t reactive_power[2] = { 0, 0 }; - for (uint32_t channel = 0; channel < 2; channel++) { + for (uint32_t channel = 0; channel < Energy.phase_count; channel++) { Ade7953.voltage_rms[channel] = reg[channel][4]; Ade7953.current_rms[channel] = reg[channel][0]; if (Ade7953.current_rms[channel] < 2000) { // No load threshold (20mA) @@ -477,7 +518,7 @@ void Ade7953GetData(void) { if (Energy.power_on) { // Powered on float divider; - for (uint32_t channel = 0; channel < 2; channel++) { + for (uint32_t channel = 0; channel < Energy.phase_count; channel++) { Energy.data_valid[channel] = 0; float power_calibration = (float)EnergyGetCalibration(channel, ENERGY_POWER_CALIBRATION) / 10; @@ -649,6 +690,11 @@ void Ade7953DrvInit(void) { pinMode(pin_reset, INPUT); } } +#ifdef USE_SHELLY_PRO + if (Ade7953.model == ADE7953_SHELLY_PRO_4PM) { + ShellyPro4Reset(); + } +#endif // USE_SHELLY_PRO delay(100); // Need 100mS to init ADE7953 #ifdef USE_ESP32_SPI From 8b96f68a5b274585817eb24968e64f49cbaf3fe1 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sat, 21 Jan 2023 15:42:31 +0100 Subject: [PATCH 161/262] Fix ESP8266 compilation --- tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino b/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino index 380ef16e8..25714ba2b 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino @@ -252,6 +252,7 @@ int Ade7953RegSize(uint16_t reg) { return size; } +#ifdef USE_ESP32_SPI void Ade7953SpiEnable(void) { digitalWrite(Ade7953.pin_cs[Ade7953.cs_index], 0); delayMicroseconds(1); // CS 1uS to SCLK edge @@ -263,6 +264,7 @@ void Ade7953SpiDisable(void) { delayMicroseconds(2); // CS high 1.2uS after SCLK edge (when writing to COMM_LOCK bit) digitalWrite(Ade7953.pin_cs[Ade7953.cs_index], 1); } +#endif // USE_ESP32_SPI void Ade7953Write(uint16_t reg, uint32_t val) { int size = Ade7953RegSize(reg); @@ -690,11 +692,13 @@ void Ade7953DrvInit(void) { pinMode(pin_reset, INPUT); } } +#ifdef USE_ESP32_SPI #ifdef USE_SHELLY_PRO if (Ade7953.model == ADE7953_SHELLY_PRO_4PM) { ShellyPro4Reset(); } #endif // USE_SHELLY_PRO +#endif // USE_ESP32_SPI delay(100); // Need 100mS to init ADE7953 #ifdef USE_ESP32_SPI From d38a0c799cb584f5d9c6a6e4fd86dcd71b6837d8 Mon Sep 17 00:00:00 2001 From: gemu Date: Sun, 22 Jan 2023 10:56:06 +0100 Subject: [PATCH 162/262] Epaper deep sleep support (#17766) * allow descriptor reload * restart reason rrsn, database rewrite * support for deep sleep * revert * restart reason --- lib/lib_display/UDisplay/uDisplay.cpp | 68 ++++++++++++++----- lib/lib_display/UDisplay/uDisplay.h | 1 + .../tasmota_xdrv_driver/xdrv_10_scripter.ino | 4 ++ .../tasmota_xdrv_driver/xdrv_13_display.ino | 4 +- 4 files changed, 60 insertions(+), 17 deletions(-) diff --git a/lib/lib_display/UDisplay/uDisplay.cpp b/lib/lib_display/UDisplay/uDisplay.cpp index bba40257a..66ab35bac 100755 --- a/lib/lib_display/UDisplay/uDisplay.cpp +++ b/lib/lib_display/UDisplay/uDisplay.cpp @@ -52,11 +52,28 @@ int8_t uDisplay::color_type(void) { return col_type; } - uDisplay::~uDisplay(void) { - if (framebuffer) { - free(framebuffer); +#ifdef UDSP_DEBUG + Serial.printf("dealloc\n"); +#endif + if (frame_buffer) { + free(frame_buffer); } + + if (lut_full) { + free(lut_full); + } + + if (lut_partial) { + free(lut_partial); + } + + for (uint16_t cnt = 0; cnt < MAX_LUTS; cnt++ ) { + if (lut_array[cnt]) { + free(lut_array[cnt]); + } + } + #ifdef USE_ESP32_S3 if (_dmadesc) { heap_caps_free(_dmadesc); @@ -66,18 +83,6 @@ uDisplay::~uDisplay(void) { if (_i80_bus) { esp_lcd_del_i80_bus(_i80_bus); } - - if (lut_full) { - free(lut_full); - } - if (lut_partial) { - free(lut_partial); - } - for (uint16_t cnt = 0; cnt < MAX_LUTS; cnt++ ) { - if (lut_array[cnt]) { - free(lut_array[cnt]); - } - } #endif // USE_ESP32_S3 } @@ -124,7 +129,10 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) { for (uint32_t cnt = 0; cnt < MAX_LUTS; cnt++) { lut_cnt[cnt] = 0; lut_cmd[cnt] = 0xff; + lut_array[cnt] = 0; } + lut_partial = 0; + lut_full = 0; char linebuff[128]; while (*lp) { @@ -498,7 +506,7 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) { } #ifdef UDSP_DEBUG - + Serial.printf("Device : %s\n", dname); Serial.printf("xs : %d\n", gxs); Serial.printf("ys : %d\n", gys); Serial.printf("bpp: %d\n", bpp); @@ -635,6 +643,10 @@ void uDisplay::delay_arg(uint32_t args) { #define EP_SEND_DATA 0x66 #define EP_CLR_FRAME 0x67 #define EP_SEND_FRAME 0x68 +#define EP_BREAK_RR_EQU 0x69 +#define EP_BREAK_RR_NEQ 0x6a + +extern int32_t ESP_ResetInfoReason(); void uDisplay::send_spi_cmds(uint16_t cmd_offset, uint16_t cmd_size) { uint16_t index = 0; @@ -692,6 +704,26 @@ uint16_t index = 0; case EP_SEND_FRAME: SetFrameMemory(framebuffer); break; + case EP_BREAK_RR_EQU: + if (args & 1) { + iob = dsp_cmds[cmd_offset++]; + index++; + if (iob == ESP_ResetInfoReason()) { + ep_update_mode = DISPLAY_INIT_PARTIAL; + goto exit; + } + } + break; + case EP_BREAK_RR_NEQ: + if (args & 1) { + iob = dsp_cmds[cmd_offset++]; + index++; + if (iob != ESP_ResetInfoReason()) { + ep_update_mode = DISPLAY_INIT_PARTIAL; + goto exit; + } + } + break; } #ifdef UDSP_DEBUG if (args & 1) { @@ -731,9 +763,12 @@ uint16_t index = 0; } if (index >= cmd_size) break; } + +exit: #ifdef UDSP_DEBUG Serial.printf("end send cmd table\n"); #endif + return; } Renderer *uDisplay::Init(void) { @@ -756,6 +791,7 @@ Renderer *uDisplay::Init(void) { } #endif // ESP8266 } + frame_buffer = framebuffer; if (interface == _UDSP_I2C) { if (wire_n == 0) { diff --git a/lib/lib_display/UDisplay/uDisplay.h b/lib/lib_display/UDisplay/uDisplay.h index de5a8479c..2f11044f1 100755 --- a/lib/lib_display/UDisplay/uDisplay.h +++ b/lib/lib_display/UDisplay/uDisplay.h @@ -301,6 +301,7 @@ class uDisplay : public Renderer { uint8_t lut_siz_full; uint8_t *lut_partial; uint8_t lut_siz_partial; + uint8_t *frame_buffer; uint8_t epcoffs_full; uint8_t epc_full_cnt; diff --git a/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino b/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino index bac7dd575..ecfc0d418 100755 --- a/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino @@ -4124,6 +4124,10 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); } goto strexit; } + if (!strncmp(lp, "rrsn", 4)) { + fvar = ESP_ResetInfoReason(); + goto exit; + } if (!strncmp(lp, "rax", 3)) { TasmotaGlobal.no_autoexec = 0; goto exit; diff --git a/tasmota/tasmota_xdrv_driver/xdrv_13_display.ino b/tasmota/tasmota_xdrv_driver/xdrv_13_display.ino index 547fdde95..05bc7db16 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_13_display.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_13_display.ino @@ -636,7 +636,9 @@ void DisplayText(void) model = Settings->display_model; fp.read((uint8_t*)fdesc, size); fp.close(); + Renderer *svptr = renderer; Get_display(temp); + renderer = svptr; if (rot >= 0) { srot = Settings->display_rotate; Settings->display_rotate = rot; @@ -646,7 +648,7 @@ void DisplayText(void) Settings->display_rotate = srot; } Set_display(temp); - AddLog(LOG_LEVEL_INFO, PSTR("DSP: File descriptor loaded %x"),renderer); + AddLog(LOG_LEVEL_INFO, PSTR("DSP: File descriptor loaded")); free(fdesc); Settings->display_model = model; } From 3f73d5a49db435f252b4fdb5523e01542da21b67 Mon Sep 17 00:00:00 2001 From: yvesdm3000 Date: Sun, 22 Jan 2023 11:50:52 +0100 Subject: [PATCH 163/262] Implement Zigbee tuya_time sync. (#17765) --- .../xdrv_23_zigbee_6_0_commands.ino | 39 ++++++++++++++++--- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_6_0_commands.ino b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_6_0_commands.ino index 4aaad582b..3183db08a 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_6_0_commands.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_6_0_commands.ino @@ -578,26 +578,55 @@ void parseSingleTuyaAttribute(Z_attribute & attr, const SBuffer &buf, } } +/*********************************************************************************************\ + * + * Reply Tuya time + * +\*********************************************************************************************/ +static void replyTuyaTime( uint16_t cluster, uint16_t shortaddr, uint8_t dstendpoint ) { + ZCLFrame zcl(10); // message is `attrs_len` bytes + zcl.shortaddr = shortaddr; + zcl.cluster = cluster; + zcl.dstendpoint = dstendpoint; + zcl.cmd = 0x24; + zcl.clusterSpecific = true; + zcl.needResponse = false; // it is a reply + zcl.direct = false; // discover route + zcl.payload.add16BigEndian(8); // Size + if (!RtcTime.valid) { + zcl.payload.add32(0); + zcl.payload.add32(0); + } else { + zcl.payload.add32BigEndian(Rtc.utc_time); + zcl.payload.add32BigEndian(Rtc.local_time); + } + zigbeeZCLSendCmd(zcl); +} + // // Tuya - MOES specifc cluster 0xEF00 // https://developer.tuya.com/en/docs/iot-device-dev/tuya-zigbee-universal-docking-access-standard?id=K9ik6zvofpzql#subtitle-6-Private%20cluster // bool convertTuyaSpecificCluster(class Z_attribute_list &attr_list, uint16_t cluster, uint8_t cmd, bool direction, uint16_t shortaddr, uint8_t srcendpoint, const SBuffer &buf) { - // uint16_t seq_number = buf.get16BigEndian(0) - uint8_t dpid = buf.get8(2); // dpid from Tuya documentation - uint8_t attr_type = buf.get8(3); // data type from Tuya documentation - uint16_t len = buf.get16BigEndian(4); if ((1 == cmd) || (2 == cmd)) { // attribute report or attribute response + // uint16_t seq_number = buf.get16BigEndian(0) + uint8_t dpid = buf.get8(2); // dpid from Tuya documentation + uint8_t attr_type = buf.get8(3); // data type from Tuya documentation + uint16_t len = buf.get16BigEndian(4); // create a synthetic attribute with id 'dpid' Z_attribute & attr = attr_list.addAttribute(cluster, (attr_type << 8) | dpid); parseSingleTuyaAttribute(attr, buf, 6, len, attr_type); return true; // true = remove the original Tuya attribute } - // TODO Cmd 0x24 to sync clock with coordinator time + if (0x24 == cmd) { + replyTuyaTime(cluster, shortaddr, srcendpoint); + return true; + } return false; } + /*********************************************************************************************\ * * Find commands From 88dd5f7f504eb859ba45b31102e460672e20b3c8 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 22 Jan 2023 16:41:25 +0100 Subject: [PATCH 164/262] Fix Shelly Pro 4PM auto reset --- tasmota/tasmota_support/support_button_v4.ino | 29 ++++-- tasmota/tasmota_support/support_switch_v4.ino | 21 +++- .../xdrv_88_esp32_shelly_pro_v2.ino | 95 +++++++++---------- .../tasmota_xnrg_energy/xnrg_07_ade7953.ino | 27 ------ 4 files changed, 83 insertions(+), 89 deletions(-) diff --git a/tasmota/tasmota_support/support_button_v4.ino b/tasmota/tasmota_support/support_button_v4.ino index 4de6f9ae5..ea9e5c398 100644 --- a/tasmota/tasmota_support/support_button_v4.ino +++ b/tasmota/tasmota_support/support_button_v4.ino @@ -27,6 +27,8 @@ #define MAX_RELAY_BUTTON1 5 // Max number of relay controlled by BUTTON1 +#define BUTTON_INVERT 0x02 // Invert bitmask + const uint8_t BUTTON_PROBE_INTERVAL = 10; // Time in milliseconds between button input probe const uint8_t BUTTON_FAST_PROBE_INTERVAL = 2; // Time in milliseconds between button input probe for AC detection const uint8_t BUTTON_AC_PERIOD = (20 + BUTTON_FAST_PROBE_INTERVAL - 1) / BUTTON_FAST_PROBE_INTERVAL; // Duration of an AC wave in probe intervals @@ -134,7 +136,7 @@ void ButtonProbe(void) { not_activated = (digitalRead(Pin(GPIO_KEY1, i)) != bitRead(Button.inverted_mask, i)); } else if (bitRead(Button.virtual_pin_used, i)) { - not_activated = bitRead(Button.virtual_pin, i); + not_activated = (bitRead(Button.virtual_pin, i) != bitRead(Button.inverted_mask, i)); } else { continue; } @@ -251,12 +253,23 @@ void ButtonInit(void) { else { XdrvMailbox.index = i; if (XdrvCall(FUNC_ADD_BUTTON)) { - - AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: Add button %d"), i); - - bitSet(Button.virtual_pin_used, i); + /* + At entry: + XdrvMailbox.index = key index + At exit: + XdrvMailbox.index bit 0 = current state + XdrvMailbox.index bit 1 = invert signal + */ Button.present++; - Button.last_state[i] = XdrvMailbox.payload; + bitSet(Button.virtual_pin_used, i); // This pin is used + bool state = (XdrvMailbox.index &1); + ButtonSetVirtualPinState(i, state); // Virtual hardware pin state + bool invert = (XdrvMailbox.index &BUTTON_INVERT); + if (invert) { ButtonInvertFlag(i); } // Set inverted flag + Button.last_state[i] = (bitRead(Button.virtual_pin, i) != bitRead(Button.inverted_mask, i)); + + AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: Add vButton%d, State %d, Info %02X"), Button.present, Button.last_state[i], XdrvMailbox.index); + used = true; } } @@ -267,6 +280,9 @@ void ButtonInit(void) { } Button.debounced_state[i] = Button.last_state[i]; } + +// AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: vPinUsed %08X, State %08X, Invert %08X"), Button.virtual_pin_used, Button.virtual_pin, Button.inverted_mask); + if (Button.present) { Button.first_change = true; TickerButton.attach_ms((ac_detect) ? BUTTON_FAST_PROBE_INTERVAL : BUTTON_PROBE_INTERVAL, ButtonProbe); @@ -371,6 +387,7 @@ void ButtonHandler(void) { if (button_present) { XdrvMailbox.index = button_index; XdrvMailbox.payload = button; + XdrvMailbox.command_code = Button.last_state[button_index]; if (XdrvCall(FUNC_BUTTON_PRESSED)) { // Serviced } diff --git a/tasmota/tasmota_support/support_switch_v4.ino b/tasmota/tasmota_support/support_switch_v4.ino index 9b4a81f72..a2aecd797 100644 --- a/tasmota/tasmota_support/support_switch_v4.ino +++ b/tasmota/tasmota_support/support_switch_v4.ino @@ -236,12 +236,20 @@ void SwitchInit(void) { else { XdrvMailbox.index = i; if (XdrvCall(FUNC_ADD_SWITCH)) { - - AddLog(LOG_LEVEL_DEBUG, PSTR("SWT: Add switch %d"), i); - - bitSet(Switch.virtual_pin_used, i); + /* + At entry: + XdrvMailbox.index = switch index + At exit: + XdrvMailbox.index bit 0 = current state + */ Switch.present++; - Switch.last_state[i] = XdrvMailbox.payload; + bitSet(Switch.virtual_pin_used, i); // This pin is used + bool state = (XdrvMailbox.index &1); + SwitchSetVirtualPinState(i, state); // Virtual hardware pin state + Switch.last_state[i] = bitRead(Switch.virtual_pin, i); + + AddLog(LOG_LEVEL_DEBUG, PSTR("SWT: Add vSwitch%d, State %d, Info %02X"), Switch.present, Switch.last_state[i], XdrvMailbox.index); + used = true; } } @@ -252,6 +260,9 @@ void SwitchInit(void) { } Switch.debounced_state[i] = Switch.last_state[i]; } + +// AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: vPinUsed %08X, State %08X"), Switch.virtual_pin_used, Switch.virtual_pin); + if (Switch.present) { Switch.first_change = true; TickerSwitch.attach_ms((ac_detect) ? SWITCH_FAST_PROBE_INTERVAL : SWITCH_PROBE_INTERVAL, SwitchProbe); diff --git a/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v2.ino b/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v2.ino index 2b43768f9..6729169ae 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v2.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v2.ino @@ -47,7 +47,6 @@ struct SPro { uint32_t probe_pin; int switch_offset; int button_offset; - uint8_t last_button[3]; uint8_t pin_register_cs; uint8_t pin_mcp23s17_int; uint8_t ledlink; @@ -151,16 +150,6 @@ void SP4Mcp23S17Update(uint8_t pin, bool pin_value, uint8_t reg_addr) { } } -void SP4Mcp23S17Setup(void) { - SP4Mcp23S17Write(SP4_MCP23S17_IOCONA, 0b01011000); // Enable INT mirror, Slew rate disabled, HAEN pins for addressing - SP4Mcp23S17Write(SP4_MCP23S17_GPINTENA, 0x6F); // Enable interrupt on change - SP4Mcp23S17Write(SP4_MCP23S17_GPINTENB, 0x80); // Enable interrupt on change - - // Read current output register state - SP4Mcp23S17Read(SP4_MCP23S17_OLATA, &sp4_mcp23s17_olata); - SP4Mcp23S17Read(SP4_MCP23S17_OLATB, &sp4_mcp23s17_olatb); -} - void SP4Mcp23S17PinMode(uint8_t pin, uint8_t flags) { uint8_t iodir = pin < 8 ? SP4_MCP23S17_IODIRA : SP4_MCP23S17_IODIRB; uint8_t gppu = pin < 8 ? SP4_MCP23S17_GPPUA : SP4_MCP23S17_GPPUB; @@ -216,7 +205,13 @@ void ShellyPro4Init(void) { bit 14 = output - Relay O3 bit 15 = input - Switch4 */ - SP4Mcp23S17Setup(); + SP4Mcp23S17Write(SP4_MCP23S17_IOCONA, 0b01011000); // Enable INT mirror, Slew rate disabled, HAEN pins for addressing + SP4Mcp23S17Write(SP4_MCP23S17_GPINTENA, 0x6F); // Enable interrupt on change + SP4Mcp23S17Write(SP4_MCP23S17_GPINTENB, 0x80); // Enable interrupt on change + + // Read current output register state + SP4Mcp23S17Read(SP4_MCP23S17_OLATA, &sp4_mcp23s17_olata); + SP4Mcp23S17Read(SP4_MCP23S17_OLATB, &sp4_mcp23s17_olatb); for (uint32_t i = 0; i < 4; i++) { SP4Mcp23S17PinMode(sp4_switch_pin[i], INPUT); // Switch1..4 @@ -231,7 +226,6 @@ void ShellyPro4Init(void) { SP4Mcp23S17PinMode(4, OUTPUT); // Reset display, ADE7943 SP4Mcp23S17DigitalWrite(4, 1); - } void ShellyPro4Reset(void) { @@ -241,30 +235,30 @@ void ShellyPro4Reset(void) { } bool ShellyProAddButton(void) { - if (SPro.detected != 4) { return false; } + if (SPro.detected != 4) { return false; } // Only support Shelly Pro 4 if (SPro.button_offset < 0) { SPro.button_offset = XdrvMailbox.index; } uint32_t index = XdrvMailbox.index - SPro.button_offset; - if (index > 2) { return false; } - XdrvMailbox.payload = SP4Mcp23S17DigitalRead(sp4_button_pin[index]); + if (index > 2) { return false; } // Support three buttons + XdrvMailbox.index = SP4Mcp23S17DigitalRead(sp4_button_pin[index]); return true; } bool ShellyProAddSwitch(void) { - if (SPro.detected != 4) { return false; } + if (SPro.detected != 4) { return false; } // Only support Shelly Pro 4 if (SPro.switch_offset < 0) { SPro.switch_offset = XdrvMailbox.index; } uint32_t index = XdrvMailbox.index - SPro.switch_offset; - if (index > 3) { return false; } - XdrvMailbox.payload = SP4Mcp23S17DigitalRead(sp4_switch_pin[index]); + if (index > 3) { return false; } // Support four switches + XdrvMailbox.index = SP4Mcp23S17DigitalRead(sp4_switch_pin[index]); return true; } void ShellyProUpdateSwitches(void) { - if (SPro.detected != 4) { return; } - if (digitalRead(SPro.pin_mcp23s17_int)) { return; } + if (SPro.detected != 4) { return; } // Only support Shelly Pro 4 + if (digitalRead(SPro.pin_mcp23s17_int)) { return; } // Poll interrupt - uint32_t gpio = SP4Mcp23S17ReadGpio(); + uint32_t gpio = SP4Mcp23S17ReadGpio(); // Read gpio and clear interrupt - AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Input detected 0x%04X"), gpio); +// AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Input detected 0x%04X"), gpio); // Propagate state uint32_t state; @@ -279,14 +273,14 @@ void ShellyProUpdateSwitches(void) { } bool ShellyProButton(void) { - if (SPro.detected != 4) { return false; } + if (SPro.detected != 4) { return false; } // Only support Shelly Pro 4 uint32_t button_index = XdrvMailbox.index - SPro.button_offset; - if (button_index > 2) { return false; } // We only support Up, Down, Ok + if (button_index > 2) { return false; } // Only support Up, Down, Ok - bool result = false; uint32_t button = XdrvMailbox.payload; - if ((PRESSED == button) && (NOT_PRESSED == SPro.last_button[button_index])) { // Button pressed + uint32_t last_state = XdrvMailbox.command_code; + if ((PRESSED == button) && (NOT_PRESSED == last_state)) { // Button pressed AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Button %d pressed"), button_index +1); @@ -299,10 +293,8 @@ bool ShellyProButton(void) { case 2: // Ok break; } - result = true; // Disable further button processing } - SPro.last_button[button_index] = button; - return result; + return true; // Disable further button processing } /*********************************************************************************************\ @@ -323,11 +315,11 @@ void ShellyProUpdate(void) { */ uint8_t val = SPro.power | SPro.ledlink; SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0)); - SPI.transfer(val); // Write 74HC595 shift register + SPI.transfer(val); // Write 74HC595 shift register SPI.endTransaction(); -// delayMicroseconds(2); // Wait for SPI clock to stop - digitalWrite(SPro.pin_register_cs, 1); // Latch data - delayMicroseconds(1); // Shelly 10mS +// delayMicroseconds(2); // Wait for SPI clock to stop + digitalWrite(SPro.pin_register_cs, 1); // Latch data + delayMicroseconds(1); // Shelly 10mS digitalWrite(SPro.pin_register_cs, 0); } @@ -337,18 +329,18 @@ void ShellyProUpdate(void) { void ShellyProPreInit(void) { if ((SPI_MOSI_MISO == TasmotaGlobal.spi_enabled) && - PinUsed(GPIO_SPI_CS) && // 74HC595 rclk / MCP23S17 - TasmotaGlobal.gpio_optiona.shelly_pro) { // Option_A7 + PinUsed(GPIO_SPI_CS) && // 74HC595 rclk / MCP23S17 + TasmotaGlobal.gpio_optiona.shelly_pro) { // Option_A7 if (PinUsed(GPIO_SWT1) || PinUsed(GPIO_KEY1)) { - SPro.detected = 1; // Shelly Pro 1 + SPro.detected = 1; // Shelly Pro 1 if (PinUsed(GPIO_SWT1, 1) || PinUsed(GPIO_KEY1, 1)) { - SPro.detected = 2; // Shelly Pro 2 + SPro.detected = 2; // Shelly Pro 2 } - SPro.ledlink = 0x18; // Blue led on - set by first call ShellyProPower() - Shelly 1/2 + SPro.ledlink = 0x18; // Blue led on - set by first call ShellyProPower() - Shelly 1/2 } if (SHELLY_PRO_4_PIN_SPI_CS == Pin(GPIO_SPI_CS)) { - SPro.detected = 4; // Shelly Pro 4PM (No SWT or KEY) + SPro.detected = 4; // Shelly Pro 4PM (No SWT or KEY) } if (SPro.detected) { @@ -360,13 +352,12 @@ void ShellyProPreInit(void) { SPI.begin(Pin(GPIO_SPI_CLK), Pin(GPIO_SPI_MISO), Pin(GPIO_SPI_MOSI), -1); if (4 == SPro.detected) { - digitalWrite(SPro.pin_register_cs, 1); + digitalWrite(SPro.pin_register_cs, 1); // Prep MCP23S17 chip select SPro.pin_mcp23s17_int = SHELLY_PRO_4_PIN_MCP23S17_INT; // GPIO35 = MCP23S17 common interrupt pinMode(SPro.pin_mcp23s17_int, INPUT); - // Init MCP23S17 - ShellyPro4Init(); + ShellyPro4Init(); // Init MCP23S17 } else { - digitalWrite(SPro.pin_register_cs, 0); + digitalWrite(SPro.pin_register_cs, 0); // Prep 74HC595 rclk } } } @@ -374,10 +365,10 @@ void ShellyProPreInit(void) { void ShellyProInit(void) { int pin_lan_reset = SHELLY_PRO_PIN_LAN8720_RESET; // GPIO5 = LAN8720 nRST -// delay(30); // (t-purstd) This pin must be brought low for a minimum of 25 mS after power on +// delay(30); // (t-purstd) This pin must be brought low for a minimum of 25 mS after power on digitalWrite(pin_lan_reset, 0); pinMode(pin_lan_reset, OUTPUT); - delay(1); // (t-rstia) This pin must be brought low for a minimum of 100 uS + delay(1); // (t-rstia) This pin must be brought low for a minimum of 100 uS digitalWrite(pin_lan_reset, 1); AddLog(LOG_LEVEL_INFO, PSTR("HDW: Shelly Pro %d%s initialized"), SPro.detected, (PinUsed(GPIO_ADE7953_CS))?"PM":""); @@ -386,13 +377,13 @@ void ShellyProInit(void) { void ShellyProPower(void) { if (4 == SPro.detected) { - AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Set Power 0x%08X"), XdrvMailbox.index); +// AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Set Power 0x%08X"), XdrvMailbox.index); power_t rpower = XdrvMailbox.index; for (uint32_t i = 0; i < 4; i++) { power_t state = rpower &1; SP4Mcp23S17DigitalWrite(sp4_relay_pin[i], state); - rpower >>= 1; // Select next power + rpower >>= 1; // Select next power } } else { SPro.power = XdrvMailbox.index &3; @@ -430,12 +421,12 @@ void ShellyProLedLink(void) { - Green light indicator will be on if in STA mode and connected to a Wi-Fi network. */ SPro.last_update = TasmotaGlobal.uptime; - uint32_t ledlink = 0x1C; // All leds off + uint32_t ledlink = 0x1C; // All leds off if (XdrvMailbox.index) { - ledlink &= 0xFB; // Blue blinks if wifi/mqtt lost + ledlink &= 0xFB; // Blue blinks if wifi/mqtt lost } else if (!TasmotaGlobal.global_state.wifi_down) { - ledlink &= 0xF7; // Green On + ledlink &= 0xF7; // Green On } ShellyProUpdateLedLink(ledlink); } @@ -470,9 +461,11 @@ bool Xdrv88(uint32_t function) { case FUNC_EVERY_50_MSECOND: ShellyProUpdateSwitches(); break; +/* case FUNC_BUTTON_PRESSED: result = ShellyProButton(); break; +*/ case FUNC_EVERY_SECOND: ShellyProLedLinkWifiOff(); break; diff --git a/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino b/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino index 25714ba2b..9efcd2748 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino @@ -274,19 +274,6 @@ void Ade7953Write(uint16_t reg, uint32_t val) { #ifdef USE_ESP32_SPI if (Ade7953.pin_cs[0] >= 0) { -/* - digitalWrite(Ade7953.pin_cs[Ade7953.cs_index], 0); - delayMicroseconds(1); // CS 1uS to SCLK edge - SPI.beginTransaction(Ade7953.spi_settings); - SPI.transfer16(reg); - SPI.transfer(0x00); // Write - while (size--) { - SPI.transfer((val >> (8 * size)) & 0xFF); // Write data, MSB first - } - SPI.endTransaction(); - delayMicroseconds(2); // CS high 1.2uS after SCLK edge (when writing to COMM_LOCK bit) - digitalWrite(Ade7953.pin_cs[Ade7953.cs_index], 1); -*/ Ade7953SpiEnable(); SPI.transfer16(reg); SPI.transfer(0x00); // Write @@ -294,7 +281,6 @@ void Ade7953Write(uint16_t reg, uint32_t val) { SPI.transfer((val >> (8 * size)) & 0xFF); // Write data, MSB first } Ade7953SpiDisable(); - } else { #endif // USE_ESP32_SPI Wire.beginTransmission(ADE7953_ADDR); @@ -318,18 +304,6 @@ int32_t Ade7953Read(uint16_t reg) { if (size) { #ifdef USE_ESP32_SPI if (Ade7953.pin_cs[0] >= 0) { -/* - digitalWrite(Ade7953.pin_cs[Ade7953.cs_index], 0); - delayMicroseconds(1); // CS 1uS to SCLK edge - SPI.beginTransaction(Ade7953.spi_settings); - SPI.transfer16(reg); - SPI.transfer(0x80); // Read - while (size--) { - response = response << 8 | SPI.transfer(0); // receive DATA (MSB first) - } - SPI.endTransaction(); - digitalWrite(Ade7953.pin_cs[Ade7953.cs_index], 1); -*/ Ade7953SpiEnable(); SPI.transfer16(reg); SPI.transfer(0x80); // Read @@ -337,7 +311,6 @@ int32_t Ade7953Read(uint16_t reg) { response = response << 8 | SPI.transfer(0xFF); // receive DATA (MSB first) } Ade7953SpiDisable(); - } else { #endif // USE_ESP32_SPI Wire.beginTransmission(ADE7953_ADDR); From 4297fa3f3eaecf91bd4cda094e2dc4c55275eecc Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 23 Jan 2023 12:51:02 +0100 Subject: [PATCH 165/262] Add Shelly Pro 4 input interrupt support --- tasmota/tasmota_support/support_button_v4.ino | 4 +- tasmota/tasmota_support/support_switch_v4.ino | 10 +- .../xdrv_88_esp32_shelly_pro_v2.ino | 97 +++++++++++-------- 3 files changed, 62 insertions(+), 49 deletions(-) diff --git a/tasmota/tasmota_support/support_button_v4.ino b/tasmota/tasmota_support/support_button_v4.ino index ea9e5c398..3b1ce159f 100644 --- a/tasmota/tasmota_support/support_button_v4.ino +++ b/tasmota/tasmota_support/support_button_v4.ino @@ -89,9 +89,7 @@ void ButtonTouchFlag(uint32_t button_bit) { void ButtonSetVirtualPinState(uint32_t index, uint32_t state) { - if (!Button.probe_mutex) { - bitWrite(Button.virtual_pin, index, state); - } + bitWrite(Button.virtual_pin, index, state); } /*********************************************************************************************/ diff --git a/tasmota/tasmota_support/support_switch_v4.ino b/tasmota/tasmota_support/support_switch_v4.ino index a2aecd797..a4546b66d 100644 --- a/tasmota/tasmota_support/support_switch_v4.ino +++ b/tasmota/tasmota_support/support_switch_v4.ino @@ -68,21 +68,23 @@ void SwitchPulldownFlag(uint32 switch_bit) { bitSet(Switch.pulldown_mask, switch_bit); } +// Preffered virtual switch support since v12.3.1.4 void SwitchSetVirtualPinState(uint32_t index, uint32_t state) { - if (!Switch.probe_mutex) { - bitWrite(Switch.virtual_pin, index, state); - } + bitWrite(Switch.virtual_pin, index, state); } +// Legacy virtual switch support void SwitchSetVirtual(uint32_t index, uint32_t state) { - bitSet(Switch.virtual_pin_used, index); +// bitSet(Switch.virtual_pin_used, index); Switch.debounced_state[index] = state; } +// Legacy virtual switch support uint8_t SwitchGetVirtual(uint32_t index) { return Switch.debounced_state[index]; } +// Legacy virtual switch support uint8_t SwitchLastState(uint32_t index) { return Switch.last_state[index]; } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v2.ino b/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v2.ino index 6729169ae..e7de1e849 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v2.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v2.ino @@ -45,8 +45,9 @@ struct SPro { uint32_t last_update; uint32_t probe_pin; - int switch_offset; - int button_offset; + uint16_t input_state; + int8_t switch_offset; + int8_t button_offset; uint8_t pin_register_cs; uint8_t pin_mcp23s17_int; uint8_t ledlink; @@ -98,33 +99,32 @@ void SP4Mcp23S17Disable(void) { digitalWrite(SPro.pin_register_cs, 1); } -uint32_t SP4Mcp23S17ReadGpio(void) { - // Read 16-bit gpio registers: (gpiob << 8) | gpioa - SP4Mcp23S17Enable(); - SPI.transfer(SHELLY_PRO_4_MCP23S17_ADDRESS | 1); - SPI.transfer(SP4_MCP23S17_GPIOA); - uint32_t gpio = SPI.transfer(0xFF); // SP4_MCP23S17_GPIOA - gpio |= (SPI.transfer(0xFF) << 8); // SP4_MCP23S17_GPIOB - SP4Mcp23S17Disable(); - return gpio; -} - -bool SP4Mcp23S17Read(uint8_t reg, uint8_t *value) { +uint32_t SP4Mcp23S17Read16(uint8_t reg) { + // Read 16-bit registers: (regb << 8) | rega SP4Mcp23S17Enable(); SPI.transfer(SHELLY_PRO_4_MCP23S17_ADDRESS | 1); SPI.transfer(reg); - *value = SPI.transfer(0xFF); + uint32_t value = SPI.transfer(0xFF); // RegA + value |= (SPI.transfer(0xFF) << 8); // RegB SP4Mcp23S17Disable(); - return true; + return value; } -bool SP4Mcp23S17Write(uint8_t reg, uint8_t value) { +uint32_t SP4Mcp23S17Read(uint8_t reg) { + SP4Mcp23S17Enable(); + SPI.transfer(SHELLY_PRO_4_MCP23S17_ADDRESS | 1); + SPI.transfer(reg); + uint32_t value = SPI.transfer(0xFF); + SP4Mcp23S17Disable(); + return value; +} + +void SP4Mcp23S17Write(uint8_t reg, uint8_t value) { SP4Mcp23S17Enable(); SPI.transfer(SHELLY_PRO_4_MCP23S17_ADDRESS); SPI.transfer(reg); SPI.transfer(value); SP4Mcp23S17Disable(); - return true; } void SP4Mcp23S17Update(uint8_t pin, bool pin_value, uint8_t reg_addr) { @@ -135,7 +135,7 @@ void SP4Mcp23S17Update(uint8_t pin, bool pin_value, uint8_t reg_addr) { } else if (reg_addr == SP4_MCP23S17_OLATB) { reg_value = sp4_mcp23s17_olatb; } else { - SP4Mcp23S17Read(reg_addr, ®_value); + reg_value = SP4Mcp23S17Read(reg_addr); } if (pin_value) { reg_value |= 1 << bit; @@ -167,8 +167,7 @@ void SP4Mcp23S17PinMode(uint8_t pin, uint8_t flags) { bool SP4Mcp23S17DigitalRead(uint8_t pin) { uint8_t bit = pin % 8; uint8_t reg_addr = pin < 8 ? SP4_MCP23S17_GPIOA : SP4_MCP23S17_GPIOB; - uint8_t value = 0; - SP4Mcp23S17Read(reg_addr, &value); + uint8_t value = SP4Mcp23S17Read(reg_addr); return value & (1 << bit); } @@ -210,8 +209,8 @@ void ShellyPro4Init(void) { SP4Mcp23S17Write(SP4_MCP23S17_GPINTENB, 0x80); // Enable interrupt on change // Read current output register state - SP4Mcp23S17Read(SP4_MCP23S17_OLATA, &sp4_mcp23s17_olata); - SP4Mcp23S17Read(SP4_MCP23S17_OLATB, &sp4_mcp23s17_olatb); + sp4_mcp23s17_olata = SP4Mcp23S17Read(SP4_MCP23S17_OLATA); + sp4_mcp23s17_olatb = SP4Mcp23S17Read(SP4_MCP23S17_OLATB); for (uint32_t i = 0; i < 4; i++) { SP4Mcp23S17PinMode(sp4_switch_pin[i], INPUT); // Switch1..4 @@ -226,6 +225,8 @@ void ShellyPro4Init(void) { SP4Mcp23S17PinMode(4, OUTPUT); // Reset display, ADE7943 SP4Mcp23S17DigitalWrite(4, 1); + + attachInterrupt(SPro.pin_mcp23s17_int, ShellyProUpdateIsr, CHANGE); } void ShellyPro4Reset(void) { @@ -239,7 +240,9 @@ bool ShellyProAddButton(void) { if (SPro.button_offset < 0) { SPro.button_offset = XdrvMailbox.index; } uint32_t index = XdrvMailbox.index - SPro.button_offset; if (index > 2) { return false; } // Support three buttons - XdrvMailbox.index = SP4Mcp23S17DigitalRead(sp4_button_pin[index]); + uint32_t state = SP4Mcp23S17DigitalRead(sp4_button_pin[index]); + bitWrite(SPro.input_state, sp4_button_pin[index], state); + XdrvMailbox.index = state; return true; } @@ -248,28 +251,41 @@ bool ShellyProAddSwitch(void) { if (SPro.switch_offset < 0) { SPro.switch_offset = XdrvMailbox.index; } uint32_t index = XdrvMailbox.index - SPro.switch_offset; if (index > 3) { return false; } // Support four switches - XdrvMailbox.index = SP4Mcp23S17DigitalRead(sp4_switch_pin[index]); + uint32_t state = SP4Mcp23S17DigitalRead(sp4_switch_pin[index]); + bitWrite(SPro.input_state, sp4_switch_pin[index], state); + XdrvMailbox.index = state ^1; // Invert return true; } -void ShellyProUpdateSwitches(void) { - if (SPro.detected != 4) { return; } // Only support Shelly Pro 4 - if (digitalRead(SPro.pin_mcp23s17_int)) { return; } // Poll interrupt +void ShellyProUpdateIsr(void) { + /* + The goal if this function is to minimize SPI and SetVirtualPinState calls + */ - uint32_t gpio = SP4Mcp23S17ReadGpio(); // Read gpio and clear interrupt + uint32_t input_state = SP4Mcp23S17Read16(SP4_MCP23S17_INTCAPA); // Read intcap and clear interrupt + input_state &= 0x806F; // Only test input bits -// AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Input detected 0x%04X"), gpio); +// AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Input detected %04X, was %04X"), input_state, SPro.input_state); - // Propagate state - uint32_t state; - for (uint32_t i = 0; i < 4; i++) { - state = (gpio >> sp4_switch_pin[i]) &1; - SwitchSetVirtualPinState(SPro.switch_offset +i, state); - } - for (uint32_t i = 0; i < 3; i++) { - state = (gpio >> sp4_button_pin[i]) &1; - ButtonSetVirtualPinState(SPro.button_offset +i, state); + uint32_t mask = 1; + for (uint32_t j = 0; j < 16; j++) { + if ((input_state & mask) != (SPro.input_state & mask)) { + uint32_t state = (input_state >> j) &1; + +// AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Change pin %d to %d"), j, state); + + for (uint32_t i = 0; i < 4; i++) { + if (j == sp4_switch_pin[i]) { + SwitchSetVirtualPinState(SPro.switch_offset +i, state ^1); // Invert + } + else if ((i < 3) && (j == sp4_button_pin[i])) { + ButtonSetVirtualPinState(SPro.button_offset +i, state); + } + } + } + mask <<= 1; } + SPro.input_state = input_state; } bool ShellyProButton(void) { @@ -458,9 +474,6 @@ bool Xdrv88(uint32_t function) { ShellyProPreInit(); } else if (SPro.detected) { switch (function) { - case FUNC_EVERY_50_MSECOND: - ShellyProUpdateSwitches(); - break; /* case FUNC_BUTTON_PRESSED: result = ShellyProButton(); From db0532de5f96f51113b3a172ccb1f385c8b81e85 Mon Sep 17 00:00:00 2001 From: Barbudor Date: Tue, 24 Jan 2023 08:52:43 +0100 Subject: [PATCH 166/262] ds3231 temperature sensor (#17778) --- tasmota/my_user_config.h | 1 + .../tasmota_xdrv_driver/xdrv_56_rtc_chips.ino | 53 +++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index e4455347e..6eee06d05 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -718,6 +718,7 @@ // #define USE_RTC_CHIPS // Enable RTC chip support and NTP server - Select only one // #define USE_DS3231 // [I2cDriver26] Enable DS3231 RTC (I2C address 0x68) (+1k2 code) +// #define DS3231_ENABLE_TEMP // In DS3231 driver, enable the internal temperature sensor // #define USE_BM8563 // [I2cDriver59] Enable BM8563 RTC - found in M5Stack - support both I2C buses on ESP32 (I2C address 0x51) (+2.5k code) // #define USE_PCF85363 // [I2cDriver66] Enable PCF85363 RTC - found Shelly 3EM (I2C address 0x51) (+0k7 code) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_56_rtc_chips.ino b/tasmota/tasmota_xdrv_driver/xdrv_56_rtc_chips.ino index a8f58ba40..7c9755869 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_56_rtc_chips.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_56_rtc_chips.ino @@ -23,6 +23,7 @@ struct { void (* SetTime)(uint32_t); int32_t (* MemRead)(uint8_t *, uint32_t); int32_t (* MemWrite)(uint8_t *, uint32_t); + void (* ShowSensor)(bool); bool detected; int8_t mem_size = -1; uint8_t address; @@ -51,6 +52,8 @@ struct { #define DS3231_YEAR 0x06 #define DS3231_CONTROL 0x0E #define DS3231_STATUS 0x0F +#define DS3231_TEMP_MSB 0x11 +#define DS3231_TEMP_LSB 0x12 // Control register bits #define DS3231_OSF 7 @@ -81,6 +84,47 @@ uint32_t DS3231ReadTime(void) { return MakeTime(tm); } +/*-------------------------------------------------------------------------------------------*\ + * Read temperature from DS3231 internal sensor, return as float +\*-------------------------------------------------------------------------------------------*/ +#ifdef DS3231_ENABLE_TEMP +float DS3231ReadTemp(void) { + int16_t temp_reg = I2cReadS16(RtcChip.address, DS3231_TEMP_MSB) >> 6; + float temp = temp_reg * 0.25; + //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("RTC: DS3231 temp_reg=%d"), temp_reg); + return temp; +} +#endif // #ifdef DS3231_ENABLE_TEMP + +/*-------------------------------------------------------------------------------------------*\ + * Show temperature from DS3231 internal sensor, Web or SENSOR +\*-------------------------------------------------------------------------------------------*/ +#ifdef DS3231_ENABLE_TEMP +void D3231ShowSensor(bool json) { + float f_temperature = ConvertTemp(DS3231ReadTemp()); + + if (json) { + ResponseAppend_P(PSTR(",\"DS3231\":{\"" D_JSON_TEMPERATURE "\":%*_f}"), Settings->flag2.temperature_resolution, &f_temperature); +#ifdef USE_DOMOTICZ + if (0 == TasmotaGlobal.tele_period) { + DomoticzFloatSensor(DZ_TEMP, f_temperature); + } +#endif // USE_DOMOTICZ +#ifdef USE_KNX + if (0 == TasmotaGlobal.tele_period) { + KnxSensor(KNX_TEMPERATURE, f_temperature); + } +#endif // USE_KNX + } +#ifdef USE_WEBSERVER + else { + WSContentSend_Temp("DS3231", f_temperature); + } +#endif // #ifdef USE_WEBSERVER +} +#endif // #ifdef DS3231_ENABLE_TEMP + + /*-------------------------------------------------------------------------------------------*\ * Get time as TIME_T and set the DS3231 time to this value \*-------------------------------------------------------------------------------------------*/ @@ -109,6 +153,9 @@ void DS3231Detected(void) { strcpy_P(RtcChip.name, PSTR("DS3231")); RtcChip.ReadTime = &DS3231ReadTime; RtcChip.SetTime = &DS3231SetTime; +#ifdef DS3231_ENABLE_TEMP + RtcChip.ShowSensor = &D3231ShowSensor; +#endif RtcChip.mem_size = -1; } } @@ -456,6 +503,12 @@ bool Xdrv56(uint32_t function) { case FUNC_TIME_SYNCED: RtcChipTimeSynced(); break; + case FUNC_WEB_SENSOR: + if (RtcChip.ShowSensor) RtcChip.ShowSensor(0); + break; + case FUNC_JSON_APPEND: + if (RtcChip.ShowSensor) RtcChip.ShowSensor(1); + break; } } From 36fd8358d63dde93d760c1764d9d3e592aba9f71 Mon Sep 17 00:00:00 2001 From: David Gwynne Date: Tue, 24 Jan 2023 17:54:19 +1000 Subject: [PATCH 167/262] TuyaMCUBr: support on/true/off/false/toggle in the tuyamcubool command. (#17775) * support on/true/off/false/toggle in the tuyamcubool command. i wanted a tasmotized wall switch to be able to blindly send "toggle" to a fan/light and have it do the right thing. the dp value is kept by the driver, so it can easily read, modify, and write it. * "on"/"off"/"toggle" etc are parsed when XdrvMailbox is set up so i don't have to do it, i just have to use the payload. --- .../tasmota_xdrv_driver/xdrv_65_tuyamcubr.ino | 48 ++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_65_tuyamcubr.ino b/tasmota/tasmota_xdrv_driver/xdrv_65_tuyamcubr.ino index 9c80900d1..8b5dc9e07 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_65_tuyamcubr.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_65_tuyamcubr.ino @@ -567,7 +567,53 @@ tuyamcubr_cmnd_data(struct tuyamcubr_softc *sc, uint8_t type) static void tuyamcubr_cmnd_data_bool(void) { - tuyamcubr_cmnd_data(tuyamcubr_sc, TUYAMCUBR_DATA_TYPE_BOOL); + struct tuyamcubr_softc *sc = tuyamcubr_sc; + struct { + struct tuyamcubr_data_header h; + uint8_t value[1]; + } data; + struct tuyamcubr_dp *dp; + uint32_t value; + + dp = tuyamcubr_find_dp(sc, XdrvMailbox.index, TUYAMCUBR_DATA_TYPE_BOOL); + if (dp == NULL) { + ResponseCmndChar_P(PSTR("Unknown DpId")); + return; + } + + if (XdrvMailbox.data_len == 0) { + ResponseCmndNumber(dp->dp_value); + return; + } + + switch (XdrvMailbox.payload) { + case 0: + case 1: + value = XdrvMailbox.payload; + break; + case 2: + value = !dp->dp_value; + break; + default: + ResponseCmndChar_P(PSTR("Invalid")); + return; + } + + dp->dp_value = value; + + data.h.dpid = dp->dp_id; + data.h.type = dp->dp_type; + data.h.len = htons(sizeof(data.value)); + data.value[0] = value; + + tuyamcubr_send(sc, TUYAMCUBR_CMD_SET_DP, &data, sizeof(data)); + tuyamcubr_rule_dp(sc, dp); + + ResponseCmndNumber(dp->dp_value); + + /* SetOption59 */ + if (Settings->flag3.hass_tele_on_power) + tuyamcubr_publish_dp(sc, dp); } static void From 1c39ff6cef1cc94a129cb4154aadac440f03f50a Mon Sep 17 00:00:00 2001 From: David Gwynne Date: Tue, 24 Jan 2023 17:55:28 +1000 Subject: [PATCH 168/262] add tuyamcubr_web_sensor to do a simple display of the dp values. (#17776) the format shows the type+dpid on the left hand side (eg, Bool1, Value2, Enum3, etc), and the value with %u on the right hand side. --- .../tasmota_xdrv_driver/xdrv_65_tuyamcubr.ino | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_65_tuyamcubr.ino b/tasmota/tasmota_xdrv_driver/xdrv_65_tuyamcubr.ino index 8b5dc9e07..48697e41e 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_65_tuyamcubr.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_65_tuyamcubr.ino @@ -1007,6 +1007,22 @@ tuyamcubr_loop(struct tuyamcubr_softc *sc) * Interface */ +#ifdef USE_WEBSERVER +static void +tuyamcubr_web_sensor(struct tuyamcubr_softc *sc) +{ + struct tuyamcubr_dp *dp; + const struct tuyamcubr_data_type *dt; + + STAILQ_FOREACH(dp, &sc->sc_dps, dp_entry) { + dt = &tuyamcubr_data_types[dp->dp_type]; + + WSContentSend_PD(PSTR("{s}%s%u{m}%u{e}"), + dt->t_name, dp->dp_id, dp->dp_value); + } +} +#endif // USE_WEBSERVER + static const char tuyamcubr_cmnd_names[] PROGMEM = D_CMND_TUYAMCUBR_PREFIX "|" D_CMND_TUYAMCUBR_DATA_BOOL @@ -1067,6 +1083,13 @@ Xdrv65(uint32_t function) case FUNC_AFTER_TELEPERIOD: tuyamcubr_publish(sc); break; +#ifdef USE_WEBSERVER + case FUNC_WEB_ADD_MAIN_BUTTON: + break; + case FUNC_WEB_SENSOR: + tuyamcubr_web_sensor(sc); + break; +#endif // USE_WEBSERVER case FUNC_COMMAND: result = DecodeCommand(tuyamcubr_cmnd_names, tuyamcubr_cmnds); From 95dee75b0b52f269272e8a2c45123a73ef8fba45 Mon Sep 17 00:00:00 2001 From: Barbudor Date: Tue, 24 Jan 2023 08:55:44 +0100 Subject: [PATCH 169/262] use dB value, not quality (#17777) --- tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v1.ino | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v1.ino b/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v1.ino index 6013fef3e..3f90044b9 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v1.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v1.ino @@ -1427,10 +1427,9 @@ void TuyaSetWifiStrength(void) { uint16_t payload_len = 1; uint8_t payload_buffer[1]; int32_t rssi = WiFi.RSSI(); - int signal_strength = WifiGetRssiAsQuality(rssi); + payload_buffer[0] = (uint8_t)rssi; - AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: RX MCU Get Wifi Strength -> sending %d"), signal_strength); - payload_buffer[0] = (uint8_t)signal_strength; + AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: RX MCU Get Wifi Strength -> sending %d (0x%02X)"), rssi, payload_buffer[0]); TuyaSendCmd(TUYA_CMD_GET_WIFI_STRENGTH, payload_buffer, payload_len); } From 17a969dcc86b910ba7e5b5b145b98e7178af9dd5 Mon Sep 17 00:00:00 2001 From: LenaWil Date: Tue, 24 Jan 2023 08:58:31 +0100 Subject: [PATCH 170/262] Add dark mode logo (#17780) * Add dark mode logo * Remove st from readme Typo? --- README.md | 6 +++--- tools/logo/TASMOTA_FullLogo_Vector_White.svg | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 tools/logo/TASMOTA_FullLogo_Vector_White.svg diff --git a/README.md b/README.md index 11c447a81..ed2169f14 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![Tasmota logo](/tools/logo/TASMOTA_FullLogo_Vector.svg) +![Tasmota logo](/tools/logo/TASMOTA_FullLogo_Vector.svg#gh-light-mode-only)![Tasmota logo](/tools/logo/TASMOTA_FullLogo_Vector_White.svg#gh-dark-mode-only) Alternative firmware for [ESP8266](https://en.wikipedia.org/wiki/ESP8266) and [ESP32](https://en.wikipedia.org/wiki/ESP32) based devices with **easy configuration using webUI, OTA updates, automation using timers or rules, expandability and entirely local control over MQTT, HTTP, Serial or KNX**. _Written for PlatformIO._ @@ -47,7 +47,7 @@ Note that there is a chance, as with any upgrade, that the device may not functi ## Disclaimer -st:warning: **DANGER OF ELECTROCUTION** :warning: +:warning: **DANGER OF ELECTROCUTION** :warning: If your device connects to mains electricity (AC power) there is danger of electrocution if not installed properly. If you don't know how to install it, please call an electrician (***Beware:*** certain countries prohibit installation without a licensed electrician present). Remember: _**SAFETY FIRST**_. It is not worth the risk to yourself, your family and your home if you don't know exactly what you are doing. Never tinker or try to flash a device using the serial programming interface while it is connected to MAINS ELECTRICITY (AC power). @@ -172,4 +172,4 @@ People helping to keep the show on the road: ## License -This program is licensed under GPL-3.0 \ No newline at end of file +This program is licensed under GPL-3.0 diff --git a/tools/logo/TASMOTA_FullLogo_Vector_White.svg b/tools/logo/TASMOTA_FullLogo_Vector_White.svg new file mode 100644 index 000000000..0e5528acb --- /dev/null +++ b/tools/logo/TASMOTA_FullLogo_Vector_White.svg @@ -0,0 +1 @@ +Zeichenfläche 1 \ No newline at end of file From f0bd418129109baf5bc305bac6b194183de39c7c Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Tue, 24 Jan 2023 10:19:46 +0100 Subject: [PATCH 171/262] Dark logo --- FIRMWARE.md | 2 +- RELEASENOTES.md | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/FIRMWARE.md b/FIRMWARE.md index e7ea33291..7eb36c82b 100644 --- a/FIRMWARE.md +++ b/FIRMWARE.md @@ -1,4 +1,4 @@ -![Tasmota logo](https://github.com/arendst/Tasmota/blob/development/tools/logo/TASMOTA_FullLogo_Vector.svg) +![Tasmota logo](/tools/logo/TASMOTA_FullLogo_Vector.svg#gh-light-mode-only)![Tasmota logo](/tools/logo/TASMOTA_FullLogo_Vector_White.svg#gh-dark-mode-only) Alternative firmware for [ESP8266](https://en.wikipedia.org/wiki/ESP8266) based devices with **easy configuration using webUI, OTA updates, automation using timers or rules, expandability and entirely local control over MQTT, HTTP, Serial or KNX**. _Written for PlatformIO with limited support for Arduino IDE._ diff --git a/RELEASENOTES.md b/RELEASENOTES.md index a35c8136a..40223ad6f 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,4 +1,7 @@ -Logo + + + Logo + # RELEASE NOTES From 5d98b8e05afa71e74b8bd128e4015d8fe152ec45 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Tue, 24 Jan 2023 10:27:47 +0100 Subject: [PATCH 172/262] Update RELEASENOTES.md --- RELEASENOTES.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 40223ad6f..a7a9175de 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,6 +1,6 @@ - - Logo + + Logo # RELEASE NOTES From 36c8ae98da6f706b07f72aebd8dd1b770ca94cb3 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Tue, 24 Jan 2023 10:48:38 +0100 Subject: [PATCH 173/262] Add dark theme logo --- API.md | 5 ++- CODE_OWNERS.md | 5 ++- CONTRIBUTING.md | 5 ++- TEMPLATES-PRE9.md | 5 ++- TEMPLATES.md | 81 ++++++++++++++++++++++-------------- tools/templates/templates.py | 5 ++- 6 files changed, 69 insertions(+), 37 deletions(-) diff --git a/API.md b/API.md index 9e5d51a5b..3a7a24c78 100644 --- a/API.md +++ b/API.md @@ -1,4 +1,7 @@ -Logo + + + Logo + # Basic API information diff --git a/CODE_OWNERS.md b/CODE_OWNERS.md index b5c0577fc..37851c86d 100644 --- a/CODE_OWNERS.md +++ b/CODE_OWNERS.md @@ -1,4 +1,7 @@ -Logo + + + Logo + # Code Owners diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8a2d4afc5..7b15232be 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,4 +1,7 @@ -Logo + + + Logo + # Contributing diff --git a/TEMPLATES-PRE9.md b/TEMPLATES-PRE9.md index eb1e997eb..194723c9f 100644 --- a/TEMPLATES-PRE9.md +++ b/TEMPLATES-PRE9.md @@ -1,4 +1,7 @@ -Logo + + + Logo + # Templates diff --git a/TEMPLATES.md b/TEMPLATES.md index 7d2b90617..a3e22fdc5 100644 --- a/TEMPLATES.md +++ b/TEMPLATES.md @@ -1,8 +1,11 @@ -Logo + + + Logo + # Templates -Find below the available templates as of December 2022. More template information can be found in the [Tasmota Device Templates Repository](http://blakadder.github.io/templates) +Find below the available templates as of January 2023. More template information can be found in the [Tasmota Device Templates Repository](http://blakadder.github.io/templates) ## Adapter Board ``` @@ -21,6 +24,7 @@ Kogan 5-Stage 3S {"NAME":"Kogan Air Purifier 3S","GPIO":[0,2272,0,23 ## Air Quality Sensor ``` AirGradient Pro Version DIY {"NAME":"AirGradient Pro","GPIO":[1600,1,1632,0,640,608,1,1,1664,1,1696,1,1,1],"FLAG":0,"BASE":18} +Tuya PM Box {"NAME":"PM Box","GPIO":[1,1,1,1,1,1,0,0,1,1,1,1,1,0],"FLAG":0,"BASE":54,"CMND":"TuyaMCU 99,91 | TuyaMCU 71,2 | TuyaMCU 73,3 | HumRes 1 | TempRes 1 "} ``` ## Aroma Diffuser @@ -46,6 +50,7 @@ GL.iNet POE Ethernet {"NAME":"GL-S10 v1.0","GPIO":[32,0,0,0,0,0,0,0,321, ## CCT ``` +3W KLG 320lm {"NAME":"3W_KLG","GPIO":[0,0,0,0,416,419,0,0,417,0,418,0,0,0],"FLAG":0,"BASE":18} AICase 800lm {"NAME":"AICase Smart L","GPIO":[0,0,0,0,0,416,0,0,0,417,0,0,0,0],"FLAG":0,"BASE":18} AiYaTo 12W {"NAME":"AiYaTo-CW","GPIO":[0,0,0,0,416,0,0,0,0,417,0,0,0,0],"FLAG":0,"BASE":18} Ajax Online 380lm {"NAME":"AjaxOnline","GPIO":[32,0,0,0,0,416,0,0,417,0,0,0,0,0],"FLAG":0,"BASE":38} @@ -395,9 +400,9 @@ CE Smart Home CFW500D-3W 3 Way {"NAME":"CE-WF500D-3W","GPIO":[0,0,0,0,0,0,0,0,0 CNSKOU Touch {"NAME":"CNSKOU Dimmer Switch","GPIO":[0,0,0,0,0,0,0,0,0,0,290,0,0,0],"FLAG":0,"BASE":54} Eva Logik {"NAME":"WF31 Dimmer","GPIO":[1,2272,1,2304,1,1,0,0,1,1,1,1,1,0],"FLAG":0,"BASE":54} Eva Logik 3 Way {"NAME":"EL WF31T","GPIO":[1,2272,1,2304,1,1,0,0,1,1,1,1,1,0],"FLAG":0,"BASE":54} -Feit Electric Smart {"NAME":"Feit DIM/WIFI","GPIO":[1,2272,1,2304,1,1,0,0,1,0,1,0,1,0],"FLAG":0,"BASE":54} +Feit Electric Smart {"NAME":"Feit DIM/WIFI","GPIO":[0,2272,0,2304,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54} Globe 3 Way {"NAME":"Globe Dimmer","GPIO":[0,2272,0,2304,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54} -Gosund SW2 {"NAME":"Gosund Dimmer","GPIO":[1,3200,1,3232,32,0,1,1,320,576,416,1,1,0],"FLAG":0,"BASE":18} +Gosund {"NAME":"Gosund Dimmer","GPIO":[1,3200,1,3232,32,0,1,1,320,576,416,1,1,0],"FLAG":0,"BASE":18} iLintek / Lumary {"NAME":"L-DS100","GPIO":[1,2272,1,2304,1,1,0,0,1,1,1,1,1,0],"FLAG":0,"BASE":54} iSwitch Touch Switch {"NAME":"iSwitchOZ Dimmer","GPIO":[0,0,0,0,0,0,0,0,0,0,290,0,0,0],"FLAG":0,"BASE":54} Martin Jerry SD01 {"NAME":"MJ-SD01 Dimmer","GPIO":[34,33,0,323,576,322,0,0,321,416,320,96,256,0],"FLAG":0,"BASE":73} @@ -528,7 +533,7 @@ Goldair SleepSmart GCPF315 {"NAME":"Goldair Fan","GPIO":[0,0,0,0,0,0,0,0,0,230 Holmes 36" Oscillating Tower {"NAME":"Generic","GPIO":[1,1,1,1,1,1,1,1,1,1,1,1,1,1],"FLAG":0,"BASE":54,"CMND":"TuyaMcu 11,1 | TuyaMcu 12,5 | WebButton1 Power | WebButton2 Oscillation "} Lucci Connect Remote Control {"NAME":"Lucci Fan","GPIO":[0,0,0,0,0,0,0,0,0,2304,0,2272,0,0],"FLAG":0,"BASE":54} QuietCool Gable Mount Attic {"NAME":"QuietCool-AFG-SMT-PRO-2.0","GPIO":[0,0,0,0,0,224,0,0,0,0,0,0,0,0,640,608,0,0,0,225,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":1,"CMND":"Interlock 1|WebButton1 Low|WebButton2 High|SO8 1"} -Sichler Haushaltsgeraete Column {"NAME":"Sichler Fan","GPIO":[0,2272,0,2304,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54} +Sichler Haushaltsger�te Column {"NAME":"Sichler Fan","GPIO":[0,2272,0,2304,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54} Technical Pro {"NAME":"FXA16 Fan","GPIO":[0,2272,0,2304,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54,"CMND":"TuyaMCU 12,8"} Zemismart Bladeless {"NAME":"Bladeless Fan","GPIO":[1,2272,1,2304,1,1,0,0,1,1,1,1,1,0],"FLAG":0,"BASE":54} ``` @@ -691,7 +696,9 @@ ZJ-WF-ESP-A v1.1 {"NAME":"RGB2","GPIO":[0,0,0,0,0,0,0,0,417,416,418, ## LED Strip ``` Aldi Casalux RGB {"NAME":"DW-RGB-WI01","GPIO":[1088,0,0,0,416,0,0,0,417,0,418,0,0,0],"FLAG":0,"BASE":18} +Arlec Smart 1m CCT LED Strip Light {"NAME":"ALD155HA","GPIO":[0,0,1088,0,0,416,0,0,0,417,0,0,0,0],"FLAG":0,"BASE":18} Arlec Smart 2m LED Colour Changing Strip Light {"NAME":"Arlec_Light_Strip","GPIO":[1,1,1088,1,416,419,1,1,417,420,418,0,1,1],"FLAG":0,"BASE":18} +Arlec Smart 5m White & Colour Changing {"NAME":"ALD556HA","GPIO":[0,0,1088,0,416,419,0,0,417,420,418,0,0,0],"FLAG":0,"BASE":18} B.K. Licht 2m RGB {"NAME":"RGBW-Strip","GPIO":[0,0,0,0,416,32,0,0,417,0,418,0,0,0],"FLAG":0,"BASE":18} BAZZ 10 ft RGBW {"NAME":"BAZZ U183MRGBWWF RGBW LED Strip","GPIO":[32,0,0,0,416,419,0,0,417,0,418,0,0,0],"FLAG":0,"BASE":18} BlitzWolf BW-LT11 {"NAME":"BW-LT11 Strip","GPIO":[32,0,0,0,416,419,0,0,417,0,418,0,0,0],"FLAG":0,"BASE":18} @@ -771,7 +778,7 @@ BrilliantSmart RGB Garden Kit {"NAME":"Brilliant Gard","GPIO":[0,0,0,0,416,0,0, Connect SmartHome CSH-FSTN12 {"NAME":"CSH-FSTN12","GPIO":[0,0,0,0,416,0,0,0,417,0,418,0,0,0],"FLAG":0,"BASE":18} Deta 18W 1900lm T8 Tube {"NAME":"DETA Smart LED","GPIO":[0,0,0,0,0,0,0,0,0,0,416,0,0,0],"FLAG":0,"BASE":18} electriQ MOODL Ambiance Lamp {"NAME":"ElectriQ MOODL","GPIO":[0,4640,0,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18} -Gosund Table Lamp {"NAME":"Gosund LED Light","GPIO":[0,0,0,0,0,418,0,0,417,419,0,416,0,0],"FLAG":0,"BASE":18} +Gosund Table Lamp {"NAME":"Gosund LB3","GPIO":[0,0,0,0,0,418,0,0,417,419,0,416,0,0],"FLAG":0,"BASE":18} Hama Wall Light Square, 10 cm, IP 44 {"NAME":"Hama Wifi Wall Light","GPIO":[0,0,0,0,0,416,0,0,0,417,0,0,0,1],"FLAG":0,"BASE":18} Hugoai Table Lamp {"NAME":"HG02","GPIO":[1,1,1,1,1,1,0,0,1,1,1,1,1,0],"FLAG":0,"BASE":54,"CMND":"TuyaMCU 11,20 | TuyaMCU 26,21 | TuyaMCU 21,22 | TuyaMCU 23,23 | TuyaMCU 24,24 | DimmerRange 34,1000"} Iwoole Table Lamp {"NAME":"GLOBELAMP","GPIO":[0,0,0,0,419,0,0,0,417,418,416,0,0,0],"FLAG":0,"BASE":18} @@ -824,7 +831,7 @@ Kogan Pet Fountain {"NAME":"Pet Fountain","GPIO":[0,2272,0,2304,0,0,0, LED Starry Sky Projector Light {"NAME":"STAR PROJECTOR","GPIO":[0,0,0,0,416,0,0,0,417,0,418,0,0,0],"FLAG":0,"BASE":18} Liectroux C30B Robot Vacuum {"NAME":"Liectroux C30B","GPIO":[1,1,1,1,1,1,0,0,1,1,1,1,1,0],"FLAG":0,"BASE":54} Mosquito Killer Lamp {"NAME":"MosquitoKiller","GPIO":[32,0,0,0,0,0,0,0,416,320,0,0,0,0],"FLAG":0,"BASE":18} -NEO Coolcam Mouse Trap {"NAME":"Neo Mouse Trap","GPIO":[1,2272,1,2304,1,1,0,0,1,1,1,1,1,0],"FLAG":0,"BASE":54} +NEO Coolcam Mouse Trap {"NAME":"NAS-MA01W","GPIO":[1,1,1,1,1,1,0,0,1,1,1,1,1,0],"FLAG":0,"BASE":54,"CMND":"TuyaMCU 51,51 | TuyaMCU 99,11"} PCI-e Desktop PC Remote Control {"NAME":"PC-Switch-01","GPIO":[32,0,0,0,0,0,0,0,224,544,0,0,0,0],"FLAG":0,"BASE":18} Petoneer Smart Dot Cat Toy {"NAME":"Petoneer Smart Dot","GPIO":[0,2272,0,2304,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54} Proscenic T21 Air Fryer {"NAME":"Proscenic T21","GPIO":[0,2272,0,2304,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54} @@ -853,11 +860,6 @@ Sinilink MODBUS Interface {"NAME":"XY-WFPOW","GPIO":[0,8768,544,8800,32,0,0,0 TYWE2S Replacement {"NAME":"ESP-02S","GPIO":[1,1,1,1,1,1,0,0,1,1,1,0,0,1],"FLAG":0,"BASE":18} ``` -## Module Switch -``` -Moes Mini 3 Gang 1/2 Way {"NAME":"Moes MS-104C","GPIO":[0,0,0,34,32,33,0,0,224,225,226,0,0,0],"FLAG":0,"BASE":18} -``` - ## Motion Sensor ``` DP-WP001 PIR {"NAME":"TUYA PIR","GPIO":[1,2272,1,2304,1,1,0,0,1,1,1,1,1,0],"FLAG":0,"BASE":54} @@ -1053,6 +1055,7 @@ BAW {"NAME":"BAW TPSWIFI-10","GPIO":[0,0,0,0,320,0,0,0, Bawoo {"NAME":"Bawoo S120","GPIO":[0,0,0,0,288,0,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18} Be HiTech 16A {"NAME":"Be HiTech","GPIO":[0,0,0,288,0,2720,0,0,2624,32,2656,224,0,0],"FLAG":0,"BASE":18} Bearware 303492 3AC+2USB {"NAME":"Bearware 30349","GPIO":[0,320,0,32,225,226,0,0,227,224,544,0,0,0],"FLAG":0,"BASE":18} +Beghelli Dom-e Presa Smart IT {"NAME":"Beghelli DOM-E Smart Plug","GPIO":[32,0,0,0,2720,2656,0,0,2624,544,224,0,0,0],"FLAG":0,"BASE":18} Bestek MRJ1011 {"NAME":"BestekMRJ1011","GPIO":[0,0,0,0,320,0,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":1} BlitzWolf 1200W Dual {"NAME":"BlitzWolf SHP3","GPIO":[320,0,321,0,225,2720,0,0,2624,33,2656,224,32,0],"FLAG":0,"BASE":45} BlitzWolf 16A Dual {"NAME":"SHP7 v2","GPIO":[33,576,320,2624,2720,2656,0,0,32,321,224,0,225,0],"FLAG":0,"BASE":45} @@ -1106,6 +1109,8 @@ Coosa SP1 {"NAME":"COOSA SP1","GPIO":[321,1,320,1,0,2720,0,0, CooWoo {"NAME":"CooWoo AW01","GPIO":[0,0,0,0,288,160,0,0,256,0,0,0,0,0],"FLAG":0,"BASE":18} CozyLife HomeKit 16A {"NAME":"CozyLife 16A","GPIO":[0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,2720,0,0,2656,576,0,224,2624,0,0,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":1} CrazyLynX WiFi {"NAME":"CrazyLynX","GPIO":[0,0,0,0,321,320,0,0,224,32,0,0,0,4704],"FLAG":0,"BASE":18} +CurrySmarter 16A {"NAME":"CurrySmarter 16A","GPIO":[0,0,0,32,0,0,0,0,0,320,224,0,0,0],"FLAG":0,"BASE":18} +CurrySmarter 16A Power Monitoring {"NAME":"Currysmarter XH-TW2P","GPIO":[0,0,0,2624,32,320,0,0,224,2720,2656,0,0,0],"FLAG":0,"BASE":18} CYYLTF BIFANS J23 {"NAME":"CYYLTD BIFANS J23","GPIO":[0,0,0,0,288,0,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18} CZ100 10A {"NAME":"ASZKJ","GPIO":[320,0,321,0,0,0,0,0,0,32,0,224,0,0],"FLAG":0,"BASE":18} D3D Smart Plug with USB & Power Monitor {"NAME":"D3D FLHS-ZN04","GPIO":[321,1,320,2624,1,2688,1,1,1,32,2656,224,1,1],"FLAG":0,"BASE":18} @@ -1187,13 +1192,13 @@ Globe Smart {"NAME":"GlobeSmartPlug","GPIO":[0,0,0,0,320,0,0,0, GoldenDot Mini {"NAME":"GoldenDot Mini","GPIO":[0,32,0,0,0,0,0,0,0,321,224,0,0,0],"FLAG":0,"BASE":52} GoldenDot with ADC {"NAME":"W-US003-Power","GPIO":[320,0,0,0,0,0,0,0,0,32,0,224,0,4896],"FLAG":0,"BASE":18} Goliath 16A {"NAME":"GOLIATH AV-SSTE01","GPIO":[0,0,320,0,0,0,0,0,0,32,0,224,0,0],"FLAG":0,"BASE":18} -Gosund {"NAME":"Gosund EP2","GPIO":[320,1,576,1,2656,2720,0,0,2624,32,0,224,0,0],"FLAG":0,"BASE":45} +Gosund {"NAME":"Gosund EP2","GPIO":[576,1,320,1,2656,2720,0,0,2624,32,0,224,0,0],"FLAG":0,"BASE":45} +Gosund {"NAME":"Gosund SP111","GPIO":[320,0,321,0,0,2720,0,0,2624,32,2656,224,0,0],"FLAG":0,"BASE":18} Gosund {"NAME":"SHP5","GPIO":[321,3072,320,3104,1,225,0,0,1,1,224,1,32,0],"FLAG":0,"BASE":18} Gosund 13A {"NAME":"Gosund UP111","GPIO":[0,320,0,32,2720,2656,0,0,2624,576,224,0,0,0],"FLAG":0,"BASE":18} Gosund 2 in 1 {"NAME":"Gosund WP212","GPIO":[321,288,544,0,224,2720,0,0,2624,32,2656,225,33,0],"FLAG":0,"BASE":18} Gosund Dual {"NAME":"Gosund SP211","GPIO":[33,576,320,2624,2720,2656,0,0,32,321,224,0,225,0],"FLAG":0,"BASE":18} Gosund SP1 {"NAME":"Gosund SP1 v23","GPIO":[0,321,0,32,2720,2656,0,0,2624,320,224,0,0,0],"FLAG":0,"BASE":55} -Gosund SP111 {"NAME":"Gosund SP111","GPIO":[320,0,321,0,0,2720,0,0,2624,32,2656,224,0,0],"FLAG":0,"BASE":18} Gosund SP111 v1.1 {"NAME":"Gosund SP111 v1.1","GPIO":[320,0,576,0,2656,2720,0,0,2624,32,0,224,0,0],"FLAG":0,"BASE":45} Gosund SP111 v1.4 {"NAME":"Gosund SP111 v1.4","GPIO":[321,1,320,1,0,2720,0,0,2624,32,2656,224,0,0],"FLAG":0,"BASE":45} Gosund SP112 {"NAME":"Gosund 112v3.4","GPIO":[320,0,321,0,2656,2720,0,0,2624,257,224,0,0,4800],"FLAG":0,"BASE":18} @@ -1224,10 +1229,12 @@ HiHome {"NAME":"HiHome WPP-10S","GPIO":[32,0,0,0,2720,2656 HiHome {"NAME":"HIhome WPP-10S","GPIO":[320,0,576,1,0,2720,0,0,2624,32,2656,224,0,0],"FLAG":0,"BASE":49} HiHome {"NAME":"HiHome WPP-16T","GPIO":[32,320,1,1,2720,2656,0,0,33,1,225,2592,224,4704],"FLAG":0,"BASE":18} HIPER IoT P01 {"NAME":"HIPER IoT P01","GPIO":[0,0,0,0,0,320,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18} +HIPER IoT P05 {"NAME":"HIPER IoT P05","GPIO":[0,320,0,32,0,0,0,0,0,224,0,0,0,0],"FLAG":0,"BASE":18} hiwild W-US002 {"NAME":"W-US002","GPIO":[0,32,0,0,0,0,0,0,0,288,224,0,576,0],"FLAG":0,"BASE":18} HLT-309 {"NAME":"HLT-309","GPIO":[0,0,0,0,0,0,0,0,0,32,0,224,0,0],"FLAG":0,"BASE":18} Hoin 10A {"NAME":"NIOH XS-SSC01","GPIO":[0,32,0,0,0,0,0,0,0,320,224,0,0,0],"FLAG":0,"BASE":18} Hombli Socket Duo {"NAME":"HombliSocketDuo","GPIO":[33,0,0,0,0,0,0,0,0,544,224,225,32,0],"FLAG":0,"BASE":18} +Homecube {"NAME":"Homecube SP1","GPIO":[0,321,0,32,2720,2656,0,0,2624,320,224,0,0,0],"FLAG":0,"BASE":55} HomeMate 16A Heavy Duty {"NAME":"HMLPG16","GPIO":[0,288,0,32,2720,2656,0,0,2624,544,224,0,0,0],"FLAG":0,"BASE":18} Houzetek {"NAME":"AWP07L","GPIO":[320,0,0,0,0,2720,0,0,2624,32,2656,224,0,0],"FLAG":0,"BASE":18} HS108 {"NAME":"HS108","GPIO":[0,32,0,0,0,0,0,0,0,320,224,0,0,4704],"FLAG":0,"BASE":18} @@ -1318,11 +1325,12 @@ Luminea ZX-2820 {"NAME":"ZX2820-675","GPIO":[0,0,0,32,2688,2656,0,0 Luminea ZX-2858 {"NAME":"ZX2858-675","GPIO":[32,0,0,0,2688,2656,0,0,2624,320,224,0,0,0],"FLAG":0,"BASE":65} Lunvon 2000W {"NAME":"Lunvon Smart Plug","GPIO":[32,0,0,0,0,0,288,224,0,0,0,0,0,0],"FLAG":0,"BASE":18} Lunvon 3000W {"NAME":"Lunvon Smart Plug","GPIO":[32,0,0,0,0,0,288,224,0,0,0,0,0,0],"FLAG":0,"BASE":18} +Marmitek Power SI {"NAME":"Marmitek PowerSi","GPIO":[0,0,0,32,2720,0,0,0,0,288,224,0,0,0],"FLAG":0,"BASE":18} Martin Jerry V01 {"NAME":"MJ V01","GPIO":[0,0,0,0,320,0,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18} Martin Jerry XS-SSA01 {"NAME":"MJ_XS-SSA01","GPIO":[0,32,0,0,0,0,0,0,0,320,224,0,0,0],"FLAG":0,"BASE":18} Maxcio 16A Mini {"NAME":"MAXCIO RMC021","GPIO":[0,0,0,32,2720,2656,0,0,2624,544,224,0,0,0],"FLAG":0,"BASE":1} Maxcio W-UK007S {"NAME":"Maxcio","GPIO":[320,0,1,0,0,2720,0,0,2624,32,2656,224,0,0],"FLAG":0,"BASE":45} -Maxcio W-US002S {"NAME":"W-US002S","GPIO":[321,0,320,0,0,2720,0,0,2624,32,2656,224,0,0],"FLAG":0,"BASE":45} +Maxcio W-US002S {"NAME":"W-US002S","GPIO":[0,32,0,544,2688,2656,0,0,2592,288,224,0,0,0],"FLAG":0,"BASE":18} Maxcio W-US003 {"NAME":"W-US003","GPIO":[1,32,1,1,1,1,0,0,1,225,224,1,1,0],"FLAG":0,"BASE":18} Maxcio YX-DE02 {"NAME":"Maxcio DE02","GPIO":[0,32,0,224,320,225,0,0,416,417,418,0,0,0],"FLAG":0,"BASE":18} Maxcio YX-DE04 {"NAME":"Maxcio YX-DE04","GPIO":[1,32,1,224,320,419,0,0,416,417,418,1,1,4704],"FLAG":0,"BASE":18} @@ -1408,6 +1416,7 @@ PrimeCables {"NAME":"CAB-LA-WF4","GPIO":[0,0,0,320,321,0,0,0,0, PrimeCables 2 USB Mini {"NAME":"CAB-LA-WF4-G2","GPIO":[0,0,0,0,0,320,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18} Prokord {"NAME":"PSH-WS007-EU","GPIO":[0,0,320,1,0,2720,0,0,2624,32,2656,224,0,0],"FLAG":0,"BASE":45} Prokord 16A {"NAME":"PROKORD PSH-WS021-EU","GPIO":[0,0,320,0,0,0,0,0,0,32,0,224,0,0],"FLAG":0,"BASE":18} +QNCX {"NAME":"QNCX","GPIO":[0,0,0,32,2720,2656,0,0,2624,320,224,0,0,0],"FLAG":0,"BASE":18} Qnect 16A {"NAME":"Qnect QN-WP01","GPIO":[0,0,0,0,0,224,0,0,288,0,32,0,0,0],"FLAG":0,"BASE":18} qnect 16A {"NAME":"QNECT QN-WP01E","GPIO":[0,0,0,32,2688,2656,0,0,2624,288,224,0,0,0],"FLAG":0,"BASE":18} Qualitel Mini {"NAME":"Qualitel HG01WT","GPIO":[320,0,321,0,0,2688,0,0,2624,32,2656,224,0,0],"FLAG":0,"BASE":18} @@ -1523,6 +1532,7 @@ Vettora Smart Plug {"NAME":"Vettora","GPIO":[0,0,0,32,0,0,0,0,0,320,22 Vingo {"NAME":"Karpal-01","GPIO":[0,0,0,0,0,320,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18} Vivanco 39625 Smart Home Power Adapter {"NAME":"Vivianco","GPIO":[0,0,0,32,2688,2656,0,0,2624,288,224,0,0,0],"FLAG":0,"BASE":18} Vivitar {"NAME":"Vivitar HA1003","GPIO":[576,0,320,0,0,0,0,0,0,32,0,224,0,0],"FLAG":0,"BASE":18} +Vivitar {"NAME":"Vivitar HA1004","GPIO":[576,0,0,0,0,320,0,0,224,0,0,0,0,0],"FLAG":0,"BASE":18} Vivitar HA-1006 {"NAME":"HA-1006","GPIO":[0,0,0,0,320,0,0,0,224,64,0,0,0,0],"FLAG":0,"BASE":18} Vivitar HA-1006-AU {"NAME":"HA-1006-AU","GPIO":[0,0,0,0,320,0,0,0,224,64,0,0,0,0],"FLAG":0,"BASE":18} Vivitar Plug {"NAME":"HA-1005N-AU","GPIO":[0,0,0,0,544,0,0,0,224,64,0,0,0,0],"FLAG":0,"BASE":18} @@ -1541,6 +1551,7 @@ Wipro 16A {"NAME":"Wip-DSP1160","GPIO":[0,0,0,32,2720,2656,0, Wisdom Dual {"NAME":"ZY-ACU02","GPIO":[0,0,0,544,225,224,0,0,320,32,321,0,0,0],"FLAG":0,"BASE":18} WiZ 10A {"NAME":"WIZ 9290024276","GPIO":[0,0,0,0,544,320,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18} WL-SC01 {"NAME":"WL-SC01","GPIO":[0,0,0,0,320,0,0,0,224,0,32,0,0,0],"FLAG":0,"BASE":1} +Woox EU {"NAME":"WOOX R6113","GPIO":[0,2624,0,320,32,289,0,0,2656,224,2720,0,0,0],"FLAG":0,"BASE":18} WOOX R4026 {"NAME":"WOOX R4026","GPIO":[0,0,0,32,0,0,0,0,0,320,224,0,0,0],"FLAG":0,"BASE":18} WOOX R4785 {"NAME":"WOOXR4785","GPIO":[0,0,0,0,288,224,0,0,0,32,0,0,0,0],"FLAG":0,"BASE":18} WOOX R5024 {"NAME":"WOOX5024","GPIO":[0,0,320,0,0,0,0,0,0,32,0,224,0,0],"FLAG":0,"BASE":18} @@ -1614,7 +1625,7 @@ Calex 4AC 2USB {"NAME":"Calex Power Strip 429228","GPIO":[0,320,0, Calex 4AC 4USB {"NAME":"Calex Power Strip 429228","GPIO":[0,0,0,288,224,226,0,0,0,228,227,225,32,0],"FLAG":0,"BASE":18} CE Smart Home {"NAME":"CE Power Strip","GPIO":[288,0,0,0,227,228,0,0,225,226,224,0,32,0],"FLAG":0,"BASE":18} CE Smart Home Garden Stake {"NAME":"CE Power Stake","GPIO":[0,0,0,0,320,321,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18} -CRST LTS-4G-W {"NAME":"CRST LTS-4G-W","GPIO":[0,0,0,0,227,0,0,0,225,226,224,0,0,0],"FLAG":0,"BASE":18} +CRST LTS-4G-W {"NAME":"CRST LTS-4G-W","GPIO":[544,0,0,0,227,32,0,0,225,226,224,0,0,0],"FLAG":0,"BASE":18} Curv 4 Plug {"NAME":"CURV","GPIO":[0,32,0,228,0,0,1,1,227,225,226,224,0,1],"FLAG":0,"BASE":18} Deltaco SH-P03USB {"NAME":"Deltaco SH-P03","GPIO":[320,0,0,0,0,226,0,0,224,32,225,227,0,0],"FLAG":0,"BASE":18} Digma DiPlug Strip 40 {"NAME":"DiPlug Strip 40","GPIO":[1,320,1,32,225,224,1,1,226,227,260,1,1,1],"FLAG":0,"BASE":18} @@ -1646,6 +1657,7 @@ Idinio 3AC 4USB {"NAME":"Idinio-140135","GPIO":[0,320,0,32,225,224, Jinvoo 4AC+2USB {"NAME":"JINVOO Model SM-SO306-2A","GPIO":[320,0,0,0,259,32,0,0,257,258,256,0,228,0],"FLAG":0,"BASE":18} KaBuM! Filtro de Linha {"NAME":"Kabum Power Strip","GPIO":[0,544,0,32,227,228,0,0,0,225,226,224,320,0],"FLAG":0,"BASE":18} KMC 5AC 3USB QC {"NAME":"KMC 5-Outlet","GPIO":[320,0,0,0,228,160,0,0,225,224,226,0,227,0],"FLAG":0,"BASE":18} +KMC Smart Strip 3 {"NAME":"KMC 3-Outlet (20307)","GPIO":[0,320,0,32,0,226,0,0,224,0,225,0,0,0],"FLAG":0,"BASE":18} Kogan Power Strip USB Ports & Energy Meter {"NAME":"Generic","GPIO":[64,320,0,227,2720,2656,0,0,2624,225,226,224,0,0],"FLAG":0,"BASE":18} Konesky Type 1 {"NAME":"Konesky","GPIO":[0,0,0,0,228,225,0,0,227,32,226,224,0,0],"FLAG":0,"BASE":18} Koogeek KLOE4 {"NAME":"Koogeek KLOE4","GPIO":[0,320,0,32,225,224,0,0,226,227,228,0,0,4704],"FLAG":0,"BASE":18} @@ -1680,7 +1692,7 @@ Surge Protector 3AC 2USB {"NAME":"C158","GPIO":[260,0,0,0,261,230,0,0,224,0, SWB1 {"NAME":"SWB1","GPIO":[288,0,0,0,0,227,0,0,224,32,225,226,0,0],"FLAG":0,"BASE":18} SWB2 3AC + 2USB {"NAME":"SWB2","GPIO":[576,1,0,1,0,226,0,0,224,32,225,227,0,0],"FLAG":0,"BASE":18} Swisstone 4AC 4USB {"NAME":"Swisstone SH140","GPIO":[0,576,0,32,225,224,0,0,226,227,228,0,0,0],"FLAG":0,"BASE":18} -Sygonix 4AC {"NAME":"Sygonix SY-4538254","GPIO":[576,32,0,231,229,230,0,0,225,224,226,228,259,0],"FLAG":0,"BASE":18} +Sygonix 4AC {"NAME":"Sygonix SY-4538254","GPIO":[544,32,0,8678,8676,8679,0,0,8672,8673,8675,8677,8706,0],"FLAG":0,"BASE":18} TCP Smart 4AC+USB {"NAME":"TCP WPS4WUK","GPIO":[1,320,0,32,226,227,0,0,225,224,228,0,0,1],"FLAG":0,"BASE":18} Teckin SS30 {"NAME":"Teckin SS30","GPIO":[288,1,1,321,256,32,0,0,258,257,259,1,228,0],"FLAG":0,"BASE":18} Tellur 3AC 4USB {"NAME":"Tellur","GPIO":[0,320,0,32,225,224,0,0,0,226,227,0,0,4704],"FLAG":0,"BASE":18} @@ -1939,6 +1951,7 @@ cod.m WLAN Pixel Controller v0.8 {"NAME":"cod.m Pixel Controller V0.8","GPIO":[ ESP01 NeoPixel Ring {"NAME":"ESP-01S-RGB-LED-v1.0","GPIO":[1,1,1376,1,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18} H803WF 2048 Pixel 5V-24V {"NAME":"H803WF","GPIO":[0,0,0,0,3840,3840,0,0,3872,1376,0,3872,0,0],"FLAG":0,"BASE":18} IOTMCU {"NAME":"IOTMCU_ESP-12S-RGB-LED-v1","GPIO":[1,1,1,1,0,1376,0,0,1,1088,32,0,0,0],"FLAG":0,"BASE":18} +LifeSmart Cololight PRO Hexagonal {"NAME":"Cololight PRO","GPIO":[0,0,0,0,32,0,0,0,0,33,0,0,1376,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4704,0,0,0,0,0,0],"FLAG":0,"BASE":1} SP501E WS2812B {"NAME":"SP501E","GPIO":[0,32,0,1376,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18} ``` @@ -2122,11 +2135,6 @@ Zemismart A19 10W {"NAME":"Zemism_E27_A19","GPIO":[0,0,0,0,0,0,0,0,0, Zilotek A19 800lm {"NAME":"Zilotek RGBW","GPIO":[0,0,0,0,2912,416,0,0,417,2976,2944,0,0,0],"FLAG":0,"BASE":18} ``` -## Relay -``` -LilyGo T-Relay 8 {"NAME":"LilyGo ESP32 Relay 8","GPIO":[1,1,1,1,1,231,1,1,227,226,1,1,1,1,230,229,0,228,1,1,0,544,1,1,0,0,0,0,225,224,1,1,1,0,0,1],"FLAG":0,"BASE":1} -``` - ## Relay Board ``` 2 Channel Tuya {"NAME":"TY-DIY-S02","GPIO":[1,1,1,1,1,1,0,0,1,1,1,1,1,0],"FLAG":0,"BASE":54,"CMND":"TuyaMCU 11,1 | TuyaMCU 12,2 | TuyaMCU 13,13 | TuyaMCU 1,101"} @@ -2171,8 +2179,10 @@ LC Technology 5V/8-80V 1 Channel {"NAME":"LC-Relay-ESP12-1R-MV","GPIO":[1,1,544 LC Technology 5V/8-80V 1 Channel {"NAME":"LC-Relay-ESP12-1R-D8","GPIO":[1,1,544,1,1,224,1,1,1,1,1,1,321,1],"FLAG":0,"BASE":18} LC Technology AC90V-250V 1 Channel {"NAME":"ESP32_Relay_AC_X1","GPIO":[1,1,1,1,1,1,1,1,1,1,1,1,224,1,1,1,0,1,1,544,0,1,1,1,0,0,0,0,1,1,1,1,1,0,0,1],"FLAG":0,"BASE":1} LC Technology DC5-60V 1 Channel {"NAME":"ESP32_Relay_X1","GPIO":[1,1,1,1,1,1,1,1,1,1,1,1,224,1,1,1,0,1,1,544,0,1,1,1,0,0,0,0,1,1,1,1,1,0,0,1],"FLAG":0,"BASE":1} -LC Technology DC5-60V 4 Channel {"NAME":"ESP32_Relay_X4","GPIO":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,226,227,1,0,0,0,0,224,225,1,1,1,0,0,1],"FLAG":0,"BASE":1} +LC Technology DC5-60V 2 Channel {"NAME":"ESP32_Relay_X2","GPIO":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,544,0,225,224,0,0,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":1} +LC Technology DC5-60V 4 Channel {"NAME":"ESP32_Relay_X4","GPIO":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,544,0,226,227,1,0,0,0,0,224,225,1,1,1,0,0,1],"FLAG":0,"BASE":1} LC Technology ESP8266 5V {"NAME":"ESP8266-01S","GPIO":[224,3200,0,3232,0,0,0,0,0,0,0,0,0,4704],"FLAG":0,"BASE":18} +LilyGo T-Relay 8 {"NAME":"LilyGo ESP32 Relay 8","GPIO":[1,1,1,1,1,231,1,1,227,226,1,1,1,1,230,229,0,228,1,1,0,544,1,1,0,0,0,0,225,224,1,1,1,0,0,1],"FLAG":0,"BASE":1} LilyGO TTGO 4 Channel ESP32 {"NAME":"T-Relay ESP32","GPIO":[0,0,1,0,1,227,0,0,1,1,1,1,0,0,226,225,0,224,1,1,0,544,1,1,0,0,0,0,1,1,1,1,1,0,0,1],"FLAG":0,"BASE":1} LinkNode R4 {"NAME":"LinkNode R4","GPIO":[0,0,0,0,0,0,0,0,224,225,226,0,227,0],"FLAG":0,"BASE":18} LinkNode R8 {"NAME":"LinkNode R8","GPIO":[0,0,0,0,228,229,0,231,226,227,225,230,224,0],"FLAG":0,"BASE":18} @@ -2194,11 +2204,6 @@ Yunshan 7-30V 10A {"NAME":"Yunshan 10A","GPIO":[32,1,288,1,224,161,0, ## Relay Module ``` -2 CH Smart Switch {"NAME":"Generic","GPIO":[32,1,1,1,1,225,33,1,224,288,1,1,1,1],"FLAG":0,"BASE":18} -Aubess Power Monitor Switch 16A {"NAME":"Aubess with (BL0942)","GPIO":[0,3200,0,7520,0,0,0,0,0,0,224,0,0,0],"FLAG":0,"BASE":18} -Mini Smart Switch {"NAME":"SmartSwitch-MK601","GPIO":[0,0,0,160,32,224,0,0,0,0,288,0,0,0],"FLAG":0,"BASE":18} -Moes 10A {"NAME":"Moes MS-101","GPIO":[0,0,0,0,0,320,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18} -Smarsecur Smart Switch {"NAME":"ESP-02S","GPIO":[0,0,0,32,0,0,0,0,0,0,224,0,0,0],"FLAG":0,"BASE":18} ``` ## Sensor @@ -2242,7 +2247,7 @@ AGL 2 Gang {"NAME":"AGL WiFi 02","GPIO":[0,0,544,0,0,33,0,0,22 AGL 3 Gang {"NAME":"AGL WiFi 03","GPIO":[0,0,544,0,34,33,0,0,225,224,226,0,32,0],"FLAG":0,"BASE":18} Aoycocr SW1 {"NAME":"Aoycocr SW1","GPIO":[576,1,321,1,1,1,1,1,320,32,1,224,1,1],"FLAG":0,"BASE":18} APPIO 1 Gang Switch {"NAME":"Appio-9608","GPIO":[0,0,0,0,0,32,0,0,0,0,0,224,288,0],"FLAG":0,"BASE":18} -Appio 3 Gang Touch {"NAME":"Appio 9611","GPIO":[0,0,0,0,226,33,0,0,32,224,34,225,288,0],"FLAG":0,"BASE":18} +Appio 3 Gang Touch {"NAME":"Appio-9611","GPIO":[0,0,0,0,224,33,0,0,34,226,32,225,288,0],"FLAG":0,"BASE":18} Athom 1 Gang {"NAME":"Athom SW011EU","GPIO":[576,0,0,32,0,0,0,0,0,224,288,0,0,0],"FLAG":0,"BASE":1} Athom 1 Gang {"NAME":"Athom SW031US","GPIO":[576,0,0,32,0,0,0,0,0,224,288,0,0,0],"FLAG":0,"BASE":1} Athom 1 Gang No Neutral {"NAME":"Athom SW111EU","GPIO":[576,0,0,32,0,0,0,0,0,224,288,0,0,0],"FLAG":0,"BASE":1} @@ -2351,6 +2356,7 @@ Kuled KS602S {"NAME":"KULED","GPIO":[32,1,1,1,1,1,0,0,224,320,1, Kygne CD-301 {"NAME":"KYGNE Touch","GPIO":[0,0,0,0,288,289,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":10} Laghten SS02S {"NAME":"Laghten SS02S","GPIO":[0,0,0,0,288,321,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18} LCARE Modular 2 Gang {"NAME":"2SW1-In","GPIO":[32,1,1,1,0,225,33,0,224,320,0,0,0,0],"FLAG":0,"BASE":29} +LerLink 1 Gang {"NAME":"LerLink X801","GPIO":[0,0,0,0,32,0,0,0,224,320,0,0,0,1],"FLAG":0,"BASE":18} LerLink 1 Gang No Neutral {"NAME":"LerLink X801-L","GPIO":[0,0,0,0,32,0,0,0,224,320,0,0,0,1],"FLAG":0,"BASE":18} Lerlink 2 Gang {"NAME":"Lerlink X802A","GPIO":[0,0,0,33,32,0,0,0,224,288,225,0,0,0],"FLAG":0,"BASE":18} LerLink 2 Gang No Neutral {"NAME":"Lonsonho 2gang","GPIO":[0,0,0,33,32,0,0,0,224,288,225,0,0,0],"FLAG":0,"BASE":18} @@ -2422,6 +2428,7 @@ MoKo Scene Life {"NAME":"Moko Smart Swi","GPIO":[576,0,0,0,418,417, MoKo Smart Life {"NAME":"Moko Switch (Single)","GPIO":[544,0,0,32,224,0,0,0,0,0,320,0,0,0],"FLAG":0,"BASE":59} NaamaSmart KS602 {"NAME":"KS-602","GPIO":[32,0,0,0,0,0,0,0,224,576,0,0,0,0],"FLAG":0,"BASE":18} Nedis Dual {"NAME":"SM-SW102U-2","GPIO":[576,0,0,33,225,0,0,0,32,224,0,0,0,4704],"FLAG":0,"BASE":18} +NEO Coolcam 2Ch Touch Light {"NAME":"Neo NAS-SC01W-2","GPIO":[0,0,0,0,225,0,0,0,32,224,33,0,544,0],"FLAG":0,"BASE":18} Nexete DS-123 {"NAME":"DS-123","GPIO":[544,321,1,32,224,33,0,0,1,225,320,1,1,0],"FLAG":0,"BASE":18} Nexete DS-123 Single {"NAME":"DS-123","GPIO":[544,0,1,33,0,32,0,0,1,224,320,1,1,0],"FLAG":0,"BASE":18} Novadigital Interruptor Touch Led 1 Boto {"NAME":"Nova Digital Switch 1 Gang","GPIO":[544,0,0,32,224,0,0,0,0,0,288,0,0,0],"FLAG":0,"BASE":18} @@ -2555,6 +2562,7 @@ ZUCZUG 3 Gang {"NAME":"2ph105626a x3","GPIO":[0,288,0,32,34,33,0, ## Switch Module ``` +2 CH Smart Switch {"NAME":"Generic","GPIO":[32,1,1,1,1,225,33,1,224,288,1,1,1,1],"FLAG":0,"BASE":18} AGL Modulo Relay 01 Canal {"NAME":"AGL-Basic","GPIO":[0,1,0,0,224,32,0,0,0,0,320,0,0,0],"FLAG":0,"BASE":18} Albohes 2 Channel {"NAME":"Albohes SH-08","GPIO":[0,3200,33,3232,321,320,0,0,224,544,32,0,225,1],"FLAG":0,"BASE":18} Athom 10A {"NAME":"CB01-TAS-1","GPIO":[0,0,0,32,320,0,0,0,0,224,0,0,0,1],"FLAG":0,"BASE":18} @@ -2563,6 +2571,7 @@ Athom 3-Way Mini Relay {"NAME":"RS01-TAS-1","GPIO":[0,0,0,32,576,0,0,0,0,2 Athom 4Ch Inching/Self-locking 10A {"NAME":"Athom R04","GPIO":[1,1,1,1,32,576,1,1,226,227,225,1,224,0],"FLAG":0,"BASE":18} Athom 4Ch Inching/Self-locking 30A {"NAME":"Athom R04-30A","GPIO":[1,1,1,1,32,576,1,1,226,227,225,1,224,0],"FLAG":0,"BASE":18} ATMS1601 230VAC DIN Timer/Switch {"NAME":"ATMS1601","GPIO":[1,1,1,1,544,320,1,1,224,32,1,1,1,1],"FLAG":0,"BASE":18} +Aubess Power Monitor Switch 16A {"NAME":"Aubess with (BL0942)","GPIO":[0,3200,0,7520,0,0,0,0,160,0,224,0,0,0],"FLAG":0,"BASE":18} BH OnOfre Dual Rev5 Silent Edition {"NAME":"bhonofre","GPIO":[0,0,0,0,225,224,0,0,160,161,0,0,0,0],"FLAG":0,"BASE":18} BlitzWolf BW-SS1 {"NAME":"BW-SS1","GPIO":[1,1,1,1,544,224,0,0,1,32,1,1,0,0],"FLAG":0,"BASE":18} BlitzWolf BW-SS5 1 Gang {"NAME":"BlitzWolf SS5 1 Gang","GPIO":[0,0,0,0,288,0,0,0,160,224,0,0,0,0],"FLAG":0,"BASE":18} @@ -2589,8 +2598,12 @@ LoraTap 10A {"NAME":"LoraTap RR400W","GPIO":[0,0,0,0,544,0,0,0, LoraTap RR500W {"NAME":"LoraTap RR500W","GPIO":[544,0,0,0,160,0,0,0,32,224,0,0,320,0],"FLAG":0,"BASE":18} LoveAnna AC85-250V 10A {"NAME":"2xSwitch No RF LoveAnna","GPIO":[32,0,0,0,0,225,33,0,224,320,0,0,0,0],"FLAG":0,"BASE":18} Luani HVIO {"NAME":"Luani HVIO","GPIO":[0,1,1,1,224,225,0,0,160,161,1,288,0,4704],"FLAG":0,"BASE":35} +Luminea {"NAME":"Luminea NX-4651","GPIO":[0,0,0,0,288,0,0,0,160,224,0,0,0,0],"FLAG":0,"BASE":18} Milfra Smart {"NAME":"Milfra Smart Module TB41","GPIO":[576,0,0,225,2688,2656,0,0,2592,193,480,224,192,0],"FLAG":0,"BASE":18} +Mini Smart Switch {"NAME":"SmartSwitch-MK601","GPIO":[0,0,0,160,32,224,0,0,0,0,288,0,0,0],"FLAG":0,"BASE":18} Moes {"NAME":"Moes MS-104B","GPIO":[0,0,32,0,480,0,0,0,161,160,224,225,0,0],"FLAG":0,"BASE":18} +Moes 10A {"NAME":"Moes MS-101","GPIO":[0,0,0,0,0,320,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18} +Moes Mini 3 Gang 1/2 Way {"NAME":"Moes MS-104C","GPIO":[0,0,0,34,32,33,0,0,224,225,226,0,0,0],"FLAG":0,"BASE":18} Nedis 10A {"NAME":"Nedis WIFIPS10WT","GPIO":[0,0,0,0,224,0,0,0,32,321,0,288,0,0],"FLAG":0,"BASE":18} Nova Digital Basic 1 MS101 {"NAME":"NovaDigBasic1","GPIO":[0,1,0,1,320,0,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18} PPA Contatto Wi-Fi {"NAME":"PPA Contatto","GPIO":[0,0,32,0,224,162,0,0,288,225,0,0,0,0],"FLAG":0,"BASE":18} @@ -2605,11 +2618,12 @@ Shelly 2 {"NAME":"Shelly 2","GPIO":[0,2752,0,2784,224,225,0, Shelly 2.5 {"NAME":"Shelly 2.5","GPIO":[320,0,0,0,224,193,0,0,640,192,608,225,3456,4736],"FLAG":0,"BASE":18} Shelly EM {"NAME":"Shelly EM","GPIO":[0,0,0,0,0,0,0,0,640,3457,608,224,8832,1],"FLAG":0,"BASE":18} Shelly i3 Action and Scenes Activation Device {"NAME":"Shelly i3","GPIO":[0,0,0,0,0,320,0,0,193,194,192,0,0,4736],"FLAG":0,"BASE":18} -Shelly Plus 1 {"NAME":"Shelly Plus 1 ","GPIO":[0,0,0,0,192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,224,0,0,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":1} +Shelly Plus 1 {"NAME":"Shelly Plus 1 ","GPIO":[288,0,0,0,192,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,32,224,0,0,0,0,0,4736,4705,0,0,0,0,0,0],"FLAG":0,"BASE":1} Shelly Plus 1PM {"NAME":"Shelly Plus 1PM","GPIO":[0,0,0,0,192,2720,0,0,0,0,0,0,0,0,2656,0,0,0,0,2624,0,32,224,0,0,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":1} Shelly Plus 2PM {"NAME":"Shelly Plus 2PM PCB v0.1.9","GPIO":[320,0,0,0,32,192,0,0,225,224,0,0,0,0,193,0,0,0,0,0,0,608,640,3456,0,0,0,0,0,0,0,4736,0,0,0,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,10000,10000,3350"} Shelly Plus i4 {"NAME":"Shelly Plus i4","GPIO":[0,0,0,0,0,0,0,0,192,0,193,0,0,0,0,0,0,0,0,0,0,0,195,194,0,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":1,"CMND":"SwitchMode1 1 | SwitchMode2 1 | SwitchMode3 1 | SwitchMode4 1 | SwitchTopic 0 | SetOption114 1"} Sinilink USB {"NAME":"XY-WFUSB","GPIO":[1,1,0,1,32,224,0,0,0,0,320,0,544,0],"FLAG":0,"BASE":18} +Smarsecur Smart Switch {"NAME":"ESP-02S","GPIO":[0,0,0,32,0,0,0,0,0,0,224,0,0,0],"FLAG":0,"BASE":18} Smart Home SS-8839-01 {"NAME":"SS-8839-01","GPIO":[0,1,0,1,224,0,0,0,32,321,0,320,0,0],"FLAG":0,"BASE":18} Sonoff 4CH (R2) {"NAME":"Sonoff 4CH","GPIO":[32,1,1,1,226,225,33,34,224,320,35,227,0,0],"FLAG":0,"BASE":7} Sonoff 4CH Pro (R2) {"NAME":"Sonoff 4CH Pro","GPIO":[32,1,1,1,226,225,33,34,224,320,35,227,0,0],"FLAG":0,"BASE":23} @@ -2624,6 +2638,7 @@ Sonoff Dual R3 {"NAME":"Sonoff Dual R3","GPIO":[32,0,0,0,0,0,0,0,0 Sonoff Dual R3 Lite {"NAME":"Sonoff Dual R3 Lite","GPIO":[32,0,0,0,0,0,0,0,0,576,225,0,0,0,0,0,0,0,0,0,0,0,0,224,0,0,0,0,160,161,0,0,0,0,0,0],"FLAG":0,"BASE":1} Sonoff Dual R3 v2 {"NAME":"Sonoff Dual R3 v2","GPIO":[32,0,0,0,0,0,0,0,0,576,225,0,0,0,0,0,0,0,0,0,0,3200,8128,224,0,0,0,0,160,161,0,0,0,0,0,0],"FLAG":0,"BASE":1} Sonoff Mini {"NAME":"Sonoff Mini","GPIO":[32,0,0,0,160,0,0,0,224,320,0,0,1,0],"FLAG":0,"BASE":1} +Sonoff Mini Extreme {"NAME":"Sonoff MINIR4","GPIO":[32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,576,0,0,0,0,0,0,224,160,0,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":1} Sonoff Mini R2 {"NAME":"Sonoff MINIR2","GPIO":[32,0,0,0,160,0,0,0,224,544,0,0,0,0],"FLAG":0,"BASE":1} Sonoff Pow {"NAME":"Sonoff Pow","GPIO":[32,0,0,0,0,2592,0,0,224,2656,2688,288,0,0],"FLAG":0,"BASE":6} Sonoff POW Elite 16A {"NAME":"Sonoff POWR316D","GPIO":[32,0,0,0,0,576,0,0,0,224,9280,0,3104,0,320,0,0,0,0,0,0,9184,9248,9216,0,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":1} @@ -2644,6 +2659,7 @@ SUPLA inCan by Espablo {"NAME":"Supla Espablo","GPIO":[0,1,1312,1,32,224,0 SW-R03 {"NAME":"SW-R03","GPIO":[0,0,0,0,0,0,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18} Switch Module 2x5A {"NAME":"QS-WIFI-S04-2C","GPIO":[1,1,32,1,480,0,0,0,161,160,224,225,0,0],"FLAG":0,"BASE":18} Syrotech {"NAME":"Syrotech SY-LS80","GPIO":[0,0,0,0,224,32,0,0,0,320,320,0,0,0],"FLAG":0,"BASE":18} +Tinxy 1 Node 16A for AC/Geyser {"NAME":"Tnxy16A","GPIO":[32,0,0,0,160,224,0,0,288,0,416,0,0,0],"FLAG":0,"BASE":18} Tinxy Single Node 7A {"NAME":"Tnxy07A","GPIO":[32,0,0,0,160,224,0,0,288,0,0,0,0,0],"FLAG":0,"BASE":18} WL-SW01_10 {"NAME":"WL-SW01_10","GPIO":[32,3232,0,3200,0,0,0,0,224,320,0,0,0,0],"FLAG":0,"BASE":1} Woox Integrational Switch {"NAME":"WOOXR4967","GPIO":[0,0,0,1,320,224,0,0,0,32,0,0,0,0],"FLAG":0,"BASE":18} @@ -2664,7 +2680,7 @@ Shelly Add-on {"NAME":"Shelly 1 Temp ","GPIO":[1344,0,0,1312,224, ``` Floor Heating or Water/Gas Boiler {"NAME":"ME81H Thermostat","GPIO":[1,1,1,1,1,1,0,0,1,1,1,1,1,0],"FLAG":0,"BASE":54} Lytko 101 {"NAME":"Lytko 101","GPIO":[1,7584,1312,1,1792,1824,0,0,1,1,1,224,1,4736],"FLAG":0,"BASE":18} -Moes Floor Heating or Water/Gas Boiler Wall {"NAME":"WHT-HY609-GB-WH-MS","GPIO":[0,2304,0,2272,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54} +Moes Floor Heating or Water/Gas Boiler Wall {"NAME":"WHT-HY609-GB-WH-MS","GPIO":[0,2304,0,2272,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54,"CMND":"tuyamcu 11,1 | tuyamcu 71,3 | tuyamcu 72,2 | tuyamcu 12,102"} Mysa V1 Electric Baseboard Heater {"NAME":"Mysa Thermostat","GPIO":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,224,0,0,0,0,0,0,640,608,0,0,0,0,0,0],"FLAG":0,"BASE":1} ``` @@ -2695,9 +2711,10 @@ CE Smart Home LQ-2-W3 {"NAME":"LITESUN","GPIO":[0,0,0,0,544,32,0,0,224,0, DETA Double GPO + USB {"NAME":"DETA 6920HA","GPIO":[0,0,0,3104,32,288,0,0,33,224,225,0,0,0],"FLAG":0,"BASE":18} Deta Double Power Point {"NAME":"DETA 2G GPO","GPIO":[0,0,0,0,544,0,0,0,65,224,225,0,64,0],"FLAG":0,"BASE":18} DETA Outdoor Double Powerpoint {"NAME":"DETA 6294HA","GPIO":[0,0,0,3104,32,288,0,0,33,224,225,0,0,0],"FLAG":0,"BASE":18} -Deta Single Power Point {"NAME":"DETA 2G GPO USB","GPIO":[0,0,0,2720,64,576,0,0,65,224,225,0,0,0],"FLAG":0,"BASE":18} +Deta Single Power Point {"NAME":"DETA 1G GPO","GPIO":[0,0,0,3104,64,576,0,0,0,224,0,0,0,0],"FLAG":0,"BASE":18} Ener-J 13A Twin Wall Sockets with USB {"NAME":"Ener-J 2-Gang ","GPIO":[32,0,0,0,0,224,33,0,225,320,0,0,0,0],"FLAG":0,"BASE":18} Gosund {"NAME":"Gosund WO1","GPIO":[320,0,576,0,2656,2720,0,0,2624,321,225,224,0,4704],"FLAG":0,"BASE":18} +Gosund USB Charger {"NAME":"Gosund WO2","GPIO":[320,0,576,0,0,257,0,0,0,32,0,224,0,0],"FLAG":0,"BASE":18} Hevolta Glasense {"NAME":"Hevolta Socket","GPIO":[0,0,0,0,288,289,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18} Kapok T16 {"NAME":"tiltech-t16","GPIO":[0,320,0,32,192,0,0,0,224,225,0,0,0,0],"FLAG":0,"BASE":18} Kesen KS-604 {"NAME":"KS-604","GPIO":[1,1,288,1,1,33,0,0,225,224,1,1,32,0],"FLAG":0,"BASE":18} diff --git a/tools/templates/templates.py b/tools/templates/templates.py index 5b33f8cfa..3f06ebb4c 100644 --- a/tools/templates/templates.py +++ b/tools/templates/templates.py @@ -341,7 +341,10 @@ def main(): # Write to root/TEMPLATES.md fout = open(TEMPLATES,"w+") - fout.write("\"Logo\"\n") + fout.write("\n") + fout.write(" \n") + fout.write(" \"Logo\"\n") + fout.write("\n") fout.write("\n") fout.write("# Templates\n") fout.write("\n") From ecac466e231762c524900363f355aaffa7236a2e Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Tue, 24 Jan 2023 12:04:30 +0100 Subject: [PATCH 174/262] Fix Shelly Pro 4PM power on reset --- .../xdrv_88_esp32_shelly_pro_v2.ino | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v2.ino b/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v2.ino index e7de1e849..a29e19dcc 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v2.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v2.ino @@ -240,7 +240,8 @@ bool ShellyProAddButton(void) { if (SPro.button_offset < 0) { SPro.button_offset = XdrvMailbox.index; } uint32_t index = XdrvMailbox.index - SPro.button_offset; if (index > 2) { return false; } // Support three buttons - uint32_t state = SP4Mcp23S17DigitalRead(sp4_button_pin[index]); + uint32_t state = SP4Mcp23S17DigitalRead(sp4_button_pin[index]); // 0 on power on, 1 on restart + state = 1; // Force to off on power on bitWrite(SPro.input_state, sp4_button_pin[index], state); XdrvMailbox.index = state; return true; @@ -251,7 +252,7 @@ bool ShellyProAddSwitch(void) { if (SPro.switch_offset < 0) { SPro.switch_offset = XdrvMailbox.index; } uint32_t index = XdrvMailbox.index - SPro.switch_offset; if (index > 3) { return false; } // Support four switches - uint32_t state = SP4Mcp23S17DigitalRead(sp4_switch_pin[index]); + uint32_t state = SP4Mcp23S17DigitalRead(sp4_switch_pin[index]); // 0 on power on and restart bitWrite(SPro.input_state, sp4_switch_pin[index], state); XdrvMailbox.index = state ^1; // Invert return true; @@ -261,11 +262,12 @@ void ShellyProUpdateIsr(void) { /* The goal if this function is to minimize SPI and SetVirtualPinState calls */ - uint32_t input_state = SP4Mcp23S17Read16(SP4_MCP23S17_INTCAPA); // Read intcap and clear interrupt input_state &= 0x806F; // Only test input bits -// AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Input detected %04X, was %04X"), input_state, SPro.input_state); +// AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Input from %04X to %04X"), SPro.input_state, input_state); + + if (TasmotaGlobal.uptime < 3) { return; } // Flush interrupt for 3 seconds after poweron uint32_t mask = 1; for (uint32_t j = 0; j < 16; j++) { From e81d59f65865cbcd6db6fadcc90e6a6461d174fa Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Tue, 24 Jan 2023 16:34:24 +0100 Subject: [PATCH 175/262] Fix Shelly Pro 4PM initial button state --- .../xdrv_88_esp32_shelly_pro_v2.ino | 39 +++++++++---------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v2.ino b/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v2.ino index a29e19dcc..daf423a55 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v2.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v2.ino @@ -187,13 +187,13 @@ const uint8_t sp4_button_pin[] = { 5, 2, 3 }; void ShellyPro4Init(void) { /* Shelly Pro 4PM MCP23S17 registers - bit 0 = input - Switch3 - bit 1 = input - Switch2 - bit 2 = input, pullup, inverted - Button Down - bit 3 = input, pullup, inverted - Button OK + bit 0 = input, inverted - Switch3 + bit 1 = input, inverted - Switch2 + bit 2 = input - Button Down + bit 3 = input - Button OK bit 4 = output - Reset, display, ADE7953 - bit 5 = input, pullup, inverted - Button Up - bit 6 = input - Switch1 + bit 5 = input - Button Up + bit 6 = input, inverted - Switch1 bit 7 bit 8 = output - Relay O1 bit 9 @@ -202,7 +202,7 @@ void ShellyPro4Init(void) { bit 12 = output - Relay O4 bit 13 = output - Relay O2 bit 14 = output - Relay O3 - bit 15 = input - Switch4 + bit 15 = input, inverted - Switch4 */ SP4Mcp23S17Write(SP4_MCP23S17_IOCONA, 0b01011000); // Enable INT mirror, Slew rate disabled, HAEN pins for addressing SP4Mcp23S17Write(SP4_MCP23S17_GPINTENA, 0x6F); // Enable interrupt on change @@ -212,20 +212,22 @@ void ShellyPro4Init(void) { sp4_mcp23s17_olata = SP4Mcp23S17Read(SP4_MCP23S17_OLATA); sp4_mcp23s17_olatb = SP4Mcp23S17Read(SP4_MCP23S17_OLATB); + SP4Mcp23S17PinMode(4, OUTPUT); // Reset display, ADE7943 + SP4Mcp23S17DigitalWrite(4, 1); + + for (uint32_t i = 0; i < 3; i++) { + SP4Mcp23S17PinMode(sp4_button_pin[i], INPUT); // Button Up, Down, OK (RC with 10k to 3V3 and button shorting C) + } + SPro.button_offset = -1; + for (uint32_t i = 0; i < 4; i++) { SP4Mcp23S17PinMode(sp4_switch_pin[i], INPUT); // Switch1..4 SP4Mcp23S17PinMode(sp4_relay_pin[i], OUTPUT); // Relay O1..O4 } SPro.switch_offset = -1; - for (uint32_t i = 0; i < 3; i++) { - SP4Mcp23S17PinMode(sp4_button_pin[i], PULLUP); // Button Up, Down, OK - } - SPro.button_offset = -1; - - SP4Mcp23S17PinMode(4, OUTPUT); // Reset display, ADE7943 - SP4Mcp23S17DigitalWrite(4, 1); - + // Read current input register state + SPro.input_state = SP4Mcp23S17Read16(SP4_MCP23S17_GPIOA) & 0x806F; // Read gpio and clear interrupt attachInterrupt(SPro.pin_mcp23s17_int, ShellyProUpdateIsr, CHANGE); } @@ -240,9 +242,7 @@ bool ShellyProAddButton(void) { if (SPro.button_offset < 0) { SPro.button_offset = XdrvMailbox.index; } uint32_t index = XdrvMailbox.index - SPro.button_offset; if (index > 2) { return false; } // Support three buttons - uint32_t state = SP4Mcp23S17DigitalRead(sp4_button_pin[index]); // 0 on power on, 1 on restart - state = 1; // Force to off on power on - bitWrite(SPro.input_state, sp4_button_pin[index], state); + uint32_t state = bitRead(SPro.input_state, sp4_button_pin[index]); // 1 on power on and restart XdrvMailbox.index = state; return true; } @@ -252,8 +252,7 @@ bool ShellyProAddSwitch(void) { if (SPro.switch_offset < 0) { SPro.switch_offset = XdrvMailbox.index; } uint32_t index = XdrvMailbox.index - SPro.switch_offset; if (index > 3) { return false; } // Support four switches - uint32_t state = SP4Mcp23S17DigitalRead(sp4_switch_pin[index]); // 0 on power on and restart - bitWrite(SPro.input_state, sp4_switch_pin[index], state); + uint32_t state = bitRead(SPro.input_state, sp4_switch_pin[index]); // 0 on power on and restart XdrvMailbox.index = state ^1; // Invert return true; } From e89183054539471c09325de672f53bd65ff3658d Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Tue, 24 Jan 2023 16:54:03 +0100 Subject: [PATCH 176/262] Prep ESP32 energy --- .../tasmota_xdrv_driver/xdrv_03_energy.ino | 560 +++++++++--------- .../tasmota_xdrv_driver/xdrv_10_scripter.ino | 26 +- tasmota/tasmota_xdrv_driver/xdrv_11_knx.ino | 42 +- .../xdrv_16_tuyamcu_v1.ino | 26 +- .../xdrv_16_tuyamcu_v2.ino | 26 +- .../xdrv_45_shelly_dimmer.ino | 24 +- .../xdrv_87_esp32_sonoff_tm1621.ino | 8 +- .../tasmota_xnrg_energy/xnrg_01_hlw8012.ino | 42 +- .../tasmota_xnrg_energy/xnrg_02_cse7766.ino | 40 +- .../tasmota_xnrg_energy/xnrg_03_pzem004t.ino | 24 +- .../tasmota_xnrg_energy/xnrg_04_mcp39f501.ino | 32 +- .../tasmota_xnrg_energy/xnrg_05_pzem_ac.ino | 26 +- .../tasmota_xnrg_energy/xnrg_06_pzem_dc.ino | 24 +- .../tasmota_xnrg_energy/xnrg_07_ade7953.ino | 62 +- .../tasmota_xnrg_energy/xnrg_08_sdm120.ino | 20 +- .../tasmota_xnrg_energy/xnrg_09_dds2382.ino | 18 +- .../tasmota_xnrg_energy/xnrg_10_sdm630.ino | 56 +- .../tasmota_xnrg_energy/xnrg_11_ddsu666.ino | 18 +- .../tasmota_xnrg_energy/xnrg_12_solaxX1.ino | 16 +- .../xnrg_13_fif_le01mr.ino | 20 +- .../tasmota_xnrg_energy/xnrg_14_bl09xx.ino | 54 +- .../tasmota_xnrg_energy/xnrg_15_teleinfo.ino | 52 +- .../tasmota_xnrg_energy/xnrg_16_iem3000.ino | 32 +- .../tasmota_xnrg_energy/xnrg_17_ornowe517.ino | 44 +- tasmota/tasmota_xnrg_energy/xnrg_18_sdm72.ino | 14 +- .../tasmota_xnrg_energy/xnrg_19_cse7761.ino | 50 +- .../tasmota_xnrg_energy/xnrg_21_sdm230.ino | 26 +- .../tasmota_xnrg_energy/xnrg_22_bl6523.ino | 32 +- .../tasmota_xnrg_energy/xnrg_23_ade7880.ino | 24 +- .../tasmota_xnrg_energy/xnrg_29_modbus.ino | 50 +- tasmota/tasmota_xnrg_energy/xnrg_30_dummy.ino | 46 +- .../tasmota_xsns_sensor/xsns_62_esp32_mi.ino | 8 +- .../xsns_75_prometheus.ino | 10 +- 33 files changed, 779 insertions(+), 773 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino b/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino index 70fca2527..14d7279d8 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino @@ -17,6 +17,7 @@ along with this program. If not, see . */ +//#ifdef ESP8266 #ifdef USE_ENERGY_SENSOR /*********************************************************************************************\ * Energy @@ -74,7 +75,7 @@ void (* const EnergyCommand[])(void) PROGMEM = { #endif // USE_ENERGY_MARGIN_DETECTION &CmndEnergyToday, &CmndEnergyYesterday, &CmndEnergyTotal, &CmndEnergyExportActive, &CmndEnergyUsage, &CmndEnergyExport, &CmndTariff}; -struct ENERGY { +typedef struct { float voltage[ENERGY_MAX_PHASES]; // 123.1 V float current[ENERGY_MAX_PHASES]; // 123.123 A float active_power[ENERGY_MAX_PHASES]; // 123.1 W @@ -93,10 +94,10 @@ struct ENERGY { float daily_sum_import_balanced; // 123.123 kWh float daily_sum_export_balanced; // 123.123 kWh - int32_t kWhtoday_delta[ENERGY_MAX_PHASES]; // 1212312345 Wh 10^-5 (deca micro Watt hours) - Overflows to Energy.kWhtoday (HLW and CSE only) - int32_t kWhtoday_offset[ENERGY_MAX_PHASES]; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = Energy.daily - int32_t kWhtoday[ENERGY_MAX_PHASES]; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = Energy.daily - int32_t period[ENERGY_MAX_PHASES]; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = Energy.daily + int32_t kWhtoday_delta[ENERGY_MAX_PHASES]; // 1212312345 Wh 10^-5 (deca micro Watt hours) - Overflows to Energy->kWhtoday (HLW and CSE only) + int32_t kWhtoday_offset[ENERGY_MAX_PHASES]; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = Energy->daily + int32_t kWhtoday[ENERGY_MAX_PHASES]; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = Energy->daily + int32_t period[ENERGY_MAX_PHASES]; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = Energy->daily uint8_t fifth_second; uint8_t command_code; @@ -132,7 +133,9 @@ struct ENERGY { uint8_t max_energy_state; #endif // USE_ENERGY_POWER_LIMIT #endif // USE_ENERGY_MARGIN_DETECTION -} Energy; +} tEnergy; + +tEnergy *Energy = nullptr; Ticker ticker_energy; @@ -140,25 +143,25 @@ Ticker ticker_energy; char* EnergyFormat(char* result, float* input, uint32_t resolution, uint32_t single = 0); char* EnergyFormat(char* result, float* input, uint32_t resolution, uint32_t single) { - // single = 0 - Energy.phase_count - xx or [xx,xx] or [xx,xx,xx] - // single = 1 - Energy.voltage_common or Energy.frequency_common - xx - // single = 2 - Sum of Energy.phase_count if SO129 0 - xx or if SO129 1 - [xx,xx,xx] + // single = 0 - Energy->phase_count - xx or [xx,xx] or [xx,xx,xx] + // single = 1 - Energy->voltage_common or Energy->frequency_common - xx + // single = 2 - Sum of Energy->phase_count if SO129 0 - xx or if SO129 1 - [xx,xx,xx] // single = 5 - single &0x03 = 1 - xx // single = 6 - single &0x03 = 2 - [xx,xx] - used by tarriff // single = 7 - single &0x03 = 3 - [xx,xx,xx] - uint32_t index = (single > 3) ? single &0x03 : (0 == single) ? Energy.phase_count : 1; // 1,2,3 + uint32_t index = (single > 3) ? single &0x03 : (0 == single) ? Energy->phase_count : 1; // 1,2,3 if (single > 2) { single = 0; } // 0,1,2 float input_sum = 0.0f; if (single > 1) { if (!Settings->flag5.energy_phase) { // SetOption129 - (Energy) Show phase information - for (uint32_t i = 0; i < Energy.phase_count; i++) { + for (uint32_t i = 0; i < Energy->phase_count; i++) { if (!isnan(input[i])) { input_sum += input[i]; } } input = &input_sum; } else { - index = Energy.phase_count; + index = Energy->phase_count; } } result[0] = '\0'; @@ -171,13 +174,13 @@ char* EnergyFormat(char* result, float* input, uint32_t resolution, uint32_t sin #ifdef USE_WEBSERVER char* WebEnergyFormat(char* result, float* input, uint32_t resolution, uint32_t single = 0); char* WebEnergyFormat(char* result, float* input, uint32_t resolution, uint32_t single) { - // single = 0 - Energy.phase_count - xx / xx / xx or multi column - // single = 1 - Energy.voltage_common or Energy.frequency_common - xx or single column using colspan (if needed) - // single = 2 - Sum of Energy.phase_count if SO129 0 - xx or single column using colspan (if needed) or if SO129 1 - xx / xx / xx or multi column + // single = 0 - Energy->phase_count - xx / xx / xx or multi column + // single = 1 - Energy->voltage_common or Energy->frequency_common - xx or single column using colspan (if needed) + // single = 2 - Sum of Energy->phase_count if SO129 0 - xx or single column using colspan (if needed) or if SO129 1 - xx / xx / xx or multi column float input_sum = 0.0f; if (single > 1) { // Sum and/or Single column if (!Settings->flag5.energy_phase) { // SetOption129 - (Energy) Show phase information - for (uint32_t i = 0; i < Energy.phase_count; i++) { + for (uint32_t i = 0; i < Energy->phase_count; i++) { if (!isnan(input[i])) { input_sum += input[i]; } @@ -189,25 +192,25 @@ char* WebEnergyFormat(char* result, float* input, uint32_t resolution, uint32_t } #ifdef USE_ENERGY_COLUMN_GUI ext_snprintf_P(result, GUISZ, PSTR("")); // Skip first column - if ((Energy.phase_count > 1) && single) { // Need to set colspan so need new columns + if ((Energy->phase_count > 1) && single) { // Need to set colspan so need new columns // 1.23  // 1.23  // 1.23  ext_snprintf_P(result, GUISZ, PSTR("%s%*_f "), - result, (Energy.phase_count *2) -1, (Settings->flag5.gui_table_align)?PSTR("right"):PSTR("center"), resolution, &input[0]); + result, (Energy->phase_count *2) -1, (Settings->flag5.gui_table_align)?PSTR("right"):PSTR("center"), resolution, &input[0]); } else { // 1.23  // 1.23 1.23  // 1.23 1.23 1.23  // 1.23 1.23 1.23 1.23  - for (uint32_t i = 0; i < Energy.phase_count; i++) { + for (uint32_t i = 0; i < Energy->phase_count; i++) { ext_snprintf_P(result, GUISZ, PSTR("%s%*_f "), result, (Settings->flag5.gui_table_align)?PSTR("right"):PSTR("left"), resolution, &input[i]); } } ext_snprintf_P(result, GUISZ, PSTR("%s"), result); #else // not USE_ENERGY_COLUMN_GUI - uint32_t index = (single) ? 1 : Energy.phase_count; // 1,2,3 + uint32_t index = (single) ? 1 : Energy->phase_count; // 1,2,3 result[0] = '\0'; for (uint32_t i = 0; i < index; i++) { ext_snprintf_P(result, GUISZ, PSTR("%s%s%*_f"), result, (i)?" / ":"", resolution, &input[i]); @@ -244,54 +247,54 @@ bool EnergyTariff1Active() // Off-Peak hours } void EnergyUpdateToday(void) { - Energy.total_sum = 0.0f; - Energy.yesterday_sum = 0.0f; - Energy.daily_sum = 0.0f; + Energy->total_sum = 0.0f; + Energy->yesterday_sum = 0.0f; + Energy->daily_sum = 0.0f; int32_t delta_sum_balanced = 0; - for (uint32_t i = 0; i < Energy.phase_count; i++) { - if (abs(Energy.kWhtoday_delta[i]) > 1000) { - int32_t delta = Energy.kWhtoday_delta[i] / 1000; + for (uint32_t i = 0; i < Energy->phase_count; i++) { + if (abs(Energy->kWhtoday_delta[i]) > 1000) { + int32_t delta = Energy->kWhtoday_delta[i] / 1000; delta_sum_balanced += delta; - Energy.kWhtoday_delta[i] -= (delta * 1000); - Energy.kWhtoday[i] += delta; + Energy->kWhtoday_delta[i] -= (delta * 1000); + Energy->kWhtoday[i] += delta; if (delta < 0) { // Export energy RtcSettings.energy_kWhexport_ph[i] += ((delta / 100) *-1); } } - RtcSettings.energy_kWhtoday_ph[i] = Energy.kWhtoday_offset[i] + Energy.kWhtoday[i]; - Energy.daily[i] = (float)(RtcSettings.energy_kWhtoday_ph[i]) / 100000; - Energy.total[i] = ((float)(RtcSettings.energy_kWhtotal_ph[i]) / 1000) + ((float)(RtcSettings.energy_kWhtoday_ph[i]) / 100000); - if (Energy.local_energy_active_export) { - Energy.export_active[i] = (float)(RtcSettings.energy_kWhexport_ph[i]) / 1000; + RtcSettings.energy_kWhtoday_ph[i] = Energy->kWhtoday_offset[i] + Energy->kWhtoday[i]; + Energy->daily[i] = (float)(RtcSettings.energy_kWhtoday_ph[i]) / 100000; + Energy->total[i] = ((float)(RtcSettings.energy_kWhtotal_ph[i]) / 1000) + ((float)(RtcSettings.energy_kWhtoday_ph[i]) / 100000); + if (Energy->local_energy_active_export) { + Energy->export_active[i] = (float)(RtcSettings.energy_kWhexport_ph[i]) / 1000; } - Energy.total_sum += Energy.total[i]; - Energy.yesterday_sum += (float)Settings->energy_kWhyesterday_ph[i] / 100000; - Energy.daily_sum += Energy.daily[i]; + Energy->total_sum += Energy->total[i]; + Energy->yesterday_sum += (float)Settings->energy_kWhyesterday_ph[i] / 100000; + Energy->daily_sum += Energy->daily[i]; } if (delta_sum_balanced > 0) { - Energy.daily_sum_import_balanced += (float)delta_sum_balanced / 100000; + Energy->daily_sum_import_balanced += (float)delta_sum_balanced / 100000; } else { - Energy.daily_sum_export_balanced += (float)abs(delta_sum_balanced) / 100000; + Energy->daily_sum_export_balanced += (float)abs(delta_sum_balanced) / 100000; } if (RtcTime.valid){ // We calc the difference only if we have a valid RTC time. - uint32_t energy_diff = (uint32_t)(Energy.total_sum * 1000) - RtcSettings.energy_usage.last_usage_kWhtotal; - RtcSettings.energy_usage.last_usage_kWhtotal = (uint32_t)(Energy.total_sum * 1000); + uint32_t energy_diff = (uint32_t)(Energy->total_sum * 1000) - RtcSettings.energy_usage.last_usage_kWhtotal; + RtcSettings.energy_usage.last_usage_kWhtotal = (uint32_t)(Energy->total_sum * 1000); uint32_t return_diff = 0; - if (!isnan(Energy.export_active[0])) { -// return_diff = (uint32_t)(Energy.export_active * 1000) - RtcSettings.energy_usage.last_return_kWhtotal; -// RtcSettings.energy_usage.last_return_kWhtotal = (uint32_t)(Energy.export_active * 1000); + if (!isnan(Energy->export_active[0])) { +// return_diff = (uint32_t)(Energy->export_active * 1000) - RtcSettings.energy_usage.last_return_kWhtotal; +// RtcSettings.energy_usage.last_return_kWhtotal = (uint32_t)(Energy->export_active * 1000); float export_active = 0.0f; - for (uint32_t i = 0; i < Energy.phase_count; i++) { - if (!isnan(Energy.export_active[i])) { - export_active += Energy.export_active[i]; + for (uint32_t i = 0; i < Energy->phase_count; i++) { + if (!isnan(Energy->export_active[i])) { + export_active += Energy->export_active[i]; } } return_diff = (uint32_t)(export_active * 1000) - RtcSettings.energy_usage.last_return_kWhtotal; @@ -309,17 +312,17 @@ void EnergyUpdateToday(void) { } void EnergyUpdateTotal(void) { - // Provide total import active energy as float Energy.import_active[phase] in kWh: 98Wh = 0.098kWh + // Provide total import active energy as float Energy->import_active[phase] in kWh: 98Wh = 0.098kWh - for (uint32_t i = 0; i < Energy.phase_count; i++) { - AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("NRG: EnergyTotal[%d] %4_f kWh"), i, &Energy.import_active[i]); + for (uint32_t i = 0; i < Energy->phase_count; i++) { + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("NRG: EnergyTotal[%d] %4_f kWh"), i, &Energy->import_active[i]); // Try to fix instable input by verifying allowed bandwidth (#17659) - if ((Energy.start_energy[i] != 0) && + if ((Energy->start_energy[i] != 0) && (Settings->param[P_CSE7766_INVALID_POWER] > 0) && (Settings->param[P_CSE7766_INVALID_POWER] < 128)) { // SetOption39 1..127 kWh - int total = abs((int)Energy.total[i]); // We only use kWh - int import_active = abs((int)Energy.import_active[i]); + int total = abs((int)Energy->total[i]); // We only use kWh + int import_active = abs((int)Energy->import_active[i]); if ((import_active < (total - Settings->param[P_CSE7766_INVALID_POWER])) || (import_active > (total + Settings->param[P_CSE7766_INVALID_POWER]))) { AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("NRG: Outside bandwidth")); @@ -327,20 +330,20 @@ void EnergyUpdateTotal(void) { } } - if (0 == Energy.start_energy[i] || (Energy.import_active[i] < Energy.start_energy[i])) { - Energy.start_energy[i] = Energy.import_active[i]; // Init after restart and handle roll-over if any + if (0 == Energy->start_energy[i] || (Energy->import_active[i] < Energy->start_energy[i])) { + Energy->start_energy[i] = Energy->import_active[i]; // Init after restart and handle roll-over if any } - else if (Energy.import_active[i] != Energy.start_energy[i]) { - Energy.kWhtoday[i] = (int32_t)((Energy.import_active[i] - Energy.start_energy[i]) * 100000); + else if (Energy->import_active[i] != Energy->start_energy[i]) { + Energy->kWhtoday[i] = (int32_t)((Energy->import_active[i] - Energy->start_energy[i]) * 100000); } - if ((Energy.total[i] < (Energy.import_active[i] - 0.01f)) && // We subtract a little offset of 10Wh to avoid continuous updates + if ((Energy->total[i] < (Energy->import_active[i] - 0.01f)) && // We subtract a little offset of 10Wh to avoid continuous updates Settings->flag3.hardware_energy_total) { // SetOption72 - Enable hardware energy total counter as reference (#6561) - // The following calculation allows total usage (Energy.import_active[i]) up to +/-2147483.647 kWh - RtcSettings.energy_kWhtotal_ph[i] = (int32_t)((Energy.import_active[i] * 1000) - ((Energy.kWhtoday_offset[i] + Energy.kWhtoday[i]) / 100)); + // The following calculation allows total usage (Energy->import_active[i]) up to +/-2147483.647 kWh + RtcSettings.energy_kWhtotal_ph[i] = (int32_t)((Energy->import_active[i] * 1000) - ((Energy->kWhtoday_offset[i] + Energy->kWhtoday[i]) / 100)); Settings->energy_kWhtotal_ph[i] = RtcSettings.energy_kWhtotal_ph[i]; - Energy.total[i] = Energy.import_active[i]; - Settings->energy_kWhtotal_time = (!Energy.kWhtoday_offset[i]) ? LocalTime() : Midnight(); + Energy->total[i] = Energy->import_active[i]; + Settings->energy_kWhtotal_time = (!Energy->kWhtoday_offset[i]) ? LocalTime() : Midnight(); // AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Energy Total updated with hardware value")); } } @@ -352,26 +355,26 @@ void EnergyUpdateTotal(void) { void Energy200ms(void) { - Energy.power_on = (TasmotaGlobal.power != 0) | Settings->flag.no_power_on_check; // SetOption21 - Show voltage even if powered off + Energy->power_on = (TasmotaGlobal.power != 0) | Settings->flag.no_power_on_check; // SetOption21 - Show voltage even if powered off - Energy.fifth_second++; - if (5 == Energy.fifth_second) { - Energy.fifth_second = 0; + Energy->fifth_second++; + if (5 == Energy->fifth_second) { + Energy->fifth_second = 0; XnrgCall(FUNC_ENERGY_EVERY_SECOND); if (RtcTime.valid) { - if (!Energy.kWhtoday_offset_init && (RtcTime.day_of_year == Settings->energy_kWhdoy)) { - Energy.kWhtoday_offset_init = true; + if (!Energy->kWhtoday_offset_init && (RtcTime.day_of_year == Settings->energy_kWhdoy)) { + Energy->kWhtoday_offset_init = true; for (uint32_t i = 0; i < 3; i++) { - Energy.kWhtoday_offset[i] = Settings->energy_kWhtoday_ph[i]; + Energy->kWhtoday_offset[i] = Settings->energy_kWhtoday_ph[i]; // RtcSettings.energy_kWhtoday_ph[i] = 0; } } if ((LocalTime() == Midnight()) || (RtcTime.day_of_year > Settings->energy_kWhdoy)) { - Energy.kWhtoday_offset_init = true; + Energy->kWhtoday_offset_init = true; Settings->energy_kWhdoy = RtcTime.day_of_year; for (uint32_t i = 0; i < 3; i++) { @@ -382,25 +385,25 @@ void Energy200ms(void) Settings->energy_kWhexport_ph[i] = RtcSettings.energy_kWhexport_ph[i]; - Energy.period[i] -= RtcSettings.energy_kWhtoday_ph[i]; // this becomes a large unsigned, effectively a negative for EnergyShow calculation - Energy.kWhtoday[i] = 0; - Energy.kWhtoday_offset[i] = 0; + Energy->period[i] -= RtcSettings.energy_kWhtoday_ph[i]; // this becomes a large unsigned, effectively a negative for EnergyShow calculation + Energy->kWhtoday[i] = 0; + Energy->kWhtoday_offset[i] = 0; RtcSettings.energy_kWhtoday_ph[i] = 0; Settings->energy_kWhtoday_ph[i] = 0; - Energy.start_energy[i] = 0; -// Energy.kWhtoday_delta = 0; // dont zero this, we need to carry the remainder over to tomorrow - Energy.daily_sum_import_balanced = 0.0; - Energy.daily_sum_export_balanced = 0.0; + Energy->start_energy[i] = 0; +// Energy->kWhtoday_delta = 0; // dont zero this, we need to carry the remainder over to tomorrow + Energy->daily_sum_import_balanced = 0.0; + Energy->daily_sum_export_balanced = 0.0; } EnergyUpdateToday(); #if defined(USE_ENERGY_MARGIN_DETECTION) && defined(USE_ENERGY_POWER_LIMIT) - Energy.max_energy_state = 3; + Energy->max_energy_state = 3; #endif // USE_ENERGY_POWER_LIMIT } #if defined(USE_ENERGY_MARGIN_DETECTION) && defined(USE_ENERGY_POWER_LIMIT) - if ((RtcTime.hour == Settings->energy_max_energy_start) && (3 == Energy.max_energy_state )) { - Energy.max_energy_state = 0; + if ((RtcTime.hour == Settings->energy_max_energy_start) && (3 == Energy->max_energy_state )) { + Energy->max_energy_state = 0; } #endif // USE_ENERGY_POWER_LIMIT @@ -440,9 +443,9 @@ bool EnergyMargin(bool type, uint16_t margin, uint16_t value, bool &flag, bool & } void EnergyMarginCheck(void) { - if (!Energy.phase_count || (TasmotaGlobal.uptime < 8)) { return; } - if (Energy.power_steady_counter) { - Energy.power_steady_counter--; + if (!Energy->phase_count || (TasmotaGlobal.uptime < 8)) { return; } + if (Energy->power_steady_counter) { + Energy->power_steady_counter--; return; } @@ -450,18 +453,18 @@ void EnergyMarginCheck(void) { Response_P(PSTR("{\"" D_RSLT_MARGINS "\":{")); int16_t power_diff[ENERGY_MAX_PHASES] = { 0 }; - for (uint32_t phase = 0; phase < Energy.phase_count; phase++) { - uint16_t active_power = (uint16_t)(Energy.active_power[phase]); + for (uint32_t phase = 0; phase < Energy->phase_count; phase++) { + uint16_t active_power = (uint16_t)(Energy->active_power[phase]); -// AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: APower %d, HPower0 %d, HPower1 %d, HPower2 %d"), active_power, Energy.power_history[phase][0], Energy.power_history[phase][1], Energy.power_history[phase][2]); +// AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: APower %d, HPower0 %d, HPower1 %d, HPower2 %d"), active_power, Energy->power_history[phase][0], Energy->power_history[phase][1], Energy->power_history[phase][2]); if (Settings->energy_power_delta[phase]) { - power_diff[phase] = active_power - Energy.power_history[phase][0]; + power_diff[phase] = active_power - Energy->power_history[phase][0]; uint16_t delta = abs(power_diff[phase]); bool threshold_met = false; if (delta > 0) { if (Settings->energy_power_delta[phase] < 101) { // 1..100 = Percentage - uint16_t min_power = (Energy.power_history[phase][0] > active_power) ? active_power : Energy.power_history[phase][0]; + uint16_t min_power = (Energy->power_history[phase][0] > active_power) ? active_power : Energy->power_history[phase][0]; if (0 == min_power) { min_power++; } // Fix divide by 0 exception (#6741) delta = (delta * 100) / min_power; if (delta >= Settings->energy_power_delta[phase]) { @@ -474,56 +477,56 @@ void EnergyMarginCheck(void) { } } if (threshold_met) { - Energy.power_history[phase][1] = active_power; // We only want one report so reset history - Energy.power_history[phase][2] = active_power; + Energy->power_history[phase][1] = active_power; // We only want one report so reset history + Energy->power_history[phase][2] = active_power; jsonflg = true; } else { power_diff[phase] = 0; } } - Energy.power_history[phase][0] = Energy.power_history[phase][1]; // Shift in history every second allowing power changes to settle for up to three seconds - Energy.power_history[phase][1] = Energy.power_history[phase][2]; - Energy.power_history[phase][2] = active_power; + Energy->power_history[phase][0] = Energy->power_history[phase][1]; // Shift in history every second allowing power changes to settle for up to three seconds + Energy->power_history[phase][1] = Energy->power_history[phase][2]; + Energy->power_history[phase][2] = active_power; } if (jsonflg) { - float power_diff_f[Energy.phase_count]; - for (uint32_t phase = 0; phase < Energy.phase_count; phase++) { + float power_diff_f[Energy->phase_count]; + for (uint32_t phase = 0; phase < Energy->phase_count; phase++) { power_diff_f[phase] = power_diff[phase]; } char value_chr[TOPSZ]; ResponseAppend_P(PSTR("\"" D_CMND_POWERDELTA "\":%s"), EnergyFormat(value_chr, power_diff_f, 0)); } - uint16_t energy_power_u = (uint16_t)(Energy.active_power[0]); + uint16_t energy_power_u = (uint16_t)(Energy->active_power[0]); - if (Energy.power_on && (Settings->energy_min_power || Settings->energy_max_power || Settings->energy_min_voltage || Settings->energy_max_voltage || Settings->energy_min_current || Settings->energy_max_current)) { - uint16_t energy_voltage_u = (uint16_t)(Energy.voltage[0]); - uint16_t energy_current_u = (uint16_t)(Energy.current[0] * 1000); + if (Energy->power_on && (Settings->energy_min_power || Settings->energy_max_power || Settings->energy_min_voltage || Settings->energy_max_voltage || Settings->energy_min_current || Settings->energy_max_current)) { + uint16_t energy_voltage_u = (uint16_t)(Energy->voltage[0]); + uint16_t energy_current_u = (uint16_t)(Energy->current[0] * 1000); DEBUG_DRIVER_LOG(PSTR("NRG: W %d, U %d, I %d"), energy_power_u, energy_voltage_u, energy_current_u); bool flag; - if (EnergyMargin(false, Settings->energy_min_power, energy_power_u, flag, Energy.min_power_flag)) { + if (EnergyMargin(false, Settings->energy_min_power, energy_power_u, flag, Energy->min_power_flag)) { ResponseAppend_P(PSTR("%s\"" D_CMND_POWERLOW "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag)); jsonflg = true; } - if (EnergyMargin(true, Settings->energy_max_power, energy_power_u, flag, Energy.max_power_flag)) { + if (EnergyMargin(true, Settings->energy_max_power, energy_power_u, flag, Energy->max_power_flag)) { ResponseAppend_P(PSTR("%s\"" D_CMND_POWERHIGH "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag)); jsonflg = true; } - if (EnergyMargin(false, Settings->energy_min_voltage, energy_voltage_u, flag, Energy.min_voltage_flag)) { + if (EnergyMargin(false, Settings->energy_min_voltage, energy_voltage_u, flag, Energy->min_voltage_flag)) { ResponseAppend_P(PSTR("%s\"" D_CMND_VOLTAGELOW "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag)); jsonflg = true; } - if (EnergyMargin(true, Settings->energy_max_voltage, energy_voltage_u, flag, Energy.max_voltage_flag)) { + if (EnergyMargin(true, Settings->energy_max_voltage, energy_voltage_u, flag, Energy->max_voltage_flag)) { ResponseAppend_P(PSTR("%s\"" D_CMND_VOLTAGEHIGH "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag)); jsonflg = true; } - if (EnergyMargin(false, Settings->energy_min_current, energy_current_u, flag, Energy.min_current_flag)) { + if (EnergyMargin(false, Settings->energy_min_current, energy_current_u, flag, Energy->min_current_flag)) { ResponseAppend_P(PSTR("%s\"" D_CMND_CURRENTLOW "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag)); jsonflg = true; } - if (EnergyMargin(true, Settings->energy_max_current, energy_current_u, flag, Energy.max_current_flag)) { + if (EnergyMargin(true, Settings->energy_max_current, energy_current_u, flag, Energy->max_current_flag)) { ResponseAppend_P(PSTR("%s\"" D_CMND_CURRENTHIGH "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag)); jsonflg = true; } @@ -537,35 +540,35 @@ void EnergyMarginCheck(void) { #ifdef USE_ENERGY_POWER_LIMIT // Max Power if (Settings->energy_max_power_limit) { - if (Energy.active_power[0] > Settings->energy_max_power_limit) { - if (!Energy.mplh_counter) { - Energy.mplh_counter = Settings->energy_max_power_limit_hold; + if (Energy->active_power[0] > Settings->energy_max_power_limit) { + if (!Energy->mplh_counter) { + Energy->mplh_counter = Settings->energy_max_power_limit_hold; } else { - Energy.mplh_counter--; - if (!Energy.mplh_counter) { + Energy->mplh_counter--; + if (!Energy->mplh_counter) { ResponseTime_P(PSTR(",\"" D_JSON_MAXPOWERREACHED "\":%d}"), energy_power_u); MqttPublishPrefixTopicRulesProcess_P(STAT, S_RSLT_WARNING); EnergyMqttShow(); SetAllPower(POWER_ALL_OFF, SRC_MAXPOWER); - if (!Energy.mplr_counter) { - Energy.mplr_counter = Settings->param[P_MAX_POWER_RETRY] +1; // SetOption33 - Max Power Retry count + if (!Energy->mplr_counter) { + Energy->mplr_counter = Settings->param[P_MAX_POWER_RETRY] +1; // SetOption33 - Max Power Retry count } - Energy.mplw_counter = Settings->energy_max_power_limit_window; + Energy->mplw_counter = Settings->energy_max_power_limit_window; } } } else if (TasmotaGlobal.power && (energy_power_u <= Settings->energy_max_power_limit)) { - Energy.mplh_counter = 0; - Energy.mplr_counter = 0; - Energy.mplw_counter = 0; + Energy->mplh_counter = 0; + Energy->mplr_counter = 0; + Energy->mplw_counter = 0; } if (!TasmotaGlobal.power) { - if (Energy.mplw_counter) { - Energy.mplw_counter--; + if (Energy->mplw_counter) { + Energy->mplw_counter--; } else { - if (Energy.mplr_counter) { - Energy.mplr_counter--; - if (Energy.mplr_counter) { + if (Energy->mplr_counter) { + Energy->mplr_counter--; + if (Energy->mplr_counter) { ResponseTime_P(PSTR(",\"" D_JSON_POWERMONITOR "\":\"%s\"}"), GetStateText(1)); MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_STAT, PSTR(D_JSON_POWERMONITOR)); RestorePower(true, SRC_MAXPOWER); @@ -582,16 +585,16 @@ void EnergyMarginCheck(void) { // Max Energy if (Settings->energy_max_energy) { - uint16_t energy_daily_u = (uint16_t)(Energy.daily_sum * 1000); - if (!Energy.max_energy_state && (RtcTime.hour == Settings->energy_max_energy_start)) { - Energy.max_energy_state = 1; + uint16_t energy_daily_u = (uint16_t)(Energy->daily_sum * 1000); + if (!Energy->max_energy_state && (RtcTime.hour == Settings->energy_max_energy_start)) { + Energy->max_energy_state = 1; ResponseTime_P(PSTR(",\"" D_JSON_ENERGYMONITOR "\":\"%s\"}"), GetStateText(1)); MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_STAT, PSTR(D_JSON_ENERGYMONITOR)); RestorePower(true, SRC_MAXENERGY); } - else if ((1 == Energy.max_energy_state ) && (energy_daily_u >= Settings->energy_max_energy)) { - Energy.max_energy_state = 2; - ResponseTime_P(PSTR(",\"" D_JSON_MAXENERGYREACHED "\":%3_f}"), &Energy.daily_sum); + else if ((1 == Energy->max_energy_state ) && (energy_daily_u >= Settings->energy_max_energy)) { + Energy->max_energy_state = 2; + ResponseTime_P(PSTR(",\"" D_JSON_MAXENERGYREACHED "\":%3_f}"), &Energy->daily_sum); MqttPublishPrefixTopicRulesProcess_P(STAT, S_RSLT_WARNING); EnergyMqttShow(); SetAllPower(POWER_ALL_OFF, SRC_MAXENERGY); @@ -617,7 +620,7 @@ void EnergyMqttShow(void) void EnergyEverySecond(void) { // Overtemp check - if (Energy.use_overtemp && TasmotaGlobal.global_update) { + if (Energy->use_overtemp && TasmotaGlobal.global_update) { if (TasmotaGlobal.power && !isnan(TasmotaGlobal.temperature_celsius) && (TasmotaGlobal.temperature_celsius > (float)Settings->param[P_OVER_TEMP])) { // SetOption42 Device overtemp, turn off relays AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Temperature %1_f"), &TasmotaGlobal.temperature_celsius); @@ -628,27 +631,27 @@ void EnergyEverySecond(void) // Invalid data reset if (TasmotaGlobal.uptime > ENERGY_WATCHDOG) { - uint32_t data_valid = Energy.phase_count; - for (uint32_t i = 0; i < Energy.phase_count; i++) { - if (Energy.data_valid[i] <= ENERGY_WATCHDOG) { - Energy.data_valid[i]++; - if (Energy.data_valid[i] > ENERGY_WATCHDOG) { + uint32_t data_valid = Energy->phase_count; + for (uint32_t i = 0; i < Energy->phase_count; i++) { + if (Energy->data_valid[i] <= ENERGY_WATCHDOG) { + Energy->data_valid[i]++; + if (Energy->data_valid[i] > ENERGY_WATCHDOG) { // Reset energy registers - Energy.voltage[i] = 0; - Energy.current[i] = 0; - Energy.active_power[i] = 0; - if (!isnan(Energy.apparent_power[i])) { Energy.apparent_power[i] = 0; } - if (!isnan(Energy.reactive_power[i])) { Energy.reactive_power[i] = 0; } - if (!isnan(Energy.frequency[i])) { Energy.frequency[i] = 0; } - if (!isnan(Energy.power_factor[i])) { Energy.power_factor[i] = 0; } - if (!isnan(Energy.export_active[i])) { Energy.export_active[i] = 0; } + Energy->voltage[i] = 0; + Energy->current[i] = 0; + Energy->active_power[i] = 0; + if (!isnan(Energy->apparent_power[i])) { Energy->apparent_power[i] = 0; } + if (!isnan(Energy->reactive_power[i])) { Energy->reactive_power[i] = 0; } + if (!isnan(Energy->frequency[i])) { Energy->frequency[i] = 0; } + if (!isnan(Energy->power_factor[i])) { Energy->power_factor[i] = 0; } + if (!isnan(Energy->export_active[i])) { Energy->export_active[i] = 0; } data_valid--; } } } if (!data_valid) { - //Energy.start_energy = 0; + //Energy->start_energy = 0; AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Energy reset by invalid data")); XnrgCall(FUNC_ENERGY_RESET); @@ -670,22 +673,22 @@ void ResponseCmndEnergyTotalYesterdayToday(void) { char value3_chr[TOPSZ]; float energy_yesterday_ph[3]; - for (uint32_t i = 0; i < Energy.phase_count; i++) { + for (uint32_t i = 0; i < Energy->phase_count; i++) { energy_yesterday_ph[i] = (float)Settings->energy_kWhyesterday_ph[i] / 100000; - Energy.total[i] = ((float)(RtcSettings.energy_kWhtotal_ph[i]) / 1000) + ((float)(Energy.kWhtoday_offset[i] + Energy.kWhtoday[i]) / 100000); - if (Energy.local_energy_active_export) { - Energy.export_active[i] = (float)(RtcSettings.energy_kWhexport_ph[i]) / 1000; + Energy->total[i] = ((float)(RtcSettings.energy_kWhtotal_ph[i]) / 1000) + ((float)(Energy->kWhtoday_offset[i] + Energy->kWhtoday[i]) / 100000); + if (Energy->local_energy_active_export) { + Energy->export_active[i] = (float)(RtcSettings.energy_kWhexport_ph[i]) / 1000; } } Response_P(PSTR("{\"%s\":{\"" D_JSON_TOTAL "\":%s,\"" D_JSON_YESTERDAY "\":%s,\"" D_JSON_TODAY "\":%s"), XdrvMailbox.command, - EnergyFormat(value_chr, Energy.total, Settings->flag2.energy_resolution), + EnergyFormat(value_chr, Energy->total, Settings->flag2.energy_resolution), EnergyFormat(value2_chr, energy_yesterday_ph, Settings->flag2.energy_resolution), - EnergyFormat(value3_chr, Energy.daily, Settings->flag2.energy_resolution)); - if (Energy.local_energy_active_export) { + EnergyFormat(value3_chr, Energy->daily, Settings->flag2.energy_resolution)); + if (Energy->local_energy_active_export) { ResponseAppend_P(PSTR(",\"" D_JSON_EXPORT_ACTIVE "\":%s"), - EnergyFormat(value_chr, Energy.export_active, Settings->flag2.energy_resolution)); + EnergyFormat(value_chr, Energy->export_active, Settings->flag2.energy_resolution)); } ResponseJsonEndEnd(); } @@ -694,7 +697,7 @@ void CmndEnergyTotal(void) { uint32_t values[2] = { 0 }; uint32_t params = ParseParameters(2, values); - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= Energy.phase_count) && (params > 0)) { + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= Energy->phase_count) && (params > 0)) { uint32_t phase = XdrvMailbox.index -1; // Reset Energy Total RtcSettings.energy_kWhtotal_ph[phase] = values[0]; @@ -702,9 +705,9 @@ void CmndEnergyTotal(void) { if (params > 1) { Settings->energy_kWhtotal_time = values[1]; } else { - Settings->energy_kWhtotal_time = (!Energy.kWhtoday_offset[phase]) ? LocalTime() : Midnight(); + Settings->energy_kWhtotal_time = (!Energy->kWhtoday_offset[phase]) ? LocalTime() : Midnight(); } - RtcSettings.energy_usage.last_usage_kWhtotal = (uint32_t)(Energy.total[phase] * 1000); + RtcSettings.energy_usage.last_usage_kWhtotal = (uint32_t)(Energy->total[phase] * 1000); } ResponseCmndEnergyTotalYesterdayToday(); } @@ -713,7 +716,7 @@ void CmndEnergyYesterday(void) { uint32_t values[2] = { 0 }; uint32_t params = ParseParameters(2, values); - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= Energy.phase_count) && (params > 0)) { + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= Energy->phase_count) && (params > 0)) { uint32_t phase = XdrvMailbox.index -1; // Reset Energy Yesterday Settings->energy_kWhyesterday_ph[phase] = values[0] * 100; @@ -728,21 +731,21 @@ void CmndEnergyToday(void) { uint32_t values[2] = { 0 }; uint32_t params = ParseParameters(2, values); - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= Energy.phase_count) && (params > 0)) { + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= Energy->phase_count) && (params > 0)) { uint32_t phase = XdrvMailbox.index -1; // Reset Energy Today - Energy.kWhtoday_offset[phase] = values[0] * 100; - Energy.kWhtoday[phase] = 0; - Energy.kWhtoday_delta[phase] = 0; - Energy.start_energy[phase] = 0; - Energy.period[phase] = Energy.kWhtoday_offset[phase]; - Settings->energy_kWhtoday_ph[phase] = Energy.kWhtoday_offset[phase]; - RtcSettings.energy_kWhtoday_ph[phase] = Energy.kWhtoday_offset[phase]; - Energy.daily[phase] = (float)Energy.kWhtoday_offset[phase] / 100000; + Energy->kWhtoday_offset[phase] = values[0] * 100; + Energy->kWhtoday[phase] = 0; + Energy->kWhtoday_delta[phase] = 0; + Energy->start_energy[phase] = 0; + Energy->period[phase] = Energy->kWhtoday_offset[phase]; + Settings->energy_kWhtoday_ph[phase] = Energy->kWhtoday_offset[phase]; + RtcSettings.energy_kWhtoday_ph[phase] = Energy->kWhtoday_offset[phase]; + Energy->daily[phase] = (float)Energy->kWhtoday_offset[phase] / 100000; if (params > 1) { Settings->energy_kWhtotal_time = values[1]; } - else if (!RtcSettings.energy_kWhtotal_ph[phase] && !Energy.kWhtoday_offset[phase]) { + else if (!RtcSettings.energy_kWhtotal_ph[phase] && !Energy->kWhtoday_offset[phase]) { Settings->energy_kWhtotal_time = LocalTime(); } } @@ -750,13 +753,13 @@ void CmndEnergyToday(void) { } void CmndEnergyExportActive(void) { - if (Energy.local_energy_active_export) { + if (Energy->local_energy_active_export) { // EnergyExportActive1 24 // EnergyExportActive1 24,1650111291 uint32_t values[2] = { 0 }; uint32_t params = ParseParameters(2, values); - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= Energy.phase_count) && (params > 0)) { + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= Energy->phase_count) && (params > 0)) { uint32_t phase = XdrvMailbox.index -1; // Reset Energy Export Active RtcSettings.energy_kWhexport_ph[phase] = values[0]; @@ -858,7 +861,7 @@ void CmndTariff(void) { } uint32_t EnergyGetCalibration(uint32_t chan, uint32_t cal_type) { - uint32_t channel = ((1 == chan) && (2 == Energy.phase_count)) ? 1 : 0; + uint32_t channel = ((1 == chan) && (2 == Energy->phase_count)) ? 1 : 0; if (channel) { switch (cal_type) { case ENERGY_POWER_CALIBRATION: return Settings->energy_power_calibration2; @@ -877,7 +880,7 @@ uint32_t EnergyGetCalibration(uint32_t chan, uint32_t cal_type) { void EnergyCommandCalSetResponse(uint32_t cal_type) { if (XdrvMailbox.payload > 99) { - uint32_t channel = ((2 == XdrvMailbox.index) && (2 == Energy.phase_count)) ? 1 : 0; + uint32_t channel = ((2 == XdrvMailbox.index) && (2 == Energy->phase_count)) ? 1 : 0; if (channel) { switch (cal_type) { case ENERGY_POWER_CALIBRATION: Settings->energy_power_calibration2 = XdrvMailbox.payload; break; @@ -897,7 +900,7 @@ void EnergyCommandCalSetResponse(uint32_t cal_type) { if (ENERGY_FREQUENCY_CALIBRATION == cal_type) { ResponseAppend_P(PSTR("%d}"), Settings->energy_frequency_calibration); } else { - if (2 == Energy.phase_count) { + if (2 == Energy->phase_count) { ResponseAppend_P(PSTR("[%d,%d]}"), EnergyGetCalibration(0, cal_type), EnergyGetCalibration(1, cal_type)); } else { ResponseAppend_P(PSTR("%d}"), EnergyGetCalibration(0, cal_type)); @@ -916,64 +919,64 @@ void EnergyCommandSetCalResponse(uint32_t cal_type) { } void CmndPowerCal(void) { - Energy.command_code = CMND_POWERCAL; + Energy->command_code = CMND_POWERCAL; if (XnrgCall(FUNC_COMMAND)) { // microseconds EnergyCommandCalResponse(ENERGY_POWER_CALIBRATION); } } void CmndVoltageCal(void) { - Energy.command_code = CMND_VOLTAGECAL; + Energy->command_code = CMND_VOLTAGECAL; if (XnrgCall(FUNC_COMMAND)) { // microseconds EnergyCommandCalResponse(ENERGY_VOLTAGE_CALIBRATION); } } void CmndCurrentCal(void) { - Energy.command_code = CMND_CURRENTCAL; + Energy->command_code = CMND_CURRENTCAL; if (XnrgCall(FUNC_COMMAND)) { // microseconds EnergyCommandCalResponse(ENERGY_CURRENT_CALIBRATION); } } void CmndFrequencyCal(void) { - Energy.command_code = CMND_FREQUENCYCAL; + Energy->command_code = CMND_FREQUENCYCAL; if (XnrgCall(FUNC_COMMAND)) { // microseconds EnergyCommandCalResponse(ENERGY_FREQUENCY_CALIBRATION); } } void CmndPowerSet(void) { - Energy.command_code = CMND_POWERSET; + Energy->command_code = CMND_POWERSET; if (XnrgCall(FUNC_COMMAND)) { // Watt EnergyCommandSetCalResponse(ENERGY_POWER_CALIBRATION); } } void CmndVoltageSet(void) { - Energy.command_code = CMND_VOLTAGESET; + Energy->command_code = CMND_VOLTAGESET; if (XnrgCall(FUNC_COMMAND)) { // Volt EnergyCommandSetCalResponse(ENERGY_VOLTAGE_CALIBRATION); } } void CmndCurrentSet(void) { - Energy.command_code = CMND_CURRENTSET; + Energy->command_code = CMND_CURRENTSET; if (XnrgCall(FUNC_COMMAND)) { // milliAmpere EnergyCommandSetCalResponse(ENERGY_CURRENT_CALIBRATION); } } void CmndFrequencySet(void) { - Energy.command_code = CMND_FREQUENCYSET; + Energy->command_code = CMND_FREQUENCYSET; if (XnrgCall(FUNC_COMMAND)) { // Hz EnergyCommandSetCalResponse(ENERGY_FREQUENCY_CALIBRATION); } } void CmndModuleAddress(void) { - if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 4) && (1 == Energy.phase_count)) { - Energy.command_code = CMND_MODULEADDRESS; + if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 4) && (1 == Energy->phase_count)) { + Energy->command_code = CMND_MODULEADDRESS; if (XnrgCall(FUNC_COMMAND)) { // Module address ResponseCmndDone(); } @@ -981,7 +984,7 @@ void CmndModuleAddress(void) { } void CmndEnergyConfig(void) { - Energy.command_code = CMND_ENERGYCONFIG; + Energy->command_code = CMND_ENERGYCONFIG; ResponseClear(); if (XnrgCall(FUNC_COMMAND)) { if (!ResponseLength()) { @@ -1088,7 +1091,7 @@ void CmndSafePowerWindow(void) { void CmndMaxEnergy(void) { if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 6000)) { Settings->energy_max_energy = XdrvMailbox.payload; - Energy.max_energy_state = 3; + Energy->max_energy_state = 3; } ResponseCmndNumber(Settings->energy_max_energy); } @@ -1103,21 +1106,23 @@ void CmndMaxEnergyStart(void) { #endif // USE_ENERGY_MARGIN_DETECTION void EnergyDrvInit(void) { - memset(&Energy, 0, sizeof(Energy)); // Reset all to 0 and false; -// Energy.voltage_common = false; -// Energy.frequency_common = false; -// Energy.use_overtemp = false; + Energy = (tEnergy*)calloc(sizeof(tEnergy), 1); // Need calloc to reset registers to 0/false + if (!Energy) { return; } + +// Energy->voltage_common = false; +// Energy->frequency_common = false; +// Energy->use_overtemp = false; for (uint32_t phase = 0; phase < ENERGY_MAX_PHASES; phase++) { - Energy.apparent_power[phase] = NAN; - Energy.reactive_power[phase] = NAN; - Energy.power_factor[phase] = NAN; - Energy.frequency[phase] = NAN; - Energy.export_active[phase] = NAN; + Energy->apparent_power[phase] = NAN; + Energy->reactive_power[phase] = NAN; + Energy->power_factor[phase] = NAN; + Energy->frequency[phase] = NAN; + Energy->export_active[phase] = NAN; } - Energy.phase_count = 1; // Number of phases active - Energy.voltage_available = true; // Enable if voltage is measured - Energy.current_available = true; // Enable if current is measured - Energy.power_on = true; + Energy->phase_count = 1; // Number of phases active + Energy->voltage_available = true; // Enable if voltage is measured + Energy->current_available = true; // Enable if current is measured + Energy->power_on = true; TasmotaGlobal.energy_driver = ENERGY_NONE; XnrgCall(FUNC_PRE_INIT); // Find first energy driver @@ -1139,18 +1144,18 @@ void EnergySnsInit(void) ); */ for (uint32_t i = 0; i < 3; i++) { -// Energy.kWhtoday_offset[i] = 0; // Reset by EnergyDrvInit() +// Energy->kWhtoday_offset[i] = 0; // Reset by EnergyDrvInit() // 20220805 - Change from https://github.com/arendst/Tasmota/issues/16118 if (RtcSettingsValid()) { - Energy.kWhtoday_offset[i] = RtcSettings.energy_kWhtoday_ph[i]; + Energy->kWhtoday_offset[i] = RtcSettings.energy_kWhtoday_ph[i]; RtcSettings.energy_kWhtoday_ph[i] = 0; - Energy.kWhtoday_offset_init = true; + Energy->kWhtoday_offset_init = true; } -// Energy.kWhtoday_ph[i] = 0; // Reset by EnergyDrvInit() -// Energy.kWhtoday_delta[i] = 0; // Reset by EnergyDrvInit() - Energy.period[i] = Energy.kWhtoday_offset[i]; - if (Energy.local_energy_active_export) { - Energy.export_active[i] = 0; // Was set to NAN by EnergyDrvInit() +// Energy->kWhtoday_ph[i] = 0; // Reset by EnergyDrvInit() +// Energy->kWhtoday_delta[i] = 0; // Reset by EnergyDrvInit() + Energy->period[i] = Energy->kWhtoday_offset[i]; + if (Energy->local_energy_active_export) { + Energy->export_active[i] = 0; // Was set to NAN by EnergyDrvInit() } } EnergyUpdateToday(); @@ -1174,43 +1179,43 @@ const char HTTP_ENERGY_SNS3[] PROGMEM = #endif // USE_WEBSERVER void EnergyShow(bool json) { - if (Energy.voltage_common) { - for (uint32_t i = 0; i < Energy.phase_count; i++) { - Energy.voltage[i] = Energy.voltage[0]; + if (Energy->voltage_common) { + for (uint32_t i = 0; i < Energy->phase_count; i++) { + Energy->voltage[i] = Energy->voltage[0]; } } - float apparent_power[Energy.phase_count]; - float reactive_power[Energy.phase_count]; - float power_factor[Energy.phase_count]; - if (!Energy.type_dc) { - if (Energy.current_available && Energy.voltage_available) { - for (uint32_t i = 0; i < Energy.phase_count; i++) { - apparent_power[i] = Energy.apparent_power[i]; + float apparent_power[Energy->phase_count]; + float reactive_power[Energy->phase_count]; + float power_factor[Energy->phase_count]; + if (!Energy->type_dc) { + if (Energy->current_available && Energy->voltage_available) { + for (uint32_t i = 0; i < Energy->phase_count; i++) { + apparent_power[i] = Energy->apparent_power[i]; if (isnan(apparent_power[i])) { - apparent_power[i] = Energy.voltage[i] * Energy.current[i]; + apparent_power[i] = Energy->voltage[i] * Energy->current[i]; } - if (apparent_power[i] < Energy.active_power[i]) { // Should be impossible - Energy.active_power[i] = apparent_power[i]; + if (apparent_power[i] < Energy->active_power[i]) { // Should be impossible + Energy->active_power[i] = apparent_power[i]; } - power_factor[i] = Energy.power_factor[i]; + power_factor[i] = Energy->power_factor[i]; if (isnan(power_factor[i])) { - power_factor[i] = (Energy.active_power[i] && apparent_power[i]) ? Energy.active_power[i] / apparent_power[i] : 0; + power_factor[i] = (Energy->active_power[i] && apparent_power[i]) ? Energy->active_power[i] / apparent_power[i] : 0; if (power_factor[i] > 1) { power_factor[i] = 1; } } - reactive_power[i] = Energy.reactive_power[i]; + reactive_power[i] = Energy->reactive_power[i]; if (isnan(reactive_power[i])) { reactive_power[i] = 0; - uint32_t difference = ((uint32_t)(apparent_power[i] * 100) - (uint32_t)(Energy.active_power[i] * 100)) / 10; - if ((Energy.current[i] > 0.005f) && ((difference > 15) || (difference > (uint32_t)(apparent_power[i] * 100 / 1000)))) { + uint32_t difference = ((uint32_t)(apparent_power[i] * 100) - (uint32_t)(Energy->active_power[i] * 100)) / 10; + if ((Energy->current[i] > 0.005f) && ((difference > 15) || (difference > (uint32_t)(apparent_power[i] * 100 / 1000)))) { // calculating reactive power only if current is greater than 0.005A and // difference between active and apparent power is greater than 1.5W or 1% - //reactive_power[i] = (float)(RoundSqrtInt((uint64_t)(apparent_power[i] * apparent_power[i] * 100) - (uint64_t)(Energy.active_power[i] * Energy.active_power[i] * 100))) / 10; - float power_diff = apparent_power[i] * apparent_power[i] - Energy.active_power[i] * Energy.active_power[i]; + //reactive_power[i] = (float)(RoundSqrtInt((uint64_t)(apparent_power[i] * apparent_power[i] * 100) - (uint64_t)(Energy->active_power[i] * Energy->active_power[i] * 100))) / 10; + float power_diff = apparent_power[i] * apparent_power[i] - Energy->active_power[i] * Energy->active_power[i]; if (power_diff < 10737418) // 2^30 / 100 (RoundSqrtInt is limited to 2^30-1) reactive_power[i] = (float)(RoundSqrtInt((uint32_t)(power_diff * 100.0f))) / 10.0f; else @@ -1223,11 +1228,11 @@ void EnergyShow(bool json) { } float active_power_sum = 0.0f; - float energy_yesterday_ph[Energy.phase_count]; - for (uint32_t i = 0; i < Energy.phase_count; i++) { + float energy_yesterday_ph[Energy->phase_count]; + for (uint32_t i = 0; i < Energy->phase_count; i++) { energy_yesterday_ph[i] = (float)Settings->energy_kWhyesterday_ph[i] / 100000; - active_power_sum += Energy.active_power[i]; + active_power_sum += Energy->active_power[i]; } bool energy_tariff = false; @@ -1250,7 +1255,7 @@ void EnergyShow(bool json) { ResponseAppend_P(PSTR(",\"" D_RSLT_ENERGY "\":{\"" D_JSON_TOTAL_START_TIME "\":\"%s\",\"" D_JSON_TOTAL "\":%s"), GetDateAndTime(DT_ENERGY).c_str(), - EnergyFormat(value_chr, Energy.total, Settings->flag2.energy_resolution, 2)); + EnergyFormat(value_chr, Energy->total, Settings->flag2.energy_resolution, 2)); if (energy_tariff) { ResponseAppend_P(PSTR(",\"" D_JSON_TOTAL D_CMND_TARIFF "\":%s"), @@ -1259,13 +1264,13 @@ void EnergyShow(bool json) { ResponseAppend_P(PSTR(",\"" D_JSON_YESTERDAY "\":%s,\"" D_JSON_TODAY "\":%s"), EnergyFormat(value_chr, energy_yesterday_ph, Settings->flag2.energy_resolution, 2), - EnergyFormat(value2_chr, Energy.daily, Settings->flag2.energy_resolution, 2)); + EnergyFormat(value2_chr, Energy->daily, Settings->flag2.energy_resolution, 2)); /* #if defined(SDM630_IMPORT) || defined(SDM72_IMPEXP) - if (!isnan(Energy.import_active[0])) { + if (!isnan(Energy->import_active[0])) { ResponseAppend_P(PSTR(",\"" D_JSON_IMPORT_ACTIVE "\":%s"), - EnergyFormat(value_chr, Energy.import_active, Settings->flag2.energy_resolution)); + EnergyFormat(value_chr, Energy->import_active, Settings->flag2.energy_resolution)); if (energy_tariff) { ResponseAppend_P(PSTR(",\"" D_JSON_IMPORT D_CMND_TARIFF "\":%s"), EnergyFormat(value_chr, energy_return, Settings->flag2.energy_resolution, 6)); @@ -1274,12 +1279,12 @@ void EnergyShow(bool json) { #endif // SDM630_IMPORT || SDM72_IMPEXP */ - if (!isnan(Energy.export_active[0])) { - uint32_t single = (!isnan(Energy.export_active[1]) && !isnan(Energy.export_active[2])) ? 0 : 1; + if (!isnan(Energy->export_active[0])) { + uint32_t single = (!isnan(Energy->export_active[1]) && !isnan(Energy->export_active[2])) ? 0 : 1; ResponseAppend_P(PSTR(",\"" D_JSON_TODAY_SUM_IMPORT "\":%s,\"" D_JSON_TODAY_SUM_EXPORT "\":%s,\"" D_JSON_EXPORT_ACTIVE "\":%s"), - EnergyFormat(value_chr, &Energy.daily_sum_import_balanced, Settings->flag2.energy_resolution, 1), - EnergyFormat(value2_chr, &Energy.daily_sum_export_balanced, Settings->flag2.energy_resolution, 1), - EnergyFormat(value3_chr, Energy.export_active, Settings->flag2.energy_resolution, single)); + EnergyFormat(value_chr, &Energy->daily_sum_import_balanced, Settings->flag2.energy_resolution, 1), + EnergyFormat(value2_chr, &Energy->daily_sum_export_balanced, Settings->flag2.energy_resolution, 1), + EnergyFormat(value3_chr, Energy->export_active, Settings->flag2.energy_resolution, single)); if (energy_tariff) { ResponseAppend_P(PSTR(",\"" D_JSON_EXPORT D_CMND_TARIFF "\":%s"), EnergyFormat(value_chr, energy_return, Settings->flag2.energy_resolution, 6)); @@ -1287,36 +1292,36 @@ void EnergyShow(bool json) { } if (show_energy_period) { - float energy_period[Energy.phase_count]; - for (uint32_t i = 0; i < Energy.phase_count; i++) { - energy_period[i] = (float)(RtcSettings.energy_kWhtoday_ph[i] - Energy.period[i]) / 100; - Energy.period[i] = RtcSettings.energy_kWhtoday_ph[i]; + float energy_period[Energy->phase_count]; + for (uint32_t i = 0; i < Energy->phase_count; i++) { + energy_period[i] = (float)(RtcSettings.energy_kWhtoday_ph[i] - Energy->period[i]) / 100; + Energy->period[i] = RtcSettings.energy_kWhtoday_ph[i]; } ResponseAppend_P(PSTR(",\"" D_JSON_PERIOD "\":%s"), EnergyFormat(value_chr, energy_period, Settings->flag2.wattage_resolution)); } ResponseAppend_P(PSTR(",\"" D_JSON_POWERUSAGE "\":%s"), - EnergyFormat(value_chr, Energy.active_power, Settings->flag2.wattage_resolution)); - if (!Energy.type_dc) { - if (Energy.current_available && Energy.voltage_available) { + EnergyFormat(value_chr, Energy->active_power, Settings->flag2.wattage_resolution)); + if (!Energy->type_dc) { + if (Energy->current_available && Energy->voltage_available) { ResponseAppend_P(PSTR(",\"" D_JSON_APPARENT_POWERUSAGE "\":%s,\"" D_JSON_REACTIVE_POWERUSAGE "\":%s,\"" D_JSON_POWERFACTOR "\":%s"), EnergyFormat(value_chr, apparent_power, Settings->flag2.wattage_resolution), EnergyFormat(value2_chr, reactive_power, Settings->flag2.wattage_resolution), EnergyFormat(value3_chr, power_factor, 2)); } - if (!isnan(Energy.frequency[0])) { + if (!isnan(Energy->frequency[0])) { ResponseAppend_P(PSTR(",\"" D_JSON_FREQUENCY "\":%s"), - EnergyFormat(value_chr, Energy.frequency, Settings->flag2.frequency_resolution, Energy.frequency_common)); + EnergyFormat(value_chr, Energy->frequency, Settings->flag2.frequency_resolution, Energy->frequency_common)); } } - if (Energy.voltage_available) { + if (Energy->voltage_available) { ResponseAppend_P(PSTR(",\"" D_JSON_VOLTAGE "\":%s"), - EnergyFormat(value_chr, Energy.voltage, Settings->flag2.voltage_resolution, Energy.voltage_common)); + EnergyFormat(value_chr, Energy->voltage, Settings->flag2.voltage_resolution, Energy->voltage_common)); } - if (Energy.current_available) { + if (Energy->current_available) { ResponseAppend_P(PSTR(",\"" D_JSON_CURRENT "\":%s"), - EnergyFormat(value_chr, Energy.current, Settings->flag2.current_resolution)); + EnergyFormat(value_chr, Energy->current, Settings->flag2.current_resolution)); } XnrgCall(FUNC_JSON_APPEND); ResponseJsonEnd(); @@ -1324,15 +1329,15 @@ void EnergyShow(bool json) { #ifdef USE_DOMOTICZ if (show_energy_period) { // Only send if telemetry char temp_chr[FLOATSZ]; - if (Energy.voltage_available) { - dtostrfd(Energy.voltage[0], Settings->flag2.voltage_resolution, temp_chr); + if (Energy->voltage_available) { + dtostrfd(Energy->voltage[0], Settings->flag2.voltage_resolution, temp_chr); DomoticzSensor(DZ_VOLTAGE, temp_chr); // Voltage } - if (Energy.current_available) { - dtostrfd(Energy.current[0], Settings->flag2.current_resolution, temp_chr); + if (Energy->current_available) { + dtostrfd(Energy->current[0], Settings->flag2.current_resolution, temp_chr); DomoticzSensor(DZ_CURRENT, temp_chr); // Current } - dtostrfd(Energy.total_sum * 1000, 1, temp_chr); + dtostrfd(Energy->total_sum * 1000, 1, temp_chr); DomoticzSensorPowerEnergy((int)active_power_sum, temp_chr); // PowerUsage, EnergyToday char energy_usage_chr[2][FLOATSZ]; @@ -1347,19 +1352,19 @@ void EnergyShow(bool json) { #endif // USE_DOMOTICZ #ifdef USE_KNX if (show_energy_period) { - if (Energy.voltage_available) { - KnxSensor(KNX_ENERGY_VOLTAGE, Energy.voltage[0]); + if (Energy->voltage_available) { + KnxSensor(KNX_ENERGY_VOLTAGE, Energy->voltage[0]); } - if (Energy.current_available) { - KnxSensor(KNX_ENERGY_CURRENT, Energy.current[0]); + if (Energy->current_available) { + KnxSensor(KNX_ENERGY_CURRENT, Energy->current[0]); } KnxSensor(KNX_ENERGY_POWER, active_power_sum); - if (!Energy.type_dc) { + if (!Energy->type_dc) { KnxSensor(KNX_ENERGY_POWERFACTOR, power_factor[0]); } - KnxSensor(KNX_ENERGY_DAILY, Energy.daily_sum); - KnxSensor(KNX_ENERGY_TOTAL, Energy.total_sum); - KnxSensor(KNX_ENERGY_YESTERDAY, Energy.yesterday_sum); + KnxSensor(KNX_ENERGY_DAILY, Energy->daily_sum); + KnxSensor(KNX_ENERGY_TOTAL, Energy->total_sum); + KnxSensor(KNX_ENERGY_YESTERDAY, Energy->yesterday_sum); } #endif // USE_KNX #ifdef USE_WEBSERVER @@ -1371,38 +1376,38 @@ void EnergyShow(bool json) { // {s}Head1Head2Head3{e} // {s}Head1Head2Head3Head4{e} WSContentSend_P(PSTR("
{t}{s}")); // First column is empty ({t} = , {s} = "), (no_label)?"":"L", (no_label)?"":itoa(i +1, value_chr, 10)); } WSContentSend_P(PSTR(") #endif // USE_ENERGY_COLUMN_GUI - if (Energy.voltage_available) { - WSContentSend_PD(HTTP_SNS_VOLTAGE, WebEnergyFormat(value_chr, Energy.voltage, Settings->flag2.voltage_resolution, Energy.voltage_common)); + if (Energy->voltage_available) { + WSContentSend_PD(HTTP_SNS_VOLTAGE, WebEnergyFormat(value_chr, Energy->voltage, Settings->flag2.voltage_resolution, Energy->voltage_common)); } - if (!Energy.type_dc) { - if (!isnan(Energy.frequency[0])) { + if (!Energy->type_dc) { + if (!isnan(Energy->frequency[0])) { WSContentSend_PD(PSTR("{s}" D_FREQUENCY "{m}%s " D_UNIT_HERTZ "{e}"), - WebEnergyFormat(value_chr, Energy.frequency, Settings->flag2.frequency_resolution, Energy.frequency_common)); + WebEnergyFormat(value_chr, Energy->frequency, Settings->flag2.frequency_resolution, Energy->frequency_common)); } } - if (Energy.current_available) { - WSContentSend_PD(HTTP_SNS_CURRENT, WebEnergyFormat(value_chr, Energy.current, Settings->flag2.current_resolution)); + if (Energy->current_available) { + WSContentSend_PD(HTTP_SNS_CURRENT, WebEnergyFormat(value_chr, Energy->current, Settings->flag2.current_resolution)); } - WSContentSend_PD(HTTP_SNS_POWER, WebEnergyFormat(value_chr, Energy.active_power, Settings->flag2.wattage_resolution)); - if (!Energy.type_dc) { - if (Energy.current_available && Energy.voltage_available) { + WSContentSend_PD(HTTP_SNS_POWER, WebEnergyFormat(value_chr, Energy->active_power, Settings->flag2.wattage_resolution)); + if (!Energy->type_dc) { + if (Energy->current_available && Energy->voltage_available) { WSContentSend_PD(HTTP_ENERGY_SNS1, WebEnergyFormat(value_chr, apparent_power, Settings->flag2.wattage_resolution), WebEnergyFormat(value2_chr, reactive_power, Settings->flag2.wattage_resolution), WebEnergyFormat(value3_chr, power_factor, 2)); } } - WSContentSend_PD(HTTP_ENERGY_SNS2, WebEnergyFormat(value_chr, Energy.daily, Settings->flag2.energy_resolution, 2), + WSContentSend_PD(HTTP_ENERGY_SNS2, WebEnergyFormat(value_chr, Energy->daily, Settings->flag2.energy_resolution, 2), WebEnergyFormat(value2_chr, energy_yesterday_ph, Settings->flag2.energy_resolution, 2), - WebEnergyFormat(value3_chr, Energy.total, Settings->flag2.energy_resolution, 2)); - if (!isnan(Energy.export_active[0])) { - uint32_t single = (!isnan(Energy.export_active[1]) && !isnan(Energy.export_active[2])) ? 2 : 1; - WSContentSend_PD(HTTP_ENERGY_SNS3, WebEnergyFormat(value_chr, Energy.export_active, Settings->flag2.energy_resolution, single)); + WebEnergyFormat(value3_chr, Energy->total, Settings->flag2.energy_resolution, 2)); + if (!isnan(Energy->export_active[0])) { + uint32_t single = (!isnan(Energy->export_active[1]) && !isnan(Energy->export_active[2])) ? 2 : 1; + WSContentSend_PD(HTTP_ENERGY_SNS3, WebEnergyFormat(value_chr, Energy->export_active, Settings->flag2.energy_resolution, single)); } #ifdef USE_ENERGY_COLUMN_GUI XnrgCall(FUNC_WEB_COL_SENSOR); @@ -1443,7 +1448,7 @@ bool Xdrv03(uint32_t function) break; #ifdef USE_ENERGY_MARGIN_DETECTION case FUNC_SET_POWER: - Energy.power_steady_counter = 2; + Energy->power_steady_counter = 2; break; #endif // USE_ENERGY_MARGIN_DETECTION case FUNC_COMMAND: @@ -1489,3 +1494,4 @@ bool Xsns03(uint32_t function) } #endif // USE_ENERGY_SENSOR +//#endif // ESP8266 diff --git a/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino b/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino index ecfc0d418..5d02340d5 100755 --- a/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino @@ -2773,43 +2773,43 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); while (*lp==' ') lp++; switch ((uint32_t)fvar) { case 0: - fvar = Energy.total_sum; + fvar = Energy->total_sum; break; case 1: - fvar = Energy.voltage[0]; + fvar = Energy->voltage[0]; break; case 2: - fvar = Energy.voltage[1]; + fvar = Energy->voltage[1]; break; case 3: - fvar = Energy.voltage[2]; + fvar = Energy->voltage[2]; break; case 4: - fvar = Energy.current[0]; + fvar = Energy->current[0]; break; case 5: - fvar = Energy.current[1]; + fvar = Energy->current[1]; break; case 6: - fvar = Energy.current[2]; + fvar = Energy->current[2]; break; case 7: - fvar = Energy.active_power[0]; + fvar = Energy->active_power[0]; break; case 8: - fvar = Energy.active_power[1]; + fvar = Energy->active_power[1]; break; case 9: - fvar = Energy.active_power[2]; + fvar = Energy->active_power[2]; break; case 10: - fvar = Energy.start_energy[0]; + fvar = Energy->start_energy[0]; break; case 11: - fvar = Energy.daily_sum; + fvar = Energy->daily_sum; break; case 12: - fvar = Energy.yesterday_sum; + fvar = Energy->yesterday_sum; break; default: diff --git a/tasmota/tasmota_xdrv_driver/xdrv_11_knx.ino b/tasmota/tasmota_xdrv_driver/xdrv_11_knx.ino index 04d1225d3..ef08718c1 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_11_knx.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_11_knx.ino @@ -649,58 +649,58 @@ void KNX_CB_Action(message_t const &msg, void *arg) #if defined(USE_ENERGY_SENSOR) else if (chan->type == KNX_ENERGY_VOLTAGE) // Reply KNX_ENERGY_VOLTAGE { - knx.answer_4byte_float(msg.received_on, Energy.voltage[0]); + knx.answer_4byte_float(msg.received_on, Energy->voltage[0]); if (Settings->flag.knx_enable_enhancement) { - knx.answer_4byte_float(msg.received_on, Energy.voltage[0]); - knx.answer_4byte_float(msg.received_on, Energy.voltage[0]); + knx.answer_4byte_float(msg.received_on, Energy->voltage[0]); + knx.answer_4byte_float(msg.received_on, Energy->voltage[0]); } } else if (chan->type == KNX_ENERGY_CURRENT) // Reply KNX_ENERGY_CURRENT { - knx.answer_4byte_float(msg.received_on, Energy.current[0]); + knx.answer_4byte_float(msg.received_on, Energy->current[0]); if (Settings->flag.knx_enable_enhancement) { - knx.answer_4byte_float(msg.received_on, Energy.current[0]); - knx.answer_4byte_float(msg.received_on, Energy.current[0]); + knx.answer_4byte_float(msg.received_on, Energy->current[0]); + knx.answer_4byte_float(msg.received_on, Energy->current[0]); } } else if (chan->type == KNX_ENERGY_POWER) // Reply KNX_ENERGY_POWER { - knx.answer_4byte_float(msg.received_on, Energy.active_power[0]); + knx.answer_4byte_float(msg.received_on, Energy->active_power[0]); if (Settings->flag.knx_enable_enhancement) { - knx.answer_4byte_float(msg.received_on, Energy.active_power[0]); - knx.answer_4byte_float(msg.received_on, Energy.active_power[0]); + knx.answer_4byte_float(msg.received_on, Energy->active_power[0]); + knx.answer_4byte_float(msg.received_on, Energy->active_power[0]); } } else if (chan->type == KNX_ENERGY_POWERFACTOR) // Reply KNX_ENERGY_POWERFACTOR { - knx.answer_4byte_float(msg.received_on, Energy.power_factor[0]); + knx.answer_4byte_float(msg.received_on, Energy->power_factor[0]); if (Settings->flag.knx_enable_enhancement) { - knx.answer_4byte_float(msg.received_on, Energy.power_factor[0]); - knx.answer_4byte_float(msg.received_on, Energy.power_factor[0]); + knx.answer_4byte_float(msg.received_on, Energy->power_factor[0]); + knx.answer_4byte_float(msg.received_on, Energy->power_factor[0]); } } else if (chan->type == KNX_ENERGY_YESTERDAY) // Reply KNX_ENERGY_YESTERDAY { - knx.answer_4byte_float(msg.received_on, Energy.yesterday_sum); + knx.answer_4byte_float(msg.received_on, Energy->yesterday_sum); if (Settings->flag.knx_enable_enhancement) { - knx.answer_4byte_float(msg.received_on, Energy.yesterday_sum); - knx.answer_4byte_float(msg.received_on, Energy.yesterday_sum); + knx.answer_4byte_float(msg.received_on, Energy->yesterday_sum); + knx.answer_4byte_float(msg.received_on, Energy->yesterday_sum); } } else if (chan->type == KNX_ENERGY_DAILY) // Reply KNX_ENERGY_DAILY { - knx.answer_4byte_float(msg.received_on, Energy.daily_sum); + knx.answer_4byte_float(msg.received_on, Energy->daily_sum); if (Settings->flag.knx_enable_enhancement) { - knx.answer_4byte_float(msg.received_on, Energy.daily_sum); - knx.answer_4byte_float(msg.received_on, Energy.daily_sum); + knx.answer_4byte_float(msg.received_on, Energy->daily_sum); + knx.answer_4byte_float(msg.received_on, Energy->daily_sum); } } else if (chan->type == KNX_ENERGY_TOTAL) // Reply KNX_ENERGY_TOTAL { - knx.answer_4byte_float(msg.received_on, Energy.total_sum); + knx.answer_4byte_float(msg.received_on, Energy->total_sum); if (Settings->flag.knx_enable_enhancement) { - knx.answer_4byte_float(msg.received_on, Energy.total_sum); - knx.answer_4byte_float(msg.received_on, Energy.total_sum); + knx.answer_4byte_float(msg.received_on, Energy->total_sum); + knx.answer_4byte_float(msg.received_on, Energy->total_sum); } } #endif diff --git a/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v1.ino b/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v1.ino index 3f90044b9..54633d8a5 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v1.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v1.ino @@ -812,16 +812,16 @@ void TuyaProcessStatePacket(void) { uint16_t tmpVol = Tuya.buffer[dpidStart + 4] << 8 | Tuya.buffer[dpidStart + 5]; uint16_t tmpCur = Tuya.buffer[dpidStart + 7] << 8 | Tuya.buffer[dpidStart + 8]; uint16_t tmpPow = Tuya.buffer[dpidStart + 10] << 8 | Tuya.buffer[dpidStart + 11]; - Energy.voltage[0] = (float)tmpVol / 10; - Energy.current[0] = (float)tmpCur / 1000; - Energy.active_power[0] = (float)tmpPow; + Energy->voltage[0] = (float)tmpVol / 10; + Energy->current[0] = (float)tmpCur / 1000; + Energy->active_power[0] = (float)tmpPow; AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: Rx ID=%d Voltage=%d"), Tuya.buffer[dpidStart], tmpVol); AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: Rx ID=%d Current=%d"), Tuya.buffer[dpidStart], tmpCur); AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: Rx ID=%d Active_Power=%d"), Tuya.buffer[dpidStart], tmpPow); if (RtcTime.valid) { - if (Tuya.lastPowerCheckTime != 0 && Energy.active_power[0] > 0) { - Energy.kWhtoday[0] += Energy.active_power[0] * (float)(Rtc.utc_time - Tuya.lastPowerCheckTime) / 36.0; + if (Tuya.lastPowerCheckTime != 0 && Energy->active_power[0] > 0) { + Energy->kWhtoday[0] += Energy->active_power[0] * (float)(Rtc.utc_time - Tuya.lastPowerCheckTime) / 36.0; EnergyUpdateToday(); } Tuya.lastPowerCheckTime = Rtc.utc_time; @@ -950,24 +950,24 @@ void TuyaProcessStatePacket(void) { } #ifdef USE_ENERGY_SENSOR else if (tuya_energy_enabled && fnId == TUYA_MCU_FUNC_VOLTAGE) { - Energy.voltage[0] = (float)packetValue / 10; + Energy->voltage[0] = (float)packetValue / 10; AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: Rx ID=%d Voltage=%d"), Tuya.buffer[dpidStart], packetValue); } else if (tuya_energy_enabled && fnId == TUYA_MCU_FUNC_CURRENT) { - Energy.current[0] = (float)packetValue / 1000; + Energy->current[0] = (float)packetValue / 1000; AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: Rx ID=%d Current=%d"), Tuya.buffer[dpidStart], packetValue); } else if (tuya_energy_enabled && fnId == TUYA_MCU_FUNC_POWER) { - Energy.active_power[0] = (float)packetValue / 10; + Energy->active_power[0] = (float)packetValue / 10; AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: Rx ID=%d Active_Power=%d"), Tuya.buffer[dpidStart], packetValue); if (RtcTime.valid) { - if (Tuya.lastPowerCheckTime != 0 && Energy.active_power[0] > 0) { - Energy.kWhtoday[0] += Energy.active_power[0] * (float)(Rtc.utc_time - Tuya.lastPowerCheckTime) / 36.0; + if (Tuya.lastPowerCheckTime != 0 && Energy->active_power[0] > 0) { + Energy->kWhtoday[0] += Energy->active_power[0] * (float)(Rtc.utc_time - Tuya.lastPowerCheckTime) / 36.0; EnergyUpdateToday(); } Tuya.lastPowerCheckTime = Rtc.utc_time; } } else if (tuya_energy_enabled && fnId == TUYA_MCU_FUNC_POWER_TOTAL) { - Energy.import_active[0] = (float)packetValue / 100; + Energy->import_active[0] = (float)packetValue / 100; AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: Rx ID=%d Total_Power=%d"), Tuya.buffer[dpidStart], packetValue); EnergyUpdateTotal(); } @@ -1602,10 +1602,10 @@ bool Xnrg32(uint32_t function) if (FUNC_PRE_INIT == function) { if (TuyaGetDpId(TUYA_MCU_FUNC_POWER) != 0 || TuyaGetDpId(TUYA_MCU_FUNC_POWER_COMBINED) != 0) { if (TuyaGetDpId(TUYA_MCU_FUNC_CURRENT) == 0 && TuyaGetDpId(TUYA_MCU_FUNC_POWER_COMBINED) == 0) { - Energy.current_available = false; + Energy->current_available = false; } if (TuyaGetDpId(TUYA_MCU_FUNC_VOLTAGE) == 0 && TuyaGetDpId(TUYA_MCU_FUNC_POWER_COMBINED) == 0) { - Energy.voltage_available = false; + Energy->voltage_available = false; } TasmotaGlobal.energy_driver = XNRG_32; } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v2.ino b/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v2.ino index b0bc5e6aa..d78b1bec3 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v2.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v2.ino @@ -1604,15 +1604,15 @@ void TuyaProcessRxedDP(uint8_t dpid, uint8_t type, uint8_t *data, int dpDataLen) /* uint16_t tmpVol = pTuya->buffer[dpidStart + 4] << 8 | pTuya->buffer[dpidStart + 5]; uint16_t tmpCur = pTuya->buffer[dpidStart + 7] << 8 | pTuya->buffer[dpidStart + 8]; uint16_t tmpPow = pTuya->buffer[dpidStart + 10] << 8 | pTuya->buffer[dpidStart + 11];*/ - Energy.voltage[0] = (float)tmpVol / 10; - Energy.current[0] = (float)tmpCur / 1000; - Energy.active_power[0] = (float)tmpPow; + Energy->voltage[0] = (float)tmpVol / 10; + Energy->current[0] = (float)tmpCur / 1000; + Energy->active_power[0] = (float)tmpPow; AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: fnId=%d Rx ID=%d Voltage=%d Current=%d Active_Power=%d"), fnId, dpid, tmpVol, tmpCur, tmpPow); if (RtcTime.valid) { - if (pTuya->lastPowerCheckTime != 0 && Energy.active_power[0] > 0) { - Energy.kWhtoday[0] += Energy.active_power[0] * (float)(Rtc.utc_time - pTuya->lastPowerCheckTime) / 36.0; + if (pTuya->lastPowerCheckTime != 0 && Energy->active_power[0] > 0) { + Energy->kWhtoday[0] += Energy->active_power[0] * (float)(Rtc.utc_time - pTuya->lastPowerCheckTime) / 36.0; EnergyUpdateToday(); } pTuya->lastPowerCheckTime = Rtc.utc_time; @@ -1745,24 +1745,24 @@ void TuyaProcessRxedDP(uint8_t dpid, uint8_t type, uint8_t *data, int dpDataLen) } #ifdef USE_ENERGY_SENSOR else if (tuya_energy_enabled && fnId == TUYA_MCU_FUNC_VOLTAGE) { - Energy.voltage[0] = (float)packetValue / 10; + Energy->voltage[0] = (float)packetValue / 10; AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: fnId=%d Rx ID=%d Voltage=%d"), fnId, dpid, packetValue); } else if (tuya_energy_enabled && fnId == TUYA_MCU_FUNC_CURRENT) { - Energy.current[0] = (float)packetValue / 1000; + Energy->current[0] = (float)packetValue / 1000; AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: fnId=%d Rx ID=%d Current=%d"), fnId, dpid, packetValue); } else if (tuya_energy_enabled && fnId == TUYA_MCU_FUNC_POWER) { - Energy.active_power[0] = (float)packetValue / 10; + Energy->active_power[0] = (float)packetValue / 10; AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: fnId=%d Rx ID=%d Active_Power=%d"), fnId, dpid, packetValue); if (RtcTime.valid) { - if (pTuya->lastPowerCheckTime != 0 && Energy.active_power[0] > 0) { - Energy.kWhtoday[0] += Energy.active_power[0] * (float)(Rtc.utc_time - pTuya->lastPowerCheckTime) / 36.0; + if (pTuya->lastPowerCheckTime != 0 && Energy->active_power[0] > 0) { + Energy->kWhtoday[0] += Energy->active_power[0] * (float)(Rtc.utc_time - pTuya->lastPowerCheckTime) / 36.0; EnergyUpdateToday(); } pTuya->lastPowerCheckTime = Rtc.utc_time; } } else if (tuya_energy_enabled && fnId == TUYA_MCU_FUNC_POWER_TOTAL) { - Energy.import_active[0] = (float)packetValue / 100; + Energy->import_active[0] = (float)packetValue / 100; AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: fnId=%d Rx ID=%d Total_Power=%d"), fnId, dpid, packetValue); EnergyUpdateTotal(); } @@ -2441,10 +2441,10 @@ bool Xnrg32(uint32_t function) if (FUNC_PRE_INIT == function) { if (TuyaGetDpId(TUYA_MCU_FUNC_POWER) != 0 || TuyaGetDpId(TUYA_MCU_FUNC_POWER_COMBINED) != 0) { if (TuyaGetDpId(TUYA_MCU_FUNC_CURRENT) == 0 && TuyaGetDpId(TUYA_MCU_FUNC_POWER_COMBINED) == 0) { - Energy.current_available = false; + Energy->current_available = false; } if (TuyaGetDpId(TUYA_MCU_FUNC_VOLTAGE) == 0 && TuyaGetDpId(TUYA_MCU_FUNC_POWER_COMBINED) == 0) { - Energy.voltage_available = false; + Energy->voltage_available = false; } TasmotaGlobal.energy_driver = XNRG_32; } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_45_shelly_dimmer.ino b/tasmota/tasmota_xdrv_driver/xdrv_45_shelly_dimmer.ino index 4b157ac6e..0ed553765 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_45_shelly_dimmer.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_45_shelly_dimmer.ino @@ -527,19 +527,19 @@ bool ShdPacketProcess(void) #ifdef USE_ENERGY_SENSOR if (Shd.hw_version == 2) { - Energy.current_available = true; - Energy.voltage_available = true; + Energy->current_available = true; + Energy->voltage_available = true; } - Energy.active_power[0] = wattage; - Energy.voltage[0] = voltage; - Energy.current[0] = current; - if (Shd.last_power_check > 10 && Energy.active_power[0] > 0) { + Energy->active_power[0] = wattage; + Energy->voltage[0] = voltage; + Energy->current[0] = current; + if (Shd.last_power_check > 10 && Energy->active_power[0] > 0) { uint32_t time_passed = abs(TimePassedSince(Shd.last_power_check)); // Time passed in milliseconds - uint32_t deca_microWh = (uint32_t)(Energy.active_power[0] * time_passed) / 36; + uint32_t deca_microWh = (uint32_t)(Energy->active_power[0] * time_passed) / 36; #ifdef SHELLY_DIMMER_DEBUG - AddLog(LOG_LEVEL_DEBUG, PSTR(SHD_LOGNAME "%4_f W is %u dmWh during %u ms"), &Energy.active_power[0], deca_microWh, time_passed); + AddLog(LOG_LEVEL_DEBUG, PSTR(SHD_LOGNAME "%4_f W is %u dmWh during %u ms"), &Energy->active_power[0], deca_microWh, time_passed); #endif // SHELLY_DIMMER_DEBUG - Energy.kWhtoday_delta[0] += deca_microWh; + Energy->kWhtoday_delta[0] += deca_microWh; EnergyUpdateToday(); } Shd.last_power_check = millis(); @@ -833,10 +833,10 @@ bool Xnrg31(uint32_t function) { if (Shd.present) { if (FUNC_PRE_INIT == function) { #ifndef SHELLY_VOLTAGE_MON - Energy.current_available = false; - Energy.voltage_available = false; + Energy->current_available = false; + Energy->voltage_available = false; #endif // SHELLY_VOLTAGE_MON - Energy.use_overtemp = true; // Use global temperature for overtemp detection + Energy->use_overtemp = true; // Use global temperature for overtemp detection TasmotaGlobal.energy_driver = XNRG_31; } } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_87_esp32_sonoff_tm1621.ino b/tasmota/tasmota_xdrv_driver/xdrv_87_esp32_sonoff_tm1621.ino index d8b315063..51fd818ad 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_87_esp32_sonoff_tm1621.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_87_esp32_sonoff_tm1621.ino @@ -429,13 +429,13 @@ void TM1621Show(void) { if (TM1621_POWR316D == Tm1621.device) { if (0 == Tm1621.display_rotate) { - ext_snprintf_P(Tm1621.row[0], sizeof(Tm1621.row[0]), PSTR("%1_f"), &Energy.voltage[0]); - ext_snprintf_P(Tm1621.row[1], sizeof(Tm1621.row[1]), PSTR("%1_f"), &Energy.current[0]); + ext_snprintf_P(Tm1621.row[0], sizeof(Tm1621.row[0]), PSTR("%1_f"), &Energy->voltage[0]); + ext_snprintf_P(Tm1621.row[1], sizeof(Tm1621.row[1]), PSTR("%1_f"), &Energy->current[0]); Tm1621.voltage = true; Tm1621.display_rotate = 1; } else { - ext_snprintf_P(Tm1621.row[0], sizeof(Tm1621.row[0]), PSTR("%1_f"), &Energy.total[0]); - ext_snprintf_P(Tm1621.row[1], sizeof(Tm1621.row[1]), PSTR("%1_f"), &Energy.active_power[0]); + ext_snprintf_P(Tm1621.row[0], sizeof(Tm1621.row[0]), PSTR("%1_f"), &Energy->total[0]); + ext_snprintf_P(Tm1621.row[1], sizeof(Tm1621.row[1]), PSTR("%1_f"), &Energy->active_power[0]); Tm1621.kwh = true; Tm1621.display_rotate = 0; } diff --git a/tasmota/tasmota_xnrg_energy/xnrg_01_hlw8012.ino b/tasmota/tasmota_xnrg_energy/xnrg_01_hlw8012.ino index cfbd76d94..88f6d2d74 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_01_hlw8012.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_01_hlw8012.ino @@ -93,7 +93,7 @@ void HlwCfInterrupt(void) { // Service Power Hlw.cf_pulse_counter++; Hlw.energy_period_counter++; } - Energy.data_valid[0] = 0; + Energy->data_valid[0] = 0; } void HlwCf1Interrupt(void) { // Service Voltage and Current @@ -111,7 +111,7 @@ void HlwCf1Interrupt(void) { // Service Voltage and Current Hlw.cf1_timer = 8; // We need up to HLW_SAMPLE_COUNT samples within 1 second (low current could take up to 0.3 second) } } - Energy.data_valid[0] = 0; + Energy->data_valid[0] = 0; } /********************************************************************************************/ @@ -133,15 +133,15 @@ void HlwEvery200ms(void) { Hlw.cf_summed_pulse_length = 0; Hlw.cf_pulse_counter = 0; - if (Hlw.cf_power_pulse_length && Energy.power_on && !Hlw.load_off) { + if (Hlw.cf_power_pulse_length && Energy->power_on && !Hlw.load_off) { hlw_w = (Hlw.power_ratio * Settings->energy_power_calibration) / Hlw.cf_power_pulse_length ; // W *10 - Energy.active_power[0] = (float)hlw_w / 10; + Energy->active_power[0] = (float)hlw_w / 10; Hlw.power_retry = 1; // Workaround issue #5161 } else { if (Hlw.power_retry) { Hlw.power_retry--; } else { - Energy.active_power[0] = 0; + Energy->active_power[0] = 0; } } @@ -178,21 +178,21 @@ void HlwEvery200ms(void) { if (Hlw.select_ui_flag == Hlw.ui_flag) { Hlw.cf1_voltage_pulse_length = cf1_pulse_length; - if (Hlw.cf1_voltage_pulse_length && Energy.power_on) { // If powered on always provide voltage + if (Hlw.cf1_voltage_pulse_length && Energy->power_on) { // If powered on always provide voltage hlw_u = (Hlw.voltage_ratio * Settings->energy_voltage_calibration) / Hlw.cf1_voltage_pulse_length ; // V *10 - Energy.voltage[0] = (float)hlw_u / 10; + Energy->voltage[0] = (float)hlw_u / 10; } else { - Energy.voltage[0] = 0; + Energy->voltage[0] = 0; } } else { Hlw.cf1_current_pulse_length = cf1_pulse_length; - if (Hlw.cf1_current_pulse_length && Energy.active_power[0]) { // No current if no power being consumed + if (Hlw.cf1_current_pulse_length && Energy->active_power[0]) { // No current if no power being consumed hlw_i = (Hlw.current_ratio * Settings->energy_current_calibration) / Hlw.cf1_current_pulse_length; // mA - Energy.current[0] = (float)hlw_i / 1000; + Energy->current[0] = (float)hlw_i / 1000; } else { - Energy.current[0] = 0; + Energy->current[0] = 0; } } @@ -203,7 +203,7 @@ void HlwEvery200ms(void) { } void HlwEverySecond(void) { - if (Energy.data_valid[0] > ENERGY_WATCHDOG) { + if (Energy->data_valid[0] > ENERGY_WATCHDOG) { Hlw.cf1_voltage_pulse_length = 0; Hlw.cf1_current_pulse_length = 0; Hlw.cf_power_pulse_length = 0; @@ -217,7 +217,7 @@ void HlwEverySecond(void) { hlw_len = 10000 * 100 / Hlw.energy_period_counter; // Add *100 to fix rounding on loads at 3.6kW (#9160) Hlw.energy_period_counter = 0; if (hlw_len) { - Energy.kWhtoday_delta[0] += (((Hlw.power_ratio * Settings->energy_power_calibration) / 36) * 100) / hlw_len; + Energy->kWhtoday_delta[0] += (((Hlw.power_ratio * Settings->energy_power_calibration) / 36) * 100) / hlw_len; EnergyUpdateToday(); } } @@ -270,13 +270,13 @@ void HlwDrvInit(void) { if (PinUsed(GPIO_NRG_CF1)) { // Voltage and/or Current monitor if (!PinUsed(GPIO_NRG_SEL)) { // Voltage and/or Current selector - Energy.current_available = false; // Assume Voltage + Energy->current_available = false; // Assume Voltage } } else { - Energy.current_available = false; - Energy.voltage_available = false; + Energy->current_available = false; + Energy->voltage_available = false; } - Energy.use_overtemp = true; // Use global temperature for overtemp detection + Energy->use_overtemp = true; // Use global temperature for overtemp detection TasmotaGlobal.energy_driver = XNRG_01; } @@ -285,20 +285,20 @@ void HlwDrvInit(void) { bool HlwCommand(void) { bool serviced = true; - if ((CMND_POWERCAL == Energy.command_code) || (CMND_VOLTAGECAL == Energy.command_code) || (CMND_CURRENTCAL == Energy.command_code)) { + if ((CMND_POWERCAL == Energy->command_code) || (CMND_VOLTAGECAL == Energy->command_code) || (CMND_CURRENTCAL == Energy->command_code)) { // Service in xdrv_03_energy.ino } - else if (CMND_POWERSET == Energy.command_code) { + else if (CMND_POWERSET == Energy->command_code) { if (XdrvMailbox.data_len && Hlw.cf_power_pulse_length ) { XdrvMailbox.payload = ((uint32_t)(CharToFloat(XdrvMailbox.data) * 10) * Hlw.cf_power_pulse_length ) / Hlw.power_ratio; } } - else if (CMND_VOLTAGESET == Energy.command_code) { + else if (CMND_VOLTAGESET == Energy->command_code) { if (XdrvMailbox.data_len && Hlw.cf1_voltage_pulse_length ) { XdrvMailbox.payload = ((uint32_t)(CharToFloat(XdrvMailbox.data) * 10) * Hlw.cf1_voltage_pulse_length ) / Hlw.voltage_ratio; } } - else if (CMND_CURRENTSET == Energy.command_code) { + else if (CMND_CURRENTSET == Energy->command_code) { if (XdrvMailbox.data_len && Hlw.cf1_current_pulse_length) { XdrvMailbox.payload = ((uint32_t)(CharToFloat(XdrvMailbox.data)) * Hlw.cf1_current_pulse_length) / Hlw.current_ratio; } diff --git a/tasmota/tasmota_xnrg_energy/xnrg_02_cse7766.ino b/tasmota/tasmota_xnrg_energy/xnrg_02_cse7766.ino index fd2ccc11e..b4077ed74 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_02_cse7766.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_02_cse7766.ino @@ -105,21 +105,21 @@ void CseReceived(void) { Cse.power_cycle = Cse.rx_buffer[17] << 16 | Cse.rx_buffer[18] << 8 | Cse.rx_buffer[19]; Cse.cf_pulses = Cse.rx_buffer[21] << 8 | Cse.rx_buffer[22]; - if (Energy.power_on) { // Powered on + if (Energy->power_on) { // Powered on if (adjustement & 0x40) { // Voltage valid - Energy.voltage[0] = (float)(Settings->energy_voltage_calibration * CSE_UREF) / (float)Cse.voltage_cycle; + Energy->voltage[0] = (float)(Settings->energy_voltage_calibration * CSE_UREF) / (float)Cse.voltage_cycle; } if (adjustement & 0x10) { // Power valid Cse.power_invalid = 0; if ((header & 0xF2) == 0xF2) { // Power cycle exceeds range - Energy.active_power[0] = 0; + Energy->active_power[0] = 0; } else { if (0 == Cse.power_cycle_first) { Cse.power_cycle_first = Cse.power_cycle; } // Skip first incomplete Cse.power_cycle if (Cse.power_cycle_first != Cse.power_cycle) { Cse.power_cycle_first = -1; - Energy.active_power[0] = (float)(Settings->energy_power_calibration * CSE_PREF) / (float)Cse.power_cycle; + Energy->active_power[0] = (float)(Settings->energy_power_calibration * CSE_PREF) / (float)Cse.power_cycle; } else { - Energy.active_power[0] = 0; + Energy->active_power[0] = 0; } } } else { @@ -127,21 +127,21 @@ void CseReceived(void) { Cse.power_invalid++; } else { Cse.power_cycle_first = 0; - Energy.active_power[0] = 0; // Powered on but no load + Energy->active_power[0] = 0; // Powered on but no load } } if (adjustement & 0x20) { // Current valid - if (0 == Energy.active_power[0]) { - Energy.current[0] = 0; + if (0 == Energy->active_power[0]) { + Energy->current[0] = 0; } else { - Energy.current[0] = (float)Settings->energy_current_calibration / (float)Cse.current_cycle; + Energy->current[0] = (float)Settings->energy_current_calibration / (float)Cse.current_cycle; } } } else { // Powered off Cse.power_cycle_first = 0; - Energy.voltage[0] = 0; - Energy.active_power[0] = 0; - Energy.current[0] = 0; + Energy->voltage[0] = 0; + Energy->active_power[0] = 0; + Energy->current[0] = 0; } } @@ -159,7 +159,7 @@ void CseSerialInput(void) { uint8_t checksum = 0; for (uint32_t i = 2; i < 23; i++) { checksum += Cse.rx_buffer[i]; } if (checksum == Cse.rx_buffer[23]) { - Energy.data_valid[0] = 0; + Energy->data_valid[0] = 0; CseReceived(); Cse.received = false; return; @@ -189,7 +189,7 @@ void CseSerialInput(void) { /********************************************************************************************/ void CseEverySecond(void) { - if (Energy.data_valid[0] > ENERGY_WATCHDOG) { + if (Energy->data_valid[0] > ENERGY_WATCHDOG) { Cse.voltage_cycle = 0; Cse.current_cycle = 0; Cse.power_cycle = 0; @@ -203,7 +203,7 @@ void CseEverySecond(void) { } else { cf_pulses = Cse.cf_pulses - Cse.cf_pulses_last_time; } - if (cf_pulses && Energy.active_power[0]) { + if (cf_pulses && Energy->active_power[0]) { uint32_t delta = (cf_pulses * Settings->energy_power_calibration) / 36; // prevent invalid load delta steps even checksum is valid (issue #5789): // prevent invalid load delta steps even checksum is valid but allow up to 4kW (issue #7155): @@ -211,7 +211,7 @@ void CseEverySecond(void) { // prevent invalid load delta steps even checksum is valid but allow up to 5.5kW (issue #14156): if (delta <= (5500 * 1000 / 36)) { // max load for Pow R3: 5.50kW Cse.cf_pulses_last_time = Cse.cf_pulses; - Energy.kWhtoday_delta[0] += delta; + Energy->kWhtoday_delta[0] += delta; } else { AddLog(LOG_LEVEL_DEBUG, PSTR("CSE: Overload")); @@ -236,7 +236,7 @@ void CseSnsInit(void) { Settings->param[P_CSE7766_INVALID_POWER] = CSE_MAX_INVALID_POWER; // SetOption39 1..255 } Cse.power_invalid = Settings->param[P_CSE7766_INVALID_POWER]; - Energy.use_overtemp = true; // Use global temperature for overtemp detection + Energy->use_overtemp = true; // Use global temperature for overtemp detection } else { TasmotaGlobal.energy_driver = ENERGY_NONE; } @@ -255,17 +255,17 @@ void CseDrvInit(void) { bool CseCommand(void) { bool serviced = true; - if (CMND_POWERSET == Energy.command_code) { + if (CMND_POWERSET == Energy->command_code) { if (XdrvMailbox.data_len && Cse.power_cycle) { XdrvMailbox.payload = (unsigned long)(CharToFloat(XdrvMailbox.data) * Cse.power_cycle) / CSE_PREF; } } - else if (CMND_VOLTAGESET == Energy.command_code) { + else if (CMND_VOLTAGESET == Energy->command_code) { if (XdrvMailbox.data_len && Cse.voltage_cycle) { XdrvMailbox.payload = (unsigned long)(CharToFloat(XdrvMailbox.data) * Cse.voltage_cycle) / CSE_UREF; } } - else if (CMND_CURRENTSET == Energy.command_code) { + else if (CMND_CURRENTSET == Energy->command_code) { if (XdrvMailbox.data_len && Cse.current_cycle) { XdrvMailbox.payload = (unsigned long)(CharToFloat(XdrvMailbox.data) * Cse.current_cycle) / 1000; } diff --git a/tasmota/tasmota_xnrg_energy/xnrg_03_pzem004t.ino b/tasmota/tasmota_xnrg_energy/xnrg_03_pzem004t.ino index 7e6dc699b..41644df77 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_03_pzem004t.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_03_pzem004t.ino @@ -180,20 +180,20 @@ void PzemEvery250ms(void) if (data_ready) { float value = 0; if (PzemRecieve(pzem_responses[Pzem.read_state], &value)) { - Energy.data_valid[Pzem.phase] = 0; + Energy->data_valid[Pzem.phase] = 0; switch (Pzem.read_state) { case 1: // Voltage as 230.2V - Energy.voltage[Pzem.phase] = value; + Energy->voltage[Pzem.phase] = value; break; case 2: // Current as 17.32A - Energy.current[Pzem.phase] = value; + Energy->current[Pzem.phase] = value; break; case 3: // Power as 20W - Energy.active_power[Pzem.phase] = value; + Energy->active_power[Pzem.phase] = value; break; case 4: // Total energy as 99999Wh - Energy.import_active[Pzem.phase] = value / 1000.0f; // 99.999kWh - if (Pzem.phase == Energy.phase_count -1) { + Energy->import_active[Pzem.phase] = value / 1000.0f; // 99.999kWh + if (Pzem.phase == Energy->phase_count -1) { if (TasmotaGlobal.uptime > PZEM_STABILIZE) { EnergyUpdateTotal(); } @@ -212,12 +212,12 @@ void PzemEvery250ms(void) if (0 == Pzem.send_retry || data_ready) { if (1 == Pzem.read_state) { if (0 == Pzem.phase) { - Pzem.phase = Energy.phase_count -1; + Pzem.phase = Energy->phase_count -1; } else { Pzem.phase--; } -// AddLog(LOG_LEVEL_DEBUG, PSTR("PZM: Probing address %d, Max phases %d"), Pzem.phase +1, Energy.phase_count); +// AddLog(LOG_LEVEL_DEBUG, PSTR("PZM: Probing address %d, Max phases %d"), Pzem.phase +1, Energy->phase_count); } if (Pzem.address) { @@ -229,8 +229,8 @@ void PzemEvery250ms(void) } else { Pzem.send_retry--; - if ((Energy.phase_count > 1) && (0 == Pzem.send_retry) && (TasmotaGlobal.uptime < PZEM_STABILIZE)) { - Energy.phase_count--; // Decrement phases if no response after retry within 30 seconds after restart + if ((Energy->phase_count > 1) && (0 == Pzem.send_retry) && (TasmotaGlobal.uptime < PZEM_STABILIZE)) { + Energy->phase_count--; // Decrement phases if no response after retry within 30 seconds after restart if (TasmotaGlobal.discovery_counter) { TasmotaGlobal.discovery_counter += (PZEM_RETRY / 4) + 1; // Don't send Discovery yet, delay by 5 * 250ms + 1s } @@ -246,7 +246,7 @@ void PzemSnsInit(void) if (PzemSerial->hardwareSerial()) { ClaimSerial(); } - Energy.phase_count = ENERGY_MAX_PHASES; // Start off with three phases + Energy->phase_count = ENERGY_MAX_PHASES; // Start off with three phases Pzem.phase = 0; Pzem.read_state = 1; } else { @@ -265,7 +265,7 @@ bool PzemCommand(void) { bool serviced = true; - if (CMND_MODULEADDRESS == Energy.command_code) { + if (CMND_MODULEADDRESS == Energy->command_code) { if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= ENERGY_MAX_PHASES)) { Pzem.address = XdrvMailbox.payload; // Valid addresses are 1, 2 and 3 } diff --git a/tasmota/tasmota_xnrg_energy/xnrg_04_mcp39f501.ino b/tasmota/tasmota_xnrg_energy/xnrg_04_mcp39f501.ino index 631fe9919..41259ba87 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_04_mcp39f501.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_04_mcp39f501.ino @@ -454,19 +454,19 @@ void McpParseData(void) // mcp_power_factor = McpExtractInt(mcp_buffer, 20, 2); mcp_line_frequency = McpExtractInt(mcp_buffer, 22, 2); - if (Energy.power_on) { // Powered on - Energy.data_valid[0] = 0; - Energy.frequency[0] = (float)mcp_line_frequency / 1000; - Energy.voltage[0] = (float)mcp_voltage_rms / 10; - Energy.active_power[0] = (float)mcp_active_power / 100; - if (0 == Energy.active_power[0]) { - Energy.current[0] = 0; + if (Energy->power_on) { // Powered on + Energy->data_valid[0] = 0; + Energy->frequency[0] = (float)mcp_line_frequency / 1000; + Energy->voltage[0] = (float)mcp_voltage_rms / 10; + Energy->active_power[0] = (float)mcp_active_power / 100; + if (0 == Energy->active_power[0]) { + Energy->current[0] = 0; } else { - Energy.current[0] = (float)mcp_current_rms / 10000; + Energy->current[0] = (float)mcp_current_rms / 10000; } /* } else { // Powered off - Energy.data_valid[0] = ENERGY_WATCHDOG; + Energy->data_valid[0] = ENERGY_WATCHDOG; */ } } @@ -526,7 +526,7 @@ void McpSerialInput(void) void McpEverySecond(void) { - if (Energy.data_valid[0] > ENERGY_WATCHDOG) { + if (Energy->data_valid[0] > ENERGY_WATCHDOG) { mcp_voltage_rms = 0; mcp_current_rms = 0; mcp_active_power = 0; @@ -534,7 +534,7 @@ void McpEverySecond(void) } if (mcp_active_power) { - Energy.kWhtoday_delta[0] += ((mcp_active_power * 10) / 36); + Energy->kWhtoday_delta[0] += ((mcp_active_power * 10) / 36); EnergyUpdateToday(); } @@ -573,7 +573,7 @@ void McpSnsInit(void) mcp_buffer = (char*)(malloc(MCP_BUFFER_SIZE)); } DigitalWrite(GPIO_MCP39F5_RST, 0, 1); // MCP enable - Energy.use_overtemp = true; // Use global temperature for overtemp detection + Energy->use_overtemp = true; // Use global temperature for overtemp detection } else { TasmotaGlobal.energy_driver = ENERGY_NONE; } @@ -598,7 +598,7 @@ bool McpCommand(void) bool serviced = true; unsigned long value = 0; - if (CMND_POWERSET == Energy.command_code) { + if (CMND_POWERSET == Energy->command_code) { if (XdrvMailbox.data_len && mcp_active_power) { value = (unsigned long)(CharToFloat(XdrvMailbox.data) * 100); if ((value > 100) && (value < 200000)) { // Between 1W and 2000W @@ -608,7 +608,7 @@ bool McpCommand(void) } } } - else if (CMND_VOLTAGESET == Energy.command_code) { + else if (CMND_VOLTAGESET == Energy->command_code) { if (XdrvMailbox.data_len && mcp_voltage_rms) { value = (unsigned long)(CharToFloat(XdrvMailbox.data) * 10); if ((value > 1000) && (value < 2600)) { // Between 100V and 260V @@ -618,7 +618,7 @@ bool McpCommand(void) } } } - else if (CMND_CURRENTSET == Energy.command_code) { + else if (CMND_CURRENTSET == Energy->command_code) { if (XdrvMailbox.data_len && mcp_current_rms) { value = (unsigned long)(CharToFloat(XdrvMailbox.data) * 10); if ((value > 100) && (value < 80000)) { // Between 10mA and 8A @@ -628,7 +628,7 @@ bool McpCommand(void) } } } - else if (CMND_FREQUENCYSET == Energy.command_code) { + else if (CMND_FREQUENCYSET == Energy->command_code) { if (XdrvMailbox.data_len && mcp_line_frequency) { value = (unsigned long)(CharToFloat(XdrvMailbox.data) * 1000); if ((value > 45000) && (value < 65000)) { // Between 45Hz and 65Hz diff --git a/tasmota/tasmota_xnrg_energy/xnrg_05_pzem_ac.ino b/tasmota/tasmota_xnrg_energy/xnrg_05_pzem_ac.ino index e07fcb566..242254d71 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_05_pzem_ac.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_05_pzem_ac.ino @@ -65,20 +65,20 @@ void PzemAcEverySecond(void) if (error) { AddLog(LOG_LEVEL_DEBUG, PSTR("PAC: PzemAc %d error %d"), PZEM_AC_DEVICE_ADDRESS + PzemAc.phase, error); } else { - Energy.data_valid[PzemAc.phase] = 0; + Energy->data_valid[PzemAc.phase] = 0; if (10 == registers) { // 0 1 2 3 4 5 6 7 8 9 = ModBus register // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 = Buffer index // 01 04 14 08 D1 00 6C 00 00 00 F4 00 00 00 26 00 00 01 F4 00 64 00 00 51 34 // Id Cc Sz Volt- Current---- Power------ Energy----- Frequ PFact Alarm Crc-- - Energy.voltage[PzemAc.phase] = (float)((buffer[3] << 8) + buffer[4]) / 10.0f; // 6553.0 V - Energy.current[PzemAc.phase] = (float)((buffer[7] << 24) + (buffer[8] << 16) + (buffer[5] << 8) + buffer[6]) / 1000.0f; // 4294967.000 A - Energy.active_power[PzemAc.phase] = (float)((buffer[11] << 24) + (buffer[12] << 16) + (buffer[9] << 8) + buffer[10]) / 10.0f; // 429496729.0 W - Energy.frequency[PzemAc.phase] = (float)((buffer[17] << 8) + buffer[18]) / 10.0f; // 50.0 Hz - Energy.power_factor[PzemAc.phase] = (float)((buffer[19] << 8) + buffer[20]) / 100.0f; // 1.00 - Energy.import_active[PzemAc.phase] = (float)((buffer[15] << 24) + (buffer[16] << 16) + (buffer[13] << 8) + buffer[14]) / 1000.0f; // 4294967.295 kWh - if (PzemAc.phase == Energy.phase_count -1) { + Energy->voltage[PzemAc.phase] = (float)((buffer[3] << 8) + buffer[4]) / 10.0f; // 6553.0 V + Energy->current[PzemAc.phase] = (float)((buffer[7] << 24) + (buffer[8] << 16) + (buffer[5] << 8) + buffer[6]) / 1000.0f; // 4294967.000 A + Energy->active_power[PzemAc.phase] = (float)((buffer[11] << 24) + (buffer[12] << 16) + (buffer[9] << 8) + buffer[10]) / 10.0f; // 429496729.0 W + Energy->frequency[PzemAc.phase] = (float)((buffer[17] << 8) + buffer[18]) / 10.0f; // 50.0 Hz + Energy->power_factor[PzemAc.phase] = (float)((buffer[19] << 8) + buffer[20]) / 100.0f; // 1.00 + Energy->import_active[PzemAc.phase] = (float)((buffer[15] << 24) + (buffer[16] << 16) + (buffer[13] << 8) + buffer[14]) / 1000.0f; // 4294967.295 kWh + if (PzemAc.phase == Energy->phase_count -1) { if (TasmotaGlobal.uptime > PZEM_AC_STABILIZE) { EnergyUpdateTotal(); } @@ -89,7 +89,7 @@ void PzemAcEverySecond(void) if (0 == PzemAc.send_retry || data_ready) { if (0 == PzemAc.phase) { - PzemAc.phase = Energy.phase_count -1; + PzemAc.phase = Energy->phase_count -1; } else { PzemAc.phase--; } @@ -103,8 +103,8 @@ void PzemAcEverySecond(void) } else { PzemAc.send_retry--; - if ((Energy.phase_count > 1) && (0 == PzemAc.send_retry) && (TasmotaGlobal.uptime < PZEM_AC_STABILIZE)) { - Energy.phase_count--; // Decrement phases if no response after retry within 30 seconds after restart + if ((Energy->phase_count > 1) && (0 == PzemAc.send_retry) && (TasmotaGlobal.uptime < PZEM_AC_STABILIZE)) { + Energy->phase_count--; // Decrement phases if no response after retry within 30 seconds after restart if (TasmotaGlobal.discovery_counter) { TasmotaGlobal.discovery_counter += ENERGY_WATCHDOG + 1; // Don't send Discovery yet, delay by 4s + 1s } @@ -118,7 +118,7 @@ void PzemAcSnsInit(void) uint8_t result = PzemAcModbus->Begin(9600); if (result) { if (2 == result) { ClaimSerial(); } - Energy.phase_count = ENERGY_MAX_PHASES; // Start off with three phases + Energy->phase_count = ENERGY_MAX_PHASES; // Start off with three phases PzemAc.phase = 0; } else { TasmotaGlobal.energy_driver = ENERGY_NONE; @@ -136,7 +136,7 @@ bool PzemAcCommand(void) { bool serviced = true; - if (CMND_MODULEADDRESS == Energy.command_code) { + if (CMND_MODULEADDRESS == Energy->command_code) { PzemAc.address = XdrvMailbox.payload; // Valid addresses are 1, 2 and 3 PzemAc.address_step = ADDR_SEND; } diff --git a/tasmota/tasmota_xnrg_energy/xnrg_06_pzem_dc.ino b/tasmota/tasmota_xnrg_energy/xnrg_06_pzem_dc.ino index 06dcf3bb8..1fddb68d0 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_06_pzem_dc.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_06_pzem_dc.ino @@ -64,18 +64,18 @@ void PzemDcEverySecond(void) if (error) { AddLog(LOG_LEVEL_DEBUG, PSTR("PDC: PzemDc %d error %d"), PZEM_DC_DEVICE_ADDRESS + PzemDc.channel, error); } else { - Energy.data_valid[PzemDc.channel] = 0; + Energy->data_valid[PzemDc.channel] = 0; if (8 == registers) { // 0 1 2 3 4 5 6 7 = ModBus register // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 = Buffer index // 01 04 10 05 40 00 0A 00 0D 00 00 00 02 00 00 00 00 00 00 D6 29 // Id Cc Sz Volt- Curre Power------ Energy----- HiAlm LoAlm Crc-- - Energy.voltage[PzemDc.channel] = (float)((buffer[3] << 8) + buffer[4]) / 100.0f; // 655.00 V - Energy.current[PzemDc.channel] = (float)((buffer[5] << 8) + buffer[6]) / 100.0f; // 655.00 A - Energy.active_power[PzemDc.channel] = (float)((buffer[9] << 24) + (buffer[10] << 16) + (buffer[7] << 8) + buffer[8]) / 10.0f; // 429496729.0 W - Energy.import_active[PzemDc.channel] = (float)((buffer[13] << 24) + (buffer[14] << 16) + (buffer[11] << 8) + buffer[12]) / 1000.0f; // 4294967.295 kWh - if (PzemDc.channel == Energy.phase_count -1) { + Energy->voltage[PzemDc.channel] = (float)((buffer[3] << 8) + buffer[4]) / 100.0f; // 655.00 V + Energy->current[PzemDc.channel] = (float)((buffer[5] << 8) + buffer[6]) / 100.0f; // 655.00 A + Energy->active_power[PzemDc.channel] = (float)((buffer[9] << 24) + (buffer[10] << 16) + (buffer[7] << 8) + buffer[8]) / 10.0f; // 429496729.0 W + Energy->import_active[PzemDc.channel] = (float)((buffer[13] << 24) + (buffer[14] << 16) + (buffer[11] << 8) + buffer[12]) / 1000.0f; // 4294967.295 kWh + if (PzemDc.channel == Energy->phase_count -1) { if (TasmotaGlobal.uptime > PZEM_DC_STABILIZE) { EnergyUpdateTotal(); } @@ -86,7 +86,7 @@ void PzemDcEverySecond(void) if (0 == PzemDc.send_retry || data_ready) { if (0 == PzemDc.channel) { - PzemDc.channel = Energy.phase_count -1; + PzemDc.channel = Energy->phase_count -1; } else { PzemDc.channel--; } @@ -100,8 +100,8 @@ void PzemDcEverySecond(void) } else { PzemDc.send_retry--; - if ((Energy.phase_count > 1) && (0 == PzemDc.send_retry) && (TasmotaGlobal.uptime < PZEM_DC_STABILIZE)) { - Energy.phase_count--; // Decrement channels if no response after retry within 30 seconds after restart + if ((Energy->phase_count > 1) && (0 == PzemDc.send_retry) && (TasmotaGlobal.uptime < PZEM_DC_STABILIZE)) { + Energy->phase_count--; // Decrement channels if no response after retry within 30 seconds after restart if (TasmotaGlobal.discovery_counter) { TasmotaGlobal.discovery_counter += ENERGY_WATCHDOG + 1; // Don't send Discovery yet, delay by 4s + 1s } @@ -115,8 +115,8 @@ void PzemDcSnsInit(void) uint8_t result = PzemDcModbus->Begin(9600, SERIAL_8N2); if (result) { if (2 == result) { ClaimSerial(); } - Energy.type_dc = true; - Energy.phase_count = ENERGY_MAX_PHASES; // Start off with three channels + Energy->type_dc = true; + Energy->phase_count = ENERGY_MAX_PHASES; // Start off with three channels PzemDc.channel = 0; } else { TasmotaGlobal.energy_driver = ENERGY_NONE; @@ -134,7 +134,7 @@ bool PzemDcCommand(void) { bool serviced = true; - if (CMND_MODULEADDRESS == Energy.command_code) { + if (CMND_MODULEADDRESS == Energy->command_code) { PzemDc.address = XdrvMailbox.payload; // Valid addresses are 1, 2 and 3 PzemDc.address_step = ADDR_SEND; } diff --git a/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino b/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino index 9efcd2748..d5f79e848 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino @@ -460,7 +460,7 @@ void Ade7953GetData(void) { #endif // USE_ESP32_SPI #ifdef USE_ESP32_SPI - if (1 == Energy.phase_count) { + if (1 == Energy->phase_count) { AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("ADE: ACCMODE 0x%06X, VRMS %d, Period %d, IRMS %d, WATT %d, VA %d, VAR %d"), acc_mode, reg[0][4], reg[0][5], reg[0][0], reg[0][1], reg[0][2], reg[0][3]); } else @@ -475,7 +475,7 @@ void Ade7953GetData(void) { uint32_t apparent_power[2] = { 0, 0 }; uint32_t reactive_power[2] = { 0, 0 }; - for (uint32_t channel = 0; channel < Energy.phase_count; channel++) { + for (uint32_t channel = 0; channel < Energy->phase_count; channel++) { Ade7953.voltage_rms[channel] = reg[channel][4]; Ade7953.current_rms[channel] = reg[channel][0]; if (Ade7953.current_rms[channel] < 2000) { // No load threshold (20mA) @@ -491,10 +491,10 @@ void Ade7953GetData(void) { } } - if (Energy.power_on) { // Powered on + if (Energy->power_on) { // Powered on float divider; - for (uint32_t channel = 0; channel < Energy.phase_count; channel++) { - Energy.data_valid[channel] = 0; + for (uint32_t channel = 0; channel < Energy->phase_count; channel++) { + Energy->data_valid[channel] = 0; float power_calibration = (float)EnergyGetCalibration(channel, ENERGY_POWER_CALIBRATION) / 10; #ifdef ADE7953_ACCU_ENERGY @@ -503,29 +503,29 @@ void Ade7953GetData(void) { float voltage_calibration = (float)EnergyGetCalibration(channel, ENERGY_VOLTAGE_CALIBRATION); float current_calibration = (float)EnergyGetCalibration(channel, ENERGY_CURRENT_CALIBRATION) * 10; - Energy.frequency[channel] = 223750.0f / ((float)reg[channel][5] + 1); + Energy->frequency[channel] = 223750.0f / ((float)reg[channel][5] + 1); divider = (Ade7953.calib_data[channel][ADE7953_CAL_VGAIN] != ADE7953_GAIN_DEFAULT) ? 10000 : voltage_calibration; - Energy.voltage[channel] = (float)Ade7953.voltage_rms[channel] / divider; + Energy->voltage[channel] = (float)Ade7953.voltage_rms[channel] / divider; divider = (Ade7953.calib_data[channel][ADE7953_CAL_WGAIN + channel] != ADE7953_GAIN_DEFAULT) ? ADE7953_LSB_PER_WATTSECOND : power_calibration; - Energy.active_power[channel] = (float)Ade7953.active_power[channel] / divider; + Energy->active_power[channel] = (float)Ade7953.active_power[channel] / divider; divider = (Ade7953.calib_data[channel][ADE7953_CAL_VARGAIN + channel] != ADE7953_GAIN_DEFAULT) ? ADE7953_LSB_PER_WATTSECOND : power_calibration; - Energy.reactive_power[channel] = (float)reactive_power[channel] / divider; + Energy->reactive_power[channel] = (float)reactive_power[channel] / divider; if (ADE7953_SHELLY_EM == Ade7953.model) { if (bitRead(acc_mode, 10 +channel)) { // APSIGN - Energy.active_power[channel] *= -1; + Energy->active_power[channel] *= -1; } if (bitRead(acc_mode, 12 +channel)) { // VARSIGN - Energy.reactive_power[channel] *= -1; + Energy->reactive_power[channel] *= -1; } } divider = (Ade7953.calib_data[channel][ADE7953_CAL_VAGAIN + channel] != ADE7953_GAIN_DEFAULT) ? ADE7953_LSB_PER_WATTSECOND : power_calibration; - Energy.apparent_power[channel] = (float)apparent_power[channel] / divider; - if (0 == Energy.active_power[channel]) { - Energy.current[channel] = 0; + Energy->apparent_power[channel] = (float)apparent_power[channel] / divider; + if (0 == Energy->active_power[channel]) { + Energy->current[channel] = 0; } else { divider = (Ade7953.calib_data[channel][ADE7953_CAL_IGAIN + channel] != ADE7953_GAIN_DEFAULT) ? 100000 : current_calibration; - Energy.current[channel] = (float)Ade7953.current_rms[channel] / divider; - Energy.kWhtoday_delta[channel] += Energy.active_power[channel] * 1000 / 36; + Energy->current[channel] = (float)Ade7953.current_rms[channel] / divider; + Energy->kWhtoday_delta[channel] += Energy->active_power[channel] * 1000 / 36; } } EnergyUpdateToday(); @@ -719,22 +719,22 @@ void Ade7953DrvInit(void) { Ade7953.init_step = 3; -// Energy.phase_count = 1; -// Energy.voltage_common = false; -// Energy.frequency_common = false; -// Energy.use_overtemp = false; +// Energy->phase_count = 1; +// Energy->voltage_common = false; +// Energy->frequency_common = false; +// Energy->use_overtemp = false; if (ADE7953_SHELLY_PRO_1PM == Ade7953.model) { } else { - Energy.phase_count = 2; // Handle two channels as two phases + Energy->phase_count = 2; // Handle two channels as two phases if (ADE7953_SHELLY_PRO_2PM == Ade7953.model) { } else { - Energy.voltage_common = true; // Use common voltage - Energy.frequency_common = true; // Use common frequency + Energy->voltage_common = true; // Use common voltage + Energy->frequency_common = true; // Use common frequency } } - Energy.use_overtemp = true; // Use global temperature for overtemp detection + Energy->use_overtemp = true; // Use global temperature for overtemp detection if (ADE7953_SHELLY_EM == Ade7953.model) { - Energy.local_energy_active_export = true; + Energy->local_energy_active_export = true; } TasmotaGlobal.energy_driver = XNRG_07; } @@ -746,19 +746,19 @@ bool Ade7953Command(void) { uint32_t channel = (2 == XdrvMailbox.index) ? 1 : 0; uint32_t value = (uint32_t)(CharToFloat(XdrvMailbox.data) * 100); // 1.23 = 123 - if (CMND_POWERCAL == Energy.command_code) { + if (CMND_POWERCAL == Energy->command_code) { if (1 == XdrvMailbox.payload) { XdrvMailbox.payload = ADE7953_PREF; } // Service in xdrv_03_energy.ino } - else if (CMND_VOLTAGECAL == Energy.command_code) { + else if (CMND_VOLTAGECAL == Energy->command_code) { if (1 == XdrvMailbox.payload) { XdrvMailbox.payload = ADE7953_UREF; } // Service in xdrv_03_energy.ino } - else if (CMND_CURRENTCAL == Energy.command_code) { + else if (CMND_CURRENTCAL == Energy->command_code) { if (1 == XdrvMailbox.payload) { XdrvMailbox.payload = ADE7953_IREF; } // Service in xdrv_03_energy.ino } - else if (CMND_POWERSET == Energy.command_code) { + else if (CMND_POWERSET == Energy->command_code) { if (XdrvMailbox.data_len && Ade7953.active_power[channel]) { if ((value > 100) && (value < 200000)) { // Between 1W and 2000W #ifdef ADE7953_ACCU_ENERGY @@ -771,14 +771,14 @@ bool Ade7953Command(void) { } } } - else if (CMND_VOLTAGESET == Energy.command_code) { + else if (CMND_VOLTAGESET == Energy->command_code) { if (XdrvMailbox.data_len && Ade7953.voltage_rms[channel]) { if ((value > 10000) && (value < 26000)) { // Between 100V and 260V XdrvMailbox.payload = (Ade7953.voltage_rms[channel] * 100) / value; // 0.00 V } } } - else if (CMND_CURRENTSET == Energy.command_code) { + else if (CMND_CURRENTSET == Energy->command_code) { if (XdrvMailbox.data_len && Ade7953.current_rms[channel]) { if ((value > 2000) && (value < 1000000)) { // Between 20mA and 10A XdrvMailbox.payload = ((Ade7953.current_rms[channel] * 100) / value) * 100; // 0.00 mA diff --git a/tasmota/tasmota_xnrg_energy/xnrg_08_sdm120.ino b/tasmota/tasmota_xnrg_energy/xnrg_08_sdm120.ino index d4591aa85..e3c5b9b76 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_08_sdm120.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_08_sdm120.ino @@ -85,7 +85,7 @@ void SDM120Every250ms(void) if (error) { AddLog(LOG_LEVEL_DEBUG, PSTR("SDM: SDM120 error %d"), error); } else { - Energy.data_valid[0] = 0; + Energy->data_valid[0] = 0; // 0 1 2 3 4 5 6 7 8 // SA FC BC Fh Fl Sh Sl Cl Ch @@ -98,31 +98,31 @@ void SDM120Every250ms(void) switch(Sdm120.read_state) { case 0: - Energy.voltage[0] = value; // 230.2 V + Energy->voltage[0] = value; // 230.2 V break; case 1: - Energy.current[0] = value; // 1.260 A + Energy->current[0] = value; // 1.260 A break; case 2: - Energy.active_power[0] = value; // -196.3 W + Energy->active_power[0] = value; // -196.3 W break; case 3: - Energy.apparent_power[0] = value; // 223.4 VA + Energy->apparent_power[0] = value; // 223.4 VA break; case 4: - Energy.reactive_power[0] = value; // 92.2 + Energy->reactive_power[0] = value; // 92.2 break; case 5: - Energy.power_factor[0] = value; // -0.91 + Energy->power_factor[0] = value; // -0.91 break; case 6: - Energy.frequency[0] = value; // 50.0 Hz + Energy->frequency[0] = value; // 50.0 Hz break; case 7: @@ -134,7 +134,7 @@ void SDM120Every250ms(void) break; case 9: - Energy.export_active[0] = value; // 6.216 kWh + Energy->export_active[0] = value; // 6.216 kWh break; case 10: @@ -161,7 +161,7 @@ void SDM120Every250ms(void) Sdm120.start_address_count = sdm120_table; // No extended registers available } } - Energy.import_active[0] = Sdm120.total_active; // 484.708 kWh + Energy->import_active[0] = Sdm120.total_active; // 484.708 kWh EnergyUpdateTotal(); // 484.708 kWh } } diff --git a/tasmota/tasmota_xnrg_energy/xnrg_09_dds2382.ino b/tasmota/tasmota_xnrg_energy/xnrg_09_dds2382.ino index 1c5e55a30..c8d258dd2 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_09_dds2382.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_09_dds2382.ino @@ -52,7 +52,7 @@ void Dds2382EverySecond(void) if (error) { AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "DDS2382 response error %d"), error); } else { - Energy.data_valid[0] = 0; + Energy->data_valid[0] = 0; // 0 1 2 3 4 5 6 7 8 9 A B C D E F 10 11 = ModBus register // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 = Buffer index @@ -64,18 +64,18 @@ void Dds2382EverySecond(void) // {"TotalStartTime":"2020-01-08T09:43:05","Total":0.060,"Yesterday":0.001,"Today":0.001,"ExportActive":12.670,"Period":0,"Power":1016,"ApparentPower":1020,"ReactivePower":112,"Factor":0.99,"Frequency":50,"Voltage":242,"Current":4.210}} // {"TotalStartTime":"2020-01-08T00:00:00","Total":0.061,"Yesterday":0.001,"Today":0.001,"ExportActive":12.670,"Period":0.020,"Power":1199.000,"ApparentPower":1204.231,"ReactivePower":108.000,"Factor":1.00,"Frequency":49.98,"Voltage":242.3,"Current":4.970}} - Energy.voltage[0] = (float)((buffer[27] << 8) + buffer[28]) / 10.0f; - Energy.current[0] = (float)((buffer[29] << 8) + buffer[30]) / 100.0f; - Energy.active_power[0] = (float)((buffer[31] << 8) + buffer[32]); - Energy.reactive_power[0] = (float)(int16_t)((buffer[33] << 8) + buffer[34]); - Energy.power_factor[0] = (float)((buffer[35] << 8) + buffer[36]) / 1000.0f; // 1.00 - Energy.frequency[0] = (float)((buffer[37] << 8) + buffer[38]) / 100.0f; // 50.0 Hz + Energy->voltage[0] = (float)((buffer[27] << 8) + buffer[28]) / 10.0f; + Energy->current[0] = (float)((buffer[29] << 8) + buffer[30]) / 100.0f; + Energy->active_power[0] = (float)((buffer[31] << 8) + buffer[32]); + Energy->reactive_power[0] = (float)(int16_t)((buffer[33] << 8) + buffer[34]); + Energy->power_factor[0] = (float)((buffer[35] << 8) + buffer[36]) / 1000.0f; // 1.00 + Energy->frequency[0] = (float)((buffer[37] << 8) + buffer[38]) / 100.0f; // 50.0 Hz uint8_t offset = 11; if (Settings->flag3.dds2382_model) { // SetOption71 - Select different Modbus registers for Active Energy (#6531) offset = 19; } - Energy.export_active[0] = (float)((buffer[offset] << 24) + (buffer[offset +1] << 16) + (buffer[offset +2] << 8) + buffer[offset +3]) / 100.0f; // 429496.729 kW - Energy.import_active[0] = (float)((buffer[offset +4] << 24) + (buffer[offset +5] << 16) + (buffer[offset +6] << 8) + buffer[offset +7]) / 100.0f; // 429496.729 kW + Energy->export_active[0] = (float)((buffer[offset] << 24) + (buffer[offset +1] << 16) + (buffer[offset +2] << 8) + buffer[offset +3]) / 100.0f; // 429496.729 kW + Energy->import_active[0] = (float)((buffer[offset +4] << 24) + (buffer[offset +5] << 16) + (buffer[offset +6] << 8) + buffer[offset +7]) / 100.0f; // 429496.729 kW EnergyUpdateTotal(); // 484.708 kWh } } // end data ready diff --git a/tasmota/tasmota_xnrg_energy/xnrg_10_sdm630.ino b/tasmota/tasmota_xnrg_energy/xnrg_10_sdm630.ino index f6848707d..826d6a1e1 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_10_sdm630.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_10_sdm630.ino @@ -88,9 +88,9 @@ void SDM630Every250ms(void) if (error) { AddLog(LOG_LEVEL_DEBUG, PSTR("SDM: SDM630 error %d"), error); } else { - Energy.data_valid[0] = 0; - Energy.data_valid[1] = 0; - Energy.data_valid[2] = 0; + Energy->data_valid[0] = 0; + Energy->data_valid[1] = 0; + Energy->data_valid[2] = 0; // 0 1 2 3 4 5 6 7 8 // SA FC BC Fh Fl Sh Sl Cl Ch @@ -103,95 +103,95 @@ void SDM630Every250ms(void) switch(Sdm630.read_state) { case 0: - Energy.voltage[0] = value; + Energy->voltage[0] = value; break; case 1: - Energy.voltage[1] = value; + Energy->voltage[1] = value; break; case 2: - Energy.voltage[2] = value; + Energy->voltage[2] = value; break; case 3: - Energy.current[0] = value; + Energy->current[0] = value; break; case 4: - Energy.current[1] = value; + Energy->current[1] = value; break; case 5: - Energy.current[2] = value; + Energy->current[2] = value; break; case 6: - Energy.active_power[0] = value; + Energy->active_power[0] = value; break; case 7: - Energy.active_power[1] = value; + Energy->active_power[1] = value; break; case 8: - Energy.active_power[2] = value; + Energy->active_power[2] = value; break; case 9: - Energy.reactive_power[0] = value; + Energy->reactive_power[0] = value; break; case 10: - Energy.reactive_power[1] = value; + Energy->reactive_power[1] = value; break; case 11: - Energy.reactive_power[2] = value; + Energy->reactive_power[2] = value; break; case 12: - Energy.power_factor[0] = value; + Energy->power_factor[0] = value; break; case 13: - Energy.power_factor[1] = value; + Energy->power_factor[1] = value; break; case 14: - Energy.power_factor[2] = value; + Energy->power_factor[2] = value; break; case 15: - Energy.frequency[0] = value; + Energy->frequency[0] = value; break; case 16: - Energy.export_active[0] = value; + Energy->export_active[0] = value; break; case 17: - Energy.export_active[1] = value; + Energy->export_active[1] = value; break; case 18: - Energy.export_active[2] = value; + Energy->export_active[2] = value; break; case 19: - Energy.import_active[0] = value; + Energy->import_active[0] = value; break; case 20: - Energy.import_active[1] = value; + Energy->import_active[1] = value; break; case 21: - Energy.import_active[2] = value; + Energy->import_active[2] = value; break; case 22: -// Energy.import_active[0] = value; +// Energy->import_active[0] = value; EnergyUpdateTotal(); break; } @@ -217,8 +217,8 @@ void Sdm630SnsInit(void) uint8_t result = Sdm630Modbus->Begin(SDM630_SPEED); if (result) { if (2 == result) { ClaimSerial(); } - Energy.phase_count = 3; - Energy.frequency_common = true; // Use common frequency + Energy->phase_count = 3; + Energy->frequency_common = true; // Use common frequency } else { TasmotaGlobal.energy_driver = ENERGY_NONE; } diff --git a/tasmota/tasmota_xnrg_energy/xnrg_11_ddsu666.ino b/tasmota/tasmota_xnrg_energy/xnrg_11_ddsu666.ino index ab629c106..67e8cbbb2 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_11_ddsu666.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_11_ddsu666.ino @@ -68,7 +68,7 @@ void DDSU666Every250ms(void) if (error) { AddLog(LOG_LEVEL_DEBUG, PSTR("SDM: Ddsu666 error %d"), error); } else { - Energy.data_valid[0] = 0; + Energy->data_valid[0] = 0; // 0 1 2 3 4 5 6 7 8 // SA FC BC Fh Fl Sh Sl Cl Ch @@ -81,35 +81,35 @@ void DDSU666Every250ms(void) switch(Ddsu666.read_state) { case 0: - Energy.voltage[0] = value; // 230.2 V + Energy->voltage[0] = value; // 230.2 V break; case 1: - Energy.current[0] = value; // 1.260 A + Energy->current[0] = value; // 1.260 A break; case 2: - Energy.active_power[0] = value * 1000; // -196.3 W + Energy->active_power[0] = value * 1000; // -196.3 W break; case 3: - Energy.reactive_power[0] = value * 1000; // 92.2 + Energy->reactive_power[0] = value * 1000; // 92.2 break; case 4: - Energy.power_factor[0] = value; // 0.91 + Energy->power_factor[0] = value; // 0.91 break; case 5: - Energy.frequency[0] = value; // 50.0 Hz + Energy->frequency[0] = value; // 50.0 Hz break; case 6: - Energy.import_active[0] = value; // 478.492 kWh + Energy->import_active[0] = value; // 478.492 kWh break; case 7: - Energy.export_active[0] = value; // 6.216 kWh + Energy->export_active[0] = value; // 6.216 kWh break; } diff --git a/tasmota/tasmota_xnrg_energy/xnrg_12_solaxX1.ino b/tasmota/tasmota_xnrg_energy/xnrg_12_solaxX1.ino index c57fdd8d2..9a36439b9 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_12_solaxX1.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_12_solaxX1.ino @@ -284,19 +284,19 @@ void solaxX1_250MSecond(void) // Every 250 milliseconds } if (DataRead[6] == 0x11 && DataRead[7] == 0x82) { // received "Response for query (live data)" - Energy.data_valid[0] = 0; + Energy->data_valid[0] = 0; solaxX1.temperature = (DataRead[9] << 8) | DataRead[10]; // Temperature solaxX1.energy_today = ((DataRead[11] << 8) | DataRead[12]) * 0.1f; // Energy Today solaxX1.dc1_voltage = ((DataRead[13] << 8) | DataRead[14]) * 0.1f; // PV1 Voltage solaxX1.dc2_voltage = ((DataRead[15] << 8) | DataRead[16]) * 0.1f; // PV2 Voltage solaxX1.dc1_current = ((DataRead[17] << 8) | DataRead[18]) * 0.1f; // PV1 Current solaxX1.dc2_current = ((DataRead[19] << 8) | DataRead[20]) * 0.1f; // PV2 Current - Energy.current[0] = ((DataRead[21] << 8) | DataRead[22]) * 0.1f; // AC Current - Energy.voltage[0] = ((DataRead[23] << 8) | DataRead[24]) * 0.1f; // AC Voltage - Energy.frequency[0] = ((DataRead[25] << 8) | DataRead[26]) * 0.01f; // AC Frequency - Energy.active_power[0] = ((DataRead[27] << 8) | DataRead[28]); // AC Power + Energy->current[0] = ((DataRead[21] << 8) | DataRead[22]) * 0.1f; // AC Current + Energy->voltage[0] = ((DataRead[23] << 8) | DataRead[24]) * 0.1f; // AC Voltage + Energy->frequency[0] = ((DataRead[25] << 8) | DataRead[26]) * 0.01f; // AC Frequency + Energy->active_power[0] = ((DataRead[27] << 8) | DataRead[28]); // AC Power //temporal = (float)((DataRead[29] << 8) | DataRead[30]) * 0.1f; // Not Used - Energy.import_active[0] = ((DataRead[31] << 24) | (DataRead[32] << 16) | (DataRead[33] << 8) | DataRead[34]) * 0.1f; // Energy Total + Energy->import_active[0] = ((DataRead[31] << 24) | (DataRead[32] << 16) | (DataRead[33] << 8) | DataRead[34]) * 0.1f; // Energy Total solaxX1.runtime_total = (DataRead[35] << 24) | (DataRead[36] << 16) | (DataRead[37] << 8) | DataRead[38]; // Work Time Total solaxX1.runMode = (DataRead[39] << 8) | DataRead[40]; // Work mode //temporal = (float)((DataRead[41] << 8) | DataRead[42]); // Grid voltage fault value 0.1V @@ -444,9 +444,9 @@ void solaxX1_250MSecond(void) // Every 250 milliseconds if (!solaxX1_global.SendRetry_count) { // Inverter went "off" solaxX1_global.SendRetry_count = 20; DEBUG_SENSOR_LOG(PSTR("SX1: Inverter went \"off\"")); - Energy.data_valid[0] = ENERGY_WATCHDOG; + Energy->data_valid[0] = ENERGY_WATCHDOG; solaxX1.temperature = solaxX1.dc1_voltage = solaxX1.dc2_voltage = solaxX1.dc1_current = solaxX1.dc2_current = solaxX1.dc1_power = 0; - solaxX1.dc2_power = Energy.current[0] = Energy.voltage[0] = Energy.frequency[0] = Energy.active_power[0] = 0; + solaxX1.dc2_power = Energy->current[0] = Energy->voltage[0] = Energy->frequency[0] = Energy->active_power[0] = 0; solaxX1.runMode = -1; // off(line) solaxX1_global.AddressAssigned = false; } // end Inverter went "off" diff --git a/tasmota/tasmota_xnrg_energy/xnrg_13_fif_le01mr.ino b/tasmota/tasmota_xnrg_energy/xnrg_13_fif_le01mr.ino index 1ec4f7698..5be6cc2b2 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_13_fif_le01mr.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_13_fif_le01mr.ino @@ -125,7 +125,7 @@ void FifLEEvery250ms(void) if (error) { AddLog(LOG_LEVEL_DEBUG, PSTR("FiF-LE: LE01MR Modbus error %d"), error); } else { - Energy.data_valid[0] = 0; + Energy->data_valid[0] = 0; // CA=Client Address, FC=Function Code, BC=Byte Count, B3..B0=Data byte, Ch Cl = crc16 checksum // U32 registers: @@ -153,36 +153,36 @@ void FifLEEvery250ms(void) switch(Le01mr.read_state) { case 0: - Energy.frequency[0] = value_buff * 0.01f; // 5000 => 50.00 + Energy->frequency[0] = value_buff * 0.01f; // 5000 => 50.00 break; case 1: - Energy.voltage[0] = value_buff * 0.01f; // 23298 => 232.98 V + Energy->voltage[0] = value_buff * 0.01f; // 23298 => 232.98 V break; case 2: - Energy.power_factor[0] = ((int16_t)value_buff) * 0.001f; // 1000 => 1.000 //note: I never saw this negative... + Energy->power_factor[0] = ((int16_t)value_buff) * 0.001f; // 1000 => 1.000 //note: I never saw this negative... break; case 3: - Energy.current[0] = value_buff * 0.001f; // 114 => 0.114 A + Energy->current[0] = value_buff * 0.001f; // 114 => 0.114 A break; case 4: - Energy.active_power[0] = value_buff * 1.0f; // P [W] + Energy->active_power[0] = value_buff * 1.0f; // P [W] break; case 5: - Energy.reactive_power[0] = value_buff * 1.0f; // Q [var] + Energy->reactive_power[0] = value_buff * 1.0f; // Q [var] break; case 6: - Energy.apparent_power[0] = value_buff * 1.0f; // S [VA] + Energy->apparent_power[0] = value_buff * 1.0f; // S [VA] break; case 7: - Energy.import_active[0] = value_buff * 0.01f; // [kWh] - Le01mr.total_active = Energy.import_active[0]; // Useless + Energy->import_active[0] = value_buff * 0.01f; // [kWh] + Le01mr.total_active = Energy->import_active[0]; // Useless break; case 8: diff --git a/tasmota/tasmota_xnrg_energy/xnrg_14_bl09xx.ino b/tasmota/tasmota_xnrg_energy/xnrg_14_bl09xx.ino index 9287bab21..b944078af 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_14_bl09xx.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_14_bl09xx.ino @@ -131,7 +131,7 @@ bool Bl09XXDecode3940(void) { Bl09XX.power[0] = Bl09XX.rx_buffer[18] << 16 | Bl09XX.rx_buffer[17] << 8 | Bl09XX.rx_buffer[16]; // WATT_A signed if (bitRead(Bl09XX.power[0], 23)) { Bl09XX.power[0] |= 0xFF000000; } // Extend sign bit - if (Energy.phase_count > 1) { + if (Energy->phase_count > 1) { Bl09XX.current[1] = Bl09XX.rx_buffer[9] << 16 | Bl09XX.rx_buffer[8] << 8 | Bl09XX.rx_buffer[7]; // IB_RMS unsigned Bl09XX.power[1] = Bl09XX.rx_buffer[21] << 16 | Bl09XX.rx_buffer[20] << 8 | Bl09XX.rx_buffer[19]; // WATT_B signed if (bitRead(Bl09XX.power[1], 23)) { Bl09XX.power[1] |= 0xFF000000; } // Extend sign bit @@ -187,29 +187,29 @@ bool Bl09XXDecode42(void) { } void Bl09XXUpdateEnergy() { - if (Energy.power_on) { // Powered on - Energy.voltage[0] = (float)Bl09XX.voltage / Settings->energy_voltage_calibration; + if (Energy->power_on) { // Powered on + Energy->voltage[0] = (float)Bl09XX.voltage / Settings->energy_voltage_calibration; #ifdef DEBUG_BL09XX - AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("BL9: U %2_f, T %2_f"), &Energy.voltage[0], &Bl09XX.temperature); + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("BL9: U %2_f, T %2_f"), &Energy->voltage[0], &Bl09XX.temperature); #endif - for (uint32_t chan = 0; chan < Energy.phase_count; chan++) { + for (uint32_t chan = 0; chan < Energy->phase_count; chan++) { uint32_t power_calibration = EnergyGetCalibration(chan, ENERGY_POWER_CALIBRATION); uint32_t current_calibration = EnergyGetCalibration(chan, ENERGY_CURRENT_CALIBRATION); if (Bl09XX.power[chan] > power_calibration) { // We need at least 1W - Energy.active_power[chan] = (float)Bl09XX.power[chan] / power_calibration; - Energy.current[chan] = (float)Bl09XX.current[chan] / current_calibration; + Energy->active_power[chan] = (float)Bl09XX.power[chan] / power_calibration; + Energy->current[chan] = (float)Bl09XX.current[chan] / current_calibration; } else { - Energy.active_power[chan] = 0; - Energy.current[chan] = 0; + Energy->active_power[chan] = 0; + Energy->current[chan] = 0; } #ifdef DEBUG_BL09XX - AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("BL9: Chan[%d] I %2_f, P %2_f"), chan, &Energy.current[chan], &Energy.active_power[chan]); + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("BL9: Chan[%d] I %2_f, P %2_f"), chan, &Energy->current[chan], &Energy->active_power[chan]); #endif } } else { // Powered off - Energy.voltage[0] = 0; - Energy.active_power[0] = Energy.active_power[1] = 0; - Energy.current[0] = Energy.current[1] = 0; + Energy->voltage[0] = 0; + Energy->active_power[0] = Energy->active_power[1] = 0; + Energy->current[0] = Energy->current[1] = 0; } } @@ -229,7 +229,7 @@ void Bl09XXSerialInput(void) { for (uint32_t i = 0; i < Bl09XX.buffer_size -1; i++) { checksum += Bl09XX.rx_buffer[i]; } checksum ^= 0xFF; if (checksum == Bl09XX.rx_buffer[Bl09XX.buffer_size -1]) { - Energy.data_valid[0] = 0; + Energy->data_valid[0] = 0; bool ok; if (BL0942_MODEL == Bl09XX.model) { ok = Bl09XXDecode42(); @@ -261,14 +261,14 @@ void Bl09XXSerialInput(void) { /********************************************************************************************/ void Bl09XXEverySecond(void) { - if (Energy.data_valid[0] > ENERGY_WATCHDOG) { + if (Energy->data_valid[0] > ENERGY_WATCHDOG) { Bl09XX.voltage = 0; memset(Bl09XX.current, 0, sizeof(Bl09XX.current)); memset(Bl09XX.power, 0, sizeof(Bl09XX.power)); } else { // Calculate energy by using active power - for (uint32_t channel = 0; channel < Energy.phase_count; channel++) { - Energy.kWhtoday_delta[channel] += Energy.active_power[channel] * 1000 / 36; + for (uint32_t channel = 0; channel < Energy->phase_count; channel++) { + Energy->kWhtoday_delta[channel] += Energy->active_power[channel] * 1000 / 36; } EnergyUpdateToday(); } @@ -303,7 +303,7 @@ void Bl09XXInit(void) { #ifdef DEBUG_BL09XX AddLog(LOG_LEVEL_DEBUG, PSTR("BL9: Send Init string")); #endif - Energy.use_overtemp = true; // Use global temperature for overtemp detection + Energy->use_overtemp = true; // Use global temperature for overtemp detection for (uint32_t i = 0; i < 5; i++) { uint8_t crc, byte; crc = byte = BL09XX_WRITE_COMMAND | Bl09XX.address; @@ -316,7 +316,7 @@ void Bl09XXInit(void) { delay(1); } } else { - Energy.use_overtemp = false; // Use global temperature for overtemp detection + Energy->use_overtemp = false; // Use global temperature for overtemp detection } } else { TasmotaGlobal.energy_driver = ENERGY_NONE; @@ -343,10 +343,10 @@ void Bl09XXPreInit(void) { Bl09XX.buffer_size = bl09xx_buffer_size[Bl09XX.model]; Bl09XX.rx_buffer = (uint8_t*)(malloc(Bl09XX.buffer_size)); if (Bl09XX.rx_buffer != nullptr) { - Energy.voltage_common = true; // Use common voltage - Energy.frequency_common = true; // Use common frequency - Energy.use_overtemp = true; // Use global temperature for overtemp detection - Energy.phase_count = bl09xx_phase_count[Bl09XX.model]; // Handle two channels as two phases + Energy->voltage_common = true; // Use common voltage + Energy->frequency_common = true; // Use common frequency + Energy->use_overtemp = true; // Use global temperature for overtemp detection + Energy->phase_count = bl09xx_phase_count[Bl09XX.model]; // Handle two channels as two phases TasmotaGlobal.energy_driver = XNRG_14; AddLog(LOG_LEVEL_DEBUG,PSTR("BL9: Enabling BL09%02d"), bl09xx_type[Bl09XX.model]); } @@ -357,20 +357,20 @@ void Bl09XXPreInit(void) { bool Bl09XXCommand(void) { bool serviced = true; - uint32_t channel = (2 == XdrvMailbox.index) && (Energy.phase_count > 1) ? 1 : 0; + uint32_t channel = (2 == XdrvMailbox.index) && (Energy->phase_count > 1) ? 1 : 0; uint32_t value = (uint32_t)(CharToFloat(XdrvMailbox.data) * 100); // 1.23 = 123 - if (CMND_POWERSET == Energy.command_code) { + if (CMND_POWERSET == Energy->command_code) { if (XdrvMailbox.data_len && Bl09XX.power[channel]) { XdrvMailbox.payload = (Bl09XX.power[channel] * 100) / value; } } - else if (CMND_VOLTAGESET == Energy.command_code) { + else if (CMND_VOLTAGESET == Energy->command_code) { if (XdrvMailbox.data_len && Bl09XX.voltage) { XdrvMailbox.payload = (Bl09XX.voltage * 100) / value; } } - else if (CMND_CURRENTSET == Energy.command_code) { + else if (CMND_CURRENTSET == Energy->command_code) { if (XdrvMailbox.data_len && Bl09XX.current[channel]) { XdrvMailbox.payload = (Bl09XX.current[channel] * 100) / value; } diff --git a/tasmota/tasmota_xnrg_energy/xnrg_15_teleinfo.ino b/tasmota/tasmota_xnrg_energy/xnrg_15_teleinfo.ino index f04b5f730..c25025197 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_15_teleinfo.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_15_teleinfo.ino @@ -285,16 +285,16 @@ void DataCallback(struct _ValueList * me, uint8_t flags) // Voltage V (not present on all Smart Meter) if ( ilabel == LABEL_TENSION || ilabel == LABEL_URMS1 || ilabel == LABEL_URMS2 || ilabel == LABEL_URMS3) { - Energy.voltage_available = true; + Energy->voltage_available = true; float volt = (float) atoi(me->value); AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Voltage %s=%s, now %d"), me->name, me->value, (int) volt); if ( ilabel == LABEL_URMS2) { - Energy.voltage[1] = volt; + Energy->voltage[1] = volt; } else if ( ilabel == LABEL_URMS3) { - Energy.voltage[2] = volt; + Energy->voltage[2] = volt; } else { - Energy.voltage[0] = volt; + Energy->voltage[0] = volt; } } @@ -304,25 +304,25 @@ void DataCallback(struct _ValueList * me, uint8_t flags) || ilabel == LABEL_IINST2 || ilabel == LABEL_IRMS2 || ilabel == LABEL_IINST3 || ilabel == LABEL_IRMS3 ) { - Energy.current_available = true; + Energy->current_available = true; float current = (float) atoi(me->value); AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Current %s=%s, now %d"), me->name, me->value, (int) current); if (ilabel == LABEL_IINST2 || ilabel == LABEL_IRMS2) { - Energy.current[1] = current; + Energy->current[1] = current; } else if (ilabel == LABEL_IINST3 || ilabel == LABEL_IRMS3) { - Energy.phase_count = 3; - Energy.current[2] = current; + Energy->phase_count = 3; + Energy->current[2] = current; } else { - Energy.current[0] = current; + Energy->current[0] = current; } } // Power P else if (ilabel == LABEL_PAPP || ilabel == LABEL_SINSTS) { - Energy.active_power[0] = (float) atoi(me->value);; - AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Power %s, now %d"), me->value, (int) Energy.active_power[0]); + Energy->active_power[0] = (float) atoi(me->value);; + AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Power %s, now %d"), me->value, (int) Energy->active_power[0]); } // Ok now not so real time values Does this value is new or changed? @@ -394,11 +394,11 @@ void DataCallback(struct _ValueList * me, uint8_t flags) AddLog (LOG_LEVEL_INFO, PSTR ("TIC: Total counter updated to %ld Wh"), total_wh); if (total_wh>0) { - Energy.total[0] = (float) total_wh / 1000.0f; - Energy.import_active[0] = Energy.total[0]; - //Energy.import_active[0] = (float)total/1000.0f; + Energy->total[0] = (float) total_wh / 1000.0f; + Energy->import_active[0] = Energy->total[0]; + //Energy->import_active[0] = (float)total/1000.0f; //EnergyUpdateTotal(); - AddLog (LOG_LEVEL_DEBUG_MORE, PSTR ("TIC: import_active[0]=%.3fKWh"), Energy.import_active[0] ); + AddLog (LOG_LEVEL_DEBUG_MORE, PSTR ("TIC: import_active[0]=%.3fKWh"), Energy->import_active[0] ); } } @@ -406,8 +406,8 @@ void DataCallback(struct _ValueList * me, uint8_t flags) else if ( ilabel == LABEL_EAST) { total_wh = atol(me->value); - Energy.total[0] = (float) total_wh / 1000.0f; - Energy.import_active[0] = Energy.total[0]; + Energy->total[0] = (float) total_wh / 1000.0f; + Energy->import_active[0] = Energy->total[0]; AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Total:%ldWh"), total_wh); } @@ -591,7 +591,7 @@ Comments: - void NewFrameCallback(struct _ValueList * me) { // Reset Energy Watchdog - Energy.data_valid[0] = 0; + Energy->data_valid[0] = 0; // Deprecated see setOption108 // send teleinfo MQTT raw data only if setup like that @@ -631,8 +631,8 @@ void TInfoDrvInit(void) { if (PinUsed(GPIO_TELEINFO_RX)) { tic_rx_pin = Pin(GPIO_TELEINFO_RX); TasmotaGlobal.energy_driver = XNRG_15; - Energy.voltage_available = false; - Energy.phase_count = 1; + Energy->voltage_available = false; + Energy->phase_count = 1; // init hardware energy counters total_wh = 0; Settings->flag3.hardware_energy_total = true; @@ -763,7 +763,7 @@ bool TInfoCmd(void) { //uint8_t name_len = strlen(D_NAME_TELEINFO); // At least "EnergyConfig" - if (CMND_ENERGYCONFIG == Energy.command_code) { + if (CMND_ENERGYCONFIG == Energy->command_code) { AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: len %d, data '%s'"), XdrvMailbox.data_len, XdrvMailbox.data ? XdrvMailbox.data : "null" ); @@ -1106,7 +1106,7 @@ void TInfoShow(bool json) { // Add new value (not part of TIC JSON Object) if (isousc) { - ResponseAppend_P(PSTR(",\"Load\":%d"),(int) ((Energy.current[0]*100.0f) / isousc)); + ResponseAppend_P(PSTR(",\"Load\":%d"),(int) ((Energy->current[0]*100.0f) / isousc)); } // add teleinfo TIC object @@ -1126,8 +1126,8 @@ void TInfoShow(bool json) uint8_t red, green, blue; char phase_color[8]; - for (int i=0; iphase_count ; i++ ) { + percent = (int) ((Energy->current[i]*100.0f) / isousc) ; if (percent > 100) { percent = 100; } @@ -1150,7 +1150,7 @@ void TInfoShow(bool json) } if (tinfo_mode==TINFO_MODE_HISTORIQUE ) { - if (Energy.phase_count==3) { + if (Energy->phase_count==3) { int imax[3]; for (int i=LABEL_IMAX1; i<=LABEL_IMAX3; i++) { if (getValueFromLabelIndex(i, value) ) { @@ -1177,7 +1177,7 @@ void TInfoShow(bool json) } } if (contrat && isousc) { - int percent = (int) ((Energy.current[0]*100.0f) / isousc) ; + int percent = (int) ((Energy->current[0]*100.0f) / isousc) ; GetTextIndexed(name, sizeof(name), contrat, kContratName); WSContentSend_P(HTTP_ENERGY_CONTRAT_TELEINFO, name, isousc); //WSContentSend_P(HTTP_ENERGY_LOAD_TELEINFO, percent); diff --git a/tasmota/tasmota_xnrg_energy/xnrg_16_iem3000.ino b/tasmota/tasmota_xnrg_energy/xnrg_16_iem3000.ino index 10f15afb1..5fbb007fb 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_16_iem3000.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_16_iem3000.ino @@ -83,7 +83,7 @@ void IEM3000Every250ms(void) if (error) { AddLog(LOG_LEVEL_DEBUG, PSTR("SDM: Iem3000 error %d"), error); } else { - Energy.data_valid[0] = 0; + Energy->data_valid[0] = 0; // 0 1 2 3 4 5 6 7 8 // SA FC BC Fh Fl Sh Sl Cl Ch @@ -108,55 +108,55 @@ void IEM3000Every250ms(void) switch(Iem3000.read_state) { case 0: - Energy.current[0] = value; + Energy->current[0] = value; break; case 1: - Energy.current[1] = value; + Energy->current[1] = value; break; case 2: - Energy.current[2] = value; + Energy->current[2] = value; break; case 3: - Energy.voltage[0] = value; + Energy->voltage[0] = value; break; case 4: - Energy.voltage[1] = value; + Energy->voltage[1] = value; break; case 5: - Energy.voltage[2] = value; + Energy->voltage[2] = value; break; case 6: - Energy.active_power[0] = value*1000; + Energy->active_power[0] = value*1000; break; case 7: - Energy.active_power[1] = value*1000; + Energy->active_power[1] = value*1000; break; case 8: - Energy.active_power[2] = value*1000; + Energy->active_power[2] = value*1000; break; case 9: - Energy.frequency[0] = value; + Energy->frequency[0] = value; break; case 10: - Energy.import_active[0] = value64/1000.0; + Energy->import_active[0] = value64/1000.0; break; case 11: - Energy.import_active[1] = value64/1000.0; + Energy->import_active[1] = value64/1000.0; break; case 12: - Energy.import_active[2] = value64/1000.0; + Energy->import_active[2] = value64/1000.0; break; case 13: @@ -185,8 +185,8 @@ void Iem3000SnsInit(void) uint8_t result = Iem3000Modbus->Begin(IEM3000_SPEED); if (result) { if (2 == result) { ClaimSerial(); } - Energy.phase_count = 3; - Energy.frequency_common = true; // Use common frequency + Energy->phase_count = 3; + Energy->frequency_common = true; // Use common frequency } else { TasmotaGlobal.energy_driver = ENERGY_NONE; } diff --git a/tasmota/tasmota_xnrg_energy/xnrg_17_ornowe517.ino b/tasmota/tasmota_xnrg_energy/xnrg_17_ornowe517.ino index cbdb90d0f..4e7794908 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_17_ornowe517.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_17_ornowe517.ino @@ -84,9 +84,9 @@ void WE517Every250ms(void) if (error) { AddLog(LOG_LEVEL_DEBUG, PSTR("ORNO: WE517 error %d"), error); } else { - Energy.data_valid[0] = 0; - Energy.data_valid[1] = 0; - Energy.data_valid[2] = 0; + Energy->data_valid[0] = 0; + Energy->data_valid[1] = 0; + Energy->data_valid[2] = 0; // 0 1 2 3 4 5 6 7 8 // SA FC BC Fh Fl Sh Sl Cl Ch @@ -99,71 +99,71 @@ void WE517Every250ms(void) switch(We517.read_state) { case 0: - Energy.voltage[0] = value; + Energy->voltage[0] = value; break; case 1: - Energy.voltage[1] = value; + Energy->voltage[1] = value; break; case 2: - Energy.voltage[2] = value; + Energy->voltage[2] = value; break; case 3: - Energy.current[0] = value; + Energy->current[0] = value; break; case 4: - Energy.current[1] = value; + Energy->current[1] = value; break; case 5: - Energy.current[2] = value; + Energy->current[2] = value; break; case 6: - Energy.active_power[0] = value * 1000; + Energy->active_power[0] = value * 1000; break; case 7: - Energy.active_power[1] = value * 1000; + Energy->active_power[1] = value * 1000; break; case 8: - Energy.active_power[2] = value * 1000; + Energy->active_power[2] = value * 1000; break; case 9: - Energy.reactive_power[0] = value; + Energy->reactive_power[0] = value; break; case 10: - Energy.reactive_power[1] = value; + Energy->reactive_power[1] = value; break; case 11: - Energy.reactive_power[2] = value; + Energy->reactive_power[2] = value; break; case 12: - Energy.power_factor[0] = value; + Energy->power_factor[0] = value; break; case 13: - Energy.power_factor[1] = value; + Energy->power_factor[1] = value; break; case 14: - Energy.power_factor[2] = value; + Energy->power_factor[2] = value; break; case 15: - Energy.frequency[0] = value; + Energy->frequency[0] = value; break; case 16: - Energy.import_active[0] = value; + Energy->import_active[0] = value; EnergyUpdateTotal(); break; } @@ -192,8 +192,8 @@ void We517SnsInit(void) { Serial.begin(WE517_SPEED, SERIAL_8E1); ClaimSerial(); } - Energy.phase_count = 3; - Energy.frequency_common = true; // Use common frequency + Energy->phase_count = 3; + Energy->frequency_common = true; // Use common frequency } else { TasmotaGlobal.energy_driver = ENERGY_NONE; } diff --git a/tasmota/tasmota_xnrg_energy/xnrg_18_sdm72.ino b/tasmota/tasmota_xnrg_energy/xnrg_18_sdm72.ino index bde9d90df..b058b09c0 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_18_sdm72.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_18_sdm72.ino @@ -76,7 +76,7 @@ void Sdm72Every250ms(void) if (error) { AddLog(LOG_LEVEL_DEBUG, PSTR("SDM: SDM72 error %d"), error); } else { - Energy.data_valid[0] = 0; + Energy->data_valid[0] = 0; float value; ((uint8_t*)&value)[3] = buffer[3]; // Get float values @@ -86,7 +86,7 @@ void Sdm72Every250ms(void) switch(Sdm72.read_state) { case 0: - Energy.active_power[0] = value; // W + Energy->active_power[0] = value; // W break; case 1: @@ -103,18 +103,18 @@ void Sdm72Every250ms(void) break; case 4: - Energy.import_active[0] = value; // kWh + Energy->import_active[0] = value; // kWh break; case 5: - Energy.export_active[0] = value; // kWh + Energy->export_active[0] = value; // kWh break; #endif // SDM72_IMPEXP } ++Sdm72.read_state %= nitems(sdm72_register); if (0 == Sdm72.read_state && !isnan(Sdm72.total_active)) { - Energy.import_active[0] = Sdm72.total_active; + Energy->import_active[0] = Sdm72.total_active; EnergyUpdateTotal(); } } @@ -144,8 +144,8 @@ void Sdm72SnsInit(void) void Sdm72DrvInit(void) { if (PinUsed(GPIO_SDM72_RX) && PinUsed(GPIO_SDM72_TX)) { - Energy.voltage_available = false; - Energy.current_available = false; + Energy->voltage_available = false; + Energy->current_available = false; TasmotaGlobal.energy_driver = XNRG_18; } } diff --git a/tasmota/tasmota_xnrg_energy/xnrg_19_cse7761.ino b/tasmota/tasmota_xnrg_energy/xnrg_19_cse7761.ino index 71e675e1b..a75035b5b 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_19_cse7761.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_19_cse7761.ino @@ -458,28 +458,28 @@ void Cse7761GetData(void) { CSE7761Data.current_rms[0], CSE7761Data.current_rms[1], CSE7761Data.active_power[0], CSE7761Data.active_power[1]); - if (Energy.power_on) { // Powered on + if (Energy->power_on) { // Powered on // Voltage = RmsU * RmsUC * 10 / 0x400000 - // Energy.voltage[0] = (float)(((uint64_t)CSE7761Data.voltage_rms * CSE7761Data.coefficient[RmsUC] * 10) >> 22) / 1000; // V - Energy.voltage[0] = ((float)CSE7761Data.voltage_rms / Settings->energy_voltage_calibration); // V + // Energy->voltage[0] = (float)(((uint64_t)CSE7761Data.voltage_rms * CSE7761Data.coefficient[RmsUC] * 10) >> 22) / 1000; // V + Energy->voltage[0] = ((float)CSE7761Data.voltage_rms / Settings->energy_voltage_calibration); // V #ifdef CSE7761_FREQUENCY - Energy.frequency[0] = (CSE7761Data.frequency) ? ((float)Settings->energy_frequency_calibration / 8 / CSE7761Data.frequency) : 0; // Hz + Energy->frequency[0] = (CSE7761Data.frequency) ? ((float)Settings->energy_frequency_calibration / 8 / CSE7761Data.frequency) : 0; // Hz #endif for (uint32_t channel = 0; channel < 2; channel++) { - Energy.data_valid[channel] = 0; + Energy->data_valid[channel] = 0; uint32_t power_calibration = EnergyGetCalibration(channel, ENERGY_POWER_CALIBRATION); // Active power = PowerPA * PowerPAC * 1000 / 0x80000000 - // Energy.active_power[channel] = (float)(((uint64_t)CSE7761Data.active_power[channel] * CSE7761Data.coefficient[PowerPAC + channel] * 1000) >> 31) / 1000; // W - Energy.active_power[channel] = (float)CSE7761Data.active_power[channel] / power_calibration; // W - if (0 == Energy.active_power[channel]) { - Energy.current[channel] = 0; + // Energy->active_power[channel] = (float)(((uint64_t)CSE7761Data.active_power[channel] * CSE7761Data.coefficient[PowerPAC + channel] * 1000) >> 31) / 1000; // W + Energy->active_power[channel] = (float)CSE7761Data.active_power[channel] / power_calibration; // W + if (0 == Energy->active_power[channel]) { + Energy->current[channel] = 0; } else { uint32_t current_calibration = EnergyGetCalibration(channel, ENERGY_CURRENT_CALIBRATION); // Current = RmsIA * RmsIAC / 0x800000 - // Energy.current[channel] = (float)(((uint64_t)CSE7761Data.current_rms[channel] * CSE7761Data.coefficient[RmsIAC + channel]) >> 23) / 1000; // A - Energy.current[channel] = (float)CSE7761Data.current_rms[channel] / current_calibration; // A - CSE7761Data.energy[channel] += Energy.active_power[channel]; + // Energy->current[channel] = (float)(((uint64_t)CSE7761Data.current_rms[channel] * CSE7761Data.coefficient[RmsIAC + channel]) >> 23) / 1000; // A + Energy->current[channel] = (float)CSE7761Data.current_rms[channel] / current_calibration; // A + CSE7761Data.energy[channel] += Energy->active_power[channel]; CSE7761Data.energy_update[channel]++; } } @@ -563,7 +563,7 @@ void Cse7761EverySecond(void) { if (2 == CSE7761Data.ready) { for (uint32_t channel = 0; channel < 2; channel++) { if (CSE7761Data.energy_update[channel]) { - Energy.kWhtoday_delta[channel] += ((CSE7761Data.energy[channel] * 1000) / CSE7761Data.energy_update[channel]) / 36; + Energy->kWhtoday_delta[channel] += ((CSE7761Data.energy[channel] * 1000) / CSE7761Data.energy_update[channel]) / 36; CSE7761Data.energy[channel] = 0; CSE7761Data.energy_update[channel] = 0; } @@ -597,12 +597,12 @@ void Cse7761DrvInit(void) { if (PinUsed(GPIO_CSE7761_RX) && PinUsed(GPIO_CSE7761_TX)) { CSE7761Data.ready = 0; CSE7761Data.init = 4; // Init setup steps - Energy.phase_count = 2; // Handle two channels as two phases - Energy.voltage_common = true; // Use common voltage + Energy->phase_count = 2; // Handle two channels as two phases + Energy->voltage_common = true; // Use common voltage #ifdef CSE7761_FREQUENCY - Energy.frequency_common = true; // Use common frequency + Energy->frequency_common = true; // Use common frequency #endif - Energy.use_overtemp = true; // Use global temperature for overtemp detection + Energy->use_overtemp = true; // Use global temperature for overtemp detection TasmotaGlobal.energy_driver = XNRG_19; } } @@ -613,33 +613,33 @@ bool Cse7761Command(void) { uint32_t channel = (2 == XdrvMailbox.index) ? 1 : 0; uint32_t value = (uint32_t)(CharToFloat(XdrvMailbox.data) * 100); // 1.23 = 123 - if (CMND_POWERCAL == Energy.command_code) { + if (CMND_POWERCAL == Energy->command_code) { if (1 == XdrvMailbox.payload) { XdrvMailbox.payload = Cse7761Ref(PowerPAC); } // Service in xdrv_03_energy.ino } - else if (CMND_POWERSET == Energy.command_code) { + else if (CMND_POWERSET == Energy->command_code) { if (XdrvMailbox.data_len && CSE7761Data.active_power[channel]) { if ((value > 100) && (value < 200000)) { // Between 1W and 2000W XdrvMailbox.payload = ((CSE7761Data.active_power[channel]) / value) * 100; } } } - else if (CMND_VOLTAGECAL == Energy.command_code) { + else if (CMND_VOLTAGECAL == Energy->command_code) { if (1 == XdrvMailbox.payload) { XdrvMailbox.payload = Cse7761Ref(RmsUC); } // Service in xdrv_03_energy.ino } - else if (CMND_VOLTAGESET == Energy.command_code) { + else if (CMND_VOLTAGESET == Energy->command_code) { if (XdrvMailbox.data_len && CSE7761Data.voltage_rms) { if ((value > 10000) && (value < 26000)) { // Between 100V and 260V XdrvMailbox.payload = (CSE7761Data.voltage_rms * 100) / value; } } } - else if (CMND_CURRENTCAL == Energy.command_code) { + else if (CMND_CURRENTCAL == Energy->command_code) { if (1 == XdrvMailbox.payload) { XdrvMailbox.payload = Cse7761Ref(RmsIAC); } // Service in xdrv_03_energy.ino } - else if (CMND_CURRENTSET == Energy.command_code) { + else if (CMND_CURRENTSET == Energy->command_code) { if (XdrvMailbox.data_len && CSE7761Data.current_rms[channel]) { if ((value > 1000) && (value < 1000000)) { // Between 10mA and 10A XdrvMailbox.payload = ((CSE7761Data.current_rms[channel] * 100) / value) * 1000; @@ -647,11 +647,11 @@ bool Cse7761Command(void) { } } #ifdef CSE7761_FREQUENCY - else if (CMND_FREQUENCYCAL == Energy.command_code) { + else if (CMND_FREQUENCYCAL == Energy->command_code) { if (1 == XdrvMailbox.payload) { XdrvMailbox.payload = CSE7761_FREF; } // Service in xdrv_03_energy.ino } - else if (CMND_FREQUENCYSET == Energy.command_code) { + else if (CMND_FREQUENCYSET == Energy->command_code) { if (XdrvMailbox.data_len && CSE7761Data.frequency) { if ((value > 4500) && (value < 6500)) { // Between 45.00Hz and 65.00Hz XdrvMailbox.payload = (CSE7761Data.frequency * 8 * value) / 100; diff --git a/tasmota/tasmota_xnrg_energy/xnrg_21_sdm230.ino b/tasmota/tasmota_xnrg_energy/xnrg_21_sdm230.ino index 90f16f566..f851b8110 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_21_sdm230.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_21_sdm230.ino @@ -58,7 +58,7 @@ const uint16_t sdm230_start_addresses[] { 0x0046, // SDM230_FREQUENCY [Hz] 0X0048, // SDM230_IMPORT_ACTIVE [kWh] 0X004A, // SDM230_EXPORT_ACTIVE [kWh] -// 0X0156, // SDM230_TOTAL_ENERGY_ACTIVE [kWh] // = SDM230_IMPORT_ACTIVE = Energy.total +// 0X0156, // SDM230_TOTAL_ENERGY_ACTIVE [kWh] // = SDM230_IMPORT_ACTIVE = Energy->total // read more registers offered by SDM230 (may cause timing issues) #ifdef SDM230_MORE_REGS @@ -106,7 +106,7 @@ void SDM230Every250ms(void) if (error) { AddLog(LOG_LEVEL_DEBUG, PSTR("SDM: SDM230 error %d"), error); } else { - Energy.data_valid[0] = 0; + Energy->data_valid[0] = 0; // 0 1 2 3 4 5 6 7 8 // SA FC BC Fh Fl Sh Sl Cl Ch @@ -119,39 +119,39 @@ void SDM230Every250ms(void) switch(Sdm230.read_state) { case 0: - Energy.voltage[0] = value; // 230.2 V + Energy->voltage[0] = value; // 230.2 V break; case 1: - Energy.current[0] = value; // 1.260 A + Energy->current[0] = value; // 1.260 A break; case 2: - Energy.active_power[0] = value; // -196.3 W + Energy->active_power[0] = value; // -196.3 W break; case 3: - Energy.apparent_power[0] = value; // 223.4 VA + Energy->apparent_power[0] = value; // 223.4 VA break; case 4: - Energy.reactive_power[0] = value; // 92.2 + Energy->reactive_power[0] = value; // 92.2 break; case 5: - Energy.power_factor[0] = value; // -0.91 + Energy->power_factor[0] = value; // -0.91 break; case 6: - Energy.frequency[0] = value; // 50.0 Hz + Energy->frequency[0] = value; // 50.0 Hz break; case 7: - Energy.import_active[0] = value; // 6.216 kWh => used in EnergyUpdateTotal() + Energy->import_active[0] = value; // 6.216 kWh => used in EnergyUpdateTotal() break; case 8: - Energy.export_active[0] = value; // 478.492 kWh + Energy->export_active[0] = value; // 478.492 kWh break; #ifdef SDM230_MORE_REGS @@ -192,8 +192,8 @@ void Sdm230SnsInit(void) uint8_t result = Sdm230Modbus->Begin(SDM230_SPEED); if (result) { if (2 == result) { ClaimSerial(); } - Energy.phase_count = 1; - Energy.frequency_common = true; // Use common frequency + Energy->phase_count = 1; + Energy->frequency_common = true; // Use common frequency } else { TasmotaGlobal.energy_driver = ENERGY_NONE; } diff --git a/tasmota/tasmota_xnrg_energy/xnrg_22_bl6523.ino b/tasmota/tasmota_xnrg_energy/xnrg_22_bl6523.ino index 2bdd3eff4..383b19073 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_22_bl6523.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_22_bl6523.ino @@ -162,16 +162,16 @@ RX: 35 0C TX: 00 00 00 F3 (WATT_HR) switch(rx_buffer[1]) { case BL6523_REG_AMPS : - Energy.current[SINGLE_PHASE] = (float)((tx_buffer[2] << 16) | (tx_buffer[1] << 8) | tx_buffer[0]) / Settings->energy_current_calibration; // 1.260 A + Energy->current[SINGLE_PHASE] = (float)((tx_buffer[2] << 16) | (tx_buffer[1] << 8) | tx_buffer[0]) / Settings->energy_current_calibration; // 1.260 A break; case BL6523_REG_VOLTS : - Energy.voltage[SINGLE_PHASE] = (float)((tx_buffer[2] << 16) | (tx_buffer[1] << 8) | tx_buffer[0]) / Settings->energy_voltage_calibration; // 230.2 V + Energy->voltage[SINGLE_PHASE] = (float)((tx_buffer[2] << 16) | (tx_buffer[1] << 8) | tx_buffer[0]) / Settings->energy_voltage_calibration; // 230.2 V break; case BL6523_REG_FREQ : - Energy.frequency[SINGLE_PHASE] = (float)((tx_buffer[2] << 16) | (tx_buffer[1] << 8) | tx_buffer[0]) / Settings->energy_frequency_calibration; // 50.0 Hz + Energy->frequency[SINGLE_PHASE] = (float)((tx_buffer[2] << 16) | (tx_buffer[1] << 8) | tx_buffer[0]) / Settings->energy_frequency_calibration; // 50.0 Hz break; case BL6523_REG_WATTS : - Energy.active_power[SINGLE_PHASE] = (float)((tx_buffer[2] << 16) | (tx_buffer[1] << 8) | tx_buffer[0]) / Settings->energy_power_calibration; // -196.3 W + Energy->active_power[SINGLE_PHASE] = (float)((tx_buffer[2] << 16) | (tx_buffer[1] << 8) | tx_buffer[0]) / Settings->energy_power_calibration; // -196.3 W break; case BL6523_REG_POWF : /* Power factor =(sign bit)*((PF[22]×2^-1)+(PF[21]×2^-2)+。。。) @@ -185,15 +185,15 @@ switch(rx_buffer[1]) { powf_word = powf_word & (0x7fffff >> (1+i)); } powf = (powf_buf >> 23) ? (0.0f - (powf)) : powf; // Negate if sign bit(24) is set - Energy.power_factor[SINGLE_PHASE] = powf; + Energy->power_factor[SINGLE_PHASE] = powf; break; case BL6523_REG_WATTHR : - Energy.import_active[SINGLE_PHASE] = (float)((tx_buffer[2] << 16) | (tx_buffer[1] << 8) | tx_buffer[0]) / ( Settings->energy_power_calibration - BL6523_PWHRREF_D ); // 6.216 kWh => used in EnergyUpdateTotal() + Energy->import_active[SINGLE_PHASE] = (float)((tx_buffer[2] << 16) | (tx_buffer[1] << 8) | tx_buffer[0]) / ( Settings->energy_power_calibration - BL6523_PWHRREF_D ); // 6.216 kWh => used in EnergyUpdateTotal() break; default : break; } - Energy.data_valid[SINGLE_PHASE] = 0; + Energy->data_valid[SINGLE_PHASE] = 0; EnergyUpdateTotal(); if (!Bl6523.discovery_triggered) { @@ -239,7 +239,7 @@ void Bl6523Init(void) ClaimSerial(); } Bl6523.type = 1; - Energy.phase_count = 1; + Energy->phase_count = 1; AddLog(LOG_LEVEL_DEBUG, PSTR("BL6:Init Success" )); } else @@ -256,46 +256,46 @@ bool Bl6523Command(void) { int32_t value = (int32_t)(CharToFloat(XdrvMailbox.data) * 1000); // 1.234 = 1234, -1.234 = -1234 uint32_t abs_value = abs(value) / 10; // 1.23 = 123, -1.23 = 123 - if ((CMND_POWERCAL == Energy.command_code) || (CMND_VOLTAGECAL == Energy.command_code) || (CMND_CURRENTCAL == Energy.command_code)) { + if ((CMND_POWERCAL == Energy->command_code) || (CMND_VOLTAGECAL == Energy->command_code) || (CMND_CURRENTCAL == Energy->command_code)) { // Service in xdrv_03_energy.ino } - else if (CMND_POWERSET == Energy.command_code) { + else if (CMND_POWERSET == Energy->command_code) { if (XdrvMailbox.data_len) { if ((abs_value > 100) && (abs_value < 200000)) { // Between 1.00 and 2000.00 W XdrvMailbox.payload = abs_value; } } } - else if (CMND_VOLTAGESET == Energy.command_code) { + else if (CMND_VOLTAGESET == Energy->command_code) { if (XdrvMailbox.data_len) { if ((abs_value > 10000) && (abs_value < 26000)) { // Between 100.00 and 260.00 V XdrvMailbox.payload = abs_value; } } } - else if (CMND_CURRENTSET == Energy.command_code) { + else if (CMND_CURRENTSET == Energy->command_code) { if (XdrvMailbox.data_len) { if ((abs_value > 1000) && (abs_value < 1000000)) { // Between 10.00 mA and 10.00000 A XdrvMailbox.payload = abs_value; } } } - else if (CMND_FREQUENCYSET == Energy.command_code) { + else if (CMND_FREQUENCYSET == Energy->command_code) { if (XdrvMailbox.data_len) { if ((abs_value > 4500) && (abs_value < 6500)) { // Between 45.00 and 65.00 Hz XdrvMailbox.payload = abs_value; } } } - else if (CMND_ENERGYCONFIG == Energy.command_code) { + else if (CMND_ENERGYCONFIG == Energy->command_code) { AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Config index %d, payload %d, value %d, data '%s'"), XdrvMailbox.index, XdrvMailbox.payload, value, XdrvMailbox.data ? XdrvMailbox.data : "null" ); - // EnergyConfig1 to 3 = Set Energy.current[channel] in A like 0.417 for 417mA + // EnergyConfig1 to 3 = Set Energy->current[channel] in A like 0.417 for 417mA if ((XdrvMailbox.index > 0) && (XdrvMailbox.index < 4)) { //Bl6523.current[XdrvMailbox.index -1] = value; } - // EnergyConfig4 to 6 = Set Energy.active_power[channel] in W like 100 for 100W + // EnergyConfig4 to 6 = Set Energy->active_power[channel] in W like 100 for 100W if ((XdrvMailbox.index > 3) && (XdrvMailbox.index < 7)) { //Bl6523.power[XdrvMailbox.index -4] = value; } diff --git a/tasmota/tasmota_xnrg_energy/xnrg_23_ade7880.ino b/tasmota/tasmota_xnrg_energy/xnrg_23_ade7880.ino index a11ab38f0..d4799833f 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_23_ade7880.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_23_ade7880.ino @@ -501,16 +501,16 @@ void Ade7880Cycle(void) { } Ade7880.neutral_current = (float)Ade7880ReadVerify(ADE7880_NIRMS) / 100000; // 0x43C6 for (uint32_t phase = 0; phase < 3; phase++) { - Energy.data_valid[phase] = 0; - Energy.voltage[phase] = (float)Ade7880ReadVerify(ADE7880_AVRMS + (phase * 2)) / 10000; // 0x43C1 - 0x0024CC94 = 241.1668 V - Energy.current[phase] = (float)Ade7880ReadVerify(ADE7880_AIRMS + (phase * 2)) / 100000; // 0x43C0 - 0x00002D6D = 0.11629 A - Energy.active_power[phase] = (float)Ade7880ReadVerify(ADE7880_AWATT + phase) / 100; // 0xE513 - 0xFFFFF524 = -27.79 W - Energy.apparent_power[phase] = (float)Ade7880ReadVerify(ADE7880_AVA + phase) / 100; // 0xE519 - 0xFFFFF50D - Energy.frequency[phase] = 256000.0f / Ade7880ReadVerify(ADE7880_APERIOD + phase); // 0xE905 - Page 34 and based on ADE7880_FREQ_INIT + Energy->data_valid[phase] = 0; + Energy->voltage[phase] = (float)Ade7880ReadVerify(ADE7880_AVRMS + (phase * 2)) / 10000; // 0x43C1 - 0x0024CC94 = 241.1668 V + Energy->current[phase] = (float)Ade7880ReadVerify(ADE7880_AIRMS + (phase * 2)) / 100000; // 0x43C0 - 0x00002D6D = 0.11629 A + Energy->active_power[phase] = (float)Ade7880ReadVerify(ADE7880_AWATT + phase) / 100; // 0xE513 - 0xFFFFF524 = -27.79 W + Energy->apparent_power[phase] = (float)Ade7880ReadVerify(ADE7880_AVA + phase) / 100; // 0xE519 - 0xFFFFF50D + Energy->frequency[phase] = 256000.0f / Ade7880ReadVerify(ADE7880_APERIOD + phase); // 0xE905 - Page 34 and based on ADE7880_FREQ_INIT // Suppose constant load during period of 100/120 periods as set by ADE7880_LINECYC disregards load change inbetween. // ADE7880_AWATT = 6713 = 67,13 W // 67,13 * 1000 / 36 = 1864 deca micro Wh (0.01864Wh) -// Energy.kWhtoday_delta[phase] += Energy.active_power[phase] * 1000 / 36; +// Energy->kWhtoday_delta[phase] += Energy->active_power[phase] * 1000 / 36; // By measuring load 1024000 times/second load change in 100/120 periods can be accounted for. // ADE7880_AWATT = 6713 = 67,13 W @@ -525,7 +525,7 @@ void Ade7880Cycle(void) { // 273 * 402653184 / 16384 = 6709248 = 67092,48W / 3600 = 1863 deca micro Wh // 273 * 24576 = 6709248 / 3600 = 1863 deca micro Wh int32_t active_energy = Ade7880ReadVerify(ADE7880_AWATTHR + phase); // 0xE400 - 0xFFFFFF8F = -0.112 - Energy.kWhtoday_delta[phase] += active_energy * 24576 / 3600; // Using int32_t allows loads up to 87kW (0x7FFFFFFF / 24576) + Energy->kWhtoday_delta[phase] += active_energy * 24576 / 3600; // Using int32_t allows loads up to 87kW (0x7FFFFFFF / 24576) } EnergyUpdateToday(); @@ -662,10 +662,10 @@ void Ade7880DrvInit(void) { Ade7880Defaults(); if (Ade7880SetCalibrate()) { - Energy.phase_count = 3; // Three phases + Energy->phase_count = 3; // Three phases // Settings->flag5.energy_phase = 1; // SetOption129 - (Energy) Show phase information -// Energy.use_overtemp = true; // Use global temperature for overtemp detection - Energy.local_energy_active_export = true; +// Energy->use_overtemp = true; // Use global temperature for overtemp detection + Energy->local_energy_active_export = true; TasmotaGlobal.energy_driver = XNRG_23; } } @@ -675,7 +675,7 @@ void Ade7880DrvInit(void) { bool Ade7880Command(void) { bool serviced = false; - if (CMND_ENERGYCONFIG == Energy.command_code) { + if (CMND_ENERGYCONFIG == Energy->command_code) { // Non-pesistent settings // EnergyConfig {"rms":{"current_a":3166385,"current_b":3125691,"current_c":3131983,"current_s":1756557,"voltage_a":-767262,"voltage_b":-763439,"voltage_c":-749854},"angles":{"angle0":180,"angle1":176,"angle2":176},"powers":{"totactive": {"a":-1345820,"b":-1347328,"c":-1351979}},"freq":0} // EnergyConfig {"rms":{"voltage_c":-549854}} diff --git a/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino b/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino index a98f94fe2..8dde49a5a 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino @@ -216,7 +216,7 @@ void EnergyModbusLoop(void) { * Cl = CRC lsb * Ch = CRC msb */ - Energy.data_valid[NrgMbsParam.phase] = 0; + Energy->data_valid[NrgMbsParam.phase] = 0; float value; switch (NrgMbsReg[NrgMbsParam.state].datatype) { @@ -293,31 +293,31 @@ void EnergyModbusLoop(void) { switch (NrgMbsParam.state) { case NRG_MBS_VOLTAGE: - Energy.voltage[NrgMbsParam.phase] = value; // 230.2 V + Energy->voltage[NrgMbsParam.phase] = value; // 230.2 V break; case NRG_MBS_CURRENT: - Energy.current[NrgMbsParam.phase] = value; // 1.260 A + Energy->current[NrgMbsParam.phase] = value; // 1.260 A break; case NRG_MBS_ACTIVE_POWER: - Energy.active_power[NrgMbsParam.phase] = value; // -196.3 W + Energy->active_power[NrgMbsParam.phase] = value; // -196.3 W break; case NRG_MBS_APPARENT_POWER: - Energy.apparent_power[NrgMbsParam.phase] = value; // 223.4 VA + Energy->apparent_power[NrgMbsParam.phase] = value; // 223.4 VA break; case NRG_MBS_REACTIVE_POWER: - Energy.reactive_power[NrgMbsParam.phase] = value; // 92.2 + Energy->reactive_power[NrgMbsParam.phase] = value; // 92.2 break; case NRG_MBS_POWER_FACTOR: - Energy.power_factor[NrgMbsParam.phase] = value; // -0.91 + Energy->power_factor[NrgMbsParam.phase] = value; // -0.91 break; case NRG_MBS_FREQUENCY: - Energy.frequency[NrgMbsParam.phase] = value; // 50.0 Hz + Energy->frequency[NrgMbsParam.phase] = value; // 50.0 Hz break; case NRG_MBS_TOTAL_ENERGY: - Energy.import_active[NrgMbsParam.phase] = value; // 6.216 kWh => used in EnergyUpdateTotal() + Energy->import_active[NrgMbsParam.phase] = value; // 6.216 kWh => used in EnergyUpdateTotal() break; case NRG_MBS_EXPORT_ACTIVE_ENERGY: - Energy.export_active[NrgMbsParam.phase] = value; // 478.492 kWh + Energy->export_active[NrgMbsParam.phase] = value; // 478.492 kWh break; default: if (NrgMbsUser) { @@ -334,7 +334,7 @@ void EnergyModbusLoop(void) { uint32_t phase = 0; do { NrgMbsParam.phase++; - if (NrgMbsParam.phase >= Energy.phase_count) { + if (NrgMbsParam.phase >= Energy->phase_count) { NrgMbsParam.phase = 0; NrgMbsParam.state++; if (NrgMbsParam.state >= NrgMbsParam.total_regs) { @@ -434,8 +434,8 @@ bool EnergyModbusReadUserRegisters(JsonParserObject user_add_value, uint32_t add if (!phase) { return false; // No register entered so skip } - if (phase > Energy.phase_count) { - Energy.phase_count = phase; + if (phase > Energy->phase_count) { + Energy->phase_count = phase; NrgMbsParam.devices = 1; // Only one device allowed with multiple phases } @@ -514,7 +514,7 @@ bool EnergyModbusReadRegisters(void) { if (!root) { return false; } // Invalid JSON // Init defaults - Energy.phase_count = 1; + Energy->phase_count = 1; NrgMbsParam.serial_bps = ENERGY_MODBUS_SPEED; NrgMbsParam.serial_config = ENERGY_MODBUS_CONFIG; NrgMbsParam.ticker_poll = ENERGY_MODBUS_TICKER_POLL; @@ -603,8 +603,8 @@ bool EnergyModbusReadRegisters(void) { // Get default energy registers char register_name[32]; - Energy.voltage_available = false; // Disable voltage is measured - Energy.current_available = false; // Disable current is measured + Energy->voltage_available = false; // Disable voltage is measured + Energy->current_available = false; // Disable current is measured for (uint32_t names = 0; names < NRG_MBS_MAX_REGS; names++) { val = root[GetTextIndexed(register_name, sizeof(register_name), names, kEnergyModbusValues)]; if (val) { @@ -631,24 +631,24 @@ bool EnergyModbusReadRegisters(void) { NrgMbsReg[names].address[0] = val.getUInt(); phase++; } - if (phase > Energy.phase_count) { - Energy.phase_count = phase; + if (phase > Energy->phase_count) { + Energy->phase_count = phase; NrgMbsParam.devices = 1; // Only one device allowed with multiple phases } switch(names) { case NRG_MBS_VOLTAGE: - Energy.voltage_available = true; // Enable if voltage is measured + Energy->voltage_available = true; // Enable if voltage is measured if (1 == phase) { - Energy.voltage_common = true; // Use common voltage + Energy->voltage_common = true; // Use common voltage } break; case NRG_MBS_CURRENT: - Energy.current_available = true; // Enable if current is measured + Energy->current_available = true; // Enable if current is measured break; case NRG_MBS_FREQUENCY: if (1 == phase) { - Energy.frequency_common = true; // Use common frequency + Energy->frequency_common = true; // Use common frequency } break; case NRG_MBS_TOTAL_ENERGY: @@ -707,9 +707,9 @@ bool EnergyModbusReadRegisters(void) { } if (NrgMbsParam.devices > 1) { // Multiple devices have no common values - Energy.phase_count = NrgMbsParam.devices; - Energy.voltage_common = false; // Use no common voltage - Energy.frequency_common = false; // Use no common frequency + Energy->phase_count = NrgMbsParam.devices; + Energy->voltage_common = false; // Use no common voltage + Energy->frequency_common = false; // Use no common frequency Settings->flag5.energy_phase = 1; // SetOption129 - (Energy) Show phase information } diff --git a/tasmota/tasmota_xnrg_energy/xnrg_30_dummy.ino b/tasmota/tasmota_xnrg_energy/xnrg_30_dummy.ino index 1a661b91a..dd198e8ad 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_30_dummy.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_30_dummy.ino @@ -53,25 +53,25 @@ struct { } NrgDummy; void NrgDummyEverySecond(void) { - if (Energy.power_on) { // Powered on - for (uint32_t channel = 0; channel < Energy.phase_count; channel++) { + if (Energy->power_on) { // Powered on + for (uint32_t channel = 0; channel < Energy->phase_count; channel++) { float power_calibration = (float)EnergyGetCalibration(channel, ENERGY_POWER_CALIBRATION) / 100; float voltage_calibration = (float)EnergyGetCalibration(channel, ENERGY_VOLTAGE_CALIBRATION) / 100; float current_calibration = (float)EnergyGetCalibration(channel, ENERGY_CURRENT_CALIBRATION) / 100000; float frequency_calibration = (float)EnergyGetCalibration(channel, ENERGY_FREQUENCY_CALIBRATION) / 100; - Energy.voltage[channel] = voltage_calibration; // V - Energy.frequency[channel] = frequency_calibration; // Hz + Energy->voltage[channel] = voltage_calibration; // V + Energy->frequency[channel] = frequency_calibration; // Hz if (bitRead(TasmotaGlobal.power, channel)) { // Emulate power read only if device is powered on - Energy.active_power[channel] = (NrgDummy.power[channel]) ? ((float)NrgDummy.power[channel] / 1000) : power_calibration; // W - if (0 == Energy.active_power[channel]) { - Energy.current[channel] = 0; + Energy->active_power[channel] = (NrgDummy.power[channel]) ? ((float)NrgDummy.power[channel] / 1000) : power_calibration; // W + if (0 == Energy->active_power[channel]) { + Energy->current[channel] = 0; } else { - Energy.current[channel] = (NrgDummy.current[channel]) ? ((float)NrgDummy.current[channel] / 1000) : current_calibration; // A - Energy.kWhtoday_delta[channel] += Energy.active_power[channel] * 1000 / 36; + Energy->current[channel] = (NrgDummy.current[channel]) ? ((float)NrgDummy.current[channel] / 1000) : current_calibration; // A + Energy->kWhtoday_delta[channel] += Energy->active_power[channel] * 1000 / 36; } - Energy.data_valid[channel] = 0; + Energy->data_valid[channel] = 0; } } EnergyUpdateToday(); @@ -84,46 +84,46 @@ bool NrgDummyCommand(void) { int32_t value = (int32_t)(CharToFloat(XdrvMailbox.data) * 1000); // 1.234 = 1234, -1.234 = -1234 uint32_t abs_value = abs(value) / 10; // 1.23 = 123, -1.23 = 123 - if ((CMND_POWERCAL == Energy.command_code) || (CMND_VOLTAGECAL == Energy.command_code) || (CMND_CURRENTCAL == Energy.command_code)) { + if ((CMND_POWERCAL == Energy->command_code) || (CMND_VOLTAGECAL == Energy->command_code) || (CMND_CURRENTCAL == Energy->command_code)) { // Service in xdrv_03_energy.ino } - else if (CMND_POWERSET == Energy.command_code) { + else if (CMND_POWERSET == Energy->command_code) { if (XdrvMailbox.data_len) { if ((abs_value >= 100) && (abs_value <= 16000000)) { // Between 1.00 and 160000.00 W XdrvMailbox.payload = abs_value; } } } - else if (CMND_VOLTAGESET == Energy.command_code) { + else if (CMND_VOLTAGESET == Energy->command_code) { if (XdrvMailbox.data_len) { if ((abs_value >= 10000) && (abs_value <= 40000)) { // Between 100.00 and 400.00 V XdrvMailbox.payload = abs_value; } } } - else if (CMND_CURRENTSET == Energy.command_code) { + else if (CMND_CURRENTSET == Energy->command_code) { if (XdrvMailbox.data_len) { if ((abs_value >= 1000) && (abs_value <= 40000000)) { // Between 10.00 mA and 400.00000 A XdrvMailbox.payload = abs_value; } } } - else if (CMND_FREQUENCYSET == Energy.command_code) { + else if (CMND_FREQUENCYSET == Energy->command_code) { if (XdrvMailbox.data_len) { if ((abs_value >= 4500) && (abs_value <= 6500)) { // Between 45.00 and 65.00 Hz XdrvMailbox.payload = abs_value; } } } - else if (CMND_ENERGYCONFIG == Energy.command_code) { + else if (CMND_ENERGYCONFIG == Energy->command_code) { AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Config index %d, payload %d, value %d, data '%s'"), XdrvMailbox.index, XdrvMailbox.payload, value, XdrvMailbox.data ? XdrvMailbox.data : "null" ); - // EnergyConfig1 to 3 = Set Energy.current[channel] in A like 0.417 for 417mA + // EnergyConfig1 to 3 = Set Energy->current[channel] in A like 0.417 for 417mA if ((XdrvMailbox.index > 0) && (XdrvMailbox.index < 4)) { NrgDummy.current[XdrvMailbox.index -1] = value; } - // EnergyConfig4 to 6 = Set Energy.active_power[channel] in W like 100 for 100W + // EnergyConfig4 to 6 = Set Energy->active_power[channel] in W like 100 for 100W if ((XdrvMailbox.index > 3) && (XdrvMailbox.index < 7)) { NrgDummy.power[XdrvMailbox.index -4] = value; } @@ -145,11 +145,11 @@ void NrgDummyDrvInit(void) { Settings->energy_power_calibration2 = NRG_DUMMY_PREF; } - Energy.phase_count = (TasmotaGlobal.devices_present < ENERGY_MAX_PHASES) ? TasmotaGlobal.devices_present : ENERGY_MAX_PHASES; - Energy.voltage_common = NRG_DUMMY_U_COMMON; // Phase voltage = false, Common voltage = true - Energy.frequency_common = NRG_DUMMY_F_COMMON; // Phase frequency = false, Common frequency = true - Energy.type_dc = NRG_DUMMY_DC; // AC = false, DC = true; - Energy.use_overtemp = NRG_DUMMY_OVERTEMP; // Use global temperature for overtemp detection + Energy->phase_count = (TasmotaGlobal.devices_present < ENERGY_MAX_PHASES) ? TasmotaGlobal.devices_present : ENERGY_MAX_PHASES; + Energy->voltage_common = NRG_DUMMY_U_COMMON; // Phase voltage = false, Common voltage = true + Energy->frequency_common = NRG_DUMMY_F_COMMON; // Phase frequency = false, Common frequency = true + Energy->type_dc = NRG_DUMMY_DC; // AC = false, DC = true; + Energy->use_overtemp = NRG_DUMMY_OVERTEMP; // Use global temperature for overtemp detection TasmotaGlobal.energy_driver = XNRG_30; } diff --git a/tasmota/tasmota_xsns_sensor/xsns_62_esp32_mi.ino b/tasmota/tasmota_xsns_sensor/xsns_62_esp32_mi.ino index 9a85c149b..b57503b2c 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_62_esp32_mi.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_62_esp32_mi.ino @@ -1899,11 +1899,11 @@ void MI32createPolyline(char *polyline, uint8_t *history){ #ifdef USE_MI_ESP32_ENERGY void MI32sendEnergyWidget(){ - if (Energy.current_available && Energy.voltage_available) { - WSContentSend_P(HTTP_MI32_POWER_WIDGET,MIBLEsensors.size()+1, Energy.voltage,Energy.current[1]); + if (Energy->current_available && Energy->voltage_available) { + WSContentSend_P(HTTP_MI32_POWER_WIDGET,MIBLEsensors.size()+1, Energy->voltage,Energy->current[1]); char _polyline[176]; MI32createPolyline(_polyline,MI32.energy_history); - WSContentSend_P(PSTR("

" D_POWERUSAGE ": %.1f " D_UNIT_WATT ""),Energy.active_power); + WSContentSend_P(PSTR("

" D_POWERUSAGE ": %.1f " D_UNIT_WATT ""),Energy->active_power); WSContentSend_P(HTTP_MI32_GRAPH,_polyline,185,124,124,_polyline,1); WSContentSend_P(PSTR("

")); } @@ -2243,7 +2243,7 @@ void MI32Show(bool json) #ifdef USE_MI_EXT_GUI Mi32invalidateOldHistory(); #ifdef USE_MI_ESP32_ENERGY - MI32addHistory(MI32.energy_history,Energy.active_power[0],100); //TODO: which value?? + MI32addHistory(MI32.energy_history,Energy->active_power[0],100); //TODO: which value?? #endif //USE_MI_ESP32_ENERGY #endif //USE_MI_EXT_GUI vTaskResume(MI32.ScanTask); diff --git a/tasmota/tasmota_xsns_sensor/xsns_75_prometheus.ino b/tasmota/tasmota_xsns_sensor/xsns_75_prometheus.ino index 56b507c61..f09257919 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_75_prometheus.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_75_prometheus.ino @@ -260,19 +260,19 @@ void HandleMetrics(void) { #ifdef USE_ENERGY_SENSOR WritePromMetricDec(PSTR("energy_voltage_volts"), kPromMetricGauge, - Energy.voltage[0], Settings->flag2.voltage_resolution, nullptr); + Energy->voltage[0], Settings->flag2.voltage_resolution, nullptr); WritePromMetricDec(PSTR("energy_current_amperes"), kPromMetricGauge, - Energy.current[0], Settings->flag2.current_resolution, nullptr); + Energy->current[0], Settings->flag2.current_resolution, nullptr); WritePromMetricDec(PSTR("energy_power_active_watts"), kPromMetricGauge, - Energy.active_power[0], Settings->flag2.wattage_resolution, nullptr); + Energy->active_power[0], Settings->flag2.wattage_resolution, nullptr); WritePromMetricDec(PSTR("energy_power_kilowatts_daily"), kPromMetricCounter, - Energy.daily_sum, Settings->flag2.energy_resolution, nullptr); + Energy->daily_sum, Settings->flag2.energy_resolution, nullptr); WritePromMetricDec(PSTR("energy_power_kilowatts_total"), kPromMetricCounter, - Energy.total_sum, Settings->flag2.energy_resolution, nullptr); + Energy->total_sum, Settings->flag2.energy_resolution, nullptr); #endif for (uint32_t device = 0; device < TasmotaGlobal.devices_present; device++) { From 973e4693c275b735bd76c960318c8790246e9f9b Mon Sep 17 00:00:00 2001 From: Barbudor Date: Wed, 25 Jan 2023 08:36:14 +0100 Subject: [PATCH 177/262] possibly fix sleep problem (#17786) --- tasmota/tasmota_xdrv_driver/xdrv_04_light.ino | 2 -- 1 file changed, 2 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_04_light.ino b/tasmota/tasmota_xdrv_driver/xdrv_04_light.ino index a4c305416..bbad6d364 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_04_light.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_04_light.ino @@ -1780,8 +1780,6 @@ void LightAnimate(void) if (TasmotaGlobal.sleep > PWM_MAX_SLEEP) { sleep_previous = TasmotaGlobal.sleep; // save previous value of sleep TasmotaGlobal.sleep = PWM_MAX_SLEEP; // set a maximum value (in milliseconds) to sleep to ensure that animations are smooth - } else { - sleep_previous = -1; // if low enough, don't change it } } else { if (sleep_previous > 0) { From 2529759974a01dabde9319db2749add9bf42ce63 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Wed, 25 Jan 2023 17:05:48 +0100 Subject: [PATCH 178/262] Prep energy for four+ phase support --- .../tasmota_xdrv_driver/xdrv_03_energy.ino | 50 +- .../xdrv_03_esp32_energy.ino | 1658 +++++++++++++++++ .../tasmota_xnrg_energy/xnrg_01_hlw8012.ino | 16 +- .../tasmota_xnrg_energy/xnrg_02_cse7766.ino | 20 +- .../tasmota_xnrg_energy/xnrg_04_mcp39f501.ino | 16 +- .../tasmota_xnrg_energy/xnrg_07_ade7953.ino | 20 +- .../tasmota_xnrg_energy/xnrg_14_bl09xx.ino | 24 +- .../tasmota_xnrg_energy/xnrg_19_cse7761.ino | 26 +- .../tasmota_xnrg_energy/xnrg_22_bl6523.ino | 21 +- tasmota/tasmota_xnrg_energy/xnrg_30_dummy.ino | 26 +- 10 files changed, 1769 insertions(+), 108 deletions(-) create mode 100644 tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino diff --git a/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino b/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino index 14d7279d8..94c5feb89 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino @@ -17,10 +17,10 @@ along with this program. If not, see . */ -//#ifdef ESP8266 +#ifdef ESP8266 #ifdef USE_ENERGY_SENSOR /*********************************************************************************************\ - * Energy + * Energy for ESP8266 \*********************************************************************************************/ #define XDRV_03 3 @@ -31,6 +31,8 @@ #define ENERGY_NONE 0 #define ENERGY_WATCHDOG 4 // Allow up to 4 seconds before deciding no valid data present + +#undef ENERGY_MAX_PHASES #define ENERGY_MAX_PHASES 3 #include @@ -860,7 +862,7 @@ void CmndTariff(void) { GetStateText(Settings->flag3.energy_weekend)); // CMND_TARIFF } -uint32_t EnergyGetCalibration(uint32_t chan, uint32_t cal_type) { +uint32_t EnergyGetCalibration(uint32_t cal_type, uint32_t chan = 0) { uint32_t channel = ((1 == chan) && (2 == Energy->phase_count)) ? 1 : 0; if (channel) { switch (cal_type) { @@ -878,32 +880,36 @@ uint32_t EnergyGetCalibration(uint32_t chan, uint32_t cal_type) { return Settings->energy_frequency_calibration; } +void EnergySetCalibration(uint32_t cal_type, uint32_t value, uint32_t chan = 0) { + uint32_t channel = ((1 == chan) && (2 == Energy->phase_count)) ? 1 : 0; + if (channel) { + switch (cal_type) { + case ENERGY_POWER_CALIBRATION: Settings->energy_power_calibration2 = value; return; + case ENERGY_VOLTAGE_CALIBRATION: Settings->energy_voltage_calibration2 = value; return; + case ENERGY_CURRENT_CALIBRATION: Settings->energy_current_calibration2 = value; return; + case ENERGY_FREQUENCY_CALIBRATION: Settings->energy_frequency_calibration = value; return; + } + } else { + switch (cal_type) { + case ENERGY_POWER_CALIBRATION: Settings->energy_power_calibration = value; return; + case ENERGY_VOLTAGE_CALIBRATION: Settings->energy_voltage_calibration = value; return; + case ENERGY_CURRENT_CALIBRATION: Settings->energy_current_calibration = value; return; + case ENERGY_FREQUENCY_CALIBRATION: Settings->energy_frequency_calibration = value; return; + } + } +} + void EnergyCommandCalSetResponse(uint32_t cal_type) { if (XdrvMailbox.payload > 99) { - uint32_t channel = ((2 == XdrvMailbox.index) && (2 == Energy->phase_count)) ? 1 : 0; - if (channel) { - switch (cal_type) { - case ENERGY_POWER_CALIBRATION: Settings->energy_power_calibration2 = XdrvMailbox.payload; break; - case ENERGY_VOLTAGE_CALIBRATION: Settings->energy_voltage_calibration2 = XdrvMailbox.payload; break; - case ENERGY_CURRENT_CALIBRATION: Settings->energy_current_calibration2 = XdrvMailbox.payload; break; - case ENERGY_FREQUENCY_CALIBRATION: Settings->energy_frequency_calibration = XdrvMailbox.payload; break; - } - } else { - switch (cal_type) { - case ENERGY_POWER_CALIBRATION: Settings->energy_power_calibration = XdrvMailbox.payload; break; - case ENERGY_VOLTAGE_CALIBRATION: Settings->energy_voltage_calibration = XdrvMailbox.payload; break; - case ENERGY_CURRENT_CALIBRATION: Settings->energy_current_calibration = XdrvMailbox.payload; break; - case ENERGY_FREQUENCY_CALIBRATION: Settings->energy_frequency_calibration = XdrvMailbox.payload; break; - } - } + EnergySetCalibration(cal_type, XdrvMailbox.payload, XdrvMailbox.index -1); } if (ENERGY_FREQUENCY_CALIBRATION == cal_type) { ResponseAppend_P(PSTR("%d}"), Settings->energy_frequency_calibration); } else { if (2 == Energy->phase_count) { - ResponseAppend_P(PSTR("[%d,%d]}"), EnergyGetCalibration(0, cal_type), EnergyGetCalibration(1, cal_type)); + ResponseAppend_P(PSTR("[%d,%d]}"), EnergyGetCalibration(cal_type), EnergyGetCalibration(cal_type, 1)); } else { - ResponseAppend_P(PSTR("%d}"), EnergyGetCalibration(0, cal_type)); + ResponseAppend_P(PSTR("%d}"), EnergyGetCalibration(cal_type)); } } } @@ -1494,4 +1500,4 @@ bool Xsns03(uint32_t function) } #endif // USE_ENERGY_SENSOR -//#endif // ESP8266 +#endif // ESP8266 diff --git a/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino b/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino new file mode 100644 index 000000000..2db22d9b1 --- /dev/null +++ b/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino @@ -0,0 +1,1658 @@ +/* + xdrv_03_esp32_energy.ino - Energy sensor support for Tasmota + + Copyright (C) 2021 Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifdef ESP32 +#ifdef USE_ENERGY_SENSOR +/*********************************************************************************************\ + * Energy for ESP32 +\*********************************************************************************************/ + +#define XDRV_03 3 +#define XSNS_03 3 + +#define ENERGY_NONE 0 +#define ENERGY_WATCHDOG 4 // Allow up to 4 seconds before deciding no valid data present + +#undef ENERGY_MAX_PHASES +#define ENERGY_MAX_PHASES 4 + +#define ENERGY_MAX_PHASES_FUTURE 8 + +#include + +#define D_CMND_POWERCAL "PowerCal" +#define D_CMND_VOLTAGECAL "VoltageCal" +#define D_CMND_CURRENTCAL "CurrentCal" +#define D_CMND_FREQUENCYCAL "FrequencyCal" +#define D_CMND_TARIFF "Tariff" +#define D_CMND_MODULEADDRESS "ModuleAddress" + +enum EnergyCalibration { + ENERGY_POWER_CALIBRATION, ENERGY_VOLTAGE_CALIBRATION, ENERGY_CURRENT_CALIBRATION, ENERGY_FREQUENCY_CALIBRATION }; + +enum EnergyCommands { + CMND_POWERCAL, CMND_VOLTAGECAL, CMND_CURRENTCAL, CMND_FREQUENCYCAL, + CMND_POWERSET, CMND_VOLTAGESET, CMND_CURRENTSET, CMND_FREQUENCYSET, CMND_MODULEADDRESS, CMND_ENERGYCONFIG }; + +const char kEnergyCommands[] PROGMEM = "|" // No prefix + D_CMND_POWERCAL "|" D_CMND_VOLTAGECAL "|" D_CMND_CURRENTCAL "|" D_CMND_FREQUENCYCAL "|" + D_CMND_POWERSET "|" D_CMND_VOLTAGESET "|" D_CMND_CURRENTSET "|" D_CMND_FREQUENCYSET "|" D_CMND_MODULEADDRESS "|" D_CMND_ENERGYCONFIG "|" + D_CMND_POWERDELTA "|" D_CMND_POWERLOW "|" D_CMND_POWERHIGH "|" D_CMND_VOLTAGELOW "|" D_CMND_VOLTAGEHIGH "|" D_CMND_CURRENTLOW "|" D_CMND_CURRENTHIGH "|" + D_CMND_MAXENERGY "|" D_CMND_MAXENERGYSTART "|" + D_CMND_MAXPOWER "|" D_CMND_MAXPOWERHOLD "|" D_CMND_MAXPOWERWINDOW "|" + D_CMND_SAFEPOWER "|" D_CMND_SAFEPOWERHOLD "|" D_CMND_SAFEPOWERWINDOW "|" + D_CMND_ENERGYTODAY "|" D_CMND_ENERGYYESTERDAY "|" D_CMND_ENERGYTOTAL "|" D_CMND_ENERGYEXPORTACTIVE "|" D_CMND_ENERGYUSAGE "|" D_CMND_ENERGYEXPORT "|" D_CMND_TARIFF; + +void (* const EnergyCommand[])(void) PROGMEM = { + &CmndPowerCal, &CmndVoltageCal, &CmndCurrentCal, &CmndFrequencyCal, + &CmndPowerSet, &CmndVoltageSet, &CmndCurrentSet, &CmndFrequencySet, &CmndModuleAddress, &CmndEnergyConfig, + &CmndPowerDelta, &CmndPowerLow, &CmndPowerHigh, &CmndVoltageLow, &CmndVoltageHigh, &CmndCurrentLow, &CmndCurrentHigh, + &CmndMaxEnergy, &CmndMaxEnergyStart, + &CmndMaxPower, &CmndMaxPowerHold, &CmndMaxPowerWindow, + &CmndSafePower, &CmndSafePowerHold, &CmndSafePowerWindow, + &CmndEnergyToday, &CmndEnergyYesterday, &CmndEnergyTotal, &CmndEnergyExportActive, &CmndEnergyUsage, &CmndEnergyExport, &CmndTariff}; + +/********************************************************************************************/ + +typedef struct { + float usage_total_kWh[2]; + float return_total_kWh[2]; + float last_return_total_kWh; + float last_usage_total_kWh; +} tEnergyUsage; + +typedef struct { + uint32_t crc32; // To detect file changes + uint16_t version; // To detect driver function changes + uint16_t energy_kWhdoy; + uint32_t energy_kWhtotal_time; + uint32_t spare1; + uint32_t spare2; + uint32_t spare3; + uint32_t spare4; + uint32_t spare5; + + uint32_t power_calibration[ENERGY_MAX_PHASES_FUTURE]; + uint32_t voltage_calibration[ENERGY_MAX_PHASES_FUTURE]; + uint32_t current_calibration[ENERGY_MAX_PHASES_FUTURE]; + uint32_t frequency_calibration[ENERGY_MAX_PHASES_FUTURE]; + + uint16_t tariff[2][2]; + tEnergyUsage energy_usage; + + float energy_today_kWh[ENERGY_MAX_PHASES_FUTURE]; // Energy today in kWh - float allows up to 262143.99 kWh + float energy_yesterday_kWh[ENERGY_MAX_PHASES_FUTURE]; // Energy yesterday in kWh - float allows up to 262143.99 kWh + float energy_total_kWh[ENERGY_MAX_PHASES_FUTURE]; // Total energy in kWh - float allows up to 262143.99 kWh + float energy_export_kWh[ENERGY_MAX_PHASES_FUTURE]; + + uint16_t power_delta[ENERGY_MAX_PHASES_FUTURE]; // PowerDelta + + uint16_t min_power; // PowerLow + uint16_t max_power; // PowerHigh + uint16_t min_voltage; // VoltageLow + uint16_t max_voltage; // VoltageHigh + uint16_t min_current; // CurrentLow + uint16_t max_current; // CurrentHigh + + uint16_t max_power_limit; // MaxPowerLimit + uint16_t max_power_limit_hold; // MaxPowerLimitHold + uint16_t max_power_limit_window; // MaxPowerLimitWindow + uint16_t max_power_safe_limit; // MaxSafePowerLimit + uint16_t max_power_safe_limit_hold; // MaxSafePowerLimitHold + uint16_t max_power_safe_limit_window; // MaxSafePowerLimitWindow + uint16_t max_energy; // MaxEnergy + uint16_t max_energy_start; // MaxEnergyStart +} tEnergySettings; + +typedef struct { + tEnergySettings Settings; + + // Global updated / accessed + float voltage[ENERGY_MAX_PHASES]; // 123.1 V + float current[ENERGY_MAX_PHASES]; // 123.123 A + float active_power[ENERGY_MAX_PHASES]; // 123.1 W + float apparent_power[ENERGY_MAX_PHASES]; // 123.1 VA + float reactive_power[ENERGY_MAX_PHASES]; // 123.1 VAr + float power_factor[ENERGY_MAX_PHASES]; // 0.12 + float frequency[ENERGY_MAX_PHASES]; // 123.1 Hz + float import_active[ENERGY_MAX_PHASES]; // 123.123 kWh + float export_active[ENERGY_MAX_PHASES]; // 123.123 kWh + float start_energy[ENERGY_MAX_PHASES]; // 12345.12345 kWh total previous + float total[ENERGY_MAX_PHASES]; // 12345.12345 kWh total energy + float daily_sum; // 123.123 kWh + float total_sum; // 12345.12345 kWh total energy + float yesterday_sum; // 123.123 kWh + + int32_t kWhtoday_delta[ENERGY_MAX_PHASES]; // 1212312345 Wh 10^-5 (deca micro Watt hours) - Overflows to Energy->kWhtoday (HLW and CSE only) + int32_t kWhtoday[ENERGY_MAX_PHASES]; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = Energy->daily + + // Local only + float daily_kWh[ENERGY_MAX_PHASES]; // 123.123 kWh + float energy_today_offset_kWh[ENERGY_MAX_PHASES]; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = Energy->daily + float period_kWh[ENERGY_MAX_PHASES]; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = Energy->daily + float daily_sum_import_balanced; // 123.123 kWh + float daily_sum_export_balanced; // 123.123 kWh + + uint8_t fifth_second; + uint8_t command_code; + uint8_t data_valid[ENERGY_MAX_PHASES]; + + uint8_t phase_count; // Number of phases active + bool voltage_common; // Use common voltage + bool frequency_common; // Use common frequency + bool use_overtemp; // Use global temperature as overtemp trigger on internal energy monitor hardware + bool kWhtoday_offset_init; + + bool voltage_available; // Enable if voltage is measured + bool current_available; // Enable if current is measured + bool local_energy_active_export; // Enable if support for storing energy_active + + bool type_dc; + bool power_on; + + uint16_t power_history[ENERGY_MAX_PHASES][3]; + uint8_t power_steady_counter; // Allow for power on stabilization + bool min_power_flag; + bool max_power_flag; + bool min_voltage_flag; + bool max_voltage_flag; + bool min_current_flag; + bool max_current_flag; + + uint16_t mplh_counter; + uint16_t mplw_counter; + uint8_t mplr_counter; + uint8_t max_energy_state; +} tEnergy; + +tEnergy *Energy = nullptr; + +Ticker ticker_energy; + +/*********************************************************************************************\ + * RTC Energy memory +\*********************************************************************************************/ + +const uint16_t RTC_ENERGY_MEM_VALID = 0xA55A; + +typedef struct { + uint16_t valid; + tEnergyUsage energy_usage; + float energy_today_kWh[ENERGY_MAX_PHASES_FUTURE]; + float energy_total_kWh[ENERGY_MAX_PHASES_FUTURE]; + float energy_export_kWh[ENERGY_MAX_PHASES_FUTURE]; +} tRtcEnergySettings; +tRtcEnergySettings RtcEnergySettings; +static RTC_NOINIT_ATTR tRtcEnergySettings RtcDataEnergySettings; + +uint32_t energy_rtc_settings_crc = 0; + +uint32_t EnergyGetRtcSettingsCrc(void) { + uint32_t crc = 0; + uint8_t *bytes = (uint8_t*)&RtcEnergySettings; + + for (uint32_t i = 0; i < sizeof(RtcEnergySettings); i++) { + crc += bytes[i]*(i+1); + } + return crc; +} + +void EnergyRtcSettingsSave(void) { + if (EnergyGetRtcSettingsCrc() != energy_rtc_settings_crc) { + + if (RTC_ENERGY_MEM_VALID != RtcEnergySettings.valid) { + memset(&RtcEnergySettings, 0, sizeof(RtcEnergySettings)); + RtcEnergySettings.valid = RTC_ENERGY_MEM_VALID; + RtcEnergySettings.energy_usage = Energy->Settings.energy_usage; + for (uint32_t i = 0; i < ENERGY_MAX_PHASES_FUTURE; i++) { + RtcEnergySettings.energy_today_kWh[i] = Energy->Settings.energy_today_kWh[i]; + RtcEnergySettings.energy_total_kWh[i] = Energy->Settings.energy_total_kWh[i]; + RtcEnergySettings.energy_export_kWh[i] = Energy->Settings.energy_export_kWh[i]; + } + } + +// AddLog(LOG_LEVEL_INFO, PSTR("DBG: energy_today_kWh[0] %3_f/%3_f"), RtcEnergySettings.energy_today_kWh[0], Energy->Settings.energy_today_kWh[0]); + + RtcDataEnergySettings = RtcEnergySettings; + energy_rtc_settings_crc = EnergyGetRtcSettingsCrc(); + } +} + +bool EnergyRtcSettingsLoad(void) { + RtcEnergySettings = RtcDataEnergySettings; + + bool read_valid = (RTC_ENERGY_MEM_VALID == RtcEnergySettings.valid); + if (!read_valid) { + EnergyRtcSettingsSave(); + } + return read_valid; +} + +bool EnergyRtcSettingsValid(void) { + return (RTC_ENERGY_MEM_VALID == RtcEnergySettings.valid); +} + +/*********************************************************************************************\ + * Driver Settings load and save using filesystem +\*********************************************************************************************/ + +const uint32_t XDRV_03_VERSION = 0x0101; // Latest driver version (See settings deltas below) + +void Xdrv03SettingsLoad(void) { + // *** Start init default values in case file is not found *** + memset(&Energy->Settings, 0x00, sizeof(tEnergySettings)); + Energy->Settings.version = XDRV_03_VERSION; + // Init any other parameter in struct + for (uint32_t i = 0; i < ENERGY_MAX_PHASES_FUTURE; i++) { + Energy->Settings.power_calibration[i] = HLW_PREF_PULSE; + Energy->Settings.voltage_calibration[i] = HLW_UREF_PULSE; + Energy->Settings.current_calibration[i] = HLW_IREF_PULSE; +// Energy->Settings.frequency_calibration[i] = 0; + } + Energy->Settings.max_power_limit_hold = MAX_POWER_HOLD; + Energy->Settings.max_power_limit_window = MAX_POWER_WINDOW; +// Energy->Settings.max_power_safe_limit = 0; // MaxSafePowerLimit + Energy->Settings.max_power_safe_limit_hold = SAFE_POWER_HOLD; + Energy->Settings.max_power_safe_limit_window = SAFE_POWER_WINDOW; +/* + RtcEnergySettings.energy_total_kWh[0] = 0; + RtcEnergySettings.energy_total_kWh[1] = 0; + RtcEnergySettings.energy_total_kWh[2] = 0; + memset((char*)&RtcEnergySettings.energy_usage, 0x00, sizeof(RtcEnergySettings.energy_usage)); +*/ + // *** End Init default values *** + +#ifndef USE_UFILESYS + AddLog(LOG_LEVEL_DEBUG, PSTR("CFG: XDRV03 Use defaults as file system not enabled")); +#else + // Try to load file /.drvset003 + char filename[20]; + // Use for drivers: + snprintf_P(filename, sizeof(filename), PSTR(TASM_FILE_DRIVER), XDRV_03); + if (TfsLoadFile(filename, (uint8_t*)&Energy->Settings, sizeof(tEnergySettings))) { + if (Energy->Settings.version != XDRV_03_VERSION) { // Fix version dependent changes + + // *** Start fix possible setting deltas *** + + // *** End setting deltas *** + + // Set current version and save settings + Energy->Settings.version = XDRV_03_VERSION; + Xdrv03SettingsSave(); + } + AddLog(LOG_LEVEL_INFO, PSTR("CFG: XDRV03 loaded from file")); + } else { + // File system not ready: No flash space reserved for file system + AddLog(LOG_LEVEL_DEBUG, PSTR("CFG: XDRV03 Use defaults as file system not ready or file not found")); + } +#endif // USE_UFILESYS +} + +void Xdrv03SettingsSave(void) { +#ifdef USE_UFILESYS + // Called from FUNC_SAVE_SETTINGS every SaveData second and at restart + uint32_t crc32 = GetCfgCrc32((uint8_t*)&Energy->Settings +4, sizeof(tEnergySettings) -4); // Skip crc32 + if (crc32 != Energy->Settings.crc32) { + // Try to save file /.drvset003 + Energy->Settings.crc32 = crc32; + + char filename[20]; + // Use for drivers: + snprintf_P(filename, sizeof(filename), PSTR(TASM_FILE_DRIVER), XDRV_03); + if (TfsSaveFile(filename, (const uint8_t*)&Energy->Settings, sizeof(tEnergySettings))) { + AddLog(LOG_LEVEL_DEBUG, PSTR("CFG: XDRV03 saved to file")); + } else { + // File system not ready: No flash space reserved for file system + AddLog(LOG_LEVEL_DEBUG, PSTR("CFG: XDRV03 ERROR File system not ready or unable to save file")); + } + } +#endif // USE_UFILESYS +} + +/********************************************************************************************/ + +char* EnergyFormat(char* result, float* input, uint32_t resolution, uint32_t single = 0); +char* EnergyFormat(char* result, float* input, uint32_t resolution, uint32_t single) { + // single = 0 - Energy->phase_count - xx or [xx,xx] or [xx,xx,xx] + // single = 1 - Energy->voltage_common or Energy->frequency_common - xx + // single = 2 - Sum of Energy->phase_count if SO129 0 - xx or if SO129 1 - [xx,xx,xx] + // single = 5 - single &0x03 = 1 - xx + // single = 6 - single &0x03 = 2 - [xx,xx] - used by tarriff + // single = 7 - single &0x03 = 3 - [xx,xx,xx] + uint32_t index = (single > 3) ? single &0x03 : (0 == single) ? Energy->phase_count : 1; // 1,2,3 + if (single > 2) { single = 0; } // 0,1,2 + float input_sum = 0.0f; + if (single > 1) { + if (!Settings->flag5.energy_phase) { // SetOption129 - (Energy) Show phase information + for (uint32_t i = 0; i < Energy->phase_count; i++) { + if (!isnan(input[i])) { + input_sum += input[i]; + } + } + input = &input_sum; + } else { + index = Energy->phase_count; + } + } + result[0] = '\0'; + for (uint32_t i = 0; i < index; i++) { + ext_snprintf_P(result, TOPSZ, PSTR("%s%s%*_f%s"), result, (0==i)?(1==index)?"":"[":",", resolution, &input[i], (index-1==i)?(1==index)?"":"]":""); + } + return result; +} + +#ifdef USE_WEBSERVER +char* WebEnergyFormat(char* result, float* input, uint32_t resolution, uint32_t single = 0); +char* WebEnergyFormat(char* result, float* input, uint32_t resolution, uint32_t single) { + // single = 0 - Energy->phase_count - xx / xx / xx or multi column + // single = 1 - Energy->voltage_common or Energy->frequency_common - xx or single column using colspan (if needed) + // single = 2 - Sum of Energy->phase_count if SO129 0 - xx or single column using colspan (if needed) or if SO129 1 - xx / xx / xx or multi column + float input_sum = 0.0f; + if (single > 1) { // Sum and/or Single column + if (!Settings->flag5.energy_phase) { // SetOption129 - (Energy) Show phase information + for (uint32_t i = 0; i < Energy->phase_count; i++) { + if (!isnan(input[i])) { + input_sum += input[i]; + } + } + input = &input_sum; + } else { + single = 0; + } + } +#ifdef USE_ENERGY_COLUMN_GUI + ext_snprintf_P(result, GUISZ, PSTR("")); // Skip first column + if ((Energy->phase_count > 1) && single) { // Need to set colspan so need new columns + //
"), + result, (Energy->phase_count *2) -1, (Settings->flag5.gui_table_align)?PSTR("right"):PSTR("center"), resolution, &input[0]); + } else { + // "), + result, (Settings->flag5.gui_table_align)?PSTR("right"):PSTR("left"), resolution, &input[i]); + } + } + ext_snprintf_P(result, GUISZ, PSTR("%s + +const char HTTP_ENERGY_SNS3[] PROGMEM = + "{s}" D_EXPORT_ACTIVE "{m}%s " D_UNIT_KILOWATTHOUR "{e}"; +#endif // USE_WEBSERVER + +void EnergyShow(bool json) { + if (Energy->voltage_common) { + for (uint32_t i = 0; i < Energy->phase_count; i++) { + Energy->voltage[i] = Energy->voltage[0]; + } + } + + float apparent_power[Energy->phase_count]; + float reactive_power[Energy->phase_count]; + float power_factor[Energy->phase_count]; + if (!Energy->type_dc) { + if (Energy->current_available && Energy->voltage_available) { + for (uint32_t i = 0; i < Energy->phase_count; i++) { + apparent_power[i] = Energy->apparent_power[i]; + if (isnan(apparent_power[i])) { + apparent_power[i] = Energy->voltage[i] * Energy->current[i]; + } + if (apparent_power[i] < Energy->active_power[i]) { // Should be impossible + Energy->active_power[i] = apparent_power[i]; + } + + power_factor[i] = Energy->power_factor[i]; + if (isnan(power_factor[i])) { + power_factor[i] = (Energy->active_power[i] && apparent_power[i]) ? Energy->active_power[i] / apparent_power[i] : 0; + if (power_factor[i] > 1) { + power_factor[i] = 1; + } + } + + reactive_power[i] = Energy->reactive_power[i]; + if (isnan(reactive_power[i])) { + reactive_power[i] = 0; + uint32_t difference = ((uint32_t)(apparent_power[i] * 100) - (uint32_t)(Energy->active_power[i] * 100)) / 10; + if ((Energy->current[i] > 0.005f) && ((difference > 15) || (difference > (uint32_t)(apparent_power[i] * 100 / 1000)))) { + // calculating reactive power only if current is greater than 0.005A and + // difference between active and apparent power is greater than 1.5W or 1% + //reactive_power[i] = (float)(RoundSqrtInt((uint64_t)(apparent_power[i] * apparent_power[i] * 100) - (uint64_t)(Energy->active_power[i] * Energy->active_power[i] * 100))) / 10; + float power_diff = apparent_power[i] * apparent_power[i] - Energy->active_power[i] * Energy->active_power[i]; + if (power_diff < 10737418) // 2^30 / 100 (RoundSqrtInt is limited to 2^30-1) + reactive_power[i] = (float)(RoundSqrtInt((uint32_t)(power_diff * 100.0f))) / 10.0f; + else + reactive_power[i] = (float)(SqrtInt((uint32_t)(power_diff))); + } + } + + } + } + } + + float active_power_sum = 0.0f; + float energy_yesterday_kWh[Energy->phase_count]; + for (uint32_t i = 0; i < Energy->phase_count; i++) { + energy_yesterday_kWh[i] = Energy->Settings.energy_yesterday_kWh[i]; + + active_power_sum += Energy->active_power[i]; + } + + bool energy_tariff = false; + float energy_usage_kWh[2]; + float energy_return_kWh[2]; + if (Energy->Settings.tariff[0][0] != Energy->Settings.tariff[1][0]) { + energy_usage_kWh[0] = RtcEnergySettings.energy_usage.usage_total_kWh[0]; // Tariff1 + energy_usage_kWh[1] = RtcEnergySettings.energy_usage.usage_total_kWh[1]; // Tariff2 + energy_return_kWh[0] = RtcEnergySettings.energy_usage.return_total_kWh[0]; // Tariff1 + energy_return_kWh[1] = RtcEnergySettings.energy_usage.return_total_kWh[1]; // Tariff2 + energy_tariff = true; + } + + char value_chr[GUISZ]; // Used by EnergyFormatIndex + char value2_chr[GUISZ]; + char value3_chr[GUISZ]; + + if (json) { + bool show_energy_period = (0 == TasmotaGlobal.tele_period); + + ResponseAppend_P(PSTR(",\"" D_RSLT_ENERGY "\":{\"" D_JSON_TOTAL_START_TIME "\":\"%s\",\"" D_JSON_TOTAL "\":%s"), + GetDateAndTime(DT_ENERGY).c_str(), + EnergyFormat(value_chr, Energy->total, Settings->flag2.energy_resolution, 2)); + + if (energy_tariff) { + ResponseAppend_P(PSTR(",\"" D_JSON_TOTAL D_CMND_TARIFF "\":%s"), + EnergyFormat(value_chr, energy_usage_kWh, Settings->flag2.energy_resolution, 6)); + } + + ResponseAppend_P(PSTR(",\"" D_JSON_YESTERDAY "\":%s,\"" D_JSON_TODAY "\":%s"), + EnergyFormat(value_chr, energy_yesterday_kWh, Settings->flag2.energy_resolution, 2), + EnergyFormat(value2_chr, Energy->daily_kWh, Settings->flag2.energy_resolution, 2)); + +/* + #if defined(SDM630_IMPORT) || defined(SDM72_IMPEXP) + if (!isnan(Energy->import_active[0])) { + ResponseAppend_P(PSTR(",\"" D_JSON_IMPORT_ACTIVE "\":%s"), + EnergyFormat(value_chr, Energy->import_active, Settings->flag2.energy_resolution)); + if (energy_tariff) { + ResponseAppend_P(PSTR(",\"" D_JSON_IMPORT D_CMND_TARIFF "\":%s"), + EnergyFormat(value_chr, energy_return_kWh, Settings->flag2.energy_resolution, 6)); + } + } +#endif // SDM630_IMPORT || SDM72_IMPEXP +*/ + + if (!isnan(Energy->export_active[0])) { + uint32_t single = (!isnan(Energy->export_active[1]) && !isnan(Energy->export_active[2])) ? 0 : 1; + ResponseAppend_P(PSTR(",\"" D_JSON_TODAY_SUM_IMPORT "\":%s,\"" D_JSON_TODAY_SUM_EXPORT "\":%s,\"" D_JSON_EXPORT_ACTIVE "\":%s"), + EnergyFormat(value_chr, &Energy->daily_sum_import_balanced, Settings->flag2.energy_resolution, 1), + EnergyFormat(value2_chr, &Energy->daily_sum_export_balanced, Settings->flag2.energy_resolution, 1), + EnergyFormat(value3_chr, Energy->export_active, Settings->flag2.energy_resolution, single)); + if (energy_tariff) { + ResponseAppend_P(PSTR(",\"" D_JSON_EXPORT D_CMND_TARIFF "\":%s"), + EnergyFormat(value_chr, energy_return_kWh, Settings->flag2.energy_resolution, 6)); + } + } + + if (show_energy_period) { + float energy_period[Energy->phase_count]; + for (uint32_t i = 0; i < Energy->phase_count; i++) { + energy_period[i] = RtcEnergySettings.energy_today_kWh[i] - Energy->period_kWh[i]; + Energy->period_kWh[i] = RtcEnergySettings.energy_today_kWh[i]; + } + ResponseAppend_P(PSTR(",\"" D_JSON_PERIOD "\":%s"), + EnergyFormat(value_chr, energy_period, Settings->flag2.wattage_resolution)); + } + + ResponseAppend_P(PSTR(",\"" D_JSON_POWERUSAGE "\":%s"), + EnergyFormat(value_chr, Energy->active_power, Settings->flag2.wattage_resolution)); + if (!Energy->type_dc) { + if (Energy->current_available && Energy->voltage_available) { + ResponseAppend_P(PSTR(",\"" D_JSON_APPARENT_POWERUSAGE "\":%s,\"" D_JSON_REACTIVE_POWERUSAGE "\":%s,\"" D_JSON_POWERFACTOR "\":%s"), + EnergyFormat(value_chr, apparent_power, Settings->flag2.wattage_resolution), + EnergyFormat(value2_chr, reactive_power, Settings->flag2.wattage_resolution), + EnergyFormat(value3_chr, power_factor, 2)); + } + if (!isnan(Energy->frequency[0])) { + ResponseAppend_P(PSTR(",\"" D_JSON_FREQUENCY "\":%s"), + EnergyFormat(value_chr, Energy->frequency, Settings->flag2.frequency_resolution, Energy->frequency_common)); + } + } + if (Energy->voltage_available) { + ResponseAppend_P(PSTR(",\"" D_JSON_VOLTAGE "\":%s"), + EnergyFormat(value_chr, Energy->voltage, Settings->flag2.voltage_resolution, Energy->voltage_common)); + } + if (Energy->current_available) { + ResponseAppend_P(PSTR(",\"" D_JSON_CURRENT "\":%s"), + EnergyFormat(value_chr, Energy->current, Settings->flag2.current_resolution)); + } + XnrgCall(FUNC_JSON_APPEND); + ResponseJsonEnd(); + +#ifdef USE_DOMOTICZ + if (show_energy_period) { // Only send if telemetry + char temp_chr[FLOATSZ]; + if (Energy->voltage_available) { + dtostrfd(Energy->voltage[0], Settings->flag2.voltage_resolution, temp_chr); + DomoticzSensor(DZ_VOLTAGE, temp_chr); // Voltage + } + if (Energy->current_available) { + dtostrfd(Energy->current[0], Settings->flag2.current_resolution, temp_chr); + DomoticzSensor(DZ_CURRENT, temp_chr); // Current + } + dtostrfd(Energy->total_sum * 1000, 1, temp_chr); + DomoticzSensorPowerEnergy((int)active_power_sum, temp_chr); // PowerUsage, EnergyToday + + char energy_usage_chr[2][FLOATSZ]; + char energy_return_chr[2][FLOATSZ]; + dtostrfd(RtcEnergySettings.energy_usage.usage_total_kWh[0], 1, energy_usage_chr[0]); // Tariff1 + dtostrfd(RtcEnergySettings.energy_usage.usage_total_kWh[1], 1, energy_usage_chr[1]); // Tariff2 + dtostrfd(RtcEnergySettings.energy_usage.return_total_kWh[0], 1, energy_return_chr[0]); + dtostrfd(RtcEnergySettings.energy_usage.return_total_kWh[1], 1, energy_return_chr[1]); + DomoticzSensorP1SmartMeter(energy_usage_chr[0], energy_usage_chr[1], energy_return_chr[0], energy_return_chr[1], (int)active_power_sum); + + } +#endif // USE_DOMOTICZ +#ifdef USE_KNX + if (show_energy_period) { + if (Energy->voltage_available) { + KnxSensor(KNX_ENERGY_VOLTAGE, Energy->voltage[0]); + } + if (Energy->current_available) { + KnxSensor(KNX_ENERGY_CURRENT, Energy->current[0]); + } + KnxSensor(KNX_ENERGY_POWER, active_power_sum); + if (!Energy->type_dc) { + KnxSensor(KNX_ENERGY_POWERFACTOR, power_factor[0]); + } + KnxSensor(KNX_ENERGY_DAILY, Energy->daily_sum); + KnxSensor(KNX_ENERGY_TOTAL, Energy->total_sum); + KnxSensor(KNX_ENERGY_YESTERDAY, Energy->yesterday_sum); + } +#endif // USE_KNX +#ifdef USE_WEBSERVER + } else { +#ifdef USE_ENERGY_COLUMN_GUI + // Need a new table supporting more columns using empty columns (with   in data rows) as easy column spacing + // {s}
) - bool no_label = Energy.voltage_common || (1 == Energy.phase_count); - for (uint32_t i = 0; i < Energy.phase_count; i++) { + bool no_label = Energy->voltage_common || (1 == Energy->phase_count); + for (uint32_t i = 0; i < Energy->phase_count; i++) { WSContentSend_P(PSTR("%s%s{e}")); // Last column is units ({e} =
1.23  + // 1.23  + // 1.23  + ext_snprintf_P(result, GUISZ, PSTR("%s%*_f 1.23  + // 1.23 1.23  + // 1.23 1.23 1.23  + // 1.23 1.23 1.23 1.23  + for (uint32_t i = 0; i < Energy->phase_count; i++) { + ext_snprintf_P(result, GUISZ, PSTR("%s%*_f "), result); +#else // not USE_ENERGY_COLUMN_GUI + uint32_t index = (single) ? 1 : Energy->phase_count; // 1,2,3 + result[0] = '\0'; + for (uint32_t i = 0; i < index; i++) { + ext_snprintf_P(result, GUISZ, PSTR("%s%s%*_f"), result, (i)?" / ":"", resolution, &input[i]); + } +#endif // USE_ENERGY_COLUMN_GUI + return result; +} +#endif // USE_WEBSERVER + +/********************************************************************************************/ + +bool EnergyTariff1Active() // Off-Peak hours +{ + uint8_t dst = 0; + if (IsDst() && (Energy->Settings.tariff[0][1] != Energy->Settings.tariff[1][1])) { + dst = 1; + } + if (Energy->Settings.tariff[0][dst] != Energy->Settings.tariff[1][dst]) { + if (Settings->flag3.energy_weekend && ((RtcTime.day_of_week == 1) || // CMND_TARIFF + (RtcTime.day_of_week == 7))) { + return true; + } + uint32_t minutes = MinutesPastMidnight(); + if (Energy->Settings.tariff[0][dst] > Energy->Settings.tariff[1][dst]) { + // {"Tariff":{"Off-Peak":{"STD":"22:00","DST":"23:00"},"Standard":{"STD":"06:00","DST":"07:00"},"Weekend":"OFF"}} + return ((minutes >= Energy->Settings.tariff[0][dst]) || (minutes < Energy->Settings.tariff[1][dst])); + } else { + // {"Tariff":{"Off-Peak":{"STD":"00:29","DST":"01:29"},"Standard":{"STD":"07:29","DST":"08:29"},"Weekend":"OFF"}} + return ((minutes >= Energy->Settings.tariff[0][dst]) && (minutes < Energy->Settings.tariff[1][dst])); + } + } else { + return false; + } +} + +void EnergyUpdateToday(void) { + // Energy->kWhtoday_delta[]: int32_t x = 0.0000x kWh change + // Energy->kWhtoday[] : int32_t y = 0.0000y kWh + + Energy->total_sum = 0.0f; + Energy->yesterday_sum = 0.0f; + Energy->daily_sum = 0.0f; + int32_t delta_sum_balanced = 0; + + for (uint32_t i = 0; i < Energy->phase_count; i++) { + if (abs(Energy->kWhtoday_delta[i]) > 1000) { + int32_t delta = Energy->kWhtoday_delta[i] / 1000; + delta_sum_balanced += delta; + Energy->kWhtoday_delta[i] -= (delta * 1000); + Energy->kWhtoday[i] += delta; + if (delta < 0) { // Export energy + RtcEnergySettings.energy_export_kWh[i] += ((float)(delta / 100) *-1) / 1000; + } + } + + RtcEnergySettings.energy_today_kWh[i] = Energy->energy_today_offset_kWh[i] + ((float)(Energy->kWhtoday[i]) / 100000); + Energy->daily_kWh[i] = RtcEnergySettings.energy_today_kWh[i]; + Energy->total[i] = RtcEnergySettings.energy_total_kWh[i] + RtcEnergySettings.energy_today_kWh[i]; + if (Energy->local_energy_active_export) { + Energy->export_active[i] = RtcEnergySettings.energy_export_kWh[i]; + } + + Energy->total_sum += Energy->total[i]; + Energy->yesterday_sum += Energy->Settings.energy_yesterday_kWh[i]; + Energy->daily_sum += Energy->daily_kWh[i]; + } + + if (delta_sum_balanced > 0) { + Energy->daily_sum_import_balanced += (float)delta_sum_balanced / 100000; + } else { + Energy->daily_sum_export_balanced += (float)abs(delta_sum_balanced) / 100000; + } + + if (RtcTime.valid){ // We calc the difference only if we have a valid RTC time. + + float energy_diff = Energy->total_sum - RtcEnergySettings.energy_usage.last_usage_total_kWh; + RtcEnergySettings.energy_usage.last_usage_total_kWh = Energy->total_sum; + + float return_diff = 0; + if (!isnan(Energy->export_active[0])) { +// return_diff = Energy->export_active - RtcEnergySettings.energy_usage.last_return_total_kWh; +// RtcEnergySettings.energy_usage.last_return_total_kWh = Energy->export_active; + + float export_active = 0.0f; + for (uint32_t i = 0; i < Energy->phase_count; i++) { + if (!isnan(Energy->export_active[i])) { + export_active += Energy->export_active[i]; + } + } + return_diff = export_active - RtcEnergySettings.energy_usage.last_return_total_kWh; + RtcEnergySettings.energy_usage.last_return_total_kWh = export_active; + } + + uint32_t index = (EnergyTariff1Active()) ? 0 : 1; // Tarrif1 = Off-Peak + RtcEnergySettings.energy_usage.usage_total_kWh[index] += energy_diff; + RtcEnergySettings.energy_usage.return_total_kWh[index] += return_diff; + } +} + +void EnergyUpdateTotal(void) { + // Provide total import active energy as float Energy->import_active[phase] in kWh: 98Wh = 0.098kWh + + for (uint32_t i = 0; i < Energy->phase_count; i++) { + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("NRG: EnergyTotal[%d] %4_f kWh"), i, &Energy->import_active[i]); + + // Try to fix instable input by verifying allowed bandwidth (#17659) + if ((Energy->start_energy[i] != 0) && + (Settings->param[P_CSE7766_INVALID_POWER] > 0) && + (Settings->param[P_CSE7766_INVALID_POWER] < 128)) { // SetOption39 1..127 kWh + int total = abs((int)Energy->total[i]); // We only use kWh + int import_active = abs((int)Energy->import_active[i]); + if ((import_active < (total - Settings->param[P_CSE7766_INVALID_POWER])) || + (import_active > (total + Settings->param[P_CSE7766_INVALID_POWER]))) { + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("NRG: Outside bandwidth")); + continue; // No valid energy value received + } + } + + if (0 == Energy->start_energy[i] || (Energy->import_active[i] < Energy->start_energy[i])) { + Energy->start_energy[i] = Energy->import_active[i]; // Init after restart and handle roll-over if any + } + else if (Energy->import_active[i] != Energy->start_energy[i]) { + Energy->kWhtoday[i] = (int32_t)((Energy->import_active[i] - Energy->start_energy[i]) * 100000); + } + + if ((Energy->total[i] < (Energy->import_active[i] - 0.01f)) && // We subtract a little offset of 10Wh to avoid continuous updates + Settings->flag3.hardware_energy_total) { // SetOption72 - Enable hardware energy total counter as reference (#6561) + // The following calculation allows total usage (Energy->import_active[i]) up to +/-2147483.647 kWh + RtcEnergySettings.energy_total_kWh[i] = Energy->import_active[i] - (Energy->energy_today_offset_kWh[i] + ((float)(Energy->kWhtoday[i]) / 100000)); + Energy->Settings.energy_total_kWh[i] = RtcEnergySettings.energy_total_kWh[i]; + Energy->total[i] = Energy->import_active[i]; + Energy->Settings.energy_kWhtotal_time = (!Energy->energy_today_offset_kWh[i]) ? LocalTime() : Midnight(); + // AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Energy Total updated with hardware value")); + } + } + + EnergyUpdateToday(); +} + +/*********************************************************************************************/ + +void Energy200ms(void) +{ + Energy->power_on = (TasmotaGlobal.power != 0) | Settings->flag.no_power_on_check; // SetOption21 - Show voltage even if powered off + + Energy->fifth_second++; + if (5 == Energy->fifth_second) { + Energy->fifth_second = 0; + + XnrgCall(FUNC_ENERGY_EVERY_SECOND); + + if (RtcTime.valid) { + + if (!Energy->kWhtoday_offset_init && (RtcTime.day_of_year == Energy->Settings.energy_kWhdoy)) { + Energy->kWhtoday_offset_init = true; + for (uint32_t i = 0; i < 3; i++) { + Energy->energy_today_offset_kWh[i] = Energy->Settings.energy_today_kWh[i]; +// RtcEnergySettings.energy_today_kWh[i] = 0; + } + } + + if ((LocalTime() == Midnight()) || (RtcTime.day_of_year > Energy->Settings.energy_kWhdoy)) { + Energy->kWhtoday_offset_init = true; + Energy->Settings.energy_kWhdoy = RtcTime.day_of_year; + + for (uint32_t i = 0; i < 3; i++) { + Energy->Settings.energy_yesterday_kWh[i] = RtcEnergySettings.energy_today_kWh[i]; + + RtcEnergySettings.energy_total_kWh[i] += RtcEnergySettings.energy_today_kWh[i]; + Energy->Settings.energy_total_kWh[i] = RtcEnergySettings.energy_total_kWh[i]; + Energy->Settings.energy_export_kWh[i] = RtcEnergySettings.energy_export_kWh[i]; + + Energy->period_kWh[i] -= RtcEnergySettings.energy_today_kWh[i]; // this becomes a large unsigned, effectively a negative for EnergyShow calculation + Energy->kWhtoday[i] = 0; + Energy->energy_today_offset_kWh[i] = 0; + RtcEnergySettings.energy_today_kWh[i] = 0; + Energy->Settings.energy_today_kWh[i] = 0; + + Energy->start_energy[i] = 0; +// Energy->kWhtoday_delta = 0; // dont zero this, we need to carry the remainder over to tomorrow + Energy->daily_sum_import_balanced = 0.0; + Energy->daily_sum_export_balanced = 0.0; + } + EnergyUpdateToday(); + Energy->max_energy_state = 3; + } + if ((RtcTime.hour == Energy->Settings.max_energy_start) && (3 == Energy->max_energy_state )) { + Energy->max_energy_state = 0; + } + + } + } + + XnrgCall(FUNC_EVERY_200_MSECOND); +} + +void EnergySaveState(void) +{ + Energy->Settings.energy_kWhdoy = (RtcTime.valid) ? RtcTime.day_of_year : 0; + + for (uint32_t i = 0; i < 3; i++) { + Energy->Settings.energy_today_kWh[i] = RtcEnergySettings.energy_today_kWh[i]; + Energy->Settings.energy_total_kWh[i] = RtcEnergySettings.energy_total_kWh[i]; + Energy->Settings.energy_export_kWh[i] = RtcEnergySettings.energy_export_kWh[i]; + } + + Energy->Settings.energy_usage = RtcEnergySettings.energy_usage; +} + +bool EnergyMargin(bool type, uint16_t margin, uint16_t value, bool &flag, bool &save_flag) +{ + bool change; + + if (!margin) return false; + change = save_flag; + if (type) { + flag = (value > margin); + } else { + flag = (value < margin); + } + save_flag = flag; + return (change != save_flag); +} + +void EnergyMarginCheck(void) { + if (!Energy->phase_count || (TasmotaGlobal.uptime < 8)) { return; } + if (Energy->power_steady_counter) { + Energy->power_steady_counter--; + return; + } + + bool jsonflg = false; + Response_P(PSTR("{\"" D_RSLT_MARGINS "\":{")); + + int16_t power_diff[ENERGY_MAX_PHASES] = { 0 }; + for (uint32_t phase = 0; phase < Energy->phase_count; phase++) { + uint16_t active_power = (uint16_t)(Energy->active_power[phase]); + +// AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: APower %d, HPower0 %d, HPower1 %d, HPower2 %d"), active_power, Energy->power_history[phase][0], Energy->power_history[phase][1], Energy->power_history[phase][2]); + + if (Energy->Settings.power_delta[phase]) { + power_diff[phase] = active_power - Energy->power_history[phase][0]; + uint16_t delta = abs(power_diff[phase]); + bool threshold_met = false; + if (delta > 0) { + if (Energy->Settings.power_delta[phase] < 101) { // 1..100 = Percentage + uint16_t min_power = (Energy->power_history[phase][0] > active_power) ? active_power : Energy->power_history[phase][0]; + if (0 == min_power) { min_power++; } // Fix divide by 0 exception (#6741) + delta = (delta * 100) / min_power; + if (delta >= Energy->Settings.power_delta[phase]) { + threshold_met = true; + } + } else { // 101..32000 = Absolute + if (delta >= (Energy->Settings.power_delta[phase] -100)) { + threshold_met = true; + } + } + } + if (threshold_met) { + Energy->power_history[phase][1] = active_power; // We only want one report so reset history + Energy->power_history[phase][2] = active_power; + jsonflg = true; + } else { + power_diff[phase] = 0; + } + } + Energy->power_history[phase][0] = Energy->power_history[phase][1]; // Shift in history every second allowing power changes to settle for up to three seconds + Energy->power_history[phase][1] = Energy->power_history[phase][2]; + Energy->power_history[phase][2] = active_power; + } + if (jsonflg) { + float power_diff_f[Energy->phase_count]; + for (uint32_t phase = 0; phase < Energy->phase_count; phase++) { + power_diff_f[phase] = power_diff[phase]; + } + char value_chr[TOPSZ]; + ResponseAppend_P(PSTR("\"" D_CMND_POWERDELTA "\":%s"), EnergyFormat(value_chr, power_diff_f, 0)); + } + + uint16_t energy_power_u = (uint16_t)(Energy->active_power[0]); + + if (Energy->power_on && (Energy->Settings.min_power || + Energy->Settings.max_power || + Energy->Settings.min_voltage || + Energy->Settings.max_voltage || + Energy->Settings.min_current || + Energy->Settings.max_current)) { + uint16_t energy_voltage_u = (uint16_t)(Energy->voltage[0]); + uint16_t energy_current_u = (uint16_t)(Energy->current[0] * 1000); + + DEBUG_DRIVER_LOG(PSTR("NRG: W %d, U %d, I %d"), energy_power_u, energy_voltage_u, energy_current_u); + + bool flag; + if (EnergyMargin(false, Energy->Settings.min_power, energy_power_u, flag, Energy->min_power_flag)) { + ResponseAppend_P(PSTR("%s\"" D_CMND_POWERLOW "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag)); + jsonflg = true; + } + if (EnergyMargin(true, Energy->Settings.max_power, energy_power_u, flag, Energy->max_power_flag)) { + ResponseAppend_P(PSTR("%s\"" D_CMND_POWERHIGH "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag)); + jsonflg = true; + } + if (EnergyMargin(false, Energy->Settings.min_voltage, energy_voltage_u, flag, Energy->min_voltage_flag)) { + ResponseAppend_P(PSTR("%s\"" D_CMND_VOLTAGELOW "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag)); + jsonflg = true; + } + if (EnergyMargin(true, Energy->Settings.max_voltage, energy_voltage_u, flag, Energy->max_voltage_flag)) { + ResponseAppend_P(PSTR("%s\"" D_CMND_VOLTAGEHIGH "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag)); + jsonflg = true; + } + if (EnergyMargin(false, Energy->Settings.min_current, energy_current_u, flag, Energy->min_current_flag)) { + ResponseAppend_P(PSTR("%s\"" D_CMND_CURRENTLOW "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag)); + jsonflg = true; + } + if (EnergyMargin(true, Energy->Settings.max_current, energy_current_u, flag, Energy->max_current_flag)) { + ResponseAppend_P(PSTR("%s\"" D_CMND_CURRENTHIGH "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag)); + jsonflg = true; + } + } + if (jsonflg) { + ResponseJsonEndEnd(); + MqttPublishPrefixTopicRulesProcess_P(TELE, PSTR(D_RSLT_MARGINS), MQTT_TELE_RETAIN); + EnergyMqttShow(); + } + + // Max Power + if (Energy->Settings.max_power_limit) { + if (Energy->active_power[0] > Energy->Settings.max_power_limit) { + if (!Energy->mplh_counter) { + Energy->mplh_counter = Energy->Settings.max_power_limit_hold; + } else { + Energy->mplh_counter--; + if (!Energy->mplh_counter) { + ResponseTime_P(PSTR(",\"" D_JSON_MAXPOWERREACHED "\":%d}"), energy_power_u); + MqttPublishPrefixTopicRulesProcess_P(STAT, S_RSLT_WARNING); + EnergyMqttShow(); + SetAllPower(POWER_ALL_OFF, SRC_MAXPOWER); + if (!Energy->mplr_counter) { + Energy->mplr_counter = Settings->param[P_MAX_POWER_RETRY] +1; // SetOption33 - Max Power Retry count + } + Energy->mplw_counter = Energy->Settings.max_power_limit_window; + } + } + } + else if (TasmotaGlobal.power && (energy_power_u <= Energy->Settings.max_power_limit)) { + Energy->mplh_counter = 0; + Energy->mplr_counter = 0; + Energy->mplw_counter = 0; + } + if (!TasmotaGlobal.power) { + if (Energy->mplw_counter) { + Energy->mplw_counter--; + } else { + if (Energy->mplr_counter) { + Energy->mplr_counter--; + if (Energy->mplr_counter) { + ResponseTime_P(PSTR(",\"" D_JSON_POWERMONITOR "\":\"%s\"}"), GetStateText(1)); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_STAT, PSTR(D_JSON_POWERMONITOR)); + RestorePower(true, SRC_MAXPOWER); + } else { + ResponseTime_P(PSTR(",\"" D_JSON_MAXPOWERREACHEDRETRY "\":\"%s\"}"), GetStateText(0)); + MqttPublishPrefixTopicRulesProcess_P(STAT, S_RSLT_WARNING); + EnergyMqttShow(); + SetAllPower(POWER_ALL_OFF, SRC_MAXPOWER); + } + } + } + } + } + + // Max Energy + if (Energy->Settings.max_energy) { + uint16_t energy_daily_u = (uint16_t)(Energy->daily_sum * 1000); + if (!Energy->max_energy_state && (RtcTime.hour == Energy->Settings.max_energy_start)) { + Energy->max_energy_state = 1; + ResponseTime_P(PSTR(",\"" D_JSON_ENERGYMONITOR "\":\"%s\"}"), GetStateText(1)); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_STAT, PSTR(D_JSON_ENERGYMONITOR)); + RestorePower(true, SRC_MAXENERGY); + } + else if ((1 == Energy->max_energy_state ) && (energy_daily_u >= Energy->Settings.max_energy)) { + Energy->max_energy_state = 2; + ResponseTime_P(PSTR(",\"" D_JSON_MAXENERGYREACHED "\":%3_f}"), &Energy->daily_sum); + MqttPublishPrefixTopicRulesProcess_P(STAT, S_RSLT_WARNING); + EnergyMqttShow(); + SetAllPower(POWER_ALL_OFF, SRC_MAXENERGY); + } + } +} + +void EnergyMqttShow(void) +{ +// {"Time":"2017-12-16T11:48:55","ENERGY":{"Total":0.212,"Yesterday":0.000,"Today":0.014,"Period":2.0,"Power":22.0,"Factor":1.00,"Voltage":213.6,"Current":0.100}} + int tele_period_save = TasmotaGlobal.tele_period; + TasmotaGlobal.tele_period = 2; + ResponseClear(); + ResponseAppendTime(); + EnergyShow(true); + TasmotaGlobal.tele_period = tele_period_save; + ResponseJsonEnd(); + MqttPublishTeleSensor(); +} + +void EnergyEverySecond(void) +{ + // Overtemp check + if (Energy->use_overtemp && TasmotaGlobal.global_update) { + if (TasmotaGlobal.power && !isnan(TasmotaGlobal.temperature_celsius) && (TasmotaGlobal.temperature_celsius > (float)Settings->param[P_OVER_TEMP])) { // SetOption42 Device overtemp, turn off relays + + AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Temperature %1_f"), &TasmotaGlobal.temperature_celsius); + + SetAllPower(POWER_ALL_OFF, SRC_OVERTEMP); + } + } + + // Invalid data reset + if (TasmotaGlobal.uptime > ENERGY_WATCHDOG) { + uint32_t data_valid = Energy->phase_count; + for (uint32_t i = 0; i < Energy->phase_count; i++) { + if (Energy->data_valid[i] <= ENERGY_WATCHDOG) { + Energy->data_valid[i]++; + if (Energy->data_valid[i] > ENERGY_WATCHDOG) { + // Reset energy registers + Energy->voltage[i] = 0; + Energy->current[i] = 0; + Energy->active_power[i] = 0; + if (!isnan(Energy->apparent_power[i])) { Energy->apparent_power[i] = 0; } + if (!isnan(Energy->reactive_power[i])) { Energy->reactive_power[i] = 0; } + if (!isnan(Energy->frequency[i])) { Energy->frequency[i] = 0; } + if (!isnan(Energy->power_factor[i])) { Energy->power_factor[i] = 0; } + if (!isnan(Energy->export_active[i])) { Energy->export_active[i] = 0; } + + data_valid--; + } + } + } + if (!data_valid) { + //Energy->start_energy = 0; + AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Energy reset by invalid data")); + + XnrgCall(FUNC_ENERGY_RESET); + } + } + + EnergyMarginCheck(); +} + +/*********************************************************************************************\ + * Commands +\*********************************************************************************************/ + +void ResponseCmndEnergyTotalYesterdayToday(void) { + char value_chr[TOPSZ]; // Used by EnergyFormatIndex + char value2_chr[TOPSZ]; + char value3_chr[TOPSZ]; + + float energy_yesterday_kWh[3]; + for (uint32_t i = 0; i < Energy->phase_count; i++) { + energy_yesterday_kWh[i] = Energy->Settings.energy_yesterday_kWh[i]; + Energy->total[i] = RtcEnergySettings.energy_total_kWh[i] + Energy->energy_today_offset_kWh[i] + ((float)(Energy->kWhtoday[i]) / 100000); + if (Energy->local_energy_active_export) { + Energy->export_active[i] = RtcEnergySettings.energy_export_kWh[i]; + } + } + + Response_P(PSTR("{\"%s\":{\"" D_JSON_TOTAL "\":%s,\"" D_JSON_YESTERDAY "\":%s,\"" D_JSON_TODAY "\":%s"), + XdrvMailbox.command, + EnergyFormat(value_chr, Energy->total, Settings->flag2.energy_resolution), + EnergyFormat(value2_chr, energy_yesterday_kWh, Settings->flag2.energy_resolution), + EnergyFormat(value3_chr, Energy->daily_kWh, Settings->flag2.energy_resolution)); + if (Energy->local_energy_active_export) { + ResponseAppend_P(PSTR(",\"" D_JSON_EXPORT_ACTIVE "\":%s"), + EnergyFormat(value_chr, Energy->export_active, Settings->flag2.energy_resolution)); + } + ResponseJsonEndEnd(); +} + +void CmndEnergyTotal(void) { + uint32_t values[2] = { 0 }; + uint32_t params = ParseParameters(2, values); + + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= Energy->phase_count) && (params > 0)) { + uint32_t phase = XdrvMailbox.index -1; + // Reset Energy Total + RtcEnergySettings.energy_total_kWh[phase] = (float)(values[0]) / 1000; + Energy->Settings.energy_total_kWh[phase] = RtcEnergySettings.energy_total_kWh[phase]; + if (params > 1) { + Energy->Settings.energy_kWhtotal_time = values[1]; + } else { + Energy->Settings.energy_kWhtotal_time = (!Energy->energy_today_offset_kWh[phase]) ? LocalTime() : Midnight(); + } + RtcEnergySettings.energy_usage.last_usage_total_kWh = Energy->total[phase]; + } + ResponseCmndEnergyTotalYesterdayToday(); +} + +void CmndEnergyYesterday(void) { + uint32_t values[2] = { 0 }; + uint32_t params = ParseParameters(2, values); + + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= Energy->phase_count) && (params > 0)) { + uint32_t phase = XdrvMailbox.index -1; + // Reset Energy Yesterday + Energy->Settings.energy_yesterday_kWh[phase] = (float)(values[0]) / 1000; + if (params > 1) { + Energy->Settings.energy_kWhtotal_time = values[1]; + } + } + ResponseCmndEnergyTotalYesterdayToday(); +} + +void CmndEnergyToday(void) { + uint32_t values[2] = { 0 }; + uint32_t params = ParseParameters(2, values); + + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= Energy->phase_count) && (params > 0)) { + uint32_t phase = XdrvMailbox.index -1; + // Reset Energy Today + Energy->energy_today_offset_kWh[phase] = (float)(values[0]) / 1000; + Energy->kWhtoday[phase] = 0; + Energy->kWhtoday_delta[phase] = 0; + Energy->start_energy[phase] = 0; + Energy->period_kWh[phase] = Energy->energy_today_offset_kWh[phase]; + Energy->Settings.energy_today_kWh[phase] = Energy->energy_today_offset_kWh[phase]; + RtcEnergySettings.energy_today_kWh[phase] = Energy->energy_today_offset_kWh[phase]; + Energy->daily_kWh[phase] = Energy->energy_today_offset_kWh[phase]; + if (params > 1) { + Energy->Settings.energy_kWhtotal_time = values[1]; + } + else if (!RtcEnergySettings.energy_total_kWh[phase] && !Energy->energy_today_offset_kWh[phase]) { + Energy->Settings.energy_kWhtotal_time = LocalTime(); + } + } + ResponseCmndEnergyTotalYesterdayToday(); +} + +void CmndEnergyExportActive(void) { + if (Energy->local_energy_active_export) { + // EnergyExportActive1 24 + // EnergyExportActive1 24,1650111291 + uint32_t values[2] = { 0 }; + uint32_t params = ParseParameters(2, values); + + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= Energy->phase_count) && (params > 0)) { + uint32_t phase = XdrvMailbox.index -1; + // Reset Energy Export Active + RtcEnergySettings.energy_export_kWh[phase] = (float)(values[0]) / 1000; + Energy->Settings.energy_export_kWh[phase] = RtcEnergySettings.energy_export_kWh[phase]; + if (params > 1) { + Energy->Settings.energy_kWhtotal_time = values[1]; + } + } + ResponseCmndEnergyTotalYesterdayToday(); + } +} + +void ResponseCmndEnergyUsageExport(void) { + Response_P(PSTR("{\"%s\":{\"" D_JSON_USAGE "\":[%*_f,%*_f],\"" D_JSON_EXPORT "\":[%*_f,%*_f]}}"), + XdrvMailbox.command, + Settings->flag2.energy_resolution, &Energy->Settings.energy_usage.usage_total_kWh[0], + Settings->flag2.energy_resolution, &Energy->Settings.energy_usage.usage_total_kWh[1], + Settings->flag2.energy_resolution, &Energy->Settings.energy_usage.return_total_kWh[0], + Settings->flag2.energy_resolution, &Energy->Settings.energy_usage.return_total_kWh[1]); +} + +void CmndEnergyUsage(void) { + uint32_t values[2] = { 0 }; + uint32_t params = ParseParameters(2, values); + if (params > 0) { + // Reset energy_usage.usage totals + RtcEnergySettings.energy_usage.usage_total_kWh[0] = (float)(values[0]) / 1000; + if (params > 1) { + RtcEnergySettings.energy_usage.usage_total_kWh[1] = (float)(values[1]) / 1000; + } + Energy->Settings.energy_usage.usage_total_kWh[0] = RtcEnergySettings.energy_usage.usage_total_kWh[0]; + Energy->Settings.energy_usage.usage_total_kWh[1] = RtcEnergySettings.energy_usage.usage_total_kWh[1]; + } + ResponseCmndEnergyUsageExport(); +} + +void CmndEnergyExport(void) { + uint32_t values[2] = { 0 }; + uint32_t params = ParseParameters(2, values); + if (params > 0) { + // Reset energy_usage.return totals + RtcEnergySettings.energy_usage.return_total_kWh[0] = (float)(values[0]) / 1000; + if (params > 1) { + RtcEnergySettings.energy_usage.return_total_kWh[1] = (float)(values[1]) / 1000; + } + Energy->Settings.energy_usage.return_total_kWh[0] = RtcEnergySettings.energy_usage.return_total_kWh[0]; + Energy->Settings.energy_usage.return_total_kWh[1] = RtcEnergySettings.energy_usage.return_total_kWh[1]; + } + ResponseCmndEnergyUsageExport(); +} + +void CmndTariff(void) { + // Tariff1 22:00,23:00 - Tariff1 start hour for Standard Time and Daylight Savings Time + // Tariff2 6:00,7:00 - Tariff2 start hour for Standard Time and Daylight Savings Time + // Tariffx 1320, 1380 = minutes and also 22:00, 23:00 + // Tariffx 22, 23 = hours and also 22:00, 23:00 + // Tariff9 0/1 + + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 2)) { + uint32_t tariff = XdrvMailbox.index -1; + uint32_t time_type = 0; + char *p; + char *str = strtok_r(XdrvMailbox.data, ", ", &p); // 23:15, 22:30 + while ((str != nullptr) && (time_type < 2)) { + char *q; + uint32_t value = strtol(str, &q, 10); // 23 or 22 + Energy->Settings.tariff[tariff][time_type] = value; + if (value < 24) { // Below 24 is hours + Energy->Settings.tariff[tariff][time_type] *= 60; // Multiply hours by 60 minutes + char *minute = strtok_r(nullptr, ":", &q); + if (minute) { + value = strtol(minute, nullptr, 10); // 15 or 30 + if (value > 59) { + value = 59; + } + Energy->Settings.tariff[tariff][time_type] += value; + } + } + if (Energy->Settings.tariff[tariff][time_type] > 1439) { + Energy->Settings.tariff[tariff][time_type] = 1439; // Max is 23:59 + } + str = strtok_r(nullptr, ", ", &p); + time_type++; + } + } + else if (XdrvMailbox.index == 9) { + Settings->flag3.energy_weekend = XdrvMailbox.payload & 1; // CMND_TARIFF + } + Response_P(PSTR("{\"%s\":{\"Off-Peak\":{\"STD\":\"%s\",\"DST\":\"%s\"},\"Standard\":{\"STD\":\"%s\",\"DST\":\"%s\"},\"Weekend\":\"%s\"}}"), + XdrvMailbox.command, + GetMinuteTime(Energy->Settings.tariff[0][0]).c_str(),GetMinuteTime(Energy->Settings.tariff[0][1]).c_str(), + GetMinuteTime(Energy->Settings.tariff[1][0]).c_str(),GetMinuteTime(Energy->Settings.tariff[1][1]).c_str(), + GetStateText(Settings->flag3.energy_weekend)); // CMND_TARIFF +} + +uint32_t EnergyGetCalibration(uint32_t cal_type, uint32_t chan = 0) { +// uint32_t channel = ((1 == chan) && (2 == Energy->phase_count)) ? 1 : 0; + uint32_t channel = chan; + switch (cal_type) { + case ENERGY_POWER_CALIBRATION: return Energy->Settings.power_calibration[channel]; + case ENERGY_VOLTAGE_CALIBRATION: return Energy->Settings.voltage_calibration[channel]; + case ENERGY_CURRENT_CALIBRATION: return Energy->Settings.current_calibration[channel]; + case ENERGY_FREQUENCY_CALIBRATION: return Energy->Settings.frequency_calibration[channel]; + } + return 0; +} + +void EnergySetCalibration(uint32_t cal_type, uint32_t value, uint32_t chan = 0) { +// uint32_t channel = ((1 == chan) && (2 == Energy->phase_count)) ? 1 : 0; + uint32_t channel = chan; + switch (cal_type) { + case ENERGY_POWER_CALIBRATION: Energy->Settings.power_calibration[channel] = value; return; + case ENERGY_VOLTAGE_CALIBRATION: Energy->Settings.voltage_calibration[channel] = value; return; + case ENERGY_CURRENT_CALIBRATION: Energy->Settings.current_calibration[channel] = value; return; + case ENERGY_FREQUENCY_CALIBRATION: Energy->Settings.frequency_calibration[channel] = value; return; + } +} + +void EnergyCommandCalSetResponse(uint32_t cal_type) { + if (XdrvMailbox.payload > 99) { + EnergySetCalibration(cal_type, XdrvMailbox.payload, XdrvMailbox.index -1); + } + if (2 == Energy->phase_count) { + ResponseAppend_P(PSTR("[%d,%d]}"), EnergyGetCalibration(cal_type), EnergyGetCalibration(cal_type, 1)); + } else { + ResponseAppend_P(PSTR("%d}"), EnergyGetCalibration(cal_type)); + } +} + +void EnergyCommandCalResponse(uint32_t cal_type) { + Response_P(PSTR("{\"%s\":"), XdrvMailbox.command); + EnergyCommandCalSetResponse(cal_type); +} + +void EnergyCommandSetCalResponse(uint32_t cal_type) { + Response_P(PSTR("{\"%sCal\":"), XdrvMailbox.command); + EnergyCommandCalSetResponse(cal_type); +} + +void CmndPowerCal(void) { + Energy->command_code = CMND_POWERCAL; + if (XnrgCall(FUNC_COMMAND)) { // microseconds + EnergyCommandCalResponse(ENERGY_POWER_CALIBRATION); + } +} + +void CmndVoltageCal(void) { + Energy->command_code = CMND_VOLTAGECAL; + if (XnrgCall(FUNC_COMMAND)) { // microseconds + EnergyCommandCalResponse(ENERGY_VOLTAGE_CALIBRATION); + } +} + +void CmndCurrentCal(void) { + Energy->command_code = CMND_CURRENTCAL; + if (XnrgCall(FUNC_COMMAND)) { // microseconds + EnergyCommandCalResponse(ENERGY_CURRENT_CALIBRATION); + } +} + +void CmndFrequencyCal(void) { + Energy->command_code = CMND_FREQUENCYCAL; + if (XnrgCall(FUNC_COMMAND)) { // microseconds + EnergyCommandCalResponse(ENERGY_FREQUENCY_CALIBRATION); + } +} + +void CmndPowerSet(void) { + Energy->command_code = CMND_POWERSET; + if (XnrgCall(FUNC_COMMAND)) { // Watt + EnergyCommandSetCalResponse(ENERGY_POWER_CALIBRATION); + } +} + +void CmndVoltageSet(void) { + Energy->command_code = CMND_VOLTAGESET; + if (XnrgCall(FUNC_COMMAND)) { // Volt + EnergyCommandSetCalResponse(ENERGY_VOLTAGE_CALIBRATION); + } +} + +void CmndCurrentSet(void) { + Energy->command_code = CMND_CURRENTSET; + if (XnrgCall(FUNC_COMMAND)) { // milliAmpere + EnergyCommandSetCalResponse(ENERGY_CURRENT_CALIBRATION); + } +} + +void CmndFrequencySet(void) { + Energy->command_code = CMND_FREQUENCYSET; + if (XnrgCall(FUNC_COMMAND)) { // Hz + EnergyCommandSetCalResponse(ENERGY_FREQUENCY_CALIBRATION); + } +} + +void CmndModuleAddress(void) { + if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 4) && (1 == Energy->phase_count)) { + Energy->command_code = CMND_MODULEADDRESS; + if (XnrgCall(FUNC_COMMAND)) { // Module address + ResponseCmndDone(); + } + } +} + +void CmndEnergyConfig(void) { + Energy->command_code = CMND_ENERGYCONFIG; + ResponseClear(); + if (XnrgCall(FUNC_COMMAND)) { + if (!ResponseLength()) { + ResponseCmndDone(); + } + } +} + +void CmndPowerDelta(void) { + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= ENERGY_MAX_PHASES)) { + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 32000)) { + Energy->Settings.power_delta[XdrvMailbox.index -1] = XdrvMailbox.payload; + } + ResponseCmndIdxNumber(Energy->Settings.power_delta[XdrvMailbox.index -1]); + } +} + +void CmndPowerLow(void) { + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 6000)) { + Energy->Settings.min_power = XdrvMailbox.payload; + } + ResponseCmndNumber(Energy->Settings.min_power); +} + +void CmndPowerHigh(void) { + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 6000)) { + Energy->Settings.max_power = XdrvMailbox.payload; + } + ResponseCmndNumber(Energy->Settings.max_power); +} + +void CmndVoltageLow(void) { + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 500)) { + Energy->Settings.min_voltage = XdrvMailbox.payload; + } + ResponseCmndNumber(Energy->Settings.min_voltage); +} + +void CmndVoltageHigh(void) { + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 500)) { + Energy->Settings.max_voltage = XdrvMailbox.payload; + } + ResponseCmndNumber(Energy->Settings.max_voltage); +} + +void CmndCurrentLow(void) { + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 25000)) { + Energy->Settings.min_current = XdrvMailbox.payload; + } + ResponseCmndNumber(Energy->Settings.min_current); +} + +void CmndCurrentHigh(void) { + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 25000)) { + Energy->Settings.max_current = XdrvMailbox.payload; + } + ResponseCmndNumber(Energy->Settings.max_current); +} + +void CmndMaxPower(void) { + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 6000)) { + Energy->Settings.max_power_limit = XdrvMailbox.payload; + } + ResponseCmndNumber(Energy->Settings.max_power_limit); +} + +void CmndMaxPowerHold(void) { + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 6000)) { + Energy->Settings.max_power_limit_hold = (1 == XdrvMailbox.payload) ? MAX_POWER_HOLD : XdrvMailbox.payload; + } + ResponseCmndNumber(Energy->Settings.max_power_limit_hold); +} + +void CmndMaxPowerWindow(void) { + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 6000)) { + Energy->Settings.max_power_limit_window = (1 == XdrvMailbox.payload) ? MAX_POWER_WINDOW : XdrvMailbox.payload; + } + ResponseCmndNumber(Energy->Settings.max_power_limit_window); +} + +void CmndSafePower(void) { + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 6000)) { + Energy->Settings.max_power_safe_limit = XdrvMailbox.payload; + } + ResponseCmndNumber(Energy->Settings.max_power_safe_limit); +} + +void CmndSafePowerHold(void) { + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 6000)) { + Energy->Settings.max_power_safe_limit_hold = (1 == XdrvMailbox.payload) ? SAFE_POWER_HOLD : XdrvMailbox.payload; + } + ResponseCmndNumber(Energy->Settings.max_power_safe_limit_hold); +} + +void CmndSafePowerWindow(void) { + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 1440)) { + Energy->Settings.max_power_safe_limit_window = (1 == XdrvMailbox.payload) ? SAFE_POWER_WINDOW : XdrvMailbox.payload; + } + ResponseCmndNumber(Energy->Settings.max_power_safe_limit_window); +} + +void CmndMaxEnergy(void) { + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 6000)) { + Energy->Settings.max_energy = XdrvMailbox.payload; + Energy->max_energy_state = 3; + } + ResponseCmndNumber(Energy->Settings.max_energy); +} + +void CmndMaxEnergyStart(void) { + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 24)) { + Energy->Settings.max_energy_start = XdrvMailbox.payload; + } + ResponseCmndNumber(Energy->Settings.max_energy_start); +} + +void EnergyDrvInit(void) { + Energy = (tEnergy*)calloc(sizeof(tEnergy), 1); // Need calloc to reset registers to 0/false + if (!Energy) { return; } + + Xdrv03SettingsLoad(); + EnergyRtcSettingsLoad(); + +// Energy->voltage_common = false; +// Energy->frequency_common = false; +// Energy->use_overtemp = false; + for (uint32_t phase = 0; phase < ENERGY_MAX_PHASES; phase++) { + Energy->apparent_power[phase] = NAN; + Energy->reactive_power[phase] = NAN; + Energy->power_factor[phase] = NAN; + Energy->frequency[phase] = NAN; + Energy->export_active[phase] = NAN; + } + Energy->phase_count = 1; // Number of phases active + Energy->voltage_available = true; // Enable if voltage is measured + Energy->current_available = true; // Enable if current is measured + Energy->power_on = true; + + TasmotaGlobal.energy_driver = ENERGY_NONE; + XnrgCall(FUNC_PRE_INIT); // Find first energy driver + if (TasmotaGlobal.energy_driver) { + AddLog(LOG_LEVEL_INFO, PSTR("NRG: Init driver %d"), TasmotaGlobal.energy_driver); + } +} + +void EnergySnsInit(void) +{ + XnrgCall(FUNC_INIT); + + if (TasmotaGlobal.energy_driver) { +/* + AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Rtc valid %d, kWhtoday_ph Rtc %3_f/%3_f/%3_f, Set %3_f/%3_f/%3_f"), + EnergyRtcSettingsValid(), + &RtcEnergySettings.energy_today_kWh[0],&RtcEnergySettings.energy_today_kWh[1],&RtcEnergySettings.energy_today_kWh[2], + &Energy->Settings.energy_today_kWh[0],&Energy->Settings.energy_today_kWh[1],&Energy->Settings.energy_today_kWh[2] + ); +*/ + for (uint32_t i = 0; i < 3; i++) { +// Energy->energy_today_offset_kWh[i] = 0; // Reset by EnergyDrvInit() + // 20220805 - Change from https://github.com/arendst/Tasmota/issues/16118 + if (EnergyRtcSettingsValid()) { + Energy->energy_today_offset_kWh[i] = RtcEnergySettings.energy_today_kWh[i]; + RtcEnergySettings.energy_today_kWh[i] = 0; + Energy->kWhtoday_offset_init = true; + } +// Energy->kWhtoday_ph[i] = 0; // Reset by EnergyDrvInit() +// Energy->kWhtoday_delta[i] = 0; // Reset by EnergyDrvInit() + Energy->period_kWh[i] = Energy->energy_today_offset_kWh[i]; + if (Energy->local_energy_active_export) { + Energy->export_active[i] = 0; // Was set to NAN by EnergyDrvInit() + } + } + EnergyUpdateToday(); + ticker_energy.attach_ms(200, Energy200ms); + } +} + +#ifdef USE_WEBSERVER +const char HTTP_ENERGY_SNS1[] PROGMEM = + "{s}" D_POWERUSAGE_APPARENT "{m}%s " D_UNIT_VA "{e}" + "{s}" D_POWERUSAGE_REACTIVE "{m}%s " D_UNIT_VAR "{e}" + "{s}" D_POWER_FACTOR "{m}%s{e}"; + +const char HTTP_ENERGY_SNS2[] PROGMEM = + "{s}" D_ENERGY_TODAY "{m}%s " D_UNIT_KILOWATTHOUR "{e}" + "{s}" D_ENERGY_YESTERDAY "{m}%s " D_UNIT_KILOWATTHOUR "{e}" + "{s}" D_ENERGY_TOTAL "{m}%s " D_UNIT_KILOWATTHOUR "{e}"; // {s} =
, {m} = , {e} =
Head1{e} + // {s}Head1Head2{e} + // {s}Head1Head2Head3{e} + // {s}Head1Head2Head3Head4{e} + WSContentSend_P(PSTR("

{t}{s}")); // First column is empty ({t} = , {s} = "), (no_label)?"":"L", (no_label)?"":itoa(i +1, value_chr, 10)); + } + WSContentSend_P(PSTR(") +#endif // USE_ENERGY_COLUMN_GUI + if (Energy->voltage_available) { + WSContentSend_PD(HTTP_SNS_VOLTAGE, WebEnergyFormat(value_chr, Energy->voltage, Settings->flag2.voltage_resolution, Energy->voltage_common)); + } + if (!Energy->type_dc) { + if (!isnan(Energy->frequency[0])) { + WSContentSend_PD(PSTR("{s}" D_FREQUENCY "{m}%s " D_UNIT_HERTZ "{e}"), + WebEnergyFormat(value_chr, Energy->frequency, Settings->flag2.frequency_resolution, Energy->frequency_common)); + } + } + if (Energy->current_available) { + WSContentSend_PD(HTTP_SNS_CURRENT, WebEnergyFormat(value_chr, Energy->current, Settings->flag2.current_resolution)); + } + WSContentSend_PD(HTTP_SNS_POWER, WebEnergyFormat(value_chr, Energy->active_power, Settings->flag2.wattage_resolution)); + if (!Energy->type_dc) { + if (Energy->current_available && Energy->voltage_available) { + WSContentSend_PD(HTTP_ENERGY_SNS1, WebEnergyFormat(value_chr, apparent_power, Settings->flag2.wattage_resolution), + WebEnergyFormat(value2_chr, reactive_power, Settings->flag2.wattage_resolution), + WebEnergyFormat(value3_chr, power_factor, 2)); + } + } + WSContentSend_PD(HTTP_ENERGY_SNS2, WebEnergyFormat(value_chr, Energy->daily_kWh, Settings->flag2.energy_resolution, 2), + WebEnergyFormat(value2_chr, energy_yesterday_kWh, Settings->flag2.energy_resolution, 2), + WebEnergyFormat(value3_chr, Energy->total, Settings->flag2.energy_resolution, 2)); + if (!isnan(Energy->export_active[0])) { + uint32_t single = (!isnan(Energy->export_active[1]) && !isnan(Energy->export_active[2])) ? 2 : 1; + WSContentSend_PD(HTTP_ENERGY_SNS3, WebEnergyFormat(value_chr, Energy->export_active, Settings->flag2.energy_resolution, single)); + } +#ifdef USE_ENERGY_COLUMN_GUI + XnrgCall(FUNC_WEB_COL_SENSOR); + WSContentSend_P(PSTR("
) + bool no_label = Energy->voltage_common || (1 == Energy->phase_count); + for (uint32_t i = 0; i < Energy->phase_count; i++) { + WSContentSend_P(PSTR("%s%s{e}")); // Last column is units ({e} =

{t}")); // {t} = - Define for next FUNC_WEB_SENSOR +#endif // USE_ENERGY_COLUMN_GUI + XnrgCall(FUNC_WEB_SENSOR); +#endif // USE_WEBSERVER + } +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xdrv03(uint32_t function) +{ + bool result = false; + + if (FUNC_PRE_INIT == function) { + EnergyDrvInit(); + } + else if (TasmotaGlobal.energy_driver) { + switch (function) { + case FUNC_LOOP: + case FUNC_SLEEP_LOOP: + XnrgCall(FUNC_LOOP); + break; + case FUNC_EVERY_250_MSECOND: + if (TasmotaGlobal.uptime > 4) { + XnrgCall(FUNC_EVERY_250_MSECOND); + } + break; + case FUNC_EVERY_SECOND: + XnrgCall(FUNC_EVERY_SECOND); + break; + case FUNC_SERIAL: + result = XnrgCall(FUNC_SERIAL); + break; + case FUNC_SAVE_SETTINGS: + Xdrv03SettingsSave(); + EnergyRtcSettingsSave(); + break; + case FUNC_SET_POWER: + Energy->power_steady_counter = 2; + break; + case FUNC_COMMAND: + result = DecodeCommand(kEnergyCommands, EnergyCommand); + break; + case FUNC_NETWORK_UP: + XnrgCall(FUNC_NETWORK_UP); + break; + case FUNC_NETWORK_DOWN: + XnrgCall(FUNC_NETWORK_DOWN); + break; + } + } + return result; +} + +bool Xsns03(uint32_t function) +{ + bool result = false; + + if (TasmotaGlobal.energy_driver) { + switch (function) { + case FUNC_EVERY_SECOND: + EnergyEverySecond(); + break; + case FUNC_JSON_APPEND: + EnergyShow(true); + break; +#ifdef USE_WEBSERVER + case FUNC_WEB_SENSOR: + EnergyShow(false); + break; +#endif // USE_WEBSERVER + case FUNC_SAVE_BEFORE_RESTART: + EnergySaveState(); + break; + case FUNC_INIT: + EnergySnsInit(); + break; + } + } + return result; +} + +#endif // USE_ENERGY_SENSOR +#endif // ESP32 diff --git a/tasmota/tasmota_xnrg_energy/xnrg_01_hlw8012.ino b/tasmota/tasmota_xnrg_energy/xnrg_01_hlw8012.ino index 88f6d2d74..c54d43dd6 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_01_hlw8012.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_01_hlw8012.ino @@ -134,7 +134,7 @@ void HlwEvery200ms(void) { Hlw.cf_pulse_counter = 0; if (Hlw.cf_power_pulse_length && Energy->power_on && !Hlw.load_off) { - hlw_w = (Hlw.power_ratio * Settings->energy_power_calibration) / Hlw.cf_power_pulse_length ; // W *10 + hlw_w = (Hlw.power_ratio * EnergyGetCalibration(ENERGY_POWER_CALIBRATION)) / Hlw.cf_power_pulse_length ; // W *10 Energy->active_power[0] = (float)hlw_w / 10; Hlw.power_retry = 1; // Workaround issue #5161 } else { @@ -179,7 +179,7 @@ void HlwEvery200ms(void) { Hlw.cf1_voltage_pulse_length = cf1_pulse_length; if (Hlw.cf1_voltage_pulse_length && Energy->power_on) { // If powered on always provide voltage - hlw_u = (Hlw.voltage_ratio * Settings->energy_voltage_calibration) / Hlw.cf1_voltage_pulse_length ; // V *10 + hlw_u = (Hlw.voltage_ratio * EnergyGetCalibration(ENERGY_VOLTAGE_CALIBRATION)) / Hlw.cf1_voltage_pulse_length ; // V *10 Energy->voltage[0] = (float)hlw_u / 10; } else { Energy->voltage[0] = 0; @@ -189,7 +189,7 @@ void HlwEvery200ms(void) { Hlw.cf1_current_pulse_length = cf1_pulse_length; if (Hlw.cf1_current_pulse_length && Energy->active_power[0]) { // No current if no power being consumed - hlw_i = (Hlw.current_ratio * Settings->energy_current_calibration) / Hlw.cf1_current_pulse_length; // mA + hlw_i = (Hlw.current_ratio * EnergyGetCalibration(ENERGY_CURRENT_CALIBRATION)) / Hlw.cf1_current_pulse_length; // mA Energy->current[0] = (float)hlw_i / 1000; } else { Energy->current[0] = 0; @@ -217,7 +217,7 @@ void HlwEverySecond(void) { hlw_len = 10000 * 100 / Hlw.energy_period_counter; // Add *100 to fix rounding on loads at 3.6kW (#9160) Hlw.energy_period_counter = 0; if (hlw_len) { - Energy->kWhtoday_delta[0] += (((Hlw.power_ratio * Settings->energy_power_calibration) / 36) * 100) / hlw_len; + Energy->kWhtoday_delta[0] += (((Hlw.power_ratio * EnergyGetCalibration(ENERGY_POWER_CALIBRATION)) / 36) * 100) / hlw_len; EnergyUpdateToday(); } } @@ -225,10 +225,10 @@ void HlwEverySecond(void) { } void HlwSnsInit(void) { - if (!Settings->energy_power_calibration || (4975 == Settings->energy_power_calibration)) { - Settings->energy_power_calibration = HLW_PREF_PULSE; - Settings->energy_voltage_calibration = HLW_UREF_PULSE; - Settings->energy_current_calibration = HLW_IREF_PULSE; + if (!EnergyGetCalibration(ENERGY_POWER_CALIBRATION) || (4975 == EnergyGetCalibration(ENERGY_POWER_CALIBRATION))) { + EnergySetCalibration(ENERGY_POWER_CALIBRATION, HLW_PREF_PULSE); + EnergySetCalibration(ENERGY_VOLTAGE_CALIBRATION, HLW_UREF_PULSE); + EnergySetCalibration(ENERGY_CURRENT_CALIBRATION, HLW_IREF_PULSE); } if (Hlw.model_type) { diff --git a/tasmota/tasmota_xnrg_energy/xnrg_02_cse7766.ino b/tasmota/tasmota_xnrg_energy/xnrg_02_cse7766.ino index b4077ed74..023480298 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_02_cse7766.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_02_cse7766.ino @@ -77,26 +77,26 @@ void CseReceived(void) { } // Get chip calibration data (coefficients) and use as initial defaults - if (HLW_UREF_PULSE == Settings->energy_voltage_calibration) { + if (HLW_UREF_PULSE == EnergyGetCalibration(ENERGY_VOLTAGE_CALIBRATION)) { long voltage_coefficient = 191200; // uSec if (CSE_NOT_CALIBRATED != header) { voltage_coefficient = Cse.rx_buffer[2] << 16 | Cse.rx_buffer[3] << 8 | Cse.rx_buffer[4]; } - Settings->energy_voltage_calibration = voltage_coefficient / CSE_UREF; + EnergySetCalibration(ENERGY_VOLTAGE_CALIBRATION, voltage_coefficient / CSE_UREF); } - if (HLW_IREF_PULSE == Settings->energy_current_calibration) { + if (HLW_IREF_PULSE == EnergyGetCalibration(ENERGY_CURRENT_CALIBRATION)) { long current_coefficient = 16140; // uSec if (CSE_NOT_CALIBRATED != header) { current_coefficient = Cse.rx_buffer[8] << 16 | Cse.rx_buffer[9] << 8 | Cse.rx_buffer[10]; } - Settings->energy_current_calibration = current_coefficient; + EnergySetCalibration(ENERGY_CURRENT_CALIBRATION, current_coefficient); } - if (HLW_PREF_PULSE == Settings->energy_power_calibration) { + if (HLW_PREF_PULSE == EnergyGetCalibration(ENERGY_POWER_CALIBRATION)) { long power_coefficient = 5364000; // uSec if (CSE_NOT_CALIBRATED != header) { power_coefficient = Cse.rx_buffer[14] << 16 | Cse.rx_buffer[15] << 8 | Cse.rx_buffer[16]; } - Settings->energy_power_calibration = power_coefficient / CSE_PREF; + EnergySetCalibration(ENERGY_POWER_CALIBRATION, power_coefficient / CSE_PREF); } uint8_t adjustement = Cse.rx_buffer[20]; @@ -107,7 +107,7 @@ void CseReceived(void) { if (Energy->power_on) { // Powered on if (adjustement & 0x40) { // Voltage valid - Energy->voltage[0] = (float)(Settings->energy_voltage_calibration * CSE_UREF) / (float)Cse.voltage_cycle; + Energy->voltage[0] = (float)(EnergyGetCalibration(ENERGY_VOLTAGE_CALIBRATION) * CSE_UREF) / (float)Cse.voltage_cycle; } if (adjustement & 0x10) { // Power valid Cse.power_invalid = 0; @@ -117,7 +117,7 @@ void CseReceived(void) { if (0 == Cse.power_cycle_first) { Cse.power_cycle_first = Cse.power_cycle; } // Skip first incomplete Cse.power_cycle if (Cse.power_cycle_first != Cse.power_cycle) { Cse.power_cycle_first = -1; - Energy->active_power[0] = (float)(Settings->energy_power_calibration * CSE_PREF) / (float)Cse.power_cycle; + Energy->active_power[0] = (float)(EnergyGetCalibration(ENERGY_POWER_CALIBRATION) * CSE_PREF) / (float)Cse.power_cycle; } else { Energy->active_power[0] = 0; } @@ -134,7 +134,7 @@ void CseReceived(void) { if (0 == Energy->active_power[0]) { Energy->current[0] = 0; } else { - Energy->current[0] = (float)Settings->energy_current_calibration / (float)Cse.current_cycle; + Energy->current[0] = (float)EnergyGetCalibration(ENERGY_CURRENT_CALIBRATION) / (float)Cse.current_cycle; } } } else { // Powered off @@ -204,7 +204,7 @@ void CseEverySecond(void) { cf_pulses = Cse.cf_pulses - Cse.cf_pulses_last_time; } if (cf_pulses && Energy->active_power[0]) { - uint32_t delta = (cf_pulses * Settings->energy_power_calibration) / 36; + uint32_t delta = (cf_pulses * EnergyGetCalibration(ENERGY_POWER_CALIBRATION)) / 36; // prevent invalid load delta steps even checksum is valid (issue #5789): // prevent invalid load delta steps even checksum is valid but allow up to 4kW (issue #7155): // if (delta <= (4000 * 1000 / 36)) { // max load for S31/Pow R2: 4.00kW diff --git a/tasmota/tasmota_xnrg_energy/xnrg_04_mcp39f501.ino b/tasmota/tasmota_xnrg_energy/xnrg_04_mcp39f501.ino index 41259ba87..9cd8c4a52 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_04_mcp39f501.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_04_mcp39f501.ino @@ -214,15 +214,15 @@ void McpParseCalibration(void) cal_registers.accumulation_interval = McpExtractInt(mcp_buffer, 52, 2); if (mcp_calibrate & MCP_CALIBRATE_POWER) { - cal_registers.calibration_active_power = Settings->energy_power_calibration; + cal_registers.calibration_active_power = EnergyGetCalibration(ENERGY_POWER_CALIBRATION); if (McpCalibrationCalc(&cal_registers, 16)) { action = true; } } if (mcp_calibrate & MCP_CALIBRATE_VOLTAGE) { - cal_registers.calibration_voltage = Settings->energy_voltage_calibration; + cal_registers.calibration_voltage = EnergyGetCalibration(ENERGY_VOLTAGE_CALIBRATION); if (McpCalibrationCalc(&cal_registers, 0)) { action = true; } } if (mcp_calibrate & MCP_CALIBRATE_CURRENT) { - cal_registers.calibration_current = Settings->energy_current_calibration; + cal_registers.calibration_current = EnergyGetCalibration(ENERGY_CURRENT_CALIBRATION); if (McpCalibrationCalc(&cal_registers, 8)) { action = true; } } mcp_timeout = 0; @@ -230,9 +230,9 @@ void McpParseCalibration(void) mcp_calibrate = 0; - Settings->energy_power_calibration = cal_registers.calibration_active_power; - Settings->energy_voltage_calibration = cal_registers.calibration_voltage; - Settings->energy_current_calibration = cal_registers.calibration_current; + EnergySetCalibration(ENERGY_POWER_CALIBRATION, cal_registers.calibration_active_power); + EnergySetCalibration(ENERGY_VOLTAGE_CALIBRATION, cal_registers.calibration_voltage); + EnergySetCalibration(ENERGY_CURRENT_CALIBRATION, cal_registers.calibration_current); mcp_system_configuration = cal_registers.system_configuration; @@ -386,7 +386,7 @@ void McpParseFrequency(void) uint16_t gain_line_frequency = mcp_buffer[4] * 256 + mcp_buffer[5]; if (mcp_calibrate & MCP_CALIBRATE_FREQUENCY) { - line_frequency_ref = Settings->energy_frequency_calibration; + line_frequency_ref = EnergyGetCalibration(ENERGY_FREQUENCY_CALIBRATION); if ((0xFFFF == mcp_line_frequency) || (0 == gain_line_frequency)) { // Reset values to 50Hz mcp_line_frequency = 50000; @@ -398,7 +398,7 @@ void McpParseFrequency(void) McpSetFrequency(line_frequency_ref, gain_line_frequency); } - Settings->energy_frequency_calibration = line_frequency_ref; + EnergySetCalibration(ENERGY_FREQUENCY_CALIBRATION, line_frequency_ref); mcp_calibrate = 0; } diff --git a/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino b/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino index d5f79e848..4c66d7d15 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino @@ -496,12 +496,12 @@ void Ade7953GetData(void) { for (uint32_t channel = 0; channel < Energy->phase_count; channel++) { Energy->data_valid[channel] = 0; - float power_calibration = (float)EnergyGetCalibration(channel, ENERGY_POWER_CALIBRATION) / 10; + float power_calibration = (float)EnergyGetCalibration(ENERGY_POWER_CALIBRATION, channel) / 10; #ifdef ADE7953_ACCU_ENERGY power_calibration /= ADE7953_POWER_CORRECTION; #endif // ADE7953_ACCU_ENERGY - float voltage_calibration = (float)EnergyGetCalibration(channel, ENERGY_VOLTAGE_CALIBRATION); - float current_calibration = (float)EnergyGetCalibration(channel, ENERGY_CURRENT_CALIBRATION) * 10; + float voltage_calibration = (float)EnergyGetCalibration(ENERGY_VOLTAGE_CALIBRATION, channel); + float current_calibration = (float)EnergyGetCalibration(ENERGY_CURRENT_CALIBRATION, channel) * 10; Energy->frequency[channel] = 223750.0f / ((float)reg[channel][5] + 1); divider = (Ade7953.calib_data[channel][ADE7953_CAL_VGAIN] != ADE7953_GAIN_DEFAULT) ? 10000 : voltage_calibration; @@ -705,14 +705,12 @@ void Ade7953DrvInit(void) { #ifdef USE_ESP32_SPI } #endif // USE_ESP32_SPI - - if (HLW_PREF_PULSE == Settings->energy_power_calibration) { - Settings->energy_power_calibration = ADE7953_PREF; - Settings->energy_voltage_calibration = ADE7953_UREF; - Settings->energy_current_calibration = ADE7953_IREF; - Settings->energy_power_calibration2 = ADE7953_PREF; - Settings->energy_voltage_calibration2 = ADE7953_UREF; - Settings->energy_current_calibration2 = ADE7953_IREF; + if (EnergyGetCalibration(ENERGY_POWER_CALIBRATION) == HLW_PREF_PULSE) { + for (uint32_t i = 0; i < 4; i++) { + EnergySetCalibration(ENERGY_POWER_CALIBRATION, ADE7953_PREF, i); + EnergySetCalibration(ENERGY_VOLTAGE_CALIBRATION, ADE7953_UREF, i); + EnergySetCalibration(ENERGY_CURRENT_CALIBRATION, ADE7953_IREF, i); + } } Ade7953Defaults(); diff --git a/tasmota/tasmota_xnrg_energy/xnrg_14_bl09xx.ino b/tasmota/tasmota_xnrg_energy/xnrg_14_bl09xx.ino index b944078af..a1dc34e32 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_14_bl09xx.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_14_bl09xx.ino @@ -188,13 +188,13 @@ bool Bl09XXDecode42(void) { void Bl09XXUpdateEnergy() { if (Energy->power_on) { // Powered on - Energy->voltage[0] = (float)Bl09XX.voltage / Settings->energy_voltage_calibration; + Energy->voltage[0] = (float)Bl09XX.voltage / EnergyGetCalibration(ENERGY_VOLTAGE_CALIBRATION); #ifdef DEBUG_BL09XX AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("BL9: U %2_f, T %2_f"), &Energy->voltage[0], &Bl09XX.temperature); #endif for (uint32_t chan = 0; chan < Energy->phase_count; chan++) { - uint32_t power_calibration = EnergyGetCalibration(chan, ENERGY_POWER_CALIBRATION); - uint32_t current_calibration = EnergyGetCalibration(chan, ENERGY_CURRENT_CALIBRATION); + uint32_t power_calibration = EnergyGetCalibration(ENERGY_POWER_CALIBRATION, chan); + uint32_t current_calibration = EnergyGetCalibration(ENERGY_CURRENT_CALIBRATION, chan); if (Bl09XX.power[chan] > power_calibration) { // We need at least 1W Energy->active_power[chan] = (float)Bl09XX.power[chan] / power_calibration; Energy->current[chan] = (float)Bl09XX.current[chan] / current_calibration; @@ -287,16 +287,16 @@ void Bl09XXInit(void) { if (Bl09XXSerial->hardwareSerial()) { ClaimSerial(); } - if (HLW_UREF_PULSE == Settings->energy_voltage_calibration) { - Settings->energy_voltage_calibration = bl09xx_uref[Bl09XX.model]; - Settings->energy_current_calibration = bl09xx_iref[Bl09XX.model]; - Settings->energy_power_calibration = bl09xx_pref[Bl09XX.model]; - Settings->energy_voltage_calibration2 = bl09xx_uref[Bl09XX.model]; - Settings->energy_current_calibration2 = bl09xx_iref[Bl09XX.model]; - Settings->energy_power_calibration2 = bl09xx_pref[Bl09XX.model]; + if (HLW_UREF_PULSE == EnergyGetCalibration(ENERGY_VOLTAGE_CALIBRATION)) { + for (uint32_t i = 0; i < 2; i++) { + EnergySetCalibration(ENERGY_POWER_CALIBRATION, bl09xx_pref[Bl09XX.model], i); + EnergySetCalibration(ENERGY_VOLTAGE_CALIBRATION, bl09xx_uref[Bl09XX.model], i); + EnergySetCalibration(ENERGY_CURRENT_CALIBRATION, bl09xx_iref[Bl09XX.model], i); + } } - if ((BL0940_MODEL == Bl09XX.model) && (Settings->energy_current_calibration < (BL0940_IREF / 20))) { - Settings->energy_current_calibration *= 100; + if ((BL0940_MODEL == Bl09XX.model) && (EnergyGetCalibration(ENERGY_CURRENT_CALIBRATION) < (BL0940_IREF / 20))) { + uint32_t current_calibration = EnergyGetCalibration(ENERGY_CURRENT_CALIBRATION) * 100; + EnergySetCalibration(ENERGY_CURRENT_CALIBRATION, current_calibration); } if (BL0942_MODEL != Bl09XX.model) { diff --git a/tasmota/tasmota_xnrg_energy/xnrg_19_cse7761.ino b/tasmota/tasmota_xnrg_energy/xnrg_19_cse7761.ino index a75035b5b..17ad3ad7f 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_19_cse7761.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_19_cse7761.ino @@ -221,17 +221,17 @@ bool Cse7761ChipInit(void) { CSE7761Data.coefficient[PowerPAC] = CSE7761_PREF; // CSE7761Data.coefficient[PowerPBC] = 0xADD7; } - if (HLW_PREF_PULSE == Settings->energy_power_calibration) { - Settings->energy_frequency_calibration = CSE7761_FREF; - Settings->energy_voltage_calibration = Cse7761Ref(RmsUC); - Settings->energy_current_calibration = Cse7761Ref(RmsIAC); - Settings->energy_power_calibration = Cse7761Ref(PowerPAC); - Settings->energy_current_calibration2 = Settings->energy_current_calibration; - Settings->energy_power_calibration2 = Settings->energy_power_calibration; + if (HLW_PREF_PULSE == EnergyGetCalibration(ENERGY_POWER_CALIBRATION)) { + for (uint32_t i = 0; i < 2; i++) { + EnergySetCalibration(ENERGY_POWER_CALIBRATION, Cse7761Ref(PowerPAC), i); + EnergySetCalibration(ENERGY_VOLTAGE_CALIBRATION, Cse7761Ref(RmsUC), i); + EnergySetCalibration(ENERGY_CURRENT_CALIBRATION, Cse7761Ref(RmsIAC), i); + EnergySetCalibration(ENERGY_FREQUENCY_CALIBRATION, CSE7761_FREF, i); + } } // Just to fix intermediate users - if (Settings->energy_frequency_calibration < CSE7761_FREF / 2) { - Settings->energy_frequency_calibration = CSE7761_FREF; + if (EnergyGetCalibration(ENERGY_FREQUENCY_CALIBRATION) < CSE7761_FREF / 2) { + EnergySetCalibration(ENERGY_FREQUENCY_CALIBRATION, CSE7761_FREF); } Cse7761Write(CSE7761_SPECIAL_COMMAND, CSE7761_CMD_ENABLE_WRITE); @@ -461,21 +461,21 @@ void Cse7761GetData(void) { if (Energy->power_on) { // Powered on // Voltage = RmsU * RmsUC * 10 / 0x400000 // Energy->voltage[0] = (float)(((uint64_t)CSE7761Data.voltage_rms * CSE7761Data.coefficient[RmsUC] * 10) >> 22) / 1000; // V - Energy->voltage[0] = ((float)CSE7761Data.voltage_rms / Settings->energy_voltage_calibration); // V + Energy->voltage[0] = ((float)CSE7761Data.voltage_rms / EnergyGetCalibration(ENERGY_VOLTAGE_CALIBRATION)); // V #ifdef CSE7761_FREQUENCY - Energy->frequency[0] = (CSE7761Data.frequency) ? ((float)Settings->energy_frequency_calibration / 8 / CSE7761Data.frequency) : 0; // Hz + Energy->frequency[0] = (CSE7761Data.frequency) ? ((float)EnergyGetCalibration(ENERGY_FREQUENCY_CALIBRATION) / 8 / CSE7761Data.frequency) : 0; // Hz #endif for (uint32_t channel = 0; channel < 2; channel++) { Energy->data_valid[channel] = 0; - uint32_t power_calibration = EnergyGetCalibration(channel, ENERGY_POWER_CALIBRATION); + uint32_t power_calibration = EnergyGetCalibration(ENERGY_POWER_CALIBRATION, channel); // Active power = PowerPA * PowerPAC * 1000 / 0x80000000 // Energy->active_power[channel] = (float)(((uint64_t)CSE7761Data.active_power[channel] * CSE7761Data.coefficient[PowerPAC + channel] * 1000) >> 31) / 1000; // W Energy->active_power[channel] = (float)CSE7761Data.active_power[channel] / power_calibration; // W if (0 == Energy->active_power[channel]) { Energy->current[channel] = 0; } else { - uint32_t current_calibration = EnergyGetCalibration(channel, ENERGY_CURRENT_CALIBRATION); + uint32_t current_calibration = EnergyGetCalibration(ENERGY_CURRENT_CALIBRATION, channel); // Current = RmsIA * RmsIAC / 0x800000 // Energy->current[channel] = (float)(((uint64_t)CSE7761Data.current_rms[channel] * CSE7761Data.coefficient[RmsIAC + channel]) >> 23) / 1000; // A Energy->current[channel] = (float)CSE7761Data.current_rms[channel] / current_calibration; // A diff --git a/tasmota/tasmota_xnrg_energy/xnrg_22_bl6523.ino b/tasmota/tasmota_xnrg_energy/xnrg_22_bl6523.ino index 383b19073..6df796461 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_22_bl6523.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_22_bl6523.ino @@ -162,16 +162,16 @@ RX: 35 0C TX: 00 00 00 F3 (WATT_HR) switch(rx_buffer[1]) { case BL6523_REG_AMPS : - Energy->current[SINGLE_PHASE] = (float)((tx_buffer[2] << 16) | (tx_buffer[1] << 8) | tx_buffer[0]) / Settings->energy_current_calibration; // 1.260 A + Energy->current[SINGLE_PHASE] = (float)((tx_buffer[2] << 16) | (tx_buffer[1] << 8) | tx_buffer[0]) / EnergyGetCalibration(ENERGY_CURRENT_CALIBRATION); // 1.260 A break; case BL6523_REG_VOLTS : - Energy->voltage[SINGLE_PHASE] = (float)((tx_buffer[2] << 16) | (tx_buffer[1] << 8) | tx_buffer[0]) / Settings->energy_voltage_calibration; // 230.2 V + Energy->voltage[SINGLE_PHASE] = (float)((tx_buffer[2] << 16) | (tx_buffer[1] << 8) | tx_buffer[0]) / EnergyGetCalibration(ENERGY_VOLTAGE_CALIBRATION); // 230.2 V break; case BL6523_REG_FREQ : - Energy->frequency[SINGLE_PHASE] = (float)((tx_buffer[2] << 16) | (tx_buffer[1] << 8) | tx_buffer[0]) / Settings->energy_frequency_calibration; // 50.0 Hz + Energy->frequency[SINGLE_PHASE] = (float)((tx_buffer[2] << 16) | (tx_buffer[1] << 8) | tx_buffer[0]) / EnergyGetCalibration(ENERGY_FREQUENCY_CALIBRATION); // 50.0 Hz break; case BL6523_REG_WATTS : - Energy->active_power[SINGLE_PHASE] = (float)((tx_buffer[2] << 16) | (tx_buffer[1] << 8) | tx_buffer[0]) / Settings->energy_power_calibration; // -196.3 W + Energy->active_power[SINGLE_PHASE] = (float)((tx_buffer[2] << 16) | (tx_buffer[1] << 8) | tx_buffer[0]) / EnergyGetCalibration(ENERGY_POWER_CALIBRATION); // -196.3 W break; case BL6523_REG_POWF : /* Power factor =(sign bit)*((PF[22]×2^-1)+(PF[21]×2^-2)+。。。) @@ -188,7 +188,7 @@ switch(rx_buffer[1]) { Energy->power_factor[SINGLE_PHASE] = powf; break; case BL6523_REG_WATTHR : - Energy->import_active[SINGLE_PHASE] = (float)((tx_buffer[2] << 16) | (tx_buffer[1] << 8) | tx_buffer[0]) / ( Settings->energy_power_calibration - BL6523_PWHRREF_D ); // 6.216 kWh => used in EnergyUpdateTotal() + Energy->import_active[SINGLE_PHASE] = (float)((tx_buffer[2] << 16) | (tx_buffer[1] << 8) | tx_buffer[0]) / ( EnergyGetCalibration(ENERGY_POWER_CALIBRATION) - BL6523_PWHRREF_D ); // 6.216 kWh => used in EnergyUpdateTotal() break; default : break; @@ -310,13 +310,12 @@ void Bl6523DrvInit(void) if (PinUsed(GPIO_BL6523_RX) && PinUsed(GPIO_BL6523_TX)) { AddLog(LOG_LEVEL_DEBUG, PSTR("BL6:PreInit Success" )); TasmotaGlobal.energy_driver = XNRG_22; - if (HLW_PREF_PULSE == Settings->energy_power_calibration) { - Settings->energy_frequency_calibration = BL6523_FREF; - Settings->energy_voltage_calibration = BL6523_UREF; - Settings->energy_current_calibration = BL6523_IREF; - Settings->energy_power_calibration = BL6523_PREF; + if (HLW_PREF_PULSE == EnergyGetCalibration(ENERGY_POWER_CALIBRATION)) { + EnergySetCalibration(ENERGY_POWER_CALIBRATION, BL6523_PREF); + EnergySetCalibration(ENERGY_VOLTAGE_CALIBRATION, BL6523_UREF); + EnergySetCalibration(ENERGY_CURRENT_CALIBRATION, BL6523_IREF); + EnergySetCalibration(ENERGY_FREQUENCY_CALIBRATION, BL6523_FREF); } - } else { diff --git a/tasmota/tasmota_xnrg_energy/xnrg_30_dummy.ino b/tasmota/tasmota_xnrg_energy/xnrg_30_dummy.ino index dd198e8ad..49de5be28 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_30_dummy.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_30_dummy.ino @@ -56,10 +56,10 @@ void NrgDummyEverySecond(void) { if (Energy->power_on) { // Powered on for (uint32_t channel = 0; channel < Energy->phase_count; channel++) { - float power_calibration = (float)EnergyGetCalibration(channel, ENERGY_POWER_CALIBRATION) / 100; - float voltage_calibration = (float)EnergyGetCalibration(channel, ENERGY_VOLTAGE_CALIBRATION) / 100; - float current_calibration = (float)EnergyGetCalibration(channel, ENERGY_CURRENT_CALIBRATION) / 100000; - float frequency_calibration = (float)EnergyGetCalibration(channel, ENERGY_FREQUENCY_CALIBRATION) / 100; + float power_calibration = (float)EnergyGetCalibration(ENERGY_POWER_CALIBRATION, channel) / 100; + float voltage_calibration = (float)EnergyGetCalibration(ENERGY_VOLTAGE_CALIBRATION, channel) / 100; + float current_calibration = (float)EnergyGetCalibration(ENERGY_CURRENT_CALIBRATION, channel) / 100000; + float frequency_calibration = (float)EnergyGetCalibration(ENERGY_FREQUENCY_CALIBRATION, channel) / 100; Energy->voltage[channel] = voltage_calibration; // V Energy->frequency[channel] = frequency_calibration; // Hz @@ -135,17 +135,17 @@ bool NrgDummyCommand(void) { void NrgDummyDrvInit(void) { if (TasmotaGlobal.gpio_optiona.dummy_energy && TasmotaGlobal.devices_present) { - if (HLW_PREF_PULSE == Settings->energy_power_calibration) { - Settings->energy_frequency_calibration = NRG_DUMMY_FREF; - Settings->energy_voltage_calibration = NRG_DUMMY_UREF; - Settings->energy_current_calibration = NRG_DUMMY_IREF; - Settings->energy_power_calibration = NRG_DUMMY_PREF; - Settings->energy_voltage_calibration2 = NRG_DUMMY_UREF; - Settings->energy_current_calibration2 = NRG_DUMMY_IREF; - Settings->energy_power_calibration2 = NRG_DUMMY_PREF; + Energy->phase_count = (TasmotaGlobal.devices_present < ENERGY_MAX_PHASES) ? TasmotaGlobal.devices_present : ENERGY_MAX_PHASES; + + if (HLW_PREF_PULSE == EnergyGetCalibration(ENERGY_POWER_CALIBRATION)) { + for (uint32_t i = 0; i < Energy->phase_count; i++) { + EnergySetCalibration(ENERGY_POWER_CALIBRATION, NRG_DUMMY_PREF, i); + EnergySetCalibration(ENERGY_VOLTAGE_CALIBRATION, NRG_DUMMY_UREF, i); + EnergySetCalibration(ENERGY_CURRENT_CALIBRATION, NRG_DUMMY_IREF, i); + EnergySetCalibration(ENERGY_FREQUENCY_CALIBRATION, NRG_DUMMY_FREF, i); + } } - Energy->phase_count = (TasmotaGlobal.devices_present < ENERGY_MAX_PHASES) ? TasmotaGlobal.devices_present : ENERGY_MAX_PHASES; Energy->voltage_common = NRG_DUMMY_U_COMMON; // Phase voltage = false, Common voltage = true Energy->frequency_common = NRG_DUMMY_F_COMMON; // Phase frequency = false, Common frequency = true Energy->type_dc = NRG_DUMMY_DC; // AC = false, DC = true; From 8d782caf15d72806880ee12aaf48c6b5efbf14e5 Mon Sep 17 00:00:00 2001 From: thkaiser Date: Thu, 26 Jan 2023 09:58:59 +0100 Subject: [PATCH 179/262] Support ESPC3 and ESPS3 (#17791) * Support ESPC3 and ESPS3 * remove debug comment Co-authored-by: Jason2866 <24528715+Jason2866@users.noreply.github.com> --- tasmota/tasmota_xdrv_driver/xdrv_85_esp32_ble_eq3_trv.ino | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_85_esp32_ble_eq3_trv.ino b/tasmota/tasmota_xdrv_driver/xdrv_85_esp32_ble_eq3_trv.ino index 4ab03c605..860eb0038 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_85_esp32_ble_eq3_trv.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_85_esp32_ble_eq3_trv.ino @@ -132,8 +132,7 @@ print("".join(pin)) #define USE_EQ3_ESP32 #endif -// for testing of BLE_ESP32, we remove xsns_62_MI_ESP32.ino completely, and instead add this modified xsns_52_ibeacon_BLE_ESP32.ino -#if CONFIG_IDF_TARGET_ESP32 +#if defined CONFIG_IDF_TARGET_ESP32 || defined CONFIG_IDF_TARGET_ESP32C3 || defined CONFIG_IDF_TARGET_ESP32S3 #ifdef USE_EQ3_ESP32 #ifdef ESP32 // ESP32 only. Use define USE_HM10 for ESP8266 support #ifdef USE_BLE_ESP32 From d70dbe979e75fa4108c74b751a65c3363972b3bb Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Thu, 26 Jan 2023 15:26:10 +0100 Subject: [PATCH 180/262] Prep ESP32 energy for four+ phases --- tasmota/tasmota_support/support_command.ino | 5 +- .../tasmota_xdrv_driver/xdrv_03_energy.ino | 22 ++- .../xdrv_03_esp32_energy.ino | 182 +++++++++--------- 3 files changed, 113 insertions(+), 96 deletions(-) diff --git a/tasmota/tasmota_support/support_command.ino b/tasmota/tasmota_support/support_command.ino index 3b08e1d16..ff3bcb891 100644 --- a/tasmota/tasmota_support/support_command.ino +++ b/tasmota/tasmota_support/support_command.ino @@ -886,10 +886,7 @@ void CmndStatus(void) #if defined(USE_ENERGY_SENSOR) && defined(USE_ENERGY_MARGIN_DETECTION) if (TasmotaGlobal.energy_driver) { if ((0 == payload) || (9 == payload)) { - Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS9_MARGIN "\":{\"" D_CMND_POWERDELTA "\":[%d,%d,%d],\"" D_CMND_POWERLOW "\":%d,\"" D_CMND_POWERHIGH "\":%d,\"" - D_CMND_VOLTAGELOW "\":%d,\"" D_CMND_VOLTAGEHIGH "\":%d,\"" D_CMND_CURRENTLOW "\":%d,\"" D_CMND_CURRENTHIGH "\":%d}}"), - Settings->energy_power_delta[0], Settings->energy_power_delta[1], Settings->energy_power_delta[2], Settings->energy_min_power, Settings->energy_max_power, - Settings->energy_min_voltage, Settings->energy_max_voltage, Settings->energy_min_current, Settings->energy_max_current); + EnergyMarginStatus(); CmndStatusResponse(9); } } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino b/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino index 94c5feb89..2f8f9ecc8 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino @@ -375,7 +375,8 @@ void Energy200ms(void) } } - if ((LocalTime() == Midnight()) || (RtcTime.day_of_year > Settings->energy_kWhdoy)) { + bool midnight = (LocalTime() == Midnight()); + if (midnight || (RtcTime.day_of_year > Settings->energy_kWhdoy)) { Energy->kWhtoday_offset_init = true; Settings->energy_kWhdoy = RtcTime.day_of_year; @@ -399,11 +400,11 @@ void Energy200ms(void) Energy->daily_sum_export_balanced = 0.0; } EnergyUpdateToday(); -#if defined(USE_ENERGY_MARGIN_DETECTION) && defined(USE_ENERGY_POWER_LIMIT) - Energy->max_energy_state = 3; -#endif // USE_ENERGY_POWER_LIMIT } #if defined(USE_ENERGY_MARGIN_DETECTION) && defined(USE_ENERGY_POWER_LIMIT) + if (midnight) { + Energy->max_energy_state = 3; + } if ((RtcTime.hour == Settings->energy_max_energy_start) && (3 == Energy->max_energy_state )) { Energy->max_energy_state = 0; } @@ -1000,6 +1001,17 @@ void CmndEnergyConfig(void) { } #ifdef USE_ENERGY_MARGIN_DETECTION +/*********************************************************************************************\ + * USE_ENERGY_MARGIN_DETECTION and USE_ENERGY_POWER_LIMIT +\*********************************************************************************************/ + +void EnergyMarginStatus(void) { + Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS9_MARGIN "\":{\"" D_CMND_POWERDELTA "\":[%d,%d,%d],\"" D_CMND_POWERLOW "\":%d,\"" D_CMND_POWERHIGH "\":%d,\"" + D_CMND_VOLTAGELOW "\":%d,\"" D_CMND_VOLTAGEHIGH "\":%d,\"" D_CMND_CURRENTLOW "\":%d,\"" D_CMND_CURRENTHIGH "\":%d}}"), + Settings->energy_power_delta[0], Settings->energy_power_delta[1], Settings->energy_power_delta[2], Settings->energy_min_power, Settings->energy_max_power, + Settings->energy_min_voltage, Settings->energy_max_voltage, Settings->energy_min_current, Settings->energy_max_current); +} + void CmndPowerDelta(void) { if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= ENERGY_MAX_PHASES)) { if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 32000)) { @@ -1111,6 +1123,8 @@ void CmndMaxEnergyStart(void) { #endif // USE_ENERGY_POWER_LIMIT #endif // USE_ENERGY_MARGIN_DETECTION +/********************************************************************************************/ + void EnergyDrvInit(void) { Energy = (tEnergy*)calloc(sizeof(tEnergy), 1); // Need calloc to reset registers to 0/false if (!Energy) { return; } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino b/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino index 2db22d9b1..48e0a52a2 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino @@ -99,25 +99,9 @@ typedef struct { float energy_today_kWh[ENERGY_MAX_PHASES_FUTURE]; // Energy today in kWh - float allows up to 262143.99 kWh float energy_yesterday_kWh[ENERGY_MAX_PHASES_FUTURE]; // Energy yesterday in kWh - float allows up to 262143.99 kWh float energy_total_kWh[ENERGY_MAX_PHASES_FUTURE]; // Total energy in kWh - float allows up to 262143.99 kWh - float energy_export_kWh[ENERGY_MAX_PHASES_FUTURE]; + float energy_export_kWh[ENERGY_MAX_PHASES_FUTURE]; // Export energy in kWh - float allows up to 262143.99 kWh uint16_t power_delta[ENERGY_MAX_PHASES_FUTURE]; // PowerDelta - - uint16_t min_power; // PowerLow - uint16_t max_power; // PowerHigh - uint16_t min_voltage; // VoltageLow - uint16_t max_voltage; // VoltageHigh - uint16_t min_current; // CurrentLow - uint16_t max_current; // CurrentHigh - - uint16_t max_power_limit; // MaxPowerLimit - uint16_t max_power_limit_hold; // MaxPowerLimitHold - uint16_t max_power_limit_window; // MaxPowerLimitWindow - uint16_t max_power_safe_limit; // MaxSafePowerLimit - uint16_t max_power_safe_limit_hold; // MaxSafePowerLimitHold - uint16_t max_power_safe_limit_window; // MaxSafePowerLimitWindow - uint16_t max_energy; // MaxEnergy - uint16_t max_energy_start; // MaxEnergyStart } tEnergySettings; typedef struct { @@ -254,32 +238,38 @@ bool EnergyRtcSettingsValid(void) { const uint32_t XDRV_03_VERSION = 0x0101; // Latest driver version (See settings deltas below) -void Xdrv03SettingsLoad(void) { +void EnergySettingsLoad(void) { // *** Start init default values in case file is not found *** memset(&Energy->Settings, 0x00, sizeof(tEnergySettings)); Energy->Settings.version = XDRV_03_VERSION; // Init any other parameter in struct for (uint32_t i = 0; i < ENERGY_MAX_PHASES_FUTURE; i++) { - Energy->Settings.power_calibration[i] = HLW_PREF_PULSE; - Energy->Settings.voltage_calibration[i] = HLW_UREF_PULSE; - Energy->Settings.current_calibration[i] = HLW_IREF_PULSE; -// Energy->Settings.frequency_calibration[i] = 0; + Energy->Settings.power_calibration[i] = Settings->energy_power_calibration; + Energy->Settings.voltage_calibration[i] = Settings->energy_voltage_calibration;; + Energy->Settings.current_calibration[i] = Settings->energy_current_calibration;; + Energy->Settings.frequency_calibration[i] = Settings->energy_frequency_calibration; } - Energy->Settings.max_power_limit_hold = MAX_POWER_HOLD; - Energy->Settings.max_power_limit_window = MAX_POWER_WINDOW; -// Energy->Settings.max_power_safe_limit = 0; // MaxSafePowerLimit - Energy->Settings.max_power_safe_limit_hold = SAFE_POWER_HOLD; - Energy->Settings.max_power_safe_limit_window = SAFE_POWER_WINDOW; + Energy->Settings.power_calibration[1] = Settings->energy_power_calibration2; + Energy->Settings.voltage_calibration[1] = Settings->energy_voltage_calibration2; + Energy->Settings.current_calibration[1] = Settings->energy_current_calibration2; /* RtcEnergySettings.energy_total_kWh[0] = 0; RtcEnergySettings.energy_total_kWh[1] = 0; RtcEnergySettings.energy_total_kWh[2] = 0; memset((char*)&RtcEnergySettings.energy_usage, 0x00, sizeof(RtcEnergySettings.energy_usage)); */ + for (uint32_t i = 0; i < 3; i++) { + Energy->Settings.energy_today_kWh[i] = (float)(Settings->energy_kWhtoday_ph[i]) / 10000; + Energy->Settings.energy_yesterday_kWh[i] = (float)(Settings->energy_kWhyesterday_ph[i]) / 10000; + Energy->Settings.energy_total_kWh[i] = (float)(Settings->energy_kWhtotal_ph[i]) / 10000; + Energy->Settings.energy_export_kWh[i] = (float)(Settings->energy_kWhexport_ph[i]) / 10000; + + Energy->Settings.power_delta[i] = (float)(Settings->energy_power_delta[i]); + } // *** End Init default values *** #ifndef USE_UFILESYS - AddLog(LOG_LEVEL_DEBUG, PSTR("CFG: XDRV03 Use defaults as file system not enabled")); + AddLog(LOG_LEVEL_DEBUG, PSTR("CFG: Energy use defaults as file system not enabled")); #else // Try to load file /.drvset003 char filename[20]; @@ -294,17 +284,17 @@ void Xdrv03SettingsLoad(void) { // Set current version and save settings Energy->Settings.version = XDRV_03_VERSION; - Xdrv03SettingsSave(); + EnergySettingsSave(); } - AddLog(LOG_LEVEL_INFO, PSTR("CFG: XDRV03 loaded from file")); + AddLog(LOG_LEVEL_INFO, PSTR("CFG: Energy loaded from file")); } else { // File system not ready: No flash space reserved for file system - AddLog(LOG_LEVEL_DEBUG, PSTR("CFG: XDRV03 Use defaults as file system not ready or file not found")); + AddLog(LOG_LEVEL_DEBUG, PSTR("CFG: Energy use defaults as file system not ready or file not found")); } #endif // USE_UFILESYS } -void Xdrv03SettingsSave(void) { +void EnergySettingsSave(void) { #ifdef USE_UFILESYS // Called from FUNC_SAVE_SETTINGS every SaveData second and at restart uint32_t crc32 = GetCfgCrc32((uint8_t*)&Energy->Settings +4, sizeof(tEnergySettings) -4); // Skip crc32 @@ -316,10 +306,10 @@ void Xdrv03SettingsSave(void) { // Use for drivers: snprintf_P(filename, sizeof(filename), PSTR(TASM_FILE_DRIVER), XDRV_03); if (TfsSaveFile(filename, (const uint8_t*)&Energy->Settings, sizeof(tEnergySettings))) { - AddLog(LOG_LEVEL_DEBUG, PSTR("CFG: XDRV03 saved to file")); + AddLog(LOG_LEVEL_DEBUG, PSTR("CFG: Energy saved to file")); } else { // File system not ready: No flash space reserved for file system - AddLog(LOG_LEVEL_DEBUG, PSTR("CFG: XDRV03 ERROR File system not ready or unable to save file")); + AddLog(LOG_LEVEL_DEBUG, PSTR("CFG: ERROR Energy file system not ready or unable to save file")); } } #endif // USE_UFILESYS @@ -558,7 +548,8 @@ void Energy200ms(void) } } - if ((LocalTime() == Midnight()) || (RtcTime.day_of_year > Energy->Settings.energy_kWhdoy)) { + bool midnight = (LocalTime() == Midnight()); + if (midnight || (RtcTime.day_of_year > Energy->Settings.energy_kWhdoy)) { Energy->kWhtoday_offset_init = true; Energy->Settings.energy_kWhdoy = RtcTime.day_of_year; @@ -581,9 +572,11 @@ void Energy200ms(void) Energy->daily_sum_export_balanced = 0.0; } EnergyUpdateToday(); + } + if (midnight) { Energy->max_energy_state = 3; } - if ((RtcTime.hour == Energy->Settings.max_energy_start) && (3 == Energy->max_energy_state )) { + if ((RtcTime.hour == Settings->energy_max_energy_start) && (3 == Energy->max_energy_state )) { Energy->max_energy_state = 0; } @@ -678,39 +671,34 @@ void EnergyMarginCheck(void) { uint16_t energy_power_u = (uint16_t)(Energy->active_power[0]); - if (Energy->power_on && (Energy->Settings.min_power || - Energy->Settings.max_power || - Energy->Settings.min_voltage || - Energy->Settings.max_voltage || - Energy->Settings.min_current || - Energy->Settings.max_current)) { + if (Energy->power_on && (Settings->energy_min_power || Settings->energy_max_power || Settings->energy_min_voltage || Settings->energy_max_voltage || Settings->energy_min_current || Settings->energy_max_current)) { uint16_t energy_voltage_u = (uint16_t)(Energy->voltage[0]); uint16_t energy_current_u = (uint16_t)(Energy->current[0] * 1000); DEBUG_DRIVER_LOG(PSTR("NRG: W %d, U %d, I %d"), energy_power_u, energy_voltage_u, energy_current_u); bool flag; - if (EnergyMargin(false, Energy->Settings.min_power, energy_power_u, flag, Energy->min_power_flag)) { + if (EnergyMargin(false, Settings->energy_min_power, energy_power_u, flag, Energy->min_power_flag)) { ResponseAppend_P(PSTR("%s\"" D_CMND_POWERLOW "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag)); jsonflg = true; } - if (EnergyMargin(true, Energy->Settings.max_power, energy_power_u, flag, Energy->max_power_flag)) { + if (EnergyMargin(true, Settings->energy_max_power, energy_power_u, flag, Energy->max_power_flag)) { ResponseAppend_P(PSTR("%s\"" D_CMND_POWERHIGH "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag)); jsonflg = true; } - if (EnergyMargin(false, Energy->Settings.min_voltage, energy_voltage_u, flag, Energy->min_voltage_flag)) { + if (EnergyMargin(false, Settings->energy_min_voltage, energy_voltage_u, flag, Energy->min_voltage_flag)) { ResponseAppend_P(PSTR("%s\"" D_CMND_VOLTAGELOW "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag)); jsonflg = true; } - if (EnergyMargin(true, Energy->Settings.max_voltage, energy_voltage_u, flag, Energy->max_voltage_flag)) { + if (EnergyMargin(true, Settings->energy_max_voltage, energy_voltage_u, flag, Energy->max_voltage_flag)) { ResponseAppend_P(PSTR("%s\"" D_CMND_VOLTAGEHIGH "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag)); jsonflg = true; } - if (EnergyMargin(false, Energy->Settings.min_current, energy_current_u, flag, Energy->min_current_flag)) { + if (EnergyMargin(false, Settings->energy_min_current, energy_current_u, flag, Energy->min_current_flag)) { ResponseAppend_P(PSTR("%s\"" D_CMND_CURRENTLOW "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag)); jsonflg = true; } - if (EnergyMargin(true, Energy->Settings.max_current, energy_current_u, flag, Energy->max_current_flag)) { + if (EnergyMargin(true, Settings->energy_max_current, energy_current_u, flag, Energy->max_current_flag)) { ResponseAppend_P(PSTR("%s\"" D_CMND_CURRENTHIGH "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag)); jsonflg = true; } @@ -722,10 +710,10 @@ void EnergyMarginCheck(void) { } // Max Power - if (Energy->Settings.max_power_limit) { - if (Energy->active_power[0] > Energy->Settings.max_power_limit) { + if (Settings->energy_max_power_limit) { + if (Energy->active_power[0] > Settings->energy_max_power_limit) { if (!Energy->mplh_counter) { - Energy->mplh_counter = Energy->Settings.max_power_limit_hold; + Energy->mplh_counter = Settings->energy_max_power_limit_hold; } else { Energy->mplh_counter--; if (!Energy->mplh_counter) { @@ -736,11 +724,11 @@ void EnergyMarginCheck(void) { if (!Energy->mplr_counter) { Energy->mplr_counter = Settings->param[P_MAX_POWER_RETRY] +1; // SetOption33 - Max Power Retry count } - Energy->mplw_counter = Energy->Settings.max_power_limit_window; + Energy->mplw_counter = Settings->energy_max_power_limit_window; } } } - else if (TasmotaGlobal.power && (energy_power_u <= Energy->Settings.max_power_limit)) { + else if (TasmotaGlobal.power && (energy_power_u <= Settings->energy_max_power_limit)) { Energy->mplh_counter = 0; Energy->mplr_counter = 0; Energy->mplw_counter = 0; @@ -767,15 +755,15 @@ void EnergyMarginCheck(void) { } // Max Energy - if (Energy->Settings.max_energy) { + if (Settings->energy_max_energy) { uint16_t energy_daily_u = (uint16_t)(Energy->daily_sum * 1000); - if (!Energy->max_energy_state && (RtcTime.hour == Energy->Settings.max_energy_start)) { + if (!Energy->max_energy_state && (RtcTime.hour == Settings->energy_max_energy_start)) { Energy->max_energy_state = 1; ResponseTime_P(PSTR(",\"" D_JSON_ENERGYMONITOR "\":\"%s\"}"), GetStateText(1)); MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_STAT, PSTR(D_JSON_ENERGYMONITOR)); RestorePower(true, SRC_MAXENERGY); } - else if ((1 == Energy->max_energy_state ) && (energy_daily_u >= Energy->Settings.max_energy)) { + else if ((1 == Energy->max_energy_state ) && (energy_daily_u >= Settings->energy_max_energy)) { Energy->max_energy_state = 2; ResponseTime_P(PSTR(",\"" D_JSON_MAXENERGYREACHED "\":%3_f}"), &Energy->daily_sum); MqttPublishPrefixTopicRulesProcess_P(STAT, S_RSLT_WARNING); @@ -1153,6 +1141,21 @@ void CmndEnergyConfig(void) { } } +/*********************************************************************************************\ + * USE_ENERGY_MARGIN_DETECTION and USE_ENERGY_POWER_LIMIT +\*********************************************************************************************/ + +void EnergyMarginStatus(void) { + Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS9_MARGIN "\":{\"" D_CMND_POWERDELTA "\":[")); + for (uint32_t i = 0; i < ENERGY_MAX_PHASES; i++) { + ResponseAppend_P(PSTR("%s%d"), (i>0)?",":"", Energy->Settings.power_delta[i]); + } + ResponseAppend_P(PSTR("],\"" D_CMND_POWERLOW "\":%d,\"" D_CMND_POWERHIGH "\":%d,\"" + D_CMND_VOLTAGELOW "\":%d,\"" D_CMND_VOLTAGEHIGH "\":%d,\"" D_CMND_CURRENTLOW "\":%d,\"" D_CMND_CURRENTHIGH "\":%d}}"), + Settings->energy_min_power, Settings->energy_max_power, + Settings->energy_min_voltage, Settings->energy_max_voltage, Settings->energy_min_current, Settings->energy_max_current); +} + void CmndPowerDelta(void) { if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= ENERGY_MAX_PHASES)) { if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 32000)) { @@ -1164,110 +1167,114 @@ void CmndPowerDelta(void) { void CmndPowerLow(void) { if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 6000)) { - Energy->Settings.min_power = XdrvMailbox.payload; + Settings->energy_min_power = XdrvMailbox.payload; } - ResponseCmndNumber(Energy->Settings.min_power); + ResponseCmndNumber(Settings->energy_min_power); } void CmndPowerHigh(void) { if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 6000)) { - Energy->Settings.max_power = XdrvMailbox.payload; + Settings->energy_max_power = XdrvMailbox.payload; } - ResponseCmndNumber(Energy->Settings.max_power); + ResponseCmndNumber(Settings->energy_max_power); } void CmndVoltageLow(void) { if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 500)) { - Energy->Settings.min_voltage = XdrvMailbox.payload; + Settings->energy_min_voltage = XdrvMailbox.payload; } - ResponseCmndNumber(Energy->Settings.min_voltage); + ResponseCmndNumber(Settings->energy_min_voltage); } void CmndVoltageHigh(void) { if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 500)) { - Energy->Settings.max_voltage = XdrvMailbox.payload; + Settings->energy_max_voltage = XdrvMailbox.payload; } - ResponseCmndNumber(Energy->Settings.max_voltage); + ResponseCmndNumber(Settings->energy_max_voltage); } void CmndCurrentLow(void) { if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 25000)) { - Energy->Settings.min_current = XdrvMailbox.payload; + Settings->energy_min_current = XdrvMailbox.payload; } - ResponseCmndNumber(Energy->Settings.min_current); + ResponseCmndNumber(Settings->energy_min_current); } void CmndCurrentHigh(void) { if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 25000)) { - Energy->Settings.max_current = XdrvMailbox.payload; + Settings->energy_max_current = XdrvMailbox.payload; } - ResponseCmndNumber(Energy->Settings.max_current); + ResponseCmndNumber(Settings->energy_max_current); } void CmndMaxPower(void) { if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 6000)) { - Energy->Settings.max_power_limit = XdrvMailbox.payload; + Settings->energy_max_power_limit = XdrvMailbox.payload; } - ResponseCmndNumber(Energy->Settings.max_power_limit); + ResponseCmndNumber(Settings->energy_max_power_limit); } void CmndMaxPowerHold(void) { if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 6000)) { - Energy->Settings.max_power_limit_hold = (1 == XdrvMailbox.payload) ? MAX_POWER_HOLD : XdrvMailbox.payload; + Settings->energy_max_power_limit_hold = (1 == XdrvMailbox.payload) ? MAX_POWER_HOLD : XdrvMailbox.payload; } - ResponseCmndNumber(Energy->Settings.max_power_limit_hold); + ResponseCmndNumber(Settings->energy_max_power_limit_hold); } void CmndMaxPowerWindow(void) { if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 6000)) { - Energy->Settings.max_power_limit_window = (1 == XdrvMailbox.payload) ? MAX_POWER_WINDOW : XdrvMailbox.payload; + Settings->energy_max_power_limit_window = (1 == XdrvMailbox.payload) ? MAX_POWER_WINDOW : XdrvMailbox.payload; } - ResponseCmndNumber(Energy->Settings.max_power_limit_window); + ResponseCmndNumber(Settings->energy_max_power_limit_window); } void CmndSafePower(void) { if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 6000)) { - Energy->Settings.max_power_safe_limit = XdrvMailbox.payload; + Settings->energy_max_power_safe_limit = XdrvMailbox.payload; } - ResponseCmndNumber(Energy->Settings.max_power_safe_limit); + ResponseCmndNumber(Settings->energy_max_power_safe_limit); } void CmndSafePowerHold(void) { if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 6000)) { - Energy->Settings.max_power_safe_limit_hold = (1 == XdrvMailbox.payload) ? SAFE_POWER_HOLD : XdrvMailbox.payload; + Settings->energy_max_power_safe_limit_hold = (1 == XdrvMailbox.payload) ? SAFE_POWER_HOLD : XdrvMailbox.payload; } - ResponseCmndNumber(Energy->Settings.max_power_safe_limit_hold); + ResponseCmndNumber(Settings->energy_max_power_safe_limit_hold); } void CmndSafePowerWindow(void) { if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 1440)) { - Energy->Settings.max_power_safe_limit_window = (1 == XdrvMailbox.payload) ? SAFE_POWER_WINDOW : XdrvMailbox.payload; + Settings->energy_max_power_safe_limit_window = (1 == XdrvMailbox.payload) ? SAFE_POWER_WINDOW : XdrvMailbox.payload; } - ResponseCmndNumber(Energy->Settings.max_power_safe_limit_window); + ResponseCmndNumber(Settings->energy_max_power_safe_limit_window); } void CmndMaxEnergy(void) { if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 6000)) { - Energy->Settings.max_energy = XdrvMailbox.payload; + Settings->energy_max_energy = XdrvMailbox.payload; Energy->max_energy_state = 3; } - ResponseCmndNumber(Energy->Settings.max_energy); + ResponseCmndNumber(Settings->energy_max_energy); } void CmndMaxEnergyStart(void) { if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 24)) { - Energy->Settings.max_energy_start = XdrvMailbox.payload; + Settings->energy_max_energy_start = XdrvMailbox.payload; } - ResponseCmndNumber(Energy->Settings.max_energy_start); + ResponseCmndNumber(Settings->energy_max_energy_start); } +/********************************************************************************************/ + void EnergyDrvInit(void) { Energy = (tEnergy*)calloc(sizeof(tEnergy), 1); // Need calloc to reset registers to 0/false if (!Energy) { return; } - Xdrv03SettingsLoad(); + EnergySettingsLoad(); EnergyRtcSettingsLoad(); + + // Energy->voltage_common = false; // Energy->frequency_common = false; // Energy->use_overtemp = false; @@ -1290,8 +1297,7 @@ void EnergyDrvInit(void) { } } -void EnergySnsInit(void) -{ +void EnergySnsInit(void) { XnrgCall(FUNC_INIT); if (TasmotaGlobal.energy_driver) { @@ -1606,7 +1612,7 @@ bool Xdrv03(uint32_t function) result = XnrgCall(FUNC_SERIAL); break; case FUNC_SAVE_SETTINGS: - Xdrv03SettingsSave(); + EnergySettingsSave(); EnergyRtcSettingsSave(); break; case FUNC_SET_POWER: From 9f538e9986182716a15bb78704884bf622c81edb Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Thu, 26 Jan 2023 17:27:49 +0100 Subject: [PATCH 181/262] Add ESP32 support for four channels --- .../xdrv_03_esp32_energy.ino | 10 ++- .../tasmota_xnrg_energy/xnrg_07_ade7953.ino | 68 ++++++++++++------- 2 files changed, 52 insertions(+), 26 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino b/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino index 48e0a52a2..0deb4d203 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino @@ -1049,8 +1049,12 @@ void EnergyCommandCalSetResponse(uint32_t cal_type) { if (XdrvMailbox.payload > 99) { EnergySetCalibration(cal_type, XdrvMailbox.payload, XdrvMailbox.index -1); } - if (2 == Energy->phase_count) { - ResponseAppend_P(PSTR("[%d,%d]}"), EnergyGetCalibration(cal_type), EnergyGetCalibration(cal_type, 1)); + if (Energy->phase_count > 1) { + ResponseAppend_P(PSTR("[")); + for (uint32_t i = 0; i < Energy->phase_count; i++) { + ResponseAppend_P(PSTR("%s%d"), (i>0)?",":"", EnergyGetCalibration(cal_type, i)); + } + ResponseAppend_P(PSTR("]}")); } else { ResponseAppend_P(PSTR("%d}"), EnergyGetCalibration(cal_type)); } @@ -1123,7 +1127,7 @@ void CmndFrequencySet(void) { } void CmndModuleAddress(void) { - if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload < 4) && (1 == Energy->phase_count)) { + if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= 8) && (1 == Energy->phase_count)) { Energy->command_code = CMND_MODULEADDRESS; if (XnrgCall(FUNC_COMMAND)) { // Module address ResponseCmndDone(); diff --git a/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino b/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino index 4c66d7d15..6293d0330 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino @@ -219,11 +219,18 @@ const float ADE7953_POWER_CORRECTION = 23.41494; // See https://github.com/aren const float ADE7953_LSB_PER_WATTSECOND = 44; #endif // ADE7953_ACCU_ENERGY +typedef struct { + uint32_t voltage_rms; + uint32_t current_rms; + uint32_t active_power; + int32_t calib_data[ADE7953_CALIBREGS]; +} tAde7953Channel; + struct Ade7953 { - uint32_t voltage_rms[2] = { 0, 0 }; - uint32_t current_rms[2] = { 0, 0 }; - uint32_t active_power[2] = { 0, 0 }; - int32_t calib_data[2][ADE7953_CALIBREGS]; + uint32_t voltage_rms[4] = { 0, 0 }; + uint32_t current_rms[4] = { 0, 0 }; + uint32_t active_power[4] = { 0, 0 }; + int32_t calib_data[4][ADE7953_CALIBREGS]; uint8_t init_step = 0; uint8_t model = 0; // 0 = Shelly 2.5, 1 = Shelly EM, 2 = Shelly Plus 2PM, 3 = Shelly Pro 1PM, 4 = Shelly Pro 2PM, 5 = Shelly Pro 4PM uint8_t cs_index; @@ -435,15 +442,23 @@ void Ade7953Init(void) { void Ade7953GetData(void) { uint32_t acc_mode = 0; - int32_t reg[2][ADE7953_REGISTERS]; + int32_t reg[4][ADE7953_REGISTERS]; #ifdef USE_ESP32_SPI if (Ade7953.pin_cs[0] >= 0) { + uint32_t channel = 0; for (uint32_t chip = 0; chip < 2; chip++) { if (Ade7953.pin_cs[chip] < 0) { continue; } Ade7953.cs_index = chip; for (uint32_t i = 0; i < ADE7953_REGISTERS; i++) { - reg[chip][i] = Ade7953Read(Ade7953Registers[0][i]); // IRMS, WATT, VA, VAR, VRMS, Period + reg[channel][i] = Ade7953Read(Ade7953Registers[0][i]); // IRMSa, WATTa, VAa, VARa, VRMS, Period + } + channel++; + if (4 == Energy->phase_count) { + for (uint32_t i = 0; i < ADE7953_REGISTERS; i++) { + reg[channel][i] = Ade7953Read(Ade7953Registers[1][i]); // IRMSb, WATTb, VAb, VARb, VRMS, Period + } + channel++; } } } else { @@ -459,21 +474,16 @@ void Ade7953GetData(void) { } #endif // USE_ESP32_SPI -#ifdef USE_ESP32_SPI - if (1 == Energy->phase_count) { - AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("ADE: ACCMODE 0x%06X, VRMS %d, Period %d, IRMS %d, WATT %d, VA %d, VAR %d"), - acc_mode, reg[0][4], reg[0][5], reg[0][0], reg[0][1], reg[0][2], reg[0][3]); - } else -#endif // USE_ESP32_SPI - AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("ADE: ACCMODE 0x%06X, VRMS %d, %d, Period %d, %d, IRMS %d, %d, WATT %d, %d, VA %d, %d, VAR %d, %d"), - acc_mode, reg[0][4], reg[1][4], reg[0][5], reg[1][5], - reg[0][0], reg[1][0], reg[0][1], reg[1][1], reg[0][2], reg[1][2], reg[0][3], reg[1][3]); + for (uint32_t i = 0; i < Energy->phase_count; i++) { + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("ADE: Channel%d ACCMODE 0x%06X, VRMS %d, Period %d, IRMS %d, WATT %d, VA %d, VAR %d"), + i+1, acc_mode, reg[i][4], reg[i][5], reg[i][0], reg[i][1], reg[i][2], reg[i][3]); + } // If the device is initializing, we read the energy registers to reset them, but don't report the values as the first read may be inaccurate if (Ade7953.init_step) { return; } - uint32_t apparent_power[2] = { 0, 0 }; - uint32_t reactive_power[2] = { 0, 0 }; + uint32_t apparent_power[4] = { 0, 0 }; + uint32_t reactive_power[4] = { 0, 0 }; for (uint32_t channel = 0; channel < Energy->phase_count; channel++) { Ade7953.voltage_rms[channel] = reg[channel][4]; @@ -504,12 +514,16 @@ void Ade7953GetData(void) { float current_calibration = (float)EnergyGetCalibration(ENERGY_CURRENT_CALIBRATION, channel) * 10; Energy->frequency[channel] = 223750.0f / ((float)reg[channel][5] + 1); + divider = (Ade7953.calib_data[channel][ADE7953_CAL_VGAIN] != ADE7953_GAIN_DEFAULT) ? 10000 : voltage_calibration; Energy->voltage[channel] = (float)Ade7953.voltage_rms[channel] / divider; - divider = (Ade7953.calib_data[channel][ADE7953_CAL_WGAIN + channel] != ADE7953_GAIN_DEFAULT) ? ADE7953_LSB_PER_WATTSECOND : power_calibration; + + divider = (Ade7953.calib_data[channel][ADE7953_CAL_WGAIN] != ADE7953_GAIN_DEFAULT) ? ADE7953_LSB_PER_WATTSECOND : power_calibration; Energy->active_power[channel] = (float)Ade7953.active_power[channel] / divider; - divider = (Ade7953.calib_data[channel][ADE7953_CAL_VARGAIN + channel] != ADE7953_GAIN_DEFAULT) ? ADE7953_LSB_PER_WATTSECOND : power_calibration; + + divider = (Ade7953.calib_data[channel][ADE7953_CAL_VARGAIN] != ADE7953_GAIN_DEFAULT) ? ADE7953_LSB_PER_WATTSECOND : power_calibration; Energy->reactive_power[channel] = (float)reactive_power[channel] / divider; + if (ADE7953_SHELLY_EM == Ade7953.model) { if (bitRead(acc_mode, 10 +channel)) { // APSIGN Energy->active_power[channel] *= -1; @@ -518,12 +532,14 @@ void Ade7953GetData(void) { Energy->reactive_power[channel] *= -1; } } - divider = (Ade7953.calib_data[channel][ADE7953_CAL_VAGAIN + channel] != ADE7953_GAIN_DEFAULT) ? ADE7953_LSB_PER_WATTSECOND : power_calibration; + + divider = (Ade7953.calib_data[channel][ADE7953_CAL_VAGAIN] != ADE7953_GAIN_DEFAULT) ? ADE7953_LSB_PER_WATTSECOND : power_calibration; Energy->apparent_power[channel] = (float)apparent_power[channel] / divider; + if (0 == Energy->active_power[channel]) { Energy->current[channel] = 0; } else { - divider = (Ade7953.calib_data[channel][ADE7953_CAL_IGAIN + channel] != ADE7953_GAIN_DEFAULT) ? 100000 : current_calibration; + divider = (Ade7953.calib_data[channel][ADE7953_CAL_IGAIN] != ADE7953_GAIN_DEFAULT) ? 100000 : current_calibration; Energy->current[channel] = (float)Ade7953.current_rms[channel] / divider; Energy->kWhtoday_delta[channel] += Energy->active_power[channel] * 1000 / 36; } @@ -615,7 +631,7 @@ bool Ade7953SetDefaults(const char* json) { } void Ade7953Defaults(void) { - for (uint32_t channel = 0; channel < 2; channel++) { + for (uint32_t channel = 0; channel < 4; channel++) { for (uint32_t i = 0; i < ADE7953_CALIBREGS; i++) { if (ADE7943_CAL_PHCAL == i) { Ade7953.calib_data[channel][i] = (ADE7953_SHELLY_EM == Ade7953.model) ? ADE7953_PHCAL_DEFAULT_CT : ADE7953_PHCAL_DEFAULT; @@ -728,6 +744,9 @@ void Ade7953DrvInit(void) { } else { Energy->voltage_common = true; // Use common voltage Energy->frequency_common = true; // Use common frequency + if (ADE7953_SHELLY_PRO_4PM == Ade7953.model) { + Energy->phase_count = 4; + } } } Energy->use_overtemp = true; // Use global temperature for overtemp detection @@ -741,7 +760,10 @@ void Ade7953DrvInit(void) { bool Ade7953Command(void) { bool serviced = true; - uint32_t channel = (2 == XdrvMailbox.index) ? 1 : 0; + uint32_t channel = (XdrvMailbox.index > 4) ? 0 : XdrvMailbox.index -1; + if (ADE7953_SHELLY_PRO_4PM != Ade7953.model) { + channel = (2 == XdrvMailbox.index) ? 1 : 0; + } uint32_t value = (uint32_t)(CharToFloat(XdrvMailbox.data) * 100); // 1.23 = 123 if (CMND_POWERCAL == Energy->command_code) { From 103e3f616a293f64d669e1dec6a4cdc0cd20c236 Mon Sep 17 00:00:00 2001 From: gemu Date: Fri, 27 Jan 2023 11:10:43 +0100 Subject: [PATCH 182/262] refactoring and bug fixes (#17798) --- .../tasmota_xdrv_driver/xdrv_10_scripter.ino | 640 +++++++++++++----- 1 file changed, 464 insertions(+), 176 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino b/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino index ecfc0d418..8f8e834ea 100755 --- a/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino @@ -42,6 +42,9 @@ keywords if then else endif, or, and are better readable for beginners (others m #define XDRV_10 10 + +const uint8_t SCRIPT_VERS[2] = {5, 0}; + #define SCRIPT_DEBUG 0 #ifndef MAXVARS @@ -100,7 +103,6 @@ char *Get_esc_char(char *cp, char *esc_chr); #undef USE_SCRIPT_FATFS #define USE_SCRIPT_FATFS -1 -// #pragma message "universal file system used" #else // USE_UFILESYS @@ -210,13 +212,13 @@ uint32_t alt_eeprom_init(uint32_t size) { } void alt_eeprom_writeBytes(uint32_t adr, uint32_t len, uint8_t *buf) { - uint32_t *lwp=(uint32_t*)buf; + uint32_t *lwp = (uint32_t*)buf; ESP.flashEraseSector(eeprom_block / SPI_FLASH_SEC_SIZE); ESP.flashWrite(eeprom_block , lwp, SPI_FLASH_SEC_SIZE); } void alt_eeprom_readBytes(uint32_t adr, uint32_t len, uint8_t *buf) { - uint32_t *lwp=(uint32_t*)buf; + uint32_t *lwp = (uint32_t*)buf; ESP.flashRead(eeprom_block , lwp, SPI_FLASH_SEC_SIZE); } #endif // EEP_SCRIPT_SIZE @@ -497,6 +499,10 @@ struct SCRIPT_MEM { #ifdef USE_SCRIPT_SPI struct SCRIPT_SPI spi; #endif +#ifdef USE_FEXTRACT + uint32_t from_time; + uint32_t to_time; +#endif #if defined(USE_SML_M) && defined(USE_SML_SCRIPT_CMD) && defined(USE_SCRIPT_SERIAL) char *hstr; #endif @@ -504,7 +510,7 @@ struct SCRIPT_MEM { } glob_script_mem; -uint8_t tasm_cmd_activ=0; +uint8_t tasm_cmd_activ = 0; void flt2char(float num, char *nbuff) { dtostrfd(num, glob_script_mem.script_dprec, nbuff); @@ -549,7 +555,12 @@ char *GetStringArgument(char *lp,uint8_t lastop,char *cp, struct GVARS *gv); char *ForceStringVar(char *lp,char *dstr); void send_download(void); uint8_t UfsReject(char *name); -void fread_str(uint8_t fref, char *sp, uint16_t slen); +#ifdef USE_UFILESYS +void fread_str_fp(File *fp, char *sp, uint16_t slen, uint16_t flg); +int32_t script_copy_file(File *source, File *dest, uint32_t sf_from, uint32_t sf_to, uint32_t flag, WiFiClient *client); +int32_t opt_fext(File *fp, char *ts_from, char *ts_to, uint32_t flg); +int32_t extract_from_file(File *fp, char *ts_from, char *ts_to, int8_t coffs, float **a_ptr, uint16_t *a_len, uint8_t numa, int16_t accum); +#endif char *eval_sub(char *lp, float *fvar, char *rstr); void ScriptEverySecond(void) { @@ -605,7 +616,7 @@ void SetChanged(uint32_t index) { #define SCRIPT_SKIP_SPACES while (*lp==' ' || *lp=='\t') lp++; -#define SCRIPT_SKIP_EOL while (*lp==SCRIPT_EOL) lp++; +#define SCRIPT_SKIP_EOL while (*lp == SCRIPT_EOL) lp++; float *Get_MFAddr(uint8_t index, uint16_t *len, uint16_t *ipos); @@ -763,7 +774,7 @@ char *script; vtypes[vars].bits.is_filter = 0; } *vnp_p++ = vnames_p; - while (lp=MEDIAN_FILTER_NUM) index = 0; + if (index >= MEDIAN_FILTER_NUM) index = 0; struct MEDIAN_FILTER* mf = &script_mf[index]; mf->buffer[mf->index] = in; mf->index++; - if (mf->index>=MEDIAN_SIZE) mf->index = 0; + if (mf->index >= MEDIAN_SIZE) mf->index = 0; return median_array(mf->buffer, MEDIAN_SIZE); } + #ifdef USE_UFILESYS -void fread_str(uint8_t fref, char *sp, uint16_t slen) { +void fread_str_fp(File *fp, char *sp, uint16_t slen, uint16_t flg) { uint16_t index = 0; - while (glob_script_mem.files[fref].available()) { + while (fp->available()) { uint8_t buf[1], iob; - glob_script_mem.files[fref].read(buf,1); + fp->read(buf, 1); iob = buf[0]; - if (iob == '\t' || iob == ',' || iob == '\n' || iob == '\r') { - break; + if (flg) { + if (iob == '\n') { + break; + } } else { - *sp++ = iob; - index++; - if (index >= slen - 1) break; + if (iob == '\t' || iob == ',' || iob == '\n' || iob == '\r') { + break; + } } + *sp++ = iob; + index++; + if (index >= slen - 1) break; } *sp = 0; } -#endif + +int32_t script_copy_file(File *source, File *dest, uint32_t sf_from, uint32_t sf_to, uint32_t flag, WiFiClient *client) { +int32_t res = 0; +uint32_t fsize = sf_to - sf_from; + + uint8_t *fbuff = (uint8_t*)malloc(512); + uint16_t rsize = 512; + if (fbuff) { + if (flag) { + // flag > 0 copy header + source->seek(0, SeekSet); + fread_str_fp(source, (char*)fbuff, rsize, 1); + uint16_t ssize = strlen((char*)fbuff); + fbuff[ssize++] = '\n'; + fbuff[ssize] = 0; + if (dest) { + dest->write(fbuff, ssize); + } + if (client) { + client->write(fbuff, ssize); + } + } + + // seek to start + source->seek(sf_from, SeekSet); + while (fsize) { + if (fsize < rsize) { + rsize = fsize; + } + source->read(fbuff, rsize); + if (dest) { + dest->write(fbuff, rsize); + } + if (client) { + client->write(fbuff, rsize); + } + fsize -= rsize; + } + free(fbuff); + } else { + return -3; + } + return res; +} + #ifdef USE_FEXTRACT @@ -1540,9 +1600,13 @@ uint32_t ts2ts(struct FE_TM *tm, char *ts) { } void tss2ts(struct FE_TM *tm, char *dst, uint8_t mode) { - if (mode == 1) { + if (mode & 1 == 1) { // was tsm format go to 16.12.20 15:36 - sprintf(dst, "%01d.%01d.%01d %01d:%02d", tm->day, tm->month, tm->year, tm->hour, tm->mins); + char c = ' '; + if (mode & 0x80) { + c = '-'; + } + sprintf(dst, "%01d.%01d.%01d%c%01d:%02d", tm->day, tm->month, tm->year, c, tm->hour, tm->mins); } else { // 2020-12-16T15:36:41 sprintf(dst, "%04d-%02d-%02dT%02d:%02d:%02d", tm->year + 2000, tm->month, tm->day, tm->hour, tm->mins, tm->secs); @@ -1573,16 +1637,72 @@ struct tm tmx; return tmd; } +// convert seconds to tasmota time stamp +uint32_t s2tstamp(char *ts, uint32_t tsize, uint32_t seconds, uint32_t flg) { + + time_t tmd = seconds; + struct tm *tmp; + struct FE_TM tm; + tmp = gmtime(&tmd); + if (!flg) { + tm.secs = tmp->tm_sec; + tm.mins = tmp->tm_min; + tm.hour = tmp->tm_hour; + } else { + tm.secs = 0; + tm.mins = 0; + tm.hour = 0; + } + tm.month = tmp->tm_mon + 1; + tm.year = tmp->tm_year - 100; + tm.day = tmp->tm_mday; + tss2ts(&tm, ts, 0); + return 0; +} + +// optimized access, estimate entry point +int32_t opt_fext(File *fp, char *ts_from, char *ts_to, uint32_t flg) { + // seek to start + int32_t fres = extract_from_file(fp, ts_from, ts_to, -2, 0, 0, 0, 0); + int32_t start = fres; + char tsf[32]; + fread_str_fp(fp, tsf, sizeof(tsf), 0); + uint32_t ltsf = tstamp2l(tsf); + fres = extract_from_file(fp, ts_from, ts_to, -1, 0, 0, 0, 0); + int32_t end = fres; + fread_str_fp(fp, tsf, sizeof(tsf), 0); + uint32_t tssiz = tstamp2l(tsf) - ltsf; + uint32_t tspos = tstamp2l(ts_from) - ltsf; + float perc = (float)tspos / (float)tssiz * 0.8; + if (perc < 0) perc = 0; + if (perc > 1) perc = 1; + float fsize = fp->size(); + uint32_t spos = perc * fsize; + //AddLog(LOG_LEVEL_INFO,PSTR(">>> 1 %d, %d"), (uint32_t)perc, spos); + fp->seek(spos, SeekSet); + fres = extract_from_file(fp, ts_from, ts_to, -3, 0, 0, 0, 0); + if (fres < 0) { + if (flg) { + if (flg == 1) { + fres = start; + } else { + fres = end; + } + } + } + return fres; +} + // assume 1. entry is timestamp, others are tab delimited values until LF // file reference, from timestamp, to timestampm, column offset, array pointers, array lenght, number of arrays -int32_t extract_from_file(uint8_t fref, char *ts_from, char *ts_to, int8_t coffs, float **a_ptr, uint16_t *a_len, uint8_t numa, int16_t accum) { - if (!glob_script_mem.file_flags[fref].is_open) return -1; +int32_t extract_from_file(File *fp, char *ts_from, char *ts_to, int8_t coffs, float **a_ptr, uint16_t *a_len, uint8_t numa, int16_t accum) { + char rstr[32]; uint8_t sindex = 0; uint8_t colpos = 0; uint8_t range = 0; if (coffs < 0) { - uint32_t cpos = glob_script_mem.files[fref].size(); + uint32_t cpos = fp->size(); if (coffs == -1) { // seek to last entry if (cpos > 1) cpos -= 2; @@ -1590,8 +1710,8 @@ int32_t extract_from_file(uint8_t fref, char *ts_from, char *ts_to, int8_t coff uint8_t lbuff[256]; uint8_t iob; uint16_t index = sizeof(lbuff) -1; - glob_script_mem.files[fref].seek(cpos - sizeof(lbuff), SeekSet); - glob_script_mem.files[fref].read(lbuff, sizeof(lbuff)); + fp->seek(cpos - sizeof(lbuff), SeekSet); + fp->read(lbuff, sizeof(lbuff)); while (cpos) { iob = lbuff[index]; if (iob == '\n' || iob == '\r') { @@ -1600,12 +1720,13 @@ int32_t extract_from_file(uint8_t fref, char *ts_from, char *ts_to, int8_t coff cpos--; index--; } - glob_script_mem.files[fref].seek(cpos, SeekSet); + fp->seek(cpos, SeekSet); } else if (coffs == -2) { // seek to line 2 + fp->seek(0, SeekSet); for (uint32_t cp = 0; cp < cpos; cp++) { uint8_t buff[2], iob; - glob_script_mem.files[fref].read(buff, 1); + fp->read(buff, 1); iob = buff[0]; if (iob == '\n' || iob == '\r') { cpos = cp + 1; @@ -1614,24 +1735,24 @@ int32_t extract_from_file(uint8_t fref, char *ts_from, char *ts_to, int8_t coff } } else { // seek to pos of ts_from - cpos = glob_script_mem.files[fref].position(); + cpos = fp->position(); uint32_t tsfrom = tstamp2l(ts_from); - while (glob_script_mem.files[fref].available()) { + while (fp->available()) { uint8_t buff[2], iob; - glob_script_mem.files[fref].read(buff, 1); + fp->read(buff, 1); cpos++; iob = buff[0]; if (iob == '\n' || iob == '\r') { // read time stamp char ts[22]; - glob_script_mem.files[fref].read((uint8_t*)ts, sizeof(ts)); + fp->read((uint8_t*)ts, sizeof(ts)); char *cp = strchr(ts, '\t'); if (cp) { *cp = 0; uint32_t tstc = tstamp2l(ts); //Serial.printf(">>> %s - %d - %d\n",ts, tstc, cpos ); if (tstc >= tsfrom) { - glob_script_mem.files[fref].seek(cpos, SeekSet); + fp->seek(cpos, SeekSet); return cpos; } } @@ -1642,8 +1763,8 @@ int32_t extract_from_file(uint8_t fref, char *ts_from, char *ts_to, int8_t coff } return cpos; } - uint32_t ipos = glob_script_mem.files[fref].position(); - glob_script_mem.files[fref].seek(0, SeekSet); + uint32_t ipos = fp->position(); + fp->seek(0, SeekSet); uint32_t tsfrom = tstamp2l(ts_from); uint32_t tsto = tstamp2l(ts_to); //AddLog(LOG_LEVEL_INFO, PSTR("from: %d to: %d"),tsfrom, tsto); @@ -1666,10 +1787,10 @@ int32_t extract_from_file(uint8_t fref, char *ts_from, char *ts_to, int8_t coff accum = -accum; } if (accum == 0) accum = 1; - while (glob_script_mem.files[fref].available()) { + while (fp->available()) { // scan through file uint8_t buff[2], iob; - glob_script_mem.files[fref].read(buff, 1); + fp->read(buff, 1); iob = buff[0]; if (iob == '\t' || iob == ',' || iob == '\n' || iob == '\r') { rstr[sindex] = 0; @@ -1694,7 +1815,7 @@ int32_t extract_from_file(uint8_t fref, char *ts_from, char *ts_to, int8_t coff uint32_t cts = tstamp2l(rstr); if (cts > tsto) { // end of range must seek back to last LF, for next scan - glob_script_mem.files[fref].seek(lastpos, SeekSet); + fp->seek(lastpos, SeekSet); break; } if (cts >= tsfrom && cts <= tsto) { @@ -1751,12 +1872,12 @@ int32_t extract_from_file(uint8_t fref, char *ts_from, char *ts_to, int8_t coff } colpos++; if (iob == '\n' || iob == '\r') { - lastpos = glob_script_mem.files[fref].position(); + lastpos = fp->position(); colpos = 0; lines ++; if (lines == 1) { if (ipos) { - glob_script_mem.files[fref].seek(ipos, SeekSet); + fp->seek(ipos, SeekSet); } } } @@ -1767,7 +1888,7 @@ int32_t extract_from_file(uint8_t fref, char *ts_from, char *ts_to, int8_t coff return rlines; } #endif // USE_FEXTRACT - +#endif // USE_UFILESYS uint32_t script_bcd(uint8_t sel, uint32_t val) { uint32_t res = 0; @@ -2633,16 +2754,12 @@ chknext: lp = isvar(lp + 4, &vtype, &ind, 0, 0, gv); if (!ind.bits.constant) { uint8_t index = glob_script_mem.type[ind.index].index; - if (glob_script_mem.fvars[index] != glob_script_mem.s_fvars[index]) { - // var has changed - glob_script_mem.s_fvars[index] = glob_script_mem.fvars[index]; - fvar = 1; - goto nfuncexit; - } else { - fvar = 0; - goto nfuncexit; - } + fvar = glob_script_mem.fvars[index] != glob_script_mem.s_fvars[index]; + glob_script_mem.s_fvars[index] = glob_script_mem.fvars[index]; + } else { + fvar = 0; } + goto nfuncexit; } #ifdef ESP32 if (!strncmp(vname, "core", 4)) { @@ -2727,6 +2844,39 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); goto nfuncexit; } #endif + +#ifdef USE_UFILESYS + if (!strncmp(lp, "cpf(", 4)) { + // copy file with offsets sfd, sfstart, sfstop, df + float sfd, sf_from, sf_to, dfd; + lp = GetNumericArgument(lp + 4, OPER_EQU, &sfd, 0); + lp = GetNumericArgument(lp, OPER_EQU, &sf_from, 0); + lp = GetNumericArgument(lp, OPER_EQU, &sf_to, 0); + lp = GetNumericArgument(lp, OPER_EQU, &dfd, 0); + if (*lp != ')') { + lp = GetNumericArgument(lp, OPER_EQU, &fvar, 0); + } else { + fvar = 0; + } + uint8_t source = sfd; + uint8_t dest = dfd; + + if (!glob_script_mem.file_flags[source].is_open) { + fvar -1; + goto nfuncexit; + } + if (!glob_script_mem.file_flags[dest].is_open) { + fvar -2; + goto nfuncexit; + } + fvar = script_copy_file(&glob_script_mem.files[source], &glob_script_mem.files[dest], sf_from, sf_to, fvar, 0); + glob_script_mem.files[source].close(); + glob_script_mem.file_flags[source].is_open = 0; + glob_script_mem.files[dest].close(); + glob_script_mem.file_flags[dest].is_open = 0; + goto nfuncexit; + } +#endif break; case 'd': if (!strncmp(vname, "day", 3)) { @@ -2739,18 +2889,31 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); } if (!strncmp(lp, "dp(", 3)) { lp = GetNumericArgument(lp + 3, OPER_EQU, &fvar, gv); - while (*lp==' ') lp++; + while (*lp == ' ') lp++; glob_script_mem.script_lzero = fvar; if (*lp == ',' || *lp == '.') { glob_script_mem.script_sepc = *lp; lp++; } lp = GetNumericArgument(lp , OPER_EQU, &fvar, gv); - while (*lp==' ') lp++; + while (*lp == ' ') lp++; glob_script_mem.script_dprec = fvar; fvar = 0; goto nfuncexit; } + if (!strncmp(lp, "diff[", 5)) { + struct T_INDEX ind; + uint8_t vtype; + lp = isvar(lp + 5, &vtype, &ind, 0, 0, gv); + if (!ind.bits.constant) { + uint8_t index = glob_script_mem.type[ind.index].index; + fvar = glob_script_mem.fvars[index] - glob_script_mem.s_fvars[index]; + glob_script_mem.s_fvars[index] = glob_script_mem.fvars[index]; + } else { + fvar = 0; + } + goto nfuncexit; + } break; case 'e': if (!strncmp(vname, "epoch", 5)) { @@ -2770,7 +2933,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); #ifdef USE_ENERGY_SENSOR if (!strncmp(lp, "enrg[", 5)) { lp=GetNumericArgument(lp + 5, OPER_EQU, &fvar, gv); - while (*lp==' ') lp++; + while (*lp == ' ') lp++; switch ((uint32_t)fvar) { case 0: fvar = Energy.total_sum; @@ -2826,9 +2989,9 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); if (!strncmp(lp, "fo(", 3)) { char str[SCRIPT_MAXSSIZE]; lp = GetStringArgument(lp + 3, OPER_EQU, str, 0); - while (*lp==' ') lp++; + while (*lp == ' ') lp++; uint8_t mode = 0; - if ((*lp=='r') || (*lp=='w') || (*lp=='a')) { + if ((*lp == 'r') || (*lp == 'w') || (*lp == 'a')) { switch (*lp) { case 'r': mode = 0; @@ -2848,7 +3011,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); fvar = -1; for (uint8_t cnt = 0;cntopen(str,FS_FILE_WRITE); #ifdef DEBUG_FS AddLog(LOG_LEVEL_INFO, PSTR("open file for write %d"), cnt); @@ -2886,9 +3049,9 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); } if (!strncmp(lp, "fc(", 3)) { lp = GetNumericArgument(lp + 3, OPER_EQU, &fvar, gv); - if (fvar>=0) { + if (fvar >= 0) { uint8_t ind = fvar; - if (ind>=SFS_MAX) ind = SFS_MAX - 1; + if (ind >= SFS_MAX) ind = SFS_MAX - 1; #ifdef DEBUG_FS AddLog(LOG_LEVEL_INFO, PSTR("closing file %d"), ind); #endif @@ -2901,7 +3064,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); if (!strncmp(lp, "ff(", 3)) { lp = GetNumericArgument(lp + 3, OPER_EQU, &fvar, gv); uint8_t ind = fvar; - if (ind>=SFS_MAX) ind = SFS_MAX - 1; + if (ind >= SFS_MAX) ind = SFS_MAX - 1; glob_script_mem.files[ind].flush(); fvar = 0; goto nfuncexit; @@ -2909,10 +3072,10 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); if (!strncmp(lp, "fw(", 3)) { char str[SCRIPT_MAXSSIZE]; lp = ForceStringVar(lp + 3, str); - while (*lp==' ') lp++; + while (*lp == ' ') lp++; lp = GetNumericArgument(lp, OPER_EQU, &fvar, gv); uint8_t ind = fvar; - if (ind>=SFS_MAX) ind = SFS_MAX - 1; + if (ind >= SFS_MAX) ind = SFS_MAX - 1; if (glob_script_mem.file_flags[ind].is_open) { fvar = glob_script_mem.files[ind].print(str); } else { @@ -2927,7 +3090,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); SCRIPT_SKIP_SPACES lp = GetNumericArgument(lp, OPER_EQU, &fvar, gv); uint8_t ind = fvar; - if (ind>=SFS_MAX) ind = SFS_MAX - 1; + if (ind >= SFS_MAX) ind = SFS_MAX - 1; if (glob_script_mem.file_flags[ind].is_open) { fvar = glob_script_mem.files[ind].write(buf, 1); } else { @@ -2941,9 +3104,9 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); uint8_t vtype; uint8_t sindex = 0; lp = isvar(lp + 3, &vtype, &ind, 0, 0, gv); - if (vtype!=VAR_NV) { + if (vtype != VAR_NV) { // found variable as result - if ((vtype&STYPE)==0) { + if ((vtype & STYPE) == 0) { // error fvar = 0; goto exit; @@ -2956,10 +3119,10 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); fvar = 0; goto exit; } - while (*lp==' ') lp++; + while (*lp == ' ') lp++; lp = GetNumericArgument(lp, OPER_EQU, &fvar, gv); uint8_t find = fvar; - if (find>=SFS_MAX) find = SFS_MAX - 1; + if (find >= SFS_MAX) find = SFS_MAX - 1; uint8_t index = 0; char str[SCRIPT_MAXSSIZE]; char *cp = str; @@ -2970,7 +3133,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); if (entry) { if (!UfsReject((char*)entry.name())) { char *ep = (char*)entry.name(); - if (*ep=='/') ep++; + if (*ep == '/') ep++; char *lcp = strrchr(ep,'/'); if (lcp) { ep = lcp + 1; @@ -2990,12 +3153,12 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); while (glob_script_mem.files[find].available()) { uint8_t buf[1]; glob_script_mem.files[find].read(buf,1); - if (buf[0]=='\t' || buf[0]==',' || buf[0]=='\n' || buf[0]=='\r') { + if (buf[0] == '\t' || buf[0] == ',' || buf[0] == '\n' || buf[0] == '\r') { break; } else { *cp++ = buf[0]; index++; - if (index>=glob_script_mem.max_ssize - 1) break; + if (index >= glob_script_mem.max_ssize - 1) break; } } *cp = 0; @@ -3012,7 +3175,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); if (!strncmp(lp, "frb(", 4)) { lp = GetNumericArgument(lp, OPER_EQU, &fvar, gv); uint8_t ind = fvar; - if (ind>=SFS_MAX) ind = SFS_MAX - 1; + if (ind >= SFS_MAX) ind = SFS_MAX - 1; if (glob_script_mem.file_flags[ind].is_open) { uint8_t buf[2]; buf[0] = 0; @@ -3026,7 +3189,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); if (!strncmp(lp, "fa(", 3)) { lp = GetNumericArgument(lp + 3, OPER_EQU, &fvar, gv); uint8_t ind = fvar; - if (ind>=SFS_MAX) ind = SFS_MAX - 1; + if (ind >= SFS_MAX) ind = SFS_MAX - 1; if (glob_script_mem.file_flags[ind].is_open) { fvar = glob_script_mem.files[ind].available(); } else { @@ -3040,7 +3203,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); SCRIPT_SKIP_SPACES lp = GetNumericArgument(lp, OPER_EQU, &fvar, gv); SCRIPT_SKIP_SPACES - if (ind>=SFS_MAX) ind = SFS_MAX - 1; + if (ind >= SFS_MAX) ind = SFS_MAX - 1; if (glob_script_mem.file_flags[ind].is_open) { fvar = glob_script_mem.files[ind].seek(fvar, SeekSet); } else { @@ -3052,7 +3215,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); lp = GetNumericArgument(lp + 3, OPER_EQU, &fvar, gv); SCRIPT_SKIP_SPACES uint8_t ind = fvar; - if (ind>=SFS_MAX) ind = SFS_MAX - 1; + if (ind >= SFS_MAX) ind = SFS_MAX - 1; if (glob_script_mem.file_flags[ind].is_open) { fvar = glob_script_mem.files[ind].size(); } else { @@ -3081,15 +3244,15 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); #if defined(ESP32) && defined(USE_WEBCAM) if (!strncmp(lp, "fwp(", 4)) { lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, gv); - while (*lp==' ') lp++; + while (*lp == ' ') lp++; float fvar1; lp = GetNumericArgument(lp, OPER_EQU, &fvar1, gv); uint8_t ind = fvar1; - if (ind>=SFS_MAX) ind = SFS_MAX - 1; + if (ind >= SFS_MAX) ind = SFS_MAX - 1; if (glob_script_mem.file_flags[ind].is_open) { uint8_t *buff; float maxps = WcGetPicstore(-1, 0); - if (fvar<1 || fvar>maxps) fvar = 1; + if (fvar < 1 || fvar > maxps) fvar = 1; uint32_t len = WcGetPicstore(fvar - 1, &buff); if (len) { //glob_script_mem.files[ind].seek(0,SeekEnd); @@ -3116,7 +3279,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); char *script = (char*)special_malloc(fsiz + 16); if (script) { memset(script, 0, fsiz + 16); - ef.read((uint8_t*)script,fsiz); + ef.read((uint8_t*)script, fsiz); execute_script(script); free(script); fvar = 1; @@ -3187,12 +3350,6 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); } else { break; } - /* - if (oflg) { - lp = GetNumericArgument(lp, OPER_EQU, &pfac, gv); - SCRIPT_SKIP_SPACES - }*/ - // extract from file lp = GetNumericArgument(lp, OPER_EQU, &fvar, gv); SCRIPT_SKIP_SPACES @@ -3227,37 +3384,31 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); break; } } + if (!glob_script_mem.file_flags[fref].is_open) { + fvar = -1; + goto nfuncexit; + } if (oflg) { // optimized access - // seek to start - uint32_t fres = extract_from_file(fref, ts_from, ts_to, -2, 0, 0, 0, 0); - char tsf[32]; - fread_str(fref, tsf, sizeof(tsf)); - uint32_t ltsf = tstamp2l(tsf); - fres = extract_from_file(fref, ts_from, ts_to, -1, 0, 0, 0, 0); - fread_str(fref, tsf, sizeof(tsf)); - uint32_t tssiz = tstamp2l(tsf) - ltsf; - uint32_t tspos = tstamp2l(ts_from) - ltsf; - float perc = (float)tspos / (float)tssiz * 0.9; - if (perc < 0) perc = 0; - if (perc > 1) perc = 1; - float fsize = glob_script_mem.files[fref].size(); - uint32_t spos = perc * fsize; - //AddLog(LOG_LEVEL_INFO,PSTR(">>> 1 %d, %d"), (uint32_t)perc, spos); - glob_script_mem.files[fref].seek(spos, SeekSet); - fres = extract_from_file(fref, ts_from, ts_to, -3, 0, 0, 0, 0); + int32_t fres = opt_fext(&glob_script_mem.files[fref], ts_from, ts_to, 1); //AddLog(LOG_LEVEL_INFO,PSTR(">>> 2 %s - %d - %d"), ts_from, fres, (uint32_t)(perc*100)); if (fres > 0) { - fvar = extract_from_file(fref, ts_from, ts_to, coffs, a_ptr, a_len, index, accum); + fvar = extract_from_file(&glob_script_mem.files[fref], ts_from, ts_to, coffs, a_ptr, a_len, index, accum); } else { // fatal error time stamp out of range fvar = -2; } } else { - fvar = extract_from_file(fref, ts_from, ts_to, coffs, a_ptr, a_len, index, accum); + fvar = extract_from_file(&glob_script_mem.files[fref], ts_from, ts_to, coffs, a_ptr, a_len, index, accum); } } else { - fvar = extract_from_file(fref, ts_from, ts_to, coffs, 0, 0, 0, 0); + if (oflg) { + fvar = opt_fext(&glob_script_mem.files[fref], ts_from, ts_to, 0); + if (coffs == -4) { + goto nfuncexit; + } + } + fvar = extract_from_file(&glob_script_mem.files[fref], ts_from, ts_to, coffs, 0, 0, 0, 0); } goto nfuncexit; @@ -3328,7 +3479,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); while (glob_script_mem.files[find].available()) { uint8_t buf[1]; glob_script_mem.files[find].read(buf,1); - if (buf[0]=='\t' || buf[0]==',' || buf[0]=='\n' || buf[0]=='\r') { + if (buf[0] == '\t' || buf[0] == ',' || buf[0] == '\n' || buf[0] == '\r') { // skip leading TAB if (first) { break; @@ -3351,17 +3502,16 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); #endif // USE_SCRIPT_FATFS_EXT if (!strncmp(lp, "fl1(", 4) || !strncmp(lp, "fl2(", 4) ) { - uint8_t lknum = *(lp+2)&3; + uint8_t lknum = *(lp + 2) & 3; char str[SCRIPT_MAXSSIZE]; lp = GetStringArgument(lp + 4, OPER_EQU, str, 0); - if (lknum<1 || lknum>2) lknum = 1; + if (lknum < 1 || lknum > 2) lknum = 1; strlcpy(glob_script_mem.flink[lknum - 1], str, 14); fvar = 0; goto nfuncexit; } if (!strncmp(lp, "fsm", 3)) { - fvar=(uint32_t)ufsp; - //card_init(); + fvar = (uint32_t)ufsp; goto exit; } #endif //USE_SCRIPT_FATFS @@ -3411,7 +3561,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); strlcpy(rstring, wd, glob_script_mem.max_ssize); if (index) { if (strlen(wd) && index) { - if (index<0) { + if (index < 0) { // assume val=xxx rstring[0] = 0; char *cp = strstr(wd, delim); @@ -3420,7 +3570,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); if (cp) { cp++; for (uint32_t cnt = 0; cnt < glob_script_mem.max_ssize; cnt++) { - if (*cp==',' || *cp==':' || *cp==0) { + if (*cp == ',' || *cp == ':' || *cp == 0) { rstring[cnt] = 0; break; } @@ -3520,7 +3670,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); } else { uint8_t *ucp = (uint8_t*)&fvar; uint8_t rflg = 0; - if (*lp=='r') { + if (*lp == 'r') { rflg = 1; ucp += sizeof(float); lp++; @@ -3553,17 +3703,17 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); #ifdef USE_LIGHT if (!strncmp(lp, "hsvrgb(", 7)) { lp = GetNumericArgument(lp + 7, OPER_EQU, &fvar, gv); - if (fvar<0 || fvar>360) fvar = 0; + if (fvar < 0 || fvar > 360) fvar = 0; SCRIPT_SKIP_SPACES // arg2 float fvar2; lp = GetNumericArgument(lp, OPER_EQU, &fvar2, gv); - if (fvar2<0 || fvar2>100) fvar2 = 0; + if (fvar2 < 0 || fvar2 > 100) fvar2 = 0; SCRIPT_SKIP_SPACES // arg3 float fvar3; lp = GetNumericArgument(lp, OPER_EQU, &fvar3, gv); - if (fvar3<0 || fvar3>100) fvar3 = 0; + if (fvar3 < 0 || fvar3 > 100) fvar3 = 0; fvar = HSVToRGB(fvar, fvar2, fvar3); goto nfuncexit; @@ -3857,27 +4007,27 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); float fvar1; lp = GetNumericArgument(lp + 3, OPER_EQU, &fvar1, gv); SCRIPT_SKIP_SPACES - while (*lp!=')') { + while (*lp != ')') { char *opp = lp; lp++; float fvar2; lp = GetNumericArgument(lp, OPER_EQU, &fvar2, gv); SCRIPT_SKIP_SPACES fvar = fvar1; - if ((*opp=='<' && fvar1' && fvar1>fvar2) || - (*opp=='=' && fvar1==fvar2)) { - if (*lp!='<' && *lp!='>' && *lp!='=' && *lp!=')' && *lp!=SCRIPT_EOL) { + if ((*opp == '<' && fvar1 < fvar2) || + (*opp == '>' && fvar1 > fvar2) || + (*opp == '=' && fvar1 == fvar2)) { + if (*lp !='<' && *lp != '>' && *lp != '=' && *lp != ')' && *lp != SCRIPT_EOL) { float fvar3; lp = GetNumericArgument(lp, OPER_EQU, &fvar3, gv); SCRIPT_SKIP_SPACES - fvar=fvar3; + fvar = fvar3; } else { fvar = fvar2; } break; } - while (*lp!='<' && *lp!='>' && *lp!='=' && *lp!=')' && *lp!=SCRIPT_EOL) lp++; + while (*lp != '<' && *lp != '>' && *lp != '=' && *lp != ')' && *lp != SCRIPT_EOL) lp++; } len = 0; goto exit; @@ -3978,17 +4128,6 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); if (!strncmp(lp, "pd[", 3)) { GetNumericArgument(lp + 3, OPER_EQU, &fvar, gv); uint8_t gpiopin = fvar; -/* - for (uint8_t i=0;i 0)) { fvar = TasmotaGlobal.gpio_pin[gpiopin]; // skip ] bracket @@ -4112,7 +4251,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); */ if (!strncmp(lp, "rr(", 3)) { - lp+=4; + lp += 4; len = 0; const char *cp = GetResetReason().c_str(); if (sp) { @@ -4178,7 +4317,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); lp = GetNumericArgument(lp, OPER_EQU, &fvar2, gv); lp++; len = 0; - if (fvar1<0) { + if (fvar1 < 0) { fvar1 = strlen(str) + fvar1; } if (sp) { @@ -4287,8 +4426,8 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); #ifdef ESP32 if (!strncmp(lp, "sf(", 3)) { lp = GetNumericArgument(lp + 3, OPER_EQU, &fvar, gv); - if (fvar<80) fvar = 80; - if (fvar>240) fvar = 240; + if (fvar < 80) fvar = 80; + if (fvar > 240) fvar = 240; setCpuFrequencyMhz(fvar); fvar = getCpuFrequencyMhz(); goto nfuncexit; @@ -4317,7 +4456,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); if (!strncmp(lp, "sht[", 4)) { GetNumericArgument(lp + 4, OPER_EQU, &fvar, gv); uint8_t index = fvar; - if (index<=TasmotaGlobal.shutters_present) { + if (index <= TasmotaGlobal.shutters_present) { fvar = Settings->shutter_position[index - 1]; } else { fvar = -1; @@ -4446,7 +4585,7 @@ extern char *SML_GetSVal(uint32_t index); lp = GetNumericArgument(lp, OPER_EQU, &br, gv); SCRIPT_SKIP_SPACES uint32_t sconfig = TS_SERIAL_8N1; - if (*lp!=')') { + if (*lp != ')') { // serial options, must be 3 chars 8N1, 7E2 etc uint8_t bits = *lp++ & 0xf; uint8_t parity = 0; @@ -4459,7 +4598,7 @@ extern char *SML_GetSVal(uint32_t index); SCRIPT_SKIP_SPACES // check for rec buffer float rxbsiz = 128; - if (*lp!=')') { + if (*lp != ')') { lp = GetNumericArgument(lp, OPER_EQU, &rxbsiz, gv); } fvar = -1; @@ -4944,6 +5083,16 @@ extern char *SML_GetSVal(uint32_t index); len = 0; goto strexit; } +#ifdef USE_FEXTRACT + if (!strncmp(lp, "s2t(", 4)) { + lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, 0); + char str[SCRIPT_MAXSSIZE]; + s2tstamp(str, SCRIPT_MAXSSIZE, fvar, 0); + if (sp) strlcpy(sp, str, glob_script_mem.max_ssize); + len = 0; + goto strexit; + } +#endif // USE_FEXTRACT break; case 't': @@ -5239,6 +5388,11 @@ extern char *SML_GetSVal(uint32_t index); fvar = !TasmotaGlobal.global_state.wifi_down; goto exit; } + if (!strncmp(vname, "wlp", 3)) { + OsWatchLoop(); + fvar = 0; + goto exit; + } #ifdef xUSE_SHINE if (!strncmp(vname, "wav2mp3(", 8)) { char path[SCRIPT_MAXSSIZE]; @@ -5270,7 +5424,7 @@ extern char *SML_GetSVal(uint32_t index); // nothing valid found notfound: - if (fp) *fp=0; + if (fp) *fp = 0; *vtype = VAR_NV; tind->index = VAR_NV; glob_script_mem.var_not_found = 1; @@ -5694,7 +5848,7 @@ void Replace_Cmd_Vars(char *srcbuf, uint32_t srcsize, char *dstbuf, uint32_t dst struct T_INDEX ind; char string[SCRIPT_MAXSSIZE]; dstsize -= 2; - for (count = 0; count=glob_script_mem.script_size) { + if (upload.totalSize >= glob_script_mem.script_size) { Web.upload_error = 1; WSSend(500, CT_PLAIN, F("500: file to large")); return; @@ -7332,7 +7486,7 @@ void script_upload_start(void) { uint32_t tsiz = glob_script_mem.script_size - 1; if (uplsizeremove(FAT_SCRIPT_NAME); @@ -7502,22 +7654,24 @@ void SaveScript(void) { file.close(); } else { // fallback to compressed mode - script_compress(Settings->rules[0],MAX_SCRIPT_SIZE-1); + script_compress(Settings->rules[0], MAX_SCRIPT_SIZE-1); } #else // USE_UFILESYS #ifdef EEP_SCRIPT_SIZE // here we handle EEPROM modes if (glob_script_mem.FLAGS.eeprom == true) { - if (EEP_SCRIPT_SIZE!=SPECIAL_EEPMODE_SIZE) { + if (EEP_SCRIPT_SIZE != SPECIAL_EEPMODE_SIZE) { EEP_WRITE(0, EEP_SCRIPT_SIZE, glob_script_mem.script_ram); } else { uint8_t *ucs; ucs = (uint8_t*)calloc(SPI_FLASH_SEC_SIZE + 4, 1); - if (!script_compress((char*)ucs,EEP_SCRIPT_SIZE-1)) { - alt_eeprom_writeBytes(0, EEP_SCRIPT_SIZE, ucs); + if (ucs) { + if (!script_compress((char*)ucs, EEP_SCRIPT_SIZE - 1)) { + alt_eeprom_writeBytes(0, EEP_SCRIPT_SIZE, ucs); + } + free(ucs); } - if (ucs) free(ucs); } } #else @@ -7562,8 +7716,10 @@ void ScriptSaveSettings(void) { // uint32_t script_compress(char *dest, uint32_t size) { - //AddLog(LOG_LEVEL_INFO,PSTR("in string: %s len = %d"),glob_script_mem.script_ram,strlen(glob_script_mem.script_ram)); + //AddLog(LOG_LEVEL_INFO,PSTR("len: %d dsize = %d"), size, strlen(glob_script_mem.script_ram)); + yield(); int32_t len_compressed = SCRIPT_COMPRESS(glob_script_mem.script_ram, strlen(glob_script_mem.script_ram), dest, size); + yield(); if (len_compressed > 0) { dest[len_compressed] = 0; AddLog(LOG_LEVEL_INFO,PSTR("script compressed to %d bytes = %d %%"),len_compressed,len_compressed * 100 / strlen(glob_script_mem.script_ram)); @@ -7875,7 +8031,7 @@ void Script_Check_Hue(String *response) { char *lp = glob_script_mem.section_ptr + 2; while (lp) { SCRIPT_SKIP_SPACES - while (*lp==SCRIPT_EOL) { + while (*lp == SCRIPT_EOL) { lp++; } if (!*lp || *lp=='#' || *lp=='>') { @@ -7897,7 +8053,7 @@ void Script_Check_Hue(String *response) { // get type hue_script[hue_devs].type = *cp; - for (vindex = 0; vindexexists(cp)) { +#endif if (download82_busy == true) { AddLog(LOG_LEVEL_INFO, PSTR("UFS 82: Download is busy")); return; @@ -8594,7 +8839,9 @@ void ScriptServeFile82(void) { //AddLog(LOG_LEVEL_INFO, PSTR("Sendfile 82 started")); return; } +#ifndef USE_FEXTRACT } +#endif } Handle82NotFound(); @@ -8664,8 +8911,7 @@ void ScriptServeFile(void) { SendFile(cp); return; } else { - if (ufsp->exists(cp)) { - SendFile(cp); + if (!SendFile(cp)) { return; } } @@ -8679,27 +8925,28 @@ bool script_download_busy; //#define USE_DLTASK -void SendFile(char *fname) { +int32_t SendFile(char *fname) { #ifdef ESP8266 - SendFile_sub(fname, 0); + return SendFile_sub(fname, 0); #endif // ESP8266 #ifdef ESP32 #ifdef USE_DLTASK if (script_download_busy == true) { AddLog(LOG_LEVEL_INFO, PSTR("UFS: Download is busy")); - return; + return -1; } script_download_busy = true; char *path = (char*)malloc(128); strcpy(path, fname); xTaskCreatePinnedToCore(script_download_task, "DT", 6000, (void*)path, 3, NULL, 1); #else - SendFile_sub(fname, 0); + return SendFile_sub(fname, 0); #endif #endif // ESP32 + return 0; } #ifdef USE_DLTASK @@ -8713,13 +8960,29 @@ void script_download_task(void *path) { #define REVERT_M5EPD -void SendFile_sub(char *path, uint8_t stype) { +int32_t SendFile_sub(char *path, uint8_t stype) { char buff[512]; WiFiClient client; uint8_t sflg = 0; File file; uint32_t fsize; +#ifdef USE_FEXTRACT + char *lp = strchr(path, '@'); + if (lp) { + *lp = 0; + lp++; + // /ufs/test.txt@1.2.22-00:00_12.2.22-00:00 + char *tp = strchr(lp, '_'); + if (tp) { + *tp = 0; + tp++; + glob_script_mem.from_time = tstamp2l(lp); + glob_script_mem.to_time = tstamp2l(tp); + } + } +#endif // USE_FEXTRACT + #ifdef USE_DISPLAY_DUMP char *sbmp = strstr_P(path, PSTR("scrdmp.bmp")); if (sbmp) { @@ -8741,9 +9004,12 @@ uint32_t fsize; strcpy_P(buff,PSTR("text/plain")); } - if (!buff[0]) return; + if (!buff[0]) return -2; if (!sflg) { + if (!ufsp->exists(path)) { + return -1; + } file = ufsp->open(path, FS_FILE_READ); fsize = file.size(); } @@ -8784,7 +9050,7 @@ uint32_t fsize; uint8_t *bp = renderer->framebuffer; uint8_t *lbuf = (uint8_t*)special_malloc(Settings->display_width * 3 + 2); memset(lbuf, 0, Settings->display_width * 3); - if (!lbuf) return; + if (!lbuf) return -3; uint8_t dmflg = 0; if (renderer->disp_bpp & 0x40) { dmflg = 1; @@ -8887,6 +9153,27 @@ uint32_t fsize; } #endif // USE_DISPLAY_DUMP } else { +#ifdef USE_FEXTRACT + if (glob_script_mem.to_time > glob_script_mem.from_time) { + char ts[32]; + s2tstamp(ts, sizeof(ts), glob_script_mem.from_time, 0); + int32_t fo_from = opt_fext(&file, ts, ts, 1); + s2tstamp(ts, sizeof(ts), glob_script_mem.to_time, 0); + //int32_t fo_to = opt_fext(&file, ts, ts, 2); + int32_t fo_to = extract_from_file(&file, ts, ts, -3, 0, 0, 0, 0); + if (fo_to < 0) { + fo_to = extract_from_file(&file, ts, ts, -1, 0, 0, 0, 0); + } + if (fo_from >= 0 && fo_to >= 0) { + script_copy_file(&file, 0, fo_from, fo_to, 1, &client); + } + file.close(); + client.stop(); + glob_script_mem.to_time = 0; + glob_script_mem.from_time = 0; + return 0; + } +#endif uint32_t len = sizeof(buff); while (fsize > 0) { if (len > fsize) len = fsize; @@ -8897,6 +9184,7 @@ uint32_t fsize; file.close(); client.stop(); } + return 0; } #endif // USE_UFILESYS @@ -9472,7 +9760,7 @@ const char *gc_str; strcpy_P(center, PSTR("
")); } - if ( ((!mc && (*lin != '$')) || (mc == 'w' && (*lin != '$'))) && (!(specopt&WSO_FORCEMAIN)) ) { + if ( ((!mc && (*lin != '$')) || (mc == 'w' && (*lin != '$'))) && (!(specopt & WSO_FORCEMAIN)) ) { // normal web section //AddLog(LOG_LEVEL_INFO, PSTR("normal %s"), lin); if (*lin == '@') { @@ -9620,7 +9908,7 @@ const char *gc_str; char *lp = lin + 3; uint8_t bcnt = 0; char *found = lin; - while (bcnt<4) { + while (bcnt < 4) { found = strstr(found, "bu("); if (!found) break; found += 3; @@ -10259,14 +10547,14 @@ exgc: void script_send_email_body(void(*func)(char *)) { uint8_t msect = Run_Scripter1(">m", -2, 0); - if (msect==99) { + if (msect == 99) { char tmp[256]; char *lp = glob_script_mem.section_ptr + 2; while (lp) { - while (*lp==SCRIPT_EOL) { + while (*lp == SCRIPT_EOL) { lp++; } - if (!*lp || *lp=='#' || *lp=='>') { + if (!*lp || *lp == '#' || *lp == '>') { break; } if (*lp!=';') { @@ -10275,7 +10563,7 @@ uint8_t msect = Run_Scripter1(">m", -2, 0); //client->println(tmp); func(tmp); } - if (*lp==SCRIPT_EOL) { + if (*lp == SCRIPT_EOL) { lp++; } else { lp = strchr(lp, SCRIPT_EOL); @@ -10297,7 +10585,7 @@ void ScriptJsonAppend(void) { char tmp[256]; char *lp = glob_script_mem.section_ptr + 2; while (lp) { - while (*lp==SCRIPT_EOL) { + while (*lp == SCRIPT_EOL) { lp++; } if (!*lp || *lp=='#' || *lp=='>') { From f6827590f37de15f4a9b998e4393fa5d7d010d4a Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 27 Jan 2023 15:53:40 +0100 Subject: [PATCH 183/262] Prep new energy driver --- tasmota/tasmota.ino | 14 +-- .../tasmota_xdrv_driver/xdrv_03_energy.ino | 24 ++-- .../xdrv_03_esp32_energy.ino | 50 ++++---- .../xdrv_88_esp32_shelly_pro_v2.ino | 58 ++++----- .../tasmota_xnrg_energy/xnrg_07_ade7953.ino | 117 +++++++++--------- 5 files changed, 122 insertions(+), 141 deletions(-) diff --git a/tasmota/tasmota.ino b/tasmota/tasmota.ino index 67bf25cd5..b0772932b 100644 --- a/tasmota/tasmota.ino +++ b/tasmota/tasmota.ino @@ -615,23 +615,23 @@ void setup(void) { snprintf_P(TasmotaGlobal.mqtt_topic, sizeof(TasmotaGlobal.mqtt_topic), ResolveToken(TasmotaGlobal.mqtt_topic).c_str()); RtcInit(); - GpioInit(); - ButtonInit(); - SwitchInit(); + GpioInit(); // FUNC_I2C_INIT -> FUNC_MODULE_INIT -> FUNC_LED_LINK + ButtonInit(); // FUNC_ADD_BUTTON + SwitchInit(); // FUNC_ADD_SWITCH #ifdef ROTARY_V1 RotaryInit(); #endif // ROTARY_V1 #ifdef USE_BERRY if (!TasmotaGlobal.no_autoexec) { - BerryInit(); + BerryInit(); // Load preinit.be } #endif // USE_BERRY - XdrvXsnsCall(FUNC_PRE_INIT); + XdrvXsnsCall(FUNC_PRE_INIT); // FUNC_PRE_INIT TasmotaGlobal.init_state = INIT_GPIOS; - SetPowerOnState(); + SetPowerOnState(); // FUNC_SET_POWER -> FUNC_SET_DEVICE_POWER WifiConnect(); AddLog(LOG_LEVEL_INFO, PSTR(D_PROJECT " %s - %s " D_VERSION " %s%s-" ARDUINO_CORE_RELEASE "(%s)"), @@ -644,7 +644,7 @@ void setup(void) { ArduinoOTAInit(); #endif // USE_ARDUINO_OTA - XdrvXsnsCall(FUNC_INIT); + XdrvXsnsCall(FUNC_INIT); // FUNC_INIT #ifdef USE_SCRIPT if (bitRead(Settings->rule_enabled, 0)) Run_Scripter(">BS",3,0); #endif diff --git a/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino b/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino index 2f8f9ecc8..f0533454f 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino @@ -224,8 +224,7 @@ char* WebEnergyFormat(char* result, float* input, uint32_t resolution, uint32_t /********************************************************************************************/ -bool EnergyTariff1Active() // Off-Peak hours -{ +bool EnergyTariff1Active() { // Off-Peak hours uint8_t dst = 0; if (IsDst() && (Settings->tariff[0][1] != Settings->tariff[1][1])) { dst = 1; @@ -355,8 +354,7 @@ void EnergyUpdateTotal(void) { /*********************************************************************************************/ -void Energy200ms(void) -{ +void Energy200ms(void) { Energy->power_on = (TasmotaGlobal.power != 0) | Settings->flag.no_power_on_check; // SetOption21 - Show voltage even if powered off Energy->fifth_second++; @@ -416,8 +414,7 @@ void Energy200ms(void) XnrgCall(FUNC_EVERY_200_MSECOND); } -void EnergySaveState(void) -{ +void EnergySaveState(void) { Settings->energy_kWhdoy = (RtcTime.valid) ? RtcTime.day_of_year : 0; for (uint32_t i = 0; i < 3; i++) { @@ -430,8 +427,7 @@ void EnergySaveState(void) } #ifdef USE_ENERGY_MARGIN_DETECTION -bool EnergyMargin(bool type, uint16_t margin, uint16_t value, bool &flag, bool &save_flag) -{ +bool EnergyMargin(bool type, uint16_t margin, uint16_t value, bool &flag, bool &save_flag) { bool change; if (!margin) return false; @@ -606,8 +602,7 @@ void EnergyMarginCheck(void) { #endif // USE_ENERGY_POWER_LIMIT } -void EnergyMqttShow(void) -{ +void EnergyMqttShow(void) { // {"Time":"2017-12-16T11:48:55","ENERGY":{"Total":0.212,"Yesterday":0.000,"Today":0.014,"Period":2.0,"Power":22.0,"Factor":1.00,"Voltage":213.6,"Current":0.100}} int tele_period_save = TasmotaGlobal.tele_period; TasmotaGlobal.tele_period = 2; @@ -620,8 +615,7 @@ void EnergyMqttShow(void) } #endif // USE_ENERGY_MARGIN_DETECTION -void EnergyEverySecond(void) -{ +void EnergyEverySecond(void) { // Overtemp check if (Energy->use_overtemp && TasmotaGlobal.global_update) { if (TasmotaGlobal.power && !isnan(TasmotaGlobal.temperature_celsius) && (TasmotaGlobal.temperature_celsius > (float)Settings->param[P_OVER_TEMP])) { // SetOption42 Device overtemp, turn off relays @@ -731,6 +725,7 @@ void CmndEnergyYesterday(void) { } void CmndEnergyToday(void) { + // EnergyToday 22 = 0.022 kWh uint32_t values[2] = { 0 }; uint32_t params = ParseParameters(2, values); @@ -1396,9 +1391,10 @@ void EnergyShow(bool json) { // {s}
Head1Head2Head3{e} // {s}Head1Head2Head3Head4{e} WSContentSend_P(PSTR("

{t}{s}")); // First column is empty ({t} = , {s} = "), (no_label)?"":"L", (no_label)?"":itoa(i +1, value_chr, 10)); + WSContentSend_P(PSTR(""), (no_label)?"":(label_o)?"O":"L", (no_label)?"":itoa(i +1, value_chr, 10)); } WSContentSend_P(PSTR(") #endif // USE_ENERGY_COLUMN_GUI diff --git a/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino b/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino index 0deb4d203..f4b940dae 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino @@ -71,15 +71,15 @@ void (* const EnergyCommand[])(void) PROGMEM = { /********************************************************************************************/ typedef struct { - float usage_total_kWh[2]; - float return_total_kWh[2]; + float usage_total_kWh[4]; + float return_total_kWh[4]; float last_return_total_kWh; float last_usage_total_kWh; } tEnergyUsage; typedef struct { - uint32_t crc32; // To detect file changes - uint16_t version; // To detect driver function changes + uint32_t crc32; // To detect file changes + uint16_t version; // To detect driver function changes uint16_t energy_kWhdoy; uint32_t energy_kWhtotal_time; uint32_t spare1; @@ -93,15 +93,15 @@ typedef struct { uint32_t current_calibration[ENERGY_MAX_PHASES_FUTURE]; uint32_t frequency_calibration[ENERGY_MAX_PHASES_FUTURE]; - uint16_t tariff[2][2]; + float energy_today_kWh[ENERGY_MAX_PHASES_FUTURE]; // Energy today in kWh - float allows up to 262143.99 kWh + float energy_yesterday_kWh[ENERGY_MAX_PHASES_FUTURE]; // Energy yesterday in kWh - float allows up to 262143.99 kWh + float energy_total_kWh[ENERGY_MAX_PHASES_FUTURE]; // Total energy in kWh - float allows up to 262143.99 kWh + float energy_export_kWh[ENERGY_MAX_PHASES_FUTURE]; // Export energy in kWh - float allows up to 262143.99 kWh + + uint16_t power_delta[ENERGY_MAX_PHASES_FUTURE]; // PowerDelta + + uint16_t tariff[4][2]; tEnergyUsage energy_usage; - - float energy_today_kWh[ENERGY_MAX_PHASES_FUTURE]; // Energy today in kWh - float allows up to 262143.99 kWh - float energy_yesterday_kWh[ENERGY_MAX_PHASES_FUTURE]; // Energy yesterday in kWh - float allows up to 262143.99 kWh - float energy_total_kWh[ENERGY_MAX_PHASES_FUTURE]; // Total energy in kWh - float allows up to 262143.99 kWh - float energy_export_kWh[ENERGY_MAX_PHASES_FUTURE]; // Export energy in kWh - float allows up to 262143.99 kWh - - uint16_t power_delta[ENERGY_MAX_PHASES_FUTURE]; // PowerDelta } tEnergySettings; typedef struct { @@ -398,8 +398,7 @@ char* WebEnergyFormat(char* result, float* input, uint32_t resolution, uint32_t /********************************************************************************************/ -bool EnergyTariff1Active() // Off-Peak hours -{ +bool EnergyTariff1Active() { // Off-Peak hours uint8_t dst = 0; if (IsDst() && (Energy->Settings.tariff[0][1] != Energy->Settings.tariff[1][1])) { dst = 1; @@ -528,8 +527,7 @@ void EnergyUpdateTotal(void) { /*********************************************************************************************/ -void Energy200ms(void) -{ +void Energy200ms(void) { Energy->power_on = (TasmotaGlobal.power != 0) | Settings->flag.no_power_on_check; // SetOption21 - Show voltage even if powered off Energy->fifth_second++; @@ -586,8 +584,7 @@ void Energy200ms(void) XnrgCall(FUNC_EVERY_200_MSECOND); } -void EnergySaveState(void) -{ +void EnergySaveState(void) { Energy->Settings.energy_kWhdoy = (RtcTime.valid) ? RtcTime.day_of_year : 0; for (uint32_t i = 0; i < 3; i++) { @@ -599,8 +596,7 @@ void EnergySaveState(void) Energy->Settings.energy_usage = RtcEnergySettings.energy_usage; } -bool EnergyMargin(bool type, uint16_t margin, uint16_t value, bool &flag, bool &save_flag) -{ +bool EnergyMargin(bool type, uint16_t margin, uint16_t value, bool &flag, bool &save_flag) { bool change; if (!margin) return false; @@ -773,8 +769,7 @@ void EnergyMarginCheck(void) { } } -void EnergyMqttShow(void) -{ +void EnergyMqttShow(void) { // {"Time":"2017-12-16T11:48:55","ENERGY":{"Total":0.212,"Yesterday":0.000,"Today":0.014,"Period":2.0,"Power":22.0,"Factor":1.00,"Voltage":213.6,"Current":0.100}} int tele_period_save = TasmotaGlobal.tele_period; TasmotaGlobal.tele_period = 2; @@ -786,8 +781,7 @@ void EnergyMqttShow(void) MqttPublishTeleSensor(); } -void EnergyEverySecond(void) -{ +void EnergyEverySecond(void) { // Overtemp check if (Energy->use_overtemp && TasmotaGlobal.global_update) { if (TasmotaGlobal.power && !isnan(TasmotaGlobal.temperature_celsius) && (TasmotaGlobal.temperature_celsius > (float)Settings->param[P_OVER_TEMP])) { // SetOption42 Device overtemp, turn off relays @@ -895,6 +889,7 @@ void CmndEnergyYesterday(void) { } void CmndEnergyToday(void) { + // EnergyToday 22 = 0.022 kWh uint32_t values[2] = { 0 }; uint32_t params = ParseParameters(2, values); @@ -1277,8 +1272,6 @@ void EnergyDrvInit(void) { EnergySettingsLoad(); EnergyRtcSettingsLoad(); - - // Energy->voltage_common = false; // Energy->frequency_common = false; // Energy->use_overtemp = false; @@ -1545,9 +1538,10 @@ void EnergyShow(bool json) { // {s}
) - bool no_label = Energy->voltage_common || (1 == Energy->phase_count); + bool label_o = Energy->voltage_common; + bool no_label = (1 == Energy->phase_count); for (uint32_t i = 0; i < Energy->phase_count; i++) { - WSContentSend_P(PSTR("%s%s%s%s{e}")); // Last column is units ({e} =
Head1Head2Head3{e} // {s}Head1Head2Head3Head4{e} WSContentSend_P(PSTR("

{t}{s}")); // First column is empty ({t} = , {s} = "), (no_label)?"":"L", (no_label)?"":itoa(i +1, value_chr, 10)); + WSContentSend_P(PSTR(""), (no_label)?"":(label_o)?"O":"L", (no_label)?"":itoa(i +1, value_chr, 10)); } WSContentSend_P(PSTR(") #endif // USE_ENERGY_COLUMN_GUI diff --git a/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v2.ino b/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v2.ino index daf423a55..c30b6be13 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v2.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v2.ino @@ -23,10 +23,10 @@ /*********************************************************************************************\ * Shelly Pro support * - * {"NAME":"Shelly Pro 1","GPIO":[0,1,0,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,0,0,0,32,4736,0,160,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,10000,10000,3350"} - * {"NAME":"Shelly Pro 1PM","GPIO":[9568,1,9472,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,3459,0,0,32,4736,0,160,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,10000,10000,3350"} - * {"NAME":"Shelly Pro 2","GPIO":[0,1,0,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,0,0,0,32,4736,4737,160,161],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,10000,10000,3350;AdcParam2 2,10000,10000,3350"} - * {"NAME":"Shelly Pro 2PM","GPIO":[9568,1,9472,1,768,0,0,0,672,704,736,9569,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,3460,0,0,32,4736,4737,160,161],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,10000,10000,3350;AdcParam2 2,10000,10000,3350"} + * {"NAME":"Shelly Pro 1","GPIO":[0,1,0,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,0,0,0,32,4736,0,160,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350"} + * {"NAME":"Shelly Pro 1PM","GPIO":[9568,1,9472,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,3459,0,0,32,4736,0,160,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350"} + * {"NAME":"Shelly Pro 2","GPIO":[0,1,0,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,0,0,0,32,4736,4737,160,161],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350;AdcParam2 2,5600,4700,3350"} + * {"NAME":"Shelly Pro 2PM","GPIO":[9568,1,9472,1,768,0,0,0,672,704,736,9569,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,3460,0,0,32,4736,4737,160,161],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350;AdcParam2 2,5600,4700,3350"} * * {"NAME":"Shelly Pro 4PM","GPIO":[769,1,1,1,9568,0,0,0,1,705,9569,737,768,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,6214,736,704,3461,0,4736,1,0,672],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350"} * {"NAME":"Shelly Pro 4PM No display","GPIO":[1,1,1,1,9568,0,0,0,1,1,9569,1,768,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,6214,736,704,3461,0,4736,1,0,672],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350"} @@ -44,7 +44,6 @@ struct SPro { uint32_t last_update; - uint32_t probe_pin; uint16_t input_state; int8_t switch_offset; int8_t button_offset; @@ -52,6 +51,7 @@ struct SPro { uint8_t pin_mcp23s17_int; uint8_t ledlink; uint8_t power; + bool init_done; uint8_t detected; } SPro; @@ -364,17 +364,15 @@ void ShellyProPreInit(void) { TasmotaGlobal.devices_present += SPro.detected; SPro.pin_register_cs = Pin(GPIO_SPI_CS); + digitalWrite(SPro.pin_register_cs, (4 == SPro.detected) ? 1 : 0); // Prep 74HC595 rclk pinMode(SPro.pin_register_cs, OUTPUT); // Does nothing if SPI is already initiated (by ADE7953) so no harm done SPI.begin(Pin(GPIO_SPI_CLK), Pin(GPIO_SPI_MISO), Pin(GPIO_SPI_MOSI), -1); if (4 == SPro.detected) { - digitalWrite(SPro.pin_register_cs, 1); // Prep MCP23S17 chip select SPro.pin_mcp23s17_int = SHELLY_PRO_4_PIN_MCP23S17_INT; // GPIO35 = MCP23S17 common interrupt pinMode(SPro.pin_mcp23s17_int, INPUT); ShellyPro4Init(); // Init MCP23S17 - } else { - digitalWrite(SPro.pin_register_cs, 0); // Prep 74HC595 rclk } } } @@ -388,11 +386,17 @@ void ShellyProInit(void) { delay(1); // (t-rstia) This pin must be brought low for a minimum of 100 uS digitalWrite(pin_lan_reset, 1); - AddLog(LOG_LEVEL_INFO, PSTR("HDW: Shelly Pro %d%s initialized"), SPro.detected, (PinUsed(GPIO_ADE7953_CS))?"PM":""); + AddLog(LOG_LEVEL_INFO, PSTR("HDW: Shelly Pro %d%s initialized"), + SPro.detected, (PinUsed(GPIO_ADE7953_CS))?"PM":""); + + SPro.init_done = true; } void ShellyProPower(void) { - if (4 == SPro.detected) { + if (SPro.detected != 4) { + SPro.power = XdrvMailbox.index &3; + ShellyProUpdate(); + } else { // AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Set Power 0x%08X"), XdrvMailbox.index); @@ -402,29 +406,19 @@ void ShellyProPower(void) { SP4Mcp23S17DigitalWrite(sp4_relay_pin[i], state); rpower >>= 1; // Select next power } - } else { - SPro.power = XdrvMailbox.index &3; - ShellyProUpdate(); } } void ShellyProUpdateLedLink(uint32_t ledlink) { - if (4 == SPro.detected) { - - - } else { - if (ledlink != SPro.ledlink) { - SPro.ledlink = ledlink; - ShellyProUpdate(); - } + if (ledlink != SPro.ledlink) { + SPro.ledlink = ledlink; + ShellyProUpdate(); } } void ShellyProLedLink(void) { - if (4 == SPro.detected) { - - - } else { + if (!SPro.init_done) { return; } // Block write before first power update + if (SPro.detected != 4) { /* bit 2 = blue, 3 = green, 4 = red Shelly Pro documentation @@ -450,10 +444,8 @@ void ShellyProLedLink(void) { } void ShellyProLedLinkWifiOff(void) { - if (4 == SPro.detected) { - - - } else { + if (!SPro.init_done) { return; } + if (SPro.detected != 4) { /* bit 2 = blue, 3 = green, 4 = red - Green light indicator will be on if in STA mode and connected to a Wi-Fi network. @@ -483,11 +475,8 @@ bool Xdrv88(uint32_t function) { case FUNC_EVERY_SECOND: ShellyProLedLinkWifiOff(); break; - case FUNC_SET_DEVICE_POWER: + case FUNC_SET_POWER: ShellyProPower(); - return true; - case FUNC_LED_LINK: - ShellyProLedLink(); break; case FUNC_INIT: ShellyProInit(); @@ -498,6 +487,9 @@ bool Xdrv88(uint32_t function) { case FUNC_ADD_SWITCH: result = ShellyProAddSwitch(); break; + case FUNC_LED_LINK: + ShellyProLedLink(); + break; } } return result; diff --git a/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino b/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino index 6293d0330..4f899c90e 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino @@ -82,6 +82,8 @@ #define ADE7953_PHCAL_DEFAULT 0 // = range -383 to 383 - Default phase calibration for Shunts #define ADE7953_PHCAL_DEFAULT_CT 200 // = range -383 to 383 - Default phase calibration for Current Transformers (Shelly EM) +#define ADE7953_MAX_CHANNEL 4 + enum Ade7953Models { ADE7953_SHELLY_25, ADE7953_SHELLY_EM, ADE7953_SHELLY_PLUS_2PM, ADE7953_SHELLY_PRO_1PM, ADE7953_SHELLY_PRO_2PM, ADE7953_SHELLY_PRO_4PM }; enum Ade7953_8BitRegisters { @@ -227,16 +229,16 @@ typedef struct { } tAde7953Channel; struct Ade7953 { - uint32_t voltage_rms[4] = { 0, 0 }; - uint32_t current_rms[4] = { 0, 0 }; - uint32_t active_power[4] = { 0, 0 }; - int32_t calib_data[4][ADE7953_CALIBREGS]; + uint32_t voltage_rms[ADE7953_MAX_CHANNEL] = { 0, 0 }; + uint32_t current_rms[ADE7953_MAX_CHANNEL] = { 0, 0 }; + uint32_t active_power[ADE7953_MAX_CHANNEL] = { 0, 0 }; + int32_t calib_data[ADE7953_MAX_CHANNEL][ADE7953_CALIBREGS]; uint8_t init_step = 0; uint8_t model = 0; // 0 = Shelly 2.5, 1 = Shelly EM, 2 = Shelly Plus 2PM, 3 = Shelly Pro 1PM, 4 = Shelly Pro 2PM, 5 = Shelly Pro 4PM uint8_t cs_index; #ifdef USE_ESP32_SPI SPISettings spi_settings; - int8_t pin_cs[2]; + int8_t pin_cs[ADE7953_MAX_CHANNEL / 2]; #endif // USE_ESP32_SPI } Ade7953; @@ -428,9 +430,11 @@ void Ade7953Init(void) { } } #ifdef USE_ESP32_SPI - AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("ADE: Chip%d CalibRegs%c V %d, I %d, W %d, VA %d, VAr %d, Ph %d"), chip +1, 'A'+channel, regs[0], regs[1], regs[2], regs[3], regs[4], regs[5]); + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("ADE: Chip%d CalibRegs%c V %d, I %d, W %d, VA %d, VAr %d, Ph %d"), + chip +1, 'A'+channel, regs[0], regs[1], regs[2], regs[3], regs[4], regs[5]); #else - AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("ADE: CalibRegs%c V %d, I %d, W %d, VA %d, VAr %d, Ph %d"), 'A'+channel, regs[0], regs[1], regs[2], regs[3], regs[4], regs[5]); + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("ADE: CalibRegs%c V %d, I %d, W %d, VA %d, VAr %d, Ph %d"), + 'A'+channel, regs[0], regs[1], regs[2], regs[3], regs[4], regs[5]); #endif // USE_ESP32_SPI } @@ -442,12 +446,12 @@ void Ade7953Init(void) { void Ade7953GetData(void) { uint32_t acc_mode = 0; - int32_t reg[4][ADE7953_REGISTERS]; + int32_t reg[ADE7953_MAX_CHANNEL][ADE7953_REGISTERS]; #ifdef USE_ESP32_SPI if (Ade7953.pin_cs[0] >= 0) { uint32_t channel = 0; - for (uint32_t chip = 0; chip < 2; chip++) { + for (uint32_t chip = 0; chip < ADE7953_MAX_CHANNEL / 2; chip++) { if (Ade7953.pin_cs[chip] < 0) { continue; } Ade7953.cs_index = chip; for (uint32_t i = 0; i < ADE7953_REGISTERS; i++) { @@ -482,8 +486,8 @@ void Ade7953GetData(void) { // If the device is initializing, we read the energy registers to reset them, but don't report the values as the first read may be inaccurate if (Ade7953.init_step) { return; } - uint32_t apparent_power[4] = { 0, 0 }; - uint32_t reactive_power[4] = { 0, 0 }; + uint32_t apparent_power[ADE7953_MAX_CHANNEL] = { 0, 0 }; + uint32_t reactive_power[ADE7953_MAX_CHANNEL] = { 0, 0 }; for (uint32_t channel = 0; channel < Energy->phase_count; channel++) { Ade7953.voltage_rms[channel] = reg[channel][4]; @@ -578,60 +582,54 @@ bool Ade7953SetDefaults(const char* json) { // All parameters are optional allowing for partial changes JsonParserToken val; - JsonParserObject rms = root[PSTR("rms")].getObject(); - if (rms) { - val = rms[PSTR("voltage")]; - if (val) { - Ade7953.calib_data[0][ADE7953_CAL_VGAIN] = val.getInt(); - Ade7953.calib_data[1][ADE7953_CAL_VGAIN] = Ade7953.calib_data[0][ADE7953_CAL_VGAIN]; + char field[20]; + for (uint32_t i = 0; i < ADE7953_MAX_CHANNEL; i++) { + JsonParserObject rms = root[PSTR("rms")].getObject(); + if (rms) { + val = rms[PSTR("voltage")]; + if (val) { + Ade7953.calib_data[i][ADE7953_CAL_VGAIN] = val.getInt(); + } + #ifdef USE_ESP32_SPI + snprintf_P(field, sizeof(field), PSTR("voltage_%c"), 'a'+i); + val = rms[field]; // "voltage_a" .. "voltage_d" + if (val) { Ade7953.calib_data[i][ADE7953_CAL_VGAIN] = val.getInt(); } + #endif // USE_ESP32_SPI + snprintf_P(field, sizeof(field), PSTR("current_%c"), 'a'+i); + val = rms[field]; // "current_a" .. "current_d" + if (val) { Ade7953.calib_data[i][ADE7953_CAL_IGAIN] = val.getInt(); } } -#ifdef USE_ESP32_SPI - val = rms[PSTR("voltage_a")]; - if (val) { Ade7953.calib_data[0][ADE7953_CAL_VGAIN] = val.getInt(); } - val = rms[PSTR("voltage_b")]; - if (val) { Ade7953.calib_data[1][ADE7953_CAL_VGAIN] = val.getInt(); } -#endif // USE_ESP32_SPI - val = rms[PSTR("current_a")]; - if (val) { Ade7953.calib_data[0][ADE7953_CAL_IGAIN] = val.getInt(); } - val = rms[PSTR("current_b")]; - if (val) { Ade7953.calib_data[1][ADE7953_CAL_IGAIN] = val.getInt(); } - } - JsonParserObject angles = root[PSTR("angles")].getObject(); - if (angles) { - val = angles[PSTR("angle0")]; - if (val) { Ade7953.calib_data[0][ADE7943_CAL_PHCAL] = val.getInt(); } - val = angles[PSTR("angle1")]; - if (val) { Ade7953.calib_data[1][ADE7943_CAL_PHCAL] = val.getInt(); } - } - JsonParserObject powers = root[PSTR("powers")].getObject(); - if (powers) { - JsonParserObject totactive = powers[PSTR("totactive")].getObject(); - if (totactive) { - val = totactive[PSTR("a")]; - if (val) { Ade7953.calib_data[0][ADE7953_CAL_WGAIN] = val.getInt(); } - val = totactive[PSTR("b")]; - if (val) { Ade7953.calib_data[1][ADE7953_CAL_WGAIN] = val.getInt(); } + JsonParserObject angles = root[PSTR("angles")].getObject(); + if (angles) { + snprintf_P(field, sizeof(field), PSTR("angle%c"), '0'+i); + val = angles[field]; // "angle0" .. "angle3" + if (val) { Ade7953.calib_data[i][ADE7943_CAL_PHCAL] = val.getInt(); } } - JsonParserObject apparent = powers[PSTR("apparent")].getObject(); - if (apparent) { - val = apparent[PSTR("a")]; - if (val) { Ade7953.calib_data[0][ADE7953_CAL_VAGAIN] = val.getInt(); } - val = apparent[PSTR("b")]; - if (val) { Ade7953.calib_data[1][ADE7953_CAL_VAGAIN] = val.getInt(); } - } - JsonParserObject reactive = powers[PSTR("reactive")].getObject(); - if (reactive) { - val = reactive[PSTR("a")]; - if (val) { Ade7953.calib_data[0][ADE7953_CAL_VARGAIN] = val.getInt(); } - val = reactive[PSTR("b")]; - if (val) { Ade7953.calib_data[1][ADE7953_CAL_VARGAIN] = val.getInt(); } + JsonParserObject powers = root[PSTR("powers")].getObject(); + if (powers) { + snprintf_P(field, sizeof(field), PSTR("%c"), 'a'+i); + JsonParserObject totactive = powers[PSTR("totactive")].getObject(); + if (totactive) { + val = totactive[field]; // "a" .. "d" + if (val) { Ade7953.calib_data[i][ADE7953_CAL_WGAIN] = val.getInt(); } + } + JsonParserObject apparent = powers[PSTR("apparent")].getObject(); + if (apparent) { + val = apparent[field]; // "a" .. "d" + if (val) { Ade7953.calib_data[i][ADE7953_CAL_VAGAIN] = val.getInt(); } + } + JsonParserObject reactive = powers[PSTR("reactive")].getObject(); + if (reactive) { + val = reactive[field]; // "a" .. "d" + if (val) { Ade7953.calib_data[i][ADE7953_CAL_VARGAIN] = val.getInt(); } + } } } return true; } void Ade7953Defaults(void) { - for (uint32_t channel = 0; channel < 4; channel++) { + for (uint32_t channel = 0; channel < ADE7953_MAX_CHANNEL; channel++) { for (uint32_t i = 0; i < ADE7953_CALIBREGS; i++) { if (ADE7943_CAL_PHCAL == i) { Ade7953.calib_data[channel][i] = (ADE7953_SHELLY_EM == Ade7953.model) ? ADE7953_PHCAL_DEFAULT_CT : ADE7953_PHCAL_DEFAULT; @@ -722,7 +720,7 @@ void Ade7953DrvInit(void) { } #endif // USE_ESP32_SPI if (EnergyGetCalibration(ENERGY_POWER_CALIBRATION) == HLW_PREF_PULSE) { - for (uint32_t i = 0; i < 4; i++) { + for (uint32_t i = 0; i < ADE7953_MAX_CHANNEL; i++) { EnergySetCalibration(ENERGY_POWER_CALIBRATION, ADE7953_PREF, i); EnergySetCalibration(ENERGY_VOLTAGE_CALIBRATION, ADE7953_UREF, i); EnergySetCalibration(ENERGY_CURRENT_CALIBRATION, ADE7953_IREF, i); @@ -760,7 +758,8 @@ void Ade7953DrvInit(void) { bool Ade7953Command(void) { bool serviced = true; - uint32_t channel = (XdrvMailbox.index > 4) ? 0 : XdrvMailbox.index -1; + if (XdrvMailbox.index > ADE7953_MAX_CHANNEL) { return false; }; + uint32_t channel = XdrvMailbox.index -1; if (ADE7953_SHELLY_PRO_4PM != Ade7953.model) { channel = (2 == XdrvMailbox.index) ? 1 : 0; } From 0b812361102fc7d8214428ef2def30d8b2cb39c9 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 27 Jan 2023 16:41:55 +0100 Subject: [PATCH 184/262] Prep ESP32 energy expansion --- .../tasmota_xdrv_driver/xdrv_03_energy.ino | 13 ++++-- .../xdrv_03_esp32_energy.ino | 45 ++++++++++--------- 2 files changed, 33 insertions(+), 25 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino b/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino index f0533454f..8da08b594 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino @@ -17,11 +17,17 @@ along with this program. If not, see . */ -#ifdef ESP8266 +//#ifdef ESP8266 #ifdef USE_ENERGY_SENSOR +#define USE_ENERGY_SENSOR_LEGACY +#endif // USE_ENERGY_SENSOR +//#endif // ESP8266 + +#ifdef USE_ENERGY_SENSOR_LEGACY /*********************************************************************************************\ - * Energy for ESP8266 + * Energy for ESP8266 and legacy ESP32 with max three phases/channels using Settings from flash \*********************************************************************************************/ +//#warning **** USE_ENERGY_SENSOR_LEGACY **** #define XDRV_03 3 #define XSNS_03 3 @@ -1509,5 +1515,4 @@ bool Xsns03(uint32_t function) return result; } -#endif // USE_ENERGY_SENSOR -#endif // ESP8266 +#endif // USE_ENERGY_SENSOR_V1 diff --git a/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino b/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino index f4b940dae..6c22e1fda 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino @@ -1,7 +1,7 @@ /* xdrv_03_esp32_energy.ino - Energy sensor support for Tasmota - Copyright (C) 2021 Theo Arends + Copyright (C) 2023 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -19,9 +19,15 @@ #ifdef ESP32 #ifdef USE_ENERGY_SENSOR +//#define USE_ENERGY_SENSOR_ESP32 +#endif // USE_ENERGY_SENSOR +#endif // ESP32 + +#ifdef USE_ENERGY_SENSOR_ESP32 /*********************************************************************************************\ - * Energy for ESP32 + * Energy for ESP32 with max eight phases/channels using more RAM and Settings from filesystem \*********************************************************************************************/ +//#warning **** USE_ENERGY_SENSOR_ESP32 **** #define XDRV_03 3 #define XSNS_03 3 @@ -30,9 +36,7 @@ #define ENERGY_WATCHDOG 4 // Allow up to 4 seconds before deciding no valid data present #undef ENERGY_MAX_PHASES -#define ENERGY_MAX_PHASES 4 - -#define ENERGY_MAX_PHASES_FUTURE 8 +#define ENERGY_MAX_PHASES 8 // Support max eight phases/channels #include @@ -88,17 +92,17 @@ typedef struct { uint32_t spare4; uint32_t spare5; - uint32_t power_calibration[ENERGY_MAX_PHASES_FUTURE]; - uint32_t voltage_calibration[ENERGY_MAX_PHASES_FUTURE]; - uint32_t current_calibration[ENERGY_MAX_PHASES_FUTURE]; - uint32_t frequency_calibration[ENERGY_MAX_PHASES_FUTURE]; + uint32_t power_calibration[ENERGY_MAX_PHASES]; + uint32_t voltage_calibration[ENERGY_MAX_PHASES]; + uint32_t current_calibration[ENERGY_MAX_PHASES]; + uint32_t frequency_calibration[ENERGY_MAX_PHASES]; - float energy_today_kWh[ENERGY_MAX_PHASES_FUTURE]; // Energy today in kWh - float allows up to 262143.99 kWh - float energy_yesterday_kWh[ENERGY_MAX_PHASES_FUTURE]; // Energy yesterday in kWh - float allows up to 262143.99 kWh - float energy_total_kWh[ENERGY_MAX_PHASES_FUTURE]; // Total energy in kWh - float allows up to 262143.99 kWh - float energy_export_kWh[ENERGY_MAX_PHASES_FUTURE]; // Export energy in kWh - float allows up to 262143.99 kWh + float energy_today_kWh[ENERGY_MAX_PHASES]; // Energy today in kWh - float allows up to 262143.99 kWh + float energy_yesterday_kWh[ENERGY_MAX_PHASES]; // Energy yesterday in kWh - float allows up to 262143.99 kWh + float energy_total_kWh[ENERGY_MAX_PHASES]; // Total energy in kWh - float allows up to 262143.99 kWh + float energy_export_kWh[ENERGY_MAX_PHASES]; // Export energy in kWh - float allows up to 262143.99 kWh - uint16_t power_delta[ENERGY_MAX_PHASES_FUTURE]; // PowerDelta + uint16_t power_delta[ENERGY_MAX_PHASES]; // PowerDelta uint16_t tariff[4][2]; tEnergyUsage energy_usage; @@ -178,9 +182,9 @@ const uint16_t RTC_ENERGY_MEM_VALID = 0xA55A; typedef struct { uint16_t valid; tEnergyUsage energy_usage; - float energy_today_kWh[ENERGY_MAX_PHASES_FUTURE]; - float energy_total_kWh[ENERGY_MAX_PHASES_FUTURE]; - float energy_export_kWh[ENERGY_MAX_PHASES_FUTURE]; + float energy_today_kWh[ENERGY_MAX_PHASES]; + float energy_total_kWh[ENERGY_MAX_PHASES]; + float energy_export_kWh[ENERGY_MAX_PHASES]; } tRtcEnergySettings; tRtcEnergySettings RtcEnergySettings; static RTC_NOINIT_ATTR tRtcEnergySettings RtcDataEnergySettings; @@ -204,7 +208,7 @@ void EnergyRtcSettingsSave(void) { memset(&RtcEnergySettings, 0, sizeof(RtcEnergySettings)); RtcEnergySettings.valid = RTC_ENERGY_MEM_VALID; RtcEnergySettings.energy_usage = Energy->Settings.energy_usage; - for (uint32_t i = 0; i < ENERGY_MAX_PHASES_FUTURE; i++) { + for (uint32_t i = 0; i < ENERGY_MAX_PHASES; i++) { RtcEnergySettings.energy_today_kWh[i] = Energy->Settings.energy_today_kWh[i]; RtcEnergySettings.energy_total_kWh[i] = Energy->Settings.energy_total_kWh[i]; RtcEnergySettings.energy_export_kWh[i] = Energy->Settings.energy_export_kWh[i]; @@ -243,7 +247,7 @@ void EnergySettingsLoad(void) { memset(&Energy->Settings, 0x00, sizeof(tEnergySettings)); Energy->Settings.version = XDRV_03_VERSION; // Init any other parameter in struct - for (uint32_t i = 0; i < ENERGY_MAX_PHASES_FUTURE; i++) { + for (uint32_t i = 0; i < ENERGY_MAX_PHASES; i++) { Energy->Settings.power_calibration[i] = Settings->energy_power_calibration; Energy->Settings.voltage_calibration[i] = Settings->energy_voltage_calibration;; Energy->Settings.current_calibration[i] = Settings->energy_current_calibration;; @@ -1658,5 +1662,4 @@ bool Xsns03(uint32_t function) return result; } -#endif // USE_ENERGY_SENSOR -#endif // ESP32 +#endif // USE_ENERGY_SENSOR_ESP32 From f064250d9adc57d863b8789dc681584b7121c0cf Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 27 Jan 2023 16:59:54 +0100 Subject: [PATCH 185/262] Update change logs Version bump to v12.3.1.5 --- CHANGELOG.md | 13 ++++++++++--- RELEASENOTES.md | 2 +- tasmota/include/tasmota_version.h | 2 +- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 72221d18c..b85a05c9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,19 +3,26 @@ All notable changes to this project will be documented in this file. ## [Unreleased] - Development -## [12.3.1.4] +## [12.3.1.5] ### Added -- Berry ``crypto.EC_P256`` ECDSA signature (required by Matter protocol) -- Berry add up flag to ``tasmota.wifi()`` and ``tasmota.eth()``, always return MAC +- ESP32 Prep support for eigth energy phases/channels ### Breaking Changed ### Changed +- Energy refactoring preparing for ESP32 phase/channel extension ### Fixed +- ADE7953 when calibration data for second channel is used regression from v12.2.0.2 +- Shelly Pro 1/2 relay click at restart regression from v12.3.1.4 ### Removed +## [12.3.1.4] 20230127 +### Added +- Berry ``crypto.EC_P256`` ECDSA signature (required by Matter protocol) +- Berry add up flag to ``tasmota.wifi()`` and ``tasmota.eth()``, always return MAC + ## [12.3.1.3] 20230115 ### Added - Support for PCA9632 4-channel 8-bit PWM driver as light driver by Pascal Heinrich (#17557) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index a7a9175de..e11f17dcb 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -110,7 +110,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm [Complete list](BUILDS.md) of available feature and sensors. -## Changelog v12.3.1.4 +## Changelog v12.3.1.5 ### Added - Support for up to 3 single phase modbus energy monitoring device using generic Energy Modbus driver- Support for RGB displays [#17414](https://github.com/arendst/Tasmota/issues/17414) - Support for IPv6 DNS records (AAAA) and IPv6 ``Ping`` for ESP32 and ESP8266 [#17417](https://github.com/arendst/Tasmota/issues/17417) diff --git a/tasmota/include/tasmota_version.h b/tasmota/include/tasmota_version.h index 39ddb7b90..93fc0e837 100644 --- a/tasmota/include/tasmota_version.h +++ b/tasmota/include/tasmota_version.h @@ -20,6 +20,6 @@ #ifndef _TASMOTA_VERSION_H_ #define _TASMOTA_VERSION_H_ -const uint32_t VERSION = 0x0C030104; // 12.3.1.4 +const uint32_t VERSION = 0x0C030105; // 12.3.1.5 #endif // _TASMOTA_VERSION_H_ From 4dd97a9e8202b1d88191c4a06c591bc7c31e1cca Mon Sep 17 00:00:00 2001 From: Barbudor Date: Sat, 28 Jan 2023 08:04:34 +0100 Subject: [PATCH 186/262] non-breaking fix year in DS3231 (#17803) --- tasmota/tasmota_xdrv_driver/xdrv_56_rtc_chips.ino | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_56_rtc_chips.ino b/tasmota/tasmota_xdrv_driver/xdrv_56_rtc_chips.ino index 7c9755869..b68c96c6d 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_56_rtc_chips.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_56_rtc_chips.ino @@ -80,7 +80,14 @@ uint32_t DS3231ReadTime(void) { tm.day_of_week = I2cRead8(RtcChip.address, DS3231_DAY); tm.day_of_month = Bcd2Dec(I2cRead8(RtcChip.address, DS3231_DATE)); tm.month = Bcd2Dec(I2cRead8(RtcChip.address, DS3231_MONTH) & ~_BV(DS3231_CENTURY)); // Don't use the Century bit - tm.year = Bcd2Dec(I2cRead8(RtcChip.address, DS3231_YEAR)); + // MakeTime requires tm.year as number of years since 1970, + // However DS3231 is supposed to hold the true year but before this PR it was written tm.year directly + // Assuming we read ... means ... + // 00..21 = 1970..1990 written before PR (to support a RTC written with 1970) => don't apply correction + // 22..51 = 2022..2051 written after PR => apply +30 years correction + // 52..99 = 2022..2069 written before PR => don't apply correction + uint8_t year = Bcd2Dec(I2cRead8(RtcChip.address, DS3231_YEAR)); + tm.year = ((year <= 21) || (year >= 52)) ? (year) : (year+30); return MakeTime(tm); } @@ -137,7 +144,9 @@ void DS3231SetTime(uint32_t epoch_time) { I2cWrite8(RtcChip.address, DS3231_DAY, tm.day_of_week); I2cWrite8(RtcChip.address, DS3231_DATE, Dec2Bcd(tm.day_of_month)); I2cWrite8(RtcChip.address, DS3231_MONTH, Dec2Bcd(tm.month)); - I2cWrite8(RtcChip.address, DS3231_YEAR, Dec2Bcd(tm.year)); + // BreakTime returns tm.year as number of years since 1970, while DS3231 expect the true year. Adusting to avoir leap year error + uint8_t true_year = (tm.year < 30) ? (tm.year + 70) : (tm.year - 30); + I2cWrite8(RtcChip.address, DS3231_YEAR, Dec2Bcd(true_year)); I2cWrite8(RtcChip.address, DS3231_STATUS, I2cRead8(RtcChip.address, DS3231_STATUS) & ~_BV(DS3231_OSF)); // Clear the Oscillator Stop Flag } From e77154f406d6a2e8f898463a370eb960a2491193 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sat, 28 Jan 2023 11:03:14 +0100 Subject: [PATCH 187/262] Enable ESP32 energy driver --- tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino | 4 ++-- tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino b/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino index 8da08b594..2059b51dc 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino @@ -17,11 +17,11 @@ along with this program. If not, see . */ -//#ifdef ESP8266 +#ifdef ESP8266 #ifdef USE_ENERGY_SENSOR #define USE_ENERGY_SENSOR_LEGACY #endif // USE_ENERGY_SENSOR -//#endif // ESP8266 +#endif // ESP8266 #ifdef USE_ENERGY_SENSOR_LEGACY /*********************************************************************************************\ diff --git a/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino b/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino index 6c22e1fda..18098fb01 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino @@ -19,7 +19,7 @@ #ifdef ESP32 #ifdef USE_ENERGY_SENSOR -//#define USE_ENERGY_SENSOR_ESP32 +#define USE_ENERGY_SENSOR_ESP32 #endif // USE_ENERGY_SENSOR #endif // ESP32 From e9f8cfa3383b0c281f002ba91ec633b44322ab74 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sat, 28 Jan 2023 11:06:25 +0100 Subject: [PATCH 188/262] Enable ESP32 energy driver --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b85a05c9a..3872daaa9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ All notable changes to this project will be documented in this file. - ESP32 Prep support for eigth energy phases/channels ### Breaking Changed +- Berry energy_ctypes changed with new energy driver ### Changed - Energy refactoring preparing for ESP32 phase/channel extension From 76a1c0091789159e7b0ef933e7503e34b9f1a154 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sat, 28 Jan 2023 11:30:42 +0100 Subject: [PATCH 189/262] Add more energy verbosity at restart --- tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino | 4 ++-- .../tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v2.ino | 1 - tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino | 7 ++++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino b/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino index 18098fb01..e3d1e271c 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino @@ -273,7 +273,7 @@ void EnergySettingsLoad(void) { // *** End Init default values *** #ifndef USE_UFILESYS - AddLog(LOG_LEVEL_DEBUG, PSTR("CFG: Energy use defaults as file system not enabled")); + AddLog(LOG_LEVEL_INFO, PSTR("CFG: Energy use defaults as file system not enabled")); #else // Try to load file /.drvset003 char filename[20]; @@ -293,7 +293,7 @@ void EnergySettingsLoad(void) { AddLog(LOG_LEVEL_INFO, PSTR("CFG: Energy loaded from file")); } else { // File system not ready: No flash space reserved for file system - AddLog(LOG_LEVEL_DEBUG, PSTR("CFG: Energy use defaults as file system not ready or file not found")); + AddLog(LOG_LEVEL_INFO, PSTR("CFG: Energy use defaults as file system not ready or file not found")); } #endif // USE_UFILESYS } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v2.ino b/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v2.ino index c30b6be13..89de679c3 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v2.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v2.ino @@ -27,7 +27,6 @@ * {"NAME":"Shelly Pro 1PM","GPIO":[9568,1,9472,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,3459,0,0,32,4736,0,160,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350"} * {"NAME":"Shelly Pro 2","GPIO":[0,1,0,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,0,0,0,32,4736,4737,160,161],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350;AdcParam2 2,5600,4700,3350"} * {"NAME":"Shelly Pro 2PM","GPIO":[9568,1,9472,1,768,0,0,0,672,704,736,9569,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,3460,0,0,32,4736,4737,160,161],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350;AdcParam2 2,5600,4700,3350"} - * * {"NAME":"Shelly Pro 4PM","GPIO":[769,1,1,1,9568,0,0,0,1,705,9569,737,768,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,6214,736,704,3461,0,4736,1,0,672],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350"} * {"NAME":"Shelly Pro 4PM No display","GPIO":[1,1,1,1,9568,0,0,0,1,1,9569,1,768,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,6214,736,704,3461,0,4736,1,0,672],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350"} * diff --git a/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino b/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino index 4f899c90e..3c55df525 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino @@ -24,14 +24,15 @@ #ifdef USE_ENERGY_SENSOR #ifdef USE_ADE7953 /*********************************************************************************************\ - * ADE7953 - Energy used in Shelly 2.5 (model 1), Shelly EM (model 2), Shelly Plus 2PM (model 3), Shelly Pro 1PM (model 4) and Shelly Pro 2PM (model 5) + * ADE7953 - Energy used in Shelly 2.5 (model 1), EM (model 2), Plus 2PM (model 3), Pro 1PM (model 4), Pro 2PM (model 5) and Pro 4PM (model 6) * * {"NAME":"Shelly 2.5","GPIO":[320,0,32,0,224,193,0,0,640,192,608,225,3456,4736],"FLAG":0,"BASE":18} * {"NAME":"Shelly EM","GPIO":[0,0,0,0,0,0,0,0,640,3457,608,224,8832,1],"FLAG":0,"BASE":18} * {"NAME":"Shelly Plus 2PM PCB v0.1.5","GPIO":[320,0,192,0,0,0,1,1,225,224,0,0,0,0,193,0,0,0,0,0,0,608,3840,32,0,0,0,0,0,640,0,0,3458,4736,0,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,32000,40000,3350"} * {"NAME":"Shelly Plus 2PM PCB v0.1.9","GPIO":[320,0,0,0,32,192,0,0,225,224,0,0,0,0,193,0,0,0,0,0,0,608,640,3458,0,0,0,0,0,9472,0,4736,0,0,0,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,10000,10000,3350"} - * {"NAME":"Shelly Pro 1PM","GPIO":[9568,1,9472,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,3459,0,0,32,4736,0,160,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,10000,10000,3350"} - * {"NAME":"Shelly Pro 2PM","GPIO":[9568,1,9472,1,768,0,0,0,672,704,736,9569,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,3460,0,0,32,4736,4737,160,161],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,10000,10000,3350;AdcParam2 2,10000,10000,3350"} + * {"NAME":"Shelly Pro 1PM","GPIO":[9568,1,9472,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,3459,0,0,32,4736,0,160,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350"} + * {"NAME":"Shelly Pro 2PM","GPIO":[9568,1,9472,1,768,0,0,0,672,704,736,9569,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,3460,0,0,32,4736,4737,160,161],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350;AdcParam2 2,5600,4700,3350"} + * {"NAME":"Shelly Pro 4PM No display","GPIO":[1,1,1,1,9568,0,0,0,1,1,9569,1,768,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,6214,736,704,3461,0,4736,1,0,672],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350"} * * Based on datasheet from https://www.analog.com/en/products/ade7953.html * From 78fe958d895f31af7541c9a4422712488389a706 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sat, 28 Jan 2023 13:47:37 +0100 Subject: [PATCH 190/262] Fix energy dummy supporting 8 channels --- tasmota/include/tasmota.h | 4 ++++ tasmota/tasmota_xnrg_energy/xnrg_30_dummy.ino | 18 ++++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/tasmota/include/tasmota.h b/tasmota/include/tasmota.h index db4bcec0b..2410d0a42 100644 --- a/tasmota/include/tasmota.h +++ b/tasmota/include/tasmota.h @@ -203,7 +203,11 @@ const uint16_t MAX_INPUT_BUFFER_SIZE = 2048; // Max number of characters in Ardu const uint16_t FLOATSZ = 16; // Max number of characters in float result from dtostrfd (max 32) const uint16_t CMDSZ = 24; // Max number of characters in command const uint16_t TOPSZ = 151; // Max number of characters in topic string +#ifdef ESP8266 const uint16_t GUISZ = 300; // Max number of characters in WebEnergyFormat string +#else +const uint16_t GUISZ = 600; // Max number of characters in WebEnergyFormat string +#endif #ifdef ESP8266 #ifdef PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48_SECHEAP_SHARED diff --git a/tasmota/tasmota_xnrg_energy/xnrg_30_dummy.ino b/tasmota/tasmota_xnrg_energy/xnrg_30_dummy.ino index 49de5be28..67916a717 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_30_dummy.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_30_dummy.ino @@ -28,6 +28,10 @@ * Each phase or channel can be set using commands overriding above commands * EnergyConfig1, EnergyConfig2 and EnergyConfig3 for Current phases (0.417 = 417mA) * EnergyConfig4, EnergyConfig5 and EnergyConfig6 for Active Power phases (100 = 100W) + * In addition on ESP32 supporting more channels: + * EnergyConfig11 to 18 for Current phases 1 to 8 (0.417 = 417mA) + * EnergyConfig111 to 118 for Active Power phases 1 to 8 (100 = 100W) + * * Active Power is adjusted to calculated Apparent Power (=U*I) if the latter is smaller than the first * * Enable by selecting any GPIO as Option A2 @@ -48,8 +52,8 @@ /********************************************************************************************/ struct { - int32_t current[3] = { 0 }; - int32_t power[3] = { 0 }; + int32_t current[ENERGY_MAX_PHASES] = { 0 }; + int32_t power[ENERGY_MAX_PHASES] = { 0 }; } NrgDummy; void NrgDummyEverySecond(void) { @@ -127,6 +131,16 @@ bool NrgDummyCommand(void) { if ((XdrvMailbox.index > 3) && (XdrvMailbox.index < 7)) { NrgDummy.power[XdrvMailbox.index -4] = value; } +#ifdef ESP32 + // EnergyConfig11 to 18 = Set Energy->current[channel] in A like 0.417 for 417mA + if ((XdrvMailbox.index > 10) && (XdrvMailbox.index < ENERGY_MAX_PHASES + 10)) { + NrgDummy.current[XdrvMailbox.index -1] = value; + } + // EnergyConfig111 to 118 = Set Energy->active_power[channel] in W like 100 for 100W + if ((XdrvMailbox.index > 110) && (XdrvMailbox.index < ENERGY_MAX_PHASES +110)) { + NrgDummy.power[XdrvMailbox.index -4] = value; + } +#endif } else serviced = false; // Unknown command From 9e522e8fa3b48f9f4d5caebbd2e086b0efef1577 Mon Sep 17 00:00:00 2001 From: David Gwynne Date: Sun, 29 Jan 2023 16:58:20 +1000 Subject: [PATCH 191/262] fix determination of the current weekday. (#17812) the result of c logical expressions is 0 or 1, not the values of the operands. --- tasmota/tasmota_xdrv_driver/xdrv_65_tuyamcubr.ino | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_65_tuyamcubr.ino b/tasmota/tasmota_xdrv_driver/xdrv_65_tuyamcubr.ino index 48697e41e..e6b471750 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_65_tuyamcubr.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_65_tuyamcubr.ino @@ -862,6 +862,11 @@ tuyamcubr_recv_time(struct tuyamcubr_softc *sc, uint8_t v, const uint8_t *data, size_t datalen) { struct tuyamcubr_time tm; + uint8_t weekday; + + weekday = RtcTime.day_of_week - 1; + if (weekday == 0) + weekday = 7; /* check datalen? should be 0 */ @@ -872,7 +877,7 @@ tuyamcubr_recv_time(struct tuyamcubr_softc *sc, uint8_t v, tm.hour = RtcTime.hour; tm.minute = RtcTime.minute; tm.second = RtcTime.second; - tm.weekday = (RtcTime.day_of_week - 1) || 7; + tm.weekday = weekday; tuyamcubr_send(sc, TUYAMCUBR_CMD_TIME, &tm, sizeof(tm)); } From 2ed602057c78da47a28d55c9aa692e13ca3a23db Mon Sep 17 00:00:00 2001 From: Tyeth Gundry Date: Sun, 29 Jan 2023 07:06:25 +0000 Subject: [PATCH 192/262] Add SEN5X to I2C devices (#17736) --- BUILDS.md | 1 + CODE_OWNERS.md | 1 + I2CDEVICES.md | 1 + lib/lib_i2c/Sensirion_Core/.clang-format | 14 + lib/lib_i2c/Sensirion_Core/CHANGELOG.rst | 161 ++++ lib/lib_i2c/Sensirion_Core/LICENSE | 29 + lib/lib_i2c/Sensirion_Core/README.md | 139 +++ .../AllCommandsI2c/AllCommandsI2c.ino | 62 ++ .../AllCommandsShdlc/AllCommandsShdlc.ino | 73 ++ lib/lib_i2c/Sensirion_Core/keywords.txt | 56 ++ lib/lib_i2c/Sensirion_Core/library.properties | 9 + .../Sensirion_Core/src/SensirionCore.h | 46 + .../src/SensirionCoreArduinoLibrary.h | 51 + .../Sensirion_Core/src/SensirionCrc.cpp | 64 ++ lib/lib_i2c/Sensirion_Core/src/SensirionCrc.h | 59 ++ .../Sensirion_Core/src/SensirionErrors.cpp | 148 +++ .../Sensirion_Core/src/SensirionErrors.h | 87 ++ .../src/SensirionI2CCommunication.cpp | 119 +++ .../src/SensirionI2CCommunication.h | 83 ++ .../Sensirion_Core/src/SensirionI2CRxFrame.h | 64 ++ .../src/SensirionI2CTxFrame.cpp | 144 +++ .../Sensirion_Core/src/SensirionI2CTxFrame.h | 197 ++++ .../Sensirion_Core/src/SensirionRxFrame.cpp | 129 +++ .../Sensirion_Core/src/SensirionRxFrame.h | 147 +++ .../src/SensirionShdlcCommunication.cpp | 184 ++++ .../src/SensirionShdlcCommunication.h | 95 ++ .../src/SensirionShdlcRxFrame.h | 86 ++ .../src/SensirionShdlcTxFrame.cpp | 130 +++ .../src/SensirionShdlcTxFrame.h | 184 ++++ .../Sensirion_Core/tests/compile_test.py | 45 + .../Sensirion_Core/tests/run_cppcheck.sh | 3 + .../Sensirion_Core/tests/syntax_check.sh | 5 + lib/lib_i2c/Sensirion_I2C_SEN5X/CHANGELOG.md | 20 + lib/lib_i2c/Sensirion_I2C_SEN5X/LICENSE | 29 + lib/lib_i2c/Sensirion_I2C_SEN5X/README.md | 97 ++ .../examples/exampleUsage/exampleUsage.ino | 249 +++++ .../images/SEN5X_pinout.png | Bin 0 -> 38240 bytes .../Sensirion_I2C_SEN5X/images/SEN5x.png | Bin 0 -> 450015 bytes lib/lib_i2c/Sensirion_I2C_SEN5X/keywords.txt | 55 ++ .../Sensirion_I2C_SEN5X/library.properties | 10 + .../src/SensirionI2CSen5x.cpp | 880 ++++++++++++++++++ .../src/SensirionI2CSen5x.h | 857 +++++++++++++++++ tasmota/include/tasmota_configurations.h | 1 + .../include/tasmota_configurations_ESP32.h | 2 + tasmota/my_user_config.h | 1 + tasmota/tasmota_support/support_features.ino | 5 +- .../tasmota_xsns_sensor/xsns_103_sen5x.ino | 312 +++++++ tools/decode-status.py | 2 +- 48 files changed, 5133 insertions(+), 3 deletions(-) create mode 100644 lib/lib_i2c/Sensirion_Core/.clang-format create mode 100644 lib/lib_i2c/Sensirion_Core/CHANGELOG.rst create mode 100644 lib/lib_i2c/Sensirion_Core/LICENSE create mode 100644 lib/lib_i2c/Sensirion_Core/README.md create mode 100644 lib/lib_i2c/Sensirion_Core/examples/AllCommandsI2c/AllCommandsI2c.ino create mode 100644 lib/lib_i2c/Sensirion_Core/examples/AllCommandsShdlc/AllCommandsShdlc.ino create mode 100644 lib/lib_i2c/Sensirion_Core/keywords.txt create mode 100644 lib/lib_i2c/Sensirion_Core/library.properties create mode 100644 lib/lib_i2c/Sensirion_Core/src/SensirionCore.h create mode 100644 lib/lib_i2c/Sensirion_Core/src/SensirionCoreArduinoLibrary.h create mode 100644 lib/lib_i2c/Sensirion_Core/src/SensirionCrc.cpp create mode 100644 lib/lib_i2c/Sensirion_Core/src/SensirionCrc.h create mode 100644 lib/lib_i2c/Sensirion_Core/src/SensirionErrors.cpp create mode 100644 lib/lib_i2c/Sensirion_Core/src/SensirionErrors.h create mode 100644 lib/lib_i2c/Sensirion_Core/src/SensirionI2CCommunication.cpp create mode 100644 lib/lib_i2c/Sensirion_Core/src/SensirionI2CCommunication.h create mode 100644 lib/lib_i2c/Sensirion_Core/src/SensirionI2CRxFrame.h create mode 100644 lib/lib_i2c/Sensirion_Core/src/SensirionI2CTxFrame.cpp create mode 100644 lib/lib_i2c/Sensirion_Core/src/SensirionI2CTxFrame.h create mode 100644 lib/lib_i2c/Sensirion_Core/src/SensirionRxFrame.cpp create mode 100644 lib/lib_i2c/Sensirion_Core/src/SensirionRxFrame.h create mode 100644 lib/lib_i2c/Sensirion_Core/src/SensirionShdlcCommunication.cpp create mode 100644 lib/lib_i2c/Sensirion_Core/src/SensirionShdlcCommunication.h create mode 100644 lib/lib_i2c/Sensirion_Core/src/SensirionShdlcRxFrame.h create mode 100644 lib/lib_i2c/Sensirion_Core/src/SensirionShdlcTxFrame.cpp create mode 100644 lib/lib_i2c/Sensirion_Core/src/SensirionShdlcTxFrame.h create mode 100644 lib/lib_i2c/Sensirion_Core/tests/compile_test.py create mode 100644 lib/lib_i2c/Sensirion_Core/tests/run_cppcheck.sh create mode 100644 lib/lib_i2c/Sensirion_Core/tests/syntax_check.sh create mode 100644 lib/lib_i2c/Sensirion_I2C_SEN5X/CHANGELOG.md create mode 100644 lib/lib_i2c/Sensirion_I2C_SEN5X/LICENSE create mode 100644 lib/lib_i2c/Sensirion_I2C_SEN5X/README.md create mode 100644 lib/lib_i2c/Sensirion_I2C_SEN5X/examples/exampleUsage/exampleUsage.ino create mode 100644 lib/lib_i2c/Sensirion_I2C_SEN5X/images/SEN5X_pinout.png create mode 100644 lib/lib_i2c/Sensirion_I2C_SEN5X/images/SEN5x.png create mode 100644 lib/lib_i2c/Sensirion_I2C_SEN5X/keywords.txt create mode 100644 lib/lib_i2c/Sensirion_I2C_SEN5X/library.properties create mode 100644 lib/lib_i2c/Sensirion_I2C_SEN5X/src/SensirionI2CSen5x.cpp create mode 100644 lib/lib_i2c/Sensirion_I2C_SEN5X/src/SensirionI2CSen5x.h create mode 100644 tasmota/tasmota_xsns_sensor/xsns_103_sen5x.ino diff --git a/BUILDS.md b/BUILDS.md index 12802b096..e5dadfaa6 100644 --- a/BUILDS.md +++ b/BUILDS.md @@ -118,6 +118,7 @@ Note: `minimal` variant is not listed as it shouldn't be used outside of the [up | USE_MGS | - | - / x | - | x | - | - | | USE_SGP30 | - | - / x | - | x | - | - | | USE_SGP40 | - | - / x | - | x | - | - | +| USE_SEN5X | - | - / x | - | x | - | - | | USE_SI1145 | - | - / - | - | - | - | - | | USE_LM75AD | - | - / x | - | x | - | - | | USE_APDS9960 | - | - / - | - | - | - | - | diff --git a/CODE_OWNERS.md b/CODE_OWNERS.md index 37851c86d..9e5b35411 100644 --- a/CODE_OWNERS.md +++ b/CODE_OWNERS.md @@ -198,6 +198,7 @@ In addition to @arendst the following code is mainly owned by: | xsns_100_ina3221 | @barbudor | xsns_101_hmc5883l | Andreas Achtzehn | xsns_102_ld2410 | @arendst +| xsns_103_sen5x | @tyeth | | | Libraries | | | diff --git a/I2CDEVICES.md b/I2CDEVICES.md index 171b04fd7..28818c562 100644 --- a/I2CDEVICES.md +++ b/I2CDEVICES.md @@ -111,3 +111,4 @@ Index | Define | Driver | Device | Address(es) | Description 73 | USE_HMC5883L | xsns_101 | HMC5883L | 0x1E | 3-channels Magnetic Field Sensor 74 | USE_DISPLAY_TM1650 | xdsp_20 | TM1650 | 0x24 - 0x27, 0x34 - 0x37 | Four-digit seven-segment LED controller 75 | USE_PCA9632 | xdrv_64 | PCA9632 | 0x60 | 4-channel 4-bit pwm driver + 76 | USE_SEN5X | xsns_103 | SEN5X | 0x69 | Gas (VOC/NOx index) and air quality (PPM <1,<2.5,<4,<10) diff --git a/lib/lib_i2c/Sensirion_Core/.clang-format b/lib/lib_i2c/Sensirion_Core/.clang-format new file mode 100644 index 000000000..047f2adf1 --- /dev/null +++ b/lib/lib_i2c/Sensirion_Core/.clang-format @@ -0,0 +1,14 @@ +--- +Language: Cpp +BasedOnStyle: LLVM +IndentWidth: 4 +AlignAfterOpenBracket: Align +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: false +IndentCaseLabels: true +SpacesBeforeTrailingComments: 2 +PointerAlignment: Left +AlignEscapedNewlines: Left +ForEachMacros: ['TEST_GROUP', 'TEST'] +... diff --git a/lib/lib_i2c/Sensirion_Core/CHANGELOG.rst b/lib/lib_i2c/Sensirion_Core/CHANGELOG.rst new file mode 100644 index 000000000..8d7aa66ff --- /dev/null +++ b/lib/lib_i2c/Sensirion_Core/CHANGELOG.rst @@ -0,0 +1,161 @@ +Changelog +========= + +All notable changes to this project will be documented in this file. + +The format is based on `Keep a Changelog `_ +and this project adheres to `Semantic Versioning `_. + +`Unreleased`_ +------------- + + +`0.6.0`_ 2022-06-22 +------------------- + +- Fix compiler warnings in SensirionErrors.cpp +- Allow drivers to choose CRC function + +`0.5.3`_ 2021-10-19 +------------------- + +- Add support for sensor specific errors +- Update keywords.txt + + +`0.5.2`_ 2021-08-03 +------------------- + +Fixed +..... + +- Fix CRC insertion in ``SensirionI2CTxFrame`` when more then one parameter + is sent to the sensor. + +`0.5.1`_ 2021-07-08 +------------------- + +Changed +....... + +- Adjusted deprecation warnings + +`0.5.0`_ 2021-07-07 +------------------- + +Added +..... + +- Enable SensirionTxFrame to incorporate Uint8 and Uint16 commands + + +`0.4.3`_ 2021-02-12 +------------------- + +Added +..... + +- Added ``const`` modifier to functions which process MOSI array data. + +`0.4.2`_ 2021-01-29 +------------------- + +Changed +....... + +- Renamed the library header from ``SensirionCoreArduinoLibrary.h`` to ``SensirionCore.h``. + We keep the old header for legacy support. + +`0.4.1`_ 2021-01-28 +------------------- + +Fixed +..... + +- Properly handle I2C write errors + + +`0.4.0`_ 2021-01-20 +------------------- + +Added +..... + +- Documentation for all functions. + +Breaking +........ + +- Change interface of ``errorToString()`` function to include length of the + provided buffer. + +Removed +....... + +- Removed ``reset()`` function from ``SensirionI2CTxFrame`` since the + functionality is not needed. + + +`0.3.0`_ 2021-01-13 +------------------- + +Added +..... + +- Core implementation for I2C communication. This includes a RX and TX frame + and a I2C communication class. + +Changed +....... + +- SHDLC and I2C RX frame inherit from a RX frame base class. +- ESP8266 test board from esp8266:esp8266:arduino to esp8266:esp8266:generic. +- Sorted errors into general, SHDLC and I2C errors. +- Replace C style casts with ``static_cast``. + + +`0.2.0`_ 2021-01-11 +------------------- + +Added +..... + +- Explanation what SHDLC is in README. +- ``SensirionErrors.h`` to ``SensirionCoreArduinoLibrary.h``. +- ``sendAndReceiveFrame()`` function to ``SensirionShdlcCommunication``. This + function combines ``sendFrame()`` and ``receiveFrame()`` into one function and + adds additional error checking. + +Changed +....... + +- Rename DeviceError to ExecutionError. +- Move check for execution error after the whole frame is read and checksum is + checked. This prevents that a wrong checksum can't be displayed as an + execution error. + +Removed +....... + +- ``reset()`` function from ``SensirionShdlcTxFrame`` and ``SensirionShdlcRxFrame``, + since one can just create a new frame object which has the same effect. + +`0.1.0`_ 2021-01-07 +------------------- + +- Initial release + + +.. _Unreleased: https://github.com/Sensirion/arduino-core/compare/0.6.0...main +.. _0.6.0: https://github.com/Sensirion/arduino-core/compare/0.6.0...0.5.3 +.. _0.5.3: https://github.com/Sensirion/arduino-core/compare/0.5.2...0.5.3 +.. _0.5.2: https://github.com/Sensirion/arduino-core/compare/0.5.1...0.5.2 +.. _0.5.1: https://github.com/Sensirion/arduino-core/compare/0.5.0...0.5.1 +.. _0.5.0: https://github.com/Sensirion/arduino-core/compare/0.4.3...0.5.0 +.. _0.4.3: https://github.com/Sensirion/arduino-core/compare/0.4.2...0.4.3 +.. _0.4.2: https://github.com/Sensirion/arduino-core/compare/0.4.1...0.4.2 +.. _0.4.1: https://github.com/Sensirion/arduino-core/compare/0.4.0...0.4.1 +.. _0.4.0: https://github.com/Sensirion/arduino-core/compare/0.3.0...0.4.0 +.. _0.3.0: https://github.com/Sensirion/arduino-core/compare/0.2.0...0.3.0 +.. _0.2.0: https://github.com/Sensirion/arduino-core/compare/0.1.0...0.2.0 +.. _0.1.0: https://github.com/Sensirion/arduino-core/releases/tag/0.1.0 diff --git a/lib/lib_i2c/Sensirion_Core/LICENSE b/lib/lib_i2c/Sensirion_Core/LICENSE new file mode 100644 index 000000000..fad1acd6e --- /dev/null +++ b/lib/lib_i2c/Sensirion_Core/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2020, Sensirion AG +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/lib/lib_i2c/Sensirion_Core/README.md b/lib/lib_i2c/Sensirion_Core/README.md new file mode 100644 index 000000000..1a8cf2c71 --- /dev/null +++ b/lib/lib_i2c/Sensirion_Core/README.md @@ -0,0 +1,139 @@ + +# Sensirion Arduino Core Library + +This library provides SHDLC and I2C protocol implementations for Sensirion +sensors. There shouldn't be a reason to use it directly, but is required by the +sensor driver libraries provided here: + +- [SCD4x](https://github.com/Sensirion/arduino-i2c-scd4x) +- [SVM40-I2C](https://github.com/Sensirion/arduino-i2c-svm40) +- [SVM40-UART](https://github.com/Sensirion/arduino-uart-svm40) +- [SFA3x-I2C](https://github.com/Sensirion/arduino-i2c-sfa3x) +- [SFA3x-UART](https://github.com/Sensirion/arduino-uart-sfa3x) + +# More Drivers + +Not looking for Arduino drivers? Check out our other drivers here: + +- [Embedded](https://github.com/Sensirion/info#repositories) +- [Python](https://github.com/Sensirion/info#python-drivers) + +# Usage + +## SHDLC + +SHDLC (Sensirion High-Level Data Link Control) is a byte-oriented master-slave +communication protocol based on [ISO +HDLC](https://en.wikipedia.org/wiki/High-Level_Data_Link_Control). It is used +to control some of Sensirion’s devices (for example mass flow controllers). The +detailed protocol documentation is not publicly available (yet). If you need +it, please contact our [customer +support](https://www.sensirion.com/en/about-us/contact/). + +This library provides the following classes for communication with Sensirion +Sensors using the SHDLC protocol. +- `SensirionShdlcTxFrame` +- `SensirionShdlcRxFrame` +- `SensirionShdlcCommunication` + +### Example Usage +First initialize an instance of `SensirionShdlcTxFrame` and +`SensirionShdlcRxFrame` with a properly sized buffer. A good worst case +estimation for the buffer size is `2 * (n+6)` where `n` is the number of bytes +you want to send. After that you can build your frame by first calling +`begin()`. Information about the correct COMMAND and ADDRESS can be found on +the data sheet of your sensor. Then you can add data to the frame by using +different add member functions. See the code below for examples. After adding +your data finish the frame by calling `finish()`. + +To send this frame to the sensor you first need to initialize the correct +Stream object (Serial,UART,...) to talk to your sensor. Don't forget to also +call the `.begin()` function with the right configuration. Then call the static +function `sendAndReceiveFrame()` from `SensirionShdlcCommunication` as shown +below. You need to replace `STREAMOBJECT` with the initialized Stream object of +your choice. Additionally you need to provide a timeout for to receive data +back, consult the data sheet of your sensor for information on the best timeout +value. + +You can decode the frame by using the different get members to convert the +received data to desired data types. + +All functions return a error code if an error occurs during execution and zero +otherwise. + +```cpp +uint8_t txBuffer[256]; +uint8_t rxBuffer[256]; + +SensirionShdlcTxFrame txFrame(txBuffer, 256); +SensirionShdlcRxFrame rxFrame(rxBuffer, 256); + +txFrame.begin(COMMAND, ADDRESS, DATALENGTH); + +txFrame.addUInt8(UINT8); +txFrame.addUInt32(UINT32); + +txFrame.finish(); + +SensirionShdlcCommunication::sendAndReceiveFrame(STREAMOBJECT, txFrame, rxFrame, TIMEOUT); + +rxFrame.getUInt16(UINT16); +rxFrame.getFloat(FLOAT); + +``` + +## I2C + +This library provides the following classes for communication with Sensirion +Sensors using the I2C protocol. +- `SensirionI2cTxFrame` +- `SensirionI2cRxFrame` +- `SensirionI2cCommunication` + +### Example Usage + +First initialize an instance of `SensirionI2CTxFrame` and `SensirionI2CRxFrame` +with a buffer sized the amount of data to read times 1.5. This is needed to +account for the CRC which is added after every second byte. After that you can +build your frame by first calling `addCommand()` to add the command at the +beginning of the frame. Information about the different COMMANDs can be found +on the data sheet of your sensor. Then you can add data to the frame by using +different add member functions. See the code below for examples. + +To send this frame to the sensor you first need to initialize a Wire object. +Don't forget to also call the `.begin()` function with the right configuration. +Then call the static function `sendFrame()` form `SensirionI2CCommunication` as +shown below. You can find the ADDRESS on the data sheet of the sensor. You also +need to replace `WIREOBJECT` with the initialized Wire object. Then wait the in +the data sheet documented `READ_DELAY` before receiving the reply from the +sensor by calling `receiveFrame()` with the same Wire object. + +You then can decode the frame by using the different get members to convert the +received data to desired data types. + +All functions return a error code if an error occurs during execution and zero +otherwise. + +```cpp +uint8_t txBuffer[256]; +uint8_t rxBuffer[256]; + +SensirionShdlcTxFrame txFrame(txBuffer, 256); +SensirionShdlcRxFrame rxFrame(rxBuffer, 256); + +txFrame.addCommand(COMMAND); + +txFrame.addUInt8(UINT8); +txFrame.addUInt32(UINT32); + +SensirionShdlcCommunication::sendFrame(ADDRESS, txFrame, WIREOBJECT); + +delay(READ_DELAY); + +SensirionShdlcCommunication::receiveFrame(ADDRESS, rxFrame, WIREOBJECT); + +rxFrame.getUInt16(UINT16); +rxFrame.getFloat(FLOAT); + +``` diff --git a/lib/lib_i2c/Sensirion_Core/examples/AllCommandsI2c/AllCommandsI2c.ino b/lib/lib_i2c/Sensirion_Core/examples/AllCommandsI2c/AllCommandsI2c.ino new file mode 100644 index 000000000..49b10d868 --- /dev/null +++ b/lib/lib_i2c/Sensirion_Core/examples/AllCommandsI2c/AllCommandsI2c.ino @@ -0,0 +1,62 @@ +#include +#include +#include + +uint8_t txBuffer[256]; +uint8_t rxBuffer[256]; + +SensirionI2CTxFrame txFrame(txBuffer, 256); +SensirionI2CRxFrame rxFrame(rxBuffer, 256); + +void setup() { + Wire.begin(); +} + +void loop() { + uint16_t mockCommand = 42; + uint16_t error = txFrame.addCommand(mockCommand); + + uint32_t mockUInt32 = 42; + error |= txFrame.addUInt32(mockUInt32); + + int32_t mockInt32 = 42; + error |= txFrame.addInt32(mockInt32); + + uint16_t mockUInt16 = 42; + error |= txFrame.addUInt16(mockUInt16); + + int16_t mockInt16 = 42; + error |= txFrame.addInt16(mockInt16); + + uint8_t mockUInt8 = 42; + error |= txFrame.addUInt8(mockUInt8); + + int8_t mockInt8 = 42; + error |= txFrame.addInt8(mockInt8); + + float mockFloat = 42.0f; + error |= txFrame.addFloat(mockFloat); + + bool mockBool = true; + error |= txFrame.addBool(mockBool); + + uint8_t mockBytes[] = {42, 42, 42, 42}; + error |= txFrame.addBytes(mockBytes, 4); + + uint8_t mockAddress = 42; + + error |= SensirionI2CCommunication::sendFrame(mockAddress, txFrame, Wire); + + size_t mockNumBytes = 42; + error |= SensirionI2CCommunication::receiveFrame(mockAddress, mockNumBytes, + rxFrame, Wire); + + error |= rxFrame.getUInt32(mockUInt32); + error |= rxFrame.getInt32(mockInt32); + error |= rxFrame.getUInt16(mockUInt16); + error |= rxFrame.getInt16(mockInt16); + error |= rxFrame.getUInt8(mockUInt8); + error |= rxFrame.getInt8(mockInt8); + error |= rxFrame.getFloat(mockFloat); + error |= rxFrame.getBytes(mockBytes, 4); +} diff --git a/lib/lib_i2c/Sensirion_Core/examples/AllCommandsShdlc/AllCommandsShdlc.ino b/lib/lib_i2c/Sensirion_Core/examples/AllCommandsShdlc/AllCommandsShdlc.ino new file mode 100644 index 000000000..2ff07bb94 --- /dev/null +++ b/lib/lib_i2c/Sensirion_Core/examples/AllCommandsShdlc/AllCommandsShdlc.ino @@ -0,0 +1,73 @@ +#include +#include + +uint8_t txBuffer[256]; +uint8_t rxBuffer[256]; + +SensirionShdlcTxFrame txFrame(txBuffer, 256); +SensirionShdlcRxFrame rxFrame(rxBuffer, 256); + +void setup() { + Serial.begin(115200); +} + +void loop() { + uint8_t mockCommand = 42; + uint8_t mockAddress = 42; + uint8_t mockDataLength = 42; + uint16_t error = txFrame.begin(mockCommand, mockAddress, mockDataLength); + + uint32_t mockUInt32 = 42; + error |= txFrame.addUInt32(mockUInt32); + + int32_t mockInt32 = 42; + error |= txFrame.addInt32(mockInt32); + + uint16_t mockUInt16 = 42; + error |= txFrame.addUInt16(mockUInt16); + + int16_t mockInt16 = 42; + error |= txFrame.addInt16(mockInt16); + + uint8_t mockUInt8 = 42; + error |= txFrame.addUInt8(mockUInt8); + + int8_t mockInt8 = 42; + error |= txFrame.addInt8(mockInt8); + + float mockFloat = 42.0f; + error |= txFrame.addFloat(mockFloat); + + bool mockBool = true; + error |= txFrame.addBool(mockBool); + + uint8_t mockBytes[] = {42, 42, 42, 42}; + error |= txFrame.addBytes(mockBytes, 4); + + error |= txFrame.finish(); + + error |= SensirionShdlcCommunication::sendFrame(txFrame, Serial); + + error |= SensirionShdlcCommunication::sendAndReceiveFrame( + Serial, txFrame, rxFrame, 10000000); + + error |= + SensirionShdlcCommunication::receiveFrame(rxFrame, Serial, 1000000); + + error |= rxFrame.getUInt32(mockUInt32); + error |= rxFrame.getInt32(mockInt32); + error |= rxFrame.getUInt16(mockUInt16); + error |= rxFrame.getInt16(mockInt16); + error |= rxFrame.getUInt8(mockUInt8); + error |= rxFrame.getInt8(mockInt8); + error |= rxFrame.getFloat(mockFloat); + error |= rxFrame.getBytes(mockBytes, 4); + + mockCommand = rxFrame.getCommand(); + mockAddress = rxFrame.getAddress(); + mockDataLength = rxFrame.getDataLength(); + uint8_t mockState = rxFrame.getState(); + if (mockState) { + // There is an error in the device. + } +} diff --git a/lib/lib_i2c/Sensirion_Core/keywords.txt b/lib/lib_i2c/Sensirion_Core/keywords.txt new file mode 100644 index 000000000..910b12264 --- /dev/null +++ b/lib/lib_i2c/Sensirion_Core/keywords.txt @@ -0,0 +1,56 @@ +####################################### +# Syntax Coloring Map +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### +SensirionShdlcCommunication KEYWORD1 +SensirionShdlcRxFrame KEYWORD1 +SensirionShdlcTxFrame KEYWORD1 +SensirionI2CTxFrame KEYWORD1 +SensirionI2CRxFrame KEYWORD1 +SensirionI2CCommunication KEYWORD1 + +# SensirionErrors.h +HighLevelError KEYWORD1 +LowLevelError KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### +sendFrame KEYWORD2 +receiveFrame KEYWORD2 +sendAndReceiveFrame KEYWORD2 +addUInt32 KEYWORD2 +addInt32 KEYWORD2 +addUInt16 KEYWORD2 +addInt16 KEYWORD2 +addUInt8 KEYWORD2 +addInt8 KEYWORD2 +addFloat KEYWORD2 +addBytes KEYWORD2 +addBool KEYWORD2 +addCommand KEYWORD2 +begin KEYWORD2 +finish KEYWORD2 +reset KEYWORD2 +getUInt32 KEYWORD2 +getInt32 KEYWORD2 +getUInt16 KEYWORD2 +getInt16 KEYWORD2 +getUInt8 KEYWORD2 +getInt8 KEYWORD2 +getFloat KEYWORD2 +getBytes KEYWORD2 +getCommand KEYWORD2 +getAddress KEYWORD2 +getDataLength KEYWORD2 +getState KEYWORD2 + +# SensirionErrors.h +errorToString KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/lib/lib_i2c/Sensirion_Core/library.properties b/lib/lib_i2c/Sensirion_Core/library.properties new file mode 100644 index 000000000..9c5934fa1 --- /dev/null +++ b/lib/lib_i2c/Sensirion_Core/library.properties @@ -0,0 +1,9 @@ +name=Sensirion Core +version=0.6.0 +author=Sensirion +maintainer=Sensirion +sentence=Library containing code base for Sensirion Sensor Libraries. +paragraph=All Libraries for Sensirion Sensors use this library as a code base. In this library the Sensirion specific parts for I2C and UART communication are implemented. It provides dynamic frame construction, checksum calculation and buffer handling. +category=Communication +url=https://github.com/Sensirion/arduino-core/ +includes=SensirionCore.h diff --git a/lib/lib_i2c/Sensirion_Core/src/SensirionCore.h b/lib/lib_i2c/Sensirion_Core/src/SensirionCore.h new file mode 100644 index 000000000..9222b61dd --- /dev/null +++ b/lib/lib_i2c/Sensirion_Core/src/SensirionCore.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2021, Sensirion AG + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of Sensirion AG nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _SENSIRION_CORE_H_ +#define _SENSIRION_CORE_H_ + +#include "SensirionCrc.h" +#include "SensirionErrors.h" +#include "SensirionRxFrame.h" + +#include "SensirionShdlcCommunication.h" +#include "SensirionShdlcRxFrame.h" +#include "SensirionShdlcTxFrame.h" + +#include "SensirionI2CCommunication.h" +#include "SensirionI2CRxFrame.h" +#include "SensirionI2CTxFrame.h" + +#endif /* _SENSIRION_CORE_H_ */ diff --git a/lib/lib_i2c/Sensirion_Core/src/SensirionCoreArduinoLibrary.h b/lib/lib_i2c/Sensirion_Core/src/SensirionCoreArduinoLibrary.h new file mode 100644 index 000000000..fcfeb6dca --- /dev/null +++ b/lib/lib_i2c/Sensirion_Core/src/SensirionCoreArduinoLibrary.h @@ -0,0 +1,51 @@ +/* + * + * THIS IS A LEGACY FILE AND WILL BE REMOVED SOON. + * + * Copyright (c) 2020, Sensirion AG + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of Sensirion AG nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _SENSIRION_CORE_ARDUINO_LIBRARY_H_ +#define _SENSIRION_CORE_ARDUINO_LIBRARY_H_ + +#pragma GCC warning \ + "Legacy file SensirionCoreArdunioLibrary.h included. Please include SensirionCore.h instead." + +#include "SensirionErrors.h" +#include "SensirionRxFrame.h" + +#include "SensirionShdlcCommunication.h" +#include "SensirionShdlcRxFrame.h" +#include "SensirionShdlcTxFrame.h" + +#include "SensirionI2CCommunication.h" +#include "SensirionI2CRxFrame.h" +#include "SensirionI2CTxFrame.h" + +#endif /* _SENSIRION_CORE_ARDUION_LIBRARY_H_ */ diff --git a/lib/lib_i2c/Sensirion_Core/src/SensirionCrc.cpp b/lib/lib_i2c/Sensirion_Core/src/SensirionCrc.cpp new file mode 100644 index 000000000..25b8234aa --- /dev/null +++ b/lib/lib_i2c/Sensirion_Core/src/SensirionCrc.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2022, Sensirion AG + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of Sensirion AG nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "SensirionCrc.h" + +uint8_t generateCRCGeneric(const uint8_t* data, size_t count, uint8_t init, + uint8_t polynomial) { + uint8_t crc = init; + + /* calculates 8-Bit checksum with given polynomial */ + for (size_t current_byte = 0; current_byte < count; ++current_byte) { + crc ^= (data[current_byte]); + for (uint8_t crc_bit = 8; crc_bit > 0; --crc_bit) { + if (crc & 0x80) + crc = (crc << 1) ^ polynomial; + else + crc = (crc << 1); + } + } + return crc; +} + +uint8_t generateCRC31_ff(const uint8_t* data, size_t count) { + return generateCRCGeneric(data, count, 0xff, 0x31); +} + +uint8_t generateCRC31_00(const uint8_t* data, size_t count) { + return generateCRCGeneric(data, count, 0x00, 0x31); +} + +uint8_t generateCRC(const uint8_t* data, size_t count, CrcPolynomial type) { + if (CRC31_00 == type) { + return generateCRC31_00(data, count); + } + return generateCRC31_ff(data, count); +} diff --git a/lib/lib_i2c/Sensirion_Core/src/SensirionCrc.h b/lib/lib_i2c/Sensirion_Core/src/SensirionCrc.h new file mode 100644 index 000000000..904fc9286 --- /dev/null +++ b/lib/lib_i2c/Sensirion_Core/src/SensirionCrc.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2022, Sensirion AG + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of Sensirion AG nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _SENSIRION_CRC_H_ +#define _SENSIRION_CRC_H_ + +#include +#include + +enum CrcPolynomial : uint8_t { + CRC31_00 = 0x0, + CRC31_ff = 0x1, +}; + +uint8_t generateCRCGeneric(const uint8_t* data, size_t count, uint8_t init, + uint8_t polynomial); + +uint8_t generateCRC31_ff(const uint8_t* data, size_t count); + +uint8_t generateCRC31_00(const uint8_t* data, size_t count); + +/** + * @brief Generate a crc for data given a polynomial type + * + * @param data data to calculate CRC for + * @param count the array size of data + * @param poly CRC polynomal to use + */ +uint8_t generateCRC(const uint8_t* data, size_t count, CrcPolynomial type); + +#endif /* _SENSIRION_CRC_H_ */ diff --git a/lib/lib_i2c/Sensirion_Core/src/SensirionErrors.cpp b/lib/lib_i2c/Sensirion_Core/src/SensirionErrors.cpp new file mode 100644 index 000000000..b0d7ffe62 --- /dev/null +++ b/lib/lib_i2c/Sensirion_Core/src/SensirionErrors.cpp @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2020, Sensirion AG + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of Sensirion AG nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "SensirionErrors.h" + +#include +#include +#include + +void errorToString(uint16_t error, char errorMessage[], + size_t errorMessageSize) { + + uint16_t highLevelError = error & 0xFF00; + uint16_t lowLevelError = error & 0x00FF; + + if (error & HighLevelError::SensorSpecificError) { + snprintf(errorMessage, errorMessageSize, "Sensor specific error: 0x%2x", + lowLevelError); + return; + } + + switch (highLevelError) { + case HighLevelError::NoError: + if (!error) { + strncpy(errorMessage, "No error", errorMessageSize); + return; + } + break; + case HighLevelError::WriteError: + switch (lowLevelError) { + case LowLevelError::SerialWriteError: + strncpy(errorMessage, "Error writing to serial", + errorMessageSize); + return; + case LowLevelError::InternalBufferSizeError: + strncpy(errorMessage, + "Data too long to fit in transmit buffer", + errorMessageSize); + return; + case LowLevelError::I2cAddressNack: + strncpy(errorMessage, + "Received NACK on transmit of address", + errorMessageSize); + return; + case LowLevelError::I2cDataNack: + strncpy(errorMessage, "Received NACK on transmit of data", + errorMessageSize); + return; + case LowLevelError::I2cOtherError: + strncpy(errorMessage, "Error writing to I2C bus", + errorMessageSize); + return; + } + break; + case HighLevelError::ReadError: + switch (lowLevelError) { + case LowLevelError::NonemptyFrameError: + strncpy(errorMessage, "Frame already contains data", + errorMessageSize); + return; + case LowLevelError::TimeoutError: + strncpy(errorMessage, "Timeout while reading data", + errorMessageSize); + return; + case LowLevelError::ChecksumError: + strncpy(errorMessage, "Checksum is wrong", + errorMessageSize); + return; + case LowLevelError::CRCError: + strncpy(errorMessage, "Wrong CRC found", errorMessageSize); + return; + case LowLevelError::WrongNumberBytesError: + strncpy(errorMessage, "Number of bytes not a multiple of 3", + errorMessageSize); + return; + case LowLevelError::NotEnoughDataError: + strncpy(errorMessage, "Not enough data received", + errorMessageSize); + return; + case LowLevelError::InternalBufferSizeError: + strncpy(errorMessage, "Internal I2C buffer too small", + errorMessageSize); + return; + } + break; + case HighLevelError::ExecutionError: { + char format[] = "Execution error, status register: 0x%x"; + snprintf(errorMessage, errorMessageSize, format, lowLevelError); + return; + } + case HighLevelError::TxFrameError: + switch (lowLevelError) { + case LowLevelError::BufferSizeError: + strncpy(errorMessage, "Not enough space in buffer", + errorMessageSize); + return; + } + break; + case HighLevelError::RxFrameError: + switch (lowLevelError) { + case LowLevelError::BufferSizeError: + strncpy(errorMessage, "Not enough space in buffer", + errorMessageSize); + return; + case LowLevelError::NoDataError: + strncpy(errorMessage, "No more data in frame", + errorMessageSize); + return; + case LowLevelError::RxAddressError: + strncpy(errorMessage, "Wrong address in return frame", + errorMessageSize); + return; + case LowLevelError::RxCommandError: + strncpy(errorMessage, "Wrong command in return frame", + errorMessageSize); + return; + } + } + strncpy(errorMessage, "Error processing error", errorMessageSize); + return; +} diff --git a/lib/lib_i2c/Sensirion_Core/src/SensirionErrors.h b/lib/lib_i2c/Sensirion_Core/src/SensirionErrors.h new file mode 100644 index 000000000..268d9754f --- /dev/null +++ b/lib/lib_i2c/Sensirion_Core/src/SensirionErrors.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2020, Sensirion AG + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of Sensirion AG nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _SENSIRION_ERRORS_H_ +#define _SENSIRION_ERRORS_H_ + +#include +#include + +enum HighLevelError : uint16_t { + // general errors + NoError = 0, + WriteError = 0x0100, + ReadError = 0x0200, + TxFrameError = 0x0300, + RxFrameError = 0x0400, + // shdlc errors + ExecutionError = 0x0500, + // i2c errors + + // Sensor specific errors. All errors higher than that are depending on the + // sensor used. + SensorSpecificError = 0x8000, +}; + +enum LowLevelError : uint16_t { + // general errors + NonemptyFrameError, + NoDataError, + BufferSizeError, + // shdlc errors + StopByteError, + ChecksumError, + TimeoutError, + RxCommandError, + RxAddressError, + SerialWriteError, + // i2c errors + WrongNumberBytesError, + CRCError, + I2cAddressNack, + I2cDataNack, + I2cOtherError, + NotEnoughDataError, + InternalBufferSizeError, +}; + +/** + * errorToString() - Convert error code to a human readable error message + * + * @param error Error code to be converted. + * @param errorMessage String where the error text can be + * stored. + * @param errorMessageSize Size in bytes of the string buffer for the error + * message. + */ +void errorToString(uint16_t error, char errorMessage[], + size_t errorMessageSize); + +#endif /* _SENSIRION_ERRORS_H_ */ diff --git a/lib/lib_i2c/Sensirion_Core/src/SensirionI2CCommunication.cpp b/lib/lib_i2c/Sensirion_Core/src/SensirionI2CCommunication.cpp new file mode 100644 index 000000000..2d8b7acab --- /dev/null +++ b/lib/lib_i2c/Sensirion_Core/src/SensirionI2CCommunication.cpp @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2020, Sensirion AG + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of Sensirion AG nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "SensirionI2CCommunication.h" + +#include +#include + +#include "Arduino.h" +#include "SensirionCrc.h" +#include "SensirionErrors.h" +#include "SensirionI2CRxFrame.h" +#include "SensirionI2CTxFrame.h" + +static void clearRxBuffer(TwoWire& i2cBus) { + while (i2cBus.available()) { + (void)i2cBus.read(); + } +} + +uint16_t SensirionI2CCommunication::sendFrame(uint8_t address, + SensirionI2CTxFrame& frame, + TwoWire& i2cBus) { + i2cBus.beginTransmission(address); + size_t writtenBytes = i2cBus.write(frame._buffer, frame._index); + uint8_t i2c_error = i2cBus.endTransmission(); + if (writtenBytes != frame._index) { + return WriteError | I2cOtherError; + } + // translate Arduino errors, see + // https://www.arduino.cc/en/Reference/WireEndTransmission + switch (i2c_error) { + case 0: + return NoError; + case 1: + return WriteError | InternalBufferSizeError; + case 2: + return WriteError | I2cAddressNack; + case 3: + return WriteError | I2cDataNack; + default: + return WriteError | I2cOtherError; + } +} + +uint16_t SensirionI2CCommunication::receiveFrame(uint8_t address, + size_t numBytes, + SensirionI2CRxFrame& frame, + TwoWire& i2cBus, + CrcPolynomial poly) { + size_t readAmount; + size_t i = 0; + +#ifdef I2C_BUFFER_LENGTH + const uint8_t sizeBuffer = + (static_cast(I2C_BUFFER_LENGTH) / static_cast(3)) * 3; +#elif defined(BUFFER_LENGTH) + const uint8_t sizeBuffer = + (static_cast(BUFFER_LENGTH) / static_cast(3)) * 3; +#else + const uint8_t sizeBuffer = 30; +#endif + + if (numBytes % 3) { + return ReadError | WrongNumberBytesError; + } + if ((numBytes / 3) * 2 > frame._bufferSize) { + return ReadError | BufferSizeError; + } + if (numBytes > sizeBuffer) { + return ReadError | InternalBufferSizeError; + } + + readAmount = i2cBus.requestFrom(address, static_cast(numBytes), + static_cast(true)); + if (numBytes != readAmount) { + return ReadError | NotEnoughDataError; + } + do { + frame._buffer[i++] = i2cBus.read(); + frame._buffer[i++] = i2cBus.read(); + uint8_t actualCRC = i2cBus.read(); + uint8_t expectedCRC = generateCRC(&frame._buffer[i - 2], 2, poly); + if (actualCRC != expectedCRC) { + clearRxBuffer(i2cBus); + return ReadError | CRCError; + } + readAmount -= 3; + } while (readAmount > 0); + frame._numBytes = i; + return NoError; +} diff --git a/lib/lib_i2c/Sensirion_Core/src/SensirionI2CCommunication.h b/lib/lib_i2c/Sensirion_Core/src/SensirionI2CCommunication.h new file mode 100644 index 000000000..98aead75a --- /dev/null +++ b/lib/lib_i2c/Sensirion_Core/src/SensirionI2CCommunication.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2020, Sensirion AG + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of Sensirion AG nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef SENSIRION_I2C_COMMUNICATION_H_ +#define SENSIRION_I2C_COMMUNICATION_H_ + +#include +#include + +#include "Arduino.h" +#include "Wire.h" + +#include "SensirionI2CRxFrame.h" +#include "SensirionI2CTxFrame.h" + +class SensirionI2CTxFrame; +class SensirionI2CRxFrame; + +/* + * SensirionI2CCommunication - Class which is responsible for the communication + * via a I2C bus. It provides functionality to send and receive frames from a + * Sensirion sensor. The data is sent and received in a SensirionI2cTxFrame or + * SensirionI2cRxFrame respectively. + */ +class SensirionI2CCommunication { + public: + /** + * sendFrame() - Sends frame to sensor + * + * @param address I2C address of the sensor. + * @param frame Tx frame object containing a finished frame to send to + * the sensor. + * @param i2cBus TwoWire object to communicate with the sensor. + * + * @return NoError on success, an error code otherwise + */ + static uint16_t sendFrame(uint8_t address, SensirionI2CTxFrame& frame, + TwoWire& i2cBus); + + /** + * receiveFrame() - Receive Frame from sensor + * + * @param address I2C address of the sensor. + * @param numBytes Number of bytes to receive. + * @param frame Rx frame to store the received data in. + * @param i2cBus TwoWire object to communicate with the sensor. + * @param poly CRC polynomal to use. Defaults to 0x31 with init 0xFF + * + * @return NoError on success, an error code otherwise + */ + static uint16_t receiveFrame(uint8_t address, size_t numBytes, + SensirionI2CRxFrame& frame, TwoWire& i2cBus, + CrcPolynomial poly = CRC31_ff); +}; + +#endif /* SENSIRION_I2C_COMMUNICATION_H_ */ diff --git a/lib/lib_i2c/Sensirion_Core/src/SensirionI2CRxFrame.h b/lib/lib_i2c/Sensirion_Core/src/SensirionI2CRxFrame.h new file mode 100644 index 000000000..e15cfa28b --- /dev/null +++ b/lib/lib_i2c/Sensirion_Core/src/SensirionI2CRxFrame.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2020, Sensirion AG + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of Sensirion AG nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef SENSIRION_I2C_RX_FRAME_H_ +#define SENSIRION_I2C_RX_FRAME_H_ + +#include +#include + +#include "SensirionI2CCommunication.h" +#include "SensirionRxFrame.h" + +/** + * SenirionI2CRxFrame - Class which decodes the through I2C received data into + * common data types. It contains a buffer which is filled by the + * SensirionI2CCommunication class. By calling the different decode function + * inherited from the SensirionRxFrame base class the raw data can be decoded + * into different data types. + */ +class SensirionI2CRxFrame : public SensirionRxFrame { + + friend class SensirionI2CCommunication; + + public: + /** + * Constructor + * + * @param buffer Buffer in which the receive frame will be + * stored. + * @param bufferSize Number of bytes in the buffer for the receive frame. + * + */ + SensirionI2CRxFrame(uint8_t buffer[], size_t bufferSize) + : SensirionRxFrame(buffer, bufferSize){}; +}; + +#endif /* SENSIRION_I2C_RX_FRAME_H_ */ diff --git a/lib/lib_i2c/Sensirion_Core/src/SensirionI2CTxFrame.cpp b/lib/lib_i2c/Sensirion_Core/src/SensirionI2CTxFrame.cpp new file mode 100644 index 000000000..67999f86c --- /dev/null +++ b/lib/lib_i2c/Sensirion_Core/src/SensirionI2CTxFrame.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2020, Sensirion AG + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of Sensirion AG nor the names of its + * contributors may be used to endorse or promote products derived from + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "SensirionI2CTxFrame.h" + +#include +#include + +#include "SensirionCrc.h" +#include "SensirionErrors.h" + +SensirionI2CTxFrame::SensirionI2CTxFrame(uint8_t buffer[], size_t bufferSize, + size_t numCommandBytes, + CrcPolynomial poly) + : _buffer(buffer), _bufferSize(bufferSize), _index(numCommandBytes), + _numCommandBytes(numCommandBytes), _polynomial_type(poly) { +} + +SensirionI2CTxFrame::SensirionI2CTxFrame(uint8_t buffer[], size_t bufferSize, + CrcPolynomial poly) + : SensirionI2CTxFrame(buffer, bufferSize, 2, poly) { +} + +SensirionI2CTxFrame SensirionI2CTxFrame::createWithUInt8Command( + uint8_t command, uint8_t buffer[], size_t bufferSize, CrcPolynomial poly) { + SensirionI2CTxFrame instance = + SensirionI2CTxFrame(buffer, bufferSize, 1, poly); + instance._buffer[0] = command; + return instance; +} + +SensirionI2CTxFrame SensirionI2CTxFrame::createWithUInt16Command( + uint16_t command, uint8_t buffer[], size_t bufferSize, CrcPolynomial poly) { + SensirionI2CTxFrame instance = + SensirionI2CTxFrame(buffer, bufferSize, 2, poly); + instance._buffer[0] = static_cast((command & 0xFF00) >> 8); + instance._buffer[1] = static_cast((command & 0x00FF) >> 0); + return instance; +} + +uint16_t SensirionI2CTxFrame::addCommand(uint16_t command) { + if (_bufferSize < 2) { + return TxFrameError | BufferSizeError; + } + _buffer[0] = static_cast((command & 0xFF00) >> 8); + _buffer[1] = static_cast((command & 0x00FF) >> 0); + return NoError; +} + +uint16_t SensirionI2CTxFrame::addUInt32(uint32_t data) { + uint16_t error = _addByte(static_cast((data & 0xFF000000) >> 24)); + error |= _addByte(static_cast((data & 0x00FF0000) >> 16)); + error |= _addByte(static_cast((data & 0x0000FF00) >> 8)); + error |= _addByte(static_cast((data & 0x000000FF) >> 0)); + return error; +} + +uint16_t SensirionI2CTxFrame::addInt32(int32_t data) { + return addUInt32(static_cast(data)); +} + +uint16_t SensirionI2CTxFrame::addUInt16(uint16_t data) { + uint16_t error = _addByte(static_cast((data & 0xFF00) >> 8)); + error |= _addByte(static_cast((data & 0x00FF) >> 0)); + return error; +} + +uint16_t SensirionI2CTxFrame::addInt16(int16_t data) { + return addUInt16(static_cast(data)); +} + +uint16_t SensirionI2CTxFrame::addUInt8(uint8_t data) { + return _addByte(data); +} + +uint16_t SensirionI2CTxFrame::addInt8(int8_t data) { + return _addByte(static_cast(data)); +} + +uint16_t SensirionI2CTxFrame::addBool(bool data) { + return _addByte(static_cast(data)); +} + +uint16_t SensirionI2CTxFrame::addFloat(float data) { + union { + uint32_t uInt32Data; + float floatData; + } convert; + + convert.floatData = data; + return addUInt32(convert.uInt32Data); +} + +uint16_t SensirionI2CTxFrame::addBytes(const uint8_t data[], + size_t dataLength) { + uint16_t error = 0; + for (size_t i = 0; i < dataLength; i++) { + error |= _addByte(data[i]); + } + return error; +} + +uint16_t SensirionI2CTxFrame::_addByte(uint8_t data) { + if (_bufferSize <= _index) { + return TxFrameError | BufferSizeError; + } + _buffer[_index++] = data; + if ((_index - _numCommandBytes) % 3 == 2) { + if (_bufferSize <= _index) { + return TxFrameError | BufferSizeError; + } + uint8_t crc = generateCRC(&_buffer[_index - 2], 2, _polynomial_type); + _buffer[_index++] = crc; + } + return NoError; +} diff --git a/lib/lib_i2c/Sensirion_Core/src/SensirionI2CTxFrame.h b/lib/lib_i2c/Sensirion_Core/src/SensirionI2CTxFrame.h new file mode 100644 index 000000000..3e5cee3df --- /dev/null +++ b/lib/lib_i2c/Sensirion_Core/src/SensirionI2CTxFrame.h @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2020, Sensirion AG + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of Sensirion AG nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef SENSIRION_I2C_TX_FRAME_H_ +#define SENSIRION_I2C_TX_FRAME_H_ + +#include +#include + +#include "SensirionCrc.h" +#include "SensirionI2CCommunication.h" + +/* + * SensirionI2CTxFrame - Class which helps to build a correct I2C frame for + * Sensirion Sensors. The different addDatatype() functions add the frame data + * and the addCommand() function writes the command at the beginning. Using + * these functions one can easily construct a I2C frame for Sensirion sensors. + */ +class SensirionI2CTxFrame { + + friend class SensirionI2CCommunication; + + public: + /** + * Factory to create a SensirionI2CTxFrame using a UInt8 command. + * + * @param command Command to add to the send frame. + * @param buffer Buffer in which the send frame will be stored. + * @param bufferSize Number of bytes in the buffer for the send frame. + * @param poly CRC polynomal to use. Defaults to 0x31 with init 0xFF + * + * @return the constructed SensirionI2CTxFrame. + */ + static SensirionI2CTxFrame + createWithUInt8Command(uint8_t command, uint8_t buffer[], size_t bufferSize, + CrcPolynomial poly = CRC31_ff); + + /** + * Factory to create a SensirionI2CTxFrame using a UInt16 command. + * + * @param command Command to add to the send frame. + * @param buffer Buffer in which the send frame will be stored. + * @param bufferSize Number of bytes in the buffer for the send frame. + * @param poly CRC polynomal to use. Defaults to 0x31 with init 0xFF + * + * @return the constructed SensirionI2CTxFrame. + */ + static SensirionI2CTxFrame + createWithUInt16Command(uint16_t command, uint8_t buffer[], + size_t bufferSize, CrcPolynomial poly = CRC31_ff); + + /** + * Constructor + * + * @param buffer Buffer in which the send frame will be stored. + * @param bufferSize Number of bytes in the buffer for the send frame. + * @param poly CRC polynomal to use. Defaults to 0x31 with init 0xFF + * + * @deprecated Use createWithUInt16Command() instead + */ + SensirionI2CTxFrame(uint8_t buffer[], size_t bufferSize, + CrcPolynomial poly = CRC31_ff); + + /** + * addCommand() - Add command to the send frame. + * + * @param command Command to add to the send frame. + * + * @return NoError on success, an error code otherwise + * + * @deprecated Use createWithUInt16Command() instead + */ + uint16_t addCommand(uint16_t command); + + /** + * addUInt32() - Add unsigned 32bit integer to the send frame. + * + * @param data Unsigned 32bit integer to add to the send frame. + * + * @return NoError on success, an error code otherwise + */ + uint16_t addUInt32(uint32_t data); + + /** + * addInt32() - Add signed 32bit integer to the send frame. + * + * @param data Signed 32bit integer to add to the send frame. + * + * @return NoError on success, an error code otherwise + */ + uint16_t addInt32(int32_t data); + + /** + * addUInt16() - Add unsigned 16bit integer to the send frame. + * + * @param data Unsigned 16bit integer to add to the send frame. + * + * @return NoError on success, an error code otherwise + */ + uint16_t addUInt16(uint16_t data); + + /** + * addInt16() - Add signed 16bit integer to the send frame. + * + * @param data Signed 16bit integer to add to the send frame. + * + * @return NoError on success, an error code otherwise + */ + uint16_t addInt16(int16_t data); + + /** + * addUInt8() - Add unsigned 8bit integer to the send frame. + * + * @param data Unsigned 8bit integer to add to the send frame. + * + * @return NoError on success, an error code otherwise + */ + uint16_t addUInt8(uint8_t data); + + /** + * addInt8() - Add signed 8bit integer to the send frame. + * + * @param data Signed 8bit integer to add to the send frame. + * + * @return NoError on success, an error code otherwise + */ + uint16_t addInt8(int8_t data); + + /** + * addBool() - Add boolean to the send frame. + * + * @param data Boolean to add to the send frame. + * + * @return NoError on success, an error code otherwise + */ + uint16_t addBool(bool data); + + /** + * addFloat() - Add float to the send frame. + * + * @param data Float to add to the send frame. + * + * @return NoError on success, an error code otherwise + */ + uint16_t addFloat(float data); + + /** + * addBytes() - Add byte array to the send frame. + * + * @param data Byte array to add to the send frame. + * @param dataLength Number of bytes to add to the send frame. + * + * @return NoError on success, an error code otherwise + */ + uint16_t addBytes(const uint8_t data[], size_t dataLength); + + private: + SensirionI2CTxFrame(uint8_t buffer[], size_t bufferSize, + size_t numCommandBytes, CrcPolynomial poly = CRC31_ff); + + uint16_t _addByte(uint8_t data); + + uint8_t* _buffer; + size_t _bufferSize; + size_t _index; + size_t _numCommandBytes; + CrcPolynomial _polynomial_type; +}; + +#endif /* SENSIRION_I2C_TX_FRAME_H_ */ diff --git a/lib/lib_i2c/Sensirion_Core/src/SensirionRxFrame.cpp b/lib/lib_i2c/Sensirion_Core/src/SensirionRxFrame.cpp new file mode 100644 index 000000000..c653c250d --- /dev/null +++ b/lib/lib_i2c/Sensirion_Core/src/SensirionRxFrame.cpp @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2020, Sensirion AG + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of Sensirion AG nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "SensirionRxFrame.h" + +#include +#include + +#include "SensirionErrors.h" + +SensirionRxFrame::SensirionRxFrame(uint8_t buffer[], size_t bufferSize) + : _buffer(buffer), _bufferSize(bufferSize), _index(0), _numBytes(0) { +} + +uint16_t SensirionRxFrame::getUInt32(uint32_t& data) { + if (_numBytes < 4) { + return RxFrameError | NoDataError; + } + data = static_cast(_buffer[_index++]) << 24; + data |= static_cast(_buffer[_index++]) << 16; + data |= static_cast(_buffer[_index++]) << 8; + data |= static_cast(_buffer[_index++]); + _numBytes -= 4; + return NoError; +} + +uint16_t SensirionRxFrame::getInt32(int32_t& data) { + uint32_t ret; + uint16_t error = getUInt32(ret); + data = static_cast(ret); + return error; +} + +uint16_t SensirionRxFrame::getUInt16(uint16_t& data) { + if (_numBytes < 2) { + return RxFrameError | NoDataError; + } + data = static_cast(_buffer[_index++]) << 8; + data |= static_cast(_buffer[_index++]); + _numBytes -= 2; + return NoError; +} + +uint16_t SensirionRxFrame::getInt16(int16_t& data) { + uint16_t ret; + uint16_t error = getUInt16(ret); + data = static_cast(ret); + return error; +} + +uint16_t SensirionRxFrame::getUInt8(uint8_t& data) { + if (_numBytes < 1) { + return RxFrameError | NoDataError; + } + data = _buffer[_index++]; + _numBytes -= 1; + return NoError; +} + +uint16_t SensirionRxFrame::getInt8(int8_t& data) { + if (_numBytes < 1) { + return RxFrameError | NoDataError; + } + data = static_cast(_buffer[_index++]); + _numBytes -= 1; + return NoError; +} + +uint16_t SensirionRxFrame::getBool(bool& data) { + if (_numBytes < 1) { + return RxFrameError | NoDataError; + } + data = static_cast(_buffer[_index++]); + _numBytes -= 1; + return NoError; +} + +uint16_t SensirionRxFrame::getFloat(float& data) { + union { + uint32_t uInt32Data; + float floatData; + } convert; + uint16_t error = getUInt32(convert.uInt32Data); + data = convert.floatData; + return error; +} + +uint16_t SensirionRxFrame::getBytes(uint8_t data[], size_t maxBytes) { + if (_numBytes < 1) { + return RxFrameError | NoDataError; + } + size_t readAmount = maxBytes; + if (_numBytes < maxBytes) { + readAmount = _numBytes; + } + for (size_t i = 0; i < readAmount; i++) { + data[i] = _buffer[_index++]; + } + _numBytes -= readAmount; + return NoError; +} diff --git a/lib/lib_i2c/Sensirion_Core/src/SensirionRxFrame.h b/lib/lib_i2c/Sensirion_Core/src/SensirionRxFrame.h new file mode 100644 index 000000000..a4384fb6c --- /dev/null +++ b/lib/lib_i2c/Sensirion_Core/src/SensirionRxFrame.h @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2020, Sensirion AG + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of Sensirion AG nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef SENSIRION_RX_FRAME_H_ +#define SENSIRION_RX_FRAME_H_ + +#include +#include + +/** + * SenirionRxFrame - Base class for SensirionShdlcRxFrame and + * SensirionI2cRxFrame. It decodes received data into common data types. The + * data is contained in a buffer which is filled by the one of the two + * communication classes. By calling the different decode function the raw data + * can be decoded into different data types. + */ +class SensirionRxFrame { + + friend class SensirionI2CCommunication; + friend class SensirionShdlcCommunication; + + public: + /** + * Constructor + * + * @param buffer Buffer in which the receive frame will be stored. + * @param bufferSize Number of bytes in the buffer for the receive frame. + */ + SensirionRxFrame(uint8_t buffer[], size_t bufferSize); + + /** + * getUInt32() - Get unsigned 32bit integer from the received data. + * + * @param data Memory to store unsigned 32bit integer in. + * + * @return NoError on success, an error code otherwise + */ + uint16_t getUInt32(uint32_t& data); + + /** + * getInt32() - Get signed 32bit integer from the received data. + * + * @param data Memory to store signed 32bit integer in. + * + * @return NoError on success, an error code otherwise + */ + uint16_t getInt32(int32_t& data); + + /** + * getUInt16() - Get unsigned 16bit integer from the received data. + * + * @param data Memory to store unsigned 16bit integer in. + * + * @return NoError on success, an error code otherwise + */ + uint16_t getUInt16(uint16_t& data); + + /** + * getInt16() - Get signed 16bit integer from the received data. + * + * @param data Memory to store signed 16bit integer in. + * + * @return NoError on success, an error code otherwise + */ + uint16_t getInt16(int16_t& data); + + /** + * getUInt8() - Get unsigned 8bit integer from the received data. + * + * @param data Memory to store unsigned 8bit integer in. + * + * @return NoError on success, an error code otherwise + */ + uint16_t getUInt8(uint8_t& data); + + /** + * getInt8() - Get signed 8bit integer from the received data. + * + * @param data Memory to store signed 8bit integer in. + * + * @return NoError on success, an error code otherwise + */ + uint16_t getInt8(int8_t& data); + + /** + * getBool() - Get Boolean from the received data. + * + * @param data Memory to store boolean in. + * + * @return NoError on success, an error code otherwise + */ + uint16_t getBool(bool& data); + + /** + * getFloat() - Get float from the received data. + * + * @param data Memory to store float in. + * + * @return NoError on success, an error code otherwise + */ + uint16_t getFloat(float& data); + + /** + * getBytes() - Get an array of bytes from the received data. + * + * @param data Buffer to store the bytes in. + * @param maxBytes Maximal amount of bytes to read from the received data. + * + * @return NoError on success, an error code otherwise + */ + uint16_t getBytes(uint8_t data[], size_t maxBytes); + + private: + uint8_t* _buffer = 0; + size_t _bufferSize = 0; + size_t _index = 0; + size_t _numBytes = 0; +}; + +#endif /* SENSIRION_RX_FRAME_H_ */ diff --git a/lib/lib_i2c/Sensirion_Core/src/SensirionShdlcCommunication.cpp b/lib/lib_i2c/Sensirion_Core/src/SensirionShdlcCommunication.cpp new file mode 100644 index 000000000..300546ee8 --- /dev/null +++ b/lib/lib_i2c/Sensirion_Core/src/SensirionShdlcCommunication.cpp @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2020, Sensirion AG + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of Sensirion AG nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "SensirionShdlcCommunication.h" + +#include +#include + +#include "Arduino.h" +#include "SensirionErrors.h" +#include "SensirionShdlcRxFrame.h" +#include "SensirionShdlcTxFrame.h" + +static uint16_t readByte(uint8_t& data, Stream& serial, unsigned long startTime, + unsigned long timeoutMicros) { + do { + if (micros() - startTime > timeoutMicros) { + return ReadError | TimeoutError; + } + } while (!serial.available()); + data = serial.read(); + return NoError; +} + +static uint16_t unstuffByte(uint8_t& data, Stream& serial, + unsigned long startTime, + unsigned long timeoutMicros) { + uint16_t error = readByte(data, serial, startTime, timeoutMicros); + if (error) { + return error; + } + if (data == 0x7d) { + error = readByte(data, serial, startTime, timeoutMicros); + if (error) { + return error; + } + data = data ^ (1 << 5); + } + return NoError; +} + +uint16_t SensirionShdlcCommunication::sendFrame(SensirionShdlcTxFrame& frame, + Stream& serial) { + size_t writtenBytes = serial.write(&frame._buffer[0], frame._index); + if (writtenBytes != frame._index) { + return WriteError | SerialWriteError; + } + return NoError; +} + +uint16_t SensirionShdlcCommunication::receiveFrame( + SensirionShdlcRxFrame& frame, Stream& serial, unsigned long timeoutMicros) { + unsigned long startTime = micros(); + uint16_t error; + uint8_t dataLength; + uint8_t current = 0; + + if (frame._numBytes) { + return ReadError | NonemptyFrameError; + } + + // Wait for start byte and ignore all other bytes in case a partial frame + // is still in the receive buffer due to a previous error. + do { + error = readByte(current, serial, startTime, timeoutMicros); + if (error) { + return error; + } + } while (current != 0x7e); + + // Handle a repeated start byte which may happen + do { + error = unstuffByte(current, serial, startTime, timeoutMicros); + if (error) { + return error; + } + } while (current == 0x7e); + + frame._address = current; + error = unstuffByte(frame._command, serial, startTime, timeoutMicros); + if (error) { + return error; + } + error = unstuffByte(frame._state, serial, startTime, timeoutMicros); + if (error) { + return error; + } + error = unstuffByte(dataLength, serial, startTime, timeoutMicros); + if (error) { + return error; + } + + uint8_t checksum = + frame._address + frame._command + frame._state + dataLength; + + if (dataLength > frame._bufferSize) { + return RxFrameError | BufferSizeError; + } + + size_t i = 0; + while (i < dataLength) { + error = unstuffByte(current, serial, startTime, timeoutMicros); + if (error) { + return error; + } + frame._buffer[i] = current; + checksum += current; + i++; + } + + uint8_t expectedChecksum = ~checksum; + uint8_t actualChecksum; + error = unstuffByte(actualChecksum, serial, startTime, timeoutMicros); + if (error) { + return error; + } + if (expectedChecksum != actualChecksum) { + return ReadError | ChecksumError; + } + + uint8_t stop; + error = readByte(stop, serial, startTime, timeoutMicros); + if (error) { + return error; + } + if (stop != 0x7e) { + return ReadError | StopByteError; + } + if (frame._state & 0x7F) { + return ExecutionError | frame._state; + } + frame._dataLength = dataLength; + frame._numBytes = dataLength; + return NoError; +} + +uint16_t SensirionShdlcCommunication::sendAndReceiveFrame( + Stream& serial, SensirionShdlcTxFrame& txFrame, + SensirionShdlcRxFrame& rxFrame, unsigned long rxTimeoutMicros) { + uint16_t error; + error = SensirionShdlcCommunication::sendFrame(txFrame, serial); + if (error) { + return error; + } + error = SensirionShdlcCommunication::receiveFrame(rxFrame, serial, + rxTimeoutMicros); + if (error) { + return error; + } + if (rxFrame.getCommand() != txFrame.getCommand()) { + return RxFrameError | RxCommandError; + } + if (rxFrame.getAddress() != txFrame.getAddress()) { + return RxFrameError | RxAddressError; + } + return NoError; +} diff --git a/lib/lib_i2c/Sensirion_Core/src/SensirionShdlcCommunication.h b/lib/lib_i2c/Sensirion_Core/src/SensirionShdlcCommunication.h new file mode 100644 index 000000000..9d2dc35b1 --- /dev/null +++ b/lib/lib_i2c/Sensirion_Core/src/SensirionShdlcCommunication.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2020, Sensirion AG + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of Sensirion AG nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef SENSIRION_SHDLC_COMMUNICATION_H_ +#define SENSIRION_SHDLC_COMMUNICATION_H_ + +#include +#include + +#include "Arduino.h" + +#include "SensirionShdlcRxFrame.h" +#include "SensirionShdlcTxFrame.h" + +class SensirionShdlcTxFrame; +class SensirionShdlcRxFrame; + +/* + * SensirionShdlcCommunication - Class which is responsible for the + * communication via a UART (Serial) interface. It provides functionality to + * send and receive frames from a Sensirion sensor. The data is sent and + * received in a SensirionShdlcTxFrame or SensirionShdlcRxFrame respectively. + */ +class SensirionShdlcCommunication { + + public: + /** + * sendFrame() - Sends frame to sensor + * + * @param frame Tx frame object containing a finished frame to send to the + * sensor. + * @param serial Stream object to communicate with the sensor. + * + * @return NoError on success, an error code otherwise + */ + static uint16_t sendFrame(SensirionShdlcTxFrame& frame, Stream& serial); + + /** + * receiveFrame() - Receive Frame from sensor + * + * @param frame Rx frame to store the received data in. + * @param serial Stream object to communicate with the sensor. + * @param timeoutMicros Timeout in micro seconds for the receive operation. + * + * @return NoError on success, an error code otherwise + */ + static uint16_t receiveFrame(SensirionShdlcRxFrame& frame, Stream& serial, + unsigned long timeoutMicros); + + /** + * sendAndReceiveFrame() - Send and receive a frame from sensor. + * + * @param serial Stream object to communicate with the sensor. + * @param txFrame Tx frame object containing a finished frame to + * send to the sensor. + * @param rxFrame Rx frame to store the received data in. + * @param rxTimeoutMicros Timeout in micro seconds for the receive + * operation. + * + * @return NoError on success, an error code otherwise + */ + static uint16_t sendAndReceiveFrame(Stream& serial, + SensirionShdlcTxFrame& txFrame, + SensirionShdlcRxFrame& rxFrame, + unsigned long rxTimeoutMicros); +}; + +#endif /* SENSIRION_SHDLC_COMMUNICATION_H_ */ diff --git a/lib/lib_i2c/Sensirion_Core/src/SensirionShdlcRxFrame.h b/lib/lib_i2c/Sensirion_Core/src/SensirionShdlcRxFrame.h new file mode 100644 index 000000000..d4bca0e2a --- /dev/null +++ b/lib/lib_i2c/Sensirion_Core/src/SensirionShdlcRxFrame.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2020, Sensirion AG + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of Sensirion AG nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef SENSIRION_SHDLC_RX_FRAME_H_ +#define SENSIRION_SHDLC_RX_FRAME_H_ + +#include +#include + +#include "SensirionRxFrame.h" +#include "SensirionShdlcCommunication.h" + +/** + * SenirionShdlcRxFrame - Class which decodes the through UART received data + * into common data types. It contains a buffer which is filled by the + * SensirionShdlcCommunication class. By calling the different decode function + * inherited from the SensirionRxFrame base class the raw data can be decoded + * into different data types. In addition to that it also stores the four + * header bytes defined by the SHDLC protocol state, command, address, + * datalength. These bytes can be read out by the corresponding getter method. + */ +class SensirionShdlcRxFrame : public SensirionRxFrame { + + friend class SensirionShdlcCommunication; + + public: + /** + * Constructor + * + * @param buffer Buffer in which the receive frame will be stored. + * @param bufferSize Number of bytes in the buffer for the receive frame. + */ + SensirionShdlcRxFrame(uint8_t buffer[], size_t bufferSize) + : SensirionRxFrame(buffer, bufferSize){}; + + uint8_t getAddress(void) const { + return _address; + }; + + uint8_t getCommand(void) const { + return _command; + }; + + uint8_t getState(void) const { + return _state; + }; + + uint8_t getDataLength(void) const { + return _dataLength; + }; + + private: + uint8_t _address = 0; + uint8_t _command = 0; + uint8_t _state = 0; + uint8_t _dataLength = 0; +}; + +#endif /* SENSIRION_SHDLC_RX_FRAME_H_ */ diff --git a/lib/lib_i2c/Sensirion_Core/src/SensirionShdlcTxFrame.cpp b/lib/lib_i2c/Sensirion_Core/src/SensirionShdlcTxFrame.cpp new file mode 100644 index 000000000..fc8c4c994 --- /dev/null +++ b/lib/lib_i2c/Sensirion_Core/src/SensirionShdlcTxFrame.cpp @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2020, Sensirion AG + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of Sensirion AG nor the names of its + * contributors may be used to endorse or promote products derived from + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "SensirionShdlcTxFrame.h" + +#include +#include + +#include "SensirionErrors.h" + +uint16_t SensirionShdlcTxFrame::begin(uint8_t command, uint8_t address, + uint8_t dataLength) { + _buffer[_index++] = 0x7e; + uint16_t error = addUInt8(address); + error |= addUInt8(command); + error |= addUInt8(dataLength); + _command = command; + _address = address; + return error; +} + +uint16_t SensirionShdlcTxFrame::finish(void) { + uint16_t error = addUInt8(~_checksum); + if (error) { + return error; + } + if (_index + 1 > _bufferSize) { + return TxFrameError | BufferSizeError; + } + _buffer[_index++] = 0x7e; + _isFinished = true; + return NoError; +} + +uint16_t SensirionShdlcTxFrame::addUInt32(uint32_t data) { + uint16_t error = addUInt8(static_cast((data & 0xFF000000) >> 24)); + error |= addUInt8(static_cast((data & 0x00FF0000) >> 16)); + error |= addUInt8(static_cast((data & 0x0000FF00) >> 8)); + error |= addUInt8(static_cast((data & 0x000000FF) >> 0)); + return error; +} + +uint16_t SensirionShdlcTxFrame::addInt32(int32_t data) { + return addUInt32(static_cast(data)); +} + +uint16_t SensirionShdlcTxFrame::addUInt16(uint16_t data) { + uint16_t error = addUInt8(static_cast((data & 0xFF00) >> 8)); + error |= addUInt8(static_cast((data & 0x00FF) >> 0)); + return error; +} + +uint16_t SensirionShdlcTxFrame::addInt16(int16_t data) { + return addUInt16(static_cast(data)); +} + +uint16_t SensirionShdlcTxFrame::addUInt8(uint8_t data) { + if (_index + 2 > _bufferSize) { + return TxFrameError | BufferSizeError; + } + switch (data) { + case 0x11: + case 0x13: + case 0x7d: + case 0x7e: + // byte stuffing is done by inserting 0x7d and inverting bit 5 + _buffer[_index++] = 0x7d; + _buffer[_index++] = data ^ (1 << 5); + break; + default: + _buffer[_index++] = data; + } + _checksum += data; + return NoError; +} + +uint16_t SensirionShdlcTxFrame::addInt8(int8_t data) { + return addUInt8(static_cast(data)); +} + +uint16_t SensirionShdlcTxFrame::addBool(bool data) { + return addUInt8(static_cast(data)); +} + +uint16_t SensirionShdlcTxFrame::addFloat(float data) { + union { + uint32_t uInt32Data; + float floatData; + } convert; + + convert.floatData = data; + return addUInt32(convert.uInt32Data); +} + +uint16_t SensirionShdlcTxFrame::addBytes(const uint8_t data[], + size_t dataLength) { + uint16_t error = 0; + for (size_t i = 0; i < dataLength; i++) { + error |= addUInt8(data[i]); + } + return error; +} diff --git a/lib/lib_i2c/Sensirion_Core/src/SensirionShdlcTxFrame.h b/lib/lib_i2c/Sensirion_Core/src/SensirionShdlcTxFrame.h new file mode 100644 index 000000000..eb2dbc6e7 --- /dev/null +++ b/lib/lib_i2c/Sensirion_Core/src/SensirionShdlcTxFrame.h @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2020, Sensirion AG + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of Sensirion AG nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef SENSIRION_SHDLC_TX_FRAME_H_ +#define SENSIRION_SHDLC_TX_FRAME_H_ + +#include +#include + +#include "SensirionShdlcCommunication.h" + +/* + * SensirionShdlcTxFrame - Class which helps to build a correct SHDLC frame. + * The begin() functions writes the header. The different addDatatype() + * functions add the frame data and the finish() function writes the tail. + * Using these functions one can easily construct a SHDLC frame. + */ +class SensirionShdlcTxFrame { + + friend class SensirionShdlcCommunication; + + public: + /** + * Constructor + * + * @param buffer Buffer in which the send frame will be stored. + * @param bufferSize Number of bytes in the buffer for the send frame. + */ + SensirionShdlcTxFrame(uint8_t buffer[], size_t bufferSize) + : _buffer(buffer), _bufferSize(bufferSize) { + } + + /** + * begin() - Begin frame and write header. + * + * @note This function needs to be called before calling other + * data add functions to write the header at the beginning. + * + * @param command Command byte to add to the send frame. + * @param address Address byte to add to the send frame. + * @param dataLength Data length byte to add to the send frame. + * + * @return NoError on success, an error code otherwise + */ + uint16_t begin(uint8_t command, uint8_t address, uint8_t dataLength); + + /** + * finish() - Finish frame and write tail. + * + * @note This function needs to be called last, after adding all + * data to frame and before sending the frame to the sensor. + * + * @return NoError on success, an error code otherwise + */ + uint16_t finish(void); + + /** + * addUInt32() - Add unsigned 32bit integer to the send frame. + * + * @param data Unsigned 32bit integer to add to the send frame. + * + * @return NoError on success, an error code otherwise + */ + uint16_t addUInt32(uint32_t data); + + /** + * addInt32() - Add signed 32bit integer to the send frame. + * + * @param data Signed 32bit integer to add to the send frame. + * + * @return NoError on success, an error code otherwise + */ + uint16_t addInt32(int32_t data); + + /** + * addUInt16() - Add unsigned 16bit integer to the send frame. + * + * @param data Unsigned 16bit integer to add to the send frame. + * + * @return NoError on success, an error code otherwise + */ + uint16_t addUInt16(uint16_t data); + + /** + * addInt16() - Add signed 16bit integer to the send frame. + * + * @param data Signed 16bit integer to add to the send frame. + * + * @return NoError on success, an error code otherwise + */ + uint16_t addInt16(int16_t data); + + /** + * addUInt8() - Add unsigned 8bit integer to the send frame. + * + * @param data Unsigned 8bit integer to add to the send frame. + * + * @return NoError on success, an error code otherwise + */ + uint16_t addUInt8(uint8_t data); + + /** + * addInt8() - Add signed 8bit integer to the send frame. + * + * @param data Signed 8bit integer to add to the send frame. + * + * @return NoError on success, an error code otherwise + */ + uint16_t addInt8(int8_t data); + + /** + * addBool() - Add boolean to the send frame. + * + * @param data Boolean to add to the send frame. + * + * @return NoError on success, an error code otherwise + */ + uint16_t addBool(bool data); + + /** + * addFloat() - Add float to the send frame. + * + * @param data Float to add to the send frame. + * + * @return NoError on success, an error code otherwise + */ + uint16_t addFloat(float data); + + /** + * addBytes() - Add byte array to the send frame. + * + * @param data Byte array to add to the send frame. + * @param dataLength Number of bytes to add to the send frame. + * + * @return NoError on success, an error code otherwise + */ + uint16_t addBytes(const uint8_t data[], size_t dataLength); + + uint8_t getCommand(void) const { + return _command; + }; + + uint8_t getAddress(void) const { + return _address; + } + + private: + uint8_t* _buffer; + size_t _bufferSize; + size_t _index = 0; + uint8_t _checksum = 0; + bool _isFinished = false; + uint8_t _command = 0; + uint8_t _address = 0; +}; + +#endif /* SENSIRION_SHDLC_TX_FRAME_H_ */ diff --git a/lib/lib_i2c/Sensirion_Core/tests/compile_test.py b/lib/lib_i2c/Sensirion_Core/tests/compile_test.py new file mode 100644 index 000000000..81c543a68 --- /dev/null +++ b/lib/lib_i2c/Sensirion_Core/tests/compile_test.py @@ -0,0 +1,45 @@ +#! /usr/bin/env python3 +import subprocess +import json +import argparse +import sys +import logging + + +def main(): + parser = argparse.ArgumentParser() + parser.description = u'Compile test a sketch for all available boards' + parser.add_argument(u'-s', u'--sketch', dest=u'sketch', + required=True, help=u'Path to sketch') + args = parser.parse_args() + test_all_boards(args.sketch) + + +def test_all_boards(sketch): + logging.basicConfig(level=logging.INFO, + format='%(asctime)s [%(levelname)s] %(message)s') + log = logging.getLogger('arduino-compile-test') + process = subprocess.run("arduino-cli board listall --format json".split(), + stdout=subprocess.PIPE) + board_list_json = process.stdout.decode('utf-8') + board_list = json.loads(board_list_json) + test_list = ["arduino:samd:mkrzero", "arduino:avr:mega", + "arduino:avr:nano", "arduino:avr:uno", + "esp32:esp32:esp32", "esp8266:esp8266:generic"] + for board in test_list: + if board in (b['fqbn'] for b in board_list['boards']): + log.info('Test compilation for board {}'.format(board)) + command = 'arduino-cli compile --libraries="." --warnings all'\ + ' --fqbn {board} {sketch}'.format(board=board, + sketch=sketch) + process = subprocess.run(command.split(), stdout=subprocess.PIPE) + if process.returncode: + log.error(process.stdout.decode('utf-8')) + sys.exit(process.returncode) + else: + log.error('Board not installed: {}'.format(board)) + sys.exit(-1) + + +if __name__ == '__main__': + main() diff --git a/lib/lib_i2c/Sensirion_Core/tests/run_cppcheck.sh b/lib/lib_i2c/Sensirion_Core/tests/run_cppcheck.sh new file mode 100644 index 000000000..60d620b1e --- /dev/null +++ b/lib/lib_i2c/Sensirion_Core/tests/run_cppcheck.sh @@ -0,0 +1,3 @@ +#!/bin/bash +set -euxo pipefail +cppcheck --std=c++11 --language=c++ --error-exitcode=1 --enable=warning,style,performance,portability src/* diff --git a/lib/lib_i2c/Sensirion_Core/tests/syntax_check.sh b/lib/lib_i2c/Sensirion_Core/tests/syntax_check.sh new file mode 100644 index 000000000..53aeaba2c --- /dev/null +++ b/lib/lib_i2c/Sensirion_Core/tests/syntax_check.sh @@ -0,0 +1,5 @@ +#! /bin/bash +set -euxo pipefail +editorconfig-checker +flake8 +find . -type f -iregex ".*\.\(c\|h\|cpp\|ino\)" -exec clang-format-6.0 -i -style=file {} \; && git diff --exit-code diff --git a/lib/lib_i2c/Sensirion_I2C_SEN5X/CHANGELOG.md b/lib/lib_i2c/Sensirion_I2C_SEN5X/CHANGELOG.md new file mode 100644 index 000000000..a1d8044bc --- /dev/null +++ b/lib/lib_i2c/Sensirion_I2C_SEN5X/CHANGELOG.md @@ -0,0 +1,20 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + + +## [0.2.0] - 2022-03-30 + +Add support for SEN50 + +## [0.1.0] - 2022-01-05 + +Initial release + +[0.2.0]: https://github.com/Sensirion/embedded-i2c-sen5x/compare/0.1.0...0.2.0 +[0.1.0]: https://github.com/Sensirion/arduino-i2c-sen5x/releases/tag/0.1.0 + diff --git a/lib/lib_i2c/Sensirion_I2C_SEN5X/LICENSE b/lib/lib_i2c/Sensirion_I2C_SEN5X/LICENSE new file mode 100644 index 000000000..ff20c41df --- /dev/null +++ b/lib/lib_i2c/Sensirion_I2C_SEN5X/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2021, Sensirion AG +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/lib/lib_i2c/Sensirion_I2C_SEN5X/README.md b/lib/lib_i2c/Sensirion_I2C_SEN5X/README.md new file mode 100644 index 000000000..5165ad7c3 --- /dev/null +++ b/lib/lib_i2c/Sensirion_I2C_SEN5X/README.md @@ -0,0 +1,97 @@ + +# Sensirion I2C SEN5X Arduino Library + +This is the Sensirion SEN5X library for Arduino using the +modules I2C interface. + +
+ +## Supported sensors + +- SEN50 (only particulate matter signals available) +- SEN54 (no NOx signal available) +- SEN55 (full feature set) + +# Installation + +To install, download the latest release as .zip file and add it to your +[Arduino IDE](http://www.arduino.cc/en/main/software) via + + Sketch => Include Library => Add .ZIP Library... + +Don't forget to **install the dependencies** listed below the same way via `Add +.ZIP Library` + +Note: Installation via the Arduino Library Manager is coming soon. + +# Dependencies + +* [Sensirion Core](https://github.com/Sensirion/arduino-core) + + +# Quick Start + +1. Connect the SEN5X Sensor to your Arduino board's standard + I2C bus. Check the pinout of your Arduino board to find the correct pins. + The pinout of the SEN5X Sensor board can be found in the + data sheet. + + | *SEN5X* | *Arduino* | *Jumper Wire* | + | ------- | ----------- | ------------- | + | VCC | 5V | Red | + | GND | GND | Black | + | SDA | SDA | Green | + | SCL | SCL | Yellow | + | SEL | GND for I2C | Blue | + +
+ + | *Pin* | *Name* | *Description* | *Comments* | + | ----- | ------ | ------------------------------- | -------------------------------- | + | 1 | VCC | Supply Voltage | 5V ±10% | + | 2 | GND | Ground | + | 3 | SDA | I2C: Serial data input / output | TTL 5V and LVTTL 3.3V compatible | + | 4 | SCL | I2C: Serial clock input | TTL 5V and LVTTL 3.3V compatible | + | 5 | SEL | Interface select | Pull to GND to select I2C | + | 6 | NC | Do not connect | + +2. Open the `exampleUsage` sample project within the Arduino IDE + + File => Examples => Sensirion I2C SEN5X => exampleUsage + +3. Click the `Upload` button in the Arduino IDE or + + Sketch => Upload + +4. When the upload process has finished, open the `Serial Monitor` or `Serial + Plotter` via the `Tools` menu to observe the measurement values. Note that + the `Baud Rate` in the corresponding window has to be set to `115200 baud`. + +# Contributing + +**Contributions are welcome!** + +We develop and test this driver using our company internal tools (version +control, continuous integration, code review etc.) and automatically +synchronize the master branch with GitHub. But this doesn't mean that we don't +respond to issues or don't accept pull requests on GitHub. In fact, you're very +welcome to open issues or create pull requests :) + +This Sensirion library uses +[`clang-format`](https://releases.llvm.org/download.html) to standardize the +formatting of all our `.cpp` and `.h` files. Make sure your contributions are +formatted accordingly: + +The `-i` flag will apply the format changes to the files listed. + +```bash +clang-format -i src/*.cpp src/*.h +``` + +Note that differences from this formatting will result in a failed build until +they are fixed. + +# License + +See [LICENSE](LICENSE). diff --git a/lib/lib_i2c/Sensirion_I2C_SEN5X/examples/exampleUsage/exampleUsage.ino b/lib/lib_i2c/Sensirion_I2C_SEN5X/examples/exampleUsage/exampleUsage.ino new file mode 100644 index 000000000..c92a10374 --- /dev/null +++ b/lib/lib_i2c/Sensirion_I2C_SEN5X/examples/exampleUsage/exampleUsage.ino @@ -0,0 +1,249 @@ + +/* + * I2C-Generator: 0.3.0 + * Yaml Version: 2.1.3 + * Template Version: 0.7.0-112-g190ecaa + */ +/* + * Copyright (c) 2021, Sensirion AG + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of Sensirion AG nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +// The used commands use up to 48 bytes. On some Arduino's the default buffer +// space is not large enough +#define MAXBUF_REQUIREMENT 48 + +#if (defined(I2C_BUFFER_LENGTH) && \ + (I2C_BUFFER_LENGTH >= MAXBUF_REQUIREMENT)) || \ + (defined(BUFFER_LENGTH) && BUFFER_LENGTH >= MAXBUF_REQUIREMENT) +#define USE_PRODUCT_INFO +#endif + +SensirionI2CSen5x sen5x; + +void printModuleVersions() { + uint16_t error; + char errorMessage[256]; + + unsigned char productName[32]; + uint8_t productNameSize = 32; + + error = sen5x.getProductName(productName, productNameSize); + + if (error) { + Serial.print("Error trying to execute getProductName(): "); + errorToString(error, errorMessage, 256); + Serial.println(errorMessage); + } else { + Serial.print("ProductName:"); + Serial.println((char*)productName); + } + + uint8_t firmwareMajor; + uint8_t firmwareMinor; + bool firmwareDebug; + uint8_t hardwareMajor; + uint8_t hardwareMinor; + uint8_t protocolMajor; + uint8_t protocolMinor; + + error = sen5x.getVersion(firmwareMajor, firmwareMinor, firmwareDebug, + hardwareMajor, hardwareMinor, protocolMajor, + protocolMinor); + if (error) { + Serial.print("Error trying to execute getVersion(): "); + errorToString(error, errorMessage, 256); + Serial.println(errorMessage); + } else { + Serial.print("Firmware: "); + Serial.print(firmwareMajor); + Serial.print("."); + Serial.print(firmwareMinor); + Serial.print(", "); + + Serial.print("Hardware: "); + Serial.print(hardwareMajor); + Serial.print("."); + Serial.println(hardwareMinor); + } +} + +void printSerialNumber() { + uint16_t error; + char errorMessage[256]; + unsigned char serialNumber[32]; + uint8_t serialNumberSize = 32; + + error = sen5x.getSerialNumber(serialNumber, serialNumberSize); + if (error) { + Serial.print("Error trying to execute getSerialNumber(): "); + errorToString(error, errorMessage, 256); + Serial.println(errorMessage); + } else { + Serial.print("SerialNumber:"); + Serial.println((char*)serialNumber); + } +} + +void setup() { + + Serial.begin(115200); + while (!Serial) { + delay(100); + } + + Wire.begin(); + + sen5x.begin(Wire); + + uint16_t error; + char errorMessage[256]; + error = sen5x.deviceReset(); + if (error) { + Serial.print("Error trying to execute deviceReset(): "); + errorToString(error, errorMessage, 256); + Serial.println(errorMessage); + } + +// Print SEN55 module information if i2c buffers are large enough +#ifdef USE_PRODUCT_INFO + printSerialNumber(); + printModuleVersions(); +#endif + + // set a temperature offset in degrees celsius + // Note: supported by SEN54 and SEN55 sensors + // By default, the temperature and humidity outputs from the sensor + // are compensated for the modules self-heating. If the module is + // designed into a device, the temperature compensation might need + // to be adapted to incorporate the change in thermal coupling and + // self-heating of other device components. + // + // A guide to achieve optimal performance, including references + // to mechanical design-in examples can be found in the app note + // “SEN5x – Temperature Compensation Instruction” at www.sensirion.com. + // Please refer to those application notes for further information + // on the advanced compensation settings used + // in `setTemperatureOffsetParameters`, `setWarmStartParameter` and + // `setRhtAccelerationMode`. + // + // Adjust tempOffset to account for additional temperature offsets + // exceeding the SEN module's self heating. + float tempOffset = 0.0; + error = sen5x.setTemperatureOffsetSimple(tempOffset); + if (error) { + Serial.print("Error trying to execute setTemperatureOffsetSimple(): "); + errorToString(error, errorMessage, 256); + Serial.println(errorMessage); + } else { + Serial.print("Temperature Offset set to "); + Serial.print(tempOffset); + Serial.println(" deg. Celsius (SEN54/SEN55 only"); + } + + // Start Measurement + error = sen5x.startMeasurement(); + if (error) { + Serial.print("Error trying to execute startMeasurement(): "); + errorToString(error, errorMessage, 256); + Serial.println(errorMessage); + } +} + +void loop() { + uint16_t error; + char errorMessage[256]; + + delay(1000); + + // Read Measurement + float massConcentrationPm1p0; + float massConcentrationPm2p5; + float massConcentrationPm4p0; + float massConcentrationPm10p0; + float ambientHumidity; + float ambientTemperature; + float vocIndex; + float noxIndex; + + error = sen5x.readMeasuredValues( + massConcentrationPm1p0, massConcentrationPm2p5, massConcentrationPm4p0, + massConcentrationPm10p0, ambientHumidity, ambientTemperature, vocIndex, + noxIndex); + + if (error) { + Serial.print("Error trying to execute readMeasuredValues(): "); + errorToString(error, errorMessage, 256); + Serial.println(errorMessage); + } else { + Serial.print("MassConcentrationPm1p0:"); + Serial.print(massConcentrationPm1p0); + Serial.print("\t"); + Serial.print("MassConcentrationPm2p5:"); + Serial.print(massConcentrationPm2p5); + Serial.print("\t"); + Serial.print("MassConcentrationPm4p0:"); + Serial.print(massConcentrationPm4p0); + Serial.print("\t"); + Serial.print("MassConcentrationPm10p0:"); + Serial.print(massConcentrationPm10p0); + Serial.print("\t"); + Serial.print("AmbientHumidity:"); + if (isnan(ambientHumidity)) { + Serial.print("n/a"); + } else { + Serial.print(ambientHumidity); + } + Serial.print("\t"); + Serial.print("AmbientTemperature:"); + if (isnan(ambientTemperature)) { + Serial.print("n/a"); + } else { + Serial.print(ambientTemperature); + } + Serial.print("\t"); + Serial.print("VocIndex:"); + if (isnan(vocIndex)) { + Serial.print("n/a"); + } else { + Serial.print(vocIndex); + } + Serial.print("\t"); + Serial.print("NoxIndex:"); + if (isnan(noxIndex)) { + Serial.println("n/a"); + } else { + Serial.println(noxIndex); + } + } +} diff --git a/lib/lib_i2c/Sensirion_I2C_SEN5X/images/SEN5X_pinout.png b/lib/lib_i2c/Sensirion_I2C_SEN5X/images/SEN5X_pinout.png new file mode 100644 index 0000000000000000000000000000000000000000..c42395c2f4cb8abc8bad6df32a337481cb2f7de9 GIT binary patch literal 38240 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 literal 0 HcmV?d00001 diff --git a/lib/lib_i2c/Sensirion_I2C_SEN5X/images/SEN5x.png b/lib/lib_i2c/Sensirion_I2C_SEN5X/images/SEN5x.png new file mode 100644 index 0000000000000000000000000000000000000000..32bb95b0142600145f1f10028b6d0840d01b0a27 GIT binary patch literal 450015 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

jM(%b8pDizN5pd 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[h zi8g*zCD5fh2P4LX&>O|SZp$=^^5WYYKL{>YUb{VJe3;s-{1n^F*t@cjKp@vdCQ{gS z7@v^!FzPoJBAkW5n6}AWWD1V|ujKCM199xV3XMh`c9-W9)zi>hP{KHt>U5waeE96V`QNSL4Uc-u`@ClNb<5^+ZyxX_ zziCx9=21288-E&y!7{dXCt}a>i*UZW$T6xGAis67B8fcjrBNs~RWM>7Lz-$pQHlgN zzyoL*CPsAk>N;&9+nu+)MK8j{7B7V3BAMv`)tiC!48f>?3CfVeg637gyuVf_4RKxw zCq(DHgnO7?$XI!{; z`zv`OCa<#MLueju`a?~PYorO95fY9b%Tt(<=-iF|vRq&3c^x(NN|aJ|FGPD3^YV;& z-1lUV38uA^MfFD9WA~-dgAhM}Qpeh!yK)>~>4>_8KI*@&Gy0Ct=E`RFQS=Kf0;c|z z>V|&ra6y^4#Ko4r+tH+dmOEv$MTQK|J=S{p>0Z^!$PLRN(oM|tymx!RT&0!Tt&^;K zVmenQ6`1}i^{b90$;1=56fuUPheQhB<^16;cj{+e9?pBJXMOhS$kfm){FCAskEsn9 zSU~6ivg)pOKGWZo*Dg25Gu>3`OU=;|O%v2V8 zX4r5zy3ug9-W?m;5mBv{);_gXGx4`Ic+EqSx2u%$T!a&8d$yI#4e1&Z9T)!>Z_6S! zv=>!n-iQ>l1>sO{F0%Ts`!e;tWXq=dD{lW^Ex>9Tlk}YIgYp>1OP8|CAq^Wbh3MCN zd*FVD1mx8+TLut3b!^XfZ9#y5IgkP(o`1NQ#ohgZA%Z3EpUNF#OOVSQYKz?8(FW{7 zD4!u;7{C%4d3nSDp8cFNt{r%XoOxg1y<9;h!MxoRhst1@MK(q7ZVIB&M97qI|1QBu z|Mt9i%HJa6x{D^qGqfd7db0?B(L~6JL!Byeq-Q%~E=jFHj2hz21L>$KJiCPK-W?`j z=!1)S(?{xo{!~h0)#dl;$s?!1b7-B>ypf3+R2hs}x{cFEeA^-HLeZt;Jn#~RYgr9$0la3QflPI={jx4%UNee;F&fRm#p z(T+FJyDi+XmmTi+H`8wpd$WU+)5@sE@kz^CK$G9uo`GE<3zN^7{ppP5A2O2a1MjBa z{F@gB%CjIw^*O3>2*aqYz zK!69#zVLY$fg4o3T5mjDwTUd2f11E}LXHfjS7h8K+;E^Oes;Wr@NjRFlg&n5%brT4 z^?(dF&mGD`k#}=wC_WPA3yBkrK;Q_tts9C&2O%m|0O=}yj)X)Oen$JcY^%y#rhb;| zlGjYj)c1a-cNeR?4r8f*?y}Zi&Q`95Ze5~M+6#D*FnzlkoEYnIF1rw+UexO1}XO*D_tyDG0|^?HBoT9u#I z+?6-dVzW0CZ5!rZC>XhMug{8?I_=n~e7&G=BiA9mTAkL-a1@FrTR_6gZn9$St$hs3 z3@qe`HLcU|b@&R{5TW@4(yPDBJ6c+0f7#2e0rp_N%8(EDARHI+JRk*a?AN-Bsb`54 zS0-M!pxuOFnVpTC!3zGjH@zgx!NjT3U$Z^VbrOqZT*o62`65^GLzmdvDQX$(r9^97 z2=NLrd5$p^n?PsU_O>{P0^3Q)<^T$eI^Bkax;2Xtyx&F<>>WIT_hySX^6cnOYNjH(O1!AP%uw)ZOy#=RyTdJ+WB` z2xt8XrPcRljS~m4P(=9mgccj+uRP9G>+TQIz!Ra$;K(i|bEbgk(j+W;;92bt|2zSw z<}93)e|{6_Q$hSDpfDgvCZP#t8n&T9bl6#{$tV=8yd!{AHAF{8&%i~Gm;#V-7i8NC zH4UGJZSKFrn@UMZiQG;PJZ~1Xyv~}crib_F4qdD+&>E0t1g955tms0LAv^QU4J-TK z-{^rTp6>8F?zpsB4{#g;T?6{JxU$j$g^v)K76R)cP;QWH1eaOkzK^)?FGfe*IpKq;hm}1@VtLf@N_1|Q4qlUk0NzDV)rK<0QkNHTy z$Ddq?_!ArjKSrPm8bzze=kT)VV(x4((Ki=Va%twP94C^TN}U{Tnznnn+H;tt54?8? zH3jb1(+J}y9_3{niS{e>iS&7Eo!lwUzL1i&u2-bB7PBp;-Y-fWial=aZZsJ|oSoow z#h}%#+95G;-C=sR(KplCWlh8AdDe0QH?d2sR(;_+iuWUGJ=|6R1@n-fkKa+u_#cJ(6I4^nUFDCc##&$!YwX6{ghI?=5A^M{lq;hBi07$jL6=$6fnFUTzICxrPQ zQKZlg%B|lnl^TC{=M8))sOK~SNJ5)r;eX-gLyFj0k-uldUOQ9hS4Z7D$vPXY5Ip4` zAp8?|7+2=y)UbH9N13d(BAe|~D|ynNEA5nEcK@`)@7lW|#_oexZoYd14S&~@C;$H0 z312W8EF5qAFwp@uNOU`TqRB*rzYSmXoNA`Oj0>X)USzEl;fx^lzL&xC=~wx(%glS_ z{71B8?KAPVqILPn?&Q!=22OJz`Z@qj0S|Vu8K*yM+&O>NR>*J1a+mVhzKqZ+@Gd}B z0F;20tZuu0v8TTOLl2z^STT_e7t)r}Yibx^m7N+hh~m7B$*ImG*LX%d{BHY9;BkTP zLJIi90|Z0=FP9zRvgaD+-xfQY(k` zg*{8@_T`qr!xTw1qP#jLyN3e$g}yYBR0EI9EEI3;t9MHF4;h~@RwODXN%k37R!e4# zfUp#l^RwVylOeovu*T3|)LQ2b!5xVD6qKHdoBRuG6X<-HFeer};jL?jle_kDpm%R$ zKchZ#62*5f_ws{LU1+B)aDVS|?cUeRym@7@M=6qBN@s8wvYkRpzsoDK$lAvUk>Iz_ zO-7ZDOQ6Ws?e2G?_-j?Js(PG~WU=X%D@zjD?evvSa=$t)>*U+K=#OK_*97a9f zQi31P0B=M2Lut&5BSN_gikD-xFHzXXTz++zJ^b=3zo~n?RQ6kAa|o;wcxaY&fY%NPNL^RuF?(qdvhqT=ENKaqz+{XQYlCu80C)88TGO zkWx-ij)CJ5931uw-Ao9Pf=nHYi(DvNHp5n>4WQ0~Wn%Se5$X;ME<~N==yMc2OP0xy zvO5JQtkPi?AGXK99|AMgO03ER!FgD>F{$(CjYdaCilKZ7$<>C{K*7k!2xSELblAJ+HIox-2%I5P*PUd$r!CnZ)aC++g#tGj|7>Cq&fE%EF~(=TuR26N5jByu}kXP?P;odZNOBOoEc6nCk`sb9Et0S0rVxgulfxilOfMQJzW3Utfu}^Sl43filH3q#FHR z3q!#ArJSX_&d@KoJl5Q)y|FSe=7;EGoUM+9XobR+rRfvWZInb3!FFBg!o-Iv^-ZIt zq?Jm0Bhozm5ti0V>x`xok4m#{Dzbgf9P*cly?duo0?y-s{$=d-*gMD>y|YcG4X*pY zQ>+)hUfzb;_13MwTa&(06}c9#&o}-~83cyUx=Y;`s+3vi7X5roO$7#ekLbuG-5Z-6wgbeyBDgw4cq4}sU_+$O9D)Q74?Piy8{jMYRgRXZ zho7H~zkr@}a5qB4%nW!FD?#Q4siEN7Mr`4rR7rn^{=r3DE?BV2!~IaRDa__6cY&vI zw-m{PdwX$3uX~nmJ1rj4;T1Yhw)xSQ5vNhGCCoXq(=>4Dl?6S>VkDIb&WPQ4?;IPW zsZn%+HD8{)Np0Dij__kU8IVTN&olZaecl$*osCDDY-U z_qR^E=8~pUnfvL}1L6B~s>V7;_fD>m%!Mvx1PwdhUlzPo_keTvMkaA)-UIdVq=HYW z&yGnM26JosORq9uj*>Jya_4)C_3dzOF~*SJnj8N1jRcM}NLf0!-?u+1c>t#eF>u05 zjATzK_j0INx<0SDrze{54PLrU@3UdfIi1s)+P~M>+f7jVmBsXH{Dle~S+2bIYY8Li zo9OaK49W{u9O>{iut&MbE?rXT$aEOhx=X%M>PT|N=q8H7?;dAWuwQ4%=GZc{k10uv zy6R86lj`J8AKHLDxql_G#YCTsbVKs7s1W1emfmic8Byj}toA7-i;qcEg#`t8Qw8?f z6LHUx`}QE`0@nV&YZv~R;4(Y@ZdeRUivY==n8>N`c0M?1XUA3of~P5|4UWCPQ?g@N zeD>3P_D3iGjzN6E3OFWOU{Ii=qqDbqbi*|A4Ra%jDXvvyiS<+*DJrMq&V%uwn|R#X z8XD(r>!P!MtIp>o@U+}^h<>406m$;W+D$K3bn#!z@%q$l0Qqlbr)KyN-St=enpIP$l1+`qG5!%NjMiCxJa2`*I~V#c%f zjXUANa%6IUWvkSrq-1iRz~zRv0+AJ~EXPl`R(bzEj(5%LsK9Xc-O9okj1cK37Cb(e zshSIMAGbA%v}~^isTg@_3MI9n3`T`l`>HeP?W7+kR==y(4ZY_`;<5a;SkS0n z!Af08T{OyD0&g_Wmh6^#>U#B2boT(})LK&8;L8*4UA*0t^?D3X+M!w$&$g%%KiF*L zZ28A`OPO*VK0RR2s;()FfKpY6i)KsfNgP(NC8jq7BOkIZgWuTc_GIvZ4)9gb_KO<5 z>hthSXH?@OZG+~r_0y92H9Th*+ook|9@BOeDk3?Sj2reW*K7Eu9BJ__B)JHZrrS*R zbrU|J^qmHA#@O>~zJ5bhJ9SSx^4p0{Md<0VU}U9t(jPHDwBl=(&ztFNoOsz`iBC3~ z=i7#}$l^^V`6B6n`3-HvmB4V5p!l|Dv@R4D!R~p5z$%~uKd&I8!Cha?aDOkjijn*H z80RJAQ|p=7cH~lS1UW_5b4vVOXPCU+u*uUvL(bnVs>bNGarXDn5D^7x{3yBboFoX1PG@J{ymOa? zUZ2?X?!2tT^KcCTL>K`K9TJ~4RAE%H^&vkD^%_~XA^aFA%tMkN5u5`kL=Z?|wFqCKy_5{nM|+4l2DKPOVG0YXjeO+M!9^FkN$Rv0c`+}!TsN4Ohdy9tup zpWw`k=M<3=g~?p3V$wN+1Q|dzAnMelFrg|X;-tjnmZC}oowAsnp(7Ud_AAJTBxraM@PZvop##5xR*=)6-lkV^g_L^jP6{| z(0&u21KsK)rbJrhA&Mll|$o#KWnUDlGF znlhv3gOXKimhf85&#H|^Z)E5b^Je*?vZuag!I zOtc59H-Ymg?d`ogI0!Lkeix7CIHhJAM{)aCPo{p(C`gd`o)tB0&-+P=h?LDKo>2nD zILXYC=07XKVIj@?=sGIp$bZ~Vnzuj(gUSugF;$k}n>XSxJLuwR#rzDoK(x7n3Lv4x z<)xaOFBaT(L8G{~p|rQc7BTt2-QCDjRC~e3xs#4qI+N%l1Y*$b=%$04oepHZK$LSM zX&B)6F|)SjelEw?3H7%2MzrvoMi6ZTtb(=8+rd)C?q(MiWIXOFu|p0&BrmuY!1e3^lbbOsSN2k=(eq<+`g%-(b96heFD zK9N*%r!ZoU(|}r@OWPo?fFaANSv*AX7VE2O`4bf^C9>!x;b+<|AH6kC)Y{|*qHds1 zTr&3F7rXWwvABxo+jY%%J?VG2qGDGbDe#<8C?RK(N0t4{{JnatA7-DOizQSzhncOt zmTYvQ$QD<#cD};o1kD0qO~tpHBQyvZuBxy1?f#vU!J=`>whmqtd}t_@xsP3(*WmTg zs9$nXRq3sMy$!vPTiJ&XK9}Co+zhCh@EJFdB!w%iCS2+ITN)5YOS|oL}Nf45< zWE>s3ugv>|v{jWtqRbWkD8o3mZYSK5-*pvRqhW%6cy)S`IDtL_?oXz}^?x+_|K~8X zr2S`JMlR{ocj318VFROsiKpeJ{cb09Wkty6$y53o*ZEglQfEbe4{;hZiD```w?DAd zON#&bvkzvRD9#fcFdH(vd7F3QRX(9}9HO)Le{E)={ZdYbpPLaM@3V`)qR)?n7%j5o z?Vv0S4<36)_GgJ=1aB&%lI`0Ry$V=gGuXe z40c6cqhcIqkO$H4(Ec~2$(S%tCKto*>+BC>=)#;C_P(Cp>A&?& ze*2a-3+@m>A#nJ>@@%fFUK_>|T&^zm?3~9)7DNliy|WfuK9tKmy*=*b%)ZaI?EA830eGs5HqqQ?>#;?# z9TF`9#imWz$i%Va{NN~AZXiZ*L-ifZSP!qiDXq=*;crbtdn~PWpb(tKXBOXPX|WO1 zh>a+!?T}wXq_l-a!UP{5^YGP5+!Z~};Whnc!1hc`h;bB8xQ>{&%ZsPS!RX^Lfzy~|y${r;W@RV-xoTfZ#x@0Sy$L9vI1feCSkV`E_aiqlC@Kv2y$9s);`Fg<~t z#!BmkSNw6_qb_n@o~_2w5@foEb?sFQt+7_84khfy+sf;HkFuVCRP6z(vwh~@>}+y} zeTo@b5#d_*Q~#*J1vJUba(NdW%f&!VgP==N$IN17R$^(~*qiU-Q+V|Fe5a>Rywa+? zmyV16NWi5sx%3;(nYW|o+aRY$Z?l%9g53oz=q$EzBDm51xWO$H+&)({C^*cd_39)^ z$Th3Osrwv{pKPToHHpWD`A23wF^AwJMDz^uFeL8)UWxYILFao=xD2T@M0hEZu!(=> z6GGcsTVwl+nwhljV%PE;R+1xXxgY)gIu$cMP&-(npKsIVg-#8H%o!jR)cp>%Ak_x1 z#&xY3wm--rVa{)-6zHw6MJj0!#2fO8A$mW;kS{xmnrYy)a0Nfz2U#`kr%>ShI5+6B zg~*x_i4@F~pnpR8e~~r6a3!Onf(C}5+hFnoozR7$(vlL2u7qo{@Qgls^aw%W5iwsP zpHXvb>m5^*PX4~AO_(tbLu9y_?tHY#z;UH2yT^7vDN08p^W9(oAN7OfV}?zC4;W&H zlkv@i4Co2ZrBQ3#B~s4}sbx=1dPytBZy8?Gq3crr94vY2iKvZ(|-iMJ(;2!hz zy!h$UCriuD_ht`M+a#R+lj^5f{Q1R$gu6Vl53HTEMdfP_#~m1{A|}Wr9MlQ?Lp{zv zHuy|4T3unfi_y8;I%^#1*gbtxXkj^fl>kLrN&dcpq_KRunsMT#QE4imJBGCQ`|GL0 zHl(j#Yr#}V$CB2#`Q?VV4?5EOy+2u+ct8^g@Pek^$D%a+_g9C%@xOF(`G$g(@{M0% z?KNdvlecqjCx5r3{|0Atf!8m9cn`G~7@7NF&Zw5&Jy zKxp6Zuj53pyN|E_pO*mhUAQhG=>Wic8fYDw?eKl(y~}?}V&}c_oEVkj zhvM?#&?8^Di@zZfMx76E=D|ZM;3s%K=g1_}UowhY_y64Bf46Qp#5bs8^)yu? zS5VfHw)+@QltwM>oIY6Q~{ z1NX29ESe1B>!Y`Q%%6!7pRhVk@iiU`2&4pE-C7r2nBpV2QCre`Q~BWHH~(4Bz3EeK zH-0_bQGj($@q3tShh&r@C zTW3N^?-ww%$9K_2`R&@B7Mw@1?0FYg!{Pn$xnYattTKDy=W*=M5(tEJ6FjzQ<)(Te z*kYRXgg0zrpr^Y4S~`s8z{ z^y7D^2f-cpe}LUkotH4c-C+Qmva(hF1g=L;|hy-+x!I%RD ze_Igbj8H4!X7##1MBBX(`j#S%I0T!dMH)(-${+Y;7Fx61hO#0s)0I!W$t=#FzH_`e@hr1&4+3|Za@c@?>Xdqfd>_F z?y{ULDj@G1$>U8~&^p4brO%7sRcgOFBxqRYNe!Zbc1X4;fe;t?`I552VWxmL6@eez zEnx2!P<85l;Y!4<`9p#9O$JV>qvUnMgfp$vtiZcO&6>sc@K&`w(E6E>vXVv^fyHND z*7e>3_YcL1oHs2cPh<&eUxZ=BGNr=<=8oImKKCSJDeS8(tQX;pADrtM-*OQXkfHQ6i^UWPlu*FHW`{I$~q8p=mm@^;RAA`=$lbSb)zx=Ji zMN)RWX3iO2C+-joZEw8KsSMXZ0-w>v+IS9G+j7HUKgTLV`l0M?T8sQmxeceK&m9<@ zu9CVu;$*RrpF<)ng|iut@25X7-XrdCsO_I@rmdyAK)7IU#F?WGZ8-4fXQ_bTt?=pW zmPHoE=DxYhk3I^BgeMW?p6?BQdeQXT=-9A;>KADv+lXIo_+-AHq?`v_yo=hWy%M^&{^Xcc{Jo=IU_sQETS0$b$I=8*2y;)k6G>m4#{l zcpz`8{|DdUq#CUN%-hrZWJRidXWEQzi7L9`j2S>WiQ}!a(~U?y(z<1AdoM4R^=h!H zOjCBmoK1kyduH8hf9s(s7_E93yGqZu2$+{7okIccF6wrICqB=n>s+ivfMuzP^^TXS zPlKhbf19U?{+5X-3%5G;X4elx(&2lGekd&c{GuWSB(Var^WnC(05<`INWv=x&QjCE zmeo~WFvNn~SoU{nT|`&Al=4Gfp3y@qwt)aPiI^$QapaO=z{ekcz zBz^!ErLFM|U)pT-w00_d@F+vL!QFI-zJTvk=8ZXZ@v>E% zI-yb9R`GW+mwV@Cf@LI`1W1D3qSNK$ukAm%Wrs0b_H5U`AL;6GNpe`-@&}*kOOlbR ze=!M{SnD6F(=TeB7&QLX=apX&?Ur)4Y_vMRbdC5`g@eRH zlYXrMPLd>DVypf`;<~Gkm6znkO_~ow9vGMJeO%6|5e_~GCViP_XOuI)a;#k7mszip zIk+1UL)4sGF?djuAAzBDQIB`YXjjBYxa{fe3=9{(Qf-dbJnXWdpq^ynI`9S8Cc^O| z1!F?LcKHRPEk6yHe%B27a@6+4Zq%W>>4e;Pim~fK0@7*Z`fQ^aL(LO=x7AE6n&ABv z6H5|%Bm8y|k`{wHW|YEIO)86}v zA;UN<%d=U_$_MQ%La`6W@>34{Dm|v+%q-acAU<1u6!s6!&$t#n8v<+_e)0Y z(jDpB^zXhDZFDWQ`C*L!@`$vUAjFcG>uMv6^+EB&aG0RH`#=5NNIDT19mBu}iR7(> znz6>-{q|EKL^{+Am)skq;ZmntF%A%Bg$!K;q>PQB=NTZ&m!U5x5DTp5@I?@f7<}Cl z;IDuq!?)^AIcNIW#-QZTNQI~s2ujy{+{8IF+~{D}JRYz+p@9z=g+dhW!u4C{ktny6 z9afI=O10MYXAm*2pg@2K2oQlV$oxzWI`xo!!M+=ZOYuPd)(<0sk9i@baYbQ@blTco zAEzv@Y-Sm&*J)<--dF3<_sF-$@(zjlYOnup6H8jnaM9+fGi~x#XWmFZb(xa?O8u>34H7@{j;*vR$l zv@!BsQ2L0x^S2^W%)^~j|(gcA-CVJs^TB;!vF}Eq<-0B3J~E8*CRl}C`cB^|@-Kr6a zktFlH;v3Bo0je2v&x5Iy7VZ(`pesn!xu1GBM+k2Wel^AarvHsU`;TiR7XFP#?D5;2 z&t?O9S7%$pN%1U~k>TxM7Q>rwJsl-7^^S|Iv{-?snPdQ*27XCs0Hi}$9~a)PJj zj8hZKejF!NgX(eKZ}vG3H3Y~(LptS>CJARgrc7I zvrU4t5q!v&*@X(aq4Bei8!>*4a~)4PI62-vo2U+|KMgP!N{px~dOA@d^(HKa|1||8HgFiKp`I7a zlZ2_}bolMzv$sdI!Xk)uhGeZS_`0O5U2S5ZDE-KGy;Lw zkwXYA?rhIH_?9n^n&eMeMZPaDr$!(jKvV-+PB+8c_s88JWa4-58F_jfu(=|9&OJ<`!dLIFy~D&koOSU>-ckMzC+7Q{YYy(i z`9IiYU6h9CpHVfKsJ=fl;`4gwn^;^EPVe*GxMSps`I_W z6|a@$3j-XO?mh{X!OzaSIy-|)cMd-Bsi)SP&0-#~q!#2jDEa2S*k(&53*J@7*yw}- zs0#`n(2YVBA8YdW=882__6I7_{g90h2wJEal$G21mcC1{Gy`;^%COL;mXhsp-{&xq zg<>X#3d>8e&n@~psTW5^!lR(``QZExlx-2UVUyqsP`pn0#Hyl_%OqY)8uvL$*!OKy zdph}5x*g$*)I2@(jUrjuRsupo(cWwu8}l<84i?21-X*SI4Smx15dYU#Dw1CR6*PIt zT-V6xnVtI!?35M(38OL8J7T6TtXg5gse&mhmEg#&b#*?sI{j@!lpE?B%0kWl%)yW| zX-r@`B-JePpvi@Nk>k&p6rxc>JP#N3AvZUhNWgZ4OQ)$`SM zj$%8%Nv$fZ!WG3EYqhShlF;MCH*viQx zNU+rh#gTv;FX50&cG`#2aG1`>!R`J-!dZ)KC*J=RrbtaeG?kAf-CM4Z+~bBewPVE7 zR@py@w(jT803-|%P9g+!@ev2H2~jXHGb27^BujX#+JzW2nx>I>B^?3xQmj!jhJTPs zf}1z}1!=_lz;g(h#*hRF@sjXaLP!=|;)sy~-V+FRgK%YjXTJGHHA4E9*|+av$r}yI z0Y3ZpuLx{=o&I^;ezc2MB%vD%0y<$K!9oH109%G6u(LQQq|y`caiG3n(uZ?`1lfUB z0pc6{pS*SdyUB)RIzZmY%u;XmR0@F|ehzx^SeL-pd5P;T#=t@K99~TGuY0CNWuRkK?>1PwgtQL((oid{y4#v0hm1%#G}Q2f7I1^!2ljP z6_@RDr}vBQO!2A}+pJDeC7!=^rn{T$ZSJO%EWyzz>{D``M}KW>zNtz=N{To_VMlippg^2R@R-ydF6V(FSQb1xkOqx- zTMyJ;-a-v=Z4m2JUw)3szosmtT55+CLWF|p~2{v zdB0gWFr?guy$9jw!ki9zo&eV^`AE`?!O9G8~q;8UG%O#Zr|mB ze?1=2Gk%wn@~qC|NXXNR#Xw7|w`Gc_208s_@Hz!y&-Bbly#$vqM1>hg3N<|~VJ20-ZhKiO4+Vy6sBG^Af zH6n$C$55Z%0y7gR9LYH+Dr^z0jgOBHf_EYbQ$9y~h(jN+9y*|YkrxgK;Kv|G090+n z=`8-G@y(86ITiOtb$lx0rWGM~%+F7%{;0|Pj`76^Z+g=4gmjM0;EK6ev!7rgodg>PNMd!s$2B%^5b29CO8pJ%7w zh+G=Ey&{TFboG_LQojvf-VUWh9ZJz0udY@!o#>=_IWsTYMr?eye^G6|;05WgrKw!T z3I*DWiUfCf;-P`=Pv)xDdB(vdxp;U)vMBM~^Fr3xQ_%r=%d+E_oLyeKknw17qD_AE zhb-^(`KV?`yp^vT#Gti2HC=y>>$#we^y|?ijggo;d+KX7j}Nx^ClOc z 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%0D-_ICZjBoFFh%i~-3I4Km}X!_y68s&p;aKSq2UMH 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

9!X8kny}U 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

0iPbGzzJYTK#m0Y|;I%RH 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 literal 0 HcmV?d00001 diff --git a/lib/lib_i2c/Sensirion_I2C_SEN5X/keywords.txt b/lib/lib_i2c/Sensirion_I2C_SEN5X/keywords.txt new file mode 100644 index 000000000..295031081 --- /dev/null +++ b/lib/lib_i2c/Sensirion_I2C_SEN5X/keywords.txt @@ -0,0 +1,55 @@ +####################################### +# Syntax Coloring Map +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +SensirionI2CSen5x KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### +startMeasurement KEYWORD2 +startMeasurementWithoutPm KEYWORD2 +stopMeasurement KEYWORD2 +readDataReady KEYWORD2 +readMeasuredValues KEYWORD2 +readMeasuredValuesAsIntegers KEYWORD2 +readMeasuredValuesSen50 KEYWORD2 +readMeasuredRawValues KEYWORD2 +readMeasuredPmValues KEYWORD2 +readMeasuredPmValuesAsIntegers KEYWORD2 +startFanCleaning KEYWORD2 +setTemperatureOffsetSimple KEYWORD2 +getTemperatureOffsetSimple KEYWORD2 +setTemperatureOffsetParameters KEYWORD2 +getTemperatureOffsetParameters KEYWORD2 +setWarmStartParameter KEYWORD2 +getWarmStartParameter KEYWORD2 +setVocAlgorithmTuningParameters KEYWORD2 +getVocAlgorithmTuningParameters KEYWORD2 +setNoxAlgorithmTuningParameters KEYWORD2 +getNoxAlgorithmTuningParameters KEYWORD2 +setRhtAccelerationMode KEYWORD2 +getRhtAccelerationMode KEYWORD2 +setVocAlgorithmState KEYWORD2 +getVocAlgorithmState KEYWORD2 +setFanAutoCleaningInterval KEYWORD2 +getFanAutoCleaningInterval KEYWORD2 +getProductName KEYWORD2 +getSerialNumber KEYWORD2 +getVersion KEYWORD2 +readDeviceStatus KEYWORD2 +readAndClearDeviceStatus KEYWORD2 +deviceReset KEYWORD2 +####################################### +# Instances (KEYWORD2) +####################################### + +sen5x KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/lib/lib_i2c/Sensirion_I2C_SEN5X/library.properties b/lib/lib_i2c/Sensirion_I2C_SEN5X/library.properties new file mode 100644 index 000000000..ea4a9000b --- /dev/null +++ b/lib/lib_i2c/Sensirion_I2C_SEN5X/library.properties @@ -0,0 +1,10 @@ +name=Sensirion I2C SEN5X +version=0.2.0 +author=Sensirion +maintainer=Sensirion +sentence=Library for the SEN5X sensor family by Sensirion +paragraph=Enables you to use the SEN50, SEN54 and SEN55 via I2C. +url=https://github.com/Sensirion/arduino-i2c-sen5x +category=Sensors +depends=Sensirion Core +includes=SensirionI2CSen5x.h diff --git a/lib/lib_i2c/Sensirion_I2C_SEN5X/src/SensirionI2CSen5x.cpp b/lib/lib_i2c/Sensirion_I2C_SEN5X/src/SensirionI2CSen5x.cpp new file mode 100644 index 000000000..3008e5226 --- /dev/null +++ b/lib/lib_i2c/Sensirion_I2C_SEN5X/src/SensirionI2CSen5x.cpp @@ -0,0 +1,880 @@ +/* + * THIS FILE IS AUTOMATICALLY GENERATED + * + * I2C-Generator: 0.3.0 + * Yaml Version: 2.1.3 + * Template Version: 0.7.0-112-g190ecaa + */ +/* + * Copyright (c) 2021, Sensirion AG + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of Sensirion AG nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "SensirionI2CSen5x.h" +#include "Arduino.h" +#include "SensirionCore.h" +#include +#include + +#define SEN5X_I2C_ADDRESS 0x69 +#define UINT_INVALID 0xFFFF +#define INT_INVALID 0x7FFF + +SensirionI2CSen5x::SensirionI2CSen5x() { +} + +void SensirionI2CSen5x::begin(TwoWire& i2cBus) { + _i2cBus = &i2cBus; +} + +uint16_t SensirionI2CSen5x::startMeasurement() { + uint16_t error = 0; + uint8_t buffer[2]; + SensirionI2CTxFrame txFrame = + SensirionI2CTxFrame::createWithUInt16Command(0x21, buffer, 2); + + error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, + *_i2cBus); + delay(50); + return error; +} + +uint16_t SensirionI2CSen5x::startMeasurementWithoutPm() { + uint16_t error = 0; + uint8_t buffer[2]; + SensirionI2CTxFrame txFrame = + SensirionI2CTxFrame::createWithUInt16Command(0x37, buffer, 2); + + error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, + *_i2cBus); + delay(50); + return error; +} + +uint16_t SensirionI2CSen5x::stopMeasurement() { + uint16_t error = 0; + uint8_t buffer[2]; + SensirionI2CTxFrame txFrame = + SensirionI2CTxFrame::createWithUInt16Command(0x104, buffer, 2); + + error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, + *_i2cBus); + delay(200); + return error; +} + +uint16_t SensirionI2CSen5x::readDataReady(bool& dataReady) { + uint16_t error = 0; + uint8_t buffer[3]; + SensirionI2CTxFrame txFrame = + SensirionI2CTxFrame::createWithUInt16Command(0x202, buffer, 3); + + error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, + *_i2cBus); + if (error) { + return error; + } + + delay(20); + + SensirionI2CRxFrame rxFrame(buffer, 3); + error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 3, + rxFrame, *_i2cBus); + if (error) { + return error; + } + + uint8_t padding; + error |= rxFrame.getUInt8(padding); // remove padding + error |= rxFrame.getBool(dataReady); + return error; +} + +uint16_t SensirionI2CSen5x::readMeasuredValues( + float& massConcentrationPm1p0, float& massConcentrationPm2p5, + float& massConcentrationPm4p0, float& massConcentrationPm10p0, + float& ambientHumidity, float& ambientTemperature, float& vocIndex, + float& noxIndex) { + + uint16_t error = 0; + uint16_t massConcentrationPm1p0Int; + uint16_t massConcentrationPm2p5Int; + uint16_t massConcentrationPm4p0Int; + uint16_t massConcentrationPm10p0Int; + int16_t ambientHumidityInt; + int16_t ambientTemperatureInt; + int16_t vocIndexInt; + int16_t noxIndexInt; + + error = readMeasuredValuesAsIntegers( + massConcentrationPm1p0Int, massConcentrationPm2p5Int, + massConcentrationPm4p0Int, massConcentrationPm10p0Int, + ambientHumidityInt, ambientTemperatureInt, vocIndexInt, noxIndexInt); + + if (error) { + return error; + } + + massConcentrationPm1p0 = massConcentrationPm1p0Int == UINT_INVALID + ? NAN + : massConcentrationPm1p0Int / 10.0f; + massConcentrationPm2p5 = massConcentrationPm2p5Int == UINT_INVALID + ? NAN + : massConcentrationPm2p5Int / 10.0f; + massConcentrationPm4p0 = massConcentrationPm4p0Int == UINT_INVALID + ? NAN + : massConcentrationPm4p0Int / 10.0f; + massConcentrationPm10p0 = massConcentrationPm10p0Int == UINT_INVALID + ? NAN + : massConcentrationPm10p0Int / 10.0f; + ambientHumidity = + ambientHumidityInt == INT_INVALID ? NAN : ambientHumidityInt / 100.0f; + ambientTemperature = ambientTemperatureInt == INT_INVALID + ? NAN + : ambientTemperatureInt / 200.0f; + vocIndex = vocIndexInt == INT_INVALID ? NAN : vocIndexInt / 10.0f; + noxIndex = noxIndexInt == INT_INVALID ? NAN : noxIndexInt / 10.0f; + + return NoError; +} + +uint16_t SensirionI2CSen5x::readMeasuredValuesAsIntegers( + uint16_t& massConcentrationPm1p0, uint16_t& massConcentrationPm2p5, + uint16_t& massConcentrationPm4p0, uint16_t& massConcentrationPm10p0, + int16_t& ambientHumidity, int16_t& ambientTemperature, int16_t& vocIndex, + int16_t& noxIndex) { + uint16_t error = 0; + uint8_t buffer[24]; + SensirionI2CTxFrame txFrame = + SensirionI2CTxFrame::createWithUInt16Command(0x3C4, buffer, 24); + + error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, + *_i2cBus); + if (error) { + return error; + } + + delay(20); + + SensirionI2CRxFrame rxFrame(buffer, 24); + error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 24, + rxFrame, *_i2cBus); + if (error) { + return error; + } + + error |= rxFrame.getUInt16(massConcentrationPm1p0); + error |= rxFrame.getUInt16(massConcentrationPm2p5); + error |= rxFrame.getUInt16(massConcentrationPm4p0); + error |= rxFrame.getUInt16(massConcentrationPm10p0); + error |= rxFrame.getInt16(ambientHumidity); + error |= rxFrame.getInt16(ambientTemperature); + error |= rxFrame.getInt16(vocIndex); + error |= rxFrame.getInt16(noxIndex); + return error; +} + +uint16_t SensirionI2CSen5x::readMeasuredRawValues(int16_t& rawHumidity, + int16_t& rawTemperature, + uint16_t& rawVoc, + uint16_t& rawNox) { + uint16_t error = 0; + uint8_t buffer[12]; + SensirionI2CTxFrame txFrame = + SensirionI2CTxFrame::createWithUInt16Command(0x3D2, buffer, 12); + + error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, + *_i2cBus); + if (error) { + return error; + } + + delay(20); + + SensirionI2CRxFrame rxFrame(buffer, 12); + error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 12, + rxFrame, *_i2cBus); + if (error) { + return error; + } + + error |= rxFrame.getInt16(rawHumidity); + error |= rxFrame.getInt16(rawTemperature); + error |= rxFrame.getUInt16(rawVoc); + error |= rxFrame.getUInt16(rawNox); + return error; +} + +uint16_t SensirionI2CSen5x::readMeasuredValuesSen50( + float& massConcentrationPm1p0, float& massConcentrationPm2p5, + float& massConcentrationPm4p0, float& massConcentrationPm10p0) { + + uint16_t error = 0; + float ambientHumidityDummy; + float ambientTemperatureDummy; + float vocIndexDummy; + float noxIndexDummy; + error = readMeasuredValues(massConcentrationPm1p0, massConcentrationPm2p5, + massConcentrationPm4p0, massConcentrationPm10p0, + ambientHumidityDummy, ambientTemperatureDummy, + vocIndexDummy, noxIndexDummy); + return error; +} + +uint16_t SensirionI2CSen5x::readMeasuredPmValues( + float& massConcentrationPm1p0, float& massConcentrationPm2p5, + float& massConcentrationPm4p0, float& massConcentrationPm10p0, + float& numberConcentrationPm0p5, float& numberConcentrationPm1p0, + float& numberConcentrationPm2p5, float& numberConcentrationPm4p0, + float& numberConcentrationPm10p0, float& typicalParticleSize) { + + uint16_t error = 0; + uint16_t massConcentrationPm1p0Int; + uint16_t massConcentrationPm2p5Int; + uint16_t massConcentrationPm4p0Int; + uint16_t massConcentrationPm10p0Int; + uint16_t numberConcentrationPm0p5Int; + uint16_t numberConcentrationPm1p0Int; + uint16_t numberConcentrationPm2p5Int; + uint16_t numberConcentrationPm4p0Int; + uint16_t numberConcentrationPm10p0Int; + uint16_t typicalParticleSizeInt; + + error = readMeasuredPmValuesAsIntegers( + massConcentrationPm1p0Int, massConcentrationPm2p5Int, + massConcentrationPm4p0Int, massConcentrationPm10p0Int, + numberConcentrationPm0p5Int, numberConcentrationPm1p0Int, + numberConcentrationPm2p5Int, numberConcentrationPm4p0Int, + numberConcentrationPm10p0Int, typicalParticleSizeInt); + + if (error) { + return error; + } + + massConcentrationPm1p0 = massConcentrationPm1p0Int == UINT_INVALID + ? NAN + : massConcentrationPm1p0Int / 10.0f; + massConcentrationPm2p5 = massConcentrationPm2p5Int == UINT_INVALID + ? NAN + : massConcentrationPm2p5Int / 10.0f; + massConcentrationPm4p0 = massConcentrationPm4p0Int == UINT_INVALID + ? NAN + : massConcentrationPm4p0Int / 10.0f; + massConcentrationPm10p0 = massConcentrationPm10p0Int == UINT_INVALID + ? NAN + : massConcentrationPm10p0Int / 10.0f; + numberConcentrationPm0p5 = numberConcentrationPm0p5Int == UINT_INVALID + ? NAN + : numberConcentrationPm0p5Int / 10.0f; + numberConcentrationPm1p0 = numberConcentrationPm1p0Int == UINT_INVALID + ? NAN + : numberConcentrationPm1p0Int / 10.0f; + numberConcentrationPm2p5 = numberConcentrationPm2p5Int == UINT_INVALID + ? NAN + : numberConcentrationPm2p5Int / 10.0f; + numberConcentrationPm4p0 = numberConcentrationPm4p0Int == UINT_INVALID + ? NAN + : numberConcentrationPm4p0Int / 10.0f; + numberConcentrationPm10p0 = numberConcentrationPm10p0Int == UINT_INVALID + ? NAN + : numberConcentrationPm10p0Int / 10.0f; + typicalParticleSize = typicalParticleSizeInt == UINT_INVALID + ? NAN + : typicalParticleSizeInt / 1000.0f; + + return NoError; +} + +uint16_t SensirionI2CSen5x::readMeasuredPmValuesAsIntegers( + uint16_t& massConcentrationPm1p0, uint16_t& massConcentrationPm2p5, + uint16_t& massConcentrationPm4p0, uint16_t& massConcentrationPm10p0, + uint16_t& numberConcentrationPm0p5, uint16_t& numberConcentrationPm1p0, + uint16_t& numberConcentrationPm2p5, uint16_t& numberConcentrationPm4p0, + uint16_t& numberConcentrationPm10p0, uint16_t& typicalParticleSize) { + uint16_t error = 0; + uint8_t buffer[30]; + SensirionI2CTxFrame txFrame = + SensirionI2CTxFrame::createWithUInt16Command(0x413, buffer, 30); + + error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, + *_i2cBus); + if (error) { + return error; + } + + delay(20); + + SensirionI2CRxFrame rxFrame(buffer, 30); + error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 30, + rxFrame, *_i2cBus); + if (error) { + return error; + } + + error |= rxFrame.getUInt16(massConcentrationPm1p0); + error |= rxFrame.getUInt16(massConcentrationPm2p5); + error |= rxFrame.getUInt16(massConcentrationPm4p0); + error |= rxFrame.getUInt16(massConcentrationPm10p0); + error |= rxFrame.getUInt16(numberConcentrationPm0p5); + error |= rxFrame.getUInt16(numberConcentrationPm1p0); + error |= rxFrame.getUInt16(numberConcentrationPm2p5); + error |= rxFrame.getUInt16(numberConcentrationPm4p0); + error |= rxFrame.getUInt16(numberConcentrationPm10p0); + error |= rxFrame.getUInt16(typicalParticleSize); + return error; +} + +uint16_t SensirionI2CSen5x::startFanCleaning() { + uint16_t error = 0; + uint8_t buffer[2]; + SensirionI2CTxFrame txFrame = + SensirionI2CTxFrame::createWithUInt16Command(0x5607, buffer, 2); + + error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, + *_i2cBus); + delay(20); + return error; +} + +uint16_t SensirionI2CSen5x::setTemperatureOffsetSimple(float tempOffset) { + int16_t defaultSlope = 0; + uint16_t defaultTimeConstant = 0; + int16_t tempOffsetTicks = static_cast(tempOffset * 200); + return setTemperatureOffsetParameters(tempOffsetTicks, defaultSlope, + defaultTimeConstant); +} + +uint16_t SensirionI2CSen5x::getTemperatureOffsetSimple(float& tempOffset) { + int16_t tempOffsetTicks; + int16_t slope; + uint16_t timeConstant; + uint16_t error = 0; + + error = + getTemperatureOffsetParameters(tempOffsetTicks, slope, timeConstant); + if (error) { + return error; + } + + tempOffset = static_cast(tempOffsetTicks) / 200.0f; + + return NoError; +} + +uint16_t SensirionI2CSen5x::setTemperatureOffsetParameters( + int16_t tempOffset, int16_t slope, uint16_t timeConstant) { + uint16_t error = 0; + uint8_t buffer[11]; + SensirionI2CTxFrame txFrame = + SensirionI2CTxFrame::createWithUInt16Command(0x60B2, buffer, 11); + + error |= txFrame.addInt16(tempOffset); + error |= txFrame.addInt16(slope); + error |= txFrame.addUInt16(timeConstant); + + if (error) { + return error; + } + + error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, + *_i2cBus); + delay(20); + return error; +} + +uint16_t SensirionI2CSen5x::getTemperatureOffsetParameters( + int16_t& tempOffset, int16_t& slope, uint16_t& timeConstant) { + uint16_t error = 0; + uint8_t buffer[9]; + SensirionI2CTxFrame txFrame = + SensirionI2CTxFrame::createWithUInt16Command(0x60B2, buffer, 9); + + error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, + *_i2cBus); + if (error) { + return error; + } + + delay(20); + + SensirionI2CRxFrame rxFrame(buffer, 9); + error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 9, + rxFrame, *_i2cBus); + if (error) { + return error; + } + + error |= rxFrame.getInt16(tempOffset); + error |= rxFrame.getInt16(slope); + error |= rxFrame.getUInt16(timeConstant); + return error; +} + +uint16_t SensirionI2CSen5x::setWarmStartParameter(uint16_t warmStart) { + uint16_t error = 0; + uint8_t buffer[5]; + SensirionI2CTxFrame txFrame = + SensirionI2CTxFrame::createWithUInt16Command(0x60C6, buffer, 5); + + error |= txFrame.addUInt16(warmStart); + + if (error) { + return error; + } + + error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, + *_i2cBus); + delay(20); + return error; +} + +uint16_t SensirionI2CSen5x::getWarmStartParameter(uint16_t& warmStart) { + uint16_t error = 0; + uint8_t buffer[3]; + SensirionI2CTxFrame txFrame = + SensirionI2CTxFrame::createWithUInt16Command(0x60C6, buffer, 3); + + error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, + *_i2cBus); + if (error) { + return error; + } + + delay(20); + + SensirionI2CRxFrame rxFrame(buffer, 3); + error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 3, + rxFrame, *_i2cBus); + if (error) { + return error; + } + + error |= rxFrame.getUInt16(warmStart); + return error; +} + +uint16_t SensirionI2CSen5x::setVocAlgorithmTuningParameters( + int16_t indexOffset, int16_t learningTimeOffsetHours, + int16_t learningTimeGainHours, int16_t gatingMaxDurationMinutes, + int16_t stdInitial, int16_t gainFactor) { + uint16_t error = 0; + uint8_t buffer[20]; + SensirionI2CTxFrame txFrame = + SensirionI2CTxFrame::createWithUInt16Command(0x60D0, buffer, 20); + + error |= txFrame.addInt16(indexOffset); + error |= txFrame.addInt16(learningTimeOffsetHours); + error |= txFrame.addInt16(learningTimeGainHours); + error |= txFrame.addInt16(gatingMaxDurationMinutes); + error |= txFrame.addInt16(stdInitial); + error |= txFrame.addInt16(gainFactor); + + if (error) { + return error; + } + + error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, + *_i2cBus); + delay(20); + return error; +} + +uint16_t SensirionI2CSen5x::getVocAlgorithmTuningParameters( + int16_t& indexOffset, int16_t& learningTimeOffsetHours, + int16_t& learningTimeGainHours, int16_t& gatingMaxDurationMinutes, + int16_t& stdInitial, int16_t& gainFactor) { + uint16_t error = 0; + uint8_t buffer[18]; + SensirionI2CTxFrame txFrame = + SensirionI2CTxFrame::createWithUInt16Command(0x60D0, buffer, 18); + + error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, + *_i2cBus); + if (error) { + return error; + } + + delay(20); + + SensirionI2CRxFrame rxFrame(buffer, 18); + error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 18, + rxFrame, *_i2cBus); + if (error) { + return error; + } + + error |= rxFrame.getInt16(indexOffset); + error |= rxFrame.getInt16(learningTimeOffsetHours); + error |= rxFrame.getInt16(learningTimeGainHours); + error |= rxFrame.getInt16(gatingMaxDurationMinutes); + error |= rxFrame.getInt16(stdInitial); + error |= rxFrame.getInt16(gainFactor); + return error; +} + +uint16_t SensirionI2CSen5x::setNoxAlgorithmTuningParameters( + int16_t indexOffset, int16_t learningTimeOffsetHours, + int16_t learningTimeGainHours, int16_t gatingMaxDurationMinutes, + int16_t stdInitial, int16_t gainFactor) { + uint16_t error = 0; + uint8_t buffer[20]; + SensirionI2CTxFrame txFrame = + SensirionI2CTxFrame::createWithUInt16Command(0x60E1, buffer, 20); + + error |= txFrame.addInt16(indexOffset); + error |= txFrame.addInt16(learningTimeOffsetHours); + error |= txFrame.addInt16(learningTimeGainHours); + error |= txFrame.addInt16(gatingMaxDurationMinutes); + error |= txFrame.addInt16(stdInitial); + error |= txFrame.addInt16(gainFactor); + + if (error) { + return error; + } + + error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, + *_i2cBus); + delay(20); + return error; +} + +uint16_t SensirionI2CSen5x::getNoxAlgorithmTuningParameters( + int16_t& indexOffset, int16_t& learningTimeOffsetHours, + int16_t& learningTimeGainHours, int16_t& gatingMaxDurationMinutes, + int16_t& stdInitial, int16_t& gainFactor) { + uint16_t error = 0; + uint8_t buffer[18]; + SensirionI2CTxFrame txFrame = + SensirionI2CTxFrame::createWithUInt16Command(0x60E1, buffer, 18); + + error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, + *_i2cBus); + if (error) { + return error; + } + + delay(20); + + SensirionI2CRxFrame rxFrame(buffer, 18); + error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 18, + rxFrame, *_i2cBus); + if (error) { + return error; + } + + error |= rxFrame.getInt16(indexOffset); + error |= rxFrame.getInt16(learningTimeOffsetHours); + error |= rxFrame.getInt16(learningTimeGainHours); + error |= rxFrame.getInt16(gatingMaxDurationMinutes); + error |= rxFrame.getInt16(stdInitial); + error |= rxFrame.getInt16(gainFactor); + return error; +} + +uint16_t SensirionI2CSen5x::setRhtAccelerationMode(uint16_t mode) { + uint16_t error = 0; + uint8_t buffer[5]; + SensirionI2CTxFrame txFrame = + SensirionI2CTxFrame::createWithUInt16Command(0x60F7, buffer, 5); + + error |= txFrame.addUInt16(mode); + + if (error) { + return error; + } + + error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, + *_i2cBus); + delay(20); + return error; +} + +uint16_t SensirionI2CSen5x::getRhtAccelerationMode(uint16_t& mode) { + uint16_t error = 0; + uint8_t buffer[3]; + SensirionI2CTxFrame txFrame = + SensirionI2CTxFrame::createWithUInt16Command(0x60F7, buffer, 3); + + error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, + *_i2cBus); + if (error) { + return error; + } + + delay(20); + + SensirionI2CRxFrame rxFrame(buffer, 3); + error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 3, + rxFrame, *_i2cBus); + if (error) { + return error; + } + + error |= rxFrame.getUInt16(mode); + return error; +} + +uint16_t SensirionI2CSen5x::setVocAlgorithmState(const uint8_t state[], + uint8_t stateSize) { + uint16_t error = 0; + uint8_t buffer[14]; + SensirionI2CTxFrame txFrame = + SensirionI2CTxFrame::createWithUInt16Command(0x6181, buffer, 14); + + error |= txFrame.addBytes(state, stateSize); + + if (error) { + return error; + } + + error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, + *_i2cBus); + delay(20); + return error; +} + +uint16_t SensirionI2CSen5x::getVocAlgorithmState(uint8_t state[], + uint8_t stateSize) { + uint16_t error = 0; + uint8_t buffer[12]; + SensirionI2CTxFrame txFrame = + SensirionI2CTxFrame::createWithUInt16Command(0x6181, buffer, 12); + + error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, + *_i2cBus); + if (error) { + return error; + } + + delay(20); + + SensirionI2CRxFrame rxFrame(buffer, 12); + error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 12, + rxFrame, *_i2cBus); + if (error) { + return error; + } + + error |= rxFrame.getBytes(state, stateSize); + return error; +} + +uint16_t SensirionI2CSen5x::setFanAutoCleaningInterval(uint32_t interval) { + uint16_t error = 0; + uint8_t buffer[8]; + SensirionI2CTxFrame txFrame = + SensirionI2CTxFrame::createWithUInt16Command(0x8004, buffer, 8); + + error |= txFrame.addUInt32(interval); + + if (error) { + return error; + } + + error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, + *_i2cBus); + delay(20); + return error; +} + +uint16_t SensirionI2CSen5x::getFanAutoCleaningInterval(uint32_t& interval) { + uint16_t error = 0; + uint8_t buffer[6]; + SensirionI2CTxFrame txFrame = + SensirionI2CTxFrame::createWithUInt16Command(0x8004, buffer, 6); + + error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, + *_i2cBus); + if (error) { + return error; + } + + delay(20); + + SensirionI2CRxFrame rxFrame(buffer, 6); + error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 6, + rxFrame, *_i2cBus); + if (error) { + return error; + } + + error |= rxFrame.getUInt32(interval); + return error; +} + +uint16_t SensirionI2CSen5x::getProductName(unsigned char productName[], + uint8_t productNameSize) { + uint16_t error = 0; + uint8_t buffer[48]; + SensirionI2CTxFrame txFrame = + SensirionI2CTxFrame::createWithUInt16Command(0xD014, buffer, 48); + + error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, + *_i2cBus); + if (error) { + return error; + } + + delay(50); + + SensirionI2CRxFrame rxFrame(buffer, 48); + error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 48, + rxFrame, *_i2cBus); + if (error) { + return error; + } + + error |= rxFrame.getBytes(productName, productNameSize); + return error; +} + +uint16_t SensirionI2CSen5x::getSerialNumber(unsigned char serialNumber[], + uint8_t serialNumberSize) { + uint16_t error = 0; + uint8_t buffer[48]; + SensirionI2CTxFrame txFrame = + SensirionI2CTxFrame::createWithUInt16Command(0xD033, buffer, 48); + + error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, + *_i2cBus); + if (error) { + return error; + } + + delay(50); + + SensirionI2CRxFrame rxFrame(buffer, 48); + error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 48, + rxFrame, *_i2cBus); + if (error) { + return error; + } + + error |= rxFrame.getBytes(serialNumber, serialNumberSize); + return error; +} + +uint16_t +SensirionI2CSen5x::getVersion(uint8_t& firmwareMajor, uint8_t& firmwareMinor, + bool& firmwareDebug, uint8_t& hardwareMajor, + uint8_t& hardwareMinor, uint8_t& protocolMajor, + uint8_t& protocolMinor) { + uint16_t error = 0; + uint8_t buffer[12]; + SensirionI2CTxFrame txFrame = + SensirionI2CTxFrame::createWithUInt16Command(0xD100, buffer, 12); + + error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, + *_i2cBus); + if (error) { + return error; + } + + delay(20); + + SensirionI2CRxFrame rxFrame(buffer, 12); + error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 12, + rxFrame, *_i2cBus); + if (error) { + return error; + } + + error |= rxFrame.getUInt8(firmwareMajor); + error |= rxFrame.getUInt8(firmwareMinor); + error |= rxFrame.getBool(firmwareDebug); + error |= rxFrame.getUInt8(hardwareMajor); + error |= rxFrame.getUInt8(hardwareMinor); + error |= rxFrame.getUInt8(protocolMajor); + error |= rxFrame.getUInt8(protocolMinor); + uint8_t padding; + error |= rxFrame.getUInt8(padding); // remove padding + return error; +} + +uint16_t SensirionI2CSen5x::readDeviceStatus(uint32_t& deviceStatus) { + uint16_t error = 0; + uint8_t buffer[6]; + SensirionI2CTxFrame txFrame = + SensirionI2CTxFrame::createWithUInt16Command(0xD206, buffer, 6); + + error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, + *_i2cBus); + if (error) { + return error; + } + + delay(20); + + SensirionI2CRxFrame rxFrame(buffer, 6); + error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 6, + rxFrame, *_i2cBus); + if (error) { + return error; + } + + error |= rxFrame.getUInt32(deviceStatus); + return error; +} + +uint16_t SensirionI2CSen5x::readAndClearDeviceStatus(uint32_t& deviceStatus) { + uint16_t error = 0; + uint8_t buffer[6]; + SensirionI2CTxFrame txFrame = + SensirionI2CTxFrame::createWithUInt16Command(0xD210, buffer, 6); + + error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, + *_i2cBus); + if (error) { + return error; + } + + delay(20); + + SensirionI2CRxFrame rxFrame(buffer, 6); + error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 6, + rxFrame, *_i2cBus); + if (error) { + return error; + } + + error |= rxFrame.getUInt32(deviceStatus); + return error; +} + +uint16_t SensirionI2CSen5x::deviceReset() { + uint16_t error = 0; + uint8_t buffer[2]; + SensirionI2CTxFrame txFrame = + SensirionI2CTxFrame::createWithUInt16Command(0xD304, buffer, 2); + + error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, + *_i2cBus); + delay(200); + return error; +} diff --git a/lib/lib_i2c/Sensirion_I2C_SEN5X/src/SensirionI2CSen5x.h b/lib/lib_i2c/Sensirion_I2C_SEN5X/src/SensirionI2CSen5x.h new file mode 100644 index 000000000..a572ff3fe --- /dev/null +++ b/lib/lib_i2c/Sensirion_I2C_SEN5X/src/SensirionI2CSen5x.h @@ -0,0 +1,857 @@ +/* + * THIS FILE IS AUTOMATICALLY GENERATED + * + * I2C-Generator: 0.3.0 + * Yaml Version: 2.1.3 + * Template Version: 0.7.0-112-g190ecaa + */ +/* + * Copyright (c) 2021, Sensirion AG + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of Sensirion AG nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SENSIRIONI2CSEN5X_H +#define SENSIRIONI2CSEN5X_H + +#include + +#include + +class SensirionI2CSen5x { + + public: + SensirionI2CSen5x(); + /** + * begin() - Initializes the SensirionI2CSen5x class. + * + * @param serial Arduino stream object to be communicated with. + * + */ + void begin(TwoWire& i2cBus); + + /** + * startMeasurement() - Starts a continuous measurement. + + * After starting the measurement, it takes some time (~1s) until the first + * measurement results are available. You could poll with the command + * 0x0202 \"Read Data Ready\" to check when the results are ready to read. + * + * This command is only available in idle mode. If the device is already + * in any measure mode, this command has no effect. + * + * @return 0 on success, an error code otherwise + */ + uint16_t startMeasurement(void); + + /** + * startMeasurementWithoutPm() - Starts a continuous measurement without PM. + * Only humidity, temperature, VOC and NOx are available in this mode. Laser + * and fan are switched off to keep power consumption low. + * + * After starting the measurement, it takes some time (~1s) until the first + * measurement results are available. You could poll with the command + * 0x0202 \"Read Data Ready\" to check when the results are ready to read. + * + * This command is only available in idle mode. If the device is already + * in any measure mode, this command has no effect. + * + * Supported sensors: SEN54, SEN55 + * + * @return 0 on success, an error code otherwise + */ + uint16_t startMeasurementWithoutPm(void); + + /** + * stopMeasurement() - Stops the measurement and returns to idle mode. + * + * If the device is already in idle mode, this command has no effect. + * + * @return 0 on success, an error code otherwise + */ + uint16_t stopMeasurement(void); + + /** + * readDataReady() - This command can be used to check if new measurement + * results are ready to read. The data ready flag is automatically reset + * after reading the measurement values with the 0x03.. \"Read Measured + * Values\" commands. + * + * @note During fan (auto-)cleaning, no measurement data is available for + * several seconds and thus this flag will not be set until cleaning has + * finished. So please expect gaps of several seconds at any time if fan + * auto-cleaning is enabled. + * + * @param padding Padding byte, always 0x00. + * + * @param dataReady True (0x01) if data is ready, False (0x00) if not. When + * no measurement is running, False will be returned. + * + * @return 0 on success, an error code otherwise + */ + uint16_t readDataReady(bool& dataReady); + + /** + * readMeasuredValues() - Returns the measured values. + * + * The command 0x0202 \"Read Data Ready\" can be used to check if new + * data is available since the last read operation. If no new data is + * available, the previous values will be returned again. If no data is + * available at all (e.g. measurement not running for at least one + * second), all values will be NAN. + * + * @param massConcentrationPm1p0 PM1.0 [µg/m³] + * Note: If this value is unknown, NAN is returned.* + * + * @param massConcentrationPm2p5 PM2.5 [µg/m³] + * Note: If this value is unknown, NAN is returned.* + * + * @param massConcentrationPm4p0 PM4.0 [µg/m³] + * Note: If this value is unknown, NAN is returned.* + * + * @param massConcentrationPm10p0 PM10.0 [µg/m³] + * Note: If this value is unknown, NAN is returned.* + * + * @param ambientHumidity RH [%] + * Note: If this value is unknown, NAN is returned.* + * + * @param ambientTemperature T [°C] + * Note: If this value is unknown, NAN is returned.* + * + * @param vocIndex VOC Index + * Note: If this value is unknown, NAN is returned.* + * + * @param noxIndex NOx Index + * Note: If this value is unknown, which is true for SEN54, + * NAN is returned. During the first 10..11 seconds after + * power-on or device reset, this value will be NAN as well.* + * + * @return 0 on success, an error code otherwise + */ + uint16_t readMeasuredValues(float& massConcentrationPm1p0, + float& massConcentrationPm2p5, + float& massConcentrationPm4p0, + float& massConcentrationPm10p0, + float& ambientHumidity, + float& ambientTemperature, float& vocIndex, + float& noxIndex); + + /** + * readMeasuredValuesAsIntegers() - Returns the measured values + * without scaling factors applied. + * + * The command 0x0202 \"Read Data Ready\" can be used to check if new + * data is available since the last read operation. If no new data is + * available, the previous values will be returned again. If no data is + * available at all (e.g. measurement not running for at least one + * second), all values will be at their upper limit (0xFFFF for `uint16`, + * 0x7FFF for `int16`). + * + * @param massConcentrationPm1p0 Value is scaled with factor 10: + * PM1.0 [µg/m³] = value / 10 + * Note: If this value is unknown, 0xFFFF is returned.* + * + * @param massConcentrationPm2p5 Value is scaled with factor 10: + * PM2.5 [µg/m³] = value / 10 + * Note: If this value is unknown, 0xFFFF is returned.* + * + * @param massConcentrationPm4p0 Value is scaled with factor 10: + * PM4.0 [µg/m³] = value / 10 + * Note: If this value is unknown, 0xFFFF is returned.* + * + * @param massConcentrationPm10p0 Value is scaled with factor 10: + * PM10.0 [µg/m³] = value / 10 + * Note: If this value is unknown, 0xFFFF is returned.* + * + * @param ambientHumidity Value is scaled with factor 100: + * RH [%] = value /100 + * Note: If this value is unknown, 0x7FFF is returned.* + * + * @param ambientTemperature Value is scaled with factor 200: + * T [°C] = value / 200 + * Note: If this value is unknown, 0x7FFF is returned.* + * + * @param vocIndex Value is scaled with factor 10: VOC Index = value / 10 + * Note: If this value is unknown, 0x7FFF is returned.* + * + * @param noxIndex Value is scaled with factor 10: NOx Index = value / 10 + * Note: If this value is unknown, which is the case for SEN54, + * 0x7FFF is returned. During the first 10..11 seconds after power-on + * or device reset, this value will be 0x7FFF as well.* + * + * @return 0 on success, an error code otherwise + */ + uint16_t readMeasuredValuesAsIntegers(uint16_t& massConcentrationPm1p0, + uint16_t& massConcentrationPm2p5, + uint16_t& massConcentrationPm4p0, + uint16_t& massConcentrationPm10p0, + int16_t& ambientHumidity, + int16_t& ambientTemperature, + int16_t& vocIndex, int16_t& noxIndex); + + /** + * readMeasuredRawValues() - Returns the measured raw values. + * + * The command 0x0202 \"Read Data Ready\" can be used to check if new + * data is available since the last read operation. If no new data is + * available, the previous values will be returned again. If no data + * is available at all (e.g. measurement not running for at least one + * second), all values will be at their upper limit (0xFFFF for `uint16`, + * 0x7FFF for `int16`). + * + * Supported sensors: SEN54 (no NOx), SEN55 + * + * @param rawHumidity Value is scaled with factor 100: RH [%] = value / 100 + * Note: If this value is unknown, 0x7FFF is returned.* + * + * @param rawTemperature Value is scaled with factor 200: + * T [°C] = value / 200 + * Note: If this value is unknown, 0x7FFF is returned.* + * + * @param rawVoc Raw measured VOC ticks without scale factor. + * Note: If this value is unknown, 0xFFFF is returned.* + * + * @param rawNox Raw measured NOx ticks without scale factor. + * Note: If this value is unknown, which is the case for SEN54, + * 0x7FFF is returned. During the first 10..11 seconds after power-on + * or device reset, this value will be 0x7FFF as well.* + * + * @return 0 on success, an error code otherwise + */ + uint16_t readMeasuredRawValues(int16_t& rawHumidity, + int16_t& rawTemperature, uint16_t& rawVoc, + uint16_t& rawNox); + + /** + * readMeasuredValuesSen50() - Returns the measured values for SEN50. + * + * The command 0x0202 \"Read Data Ready\" can be used to check if new + * data is available since the last read operation. If no new data is + * available, the previous values will be returned again. If no data is + * available at all (e.g. measurement not running for at least one + * second), all values will be NAN. + * + * @param massConcentrationPm1p0 PM1.0 [µg/m³] + * Note: If this value is unknown, NAN is returned.* + * + * @param massConcentrationPm2p5 PM2.5 [µg/m³] + * Note: If this value is unknown, NAN is returned.* + * + * @param massConcentrationPm4p0 PM4.0 [µg/m³] + * Note: If this value is unknown, NAN is returned.* + * + * @param massConcentrationPm10p0 PM10.0 [µg/m³] + * Note: If this value is unknown, NAN is returned.* + * + * @return 0 on success, an error code otherwise + */ + uint16_t readMeasuredValuesSen50(float& massConcentrationPm1p0, + float& massConcentrationPm2p5, + float& massConcentrationPm4p0, + float& massConcentrationPm10p0); + + /** + * readMeasuredPmValues() - Returns the measured particulate matter values. + * + * The command 0x0202 \"Read Data Ready\" can be used to check if new + * data is available since the last read operation. If no new data is + * available, the previous values will be returned again. If no data + * is available at all (e.g. measurement not running for at least one + * second), all values will be NAN. + * + * @param massConcentrationPm1p0 PM1.0 [µg/m³] + * Note: If this value is unknown, NAN is returned.* + * + * @param massConcentrationPm2p5 PM2.5 [µg/m³] + * Note: If this value is unknown, NAN is returned.* + * + * @param massConcentrationPm4p0 PM4.0 [µg/m³] + * Note: If this value is unknown, NAN is returned.* + * + * @param massConcentrationPm10p0 PM10.0 [µg/m³] + * Note: If this value is unknown, NAN is returned.* + * + * @param numberConcentrationPm0p5 PM0.5 [#/cm³] + * Note: If this value is unknown, NAN is returned.* + * + * @param numberConcentrationPm1p0 PM1.0 [#/cm³] + * Note: If this value is unknown, NAN is returned.* + * + * @param numberConcentrationPm2p5 PM2.5 [#/cm³] + * Note: If this value is unknown, NAN is returned.* + * + * @param numberConcentrationPm4p0 PM4.0 [#/cm³] + * Note: If this value is unknown, NAN is returned.* + * + * @param numberConcentrationPm10p0 PM10.0 [#/cm³] + * Note: If this value is unknown, NAN is returned.* + * + * @param typicalParticleSize Size [µm] + * Note: If this value is unknown, NAN is returned.* + * + * @return 0 on success, an error code otherwise + */ + uint16_t readMeasuredPmValues( + float& massConcentrationPm1p0, float& massConcentrationPm2p5, + float& massConcentrationPm4p0, float& massConcentrationPm10p0, + float& numberConcentrationPm0p5, float& numberConcentrationPm1p0, + float& numberConcentrationPm2p5, float& numberConcentrationPm4p0, + float& numberConcentrationPm10p0, float& typicalParticleSize); + + /** + * readMeasuredPmValuesAsIntegers() - Returns the measured particulate + * matter values. + * + * The command 0x0202 \"Read Data Ready\" can be used to check if new + * data is available since the last read operation. If no new data is + * available, the previous values will be returned again. If no data + * is available at all (e.g. measurement not running for at least one + * second), all values will be 0xFFFF. + * + * @param massConcentrationPm1p0 Value is scaled with factor 10: + * PM1.0 [µg/m³] = value / 1 + * Note: If this value is unknown, 0xFFFF is returned.* + * + * @param massConcentrationPm2p5 Value is scaled with factor 10: + * PM2.5 [µg/m³] = value / 1 + * Note: If this value is unknown, 0xFFFF is returned.* + * + * @param massConcentrationPm4p0 Value is scaled with factor 10: + * PM4.0 [µg/m³] = value / 1 + * Note: If this value is unknown, 0xFFFF is returned.* + * + * @param massConcentrationPm10p0 Value is scaled with factor 10: + * PM10.0 [µg/m³] = value / 1 + * Note: If this value is unknown, 0xFFFF is returned.* + * + * @param numberConcentrationPm0p5 Value is scaled with factor 10: + * PM0.5 [#/cm³] = value / 1 + * Note: If this value is unknown, 0xFFFF is returned.* + * + * @param numberConcentrationPm1p0 Value is scaled with factor 10: + * PM1.0 [#/cm³] = value / 1 + * Note: If this value is unknown, 0xFFFF is returned.* + * + * @param numberConcentrationPm2p5 Value is scaled with factor 10: + * PM2.5 [#/cm³] = value / 1 + * Note: If this value is unknown, 0xFFFF is returned.* + * + * @param numberConcentrationPm4p0 Value is scaled with factor 10: + * PM4.0 [#/cm³] = value / 1 + * Note: If this value is unknown, 0xFFFF is returned.* + * + * @param numberConcentrationPm10p0 Value is scaled with factor 10: + * PM10.0 [#/cm³] = value / 10 + * Note: If this value is unknown, 0xFFFF is returned.* + * + * @param typicalParticleSize Value is scaled with factor 1000: + * Size [µm] = value / 1000 + * Note: If this value is unknown, 0xFFFF is returned.* + * + * @return 0 on success, an error code otherwise + */ + uint16_t readMeasuredPmValuesAsIntegers( + uint16_t& massConcentrationPm1p0, uint16_t& massConcentrationPm2p5, + uint16_t& massConcentrationPm4p0, uint16_t& massConcentrationPm10p0, + uint16_t& numberConcentrationPm0p5, uint16_t& numberConcentrationPm1p0, + uint16_t& numberConcentrationPm2p5, uint16_t& numberConcentrationPm4p0, + uint16_t& numberConcentrationPm10p0, uint16_t& typicalParticleSize); + + /** + * startFanCleaning() - Starts the fan cleaning manually. The \"data + * ready\"-flag will be cleared immediately and during the next few seconds, + * no new measurement results will be available (old values will be + * returned). Once the cleaning is finished, the \"data ready\"-flag will be + * set and new measurement results will be available. + * + * When executing this command while cleaning is already active, the + * command does nothing. + * + * If you stop the measurement while fan cleaning is active, the cleaning + * will be aborted immediately. + * + * @note This command is only available in measure mode with PM measurement + * enabled, i.e. only if the fan is already running. In any other state, + * this command does nothing. + * + * @return 0 on success, an error code otherwise + */ + uint16_t startFanCleaning(void); + + /** + * setTemperatureOffsetSimple() - Sets the temperature offset parameter + * in degrees celsius for the device, while leaving the other parameters at + * their default setting. + * + * Supported sensors: SEN54, SEN55 + * + * @param tempOffset Constant temperature offset in degrees celsius. + * The default value is 0. + * + * @return 0 on success, an error code otherwise + */ + uint16_t setTemperatureOffsetSimple(float tempOffset); + + /** + * getTemperatureOffsetSimple() - Gets the temperature offset parameter + * in degrees celsius from the device. + * @note The other parameters, such as slope and time constant may differ + * from the default values, if they were previously set using + * `setTemperatureOffsetParameters`. + * + * Supported sensors: SEN54, SEN55 + * + * @param tempOffset Constant temperature offset in degrees celsius. + * + * @return 0 on success, an error code otherwise + */ + uint16_t getTemperatureOffsetSimple(float& tempOffset); + + /** + * setTemperatureOffsetParameters() - Sets the temperature offset parameters + * for the device. + * + * Supported sensors: SEN54, SEN55 + * + * @param tempOffset Constant temperature offset scaled with factor 200 (T + * [°C] = value / 200). The default value is 0. + * + * @param slope Normalized temperature offset slope scaled with factor 10000 + * (applied factor = value / 10000). The default value is 0. + * + * @param timeConstant Time constant [s] how fast the new slope and offset + * will be applied. After the specified value in seconds, 63% of the new + * slope and offset are applied. A time constant of zero means the new + * values will be applied immediately (within the next measure interval of 1 + * second). + * + * @return 0 on success, an error code otherwise + */ + uint16_t setTemperatureOffsetParameters(int16_t tempOffset, int16_t slope, + uint16_t timeConstant); + + /** + * getTemperatureOffsetParameters() - Gets the temperature offset parameters + * from the device. + * + * Supported sensors: SEN54, SEN55 + * + * @param tempOffset Constant temperature offset scaled with factor 200 (T + * [°C] = value / 200). + * + * @param slope Normalized temperature offset slope scaled with factor 10000 + * (applied factor = value / 10000). + * + * @param timeConstant Time constant [s] how fast the slope and offset are + * applied. After the specified value in seconds, 63% of the new slope and + * offset are applied. + * + * @return 0 on success, an error code otherwise + */ + uint16_t getTemperatureOffsetParameters(int16_t& tempOffset, int16_t& slope, + uint16_t& timeConstant); + + /** + * setWarmStartParameter() - Sets the warm start parameter for the device. + * + * Supported sensors: SEN54, SEN55 + * + * @note This parameter can be changed in any state of the device (and the + * getter immediately returns the new value), but it is applied only the + * next time starting a measurement, i.e. when sending a \"Start + * Measurement\" command! So the parameter needs to be set *before* a + * warm-start measurement is started. + * + * @param warmStart Warm start behavior as a value in the range from 0 (cold + * start) to 65535 (warm start). The default value is 0. + * + * @return 0 on success, an error code otherwise + */ + uint16_t setWarmStartParameter(uint16_t warmStart); + + /** + * getWarmStartParameter() - Gets the warm start parameter from the device. + * + * Supported sensors: SEN54, SEN55 + * + * @param warmStart Warm start behavior as a value in the range from 0 (cold + * start) to 65535 (warm start). + * + * @return 0 on success, an error code otherwise + */ + uint16_t getWarmStartParameter(uint16_t& warmStart); + + /** + * setVocAlgorithmTuningParameters() - Sets the tuning parameters of the VOC + * algorithm. + * + * Supported sensors: SEN54, SEN55 + * + * @note This command is available only in idle mode. In measure mode, this + * command has no effect. In addition, it has no effect if at least one + * parameter is outside the specified range. + * + * @param indexOffset VOC index representing typical (average) conditions. + * Allowed values are in range 1..250. The default value is 100. + * + * @param learningTimeOffsetHours Time constant to estimate the VOC + * algorithm offset from the history in hours. Past events will be forgotten + * after about twice the learning time. Allowed values are in range 1..1000. + * The default value is 12 hours. + * + * @param learningTimeGainHours Time constant to estimate the VOC algorithm + * gain from the history in hours. Past events will be forgotten after about + * twice the learning time. Allowed values are in range 1..1000. The default + * value is 12 hours. + * + * @param gatingMaxDurationMinutes Maximum duration of gating in minutes + * (freeze of estimator during high VOC index signal). Set to zero to + * disable the gating. Allowed values are in range 0..3000. The default + * value is 180 minutes. + * + * @param stdInitial Initial estimate for standard deviation. Lower value + * boosts events during initial learning period, but may result in larger + * device-to-device variations. Allowed values are in range 10..5000. The + * default value is 50. + * + * @param gainFactor Gain factor to amplify or to attenuate the VOC index + * output. Allowed values are in range 1..1000. The default value is 230. + * + * @return 0 on success, an error code otherwise + */ + uint16_t setVocAlgorithmTuningParameters(int16_t indexOffset, + int16_t learningTimeOffsetHours, + int16_t learningTimeGainHours, + int16_t gatingMaxDurationMinutes, + int16_t stdInitial, + int16_t gainFactor); + + /** + * getVocAlgorithmTuningParameters() - Gets the currently set tuning + * parameters of the VOC algorithm. + * + * Supported sensors: SEN54, SEN55 + * + * @param indexOffset VOC index representing typical (average) conditions. + * + * @param learningTimeOffsetHours Time constant to estimate the VOC + * algorithm offset from the history in hours. Past events will be forgotten + * after about twice the learning time. + * + * @param learningTimeGainHours Time constant to estimate the VOC algorithm + * gain from the history in hours. Past events will be forgotten after about + * twice the learning time. + * + * @param gatingMaxDurationMinutes Maximum duration of gating in minutes + * (freeze of estimator during high VOC index signal). Zero disables the + * gating. + * + * @param stdInitial Initial estimate for standard deviation. Lower value + * boosts events during initial learning period, but may result in larger + * device-to-device variations. + * + * @param gainFactor Gain factor to amplify or to attenuate the VOC index + * output. + * + * @return 0 on success, an error code otherwise + */ + uint16_t getVocAlgorithmTuningParameters(int16_t& indexOffset, + int16_t& learningTimeOffsetHours, + int16_t& learningTimeGainHours, + int16_t& gatingMaxDurationMinutes, + int16_t& stdInitial, + int16_t& gainFactor); + + /** + * setNoxAlgorithmTuningParameters() - Sets the tuning parameters of the NOx + * algorithm. + * + * Supported sensors: SEN55 + * + * @note This command is available only in idle mode. In measure mode, this + * command has no effect. In addition, it has no effect if at least one + * parameter is outside the specified range. + * + * @param indexOffset NOx index representing typical (average) conditions. + * Allowed values are in range 1..250. The default value is 1. + * + * @param learningTimeOffsetHours Time constant to estimate the NOx + * algorithm offset from the history in hours. Past events will be forgotten + * after about twice the learning time. Allowed values are in range 1..1000. + * The default value is 12 hours. + * + * @param learningTimeGainHours The time constant to estimate the NOx + * algorithm gain from the history has no impact for NOx. This parameter is + * still in place for consistency reasons with the VOC tuning parameters + * command. This parameter must always be set to 12 hours. + * + * @param gatingMaxDurationMinutes Maximum duration of gating in minutes + * (freeze of estimator during high NOx index signal). Set to zero to + * disable the gating. Allowed values are in range 0..3000. The default + * value is 720 minutes. + * + * @param stdInitial The initial estimate for standard deviation parameter + * has no impact for NOx. This parameter is still in place for consistency + * reasons with the VOC tuning parameters command. This parameter must + * always be set to 50. + * + * @param gainFactor Gain factor to amplify or to attenuate the NOx index + * output. Allowed values are in range 1..1000. The default value is 230. + * + * @return 0 on success, an error code otherwise + */ + uint16_t setNoxAlgorithmTuningParameters(int16_t indexOffset, + int16_t learningTimeOffsetHours, + int16_t learningTimeGainHours, + int16_t gatingMaxDurationMinutes, + int16_t stdInitial, + int16_t gainFactor); + + /** + * getNoxAlgorithmTuningParameters() - Gets the currently set tuning + * parameters of the NOx algorithm. + * + * Supported sensors: SEN55 + * + * @param indexOffset NOx index representing typical (average) conditions. + * + * @param learningTimeOffsetHours Time constant to estimate the NOx + * algorithm offset from the history in hours. Past events will be forgotten + * after about twice the learning time. + * + * @param learningTimeGainHours The time constant to estimate the NOx + * algorithm gain from the history has no impact for NOx. This parameter is + * still in place for consistency reasons with the VOC tuning parameters + * command. + * + * @param gatingMaxDurationMinutes Maximum duration of gating in minutes + * (freeze of estimator during high NOx index signal). Zero disables the + * gating. + * + * @param stdInitial The initial estimate for standard deviation has no + * impact for NOx. This parameter is still in place for consistency reasons + * with the VOC tuning parameters command. + * + * @param gainFactor Gain factor to amplify or to attenuate the NOx index + * output. + * + * @return 0 on success, an error code otherwise + */ + uint16_t getNoxAlgorithmTuningParameters(int16_t& indexOffset, + int16_t& learningTimeOffsetHours, + int16_t& learningTimeGainHours, + int16_t& gatingMaxDurationMinutes, + int16_t& stdInitial, + int16_t& gainFactor); + + /** + * setRhtAccelerationMode() - Sets the RH/T acceleration mode. + * + * Supported sensors: SEN54, SEN55 + * + * @note This parameter can be changed in any state of the device (and the + * getter immediately returns the new value), but it is applied only the + * next time starting a measurement, i.e. when sending a \"Start + * Measurement\" command. So the parameter needs to be set *before* a new + * measurement is started. + * + * @param mode The new RH/T acceleration mode. + * + * @return 0 on success, an error code otherwise + */ + uint16_t setRhtAccelerationMode(uint16_t mode); + + /** + * getRhtAccelerationMode() - Gets the RH/T acceleration mode. + * + * Supported sensors: SEN54, SEN55 + * + * @param mode The current RH/T acceleration mode. + * + * @return 0 on success, an error code otherwise + */ + uint16_t getRhtAccelerationMode(uint16_t& mode); + + /** + * setVocAlgorithmState() - Sets the VOC algorithm state previously received + * with the \"Get VOC Algorithm State\" command. + * + * Supported sensors: SEN54, SEN55 + * + * @note This command is only available in idle mode and the state will be + * applied only once when starting the next measurement. Any further + * measurements (i.e. when stopping and restarting the measure mode) will + * reset the state to initial values. In measure mode, this command has no + * effect. + * + * @param state VOC algorithm state to restore. + * + * @return 0 on success, an error code otherwise + */ + uint16_t setVocAlgorithmState(const uint8_t state[], uint8_t stateSize); + + /** + * getVocAlgorithmState() - Gets the current VOC algorithm state. This data + * can be used to restore the state with the \"Set VOC Algorithm State\" + * command after a short power cycle or device reset. + * + * This command can be used either in measure mode or in idle mode + * (which will then return the state at the time when the measurement + * was stopped). In measure mode, the state can be read each measure + * interval to always have the latest state available, even in case of + * a sudden power loss. + * + * Supported sensors: SEN54, SEN55 + * + * @param state Current VOC algorithm state. + * + * @return 0 on success, an error code otherwise + */ + uint16_t getVocAlgorithmState(uint8_t state[], uint8_t stateSize); + + /** + * setFanAutoCleaningInterval() - Sets the fan auto cleaning interval for + * the device. + * + * @param interval Fan auto cleaning interval [s]. Set to zero to disable + * auto cleaning. + * + * @return 0 on success, an error code otherwise + */ + uint16_t setFanAutoCleaningInterval(uint32_t interval); + + /** + * getFanAutoCleaningInterval() - Gets the fan auto cleaning interval from + * the device. + * + * @param interval Fan auto cleaning interval [s]. Zero means auto cleaning + * is disabled. + * + * @return 0 on success, an error code otherwise + */ + uint16_t getFanAutoCleaningInterval(uint32_t& interval); + + /** + * getProductName() - Gets the product name from the device. + * + * @param productName Null-terminated ASCII string containing the product + * name. Up to 32 characters can be read from the device. + * + * @return 0 on success, an error code otherwise + */ + uint16_t getProductName(unsigned char productName[], + uint8_t productNameSize); + + /** + * getSerialNumber() - Gets the serial number from the device. + * + * @param serialNumber Null-terminated ASCII string containing the serial + * number. Up to 32 characters can be read from the device. + * + * @return 0 on success, an error code otherwise + */ + uint16_t getSerialNumber(unsigned char serialNumber[], + uint8_t serialNumberSize); + + /** + * getVersion() - Gets the version information for the hardware, firmware + * and communication protocol. + * + * @param firmwareMajor Firmware major version number. + * + * @param firmwareMinor Firmware minor version number. + * + * @param firmwareDebug Firmware debug state. If the debug state is set, the + * firmware is in development. + * + * @param hardwareMajor Hardware major version number. + * + * @param hardwareMinor Hardware minor version number. + * + * @param protocolMajor Protocol major version number. + * + * @param protocolMinor Protocol minor version number. + * + * @param padding Padding byte, ignore this. + * + * @return 0 on success, an error code otherwise + */ + uint16_t getVersion(uint8_t& firmwareMajor, uint8_t& firmwareMinor, + bool& firmwareDebug, uint8_t& hardwareMajor, + uint8_t& hardwareMinor, uint8_t& protocolMajor, + uint8_t& protocolMinor); + + /** + * readDeviceStatus() - Reads the current device status. + * + * Use this command to get detailed information about the device status. + * The device status is encoded in flags. Each device status flag + * represents a single bit in a 32-bit integer value. If more than one + * error is present, the device status register value is the sum of the + * corresponding flag values. For details about the available flags, + * refer to the device status flags documentation. + * + * @note The status flags of type \"Error\" are sticky, i.e. they are not + * cleared automatically even if the error condition no longer exists. So + * they can only be cleared manually with the command 0xD210 \"Read And + * Clear Device Status\" or with a device reset. All other flags are not + * sticky, i.e. they are cleared automatically if the trigger condition + * disappears. + * + * @param deviceStatus Device status (32 flags as an integer value). For + * details, please refer to the device status flags documentation. + * + * @return 0 on success, an error code otherwise + */ + uint16_t readDeviceStatus(uint32_t& deviceStatus); + + /** + * readAndClearDeviceStatus() - Reads the current device status (like + * command 0xD206 \"Read Device Status\") and afterwards clears all flags. + * + * @param deviceStatus Device status (32 flags as an integer value) + * **before** clearing it. For details, please refer to the device status + * flags documentation. + * + * @return 0 on success, an error code otherwise + */ + uint16_t readAndClearDeviceStatus(uint32_t& deviceStatus); + + /** + * deviceReset() - Executes a reset on the device. This has the same effect + * as a power cycle. + * + * @return 0 on success, an error code otherwise + */ + uint16_t deviceReset(void); + + private: + TwoWire* _i2cBus = nullptr; +}; + +#endif /* SENSIRIONI2CSEN5X_H */ diff --git a/tasmota/include/tasmota_configurations.h b/tasmota/include/tasmota_configurations.h index 1ed060c54..bc572e890 100644 --- a/tasmota/include/tasmota_configurations.h +++ b/tasmota/include/tasmota_configurations.h @@ -98,6 +98,7 @@ #define USE_MGS // [I2cDriver17] Enable Xadow and Grove Mutichannel Gas sensor using library Multichannel_Gas_Sensor (+10k code) #define USE_SGP30 // [I2cDriver18] Enable SGP30 sensor (I2C address 0x58) (+1k1 code) #define USE_SGP40 // [I2cDriver69] Enable SGP40 sensor (I2C address 0x59) (+1k4 code) +#define USE_SEN5X // [I2cDriver76] Enable SEN5X sensor (I2C address 0x69) (+3k code) //#define USE_SI1145 // [I2cDriver19] Enable SI1145/46/47 sensor (I2C address 0x60) (+1k code) #define USE_LM75AD // [I2cDriver20] Enable LM75AD sensor (I2C addresses 0x48 - 0x4F) (+0k5 code) //#define USE_APDS9960 // [I2cDriver21] Enable APDS9960 Proximity Sensor (I2C address 0x39). Disables SHT and VEML6070 (+4k7 code) diff --git a/tasmota/include/tasmota_configurations_ESP32.h b/tasmota/include/tasmota_configurations_ESP32.h index 9360a109c..673c70d49 100644 --- a/tasmota/include/tasmota_configurations_ESP32.h +++ b/tasmota/include/tasmota_configurations_ESP32.h @@ -369,6 +369,7 @@ //#define USE_MGS // [I2cDriver17] Enable Xadow and Grove Mutichannel Gas sensor using library Multichannel_Gas_Sensor (+10k code) //#define USE_SGP30 // [I2cDriver18] Enable SGP30 sensor (I2C address 0x58) (+1k1 code) //#define USE_SGP40 // [I2cDriver69] Enable SGP40 sensor (I2C address 0x59) (+1k4 code) +//#define USE_SEN5X // [I2cDriver76] Enable SEN5X sensor (I2C address 0x69) (+3k code) //#define USE_SI1145 // [I2cDriver19] Enable SI1145/46/47 sensor (I2C address 0x60) (+1k code) //#define USE_LM75AD // [I2cDriver20] Enable LM75AD sensor (I2C addresses 0x48 - 0x4F) (+0k5 code) //#define USE_APDS9960 // [I2cDriver21] Enable APDS9960 Proximity Sensor (I2C address 0x39). Disables SHT and VEML6070 (+4k7 code) @@ -586,6 +587,7 @@ #define USE_MGS // [I2cDriver17] Enable Xadow and Grove Mutichannel Gas sensor using library Multichannel_Gas_Sensor (+10k code) #define USE_SGP30 // [I2cDriver18] Enable SGP30 sensor (I2C address 0x58) (+1k1 code) #define USE_SGP40 // [I2cDriver69] Enable SGP40 sensor (I2C address 0x59) (+1k4 code) +#define USE_SEN5X // [I2cDriver76] Enable SEN5X sensor (I2C address 0x69) (+3k code) //#define USE_SI1145 // [I2cDriver19] Enable SI1145/46/47 sensor (I2C address 0x60) (+1k code) #define USE_LM75AD // [I2cDriver20] Enable LM75AD sensor (I2C addresses 0x48 - 0x4F) (+0k5 code) //#define USE_APDS9960 // [I2cDriver21] Enable APDS9960 Proximity Sensor (I2C address 0x39). Disables SHT and VEML6070 (+4k7 code) diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index 6eee06d05..64b040afc 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -619,6 +619,7 @@ #define MGS_SENSOR_ADDR 0x04 // Default Mutichannel Gas sensor i2c address // #define USE_SGP30 // [I2cDriver18] Enable SGP30 sensor (I2C address 0x58) (+1k1 code) // #define USE_SGP40 // [I2cDriver69] Enable SGP40 sensor (I2C address 0x59) (+1k4 code) +// #define USE_SEN5X // [I2cDriver76] Enable SEN5X sensor (I2C address 0x69) (+3k code) // #define USE_SI1145 // [I2cDriver19] Enable SI1145/46/47 sensor (I2C address 0x60) (+1k code) // #define USE_LM75AD // [I2cDriver20] Enable LM75AD sensor (I2C addresses 0x48 - 0x4F) (+0k5 code) // #define USE_APDS9960 // [I2cDriver21] Enable APDS9960 Proximity Sensor (I2C address 0x39). Disables SHT and VEML6070 (+4k7 code) diff --git a/tasmota/tasmota_support/support_features.ino b/tasmota/tasmota_support/support_features.ino index 8f52b111e..c1e816293 100644 --- a/tasmota/tasmota_support/support_features.ino +++ b/tasmota/tasmota_support/support_features.ino @@ -870,8 +870,9 @@ void ResponseAppendFeatures(void) #ifdef USE_TUYAMCUBR feature9 |= 0x00004000; // xdrv_65_tuyamcubr.ino #endif - -// feature9 |= 0x00008000; +#if defined(USE_I2C) && defined(USE_SEN5X) + feature9 |= 0x00008000; // xsns_103_sen5x.ino +#endif // feature9 |= 0x00010000; // feature9 |= 0x00020000; diff --git a/tasmota/tasmota_xsns_sensor/xsns_103_sen5x.ino b/tasmota/tasmota_xsns_sensor/xsns_103_sen5x.ino new file mode 100644 index 000000000..720550137 --- /dev/null +++ b/tasmota/tasmota_xsns_sensor/xsns_103_sen5x.ino @@ -0,0 +1,312 @@ +/* + xsns_103_sen5x.ino - SEN5X gas and air quality sensor support for Tasmota + + Copyright (C) 2022 Tyeth Gundry + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifdef USE_I2C +#ifdef USE_SEN5X +/*********************************************************************************************\ + * SEN5X - Gas (VOC - Volatile Organic Compounds / NOx - Nitrous Oxides) and Particulates (PPM) + * + * Source: Sensirion SEN5X Driver + Example, and Tasmota Driver 98 by Jean-Pierre Deschamps + * Adaption for TASMOTA: Tyeth Gundry + * + * I2C Address: 0x59 +\*********************************************************************************************/ + +#define XSNS_103 103 +#define XI2C_76 76 // See I2CDEVICES.md + +#define SEN5X_ADDRESS 0x69 + +#include +#include +SensirionI2CSen5x *sen5x = nullptr; + +struct SEN5XDATA_s { + bool sen5x_ready; + float abshum; + float massConcentrationPm1p0; + float massConcentrationPm2p5; + float massConcentrationPm4p0; + float massConcentrationPm10p0; + float ambientHumidity; + float ambientTemperature; + float vocIndex; + float noxIndex; +} *SEN5XDATA = nullptr; +/********************************************************************************************/ + +void sen5x_Init(void) +{ + if(!TasmotaGlobal.i2c_enabled){ + DEBUG_SENSOR_LOG(PSTR("I2C Not enabled, so not loading SEN5X driver.")); + return; + } + int usingI2cBus = 0; +#ifdef ESP32 + if (!I2cSetDevice(SEN5X_ADDRESS, 0)) + { + DEBUG_SENSOR_LOG(PSTR("Sensirion SEN5X not found, i2c bus 0")); + if (TasmotaGlobal.i2c_enabled_2 ){ + + if(!I2cSetDevice(SEN5X_ADDRESS, 1)){ + DEBUG_SENSOR_LOG(PSTR("Sensirion SEN5X not found, i2c bus 1")); + return; + } + usingI2cBus = 1; + } + else { + return; + } + } +#else + if (!I2cSetDevice(SEN5X_ADDRESS)) + { + DEBUG_SENSOR_LOG(PSTR("Sensirion SEN5X not found, i2c bus 0")); + return; + } +#endif + if (SEN5XDATA == nullptr) + SEN5XDATA = (SEN5XDATA_s *)calloc(1, sizeof(struct SEN5XDATA_s)); + SEN5XDATA->sen5x_ready = false; + if(sen5x == nullptr) sen5x = new SensirionI2CSen5x(); + if(usingI2cBus==1){ +#ifdef ESP32 + sen5x->begin(Wire1); +#else + sen5x->begin(Wire); +#endif + } + else { + sen5x->begin(Wire); + } + int error_stop = sen5x->deviceReset(); + if (error_stop != 0) + { + DEBUG_SENSOR_LOG(PSTR("Sensirion SEN5X failed to reset device (I2C Bus %d)"), usingI2cBus); + return; + } + // Wait 1 second for sensors to start recording + 100ms for reset command + delay(1100); + int error_start = sen5x->startMeasurement(); + if (error_start != 0) + { + DEBUG_SENSOR_LOG(PSTR("Sensirion SEN5X failed to start measurement (I2C Bus %d)"), usingI2cBus); + return; + } + SEN5XDATA->sen5x_ready = true; + I2cSetActiveFound(SEN5X_ADDRESS, "SEN5X", usingI2cBus); + DEBUG_SENSOR_LOG(PSTR("Sensirion SEN5X found, i2c bus %d"), usingI2cBus); +} + +// #define POW_FUNC pow +#define POW_FUNC FastPrecisePow + +float sen5x_AbsoluteHumidity(float temperature, float humidity) +{ + // taken from https://carnotcycle.wordpress.com/2012/08/04/how-to-convert-relative-humidity-to-absolute-humidity/ + // precision is about 0.1°C in range -30 to 35°C + // August-Roche-Magnus 6.1094 exp(17.625 x T)/(T + 243.04) + // Buck (1981) 6.1121 exp(17.502 x T)/(T + 240.97) + // reference https://www.eas.ualberta.ca/jdwilson/EAS372_13/Vomel_CIRES_satvpformulae.html + float temp = NAN; + const float mw = 18.01534f; // molar mass of water g/mol + const float r = 8.31447215f; // Universal gas constant J/mol/K + + if (isnan(temperature) || isnan(humidity)) + { + return NAN; + } + + temp = POW_FUNC(2.718281828f, (17.67f * temperature) / (temperature + 243.5f)); + + // return (6.112 * temp * humidity * 2.1674) / (273.15 + temperature); //simplified version + return (6.112f * temp * humidity * mw) / ((273.15f + temperature) * r); // long version +} + +#define SAVE_PERIOD 30 + +void SEN5XUpdate(void) // Perform every second to ensure proper operation of the baseline compensation algorithm +{ + uint16_t error; + char errorMessage[256]; + DEBUG_SENSOR_LOG(PSTR("Running readMeasuredValues for SEN5X...")); + + error = sen5x->readMeasuredValues( + SEN5XDATA->massConcentrationPm1p0, SEN5XDATA->massConcentrationPm2p5, SEN5XDATA->massConcentrationPm4p0, + SEN5XDATA->massConcentrationPm10p0, SEN5XDATA->ambientHumidity, SEN5XDATA->ambientTemperature, SEN5XDATA->vocIndex, + SEN5XDATA->noxIndex); + + if (error) + { + AddLog(LOG_LEVEL_DEBUG, PSTR("Failed to retrieve SEN5X readings.")); + #ifdef DEBUG_TASMOTA_SENSOR + DEBUG_SENSOR_LOG(PSTR("Error trying to execute readMeasuredValues(): \n")); + errorToString(error, errorMessage, 256); + DEBUG_SENSOR_LOG(errorMessage); + #endif + } + else + { +#ifdef DEBUG_TASMOTA_SENSOR + DEBUG_SENSOR_LOG(PSTR("SEN5x readings:-")); + DEBUG_SENSOR_LOG(PSTR("MassConcentrationPm1p0: %f\n"), SEN5XDATA->massConcentrationPm1p0); + DEBUG_SENSOR_LOG(PSTR("MassConcentrationPm2p5: %f\n"), SEN5XDATA->massConcentrationPm2p5); + DEBUG_SENSOR_LOG(PSTR("MassConcentrationPm4p0: %f\n"), SEN5XDATA->massConcentrationPm4p0); + DEBUG_SENSOR_LOG(PSTR("MassConcentrationPm10p0: %f\n"), SEN5XDATA->massConcentrationPm10p0); + if (isnan(SEN5XDATA->ambientHumidity)) + { + DEBUG_SENSOR_LOG(PSTR("AmbientHumidity: n/a\n")); + } + else + { + DEBUG_SENSOR_LOG(PSTR("AmbientHumidity: %f\n"), SEN5XDATA->ambientHumidity); + } + + if (isnan(SEN5XDATA->ambientTemperature)) + { + DEBUG_SENSOR_LOG(PSTR("AmbientTemperature: n/a\n")); + } + else + { + DEBUG_SENSOR_LOG(PSTR("AmbientTemperature: %f\n"), SEN5XDATA->ambientTemperature); + } + + if (isnan(SEN5XDATA->vocIndex)) + { + DEBUG_SENSOR_LOG(PSTR("VocIndex: n/a\n")); + } + else + { + DEBUG_SENSOR_LOG(PSTR("VocIndex: %f\n"), SEN5XDATA->vocIndex); + } + + if (isnan(SEN5XDATA->noxIndex)) + { + DEBUG_SENSOR_LOG(PSTR("NoxIndex: n/a\n")); + } + else + { + DEBUG_SENSOR_LOG(PSTR("NoxIndex: %f\n"), SEN5XDATA->noxIndex); + } +#endif + } + if (!isnan(SEN5XDATA->ambientTemperature) && SEN5XDATA->ambientHumidity > 0) { + SEN5XDATA->abshum = sen5x_AbsoluteHumidity(SEN5XDATA->ambientTemperature, SEN5XDATA->ambientHumidity); + DEBUG_SENSOR_LOG(PSTR("AbsoluteHumidity: %f\n"), SEN5XDATA->abshum); + } +} + +#ifdef USE_WEBSERVER +const char HTTP_SNS_SEN5X_UNITS[] PROGMEM = "{s}SEN5X %s{m}%.*f %s{e}"; +const char HTTP_SNS_SEN5X_UNITLESS[] PROGMEM = "{s}SEN5X %s{m}%.*f{e}"; +// {s} =

+const char HTTP_SNS_AHUMSEN5X[] PROGMEM = "{s}SEN5X Abs Humidity{m}%s g/m³{e}"; +#endif + +#define D_JSON_AHUM "aHumidity" + +void SEN5XShow(bool json) +{ + if (SEN5XDATA->sen5x_ready) + { + char sen5x_abs_hum[33]; + bool ahum_available = !isnan(SEN5XDATA->ambientTemperature) && (SEN5XDATA->ambientHumidity > 0); + if (ahum_available) + { + // has humidity + temperature + dtostrfd(SEN5XDATA->abshum, 4, sen5x_abs_hum); + } + if (json) + { + ResponseAppend_P(PSTR(",\"SEN5X\":{")); + ResponseAppend_P(PSTR("\"PM1\":%.1f,"), SEN5XDATA->massConcentrationPm1p0); + ResponseAppend_P(PSTR("\"PM2.5\":%.1f,"), SEN5XDATA->massConcentrationPm2p5); + ResponseAppend_P(PSTR("\"PM4\":%.1f,"), SEN5XDATA->massConcentrationPm4p0); + ResponseAppend_P(PSTR("\"PM10\":%.1f,"), SEN5XDATA->massConcentrationPm10p0); + if (!isnan(SEN5XDATA->noxIndex)) + ResponseAppend_P(PSTR("\"NOx\":%.0f,"), SEN5XDATA->noxIndex); + if (!isnan(SEN5XDATA->vocIndex)) + ResponseAppend_P(PSTR("\"VOC\":%.0f,"), SEN5XDATA->vocIndex); + if (!isnan(SEN5XDATA->ambientTemperature)) + ResponseAppendTHD(SEN5XDATA->ambientTemperature, SEN5XDATA->ambientHumidity); + if (ahum_available) + ResponseAppend_P(PSTR(",\"" D_JSON_AHUM "\":%s"), sen5x_abs_hum); + ResponseJsonEnd(); + } + +#ifdef USE_WEBSERVER + + WSContentSend_PD(HTTP_SNS_SEN5X_UNITS, "PM1", 1, SEN5XDATA->massConcentrationPm1p0, "μg/m³"); + WSContentSend_PD(HTTP_SNS_SEN5X_UNITS, "PM2.5", 1, SEN5XDATA->massConcentrationPm2p5, "μg/m³"); + WSContentSend_PD(HTTP_SNS_SEN5X_UNITS, "PM4", 1, SEN5XDATA->massConcentrationPm4p0, "μg/m³"); + WSContentSend_PD(HTTP_SNS_SEN5X_UNITS, "PM10", 1, SEN5XDATA->massConcentrationPm10p0, "μg/m³"); + if (!isnan(SEN5XDATA->noxIndex)) + WSContentSend_PD(HTTP_SNS_SEN5X_UNITLESS, "NOx", 0, SEN5XDATA->noxIndex); + if (!isnan(SEN5XDATA->vocIndex)) + WSContentSend_PD(HTTP_SNS_SEN5X_UNITLESS, "VOC", 0, SEN5XDATA->vocIndex); + if (!isnan(SEN5XDATA->ambientTemperature)) + WSContentSend_PD(HTTP_SNS_SEN5X_UNITS, "Temperature", 2, SEN5XDATA->ambientTemperature, "°C"); + if (!isnan(SEN5XDATA->ambientHumidity)) + WSContentSend_PD(HTTP_SNS_SEN5X_UNITS, "Humidity", 2, SEN5XDATA->ambientHumidity, "%RH"); + if (ahum_available) + WSContentSend_PD(HTTP_SNS_AHUMSEN5X, sen5x_abs_hum); + +#endif + } +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xsns103(uint32_t function) +{ + if (!I2cEnabled(XI2C_76)) + { + return false; + } + + bool result = false; + + if (FUNC_INIT == function) + { + sen5x_Init(); + } + else if (SEN5XDATA != nullptr) + { + switch (function) + { + case FUNC_EVERY_SECOND: + SEN5XUpdate(); + break; + case FUNC_JSON_APPEND: + SEN5XShow(1); + break; +#ifdef USE_WEBSERVER + case FUNC_WEB_SENSOR: + SEN5XShow(0); + break; +#endif // USE_WEBSERVER + } + } + return result; +} + +#endif // USE_SEN5X +#endif // USE_I2C diff --git a/tools/decode-status.py b/tools/decode-status.py index 843a2d0e8..567d54d90 100755 --- a/tools/decode-status.py +++ b/tools/decode-status.py @@ -290,7 +290,7 @@ a_features = [[ "USE_SGP40","USE_LUXV30B","USE_CANSNIFFER","USE_QMC5883L", "USE_MODBUS_ENERGY","USE_SHELLY_PRO","USE_DALI","USE_BP1658CJ", "USE_DINGTIAN_RELAY","USE_HMC5883L","USE_LD2410","USE_ME007", - "USE_DISPLAY_TM1650","USE_PCA9632","USE_TUYAMCUBR","", + "USE_DISPLAY_TM1650","USE_PCA9632","USE_TUYAMCUBR","USE_SEN5X", "","","","", "","","","", "","","","", From 19d5a363e1c48372b0c00d6349e14a8820a2a17a Mon Sep 17 00:00:00 2001 From: David Smith Date: Sun, 29 Jan 2023 00:48:23 -0700 Subject: [PATCH 193/262] Multicast address typo in my_user_config.h (#17816) For ArtNet Multicast address the defined value and the value in the comment are different. --- tasmota/my_user_config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index 64b040afc..542cc0128 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -580,7 +580,7 @@ //#define USE_LSC_MCSL // Add support for GPE Multi color smart light as sold by Action in the Netherlands (+1k1 code) // #define USE_LIGHT_ARTNET // Add support for DMX/ArtNet via UDP on port 6454 (+3.5k code) - #define USE_LIGHT_ARTNET_MCAST 239,255,25,54 // Multicast address used to listen: 239.255.25.24 + #define USE_LIGHT_ARTNET_MCAST 239,255,25,54 // Multicast address used to listen: 239.255.25.54 // -- Counter input ------------------------------- #define USE_COUNTER // Enable inputs as counter (+0k8 code) From b98b2838e85e0158012d7f30b8bef484bdad9ee0 Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Sun, 29 Jan 2023 10:46:06 +0100 Subject: [PATCH 194/262] Zigbee extend plug-in modifiers to 16 bits (#17817) --- CHANGELOG.md | 1 + tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_1z_libs.ino | 7 +++++-- .../xdrv_23_zigbee_5_1_attributes.ino | 6 +++--- .../xdrv_23_zigbee_5_2_converters.ino | 5 +++-- .../tasmota_xdrv_driver/xdrv_23_zigbee_7_7_plugin.ino | 10 +++++----- tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_A_impl.ino | 8 ++++---- 6 files changed, 21 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3872daaa9..3136fa830 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ All notable changes to this project will be documented in this file. ### Fixed - ADE7953 when calibration data for second channel is used regression from v12.2.0.2 - Shelly Pro 1/2 relay click at restart regression from v12.3.1.4 +- Zigbee extend plug-in modifiers to 16 bits ### Removed diff --git a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_1z_libs.ino b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_1z_libs.ino index 4e67e4673..f93d375a8 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_1z_libs.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_1z_libs.ino @@ -111,8 +111,9 @@ public: // Bit #9 is `0` command is cluster specific, or `1` general_command uint8_t key_suffix; // append a suffix to key (default is 1, explicitly output if >1) uint8_t attr_type; // [opt] type of the attribute, default to Zunk (0xFF) - int8_t attr_multiplier; // [opt] multiplier for attribute, defaults to 0x01 (no change) - int8_t attr_divider; // [opt] divider + uint16_t attr_multiplier; // [opt] multiplier for attribute, defaults to 0x01 (no change) + uint16_t attr_divider; // [opt] divider + int16_t attr_base; // [opt] base for conversion uint16_t manuf; // manufacturer id (0 if none) // Constructor with all defaults @@ -130,6 +131,7 @@ public: attr_type(0xFF), attr_multiplier(1), attr_divider(1), + attr_base(0), manuf(0) {}; @@ -789,6 +791,7 @@ void Z_attribute::deepCopy(const Z_attribute & rhs) { attr_type = rhs.attr_type; attr_multiplier = rhs.attr_multiplier; attr_divider = rhs.attr_divider; + attr_base = rhs.attr_base; // copy value copyVal(rhs); // don't touch next pointer diff --git a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_5_1_attributes.ino b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_5_1_attributes.ino index 96216c02c..8e3fe493d 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_5_1_attributes.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_5_1_attributes.ino @@ -530,10 +530,10 @@ public: uint16_t cluster = 0xFFFF; uint16_t attribute = 0xFFFF; const char * name = nullptr; + uint16_t multiplier = 1; + uint16_t divider = 1; + int16_t base = 0; uint8_t zigbee_type = Znodata; - int8_t multiplier = 1; - int8_t divider = 1; - int8_t base = 0; uint8_t map_offset = 0; Z_Data_Type map_type = Z_Data_Type::Z_Unknown; uint16_t manuf = 0x0000; // manuf code (if any) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_5_2_converters.ino b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_5_2_converters.ino index 4faa86a39..9a085787c 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_5_2_converters.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_5_2_converters.ino @@ -1612,6 +1612,7 @@ void Z_parseAttributeKey_inner(uint16_t shortaddr, class Z_attribute & attr, uin attr.attr_type = matched_attr.zigbee_type; attr.attr_multiplier = matched_attr.multiplier; attr.attr_divider = matched_attr.divider; + attr.attr_base = matched_attr.base; attr.manuf = matched_attr.manuf; } } @@ -1695,8 +1696,8 @@ void Z_Data::toAttributes(Z_attribute_list & attr_list) const { const Z_AttributeConverter *converter = &Z_PostProcess[i]; uint8_t conv_export = pgm_read_byte(&converter->multiplier_idx) & Z_EXPORT_DATA; uint8_t conv_mapping = pgm_read_byte(&converter->mapping); - int8_t multiplier = 1; - int8_t divider = 1; + uint16_t multiplier = 1; + uint16_t divider = 1; int8_t multiplier8 = CmToMultiplier(pgm_read_byte(&converter->multiplier_idx)); if (multiplier8 > 1) { multiplier = multiplier8; } if (multiplier8 < 0) { divider = -multiplier8; } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_7_7_plugin.ino b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_7_7_plugin.ino index f6cc778d5..445d6106d 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_7_7_plugin.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_7_7_plugin.ino @@ -214,8 +214,8 @@ bool ZbLoad_inner(const char *filename, File &fp) { uint16_t attr_id = 0xFFFF; uint16_t cluster_id = 0xFFFF; uint8_t type_id = Zunk; - int8_t multiplier = 1; - int8_t divider = 1; + uint16_t multiplier = 1; + uint16_t divider = 1; int16_t base = 0; char * name = nullptr; uint16_t manuf = 0; @@ -281,9 +281,9 @@ bool ZbLoad_inner(const char *filename, File &fp) { char * delimiter_slash2 = strchr(tok2, '/'); uint16_t new_cluster_id = strtoul(tok2, &delimiter_slash2, 16); uint16_t new_attr_id = strtoul(delimiter_slash2+1, nullptr, 16); - int8_t multiplier = 1; - int8_t divider = 1; - int16_t base = 0; + uint16_t multiplier = 1; + uint16_t divider = 1; + int16_t base = 0; // ADDITIONAL ELEMENTS? while (token = strtok_r(rest, ",", &rest)) { diff --git a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_A_impl.ino b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_A_impl.ino index 46f3b7023..17b954b47 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_A_impl.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_A_impl.ino @@ -232,7 +232,7 @@ void zigbeeZCLSendCmd(class ZCLFrame &zcl) { // I.e. multipliers and dividers are inversed // multiplier == 0: ignore // multiplier == 1: ignore -void ZbApplyMultiplierForWrites(double &val_d, int8_t multiplier, int8_t divider, int8_t base) { +void ZbApplyMultiplierForWrites(double &val_d, uint16_t multiplier, uint16_t divider, int16_t base) { if (0 != base) { val_d = val_d - base; } @@ -253,7 +253,7 @@ bool ZbTuyaWrite(SBuffer & buf, const Z_attribute & attr) { if (attr.key_is_str || attr.key_is_cmd) { return false; } // couldn't find attr if so skip if (attr.isNum()) { - ZbApplyMultiplierForWrites(val_d, attr.attr_multiplier, attr.attr_divider, 0); + ZbApplyMultiplierForWrites(val_d, attr.attr_multiplier, attr.attr_divider, attr.attr_base); } uint32_t u32 = val_d; int32_t i32 = val_d; @@ -312,7 +312,7 @@ bool ZbAppendWriteBuf(SBuffer & buf, const Z_attribute & attr, bool prepend_stat if (attr.key_is_str && attr.key_is_cmd) { return false; } // couldn't find attr if so skip if (attr.isNum()) { - ZbApplyMultiplierForWrites(val_d, attr.attr_multiplier, attr.attr_divider, 0); + ZbApplyMultiplierForWrites(val_d, attr.attr_multiplier, attr.attr_divider, attr.attr_base); } // push the value in the buffer @@ -433,7 +433,7 @@ void ZbSendReportWrite(class JsonParserToken val_pubwrite, class ZCLFrame & zcl) val_str = val_attr_rc.getStr(); if (!val_attr_rc.isNull()) { val_d = val_attr_rc.getFloat(); - ZbApplyMultiplierForWrites(val_d, attr.attr_multiplier, attr.attr_divider, 0); + ZbApplyMultiplierForWrites(val_d, attr.attr_multiplier, attr.attr_divider, attr.attr_base); } else { val_d = NAN; } From 03815d827aaa37488d273d3fdddd3e944324f9b2 Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Sun, 29 Jan 2023 12:09:29 +0100 Subject: [PATCH 195/262] Berry energy_ctypes fixed accordingly (#17820) --- CHANGELOG.md | 1 + .../src/be_energy_ctypes_definitions.c | 111 +---------- tasmota/berry/modules/energy_ctypes.be | 179 ------------------ .../xdrv_52_3_berry_energy.ino | 141 ++++++++++++++ 4 files changed, 147 insertions(+), 285 deletions(-) delete mode 100644 tasmota/berry/modules/energy_ctypes.be create mode 100644 tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_energy.ino diff --git a/CHANGELOG.md b/CHANGELOG.md index 3136fa830..e0ec39a66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ All notable changes to this project will be documented in this file. ### Breaking Changed - Berry energy_ctypes changed with new energy driver +- Berry energy_ctypes fixed accordingly ### Changed - Energy refactoring preparing for ESP32 phase/channel extension diff --git a/lib/libesp32/berry_tasmota/src/be_energy_ctypes_definitions.c b/lib/libesp32/berry_tasmota/src/be_energy_ctypes_definitions.c index 21ece3f3a..1844134a3 100644 --- a/lib/libesp32/berry_tasmota/src/be_energy_ctypes_definitions.c +++ b/lib/libesp32/berry_tasmota/src/be_energy_ctypes_definitions.c @@ -1,112 +1,11 @@ -/******************************************************************** - * Tasmota LVGL ctypes mapping - *******************************************************************/ +// /******************************************************************** +// * Tasmota LVGL ctypes mapping +// *******************************************************************/ #include "be_ctypes.h" #ifdef USE_ENERGY_SENSOR -/******************************************************************** - * Generated code, don't edit - *******************************************************************/ - -static const char * be_ctypes_instance_mappings[]; /* forward definition */ - -const be_ctypes_structure_t be_energy_struct = { - 250, /* size in bytes */ - 85, /* number of elements */ - be_ctypes_instance_mappings, - (const be_ctypes_structure_item_t[85]) { - { "active_power", 24, 0, 0, ctypes_float, 0 }, - { "active_power_2", 28, 0, 0, ctypes_float, 0 }, - { "active_power_3", 32, 0, 0, ctypes_float, 0 }, - { "apparent_power", 36, 0, 0, ctypes_float, 0 }, - { "apparent_power_2", 40, 0, 0, ctypes_float, 0 }, - { "apparent_power_3", 44, 0, 0, ctypes_float, 0 }, - { "command_code", 205, 0, 0, ctypes_u8, 0 }, - { "current", 12, 0, 0, ctypes_float, 0 }, - { "current_2", 16, 0, 0, ctypes_float, 0 }, - { "current_3", 20, 0, 0, ctypes_float, 0 }, - { "current_available", 215, 0, 0, ctypes_u8, 0 }, - { "daily", 120, 0, 0, ctypes_float, 0 }, - { "daily_2", 124, 0, 0, ctypes_float, 0 }, - { "daily_3", 128, 0, 0, ctypes_float, 0 }, - { "daily_sum", 144, 0, 0, ctypes_float, 0 }, - { "data_valid", 206, 0, 0, ctypes_u8, 0 }, - { "data_valid_2", 207, 0, 0, ctypes_u8, 0 }, - { "data_valid_3", 208, 0, 0, ctypes_u8, 0 }, - { "export_active", 96, 0, 0, ctypes_float, 0 }, - { "export_active_2", 100, 0, 0, ctypes_float, 0 }, - { "export_active_3", 104, 0, 0, ctypes_float, 0 }, - { "fifth_second", 204, 0, 0, ctypes_u8, 0 }, - { "frequency", 72, 0, 0, ctypes_float, 0 }, - { "frequency_2", 76, 0, 0, ctypes_float, 0 }, - { "frequency_3", 80, 0, 0, ctypes_float, 0 }, - { "frequency_common", 211, 0, 0, ctypes_u8, 0 }, - { "import_active", 84, 0, 0, ctypes_float, 0 }, - { "import_active_2", 88, 0, 0, ctypes_float, 0 }, - { "import_active_3", 92, 0, 0, ctypes_float, 0 }, - { "max_current_flag", 242, 0, 0, ctypes_u8, 0 }, - { "max_energy_state", 249, 0, 0, ctypes_u8, 0 }, - { "max_power_flag", 238, 0, 0, ctypes_u8, 0 }, - { "max_voltage_flag", 240, 0, 0, ctypes_u8, 0 }, - { "min_current_flag", 241, 0, 0, ctypes_u8, 0 }, - { "min_power_flag", 237, 0, 0, ctypes_u8, 0 }, - { "min_voltage_flag", 239, 0, 0, ctypes_u8, 0 }, - { "mplh_counter", 244, 0, 0, ctypes_u16, 0 }, - { "mplr_counter", 248, 0, 0, ctypes_u8, 0 }, - { "mplw_counter", 246, 0, 0, ctypes_u16, 0 }, - { "period", 192, 0, 0, ctypes_u32, 0 }, - { "period_2", 196, 0, 0, ctypes_u32, 0 }, - { "period_3", 200, 0, 0, ctypes_u32, 0 }, - { "phase_count", 209, 0, 0, ctypes_u8, 0 }, - { "power_factor", 60, 0, 0, ctypes_float, 0 }, - { "power_factor_2", 64, 0, 0, ctypes_float, 0 }, - { "power_factor_3", 68, 0, 0, ctypes_float, 0 }, - { "power_history_0", 218, 0, 0, ctypes_u16, 0 }, - { "power_history_0_2", 220, 0, 0, ctypes_u16, 0 }, - { "power_history_0_3", 222, 0, 0, ctypes_u16, 0 }, - { "power_history_1", 224, 0, 0, ctypes_u16, 0 }, - { "power_history_1_2", 226, 0, 0, ctypes_u16, 0 }, - { "power_history_1_3", 228, 0, 0, ctypes_u16, 0 }, - { "power_history_2", 230, 0, 0, ctypes_u16, 0 }, - { "power_history_2_2", 232, 0, 0, ctypes_u16, 0 }, - { "power_history_2_3", 234, 0, 0, ctypes_u16, 0 }, - { "power_on", 217, 0, 0, ctypes_u8, 0 }, - { "power_steady_counter", 236, 0, 0, ctypes_u8, 0 }, - { "reactive_power", 48, 0, 0, ctypes_float, 0 }, - { "reactive_power_2", 52, 0, 0, ctypes_float, 0 }, - { "reactive_power_3", 56, 0, 0, ctypes_float, 0 }, - { "start_energy", 108, 0, 0, ctypes_float, 0 }, - { "start_energy_2", 112, 0, 0, ctypes_float, 0 }, - { "start_energy_3", 116, 0, 0, ctypes_float, 0 }, - { "today_delta_kwh", 156, 0, 0, ctypes_u32, 0 }, - { "today_delta_kwh_2", 160, 0, 0, ctypes_u32, 0 }, - { "today_delta_kwh_3", 164, 0, 0, ctypes_u32, 0 }, - { "today_kwh", 180, 0, 0, ctypes_u32, 0 }, - { "today_kwh_2", 184, 0, 0, ctypes_u32, 0 }, - { "today_kwh_3", 188, 0, 0, ctypes_u32, 0 }, - { "today_offset_init_kwh", 213, 0, 0, ctypes_u8, 0 }, - { "today_offset_kwh", 168, 0, 0, ctypes_u32, 0 }, - { "today_offset_kwh_2", 172, 0, 0, ctypes_u32, 0 }, - { "today_offset_kwh_3", 176, 0, 0, ctypes_u32, 0 }, - { "total", 132, 0, 0, ctypes_float, 0 }, - { "total_2", 136, 0, 0, ctypes_float, 0 }, - { "total_3", 140, 0, 0, ctypes_float, 0 }, - { "total_sum", 148, 0, 0, ctypes_float, 0 }, - { "type_dc", 216, 0, 0, ctypes_u8, 0 }, - { "use_overtemp", 212, 0, 0, ctypes_u8, 0 }, - { "voltage", 0, 0, 0, ctypes_float, 0 }, - { "voltage_2", 4, 0, 0, ctypes_float, 0 }, - { "voltage_3", 8, 0, 0, ctypes_float, 0 }, - { "voltage_available", 214, 0, 0, ctypes_u8, 0 }, - { "voltage_common", 210, 0, 0, ctypes_u8, 0 }, - { "yesterday_sum", 152, 0, 0, ctypes_float, 0 }, -}}; - -static const char * be_ctypes_instance_mappings[] = { - NULL -}; - +extern const be_ctypes_structure_t be_energy_struct[]; be_define_ctypes_class(energy_struct, &be_energy_struct, &be_class_ctypes_bytes, "energy_struct"); -#endif // USE_ENERGY_SENSOR \ No newline at end of file +#endif // USE_ENERGY_SENSOR diff --git a/tasmota/berry/modules/energy_ctypes.be b/tasmota/berry/modules/energy_ctypes.be deleted file mode 100644 index 4d2ebea1c..000000000 --- a/tasmota/berry/modules/energy_ctypes.be +++ /dev/null @@ -1,179 +0,0 @@ -# -# ctype buidings for Tasmota Energy driver -# -# To generate C bindings, do: -# > compile("energy_ctypes.be","file")() -# -# and copy/paste output in C format -# -import ctypes - -ctypes.print_types() - -float = ctypes.float -uint8 = ctypes.u8 -uint16 = ctypes.u16 -uint32 = ctypes.u32 -int32 = ctypes.i32 -bol = ctypes.u8 - -energy_struct = [ - [float, "voltage"], - [float, "voltage_2"], - [float, "voltage_3"], - [float, "current"], - [float, "current_2"], - [float, "current_3"], - [float, "active_power"], - [float, "active_power_2"], - [float, "active_power_3"], - [float, "apparent_power"], - [float, "apparent_power_2"], - [float, "apparent_power_3"], - [float, "reactive_power"], - [float, "reactive_power_2"], - [float, "reactive_power_3"], - [float, "power_factor"], - [float, "power_factor_2"], - [float, "power_factor_3"], - [float, "frequency"], - [float, "frequency_2"], - [float, "frequency_3"], - [float, "import_active"], - [float, "import_active_2"], - [float, "import_active_3"], - [float, "export_active"], - [float, "export_active_2"], - [float, "export_active_3"], - [float, "start_energy"], - [float, "start_energy_2"], - [float, "start_energy_3"], - [float, "daily"], - [float, "daily_2"], - [float, "daily_3"], - [float, "total"], - [float, "total_2"], - [float, "total_3"], - - [float, "daily_sum"], - [float, "total_sum"], - [float, "yesterday_sum"], - - [uint32, "today_delta_kwh"], - [uint32, "today_delta_kwh_2"], - [uint32, "today_delta_kwh_3"], - [uint32, "today_offset_kwh"], - [uint32, "today_offset_kwh_2"], - [uint32, "today_offset_kwh_3"], - [uint32, "today_kwh"], - [uint32, "today_kwh_2"], - [uint32, "today_kwh_3"], - [uint32, "period"], - [uint32, "period_2"], - [uint32, "period_3"], - - [uint8, "fifth_second"], - [uint8, "command_code"], - [uint8, "data_valid"], - [uint8, "data_valid_2"], - [uint8, "data_valid_3"], - - [uint8, "phase_count"], - - [bol, "voltage_common"], - [bol, "frequency_common"], - [bol, "use_overtemp"], - [bol, "today_offset_init_kwh"], - - [bol, "voltage_available"], - [bol, "current_available"], - - [bol, "type_dc"], - [bol, "power_on"], -# #ifdef USE_ENERGY_MARGIN_DETECTION - [uint16, "power_history_0"], - [uint16, "power_history_0_2"], - [uint16, "power_history_0_3"], - [uint16, "power_history_1"], - [uint16, "power_history_1_2"], - [uint16, "power_history_1_3"], - [uint16, "power_history_2"], - [uint16, "power_history_2_2"], - [uint16, "power_history_2_3"], - - [uint8, "power_steady_counter"], - - [bol, "min_power_flag"], - [bol, "max_power_flag"], - [bol, "min_voltage_flag"], - [bol, "max_voltage_flag"], - [bol, "min_current_flag"], - [bol, "max_current_flag"], - -# #ifdef USE_ENERGY_POWER_LIMIT - [uint16, "mplh_counter"], - [uint16, "mplw_counter"], - [uint8, "mplr_counter"], - [uint8, "max_energy_state"], -] -energy_struct = ctypes.structure(energy_struct, "energy_struct") - -# struct ENERGY { -# float voltage[ENERGY_MAX_PHASES]; // 123.1 V -# float current[ENERGY_MAX_PHASES]; // 123.123 A -# float active_power[ENERGY_MAX_PHASES]; // 123.1 W -# float apparent_power[ENERGY_MAX_PHASES]; // 123.1 VA -# float reactive_power[ENERGY_MAX_PHASES]; // 123.1 VAr -# float power_factor[ENERGY_MAX_PHASES]; // 0.12 -# float frequency[ENERGY_MAX_PHASES]; // 123.1 Hz -# #if defined(SDM630_IMPORT) || defined(SDM72_IMPEXP) -# float import_active[ENERGY_MAX_PHASES]; // 123.123 kWh -# #endif // SDM630_IMPORT || SDM72_IMPEXP -# float export_active[ENERGY_MAX_PHASES]; // 123.123 kWh - -# float start_energy; // 12345.12345 kWh total previous -# float daily; // 123.123 kWh -# float total; // 12345.12345 kWh total energy - -# unsigned long kWhtoday_delta; // 1212312345 Wh 10^-5 (deca micro Watt hours) - Overflows to Energy.kWhtoday (HLW and CSE only) -# unsigned long kWhtoday_offset; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = Energy.daily -# unsigned long kWhtoday; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = Energy.daily -# unsigned long period; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = Energy.daily - -# uint8_t fifth_second; -# uint8_t command_code; -# uint8_t data_valid[ENERGY_MAX_PHASES]; - -# uint8_t phase_count; // Number of phases active -# bool voltage_common; // Use single voltage -# bool frequency_common; // Use single frequency -# bool use_overtemp; // Use global temperature as overtemp trigger on internal energy monitor hardware -# bool kWhtoday_offset_init; - -# bool voltage_available; // Enable if voltage is measured -# bool current_available; // Enable if current is measured - -# bool type_dc; -# bool power_on; - -# #ifdef USE_ENERGY_MARGIN_DETECTION -# uint16_t power_history[ENERGY_MAX_PHASES][3]; -# uint8_t power_steady_counter; // Allow for power on stabilization -# bool min_power_flag; -# bool max_power_flag; -# bool min_voltage_flag; -# bool max_voltage_flag; -# bool min_current_flag; -# bool max_current_flag; - -# #ifdef USE_ENERGY_POWER_LIMIT -# uint16_t mplh_counter; -# uint16_t mplw_counter; -# uint8_t mplr_counter; -# uint8_t max_energy_state; -# #endif // USE_ENERGY_POWER_LIMIT -# #endif // USE_ENERGY_MARGIN_DETECTION -# } Energy; - -# -ctypes.print_classes("energy") diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_energy.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_energy.ino new file mode 100644 index 000000000..f9eca21f5 --- /dev/null +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_energy.ino @@ -0,0 +1,141 @@ +/* + xdrv_52_3_berry_energy.ino - Berry scripting language, native fucnctions + + Copyright (C) 2021 Stephan Hadinger, Berry language by Guan Wenliang https://github.com/Skiars/berry + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +// Mappgin from internal light and a generic `light_state` Berry class + +#ifdef USE_BERRY +#ifdef USE_ENERGY_SENSOR + +#include "berry.h" +#include "be_func.h" +#include "be_ctypes.h" + +/*********************************************************************************************\ + * Mapping for tEnergy + * +\*********************************************************************************************/ +extern "C" { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Winvalid-offsetof" // avoid warnings since we're using offsetof() in a risky way + + static const char * be_ctypes_instance_mappings[] = { + NULL + }; + extern "C" const be_ctypes_structure_t be_energy_struct = { + sizeof(tEnergy), /* size in bytes */ + 88, /* number of elements */ + be_ctypes_instance_mappings, + (const be_ctypes_structure_item_t[88]) { + { "active_power", offsetof(tEnergy, active_power[0]), 0, 0, ctypes_float, 0 }, + { "active_power_2", offsetof(tEnergy, active_power[1]), 0, 0, ctypes_float, 0 }, + { "active_power_3", offsetof(tEnergy, active_power[2]), 0, 0, ctypes_float, 0 }, + { "apparent_power", offsetof(tEnergy, apparent_power[0]), 0, 0, ctypes_float, 0 }, + { "apparent_power_2", offsetof(tEnergy, apparent_power[1]), 0, 0, ctypes_float, 0 }, + { "apparent_power_3", offsetof(tEnergy, apparent_power[2]), 0, 0, ctypes_float, 0 }, + { "command_code", offsetof(tEnergy, command_code), 0, 0, ctypes_u8, 0 }, + { "current", offsetof(tEnergy, current[0]), 0, 0, ctypes_float, 0 }, + { "current_2", offsetof(tEnergy, current[1]), 0, 0, ctypes_float, 0 }, + { "current_3", offsetof(tEnergy, current[2]), 0, 0, ctypes_float, 0 }, + { "current_available", offsetof(tEnergy, current_available), 0, 0, ctypes_u8, 0 }, + { "daily", offsetof(tEnergy, daily_kWh[0]), 0, 0, ctypes_float, 0 }, + { "daily_2", offsetof(tEnergy, daily_kWh[1]), 0, 0, ctypes_float, 0 }, + { "daily_3", offsetof(tEnergy, daily_kWh[2]), 0, 0, ctypes_float, 0 }, + { "daily_sum", offsetof(tEnergy, daily_sum), 0, 0, ctypes_float, 0 }, + { "daily_sum_export_balanced", offsetof(tEnergy, daily_sum_export_balanced), 0, 0, ctypes_float, 0 }, + { "daily_sum_import_balanced", offsetof(tEnergy, daily_sum_import_balanced), 0, 0, ctypes_float, 0 }, + { "data_valid", offsetof(tEnergy, data_valid[0]), 0, 0, ctypes_u8, 0 }, + { "data_valid_2", offsetof(tEnergy, data_valid[1]), 0, 0, ctypes_u8, 0 }, + { "data_valid_3", offsetof(tEnergy, data_valid[2]), 0, 0, ctypes_u8, 0 }, + { "energy_active_export", offsetof(tEnergy, local_energy_active_export), 0, 0, ctypes_u8, 0 }, + { "export_active", offsetof(tEnergy, export_active[0]), 0, 0, ctypes_float, 0 }, + { "export_active_2", offsetof(tEnergy, export_active[1]), 0, 0, ctypes_float, 0 }, + { "export_active_3", offsetof(tEnergy, export_active[2]), 0, 0, ctypes_float, 0 }, + { "fifth_second", offsetof(tEnergy, fifth_second), 0, 0, ctypes_u8, 0 }, + { "frequency", offsetof(tEnergy, frequency[0]), 0, 0, ctypes_float, 0 }, + { "frequency_2", offsetof(tEnergy, frequency[1]), 0, 0, ctypes_float, 0 }, + { "frequency_3", offsetof(tEnergy, frequency[2]), 0, 0, ctypes_float, 0 }, + { "frequency_common", offsetof(tEnergy, frequency_common), 0, 0, ctypes_u8, 0 }, + { "import_active", offsetof(tEnergy, import_active[0]), 0, 0, ctypes_float, 0 }, + { "import_active_2", offsetof(tEnergy, import_active[1]), 0, 0, ctypes_float, 0 }, + { "import_active_3", offsetof(tEnergy, import_active[2]), 0, 0, ctypes_float, 0 }, + { "max_current_flag", offsetof(tEnergy, max_current_flag), 0, 0, ctypes_u8, 0 }, + { "max_energy_state", offsetof(tEnergy, max_energy_state), 0, 0, ctypes_u8, 0 }, + { "max_power_flag", offsetof(tEnergy, max_power_flag), 0, 0, ctypes_u8, 0 }, + { "max_voltage_flag", offsetof(tEnergy, max_voltage_flag), 0, 0, ctypes_u8, 0 }, + { "min_current_flag", offsetof(tEnergy, min_current_flag), 0, 0, ctypes_u8, 0 }, + { "min_power_flag", offsetof(tEnergy, min_power_flag), 0, 0, ctypes_u8, 0 }, + { "min_voltage_flag", offsetof(tEnergy, min_voltage_flag), 0, 0, ctypes_u8, 0 }, + { "mplh_counter", offsetof(tEnergy, mplh_counter), 0, 0, ctypes_u16, 0 }, + { "mplr_counter", offsetof(tEnergy, mplr_counter), 0, 0, ctypes_u8, 0 }, + { "mplw_counter", offsetof(tEnergy, mplw_counter), 0, 0, ctypes_u16, 0 }, + { "period", offsetof(tEnergy, period_kWh[0]), 0, 0, ctypes_float, 0 }, + { "period_2", offsetof(tEnergy, period_kWh[1]), 0, 0, ctypes_float, 0 }, + { "period_3", offsetof(tEnergy, period_kWh[2]), 0, 0, ctypes_float, 0 }, + { "phase_count", offsetof(tEnergy, phase_count), 0, 0, ctypes_u8, 0 }, + { "power_factor", offsetof(tEnergy, power_factor[0]), 0, 0, ctypes_float, 0 }, + { "power_factor_2", offsetof(tEnergy, power_factor[1]), 0, 0, ctypes_float, 0 }, + { "power_factor_3", offsetof(tEnergy, power_factor[2]), 0, 0, ctypes_float, 0 }, + { "power_history_0", offsetof(tEnergy, power_history[0][0]), 0, 0, ctypes_u16, 0 }, + { "power_history_0_2", offsetof(tEnergy, power_history[0][1]), 0, 0, ctypes_u16, 0 }, + { "power_history_0_3", offsetof(tEnergy, power_history[0][2]), 0, 0, ctypes_u16, 0 }, + { "power_history_1", offsetof(tEnergy, power_history[1][0]), 0, 0, ctypes_u16, 0 }, + { "power_history_1_2", offsetof(tEnergy, power_history[1][1]), 0, 0, ctypes_u16, 0 }, + { "power_history_1_3", offsetof(tEnergy, power_history[1][2]), 0, 0, ctypes_u16, 0 }, + { "power_history_2", offsetof(tEnergy, power_history[2][0]), 0, 0, ctypes_u16, 0 }, + { "power_history_2_2", offsetof(tEnergy, power_history[2][1]), 0, 0, ctypes_u16, 0 }, + { "power_history_2_3", offsetof(tEnergy, power_history[2][2]), 0, 0, ctypes_u16, 0 }, + { "power_on", offsetof(tEnergy, power_on), 0, 0, ctypes_u8, 0 }, + { "power_steady_counter", offsetof(tEnergy, power_steady_counter), 0, 0, ctypes_u8, 0 }, + { "reactive_power", offsetof(tEnergy, reactive_power[0]), 0, 0, ctypes_float, 0 }, + { "reactive_power_2", offsetof(tEnergy, reactive_power[1]), 0, 0, ctypes_float, 0 }, + { "reactive_power_3", offsetof(tEnergy, reactive_power[2]), 0, 0, ctypes_float, 0 }, + { "start_energy", offsetof(tEnergy, start_energy[0]), 0, 0, ctypes_float, 0 }, + { "start_energy_2", offsetof(tEnergy, start_energy[1]), 0, 0, ctypes_float, 0 }, + { "start_energy_3", offsetof(tEnergy, start_energy[2]), 0, 0, ctypes_float, 0 }, + { "today_delta_kwh", offsetof(tEnergy, kWhtoday_delta[0]), 0, 0, ctypes_u32, 0 }, + { "today_delta_kwh_2", offsetof(tEnergy, kWhtoday_delta[1]), 0, 0, ctypes_u32, 0 }, + { "today_delta_kwh_3", offsetof(tEnergy, kWhtoday_delta[2]), 0, 0, ctypes_u32, 0 }, + { "today_kwh", offsetof(tEnergy, kWhtoday[0]), 0, 0, ctypes_u32, 0 }, + { "today_kwh_2", offsetof(tEnergy, kWhtoday[1]), 0, 0, ctypes_u32, 0 }, + { "today_kwh_3", offsetof(tEnergy, kWhtoday[2]), 0, 0, ctypes_u32, 0 }, + { "today_offset_init_kwh", offsetof(tEnergy, kWhtoday_offset_init), 0, 0, ctypes_u8, 0 }, + { "today_offset_kwh", offsetof(tEnergy, energy_today_offset_kWh[0]), 0, 0, ctypes_float, 0 }, + { "today_offset_kwh_2", offsetof(tEnergy, energy_today_offset_kWh[1]), 0, 0, ctypes_float, 0 }, + { "today_offset_kwh_3", offsetof(tEnergy, energy_today_offset_kWh[2]), 0, 0, ctypes_float, 0 }, + { "total", offsetof(tEnergy, total[0]), 0, 0, ctypes_float, 0 }, + { "total_2", offsetof(tEnergy, total[1]), 0, 0, ctypes_float, 0 }, + { "total_3", offsetof(tEnergy, total[2]), 0, 0, ctypes_float, 0 }, + { "total_sum", offsetof(tEnergy, total_sum), 0, 0, ctypes_float, 0 }, + { "type_dc", offsetof(tEnergy, type_dc), 0, 0, ctypes_u8, 0 }, + { "use_overtemp", offsetof(tEnergy, use_overtemp), 0, 0, ctypes_u8, 0 }, + { "voltage", offsetof(tEnergy, voltage[0]), 0, 0, ctypes_float, 0 }, + { "voltage_2", offsetof(tEnergy, voltage[1]), 0, 0, ctypes_float, 0 }, + { "voltage_3", offsetof(tEnergy, voltage[2]), 0, 0, ctypes_float, 0 }, + { "voltage_available", offsetof(tEnergy, voltage_available), 0, 0, ctypes_u8, 0 }, + { "voltage_common", offsetof(tEnergy, voltage_common), 0, 0, ctypes_u8, 0 }, + { "yesterday_sum", offsetof(tEnergy, yesterday_sum), 0, 0, ctypes_float, 0 }, + }}; + // be_define_ctypes_class(energy_struct, &be_energy_struct, &be_class_ctypes_bytes, "energy_struct"); + +#pragma GCC diagnostic pop +} + + +#endif // USE_ZIGBEE +#endif // USE_BERRY From 400f0e453ef1cd1160bfae41c89a7403d4c4933a Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Sun, 29 Jan 2023 13:06:13 +0100 Subject: [PATCH 196/262] IDF 4.4.3 changes (#17821) - updated mDNS to version from esp-protocols - added PHY driver --- platformio_tasmota32.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio_tasmota32.ini b/platformio_tasmota32.ini index d4d0c7cfa..08bd7e0a3 100644 --- a/platformio_tasmota32.ini +++ b/platformio_tasmota32.ini @@ -42,7 +42,7 @@ extra_scripts = pre:pio-tools/add_c_flags.py ${esp_defaults.extra_scripts} [core32] -platform = https://github.com/tasmota/platform-espressif32/releases/download/2022.12.2/platform-espressif32.zip +platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.01.01/platform-espressif32.zip platform_packages = build_unflags = ${esp32_defaults.build_unflags} build_flags = ${esp32_defaults.build_flags} From 91559ec883c9ab6c6f9f72b7e38ab62402e09d77 Mon Sep 17 00:00:00 2001 From: Tyeth Gundry Date: Sun, 29 Jan 2023 12:48:33 +0000 Subject: [PATCH 197/262] fix: detection of SPS30 serial number (#17809) --- tasmota/tasmota_xsns_sensor/xsns_44_sps30.ino | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/tasmota/tasmota_xsns_sensor/xsns_44_sps30.ino b/tasmota/tasmota_xsns_sensor/xsns_44_sps30.ino index 016f7ef9b..21a7fd05b 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_44_sps30.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_44_sps30.ino @@ -81,11 +81,11 @@ unsigned char twi_readFrom(unsigned char address, unsigned char* buf, unsigned i #endif void sps30_get_data(uint16_t cmd, uint8_t *data, uint8_t dlen) { -unsigned char cmdb[2]; -uint8_t tmp[3]; -uint8_t index=0; -memset(data,0,dlen); -uint8_t twi_buff[64]; + unsigned char cmdb[2]; + uint8_t tmp[3]; + uint8_t index=0; + memset(data,0,dlen); + uint8_t twi_buff[64]; Wire.beginTransmission(SPS30_ADDR); cmdb[0]=cmd>>8; @@ -140,14 +140,16 @@ unsigned char cmdb[6]; void SPS30_Detect(void) { if (!I2cSetDevice(SPS30_ADDR)) { return; } - I2cSetActiveFound(SPS30_ADDR, "SPS30"); - uint8_t dcode[32]; sps30_get_data(SPS_CMD_GET_SERIAL,dcode,sizeof(dcode)); - AddLog(LOG_LEVEL_DEBUG, PSTR("sps30 found with serial: %s"),dcode); + if(dcode[0] == 0) { + return; + } + AddLog(LOG_LEVEL_DEBUG, PSTR("sps30 found with serial: %s"), dcode); sps30_cmd(SPS_CMD_START_MEASUREMENT); sps30_running = 1; sps30_ready = 1; + I2cSetActiveFound(SPS30_ADDR, "SPS30"); } #define D_UNIT_PM "ug/m3" From 664b60332a37d2d74393c327c9197a9932c1a3e7 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 29 Jan 2023 13:59:09 +0100 Subject: [PATCH 198/262] Fix broken I2C priority Fix broken I2C priority regression from v12.3.1.3 (#17810) --- CHANGELOG.md | 1 + tasmota/tasmota_support/support_a_i2c.ino | 27 +++++++++++------------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e0ec39a66..3f0c7ce11 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ All notable changes to this project will be documented in this file. - ADE7953 when calibration data for second channel is used regression from v12.2.0.2 - Shelly Pro 1/2 relay click at restart regression from v12.3.1.4 - Zigbee extend plug-in modifiers to 16 bits +- Broken I2C priority regression from v12.3.1.3 (#17810) ### Removed diff --git a/tasmota/tasmota_support/support_a_i2c.ino b/tasmota/tasmota_support/support_a_i2c.ino index a3fef3c2f..32237d173 100644 --- a/tasmota/tasmota_support/support_a_i2c.ino +++ b/tasmota/tasmota_support/support_a_i2c.ino @@ -267,30 +267,29 @@ void I2cScan(uint8_t bus = 0) { } } -void I2cResetActive(uint32_t addr, uint32_t count = 1, uint8_t bus = 0) { +void I2cResetActive(uint32_t addr, uint8_t bus = 0) { #ifdef ESP8266 bus = 0; #endif addr &= 0x7F; // Max I2C address is 127 - count &= 0x7F; // Max 4 x 32 bits available - while (count-- && (addr < 128)) { - i2c_active[bus][addr / 32] &= ~(1 << (addr % 32)); - addr++; - } -// AddLog(LOG_LEVEL_DEBUG, PSTR("I2C: Active %08X,%08X,%08X,%08X"), i2c_active[bus][0], i2c_active[bus][1], i2c_active[bus][2], i2c_active[bus][3]); + i2c_active[bus][addr / 32] &= ~(1 << (addr % 32)); + +// AddLog(LOG_LEVEL_DEBUG, PSTR("I2C: I2cResetActive bus0 %08X-%08X-%08X-%08X, bus1 %08X-%08X-%08X-%08X"), +// i2c_active[0][0], i2c_active[0][1], i2c_active[0][2], i2c_active[0][3], +// i2c_active[1][0], i2c_active[1][1], i2c_active[1][2], i2c_active[1][3]); } -void I2cSetActive(uint32_t addr, uint32_t count = 1, uint8_t bus = 0) { +void I2cSetActive(uint32_t addr, uint8_t bus = 0) { #ifdef ESP8266 bus = 0; #endif addr &= 0x7F; // Max I2C address is 127 - count &= 0x7F; // Max 4 x 32 bits available - while (count-- && (addr < 128)) { - i2c_active[bus][addr / 32] |= (1 << (addr % 32)); - addr++; - } -// AddLog(LOG_LEVEL_DEBUG, PSTR("I2C: Active %08X,%08X,%08X,%08X"), i2c_active[bus][0], i2c_active[bus][1], i2c_active[bus][2], i2c_active[bus][3]); + i2c_active[bus][addr / 32] |= (1 << (addr % 32)); + +// AddLog(LOG_LEVEL_DEBUG, PSTR("I2C: I2cSetActive addr %02X, bus%d, bus0 %08X-%08X-%08X-%08X, bus1 %08X-%08X-%08X-%08X"), +// addr, bus, +// i2c_active[0][0], i2c_active[0][1], i2c_active[0][2], i2c_active[0][3], +// i2c_active[1][0], i2c_active[1][1], i2c_active[1][2], i2c_active[1][3]); } void I2cSetActiveFound(uint32_t addr, const char *types, uint8_t bus = 0) { From db3fdc511891b7bb550942893620e633b9eabb4e Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 29 Jan 2023 16:09:13 +0100 Subject: [PATCH 199/262] Add ESP32 support for eigth energy phases/channels - ESP32 support for eigth energy phases/channels - ESP32 command ``EnergyCols 1..8`` to change number of GUI columns - ESP32 command ``EnergyDisplay 1..3`` to change GUI column presentation - support for SEN5X gas and air quality sensor by Tyeth Gundry (#17736) --- CHANGELOG.md | 5 +- RELEASENOTES.md | 4 + tasmota/include/i18n.h | 2 + .../xdrv_03_esp32_energy.ino | 266 +++++++++++++----- .../tasmota_xnrg_energy/xnrg_07_ade7953.ino | 2 +- 5 files changed, 208 insertions(+), 71 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f0c7ce11..14f5895fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,10 @@ All notable changes to this project will be documented in this file. ## [12.3.1.5] ### Added -- ESP32 Prep support for eigth energy phases/channels +- ESP32 support for eigth energy phases/channels +- ESP32 command ``EnergyCols 1..8`` to change number of GUI columns +- ESP32 command ``EnergyDisplay 1..3`` to change GUI column presentation +- support for SEN5X gas and air quality sensor by Tyeth Gundry (#17736) ### Breaking Changed - Berry energy_ctypes changed with new energy driver diff --git a/RELEASENOTES.md b/RELEASENOTES.md index e11f17dcb..d9421ff0b 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -117,11 +117,15 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm - Support for IPv6 only networks on Ethernet (not yet Wifi) - Support for TM1650 display as used in some clocks by Stefan Oskamp [#17594](https://github.com/arendst/Tasmota/issues/17594) - Support for PCA9632 4-channel 8-bit PWM driver as light driver by Pascal Heinrich [#17557](https://github.com/arendst/Tasmota/issues/17557) +- support for SEN5X gas and air quality sensor by Tyeth Gundry [#17736](https://github.com/arendst/Tasmota/issues/17736) - Berry support for ``crypto.SHA256`` [#17430](https://github.com/arendst/Tasmota/issues/17430) - Berry crypto add ``EC_P256`` and ``PBKDF2_HMAC_SHA256`` algorithms required by Matter protocol [#17473](https://github.com/arendst/Tasmota/issues/17473) - Berry crypto add ``random`` to generate series of random bytes - Berry crypto add ``HKDF_HMAC_SHA256`` - Berry crypto add ``SPAKE2P_Matter`` for Matter support +- ESP32 command ``EnergyCols 1..8`` to change number of GUI columns +- ESP32 command ``EnergyDisplay 1..3`` to change GUI column presentation +- ESP32 support for eigth energy phases/channels - ESP32 support for BMPxxx sensors on two I2C busses [#17643](https://github.com/arendst/Tasmota/issues/17643) ### Breaking Changed diff --git a/tasmota/include/i18n.h b/tasmota/include/i18n.h index 8cb8a5da1..c3df48348 100644 --- a/tasmota/include/i18n.h +++ b/tasmota/include/i18n.h @@ -454,6 +454,8 @@ #define D_CMND_VOLTAGEHIGH "VoltageHigh" #define D_CMND_CURRENTLOW "CurrentLow" #define D_CMND_CURRENTHIGH "CurrentHigh" +#define D_CMND_ENERGYDISPLAY "EnergyDisplay" +#define D_CMND_ENERGYCOLS "EnergyCols" #define D_CMND_ENERGYTODAY "EnergyToday" #define D_CMND_ENERGYYESTERDAY "EnergyYesterday" #define D_CMND_ENERGYTOTAL "EnergyTotal" diff --git a/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino b/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino index e3d1e271c..cf218d91c 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino @@ -38,6 +38,9 @@ #undef ENERGY_MAX_PHASES #define ENERGY_MAX_PHASES 8 // Support max eight phases/channels +#define ENERGY_GUI_MAX_COLS 4 // [EnergyCols] Number of GUI data columns - Preffered 4 +#define ENERGY_GUI_DISPLAY_MODE 3 // [EnergyDisplay] 1 = Rotate if over EnergyCols, 2 = Rotate only powered on if over EnergyCols, 3 = Use tabs if over EnergyCols + #include #define D_CMND_POWERCAL "PowerCal" @@ -47,6 +50,11 @@ #define D_CMND_TARIFF "Tariff" #define D_CMND_MODULEADDRESS "ModuleAddress" +enum EnergyDisplayModes { + ENERGY_DISPLAY_MIN_OPTION, + ENERGY_DISPLAY_ROTATE, ENERGY_DISPLAY_ROTATE_POWERED_ON, ENERGY_DISPLAY_TABS, + ENERGY_DISPLAY_MAX_OPTION }; + enum EnergyCalibration { ENERGY_POWER_CALIBRATION, ENERGY_VOLTAGE_CALIBRATION, ENERGY_CURRENT_CALIBRATION, ENERGY_FREQUENCY_CALIBRATION }; @@ -61,7 +69,8 @@ const char kEnergyCommands[] PROGMEM = "|" // No prefix D_CMND_MAXENERGY "|" D_CMND_MAXENERGYSTART "|" D_CMND_MAXPOWER "|" D_CMND_MAXPOWERHOLD "|" D_CMND_MAXPOWERWINDOW "|" D_CMND_SAFEPOWER "|" D_CMND_SAFEPOWERHOLD "|" D_CMND_SAFEPOWERWINDOW "|" - D_CMND_ENERGYTODAY "|" D_CMND_ENERGYYESTERDAY "|" D_CMND_ENERGYTOTAL "|" D_CMND_ENERGYEXPORTACTIVE "|" D_CMND_ENERGYUSAGE "|" D_CMND_ENERGYEXPORT "|" D_CMND_TARIFF; + D_CMND_ENERGYTODAY "|" D_CMND_ENERGYYESTERDAY "|" D_CMND_ENERGYTOTAL "|" D_CMND_ENERGYEXPORTACTIVE "|" D_CMND_ENERGYUSAGE "|" D_CMND_ENERGYEXPORT "|" + D_CMND_TARIFF "|" D_CMND_ENERGYDISPLAY "|" D_CMND_ENERGYCOLS ; void (* const EnergyCommand[])(void) PROGMEM = { &CmndPowerCal, &CmndVoltageCal, &CmndCurrentCal, &CmndFrequencyCal, @@ -70,7 +79,8 @@ void (* const EnergyCommand[])(void) PROGMEM = { &CmndMaxEnergy, &CmndMaxEnergyStart, &CmndMaxPower, &CmndMaxPowerHold, &CmndMaxPowerWindow, &CmndSafePower, &CmndSafePowerHold, &CmndSafePowerWindow, - &CmndEnergyToday, &CmndEnergyYesterday, &CmndEnergyTotal, &CmndEnergyExportActive, &CmndEnergyUsage, &CmndEnergyExport, &CmndTariff}; + &CmndEnergyToday, &CmndEnergyYesterday, &CmndEnergyTotal, &CmndEnergyExportActive, &CmndEnergyUsage, &CmndEnergyExport, + &CmndTariff, &CmndEnergyDisplay, &CmndEnergyCols }; /********************************************************************************************/ @@ -81,16 +91,40 @@ typedef struct { float last_usage_total_kWh; } tEnergyUsage; +typedef union { + uint16_t data; + struct { + uint16_t spare00 : 1; // bit 0 + uint16_t spare01 : 1; // bit 1 + uint16_t spare02 : 1; // bit 2 + uint16_t spare03 : 1; // bit 3 + uint16_t spare04 : 1; // bit 4 + uint16_t spare05 : 1; // bit 5 + uint16_t spare06 : 1; // bit 6 + uint16_t spare07 : 1; // bit 7 + uint16_t spare08 : 1; // bit 8 + uint16_t spare09 : 1; // bit 9 + uint16_t spare10 : 1; // bit 10 + uint16_t spare11 : 1; // bit 11 + uint16_t spare12 : 1; // bit 12 + uint16_t spare13 : 1; // bit 13 + uint16_t spare14 : 1; // bit 14 + uint16_t spare15 : 1; // bit 15 + }; +} tEnergyBitfield; + typedef struct { - uint32_t crc32; // To detect file changes - uint16_t version; // To detect driver function changes + uint32_t crc32; // To detect file changes + uint16_t version; // To detect driver function changes uint16_t energy_kWhdoy; uint32_t energy_kWhtotal_time; - uint32_t spare1; - uint32_t spare2; - uint32_t spare3; - uint32_t spare4; - uint32_t spare5; + tEnergyBitfield flag; + uint8_t gui_display; // EnergyDisplay - GUI display all relays (0), only powered on relays (1) or user selected relays (2) + uint8_t gui_cols; // EnergyCols + uint32_t spare32_1; + uint32_t spare32_2; + uint32_t spare32_3; + uint32_t spare32_4; uint32_t power_calibration[ENERGY_MAX_PHASES]; uint32_t voltage_calibration[ENERGY_MAX_PHASES]; @@ -137,36 +171,39 @@ typedef struct { float daily_sum_import_balanced; // 123.123 kWh float daily_sum_export_balanced; // 123.123 kWh + uint16_t power_history[ENERGY_MAX_PHASES][3]; + uint16_t mplh_counter; + uint16_t mplw_counter; + + uint8_t data_valid[ENERGY_MAX_PHASES]; + uint8_t phase_count; // Number of phases active uint8_t fifth_second; uint8_t command_code; - uint8_t data_valid[ENERGY_MAX_PHASES]; + uint8_t power_steady_counter; // Allow for power on stabilization + uint8_t mplr_counter; + uint8_t max_energy_state; + + uint8_t gui_indirect[ENERGY_MAX_PHASES]; + uint8_t gui_rotate; + uint8_t gui_count; + uint8_t gui_offset; - uint8_t phase_count; // Number of phases active bool voltage_common; // Use common voltage bool frequency_common; // Use common frequency bool use_overtemp; // Use global temperature as overtemp trigger on internal energy monitor hardware bool kWhtoday_offset_init; - bool voltage_available; // Enable if voltage is measured bool current_available; // Enable if current is measured bool local_energy_active_export; // Enable if support for storing energy_active - bool type_dc; bool power_on; - uint16_t power_history[ENERGY_MAX_PHASES][3]; - uint8_t power_steady_counter; // Allow for power on stabilization bool min_power_flag; bool max_power_flag; bool min_voltage_flag; bool max_voltage_flag; bool min_current_flag; bool max_current_flag; - - uint16_t mplh_counter; - uint16_t mplw_counter; - uint8_t mplr_counter; - uint8_t max_energy_state; } tEnergy; tEnergy *Energy = nullptr; @@ -240,7 +277,7 @@ bool EnergyRtcSettingsValid(void) { * Driver Settings load and save using filesystem \*********************************************************************************************/ -const uint32_t XDRV_03_VERSION = 0x0101; // Latest driver version (See settings deltas below) +const uint32_t XDRV_03_VERSION = 0x0102; // Latest driver version (See settings deltas below) void EnergySettingsLoad(void) { // *** Start init default values in case file is not found *** @@ -270,6 +307,11 @@ void EnergySettingsLoad(void) { Energy->Settings.power_delta[i] = (float)(Settings->energy_power_delta[i]); } + + // v0102 additions + Energy->Settings.gui_display = ENERGY_GUI_DISPLAY_MODE; + Energy->Settings.gui_cols = ENERGY_GUI_MAX_COLS; + // *** End Init default values *** #ifndef USE_UFILESYS @@ -283,6 +325,10 @@ void EnergySettingsLoad(void) { if (Energy->Settings.version != XDRV_03_VERSION) { // Fix version dependent changes // *** Start fix possible setting deltas *** + if (Energy->Settings.version < 0x0102) { + Energy->Settings.gui_display = ENERGY_GUI_DISPLAY_MODE; + Energy->Settings.gui_cols = ENERGY_GUI_MAX_COLS; + } // *** End setting deltas *** @@ -346,7 +392,7 @@ char* EnergyFormat(char* result, float* input, uint32_t resolution, uint32_t sin } result[0] = '\0'; for (uint32_t i = 0; i < index; i++) { - ext_snprintf_P(result, TOPSZ, PSTR("%s%s%*_f%s"), result, (0==i)?(1==index)?"":"[":",", resolution, &input[i], (index-1==i)?(1==index)?"":"]":""); + ext_snprintf_P(result, GUISZ, PSTR("%s%s%*_f%s"), result, (0==i)?(1==index)?"":"[":",", resolution, &input[i], (index-1==i)?(1==index)?"":"]":""); } return result; } @@ -372,20 +418,20 @@ char* WebEnergyFormat(char* result, float* input, uint32_t resolution, uint32_t } #ifdef USE_ENERGY_COLUMN_GUI ext_snprintf_P(result, GUISZ, PSTR("")); // Skip first column - if ((Energy->phase_count > 1) && single) { // Need to set colspan so need new columns + if ((Energy->gui_count > 1) && single) { // Need to set colspan so need new columns // "), - result, (Energy->phase_count *2) -1, (Settings->flag5.gui_table_align)?PSTR("right"):PSTR("center"), resolution, &input[0]); + result, (Energy->gui_count *2) -1, (Settings->flag5.gui_table_align)?PSTR("right"):PSTR("center"), resolution, &input[Energy->gui_indirect[0]]); } else { // "), - result, (Settings->flag5.gui_table_align)?PSTR("right"):PSTR("left"), resolution, &input[i]); + result, (Settings->flag5.gui_table_align)?PSTR("right"):PSTR("left"), resolution, &input[Energy->gui_indirect[Energy->gui_offset +i]]); } } ext_snprintf_P(result, GUISZ, PSTR("%s
) - bool no_label = Energy->voltage_common || (1 == Energy->phase_count); + bool label_o = Energy->voltage_common; + bool no_label = (1 == Energy->phase_count); for (uint32_t i = 0; i < Energy->phase_count; i++) { - WSContentSend_P(PSTR("%s%s%s%s{e}")); // Last column is units ({e} =
, {m} = , {e} =
1.23  // 1.23  // 1.23  ext_snprintf_P(result, GUISZ, PSTR("%s%*_f 1.23  // 1.23 1.23  // 1.23 1.23 1.23  // 1.23 1.23 1.23 1.23  - for (uint32_t i = 0; i < Energy->phase_count; i++) { + for (uint32_t i = 0; i < Energy->gui_count; i++) { ext_snprintf_P(result, GUISZ, PSTR("%s%*_f "), result); @@ -665,7 +711,7 @@ void EnergyMarginCheck(void) { for (uint32_t phase = 0; phase < Energy->phase_count; phase++) { power_diff_f[phase] = power_diff[phase]; } - char value_chr[TOPSZ]; + char value_chr[GUISZ]; ResponseAppend_P(PSTR("\"" D_CMND_POWERDELTA "\":%s"), EnergyFormat(value_chr, power_diff_f, 0)); } @@ -833,9 +879,9 @@ void EnergyEverySecond(void) { \*********************************************************************************************/ void ResponseCmndEnergyTotalYesterdayToday(void) { - char value_chr[TOPSZ]; // Used by EnergyFormatIndex - char value2_chr[TOPSZ]; - char value3_chr[TOPSZ]; + char value_chr[GUISZ]; // Used by EnergyFormatIndex + char value2_chr[GUISZ]; + char value3_chr[GUISZ]; float energy_yesterday_kWh[3]; for (uint32_t i = 0; i < Energy->phase_count; i++) { @@ -858,6 +904,26 @@ void ResponseCmndEnergyTotalYesterdayToday(void) { ResponseJsonEndEnd(); } +void CmndEnergyDisplay(void) { + // Select either all relays, only powered on relays or user selected relay group + // EnergyDisplay 1, EnergyDisplay 2 or EnergyDisplay 3 + if ((XdrvMailbox.payload > ENERGY_DISPLAY_MIN_OPTION) && (XdrvMailbox.payload < ENERGY_DISPLAY_MAX_OPTION)) { + Energy->Settings.gui_display = XdrvMailbox.payload; + Energy->gui_rotate = 0; + } + ResponseCmndNumber(Energy->Settings.gui_display); +} + +void CmndEnergyCols(void) { + // Select number of columns + // EnergyCols 1..8 + if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= ENERGY_MAX_PHASES)) { + Energy->Settings.gui_cols = XdrvMailbox.payload; + Energy->gui_rotate = 0; + } + ResponseCmndNumber(Energy->Settings.gui_cols); +} + void CmndEnergyTotal(void) { uint32_t values[2] = { 0 }; uint32_t params = ParseParameters(2, values); @@ -1536,55 +1602,114 @@ void EnergyShow(bool json) { #ifdef USE_WEBSERVER } else { #ifdef USE_ENERGY_COLUMN_GUI - // Need a new table supporting more columns using empty columns (with   in data rows) as easy column spacing - // {s}Head1{e} - // {s}Head1Head2{e} - // {s}Head1Head2Head3{e} - // {s}Head1Head2Head3Head4{e} - WSContentSend_P(PSTR("

{t}{s}")); // First column is empty ({t} = , {s} = "), (no_label)?"":(label_o)?"O":"L", (no_label)?"":itoa(i +1, value_chr, 10)); + uint8_t relays[ENERGY_MAX_PHASES]; + uint32_t relay_show = 0; + power_t power = TasmotaGlobal.power; + for (uint32_t i = 0; i < Energy->phase_count; i++) { // Init relays and gui_indirect tables based on EnergyDisplay + if ((ENERGY_DISPLAY_ROTATE == Energy->Settings.gui_display) || + ((ENERGY_DISPLAY_ROTATE_POWERED_ON == Energy->Settings.gui_display) && (power >> i) &1) || + (ENERGY_DISPLAY_TABS == Energy->Settings.gui_display)) { + relays[relay_show] = i +1; + Energy->gui_indirect[relay_show] = i; + relay_show++; + } } - WSContentSend_P(PSTR(") + + if (relay_show) { + if (Energy->Settings.gui_display != ENERGY_DISPLAY_TABS) { + if (relay_show > Energy->Settings.gui_cols) { + Energy->gui_rotate++; + } else { + Energy->gui_rotate = 0; + } + } + if (Energy->gui_rotate >= relay_show) { + Energy->gui_rotate = 0; + } + Energy->gui_offset = (Energy->gui_rotate / Energy->Settings.gui_cols) * Energy->Settings.gui_cols; + Energy->gui_count = relay_show - Energy->gui_offset; + if (Energy->gui_count > Energy->Settings.gui_cols) { Energy->gui_count = Energy->Settings.gui_cols; } + + WSContentSend_P(PSTR("
) - bool label_o = Energy->voltage_common; - bool no_label = (1 == Energy->phase_count); - for (uint32_t i = 0; i < Energy->phase_count; i++) { - WSContentSend_P(PSTR("%s%s{e}")); // Last column is units ({e} =

")); // Close current table as we will use different column count + bool label_o = Energy->voltage_common; + if (ENERGY_DISPLAY_TABS == Energy->Settings.gui_display) { + uint32_t tabs = (relay_show -1 + Energy->Settings.gui_cols) / Energy->Settings.gui_cols; + if (tabs > 1) { + WSContentSend_P(PSTR("{t}")); // {t} = + uint32_t cols_width = 100 / tabs; + uint32_t current_tab = Energy->gui_rotate / Energy->Settings.gui_cols; + for (uint32_t idx = 0; idx < tabs; idx++) { + WSContentSend_P(PSTR(""), // &k03 is related to WebGetArg("k", tmp, sizeof(tmp)); + cols_width, + (current_tab == idx) ? WebColor(COL_BACKGROUND) : WebColor(COL_FORM), + (current_tab == idx) ? "bold" : "normal", + idx, + (label_o) ? "O" : "L", (idx *Energy->Settings.gui_cols) +1); + } + WSContentSend_P(PSTR("
")); // Close current table as we will use different column count + } + } + // {s}Head1{e} + // {s}Head1Head2{e} + // {s}Head1Head2Head3{e} + // {s}Head1Head2Head3Head4{e} + WSContentSend_P(PSTR("{t}{s}")); // First column is empty ({t} = , {s} = "), + (no_label) ? "" : (label_o) ? "O" : "L", + (no_label) ? "" : itoa(relays[Energy->gui_offset +i], value_chr, 10)); + } + WSContentSend_P(PSTR(") #endif // USE_ENERGY_COLUMN_GUI - if (Energy->voltage_available) { - WSContentSend_PD(HTTP_SNS_VOLTAGE, WebEnergyFormat(value_chr, Energy->voltage, Settings->flag2.voltage_resolution, Energy->voltage_common)); - } - if (!Energy->type_dc) { - if (!isnan(Energy->frequency[0])) { - WSContentSend_PD(PSTR("{s}" D_FREQUENCY "{m}%s " D_UNIT_HERTZ "{e}"), - WebEnergyFormat(value_chr, Energy->frequency, Settings->flag2.frequency_resolution, Energy->frequency_common)); + if (Energy->voltage_available) { + WSContentSend_PD(HTTP_SNS_VOLTAGE, WebEnergyFormat(value_chr, Energy->voltage, Settings->flag2.voltage_resolution, Energy->voltage_common)); } - } - if (Energy->current_available) { - WSContentSend_PD(HTTP_SNS_CURRENT, WebEnergyFormat(value_chr, Energy->current, Settings->flag2.current_resolution)); - } - WSContentSend_PD(HTTP_SNS_POWER, WebEnergyFormat(value_chr, Energy->active_power, Settings->flag2.wattage_resolution)); - if (!Energy->type_dc) { - if (Energy->current_available && Energy->voltage_available) { - WSContentSend_PD(HTTP_ENERGY_SNS1, WebEnergyFormat(value_chr, apparent_power, Settings->flag2.wattage_resolution), - WebEnergyFormat(value2_chr, reactive_power, Settings->flag2.wattage_resolution), - WebEnergyFormat(value3_chr, power_factor, 2)); + if (!Energy->type_dc) { + if (!isnan(Energy->frequency[0])) { + WSContentSend_PD(PSTR("{s}" D_FREQUENCY "{m}%s " D_UNIT_HERTZ "{e}"), + WebEnergyFormat(value_chr, Energy->frequency, Settings->flag2.frequency_resolution, Energy->frequency_common)); + } } - } - WSContentSend_PD(HTTP_ENERGY_SNS2, WebEnergyFormat(value_chr, Energy->daily_kWh, Settings->flag2.energy_resolution, 2), - WebEnergyFormat(value2_chr, energy_yesterday_kWh, Settings->flag2.energy_resolution, 2), - WebEnergyFormat(value3_chr, Energy->total, Settings->flag2.energy_resolution, 2)); - if (!isnan(Energy->export_active[0])) { - uint32_t single = (!isnan(Energy->export_active[1]) && !isnan(Energy->export_active[2])) ? 2 : 1; - WSContentSend_PD(HTTP_ENERGY_SNS3, WebEnergyFormat(value_chr, Energy->export_active, Settings->flag2.energy_resolution, single)); - } + if (Energy->current_available) { + WSContentSend_PD(HTTP_SNS_CURRENT, WebEnergyFormat(value_chr, Energy->current, Settings->flag2.current_resolution)); + } + WSContentSend_PD(HTTP_SNS_POWER, WebEnergyFormat(value_chr, Energy->active_power, Settings->flag2.wattage_resolution)); + if (!Energy->type_dc) { + if (Energy->current_available && Energy->voltage_available) { + WSContentSend_PD(HTTP_ENERGY_SNS1, WebEnergyFormat(value_chr, apparent_power, Settings->flag2.wattage_resolution), + WebEnergyFormat(value2_chr, reactive_power, Settings->flag2.wattage_resolution), + WebEnergyFormat(value3_chr, power_factor, 2)); + } + } + WSContentSend_PD(HTTP_ENERGY_SNS2, WebEnergyFormat(value_chr, Energy->daily_kWh, Settings->flag2.energy_resolution, 2), + WebEnergyFormat(value2_chr, energy_yesterday_kWh, Settings->flag2.energy_resolution, 2), + WebEnergyFormat(value3_chr, Energy->total, Settings->flag2.energy_resolution, 2)); + if (!isnan(Energy->export_active[0])) { + uint32_t single = (!isnan(Energy->export_active[1]) && !isnan(Energy->export_active[2])) ? 2 : 1; + WSContentSend_PD(HTTP_ENERGY_SNS3, WebEnergyFormat(value_chr, Energy->export_active, Settings->flag2.energy_resolution, single)); + } + #ifdef USE_ENERGY_COLUMN_GUI - XnrgCall(FUNC_WEB_COL_SENSOR); - WSContentSend_P(PSTR("
) + bool no_label = (1 == Energy->phase_count); + for (uint32_t i = 0; i < Energy->gui_count; i++) { + WSContentSend_P(PSTR("%s%s{e}")); // Last column is units ({e} =

{t}")); // {t} = - Define for next FUNC_WEB_SENSOR + XnrgCall(FUNC_WEB_COL_SENSOR); + WSContentSend_P(PSTR("

{t}")); // {t} = - Define for next FUNC_WEB_SENSOR #endif // USE_ENERGY_COLUMN_GUI - XnrgCall(FUNC_WEB_SENSOR); + XnrgCall(FUNC_WEB_SENSOR); #endif // USE_WEBSERVER + } } } +#ifdef USE_WEBSERVER + +void EnergyWebGetArg(void) { + char tmp[8]; // WebGetArg numbers only + WebGetArg(PSTR("k03"), tmp, sizeof(tmp)); // relay gtoups + if (strlen(tmp)) { Energy->gui_rotate = atoi(tmp) * Energy->Settings.gui_cols; } +} + +#endif // USE_WEBSERVER + /*********************************************************************************************\ * Interface \*********************************************************************************************/ @@ -1650,6 +1775,9 @@ bool Xsns03(uint32_t function) case FUNC_WEB_SENSOR: EnergyShow(false); break; + case FUNC_WEB_GET_ARG: + EnergyWebGetArg(); + break; #endif // USE_WEBSERVER case FUNC_SAVE_BEFORE_RESTART: EnergySaveState(); diff --git a/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino b/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino index 3c55df525..0eda31567 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino @@ -660,7 +660,7 @@ void Ade7953DrvInit(void) { if (PinUsed(GPIO_ADE7953_IRQ, GPIO_ANY)) { // Irq is not supported... uint32_t pin_irq = Pin(GPIO_ADE7953_IRQ, GPIO_ANY); pinMode(pin_irq, INPUT); // Related to resetPins() - Must be set to input - // 0 (1 = Shelly 2.5), 1 (2 = Shelly EM), 2 (3 = Shelly Plus 2PM), 3 (4 = Shelly Pro 1PM), 4 (5 = Shelly Pro 2PM) + // 0 (1 = Shelly 2.5), 1 (2 = Shelly EM), 2 (3 = Shelly Plus 2PM), 3 (4 = Shelly Pro 1PM), 4 (5 = Shelly Pro 2PM), 5 (6 = Shelly Pro 4PM) Ade7953.model = GetPin(pin_irq) - AGPIO(GPIO_ADE7953_IRQ); int pin_reset = Pin(GPIO_ADE7953_RST); // -1 if not defined From 5b0ee76173546007ff98048c9f8a5c3ff04639fb Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 30 Jan 2023 13:14:02 +0100 Subject: [PATCH 200/262] Fix ESP32 energy monitoring migration --- .../xdrv_03_esp32_energy.ino | 39 +++++++++++-------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino b/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino index cf218d91c..413562800 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino @@ -299,13 +299,18 @@ void EnergySettingsLoad(void) { RtcEnergySettings.energy_total_kWh[2] = 0; memset((char*)&RtcEnergySettings.energy_usage, 0x00, sizeof(RtcEnergySettings.energy_usage)); */ + Energy->Settings.energy_kWhdoy = Settings->energy_kWhdoy; for (uint32_t i = 0; i < 3; i++) { - Energy->Settings.energy_today_kWh[i] = (float)(Settings->energy_kWhtoday_ph[i]) / 10000; - Energy->Settings.energy_yesterday_kWh[i] = (float)(Settings->energy_kWhyesterday_ph[i]) / 10000; - Energy->Settings.energy_total_kWh[i] = (float)(Settings->energy_kWhtotal_ph[i]) / 10000; - Energy->Settings.energy_export_kWh[i] = (float)(Settings->energy_kWhexport_ph[i]) / 10000; + Energy->Settings.energy_today_kWh[i] = (float)Settings->energy_kWhtoday_ph[i] / 100000; + Energy->Settings.energy_yesterday_kWh[i] = (float)Settings->energy_kWhyesterday_ph[i] / 100000; + Energy->Settings.energy_total_kWh[i] = (float)Settings->energy_kWhtotal_ph[i] / 1000; + Energy->Settings.energy_export_kWh[i] = (float)Settings->energy_kWhexport_ph[i] / 1000; - Energy->Settings.power_delta[i] = (float)(Settings->energy_power_delta[i]); + Energy->Settings.power_delta[i] = (float)Settings->energy_power_delta[i]; + +// AddLog(LOG_LEVEL_INFO, PSTR("DBG: kWhtoday %d = %4_f, kWhyesterday %d = %4_f"), +// Settings->energy_kWhtoday_ph[i], &Energy->Settings.energy_today_kWh[i], +// Settings->energy_kWhyesterday_ph[i], &Energy->Settings.energy_yesterday_kWh[i]); } // v0102 additions @@ -491,7 +496,7 @@ void EnergyUpdateToday(void) { } } - RtcEnergySettings.energy_today_kWh[i] = Energy->energy_today_offset_kWh[i] + ((float)(Energy->kWhtoday[i]) / 100000); + RtcEnergySettings.energy_today_kWh[i] = Energy->energy_today_offset_kWh[i] + ((float)Energy->kWhtoday[i] / 100000); Energy->daily_kWh[i] = RtcEnergySettings.energy_today_kWh[i]; Energy->total[i] = RtcEnergySettings.energy_total_kWh[i] + RtcEnergySettings.energy_today_kWh[i]; if (Energy->local_energy_active_export) { @@ -564,7 +569,7 @@ void EnergyUpdateTotal(void) { if ((Energy->total[i] < (Energy->import_active[i] - 0.01f)) && // We subtract a little offset of 10Wh to avoid continuous updates Settings->flag3.hardware_energy_total) { // SetOption72 - Enable hardware energy total counter as reference (#6561) // The following calculation allows total usage (Energy->import_active[i]) up to +/-2147483.647 kWh - RtcEnergySettings.energy_total_kWh[i] = Energy->import_active[i] - (Energy->energy_today_offset_kWh[i] + ((float)(Energy->kWhtoday[i]) / 100000)); + RtcEnergySettings.energy_total_kWh[i] = Energy->import_active[i] - (Energy->energy_today_offset_kWh[i] + ((float)Energy->kWhtoday[i] / 100000)); Energy->Settings.energy_total_kWh[i] = RtcEnergySettings.energy_total_kWh[i]; Energy->total[i] = Energy->import_active[i]; Energy->Settings.energy_kWhtotal_time = (!Energy->energy_today_offset_kWh[i]) ? LocalTime() : Midnight(); @@ -601,7 +606,7 @@ void Energy200ms(void) { Energy->kWhtoday_offset_init = true; Energy->Settings.energy_kWhdoy = RtcTime.day_of_year; - for (uint32_t i = 0; i < 3; i++) { + for (uint32_t i = 0; i < ENERGY_MAX_PHASES; i++) { Energy->Settings.energy_yesterday_kWh[i] = RtcEnergySettings.energy_today_kWh[i]; RtcEnergySettings.energy_total_kWh[i] += RtcEnergySettings.energy_today_kWh[i]; @@ -886,7 +891,7 @@ void ResponseCmndEnergyTotalYesterdayToday(void) { float energy_yesterday_kWh[3]; for (uint32_t i = 0; i < Energy->phase_count; i++) { energy_yesterday_kWh[i] = Energy->Settings.energy_yesterday_kWh[i]; - Energy->total[i] = RtcEnergySettings.energy_total_kWh[i] + Energy->energy_today_offset_kWh[i] + ((float)(Energy->kWhtoday[i]) / 100000); + Energy->total[i] = RtcEnergySettings.energy_total_kWh[i] + Energy->energy_today_offset_kWh[i] + ((float)Energy->kWhtoday[i] / 100000); if (Energy->local_energy_active_export) { Energy->export_active[i] = RtcEnergySettings.energy_export_kWh[i]; } @@ -931,7 +936,7 @@ void CmndEnergyTotal(void) { if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= Energy->phase_count) && (params > 0)) { uint32_t phase = XdrvMailbox.index -1; // Reset Energy Total - RtcEnergySettings.energy_total_kWh[phase] = (float)(values[0]) / 1000; + RtcEnergySettings.energy_total_kWh[phase] = (float)values[0] / 1000; Energy->Settings.energy_total_kWh[phase] = RtcEnergySettings.energy_total_kWh[phase]; if (params > 1) { Energy->Settings.energy_kWhtotal_time = values[1]; @@ -950,7 +955,7 @@ void CmndEnergyYesterday(void) { if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= Energy->phase_count) && (params > 0)) { uint32_t phase = XdrvMailbox.index -1; // Reset Energy Yesterday - Energy->Settings.energy_yesterday_kWh[phase] = (float)(values[0]) / 1000; + Energy->Settings.energy_yesterday_kWh[phase] = (float)values[0] / 1000; if (params > 1) { Energy->Settings.energy_kWhtotal_time = values[1]; } @@ -966,7 +971,7 @@ void CmndEnergyToday(void) { if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= Energy->phase_count) && (params > 0)) { uint32_t phase = XdrvMailbox.index -1; // Reset Energy Today - Energy->energy_today_offset_kWh[phase] = (float)(values[0]) / 1000; + Energy->energy_today_offset_kWh[phase] = (float)values[0] / 1000; Energy->kWhtoday[phase] = 0; Energy->kWhtoday_delta[phase] = 0; Energy->start_energy[phase] = 0; @@ -994,7 +999,7 @@ void CmndEnergyExportActive(void) { if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= Energy->phase_count) && (params > 0)) { uint32_t phase = XdrvMailbox.index -1; // Reset Energy Export Active - RtcEnergySettings.energy_export_kWh[phase] = (float)(values[0]) / 1000; + RtcEnergySettings.energy_export_kWh[phase] = (float)values[0] / 1000; Energy->Settings.energy_export_kWh[phase] = RtcEnergySettings.energy_export_kWh[phase]; if (params > 1) { Energy->Settings.energy_kWhtotal_time = values[1]; @@ -1018,9 +1023,9 @@ void CmndEnergyUsage(void) { uint32_t params = ParseParameters(2, values); if (params > 0) { // Reset energy_usage.usage totals - RtcEnergySettings.energy_usage.usage_total_kWh[0] = (float)(values[0]) / 1000; + RtcEnergySettings.energy_usage.usage_total_kWh[0] = (float)values[0] / 1000; if (params > 1) { - RtcEnergySettings.energy_usage.usage_total_kWh[1] = (float)(values[1]) / 1000; + RtcEnergySettings.energy_usage.usage_total_kWh[1] = (float)values[1] / 1000; } Energy->Settings.energy_usage.usage_total_kWh[0] = RtcEnergySettings.energy_usage.usage_total_kWh[0]; Energy->Settings.energy_usage.usage_total_kWh[1] = RtcEnergySettings.energy_usage.usage_total_kWh[1]; @@ -1033,9 +1038,9 @@ void CmndEnergyExport(void) { uint32_t params = ParseParameters(2, values); if (params > 0) { // Reset energy_usage.return totals - RtcEnergySettings.energy_usage.return_total_kWh[0] = (float)(values[0]) / 1000; + RtcEnergySettings.energy_usage.return_total_kWh[0] = (float)values[0] / 1000; if (params > 1) { - RtcEnergySettings.energy_usage.return_total_kWh[1] = (float)(values[1]) / 1000; + RtcEnergySettings.energy_usage.return_total_kWh[1] = (float)values[1] / 1000; } Energy->Settings.energy_usage.return_total_kWh[0] = RtcEnergySettings.energy_usage.return_total_kWh[0]; Energy->Settings.energy_usage.return_total_kWh[1] = RtcEnergySettings.energy_usage.return_total_kWh[1]; From 9e9afe88f18a6b6ad81ffa9307d586b0ead8c1a8 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 30 Jan 2023 14:16:13 +0100 Subject: [PATCH 201/262] Fix ESP32 energy monitoring over 3 phases --- tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino b/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino index 413562800..62f36bbba 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino @@ -166,8 +166,8 @@ typedef struct { // Local only float daily_kWh[ENERGY_MAX_PHASES]; // 123.123 kWh - float energy_today_offset_kWh[ENERGY_MAX_PHASES]; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = Energy->daily - float period_kWh[ENERGY_MAX_PHASES]; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = Energy->daily + float energy_today_offset_kWh[ENERGY_MAX_PHASES]; // 123.12312 kWh = Energy->daily + float period_kWh[ENERGY_MAX_PHASES]; // 123.12312 kWh = Energy->daily float daily_sum_import_balanced; // 123.123 kWh float daily_sum_export_balanced; // 123.123 kWh @@ -595,7 +595,7 @@ void Energy200ms(void) { if (!Energy->kWhtoday_offset_init && (RtcTime.day_of_year == Energy->Settings.energy_kWhdoy)) { Energy->kWhtoday_offset_init = true; - for (uint32_t i = 0; i < 3; i++) { + for (uint32_t i = 0; i < ENERGY_MAX_PHASES; i++) { Energy->energy_today_offset_kWh[i] = Energy->Settings.energy_today_kWh[i]; // RtcEnergySettings.energy_today_kWh[i] = 0; } @@ -642,7 +642,7 @@ void Energy200ms(void) { void EnergySaveState(void) { Energy->Settings.energy_kWhdoy = (RtcTime.valid) ? RtcTime.day_of_year : 0; - for (uint32_t i = 0; i < 3; i++) { + for (uint32_t i = 0; i < ENERGY_MAX_PHASES; i++) { Energy->Settings.energy_today_kWh[i] = RtcEnergySettings.energy_today_kWh[i]; Energy->Settings.energy_total_kWh[i] = RtcEnergySettings.energy_total_kWh[i]; Energy->Settings.energy_export_kWh[i] = RtcEnergySettings.energy_export_kWh[i]; @@ -1380,7 +1380,7 @@ void EnergySnsInit(void) { &Energy->Settings.energy_today_kWh[0],&Energy->Settings.energy_today_kWh[1],&Energy->Settings.energy_today_kWh[2] ); */ - for (uint32_t i = 0; i < 3; i++) { + for (uint32_t i = 0; i < ENERGY_MAX_PHASES; i++) { // Energy->energy_today_offset_kWh[i] = 0; // Reset by EnergyDrvInit() // 20220805 - Change from https://github.com/arendst/Tasmota/issues/16118 if (EnergyRtcSettingsValid()) { From f09a083777c4e2b524f79360bb754c1c5bef1eed Mon Sep 17 00:00:00 2001 From: gemu Date: Mon, 30 Jan 2023 15:03:46 +0100 Subject: [PATCH 202/262] Sml ams (#17828) * sml ams crypto support * add ams library * fix crc names * fix TLS dependency * Update library.properties * Update xsns_53_sml.ino --- lib/lib_div/ams/Cosem.cpp | 25 + lib/lib_div/ams/Cosem.h | 92 +++ lib/lib_div/ams/DataParser.h | 31 + lib/lib_div/ams/DataParsers.h | 13 + lib/lib_div/ams/DlmsParser.cpp | 38 ++ lib/lib_div/ams/DlmsParser.h | 12 + lib/lib_div/ams/DsmrParser.cpp | 29 + lib/lib_div/ams/DsmrParser.h | 13 + lib/lib_div/ams/GbtParser.cpp | 36 ++ lib/lib_div/ams/GbtParser.h | 27 + lib/lib_div/ams/GcmParser.cpp | 104 +++ lib/lib_div/ams/GcmParser.h | 28 + lib/lib_div/ams/HdlcParser.cpp | 56 ++ lib/lib_div/ams/HdlcParser.h | 29 + lib/lib_div/ams/LlcParser.cpp | 6 + lib/lib_div/ams/LlcParser.h | 18 + lib/lib_div/ams/MbusParser.cpp | 91 +++ lib/lib_div/ams/MbusParser.h | 35 + lib/lib_div/ams/Time.cpp | 321 ++++++++++ lib/lib_div/ams/TimeLib.h | 144 +++++ lib/lib_div/ams/crc.cpp | 29 + lib/lib_div/ams/crc.h | 10 + lib/lib_div/ams/han_Parser.cpp | 273 ++++++++ lib/lib_div/ams/han_Parser.h | 47 ++ lib/lib_div/ams/hexutils.cpp | 23 + lib/lib_div/ams/hexutils.h | 11 + lib/lib_div/ams/library.json | 17 + lib/lib_div/ams/library.properties | 17 + lib/lib_div/ams/ntohll.cpp | 5 + lib/lib_div/ams/ntohll.h | 8 + .../tasmota_xdrv_driver/xdrv_10_scripter.ino | 12 +- tasmota/tasmota_xsns_sensor/xsns_53_sml.ino | 600 +++++++++++------- 32 files changed, 1972 insertions(+), 228 deletions(-) create mode 100644 lib/lib_div/ams/Cosem.cpp create mode 100644 lib/lib_div/ams/Cosem.h create mode 100644 lib/lib_div/ams/DataParser.h create mode 100644 lib/lib_div/ams/DataParsers.h create mode 100644 lib/lib_div/ams/DlmsParser.cpp create mode 100644 lib/lib_div/ams/DlmsParser.h create mode 100644 lib/lib_div/ams/DsmrParser.cpp create mode 100644 lib/lib_div/ams/DsmrParser.h create mode 100644 lib/lib_div/ams/GbtParser.cpp create mode 100644 lib/lib_div/ams/GbtParser.h create mode 100644 lib/lib_div/ams/GcmParser.cpp create mode 100644 lib/lib_div/ams/GcmParser.h create mode 100644 lib/lib_div/ams/HdlcParser.cpp create mode 100644 lib/lib_div/ams/HdlcParser.h create mode 100644 lib/lib_div/ams/LlcParser.cpp create mode 100644 lib/lib_div/ams/LlcParser.h create mode 100644 lib/lib_div/ams/MbusParser.cpp create mode 100644 lib/lib_div/ams/MbusParser.h create mode 100644 lib/lib_div/ams/Time.cpp create mode 100644 lib/lib_div/ams/TimeLib.h create mode 100644 lib/lib_div/ams/crc.cpp create mode 100644 lib/lib_div/ams/crc.h create mode 100644 lib/lib_div/ams/han_Parser.cpp create mode 100644 lib/lib_div/ams/han_Parser.h create mode 100644 lib/lib_div/ams/hexutils.cpp create mode 100644 lib/lib_div/ams/hexutils.h create mode 100644 lib/lib_div/ams/library.json create mode 100755 lib/lib_div/ams/library.properties create mode 100644 lib/lib_div/ams/ntohll.cpp create mode 100644 lib/lib_div/ams/ntohll.h diff --git a/lib/lib_div/ams/Cosem.cpp b/lib/lib_div/ams/Cosem.cpp new file mode 100644 index 000000000..b53cc74b6 --- /dev/null +++ b/lib/lib_div/ams/Cosem.cpp @@ -0,0 +1,25 @@ +#include "Cosem.h" +#include "lwip/def.h" +#include "TimeLib.h" + + +time_t decodeCosemDateTime(CosemDateTime timestamp) { + tmElements_t tm; + uint16_t year = ntohs(timestamp.year); + if(year < 1970) return 0; + tm.Year = year - 1970; + tm.Month = timestamp.month; + tm.Day = timestamp.dayOfMonth; + tm.Hour = timestamp.hour; + tm.Minute = timestamp.minute; + tm.Second = timestamp.second; + + //Serial.printf("\nY: %d, M: %d, D: %d, h: %d, m: %d, s: %d, deviation: 0x%2X, status: 0x%1X\n", tm.Year, tm.Month, tm.Day, tm.Hour, tm.Minute, tm.Second, timestamp.deviation, timestamp.status); + + time_t time = makeTime(tm); + int16_t deviation = ntohs(timestamp.deviation); + if(deviation >= -720 && deviation <= 720) { + time -= deviation * 60; + } + return time; +} diff --git a/lib/lib_div/ams/Cosem.h b/lib/lib_div/ams/Cosem.h new file mode 100644 index 000000000..e218cd7eb --- /dev/null +++ b/lib/lib_div/ams/Cosem.h @@ -0,0 +1,92 @@ +#ifndef _COSEM_H +#define _COSEM_H + +#include "lwip/def.h" + +// Blue book, Table 2 +enum CosemType { + CosemTypeNull = 0x00, + CosemTypeArray = 0x01, + CosemTypeStructure = 0x02, + CosemTypeOctetString = 0x09, + CosemTypeString = 0x0A, + CosemTypeDLongSigned = 0x05, + CosemTypeDLongUnsigned = 0x06, + CosemTypeLongSigned = 0x10, + CosemTypeLongUnsigned = 0x12, + CosemTypeLong64Signed = 0x14, + CosemTypeLong64Unsigned = 0x15, + CosemTypeDateTime = 0x19 +}; + +struct CosemBasic { + uint8_t type; + uint8_t length; +} __attribute__((packed)); + +struct CosemString { + uint8_t type; + uint8_t length; + uint8_t data[]; +} __attribute__((packed)); + +struct CosemLongSigned { + uint8_t type; + int16_t data; +} __attribute__((packed)); + +struct CosemLongUnsigned { + uint8_t type; + uint16_t data; +} __attribute__((packed)); + +struct CosemDLongSigned { + uint8_t type; + int32_t data; +} __attribute__((packed)); + +struct CosemDLongUnsigned { + uint8_t type; + uint32_t data; +} __attribute__((packed)); + +struct CosemLong64Signed { + uint8_t type; + int64_t data; +} __attribute__((packed)); + +struct CosemLong64Unsigned { + uint8_t type; + uint64_t data; +} __attribute__((packed)); + +struct CosemDateTime { + uint8_t type; + uint16_t year; + uint8_t month; + uint8_t dayOfMonth; + uint8_t dayOfWeek; + uint8_t hour; + uint8_t minute; + uint8_t second; + uint8_t hundredths; + int16_t deviation; + uint8_t status; +} __attribute__((packed)); + +typedef union { + struct CosemBasic base; + struct CosemString str; + struct CosemString oct; + struct CosemLongSigned ls; + struct CosemLongUnsigned lu; + struct CosemDLongSigned dls; + struct CosemDLongUnsigned dlu; + struct CosemLong64Signed l64s; + struct CosemLong64Unsigned l64u; + struct CosemDateTime dt; +} CosemData; + +time_t decodeCosemDateTime(CosemDateTime timestamp); + +#endif diff --git a/lib/lib_div/ams/DataParser.h b/lib/lib_div/ams/DataParser.h new file mode 100644 index 000000000..6aa92faec --- /dev/null +++ b/lib/lib_div/ams/DataParser.h @@ -0,0 +1,31 @@ +#ifndef _DATAPASERSER_H +#define _DATAPASERSER_H + +#define DATA_TAG_NONE 0x00 +#define DATA_TAG_AUTO 0x01 +#define DATA_TAG_HDLC 0x7E +#define DATA_TAG_LLC 0xE6 +#define DATA_TAG_DLMS 0x0F +#define DATA_TAG_DSMR 0x2F +#define DATA_TAG_MBUS 0x68 +#define DATA_TAG_GBT 0xE0 +#define DATA_TAG_GCM 0xDB + +#define DATA_PARSE_OK 0 +#define DATA_PARSE_FAIL -1 +#define DATA_PARSE_INCOMPLETE -2 +#define DATA_PARSE_BOUNDRY_FLAG_MISSING -3 +#define DATA_PARSE_HEADER_CHECKSUM_ERROR -4 +#define DATA_PARSE_FOOTER_CHECKSUM_ERROR -5 +#define DATA_PARSE_INTERMEDIATE_SEGMENT -6 +#define DATA_PARSE_FINAL_SEGMENT -7 +#define DATA_PARSE_UNKNOWN_DATA -9 + +struct DataParserContext { + uint8_t type; + uint16_t length; + time_t timestamp; + uint8_t system_title[8]; +}; + +#endif diff --git a/lib/lib_div/ams/DataParsers.h b/lib/lib_div/ams/DataParsers.h new file mode 100644 index 000000000..5355784e8 --- /dev/null +++ b/lib/lib_div/ams/DataParsers.h @@ -0,0 +1,13 @@ +#ifndef _DATAPASERSERS_H +#define _DATAPASERSERS_H + +#include "HdlcParser.h" +#include "DlmsParser.h" +#include "DsmrParser.h" +#include "MbusParser.h" +#include "GbtParser.h" +#include "GcmParser.h" +#include "LlcParser.h" + +#endif + diff --git a/lib/lib_div/ams/DlmsParser.cpp b/lib/lib_div/ams/DlmsParser.cpp new file mode 100644 index 000000000..f0ed63e2b --- /dev/null +++ b/lib/lib_div/ams/DlmsParser.cpp @@ -0,0 +1,38 @@ +#include "DlmsParser.h" +#include "Cosem.h" + +int8_t DLMSParser::parse(uint8_t *buf, DataParserContext &ctx) { + if(ctx.length < 6) return DATA_PARSE_INCOMPLETE; + + uint8_t* ptr = buf+1; + ptr += 4; // Skip invoke ID and priority + + CosemData* item = (CosemData*) ptr; + if(item->base.type == CosemTypeOctetString) { + if(item->base.length == 0x0C) { + CosemDateTime* dateTime = (CosemDateTime*) (ptr+1); + ctx.timestamp = decodeCosemDateTime(*dateTime); + } + uint8_t len = 5+14; + ctx.length -= len; + return len; + } else if(item->base.type == CosemTypeNull) { + ctx.timestamp = 0; + uint8_t len = 5+1; + ctx.length -= len; + return len; + } else if(item->base.type == CosemTypeDateTime) { + CosemDateTime* dateTime = (CosemDateTime*) (ptr); + ctx.timestamp = decodeCosemDateTime(*dateTime); + uint8_t len = 5+13; + ctx.length -= len; + return len; + } else if(item->base.type == 0x0C) { // Kamstrup bug... + CosemDateTime* dateTime = (CosemDateTime*) (ptr); + ctx.timestamp = decodeCosemDateTime(*dateTime); + uint8_t len = 5+13; + ctx.length -= len; + return len; + } + return DATA_PARSE_UNKNOWN_DATA; +} diff --git a/lib/lib_div/ams/DlmsParser.h b/lib/lib_div/ams/DlmsParser.h new file mode 100644 index 000000000..200f0fe91 --- /dev/null +++ b/lib/lib_div/ams/DlmsParser.h @@ -0,0 +1,12 @@ +#ifndef _DLMSPARSER_H +#define _DLMSPARSER_H + +#include "Arduino.h" +#include "DataParser.h" + +class DLMSParser { +public: + int8_t parse(uint8_t *buf, DataParserContext &ctx); +}; + +#endif diff --git a/lib/lib_div/ams/DsmrParser.cpp b/lib/lib_div/ams/DsmrParser.cpp new file mode 100644 index 000000000..94ab1c42e --- /dev/null +++ b/lib/lib_div/ams/DsmrParser.cpp @@ -0,0 +1,29 @@ +#include "DsmrParser.h" +#include "crc.h" +#include "hexutils.h" +#include "lwip/def.h" + +int8_t DSMRParser::parse(uint8_t *buf, DataParserContext &ctx, bool verified) { + uint16_t crcPos = 0; + bool reachedEnd = verified; + uint8_t lastByte = 0x00; + for(int pos = 0; pos < ctx.length; pos++) { + uint8_t b = *(buf+pos); + if(pos == 0 && b != '/') return DATA_PARSE_BOUNDRY_FLAG_MISSING; + if(pos > 0 && b == '!' && lastByte == '\n') crcPos = pos+1; + if(crcPos > 0 && b == '\n') reachedEnd = true; + lastByte = b; + } + if(!reachedEnd) return DATA_PARSE_INCOMPLETE; + buf[ctx.length+1] = '\0'; + if(crcPos > 0) { + uint16_t crc_calc = AMS_crc16(buf, crcPos); + uint16_t crc = 0x0000; + AMS_fromHex((uint8_t*) &crc, String((char*) buf+crcPos), 2); + crc = ntohs(crc); + + if(crc != crc_calc) + return DATA_PARSE_FOOTER_CHECKSUM_ERROR; + } + return DATA_PARSE_OK; +} diff --git a/lib/lib_div/ams/DsmrParser.h b/lib/lib_div/ams/DsmrParser.h new file mode 100644 index 000000000..7d476de9f --- /dev/null +++ b/lib/lib_div/ams/DsmrParser.h @@ -0,0 +1,13 @@ +#ifndef _DSMRPARSER_H +#define _DSMRPARSER_H + +#include "Arduino.h" +#include "DataParser.h" + +class DSMRParser { +public: + int8_t parse(uint8_t *buf, DataParserContext &ctx, bool verified); +private: +}; + +#endif diff --git a/lib/lib_div/ams/GbtParser.cpp b/lib/lib_div/ams/GbtParser.cpp new file mode 100644 index 000000000..34e366a3b --- /dev/null +++ b/lib/lib_div/ams/GbtParser.cpp @@ -0,0 +1,36 @@ +#include "GbtParser.h" +#include "lwip/def.h" + +GBTParser::~GBTParser(void) { + if (buf) free(buf); +} + +int8_t GBTParser::parse(uint8_t *d, DataParserContext &ctx) { + GBTHeader* h = (GBTHeader*) (d); + uint16_t sequence = ntohs(h->sequence); + + if(h->flag != GBT_TAG) return DATA_PARSE_BOUNDRY_FLAG_MISSING; + + if(sequence == 1) { + if(buf == NULL) buf = (uint8_t *)malloc((size_t)1024); // TODO find out from first package ? + pos = 0; + } else if(lastSequenceNumber != sequence-1) { + return DATA_PARSE_FAIL; + } + + if(buf == NULL) return DATA_PARSE_FAIL; + + uint8_t* ptr = (uint8_t*) &h[1]; + memcpy(buf + pos, ptr, h->size); + pos += h->size; + lastSequenceNumber = sequence; + + if((h->control & 0x80) == 0x00) { + return DATA_PARSE_INTERMEDIATE_SEGMENT; + } else { + memcpy((uint8_t *) d, buf, pos); + } + ctx.length = pos; + return DATA_PARSE_OK; + +} diff --git a/lib/lib_div/ams/GbtParser.h b/lib/lib_div/ams/GbtParser.h new file mode 100644 index 000000000..d184895db --- /dev/null +++ b/lib/lib_div/ams/GbtParser.h @@ -0,0 +1,27 @@ +#ifndef _GBTPARSER_H +#define _GBTPARSER_H + +#include "Arduino.h" +#include "DataParser.h" + +#define GBT_TAG 0xE0 + +typedef struct GBTHeader { + uint8_t flag; + uint8_t control; + uint16_t sequence; + uint16_t sequenceAck; + uint8_t size; +} __attribute__((packed)) GBTHeader; + +class GBTParser { +public: + int8_t parse(uint8_t *buf, DataParserContext &ctx); + ~GBTParser(void); +private: + uint8_t lastSequenceNumber = 0; + uint16_t pos = 0; + uint8_t *buf = NULL; +}; + +#endif diff --git a/lib/lib_div/ams/GcmParser.cpp b/lib/lib_div/ams/GcmParser.cpp new file mode 100644 index 000000000..cbdf130fe --- /dev/null +++ b/lib/lib_div/ams/GcmParser.cpp @@ -0,0 +1,104 @@ + +#include "GcmParser.h" +#include "tasmota_options.h" + +#ifdef USE_TLS +#include "lwip/def.h" +#include + +GCMParser::GCMParser(uint8_t *encryption_key, uint8_t *authentication_key) { + memcpy(this->encryption_key, encryption_key, 16); + memcpy(this->authentication_key, authentication_key, 16); + use_auth = 0; + for (uint16_t cnt = 0; cnt < 16; cnt++) { + if (authentication_key[cnt]) { + use_auth |= 1; + } + } +} + +int8_t GCMParser::parse(uint8_t *d, DataParserContext &ctx) { + if(ctx.length < 12) return DATA_PARSE_INCOMPLETE; + + uint8_t* ptr = (uint8_t*) d; + if(*ptr != GCM_TAG) return DATA_PARSE_BOUNDRY_FLAG_MISSING; + ptr++; + // Encrypted APDU + // http://www.weigu.lu/tutorials/sensors2bus/04_encryption/index.html + + uint8_t systemTitleLength = *ptr; + ptr++; + + uint8_t initialization_vector[12]; + memcpy(ctx.system_title, ptr, systemTitleLength); + memcpy(initialization_vector, ctx.system_title, systemTitleLength); + + int len = 0; + int headersize = 2 + systemTitleLength; + ptr += systemTitleLength; + if(((*ptr) & 0xFF) == 0x81) { + ptr++; + len = *ptr; + // 1-byte payload length + ptr++; + headersize += 2; + } else if(((*ptr) & 0xFF) == 0x82) { + GCMSizeDef* h = (GCMSizeDef*) ptr; + + // 2-byte payload length + len = (ntohs(h->format) & 0xFFFF); + + ptr += 3; + headersize += 3; + } else if(((*ptr) & 0xFF) == 0x4f) { + // ???????? single frame did only decode with this compare + ptr++; + headersize++; + } + if(len + headersize > ctx.length) + return DATA_PARSE_INCOMPLETE; + + uint8_t additional_authenticated_data[17]; + memcpy(additional_authenticated_data, ptr, 1); + + // Security tag + uint8_t sec = *ptr; + ptr++; + headersize++; + + // Frame counter + memcpy(initialization_vector + 8, ptr, 4); + ptr += 4; + headersize += 4; + + int footersize = 0; + + // Authentication enabled + uint8_t authentication_tag[12]; + uint8_t authkeylen = 0, aadlen = 0; + if((sec & 0x10) == 0x10) { + authkeylen = 12; + aadlen = 17; + footersize += authkeylen; + memcpy(additional_authenticated_data + 1, authentication_key, 16); + memcpy(authentication_tag, ptr + len - footersize - 5, authkeylen); + } + + br_gcm_context gcm_ctx; + br_aes_small_ctr_keys ctr_ctx; + br_aes_small_ctr_init(&ctr_ctx, encryption_key, 16); + br_gcm_init(&gcm_ctx, &ctr_ctx.vtable, &br_ghash_ctmul32); + br_gcm_reset(&gcm_ctx, initialization_vector, 12); + if (use_auth && authkeylen > 0) { + br_gcm_aad_inject(&gcm_ctx, additional_authenticated_data, aadlen); + } + br_gcm_flip(&gcm_ctx); + br_gcm_run(&gcm_ctx, 0, ptr , ctx.length - headersize); + if (use_auth && authkeylen > 0 && br_gcm_check_tag_trunc(&gcm_ctx, authentication_tag, authkeylen) != 1) { + return GCM_AUTH_FAILED; + } + + ctx.length -= footersize + headersize; + return ptr - d; +} +#endif // USE_TLS diff --git a/lib/lib_div/ams/GcmParser.h b/lib/lib_div/ams/GcmParser.h new file mode 100644 index 000000000..71ec0fe95 --- /dev/null +++ b/lib/lib_div/ams/GcmParser.h @@ -0,0 +1,28 @@ +#ifndef _GCMPARSER_H +#define _GCMPARSER_H + +#include "Arduino.h" +#include "DataParser.h" + +#define GCM_TAG 0xDB +#define GCM_AUTH_FAILED -51 +#define GCM_DECRYPT_FAILED -52 +#define GCM_ENCRYPTION_KEY_FAILED -53 + +typedef struct GCMSizeDef { + uint8_t flag; + uint16_t format; +} __attribute__((packed)) GCMSizeDef; + + +class GCMParser { +public: + GCMParser(uint8_t *encryption_key, uint8_t *authentication_key); + int8_t parse(uint8_t *buf, DataParserContext &ctx); +private: + uint8_t encryption_key[16]; + uint8_t authentication_key[16]; + uint8_t use_auth = 0; +}; + +#endif diff --git a/lib/lib_div/ams/HdlcParser.cpp b/lib/lib_div/ams/HdlcParser.cpp new file mode 100644 index 000000000..9e6faad74 --- /dev/null +++ b/lib/lib_div/ams/HdlcParser.cpp @@ -0,0 +1,56 @@ +#include "HdlcParser.h" +#include "lwip/def.h" +#include "crc.h" + +int8_t HDLCParser::parse(uint8_t *d, DataParserContext &ctx) { + int len; + + uint8_t* ptr; + if(ctx.length < 3) + return DATA_PARSE_INCOMPLETE; + + HDLCHeader* h = (HDLCHeader*) d; + ptr = (uint8_t*) &h[1]; + + // Frame format type 3 + if((h->format & 0xF0) == 0xA0) { + // Length field (11 lsb of format) + len = (ntohs(h->format) & 0x7FF) + 2; + if(len > ctx.length) + return DATA_PARSE_INCOMPLETE; + + HDLCFooter* f = (HDLCFooter*) (d + len - sizeof *f); + + // First and last byte should be HDLC_FLAG + if(h->flag != HDLC_FLAG || f->flag != HDLC_FLAG) + return DATA_PARSE_BOUNDRY_FLAG_MISSING; + + // Verify FCS + if(ntohs(f->fcs) != AMS_crc16_x25(d + 1, len - sizeof *f - 1)) + return DATA_PARSE_FOOTER_CHECKSUM_ERROR; + + // Skip destination address, LSB marks last byte + while(((*ptr) & 0x01) == 0x00) { + ptr++; + } + ptr++; + + // Skip source address, LSB marks last byte + while(((*ptr) & 0x01) == 0x00) { + ptr++; + } + ptr++; + + HDLC3CtrlHcs* t3 = (HDLC3CtrlHcs*) (ptr); + + // Verify HCS + if(ntohs(t3->hcs) != AMS_crc16_x25(d + 1, ptr-d)) + return DATA_PARSE_HEADER_CHECKSUM_ERROR; + ptr += 3; + + // Exclude all of header and 3 byte footer + ctx.length -= ptr-d+3; + return ptr-d; + } + return DATA_PARSE_UNKNOWN_DATA; +} diff --git a/lib/lib_div/ams/HdlcParser.h b/lib/lib_div/ams/HdlcParser.h new file mode 100644 index 000000000..7091cfbda --- /dev/null +++ b/lib/lib_div/ams/HdlcParser.h @@ -0,0 +1,29 @@ +#ifndef _HDLCPARSER_H +#define _HDLCPARSER_H + +#include "Arduino.h" +#include "DataParser.h" + +#define HDLC_FLAG 0x7E + +typedef struct HDLCHeader { + uint8_t flag; + uint16_t format; +} __attribute__((packed)) HDLCHeader; + +typedef struct HDLCFooter { + uint16_t fcs; + uint8_t flag; +} __attribute__((packed)) HDLCFooter; + +typedef struct HDLC3CtrlHcs { + uint8_t control; + uint16_t hcs; +} __attribute__((packed)) HDLC3CtrlHcs; + +class HDLCParser { +public: + int8_t parse(uint8_t *buf, DataParserContext &ctx); +}; + +#endif diff --git a/lib/lib_div/ams/LlcParser.cpp b/lib/lib_div/ams/LlcParser.cpp new file mode 100644 index 000000000..c6d41a564 --- /dev/null +++ b/lib/lib_div/ams/LlcParser.cpp @@ -0,0 +1,6 @@ +#include "LlcParser.h" + +int8_t LLCParser::parse(uint8_t *buf, DataParserContext &ctx) { + ctx.length -= 3; + return 3; +} \ No newline at end of file diff --git a/lib/lib_div/ams/LlcParser.h b/lib/lib_div/ams/LlcParser.h new file mode 100644 index 000000000..3be931092 --- /dev/null +++ b/lib/lib_div/ams/LlcParser.h @@ -0,0 +1,18 @@ +#ifndef _LLCPARSER_H +#define _LLCPARSER_H + +#include "Arduino.h" +#include "DataParser.h" + +typedef struct LLCHeader { + uint8_t dst; + uint8_t src; + uint8_t control; +} __attribute__((packed)) LLCHeader; + +class LLCParser { +public: + int8_t parse(uint8_t *buf, DataParserContext &ctx); +}; + +#endif diff --git a/lib/lib_div/ams/MbusParser.cpp b/lib/lib_div/ams/MbusParser.cpp new file mode 100644 index 000000000..e9c93a5a9 --- /dev/null +++ b/lib/lib_div/ams/MbusParser.cpp @@ -0,0 +1,91 @@ +#include "MbusParser.h" + + +MBUSParser::~MBUSParser(void) { + if (buf) free(buf); +} +int8_t MBUSParser::parse(uint8_t *d, DataParserContext &ctx) { + int len; + int headersize = 3; + int footersize = 1; + + uint8_t* ptr; + + // https://m-bus.com/documentation-wired/06-application-layer + if(ctx.length < 4) + return DATA_PARSE_INCOMPLETE; + + MbusHeader* mh = (MbusHeader*) d; + if(mh->flag1 != MBUS_START || mh->flag2 != MBUS_START) + return DATA_PARSE_BOUNDRY_FLAG_MISSING; + + // First two bytes is 1-byte length value repeated. Only used for last segment + if(mh->len1 != mh->len2) + return MBUS_FRAME_LENGTH_NOT_EQUAL; + len = mh->len1; + ptr = (uint8_t*) &mh[1]; + headersize = 4; + footersize = 2; + + if(len == 0x00) + len = ctx.length - headersize - footersize; + // Payload can max be 255 bytes, so I think the following case is only valid for austrian meters + if(len < headersize) + len += 256; + + if((headersize + footersize + len) > ctx.length) + return DATA_PARSE_INCOMPLETE; + + MbusFooter* mf = (MbusFooter*) (d + len + headersize); + if(mf->flag != MBUS_END) + return DATA_PARSE_BOUNDRY_FLAG_MISSING; + if(checksum(d + headersize, len) != mf->fcs) + return DATA_PARSE_FOOTER_CHECKSUM_ERROR; + + ptr += 2; len -= 2; + + // Control information field + uint8_t ci = *ptr; + + // Skip CI, STSAP and DTSAP + ptr += 3; len -= 3; + + // Bits 7 6 5 4 3 2 1 0 + // 0 0 0 Finished Sequence number + uint8_t sequenceNumber = (ci & 0x0F); + if((ci & 0x10) == 0x00) { // Not finished yet + if(sequenceNumber == 0) { + if(buf == NULL) buf = (uint8_t *)malloc((size_t)1024); // TODO find out from first package ? + pos = 0; + } else if(buf == NULL || pos + len > 1024 || sequenceNumber != (lastSequenceNumber + 1)) { + return DATA_PARSE_FAIL; + } + memcpy(buf+pos, ptr, len); + pos += len; + lastSequenceNumber = sequenceNumber; + return DATA_PARSE_INTERMEDIATE_SEGMENT; + } else if(sequenceNumber > 0) { // This is the last frame of multiple, assembly needed + if(buf == NULL || pos + len > 1024 || sequenceNumber != (lastSequenceNumber + 1)) { + return DATA_PARSE_FAIL; + } + memcpy(buf+pos, ptr, len); + pos += len; + return DATA_PARSE_FINAL_SEGMENT; + } + return ptr-d; +} + +uint16_t MBUSParser::write(const uint8_t* d, DataParserContext &ctx) { + if(buf != NULL) { + memcpy((uint8_t *) d, buf, pos); + ctx.length = pos; + } + return 0; +} + +uint8_t MBUSParser::checksum(const uint8_t* p, int len) { + uint8_t ret = 0; + while(len--) + ret += *p++; + return ret; +} diff --git a/lib/lib_div/ams/MbusParser.h b/lib/lib_div/ams/MbusParser.h new file mode 100644 index 000000000..d0520aecc --- /dev/null +++ b/lib/lib_div/ams/MbusParser.h @@ -0,0 +1,35 @@ +#ifndef _MBUSPARSER_H +#define _MBUSPARSER_H + +#include "Arduino.h" +#include "DataParser.h" + +#define MBUS_START 0x68 +#define MBUS_END 0x16 +#define MBUS_FRAME_LENGTH_NOT_EQUAL -41 + +typedef struct MbusHeader { + uint8_t flag1; + uint8_t len1; + uint8_t len2; + uint8_t flag2; +} __attribute__((packed)) MbusHeader; + +typedef struct MbusFooter { + uint8_t fcs; + uint8_t flag; +} __attribute__((packed)) MbusFooter; + +class MBUSParser { +public: + int8_t parse(uint8_t *buf, DataParserContext &ctx); + ~MBUSParser(void); + uint16_t write(const uint8_t* d, DataParserContext &ctx); +private: + uint8_t lastSequenceNumber = 0; + uint16_t pos = 0; + uint8_t *buf = NULL; + uint8_t checksum(const uint8_t* p, int len); +}; + +#endif diff --git a/lib/lib_div/ams/Time.cpp b/lib/lib_div/ams/Time.cpp new file mode 100644 index 000000000..0dcb29f7e --- /dev/null +++ b/lib/lib_div/ams/Time.cpp @@ -0,0 +1,321 @@ +/* + time.c - low level time and date functions + Copyright (c) Michael Margolis 2009-2014 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + 1.0 6 Jan 2010 - initial release + 1.1 12 Feb 2010 - fixed leap year calculation error + 1.2 1 Nov 2010 - fixed setTime bug (thanks to Korman for this) + 1.3 24 Mar 2012 - many edits by Paul Stoffregen: fixed timeStatus() to update + status, updated examples for Arduino 1.0, fixed ARM + compatibility issues, added TimeArduinoDue and TimeTeensy3 + examples, add error checking and messages to RTC examples, + add examples to DS1307RTC library. + 1.4 5 Sep 2014 - compatibility with Arduino 1.5.7 +*/ + +#if ARDUINO >= 100 +#include +#else +#include +#endif + +#include "TimeLib.h" + +static tmElements_t tm; // a cache of time elements +static time_t cacheTime; // the time the cache was updated +static uint32_t syncInterval = 300; // time sync will be attempted after this many seconds + +void refreshCache(time_t t) { + if (t != cacheTime) { + breakTime(t, tm); + cacheTime = t; + } +} + +int hour() { // the hour now + return hour(now()); +} + +int hour(time_t t) { // the hour for the given time + refreshCache(t); + return tm.Hour; +} + +int hourFormat12() { // the hour now in 12 hour format + return hourFormat12(now()); +} + +int hourFormat12(time_t t) { // the hour for the given time in 12 hour format + refreshCache(t); + if( tm.Hour == 0 ) + return 12; // 12 midnight + else if( tm.Hour > 12) + return tm.Hour - 12 ; + else + return tm.Hour ; +} + +uint8_t isAM() { // returns true if time now is AM + return !isPM(now()); +} + +uint8_t isAM(time_t t) { // returns true if given time is AM + return !isPM(t); +} + +uint8_t isPM() { // returns true if PM + return isPM(now()); +} + +uint8_t isPM(time_t t) { // returns true if PM + return (hour(t) >= 12); +} + +int minute() { + return minute(now()); +} + +int minute(time_t t) { // the minute for the given time + refreshCache(t); + return tm.Minute; +} + +int second() { + return second(now()); +} + +int second(time_t t) { // the second for the given time + refreshCache(t); + return tm.Second; +} + +int day(){ + return(day(now())); +} + +int day(time_t t) { // the day for the given time (0-6) + refreshCache(t); + return tm.Day; +} + +int weekday() { // Sunday is day 1 + return weekday(now()); +} + +int weekday(time_t t) { + refreshCache(t); + return tm.Wday; +} + +int month(){ + return month(now()); +} + +int month(time_t t) { // the month for the given time + refreshCache(t); + return tm.Month; +} + +int year() { // as in Processing, the full four digit year: (2009, 2010 etc) + return year(now()); +} + +int year(time_t t) { // the year for the given time + refreshCache(t); + return tmYearToCalendar(tm.Year); +} + +/*============================================================================*/ +/* functions to convert to and from system time */ +/* These are for interfacing with time services and are not normally needed in a sketch */ + +// leap year calculator expects year argument as years offset from 1970 +#define LEAP_YEAR(Y) ( ((1970+(Y))>0) && !((1970+(Y))%4) && ( ((1970+(Y))%100) || !((1970+(Y))%400) ) ) + +static const uint8_t monthDays[]={31,28,31,30,31,30,31,31,30,31,30,31}; // API starts months from 1, this array starts from 0 + +void breakTime(time_t timeInput, tmElements_t &tm){ +// break the given time_t into time components +// this is a more compact version of the C library localtime function +// note that year is offset from 1970 !!! + + uint8_t year; + uint8_t month, monthLength; + uint32_t time; + unsigned long days; + + time = (uint32_t)timeInput; + tm.Second = time % 60; + time /= 60; // now it is minutes + tm.Minute = time % 60; + time /= 60; // now it is hours + tm.Hour = time % 24; + time /= 24; // now it is days + tm.Wday = ((time + 4) % 7) + 1; // Sunday is day 1 + + year = 0; + days = 0; + while((unsigned)(days += (LEAP_YEAR(year) ? 366 : 365)) <= time) { + year++; + } + tm.Year = year; // year is offset from 1970 + + days -= LEAP_YEAR(year) ? 366 : 365; + time -= days; // now it is days in this year, starting at 0 + + days=0; + month=0; + monthLength=0; + for (month=0; month<12; month++) { + if (month==1) { // february + if (LEAP_YEAR(year)) { + monthLength=29; + } else { + monthLength=28; + } + } else { + monthLength = monthDays[month]; + } + + if (time >= monthLength) { + time -= monthLength; + } else { + break; + } + } + tm.Month = month + 1; // jan is month 1 + tm.Day = time + 1; // day of month +} + +time_t makeTime(const tmElements_t &tm){ +// assemble time elements into time_t +// note year argument is offset from 1970 (see macros in time.h to convert to other formats) +// previous version used full four digit year (or digits since 2000),i.e. 2009 was 2009 or 9 + + int i; + uint32_t seconds; + + // seconds from 1970 till 1 jan 00:00:00 of the given year + seconds= tm.Year*(SECS_PER_DAY * 365); + for (i = 0; i < tm.Year; i++) { + if (LEAP_YEAR(i)) { + seconds += SECS_PER_DAY; // add extra days for leap years + } + } + + // add days for this year, months start from 1 + for (i = 1; i < tm.Month; i++) { + if ( (i == 2) && LEAP_YEAR(tm.Year)) { + seconds += SECS_PER_DAY * 29; + } else { + seconds += SECS_PER_DAY * monthDays[i-1]; //monthDay array starts from 0 + } + } + seconds+= (tm.Day-1) * SECS_PER_DAY; + seconds+= tm.Hour * SECS_PER_HOUR; + seconds+= tm.Minute * SECS_PER_MIN; + seconds+= tm.Second; + return (time_t)seconds; +} +/*=====================================================*/ +/* Low level system time functions */ + +static uint32_t sysTime = 0; +static uint32_t prevMillis = 0; +static uint32_t nextSyncTime = 0; +static timeStatus_t Status = timeNotSet; + +getExternalTime getTimePtr; // pointer to external sync function +//setExternalTime setTimePtr; // not used in this version + +#ifdef TIME_DRIFT_INFO // define this to get drift data +time_t sysUnsyncedTime = 0; // the time sysTime unadjusted by sync +#endif + + +time_t now() { + // calculate number of seconds passed since last call to now() + while (millis() - prevMillis >= 1000) { + // millis() and prevMillis are both unsigned ints thus the subtraction will always be the absolute value of the difference + sysTime++; + prevMillis += 1000; +#ifdef TIME_DRIFT_INFO + sysUnsyncedTime++; // this can be compared to the synced time to measure long term drift +#endif + } + if (nextSyncTime <= sysTime) { + if (getTimePtr != 0) { + time_t t = getTimePtr(); + if (t != 0) { + setTime(t); + } else { + nextSyncTime = sysTime + syncInterval; + Status = (Status == timeNotSet) ? timeNotSet : timeNeedsSync; + } + } + } + return (time_t)sysTime; +} + +void setTime(time_t t) { +#ifdef TIME_DRIFT_INFO + if(sysUnsyncedTime == 0) + sysUnsyncedTime = t; // store the time of the first call to set a valid Time +#endif + + sysTime = (uint32_t)t; + nextSyncTime = (uint32_t)t + syncInterval; + Status = timeSet; + prevMillis = millis(); // restart counting from now (thanks to Korman for this fix) +} + +void setTime(int hr,int min,int sec,int dy, int mnth, int yr){ + // year can be given as full four digit year or two digts (2010 or 10 for 2010); + //it is converted to years since 1970 + if( yr > 99) + yr = yr - 1970; + else + yr += 30; + tm.Year = yr; + tm.Month = mnth; + tm.Day = dy; + tm.Hour = hr; + tm.Minute = min; + tm.Second = sec; + setTime(makeTime(tm)); +} + +void adjustTime(long adjustment) { + sysTime += adjustment; +} + +// indicates if time has been set and recently synchronized +timeStatus_t timeStatus() { + now(); // required to actually update the status + return Status; +} + +void setSyncProvider( getExternalTime getTimeFunction){ + getTimePtr = getTimeFunction; + nextSyncTime = sysTime; + now(); // this will sync the clock +} + +void setSyncInterval(time_t interval){ // set the number of seconds between re-sync + syncInterval = (uint32_t)interval; + nextSyncTime = sysTime + syncInterval; +} diff --git a/lib/lib_div/ams/TimeLib.h b/lib/lib_div/ams/TimeLib.h new file mode 100644 index 000000000..b587046e3 --- /dev/null +++ b/lib/lib_div/ams/TimeLib.h @@ -0,0 +1,144 @@ +/* + time.h - low level time and date functions +*/ + +/* + July 3 2011 - fixed elapsedSecsThisWeek macro (thanks Vincent Valdy for this) + - fixed daysToTime_t macro (thanks maniacbug) +*/ + +#ifndef _Time_h +#ifdef __cplusplus +#define _Time_h + +#include +#ifndef __AVR__ +#include // for __time_t_defined, but avr libc lacks sys/types.h +#endif + + +#if !defined(__time_t_defined) // avoid conflict with newlib or other posix libc +typedef unsigned long time_t; +#endif + + +// This ugly hack allows us to define C++ overloaded functions, when included +// from within an extern "C", as newlib's sys/stat.h does. Actually it is +// intended to include "time.h" from the C library (on ARM, but AVR does not +// have that file at all). On Mac and Windows, the compiler will find this +// "Time.h" instead of the C library "time.h", so we may cause other weird +// and unpredictable effects by conflicting with the C library header "time.h", +// but at least this hack lets us define C++ functions as intended. Hopefully +// nothing too terrible will result from overriding the C library header?! +extern "C++" { +typedef enum {timeNotSet, timeNeedsSync, timeSet +} timeStatus_t ; + +typedef enum { + dowInvalid, dowSunday, dowMonday, dowTuesday, dowWednesday, dowThursday, dowFriday, dowSaturday +} timeDayOfWeek_t; + +typedef enum { + tmSecond, tmMinute, tmHour, tmWday, tmDay,tmMonth, tmYear, tmNbrFields +} tmByteFields; + +typedef struct { + uint8_t Second; + uint8_t Minute; + uint8_t Hour; + uint8_t Wday; // day of week, sunday is day 1 + uint8_t Day; + uint8_t Month; + uint8_t Year; // offset from 1970; +} tmElements_t, TimeElements, *tmElementsPtr_t; + +//convenience macros to convert to and from tm years +#define tmYearToCalendar(Y) ((Y) + 1970) // full four digit year +#define CalendarYrToTm(Y) ((Y) - 1970) +#define tmYearToY2k(Y) ((Y) - 30) // offset is from 2000 +#define y2kYearToTm(Y) ((Y) + 30) + +typedef time_t(*getExternalTime)(); +//typedef void (*setExternalTime)(const time_t); // not used in this version + + +/*==============================================================================*/ +/* Useful Constants */ +#define SECS_PER_MIN ((time_t)(60UL)) +#define SECS_PER_HOUR ((time_t)(3600UL)) +#define SECS_PER_DAY ((time_t)(SECS_PER_HOUR * 24UL)) +#define DAYS_PER_WEEK ((time_t)(7UL)) +#define SECS_PER_WEEK ((time_t)(SECS_PER_DAY * DAYS_PER_WEEK)) +#define SECS_PER_YEAR ((time_t)(SECS_PER_DAY * 365UL)) // TODO: ought to handle leap years +#define SECS_YR_2000 ((time_t)(946684800UL)) // the time at the start of y2k + +/* Useful Macros for getting elapsed time */ +#define numberOfSeconds(_time_) ((_time_) % SECS_PER_MIN) +#define numberOfMinutes(_time_) (((_time_) / SECS_PER_MIN) % SECS_PER_MIN) +#define numberOfHours(_time_) (((_time_) % SECS_PER_DAY) / SECS_PER_HOUR) +#define dayOfWeek(_time_) ((((_time_) / SECS_PER_DAY + 4) % DAYS_PER_WEEK)+1) // 1 = Sunday +#define elapsedDays(_time_) ((_time_) / SECS_PER_DAY) // this is number of days since Jan 1 1970 +#define elapsedSecsToday(_time_) ((_time_) % SECS_PER_DAY) // the number of seconds since last midnight +// The following macros are used in calculating alarms and assume the clock is set to a date later than Jan 1 1971 +// Always set the correct time before setting alarms +#define previousMidnight(_time_) (((_time_) / SECS_PER_DAY) * SECS_PER_DAY) // time at the start of the given day +#define nextMidnight(_time_) (previousMidnight(_time_) + SECS_PER_DAY) // time at the end of the given day +#define elapsedSecsThisWeek(_time_) (elapsedSecsToday(_time_) + ((dayOfWeek(_time_)-1) * SECS_PER_DAY)) // note that week starts on day 1 +#define previousSunday(_time_) ((_time_) - elapsedSecsThisWeek(_time_)) // time at the start of the week for the given time +#define nextSunday(_time_) (previousSunday(_time_)+SECS_PER_WEEK) // time at the end of the week for the given time + + +/* Useful Macros for converting elapsed time to a time_t */ +#define minutesToTime_t ((M)) ( (M) * SECS_PER_MIN) +#define hoursToTime_t ((H)) ( (H) * SECS_PER_HOUR) +#define daysToTime_t ((D)) ( (D) * SECS_PER_DAY) // fixed on Jul 22 2011 +#define weeksToTime_t ((W)) ( (W) * SECS_PER_WEEK) + +/*============================================================================*/ +/* time and date functions */ +int hour(); // the hour now +int hour(time_t t); // the hour for the given time +int hourFormat12(); // the hour now in 12 hour format +int hourFormat12(time_t t); // the hour for the given time in 12 hour format +uint8_t isAM(); // returns true if time now is AM +uint8_t isAM(time_t t); // returns true the given time is AM +uint8_t isPM(); // returns true if time now is PM +uint8_t isPM(time_t t); // returns true the given time is PM +int minute(); // the minute now +int minute(time_t t); // the minute for the given time +int second(); // the second now +int second(time_t t); // the second for the given time +int day(); // the day now +int day(time_t t); // the day for the given time +int weekday(); // the weekday now (Sunday is day 1) +int weekday(time_t t); // the weekday for the given time +int month(); // the month now (Jan is month 1) +int month(time_t t); // the month for the given time +int year(); // the full four digit year: (2009, 2010 etc) +int year(time_t t); // the year for the given time + +time_t now(); // return the current time as seconds since Jan 1 1970 +void setTime(time_t t); +void setTime(int hr,int min,int sec,int day, int month, int yr); +void adjustTime(long adjustment); + +/* date strings */ +#define dt_MAX_STRING_LEN 9 // length of longest date string (excluding terminating null) +char* monthStr(uint8_t month); +char* dayStr(uint8_t day); +char* monthShortStr(uint8_t month); +char* dayShortStr(uint8_t day); + +/* time sync functions */ +timeStatus_t timeStatus(); // indicates if time has been set and recently synchronized +void setSyncProvider( getExternalTime getTimeFunction); // identify the external time provider +void setSyncInterval(time_t interval); // set the number of seconds between re-sync + +/* low level functions to convert to and from system time */ +void breakTime(time_t time, tmElements_t &tm); // break time_t into elements +time_t makeTime(const tmElements_t &tm); // convert time elements into time_t + +} // extern "C++" +#endif // __cplusplus +#endif /* _Time_h */ + diff --git a/lib/lib_div/ams/crc.cpp b/lib/lib_div/ams/crc.cpp new file mode 100644 index 000000000..33ab5a4ff --- /dev/null +++ b/lib/lib_div/ams/crc.cpp @@ -0,0 +1,29 @@ +#include "crc.h" + +uint16_t AMS_crc16_x25(const uint8_t* p, int len) +{ + uint16_t crc = UINT16_MAX; + + while(len--) + for (uint16_t i = 0, d = 0xff & *p++; i < 8; i++, d >>= 1) + crc = ((crc & 1) ^ (d & 1)) ? (crc >> 1) ^ 0x8408 : (crc >> 1); + + return (~crc << 8) | (~crc >> 8 & 0xff); +} + +uint16_t AMS_crc16 (const uint8_t *p, int len) { + uint16_t crc = 0; + + while (len--) { + int i; + crc ^= *p++; + for (i = 0 ; i < 8 ; ++i) { + if (crc & 1) + crc = (crc >> 1) ^ 0xa001; + else + crc = (crc >> 1); + } + } + + return crc; +} diff --git a/lib/lib_div/ams/crc.h b/lib/lib_div/ams/crc.h new file mode 100644 index 000000000..d90a75ad2 --- /dev/null +++ b/lib/lib_div/ams/crc.h @@ -0,0 +1,10 @@ +#ifndef _CRC_H +#define _CRC_H + +#include "Arduino.h" +#include + +uint16_t AMS_crc16(const uint8_t* p, int len); +uint16_t AMS_crc16_x25(const uint8_t* p, int len); + +#endif diff --git a/lib/lib_div/ams/han_Parser.cpp b/lib/lib_div/ams/han_Parser.cpp new file mode 100644 index 000000000..97bd2449c --- /dev/null +++ b/lib/lib_div/ams/han_Parser.cpp @@ -0,0 +1,273 @@ +#include "han_Parser.h" +#include "Cosem.h" + + +extern int SML_print(const char *, ...); +#define han_debug SML_print + + +Han_Parser::Han_Parser(uint16_t (dp)(uint8_t, uint8_t), uint8_t m, uint8_t *key, uint8_t *auth) { + dispatch = dp; + meter = m; + memmove(encryptionKey, key, 16); + if (auth) { + memmove(authenticationKey, auth, 16); + } else { + memset(authenticationKey, 0, 16); + } +} + +Han_Parser::~Han_Parser(void) { + if (hdlcParser) delete hdlcParser; + if (mbusParser) delete mbusParser; + if (gbtParser) delete gbtParser; + if (gcmParser) delete gcmParser; + if (llcParser) delete llcParser; + if (dlmsParser) delete dlmsParser; + if (dsmrParser) delete dsmrParser; +} + +int Han_Parser::serial_available(void) { + return dispatch(meter, 0); +} +int Han_Parser::serial_read(void) { + return dispatch(meter, 1); +} + +int16_t Han_Parser::serial_readBytes(uint8_t *buf, uint16_t size) { + if (size > serial_available()) { + size = serial_available(); + } + for (uint16_t cnt = 0; cnt < size; cnt++) { + buf[cnt] = serial_read(); + } + return size; +} + +bool Han_Parser::readHanPort(uint8_t **out, uint16_t *size) { + + if (!serial_available()) return false; + + // Before reading, empty serial buffer to increase chance of getting first byte of a data transfer + if (!serialInit) { + serial_readBytes(hanBuffer, BUF_SIZE_HAN); + serialInit = true; + return false; + } + + DataParserContext ctx = {0}; + int pos = DATA_PARSE_INCOMPLETE; + // For each byte received, check if we have a complete frame we can handle + while (serial_available() && pos == DATA_PARSE_INCOMPLETE) { + yield(); + // If buffer was overflowed, reset + if (len >= BUF_SIZE_HAN) { + serial_readBytes(hanBuffer, BUF_SIZE_HAN); + len = 0; + han_debug(PSTR("Buffer overflow, resetting")); + return false; + } + hanBuffer[len++] = serial_read(); + ctx.length = len; + pos = unwrapData((uint8_t *) hanBuffer, ctx); + if(ctx.type > 0 && pos >= 0) { + if(ctx.type == DATA_TAG_DLMS) { + han_debug(PSTR("Received valid DLMS at %d"), pos); + } else if(ctx.type == DATA_TAG_DSMR) { + han_debug(PSTR("Received valid DSMR at %d"), pos); + } else { + // TODO: Move this so that payload is sent to MQTT + han_debug(PSTR("Unknown tag %02X at pos %d"), ctx.type, pos); + len = 0; + return false; + } + } + } + if (pos == DATA_PARSE_INCOMPLETE) { + return false; + } else if(pos == DATA_PARSE_UNKNOWN_DATA) { + han_debug(PSTR("Unknown data payload:")); + len = len + serial_readBytes(hanBuffer + len, BUF_SIZE_HAN - len); + //debugPrint(hanBuffer, 0, len); + len = 0; + return false; + } + + if (pos == DATA_PARSE_INTERMEDIATE_SEGMENT) { + len = 0; + return false; + } else if (pos < 0) { + printHanReadError(pos); + len += serial_readBytes(hanBuffer + len, BUF_SIZE_HAN - len); + while (serial_available()) serial_read(); // Make sure it is all empty, in case we overflowed buffer above + len = 0; + return false; + } + + // Data is valid, clear the rest of the buffer to avoid tainted parsing + for (int i = pos + ctx.length; i < BUF_SIZE_HAN; i++) { + hanBuffer[i] = 0x00; + } + + //AmsData data; + char* payload = ((char *) (hanBuffer)) + pos; + if (ctx.type == DATA_TAG_DLMS) { + han_debug(PSTR("Using application data:")); + + //if (Debug.isActive(RemoteDebug::VERBOSE)) debugPrint((byte*) payload, 0, ctx.length); + + // Rudimentary detector for L&G proprietary format + if (payload[0] == CosemTypeStructure && payload[2] == CosemTypeArray && payload[1] == payload[3]) { + //data = LNG(payload, meterState.getMeterType(), &meterConfig, ctx, &Debug); + } else { + // TODO: Split IEC6205675 into DataParserKaifa and DataParserObis. This way we can add other means of parsing, for those other proprietary formats + //data = IEC6205675(payload, meterState.getMeterType(), &meterConfig, ctx); + } + } else if(ctx.type == DATA_TAG_DSMR) { + //data = IEC6205621(payload); + } + + *out = hanBuffer + pos; + *size = ctx.length; + len = 0; + return true; +} + + +int16_t Han_Parser::unwrapData(uint8_t *buf, DataParserContext &context) { + int16_t ret = 0; + bool doRet = false; + uint16_t end = BUF_SIZE_HAN; + uint8_t tag = (*buf); + uint8_t lastTag = DATA_TAG_NONE; + while (tag != DATA_TAG_NONE) { + int16_t curLen = context.length; + int8_t res = 0; + switch(tag) { + case DATA_TAG_HDLC: + if (hdlcParser == NULL) hdlcParser = new HDLCParser(); + res = hdlcParser->parse(buf, context); + break; + case DATA_TAG_MBUS: + if (mbusParser == NULL) mbusParser = new MBUSParser(); + res = mbusParser->parse(buf, context); + break; + case DATA_TAG_GBT: + if (gbtParser == NULL) gbtParser = new GBTParser(); + res = gbtParser->parse(buf, context); + break; + case DATA_TAG_GCM: + if (gcmParser == NULL) gcmParser = new GCMParser(encryptionKey, authenticationKey); + res = gcmParser->parse(buf, context); + break; + case DATA_TAG_LLC: + if (llcParser == NULL) llcParser = new LLCParser(); + res = llcParser->parse(buf, context); + break; + case DATA_TAG_DLMS: + if (dlmsParser == NULL) dlmsParser = new DLMSParser(); + res = dlmsParser->parse(buf, context); + if (res >= 0) doRet = true; + break; + case DATA_TAG_DSMR: + if (dsmrParser == NULL) dsmrParser = new DSMRParser(); + res = dsmrParser->parse(buf, context, lastTag != DATA_TAG_NONE); + if (res >= 0) doRet = true; + break; + default: + han_debug(PSTR("Ended up in default case while unwrapping...(tag %02X)"), tag); + return DATA_PARSE_UNKNOWN_DATA; + } + lastTag = tag; + if (res == DATA_PARSE_INCOMPLETE) { + return res; + } + if (context.length > end) return false; + if (Debug) { + switch(tag) { + case DATA_TAG_HDLC: + han_debug(PSTR("HDLC frame:")); + break; + case DATA_TAG_MBUS: + han_debug(PSTR("MBUS frame:")); + break; + case DATA_TAG_GBT: + han_debug(PSTR("GBT frame:")); + break; + case DATA_TAG_GCM: + han_debug(PSTR("GCM frame:")); + break; + case DATA_TAG_LLC: + han_debug(PSTR("LLC frame:")); + break; + case DATA_TAG_DLMS: + han_debug(PSTR("DLMS frame:")); + break; + case DATA_TAG_DSMR: + han_debug(PSTR("DSMR frame:")); + break; + } + } + if (res == DATA_PARSE_FINAL_SEGMENT) { + if (tag == DATA_TAG_MBUS) { + res = mbusParser->write(buf, context); + } + } + + if (res < 0) { + return res; + } + buf += res; + end -= res; + ret += res; + + // If we are ready to return, do that + if (doRet) { + context.type = tag; + return ret; + } + + // Use start byte of new buffer position as tag for next round in loop + tag = (*buf); + } + han_debug(PSTR("Got to end of unwrap method...")); + return DATA_PARSE_UNKNOWN_DATA; +} + +void Han_Parser::printHanReadError(int16_t pos) { + switch(pos) { + case DATA_PARSE_BOUNDRY_FLAG_MISSING: + han_debug(PSTR("Boundry flag missing")); + break; + case DATA_PARSE_HEADER_CHECKSUM_ERROR: + han_debug(PSTR("Header checksum error")); + break; + case DATA_PARSE_FOOTER_CHECKSUM_ERROR: + han_debug(PSTR("Frame checksum error")); + break; + case DATA_PARSE_INCOMPLETE: + han_debug(PSTR("Received frame is incomplete")); + break; + case GCM_AUTH_FAILED: + han_debug(PSTR("Decrypt authentication failed")); + break; + case GCM_ENCRYPTION_KEY_FAILED: + han_debug(PSTR("Setting decryption key failed")); + break; + case GCM_DECRYPT_FAILED: + han_debug(PSTR("Decryption failed")); + break; + case MBUS_FRAME_LENGTH_NOT_EQUAL: + han_debug(PSTR("Frame length mismatch")); + break; + case DATA_PARSE_INTERMEDIATE_SEGMENT: + han_debug(PSTR("Intermediate segment received")); + break; + case DATA_PARSE_UNKNOWN_DATA: + han_debug(PSTR("Unknown data format %02X"), hanBuffer[0]); + break; + default: + han_debug(PSTR("Unspecified error while reading data: %d"), pos); + break; + } +} diff --git a/lib/lib_div/ams/han_Parser.h b/lib/lib_div/ams/han_Parser.h new file mode 100644 index 000000000..1847865dd --- /dev/null +++ b/lib/lib_div/ams/han_Parser.h @@ -0,0 +1,47 @@ + +#ifndef _HAN_PARSER_H +#define _HAN_PARSER_H +#if defined __cplusplus +#include "Arduino.h" +#include "DataParsers.h" +#include "DataParser.h" +#include "Cosem.h" +#include "ntohll.h" + +#define BUF_SIZE_HAN (1280) + +int16_t serial_available(void); +uint8_t serial_read(void); + +class Han_Parser +{ +public: + Han_Parser(uint16_t (*)(uint8_t, uint8_t), uint8_t, uint8_t *, uint8_t *); + ~Han_Parser(void); + bool readHanPort(uint8_t **out, uint16_t *size); + int16_t unwrapData(uint8_t *buf, DataParserContext &context); + void printHanReadError(int16_t pos); + uint8_t encryptionKey[16]; + uint8_t authenticationKey[16]; + uint8_t hanBuffer[BUF_SIZE_HAN]; + int len = 0; +private: + uint16_t (*dispatch)(uint8_t, uint8_t); + int serial_available(void); + int serial_read(void); + int16_t serial_readBytes(uint8_t *, uint16_t); + HDLCParser *hdlcParser = NULL; + MBUSParser *mbusParser = NULL; + GBTParser *gbtParser = NULL; + GCMParser *gcmParser = NULL; + LLCParser *llcParser = NULL; + DLMSParser *dlmsParser = NULL; + DSMRParser *dsmrParser = NULL; + uint8_t encryption_key[16]; + uint8_t authentication_key[16]; + uint8_t meter; + bool serialInit = true; + bool Debug = true; +}; +#endif +#endif diff --git a/lib/lib_div/ams/hexutils.cpp b/lib/lib_div/ams/hexutils.cpp new file mode 100644 index 000000000..98d9ac717 --- /dev/null +++ b/lib/lib_div/ams/hexutils.cpp @@ -0,0 +1,23 @@ +#include "hexutils.h" + +String AMS_toHex(uint8_t* in) { + return AMS_toHex(in, sizeof(in)*2); +} + +String AMS_toHex(uint8_t* in, uint16_t size) { + String hex; + for(int i = 0; i < size; i++) { + if(in[i] < 0x10) { + hex += '0'; + } + hex += String(in[i], HEX); + } + hex.toUpperCase(); + return hex; +} + +void AMS_fromHex(uint8_t *out, String in, uint16_t size) { + for(int i = 0; i < size*2; i += 2) { + out[i/2] = strtol(in.substring(i, i+2).c_str(), 0, 16); + } +} diff --git a/lib/lib_div/ams/hexutils.h b/lib/lib_div/ams/hexutils.h new file mode 100644 index 000000000..47f2117af --- /dev/null +++ b/lib/lib_div/ams/hexutils.h @@ -0,0 +1,11 @@ +#ifndef _HEXUTILS_H +#define _HEXUTILS_H + +#include +#include "Arduino.h" + +String AMS_toHex(uint8_t* in); +String AMS_toHex(uint8_t* in, uint16_t size); +void AMS_fromHex(uint8_t *out, String in, uint16_t size); + +#endif diff --git a/lib/lib_div/ams/library.json b/lib/lib_div/ams/library.json new file mode 100644 index 000000000..5c19a8062 --- /dev/null +++ b/lib/lib_div/ams/library.json @@ -0,0 +1,17 @@ +{ + "name": "ams", + "version": "1.0", + "description": "ESP8266 ESP32 library for Advanced utility meters", + "license": "GPL", + "homepage": "https://github.com/arendst/Tasmota", + "frameworks": "*", + "platforms": "*", + "authors": + { + "name": "Gerhard Mutz", + "maintainer": true + }, + "build": { + "flags": [ "-I$PROJECT_DIR/include" ] + } +} diff --git a/lib/lib_div/ams/library.properties b/lib/lib_div/ams/library.properties new file mode 100755 index 000000000..472c784f0 --- /dev/null +++ b/lib/lib_div/ams/library.properties @@ -0,0 +1,17 @@ +name=AMS Parser + +version=1.2.0 + +author=Gunnar Skjold + +maintainer=https://github.com/gskjold + +sentence=Meter parsing Library for Espressif ESP32 and ESP8266 devices. + +paragraph=This library allows the ESP32 and ESP8266 devices to parse several meter protocolls + +category=Communication + +url=https://github.com/UtilitechAS/amsreader-firmware + +architectures=esp32,esp8266 diff --git a/lib/lib_div/ams/ntohll.cpp b/lib/lib_div/ams/ntohll.cpp new file mode 100644 index 000000000..25732434d --- /dev/null +++ b/lib/lib_div/ams/ntohll.cpp @@ -0,0 +1,5 @@ +#include "ntohll.h" + +uint64_t ntohll(uint64_t x) { + return (((uint64_t)ntohl((uint32_t)x)) << 32) + ntohl(x >> 32); +} \ No newline at end of file diff --git a/lib/lib_div/ams/ntohll.h b/lib/lib_div/ams/ntohll.h new file mode 100644 index 000000000..2bb1e5e09 --- /dev/null +++ b/lib/lib_div/ams/ntohll.h @@ -0,0 +1,8 @@ +#ifndef _NTOHLL_H +#define _NTOHLL_H + +#include "lwip/def.h" + +uint64_t ntohll(uint64_t x); + +#endif diff --git a/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino b/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino index 6de4e6719..f9faa90fb 100755 --- a/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino @@ -2932,7 +2932,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); } #ifdef USE_ENERGY_SENSOR if (!strncmp(lp, "enrg[", 5)) { - lp=GetNumericArgument(lp + 5, OPER_EQU, &fvar, gv); + lp = GetNumericArgument(lp + 5, OPER_EQU, &fvar, gv); while (*lp == ' ') lp++; switch ((uint32_t)fvar) { case 0: @@ -4478,7 +4478,9 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); } #endif //USE_ANGLE_FUNC + #if defined(USE_SML_M) && defined (USE_SML_SCRIPT_CMD) +uint32_t sml_status(uint32_t meter); extern char *SML_GetSVal(uint32_t index); if (!strncmp(lp, "sml[", 4)) { @@ -4547,13 +4549,7 @@ extern char *SML_GetSVal(uint32_t index); fvar = -99; } } else { - - -#if defined(ED300L) || defined(AS2020) - fvar = SML_Status(fvar1); -#else - fvar = 0; -#endif //ED300L + fvar = sml_status(fvar1); } goto nfuncexit; } diff --git a/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino b/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino index 3dbfe9e38..698fc02ca 100755 --- a/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino @@ -35,6 +35,7 @@ #include + // use special no wait serial driver, should be always on #ifndef ESP32 #define SPECIAL_SS @@ -50,6 +51,9 @@ USE_ESP32_SW_SERIAL default off, uses a special combo driver that allows more then 3 serial ports on ESP32. define rec pins as negativ to use software serial + + USE_SML_AUTHKEY + rarely used , thus off by default */ // if you have to save more RAM you may disable these options by defines in user_config_override @@ -87,6 +91,11 @@ #define USE_SML_MEDIAN_FILTER #endif + +#ifdef USE_SML_DECRYPT +#include "han_Parser.h" +#endif + /* special options per meter 1: special binary SML option for meters that use a bit in the status register to sign import or export like ED300L, AS2020 or DTZ541 @@ -107,13 +116,22 @@ e.g. 1,=so2,2 set obis line mode on meter 1 3: serial buffers a. serial buffer size -b. serial irq buffer size +b. serial irq buffer size, a must be given +c. dumplog buffer size, default is 128 , a and b must be given e.g. 1,=so3,256,256 set serial buffers on meter 1 4: decrytion key, 16 bytes hex btw 32 chars without spaces or commas defining key switches decryption mode on +5: +authentication key, 16 bytes hex btw 32 chars without spaces or commas +needs USE_SML_AUTHKEY + +6: +synchronisation timout in milliseconds, after no serial data within this +time serial pointer is reset to zero + */ //#define MODBUS_DEBUG @@ -131,9 +149,9 @@ public: virtual ~SML_ESP32_SERIAL(); bool begin(uint32_t speed, uint32_t smode, int32_t recpin, int32_t trxpin); int32_t peek(void); - int32_t read(void) override; + int read(void) override; size_t write(uint8_t byte) override; - int32_t available(void) override; + int available(void) override; void flush(void) override; void setRxBufferSize(uint32_t size); void updateBaudRate(uint32_t baud); @@ -232,7 +250,7 @@ int32_t SML_ESP32_SERIAL::peek(void) { } } -int32_t SML_ESP32_SERIAL::read(void) { +int SML_ESP32_SERIAL::read(void) { if (hws) { return hws->read(); } else { @@ -243,7 +261,7 @@ int32_t SML_ESP32_SERIAL::read(void) { } } -int32_t SML_ESP32_SERIAL::available(void) { +int SML_ESP32_SERIAL::available(void) { if (hws) { return hws->available(); } else { @@ -350,6 +368,10 @@ typedef union { #define TMSBSIZ 256 #endif +#ifndef SML_STIMEOUT +#define SML_STIMEOUT 1000 +#endif + #define SO_DWS74_BUG 1 #define SO_OBIS_LINE 2 @@ -376,6 +398,8 @@ struct METER_DESC { uint8_t *sbuff; uint16_t spos; uint16_t sibsiz; + uint32_t lastms; + uint16_t tout_ms; uint8_t so_flags; char meter_id[METER_ID_SIZE]; #ifdef USE_SML_SPECOPT @@ -398,9 +422,13 @@ struct METER_DESC { TasmotaSerial *meter_ss; #endif // ESP8266 #ifdef USE_SML_DECRYPT - bool use_crypt; + bool use_crypt = false; uint8_t last_iob; uint8_t key[SML_CRYPT_SIZE]; + Han_Parser *hp; +#ifdef USE_SML_AUTHKEY + uint8_t auth[SML_CRYPT_SIZE]; +#endif #endif }; @@ -418,8 +446,6 @@ struct METER_DESC meter_desc[MAX_METERS]; #define VBUS_SYNC 0xaa #define SML_SYNC 0x77 -#define SML_CRYPT_SYNC1 0x7e -#define SML_CRYPT_SYNC2 0xa0 #define EBUS_SYNC 0xaa #define EBUS_ESC 0xa9 @@ -456,6 +482,7 @@ struct SML_GLOBS { uint8_t ser_act_meter_num = 0; uint16_t sml_logindex; char *log_data; + uint16_t logsize = SML_DUMP_SIZE; #if defined(ED300L) || defined(AS2020) || defined(DTZ541) || defined(USE_SML_SPECOPT) uint8_t sml_status[MAX_METERS]; uint8_t g_mindex; @@ -541,9 +568,9 @@ double sml_median(struct SML_MEDIAN_FILTER* mf, double in) { #define SML_SAVAILABLE Serial_available() #define SML_SREAD Serial_read() -#define SML_SPEAK Serial_peek() +#define SML_SPEEK Serial_peek() -bool Serial_available() { +uint16_t Serial_available() { uint8_t num = sml_globs.dump2log & 7; if (num < 1 || num > sml_globs.meters_used) num = 1; if (!meter_desc[num - 1].meter_ss) return 0; @@ -564,9 +591,15 @@ uint8_t Serial_peek() { return meter_desc[num - 1].meter_ss->peek(); } +void sml_dump_start(char c) { + sml_globs.log_data[0] = ':'; + sml_globs.log_data[1] = c; + sml_globs.sml_logindex = 2; +} + #define SML_EBUS_SKIP_SYNC_DUMPS -uint8_t *hdlc_decode(uint8_t *data, uint32_t dlen, uint8_t *key, uint16_t *size); +uint8_t *hdlc_decode(struct METER_DESC *mp, uint16_t *size); void dump2log(void) { int16_t index = 0, hcnt = 0; @@ -582,42 +615,23 @@ void dump2log(void) { struct METER_DESC *mp = &meter_desc[meter]; if (mp->use_crypt == true) { d_lastms = millis(); - sml_globs.log_data[0] = ':'; - sml_globs.log_data[1] = ' '; - sml_globs.sml_logindex = 2; - while ((millis() - d_lastms) < 40) { + while ((millis() - d_lastms) < 50) { while (SML_SAVAILABLE) { - uint8_t iob = SML_SREAD; - sprintf(&sml_globs.log_data[sml_globs.sml_logindex], "%02x ", iob); - if (sml_globs.sml_logindex < SML_DUMP_SIZE - 7) { - sml_globs.sml_logindex += 3; - } - // fill raw serial buffer - mp->sbuff[mp->spos] = iob; - mp->spos++; - if (mp->spos >= mp->sbsiz) { - mp->spos = mp->sbsiz - 1; - } - if (iob == SML_CRYPT_SYNC2 && mp->last_iob == SML_CRYPT_SYNC1) { - // frame start - mp->spos = 2; - mp->sbuff[0] = SML_CRYPT_SYNC1; - mp->sbuff[1] = SML_CRYPT_SYNC2; - } - mp->last_iob = iob; + d_lastms = millis(); uint16_t logsiz; - uint8_t *fbuff = hdlc_decode(mp->sbuff, mp->spos, meter_desc[meter].key, &logsiz); - if (fbuff) { - // we decoded a valid frame - AddLog(LOG_LEVEL_INFO, PSTR(">> decrypted block: %d bytes"), logsiz); + uint8_t *payload; + if (mp->hp->readHanPort(&payload, &logsiz)) { + if (logsiz > mp->sbsiz) { + logsiz = mp->sbsiz; + } + memmove(mp->sbuff, payload, logsiz); + AddLog(LOG_LEVEL_INFO, PSTR("decrypted block: %d bytes"), logsiz); uint16_t index = 0; while (logsiz) { - sml_globs.log_data[0] = ':'; - sml_globs.log_data[1] = '>'; - sml_globs.sml_logindex = 2; + sml_dump_start('>'); for (uint16_t cnt = 0; cnt < 16; cnt++) { - sprintf(&sml_globs.log_data[sml_globs.sml_logindex], "%02x ", fbuff[index++]); - if (sml_globs.sml_logindex < SML_DUMP_SIZE - 7) { + sprintf(&sml_globs.log_data[sml_globs.sml_logindex], "%02x ", mp->sbuff[index++]); + if (sml_globs.sml_logindex < sml_globs.logsize - 7) { sml_globs.sml_logindex += 3; } logsiz--; @@ -627,13 +641,24 @@ void dump2log(void) { } AddLogData(LOG_LEVEL_INFO, sml_globs.log_data); } + } else { + // dump serial buffer + sml_dump_start(' '); + while (index < mp->spos) { + sprintf(&sml_globs.log_data[sml_globs.sml_logindex], "%02x ", mp->sbuff[index++]); + if (sml_globs.sml_logindex >= 32*3+2) { + AddLogData(LOG_LEVEL_INFO, sml_globs.log_data); + sml_dump_start(' '); + } + } } } } - if (sml_globs.sml_logindex > 2) { - sml_globs.log_data[sml_globs.sml_logindex] = 0; - AddLogData(LOG_LEVEL_INFO, sml_globs.log_data); - } + if (sml_globs.sml_logindex > 2) { + AddLogData(LOG_LEVEL_INFO, sml_globs.log_data); + sml_dump_start(' '); + } + mp->hp->len = 0; return; } #endif @@ -655,12 +680,9 @@ void dump2log(void) { hcnt++; if (hcnt > 15) { // line complete, build asci chars - sml_globs.log_data[index] = '='; - index++; - sml_globs.log_data[index] = '>'; - index++; - sml_globs.log_data[index] = ' '; - index++; + sml_globs.log_data[index++] = '='; + sml_globs.log_data[index++] = '>'; + sml_globs.log_data[index++] = ' '; for (uint8_t ccnt = 0; ccnt < 16; ccnt++) { if (isprint(dchars[ccnt])) { sml_globs.log_data[index] = dchars[ccnt]; @@ -690,14 +712,12 @@ void dump2log(void) { if (sml_globs.sml_logindex > 2) { sml_globs.log_data[sml_globs.sml_logindex] = 0; AddLogData(LOG_LEVEL_INFO, sml_globs.log_data); - sml_globs.log_data[0] = ':'; - sml_globs.log_data[1] = ' '; - sml_globs.sml_logindex = 2; + sml_dump_start(' '); } continue; } sml_globs.log_data[sml_globs.sml_logindex] = c; - if (sml_globs.sml_logindex < SML_DUMP_SIZE - 2) { + if (sml_globs.sml_logindex < sml_globs.logsize - 2) { sml_globs.sml_logindex++; } } @@ -710,12 +730,10 @@ void dump2log(void) { if (c == VBUS_SYNC) { sml_globs.log_data[sml_globs.sml_logindex] = 0; AddLogData(LOG_LEVEL_INFO, sml_globs.log_data); - sml_globs.log_data[0] = ':'; - sml_globs.log_data[1] = ' '; - sml_globs.sml_logindex = 2; + sml_dump_start(' '); } sprintf(&sml_globs.log_data[sml_globs.sml_logindex], "%02x ", c); - if (sml_globs.sml_logindex < SML_DUMP_SIZE - 7) { + if (sml_globs.sml_logindex < sml_globs.logsize - 7) { sml_globs.sml_logindex += 3; } } @@ -727,7 +745,7 @@ void dump2log(void) { while (SML_SAVAILABLE) { c = SML_SREAD; if (c == EBUS_SYNC) { - p = SML_SPEAK; + p = SML_SPEEK; if (p != EBUS_SYNC && sml_globs.sml_logindex > 5) { // new packet, plot last one sml_globs.log_data[sml_globs.sml_logindex] = 0; @@ -738,7 +756,7 @@ void dump2log(void) { continue; } sprintf(&sml_globs.log_data[sml_globs.sml_logindex], "%02x ", c); - if (sml_globs.sml_logindex < SML_DUMP_SIZE - 7) { + if (sml_globs.sml_logindex < sml_globs.logsize - 7) { sml_globs.sml_logindex += 3; } } @@ -752,12 +770,10 @@ void dump2log(void) { if (c == SML_SYNC) { sml_globs.log_data[sml_globs.sml_logindex] = 0; AddLogData(LOG_LEVEL_INFO, sml_globs.log_data); - sml_globs.log_data[0] = ':'; - sml_globs.log_data[1] = ' '; - sml_globs.sml_logindex = 2; + sml_dump_start(' '); } sprintf(&sml_globs.log_data[sml_globs.sml_logindex], "%02x ", c); - if (sml_globs.sml_logindex < SML_DUMP_SIZE - 7) { + if (sml_globs.sml_logindex < sml_globs.logsize - 7) { sml_globs.sml_logindex += 3; } } @@ -766,25 +782,28 @@ void dump2log(void) { default: // raw dump d_lastms = millis(); - sml_globs.log_data[0] = ':'; - sml_globs.log_data[1] = ' '; - sml_globs.sml_logindex = 2; - while ((millis() - d_lastms) < 40) { - while (SML_SAVAILABLE) { + sml_dump_start(' '); + while ((millis() - d_lastms) < 40) { + while (SML_SAVAILABLE) { + d_lastms = millis(); + yield(); sprintf(&sml_globs.log_data[sml_globs.sml_logindex], "%02x ", SML_SREAD); - if (sml_globs.sml_logindex < SML_DUMP_SIZE - 7) { + if (sml_globs.sml_logindex < sml_globs.logsize - 7) { sml_globs.sml_logindex += 3; - } else { - break; + } + if (sml_globs.sml_logindex >= 32*3+2) { + AddLogData(LOG_LEVEL_INFO, sml_globs.log_data); + sml_dump_start(' '); } - } + } } if (sml_globs.sml_logindex > 2) { sml_globs.log_data[sml_globs.sml_logindex] = 0; AddLogData(LOG_LEVEL_INFO, sml_globs.log_data); } break; - } + + } } } @@ -1158,27 +1177,24 @@ void sml_shift_in(uint32_t meters, uint32_t shard) { #ifdef USE_SML_DECRYPT if (mp->use_crypt) { - uint8_t iob = (uint8_t)mp->meter_ss->read(); - if (mp->spos < mp->sbsiz) { - mp->sbuff[mp->spos] = iob; - } - mp->spos++; - - if (iob == SML_CRYPT_SYNC2 && mp->last_iob == SML_CRYPT_SYNC1) { - // frame start - mp->spos = 2; - mp->sbuff[0] = SML_CRYPT_SYNC1; - mp->sbuff[1] = SML_CRYPT_SYNC2; - } - mp->last_iob = iob; - - uint16_t logsiz; - uint8_t *db = hdlc_decode(mp->sbuff, mp->spos, mp->key, &logsiz); - if (db) { - // we decoded a valid frame - memmove(mp->sbuff, db, logsiz); - AddLog(LOG_LEVEL_INFO, PSTR(">> decrypted block: %d bytes"), logsiz); - SML_Decode(meters); + if (mp->hp) { + uint32_t timediff = millis() - mp->lastms; + if (timediff > mp->tout_ms) { + mp->hp->len = 0; + mp->spos = 0; + AddLog(LOG_LEVEL_DEBUG, PSTR("SML: sync")); + } + mp->lastms = millis(); + uint16_t len; + uint8_t *payload; + if (mp->hp->readHanPort(&payload, &len)) { + if (len > mp->sbsiz) { + len = mp->sbsiz; + } + memmove(mp->sbuff, payload, len); + AddLog(LOG_LEVEL_INFO, PSTR(">> decrypted block: %d bytes"), len); + SML_Decode(meters); + } } return; } @@ -1220,11 +1236,19 @@ void sml_shift_in(uint32_t meters, uint32_t shard) { break; case 'R': // raw without shift + { + uint32_t timediff = millis() - mp->lastms; + if (timediff > mp->tout_ms) { + mp->spos = 0; + AddLog(LOG_LEVEL_DEBUG, PSTR("SML: sync")); + } + mp->lastms = millis(); mp->sbuff[mp->spos] = iob; mp->spos++; if (mp->spos > mp->sbsiz) { mp->spos = 0; } + } break; case 'k': // Kamstrup @@ -1338,6 +1362,8 @@ void sml_shift_in(uint32_t meters, uint32_t shard) { } +uint16_t sml_count = 0; + // polled every 50 ms void SML_Poll(void) { uint32_t meters; @@ -1352,6 +1378,14 @@ uint32_t meters; while (meter_desc[meters].meter_ss->available()) { sml_shift_in(meters, 0); } +/* + if (meter_desc[meters].meter_ss->available()) { + sml_count++; + uint8_t iob = meter_desc[meters].meter_ss->read(); + if (sml_count<5 || sml_count > 100) { + AddLog(LOG_LEVEL_INFO, PSTR(">> %02x - %d"),iob,sml_count); + } + }*/ } } } @@ -1400,6 +1434,54 @@ char *skip_double(char *cp) { return 0; } +uint8_t *sml_find(uint8_t *src, uint16_t ssize, uint8_t *pattern, uint16_t psize) { + //AddLog(LOG_LEVEL_INFO, PSTR(">> %02x %02x %02x %02x"),pattern[0],pattern[1],pattern[2],pattern[3]); + if (psize >= ssize) { + return 0; + } + for (uint32_t cnt = 0; cnt < ssize - psize; cnt++) { + if (!memcmp(src, pattern, psize)) { + return src; + } + src++; + } + return 0; +} + +double sml_get_obis_value(uint8_t *data) { + double out = 0; + CosemData *item = (CosemData *)data; + switch (item->base.type) { + case CosemTypeLongSigned: { + out = ntohs(item->ls.data); + break; + } + case CosemTypeLongUnsigned: { + out = ntohs(item->lu.data); + break; + } + case CosemTypeDLongSigned: { + out = ntohl(item->dlu.data); + break; + } + case CosemTypeDLongUnsigned: { + out = ntohl(item->dlu.data); + break; + } + case CosemTypeLong64Signed: { + out = ntohll(item->l64s.data); + break; + } + case CosemTypeLong64Unsigned: { + out = ntohll(item->l64u.data); + break; + } + } + return out; +} + + + void SML_Decode(uint8_t index) { const char *mp = (const char*)sml_globs.meter_p; @@ -1512,7 +1594,7 @@ void SML_Decode(uint8_t index) { SML_Immediate_MQTT((const char*)mp, vindex, mindex); sml_globs.dvalid[vindex] = 1; // get sfac - } else if (*mp=='d') { + } else if (*mp == 'd') { // calc deltas d ind 10 (eg every 10 secs) if (dindex < MAX_DVARS) { // only n indexes @@ -1583,12 +1665,73 @@ void SML_Decode(uint8_t index) { uint8_t val = hexnibble(*mp++) << 4; val |= hexnibble(*mp++); if (val != *cp++) { - found=0; + found = 0; } } else { // ebus modbus pzem vbus or raw - // XXHHHHSSUU - if (*mp == 'x') { + if (!strncmp(mp, "pm(", 3)) { + // pattern match + uint8_t dp = 0; + mp += 3; + // default to asci obis + uint8_t aflg = 3; + if (*mp == 'r') { + aflg = 0; + mp++; + } else if (*mp == 'h') { + aflg = 1; + mp++; + } + uint8_t pattern[64]; + // check for obis pattern + for (uint32_t cnt = 0; cnt < sizeof(pattern); cnt++) { + if (*mp == '@' || !*mp) { + break; + } + if (*mp == ')') { + mp++; + if ((aflg & 2) && (dp == 2)) { + pattern[cnt] = 0xff; + cnt++; + } + pattern[cnt] = 0; + uint8_t *ucp = sml_find(cp, meter_desc[index].sbsiz, pattern, cnt); + if (ucp) { + cp = ucp + cnt; + // check auto type + if (aflg & 1) { + // METER_ID_SIZE + CosemData *item = (CosemData *)cp; + switch (item->base.type) { + case CosemTypeString: + memcpy(meter_desc[mindex].meter_id, item->str.data, item->str.length); + meter_desc[mindex].meter_id[item->str.length] = 0; + break; + case CosemTypeOctetString: + memcpy(meter_desc[mindex].meter_id, item->oct.data, item->oct.length); + meter_desc[mindex].meter_id[item->oct.length] = 0; + break; + default: + ebus_dval = sml_get_obis_value(cp); + } + } + } + break; + } + uint8_t iob; + if (aflg & 2) { + iob = strtol((char*)mp, (char**)&mp, 10); + if (*mp == '.') { + mp++; + dp++; + } + } else { + iob = hexnibble(*mp++) << 4; + iob |= hexnibble(*mp++); + } + pattern[cnt] = iob; + } + } else if (*mp == 'x') { if (*(mp + 1) == 'x') { //ignore one byte mp += 2; @@ -1873,7 +2016,6 @@ void SML_Decode(uint8_t index) { meter_desc[mindex].meter_id[p] = *cp++; } meter_desc[mindex].meter_id[p] = 0; - } else if (sml_globs.mp[mindex].type == 'k') { // 220901 uint32_t date = mbus_dval; @@ -1889,7 +2031,7 @@ void SML_Decode(uint8_t index) { } else { double dval; char type = sml_globs.mp[mindex].type; - if (type != 'e' && type != 'r' && type != 'm' && type != 'M' && type != 'k' && type != 'p' && type != 'v') { + if (type != 'e' && type != 'r' && type != 'R' && type != 'm' && type != 'M' && type != 'k' && type != 'p' && type != 'v') { // get numeric values if (type == 'o' || type == 'c') { if (*mp == '(') { @@ -2220,7 +2362,6 @@ void SML_Show(boolean json) { } - #ifdef USE_DOMOTICZ if (json && !TasmotaGlobal.tele_period) { char str[16]; @@ -2274,7 +2415,6 @@ void IRAM_ATTR SML_CounterIsr(void *arg) { sml_counter_pinstate ^= (1 << index); } - #ifndef METER_DEF_SIZE #define METER_DEF_SIZE 3000 #endif @@ -2336,161 +2476,169 @@ bool Gpio_used(uint8_t gpiopin) { #define SML_MINSB 64 char *SpecOptions(char *cp, uint32_t mnum) { // special option +struct METER_DESC *mp = &meter_desc[mnum]; switch (*cp) { case '1': cp++; #ifdef USE_SML_SPECOPT if (*cp == ',') { cp++; - meter_desc[mnum].so_obis1 = strtol(cp, &cp, 16); + mp->so_obis1 = strtol(cp, &cp, 16); } if (*cp == ',') { cp++; - meter_desc[mnum].so_fcode1 = strtol(cp, &cp, 16); + mp->so_fcode1 = strtol(cp, &cp, 16); } if (*cp == ',') { cp++; - meter_desc[mnum].so_bpos1 = strtol(cp, &cp, 10); + mp->so_bpos1 = strtol(cp, &cp, 10); } if (*cp == ',') { cp++; - meter_desc[mnum].so_fcode2 = strtol(cp, &cp, 16); + mp->so_fcode2 = strtol(cp, &cp, 16); } if (*cp == ',') { cp++; - meter_desc[mnum].so_bpos2 = strtol(cp, &cp, 10); + mp->so_bpos2 = strtol(cp, &cp, 10); } if (*cp == ',') { cp++; - meter_desc[mnum].so_obis2 = strtol(cp, &cp, 16); + mp->so_obis2 = strtol(cp, &cp, 16); } #endif break; case '2': cp += 2; - meter_desc[mnum].so_flags = strtol(cp, &cp, 16); + mp->so_flags = strtol(cp, &cp, 16); break; case '3': cp += 2; - meter_desc[mnum].sbsiz = strtol(cp, &cp, 10); + mp->sbsiz = strtol(cp, &cp, 10); if (*cp == ',') { cp++; - meter_desc[mnum].sibsiz = strtol(cp, &cp, 10); - if (meter_desc[mnum].sibsiz < SML_MINSB) { - meter_desc[mnum].sibsiz = SML_MINSB; + mp->sibsiz = strtol(cp, &cp, 10); + if (mp->sibsiz < SML_MINSB) { + mp->sibsiz = SML_MINSB; } } + if (*cp == ',') { + cp++; + sml_globs.logsize = strtol(cp, &cp, 10); + } break; case '4': cp += 2; #ifdef USE_SML_DECRYPT meter_desc[mnum].use_crypt = true; for (uint8_t cnt = 0; cnt < (SML_CRYPT_SIZE * 2); cnt += 2) { - meter_desc[mnum].key[cnt / 2] = (sml_hexnibble(cp[cnt]) << 4) | sml_hexnibble(cp[cnt + 1]); + mp->key[cnt / 2] = (sml_hexnibble(cp[cnt]) << 4) | sml_hexnibble(cp[cnt + 1]); } -#endif + AddLog(LOG_LEVEL_INFO, PSTR("SML: crypto mode used for meter %d"), mnum + 1); break; +#ifdef USE_SML_AUTHKEY + case '5': + cp += 2; + for (uint8_t cnt = 0; cnt < (SML_CRYPT_SIZE * 2); cnt += 2) { + mp->auth[cnt / 2] = (sml_hexnibble(cp[cnt]) << 4) | sml_hexnibble(cp[cnt + 1]); + } + break; + case '6': + cp += 2; + mp->tout_ms = strtol(cp, &cp, 10); + break; +#endif +#endif } return cp; } #ifdef USE_SML_DECRYPT - -//// calculate crc16 CCITT -uint16_t hdlc_crc16(const uint8_t *dp, uint8_t len) { -#define POLY 0x8408 - uint8_t i; - uint16_t data; - uint16_t crc = 0xffff; - - if (len == 0) { - return (~crc); +uint16_t serial_dispatch(uint8_t meter, uint8_t sel) { + struct METER_DESC *mp = &meter_desc[meter]; + if (!sel) { + return mp->meter_ss->available(); } - do { - data = (unsigned int)0xff & *dp++; - for (i = 0; i < 8; i++) { - if ((crc & 0x0001) ^ (data & 0x0001)) { - crc = (crc >> 1) ^ POLY; - } else { - crc >>= 1; - } - data >>= 1; - } - } while (--len); - - crc = ~crc; - data = crc; - crc = (crc << 8) | (data >> 8 & 0xff); - return crc; + uint8_t iob = mp->meter_ss->read(); + return iob; } -uint8_t *hdlc_decode(uint8_t *data, uint32_t dlen, uint8_t *key, uint16_t *size) { - if (dlen < 31) { - return 0; +int SML_print(const char *format, ...) { + static char loc_buf[64]; + char* temp = loc_buf; + int len; + va_list arg; + va_list copy; + va_start(arg, format); + va_copy(copy, arg); + len = vsnprintf(NULL, 0, format, arg); + va_end(copy); + if (len >= sizeof(loc_buf)) { + temp = (char*)malloc(len + 1); + if (temp == NULL) { + return 0; + } } - uint16_t crc = hdlc_crc16(data + 1, dlen - 4); - uint16_t dcrc = data[dlen - 3] << 8 | data[dlen - 2]; - if (crc != dcrc) { - return 0; + vsnprintf(temp, len + 1, format, arg); + AddLog(LOG_LEVEL_DEBUG, PSTR("SML: %s"),temp); + va_end(arg); + if (len >= sizeof(loc_buf)) { + free(temp); } - - // crc OK - uint8_t ivec[12]; - uint8_t index = 0; - for (uint8_t cnt = 14; cnt < 14+8; cnt++) { - ivec[index] = data[cnt]; - index++; - } - for (uint8_t cnt = 24; cnt < 24+4; cnt++) { - ivec[index] = data[cnt]; - index++; - } - - br_gcm_context gcm_ctx; - br_aes_small_ctr_keys ctr_ctx; - br_aes_small_ctr_init(&ctr_ctx, key, 16); - br_gcm_init(&gcm_ctx, &ctr_ctx.vtable, &br_ghash_ctmul32); - br_gcm_reset(&gcm_ctx, ivec, 12); - br_gcm_flip(&gcm_ctx); - br_gcm_run(&gcm_ctx, 0, data + 28 , dlen - 31); - *size = dlen - 31; - return data + 28; + return len; } -#endif +#endif // USE_SML_DECRYPT void reset_sml_vars(uint16_t maxmeters) { for (uint32_t meters = 0; meters < maxmeters; meters++) { - meter_desc[meters].spos = 0; - meter_desc[meters].sbsiz = SML_BSIZ; - meter_desc[meters].sibsiz = TMSBSIZ; - if (meter_desc[meters].sbuff) { - free(meter_desc[meters].sbuff); - meter_desc[meters].sbuff = 0; + + struct METER_DESC *mp = &meter_desc[meters]; + mp->spos = 0; + mp->sbsiz = SML_BSIZ; + mp->sibsiz = TMSBSIZ; + if (mp->sbuff) { + free(mp->sbuff); + mp->sbuff = 0; } #ifdef USE_SML_SPECOPT - meter_desc[meters].so_obis1 = 0; - meter_desc[meters].so_obis2 = 0; + mp->so_obis1 = 0; + mp->so_obis2 = 0; #endif - meter_desc[meters].so_flags = 0; + mp->so_flags = 0; // addresses a bug in meter DWS74 #ifdef DWS74_BUG - meter_desc[meters].so_flags |= SO_DWS74_BUG; + mp->so_flags |= SO_DWS74_BUG; #endif #ifdef SML_OBIS_LINE - meter_desc[meters].so_flags |= SO_OBIS_LINE; + mp->so_flags |= SO_OBIS_LINE; #endif - if (meter_desc[meters].txmem) { - free(meter_desc[meters].txmem); - meter_desc[meters].txmem = 0; + if (mp->txmem) { + free(mp->txmem); + mp->txmem = 0; } - meter_desc[meters].txmem = 0; - meter_desc[meters].trxpin = -1; - if (meter_desc[meters].meter_ss) { - delete meter_desc[meters].meter_ss; - meter_desc[meters].meter_ss = NULL; + mp->txmem = 0; + mp->trxpin = -1; + if (mp->meter_ss) { + delete mp->meter_ss; + mp->meter_ss = NULL; } + + mp->lastms = millis(); + mp->tout_ms = SML_STIMEOUT; + +#ifdef USE_SML_DECRYPT + if (mp->use_crypt) { + if (mp->hp) { + delete mp->hp; + mp->hp = NULL; + } + } + mp->use_crypt = 0; +#ifdef USE_SML_AUTHKEY + memset(mp->auth, 0, SML_CRYPT_SIZE); +#endif +#endif // USE_SML_DECRYPT } } @@ -2940,6 +3088,16 @@ next_line: } else { mp->shift_mode = (type != 'o' && type != 'e' && type != 'k' && type != 'm' && type != 'M' && type != 'p' && type != 'R' && type != 'v'); } + +#ifdef USE_SML_DECRYPT + if (mp->use_crypt) { +#ifdef USE_SML_AUTHKEY + mp->hp = new Han_Parser(serial_dispatch, meters, mp->key, mp->auth); +#else + mp->hp = new Han_Parser(serial_dispatch, meters, mp->key, nullptr); +#endif + } +#endif } sml_globs.ready = true; @@ -3462,22 +3620,24 @@ bool XSNS_53_cmd(void) { char *cp = XdrvMailbox.data; if (*cp == 'd') { // set dump mode - cp++; - uint8_t index = atoi(cp); - if ((index & 7) > sml_globs.meters_used) index = 1; - if (index > 0 && sml_globs.mp[(index & 7) - 1].type == 'c') { - index = 0; - } - if (sml_globs.log_data) { - free(sml_globs.log_data); - sml_globs.log_data = 0; - } + if (sml_globs.ready) { + cp++; + uint8_t index = atoi(cp); + if ((index & 7) > sml_globs.meters_used) index = 1; + if (index > 0 && sml_globs.mp[(index & 7) - 1].type == 'c') { + index = 0; + } + if (sml_globs.log_data) { + free(sml_globs.log_data); + sml_globs.log_data = 0; + } - if (index > 0) { - sml_globs.log_data = (char*)calloc(SML_DUMP_SIZE, sizeof(char)); + if (index > 0) { + sml_globs.log_data = (char*)calloc(sml_globs.logsize, sizeof(char)); + } + sml_globs.dump2log = index; + ResponseTime_P(PSTR(",\"SML\":{\"CMD\":\"dump: %d\"}}"), sml_globs.dump2log); } - sml_globs.dump2log = index; - ResponseTime_P(PSTR(",\"SML\":{\"CMD\":\"dump: %d\"}}"), sml_globs.dump2log); } else if (*cp == 'c') { // set counter cp++; @@ -3498,38 +3658,38 @@ bool XSNS_53_cmd(void) { } } ResponseTime_P(PSTR(",\"SML\":{\"CMD\":\"counter%d: %d\"}}"), index, RtcSettings.pulse_counter[index - 1]); - } else if (*cp=='r') { + } else if (*cp == 'r') { // restart ResponseTime_P(PSTR(",\"SML\":{\"CMD\":\"restart\"}}")); SML_CounterSaveState(); SML_Init(); - } else if (*cp=='m') { + } else if (*cp == 'm') { // meter number for serial activity cp++; if (!isdigit(*cp)) { - ResponseTime_P(PSTR(",\"SML\":{\"CMD\":\"sml_globs.ser_act_meter_num: %d\"}}"),sml_globs.ser_act_meter_num); + ResponseTime_P(PSTR(",\"SML\":{\"CMD\":\"sml_globs.ser_act_meter_num: %d\"}}"), sml_globs.ser_act_meter_num); } else { - sml_globs.ser_act_meter_num=atoi(cp); - ResponseTime_P(PSTR(",\"SML\":{\"CMD\":\"sml_globs.ser_act_meter_num: %d\"}}"),sml_globs.ser_act_meter_num); + sml_globs.ser_act_meter_num = atoi(cp); + ResponseTime_P(PSTR(",\"SML\":{\"CMD\":\"sml_globs.ser_act_meter_num: %d\"}}"), sml_globs.ser_act_meter_num); } - } else if (*cp=='l') { + } else if (*cp == 'l') { // serial activity LED-GPIO cp++; if (!isdigit(*cp)) { - ResponseTime_P(PSTR(",\"SML\":{\"CMD\":\"sml_globs.ser_act_LED_pin: %d\"}}"),sml_globs.ser_act_LED_pin); + ResponseTime_P(PSTR(",\"SML\":{\"CMD\":\"sml_globs.ser_act_LED_pin: %d\"}}"), sml_globs.ser_act_LED_pin); } else { - sml_globs.ser_act_LED_pin=atoi(cp); + sml_globs.ser_act_LED_pin = atoi(cp); if (Gpio_used(sml_globs.ser_act_LED_pin)) { - AddLog(LOG_LEVEL_INFO, PSTR("SML: Error: Duplicate GPIO %d defined. Not usable for LED."),sml_globs.ser_act_LED_pin); - sml_globs.ser_act_LED_pin=255; + AddLog(LOG_LEVEL_INFO, PSTR("SML: Error: Duplicate GPIO %d defined. Not usable for LED."), sml_globs.ser_act_LED_pin); + sml_globs.ser_act_LED_pin = 255; } - if (sml_globs.ser_act_LED_pin!=255) { + if (sml_globs.ser_act_LED_pin != 255) { pinMode(sml_globs.ser_act_LED_pin, OUTPUT); } - ResponseTime_P(PSTR(",\"SML\":{\"CMD\":\"sml_globs.ser_act_LED_pin: %d\"}}"),sml_globs.ser_act_LED_pin); + ResponseTime_P(PSTR(",\"SML\":{\"CMD\":\"sml_globs.ser_act_LED_pin: %d\"}}"), sml_globs.ser_act_LED_pin); } } else { - serviced=false; + serviced = false; } } return serviced; From d9cbbaeb2a3279b6befde3bb25248e242b251d9d Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 30 Jan 2023 15:36:46 +0100 Subject: [PATCH 203/262] Fix energy usage and return migrated too small Fix energy usage and return migrated too small (/10000) regression from v12.3.1.3 --- CHANGELOG.md | 1 + tasmota/tasmota_support/settings.ino | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 14f5895fc..23ae173f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ All notable changes to this project will be documented in this file. - Shelly Pro 1/2 relay click at restart regression from v12.3.1.4 - Zigbee extend plug-in modifiers to 16 bits - Broken I2C priority regression from v12.3.1.3 (#17810) +- Energy usage and return migrated too small (/10000) regression from v12.3.1.3 ### Removed diff --git a/tasmota/tasmota_support/settings.ino b/tasmota/tasmota_support/settings.ino index cbc88be95..06a322e5d 100644 --- a/tasmota/tasmota_support/settings.ino +++ b/tasmota/tasmota_support/settings.ino @@ -1620,13 +1620,13 @@ void SettingsDelta(void) { Settings->energy_kWhtotal_ph[i] /= 100; RtcSettings.energy_kWhexport_ph[i] /= 100; Settings->energy_kWhexport_ph[i] /= 100; - RtcSettings.energy_usage.usage1_kWhtotal /= 100; - RtcSettings.energy_usage.usage2_kWhtotal /= 100; - RtcSettings.energy_usage.return1_kWhtotal /= 100; - RtcSettings.energy_usage.return2_kWhtotal /= 100; - RtcSettings.energy_usage.last_return_kWhtotal /= 100; - RtcSettings.energy_usage.last_usage_kWhtotal /= 100; } + RtcSettings.energy_usage.usage1_kWhtotal /= 100; + RtcSettings.energy_usage.usage2_kWhtotal /= 100; + RtcSettings.energy_usage.return1_kWhtotal /= 100; + RtcSettings.energy_usage.return2_kWhtotal /= 100; + RtcSettings.energy_usage.last_return_kWhtotal /= 100; + RtcSettings.energy_usage.last_usage_kWhtotal /= 100; } Settings->version = VERSION; From 3d39efaf4ab4617b6dd82624bf68dd5ed1aebd57 Mon Sep 17 00:00:00 2001 From: Barbudor Date: Mon, 30 Jan 2023 22:35:38 +0100 Subject: [PATCH 204/262] isTuya optionnal arg to validpin (#17835) --- tasmota/tasmota_support/support.ino | 4 ++-- tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v1.ino | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tasmota/tasmota_support/support.ino b/tasmota/tasmota_support/support.ino index 33b69b51b..7c8c90f5e 100755 --- a/tasmota/tasmota_support/support.ino +++ b/tasmota/tasmota_support/support.ino @@ -1646,7 +1646,7 @@ bool RedPin(uint32_t pin) // pin may be dangerous to change, display in RED in t #endif } -uint32_t ValidPin(uint32_t pin, uint32_t gpio) { +uint32_t ValidPin(uint32_t pin, uint32_t gpio, uint8_t isTuya = false) { if (FlashPin(pin)) { return GPIO_NONE; // Disable flash pins GPIO6, GPIO7, GPIO8 and GPIO11 } @@ -1658,7 +1658,7 @@ uint32_t ValidPin(uint32_t pin, uint32_t gpio) { #elif defined(CONFIG_IDF_TARGET_ESP32) // ignore #else // not ESP32C3 and not ESP32S2 - if (((WEMOS == Settings->module) || (TUYA_DIMMER == Settings->module) || (USER_MODULE == Settings->module)) && !Settings->flag3.user_esp8285_enable) { // SetOption51 - Enable ESP8285 user GPIO's + if (((WEMOS == Settings->module) || isTuya) && !Settings->flag3.user_esp8285_enable) { // SetOption51 - Enable ESP8285 user GPIO's if ((9 == pin) || (10 == pin)) { return GPIO_NONE; // Disable possible flash GPIO9 and GPIO10 } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v1.ino b/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v1.ino index 54633d8a5..431ac2979 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v1.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v1.ino @@ -1111,7 +1111,7 @@ void TuyaNormalPowerModePacketProcess(void) // If LED_1 not yet configured if (!led1_set) { // Check is the GPIO is not already in use and if it is valid - if (!Settings->my_gp.io[led1_gpio] && ValidPin(led1_gpio,GPIO_LED1)) { + if (!Settings->my_gp.io[led1_gpio] && ValidPin(led1_gpio,GPIO_LED1, true)) { Settings->my_gp.io[led1_gpio] = AGPIO(GPIO_LED1); TasmotaGlobal.restart_flag = 2; AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: Set LED1 on gpio%d, will restart"), led1_gpio); @@ -1122,7 +1122,7 @@ void TuyaNormalPowerModePacketProcess(void) // If KEY_1 not yet configured if (!key1_set) { // Check is the GPIO is not already in use and if it is valid - if (!Settings->my_gp.io[key1_gpio] && ValidPin(key1_gpio,GPIO_KEY1)) { + if (!Settings->my_gp.io[key1_gpio] && ValidPin(key1_gpio,GPIO_KEY1, true)) { Settings->my_gp.io[key1_gpio] = AGPIO(GPIO_KEY1); TasmotaGlobal.restart_flag = 2; AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: Set KEY1 on gpio%d, will restart"), key1_gpio); From 2207d08cfa8037176d0cfeb816acc424c35392a8 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Tue, 31 Jan 2023 11:41:41 +0100 Subject: [PATCH 205/262] rm non existing env `tasmota32-sensors` --- platformio_override_sample.ini | 1 - 1 file changed, 1 deletion(-) diff --git a/platformio_override_sample.ini b/platformio_override_sample.ini index 572a595a0..96a9d8571 100644 --- a/platformio_override_sample.ini +++ b/platformio_override_sample.ini @@ -32,7 +32,6 @@ default_envs = ; tasmota32-bluetooth ; tasmota32-webcam ; tasmota32-knx -; tasmota32-sensors ; tasmota32-lvgl ; tasmota32-ir ; tasmota32solo1 From b8677ce0d64d6a895009280cbfb393a810343792 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Tue, 31 Jan 2023 14:46:09 +0100 Subject: [PATCH 206/262] revert PR Olimex fix (#17841) --- .../xdrv_82_esp32_ethernet.ino | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_82_esp32_ethernet.ino b/tasmota/tasmota_xdrv_driver/xdrv_82_esp32_ethernet.ino index ddb1a0e5c..0ce6b3789 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_82_esp32_ethernet.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_82_esp32_ethernet.ino @@ -190,31 +190,31 @@ void EthernetInit(void) { int eth_power = Pin(GPIO_ETH_PHY_POWER); int eth_mdc = Pin(GPIO_ETH_PHY_MDC); int eth_mdio = Pin(GPIO_ETH_PHY_MDIO); -#if CONFIG_IDF_TARGET_ESP32 +//#if CONFIG_IDF_TARGET_ESP32 // fix an disconnection issue after rebooting Olimex POE - this forces a clean state for all GPIO involved in RMII - gpio_reset_pin((gpio_num_t)GPIO_ETH_PHY_POWER); - gpio_reset_pin((gpio_num_t)GPIO_ETH_PHY_MDC); - gpio_reset_pin((gpio_num_t)GPIO_ETH_PHY_MDIO); - gpio_reset_pin(GPIO_NUM_19); // EMAC_TXD0 - hardcoded - gpio_reset_pin(GPIO_NUM_21); // EMAC_TX_EN - hardcoded - gpio_reset_pin(GPIO_NUM_22); // EMAC_TXD1 - hardcoded - gpio_reset_pin(GPIO_NUM_25); // EMAC_RXD0 - hardcoded - gpio_reset_pin(GPIO_NUM_26); // EMAC_RXD1 - hardcoded - gpio_reset_pin(GPIO_NUM_27); // EMAC_RX_CRS_DV - hardcoded - switch (Settings->eth_clk_mode) { - case 0: // ETH_CLOCK_GPIO0_IN - case 1: // ETH_CLOCK_GPIO0_OUT - gpio_reset_pin(GPIO_NUM_0); - break; - case 2: // ETH_CLOCK_GPIO16_OUT - gpio_reset_pin(GPIO_NUM_16); - break; - case 3: // ETH_CLOCK_GPIO17_OUT - gpio_reset_pin(GPIO_NUM_17); - break; - } - delay(1); -#endif // CONFIG_IDF_TARGET_ESP32 +// gpio_reset_pin((gpio_num_t)GPIO_ETH_PHY_POWER); +// gpio_reset_pin((gpio_num_t)GPIO_ETH_PHY_MDC); +// gpio_reset_pin((gpio_num_t)GPIO_ETH_PHY_MDIO); +// gpio_reset_pin(GPIO_NUM_19); // EMAC_TXD0 - hardcoded +// gpio_reset_pin(GPIO_NUM_21); // EMAC_TX_EN - hardcoded +// gpio_reset_pin(GPIO_NUM_22); // EMAC_TXD1 - hardcoded +// gpio_reset_pin(GPIO_NUM_25); // EMAC_RXD0 - hardcoded +// gpio_reset_pin(GPIO_NUM_26); // EMAC_RXD1 - hardcoded +// gpio_reset_pin(GPIO_NUM_27); // EMAC_RX_CRS_DV - hardcoded +// switch (Settings->eth_clk_mode) { +// case 0: // ETH_CLOCK_GPIO0_IN +// case 1: // ETH_CLOCK_GPIO0_OUT +// gpio_reset_pin(GPIO_NUM_0); +// break; +// case 2: // ETH_CLOCK_GPIO16_OUT +// gpio_reset_pin(GPIO_NUM_16); +// break; +// case 3: // ETH_CLOCK_GPIO17_OUT +// gpio_reset_pin(GPIO_NUM_17); +// break; +// } +// delay(1); +//#endif // CONFIG_IDF_TARGET_ESP32 if (!ETH.begin(Settings->eth_address, eth_power, eth_mdc, eth_mdio, (eth_phy_type_t)Settings->eth_type, (eth_clock_mode_t)Settings->eth_clk_mode)) { AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_ETH "Bad PHY type or init error")); return; From ae8041140f0d3fa013296ca1e0f4d9277b657694 Mon Sep 17 00:00:00 2001 From: gemu Date: Tue, 31 Jan 2023 22:22:28 +0100 Subject: [PATCH 207/262] Webcam fix (#17840) * Update xdrv_81_esp32_webcam.ino * fix single picture fetch * delay not needed --- .../tasmota_xdrv_driver/xdrv_81_esp32_webcam.ino | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_81_esp32_webcam.ino b/tasmota/tasmota_xdrv_driver/xdrv_81_esp32_webcam.ino index c03031c56..59f4e83e6 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_81_esp32_webcam.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_81_esp32_webcam.ino @@ -192,7 +192,7 @@ bool WcPinUsed(void) { if (!PinUsed(GPIO_WEBCAM_XCLK) || !PinUsed(GPIO_WEBCAM_PCLK) || !PinUsed(GPIO_WEBCAM_VSYNC) || !PinUsed(GPIO_WEBCAM_HREF) || ((!PinUsed(GPIO_WEBCAM_SIOD) || !PinUsed(GPIO_WEBCAM_SIOC)) && !TasmotaGlobal.i2c_enabled_2) // preferred option is to reuse and share I2Cbus 2 - ) { + ) { pin_used = false; } return pin_used; @@ -432,7 +432,10 @@ uint32_t WcSetup(int32_t fsiz) { WcApplySettings(); - AddLog(LOG_LEVEL_INFO, PSTR("CAM: Initialized")); + camera_sensor_info_t *info = esp_camera_sensor_get_info(&wc_s->id); + + AddLog(LOG_LEVEL_INFO, PSTR("CAM: %s Initialized"), info->name); + Wc.up = 1; if (psram) { Wc.up = 2; } @@ -756,6 +759,13 @@ void HandleImage(void) { camera_fb_t *wc_fb = 0; wc_fb = esp_camera_fb_get(); if (!wc_fb) { return; } + if (Wc.stream_active < 2) { + // fetch some more frames + esp_camera_fb_return(wc_fb); + wc_fb = esp_camera_fb_get(); + esp_camera_fb_return(wc_fb); + wc_fb = esp_camera_fb_get(); + } if (wc_fb->format != PIXFORMAT_JPEG) { bool jpeg_converted = frame2jpg(wc_fb, 80, &_jpg_buf, &_jpg_buf_len); if (!jpeg_converted) { From 438b235dc88a4dbb954a9b9737671f0aa06fd9b1 Mon Sep 17 00:00:00 2001 From: SteWers <42718143+SteWers@users.noreply.github.com> Date: Tue, 31 Jan 2023 22:23:31 +0100 Subject: [PATCH 208/262] [Solax X1] fix apparent power (#17833) U*I from inverter is not valid for apparent power as U*I could be lower than active power --- tasmota/tasmota_xnrg_energy/xnrg_12_solaxX1.ino | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tasmota/tasmota_xnrg_energy/xnrg_12_solaxX1.ino b/tasmota/tasmota_xnrg_energy/xnrg_12_solaxX1.ino index 9a36439b9..6915d1411 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_12_solaxX1.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_12_solaxX1.ino @@ -2,7 +2,7 @@ xnrg_12_solaxX1.ino - Solax X1 inverter RS485 support for Tasmota Copyright (C) 2021 by Pablo Zerón - Copyright (C) 2022 by Stefan Wershoven + Copyright (C) 2023 by Stefan Wershoven This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -295,6 +295,7 @@ void solaxX1_250MSecond(void) // Every 250 milliseconds Energy->voltage[0] = ((DataRead[23] << 8) | DataRead[24]) * 0.1f; // AC Voltage Energy->frequency[0] = ((DataRead[25] << 8) | DataRead[26]) * 0.01f; // AC Frequency Energy->active_power[0] = ((DataRead[27] << 8) | DataRead[28]); // AC Power + Energy->apparent_power[0] = Energy->active_power[0]; // U*I from inverter is not valid for apparent power; U*I could be lower than active power //temporal = (float)((DataRead[29] << 8) | DataRead[30]) * 0.1f; // Not Used Energy->import_active[0] = ((DataRead[31] << 24) | (DataRead[32] << 16) | (DataRead[33] << 8) | DataRead[34]) * 0.1f; // Energy Total solaxX1.runtime_total = (DataRead[35] << 24) | (DataRead[36] << 16) | (DataRead[37] << 8) | DataRead[38]; // Work Time Total From db581b15c730a3138f640edc244ecc74b168c07c Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Tue, 31 Jan 2023 22:30:50 +0100 Subject: [PATCH 209/262] Add SetOption150 Add SetOption150 - (Energy) Force no voltage/frequency common allowing individual voltage channel calibration. --- tasmota/include/tasmota_types.h | 2 +- tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino | 15 +++++++++------ .../tasmota_xdrv_driver/xdrv_03_esp32_energy.ino | 15 +++++++++------ tools/decode-status.py | 5 +++-- 4 files changed, 22 insertions(+), 15 deletions(-) diff --git a/tasmota/include/tasmota_types.h b/tasmota/include/tasmota_types.h index 5e7d5cd16..2e672f088 100644 --- a/tasmota/include/tasmota_types.h +++ b/tasmota/include/tasmota_types.h @@ -183,7 +183,7 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu uint32_t mqtt_disable_sserialrec : 1; // bit 1 (v12.1.1.2) - SetOption147 - (MQTT) Disable publish SSerialReceived MQTT messages, you must use event trigger rules instead. uint32_t artnet_autorun : 1; // bit 2 (v12.2.0.4) - SetOption148 - (Light) start DMX ArtNet at boot, listen to UDP port as soon as network is up uint32_t dns_ipv6_priority : 1; // bit 3 (v12.2.0.6) - SetOption149 - (Wifi) prefer IPv6 DNS resolution to IPv4 address when available. Requires `#define USE_IPV6` - uint32_t spare04 : 1; // bit 4 + uint32_t no_voltage_common : 1; // bit 4 (v12.3.1.5) - SetOption150 - (Energy) Force no voltage/frequency common uint32_t spare05 : 1; // bit 5 uint32_t spare06 : 1; // bit 6 uint32_t spare07 : 1; // bit 7 diff --git a/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino b/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino index 2059b51dc..bdba44bfa 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino @@ -1200,7 +1200,10 @@ const char HTTP_ENERGY_SNS3[] PROGMEM = #endif // USE_WEBSERVER void EnergyShow(bool json) { - if (Energy->voltage_common) { + bool voltage_common = (Settings->flag6.no_voltage_common) ? false : Energy->voltage_common; + bool frequency_common = (Settings->flag6.no_voltage_common) ? false : Energy->frequency_common; + + if (voltage_common) { for (uint32_t i = 0; i < Energy->phase_count; i++) { Energy->voltage[i] = Energy->voltage[0]; } @@ -1333,12 +1336,12 @@ void EnergyShow(bool json) { } if (!isnan(Energy->frequency[0])) { ResponseAppend_P(PSTR(",\"" D_JSON_FREQUENCY "\":%s"), - EnergyFormat(value_chr, Energy->frequency, Settings->flag2.frequency_resolution, Energy->frequency_common)); + EnergyFormat(value_chr, Energy->frequency, Settings->flag2.frequency_resolution, frequency_common)); } } if (Energy->voltage_available) { ResponseAppend_P(PSTR(",\"" D_JSON_VOLTAGE "\":%s"), - EnergyFormat(value_chr, Energy->voltage, Settings->flag2.voltage_resolution, Energy->voltage_common)); + EnergyFormat(value_chr, Energy->voltage, Settings->flag2.voltage_resolution, voltage_common)); } if (Energy->current_available) { ResponseAppend_P(PSTR(",\"" D_JSON_CURRENT "\":%s"), @@ -1397,7 +1400,7 @@ void EnergyShow(bool json) { // {s}
Head1Head2Head3{e} // {s}Head1Head2Head3Head4{e} WSContentSend_P(PSTR("

{t}{s}")); // First column is empty ({t} = , {s} = "), (no_label)?"":(label_o)?"O":"L", (no_label)?"":itoa(i +1, value_chr, 10)); @@ -1405,12 +1408,12 @@ void EnergyShow(bool json) { WSContentSend_P(PSTR(") #endif // USE_ENERGY_COLUMN_GUI if (Energy->voltage_available) { - WSContentSend_PD(HTTP_SNS_VOLTAGE, WebEnergyFormat(value_chr, Energy->voltage, Settings->flag2.voltage_resolution, Energy->voltage_common)); + WSContentSend_PD(HTTP_SNS_VOLTAGE, WebEnergyFormat(value_chr, Energy->voltage, Settings->flag2.voltage_resolution, voltage_common)); } if (!Energy->type_dc) { if (!isnan(Energy->frequency[0])) { WSContentSend_PD(PSTR("{s}" D_FREQUENCY "{m}%s " D_UNIT_HERTZ "{e}"), - WebEnergyFormat(value_chr, Energy->frequency, Settings->flag2.frequency_resolution, Energy->frequency_common)); + WebEnergyFormat(value_chr, Energy->frequency, Settings->flag2.frequency_resolution, frequency_common)); } } if (Energy->current_available) { diff --git a/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino b/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino index 62f36bbba..cb5007ffc 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino @@ -1416,7 +1416,10 @@ const char HTTP_ENERGY_SNS3[] PROGMEM = #endif // USE_WEBSERVER void EnergyShow(bool json) { - if (Energy->voltage_common) { + bool voltage_common = (Settings->flag6.no_voltage_common) ? false : Energy->voltage_common; + bool frequency_common = (Settings->flag6.no_voltage_common) ? false : Energy->frequency_common; + + if (voltage_common) { for (uint32_t i = 0; i < Energy->phase_count; i++) { Energy->voltage[i] = Energy->voltage[0]; } @@ -1549,12 +1552,12 @@ void EnergyShow(bool json) { } if (!isnan(Energy->frequency[0])) { ResponseAppend_P(PSTR(",\"" D_JSON_FREQUENCY "\":%s"), - EnergyFormat(value_chr, Energy->frequency, Settings->flag2.frequency_resolution, Energy->frequency_common)); + EnergyFormat(value_chr, Energy->frequency, Settings->flag2.frequency_resolution, frequency_common)); } } if (Energy->voltage_available) { ResponseAppend_P(PSTR(",\"" D_JSON_VOLTAGE "\":%s"), - EnergyFormat(value_chr, Energy->voltage, Settings->flag2.voltage_resolution, Energy->voltage_common)); + EnergyFormat(value_chr, Energy->voltage, Settings->flag2.voltage_resolution, voltage_common)); } if (Energy->current_available) { ResponseAppend_P(PSTR(",\"" D_JSON_CURRENT "\":%s"), @@ -1636,7 +1639,7 @@ void EnergyShow(bool json) { if (Energy->gui_count > Energy->Settings.gui_cols) { Energy->gui_count = Energy->Settings.gui_cols; } WSContentSend_P(PSTR("
) - bool label_o = Energy->voltage_common; + bool label_o = voltage_common; bool no_label = (1 == Energy->phase_count); for (uint32_t i = 0; i < Energy->phase_count; i++) { WSContentSend_P(PSTR("%s%s{e}")); // Last column is units ({e} =

")); // Close current table as we will use different column count - bool label_o = Energy->voltage_common; + bool label_o = voltage_common; if (ENERGY_DISPLAY_TABS == Energy->Settings.gui_display) { uint32_t tabs = (relay_show -1 + Energy->Settings.gui_cols) / Energy->Settings.gui_cols; if (tabs > 1) { @@ -1668,12 +1671,12 @@ void EnergyShow(bool json) { WSContentSend_P(PSTR("{e}")); // Last column is units ({e} = ) #endif // USE_ENERGY_COLUMN_GUI if (Energy->voltage_available) { - WSContentSend_PD(HTTP_SNS_VOLTAGE, WebEnergyFormat(value_chr, Energy->voltage, Settings->flag2.voltage_resolution, Energy->voltage_common)); + WSContentSend_PD(HTTP_SNS_VOLTAGE, WebEnergyFormat(value_chr, Energy->voltage, Settings->flag2.voltage_resolution, voltage_common)); } if (!Energy->type_dc) { if (!isnan(Energy->frequency[0])) { WSContentSend_PD(PSTR("{s}" D_FREQUENCY "{m}%s " D_UNIT_HERTZ "{e}"), - WebEnergyFormat(value_chr, Energy->frequency, Settings->flag2.frequency_resolution, Energy->frequency_common)); + WebEnergyFormat(value_chr, Energy->frequency, Settings->flag2.frequency_resolution, frequency_common)); } } if (Energy->current_available) { diff --git a/tools/decode-status.py b/tools/decode-status.py index 567d54d90..52ddfc257 100755 --- a/tools/decode-status.py +++ b/tools/decode-status.py @@ -205,7 +205,8 @@ a_setoption = [[ "(MQTT) Disable publish SSerialReceived MQTT messages, you must use event trigger rules instead", "(Light) start DMX ArtNet at boot, listen to UDP port as soon as network is up", "(Wifi) prefer IPv6 DNS resolution to IPv4 address when available. Requires `#define USE_IPV6`", - "","","","", + "(Energy) Force no voltage/frequency common", + "","","", "","","","", "","","","", "","","","", @@ -322,7 +323,7 @@ else: obj = json.load(fp) def StartDecode(): - print ("\n*** decode-status.py v12.3.1.2 by Theo Arends and Jacek Ziolkowski ***") + print ("\n*** decode-status.py v12.3.1.5 by Theo Arends and Jacek Ziolkowski ***") # print("Decoding\n{}".format(obj)) From bd07b05d40631d8425f3ca7fb06a5b3f24b6dcdf Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Tue, 31 Jan 2023 22:53:23 +0100 Subject: [PATCH 210/262] Berry add ``mdns`` advanced features and query (#17842) * Berry add ``mdns`` advanced features and query * typo --- CHANGELOG.md | 1 + .../berry_tasmota/src/be_mdns_module.cpp | 195 +++++++++++++++++- 2 files changed, 194 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 23ae173f8..db0e80491 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ All notable changes to this project will be documented in this file. - ESP32 command ``EnergyCols 1..8`` to change number of GUI columns - ESP32 command ``EnergyDisplay 1..3`` to change GUI column presentation - support for SEN5X gas and air quality sensor by Tyeth Gundry (#17736) +- Berry add ``mdns`` advanced features and query ### Breaking Changed - Berry energy_ctypes changed with new energy driver diff --git a/lib/libesp32/berry_tasmota/src/be_mdns_module.cpp b/lib/libesp32/berry_tasmota/src/be_mdns_module.cpp index 843090650..dad697ba0 100644 --- a/lib/libesp32/berry_tasmota/src/be_mdns_module.cpp +++ b/lib/libesp32/berry_tasmota/src/be_mdns_module.cpp @@ -12,6 +12,7 @@ #ifdef USE_DISCOVERY #include "mdns.h" #include +#include "IPAddress.h" // // `mdsn.start([hostname:string]) -> nil` @@ -52,7 +53,7 @@ static void m_mdns_set_hostname(struct bvm *vm, const char * hostname) { BE_FUNC_CTYPE_DECLARE(m_mdns_set_hostname, "", "@s") // -// `mdns.add_service(service:string, proto:string, port:int, txt:map) -> nil` +// `mdns.add_service(service:string, proto:string, port:int, txt:map [, instance:string, hostname:string]) -> nil` // // add a service declaration using the current hostname as instance name, and specify TXT fields as a `map` // @@ -66,6 +67,14 @@ static int32_t m_mdns_add_service(struct bvm *vm) { const char* service_type = be_tostring(vm, 1); const char* proto = be_tostring(vm, 2); uint16_t port = be_toint(vm, 3); + const char * instance = nullptr; + const char * hostname = nullptr; + if (top >= 5 && be_isstring(vm, 5)) { + instance = be_tostring(vm, 5); + } + if (top >= 6 && be_isstring(vm, 6)) { + hostname = be_tostring(vm, 6); + } mdns_txt_item_t * txt_items = NULL; int32_t txt_num = 0; @@ -98,7 +107,12 @@ static int32_t m_mdns_add_service(struct bvm *vm) { be_pop(vm, 1); /* pop iterator */ } } - esp_err_t err = mdns_service_add(NULL, service_type, proto, port, txt_items, txt_num); + esp_err_t err; + if (hostname == nullptr) { + err = mdns_service_add(instance, service_type, proto, port, txt_items, txt_num); + } else { + err = mdns_service_add_for_host(instance, service_type, proto, hostname, port, txt_items, txt_num); + } // free all allocated memory if (txt_items != NULL) { for (uint32_t i = 0; i < txt_num; i++) { @@ -115,12 +129,189 @@ static int32_t m_mdns_add_service(struct bvm *vm) { be_raise(vm, "value_error", "wrong or missing arguments"); } +// `mdns_service_subtype_add_for_host()` is only available in most recent esp-protocols version +// +// This alias makes sure that the compilation succeeds even if the function is not available +// +extern "C" esp_err_t __tasmota_mdns_service_subtype_add_for_host (const char *instance_name, const char *service_type, const char *proto, const char *hostname, const char *subtype) +{ return ESP_OK; } +extern "C" esp_err_t mdns_service_subtype_add_for_host(const char *instance_name, const char *service_type, const char *proto, const char *hostname, const char *subtype) __attribute__ ((weak, alias ("__tasmota_mdns_service_subtype_add_for_host"))); + +// +// `mdns.add_subtype(service:string, proto:string, instance:string, hostname:string, subtype:string) -> nil` +// +// add a subtype +// +static int32_t m_dns_add_subtype(struct bvm *vm) { + int32_t top = be_top(vm); + if (top >= 5 && be_isstring(vm, 1) && be_isstring(vm, 2) && be_isstring(vm, 3) && be_isstring(vm, 4) && be_isstring(vm, 5)) { + const char* service_type = be_tostring(vm, 1); + const char* proto = be_tostring(vm, 2); + const char* instance = be_tostring(vm, 3); + const char* hostname = be_tostring(vm, 4); + const char* subtype = be_tostring(vm, 5); + + esp_err_t err; + // Waiting for support of `mdns_service_subtype_add_for_host()` + err = mdns_service_subtype_add_for_host(instance, service_type, proto, hostname, subtype); + if (err != ESP_OK) { + be_raisef(vm, "internal_error", "mdns add_subtype err=%i", err); + } + be_return_nil(vm); + } + be_raise(vm, "value_error", "wrong or missing arguments"); +} + +// +// `mdns.add_hostname(hostname:string, ip:string [, ip:string]*) -> nil` +// +// add a delegate hostname +// +static int32_t m_dns_add_hostname(struct bvm *vm) { + int32_t top = be_top(vm); + if (top >= 2 && be_isstring(vm, 1) && be_isstring(vm, 2)) { + mdns_ip_addr_t * head = nullptr; // head of the linked list of addresses + esp_err_t err = ESP_OK; // return status + + const char* hostname = be_tostring(vm, 1); + const char* ip_text = nullptr; + ip_addr_t a; + for (uint16_t i = 2; i <= top; i++) { + const char* ip_text = be_tostring(vm, i); + if (ip_text == nullptr || ip_text[0] == 0) { continue; } // ignore empty string + IPAddress ip; + if (!ip.fromString(ip_text)) { err = -1; break; } + + // allocate new slot + mdns_ip_addr_t *new_head = (mdns_ip_addr_t*) be_os_malloc(sizeof(mdns_ip_addr_t)); + if (new_head == nullptr) { err = -2; break; } + new_head->next = head; + head = new_head; + + // + ip_addr_t *ip_addr = (ip_addr_t*) ip; + head->addr.type = ip_addr->type; + if (ip_addr->type == ESP_IPADDR_TYPE_V6) { + memcpy(head->addr.u_addr.ip6.addr, ip_addr->u_addr.ip6.addr, 16); + } else { + head->addr.u_addr.ip4.addr = ip_addr->u_addr.ip4.addr; + } + } while (0); + + if (err == ESP_OK && head != nullptr) { + err = mdns_delegate_hostname_add(hostname, head); + } + + // deallocate all memory + while (head != nullptr) { + mdns_ip_addr_t * next = head->next; + be_os_free(head); + head = next; + } + + if (err == -1) { + be_raisef(vm, "value_error", "Invalid IP Address '%s'", ip_text); + } else if (err == -2) { + be_raise(vm, "memory_error", nullptr); + } else if (err != ESP_OK) { + be_raisef(vm, "value_error", "mdns_delegate_hostname_add err=%i", err); + } + be_return_nil(vm); + + } + be_raise(vm, "value_error", "wrong or missing arguments"); +} + +// +// `mdns.find_service(service:string, proto:string [timeout_ms:int(3000), max_responses:int(20)]) -> map` +// +static int32_t m_dns_find_service(struct bvm *vm) { + static const char * ip_protocol_str[] = {"v4", "v6", "max"}; + int32_t top = be_top(vm); + if (top >= 2 && be_isstring(vm, 1) && be_isstring(vm, 2)) { + const char* service_name = be_tostring(vm, 1); + const char* proto = be_tostring(vm, 2); + int32_t timeout_ms = 3000; + if (top >= 3 && be_isint(vm, 3)) { + timeout_ms = be_toint(vm, 3); + } + int32_t max_responses = 20; + if (top >= 4 && be_isint(vm, 4)) { + max_responses = be_toint(vm, 4); + } + + mdns_result_t * results = NULL; + esp_err_t err = mdns_query_ptr(service_name, proto, timeout_ms, max_responses, &results); + if (err != ESP_OK) { be_raisef(vm, "value_error", "mdns_query_ptr err=%i", err); } + if (results == NULL) { be_return_nil(vm); } + + mdns_result_t * r = results; + mdns_ip_addr_t * a = NULL; + be_newobject(vm, "list"); + while (r) { + be_newobject(vm, "map"); + be_map_insert_str(vm, "type", ip_protocol_str[r->ip_protocol]); + if (r->instance_name) { be_map_insert_str(vm, "instance", r->instance_name); } + if (r->hostname) { be_map_insert_str(vm, "hostname", r->hostname); } + // TXT + be_pushstring(vm, "txt"); + be_newobject(vm, "map"); + for (int32_t t=0; t < r->txt_count; t++){ + be_map_insert_str(vm, r->txt[t].key, r->txt[t].value); + } + // + be_pop(vm, 1); + be_data_insert(vm, -3); + be_pop(vm, 2); + // + + // IP addresses + be_pushstring(vm, "ip"); + be_newobject(vm, "list"); + // + for (a = r->addr; a != NULL; a = a->next) { + ip_addr_t ip_addr; + if (a->addr.type == IPADDR_TYPE_V6) { + ip_addr_copy_from_ip6(ip_addr, a->addr.u_addr.ip6); + } else if (a->addr.type == IPADDR_TYPE_V4) { + ip_addr_copy_from_ip4(ip_addr, a->addr.u_addr.ip4); + } else { + continue; + } + be_pushstring(vm, IPAddress(ip_addr).toString().c_str()); + be_data_push(vm, -2); + be_pop(vm, 1); + } + // + be_pop(vm, 1); + be_data_insert(vm, -3); + be_pop(vm, 2); + + be_pop(vm, 1); + be_data_push(vm, -2); + be_pop(vm, 1); + + r = r->next; + } + be_pop(vm, 1); // now list is on top + + mdns_query_results_free(results); + be_return(vm); + } + be_raise(vm, "value_error", "wrong or missing arguments"); +} + /* @const_object_info_begin module mdns (scope: global) { start, ctype_func(m_mdns_start) stop, ctype_func(m_mdns_stop) set_hostname, ctype_func(m_mdns_set_hostname) add_service, func(m_mdns_add_service) + add_hostname, func(m_dns_add_hostname) + add_subtype, func(m_dns_add_subtype) + + // querying + find_service, func(m_dns_find_service) } @const_object_info_end */ #include "be_fixed_mdns.h" From 5ea9a95660cb94c4b1088e9520a6490625d8e175 Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Tue, 31 Jan 2023 23:23:36 +0100 Subject: [PATCH 211/262] Berry add `tasmota.locale()` (#17843) --- lib/libesp32/berry_tasmota/src/be_tasmota_lib.c | 2 ++ .../tasmota_xdrv_driver/xdrv_52_3_berry_tasmota.ino | 10 +++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/libesp32/berry_tasmota/src/be_tasmota_lib.c b/lib/libesp32/berry_tasmota/src/be_tasmota_lib.c index b3d7c540d..0f27586ab 100644 --- a/lib/libesp32/berry_tasmota/src/be_tasmota_lib.c +++ b/lib/libesp32/berry_tasmota/src/be_tasmota_lib.c @@ -35,6 +35,7 @@ extern int l_scaleuint(bvm *vm); extern int l_logInfo(bvm *vm); extern int l_save(bvm *vm); extern int t_random_byte(bvm *vm); +extern int l_locale(bvm *vm); extern int l_read_sensors(bvm *vm); @@ -109,6 +110,7 @@ class be_class_tasmota (scope: global, name: Tasmota) { scale_uint, func(l_scaleuint) log, func(l_logInfo) save, func(l_save) + locale, func(l_locale) read_sensors, func(l_read_sensors) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota.ino index 4ac0451d3..5bb9488bc 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota.ino @@ -157,8 +157,16 @@ extern "C" { } be_raise(vm, kTypeError, nullptr); } + + // Berry: tasmota.locale() -> string + // + int32_t l_locale(struct bvm *vm); + int32_t l_locale(struct bvm *vm) { + be_pushstring(vm, D_HTML_LANGUAGE); + be_return(vm); + } - // Berry: tasmota.time_reached(timer:int) -> bool + // Berry: tasmota.rtc() -> map // int32_t l_rtc(struct bvm *vm); int32_t l_rtc(struct bvm *vm) { From 293ae8064d753e6d38488b46d21cdc52a4a6e637 Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Tue, 31 Jan 2023 23:23:52 +0100 Subject: [PATCH 212/262] Berry webserver raw content (#17844) --- .../berry_tasmota/src/be_webserver_lib.c | 2 ++ .../xdrv_52_3_berry_webserver.ino | 29 +++++++++++++++++-- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/lib/libesp32/berry_tasmota/src/be_webserver_lib.c b/lib/libesp32/berry_tasmota/src/be_webserver_lib.c index 7f6d6f93a..ad7bcadd7 100644 --- a/lib/libesp32/berry_tasmota/src/be_webserver_lib.c +++ b/lib/libesp32/berry_tasmota/src/be_webserver_lib.c @@ -16,6 +16,7 @@ extern int w_webserver_state(bvm *vm); extern int w_webserver_check_privileged_access(bvm *vm); extern int w_webserver_redirect(bvm *vm); extern int w_webserver_content_start(bvm *vm); +extern int w_webserver_content_open(bvm *vm); extern int w_webserver_content_send(bvm *vm); extern int w_webserver_content_response(bvm *vm); extern int w_webserver_content_send_style(bvm *vm); @@ -42,6 +43,7 @@ module webserver (scope: global) { content_response, func(w_webserver_content_response) content_send_style, func(w_webserver_content_send_style) content_flush, func(w_webserver_content_flush) + content_open, func(w_webserver_content_open) content_start, func(w_webserver_content_start) content_stop, func(w_webserver_content_stop) content_button, func(w_webserver_content_button) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_webserver.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_webserver.ino index dd4e8384e..599548ac4 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_webserver.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_webserver.ino @@ -144,7 +144,7 @@ extern "C" { be_raise(vm, kTypeError, nullptr); } - // Berry: `webserver.content_start() -> nil` + // Berry: `webserver.content_start(title:string) -> nil` // int32_t w_webserver_content_start(struct bvm *vm); int32_t w_webserver_content_start(struct bvm *vm) { @@ -157,13 +157,36 @@ extern "C" { be_raise(vm, kTypeError, nullptr); } + // Berry: `webserver.content_open(http_code:int, mimetype:string) -> nil` + // + int32_t w_webserver_content_open(struct bvm *vm); + int32_t w_webserver_content_open(struct bvm *vm) { + int32_t argc = be_top(vm); // Get the number of arguments + if (argc >= 2 && be_isint(vm, 1) && be_isstring(vm, 2)) { + int32_t httpcode = be_toint(vm, 1); + const char * mimetype = be_tostring(vm, 2); + Webserver->client().flush(); + WSHeaderSend(); + Webserver->setContentLength(CONTENT_LENGTH_UNKNOWN); + Webserver->send(httpcode, mimetype, ""); + Web.chunk_buffer = ""; + be_return_nil(vm); + } + be_raise(vm, kTypeError, nullptr); + } + // Berry: `webserver.content_send(string) -> nil` // int32_t w_webserver_content_send(struct bvm *vm); int32_t w_webserver_content_send(struct bvm *vm) { int32_t argc = be_top(vm); // Get the number of arguments - if (argc >= 1 && be_isstring(vm, 1)) { - const char * html = be_tostring(vm, 1); + if (argc >= 1 && (be_isstring(vm, 1) || be_iscomptr(vm, 1))) { + const char * html; + if (be_isstring(vm, 1)) { + html = be_tostring(vm, 1); + } else { + html = (const char*) be_tocomptr(vm, 1); + } WSContentSend_P(PSTR("%s"), html); be_return_nil(vm); } From 052b5c29263df66ac238d2a9ac7e6c75c9e6b54f Mon Sep 17 00:00:00 2001 From: David Gwynne Date: Wed, 1 Feb 2023 20:48:07 +1000 Subject: [PATCH 213/262] reset recv parser if it takes too long for the message to arrive. (#17845) i have a tuyamcu based device that occasionally gets a flipped bit in messages it receives from the muc. those usually show up as checksum failures, but if the bit flips in the length field then we wait for bytes that just arent going to arrive, so we don't get to the cksum field for that test to fail. instead, add a timeout that the tick checks, and reset the recv state machine on a timeout. if the message that was corrupted was a dp update, we'll end up with an inconsistent view of the state of the DPs. maybe we should send a request for all datapoint values when this or a cksum failure happens? --- tasmota/tasmota_xdrv_driver/xdrv_65_tuyamcubr.ino | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_65_tuyamcubr.ino b/tasmota/tasmota_xdrv_driver/xdrv_65_tuyamcubr.ino index e6b471750..d5d4b0ac8 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_65_tuyamcubr.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_65_tuyamcubr.ino @@ -380,6 +380,7 @@ tuyamcubr_parse(struct tuyamcubr_softc *sc, uint8_t byte) if (byte != TUYAMCUBR_H_TWO) return (TUYAMCUBR_P_START); + p->p_deadline = sc->sc_clock + (10 * 1000); nstate = TUYAMCUBR_P_VERSION; break; case TUYAMCUBR_P_VERSION: @@ -889,6 +890,16 @@ tuyamcubr_tick(struct tuyamcubr_softc *sc, unsigned int ms) sc->sc_clock += ms; + if (sc->sc_parser.p_state >= TUYAMCUBR_P_VERSION) { + /* parser timeout only starts after the header */ + diff = sc->sc_clock - sc->sc_parser.p_deadline; + if (diff > 0) { + AddLog(LOG_LEVEL_ERROR, + TUYAMCUBR_FMT("recv timeout")); + sc->sc_parser.p_state = TUYAMCUBR_P_START; + } + } + diff = sc->sc_clock - sc->sc_deadline; if (diff < 0) { /* deadline hasn't been reached, nothing to do */ From 1147304781c63c9001176cde4b56cffc0257ddc3 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Wed, 1 Feb 2023 12:09:55 +0100 Subject: [PATCH 214/262] Fix second voltage channel if SO150 set --- tasmota/tasmota_xnrg_energy/xnrg_14_bl09xx.ino | 2 ++ tasmota/tasmota_xnrg_energy/xnrg_19_cse7761.ino | 2 ++ 2 files changed, 4 insertions(+) diff --git a/tasmota/tasmota_xnrg_energy/xnrg_14_bl09xx.ino b/tasmota/tasmota_xnrg_energy/xnrg_14_bl09xx.ino index a1dc34e32..2e3a15cda 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_14_bl09xx.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_14_bl09xx.ino @@ -189,6 +189,7 @@ bool Bl09XXDecode42(void) { void Bl09XXUpdateEnergy() { if (Energy->power_on) { // Powered on Energy->voltage[0] = (float)Bl09XX.voltage / EnergyGetCalibration(ENERGY_VOLTAGE_CALIBRATION); + Energy->voltage[1] = Energy->voltage[0]; #ifdef DEBUG_BL09XX AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("BL9: U %2_f, T %2_f"), &Energy->voltage[0], &Bl09XX.temperature); #endif @@ -208,6 +209,7 @@ void Bl09XXUpdateEnergy() { } } else { // Powered off Energy->voltage[0] = 0; + Energy->voltage[1] = 0; Energy->active_power[0] = Energy->active_power[1] = 0; Energy->current[0] = Energy->current[1] = 0; } diff --git a/tasmota/tasmota_xnrg_energy/xnrg_19_cse7761.ino b/tasmota/tasmota_xnrg_energy/xnrg_19_cse7761.ino index 17ad3ad7f..b176065df 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_19_cse7761.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_19_cse7761.ino @@ -462,8 +462,10 @@ void Cse7761GetData(void) { // Voltage = RmsU * RmsUC * 10 / 0x400000 // Energy->voltage[0] = (float)(((uint64_t)CSE7761Data.voltage_rms * CSE7761Data.coefficient[RmsUC] * 10) >> 22) / 1000; // V Energy->voltage[0] = ((float)CSE7761Data.voltage_rms / EnergyGetCalibration(ENERGY_VOLTAGE_CALIBRATION)); // V + Energy->voltage[1] = Energy->voltage[0]; #ifdef CSE7761_FREQUENCY Energy->frequency[0] = (CSE7761Data.frequency) ? ((float)EnergyGetCalibration(ENERGY_FREQUENCY_CALIBRATION) / 8 / CSE7761Data.frequency) : 0; // Hz + Energy->frequency[1] = Energy->frequency[0]; #endif for (uint32_t channel = 0; channel < 2; channel++) { From 949f3fdc32e8b02bcc7f22d5e94aa64f83840883 Mon Sep 17 00:00:00 2001 From: Barbudor Date: Wed, 1 Feb 2023 21:40:04 +0100 Subject: [PATCH 215/262] enfore TLS for sml decryption (#17852) --- tasmota/include/tasmota_configurations.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tasmota/include/tasmota_configurations.h b/tasmota/include/tasmota_configurations.h index bc572e890..5eecd5436 100644 --- a/tasmota/include/tasmota_configurations.h +++ b/tasmota/include/tasmota_configurations.h @@ -1073,7 +1073,13 @@ #ifdef USE_SCRIPT #define USE_UNISHOX_COMPRESSION // Add support for string compression +#if defined(USE_SML_M) && !defined(NO_USE_SML_DECRYPT) +#ifndef USE_TLS // Add support for TLS as requires by SML decryption +#define USE_TLS #endif +#endif +#endif + #ifdef USE_ZIGBEE #define USE_UNISHOX_COMPRESSION // Add support for string compression #endif From 813233906b490742e925a448a0304eaac6179346 Mon Sep 17 00:00:00 2001 From: Norbert <48217146+Noschvie@users.noreply.github.com> Date: Thu, 2 Feb 2023 08:57:01 +0100 Subject: [PATCH 216/262] Fix spelling (#17853) --- tasmota/include/tasmota_configurations.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasmota/include/tasmota_configurations.h b/tasmota/include/tasmota_configurations.h index 5eecd5436..f29eb254c 100644 --- a/tasmota/include/tasmota_configurations.h +++ b/tasmota/include/tasmota_configurations.h @@ -1074,7 +1074,7 @@ #ifdef USE_SCRIPT #define USE_UNISHOX_COMPRESSION // Add support for string compression #if defined(USE_SML_M) && !defined(NO_USE_SML_DECRYPT) -#ifndef USE_TLS // Add support for TLS as requires by SML decryption +#ifndef USE_TLS // Add support for TLS as required by SML decryption #define USE_TLS #endif #endif From 2c9f1fef0d5f2ea7260aae9fc8c89e6510294017 Mon Sep 17 00:00:00 2001 From: Fabrizio Amodio <32312585+ZioFabry@users.noreply.github.com> Date: Thu, 2 Feb 2023 19:09:24 +0100 Subject: [PATCH 217/262] Biopdu-v1.1.0 (#17857) * BioPDU language labels * xnrg_33 BioPDU 625x12 driver * missing enums * Rename energy driver from 33 to 24 * Removed driver 33 --- .../include/tasmota_configurations_ESP32.h | 1 + tasmota/include/tasmota_template.h | 8 + tasmota/language/af_AF.h | 3 + tasmota/language/bg_BG.h | 3 + tasmota/language/ca_AD.h | 3 + tasmota/language/cs_CZ.h | 3 + tasmota/language/de_DE.h | 3 + tasmota/language/el_GR.h | 3 + tasmota/language/en_GB.h | 3 + tasmota/language/es_ES.h | 3 + tasmota/language/fr_FR.h | 3 + tasmota/language/fy_NL.h | 3 + tasmota/language/he_HE.h | 3 + tasmota/language/hu_HU.h | 6 + tasmota/language/it_IT.h | 3 + tasmota/language/ko_KO.h | 3 + tasmota/language/nl_NL.h | 3 + tasmota/language/pl_PL.h | 3 + tasmota/language/pt_BR.h | 3 + tasmota/language/pt_PT.h | 3 + tasmota/language/ro_RO.h | 3 + tasmota/language/ru_RU.h | 3 + tasmota/language/sk_SK.h | 3 + tasmota/language/sv_SE.h | 3 + tasmota/language/tr_TR.h | 3 + tasmota/language/uk_UA.h | 3 + tasmota/language/vi_VN.h | 3 + tasmota/language/zh_CN.h | 3 + tasmota/language/zh_TW.h | 3 + .../tasmota_xnrg_energy/xnrg_24_biopdu.ino | 292 ++++++++++++++++++ tools/lv_gpio/lv_gpio_enum.h | 3 + 31 files changed, 388 insertions(+) create mode 100644 tasmota/tasmota_xnrg_energy/xnrg_24_biopdu.ino diff --git a/tasmota/include/tasmota_configurations_ESP32.h b/tasmota/include/tasmota_configurations_ESP32.h index 673c70d49..495d41652 100644 --- a/tasmota/include/tasmota_configurations_ESP32.h +++ b/tasmota/include/tasmota_configurations_ESP32.h @@ -711,6 +711,7 @@ #define USE_WE517 // Add support for Orno WE517-Modbus energy monitor (+1k code) #define USE_SONOFF_SPM // Add support for ESP32 based Sonoff Smart Stackable Power Meter (+11k code) #define USE_MODBUS_ENERGY // Add support for generic modbus energy monitor using a user file in rule space (+5k code) +//#define USE_BIOPDU // Add support for BioPDU 625x12 6-channel energy monitor #define USE_DHT // Add support for DHT11, AM2301 (DHT21, DHT22, AM2302, AM2321) and SI7021 Temperature and Humidity sensor #define USE_MAX31855 // Add support for MAX31855 K-Type thermocouple sensor using softSPI diff --git a/tasmota/include/tasmota_template.h b/tasmota/include/tasmota_template.h index ecd43e1d1..5dc854d01 100644 --- a/tasmota/include/tasmota_template.h +++ b/tasmota/include/tasmota_template.h @@ -205,6 +205,7 @@ enum UserSelectablePins { GPIO_MBR_TX_ENA, GPIO_NRG_MBS_TX_ENA, // Modbus Bridge Serial Transmit Enable GPIO_ME007_TRIG, GPIO_ME007_RX, // ME007 Serial/Trigger interface GPIO_TUYAMCUBR_TX, GPIO_TUYAMCUBR_RX, // TuyaMCU Bridge + GPIO_BIOPDU_PZEM0XX_TX, GPIO_BIOPDU_PZEM016_RX, GPIO_BIOPDU_BIT, // Biomine BioPDU 625x12 GPIO_SENSOR_END }; // Error as warning to rethink GPIO usage with max 2045 @@ -457,6 +458,7 @@ const char kSensorNames[] PROGMEM = D_SENSOR_MBR_TX_ENA "|" D_SENSOR_NRG_MBS_TX_ENA "|" D_SENSOR_ME007_TRIG "|" D_SENSOR_ME007_RX "|" D_SENSOR_TUYAMCUBR_TX "|" D_SENSOR_TUYAMCUBR_RX "|" + D_SENSOR_BIOPDU_PZEM0XX_TX "|" D_SENSOR_BIOPDU_PZEM016_RX "|" D_SENSOR_BIOPDU_BIT "|" ; const char kSensorNamesFixed[] PROGMEM = @@ -1138,6 +1140,12 @@ const uint16_t kGpioNiceList[] PROGMEM = { AGPIO(GPIO_ADC_JOY) + MAX_ADCS, // Joystick AGPIO(GPIO_ADC_PH) + MAX_ADCS, // Analog PH Sensor AGPIO(GPIO_ADC_MQ) + MAX_ADCS, // Analog MQ Sensor + +#ifdef USE_BIOPDU + AGPIO(GPIO_BIOPDU_PZEM0XX_TX), // Biomine BioPDU pins + AGPIO(GPIO_BIOPDU_PZEM016_RX), + AGPIO(GPIO_BIOPDU_BIT) + 3, +#endif #endif // ESP32 }; diff --git a/tasmota/language/af_AF.h b/tasmota/language/af_AF.h index 7d1c464f1..91898f7a7 100644 --- a/tasmota/language/af_AF.h +++ b/tasmota/language/af_AF.h @@ -919,6 +919,9 @@ #define D_SENSOR_ME007_RX "ME007 Rx" #define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" #define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" +#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" +#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" +#define D_SENSOR_BIOPDU_BIT "BioPDU Bit" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/bg_BG.h b/tasmota/language/bg_BG.h index dfb0a19f2..db2b69eac 100644 --- a/tasmota/language/bg_BG.h +++ b/tasmota/language/bg_BG.h @@ -919,6 +919,9 @@ #define D_SENSOR_ME007_RX "ME007 Rx" #define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" #define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" +#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" +#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" +#define D_SENSOR_BIOPDU_BIT "BioPDU Bit" // Units #define D_UNIT_AMPERE "А" diff --git a/tasmota/language/ca_AD.h b/tasmota/language/ca_AD.h index 3a3fca3fd..754f4dee3 100644 --- a/tasmota/language/ca_AD.h +++ b/tasmota/language/ca_AD.h @@ -919,6 +919,9 @@ #define D_SENSOR_ME007_RX "ME007 Rx" #define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" #define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" +#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" +#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" +#define D_SENSOR_BIOPDU_BIT "BioPDU Bit" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/cs_CZ.h b/tasmota/language/cs_CZ.h index 3aa103e51..8fe0507c7 100644 --- a/tasmota/language/cs_CZ.h +++ b/tasmota/language/cs_CZ.h @@ -919,6 +919,9 @@ #define D_SENSOR_ME007_RX "ME007 Rx" #define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" #define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" +#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" +#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" +#define D_SENSOR_BIOPDU_BIT "BioPDU Bit" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/de_DE.h b/tasmota/language/de_DE.h index ed4d18686..83b685742 100644 --- a/tasmota/language/de_DE.h +++ b/tasmota/language/de_DE.h @@ -919,6 +919,9 @@ #define D_SENSOR_ME007_RX "ME007 Rx" #define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" #define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" +#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" +#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" +#define D_SENSOR_BIOPDU_BIT "BioPDU Bit" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/el_GR.h b/tasmota/language/el_GR.h index 9b885d832..3c5ed60c6 100644 --- a/tasmota/language/el_GR.h +++ b/tasmota/language/el_GR.h @@ -919,6 +919,9 @@ #define D_SENSOR_ME007_RX "ME007 Rx" #define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" #define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" +#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" +#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" +#define D_SENSOR_BIOPDU_BIT "BioPDU Bit" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/en_GB.h b/tasmota/language/en_GB.h index 8bcdab91d..8071fe613 100644 --- a/tasmota/language/en_GB.h +++ b/tasmota/language/en_GB.h @@ -919,6 +919,9 @@ #define D_SENSOR_ME007_RX "ME007 Rx" #define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" #define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" +#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" +#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" +#define D_SENSOR_BIOPDU_BIT "BioPDU Bit" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/es_ES.h b/tasmota/language/es_ES.h index d5b64734e..9f6f5b351 100644 --- a/tasmota/language/es_ES.h +++ b/tasmota/language/es_ES.h @@ -919,6 +919,9 @@ #define D_SENSOR_ME007_RX "ME007 Rx" #define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" #define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" +#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" +#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" +#define D_SENSOR_BIOPDU_BIT "BioPDU Bit" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/fr_FR.h b/tasmota/language/fr_FR.h index c1d2b1c72..1657e5fdb 100644 --- a/tasmota/language/fr_FR.h +++ b/tasmota/language/fr_FR.h @@ -919,6 +919,9 @@ #define D_SENSOR_ME007_RX "ME007 Rx" #define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" #define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" +#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" +#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" +#define D_SENSOR_BIOPDU_BIT "BioPDU Bit" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/fy_NL.h b/tasmota/language/fy_NL.h index cc4329c89..a3d15372c 100644 --- a/tasmota/language/fy_NL.h +++ b/tasmota/language/fy_NL.h @@ -919,6 +919,9 @@ #define D_SENSOR_ME007_RX "ME007 Rx" #define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" #define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" +#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" +#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" +#define D_SENSOR_BIOPDU_BIT "BioPDU Bit" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/he_HE.h b/tasmota/language/he_HE.h index de30f6352..670c7d0df 100644 --- a/tasmota/language/he_HE.h +++ b/tasmota/language/he_HE.h @@ -919,6 +919,9 @@ #define D_SENSOR_ME007_RX "ME007 Rx" #define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" #define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" +#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" +#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" +#define D_SENSOR_BIOPDU_BIT "BioPDU Bit" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/hu_HU.h b/tasmota/language/hu_HU.h index 00da79687..f2c6d03fe 100644 --- a/tasmota/language/hu_HU.h +++ b/tasmota/language/hu_HU.h @@ -919,6 +919,12 @@ #define D_SENSOR_ME007_RX "ME007 Rx" #define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" #define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" +#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" +#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" +#define D_SENSOR_BIOPDU_BIT "BioPDU Bit" +#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" +#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" +#define D_SENSOR_BIOPDU_BIT "BioPDU Bit" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/it_IT.h b/tasmota/language/it_IT.h index a7b12b8de..fc7f1ccc6 100644 --- a/tasmota/language/it_IT.h +++ b/tasmota/language/it_IT.h @@ -919,6 +919,9 @@ #define D_SENSOR_ME007_RX "ME007 - RX" #define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr - TX" #define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr - RX" +#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" +#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" +#define D_SENSOR_BIOPDU_BIT "BioPDU Bit" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/ko_KO.h b/tasmota/language/ko_KO.h index dcd06089e..9047b95c5 100644 --- a/tasmota/language/ko_KO.h +++ b/tasmota/language/ko_KO.h @@ -919,6 +919,9 @@ #define D_SENSOR_ME007_RX "ME007 Rx" #define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" #define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" +#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" +#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" +#define D_SENSOR_BIOPDU_BIT "BioPDU Bit" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/nl_NL.h b/tasmota/language/nl_NL.h index ea9130f0f..69bead33e 100644 --- a/tasmota/language/nl_NL.h +++ b/tasmota/language/nl_NL.h @@ -919,6 +919,9 @@ #define D_SENSOR_ME007_RX "ME007 Rx" #define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" #define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" +#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" +#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" +#define D_SENSOR_BIOPDU_BIT "BioPDU Bit" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/pl_PL.h b/tasmota/language/pl_PL.h index 7906633aa..c8f2cd71c 100644 --- a/tasmota/language/pl_PL.h +++ b/tasmota/language/pl_PL.h @@ -919,6 +919,9 @@ #define D_SENSOR_ME007_RX "ME007 Rx" #define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" #define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" +#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" +#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" +#define D_SENSOR_BIOPDU_BIT "BioPDU Bit" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/pt_BR.h b/tasmota/language/pt_BR.h index c7ee07fe3..7152da31d 100644 --- a/tasmota/language/pt_BR.h +++ b/tasmota/language/pt_BR.h @@ -919,6 +919,9 @@ #define D_SENSOR_ME007_RX "ME007 Rx" #define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" #define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" +#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" +#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" +#define D_SENSOR_BIOPDU_BIT "BioPDU Bit" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/pt_PT.h b/tasmota/language/pt_PT.h index 74ae4e72e..df69b7c1c 100644 --- a/tasmota/language/pt_PT.h +++ b/tasmota/language/pt_PT.h @@ -919,6 +919,9 @@ #define D_SENSOR_ME007_RX "ME007 Rx" #define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" #define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" +#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" +#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" +#define D_SENSOR_BIOPDU_BIT "BioPDU Bit" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/ro_RO.h b/tasmota/language/ro_RO.h index 1e2f6f992..b7427a821 100644 --- a/tasmota/language/ro_RO.h +++ b/tasmota/language/ro_RO.h @@ -919,6 +919,9 @@ #define D_SENSOR_ME007_RX "ME007 Rx" #define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" #define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" +#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" +#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" +#define D_SENSOR_BIOPDU_BIT "BioPDU Bit" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/ru_RU.h b/tasmota/language/ru_RU.h index 893693054..02e0851dc 100644 --- a/tasmota/language/ru_RU.h +++ b/tasmota/language/ru_RU.h @@ -919,6 +919,9 @@ #define D_SENSOR_ME007_RX "ME007 Rx" #define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" #define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" +#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" +#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" +#define D_SENSOR_BIOPDU_BIT "BioPDU Bit" // Units #define D_UNIT_AMPERE "А" diff --git a/tasmota/language/sk_SK.h b/tasmota/language/sk_SK.h index 9ede0cf21..79212a44a 100644 --- a/tasmota/language/sk_SK.h +++ b/tasmota/language/sk_SK.h @@ -919,6 +919,9 @@ #define D_SENSOR_ME007_RX "ME007 Rx" #define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" #define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" +#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" +#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" +#define D_SENSOR_BIOPDU_BIT "BioPDU Bit" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/sv_SE.h b/tasmota/language/sv_SE.h index 1145c3f2c..2bc09f434 100644 --- a/tasmota/language/sv_SE.h +++ b/tasmota/language/sv_SE.h @@ -919,6 +919,9 @@ #define D_SENSOR_ME007_RX "ME007 Rx" #define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" #define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" +#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" +#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" +#define D_SENSOR_BIOPDU_BIT "BioPDU Bit" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/tr_TR.h b/tasmota/language/tr_TR.h index b43eaf75c..2b4b962f5 100644 --- a/tasmota/language/tr_TR.h +++ b/tasmota/language/tr_TR.h @@ -919,6 +919,9 @@ #define D_SENSOR_ME007_RX "ME007 Rx" #define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" #define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" +#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" +#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" +#define D_SENSOR_BIOPDU_BIT "BioPDU Bit" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/uk_UA.h b/tasmota/language/uk_UA.h index 1c72ce490..a45664b64 100644 --- a/tasmota/language/uk_UA.h +++ b/tasmota/language/uk_UA.h @@ -919,6 +919,9 @@ #define D_SENSOR_ME007_RX "ME007 Rx" #define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" #define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" +#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" +#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" +#define D_SENSOR_BIOPDU_BIT "BioPDU Bit" // Units #define D_UNIT_AMPERE "А" diff --git a/tasmota/language/vi_VN.h b/tasmota/language/vi_VN.h index 1ca96fd17..2c85c22e1 100644 --- a/tasmota/language/vi_VN.h +++ b/tasmota/language/vi_VN.h @@ -919,6 +919,9 @@ #define D_SENSOR_ME007_RX "ME007 Rx" #define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" #define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" +#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" +#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" +#define D_SENSOR_BIOPDU_BIT "BioPDU Bit" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/zh_CN.h b/tasmota/language/zh_CN.h index 5690e5018..7baa2711d 100644 --- a/tasmota/language/zh_CN.h +++ b/tasmota/language/zh_CN.h @@ -919,6 +919,9 @@ #define D_SENSOR_ME007_RX "ME007 Rx" #define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" #define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" +#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" +#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" +#define D_SENSOR_BIOPDU_BIT "BioPDU Bit" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/zh_TW.h b/tasmota/language/zh_TW.h index 9f9e1959a..77de2a6f0 100644 --- a/tasmota/language/zh_TW.h +++ b/tasmota/language/zh_TW.h @@ -919,6 +919,9 @@ #define D_SENSOR_ME007_RX "ME007 Rx" #define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" #define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr Rx" +#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" +#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" +#define D_SENSOR_BIOPDU_BIT "BioPDU Bit" // Units #define D_UNIT_AMPERE "安培" diff --git a/tasmota/tasmota_xnrg_energy/xnrg_24_biopdu.ino b/tasmota/tasmota_xnrg_energy/xnrg_24_biopdu.ino new file mode 100644 index 000000000..816f6569a --- /dev/null +++ b/tasmota/tasmota_xnrg_energy/xnrg_24_biopdu.ino @@ -0,0 +1,292 @@ +/* + xnrg_24_biopdu.ino - BioPDU-625x12 (based on xnrg_05_pzem_ac.ino) + Biomine 625x12 Custom Board + 6 x Independent PZEM-004V3 Modbus AC energy sensor + 3bit serial switch + Integrated MCP23008 + + Template {"NAME":"Olimex ESP32-PoE-BioPDU","GPIO":[1,10081,10082,1,10016,1,0,0,5536,640,1,1,608,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,1,10080,1,1,10048,0,0,1],"FLAG":0,"BASE":1} + + Copyright (C) 2021 Theo Arends + Copyright (C) 2022-2023 Fabrizio Amodio + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#if defined(USE_ENERGY_SENSOR_ESP32) && defined(USE_I2C) +#ifdef USE_BIOPDU + +#define XNRG_24 24 + +#undef ENERGY_MAX_PHASES +#define ENERGY_MAX_PHASES 6 // BioPDU support max six phases/channels + +#undef ENERGY_GUI_MAX_COLS +#define ENERGY_GUI_MAX_COLS 6 // [EnergyCols] Number of GUI data columns - Preffered 6 + +#undef ENERGY_GUI_DISPLAY_MODE +#define ENERGY_GUI_DISPLAY_MODE ENERGY_DISPLAY_TABS // [EnergyDisplay] 1 = Rotate if over EnergyCols, 2 = Rotate only powered on if over EnergyCols, 3 = Use tabs if over EnergyCols + +const uint8_t BIOPDU_DEVICE_ADDRESS = 0x01; // PZEM default address +const uint32_t BIOPDU_STABILIZE = 30; // Number of seconds to stabilize configuration + +#include +TasmotaModbus *BioPduModbus; + +struct BIOPDU +{ + float energy = 0; + float last_energy = 0; + uint8_t send_retry = 0; + uint8_t phase = 0; + uint8_t address = 0; + uint8_t address_step = ADDR_IDLE; + uint8_t pins = 0; + uint8_t current_mux = 99; +} BioPdu; + +void BioPduSetPins(uint8_t current) +{ + if (BioPdu.current_mux != current) + { + for (uint8_t p = 0; p < BioPdu.pins; p++) + { + digitalWrite(Pin(GPIO_BIOPDU_BIT, p), (current + 1) & (1 << p) ? 1 : 0); + } + BioPdu.current_mux = current; + } +} + +void BioPduEverySecond(void) +{ + static uint32_t lastms = 0; + + if (millis() >= lastms + 1000) + { + lastms = millis(); + EnergyUpdateTotal(); + } +} + +void BioPduEvery250ms(void) +{ + bool data_ready = BioPduModbus->ReceiveReady(); + + if (data_ready) + { + uint8_t buffer[30]; // At least 5 + (2 * 10) = 25 + + uint8_t registers = 10; + if (ADDR_RECEIVE == BioPdu.address_step) + { + registers = 2; // Need 1 byte extra as response is F8 06 00 02 00 01 FD A3 + BioPdu.address_step--; + } + uint8_t error = BioPduModbus->ReceiveBuffer(buffer, registers); + AddLogBuffer(LOG_LEVEL_DEBUG_MORE, buffer, BioPduModbus->ReceiveCount()); + + if (error) + { + AddLog(LOG_LEVEL_DEBUG, PSTR("PDU: phase %d error %d"), BioPdu.phase, error); + } + else + { + Energy->data_valid[BioPdu.phase] = 0; + if (10 == registers) + { + + // 0 1 2 3 4 5 6 7 8 9 = ModBus register + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 = Buffer index + // Id Cc Sz Volt- Current---- Power------ Energy----- Frequ PFact Alarm Crc-- + // 01 04 14 08 D1 00 6C 00 00 00 F4 00 00 00 26 00 00 01 F4 00 64 00 00 51 34 + // 01 04 14 08 CE 00 22 00 00 00 00 00 00 00 02 00 00 01 F4 00 00 00 00 33 FE + Energy->voltage[BioPdu.phase] = (float)((buffer[3] << 8) + buffer[4]) / 10.0f; // 6553.0 V + Energy->current[BioPdu.phase] = (float)((buffer[7] << 24) + (buffer[8] << 16) + (buffer[5] << 8) + buffer[6]) / 1000.0f; // 4294967.000 A + Energy->active_power[BioPdu.phase] = (float)((buffer[11] << 24) + (buffer[12] << 16) + (buffer[9] << 8) + buffer[10]) / 10.0f; // 429496729.0 W + Energy->frequency[BioPdu.phase] = (float)((buffer[17] << 8) + buffer[18]) / 10.0f; // 50.0 Hz + Energy->power_factor[BioPdu.phase] = (float)((buffer[19] << 8) + buffer[20]) / 100.0f; // 1.00 + Energy->import_active[BioPdu.phase] = (float)((buffer[15] << 24) + (buffer[16] << 16) + (buffer[13] << 8) + buffer[14]) / 1000.0f; // 4294967.295 kWh + + // AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("PDU: ph=%d v=%2_f c=%4_f ap=%2_f f=%2_f pf=%3_f ia=%4_f"), + // BioPdu.phase, + // &Energy->voltage[BioPdu.phase], + // &Energy->current[BioPdu.phase], + // &Energy->active_power[BioPdu.phase], + // &Energy->frequency[BioPdu.phase], + // &Energy->power_factor[BioPdu.phase], + // &Energy->import_active[BioPdu.phase] + // ); + } + } + } + + // AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("PDU: ph=%d st=%d dr=%d sr=%d"), BioPdu.phase, BioPdu.address_step, data_ready, BioPdu.send_retry); + + if (0 == BioPdu.send_retry || data_ready) + { + if (ADDR_SEND == BioPdu.address_step) + { + BioPduModbus->Send(0xF8, 0x06, 0x0002, (uint16_t)BioPdu.address); + BioPdu.address_step--; + } + else + { + uint8_t gpio = MCP230xx_readGPIO(0); + + BioPdu.send_retry = 1 /*ENERGY_WATCHDOG*/; + for (uint8_t p = 0; p < Energy->phase_count; p++) + { + if (++BioPdu.phase == Energy->phase_count) + { + BioPdu.phase = 0; + } + + if ((gpio >> (BioPdu.phase + 1)) & 1) + { + BioPduSetPins(BioPdu.phase); + + delay(1); + + uint8_t res = BioPduModbus->Send(BIOPDU_DEVICE_ADDRESS /*+ BioPdu.phase*/, 0x04, 0, 10); + if (res != 0) + { + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("PDU: phase %d modbus_error="), BioPdu.phase, res); + } + break; + } + else + { + // AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("PDU: phase %d not read"), BioPdu.phase); + } + } + } + } + else + { + BioPdu.send_retry--; + if ((Energy->phase_count > 1) && (0 == BioPdu.send_retry) && (TasmotaGlobal.uptime < BIOPDU_STABILIZE)) + { + // Energy->phase_count--; // Decrement phases if no response after retry within 30 seconds after restart + // if (TasmotaGlobal.discovery_counter) + // { + // TasmotaGlobal.discovery_counter += ENERGY_WATCHDOG + 1; // Don't send Discovery yet, delay by 4s + 1s + // } + } + } +} + +void BioPduSnsInit(void) +{ + BioPduModbus = new TasmotaModbus(Pin(GPIO_BIOPDU_PZEM016_RX), Pin(GPIO_BIOPDU_PZEM0XX_TX)); + uint8_t result = BioPduModbus->Begin(9600); + if (result) + { + if (2 == result) + { + ClaimSerial(); + } + BioPdu.phase = Energy->phase_count - 1; + } + else + { + TasmotaGlobal.energy_driver = ENERGY_NONE; + } +} + +void BioPduDrvInit(void) +{ + if (PinUsed(GPIO_BIOPDU_PZEM016_RX) && PinUsed(GPIO_BIOPDU_PZEM0XX_TX) && PinUsed(GPIO_BIOPDU_BIT)) + { + TasmotaGlobal.energy_driver = XNRG_24; + + Energy->voltage_common = false; + Energy->frequency_common = false; + + AddLog(LOG_LEVEL_DEBUG, PSTR("PDU: checking pins")); + + for (uint8_t p = 0; p < 3; p++) + { + if (PinUsed(GPIO_BIOPDU_BIT, p)) + { + pinMode(Pin(GPIO_BIOPDU_BIT, p), OUTPUT); + digitalWrite(Pin(GPIO_BIOPDU_BIT, p), 0); + + AddLog(LOG_LEVEL_DEBUG, PSTR("PDU: Add GPIO %d/%d for pin %d"), GPIO_BIOPDU_BIT, p, BioPdu.pins); + + BioPdu.pins++; + } + else + { + break; + } + } + + Energy->phase_count = std::min((uint8_t)(pow(2, BioPdu.pins) - 1), (uint8_t)ENERGY_MAX_PHASES); // Start off with 6 phases + + AddLog(LOG_LEVEL_DEBUG, PSTR("PDU: number of pins=%d, max_phase=%d"), BioPdu.pins, Energy->phase_count); + } +} + +bool BioPduCommand(void) +{ + bool serviced = true; + + if (CMND_MODULEADDRESS == Energy->command_code) + { + BioPdu.address = XdrvMailbox.payload; // Valid addresses are 1, 2 and 3 + BioPdu.address_step = ADDR_SEND; + } + else + serviced = false; // Unknown command + + return serviced; +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xnrg24(uint32_t function) +{ + bool result = false; + + switch (function) + { + case FUNC_EVERY_250_MSECOND: + if (TasmotaGlobal.uptime > 4) + { + BioPduEvery250ms(); + } // Fix start up issue #5875 + break; + case FUNC_ENERGY_EVERY_SECOND: + if (TasmotaGlobal.uptime > BIOPDU_STABILIZE) + { + BioPduEverySecond(); + } + break; + case FUNC_COMMAND: + result = BioPduCommand(); + break; + case FUNC_INIT: + BioPduSnsInit(); + break; + case FUNC_PRE_INIT: + BioPduDrvInit(); + break; + } + return result; +} + +#endif // USE_BIOPDU +#endif // USE_ENERGY_SENSOR diff --git a/tools/lv_gpio/lv_gpio_enum.h b/tools/lv_gpio/lv_gpio_enum.h index 70b297099..cfb7bdb92 100644 --- a/tools/lv_gpio/lv_gpio_enum.h +++ b/tools/lv_gpio/lv_gpio_enum.h @@ -329,5 +329,8 @@ ADE7953_RST = GPIO_ADE7953_RST NRG_MBS_TX = GPIO_NRG_MBS_TX NRG_MBS_RX = GPIO_NRG_MBS_RX ADE7953_CS = GPIO_ADE7953_CS +BIOPDU_PZEM0XX_TX = GPIO_BIOPDU_PZEM0XX_TX +BIOPDU_PZEM016_RX = GPIO_BIOPDU_PZEM016_RX +BIOPDU_BIT = GPIO_BIOPDU_BIT SENSOR_END = GPIO_SENSOR_END From 96b66225d2055b22aee6f70c03be0947b5ead118 Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Thu, 2 Feb 2023 20:22:59 +0100 Subject: [PATCH 218/262] Reserve `SetOption151` for Matter protocol (#17860) --- tasmota/include/tasmota_types.h | 2 +- tasmota/tasmota_support/support_command.ino | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/tasmota/include/tasmota_types.h b/tasmota/include/tasmota_types.h index 2e672f088..bbb4fddbc 100644 --- a/tasmota/include/tasmota_types.h +++ b/tasmota/include/tasmota_types.h @@ -184,7 +184,7 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu uint32_t artnet_autorun : 1; // bit 2 (v12.2.0.4) - SetOption148 - (Light) start DMX ArtNet at boot, listen to UDP port as soon as network is up uint32_t dns_ipv6_priority : 1; // bit 3 (v12.2.0.6) - SetOption149 - (Wifi) prefer IPv6 DNS resolution to IPv4 address when available. Requires `#define USE_IPV6` uint32_t no_voltage_common : 1; // bit 4 (v12.3.1.5) - SetOption150 - (Energy) Force no voltage/frequency common - uint32_t spare05 : 1; // bit 5 + uint32_t matter_enabled : 1; // bit 5 (v12.3.1.5) - SetOption151 - (Matter) Enable Matter protocol over Wifi uint32_t spare06 : 1; // bit 6 uint32_t spare07 : 1; // bit 7 uint32_t spare08 : 1; // bit 8 diff --git a/tasmota/tasmota_support/support_command.ino b/tasmota/tasmota_support/support_command.ino index ff3bcb891..4709fc309 100644 --- a/tasmota/tasmota_support/support_command.ino +++ b/tasmota/tasmota_support/support_command.ino @@ -1449,6 +1449,11 @@ void CmndSetoptionBase(bool indexed) { } else if (6 == ptype) { // SetOption146 .. 177 bitWrite(Settings->flag6.data, pindex, XdrvMailbox.payload); + switch (pindex) { + case 5: // SetOption151 - Matter enabled + TasmotaGlobal.restart_flag = 2; + break; + } } } else { ptype = 99; // Command Error From de81eecc016292737f1b0e0a2b07bb7a796e4032 Mon Sep 17 00:00:00 2001 From: Norbert <48217146+Noschvie@users.noreply.github.com> Date: Fri, 3 Feb 2023 10:50:53 +0100 Subject: [PATCH 219/262] Change log option for "decrypted block" (#17863) --- tasmota/tasmota_xsns_sensor/xsns_53_sml.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino b/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino index 698fc02ca..71e8e1696 100755 --- a/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino @@ -625,7 +625,7 @@ void dump2log(void) { logsiz = mp->sbsiz; } memmove(mp->sbuff, payload, logsiz); - AddLog(LOG_LEVEL_INFO, PSTR("decrypted block: %d bytes"), logsiz); + AddLog(LOG_LEVEL_DEBUG, PSTR("SML: decrypted block: %d bytes"), logsiz); uint16_t index = 0; while (logsiz) { sml_dump_start('>'); @@ -1192,7 +1192,7 @@ void sml_shift_in(uint32_t meters, uint32_t shard) { len = mp->sbsiz; } memmove(mp->sbuff, payload, len); - AddLog(LOG_LEVEL_INFO, PSTR(">> decrypted block: %d bytes"), len); + AddLog(LOG_LEVEL_DEBUG, PSTR("SML: decrypted block: %d bytes"), len); SML_Decode(meters); } } From e8056df1ad43994a6c1c6477a47753b106e2b021 Mon Sep 17 00:00:00 2001 From: Fabrizio Amodio <32312585+ZioFabry@users.noreply.github.com> Date: Fri, 3 Feb 2023 17:52:26 +0100 Subject: [PATCH 220/262] Biopdu-v1.1.1 (#17868) * Template Fix * Removed common setting, use SetOption150 instead * code cleaning * BioPDU Factory Settings * CHANGELOG update * RELEASENOTES update --- CHANGELOG.md | 1 + RELEASENOTES.md | 1 + .../tasmota_xnrg_energy/xnrg_24_biopdu.ino | 66 +++++++++++-------- 3 files changed, 40 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index db0e80491..99b4e482f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ All notable changes to this project will be documented in this file. - ESP32 command ``EnergyDisplay 1..3`` to change GUI column presentation - support for SEN5X gas and air quality sensor by Tyeth Gundry (#17736) - Berry add ``mdns`` advanced features and query +- ESP32 support for Biomine BioPDU 625x12 (#17857) ### Breaking Changed - Berry energy_ctypes changed with new energy driver diff --git a/RELEASENOTES.md b/RELEASENOTES.md index d9421ff0b..5f2183fd9 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -127,6 +127,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm - ESP32 command ``EnergyDisplay 1..3`` to change GUI column presentation - ESP32 support for eigth energy phases/channels - ESP32 support for BMPxxx sensors on two I2C busses [#17643](https://github.com/arendst/Tasmota/issues/17643) +- ESP32 support for Biomine BioPDU 625x12 [#17857](https://github.com/arendst/Tasmota/issues/17857) ### Breaking Changed diff --git a/tasmota/tasmota_xnrg_energy/xnrg_24_biopdu.ino b/tasmota/tasmota_xnrg_energy/xnrg_24_biopdu.ino index 816f6569a..e4413f814 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_24_biopdu.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_24_biopdu.ino @@ -1,11 +1,12 @@ /* xnrg_24_biopdu.ino - BioPDU-625x12 (based on xnrg_05_pzem_ac.ino) Biomine 625x12 Custom Board + 6 x 25A Relays 6 x Independent PZEM-004V3 Modbus AC energy sensor 3bit serial switch Integrated MCP23008 - Template {"NAME":"Olimex ESP32-PoE-BioPDU","GPIO":[1,10081,10082,1,10016,1,0,0,5536,640,1,1,608,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,1,10080,1,1,10048,0,0,1],"FLAG":0,"BASE":1} + Template {"NAME":"Olimex ESP32-PoE-BioPDU","GPIO":[1,10209,10210,1,10144,1,0,0,5536,640,1,1,608,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,1,10208,1,1,10176,0,0,1],"FLAG":0,"BASE":1} Copyright (C) 2021 Theo Arends Copyright (C) 2022-2023 Fabrizio Amodio @@ -27,6 +28,42 @@ #if defined(USE_ENERGY_SENSOR_ESP32) && defined(USE_I2C) #ifdef USE_BIOPDU +/* + BioPDU 625x12 Factory Settings: + + Template {"NAME":"Olimex ESP32-PoE-BioPDU","GPIO":[1,10209,10210,1,10144,1,0,0,5536,640,1,1,608,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,1,10208,1,1,10176,0,0,1],"FLAG":0,"BASE":1} + Module 0 + EthType 0 + EthAddress 0 + EthClockMode 3 + SetOption26 1 + SetOption129 1 + SetOption150 1 + EnergyDisplay 1 + EnergyCols 6 + i2cscan + Sensor29 0,1,0 + Sensor29 1,5,2 + Sensor29 2,5,2 + Sensor29 3,5,2 + Sensor29 4,5,2 + Sensor29 5,5,2 + Sensor29 6,5,2 + Sensor29 7,1,0 + + compile with build flags: + + ${env:tasmota32.build_flags} + USE_ETHERNET + ETH_TYPE=0 + ETH_ADDRESS=0 + ETH_CLKMODE=3 + USE_MCP230xx + USE_MCP230xx_ADDR=0x20 + USE_MCP230xx_OUTPUT + USE_BIOPDU +*/ + #define XNRG_24 24 #undef ENERGY_MAX_PHASES @@ -117,22 +154,10 @@ void BioPduEvery250ms(void) Energy->frequency[BioPdu.phase] = (float)((buffer[17] << 8) + buffer[18]) / 10.0f; // 50.0 Hz Energy->power_factor[BioPdu.phase] = (float)((buffer[19] << 8) + buffer[20]) / 100.0f; // 1.00 Energy->import_active[BioPdu.phase] = (float)((buffer[15] << 24) + (buffer[16] << 16) + (buffer[13] << 8) + buffer[14]) / 1000.0f; // 4294967.295 kWh - - // AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("PDU: ph=%d v=%2_f c=%4_f ap=%2_f f=%2_f pf=%3_f ia=%4_f"), - // BioPdu.phase, - // &Energy->voltage[BioPdu.phase], - // &Energy->current[BioPdu.phase], - // &Energy->active_power[BioPdu.phase], - // &Energy->frequency[BioPdu.phase], - // &Energy->power_factor[BioPdu.phase], - // &Energy->import_active[BioPdu.phase] - // ); } } } - // AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("PDU: ph=%d st=%d dr=%d sr=%d"), BioPdu.phase, BioPdu.address_step, data_ready, BioPdu.send_retry); - if (0 == BioPdu.send_retry || data_ready) { if (ADDR_SEND == BioPdu.address_step) @@ -165,24 +190,12 @@ void BioPduEvery250ms(void) } break; } - else - { - // AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("PDU: phase %d not read"), BioPdu.phase); - } } } } else { BioPdu.send_retry--; - if ((Energy->phase_count > 1) && (0 == BioPdu.send_retry) && (TasmotaGlobal.uptime < BIOPDU_STABILIZE)) - { - // Energy->phase_count--; // Decrement phases if no response after retry within 30 seconds after restart - // if (TasmotaGlobal.discovery_counter) - // { - // TasmotaGlobal.discovery_counter += ENERGY_WATCHDOG + 1; // Don't send Discovery yet, delay by 4s + 1s - // } - } } } @@ -210,9 +223,6 @@ void BioPduDrvInit(void) { TasmotaGlobal.energy_driver = XNRG_24; - Energy->voltage_common = false; - Energy->frequency_common = false; - AddLog(LOG_LEVEL_DEBUG, PSTR("PDU: checking pins")); for (uint8_t p = 0; p < 3; p++) From a483991ba350a83587caa17efa0d46be2f69f9a5 Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Sat, 4 Feb 2023 00:00:21 +0100 Subject: [PATCH 221/262] ESP32 preliminary support for Matter protocol, milestone 1 (commissioning) (#17871) * ESP32 preliminary support for Matter protocol, milestone 1 (commissioning) * Fix case --- CHANGELOG.md | 1 + lib/libesp32/berry/default/be_modtab.c | 6 + .../generate/Matter_generate_c.be | 121 + .../berry_matter/generate/be_matter_certs.h | 351 + .../generate/be_matter_clusters.h | 1572 ++++ .../berry_matter/generate/be_matter_opcodes.h | 29 + .../berry_matter/generate/matter_clusters.be | 7425 +++++++++++++++++ lib/libesp32/berry_matter/library.json | 17 + lib/libesp32/berry_matter/path.be | 2 + lib/libesp32/berry_matter/solidify_all.be | 86 + .../berry_matter/src/be_matter_counter.cpp | 266 + .../berry_matter/src/be_matter_module.c | 270 + .../src/be_matter_qrcode_min_js.h | 45 + .../berry_matter/src/be_matter_verhoeff.cpp | 105 + lib/libesp32/berry_matter/src/berry_tasmota.h | 8 + .../src/embedded/Matter_Base38.be | 71 + .../src/embedded/Matter_Commissioning.be | 632 ++ .../src/embedded/Matter_Commissioning_Data.be | 317 + .../src/embedded/Matter_Device.be | 508 ++ .../berry_matter/src/embedded/Matter_IM.be | 326 + .../src/embedded/Matter_IM_Data.be | 946 +++ .../src/embedded/Matter_Message.be | 407 + .../src/embedded/Matter_MessageHandler.be | 171 + .../src/embedded/Matter_Module.be | 46 + .../src/embedded/Matter_Plugin.be | 88 + .../src/embedded/Matter_Plugin_Relay.be | 52 + .../src/embedded/Matter_Plugin_core.be | 372 + .../src/embedded/Matter_Session.be | 574 ++ .../berry_matter/src/embedded/Matter_TLV.be | 874 ++ .../src/embedded/Matter_UDPServer.be | 187 + .../berry_matter/src/embedded/Matter_UI.be | 259 + .../src/embedded/Matter_inspect.be | 64 + .../berry_matter/src/embedded/matter.be | 4 + lib/libesp32/berry_matter/src/solidify/.keep | 0 .../src/solidify/solidified_Matter_Base38.h | 154 + .../solidified_Matter_Commissioning.h | 2430 ++++++ .../solidified_Matter_Commissioning_Data.h | 970 +++ .../src/solidify/solidified_Matter_Device.h | 2136 +++++ .../src/solidify/solidified_Matter_IM.h | 1274 +++ .../src/solidify/solidified_Matter_IM_Data.h | 4020 +++++++++ .../src/solidify/solidified_Matter_Message.h | 1227 +++ .../solidified_Matter_MessageHandler.h | 582 ++ .../src/solidify/solidified_Matter_Module.h | 90 + .../src/solidify/solidified_Matter_Plugin.h | 272 + .../solidify/solidified_Matter_Plugin_Relay.h | 118 + .../solidify/solidified_Matter_Plugin_core.h | 1053 +++ .../src/solidify/solidified_Matter_Session.h | 2239 +++++ .../src/solidify/solidified_Matter_TLV.h | 2909 +++++++ .../solidify/solidified_Matter_UDPServer.h | 626 ++ .../src/solidify/solidified_Matter_UI.h | 893 ++ .../src/solidify/solidified_Matter_inspect.h | 189 + .../src/solidify/solidified_matter.h | 7 + lib/libesp32/berry_tasmota/solidify_all.be | 5 +- .../src/embedded/autoconf_module.be | 2 +- pio-tools/gen-berry-structures.py | 2 +- .../xdrv_52_7_berry_embedded.ino | 5 + .../tasmota_xdrv_driver/xdrv_52_9_berry.ino | 3 + 57 files changed, 37404 insertions(+), 4 deletions(-) create mode 100644 lib/libesp32/berry_matter/generate/Matter_generate_c.be create mode 100644 lib/libesp32/berry_matter/generate/be_matter_certs.h create mode 100644 lib/libesp32/berry_matter/generate/be_matter_clusters.h create mode 100644 lib/libesp32/berry_matter/generate/be_matter_opcodes.h create mode 100644 lib/libesp32/berry_matter/generate/matter_clusters.be create mode 100644 lib/libesp32/berry_matter/library.json create mode 100644 lib/libesp32/berry_matter/path.be create mode 100755 lib/libesp32/berry_matter/solidify_all.be create mode 100644 lib/libesp32/berry_matter/src/be_matter_counter.cpp create mode 100644 lib/libesp32/berry_matter/src/be_matter_module.c create mode 100644 lib/libesp32/berry_matter/src/be_matter_qrcode_min_js.h create mode 100644 lib/libesp32/berry_matter/src/be_matter_verhoeff.cpp create mode 100644 lib/libesp32/berry_matter/src/berry_tasmota.h create mode 100644 lib/libesp32/berry_matter/src/embedded/Matter_Base38.be create mode 100644 lib/libesp32/berry_matter/src/embedded/Matter_Commissioning.be create mode 100644 lib/libesp32/berry_matter/src/embedded/Matter_Commissioning_Data.be create mode 100644 lib/libesp32/berry_matter/src/embedded/Matter_Device.be create mode 100644 lib/libesp32/berry_matter/src/embedded/Matter_IM.be create mode 100644 lib/libesp32/berry_matter/src/embedded/Matter_IM_Data.be create mode 100644 lib/libesp32/berry_matter/src/embedded/Matter_Message.be create mode 100644 lib/libesp32/berry_matter/src/embedded/Matter_MessageHandler.be create mode 100644 lib/libesp32/berry_matter/src/embedded/Matter_Module.be create mode 100644 lib/libesp32/berry_matter/src/embedded/Matter_Plugin.be create mode 100644 lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Relay.be create mode 100644 lib/libesp32/berry_matter/src/embedded/Matter_Plugin_core.be create mode 100644 lib/libesp32/berry_matter/src/embedded/Matter_Session.be create mode 100644 lib/libesp32/berry_matter/src/embedded/Matter_TLV.be create mode 100644 lib/libesp32/berry_matter/src/embedded/Matter_UDPServer.be create mode 100644 lib/libesp32/berry_matter/src/embedded/Matter_UI.be create mode 100644 lib/libesp32/berry_matter/src/embedded/Matter_inspect.be create mode 100644 lib/libesp32/berry_matter/src/embedded/matter.be create mode 100644 lib/libesp32/berry_matter/src/solidify/.keep create mode 100644 lib/libesp32/berry_matter/src/solidify/solidified_Matter_Base38.h create mode 100644 lib/libesp32/berry_matter/src/solidify/solidified_Matter_Commissioning.h create mode 100644 lib/libesp32/berry_matter/src/solidify/solidified_Matter_Commissioning_Data.h create mode 100644 lib/libesp32/berry_matter/src/solidify/solidified_Matter_Device.h create mode 100644 lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM.h create mode 100644 lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM_Data.h create mode 100644 lib/libesp32/berry_matter/src/solidify/solidified_Matter_Message.h create mode 100644 lib/libesp32/berry_matter/src/solidify/solidified_Matter_MessageHandler.h create mode 100644 lib/libesp32/berry_matter/src/solidify/solidified_Matter_Module.h create mode 100644 lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin.h create mode 100644 lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Relay.h create mode 100644 lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_core.h create mode 100644 lib/libesp32/berry_matter/src/solidify/solidified_Matter_Session.h create mode 100644 lib/libesp32/berry_matter/src/solidify/solidified_Matter_TLV.h create mode 100644 lib/libesp32/berry_matter/src/solidify/solidified_Matter_UDPServer.h create mode 100644 lib/libesp32/berry_matter/src/solidify/solidified_Matter_UI.h create mode 100644 lib/libesp32/berry_matter/src/solidify/solidified_Matter_inspect.h create mode 100644 lib/libesp32/berry_matter/src/solidify/solidified_matter.h diff --git a/CHANGELOG.md b/CHANGELOG.md index 99b4e482f..3377495c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ All notable changes to this project will be documented in this file. - support for SEN5X gas and air quality sensor by Tyeth Gundry (#17736) - Berry add ``mdns`` advanced features and query - ESP32 support for Biomine BioPDU 625x12 (#17857) +- ESP32 preliminary support for Matter protocol, milestone 1 (commissioning) ### Breaking Changed - Berry energy_ctypes changed with new energy driver diff --git a/lib/libesp32/berry/default/be_modtab.c b/lib/libesp32/berry/default/be_modtab.c index ad1844d0a..e95c65ba2 100644 --- a/lib/libesp32/berry/default/be_modtab.c +++ b/lib/libesp32/berry/default/be_modtab.c @@ -65,6 +65,9 @@ be_extern_native_module(lv_tasmota); be_extern_native_module(haspmota); #endif // USE_LVGL_HASPMOTA #endif // USE_LVGL +#ifdef USE_MATTER_DEVICE +be_extern_native_module(matter); +#endif // USE_MATTER_DEVICE /* user-defined modules declare start */ @@ -175,6 +178,9 @@ BERRY_LOCAL const bntvmodule* const be_module_table[] = { #ifdef USE_DISCOVERY &be_native_module(mdns), #endif // USE_DISCOVERY +#ifdef USE_MATTER_DEVICE + &be_native_module(matter), +#endif // USE_MATTER_DEVICE #endif // TASMOTA /* user-defined modules register end */ NULL /* do not remove */ diff --git a/lib/libesp32/berry_matter/generate/Matter_generate_c.be b/lib/libesp32/berry_matter/generate/Matter_generate_c.be new file mode 100644 index 000000000..6c9c13170 --- /dev/null +++ b/lib/libesp32/berry_matter/generate/Matter_generate_c.be @@ -0,0 +1,121 @@ +# ../../berry/berry -s -g Matter_generate_c.be +# +# generate C headers + +import matter_clusters +var c = matter_clusters + + +################################################################################# +# Simple insertion sort - sorts the list in place, and returns the list +################################################################################# +def sort(l) for i:1..size(l)-1 var k = l[i] var j = i while (j > 0) && (l[j-1] > k) l[j] = l[j-1] j -= 1 end l[j] = k end return l end + +# keys to llist +def k2l(m) var r=[] for k:m.keys() r.push(k) end return sort(r) end + +var cl_keys = {} +for cl:c + for k:cl.keys() + cl_keys[k] = true + end +end + +var attr_ids = {} +var attr_keys = {} +var attr_types = {} +for cl:c + for attr:cl['attributes'] + attr_ids[attr['attributeId']] = true + for k:attr.keys() + attr_keys[k] = true + end + attr_types[attr['type']] = true + end +end + +import string + +# prepare file +f=open("be_matter_clusters.h", "w") +def fprint(*l) + f.write(l.concat(" ")) + f.write("\n") +end + +# fprint("Cluster keys:",k2l(cl_keys)) +# fprint("Attribute ids:",k2l(attr_ids)) +# fprint("Attribute keys:",k2l(attr_keys)) +# fprint("Attribute types:",k2l(attr_types)) + +var cl_id_name = {} +for cl:c + cl_id_name[cl['clusterId']] = cl['clusterName'] +end +var cl_ids = k2l(cl_id_name) + +fprint("/*********************************************************************************\\") +fprint("* Compact form for attributes and clusters") +fprint("*") +fprint("* Generated content, do not edit") +fprint("\\*********************************************************************************/") +fprint() +fprint("typedef struct {") +fprint(" uint16_t id;") +fprint(" uint8_t type;") +fprint(" uint8_t flags;") +fprint(" const char* name;") +fprint("} matter_attribute_t;") +fprint() +fprint("typedef struct {") +fprint(" uint16_t id;") +fprint(" const char* name;") +fprint("} matter_command_t;") +fprint() +fprint("typedef struct {") +fprint(" uint16_t id;") +fprint(" const char* name;") +fprint(" const matter_attribute_t* attributes;") +fprint(" const matter_command_t* commands;") +fprint("} matter_cluster_t;") +fprint() +for cl:cl_ids + fprint(string.format("const matter_attribute_t matter_Attributes_%04X[] = {", cl)) + var attributes = c[cl_id_name[cl]]['attributes'] + var attr_id_name = {} + for attr:attributes + attr_id_name[attr['attributeId']] = attr['attributeName'] + end + var attr_ids_local = k2l(attr_id_name) + + for attr_id:attr_ids_local + fprint(string.format(' { 0x%04X, %i, 0x%02X, "%s" },', attr_id, 0, 0, attributes[attr_id]['attributeName'])) + end + fprint(' { 0xFFFF, 0, 0x00, NULL },') + fprint("};") + fprint() + # commands + fprint(string.format("const matter_command_t matter_Commands_%04X[] = {", cl)) + var commands = c[cl_id_name[cl]]['commands'] + var cmd_id_name = {} + for cmd:commands + cmd_id_name[cmd['commandId']] = cmd['commandName'] + end + var cmd_ids_local = k2l(cmd_id_name) + + for cmd_id:cmd_ids_local + fprint(string.format(' { 0x%04X, "%s" },', cmd_id, commands[cmd_id]['commandName'])) + end + fprint(' { 0xFFFF, NULL },') + fprint("};") + fprint() +end + +fprint("const matter_cluster_t matterAllClusters[] = {") +for cl:cl_ids + fprint(string.format(' { 0x%04X, "%s", matter_Attributes_%04X, matter_Commands_%04X },', cl, cl_id_name[cl], cl, cl)) +end + fprint(' { 0xFFFF, NULL, NULL },') +fprint("};") + +f.close() diff --git a/lib/libesp32/berry_matter/generate/be_matter_certs.h b/lib/libesp32/berry_matter/generate/be_matter_certs.h new file mode 100644 index 000000000..e3205013b --- /dev/null +++ b/lib/libesp32/berry_matter/generate/be_matter_certs.h @@ -0,0 +1,351 @@ +// Certificates and credentials from demo + +#include +#include + +const uint8_t kDevelopmentPAI_Cert_FFF1[463] = { + 0x30, 0x82, 0x01, 0xcb, 0x30, 0x82, 0x01, 0x71, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x56, 0xad, 0x82, 0x22, 0xad, 0x94, + 0x5b, 0x64, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x30, 0x31, 0x18, 0x30, 0x16, 0x06, + 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0f, 0x4d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x50, 0x41, 0x41, + 0x31, 0x14, 0x30, 0x12, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xa2, 0x7c, 0x02, 0x01, 0x0c, 0x04, 0x46, 0x46, 0x46, + 0x31, 0x30, 0x20, 0x17, 0x0d, 0x32, 0x32, 0x30, 0x32, 0x30, 0x35, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x39, + 0x39, 0x39, 0x39, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x3d, 0x31, 0x25, 0x30, 0x23, 0x06, + 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1c, 0x4d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x20, 0x44, 0x65, 0x76, 0x20, 0x50, 0x41, 0x49, 0x20, + 0x30, 0x78, 0x46, 0x46, 0x46, 0x31, 0x20, 0x6e, 0x6f, 0x20, 0x50, 0x49, 0x44, 0x31, 0x14, 0x30, 0x12, 0x06, 0x0a, 0x2b, 0x06, + 0x01, 0x04, 0x01, 0x82, 0xa2, 0x7c, 0x02, 0x01, 0x0c, 0x04, 0x46, 0x46, 0x46, 0x31, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, + 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x41, + 0x9a, 0x93, 0x15, 0xc2, 0x17, 0x3e, 0x0c, 0x8c, 0x87, 0x6d, 0x03, 0xcc, 0xfc, 0x94, 0x48, 0x52, 0x64, 0x7f, 0x7f, 0xec, 0x5e, + 0x50, 0x82, 0xf4, 0x05, 0x99, 0x28, 0xec, 0xa8, 0x94, 0xc5, 0x94, 0x15, 0x13, 0x09, 0xac, 0x63, 0x1e, 0x4c, 0xb0, 0x33, 0x92, + 0xaf, 0x68, 0x4b, 0x0b, 0xaf, 0xb7, 0xe6, 0x5b, 0x3b, 0x81, 0x62, 0xc2, 0xf5, 0x2b, 0xf9, 0x31, 0xb8, 0xe7, 0x7a, 0xaa, 0x82, + 0xa3, 0x66, 0x30, 0x64, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, + 0x02, 0x01, 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x1d, + 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x63, 0x54, 0x0e, 0x47, 0xf6, 0x4b, 0x1c, 0x38, 0xd1, 0x38, 0x84, 0xa4, + 0x62, 0xd1, 0x6c, 0x19, 0x5d, 0x8f, 0xfb, 0x3c, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, + 0x6a, 0xfd, 0x22, 0x77, 0x1f, 0x51, 0x1f, 0xec, 0xbf, 0x16, 0x41, 0x97, 0x67, 0x10, 0xdc, 0xdc, 0x31, 0xa1, 0x71, 0x7e, 0x30, + 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x48, 0x00, 0x30, 0x45, 0x02, 0x21, 0x00, 0xb2, 0xef, + 0x27, 0xf4, 0x9a, 0xe9, 0xb5, 0x0f, 0xb9, 0x1e, 0xea, 0xc9, 0x4c, 0x4d, 0x0b, 0xdb, 0xb8, 0xd7, 0x92, 0x9c, 0x6c, 0xb8, 0x8f, + 0xac, 0xe5, 0x29, 0x36, 0x8d, 0x12, 0x05, 0x4c, 0x0c, 0x02, 0x20, 0x65, 0x5d, 0xc9, 0x2b, 0x86, 0xbd, 0x90, 0x98, 0x82, 0xa6, + 0xc6, 0x21, 0x77, 0xb8, 0x25, 0xd7, 0xd0, 0x5e, 0xdb, 0xe7, 0xc2, 0x2f, 0x9f, 0xea, 0x71, 0x22, 0x0e, 0x7e, 0xa7, 0x03, 0xf8, + 0x91, +}; + +const uint8_t kDevelopmentPAI_PublicKey_FFF1[65] = { + 0x04, 0x41, 0x9a, 0x93, 0x15, 0xc2, 0x17, 0x3e, 0x0c, 0x8c, 0x87, 0x6d, 0x03, 0xcc, 0xfc, 0x94, 0x48, + 0x52, 0x64, 0x7f, 0x7f, 0xec, 0x5e, 0x50, 0x82, 0xf4, 0x05, 0x99, 0x28, 0xec, 0xa8, 0x94, 0xc5, 0x94, + 0x15, 0x13, 0x09, 0xac, 0x63, 0x1e, 0x4c, 0xb0, 0x33, 0x92, 0xaf, 0x68, 0x4b, 0x0b, 0xaf, 0xb7, 0xe6, + 0x5b, 0x3b, 0x81, 0x62, 0xc2, 0xf5, 0x2b, 0xf9, 0x31, 0xb8, 0xe7, 0x7a, 0xaa, 0x82, +}; +const uint8_t kDevelopmentPAI_PrivateKey_FFF1[32] = { + 0xc1, 0xab, 0x5f, 0xe2, 0x84, 0xb4, 0xc1, 0x89, 0x40, 0xa5, 0x31, 0x61, 0xf8, 0x06, 0x94, 0x40, + 0x50, 0xa1, 0x69, 0x7b, 0x71, 0x76, 0x1d, 0x38, 0x53, 0x37, 0xa8, 0xa3, 0xcd, 0x09, 0x5c, 0x34, +}; + +/* +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 56:ad:82:22:ad:94:5b:64 + Signature Algorithm: ecdsa-with-SHA256 + Issuer: CN = Matter Test PAA, 1.3.6.1.4.1.37244.2.1 = FFF1 + Validity + Not Before: Feb 5 00:00:00 2022 GMT + Not After : Dec 31 23:59:59 9999 GMT + Subject: CN = Matter Dev PAI 0xFFF1 no PID, 1.3.6.1.4.1.37244.2.1 = FFF1 + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:41:9a:93:15:c2:17:3e:0c:8c:87:6d:03:cc:fc: + 94:48:52:64:7f:7f:ec:5e:50:82:f4:05:99:28:ec: + a8:94:c5:94:15:13:09:ac:63:1e:4c:b0:33:92:af: + 68:4b:0b:af:b7:e6:5b:3b:81:62:c2:f5:2b:f9:31: + b8:e7:7a:aa:82 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE, pathlen:0 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + 63:54:0E:47:F6:4B:1C:38:D1:38:84:A4:62:D1:6C:19:5D:8F:FB:3C + X509v3 Authority Key Identifier: + keyid:6A:FD:22:77:1F:51:1F:EC:BF:16:41:97:67:10:DC:DC:31:A1:71:7E + + Signature Algorithm: ecdsa-with-SHA256 + 30:45:02:21:00:b2:ef:27:f4:9a:e9:b5:0f:b9:1e:ea:c9:4c: + 4d:0b:db:b8:d7:92:9c:6c:b8:8f:ac:e5:29:36:8d:12:05:4c: + 0c:02:20:65:5d:c9:2b:86:bd:90:98:82:a6:c6:21:77:b8:25: + d7:d0:5e:db:e7:c2:2f:9f:ea:71:22:0e:7e:a7:03:f8:91 +*/ + +/* +ASN.1 + +SEQUENCE (3 elem) + SEQUENCE (8 elem) + [0] (1 elem) + INTEGER 2 + INTEGER (63 bit) 6245791343685426020 + SEQUENCE (1 elem) + OBJECT IDENTIFIER 1.2.840.10045.4.3.2 ecdsaWithSHA256 (ANSI X9.62 ECDSA algorithm with SHA256) + SEQUENCE (2 elem) + SET (1 elem) + SEQUENCE (2 elem) + OBJECT IDENTIFIER 2.5.4.3 commonName (X.520 DN component) + UTF8String Matter Test PAA + SET (1 elem) + SEQUENCE (2 elem) + OBJECT IDENTIFIER 1.3.6.1.4.1.37244.2.1 + UTF8String FFF1 + SEQUENCE (2 elem) + UTCTime 2022-02-05 00:00:00 UTC + GeneralizedTime 9999-12-31 23:59:59 UTC + SEQUENCE (2 elem) + SET (1 elem) + SEQUENCE (2 elem) + OBJECT IDENTIFIER 2.5.4.3 commonName (X.520 DN component) + UTF8String Matter Dev PAI 0xFFF1 no PID + SET (1 elem) + SEQUENCE (2 elem) + OBJECT IDENTIFIER 1.3.6.1.4.1.37244.2.1 + UTF8String FFF1 + SEQUENCE (2 elem) + SEQUENCE (2 elem) + OBJECT IDENTIFIER 1.2.840.10045.2.1 ecPublicKey (ANSI X9.62 public key type) + OBJECT IDENTIFIER 1.2.840.10045.3.1.7 prime256v1 (ANSI X9.62 named elliptic curve) + BIT STRING (520 bit) 0000010001000001100110101001001100010101110000100001011100111110000011… + [3] (1 elem) + SEQUENCE (4 elem) + SEQUENCE (3 elem) + OBJECT IDENTIFIER 2.5.29.19 basicConstraints (X.509 extension) + BOOLEAN true + OCTET STRING (8 byte) 30060101FF020100 + SEQUENCE (2 elem) + BOOLEAN true + INTEGER 0 + SEQUENCE (3 elem) + OBJECT IDENTIFIER 2.5.29.15 keyUsage (X.509 extension) + BOOLEAN true + OCTET STRING (4 byte) 03020106 + BIT STRING (7 bit) 0000011 + SEQUENCE (2 elem) + OBJECT IDENTIFIER 2.5.29.14 subjectKeyIdentifier (X.509 extension) + OCTET STRING (22 byte) 041463540E47F64B1C38D13884A462D16C195D8FFB3C + OCTET STRING (20 byte) 63540E47F64B1C38D13884A462D16C195D8FFB3C + SEQUENCE (2 elem) + OBJECT IDENTIFIER 2.5.29.35 authorityKeyIdentifier (X.509 extension) + OCTET STRING (24 byte) 301680146AFD22771F511FECBF1641976710DCDC31A1717E + SEQUENCE (1 elem) + [0] (20 byte) 6AFD22771F511FECBF1641976710DCDC31A1717E + SEQUENCE (1 elem) +Offset: 377 +Length: 2+10 +(constructed) +Value: +(1 elem) + OBJECT IDENTIFIER 1.2.840.10045.4.3.2 ecdsaWithSHA256 (ANSI X9.62 ECDSA algorithm with SHA256) + BIT STRING (568 bit) 0011000001000101000000100010000100000000101100101110111100100111111101… + SEQUENCE (2 elem) + INTEGER (256 bit) 8093423925895219711386938045632983408737245943652937189339272815747009… + INTEGER (255 bit) 4584930290841753608947726397552150715869097421278636946745345682393985… +*/ + +const uint8_t kDevelopmentDAC_Cert_FFF1_8000[493] = { + 0x30, 0x82, 0x01, 0xe9, 0x30, 0x82, 0x01, 0x8e, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x23, 0x8a, 0x64, 0x7b, 0xbc, 0x4c, + 0x30, 0xdd, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x3d, 0x31, 0x25, 0x30, 0x23, 0x06, + 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1c, 0x4d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x20, 0x44, 0x65, 0x76, 0x20, 0x50, 0x41, 0x49, 0x20, + 0x30, 0x78, 0x46, 0x46, 0x46, 0x31, 0x20, 0x6e, 0x6f, 0x20, 0x50, 0x49, 0x44, 0x31, 0x14, 0x30, 0x12, 0x06, 0x0a, 0x2b, 0x06, + 0x01, 0x04, 0x01, 0x82, 0xa2, 0x7c, 0x02, 0x01, 0x0c, 0x04, 0x46, 0x46, 0x46, 0x31, 0x30, 0x20, 0x17, 0x0d, 0x32, 0x32, 0x30, + 0x32, 0x30, 0x35, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x39, 0x39, 0x39, 0x39, 0x31, 0x32, 0x33, 0x31, 0x32, + 0x33, 0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x53, 0x31, 0x25, 0x30, 0x23, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1c, 0x4d, 0x61, + 0x74, 0x74, 0x65, 0x72, 0x20, 0x44, 0x65, 0x76, 0x20, 0x44, 0x41, 0x43, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x31, 0x2f, 0x30, + 0x78, 0x38, 0x30, 0x30, 0x30, 0x31, 0x14, 0x30, 0x12, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xa2, 0x7c, 0x02, 0x01, + 0x0c, 0x04, 0x46, 0x46, 0x46, 0x31, 0x31, 0x14, 0x30, 0x12, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xa2, 0x7c, 0x02, + 0x02, 0x0c, 0x04, 0x38, 0x30, 0x30, 0x30, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, + 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x62, 0xdb, 0x16, 0xba, 0xde, 0xa3, 0x26, 0xa6, + 0xdb, 0x84, 0x81, 0x4a, 0x06, 0x3f, 0xc6, 0xc7, 0xe9, 0xe2, 0xb1, 0x01, 0xb7, 0x21, 0x64, 0x8e, 0xba, 0x4e, 0x5a, 0xc8, 0x40, + 0xf5, 0xda, 0x30, 0x1e, 0xe6, 0x18, 0x12, 0x4e, 0xb4, 0x18, 0x0e, 0x2f, 0xc3, 0xa2, 0x04, 0x7a, 0x56, 0x4b, 0xa9, 0xbc, 0xfa, + 0x0b, 0xf7, 0x1f, 0x60, 0xce, 0x89, 0x30, 0xf1, 0xe7, 0xf6, 0x6e, 0xc8, 0xd7, 0x28, 0xa3, 0x60, 0x30, 0x5e, 0x30, 0x0c, 0x06, + 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, + 0x04, 0x04, 0x03, 0x02, 0x07, 0x80, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xbc, 0xf7, 0xb0, 0x07, + 0x49, 0x70, 0x63, 0x60, 0x6a, 0x26, 0xbe, 0x4e, 0x08, 0x7c, 0x59, 0x56, 0x87, 0x74, 0x5a, 0x5a, 0x30, 0x1f, 0x06, 0x03, 0x55, + 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x63, 0x54, 0x0e, 0x47, 0xf6, 0x4b, 0x1c, 0x38, 0xd1, 0x38, 0x84, 0xa4, 0x62, + 0xd1, 0x6c, 0x19, 0x5d, 0x8f, 0xfb, 0x3c, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x49, + 0x00, 0x30, 0x46, 0x02, 0x21, 0x00, 0x97, 0x97, 0x11, 0xec, 0x9e, 0x76, 0x18, 0xce, 0x41, 0x80, 0x11, 0x32, 0xc2, 0x50, 0xdb, + 0x70, 0x76, 0x74, 0x63, 0x0c, 0xd5, 0x8c, 0x12, 0xc6, 0xe2, 0x31, 0x5f, 0x08, 0xd0, 0x1e, 0xe1, 0x78, 0x02, 0x21, 0x00, 0xec, + 0xfc, 0x13, 0x06, 0xbd, 0x2a, 0x13, 0x3d, 0x12, 0x2a, 0x27, 0x86, 0x10, 0xea, 0x3d, 0xca, 0x47, 0xf0, 0x5c, 0x7a, 0x8b, 0x80, + 0x5f, 0xa7, 0x1c, 0x6f, 0xf4, 0x15, 0x38, 0xa8, 0x64, 0xc8, +}; + +/* +Decoded cert: openssl x509 -inform der -in DAC_Cert_FFF1_8000.der -text -noout + +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 23:8a:64:7b:bc:4c:30:dd + Signature Algorithm: ecdsa-with-SHA256 + Issuer: CN = Matter Dev PAI 0xFFF1 no PID, 1.3.6.1.4.1.37244.2.1 = FFF1 + Validity + Not Before: Feb 5 00:00:00 2022 GMT + Not After : Dec 31 23:59:59 9999 GMT + Subject: CN = Matter Dev DAC 0xFFF1/0x8000, 1.3.6.1.4.1.37244.2.1 = FFF1, 1.3.6.1.4.1.37244.2.2 = 8000 + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:62:db:16:ba:de:a3:26:a6:db:84:81:4a:06:3f: + c6:c7:e9:e2:b1:01:b7:21:64:8e:ba:4e:5a:c8:40: + f5:da:30:1e:e6:18:12:4e:b4:18:0e:2f:c3:a2:04: + 7a:56:4b:a9:bc:fa:0b:f7:1f:60:ce:89:30:f1:e7: + f6:6e:c8:d7:28 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:FALSE + X509v3 Key Usage: critical + Digital Signature + X509v3 Subject Key Identifier: + BC:F7:B0:07:49:70:63:60:6A:26:BE:4E:08:7C:59:56:87:74:5A:5A + X509v3 Authority Key Identifier: + keyid:63:54:0E:47:F6:4B:1C:38:D1:38:84:A4:62:D1:6C:19:5D:8F:FB:3C + + Signature Algorithm: ecdsa-with-SHA256 + 30:46:02:21:00:97:97:11:ec:9e:76:18:ce:41:80:11:32:c2: + 50:db:70:76:74:63:0c:d5:8c:12:c6:e2:31:5f:08:d0:1e:e1: + 78:02:21:00:ec:fc:13:06:bd:2a:13:3d:12:2a:27:86:10:ea: + 3d:ca:47:f0:5c:7a:8b:80:5f:a7:1c:6f:f4:15:38:a8:64:c8 + +*/ + +/* Decoded ASN.1 + +SEQUENCE (3 elem) + SEQUENCE (8 elem) + [0] (1 elem) + INTEGER 2 + INTEGER (62 bit) 2560969820716413149 + SEQUENCE (1 elem) + OBJECT IDENTIFIER 1.2.840.10045.4.3.2 ecdsaWithSHA256 (ANSI X9.62 ECDSA algorithm with SHA256) + SEQUENCE (2 elem) + SET (1 elem) + SEQUENCE (2 elem) + OBJECT IDENTIFIER 2.5.4.3 commonName (X.520 DN component) + UTF8String Matter Dev PAI 0xFFF1 no PID + SET (1 elem) + SEQUENCE (2 elem) + OBJECT IDENTIFIER 1.3.6.1.4.1.37244.2.1 + UTF8String FFF1 + SEQUENCE (2 elem) + UTCTime 2022-02-05 00:00:00 UTC + GeneralizedTime 9999-12-31 23:59:59 UTC + SEQUENCE (3 elem) + SET (1 elem) + SEQUENCE (2 elem) + OBJECT IDENTIFIER 2.5.4.3 commonName (X.520 DN component) + UTF8String Matter Dev DAC 0xFFF1/0x8000 + SET (1 elem) + SEQUENCE (2 elem) + OBJECT IDENTIFIER 1.3.6.1.4.1.37244.2.1 + UTF8String FFF1 + SET (1 elem) + SEQUENCE (2 elem) + OBJECT IDENTIFIER 1.3.6.1.4.1.37244.2.2 + UTF8String 8000 + SEQUENCE (2 elem) + SEQUENCE (2 elem) + OBJECT IDENTIFIER 1.2.840.10045.2.1 ecPublicKey (ANSI X9.62 public key type) + OBJECT IDENTIFIER 1.2.840.10045.3.1.7 prime256v1 (ANSI X9.62 named elliptic curve) + BIT STRING (520 bit) 0000010001100010110110110001011010111010110111101010001100100110101001… + [3] (1 elem) + SEQUENCE (4 elem) + SEQUENCE (3 elem) + OBJECT IDENTIFIER 2.5.29.19 basicConstraints (X.509 extension) + BOOLEAN true + OCTET STRING (2 byte) 3000 + SEQUENCE (0 elem) + SEQUENCE (3 elem) + OBJECT IDENTIFIER 2.5.29.15 keyUsage (X.509 extension) + BOOLEAN true + OCTET STRING (4 byte) 03020780 + BIT STRING (1 bit) 1 + SEQUENCE (2 elem) + OBJECT IDENTIFIER 2.5.29.14 subjectKeyIdentifier (X.509 extension) + OCTET STRING (22 byte) 0414BCF7B007497063606A26BE4E087C595687745A5A + OCTET STRING (20 byte) BCF7B007497063606A26BE4E087C595687745A5A + SEQUENCE (2 elem) + OBJECT IDENTIFIER 2.5.29.35 authorityKeyIdentifier (X.509 extension) + OCTET STRING (24 byte) 3016801463540E47F64B1C38D13884A462D16C195D8FFB3C + SEQUENCE (1 elem) + [0] (20 byte) 63540E47F64B1C38D13884A462D16C195D8FFB3C + SEQUENCE (1 elem) + OBJECT IDENTIFIER 1.2.840.10045.4.3.2 ecdsaWithSHA256 (ANSI X9.62 ECDSA algorithm with SHA256) + BIT STRING (576 bit) 0011000001000110000000100010000100000000100101111001011100010001111011… + SEQUENCE (2 elem) + INTEGER (256 bit) 6856615775177799389454949658700013485116050405241433595512074226650010… + INTEGER (256 bit) 1071912090408366213691559168363210336766445086127676108978024779974417… +*/ + +const uint8_t kDevelopmentDAC_PublicKey_FFF1_8000[65] = { + 0x04, 0x62, 0xdb, 0x16, 0xba, 0xde, 0xa3, 0x26, 0xa6, 0xdb, 0x84, 0x81, 0x4a, 0x06, 0x3f, 0xc6, 0xc7, + 0xe9, 0xe2, 0xb1, 0x01, 0xb7, 0x21, 0x64, 0x8e, 0xba, 0x4e, 0x5a, 0xc8, 0x40, 0xf5, 0xda, 0x30, 0x1e, + 0xe6, 0x18, 0x12, 0x4e, 0xb4, 0x18, 0x0e, 0x2f, 0xc3, 0xa2, 0x04, 0x7a, 0x56, 0x4b, 0xa9, 0xbc, 0xfa, + 0x0b, 0xf7, 0x1f, 0x60, 0xce, 0x89, 0x30, 0xf1, 0xe7, 0xf6, 0x6e, 0xc8, 0xd7, 0x28, +}; + +const uint8_t kDevelopmentDAC_PrivateKey_FFF1_8000[32] = { + 0xcc, 0xcf, 0x9d, 0xc7, 0x05, 0x0e, 0xf5, 0xd9, 0x0b, 0xe4, 0x57, 0x07, 0xb9, 0x0e, 0x1f, 0x87, + 0x5d, 0x59, 0xbe, 0x1f, 0xa9, 0x42, 0xe8, 0xed, 0x2e, 0x42, 0x72, 0x03, 0xf6, 0xc2, 0xee, 0x3d, +}; + +/* CertificationDeclaration */ +//-> format_version = 1 +//-> vendor_id = 0xFFF1 +//-> product_id_array = [ 0x8000, 0x8001, 0x8002, 0x8003, 0x8004, 0x8005, 0x8006, 0x8007, 0x8008, 0x8009, 0x800A, 0x800B, +// 0x800C, 0x800D, 0x800E, 0x800F, 0x8010, 0x8011, 0x8012, 0x8013, 0x8014, 0x8015, 0x8016, 0x8017, 0x8018, 0x8019, 0x801A, +// 0x801B, 0x801C, 0x801D, 0x801E, 0x801F, 0x8020, 0x8021, 0x8022, 0x8023, 0x8024, 0x8025, 0x8026, 0x8027, 0x8028, 0x8029, +// 0x802A, 0x802B, 0x802C, 0x802D, 0x802E, 0x802F, 0x8030, 0x8031, 0x8032, 0x8033, 0x8034, 0x8035, 0x8036, 0x8037, 0x8038, +// 0x8039, 0x803A, 0x803B, 0x803C, 0x803D, 0x803E, 0x803F, 0x8040, 0x8041, 0x8042, 0x8043, 0x8044, 0x8045, 0x8046, 0x8047, +// 0x8048, 0x8049, 0x804A, 0x804B, 0x804C, 0x804D, 0x804E, 0x804F, 0x8050, 0x8051, 0x8052, 0x8053, 0x8054, 0x8055, 0x8056, +// 0x8057, 0x8058, 0x8059, 0x805A, 0x805B, 0x805C, 0x805D, 0x805E, 0x805F, 0x8060, 0x8061, 0x8062, 0x8063 ] +//-> device_type_id = 0x0016 +//-> certificate_id = "CSA00000SWC00000-00" +//-> security_level = 0 +//-> security_information = 0 +//-> version_number = 1 +//-> certification_type = 0 +//-> dac_origin_vendor_id is not present +//-> dac_origin_product_id is not present +const uint8_t kCdForAllExamples[539] = { + 0x30, 0x82, 0x02, 0x17, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x02, 0x08, 0x30, + 0x82, 0x02, 0x04, 0x02, 0x01, 0x03, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, + 0x01, 0x30, 0x82, 0x01, 0x70, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x82, 0x01, 0x61, + 0x04, 0x82, 0x01, 0x5d, 0x15, 0x24, 0x00, 0x01, 0x25, 0x01, 0xf1, 0xff, 0x36, 0x02, 0x05, 0x00, 0x80, 0x05, 0x01, 0x80, + 0x05, 0x02, 0x80, 0x05, 0x03, 0x80, 0x05, 0x04, 0x80, 0x05, 0x05, 0x80, 0x05, 0x06, 0x80, 0x05, 0x07, 0x80, 0x05, 0x08, + 0x80, 0x05, 0x09, 0x80, 0x05, 0x0a, 0x80, 0x05, 0x0b, 0x80, 0x05, 0x0c, 0x80, 0x05, 0x0d, 0x80, 0x05, 0x0e, 0x80, 0x05, + 0x0f, 0x80, 0x05, 0x10, 0x80, 0x05, 0x11, 0x80, 0x05, 0x12, 0x80, 0x05, 0x13, 0x80, 0x05, 0x14, 0x80, 0x05, 0x15, 0x80, + 0x05, 0x16, 0x80, 0x05, 0x17, 0x80, 0x05, 0x18, 0x80, 0x05, 0x19, 0x80, 0x05, 0x1a, 0x80, 0x05, 0x1b, 0x80, 0x05, 0x1c, + 0x80, 0x05, 0x1d, 0x80, 0x05, 0x1e, 0x80, 0x05, 0x1f, 0x80, 0x05, 0x20, 0x80, 0x05, 0x21, 0x80, 0x05, 0x22, 0x80, 0x05, + 0x23, 0x80, 0x05, 0x24, 0x80, 0x05, 0x25, 0x80, 0x05, 0x26, 0x80, 0x05, 0x27, 0x80, 0x05, 0x28, 0x80, 0x05, 0x29, 0x80, + 0x05, 0x2a, 0x80, 0x05, 0x2b, 0x80, 0x05, 0x2c, 0x80, 0x05, 0x2d, 0x80, 0x05, 0x2e, 0x80, 0x05, 0x2f, 0x80, 0x05, 0x30, + 0x80, 0x05, 0x31, 0x80, 0x05, 0x32, 0x80, 0x05, 0x33, 0x80, 0x05, 0x34, 0x80, 0x05, 0x35, 0x80, 0x05, 0x36, 0x80, 0x05, + 0x37, 0x80, 0x05, 0x38, 0x80, 0x05, 0x39, 0x80, 0x05, 0x3a, 0x80, 0x05, 0x3b, 0x80, 0x05, 0x3c, 0x80, 0x05, 0x3d, 0x80, + 0x05, 0x3e, 0x80, 0x05, 0x3f, 0x80, 0x05, 0x40, 0x80, 0x05, 0x41, 0x80, 0x05, 0x42, 0x80, 0x05, 0x43, 0x80, 0x05, 0x44, + 0x80, 0x05, 0x45, 0x80, 0x05, 0x46, 0x80, 0x05, 0x47, 0x80, 0x05, 0x48, 0x80, 0x05, 0x49, 0x80, 0x05, 0x4a, 0x80, 0x05, + 0x4b, 0x80, 0x05, 0x4c, 0x80, 0x05, 0x4d, 0x80, 0x05, 0x4e, 0x80, 0x05, 0x4f, 0x80, 0x05, 0x50, 0x80, 0x05, 0x51, 0x80, + 0x05, 0x52, 0x80, 0x05, 0x53, 0x80, 0x05, 0x54, 0x80, 0x05, 0x55, 0x80, 0x05, 0x56, 0x80, 0x05, 0x57, 0x80, 0x05, 0x58, + 0x80, 0x05, 0x59, 0x80, 0x05, 0x5a, 0x80, 0x05, 0x5b, 0x80, 0x05, 0x5c, 0x80, 0x05, 0x5d, 0x80, 0x05, 0x5e, 0x80, 0x05, + 0x5f, 0x80, 0x05, 0x60, 0x80, 0x05, 0x61, 0x80, 0x05, 0x62, 0x80, 0x05, 0x63, 0x80, 0x18, 0x24, 0x03, 0x16, 0x2c, 0x04, + 0x13, 0x43, 0x53, 0x41, 0x30, 0x30, 0x30, 0x30, 0x30, 0x53, 0x57, 0x43, 0x30, 0x30, 0x30, 0x30, 0x30, 0x2d, 0x30, 0x30, + 0x24, 0x05, 0x00, 0x24, 0x06, 0x00, 0x24, 0x07, 0x01, 0x24, 0x08, 0x00, 0x18, 0x31, 0x7c, 0x30, 0x7a, 0x02, 0x01, 0x03, + 0x80, 0x14, 0xfe, 0x34, 0x3f, 0x95, 0x99, 0x47, 0x76, 0x3b, 0x61, 0xee, 0x45, 0x39, 0x13, 0x13, 0x38, 0x49, 0x4f, 0xe6, + 0x7d, 0x8e, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x30, 0x0a, 0x06, 0x08, 0x2a, + 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x04, 0x46, 0x30, 0x44, 0x02, 0x20, 0x4a, 0x12, 0xf8, 0xd4, 0x2f, 0x90, 0x23, + 0x5c, 0x05, 0xa7, 0x71, 0x21, 0xcb, 0xeb, 0xae, 0x15, 0xd5, 0x90, 0x14, 0x65, 0x58, 0xe9, 0xc9, 0xb4, 0x7a, 0x1a, 0x38, + 0xf7, 0xa3, 0x6a, 0x7d, 0xc5, 0x02, 0x20, 0x20, 0xa4, 0x74, 0x28, 0x97, 0xc3, 0x0a, 0xed, 0xa0, 0xa5, 0x6b, 0x36, 0xe1, + 0x4e, 0xbb, 0xc8, 0x5b, 0xbd, 0xb7, 0x44, 0x93, 0xf9, 0x93, 0x58, 0x1e, 0xb0, 0x44, 0x4e, 0xd6, 0xca, 0x94, 0x0b +}; diff --git a/lib/libesp32/berry_matter/generate/be_matter_clusters.h b/lib/libesp32/berry_matter/generate/be_matter_clusters.h new file mode 100644 index 000000000..fc9171ce6 --- /dev/null +++ b/lib/libesp32/berry_matter/generate/be_matter_clusters.h @@ -0,0 +1,1572 @@ +/*********************************************************************************\ +* Compact form for attributes and clusters +* +* Generated content, do not edit +\*********************************************************************************/ +#include +#include + +typedef struct { + uint16_t id; + uint8_t type; + uint8_t flags; + const char* name; +} matter_attribute_t; + +typedef struct { + uint16_t id; + const char* name; +} matter_command_t; + +typedef struct { + uint16_t id; + const char* name; + const matter_attribute_t* attributes; + const matter_command_t* commands; +} matter_cluster_t; + +const matter_attribute_t matter_Attributes_0003[] = { + { 0x0000, 0, 0x00, "IdentifyTime" }, + { 0x0001, 0, 0x00, "IdentifyType" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0003[] = { + { 0x0000, "Identify" }, + { 0x0040, "TriggerEffect" }, + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0004[] = { + { 0x0000, 0, 0x00, "NameSupport" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0004[] = { + { 0x0000, "AddGroup" }, + { 0x0001, "ViewGroup" }, + { 0x0002, "GetGroupMembership" }, + { 0x0003, "RemoveGroup" }, + { 0x0004, "RemoveAllGroups" }, + { 0x0005, "AddGroupIfIdentifying" }, + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0005[] = { + { 0x0000, 0, 0x00, "SceneCount" }, + { 0x0001, 0, 0x00, "CurrentScene" }, + { 0x0002, 0, 0x00, "CurrentGroup" }, + { 0x0003, 0, 0x00, "SceneValid" }, + { 0x0004, 0, 0x00, "NameSupport" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0005[] = { + { 0x0000, "AddScene" }, + { 0x0001, "ViewScene" }, + { 0x0002, "RemoveScene" }, + { 0x0003, "RemoveAllScenes" }, + { 0x0004, "StoreScene" }, + { 0x0005, "RecallScene" }, + { 0x0006, "GetSceneMembership" }, + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0006[] = { + { 0x0000, 0, 0x00, "OnOff" }, + { 0x4000, 0, 0x00, "GlobalSceneControl" }, + { 0x4001, 0, 0x00, "OnTime" }, + { 0x4002, 0, 0x00, "OffWaitTime" }, + { 0x4003, 0, 0x00, "StartUpOnOff" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0006[] = { + { 0x0000, "Off" }, + { 0x0001, "On" }, + { 0x0002, "Toggle" }, + { 0x0040, "OffWithEffect" }, + { 0x0041, "OnWithRecallGlobalScene" }, + { 0x0042, "OnWithTimedOff" }, + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0007[] = { + { 0x0000, 0, 0x00, "SwitchType" }, + { 0x0010, 0, 0x00, "SwitchActions" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0007[] = { + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0008[] = { + { 0x0000, 0, 0x00, "CurrentLevel" }, + { 0x0001, 0, 0x00, "RemainingTime" }, + { 0x0002, 0, 0x00, "MinLevel" }, + { 0x0003, 0, 0x00, "MaxLevel" }, + { 0x0004, 0, 0x00, "CurrentFrequency" }, + { 0x0005, 0, 0x00, "MinFrequency" }, + { 0x0006, 0, 0x00, "MaxFrequency" }, + { 0x000F, 0, 0x00, "Options" }, + { 0x0010, 0, 0x00, "OnOffTransitionTime" }, + { 0x0011, 0, 0x00, "OnLevel" }, + { 0x0012, 0, 0x00, "OnTransitionTime" }, + { 0x0013, 0, 0x00, "OffTransitionTime" }, + { 0x0014, 0, 0x00, "DefaultMoveRate" }, + { 0x4000, 0, 0x00, "StartUpCurrentLevel" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0008[] = { + { 0x0000, "MoveToLevel" }, + { 0x0001, "Move" }, + { 0x0002, "Step" }, + { 0x0003, "Stop" }, + { 0x0004, "MoveToLevelWithOnOff" }, + { 0x0005, "MoveWithOnOff" }, + { 0x0006, "StepWithOnOff" }, + { 0x0007, "StopWithOnOff" }, + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_000F[] = { + { 0x0051, 0, 0x00, "OutOfService" }, + { 0x0055, 0, 0x00, "PresentValue" }, + { 0x006F, 0, 0x00, "StatusFlags" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_000F[] = { + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_001D[] = { + { 0x0000, 0, 0x00, "DeviceTypeList" }, + { 0x0001, 0, 0x00, "ServerList" }, + { 0x0002, 0, 0x00, "ClientList" }, + { 0x0003, 0, 0x00, "PartsList" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_001D[] = { + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_001E[] = { + { 0x0000, 0, 0x00, "Binding" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_001E[] = { + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_001F[] = { + { 0x0000, 0, 0x00, "Acl" }, + { 0x0001, 0, 0x00, "Extension" }, + { 0x0002, 0, 0x00, "SubjectsPerAccessControlEntry" }, + { 0x0003, 0, 0x00, "TargetsPerAccessControlEntry" }, + { 0x0004, 0, 0x00, "AccessControlEntriesPerFabric" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_001F[] = { + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0025[] = { + { 0x0000, 0, 0x00, "ActionList" }, + { 0x0001, 0, 0x00, "EndpointLists" }, + { 0x0002, 0, 0x00, "SetupURL" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0025[] = { + { 0x0000, "InstantAction" }, + { 0x0001, "InstantActionWithTransition" }, + { 0x0002, "StartAction" }, + { 0x0003, "StartActionWithDuration" }, + { 0x0004, "StopAction" }, + { 0x0005, "PauseAction" }, + { 0x0006, "PauseActionWithDuration" }, + { 0x0007, "ResumeAction" }, + { 0x0008, "EnableAction" }, + { 0x0009, "EnableActionWithDuration" }, + { 0x000A, "DisableAction" }, + { 0x000B, "DisableActionWithDuration" }, + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0028[] = { + { 0x0000, 0, 0x00, "DataModelRevision" }, + { 0x0001, 0, 0x00, "VendorName" }, + { 0x0002, 0, 0x00, "VendorID" }, + { 0x0003, 0, 0x00, "ProductName" }, + { 0x0004, 0, 0x00, "ProductID" }, + { 0x0005, 0, 0x00, "NodeLabel" }, + { 0x0006, 0, 0x00, "Location" }, + { 0x0007, 0, 0x00, "HardwareVersion" }, + { 0x0008, 0, 0x00, "HardwareVersionString" }, + { 0x0009, 0, 0x00, "SoftwareVersion" }, + { 0x000A, 0, 0x00, "SoftwareVersionString" }, + { 0x000B, 0, 0x00, "ManufacturingDate" }, + { 0x000C, 0, 0x00, "PartNumber" }, + { 0x000D, 0, 0x00, "ProductURL" }, + { 0x000E, 0, 0x00, "ProductLabel" }, + { 0x000F, 0, 0x00, "SerialNumber" }, + { 0x0010, 0, 0x00, "LocalConfigDisabled" }, + { 0x0011, 0, 0x00, "Reachable" }, + { 0x0012, 0, 0x00, "UniqueID" }, + { 0x0013, 0, 0x00, "CapabilityMinima" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0028[] = { + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0029[] = { + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0029[] = { + { 0x0000, "QueryImage" }, + { 0x0002, "ApplyUpdateRequest" }, + { 0x0004, "NotifyUpdateApplied" }, + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_002A[] = { + { 0x0000, 0, 0x00, "DefaultOtaProviders" }, + { 0x0001, 0, 0x00, "UpdatePossible" }, + { 0x0002, 0, 0x00, "UpdateState" }, + { 0x0003, 0, 0x00, "UpdateStateProgress" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_002A[] = { + { 0x0000, "AnnounceOtaProvider" }, + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_002B[] = { + { 0x0000, 0, 0x00, "ActiveLocale" }, + { 0x0001, 0, 0x00, "SupportedLocales" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_002B[] = { + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_002C[] = { + { 0x0000, 0, 0x00, "HourFormat" }, + { 0x0001, 0, 0x00, "ActiveCalendarType" }, + { 0x0002, 0, 0x00, "SupportedCalendarTypes" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_002C[] = { + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_002D[] = { + { 0x0000, 0, 0x00, "TemperatureUnit" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_002D[] = { + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_002E[] = { + { 0x0000, 0, 0x00, "Sources" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_002E[] = { + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_002F[] = { + { 0x0000, 0, 0x00, "Status" }, + { 0x0001, 0, 0x00, "Order" }, + { 0x0002, 0, 0x00, "Description" }, + { 0x0003, 0, 0x00, "WiredAssessedInputVoltage" }, + { 0x0004, 0, 0x00, "WiredAssessedInputFrequency" }, + { 0x0005, 0, 0x00, "WiredCurrentType" }, + { 0x0006, 0, 0x00, "WiredAssessedCurrent" }, + { 0x0007, 0, 0x00, "WiredNominalVoltage" }, + { 0x0008, 0, 0x00, "WiredMaximumCurrent" }, + { 0x0009, 0, 0x00, "WiredPresent" }, + { 0x000A, 0, 0x00, "ActiveWiredFaults" }, + { 0x000B, 0, 0x00, "BatVoltage" }, + { 0x000C, 0, 0x00, "BatPercentRemaining" }, + { 0x000D, 0, 0x00, "BatTimeRemaining" }, + { 0x000E, 0, 0x00, "BatChargeLevel" }, + { 0x000F, 0, 0x00, "BatReplacementNeeded" }, + { 0x0010, 0, 0x00, "BatReplaceability" }, + { 0x0011, 0, 0x00, "BatPresent" }, + { 0x0012, 0, 0x00, "ActiveBatFaults" }, + { 0x0013, 0, 0x00, "BatReplacementDescription" }, + { 0x0014, 0, 0x00, "BatCommonDesignation" }, + { 0x0015, 0, 0x00, "BatANSIDesignation" }, + { 0x0016, 0, 0x00, "BatIECDesignation" }, + { 0x0017, 0, 0x00, "BatApprovedChemistry" }, + { 0x0018, 0, 0x00, "BatCapacity" }, + { 0x0019, 0, 0x00, "BatQuantity" }, + { 0x001A, 0, 0x00, "BatChargeState" }, + { 0x001B, 0, 0x00, "BatTimeToFullCharge" }, + { 0x001C, 0, 0x00, "BatFunctionalWhileCharging" }, + { 0x001D, 0, 0x00, "BatChargingCurrent" }, + { 0x001E, 0, 0x00, "ActiveBatChargeFaults" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_002F[] = { + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0030[] = { + { 0x0000, 0, 0x00, "Breadcrumb" }, + { 0x0001, 0, 0x00, "BasicCommissioningInfo" }, + { 0x0002, 0, 0x00, "RegulatoryConfig" }, + { 0x0003, 0, 0x00, "LocationCapability" }, + { 0x0004, 0, 0x00, "SupportsConcurrentConnection" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0030[] = { + { 0x0000, "ArmFailSafe" }, + { 0x0001, "ArmFailSafeResponse" }, + { 0x0002, "SetRegulatoryConfig" }, + { 0x0003, "SetRegulatoryConfigResponse" }, + { 0x0004, "CommissioningComplete" }, + { 0x0005, "CommissioningCompleteResponse" }, + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0031[] = { + { 0x0000, 0, 0x00, "MaxNetworks" }, + { 0x0001, 0, 0x00, "Networks" }, + { 0x0002, 0, 0x00, "ScanMaxTimeSeconds" }, + { 0x0003, 0, 0x00, "ConnectMaxTimeSeconds" }, + { 0x0004, 0, 0x00, "InterfaceEnabled" }, + { 0x0005, 0, 0x00, "LastNetworkingStatus" }, + { 0x0006, 0, 0x00, "LastNetworkID" }, + { 0x0007, 0, 0x00, "LastConnectErrorValue" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0031[] = { + { 0x0000, "ScanNetworks" }, + { 0x0002, "AddOrUpdateWiFiNetwork" }, + { 0x0003, "AddOrUpdateThreadNetwork" }, + { 0x0004, "RemoveNetwork" }, + { 0x0006, "ConnectNetwork" }, + { 0x0008, "ReorderNetwork" }, + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0032[] = { + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0032[] = { + { 0x0000, "RetrieveLogsRequest" }, + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0033[] = { + { 0x0000, 0, 0x00, "NetworkInterfaces" }, + { 0x0001, 0, 0x00, "RebootCount" }, + { 0x0002, 0, 0x00, "UpTime" }, + { 0x0003, 0, 0x00, "TotalOperationalHours" }, + { 0x0004, 0, 0x00, "BootReasons" }, + { 0x0005, 0, 0x00, "ActiveHardwareFaults" }, + { 0x0006, 0, 0x00, "ActiveRadioFaults" }, + { 0x0007, 0, 0x00, "ActiveNetworkFaults" }, + { 0x0008, 0, 0x00, "TestEventTriggersEnabled" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0033[] = { + { 0x0000, "TestEventTrigger" }, + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0034[] = { + { 0x0000, 0, 0x00, "ThreadMetrics" }, + { 0x0001, 0, 0x00, "CurrentHeapFree" }, + { 0x0002, 0, 0x00, "CurrentHeapUsed" }, + { 0x0003, 0, 0x00, "CurrentHeapHighWatermark" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0034[] = { + { 0x0000, "ResetWatermarks" }, + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0035[] = { + { 0x0000, 0, 0x00, "Channel" }, + { 0x0001, 0, 0x00, "RoutingRole" }, + { 0x0002, 0, 0x00, "NetworkName" }, + { 0x0003, 0, 0x00, "PanId" }, + { 0x0004, 0, 0x00, "ExtendedPanId" }, + { 0x0005, 0, 0x00, "MeshLocalPrefix" }, + { 0x0006, 0, 0x00, "OverrunCount" }, + { 0x0007, 0, 0x00, "NeighborTableList" }, + { 0x0008, 0, 0x00, "RouteTableList" }, + { 0x0009, 0, 0x00, "PartitionId" }, + { 0x000A, 0, 0x00, "Weighting" }, + { 0x000B, 0, 0x00, "DataVersion" }, + { 0x000C, 0, 0x00, "StableDataVersion" }, + { 0x000D, 0, 0x00, "LeaderRouterId" }, + { 0x000E, 0, 0x00, "DetachedRoleCount" }, + { 0x000F, 0, 0x00, "ChildRoleCount" }, + { 0x0010, 0, 0x00, "RouterRoleCount" }, + { 0x0011, 0, 0x00, "LeaderRoleCount" }, + { 0x0012, 0, 0x00, "AttachAttemptCount" }, + { 0x0013, 0, 0x00, "PartitionIdChangeCount" }, + { 0x0014, 0, 0x00, "BetterPartitionAttachAttemptCount" }, + { 0x0015, 0, 0x00, "ParentChangeCount" }, + { 0x0016, 0, 0x00, "TxTotalCount" }, + { 0x0017, 0, 0x00, "TxUnicastCount" }, + { 0x0018, 0, 0x00, "TxBroadcastCount" }, + { 0x0019, 0, 0x00, "TxAckRequestedCount" }, + { 0x001A, 0, 0x00, "TxAckedCount" }, + { 0x001B, 0, 0x00, "TxNoAckRequestedCount" }, + { 0x001C, 0, 0x00, "TxDataCount" }, + { 0x001D, 0, 0x00, "TxDataPollCount" }, + { 0x001E, 0, 0x00, "TxBeaconCount" }, + { 0x001F, 0, 0x00, "TxBeaconRequestCount" }, + { 0x0020, 0, 0x00, "TxOtherCount" }, + { 0x0021, 0, 0x00, "TxRetryCount" }, + { 0x0022, 0, 0x00, "TxDirectMaxRetryExpiryCount" }, + { 0x0023, 0, 0x00, "TxIndirectMaxRetryExpiryCount" }, + { 0x0024, 0, 0x00, "TxErrCcaCount" }, + { 0x0025, 0, 0x00, "TxErrAbortCount" }, + { 0x0026, 0, 0x00, "TxErrBusyChannelCount" }, + { 0x0027, 0, 0x00, "RxTotalCount" }, + { 0x0028, 0, 0x00, "RxUnicastCount" }, + { 0x0029, 0, 0x00, "RxBroadcastCount" }, + { 0x002A, 0, 0x00, "RxDataCount" }, + { 0x002B, 0, 0x00, "RxDataPollCount" }, + { 0x002C, 0, 0x00, "RxBeaconCount" }, + { 0x002D, 0, 0x00, "RxBeaconRequestCount" }, + { 0x002E, 0, 0x00, "RxOtherCount" }, + { 0x002F, 0, 0x00, "RxAddressFilteredCount" }, + { 0x0030, 0, 0x00, "RxDestAddrFilteredCount" }, + { 0x0031, 0, 0x00, "RxDuplicatedCount" }, + { 0x0032, 0, 0x00, "RxErrNoFrameCount" }, + { 0x0033, 0, 0x00, "RxErrUnknownNeighborCount" }, + { 0x0034, 0, 0x00, "RxErrInvalidSrcAddrCount" }, + { 0x0035, 0, 0x00, "RxErrSecCount" }, + { 0x0036, 0, 0x00, "RxErrFcsCount" }, + { 0x0037, 0, 0x00, "RxErrOtherCount" }, + { 0x0038, 0, 0x00, "ActiveTimestamp" }, + { 0x0039, 0, 0x00, "PendingTimestamp" }, + { 0x003A, 0, 0x00, "Delay" }, + { 0x003B, 0, 0x00, "SecurityPolicy" }, + { 0x003C, 0, 0x00, "ChannelPage0Mask" }, + { 0x003D, 0, 0x00, "OperationalDatasetComponents" }, + { 0x003E, 0, 0x00, "ActiveNetworkFaultsList" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0035[] = { + { 0x0000, "ResetCounts" }, + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0036[] = { + { 0x0000, 0, 0x00, "Bssid" }, + { 0x0001, 0, 0x00, "SecurityType" }, + { 0x0002, 0, 0x00, "WiFiVersion" }, + { 0x0003, 0, 0x00, "ChannelNumber" }, + { 0x0004, 0, 0x00, "Rssi" }, + { 0x0005, 0, 0x00, "BeaconLostCount" }, + { 0x0006, 0, 0x00, "BeaconRxCount" }, + { 0x0007, 0, 0x00, "PacketMulticastRxCount" }, + { 0x0008, 0, 0x00, "PacketMulticastTxCount" }, + { 0x0009, 0, 0x00, "PacketUnicastRxCount" }, + { 0x000A, 0, 0x00, "PacketUnicastTxCount" }, + { 0x000B, 0, 0x00, "CurrentMaxRate" }, + { 0x000C, 0, 0x00, "OverrunCount" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0036[] = { + { 0x0000, "ResetCounts" }, + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0037[] = { + { 0x0000, 0, 0x00, "PHYRate" }, + { 0x0001, 0, 0x00, "FullDuplex" }, + { 0x0002, 0, 0x00, "PacketRxCount" }, + { 0x0003, 0, 0x00, "PacketTxCount" }, + { 0x0004, 0, 0x00, "TxErrCount" }, + { 0x0005, 0, 0x00, "CollisionCount" }, + { 0x0006, 0, 0x00, "OverrunCount" }, + { 0x0007, 0, 0x00, "CarrierDetect" }, + { 0x0008, 0, 0x00, "TimeSinceReset" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0037[] = { + { 0x0000, "ResetCounts" }, + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0039[] = { + { 0x0001, 0, 0x00, "VendorName" }, + { 0x0002, 0, 0x00, "VendorID" }, + { 0x0003, 0, 0x00, "ProductName" }, + { 0x0005, 0, 0x00, "NodeLabel" }, + { 0x0007, 0, 0x00, "HardwareVersion" }, + { 0x0008, 0, 0x00, "HardwareVersionString" }, + { 0x0009, 0, 0x00, "SoftwareVersion" }, + { 0x000A, 0, 0x00, "SoftwareVersionString" }, + { 0x000B, 0, 0x00, "ManufacturingDate" }, + { 0x000C, 0, 0x00, "PartNumber" }, + { 0x000D, 0, 0x00, "ProductURL" }, + { 0x000E, 0, 0x00, "ProductLabel" }, + { 0x000F, 0, 0x00, "SerialNumber" }, + { 0x0011, 0, 0x00, "Reachable" }, + { 0x0012, 0, 0x00, "UniqueID" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0039[] = { + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_003B[] = { + { 0x0000, 0, 0x00, "NumberOfPositions" }, + { 0x0001, 0, 0x00, "CurrentPosition" }, + { 0x0002, 0, 0x00, "MultiPressMax" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_003B[] = { + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_003C[] = { + { 0x0000, 0, 0x00, "WindowStatus" }, + { 0x0001, 0, 0x00, "AdminFabricIndex" }, + { 0x0002, 0, 0x00, "AdminVendorId" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_003C[] = { + { 0x0000, "OpenCommissioningWindow" }, + { 0x0001, "OpenBasicCommissioningWindow" }, + { 0x0002, "RevokeCommissioning" }, + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_003E[] = { + { 0x0000, 0, 0x00, "NOCs" }, + { 0x0001, 0, 0x00, "Fabrics" }, + { 0x0002, 0, 0x00, "SupportedFabrics" }, + { 0x0003, 0, 0x00, "CommissionedFabrics" }, + { 0x0004, 0, 0x00, "TrustedRootCertificates" }, + { 0x0005, 0, 0x00, "CurrentFabricIndex" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_003E[] = { + { 0x0000, "AttestationRequest" }, + { 0x0001, "AttestationResponse" }, + { 0x0002, "CertificateChainRequest" }, + { 0x0003, "CertificateChainResponse" }, + { 0x0004, "CSRRequest" }, + { 0x0005, "CSRResponse" }, + { 0x0006, "AddNOC" }, + { 0x0007, "UpdateNOC" }, + { 0x0008, "NOCResponse" }, + { 0x0009, "UpdateFabricLabel" }, + { 0x000A, "RemoveFabric" }, + { 0x000B, "AddTrustedRootCertificate" }, + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_003F[] = { + { 0x0000, 0, 0x00, "GroupKeyMap" }, + { 0x0001, 0, 0x00, "GroupTable" }, + { 0x0002, 0, 0x00, "MaxGroupsPerFabric" }, + { 0x0003, 0, 0x00, "MaxGroupKeysPerFabric" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_003F[] = { + { 0x0000, "KeySetWrite" }, + { 0x0001, "KeySetRead" }, + { 0x0003, "KeySetRemove" }, + { 0x0004, "KeySetReadAllIndices" }, + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0040[] = { + { 0x0000, 0, 0x00, "LabelList" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0040[] = { + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0041[] = { + { 0x0000, 0, 0x00, "LabelList" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0041[] = { + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0045[] = { + { 0x0000, 0, 0x00, "StateValue" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0045[] = { + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0050[] = { + { 0x0000, 0, 0x00, "Description" }, + { 0x0001, 0, 0x00, "StandardNamespace" }, + { 0x0002, 0, 0x00, "SupportedModes" }, + { 0x0003, 0, 0x00, "CurrentMode" }, + { 0x0004, 0, 0x00, "StartUpMode" }, + { 0x0005, 0, 0x00, "OnMode" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0050[] = { + { 0x0000, "ChangeToMode" }, + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0101[] = { + { 0x0000, 0, 0x00, "LockState" }, + { 0x0001, 0, 0x00, "LockType" }, + { 0x0002, 0, 0x00, "ActuatorEnabled" }, + { 0x0003, 0, 0x00, "DoorState" }, + { 0x0011, 0, 0x00, "NumberOfTotalUsersSupported" }, + { 0x0012, 0, 0x00, "NumberOfPINUsersSupported" }, + { 0x0013, 0, 0x00, "NumberOfRFIDUsersSupported" }, + { 0x0014, 0, 0x00, "NumberOfWeekDaySchedulesSupportedPerUser" }, + { 0x0015, 0, 0x00, "NumberOfYearDaySchedulesSupportedPerUser" }, + { 0x0016, 0, 0x00, "NumberOfHolidaySchedulesSupported" }, + { 0x0017, 0, 0x00, "MaxPINCodeLength" }, + { 0x0018, 0, 0x00, "MinPINCodeLength" }, + { 0x0019, 0, 0x00, "MaxRFIDCodeLength" }, + { 0x001A, 0, 0x00, "MinRFIDCodeLength" }, + { 0x001C, 0, 0x00, "NumberOfCredentialsSupportedPerUser" }, + { 0x0021, 0, 0x00, "Language" }, + { 0x0023, 0, 0x00, "AutoRelockTime" }, + { 0x0024, 0, 0x00, "SoundVolume" }, + { 0x0025, 0, 0x00, "OperatingMode" }, + { 0x0026, 0, 0x00, "SupportedOperatingModes" }, + { 0x0029, 0, 0x00, "EnableOneTouchLocking" }, + { 0x002B, 0, 0x00, "EnablePrivacyModeButton" }, + { 0x0030, 0, 0x00, "WrongCodeEntryLimit" }, + { 0x0031, 0, 0x00, "UserCodeTemporaryDisableTime" }, + { 0x0033, 0, 0x00, "RequirePINforRemoteOperation" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0101[] = { + { 0x0000, "LockDoor" }, + { 0x0001, "UnlockDoor" }, + { 0x0003, "UnlockWithTimeout" }, + { 0x000B, "SetWeekDaySchedule" }, + { 0x000C, "GetWeekDaySchedule" }, + { 0x000D, "ClearWeekDaySchedule" }, + { 0x000E, "SetYearDaySchedule" }, + { 0x000F, "GetYearDaySchedule" }, + { 0x0010, "ClearYearDaySchedule" }, + { 0x0011, "SetHolidaySchedule" }, + { 0x0012, "GetHolidaySchedule" }, + { 0x0013, "ClearHolidaySchedule" }, + { 0x001A, "SetUser" }, + { 0x001B, "GetUser" }, + { 0x001D, "ClearUser" }, + { 0x0022, "SetCredential" }, + { 0x0024, "GetCredentialStatus" }, + { 0x0026, "ClearCredential" }, + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0102[] = { + { 0x0000, 0, 0x00, "Type" }, + { 0x0001, 0, 0x00, "PhysicalClosedLimitLift" }, + { 0x0002, 0, 0x00, "PhysicalClosedLimitTilt" }, + { 0x0003, 0, 0x00, "CurrentPositionLift" }, + { 0x0004, 0, 0x00, "CurrentPositionTilt" }, + { 0x0005, 0, 0x00, "NumberOfActuationsLift" }, + { 0x0006, 0, 0x00, "NumberOfActuationsTilt" }, + { 0x0007, 0, 0x00, "ConfigStatus" }, + { 0x0008, 0, 0x00, "CurrentPositionLiftPercentage" }, + { 0x0009, 0, 0x00, "CurrentPositionTiltPercentage" }, + { 0x000A, 0, 0x00, "OperationalStatus" }, + { 0x000B, 0, 0x00, "TargetPositionLiftPercent100ths" }, + { 0x000C, 0, 0x00, "TargetPositionTiltPercent100ths" }, + { 0x000D, 0, 0x00, "EndProductType" }, + { 0x000E, 0, 0x00, "CurrentPositionLiftPercent100ths" }, + { 0x000F, 0, 0x00, "CurrentPositionTiltPercent100ths" }, + { 0x0010, 0, 0x00, "InstalledOpenLimitLift" }, + { 0x0011, 0, 0x00, "InstalledClosedLimitLift" }, + { 0x0012, 0, 0x00, "InstalledOpenLimitTilt" }, + { 0x0013, 0, 0x00, "InstalledClosedLimitTilt" }, + { 0x0017, 0, 0x00, "Mode" }, + { 0x001A, 0, 0x00, "SafetyStatus" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0102[] = { + { 0x0000, "UpOrOpen" }, + { 0x0001, "DownOrClose" }, + { 0x0002, "StopMotion" }, + { 0x0004, "GoToLiftValue" }, + { 0x0005, "GoToLiftPercentage" }, + { 0x0007, "GoToTiltValue" }, + { 0x0008, "GoToTiltPercentage" }, + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0103[] = { + { 0x0001, 0, 0x00, "BarrierMovingState" }, + { 0x0002, 0, 0x00, "BarrierSafetyStatus" }, + { 0x0003, 0, 0x00, "BarrierCapabilities" }, + { 0x000A, 0, 0x00, "BarrierPosition" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0103[] = { + { 0x0000, "BarrierControlGoToPercent" }, + { 0x0001, "BarrierControlStop" }, + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0200[] = { + { 0x0000, 0, 0x00, "MaxPressure" }, + { 0x0001, 0, 0x00, "MaxSpeed" }, + { 0x0002, 0, 0x00, "MaxFlow" }, + { 0x0003, 0, 0x00, "MinConstPressure" }, + { 0x0004, 0, 0x00, "MaxConstPressure" }, + { 0x0005, 0, 0x00, "MinCompPressure" }, + { 0x0006, 0, 0x00, "MaxCompPressure" }, + { 0x0007, 0, 0x00, "MinConstSpeed" }, + { 0x0008, 0, 0x00, "MaxConstSpeed" }, + { 0x0009, 0, 0x00, "MinConstFlow" }, + { 0x000A, 0, 0x00, "MaxConstFlow" }, + { 0x000B, 0, 0x00, "MinConstTemp" }, + { 0x000C, 0, 0x00, "MaxConstTemp" }, + { 0x0010, 0, 0x00, "PumpStatus" }, + { 0x0011, 0, 0x00, "EffectiveOperationMode" }, + { 0x0012, 0, 0x00, "EffectiveControlMode" }, + { 0x0013, 0, 0x00, "Capacity" }, + { 0x0014, 0, 0x00, "Speed" }, + { 0x0015, 0, 0x00, "LifetimeRunningHours" }, + { 0x0016, 0, 0x00, "Power" }, + { 0x0017, 0, 0x00, "LifetimeEnergyConsumed" }, + { 0x0020, 0, 0x00, "OperationMode" }, + { 0x0021, 0, 0x00, "ControlMode" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0200[] = { + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0201[] = { + { 0x0000, 0, 0x00, "LocalTemperature" }, + { 0x0003, 0, 0x00, "AbsMinHeatSetpointLimit" }, + { 0x0004, 0, 0x00, "AbsMaxHeatSetpointLimit" }, + { 0x0005, 0, 0x00, "AbsMinCoolSetpointLimit" }, + { 0x0006, 0, 0x00, "AbsMaxCoolSetpointLimit" }, + { 0x0011, 0, 0x00, "OccupiedCoolingSetpoint" }, + { 0x0012, 0, 0x00, "OccupiedHeatingSetpoint" }, + { 0x0015, 0, 0x00, "MinHeatSetpointLimit" }, + { 0x0016, 0, 0x00, "MaxHeatSetpointLimit" }, + { 0x0017, 0, 0x00, "MinCoolSetpointLimit" }, + { 0x0018, 0, 0x00, "MaxCoolSetpointLimit" }, + { 0x0019, 0, 0x00, "MinSetpointDeadBand" }, + { 0x001B, 0, 0x00, "ControlSequenceOfOperation" }, + { 0x001C, 0, 0x00, "SystemMode" }, + { 0x0020, 0, 0x00, "StartOfWeek" }, + { 0x0021, 0, 0x00, "NumberOfWeeklyTransitions" }, + { 0x0022, 0, 0x00, "NumberOfDailyTransitions" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0201[] = { + { 0x0000, "SetpointRaiseLower" }, + { 0x0001, "SetWeeklySchedule" }, + { 0x0002, "GetWeeklySchedule" }, + { 0x0003, "ClearWeeklySchedule" }, + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0202[] = { + { 0x0000, 0, 0x00, "FanMode" }, + { 0x0001, 0, 0x00, "FanModeSequence" }, + { 0x0002, 0, 0x00, "PercentSetting" }, + { 0x0003, 0, 0x00, "PercentCurrent" }, + { 0x0004, 0, 0x00, "SpeedMax" }, + { 0x0005, 0, 0x00, "SpeedSetting" }, + { 0x0006, 0, 0x00, "SpeedCurrent" }, + { 0x0007, 0, 0x00, "RockSupport" }, + { 0x0008, 0, 0x00, "RockSetting" }, + { 0x0009, 0, 0x00, "WindSupport" }, + { 0x000A, 0, 0x00, "WindSetting" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0202[] = { + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0204[] = { + { 0x0000, 0, 0x00, "TemperatureDisplayMode" }, + { 0x0001, 0, 0x00, "KeypadLockout" }, + { 0x0002, 0, 0x00, "ScheduleProgrammingVisibility" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0204[] = { + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0300[] = { + { 0x0000, 0, 0x00, "CurrentHue" }, + { 0x0001, 0, 0x00, "CurrentSaturation" }, + { 0x0002, 0, 0x00, "RemainingTime" }, + { 0x0003, 0, 0x00, "CurrentX" }, + { 0x0004, 0, 0x00, "CurrentY" }, + { 0x0005, 0, 0x00, "DriftCompensation" }, + { 0x0006, 0, 0x00, "CompensationText" }, + { 0x0007, 0, 0x00, "ColorTemperatureMireds" }, + { 0x0008, 0, 0x00, "ColorMode" }, + { 0x000F, 0, 0x00, "Options" }, + { 0x0010, 0, 0x00, "NumberOfPrimaries" }, + { 0x0011, 0, 0x00, "Primary1X" }, + { 0x0012, 0, 0x00, "Primary1Y" }, + { 0x0013, 0, 0x00, "Primary1Intensity" }, + { 0x0015, 0, 0x00, "Primary2X" }, + { 0x0016, 0, 0x00, "Primary2Y" }, + { 0x0017, 0, 0x00, "Primary2Intensity" }, + { 0x0019, 0, 0x00, "Primary3X" }, + { 0x001A, 0, 0x00, "Primary3Y" }, + { 0x001B, 0, 0x00, "Primary3Intensity" }, + { 0x0020, 0, 0x00, "Primary4X" }, + { 0x0021, 0, 0x00, "Primary4Y" }, + { 0x0022, 0, 0x00, "Primary4Intensity" }, + { 0x0024, 0, 0x00, "Primary5X" }, + { 0x0025, 0, 0x00, "Primary5Y" }, + { 0x0026, 0, 0x00, "Primary5Intensity" }, + { 0x0028, 0, 0x00, "Primary6X" }, + { 0x0029, 0, 0x00, "Primary6Y" }, + { 0x002A, 0, 0x00, "Primary6Intensity" }, + { 0x0030, 0, 0x00, "WhitePointX" }, + { 0x0031, 0, 0x00, "WhitePointY" }, + { 0x0032, 0, 0x00, "ColorPointRX" }, + { 0x0033, 0, 0x00, "ColorPointRY" }, + { 0x0034, 0, 0x00, "ColorPointRIntensity" }, + { 0x0036, 0, 0x00, "ColorPointGX" }, + { 0x0037, 0, 0x00, "ColorPointGY" }, + { 0x0038, 0, 0x00, "ColorPointGIntensity" }, + { 0x003A, 0, 0x00, "ColorPointBX" }, + { 0x003B, 0, 0x00, "ColorPointBY" }, + { 0x003C, 0, 0x00, "ColorPointBIntensity" }, + { 0x4000, 0, 0x00, "EnhancedCurrentHue" }, + { 0x4001, 0, 0x00, "EnhancedColorMode" }, + { 0x4002, 0, 0x00, "ColorLoopActive" }, + { 0x4003, 0, 0x00, "ColorLoopDirection" }, + { 0x4004, 0, 0x00, "ColorLoopTime" }, + { 0x4005, 0, 0x00, "ColorLoopStartEnhancedHue" }, + { 0x4006, 0, 0x00, "ColorLoopStoredEnhancedHue" }, + { 0x400A, 0, 0x00, "ColorCapabilities" }, + { 0x400B, 0, 0x00, "ColorTempPhysicalMinMireds" }, + { 0x400C, 0, 0x00, "ColorTempPhysicalMaxMireds" }, + { 0x400D, 0, 0x00, "CoupleColorTempToLevelMinMireds" }, + { 0x4010, 0, 0x00, "StartUpColorTemperatureMireds" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0300[] = { + { 0x0000, "MoveToHue" }, + { 0x0001, "MoveHue" }, + { 0x0002, "StepHue" }, + { 0x0003, "MoveToSaturation" }, + { 0x0004, "MoveSaturation" }, + { 0x0005, "StepSaturation" }, + { 0x0006, "MoveToHueAndSaturation" }, + { 0x0007, "MoveToColor" }, + { 0x0008, "MoveColor" }, + { 0x0009, "StepColor" }, + { 0x000A, "MoveToColorTemperature" }, + { 0x0040, "EnhancedMoveToHue" }, + { 0x0041, "EnhancedMoveHue" }, + { 0x0042, "EnhancedStepHue" }, + { 0x0043, "EnhancedMoveToHueAndSaturation" }, + { 0x0044, "ColorLoopSet" }, + { 0x0047, "StopMoveStep" }, + { 0x004B, "MoveColorTemperature" }, + { 0x004C, "StepColorTemperature" }, + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0301[] = { + { 0x0000, 0, 0x00, "PhysicalMinLevel" }, + { 0x0001, 0, 0x00, "PhysicalMaxLevel" }, + { 0x0002, 0, 0x00, "BallastStatus" }, + { 0x0010, 0, 0x00, "MinLevel" }, + { 0x0011, 0, 0x00, "MaxLevel" }, + { 0x0014, 0, 0x00, "IntrinsicBalanceFactor" }, + { 0x0015, 0, 0x00, "BallastFactorAdjustment" }, + { 0x0020, 0, 0x00, "LampQuantity" }, + { 0x0030, 0, 0x00, "LampType" }, + { 0x0031, 0, 0x00, "LampManufacturer" }, + { 0x0032, 0, 0x00, "LampRatedHours" }, + { 0x0033, 0, 0x00, "LampBurnHours" }, + { 0x0034, 0, 0x00, "LampAlarmMode" }, + { 0x0035, 0, 0x00, "LampBurnHoursTripPoint" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0301[] = { + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0400[] = { + { 0x0000, 0, 0x00, "MeasuredValue" }, + { 0x0001, 0, 0x00, "MinMeasuredValue" }, + { 0x0002, 0, 0x00, "MaxMeasuredValue" }, + { 0x0003, 0, 0x00, "Tolerance" }, + { 0x0004, 0, 0x00, "LightSensorType" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0400[] = { + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0402[] = { + { 0x0000, 0, 0x00, "MeasuredValue" }, + { 0x0001, 0, 0x00, "MinMeasuredValue" }, + { 0x0002, 0, 0x00, "MaxMeasuredValue" }, + { 0x0003, 0, 0x00, "Tolerance" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0402[] = { + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0403[] = { + { 0x0000, 0, 0x00, "MeasuredValue" }, + { 0x0001, 0, 0x00, "MinMeasuredValue" }, + { 0x0002, 0, 0x00, "MaxMeasuredValue" }, + { 0x0003, 0, 0x00, "Tolerance" }, + { 0x0010, 0, 0x00, "ScaledValue" }, + { 0x0011, 0, 0x00, "MinScaledValue" }, + { 0x0012, 0, 0x00, "MaxScaledValue" }, + { 0x0013, 0, 0x00, "ScaledTolerance" }, + { 0x0014, 0, 0x00, "Scale" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0403[] = { + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0404[] = { + { 0x0000, 0, 0x00, "MeasuredValue" }, + { 0x0001, 0, 0x00, "MinMeasuredValue" }, + { 0x0002, 0, 0x00, "MaxMeasuredValue" }, + { 0x0003, 0, 0x00, "Tolerance" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0404[] = { + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0405[] = { + { 0x0000, 0, 0x00, "MeasuredValue" }, + { 0x0001, 0, 0x00, "MinMeasuredValue" }, + { 0x0002, 0, 0x00, "MaxMeasuredValue" }, + { 0x0003, 0, 0x00, "Tolerance" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0405[] = { + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0406[] = { + { 0x0000, 0, 0x00, "Occupancy" }, + { 0x0001, 0, 0x00, "OccupancySensorType" }, + { 0x0002, 0, 0x00, "OccupancySensorTypeBitmap" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0406[] = { + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0503[] = { + { 0x0000, 0, 0x00, "MACAddress" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0503[] = { + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0504[] = { + { 0x0000, 0, 0x00, "ChannelList" }, + { 0x0001, 0, 0x00, "Lineup" }, + { 0x0002, 0, 0x00, "CurrentChannel" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0504[] = { + { 0x0000, "ChangeChannel" }, + { 0x0002, "ChangeChannelByNumber" }, + { 0x0003, "SkipChannel" }, + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0505[] = { + { 0x0000, 0, 0x00, "TargetList" }, + { 0x0001, 0, 0x00, "CurrentTarget" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0505[] = { + { 0x0000, "NavigateTarget" }, + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0506[] = { + { 0x0000, 0, 0x00, "CurrentState" }, + { 0x0001, 0, 0x00, "StartTime" }, + { 0x0002, 0, 0x00, "Duration" }, + { 0x0003, 0, 0x00, "SampledPosition" }, + { 0x0004, 0, 0x00, "PlaybackSpeed" }, + { 0x0005, 0, 0x00, "SeekRangeEnd" }, + { 0x0006, 0, 0x00, "SeekRangeStart" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0506[] = { + { 0x0000, "Play" }, + { 0x0001, "Pause" }, + { 0x0002, "StopPlayback" }, + { 0x0003, "StartOver" }, + { 0x0004, "Previous" }, + { 0x0005, "Next" }, + { 0x0006, "Rewind" }, + { 0x0007, "FastForward" }, + { 0x0008, "SkipForward" }, + { 0x0009, "SkipBackward" }, + { 0x000B, "Seek" }, + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0507[] = { + { 0x0000, 0, 0x00, "InputList" }, + { 0x0001, 0, 0x00, "CurrentInput" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0507[] = { + { 0x0000, "SelectInput" }, + { 0x0001, "ShowInputStatus" }, + { 0x0002, "HideInputStatus" }, + { 0x0003, "RenameInput" }, + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0508[] = { + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0508[] = { + { 0x0000, "Sleep" }, + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0509[] = { + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0509[] = { + { 0x0000, "SendKey" }, + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_050A[] = { + { 0x0000, 0, 0x00, "AcceptHeader" }, + { 0x0001, 0, 0x00, "SupportedStreamingProtocols" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_050A[] = { + { 0x0000, "LaunchContent" }, + { 0x0001, "LaunchURL" }, + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_050B[] = { + { 0x0000, 0, 0x00, "OutputList" }, + { 0x0001, 0, 0x00, "CurrentOutput" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_050B[] = { + { 0x0000, "SelectOutput" }, + { 0x0001, "RenameOutput" }, + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_050C[] = { + { 0x0000, 0, 0x00, "CatalogList" }, + { 0x0001, 0, 0x00, "CurrentApp" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_050C[] = { + { 0x0000, "LaunchApp" }, + { 0x0001, "StopApp" }, + { 0x0002, "HideApp" }, + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_050D[] = { + { 0x0000, 0, 0x00, "VendorName" }, + { 0x0001, 0, 0x00, "VendorID" }, + { 0x0002, 0, 0x00, "ApplicationName" }, + { 0x0003, 0, 0x00, "ProductID" }, + { 0x0004, 0, 0x00, "Application" }, + { 0x0005, 0, 0x00, "Status" }, + { 0x0006, 0, 0x00, "ApplicationVersion" }, + { 0x0007, 0, 0x00, "AllowedVendorList" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_050D[] = { + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_050E[] = { + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_050E[] = { + { 0x0000, "GetSetupPIN" }, + { 0x0002, "Login" }, + { 0x0003, "Logout" }, + { 0xFFFF, NULL }, +}; + +const matter_attribute_t matter_Attributes_0B04[] = { + { 0x0000, 0, 0x00, "MeasurementType" }, + { 0x0304, 0, 0x00, "TotalActivePower" }, + { 0x0505, 0, 0x00, "RmsVoltage" }, + { 0x0506, 0, 0x00, "RmsVoltageMin" }, + { 0x0507, 0, 0x00, "RmsVoltageMax" }, + { 0x0508, 0, 0x00, "RmsCurrent" }, + { 0x0509, 0, 0x00, "RmsCurrentMin" }, + { 0x050A, 0, 0x00, "RmsCurrentMax" }, + { 0x050B, 0, 0x00, "ActivePower" }, + { 0x050C, 0, 0x00, "ActivePowerMin" }, + { 0x050D, 0, 0x00, "ActivePowerMax" }, + { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x00, "AttributeList" }, + { 0xFFFC, 0, 0x00, "FeatureMap" }, + { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFF, 0, 0x00, NULL }, +}; + +const matter_command_t matter_Commands_0B04[] = { + { 0xFFFF, NULL }, +}; + +const matter_cluster_t matterAllClusters[] = { + { 0x0003, "Identify", matter_Attributes_0003, matter_Commands_0003 }, + { 0x0004, "Groups", matter_Attributes_0004, matter_Commands_0004 }, + { 0x0005, "Scenes", matter_Attributes_0005, matter_Commands_0005 }, + { 0x0006, "OnOff", matter_Attributes_0006, matter_Commands_0006 }, + { 0x0007, "OnOffSwitchConfiguration", matter_Attributes_0007, matter_Commands_0007 }, + { 0x0008, "LevelControl", matter_Attributes_0008, matter_Commands_0008 }, + { 0x000F, "BinaryInputBasic", matter_Attributes_000F, matter_Commands_000F }, + { 0x001D, "Descriptor", matter_Attributes_001D, matter_Commands_001D }, + { 0x001E, "Binding", matter_Attributes_001E, matter_Commands_001E }, + { 0x001F, "AccessControl", matter_Attributes_001F, matter_Commands_001F }, + { 0x0025, "Actions", matter_Attributes_0025, matter_Commands_0025 }, + { 0x0028, "Basic", matter_Attributes_0028, matter_Commands_0028 }, + { 0x0029, "OtaSoftwareUpdateProvider", matter_Attributes_0029, matter_Commands_0029 }, + { 0x002A, "OtaSoftwareUpdateRequestor", matter_Attributes_002A, matter_Commands_002A }, + { 0x002B, "LocalizationConfiguration", matter_Attributes_002B, matter_Commands_002B }, + { 0x002C, "TimeFormatLocalization", matter_Attributes_002C, matter_Commands_002C }, + { 0x002D, "UnitLocalization", matter_Attributes_002D, matter_Commands_002D }, + { 0x002E, "PowerSourceConfiguration", matter_Attributes_002E, matter_Commands_002E }, + { 0x002F, "PowerSource", matter_Attributes_002F, matter_Commands_002F }, + { 0x0030, "GeneralCommissioning", matter_Attributes_0030, matter_Commands_0030 }, + { 0x0031, "NetworkCommissioning", matter_Attributes_0031, matter_Commands_0031 }, + { 0x0032, "DiagnosticLogs", matter_Attributes_0032, matter_Commands_0032 }, + { 0x0033, "GeneralDiagnostics", matter_Attributes_0033, matter_Commands_0033 }, + { 0x0034, "SoftwareDiagnostics", matter_Attributes_0034, matter_Commands_0034 }, + { 0x0035, "ThreadNetworkDiagnostics", matter_Attributes_0035, matter_Commands_0035 }, + { 0x0036, "WiFiNetworkDiagnostics", matter_Attributes_0036, matter_Commands_0036 }, + { 0x0037, "EthernetNetworkDiagnostics", matter_Attributes_0037, matter_Commands_0037 }, + { 0x0039, "BridgedDeviceBasic", matter_Attributes_0039, matter_Commands_0039 }, + { 0x003B, "Switch", matter_Attributes_003B, matter_Commands_003B }, + { 0x003C, "AdministratorCommissioning", matter_Attributes_003C, matter_Commands_003C }, + { 0x003E, "OperationalCredentials", matter_Attributes_003E, matter_Commands_003E }, + { 0x003F, "GroupKeyManagement", matter_Attributes_003F, matter_Commands_003F }, + { 0x0040, "FixedLabel", matter_Attributes_0040, matter_Commands_0040 }, + { 0x0041, "UserLabel", matter_Attributes_0041, matter_Commands_0041 }, + { 0x0045, "BooleanState", matter_Attributes_0045, matter_Commands_0045 }, + { 0x0050, "ModeSelect", matter_Attributes_0050, matter_Commands_0050 }, + { 0x0101, "DoorLock", matter_Attributes_0101, matter_Commands_0101 }, + { 0x0102, "WindowCovering", matter_Attributes_0102, matter_Commands_0102 }, + { 0x0103, "BarrierControl", matter_Attributes_0103, matter_Commands_0103 }, + { 0x0200, "PumpConfigurationAndControl", matter_Attributes_0200, matter_Commands_0200 }, + { 0x0201, "Thermostat", matter_Attributes_0201, matter_Commands_0201 }, + { 0x0202, "FanControl", matter_Attributes_0202, matter_Commands_0202 }, + { 0x0204, "ThermostatUserInterfaceConfiguration", matter_Attributes_0204, matter_Commands_0204 }, + { 0x0300, "ColorControl", matter_Attributes_0300, matter_Commands_0300 }, + { 0x0301, "BallastConfiguration", matter_Attributes_0301, matter_Commands_0301 }, + { 0x0400, "IlluminanceMeasurement", matter_Attributes_0400, matter_Commands_0400 }, + { 0x0402, "TemperatureMeasurement", matter_Attributes_0402, matter_Commands_0402 }, + { 0x0403, "PressureMeasurement", matter_Attributes_0403, matter_Commands_0403 }, + { 0x0404, "FlowMeasurement", matter_Attributes_0404, matter_Commands_0404 }, + { 0x0405, "RelativeHumidityMeasurement", matter_Attributes_0405, matter_Commands_0405 }, + { 0x0406, "OccupancySensing", matter_Attributes_0406, matter_Commands_0406 }, + { 0x0503, "WakeOnLan", matter_Attributes_0503, matter_Commands_0503 }, + { 0x0504, "Channel", matter_Attributes_0504, matter_Commands_0504 }, + { 0x0505, "TargetNavigator", matter_Attributes_0505, matter_Commands_0505 }, + { 0x0506, "MediaPlayback", matter_Attributes_0506, matter_Commands_0506 }, + { 0x0507, "MediaInput", matter_Attributes_0507, matter_Commands_0507 }, + { 0x0508, "LowPower", matter_Attributes_0508, matter_Commands_0508 }, + { 0x0509, "KeypadInput", matter_Attributes_0509, matter_Commands_0509 }, + { 0x050A, "ContentLauncher", matter_Attributes_050A, matter_Commands_050A }, + { 0x050B, "AudioOutput", matter_Attributes_050B, matter_Commands_050B }, + { 0x050C, "ApplicationLauncher", matter_Attributes_050C, matter_Commands_050C }, + { 0x050D, "ApplicationBasic", matter_Attributes_050D, matter_Commands_050D }, + { 0x050E, "AccountLogin", matter_Attributes_050E, matter_Commands_050E }, + { 0x0B04, "ElectricalMeasurement", matter_Attributes_0B04, matter_Commands_0B04 }, + { 0xFFFF, NULL, NULL }, +}; diff --git a/lib/libesp32/berry_matter/generate/be_matter_opcodes.h b/lib/libesp32/berry_matter/generate/be_matter_opcodes.h new file mode 100644 index 000000000..7d361159b --- /dev/null +++ b/lib/libesp32/berry_matter/generate/be_matter_opcodes.h @@ -0,0 +1,29 @@ +/*********************************************************************************\ +* Compact form for attributes and clusters +* +* Generated content, do not edit +\*********************************************************************************/ +#include +#include + +typedef struct { + uint16_t id; + const char* name; +} matter_opcode_t; + +const matter_opcode_t matter_OpCodes[] = { + { 0x0000, "MsgCounterSyncReq" }, + { 0x0001, "MsgCounterSyncRsp" }, + { 0x0010, "MRP_Standalone_Acknowledgement" }, + { 0x0020, "PBKDFParamRequest" }, + { 0x0021, "PBKDFParamResponse" }, + { 0x0022, "PASE_Pake1" }, + { 0x0023, "PASE_Pake2" }, + { 0x0024, "PASE_Pake3" }, + { 0x0030, "CASE_Sigma1" }, + { 0x0031, "CASE_Sigma2" }, + { 0x0032, "CASE_Sigma3" }, + { 0x0033, "CASE_Sigma2_Resume" }, + { 0x0040, "StatusReport" }, + { 0xFFFF, NULL }, +}; diff --git a/lib/libesp32/berry_matter/generate/matter_clusters.be b/lib/libesp32/berry_matter/generate/matter_clusters.be new file mode 100644 index 000000000..2ca6fc239 --- /dev/null +++ b/lib/libesp32/berry_matter/generate/matter_clusters.be @@ -0,0 +1,7425 @@ +# Matter clusters +# +# Needs to be reword, this structure is huge... +# +# imported from Python definition + + +var _Matter_clusters = +{ + 'Identify': { + 'clusterName': 'Identify', + 'clusterId': 3, + 'commands': { + 0: { + 'commandId': 0, + 'commandName': 'Identify', + 'args': { + 'identifyTime': 'int' + } + }, + 64: { + 'commandId': 64, + 'commandName': 'TriggerEffect', + 'args': { + 'effectIdentifier': 'int', + 'effectVariant': 'int' + } + } + }, + 'attributes': { + 0: { + 'attributeName': 'IdentifyTime', + 'attributeId': 0, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 1: { + 'attributeName': 'IdentifyType', + 'attributeId': 1, + 'type': 'int', + 'reportable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'Groups': { + 'clusterName': 'Groups', + 'clusterId': 4, + 'commands': { + 0: { + 'commandId': 0, + 'commandName': 'AddGroup', + 'args': { + 'groupId': 'int', + 'groupName': 'str' + } + }, + 1: { + 'commandId': 1, + 'commandName': 'ViewGroup', + 'args': { + 'groupId': 'int' + } + }, + 2: { + 'commandId': 2, + 'commandName': 'GetGroupMembership', + 'args': { + 'groupList': 'int' + } + }, + 3: { + 'commandId': 3, + 'commandName': 'RemoveGroup', + 'args': { + 'groupId': 'int' + } + }, + 4: { + 'commandId': 4, + 'commandName': 'RemoveAllGroups', + 'args': {} + }, + 5: { + 'commandId': 5, + 'commandName': 'AddGroupIfIdentifying', + 'args': { + 'groupId': 'int', + 'groupName': 'str' + } + } + }, + 'attributes': { + 0: { + 'attributeName': 'NameSupport', + 'attributeId': 0, + 'type': 'int', + 'reportable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'Scenes': { + 'clusterName': 'Scenes', + 'clusterId': 5, + 'commands': { + 0: { + 'commandId': 0, + 'commandName': 'AddScene', + 'args': { + 'groupId': 'int', + 'sceneId': 'int', + 'transitionTime': 'int', + 'sceneName': 'str', + 'clusterId': 'int', + 'attributeValueList': '' + } + }, + 1: { + 'commandId': 1, + 'commandName': 'ViewScene', + 'args': { + 'groupId': 'int', + 'sceneId': 'int' + } + }, + 2: { + 'commandId': 2, + 'commandName': 'RemoveScene', + 'args': { + 'groupId': 'int', + 'sceneId': 'int' + } + }, + 3: { + 'commandId': 3, + 'commandName': 'RemoveAllScenes', + 'args': { + 'groupId': 'int' + } + }, + 4: { + 'commandId': 4, + 'commandName': 'StoreScene', + 'args': { + 'groupId': 'int', + 'sceneId': 'int' + } + }, + 5: { + 'commandId': 5, + 'commandName': 'RecallScene', + 'args': { + 'groupId': 'int', + 'sceneId': 'int', + 'transitionTime': 'int' + } + }, + 6: { + 'commandId': 6, + 'commandName': 'GetSceneMembership', + 'args': { + 'groupId': 'int' + } + } + }, + 'attributes': { + 0: { + 'attributeName': 'SceneCount', + 'attributeId': 0, + 'type': 'int', + 'reportable': true + }, + 1: { + 'attributeName': 'CurrentScene', + 'attributeId': 1, + 'type': 'int', + 'reportable': true + }, + 2: { + 'attributeName': 'CurrentGroup', + 'attributeId': 2, + 'type': 'int', + 'reportable': true + }, + 3: { + 'attributeName': 'SceneValid', + 'attributeId': 3, + 'type': 'bool', + 'reportable': true + }, + 4: { + 'attributeName': 'NameSupport', + 'attributeId': 4, + 'type': 'int', + 'reportable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'OnOff': { + 'clusterName': 'OnOff', + 'clusterId': 6, + 'commands': { + 0: { + 'commandId': 0, + 'commandName': 'Off', + 'args': {} + }, + 1: { + 'commandId': 1, + 'commandName': 'On', + 'args': {} + }, + 2: { + 'commandId': 2, + 'commandName': 'Toggle', + 'args': {} + }, + 64: { + 'commandId': 64, + 'commandName': 'OffWithEffect', + 'args': { + 'effectId': 'int', + 'effectVariant': 'int' + } + }, + 65: { + 'commandId': 65, + 'commandName': 'OnWithRecallGlobalScene', + 'args': {} + }, + 66: { + 'commandId': 66, + 'commandName': 'OnWithTimedOff', + 'args': { + 'onOffControl': 'int', + 'onTime': 'int', + 'offWaitTime': 'int' + } + } + }, + 'attributes': { + 0: { + 'attributeName': 'OnOff', + 'attributeId': 0, + 'type': 'bool', + 'reportable': true + }, + 16384: { + 'attributeName': 'GlobalSceneControl', + 'attributeId': 16384, + 'type': 'bool', + 'reportable': true + }, + 16385: { + 'attributeName': 'OnTime', + 'attributeId': 16385, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 16386: { + 'attributeName': 'OffWaitTime', + 'attributeId': 16386, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 16387: { + 'attributeName': 'StartUpOnOff', + 'attributeId': 16387, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'OnOffSwitchConfiguration': { + 'clusterName': 'OnOffSwitchConfiguration', + 'clusterId': 7, + 'commands': {}, + 'attributes': { + 0: { + 'attributeName': 'SwitchType', + 'attributeId': 0, + 'type': 'int', + 'reportable': true + }, + 16: { + 'attributeName': 'SwitchActions', + 'attributeId': 16, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'LevelControl': { + 'clusterName': 'LevelControl', + 'clusterId': 8, + 'commands': { + 0: { + 'commandId': 0, + 'commandName': 'MoveToLevel', + 'args': { + 'level': 'int', + 'transitionTime': 'int', + 'optionsMask': 'int', + 'optionsOverride': 'int' + } + }, + 1: { + 'commandId': 1, + 'commandName': 'Move', + 'args': { + 'moveMode': 'int', + 'rate': 'int', + 'optionsMask': 'int', + 'optionsOverride': 'int' + } + }, + 2: { + 'commandId': 2, + 'commandName': 'Step', + 'args': { + 'stepMode': 'int', + 'stepSize': 'int', + 'transitionTime': 'int', + 'optionsMask': 'int', + 'optionsOverride': 'int' + } + }, + 3: { + 'commandId': 3, + 'commandName': 'Stop', + 'args': { + 'optionsMask': 'int', + 'optionsOverride': 'int' + } + }, + 4: { + 'commandId': 4, + 'commandName': 'MoveToLevelWithOnOff', + 'args': { + 'level': 'int', + 'transitionTime': 'int', + 'optionsMask': 'int', + 'optionsOverride': 'int' + } + }, + 5: { + 'commandId': 5, + 'commandName': 'MoveWithOnOff', + 'args': { + 'moveMode': 'int', + 'rate': 'int', + 'optionsMask': 'int', + 'optionsOverride': 'int' + } + }, + 6: { + 'commandId': 6, + 'commandName': 'StepWithOnOff', + 'args': { + 'stepMode': 'int', + 'stepSize': 'int', + 'transitionTime': 'int', + 'optionsMask': 'int', + 'optionsOverride': 'int' + } + }, + 7: { + 'commandId': 7, + 'commandName': 'StopWithOnOff', + 'args': { + 'optionsMask': 'int', + 'optionsOverride': 'int' + } + } + }, + 'attributes': { + 0: { + 'attributeName': 'CurrentLevel', + 'attributeId': 0, + 'type': 'int', + 'reportable': true + }, + 1: { + 'attributeName': 'RemainingTime', + 'attributeId': 1, + 'type': 'int', + 'reportable': true + }, + 2: { + 'attributeName': 'MinLevel', + 'attributeId': 2, + 'type': 'int', + 'reportable': true + }, + 3: { + 'attributeName': 'MaxLevel', + 'attributeId': 3, + 'type': 'int', + 'reportable': true + }, + 4: { + 'attributeName': 'CurrentFrequency', + 'attributeId': 4, + 'type': 'int', + 'reportable': true + }, + 5: { + 'attributeName': 'MinFrequency', + 'attributeId': 5, + 'type': 'int', + 'reportable': true + }, + 6: { + 'attributeName': 'MaxFrequency', + 'attributeId': 6, + 'type': 'int', + 'reportable': true + }, + 15: { + 'attributeName': 'Options', + 'attributeId': 15, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 16: { + 'attributeName': 'OnOffTransitionTime', + 'attributeId': 16, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 17: { + 'attributeName': 'OnLevel', + 'attributeId': 17, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 18: { + 'attributeName': 'OnTransitionTime', + 'attributeId': 18, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 19: { + 'attributeName': 'OffTransitionTime', + 'attributeId': 19, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 20: { + 'attributeName': 'DefaultMoveRate', + 'attributeId': 20, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 16384: { + 'attributeName': 'StartUpCurrentLevel', + 'attributeId': 16384, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'BinaryInputBasic': { + 'clusterName': 'BinaryInputBasic', + 'clusterId': 15, + 'commands': {}, + 'attributes': { + 81: { + 'attributeName': 'OutOfService', + 'attributeId': 81, + 'type': 'bool', + 'reportable': true, + 'writable': true + }, + 85: { + 'attributeName': 'PresentValue', + 'attributeId': 85, + 'type': 'bool', + 'reportable': true, + 'writable': true + }, + 111: { + 'attributeName': 'StatusFlags', + 'attributeId': 111, + 'type': 'int', + 'reportable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'Descriptor': { + 'clusterName': 'Descriptor', + 'clusterId': 29, + 'commands': {}, + 'attributes': { + 0: { + 'attributeName': 'DeviceTypeList', + 'attributeId': 0, + 'type': '', + 'reportable': true + }, + 1: { + 'attributeName': 'ServerList', + 'attributeId': 1, + 'type': 'int', + 'reportable': true + }, + 2: { + 'attributeName': 'ClientList', + 'attributeId': 2, + 'type': 'int', + 'reportable': true + }, + 3: { + 'attributeName': 'PartsList', + 'attributeId': 3, + 'type': 'int', + 'reportable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'Binding': { + 'clusterName': 'Binding', + 'clusterId': 30, + 'commands': {}, + 'attributes': { + 0: { + 'attributeName': 'Binding', + 'attributeId': 0, + 'type': '', + 'reportable': true, + 'writable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'AccessControl': { + 'clusterName': 'AccessControl', + 'clusterId': 31, + 'commands': {}, + 'attributes': { + 0: { + 'attributeName': 'Acl', + 'attributeId': 0, + 'type': '', + 'reportable': true, + 'writable': true + }, + 1: { + 'attributeName': 'Extension', + 'attributeId': 1, + 'type': '', + 'reportable': true, + 'writable': true + }, + 2: { + 'attributeName': 'SubjectsPerAccessControlEntry', + 'attributeId': 2, + 'type': 'int', + 'reportable': true + }, + 3: { + 'attributeName': 'TargetsPerAccessControlEntry', + 'attributeId': 3, + 'type': 'int', + 'reportable': true + }, + 4: { + 'attributeName': 'AccessControlEntriesPerFabric', + 'attributeId': 4, + 'type': 'int', + 'reportable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'Actions': { + 'clusterName': 'Actions', + 'clusterId': 37, + 'commands': { + 0: { + 'commandId': 0, + 'commandName': 'InstantAction', + 'args': { + 'actionID': 'int', + 'invokeID': 'int' + } + }, + 1: { + 'commandId': 1, + 'commandName': 'InstantActionWithTransition', + 'args': { + 'actionID': 'int', + 'invokeID': 'int', + 'transitionTime': 'int' + } + }, + 2: { + 'commandId': 2, + 'commandName': 'StartAction', + 'args': { + 'actionID': 'int', + 'invokeID': 'int' + } + }, + 3: { + 'commandId': 3, + 'commandName': 'StartActionWithDuration', + 'args': { + 'actionID': 'int', + 'invokeID': 'int', + 'duration': 'int' + } + }, + 4: { + 'commandId': 4, + 'commandName': 'StopAction', + 'args': { + 'actionID': 'int', + 'invokeID': 'int' + } + }, + 5: { + 'commandId': 5, + 'commandName': 'PauseAction', + 'args': { + 'actionID': 'int', + 'invokeID': 'int' + } + }, + 6: { + 'commandId': 6, + 'commandName': 'PauseActionWithDuration', + 'args': { + 'actionID': 'int', + 'invokeID': 'int', + 'duration': 'int' + } + }, + 7: { + 'commandId': 7, + 'commandName': 'ResumeAction', + 'args': { + 'actionID': 'int', + 'invokeID': 'int' + } + }, + 8: { + 'commandId': 8, + 'commandName': 'EnableAction', + 'args': { + 'actionID': 'int', + 'invokeID': 'int' + } + }, + 9: { + 'commandId': 9, + 'commandName': 'EnableActionWithDuration', + 'args': { + 'actionID': 'int', + 'invokeID': 'int', + 'duration': 'int' + } + }, + 10: { + 'commandId': 10, + 'commandName': 'DisableAction', + 'args': { + 'actionID': 'int', + 'invokeID': 'int' + } + }, + 11: { + 'commandId': 11, + 'commandName': 'DisableActionWithDuration', + 'args': { + 'actionID': 'int', + 'invokeID': 'int', + 'duration': 'int' + } + } + }, + 'attributes': { + 0: { + 'attributeName': 'ActionList', + 'attributeId': 0, + 'type': '', + 'reportable': true + }, + 1: { + 'attributeName': 'EndpointLists', + 'attributeId': 1, + 'type': '', + 'reportable': true + }, + 2: { + 'attributeName': 'SetupURL', + 'attributeId': 2, + 'type': 'str', + 'reportable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'Basic': { + 'clusterName': 'Basic', + 'clusterId': 40, + 'commands': {}, + 'attributes': { + 0: { + 'attributeName': 'DataModelRevision', + 'attributeId': 0, + 'type': 'int', + 'reportable': true + }, + 1: { + 'attributeName': 'VendorName', + 'attributeId': 1, + 'type': 'str', + 'reportable': true + }, + 2: { + 'attributeName': 'VendorID', + 'attributeId': 2, + 'type': 'int', + 'reportable': true + }, + 3: { + 'attributeName': 'ProductName', + 'attributeId': 3, + 'type': 'str', + 'reportable': true + }, + 4: { + 'attributeName': 'ProductID', + 'attributeId': 4, + 'type': 'int', + 'reportable': true + }, + 5: { + 'attributeName': 'NodeLabel', + 'attributeId': 5, + 'type': 'str', + 'reportable': true, + 'writable': true + }, + 6: { + 'attributeName': 'Location', + 'attributeId': 6, + 'type': 'str', + 'reportable': true, + 'writable': true + }, + 7: { + 'attributeName': 'HardwareVersion', + 'attributeId': 7, + 'type': 'int', + 'reportable': true + }, + 8: { + 'attributeName': 'HardwareVersionString', + 'attributeId': 8, + 'type': 'str', + 'reportable': true + }, + 9: { + 'attributeName': 'SoftwareVersion', + 'attributeId': 9, + 'type': 'int', + 'reportable': true + }, + 10: { + 'attributeName': 'SoftwareVersionString', + 'attributeId': 10, + 'type': 'str', + 'reportable': true + }, + 11: { + 'attributeName': 'ManufacturingDate', + 'attributeId': 11, + 'type': 'str', + 'reportable': true + }, + 12: { + 'attributeName': 'PartNumber', + 'attributeId': 12, + 'type': 'str', + 'reportable': true + }, + 13: { + 'attributeName': 'ProductURL', + 'attributeId': 13, + 'type': 'str', + 'reportable': true + }, + 14: { + 'attributeName': 'ProductLabel', + 'attributeId': 14, + 'type': 'str', + 'reportable': true + }, + 15: { + 'attributeName': 'SerialNumber', + 'attributeId': 15, + 'type': 'str', + 'reportable': true + }, + 16: { + 'attributeName': 'LocalConfigDisabled', + 'attributeId': 16, + 'type': 'bool', + 'reportable': true, + 'writable': true + }, + 17: { + 'attributeName': 'Reachable', + 'attributeId': 17, + 'type': 'bool', + 'reportable': true + }, + 18: { + 'attributeName': 'UniqueID', + 'attributeId': 18, + 'type': 'str', + 'reportable': true + }, + 19: { + 'attributeName': 'CapabilityMinima', + 'attributeId': 19, + 'type': '', + 'reportable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'OtaSoftwareUpdateProvider': { + 'clusterName': 'OtaSoftwareUpdateProvider', + 'clusterId': 41, + 'commands': { + 0: { + 'commandId': 0, + 'commandName': 'QueryImage', + 'args': { + 'vendorId': 'int', + 'productId': 'int', + 'softwareVersion': 'int', + 'protocolsSupported': 'int', + 'hardwareVersion': 'int', + 'location': 'str', + 'requestorCanConsent': 'bool', + 'metadataForProvider': 'bytes' + } + }, + 2: { + 'commandId': 2, + 'commandName': 'ApplyUpdateRequest', + 'args': { + 'updateToken': 'bytes', + 'newVersion': 'int' + } + }, + 4: { + 'commandId': 4, + 'commandName': 'NotifyUpdateApplied', + 'args': { + 'updateToken': 'bytes', + 'softwareVersion': 'int' + } + } + }, + 'attributes': { + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'OtaSoftwareUpdateRequestor': { + 'clusterName': 'OtaSoftwareUpdateRequestor', + 'clusterId': 42, + 'commands': { + 0: { + 'commandId': 0, + 'commandName': 'AnnounceOtaProvider', + 'args': { + 'providerNodeId': 'int', + 'vendorId': 'int', + 'announcementReason': 'int', + 'metadataForNode': 'bytes', + 'endpoint': 'int' + } + } + }, + 'attributes': { + 0: { + 'attributeName': 'DefaultOtaProviders', + 'attributeId': 0, + 'type': '', + 'reportable': true, + 'writable': true + }, + 1: { + 'attributeName': 'UpdatePossible', + 'attributeId': 1, + 'type': 'bool', + 'reportable': true + }, + 2: { + 'attributeName': 'UpdateState', + 'attributeId': 2, + 'type': 'int', + 'reportable': true + }, + 3: { + 'attributeName': 'UpdateStateProgress', + 'attributeId': 3, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'LocalizationConfiguration': { + 'clusterName': 'LocalizationConfiguration', + 'clusterId': 43, + 'commands': {}, + 'attributes': { + 0: { + 'attributeName': 'ActiveLocale', + 'attributeId': 0, + 'type': 'str', + 'reportable': true, + 'writable': true + }, + 1: { + 'attributeName': 'SupportedLocales', + 'attributeId': 1, + 'type': 'str', + 'reportable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'TimeFormatLocalization': { + 'clusterName': 'TimeFormatLocalization', + 'clusterId': 44, + 'commands': {}, + 'attributes': { + 0: { + 'attributeName': 'HourFormat', + 'attributeId': 0, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 1: { + 'attributeName': 'ActiveCalendarType', + 'attributeId': 1, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 2: { + 'attributeName': 'SupportedCalendarTypes', + 'attributeId': 2, + 'type': 'int', + 'reportable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'UnitLocalization': { + 'clusterName': 'UnitLocalization', + 'clusterId': 45, + 'commands': {}, + 'attributes': { + 0: { + 'attributeName': 'TemperatureUnit', + 'attributeId': 0, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'PowerSourceConfiguration': { + 'clusterName': 'PowerSourceConfiguration', + 'clusterId': 46, + 'commands': {}, + 'attributes': { + 0: { + 'attributeName': 'Sources', + 'attributeId': 0, + 'type': 'int', + 'reportable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'PowerSource': { + 'clusterName': 'PowerSource', + 'clusterId': 47, + 'commands': {}, + 'attributes': { + 0: { + 'attributeName': 'Status', + 'attributeId': 0, + 'type': 'int', + 'reportable': true + }, + 1: { + 'attributeName': 'Order', + 'attributeId': 1, + 'type': 'int', + 'reportable': true + }, + 2: { + 'attributeName': 'Description', + 'attributeId': 2, + 'type': 'str', + 'reportable': true + }, + 3: { + 'attributeName': 'WiredAssessedInputVoltage', + 'attributeId': 3, + 'type': 'int', + 'reportable': true + }, + 4: { + 'attributeName': 'WiredAssessedInputFrequency', + 'attributeId': 4, + 'type': 'int', + 'reportable': true + }, + 5: { + 'attributeName': 'WiredCurrentType', + 'attributeId': 5, + 'type': 'int', + 'reportable': true + }, + 6: { + 'attributeName': 'WiredAssessedCurrent', + 'attributeId': 6, + 'type': 'int', + 'reportable': true + }, + 7: { + 'attributeName': 'WiredNominalVoltage', + 'attributeId': 7, + 'type': 'int', + 'reportable': true + }, + 8: { + 'attributeName': 'WiredMaximumCurrent', + 'attributeId': 8, + 'type': 'int', + 'reportable': true + }, + 9: { + 'attributeName': 'WiredPresent', + 'attributeId': 9, + 'type': 'bool', + 'reportable': true + }, + 10: { + 'attributeName': 'ActiveWiredFaults', + 'attributeId': 10, + 'type': 'int', + 'reportable': true + }, + 11: { + 'attributeName': 'BatVoltage', + 'attributeId': 11, + 'type': 'int', + 'reportable': true + }, + 12: { + 'attributeName': 'BatPercentRemaining', + 'attributeId': 12, + 'type': 'int', + 'reportable': true + }, + 13: { + 'attributeName': 'BatTimeRemaining', + 'attributeId': 13, + 'type': 'int', + 'reportable': true + }, + 14: { + 'attributeName': 'BatChargeLevel', + 'attributeId': 14, + 'type': 'int', + 'reportable': true + }, + 15: { + 'attributeName': 'BatReplacementNeeded', + 'attributeId': 15, + 'type': 'bool', + 'reportable': true + }, + 16: { + 'attributeName': 'BatReplaceability', + 'attributeId': 16, + 'type': 'int', + 'reportable': true + }, + 17: { + 'attributeName': 'BatPresent', + 'attributeId': 17, + 'type': 'bool', + 'reportable': true + }, + 18: { + 'attributeName': 'ActiveBatFaults', + 'attributeId': 18, + 'type': 'int', + 'reportable': true + }, + 19: { + 'attributeName': 'BatReplacementDescription', + 'attributeId': 19, + 'type': 'str', + 'reportable': true + }, + 20: { + 'attributeName': 'BatCommonDesignation', + 'attributeId': 20, + 'type': 'int', + 'reportable': true + }, + 21: { + 'attributeName': 'BatANSIDesignation', + 'attributeId': 21, + 'type': 'str', + 'reportable': true + }, + 22: { + 'attributeName': 'BatIECDesignation', + 'attributeId': 22, + 'type': 'str', + 'reportable': true + }, + 23: { + 'attributeName': 'BatApprovedChemistry', + 'attributeId': 23, + 'type': 'int', + 'reportable': true + }, + 24: { + 'attributeName': 'BatCapacity', + 'attributeId': 24, + 'type': 'int', + 'reportable': true + }, + 25: { + 'attributeName': 'BatQuantity', + 'attributeId': 25, + 'type': 'int', + 'reportable': true + }, + 26: { + 'attributeName': 'BatChargeState', + 'attributeId': 26, + 'type': 'int', + 'reportable': true + }, + 27: { + 'attributeName': 'BatTimeToFullCharge', + 'attributeId': 27, + 'type': 'int', + 'reportable': true + }, + 28: { + 'attributeName': 'BatFunctionalWhileCharging', + 'attributeId': 28, + 'type': 'bool', + 'reportable': true + }, + 29: { + 'attributeName': 'BatChargingCurrent', + 'attributeId': 29, + 'type': 'int', + 'reportable': true + }, + 30: { + 'attributeName': 'ActiveBatChargeFaults', + 'attributeId': 30, + 'type': 'int', + 'reportable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'GeneralCommissioning': { + 'clusterName': 'GeneralCommissioning', + 'clusterId': 48, + 'commands': { + 0: { + 'commandId': 0, + 'commandName': 'ArmFailSafe', + 'args': { + 'expiryLengthSeconds': 'int', + 'breadcrumb': 'int' + } + }, + 2: { + 'commandId': 2, + 'commandName': 'SetRegulatoryConfig', + 'args': { + 'newRegulatoryConfig': 'int', + 'countryCode': 'str', + 'breadcrumb': 'int' + } + }, + 4: { + 'commandId': 4, + 'commandName': 'CommissioningComplete', + 'args': {} + } + }, + 'attributes': { + 0: { + 'attributeName': 'Breadcrumb', + 'attributeId': 0, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 1: { + 'attributeName': 'BasicCommissioningInfo', + 'attributeId': 1, + 'type': '', + 'reportable': true + }, + 2: { + 'attributeName': 'RegulatoryConfig', + 'attributeId': 2, + 'type': 'int', + 'reportable': true + }, + 3: { + 'attributeName': 'LocationCapability', + 'attributeId': 3, + 'type': 'int', + 'reportable': true + }, + 4: { + 'attributeName': 'SupportsConcurrentConnection', + 'attributeId': 4, + 'type': 'bool', + 'reportable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'NetworkCommissioning': { + 'clusterName': 'NetworkCommissioning', + 'clusterId': 49, + 'commands': { + 0: { + 'commandId': 0, + 'commandName': 'ScanNetworks', + 'args': { + 'ssid': 'bytes', + 'breadcrumb': 'int' + } + }, + 2: { + 'commandId': 2, + 'commandName': 'AddOrUpdateWiFiNetwork', + 'args': { + 'ssid': 'bytes', + 'credentials': 'bytes', + 'breadcrumb': 'int' + } + }, + 3: { + 'commandId': 3, + 'commandName': 'AddOrUpdateThreadNetwork', + 'args': { + 'operationalDataset': 'bytes', + 'breadcrumb': 'int' + } + }, + 4: { + 'commandId': 4, + 'commandName': 'RemoveNetwork', + 'args': { + 'networkID': 'bytes', + 'breadcrumb': 'int' + } + }, + 6: { + 'commandId': 6, + 'commandName': 'ConnectNetwork', + 'args': { + 'networkID': 'bytes', + 'breadcrumb': 'int' + } + }, + 8: { + 'commandId': 8, + 'commandName': 'ReorderNetwork', + 'args': { + 'networkID': 'bytes', + 'networkIndex': 'int', + 'breadcrumb': 'int' + } + } + }, + 'attributes': { + 0: { + 'attributeName': 'MaxNetworks', + 'attributeId': 0, + 'type': 'int', + 'reportable': true + }, + 1: { + 'attributeName': 'Networks', + 'attributeId': 1, + 'type': '', + 'reportable': true + }, + 2: { + 'attributeName': 'ScanMaxTimeSeconds', + 'attributeId': 2, + 'type': 'int', + 'reportable': true + }, + 3: { + 'attributeName': 'ConnectMaxTimeSeconds', + 'attributeId': 3, + 'type': 'int', + 'reportable': true + }, + 4: { + 'attributeName': 'InterfaceEnabled', + 'attributeId': 4, + 'type': 'bool', + 'reportable': true, + 'writable': true + }, + 5: { + 'attributeName': 'LastNetworkingStatus', + 'attributeId': 5, + 'type': 'int', + 'reportable': true + }, + 6: { + 'attributeName': 'LastNetworkID', + 'attributeId': 6, + 'type': 'bytes', + 'reportable': true + }, + 7: { + 'attributeName': 'LastConnectErrorValue', + 'attributeId': 7, + 'type': 'int', + 'reportable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'DiagnosticLogs': { + 'clusterName': 'DiagnosticLogs', + 'clusterId': 50, + 'commands': { + 0: { + 'commandId': 0, + 'commandName': 'RetrieveLogsRequest', + 'args': { + 'intent': 'int', + 'requestedProtocol': 'int', + 'transferFileDesignator': 'bytes' + } + } + }, + 'attributes': { + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'GeneralDiagnostics': { + 'clusterName': 'GeneralDiagnostics', + 'clusterId': 51, + 'commands': { + 0: { + 'commandId': 0, + 'commandName': 'TestEventTrigger', + 'args': { + 'enableKey': 'bytes', + 'eventTrigger': 'int' + } + } + }, + 'attributes': { + 0: { + 'attributeName': 'NetworkInterfaces', + 'attributeId': 0, + 'type': '', + 'reportable': true + }, + 1: { + 'attributeName': 'RebootCount', + 'attributeId': 1, + 'type': 'int', + 'reportable': true + }, + 2: { + 'attributeName': 'UpTime', + 'attributeId': 2, + 'type': 'int', + 'reportable': true + }, + 3: { + 'attributeName': 'TotalOperationalHours', + 'attributeId': 3, + 'type': 'int', + 'reportable': true + }, + 4: { + 'attributeName': 'BootReasons', + 'attributeId': 4, + 'type': 'int', + 'reportable': true + }, + 5: { + 'attributeName': 'ActiveHardwareFaults', + 'attributeId': 5, + 'type': 'int', + 'reportable': true + }, + 6: { + 'attributeName': 'ActiveRadioFaults', + 'attributeId': 6, + 'type': 'int', + 'reportable': true + }, + 7: { + 'attributeName': 'ActiveNetworkFaults', + 'attributeId': 7, + 'type': 'int', + 'reportable': true + }, + 8: { + 'attributeName': 'TestEventTriggersEnabled', + 'attributeId': 8, + 'type': 'bool', + 'reportable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'SoftwareDiagnostics': { + 'clusterName': 'SoftwareDiagnostics', + 'clusterId': 52, + 'commands': { + 0: { + 'commandId': 0, + 'commandName': 'ResetWatermarks', + 'args': {} + } + }, + 'attributes': { + 0: { + 'attributeName': 'ThreadMetrics', + 'attributeId': 0, + 'type': '', + 'reportable': true + }, + 1: { + 'attributeName': 'CurrentHeapFree', + 'attributeId': 1, + 'type': 'int', + 'reportable': true + }, + 2: { + 'attributeName': 'CurrentHeapUsed', + 'attributeId': 2, + 'type': 'int', + 'reportable': true + }, + 3: { + 'attributeName': 'CurrentHeapHighWatermark', + 'attributeId': 3, + 'type': 'int', + 'reportable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'ThreadNetworkDiagnostics': { + 'clusterName': 'ThreadNetworkDiagnostics', + 'clusterId': 53, + 'commands': { + 0: { + 'commandId': 0, + 'commandName': 'ResetCounts', + 'args': {} + } + }, + 'attributes': { + 0: { + 'attributeName': 'Channel', + 'attributeId': 0, + 'type': 'int', + 'reportable': true + }, + 1: { + 'attributeName': 'RoutingRole', + 'attributeId': 1, + 'type': 'int', + 'reportable': true + }, + 2: { + 'attributeName': 'NetworkName', + 'attributeId': 2, + 'type': 'str', + 'reportable': true + }, + 3: { + 'attributeName': 'PanId', + 'attributeId': 3, + 'type': 'int', + 'reportable': true + }, + 4: { + 'attributeName': 'ExtendedPanId', + 'attributeId': 4, + 'type': 'int', + 'reportable': true + }, + 5: { + 'attributeName': 'MeshLocalPrefix', + 'attributeId': 5, + 'type': 'bytes', + 'reportable': true + }, + 6: { + 'attributeName': 'OverrunCount', + 'attributeId': 6, + 'type': 'int', + 'reportable': true + }, + 7: { + 'attributeName': 'NeighborTableList', + 'attributeId': 7, + 'type': '', + 'reportable': true + }, + 8: { + 'attributeName': 'RouteTableList', + 'attributeId': 8, + 'type': '', + 'reportable': true + }, + 9: { + 'attributeName': 'PartitionId', + 'attributeId': 9, + 'type': 'int', + 'reportable': true + }, + 10: { + 'attributeName': 'Weighting', + 'attributeId': 10, + 'type': 'int', + 'reportable': true + }, + 11: { + 'attributeName': 'DataVersion', + 'attributeId': 11, + 'type': 'int', + 'reportable': true + }, + 12: { + 'attributeName': 'StableDataVersion', + 'attributeId': 12, + 'type': 'int', + 'reportable': true + }, + 13: { + 'attributeName': 'LeaderRouterId', + 'attributeId': 13, + 'type': 'int', + 'reportable': true + }, + 14: { + 'attributeName': 'DetachedRoleCount', + 'attributeId': 14, + 'type': 'int', + 'reportable': true + }, + 15: { + 'attributeName': 'ChildRoleCount', + 'attributeId': 15, + 'type': 'int', + 'reportable': true + }, + 16: { + 'attributeName': 'RouterRoleCount', + 'attributeId': 16, + 'type': 'int', + 'reportable': true + }, + 17: { + 'attributeName': 'LeaderRoleCount', + 'attributeId': 17, + 'type': 'int', + 'reportable': true + }, + 18: { + 'attributeName': 'AttachAttemptCount', + 'attributeId': 18, + 'type': 'int', + 'reportable': true + }, + 19: { + 'attributeName': 'PartitionIdChangeCount', + 'attributeId': 19, + 'type': 'int', + 'reportable': true + }, + 20: { + 'attributeName': 'BetterPartitionAttachAttemptCount', + 'attributeId': 20, + 'type': 'int', + 'reportable': true + }, + 21: { + 'attributeName': 'ParentChangeCount', + 'attributeId': 21, + 'type': 'int', + 'reportable': true + }, + 22: { + 'attributeName': 'TxTotalCount', + 'attributeId': 22, + 'type': 'int', + 'reportable': true + }, + 23: { + 'attributeName': 'TxUnicastCount', + 'attributeId': 23, + 'type': 'int', + 'reportable': true + }, + 24: { + 'attributeName': 'TxBroadcastCount', + 'attributeId': 24, + 'type': 'int', + 'reportable': true + }, + 25: { + 'attributeName': 'TxAckRequestedCount', + 'attributeId': 25, + 'type': 'int', + 'reportable': true + }, + 26: { + 'attributeName': 'TxAckedCount', + 'attributeId': 26, + 'type': 'int', + 'reportable': true + }, + 27: { + 'attributeName': 'TxNoAckRequestedCount', + 'attributeId': 27, + 'type': 'int', + 'reportable': true + }, + 28: { + 'attributeName': 'TxDataCount', + 'attributeId': 28, + 'type': 'int', + 'reportable': true + }, + 29: { + 'attributeName': 'TxDataPollCount', + 'attributeId': 29, + 'type': 'int', + 'reportable': true + }, + 30: { + 'attributeName': 'TxBeaconCount', + 'attributeId': 30, + 'type': 'int', + 'reportable': true + }, + 31: { + 'attributeName': 'TxBeaconRequestCount', + 'attributeId': 31, + 'type': 'int', + 'reportable': true + }, + 32: { + 'attributeName': 'TxOtherCount', + 'attributeId': 32, + 'type': 'int', + 'reportable': true + }, + 33: { + 'attributeName': 'TxRetryCount', + 'attributeId': 33, + 'type': 'int', + 'reportable': true + }, + 34: { + 'attributeName': 'TxDirectMaxRetryExpiryCount', + 'attributeId': 34, + 'type': 'int', + 'reportable': true + }, + 35: { + 'attributeName': 'TxIndirectMaxRetryExpiryCount', + 'attributeId': 35, + 'type': 'int', + 'reportable': true + }, + 36: { + 'attributeName': 'TxErrCcaCount', + 'attributeId': 36, + 'type': 'int', + 'reportable': true + }, + 37: { + 'attributeName': 'TxErrAbortCount', + 'attributeId': 37, + 'type': 'int', + 'reportable': true + }, + 38: { + 'attributeName': 'TxErrBusyChannelCount', + 'attributeId': 38, + 'type': 'int', + 'reportable': true + }, + 39: { + 'attributeName': 'RxTotalCount', + 'attributeId': 39, + 'type': 'int', + 'reportable': true + }, + 40: { + 'attributeName': 'RxUnicastCount', + 'attributeId': 40, + 'type': 'int', + 'reportable': true + }, + 41: { + 'attributeName': 'RxBroadcastCount', + 'attributeId': 41, + 'type': 'int', + 'reportable': true + }, + 42: { + 'attributeName': 'RxDataCount', + 'attributeId': 42, + 'type': 'int', + 'reportable': true + }, + 43: { + 'attributeName': 'RxDataPollCount', + 'attributeId': 43, + 'type': 'int', + 'reportable': true + }, + 44: { + 'attributeName': 'RxBeaconCount', + 'attributeId': 44, + 'type': 'int', + 'reportable': true + }, + 45: { + 'attributeName': 'RxBeaconRequestCount', + 'attributeId': 45, + 'type': 'int', + 'reportable': true + }, + 46: { + 'attributeName': 'RxOtherCount', + 'attributeId': 46, + 'type': 'int', + 'reportable': true + }, + 47: { + 'attributeName': 'RxAddressFilteredCount', + 'attributeId': 47, + 'type': 'int', + 'reportable': true + }, + 48: { + 'attributeName': 'RxDestAddrFilteredCount', + 'attributeId': 48, + 'type': 'int', + 'reportable': true + }, + 49: { + 'attributeName': 'RxDuplicatedCount', + 'attributeId': 49, + 'type': 'int', + 'reportable': true + }, + 50: { + 'attributeName': 'RxErrNoFrameCount', + 'attributeId': 50, + 'type': 'int', + 'reportable': true + }, + 51: { + 'attributeName': 'RxErrUnknownNeighborCount', + 'attributeId': 51, + 'type': 'int', + 'reportable': true + }, + 52: { + 'attributeName': 'RxErrInvalidSrcAddrCount', + 'attributeId': 52, + 'type': 'int', + 'reportable': true + }, + 53: { + 'attributeName': 'RxErrSecCount', + 'attributeId': 53, + 'type': 'int', + 'reportable': true + }, + 54: { + 'attributeName': 'RxErrFcsCount', + 'attributeId': 54, + 'type': 'int', + 'reportable': true + }, + 55: { + 'attributeName': 'RxErrOtherCount', + 'attributeId': 55, + 'type': 'int', + 'reportable': true + }, + 56: { + 'attributeName': 'ActiveTimestamp', + 'attributeId': 56, + 'type': 'int', + 'reportable': true + }, + 57: { + 'attributeName': 'PendingTimestamp', + 'attributeId': 57, + 'type': 'int', + 'reportable': true + }, + 58: { + 'attributeName': 'Delay', + 'attributeId': 58, + 'type': 'int', + 'reportable': true + }, + 59: { + 'attributeName': 'SecurityPolicy', + 'attributeId': 59, + 'type': '', + 'reportable': true + }, + 60: { + 'attributeName': 'ChannelPage0Mask', + 'attributeId': 60, + 'type': 'bytes', + 'reportable': true + }, + 61: { + 'attributeName': 'OperationalDatasetComponents', + 'attributeId': 61, + 'type': '', + 'reportable': true + }, + 62: { + 'attributeName': 'ActiveNetworkFaultsList', + 'attributeId': 62, + 'type': 'int', + 'reportable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'WiFiNetworkDiagnostics': { + 'clusterName': 'WiFiNetworkDiagnostics', + 'clusterId': 54, + 'commands': { + 0: { + 'commandId': 0, + 'commandName': 'ResetCounts', + 'args': {} + } + }, + 'attributes': { + 0: { + 'attributeName': 'Bssid', + 'attributeId': 0, + 'type': 'bytes', + 'reportable': true + }, + 1: { + 'attributeName': 'SecurityType', + 'attributeId': 1, + 'type': 'int', + 'reportable': true + }, + 2: { + 'attributeName': 'WiFiVersion', + 'attributeId': 2, + 'type': 'int', + 'reportable': true + }, + 3: { + 'attributeName': 'ChannelNumber', + 'attributeId': 3, + 'type': 'int', + 'reportable': true + }, + 4: { + 'attributeName': 'Rssi', + 'attributeId': 4, + 'type': 'int', + 'reportable': true + }, + 5: { + 'attributeName': 'BeaconLostCount', + 'attributeId': 5, + 'type': 'int', + 'reportable': true + }, + 6: { + 'attributeName': 'BeaconRxCount', + 'attributeId': 6, + 'type': 'int', + 'reportable': true + }, + 7: { + 'attributeName': 'PacketMulticastRxCount', + 'attributeId': 7, + 'type': 'int', + 'reportable': true + }, + 8: { + 'attributeName': 'PacketMulticastTxCount', + 'attributeId': 8, + 'type': 'int', + 'reportable': true + }, + 9: { + 'attributeName': 'PacketUnicastRxCount', + 'attributeId': 9, + 'type': 'int', + 'reportable': true + }, + 10: { + 'attributeName': 'PacketUnicastTxCount', + 'attributeId': 10, + 'type': 'int', + 'reportable': true + }, + 11: { + 'attributeName': 'CurrentMaxRate', + 'attributeId': 11, + 'type': 'int', + 'reportable': true + }, + 12: { + 'attributeName': 'OverrunCount', + 'attributeId': 12, + 'type': 'int', + 'reportable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'EthernetNetworkDiagnostics': { + 'clusterName': 'EthernetNetworkDiagnostics', + 'clusterId': 55, + 'commands': { + 0: { + 'commandId': 0, + 'commandName': 'ResetCounts', + 'args': {} + } + }, + 'attributes': { + 0: { + 'attributeName': 'PHYRate', + 'attributeId': 0, + 'type': 'int', + 'reportable': true + }, + 1: { + 'attributeName': 'FullDuplex', + 'attributeId': 1, + 'type': 'bool', + 'reportable': true + }, + 2: { + 'attributeName': 'PacketRxCount', + 'attributeId': 2, + 'type': 'int', + 'reportable': true + }, + 3: { + 'attributeName': 'PacketTxCount', + 'attributeId': 3, + 'type': 'int', + 'reportable': true + }, + 4: { + 'attributeName': 'TxErrCount', + 'attributeId': 4, + 'type': 'int', + 'reportable': true + }, + 5: { + 'attributeName': 'CollisionCount', + 'attributeId': 5, + 'type': 'int', + 'reportable': true + }, + 6: { + 'attributeName': 'OverrunCount', + 'attributeId': 6, + 'type': 'int', + 'reportable': true + }, + 7: { + 'attributeName': 'CarrierDetect', + 'attributeId': 7, + 'type': 'bool', + 'reportable': true + }, + 8: { + 'attributeName': 'TimeSinceReset', + 'attributeId': 8, + 'type': 'int', + 'reportable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'BridgedDeviceBasic': { + 'clusterName': 'BridgedDeviceBasic', + 'clusterId': 57, + 'commands': {}, + 'attributes': { + 1: { + 'attributeName': 'VendorName', + 'attributeId': 1, + 'type': 'str', + 'reportable': true + }, + 2: { + 'attributeName': 'VendorID', + 'attributeId': 2, + 'type': 'int', + 'reportable': true + }, + 3: { + 'attributeName': 'ProductName', + 'attributeId': 3, + 'type': 'str', + 'reportable': true + }, + 5: { + 'attributeName': 'NodeLabel', + 'attributeId': 5, + 'type': 'str', + 'reportable': true, + 'writable': true + }, + 7: { + 'attributeName': 'HardwareVersion', + 'attributeId': 7, + 'type': 'int', + 'reportable': true + }, + 8: { + 'attributeName': 'HardwareVersionString', + 'attributeId': 8, + 'type': 'str', + 'reportable': true + }, + 9: { + 'attributeName': 'SoftwareVersion', + 'attributeId': 9, + 'type': 'int', + 'reportable': true + }, + 10: { + 'attributeName': 'SoftwareVersionString', + 'attributeId': 10, + 'type': 'str', + 'reportable': true + }, + 11: { + 'attributeName': 'ManufacturingDate', + 'attributeId': 11, + 'type': 'str', + 'reportable': true + }, + 12: { + 'attributeName': 'PartNumber', + 'attributeId': 12, + 'type': 'str', + 'reportable': true + }, + 13: { + 'attributeName': 'ProductURL', + 'attributeId': 13, + 'type': 'str', + 'reportable': true + }, + 14: { + 'attributeName': 'ProductLabel', + 'attributeId': 14, + 'type': 'str', + 'reportable': true + }, + 15: { + 'attributeName': 'SerialNumber', + 'attributeId': 15, + 'type': 'str', + 'reportable': true + }, + 17: { + 'attributeName': 'Reachable', + 'attributeId': 17, + 'type': 'bool', + 'reportable': true + }, + 18: { + 'attributeName': 'UniqueID', + 'attributeId': 18, + 'type': 'str', + 'reportable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'Switch': { + 'clusterName': 'Switch', + 'clusterId': 59, + 'commands': {}, + 'attributes': { + 0: { + 'attributeName': 'NumberOfPositions', + 'attributeId': 0, + 'type': 'int', + 'reportable': true + }, + 1: { + 'attributeName': 'CurrentPosition', + 'attributeId': 1, + 'type': 'int', + 'reportable': true + }, + 2: { + 'attributeName': 'MultiPressMax', + 'attributeId': 2, + 'type': 'int', + 'reportable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'AdministratorCommissioning': { + 'clusterName': 'AdministratorCommissioning', + 'clusterId': 60, + 'commands': { + 0: { + 'commandId': 0, + 'commandName': 'OpenCommissioningWindow', + 'args': { + 'commissioningTimeout': 'int', + 'PAKEVerifier': 'bytes', + 'discriminator': 'int', + 'iterations': 'int', + 'salt': 'bytes' + } + }, + 1: { + 'commandId': 1, + 'commandName': 'OpenBasicCommissioningWindow', + 'args': { + 'commissioningTimeout': 'int' + } + }, + 2: { + 'commandId': 2, + 'commandName': 'RevokeCommissioning', + 'args': {} + } + }, + 'attributes': { + 0: { + 'attributeName': 'WindowStatus', + 'attributeId': 0, + 'type': 'int', + 'reportable': true + }, + 1: { + 'attributeName': 'AdminFabricIndex', + 'attributeId': 1, + 'type': 'int', + 'reportable': true + }, + 2: { + 'attributeName': 'AdminVendorId', + 'attributeId': 2, + 'type': 'int', + 'reportable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'OperationalCredentials': { + 'clusterName': 'OperationalCredentials', + 'clusterId': 62, + 'commands': { + 0: { + 'commandId': 0, + 'commandName': 'AttestationRequest', + 'args': { + 'attestationNonce': 'bytes' + } + }, + 2: { + 'commandId': 2, + 'commandName': 'CertificateChainRequest', + 'args': { + 'certificateType': 'int' + } + }, + 4: { + 'commandId': 4, + 'commandName': 'CSRRequest', + 'args': { + 'CSRNonce': 'bytes', + 'isForUpdateNOC': 'bool' + } + }, + 6: { + 'commandId': 6, + 'commandName': 'AddNOC', + 'args': { + 'NOCValue': 'bytes', + 'ICACValue': 'bytes', + 'IPKValue': 'bytes', + 'caseAdminSubject': 'int', + 'adminVendorId': 'int' + } + }, + 7: { + 'commandId': 7, + 'commandName': 'UpdateNOC', + 'args': { + 'NOCValue': 'bytes', + 'ICACValue': 'bytes' + } + }, + 9: { + 'commandId': 9, + 'commandName': 'UpdateFabricLabel', + 'args': { + 'label': 'str' + } + }, + 10: { + 'commandId': 10, + 'commandName': 'RemoveFabric', + 'args': { + 'fabricIndex': 'int' + } + }, + 11: { + 'commandId': 11, + 'commandName': 'AddTrustedRootCertificate', + 'args': { + 'rootCertificate': 'bytes' + } + } + }, + 'attributes': { + 0: { + 'attributeName': 'NOCs', + 'attributeId': 0, + 'type': '', + 'reportable': true + }, + 1: { + 'attributeName': 'Fabrics', + 'attributeId': 1, + 'type': '', + 'reportable': true + }, + 2: { + 'attributeName': 'SupportedFabrics', + 'attributeId': 2, + 'type': 'int', + 'reportable': true + }, + 3: { + 'attributeName': 'CommissionedFabrics', + 'attributeId': 3, + 'type': 'int', + 'reportable': true + }, + 4: { + 'attributeName': 'TrustedRootCertificates', + 'attributeId': 4, + 'type': 'bytes', + 'reportable': true + }, + 5: { + 'attributeName': 'CurrentFabricIndex', + 'attributeId': 5, + 'type': 'int', + 'reportable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'GroupKeyManagement': { + 'clusterName': 'GroupKeyManagement', + 'clusterId': 63, + 'commands': { + 0: { + 'commandId': 0, + 'commandName': 'KeySetWrite', + 'args': { + 'groupKeySetID': 'int', + 'groupKeySecurityPolicy': 'int', + 'epochKey0': 'bytes', + 'epochStartTime0': 'int', + 'epochKey1': 'bytes', + 'epochStartTime1': 'int', + 'epochKey2': 'bytes', + 'epochStartTime2': 'int' + } + }, + 1: { + 'commandId': 1, + 'commandName': 'KeySetRead', + 'args': { + 'groupKeySetID': 'int' + } + }, + 3: { + 'commandId': 3, + 'commandName': 'KeySetRemove', + 'args': { + 'groupKeySetID': 'int' + } + }, + 4: { + 'commandId': 4, + 'commandName': 'KeySetReadAllIndices', + 'args': { + 'groupKeySetIDs': 'int' + } + } + }, + 'attributes': { + 0: { + 'attributeName': 'GroupKeyMap', + 'attributeId': 0, + 'type': '', + 'reportable': true, + 'writable': true + }, + 1: { + 'attributeName': 'GroupTable', + 'attributeId': 1, + 'type': '', + 'reportable': true + }, + 2: { + 'attributeName': 'MaxGroupsPerFabric', + 'attributeId': 2, + 'type': 'int', + 'reportable': true + }, + 3: { + 'attributeName': 'MaxGroupKeysPerFabric', + 'attributeId': 3, + 'type': 'int', + 'reportable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'FixedLabel': { + 'clusterName': 'FixedLabel', + 'clusterId': 64, + 'commands': {}, + 'attributes': { + 0: { + 'attributeName': 'LabelList', + 'attributeId': 0, + 'type': '', + 'reportable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'UserLabel': { + 'clusterName': 'UserLabel', + 'clusterId': 65, + 'commands': {}, + 'attributes': { + 0: { + 'attributeName': 'LabelList', + 'attributeId': 0, + 'type': '', + 'reportable': true, + 'writable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'BooleanState': { + 'clusterName': 'BooleanState', + 'clusterId': 69, + 'commands': {}, + 'attributes': { + 0: { + 'attributeName': 'StateValue', + 'attributeId': 0, + 'type': 'bool', + 'reportable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'ModeSelect': { + 'clusterName': 'ModeSelect', + 'clusterId': 80, + 'commands': { + 0: { + 'commandId': 0, + 'commandName': 'ChangeToMode', + 'args': { + 'newMode': 'int' + } + } + }, + 'attributes': { + 0: { + 'attributeName': 'Description', + 'attributeId': 0, + 'type': 'str', + 'reportable': true + }, + 1: { + 'attributeName': 'StandardNamespace', + 'attributeId': 1, + 'type': 'int', + 'reportable': true + }, + 2: { + 'attributeName': 'SupportedModes', + 'attributeId': 2, + 'type': '', + 'reportable': true + }, + 3: { + 'attributeName': 'CurrentMode', + 'attributeId': 3, + 'type': 'int', + 'reportable': true + }, + 4: { + 'attributeName': 'StartUpMode', + 'attributeId': 4, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 5: { + 'attributeName': 'OnMode', + 'attributeId': 5, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'DoorLock': { + 'clusterName': 'DoorLock', + 'clusterId': 257, + 'commands': { + 0: { + 'commandId': 0, + 'commandName': 'LockDoor', + 'args': { + 'pinCode': 'bytes' + } + }, + 1: { + 'commandId': 1, + 'commandName': 'UnlockDoor', + 'args': { + 'pinCode': 'bytes' + } + }, + 3: { + 'commandId': 3, + 'commandName': 'UnlockWithTimeout', + 'args': { + 'timeout': 'int', + 'pinCode': 'bytes' + } + }, + 11: { + 'commandId': 11, + 'commandName': 'SetWeekDaySchedule', + 'args': { + 'weekDayIndex': 'int', + 'userIndex': 'int', + 'daysMask': 'int', + 'startHour': 'int', + 'startMinute': 'int', + 'endHour': 'int', + 'endMinute': 'int' + } + }, + 12: { + 'commandId': 12, + 'commandName': 'GetWeekDaySchedule', + 'args': { + 'weekDayIndex': 'int', + 'userIndex': 'int' + } + }, + 13: { + 'commandId': 13, + 'commandName': 'ClearWeekDaySchedule', + 'args': { + 'weekDayIndex': 'int', + 'userIndex': 'int' + } + }, + 14: { + 'commandId': 14, + 'commandName': 'SetYearDaySchedule', + 'args': { + 'yearDayIndex': 'int', + 'userIndex': 'int', + 'localStartTime': 'int', + 'localEndTime': 'int' + } + }, + 15: { + 'commandId': 15, + 'commandName': 'GetYearDaySchedule', + 'args': { + 'yearDayIndex': 'int', + 'userIndex': 'int' + } + }, + 16: { + 'commandId': 16, + 'commandName': 'ClearYearDaySchedule', + 'args': { + 'yearDayIndex': 'int', + 'userIndex': 'int' + } + }, + 17: { + 'commandId': 17, + 'commandName': 'SetHolidaySchedule', + 'args': { + 'holidayIndex': 'int', + 'localStartTime': 'int', + 'localEndTime': 'int', + 'operatingMode': 'int' + } + }, + 18: { + 'commandId': 18, + 'commandName': 'GetHolidaySchedule', + 'args': { + 'holidayIndex': 'int' + } + }, + 19: { + 'commandId': 19, + 'commandName': 'ClearHolidaySchedule', + 'args': { + 'holidayIndex': 'int' + } + }, + 26: { + 'commandId': 26, + 'commandName': 'SetUser', + 'args': { + 'operationType': 'int', + 'userIndex': 'int', + 'userName': 'str', + 'userUniqueId': 'int', + 'userStatus': 'int', + 'userType': 'int', + 'credentialRule': 'int' + } + }, + 27: { + 'commandId': 27, + 'commandName': 'GetUser', + 'args': { + 'userIndex': 'int' + } + }, + 29: { + 'commandId': 29, + 'commandName': 'ClearUser', + 'args': { + 'userIndex': 'int' + } + }, + 34: { + 'commandId': 34, + 'commandName': 'SetCredential', + 'args': { + 'operationType': 'int', + 'credentialType': 'int', + 'credentialIndex': 'int', + 'credentialData': 'bytes', + 'userIndex': 'int', + 'userStatus': 'int', + 'userType': 'int' + } + }, + 36: { + 'commandId': 36, + 'commandName': 'GetCredentialStatus', + 'args': { + 'credentialType': 'int', + 'credentialIndex': 'int' + } + }, + 38: { + 'commandId': 38, + 'commandName': 'ClearCredential', + 'args': { + 'credentialType': 'int', + 'credentialIndex': 'int' + } + } + }, + 'attributes': { + 0: { + 'attributeName': 'LockState', + 'attributeId': 0, + 'type': 'int', + 'reportable': true + }, + 1: { + 'attributeName': 'LockType', + 'attributeId': 1, + 'type': 'int', + 'reportable': true + }, + 2: { + 'attributeName': 'ActuatorEnabled', + 'attributeId': 2, + 'type': 'bool', + 'reportable': true + }, + 3: { + 'attributeName': 'DoorState', + 'attributeId': 3, + 'type': 'int', + 'reportable': true + }, + 17: { + 'attributeName': 'NumberOfTotalUsersSupported', + 'attributeId': 17, + 'type': 'int', + 'reportable': true + }, + 18: { + 'attributeName': 'NumberOfPINUsersSupported', + 'attributeId': 18, + 'type': 'int', + 'reportable': true + }, + 19: { + 'attributeName': 'NumberOfRFIDUsersSupported', + 'attributeId': 19, + 'type': 'int', + 'reportable': true + }, + 20: { + 'attributeName': 'NumberOfWeekDaySchedulesSupportedPerUser', + 'attributeId': 20, + 'type': 'int', + 'reportable': true + }, + 21: { + 'attributeName': 'NumberOfYearDaySchedulesSupportedPerUser', + 'attributeId': 21, + 'type': 'int', + 'reportable': true + }, + 22: { + 'attributeName': 'NumberOfHolidaySchedulesSupported', + 'attributeId': 22, + 'type': 'int', + 'reportable': true + }, + 23: { + 'attributeName': 'MaxPINCodeLength', + 'attributeId': 23, + 'type': 'int', + 'reportable': true + }, + 24: { + 'attributeName': 'MinPINCodeLength', + 'attributeId': 24, + 'type': 'int', + 'reportable': true + }, + 25: { + 'attributeName': 'MaxRFIDCodeLength', + 'attributeId': 25, + 'type': 'int', + 'reportable': true + }, + 26: { + 'attributeName': 'MinRFIDCodeLength', + 'attributeId': 26, + 'type': 'int', + 'reportable': true + }, + 28: { + 'attributeName': 'NumberOfCredentialsSupportedPerUser', + 'attributeId': 28, + 'type': 'int', + 'reportable': true + }, + 33: { + 'attributeName': 'Language', + 'attributeId': 33, + 'type': 'str', + 'reportable': true, + 'writable': true + }, + 35: { + 'attributeName': 'AutoRelockTime', + 'attributeId': 35, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 36: { + 'attributeName': 'SoundVolume', + 'attributeId': 36, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 37: { + 'attributeName': 'OperatingMode', + 'attributeId': 37, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 38: { + 'attributeName': 'SupportedOperatingModes', + 'attributeId': 38, + 'type': 'int', + 'reportable': true + }, + 41: { + 'attributeName': 'EnableOneTouchLocking', + 'attributeId': 41, + 'type': 'bool', + 'reportable': true, + 'writable': true + }, + 43: { + 'attributeName': 'EnablePrivacyModeButton', + 'attributeId': 43, + 'type': 'bool', + 'reportable': true, + 'writable': true + }, + 48: { + 'attributeName': 'WrongCodeEntryLimit', + 'attributeId': 48, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 49: { + 'attributeName': 'UserCodeTemporaryDisableTime', + 'attributeId': 49, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 51: { + 'attributeName': 'RequirePINforRemoteOperation', + 'attributeId': 51, + 'type': 'bool', + 'writable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'WindowCovering': { + 'clusterName': 'WindowCovering', + 'clusterId': 258, + 'commands': { + 0: { + 'commandId': 0, + 'commandName': 'UpOrOpen', + 'args': {} + }, + 1: { + 'commandId': 1, + 'commandName': 'DownOrClose', + 'args': {} + }, + 2: { + 'commandId': 2, + 'commandName': 'StopMotion', + 'args': {} + }, + 4: { + 'commandId': 4, + 'commandName': 'GoToLiftValue', + 'args': { + 'liftValue': 'int' + } + }, + 5: { + 'commandId': 5, + 'commandName': 'GoToLiftPercentage', + 'args': { + 'liftPercent100thsValue': 'int' + } + }, + 7: { + 'commandId': 7, + 'commandName': 'GoToTiltValue', + 'args': { + 'tiltValue': 'int' + } + }, + 8: { + 'commandId': 8, + 'commandName': 'GoToTiltPercentage', + 'args': { + 'tiltPercent100thsValue': 'int' + } + } + }, + 'attributes': { + 0: { + 'attributeName': 'Type', + 'attributeId': 0, + 'type': 'int', + 'reportable': true + }, + 1: { + 'attributeName': 'PhysicalClosedLimitLift', + 'attributeId': 1, + 'type': 'int', + 'reportable': true + }, + 2: { + 'attributeName': 'PhysicalClosedLimitTilt', + 'attributeId': 2, + 'type': 'int', + 'reportable': true + }, + 3: { + 'attributeName': 'CurrentPositionLift', + 'attributeId': 3, + 'type': 'int', + 'reportable': true + }, + 4: { + 'attributeName': 'CurrentPositionTilt', + 'attributeId': 4, + 'type': 'int', + 'reportable': true + }, + 5: { + 'attributeName': 'NumberOfActuationsLift', + 'attributeId': 5, + 'type': 'int', + 'reportable': true + }, + 6: { + 'attributeName': 'NumberOfActuationsTilt', + 'attributeId': 6, + 'type': 'int', + 'reportable': true + }, + 7: { + 'attributeName': 'ConfigStatus', + 'attributeId': 7, + 'type': 'int', + 'reportable': true + }, + 8: { + 'attributeName': 'CurrentPositionLiftPercentage', + 'attributeId': 8, + 'type': 'int', + 'reportable': true + }, + 9: { + 'attributeName': 'CurrentPositionTiltPercentage', + 'attributeId': 9, + 'type': 'int', + 'reportable': true + }, + 10: { + 'attributeName': 'OperationalStatus', + 'attributeId': 10, + 'type': 'int', + 'reportable': true + }, + 11: { + 'attributeName': 'TargetPositionLiftPercent100ths', + 'attributeId': 11, + 'type': 'int', + 'reportable': true + }, + 12: { + 'attributeName': 'TargetPositionTiltPercent100ths', + 'attributeId': 12, + 'type': 'int', + 'reportable': true + }, + 13: { + 'attributeName': 'EndProductType', + 'attributeId': 13, + 'type': 'int', + 'reportable': true + }, + 14: { + 'attributeName': 'CurrentPositionLiftPercent100ths', + 'attributeId': 14, + 'type': 'int', + 'reportable': true + }, + 15: { + 'attributeName': 'CurrentPositionTiltPercent100ths', + 'attributeId': 15, + 'type': 'int', + 'reportable': true + }, + 16: { + 'attributeName': 'InstalledOpenLimitLift', + 'attributeId': 16, + 'type': 'int', + 'reportable': true + }, + 17: { + 'attributeName': 'InstalledClosedLimitLift', + 'attributeId': 17, + 'type': 'int', + 'reportable': true + }, + 18: { + 'attributeName': 'InstalledOpenLimitTilt', + 'attributeId': 18, + 'type': 'int', + 'reportable': true + }, + 19: { + 'attributeName': 'InstalledClosedLimitTilt', + 'attributeId': 19, + 'type': 'int', + 'reportable': true + }, + 23: { + 'attributeName': 'Mode', + 'attributeId': 23, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 26: { + 'attributeName': 'SafetyStatus', + 'attributeId': 26, + 'type': 'int', + 'reportable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'BarrierControl': { + 'clusterName': 'BarrierControl', + 'clusterId': 259, + 'commands': { + 0: { + 'commandId': 0, + 'commandName': 'BarrierControlGoToPercent', + 'args': { + 'percentOpen': 'int' + } + }, + 1: { + 'commandId': 1, + 'commandName': 'BarrierControlStop', + 'args': {} + } + }, + 'attributes': { + 1: { + 'attributeName': 'BarrierMovingState', + 'attributeId': 1, + 'type': 'int', + 'reportable': true + }, + 2: { + 'attributeName': 'BarrierSafetyStatus', + 'attributeId': 2, + 'type': 'int', + 'reportable': true + }, + 3: { + 'attributeName': 'BarrierCapabilities', + 'attributeId': 3, + 'type': 'int', + 'reportable': true + }, + 10: { + 'attributeName': 'BarrierPosition', + 'attributeId': 10, + 'type': 'int', + 'reportable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'PumpConfigurationAndControl': { + 'clusterName': 'PumpConfigurationAndControl', + 'clusterId': 512, + 'commands': {}, + 'attributes': { + 0: { + 'attributeName': 'MaxPressure', + 'attributeId': 0, + 'type': 'int', + 'reportable': true + }, + 1: { + 'attributeName': 'MaxSpeed', + 'attributeId': 1, + 'type': 'int', + 'reportable': true + }, + 2: { + 'attributeName': 'MaxFlow', + 'attributeId': 2, + 'type': 'int', + 'reportable': true + }, + 3: { + 'attributeName': 'MinConstPressure', + 'attributeId': 3, + 'type': 'int', + 'reportable': true + }, + 4: { + 'attributeName': 'MaxConstPressure', + 'attributeId': 4, + 'type': 'int', + 'reportable': true + }, + 5: { + 'attributeName': 'MinCompPressure', + 'attributeId': 5, + 'type': 'int', + 'reportable': true + }, + 6: { + 'attributeName': 'MaxCompPressure', + 'attributeId': 6, + 'type': 'int', + 'reportable': true + }, + 7: { + 'attributeName': 'MinConstSpeed', + 'attributeId': 7, + 'type': 'int', + 'reportable': true + }, + 8: { + 'attributeName': 'MaxConstSpeed', + 'attributeId': 8, + 'type': 'int', + 'reportable': true + }, + 9: { + 'attributeName': 'MinConstFlow', + 'attributeId': 9, + 'type': 'int', + 'reportable': true + }, + 10: { + 'attributeName': 'MaxConstFlow', + 'attributeId': 10, + 'type': 'int', + 'reportable': true + }, + 11: { + 'attributeName': 'MinConstTemp', + 'attributeId': 11, + 'type': 'int', + 'reportable': true + }, + 12: { + 'attributeName': 'MaxConstTemp', + 'attributeId': 12, + 'type': 'int', + 'reportable': true + }, + 16: { + 'attributeName': 'PumpStatus', + 'attributeId': 16, + 'type': 'int', + 'reportable': true + }, + 17: { + 'attributeName': 'EffectiveOperationMode', + 'attributeId': 17, + 'type': 'int', + 'reportable': true + }, + 18: { + 'attributeName': 'EffectiveControlMode', + 'attributeId': 18, + 'type': 'int', + 'reportable': true + }, + 19: { + 'attributeName': 'Capacity', + 'attributeId': 19, + 'type': 'int', + 'reportable': true + }, + 20: { + 'attributeName': 'Speed', + 'attributeId': 20, + 'type': 'int', + 'reportable': true + }, + 21: { + 'attributeName': 'LifetimeRunningHours', + 'attributeId': 21, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 22: { + 'attributeName': 'Power', + 'attributeId': 22, + 'type': 'int', + 'reportable': true + }, + 23: { + 'attributeName': 'LifetimeEnergyConsumed', + 'attributeId': 23, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 32: { + 'attributeName': 'OperationMode', + 'attributeId': 32, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 33: { + 'attributeName': 'ControlMode', + 'attributeId': 33, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'Thermostat': { + 'clusterName': 'Thermostat', + 'clusterId': 513, + 'commands': { + 0: { + 'commandId': 0, + 'commandName': 'SetpointRaiseLower', + 'args': { + 'mode': 'int', + 'amount': 'int' + } + }, + 1: { + 'commandId': 1, + 'commandName': 'SetWeeklySchedule', + 'args': { + 'numberOfTransitionsForSequence': 'int', + 'dayOfWeekForSequence': 'int', + 'modeForSequence': 'int', + 'transitionTime': 'int', + 'heatSetpoint': 'int', + 'coolSetpoint': 'int' + } + }, + 2: { + 'commandId': 2, + 'commandName': 'GetWeeklySchedule', + 'args': { + 'daysToReturn': 'int', + 'modeToReturn': 'int' + } + }, + 3: { + 'commandId': 3, + 'commandName': 'ClearWeeklySchedule', + 'args': {} + } + }, + 'attributes': { + 0: { + 'attributeName': 'LocalTemperature', + 'attributeId': 0, + 'type': 'int', + 'reportable': true + }, + 3: { + 'attributeName': 'AbsMinHeatSetpointLimit', + 'attributeId': 3, + 'type': 'int', + 'reportable': true + }, + 4: { + 'attributeName': 'AbsMaxHeatSetpointLimit', + 'attributeId': 4, + 'type': 'int', + 'reportable': true + }, + 5: { + 'attributeName': 'AbsMinCoolSetpointLimit', + 'attributeId': 5, + 'type': 'int', + 'reportable': true + }, + 6: { + 'attributeName': 'AbsMaxCoolSetpointLimit', + 'attributeId': 6, + 'type': 'int', + 'reportable': true + }, + 17: { + 'attributeName': 'OccupiedCoolingSetpoint', + 'attributeId': 17, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 18: { + 'attributeName': 'OccupiedHeatingSetpoint', + 'attributeId': 18, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 21: { + 'attributeName': 'MinHeatSetpointLimit', + 'attributeId': 21, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 22: { + 'attributeName': 'MaxHeatSetpointLimit', + 'attributeId': 22, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 23: { + 'attributeName': 'MinCoolSetpointLimit', + 'attributeId': 23, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 24: { + 'attributeName': 'MaxCoolSetpointLimit', + 'attributeId': 24, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 25: { + 'attributeName': 'MinSetpointDeadBand', + 'attributeId': 25, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 27: { + 'attributeName': 'ControlSequenceOfOperation', + 'attributeId': 27, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 28: { + 'attributeName': 'SystemMode', + 'attributeId': 28, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 32: { + 'attributeName': 'StartOfWeek', + 'attributeId': 32, + 'type': 'int', + 'reportable': true + }, + 33: { + 'attributeName': 'NumberOfWeeklyTransitions', + 'attributeId': 33, + 'type': 'int', + 'reportable': true + }, + 34: { + 'attributeName': 'NumberOfDailyTransitions', + 'attributeId': 34, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'FanControl': { + 'clusterName': 'FanControl', + 'clusterId': 514, + 'commands': {}, + 'attributes': { + 0: { + 'attributeName': 'FanMode', + 'attributeId': 0, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 1: { + 'attributeName': 'FanModeSequence', + 'attributeId': 1, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 2: { + 'attributeName': 'PercentSetting', + 'attributeId': 2, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 3: { + 'attributeName': 'PercentCurrent', + 'attributeId': 3, + 'type': 'int', + 'reportable': true + }, + 4: { + 'attributeName': 'SpeedMax', + 'attributeId': 4, + 'type': 'int', + 'reportable': true + }, + 5: { + 'attributeName': 'SpeedSetting', + 'attributeId': 5, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 6: { + 'attributeName': 'SpeedCurrent', + 'attributeId': 6, + 'type': 'int', + 'reportable': true + }, + 7: { + 'attributeName': 'RockSupport', + 'attributeId': 7, + 'type': 'int', + 'reportable': true + }, + 8: { + 'attributeName': 'RockSetting', + 'attributeId': 8, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 9: { + 'attributeName': 'WindSupport', + 'attributeId': 9, + 'type': 'int', + 'reportable': true + }, + 10: { + 'attributeName': 'WindSetting', + 'attributeId': 10, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'ThermostatUserInterfaceConfiguration': { + 'clusterName': 'ThermostatUserInterfaceConfiguration', + 'clusterId': 516, + 'commands': {}, + 'attributes': { + 0: { + 'attributeName': 'TemperatureDisplayMode', + 'attributeId': 0, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 1: { + 'attributeName': 'KeypadLockout', + 'attributeId': 1, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 2: { + 'attributeName': 'ScheduleProgrammingVisibility', + 'attributeId': 2, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'ColorControl': { + 'clusterName': 'ColorControl', + 'clusterId': 768, + 'commands': { + 0: { + 'commandId': 0, + 'commandName': 'MoveToHue', + 'args': { + 'hue': 'int', + 'direction': 'int', + 'transitionTime': 'int', + 'optionsMask': 'int', + 'optionsOverride': 'int' + } + }, + 1: { + 'commandId': 1, + 'commandName': 'MoveHue', + 'args': { + 'moveMode': 'int', + 'rate': 'int', + 'optionsMask': 'int', + 'optionsOverride': 'int' + } + }, + 2: { + 'commandId': 2, + 'commandName': 'StepHue', + 'args': { + 'stepMode': 'int', + 'stepSize': 'int', + 'transitionTime': 'int', + 'optionsMask': 'int', + 'optionsOverride': 'int' + } + }, + 3: { + 'commandId': 3, + 'commandName': 'MoveToSaturation', + 'args': { + 'saturation': 'int', + 'transitionTime': 'int', + 'optionsMask': 'int', + 'optionsOverride': 'int' + } + }, + 4: { + 'commandId': 4, + 'commandName': 'MoveSaturation', + 'args': { + 'moveMode': 'int', + 'rate': 'int', + 'optionsMask': 'int', + 'optionsOverride': 'int' + } + }, + 5: { + 'commandId': 5, + 'commandName': 'StepSaturation', + 'args': { + 'stepMode': 'int', + 'stepSize': 'int', + 'transitionTime': 'int', + 'optionsMask': 'int', + 'optionsOverride': 'int' + } + }, + 6: { + 'commandId': 6, + 'commandName': 'MoveToHueAndSaturation', + 'args': { + 'hue': 'int', + 'saturation': 'int', + 'transitionTime': 'int', + 'optionsMask': 'int', + 'optionsOverride': 'int' + } + }, + 7: { + 'commandId': 7, + 'commandName': 'MoveToColor', + 'args': { + 'colorX': 'int', + 'colorY': 'int', + 'transitionTime': 'int', + 'optionsMask': 'int', + 'optionsOverride': 'int' + } + }, + 8: { + 'commandId': 8, + 'commandName': 'MoveColor', + 'args': { + 'rateX': 'int', + 'rateY': 'int', + 'optionsMask': 'int', + 'optionsOverride': 'int' + } + }, + 9: { + 'commandId': 9, + 'commandName': 'StepColor', + 'args': { + 'stepX': 'int', + 'stepY': 'int', + 'transitionTime': 'int', + 'optionsMask': 'int', + 'optionsOverride': 'int' + } + }, + 10: { + 'commandId': 10, + 'commandName': 'MoveToColorTemperature', + 'args': { + 'colorTemperature': 'int', + 'transitionTime': 'int', + 'optionsMask': 'int', + 'optionsOverride': 'int' + } + }, + 64: { + 'commandId': 64, + 'commandName': 'EnhancedMoveToHue', + 'args': { + 'enhancedHue': 'int', + 'direction': 'int', + 'transitionTime': 'int', + 'optionsMask': 'int', + 'optionsOverride': 'int' + } + }, + 65: { + 'commandId': 65, + 'commandName': 'EnhancedMoveHue', + 'args': { + 'moveMode': 'int', + 'rate': 'int', + 'optionsMask': 'int', + 'optionsOverride': 'int' + } + }, + 66: { + 'commandId': 66, + 'commandName': 'EnhancedStepHue', + 'args': { + 'stepMode': 'int', + 'stepSize': 'int', + 'transitionTime': 'int', + 'optionsMask': 'int', + 'optionsOverride': 'int' + } + }, + 67: { + 'commandId': 67, + 'commandName': 'EnhancedMoveToHueAndSaturation', + 'args': { + 'enhancedHue': 'int', + 'saturation': 'int', + 'transitionTime': 'int', + 'optionsMask': 'int', + 'optionsOverride': 'int' + } + }, + 68: { + 'commandId': 68, + 'commandName': 'ColorLoopSet', + 'args': { + 'updateFlags': 'int', + 'action': 'int', + 'direction': 'int', + 'time': 'int', + 'startHue': 'int', + 'optionsMask': 'int', + 'optionsOverride': 'int' + } + }, + 71: { + 'commandId': 71, + 'commandName': 'StopMoveStep', + 'args': { + 'optionsMask': 'int', + 'optionsOverride': 'int' + } + }, + 75: { + 'commandId': 75, + 'commandName': 'MoveColorTemperature', + 'args': { + 'moveMode': 'int', + 'rate': 'int', + 'colorTemperatureMinimumMireds': 'int', + 'colorTemperatureMaximumMireds': 'int', + 'optionsMask': 'int', + 'optionsOverride': 'int' + } + }, + 76: { + 'commandId': 76, + 'commandName': 'StepColorTemperature', + 'args': { + 'stepMode': 'int', + 'stepSize': 'int', + 'transitionTime': 'int', + 'colorTemperatureMinimumMireds': 'int', + 'colorTemperatureMaximumMireds': 'int', + 'optionsMask': 'int', + 'optionsOverride': 'int' + } + } + }, + 'attributes': { + 0: { + 'attributeName': 'CurrentHue', + 'attributeId': 0, + 'type': 'int', + 'reportable': true + }, + 1: { + 'attributeName': 'CurrentSaturation', + 'attributeId': 1, + 'type': 'int', + 'reportable': true + }, + 2: { + 'attributeName': 'RemainingTime', + 'attributeId': 2, + 'type': 'int', + 'reportable': true + }, + 3: { + 'attributeName': 'CurrentX', + 'attributeId': 3, + 'type': 'int', + 'reportable': true + }, + 4: { + 'attributeName': 'CurrentY', + 'attributeId': 4, + 'type': 'int', + 'reportable': true + }, + 5: { + 'attributeName': 'DriftCompensation', + 'attributeId': 5, + 'type': 'int', + 'reportable': true + }, + 6: { + 'attributeName': 'CompensationText', + 'attributeId': 6, + 'type': 'str', + 'reportable': true + }, + 7: { + 'attributeName': 'ColorTemperatureMireds', + 'attributeId': 7, + 'type': 'int', + 'reportable': true + }, + 8: { + 'attributeName': 'ColorMode', + 'attributeId': 8, + 'type': 'int', + 'reportable': true + }, + 15: { + 'attributeName': 'Options', + 'attributeId': 15, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 16: { + 'attributeName': 'NumberOfPrimaries', + 'attributeId': 16, + 'type': 'int', + 'reportable': true + }, + 17: { + 'attributeName': 'Primary1X', + 'attributeId': 17, + 'type': 'int', + 'reportable': true + }, + 18: { + 'attributeName': 'Primary1Y', + 'attributeId': 18, + 'type': 'int', + 'reportable': true + }, + 19: { + 'attributeName': 'Primary1Intensity', + 'attributeId': 19, + 'type': 'int', + 'reportable': true + }, + 21: { + 'attributeName': 'Primary2X', + 'attributeId': 21, + 'type': 'int', + 'reportable': true + }, + 22: { + 'attributeName': 'Primary2Y', + 'attributeId': 22, + 'type': 'int', + 'reportable': true + }, + 23: { + 'attributeName': 'Primary2Intensity', + 'attributeId': 23, + 'type': 'int', + 'reportable': true + }, + 25: { + 'attributeName': 'Primary3X', + 'attributeId': 25, + 'type': 'int', + 'reportable': true + }, + 26: { + 'attributeName': 'Primary3Y', + 'attributeId': 26, + 'type': 'int', + 'reportable': true + }, + 27: { + 'attributeName': 'Primary3Intensity', + 'attributeId': 27, + 'type': 'int', + 'reportable': true + }, + 32: { + 'attributeName': 'Primary4X', + 'attributeId': 32, + 'type': 'int', + 'reportable': true + }, + 33: { + 'attributeName': 'Primary4Y', + 'attributeId': 33, + 'type': 'int', + 'reportable': true + }, + 34: { + 'attributeName': 'Primary4Intensity', + 'attributeId': 34, + 'type': 'int', + 'reportable': true + }, + 36: { + 'attributeName': 'Primary5X', + 'attributeId': 36, + 'type': 'int', + 'reportable': true + }, + 37: { + 'attributeName': 'Primary5Y', + 'attributeId': 37, + 'type': 'int', + 'reportable': true + }, + 38: { + 'attributeName': 'Primary5Intensity', + 'attributeId': 38, + 'type': 'int', + 'reportable': true + }, + 40: { + 'attributeName': 'Primary6X', + 'attributeId': 40, + 'type': 'int', + 'reportable': true + }, + 41: { + 'attributeName': 'Primary6Y', + 'attributeId': 41, + 'type': 'int', + 'reportable': true + }, + 42: { + 'attributeName': 'Primary6Intensity', + 'attributeId': 42, + 'type': 'int', + 'reportable': true + }, + 48: { + 'attributeName': 'WhitePointX', + 'attributeId': 48, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 49: { + 'attributeName': 'WhitePointY', + 'attributeId': 49, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 50: { + 'attributeName': 'ColorPointRX', + 'attributeId': 50, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 51: { + 'attributeName': 'ColorPointRY', + 'attributeId': 51, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 52: { + 'attributeName': 'ColorPointRIntensity', + 'attributeId': 52, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 54: { + 'attributeName': 'ColorPointGX', + 'attributeId': 54, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 55: { + 'attributeName': 'ColorPointGY', + 'attributeId': 55, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 56: { + 'attributeName': 'ColorPointGIntensity', + 'attributeId': 56, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 58: { + 'attributeName': 'ColorPointBX', + 'attributeId': 58, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 59: { + 'attributeName': 'ColorPointBY', + 'attributeId': 59, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 60: { + 'attributeName': 'ColorPointBIntensity', + 'attributeId': 60, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 16384: { + 'attributeName': 'EnhancedCurrentHue', + 'attributeId': 16384, + 'type': 'int', + 'reportable': true + }, + 16385: { + 'attributeName': 'EnhancedColorMode', + 'attributeId': 16385, + 'type': 'int', + 'reportable': true + }, + 16386: { + 'attributeName': 'ColorLoopActive', + 'attributeId': 16386, + 'type': 'int', + 'reportable': true + }, + 16387: { + 'attributeName': 'ColorLoopDirection', + 'attributeId': 16387, + 'type': 'int', + 'reportable': true + }, + 16388: { + 'attributeName': 'ColorLoopTime', + 'attributeId': 16388, + 'type': 'int', + 'reportable': true + }, + 16389: { + 'attributeName': 'ColorLoopStartEnhancedHue', + 'attributeId': 16389, + 'type': 'int', + 'reportable': true + }, + 16390: { + 'attributeName': 'ColorLoopStoredEnhancedHue', + 'attributeId': 16390, + 'type': 'int', + 'reportable': true + }, + 16394: { + 'attributeName': 'ColorCapabilities', + 'attributeId': 16394, + 'type': 'int', + 'reportable': true + }, + 16395: { + 'attributeName': 'ColorTempPhysicalMinMireds', + 'attributeId': 16395, + 'type': 'int', + 'reportable': true + }, + 16396: { + 'attributeName': 'ColorTempPhysicalMaxMireds', + 'attributeId': 16396, + 'type': 'int', + 'reportable': true + }, + 16397: { + 'attributeName': 'CoupleColorTempToLevelMinMireds', + 'attributeId': 16397, + 'type': 'int', + 'reportable': true + }, + 16400: { + 'attributeName': 'StartUpColorTemperatureMireds', + 'attributeId': 16400, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'BallastConfiguration': { + 'clusterName': 'BallastConfiguration', + 'clusterId': 769, + 'commands': {}, + 'attributes': { + 0: { + 'attributeName': 'PhysicalMinLevel', + 'attributeId': 0, + 'type': 'int', + 'reportable': true + }, + 1: { + 'attributeName': 'PhysicalMaxLevel', + 'attributeId': 1, + 'type': 'int', + 'reportable': true + }, + 2: { + 'attributeName': 'BallastStatus', + 'attributeId': 2, + 'type': 'int', + 'reportable': true + }, + 16: { + 'attributeName': 'MinLevel', + 'attributeId': 16, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 17: { + 'attributeName': 'MaxLevel', + 'attributeId': 17, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 20: { + 'attributeName': 'IntrinsicBalanceFactor', + 'attributeId': 20, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 21: { + 'attributeName': 'BallastFactorAdjustment', + 'attributeId': 21, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 32: { + 'attributeName': 'LampQuantity', + 'attributeId': 32, + 'type': 'int', + 'reportable': true + }, + 48: { + 'attributeName': 'LampType', + 'attributeId': 48, + 'type': 'str', + 'reportable': true, + 'writable': true + }, + 49: { + 'attributeName': 'LampManufacturer', + 'attributeId': 49, + 'type': 'str', + 'reportable': true, + 'writable': true + }, + 50: { + 'attributeName': 'LampRatedHours', + 'attributeId': 50, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 51: { + 'attributeName': 'LampBurnHours', + 'attributeId': 51, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 52: { + 'attributeName': 'LampAlarmMode', + 'attributeId': 52, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 53: { + 'attributeName': 'LampBurnHoursTripPoint', + 'attributeId': 53, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'IlluminanceMeasurement': { + 'clusterName': 'IlluminanceMeasurement', + 'clusterId': 1024, + 'commands': {}, + 'attributes': { + 0: { + 'attributeName': 'MeasuredValue', + 'attributeId': 0, + 'type': 'int', + 'reportable': true + }, + 1: { + 'attributeName': 'MinMeasuredValue', + 'attributeId': 1, + 'type': 'int', + 'reportable': true + }, + 2: { + 'attributeName': 'MaxMeasuredValue', + 'attributeId': 2, + 'type': 'int', + 'reportable': true + }, + 3: { + 'attributeName': 'Tolerance', + 'attributeId': 3, + 'type': 'int', + 'reportable': true + }, + 4: { + 'attributeName': 'LightSensorType', + 'attributeId': 4, + 'type': 'int', + 'reportable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'TemperatureMeasurement': { + 'clusterName': 'TemperatureMeasurement', + 'clusterId': 1026, + 'commands': {}, + 'attributes': { + 0: { + 'attributeName': 'MeasuredValue', + 'attributeId': 0, + 'type': 'int', + 'reportable': true + }, + 1: { + 'attributeName': 'MinMeasuredValue', + 'attributeId': 1, + 'type': 'int', + 'reportable': true + }, + 2: { + 'attributeName': 'MaxMeasuredValue', + 'attributeId': 2, + 'type': 'int', + 'reportable': true + }, + 3: { + 'attributeName': 'Tolerance', + 'attributeId': 3, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'PressureMeasurement': { + 'clusterName': 'PressureMeasurement', + 'clusterId': 1027, + 'commands': {}, + 'attributes': { + 0: { + 'attributeName': 'MeasuredValue', + 'attributeId': 0, + 'type': 'int', + 'reportable': true + }, + 1: { + 'attributeName': 'MinMeasuredValue', + 'attributeId': 1, + 'type': 'int', + 'reportable': true + }, + 2: { + 'attributeName': 'MaxMeasuredValue', + 'attributeId': 2, + 'type': 'int', + 'reportable': true + }, + 3: { + 'attributeName': 'Tolerance', + 'attributeId': 3, + 'type': 'int', + 'reportable': true + }, + 16: { + 'attributeName': 'ScaledValue', + 'attributeId': 16, + 'type': 'int', + 'reportable': true + }, + 17: { + 'attributeName': 'MinScaledValue', + 'attributeId': 17, + 'type': 'int', + 'reportable': true + }, + 18: { + 'attributeName': 'MaxScaledValue', + 'attributeId': 18, + 'type': 'int', + 'reportable': true + }, + 19: { + 'attributeName': 'ScaledTolerance', + 'attributeId': 19, + 'type': 'int', + 'reportable': true + }, + 20: { + 'attributeName': 'Scale', + 'attributeId': 20, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'FlowMeasurement': { + 'clusterName': 'FlowMeasurement', + 'clusterId': 1028, + 'commands': {}, + 'attributes': { + 0: { + 'attributeName': 'MeasuredValue', + 'attributeId': 0, + 'type': 'int', + 'reportable': true + }, + 1: { + 'attributeName': 'MinMeasuredValue', + 'attributeId': 1, + 'type': 'int', + 'reportable': true + }, + 2: { + 'attributeName': 'MaxMeasuredValue', + 'attributeId': 2, + 'type': 'int', + 'reportable': true + }, + 3: { + 'attributeName': 'Tolerance', + 'attributeId': 3, + 'type': 'int', + 'reportable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'RelativeHumidityMeasurement': { + 'clusterName': 'RelativeHumidityMeasurement', + 'clusterId': 1029, + 'commands': {}, + 'attributes': { + 0: { + 'attributeName': 'MeasuredValue', + 'attributeId': 0, + 'type': 'int', + 'reportable': true + }, + 1: { + 'attributeName': 'MinMeasuredValue', + 'attributeId': 1, + 'type': 'int', + 'reportable': true + }, + 2: { + 'attributeName': 'MaxMeasuredValue', + 'attributeId': 2, + 'type': 'int', + 'reportable': true + }, + 3: { + 'attributeName': 'Tolerance', + 'attributeId': 3, + 'type': 'int', + 'reportable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'OccupancySensing': { + 'clusterName': 'OccupancySensing', + 'clusterId': 1030, + 'commands': {}, + 'attributes': { + 0: { + 'attributeName': 'Occupancy', + 'attributeId': 0, + 'type': 'int', + 'reportable': true + }, + 1: { + 'attributeName': 'OccupancySensorType', + 'attributeId': 1, + 'type': 'int', + 'reportable': true + }, + 2: { + 'attributeName': 'OccupancySensorTypeBitmap', + 'attributeId': 2, + 'type': 'int', + 'reportable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'WakeOnLan': { + 'clusterName': 'WakeOnLan', + 'clusterId': 1283, + 'commands': {}, + 'attributes': { + 0: { + 'attributeName': 'MACAddress', + 'attributeId': 0, + 'type': 'str', + 'reportable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'Channel': { + 'clusterName': 'Channel', + 'clusterId': 1284, + 'commands': { + 0: { + 'commandId': 0, + 'commandName': 'ChangeChannel', + 'args': { + 'match': 'str' + } + }, + 2: { + 'commandId': 2, + 'commandName': 'ChangeChannelByNumber', + 'args': { + 'majorNumber': 'int', + 'minorNumber': 'int' + } + }, + 3: { + 'commandId': 3, + 'commandName': 'SkipChannel', + 'args': { + 'count': 'int' + } + } + }, + 'attributes': { + 0: { + 'attributeName': 'ChannelList', + 'attributeId': 0, + 'type': '', + 'reportable': true + }, + 1: { + 'attributeName': 'Lineup', + 'attributeId': 1, + 'type': '', + 'reportable': true + }, + 2: { + 'attributeName': 'CurrentChannel', + 'attributeId': 2, + 'type': '', + 'reportable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'TargetNavigator': { + 'clusterName': 'TargetNavigator', + 'clusterId': 1285, + 'commands': { + 0: { + 'commandId': 0, + 'commandName': 'NavigateTarget', + 'args': { + 'target': 'int', + 'data': 'str' + } + } + }, + 'attributes': { + 0: { + 'attributeName': 'TargetList', + 'attributeId': 0, + 'type': '', + 'reportable': true + }, + 1: { + 'attributeName': 'CurrentTarget', + 'attributeId': 1, + 'type': 'int', + 'reportable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'MediaPlayback': { + 'clusterName': 'MediaPlayback', + 'clusterId': 1286, + 'commands': { + 0: { + 'commandId': 0, + 'commandName': 'Play', + 'args': {} + }, + 1: { + 'commandId': 1, + 'commandName': 'Pause', + 'args': {} + }, + 2: { + 'commandId': 2, + 'commandName': 'StopPlayback', + 'args': {} + }, + 3: { + 'commandId': 3, + 'commandName': 'StartOver', + 'args': {} + }, + 4: { + 'commandId': 4, + 'commandName': 'Previous', + 'args': {} + }, + 5: { + 'commandId': 5, + 'commandName': 'Next', + 'args': {} + }, + 6: { + 'commandId': 6, + 'commandName': 'Rewind', + 'args': {} + }, + 7: { + 'commandId': 7, + 'commandName': 'FastForward', + 'args': {} + }, + 8: { + 'commandId': 8, + 'commandName': 'SkipForward', + 'args': { + 'deltaPositionMilliseconds': 'int' + } + }, + 9: { + 'commandId': 9, + 'commandName': 'SkipBackward', + 'args': { + 'deltaPositionMilliseconds': 'int' + } + }, + 11: { + 'commandId': 11, + 'commandName': 'Seek', + 'args': { + 'position': 'int' + } + } + }, + 'attributes': { + 0: { + 'attributeName': 'CurrentState', + 'attributeId': 0, + 'type': 'int', + 'reportable': true + }, + 1: { + 'attributeName': 'StartTime', + 'attributeId': 1, + 'type': 'int', + 'reportable': true + }, + 2: { + 'attributeName': 'Duration', + 'attributeId': 2, + 'type': 'int', + 'reportable': true + }, + 3: { + 'attributeName': 'SampledPosition', + 'attributeId': 3, + 'type': '', + 'reportable': true + }, + 4: { + 'attributeName': 'PlaybackSpeed', + 'attributeId': 4, + 'type': '', + 'reportable': true + }, + 5: { + 'attributeName': 'SeekRangeEnd', + 'attributeId': 5, + 'type': 'int', + 'reportable': true + }, + 6: { + 'attributeName': 'SeekRangeStart', + 'attributeId': 6, + 'type': 'int', + 'reportable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'MediaInput': { + 'clusterName': 'MediaInput', + 'clusterId': 1287, + 'commands': { + 0: { + 'commandId': 0, + 'commandName': 'SelectInput', + 'args': { + 'index': 'int' + } + }, + 1: { + 'commandId': 1, + 'commandName': 'ShowInputStatus', + 'args': {} + }, + 2: { + 'commandId': 2, + 'commandName': 'HideInputStatus', + 'args': {} + }, + 3: { + 'commandId': 3, + 'commandName': 'RenameInput', + 'args': { + 'index': 'int', + 'name': 'str' + } + } + }, + 'attributes': { + 0: { + 'attributeName': 'InputList', + 'attributeId': 0, + 'type': '', + 'reportable': true + }, + 1: { + 'attributeName': 'CurrentInput', + 'attributeId': 1, + 'type': 'int', + 'reportable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'LowPower': { + 'clusterName': 'LowPower', + 'clusterId': 1288, + 'commands': { + 0: { + 'commandId': 0, + 'commandName': 'Sleep', + 'args': {} + } + }, + 'attributes': { + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'KeypadInput': { + 'clusterName': 'KeypadInput', + 'clusterId': 1289, + 'commands': { + 0: { + 'commandId': 0, + 'commandName': 'SendKey', + 'args': { + 'keyCode': 'int' + } + } + }, + 'attributes': { + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'ContentLauncher': { + 'clusterName': 'ContentLauncher', + 'clusterId': 1290, + 'commands': { + 0: { + 'commandId': 0, + 'commandName': 'LaunchContent', + 'args': { + 'parameterList': '', + 'autoPlay': 'bool', + 'data': 'str' + } + }, + 1: { + 'commandId': 1, + 'commandName': 'LaunchURL', + 'args': { + 'contentURL': 'str', + 'displayString': 'str', + 'providerName': 'str', + 'background': '', + 'logo': '', + 'progressBar': '', + 'splash': '', + 'waterMark': '' + } + } + }, + 'attributes': { + 0: { + 'attributeName': 'AcceptHeader', + 'attributeId': 0, + 'type': 'str', + 'reportable': true + }, + 1: { + 'attributeName': 'SupportedStreamingProtocols', + 'attributeId': 1, + 'type': 'int', + 'reportable': true, + 'writable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'AudioOutput': { + 'clusterName': 'AudioOutput', + 'clusterId': 1291, + 'commands': { + 0: { + 'commandId': 0, + 'commandName': 'SelectOutput', + 'args': { + 'index': 'int' + } + }, + 1: { + 'commandId': 1, + 'commandName': 'RenameOutput', + 'args': { + 'index': 'int', + 'name': 'str' + } + } + }, + 'attributes': { + 0: { + 'attributeName': 'OutputList', + 'attributeId': 0, + 'type': '', + 'reportable': true + }, + 1: { + 'attributeName': 'CurrentOutput', + 'attributeId': 1, + 'type': 'int', + 'reportable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'ApplicationLauncher': { + 'clusterName': 'ApplicationLauncher', + 'clusterId': 1292, + 'commands': { + 0: { + 'commandId': 0, + 'commandName': 'LaunchApp', + 'args': { + 'catalogVendorId': 'int', + 'applicationId': 'str', + 'data': 'bytes' + } + }, + 1: { + 'commandId': 1, + 'commandName': 'StopApp', + 'args': { + 'catalogVendorId': 'int', + 'applicationId': 'str' + } + }, + 2: { + 'commandId': 2, + 'commandName': 'HideApp', + 'args': { + 'catalogVendorId': 'int', + 'applicationId': 'str' + } + } + }, + 'attributes': { + 0: { + 'attributeName': 'CatalogList', + 'attributeId': 0, + 'type': 'int', + 'reportable': true + }, + 1: { + 'attributeName': 'CurrentApp', + 'attributeId': 1, + 'type': '', + 'reportable': true, + 'writable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'ApplicationBasic': { + 'clusterName': 'ApplicationBasic', + 'clusterId': 1293, + 'commands': {}, + 'attributes': { + 0: { + 'attributeName': 'VendorName', + 'attributeId': 0, + 'type': 'str', + 'reportable': true + }, + 1: { + 'attributeName': 'VendorID', + 'attributeId': 1, + 'type': 'int', + 'reportable': true + }, + 2: { + 'attributeName': 'ApplicationName', + 'attributeId': 2, + 'type': 'str', + 'reportable': true + }, + 3: { + 'attributeName': 'ProductID', + 'attributeId': 3, + 'type': 'int', + 'reportable': true + }, + 4: { + 'attributeName': 'Application', + 'attributeId': 4, + 'type': '', + 'reportable': true + }, + 5: { + 'attributeName': 'Status', + 'attributeId': 5, + 'type': 'int', + 'reportable': true + }, + 6: { + 'attributeName': 'ApplicationVersion', + 'attributeId': 6, + 'type': 'str', + 'reportable': true + }, + 7: { + 'attributeName': 'AllowedVendorList', + 'attributeId': 7, + 'type': 'int', + 'reportable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'AccountLogin': { + 'clusterName': 'AccountLogin', + 'clusterId': 1294, + 'commands': { + 0: { + 'commandId': 0, + 'commandName': 'GetSetupPIN', + 'args': { + 'tempAccountIdentifier': 'str' + } + }, + 2: { + 'commandId': 2, + 'commandName': 'Login', + 'args': { + 'tempAccountIdentifier': 'str', + 'setupPIN': 'str' + } + }, + 3: { + 'commandId': 3, + 'commandName': 'Logout', + 'args': {} + } + }, + 'attributes': { + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + 'ElectricalMeasurement': { + 'clusterName': 'ElectricalMeasurement', + 'clusterId': 2820, + 'commands': {}, + 'attributes': { + 0: { + 'attributeName': 'MeasurementType', + 'attributeId': 0, + 'type': 'int', + 'reportable': true + }, + 772: { + 'attributeName': 'TotalActivePower', + 'attributeId': 772, + 'type': 'int', + 'reportable': true + }, + 1285: { + 'attributeName': 'RmsVoltage', + 'attributeId': 1285, + 'type': 'int', + 'reportable': true + }, + 1286: { + 'attributeName': 'RmsVoltageMin', + 'attributeId': 1286, + 'type': 'int', + 'reportable': true + }, + 1287: { + 'attributeName': 'RmsVoltageMax', + 'attributeId': 1287, + 'type': 'int', + 'reportable': true + }, + 1288: { + 'attributeName': 'RmsCurrent', + 'attributeId': 1288, + 'type': 'int', + 'reportable': true + }, + 1289: { + 'attributeName': 'RmsCurrentMin', + 'attributeId': 1289, + 'type': 'int', + 'reportable': true + }, + 1290: { + 'attributeName': 'RmsCurrentMax', + 'attributeId': 1290, + 'type': 'int', + 'reportable': true + }, + 1291: { + 'attributeName': 'ActivePower', + 'attributeId': 1291, + 'type': 'int', + 'reportable': true + }, + 1292: { + 'attributeName': 'ActivePowerMin', + 'attributeId': 1292, + 'type': 'int', + 'reportable': true + }, + 1293: { + 'attributeName': 'ActivePowerMax', + 'attributeId': 1293, + 'type': 'int', + 'reportable': true + }, + 65528: { + 'attributeName': 'GeneratedCommandList', + 'attributeId': 65528, + 'type': 'int', + 'reportable': true + }, + 65529: { + 'attributeName': 'AcceptedCommandList', + 'attributeId': 65529, + 'type': 'int', + 'reportable': true + }, + 65531: { + 'attributeName': 'AttributeList', + 'attributeId': 65531, + 'type': 'int', + 'reportable': true + }, + 65532: { + 'attributeName': 'FeatureMap', + 'attributeId': 65532, + 'type': 'int', + 'reportable': true + }, + 65533: { + 'attributeName': 'ClusterRevision', + 'attributeId': 65533, + 'type': 'int', + 'reportable': true + } + } + }, + # 'UnitTesting': { + # 'clusterName': 'UnitTesting', + # 'clusterId': 4294048773, + # 'commands': { + # 0: { + # 'commandId': 0, + # 'commandName': 'Test', + # 'args': {} + # }, + # 1: { + # 'commandId': 1, + # 'commandName': 'TestNotHandled', + # 'args': {} + # }, + # 2: { + # 'commandId': 2, + # 'commandName': 'TestSpecific', + # 'args': {} + # }, + # 3: { + # 'commandId': 3, + # 'commandName': 'TestUnknownCommand', + # 'args': {} + # }, + # 4: { + # 'commandId': 4, + # 'commandName': 'TestAddArguments', + # 'args': { + # 'arg1': 'int', + # 'arg2': 'int' + # } + # }, + # 7: { + # 'commandId': 7, + # 'commandName': 'TestStructArgumentRequest', + # 'args': { + # 'a': 'int', + # 'b': 'bool', + # 'c': 'int', + # 'd': 'bytes', + # 'e': 'str', + # 'f': 'int', + # 'g': '', + # 'h': '' + # } + # }, + # 8: { + # 'commandId': 8, + # 'commandName': 'TestNestedStructArgumentRequest', + # 'args': { + # 'a': 'int', + # 'b': 'bool', + # 'c': '' + # } + # }, + # 9: { + # 'commandId': 9, + # 'commandName': 'TestListStructArgumentRequest', + # 'args': { + # 'a': 'int', + # 'b': 'bool', + # 'c': 'int', + # 'd': 'bytes', + # 'e': 'str', + # 'f': 'int', + # 'g': '', + # 'h': '' + # } + # }, + # 10: { + # 'commandId': 10, + # 'commandName': 'TestListInt8UArgumentRequest', + # 'args': { + # 'arg1': 'int' + # } + # }, + # 11: { + # 'commandId': 11, + # 'commandName': 'TestNestedStructListArgumentRequest', + # 'args': { + # 'a': 'int', + # 'b': 'bool', + # 'c': '', + # 'd': '', + # 'e': 'int', + # 'f': 'bytes', + # 'g': 'int' + # } + # }, + # 12: { + # 'commandId': 12, + # 'commandName': 'TestListNestedStructListArgumentRequest', + # 'args': { + # 'a': 'int', + # 'b': 'bool', + # 'c': '', + # 'd': '', + # 'e': 'int', + # 'f': 'bytes', + # 'g': 'int' + # } + # }, + # 13: { + # 'commandId': 13, + # 'commandName': 'TestListInt8UReverseRequest', + # 'args': { + # 'arg1': 'int' + # } + # }, + # 14: { + # 'commandId': 14, + # 'commandName': 'TestEnumsRequest', + # 'args': { + # 'arg1': 'int', + # 'arg2': 'int' + # } + # }, + # 15: { + # 'commandId': 15, + # 'commandName': 'TestNullableOptionalRequest', + # 'args': { + # 'arg1': 'int' + # } + # }, + # 17: { + # 'commandId': 17, + # 'commandName': 'SimpleStructEchoRequest', + # 'args': { + # 'a': 'int', + # 'b': 'bool', + # 'c': 'int', + # 'd': 'bytes', + # 'e': 'str', + # 'f': 'int', + # 'g': '', + # 'h': '' + # } + # }, + # 18: { + # 'commandId': 18, + # 'commandName': 'TimedInvokeRequest', + # 'args': {} + # }, + # 19: { + # 'commandId': 19, + # 'commandName': 'TestSimpleOptionalArgumentRequest', + # 'args': { + # 'arg1': 'bool' + # } + # }, + # 20: { + # 'commandId': 20, + # 'commandName': 'TestEmitTestEventRequest', + # 'args': { + # 'arg1': 'int', + # 'arg2': 'int', + # 'arg3': 'bool' + # } + # } + # }, + # 'attributes': { + # 0: { + # 'attributeName': 'Boolean', + # 'attributeId': 0, + # 'type': 'bool', + # 'reportable': true, + # 'writable': true + # }, + # 1: { + # 'attributeName': 'Bitmap8', + # 'attributeId': 1, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 2: { + # 'attributeName': 'Bitmap16', + # 'attributeId': 2, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 3: { + # 'attributeName': 'Bitmap32', + # 'attributeId': 3, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 4: { + # 'attributeName': 'Bitmap64', + # 'attributeId': 4, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 5: { + # 'attributeName': 'Int8u', + # 'attributeId': 5, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 6: { + # 'attributeName': 'Int16u', + # 'attributeId': 6, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 7: { + # 'attributeName': 'Int24u', + # 'attributeId': 7, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 8: { + # 'attributeName': 'Int32u', + # 'attributeId': 8, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 9: { + # 'attributeName': 'Int40u', + # 'attributeId': 9, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 10: { + # 'attributeName': 'Int48u', + # 'attributeId': 10, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 11: { + # 'attributeName': 'Int56u', + # 'attributeId': 11, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 12: { + # 'attributeName': 'Int64u', + # 'attributeId': 12, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 13: { + # 'attributeName': 'Int8s', + # 'attributeId': 13, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 14: { + # 'attributeName': 'Int16s', + # 'attributeId': 14, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 15: { + # 'attributeName': 'Int24s', + # 'attributeId': 15, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 16: { + # 'attributeName': 'Int32s', + # 'attributeId': 16, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 17: { + # 'attributeName': 'Int40s', + # 'attributeId': 17, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 18: { + # 'attributeName': 'Int48s', + # 'attributeId': 18, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 19: { + # 'attributeName': 'Int56s', + # 'attributeId': 19, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 20: { + # 'attributeName': 'Int64s', + # 'attributeId': 20, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 21: { + # 'attributeName': 'Enum8', + # 'attributeId': 21, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 22: { + # 'attributeName': 'Enum16', + # 'attributeId': 22, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 23: { + # 'attributeName': 'FloatSingle', + # 'attributeId': 23, + # 'type': '', + # 'reportable': true, + # 'writable': true + # }, + # 24: { + # 'attributeName': 'FloatDouble', + # 'attributeId': 24, + # 'type': '', + # 'reportable': true, + # 'writable': true + # }, + # 25: { + # 'attributeName': 'OctetString', + # 'attributeId': 25, + # 'type': 'bytes', + # 'reportable': true, + # 'writable': true + # }, + # 26: { + # 'attributeName': 'ListInt8u', + # 'attributeId': 26, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 27: { + # 'attributeName': 'ListOctetString', + # 'attributeId': 27, + # 'type': 'bytes', + # 'reportable': true, + # 'writable': true + # }, + # 28: { + # 'attributeName': 'ListStructOctetString', + # 'attributeId': 28, + # 'type': '', + # 'reportable': true, + # 'writable': true + # }, + # 29: { + # 'attributeName': 'LongOctetString', + # 'attributeId': 29, + # 'type': 'bytes', + # 'reportable': true, + # 'writable': true + # }, + # 30: { + # 'attributeName': 'CharString', + # 'attributeId': 30, + # 'type': 'str', + # 'reportable': true, + # 'writable': true + # }, + # 31: { + # 'attributeName': 'LongCharString', + # 'attributeId': 31, + # 'type': 'str', + # 'reportable': true, + # 'writable': true + # }, + # 32: { + # 'attributeName': 'EpochUs', + # 'attributeId': 32, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 33: { + # 'attributeName': 'EpochS', + # 'attributeId': 33, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 34: { + # 'attributeName': 'VendorId', + # 'attributeId': 34, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 35: { + # 'attributeName': 'ListNullablesAndOptionalsStruct', + # 'attributeId': 35, + # 'type': '', + # 'reportable': true, + # 'writable': true + # }, + # 36: { + # 'attributeName': 'EnumAttr', + # 'attributeId': 36, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 37: { + # 'attributeName': 'StructAttr', + # 'attributeId': 37, + # 'type': '', + # 'reportable': true, + # 'writable': true + # }, + # 38: { + # 'attributeName': 'RangeRestrictedInt8u', + # 'attributeId': 38, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 39: { + # 'attributeName': 'RangeRestrictedInt8s', + # 'attributeId': 39, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 40: { + # 'attributeName': 'RangeRestrictedInt16u', + # 'attributeId': 40, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 41: { + # 'attributeName': 'RangeRestrictedInt16s', + # 'attributeId': 41, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 42: { + # 'attributeName': 'ListLongOctetString', + # 'attributeId': 42, + # 'type': 'bytes', + # 'reportable': true, + # 'writable': true + # }, + # 43: { + # 'attributeName': 'ListFabricScoped', + # 'attributeId': 43, + # 'type': '', + # 'reportable': true, + # 'writable': true + # }, + # 48: { + # 'attributeName': 'TimedWriteBoolean', + # 'attributeId': 48, + # 'type': 'bool', + # 'reportable': true, + # 'writable': true + # }, + # 49: { + # 'attributeName': 'GeneralErrorBoolean', + # 'attributeId': 49, + # 'type': 'bool', + # 'reportable': true, + # 'writable': true + # }, + # 50: { + # 'attributeName': 'ClusterErrorBoolean', + # 'attributeId': 50, + # 'type': 'bool', + # 'reportable': true, + # 'writable': true + # }, + # 255: { + # 'attributeName': 'Unsupported', + # 'attributeId': 255, + # 'type': 'bool', + # 'reportable': true, + # 'writable': true + # }, + # 16384: { + # 'attributeName': 'NullableBoolean', + # 'attributeId': 16384, + # 'type': 'bool', + # 'reportable': true, + # 'writable': true + # }, + # 16385: { + # 'attributeName': 'NullableBitmap8', + # 'attributeId': 16385, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 16386: { + # 'attributeName': 'NullableBitmap16', + # 'attributeId': 16386, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 16387: { + # 'attributeName': 'NullableBitmap32', + # 'attributeId': 16387, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 16388: { + # 'attributeName': 'NullableBitmap64', + # 'attributeId': 16388, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 16389: { + # 'attributeName': 'NullableInt8u', + # 'attributeId': 16389, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 16390: { + # 'attributeName': 'NullableInt16u', + # 'attributeId': 16390, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 16391: { + # 'attributeName': 'NullableInt24u', + # 'attributeId': 16391, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 16392: { + # 'attributeName': 'NullableInt32u', + # 'attributeId': 16392, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 16393: { + # 'attributeName': 'NullableInt40u', + # 'attributeId': 16393, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 16394: { + # 'attributeName': 'NullableInt48u', + # 'attributeId': 16394, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 16395: { + # 'attributeName': 'NullableInt56u', + # 'attributeId': 16395, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 16396: { + # 'attributeName': 'NullableInt64u', + # 'attributeId': 16396, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 16397: { + # 'attributeName': 'NullableInt8s', + # 'attributeId': 16397, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 16398: { + # 'attributeName': 'NullableInt16s', + # 'attributeId': 16398, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 16399: { + # 'attributeName': 'NullableInt24s', + # 'attributeId': 16399, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 16400: { + # 'attributeName': 'NullableInt32s', + # 'attributeId': 16400, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 16401: { + # 'attributeName': 'NullableInt40s', + # 'attributeId': 16401, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 16402: { + # 'attributeName': 'NullableInt48s', + # 'attributeId': 16402, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 16403: { + # 'attributeName': 'NullableInt56s', + # 'attributeId': 16403, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 16404: { + # 'attributeName': 'NullableInt64s', + # 'attributeId': 16404, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 16405: { + # 'attributeName': 'NullableEnum8', + # 'attributeId': 16405, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 16406: { + # 'attributeName': 'NullableEnum16', + # 'attributeId': 16406, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 16407: { + # 'attributeName': 'NullableFloatSingle', + # 'attributeId': 16407, + # 'type': '', + # 'reportable': true, + # 'writable': true + # }, + # 16408: { + # 'attributeName': 'NullableFloatDouble', + # 'attributeId': 16408, + # 'type': '', + # 'reportable': true, + # 'writable': true + # }, + # 16409: { + # 'attributeName': 'NullableOctetString', + # 'attributeId': 16409, + # 'type': 'bytes', + # 'reportable': true, + # 'writable': true + # }, + # 16414: { + # 'attributeName': 'NullableCharString', + # 'attributeId': 16414, + # 'type': 'str', + # 'reportable': true, + # 'writable': true + # }, + # 16420: { + # 'attributeName': 'NullableEnumAttr', + # 'attributeId': 16420, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 16421: { + # 'attributeName': 'NullableStruct', + # 'attributeId': 16421, + # 'type': '', + # 'reportable': true, + # 'writable': true + # }, + # 16422: { + # 'attributeName': 'NullableRangeRestrictedInt8u', + # 'attributeId': 16422, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 16423: { + # 'attributeName': 'NullableRangeRestrictedInt8s', + # 'attributeId': 16423, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 16424: { + # 'attributeName': 'NullableRangeRestrictedInt16u', + # 'attributeId': 16424, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 16425: { + # 'attributeName': 'NullableRangeRestrictedInt16s', + # 'attributeId': 16425, + # 'type': 'int', + # 'reportable': true, + # 'writable': true + # }, + # 65528: { + # 'attributeName': 'GeneratedCommandList', + # 'attributeId': 65528, + # 'type': 'int', + # 'reportable': true + # }, + # 65529: { + # 'attributeName': 'AcceptedCommandList', + # 'attributeId': 65529, + # 'type': 'int', + # 'reportable': true + # }, + # 65531: { + # 'attributeName': 'AttributeList', + # 'attributeId': 65531, + # 'type': 'int', + # 'reportable': true + # }, + # 65532: { + # 'attributeName': 'FeatureMap', + # 'attributeId': 65532, + # 'type': 'int', + # 'reportable': true + # }, + # 65533: { + # 'attributeName': 'ClusterRevision', + # 'attributeId': 65533, + # 'type': 'int', + # 'reportable': true + # } + # } + # } +} + +return _Matter_clusters diff --git a/lib/libesp32/berry_matter/library.json b/lib/libesp32/berry_matter/library.json new file mode 100644 index 000000000..fce77cc08 --- /dev/null +++ b/lib/libesp32/berry_matter/library.json @@ -0,0 +1,17 @@ +{ + "name": "Berry Matter protocol implementation", + "version": "0.1", + "description": "Implementation of the Matter protocol specification in Berry for Tasmota, acting as an end-device over Wifi", + "license": "MIT", + "homepage": "https://github.com/arendst/Tasmota", + "frameworks": "arduino", + "platforms": "espressif32", + "authors": + { + "name": "Stephan Hadinger", + "maintainer": true + }, + "build": { + "flags": [ "-I$PROJECT_DIR/include", "-includetasmota_options.h" ] + } +} \ No newline at end of file diff --git a/lib/libesp32/berry_matter/path.be b/lib/libesp32/berry_matter/path.be new file mode 100644 index 000000000..afba51adc --- /dev/null +++ b/lib/libesp32/berry_matter/path.be @@ -0,0 +1,2 @@ +# empty module +# allows stand-alone `import path` diff --git a/lib/libesp32/berry_matter/solidify_all.be b/lib/libesp32/berry_matter/solidify_all.be new file mode 100755 index 000000000..81f392870 --- /dev/null +++ b/lib/libesp32/berry_matter/solidify_all.be @@ -0,0 +1,86 @@ +#! ../berry/berry -s -g +# +# Berry solidify files +# +# `../berry/berry -s -g` + +import os +import global +import solidify +import string +import re + +import sys +sys.path().push('src/embedded') # allow to import from src/embedded + +# globals that need to exist to make compilation succeed +var globs = "path,ctypes_bytes_dyn,tasmota,ccronexpr,gpio,light,webclient,load,MD5,lv,light_state,udp," + "lv_clock,lv_clock_icon,lv_signal_arcs,lv_signal_bars,lv_wifi_arcs_icon,lv_wifi_arcs," + "lv_wifi_bars_icon,lv_wifi_bars," + "_lvgl," + "int64" + +for g:string.split(globs, ",") + global.(g) = nil +end + +var prefix_dir = "src/embedded/" +var prefix_out = "src/solidify/" + +def clean_directory(dir) + var file_list = os.listdir(dir) + for f : file_list + if f[0] == '.' continue end # ignore files starting with `.` + os.remove(dir + f) + end +end + +var pattern = "#@\\s*solidify:([A-Za-z0-9_.,]+)" + +def parse_file(fname, prefix_out) + print("Parsing: ", fname) + var f = open(prefix_dir + fname) + var src = f.read() + f.close() + # try to compile + var compiled = compile(src) + compiled() # run the compile code to instanciate the classes and modules + # output solidified + var fname_h = string.split(fname, '.be')[0] + '.h' # take whatever is before the first '.be' + var fout = open(prefix_out + "solidified_" + fname_h, "w") + fout.write(string.format("/* Solidification of %s */\n", fname_h)) + fout.write("/********************************************************************\\\n") + fout.write("* Generated code, don't edit *\n") + fout.write("\\********************************************************************/\n") + fout.write('#include "be_constobj.h"\n') + + var directives = re.searchall(pattern, src) + # print(directives) + + for directive : directives + var object_list = string.split(directive[1], ',') + var object_name = object_list[0] + var weak = (object_list.find('weak') != nil) # do we solidify with weak strings? + var o = global + var cl_name = nil + var obj_name = nil + for subname : string.split(object_name, '.') + o = o.(subname) + cl_name = obj_name + obj_name = subname + end + solidify.dump(o, weak, fout, cl_name) + end + + fout.write("/********************************************************************/\n") + fout.write("/* End of solidification */\n") + fout.close() +end + +clean_directory(prefix_out) + +var src_file_list = os.listdir(prefix_dir) +for src_file : src_file_list + if src_file[0] == '.' continue end + parse_file(src_file, prefix_out) +end diff --git a/lib/libesp32/berry_matter/src/be_matter_counter.cpp b/lib/libesp32/berry_matter/src/be_matter_counter.cpp new file mode 100644 index 000000000..a33dd6442 --- /dev/null +++ b/lib/libesp32/berry_matter/src/be_matter_counter.cpp @@ -0,0 +1,266 @@ +/* + be_matter_counter.cpp - implements Matter counters for message replay prevention + + Copyright (C) 2023 Stephan Hadinger & Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/******************************************************************** + * Matter_Counter - Support for 32 bits counter with history window + * + * This is used in Matter to detect collision and replay of packets + * See section "4.5. Message Counters" + *******************************************************************/ + +#include +#include "be_constobj.h" +#include "be_mapping.h" +#include "be_mem.h" + +#include "esp_random.h" + +#define MESSAGE_COUNTER_WINDOW_SIZE 32 + +typedef struct { + uint32_t counter; // value of the counter + std::bitset window; +} matter_counter_t; + +/* + * Initialize a local message counter with random value between [1, 2^28]. This increases the difficulty of traffic analysis + * attacks by making it harder to determine how long a particular session has been open. The initial counter is always 1 or + * higher to guarantee first message is always greater than initial peer counter set to 0. +*/ + +static void mc_randomize(matter_counter_t *c) { + // pick a random one in range 0..2^28 + esp_fill_random(&c->counter, sizeof(c->counter)); + c->counter = c->counter & 0x0FFFFFFF; // keep only 28 bits + if (c->counter == 0) { c->counter = 1; } // unfortunate event that the random generates `0` + c->window.reset(); +} + +// `Matter_Counter([counter:int]) -> instance(Matter_Counter)` +// +// Creates a new monotonic counter for sending or receiving +// If value is `0` or absent, a random counter is generated in the range 1..2^28 +static void* mc_init(bvm *vm, int32_t val) { + matter_counter_t *c = (matter_counter_t*)be_malloc(vm, sizeof(matter_counter_t)); + c->counter = val; + c->window.reset(); // reset the window + return c; +} +BE_FUNC_CTYPE_DECLARE(mc_init, "+_p", "@[i]") + +static void mc_deinit(bvm *vm, matter_counter_t *c) { + be_free(vm, c, sizeof(matter_counter_t)); +} +BE_FUNC_CTYPE_DECLARE(mc_deinit, "", "@.") + +static void mc_reset(matter_counter_t *c, int32_t val) { + c->counter = val; + c->window.reset(); +} +BE_FUNC_CTYPE_DECLARE(mc_reset, "", ".[i]") + + +int32_t mc_val(matter_counter_t *c) { + return c->counter; +} +BE_FUNC_CTYPE_DECLARE(mc_val, "i", ".") + +int32_t mc_next(matter_counter_t *c) { + if (c->counter == 0) { mc_randomize(c); } + c->counter++; + c->window <<= 1; + if (c->counter == 0) { + c->counter++; + c->window <<= 1; + } + return c->counter; +} +BE_FUNC_CTYPE_DECLARE(mc_next, "i", ".") + +// validate if the value is acceptable +// +// strict_mode is used for encrypted messages: roll-over is not permitted +// otherwise roll-over is permitted and counter in the past +// (outside of window) is allowed +// +// return `true` if ok, `false` if rejected +int32_t mc_validate(matter_counter_t *c, uint32_t new_val, bbool strict_mode) { + if (new_val == c->counter) { return bfalse; } // simple case of a collision of the last message + + if (c->counter == 0) { // first message received, accept any value + c->counter = new_val; + c->window.reset(); + return btrue; + } + + if (new_val > c->counter) { // counter is in the future, same handling for both modes + if (new_val - c->counter > MESSAGE_COUNTER_WINDOW_SIZE) { + c->window.reset(); // no index is in the window anymore, clear all + } else { + c->window <<= new_val - c->counter; + c->window[new_val - c->counter - 1] = true; // mark previous val + // adjust window + } + c->counter = new_val; + return btrue; + } else { // here: new_val < c->counter + // are we in the window? + uint32_t gap = c->counter - new_val; + if (gap <= 32) { + if (c->window[gap-1]) { + return false; // reject because already seen + } else { + c->window[gap-1] = btrue; + return true; + } + } else { + // in the past and out of the window (we ignore roll-over to simplify) + if (strict_mode) { + return bfalse; + } else { + c->counter = new_val; + c->window.reset(); + return btrue; + } + } + } +} +BE_FUNC_CTYPE_DECLARE(mc_validate, "b", ".ib") + + +static int mc_tostring(bvm *vm) { + be_getmember(vm, 1, "_p"); + matter_counter_t *c = (matter_counter_t*) be_tocomptr(vm, -1); + if (c->counter != 0) { + be_pushstring(vm, "["); + + for (uint32_t i = MESSAGE_COUNTER_WINDOW_SIZE; i > 0; i--) { + be_pushint(vm, c->window[i-1]); + be_toescape(vm, -1, 'x'); /* escape string */ + be_strconcat(vm, -2); + be_pop(vm, 1); + } + + be_pushstring(vm, "]"); + be_strconcat(vm, -2); + be_pop(vm, 1); + + be_pushint(vm, c->counter); + be_toescape(vm, -1, 'x'); /* escape string */ + be_strconcat(vm, -2); + be_pop(vm, 1); + } else { + be_pushstring(vm, "[]-"); + } + + be_return(vm); +} + +#include "be_fixed_be_class_Matter_Counter.h" + +/* @const_object_info_begin +class be_class_Matter_Counter (scope: global, name: Matter_Counter) { + _p, var + init, ctype_func(mc_init) + deinit, ctype_func(mc_deinit) + reset, ctype_func(mc_reset) + tostring, func(mc_tostring) + + val, ctype_func(mc_val) + next, ctype_func(mc_next) + validate, ctype_func(mc_validate) +} +@const_object_info_end */ + + +/* + +# Unit tests +import matter +var c = matter.Counter(100) +assert(str(c) == '[00000000000000000000000000000000]100') +assert(c.val() == 100) +assert(c.next() == 101) +assert(c.val() == 101) +assert(str(c) == '[00000000000000000000000000000000]101') + +c.reset(101) +assert(!c.validate(101, true)) +assert(str(c) == '[00000000000000000000000000000000]101') + +c.reset(101) +assert(c.validate(100, true)) +assert(str(c) == '[00000000000000000000000000000001]101') +assert(!c.validate(100, true)) +assert(str(c) == '[00000000000000000000000000000001]101') + +c.reset(101) +assert(c.validate(100, false)) +assert(str(c) == '[00000000000000000000000000000001]101') +assert(!c.validate(100, false)) +assert(str(c) == '[00000000000000000000000000000001]101') + + +c.reset(128) +assert(c.validate(96, true)) +assert(str(c) == '[10000000000000000000000000000000]128') +assert(!c.validate(95, true)) +assert(str(c) == '[10000000000000000000000000000000]128') + +c.reset(128) +assert(c.validate(96, false)) +assert(str(c) == '[10000000000000000000000000000000]128') +assert(c.validate(95, false)) +assert(str(c) == '[00000000000000000000000000000000]95') + + +c.reset(100) +# set the context as in the documentation +assert(c.validate(99, true)) +assert(c.validate(96, true)) +assert(c.validate(70, true)) +assert(str(c) == '[00100000000000000000000000001001]100') + +assert(c.validate(97, true)) +assert(str(c) == '[00100000000000000000000000001101]100') + +assert(!c.validate(100, true)) +assert(!c.validate(99, true)) +assert(!c.validate(97, true)) +assert(!c.validate(96, true)) +assert(!c.validate(70, true)) +assert(str(c) == '[00100000000000000000000000001101]100') # unchanged + +assert(c.validate(101, true)) +assert(str(c) == '[01000000000000000000000000011011]101') + +assert(c.validate(103, true)) +assert(str(c) == '[00000000000000000000000001101110]103') + +assert(!c.validate(70, true)) + +assert(c.validate(200, true)) +assert(str(c) == '[00000000000000000000000000000000]200') + +### counters for outgoing messages + +c.reset() +assert(c.val() == 0) + +*/ \ No newline at end of file diff --git a/lib/libesp32/berry_matter/src/be_matter_module.c b/lib/libesp32/berry_matter/src/be_matter_module.c new file mode 100644 index 000000000..b33a8939f --- /dev/null +++ b/lib/libesp32/berry_matter/src/be_matter_module.c @@ -0,0 +1,270 @@ +/* + be_matter_module.c - implements the high level `matter` Berry module + + Copyright (C) 2023 Stephan Hadinger & Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/******************************************************************** + * Matter global module + * + *******************************************************************/ + +#include "be_constobj.h" +#include "be_mapping.h" + +#include "be_matter_qrcode_min_js.h" + +// Matter logo +static const uint8_t MATTER_LOGO[] = + "" + ""; + +extern const bclass be_class_Matter_Counter; +extern const bclass be_class_Matter_Verhoeff; + +#include "solidify/solidified_Matter_Module.h" + +#include "../generate/be_matter_clusters.h" +#include "../generate/be_matter_opcodes.h" + +const char* matter_get_cluster_name(uint16_t cluster) { + for (const matter_cluster_t * cl = matterAllClusters; cl->id != 0xFFFF; cl++) { + if (cl->id == cluster) { + return cl->name; + } + } + return NULL; +} +BE_FUNC_CTYPE_DECLARE(matter_get_cluster_name, "s", "i") + +const char* matter_get_opcode_name(uint16_t opcode) { + for (const matter_opcode_t * op = matter_OpCodes; op->id != 0xFFFF; op++) { + if (op->id == opcode) { + return op->name; + } + } + return NULL; +} +BE_FUNC_CTYPE_DECLARE(matter_get_opcode_name, "s", "i") + +const char* matter_get_attribute_name(uint16_t cluster, uint16_t attribute) { + for (const matter_cluster_t * cl = matterAllClusters; cl->id != 0xFFFF; cl++) { + if (cl->id == cluster) { + for (const matter_attribute_t * at = cl->attributes; at->id != 0xFFFF; at++) { + if (at->id == attribute) { + return at->name; + } + } + } + } + return NULL; +} +BE_FUNC_CTYPE_DECLARE(matter_get_attribute_name, "s", "ii") + +const char* matter_get_command_name(uint16_t cluster, uint16_t command) { + for (const matter_cluster_t * cl = matterAllClusters; cl->id != 0xFFFF; cl++) { + if (cl->id == cluster) { + for (const matter_command_t * cmd = cl->commands; cmd->id != 0xFFFF; cmd++) { + if (cmd->id == command) { + return cmd->name; + } + } + } + } + return NULL; +} +BE_FUNC_CTYPE_DECLARE(matter_get_command_name, "s", "ii") + +#include "solidify/solidified_Matter_inspect.h" + +extern const bclass be_class_Matter_TLV; // need to declare it upfront because of circular reference +#include "solidify/solidified_Matter_TLV.h" +#include "solidify/solidified_Matter_IM_Data.h" +#include "solidify/solidified_Matter_UDPServer.h" +#include "solidify/solidified_Matter_Session.h" +#include "solidify/solidified_Matter_Commissioning_Data.h" +#include "solidify/solidified_Matter_Commissioning.h" +#include "solidify/solidified_Matter_Message.h" +#include "solidify/solidified_Matter_MessageHandler.h" +#include "solidify/solidified_Matter_IM.h" +#include "solidify/solidified_Matter_Plugin.h" +#include "solidify/solidified_Matter_Base38.h" +#include "solidify/solidified_Matter_UI.h" +#include "solidify/solidified_Matter_Device.h" + +#include "../generate/be_matter_certs.h" + +#include "solidify/solidified_Matter_Plugin_core.h" +#include "solidify/solidified_Matter_Plugin_Relay.h" + +/*********************************************************************************************\ + * Get a bytes() object of the certificate DAC/PAI_Cert +\*********************************************************************************************/ +static int matter_return_static_bytes(bvm *vm, const uint8* addr, size_t len) { + be_getbuiltin(vm, "bytes"); + be_pushcomptr(vm, addr); + be_pushint(vm, - len); + be_call(vm, 2); + be_pop(vm, 2); + be_return(vm); +} +static int matter_PAI_Cert_FFF1(bvm *vm) { return matter_return_static_bytes(vm, kDevelopmentPAI_Cert_FFF1, sizeof(kDevelopmentPAI_Cert_FFF1)); } +static int matter_PAI_Pub_FFF1(bvm *vm) { return matter_return_static_bytes(vm, kDevelopmentPAI_PublicKey_FFF1, sizeof(kDevelopmentPAI_PublicKey_FFF1)); } +static int matter_PAI_Priv_FFF1(bvm *vm) { return matter_return_static_bytes(vm, kDevelopmentPAI_PrivateKey_FFF1, sizeof(kDevelopmentPAI_PrivateKey_FFF1)); } +static int matter_DAC_Cert_FFF1_8000(bvm *vm) { return matter_return_static_bytes(vm, kDevelopmentDAC_Cert_FFF1_8000, sizeof(kDevelopmentDAC_Cert_FFF1_8000)); } +static int matter_DAC_Pub_FFF1_8000(bvm *vm) { return matter_return_static_bytes(vm, kDevelopmentDAC_PublicKey_FFF1_8000, sizeof(kDevelopmentDAC_PublicKey_FFF1_8000)); } +static int matter_DAC_Priv_FFF1_8000(bvm *vm) { return matter_return_static_bytes(vm, kDevelopmentDAC_PrivateKey_FFF1_8000, sizeof(kDevelopmentDAC_PrivateKey_FFF1_8000)); } +static int matter_CD_FFF1_8000(bvm *vm) { return matter_return_static_bytes(vm, kCdForAllExamples, sizeof(kCdForAllExamples)); } + + +#include "be_fixed_matter.h" + +/* @const_object_info_begin + +module matter (scope: global) { + _LOGO, comptr(MATTER_LOGO) + _QRCODE_MINJS, comptr(QRCODE_MINJS) + MATTER_OPTION, int(151) // SetOption151 enables Matter + + Verhoeff, class(be_class_Matter_Verhoeff) + Counter, class(be_class_Matter_Counter) + setmember, closure(matter_setmember_closure) + member, closure(matter_member_closure) + + get_cluster_name, ctype_func(matter_get_cluster_name) + get_attribute_name, ctype_func(matter_get_attribute_name) + get_command_name, ctype_func(matter_get_command_name) + get_opcode_name, ctype_func(matter_get_opcode_name) + TLV, class(be_class_Matter_TLV) + sort, closure(matter_sort_closure) + inspect, closure(matter_inspect_closure) + + // Status codes + SUCCESS, int(0x00) + FAILURE, int(0x01) + INVALID_SUBSCRIPTION, int(0x7D) + UNSUPPORTED_ACCESS, int(0x7E) + UNSUPPORTED_ENDPOINT, int(0x7F) + INVALID_ACTION, int(0x80) + UNSUPPORTED_COMMAND, int(0x81) + INVALID_COMMAND, int(0x85) + UNSUPPORTED_ATTRIBUTE, int(0x86) + CONSTRAINT_ERROR, int(0x87) + UNSUPPORTED_WRITE, int(0x88) + RESOURCE_EXHAUSTED, int(0x89) + NOT_FOUND, int(0x8B) + UNREPORTABLE_ATTRIBUTE, int(0x8C) + INVALID_DATA_TYPE, int(0x8D) + UNSUPPORTED_READ, int(0x8F) + DATA_VERSION_MISMATCH, int(0x92) + TIMEOUT, int(0x94) + UNSUPPORTED_NODE, int(0x9B) + BUSY, int(0x9C) + UNSUPPORTED_CLUSTER, int(0xC3) + NO_UPSTREAM_SUBSCRIP­TION, int(0xC5) + NEEDS_TIMED_INTERACTION, int(0xC6) + UNSUPPORTED_EVENT, int(0xC7) + PATHS_EXHAUSTED, int(0xC8) + TIMED_REQUEST_MISMATCH, int(0xC9) + FAILSAFE_REQUIRED, int(0xCA) + + // Matter_Data_IM classes + AttributePathIB, class(be_class_Matter_AttributePathIB) + ClusterPathIB, class(be_class_Matter_ClusterPathIB) + DataVersionFilterIB, class(be_class_Matter_DataVersionFilterIB) + AttributeDataIB, class(be_class_Matter_AttributeDataIB) + AttributeReportIB, class(be_class_Matter_AttributeReportIB) + EventFilterIB, class(be_class_Matter_EventFilterIB) + EventPathIB, class(be_class_Matter_EventPathIB) + EventDataIB, class(be_class_Matter_EventDataIB) + EventReportIB, class(be_class_Matter_EventReportIB) + CommandPathIB, class(be_class_Matter_CommandPathIB) + CommandDataIB, class(be_class_Matter_CommandDataIB) + InvokeResponseIB, class(be_class_Matter_InvokeResponseIB) + CommandStatusIB, class(be_class_Matter_CommandStatusIB) + EventStatusIB, class(be_class_Matter_EventStatusIB) + AttributeStatusIB, class(be_class_Matter_AttributeStatusIB) + StatusIB, class(be_class_Matter_StatusIB) + StatusResponseMessage, class(be_class_Matter_StatusResponseMessage) + ReadRequestMessage, class(be_class_Matter_ReadRequestMessage) + ReportDataMessage, class(be_class_Matter_ReportDataMessage) + SubscribeRequestMessage, class(be_class_Matter_SubscribeRequestMessage) + SubscribeResponseMessage, class(be_class_Matter_SubscribeResponseMessage) + WriteRequestMessage, class(be_class_Matter_WriteRequestMessage) + WriteResponseMessage, class(be_class_Matter_WriteResponseMessage) + TimedRequestMessage, class(be_class_Matter_TimedRequestMessage) + InvokeRequestMessage, class(be_class_Matter_InvokeRequestMessage) + InvokeResponseMessage, class(be_class_Matter_InvokeResponseMessage) + + // Matter Commisioning messages + PBKDFParamRequest, class(be_class_Matter_PBKDFParamRequest) + PBKDFParamResponse, class(be_class_Matter_PBKDFParamResponse) + Pake1, class(be_class_Matter_Pake1) + Pake2, class(be_class_Matter_Pake2) + Pake3, class(be_class_Matter_Pake3) + Sigma1, class(be_class_Matter_Sigma1) + Sigma2, class(be_class_Matter_Sigma2) + Sigma2Resume, class(be_class_Matter_Sigma2Resume) + Sigma3, class(be_class_Matter_Sigma3) + + Commisioning_Context, class(be_class_Matter_Commisioning_Context) + + // UDP Server + UDPPacket_sent, class(be_class_Matter_UDPPacket_sent) + UDPServer, class(be_class_Matter_UDPServer) + + // Sessions + Session, class(be_class_Matter_Session) + Session_Store, class(be_class_Matter_Session_Store) + + // Message Handler + Frame, class(be_class_Matter_Frame) + MessageHandler, class(be_class_Matter_MessageHandler) + + // Interation Model + Response_container, class(be_class_Matter_Response_container) + IM, class(be_class_Matter_IM) + Plugin_core, class(be_class_Matter_Plugin_core) + UI, class(be_class_Matter_UI) + + // Base38 for QR Code + Base38, class(be_class_Matter_Base38) + + // Matter Device core class + Device, class(be_class_Matter_Device) + + // credentials from example + PAI_Cert_FFF1, func(matter_PAI_Cert_FFF1) + PAI_Pub_FFF1, func(matter_PAI_Pub_FFF1) + PAI_Priv_FFF1, func(matter_PAI_Priv_FFF1) + DAC_Cert_FFF1_8000, func(matter_DAC_Cert_FFF1_8000) + DAC_Pub_FFF1_8000, func(matter_DAC_Pub_FFF1_8000) + DAC_Priv_FFF1_8000, func(matter_DAC_Priv_FFF1_8000) + CD_FFF1_8000, func(matter_CD_FFF1_8000) // Certification Declaration + + // Plugins + Plugin_core, class(be_class_Matter_Plugin_core) // Generic behavior common to all devices + Plugin_Relay, class(be_class_Matter_Plugin_Relay) // Relay behavior (OnOff) +} + +@const_object_info_end */ + diff --git a/lib/libesp32/berry_matter/src/be_matter_qrcode_min_js.h b/lib/libesp32/berry_matter/src/be_matter_qrcode_min_js.h new file mode 100644 index 000000000..ee97215d0 --- /dev/null +++ b/lib/libesp32/berry_matter/src/be_matter_qrcode_min_js.h @@ -0,0 +1,45 @@ +/* + be_matter_qrcode_min_js.h - solidify in Flash `qrcode.min.js` for browser-side QRCode generation in Javascript + + Copyright (C) 2023 Stephan Hadinger & Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +// Lib JS from +// from https://github.com/davidshimjs/qrcodejs +// file qrcode.min.js + +// Converter: https://tomeko.net/online_tools/cpp_text_escape.php?lang=en + +/* +The MIT License (MIT) +--------------------- +Copyright (c) 2012 davidshimjs + +Permission is hereby granted, free of charge, +to any person obtaining a copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +static const uint8_t QRCODE_MINJS[] = +"var QRCode;!function(){function a(a){this.mode=c.MODE_8BIT_BYTE,this.data=a,this.parsedData=[];for(var b=[],d=0,e=this.data.length;e>d;d++){var f=this.data.charCodeAt(d);f>65536?(b[0]=240|(1835008&f)>>>18,b[1]=128|(258048&f)>>>12,b[2]=128|(4032&f)>>>6,b[3]=128|63&f):f>2048?(b[0]=224|(61440&f)>>>12,b[1]=128|(4032&f)>>>6,b[2]=128|63&f):f>128?(b[0]=192|(1984&f)>>>6,b[1]=128|63&f):b[0]=f,this.parsedData=this.parsedData.concat(b)}this.parsedData.length!=this.data.length&&(this.parsedData.unshift(191),this.parsedData.unshift(187),this.parsedData.unshift(239))}function b(a,b){this.typeNumber=a,this.errorCorrectLevel=b,this.modules=null,this.moduleCount=0,this.dataCache=null,this.dataList=[]}function i(a,b){if(void 0==a.length)throw new Error(a.length+\"/\"+b);for(var c=0;c=f;f++){var h=0;switch(b){case d.L:h=l[f][0];break;case d.M:h=l[f][1];break;case d.Q:h=l[f][2];break;case d.H:h=l[f][3]}if(h>=e)break;c++}if(c>l.length)throw new Error(\"Too long data\");return c}function s(a){var b=encodeURI(a).toString().replace(/\\%[0-9a-fA-F]{2}/g,\"a\");return b.length+(b.length!=a?3:0)}a.prototype={getLength:function(){return this.parsedData.length},write:function(a){for(var b=0,c=this.parsedData.length;c>b;b++)a.put(this.parsedData[b],8)}},b.prototype={addData:function(b){var c=new a(b);this.dataList.push(c),this.dataCache=null},isDark:function(a,b){if(0>a||this.moduleCount<=a||0>b||this.moduleCount<=b)throw new Error(a+\",\"+b);return this.modules[a][b]},getModuleCount:function(){return this.moduleCount},make:function(){this.makeImpl(!1,this.getBestMaskPattern())},makeImpl:function(a,c){this.moduleCount=4*this.typeNumber+17,this.modules=new Array(this.moduleCount);for(var d=0;d=7&&this.setupTypeNumber(a),null==this.dataCache&&(this.dataCache=b.createData(this.typeNumber,this.errorCorrectLevel,this.dataList)),this.mapData(this.dataCache,c)},setupPositionProbePattern:function(a,b){for(var c=-1;7>=c;c++)if(!(-1>=a+c||this.moduleCount<=a+c))for(var d=-1;7>=d;d++)-1>=b+d||this.moduleCount<=b+d||(this.modules[a+c][b+d]=c>=0&&6>=c&&(0==d||6==d)||d>=0&&6>=d&&(0==c||6==c)||c>=2&&4>=c&&d>=2&&4>=d?!0:!1)},getBestMaskPattern:function(){for(var a=0,b=0,c=0;8>c;c++){this.makeImpl(!0,c);var d=f.getLostPoint(this);(0==c||a>d)&&(a=d,b=c)}return b},createMovieClip:function(a,b,c){var d=a.createEmptyMovieClip(b,c),e=1;this.make();for(var f=0;f=g;g++)for(var h=-2;2>=h;h++)this.modules[d+g][e+h]=-2==g||2==g||-2==h||2==h||0==g&&0==h?!0:!1}},setupTypeNumber:function(a){for(var b=f.getBCHTypeNumber(this.typeNumber),c=0;18>c;c++){var d=!a&&1==(1&b>>c);this.modules[Math.floor(c/3)][c%3+this.moduleCount-8-3]=d}for(var c=0;18>c;c++){var d=!a&&1==(1&b>>c);this.modules[c%3+this.moduleCount-8-3][Math.floor(c/3)]=d}},setupTypeInfo:function(a,b){for(var c=this.errorCorrectLevel<<3|b,d=f.getBCHTypeInfo(c),e=0;15>e;e++){var g=!a&&1==(1&d>>e);6>e?this.modules[e][8]=g:8>e?this.modules[e+1][8]=g:this.modules[this.moduleCount-15+e][8]=g}for(var e=0;15>e;e++){var g=!a&&1==(1&d>>e);8>e?this.modules[8][this.moduleCount-e-1]=g:9>e?this.modules[8][15-e-1+1]=g:this.modules[8][15-e-1]=g}this.modules[this.moduleCount-8][8]=!a},mapData:function(a,b){for(var c=-1,d=this.moduleCount-1,e=7,g=0,h=this.moduleCount-1;h>0;h-=2)for(6==h&&h--;;){for(var i=0;2>i;i++)if(null==this.modules[d][h-i]){var j=!1;g>>e));var k=f.getMask(b,d,h-i);k&&(j=!j),this.modules[d][h-i]=j,e--,-1==e&&(g++,e=7)}if(d+=c,0>d||this.moduleCount<=d){d-=c,c=-c;break}}}},b.PAD0=236,b.PAD1=17,b.createData=function(a,c,d){for(var e=j.getRSBlocks(a,c),g=new k,h=0;h8*l)throw new Error(\"code length overflow. (\"+g.getLengthInBits()+\">\"+8*l+\")\");for(g.getLengthInBits()+4<=8*l&&g.put(0,4);0!=g.getLengthInBits()%8;)g.putBit(!1);for(;;){if(g.getLengthInBits()>=8*l)break;if(g.put(b.PAD0,8),g.getLengthInBits()>=8*l)break;g.put(b.PAD1,8)}return b.createBytes(g,e)},b.createBytes=function(a,b){for(var c=0,d=0,e=0,g=new Array(b.length),h=new Array(b.length),j=0;j=0?p.get(q):0}}for(var r=0,m=0;mm;m++)for(var j=0;jm;m++)for(var j=0;j=0;)b^=f.G15<=0;)b^=f.G18<>>=1;return b},getPatternPosition:function(a){return f.PATTERN_POSITION_TABLE[a-1]},getMask:function(a,b,c){switch(a){case e.PATTERN000:return 0==(b+c)%2;case e.PATTERN001:return 0==b%2;case e.PATTERN010:return 0==c%3;case e.PATTERN011:return 0==(b+c)%3;case e.PATTERN100:return 0==(Math.floor(b/2)+Math.floor(c/3))%2;case e.PATTERN101:return 0==b*c%2+b*c%3;case e.PATTERN110:return 0==(b*c%2+b*c%3)%2;case e.PATTERN111:return 0==(b*c%3+(b+c)%2)%2;default:throw new Error(\"bad maskPattern:\"+a)}},getErrorCorrectPolynomial:function(a){for(var b=new i([1],0),c=0;a>c;c++)b=b.multiply(new i([1,g.gexp(c)],0));return b},getLengthInBits:function(a,b){if(b>=1&&10>b)switch(a){case c.MODE_NUMBER:return 10;case c.MODE_ALPHA_NUM:return 9;case c.MODE_8BIT_BYTE:return 8;case c.MODE_KANJI:return 8;default:throw new Error(\"mode:\"+a)}else if(27>b)switch(a){case c.MODE_NUMBER:return 12;case c.MODE_ALPHA_NUM:return 11;case c.MODE_8BIT_BYTE:return 16;case c.MODE_KANJI:return 10;default:throw new Error(\"mode:\"+a)}else{if(!(41>b))throw new Error(\"type:\"+b);switch(a){case c.MODE_NUMBER:return 14;case c.MODE_ALPHA_NUM:return 13;case c.MODE_8BIT_BYTE:return 16;case c.MODE_KANJI:return 12;default:throw new Error(\"mode:\"+a)}}},getLostPoint:function(a){for(var b=a.getModuleCount(),c=0,d=0;b>d;d++)for(var e=0;b>e;e++){for(var f=0,g=a.isDark(d,e),h=-1;1>=h;h++)if(!(0>d+h||d+h>=b))for(var i=-1;1>=i;i++)0>e+i||e+i>=b||(0!=h||0!=i)&&g==a.isDark(d+h,e+i)&&f++;f>5&&(c+=3+f-5)}for(var d=0;b-1>d;d++)for(var e=0;b-1>e;e++){var j=0;a.isDark(d,e)&&j++,a.isDark(d+1,e)&&j++,a.isDark(d,e+1)&&j++,a.isDark(d+1,e+1)&&j++,(0==j||4==j)&&(c+=3)}for(var d=0;b>d;d++)for(var e=0;b-6>e;e++)a.isDark(d,e)&&!a.isDark(d,e+1)&&a.isDark(d,e+2)&&a.isDark(d,e+3)&&a.isDark(d,e+4)&&!a.isDark(d,e+5)&&a.isDark(d,e+6)&&(c+=40);for(var e=0;b>e;e++)for(var d=0;b-6>d;d++)a.isDark(d,e)&&!a.isDark(d+1,e)&&a.isDark(d+2,e)&&a.isDark(d+3,e)&&a.isDark(d+4,e)&&!a.isDark(d+5,e)&&a.isDark(d+6,e)&&(c+=40);for(var k=0,e=0;b>e;e++)for(var d=0;b>d;d++)a.isDark(d,e)&&k++;var l=Math.abs(100*k/b/b-50)/5;return c+=10*l}},g={glog:function(a){if(1>a)throw new Error(\"glog(\"+a+\")\");return g.LOG_TABLE[a]},gexp:function(a){for(;0>a;)a+=255;for(;a>=256;)a-=255;return g.EXP_TABLE[a]},EXP_TABLE:new Array(256),LOG_TABLE:new Array(256)},h=0;8>h;h++)g.EXP_TABLE[h]=1<h;h++)g.EXP_TABLE[h]=g.EXP_TABLE[h-4]^g.EXP_TABLE[h-5]^g.EXP_TABLE[h-6]^g.EXP_TABLE[h-8];for(var h=0;255>h;h++)g.LOG_TABLE[g.EXP_TABLE[h]]=h;i.prototype={get:function(a){return this.num[a]},getLength:function(){return this.num.length},multiply:function(a){for(var b=new Array(this.getLength()+a.getLength()-1),c=0;cf;f++)for(var g=c[3*f+0],h=c[3*f+1],i=c[3*f+2],k=0;g>k;k++)e.push(new j(h,i));return e},j.getRsBlockTable=function(a,b){switch(b){case d.L:return j.RS_BLOCK_TABLE[4*(a-1)+0];case d.M:return j.RS_BLOCK_TABLE[4*(a-1)+1];case d.Q:return j.RS_BLOCK_TABLE[4*(a-1)+2];case d.H:return j.RS_BLOCK_TABLE[4*(a-1)+3];default:return void 0}},k.prototype={get:function(a){var b=Math.floor(a/8);return 1==(1&this.buffer[b]>>>7-a%8)},put:function(a,b){for(var c=0;b>c;c++)this.putBit(1==(1&a>>>b-c-1))},getLengthInBits:function(){return this.length},putBit:function(a){var b=Math.floor(this.length/8);this.buffer.length<=b&&this.buffer.push(0),a&&(this.buffer[b]|=128>>>this.length%8),this.length++}};var l=[[17,14,11,7],[32,26,20,14],[53,42,32,24],[78,62,46,34],[106,84,60,44],[134,106,74,58],[154,122,86,64],[192,152,108,84],[230,180,130,98],[271,213,151,119],[321,251,177,137],[367,287,203,155],[425,331,241,177],[458,362,258,194],[520,412,292,220],[586,450,322,250],[644,504,364,280],[718,560,394,310],[792,624,442,338],[858,666,482,382],[929,711,509,403],[1003,779,565,439],[1091,857,611,461],[1171,911,661,511],[1273,997,715,535],[1367,1059,751,593],[1465,1125,805,625],[1528,1190,868,658],[1628,1264,908,698],[1732,1370,982,742],[1840,1452,1030,790],[1952,1538,1112,842],[2068,1628,1168,898],[2188,1722,1228,958],[2303,1809,1283,983],[2431,1911,1351,1051],[2563,1989,1423,1093],[2699,2099,1499,1139],[2809,2213,1579,1219],[2953,2331,1663,1273]],o=function(){var a=function(a,b){this._el=a,this._htOption=b};return a.prototype.draw=function(a){function g(a,b){var c=document.createElementNS(\"http://www.w3.org/2000/svg\",a);for(var d in b)b.hasOwnProperty(d)&&c.setAttribute(d,b[d]);return c}var b=this._htOption,c=this._el,d=a.getModuleCount();Math.floor(b.width/d),Math.floor(b.height/d),this.clear();var h=g(\"svg\",{viewBox:\"0 0 \"+String(d)+\" \"+String(d),width:\"100%\",height:\"100%\",fill:b.colorLight});h.setAttributeNS(\"http://www.w3.org/2000/xmlns/\",\"xmlns:xlink\",\"http://www.w3.org/1999/xlink\"),c.appendChild(h),h.appendChild(g(\"rect\",{fill:b.colorDark,width:\"1\",height:\"1\",id:\"template\"}));for(var i=0;d>i;i++)for(var j=0;d>j;j++)if(a.isDark(i,j)){var k=g(\"use\",{x:String(i),y:String(j)});k.setAttributeNS(\"http://www.w3.org/1999/xlink\",\"href\",\"#template\"),h.appendChild(k)}},a.prototype.clear=function(){for(;this._el.hasChildNodes();)this._el.removeChild(this._el.lastChild)},a}(),p=\"svg\"===document.documentElement.tagName.toLowerCase(),q=p?o:m()?function(){function a(){this._elImage.src=this._elCanvas.toDataURL(\"image/png\"),this._elImage.style.display=\"block\",this._elCanvas.style.display=\"none\"}function d(a,b){var c=this;if(c._fFail=b,c._fSuccess=a,null===c._bSupportDataURI){var d=document.createElement(\"img\"),e=function(){c._bSupportDataURI=!1,c._fFail&&_fFail.call(c)},f=function(){c._bSupportDataURI=!0,c._fSuccess&&c._fSuccess.call(c)};return d.onabort=e,d.onerror=e,d.onload=f,d.src=\"data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==\",void 0}c._bSupportDataURI===!0&&c._fSuccess?c._fSuccess.call(c):c._bSupportDataURI===!1&&c._fFail&&c._fFail.call(c)}if(this._android&&this._android<=2.1){var b=1/window.devicePixelRatio,c=CanvasRenderingContext2D.prototype.drawImage;CanvasRenderingContext2D.prototype.drawImage=function(a,d,e,f,g,h,i,j){if(\"nodeName\"in a&&/img/i.test(a.nodeName))for(var l=arguments.length-1;l>=1;l--)arguments[l]=arguments[l]*b;else\"undefined\"==typeof j&&(arguments[1]*=b,arguments[2]*=b,arguments[3]*=b,arguments[4]*=b);c.apply(this,arguments)}}var e=function(a,b){this._bIsPainted=!1,this._android=n(),this._htOption=b,this._elCanvas=document.createElement(\"canvas\"),this._elCanvas.width=b.width,this._elCanvas.height=b.height,a.appendChild(this._elCanvas),this._el=a,this._oContext=this._elCanvas.getContext(\"2d\"),this._bIsPainted=!1,this._elImage=document.createElement(\"img\"),this._elImage.style.display=\"none\",this._el.appendChild(this._elImage),this._bSupportDataURI=null};return e.prototype.draw=function(a){var b=this._elImage,c=this._oContext,d=this._htOption,e=a.getModuleCount(),f=d.width/e,g=d.height/e,h=Math.round(f),i=Math.round(g);b.style.display=\"none\",this.clear();for(var j=0;e>j;j++)for(var k=0;e>k;k++){var l=a.isDark(j,k),m=k*f,n=j*g;c.strokeStyle=l?d.colorDark:d.colorLight,c.lineWidth=1,c.fillStyle=l?d.colorDark:d.colorLight,c.fillRect(m,n,f,g),c.strokeRect(Math.floor(m)+.5,Math.floor(n)+.5,h,i),c.strokeRect(Math.ceil(m)-.5,Math.ceil(n)-.5,h,i)}this._bIsPainted=!0},e.prototype.makeImage=function(){this._bIsPainted&&d.call(this,a)},e.prototype.isPainted=function(){return this._bIsPainted},e.prototype.clear=function(){this._oContext.clearRect(0,0,this._elCanvas.width,this._elCanvas.height),this._bIsPainted=!1},e.prototype.round=function(a){return a?Math.floor(1e3*a)/1e3:a},e}():function(){var a=function(a,b){this._el=a,this._htOption=b};return a.prototype.draw=function(a){for(var b=this._htOption,c=this._el,d=a.getModuleCount(),e=Math.floor(b.width/d),f=Math.floor(b.height/d),g=[''],h=0;d>h;h++){g.push(\"\");for(var i=0;d>i;i++)g.push('');g.push(\"\")}g.push(\"
\"),c.innerHTML=g.join(\"\");var j=c.childNodes[0],k=(b.width-j.offsetWidth)/2,l=(b.height-j.offsetHeight)/2;k>0&&l>0&&(j.style.margin=l+\"px \"+k+\"px\")},a.prototype.clear=function(){this._el.innerHTML=\"\"},a}();QRCode=function(a,b){if(this._htOption={width:256,height:256,typeNumber:4,colorDark:\"#000000\",colorLight:\"#ffffff\",correctLevel:d.H},\"string\"==typeof b&&(b={text:b}),b)for(var c in b)this._htOption[c]=b[c];\"string\"==typeof a&&(a=document.getElementById(a)),this._android=n(),this._el=a,this._oQRCode=null,this._oDrawing=new q(this._el,this._htOption),this._htOption.text&&this.makeCode(this._htOption.text)},QRCode.prototype.makeCode=function(a){this._oQRCode=new b(r(a,this._htOption.correctLevel),this._htOption.correctLevel),this._oQRCode.addData(a),this._oQRCode.make(),this._el.title=a,this._oDrawing.draw(this._oQRCode),this.makeImage()},QRCode.prototype.makeImage=function(){\"function\"==typeof this._oDrawing.makeImage&&(!this._android||this._android>=3)&&this._oDrawing.makeImage()},QRCode.prototype.clear=function(){this._oDrawing.clear()},QRCode.CorrectLevel=d}();" +; diff --git a/lib/libesp32/berry_matter/src/be_matter_verhoeff.cpp b/lib/libesp32/berry_matter/src/be_matter_verhoeff.cpp new file mode 100644 index 000000000..5e8f56511 --- /dev/null +++ b/lib/libesp32/berry_matter/src/be_matter_verhoeff.cpp @@ -0,0 +1,105 @@ +/* + be_matter_verhoeff.cpp - implements the Verhoeff algorithm to compute a checksum digit for QR Code + + Copyright (C) 2023 Stephan Hadinger & Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include +#include +#include "be_constobj.h" +#include "be_mapping.h" + +// code inspired from https://www.programmingalgorithms.com/algorithm/verhoeff-algorithm/c/ + +static const int8_t _multiplicationTable[10][10] = { + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, + { 1, 2, 3, 4, 0, 6, 7, 8, 9, 5 }, + { 2, 3, 4, 0, 1, 7, 8, 9, 5, 6 }, + { 3, 4, 0, 1, 2, 8, 9, 5, 6, 7 }, + { 4, 0, 1, 2, 3, 9, 5, 6, 7, 8 }, + { 5, 9, 8, 7, 6, 0, 4, 3, 2, 1 }, + { 6, 5, 9, 8, 7, 1, 0, 4, 3, 2 }, + { 7, 6, 5, 9, 8, 2, 1, 0, 4, 3 }, + { 8, 7, 6, 5, 9, 3, 2, 1, 0, 4 }, + { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 } +}; + +static const int8_t _permutationTable[10][10] = { + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, + { 1, 5, 7, 6, 2, 8, 3, 0, 9, 4 }, + { 5, 8, 0, 3, 7, 9, 6, 1, 4, 2 }, + { 8, 9, 1, 6, 0, 4, 3, 5, 2, 7 }, + { 9, 4, 5, 3, 1, 2, 6, 8, 7, 0 }, + { 4, 2, 8, 6, 5, 7, 3, 9, 0, 1 }, + { 2, 7, 9, 3, 8, 0, 6, 4, 1, 5 }, + { 7, 0, 4, 6, 9, 1, 3, 2, 5, 8 } +}; + +static const int8_t _inverseTable[10] = { 0, 4, 3, 2, 1, 5, 6, 7, 8, 9 }; + +static char ret_digit[] = "0"; // used as a placeholder to return a single digit string + +const char* vh_checksum(const char* number) { + int32_t c = 0; + int32_t len = strlen(number); + + for (int32_t i = 0; i < len; ++i) { + int8_t digit = number[len - i - 1] - '0'; + if (digit < 0) { digit = 0; } + if (digit > 9) { digit = 9; } + c = _multiplicationTable[c][_permutationTable[((i + 1) % 8)][digit]]; + } + + ret_digit[0] = _inverseTable[c] + '0'; + return ret_digit; +} +BE_FUNC_CTYPE_DECLARE(vh_checksum, "s", "s") + +static bbool vh_validate(char* number) { + int32_t c = 0; + int32_t len = strlen(number); + + for (int32_t i = 0; i < len; ++i) { + int8_t digit = number[len - i - 1] - '0'; + if (digit < 0) { digit = 0; } + if (digit > 9) { digit = 9; } + c = _multiplicationTable[c][_permutationTable[(i % 8)][digit]]; + } + return c == 0; +} +BE_FUNC_CTYPE_DECLARE(vh_validate, "b", "s") + +#include "be_fixed_be_class_Matter_Verhoeff.h" + +/* @const_object_info_begin +class be_class_Matter_Verhoeff (scope: global, name: Matter_Verhoeff) { + checksum, static_ctype_func(vh_checksum) + validate, static_ctype_func(vh_validate) +} +@const_object_info_end */ + + +/* + +# Unit tests +import matter + +assert(matter.Verhoeff.checksum("236") == "3") +assert(matter.Verhoeff.validate("236")) +assert(matter.Verhoeff.checksum("58564") == "9") +assert(matter.Verhoeff.validate("585649")) + +*/ \ No newline at end of file diff --git a/lib/libesp32/berry_matter/src/berry_tasmota.h b/lib/libesp32/berry_matter/src/berry_tasmota.h new file mode 100644 index 000000000..4d9bed92a --- /dev/null +++ b/lib/libesp32/berry_matter/src/berry_tasmota.h @@ -0,0 +1,8 @@ +// force include of module by including this file + +#ifndef __BERRY_MATTER__ +#define __BERRY_MATTER__ + + + +#endif // __BERRY_MATTER__ diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Base38.be b/lib/libesp32/berry_matter/src/embedded/Matter_Base38.be new file mode 100644 index 000000000..0992d682d --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Base38.be @@ -0,0 +1,71 @@ +# +# Matter_Base38.be - suppport for Base38 encoding which is used in QR Codes +# +# Copyright (C) 2023 Stephan Hadinger & Theo Arends +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +import matter + +#@ solidify:Matter_Base38,weak + +class Matter_Base38 + + static def encode(raw) + # encodes b38 (mutates `b`) + def b38_enc(v, l) + import string + var ENCODE = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-." + var i = 0 + var ret = "" + while i < l + ret += ENCODE[v % 38] + v = v / 38 + i += 1 + end + return ret + end + + var idx = 0 + var sz = size(raw) + var out = "" + + while idx < sz + var val + if idx + 2 < sz + # encode 3 bytes + val = raw[idx] | (raw[idx+1] << 8) | (raw[idx+2] << 16) + out += b38_enc(val, 5) + idx += 3 + elif idx + 1 < sz + # encode 2 bytes + val = raw[idx] | (raw[idx+1] << 8) + out += b38_enc(val, 4) + idx += 2 + else + # encode 1 byte + val = raw[idx] + out += b38_enc(val, 2) + idx += 1 + end + end + return out + end +end +matter.Base38 = Matter_Base38 + +#- + +-# diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Commissioning.be b/lib/libesp32/berry_matter/src/embedded/Matter_Commissioning.be new file mode 100644 index 000000000..0a027affd --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Commissioning.be @@ -0,0 +1,632 @@ +# +# Matter_Commissioning.be - suppport for Matter Commissioning process +# +# Copyright (C) 2023 Stephan Hadinger & Theo Arends +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +import matter + +#@ solidify:Matter_Commisioning_Context,weak + +################################################################################# +# Class Matter_Commisioning_Context +################################################################################# +class Matter_Commisioning_Context +# static Matter_Context_Prefix = "Matter PAKE V1 Commissioning" # spec is wrong + static var Matter_Context_Prefix = "CHIP PAKE V1 Commissioning" # from CHIP code + static var SEKeys_Info = "SessionKeys" + static var S2K_Info = "Sigma2" + static var S3K_Info = "Sigma3" + static var TBEData2_Nonce = "NCASE_Sigma2N" + static var TBEData3_Nonce = "NCASE_Sigma3N" + + var responder # reference to the caller, sending packets + var device # root device object + var spake + var future_initiator_session_id + var future_local_session_id + # used by TT hash + var PBKDFParamRequest, PBKDFParamResponse + # PAKE + var y # 32 bytes random known only by verifier + var pA, pB, cA, cB + var Ke + # CASE + var ResponderEph_priv, ResponderEph_pub + var initiatorEph_pub + # Session data + var session_timestamp + var I2RKey, R2IKey, AttestationChallenge + # is commissioning window open + var window_open + + def init(responder) + import crypto + self.responder = responder + self.device = responder.device + # generate y once + self.y = crypto.random(32) + + self.window_open = true # auto-commissioning for now + end + + def process_incoming(msg, remote_ip, remote_port) + # + if !self.window_open + tasmota.log("MTR: commissioning not open", 2) + return false + end + + tasmota.log("MTR: received message " + matter.inspect(msg), 3) + if msg.opcode == 0x20 + return self.parse_PBKDFParamRequest(msg, remote_ip, remote_port) + elif msg.opcode == 0x22 + return self.parse_Pake1(msg, remote_ip, remote_port) + elif msg.opcode == 0x24 + return self.parse_Pake3(msg, remote_ip, remote_port) + elif msg.opcode == 0x30 + return self.parse_Sigma1(msg, remote_ip, remote_port) + elif msg.opcode == 0x32 + return self.parse_Sigma3(msg, remote_ip, remote_port) + end + + return false + end + + def parse_PBKDFParamRequest(msg, addr, port) + import crypto + # sanity checks + if msg.opcode != 0x20 || msg.local_session_id != 0 || msg.protocol_id != 0 + raise "protocol_error", "invalid PBKDFParamRequest message" + end + var pbkdfparamreq = matter.PBKDFParamRequest().parse(msg.raw, msg.app_payload_idx) + msg.session.set_mode(matter.Session.__PASE) + + self.PBKDFParamRequest = msg.raw[msg.app_payload_idx..] + + # sanity check for PBKDFParamRequest + if pbkdfparamreq.passcodeId != 0 raise "protocol_error", "non-zero passcode id" end + + # record the initiator_session_id + self.future_initiator_session_id = pbkdfparamreq.initiator_session_id + self.future_local_session_id = self.device.sessions.gen_local_session_id() + + # prepare response + var pbkdfparamresp = matter.PBKDFParamResponse() + + pbkdfparamresp.initiatorRandom = pbkdfparamreq.initiatorRandom + # generate 32 bytes random + pbkdfparamresp.responderRandom = crypto.random(32) + pbkdfparamresp.responderSessionId = self.future_local_session_id + pbkdfparamresp.pbkdf_parameters_salt = self.device.salt + pbkdfparamresp.pbkdf_parameters_iterations = self.device.iterations + tasmota.log("MTR: pbkdfparamresp: " + str(matter.inspect(pbkdfparamresp)), 3) + var pbkdfparamresp_raw = pbkdfparamresp.encode() + tasmota.log("MTR: pbkdfparamresp_raw: " + pbkdfparamresp_raw.tohex(), 3) + + self.PBKDFParamResponse = pbkdfparamresp_raw + + var resp = msg.build_response(0x21 #-PBKDR Response-#, true) + var raw = resp.encode(pbkdfparamresp_raw) + + self.responder.send_response(raw, addr, port, resp.message_counter) + end + + def parse_Pake1(msg, addr, port) + import crypto + # sanity checks + if msg.opcode != 0x22 || msg.local_session_id != 0 || msg.protocol_id != 0 + raise "protocol_error", "invalid Pake1 message" + end + var pake1 = matter.Pake1().parse(msg.raw, msg.app_payload_idx) + + self.pA = pake1.pA + tasmota.log("MTR: received pA=" + self.pA.tohex(), 3) + + + tasmota.log("MTR: spake: " + matter.inspect(self.spake), 3) + # instanciate SPAKE + self.spake = crypto.SPAKE2P_Matter(self.device.w0, self.device.w1, self.device.L) + # compute pB + self.spake.compute_pB(self.y) + self.pB = self.spake.pB + tasmota.log("MTR: y=" + self.y.tohex(), 3) + tasmota.log("MTR: pb=" + self.pB.tohex(), 3) + + # compute ZV + self.spake.compute_ZV_verifier(self.pA) + tasmota.log("MTR: Z=" + self.spake.Z.tohex(), 3) + tasmota.log("MTR: V=" + self.spake.V.tohex(), 3) + + var context = crypto.SHA256() + context.update(bytes().fromstring(self.Matter_Context_Prefix)) + context.update(self.PBKDFParamRequest) + context.update(self.PBKDFParamResponse) + var context_hash = context.out() + + tasmota.log("MTR: Context=" + context_hash.tohex(), 3) + + # add pA + self.spake.pA = self.pA + + self.spake.set_context(context_hash) + self.spake.compute_TT_hash(true) # `true` to indicate it's Matter variant to SPAKE2+ + + tasmota.log("MTR: ------------------------------", 3) + tasmota.log("MTR: Context = " + self.spake.Context.tohex(), 3) + tasmota.log("MTR: A = " + self.spake.A.tohex(), 3) + tasmota.log("MTR: B = " + self.spake.B.tohex(), 3) + tasmota.log("MTR: M = " + self.spake.M.tohex(), 3) + tasmota.log("MTR: N = " + self.spake.N.tohex(), 3) + tasmota.log("MTR: pA = " + self.spake.pA.tohex(), 3) + tasmota.log("MTR: pB = " + self.spake.pB.tohex(), 3) + tasmota.log("MTR: Z = " + self.spake.Z.tohex(), 3) + tasmota.log("MTR: V = " + self.spake.V.tohex(), 3) + tasmota.log("MTR: w0 = " + self.spake.w0.tohex(), 3) + tasmota.log("MTR: ------------------------------", 3) + + tasmota.log("MTR: Kmain =" + self.spake.Kmain.tohex(), 3) + + tasmota.log("MTR: KcA =" + self.spake.KcA.tohex(), 3) + tasmota.log("MTR: KcB =" + self.spake.KcB.tohex(), 3) + tasmota.log("MTR: K_shared=" + self.spake.K_shared.tohex(), 3) + tasmota.log("MTR: Ke =" + self.spake.Ke.tohex(), 3) + self.cB = self.spake.cB + self.Ke = self.spake.Ke + tasmota.log("MTR: cB=" + self.cB.tohex(), 3) + + var pake2 = matter.Pake2() + pake2.pB = self.pB + pake2.cB = self.cB + tasmota.log("MTR: pake2: " + matter.inspect(pake2), 3) + var pake2_raw = pake2.encode() + tasmota.log("MTR: pake2_raw: " + pake2_raw.tohex(), 3) + + + # now package the response message + var resp = msg.build_response(0x23 #-pake-2-#, true) # no reliable flag + var raw = resp.encode(pake2_raw) + + self.responder.send_response(raw, addr, port, resp.message_counter) + end + + def parse_Pake3(msg, addr, port) + import crypto + # sanity checks + if msg.opcode != 0x24 || msg.local_session_id != 0 || msg.protocol_id != 0 + raise "protocol_error", "invalid Pake3 message" + end + var pake3 = matter.Pake3().parse(msg.raw, msg.app_payload_idx) + + self.cA = pake3.cA + tasmota.log("MTR: received cA=" + self.cA.tohex(), 3) + + # check the value against computed + if self.cA != self.spake.cA raise "protocol_error", "invalid cA received" end + + # send PakeFinished and compute session key + self.session_timestamp = tasmota.rtc()['utc'] + var session_keys = crypto.HKDF_SHA256().derive(self.Ke, bytes(), bytes().fromstring(self.SEKeys_Info), 48) + self.I2RKey = session_keys[0..15] + self.R2IKey = session_keys[16..31] + self.AttestationChallenge = session_keys[32..47] + + tasmota.log("MTR: ******************************", 3) + tasmota.log("MTR: session_keys=" + session_keys.tohex(), 3) + tasmota.log("MTR: I2RKey =" + self.I2RKey.tohex(), 3) + tasmota.log("MTR: R2IKey =" + self.R2IKey.tohex(), 3) + tasmota.log("MTR: AC =" + self.AttestationChallenge.tohex(), 3) + tasmota.log("MTR: ******************************", 3) + + # now package the response message + var resp = msg.build_response(0x40 #-StatusReport-#, false) # no reliable flag + + var status_raw = bytes() + status_raw.add(0x00, 2) # GeneralCode = SUCCESS + status_raw.add(0x0000, 4) # ProtocolID = 0 (PROTOCOL_ID_SECURE_CHANNEL) + status_raw.add(0x0000, 4) # ProtocolCode = 0 (SESSION_ESTABLISHMENT_SUCCESS) + + var raw = resp.encode(status_raw) + + self.responder.send_response(raw, addr, port, nil) + self.responder.add_session(self.future_local_session_id, self.future_initiator_session_id, self.I2RKey, self.R2IKey, self.AttestationChallenge, self.session_timestamp) + end + + def find_session_by_destination_id(destinationId, initiatorRandom) + import crypto + # Validate Sigma1 Destination ID, p.162 + # traverse all existing sessions + tasmota.log("MTR: SEARCHING: destinationId=" + destinationId.tohex(), 3) + for session:self.device.sessions.sessions + if session.noc == nil || session.fabric == nil || session.deviceid == nil continue end + # compute candidateDestinationId, Section 4.13.2.4.1, “Destination Identifier” + var destinationMessage = initiatorRandom + session.get_ca_pub() + session.get_fabric() + session.get_deviceid() + var key = session.get_ipk_group_key() + tasmota.log("MTR: SIGMA1: destinationMessage=" + destinationMessage.tohex(), 3) + tasmota.log("MTR: SIGMA1: key_ipk=" + key.tohex(), 3) + var h = crypto.HMAC_SHA256(key) + h.update(destinationMessage) + var candidateDestinationId = h.out() + tasmota.log("MTR: SIGMA1: candidateDestinationId=" + candidateDestinationId.tohex(), 3) + if candidateDestinationId == destinationId + return session + end + end + return nil + end + + def parse_Sigma1(msg, addr, port) + import crypto + # sanity checks + if msg.opcode != 0x30 || msg.local_session_id != 0 || msg.protocol_id != 0 + raise "protocol_error", "invalid Pake1 message" + end + var sigma1 = matter.Sigma1().parse(msg.raw, msg.app_payload_idx) + + self.initiatorEph_pub = sigma1.initiatorEphPubKey + + # find session + var session = self.find_session_by_destination_id(sigma1.destinationId, sigma1.initiatorRandom) + if session == nil raise "valuer_error", "StatusReport(GeneralCode: FAILURE, ProtocolId: SECURE_CHANNEL, ProtocolCode: NO_SHARED_TRUST_ROOTS)" end + session.source_node_id = msg.source_node_id + session.set_mode(matter.Session.__CASE) + + if msg.session + self.device.sessions.remove_session(msg.session) # drop the temporary session that was created + end + msg.session = session + session._future_initiator_session_id = sigma1.initiator_session_id # update initiator_session_id + session._future_local_session_id = self.device.sessions.gen_local_session_id() + self.future_local_session_id = session._future_local_session_id + + + # Check that it's a resumption + if sigma1.resumptionID != nil && sigma1.initiatorResumeMIC != nil && + session.shared_secret != nil + # Resumption p.169 + var s1rk_salt = sigma1.initiatorRandom + sigma1.resumptionID + var s1rk_info = bytes().fromstring("Sigma1_Resume") + var s1rk = crypto.HKDF_SHA256().derive(session.shared_secret, s1rk_salt, s1rk_info, 16) + + var Resume1MIC_Nonce = bytes().fromstring("NCASE_SigmaR1") + var encrypted = sigma1.initiatorResumeMIC[0..-17] + var tag = sigma1.initiatorResumeMIC[-16..] + var ec = crypto.AES_CCM(s1rk, Resume1MIC_Nonce, bytes(), size(encrypted), 16) + var Resume1MICPayload = ec.decrypt(encrypted) + var decrypted_tag = ec.tag() + + tasmota.log("****************************************", 3) + tasmota.log("MTR: * s1rk = " + s1rk.tohex(), 3) + tasmota.log("MTR: * tag = " + tag.tohex(), 3) + tasmota.log("MTR: * Resume1MICPayload = " + Resume1MICPayload.tohex(), 3) + tasmota.log("MTR: * decrypted_tag = " + decrypted_tag.tohex(), 3) + tasmota.log("****************************************", 3) + if tag == decrypted_tag + # Generate and Send Sigma2_Resume + session.resumption_id = crypto.random(16) # generate a new resumption id + + # compute S2RK + var s2rk_info = bytes().fromstring("Sigma2_Resume") + session.resumption_id + var s2rk_salt = sigma1.initiatorRandom + sigma1.resumptionID + var s2rk = crypto.HKDF_SHA256().derive(session.shared_secret, s2rk_salt, s2rk_info, 16) + + # compute Resume2MIC + var aes = crypto.AES_CCM(s2rk, bytes().fromstring("NCASE_SigmaR2"), bytes(), 0, 16) + var Resume2MIC = aes.tag() + + var sigma2resume = matter.Sigma2Resume() + sigma2resume.resumptionID = session.resumption_id + sigma2resume.responderSessionID = session._future_local_session_id + sigma2resume.sigma2ResumeMIC = Resume2MIC + + # # compute session key, p.178 + var session_keys = crypto.HKDF_SHA256().derive(session.shared_secret #- input key -#, + sigma1.initiatorRandom + sigma1.resumptionID #- salt -#, + bytes().fromstring("SessionResumptionKeys") #- info -#, + 48) + var i2r = session_keys[0..15] + var r2i = session_keys[16..31] + var ac = session_keys[32..47] + var session_timestamp = tasmota.rtc()['utc'] + + tasmota.log("MTR: ******************************", 3) + tasmota.log("MTR: I2RKey =" + i2r.tohex(), 3) + tasmota.log("MTR: R2IKey =" + r2i.tohex(), 3) + tasmota.log("MTR: AC =" + ac.tohex(), 3) + tasmota.log("MTR: ******************************", 3) + + var sigma2resume_raw = sigma2resume.encode() + session._Msg1 = nil + tasmota.log("MTR: sigma2resume_raw: " + sigma2resume_raw.tohex(), 3) + + # now package the response message + var resp = msg.build_response(0x33 #-sigma-2-resume-#, true) + var raw = resp.encode(sigma2resume_raw) + + self.responder.send_response(raw, addr, port, resp.message_counter) + + session.close() + session.set_keys(i2r, r2i, ac, session_timestamp) + session.set_persist(true) # keep session on flash + session.set_no_expiration() # never expire + session.save() + + return true + else + sigma1.resumptionID = nil + # fall through normal sigma1 (non-resumption) + end + end + + if sigma1.resumptionID == nil || sigma1.initiatorResumeMIC == nil + # Compute Sigma2, p.162 + session.resumption_id = crypto.random(16) + self.ResponderEph_priv = crypto.random(32) + self.ResponderEph_pub = crypto.EC_P256().public_key(self.ResponderEph_priv) + var responderRandom = crypto.random(32) + + session.shared_secret = crypto.EC_P256().shared_key(self.ResponderEph_priv, sigma1.initiatorEphPubKey) + + var sigma2_tbsdata = matter.TLV.Matter_TLV_struct() + sigma2_tbsdata.add_TLV(1, matter.TLV.B2, session.get_noc()) + sigma2_tbsdata.add_TLV(2, matter.TLV.B2, session.get_icac()) + sigma2_tbsdata.add_TLV(3, matter.TLV.B2, self.ResponderEph_pub) + sigma2_tbsdata.add_TLV(4, matter.TLV.B2, sigma1.initiatorEphPubKey) + + var TBSData2Signature = crypto.EC_P256().ecdsa_sign_sha256(session.get_pk(), sigma2_tbsdata.encode()) + + var sigma2_tbedata = matter.TLV.Matter_TLV_struct() + sigma2_tbedata.add_TLV(1, matter.TLV.B2, session.get_noc()) + sigma2_tbedata.add_TLV(2, matter.TLV.B2, session.get_icac()) + sigma2_tbedata.add_TLV(3, matter.TLV.B2, TBSData2Signature) + sigma2_tbedata.add_TLV(4, matter.TLV.B2, session.resumption_id) + + # compute TranscriptHash = Crypto_Hash(message = Msg1) + tasmota.log("****************************************", 3) + session._Msg1 = sigma1.Msg1 + tasmota.log("MTR: * MSG1 = " + session._Msg1.tohex(), 3) + var TranscriptHash = crypto.SHA256().update(session._Msg1).out() + + # Compute S2K, p.175 + var s2k_info = bytes().fromstring(self.S2K_Info) + var s2k_salt = session.get_ipk_group_key() + responderRandom + self.ResponderEph_pub + TranscriptHash + + var s2k = crypto.HKDF_SHA256().derive(session.shared_secret, s2k_salt, s2k_info, 16) + tasmota.log("MTR: * SharedSecret = " + session.shared_secret.tohex(), 3) + tasmota.log("MTR: * s2k_salt = " + s2k_salt.tohex(), 3) + tasmota.log("MTR: * s2k = " + s2k.tohex(), 3) + + var sigma2_tbedata_raw = sigma2_tbedata.encode() + # // `AES_CCM.init(secret_key:bytes(16 or 32), iv:bytes(7..13), aad:bytes(), data_len:int, tag_len:int) -> instance` + + var aes = crypto.AES_CCM(s2k, bytes().fromstring(self.TBEData2_Nonce), bytes(), size(sigma2_tbedata_raw), 16) + var TBEData2Encrypted = aes.encrypt(sigma2_tbedata_raw) + aes.tag() + tasmota.log("MTR: * TBEData2Enc = " + TBEData2Encrypted.tohex(), 3) + tasmota.log("****************************************", 3) + + var sigma2 = matter.Sigma2() + sigma2.responderRandom = responderRandom + sigma2.responderSessionId = self.future_local_session_id + sigma2.responderEphPubKey = self.ResponderEph_pub + sigma2.encrypted2 = TBEData2Encrypted + tasmota.log("MTR: sigma2: " + matter.inspect(sigma2), 3) + var sigma2_raw = sigma2.encode() + session._Msg2 = sigma2_raw + tasmota.log("MTR: sigma2_raw: " + sigma2_raw.tohex(), 3) + + # now package the response message + var resp = msg.build_response(0x31 #-sigma-2-#, true) # no reliable flag + var raw = resp.encode(sigma2_raw) + + self.responder.send_response(raw, addr, port, resp.message_counter) + return true + end + + return true + end + + def parse_Sigma3(msg, addr, port) + import crypto + # sanity checks + if msg.opcode != 0x32 || msg.local_session_id != 0 || msg.protocol_id != 0 + raise "protocol_error", "invalid Pake1 message" + end + var session = msg.session + var sigma3 = matter.Sigma3().parse(msg.raw, msg.app_payload_idx) + + tasmota.log("****************************************", 3) + # compute TranscriptHash = Crypto_Hash(message = Msg1 || Msg2) + var TranscriptHash = crypto.SHA256().update(session._Msg1).update(session._Msg2).out() + tasmota.log("MTR: * session = " + str(session), 3) + tasmota.log("MTR: session.ipk_epoch_key " + str(session.ipk_epoch_key), 3) + tasmota.log("MTR: session.fabric_compressed " + str(session.fabric_compressed), 3) + tasmota.log("MTR: * ipk_group_key = " + session.get_ipk_group_key().tohex(), 3) + tasmota.log("MTR: * TranscriptHash= " + TranscriptHash.tohex(), 3) + + var s3k_info = bytes().fromstring(self.S3K_Info) + var s3k = crypto.HKDF_SHA256().derive(session.shared_secret, session.get_ipk_group_key() + TranscriptHash, s3k_info, 16) + + tasmota.log("****************************************", 3) + # self.ipk_epoch_key == nil || self.fabric_compressed") + tasmota.log("MTR: * s3k_salt = " + (session.get_ipk_group_key() + TranscriptHash).tohex(), 3) + tasmota.log("MTR: * s3k = " + s3k.tohex(), 3) + tasmota.log("****************************************", 3) + + # decrypt + var encrypted = sigma3.TBEData3Encrypted[0..-17] + var tag = sigma3.TBEData3Encrypted[-16..] + var ec = crypto.AES_CCM(s3k, bytes().fromstring(self.TBEData3_Nonce), bytes(), size(encrypted), 16) + var TBEData3 = ec.decrypt(encrypted) + var TBETag3 = ec.tag() + tasmota.log("MTR: * TBEData3 = " + TBEData3.tohex(), 3) + tasmota.log("MTR: * TBETag3 = " + TBETag3.tohex(), 3) + tasmota.log("MTR: * tag_sent = " + tag.tohex(), 3) + tasmota.log("****************************************", 3) + + if TBETag3 != tag raise "value_error", "tag do not match" end + + var TBEData3TLV = matter.TLV.parse(TBEData3) + var initiatorNOC = TBEData3TLV.findsubval(1) + var initiatorICAC = TBEData3TLV.findsubval(2) + var ec_signature = TBEData3TLV.findsubval(3) + # Success = Crypto_VerifyChain(certificates = [TBEData3.initiatorNOC, TBEData3.initiatorICAC, TrustedRCAC]), when TBEData3.initiatorICAC is present + # TODO + var initiatorNOCTLV = matter.TLV.parse(initiatorNOC) + tasmota.log("MTR: initiatorNOCTLV = " + str(initiatorNOCTLV), 3) + var initiatorNOCPubKey = initiatorNOCTLV.findsubval(9) + var initiatorNOCListDN = initiatorNOCTLV.findsub(6) + var initiatorFabricId = initiatorNOCListDN.findsubval(17) + if type(initiatorFabricId) == 'int' initiatorFabricId = int64(initiatorFabricId) end + session.peer_node_id = initiatorFabricId.tobytes() + tasmota.log("MTR: initiatorFabricId="+str(session.peer_node_id), 3) + + var sigma3_tbs = matter.TLV.Matter_TLV_struct() + sigma3_tbs.add_TLV(1, matter.TLV.B1, initiatorNOC) + sigma3_tbs.add_TLV(2, matter.TLV.B1, initiatorICAC) + sigma3_tbs.add_TLV(3, matter.TLV.B1, self.initiatorEph_pub) + sigma3_tbs.add_TLV(4, matter.TLV.B1, self.ResponderEph_pub) + var sigma3_tbs_raw = sigma3_tbs.encode() + + tasmota.log("MTR: * initiatorNOCPubKey = " + initiatorNOCPubKey.tohex(), 3) + tasmota.log("MTR: * ec_signature = " + ec_signature.tohex(), 3) + tasmota.log("****************************************", 3) + + # `crypto.EC_P256().ecdsa_verify_sha256(public_key:bytes(65), message:bytes(), hash:bytes()) -> bool` + var sigma3_tbs_valid = crypto.EC_P256().ecdsa_verify_sha256(initiatorNOCPubKey, sigma3_tbs_raw, ec_signature) + + if !sigma3_tbs_valid raise "value_error", "sigma3_tbs does not have a valid signature" end + + # All good, compute new keys + tasmota.log("MTR: Sigma3 verified, computing new keys", 3) + + TranscriptHash = crypto.SHA256().update(session._Msg1).update(session._Msg2).update(sigma3.Msg3).out() + # we can now free _Msg1 and _Msg2 + session._Msg1 = nil + session._Msg2 = nil + + tasmota.log("MTR: ******************************", 3) + tasmota.log("MTR: shared_secret =" + session.shared_secret.tohex(), 3) + tasmota.log("MTR: ipk + hash =" + (session.get_ipk_group_key() + TranscriptHash).tohex(), 3) + # compute session key + var session_keys = crypto.HKDF_SHA256().derive(session.shared_secret #- input key -#, + session.get_ipk_group_key() + TranscriptHash #- salt -#, + bytes().fromstring(self.SEKeys_Info) #- info -#, + 48) + var i2r = session_keys[0..15] + var r2i = session_keys[16..31] + var ac = session_keys[32..47] + var session_timestamp = tasmota.rtc()['utc'] + + tasmota.log("MTR: ******************************", 3) + tasmota.log("MTR: I2RKey =" + i2r.tohex(), 3) + tasmota.log("MTR: R2IKey =" + r2i.tohex(), 3) + tasmota.log("MTR: AC =" + ac.tohex(), 3) + tasmota.log("MTR: ******************************", 3) + + # Send success status report + var resp = msg.build_response(0x40 #-StatusReport-#, true) # reliable flag + + var status_raw = bytes() + status_raw.add(0x00, 2) # GeneralCode = SUCCESS + status_raw.add(0x0000, 4) # ProtocolID = 0 (PROTOCOL_ID_SECURE_CHANNEL) + status_raw.add(0x0000, 4) # ProtocolCode = 0 (SESSION_ESTABLISHMENT_SUCCESS) + + var raw = resp.encode(status_raw) + + self.responder.send_response(raw, addr, port, resp.message_counter) + + session.close() + session.set_keys(i2r, r2i, ac, session_timestamp) + session.set_persist(true) # keep session on flash + session.set_no_expiration() # never expire + session.save() + + return true + end + + ############################################################# + # placeholder, nothing to run for now + def every_second() + end +end +matter.Commisioning_Context = Matter_Commisioning_Context + +#- + +# STEP 1 +PBKDF_PR = matter.PBKDFParamRequest().parse(bytes("15300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D662502054C240300280435052501881325022C011818")) +{'passcodeId': 0, 'initiatorRandom': bytes('D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66'), +'hasPBKDFParameters': 0, 'SLEEPY_IDLE_INTERVAL': 5000, 'SLEEPY_ACTIVE_INTERVAL': 300, 'initiator_session_id': 19461} + + + + + +# ########################################################################################## +PBKDF_PR = matter.PBKDFParamRequest().parse(bytes("15300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D662502054C240300280435052501881325022C011818")) +print(matter.inspect(PBKDF_PR)) +{'passcodeId': 0, 'initiatorRandom': bytes('D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66'), 'hasPBKDFParameters': 0, 'SLEEPY_IDLE_INTERVAL': 5000, 'SLEEPY_ACTIVE_INTERVAL': 300, 'initiator_session_id': 19461} + +var r = matter.PBKDFParamResponse() +r.initiatorRandom = bytes("112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00") +r.responderRandom = bytes("112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00") +r.responderSessionId = 1234 +r.pbkdf_parameters_iterations = 1000 +r.pbkdf_parameters_salt = bytes("deadbeef11223344deadbeef11223344") +r.SLEEPY_IDLE_INTERVAL = 100 +r.SLEEPY_ACTIVE_INTERVAL = 200 + +bytes('15300120112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00300220112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF002503D20418') + + +# ########################################################################################## +var m = matter.Frame() +m.decode(bytes("0400000006747A09347BFD880AC8128005205FC3000015300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D662502054C240300280435052501881325022C011818")) + +# 'opcode': 32 +# 'local_session_id': 0 +# 'protocol_id': 0 + +#{'dest_node_id_8': nil, 'flag_dsiz': 0, 'x_flag_r': 1, 'sec_c': 0, 'app_payload_idx': 22, 'sec_flags': 0, +#'dest_node_id_2': nil, 'x_flag_sx': 0, 'sec_p': 0, 'message_counter': 159020038, 'x_flag_v': 0, 'flags': 4, +#'vendor_id': nil, 'x_flag_i': 1, 'source_node_id': bytes('347BFD880AC81280'), +#'ack_message_counter': nil, 'raw': bytes('0400000006747A09347BFD880AC8128005205FC3000015300120D2DAEE8760C9...'), +#'exchange_id': 50015, 'opcode': 32, 'local_session_id': 0, 'x_flag_a': 0, 'flag_s': 1, 'x_flags': 5, 'sec_sesstype': 0, +#'sec_extensions': nil, 'sec_mx': 0, 'protocol_id': 0} + +0400000006747A09347BFD880AC8128005205FC3000015300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D662502054C240300280435052501881325022C011818 + +12:09:05.561 MTR: sending packet to '192.168.2.109:5540' 050000000674C82B96B90B530000347BFD880AC8128000215FC3000015300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66300220AA981992DB666B51DEDC0DD67ED6ABBB29AB30E67452C8893166FBF5FD95601D2503010018 + +050000000674C82B96B90B530000347BFD880AC8128000215FC3000015300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66300220AA981992DB666B51DEDC0DD67ED6ABBB29AB30E67452C8893166FBF5FD95601D2503010018 +12:10:29.174 MTR: received message { + 'flag_s': 1, 'flag_dsiz': 1, 'x_flag_r': 1, 'x_flag_sx': 1, 'sec_mx': 0, 'sec_flags': 0, + 'dest_node_id_2': nil, 'sec_sesstype': 0, 'local_session_id': 0, 'ack_message_counter': -2014389550, + 'x_flag_v': 1, 'flags': 5, 'vendor_id': 8193, 'x_flag_i': 1, 'source_node_id': bytes('96B90B530000347B'), + 'app_payload_idx': 51590, + 'raw': bytes('050000000674C82B96B90B530000347BFD880AC8128000215FC3000015300120...'), + 'exchange_id': 0, 'opcode': 195, 'message_counter': 734557190, 'sec_p': 0, 'sec_c': 0, + 'protocol_id': 12309, 'dest_node_id_8': bytes('FD880AC812800021'), + 'sec_extensions': nil, 'x_flag_a': 1, 'x_flags': 95} + +347BFD880AC81280 + +fe80::1bf1:bd1a:c5ff:818a +b8:27:eb:8b:d2:59 + +{'mac': 'C8:2B:96:B9:0B:53', 'ip6local': 'fe80::ca2b:96ff:feb9:b53', 'ip': '192.168.1.116'} + +-# diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Commissioning_Data.be b/lib/libesp32/berry_matter/src/embedded/Matter_Commissioning_Data.be new file mode 100644 index 000000000..9aca4927c --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Commissioning_Data.be @@ -0,0 +1,317 @@ +# +# Matter_Commissioning_Data.be - suppport for Matter Commissioning messages structure +# +# Copyright (C) 2023 Stephan Hadinger & Theo Arends +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +import matter + +#@ solidify:Matter_PBKDFParamRequest,weak +#@ solidify:Matter_PBKDFParamResponse,weak +#@ solidify:Matter_Pake1,weak +#@ solidify:Matter_Pake2,weak +#@ solidify:Matter_Pake3,weak +#@ solidify:Matter_Sigma1,weak +#@ solidify:Matter_Sigma2,weak +#@ solidify:Matter_Sigma2Resume,weak +#@ solidify:Matter_Sigma3,weak + +################################################################################# +# class PBKDFParamRequest encaspulating pbkdfparamreq-struct (p. 151) +################################################################################# +class Matter_PBKDFParamRequest + var initiatorRandom + var initiator_session_id + var passcodeId + var hasPBKDFParameters + var SLEEPY_IDLE_INTERVAL + var SLEEPY_ACTIVE_INTERVAL + + def parse(b, idx) + if idx == nil idx = 0 end + var val = matter.TLV.parse(b, idx) + + self.initiatorRandom = val.getsubval(1) + self.initiator_session_id = val.getsubval(2) + self.passcodeId = val.getsubval(3) + self.hasPBKDFParameters = val.getsubval(4) + var initiatorSEDParams = val.findsub(5) + if initiatorSEDParams != nil + self.SLEEPY_IDLE_INTERVAL = initiatorSEDParams.findsubval(1) + self.SLEEPY_ACTIVE_INTERVAL = initiatorSEDParams.findsubval(2) + end + return self + end +end +matter.PBKDFParamRequest = Matter_PBKDFParamRequest + +################################################################################# +# class PBKDFParamResponse encaspulating pbkdfparamresp-struct (p. 153) +################################################################################# +class Matter_PBKDFParamResponse + var initiatorRandom + var responderRandom + var responderSessionId + var pbkdf_parameters_iterations + var pbkdf_parameters_salt + var SLEEPY_IDLE_INTERVAL + var SLEEPY_ACTIVE_INTERVAL + + def encode(b) + var s = matter.TLV.Matter_TLV_struct() + # initiatorRandom + s.add_TLV(1, matter.TLV.B1, self.initiatorRandom) + s.add_TLV(2, matter.TLV.B1, self.responderRandom) + s.add_TLV(3, matter.TLV.U2, self.responderSessionId) + var s_pbkdf = s.add_struct(4) + s_pbkdf.add_TLV(1, matter.TLV.U4, self.pbkdf_parameters_iterations) + s_pbkdf.add_TLV(2, matter.TLV.B1, self.pbkdf_parameters_salt) + if self.SLEEPY_IDLE_INTERVAL != nil || self.SLEEPY_ACTIVE_INTERVAL != nil + var s2 = s.add_struct(5) + s2.add_TLV(1, matter.TLV.U4, self.SLEEPY_IDLE_INTERVAL) + s2.add_TLV(2, matter.TLV.U4, self.SLEEPY_ACTIVE_INTERVAL) + end + return s.encode() + end +end +matter.PBKDFParamResponse = Matter_PBKDFParamResponse + +################################################################################# +# class Pake1 +################################################################################# +class Matter_Pake1 + var pA + + def parse(b, idx) + if idx == nil idx = 0 end + var val = matter.TLV.parse(b, idx) + tasmota.log("MTR: parsed TLV: " + str(val), 3) + + self.pA = val.getsubval(1) + return self + end +end +matter.Pake1 = Matter_Pake1 + +################################################################################# +# class Pake1 +################################################################################# +class Matter_Pake2 + var pB # 65 bytes + var cB # 32 bytes + + def encode(b) + var s = matter.TLV.Matter_TLV_struct() + # + s.add_TLV(1, matter.TLV.B1, self.pB) + s.add_TLV(2, matter.TLV.B1, self.cB) + return s.encode() + end +end +matter.Pake2 = Matter_Pake2 + +# class Pake3 +class Matter_Pake3 + var cA + + def parse(b, idx) + if idx == nil idx = 0 end + var val = matter.TLV.parse(b, idx) + tasmota.log("MTR: parsed TLV: " + str(val), 3) + + self.cA = val.getsubval(1) + return self + end +end +matter.Pake3 = Matter_Pake3 + +################################################################################# +# class Sigma1, p.160 +################################################################################# +class Matter_Sigma1 + var initiatorRandom # bytes(32) + var initiator_session_id # U16 + var destinationId # bytes(32) + var initiatorEphPubKey # bytes(65) + # var initiatorSEDParams # (opt) sed-parameter-struct + var SLEEPY_IDLE_INTERVAL + var SLEEPY_ACTIVE_INTERVAL + var resumptionID # (opt) bytes(16) + var initiatorResumeMIC # (opt) bytes(16) + var Msg1 + + def parse(b, idx) + if idx == nil idx = 0 end + var val = matter.TLV.parse(b, idx) + self.Msg1 = b[idx..] + tasmota.log("MTR: Sigma1 TLV=" + str(val), 3) + + self.initiatorRandom = val.getsubval(1) + self.initiator_session_id = val.getsubval(2) + self.destinationId = val.getsubval(3) + self.initiatorEphPubKey = val.getsubval(4) + var initiatorSEDParams = val.findsub(5) + if initiatorSEDParams != nil + self.SLEEPY_IDLE_INTERVAL = initiatorSEDParams.findsubval(1) + self.SLEEPY_ACTIVE_INTERVAL = initiatorSEDParams.findsubval(2) + end + var resumptionID = val.findsub(6) + var initiatorResumeMIC = val.findsub(7) + return self + end +end +matter.Sigma1 = Matter_Sigma1 + +################################################################################# +# class Sigma2 +################################################################################# +class Matter_Sigma2 + var responderRandom # bytes(32) + var responderSessionId # U16 + var responderEphPubKey # bytes(65) + var encrypted2 # bytes() + var SLEEPY_IDLE_INTERVAL + var SLEEPY_ACTIVE_INTERVAL + + def encode(b) + var s = matter.TLV.Matter_TLV_struct() + # initiatorRandom + s.add_TLV(1, matter.TLV.B1, self.responderRandom) + s.add_TLV(2, matter.TLV.U2, self.responderSessionId) + s.add_TLV(3, matter.TLV.B1, self.responderEphPubKey) + s.add_TLV(4, matter.TLV.B1, self.encrypted2) + if self.SLEEPY_IDLE_INTERVAL != nil || self.SLEEPY_ACTIVE_INTERVAL != nil + var s2 = s.add_struct(5) + s2.add_TLV(1, matter.TLV.U4, self.SLEEPY_IDLE_INTERVAL) + s2.add_TLV(2, matter.TLV.U4, self.SLEEPY_ACTIVE_INTERVAL) + end + return s.encode() + end +end +matter.Sigma2 = Matter_Sigma2 + +################################################################################# +# class Sigma2Resume, p.170 +################################################################################# +class Matter_Sigma2Resume + var resumptionID # bytes(16) + var sigma2ResumeMIC # bytes(16) + var responderSessionID # u16 + var SLEEPY_IDLE_INTERVAL + var SLEEPY_ACTIVE_INTERVAL + + def encode(b) + var s = matter.TLV.Matter_TLV_struct() + # initiatorRandom + s.add_TLV(1, matter.TLV.B1, self.resumptionID) + s.add_TLV(2, matter.TLV.B1, self.sigma2ResumeMIC) + s.add_TLV(3, matter.TLV.B1, self.responderSessionID) + if self.SLEEPY_IDLE_INTERVAL != nil || self.SLEEPY_ACTIVE_INTERVAL != nil + var s2 = s.add_struct(4) + s2.add_TLV(1, matter.TLV.U4, self.SLEEPY_IDLE_INTERVAL) + s2.add_TLV(2, matter.TLV.U4, self.SLEEPY_ACTIVE_INTERVAL) + end + return s.encode() + end +end +matter.Sigma2Resume = Matter_Sigma2Resume + +################################################################################# +# class Sigma3, p.160 +################################################################################# +class Matter_Sigma3 + var TBEData3Encrypted # bytes() + var Msg3 + + def parse(b, idx) + if idx == nil idx = 0 end + var val = matter.TLV.parse(b, idx) + self.Msg3 = b[idx..] + tasmota.log("MTR: Sigma3 TLV=" + str(val), 3) + + self.TBEData3Encrypted = val.getsubval(1) + return self + end +end +matter.Sigma3 = Matter_Sigma3 + + +#- + +# STEP 1 +PBKDF_PR = matter.PBKDFParamRequest().parse(bytes("15300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D662502054C240300280435052501881325022C011818")) +{'passcodeId': 0, 'initiatorRandom': bytes('D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66'), +'hasPBKDFParameters': 0, 'SLEEPY_IDLE_INTERVAL': 5000, 'SLEEPY_ACTIVE_INTERVAL': 300, 'initiator_session_id': 19461} + + + + + +# ########################################################################################## +PBKDF_PR = matter.PBKDFParamRequest().parse(bytes("15300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D662502054C240300280435052501881325022C011818")) +print(matter.inspect(PBKDF_PR)) +{'passcodeId': 0, 'initiatorRandom': bytes('D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66'), 'hasPBKDFParameters': 0, 'SLEEPY_IDLE_INTERVAL': 5000, 'SLEEPY_ACTIVE_INTERVAL': 300, 'initiator_session_id': 19461} + +var r = matter.PBKDFParamResponse() +r.initiatorRandom = bytes("112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00") +r.responderRandom = bytes("112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00") +r.responderSessionId = 1234 +r.pbkdf_parameters_iterations = 1000 +r.pbkdf_parameters_salt = bytes("deadbeef11223344deadbeef11223344") +r.SLEEPY_IDLE_INTERVAL = 100 +r.SLEEPY_ACTIVE_INTERVAL = 200 + +bytes('15300120112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF00300220112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF002503D20418') + + +# ########################################################################################## +var m = matter.Frame() +m.decode(bytes("0400000006747A09347BFD880AC8128005205FC3000015300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D662502054C240300280435052501881325022C011818")) + +# 'opcode': 32 +# 'local_session_id': 0 +# 'protocol_id': 0 + +#{'dest_node_id_8': nil, 'flag_dsiz': 0, 'x_flag_r': 1, 'sec_c': 0, 'app_payload_idx': 22, 'sec_flags': 0, +#'dest_node_id_2': nil, 'x_flag_sx': 0, 'sec_p': 0, 'message_counter': 159020038, 'x_flag_v': 0, 'flags': 4, +#'vendor_id': nil, 'x_flag_i': 1, 'source_node_id': bytes('347BFD880AC81280'), +#'ack_message_counter': nil, 'raw': bytes('0400000006747A09347BFD880AC8128005205FC3000015300120D2DAEE8760C9...'), +#'exchange_id': 50015, 'opcode': 32, 'local_session_id': 0, 'x_flag_a': 0, 'flag_s': 1, 'x_flags': 5, 'sec_sesstype': 0, +#'sec_extensions': nil, 'sec_mx': 0, 'protocol_id': 0} + +0400000006747A09347BFD880AC8128005205FC3000015300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D662502054C240300280435052501881325022C011818 + +12:09:05.561 MTR: sending packet to '192.168.2.109:5540' 050000000674C82B96B90B530000347BFD880AC8128000215FC3000015300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66300220AA981992DB666B51DEDC0DD67ED6ABBB29AB30E67452C8893166FBF5FD95601D2503010018 + +050000000674C82B96B90B530000347BFD880AC8128000215FC3000015300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66300220AA981992DB666B51DEDC0DD67ED6ABBB29AB30E67452C8893166FBF5FD95601D2503010018 +12:10:29.174 MTR: received message { + 'flag_s': 1, 'flag_dsiz': 1, 'x_flag_r': 1, 'x_flag_sx': 1, 'sec_mx': 0, 'sec_flags': 0, + 'dest_node_id_2': nil, 'sec_sesstype': 0, 'local_session_id': 0, 'ack_message_counter': -2014389550, + 'x_flag_v': 1, 'flags': 5, 'vendor_id': 8193, 'x_flag_i': 1, 'source_node_id': bytes('96B90B530000347B'), + 'app_payload_idx': 51590, + 'raw': bytes('050000000674C82B96B90B530000347BFD880AC8128000215FC3000015300120...'), + 'exchange_id': 0, 'opcode': 195, 'message_counter': 734557190, 'sec_p': 0, 'sec_c': 0, + 'protocol_id': 12309, 'dest_node_id_8': bytes('FD880AC812800021'), + 'sec_extensions': nil, 'x_flag_a': 1, 'x_flags': 95} + +347BFD880AC81280 + +fe80::1bf1:bd1a:c5ff:818a +b8:27:eb:8b:d2:59 + +{'mac': 'C8:2B:96:B9:0B:53', 'ip6local': 'fe80::ca2b:96ff:feb9:b53', 'ip': '192.168.1.116'} + +-# diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Device.be b/lib/libesp32/berry_matter/src/embedded/Matter_Device.be new file mode 100644 index 000000000..96463cac2 --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Device.be @@ -0,0 +1,508 @@ +# +# Matter_Device.be - implements a generic Matter device (commissionee) +# +# Copyright (C) 2023 Stephan Hadinger & Theo Arends +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +#@ solidify:Matter_Device,weak + +class Matter_Device + static var UDP_PORT = 5540 # this is the default port for group multicast, we also use it for unicast + static var PASSCODE_DEFAULT = 20202021 + static var PBKDF_ITERATIONS = 1000 # I don't see any reason to choose a different number + static var VENDOR_ID = 0xFFF1 + static var PRODUCT_ID = 0x8000 + static var FILENAME = "_matter_device.json" + var plugins # list of plugins + var udp_server # `matter.UDPServer()` object + var msg_handler # `matter.MessageHandler()` object + var sessions # `matter.Session_Store()` objet + var ui + # information about the device + var commissioning_instance_wifi # random instance name for commissioning + var commissioning_instance_eth # random instance name for commissioning + var hostname_wifi # MAC-derived hostname for commissioning + var hostname_eth # MAC-derived hostname for commissioning + var vendorid + var productid + var discriminator + # context for PBKDF + var passcode + var iterations + # PBKDF information used only during PASE (freed afterwards) + var salt + var w0, w1, L + + ############################################################# + def init() + import crypto + import string + if !tasmota.get_option(matter.MATTER_OPTION) + matter.UI(self) # minimal UI + return + end # abort if SetOption 151 is not set + + self.plugins = [] + self.vendorid = self.VENDOR_ID + self.productid = self.PRODUCT_ID + self.iterations = self.PBKDF_ITERATIONS + self.load_param() + self.commissioning_instance_wifi = crypto.random(8).tohex() # 16 characters random hostname + self.commissioning_instance_eth = crypto.random(8).tohex() # 16 characters random hostname + + self.sessions = matter.Session_Store() + self.sessions.load() + self.msg_handler = matter.MessageHandler(self) + self.ui = matter.UI(self) + + # add the default plugin + self.plugins.push(matter.Plugin_core(self)) + + self.start_mdns_announce_hostnames() + + if tasmota.wifi()['up'] + self.start_udp(self.UDP_PORT) + else + tasmota.add_rule("Wifi#Connected", def () + self.start_udp(self.UDP_PORT) + tasmota.remove_rule("Wifi#Connected", "matter_device_udp") + + end, self) + end + + if tasmota.eth()['up'] + self.start_udp(self.UDP_PORT) + else + tasmota.add_rule("Eth#Connected", def () + self.start_udp(self.UDP_PORT) + tasmota.remove_rule("Eth#Connected", "matter_device_udp") + end, self) + end + + self.start_basic_commissioning() + + tasmota.add_driver(self) + end + + ############################################################# + # Start Basic Commissioning Window + def start_basic_commissioning() + # compute PBKDF + self.compute_pbkdf(self.passcode) + end + + def finish_commissioning() + end + + ############################################################# + # Compute the PBKDF parameters for SPAKE2+ + # + # iterations is set to 1000 which is large enough + def compute_pbkdf(passcode_int) + import crypto + self.salt = crypto.random(16) # bytes("5350414B453250204B65792053616C74") + var passcode = bytes().add(passcode_int, 4) + + var tv = crypto.PBKDF2_HMAC_SHA256().derive(passcode, self.salt, self.iterations, 80) + var w0s = tv[0..39] + var w1s = tv[40..79] + + self.w0 = crypto.EC_P256().mod(w0s) + self.w1 = crypto.EC_P256().mod(w1s) + self.L = crypto.EC_P256().public_key(self.w1) + + tasmota.log("MTR: ******************************", 3) + tasmota.log("MTR: salt = " + self.salt.tohex(), 3) + tasmota.log("MTR: passcode = " + passcode.tohex(), 3) + tasmota.log("MTR: w0 = " + self.w0.tohex(), 3) + tasmota.log("MTR: w1 = " + self.w1.tohex(), 3) + tasmota.log("MTR: L = " + self.L.tohex(), 3) + tasmota.log("MTR: ******************************", 3) + end + + ############################################################# + # compute QR Code content + def compute_qrcode_content() + var raw = bytes().resize(11) # we don't use TLV Data so it's only 88 bits or 11 bytes + # version is `000` dont touch + raw.setbits(3, 16, self.vendorid) + raw.setbits(19, 16, self.productid) + # custom flow = 0 (offset=35, len=2) + raw.setbits(37, 8, 0x04) # already on IP network + raw.setbits(45, 12, self.discriminator & 0xFFF) + raw.setbits(57, 27, self.passcode & 0x7FFFFFF) + # padding (offset=84 len=4) + return "MT:" + matter.Base38.encode(raw) + end + + + ############################################################# + # compute the 11 digits manual pairing code (wihout vendorid nor productid) p.223 + def compute_manual_pairing_code() + import string + var digit_1 = (self.discriminator & 0x0FFF) >> 10 + var digit_2_6 = ((self.discriminator & 0x0300) << 6) | (self.passcode & 0x3FFF) + var digit_7_10 = (self.passcode >> 14) + + var ret = string.format("%1i%05i%04i", digit_1, digit_2_6, digit_7_10) + ret += matter.Verhoeff.checksum(ret) + return ret + end + + ############################################################# + # dispatch every second click to sub-objects that need it + def every_second() + self.sessions.every_second() + self.msg_handler.every_second() + end + + ############################################################# + def stop() + if self.udp_server self.udp_server.stop() end + end + + ############################################################# + # callback when message is received + def msg_received(raw, addr, port) + return self.msg_handler.msg_received(raw, addr, port) + end + + def msg_send(raw, addr, port, id) + return self.udp_server.send_response(raw, addr, port, id) + end + + def packet_ack(id) + return self.udp_server.packet_ack(id) + end + + ############################################################# + # Start UDP Server + def start_udp(port) + if self.udp_server return end # already started + if port == nil port = 5540 end + tasmota.log("MTR: starting UDP server on port: " + str(port), 2) + self.udp_server = matter.UDPServer("", port) + self.udp_server.start(/ raw, addr, port -> self.msg_received(raw, addr, port)) + end + + ############################################################# + # start_operational_dicovery + # + # Pass control to `device` + def start_operational_dicovery_deferred(session) + # defer to next click + tasmota.set_timer(0, /-> self.start_operational_dicovery(session)) + end + + ############################################################# + def start_commissioning_complete_deferred(session) + # defer to next click + tasmota.set_timer(0, /-> self.start_commissioning_complete(session)) + end + + ############################################################# + # Start UDP mDNS announcements for commissioning + # + # eth is `true` if ethernet turned up, `false` is wifi turned up + # def mdns_announce_commissioning() + # var services = { + # "VP":str(self.vendorid) + "+" + str(self.productid), + # "D": self.discriminator, + # "CM":1, # requires passcode + # "T":0, # no support for TCP + # "SII":5000, "SAI":300 + # } + + # if self.self.hostname_eth + # mdns.add_service("_matterc","_udp", 5540, services, self.commissioning_instance_eth, self.hostname_eth) + # end + # if self.self.hostname_wifi + # mdns.add_service("_matter","_tcp", 5540, services, self.commissioning_instance_wifi, self.hostname_wifi) + # end + # end + + ############################################################# + # Start Operational Discovery + def start_operational_dicovery(session) + import crypto + import mdns + import string + + # clear any PBKDF information to free memory + self.salt = nil + self.w0 = nil + self.w1 = nil + self.L = nil + + # save session as persistant + session.set_no_expiration() + session.set_persist(true) + # close the PASE session, it will be re-opened with a CASE session + session.close() + self.sessions.save() + + self.mdns_announce_op_discovery(session) + end + + ############################################################# + # Commissioning Complete + # + def start_commissioning_complete(session) + tasmota.log("MTR: *** Commissioning complete ***", 2) + end + + ############################################################# + # read an attribute + # + def read_attribute(msg, endpoint, cluster, attribute) + var idx = 0 + while idx < size(self.plugins) + var plugin = self.plugins[idx] + + var ret = plugin.read_attribute(msg, endpoint, cluster, attribute) + if ret != nil + return ret + end + + idx += 1 + end + end + + + + ############################################################# + # Persistance of Matter Device parameters + # + ############################################################# + # + def save_param() + import json + var j = json.dump({'distinguish':self.discriminator, 'passcode':self.passcode}) + try + import string + var f = open(self.FILENAME, "w") + f.write(j) + f.close() + return j + except .. as e, m + tasmota.log("MTR: Session_Store::save Exception:" + str(e) + "|" + str(m), 2) + return j + end + end + + ############################################################# + def load_param() + import string + import crypto + try + + var f = open(self.FILENAME) + var s = f.read() + f.close() + + import json + var j = json.load(s) + + self.discriminator = j.find("distinguish") + self.passcode = j.find("passcode") + except .. as e, m + if e != "io_error" + tasmota.log("MTR: Session_Store::load Exception:" + str(e) + "|" + str(m), 2) + end + end + + var dirty = false + if self.discriminator == nil + self.discriminator = crypto.random(2).get(0,2) & 0xFFF + dirty = true + end + if self.passcode == nil + self.passcode = self.PASSCODE_DEFAULT + dirty = true + end + if dirty self.save_param() end + end + + + ############################################################# + # Matter plugin management + # + # Plugins allow to specify response to read/write attributes + # and command invokes + ############################################################# + def invoke_request(msg, val, ctx) + var idx = 0 + while idx < size(self.plugins) + var plugin = self.plugins[idx] + + var ret = plugin.invoke_request(msg, val, ctx) + if ret != nil || ctx.status != matter.UNSUPPORTED_COMMAND # default value + return ret + end + + idx += 1 + end + end + + ############################################################# + # MDNS Configuration + ############################################################# + # Start MDNS and announce hostnames for Wifi and ETH from MAC + # + # When the announce is active, `hostname_wifi` and `hostname_eth` + # are defined + def start_mdns_announce_hostnames() + if tasmota.wifi()['up'] + self._start_mdns_announce(false) + else + tasmota.add_rule("Wifi#Connected", def () + self._start_mdns_announce(false) + tasmota.remove_rule("Wifi#Connected", "matter_device_mdns") + end, self) + end + + if tasmota.eth()['up'] + self._start_mdns_announce(true) + else + tasmota.add_rule("Eth#Connected", def () + self._start_mdns_announce(true) + tasmota.remove_rule("Eth#Connected", "matter_device_mdns") + end, self) + end + end + + ############################################################# + # Start UDP mDNS announcements for commissioning + # + # eth is `true` if ethernet turned up, `false` is wifi turned up + def _start_mdns_announce(is_eth) + import mdns + import string + + mdns.start() + + var services = { + "VP":str(self.vendorid) + "+" + str(self.productid), + "D": self.discriminator, + "CM":1, # requires passcode + "T":0, # no support for TCP + "SII":5000, "SAI":300 + } + + # mdns + try + if is_eth + var eth = tasmota.eth() + self.hostname_eth = string.replace(eth.find("mac"), ':', '') + mdns.add_hostname(self.hostname_eth, eth.find('ip6local',''), eth.find('ip',''), eth.find('ip6','')) + mdns.add_service("_matterc", "_udp", 5540, services, self.commissioning_instance_eth, self.hostname_eth) + + tasmota.log(string.format("MTR: starting mDNS on %s '%s' ptr to `%s.local`", is_eth ? "eth" : "wifi", + is_eth ? self.commissioning_instance_eth : self.commissioning_instance_wifi, + is_eth ? self.hostname_eth : self.hostname_wifi), 2) + + # `mdns.add_subtype(service:string, proto:string, instance:string, hostname:string, subtype:string) -> nil` + var subtype = "_L" + str(self.discriminator & 0xFFF) + tasmota.log("MTR: adding subtype: "+subtype, 3) + mdns.add_subtype("_matterc", "_udp", self.commissioning_instance_eth, self.hostname_eth, subtype) + subtype = "_S" + str((self.discriminator & 0xF00) >> 8) + tasmota.log("MTR: adding subtype: "+subtype, 3) + mdns.add_subtype("_matterc", "_udp", self.commissioning_instance_eth, self.hostname_eth, subtype) + subtype = "_V" + str(self.vendorid) + tasmota.log("MTR: adding subtype: "+subtype, 3) + mdns.add_subtype("_matterc", "_udp", self.commissioning_instance_eth, self.hostname_eth, subtype) + subtype = "_CM1" + tasmota.log("MTR: adding subtype: "+subtype, 3) + mdns.add_subtype("_matterc", "_udp", self.commissioning_instance_eth, self.hostname_eth, subtype) + else + var wifi = tasmota.wifi() + self.hostname_wifi = string.replace(wifi.find("mac"), ':', '') + mdns.add_hostname(self.hostname_wifi, wifi.find('ip6local',''), wifi.find('ip',''), wifi.find('ip6','')) + mdns.add_service("_matter", "_tcp", 5540, services, self.commissioning_instance_wifi, self.hostname_wifi) + + tasmota.log(string.format("MTR: starting mDNS on %s '%s' ptr to `%s.local`", is_eth ? "eth" : "wifi", + is_eth ? self.commissioning_instance_eth : self.commissioning_instance_wifi, + is_eth ? self.hostname_eth : self.hostname_wifi), 2) + + # `mdns.add_subtype(service:string, proto:string, instance:string, hostname:string, subtype:string) -> nil` + var subtype = "_L" + str(self.discriminator & 0xFFF) + tasmota.log("MTR: adding subtype: "+subtype, 3) + mdns.add_subtype("_matterc", "_udp", self.commissioning_instance_wifi, self.hostname_wifi, subtype) + subtype = "_S" + str((self.discriminator & 0xF00) >> 8) + tasmota.log("MTR: adding subtype: "+subtype, 3) + mdns.add_subtype("_matterc", "_udp", self.commissioning_instance_wifi, self.hostname_wifi, subtype) + subtype = "_V" + str(self.vendorid) + tasmota.log("MTR: adding subtype: "+subtype, 3) + mdns.add_subtype("_matterc", "_udp", self.commissioning_instance_wifi, self.hostname_wifi, subtype) + subtype = "_CM1" + tasmota.log("MTR: adding subtype: "+subtype, 3) + mdns.add_subtype("_matterc", "_udp", self.commissioning_instance_wifi, self.hostname_wifi, subtype) + end + except .. as e, m + tasmota.log("MTR: Exception" + str(e) + "|" + str(m), 2) + end + + self.mdns_announce_op_discovery_all_sessions() + end + + ############################################################# + # Start UDP mDNS announcements for commissioning for all persisted sessions + def mdns_announce_op_discovery_all_sessions() + for session: self.sessions.sessions + if session.get_deviceid() && session.get_fabric() + self.mdns_announce_op_discovery(session) + end + end + end + + ############################################################# + # Start UDP mDNS announcements for commissioning + def mdns_announce_op_discovery(session) + import mdns + import string + try + var device_id = session.get_deviceid().copy().reverse() + var k_fabric = session.get_fabric_compressed() + var op_node = k_fabric.tohex() + "-" + device_id.tohex() + tasmota.log("MTR: Operational Discovery node = " + op_node, 2) + + # mdns + if (tasmota.eth().find("up")) + tasmota.log(string.format("MTR: adding mDNS on %s '%s' ptr to `%s.local`", "eth", op_node, self.hostname_eth), 3) + mdns.add_service("_matter","_tcp", 5540, nil, op_node, self.hostname_eth) + var subtype = "_I" + k_fabric.tohex() + tasmota.log("MTR: adding subtype: "+subtype, 3) + mdns.add_subtype("_matter", "_tcp", op_node, self.hostname_eth, subtype) + end + if (tasmota.wifi().find("up")) + tasmota.log(string.format("MTR: adding mDNS on %s '%s' ptr to `%s.local`", "wifi", op_node, self.hostname_wifi), 3) + mdns.add_service("_matter","_tcp", 5540, nil, op_node, self.hostname_wifi) + var subtype = "_I" + k_fabric.tohex() + tasmota.log("MTR: adding subtype: "+subtype, 3) + mdns.add_subtype("_matter", "_tcp", op_node, self.hostname_wifi, subtype) + end + except .. as e, m + tasmota.log("MTR: Exception" + str(e) + "|" + str(m), 2) + end + end +end +matter.Device = Matter_Device + +#- +import global +global.matter_device = matter_device() +return matter_device +-# diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_IM.be b/lib/libesp32/berry_matter/src/embedded/Matter_IM.be new file mode 100644 index 000000000..35fdb74d7 --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_IM.be @@ -0,0 +1,326 @@ +# +# Matter_IM.be - suppport for Matter Interaction Model +# +# Copyright (C) 2023 Stephan Hadinger & Theo Arends +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +import matter + +#@ solidify:Matter_Response_container,weak +#@ solidify:Matter_IM,weak + +################################################################################# +# Matter_Response_container +# +# Used to store all the elements of the reponse to an attribute or command +################################################################################# +class Matter_Response_container + var endpoint + var cluster + var attribute + var command + var status +end +matter.Response_container = Matter_Response_container + +################################################################################# +# Matter_IM class +################################################################################# +class Matter_IM + var responder + + def init(responder) + self.responder = responder + end + + def process_incoming(msg, remote_ip, remote_port) + # messages are always TLV, decode payload + tasmota.log("MTR: received IM message " + matter.inspect(msg), 3) + + var val = matter.TLV.parse(msg.raw, msg.app_payload_idx) + + tasmota.log("MTR: IM TLV: " + str(val), 3) + + var InteractionModelRevision = val.findsubval(0xFF) + tasmota.log("MTR: InteractionModelRevision=" + (InteractionModelRevision != nil ? str(InteractionModelRevision) : "nil"), 3) + + var opcode = msg.opcode + if opcode == 0x01 # Status Response + return self.process_status_response(msg, val, remote_ip, remote_port) + elif opcode == 0x02 # Read Request + return self.process_read_request(msg, val, remote_ip, remote_port) + elif opcode == 0x03 # Subscribe Request + return self.subscribe_request(msg, val, remote_ip, remote_port) + elif opcode == 0x04 # Subscribe Response + return self.subscribe_response(msg, val, remote_ip, remote_port) + elif opcode == 0x05 # Report Data + return self.report_data(msg, val, remote_ip, remote_port) + elif opcode == 0x06 # Write Request + return self.process_write_request(msg, val, remote_ip, remote_port) + elif opcode == 0x07 # Write Response + return self.process_write_response(msg, val, remote_ip, remote_port) + elif opcode == 0x08 # Invoke Request + return self.process_invoke_request(msg, val, remote_ip, remote_port) + elif opcode == 0x09 # Invoke Response + return self.process_invoke_response(msg, val, remote_ip, remote_port) + elif opcode == 0x0A # Timed Request + return self.process_timed_request(msg, val, remote_ip, remote_port) + end + + return false + end + + ############################################################# + # process IM 0x01 Status Response + # + # val is the TLV structure + # returns `true` if processed, `false` if silently ignored, + # or raises an exception + def process_status_response(msg, val, remote_ip, remote_port) + import string + var status = val.findsubval(0, 0xFF) + tasmota.log(string.format("MTR: Status Response = 0x%02X", status), 3) + return true + end + + ############################################################# + # process IM 0x02 Read Request + # + # val is the TLV structure + # returns `true` if processed, `false` if silently ignored, + # or raises an exception + def process_read_request(msg, val, remote_ip, remote_port) + # structure is `ReadRequestMessage` 10.6.2 p.558 + tasmota.log("MTR: IM:read_request processing start", 3) + + var query = matter.ReadRequestMessage().from_TLV(val) + if query.attributes_requests != nil + # prepare the response + var ret = matter.ReportDataMessage() + ret.suppress_response = true + ret.attribute_reports = [] + + # TODO - we need to implement Concrete path expansion here + + for q:query.attributes_requests + var attr_name = matter.get_attribute_name(q.cluster, q.attribute) + tasmota.log("MTR: Read Attribute " + str(q) + (attr_name ? " (" + attr_name + ")" : ""), 2) + var res = self.responder.device.read_attribute(msg, q.endpoint, q.cluster, q.attribute) + if res != nil + var a1 = matter.AttributeReportIB() + # a1.attribute_status = matter.AttributeStatusIB() + # a1.attribute_status.path = matter.AttributePathIB() + # a1.attribute_status.status = matter.StatusIB() + # a1.attribute_status.path.endpoint = 0 + # a1.attribute_status.path.cluster = q.cluster + # a1.attribute_status.path.attribute = q.attribute + # a1.attribute_status.status.status = matter.SUCCESS + a1.attribute_data = matter.AttributeDataIB() + a1.attribute_data.data_version = 1 + a1.attribute_data.path = matter.AttributePathIB() + a1.attribute_data.path.endpoint = 0 + a1.attribute_data.path.cluster = q.cluster + a1.attribute_data.path.attribute = q.attribute + a1.attribute_data.data = res + + ret.attribute_reports.push(a1) + end + end + + tasmota.log("MTR: ReportDataMessage=" + str(ret), 3) + tasmota.log("MTR: ReportDataMessageTLV=" + str(ret.to_TLV()), 3) + + var resp = msg.build_response(0x05 #-Report Data-#, true) + resp.encode(ret.to_TLV().encode()) # payload in cleartext + resp.encrypt() + + self.responder.send_response(resp.raw, remote_ip, remote_port, resp.message_counter) + end + + return true + end + + ############################################################# + # process IM 0x08 Invoke Request + # + # val is the TLV structure + # returns `true` if processed, `false` if silently ignored, + # or raises an exception + def process_invoke_request(msg, val, remote_ip, remote_port) + import string + # structure is `ReadRequestMessage` 10.6.2 p.558 + tasmota.log("MTR: IM:invoke_request processing start", 3) + var ctx = matter.Response_container() + + var query = matter.InvokeRequestMessage().from_TLV(val) + if query.invoke_requests != nil + # prepare the response + var ret = matter.InvokeResponseMessage() + ret.suppress_response = false + ret.invoke_responses = [] + + for q:query.invoke_requests + ctx.endpoint = q.command_path.endpoint + ctx.cluster = q.command_path.cluster + ctx.command = q.command_path.command + ctx.status = matter.UNSUPPORTED_COMMAND #default error if returned `nil` + + var cmd_name = matter.get_command_name(ctx.cluster, ctx.command) + if cmd_name == nil cmd_name = string.format("0x%04X/0x02X", ctx.cluster, ctx.command) end + tasmota.log(string.format("MTR: >Received_cmd %s from [%s]:%i", cmd_name, remote_ip, remote_port), 2) + var res = self.responder.device.invoke_request(msg, q.command_fields, ctx) + var a1 = matter.InvokeResponseIB() + if res != nil + a1.command = matter.CommandDataIB() + a1.command.command_path = matter.CommandPathIB() + a1.command.command_path.endpoint = ctx.endpoint + a1.command.command_path.cluster = ctx.cluster + a1.command.command_path.command = ctx.command + a1.command.command_fields = res + ret.invoke_responses.push(a1) + + cmd_name = matter.get_command_name(ctx.cluster, ctx.command) + if cmd_name == nil cmd_name = string.format("0x%04X/0x%02X", ctx.cluster, ctx.command) end + tasmota.log(string.format("MTR: Received_IM TimedRequest=%i from [%s]:%i", query.timeout, remote_ip, remote_port), 2) + + # Send success status report + var sr = matter.StatusResponseMessage() + sr.status = matter.SUCCESS + var resp = msg.build_response(0x01 #-Status Response-#, true #-reliable-#) + resp.encode(sr.to_TLV().encode()) # payload in cleartext + resp.encrypt() + self.responder.send_response(resp.raw, remote_ip, remote_port, resp.message_counter) + + return true + end + + ############################################################# + # placeholder, nothing to run for now + def every_second() + end +end +matter.IM = Matter_IM + +#- + +# Unit tests + + +-# + diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_IM_Data.be b/lib/libesp32/berry_matter/src/embedded/Matter_IM_Data.be new file mode 100644 index 000000000..b6f367bc9 --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_IM_Data.be @@ -0,0 +1,946 @@ +# +# Matter_IM_Data.be - suppport for Matter Interation Model messages structure +# +# Copyright (C) 2023 Stephan Hadinger & Theo Arends +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +import matter + +#@ solidify:Matter_IM_base,weak +#@ solidify:Matter_IM_Message_base,weak + +#@ solidify:matter.AttributePathIB,weak +#@ solidify:matter.ClusterPathIB,weak +#@ solidify:matter.DataVersionFilterIB,weak +#@ solidify:matter.AttributeDataIB,weak +#@ solidify:matter.AttributeReportIB,weak +#@ solidify:matter.EventFilterIB,weak +#@ solidify:matter.EventPathIB,weak +#@ solidify:matter.EventDataIB,weak +#@ solidify:matter.EventReportIB,weak +#@ solidify:matter.CommandPathIB,weak +#@ solidify:matter.CommandDataIB,weak +#@ solidify:matter.InvokeResponseIB,weak +#@ solidify:matter.CommandStatusIB,weak +#@ solidify:matter.EventStatusIB,weak +#@ solidify:matter.AttributeStatusIB,weak +#@ solidify:matter.StatusIB,weak +#@ solidify:matter.StatusResponseMessage,weak +#@ solidify:matter.ReadRequestMessage,weak +#@ solidify:matter.ReportDataMessage,weak +#@ solidify:matter.SubscribeRequestMessage,weak +#@ solidify:matter.SubscribeResponseMessage,weak +#@ solidify:matter.WriteRequestMessage,weak +#@ solidify:matter.WriteResponseMessage,weak +#@ solidify:matter.TimedRequestMessage,weak +#@ solidify:matter.InvokeRequestMessage,weak +#@ solidify:matter.InvokeResponseMessage,weak + +################################################################################# +# Base class for all IM containers +################################################################################# +class Matter_IM_base + def tostring() + return "<" + classname(self) + ":" + matter.inspect(self) + ">" + end + + # arr: array (list) of TLV values + # cl: class for the TLV decoder + def from_TLV_array(arr, cl) + if arr == nil return nil end + var r = [] + for v:arr + r.push(cl().from_TLV(v)) + end + return r + end + + # add an array of objects to TLV + # s: current container to add to + # tag: tag for the array (inner items don't have tags) + # arr: the array of objects supporting `to_TLV()` + # + # if arr is `nil`, nothing happens + def to_TLV_array(s, tag, arr) + if arr == nil return nil end + var l = s.add_array(tag) # create the list container and add to the current container + for v:arr + l.add_obj(nil, v) + end + end +end + +################################################################################# +# Matter_AttributePathIB class +################################################################################# +class Matter_AttributePathIB : Matter_IM_base + var tag_compression # false if none + var node # u64 as bytes + var endpoint # u16 + var cluster # u32 + var attribute # u32 + var list_index # ? + + def tostring() + try + import string + var s = "" + if self.node s += string.format("node=%s ", self.node) end + s += (self.endpoint != nil ? string.format("[%02X]", self.endpoint) : "[**]") + s += (self.cluster != nil ? string.format("%04X/", self.cluster) : "****/") + s += (self.attribute != nil ? string.format("%04X", self.attribute) : "****") + return s + except .. as e, m + return "Exception> " + str(e) + ", " + str(m) + end + end + + # decode from TLV + def from_TLV(val) + if val == nil return nil end + self.tag_compression = val.findsubval(0) + self.node = val.findsubval(1) + self.endpoint = val.findsubval(2) + self.cluster = val.findsubval(3) + self.attribute = val.findsubval(4) + self.list_index = val.findsubval(5) + return self + end + + def to_TLV() + var TLV = matter.TLV + var s = TLV.Matter_TLV_list() + s.add_TLV(0, TLV.BOOL, self.tag_compression) + s.add_TLV(1, TLV.U8, self.node) + s.add_TLV(2, TLV.U2, self.endpoint) + s.add_TLV(3, TLV.U4, self.cluster) + s.add_TLV(4, TLV.U4, self.attribute) + s.add_TLV(5, TLV.U2, self.list_index) + return s + end +end +matter.AttributePathIB = Matter_AttributePathIB + + +################################################################################# +# ClusterPathIB class +################################################################################# +class Matter_ClusterPathIB : Matter_IM_base + var node # u64 as bytes + var endpoint # u16 + var cluster # u32 + + # decode from TLV + def from_TLV(val) + if val == nil return nil end + self.node = val.findsubval(0) + self.endpoint = val.findsubval(1) + self.cluster = val.findsubval(2) + return self + end + + def to_TLV() + var TLV = matter.TLV + var s = TLV.Matter_TLV_list() + s.add_TLV(0, TLV.U8, self.node) + s.add_TLV(1, TLV.U2, self.endpoint) + s.add_TLV(2, TLV.U4, self.cluster) + return s + end +end +matter.ClusterPathIB = Matter_ClusterPathIB + +################################################################################# +# DataVersionFilterIB class +################################################################################# +class Matter_DataVersionFilterIB : Matter_IM_base + var path # false if none + var data_version # u64 as bytes + + # decode from TLV + def from_TLV(val) + if val == nil return nil end + self.path = matter.ClusterPathIB().from_TLV(val.findsub(0)) + self.data_version = val.findsubval(1) # u32 + return self + end + + def to_TLV() + var TLV = matter.TLV + var s = TLV.Matter_TLV_struct() + s.add_obj(0, self.path) + s.add_TLV(1, TLV.U4, self.data_version) + return s + end +end +matter.DataVersionFilterIB = Matter_DataVersionFilterIB + +################################################################################# +# AttributeDataIB class +################################################################################# +class Matter_AttributeDataIB : Matter_IM_base + var data_version # u32 + var path # AttributePathIB + var data # any TLV + + # decode from TLV + def from_TLV(val) + if val == nil return nil end + self.data_version = val.findsubval(0) # u32 + self.path = matter.AttributePathIB().from_TLV(val.findsub(1)) + self.data = val.findsubval(2) # any + return self + end + + def to_TLV() + var TLV = matter.TLV + var s = TLV.Matter_TLV_struct() + s.add_TLV(0, TLV.U4, self.data_version) + s.add_obj(1, self.path) + s.add_obj(2, self.data) + return s + end +end +matter.AttributeDataIB = Matter_AttributeDataIB + +################################################################################# +# AttributeReportIB class +################################################################################# +class Matter_AttributeReportIB : Matter_IM_base + var attribute_status # AttributeStatusIB + var attribute_data # AttributeDataIB + + # decode from TLV + def from_TLV(val) + if val == nil return nil end + self.attribute_status = matter.AttributeStatusIB().from_TLV(val.findsub(0)) + self.attribute_data = matter.AttributeDataIB().from_TLV(val.findsub(1)) + return self + end + + def to_TLV() + var TLV = matter.TLV + var s = TLV.Matter_TLV_struct() + s.add_obj(0, self.attribute_status) + s.add_obj(1, self.attribute_data) + return s + end +end +matter.AttributeReportIB = Matter_AttributeReportIB + +################################################################################# +# EventFilterIB class +################################################################################# +class Matter_EventFilterIB : Matter_IM_base + var node # u64 + var event_min # u64 + + # decode from TLV + def from_TLV(val) + if val == nil return nil end + self.node = val.findsubval(0) + self.event_min = val.findsubval(1) + return self + end + + def to_TLV() + var TLV = matter.TLV + var s = TLV.Matter_TLV_struct() + s.add_TLV(0, TLV.U8, self.node) + s.add_TLV(1, TLV.U8, self.event_min) + return s + end +end +matter.EventFilterIB = Matter_EventFilterIB + +################################################################################# +# EventPathIB class +################################################################################# +class Matter_EventPathIB : Matter_IM_base + var node # u64 as bytes + var endpoint # u16 + var cluster # u32 + var event # u32 + var is_urgent # bool + + # decode from TLV + def from_TLV(val) + if val == nil return nil end + self.node = val.findsubval(0) + self.endpoint = val.findsubval(1) + self.cluster = val.findsubval(2) + self.event = val.findsubval(3) + self.is_urgent = val.findsubval(4) + return self + end + + def to_TLV(s) + var TLV = matter.TLV + if s == nil s = TLV.Matter_TLV_list() end + s.add_TLV(0, TLV.U8, self.node) + s.add_TLV(1, TLV.U2, self.endpoint) + s.add_TLV(2, TLV.U4, self.cluster) + s.add_TLV(3, TLV.U4, self.event) + s.add_TLV(4, TLV.BOOL, self.is_urgent) + return s + end +end +matter.EventPathIB = Matter_EventPathIB + + +################################################################################# +# EventDataIB class +################################################################################# +class Matter_EventDataIB : Matter_IM_base + var path # + var event_number # u64 as bytes + var priority # u8 + # one of + var epoch_timestamp # u64 + var system_timestamp # u64 + var delta_epoch_timestamp # u64 + var delta_system_timestamp # u64 + # data + var data # any TLV + + # decode from TLV + def from_TLV(val) + if val == nil return nil end + self.path = matter.EventPathIB().from_TLV(val.findsub(0)) + self.event_number = val.findsubval(1) # u64 + self.priority = val.findsubval(2) # u64 + self.epoch_timestamp = val.findsubval(3) # u64 + self.system_timestamp = val.findsubval(4) # u64 + self.delta_epoch_timestamp = val.findsubval(5) # u64 + self.delta_system_timestamp = val.findsubval(6) # u64 + self.data = val.findsubval(7) # any + return self + end + + def to_TLV(s) + var TLV = matter.TLV + if s == nil s = TLV.Matter_TLV_struct() end + if self.path + self.path.to_TLV(s.add_list(0)) + end + s.add_TLV(1, TLV.U8, self.event_number) + s.add_TLV(2, TLV.U1, self.priority) + s.add_TLV(3, TLV.U8, self.epoch_timestamp) + s.add_TLV(4, TLV.U8, self.system_timestamp) + s.add_TLV(5, TLV.U8, self.delta_epoch_timestamp) + s.add_TLV(6, TLV.U8, self.delta_system_timestamp) + s.add_obj(7, self.data) + return s + end +end +matter.EventDataIB = Matter_EventDataIB + + +################################################################################# +# EventReportIB class +################################################################################# +class Matter_EventReportIB : Matter_IM_base + var event_status # EventStatusIB + var event_data # EventDataIB + + # decode from TLV + def from_TLV(val) + if val == nil return nil end + self.event_status = matter.EventStatusIB().from_TLV(val.findsub(0)) + self.event_data = matter.EventDataIB().from_TLV(val.findsub(1)) + return self + end + + def to_TLV() + var TLV = matter.TLV + var s = TLV.Matter_TLV_struct() + s.add_obj(0, self.event_status) + s.add_obj(1, self.event_data) + return s + end +end +matter.EventReportIB = Matter_EventReportIB + +################################################################################# +# CommandPathIB class +################################################################################# +class Matter_CommandPathIB : Matter_IM_base + var endpoint # u16 + var cluster # u32 + var command # u32 + + # decode from TLV + def from_TLV(val) + if val == nil return nil end + self.endpoint = val.findsubval(0) + self.cluster = val.findsubval(1) + self.command = val.findsubval(2) + return self + end + + def to_TLV() + var TLV = matter.TLV + var s = TLV.Matter_TLV_list() + s.add_TLV(0, TLV.U2, self.endpoint) + s.add_TLV(1, TLV.U4, self.cluster) + s.add_TLV(2, TLV.U4, self.command) + return s + end +end +matter.CommandPathIB = Matter_CommandPathIB + +################################################################################# +# CommandDataIB class +################################################################################# +class Matter_CommandDataIB : Matter_IM_base + var command_path # CommandPathIB + var command_fields # any + + # decode from TLV + def from_TLV(val) + if val == nil return nil end + self.command_path = matter.CommandPathIB().from_TLV(val.findsub(0)) + self.command_fields = val.findsub(1) + return self + end + + def to_TLV() + var TLV = matter.TLV + var s = TLV.Matter_TLV_struct() + s.add_obj(0, self.command_path) + s.add_obj(1, self.command_fields) + return s + end +end +matter.CommandDataIB = Matter_CommandDataIB + + +################################################################################# +# InvokeResponseIB class +################################################################################# +class Matter_InvokeResponseIB : Matter_IM_base + var command # CommandDataIB + var status # CommandStatusIB + + # decode from TLV + def from_TLV(val) + if val == nil return nil end + self.command = matter.CommandDataIB().from_TLV(val.findsub(0)) + self.status = matter.CommandStatusIB().from_TLV(val.findsub(1)) + return self + end + + def to_TLV() + var TLV = matter.TLV + var s = TLV.Matter_TLV_struct() + s.add_obj(0, self.command) + s.add_obj(1, self.status) + return s + end +end +matter.InvokeResponseIB = Matter_InvokeResponseIB + + +################################################################################# +# CommandStatusIB class +################################################################################# +class Matter_CommandStatusIB : Matter_IM_base + var command_path # CommandPathIB + var status # StatusIB + + # decode from TLV + def from_TLV(val) + if val == nil return nil end + self.command_path = matter.CommandPathIB().from_TLV(val.findsub(0)) + self.status = matter.StatusIB().from_TLV(val.findsub(1)) + return self + end + + def to_TLV() + var TLV = matter.TLV + var s = TLV.Matter_TLV_struct() + s.add_obj(0, self.command_path) + s.add_obj(1, self.status) + return s + end +end +matter.CommandStatusIB = Matter_CommandStatusIB + +################################################################################# +# EventStatusIB class +################################################################################# +class Matter_EventStatusIB : Matter_IM_base + var path # EventPathIB + var status # StatusIB + + # decode from TLV + def from_TLV(val) + if val == nil return nil end + self.path = matter.EventPathIB().from_TLV(val.findsub(0)) + self.status = matter.StatusIB().from_TLV(val.findsub(1)) + return self + end + + def to_TLV() + var TLV = matter.TLV + var s = TLV.Matter_TLV_struct() + s.add_obj(0, self.path) + s.add_obj(1, self.status) + return s + end +end +matter.EventStatusIB = Matter_EventStatusIB + +################################################################################# +# AttributeStatusIB class +################################################################################# +class Matter_AttributeStatusIB : Matter_IM_base + var path # AttributePathIB + var status # StatusIB + + # decode from TLV + def from_TLV(val) + if val == nil return nil end + self.path = matter.AttributePathIB().from_TLV(val.findsub(0)) + self.status = matter.StatusIB().from_TLV(val.findsub(1)) + return self + end + + def to_TLV() + var TLV = matter.TLV + var s = TLV.Matter_TLV_struct() + s.add_obj(0, self.path) + s.add_obj(1, self.status) + return s + end +end +matter.AttributeStatusIB = Matter_AttributeStatusIB + +################################################################################# +# StatusIB class +################################################################################# +class Matter_StatusIB : Matter_IM_base + var status # u16 + var cluster_status # u16 + + # decode from TLV + def from_TLV(val) + if val == nil return nil end + self.status = val.findsubval(0) + self.cluster_status = val.findsubval(1) + return self + end + + def to_TLV() + var TLV = matter.TLV + var s = TLV.Matter_TLV_list() + s.add_TLV(0, TLV.U2, self.status) + s.add_TLV(1, TLV.U2, self.cluster_status) + return s + end +end +matter.StatusIB = Matter_StatusIB + +################################################################################# +################################################################################# +# Matter_IM_Message_base class +# +# This is the superclass for all high-level messages +################################################################################# +################################################################################# +class Matter_IM_Message_base : Matter_IM_base + var InteractionModelRevision # 0xFF + + def init() + self.InteractionModelRevision = 1 + end +end + + +################################################################################# +# StatusResponseMessage class +################################################################################# +class Matter_StatusResponseMessage : Matter_IM_Message_base + var status # u32 + + # decode from TLV + def from_TLV(val) + if val == nil return nil end + self.status = val.findsubval(0) + return self + end + + def to_TLV() + var TLV = matter.TLV + var s = TLV.Matter_TLV_struct() + s.add_TLV(0, TLV.U4, self.status) + s.add_TLV(0xFF, TLV.U1, self.InteractionModelRevision) + return s + end +end +matter.StatusResponseMessage = Matter_StatusResponseMessage + +################################################################################# +# ReadRequestMessage class +################################################################################# +class Matter_ReadRequestMessage : Matter_IM_Message_base + var attributes_requests # array of AttributePathIB + var event_requests # array of EventPathIB + var event_filters # array of EventFilterIB + var fabric_filtered # bool + var data_version_filters # array of DataVersionFilterIB + + # decode from TLV + def from_TLV(val) + if val == nil return nil end + self.attributes_requests = self.from_TLV_array(val.findsubval(0), matter.AttributePathIB) + self.event_requests = self.from_TLV_array(val.findsubval(1), matter.EventPathIB) + self.event_filters = self.from_TLV_array(val.findsubval(2), matter.EventFilterIB) + self.fabric_filtered = val.findsubval(3) + self.data_version_filters = self.from_TLV_array(val.findsubval(4), matter.DataVersionFilterIB) + return self + end + + def to_TLV() + var TLV = matter.TLV + var s = TLV.Matter_TLV_struct() + self.to_TLV_array(s, 0, self.attributes_requests) + self.to_TLV_array(s, 1, self.event_requests) + self.to_TLV_array(s, 2, self.event_filters) + s.add_TLV(3, TLV.BOOL, self.fabric_filtered) + self.to_TLV_array(s, 4, self.data_version_filters) + s.add_TLV(0xFF, TLV.U1, self.InteractionModelRevision) + return s + end +end +matter.ReadRequestMessage = Matter_ReadRequestMessage + +################################################################################# +# ReportDataMessage class +################################################################################# +class Matter_ReportDataMessage : Matter_IM_Message_base + var subscription_id # u32 + var attribute_reports # array of AttributeReportIB + var event_reports # array of EventReportIB + var more_chunked_messages # bool + var suppress_response # bool + + # decode from TLV + def from_TLV(val) + if val == nil return nil end + self.subscription_id = val.findsubval(0) + self.attribute_reports = self.from_TLV_array(val.findsubval(1), matter.AttributeReportIB) + self.event_reports = self.from_TLV_array(val.findsubval(2), matter.EventReportIB) + self.more_chunked_messages = val.findsubval(3) + self.suppress_response = val.findsubval(4) + return self + end + + def to_TLV() + var TLV = matter.TLV + var s = TLV.Matter_TLV_struct() + s.add_TLV(0, TLV.U4, self.subscription_id) + self.to_TLV_array(s, 1, self.attribute_reports) + self.to_TLV_array(s, 2, self.event_reports) + s.add_TLV(3, TLV.BOOL, self.more_chunked_messages) + s.add_TLV(4, TLV.BOOL, self.suppress_response) + s.add_TLV(0xFF, TLV.U1, self.InteractionModelRevision) + return s + end +end +matter.ReportDataMessage = Matter_ReportDataMessage + +################################################################################# +# SubscribeRequestMessage class +################################################################################# +class Matter_SubscribeRequestMessage : Matter_IM_Message_base + var keep_subscriptions # bool + var min_interval_floor # u16 + var max_interval_ceiling # u16 + var attribute_requests # array of AttributePathIB + var event_requests # array of EventPathIB + var event_filters # array of EventFilterIB + var fabric_filtered # bool + var data_version_filters # array of DataVersionFilterIB + + # decode from TLV + def from_TLV(val) + if val == nil return nil end + self.keep_subscriptions = val.findsubval(0) + self.min_interval_floor = val.findsubval(1) + self.max_interval_ceiling = val.findsubval(2) + self.attribute_requests = self.from_TLV_array(val.findsubval(3), matter.AttributePathIB) + self.event_requests = self.from_TLV_array(val.findsubval(4), matter.EventPathIB) + self.event_filters = self.from_TLV_array(val.findsubval(5), matter.EventFilterIB) + self.fabric_filtered = val.findsubval(7) + self.data_version_filters = self.from_TLV_array(val.findsubval(8), matter.DataVersionFilterIB) + return self + end + + def to_TLV() + var TLV = matter.TLV + var s = TLV.Matter_TLV_struct() + s.add_TLV(0, TLV.BOOL, self.keep_subscriptions) + s.add_TLV(1, TLV.U2, self.min_interval_floor) + s.add_TLV(2, TLV.U2, self.max_interval_ceiling) + self.to_TLV_array(s, 3, self.attribute_requests) + self.to_TLV_array(s, 4, self.event_requests) + self.to_TLV_array(s, 5, self.event_filters) + s.add_TLV(7, TLV.BOOL, self.fabric_filtered) + self.to_TLV_array(s, 8, self.data_version_filters) + s.add_TLV(0xFF, TLV.U1, self.InteractionModelRevision) + return s + end +end +matter.SubscribeRequestMessage = Matter_SubscribeRequestMessage + +################################################################################# +# SubscribeResponseMessage class +################################################################################# +class Matter_SubscribeResponseMessage : Matter_IM_Message_base + var subscription_id # u32 + var max_interval # u16 + + # decode from TLV + def from_TLV(val) + if val == nil return nil end + self.subscription_id = val.findsubval(0) + self.max_interval = val.findsubval(2) + return self + end + + def to_TLV() + var TLV = matter.TLV + var s = TLV.Matter_TLV_struct() + s.add_TLV(0, TLV.U4, self.subscription_id) + s.add_TLV(2, TLV.U2, self.max_interval) + s.add_TLV(0xFF, TLV.U1, self.InteractionModelRevision) + return s + end +end +matter.SubscribeResponseMessage = Matter_SubscribeResponseMessage + +################################################################################# +# WriteRequestMessage class +################################################################################# +class Matter_WriteRequestMessage : Matter_IM_Message_base + var suppress_response # bool + var timed_request # bool + var write_requests # array of AttributeDataIB + var more_chunked_messages # bool + + # decode from TLV + def from_TLV(val) + if val == nil return nil end + self.suppress_response = val.findsubval(0) + self.timed_request = val.findsubval(1) + self.write_requests = self.from_TLV_array(val.findsubval(2), matter.AttributeDataIB) + self.more_chunked_messages = val.findsubval(3) + return self + end + + def to_TLV() + var TLV = matter.TLV + var s = TLV.Matter_TLV_struct() + s.add_TLV(0, TLV.BOOL, self.suppress_response) + s.add_TLV(1, TLV.BOOL, self.timed_request) + self.to_TLV_array(s, 2, self.write_requests) + s.add_TLV(3, TLV.BOOL, self.more_chunked_messages) + s.add_TLV(0xFF, TLV.U1, self.InteractionModelRevision) + return s + end +end +matter.WriteRequestMessage = Matter_WriteRequestMessage + +################################################################################# +# WriteResponseMessage class +################################################################################# +class Matter_WriteResponseMessage : Matter_IM_Message_base + var write_responses # array of AttributeStatusIB + + # decode from TLV + def from_TLV(val) + if val == nil return nil end + self.write_requests = self.from_TLV_array(val.findsubval(0), matter.AttributeStatusIB) + return self + end + + def to_TLV() + var TLV = matter.TLV + var s = TLV.Matter_TLV_struct() + self.to_TLV_array(s, 0, self.write_responses) + s.add_TLV(0xFF, TLV.U1, self.InteractionModelRevision) + return s + end +end +matter.WriteResponseMessage = Matter_WriteResponseMessage + +################################################################################# +# TimedRequestMessage class +################################################################################# +class Matter_TimedRequestMessage : Matter_IM_Message_base + var timeout # u16 + + # decode from TLV + def from_TLV(val) + if val == nil return nil end + self.timeout = val.findsubval(0) + return self + end + + def to_TLV() + var TLV = matter.TLV + var s = TLV.Matter_TLV_struct() + s.add_TLV(0, TLV.U2, self.timeout) + s.add_TLV(0xFF, TLV.U1, self.InteractionModelRevision) + return s + end +end +matter.TimedRequestMessage = Matter_TimedRequestMessage + +################################################################################# +# InvokeRequestMessage class +################################################################################# +class Matter_InvokeRequestMessage : Matter_IM_Message_base + var suppress_response # bool + var timed_request # bool + var invoke_requests # array of CommandDataIB + + # decode from TLV + def from_TLV(val) + if val == nil return nil end + self.suppress_response = val.findsubval(0) + self.timed_request = val.findsubval(1) + self.invoke_requests = self.from_TLV_array(val.findsubval(2), matter.CommandDataIB) + return self + end + + def to_TLV() + var TLV = matter.TLV + var s = TLV.Matter_TLV_struct() + s.add_TLV(0, TLV.BOOL, self.suppress_response) + s.add_TLV(1, TLV.BOOL, self.timed_request) + self.to_TLV_array(s, 2, self.invoke_requests) + s.add_TLV(0xFF, TLV.U1, self.InteractionModelRevision) + return s + end +end +matter.InvokeRequestMessage = Matter_InvokeRequestMessage + +################################################################################# +# InvokeResponseMessage class +################################################################################# +class Matter_InvokeResponseMessage : Matter_IM_Message_base + var suppress_response # bool + var invoke_responses # array of InvokeResponseIB + + # decode from TLV + def from_TLV(val) + if val == nil return nil end + self.suppress_response = val.findsubval(0) + self.invoke_responses = self.from_TLV_array(val.findsubval(1), matter.InvokeResponseIB) + return self + end + + def to_TLV() + var TLV = matter.TLV + var s = TLV.Matter_TLV_struct() + s.add_TLV(0, TLV.BOOL, self.suppress_response) + self.to_TLV_array(s, 1, self.invoke_responses) + s.add_TLV(0xFF, TLV.U1, self.InteractionModelRevision) + return s + end +end +matter.InvokeResponseMessage = Matter_InvokeResponseMessage + + +#- + +# Unit tests + +import matter + +m = matter.TLV.parse(bytes("1724020024033024040018")) +assert(m.tostring() == "[[2 = 0U, 3 = 48U, 4 = 0U]]") +#a = matter.IM.AttributePathIB().from_TLV(m) +a = matter.AttributePathIB().from_TLV(m) +assert(str(a) == "[00]0030/0000") +m = a.to_TLV() +assert(m.tostring() == "[[2 = 0U, 3 = 48U, 4 = 0U]]") +assert(m.encode() == bytes("1724020024033024040018")) + + +# create DataVersionFilterIB from scratch +c = matter.ClusterPathIB() +c.endpoint = 1 +c.cluster = 32 +c.to_TLV() +assert(str(c.to_TLV()) == "[[1 = 1U, 2 = 32U]]") + +d = matter.DataVersionFilterIB() +d.path = c +d.data_version = 10 +assert(str(d.to_TLV()) == '{0 = [[1 = 1U, 2 = 32U]], 1 = 10U}') +assert(d.to_TLV().encode() == bytes('1537002401012402201824010A18')) + +# decode DataVersionFilterIB from scratch +m = matter.TLV.parse(bytes("1537002401012402201824010A18")) +assert(str(m) == '{0 = [[1 = 1U, 2 = 32U]], 1 = 10U}') + +# ReadRequestMessage +m = matter.TLV.parse(bytes("153600172403312504FCFF18172402002403302404001817240200240330240401181724020024033024040218172402002403302404031817240200240328240402181724020024032824040418172403312404031818280324FF0118")) +assert(str(m) == "{0 = [[[3 = 49U, 4 = 65532U]], [[2 = 0U, 3 = 48U, 4 = 0U]], [[2 = 0U, 3 = 48U, 4 = 1U]], [[2 = 0U, 3 = 48U, 4 = 2U]], [[2 = 0U, 3 = 48U, 4 = 3U]], [[2 = 0U, 3 = 40U, 4 = 2U]], [[2 = 0U, 3 = 40U, 4 = 4U]], [[3 = 49U, 4 = 3U]]], 3 = false, 255 = 1U}") +r = matter.ReadRequestMessage().from_TLV(m) +assert(str(r) == "") +t = r.to_TLV() +assert(str(t) == "{0 = [[[3 = 49U, 4 = 65532U]], [[2 = 0U, 3 = 48U, 4 = 0U]], [[2 = 0U, 3 = 48U, 4 = 1U]], [[2 = 0U, 3 = 48U, 4 = 2U]], [[2 = 0U, 3 = 48U, 4 = 3U]], [[2 = 0U, 3 = 40U, 4 = 2U]], [[2 = 0U, 3 = 40U, 4 = 4U]], [[3 = 49U, 4 = 3U]]], 3 = false}") + + +# ReportDataMessage +r = matter.ReportDataMessage() +r.subscription_id = 1 +r.attribute_reports = [] +a1 = matter.AttributeReportIB() +a1.attribute_status = matter.AttributeStatusIB() +a1.attribute_status.path = matter.AttributePathIB() +a1.attribute_status.status = matter.StatusIB() +a1.attribute_status.path.endpoint = 0 +a1.attribute_status.path.cluster = 0x0030 +a1.attribute_status.path.attribute = 0 +a1.attribute_status.status.status = 0 +a1.attribute_status.status.cluster_status = 0 +a1.attribute_data = matter.AttributeDataIB() +a1.attribute_data.data_version = 1 +a1.attribute_data.path = matter.AttributePathIB() +a1.attribute_data.path.endpoint = 0 +a1.attribute_data.path.cluster = 0x0030 +a1.attribute_data.path.attribute = 0 +a1.attribute_data.data = matter.TLV.create_TLV(matter.TLV.UTF1, "Tasmota") +assert(str(a1.to_TLV()) == '{0 = {0 = [[2 = 0U, 3 = 48U, 4 = 0U]], 1 = [[0 = 0U, 1 = 0U]]}, 1 = {0 = 1U, 1 = [[2 = 0U, 3 = 48U, 4 = 0U]], 2 = "Tasmota"}}') +r.attribute_reports.push(a1) +#{0 = 1U, 1 = [{0 = {0 = [[2 = 0U, 3 = 48U, 4 = 0U]], 1 = [[0 = 0U, 1 = 0U]]}, 1 = {0 = 1U, 1 = [[2 = 0U, 3 = 48U, 4 = 0U]], 2 = "Tasmota"}}]} +assert(r.to_TLV().encode() == bytes('1524000136011535003700240200240330240400183701240000240100181835012400013701240200240330240400182C02075461736D6F746118181818')) + + +# , +# 'attribute_status': }>}> + +-# + diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Message.be b/lib/libesp32/berry_matter/src/embedded/Matter_Message.be new file mode 100644 index 000000000..3eadf0c55 --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Message.be @@ -0,0 +1,407 @@ +# +# Matter_Message.be - suppport for Matter Message Packet/Frame structure, deconding, enconding, encryption & decryption +# +# Copyright (C) 2023 Stephan Hadinger & Theo Arends +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + + +import matter + +#@ solidify:Matter_Frame,weak + +# Matter frame format, see 4.4 (p. 107) +class Matter_Frame + # context information + var message_handler # the message handler instance that decodes and generate responses + var session # the session object associated, or `nil` if no session + # content of the message + var raw # raw bytes of the packet + var payload_idx # index in raw for beginning of payload + # Message header + var flags + var flag_s # Note: Matter booleans are 1/0 not true/false + var flag_dsiz + var local_session_id + var sec_flags + var sec_p + var sec_c + var sec_mx + var sec_sesstype + var message_counter + var source_node_id + var dest_node_id_2 # if 2 bytes + var dest_node_id_8 # if 8 bytes + # Message payload + var x_flags + var x_flag_v + var x_flag_sx + var x_flag_r + var x_flag_a + var x_flag_i + var opcode + var exchange_id + var protocol_id + var vendor_id # (opt) + var ack_message_counter # (opt) + var sec_extensions + # var + var app_payload_idx # index where the application payload starts + + ############################################################# + # keep track of the message_handler object + # + def init(message_handler, raw) + self.message_handler = message_handler + self.raw = raw + end + + ############################################################# + # decode the header of the message and provide session + # information if decryption is required + # + # returns `true` if ok, `false` if message needs to be ignored + # or raises an exception if something went wrong + def decode_header() + var idx = 0 + var raw = self.raw + # flags + self.flags = raw.get(0, 1) + if (self.flags & 0xF8) != 0x00 return false end # ignore if Matter version if not 1.0 + self.flag_s = raw.getbits(2, 1) + self.flag_dsiz = raw.getbits(0, 2) + if self.flag_dsiz == 3 return false end # ignore if dsiz is unknown + + # security flagse + self.sec_flags = raw.get(3, 1) + self.sec_p = raw.getbits(3*8 + 7, 1) + self.sec_c = raw.getbits(3*8 + 6, 1) + self.sec_mx = raw.getbits(3*8 + 5, 1) + self.sec_sesstype = raw.getbits(3*8, 2) + if self.sec_sesstype > 1 return false end # ignore if session type is unknown + + # + self.local_session_id = raw.get(1, 2) + self.message_counter = raw.get(4, 4) + idx += 8 + # source node id? + if self.flag_s + self.source_node_id = raw[idx .. idx+7] + idx += 8 + end + # dest node id? + if self.flag_dsiz == 1 + self.dest_node_id_8 = raw[idx .. idx+7] + idx += 8 + elif self.flag_dsiz == 2 + self.dest_node_id_2 = raw.get(idx, 2) + idx += 2 + end + + # skip MX if any + if self.sec_mx + var sz = raw.get(idx, 2) + idx += sz + 2 # ignore bytes + end + + self.payload_idx = idx + return true + end + + ############################################################# + def decode_payload() + var idx = self.payload_idx # retrieve index for payload + var raw = self.raw + + # Message paylod + self.x_flags = raw.get(idx, 1) + # flags + self.x_flag_v = raw.getbits(idx*8 + 4, 1) + self.x_flag_sx = raw.getbits(idx*8 + 3, 1) + self.x_flag_r = raw.getbits(idx*8 + 2, 1) + self.x_flag_a = raw.getbits(idx*8 + 1, 1) + self.x_flag_i = raw.getbits(idx*8, 1) + + self.opcode = raw.get(idx+1, 1) + self.exchange_id = raw.get(idx+2, 2) + self.protocol_id = raw.get(idx+4, 2) + idx += 6 + + # optional protocol vendor id + if self.x_flag_v + self.vendor_id = raw.get(idx, 2) + idx += 2 + end + # optional Acknowledged Message Counter (32 bits) + if self.x_flag_a + self.ack_message_counter = raw.get(idx, 4) + idx += 4 + end + # optional secure extensions + if self.x_flag_sx + var sz = raw.get(idx, 2) + idx += sz + 2 # skip + end + + self.app_payload_idx = idx + return self + end + + ############################################################# + # Encode the packet as raw bytes + # + # If encryption is needed, it is done later + # + # Header is built from attributes + # `payload` is a bytes() buffer for the app payload + def encode(payload) + var raw = bytes() + # compute flags + if self.flags == nil + self.flags = 0x00 + if self.flag_s self.flags = self.flags | 0x04 end + if self.flag_dsiz self.flags = self.flags | (self.flag_dsiz & 0x03) end + end + raw.add(self.flags, 1) + # local_session_id (mandatory) + raw.add(self.local_session_id ? self.local_session_id : 0, 2) + # compute security flags + if self.sec_flags == nil + self.sec_flags = 0x00 + if self.sec_p self.sec_flags = self.sec_flags | 0x80 end + if self.sec_c self.sec_flags = self.sec_flags | 0x40 end + # if self.sec_mx self.sec_flags = self.sec_flags | 0x20 end # not supportedd + if self.sec_sesstype self.sec_flags = self.sec_flags | (self.sec_sesstype & 0x03) end + end + raw.add(self.sec_flags, 1) + # + raw.add(self.message_counter, 4) # mandatory + # + if self.flag_s raw .. self.source_node_id end # 8 bytes + if self.flag_dsiz == 0x01 raw .. self.dest_node_id_8 end # 8 bytes + if self.flag_dsiz == 0x02 raw.add(self.dest_node_id_2, 2) end # 2 bytes + # skip message extensions + self.payload_idx = size(raw) + # Message payload + if self.x_flags == nil + self.x_flags = 0x00 + if self.x_flag_v self.x_flags = self.x_flags | 0x10 end + # if self.x_flag_sx self.x_flags = self.x_flags | 0x08 end # not implemented + if self.x_flag_r self.x_flags = self.x_flags | 0x04 end + if self.x_flag_a self.x_flags = self.x_flags | 0x02 end + if self.x_flag_i self.x_flags = self.x_flags | 0x01 end + end + raw.add(self.x_flags, 1) + # opcode (mandatory) + raw.add(self.opcode, 1) + raw.add(self.exchange_id, 2) + raw.add(self.protocol_id, 2) + if self.x_flag_a raw.add(self.ack_message_counter, 4) end + # finally payload + self.app_payload_idx = size(raw) + if payload + raw .. payload + end + + self.debug(raw) + self.raw = raw + return raw + end + + ############################################################# + # Generate a Standalone Acknowledgment + # Uses `PROTOCOL_ID_SECURE_CHANNEL` no ecnryption required + def build_standalone_ack() + import string + # send back response + var resp = classof(self)(self.message_handler) + + if self.flag_s + resp.flag_dsiz = 0x01 + resp.dest_node_id_8 = self.source_node_id + else + resp.flag_dsiz = 0x00 + end + resp.session = self.session # also copy the session object + # message counter + resp.message_counter = self.session.counter_snd.next() + resp.local_session_id = self.session.initiator_session_id + + resp.x_flag_i = 0 # not sent by initiator + resp.opcode = 0x10 # MRP Standalone Acknowledgement + resp.exchange_id = self.exchange_id + resp.protocol_id = 0 # PROTOCOL_ID_SECURE_CHANNEL + resp.x_flag_a = 1 # ACK of previous message + resp.ack_message_counter = self.message_counter + resp.x_flag_r = 0 + + tasmota.log(string.format("MTR: . +# + +import matter + +#@ solidify:Matter_MessageHandler,weak + +class Matter_MessageHandler + # callback for sending messages + var device # `tansport.msg_send(raw:bytes() [,...]) -> bool` true if succeeded + + # handlers + var commissioning + var im # handler for Interaction Model + # counters + var counter_rcv # Global Unencrypted Message Counter incoming + + ############################################################# + def init(device) + self.device = device + self.commissioning = matter.Commisioning_Context(self) + self.im = matter.IM(self) + self.counter_rcv = matter.Counter() + end + + ############################################################# + # Called when a message is received + # + # Find or create a session for the message + # and dispacth to appropriate handler + # + def msg_received(raw, addr, port) + import string + try + tasmota.log("MTR: MessageHandler::msg_received raw="+raw.tohex(), 4) + var frame = matter.Frame(self, raw) + + var ok = frame.decode_header() + if !ok return false end + + # do we need decryption? + if frame.local_session_id == 0 && frame.sec_sesstype == 0 + ############################################################# + ### unencrypted session, handled by commissioning + var session = self.device.sessions.find_session_source_id_unsecure(frame.source_node_id, 90) # 90 seconds max + tasmota.log("MTR: find session by source_node_id = " + str(frame.source_node_id) + "session_id = " + str(session.local_session_id), 3) + frame.session = session + + # check if it's a duplicate + if !self.counter_rcv.validate(frame.message_counter, false) + tasmota.log(string.format("MTR: rejected duplicate unencrypted message = %i ref = %i", frame.message_counter, self.counter_rcv.val()), 3) + return false + end + + if !frame.decode_payload() return false end + self.device.packet_ack(frame.ack_message_counter) # acknowledge packet + if frame.opcode != 0x10 # don't show `MRP_Standalone_Acknowledgement` + var op_name = matter.get_opcode_name(frame.opcode) + if !op_name op_name = string.format("0x%02X", frame.opcode) end + tasmota.log(string.format("MTR: >Received %s from [%s]:%i", op_name, addr, port), 2) + end + self.commissioning.process_incoming(frame, addr, port) + return true + else + ############################################################# + # encrypted message + tasmota.log(string.format("MTR: decode header: local_session_id=%i message_counter=%i", frame.local_session_id, frame.message_counter), 3) + + var session = self.device.sessions.get_session_by_local_session_id(frame.local_session_id) + if session == nil + tasmota.log("MTR: unknown local_session_id "+str(frame.local_session_id), 3) + tasmota.log("MTR: frame="+matter.inspect(frame), 3) + return false + end + frame.session = session # keep a pointer of the session in the message + + # check if it's a duplicate + if !session.counter_rcv.validate(frame.message_counter, true) + tasmota.log("MTR: rejected duplicate encrypted message = " + str(frame.message_counter) + " counter=" + str(session.counter_rcv.val()), 3) + return false + end + + var cleartext = frame.decrypt() + if !cleartext return false end + + # packet is good, put back content in raw + frame.raw = frame.raw[0 .. frame.payload_idx - 1] # remove encrypted payload + frame.raw .. cleartext # add cleartext + + # continue decoding + tasmota.log(string.format("MTR: idx=%i clear=%s", frame.payload_idx, frame.raw.tohex()), 3) + frame.decode_payload() + tasmota.log("MTR: decrypted message: protocol_id:"+str(frame.protocol_id)+" opcode="+str(frame.opcode)+" exchange_id"+str(frame.exchange_id), 3) + + self.device.packet_ack(frame.ack_message_counter) # acknowledge packet + + # dispatch according to protocol_id + var protocol_id = frame.protocol_id + if protocol_id == 0x0000 # PROTOCOL_ID_SECURE_CHANNEL + # it should not be encrypted + tasmota.log("MTR: PROTOCOL_ID_SECURE_CHANNEL " + matter.inspect(frame), 3) + # if frame.opcode == 0x10 + # end + return true + elif protocol_id == 0x0001 # PROTOCOL_ID_INTERACTION_MODEL + # dispatch to IM Protocol Messages + return self.im.process_incoming(frame, addr, port) + + # -- PROTOCOL_ID_BDX is used for file transfer between devices, not used in Tasmota + # elif protocol_id == 0x0002 # PROTOCOL_ID_BDX -- BDX not handled at all in Tasmota + # tasmota.log("MTR: PROTOCOL_ID_BDX not yet handled", 2) + # return false # ignore for now TODO + # -- PROTOCOL_ID_USER_DIRECTED_COMMISSIONING is only used by devices, as a device we will not receive any + # elif protocol_id == 0x0003 # PROTOCOL_ID_USER_DIRECTED_COMMISSIONING + # tasmota.log("MTR: PROTOCOL_ID_USER_DIRECTED_COMMISSIONING not yet handled", 2) + # return false # ignore for now TODO + else + tasmota.log("MTR: ignoring unhandled protocol_id:"+str(protocol_id), 3) + return false + end + + end + + return true + except .. as e, m + tasmota.log("MTR: MessageHandler::msg_received exception: "+str(e)+";"+str(m)) + import debug + debug.traceback() + return false + end + end + + ############################################################# + def send_response(raw, addr, port, id) + self.device.msg_send(raw, addr, port, id) + end + + ############################################################# + def add_session(local_session_id, initiator_session_id, i2r, r2i, ac, session_timestamp) + import string + # create session object + tasmota.log(string.format("MTR: add_session local_session_id=%i initiator_session_id=%i", local_session_id, initiator_session_id), 3) + + var session = self.device.sessions.create_session(local_session_id, initiator_session_id) + session.set_keys(i2r, r2i, ac, session_timestamp) + end + + ############################################################# + # placeholder, nothing to run for now + def every_second() + self.commissioning.every_second() + self.im.every_second() + end +end +matter.MessageHandler = Matter_MessageHandler diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Module.be b/lib/libesp32/berry_matter/src/embedded/Matter_Module.be new file mode 100644 index 000000000..0f138d76f --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Module.be @@ -0,0 +1,46 @@ +# +# Matter_Module.be - implements the global `matter` module from a solidified module that can be dynamically enriched +# +# Copyright (C) 2023 Stephan Hadinger & Theo Arends +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +# matter module for extensibility +# +# this allows the module `matter` to be extended + +var matter = module("matter") + +def setmember(k, v) + import global + if !global.contains(".matter") global.(".matter") = {} end + global.(".matter")[k] = v +end + +def member(k) + import global + import undefined + + if global.contains(".matter") && global.(".matter").contains(k) + return global.(".matter")[k] + else + return undefined + end +end + +matter.setmember = setmember +matter.member = member +#@ solidify:matter.setmember,weak +#@ solidify:matter.member,weak diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin.be new file mode 100644 index 000000000..fb3c170de --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin.be @@ -0,0 +1,88 @@ +# +# Matter_Plugin.be - generic superclass for all Matter plugins, used to define specific behaviors (light, switch, media...) +# +# Copyright (C) 2023 Stephan Hadinger & Theo Arends +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +# Matter modules for extensibility +# template but not actually used + +#@ solidify:Matter_Plugin,weak + +class Matter_Plugin + var device + var endpoints + + ############################################################# + # Constructor + def init(device) + self.device = device + self.endpoints = [] + end + + ############################################################# + # Which endpoints does it handle (list of numbers) + def get_endpoints() + return self.endpoints + end + + ############################################################# + # read attribute + def read_attribute(msg, endpoint, cluster, attribute) + return nil + end + + ############################################################# + # read event + # TODO + def read_event(msg, endpoint, cluster, eventid) + return nil + end + + ############################################################# + # subscribe attribute + # TODO + def subscribe_attribute(msg, endpoint, cluster, attribute) + return nil + end + + ############################################################# + # subscribe event + # TODO + def subscribe_event(msg, endpoint, cluster, eventid) + return nil + end + + ############################################################# + # write attribute + def write_attribute(msg, endpoint, cluster, attribute) + return nil + end + + ############################################################# + # invoke command + def invoke_request(msg, val, ctx) + return nil + end + + ############################################################# + # timed request + # TODO - should we even support this? + def timed_request(msg, val, ctx) + return nil + end +end +matter.Plugin = Matter_Plugin diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Relay.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Relay.be new file mode 100644 index 000000000..3a923246d --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Relay.be @@ -0,0 +1,52 @@ +# +# Matter_Plugin_Relay.be - implements the behavior for a Relay (OnOff) +# +# Copyright (C) 2023 Stephan Hadinger & Theo Arends +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +# Matter plug-in for core behavior + +# dummy declaration for solidification +class Matter_Plugin end + +#@ solidify:Matter_Plugin_Relay,weak + +class Matter_Plugin_Relay : Matter_Plugin + ############################################################# + # Constructor + def init(device) + super(self).init(device) + self.endpoints = [ 1 ] + end + + ############################################################# + # read an attribute + # + def read_attribute(msg, endpoint, cluster, attribute) + # no match found, return that the attribute is unsupported + end + + ############################################################# + # Invoke a command + # + # returns a TLV object if successful, contains the response + # or an `int` to indicate a status + def invoke_request(msg, val, ctx) + # no match found, return that the command is unsupported + end +end +matter.Plugin_core = Matter_Plugin_core + \ No newline at end of file diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_core.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_core.be new file mode 100644 index 000000000..57f516825 --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_core.be @@ -0,0 +1,372 @@ +# +# Matter_Plugin_core.be - implements the core features that a Matter device must implemment +# +# Copyright (C) 2023 Stephan Hadinger & Theo Arends +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +# Matter plug-in for core behavior + +# dummy declaration for solidification +class Matter_Plugin end + +#@ solidify:Matter_Plugin_core,weak + +class Matter_Plugin_core : Matter_Plugin + ############################################################# + # Constructor + def init(device) + super(self).init(device) + self.endpoints = [ 0 ] + end + + ############################################################# + # read an attribute + # + def read_attribute(msg, endpoint, cluster, attribute) + var TLV = matter.TLV + + if cluster == 0x0030 # ========== GeneralCommissioning cluster 11.9 p.627 ========== + + if attribute == 0x0000 # ---------- Breadcrumb ---------- + return TLV.create_TLV(TLV.U8, msg.session.breadcrumb) + elif attribute == 0x0001 # ---------- BasicCommissioningInfo / BasicCommissioningInfo---------- + var bci = TLV.Matter_TLV_struct() + bci.add_TLV(0, TLV.U2, 60) # FailSafeExpiryLengthSeconds + bci.add_TLV(1, TLV.U2, 900) # MaxCumulativeFailsafeSeconds + return bci + elif attribute == 0x0002 # ---------- RegulatoryConfig / RegulatoryLocationType ---------- + return TLV.create_TLV(TLV.U1, 2) # 2 = IndoorOutdoor | esp-matter = 0 + elif attribute == 0x0003 # ---------- LocationCapability / RegulatoryLocationType---------- + return TLV.create_TLV(TLV.U1, 2) # 2 = IndoorOutdoor + elif attribute == 0x0004 # ---------- SupportsConcurrentConnection / bool ---------- + return TLV.create_TLV(TLV.BOOL, false) # false - maybe can set to true + end + # ==================================================================================================== + elif cluster == 0x0032 # ========== Diagnostic Logs Cluster 11.10 p.637 ========== + # no attributes + + # ==================================================================================================== + elif cluster == 0x0033 # ========== General Diagnostics Cluster 11.11 p.642 ========== + + if attribute == 0x0000 # ---------- NetworkInterfaces ---------- + var nwi = TLV.Matter_TLV_list() # TODO list network interfaces, empty list for now + return nwi + elif attribute == 0x0001 # ---------- RebootCount u16 ---------- + return TLV.create_TLV(TLV.U2, tasmota.cmd("Status 1")['StatusPRM']['BootCount']) + elif attribute == 0x0002 # ---------- UpTime u16 ---------- + return TLV.create_TLV(TLV.U4, tasmota.cmd("Status 11")['StatusSTS']['UptimeSec']) + # TODO add later other attributes + elif attribute == 0x0008 # ---------- TestEventTriggersEnabled bool ---------- + return TLV.create_TLV(TLV.BOOL, false) # false - maybe can set to true + end + + # ==================================================================================================== + elif cluster == 0x0034 # ========== Software Diagnostics Cluster 11.12 p.654 ========== + # no mandatory attributes - to be added later (maybe) + + # ==================================================================================================== + elif cluster == 0x0038 # ========== Time Synchronization 11.16 p.689 ========== + if attribute == 0x0000 # ---------- UTCTime / epoch_us ---------- + var epoch_us = int64(tasmota.rtc()['utc']) * int64(1000000) + return TLV.create_TLV(TLV.U8, epoch_us) # TODO test the conversion of int64() + elif attribute == 0x0001 # ---------- Granularity / enum ---------- + return TLV.create_TLV(TLV.U1, 3) # MillisecondsGranularity (NTP every hour, i.e. 36ms max drift) + # TODO add some missing args + elif attribute == 0x0007 # ---------- LocalTime / epoch_us ---------- + var epoch_us = int64(tasmota.rtc()['local']) * int64(1000000) + return TLV.create_TLV(TLV.U8, epoch_us) # TODO test the conversion of int64() + end + + # ==================================================================================================== + elif cluster == 0x003E # ========== Node Operational Credentials Cluster 11.17 p.704 ========== + + if attribute == 0x0000 # ---------- NOCs / list[NOCStruct] ---------- + # TODO + elif attribute == 0x0001 # ---------- Fabrics / list[FabricDescriptorStruct] ---------- + # TODO + elif attribute == 0x0002 # ---------- SupportedFabrics / u1 ---------- + return TLV.create_TLV(TLV.U1, 5) # Max 5 fabrics + elif attribute == 0x0003 # ---------- CommissionedFabrics / u1 ---------- + return TLV.create_TLV(TLV.U1, 1) # TODO + elif attribute == 0x0004 # ---------- TrustedRootCertificates / list[octstr] ---------- + # TODO + elif attribute == 0x0005 # ---------- Current­ FabricIndex / u1 ---------- + # TODO + end + + # ==================================================================================================== + elif cluster == 0x003C # ========== Administrator Commissioning Cluster 11.18 p.725 ========== + # TODO + + # ==================================================================================================== + elif cluster == 0x0028 # ========== Basic Information Cluster cluster 11.1 p.565 ========== + + if attribute == 0x0000 # ---------- DataModelRevision / u16 ---------- + return TLV.create_TLV(TLV.U2, 0) + elif attribute == 0x0001 # ---------- VendorName / string ---------- + return TLV.create_TLV(TLV.UTF1, "Tasmota") + elif attribute == 0x0002 # ---------- VendorID / vendor-id ---------- + return TLV.create_TLV(TLV.U2, self.device.vendorid) # Vendor ID reserved for development + elif attribute == 0x0003 # ---------- ProductName / string ---------- + return TLV.create_TLV(TLV.UTF1, tasmota.cmd("DeviceName")['DeviceName']) + elif attribute == 0x0004 # ---------- ProductID / u16 (opt) ---------- + return TLV.create_TLV(TLV.U2, 32768) # taken from esp-matter example + elif attribute == 0x0005 # ---------- NodeLabel / string ---------- + return TLV.create_TLV(TLV.UTF1, tasmota.cmd("FriendlyName")['FriendlyName1']) + elif attribute == 0x0006 # ---------- Location / string ---------- + return TLV.create_TLV(TLV.UTF1, "XX") # no location + elif attribute == 0x0007 # ---------- HardwareVersion / u16 ---------- + return TLV.create_TLV(TLV.U2, 0) + elif attribute == 0x0008 # ---------- HardwareVersionString / string ---------- + return TLV.create_TLV(TLV.UTF1, tasmota.cmd("Status 2")['StatusFWR']['Hardware']) + elif attribute == 0x0009 # ---------- SoftwareVersion / u32 ---------- + return TLV.create_TLV(TLV.U2, 0) + elif attribute == 0x000A # ---------- SoftwareVersionString / string ---------- + return TLV.create_TLV(TLV.UTF1, tasmota.cmd("Status 2")['StatusFWR']['Version']) + end + + # ==================================================================================================== + elif cluster == 0x003F # ========== Group Key Management Cluster 11.2 p.572 ========== + # TODO + + # ==================================================================================================== + elif cluster == 0x002B # ========== Localization Configuration Cluster 11.3 p.580 ========== + + if attribute == 0x0000 # ---------- ActiveLocale / string ---------- + return TLV.create_TLV(TLV.UTF1, tasmota.locale()) + elif attribute == 0x0001 # ---------- SupportedLocales / list[string] ---------- + var locl = TLV.Matter_TLV_list() + locl.add_TLV(nil, TLV.UTF1, tasmota.locale()) + return locl + end + + # ==================================================================================================== + elif cluster == 0x002C # ========== Time Format Localization Cluster 11.4 p.581 ========== + + if attribute == 0x0000 # ---------- HourFormat / HourFormat ---------- + return TLV.create_TLV(TLV.U1, 1) # 1 = 24hr + elif attribute == 0x0001 # ---------- ActiveCalendarType / CalendarType ---------- + return TLV.create_TLV(TLV.U1, 4) # 4 = Gregorian + elif attribute == 0x0002 # ---------- SupportedCalendarTypes / list[CalendarType] ---------- + var callist = TLV.Matter_TLV_list() + callist.add_TLV(nil, TLV.create_TLV(TLV.U1, 4)) + return callist + end + + # ==================================================================================================== + elif cluster == 0x0031 # ========== Network Commissioning Cluster cluster 11.8 p.606 ========== + if attribute == 0x0003 # ---------- ConnectMaxTimeSeconds / uint8 ---------- + return TLV.create_TLV(TLV.U1, 30) # 30 - value taking from example in esp-matter + elif attribute == 0xFFFC # ---------- FeatureMap / map32 ---------- + return TLV.create_TLV(TLV.U4, 0) # 15s ??? TOOD what should we put here? + end + end + # no match found, return that the attribute is unsupported + end + + ############################################################# + # Invoke a command + # + # returns a TLV object if successful, contains the response + # or an `int` to indicate a status + def invoke_request(msg, val, ctx) + import crypto + var TLV = matter.TLV + var cluster = ctx.cluster + var command = ctx.command + var session = msg.session + if cluster == 0x0030 # ========== GeneralCommissioning cluster 11.9 p.627 ========== + + if command == 0x0000 # ---------- ArmFailSafe ---------- + # create ArmFailSafeResponse + # ID=1 + # 0=ErrorCode (OK=0) + # 1=DebugText + var ExpiryLengthSeconds = val.findsubval(0, 900) + var Breadcrumb = val.findsubval(1, 0) + session.breadcrumb = Breadcrumb + + var afsr = TLV.Matter_TLV_struct() + afsr.add_TLV(0, TLV.U1, 0) # ErrorCode = OK + afsr.add_TLV(1, TLV.UTF1, "") # DebugText = "" + ctx.command = 0x01 # ArmFailSafeResponse + return afsr + + elif command == 0x0002 # ---------- SetRegulatoryConfig ---------- + var NewRegulatoryConfig = val.findsubval(0) # RegulatoryLocationType Enum + var CountryCode = val.findsubval(1, "XX") + var Breadcrumb = val.findsubval(2, 0) + session.breadcrumb = Breadcrumb + # create SetRegulatoryConfigResponse + # ID=1 + # 0=ErrorCode (OK=0) + # 1=DebugText + var srcr = TLV.Matter_TLV_struct() + srcr.add_TLV(0, TLV.U1, 0) # ErrorCode = OK + srcr.add_TLV(1, TLV.UTF1, "") # DebugText = "" + ctx.command = 0x03 # SetRegulatoryConfigResponse + return srcr + + elif command == 0x0004 # ---------- CommissioningComplete p.636 ---------- + # no data + session.breadcrumb = 0 # clear breadcrumb + session.set_no_expiration() + + # create CommissioningCompleteResponse + # ID=1 + # 0=ErrorCode (OK=0) + # 1=DebugText + var ccr = TLV.Matter_TLV_struct() + ccr.add_TLV(0, TLV.U1, 0) # ErrorCode = OK + ccr.add_TLV(1, TLV.UTF1, "") # DebugText = "" + ctx.command = 0x05 # CommissioningCompleteResponse + + self.device.start_commissioning_complete_deferred(session) + return ccr # trigger a standalone ack + end + + elif cluster == 0x003E # ========== Node Operational Credentials Cluster 11.17 p.704 ========== + + if command == 0x0002 # ---------- CertificateChainRequest ---------- + var CertificateType = val.findsubval(0) # CertificateChainType Enum 1=DACCertificate 2=PAICertificate + if CertificateType != 1 && CertificateType != 2 + ctx.status = matter.UNSUPPORTED_COMMAND + return nil + end + # create CertificateChainResponse + # ID=1 + # 0=Certificate (octstr) + var ccr = TLV.Matter_TLV_struct() + ccr.add_TLV(0, TLV.B2, CertificateType == 1 ? matter.DAC_Cert_FFF1_8000() : matter.PAI_Cert_FFF1()) # send DAC_Cert_FFF1_8000 or PAI_Cert_FFF1 + ctx.command = 0x03 # CertificateChainResponse + return ccr + + elif command == 0x0000 # ---------- AttestationRequest ---------- + var AttestationNonce = val.findsubval(0) # octstr + if size(AttestationNonce) != 32 return nil end # check size on nonce + ctx.command = 0x01 # AttestationResponse + + # build Attestation Elements 11.17.5.4 p.707 + var att_elts = TLV.Matter_TLV_struct() + att_elts.add_TLV(1, TLV.B2, matter.CD_FFF1_8000()) # certification_declaration + att_elts.add_TLV(2, TLV.B1, AttestationNonce) # attestation_nonce + att_elts.add_TLV(3, TLV.U4, tasmota.rtc()['utc']) # timestamp in epoch-s + var attestation_message = att_elts.encode() + + var ac = session.get_ac() + var attestation_tbs = attestation_message + ac + tasmota.log("MTR: attestation_tbs=" + attestation_tbs.tohex(), 3) + + var attestation_signature = crypto.EC_P256().ecdsa_sign_sha256(matter.DAC_Priv_FFF1_8000(), attestation_tbs) + + # create AttestationResponse + # 0=AttestationElements (octstr max 900 bytes) + # 1=AttestationSignature (octstr 64) + var ar = TLV.Matter_TLV_struct() + ar.add_TLV(0, TLV.B2, attestation_message) # AttestationElements + ar.add_TLV(1, TLV.B1, attestation_signature) # AttestationElements + ctx.command = 0x01 # AttestationResponse + return ar + + elif command == 0x0004 # ---------- CSRRequest ---------- + var CSRNonce = val.findsubval(0) # octstr 32 + if size(CSRNonce) != 32 return nil end # check size on nonce + var IsForUpdateNOC = val.findsubval(1, false) # bool + + var csr = session.gen_CSR() + + var nocsr_elements = TLV.Matter_TLV_struct() + nocsr_elements.add_TLV(1, TLV.B2, csr) + nocsr_elements.add_TLV(2, TLV.B1, CSRNonce) + var nocsr_elements_message = nocsr_elements.encode() + # sign with attestation challenge + var nocsr_tbs = nocsr_elements_message + session.get_ac() + tasmota.log("MTR: nocsr_tbs=" + nocsr_tbs.tohex(), 3) + var attestation_signature = crypto.EC_P256().ecdsa_sign_sha256(matter.DAC_Priv_FFF1_8000(), nocsr_tbs) + + # create CSRResponse + # 0=NOCSRElements (octstr max 900 bytes) + # 1=AttestationSignature (octstr 64) + var csrr = TLV.Matter_TLV_struct() + csrr.add_TLV(0, TLV.B2, nocsr_elements_message) # AttestationElements + csrr.add_TLV(1, TLV.B1, attestation_signature) # AttestationElements + ctx.command = 0x05 # CSRResponse + return csrr + + elif command == 0x000B # ---------- AddTrustedRootCertificate ---------- + var RootCACertificate = val.findsubval(0) # octstr 400 max + session.set_ca(RootCACertificate) + tasmota.log("MTR: received ca_root="+RootCACertificate.tohex(), 3) + ctx.status = matter.SUCCESS # OK + return nil # trigger a standalone ack + + elif command == 0x0006 # ---------- AddNOC ---------- + var NOCValue = val.findsubval(0) # octstr max 400 + var ICACValue = val.findsubval(1) # octstr max 400 + var IpkValue = val.findsubval(2) # octstr max 16 + var CaseAdminSubject = val.findsubval(3) + var AdminVendorId = val.findsubval(4) + + if session.get_ca() == nil + tasmota.log("MTR: Error: AdNOC without CA", 2) + return nil + end + + session.set_noc(NOCValue, ICACValue) + session.set_ipk_epoch_key(IpkValue) + session.admin_subject = CaseAdminSubject + session.admin_vendor = AdminVendorId + + # extract important information from NOC + var noc_cert = matter.TLV.parse(NOCValue) + var dnlist = noc_cert.findsub(6) + var fabric = dnlist.findsubval(21) + var deviceid = dnlist.findsubval(17) + if !fabric || !deviceid + tasmota.log("MTR: Error: no fabricid nor deviceid in NOC certificate", 2) + return false + end + # convert fo bytes(8) + if type(fabric) == 'int' fabric = int64(fabric).tobytes() else fabric = fabric.tobytes() end + if type(deviceid) == 'int' deviceid = int64(deviceid).tobytes() else deviceid = deviceid.tobytes() end + + var root_ca = matter.TLV.parse(session.get_ca()).findsubval(9) # extract public key from ca + root_ca = root_ca[1..] # remove first byte as per Matter specification + var info = bytes().fromstring("CompressedFabric") # as per spec, 4.3.2.2 p.99 + var hk = crypto.HKDF_SHA256() + var fabric_rev = fabric.copy().reverse() + var k_fabric = hk.derive(root_ca, fabric_rev, info, 8) + session.set_fabric_device(fabric, deviceid, k_fabric) + + # move to next step + self.device.start_operational_dicovery_deferred(session) + # create NOCResponse + # 0=StatusCode + # 1=FabricIndex (1-254) (opt) + # 2=DebugText (opt) + var nocr = TLV.Matter_TLV_struct() + nocr.add_TLV(0, TLV.U1, matter.SUCCESS) # Status + nocr.add_TLV(1, TLV.U1, 1) # fabric-index + ctx.command = 0x08 # NOCResponse + return nocr + + end + end + + end +end +matter.Plugin_core = Matter_Plugin_core + \ No newline at end of file diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Session.be b/lib/libesp32/berry_matter/src/embedded/Matter_Session.be new file mode 100644 index 000000000..8c1f56235 --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Session.be @@ -0,0 +1,574 @@ +# +# Matter_Session.be - Support for Matter Sessions and Session Store +# +# Copyright (C) 2023 Stephan Hadinger & Theo Arends +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +import matter + +#@ solidify:Matter_Session,weak +#@ solidify:Matter_Session_Store,weak + +################################################################################# +# Matter_Session class +# +# Session is refered by remote_session_id once a session is established +# It can also be retrived by `source_node_id` when `local_session_id` is 0 +# +# By convention, names starting with `_` are not persisted +################################################################################# +class Matter_Session + static var __PASE = 1 # PASE authentication in progress + static var __CASE = 2 # CASE authentication in progress + var __store # reference back to session store + # mode for Session. Can be PASE=1, CASE=2, Established=10 none=0 + var mode + # sesions + var local_session_id # id for the current local session, starts with 1 + var initiator_session_id # id used to respond to the initiator + var session_timestamp # timestamp (UTC) when the session was created + var source_node_id # source node if bytes(8) (opt, used only when session is not established) + # session_ids when the session will be active + var _future_initiator_session_id + var _future_local_session_id + # counters + var counter_rcv # counter for incoming messages + var counter_snd # counter for outgoing messages + # non-session counters + var _counter_insecure_rcv # counter for incoming messages + var _counter_insecure_snd # counter for outgoing messages + # encryption keys and challenges + var i2rkey # key initiator to receiver (incoming) + var r2ikey # key receiver to initiator (outgoing) + var attestation_challenge # Attestation challenge + var peer_node_id + # breadcrumb + var breadcrumb # breadcrumb attribute for this session + # our own private key + var no_private_key # private key of the device certificate (generated at commissioning) + # NOC information + var root_ca_certificate # root certificate of the initiator + var noc # Node Operational Certificate in TLV Matter Certificate + var icac # Initiator CA Certificate in TLV Matter Certificate + var ipk_epoch_key # timestamp + # CASE + var resumption_id # bytes(16) + var shared_secret # ECDH shared secret used in CASE + # Information extracted from `noc` + var fabric # fabric identifier as bytes(8) little endian + var fabric_compressed # comrpessed fabric identifier, hashed with root_ca public key + var deviceid # our own device id bytes(8) little endian + # Admin info extracted from NOC/ICAC + var admin_subject + var admin_vendor + # Previous CASE messages for Transcript hash + var _Msg1, _Msg2 + # Expiration + var _persist # do we persist this sessions or is it remporary + var expiration # if not `nil` the entry is removed after this timestamp + + # Group Key Derivation + static var __GROUP_KEY = "GroupKey v1.0" # starting with double `_` means it's not writable + + ############################################################# + def init(store, local_session_id, initiator_session_id) + self.__store = store + self.mode = 0 + self.local_session_id = local_session_id + self.initiator_session_id = initiator_session_id + self.counter_rcv = matter.Counter() + self.counter_snd = matter.Counter() + self._counter_insecure_rcv = matter.Counter() + self._counter_insecure_snd = matter.Counter() + self.breadcrumb = int64() + end + + ############################################################# + # Close the current PASE/CASE session to be re-negociated + # + def close() + # close the PASE session, it will be re-opened with a CASE session + var persist_save = self._persist + self.local_session_id = self._future_local_session_id + self.initiator_session_id = self._future_initiator_session_id + self.source_node_id = nil + self.counter_rcv.reset() + self.counter_snd.reset() + self.i2rkey = nil + self.r2ikey = nil + self.attestation_challenge = nil + # clear any attribute starting with `_` + import introspect + for k : introspect.members(self) + var v = introspect.get(self, k) + if type(v) != 'function' && type(v) != 'instance' && k[0] == '_' && k[1] != '_' + self.(k) = nil + end + end + self._persist = persist_save + # self._future_initiator_session_id = nil + # self._future_local_session_id = nil + end + + ############################################################# + def set_mode(mode) + self.mode = mode + end + def set_keys(i2r, r2i, ac, st) + self.i2rkey = i2r + self.r2ikey = r2i + self.attestation_challenge = ac + self.session_timestamp = st + end + def set_ca(ca) + self.root_ca_certificate = ca + end + def set_noc(noc, icac) + self.noc = noc + self.icac = icac + end + def set_ipk_epoch_key(ipk_epoch_key) + self.ipk_epoch_key = ipk_epoch_key + end + def set_fabric_device(fabric, deviceid, fc) + self.fabric = fabric + self.deviceid = deviceid + self.fabric_compressed = fc + self.__store.remove_redundant_session(self) + end + def set_persist(p) + self._persist = bool(p) + end + + ############################################################# + def get_mode() + return self.mode + end + def get_i2r() + return self.i2rkey + end + def get_r2i() + return self.r2ikey + end + def get_ac() + return self.attestation_challenge + end + def get_ca() + return self.root_ca_certificate + end + def get_ca_pub() + if self.root_ca_certificate + var m = matter.TLV.parse(self.root_ca_certificate) + return m.findsubval(9) + end + end + def get_noc() return self.noc end + def get_icac() return self.icac end + def get_ipk_epoch_key() return self.ipk_epoch_key end + def get_fabric() return self.fabric end + def get_deviceid() return self.deviceid end + def get_fabric_compressed() return self.fabric_compressed end + + ############################################################# + # Generate a private key (or retrieve it) + def get_pk() + if !self.no_private_key + import crypto + self.no_private_key = crypto.random(32) + end + return self.no_private_key + end + + ############################################################# + # Operational Group Key Derivation, 4.15.2, p.182 + def get_ipk_group_key() + if self.ipk_epoch_key == nil || self.fabric_compressed == nil return nil end + import crypto + var hk = crypto.HKDF_SHA256() + var info = bytes().fromstring(self.__GROUP_KEY) + var hash = hk.derive(self.ipk_epoch_key, self.fabric_compressed, info, 16) + return hash + end + + ############################################################# + # set absolute time for expiration + def set_no_expiration() + self.expiration = nil + end + + ############################################################# + # set absolute time for expiration + def set_expire_time(t) + self.expiration = int(t) + end + + ############################################################# + # set relative time in the future for expiration (in seconds) + def set_expire_in_seconds(s, now) + if s == nil return end + if now == nil now = tasmota.rtc()['utc'] end + self.set_expire_time(now + s) + end + + ############################################################# + # set relative time in the future for expiration (in seconds) + # returns `true` if expiration date has been reached + def has_expired(now) + if now == nil now = tasmota.rtc()['utc'] end + if self.expiration != nil + return now >= self.expiration + end + return false + end + + ############################################################# + # to_json() + # + # convert a single entry as json + # returns a JSON string + ############################################################# + def tojson() + import json + import string + import introspect + + var keys = [] + for k : introspect.members(self) + var v = introspect.get(self, k) + if type(v) != 'function' && k[0] != '_' keys.push(k) end + end + keys = matter.sort(keys) + + var r = [] + for k : keys + var v = introspect.get(self, k) + if v == nil continue end + + if k == "counter_rcv" v = v.val() + elif k == "counter_snd" v = v.val() + 256 # take a margin to avoid reusing the same counter + end + + if isinstance(v, bytes) v = "$$" + v.tob64() end # bytes + # if isinstance(v, bytes) v = "0x" + v.tohex() end + + # if type(v) == 'string' v = string.escape(v, true) end + r.push(string.format("%s:%s", json.dump(str(k)), json.dump(v))) + end + return "{" + r.concat(",") + "}" + end + + ############################################################# + # fromjson() + # + # reads a map and load arguments + # returns an new instance of session + ############################################################# + static def fromjson(store, values) + import string + import introspect + var self = matter.Session(store) + + for k:values.keys() + var v = values[k] + if k == "counter_rcv" self.counter_rcv.reset(int(v)) + elif k == "counter_snd" self.counter_snd.reset(int(v)) + else + # standard values + if type(v) == 'string' + if string.find(v, "0x") == 0 # treat as bytes + introspect.set(self, k, bytes().fromhex(v[2..])) + elif string.find(v, "$$") == 0 # treat as bytes + introspect.set(self, k, bytes().fromb64(v[2..])) + else + introspect.set(self, k, v) + end + else + introspect.set(self, k, v) + end + end + end + + return self + end + + ############################################################# + # Callback to Session store + def save() + self.__store.save() + end + + ############################################################# + def gen_CSR() + # Create CSR + # See 6.4.7. Node Operational Certificate Signing Request (NOCSR) p.302 + var pk = self.get_pk() # private key of device + + # Example + # 3081CA + # 3070020100300E310C300A060355040A0C034353523059301306072A8648CE3D020106082A8648CE3D030107 + # PubKey=034200.043AEFB8D1F25813BE355920577971814827B24F2784A729297F88FBD998A59D29D439604678C42D2FA5DE4E9402C30376015E05DF0AD4A8737DCD4E6D03B11CF5 + # A000 + # 300C06082A8648CE3D0403020500 + # 034800 + # ECDSA=3045022054907C4F096B30EFEB56190E0F2AFAEE447991C927003185AD044D1A971BDEDD02210088FB7E44116FBD7DE5277890A3F3BC26ACC35441DF04FD0BBF02A369E751241D + + import crypto + var ec256 = crypto.EC_P256() + var pub = ec256.public_key(pk) + + var seg1 = bytes("3070020100300E310C300A060355040A0C034353523059301306072A8648CE3D020106082A8648CE3D030107034200") + seg1 .. pub + seg1 .. bytes("A000") + var seg2 = bytes("300C06082A8648CE3D0403020500") # not mutable + # compute signature in ECDSA format + var sig = ec256.ecdsa_sign_sha256_asn1(pk, seg1) + var seg3 = bytes(128) + seg3.add(0x03, 1) + seg3.add(size(sig)+1, 1) + seg3.add(0x00, 1) + seg3 .. sig + # construct the global csr + var seg_123_size = size(seg1) + size(seg2) + size(seg3) + var csr = bytes(208) + csr.add(0x30, 1) + csr.add(0x81, 1) + csr.add(seg_123_size & 0xFF, 1) + csr .. seg1 + csr .. seg2 + csr .. seg3 + return csr + end + +end +matter.Session = Matter_Session + + +################################################################################# +# Matter_Session_Store class +################################################################################# +class Matter_Session_Store + var sessions + static var FILENAME = "_matter_sessions.json" + + ############################################################# + def init() + self.sessions = [] + end + + ############################################################# + # add session + def create_session(local_session_id, initiator_session_id) + var session = self.get_session_by_local_session_id(local_session_id) + if session != nil self.remove_session(session) end + session = matter.Session(self, local_session_id, initiator_session_id) + self.sessions.push(session) + return session + end + + ############################################################# + # add session + def add_session(s, expires_in_seconds) + if expires_in_seconds != nil + s.set_expire_in_seconds(expires_in_seconds) + end + self.sessions.push(s) + end + + ############################################################# + def get_session_by_local_session_id(id) + if id == nil return nil end + var sz = size(self.sessions) + var i = 0 + var sessions = self.sessions + while i < sz + if sessions[i].local_session_id == id return sessions[i] end + i += 1 + end + end + + ############################################################# + def get_session_by_source_node_id(nodeid) + if nodeid == nil return nil end + var sz = size(self.sessions) + var i = 0 + var sessions = self.sessions + while i < sz + if sessions[i].source_node_id == nodeid return sessions[i] end + i += 1 + end + end + + ############################################################# + # Remove session by reference + # + def remove_session(s) + var i = 0 + var sessions = self.sessions + while i < size(self.sessions) + if sessions[i] == s + sessions.remove(i) + else + i += 1 + end + end + end + + ############################################################# + # Remove session by reference + # + # remove all other sessions that have the same: + # fabric / deviceid / fc + def remove_redundant_session(s) + var i = 0 + var sessions = self.sessions + while i < size(self.sessions) + var session = sessions[i] + if session != s && session.fabric == s.fabric && session.deviceid == s.deviceid #- && session.fabric_compressed == s.fabric_compressed -# + sessions.remove(i) + else + i += 1 + end + end + end + + ############################################################# + # Generate a new local_session_id + def gen_local_session_id() + import crypto + while true + var candidate_local_session_id = crypto.random(2).get(0, 2) + + if self.get_session_by_local_session_id(candidate_local_session_id) == nil + return candidate_local_session_id + end + + end + end + + ############################################################# + # remove_expired + # + # Check is any session has expired + def remove_expired() + var dirty = false + var i = 0 + var sessions = self.sessions + while i < size(self.sessions) + if sessions[i].has_expired() + if sessions[i]._persist dirty = true end # do we need to save + sessions.remove(i) + else + i += 1 + end + end + if dirty self.save() end + end + def every_second() + self.remove_expired() + end + + ############################################################# + # find or create a session for unencrypted traffic + # expires in `expire` seconds + def find_session_source_id_unsecure(source_node_id, expire) + var session = self.get_session_by_source_node_id(source_node_id) + if session == nil + session = matter.Session(self, 0, 0) + session.source_node_id = source_node_id + self.sessions.push(session) + end + session.set_expire_in_seconds(expire) + return session + end + + ############################################################# + def save() + import json + self.remove_expired() # clean before saving + + var j = [] + for v:self.sessions + if v._persist + j.push(v.tojson()) + end + end + var j_size = size(j) + j = "[" + j.concat(",") + "]" + + try + import string + var f = open(self.FILENAME, "w") + f.write(j) + f.close() + tasmota.log(string.format("MTR: Saved %i session(s)", j_size), 2) + return j + except .. as e, m + tasmota.log("MTR: Session_Store::save Exception:" + str(e) + "|" + str(m), 2) + return j + end + end + + ############################################################# + def load() + import string + try + self.sessions = [] # remove any left-over + var f = open(self.FILENAME) + var s = f.read() + f.close() + + import json + var j = json.load(s) + s = nil + tasmota.gc() # clean-up a potential long string + + for v:j # iterate on values + var session = matter.Session.fromjson(self, v) + if session != nil + self.add_session(session) + end + end + + tasmota.log(string.format("MTR: Loaded %i session(s)", size(self.sessions)), 2) + except .. as e, m + if e != "io_error" + tasmota.log("MTR: Session_Store::load Exception:" + str(e) + "|" + str(m), 2) + end + end + self.remove_expired() # clean after load + end +end +matter.Session_Store = Matter_Session_Store + +#- + +# Unit test +var s = Matter_Session(1,2) +s.counter_rcv.validate(0x100, false) +s.counter_snd.validate(0x1000, false) +s.source_node_id = bytes("1122334455667788") +assert(s.tojson() == '{"breadcrumb":"0","counter_rcv":256,"counter_snd":4352,"initiator_session_id":2,"local_session_id":1,"source_node_id":"0x1122334455667788"}') + +var ss = Matter_Session_Store() +ss.add_session(s) +var j = ss.save() +assert(j == '{"1":{"breadcrumb":"0","counter_rcv":256,"counter_snd":4352,"initiator_session_id":2,"local_session_id":1,"source_node_id":"0x1122334455667788"}}') + + +var ss = Matter_Session_Store() +ss.load() + +-# diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_TLV.be b/lib/libesp32/berry_matter/src/embedded/Matter_TLV.be new file mode 100644 index 000000000..58a1e8e13 --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_TLV.be @@ -0,0 +1,874 @@ +# +# Matter_TLV.be - implements the encoding and decoding of Matter TLV structures (Tag/Lenght/Value) Appendix A. +# +# Copyright (C) 2023 Stephan Hadinger & Theo Arends +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +# Support for Matter Protocol: TLV encoding and decoding + +import matter + +#@ solidify:Matter_TLV.Matter_TLV_item,weak +#@ solidify:Matter_TLV.Matter_TLV_list,weak +#@ solidify:Matter_TLV.Matter_TLV_struct,weak +#@ solidify:Matter_TLV.Matter_TLV_array,weak +#@ solidify:Matter_TLV,weak + +class Matter_TLV + static var _type = [ + 'i1', 'i2', 'i4', 'i8', 'u1', 'u2', 'u4', 'u8', # signed and unsigned 0x00-0x07 + 'bool', 'bool', 'float', 'double', # 0x08-0x0B + 'UTF1', 'UTF2', 'UTF4', 'UTF8', # 0x0C-0x0F + 'b1', 'b2', 'b4', 'b8', # 0x10-0x13 + 'null', 'struct', 'array', 'list', 'end' # 0x14-0x18 + # all other are reserved +] + + static var _len = [ + 1, 2, 4, 8, 1, 2, 4, 8, + 0, 0, 4, 8, + -1, -2, -4, -8, + -1, -2, -4, -8, + 0, -99, -99, -99, 0 + ] + + # type values (enum like) + static var I1 = 0x00 + static var I2 = 0x01 + static var I4 = 0x02 + static var I8 = 0x03 + static var U1 = 0x04 + static var U2 = 0x05 + static var U4 = 0x06 + static var U8 = 0x07 + static var BOOL = 0x08 # when encoding, use indifferentiate + static var BFALSE = 0x08 + static var BTRUE = 0x09 + static var FLOAT = 0x0A + static var DOUBLE = 0x0B + static var UTF1 = 0x0C + static var UTF2 = 0x0D + static var UTF4 = 0x0E + static var UTF8 = 0x0F + static var B1 = 0x10 + static var B2 = 0x11 + static var B4 = 0x12 + static var B8 = 0x13 + static var NULL = 0x14 + static var STRUCT = 0x15 + static var ARRAY = 0x16 + static var LIST = 0x17 + static var EOC = 0x18 + + ################################################################################# + # Matter_TLV_item class + ################################################################################# + static class Matter_TLV_item + # we keep a shortcut reference to the Matter_TLV class + static var TLV = Matter_TLV + # parent tag to inherit vendor/profile/tag + var parent + var next_idx # next idx in buffer (when parsing) + # tags + var tag_vendor # 16 bit VendorID [opt] + var tag_profile # 16 bit profile number [opt] + var tag_number # 32 bit tag number + var tag_sub # context specific tag 8 bit [opt] + # type + var typ # TLV type number, set at decoding, mandatory for encoding + # value + var val # multi-type: int, float, bool, bytes, map, list + + ############################################################# + # constructor + def init(parent) + self.parent = parent + end + + ############################################################# + # neutral converter + def to_TLV() + return self + end + + ############################################################# + # create simple TLV + static def create_TLV(t, value) + if value != nil + var v = _class() # parent is nil + v.typ = t + v.val = value + return v + end + end + + ############################################################# + # tostring + # + # We are trying to follow the official Matter way of printing TLV + # Ex: '42U' or '1 = 42U' or '0xFFF1::0xDEED:0xAA55FEED = 42U' + def tostring() + import string + # var s = " 0 s += "= " end + + # print value + if type(self.val) == 'int' s += string.format("%i", self.val) + if self.typ >= self.TLV.U1 && self.typ <= self.TLV.U8 s += "U" end + elif type(self.val) == 'bool' s += self.val ? "true" : "false" + elif self.val == nil s += "null" + elif type(self.val) == 'real' s += string.format("%g", self.val) + elif type(self.val) == 'string' s += string.format('"%s"', self.val) + elif isinstance(self.val, int64) s += self.val.tostring() + if self.typ >= self.TLV.U1 && self.typ <= self.TLV.U8 s += "U" end + elif type(self.val) == 'instance' + s += string.format("%s", self.val.tohex()) + end + + except .. as e, m + return e + " " + m + end + return s + end + + ############################################################# + # parse a bytes() array from `idx` + # args: + # b: bytes() buffer + # idx: starting index in the bytes() buffer + # parent: (optional) the parent object to inherit tag values + # + # returns the next `idx` for the item following or `-1` if error + # The next `idx` is also stored in `self.next_idx` + def parse(b, idx) + var item_type = self.typ + # parse LV + var TLV = self.TLV # cache value in register + var item_len = TLV._len[item_type] + + if item_len == 8 # i64 / u64 / double + self.val = int64() + self.val.frombytes(b, idx) + idx += 8 + elif item_type == TLV.BFALSE || item_type == TLV.BTRUE # bool + self.val = (item_type == TLV.BTRUE) + elif item_type < TLV.U8 # i1/i2/i4 u1/u2/u4 + self.val = item_type <= TLV.I8 ? b.geti(idx, item_len) : b.get(idx, item_len) + idx += item_len + elif item_type == TLV.FLOAT # float + self.val = b.getfloat(idx) + idx += 4 + elif item_len >= -8 && item_len <= -1 # len prefix 1/2/4/8 + # TODO skip len == 8 for now + var b_len = b.get(idx, -item_len) + idx += -item_len + self.val = b[idx .. idx + b_len - 1] + idx += b_len + if (item_type <= TLV.UTF8) self.val = self.val.asstring() end + elif item_type == TLV.NULL # null + # do nothing + elif item_type == TLV.EOC + tasmota.log("MTR: unexpected eoc", 3) + else + tasmota.log("MTR: unexpected type: " + str(item_type), 3) + end + self.next_idx = idx + return idx + end + + ############################################################# + # encode TLV + # + # appends to the bytes() object + def encode(b) + var TLV = self.TLV + if b == nil b = bytes() end # start new buffer if none passed + + # special case for bool + # we need to change the type according to the value + if self.typ == TLV.BFALSE || self.typ == TLV.BTRUE + self.typ = bool(self.val) ? TLV.BTRUE : TLV.BFALSE + # try to compress ints + elif self.typ >= TLV.I2 && self.typ <= TLV.I4 + var i = int(self.val) + if i <= 127 && i >= -128 self.typ = TLV.I1 + elif i <= 32767 && i >= -32768 self.typ = TLV.I2 + end + elif self.typ >= TLV.U2 && self.typ <= TLV.U4 + var i = int(self.val) + if i <= 255 && i >= 0 self.typ = TLV.U1 + elif i <= 65535 && i >= 0 self.typ = TLV.U2 + end + elif self.typ >= TLV.B1 && self.typ <= TLV.B8 # encode length as minimum possible + if size(self.val) <= 255 + self.typ = TLV.B1 + elif size(self.val) <= 65535 + self.typ = TLV.B2 + else + self.typ = TLV.B4 # B4 is unlikely, B8 is impossible + end + elif self.typ >= TLV.UTF1 && self.typ <= TLV.UTF8 + if size(self.val) <= 255 + self.typ = TLV.UTF1 + elif size(self.val) <= 65535 + self.typ = TLV.UTF2 + else + self.typ = TLV.UTF4 # UTF4 is unlikely, UTF8 is impossible + end + end + + # encode tag and type + self._encode_tag(b) + # encode value + + if self.typ == TLV.I1 || self.typ == TLV.U1 + b.add(int(self.val), 1) + elif self.typ == TLV.I2 || self.typ == TLV.U2 + b.add(int(self.val), 2) + elif self.typ == TLV.I4 || self.typ == TLV.U4 + b.add(int(self.val), 4) + elif self.typ == TLV.I8 || self.typ == TLV.U8 + var i64 = self.val + if !isinstance(i64, int64) + i64 = int64(int(self.val)) + end + b .. i64.tobytes() + elif self.typ == TLV.BFALSE || self.typ == TLV.BTRUE + # push nothing + elif self.typ == TLV.FLOAT + var idx = size(b) + b.add(0, 4) + b.setfloat(idx, real(self.val)) + elif self.typ == TLV.DOUBLE + raise "value_error", "Unsupported type TLV.DOUBLE" + elif self.typ == TLV.UTF1 + if size(self.val) > 255 raise "value_error", "string too big" end + b.add(size(self.val), 1) + b..bytes().fromstring(str(self.val)) + elif self.typ == TLV.UTF2 + if size(self.val) > 65535 raise "value_error", "string too big" end + b.add(size(self.val), 2) + b..bytes().frostring(str(self.val)) + elif self.typ == TLV.B1 + if size(self.val) > 255 raise "value_error", "bytes too big" end + b.add(size(self.val), 1) + b..self.val + elif self.typ == TLV.B2 + if size(self.val) > 65535 raise "value_error", "bytes too big" end + b.add(size(self.val), 2) + b..self.val + elif self.typ == TLV.NULL + # push nothing + else + raise "value_error", "unsupported type " + str(self.typ) + end + + return b + end + + ############################################################# + # internal_function + # encode Tag+Type as the first bytes + def _encode_tag(b) + var tag_number = self.tag_number != nil ? self.tag_number : 0 + var tag_huge = (tag_number >= 65536) || (tag_number < 0) + var tag_control = 0x00 + if self.tag_vendor != nil + # full encoding + if tag_huge + b.add(0xE0 + self.typ, 1) + b.add(self.tag_vendor, 2) + b.add(self.tag_profile, 2) + b.add(self.tag_number, 4) + else + b.add(0xC0 + self.typ, 1) + b.add(self.tag_vendor, 2) + b.add(self.tag_profile, 2) + b.add(self.tag_number, 2) + end + elif self.tag_profile == -1 # Matter Common profile + if tag_huge + b.add(0x60 + self.typ, 1) + b.add(self.tag_number, 4) + else + b.add(0x40 + self.typ, 1) + b.add(self.tag_number, 2) + end + elif self.tag_profile != nil + if tag_huge + b.add(0xA0 + self.typ, 1) + b.add(self.tag_number, 4) + else + b.add(0x80 + self.typ, 1) + b.add(self.tag_number, 2) + end + elif self.tag_sub != nil + b.add(0x20 + self.typ, 1) + b.add(self.tag_sub, 1) + else # anonymous tag + b.add(0x00 + self.typ, 1) + end + end + + ############################################################# + # Compare the value index with an element + # returns: + # 1 if self is strictly greater than k + # 0 if equal or lower + def _cmp_gt(k) + # compare tag_vendor + if self.tag_vendor != nil + if k.tag_vendor == nil return 1 end + if self.tag_vendor > k.tag_vendor return 1 end + if self.tag_vendor == k.tag_vendor + if self.tag_profile > k.tag_profile return 1 end + end + # continue to tag comparison + end + + # Matter common profile + if self.tag_profile == -1 + if k.tag_profile == nil return 1 end + elif self.tag_profile == nil + if k.tag_profile == -1 return 0 end + end + + if self.tag_number != nil + if k.tag_number == nil return 1 end + if self.tag_number > k.tag_number return 1 end + return 0 + end + + if self.tag_sub != nil + if k.tag_sub == nil return 1 end + if self.tag_sub > k.tag_sub return 1 end + end + + return 0 + end + + ################################################################################# + # Simple insertion sort - sorts the list in place, and returns the list + ################################################################################# + static def sort(l) + # insertion sort + for i:1..size(l)-1 + var k = l[i] + var j = i + while (j > 0) && (l[j-1]._cmp_gt(k) > 0) + l[j] = l[j-1] + j -= 1 + end + l[j] = k + end + return l + end + + ############################################################# + # set parent + def set_parent(parent) + self.parent = parent + end + + ############################################################# + # Setters for tags + def set_fulltag(vendor, profile, tag) + self.tag_vendor = int(vendor) + self.tag_profile = int(profile) + self.tag_number = int(tag) + self.tag_sub = nil + end + # set context specific + def set_anonymoustag() + self.set_fulltag() + end + # set common profile + def set_commonprofile() + self.set_fulltag(nil, -1, nil) + end + # set context specific + def set_contextspecific(n) + self.set_fulltag() + self.tag_sub = int(n) + end + end + +# class Matter_TLV_array var _ end +# class Matter_TLV_struct var _ end + + static class Matter_TLV_list : Matter_TLV_item + ################################################################################# + def init(parent) + super(self).init(parent) + self.typ = self.TLV.LIST + self.val = [] + end + + ################################################################################# + def tostring() + return self.tostring_inner(false, "[[", "]]") + end + + def tostring_inner(sorted, pre, post) + import string + var s = "" + try + + if self.tag_profile == -1 + s += "Matter::" + if self.tag_number != nil s += string.format("0x%08X ", self.tag_number) end + else + if self.tag_vendor != nil s += string.format("0x%04X::", self.tag_vendor) end + if self.tag_profile != nil s += string.format("0x%04X:", self.tag_profile) end + if self.tag_number != nil s += string.format("0x%08X ", self.tag_number) end + if self.tag_sub != nil s += string.format("%i ", self.tag_sub) end + end + + if size(s) > 0 s += "= " end + + s += pre + + # sort values + var val_list = self.val.copy() + if sorted + self.sort(val_list) + end + + s += val_list.concat(", ") + + s += post + + except .. as e, m + return e + " " + m + end + return s + end + + ################################################################################# + def parse(b, idx) + # iterate until end of struct + while b[idx] != self.TLV.EOC + # read next + var item = self.TLV.parse(b, idx, self) + idx = item.next_idx + + self.val.push(item) + end + idx += 1 + + self.next_idx = idx + return idx + end + + ############################################################# + # encode TLV + # + # appends to the bytes() object + def _encode_inner(b, is_struct) + if b == nil b = bytes() end + # encode tag and type + self._encode_tag(b) + # sort values + var val_list = self.val.copy() + if is_struct + self.sort(val_list) + end + + # output each one after the other + for v : val_list + v.encode(b) + end + + # add 'end of container' + b.add(self.TLV.EOC, 1) + + return b + end + + ############################################################# + def encode(b) + return self._encode_inner(b, false) + end + + ############################################################# + # Getters + # + # get by index + def item(n) + return self.val[n] + end + def setitem(n, v) + self.val[n] = v + end + def push(v) + self.val.push(v) + end + def size() + return size(self.val) + end + + ############################################################# + # get by sub-tag, return nil if not found + def findsub(n, v) + for k : self.val + if k.tag_sub == n return k end + end + return v + end + def findsubval(n, v) + var r = self.findsub(n) + if r != nil return r.val end + return v + end + def findsubtyp(n) + var r = self.findsub(n) + if r != nil return r.typ end + return nil + end + def getsub(n) + var v = self.findsub(n) + if v == nil raise "value_error", "sub not found" end + return v + end + def getsubval(n) + return self.getsub(n).val + end + + ############################################################# + # adders + def add_TLV(tag, t, value) + if value != nil + var v = self.TLV.Matter_TLV_item(self) + v.tag_sub = tag + v.typ = t + v.val = value + self.val.push(v) + end + return self + end + + # add on object that implements `to_TLV()` and adds to the current container + # + # obj can be `nil`, in such case nothing happens + # returns `self` to allow calls to be chained + def add_obj(tag, obj) + if obj != nil + var value = obj.to_TLV() + value.tag_sub = tag + self.val.push(value) + end + return self + end + + def add_list(tag) + var s = self.TLV.Matter_TLV_list(self) + s.tag_sub = tag + self.val.push(s) + return s + end + + def add_array(tag) + var s = self.TLV.Matter_TLV_array(self) + s.tag_sub = tag + self.val.push(s) + return s + end + + def add_struct(tag) + var s = self.TLV.Matter_TLV_struct(self) + s.tag_sub = tag + self.val.push(s) + return s + end + + end + + ################################################################################# + # Matter_TLV_struct class + ################################################################################# + static class Matter_TLV_struct : Matter_TLV_list + def init(parent) + super(self).init(parent) + self.typ = self.TLV.STRUCT + self.val = [] + end + + ############################################################# + def tostring() + return self.tostring_inner(true, "{", "}") + end + + ############################################################# + # encode TLV + # + # appends to the bytes() object + def encode(b) + return self._encode_inner(b, true) + end + end + + ################################################################################# + # Matter_TLV_array class + ################################################################################# + static class Matter_TLV_array : Matter_TLV_list + def init(parent) + super(self).init(parent) + self.typ = self.TLV.ARRAY + self.val = [] + end + + ############################################################# + def tostring() + return self.tostring_inner(false, "[", "]") + end + + ############################################################# + def parse(b, idx) + # iterate until end of struct + while b[idx] != self.TLV.EOC + # read next + var item = self.TLV.parse(b, idx, self) + idx = item.next_idx + + # for arrays, all tags must be anonymous + item.tag_vendor = nil + item.tag_profile = nil + item.tag_number = nil + item.tag_sub = nil + self.val.push(item) + end + idx += 1 + + self.next_idx = idx + return idx + end + end + + ################################################################################# + # bookkeeping + ################################################################################# + # Matter_TLV.Matter_TLV_item = Matter_TLV_item + # Matter_TLV.Matter_TLV_struct = Matter_TLV_struct + # Matter_TLV.Matter_TLV_array = Matter_TLV_array + # Matter_TLV.Matter_TLV_list = Matter_TLV_list + + # parse a bytes() array from `idx` + # args: + # b: bytes() buffer + # idx: starting index in the bytes() buffer + # parent: (optional) the parent object to inherit tag values + # returns the next `idx` for the item following or `-1` if error + static def parse(b, idx, parent) + var TLV = _class + if idx == nil idx = 0 end + # read type and tag_control + var item_type = b[idx] & 0x1F # values 0x00 - 0x1F + var item_tag_control = b[idx] & 0xE0 # values 0x20 - 0xE0 + idx += 1 # skip tag/type byte + + if (item_type > TLV.EOC) raise "TLV_error", "invalid TLV type "+str(item_type) end + + # ############################################################ + # instanciate TLV item or struct + var item + if item_type == TLV.STRUCT + item = _class.Matter_TLV_struct(parent) + elif item_type == TLV.ARRAY + item = _class.Matter_TLV_array(parent) + elif item_type == TLV.LIST + item = _class.Matter_TLV_list(parent) + else + item = _class.Matter_TLV_item(parent) + end + item.typ = item_type # set type for item + + # ############################################################ + # parse Tag and length + # do we have a vendor? + if item_tag_control == 0xC0 || item_tag_control == 0xE0 + item.tag_vendor = b.get(idx, 2) + item.tag_profile = b.get(idx + 2, 2) + idx += 4 + end + # Common profile tags + if item_tag_control == 0x40 || item_tag_control == 0x60 + item.tag_vendor = nil + item.tag_profile = -1 + end + # Tags + if item_tag_control == 0x00 + # pass + elif item_tag_control == 0x20 + # context specific tag + item.tag_sub = b[idx] + idx += 1 + elif item_tag_control == 0xC0 || item_tag_control == 0x80 || item_tag_control == 0x40 + item.tag_number = b.get(idx, 2) + idx += 2 + else + item.tag_number = b.get(idx, 4) + idx += 4 + end + + # ############################################################ + # parse Value + idx = item.parse(b, idx) + + return item + end + ############################################################# + # create simple TLV + static def create_TLV(t, value) + return _class.Matter_TLV_item.create_TLV(t, value) + end +end + +# add to matter +import matter +matter.TLV = Matter_TLV + +#- + +# Test +import matter + +#load("Matter_TLV.be") + +var m +m = matter.TLV.parse(bytes("2502054C")) +assert(m.tostring() == "2 = 19461U") +assert(m.encode() == bytes("2502054C")) + +m = matter.TLV.parse(bytes("0001")) +assert(m.tostring() == "1") +assert(m.encode() == bytes("0001")) + +m = matter.TLV.parse(bytes("08")) +assert(m.tostring() == "false") +assert(m.encode() == bytes("08")) +m = matter.TLV.parse(bytes("09")) +assert(m.tostring() == "true") +assert(m.encode() == bytes("09")) + +m = matter.TLV.parse(bytes("01FFFF")) +assert(m.tostring() == "-1") +assert(m.encode() == bytes("00FF")) +m = matter.TLV.parse(bytes("05FFFF")) +assert(m.tostring() == "65535U") +assert(m.encode() == bytes("05FFFF")) + +m = matter.TLV.parse(bytes("0A0000C03F")) +assert(m.tostring() == "1.5") +assert(m.encode() == bytes("0A0000C03F")) + +m = matter.TLV.parse(bytes("0C06466f6f626172")) +assert(m.tostring() == '"Foobar"') +assert(m.encode() == bytes("0C06466f6f626172")) + +m = matter.TLV.parse(bytes("1006466f6f626172")) +assert(m.tostring() == "466F6F626172") +assert(m.encode() == bytes("1006466f6f626172")) + +m = matter.TLV.parse(bytes("e4f1ffeddeedfe55aa2a")) +assert(m.tostring() == "0xFFF1::0xDEED:0xAA55FEED = 42U") +assert(m.encode() == bytes("e4f1ffeddeedfe55aa2a")) + + +m = matter.TLV.parse(bytes("300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66")) +assert(m.tostring() == "1 = D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66") +assert(m.encode() == bytes("300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66")) + +# context specific +m = matter.TLV.parse(bytes("24012a")) +assert(m.tostring() == "1 = 42U") +assert(m.encode() == bytes("24012a")) + +m = matter.TLV.parse(bytes("4401002a")) +assert(m.tostring() == "Matter::0x00000001 = 42U") +assert(m.encode() == bytes("4401002a")) + +# int64 +m = matter.TLV.parse(bytes("030102000000000000")) +assert(m.tostring() == "513") +assert(m.encode() == bytes("030102000000000000")) + +m = matter.TLV.parse(bytes("070102000000000000")) +assert(m.tostring() == "513U") +assert(m.encode() == bytes("070102000000000000")) + +m = matter.TLV.parse(bytes("03FFFFFFFFFFFFFFFF")) +assert(m.tostring() == "-1") +assert(m.encode() == bytes("03FFFFFFFFFFFFFFFF")) + +m = matter.TLV.parse(bytes("07FFFFFFFFFFFFFF7F")) +assert(m.tostring() == "9223372036854775807U") +assert(m.encode() == bytes("07FFFFFFFFFFFFFF7F")) + +# structure +m = matter.TLV.parse(bytes("1518")) +assert(m.tostring() == "{}") +assert(m.encode() == bytes("1518")) + +m = matter.TLV.parse(bytes("15300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D662502054C240300280418")) +assert(m.tostring() == "{1 = D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66, 2 = 19461U, 3 = 0U, 4 = false}") +assert(m.encode() == bytes("15300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D662502054C240300280418")) + +m = matter.TLV.parse(bytes("15300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D662502054C240300280435052501881325022C011818")) +assert(m.tostring() == "{1 = D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66, 2 = 19461U, 3 = 0U, 4 = false, 5 = {1 = 5000U, 2 = 300U}}") +assert(m.encode() == bytes("15300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D662502054C240300280435052501881325022C011818")) + +# list +m = matter.TLV.parse(bytes("1718")) +assert(m.tostring() == "[[]]") +assert(m.encode() == bytes("1718")) + +m = matter.TLV.parse(bytes("17000120002a000200032000ef18")) +assert(m.tostring() == "[[1, 0 = 42, 2, 3, 0 = -17]]") +assert(m.encode() == bytes("17000120002a000200032000ef18")) + + +# array +m = matter.TLV.parse(bytes("1618")) +assert(m.tostring() == "[]") +assert(m.encode() == bytes("1618")) + +m = matter.TLV.parse(bytes("160000000100020003000418")) +assert(m.tostring() == "[0, 1, 2, 3, 4]") +assert(m.encode() == bytes("160000000100020003000418")) + +# mix +m = matter.TLV.parse(bytes("16002a02f067fdff15180a33338f410c0648656c6c6f2118")) +assert(m.tostring() == '[42, -170000, {}, 17.9, "Hello!"]') +assert(m.encode() == bytes("16002a02f067fdff15180a33338f410c0648656c6c6f2118")) + +m = matter.TLV.parse(bytes("153600172403312504FCFF18172402002403302404001817240200240330240401181724020024033024040218172402002403302404031817240200240328240402181724020024032824040418172403312404031818280324FF0118")) +assert(m.tostring() == '{0 = [[[3 = 49U, 4 = 65532U]], [[2 = 0U, 3 = 48U, 4 = 0U]], [[2 = 0U, 3 = 48U, 4 = 1U]], [[2 = 0U, 3 = 48U, 4 = 2U]], [[2 = 0U, 3 = 48U, 4 = 3U]], [[2 = 0U, 3 = 40U, 4 = 2U]], [[2 = 0U, 3 = 40U, 4 = 4U]], [[3 = 49U, 4 = 3U]]], 3 = false, 255 = 1U}') +assert(m.encode() == bytes("153600172403312504FCFF18172402002403302404001817240200240330240401181724020024033024040218172402002403302404031817240200240328240402181724020024032824040418172403312404031818280324FF0118")) + +-# diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_UDPServer.be b/lib/libesp32/berry_matter/src/embedded/Matter_UDPServer.be new file mode 100644 index 000000000..75df885c3 --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_UDPServer.be @@ -0,0 +1,187 @@ +# +# Matter_UDPServer.be - implements IPv6 UDP communication for Matter +# +# Copyright (C) 2023 Stephan Hadinger & Theo Arends +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +# Matter_UDPServer class +# +# For receiving and outgoing messages on UDP +# + +import matter + +#@ solidify:Matter_UDPPacket_sent,weak +#@ solidify:Matter_UDPServer,weak + +################################################################################# +# Matter_UDPPacket_sent class +# +# A packet that needs to be resent if not acknowledged by the other party +################################################################################# +class Matter_UDPPacket_sent + static var RETRY_MS = 500 # retry every 500 ms + static var RETRIES = 4 # retry every 500 ms + var raw # bytes() to be sent + var addr # ip_address (string) + var port # port (int) + var msg_id # (int) message identifier that needs to be acknowledged + var retries # how many retries are allowed, when `0` drop and log + var next_try # timestamp (millis) when to try again + + def init(raw, addr, port, id) + self.raw = raw + self.addr = addr + self.port = port + self.msg_id = id + self.retries = self.RETRIES + self.next_try = tasmota.millis() + self.RETRY_MS + end + + def send(udp_socket) + import string + var ok = udp_socket.send(self.addr ? self.addr : udp_socket.remote_ip, self.port ? self.port : udp_socket.remote_port, self.raw) + if ok + tasmota.log(string.format("MTR: sending packet to '[%s]:%i'", self.addr, self.port), 3) + else + tasmota.log(string.format("MTR: failed to send packet to '[%s]:%i'", self.addr, self.port), 2) + end + end +end +matter.UDPPacket_sent = Matter_UDPPacket_sent + +################################################################################# +# Matter_UDPServer class +# +################################################################################# +class Matter_UDPServer + static var MAX_PACKETS_READ = 4 # read at most 4 packets per tick + var address, port # local address and port + var listening # true if active + var udp_socket + var dispatch_cb # callback to call when a message is received + var packets_sent # map of packets sent to be acknowledged + + ############################################################# + def init(address, port) + self.address = address ? address : "" + self.port = port ? port : 5540 + self.listening = false + self.packets_sent = {} + end + + ############################################################# + # start the server + # raises an exception if something is wrong + # registers as device handle + # + # `cb`: callback to call when a message is received + def start(cb) + if !self.listening + self.udp_socket = udp() + var ok = self.udp_socket.begin(self.address, self.port) + if !ok raise "network_error", "could not open UDP server" end + self.listening = true + self.dispatch_cb = cb + tasmota.add_driver(self) + end + end + + ############################################################# + # stop the server + # remove driver + def stop() + if self.listening + self.udp_socket.stop() + self.listening = false + tasmota.remove_driver(self) + end + end + + ############################################################# + def every_50ms() + import string + var packet_read = 0 + if self.udp_socket == nil return end + var packet = self.udp_socket.read() + while packet != nil + # self.packet = packet + packet_read += 1 + var from_addr = self.udp_socket.remote_ip + var from_port = self.udp_socket.remote_port + tasmota.log(string.format("MTR: UDP received from [%s]:%i", from_addr, from_port), 4) + if self.dispatch_cb + self.dispatch_cb(packet, from_addr, from_port) + end + # are we reading new packets? + if packet_read < self.MAX_PACKETS_READ + packet = self.udp_socket.read() + else + packet = nil + end + end + self.resend_packets() # resend any packet + end + + ############################################################# + def resend_packets() + for packet:self.packets_sent + if tasmota.time_reached(packet.next_try) + tasmota.log("MTR: resending packet id=" + str(packet.msg_id), 3) + packet.send(self.udp_socket) # resend + packet.retries -= 1 + if packet.retries <= 0 + self.packets_sent.remove(packet.msg_id) + else + packet.next_try = tasmota.millis() + packet.RETRY_MS + end + end + end + end + + ############################################################# + # just received acknowledgment, remove packet from sender + def packet_ack(id) + if id == nil return end + if self.packets_sent.contains(id) + self.packets_sent.remove(id) + tasmota.log("MTR: removed packet from sending list id=" + str(id), 3) + end + end + + ############################################################# + def send_response(raw, addr, port, id) + var packet = matter.UDPPacket_sent(raw, addr, port, id) + packet.send(self.udp_socket) # send + if id + self.packets_sent[id] = packet + end + end + + ############################################################# + # placeholder, nothing to run for now + def every_second() + end +end +matter.UDPServer = Matter_UDPServer + +#- + +import matter +var udps = matter.UDPServer() +udps.listen() + +-# diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_UI.be b/lib/libesp32/berry_matter/src/embedded/Matter_UI.be new file mode 100644 index 000000000..7bd6921f4 --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_UI.be @@ -0,0 +1,259 @@ +# +# Matter_UI.be - WebUI for Matter configuration in Tasmota +# +# Copyright (C) 2023 Stephan Hadinger & Theo Arends +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +####################################################################### +# Matter Web UI +# +####################################################################### + +import matter + +#@ solidify:Matter_UI,weak + +################################################################################# +# Partition_wizard_UI +# +# WebUI for the partition manager +################################################################################# +class Matter_UI + var device + + def init(device) + self.device = device + tasmota.add_driver(self) + end + + # #################################################################################################### + # Init web handlers + # #################################################################################################### + # Displays a "Autoconf" button on the configuration page + def web_add_config_button() + import webserver + # webserver.content_send("

") + webserver.content_send("

") + end + + #- ---------------------------------------------------------------------- -# + #- Show commissioning information and QR Code + # + # Returns true if Matter is enabled + #- ---------------------------------------------------------------------- -# + def show_enable(p) + import webserver + import string + var matter_enabled = tasmota.get_option(matter.MATTER_OPTION) + + webserver.content_send(string.format("
 Matter %s 

", + matter_enabled ? "Enabled" : "Disabled")) + + webserver.content_send("

Matter support is experimental.

") + + webserver.content_send("
") + webserver.content_send(string.format("

") + + webserver.content_send("

") + + return matter_enabled + end + + #- ---------------------------------------------------------------------- -# + #- Show commissioning information and QR Code + #- ---------------------------------------------------------------------- -# + def show_commissioning_info() + import webserver + import string + + webserver.content_send("
 Matter Passcode 

") + + var pairing_code = self.device.compute_manual_pairing_code() + webserver.content_send(string.format("

Manual pairing code:
%s-%s-%s


", pairing_code[0..3], pairing_code[4..6], pairing_code[7..])) + + var qr_text = self.device.compute_qrcode_content() + webserver.content_send('
') + webserver.content_send(string.format('', qr_text)) + webserver.content_send(string.format("

%s


", qr_text)) + + webserver.content_send("
") + webserver.content_send("

Passcode:

") + webserver.content_send(string.format("", self.device.passcode)) + webserver.content_send("

Distinguish id:

") + webserver.content_send(string.format("", self.device.discriminator)) + webserver.content_send("

") + + + webserver.content_send("

") + + end + + #- ---------------------------------------------------------------------- -# + #- Show commissioning information and QR Code + #- ---------------------------------------------------------------------- -# + def show_session_info(p) + import webserver + import string + + webserver.content_send("
 Sessions 

") + webserver.content_send("

Existing sessions:

") + + if size(self.device.sessions.sessions) == 0 + webserver.content_send("

None

") + else + var i = 0 + var sz = size(self.device.sessions.sessions) + while i < sz + var s = self.device.sessions.sessions[i] + if s.fabric + webserver.content_send(string.format("
 Session %i 

", s.local_session_id)) + if i != 0 webserver.content_send("
") end + var fabric_rev = s.fabric.copy().reverse() + var deviceid_rev = s.deviceid.copy().reverse() + webserver.content_send(string.format("Fabric: %s
", fabric_rev.tohex())) + webserver.content_send(string.format("Device: %s
 ", deviceid_rev.tohex())) + + webserver.content_send("
") + webserver.content_send(string.format("", s.local_session_id)) + webserver.content_send("

") + + webserver.content_send("

") + end + i += 1 + end + end + + webserver.content_send("

") + + end + + + ####################################################################### + # Serve qrcode.min.js static file + ####################################################################### + def page_qrcode_min_js() + import webserver + + webserver.content_open(200, "text/javascript") + webserver.content_send(matter._QRCODE_MINJS) + end + + ####################################################################### + # Display the complete page + ####################################################################### + def page_part_mgr() + import webserver + import string + + if !webserver.check_privileged_access() return nil end + + webserver.content_start("Matter") #- title of the web page -# + webserver.content_send_style() #- send standard Tasmota styles -# + + webserver.content_send('') + + if self.show_enable() + self.show_commissioning_info() + self.show_session_info() + end + webserver.content_button(webserver.BUTTON_CONFIGURATION) + webserver.content_stop() #- end of web page -# + end + + ####################################################################### + # Web Controller, called by POST to `/part_wiz` + ####################################################################### + def page_part_ctl() + import webserver + if !webserver.check_privileged_access() return nil end + + import string + import partition_core + import persist + + + #- check that the partition is valid -# + var p = partition_core.Partition() + + try + + #---------------------------------------------------------------------# + # Change Passcode and/or Passcode + #---------------------------------------------------------------------# + if webserver.has_arg("passcode") || webserver.has_arg("discriminator") + if webserver.has_arg("passcode") + self.device.passcode = int(webserver.arg("passcode")) + end + if webserver.has_arg("discriminator") + self.device.discriminator = int(webserver.arg("discriminator")) + end + self.device.save_param() + + #- and force restart -# + webserver.redirect("/?rst=") + + elif webserver.has_arg("enable") + tasmota.cmd("SetOption" + str(matter.MATTER_OPTION) + " 1") + #- and force restart -# + webserver.redirect("/?rst=") + + elif webserver.has_arg("disable") + tasmota.cmd("SetOption" + str(matter.MATTER_OPTION) + " 0") + #- and force restart -# + webserver.redirect("/?rst=") + + elif webserver.has_arg("del_session") + var session = self.device.sessions.get_session_by_local_session_id(int(webserver.arg("del_session"))) + if session != nil + self.device.sessions.remove_session(session) + self.device.sessions.save() + end + + #- and force restart -# + webserver.redirect("/?rst=") + + end + except .. as e, m + tasmota.log(string.format("BRY: Exception> '%s' - %s", e, m), 2) + #- display error page -# + webserver.content_start("Parameter error") #- title of the web page -# + webserver.content_send_style() #- send standard Tasmota styles -# + + webserver.content_send(string.format("

Exception:
'%s'
%s

", e, m)) + + webserver.content_button(webserver.BUTTON_MANAGEMENT) #- button back to management page -# + webserver.content_stop() #- end of web page -# + end + end + + #- ---------------------------------------------------------------------- -# + # respond to web_add_handler() event to register web listeners + #- ---------------------------------------------------------------------- -# + #- this is called at Tasmota start-up, as soon as Wifi/Eth is up and web server running -# + def web_add_handler() + import webserver + #- we need to register a closure, not just a function, that captures the current instance -# + webserver.on("/matterc", / -> self.page_part_mgr(), webserver.HTTP_GET) + webserver.on("/matterc", / -> self.page_part_ctl(), webserver.HTTP_POST) + webserver.on("/qrcode.min.js", / -> self.page_qrcode_min_js(), webserver.HTTP_GET) + end +end +matter.UI = Matter_UI diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_inspect.be b/lib/libesp32/berry_matter/src/embedded/Matter_inspect.be new file mode 100644 index 000000000..c9f9a15d2 --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_inspect.be @@ -0,0 +1,64 @@ +# +# Matter_inspect.be - implements a generic function to inspect an instance (for debugging only) +# +# Copyright (C) 2023 Stephan Hadinger & Theo Arends +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +import matter + +#@ solidify:matter.sort,weak +def sort(l) + # insertion sort + for i:1..size(l)-1 + var k = l[i] + var j = i + while (j > 0) && (l[j-1] > k) + l[j] = l[j-1] + j -= 1 + end + l[j] = k + end + return l +end +matter.sort = sort + +#@ solidify:matter.inspect,weak +# debug function +def inspect(p) + try + import string + import introspect + + var keys = [] + for k : introspect.members(p) + var v = introspect.get(p, k) + if type(v) != 'function' keys.push(k) end + end + keys = matter.sort(keys) + + var r = [] + for k : keys + var v = introspect.get(p, k) + # if type(v) == 'string' v = string.escape(v, true) end + r.push(string.format("'%s': %s", str(k), str(v))) + end + + return "{" + r.concat(", ") + "}" + except .. as e, m + return "Exception:" + str(e) + "|" + str(m) + end +end +matter.inspect = inspect diff --git a/lib/libesp32/berry_matter/src/embedded/matter.be b/lib/libesp32/berry_matter/src/embedded/matter.be new file mode 100644 index 000000000..49a23ab68 --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/matter.be @@ -0,0 +1,4 @@ +# placeholder for `import matter` not to fail when running solidification + +var m = module("matter") +return m diff --git a/lib/libesp32/berry_matter/src/solidify/.keep b/lib/libesp32/berry_matter/src/solidify/.keep new file mode 100644 index 000000000..e69de29bb diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Base38.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Base38.h new file mode 100644 index 000000000..2bef18e6f --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Base38.h @@ -0,0 +1,154 @@ +/* Solidification of Matter_Base38.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_Base38; + +/******************************************************************** +** Solidified function: encode +********************************************************************/ +be_local_closure(Matter_Base38_encode, /* name */ + be_nested_proto( + 10, /* nstack */ + 1, /* argc */ + 4, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 1, /* has sup protos */ + ( &(const struct bproto*[ 1]) { + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_X2D_X2E), + /* K2 */ be_const_int(0), + /* K3 */ be_nested_str_weak(), + /* K4 */ be_const_int(1), + }), + be_str_weak(b38_enc), + &be_const_str_solidified, + ( &(const binstruction[15]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0x580C0001, // 0001 LDCONST R3 K1 + 0x58100002, // 0002 LDCONST R4 K2 + 0x58140003, // 0003 LDCONST R5 K3 + 0x14180801, // 0004 LT R6 R4 R1 + 0x781A0007, // 0005 JMPF R6 #000E + 0x541A0025, // 0006 LDINT R6 38 + 0x10180006, // 0007 MOD R6 R0 R6 + 0x94180606, // 0008 GETIDX R6 R3 R6 + 0x00140A06, // 0009 ADD R5 R5 R6 + 0x541A0025, // 000A LDINT R6 38 + 0x0C000006, // 000B DIV R0 R0 R6 + 0x00100904, // 000C ADD R4 R4 K4 + 0x7001FFF5, // 000D JMP #0004 + 0x80040A00, // 000E RET 1 R5 + }) + ), + }), + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_const_class(be_class_Matter_Base38), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str_weak(), + /* K3 */ be_const_int(2), + /* K4 */ be_const_int(1), + /* K5 */ be_const_int(3), + }), + be_str_weak(encode), + &be_const_str_solidified, + ( &(const binstruction[58]) { /* code */ + 0x58040000, // 0000 LDCONST R1 K0 + 0x84080000, // 0001 CLOSURE R2 P0 + 0x580C0001, // 0002 LDCONST R3 K1 + 0x6010000C, // 0003 GETGBL R4 G12 + 0x5C140000, // 0004 MOVE R5 R0 + 0x7C100200, // 0005 CALL R4 1 + 0x58140002, // 0006 LDCONST R5 K2 + 0x14180604, // 0007 LT R6 R3 R4 + 0x781A002F, // 0008 JMPF R6 #0039 + 0x4C180000, // 0009 LDNIL R6 + 0x001C0703, // 000A ADD R7 R3 K3 + 0x141C0E04, // 000B LT R7 R7 R4 + 0x781E0012, // 000C JMPF R7 #0020 + 0x941C0003, // 000D GETIDX R7 R0 R3 + 0x00200704, // 000E ADD R8 R3 K4 + 0x94200008, // 000F GETIDX R8 R0 R8 + 0x54260007, // 0010 LDINT R9 8 + 0x38201009, // 0011 SHL R8 R8 R9 + 0x301C0E08, // 0012 OR R7 R7 R8 + 0x00200703, // 0013 ADD R8 R3 K3 + 0x94200008, // 0014 GETIDX R8 R0 R8 + 0x5426000F, // 0015 LDINT R9 16 + 0x38201009, // 0016 SHL R8 R8 R9 + 0x301C0E08, // 0017 OR R7 R7 R8 + 0x5C180E00, // 0018 MOVE R6 R7 + 0x5C1C0400, // 0019 MOVE R7 R2 + 0x5C200C00, // 001A MOVE R8 R6 + 0x54260004, // 001B LDINT R9 5 + 0x7C1C0400, // 001C CALL R7 2 + 0x00140A07, // 001D ADD R5 R5 R7 + 0x000C0705, // 001E ADD R3 R3 K5 + 0x70020017, // 001F JMP #0038 + 0x001C0704, // 0020 ADD R7 R3 K4 + 0x141C0E04, // 0021 LT R7 R7 R4 + 0x781E000D, // 0022 JMPF R7 #0031 + 0x941C0003, // 0023 GETIDX R7 R0 R3 + 0x00200704, // 0024 ADD R8 R3 K4 + 0x94200008, // 0025 GETIDX R8 R0 R8 + 0x54260007, // 0026 LDINT R9 8 + 0x38201009, // 0027 SHL R8 R8 R9 + 0x301C0E08, // 0028 OR R7 R7 R8 + 0x5C180E00, // 0029 MOVE R6 R7 + 0x5C1C0400, // 002A MOVE R7 R2 + 0x5C200C00, // 002B MOVE R8 R6 + 0x54260003, // 002C LDINT R9 4 + 0x7C1C0400, // 002D CALL R7 2 + 0x00140A07, // 002E ADD R5 R5 R7 + 0x000C0703, // 002F ADD R3 R3 K3 + 0x70020006, // 0030 JMP #0038 + 0x94180003, // 0031 GETIDX R6 R0 R3 + 0x5C1C0400, // 0032 MOVE R7 R2 + 0x5C200C00, // 0033 MOVE R8 R6 + 0x58240003, // 0034 LDCONST R9 K3 + 0x7C1C0400, // 0035 CALL R7 2 + 0x00140A07, // 0036 ADD R5 R5 R7 + 0x000C0704, // 0037 ADD R3 R3 K4 + 0x7001FFCD, // 0038 JMP #0007 + 0x80040A00, // 0039 RET 1 R5 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_Base38 +********************************************************************/ +be_local_class(Matter_Base38, + 0, + NULL, + be_nested_map(1, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(encode, -1), be_const_static_closure(Matter_Base38_encode_closure) }, + })), + be_str_weak(Matter_Base38) +); +/*******************************************************************/ + +void be_load_Matter_Base38_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Base38); + be_setglobal(vm, "Matter_Base38"); + be_pop(vm, 1); +} +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Commissioning.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Commissioning.h new file mode 100644 index 000000000..4f922fc06 --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Commissioning.h @@ -0,0 +1,2430 @@ +/* Solidification of Matter_Commissioning.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_Commisioning_Context; + +/******************************************************************** +** Solidified function: parse_PBKDFParamRequest +********************************************************************/ +be_local_closure(Matter_Commisioning_Context_parse_PBKDFParamRequest, /* name */ + be_nested_proto( + 16, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[46]) { /* constants */ + /* K0 */ be_nested_str_weak(crypto), + /* K1 */ be_nested_str_weak(opcode), + /* K2 */ be_nested_str_weak(local_session_id), + /* K3 */ be_const_int(0), + /* K4 */ be_nested_str_weak(protocol_id), + /* K5 */ be_nested_str_weak(protocol_error), + /* K6 */ be_nested_str_weak(invalid_X20PBKDFParamRequest_X20message), + /* K7 */ be_nested_str_weak(matter), + /* K8 */ be_nested_str_weak(PBKDFParamRequest), + /* K9 */ be_nested_str_weak(parse), + /* K10 */ be_nested_str_weak(raw), + /* K11 */ be_nested_str_weak(app_payload_idx), + /* K12 */ be_nested_str_weak(session), + /* K13 */ be_nested_str_weak(set_mode), + /* K14 */ be_nested_str_weak(Session), + /* K15 */ be_nested_str_weak(__PASE), + /* K16 */ be_const_int(2147483647), + /* K17 */ be_nested_str_weak(passcodeId), + /* K18 */ be_nested_str_weak(non_X2Dzero_X20passcode_X20id), + /* K19 */ be_nested_str_weak(future_initiator_session_id), + /* K20 */ be_nested_str_weak(initiator_session_id), + /* K21 */ be_nested_str_weak(future_local_session_id), + /* K22 */ be_nested_str_weak(device), + /* K23 */ be_nested_str_weak(sessions), + /* K24 */ be_nested_str_weak(gen_local_session_id), + /* K25 */ be_nested_str_weak(PBKDFParamResponse), + /* K26 */ be_nested_str_weak(initiatorRandom), + /* K27 */ be_nested_str_weak(responderRandom), + /* K28 */ be_nested_str_weak(random), + /* K29 */ be_nested_str_weak(responderSessionId), + /* K30 */ be_nested_str_weak(pbkdf_parameters_salt), + /* K31 */ be_nested_str_weak(salt), + /* K32 */ be_nested_str_weak(pbkdf_parameters_iterations), + /* K33 */ be_nested_str_weak(iterations), + /* K34 */ be_nested_str_weak(tasmota), + /* K35 */ be_nested_str_weak(log), + /* K36 */ be_nested_str_weak(MTR_X3A_X20pbkdfparamresp_X3A_X20), + /* K37 */ be_nested_str_weak(inspect), + /* K38 */ be_const_int(3), + /* K39 */ be_nested_str_weak(encode), + /* K40 */ be_nested_str_weak(MTR_X3A_X20pbkdfparamresp_raw_X3A_X20), + /* K41 */ be_nested_str_weak(tohex), + /* K42 */ be_nested_str_weak(build_response), + /* K43 */ be_nested_str_weak(responder), + /* K44 */ be_nested_str_weak(send_response), + /* K45 */ be_nested_str_weak(message_counter), + }), + be_str_weak(parse_PBKDFParamRequest), + &be_const_str_solidified, + ( &(const binstruction[94]) { /* code */ + 0xA4120000, // 0000 IMPORT R4 K0 + 0x88140301, // 0001 GETMBR R5 R1 K1 + 0x541A001F, // 0002 LDINT R6 32 + 0x20140A06, // 0003 NE R5 R5 R6 + 0x74160005, // 0004 JMPT R5 #000B + 0x88140302, // 0005 GETMBR R5 R1 K2 + 0x20140B03, // 0006 NE R5 R5 K3 + 0x74160002, // 0007 JMPT R5 #000B + 0x88140304, // 0008 GETMBR R5 R1 K4 + 0x20140B03, // 0009 NE R5 R5 K3 + 0x78160000, // 000A JMPF R5 #000C + 0xB0060B06, // 000B RAISE 1 K5 K6 + 0xB8160E00, // 000C GETNGBL R5 K7 + 0x8C140B08, // 000D GETMET R5 R5 K8 + 0x7C140200, // 000E CALL R5 1 + 0x8C140B09, // 000F GETMET R5 R5 K9 + 0x881C030A, // 0010 GETMBR R7 R1 K10 + 0x8820030B, // 0011 GETMBR R8 R1 K11 + 0x7C140600, // 0012 CALL R5 3 + 0x8818030C, // 0013 GETMBR R6 R1 K12 + 0x8C180D0D, // 0014 GETMET R6 R6 K13 + 0xB8220E00, // 0015 GETNGBL R8 K7 + 0x8820110E, // 0016 GETMBR R8 R8 K14 + 0x8820110F, // 0017 GETMBR R8 R8 K15 + 0x7C180400, // 0018 CALL R6 2 + 0x8818030B, // 0019 GETMBR R6 R1 K11 + 0x40180D10, // 001A CONNECT R6 R6 K16 + 0x881C030A, // 001B GETMBR R7 R1 K10 + 0x94180E06, // 001C GETIDX R6 R7 R6 + 0x90021006, // 001D SETMBR R0 K8 R6 + 0x88180B11, // 001E GETMBR R6 R5 K17 + 0x20180D03, // 001F NE R6 R6 K3 + 0x781A0000, // 0020 JMPF R6 #0022 + 0xB0060B12, // 0021 RAISE 1 K5 K18 + 0x88180B14, // 0022 GETMBR R6 R5 K20 + 0x90022606, // 0023 SETMBR R0 K19 R6 + 0x88180116, // 0024 GETMBR R6 R0 K22 + 0x88180D17, // 0025 GETMBR R6 R6 K23 + 0x8C180D18, // 0026 GETMET R6 R6 K24 + 0x7C180200, // 0027 CALL R6 1 + 0x90022A06, // 0028 SETMBR R0 K21 R6 + 0xB81A0E00, // 0029 GETNGBL R6 K7 + 0x8C180D19, // 002A GETMET R6 R6 K25 + 0x7C180200, // 002B CALL R6 1 + 0x881C0B1A, // 002C GETMBR R7 R5 K26 + 0x901A3407, // 002D SETMBR R6 K26 R7 + 0x8C1C091C, // 002E GETMET R7 R4 K28 + 0x5426001F, // 002F LDINT R9 32 + 0x7C1C0400, // 0030 CALL R7 2 + 0x901A3607, // 0031 SETMBR R6 K27 R7 + 0x881C0115, // 0032 GETMBR R7 R0 K21 + 0x901A3A07, // 0033 SETMBR R6 K29 R7 + 0x881C0116, // 0034 GETMBR R7 R0 K22 + 0x881C0F1F, // 0035 GETMBR R7 R7 K31 + 0x901A3C07, // 0036 SETMBR R6 K30 R7 + 0x881C0116, // 0037 GETMBR R7 R0 K22 + 0x881C0F21, // 0038 GETMBR R7 R7 K33 + 0x901A4007, // 0039 SETMBR R6 K32 R7 + 0xB81E4400, // 003A GETNGBL R7 K34 + 0x8C1C0F23, // 003B GETMET R7 R7 K35 + 0x60240008, // 003C GETGBL R9 G8 + 0xB82A0E00, // 003D GETNGBL R10 K7 + 0x8C281525, // 003E GETMET R10 R10 K37 + 0x5C300C00, // 003F MOVE R12 R6 + 0x7C280400, // 0040 CALL R10 2 + 0x7C240200, // 0041 CALL R9 1 + 0x00264809, // 0042 ADD R9 K36 R9 + 0x58280026, // 0043 LDCONST R10 K38 + 0x7C1C0600, // 0044 CALL R7 3 + 0x8C1C0D27, // 0045 GETMET R7 R6 K39 + 0x7C1C0200, // 0046 CALL R7 1 + 0xB8224400, // 0047 GETNGBL R8 K34 + 0x8C201123, // 0048 GETMET R8 R8 K35 + 0x8C280F29, // 0049 GETMET R10 R7 K41 + 0x7C280200, // 004A CALL R10 1 + 0x002A500A, // 004B ADD R10 K40 R10 + 0x582C0026, // 004C LDCONST R11 K38 + 0x7C200600, // 004D CALL R8 3 + 0x90023207, // 004E SETMBR R0 K25 R7 + 0x8C20032A, // 004F GETMET R8 R1 K42 + 0x542A0020, // 0050 LDINT R10 33 + 0x502C0200, // 0051 LDBOOL R11 1 0 + 0x7C200600, // 0052 CALL R8 3 + 0x8C241127, // 0053 GETMET R9 R8 K39 + 0x5C2C0E00, // 0054 MOVE R11 R7 + 0x7C240400, // 0055 CALL R9 2 + 0x8828012B, // 0056 GETMBR R10 R0 K43 + 0x8C28152C, // 0057 GETMET R10 R10 K44 + 0x5C301200, // 0058 MOVE R12 R9 + 0x5C340400, // 0059 MOVE R13 R2 + 0x5C380600, // 005A MOVE R14 R3 + 0x883C112D, // 005B GETMBR R15 R8 K45 + 0x7C280A00, // 005C CALL R10 5 + 0x80000000, // 005D RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_Commisioning_Context_init, /* name */ + be_nested_proto( + 6, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(crypto), + /* K1 */ be_nested_str_weak(responder), + /* K2 */ be_nested_str_weak(device), + /* K3 */ be_nested_str_weak(y), + /* K4 */ be_nested_str_weak(random), + /* K5 */ be_nested_str_weak(window_open), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[11]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0x90020201, // 0001 SETMBR R0 K1 R1 + 0x880C0302, // 0002 GETMBR R3 R1 K2 + 0x90020403, // 0003 SETMBR R0 K2 R3 + 0x8C0C0504, // 0004 GETMET R3 R2 K4 + 0x5416001F, // 0005 LDINT R5 32 + 0x7C0C0400, // 0006 CALL R3 2 + 0x90020603, // 0007 SETMBR R0 K3 R3 + 0x500C0200, // 0008 LDBOOL R3 1 0 + 0x90020A03, // 0009 SETMBR R0 K5 R3 + 0x80000000, // 000A RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: parse_Pake1 +********************************************************************/ +be_local_closure(Matter_Commisioning_Context_parse_Pake1, /* name */ + be_nested_proto( + 18, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[82]) { /* constants */ + /* K0 */ be_nested_str_weak(crypto), + /* K1 */ be_nested_str_weak(opcode), + /* K2 */ be_nested_str_weak(local_session_id), + /* K3 */ be_const_int(0), + /* K4 */ be_nested_str_weak(protocol_id), + /* K5 */ be_nested_str_weak(protocol_error), + /* K6 */ be_nested_str_weak(invalid_X20Pake1_X20message), + /* K7 */ be_nested_str_weak(matter), + /* K8 */ be_nested_str_weak(Pake1), + /* K9 */ be_nested_str_weak(parse), + /* K10 */ be_nested_str_weak(raw), + /* K11 */ be_nested_str_weak(app_payload_idx), + /* K12 */ be_nested_str_weak(pA), + /* K13 */ be_nested_str_weak(tasmota), + /* K14 */ be_nested_str_weak(log), + /* K15 */ be_nested_str_weak(MTR_X3A_X20received_X20pA_X3D), + /* K16 */ be_nested_str_weak(tohex), + /* K17 */ be_const_int(3), + /* K18 */ be_nested_str_weak(MTR_X3A_X20spake_X3A_X20), + /* K19 */ be_nested_str_weak(inspect), + /* K20 */ be_nested_str_weak(spake), + /* K21 */ be_nested_str_weak(SPAKE2P_Matter), + /* K22 */ be_nested_str_weak(device), + /* K23 */ be_nested_str_weak(w0), + /* K24 */ be_nested_str_weak(w1), + /* K25 */ be_nested_str_weak(L), + /* K26 */ be_nested_str_weak(compute_pB), + /* K27 */ be_nested_str_weak(y), + /* K28 */ be_nested_str_weak(pB), + /* K29 */ be_nested_str_weak(MTR_X3A_X20y_X3D), + /* K30 */ be_nested_str_weak(MTR_X3A_X20pb_X3D), + /* K31 */ be_nested_str_weak(compute_ZV_verifier), + /* K32 */ be_nested_str_weak(MTR_X3A_X20Z_X3D), + /* K33 */ be_nested_str_weak(Z), + /* K34 */ be_nested_str_weak(MTR_X3A_X20V_X3D), + /* K35 */ be_nested_str_weak(V), + /* K36 */ be_nested_str_weak(SHA256), + /* K37 */ be_nested_str_weak(update), + /* K38 */ be_nested_str_weak(fromstring), + /* K39 */ be_nested_str_weak(Matter_Context_Prefix), + /* K40 */ be_nested_str_weak(PBKDFParamRequest), + /* K41 */ be_nested_str_weak(PBKDFParamResponse), + /* K42 */ be_nested_str_weak(out), + /* K43 */ be_nested_str_weak(MTR_X3A_X20Context_X3D), + /* K44 */ be_nested_str_weak(set_context), + /* K45 */ be_nested_str_weak(compute_TT_hash), + /* K46 */ be_nested_str_weak(MTR_X3A_X20_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D), + /* K47 */ be_nested_str_weak(MTR_X3A_X20Context_X20_X3D_X20), + /* K48 */ be_nested_str_weak(Context), + /* K49 */ be_nested_str_weak(MTR_X3A_X20A_X20_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K50 */ be_nested_str_weak(A), + /* K51 */ be_nested_str_weak(MTR_X3A_X20B_X20_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K52 */ be_nested_str_weak(B), + /* K53 */ be_nested_str_weak(MTR_X3A_X20M_X20_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K54 */ be_nested_str_weak(M), + /* K55 */ be_nested_str_weak(MTR_X3A_X20N_X20_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K56 */ be_nested_str_weak(N), + /* K57 */ be_nested_str_weak(MTR_X3A_X20pA_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K58 */ be_nested_str_weak(MTR_X3A_X20pB_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K59 */ be_nested_str_weak(MTR_X3A_X20Z_X20_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K60 */ be_nested_str_weak(MTR_X3A_X20V_X20_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K61 */ be_nested_str_weak(MTR_X3A_X20w0_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K62 */ be_nested_str_weak(MTR_X3A_X20Kmain_X20_X20_X20_X3D), + /* K63 */ be_nested_str_weak(Kmain), + /* K64 */ be_nested_str_weak(MTR_X3A_X20KcA_X20_X20_X20_X20_X20_X3D), + /* K65 */ be_nested_str_weak(KcA), + /* K66 */ be_nested_str_weak(MTR_X3A_X20KcB_X20_X20_X20_X20_X20_X3D), + /* K67 */ be_nested_str_weak(KcB), + /* K68 */ be_nested_str_weak(MTR_X3A_X20K_shared_X3D), + /* K69 */ be_nested_str_weak(K_shared), + /* K70 */ be_nested_str_weak(MTR_X3A_X20Ke_X20_X20_X20_X20_X20_X20_X3D), + /* K71 */ be_nested_str_weak(Ke), + /* K72 */ be_nested_str_weak(cB), + /* K73 */ be_nested_str_weak(MTR_X3A_X20cB_X3D), + /* K74 */ be_nested_str_weak(Pake2), + /* K75 */ be_nested_str_weak(MTR_X3A_X20pake2_X3A_X20), + /* K76 */ be_nested_str_weak(encode), + /* K77 */ be_nested_str_weak(MTR_X3A_X20pake2_raw_X3A_X20), + /* K78 */ be_nested_str_weak(build_response), + /* K79 */ be_nested_str_weak(responder), + /* K80 */ be_nested_str_weak(send_response), + /* K81 */ be_nested_str_weak(message_counter), + }), + be_str_weak(parse_Pake1), + &be_const_str_solidified, + ( &(const binstruction[326]) { /* code */ + 0xA4120000, // 0000 IMPORT R4 K0 + 0x88140301, // 0001 GETMBR R5 R1 K1 + 0x541A0021, // 0002 LDINT R6 34 + 0x20140A06, // 0003 NE R5 R5 R6 + 0x74160005, // 0004 JMPT R5 #000B + 0x88140302, // 0005 GETMBR R5 R1 K2 + 0x20140B03, // 0006 NE R5 R5 K3 + 0x74160002, // 0007 JMPT R5 #000B + 0x88140304, // 0008 GETMBR R5 R1 K4 + 0x20140B03, // 0009 NE R5 R5 K3 + 0x78160000, // 000A JMPF R5 #000C + 0xB0060B06, // 000B RAISE 1 K5 K6 + 0xB8160E00, // 000C GETNGBL R5 K7 + 0x8C140B08, // 000D GETMET R5 R5 K8 + 0x7C140200, // 000E CALL R5 1 + 0x8C140B09, // 000F GETMET R5 R5 K9 + 0x881C030A, // 0010 GETMBR R7 R1 K10 + 0x8820030B, // 0011 GETMBR R8 R1 K11 + 0x7C140600, // 0012 CALL R5 3 + 0x88180B0C, // 0013 GETMBR R6 R5 K12 + 0x90021806, // 0014 SETMBR R0 K12 R6 + 0xB81A1A00, // 0015 GETNGBL R6 K13 + 0x8C180D0E, // 0016 GETMET R6 R6 K14 + 0x8820010C, // 0017 GETMBR R8 R0 K12 + 0x8C201110, // 0018 GETMET R8 R8 K16 + 0x7C200200, // 0019 CALL R8 1 + 0x00221E08, // 001A ADD R8 K15 R8 + 0x58240011, // 001B LDCONST R9 K17 + 0x7C180600, // 001C CALL R6 3 + 0xB81A1A00, // 001D GETNGBL R6 K13 + 0x8C180D0E, // 001E GETMET R6 R6 K14 + 0xB8220E00, // 001F GETNGBL R8 K7 + 0x8C201113, // 0020 GETMET R8 R8 K19 + 0x88280114, // 0021 GETMBR R10 R0 K20 + 0x7C200400, // 0022 CALL R8 2 + 0x00222408, // 0023 ADD R8 K18 R8 + 0x58240011, // 0024 LDCONST R9 K17 + 0x7C180600, // 0025 CALL R6 3 + 0x8C180915, // 0026 GETMET R6 R4 K21 + 0x88200116, // 0027 GETMBR R8 R0 K22 + 0x88201117, // 0028 GETMBR R8 R8 K23 + 0x88240116, // 0029 GETMBR R9 R0 K22 + 0x88241318, // 002A GETMBR R9 R9 K24 + 0x88280116, // 002B GETMBR R10 R0 K22 + 0x88281519, // 002C GETMBR R10 R10 K25 + 0x7C180800, // 002D CALL R6 4 + 0x90022806, // 002E SETMBR R0 K20 R6 + 0x88180114, // 002F GETMBR R6 R0 K20 + 0x8C180D1A, // 0030 GETMET R6 R6 K26 + 0x8820011B, // 0031 GETMBR R8 R0 K27 + 0x7C180400, // 0032 CALL R6 2 + 0x88180114, // 0033 GETMBR R6 R0 K20 + 0x88180D1C, // 0034 GETMBR R6 R6 K28 + 0x90023806, // 0035 SETMBR R0 K28 R6 + 0xB81A1A00, // 0036 GETNGBL R6 K13 + 0x8C180D0E, // 0037 GETMET R6 R6 K14 + 0x8820011B, // 0038 GETMBR R8 R0 K27 + 0x8C201110, // 0039 GETMET R8 R8 K16 + 0x7C200200, // 003A CALL R8 1 + 0x00223A08, // 003B ADD R8 K29 R8 + 0x58240011, // 003C LDCONST R9 K17 + 0x7C180600, // 003D CALL R6 3 + 0xB81A1A00, // 003E GETNGBL R6 K13 + 0x8C180D0E, // 003F GETMET R6 R6 K14 + 0x8820011C, // 0040 GETMBR R8 R0 K28 + 0x8C201110, // 0041 GETMET R8 R8 K16 + 0x7C200200, // 0042 CALL R8 1 + 0x00223C08, // 0043 ADD R8 K30 R8 + 0x58240011, // 0044 LDCONST R9 K17 + 0x7C180600, // 0045 CALL R6 3 + 0x88180114, // 0046 GETMBR R6 R0 K20 + 0x8C180D1F, // 0047 GETMET R6 R6 K31 + 0x8820010C, // 0048 GETMBR R8 R0 K12 + 0x7C180400, // 0049 CALL R6 2 + 0xB81A1A00, // 004A GETNGBL R6 K13 + 0x8C180D0E, // 004B GETMET R6 R6 K14 + 0x88200114, // 004C GETMBR R8 R0 K20 + 0x88201121, // 004D GETMBR R8 R8 K33 + 0x8C201110, // 004E GETMET R8 R8 K16 + 0x7C200200, // 004F CALL R8 1 + 0x00224008, // 0050 ADD R8 K32 R8 + 0x58240011, // 0051 LDCONST R9 K17 + 0x7C180600, // 0052 CALL R6 3 + 0xB81A1A00, // 0053 GETNGBL R6 K13 + 0x8C180D0E, // 0054 GETMET R6 R6 K14 + 0x88200114, // 0055 GETMBR R8 R0 K20 + 0x88201123, // 0056 GETMBR R8 R8 K35 + 0x8C201110, // 0057 GETMET R8 R8 K16 + 0x7C200200, // 0058 CALL R8 1 + 0x00224408, // 0059 ADD R8 K34 R8 + 0x58240011, // 005A LDCONST R9 K17 + 0x7C180600, // 005B CALL R6 3 + 0x8C180924, // 005C GETMET R6 R4 K36 + 0x7C180200, // 005D CALL R6 1 + 0x8C1C0D25, // 005E GETMET R7 R6 K37 + 0x60240015, // 005F GETGBL R9 G21 + 0x7C240000, // 0060 CALL R9 0 + 0x8C241326, // 0061 GETMET R9 R9 K38 + 0x882C0127, // 0062 GETMBR R11 R0 K39 + 0x7C240400, // 0063 CALL R9 2 + 0x7C1C0400, // 0064 CALL R7 2 + 0x8C1C0D25, // 0065 GETMET R7 R6 K37 + 0x88240128, // 0066 GETMBR R9 R0 K40 + 0x7C1C0400, // 0067 CALL R7 2 + 0x8C1C0D25, // 0068 GETMET R7 R6 K37 + 0x88240129, // 0069 GETMBR R9 R0 K41 + 0x7C1C0400, // 006A CALL R7 2 + 0x8C1C0D2A, // 006B GETMET R7 R6 K42 + 0x7C1C0200, // 006C CALL R7 1 + 0xB8221A00, // 006D GETNGBL R8 K13 + 0x8C20110E, // 006E GETMET R8 R8 K14 + 0x8C280F10, // 006F GETMET R10 R7 K16 + 0x7C280200, // 0070 CALL R10 1 + 0x002A560A, // 0071 ADD R10 K43 R10 + 0x582C0011, // 0072 LDCONST R11 K17 + 0x7C200600, // 0073 CALL R8 3 + 0x88200114, // 0074 GETMBR R8 R0 K20 + 0x8824010C, // 0075 GETMBR R9 R0 K12 + 0x90221809, // 0076 SETMBR R8 K12 R9 + 0x88200114, // 0077 GETMBR R8 R0 K20 + 0x8C20112C, // 0078 GETMET R8 R8 K44 + 0x5C280E00, // 0079 MOVE R10 R7 + 0x7C200400, // 007A CALL R8 2 + 0x88200114, // 007B GETMBR R8 R0 K20 + 0x8C20112D, // 007C GETMET R8 R8 K45 + 0x50280200, // 007D LDBOOL R10 1 0 + 0x7C200400, // 007E CALL R8 2 + 0xB8221A00, // 007F GETNGBL R8 K13 + 0x8C20110E, // 0080 GETMET R8 R8 K14 + 0x5828002E, // 0081 LDCONST R10 K46 + 0x582C0011, // 0082 LDCONST R11 K17 + 0x7C200600, // 0083 CALL R8 3 + 0xB8221A00, // 0084 GETNGBL R8 K13 + 0x8C20110E, // 0085 GETMET R8 R8 K14 + 0x88280114, // 0086 GETMBR R10 R0 K20 + 0x88281530, // 0087 GETMBR R10 R10 K48 + 0x8C281510, // 0088 GETMET R10 R10 K16 + 0x7C280200, // 0089 CALL R10 1 + 0x002A5E0A, // 008A ADD R10 K47 R10 + 0x582C0011, // 008B LDCONST R11 K17 + 0x7C200600, // 008C CALL R8 3 + 0xB8221A00, // 008D GETNGBL R8 K13 + 0x8C20110E, // 008E GETMET R8 R8 K14 + 0x88280114, // 008F GETMBR R10 R0 K20 + 0x88281532, // 0090 GETMBR R10 R10 K50 + 0x8C281510, // 0091 GETMET R10 R10 K16 + 0x7C280200, // 0092 CALL R10 1 + 0x002A620A, // 0093 ADD R10 K49 R10 + 0x582C0011, // 0094 LDCONST R11 K17 + 0x7C200600, // 0095 CALL R8 3 + 0xB8221A00, // 0096 GETNGBL R8 K13 + 0x8C20110E, // 0097 GETMET R8 R8 K14 + 0x88280114, // 0098 GETMBR R10 R0 K20 + 0x88281534, // 0099 GETMBR R10 R10 K52 + 0x8C281510, // 009A GETMET R10 R10 K16 + 0x7C280200, // 009B CALL R10 1 + 0x002A660A, // 009C ADD R10 K51 R10 + 0x582C0011, // 009D LDCONST R11 K17 + 0x7C200600, // 009E CALL R8 3 + 0xB8221A00, // 009F GETNGBL R8 K13 + 0x8C20110E, // 00A0 GETMET R8 R8 K14 + 0x88280114, // 00A1 GETMBR R10 R0 K20 + 0x88281536, // 00A2 GETMBR R10 R10 K54 + 0x8C281510, // 00A3 GETMET R10 R10 K16 + 0x7C280200, // 00A4 CALL R10 1 + 0x002A6A0A, // 00A5 ADD R10 K53 R10 + 0x582C0011, // 00A6 LDCONST R11 K17 + 0x7C200600, // 00A7 CALL R8 3 + 0xB8221A00, // 00A8 GETNGBL R8 K13 + 0x8C20110E, // 00A9 GETMET R8 R8 K14 + 0x88280114, // 00AA GETMBR R10 R0 K20 + 0x88281538, // 00AB GETMBR R10 R10 K56 + 0x8C281510, // 00AC GETMET R10 R10 K16 + 0x7C280200, // 00AD CALL R10 1 + 0x002A6E0A, // 00AE ADD R10 K55 R10 + 0x582C0011, // 00AF LDCONST R11 K17 + 0x7C200600, // 00B0 CALL R8 3 + 0xB8221A00, // 00B1 GETNGBL R8 K13 + 0x8C20110E, // 00B2 GETMET R8 R8 K14 + 0x88280114, // 00B3 GETMBR R10 R0 K20 + 0x8828150C, // 00B4 GETMBR R10 R10 K12 + 0x8C281510, // 00B5 GETMET R10 R10 K16 + 0x7C280200, // 00B6 CALL R10 1 + 0x002A720A, // 00B7 ADD R10 K57 R10 + 0x582C0011, // 00B8 LDCONST R11 K17 + 0x7C200600, // 00B9 CALL R8 3 + 0xB8221A00, // 00BA GETNGBL R8 K13 + 0x8C20110E, // 00BB GETMET R8 R8 K14 + 0x88280114, // 00BC GETMBR R10 R0 K20 + 0x8828151C, // 00BD GETMBR R10 R10 K28 + 0x8C281510, // 00BE GETMET R10 R10 K16 + 0x7C280200, // 00BF CALL R10 1 + 0x002A740A, // 00C0 ADD R10 K58 R10 + 0x582C0011, // 00C1 LDCONST R11 K17 + 0x7C200600, // 00C2 CALL R8 3 + 0xB8221A00, // 00C3 GETNGBL R8 K13 + 0x8C20110E, // 00C4 GETMET R8 R8 K14 + 0x88280114, // 00C5 GETMBR R10 R0 K20 + 0x88281521, // 00C6 GETMBR R10 R10 K33 + 0x8C281510, // 00C7 GETMET R10 R10 K16 + 0x7C280200, // 00C8 CALL R10 1 + 0x002A760A, // 00C9 ADD R10 K59 R10 + 0x582C0011, // 00CA LDCONST R11 K17 + 0x7C200600, // 00CB CALL R8 3 + 0xB8221A00, // 00CC GETNGBL R8 K13 + 0x8C20110E, // 00CD GETMET R8 R8 K14 + 0x88280114, // 00CE GETMBR R10 R0 K20 + 0x88281523, // 00CF GETMBR R10 R10 K35 + 0x8C281510, // 00D0 GETMET R10 R10 K16 + 0x7C280200, // 00D1 CALL R10 1 + 0x002A780A, // 00D2 ADD R10 K60 R10 + 0x582C0011, // 00D3 LDCONST R11 K17 + 0x7C200600, // 00D4 CALL R8 3 + 0xB8221A00, // 00D5 GETNGBL R8 K13 + 0x8C20110E, // 00D6 GETMET R8 R8 K14 + 0x88280114, // 00D7 GETMBR R10 R0 K20 + 0x88281517, // 00D8 GETMBR R10 R10 K23 + 0x8C281510, // 00D9 GETMET R10 R10 K16 + 0x7C280200, // 00DA CALL R10 1 + 0x002A7A0A, // 00DB ADD R10 K61 R10 + 0x582C0011, // 00DC LDCONST R11 K17 + 0x7C200600, // 00DD CALL R8 3 + 0xB8221A00, // 00DE GETNGBL R8 K13 + 0x8C20110E, // 00DF GETMET R8 R8 K14 + 0x5828002E, // 00E0 LDCONST R10 K46 + 0x582C0011, // 00E1 LDCONST R11 K17 + 0x7C200600, // 00E2 CALL R8 3 + 0xB8221A00, // 00E3 GETNGBL R8 K13 + 0x8C20110E, // 00E4 GETMET R8 R8 K14 + 0x88280114, // 00E5 GETMBR R10 R0 K20 + 0x8828153F, // 00E6 GETMBR R10 R10 K63 + 0x8C281510, // 00E7 GETMET R10 R10 K16 + 0x7C280200, // 00E8 CALL R10 1 + 0x002A7C0A, // 00E9 ADD R10 K62 R10 + 0x582C0011, // 00EA LDCONST R11 K17 + 0x7C200600, // 00EB CALL R8 3 + 0xB8221A00, // 00EC GETNGBL R8 K13 + 0x8C20110E, // 00ED GETMET R8 R8 K14 + 0x88280114, // 00EE GETMBR R10 R0 K20 + 0x88281541, // 00EF GETMBR R10 R10 K65 + 0x8C281510, // 00F0 GETMET R10 R10 K16 + 0x7C280200, // 00F1 CALL R10 1 + 0x002A800A, // 00F2 ADD R10 K64 R10 + 0x582C0011, // 00F3 LDCONST R11 K17 + 0x7C200600, // 00F4 CALL R8 3 + 0xB8221A00, // 00F5 GETNGBL R8 K13 + 0x8C20110E, // 00F6 GETMET R8 R8 K14 + 0x88280114, // 00F7 GETMBR R10 R0 K20 + 0x88281543, // 00F8 GETMBR R10 R10 K67 + 0x8C281510, // 00F9 GETMET R10 R10 K16 + 0x7C280200, // 00FA CALL R10 1 + 0x002A840A, // 00FB ADD R10 K66 R10 + 0x582C0011, // 00FC LDCONST R11 K17 + 0x7C200600, // 00FD CALL R8 3 + 0xB8221A00, // 00FE GETNGBL R8 K13 + 0x8C20110E, // 00FF GETMET R8 R8 K14 + 0x88280114, // 0100 GETMBR R10 R0 K20 + 0x88281545, // 0101 GETMBR R10 R10 K69 + 0x8C281510, // 0102 GETMET R10 R10 K16 + 0x7C280200, // 0103 CALL R10 1 + 0x002A880A, // 0104 ADD R10 K68 R10 + 0x582C0011, // 0105 LDCONST R11 K17 + 0x7C200600, // 0106 CALL R8 3 + 0xB8221A00, // 0107 GETNGBL R8 K13 + 0x8C20110E, // 0108 GETMET R8 R8 K14 + 0x88280114, // 0109 GETMBR R10 R0 K20 + 0x88281547, // 010A GETMBR R10 R10 K71 + 0x8C281510, // 010B GETMET R10 R10 K16 + 0x7C280200, // 010C CALL R10 1 + 0x002A8C0A, // 010D ADD R10 K70 R10 + 0x582C0011, // 010E LDCONST R11 K17 + 0x7C200600, // 010F CALL R8 3 + 0x88200114, // 0110 GETMBR R8 R0 K20 + 0x88201148, // 0111 GETMBR R8 R8 K72 + 0x90029008, // 0112 SETMBR R0 K72 R8 + 0x88200114, // 0113 GETMBR R8 R0 K20 + 0x88201147, // 0114 GETMBR R8 R8 K71 + 0x90028E08, // 0115 SETMBR R0 K71 R8 + 0xB8221A00, // 0116 GETNGBL R8 K13 + 0x8C20110E, // 0117 GETMET R8 R8 K14 + 0x88280148, // 0118 GETMBR R10 R0 K72 + 0x8C281510, // 0119 GETMET R10 R10 K16 + 0x7C280200, // 011A CALL R10 1 + 0x002A920A, // 011B ADD R10 K73 R10 + 0x582C0011, // 011C LDCONST R11 K17 + 0x7C200600, // 011D CALL R8 3 + 0xB8220E00, // 011E GETNGBL R8 K7 + 0x8C20114A, // 011F GETMET R8 R8 K74 + 0x7C200200, // 0120 CALL R8 1 + 0x8824011C, // 0121 GETMBR R9 R0 K28 + 0x90223809, // 0122 SETMBR R8 K28 R9 + 0x88240148, // 0123 GETMBR R9 R0 K72 + 0x90229009, // 0124 SETMBR R8 K72 R9 + 0xB8261A00, // 0125 GETNGBL R9 K13 + 0x8C24130E, // 0126 GETMET R9 R9 K14 + 0xB82E0E00, // 0127 GETNGBL R11 K7 + 0x8C2C1713, // 0128 GETMET R11 R11 K19 + 0x5C341000, // 0129 MOVE R13 R8 + 0x7C2C0400, // 012A CALL R11 2 + 0x002E960B, // 012B ADD R11 K75 R11 + 0x58300011, // 012C LDCONST R12 K17 + 0x7C240600, // 012D CALL R9 3 + 0x8C24114C, // 012E GETMET R9 R8 K76 + 0x7C240200, // 012F CALL R9 1 + 0xB82A1A00, // 0130 GETNGBL R10 K13 + 0x8C28150E, // 0131 GETMET R10 R10 K14 + 0x8C301310, // 0132 GETMET R12 R9 K16 + 0x7C300200, // 0133 CALL R12 1 + 0x00329A0C, // 0134 ADD R12 K77 R12 + 0x58340011, // 0135 LDCONST R13 K17 + 0x7C280600, // 0136 CALL R10 3 + 0x8C28034E, // 0137 GETMET R10 R1 K78 + 0x54320022, // 0138 LDINT R12 35 + 0x50340200, // 0139 LDBOOL R13 1 0 + 0x7C280600, // 013A CALL R10 3 + 0x8C2C154C, // 013B GETMET R11 R10 K76 + 0x5C341200, // 013C MOVE R13 R9 + 0x7C2C0400, // 013D CALL R11 2 + 0x8830014F, // 013E GETMBR R12 R0 K79 + 0x8C301950, // 013F GETMET R12 R12 K80 + 0x5C381600, // 0140 MOVE R14 R11 + 0x5C3C0400, // 0141 MOVE R15 R2 + 0x5C400600, // 0142 MOVE R16 R3 + 0x88441551, // 0143 GETMBR R17 R10 K81 + 0x7C300A00, // 0144 CALL R12 5 + 0x80000000, // 0145 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: find_session_by_destination_id +********************************************************************/ +be_local_closure(Matter_Commisioning_Context_find_session_by_destination_id, /* name */ + be_nested_proto( + 14, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[22]) { /* constants */ + /* K0 */ be_nested_str_weak(crypto), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(log), + /* K3 */ be_nested_str_weak(MTR_X3A_X20SEARCHING_X3A_X20destinationId_X3D), + /* K4 */ be_nested_str_weak(tohex), + /* K5 */ be_const_int(3), + /* K6 */ be_nested_str_weak(device), + /* K7 */ be_nested_str_weak(sessions), + /* K8 */ be_nested_str_weak(noc), + /* K9 */ be_nested_str_weak(fabric), + /* K10 */ be_nested_str_weak(deviceid), + /* K11 */ be_nested_str_weak(get_ca_pub), + /* K12 */ be_nested_str_weak(get_fabric), + /* K13 */ be_nested_str_weak(get_deviceid), + /* K14 */ be_nested_str_weak(get_ipk_group_key), + /* K15 */ be_nested_str_weak(MTR_X3A_X20SIGMA1_X3A_X20destinationMessage_X3D), + /* K16 */ be_nested_str_weak(MTR_X3A_X20SIGMA1_X3A_X20key_ipk_X3D), + /* K17 */ be_nested_str_weak(HMAC_SHA256), + /* K18 */ be_nested_str_weak(update), + /* K19 */ be_nested_str_weak(out), + /* K20 */ be_nested_str_weak(MTR_X3A_X20SIGMA1_X3A_X20candidateDestinationId_X3D), + /* K21 */ be_nested_str_weak(stop_iteration), + }), + be_str_weak(find_session_by_destination_id), + &be_const_str_solidified, + ( &(const binstruction[79]) { /* code */ + 0xA40E0000, // 0000 IMPORT R3 K0 + 0xB8120200, // 0001 GETNGBL R4 K1 + 0x8C100902, // 0002 GETMET R4 R4 K2 + 0x8C180304, // 0003 GETMET R6 R1 K4 + 0x7C180200, // 0004 CALL R6 1 + 0x001A0606, // 0005 ADD R6 K3 R6 + 0x581C0005, // 0006 LDCONST R7 K5 + 0x7C100600, // 0007 CALL R4 3 + 0x60100010, // 0008 GETGBL R4 G16 + 0x88140106, // 0009 GETMBR R5 R0 K6 + 0x88140B07, // 000A GETMBR R5 R5 K7 + 0x88140B07, // 000B GETMBR R5 R5 K7 + 0x7C100200, // 000C CALL R4 1 + 0xA802003B, // 000D EXBLK 0 #004A + 0x5C140800, // 000E MOVE R5 R4 + 0x7C140000, // 000F CALL R5 0 + 0x88180B08, // 0010 GETMBR R6 R5 K8 + 0x4C1C0000, // 0011 LDNIL R7 + 0x1C180C07, // 0012 EQ R6 R6 R7 + 0x741A0007, // 0013 JMPT R6 #001C + 0x88180B09, // 0014 GETMBR R6 R5 K9 + 0x4C1C0000, // 0015 LDNIL R7 + 0x1C180C07, // 0016 EQ R6 R6 R7 + 0x741A0003, // 0017 JMPT R6 #001C + 0x88180B0A, // 0018 GETMBR R6 R5 K10 + 0x4C1C0000, // 0019 LDNIL R7 + 0x1C180C07, // 001A EQ R6 R6 R7 + 0x781A0000, // 001B JMPF R6 #001D + 0x7001FFF0, // 001C JMP #000E + 0x8C180B0B, // 001D GETMET R6 R5 K11 + 0x7C180200, // 001E CALL R6 1 + 0x00180406, // 001F ADD R6 R2 R6 + 0x8C1C0B0C, // 0020 GETMET R7 R5 K12 + 0x7C1C0200, // 0021 CALL R7 1 + 0x00180C07, // 0022 ADD R6 R6 R7 + 0x8C1C0B0D, // 0023 GETMET R7 R5 K13 + 0x7C1C0200, // 0024 CALL R7 1 + 0x00180C07, // 0025 ADD R6 R6 R7 + 0x8C1C0B0E, // 0026 GETMET R7 R5 K14 + 0x7C1C0200, // 0027 CALL R7 1 + 0xB8220200, // 0028 GETNGBL R8 K1 + 0x8C201102, // 0029 GETMET R8 R8 K2 + 0x8C280D04, // 002A GETMET R10 R6 K4 + 0x7C280200, // 002B CALL R10 1 + 0x002A1E0A, // 002C ADD R10 K15 R10 + 0x582C0005, // 002D LDCONST R11 K5 + 0x7C200600, // 002E CALL R8 3 + 0xB8220200, // 002F GETNGBL R8 K1 + 0x8C201102, // 0030 GETMET R8 R8 K2 + 0x8C280F04, // 0031 GETMET R10 R7 K4 + 0x7C280200, // 0032 CALL R10 1 + 0x002A200A, // 0033 ADD R10 K16 R10 + 0x582C0005, // 0034 LDCONST R11 K5 + 0x7C200600, // 0035 CALL R8 3 + 0x8C200711, // 0036 GETMET R8 R3 K17 + 0x5C280E00, // 0037 MOVE R10 R7 + 0x7C200400, // 0038 CALL R8 2 + 0x8C241112, // 0039 GETMET R9 R8 K18 + 0x5C2C0C00, // 003A MOVE R11 R6 + 0x7C240400, // 003B CALL R9 2 + 0x8C241113, // 003C GETMET R9 R8 K19 + 0x7C240200, // 003D CALL R9 1 + 0xB82A0200, // 003E GETNGBL R10 K1 + 0x8C281502, // 003F GETMET R10 R10 K2 + 0x8C301304, // 0040 GETMET R12 R9 K4 + 0x7C300200, // 0041 CALL R12 1 + 0x0032280C, // 0042 ADD R12 K20 R12 + 0x58340005, // 0043 LDCONST R13 K5 + 0x7C280600, // 0044 CALL R10 3 + 0x1C281201, // 0045 EQ R10 R9 R1 + 0x782A0001, // 0046 JMPF R10 #0049 + 0xA8040001, // 0047 EXBLK 1 1 + 0x80040A00, // 0048 RET 1 R5 + 0x7001FFC3, // 0049 JMP #000E + 0x58100015, // 004A LDCONST R4 K21 + 0xAC100200, // 004B CATCH R4 1 0 + 0xB0080000, // 004C RAISE 2 R0 R0 + 0x4C100000, // 004D LDNIL R4 + 0x80040800, // 004E RET 1 R4 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: every_second +********************************************************************/ +be_local_closure(Matter_Commisioning_Context_every_second, /* name */ + be_nested_proto( + 1, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + be_str_weak(every_second), + &be_const_str_solidified, + ( &(const binstruction[ 1]) { /* code */ + 0x80000000, // 0000 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: parse_Sigma3 +********************************************************************/ +be_local_closure(Matter_Commisioning_Context_parse_Sigma3, /* name */ + be_nested_proto( + 40, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[92]) { /* constants */ + /* K0 */ be_nested_str_weak(crypto), + /* K1 */ be_nested_str_weak(opcode), + /* K2 */ be_nested_str_weak(local_session_id), + /* K3 */ be_const_int(0), + /* K4 */ be_nested_str_weak(protocol_id), + /* K5 */ be_nested_str_weak(protocol_error), + /* K6 */ be_nested_str_weak(invalid_X20Pake1_X20message), + /* K7 */ be_nested_str_weak(session), + /* K8 */ be_nested_str_weak(matter), + /* K9 */ be_nested_str_weak(Sigma3), + /* K10 */ be_nested_str_weak(parse), + /* K11 */ be_nested_str_weak(raw), + /* K12 */ be_nested_str_weak(app_payload_idx), + /* K13 */ be_nested_str_weak(tasmota), + /* K14 */ be_nested_str_weak(log), + /* K15 */ be_nested_str_weak(_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A), + /* K16 */ be_const_int(3), + /* K17 */ be_nested_str_weak(SHA256), + /* K18 */ be_nested_str_weak(update), + /* K19 */ be_nested_str_weak(_Msg1), + /* K20 */ be_nested_str_weak(_Msg2), + /* K21 */ be_nested_str_weak(out), + /* K22 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20session_X20_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K23 */ be_nested_str_weak(MTR_X3A_X20session_X2Eipk_epoch_key_X20), + /* K24 */ be_nested_str_weak(ipk_epoch_key), + /* K25 */ be_nested_str_weak(MTR_X3A_X20session_X2Efabric_compressed_X20), + /* K26 */ be_nested_str_weak(fabric_compressed), + /* K27 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20ipk_group_key_X20_X3D_X20), + /* K28 */ be_nested_str_weak(get_ipk_group_key), + /* K29 */ be_nested_str_weak(tohex), + /* K30 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20TranscriptHash_X3D_X20), + /* K31 */ be_nested_str_weak(fromstring), + /* K32 */ be_nested_str_weak(S3K_Info), + /* K33 */ be_nested_str_weak(HKDF_SHA256), + /* K34 */ be_nested_str_weak(derive), + /* K35 */ be_nested_str_weak(shared_secret), + /* K36 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20s3k_salt_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K37 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20s3k_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K38 */ be_nested_str_weak(TBEData3Encrypted), + /* K39 */ be_const_int(2147483647), + /* K40 */ be_nested_str_weak(AES_CCM), + /* K41 */ be_nested_str_weak(TBEData3_Nonce), + /* K42 */ be_nested_str_weak(decrypt), + /* K43 */ be_nested_str_weak(tag), + /* K44 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20TBEData3_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K45 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20TBETag3_X20_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K46 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20tag_sent_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K47 */ be_nested_str_weak(value_error), + /* K48 */ be_nested_str_weak(tag_X20do_X20not_X20match), + /* K49 */ be_nested_str_weak(TLV), + /* K50 */ be_nested_str_weak(findsubval), + /* K51 */ be_const_int(1), + /* K52 */ be_const_int(2), + /* K53 */ be_nested_str_weak(MTR_X3A_X20initiatorNOCTLV_X20_X3D_X20), + /* K54 */ be_nested_str_weak(findsub), + /* K55 */ be_nested_str_weak(int), + /* K56 */ be_nested_str_weak(int64), + /* K57 */ be_nested_str_weak(peer_node_id), + /* K58 */ be_nested_str_weak(tobytes), + /* K59 */ be_nested_str_weak(MTR_X3A_X20initiatorFabricId_X3D), + /* K60 */ be_nested_str_weak(Matter_TLV_struct), + /* K61 */ be_nested_str_weak(add_TLV), + /* K62 */ be_nested_str_weak(B1), + /* K63 */ be_nested_str_weak(initiatorEph_pub), + /* K64 */ be_nested_str_weak(ResponderEph_pub), + /* K65 */ be_nested_str_weak(encode), + /* K66 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20initiatorNOCPubKey_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K67 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20ec_signature_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K68 */ be_nested_str_weak(EC_P256), + /* K69 */ be_nested_str_weak(ecdsa_verify_sha256), + /* K70 */ be_nested_str_weak(sigma3_tbs_X20does_X20not_X20have_X20a_X20valid_X20signature), + /* K71 */ be_nested_str_weak(MTR_X3A_X20Sigma3_X20verified_X2C_X20computing_X20new_X20keys), + /* K72 */ be_nested_str_weak(Msg3), + /* K73 */ be_nested_str_weak(MTR_X3A_X20_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A), + /* K74 */ be_nested_str_weak(MTR_X3A_X20shared_secret_X20_X3D), + /* K75 */ be_nested_str_weak(MTR_X3A_X20ipk_X20_X2B_X20hash_X20_X20_X20_X20_X3D), + /* K76 */ be_nested_str_weak(SEKeys_Info), + /* K77 */ be_nested_str_weak(rtc), + /* K78 */ be_nested_str_weak(utc), + /* K79 */ be_nested_str_weak(MTR_X3A_X20I2RKey_X20_X20_X20_X20_X20_X20_X3D), + /* K80 */ be_nested_str_weak(MTR_X3A_X20R2IKey_X20_X20_X20_X20_X20_X20_X3D), + /* K81 */ be_nested_str_weak(MTR_X3A_X20AC_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), + /* K82 */ be_nested_str_weak(build_response), + /* K83 */ be_nested_str_weak(add), + /* K84 */ be_nested_str_weak(responder), + /* K85 */ be_nested_str_weak(send_response), + /* K86 */ be_nested_str_weak(message_counter), + /* K87 */ be_nested_str_weak(close), + /* K88 */ be_nested_str_weak(set_keys), + /* K89 */ be_nested_str_weak(set_persist), + /* K90 */ be_nested_str_weak(set_no_expiration), + /* K91 */ be_nested_str_weak(save), + }), + be_str_weak(parse_Sigma3), + &be_const_str_solidified, + ( &(const binstruction[445]) { /* code */ + 0xA4120000, // 0000 IMPORT R4 K0 + 0x88140301, // 0001 GETMBR R5 R1 K1 + 0x541A0031, // 0002 LDINT R6 50 + 0x20140A06, // 0003 NE R5 R5 R6 + 0x74160005, // 0004 JMPT R5 #000B + 0x88140302, // 0005 GETMBR R5 R1 K2 + 0x20140B03, // 0006 NE R5 R5 K3 + 0x74160002, // 0007 JMPT R5 #000B + 0x88140304, // 0008 GETMBR R5 R1 K4 + 0x20140B03, // 0009 NE R5 R5 K3 + 0x78160000, // 000A JMPF R5 #000C + 0xB0060B06, // 000B RAISE 1 K5 K6 + 0x88140307, // 000C GETMBR R5 R1 K7 + 0xB81A1000, // 000D GETNGBL R6 K8 + 0x8C180D09, // 000E GETMET R6 R6 K9 + 0x7C180200, // 000F CALL R6 1 + 0x8C180D0A, // 0010 GETMET R6 R6 K10 + 0x8820030B, // 0011 GETMBR R8 R1 K11 + 0x8824030C, // 0012 GETMBR R9 R1 K12 + 0x7C180600, // 0013 CALL R6 3 + 0xB81E1A00, // 0014 GETNGBL R7 K13 + 0x8C1C0F0E, // 0015 GETMET R7 R7 K14 + 0x5824000F, // 0016 LDCONST R9 K15 + 0x58280010, // 0017 LDCONST R10 K16 + 0x7C1C0600, // 0018 CALL R7 3 + 0x8C1C0911, // 0019 GETMET R7 R4 K17 + 0x7C1C0200, // 001A CALL R7 1 + 0x8C1C0F12, // 001B GETMET R7 R7 K18 + 0x88240B13, // 001C GETMBR R9 R5 K19 + 0x7C1C0400, // 001D CALL R7 2 + 0x8C1C0F12, // 001E GETMET R7 R7 K18 + 0x88240B14, // 001F GETMBR R9 R5 K20 + 0x7C1C0400, // 0020 CALL R7 2 + 0x8C1C0F15, // 0021 GETMET R7 R7 K21 + 0x7C1C0200, // 0022 CALL R7 1 + 0xB8221A00, // 0023 GETNGBL R8 K13 + 0x8C20110E, // 0024 GETMET R8 R8 K14 + 0x60280008, // 0025 GETGBL R10 G8 + 0x5C2C0A00, // 0026 MOVE R11 R5 + 0x7C280200, // 0027 CALL R10 1 + 0x002A2C0A, // 0028 ADD R10 K22 R10 + 0x582C0010, // 0029 LDCONST R11 K16 + 0x7C200600, // 002A CALL R8 3 + 0xB8221A00, // 002B GETNGBL R8 K13 + 0x8C20110E, // 002C GETMET R8 R8 K14 + 0x60280008, // 002D GETGBL R10 G8 + 0x882C0B18, // 002E GETMBR R11 R5 K24 + 0x7C280200, // 002F CALL R10 1 + 0x002A2E0A, // 0030 ADD R10 K23 R10 + 0x582C0010, // 0031 LDCONST R11 K16 + 0x7C200600, // 0032 CALL R8 3 + 0xB8221A00, // 0033 GETNGBL R8 K13 + 0x8C20110E, // 0034 GETMET R8 R8 K14 + 0x60280008, // 0035 GETGBL R10 G8 + 0x882C0B1A, // 0036 GETMBR R11 R5 K26 + 0x7C280200, // 0037 CALL R10 1 + 0x002A320A, // 0038 ADD R10 K25 R10 + 0x582C0010, // 0039 LDCONST R11 K16 + 0x7C200600, // 003A CALL R8 3 + 0xB8221A00, // 003B GETNGBL R8 K13 + 0x8C20110E, // 003C GETMET R8 R8 K14 + 0x8C280B1C, // 003D GETMET R10 R5 K28 + 0x7C280200, // 003E CALL R10 1 + 0x8C28151D, // 003F GETMET R10 R10 K29 + 0x7C280200, // 0040 CALL R10 1 + 0x002A360A, // 0041 ADD R10 K27 R10 + 0x582C0010, // 0042 LDCONST R11 K16 + 0x7C200600, // 0043 CALL R8 3 + 0xB8221A00, // 0044 GETNGBL R8 K13 + 0x8C20110E, // 0045 GETMET R8 R8 K14 + 0x8C280F1D, // 0046 GETMET R10 R7 K29 + 0x7C280200, // 0047 CALL R10 1 + 0x002A3C0A, // 0048 ADD R10 K30 R10 + 0x582C0010, // 0049 LDCONST R11 K16 + 0x7C200600, // 004A CALL R8 3 + 0x60200015, // 004B GETGBL R8 G21 + 0x7C200000, // 004C CALL R8 0 + 0x8C20111F, // 004D GETMET R8 R8 K31 + 0x88280120, // 004E GETMBR R10 R0 K32 + 0x7C200400, // 004F CALL R8 2 + 0x8C240921, // 0050 GETMET R9 R4 K33 + 0x7C240200, // 0051 CALL R9 1 + 0x8C241322, // 0052 GETMET R9 R9 K34 + 0x882C0B23, // 0053 GETMBR R11 R5 K35 + 0x8C300B1C, // 0054 GETMET R12 R5 K28 + 0x7C300200, // 0055 CALL R12 1 + 0x00301807, // 0056 ADD R12 R12 R7 + 0x5C341000, // 0057 MOVE R13 R8 + 0x543A000F, // 0058 LDINT R14 16 + 0x7C240A00, // 0059 CALL R9 5 + 0xB82A1A00, // 005A GETNGBL R10 K13 + 0x8C28150E, // 005B GETMET R10 R10 K14 + 0x5830000F, // 005C LDCONST R12 K15 + 0x58340010, // 005D LDCONST R13 K16 + 0x7C280600, // 005E CALL R10 3 + 0xB82A1A00, // 005F GETNGBL R10 K13 + 0x8C28150E, // 0060 GETMET R10 R10 K14 + 0x8C300B1C, // 0061 GETMET R12 R5 K28 + 0x7C300200, // 0062 CALL R12 1 + 0x00301807, // 0063 ADD R12 R12 R7 + 0x8C30191D, // 0064 GETMET R12 R12 K29 + 0x7C300200, // 0065 CALL R12 1 + 0x0032480C, // 0066 ADD R12 K36 R12 + 0x58340010, // 0067 LDCONST R13 K16 + 0x7C280600, // 0068 CALL R10 3 + 0xB82A1A00, // 0069 GETNGBL R10 K13 + 0x8C28150E, // 006A GETMET R10 R10 K14 + 0x8C30131D, // 006B GETMET R12 R9 K29 + 0x7C300200, // 006C CALL R12 1 + 0x00324A0C, // 006D ADD R12 K37 R12 + 0x58340010, // 006E LDCONST R13 K16 + 0x7C280600, // 006F CALL R10 3 + 0xB82A1A00, // 0070 GETNGBL R10 K13 + 0x8C28150E, // 0071 GETMET R10 R10 K14 + 0x5830000F, // 0072 LDCONST R12 K15 + 0x58340010, // 0073 LDCONST R13 K16 + 0x7C280600, // 0074 CALL R10 3 + 0x5429FFEE, // 0075 LDINT R10 -17 + 0x402A060A, // 0076 CONNECT R10 K3 R10 + 0x882C0D26, // 0077 GETMBR R11 R6 K38 + 0x9428160A, // 0078 GETIDX R10 R11 R10 + 0x5431FFEF, // 0079 LDINT R12 -16 + 0x40301927, // 007A CONNECT R12 R12 K39 + 0x88340D26, // 007B GETMBR R13 R6 K38 + 0x942C1A0C, // 007C GETIDX R11 R13 R12 + 0x8C380928, // 007D GETMET R14 R4 K40 + 0x5C401200, // 007E MOVE R16 R9 + 0x60440015, // 007F GETGBL R17 G21 + 0x7C440000, // 0080 CALL R17 0 + 0x8C44231F, // 0081 GETMET R17 R17 K31 + 0x884C0129, // 0082 GETMBR R19 R0 K41 + 0x7C440400, // 0083 CALL R17 2 + 0x60480015, // 0084 GETGBL R18 G21 + 0x7C480000, // 0085 CALL R18 0 + 0x604C000C, // 0086 GETGBL R19 G12 + 0x5C501400, // 0087 MOVE R20 R10 + 0x7C4C0200, // 0088 CALL R19 1 + 0x5452000F, // 0089 LDINT R20 16 + 0x7C380C00, // 008A CALL R14 6 + 0x5C301C00, // 008B MOVE R12 R14 + 0x8C38192A, // 008C GETMET R14 R12 K42 + 0x5C401400, // 008D MOVE R16 R10 + 0x7C380400, // 008E CALL R14 2 + 0x5C341C00, // 008F MOVE R13 R14 + 0x8C38192B, // 0090 GETMET R14 R12 K43 + 0x7C380200, // 0091 CALL R14 1 + 0xB83E1A00, // 0092 GETNGBL R15 K13 + 0x8C3C1F0E, // 0093 GETMET R15 R15 K14 + 0x8C441B1D, // 0094 GETMET R17 R13 K29 + 0x7C440200, // 0095 CALL R17 1 + 0x00465811, // 0096 ADD R17 K44 R17 + 0x58480010, // 0097 LDCONST R18 K16 + 0x7C3C0600, // 0098 CALL R15 3 + 0xB83E1A00, // 0099 GETNGBL R15 K13 + 0x8C3C1F0E, // 009A GETMET R15 R15 K14 + 0x8C441D1D, // 009B GETMET R17 R14 K29 + 0x7C440200, // 009C CALL R17 1 + 0x00465A11, // 009D ADD R17 K45 R17 + 0x58480010, // 009E LDCONST R18 K16 + 0x7C3C0600, // 009F CALL R15 3 + 0xB83E1A00, // 00A0 GETNGBL R15 K13 + 0x8C3C1F0E, // 00A1 GETMET R15 R15 K14 + 0x8C44171D, // 00A2 GETMET R17 R11 K29 + 0x7C440200, // 00A3 CALL R17 1 + 0x00465C11, // 00A4 ADD R17 K46 R17 + 0x58480010, // 00A5 LDCONST R18 K16 + 0x7C3C0600, // 00A6 CALL R15 3 + 0xB83E1A00, // 00A7 GETNGBL R15 K13 + 0x8C3C1F0E, // 00A8 GETMET R15 R15 K14 + 0x5844000F, // 00A9 LDCONST R17 K15 + 0x58480010, // 00AA LDCONST R18 K16 + 0x7C3C0600, // 00AB CALL R15 3 + 0x203C1C0B, // 00AC NE R15 R14 R11 + 0x783E0000, // 00AD JMPF R15 #00AF + 0xB0065F30, // 00AE RAISE 1 K47 K48 + 0xB83E1000, // 00AF GETNGBL R15 K8 + 0x883C1F31, // 00B0 GETMBR R15 R15 K49 + 0x8C3C1F0A, // 00B1 GETMET R15 R15 K10 + 0x5C441A00, // 00B2 MOVE R17 R13 + 0x7C3C0400, // 00B3 CALL R15 2 + 0x8C401F32, // 00B4 GETMET R16 R15 K50 + 0x58480033, // 00B5 LDCONST R18 K51 + 0x7C400400, // 00B6 CALL R16 2 + 0x8C441F32, // 00B7 GETMET R17 R15 K50 + 0x584C0034, // 00B8 LDCONST R19 K52 + 0x7C440400, // 00B9 CALL R17 2 + 0x8C481F32, // 00BA GETMET R18 R15 K50 + 0x58500010, // 00BB LDCONST R20 K16 + 0x7C480400, // 00BC CALL R18 2 + 0xB84E1000, // 00BD GETNGBL R19 K8 + 0x884C2731, // 00BE GETMBR R19 R19 K49 + 0x8C4C270A, // 00BF GETMET R19 R19 K10 + 0x5C542000, // 00C0 MOVE R21 R16 + 0x7C4C0400, // 00C1 CALL R19 2 + 0xB8521A00, // 00C2 GETNGBL R20 K13 + 0x8C50290E, // 00C3 GETMET R20 R20 K14 + 0x60580008, // 00C4 GETGBL R22 G8 + 0x5C5C2600, // 00C5 MOVE R23 R19 + 0x7C580200, // 00C6 CALL R22 1 + 0x005A6A16, // 00C7 ADD R22 K53 R22 + 0x585C0010, // 00C8 LDCONST R23 K16 + 0x7C500600, // 00C9 CALL R20 3 + 0x8C502732, // 00CA GETMET R20 R19 K50 + 0x545A0008, // 00CB LDINT R22 9 + 0x7C500400, // 00CC CALL R20 2 + 0x8C542736, // 00CD GETMET R21 R19 K54 + 0x545E0005, // 00CE LDINT R23 6 + 0x7C540400, // 00CF CALL R21 2 + 0x8C582B32, // 00D0 GETMET R22 R21 K50 + 0x54620010, // 00D1 LDINT R24 17 + 0x7C580400, // 00D2 CALL R22 2 + 0x605C0004, // 00D3 GETGBL R23 G4 + 0x5C602C00, // 00D4 MOVE R24 R22 + 0x7C5C0200, // 00D5 CALL R23 1 + 0x1C5C2F37, // 00D6 EQ R23 R23 K55 + 0x785E0003, // 00D7 JMPF R23 #00DC + 0xB85E7000, // 00D8 GETNGBL R23 K56 + 0x5C602C00, // 00D9 MOVE R24 R22 + 0x7C5C0200, // 00DA CALL R23 1 + 0x5C582E00, // 00DB MOVE R22 R23 + 0x8C5C2D3A, // 00DC GETMET R23 R22 K58 + 0x7C5C0200, // 00DD CALL R23 1 + 0x90167217, // 00DE SETMBR R5 K57 R23 + 0xB85E1A00, // 00DF GETNGBL R23 K13 + 0x8C5C2F0E, // 00E0 GETMET R23 R23 K14 + 0x60640008, // 00E1 GETGBL R25 G8 + 0x88680B39, // 00E2 GETMBR R26 R5 K57 + 0x7C640200, // 00E3 CALL R25 1 + 0x00667619, // 00E4 ADD R25 K59 R25 + 0x58680010, // 00E5 LDCONST R26 K16 + 0x7C5C0600, // 00E6 CALL R23 3 + 0xB85E1000, // 00E7 GETNGBL R23 K8 + 0x885C2F31, // 00E8 GETMBR R23 R23 K49 + 0x8C5C2F3C, // 00E9 GETMET R23 R23 K60 + 0x7C5C0200, // 00EA CALL R23 1 + 0x8C602F3D, // 00EB GETMET R24 R23 K61 + 0x58680033, // 00EC LDCONST R26 K51 + 0xB86E1000, // 00ED GETNGBL R27 K8 + 0x886C3731, // 00EE GETMBR R27 R27 K49 + 0x886C373E, // 00EF GETMBR R27 R27 K62 + 0x5C702000, // 00F0 MOVE R28 R16 + 0x7C600800, // 00F1 CALL R24 4 + 0x8C602F3D, // 00F2 GETMET R24 R23 K61 + 0x58680034, // 00F3 LDCONST R26 K52 + 0xB86E1000, // 00F4 GETNGBL R27 K8 + 0x886C3731, // 00F5 GETMBR R27 R27 K49 + 0x886C373E, // 00F6 GETMBR R27 R27 K62 + 0x5C702200, // 00F7 MOVE R28 R17 + 0x7C600800, // 00F8 CALL R24 4 + 0x8C602F3D, // 00F9 GETMET R24 R23 K61 + 0x58680010, // 00FA LDCONST R26 K16 + 0xB86E1000, // 00FB GETNGBL R27 K8 + 0x886C3731, // 00FC GETMBR R27 R27 K49 + 0x886C373E, // 00FD GETMBR R27 R27 K62 + 0x8870013F, // 00FE GETMBR R28 R0 K63 + 0x7C600800, // 00FF CALL R24 4 + 0x8C602F3D, // 0100 GETMET R24 R23 K61 + 0x546A0003, // 0101 LDINT R26 4 + 0xB86E1000, // 0102 GETNGBL R27 K8 + 0x886C3731, // 0103 GETMBR R27 R27 K49 + 0x886C373E, // 0104 GETMBR R27 R27 K62 + 0x88700140, // 0105 GETMBR R28 R0 K64 + 0x7C600800, // 0106 CALL R24 4 + 0x8C602F41, // 0107 GETMET R24 R23 K65 + 0x7C600200, // 0108 CALL R24 1 + 0xB8661A00, // 0109 GETNGBL R25 K13 + 0x8C64330E, // 010A GETMET R25 R25 K14 + 0x8C6C291D, // 010B GETMET R27 R20 K29 + 0x7C6C0200, // 010C CALL R27 1 + 0x006E841B, // 010D ADD R27 K66 R27 + 0x58700010, // 010E LDCONST R28 K16 + 0x7C640600, // 010F CALL R25 3 + 0xB8661A00, // 0110 GETNGBL R25 K13 + 0x8C64330E, // 0111 GETMET R25 R25 K14 + 0x8C6C251D, // 0112 GETMET R27 R18 K29 + 0x7C6C0200, // 0113 CALL R27 1 + 0x006E861B, // 0114 ADD R27 K67 R27 + 0x58700010, // 0115 LDCONST R28 K16 + 0x7C640600, // 0116 CALL R25 3 + 0xB8661A00, // 0117 GETNGBL R25 K13 + 0x8C64330E, // 0118 GETMET R25 R25 K14 + 0x586C000F, // 0119 LDCONST R27 K15 + 0x58700010, // 011A LDCONST R28 K16 + 0x7C640600, // 011B CALL R25 3 + 0x8C640944, // 011C GETMET R25 R4 K68 + 0x7C640200, // 011D CALL R25 1 + 0x8C643345, // 011E GETMET R25 R25 K69 + 0x5C6C2800, // 011F MOVE R27 R20 + 0x5C703000, // 0120 MOVE R28 R24 + 0x5C742400, // 0121 MOVE R29 R18 + 0x7C640800, // 0122 CALL R25 4 + 0x5C683200, // 0123 MOVE R26 R25 + 0x746A0000, // 0124 JMPT R26 #0126 + 0xB0065F46, // 0125 RAISE 1 K47 K70 + 0xB86A1A00, // 0126 GETNGBL R26 K13 + 0x8C68350E, // 0127 GETMET R26 R26 K14 + 0x58700047, // 0128 LDCONST R28 K71 + 0x58740010, // 0129 LDCONST R29 K16 + 0x7C680600, // 012A CALL R26 3 + 0x8C680911, // 012B GETMET R26 R4 K17 + 0x7C680200, // 012C CALL R26 1 + 0x8C683512, // 012D GETMET R26 R26 K18 + 0x88700B13, // 012E GETMBR R28 R5 K19 + 0x7C680400, // 012F CALL R26 2 + 0x8C683512, // 0130 GETMET R26 R26 K18 + 0x88700B14, // 0131 GETMBR R28 R5 K20 + 0x7C680400, // 0132 CALL R26 2 + 0x8C683512, // 0133 GETMET R26 R26 K18 + 0x88700D48, // 0134 GETMBR R28 R6 K72 + 0x7C680400, // 0135 CALL R26 2 + 0x8C683515, // 0136 GETMET R26 R26 K21 + 0x7C680200, // 0137 CALL R26 1 + 0x5C1C3400, // 0138 MOVE R7 R26 + 0x4C680000, // 0139 LDNIL R26 + 0x9016261A, // 013A SETMBR R5 K19 R26 + 0x4C680000, // 013B LDNIL R26 + 0x9016281A, // 013C SETMBR R5 K20 R26 + 0xB86A1A00, // 013D GETNGBL R26 K13 + 0x8C68350E, // 013E GETMET R26 R26 K14 + 0x58700049, // 013F LDCONST R28 K73 + 0x58740010, // 0140 LDCONST R29 K16 + 0x7C680600, // 0141 CALL R26 3 + 0xB86A1A00, // 0142 GETNGBL R26 K13 + 0x8C68350E, // 0143 GETMET R26 R26 K14 + 0x88700B23, // 0144 GETMBR R28 R5 K35 + 0x8C70391D, // 0145 GETMET R28 R28 K29 + 0x7C700200, // 0146 CALL R28 1 + 0x0072941C, // 0147 ADD R28 K74 R28 + 0x58740010, // 0148 LDCONST R29 K16 + 0x7C680600, // 0149 CALL R26 3 + 0xB86A1A00, // 014A GETNGBL R26 K13 + 0x8C68350E, // 014B GETMET R26 R26 K14 + 0x8C700B1C, // 014C GETMET R28 R5 K28 + 0x7C700200, // 014D CALL R28 1 + 0x00703807, // 014E ADD R28 R28 R7 + 0x8C70391D, // 014F GETMET R28 R28 K29 + 0x7C700200, // 0150 CALL R28 1 + 0x0072961C, // 0151 ADD R28 K75 R28 + 0x58740010, // 0152 LDCONST R29 K16 + 0x7C680600, // 0153 CALL R26 3 + 0x8C680921, // 0154 GETMET R26 R4 K33 + 0x7C680200, // 0155 CALL R26 1 + 0x8C683522, // 0156 GETMET R26 R26 K34 + 0x88700B23, // 0157 GETMBR R28 R5 K35 + 0x8C740B1C, // 0158 GETMET R29 R5 K28 + 0x7C740200, // 0159 CALL R29 1 + 0x00743A07, // 015A ADD R29 R29 R7 + 0x60780015, // 015B GETGBL R30 G21 + 0x7C780000, // 015C CALL R30 0 + 0x8C783D1F, // 015D GETMET R30 R30 K31 + 0x8880014C, // 015E GETMBR R32 R0 K76 + 0x7C780400, // 015F CALL R30 2 + 0x547E002F, // 0160 LDINT R31 48 + 0x7C680A00, // 0161 CALL R26 5 + 0x546E000E, // 0162 LDINT R27 15 + 0x406E061B, // 0163 CONNECT R27 K3 R27 + 0x946C341B, // 0164 GETIDX R27 R26 R27 + 0x5472000F, // 0165 LDINT R28 16 + 0x5476001E, // 0166 LDINT R29 31 + 0x4070381D, // 0167 CONNECT R28 R28 R29 + 0x9470341C, // 0168 GETIDX R28 R26 R28 + 0x5476001F, // 0169 LDINT R29 32 + 0x547A002E, // 016A LDINT R30 47 + 0x40743A1E, // 016B CONNECT R29 R29 R30 + 0x9474341D, // 016C GETIDX R29 R26 R29 + 0xB87A1A00, // 016D GETNGBL R30 K13 + 0x8C783D4D, // 016E GETMET R30 R30 K77 + 0x7C780200, // 016F CALL R30 1 + 0x94783D4E, // 0170 GETIDX R30 R30 K78 + 0xB87E1A00, // 0171 GETNGBL R31 K13 + 0x8C7C3F0E, // 0172 GETMET R31 R31 K14 + 0x58840049, // 0173 LDCONST R33 K73 + 0x58880010, // 0174 LDCONST R34 K16 + 0x7C7C0600, // 0175 CALL R31 3 + 0xB87E1A00, // 0176 GETNGBL R31 K13 + 0x8C7C3F0E, // 0177 GETMET R31 R31 K14 + 0x8C84371D, // 0178 GETMET R33 R27 K29 + 0x7C840200, // 0179 CALL R33 1 + 0x00869E21, // 017A ADD R33 K79 R33 + 0x58880010, // 017B LDCONST R34 K16 + 0x7C7C0600, // 017C CALL R31 3 + 0xB87E1A00, // 017D GETNGBL R31 K13 + 0x8C7C3F0E, // 017E GETMET R31 R31 K14 + 0x8C84391D, // 017F GETMET R33 R28 K29 + 0x7C840200, // 0180 CALL R33 1 + 0x0086A021, // 0181 ADD R33 K80 R33 + 0x58880010, // 0182 LDCONST R34 K16 + 0x7C7C0600, // 0183 CALL R31 3 + 0xB87E1A00, // 0184 GETNGBL R31 K13 + 0x8C7C3F0E, // 0185 GETMET R31 R31 K14 + 0x8C843B1D, // 0186 GETMET R33 R29 K29 + 0x7C840200, // 0187 CALL R33 1 + 0x0086A221, // 0188 ADD R33 K81 R33 + 0x58880010, // 0189 LDCONST R34 K16 + 0x7C7C0600, // 018A CALL R31 3 + 0xB87E1A00, // 018B GETNGBL R31 K13 + 0x8C7C3F0E, // 018C GETMET R31 R31 K14 + 0x58840049, // 018D LDCONST R33 K73 + 0x58880010, // 018E LDCONST R34 K16 + 0x7C7C0600, // 018F CALL R31 3 + 0x8C7C0352, // 0190 GETMET R31 R1 K82 + 0x5486003F, // 0191 LDINT R33 64 + 0x50880200, // 0192 LDBOOL R34 1 0 + 0x7C7C0600, // 0193 CALL R31 3 + 0x60800015, // 0194 GETGBL R32 G21 + 0x7C800000, // 0195 CALL R32 0 + 0x8C844153, // 0196 GETMET R33 R32 K83 + 0x588C0003, // 0197 LDCONST R35 K3 + 0x58900034, // 0198 LDCONST R36 K52 + 0x7C840600, // 0199 CALL R33 3 + 0x8C844153, // 019A GETMET R33 R32 K83 + 0x588C0003, // 019B LDCONST R35 K3 + 0x54920003, // 019C LDINT R36 4 + 0x7C840600, // 019D CALL R33 3 + 0x8C844153, // 019E GETMET R33 R32 K83 + 0x588C0003, // 019F LDCONST R35 K3 + 0x54920003, // 01A0 LDINT R36 4 + 0x7C840600, // 01A1 CALL R33 3 + 0x8C843F41, // 01A2 GETMET R33 R31 K65 + 0x5C8C4000, // 01A3 MOVE R35 R32 + 0x7C840400, // 01A4 CALL R33 2 + 0x88880154, // 01A5 GETMBR R34 R0 K84 + 0x8C884555, // 01A6 GETMET R34 R34 K85 + 0x5C904200, // 01A7 MOVE R36 R33 + 0x5C940400, // 01A8 MOVE R37 R2 + 0x5C980600, // 01A9 MOVE R38 R3 + 0x889C3F56, // 01AA GETMBR R39 R31 K86 + 0x7C880A00, // 01AB CALL R34 5 + 0x8C880B57, // 01AC GETMET R34 R5 K87 + 0x7C880200, // 01AD CALL R34 1 + 0x8C880B58, // 01AE GETMET R34 R5 K88 + 0x5C903600, // 01AF MOVE R36 R27 + 0x5C943800, // 01B0 MOVE R37 R28 + 0x5C983A00, // 01B1 MOVE R38 R29 + 0x5C9C3C00, // 01B2 MOVE R39 R30 + 0x7C880A00, // 01B3 CALL R34 5 + 0x8C880B59, // 01B4 GETMET R34 R5 K89 + 0x50900200, // 01B5 LDBOOL R36 1 0 + 0x7C880400, // 01B6 CALL R34 2 + 0x8C880B5A, // 01B7 GETMET R34 R5 K90 + 0x7C880200, // 01B8 CALL R34 1 + 0x8C880B5B, // 01B9 GETMET R34 R5 K91 + 0x7C880200, // 01BA CALL R34 1 + 0x50880200, // 01BB LDBOOL R34 1 0 + 0x80044400, // 01BC RET 1 R34 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: parse_Sigma1 +********************************************************************/ +be_local_closure(Matter_Commisioning_Context_parse_Sigma1, /* name */ + be_nested_proto( + 36, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[116]) { /* constants */ + /* K0 */ be_nested_str_weak(crypto), + /* K1 */ be_nested_str_weak(opcode), + /* K2 */ be_nested_str_weak(local_session_id), + /* K3 */ be_const_int(0), + /* K4 */ be_nested_str_weak(protocol_id), + /* K5 */ be_nested_str_weak(protocol_error), + /* K6 */ be_nested_str_weak(invalid_X20Pake1_X20message), + /* K7 */ be_nested_str_weak(matter), + /* K8 */ be_nested_str_weak(Sigma1), + /* K9 */ be_nested_str_weak(parse), + /* K10 */ be_nested_str_weak(raw), + /* K11 */ be_nested_str_weak(app_payload_idx), + /* K12 */ be_nested_str_weak(initiatorEph_pub), + /* K13 */ be_nested_str_weak(initiatorEphPubKey), + /* K14 */ be_nested_str_weak(find_session_by_destination_id), + /* K15 */ be_nested_str_weak(destinationId), + /* K16 */ be_nested_str_weak(initiatorRandom), + /* K17 */ be_nested_str_weak(valuer_error), + /* K18 */ be_nested_str_weak(StatusReport_X28GeneralCode_X3A_X20FAILURE_X2C_X20ProtocolId_X3A_X20SECURE_CHANNEL_X2C_X20ProtocolCode_X3A_X20NO_SHARED_TRUST_ROOTS_X29), + /* K19 */ be_nested_str_weak(source_node_id), + /* K20 */ be_nested_str_weak(set_mode), + /* K21 */ be_nested_str_weak(Session), + /* K22 */ be_nested_str_weak(__CASE), + /* K23 */ be_nested_str_weak(session), + /* K24 */ be_nested_str_weak(device), + /* K25 */ be_nested_str_weak(sessions), + /* K26 */ be_nested_str_weak(remove_session), + /* K27 */ be_nested_str_weak(_future_initiator_session_id), + /* K28 */ be_nested_str_weak(initiator_session_id), + /* K29 */ be_nested_str_weak(_future_local_session_id), + /* K30 */ be_nested_str_weak(gen_local_session_id), + /* K31 */ be_nested_str_weak(future_local_session_id), + /* K32 */ be_nested_str_weak(resumptionID), + /* K33 */ be_nested_str_weak(initiatorResumeMIC), + /* K34 */ be_nested_str_weak(shared_secret), + /* K35 */ be_nested_str_weak(fromstring), + /* K36 */ be_nested_str_weak(Sigma1_Resume), + /* K37 */ be_nested_str_weak(HKDF_SHA256), + /* K38 */ be_nested_str_weak(derive), + /* K39 */ be_nested_str_weak(NCASE_SigmaR1), + /* K40 */ be_const_int(2147483647), + /* K41 */ be_nested_str_weak(AES_CCM), + /* K42 */ be_nested_str_weak(decrypt), + /* K43 */ be_nested_str_weak(tag), + /* K44 */ be_nested_str_weak(tasmota), + /* K45 */ be_nested_str_weak(log), + /* K46 */ be_nested_str_weak(_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A), + /* K47 */ be_const_int(3), + /* K48 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20s1rk_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K49 */ be_nested_str_weak(tohex), + /* K50 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20tag_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K51 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20Resume1MICPayload_X20_X3D_X20), + /* K52 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20decrypted_tag_X20_X20_X20_X20_X20_X3D_X20), + /* K53 */ be_nested_str_weak(resumption_id), + /* K54 */ be_nested_str_weak(random), + /* K55 */ be_nested_str_weak(Sigma2_Resume), + /* K56 */ be_nested_str_weak(NCASE_SigmaR2), + /* K57 */ be_nested_str_weak(Sigma2Resume), + /* K58 */ be_nested_str_weak(responderSessionID), + /* K59 */ be_nested_str_weak(sigma2ResumeMIC), + /* K60 */ be_nested_str_weak(SessionResumptionKeys), + /* K61 */ be_nested_str_weak(rtc), + /* K62 */ be_nested_str_weak(utc), + /* K63 */ be_nested_str_weak(MTR_X3A_X20_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A), + /* K64 */ be_nested_str_weak(MTR_X3A_X20I2RKey_X20_X20_X20_X20_X20_X20_X3D), + /* K65 */ be_nested_str_weak(MTR_X3A_X20R2IKey_X20_X20_X20_X20_X20_X20_X3D), + /* K66 */ be_nested_str_weak(MTR_X3A_X20AC_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), + /* K67 */ be_nested_str_weak(encode), + /* K68 */ be_nested_str_weak(_Msg1), + /* K69 */ be_nested_str_weak(MTR_X3A_X20sigma2resume_raw_X3A_X20), + /* K70 */ be_nested_str_weak(build_response), + /* K71 */ be_nested_str_weak(responder), + /* K72 */ be_nested_str_weak(send_response), + /* K73 */ be_nested_str_weak(message_counter), + /* K74 */ be_nested_str_weak(close), + /* K75 */ be_nested_str_weak(set_keys), + /* K76 */ be_nested_str_weak(set_persist), + /* K77 */ be_nested_str_weak(set_no_expiration), + /* K78 */ be_nested_str_weak(save), + /* K79 */ be_nested_str_weak(ResponderEph_priv), + /* K80 */ be_nested_str_weak(ResponderEph_pub), + /* K81 */ be_nested_str_weak(EC_P256), + /* K82 */ be_nested_str_weak(public_key), + /* K83 */ be_nested_str_weak(shared_key), + /* K84 */ be_nested_str_weak(TLV), + /* K85 */ be_nested_str_weak(Matter_TLV_struct), + /* K86 */ be_nested_str_weak(add_TLV), + /* K87 */ be_const_int(1), + /* K88 */ be_nested_str_weak(B2), + /* K89 */ be_nested_str_weak(get_noc), + /* K90 */ be_const_int(2), + /* K91 */ be_nested_str_weak(get_icac), + /* K92 */ be_nested_str_weak(ecdsa_sign_sha256), + /* K93 */ be_nested_str_weak(get_pk), + /* K94 */ be_nested_str_weak(Msg1), + /* K95 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20MSG1_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K96 */ be_nested_str_weak(SHA256), + /* K97 */ be_nested_str_weak(update), + /* K98 */ be_nested_str_weak(out), + /* K99 */ be_nested_str_weak(S2K_Info), + /* K100 */ be_nested_str_weak(get_ipk_group_key), + /* K101 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20SharedSecret_X20_X20_X3D_X20), + /* K102 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20s2k_salt_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K103 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20s2k_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K104 */ be_nested_str_weak(TBEData2_Nonce), + /* K105 */ be_nested_str_weak(encrypt), + /* K106 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20TBEData2Enc_X20_X20_X20_X3D_X20), + /* K107 */ be_nested_str_weak(Sigma2), + /* K108 */ be_nested_str_weak(responderRandom), + /* K109 */ be_nested_str_weak(responderSessionId), + /* K110 */ be_nested_str_weak(responderEphPubKey), + /* K111 */ be_nested_str_weak(encrypted2), + /* K112 */ be_nested_str_weak(MTR_X3A_X20sigma2_X3A_X20), + /* K113 */ be_nested_str_weak(inspect), + /* K114 */ be_nested_str_weak(_Msg2), + /* K115 */ be_nested_str_weak(MTR_X3A_X20sigma2_raw_X3A_X20), + }), + be_str_weak(parse_Sigma1), + &be_const_str_solidified, + ( &(const binstruction[551]) { /* code */ + 0xA4120000, // 0000 IMPORT R4 K0 + 0x88140301, // 0001 GETMBR R5 R1 K1 + 0x541A002F, // 0002 LDINT R6 48 + 0x20140A06, // 0003 NE R5 R5 R6 + 0x74160005, // 0004 JMPT R5 #000B + 0x88140302, // 0005 GETMBR R5 R1 K2 + 0x20140B03, // 0006 NE R5 R5 K3 + 0x74160002, // 0007 JMPT R5 #000B + 0x88140304, // 0008 GETMBR R5 R1 K4 + 0x20140B03, // 0009 NE R5 R5 K3 + 0x78160000, // 000A JMPF R5 #000C + 0xB0060B06, // 000B RAISE 1 K5 K6 + 0xB8160E00, // 000C GETNGBL R5 K7 + 0x8C140B08, // 000D GETMET R5 R5 K8 + 0x7C140200, // 000E CALL R5 1 + 0x8C140B09, // 000F GETMET R5 R5 K9 + 0x881C030A, // 0010 GETMBR R7 R1 K10 + 0x8820030B, // 0011 GETMBR R8 R1 K11 + 0x7C140600, // 0012 CALL R5 3 + 0x88180B0D, // 0013 GETMBR R6 R5 K13 + 0x90021806, // 0014 SETMBR R0 K12 R6 + 0x8C18010E, // 0015 GETMET R6 R0 K14 + 0x88200B0F, // 0016 GETMBR R8 R5 K15 + 0x88240B10, // 0017 GETMBR R9 R5 K16 + 0x7C180600, // 0018 CALL R6 3 + 0x4C1C0000, // 0019 LDNIL R7 + 0x1C1C0C07, // 001A EQ R7 R6 R7 + 0x781E0000, // 001B JMPF R7 #001D + 0xB0062312, // 001C RAISE 1 K17 K18 + 0x881C0313, // 001D GETMBR R7 R1 K19 + 0x901A2607, // 001E SETMBR R6 K19 R7 + 0x8C1C0D14, // 001F GETMET R7 R6 K20 + 0xB8260E00, // 0020 GETNGBL R9 K7 + 0x88241315, // 0021 GETMBR R9 R9 K21 + 0x88241316, // 0022 GETMBR R9 R9 K22 + 0x7C1C0400, // 0023 CALL R7 2 + 0x881C0317, // 0024 GETMBR R7 R1 K23 + 0x781E0004, // 0025 JMPF R7 #002B + 0x881C0118, // 0026 GETMBR R7 R0 K24 + 0x881C0F19, // 0027 GETMBR R7 R7 K25 + 0x8C1C0F1A, // 0028 GETMET R7 R7 K26 + 0x88240317, // 0029 GETMBR R9 R1 K23 + 0x7C1C0400, // 002A CALL R7 2 + 0x90062E06, // 002B SETMBR R1 K23 R6 + 0x881C0B1C, // 002C GETMBR R7 R5 K28 + 0x901A3607, // 002D SETMBR R6 K27 R7 + 0x881C0118, // 002E GETMBR R7 R0 K24 + 0x881C0F19, // 002F GETMBR R7 R7 K25 + 0x8C1C0F1E, // 0030 GETMET R7 R7 K30 + 0x7C1C0200, // 0031 CALL R7 1 + 0x901A3A07, // 0032 SETMBR R6 K29 R7 + 0x881C0D1D, // 0033 GETMBR R7 R6 K29 + 0x90023E07, // 0034 SETMBR R0 K31 R7 + 0x881C0B20, // 0035 GETMBR R7 R5 K32 + 0x4C200000, // 0036 LDNIL R8 + 0x201C0E08, // 0037 NE R7 R7 R8 + 0x781E00F2, // 0038 JMPF R7 #012C + 0x881C0B21, // 0039 GETMBR R7 R5 K33 + 0x4C200000, // 003A LDNIL R8 + 0x201C0E08, // 003B NE R7 R7 R8 + 0x781E00EE, // 003C JMPF R7 #012C + 0x881C0D22, // 003D GETMBR R7 R6 K34 + 0x4C200000, // 003E LDNIL R8 + 0x201C0E08, // 003F NE R7 R7 R8 + 0x781E00EA, // 0040 JMPF R7 #012C + 0x881C0B10, // 0041 GETMBR R7 R5 K16 + 0x88200B20, // 0042 GETMBR R8 R5 K32 + 0x001C0E08, // 0043 ADD R7 R7 R8 + 0x60200015, // 0044 GETGBL R8 G21 + 0x7C200000, // 0045 CALL R8 0 + 0x8C201123, // 0046 GETMET R8 R8 K35 + 0x58280024, // 0047 LDCONST R10 K36 + 0x7C200400, // 0048 CALL R8 2 + 0x8C240925, // 0049 GETMET R9 R4 K37 + 0x7C240200, // 004A CALL R9 1 + 0x8C241326, // 004B GETMET R9 R9 K38 + 0x882C0D22, // 004C GETMBR R11 R6 K34 + 0x5C300E00, // 004D MOVE R12 R7 + 0x5C341000, // 004E MOVE R13 R8 + 0x543A000F, // 004F LDINT R14 16 + 0x7C240A00, // 0050 CALL R9 5 + 0x60280015, // 0051 GETGBL R10 G21 + 0x7C280000, // 0052 CALL R10 0 + 0x8C281523, // 0053 GETMET R10 R10 K35 + 0x58300027, // 0054 LDCONST R12 K39 + 0x7C280400, // 0055 CALL R10 2 + 0x542DFFEE, // 0056 LDINT R11 -17 + 0x402E060B, // 0057 CONNECT R11 K3 R11 + 0x88300B21, // 0058 GETMBR R12 R5 K33 + 0x942C180B, // 0059 GETIDX R11 R12 R11 + 0x5435FFEF, // 005A LDINT R13 -16 + 0x40341B28, // 005B CONNECT R13 R13 K40 + 0x88380B21, // 005C GETMBR R14 R5 K33 + 0x94301C0D, // 005D GETIDX R12 R14 R13 + 0x8C3C0929, // 005E GETMET R15 R4 K41 + 0x5C441200, // 005F MOVE R17 R9 + 0x5C481400, // 0060 MOVE R18 R10 + 0x604C0015, // 0061 GETGBL R19 G21 + 0x7C4C0000, // 0062 CALL R19 0 + 0x6050000C, // 0063 GETGBL R20 G12 + 0x5C541600, // 0064 MOVE R21 R11 + 0x7C500200, // 0065 CALL R20 1 + 0x5456000F, // 0066 LDINT R21 16 + 0x7C3C0C00, // 0067 CALL R15 6 + 0x5C341E00, // 0068 MOVE R13 R15 + 0x8C3C1B2A, // 0069 GETMET R15 R13 K42 + 0x5C441600, // 006A MOVE R17 R11 + 0x7C3C0400, // 006B CALL R15 2 + 0x5C381E00, // 006C MOVE R14 R15 + 0x8C3C1B2B, // 006D GETMET R15 R13 K43 + 0x7C3C0200, // 006E CALL R15 1 + 0xB8425800, // 006F GETNGBL R16 K44 + 0x8C40212D, // 0070 GETMET R16 R16 K45 + 0x5848002E, // 0071 LDCONST R18 K46 + 0x584C002F, // 0072 LDCONST R19 K47 + 0x7C400600, // 0073 CALL R16 3 + 0xB8425800, // 0074 GETNGBL R16 K44 + 0x8C40212D, // 0075 GETMET R16 R16 K45 + 0x8C481331, // 0076 GETMET R18 R9 K49 + 0x7C480200, // 0077 CALL R18 1 + 0x004A6012, // 0078 ADD R18 K48 R18 + 0x584C002F, // 0079 LDCONST R19 K47 + 0x7C400600, // 007A CALL R16 3 + 0xB8425800, // 007B GETNGBL R16 K44 + 0x8C40212D, // 007C GETMET R16 R16 K45 + 0x8C481931, // 007D GETMET R18 R12 K49 + 0x7C480200, // 007E CALL R18 1 + 0x004A6412, // 007F ADD R18 K50 R18 + 0x584C002F, // 0080 LDCONST R19 K47 + 0x7C400600, // 0081 CALL R16 3 + 0xB8425800, // 0082 GETNGBL R16 K44 + 0x8C40212D, // 0083 GETMET R16 R16 K45 + 0x8C481D31, // 0084 GETMET R18 R14 K49 + 0x7C480200, // 0085 CALL R18 1 + 0x004A6612, // 0086 ADD R18 K51 R18 + 0x584C002F, // 0087 LDCONST R19 K47 + 0x7C400600, // 0088 CALL R16 3 + 0xB8425800, // 0089 GETNGBL R16 K44 + 0x8C40212D, // 008A GETMET R16 R16 K45 + 0x8C481F31, // 008B GETMET R18 R15 K49 + 0x7C480200, // 008C CALL R18 1 + 0x004A6812, // 008D ADD R18 K52 R18 + 0x584C002F, // 008E LDCONST R19 K47 + 0x7C400600, // 008F CALL R16 3 + 0xB8425800, // 0090 GETNGBL R16 K44 + 0x8C40212D, // 0091 GETMET R16 R16 K45 + 0x5848002E, // 0092 LDCONST R18 K46 + 0x584C002F, // 0093 LDCONST R19 K47 + 0x7C400600, // 0094 CALL R16 3 + 0x1C40180F, // 0095 EQ R16 R12 R15 + 0x78420092, // 0096 JMPF R16 #012A + 0x8C400936, // 0097 GETMET R16 R4 K54 + 0x544A000F, // 0098 LDINT R18 16 + 0x7C400400, // 0099 CALL R16 2 + 0x901A6A10, // 009A SETMBR R6 K53 R16 + 0x60400015, // 009B GETGBL R16 G21 + 0x7C400000, // 009C CALL R16 0 + 0x8C402123, // 009D GETMET R16 R16 K35 + 0x58480037, // 009E LDCONST R18 K55 + 0x7C400400, // 009F CALL R16 2 + 0x88440D35, // 00A0 GETMBR R17 R6 K53 + 0x00402011, // 00A1 ADD R16 R16 R17 + 0x88440B10, // 00A2 GETMBR R17 R5 K16 + 0x88480B20, // 00A3 GETMBR R18 R5 K32 + 0x00442212, // 00A4 ADD R17 R17 R18 + 0x8C480925, // 00A5 GETMET R18 R4 K37 + 0x7C480200, // 00A6 CALL R18 1 + 0x8C482526, // 00A7 GETMET R18 R18 K38 + 0x88500D22, // 00A8 GETMBR R20 R6 K34 + 0x5C542200, // 00A9 MOVE R21 R17 + 0x5C582000, // 00AA MOVE R22 R16 + 0x545E000F, // 00AB LDINT R23 16 + 0x7C480A00, // 00AC CALL R18 5 + 0x8C4C0929, // 00AD GETMET R19 R4 K41 + 0x5C542400, // 00AE MOVE R21 R18 + 0x60580015, // 00AF GETGBL R22 G21 + 0x7C580000, // 00B0 CALL R22 0 + 0x8C582D23, // 00B1 GETMET R22 R22 K35 + 0x58600038, // 00B2 LDCONST R24 K56 + 0x7C580400, // 00B3 CALL R22 2 + 0x605C0015, // 00B4 GETGBL R23 G21 + 0x7C5C0000, // 00B5 CALL R23 0 + 0x58600003, // 00B6 LDCONST R24 K3 + 0x5466000F, // 00B7 LDINT R25 16 + 0x7C4C0C00, // 00B8 CALL R19 6 + 0x8C50272B, // 00B9 GETMET R20 R19 K43 + 0x7C500200, // 00BA CALL R20 1 + 0xB8560E00, // 00BB GETNGBL R21 K7 + 0x8C542B39, // 00BC GETMET R21 R21 K57 + 0x7C540200, // 00BD CALL R21 1 + 0x88580D35, // 00BE GETMBR R22 R6 K53 + 0x90564016, // 00BF SETMBR R21 K32 R22 + 0x88580D1D, // 00C0 GETMBR R22 R6 K29 + 0x90567416, // 00C1 SETMBR R21 K58 R22 + 0x90567614, // 00C2 SETMBR R21 K59 R20 + 0x8C580925, // 00C3 GETMET R22 R4 K37 + 0x7C580200, // 00C4 CALL R22 1 + 0x8C582D26, // 00C5 GETMET R22 R22 K38 + 0x88600D22, // 00C6 GETMBR R24 R6 K34 + 0x88640B10, // 00C7 GETMBR R25 R5 K16 + 0x88680B20, // 00C8 GETMBR R26 R5 K32 + 0x0064321A, // 00C9 ADD R25 R25 R26 + 0x60680015, // 00CA GETGBL R26 G21 + 0x7C680000, // 00CB CALL R26 0 + 0x8C683523, // 00CC GETMET R26 R26 K35 + 0x5870003C, // 00CD LDCONST R28 K60 + 0x7C680400, // 00CE CALL R26 2 + 0x546E002F, // 00CF LDINT R27 48 + 0x7C580A00, // 00D0 CALL R22 5 + 0x545E000E, // 00D1 LDINT R23 15 + 0x405E0617, // 00D2 CONNECT R23 K3 R23 + 0x945C2C17, // 00D3 GETIDX R23 R22 R23 + 0x5462000F, // 00D4 LDINT R24 16 + 0x5466001E, // 00D5 LDINT R25 31 + 0x40603019, // 00D6 CONNECT R24 R24 R25 + 0x94602C18, // 00D7 GETIDX R24 R22 R24 + 0x5466001F, // 00D8 LDINT R25 32 + 0x546A002E, // 00D9 LDINT R26 47 + 0x4064321A, // 00DA CONNECT R25 R25 R26 + 0x94642C19, // 00DB GETIDX R25 R22 R25 + 0xB86A5800, // 00DC GETNGBL R26 K44 + 0x8C68353D, // 00DD GETMET R26 R26 K61 + 0x7C680200, // 00DE CALL R26 1 + 0x9468353E, // 00DF GETIDX R26 R26 K62 + 0xB86E5800, // 00E0 GETNGBL R27 K44 + 0x8C6C372D, // 00E1 GETMET R27 R27 K45 + 0x5874003F, // 00E2 LDCONST R29 K63 + 0x5878002F, // 00E3 LDCONST R30 K47 + 0x7C6C0600, // 00E4 CALL R27 3 + 0xB86E5800, // 00E5 GETNGBL R27 K44 + 0x8C6C372D, // 00E6 GETMET R27 R27 K45 + 0x8C742F31, // 00E7 GETMET R29 R23 K49 + 0x7C740200, // 00E8 CALL R29 1 + 0x0076801D, // 00E9 ADD R29 K64 R29 + 0x5878002F, // 00EA LDCONST R30 K47 + 0x7C6C0600, // 00EB CALL R27 3 + 0xB86E5800, // 00EC GETNGBL R27 K44 + 0x8C6C372D, // 00ED GETMET R27 R27 K45 + 0x8C743131, // 00EE GETMET R29 R24 K49 + 0x7C740200, // 00EF CALL R29 1 + 0x0076821D, // 00F0 ADD R29 K65 R29 + 0x5878002F, // 00F1 LDCONST R30 K47 + 0x7C6C0600, // 00F2 CALL R27 3 + 0xB86E5800, // 00F3 GETNGBL R27 K44 + 0x8C6C372D, // 00F4 GETMET R27 R27 K45 + 0x8C743331, // 00F5 GETMET R29 R25 K49 + 0x7C740200, // 00F6 CALL R29 1 + 0x0076841D, // 00F7 ADD R29 K66 R29 + 0x5878002F, // 00F8 LDCONST R30 K47 + 0x7C6C0600, // 00F9 CALL R27 3 + 0xB86E5800, // 00FA GETNGBL R27 K44 + 0x8C6C372D, // 00FB GETMET R27 R27 K45 + 0x5874003F, // 00FC LDCONST R29 K63 + 0x5878002F, // 00FD LDCONST R30 K47 + 0x7C6C0600, // 00FE CALL R27 3 + 0x8C6C2B43, // 00FF GETMET R27 R21 K67 + 0x7C6C0200, // 0100 CALL R27 1 + 0x4C700000, // 0101 LDNIL R28 + 0x901A881C, // 0102 SETMBR R6 K68 R28 + 0xB8725800, // 0103 GETNGBL R28 K44 + 0x8C70392D, // 0104 GETMET R28 R28 K45 + 0x8C783731, // 0105 GETMET R30 R27 K49 + 0x7C780200, // 0106 CALL R30 1 + 0x007A8A1E, // 0107 ADD R30 K69 R30 + 0x587C002F, // 0108 LDCONST R31 K47 + 0x7C700600, // 0109 CALL R28 3 + 0x8C700346, // 010A GETMET R28 R1 K70 + 0x547A0032, // 010B LDINT R30 51 + 0x507C0200, // 010C LDBOOL R31 1 0 + 0x7C700600, // 010D CALL R28 3 + 0x8C743943, // 010E GETMET R29 R28 K67 + 0x5C7C3600, // 010F MOVE R31 R27 + 0x7C740400, // 0110 CALL R29 2 + 0x88780147, // 0111 GETMBR R30 R0 K71 + 0x8C783D48, // 0112 GETMET R30 R30 K72 + 0x5C803A00, // 0113 MOVE R32 R29 + 0x5C840400, // 0114 MOVE R33 R2 + 0x5C880600, // 0115 MOVE R34 R3 + 0x888C3949, // 0116 GETMBR R35 R28 K73 + 0x7C780A00, // 0117 CALL R30 5 + 0x8C780D4A, // 0118 GETMET R30 R6 K74 + 0x7C780200, // 0119 CALL R30 1 + 0x8C780D4B, // 011A GETMET R30 R6 K75 + 0x5C802E00, // 011B MOVE R32 R23 + 0x5C843000, // 011C MOVE R33 R24 + 0x5C883200, // 011D MOVE R34 R25 + 0x5C8C3400, // 011E MOVE R35 R26 + 0x7C780A00, // 011F CALL R30 5 + 0x8C780D4C, // 0120 GETMET R30 R6 K76 + 0x50800200, // 0121 LDBOOL R32 1 0 + 0x7C780400, // 0122 CALL R30 2 + 0x8C780D4D, // 0123 GETMET R30 R6 K77 + 0x7C780200, // 0124 CALL R30 1 + 0x8C780D4E, // 0125 GETMET R30 R6 K78 + 0x7C780200, // 0126 CALL R30 1 + 0x50780200, // 0127 LDBOOL R30 1 0 + 0x80043C00, // 0128 RET 1 R30 + 0x70020001, // 0129 JMP #012C + 0x4C400000, // 012A LDNIL R16 + 0x90164010, // 012B SETMBR R5 K32 R16 + 0x881C0B20, // 012C GETMBR R7 R5 K32 + 0x4C200000, // 012D LDNIL R8 + 0x1C1C0E08, // 012E EQ R7 R7 R8 + 0x741E0003, // 012F JMPT R7 #0134 + 0x881C0B21, // 0130 GETMBR R7 R5 K33 + 0x4C200000, // 0131 LDNIL R8 + 0x1C1C0E08, // 0132 EQ R7 R7 R8 + 0x781E00F0, // 0133 JMPF R7 #0225 + 0x8C1C0936, // 0134 GETMET R7 R4 K54 + 0x5426000F, // 0135 LDINT R9 16 + 0x7C1C0400, // 0136 CALL R7 2 + 0x901A6A07, // 0137 SETMBR R6 K53 R7 + 0x8C1C0936, // 0138 GETMET R7 R4 K54 + 0x5426001F, // 0139 LDINT R9 32 + 0x7C1C0400, // 013A CALL R7 2 + 0x90029E07, // 013B SETMBR R0 K79 R7 + 0x8C1C0951, // 013C GETMET R7 R4 K81 + 0x7C1C0200, // 013D CALL R7 1 + 0x8C1C0F52, // 013E GETMET R7 R7 K82 + 0x8824014F, // 013F GETMBR R9 R0 K79 + 0x7C1C0400, // 0140 CALL R7 2 + 0x9002A007, // 0141 SETMBR R0 K80 R7 + 0x8C1C0936, // 0142 GETMET R7 R4 K54 + 0x5426001F, // 0143 LDINT R9 32 + 0x7C1C0400, // 0144 CALL R7 2 + 0x8C200951, // 0145 GETMET R8 R4 K81 + 0x7C200200, // 0146 CALL R8 1 + 0x8C201153, // 0147 GETMET R8 R8 K83 + 0x8828014F, // 0148 GETMBR R10 R0 K79 + 0x882C0B0D, // 0149 GETMBR R11 R5 K13 + 0x7C200600, // 014A CALL R8 3 + 0x901A4408, // 014B SETMBR R6 K34 R8 + 0xB8220E00, // 014C GETNGBL R8 K7 + 0x88201154, // 014D GETMBR R8 R8 K84 + 0x8C201155, // 014E GETMET R8 R8 K85 + 0x7C200200, // 014F CALL R8 1 + 0x8C241156, // 0150 GETMET R9 R8 K86 + 0x582C0057, // 0151 LDCONST R11 K87 + 0xB8320E00, // 0152 GETNGBL R12 K7 + 0x88301954, // 0153 GETMBR R12 R12 K84 + 0x88301958, // 0154 GETMBR R12 R12 K88 + 0x8C340D59, // 0155 GETMET R13 R6 K89 + 0x7C340200, // 0156 CALL R13 1 + 0x7C240800, // 0157 CALL R9 4 + 0x8C241156, // 0158 GETMET R9 R8 K86 + 0x582C005A, // 0159 LDCONST R11 K90 + 0xB8320E00, // 015A GETNGBL R12 K7 + 0x88301954, // 015B GETMBR R12 R12 K84 + 0x88301958, // 015C GETMBR R12 R12 K88 + 0x8C340D5B, // 015D GETMET R13 R6 K91 + 0x7C340200, // 015E CALL R13 1 + 0x7C240800, // 015F CALL R9 4 + 0x8C241156, // 0160 GETMET R9 R8 K86 + 0x582C002F, // 0161 LDCONST R11 K47 + 0xB8320E00, // 0162 GETNGBL R12 K7 + 0x88301954, // 0163 GETMBR R12 R12 K84 + 0x88301958, // 0164 GETMBR R12 R12 K88 + 0x88340150, // 0165 GETMBR R13 R0 K80 + 0x7C240800, // 0166 CALL R9 4 + 0x8C241156, // 0167 GETMET R9 R8 K86 + 0x542E0003, // 0168 LDINT R11 4 + 0xB8320E00, // 0169 GETNGBL R12 K7 + 0x88301954, // 016A GETMBR R12 R12 K84 + 0x88301958, // 016B GETMBR R12 R12 K88 + 0x88340B0D, // 016C GETMBR R13 R5 K13 + 0x7C240800, // 016D CALL R9 4 + 0x8C240951, // 016E GETMET R9 R4 K81 + 0x7C240200, // 016F CALL R9 1 + 0x8C24135C, // 0170 GETMET R9 R9 K92 + 0x8C2C0D5D, // 0171 GETMET R11 R6 K93 + 0x7C2C0200, // 0172 CALL R11 1 + 0x8C301143, // 0173 GETMET R12 R8 K67 + 0x7C300200, // 0174 CALL R12 1 + 0x7C240600, // 0175 CALL R9 3 + 0xB82A0E00, // 0176 GETNGBL R10 K7 + 0x88281554, // 0177 GETMBR R10 R10 K84 + 0x8C281555, // 0178 GETMET R10 R10 K85 + 0x7C280200, // 0179 CALL R10 1 + 0x8C2C1556, // 017A GETMET R11 R10 K86 + 0x58340057, // 017B LDCONST R13 K87 + 0xB83A0E00, // 017C GETNGBL R14 K7 + 0x88381D54, // 017D GETMBR R14 R14 K84 + 0x88381D58, // 017E GETMBR R14 R14 K88 + 0x8C3C0D59, // 017F GETMET R15 R6 K89 + 0x7C3C0200, // 0180 CALL R15 1 + 0x7C2C0800, // 0181 CALL R11 4 + 0x8C2C1556, // 0182 GETMET R11 R10 K86 + 0x5834005A, // 0183 LDCONST R13 K90 + 0xB83A0E00, // 0184 GETNGBL R14 K7 + 0x88381D54, // 0185 GETMBR R14 R14 K84 + 0x88381D58, // 0186 GETMBR R14 R14 K88 + 0x8C3C0D5B, // 0187 GETMET R15 R6 K91 + 0x7C3C0200, // 0188 CALL R15 1 + 0x7C2C0800, // 0189 CALL R11 4 + 0x8C2C1556, // 018A GETMET R11 R10 K86 + 0x5834002F, // 018B LDCONST R13 K47 + 0xB83A0E00, // 018C GETNGBL R14 K7 + 0x88381D54, // 018D GETMBR R14 R14 K84 + 0x88381D58, // 018E GETMBR R14 R14 K88 + 0x5C3C1200, // 018F MOVE R15 R9 + 0x7C2C0800, // 0190 CALL R11 4 + 0x8C2C1556, // 0191 GETMET R11 R10 K86 + 0x54360003, // 0192 LDINT R13 4 + 0xB83A0E00, // 0193 GETNGBL R14 K7 + 0x88381D54, // 0194 GETMBR R14 R14 K84 + 0x88381D58, // 0195 GETMBR R14 R14 K88 + 0x883C0D35, // 0196 GETMBR R15 R6 K53 + 0x7C2C0800, // 0197 CALL R11 4 + 0xB82E5800, // 0198 GETNGBL R11 K44 + 0x8C2C172D, // 0199 GETMET R11 R11 K45 + 0x5834002E, // 019A LDCONST R13 K46 + 0x5838002F, // 019B LDCONST R14 K47 + 0x7C2C0600, // 019C CALL R11 3 + 0x882C0B5E, // 019D GETMBR R11 R5 K94 + 0x901A880B, // 019E SETMBR R6 K68 R11 + 0xB82E5800, // 019F GETNGBL R11 K44 + 0x8C2C172D, // 01A0 GETMET R11 R11 K45 + 0x88340D44, // 01A1 GETMBR R13 R6 K68 + 0x8C341B31, // 01A2 GETMET R13 R13 K49 + 0x7C340200, // 01A3 CALL R13 1 + 0x0036BE0D, // 01A4 ADD R13 K95 R13 + 0x5838002F, // 01A5 LDCONST R14 K47 + 0x7C2C0600, // 01A6 CALL R11 3 + 0x8C2C0960, // 01A7 GETMET R11 R4 K96 + 0x7C2C0200, // 01A8 CALL R11 1 + 0x8C2C1761, // 01A9 GETMET R11 R11 K97 + 0x88340D44, // 01AA GETMBR R13 R6 K68 + 0x7C2C0400, // 01AB CALL R11 2 + 0x8C2C1762, // 01AC GETMET R11 R11 K98 + 0x7C2C0200, // 01AD CALL R11 1 + 0x60300015, // 01AE GETGBL R12 G21 + 0x7C300000, // 01AF CALL R12 0 + 0x8C301923, // 01B0 GETMET R12 R12 K35 + 0x88380163, // 01B1 GETMBR R14 R0 K99 + 0x7C300400, // 01B2 CALL R12 2 + 0x8C340D64, // 01B3 GETMET R13 R6 K100 + 0x7C340200, // 01B4 CALL R13 1 + 0x00341A07, // 01B5 ADD R13 R13 R7 + 0x88380150, // 01B6 GETMBR R14 R0 K80 + 0x00341A0E, // 01B7 ADD R13 R13 R14 + 0x00341A0B, // 01B8 ADD R13 R13 R11 + 0x8C380925, // 01B9 GETMET R14 R4 K37 + 0x7C380200, // 01BA CALL R14 1 + 0x8C381D26, // 01BB GETMET R14 R14 K38 + 0x88400D22, // 01BC GETMBR R16 R6 K34 + 0x5C441A00, // 01BD MOVE R17 R13 + 0x5C481800, // 01BE MOVE R18 R12 + 0x544E000F, // 01BF LDINT R19 16 + 0x7C380A00, // 01C0 CALL R14 5 + 0xB83E5800, // 01C1 GETNGBL R15 K44 + 0x8C3C1F2D, // 01C2 GETMET R15 R15 K45 + 0x88440D22, // 01C3 GETMBR R17 R6 K34 + 0x8C442331, // 01C4 GETMET R17 R17 K49 + 0x7C440200, // 01C5 CALL R17 1 + 0x0046CA11, // 01C6 ADD R17 K101 R17 + 0x5848002F, // 01C7 LDCONST R18 K47 + 0x7C3C0600, // 01C8 CALL R15 3 + 0xB83E5800, // 01C9 GETNGBL R15 K44 + 0x8C3C1F2D, // 01CA GETMET R15 R15 K45 + 0x8C441B31, // 01CB GETMET R17 R13 K49 + 0x7C440200, // 01CC CALL R17 1 + 0x0046CC11, // 01CD ADD R17 K102 R17 + 0x5848002F, // 01CE LDCONST R18 K47 + 0x7C3C0600, // 01CF CALL R15 3 + 0xB83E5800, // 01D0 GETNGBL R15 K44 + 0x8C3C1F2D, // 01D1 GETMET R15 R15 K45 + 0x8C441D31, // 01D2 GETMET R17 R14 K49 + 0x7C440200, // 01D3 CALL R17 1 + 0x0046CE11, // 01D4 ADD R17 K103 R17 + 0x5848002F, // 01D5 LDCONST R18 K47 + 0x7C3C0600, // 01D6 CALL R15 3 + 0x8C3C1543, // 01D7 GETMET R15 R10 K67 + 0x7C3C0200, // 01D8 CALL R15 1 + 0x8C400929, // 01D9 GETMET R16 R4 K41 + 0x5C481C00, // 01DA MOVE R18 R14 + 0x604C0015, // 01DB GETGBL R19 G21 + 0x7C4C0000, // 01DC CALL R19 0 + 0x8C4C2723, // 01DD GETMET R19 R19 K35 + 0x88540168, // 01DE GETMBR R21 R0 K104 + 0x7C4C0400, // 01DF CALL R19 2 + 0x60500015, // 01E0 GETGBL R20 G21 + 0x7C500000, // 01E1 CALL R20 0 + 0x6054000C, // 01E2 GETGBL R21 G12 + 0x5C581E00, // 01E3 MOVE R22 R15 + 0x7C540200, // 01E4 CALL R21 1 + 0x545A000F, // 01E5 LDINT R22 16 + 0x7C400C00, // 01E6 CALL R16 6 + 0x8C442169, // 01E7 GETMET R17 R16 K105 + 0x5C4C1E00, // 01E8 MOVE R19 R15 + 0x7C440400, // 01E9 CALL R17 2 + 0x8C48212B, // 01EA GETMET R18 R16 K43 + 0x7C480200, // 01EB CALL R18 1 + 0x00442212, // 01EC ADD R17 R17 R18 + 0xB84A5800, // 01ED GETNGBL R18 K44 + 0x8C48252D, // 01EE GETMET R18 R18 K45 + 0x8C502331, // 01EF GETMET R20 R17 K49 + 0x7C500200, // 01F0 CALL R20 1 + 0x0052D414, // 01F1 ADD R20 K106 R20 + 0x5854002F, // 01F2 LDCONST R21 K47 + 0x7C480600, // 01F3 CALL R18 3 + 0xB84A5800, // 01F4 GETNGBL R18 K44 + 0x8C48252D, // 01F5 GETMET R18 R18 K45 + 0x5850002E, // 01F6 LDCONST R20 K46 + 0x5854002F, // 01F7 LDCONST R21 K47 + 0x7C480600, // 01F8 CALL R18 3 + 0xB84A0E00, // 01F9 GETNGBL R18 K7 + 0x8C48256B, // 01FA GETMET R18 R18 K107 + 0x7C480200, // 01FB CALL R18 1 + 0x904AD807, // 01FC SETMBR R18 K108 R7 + 0x884C011F, // 01FD GETMBR R19 R0 K31 + 0x904ADA13, // 01FE SETMBR R18 K109 R19 + 0x884C0150, // 01FF GETMBR R19 R0 K80 + 0x904ADC13, // 0200 SETMBR R18 K110 R19 + 0x904ADE11, // 0201 SETMBR R18 K111 R17 + 0xB84E5800, // 0202 GETNGBL R19 K44 + 0x8C4C272D, // 0203 GETMET R19 R19 K45 + 0xB8560E00, // 0204 GETNGBL R21 K7 + 0x8C542B71, // 0205 GETMET R21 R21 K113 + 0x5C5C2400, // 0206 MOVE R23 R18 + 0x7C540400, // 0207 CALL R21 2 + 0x0056E015, // 0208 ADD R21 K112 R21 + 0x5858002F, // 0209 LDCONST R22 K47 + 0x7C4C0600, // 020A CALL R19 3 + 0x8C4C2543, // 020B GETMET R19 R18 K67 + 0x7C4C0200, // 020C CALL R19 1 + 0x901AE413, // 020D SETMBR R6 K114 R19 + 0xB8525800, // 020E GETNGBL R20 K44 + 0x8C50292D, // 020F GETMET R20 R20 K45 + 0x8C582731, // 0210 GETMET R22 R19 K49 + 0x7C580200, // 0211 CALL R22 1 + 0x005AE616, // 0212 ADD R22 K115 R22 + 0x585C002F, // 0213 LDCONST R23 K47 + 0x7C500600, // 0214 CALL R20 3 + 0x8C500346, // 0215 GETMET R20 R1 K70 + 0x545A0030, // 0216 LDINT R22 49 + 0x505C0200, // 0217 LDBOOL R23 1 0 + 0x7C500600, // 0218 CALL R20 3 + 0x8C542943, // 0219 GETMET R21 R20 K67 + 0x5C5C2600, // 021A MOVE R23 R19 + 0x7C540400, // 021B CALL R21 2 + 0x88580147, // 021C GETMBR R22 R0 K71 + 0x8C582D48, // 021D GETMET R22 R22 K72 + 0x5C602A00, // 021E MOVE R24 R21 + 0x5C640400, // 021F MOVE R25 R2 + 0x5C680600, // 0220 MOVE R26 R3 + 0x886C2949, // 0221 GETMBR R27 R20 K73 + 0x7C580A00, // 0222 CALL R22 5 + 0x50580200, // 0223 LDBOOL R22 1 0 + 0x80042C00, // 0224 RET 1 R22 + 0x501C0200, // 0225 LDBOOL R7 1 0 + 0x80040E00, // 0226 RET 1 R7 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: parse_Pake3 +********************************************************************/ +be_local_closure(Matter_Commisioning_Context_parse_Pake3, /* name */ + be_nested_proto( + 18, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[45]) { /* constants */ + /* K0 */ be_nested_str_weak(crypto), + /* K1 */ be_nested_str_weak(opcode), + /* K2 */ be_nested_str_weak(local_session_id), + /* K3 */ be_const_int(0), + /* K4 */ be_nested_str_weak(protocol_id), + /* K5 */ be_nested_str_weak(protocol_error), + /* K6 */ be_nested_str_weak(invalid_X20Pake3_X20message), + /* K7 */ be_nested_str_weak(matter), + /* K8 */ be_nested_str_weak(Pake3), + /* K9 */ be_nested_str_weak(parse), + /* K10 */ be_nested_str_weak(raw), + /* K11 */ be_nested_str_weak(app_payload_idx), + /* K12 */ be_nested_str_weak(cA), + /* K13 */ be_nested_str_weak(tasmota), + /* K14 */ be_nested_str_weak(log), + /* K15 */ be_nested_str_weak(MTR_X3A_X20received_X20cA_X3D), + /* K16 */ be_nested_str_weak(tohex), + /* K17 */ be_const_int(3), + /* K18 */ be_nested_str_weak(spake), + /* K19 */ be_nested_str_weak(invalid_X20cA_X20received), + /* K20 */ be_nested_str_weak(session_timestamp), + /* K21 */ be_nested_str_weak(rtc), + /* K22 */ be_nested_str_weak(utc), + /* K23 */ be_nested_str_weak(HKDF_SHA256), + /* K24 */ be_nested_str_weak(derive), + /* K25 */ be_nested_str_weak(Ke), + /* K26 */ be_nested_str_weak(fromstring), + /* K27 */ be_nested_str_weak(SEKeys_Info), + /* K28 */ be_nested_str_weak(I2RKey), + /* K29 */ be_nested_str_weak(R2IKey), + /* K30 */ be_nested_str_weak(AttestationChallenge), + /* K31 */ be_nested_str_weak(MTR_X3A_X20_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A), + /* K32 */ be_nested_str_weak(MTR_X3A_X20session_keys_X3D), + /* K33 */ be_nested_str_weak(MTR_X3A_X20I2RKey_X20_X20_X20_X20_X20_X20_X3D), + /* K34 */ be_nested_str_weak(MTR_X3A_X20R2IKey_X20_X20_X20_X20_X20_X20_X3D), + /* K35 */ be_nested_str_weak(MTR_X3A_X20AC_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), + /* K36 */ be_nested_str_weak(build_response), + /* K37 */ be_nested_str_weak(add), + /* K38 */ be_const_int(2), + /* K39 */ be_nested_str_weak(encode), + /* K40 */ be_nested_str_weak(responder), + /* K41 */ be_nested_str_weak(send_response), + /* K42 */ be_nested_str_weak(add_session), + /* K43 */ be_nested_str_weak(future_local_session_id), + /* K44 */ be_nested_str_weak(future_initiator_session_id), + }), + be_str_weak(parse_Pake3), + &be_const_str_solidified, + ( &(const binstruction[146]) { /* code */ + 0xA4120000, // 0000 IMPORT R4 K0 + 0x88140301, // 0001 GETMBR R5 R1 K1 + 0x541A0023, // 0002 LDINT R6 36 + 0x20140A06, // 0003 NE R5 R5 R6 + 0x74160005, // 0004 JMPT R5 #000B + 0x88140302, // 0005 GETMBR R5 R1 K2 + 0x20140B03, // 0006 NE R5 R5 K3 + 0x74160002, // 0007 JMPT R5 #000B + 0x88140304, // 0008 GETMBR R5 R1 K4 + 0x20140B03, // 0009 NE R5 R5 K3 + 0x78160000, // 000A JMPF R5 #000C + 0xB0060B06, // 000B RAISE 1 K5 K6 + 0xB8160E00, // 000C GETNGBL R5 K7 + 0x8C140B08, // 000D GETMET R5 R5 K8 + 0x7C140200, // 000E CALL R5 1 + 0x8C140B09, // 000F GETMET R5 R5 K9 + 0x881C030A, // 0010 GETMBR R7 R1 K10 + 0x8820030B, // 0011 GETMBR R8 R1 K11 + 0x7C140600, // 0012 CALL R5 3 + 0x88180B0C, // 0013 GETMBR R6 R5 K12 + 0x90021806, // 0014 SETMBR R0 K12 R6 + 0xB81A1A00, // 0015 GETNGBL R6 K13 + 0x8C180D0E, // 0016 GETMET R6 R6 K14 + 0x8820010C, // 0017 GETMBR R8 R0 K12 + 0x8C201110, // 0018 GETMET R8 R8 K16 + 0x7C200200, // 0019 CALL R8 1 + 0x00221E08, // 001A ADD R8 K15 R8 + 0x58240011, // 001B LDCONST R9 K17 + 0x7C180600, // 001C CALL R6 3 + 0x8818010C, // 001D GETMBR R6 R0 K12 + 0x881C0112, // 001E GETMBR R7 R0 K18 + 0x881C0F0C, // 001F GETMBR R7 R7 K12 + 0x20180C07, // 0020 NE R6 R6 R7 + 0x781A0000, // 0021 JMPF R6 #0023 + 0xB0060B13, // 0022 RAISE 1 K5 K19 + 0xB81A1A00, // 0023 GETNGBL R6 K13 + 0x8C180D15, // 0024 GETMET R6 R6 K21 + 0x7C180200, // 0025 CALL R6 1 + 0x94180D16, // 0026 GETIDX R6 R6 K22 + 0x90022806, // 0027 SETMBR R0 K20 R6 + 0x8C180917, // 0028 GETMET R6 R4 K23 + 0x7C180200, // 0029 CALL R6 1 + 0x8C180D18, // 002A GETMET R6 R6 K24 + 0x88200119, // 002B GETMBR R8 R0 K25 + 0x60240015, // 002C GETGBL R9 G21 + 0x7C240000, // 002D CALL R9 0 + 0x60280015, // 002E GETGBL R10 G21 + 0x7C280000, // 002F CALL R10 0 + 0x8C28151A, // 0030 GETMET R10 R10 K26 + 0x8830011B, // 0031 GETMBR R12 R0 K27 + 0x7C280400, // 0032 CALL R10 2 + 0x542E002F, // 0033 LDINT R11 48 + 0x7C180A00, // 0034 CALL R6 5 + 0x541E000E, // 0035 LDINT R7 15 + 0x401E0607, // 0036 CONNECT R7 K3 R7 + 0x941C0C07, // 0037 GETIDX R7 R6 R7 + 0x90023807, // 0038 SETMBR R0 K28 R7 + 0x541E000F, // 0039 LDINT R7 16 + 0x5422001E, // 003A LDINT R8 31 + 0x401C0E08, // 003B CONNECT R7 R7 R8 + 0x941C0C07, // 003C GETIDX R7 R6 R7 + 0x90023A07, // 003D SETMBR R0 K29 R7 + 0x541E001F, // 003E LDINT R7 32 + 0x5422002E, // 003F LDINT R8 47 + 0x401C0E08, // 0040 CONNECT R7 R7 R8 + 0x941C0C07, // 0041 GETIDX R7 R6 R7 + 0x90023C07, // 0042 SETMBR R0 K30 R7 + 0xB81E1A00, // 0043 GETNGBL R7 K13 + 0x8C1C0F0E, // 0044 GETMET R7 R7 K14 + 0x5824001F, // 0045 LDCONST R9 K31 + 0x58280011, // 0046 LDCONST R10 K17 + 0x7C1C0600, // 0047 CALL R7 3 + 0xB81E1A00, // 0048 GETNGBL R7 K13 + 0x8C1C0F0E, // 0049 GETMET R7 R7 K14 + 0x8C240D10, // 004A GETMET R9 R6 K16 + 0x7C240200, // 004B CALL R9 1 + 0x00264009, // 004C ADD R9 K32 R9 + 0x58280011, // 004D LDCONST R10 K17 + 0x7C1C0600, // 004E CALL R7 3 + 0xB81E1A00, // 004F GETNGBL R7 K13 + 0x8C1C0F0E, // 0050 GETMET R7 R7 K14 + 0x8824011C, // 0051 GETMBR R9 R0 K28 + 0x8C241310, // 0052 GETMET R9 R9 K16 + 0x7C240200, // 0053 CALL R9 1 + 0x00264209, // 0054 ADD R9 K33 R9 + 0x58280011, // 0055 LDCONST R10 K17 + 0x7C1C0600, // 0056 CALL R7 3 + 0xB81E1A00, // 0057 GETNGBL R7 K13 + 0x8C1C0F0E, // 0058 GETMET R7 R7 K14 + 0x8824011D, // 0059 GETMBR R9 R0 K29 + 0x8C241310, // 005A GETMET R9 R9 K16 + 0x7C240200, // 005B CALL R9 1 + 0x00264409, // 005C ADD R9 K34 R9 + 0x58280011, // 005D LDCONST R10 K17 + 0x7C1C0600, // 005E CALL R7 3 + 0xB81E1A00, // 005F GETNGBL R7 K13 + 0x8C1C0F0E, // 0060 GETMET R7 R7 K14 + 0x8824011E, // 0061 GETMBR R9 R0 K30 + 0x8C241310, // 0062 GETMET R9 R9 K16 + 0x7C240200, // 0063 CALL R9 1 + 0x00264609, // 0064 ADD R9 K35 R9 + 0x58280011, // 0065 LDCONST R10 K17 + 0x7C1C0600, // 0066 CALL R7 3 + 0xB81E1A00, // 0067 GETNGBL R7 K13 + 0x8C1C0F0E, // 0068 GETMET R7 R7 K14 + 0x5824001F, // 0069 LDCONST R9 K31 + 0x58280011, // 006A LDCONST R10 K17 + 0x7C1C0600, // 006B CALL R7 3 + 0x8C1C0324, // 006C GETMET R7 R1 K36 + 0x5426003F, // 006D LDINT R9 64 + 0x50280000, // 006E LDBOOL R10 0 0 + 0x7C1C0600, // 006F CALL R7 3 + 0x60200015, // 0070 GETGBL R8 G21 + 0x7C200000, // 0071 CALL R8 0 + 0x8C241125, // 0072 GETMET R9 R8 K37 + 0x582C0003, // 0073 LDCONST R11 K3 + 0x58300026, // 0074 LDCONST R12 K38 + 0x7C240600, // 0075 CALL R9 3 + 0x8C241125, // 0076 GETMET R9 R8 K37 + 0x582C0003, // 0077 LDCONST R11 K3 + 0x54320003, // 0078 LDINT R12 4 + 0x7C240600, // 0079 CALL R9 3 + 0x8C241125, // 007A GETMET R9 R8 K37 + 0x582C0003, // 007B LDCONST R11 K3 + 0x54320003, // 007C LDINT R12 4 + 0x7C240600, // 007D CALL R9 3 + 0x8C240F27, // 007E GETMET R9 R7 K39 + 0x5C2C1000, // 007F MOVE R11 R8 + 0x7C240400, // 0080 CALL R9 2 + 0x88280128, // 0081 GETMBR R10 R0 K40 + 0x8C281529, // 0082 GETMET R10 R10 K41 + 0x5C301200, // 0083 MOVE R12 R9 + 0x5C340400, // 0084 MOVE R13 R2 + 0x5C380600, // 0085 MOVE R14 R3 + 0x4C3C0000, // 0086 LDNIL R15 + 0x7C280A00, // 0087 CALL R10 5 + 0x88280128, // 0088 GETMBR R10 R0 K40 + 0x8C28152A, // 0089 GETMET R10 R10 K42 + 0x8830012B, // 008A GETMBR R12 R0 K43 + 0x8834012C, // 008B GETMBR R13 R0 K44 + 0x8838011C, // 008C GETMBR R14 R0 K28 + 0x883C011D, // 008D GETMBR R15 R0 K29 + 0x8840011E, // 008E GETMBR R16 R0 K30 + 0x88440114, // 008F GETMBR R17 R0 K20 + 0x7C280E00, // 0090 CALL R10 7 + 0x80000000, // 0091 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: process_incoming +********************************************************************/ +be_local_closure(Matter_Commisioning_Context_process_incoming, /* name */ + be_nested_proto( + 9, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[15]) { /* constants */ + /* K0 */ be_nested_str_weak(window_open), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(log), + /* K3 */ be_nested_str_weak(MTR_X3A_X20commissioning_X20not_X20open), + /* K4 */ be_const_int(2), + /* K5 */ be_nested_str_weak(MTR_X3A_X20received_X20message_X20), + /* K6 */ be_nested_str_weak(matter), + /* K7 */ be_nested_str_weak(inspect), + /* K8 */ be_const_int(3), + /* K9 */ be_nested_str_weak(opcode), + /* K10 */ be_nested_str_weak(parse_PBKDFParamRequest), + /* K11 */ be_nested_str_weak(parse_Pake1), + /* K12 */ be_nested_str_weak(parse_Pake3), + /* K13 */ be_nested_str_weak(parse_Sigma1), + /* K14 */ be_nested_str_weak(parse_Sigma3), + }), + be_str_weak(process_incoming), + &be_const_str_solidified, + ( &(const binstruction[74]) { /* code */ + 0x88100100, // 0000 GETMBR R4 R0 K0 + 0x74120006, // 0001 JMPT R4 #0009 + 0xB8120200, // 0002 GETNGBL R4 K1 + 0x8C100902, // 0003 GETMET R4 R4 K2 + 0x58180003, // 0004 LDCONST R6 K3 + 0x581C0004, // 0005 LDCONST R7 K4 + 0x7C100600, // 0006 CALL R4 3 + 0x50100000, // 0007 LDBOOL R4 0 0 + 0x80040800, // 0008 RET 1 R4 + 0xB8120200, // 0009 GETNGBL R4 K1 + 0x8C100902, // 000A GETMET R4 R4 K2 + 0xB81A0C00, // 000B GETNGBL R6 K6 + 0x8C180D07, // 000C GETMET R6 R6 K7 + 0x5C200200, // 000D MOVE R8 R1 + 0x7C180400, // 000E CALL R6 2 + 0x001A0A06, // 000F ADD R6 K5 R6 + 0x581C0008, // 0010 LDCONST R7 K8 + 0x7C100600, // 0011 CALL R4 3 + 0x88100309, // 0012 GETMBR R4 R1 K9 + 0x5416001F, // 0013 LDINT R5 32 + 0x1C100805, // 0014 EQ R4 R4 R5 + 0x78120006, // 0015 JMPF R4 #001D + 0x8C10010A, // 0016 GETMET R4 R0 K10 + 0x5C180200, // 0017 MOVE R6 R1 + 0x5C1C0400, // 0018 MOVE R7 R2 + 0x5C200600, // 0019 MOVE R8 R3 + 0x7C100800, // 001A CALL R4 4 + 0x80040800, // 001B RET 1 R4 + 0x7002002A, // 001C JMP #0048 + 0x88100309, // 001D GETMBR R4 R1 K9 + 0x54160021, // 001E LDINT R5 34 + 0x1C100805, // 001F EQ R4 R4 R5 + 0x78120006, // 0020 JMPF R4 #0028 + 0x8C10010B, // 0021 GETMET R4 R0 K11 + 0x5C180200, // 0022 MOVE R6 R1 + 0x5C1C0400, // 0023 MOVE R7 R2 + 0x5C200600, // 0024 MOVE R8 R3 + 0x7C100800, // 0025 CALL R4 4 + 0x80040800, // 0026 RET 1 R4 + 0x7002001F, // 0027 JMP #0048 + 0x88100309, // 0028 GETMBR R4 R1 K9 + 0x54160023, // 0029 LDINT R5 36 + 0x1C100805, // 002A EQ R4 R4 R5 + 0x78120006, // 002B JMPF R4 #0033 + 0x8C10010C, // 002C GETMET R4 R0 K12 + 0x5C180200, // 002D MOVE R6 R1 + 0x5C1C0400, // 002E MOVE R7 R2 + 0x5C200600, // 002F MOVE R8 R3 + 0x7C100800, // 0030 CALL R4 4 + 0x80040800, // 0031 RET 1 R4 + 0x70020014, // 0032 JMP #0048 + 0x88100309, // 0033 GETMBR R4 R1 K9 + 0x5416002F, // 0034 LDINT R5 48 + 0x1C100805, // 0035 EQ R4 R4 R5 + 0x78120006, // 0036 JMPF R4 #003E + 0x8C10010D, // 0037 GETMET R4 R0 K13 + 0x5C180200, // 0038 MOVE R6 R1 + 0x5C1C0400, // 0039 MOVE R7 R2 + 0x5C200600, // 003A MOVE R8 R3 + 0x7C100800, // 003B CALL R4 4 + 0x80040800, // 003C RET 1 R4 + 0x70020009, // 003D JMP #0048 + 0x88100309, // 003E GETMBR R4 R1 K9 + 0x54160031, // 003F LDINT R5 50 + 0x1C100805, // 0040 EQ R4 R4 R5 + 0x78120005, // 0041 JMPF R4 #0048 + 0x8C10010E, // 0042 GETMET R4 R0 K14 + 0x5C180200, // 0043 MOVE R6 R1 + 0x5C1C0400, // 0044 MOVE R7 R2 + 0x5C200600, // 0045 MOVE R8 R3 + 0x7C100800, // 0046 CALL R4 4 + 0x80040800, // 0047 RET 1 R4 + 0x50100000, // 0048 LDBOOL R4 0 0 + 0x80040800, // 0049 RET 1 R4 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_Commisioning_Context +********************************************************************/ +be_local_class(Matter_Commisioning_Context, + 21, + NULL, + be_nested_map(36, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(parse_PBKDFParamRequest, -1), be_const_closure(Matter_Commisioning_Context_parse_PBKDFParamRequest_closure) }, + { be_const_key_weak(cA, 32), be_const_var(10) }, + { be_const_key_weak(PBKDFParamRequest, -1), be_const_var(5) }, + { be_const_key_weak(parse_Pake3, 20), be_const_closure(Matter_Commisioning_Context_parse_Pake3_closure) }, + { be_const_key_weak(cB, -1), be_const_var(11) }, + { be_const_key_weak(spake, -1), be_const_var(2) }, + { be_const_key_weak(find_session_by_destination_id, 2), be_const_closure(Matter_Commisioning_Context_find_session_by_destination_id_closure) }, + { be_const_key_weak(R2IKey, -1), be_const_var(18) }, + { be_const_key_weak(Ke, -1), be_const_var(12) }, + { be_const_key_weak(parse_Sigma1, -1), be_const_closure(Matter_Commisioning_Context_parse_Sigma1_closure) }, + { be_const_key_weak(SEKeys_Info, -1), be_nested_str_weak(SessionKeys) }, + { be_const_key_weak(I2RKey, -1), be_const_var(17) }, + { be_const_key_weak(ResponderEph_priv, -1), be_const_var(13) }, + { be_const_key_weak(parse_Pake1, -1), be_const_closure(Matter_Commisioning_Context_parse_Pake1_closure) }, + { be_const_key_weak(AttestationChallenge, -1), be_const_var(19) }, + { be_const_key_weak(init, 3), be_const_closure(Matter_Commisioning_Context_init_closure) }, + { be_const_key_weak(ResponderEph_pub, 6), be_const_var(14) }, + { be_const_key_weak(initiatorEph_pub, -1), be_const_var(15) }, + { be_const_key_weak(window_open, -1), be_const_var(20) }, + { be_const_key_weak(session_timestamp, 26), be_const_var(16) }, + { be_const_key_weak(future_local_session_id, 34), be_const_var(4) }, + { be_const_key_weak(Matter_Context_Prefix, 27), be_nested_str_weak(CHIP_X20PAKE_X20V1_X20Commissioning) }, + { be_const_key_weak(pA, 30), be_const_var(8) }, + { be_const_key_weak(pB, -1), be_const_var(9) }, + { be_const_key_weak(TBEData2_Nonce, -1), be_nested_str_weak(NCASE_Sigma2N) }, + { be_const_key_weak(future_initiator_session_id, -1), be_const_var(3) }, + { be_const_key_weak(PBKDFParamResponse, -1), be_const_var(6) }, + { be_const_key_weak(every_second, -1), be_const_closure(Matter_Commisioning_Context_every_second_closure) }, + { be_const_key_weak(y, 19), be_const_var(7) }, + { be_const_key_weak(parse_Sigma3, 8), be_const_closure(Matter_Commisioning_Context_parse_Sigma3_closure) }, + { be_const_key_weak(S2K_Info, -1), be_nested_str_weak(Sigma2) }, + { be_const_key_weak(TBEData3_Nonce, 9), be_nested_str_weak(NCASE_Sigma3N) }, + { be_const_key_weak(responder, -1), be_const_var(0) }, + { be_const_key_weak(S3K_Info, -1), be_nested_str_weak(Sigma3) }, + { be_const_key_weak(device, -1), be_const_var(1) }, + { be_const_key_weak(process_incoming, -1), be_const_closure(Matter_Commisioning_Context_process_incoming_closure) }, + })), + be_str_weak(Matter_Commisioning_Context) +); +/*******************************************************************/ + +void be_load_Matter_Commisioning_Context_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Commisioning_Context); + be_setglobal(vm, "Matter_Commisioning_Context"); + be_pop(vm, 1); +} +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Commissioning_Data.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Commissioning_Data.h new file mode 100644 index 000000000..2c2bb647a --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Commissioning_Data.h @@ -0,0 +1,970 @@ +/* Solidification of Matter_Commissioning_Data.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_PBKDFParamRequest; + +/******************************************************************** +** Solidified function: parse +********************************************************************/ +be_local_closure(Matter_PBKDFParamRequest_parse, /* name */ + be_nested_proto( + 8, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[16]) { /* constants */ + /* K0 */ be_const_int(0), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(TLV), + /* K3 */ be_nested_str_weak(parse), + /* K4 */ be_nested_str_weak(initiatorRandom), + /* K5 */ be_nested_str_weak(getsubval), + /* K6 */ be_const_int(1), + /* K7 */ be_nested_str_weak(initiator_session_id), + /* K8 */ be_const_int(2), + /* K9 */ be_nested_str_weak(passcodeId), + /* K10 */ be_const_int(3), + /* K11 */ be_nested_str_weak(hasPBKDFParameters), + /* K12 */ be_nested_str_weak(findsub), + /* K13 */ be_nested_str_weak(SLEEPY_IDLE_INTERVAL), + /* K14 */ be_nested_str_weak(findsubval), + /* K15 */ be_nested_str_weak(SLEEPY_ACTIVE_INTERVAL), + }), + be_str_weak(parse), + &be_const_str_solidified, + ( &(const binstruction[41]) { /* code */ + 0x4C0C0000, // 0000 LDNIL R3 + 0x1C0C0403, // 0001 EQ R3 R2 R3 + 0x780E0000, // 0002 JMPF R3 #0004 + 0x58080000, // 0003 LDCONST R2 K0 + 0xB80E0200, // 0004 GETNGBL R3 K1 + 0x880C0702, // 0005 GETMBR R3 R3 K2 + 0x8C0C0703, // 0006 GETMET R3 R3 K3 + 0x5C140200, // 0007 MOVE R5 R1 + 0x5C180400, // 0008 MOVE R6 R2 + 0x7C0C0600, // 0009 CALL R3 3 + 0x8C100705, // 000A GETMET R4 R3 K5 + 0x58180006, // 000B LDCONST R6 K6 + 0x7C100400, // 000C CALL R4 2 + 0x90020804, // 000D SETMBR R0 K4 R4 + 0x8C100705, // 000E GETMET R4 R3 K5 + 0x58180008, // 000F LDCONST R6 K8 + 0x7C100400, // 0010 CALL R4 2 + 0x90020E04, // 0011 SETMBR R0 K7 R4 + 0x8C100705, // 0012 GETMET R4 R3 K5 + 0x5818000A, // 0013 LDCONST R6 K10 + 0x7C100400, // 0014 CALL R4 2 + 0x90021204, // 0015 SETMBR R0 K9 R4 + 0x8C100705, // 0016 GETMET R4 R3 K5 + 0x541A0003, // 0017 LDINT R6 4 + 0x7C100400, // 0018 CALL R4 2 + 0x90021604, // 0019 SETMBR R0 K11 R4 + 0x8C10070C, // 001A GETMET R4 R3 K12 + 0x541A0004, // 001B LDINT R6 5 + 0x7C100400, // 001C CALL R4 2 + 0x4C140000, // 001D LDNIL R5 + 0x20140805, // 001E NE R5 R4 R5 + 0x78160007, // 001F JMPF R5 #0028 + 0x8C14090E, // 0020 GETMET R5 R4 K14 + 0x581C0006, // 0021 LDCONST R7 K6 + 0x7C140400, // 0022 CALL R5 2 + 0x90021A05, // 0023 SETMBR R0 K13 R5 + 0x8C14090E, // 0024 GETMET R5 R4 K14 + 0x581C0008, // 0025 LDCONST R7 K8 + 0x7C140400, // 0026 CALL R5 2 + 0x90021E05, // 0027 SETMBR R0 K15 R5 + 0x80040000, // 0028 RET 1 R0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_PBKDFParamRequest +********************************************************************/ +be_local_class(Matter_PBKDFParamRequest, + 6, + NULL, + be_nested_map(7, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(initiatorRandom, 6), be_const_var(0) }, + { be_const_key_weak(passcodeId, -1), be_const_var(2) }, + { be_const_key_weak(hasPBKDFParameters, -1), be_const_var(3) }, + { be_const_key_weak(parse, -1), be_const_closure(Matter_PBKDFParamRequest_parse_closure) }, + { be_const_key_weak(initiator_session_id, 0), be_const_var(1) }, + { be_const_key_weak(SLEEPY_IDLE_INTERVAL, 3), be_const_var(4) }, + { be_const_key_weak(SLEEPY_ACTIVE_INTERVAL, -1), be_const_var(5) }, + })), + be_str_weak(Matter_PBKDFParamRequest) +); +/*******************************************************************/ + +void be_load_Matter_PBKDFParamRequest_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_PBKDFParamRequest); + be_setglobal(vm, "Matter_PBKDFParamRequest"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_PBKDFParamResponse; + +/******************************************************************** +** Solidified function: encode +********************************************************************/ +be_local_closure(Matter_PBKDFParamResponse_encode, /* name */ + be_nested_proto( + 10, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[19]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(TLV), + /* K2 */ be_nested_str_weak(Matter_TLV_struct), + /* K3 */ be_nested_str_weak(add_TLV), + /* K4 */ be_const_int(1), + /* K5 */ be_nested_str_weak(B1), + /* K6 */ be_nested_str_weak(initiatorRandom), + /* K7 */ be_const_int(2), + /* K8 */ be_nested_str_weak(responderRandom), + /* K9 */ be_const_int(3), + /* K10 */ be_nested_str_weak(U2), + /* K11 */ be_nested_str_weak(responderSessionId), + /* K12 */ be_nested_str_weak(add_struct), + /* K13 */ be_nested_str_weak(U4), + /* K14 */ be_nested_str_weak(pbkdf_parameters_iterations), + /* K15 */ be_nested_str_weak(pbkdf_parameters_salt), + /* K16 */ be_nested_str_weak(SLEEPY_IDLE_INTERVAL), + /* K17 */ be_nested_str_weak(SLEEPY_ACTIVE_INTERVAL), + /* K18 */ be_nested_str_weak(encode), + }), + be_str_weak(encode), + &be_const_str_solidified, + ( &(const binstruction[70]) { /* code */ + 0xB80A0000, // 0000 GETNGBL R2 K0 + 0x88080501, // 0001 GETMBR R2 R2 K1 + 0x8C080502, // 0002 GETMET R2 R2 K2 + 0x7C080200, // 0003 CALL R2 1 + 0x8C0C0503, // 0004 GETMET R3 R2 K3 + 0x58140004, // 0005 LDCONST R5 K4 + 0xB81A0000, // 0006 GETNGBL R6 K0 + 0x88180D01, // 0007 GETMBR R6 R6 K1 + 0x88180D05, // 0008 GETMBR R6 R6 K5 + 0x881C0106, // 0009 GETMBR R7 R0 K6 + 0x7C0C0800, // 000A CALL R3 4 + 0x8C0C0503, // 000B GETMET R3 R2 K3 + 0x58140007, // 000C LDCONST R5 K7 + 0xB81A0000, // 000D GETNGBL R6 K0 + 0x88180D01, // 000E GETMBR R6 R6 K1 + 0x88180D05, // 000F GETMBR R6 R6 K5 + 0x881C0108, // 0010 GETMBR R7 R0 K8 + 0x7C0C0800, // 0011 CALL R3 4 + 0x8C0C0503, // 0012 GETMET R3 R2 K3 + 0x58140009, // 0013 LDCONST R5 K9 + 0xB81A0000, // 0014 GETNGBL R6 K0 + 0x88180D01, // 0015 GETMBR R6 R6 K1 + 0x88180D0A, // 0016 GETMBR R6 R6 K10 + 0x881C010B, // 0017 GETMBR R7 R0 K11 + 0x7C0C0800, // 0018 CALL R3 4 + 0x8C0C050C, // 0019 GETMET R3 R2 K12 + 0x54160003, // 001A LDINT R5 4 + 0x7C0C0400, // 001B CALL R3 2 + 0x8C100703, // 001C GETMET R4 R3 K3 + 0x58180004, // 001D LDCONST R6 K4 + 0xB81E0000, // 001E GETNGBL R7 K0 + 0x881C0F01, // 001F GETMBR R7 R7 K1 + 0x881C0F0D, // 0020 GETMBR R7 R7 K13 + 0x8820010E, // 0021 GETMBR R8 R0 K14 + 0x7C100800, // 0022 CALL R4 4 + 0x8C100703, // 0023 GETMET R4 R3 K3 + 0x58180007, // 0024 LDCONST R6 K7 + 0xB81E0000, // 0025 GETNGBL R7 K0 + 0x881C0F01, // 0026 GETMBR R7 R7 K1 + 0x881C0F05, // 0027 GETMBR R7 R7 K5 + 0x8820010F, // 0028 GETMBR R8 R0 K15 + 0x7C100800, // 0029 CALL R4 4 + 0x88100110, // 002A GETMBR R4 R0 K16 + 0x4C140000, // 002B LDNIL R5 + 0x20100805, // 002C NE R4 R4 R5 + 0x74120003, // 002D JMPT R4 #0032 + 0x88100111, // 002E GETMBR R4 R0 K17 + 0x4C140000, // 002F LDNIL R5 + 0x20100805, // 0030 NE R4 R4 R5 + 0x78120010, // 0031 JMPF R4 #0043 + 0x8C10050C, // 0032 GETMET R4 R2 K12 + 0x541A0004, // 0033 LDINT R6 5 + 0x7C100400, // 0034 CALL R4 2 + 0x8C140903, // 0035 GETMET R5 R4 K3 + 0x581C0004, // 0036 LDCONST R7 K4 + 0xB8220000, // 0037 GETNGBL R8 K0 + 0x88201101, // 0038 GETMBR R8 R8 K1 + 0x8820110D, // 0039 GETMBR R8 R8 K13 + 0x88240110, // 003A GETMBR R9 R0 K16 + 0x7C140800, // 003B CALL R5 4 + 0x8C140903, // 003C GETMET R5 R4 K3 + 0x581C0007, // 003D LDCONST R7 K7 + 0xB8220000, // 003E GETNGBL R8 K0 + 0x88201101, // 003F GETMBR R8 R8 K1 + 0x8820110D, // 0040 GETMBR R8 R8 K13 + 0x88240111, // 0041 GETMBR R9 R0 K17 + 0x7C140800, // 0042 CALL R5 4 + 0x8C100512, // 0043 GETMET R4 R2 K18 + 0x7C100200, // 0044 CALL R4 1 + 0x80040800, // 0045 RET 1 R4 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_PBKDFParamResponse +********************************************************************/ +be_local_class(Matter_PBKDFParamResponse, + 7, + NULL, + be_nested_map(8, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(pbkdf_parameters_salt, -1), be_const_var(4) }, + { be_const_key_weak(SLEEPY_IDLE_INTERVAL, -1), be_const_var(5) }, + { be_const_key_weak(SLEEPY_ACTIVE_INTERVAL, 1), be_const_var(6) }, + { be_const_key_weak(responderRandom, -1), be_const_var(1) }, + { be_const_key_weak(pbkdf_parameters_iterations, -1), be_const_var(3) }, + { be_const_key_weak(initiatorRandom, -1), be_const_var(0) }, + { be_const_key_weak(responderSessionId, 3), be_const_var(2) }, + { be_const_key_weak(encode, -1), be_const_closure(Matter_PBKDFParamResponse_encode_closure) }, + })), + be_str_weak(Matter_PBKDFParamResponse) +); +/*******************************************************************/ + +void be_load_Matter_PBKDFParamResponse_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_PBKDFParamResponse); + be_setglobal(vm, "Matter_PBKDFParamResponse"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_Pake1; + +/******************************************************************** +** Solidified function: parse +********************************************************************/ +be_local_closure(Matter_Pake1_parse, /* name */ + be_nested_proto( + 8, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[11]) { /* constants */ + /* K0 */ be_const_int(0), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(TLV), + /* K3 */ be_nested_str_weak(parse), + /* K4 */ be_nested_str_weak(tasmota), + /* K5 */ be_nested_str_weak(log), + /* K6 */ be_nested_str_weak(MTR_X3A_X20parsed_X20TLV_X3A_X20), + /* K7 */ be_const_int(3), + /* K8 */ be_nested_str_weak(pA), + /* K9 */ be_nested_str_weak(getsubval), + /* K10 */ be_const_int(1), + }), + be_str_weak(parse), + &be_const_str_solidified, + ( &(const binstruction[23]) { /* code */ + 0x4C0C0000, // 0000 LDNIL R3 + 0x1C0C0403, // 0001 EQ R3 R2 R3 + 0x780E0000, // 0002 JMPF R3 #0004 + 0x58080000, // 0003 LDCONST R2 K0 + 0xB80E0200, // 0004 GETNGBL R3 K1 + 0x880C0702, // 0005 GETMBR R3 R3 K2 + 0x8C0C0703, // 0006 GETMET R3 R3 K3 + 0x5C140200, // 0007 MOVE R5 R1 + 0x5C180400, // 0008 MOVE R6 R2 + 0x7C0C0600, // 0009 CALL R3 3 + 0xB8120800, // 000A GETNGBL R4 K4 + 0x8C100905, // 000B GETMET R4 R4 K5 + 0x60180008, // 000C GETGBL R6 G8 + 0x5C1C0600, // 000D MOVE R7 R3 + 0x7C180200, // 000E CALL R6 1 + 0x001A0C06, // 000F ADD R6 K6 R6 + 0x581C0007, // 0010 LDCONST R7 K7 + 0x7C100600, // 0011 CALL R4 3 + 0x8C100709, // 0012 GETMET R4 R3 K9 + 0x5818000A, // 0013 LDCONST R6 K10 + 0x7C100400, // 0014 CALL R4 2 + 0x90021004, // 0015 SETMBR R0 K8 R4 + 0x80040000, // 0016 RET 1 R0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_Pake1 +********************************************************************/ +be_local_class(Matter_Pake1, + 1, + NULL, + be_nested_map(2, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(pA, 1), be_const_var(0) }, + { be_const_key_weak(parse, -1), be_const_closure(Matter_Pake1_parse_closure) }, + })), + be_str_weak(Matter_Pake1) +); +/*******************************************************************/ + +void be_load_Matter_Pake1_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Pake1); + be_setglobal(vm, "Matter_Pake1"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_Pake2; + +/******************************************************************** +** Solidified function: encode +********************************************************************/ +be_local_closure(Matter_Pake2_encode, /* name */ + be_nested_proto( + 8, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[10]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(TLV), + /* K2 */ be_nested_str_weak(Matter_TLV_struct), + /* K3 */ be_nested_str_weak(add_TLV), + /* K4 */ be_const_int(1), + /* K5 */ be_nested_str_weak(B1), + /* K6 */ be_nested_str_weak(pB), + /* K7 */ be_const_int(2), + /* K8 */ be_nested_str_weak(cB), + /* K9 */ be_nested_str_weak(encode), + }), + be_str_weak(encode), + &be_const_str_solidified, + ( &(const binstruction[21]) { /* code */ + 0xB80A0000, // 0000 GETNGBL R2 K0 + 0x88080501, // 0001 GETMBR R2 R2 K1 + 0x8C080502, // 0002 GETMET R2 R2 K2 + 0x7C080200, // 0003 CALL R2 1 + 0x8C0C0503, // 0004 GETMET R3 R2 K3 + 0x58140004, // 0005 LDCONST R5 K4 + 0xB81A0000, // 0006 GETNGBL R6 K0 + 0x88180D01, // 0007 GETMBR R6 R6 K1 + 0x88180D05, // 0008 GETMBR R6 R6 K5 + 0x881C0106, // 0009 GETMBR R7 R0 K6 + 0x7C0C0800, // 000A CALL R3 4 + 0x8C0C0503, // 000B GETMET R3 R2 K3 + 0x58140007, // 000C LDCONST R5 K7 + 0xB81A0000, // 000D GETNGBL R6 K0 + 0x88180D01, // 000E GETMBR R6 R6 K1 + 0x88180D05, // 000F GETMBR R6 R6 K5 + 0x881C0108, // 0010 GETMBR R7 R0 K8 + 0x7C0C0800, // 0011 CALL R3 4 + 0x8C0C0509, // 0012 GETMET R3 R2 K9 + 0x7C0C0200, // 0013 CALL R3 1 + 0x80040600, // 0014 RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_Pake2 +********************************************************************/ +be_local_class(Matter_Pake2, + 2, + NULL, + be_nested_map(3, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(encode, -1), be_const_closure(Matter_Pake2_encode_closure) }, + { be_const_key_weak(cB, -1), be_const_var(1) }, + { be_const_key_weak(pB, 0), be_const_var(0) }, + })), + be_str_weak(Matter_Pake2) +); +/*******************************************************************/ + +void be_load_Matter_Pake2_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Pake2); + be_setglobal(vm, "Matter_Pake2"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_Pake3; + +/******************************************************************** +** Solidified function: parse +********************************************************************/ +be_local_closure(Matter_Pake3_parse, /* name */ + be_nested_proto( + 8, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[11]) { /* constants */ + /* K0 */ be_const_int(0), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(TLV), + /* K3 */ be_nested_str_weak(parse), + /* K4 */ be_nested_str_weak(tasmota), + /* K5 */ be_nested_str_weak(log), + /* K6 */ be_nested_str_weak(MTR_X3A_X20parsed_X20TLV_X3A_X20), + /* K7 */ be_const_int(3), + /* K8 */ be_nested_str_weak(cA), + /* K9 */ be_nested_str_weak(getsubval), + /* K10 */ be_const_int(1), + }), + be_str_weak(parse), + &be_const_str_solidified, + ( &(const binstruction[23]) { /* code */ + 0x4C0C0000, // 0000 LDNIL R3 + 0x1C0C0403, // 0001 EQ R3 R2 R3 + 0x780E0000, // 0002 JMPF R3 #0004 + 0x58080000, // 0003 LDCONST R2 K0 + 0xB80E0200, // 0004 GETNGBL R3 K1 + 0x880C0702, // 0005 GETMBR R3 R3 K2 + 0x8C0C0703, // 0006 GETMET R3 R3 K3 + 0x5C140200, // 0007 MOVE R5 R1 + 0x5C180400, // 0008 MOVE R6 R2 + 0x7C0C0600, // 0009 CALL R3 3 + 0xB8120800, // 000A GETNGBL R4 K4 + 0x8C100905, // 000B GETMET R4 R4 K5 + 0x60180008, // 000C GETGBL R6 G8 + 0x5C1C0600, // 000D MOVE R7 R3 + 0x7C180200, // 000E CALL R6 1 + 0x001A0C06, // 000F ADD R6 K6 R6 + 0x581C0007, // 0010 LDCONST R7 K7 + 0x7C100600, // 0011 CALL R4 3 + 0x8C100709, // 0012 GETMET R4 R3 K9 + 0x5818000A, // 0013 LDCONST R6 K10 + 0x7C100400, // 0014 CALL R4 2 + 0x90021004, // 0015 SETMBR R0 K8 R4 + 0x80040000, // 0016 RET 1 R0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_Pake3 +********************************************************************/ +be_local_class(Matter_Pake3, + 1, + NULL, + be_nested_map(2, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(parse, -1), be_const_closure(Matter_Pake3_parse_closure) }, + { be_const_key_weak(cA, -1), be_const_var(0) }, + })), + be_str_weak(Matter_Pake3) +); +/*******************************************************************/ + +void be_load_Matter_Pake3_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Pake3); + be_setglobal(vm, "Matter_Pake3"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_Sigma1; + +/******************************************************************** +** Solidified function: parse +********************************************************************/ +be_local_closure(Matter_Sigma1_parse, /* name */ + be_nested_proto( + 9, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[21]) { /* constants */ + /* K0 */ be_const_int(0), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(TLV), + /* K3 */ be_nested_str_weak(parse), + /* K4 */ be_nested_str_weak(Msg1), + /* K5 */ be_const_int(2147483647), + /* K6 */ be_nested_str_weak(tasmota), + /* K7 */ be_nested_str_weak(log), + /* K8 */ be_nested_str_weak(MTR_X3A_X20Sigma1_X20TLV_X3D), + /* K9 */ be_const_int(3), + /* K10 */ be_nested_str_weak(initiatorRandom), + /* K11 */ be_nested_str_weak(getsubval), + /* K12 */ be_const_int(1), + /* K13 */ be_nested_str_weak(initiator_session_id), + /* K14 */ be_const_int(2), + /* K15 */ be_nested_str_weak(destinationId), + /* K16 */ be_nested_str_weak(initiatorEphPubKey), + /* K17 */ be_nested_str_weak(findsub), + /* K18 */ be_nested_str_weak(SLEEPY_IDLE_INTERVAL), + /* K19 */ be_nested_str_weak(findsubval), + /* K20 */ be_nested_str_weak(SLEEPY_ACTIVE_INTERVAL), + }), + be_str_weak(parse), + &be_const_str_solidified, + ( &(const binstruction[58]) { /* code */ + 0x4C0C0000, // 0000 LDNIL R3 + 0x1C0C0403, // 0001 EQ R3 R2 R3 + 0x780E0000, // 0002 JMPF R3 #0004 + 0x58080000, // 0003 LDCONST R2 K0 + 0xB80E0200, // 0004 GETNGBL R3 K1 + 0x880C0702, // 0005 GETMBR R3 R3 K2 + 0x8C0C0703, // 0006 GETMET R3 R3 K3 + 0x5C140200, // 0007 MOVE R5 R1 + 0x5C180400, // 0008 MOVE R6 R2 + 0x7C0C0600, // 0009 CALL R3 3 + 0x40100505, // 000A CONNECT R4 R2 K5 + 0x94100204, // 000B GETIDX R4 R1 R4 + 0x90020804, // 000C SETMBR R0 K4 R4 + 0xB8120C00, // 000D GETNGBL R4 K6 + 0x8C100907, // 000E GETMET R4 R4 K7 + 0x60180008, // 000F GETGBL R6 G8 + 0x5C1C0600, // 0010 MOVE R7 R3 + 0x7C180200, // 0011 CALL R6 1 + 0x001A1006, // 0012 ADD R6 K8 R6 + 0x581C0009, // 0013 LDCONST R7 K9 + 0x7C100600, // 0014 CALL R4 3 + 0x8C10070B, // 0015 GETMET R4 R3 K11 + 0x5818000C, // 0016 LDCONST R6 K12 + 0x7C100400, // 0017 CALL R4 2 + 0x90021404, // 0018 SETMBR R0 K10 R4 + 0x8C10070B, // 0019 GETMET R4 R3 K11 + 0x5818000E, // 001A LDCONST R6 K14 + 0x7C100400, // 001B CALL R4 2 + 0x90021A04, // 001C SETMBR R0 K13 R4 + 0x8C10070B, // 001D GETMET R4 R3 K11 + 0x58180009, // 001E LDCONST R6 K9 + 0x7C100400, // 001F CALL R4 2 + 0x90021E04, // 0020 SETMBR R0 K15 R4 + 0x8C10070B, // 0021 GETMET R4 R3 K11 + 0x541A0003, // 0022 LDINT R6 4 + 0x7C100400, // 0023 CALL R4 2 + 0x90022004, // 0024 SETMBR R0 K16 R4 + 0x8C100711, // 0025 GETMET R4 R3 K17 + 0x541A0004, // 0026 LDINT R6 5 + 0x7C100400, // 0027 CALL R4 2 + 0x4C140000, // 0028 LDNIL R5 + 0x20140805, // 0029 NE R5 R4 R5 + 0x78160007, // 002A JMPF R5 #0033 + 0x8C140913, // 002B GETMET R5 R4 K19 + 0x581C000C, // 002C LDCONST R7 K12 + 0x7C140400, // 002D CALL R5 2 + 0x90022405, // 002E SETMBR R0 K18 R5 + 0x8C140913, // 002F GETMET R5 R4 K19 + 0x581C000E, // 0030 LDCONST R7 K14 + 0x7C140400, // 0031 CALL R5 2 + 0x90022805, // 0032 SETMBR R0 K20 R5 + 0x8C140711, // 0033 GETMET R5 R3 K17 + 0x541E0005, // 0034 LDINT R7 6 + 0x7C140400, // 0035 CALL R5 2 + 0x8C180711, // 0036 GETMET R6 R3 K17 + 0x54220006, // 0037 LDINT R8 7 + 0x7C180400, // 0038 CALL R6 2 + 0x80040000, // 0039 RET 1 R0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_Sigma1 +********************************************************************/ +be_local_class(Matter_Sigma1, + 9, + NULL, + be_nested_map(10, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(SLEEPY_ACTIVE_INTERVAL, -1), be_const_var(5) }, + { be_const_key_weak(Msg1, -1), be_const_var(8) }, + { be_const_key_weak(parse, 6), be_const_closure(Matter_Sigma1_parse_closure) }, + { be_const_key_weak(initiatorRandom, -1), be_const_var(0) }, + { be_const_key_weak(SLEEPY_IDLE_INTERVAL, 7), be_const_var(4) }, + { be_const_key_weak(initiatorEphPubKey, -1), be_const_var(3) }, + { be_const_key_weak(initiatorResumeMIC, -1), be_const_var(7) }, + { be_const_key_weak(resumptionID, -1), be_const_var(6) }, + { be_const_key_weak(destinationId, -1), be_const_var(2) }, + { be_const_key_weak(initiator_session_id, 1), be_const_var(1) }, + })), + be_str_weak(Matter_Sigma1) +); +/*******************************************************************/ + +void be_load_Matter_Sigma1_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Sigma1); + be_setglobal(vm, "Matter_Sigma1"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_Sigma2; + +/******************************************************************** +** Solidified function: encode +********************************************************************/ +be_local_closure(Matter_Sigma2_encode, /* name */ + be_nested_proto( + 9, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[18]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(TLV), + /* K2 */ be_nested_str_weak(Matter_TLV_struct), + /* K3 */ be_nested_str_weak(add_TLV), + /* K4 */ be_const_int(1), + /* K5 */ be_nested_str_weak(B1), + /* K6 */ be_nested_str_weak(responderRandom), + /* K7 */ be_const_int(2), + /* K8 */ be_nested_str_weak(U2), + /* K9 */ be_nested_str_weak(responderSessionId), + /* K10 */ be_const_int(3), + /* K11 */ be_nested_str_weak(responderEphPubKey), + /* K12 */ be_nested_str_weak(encrypted2), + /* K13 */ be_nested_str_weak(SLEEPY_IDLE_INTERVAL), + /* K14 */ be_nested_str_weak(SLEEPY_ACTIVE_INTERVAL), + /* K15 */ be_nested_str_weak(add_struct), + /* K16 */ be_nested_str_weak(U4), + /* K17 */ be_nested_str_weak(encode), + }), + be_str_weak(encode), + &be_const_str_solidified, + ( &(const binstruction[60]) { /* code */ + 0xB80A0000, // 0000 GETNGBL R2 K0 + 0x88080501, // 0001 GETMBR R2 R2 K1 + 0x8C080502, // 0002 GETMET R2 R2 K2 + 0x7C080200, // 0003 CALL R2 1 + 0x8C0C0503, // 0004 GETMET R3 R2 K3 + 0x58140004, // 0005 LDCONST R5 K4 + 0xB81A0000, // 0006 GETNGBL R6 K0 + 0x88180D01, // 0007 GETMBR R6 R6 K1 + 0x88180D05, // 0008 GETMBR R6 R6 K5 + 0x881C0106, // 0009 GETMBR R7 R0 K6 + 0x7C0C0800, // 000A CALL R3 4 + 0x8C0C0503, // 000B GETMET R3 R2 K3 + 0x58140007, // 000C LDCONST R5 K7 + 0xB81A0000, // 000D GETNGBL R6 K0 + 0x88180D01, // 000E GETMBR R6 R6 K1 + 0x88180D08, // 000F GETMBR R6 R6 K8 + 0x881C0109, // 0010 GETMBR R7 R0 K9 + 0x7C0C0800, // 0011 CALL R3 4 + 0x8C0C0503, // 0012 GETMET R3 R2 K3 + 0x5814000A, // 0013 LDCONST R5 K10 + 0xB81A0000, // 0014 GETNGBL R6 K0 + 0x88180D01, // 0015 GETMBR R6 R6 K1 + 0x88180D05, // 0016 GETMBR R6 R6 K5 + 0x881C010B, // 0017 GETMBR R7 R0 K11 + 0x7C0C0800, // 0018 CALL R3 4 + 0x8C0C0503, // 0019 GETMET R3 R2 K3 + 0x54160003, // 001A LDINT R5 4 + 0xB81A0000, // 001B GETNGBL R6 K0 + 0x88180D01, // 001C GETMBR R6 R6 K1 + 0x88180D05, // 001D GETMBR R6 R6 K5 + 0x881C010C, // 001E GETMBR R7 R0 K12 + 0x7C0C0800, // 001F CALL R3 4 + 0x880C010D, // 0020 GETMBR R3 R0 K13 + 0x4C100000, // 0021 LDNIL R4 + 0x200C0604, // 0022 NE R3 R3 R4 + 0x740E0003, // 0023 JMPT R3 #0028 + 0x880C010E, // 0024 GETMBR R3 R0 K14 + 0x4C100000, // 0025 LDNIL R4 + 0x200C0604, // 0026 NE R3 R3 R4 + 0x780E0010, // 0027 JMPF R3 #0039 + 0x8C0C050F, // 0028 GETMET R3 R2 K15 + 0x54160004, // 0029 LDINT R5 5 + 0x7C0C0400, // 002A CALL R3 2 + 0x8C100703, // 002B GETMET R4 R3 K3 + 0x58180004, // 002C LDCONST R6 K4 + 0xB81E0000, // 002D GETNGBL R7 K0 + 0x881C0F01, // 002E GETMBR R7 R7 K1 + 0x881C0F10, // 002F GETMBR R7 R7 K16 + 0x8820010D, // 0030 GETMBR R8 R0 K13 + 0x7C100800, // 0031 CALL R4 4 + 0x8C100703, // 0032 GETMET R4 R3 K3 + 0x58180007, // 0033 LDCONST R6 K7 + 0xB81E0000, // 0034 GETNGBL R7 K0 + 0x881C0F01, // 0035 GETMBR R7 R7 K1 + 0x881C0F10, // 0036 GETMBR R7 R7 K16 + 0x8820010E, // 0037 GETMBR R8 R0 K14 + 0x7C100800, // 0038 CALL R4 4 + 0x8C0C0511, // 0039 GETMET R3 R2 K17 + 0x7C0C0200, // 003A CALL R3 1 + 0x80040600, // 003B RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_Sigma2 +********************************************************************/ +be_local_class(Matter_Sigma2, + 6, + NULL, + be_nested_map(7, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(encrypted2, -1), be_const_var(3) }, + { be_const_key_weak(encode, -1), be_const_closure(Matter_Sigma2_encode_closure) }, + { be_const_key_weak(responderSessionId, -1), be_const_var(1) }, + { be_const_key_weak(SLEEPY_IDLE_INTERVAL, 6), be_const_var(4) }, + { be_const_key_weak(SLEEPY_ACTIVE_INTERVAL, 0), be_const_var(5) }, + { be_const_key_weak(responderRandom, 3), be_const_var(0) }, + { be_const_key_weak(responderEphPubKey, -1), be_const_var(2) }, + })), + be_str_weak(Matter_Sigma2) +); +/*******************************************************************/ + +void be_load_Matter_Sigma2_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Sigma2); + be_setglobal(vm, "Matter_Sigma2"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_Sigma2Resume; + +/******************************************************************** +** Solidified function: encode +********************************************************************/ +be_local_closure(Matter_Sigma2Resume_encode, /* name */ + be_nested_proto( + 9, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[16]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(TLV), + /* K2 */ be_nested_str_weak(Matter_TLV_struct), + /* K3 */ be_nested_str_weak(add_TLV), + /* K4 */ be_const_int(1), + /* K5 */ be_nested_str_weak(B1), + /* K6 */ be_nested_str_weak(resumptionID), + /* K7 */ be_const_int(2), + /* K8 */ be_nested_str_weak(sigma2ResumeMIC), + /* K9 */ be_const_int(3), + /* K10 */ be_nested_str_weak(responderSessionID), + /* K11 */ be_nested_str_weak(SLEEPY_IDLE_INTERVAL), + /* K12 */ be_nested_str_weak(SLEEPY_ACTIVE_INTERVAL), + /* K13 */ be_nested_str_weak(add_struct), + /* K14 */ be_nested_str_weak(U4), + /* K15 */ be_nested_str_weak(encode), + }), + be_str_weak(encode), + &be_const_str_solidified, + ( &(const binstruction[53]) { /* code */ + 0xB80A0000, // 0000 GETNGBL R2 K0 + 0x88080501, // 0001 GETMBR R2 R2 K1 + 0x8C080502, // 0002 GETMET R2 R2 K2 + 0x7C080200, // 0003 CALL R2 1 + 0x8C0C0503, // 0004 GETMET R3 R2 K3 + 0x58140004, // 0005 LDCONST R5 K4 + 0xB81A0000, // 0006 GETNGBL R6 K0 + 0x88180D01, // 0007 GETMBR R6 R6 K1 + 0x88180D05, // 0008 GETMBR R6 R6 K5 + 0x881C0106, // 0009 GETMBR R7 R0 K6 + 0x7C0C0800, // 000A CALL R3 4 + 0x8C0C0503, // 000B GETMET R3 R2 K3 + 0x58140007, // 000C LDCONST R5 K7 + 0xB81A0000, // 000D GETNGBL R6 K0 + 0x88180D01, // 000E GETMBR R6 R6 K1 + 0x88180D05, // 000F GETMBR R6 R6 K5 + 0x881C0108, // 0010 GETMBR R7 R0 K8 + 0x7C0C0800, // 0011 CALL R3 4 + 0x8C0C0503, // 0012 GETMET R3 R2 K3 + 0x58140009, // 0013 LDCONST R5 K9 + 0xB81A0000, // 0014 GETNGBL R6 K0 + 0x88180D01, // 0015 GETMBR R6 R6 K1 + 0x88180D05, // 0016 GETMBR R6 R6 K5 + 0x881C010A, // 0017 GETMBR R7 R0 K10 + 0x7C0C0800, // 0018 CALL R3 4 + 0x880C010B, // 0019 GETMBR R3 R0 K11 + 0x4C100000, // 001A LDNIL R4 + 0x200C0604, // 001B NE R3 R3 R4 + 0x740E0003, // 001C JMPT R3 #0021 + 0x880C010C, // 001D GETMBR R3 R0 K12 + 0x4C100000, // 001E LDNIL R4 + 0x200C0604, // 001F NE R3 R3 R4 + 0x780E0010, // 0020 JMPF R3 #0032 + 0x8C0C050D, // 0021 GETMET R3 R2 K13 + 0x54160003, // 0022 LDINT R5 4 + 0x7C0C0400, // 0023 CALL R3 2 + 0x8C100703, // 0024 GETMET R4 R3 K3 + 0x58180004, // 0025 LDCONST R6 K4 + 0xB81E0000, // 0026 GETNGBL R7 K0 + 0x881C0F01, // 0027 GETMBR R7 R7 K1 + 0x881C0F0E, // 0028 GETMBR R7 R7 K14 + 0x8820010B, // 0029 GETMBR R8 R0 K11 + 0x7C100800, // 002A CALL R4 4 + 0x8C100703, // 002B GETMET R4 R3 K3 + 0x58180007, // 002C LDCONST R6 K7 + 0xB81E0000, // 002D GETNGBL R7 K0 + 0x881C0F01, // 002E GETMBR R7 R7 K1 + 0x881C0F0E, // 002F GETMBR R7 R7 K14 + 0x8820010C, // 0030 GETMBR R8 R0 K12 + 0x7C100800, // 0031 CALL R4 4 + 0x8C0C050F, // 0032 GETMET R3 R2 K15 + 0x7C0C0200, // 0033 CALL R3 1 + 0x80040600, // 0034 RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_Sigma2Resume +********************************************************************/ +be_local_class(Matter_Sigma2Resume, + 5, + NULL, + be_nested_map(6, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(SLEEPY_IDLE_INTERVAL, 3), be_const_var(3) }, + { be_const_key_weak(resumptionID, -1), be_const_var(0) }, + { be_const_key_weak(sigma2ResumeMIC, -1), be_const_var(1) }, + { be_const_key_weak(responderSessionID, 1), be_const_var(2) }, + { be_const_key_weak(SLEEPY_ACTIVE_INTERVAL, -1), be_const_var(4) }, + { be_const_key_weak(encode, -1), be_const_closure(Matter_Sigma2Resume_encode_closure) }, + })), + be_str_weak(Matter_Sigma2Resume) +); +/*******************************************************************/ + +void be_load_Matter_Sigma2Resume_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Sigma2Resume); + be_setglobal(vm, "Matter_Sigma2Resume"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_Sigma3; + +/******************************************************************** +** Solidified function: parse +********************************************************************/ +be_local_closure(Matter_Sigma3_parse, /* name */ + be_nested_proto( + 8, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[13]) { /* constants */ + /* K0 */ be_const_int(0), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(TLV), + /* K3 */ be_nested_str_weak(parse), + /* K4 */ be_nested_str_weak(Msg3), + /* K5 */ be_const_int(2147483647), + /* K6 */ be_nested_str_weak(tasmota), + /* K7 */ be_nested_str_weak(log), + /* K8 */ be_nested_str_weak(MTR_X3A_X20Sigma3_X20TLV_X3D), + /* K9 */ be_const_int(3), + /* K10 */ be_nested_str_weak(TBEData3Encrypted), + /* K11 */ be_nested_str_weak(getsubval), + /* K12 */ be_const_int(1), + }), + be_str_weak(parse), + &be_const_str_solidified, + ( &(const binstruction[26]) { /* code */ + 0x4C0C0000, // 0000 LDNIL R3 + 0x1C0C0403, // 0001 EQ R3 R2 R3 + 0x780E0000, // 0002 JMPF R3 #0004 + 0x58080000, // 0003 LDCONST R2 K0 + 0xB80E0200, // 0004 GETNGBL R3 K1 + 0x880C0702, // 0005 GETMBR R3 R3 K2 + 0x8C0C0703, // 0006 GETMET R3 R3 K3 + 0x5C140200, // 0007 MOVE R5 R1 + 0x5C180400, // 0008 MOVE R6 R2 + 0x7C0C0600, // 0009 CALL R3 3 + 0x40100505, // 000A CONNECT R4 R2 K5 + 0x94100204, // 000B GETIDX R4 R1 R4 + 0x90020804, // 000C SETMBR R0 K4 R4 + 0xB8120C00, // 000D GETNGBL R4 K6 + 0x8C100907, // 000E GETMET R4 R4 K7 + 0x60180008, // 000F GETGBL R6 G8 + 0x5C1C0600, // 0010 MOVE R7 R3 + 0x7C180200, // 0011 CALL R6 1 + 0x001A1006, // 0012 ADD R6 K8 R6 + 0x581C0009, // 0013 LDCONST R7 K9 + 0x7C100600, // 0014 CALL R4 3 + 0x8C10070B, // 0015 GETMET R4 R3 K11 + 0x5818000C, // 0016 LDCONST R6 K12 + 0x7C100400, // 0017 CALL R4 2 + 0x90021404, // 0018 SETMBR R0 K10 R4 + 0x80040000, // 0019 RET 1 R0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_Sigma3 +********************************************************************/ +be_local_class(Matter_Sigma3, + 2, + NULL, + be_nested_map(3, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(TBEData3Encrypted, 2), be_const_var(0) }, + { be_const_key_weak(parse, -1), be_const_closure(Matter_Sigma3_parse_closure) }, + { be_const_key_weak(Msg3, -1), be_const_var(1) }, + })), + be_str_weak(Matter_Sigma3) +); +/*******************************************************************/ + +void be_load_Matter_Sigma3_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Sigma3); + be_setglobal(vm, "Matter_Sigma3"); + be_pop(vm, 1); +} +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Device.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Device.h new file mode 100644 index 000000000..8040cef05 --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Device.h @@ -0,0 +1,2136 @@ +/* Solidification of Matter_Device.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_Device; + +/******************************************************************** +** Solidified function: msg_send +********************************************************************/ +be_local_closure(Matter_Device_msg_send, /* name */ + be_nested_proto( + 11, /* nstack */ + 5, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(udp_server), + /* K1 */ be_nested_str_weak(send_response), + }), + be_str_weak(msg_send), + &be_const_str_solidified, + ( &(const binstruction[ 8]) { /* code */ + 0x88140100, // 0000 GETMBR R5 R0 K0 + 0x8C140B01, // 0001 GETMET R5 R5 K1 + 0x5C1C0200, // 0002 MOVE R7 R1 + 0x5C200400, // 0003 MOVE R8 R2 + 0x5C240600, // 0004 MOVE R9 R3 + 0x5C280800, // 0005 MOVE R10 R4 + 0x7C140A00, // 0006 CALL R5 5 + 0x80040A00, // 0007 RET 1 R5 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: start_operational_dicovery_deferred +********************************************************************/ +be_local_closure(Matter_Device_start_operational_dicovery_deferred, /* name */ + be_nested_proto( + 6, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 1, /* has sup protos */ + ( &(const struct bproto*[ 1]) { + be_nested_proto( + 3, /* nstack */ + 0, /* argc */ + 0, /* varg */ + 1, /* has upvals */ + ( &(const bupvaldesc[ 2]) { /* upvals */ + be_local_const_upval(1, 0), + be_local_const_upval(1, 1), + }), + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(start_operational_dicovery), + }), + be_str_weak(_X3Clambda_X3E), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x68000000, // 0000 GETUPV R0 U0 + 0x8C000100, // 0001 GETMET R0 R0 K0 + 0x68080001, // 0002 GETUPV R2 U1 + 0x7C000400, // 0003 CALL R0 2 + 0x80040000, // 0004 RET 1 R0 + }) + ), + }), + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(tasmota), + /* K1 */ be_nested_str_weak(set_timer), + /* K2 */ be_const_int(0), + }), + be_str_weak(start_operational_dicovery_deferred), + &be_const_str_solidified, + ( &(const binstruction[ 7]) { /* code */ + 0xB80A0000, // 0000 GETNGBL R2 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x58100002, // 0002 LDCONST R4 K2 + 0x84140000, // 0003 CLOSURE R5 P0 + 0x7C080600, // 0004 CALL R2 3 + 0xA0000000, // 0005 CLOSE R0 + 0x80000000, // 0006 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: start_commissioning_complete_deferred +********************************************************************/ +be_local_closure(Matter_Device_start_commissioning_complete_deferred, /* name */ + be_nested_proto( + 6, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 1, /* has sup protos */ + ( &(const struct bproto*[ 1]) { + be_nested_proto( + 3, /* nstack */ + 0, /* argc */ + 0, /* varg */ + 1, /* has upvals */ + ( &(const bupvaldesc[ 2]) { /* upvals */ + be_local_const_upval(1, 0), + be_local_const_upval(1, 1), + }), + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(start_commissioning_complete), + }), + be_str_weak(_X3Clambda_X3E), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x68000000, // 0000 GETUPV R0 U0 + 0x8C000100, // 0001 GETMET R0 R0 K0 + 0x68080001, // 0002 GETUPV R2 U1 + 0x7C000400, // 0003 CALL R0 2 + 0x80040000, // 0004 RET 1 R0 + }) + ), + }), + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(tasmota), + /* K1 */ be_nested_str_weak(set_timer), + /* K2 */ be_const_int(0), + }), + be_str_weak(start_commissioning_complete_deferred), + &be_const_str_solidified, + ( &(const binstruction[ 7]) { /* code */ + 0xB80A0000, // 0000 GETNGBL R2 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x58100002, // 0002 LDCONST R4 K2 + 0x84140000, // 0003 CLOSURE R5 P0 + 0x7C080600, // 0004 CALL R2 3 + 0xA0000000, // 0005 CLOSE R0 + 0x80000000, // 0006 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: packet_ack +********************************************************************/ +be_local_closure(Matter_Device_packet_ack, /* name */ + be_nested_proto( + 5, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(udp_server), + /* K1 */ be_nested_str_weak(packet_ack), + }), + be_str_weak(packet_ack), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x5C100200, // 0002 MOVE R4 R1 + 0x7C080400, // 0003 CALL R2 2 + 0x80040400, // 0004 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: stop +********************************************************************/ +be_local_closure(Matter_Device_stop, /* name */ + be_nested_proto( + 3, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(udp_server), + /* K1 */ be_nested_str_weak(stop), + }), + be_str_weak(stop), + &be_const_str_solidified, + ( &(const binstruction[ 6]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x78060002, // 0001 JMPF R1 #0005 + 0x88040100, // 0002 GETMBR R1 R0 K0 + 0x8C040301, // 0003 GETMET R1 R1 K1 + 0x7C040200, // 0004 CALL R1 1 + 0x80000000, // 0005 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: load_param +********************************************************************/ +be_local_closure(Matter_Device_load_param, /* name */ + be_nested_proto( + 10, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[22]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(crypto), + /* K2 */ be_nested_str_weak(FILENAME), + /* K3 */ be_nested_str_weak(read), + /* K4 */ be_nested_str_weak(close), + /* K5 */ be_nested_str_weak(json), + /* K6 */ be_nested_str_weak(load), + /* K7 */ be_nested_str_weak(discriminator), + /* K8 */ be_nested_str_weak(find), + /* K9 */ be_nested_str_weak(distinguish), + /* K10 */ be_nested_str_weak(passcode), + /* K11 */ be_nested_str_weak(io_error), + /* K12 */ be_nested_str_weak(tasmota), + /* K13 */ be_nested_str_weak(log), + /* K14 */ be_nested_str_weak(MTR_X3A_X20Session_Store_X3A_X3Aload_X20Exception_X3A), + /* K15 */ be_nested_str_weak(_X7C), + /* K16 */ be_const_int(2), + /* K17 */ be_nested_str_weak(random), + /* K18 */ be_nested_str_weak(get), + /* K19 */ be_const_int(0), + /* K20 */ be_nested_str_weak(PASSCODE_DEFAULT), + /* K21 */ be_nested_str_weak(save_param), + }), + be_str_weak(load_param), + &be_const_str_solidified, + ( &(const binstruction[70]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0xA40A0200, // 0001 IMPORT R2 K1 + 0xA8020014, // 0002 EXBLK 0 #0018 + 0x600C0011, // 0003 GETGBL R3 G17 + 0x88100102, // 0004 GETMBR R4 R0 K2 + 0x7C0C0200, // 0005 CALL R3 1 + 0x8C100703, // 0006 GETMET R4 R3 K3 + 0x7C100200, // 0007 CALL R4 1 + 0x8C140704, // 0008 GETMET R5 R3 K4 + 0x7C140200, // 0009 CALL R5 1 + 0xA4160A00, // 000A IMPORT R5 K5 + 0x8C180B06, // 000B GETMET R6 R5 K6 + 0x5C200800, // 000C MOVE R8 R4 + 0x7C180400, // 000D CALL R6 2 + 0x8C1C0D08, // 000E GETMET R7 R6 K8 + 0x58240009, // 000F LDCONST R9 K9 + 0x7C1C0400, // 0010 CALL R7 2 + 0x90020E07, // 0011 SETMBR R0 K7 R7 + 0x8C1C0D08, // 0012 GETMET R7 R6 K8 + 0x5824000A, // 0013 LDCONST R9 K10 + 0x7C1C0400, // 0014 CALL R7 2 + 0x90021407, // 0015 SETMBR R0 K10 R7 + 0xA8040001, // 0016 EXBLK 1 1 + 0x70020012, // 0017 JMP #002B + 0xAC0C0002, // 0018 CATCH R3 0 2 + 0x7002000F, // 0019 JMP #002A + 0x2014070B, // 001A NE R5 R3 K11 + 0x7816000C, // 001B JMPF R5 #0029 + 0xB8161800, // 001C GETNGBL R5 K12 + 0x8C140B0D, // 001D GETMET R5 R5 K13 + 0x601C0008, // 001E GETGBL R7 G8 + 0x5C200600, // 001F MOVE R8 R3 + 0x7C1C0200, // 0020 CALL R7 1 + 0x001E1C07, // 0021 ADD R7 K14 R7 + 0x001C0F0F, // 0022 ADD R7 R7 K15 + 0x60200008, // 0023 GETGBL R8 G8 + 0x5C240800, // 0024 MOVE R9 R4 + 0x7C200200, // 0025 CALL R8 1 + 0x001C0E08, // 0026 ADD R7 R7 R8 + 0x58200010, // 0027 LDCONST R8 K16 + 0x7C140600, // 0028 CALL R5 3 + 0x70020000, // 0029 JMP #002B + 0xB0080000, // 002A RAISE 2 R0 R0 + 0x500C0000, // 002B LDBOOL R3 0 0 + 0x88100107, // 002C GETMBR R4 R0 K7 + 0x4C140000, // 002D LDNIL R5 + 0x1C100805, // 002E EQ R4 R4 R5 + 0x7812000A, // 002F JMPF R4 #003B + 0x8C100511, // 0030 GETMET R4 R2 K17 + 0x58180010, // 0031 LDCONST R6 K16 + 0x7C100400, // 0032 CALL R4 2 + 0x8C100912, // 0033 GETMET R4 R4 K18 + 0x58180013, // 0034 LDCONST R6 K19 + 0x581C0010, // 0035 LDCONST R7 K16 + 0x7C100600, // 0036 CALL R4 3 + 0x54160FFE, // 0037 LDINT R5 4095 + 0x2C100805, // 0038 AND R4 R4 R5 + 0x90020E04, // 0039 SETMBR R0 K7 R4 + 0x500C0200, // 003A LDBOOL R3 1 0 + 0x8810010A, // 003B GETMBR R4 R0 K10 + 0x4C140000, // 003C LDNIL R5 + 0x1C100805, // 003D EQ R4 R4 R5 + 0x78120002, // 003E JMPF R4 #0042 + 0x88100114, // 003F GETMBR R4 R0 K20 + 0x90021404, // 0040 SETMBR R0 K10 R4 + 0x500C0200, // 0041 LDBOOL R3 1 0 + 0x780E0001, // 0042 JMPF R3 #0045 + 0x8C100115, // 0043 GETMET R4 R0 K21 + 0x7C100200, // 0044 CALL R4 1 + 0x80000000, // 0045 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: every_second +********************************************************************/ +be_local_closure(Matter_Device_every_second, /* name */ + be_nested_proto( + 3, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(sessions), + /* K1 */ be_nested_str_weak(every_second), + /* K2 */ be_nested_str_weak(msg_handler), + }), + be_str_weak(every_second), + &be_const_str_solidified, + ( &(const binstruction[ 7]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0x7C040200, // 0002 CALL R1 1 + 0x88040102, // 0003 GETMBR R1 R0 K2 + 0x8C040301, // 0004 GETMET R1 R1 K1 + 0x7C040200, // 0005 CALL R1 1 + 0x80000000, // 0006 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: save_param +********************************************************************/ +be_local_closure(Matter_Device_save_param, /* name */ + be_nested_proto( + 10, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[15]) { /* constants */ + /* K0 */ be_nested_str_weak(json), + /* K1 */ be_nested_str_weak(dump), + /* K2 */ be_nested_str_weak(distinguish), + /* K3 */ be_nested_str_weak(discriminator), + /* K4 */ be_nested_str_weak(passcode), + /* K5 */ be_nested_str_weak(string), + /* K6 */ be_nested_str_weak(FILENAME), + /* K7 */ be_nested_str_weak(w), + /* K8 */ be_nested_str_weak(write), + /* K9 */ be_nested_str_weak(close), + /* K10 */ be_nested_str_weak(tasmota), + /* K11 */ be_nested_str_weak(log), + /* K12 */ be_nested_str_weak(MTR_X3A_X20Session_Store_X3A_X3Asave_X20Exception_X3A), + /* K13 */ be_nested_str_weak(_X7C), + /* K14 */ be_const_int(2), + }), + be_str_weak(save_param), + &be_const_str_solidified, + ( &(const binstruction[43]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x8C080301, // 0001 GETMET R2 R1 K1 + 0x60100013, // 0002 GETGBL R4 G19 + 0x7C100000, // 0003 CALL R4 0 + 0x88140103, // 0004 GETMBR R5 R0 K3 + 0x98120405, // 0005 SETIDX R4 K2 R5 + 0x88140104, // 0006 GETMBR R5 R0 K4 + 0x98120805, // 0007 SETIDX R4 K4 R5 + 0x7C080400, // 0008 CALL R2 2 + 0xA802000D, // 0009 EXBLK 0 #0018 + 0xA40E0A00, // 000A IMPORT R3 K5 + 0x60100011, // 000B GETGBL R4 G17 + 0x88140106, // 000C GETMBR R5 R0 K6 + 0x58180007, // 000D LDCONST R6 K7 + 0x7C100400, // 000E CALL R4 2 + 0x8C140908, // 000F GETMET R5 R4 K8 + 0x5C1C0400, // 0010 MOVE R7 R2 + 0x7C140400, // 0011 CALL R5 2 + 0x8C140909, // 0012 GETMET R5 R4 K9 + 0x7C140200, // 0013 CALL R5 1 + 0xA8040001, // 0014 EXBLK 1 1 + 0x80040400, // 0015 RET 1 R2 + 0xA8040001, // 0016 EXBLK 1 1 + 0x70020011, // 0017 JMP #002A + 0xAC0C0002, // 0018 CATCH R3 0 2 + 0x7002000E, // 0019 JMP #0029 + 0xB8161400, // 001A GETNGBL R5 K10 + 0x8C140B0B, // 001B GETMET R5 R5 K11 + 0x601C0008, // 001C GETGBL R7 G8 + 0x5C200600, // 001D MOVE R8 R3 + 0x7C1C0200, // 001E CALL R7 1 + 0x001E1807, // 001F ADD R7 K12 R7 + 0x001C0F0D, // 0020 ADD R7 R7 K13 + 0x60200008, // 0021 GETGBL R8 G8 + 0x5C240800, // 0022 MOVE R9 R4 + 0x7C200200, // 0023 CALL R8 1 + 0x001C0E08, // 0024 ADD R7 R7 R8 + 0x5820000E, // 0025 LDCONST R8 K14 + 0x7C140600, // 0026 CALL R5 3 + 0x80040400, // 0027 RET 1 R2 + 0x70020000, // 0028 JMP #002A + 0xB0080000, // 0029 RAISE 2 R0 R0 + 0x80000000, // 002A RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: start_operational_dicovery +********************************************************************/ +be_local_closure(Matter_Device_start_operational_dicovery, /* name */ + be_nested_proto( + 8, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[13]) { /* constants */ + /* K0 */ be_nested_str_weak(crypto), + /* K1 */ be_nested_str_weak(mdns), + /* K2 */ be_nested_str_weak(string), + /* K3 */ be_nested_str_weak(salt), + /* K4 */ be_nested_str_weak(w0), + /* K5 */ be_nested_str_weak(w1), + /* K6 */ be_nested_str_weak(L), + /* K7 */ be_nested_str_weak(set_no_expiration), + /* K8 */ be_nested_str_weak(set_persist), + /* K9 */ be_nested_str_weak(close), + /* K10 */ be_nested_str_weak(sessions), + /* K11 */ be_nested_str_weak(save), + /* K12 */ be_nested_str_weak(mdns_announce_op_discovery), + }), + be_str_weak(start_operational_dicovery), + &be_const_str_solidified, + ( &(const binstruction[25]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0xA40E0200, // 0001 IMPORT R3 K1 + 0xA4120400, // 0002 IMPORT R4 K2 + 0x4C140000, // 0003 LDNIL R5 + 0x90020605, // 0004 SETMBR R0 K3 R5 + 0x4C140000, // 0005 LDNIL R5 + 0x90020805, // 0006 SETMBR R0 K4 R5 + 0x4C140000, // 0007 LDNIL R5 + 0x90020A05, // 0008 SETMBR R0 K5 R5 + 0x4C140000, // 0009 LDNIL R5 + 0x90020C05, // 000A SETMBR R0 K6 R5 + 0x8C140307, // 000B GETMET R5 R1 K7 + 0x7C140200, // 000C CALL R5 1 + 0x8C140308, // 000D GETMET R5 R1 K8 + 0x501C0200, // 000E LDBOOL R7 1 0 + 0x7C140400, // 000F CALL R5 2 + 0x8C140309, // 0010 GETMET R5 R1 K9 + 0x7C140200, // 0011 CALL R5 1 + 0x8814010A, // 0012 GETMBR R5 R0 K10 + 0x8C140B0B, // 0013 GETMET R5 R5 K11 + 0x7C140200, // 0014 CALL R5 1 + 0x8C14010C, // 0015 GETMET R5 R0 K12 + 0x5C1C0200, // 0016 MOVE R7 R1 + 0x7C140400, // 0017 CALL R5 2 + 0x80000000, // 0018 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: compute_manual_pairing_code +********************************************************************/ +be_local_closure(Matter_Device_compute_manual_pairing_code, /* name */ + be_nested_proto( + 11, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(discriminator), + /* K2 */ be_nested_str_weak(passcode), + /* K3 */ be_nested_str_weak(format), + /* K4 */ be_nested_str_weak(_X251i_X2505i_X2504i), + /* K5 */ be_nested_str_weak(matter), + /* K6 */ be_nested_str_weak(Verhoeff), + /* K7 */ be_nested_str_weak(checksum), + }), + be_str_weak(compute_manual_pairing_code), + &be_const_str_solidified, + ( &(const binstruction[31]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x88080101, // 0001 GETMBR R2 R0 K1 + 0x540E0FFE, // 0002 LDINT R3 4095 + 0x2C080403, // 0003 AND R2 R2 R3 + 0x540E0009, // 0004 LDINT R3 10 + 0x3C080403, // 0005 SHR R2 R2 R3 + 0x880C0101, // 0006 GETMBR R3 R0 K1 + 0x541202FF, // 0007 LDINT R4 768 + 0x2C0C0604, // 0008 AND R3 R3 R4 + 0x54120005, // 0009 LDINT R4 6 + 0x380C0604, // 000A SHL R3 R3 R4 + 0x88100102, // 000B GETMBR R4 R0 K2 + 0x54163FFE, // 000C LDINT R5 16383 + 0x2C100805, // 000D AND R4 R4 R5 + 0x300C0604, // 000E OR R3 R3 R4 + 0x88100102, // 000F GETMBR R4 R0 K2 + 0x5416000D, // 0010 LDINT R5 14 + 0x3C100805, // 0011 SHR R4 R4 R5 + 0x8C140303, // 0012 GETMET R5 R1 K3 + 0x581C0004, // 0013 LDCONST R7 K4 + 0x5C200400, // 0014 MOVE R8 R2 + 0x5C240600, // 0015 MOVE R9 R3 + 0x5C280800, // 0016 MOVE R10 R4 + 0x7C140A00, // 0017 CALL R5 5 + 0xB81A0A00, // 0018 GETNGBL R6 K5 + 0x88180D06, // 0019 GETMBR R6 R6 K6 + 0x8C180D07, // 001A GETMET R6 R6 K7 + 0x5C200A00, // 001B MOVE R8 R5 + 0x7C180400, // 001C CALL R6 2 + 0x00140A06, // 001D ADD R5 R5 R6 + 0x80040A00, // 001E RET 1 R5 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: start_udp +********************************************************************/ +be_local_closure(Matter_Device_start_udp, /* name */ + be_nested_proto( + 6, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 1, /* has sup protos */ + ( &(const struct bproto*[ 1]) { + be_nested_proto( + 8, /* nstack */ + 3, /* argc */ + 0, /* varg */ + 1, /* has upvals */ + ( &(const bupvaldesc[ 1]) { /* upvals */ + be_local_const_upval(1, 0), + }), + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(msg_received), + }), + be_str_weak(_X3Clambda_X3E), + &be_const_str_solidified, + ( &(const binstruction[ 7]) { /* code */ + 0x680C0000, // 0000 GETUPV R3 U0 + 0x8C0C0700, // 0001 GETMET R3 R3 K0 + 0x5C140000, // 0002 MOVE R5 R0 + 0x5C180200, // 0003 MOVE R6 R1 + 0x5C1C0400, // 0004 MOVE R7 R2 + 0x7C0C0800, // 0005 CALL R3 4 + 0x80040600, // 0006 RET 1 R3 + }) + ), + }), + 1, /* has constants */ + ( &(const bvalue[ 9]) { /* constants */ + /* K0 */ be_nested_str_weak(udp_server), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(log), + /* K3 */ be_nested_str_weak(MTR_X3A_X20starting_X20UDP_X20server_X20on_X20port_X3A_X20), + /* K4 */ be_const_int(2), + /* K5 */ be_nested_str_weak(matter), + /* K6 */ be_nested_str_weak(UDPServer), + /* K7 */ be_nested_str_weak(), + /* K8 */ be_nested_str_weak(start), + }), + be_str_weak(start_udp), + &be_const_str_solidified, + ( &(const binstruction[27]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x780A0000, // 0001 JMPF R2 #0003 + 0x80000400, // 0002 RET 0 + 0x4C080000, // 0003 LDNIL R2 + 0x1C080202, // 0004 EQ R2 R1 R2 + 0x780A0000, // 0005 JMPF R2 #0007 + 0x540615A3, // 0006 LDINT R1 5540 + 0xB80A0200, // 0007 GETNGBL R2 K1 + 0x8C080502, // 0008 GETMET R2 R2 K2 + 0x60100008, // 0009 GETGBL R4 G8 + 0x5C140200, // 000A MOVE R5 R1 + 0x7C100200, // 000B CALL R4 1 + 0x00120604, // 000C ADD R4 K3 R4 + 0x58140004, // 000D LDCONST R5 K4 + 0x7C080600, // 000E CALL R2 3 + 0xB80A0A00, // 000F GETNGBL R2 K5 + 0x8C080506, // 0010 GETMET R2 R2 K6 + 0x58100007, // 0011 LDCONST R4 K7 + 0x5C140200, // 0012 MOVE R5 R1 + 0x7C080600, // 0013 CALL R2 3 + 0x90020002, // 0014 SETMBR R0 K0 R2 + 0x88080100, // 0015 GETMBR R2 R0 K0 + 0x8C080508, // 0016 GETMET R2 R2 K8 + 0x84100000, // 0017 CLOSURE R4 P0 + 0x7C080400, // 0018 CALL R2 2 + 0xA0000000, // 0019 CLOSE R0 + 0x80000000, // 001A RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: finish_commissioning +********************************************************************/ +be_local_closure(Matter_Device_finish_commissioning, /* name */ + be_nested_proto( + 1, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + be_str_weak(finish_commissioning), + &be_const_str_solidified, + ( &(const binstruction[ 1]) { /* code */ + 0x80000000, // 0000 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: start_mdns_announce_hostnames +********************************************************************/ +be_local_closure(Matter_Device_start_mdns_announce_hostnames, /* name */ + be_nested_proto( + 6, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 1, /* has sup protos */ + ( &(const struct bproto*[ 2]) { + be_nested_proto( + 4, /* nstack */ + 0, /* argc */ + 0, /* varg */ + 1, /* has upvals */ + ( &(const bupvaldesc[ 1]) { /* upvals */ + be_local_const_upval(1, 0), + }), + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(_start_mdns_announce), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(remove_rule), + /* K3 */ be_nested_str_weak(Wifi_X23Connected), + /* K4 */ be_nested_str_weak(matter_device_mdns), + }), + be_str_weak(_anonymous_), + &be_const_str_solidified, + ( &(const binstruction[10]) { /* code */ + 0x68000000, // 0000 GETUPV R0 U0 + 0x8C000100, // 0001 GETMET R0 R0 K0 + 0x50080000, // 0002 LDBOOL R2 0 0 + 0x7C000400, // 0003 CALL R0 2 + 0xB8020200, // 0004 GETNGBL R0 K1 + 0x8C000102, // 0005 GETMET R0 R0 K2 + 0x58080003, // 0006 LDCONST R2 K3 + 0x580C0004, // 0007 LDCONST R3 K4 + 0x7C000600, // 0008 CALL R0 3 + 0x80000000, // 0009 RET 0 + }) + ), + be_nested_proto( + 4, /* nstack */ + 0, /* argc */ + 0, /* varg */ + 1, /* has upvals */ + ( &(const bupvaldesc[ 1]) { /* upvals */ + be_local_const_upval(1, 0), + }), + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(_start_mdns_announce), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(remove_rule), + /* K3 */ be_nested_str_weak(Eth_X23Connected), + /* K4 */ be_nested_str_weak(matter_device_mdns), + }), + be_str_weak(_anonymous_), + &be_const_str_solidified, + ( &(const binstruction[10]) { /* code */ + 0x68000000, // 0000 GETUPV R0 U0 + 0x8C000100, // 0001 GETMET R0 R0 K0 + 0x50080200, // 0002 LDBOOL R2 1 0 + 0x7C000400, // 0003 CALL R0 2 + 0xB8020200, // 0004 GETNGBL R0 K1 + 0x8C000102, // 0005 GETMET R0 R0 K2 + 0x58080003, // 0006 LDCONST R2 K3 + 0x580C0004, // 0007 LDCONST R3 K4 + 0x7C000600, // 0008 CALL R0 3 + 0x80000000, // 0009 RET 0 + }) + ), + }), + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(tasmota), + /* K1 */ be_nested_str_weak(wifi), + /* K2 */ be_nested_str_weak(up), + /* K3 */ be_nested_str_weak(_start_mdns_announce), + /* K4 */ be_nested_str_weak(add_rule), + /* K5 */ be_nested_str_weak(Wifi_X23Connected), + /* K6 */ be_nested_str_weak(eth), + /* K7 */ be_nested_str_weak(Eth_X23Connected), + }), + be_str_weak(start_mdns_announce_hostnames), + &be_const_str_solidified, + ( &(const binstruction[32]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0x7C040200, // 0002 CALL R1 1 + 0x94040302, // 0003 GETIDX R1 R1 K2 + 0x78060003, // 0004 JMPF R1 #0009 + 0x8C040103, // 0005 GETMET R1 R0 K3 + 0x500C0000, // 0006 LDBOOL R3 0 0 + 0x7C040400, // 0007 CALL R1 2 + 0x70020005, // 0008 JMP #000F + 0xB8060000, // 0009 GETNGBL R1 K0 + 0x8C040304, // 000A GETMET R1 R1 K4 + 0x580C0005, // 000B LDCONST R3 K5 + 0x84100000, // 000C CLOSURE R4 P0 + 0x5C140000, // 000D MOVE R5 R0 + 0x7C040800, // 000E CALL R1 4 + 0xB8060000, // 000F GETNGBL R1 K0 + 0x8C040306, // 0010 GETMET R1 R1 K6 + 0x7C040200, // 0011 CALL R1 1 + 0x94040302, // 0012 GETIDX R1 R1 K2 + 0x78060003, // 0013 JMPF R1 #0018 + 0x8C040103, // 0014 GETMET R1 R0 K3 + 0x500C0200, // 0015 LDBOOL R3 1 0 + 0x7C040400, // 0016 CALL R1 2 + 0x70020005, // 0017 JMP #001E + 0xB8060000, // 0018 GETNGBL R1 K0 + 0x8C040304, // 0019 GETMET R1 R1 K4 + 0x580C0007, // 001A LDCONST R3 K7 + 0x84100001, // 001B CLOSURE R4 P1 + 0x5C140000, // 001C MOVE R5 R0 + 0x7C040800, // 001D CALL R1 4 + 0xA0000000, // 001E CLOSE R0 + 0x80000000, // 001F RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: mdns_announce_op_discovery +********************************************************************/ +be_local_closure(Matter_Device_mdns_announce_op_discovery, /* name */ + be_nested_proto( + 15, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[29]) { /* constants */ + /* K0 */ be_nested_str_weak(mdns), + /* K1 */ be_nested_str_weak(string), + /* K2 */ be_nested_str_weak(get_deviceid), + /* K3 */ be_nested_str_weak(copy), + /* K4 */ be_nested_str_weak(reverse), + /* K5 */ be_nested_str_weak(get_fabric_compressed), + /* K6 */ be_nested_str_weak(tohex), + /* K7 */ be_nested_str_weak(_X2D), + /* K8 */ be_nested_str_weak(tasmota), + /* K9 */ be_nested_str_weak(log), + /* K10 */ be_nested_str_weak(MTR_X3A_X20Operational_X20Discovery_X20node_X20_X3D_X20), + /* K11 */ be_const_int(2), + /* K12 */ be_nested_str_weak(eth), + /* K13 */ be_nested_str_weak(find), + /* K14 */ be_nested_str_weak(up), + /* K15 */ be_nested_str_weak(format), + /* K16 */ be_nested_str_weak(MTR_X3A_X20adding_X20mDNS_X20on_X20_X25s_X20_X27_X25s_X27_X20ptr_X20to_X20_X60_X25s_X2Elocal_X60), + /* K17 */ be_nested_str_weak(hostname_eth), + /* K18 */ be_const_int(3), + /* K19 */ be_nested_str_weak(add_service), + /* K20 */ be_nested_str_weak(_matter), + /* K21 */ be_nested_str_weak(_tcp), + /* K22 */ be_nested_str_weak(_I), + /* K23 */ be_nested_str_weak(MTR_X3A_X20adding_X20subtype_X3A_X20), + /* K24 */ be_nested_str_weak(add_subtype), + /* K25 */ be_nested_str_weak(wifi), + /* K26 */ be_nested_str_weak(hostname_wifi), + /* K27 */ be_nested_str_weak(MTR_X3A_X20Exception), + /* K28 */ be_nested_str_weak(_X7C), + }), + be_str_weak(mdns_announce_op_discovery), + &be_const_str_solidified, + ( &(const binstruction[122]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0xA40E0200, // 0001 IMPORT R3 K1 + 0xA8020064, // 0002 EXBLK 0 #0068 + 0x8C100302, // 0003 GETMET R4 R1 K2 + 0x7C100200, // 0004 CALL R4 1 + 0x8C100903, // 0005 GETMET R4 R4 K3 + 0x7C100200, // 0006 CALL R4 1 + 0x8C100904, // 0007 GETMET R4 R4 K4 + 0x7C100200, // 0008 CALL R4 1 + 0x8C140305, // 0009 GETMET R5 R1 K5 + 0x7C140200, // 000A CALL R5 1 + 0x8C180B06, // 000B GETMET R6 R5 K6 + 0x7C180200, // 000C CALL R6 1 + 0x00180D07, // 000D ADD R6 R6 K7 + 0x8C1C0906, // 000E GETMET R7 R4 K6 + 0x7C1C0200, // 000F CALL R7 1 + 0x00180C07, // 0010 ADD R6 R6 R7 + 0xB81E1000, // 0011 GETNGBL R7 K8 + 0x8C1C0F09, // 0012 GETMET R7 R7 K9 + 0x00261406, // 0013 ADD R9 K10 R6 + 0x5828000B, // 0014 LDCONST R10 K11 + 0x7C1C0600, // 0015 CALL R7 3 + 0xB81E1000, // 0016 GETNGBL R7 K8 + 0x8C1C0F0C, // 0017 GETMET R7 R7 K12 + 0x7C1C0200, // 0018 CALL R7 1 + 0x8C1C0F0D, // 0019 GETMET R7 R7 K13 + 0x5824000E, // 001A LDCONST R9 K14 + 0x7C1C0400, // 001B CALL R7 2 + 0x781E0020, // 001C JMPF R7 #003E + 0xB81E1000, // 001D GETNGBL R7 K8 + 0x8C1C0F09, // 001E GETMET R7 R7 K9 + 0x8C24070F, // 001F GETMET R9 R3 K15 + 0x582C0010, // 0020 LDCONST R11 K16 + 0x5830000C, // 0021 LDCONST R12 K12 + 0x5C340C00, // 0022 MOVE R13 R6 + 0x88380111, // 0023 GETMBR R14 R0 K17 + 0x7C240A00, // 0024 CALL R9 5 + 0x58280012, // 0025 LDCONST R10 K18 + 0x7C1C0600, // 0026 CALL R7 3 + 0x8C1C0513, // 0027 GETMET R7 R2 K19 + 0x58240014, // 0028 LDCONST R9 K20 + 0x58280015, // 0029 LDCONST R10 K21 + 0x542E15A3, // 002A LDINT R11 5540 + 0x4C300000, // 002B LDNIL R12 + 0x5C340C00, // 002C MOVE R13 R6 + 0x88380111, // 002D GETMBR R14 R0 K17 + 0x7C1C0E00, // 002E CALL R7 7 + 0x8C1C0B06, // 002F GETMET R7 R5 K6 + 0x7C1C0200, // 0030 CALL R7 1 + 0x001E2C07, // 0031 ADD R7 K22 R7 + 0xB8221000, // 0032 GETNGBL R8 K8 + 0x8C201109, // 0033 GETMET R8 R8 K9 + 0x002A2E07, // 0034 ADD R10 K23 R7 + 0x582C0012, // 0035 LDCONST R11 K18 + 0x7C200600, // 0036 CALL R8 3 + 0x8C200518, // 0037 GETMET R8 R2 K24 + 0x58280014, // 0038 LDCONST R10 K20 + 0x582C0015, // 0039 LDCONST R11 K21 + 0x5C300C00, // 003A MOVE R12 R6 + 0x88340111, // 003B GETMBR R13 R0 K17 + 0x5C380E00, // 003C MOVE R14 R7 + 0x7C200C00, // 003D CALL R8 6 + 0xB81E1000, // 003E GETNGBL R7 K8 + 0x8C1C0F19, // 003F GETMET R7 R7 K25 + 0x7C1C0200, // 0040 CALL R7 1 + 0x8C1C0F0D, // 0041 GETMET R7 R7 K13 + 0x5824000E, // 0042 LDCONST R9 K14 + 0x7C1C0400, // 0043 CALL R7 2 + 0x781E0020, // 0044 JMPF R7 #0066 + 0xB81E1000, // 0045 GETNGBL R7 K8 + 0x8C1C0F09, // 0046 GETMET R7 R7 K9 + 0x8C24070F, // 0047 GETMET R9 R3 K15 + 0x582C0010, // 0048 LDCONST R11 K16 + 0x58300019, // 0049 LDCONST R12 K25 + 0x5C340C00, // 004A MOVE R13 R6 + 0x8838011A, // 004B GETMBR R14 R0 K26 + 0x7C240A00, // 004C CALL R9 5 + 0x58280012, // 004D LDCONST R10 K18 + 0x7C1C0600, // 004E CALL R7 3 + 0x8C1C0513, // 004F GETMET R7 R2 K19 + 0x58240014, // 0050 LDCONST R9 K20 + 0x58280015, // 0051 LDCONST R10 K21 + 0x542E15A3, // 0052 LDINT R11 5540 + 0x4C300000, // 0053 LDNIL R12 + 0x5C340C00, // 0054 MOVE R13 R6 + 0x8838011A, // 0055 GETMBR R14 R0 K26 + 0x7C1C0E00, // 0056 CALL R7 7 + 0x8C1C0B06, // 0057 GETMET R7 R5 K6 + 0x7C1C0200, // 0058 CALL R7 1 + 0x001E2C07, // 0059 ADD R7 K22 R7 + 0xB8221000, // 005A GETNGBL R8 K8 + 0x8C201109, // 005B GETMET R8 R8 K9 + 0x002A2E07, // 005C ADD R10 K23 R7 + 0x582C0012, // 005D LDCONST R11 K18 + 0x7C200600, // 005E CALL R8 3 + 0x8C200518, // 005F GETMET R8 R2 K24 + 0x58280014, // 0060 LDCONST R10 K20 + 0x582C0015, // 0061 LDCONST R11 K21 + 0x5C300C00, // 0062 MOVE R12 R6 + 0x8834011A, // 0063 GETMBR R13 R0 K26 + 0x5C380E00, // 0064 MOVE R14 R7 + 0x7C200C00, // 0065 CALL R8 6 + 0xA8040001, // 0066 EXBLK 1 1 + 0x70020010, // 0067 JMP #0079 + 0xAC100002, // 0068 CATCH R4 0 2 + 0x7002000D, // 0069 JMP #0078 + 0xB81A1000, // 006A GETNGBL R6 K8 + 0x8C180D09, // 006B GETMET R6 R6 K9 + 0x60200008, // 006C GETGBL R8 G8 + 0x5C240800, // 006D MOVE R9 R4 + 0x7C200200, // 006E CALL R8 1 + 0x00223608, // 006F ADD R8 K27 R8 + 0x0020111C, // 0070 ADD R8 R8 K28 + 0x60240008, // 0071 GETGBL R9 G8 + 0x5C280A00, // 0072 MOVE R10 R5 + 0x7C240200, // 0073 CALL R9 1 + 0x00201009, // 0074 ADD R8 R8 R9 + 0x5824000B, // 0075 LDCONST R9 K11 + 0x7C180600, // 0076 CALL R6 3 + 0x70020000, // 0077 JMP #0079 + 0xB0080000, // 0078 RAISE 2 R0 R0 + 0x80000000, // 0079 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: start_commissioning_complete +********************************************************************/ +be_local_closure(Matter_Device_start_commissioning_complete, /* name */ + be_nested_proto( + 6, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(tasmota), + /* K1 */ be_nested_str_weak(log), + /* K2 */ be_nested_str_weak(MTR_X3A_X20_X2A_X2A_X2A_X20Commissioning_X20complete_X20_X2A_X2A_X2A), + /* K3 */ be_const_int(2), + }), + be_str_weak(start_commissioning_complete), + &be_const_str_solidified, + ( &(const binstruction[ 6]) { /* code */ + 0xB80A0000, // 0000 GETNGBL R2 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x58100002, // 0002 LDCONST R4 K2 + 0x58140003, // 0003 LDCONST R5 K3 + 0x7C080600, // 0004 CALL R2 3 + 0x80000000, // 0005 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: start_basic_commissioning +********************************************************************/ +be_local_closure(Matter_Device_start_basic_commissioning, /* name */ + be_nested_proto( + 4, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(compute_pbkdf), + /* K1 */ be_nested_str_weak(passcode), + }), + be_str_weak(start_basic_commissioning), + &be_const_str_solidified, + ( &(const binstruction[ 4]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x880C0101, // 0001 GETMBR R3 R0 K1 + 0x7C040400, // 0002 CALL R1 2 + 0x80000000, // 0003 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: compute_pbkdf +********************************************************************/ +be_local_closure(Matter_Device_compute_pbkdf, /* name */ + be_nested_proto( + 11, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[24]) { /* constants */ + /* K0 */ be_nested_str_weak(crypto), + /* K1 */ be_nested_str_weak(salt), + /* K2 */ be_nested_str_weak(random), + /* K3 */ be_nested_str_weak(add), + /* K4 */ be_nested_str_weak(PBKDF2_HMAC_SHA256), + /* K5 */ be_nested_str_weak(derive), + /* K6 */ be_nested_str_weak(iterations), + /* K7 */ be_const_int(0), + /* K8 */ be_nested_str_weak(w0), + /* K9 */ be_nested_str_weak(EC_P256), + /* K10 */ be_nested_str_weak(mod), + /* K11 */ be_nested_str_weak(w1), + /* K12 */ be_nested_str_weak(L), + /* K13 */ be_nested_str_weak(public_key), + /* K14 */ be_nested_str_weak(tasmota), + /* K15 */ be_nested_str_weak(log), + /* K16 */ be_nested_str_weak(MTR_X3A_X20_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A), + /* K17 */ be_const_int(3), + /* K18 */ be_nested_str_weak(MTR_X3A_X20salt_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K19 */ be_nested_str_weak(tohex), + /* K20 */ be_nested_str_weak(MTR_X3A_X20passcode_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K21 */ be_nested_str_weak(MTR_X3A_X20w0_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K22 */ be_nested_str_weak(MTR_X3A_X20w1_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K23 */ be_nested_str_weak(MTR_X3A_X20L_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D_X20), + }), + be_str_weak(compute_pbkdf), + &be_const_str_solidified, + ( &(const binstruction[94]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0x8C0C0502, // 0001 GETMET R3 R2 K2 + 0x5416000F, // 0002 LDINT R5 16 + 0x7C0C0400, // 0003 CALL R3 2 + 0x90020203, // 0004 SETMBR R0 K1 R3 + 0x600C0015, // 0005 GETGBL R3 G21 + 0x7C0C0000, // 0006 CALL R3 0 + 0x8C0C0703, // 0007 GETMET R3 R3 K3 + 0x5C140200, // 0008 MOVE R5 R1 + 0x541A0003, // 0009 LDINT R6 4 + 0x7C0C0600, // 000A CALL R3 3 + 0x8C100504, // 000B GETMET R4 R2 K4 + 0x7C100200, // 000C CALL R4 1 + 0x8C100905, // 000D GETMET R4 R4 K5 + 0x5C180600, // 000E MOVE R6 R3 + 0x881C0101, // 000F GETMBR R7 R0 K1 + 0x88200106, // 0010 GETMBR R8 R0 K6 + 0x5426004F, // 0011 LDINT R9 80 + 0x7C100A00, // 0012 CALL R4 5 + 0x54160026, // 0013 LDINT R5 39 + 0x40160E05, // 0014 CONNECT R5 K7 R5 + 0x94140805, // 0015 GETIDX R5 R4 R5 + 0x541A0027, // 0016 LDINT R6 40 + 0x541E004E, // 0017 LDINT R7 79 + 0x40180C07, // 0018 CONNECT R6 R6 R7 + 0x94180806, // 0019 GETIDX R6 R4 R6 + 0x8C1C0509, // 001A GETMET R7 R2 K9 + 0x7C1C0200, // 001B CALL R7 1 + 0x8C1C0F0A, // 001C GETMET R7 R7 K10 + 0x5C240A00, // 001D MOVE R9 R5 + 0x7C1C0400, // 001E CALL R7 2 + 0x90021007, // 001F SETMBR R0 K8 R7 + 0x8C1C0509, // 0020 GETMET R7 R2 K9 + 0x7C1C0200, // 0021 CALL R7 1 + 0x8C1C0F0A, // 0022 GETMET R7 R7 K10 + 0x5C240C00, // 0023 MOVE R9 R6 + 0x7C1C0400, // 0024 CALL R7 2 + 0x90021607, // 0025 SETMBR R0 K11 R7 + 0x8C1C0509, // 0026 GETMET R7 R2 K9 + 0x7C1C0200, // 0027 CALL R7 1 + 0x8C1C0F0D, // 0028 GETMET R7 R7 K13 + 0x8824010B, // 0029 GETMBR R9 R0 K11 + 0x7C1C0400, // 002A CALL R7 2 + 0x90021807, // 002B SETMBR R0 K12 R7 + 0xB81E1C00, // 002C GETNGBL R7 K14 + 0x8C1C0F0F, // 002D GETMET R7 R7 K15 + 0x58240010, // 002E LDCONST R9 K16 + 0x58280011, // 002F LDCONST R10 K17 + 0x7C1C0600, // 0030 CALL R7 3 + 0xB81E1C00, // 0031 GETNGBL R7 K14 + 0x8C1C0F0F, // 0032 GETMET R7 R7 K15 + 0x88240101, // 0033 GETMBR R9 R0 K1 + 0x8C241313, // 0034 GETMET R9 R9 K19 + 0x7C240200, // 0035 CALL R9 1 + 0x00262409, // 0036 ADD R9 K18 R9 + 0x58280011, // 0037 LDCONST R10 K17 + 0x7C1C0600, // 0038 CALL R7 3 + 0xB81E1C00, // 0039 GETNGBL R7 K14 + 0x8C1C0F0F, // 003A GETMET R7 R7 K15 + 0x8C240713, // 003B GETMET R9 R3 K19 + 0x7C240200, // 003C CALL R9 1 + 0x00262809, // 003D ADD R9 K20 R9 + 0x58280011, // 003E LDCONST R10 K17 + 0x7C1C0600, // 003F CALL R7 3 + 0xB81E1C00, // 0040 GETNGBL R7 K14 + 0x8C1C0F0F, // 0041 GETMET R7 R7 K15 + 0x88240108, // 0042 GETMBR R9 R0 K8 + 0x8C241313, // 0043 GETMET R9 R9 K19 + 0x7C240200, // 0044 CALL R9 1 + 0x00262A09, // 0045 ADD R9 K21 R9 + 0x58280011, // 0046 LDCONST R10 K17 + 0x7C1C0600, // 0047 CALL R7 3 + 0xB81E1C00, // 0048 GETNGBL R7 K14 + 0x8C1C0F0F, // 0049 GETMET R7 R7 K15 + 0x8824010B, // 004A GETMBR R9 R0 K11 + 0x8C241313, // 004B GETMET R9 R9 K19 + 0x7C240200, // 004C CALL R9 1 + 0x00262C09, // 004D ADD R9 K22 R9 + 0x58280011, // 004E LDCONST R10 K17 + 0x7C1C0600, // 004F CALL R7 3 + 0xB81E1C00, // 0050 GETNGBL R7 K14 + 0x8C1C0F0F, // 0051 GETMET R7 R7 K15 + 0x8824010C, // 0052 GETMBR R9 R0 K12 + 0x8C241313, // 0053 GETMET R9 R9 K19 + 0x7C240200, // 0054 CALL R9 1 + 0x00262E09, // 0055 ADD R9 K23 R9 + 0x58280011, // 0056 LDCONST R10 K17 + 0x7C1C0600, // 0057 CALL R7 3 + 0xB81E1C00, // 0058 GETNGBL R7 K14 + 0x8C1C0F0F, // 0059 GETMET R7 R7 K15 + 0x58240010, // 005A LDCONST R9 K16 + 0x58280011, // 005B LDCONST R10 K17 + 0x7C1C0600, // 005C CALL R7 3 + 0x80000000, // 005D RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_Device_init, /* name */ + be_nested_proto( + 8, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 1, /* has sup protos */ + ( &(const struct bproto*[ 2]) { + be_nested_proto( + 4, /* nstack */ + 0, /* argc */ + 0, /* varg */ + 1, /* has upvals */ + ( &(const bupvaldesc[ 1]) { /* upvals */ + be_local_const_upval(1, 0), + }), + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(start_udp), + /* K1 */ be_nested_str_weak(UDP_PORT), + /* K2 */ be_nested_str_weak(tasmota), + /* K3 */ be_nested_str_weak(remove_rule), + /* K4 */ be_nested_str_weak(Wifi_X23Connected), + /* K5 */ be_nested_str_weak(matter_device_udp), + }), + be_str_weak(_anonymous_), + &be_const_str_solidified, + ( &(const binstruction[11]) { /* code */ + 0x68000000, // 0000 GETUPV R0 U0 + 0x8C000100, // 0001 GETMET R0 R0 K0 + 0x68080000, // 0002 GETUPV R2 U0 + 0x88080501, // 0003 GETMBR R2 R2 K1 + 0x7C000400, // 0004 CALL R0 2 + 0xB8020400, // 0005 GETNGBL R0 K2 + 0x8C000103, // 0006 GETMET R0 R0 K3 + 0x58080004, // 0007 LDCONST R2 K4 + 0x580C0005, // 0008 LDCONST R3 K5 + 0x7C000600, // 0009 CALL R0 3 + 0x80000000, // 000A RET 0 + }) + ), + be_nested_proto( + 4, /* nstack */ + 0, /* argc */ + 0, /* varg */ + 1, /* has upvals */ + ( &(const bupvaldesc[ 1]) { /* upvals */ + be_local_const_upval(1, 0), + }), + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(start_udp), + /* K1 */ be_nested_str_weak(UDP_PORT), + /* K2 */ be_nested_str_weak(tasmota), + /* K3 */ be_nested_str_weak(remove_rule), + /* K4 */ be_nested_str_weak(Eth_X23Connected), + /* K5 */ be_nested_str_weak(matter_device_udp), + }), + be_str_weak(_anonymous_), + &be_const_str_solidified, + ( &(const binstruction[11]) { /* code */ + 0x68000000, // 0000 GETUPV R0 U0 + 0x8C000100, // 0001 GETMET R0 R0 K0 + 0x68080000, // 0002 GETUPV R2 U0 + 0x88080501, // 0003 GETMBR R2 R2 K1 + 0x7C000400, // 0004 CALL R0 2 + 0xB8020400, // 0005 GETNGBL R0 K2 + 0x8C000103, // 0006 GETMET R0 R0 K3 + 0x58080004, // 0007 LDCONST R2 K4 + 0x580C0005, // 0008 LDCONST R3 K5 + 0x7C000600, // 0009 CALL R0 3 + 0x80000000, // 000A RET 0 + }) + ), + }), + 1, /* has constants */ + ( &(const bvalue[38]) { /* constants */ + /* K0 */ be_nested_str_weak(crypto), + /* K1 */ be_nested_str_weak(string), + /* K2 */ be_nested_str_weak(tasmota), + /* K3 */ be_nested_str_weak(get_option), + /* K4 */ be_nested_str_weak(matter), + /* K5 */ be_nested_str_weak(MATTER_OPTION), + /* K6 */ be_nested_str_weak(UI), + /* K7 */ be_nested_str_weak(plugins), + /* K8 */ be_nested_str_weak(vendorid), + /* K9 */ be_nested_str_weak(VENDOR_ID), + /* K10 */ be_nested_str_weak(productid), + /* K11 */ be_nested_str_weak(PRODUCT_ID), + /* K12 */ be_nested_str_weak(iterations), + /* K13 */ be_nested_str_weak(PBKDF_ITERATIONS), + /* K14 */ be_nested_str_weak(load_param), + /* K15 */ be_nested_str_weak(commissioning_instance_wifi), + /* K16 */ be_nested_str_weak(random), + /* K17 */ be_nested_str_weak(tohex), + /* K18 */ be_nested_str_weak(commissioning_instance_eth), + /* K19 */ be_nested_str_weak(sessions), + /* K20 */ be_nested_str_weak(Session_Store), + /* K21 */ be_nested_str_weak(load), + /* K22 */ be_nested_str_weak(msg_handler), + /* K23 */ be_nested_str_weak(MessageHandler), + /* K24 */ be_nested_str_weak(ui), + /* K25 */ be_nested_str_weak(push), + /* K26 */ be_nested_str_weak(Plugin_core), + /* K27 */ be_nested_str_weak(start_mdns_announce_hostnames), + /* K28 */ be_nested_str_weak(wifi), + /* K29 */ be_nested_str_weak(up), + /* K30 */ be_nested_str_weak(start_udp), + /* K31 */ be_nested_str_weak(UDP_PORT), + /* K32 */ be_nested_str_weak(add_rule), + /* K33 */ be_nested_str_weak(Wifi_X23Connected), + /* K34 */ be_nested_str_weak(eth), + /* K35 */ be_nested_str_weak(Eth_X23Connected), + /* K36 */ be_nested_str_weak(start_basic_commissioning), + /* K37 */ be_nested_str_weak(add_driver), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[100]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0xA40A0200, // 0001 IMPORT R2 K1 + 0xB80E0400, // 0002 GETNGBL R3 K2 + 0x8C0C0703, // 0003 GETMET R3 R3 K3 + 0xB8160800, // 0004 GETNGBL R5 K4 + 0x88140B05, // 0005 GETMBR R5 R5 K5 + 0x7C0C0400, // 0006 CALL R3 2 + 0x740E0004, // 0007 JMPT R3 #000D + 0xB80E0800, // 0008 GETNGBL R3 K4 + 0x8C0C0706, // 0009 GETMET R3 R3 K6 + 0x5C140000, // 000A MOVE R5 R0 + 0x7C0C0400, // 000B CALL R3 2 + 0x80000600, // 000C RET 0 + 0x600C0012, // 000D GETGBL R3 G18 + 0x7C0C0000, // 000E CALL R3 0 + 0x90020E03, // 000F SETMBR R0 K7 R3 + 0x880C0109, // 0010 GETMBR R3 R0 K9 + 0x90021003, // 0011 SETMBR R0 K8 R3 + 0x880C010B, // 0012 GETMBR R3 R0 K11 + 0x90021403, // 0013 SETMBR R0 K10 R3 + 0x880C010D, // 0014 GETMBR R3 R0 K13 + 0x90021803, // 0015 SETMBR R0 K12 R3 + 0x8C0C010E, // 0016 GETMET R3 R0 K14 + 0x7C0C0200, // 0017 CALL R3 1 + 0x8C0C0310, // 0018 GETMET R3 R1 K16 + 0x54160007, // 0019 LDINT R5 8 + 0x7C0C0400, // 001A CALL R3 2 + 0x8C0C0711, // 001B GETMET R3 R3 K17 + 0x7C0C0200, // 001C CALL R3 1 + 0x90021E03, // 001D SETMBR R0 K15 R3 + 0x8C0C0310, // 001E GETMET R3 R1 K16 + 0x54160007, // 001F LDINT R5 8 + 0x7C0C0400, // 0020 CALL R3 2 + 0x8C0C0711, // 0021 GETMET R3 R3 K17 + 0x7C0C0200, // 0022 CALL R3 1 + 0x90022403, // 0023 SETMBR R0 K18 R3 + 0xB80E0800, // 0024 GETNGBL R3 K4 + 0x8C0C0714, // 0025 GETMET R3 R3 K20 + 0x7C0C0200, // 0026 CALL R3 1 + 0x90022603, // 0027 SETMBR R0 K19 R3 + 0x880C0113, // 0028 GETMBR R3 R0 K19 + 0x8C0C0715, // 0029 GETMET R3 R3 K21 + 0x7C0C0200, // 002A CALL R3 1 + 0xB80E0800, // 002B GETNGBL R3 K4 + 0x8C0C0717, // 002C GETMET R3 R3 K23 + 0x5C140000, // 002D MOVE R5 R0 + 0x7C0C0400, // 002E CALL R3 2 + 0x90022C03, // 002F SETMBR R0 K22 R3 + 0xB80E0800, // 0030 GETNGBL R3 K4 + 0x8C0C0706, // 0031 GETMET R3 R3 K6 + 0x5C140000, // 0032 MOVE R5 R0 + 0x7C0C0400, // 0033 CALL R3 2 + 0x90023003, // 0034 SETMBR R0 K24 R3 + 0x880C0107, // 0035 GETMBR R3 R0 K7 + 0x8C0C0719, // 0036 GETMET R3 R3 K25 + 0xB8160800, // 0037 GETNGBL R5 K4 + 0x8C140B1A, // 0038 GETMET R5 R5 K26 + 0x5C1C0000, // 0039 MOVE R7 R0 + 0x7C140400, // 003A CALL R5 2 + 0x7C0C0400, // 003B CALL R3 2 + 0x8C0C011B, // 003C GETMET R3 R0 K27 + 0x7C0C0200, // 003D CALL R3 1 + 0xB80E0400, // 003E GETNGBL R3 K2 + 0x8C0C071C, // 003F GETMET R3 R3 K28 + 0x7C0C0200, // 0040 CALL R3 1 + 0x940C071D, // 0041 GETIDX R3 R3 K29 + 0x780E0003, // 0042 JMPF R3 #0047 + 0x8C0C011E, // 0043 GETMET R3 R0 K30 + 0x8814011F, // 0044 GETMBR R5 R0 K31 + 0x7C0C0400, // 0045 CALL R3 2 + 0x70020005, // 0046 JMP #004D + 0xB80E0400, // 0047 GETNGBL R3 K2 + 0x8C0C0720, // 0048 GETMET R3 R3 K32 + 0x58140021, // 0049 LDCONST R5 K33 + 0x84180000, // 004A CLOSURE R6 P0 + 0x5C1C0000, // 004B MOVE R7 R0 + 0x7C0C0800, // 004C CALL R3 4 + 0xB80E0400, // 004D GETNGBL R3 K2 + 0x8C0C0722, // 004E GETMET R3 R3 K34 + 0x7C0C0200, // 004F CALL R3 1 + 0x940C071D, // 0050 GETIDX R3 R3 K29 + 0x780E0003, // 0051 JMPF R3 #0056 + 0x8C0C011E, // 0052 GETMET R3 R0 K30 + 0x8814011F, // 0053 GETMBR R5 R0 K31 + 0x7C0C0400, // 0054 CALL R3 2 + 0x70020005, // 0055 JMP #005C + 0xB80E0400, // 0056 GETNGBL R3 K2 + 0x8C0C0720, // 0057 GETMET R3 R3 K32 + 0x58140023, // 0058 LDCONST R5 K35 + 0x84180001, // 0059 CLOSURE R6 P1 + 0x5C1C0000, // 005A MOVE R7 R0 + 0x7C0C0800, // 005B CALL R3 4 + 0x8C0C0124, // 005C GETMET R3 R0 K36 + 0x7C0C0200, // 005D CALL R3 1 + 0xB80E0400, // 005E GETNGBL R3 K2 + 0x8C0C0725, // 005F GETMET R3 R3 K37 + 0x5C140000, // 0060 MOVE R5 R0 + 0x7C0C0400, // 0061 CALL R3 2 + 0xA0000000, // 0062 CLOSE R0 + 0x80000000, // 0063 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: _start_mdns_announce +********************************************************************/ +be_local_closure(Matter_Device__start_mdns_announce, /* name */ + be_nested_proto( + 15, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[50]) { /* constants */ + /* K0 */ be_nested_str_weak(mdns), + /* K1 */ be_nested_str_weak(string), + /* K2 */ be_nested_str_weak(start), + /* K3 */ be_nested_str_weak(VP), + /* K4 */ be_nested_str_weak(vendorid), + /* K5 */ be_nested_str_weak(_X2B), + /* K6 */ be_nested_str_weak(productid), + /* K7 */ be_nested_str_weak(D), + /* K8 */ be_nested_str_weak(discriminator), + /* K9 */ be_nested_str_weak(CM), + /* K10 */ be_const_int(1), + /* K11 */ be_nested_str_weak(T), + /* K12 */ be_const_int(0), + /* K13 */ be_nested_str_weak(SII), + /* K14 */ be_nested_str_weak(SAI), + /* K15 */ be_nested_str_weak(tasmota), + /* K16 */ be_nested_str_weak(eth), + /* K17 */ be_nested_str_weak(hostname_eth), + /* K18 */ be_nested_str_weak(replace), + /* K19 */ be_nested_str_weak(find), + /* K20 */ be_nested_str_weak(mac), + /* K21 */ be_nested_str_weak(_X3A), + /* K22 */ be_nested_str_weak(), + /* K23 */ be_nested_str_weak(add_hostname), + /* K24 */ be_nested_str_weak(ip6local), + /* K25 */ be_nested_str_weak(ip), + /* K26 */ be_nested_str_weak(ip6), + /* K27 */ be_nested_str_weak(add_service), + /* K28 */ be_nested_str_weak(_matterc), + /* K29 */ be_nested_str_weak(_udp), + /* K30 */ be_nested_str_weak(commissioning_instance_eth), + /* K31 */ be_nested_str_weak(log), + /* K32 */ be_nested_str_weak(format), + /* K33 */ be_nested_str_weak(MTR_X3A_X20starting_X20mDNS_X20on_X20_X25s_X20_X27_X25s_X27_X20ptr_X20to_X20_X60_X25s_X2Elocal_X60), + /* K34 */ be_nested_str_weak(wifi), + /* K35 */ be_nested_str_weak(commissioning_instance_wifi), + /* K36 */ be_nested_str_weak(hostname_wifi), + /* K37 */ be_const_int(2), + /* K38 */ be_nested_str_weak(_L), + /* K39 */ be_nested_str_weak(MTR_X3A_X20adding_X20subtype_X3A_X20), + /* K40 */ be_const_int(3), + /* K41 */ be_nested_str_weak(add_subtype), + /* K42 */ be_nested_str_weak(_S), + /* K43 */ be_nested_str_weak(_V), + /* K44 */ be_nested_str_weak(_CM1), + /* K45 */ be_nested_str_weak(_matter), + /* K46 */ be_nested_str_weak(_tcp), + /* K47 */ be_nested_str_weak(MTR_X3A_X20Exception), + /* K48 */ be_nested_str_weak(_X7C), + /* K49 */ be_nested_str_weak(mdns_announce_op_discovery_all_sessions), + }), + be_str_weak(_start_mdns_announce), + &be_const_str_solidified, + ( &(const binstruction[292]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0xA40E0200, // 0001 IMPORT R3 K1 + 0x8C100502, // 0002 GETMET R4 R2 K2 + 0x7C100200, // 0003 CALL R4 1 + 0x60100013, // 0004 GETGBL R4 G19 + 0x7C100000, // 0005 CALL R4 0 + 0x60140008, // 0006 GETGBL R5 G8 + 0x88180104, // 0007 GETMBR R6 R0 K4 + 0x7C140200, // 0008 CALL R5 1 + 0x00140B05, // 0009 ADD R5 R5 K5 + 0x60180008, // 000A GETGBL R6 G8 + 0x881C0106, // 000B GETMBR R7 R0 K6 + 0x7C180200, // 000C CALL R6 1 + 0x00140A06, // 000D ADD R5 R5 R6 + 0x98120605, // 000E SETIDX R4 K3 R5 + 0x88140108, // 000F GETMBR R5 R0 K8 + 0x98120E05, // 0010 SETIDX R4 K7 R5 + 0x9812130A, // 0011 SETIDX R4 K9 K10 + 0x9812170C, // 0012 SETIDX R4 K11 K12 + 0x54161387, // 0013 LDINT R5 5000 + 0x98121A05, // 0014 SETIDX R4 K13 R5 + 0x5416012B, // 0015 LDINT R5 300 + 0x98121C05, // 0016 SETIDX R4 K14 R5 + 0xA80200F7, // 0017 EXBLK 0 #0110 + 0x7806007A, // 0018 JMPF R1 #0094 + 0xB8161E00, // 0019 GETNGBL R5 K15 + 0x8C140B10, // 001A GETMET R5 R5 K16 + 0x7C140200, // 001B CALL R5 1 + 0x8C180712, // 001C GETMET R6 R3 K18 + 0x8C200B13, // 001D GETMET R8 R5 K19 + 0x58280014, // 001E LDCONST R10 K20 + 0x7C200400, // 001F CALL R8 2 + 0x58240015, // 0020 LDCONST R9 K21 + 0x58280016, // 0021 LDCONST R10 K22 + 0x7C180800, // 0022 CALL R6 4 + 0x90022206, // 0023 SETMBR R0 K17 R6 + 0x8C180517, // 0024 GETMET R6 R2 K23 + 0x88200111, // 0025 GETMBR R8 R0 K17 + 0x8C240B13, // 0026 GETMET R9 R5 K19 + 0x582C0018, // 0027 LDCONST R11 K24 + 0x58300016, // 0028 LDCONST R12 K22 + 0x7C240600, // 0029 CALL R9 3 + 0x8C280B13, // 002A GETMET R10 R5 K19 + 0x58300019, // 002B LDCONST R12 K25 + 0x58340016, // 002C LDCONST R13 K22 + 0x7C280600, // 002D CALL R10 3 + 0x8C2C0B13, // 002E GETMET R11 R5 K19 + 0x5834001A, // 002F LDCONST R13 K26 + 0x58380016, // 0030 LDCONST R14 K22 + 0x7C2C0600, // 0031 CALL R11 3 + 0x7C180A00, // 0032 CALL R6 5 + 0x8C18051B, // 0033 GETMET R6 R2 K27 + 0x5820001C, // 0034 LDCONST R8 K28 + 0x5824001D, // 0035 LDCONST R9 K29 + 0x542A15A3, // 0036 LDINT R10 5540 + 0x5C2C0800, // 0037 MOVE R11 R4 + 0x8830011E, // 0038 GETMBR R12 R0 K30 + 0x88340111, // 0039 GETMBR R13 R0 K17 + 0x7C180E00, // 003A CALL R6 7 + 0xB81A1E00, // 003B GETNGBL R6 K15 + 0x8C180D1F, // 003C GETMET R6 R6 K31 + 0x8C200720, // 003D GETMET R8 R3 K32 + 0x58280021, // 003E LDCONST R10 K33 + 0x78060001, // 003F JMPF R1 #0042 + 0x582C0010, // 0040 LDCONST R11 K16 + 0x70020000, // 0041 JMP #0043 + 0x582C0022, // 0042 LDCONST R11 K34 + 0x78060001, // 0043 JMPF R1 #0046 + 0x8830011E, // 0044 GETMBR R12 R0 K30 + 0x70020000, // 0045 JMP #0047 + 0x88300123, // 0046 GETMBR R12 R0 K35 + 0x78060001, // 0047 JMPF R1 #004A + 0x88340111, // 0048 GETMBR R13 R0 K17 + 0x70020000, // 0049 JMP #004B + 0x88340124, // 004A GETMBR R13 R0 K36 + 0x7C200A00, // 004B CALL R8 5 + 0x58240025, // 004C LDCONST R9 K37 + 0x7C180600, // 004D CALL R6 3 + 0x60180008, // 004E GETGBL R6 G8 + 0x881C0108, // 004F GETMBR R7 R0 K8 + 0x54220FFE, // 0050 LDINT R8 4095 + 0x2C1C0E08, // 0051 AND R7 R7 R8 + 0x7C180200, // 0052 CALL R6 1 + 0x001A4C06, // 0053 ADD R6 K38 R6 + 0xB81E1E00, // 0054 GETNGBL R7 K15 + 0x8C1C0F1F, // 0055 GETMET R7 R7 K31 + 0x00264E06, // 0056 ADD R9 K39 R6 + 0x58280028, // 0057 LDCONST R10 K40 + 0x7C1C0600, // 0058 CALL R7 3 + 0x8C1C0529, // 0059 GETMET R7 R2 K41 + 0x5824001C, // 005A LDCONST R9 K28 + 0x5828001D, // 005B LDCONST R10 K29 + 0x882C011E, // 005C GETMBR R11 R0 K30 + 0x88300111, // 005D GETMBR R12 R0 K17 + 0x5C340C00, // 005E MOVE R13 R6 + 0x7C1C0C00, // 005F CALL R7 6 + 0x601C0008, // 0060 GETGBL R7 G8 + 0x88200108, // 0061 GETMBR R8 R0 K8 + 0x54260EFF, // 0062 LDINT R9 3840 + 0x2C201009, // 0063 AND R8 R8 R9 + 0x54260007, // 0064 LDINT R9 8 + 0x3C201009, // 0065 SHR R8 R8 R9 + 0x7C1C0200, // 0066 CALL R7 1 + 0x001E5407, // 0067 ADD R7 K42 R7 + 0x5C180E00, // 0068 MOVE R6 R7 + 0xB81E1E00, // 0069 GETNGBL R7 K15 + 0x8C1C0F1F, // 006A GETMET R7 R7 K31 + 0x00264E06, // 006B ADD R9 K39 R6 + 0x58280028, // 006C LDCONST R10 K40 + 0x7C1C0600, // 006D CALL R7 3 + 0x8C1C0529, // 006E GETMET R7 R2 K41 + 0x5824001C, // 006F LDCONST R9 K28 + 0x5828001D, // 0070 LDCONST R10 K29 + 0x882C011E, // 0071 GETMBR R11 R0 K30 + 0x88300111, // 0072 GETMBR R12 R0 K17 + 0x5C340C00, // 0073 MOVE R13 R6 + 0x7C1C0C00, // 0074 CALL R7 6 + 0x601C0008, // 0075 GETGBL R7 G8 + 0x88200104, // 0076 GETMBR R8 R0 K4 + 0x7C1C0200, // 0077 CALL R7 1 + 0x001E5607, // 0078 ADD R7 K43 R7 + 0x5C180E00, // 0079 MOVE R6 R7 + 0xB81E1E00, // 007A GETNGBL R7 K15 + 0x8C1C0F1F, // 007B GETMET R7 R7 K31 + 0x00264E06, // 007C ADD R9 K39 R6 + 0x58280028, // 007D LDCONST R10 K40 + 0x7C1C0600, // 007E CALL R7 3 + 0x8C1C0529, // 007F GETMET R7 R2 K41 + 0x5824001C, // 0080 LDCONST R9 K28 + 0x5828001D, // 0081 LDCONST R10 K29 + 0x882C011E, // 0082 GETMBR R11 R0 K30 + 0x88300111, // 0083 GETMBR R12 R0 K17 + 0x5C340C00, // 0084 MOVE R13 R6 + 0x7C1C0C00, // 0085 CALL R7 6 + 0x5818002C, // 0086 LDCONST R6 K44 + 0xB81E1E00, // 0087 GETNGBL R7 K15 + 0x8C1C0F1F, // 0088 GETMET R7 R7 K31 + 0x00264E06, // 0089 ADD R9 K39 R6 + 0x58280028, // 008A LDCONST R10 K40 + 0x7C1C0600, // 008B CALL R7 3 + 0x8C1C0529, // 008C GETMET R7 R2 K41 + 0x5824001C, // 008D LDCONST R9 K28 + 0x5828001D, // 008E LDCONST R10 K29 + 0x882C011E, // 008F GETMBR R11 R0 K30 + 0x88300111, // 0090 GETMBR R12 R0 K17 + 0x5C340C00, // 0091 MOVE R13 R6 + 0x7C1C0C00, // 0092 CALL R7 6 + 0x70020079, // 0093 JMP #010E + 0xB8161E00, // 0094 GETNGBL R5 K15 + 0x8C140B22, // 0095 GETMET R5 R5 K34 + 0x7C140200, // 0096 CALL R5 1 + 0x8C180712, // 0097 GETMET R6 R3 K18 + 0x8C200B13, // 0098 GETMET R8 R5 K19 + 0x58280014, // 0099 LDCONST R10 K20 + 0x7C200400, // 009A CALL R8 2 + 0x58240015, // 009B LDCONST R9 K21 + 0x58280016, // 009C LDCONST R10 K22 + 0x7C180800, // 009D CALL R6 4 + 0x90024806, // 009E SETMBR R0 K36 R6 + 0x8C180517, // 009F GETMET R6 R2 K23 + 0x88200124, // 00A0 GETMBR R8 R0 K36 + 0x8C240B13, // 00A1 GETMET R9 R5 K19 + 0x582C0018, // 00A2 LDCONST R11 K24 + 0x58300016, // 00A3 LDCONST R12 K22 + 0x7C240600, // 00A4 CALL R9 3 + 0x8C280B13, // 00A5 GETMET R10 R5 K19 + 0x58300019, // 00A6 LDCONST R12 K25 + 0x58340016, // 00A7 LDCONST R13 K22 + 0x7C280600, // 00A8 CALL R10 3 + 0x8C2C0B13, // 00A9 GETMET R11 R5 K19 + 0x5834001A, // 00AA LDCONST R13 K26 + 0x58380016, // 00AB LDCONST R14 K22 + 0x7C2C0600, // 00AC CALL R11 3 + 0x7C180A00, // 00AD CALL R6 5 + 0x8C18051B, // 00AE GETMET R6 R2 K27 + 0x5820002D, // 00AF LDCONST R8 K45 + 0x5824002E, // 00B0 LDCONST R9 K46 + 0x542A15A3, // 00B1 LDINT R10 5540 + 0x5C2C0800, // 00B2 MOVE R11 R4 + 0x88300123, // 00B3 GETMBR R12 R0 K35 + 0x88340124, // 00B4 GETMBR R13 R0 K36 + 0x7C180E00, // 00B5 CALL R6 7 + 0xB81A1E00, // 00B6 GETNGBL R6 K15 + 0x8C180D1F, // 00B7 GETMET R6 R6 K31 + 0x8C200720, // 00B8 GETMET R8 R3 K32 + 0x58280021, // 00B9 LDCONST R10 K33 + 0x78060001, // 00BA JMPF R1 #00BD + 0x582C0010, // 00BB LDCONST R11 K16 + 0x70020000, // 00BC JMP #00BE + 0x582C0022, // 00BD LDCONST R11 K34 + 0x78060001, // 00BE JMPF R1 #00C1 + 0x8830011E, // 00BF GETMBR R12 R0 K30 + 0x70020000, // 00C0 JMP #00C2 + 0x88300123, // 00C1 GETMBR R12 R0 K35 + 0x78060001, // 00C2 JMPF R1 #00C5 + 0x88340111, // 00C3 GETMBR R13 R0 K17 + 0x70020000, // 00C4 JMP #00C6 + 0x88340124, // 00C5 GETMBR R13 R0 K36 + 0x7C200A00, // 00C6 CALL R8 5 + 0x58240025, // 00C7 LDCONST R9 K37 + 0x7C180600, // 00C8 CALL R6 3 + 0x60180008, // 00C9 GETGBL R6 G8 + 0x881C0108, // 00CA GETMBR R7 R0 K8 + 0x54220FFE, // 00CB LDINT R8 4095 + 0x2C1C0E08, // 00CC AND R7 R7 R8 + 0x7C180200, // 00CD CALL R6 1 + 0x001A4C06, // 00CE ADD R6 K38 R6 + 0xB81E1E00, // 00CF GETNGBL R7 K15 + 0x8C1C0F1F, // 00D0 GETMET R7 R7 K31 + 0x00264E06, // 00D1 ADD R9 K39 R6 + 0x58280028, // 00D2 LDCONST R10 K40 + 0x7C1C0600, // 00D3 CALL R7 3 + 0x8C1C0529, // 00D4 GETMET R7 R2 K41 + 0x5824001C, // 00D5 LDCONST R9 K28 + 0x5828001D, // 00D6 LDCONST R10 K29 + 0x882C0123, // 00D7 GETMBR R11 R0 K35 + 0x88300124, // 00D8 GETMBR R12 R0 K36 + 0x5C340C00, // 00D9 MOVE R13 R6 + 0x7C1C0C00, // 00DA CALL R7 6 + 0x601C0008, // 00DB GETGBL R7 G8 + 0x88200108, // 00DC GETMBR R8 R0 K8 + 0x54260EFF, // 00DD LDINT R9 3840 + 0x2C201009, // 00DE AND R8 R8 R9 + 0x54260007, // 00DF LDINT R9 8 + 0x3C201009, // 00E0 SHR R8 R8 R9 + 0x7C1C0200, // 00E1 CALL R7 1 + 0x001E5407, // 00E2 ADD R7 K42 R7 + 0x5C180E00, // 00E3 MOVE R6 R7 + 0xB81E1E00, // 00E4 GETNGBL R7 K15 + 0x8C1C0F1F, // 00E5 GETMET R7 R7 K31 + 0x00264E06, // 00E6 ADD R9 K39 R6 + 0x58280028, // 00E7 LDCONST R10 K40 + 0x7C1C0600, // 00E8 CALL R7 3 + 0x8C1C0529, // 00E9 GETMET R7 R2 K41 + 0x5824001C, // 00EA LDCONST R9 K28 + 0x5828001D, // 00EB LDCONST R10 K29 + 0x882C0123, // 00EC GETMBR R11 R0 K35 + 0x88300124, // 00ED GETMBR R12 R0 K36 + 0x5C340C00, // 00EE MOVE R13 R6 + 0x7C1C0C00, // 00EF CALL R7 6 + 0x601C0008, // 00F0 GETGBL R7 G8 + 0x88200104, // 00F1 GETMBR R8 R0 K4 + 0x7C1C0200, // 00F2 CALL R7 1 + 0x001E5607, // 00F3 ADD R7 K43 R7 + 0x5C180E00, // 00F4 MOVE R6 R7 + 0xB81E1E00, // 00F5 GETNGBL R7 K15 + 0x8C1C0F1F, // 00F6 GETMET R7 R7 K31 + 0x00264E06, // 00F7 ADD R9 K39 R6 + 0x58280028, // 00F8 LDCONST R10 K40 + 0x7C1C0600, // 00F9 CALL R7 3 + 0x8C1C0529, // 00FA GETMET R7 R2 K41 + 0x5824001C, // 00FB LDCONST R9 K28 + 0x5828001D, // 00FC LDCONST R10 K29 + 0x882C0123, // 00FD GETMBR R11 R0 K35 + 0x88300124, // 00FE GETMBR R12 R0 K36 + 0x5C340C00, // 00FF MOVE R13 R6 + 0x7C1C0C00, // 0100 CALL R7 6 + 0x5818002C, // 0101 LDCONST R6 K44 + 0xB81E1E00, // 0102 GETNGBL R7 K15 + 0x8C1C0F1F, // 0103 GETMET R7 R7 K31 + 0x00264E06, // 0104 ADD R9 K39 R6 + 0x58280028, // 0105 LDCONST R10 K40 + 0x7C1C0600, // 0106 CALL R7 3 + 0x8C1C0529, // 0107 GETMET R7 R2 K41 + 0x5824001C, // 0108 LDCONST R9 K28 + 0x5828001D, // 0109 LDCONST R10 K29 + 0x882C0123, // 010A GETMBR R11 R0 K35 + 0x88300124, // 010B GETMBR R12 R0 K36 + 0x5C340C00, // 010C MOVE R13 R6 + 0x7C1C0C00, // 010D CALL R7 6 + 0xA8040001, // 010E EXBLK 1 1 + 0x70020010, // 010F JMP #0121 + 0xAC140002, // 0110 CATCH R5 0 2 + 0x7002000D, // 0111 JMP #0120 + 0xB81E1E00, // 0112 GETNGBL R7 K15 + 0x8C1C0F1F, // 0113 GETMET R7 R7 K31 + 0x60240008, // 0114 GETGBL R9 G8 + 0x5C280A00, // 0115 MOVE R10 R5 + 0x7C240200, // 0116 CALL R9 1 + 0x00265E09, // 0117 ADD R9 K47 R9 + 0x00241330, // 0118 ADD R9 R9 K48 + 0x60280008, // 0119 GETGBL R10 G8 + 0x5C2C0C00, // 011A MOVE R11 R6 + 0x7C280200, // 011B CALL R10 1 + 0x0024120A, // 011C ADD R9 R9 R10 + 0x58280025, // 011D LDCONST R10 K37 + 0x7C1C0600, // 011E CALL R7 3 + 0x70020000, // 011F JMP #0121 + 0xB0080000, // 0120 RAISE 2 R0 R0 + 0x8C140131, // 0121 GETMET R5 R0 K49 + 0x7C140200, // 0122 CALL R5 1 + 0x80000000, // 0123 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: compute_qrcode_content +********************************************************************/ +be_local_closure(Matter_Device_compute_qrcode_content, /* name */ + be_nested_proto( + 8, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[12]) { /* constants */ + /* K0 */ be_nested_str_weak(resize), + /* K1 */ be_nested_str_weak(setbits), + /* K2 */ be_const_int(3), + /* K3 */ be_nested_str_weak(vendorid), + /* K4 */ be_nested_str_weak(productid), + /* K5 */ be_nested_str_weak(discriminator), + /* K6 */ be_nested_str_weak(passcode), + /* K7 */ be_const_int(134217727), + /* K8 */ be_nested_str_weak(MT_X3A), + /* K9 */ be_nested_str_weak(matter), + /* K10 */ be_nested_str_weak(Base38), + /* K11 */ be_nested_str_weak(encode), + }), + be_str_weak(compute_qrcode_content), + &be_const_str_solidified, + ( &(const binstruction[40]) { /* code */ + 0x60040015, // 0000 GETGBL R1 G21 + 0x7C040000, // 0001 CALL R1 0 + 0x8C040300, // 0002 GETMET R1 R1 K0 + 0x540E000A, // 0003 LDINT R3 11 + 0x7C040400, // 0004 CALL R1 2 + 0x8C080301, // 0005 GETMET R2 R1 K1 + 0x58100002, // 0006 LDCONST R4 K2 + 0x5416000F, // 0007 LDINT R5 16 + 0x88180103, // 0008 GETMBR R6 R0 K3 + 0x7C080800, // 0009 CALL R2 4 + 0x8C080301, // 000A GETMET R2 R1 K1 + 0x54120012, // 000B LDINT R4 19 + 0x5416000F, // 000C LDINT R5 16 + 0x88180104, // 000D GETMBR R6 R0 K4 + 0x7C080800, // 000E CALL R2 4 + 0x8C080301, // 000F GETMET R2 R1 K1 + 0x54120024, // 0010 LDINT R4 37 + 0x54160007, // 0011 LDINT R5 8 + 0x541A0003, // 0012 LDINT R6 4 + 0x7C080800, // 0013 CALL R2 4 + 0x8C080301, // 0014 GETMET R2 R1 K1 + 0x5412002C, // 0015 LDINT R4 45 + 0x5416000B, // 0016 LDINT R5 12 + 0x88180105, // 0017 GETMBR R6 R0 K5 + 0x541E0FFE, // 0018 LDINT R7 4095 + 0x2C180C07, // 0019 AND R6 R6 R7 + 0x7C080800, // 001A CALL R2 4 + 0x8C080301, // 001B GETMET R2 R1 K1 + 0x54120038, // 001C LDINT R4 57 + 0x5416001A, // 001D LDINT R5 27 + 0x88180106, // 001E GETMBR R6 R0 K6 + 0x2C180D07, // 001F AND R6 R6 K7 + 0x7C080800, // 0020 CALL R2 4 + 0xB80A1200, // 0021 GETNGBL R2 K9 + 0x8808050A, // 0022 GETMBR R2 R2 K10 + 0x8C08050B, // 0023 GETMET R2 R2 K11 + 0x5C100200, // 0024 MOVE R4 R1 + 0x7C080400, // 0025 CALL R2 2 + 0x000A1002, // 0026 ADD R2 K8 R2 + 0x80040400, // 0027 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: msg_received +********************************************************************/ +be_local_closure(Matter_Device_msg_received, /* name */ + be_nested_proto( + 9, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(msg_handler), + /* K1 */ be_nested_str_weak(msg_received), + }), + be_str_weak(msg_received), + &be_const_str_solidified, + ( &(const binstruction[ 7]) { /* code */ + 0x88100100, // 0000 GETMBR R4 R0 K0 + 0x8C100901, // 0001 GETMET R4 R4 K1 + 0x5C180200, // 0002 MOVE R6 R1 + 0x5C1C0400, // 0003 MOVE R7 R2 + 0x5C200600, // 0004 MOVE R8 R3 + 0x7C100800, // 0005 CALL R4 4 + 0x80040800, // 0006 RET 1 R4 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: mdns_announce_op_discovery_all_sessions +********************************************************************/ +be_local_closure(Matter_Device_mdns_announce_op_discovery_all_sessions, /* name */ + be_nested_proto( + 6, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(sessions), + /* K1 */ be_nested_str_weak(get_deviceid), + /* K2 */ be_nested_str_weak(get_fabric), + /* K3 */ be_nested_str_weak(mdns_announce_op_discovery), + /* K4 */ be_nested_str_weak(stop_iteration), + }), + be_str_weak(mdns_announce_op_discovery_all_sessions), + &be_const_str_solidified, + ( &(const binstruction[21]) { /* code */ + 0x60040010, // 0000 GETGBL R1 G16 + 0x88080100, // 0001 GETMBR R2 R0 K0 + 0x88080500, // 0002 GETMBR R2 R2 K0 + 0x7C040200, // 0003 CALL R1 1 + 0xA802000B, // 0004 EXBLK 0 #0011 + 0x5C080200, // 0005 MOVE R2 R1 + 0x7C080000, // 0006 CALL R2 0 + 0x8C0C0501, // 0007 GETMET R3 R2 K1 + 0x7C0C0200, // 0008 CALL R3 1 + 0x780E0005, // 0009 JMPF R3 #0010 + 0x8C0C0502, // 000A GETMET R3 R2 K2 + 0x7C0C0200, // 000B CALL R3 1 + 0x780E0002, // 000C JMPF R3 #0010 + 0x8C0C0103, // 000D GETMET R3 R0 K3 + 0x5C140400, // 000E MOVE R5 R2 + 0x7C0C0400, // 000F CALL R3 2 + 0x7001FFF3, // 0010 JMP #0005 + 0x58040004, // 0011 LDCONST R1 K4 + 0xAC040200, // 0012 CATCH R1 1 0 + 0xB0080000, // 0013 RAISE 2 R0 R0 + 0x80000000, // 0014 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: invoke_request +********************************************************************/ +be_local_closure(Matter_Device_invoke_request, /* name */ + be_nested_proto( + 11, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 7]) { /* constants */ + /* K0 */ be_const_int(0), + /* K1 */ be_nested_str_weak(plugins), + /* K2 */ be_nested_str_weak(invoke_request), + /* K3 */ be_nested_str_weak(status), + /* K4 */ be_nested_str_weak(matter), + /* K5 */ be_nested_str_weak(UNSUPPORTED_COMMAND), + /* K6 */ be_const_int(1), + }), + be_str_weak(invoke_request), + &be_const_str_solidified, + ( &(const binstruction[25]) { /* code */ + 0x58100000, // 0000 LDCONST R4 K0 + 0x6014000C, // 0001 GETGBL R5 G12 + 0x88180101, // 0002 GETMBR R6 R0 K1 + 0x7C140200, // 0003 CALL R5 1 + 0x14140805, // 0004 LT R5 R4 R5 + 0x78160011, // 0005 JMPF R5 #0018 + 0x88140101, // 0006 GETMBR R5 R0 K1 + 0x94140A04, // 0007 GETIDX R5 R5 R4 + 0x8C180B02, // 0008 GETMET R6 R5 K2 + 0x5C200200, // 0009 MOVE R8 R1 + 0x5C240400, // 000A MOVE R9 R2 + 0x5C280600, // 000B MOVE R10 R3 + 0x7C180800, // 000C CALL R6 4 + 0x4C1C0000, // 000D LDNIL R7 + 0x201C0C07, // 000E NE R7 R6 R7 + 0x741E0004, // 000F JMPT R7 #0015 + 0x881C0703, // 0010 GETMBR R7 R3 K3 + 0xB8220800, // 0011 GETNGBL R8 K4 + 0x88201105, // 0012 GETMBR R8 R8 K5 + 0x201C0E08, // 0013 NE R7 R7 R8 + 0x781E0000, // 0014 JMPF R7 #0016 + 0x80040C00, // 0015 RET 1 R6 + 0x00100906, // 0016 ADD R4 R4 K6 + 0x7001FFE8, // 0017 JMP #0001 + 0x80000000, // 0018 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: read_attribute +********************************************************************/ +be_local_closure(Matter_Device_read_attribute, /* name */ + be_nested_proto( + 13, /* nstack */ + 5, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_const_int(0), + /* K1 */ be_nested_str_weak(plugins), + /* K2 */ be_nested_str_weak(read_attribute), + /* K3 */ be_const_int(1), + }), + be_str_weak(read_attribute), + &be_const_str_solidified, + ( &(const binstruction[21]) { /* code */ + 0x58140000, // 0000 LDCONST R5 K0 + 0x6018000C, // 0001 GETGBL R6 G12 + 0x881C0101, // 0002 GETMBR R7 R0 K1 + 0x7C180200, // 0003 CALL R6 1 + 0x14180A06, // 0004 LT R6 R5 R6 + 0x781A000D, // 0005 JMPF R6 #0014 + 0x88180101, // 0006 GETMBR R6 R0 K1 + 0x94180C05, // 0007 GETIDX R6 R6 R5 + 0x8C1C0D02, // 0008 GETMET R7 R6 K2 + 0x5C240200, // 0009 MOVE R9 R1 + 0x5C280400, // 000A MOVE R10 R2 + 0x5C2C0600, // 000B MOVE R11 R3 + 0x5C300800, // 000C MOVE R12 R4 + 0x7C1C0A00, // 000D CALL R7 5 + 0x4C200000, // 000E LDNIL R8 + 0x20200E08, // 000F NE R8 R7 R8 + 0x78220000, // 0010 JMPF R8 #0012 + 0x80040E00, // 0011 RET 1 R7 + 0x00140B03, // 0012 ADD R5 R5 K3 + 0x7001FFEC, // 0013 JMP #0001 + 0x80000000, // 0014 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_Device +********************************************************************/ +be_local_class(Matter_Device, + 18, + NULL, + be_nested_map(48, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(read_attribute, 15), be_const_closure(Matter_Device_read_attribute_closure) }, + { be_const_key_weak(msg_send, -1), be_const_closure(Matter_Device_msg_send_closure) }, + { be_const_key_weak(start_operational_dicovery_deferred, 32), be_const_closure(Matter_Device_start_operational_dicovery_deferred_closure) }, + { be_const_key_weak(start_commissioning_complete_deferred, 30), be_const_closure(Matter_Device_start_commissioning_complete_deferred_closure) }, + { be_const_key_weak(invoke_request, -1), be_const_closure(Matter_Device_invoke_request_closure) }, + { be_const_key_weak(stop, -1), be_const_closure(Matter_Device_stop_closure) }, + { be_const_key_weak(udp_server, -1), be_const_var(1) }, + { be_const_key_weak(mdns_announce_op_discovery, -1), be_const_closure(Matter_Device_mdns_announce_op_discovery_closure) }, + { be_const_key_weak(hostname_eth, 38), be_const_var(8) }, + { be_const_key_weak(every_second, -1), be_const_closure(Matter_Device_every_second_closure) }, + { be_const_key_weak(start_commissioning_complete, -1), be_const_closure(Matter_Device_start_commissioning_complete_closure) }, + { be_const_key_weak(ui, 4), be_const_var(4) }, + { be_const_key_weak(PRODUCT_ID, -1), be_const_int(32768) }, + { be_const_key_weak(L, -1), be_const_var(17) }, + { be_const_key_weak(vendorid, -1), be_const_var(9) }, + { be_const_key_weak(mdns_announce_op_discovery_all_sessions, -1), be_const_closure(Matter_Device_mdns_announce_op_discovery_all_sessions_closure) }, + { be_const_key_weak(start_operational_dicovery, -1), be_const_closure(Matter_Device_start_operational_dicovery_closure) }, + { be_const_key_weak(productid, -1), be_const_var(10) }, + { be_const_key_weak(compute_manual_pairing_code, -1), be_const_closure(Matter_Device_compute_manual_pairing_code_closure) }, + { be_const_key_weak(start_udp, -1), be_const_closure(Matter_Device_start_udp_closure) }, + { be_const_key_weak(sessions, -1), be_const_var(3) }, + { be_const_key_weak(start_mdns_announce_hostnames, -1), be_const_closure(Matter_Device_start_mdns_announce_hostnames_closure) }, + { be_const_key_weak(finish_commissioning, 7), be_const_closure(Matter_Device_finish_commissioning_closure) }, + { be_const_key_weak(packet_ack, 10), be_const_closure(Matter_Device_packet_ack_closure) }, + { be_const_key_weak(discriminator, -1), be_const_var(11) }, + { be_const_key_weak(VENDOR_ID, -1), be_const_int(65521) }, + { be_const_key_weak(start_basic_commissioning, 41), be_const_closure(Matter_Device_start_basic_commissioning_closure) }, + { be_const_key_weak(plugins, 24), be_const_var(0) }, + { be_const_key_weak(compute_pbkdf, 20), be_const_closure(Matter_Device_compute_pbkdf_closure) }, + { be_const_key_weak(passcode, -1), be_const_var(12) }, + { be_const_key_weak(init, 47), be_const_closure(Matter_Device_init_closure) }, + { be_const_key_weak(PBKDF_ITERATIONS, -1), be_const_int(1000) }, + { be_const_key_weak(w0, 46), be_const_var(15) }, + { be_const_key_weak(salt, 36), be_const_var(14) }, + { be_const_key_weak(UDP_PORT, -1), be_const_int(5540) }, + { be_const_key_weak(_start_mdns_announce, -1), be_const_closure(Matter_Device__start_mdns_announce_closure) }, + { be_const_key_weak(msg_handler, -1), be_const_var(2) }, + { be_const_key_weak(w1, 35), be_const_var(16) }, + { be_const_key_weak(FILENAME, -1), be_nested_str_weak(_matter_device_X2Ejson) }, + { be_const_key_weak(compute_qrcode_content, -1), be_const_closure(Matter_Device_compute_qrcode_content_closure) }, + { be_const_key_weak(msg_received, -1), be_const_closure(Matter_Device_msg_received_closure) }, + { be_const_key_weak(commissioning_instance_eth, -1), be_const_var(6) }, + { be_const_key_weak(commissioning_instance_wifi, 0), be_const_var(5) }, + { be_const_key_weak(PASSCODE_DEFAULT, 13), be_const_int(20202021) }, + { be_const_key_weak(hostname_wifi, -1), be_const_var(7) }, + { be_const_key_weak(iterations, -1), be_const_var(13) }, + { be_const_key_weak(save_param, -1), be_const_closure(Matter_Device_save_param_closure) }, + { be_const_key_weak(load_param, -1), be_const_closure(Matter_Device_load_param_closure) }, + })), + be_str_weak(Matter_Device) +); +/*******************************************************************/ + +void be_load_Matter_Device_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Device); + be_setglobal(vm, "Matter_Device"); + be_pop(vm, 1); +} +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM.h new file mode 100644 index 000000000..2c89b8f4f --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM.h @@ -0,0 +1,1274 @@ +/* Solidification of Matter_IM.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_Response_container; + +/******************************************************************** +** Solidified class: Matter_Response_container +********************************************************************/ +be_local_class(Matter_Response_container, + 5, + NULL, + be_nested_map(5, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(command, -1), be_const_var(3) }, + { be_const_key_weak(attribute, -1), be_const_var(2) }, + { be_const_key_weak(cluster, -1), be_const_var(1) }, + { be_const_key_weak(endpoint, 0), be_const_var(0) }, + { be_const_key_weak(status, -1), be_const_var(4) }, + })), + be_str_weak(Matter_Response_container) +); +/*******************************************************************/ + +void be_load_Matter_Response_container_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Response_container); + be_setglobal(vm, "Matter_Response_container"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_IM; + +/******************************************************************** +** Solidified function: process_timed_request +********************************************************************/ +be_local_closure(Matter_IM_process_timed_request, /* name */ + be_nested_proto( + 15, /* nstack */ + 5, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[24]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(TimedRequestMessage), + /* K3 */ be_nested_str_weak(from_TLV), + /* K4 */ be_nested_str_weak(tasmota), + /* K5 */ be_nested_str_weak(log), + /* K6 */ be_nested_str_weak(MTR_X3A_X20received_X20TimedRequestMessage_X3D), + /* K7 */ be_const_int(3), + /* K8 */ be_nested_str_weak(format), + /* K9 */ be_nested_str_weak(MTR_X3A_X20_X3EReceived_IM_X20_X20_X20TimedRequest_X3D_X25i_X20from_X20_X5B_X25s_X5D_X3A_X25i), + /* K10 */ be_nested_str_weak(timeout), + /* K11 */ be_const_int(2), + /* K12 */ be_nested_str_weak(StatusResponseMessage), + /* K13 */ be_nested_str_weak(status), + /* K14 */ be_nested_str_weak(SUCCESS), + /* K15 */ be_nested_str_weak(build_response), + /* K16 */ be_const_int(1), + /* K17 */ be_nested_str_weak(encode), + /* K18 */ be_nested_str_weak(to_TLV), + /* K19 */ be_nested_str_weak(encrypt), + /* K20 */ be_nested_str_weak(responder), + /* K21 */ be_nested_str_weak(send_response), + /* K22 */ be_nested_str_weak(raw), + /* K23 */ be_nested_str_weak(message_counter), + }), + be_str_weak(process_timed_request), + &be_const_str_solidified, + ( &(const binstruction[52]) { /* code */ + 0xA4160000, // 0000 IMPORT R5 K0 + 0xB81A0200, // 0001 GETNGBL R6 K1 + 0x8C180D02, // 0002 GETMET R6 R6 K2 + 0x7C180200, // 0003 CALL R6 1 + 0x8C180D03, // 0004 GETMET R6 R6 K3 + 0x5C200400, // 0005 MOVE R8 R2 + 0x7C180400, // 0006 CALL R6 2 + 0xB81E0800, // 0007 GETNGBL R7 K4 + 0x8C1C0F05, // 0008 GETMET R7 R7 K5 + 0x60240008, // 0009 GETGBL R9 G8 + 0x5C280C00, // 000A MOVE R10 R6 + 0x7C240200, // 000B CALL R9 1 + 0x00260C09, // 000C ADD R9 K6 R9 + 0x58280007, // 000D LDCONST R10 K7 + 0x7C1C0600, // 000E CALL R7 3 + 0xB81E0800, // 000F GETNGBL R7 K4 + 0x8C1C0F05, // 0010 GETMET R7 R7 K5 + 0x8C240B08, // 0011 GETMET R9 R5 K8 + 0x582C0009, // 0012 LDCONST R11 K9 + 0x88300D0A, // 0013 GETMBR R12 R6 K10 + 0x5C340600, // 0014 MOVE R13 R3 + 0x5C380800, // 0015 MOVE R14 R4 + 0x7C240A00, // 0016 CALL R9 5 + 0x5828000B, // 0017 LDCONST R10 K11 + 0x7C1C0600, // 0018 CALL R7 3 + 0xB81E0200, // 0019 GETNGBL R7 K1 + 0x8C1C0F0C, // 001A GETMET R7 R7 K12 + 0x7C1C0200, // 001B CALL R7 1 + 0xB8220200, // 001C GETNGBL R8 K1 + 0x8820110E, // 001D GETMBR R8 R8 K14 + 0x901E1A08, // 001E SETMBR R7 K13 R8 + 0x8C20030F, // 001F GETMET R8 R1 K15 + 0x58280010, // 0020 LDCONST R10 K16 + 0x502C0200, // 0021 LDBOOL R11 1 0 + 0x7C200600, // 0022 CALL R8 3 + 0x8C241111, // 0023 GETMET R9 R8 K17 + 0x8C2C0F12, // 0024 GETMET R11 R7 K18 + 0x7C2C0200, // 0025 CALL R11 1 + 0x8C2C1711, // 0026 GETMET R11 R11 K17 + 0x7C2C0200, // 0027 CALL R11 1 + 0x7C240400, // 0028 CALL R9 2 + 0x8C241113, // 0029 GETMET R9 R8 K19 + 0x7C240200, // 002A CALL R9 1 + 0x88240114, // 002B GETMBR R9 R0 K20 + 0x8C241315, // 002C GETMET R9 R9 K21 + 0x882C1116, // 002D GETMBR R11 R8 K22 + 0x5C300600, // 002E MOVE R12 R3 + 0x5C340800, // 002F MOVE R13 R4 + 0x88381117, // 0030 GETMBR R14 R8 K23 + 0x7C240A00, // 0031 CALL R9 5 + 0x50240200, // 0032 LDBOOL R9 1 0 + 0x80041200, // 0033 RET 1 R9 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: process_status_response +********************************************************************/ +be_local_closure(Matter_IM_process_status_response, /* name */ + be_nested_proto( + 13, /* nstack */ + 5, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(findsubval), + /* K2 */ be_const_int(0), + /* K3 */ be_nested_str_weak(tasmota), + /* K4 */ be_nested_str_weak(log), + /* K5 */ be_nested_str_weak(format), + /* K6 */ be_nested_str_weak(MTR_X3A_X20Status_X20Response_X20_X3D_X200x_X2502X), + /* K7 */ be_const_int(3), + }), + be_str_weak(process_status_response), + &be_const_str_solidified, + ( &(const binstruction[15]) { /* code */ + 0xA4160000, // 0000 IMPORT R5 K0 + 0x8C180501, // 0001 GETMET R6 R2 K1 + 0x58200002, // 0002 LDCONST R8 K2 + 0x542600FE, // 0003 LDINT R9 255 + 0x7C180600, // 0004 CALL R6 3 + 0xB81E0600, // 0005 GETNGBL R7 K3 + 0x8C1C0F04, // 0006 GETMET R7 R7 K4 + 0x8C240B05, // 0007 GETMET R9 R5 K5 + 0x582C0006, // 0008 LDCONST R11 K6 + 0x5C300C00, // 0009 MOVE R12 R6 + 0x7C240600, // 000A CALL R9 3 + 0x58280007, // 000B LDCONST R10 K7 + 0x7C1C0600, // 000C CALL R7 3 + 0x501C0200, // 000D LDBOOL R7 1 0 + 0x80040E00, // 000E RET 1 R7 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_IM_init, /* name */ + be_nested_proto( + 2, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(responder), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x80000000, // 0001 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: every_second +********************************************************************/ +be_local_closure(Matter_IM_every_second, /* name */ + be_nested_proto( + 1, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + be_str_weak(every_second), + &be_const_str_solidified, + ( &(const binstruction[ 1]) { /* code */ + 0x80000000, // 0000 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: process_write_response +********************************************************************/ +be_local_closure(Matter_IM_process_write_response, /* name */ + be_nested_proto( + 11, /* nstack */ + 5, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(WriteResponseMessage), + /* K3 */ be_nested_str_weak(from_TLV), + /* K4 */ be_nested_str_weak(tasmota), + /* K5 */ be_nested_str_weak(log), + /* K6 */ be_nested_str_weak(MTR_X3A_X20received_X20WriteResponseMessage_X3D), + /* K7 */ be_const_int(3), + }), + be_str_weak(process_write_response), + &be_const_str_solidified, + ( &(const binstruction[17]) { /* code */ + 0xA4160000, // 0000 IMPORT R5 K0 + 0xB81A0200, // 0001 GETNGBL R6 K1 + 0x8C180D02, // 0002 GETMET R6 R6 K2 + 0x7C180200, // 0003 CALL R6 1 + 0x8C180D03, // 0004 GETMET R6 R6 K3 + 0x5C200400, // 0005 MOVE R8 R2 + 0x7C180400, // 0006 CALL R6 2 + 0xB81E0800, // 0007 GETNGBL R7 K4 + 0x8C1C0F05, // 0008 GETMET R7 R7 K5 + 0x60240008, // 0009 GETGBL R9 G8 + 0x5C280C00, // 000A MOVE R10 R6 + 0x7C240200, // 000B CALL R9 1 + 0x00260C09, // 000C ADD R9 K6 R9 + 0x58280007, // 000D LDCONST R10 K7 + 0x7C1C0600, // 000E CALL R7 3 + 0x501C0000, // 000F LDBOOL R7 0 0 + 0x80040E00, // 0010 RET 1 R7 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: process_incoming +********************************************************************/ +be_local_closure(Matter_IM_process_incoming, /* name */ + be_nested_proto( + 13, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[27]) { /* constants */ + /* K0 */ be_nested_str_weak(tasmota), + /* K1 */ be_nested_str_weak(log), + /* K2 */ be_nested_str_weak(MTR_X3A_X20received_X20IM_X20message_X20), + /* K3 */ be_nested_str_weak(matter), + /* K4 */ be_nested_str_weak(inspect), + /* K5 */ be_const_int(3), + /* K6 */ be_nested_str_weak(TLV), + /* K7 */ be_nested_str_weak(parse), + /* K8 */ be_nested_str_weak(raw), + /* K9 */ be_nested_str_weak(app_payload_idx), + /* K10 */ be_nested_str_weak(MTR_X3A_X20IM_X20TLV_X3A_X20), + /* K11 */ be_nested_str_weak(findsubval), + /* K12 */ be_nested_str_weak(MTR_X3A_X20InteractionModelRevision_X3D), + /* K13 */ be_nested_str_weak(nil), + /* K14 */ be_nested_str_weak(opcode), + /* K15 */ be_const_int(1), + /* K16 */ be_nested_str_weak(process_status_response), + /* K17 */ be_const_int(2), + /* K18 */ be_nested_str_weak(process_read_request), + /* K19 */ be_nested_str_weak(subscribe_request), + /* K20 */ be_nested_str_weak(subscribe_response), + /* K21 */ be_nested_str_weak(report_data), + /* K22 */ be_nested_str_weak(process_write_request), + /* K23 */ be_nested_str_weak(process_write_response), + /* K24 */ be_nested_str_weak(process_invoke_request), + /* K25 */ be_nested_str_weak(process_invoke_response), + /* K26 */ be_nested_str_weak(process_timed_request), + }), + be_str_weak(process_incoming), + &be_const_str_solidified, + ( &(const binstruction[148]) { /* code */ + 0xB8120000, // 0000 GETNGBL R4 K0 + 0x8C100901, // 0001 GETMET R4 R4 K1 + 0xB81A0600, // 0002 GETNGBL R6 K3 + 0x8C180D04, // 0003 GETMET R6 R6 K4 + 0x5C200200, // 0004 MOVE R8 R1 + 0x7C180400, // 0005 CALL R6 2 + 0x001A0406, // 0006 ADD R6 K2 R6 + 0x581C0005, // 0007 LDCONST R7 K5 + 0x7C100600, // 0008 CALL R4 3 + 0xB8120600, // 0009 GETNGBL R4 K3 + 0x88100906, // 000A GETMBR R4 R4 K6 + 0x8C100907, // 000B GETMET R4 R4 K7 + 0x88180308, // 000C GETMBR R6 R1 K8 + 0x881C0309, // 000D GETMBR R7 R1 K9 + 0x7C100600, // 000E CALL R4 3 + 0xB8160000, // 000F GETNGBL R5 K0 + 0x8C140B01, // 0010 GETMET R5 R5 K1 + 0x601C0008, // 0011 GETGBL R7 G8 + 0x5C200800, // 0012 MOVE R8 R4 + 0x7C1C0200, // 0013 CALL R7 1 + 0x001E1407, // 0014 ADD R7 K10 R7 + 0x58200005, // 0015 LDCONST R8 K5 + 0x7C140600, // 0016 CALL R5 3 + 0x8C14090B, // 0017 GETMET R5 R4 K11 + 0x541E00FE, // 0018 LDINT R7 255 + 0x7C140400, // 0019 CALL R5 2 + 0xB81A0000, // 001A GETNGBL R6 K0 + 0x8C180D01, // 001B GETMET R6 R6 K1 + 0x4C200000, // 001C LDNIL R8 + 0x20200A08, // 001D NE R8 R5 R8 + 0x78220003, // 001E JMPF R8 #0023 + 0x60200008, // 001F GETGBL R8 G8 + 0x5C240A00, // 0020 MOVE R9 R5 + 0x7C200200, // 0021 CALL R8 1 + 0x70020000, // 0022 JMP #0024 + 0x5820000D, // 0023 LDCONST R8 K13 + 0x00221808, // 0024 ADD R8 K12 R8 + 0x58240005, // 0025 LDCONST R9 K5 + 0x7C180600, // 0026 CALL R6 3 + 0x8818030E, // 0027 GETMBR R6 R1 K14 + 0x1C1C0D0F, // 0028 EQ R7 R6 K15 + 0x781E0007, // 0029 JMPF R7 #0032 + 0x8C1C0110, // 002A GETMET R7 R0 K16 + 0x5C240200, // 002B MOVE R9 R1 + 0x5C280800, // 002C MOVE R10 R4 + 0x5C2C0400, // 002D MOVE R11 R2 + 0x5C300600, // 002E MOVE R12 R3 + 0x7C1C0A00, // 002F CALL R7 5 + 0x80040E00, // 0030 RET 1 R7 + 0x7002005F, // 0031 JMP #0092 + 0x1C1C0D11, // 0032 EQ R7 R6 K17 + 0x781E0007, // 0033 JMPF R7 #003C + 0x8C1C0112, // 0034 GETMET R7 R0 K18 + 0x5C240200, // 0035 MOVE R9 R1 + 0x5C280800, // 0036 MOVE R10 R4 + 0x5C2C0400, // 0037 MOVE R11 R2 + 0x5C300600, // 0038 MOVE R12 R3 + 0x7C1C0A00, // 0039 CALL R7 5 + 0x80040E00, // 003A RET 1 R7 + 0x70020055, // 003B JMP #0092 + 0x1C1C0D05, // 003C EQ R7 R6 K5 + 0x781E0007, // 003D JMPF R7 #0046 + 0x8C1C0113, // 003E GETMET R7 R0 K19 + 0x5C240200, // 003F MOVE R9 R1 + 0x5C280800, // 0040 MOVE R10 R4 + 0x5C2C0400, // 0041 MOVE R11 R2 + 0x5C300600, // 0042 MOVE R12 R3 + 0x7C1C0A00, // 0043 CALL R7 5 + 0x80040E00, // 0044 RET 1 R7 + 0x7002004B, // 0045 JMP #0092 + 0x541E0003, // 0046 LDINT R7 4 + 0x1C1C0C07, // 0047 EQ R7 R6 R7 + 0x781E0007, // 0048 JMPF R7 #0051 + 0x8C1C0114, // 0049 GETMET R7 R0 K20 + 0x5C240200, // 004A MOVE R9 R1 + 0x5C280800, // 004B MOVE R10 R4 + 0x5C2C0400, // 004C MOVE R11 R2 + 0x5C300600, // 004D MOVE R12 R3 + 0x7C1C0A00, // 004E CALL R7 5 + 0x80040E00, // 004F RET 1 R7 + 0x70020040, // 0050 JMP #0092 + 0x541E0004, // 0051 LDINT R7 5 + 0x1C1C0C07, // 0052 EQ R7 R6 R7 + 0x781E0007, // 0053 JMPF R7 #005C + 0x8C1C0115, // 0054 GETMET R7 R0 K21 + 0x5C240200, // 0055 MOVE R9 R1 + 0x5C280800, // 0056 MOVE R10 R4 + 0x5C2C0400, // 0057 MOVE R11 R2 + 0x5C300600, // 0058 MOVE R12 R3 + 0x7C1C0A00, // 0059 CALL R7 5 + 0x80040E00, // 005A RET 1 R7 + 0x70020035, // 005B JMP #0092 + 0x541E0005, // 005C LDINT R7 6 + 0x1C1C0C07, // 005D EQ R7 R6 R7 + 0x781E0007, // 005E JMPF R7 #0067 + 0x8C1C0116, // 005F GETMET R7 R0 K22 + 0x5C240200, // 0060 MOVE R9 R1 + 0x5C280800, // 0061 MOVE R10 R4 + 0x5C2C0400, // 0062 MOVE R11 R2 + 0x5C300600, // 0063 MOVE R12 R3 + 0x7C1C0A00, // 0064 CALL R7 5 + 0x80040E00, // 0065 RET 1 R7 + 0x7002002A, // 0066 JMP #0092 + 0x541E0006, // 0067 LDINT R7 7 + 0x1C1C0C07, // 0068 EQ R7 R6 R7 + 0x781E0007, // 0069 JMPF R7 #0072 + 0x8C1C0117, // 006A GETMET R7 R0 K23 + 0x5C240200, // 006B MOVE R9 R1 + 0x5C280800, // 006C MOVE R10 R4 + 0x5C2C0400, // 006D MOVE R11 R2 + 0x5C300600, // 006E MOVE R12 R3 + 0x7C1C0A00, // 006F CALL R7 5 + 0x80040E00, // 0070 RET 1 R7 + 0x7002001F, // 0071 JMP #0092 + 0x541E0007, // 0072 LDINT R7 8 + 0x1C1C0C07, // 0073 EQ R7 R6 R7 + 0x781E0007, // 0074 JMPF R7 #007D + 0x8C1C0118, // 0075 GETMET R7 R0 K24 + 0x5C240200, // 0076 MOVE R9 R1 + 0x5C280800, // 0077 MOVE R10 R4 + 0x5C2C0400, // 0078 MOVE R11 R2 + 0x5C300600, // 0079 MOVE R12 R3 + 0x7C1C0A00, // 007A CALL R7 5 + 0x80040E00, // 007B RET 1 R7 + 0x70020014, // 007C JMP #0092 + 0x541E0008, // 007D LDINT R7 9 + 0x1C1C0C07, // 007E EQ R7 R6 R7 + 0x781E0007, // 007F JMPF R7 #0088 + 0x8C1C0119, // 0080 GETMET R7 R0 K25 + 0x5C240200, // 0081 MOVE R9 R1 + 0x5C280800, // 0082 MOVE R10 R4 + 0x5C2C0400, // 0083 MOVE R11 R2 + 0x5C300600, // 0084 MOVE R12 R3 + 0x7C1C0A00, // 0085 CALL R7 5 + 0x80040E00, // 0086 RET 1 R7 + 0x70020009, // 0087 JMP #0092 + 0x541E0009, // 0088 LDINT R7 10 + 0x1C1C0C07, // 0089 EQ R7 R6 R7 + 0x781E0006, // 008A JMPF R7 #0092 + 0x8C1C011A, // 008B GETMET R7 R0 K26 + 0x5C240200, // 008C MOVE R9 R1 + 0x5C280800, // 008D MOVE R10 R4 + 0x5C2C0400, // 008E MOVE R11 R2 + 0x5C300600, // 008F MOVE R12 R3 + 0x7C1C0A00, // 0090 CALL R7 5 + 0x80040E00, // 0091 RET 1 R7 + 0x501C0000, // 0092 LDBOOL R7 0 0 + 0x80040E00, // 0093 RET 1 R7 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: process_write_request +********************************************************************/ +be_local_closure(Matter_IM_process_write_request, /* name */ + be_nested_proto( + 11, /* nstack */ + 5, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(WriteRequestMessage), + /* K3 */ be_nested_str_weak(from_TLV), + /* K4 */ be_nested_str_weak(tasmota), + /* K5 */ be_nested_str_weak(log), + /* K6 */ be_nested_str_weak(MTR_X3A_X20received_X20WriteRequestMessage_X3D), + /* K7 */ be_const_int(3), + }), + be_str_weak(process_write_request), + &be_const_str_solidified, + ( &(const binstruction[17]) { /* code */ + 0xA4160000, // 0000 IMPORT R5 K0 + 0xB81A0200, // 0001 GETNGBL R6 K1 + 0x8C180D02, // 0002 GETMET R6 R6 K2 + 0x7C180200, // 0003 CALL R6 1 + 0x8C180D03, // 0004 GETMET R6 R6 K3 + 0x5C200400, // 0005 MOVE R8 R2 + 0x7C180400, // 0006 CALL R6 2 + 0xB81E0800, // 0007 GETNGBL R7 K4 + 0x8C1C0F05, // 0008 GETMET R7 R7 K5 + 0x60240008, // 0009 GETGBL R9 G8 + 0x5C280C00, // 000A MOVE R10 R6 + 0x7C240200, // 000B CALL R9 1 + 0x00260C09, // 000C ADD R9 K6 R9 + 0x58280007, // 000D LDCONST R10 K7 + 0x7C1C0600, // 000E CALL R7 3 + 0x501C0000, // 000F LDBOOL R7 0 0 + 0x80040E00, // 0010 RET 1 R7 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: process_invoke_request +********************************************************************/ +be_local_closure(Matter_IM_process_invoke_request, /* name */ + be_nested_proto( + 20, /* nstack */ + 5, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[50]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(log), + /* K3 */ be_nested_str_weak(MTR_X3A_X20IM_X3Ainvoke_request_X20processing_X20start), + /* K4 */ be_const_int(3), + /* K5 */ be_nested_str_weak(matter), + /* K6 */ be_nested_str_weak(Response_container), + /* K7 */ be_nested_str_weak(InvokeRequestMessage), + /* K8 */ be_nested_str_weak(from_TLV), + /* K9 */ be_nested_str_weak(invoke_requests), + /* K10 */ be_nested_str_weak(InvokeResponseMessage), + /* K11 */ be_nested_str_weak(suppress_response), + /* K12 */ be_nested_str_weak(invoke_responses), + /* K13 */ be_nested_str_weak(endpoint), + /* K14 */ be_nested_str_weak(command_path), + /* K15 */ be_nested_str_weak(cluster), + /* K16 */ be_nested_str_weak(command), + /* K17 */ be_nested_str_weak(status), + /* K18 */ be_nested_str_weak(UNSUPPORTED_COMMAND), + /* K19 */ be_nested_str_weak(get_command_name), + /* K20 */ be_nested_str_weak(format), + /* K21 */ be_nested_str_weak(0x_X2504X_X2F0x02X), + /* K22 */ be_nested_str_weak(MTR_X3A_X20_X3EReceived_cmd_X20_X20_X25s_X20from_X20_X5B_X25s_X5D_X3A_X25i), + /* K23 */ be_const_int(2), + /* K24 */ be_nested_str_weak(responder), + /* K25 */ be_nested_str_weak(device), + /* K26 */ be_nested_str_weak(invoke_request), + /* K27 */ be_nested_str_weak(command_fields), + /* K28 */ be_nested_str_weak(InvokeResponseIB), + /* K29 */ be_nested_str_weak(CommandDataIB), + /* K30 */ be_nested_str_weak(CommandPathIB), + /* K31 */ be_nested_str_weak(push), + /* K32 */ be_nested_str_weak(0x_X2504X_X2F0x_X2502X), + /* K33 */ be_nested_str_weak(MTR_X3A_X20_X3CReplied_cmd_X20_X20_X20_X25s), + /* K34 */ be_nested_str_weak(CommandStatusIB), + /* K35 */ be_nested_str_weak(StatusIB), + /* K36 */ be_nested_str_weak(stop_iteration), + /* K37 */ be_nested_str_weak(MTR_X3A_X20invoke_responses_X3D), + /* K38 */ be_const_int(0), + /* K39 */ be_nested_str_weak(MTR_X3A_X20InvokeResponse_X3D), + /* K40 */ be_nested_str_weak(MTR_X3A_X20InvokeResponseTLV_X3D), + /* K41 */ be_nested_str_weak(to_TLV), + /* K42 */ be_nested_str_weak(build_response), + /* K43 */ be_nested_str_weak(encode), + /* K44 */ be_nested_str_weak(encrypt), + /* K45 */ be_nested_str_weak(send_response), + /* K46 */ be_nested_str_weak(raw), + /* K47 */ be_nested_str_weak(message_counter), + /* K48 */ be_nested_str_weak(x_flag_r), + /* K49 */ be_nested_str_weak(build_standalone_ack), + }), + be_str_weak(process_invoke_request), + &be_const_str_solidified, + ( &(const binstruction[242]) { /* code */ + 0xA4160000, // 0000 IMPORT R5 K0 + 0xB81A0200, // 0001 GETNGBL R6 K1 + 0x8C180D02, // 0002 GETMET R6 R6 K2 + 0x58200003, // 0003 LDCONST R8 K3 + 0x58240004, // 0004 LDCONST R9 K4 + 0x7C180600, // 0005 CALL R6 3 + 0xB81A0A00, // 0006 GETNGBL R6 K5 + 0x8C180D06, // 0007 GETMET R6 R6 K6 + 0x7C180200, // 0008 CALL R6 1 + 0xB81E0A00, // 0009 GETNGBL R7 K5 + 0x8C1C0F07, // 000A GETMET R7 R7 K7 + 0x7C1C0200, // 000B CALL R7 1 + 0x8C1C0F08, // 000C GETMET R7 R7 K8 + 0x5C240400, // 000D MOVE R9 R2 + 0x7C1C0400, // 000E CALL R7 2 + 0x88200F09, // 000F GETMBR R8 R7 K9 + 0x4C240000, // 0010 LDNIL R9 + 0x20201009, // 0011 NE R8 R8 R9 + 0x782200DD, // 0012 JMPF R8 #00F1 + 0xB8220A00, // 0013 GETNGBL R8 K5 + 0x8C20110A, // 0014 GETMET R8 R8 K10 + 0x7C200200, // 0015 CALL R8 1 + 0x50240000, // 0016 LDBOOL R9 0 0 + 0x90221609, // 0017 SETMBR R8 K11 R9 + 0x60240012, // 0018 GETGBL R9 G18 + 0x7C240000, // 0019 CALL R9 0 + 0x90221809, // 001A SETMBR R8 K12 R9 + 0x60240010, // 001B GETGBL R9 G16 + 0x88280F09, // 001C GETMBR R10 R7 K9 + 0x7C240200, // 001D CALL R9 1 + 0xA802008D, // 001E EXBLK 0 #00AD + 0x5C281200, // 001F MOVE R10 R9 + 0x7C280000, // 0020 CALL R10 0 + 0x882C150E, // 0021 GETMBR R11 R10 K14 + 0x882C170D, // 0022 GETMBR R11 R11 K13 + 0x901A1A0B, // 0023 SETMBR R6 K13 R11 + 0x882C150E, // 0024 GETMBR R11 R10 K14 + 0x882C170F, // 0025 GETMBR R11 R11 K15 + 0x901A1E0B, // 0026 SETMBR R6 K15 R11 + 0x882C150E, // 0027 GETMBR R11 R10 K14 + 0x882C1710, // 0028 GETMBR R11 R11 K16 + 0x901A200B, // 0029 SETMBR R6 K16 R11 + 0xB82E0A00, // 002A GETNGBL R11 K5 + 0x882C1712, // 002B GETMBR R11 R11 K18 + 0x901A220B, // 002C SETMBR R6 K17 R11 + 0xB82E0A00, // 002D GETNGBL R11 K5 + 0x8C2C1713, // 002E GETMET R11 R11 K19 + 0x88340D0F, // 002F GETMBR R13 R6 K15 + 0x88380D10, // 0030 GETMBR R14 R6 K16 + 0x7C2C0600, // 0031 CALL R11 3 + 0x4C300000, // 0032 LDNIL R12 + 0x1C30160C, // 0033 EQ R12 R11 R12 + 0x78320005, // 0034 JMPF R12 #003B + 0x8C300B14, // 0035 GETMET R12 R5 K20 + 0x58380015, // 0036 LDCONST R14 K21 + 0x883C0D0F, // 0037 GETMBR R15 R6 K15 + 0x88400D10, // 0038 GETMBR R16 R6 K16 + 0x7C300800, // 0039 CALL R12 4 + 0x5C2C1800, // 003A MOVE R11 R12 + 0xB8320200, // 003B GETNGBL R12 K1 + 0x8C301902, // 003C GETMET R12 R12 K2 + 0x8C380B14, // 003D GETMET R14 R5 K20 + 0x58400016, // 003E LDCONST R16 K22 + 0x5C441600, // 003F MOVE R17 R11 + 0x5C480600, // 0040 MOVE R18 R3 + 0x5C4C0800, // 0041 MOVE R19 R4 + 0x7C380A00, // 0042 CALL R14 5 + 0x583C0017, // 0043 LDCONST R15 K23 + 0x7C300600, // 0044 CALL R12 3 + 0x88300118, // 0045 GETMBR R12 R0 K24 + 0x88301919, // 0046 GETMBR R12 R12 K25 + 0x8C30191A, // 0047 GETMET R12 R12 K26 + 0x5C380200, // 0048 MOVE R14 R1 + 0x883C151B, // 0049 GETMBR R15 R10 K27 + 0x5C400C00, // 004A MOVE R16 R6 + 0x7C300800, // 004B CALL R12 4 + 0xB8360A00, // 004C GETNGBL R13 K5 + 0x8C341B1C, // 004D GETMET R13 R13 K28 + 0x7C340200, // 004E CALL R13 1 + 0x4C380000, // 004F LDNIL R14 + 0x2038180E, // 0050 NE R14 R12 R14 + 0x783A0032, // 0051 JMPF R14 #0085 + 0xB83A0A00, // 0052 GETNGBL R14 K5 + 0x8C381D1D, // 0053 GETMET R14 R14 K29 + 0x7C380200, // 0054 CALL R14 1 + 0x9036200E, // 0055 SETMBR R13 K16 R14 + 0x88381B10, // 0056 GETMBR R14 R13 K16 + 0xB83E0A00, // 0057 GETNGBL R15 K5 + 0x8C3C1F1E, // 0058 GETMET R15 R15 K30 + 0x7C3C0200, // 0059 CALL R15 1 + 0x903A1C0F, // 005A SETMBR R14 K14 R15 + 0x88381B10, // 005B GETMBR R14 R13 K16 + 0x88381D0E, // 005C GETMBR R14 R14 K14 + 0x883C0D0D, // 005D GETMBR R15 R6 K13 + 0x903A1A0F, // 005E SETMBR R14 K13 R15 + 0x88381B10, // 005F GETMBR R14 R13 K16 + 0x88381D0E, // 0060 GETMBR R14 R14 K14 + 0x883C0D0F, // 0061 GETMBR R15 R6 K15 + 0x903A1E0F, // 0062 SETMBR R14 K15 R15 + 0x88381B10, // 0063 GETMBR R14 R13 K16 + 0x88381D0E, // 0064 GETMBR R14 R14 K14 + 0x883C0D10, // 0065 GETMBR R15 R6 K16 + 0x903A200F, // 0066 SETMBR R14 K16 R15 + 0x88381B10, // 0067 GETMBR R14 R13 K16 + 0x903A360C, // 0068 SETMBR R14 K27 R12 + 0x8838110C, // 0069 GETMBR R14 R8 K12 + 0x8C381D1F, // 006A GETMET R14 R14 K31 + 0x5C401A00, // 006B MOVE R16 R13 + 0x7C380400, // 006C CALL R14 2 + 0xB83A0A00, // 006D GETNGBL R14 K5 + 0x8C381D13, // 006E GETMET R14 R14 K19 + 0x88400D0F, // 006F GETMBR R16 R6 K15 + 0x88440D10, // 0070 GETMBR R17 R6 K16 + 0x7C380600, // 0071 CALL R14 3 + 0x5C2C1C00, // 0072 MOVE R11 R14 + 0x4C380000, // 0073 LDNIL R14 + 0x1C38160E, // 0074 EQ R14 R11 R14 + 0x783A0005, // 0075 JMPF R14 #007C + 0x8C380B14, // 0076 GETMET R14 R5 K20 + 0x58400020, // 0077 LDCONST R16 K32 + 0x88440D0F, // 0078 GETMBR R17 R6 K15 + 0x88480D10, // 0079 GETMBR R18 R6 K16 + 0x7C380800, // 007A CALL R14 4 + 0x5C2C1C00, // 007B MOVE R11 R14 + 0xB83A0200, // 007C GETNGBL R14 K1 + 0x8C381D02, // 007D GETMET R14 R14 K2 + 0x8C400B14, // 007E GETMET R16 R5 K20 + 0x58480021, // 007F LDCONST R18 K33 + 0x5C4C1600, // 0080 MOVE R19 R11 + 0x7C400600, // 0081 CALL R16 3 + 0x58440017, // 0082 LDCONST R17 K23 + 0x7C380600, // 0083 CALL R14 3 + 0x70020026, // 0084 JMP #00AC + 0x88380D11, // 0085 GETMBR R14 R6 K17 + 0x4C3C0000, // 0086 LDNIL R15 + 0x20381C0F, // 0087 NE R14 R14 R15 + 0x783A0022, // 0088 JMPF R14 #00AC + 0xB83A0A00, // 0089 GETNGBL R14 K5 + 0x8C381D22, // 008A GETMET R14 R14 K34 + 0x7C380200, // 008B CALL R14 1 + 0x9036220E, // 008C SETMBR R13 K17 R14 + 0x88381B11, // 008D GETMBR R14 R13 K17 + 0xB83E0A00, // 008E GETNGBL R15 K5 + 0x8C3C1F1E, // 008F GETMET R15 R15 K30 + 0x7C3C0200, // 0090 CALL R15 1 + 0x903A1C0F, // 0091 SETMBR R14 K14 R15 + 0x88381B11, // 0092 GETMBR R14 R13 K17 + 0x88381D0E, // 0093 GETMBR R14 R14 K14 + 0x883C0D0D, // 0094 GETMBR R15 R6 K13 + 0x903A1A0F, // 0095 SETMBR R14 K13 R15 + 0x88381B11, // 0096 GETMBR R14 R13 K17 + 0x88381D0E, // 0097 GETMBR R14 R14 K14 + 0x883C0D0F, // 0098 GETMBR R15 R6 K15 + 0x903A1E0F, // 0099 SETMBR R14 K15 R15 + 0x88381B11, // 009A GETMBR R14 R13 K17 + 0x88381D0E, // 009B GETMBR R14 R14 K14 + 0x883C0D10, // 009C GETMBR R15 R6 K16 + 0x903A200F, // 009D SETMBR R14 K16 R15 + 0x88381B11, // 009E GETMBR R14 R13 K17 + 0xB83E0A00, // 009F GETNGBL R15 K5 + 0x8C3C1F23, // 00A0 GETMET R15 R15 K35 + 0x7C3C0200, // 00A1 CALL R15 1 + 0x903A220F, // 00A2 SETMBR R14 K17 R15 + 0x88381B11, // 00A3 GETMBR R14 R13 K17 + 0x88381D11, // 00A4 GETMBR R14 R14 K17 + 0x883C0D11, // 00A5 GETMBR R15 R6 K17 + 0x903A220F, // 00A6 SETMBR R14 K17 R15 + 0x8838110C, // 00A7 GETMBR R14 R8 K12 + 0x8C381D1F, // 00A8 GETMET R14 R14 K31 + 0x5C401A00, // 00A9 MOVE R16 R13 + 0x7C380400, // 00AA CALL R14 2 + 0x7001FFFF, // 00AB JMP #00AC + 0x7001FF71, // 00AC JMP #001F + 0x58240024, // 00AD LDCONST R9 K36 + 0xAC240200, // 00AE CATCH R9 1 0 + 0xB0080000, // 00AF RAISE 2 R0 R0 + 0xB8260200, // 00B0 GETNGBL R9 K1 + 0x8C241302, // 00B1 GETMET R9 R9 K2 + 0x602C0008, // 00B2 GETGBL R11 G8 + 0x8830110C, // 00B3 GETMBR R12 R8 K12 + 0x7C2C0200, // 00B4 CALL R11 1 + 0x002E4A0B, // 00B5 ADD R11 K37 R11 + 0x58300004, // 00B6 LDCONST R12 K4 + 0x7C240600, // 00B7 CALL R9 3 + 0x6024000C, // 00B8 GETGBL R9 G12 + 0x8828110C, // 00B9 GETMBR R10 R8 K12 + 0x7C240200, // 00BA CALL R9 1 + 0x24241326, // 00BB GT R9 R9 K38 + 0x78260024, // 00BC JMPF R9 #00E2 + 0xB8260200, // 00BD GETNGBL R9 K1 + 0x8C241302, // 00BE GETMET R9 R9 K2 + 0x602C0008, // 00BF GETGBL R11 G8 + 0x5C301000, // 00C0 MOVE R12 R8 + 0x7C2C0200, // 00C1 CALL R11 1 + 0x002E4E0B, // 00C2 ADD R11 K39 R11 + 0x58300004, // 00C3 LDCONST R12 K4 + 0x7C240600, // 00C4 CALL R9 3 + 0xB8260200, // 00C5 GETNGBL R9 K1 + 0x8C241302, // 00C6 GETMET R9 R9 K2 + 0x602C0008, // 00C7 GETGBL R11 G8 + 0x8C301129, // 00C8 GETMET R12 R8 K41 + 0x7C300200, // 00C9 CALL R12 1 + 0x7C2C0200, // 00CA CALL R11 1 + 0x002E500B, // 00CB ADD R11 K40 R11 + 0x58300004, // 00CC LDCONST R12 K4 + 0x7C240600, // 00CD CALL R9 3 + 0x8C24032A, // 00CE GETMET R9 R1 K42 + 0x542E0008, // 00CF LDINT R11 9 + 0x50300200, // 00D0 LDBOOL R12 1 0 + 0x7C240600, // 00D1 CALL R9 3 + 0x8C28132B, // 00D2 GETMET R10 R9 K43 + 0x8C301129, // 00D3 GETMET R12 R8 K41 + 0x7C300200, // 00D4 CALL R12 1 + 0x8C30192B, // 00D5 GETMET R12 R12 K43 + 0x7C300200, // 00D6 CALL R12 1 + 0x7C280400, // 00D7 CALL R10 2 + 0x8C28132C, // 00D8 GETMET R10 R9 K44 + 0x7C280200, // 00D9 CALL R10 1 + 0x88280118, // 00DA GETMBR R10 R0 K24 + 0x8C28152D, // 00DB GETMET R10 R10 K45 + 0x8830132E, // 00DC GETMBR R12 R9 K46 + 0x5C340600, // 00DD MOVE R13 R3 + 0x5C380800, // 00DE MOVE R14 R4 + 0x883C132F, // 00DF GETMBR R15 R9 K47 + 0x7C280A00, // 00E0 CALL R10 5 + 0x7002000E, // 00E1 JMP #00F1 + 0x88240330, // 00E2 GETMBR R9 R1 K48 + 0x7826000C, // 00E3 JMPF R9 #00F1 + 0x8C240331, // 00E4 GETMET R9 R1 K49 + 0x7C240200, // 00E5 CALL R9 1 + 0x8C28132B, // 00E6 GETMET R10 R9 K43 + 0x7C280200, // 00E7 CALL R10 1 + 0x8C28132C, // 00E8 GETMET R10 R9 K44 + 0x7C280200, // 00E9 CALL R10 1 + 0x88280118, // 00EA GETMBR R10 R0 K24 + 0x8C28152D, // 00EB GETMET R10 R10 K45 + 0x8830132E, // 00EC GETMBR R12 R9 K46 + 0x5C340600, // 00ED MOVE R13 R3 + 0x5C380800, // 00EE MOVE R14 R4 + 0x883C132F, // 00EF GETMBR R15 R9 K47 + 0x7C280A00, // 00F0 CALL R10 5 + 0x80000000, // 00F1 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: subscribe_response +********************************************************************/ +be_local_closure(Matter_IM_subscribe_response, /* name */ + be_nested_proto( + 11, /* nstack */ + 5, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(SubscribeResponseMessage), + /* K3 */ be_nested_str_weak(from_TLV), + /* K4 */ be_nested_str_weak(tasmota), + /* K5 */ be_nested_str_weak(log), + /* K6 */ be_nested_str_weak(MTR_X3A_X20received_X20SubscribeResponsetMessage_X3D), + /* K7 */ be_const_int(3), + }), + be_str_weak(subscribe_response), + &be_const_str_solidified, + ( &(const binstruction[17]) { /* code */ + 0xA4160000, // 0000 IMPORT R5 K0 + 0xB81A0200, // 0001 GETNGBL R6 K1 + 0x8C180D02, // 0002 GETMET R6 R6 K2 + 0x7C180200, // 0003 CALL R6 1 + 0x8C180D03, // 0004 GETMET R6 R6 K3 + 0x5C200400, // 0005 MOVE R8 R2 + 0x7C180400, // 0006 CALL R6 2 + 0xB81E0800, // 0007 GETNGBL R7 K4 + 0x8C1C0F05, // 0008 GETMET R7 R7 K5 + 0x60240008, // 0009 GETGBL R9 G8 + 0x5C280C00, // 000A MOVE R10 R6 + 0x7C240200, // 000B CALL R9 1 + 0x00260C09, // 000C ADD R9 K6 R9 + 0x58280007, // 000D LDCONST R10 K7 + 0x7C1C0600, // 000E CALL R7 3 + 0x501C0000, // 000F LDBOOL R7 0 0 + 0x80040E00, // 0010 RET 1 R7 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: subscribe_request +********************************************************************/ +be_local_closure(Matter_IM_subscribe_request, /* name */ + be_nested_proto( + 11, /* nstack */ + 5, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(SubscribeRequestMessage), + /* K3 */ be_nested_str_weak(from_TLV), + /* K4 */ be_nested_str_weak(tasmota), + /* K5 */ be_nested_str_weak(log), + /* K6 */ be_nested_str_weak(MTR_X3A_X20received_X20SubscribeRequestMessage_X3D), + /* K7 */ be_const_int(3), + }), + be_str_weak(subscribe_request), + &be_const_str_solidified, + ( &(const binstruction[17]) { /* code */ + 0xA4160000, // 0000 IMPORT R5 K0 + 0xB81A0200, // 0001 GETNGBL R6 K1 + 0x8C180D02, // 0002 GETMET R6 R6 K2 + 0x7C180200, // 0003 CALL R6 1 + 0x8C180D03, // 0004 GETMET R6 R6 K3 + 0x5C200400, // 0005 MOVE R8 R2 + 0x7C180400, // 0006 CALL R6 2 + 0xB81E0800, // 0007 GETNGBL R7 K4 + 0x8C1C0F05, // 0008 GETMET R7 R7 K5 + 0x60240008, // 0009 GETGBL R9 G8 + 0x5C280C00, // 000A MOVE R10 R6 + 0x7C240200, // 000B CALL R9 1 + 0x00260C09, // 000C ADD R9 K6 R9 + 0x58280007, // 000D LDCONST R10 K7 + 0x7C1C0600, // 000E CALL R7 3 + 0x501C0000, // 000F LDBOOL R7 0 0 + 0x80040E00, // 0010 RET 1 R7 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: process_read_request +********************************************************************/ +be_local_closure(Matter_IM_process_read_request, /* name */ + be_nested_proto( + 16, /* nstack */ + 5, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[43]) { /* constants */ + /* K0 */ be_nested_str_weak(tasmota), + /* K1 */ be_nested_str_weak(log), + /* K2 */ be_nested_str_weak(MTR_X3A_X20IM_X3Aread_request_X20processing_X20start), + /* K3 */ be_const_int(3), + /* K4 */ be_nested_str_weak(matter), + /* K5 */ be_nested_str_weak(ReadRequestMessage), + /* K6 */ be_nested_str_weak(from_TLV), + /* K7 */ be_nested_str_weak(attributes_requests), + /* K8 */ be_nested_str_weak(ReportDataMessage), + /* K9 */ be_nested_str_weak(suppress_response), + /* K10 */ be_nested_str_weak(attribute_reports), + /* K11 */ be_nested_str_weak(get_attribute_name), + /* K12 */ be_nested_str_weak(cluster), + /* K13 */ be_nested_str_weak(attribute), + /* K14 */ be_nested_str_weak(MTR_X3A_X20Read_X20Attribute_X20), + /* K15 */ be_nested_str_weak(_X20_X28), + /* K16 */ be_nested_str_weak(_X29), + /* K17 */ be_nested_str_weak(), + /* K18 */ be_const_int(2), + /* K19 */ be_nested_str_weak(responder), + /* K20 */ be_nested_str_weak(device), + /* K21 */ be_nested_str_weak(read_attribute), + /* K22 */ be_nested_str_weak(endpoint), + /* K23 */ be_nested_str_weak(AttributeReportIB), + /* K24 */ be_nested_str_weak(attribute_data), + /* K25 */ be_nested_str_weak(AttributeDataIB), + /* K26 */ be_nested_str_weak(data_version), + /* K27 */ be_const_int(1), + /* K28 */ be_nested_str_weak(path), + /* K29 */ be_nested_str_weak(AttributePathIB), + /* K30 */ be_const_int(0), + /* K31 */ be_nested_str_weak(data), + /* K32 */ be_nested_str_weak(push), + /* K33 */ be_nested_str_weak(stop_iteration), + /* K34 */ be_nested_str_weak(MTR_X3A_X20ReportDataMessage_X3D), + /* K35 */ be_nested_str_weak(MTR_X3A_X20ReportDataMessageTLV_X3D), + /* K36 */ be_nested_str_weak(to_TLV), + /* K37 */ be_nested_str_weak(build_response), + /* K38 */ be_nested_str_weak(encode), + /* K39 */ be_nested_str_weak(encrypt), + /* K40 */ be_nested_str_weak(send_response), + /* K41 */ be_nested_str_weak(raw), + /* K42 */ be_nested_str_weak(message_counter), + }), + be_str_weak(process_read_request), + &be_const_str_solidified, + ( &(const binstruction[132]) { /* code */ + 0xB8160000, // 0000 GETNGBL R5 K0 + 0x8C140B01, // 0001 GETMET R5 R5 K1 + 0x581C0002, // 0002 LDCONST R7 K2 + 0x58200003, // 0003 LDCONST R8 K3 + 0x7C140600, // 0004 CALL R5 3 + 0xB8160800, // 0005 GETNGBL R5 K4 + 0x8C140B05, // 0006 GETMET R5 R5 K5 + 0x7C140200, // 0007 CALL R5 1 + 0x8C140B06, // 0008 GETMET R5 R5 K6 + 0x5C1C0400, // 0009 MOVE R7 R2 + 0x7C140400, // 000A CALL R5 2 + 0x88180B07, // 000B GETMBR R6 R5 K7 + 0x4C1C0000, // 000C LDNIL R7 + 0x20180C07, // 000D NE R6 R6 R7 + 0x781A0072, // 000E JMPF R6 #0082 + 0xB81A0800, // 000F GETNGBL R6 K4 + 0x8C180D08, // 0010 GETMET R6 R6 K8 + 0x7C180200, // 0011 CALL R6 1 + 0x501C0200, // 0012 LDBOOL R7 1 0 + 0x901A1207, // 0013 SETMBR R6 K9 R7 + 0x601C0012, // 0014 GETGBL R7 G18 + 0x7C1C0000, // 0015 CALL R7 0 + 0x901A1407, // 0016 SETMBR R6 K10 R7 + 0x601C0010, // 0017 GETGBL R7 G16 + 0x88200B07, // 0018 GETMBR R8 R5 K7 + 0x7C1C0200, // 0019 CALL R7 1 + 0xA802003F, // 001A EXBLK 0 #005B + 0x5C200E00, // 001B MOVE R8 R7 + 0x7C200000, // 001C CALL R8 0 + 0xB8260800, // 001D GETNGBL R9 K4 + 0x8C24130B, // 001E GETMET R9 R9 K11 + 0x882C110C, // 001F GETMBR R11 R8 K12 + 0x8830110D, // 0020 GETMBR R12 R8 K13 + 0x7C240600, // 0021 CALL R9 3 + 0xB82A0000, // 0022 GETNGBL R10 K0 + 0x8C281501, // 0023 GETMET R10 R10 K1 + 0x60300008, // 0024 GETGBL R12 G8 + 0x5C341000, // 0025 MOVE R13 R8 + 0x7C300200, // 0026 CALL R12 1 + 0x00321C0C, // 0027 ADD R12 K14 R12 + 0x78260002, // 0028 JMPF R9 #002C + 0x00361E09, // 0029 ADD R13 K15 R9 + 0x00341B10, // 002A ADD R13 R13 K16 + 0x70020000, // 002B JMP #002D + 0x58340011, // 002C LDCONST R13 K17 + 0x0030180D, // 002D ADD R12 R12 R13 + 0x58340012, // 002E LDCONST R13 K18 + 0x7C280600, // 002F CALL R10 3 + 0x88280113, // 0030 GETMBR R10 R0 K19 + 0x88281514, // 0031 GETMBR R10 R10 K20 + 0x8C281515, // 0032 GETMET R10 R10 K21 + 0x5C300200, // 0033 MOVE R12 R1 + 0x88341116, // 0034 GETMBR R13 R8 K22 + 0x8838110C, // 0035 GETMBR R14 R8 K12 + 0x883C110D, // 0036 GETMBR R15 R8 K13 + 0x7C280A00, // 0037 CALL R10 5 + 0x4C2C0000, // 0038 LDNIL R11 + 0x202C140B, // 0039 NE R11 R10 R11 + 0x782E001E, // 003A JMPF R11 #005A + 0xB82E0800, // 003B GETNGBL R11 K4 + 0x8C2C1717, // 003C GETMET R11 R11 K23 + 0x7C2C0200, // 003D CALL R11 1 + 0xB8320800, // 003E GETNGBL R12 K4 + 0x8C301919, // 003F GETMET R12 R12 K25 + 0x7C300200, // 0040 CALL R12 1 + 0x902E300C, // 0041 SETMBR R11 K24 R12 + 0x88301718, // 0042 GETMBR R12 R11 K24 + 0x9032351B, // 0043 SETMBR R12 K26 K27 + 0x88301718, // 0044 GETMBR R12 R11 K24 + 0xB8360800, // 0045 GETNGBL R13 K4 + 0x8C341B1D, // 0046 GETMET R13 R13 K29 + 0x7C340200, // 0047 CALL R13 1 + 0x9032380D, // 0048 SETMBR R12 K28 R13 + 0x88301718, // 0049 GETMBR R12 R11 K24 + 0x8830191C, // 004A GETMBR R12 R12 K28 + 0x90322D1E, // 004B SETMBR R12 K22 K30 + 0x88301718, // 004C GETMBR R12 R11 K24 + 0x8830191C, // 004D GETMBR R12 R12 K28 + 0x8834110C, // 004E GETMBR R13 R8 K12 + 0x9032180D, // 004F SETMBR R12 K12 R13 + 0x88301718, // 0050 GETMBR R12 R11 K24 + 0x8830191C, // 0051 GETMBR R12 R12 K28 + 0x8834110D, // 0052 GETMBR R13 R8 K13 + 0x90321A0D, // 0053 SETMBR R12 K13 R13 + 0x88301718, // 0054 GETMBR R12 R11 K24 + 0x90323E0A, // 0055 SETMBR R12 K31 R10 + 0x88300D0A, // 0056 GETMBR R12 R6 K10 + 0x8C301920, // 0057 GETMET R12 R12 K32 + 0x5C381600, // 0058 MOVE R14 R11 + 0x7C300400, // 0059 CALL R12 2 + 0x7001FFBF, // 005A JMP #001B + 0x581C0021, // 005B LDCONST R7 K33 + 0xAC1C0200, // 005C CATCH R7 1 0 + 0xB0080000, // 005D RAISE 2 R0 R0 + 0xB81E0000, // 005E GETNGBL R7 K0 + 0x8C1C0F01, // 005F GETMET R7 R7 K1 + 0x60240008, // 0060 GETGBL R9 G8 + 0x5C280C00, // 0061 MOVE R10 R6 + 0x7C240200, // 0062 CALL R9 1 + 0x00264409, // 0063 ADD R9 K34 R9 + 0x58280003, // 0064 LDCONST R10 K3 + 0x7C1C0600, // 0065 CALL R7 3 + 0xB81E0000, // 0066 GETNGBL R7 K0 + 0x8C1C0F01, // 0067 GETMET R7 R7 K1 + 0x60240008, // 0068 GETGBL R9 G8 + 0x8C280D24, // 0069 GETMET R10 R6 K36 + 0x7C280200, // 006A CALL R10 1 + 0x7C240200, // 006B CALL R9 1 + 0x00264609, // 006C ADD R9 K35 R9 + 0x58280003, // 006D LDCONST R10 K3 + 0x7C1C0600, // 006E CALL R7 3 + 0x8C1C0325, // 006F GETMET R7 R1 K37 + 0x54260004, // 0070 LDINT R9 5 + 0x50280200, // 0071 LDBOOL R10 1 0 + 0x7C1C0600, // 0072 CALL R7 3 + 0x8C200F26, // 0073 GETMET R8 R7 K38 + 0x8C280D24, // 0074 GETMET R10 R6 K36 + 0x7C280200, // 0075 CALL R10 1 + 0x8C281526, // 0076 GETMET R10 R10 K38 + 0x7C280200, // 0077 CALL R10 1 + 0x7C200400, // 0078 CALL R8 2 + 0x8C200F27, // 0079 GETMET R8 R7 K39 + 0x7C200200, // 007A CALL R8 1 + 0x88200113, // 007B GETMBR R8 R0 K19 + 0x8C201128, // 007C GETMET R8 R8 K40 + 0x88280F29, // 007D GETMBR R10 R7 K41 + 0x5C2C0600, // 007E MOVE R11 R3 + 0x5C300800, // 007F MOVE R12 R4 + 0x88340F2A, // 0080 GETMBR R13 R7 K42 + 0x7C200A00, // 0081 CALL R8 5 + 0x50180200, // 0082 LDBOOL R6 1 0 + 0x80040C00, // 0083 RET 1 R6 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: report_data +********************************************************************/ +be_local_closure(Matter_IM_report_data, /* name */ + be_nested_proto( + 11, /* nstack */ + 5, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(ReportDataMessage), + /* K3 */ be_nested_str_weak(from_TLV), + /* K4 */ be_nested_str_weak(tasmota), + /* K5 */ be_nested_str_weak(log), + /* K6 */ be_nested_str_weak(MTR_X3A_X20received_X20ReportDataMessage_X3D), + /* K7 */ be_const_int(3), + }), + be_str_weak(report_data), + &be_const_str_solidified, + ( &(const binstruction[17]) { /* code */ + 0xA4160000, // 0000 IMPORT R5 K0 + 0xB81A0200, // 0001 GETNGBL R6 K1 + 0x8C180D02, // 0002 GETMET R6 R6 K2 + 0x7C180200, // 0003 CALL R6 1 + 0x8C180D03, // 0004 GETMET R6 R6 K3 + 0x5C200400, // 0005 MOVE R8 R2 + 0x7C180400, // 0006 CALL R6 2 + 0xB81E0800, // 0007 GETNGBL R7 K4 + 0x8C1C0F05, // 0008 GETMET R7 R7 K5 + 0x60240008, // 0009 GETGBL R9 G8 + 0x5C280C00, // 000A MOVE R10 R6 + 0x7C240200, // 000B CALL R9 1 + 0x00260C09, // 000C ADD R9 K6 R9 + 0x58280007, // 000D LDCONST R10 K7 + 0x7C1C0600, // 000E CALL R7 3 + 0x501C0000, // 000F LDBOOL R7 0 0 + 0x80040E00, // 0010 RET 1 R7 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: process_invoke_response +********************************************************************/ +be_local_closure(Matter_IM_process_invoke_response, /* name */ + be_nested_proto( + 11, /* nstack */ + 5, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(InvokeResponseMessage), + /* K3 */ be_nested_str_weak(from_TLV), + /* K4 */ be_nested_str_weak(tasmota), + /* K5 */ be_nested_str_weak(log), + /* K6 */ be_nested_str_weak(MTR_X3A_X20received_X20InvokeResponseMessage_X3D), + /* K7 */ be_const_int(3), + }), + be_str_weak(process_invoke_response), + &be_const_str_solidified, + ( &(const binstruction[17]) { /* code */ + 0xA4160000, // 0000 IMPORT R5 K0 + 0xB81A0200, // 0001 GETNGBL R6 K1 + 0x8C180D02, // 0002 GETMET R6 R6 K2 + 0x7C180200, // 0003 CALL R6 1 + 0x8C180D03, // 0004 GETMET R6 R6 K3 + 0x5C200400, // 0005 MOVE R8 R2 + 0x7C180400, // 0006 CALL R6 2 + 0xB81E0800, // 0007 GETNGBL R7 K4 + 0x8C1C0F05, // 0008 GETMET R7 R7 K5 + 0x60240008, // 0009 GETGBL R9 G8 + 0x5C280C00, // 000A MOVE R10 R6 + 0x7C240200, // 000B CALL R9 1 + 0x00260C09, // 000C ADD R9 K6 R9 + 0x58280007, // 000D LDCONST R10 K7 + 0x7C1C0600, // 000E CALL R7 3 + 0x501C0000, // 000F LDBOOL R7 0 0 + 0x80040E00, // 0010 RET 1 R7 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_IM +********************************************************************/ +be_local_class(Matter_IM, + 1, + NULL, + be_nested_map(14, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(process_timed_request, -1), be_const_closure(Matter_IM_process_timed_request_closure) }, + { be_const_key_weak(process_status_response, -1), be_const_closure(Matter_IM_process_status_response_closure) }, + { be_const_key_weak(process_incoming, -1), be_const_closure(Matter_IM_process_incoming_closure) }, + { be_const_key_weak(every_second, -1), be_const_closure(Matter_IM_every_second_closure) }, + { be_const_key_weak(process_write_response, -1), be_const_closure(Matter_IM_process_write_response_closure) }, + { be_const_key_weak(init, 10), be_const_closure(Matter_IM_init_closure) }, + { be_const_key_weak(process_write_request, -1), be_const_closure(Matter_IM_process_write_request_closure) }, + { be_const_key_weak(process_invoke_request, 2), be_const_closure(Matter_IM_process_invoke_request_closure) }, + { be_const_key_weak(process_read_request, -1), be_const_closure(Matter_IM_process_read_request_closure) }, + { be_const_key_weak(subscribe_response, -1), be_const_closure(Matter_IM_subscribe_response_closure) }, + { be_const_key_weak(subscribe_request, 7), be_const_closure(Matter_IM_subscribe_request_closure) }, + { be_const_key_weak(responder, 8), be_const_var(0) }, + { be_const_key_weak(report_data, -1), be_const_closure(Matter_IM_report_data_closure) }, + { be_const_key_weak(process_invoke_response, -1), be_const_closure(Matter_IM_process_invoke_response_closure) }, + })), + be_str_weak(Matter_IM) +); +/*******************************************************************/ + +void be_load_Matter_IM_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_IM); + be_setglobal(vm, "Matter_IM"); + be_pop(vm, 1); +} +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM_Data.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM_Data.h new file mode 100644 index 000000000..b0fe641e7 --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM_Data.h @@ -0,0 +1,4020 @@ +/* Solidification of Matter_IM_Data.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_IM_base; + +/******************************************************************** +** Solidified function: to_TLV_array +********************************************************************/ +be_local_closure(Matter_IM_base_to_TLV_array, /* name */ + be_nested_proto( + 11, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(add_array), + /* K1 */ be_nested_str_weak(add_obj), + /* K2 */ be_nested_str_weak(stop_iteration), + }), + be_str_weak(to_TLV_array), + &be_const_str_solidified, + ( &(const binstruction[23]) { /* code */ + 0x4C100000, // 0000 LDNIL R4 + 0x1C100604, // 0001 EQ R4 R3 R4 + 0x78120001, // 0002 JMPF R4 #0005 + 0x4C100000, // 0003 LDNIL R4 + 0x80040800, // 0004 RET 1 R4 + 0x8C100300, // 0005 GETMET R4 R1 K0 + 0x5C180400, // 0006 MOVE R6 R2 + 0x7C100400, // 0007 CALL R4 2 + 0x60140010, // 0008 GETGBL R5 G16 + 0x5C180600, // 0009 MOVE R6 R3 + 0x7C140200, // 000A CALL R5 1 + 0xA8020006, // 000B EXBLK 0 #0013 + 0x5C180A00, // 000C MOVE R6 R5 + 0x7C180000, // 000D CALL R6 0 + 0x8C1C0901, // 000E GETMET R7 R4 K1 + 0x4C240000, // 000F LDNIL R9 + 0x5C280C00, // 0010 MOVE R10 R6 + 0x7C1C0600, // 0011 CALL R7 3 + 0x7001FFF8, // 0012 JMP #000C + 0x58140002, // 0013 LDCONST R5 K2 + 0xAC140200, // 0014 CATCH R5 1 0 + 0xB0080000, // 0015 RAISE 2 R0 R0 + 0x80000000, // 0016 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: tostring +********************************************************************/ +be_local_closure(Matter_IM_base_tostring, /* name */ + be_nested_proto( + 5, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(_X3C), + /* K1 */ be_nested_str_weak(_X3A), + /* K2 */ be_nested_str_weak(matter), + /* K3 */ be_nested_str_weak(inspect), + /* K4 */ be_nested_str_weak(_X3E), + }), + be_str_weak(tostring), + &be_const_str_solidified, + ( &(const binstruction[12]) { /* code */ + 0x60040005, // 0000 GETGBL R1 G5 + 0x5C080000, // 0001 MOVE R2 R0 + 0x7C040200, // 0002 CALL R1 1 + 0x00060001, // 0003 ADD R1 K0 R1 + 0x00040301, // 0004 ADD R1 R1 K1 + 0xB80A0400, // 0005 GETNGBL R2 K2 + 0x8C080503, // 0006 GETMET R2 R2 K3 + 0x5C100000, // 0007 MOVE R4 R0 + 0x7C080400, // 0008 CALL R2 2 + 0x00040202, // 0009 ADD R1 R1 R2 + 0x00040304, // 000A ADD R1 R1 K4 + 0x80040200, // 000B RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: from_TLV_array +********************************************************************/ +be_local_closure(Matter_IM_base_from_TLV_array, /* name */ + be_nested_proto( + 11, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(push), + /* K1 */ be_nested_str_weak(from_TLV), + /* K2 */ be_nested_str_weak(stop_iteration), + }), + be_str_weak(from_TLV_array), + &be_const_str_solidified, + ( &(const binstruction[25]) { /* code */ + 0x4C0C0000, // 0000 LDNIL R3 + 0x1C0C0203, // 0001 EQ R3 R1 R3 + 0x780E0001, // 0002 JMPF R3 #0005 + 0x4C0C0000, // 0003 LDNIL R3 + 0x80040600, // 0004 RET 1 R3 + 0x600C0012, // 0005 GETGBL R3 G18 + 0x7C0C0000, // 0006 CALL R3 0 + 0x60100010, // 0007 GETGBL R4 G16 + 0x5C140200, // 0008 MOVE R5 R1 + 0x7C100200, // 0009 CALL R4 1 + 0xA8020009, // 000A EXBLK 0 #0015 + 0x5C140800, // 000B MOVE R5 R4 + 0x7C140000, // 000C CALL R5 0 + 0x8C180700, // 000D GETMET R6 R3 K0 + 0x5C200400, // 000E MOVE R8 R2 + 0x7C200000, // 000F CALL R8 0 + 0x8C201101, // 0010 GETMET R8 R8 K1 + 0x5C280A00, // 0011 MOVE R10 R5 + 0x7C200400, // 0012 CALL R8 2 + 0x7C180400, // 0013 CALL R6 2 + 0x7001FFF5, // 0014 JMP #000B + 0x58100002, // 0015 LDCONST R4 K2 + 0xAC100200, // 0016 CATCH R4 1 0 + 0xB0080000, // 0017 RAISE 2 R0 R0 + 0x80040600, // 0018 RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_IM_base +********************************************************************/ +be_local_class(Matter_IM_base, + 0, + NULL, + be_nested_map(3, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(from_TLV_array, -1), be_const_closure(Matter_IM_base_from_TLV_array_closure) }, + { be_const_key_weak(tostring, -1), be_const_closure(Matter_IM_base_tostring_closure) }, + { be_const_key_weak(to_TLV_array, 0), be_const_closure(Matter_IM_base_to_TLV_array_closure) }, + })), + be_str_weak(Matter_IM_base) +); +/*******************************************************************/ + +void be_load_Matter_IM_base_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_IM_base); + be_setglobal(vm, "Matter_IM_base"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_IM_Message_base; + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_IM_Message_base_init, /* name */ + be_nested_proto( + 1, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(InteractionModelRevision), + /* K1 */ be_const_int(1), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x90020101, // 0000 SETMBR R0 K0 K1 + 0x80000000, // 0001 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_IM_Message_base +********************************************************************/ +extern const bclass be_class_Matter_IM_base; +be_local_class(Matter_IM_Message_base, + 1, + &be_class_Matter_IM_base, + be_nested_map(2, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(init, -1), be_const_closure(Matter_IM_Message_base_init_closure) }, + { be_const_key_weak(InteractionModelRevision, 0), be_const_var(0) }, + })), + be_str_weak(Matter_IM_Message_base) +); +/*******************************************************************/ + +void be_load_Matter_IM_Message_base_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_IM_Message_base); + be_setglobal(vm, "Matter_IM_Message_base"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_AttributePathIB; + +/******************************************************************** +** Solidified function: to_TLV +********************************************************************/ +be_local_closure(Matter_AttributePathIB_to_TLV, /* name */ + be_nested_proto( + 8, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[18]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(TLV), + /* K2 */ be_nested_str_weak(Matter_TLV_list), + /* K3 */ be_nested_str_weak(add_TLV), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str_weak(BOOL), + /* K6 */ be_nested_str_weak(tag_compression), + /* K7 */ be_const_int(1), + /* K8 */ be_nested_str_weak(U8), + /* K9 */ be_nested_str_weak(node), + /* K10 */ be_const_int(2), + /* K11 */ be_nested_str_weak(U2), + /* K12 */ be_nested_str_weak(endpoint), + /* K13 */ be_const_int(3), + /* K14 */ be_nested_str_weak(U4), + /* K15 */ be_nested_str_weak(cluster), + /* K16 */ be_nested_str_weak(attribute), + /* K17 */ be_nested_str_weak(list_index), + }), + be_str_weak(to_TLV), + &be_const_str_solidified, + ( &(const binstruction[35]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x88040301, // 0001 GETMBR R1 R1 K1 + 0x8C080302, // 0002 GETMET R2 R1 K2 + 0x7C080200, // 0003 CALL R2 1 + 0x8C0C0503, // 0004 GETMET R3 R2 K3 + 0x58140004, // 0005 LDCONST R5 K4 + 0x88180305, // 0006 GETMBR R6 R1 K5 + 0x881C0106, // 0007 GETMBR R7 R0 K6 + 0x7C0C0800, // 0008 CALL R3 4 + 0x8C0C0503, // 0009 GETMET R3 R2 K3 + 0x58140007, // 000A LDCONST R5 K7 + 0x88180308, // 000B GETMBR R6 R1 K8 + 0x881C0109, // 000C GETMBR R7 R0 K9 + 0x7C0C0800, // 000D CALL R3 4 + 0x8C0C0503, // 000E GETMET R3 R2 K3 + 0x5814000A, // 000F LDCONST R5 K10 + 0x8818030B, // 0010 GETMBR R6 R1 K11 + 0x881C010C, // 0011 GETMBR R7 R0 K12 + 0x7C0C0800, // 0012 CALL R3 4 + 0x8C0C0503, // 0013 GETMET R3 R2 K3 + 0x5814000D, // 0014 LDCONST R5 K13 + 0x8818030E, // 0015 GETMBR R6 R1 K14 + 0x881C010F, // 0016 GETMBR R7 R0 K15 + 0x7C0C0800, // 0017 CALL R3 4 + 0x8C0C0503, // 0018 GETMET R3 R2 K3 + 0x54160003, // 0019 LDINT R5 4 + 0x8818030E, // 001A GETMBR R6 R1 K14 + 0x881C0110, // 001B GETMBR R7 R0 K16 + 0x7C0C0800, // 001C CALL R3 4 + 0x8C0C0503, // 001D GETMET R3 R2 K3 + 0x54160004, // 001E LDINT R5 5 + 0x8818030B, // 001F GETMBR R6 R1 K11 + 0x881C0111, // 0020 GETMBR R7 R0 K17 + 0x7C0C0800, // 0021 CALL R3 4 + 0x80040400, // 0022 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: tostring +********************************************************************/ +be_local_closure(Matter_AttributePathIB_tostring, /* name */ + be_nested_proto( + 7, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[16]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(), + /* K2 */ be_nested_str_weak(node), + /* K3 */ be_nested_str_weak(format), + /* K4 */ be_nested_str_weak(node_X3D_X25s_X20), + /* K5 */ be_nested_str_weak(endpoint), + /* K6 */ be_nested_str_weak(_X5B_X2502X_X5D), + /* K7 */ be_nested_str_weak(_X5B_X2A_X2A_X5D), + /* K8 */ be_nested_str_weak(cluster), + /* K9 */ be_nested_str_weak(_X2504X_X2F), + /* K10 */ be_nested_str_weak(_X2A_X2A_X2A_X2A_X2F), + /* K11 */ be_nested_str_weak(attribute), + /* K12 */ be_nested_str_weak(_X2504X), + /* K13 */ be_nested_str_weak(_X2A_X2A_X2A_X2A), + /* K14 */ be_nested_str_weak(Exception_X3E_X20), + /* K15 */ be_nested_str_weak(_X2C_X20), + }), + be_str_weak(tostring), + &be_const_str_solidified, + ( &(const binstruction[62]) { /* code */ + 0xA802002D, // 0000 EXBLK 0 #002F + 0xA4060000, // 0001 IMPORT R1 K0 + 0x58080001, // 0002 LDCONST R2 K1 + 0x880C0102, // 0003 GETMBR R3 R0 K2 + 0x780E0004, // 0004 JMPF R3 #000A + 0x8C0C0303, // 0005 GETMET R3 R1 K3 + 0x58140004, // 0006 LDCONST R5 K4 + 0x88180102, // 0007 GETMBR R6 R0 K2 + 0x7C0C0600, // 0008 CALL R3 3 + 0x00080403, // 0009 ADD R2 R2 R3 + 0x880C0105, // 000A GETMBR R3 R0 K5 + 0x4C100000, // 000B LDNIL R4 + 0x200C0604, // 000C NE R3 R3 R4 + 0x780E0004, // 000D JMPF R3 #0013 + 0x8C0C0303, // 000E GETMET R3 R1 K3 + 0x58140006, // 000F LDCONST R5 K6 + 0x88180105, // 0010 GETMBR R6 R0 K5 + 0x7C0C0600, // 0011 CALL R3 3 + 0x70020000, // 0012 JMP #0014 + 0x580C0007, // 0013 LDCONST R3 K7 + 0x00080403, // 0014 ADD R2 R2 R3 + 0x880C0108, // 0015 GETMBR R3 R0 K8 + 0x4C100000, // 0016 LDNIL R4 + 0x200C0604, // 0017 NE R3 R3 R4 + 0x780E0004, // 0018 JMPF R3 #001E + 0x8C0C0303, // 0019 GETMET R3 R1 K3 + 0x58140009, // 001A LDCONST R5 K9 + 0x88180108, // 001B GETMBR R6 R0 K8 + 0x7C0C0600, // 001C CALL R3 3 + 0x70020000, // 001D JMP #001F + 0x580C000A, // 001E LDCONST R3 K10 + 0x00080403, // 001F ADD R2 R2 R3 + 0x880C010B, // 0020 GETMBR R3 R0 K11 + 0x4C100000, // 0021 LDNIL R4 + 0x200C0604, // 0022 NE R3 R3 R4 + 0x780E0004, // 0023 JMPF R3 #0029 + 0x8C0C0303, // 0024 GETMET R3 R1 K3 + 0x5814000C, // 0025 LDCONST R5 K12 + 0x8818010B, // 0026 GETMBR R6 R0 K11 + 0x7C0C0600, // 0027 CALL R3 3 + 0x70020000, // 0028 JMP #002A + 0x580C000D, // 0029 LDCONST R3 K13 + 0x00080403, // 002A ADD R2 R2 R3 + 0xA8040001, // 002B EXBLK 1 1 + 0x80040400, // 002C RET 1 R2 + 0xA8040001, // 002D EXBLK 1 1 + 0x7002000D, // 002E JMP #003D + 0xAC040002, // 002F CATCH R1 0 2 + 0x7002000A, // 0030 JMP #003C + 0x600C0008, // 0031 GETGBL R3 G8 + 0x5C100200, // 0032 MOVE R4 R1 + 0x7C0C0200, // 0033 CALL R3 1 + 0x000E1C03, // 0034 ADD R3 K14 R3 + 0x000C070F, // 0035 ADD R3 R3 K15 + 0x60100008, // 0036 GETGBL R4 G8 + 0x5C140400, // 0037 MOVE R5 R2 + 0x7C100200, // 0038 CALL R4 1 + 0x000C0604, // 0039 ADD R3 R3 R4 + 0x80040600, // 003A RET 1 R3 + 0x70020000, // 003B JMP #003D + 0xB0080000, // 003C RAISE 2 R0 R0 + 0x80000000, // 003D RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: from_TLV +********************************************************************/ +be_local_closure(Matter_AttributePathIB_from_TLV, /* name */ + be_nested_proto( + 5, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[11]) { /* constants */ + /* K0 */ be_nested_str_weak(tag_compression), + /* K1 */ be_nested_str_weak(findsubval), + /* K2 */ be_const_int(0), + /* K3 */ be_nested_str_weak(node), + /* K4 */ be_const_int(1), + /* K5 */ be_nested_str_weak(endpoint), + /* K6 */ be_const_int(2), + /* K7 */ be_nested_str_weak(cluster), + /* K8 */ be_const_int(3), + /* K9 */ be_nested_str_weak(attribute), + /* K10 */ be_nested_str_weak(list_index), + }), + be_str_weak(from_TLV), + &be_const_str_solidified, + ( &(const binstruction[30]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0001, // 0002 JMPF R2 #0005 + 0x4C080000, // 0003 LDNIL R2 + 0x80040400, // 0004 RET 1 R2 + 0x8C080301, // 0005 GETMET R2 R1 K1 + 0x58100002, // 0006 LDCONST R4 K2 + 0x7C080400, // 0007 CALL R2 2 + 0x90020002, // 0008 SETMBR R0 K0 R2 + 0x8C080301, // 0009 GETMET R2 R1 K1 + 0x58100004, // 000A LDCONST R4 K4 + 0x7C080400, // 000B CALL R2 2 + 0x90020602, // 000C SETMBR R0 K3 R2 + 0x8C080301, // 000D GETMET R2 R1 K1 + 0x58100006, // 000E LDCONST R4 K6 + 0x7C080400, // 000F CALL R2 2 + 0x90020A02, // 0010 SETMBR R0 K5 R2 + 0x8C080301, // 0011 GETMET R2 R1 K1 + 0x58100008, // 0012 LDCONST R4 K8 + 0x7C080400, // 0013 CALL R2 2 + 0x90020E02, // 0014 SETMBR R0 K7 R2 + 0x8C080301, // 0015 GETMET R2 R1 K1 + 0x54120003, // 0016 LDINT R4 4 + 0x7C080400, // 0017 CALL R2 2 + 0x90021202, // 0018 SETMBR R0 K9 R2 + 0x8C080301, // 0019 GETMET R2 R1 K1 + 0x54120004, // 001A LDINT R4 5 + 0x7C080400, // 001B CALL R2 2 + 0x90021402, // 001C SETMBR R0 K10 R2 + 0x80040000, // 001D RET 1 R0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_AttributePathIB +********************************************************************/ +extern const bclass be_class_Matter_IM_base; +be_local_class(Matter_AttributePathIB, + 6, + &be_class_Matter_IM_base, + be_nested_map(9, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(tostring, -1), be_const_closure(Matter_AttributePathIB_tostring_closure) }, + { be_const_key_weak(tag_compression, 0), be_const_var(0) }, + { be_const_key_weak(cluster, -1), be_const_var(3) }, + { be_const_key_weak(attribute, -1), be_const_var(4) }, + { be_const_key_weak(to_TLV, 2), be_const_closure(Matter_AttributePathIB_to_TLV_closure) }, + { be_const_key_weak(list_index, 3), be_const_var(5) }, + { be_const_key_weak(from_TLV, -1), be_const_closure(Matter_AttributePathIB_from_TLV_closure) }, + { be_const_key_weak(endpoint, 1), be_const_var(2) }, + { be_const_key_weak(node, -1), be_const_var(1) }, + })), + be_str_weak(Matter_AttributePathIB) +); +/*******************************************************************/ + +void be_load_Matter_AttributePathIB_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_AttributePathIB); + be_setglobal(vm, "Matter_AttributePathIB"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_ClusterPathIB; + +/******************************************************************** +** Solidified function: from_TLV +********************************************************************/ +be_local_closure(Matter_ClusterPathIB_from_TLV, /* name */ + be_nested_proto( + 5, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 7]) { /* constants */ + /* K0 */ be_nested_str_weak(node), + /* K1 */ be_nested_str_weak(findsubval), + /* K2 */ be_const_int(0), + /* K3 */ be_nested_str_weak(endpoint), + /* K4 */ be_const_int(1), + /* K5 */ be_nested_str_weak(cluster), + /* K6 */ be_const_int(2), + }), + be_str_weak(from_TLV), + &be_const_str_solidified, + ( &(const binstruction[18]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0001, // 0002 JMPF R2 #0005 + 0x4C080000, // 0003 LDNIL R2 + 0x80040400, // 0004 RET 1 R2 + 0x8C080301, // 0005 GETMET R2 R1 K1 + 0x58100002, // 0006 LDCONST R4 K2 + 0x7C080400, // 0007 CALL R2 2 + 0x90020002, // 0008 SETMBR R0 K0 R2 + 0x8C080301, // 0009 GETMET R2 R1 K1 + 0x58100004, // 000A LDCONST R4 K4 + 0x7C080400, // 000B CALL R2 2 + 0x90020602, // 000C SETMBR R0 K3 R2 + 0x8C080301, // 000D GETMET R2 R1 K1 + 0x58100006, // 000E LDCONST R4 K6 + 0x7C080400, // 000F CALL R2 2 + 0x90020A02, // 0010 SETMBR R0 K5 R2 + 0x80040000, // 0011 RET 1 R0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: to_TLV +********************************************************************/ +be_local_closure(Matter_ClusterPathIB_to_TLV, /* name */ + be_nested_proto( + 8, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[13]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(TLV), + /* K2 */ be_nested_str_weak(Matter_TLV_list), + /* K3 */ be_nested_str_weak(add_TLV), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str_weak(U8), + /* K6 */ be_nested_str_weak(node), + /* K7 */ be_const_int(1), + /* K8 */ be_nested_str_weak(U2), + /* K9 */ be_nested_str_weak(endpoint), + /* K10 */ be_const_int(2), + /* K11 */ be_nested_str_weak(U4), + /* K12 */ be_nested_str_weak(cluster), + }), + be_str_weak(to_TLV), + &be_const_str_solidified, + ( &(const binstruction[20]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x88040301, // 0001 GETMBR R1 R1 K1 + 0x8C080302, // 0002 GETMET R2 R1 K2 + 0x7C080200, // 0003 CALL R2 1 + 0x8C0C0503, // 0004 GETMET R3 R2 K3 + 0x58140004, // 0005 LDCONST R5 K4 + 0x88180305, // 0006 GETMBR R6 R1 K5 + 0x881C0106, // 0007 GETMBR R7 R0 K6 + 0x7C0C0800, // 0008 CALL R3 4 + 0x8C0C0503, // 0009 GETMET R3 R2 K3 + 0x58140007, // 000A LDCONST R5 K7 + 0x88180308, // 000B GETMBR R6 R1 K8 + 0x881C0109, // 000C GETMBR R7 R0 K9 + 0x7C0C0800, // 000D CALL R3 4 + 0x8C0C0503, // 000E GETMET R3 R2 K3 + 0x5814000A, // 000F LDCONST R5 K10 + 0x8818030B, // 0010 GETMBR R6 R1 K11 + 0x881C010C, // 0011 GETMBR R7 R0 K12 + 0x7C0C0800, // 0012 CALL R3 4 + 0x80040400, // 0013 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_ClusterPathIB +********************************************************************/ +extern const bclass be_class_Matter_IM_base; +be_local_class(Matter_ClusterPathIB, + 3, + &be_class_Matter_IM_base, + be_nested_map(5, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(from_TLV, -1), be_const_closure(Matter_ClusterPathIB_from_TLV_closure) }, + { be_const_key_weak(node, -1), be_const_var(0) }, + { be_const_key_weak(cluster, -1), be_const_var(2) }, + { be_const_key_weak(endpoint, 0), be_const_var(1) }, + { be_const_key_weak(to_TLV, -1), be_const_closure(Matter_ClusterPathIB_to_TLV_closure) }, + })), + be_str_weak(Matter_ClusterPathIB) +); +/*******************************************************************/ + +void be_load_Matter_ClusterPathIB_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_ClusterPathIB); + be_setglobal(vm, "Matter_ClusterPathIB"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_DataVersionFilterIB; + +/******************************************************************** +** Solidified function: from_TLV +********************************************************************/ +be_local_closure(Matter_DataVersionFilterIB_from_TLV, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 9]) { /* constants */ + /* K0 */ be_nested_str_weak(path), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(ClusterPathIB), + /* K3 */ be_nested_str_weak(from_TLV), + /* K4 */ be_nested_str_weak(findsub), + /* K5 */ be_const_int(0), + /* K6 */ be_nested_str_weak(data_version), + /* K7 */ be_nested_str_weak(findsubval), + /* K8 */ be_const_int(1), + }), + be_str_weak(from_TLV), + &be_const_str_solidified, + ( &(const binstruction[19]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0001, // 0002 JMPF R2 #0005 + 0x4C080000, // 0003 LDNIL R2 + 0x80040400, // 0004 RET 1 R2 + 0xB80A0200, // 0005 GETNGBL R2 K1 + 0x8C080502, // 0006 GETMET R2 R2 K2 + 0x7C080200, // 0007 CALL R2 1 + 0x8C080503, // 0008 GETMET R2 R2 K3 + 0x8C100304, // 0009 GETMET R4 R1 K4 + 0x58180005, // 000A LDCONST R6 K5 + 0x7C100400, // 000B CALL R4 2 + 0x7C080400, // 000C CALL R2 2 + 0x90020002, // 000D SETMBR R0 K0 R2 + 0x8C080307, // 000E GETMET R2 R1 K7 + 0x58100008, // 000F LDCONST R4 K8 + 0x7C080400, // 0010 CALL R2 2 + 0x90020C02, // 0011 SETMBR R0 K6 R2 + 0x80040000, // 0012 RET 1 R0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: to_TLV +********************************************************************/ +be_local_closure(Matter_DataVersionFilterIB_to_TLV, /* name */ + be_nested_proto( + 8, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[10]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(TLV), + /* K2 */ be_nested_str_weak(Matter_TLV_struct), + /* K3 */ be_nested_str_weak(add_obj), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str_weak(path), + /* K6 */ be_nested_str_weak(add_TLV), + /* K7 */ be_const_int(1), + /* K8 */ be_nested_str_weak(U4), + /* K9 */ be_nested_str_weak(data_version), + }), + be_str_weak(to_TLV), + &be_const_str_solidified, + ( &(const binstruction[14]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x88040301, // 0001 GETMBR R1 R1 K1 + 0x8C080302, // 0002 GETMET R2 R1 K2 + 0x7C080200, // 0003 CALL R2 1 + 0x8C0C0503, // 0004 GETMET R3 R2 K3 + 0x58140004, // 0005 LDCONST R5 K4 + 0x88180105, // 0006 GETMBR R6 R0 K5 + 0x7C0C0600, // 0007 CALL R3 3 + 0x8C0C0506, // 0008 GETMET R3 R2 K6 + 0x58140007, // 0009 LDCONST R5 K7 + 0x88180308, // 000A GETMBR R6 R1 K8 + 0x881C0109, // 000B GETMBR R7 R0 K9 + 0x7C0C0800, // 000C CALL R3 4 + 0x80040400, // 000D RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_DataVersionFilterIB +********************************************************************/ +extern const bclass be_class_Matter_IM_base; +be_local_class(Matter_DataVersionFilterIB, + 2, + &be_class_Matter_IM_base, + be_nested_map(4, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(from_TLV, -1), be_const_closure(Matter_DataVersionFilterIB_from_TLV_closure) }, + { be_const_key_weak(to_TLV, -1), be_const_closure(Matter_DataVersionFilterIB_to_TLV_closure) }, + { be_const_key_weak(path, 3), be_const_var(0) }, + { be_const_key_weak(data_version, -1), be_const_var(1) }, + })), + be_str_weak(Matter_DataVersionFilterIB) +); +/*******************************************************************/ + +void be_load_Matter_DataVersionFilterIB_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_DataVersionFilterIB); + be_setglobal(vm, "Matter_DataVersionFilterIB"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_AttributeDataIB; + +/******************************************************************** +** Solidified function: from_TLV +********************************************************************/ +be_local_closure(Matter_AttributeDataIB_from_TLV, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[11]) { /* constants */ + /* K0 */ be_nested_str_weak(data_version), + /* K1 */ be_nested_str_weak(findsubval), + /* K2 */ be_const_int(0), + /* K3 */ be_nested_str_weak(path), + /* K4 */ be_nested_str_weak(matter), + /* K5 */ be_nested_str_weak(AttributePathIB), + /* K6 */ be_nested_str_weak(from_TLV), + /* K7 */ be_nested_str_weak(findsub), + /* K8 */ be_const_int(1), + /* K9 */ be_nested_str_weak(data), + /* K10 */ be_const_int(2), + }), + be_str_weak(from_TLV), + &be_const_str_solidified, + ( &(const binstruction[23]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0001, // 0002 JMPF R2 #0005 + 0x4C080000, // 0003 LDNIL R2 + 0x80040400, // 0004 RET 1 R2 + 0x8C080301, // 0005 GETMET R2 R1 K1 + 0x58100002, // 0006 LDCONST R4 K2 + 0x7C080400, // 0007 CALL R2 2 + 0x90020002, // 0008 SETMBR R0 K0 R2 + 0xB80A0800, // 0009 GETNGBL R2 K4 + 0x8C080505, // 000A GETMET R2 R2 K5 + 0x7C080200, // 000B CALL R2 1 + 0x8C080506, // 000C GETMET R2 R2 K6 + 0x8C100307, // 000D GETMET R4 R1 K7 + 0x58180008, // 000E LDCONST R6 K8 + 0x7C100400, // 000F CALL R4 2 + 0x7C080400, // 0010 CALL R2 2 + 0x90020602, // 0011 SETMBR R0 K3 R2 + 0x8C080301, // 0012 GETMET R2 R1 K1 + 0x5810000A, // 0013 LDCONST R4 K10 + 0x7C080400, // 0014 CALL R2 2 + 0x90021202, // 0015 SETMBR R0 K9 R2 + 0x80040000, // 0016 RET 1 R0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: to_TLV +********************************************************************/ +be_local_closure(Matter_AttributeDataIB_to_TLV, /* name */ + be_nested_proto( + 8, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[12]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(TLV), + /* K2 */ be_nested_str_weak(Matter_TLV_struct), + /* K3 */ be_nested_str_weak(add_TLV), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str_weak(U4), + /* K6 */ be_nested_str_weak(data_version), + /* K7 */ be_nested_str_weak(add_obj), + /* K8 */ be_const_int(1), + /* K9 */ be_nested_str_weak(path), + /* K10 */ be_const_int(2), + /* K11 */ be_nested_str_weak(data), + }), + be_str_weak(to_TLV), + &be_const_str_solidified, + ( &(const binstruction[18]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x88040301, // 0001 GETMBR R1 R1 K1 + 0x8C080302, // 0002 GETMET R2 R1 K2 + 0x7C080200, // 0003 CALL R2 1 + 0x8C0C0503, // 0004 GETMET R3 R2 K3 + 0x58140004, // 0005 LDCONST R5 K4 + 0x88180305, // 0006 GETMBR R6 R1 K5 + 0x881C0106, // 0007 GETMBR R7 R0 K6 + 0x7C0C0800, // 0008 CALL R3 4 + 0x8C0C0507, // 0009 GETMET R3 R2 K7 + 0x58140008, // 000A LDCONST R5 K8 + 0x88180109, // 000B GETMBR R6 R0 K9 + 0x7C0C0600, // 000C CALL R3 3 + 0x8C0C0507, // 000D GETMET R3 R2 K7 + 0x5814000A, // 000E LDCONST R5 K10 + 0x8818010B, // 000F GETMBR R6 R0 K11 + 0x7C0C0600, // 0010 CALL R3 3 + 0x80040400, // 0011 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_AttributeDataIB +********************************************************************/ +extern const bclass be_class_Matter_IM_base; +be_local_class(Matter_AttributeDataIB, + 3, + &be_class_Matter_IM_base, + be_nested_map(5, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(data_version, -1), be_const_var(0) }, + { be_const_key_weak(data, -1), be_const_var(2) }, + { be_const_key_weak(from_TLV, -1), be_const_closure(Matter_AttributeDataIB_from_TLV_closure) }, + { be_const_key_weak(path, 2), be_const_var(1) }, + { be_const_key_weak(to_TLV, -1), be_const_closure(Matter_AttributeDataIB_to_TLV_closure) }, + })), + be_str_weak(Matter_AttributeDataIB) +); +/*******************************************************************/ + +void be_load_Matter_AttributeDataIB_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_AttributeDataIB); + be_setglobal(vm, "Matter_AttributeDataIB"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_AttributeReportIB; + +/******************************************************************** +** Solidified function: to_TLV +********************************************************************/ +be_local_closure(Matter_AttributeReportIB_to_TLV, /* name */ + be_nested_proto( + 7, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(TLV), + /* K2 */ be_nested_str_weak(Matter_TLV_struct), + /* K3 */ be_nested_str_weak(add_obj), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str_weak(attribute_status), + /* K6 */ be_const_int(1), + /* K7 */ be_nested_str_weak(attribute_data), + }), + be_str_weak(to_TLV), + &be_const_str_solidified, + ( &(const binstruction[13]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x88040301, // 0001 GETMBR R1 R1 K1 + 0x8C080302, // 0002 GETMET R2 R1 K2 + 0x7C080200, // 0003 CALL R2 1 + 0x8C0C0503, // 0004 GETMET R3 R2 K3 + 0x58140004, // 0005 LDCONST R5 K4 + 0x88180105, // 0006 GETMBR R6 R0 K5 + 0x7C0C0600, // 0007 CALL R3 3 + 0x8C0C0503, // 0008 GETMET R3 R2 K3 + 0x58140006, // 0009 LDCONST R5 K6 + 0x88180107, // 000A GETMBR R6 R0 K7 + 0x7C0C0600, // 000B CALL R3 3 + 0x80040400, // 000C RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: from_TLV +********************************************************************/ +be_local_closure(Matter_AttributeReportIB_from_TLV, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 9]) { /* constants */ + /* K0 */ be_nested_str_weak(attribute_status), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(AttributeStatusIB), + /* K3 */ be_nested_str_weak(from_TLV), + /* K4 */ be_nested_str_weak(findsub), + /* K5 */ be_const_int(0), + /* K6 */ be_nested_str_weak(attribute_data), + /* K7 */ be_nested_str_weak(AttributeDataIB), + /* K8 */ be_const_int(1), + }), + be_str_weak(from_TLV), + &be_const_str_solidified, + ( &(const binstruction[24]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0001, // 0002 JMPF R2 #0005 + 0x4C080000, // 0003 LDNIL R2 + 0x80040400, // 0004 RET 1 R2 + 0xB80A0200, // 0005 GETNGBL R2 K1 + 0x8C080502, // 0006 GETMET R2 R2 K2 + 0x7C080200, // 0007 CALL R2 1 + 0x8C080503, // 0008 GETMET R2 R2 K3 + 0x8C100304, // 0009 GETMET R4 R1 K4 + 0x58180005, // 000A LDCONST R6 K5 + 0x7C100400, // 000B CALL R4 2 + 0x7C080400, // 000C CALL R2 2 + 0x90020002, // 000D SETMBR R0 K0 R2 + 0xB80A0200, // 000E GETNGBL R2 K1 + 0x8C080507, // 000F GETMET R2 R2 K7 + 0x7C080200, // 0010 CALL R2 1 + 0x8C080503, // 0011 GETMET R2 R2 K3 + 0x8C100304, // 0012 GETMET R4 R1 K4 + 0x58180008, // 0013 LDCONST R6 K8 + 0x7C100400, // 0014 CALL R4 2 + 0x7C080400, // 0015 CALL R2 2 + 0x90020C02, // 0016 SETMBR R0 K6 R2 + 0x80040000, // 0017 RET 1 R0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_AttributeReportIB +********************************************************************/ +extern const bclass be_class_Matter_IM_base; +be_local_class(Matter_AttributeReportIB, + 2, + &be_class_Matter_IM_base, + be_nested_map(4, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(attribute_data, 3), be_const_var(1) }, + { be_const_key_weak(to_TLV, -1), be_const_closure(Matter_AttributeReportIB_to_TLV_closure) }, + { be_const_key_weak(attribute_status, -1), be_const_var(0) }, + { be_const_key_weak(from_TLV, -1), be_const_closure(Matter_AttributeReportIB_from_TLV_closure) }, + })), + be_str_weak(Matter_AttributeReportIB) +); +/*******************************************************************/ + +void be_load_Matter_AttributeReportIB_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_AttributeReportIB); + be_setglobal(vm, "Matter_AttributeReportIB"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_EventFilterIB; + +/******************************************************************** +** Solidified function: from_TLV +********************************************************************/ +be_local_closure(Matter_EventFilterIB_from_TLV, /* name */ + be_nested_proto( + 5, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(node), + /* K1 */ be_nested_str_weak(findsubval), + /* K2 */ be_const_int(0), + /* K3 */ be_nested_str_weak(event_min), + /* K4 */ be_const_int(1), + }), + be_str_weak(from_TLV), + &be_const_str_solidified, + ( &(const binstruction[14]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0001, // 0002 JMPF R2 #0005 + 0x4C080000, // 0003 LDNIL R2 + 0x80040400, // 0004 RET 1 R2 + 0x8C080301, // 0005 GETMET R2 R1 K1 + 0x58100002, // 0006 LDCONST R4 K2 + 0x7C080400, // 0007 CALL R2 2 + 0x90020002, // 0008 SETMBR R0 K0 R2 + 0x8C080301, // 0009 GETMET R2 R1 K1 + 0x58100004, // 000A LDCONST R4 K4 + 0x7C080400, // 000B CALL R2 2 + 0x90020602, // 000C SETMBR R0 K3 R2 + 0x80040000, // 000D RET 1 R0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: to_TLV +********************************************************************/ +be_local_closure(Matter_EventFilterIB_to_TLV, /* name */ + be_nested_proto( + 8, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 9]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(TLV), + /* K2 */ be_nested_str_weak(Matter_TLV_struct), + /* K3 */ be_nested_str_weak(add_TLV), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str_weak(U8), + /* K6 */ be_nested_str_weak(node), + /* K7 */ be_const_int(1), + /* K8 */ be_nested_str_weak(event_min), + }), + be_str_weak(to_TLV), + &be_const_str_solidified, + ( &(const binstruction[15]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x88040301, // 0001 GETMBR R1 R1 K1 + 0x8C080302, // 0002 GETMET R2 R1 K2 + 0x7C080200, // 0003 CALL R2 1 + 0x8C0C0503, // 0004 GETMET R3 R2 K3 + 0x58140004, // 0005 LDCONST R5 K4 + 0x88180305, // 0006 GETMBR R6 R1 K5 + 0x881C0106, // 0007 GETMBR R7 R0 K6 + 0x7C0C0800, // 0008 CALL R3 4 + 0x8C0C0503, // 0009 GETMET R3 R2 K3 + 0x58140007, // 000A LDCONST R5 K7 + 0x88180305, // 000B GETMBR R6 R1 K5 + 0x881C0108, // 000C GETMBR R7 R0 K8 + 0x7C0C0800, // 000D CALL R3 4 + 0x80040400, // 000E RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_EventFilterIB +********************************************************************/ +extern const bclass be_class_Matter_IM_base; +be_local_class(Matter_EventFilterIB, + 2, + &be_class_Matter_IM_base, + be_nested_map(4, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(event_min, 3), be_const_var(1) }, + { be_const_key_weak(node, 2), be_const_var(0) }, + { be_const_key_weak(to_TLV, -1), be_const_closure(Matter_EventFilterIB_to_TLV_closure) }, + { be_const_key_weak(from_TLV, -1), be_const_closure(Matter_EventFilterIB_from_TLV_closure) }, + })), + be_str_weak(Matter_EventFilterIB) +); +/*******************************************************************/ + +void be_load_Matter_EventFilterIB_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_EventFilterIB); + be_setglobal(vm, "Matter_EventFilterIB"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_EventPathIB; + +/******************************************************************** +** Solidified function: from_TLV +********************************************************************/ +be_local_closure(Matter_EventPathIB_from_TLV, /* name */ + be_nested_proto( + 5, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[10]) { /* constants */ + /* K0 */ be_nested_str_weak(node), + /* K1 */ be_nested_str_weak(findsubval), + /* K2 */ be_const_int(0), + /* K3 */ be_nested_str_weak(endpoint), + /* K4 */ be_const_int(1), + /* K5 */ be_nested_str_weak(cluster), + /* K6 */ be_const_int(2), + /* K7 */ be_nested_str_weak(event), + /* K8 */ be_const_int(3), + /* K9 */ be_nested_str_weak(is_urgent), + }), + be_str_weak(from_TLV), + &be_const_str_solidified, + ( &(const binstruction[26]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0001, // 0002 JMPF R2 #0005 + 0x4C080000, // 0003 LDNIL R2 + 0x80040400, // 0004 RET 1 R2 + 0x8C080301, // 0005 GETMET R2 R1 K1 + 0x58100002, // 0006 LDCONST R4 K2 + 0x7C080400, // 0007 CALL R2 2 + 0x90020002, // 0008 SETMBR R0 K0 R2 + 0x8C080301, // 0009 GETMET R2 R1 K1 + 0x58100004, // 000A LDCONST R4 K4 + 0x7C080400, // 000B CALL R2 2 + 0x90020602, // 000C SETMBR R0 K3 R2 + 0x8C080301, // 000D GETMET R2 R1 K1 + 0x58100006, // 000E LDCONST R4 K6 + 0x7C080400, // 000F CALL R2 2 + 0x90020A02, // 0010 SETMBR R0 K5 R2 + 0x8C080301, // 0011 GETMET R2 R1 K1 + 0x58100008, // 0012 LDCONST R4 K8 + 0x7C080400, // 0013 CALL R2 2 + 0x90020E02, // 0014 SETMBR R0 K7 R2 + 0x8C080301, // 0015 GETMET R2 R1 K1 + 0x54120003, // 0016 LDINT R4 4 + 0x7C080400, // 0017 CALL R2 2 + 0x90021202, // 0018 SETMBR R0 K9 R2 + 0x80040000, // 0019 RET 1 R0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: to_TLV +********************************************************************/ +be_local_closure(Matter_EventPathIB_to_TLV, /* name */ + be_nested_proto( + 8, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[17]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(TLV), + /* K2 */ be_nested_str_weak(Matter_TLV_list), + /* K3 */ be_nested_str_weak(add_TLV), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str_weak(U8), + /* K6 */ be_nested_str_weak(node), + /* K7 */ be_const_int(1), + /* K8 */ be_nested_str_weak(U2), + /* K9 */ be_nested_str_weak(endpoint), + /* K10 */ be_const_int(2), + /* K11 */ be_nested_str_weak(U4), + /* K12 */ be_nested_str_weak(cluster), + /* K13 */ be_const_int(3), + /* K14 */ be_nested_str_weak(event), + /* K15 */ be_nested_str_weak(BOOL), + /* K16 */ be_nested_str_weak(is_urgent), + }), + be_str_weak(to_TLV), + &be_const_str_solidified, + ( &(const binstruction[34]) { /* code */ + 0xB80A0000, // 0000 GETNGBL R2 K0 + 0x88080501, // 0001 GETMBR R2 R2 K1 + 0x4C0C0000, // 0002 LDNIL R3 + 0x1C0C0203, // 0003 EQ R3 R1 R3 + 0x780E0002, // 0004 JMPF R3 #0008 + 0x8C0C0502, // 0005 GETMET R3 R2 K2 + 0x7C0C0200, // 0006 CALL R3 1 + 0x5C040600, // 0007 MOVE R1 R3 + 0x8C0C0303, // 0008 GETMET R3 R1 K3 + 0x58140004, // 0009 LDCONST R5 K4 + 0x88180505, // 000A GETMBR R6 R2 K5 + 0x881C0106, // 000B GETMBR R7 R0 K6 + 0x7C0C0800, // 000C CALL R3 4 + 0x8C0C0303, // 000D GETMET R3 R1 K3 + 0x58140007, // 000E LDCONST R5 K7 + 0x88180508, // 000F GETMBR R6 R2 K8 + 0x881C0109, // 0010 GETMBR R7 R0 K9 + 0x7C0C0800, // 0011 CALL R3 4 + 0x8C0C0303, // 0012 GETMET R3 R1 K3 + 0x5814000A, // 0013 LDCONST R5 K10 + 0x8818050B, // 0014 GETMBR R6 R2 K11 + 0x881C010C, // 0015 GETMBR R7 R0 K12 + 0x7C0C0800, // 0016 CALL R3 4 + 0x8C0C0303, // 0017 GETMET R3 R1 K3 + 0x5814000D, // 0018 LDCONST R5 K13 + 0x8818050B, // 0019 GETMBR R6 R2 K11 + 0x881C010E, // 001A GETMBR R7 R0 K14 + 0x7C0C0800, // 001B CALL R3 4 + 0x8C0C0303, // 001C GETMET R3 R1 K3 + 0x54160003, // 001D LDINT R5 4 + 0x8818050F, // 001E GETMBR R6 R2 K15 + 0x881C0110, // 001F GETMBR R7 R0 K16 + 0x7C0C0800, // 0020 CALL R3 4 + 0x80040200, // 0021 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_EventPathIB +********************************************************************/ +extern const bclass be_class_Matter_IM_base; +be_local_class(Matter_EventPathIB, + 5, + &be_class_Matter_IM_base, + be_nested_map(7, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(endpoint, 5), be_const_var(1) }, + { be_const_key_weak(from_TLV, -1), be_const_closure(Matter_EventPathIB_from_TLV_closure) }, + { be_const_key_weak(to_TLV, -1), be_const_closure(Matter_EventPathIB_to_TLV_closure) }, + { be_const_key_weak(is_urgent, -1), be_const_var(4) }, + { be_const_key_weak(event, -1), be_const_var(3) }, + { be_const_key_weak(cluster, 3), be_const_var(2) }, + { be_const_key_weak(node, -1), be_const_var(0) }, + })), + be_str_weak(Matter_EventPathIB) +); +/*******************************************************************/ + +void be_load_Matter_EventPathIB_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_EventPathIB); + be_setglobal(vm, "Matter_EventPathIB"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_EventDataIB; + +/******************************************************************** +** Solidified function: from_TLV +********************************************************************/ +be_local_closure(Matter_EventDataIB_from_TLV, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[17]) { /* constants */ + /* K0 */ be_nested_str_weak(path), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(EventPathIB), + /* K3 */ be_nested_str_weak(from_TLV), + /* K4 */ be_nested_str_weak(findsub), + /* K5 */ be_const_int(0), + /* K6 */ be_nested_str_weak(event_number), + /* K7 */ be_nested_str_weak(findsubval), + /* K8 */ be_const_int(1), + /* K9 */ be_nested_str_weak(priority), + /* K10 */ be_const_int(2), + /* K11 */ be_nested_str_weak(epoch_timestamp), + /* K12 */ be_const_int(3), + /* K13 */ be_nested_str_weak(system_timestamp), + /* K14 */ be_nested_str_weak(delta_epoch_timestamp), + /* K15 */ be_nested_str_weak(delta_system_timestamp), + /* K16 */ be_nested_str_weak(data), + }), + be_str_weak(from_TLV), + &be_const_str_solidified, + ( &(const binstruction[43]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0001, // 0002 JMPF R2 #0005 + 0x4C080000, // 0003 LDNIL R2 + 0x80040400, // 0004 RET 1 R2 + 0xB80A0200, // 0005 GETNGBL R2 K1 + 0x8C080502, // 0006 GETMET R2 R2 K2 + 0x7C080200, // 0007 CALL R2 1 + 0x8C080503, // 0008 GETMET R2 R2 K3 + 0x8C100304, // 0009 GETMET R4 R1 K4 + 0x58180005, // 000A LDCONST R6 K5 + 0x7C100400, // 000B CALL R4 2 + 0x7C080400, // 000C CALL R2 2 + 0x90020002, // 000D SETMBR R0 K0 R2 + 0x8C080307, // 000E GETMET R2 R1 K7 + 0x58100008, // 000F LDCONST R4 K8 + 0x7C080400, // 0010 CALL R2 2 + 0x90020C02, // 0011 SETMBR R0 K6 R2 + 0x8C080307, // 0012 GETMET R2 R1 K7 + 0x5810000A, // 0013 LDCONST R4 K10 + 0x7C080400, // 0014 CALL R2 2 + 0x90021202, // 0015 SETMBR R0 K9 R2 + 0x8C080307, // 0016 GETMET R2 R1 K7 + 0x5810000C, // 0017 LDCONST R4 K12 + 0x7C080400, // 0018 CALL R2 2 + 0x90021602, // 0019 SETMBR R0 K11 R2 + 0x8C080307, // 001A GETMET R2 R1 K7 + 0x54120003, // 001B LDINT R4 4 + 0x7C080400, // 001C CALL R2 2 + 0x90021A02, // 001D SETMBR R0 K13 R2 + 0x8C080307, // 001E GETMET R2 R1 K7 + 0x54120004, // 001F LDINT R4 5 + 0x7C080400, // 0020 CALL R2 2 + 0x90021C02, // 0021 SETMBR R0 K14 R2 + 0x8C080307, // 0022 GETMET R2 R1 K7 + 0x54120005, // 0023 LDINT R4 6 + 0x7C080400, // 0024 CALL R2 2 + 0x90021E02, // 0025 SETMBR R0 K15 R2 + 0x8C080307, // 0026 GETMET R2 R1 K7 + 0x54120006, // 0027 LDINT R4 7 + 0x7C080400, // 0028 CALL R2 2 + 0x90022002, // 0029 SETMBR R0 K16 R2 + 0x80040000, // 002A RET 1 R0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: to_TLV +********************************************************************/ +be_local_closure(Matter_EventDataIB_to_TLV, /* name */ + be_nested_proto( + 8, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[21]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(TLV), + /* K2 */ be_nested_str_weak(Matter_TLV_struct), + /* K3 */ be_nested_str_weak(path), + /* K4 */ be_nested_str_weak(to_TLV), + /* K5 */ be_nested_str_weak(add_list), + /* K6 */ be_const_int(0), + /* K7 */ be_nested_str_weak(add_TLV), + /* K8 */ be_const_int(1), + /* K9 */ be_nested_str_weak(U8), + /* K10 */ be_nested_str_weak(event_number), + /* K11 */ be_const_int(2), + /* K12 */ be_nested_str_weak(U1), + /* K13 */ be_nested_str_weak(priority), + /* K14 */ be_const_int(3), + /* K15 */ be_nested_str_weak(epoch_timestamp), + /* K16 */ be_nested_str_weak(system_timestamp), + /* K17 */ be_nested_str_weak(delta_epoch_timestamp), + /* K18 */ be_nested_str_weak(delta_system_timestamp), + /* K19 */ be_nested_str_weak(add_obj), + /* K20 */ be_nested_str_weak(data), + }), + be_str_weak(to_TLV), + &be_const_str_solidified, + ( &(const binstruction[51]) { /* code */ + 0xB80A0000, // 0000 GETNGBL R2 K0 + 0x88080501, // 0001 GETMBR R2 R2 K1 + 0x4C0C0000, // 0002 LDNIL R3 + 0x1C0C0203, // 0003 EQ R3 R1 R3 + 0x780E0002, // 0004 JMPF R3 #0008 + 0x8C0C0502, // 0005 GETMET R3 R2 K2 + 0x7C0C0200, // 0006 CALL R3 1 + 0x5C040600, // 0007 MOVE R1 R3 + 0x880C0103, // 0008 GETMBR R3 R0 K3 + 0x780E0005, // 0009 JMPF R3 #0010 + 0x880C0103, // 000A GETMBR R3 R0 K3 + 0x8C0C0704, // 000B GETMET R3 R3 K4 + 0x8C140305, // 000C GETMET R5 R1 K5 + 0x581C0006, // 000D LDCONST R7 K6 + 0x7C140400, // 000E CALL R5 2 + 0x7C0C0400, // 000F CALL R3 2 + 0x8C0C0307, // 0010 GETMET R3 R1 K7 + 0x58140008, // 0011 LDCONST R5 K8 + 0x88180509, // 0012 GETMBR R6 R2 K9 + 0x881C010A, // 0013 GETMBR R7 R0 K10 + 0x7C0C0800, // 0014 CALL R3 4 + 0x8C0C0307, // 0015 GETMET R3 R1 K7 + 0x5814000B, // 0016 LDCONST R5 K11 + 0x8818050C, // 0017 GETMBR R6 R2 K12 + 0x881C010D, // 0018 GETMBR R7 R0 K13 + 0x7C0C0800, // 0019 CALL R3 4 + 0x8C0C0307, // 001A GETMET R3 R1 K7 + 0x5814000E, // 001B LDCONST R5 K14 + 0x88180509, // 001C GETMBR R6 R2 K9 + 0x881C010F, // 001D GETMBR R7 R0 K15 + 0x7C0C0800, // 001E CALL R3 4 + 0x8C0C0307, // 001F GETMET R3 R1 K7 + 0x54160003, // 0020 LDINT R5 4 + 0x88180509, // 0021 GETMBR R6 R2 K9 + 0x881C0110, // 0022 GETMBR R7 R0 K16 + 0x7C0C0800, // 0023 CALL R3 4 + 0x8C0C0307, // 0024 GETMET R3 R1 K7 + 0x54160004, // 0025 LDINT R5 5 + 0x88180509, // 0026 GETMBR R6 R2 K9 + 0x881C0111, // 0027 GETMBR R7 R0 K17 + 0x7C0C0800, // 0028 CALL R3 4 + 0x8C0C0307, // 0029 GETMET R3 R1 K7 + 0x54160005, // 002A LDINT R5 6 + 0x88180509, // 002B GETMBR R6 R2 K9 + 0x881C0112, // 002C GETMBR R7 R0 K18 + 0x7C0C0800, // 002D CALL R3 4 + 0x8C0C0313, // 002E GETMET R3 R1 K19 + 0x54160006, // 002F LDINT R5 7 + 0x88180114, // 0030 GETMBR R6 R0 K20 + 0x7C0C0600, // 0031 CALL R3 3 + 0x80040200, // 0032 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_EventDataIB +********************************************************************/ +extern const bclass be_class_Matter_IM_base; +be_local_class(Matter_EventDataIB, + 8, + &be_class_Matter_IM_base, + be_nested_map(10, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(delta_system_timestamp, -1), be_const_var(6) }, + { be_const_key_weak(data, -1), be_const_var(7) }, + { be_const_key_weak(to_TLV, 6), be_const_closure(Matter_EventDataIB_to_TLV_closure) }, + { be_const_key_weak(from_TLV, -1), be_const_closure(Matter_EventDataIB_from_TLV_closure) }, + { be_const_key_weak(delta_epoch_timestamp, -1), be_const_var(5) }, + { be_const_key_weak(epoch_timestamp, -1), be_const_var(3) }, + { be_const_key_weak(system_timestamp, -1), be_const_var(4) }, + { be_const_key_weak(priority, 5), be_const_var(2) }, + { be_const_key_weak(path, 3), be_const_var(0) }, + { be_const_key_weak(event_number, 2), be_const_var(1) }, + })), + be_str_weak(Matter_EventDataIB) +); +/*******************************************************************/ + +void be_load_Matter_EventDataIB_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_EventDataIB); + be_setglobal(vm, "Matter_EventDataIB"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_EventReportIB; + +/******************************************************************** +** Solidified function: to_TLV +********************************************************************/ +be_local_closure(Matter_EventReportIB_to_TLV, /* name */ + be_nested_proto( + 7, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(TLV), + /* K2 */ be_nested_str_weak(Matter_TLV_struct), + /* K3 */ be_nested_str_weak(add_obj), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str_weak(event_status), + /* K6 */ be_const_int(1), + /* K7 */ be_nested_str_weak(event_data), + }), + be_str_weak(to_TLV), + &be_const_str_solidified, + ( &(const binstruction[13]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x88040301, // 0001 GETMBR R1 R1 K1 + 0x8C080302, // 0002 GETMET R2 R1 K2 + 0x7C080200, // 0003 CALL R2 1 + 0x8C0C0503, // 0004 GETMET R3 R2 K3 + 0x58140004, // 0005 LDCONST R5 K4 + 0x88180105, // 0006 GETMBR R6 R0 K5 + 0x7C0C0600, // 0007 CALL R3 3 + 0x8C0C0503, // 0008 GETMET R3 R2 K3 + 0x58140006, // 0009 LDCONST R5 K6 + 0x88180107, // 000A GETMBR R6 R0 K7 + 0x7C0C0600, // 000B CALL R3 3 + 0x80040400, // 000C RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: from_TLV +********************************************************************/ +be_local_closure(Matter_EventReportIB_from_TLV, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 9]) { /* constants */ + /* K0 */ be_nested_str_weak(event_status), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(EventStatusIB), + /* K3 */ be_nested_str_weak(from_TLV), + /* K4 */ be_nested_str_weak(findsub), + /* K5 */ be_const_int(0), + /* K6 */ be_nested_str_weak(event_data), + /* K7 */ be_nested_str_weak(EventDataIB), + /* K8 */ be_const_int(1), + }), + be_str_weak(from_TLV), + &be_const_str_solidified, + ( &(const binstruction[24]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0001, // 0002 JMPF R2 #0005 + 0x4C080000, // 0003 LDNIL R2 + 0x80040400, // 0004 RET 1 R2 + 0xB80A0200, // 0005 GETNGBL R2 K1 + 0x8C080502, // 0006 GETMET R2 R2 K2 + 0x7C080200, // 0007 CALL R2 1 + 0x8C080503, // 0008 GETMET R2 R2 K3 + 0x8C100304, // 0009 GETMET R4 R1 K4 + 0x58180005, // 000A LDCONST R6 K5 + 0x7C100400, // 000B CALL R4 2 + 0x7C080400, // 000C CALL R2 2 + 0x90020002, // 000D SETMBR R0 K0 R2 + 0xB80A0200, // 000E GETNGBL R2 K1 + 0x8C080507, // 000F GETMET R2 R2 K7 + 0x7C080200, // 0010 CALL R2 1 + 0x8C080503, // 0011 GETMET R2 R2 K3 + 0x8C100304, // 0012 GETMET R4 R1 K4 + 0x58180008, // 0013 LDCONST R6 K8 + 0x7C100400, // 0014 CALL R4 2 + 0x7C080400, // 0015 CALL R2 2 + 0x90020C02, // 0016 SETMBR R0 K6 R2 + 0x80040000, // 0017 RET 1 R0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_EventReportIB +********************************************************************/ +extern const bclass be_class_Matter_IM_base; +be_local_class(Matter_EventReportIB, + 2, + &be_class_Matter_IM_base, + be_nested_map(4, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(event_data, 3), be_const_var(1) }, + { be_const_key_weak(to_TLV, -1), be_const_closure(Matter_EventReportIB_to_TLV_closure) }, + { be_const_key_weak(event_status, -1), be_const_var(0) }, + { be_const_key_weak(from_TLV, -1), be_const_closure(Matter_EventReportIB_from_TLV_closure) }, + })), + be_str_weak(Matter_EventReportIB) +); +/*******************************************************************/ + +void be_load_Matter_EventReportIB_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_EventReportIB); + be_setglobal(vm, "Matter_EventReportIB"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_CommandPathIB; + +/******************************************************************** +** Solidified function: from_TLV +********************************************************************/ +be_local_closure(Matter_CommandPathIB_from_TLV, /* name */ + be_nested_proto( + 5, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 7]) { /* constants */ + /* K0 */ be_nested_str_weak(endpoint), + /* K1 */ be_nested_str_weak(findsubval), + /* K2 */ be_const_int(0), + /* K3 */ be_nested_str_weak(cluster), + /* K4 */ be_const_int(1), + /* K5 */ be_nested_str_weak(command), + /* K6 */ be_const_int(2), + }), + be_str_weak(from_TLV), + &be_const_str_solidified, + ( &(const binstruction[18]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0001, // 0002 JMPF R2 #0005 + 0x4C080000, // 0003 LDNIL R2 + 0x80040400, // 0004 RET 1 R2 + 0x8C080301, // 0005 GETMET R2 R1 K1 + 0x58100002, // 0006 LDCONST R4 K2 + 0x7C080400, // 0007 CALL R2 2 + 0x90020002, // 0008 SETMBR R0 K0 R2 + 0x8C080301, // 0009 GETMET R2 R1 K1 + 0x58100004, // 000A LDCONST R4 K4 + 0x7C080400, // 000B CALL R2 2 + 0x90020602, // 000C SETMBR R0 K3 R2 + 0x8C080301, // 000D GETMET R2 R1 K1 + 0x58100006, // 000E LDCONST R4 K6 + 0x7C080400, // 000F CALL R2 2 + 0x90020A02, // 0010 SETMBR R0 K5 R2 + 0x80040000, // 0011 RET 1 R0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: to_TLV +********************************************************************/ +be_local_closure(Matter_CommandPathIB_to_TLV, /* name */ + be_nested_proto( + 8, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[12]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(TLV), + /* K2 */ be_nested_str_weak(Matter_TLV_list), + /* K3 */ be_nested_str_weak(add_TLV), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str_weak(U2), + /* K6 */ be_nested_str_weak(endpoint), + /* K7 */ be_const_int(1), + /* K8 */ be_nested_str_weak(U4), + /* K9 */ be_nested_str_weak(cluster), + /* K10 */ be_const_int(2), + /* K11 */ be_nested_str_weak(command), + }), + be_str_weak(to_TLV), + &be_const_str_solidified, + ( &(const binstruction[20]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x88040301, // 0001 GETMBR R1 R1 K1 + 0x8C080302, // 0002 GETMET R2 R1 K2 + 0x7C080200, // 0003 CALL R2 1 + 0x8C0C0503, // 0004 GETMET R3 R2 K3 + 0x58140004, // 0005 LDCONST R5 K4 + 0x88180305, // 0006 GETMBR R6 R1 K5 + 0x881C0106, // 0007 GETMBR R7 R0 K6 + 0x7C0C0800, // 0008 CALL R3 4 + 0x8C0C0503, // 0009 GETMET R3 R2 K3 + 0x58140007, // 000A LDCONST R5 K7 + 0x88180308, // 000B GETMBR R6 R1 K8 + 0x881C0109, // 000C GETMBR R7 R0 K9 + 0x7C0C0800, // 000D CALL R3 4 + 0x8C0C0503, // 000E GETMET R3 R2 K3 + 0x5814000A, // 000F LDCONST R5 K10 + 0x88180308, // 0010 GETMBR R6 R1 K8 + 0x881C010B, // 0011 GETMBR R7 R0 K11 + 0x7C0C0800, // 0012 CALL R3 4 + 0x80040400, // 0013 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_CommandPathIB +********************************************************************/ +extern const bclass be_class_Matter_IM_base; +be_local_class(Matter_CommandPathIB, + 3, + &be_class_Matter_IM_base, + be_nested_map(5, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(endpoint, -1), be_const_var(0) }, + { be_const_key_weak(from_TLV, 0), be_const_closure(Matter_CommandPathIB_from_TLV_closure) }, + { be_const_key_weak(cluster, -1), be_const_var(1) }, + { be_const_key_weak(command, 1), be_const_var(2) }, + { be_const_key_weak(to_TLV, -1), be_const_closure(Matter_CommandPathIB_to_TLV_closure) }, + })), + be_str_weak(Matter_CommandPathIB) +); +/*******************************************************************/ + +void be_load_Matter_CommandPathIB_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_CommandPathIB); + be_setglobal(vm, "Matter_CommandPathIB"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_CommandDataIB; + +/******************************************************************** +** Solidified function: to_TLV +********************************************************************/ +be_local_closure(Matter_CommandDataIB_to_TLV, /* name */ + be_nested_proto( + 7, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(TLV), + /* K2 */ be_nested_str_weak(Matter_TLV_struct), + /* K3 */ be_nested_str_weak(add_obj), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str_weak(command_path), + /* K6 */ be_const_int(1), + /* K7 */ be_nested_str_weak(command_fields), + }), + be_str_weak(to_TLV), + &be_const_str_solidified, + ( &(const binstruction[13]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x88040301, // 0001 GETMBR R1 R1 K1 + 0x8C080302, // 0002 GETMET R2 R1 K2 + 0x7C080200, // 0003 CALL R2 1 + 0x8C0C0503, // 0004 GETMET R3 R2 K3 + 0x58140004, // 0005 LDCONST R5 K4 + 0x88180105, // 0006 GETMBR R6 R0 K5 + 0x7C0C0600, // 0007 CALL R3 3 + 0x8C0C0503, // 0008 GETMET R3 R2 K3 + 0x58140006, // 0009 LDCONST R5 K6 + 0x88180107, // 000A GETMBR R6 R0 K7 + 0x7C0C0600, // 000B CALL R3 3 + 0x80040400, // 000C RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: from_TLV +********************************************************************/ +be_local_closure(Matter_CommandDataIB_from_TLV, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(command_path), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(CommandPathIB), + /* K3 */ be_nested_str_weak(from_TLV), + /* K4 */ be_nested_str_weak(findsub), + /* K5 */ be_const_int(0), + /* K6 */ be_nested_str_weak(command_fields), + /* K7 */ be_const_int(1), + }), + be_str_weak(from_TLV), + &be_const_str_solidified, + ( &(const binstruction[19]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0001, // 0002 JMPF R2 #0005 + 0x4C080000, // 0003 LDNIL R2 + 0x80040400, // 0004 RET 1 R2 + 0xB80A0200, // 0005 GETNGBL R2 K1 + 0x8C080502, // 0006 GETMET R2 R2 K2 + 0x7C080200, // 0007 CALL R2 1 + 0x8C080503, // 0008 GETMET R2 R2 K3 + 0x8C100304, // 0009 GETMET R4 R1 K4 + 0x58180005, // 000A LDCONST R6 K5 + 0x7C100400, // 000B CALL R4 2 + 0x7C080400, // 000C CALL R2 2 + 0x90020002, // 000D SETMBR R0 K0 R2 + 0x8C080304, // 000E GETMET R2 R1 K4 + 0x58100007, // 000F LDCONST R4 K7 + 0x7C080400, // 0010 CALL R2 2 + 0x90020C02, // 0011 SETMBR R0 K6 R2 + 0x80040000, // 0012 RET 1 R0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_CommandDataIB +********************************************************************/ +extern const bclass be_class_Matter_IM_base; +be_local_class(Matter_CommandDataIB, + 2, + &be_class_Matter_IM_base, + be_nested_map(4, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(command_path, 3), be_const_var(0) }, + { be_const_key_weak(to_TLV, -1), be_const_closure(Matter_CommandDataIB_to_TLV_closure) }, + { be_const_key_weak(command_fields, -1), be_const_var(1) }, + { be_const_key_weak(from_TLV, -1), be_const_closure(Matter_CommandDataIB_from_TLV_closure) }, + })), + be_str_weak(Matter_CommandDataIB) +); +/*******************************************************************/ + +void be_load_Matter_CommandDataIB_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_CommandDataIB); + be_setglobal(vm, "Matter_CommandDataIB"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_InvokeResponseIB; + +/******************************************************************** +** Solidified function: from_TLV +********************************************************************/ +be_local_closure(Matter_InvokeResponseIB_from_TLV, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 9]) { /* constants */ + /* K0 */ be_nested_str_weak(command), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(CommandDataIB), + /* K3 */ be_nested_str_weak(from_TLV), + /* K4 */ be_nested_str_weak(findsub), + /* K5 */ be_const_int(0), + /* K6 */ be_nested_str_weak(status), + /* K7 */ be_nested_str_weak(CommandStatusIB), + /* K8 */ be_const_int(1), + }), + be_str_weak(from_TLV), + &be_const_str_solidified, + ( &(const binstruction[24]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0001, // 0002 JMPF R2 #0005 + 0x4C080000, // 0003 LDNIL R2 + 0x80040400, // 0004 RET 1 R2 + 0xB80A0200, // 0005 GETNGBL R2 K1 + 0x8C080502, // 0006 GETMET R2 R2 K2 + 0x7C080200, // 0007 CALL R2 1 + 0x8C080503, // 0008 GETMET R2 R2 K3 + 0x8C100304, // 0009 GETMET R4 R1 K4 + 0x58180005, // 000A LDCONST R6 K5 + 0x7C100400, // 000B CALL R4 2 + 0x7C080400, // 000C CALL R2 2 + 0x90020002, // 000D SETMBR R0 K0 R2 + 0xB80A0200, // 000E GETNGBL R2 K1 + 0x8C080507, // 000F GETMET R2 R2 K7 + 0x7C080200, // 0010 CALL R2 1 + 0x8C080503, // 0011 GETMET R2 R2 K3 + 0x8C100304, // 0012 GETMET R4 R1 K4 + 0x58180008, // 0013 LDCONST R6 K8 + 0x7C100400, // 0014 CALL R4 2 + 0x7C080400, // 0015 CALL R2 2 + 0x90020C02, // 0016 SETMBR R0 K6 R2 + 0x80040000, // 0017 RET 1 R0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: to_TLV +********************************************************************/ +be_local_closure(Matter_InvokeResponseIB_to_TLV, /* name */ + be_nested_proto( + 7, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(TLV), + /* K2 */ be_nested_str_weak(Matter_TLV_struct), + /* K3 */ be_nested_str_weak(add_obj), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str_weak(command), + /* K6 */ be_const_int(1), + /* K7 */ be_nested_str_weak(status), + }), + be_str_weak(to_TLV), + &be_const_str_solidified, + ( &(const binstruction[13]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x88040301, // 0001 GETMBR R1 R1 K1 + 0x8C080302, // 0002 GETMET R2 R1 K2 + 0x7C080200, // 0003 CALL R2 1 + 0x8C0C0503, // 0004 GETMET R3 R2 K3 + 0x58140004, // 0005 LDCONST R5 K4 + 0x88180105, // 0006 GETMBR R6 R0 K5 + 0x7C0C0600, // 0007 CALL R3 3 + 0x8C0C0503, // 0008 GETMET R3 R2 K3 + 0x58140006, // 0009 LDCONST R5 K6 + 0x88180107, // 000A GETMBR R6 R0 K7 + 0x7C0C0600, // 000B CALL R3 3 + 0x80040400, // 000C RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_InvokeResponseIB +********************************************************************/ +extern const bclass be_class_Matter_IM_base; +be_local_class(Matter_InvokeResponseIB, + 2, + &be_class_Matter_IM_base, + be_nested_map(4, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(from_TLV, -1), be_const_closure(Matter_InvokeResponseIB_from_TLV_closure) }, + { be_const_key_weak(to_TLV, -1), be_const_closure(Matter_InvokeResponseIB_to_TLV_closure) }, + { be_const_key_weak(command, -1), be_const_var(0) }, + { be_const_key_weak(status, -1), be_const_var(1) }, + })), + be_str_weak(Matter_InvokeResponseIB) +); +/*******************************************************************/ + +void be_load_Matter_InvokeResponseIB_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_InvokeResponseIB); + be_setglobal(vm, "Matter_InvokeResponseIB"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_CommandStatusIB; + +/******************************************************************** +** Solidified function: to_TLV +********************************************************************/ +be_local_closure(Matter_CommandStatusIB_to_TLV, /* name */ + be_nested_proto( + 7, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(TLV), + /* K2 */ be_nested_str_weak(Matter_TLV_struct), + /* K3 */ be_nested_str_weak(add_obj), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str_weak(command_path), + /* K6 */ be_const_int(1), + /* K7 */ be_nested_str_weak(status), + }), + be_str_weak(to_TLV), + &be_const_str_solidified, + ( &(const binstruction[13]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x88040301, // 0001 GETMBR R1 R1 K1 + 0x8C080302, // 0002 GETMET R2 R1 K2 + 0x7C080200, // 0003 CALL R2 1 + 0x8C0C0503, // 0004 GETMET R3 R2 K3 + 0x58140004, // 0005 LDCONST R5 K4 + 0x88180105, // 0006 GETMBR R6 R0 K5 + 0x7C0C0600, // 0007 CALL R3 3 + 0x8C0C0503, // 0008 GETMET R3 R2 K3 + 0x58140006, // 0009 LDCONST R5 K6 + 0x88180107, // 000A GETMBR R6 R0 K7 + 0x7C0C0600, // 000B CALL R3 3 + 0x80040400, // 000C RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: from_TLV +********************************************************************/ +be_local_closure(Matter_CommandStatusIB_from_TLV, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 9]) { /* constants */ + /* K0 */ be_nested_str_weak(command_path), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(CommandPathIB), + /* K3 */ be_nested_str_weak(from_TLV), + /* K4 */ be_nested_str_weak(findsub), + /* K5 */ be_const_int(0), + /* K6 */ be_nested_str_weak(status), + /* K7 */ be_nested_str_weak(StatusIB), + /* K8 */ be_const_int(1), + }), + be_str_weak(from_TLV), + &be_const_str_solidified, + ( &(const binstruction[24]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0001, // 0002 JMPF R2 #0005 + 0x4C080000, // 0003 LDNIL R2 + 0x80040400, // 0004 RET 1 R2 + 0xB80A0200, // 0005 GETNGBL R2 K1 + 0x8C080502, // 0006 GETMET R2 R2 K2 + 0x7C080200, // 0007 CALL R2 1 + 0x8C080503, // 0008 GETMET R2 R2 K3 + 0x8C100304, // 0009 GETMET R4 R1 K4 + 0x58180005, // 000A LDCONST R6 K5 + 0x7C100400, // 000B CALL R4 2 + 0x7C080400, // 000C CALL R2 2 + 0x90020002, // 000D SETMBR R0 K0 R2 + 0xB80A0200, // 000E GETNGBL R2 K1 + 0x8C080507, // 000F GETMET R2 R2 K7 + 0x7C080200, // 0010 CALL R2 1 + 0x8C080503, // 0011 GETMET R2 R2 K3 + 0x8C100304, // 0012 GETMET R4 R1 K4 + 0x58180008, // 0013 LDCONST R6 K8 + 0x7C100400, // 0014 CALL R4 2 + 0x7C080400, // 0015 CALL R2 2 + 0x90020C02, // 0016 SETMBR R0 K6 R2 + 0x80040000, // 0017 RET 1 R0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_CommandStatusIB +********************************************************************/ +extern const bclass be_class_Matter_IM_base; +be_local_class(Matter_CommandStatusIB, + 2, + &be_class_Matter_IM_base, + be_nested_map(4, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(command_path, 2), be_const_var(0) }, + { be_const_key_weak(to_TLV, -1), be_const_closure(Matter_CommandStatusIB_to_TLV_closure) }, + { be_const_key_weak(from_TLV, -1), be_const_closure(Matter_CommandStatusIB_from_TLV_closure) }, + { be_const_key_weak(status, -1), be_const_var(1) }, + })), + be_str_weak(Matter_CommandStatusIB) +); +/*******************************************************************/ + +void be_load_Matter_CommandStatusIB_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_CommandStatusIB); + be_setglobal(vm, "Matter_CommandStatusIB"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_EventStatusIB; + +/******************************************************************** +** Solidified function: from_TLV +********************************************************************/ +be_local_closure(Matter_EventStatusIB_from_TLV, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 9]) { /* constants */ + /* K0 */ be_nested_str_weak(path), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(EventPathIB), + /* K3 */ be_nested_str_weak(from_TLV), + /* K4 */ be_nested_str_weak(findsub), + /* K5 */ be_const_int(0), + /* K6 */ be_nested_str_weak(status), + /* K7 */ be_nested_str_weak(StatusIB), + /* K8 */ be_const_int(1), + }), + be_str_weak(from_TLV), + &be_const_str_solidified, + ( &(const binstruction[24]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0001, // 0002 JMPF R2 #0005 + 0x4C080000, // 0003 LDNIL R2 + 0x80040400, // 0004 RET 1 R2 + 0xB80A0200, // 0005 GETNGBL R2 K1 + 0x8C080502, // 0006 GETMET R2 R2 K2 + 0x7C080200, // 0007 CALL R2 1 + 0x8C080503, // 0008 GETMET R2 R2 K3 + 0x8C100304, // 0009 GETMET R4 R1 K4 + 0x58180005, // 000A LDCONST R6 K5 + 0x7C100400, // 000B CALL R4 2 + 0x7C080400, // 000C CALL R2 2 + 0x90020002, // 000D SETMBR R0 K0 R2 + 0xB80A0200, // 000E GETNGBL R2 K1 + 0x8C080507, // 000F GETMET R2 R2 K7 + 0x7C080200, // 0010 CALL R2 1 + 0x8C080503, // 0011 GETMET R2 R2 K3 + 0x8C100304, // 0012 GETMET R4 R1 K4 + 0x58180008, // 0013 LDCONST R6 K8 + 0x7C100400, // 0014 CALL R4 2 + 0x7C080400, // 0015 CALL R2 2 + 0x90020C02, // 0016 SETMBR R0 K6 R2 + 0x80040000, // 0017 RET 1 R0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: to_TLV +********************************************************************/ +be_local_closure(Matter_EventStatusIB_to_TLV, /* name */ + be_nested_proto( + 7, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(TLV), + /* K2 */ be_nested_str_weak(Matter_TLV_struct), + /* K3 */ be_nested_str_weak(add_obj), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str_weak(path), + /* K6 */ be_const_int(1), + /* K7 */ be_nested_str_weak(status), + }), + be_str_weak(to_TLV), + &be_const_str_solidified, + ( &(const binstruction[13]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x88040301, // 0001 GETMBR R1 R1 K1 + 0x8C080302, // 0002 GETMET R2 R1 K2 + 0x7C080200, // 0003 CALL R2 1 + 0x8C0C0503, // 0004 GETMET R3 R2 K3 + 0x58140004, // 0005 LDCONST R5 K4 + 0x88180105, // 0006 GETMBR R6 R0 K5 + 0x7C0C0600, // 0007 CALL R3 3 + 0x8C0C0503, // 0008 GETMET R3 R2 K3 + 0x58140006, // 0009 LDCONST R5 K6 + 0x88180107, // 000A GETMBR R6 R0 K7 + 0x7C0C0600, // 000B CALL R3 3 + 0x80040400, // 000C RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_EventStatusIB +********************************************************************/ +extern const bclass be_class_Matter_IM_base; +be_local_class(Matter_EventStatusIB, + 2, + &be_class_Matter_IM_base, + be_nested_map(4, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(from_TLV, -1), be_const_closure(Matter_EventStatusIB_from_TLV_closure) }, + { be_const_key_weak(to_TLV, -1), be_const_closure(Matter_EventStatusIB_to_TLV_closure) }, + { be_const_key_weak(path, -1), be_const_var(0) }, + { be_const_key_weak(status, -1), be_const_var(1) }, + })), + be_str_weak(Matter_EventStatusIB) +); +/*******************************************************************/ + +void be_load_Matter_EventStatusIB_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_EventStatusIB); + be_setglobal(vm, "Matter_EventStatusIB"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_AttributeStatusIB; + +/******************************************************************** +** Solidified function: from_TLV +********************************************************************/ +be_local_closure(Matter_AttributeStatusIB_from_TLV, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 9]) { /* constants */ + /* K0 */ be_nested_str_weak(path), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(AttributePathIB), + /* K3 */ be_nested_str_weak(from_TLV), + /* K4 */ be_nested_str_weak(findsub), + /* K5 */ be_const_int(0), + /* K6 */ be_nested_str_weak(status), + /* K7 */ be_nested_str_weak(StatusIB), + /* K8 */ be_const_int(1), + }), + be_str_weak(from_TLV), + &be_const_str_solidified, + ( &(const binstruction[24]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0001, // 0002 JMPF R2 #0005 + 0x4C080000, // 0003 LDNIL R2 + 0x80040400, // 0004 RET 1 R2 + 0xB80A0200, // 0005 GETNGBL R2 K1 + 0x8C080502, // 0006 GETMET R2 R2 K2 + 0x7C080200, // 0007 CALL R2 1 + 0x8C080503, // 0008 GETMET R2 R2 K3 + 0x8C100304, // 0009 GETMET R4 R1 K4 + 0x58180005, // 000A LDCONST R6 K5 + 0x7C100400, // 000B CALL R4 2 + 0x7C080400, // 000C CALL R2 2 + 0x90020002, // 000D SETMBR R0 K0 R2 + 0xB80A0200, // 000E GETNGBL R2 K1 + 0x8C080507, // 000F GETMET R2 R2 K7 + 0x7C080200, // 0010 CALL R2 1 + 0x8C080503, // 0011 GETMET R2 R2 K3 + 0x8C100304, // 0012 GETMET R4 R1 K4 + 0x58180008, // 0013 LDCONST R6 K8 + 0x7C100400, // 0014 CALL R4 2 + 0x7C080400, // 0015 CALL R2 2 + 0x90020C02, // 0016 SETMBR R0 K6 R2 + 0x80040000, // 0017 RET 1 R0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: to_TLV +********************************************************************/ +be_local_closure(Matter_AttributeStatusIB_to_TLV, /* name */ + be_nested_proto( + 7, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(TLV), + /* K2 */ be_nested_str_weak(Matter_TLV_struct), + /* K3 */ be_nested_str_weak(add_obj), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str_weak(path), + /* K6 */ be_const_int(1), + /* K7 */ be_nested_str_weak(status), + }), + be_str_weak(to_TLV), + &be_const_str_solidified, + ( &(const binstruction[13]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x88040301, // 0001 GETMBR R1 R1 K1 + 0x8C080302, // 0002 GETMET R2 R1 K2 + 0x7C080200, // 0003 CALL R2 1 + 0x8C0C0503, // 0004 GETMET R3 R2 K3 + 0x58140004, // 0005 LDCONST R5 K4 + 0x88180105, // 0006 GETMBR R6 R0 K5 + 0x7C0C0600, // 0007 CALL R3 3 + 0x8C0C0503, // 0008 GETMET R3 R2 K3 + 0x58140006, // 0009 LDCONST R5 K6 + 0x88180107, // 000A GETMBR R6 R0 K7 + 0x7C0C0600, // 000B CALL R3 3 + 0x80040400, // 000C RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_AttributeStatusIB +********************************************************************/ +extern const bclass be_class_Matter_IM_base; +be_local_class(Matter_AttributeStatusIB, + 2, + &be_class_Matter_IM_base, + be_nested_map(4, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(from_TLV, -1), be_const_closure(Matter_AttributeStatusIB_from_TLV_closure) }, + { be_const_key_weak(to_TLV, -1), be_const_closure(Matter_AttributeStatusIB_to_TLV_closure) }, + { be_const_key_weak(path, -1), be_const_var(0) }, + { be_const_key_weak(status, -1), be_const_var(1) }, + })), + be_str_weak(Matter_AttributeStatusIB) +); +/*******************************************************************/ + +void be_load_Matter_AttributeStatusIB_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_AttributeStatusIB); + be_setglobal(vm, "Matter_AttributeStatusIB"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_StatusIB; + +/******************************************************************** +** Solidified function: to_TLV +********************************************************************/ +be_local_closure(Matter_StatusIB_to_TLV, /* name */ + be_nested_proto( + 8, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 9]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(TLV), + /* K2 */ be_nested_str_weak(Matter_TLV_list), + /* K3 */ be_nested_str_weak(add_TLV), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str_weak(U2), + /* K6 */ be_nested_str_weak(status), + /* K7 */ be_const_int(1), + /* K8 */ be_nested_str_weak(cluster_status), + }), + be_str_weak(to_TLV), + &be_const_str_solidified, + ( &(const binstruction[15]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x88040301, // 0001 GETMBR R1 R1 K1 + 0x8C080302, // 0002 GETMET R2 R1 K2 + 0x7C080200, // 0003 CALL R2 1 + 0x8C0C0503, // 0004 GETMET R3 R2 K3 + 0x58140004, // 0005 LDCONST R5 K4 + 0x88180305, // 0006 GETMBR R6 R1 K5 + 0x881C0106, // 0007 GETMBR R7 R0 K6 + 0x7C0C0800, // 0008 CALL R3 4 + 0x8C0C0503, // 0009 GETMET R3 R2 K3 + 0x58140007, // 000A LDCONST R5 K7 + 0x88180305, // 000B GETMBR R6 R1 K5 + 0x881C0108, // 000C GETMBR R7 R0 K8 + 0x7C0C0800, // 000D CALL R3 4 + 0x80040400, // 000E RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: from_TLV +********************************************************************/ +be_local_closure(Matter_StatusIB_from_TLV, /* name */ + be_nested_proto( + 5, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(status), + /* K1 */ be_nested_str_weak(findsubval), + /* K2 */ be_const_int(0), + /* K3 */ be_nested_str_weak(cluster_status), + /* K4 */ be_const_int(1), + }), + be_str_weak(from_TLV), + &be_const_str_solidified, + ( &(const binstruction[14]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0001, // 0002 JMPF R2 #0005 + 0x4C080000, // 0003 LDNIL R2 + 0x80040400, // 0004 RET 1 R2 + 0x8C080301, // 0005 GETMET R2 R1 K1 + 0x58100002, // 0006 LDCONST R4 K2 + 0x7C080400, // 0007 CALL R2 2 + 0x90020002, // 0008 SETMBR R0 K0 R2 + 0x8C080301, // 0009 GETMET R2 R1 K1 + 0x58100004, // 000A LDCONST R4 K4 + 0x7C080400, // 000B CALL R2 2 + 0x90020602, // 000C SETMBR R0 K3 R2 + 0x80040000, // 000D RET 1 R0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_StatusIB +********************************************************************/ +extern const bclass be_class_Matter_IM_base; +be_local_class(Matter_StatusIB, + 2, + &be_class_Matter_IM_base, + be_nested_map(4, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(cluster_status, 2), be_const_var(1) }, + { be_const_key_weak(to_TLV, -1), be_const_closure(Matter_StatusIB_to_TLV_closure) }, + { be_const_key_weak(from_TLV, -1), be_const_closure(Matter_StatusIB_from_TLV_closure) }, + { be_const_key_weak(status, -1), be_const_var(0) }, + })), + be_str_weak(Matter_StatusIB) +); +/*******************************************************************/ + +void be_load_Matter_StatusIB_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_StatusIB); + be_setglobal(vm, "Matter_StatusIB"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_StatusResponseMessage; + +/******************************************************************** +** Solidified function: from_TLV +********************************************************************/ +be_local_closure(Matter_StatusResponseMessage_from_TLV, /* name */ + be_nested_proto( + 5, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(status), + /* K1 */ be_nested_str_weak(findsubval), + /* K2 */ be_const_int(0), + }), + be_str_weak(from_TLV), + &be_const_str_solidified, + ( &(const binstruction[10]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0001, // 0002 JMPF R2 #0005 + 0x4C080000, // 0003 LDNIL R2 + 0x80040400, // 0004 RET 1 R2 + 0x8C080301, // 0005 GETMET R2 R1 K1 + 0x58100002, // 0006 LDCONST R4 K2 + 0x7C080400, // 0007 CALL R2 2 + 0x90020002, // 0008 SETMBR R0 K0 R2 + 0x80040000, // 0009 RET 1 R0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: to_TLV +********************************************************************/ +be_local_closure(Matter_StatusResponseMessage_to_TLV, /* name */ + be_nested_proto( + 8, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 9]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(TLV), + /* K2 */ be_nested_str_weak(Matter_TLV_struct), + /* K3 */ be_nested_str_weak(add_TLV), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str_weak(U4), + /* K6 */ be_nested_str_weak(status), + /* K7 */ be_nested_str_weak(U1), + /* K8 */ be_nested_str_weak(InteractionModelRevision), + }), + be_str_weak(to_TLV), + &be_const_str_solidified, + ( &(const binstruction[15]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x88040301, // 0001 GETMBR R1 R1 K1 + 0x8C080302, // 0002 GETMET R2 R1 K2 + 0x7C080200, // 0003 CALL R2 1 + 0x8C0C0503, // 0004 GETMET R3 R2 K3 + 0x58140004, // 0005 LDCONST R5 K4 + 0x88180305, // 0006 GETMBR R6 R1 K5 + 0x881C0106, // 0007 GETMBR R7 R0 K6 + 0x7C0C0800, // 0008 CALL R3 4 + 0x8C0C0503, // 0009 GETMET R3 R2 K3 + 0x541600FE, // 000A LDINT R5 255 + 0x88180307, // 000B GETMBR R6 R1 K7 + 0x881C0108, // 000C GETMBR R7 R0 K8 + 0x7C0C0800, // 000D CALL R3 4 + 0x80040400, // 000E RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_StatusResponseMessage +********************************************************************/ +extern const bclass be_class_Matter_IM_Message_base; +be_local_class(Matter_StatusResponseMessage, + 1, + &be_class_Matter_IM_Message_base, + be_nested_map(3, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(from_TLV, -1), be_const_closure(Matter_StatusResponseMessage_from_TLV_closure) }, + { be_const_key_weak(to_TLV, 2), be_const_closure(Matter_StatusResponseMessage_to_TLV_closure) }, + { be_const_key_weak(status, -1), be_const_var(0) }, + })), + be_str_weak(Matter_StatusResponseMessage) +); +/*******************************************************************/ + +void be_load_Matter_StatusResponseMessage_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_StatusResponseMessage); + be_setglobal(vm, "Matter_StatusResponseMessage"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_ReadRequestMessage; + +/******************************************************************** +** Solidified function: from_TLV +********************************************************************/ +be_local_closure(Matter_ReadRequestMessage_from_TLV, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[16]) { /* constants */ + /* K0 */ be_nested_str_weak(attributes_requests), + /* K1 */ be_nested_str_weak(from_TLV_array), + /* K2 */ be_nested_str_weak(findsubval), + /* K3 */ be_const_int(0), + /* K4 */ be_nested_str_weak(matter), + /* K5 */ be_nested_str_weak(AttributePathIB), + /* K6 */ be_nested_str_weak(event_requests), + /* K7 */ be_const_int(1), + /* K8 */ be_nested_str_weak(EventPathIB), + /* K9 */ be_nested_str_weak(event_filters), + /* K10 */ be_const_int(2), + /* K11 */ be_nested_str_weak(EventFilterIB), + /* K12 */ be_nested_str_weak(fabric_filtered), + /* K13 */ be_const_int(3), + /* K14 */ be_nested_str_weak(data_version_filters), + /* K15 */ be_nested_str_weak(DataVersionFilterIB), + }), + be_str_weak(from_TLV), + &be_const_str_solidified, + ( &(const binstruction[42]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0001, // 0002 JMPF R2 #0005 + 0x4C080000, // 0003 LDNIL R2 + 0x80040400, // 0004 RET 1 R2 + 0x8C080101, // 0005 GETMET R2 R0 K1 + 0x8C100302, // 0006 GETMET R4 R1 K2 + 0x58180003, // 0007 LDCONST R6 K3 + 0x7C100400, // 0008 CALL R4 2 + 0xB8160800, // 0009 GETNGBL R5 K4 + 0x88140B05, // 000A GETMBR R5 R5 K5 + 0x7C080600, // 000B CALL R2 3 + 0x90020002, // 000C SETMBR R0 K0 R2 + 0x8C080101, // 000D GETMET R2 R0 K1 + 0x8C100302, // 000E GETMET R4 R1 K2 + 0x58180007, // 000F LDCONST R6 K7 + 0x7C100400, // 0010 CALL R4 2 + 0xB8160800, // 0011 GETNGBL R5 K4 + 0x88140B08, // 0012 GETMBR R5 R5 K8 + 0x7C080600, // 0013 CALL R2 3 + 0x90020C02, // 0014 SETMBR R0 K6 R2 + 0x8C080101, // 0015 GETMET R2 R0 K1 + 0x8C100302, // 0016 GETMET R4 R1 K2 + 0x5818000A, // 0017 LDCONST R6 K10 + 0x7C100400, // 0018 CALL R4 2 + 0xB8160800, // 0019 GETNGBL R5 K4 + 0x88140B0B, // 001A GETMBR R5 R5 K11 + 0x7C080600, // 001B CALL R2 3 + 0x90021202, // 001C SETMBR R0 K9 R2 + 0x8C080302, // 001D GETMET R2 R1 K2 + 0x5810000D, // 001E LDCONST R4 K13 + 0x7C080400, // 001F CALL R2 2 + 0x90021802, // 0020 SETMBR R0 K12 R2 + 0x8C080101, // 0021 GETMET R2 R0 K1 + 0x8C100302, // 0022 GETMET R4 R1 K2 + 0x541A0003, // 0023 LDINT R6 4 + 0x7C100400, // 0024 CALL R4 2 + 0xB8160800, // 0025 GETNGBL R5 K4 + 0x88140B0F, // 0026 GETMBR R5 R5 K15 + 0x7C080600, // 0027 CALL R2 3 + 0x90021C02, // 0028 SETMBR R0 K14 R2 + 0x80040000, // 0029 RET 1 R0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: to_TLV +********************************************************************/ +be_local_closure(Matter_ReadRequestMessage_to_TLV, /* name */ + be_nested_proto( + 8, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[17]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(TLV), + /* K2 */ be_nested_str_weak(Matter_TLV_struct), + /* K3 */ be_nested_str_weak(to_TLV_array), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str_weak(attributes_requests), + /* K6 */ be_const_int(1), + /* K7 */ be_nested_str_weak(event_requests), + /* K8 */ be_const_int(2), + /* K9 */ be_nested_str_weak(event_filters), + /* K10 */ be_nested_str_weak(add_TLV), + /* K11 */ be_const_int(3), + /* K12 */ be_nested_str_weak(BOOL), + /* K13 */ be_nested_str_weak(fabric_filtered), + /* K14 */ be_nested_str_weak(data_version_filters), + /* K15 */ be_nested_str_weak(U1), + /* K16 */ be_nested_str_weak(InteractionModelRevision), + }), + be_str_weak(to_TLV), + &be_const_str_solidified, + ( &(const binstruction[35]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x88040301, // 0001 GETMBR R1 R1 K1 + 0x8C080302, // 0002 GETMET R2 R1 K2 + 0x7C080200, // 0003 CALL R2 1 + 0x8C0C0103, // 0004 GETMET R3 R0 K3 + 0x5C140400, // 0005 MOVE R5 R2 + 0x58180004, // 0006 LDCONST R6 K4 + 0x881C0105, // 0007 GETMBR R7 R0 K5 + 0x7C0C0800, // 0008 CALL R3 4 + 0x8C0C0103, // 0009 GETMET R3 R0 K3 + 0x5C140400, // 000A MOVE R5 R2 + 0x58180006, // 000B LDCONST R6 K6 + 0x881C0107, // 000C GETMBR R7 R0 K7 + 0x7C0C0800, // 000D CALL R3 4 + 0x8C0C0103, // 000E GETMET R3 R0 K3 + 0x5C140400, // 000F MOVE R5 R2 + 0x58180008, // 0010 LDCONST R6 K8 + 0x881C0109, // 0011 GETMBR R7 R0 K9 + 0x7C0C0800, // 0012 CALL R3 4 + 0x8C0C050A, // 0013 GETMET R3 R2 K10 + 0x5814000B, // 0014 LDCONST R5 K11 + 0x8818030C, // 0015 GETMBR R6 R1 K12 + 0x881C010D, // 0016 GETMBR R7 R0 K13 + 0x7C0C0800, // 0017 CALL R3 4 + 0x8C0C0103, // 0018 GETMET R3 R0 K3 + 0x5C140400, // 0019 MOVE R5 R2 + 0x541A0003, // 001A LDINT R6 4 + 0x881C010E, // 001B GETMBR R7 R0 K14 + 0x7C0C0800, // 001C CALL R3 4 + 0x8C0C050A, // 001D GETMET R3 R2 K10 + 0x541600FE, // 001E LDINT R5 255 + 0x8818030F, // 001F GETMBR R6 R1 K15 + 0x881C0110, // 0020 GETMBR R7 R0 K16 + 0x7C0C0800, // 0021 CALL R3 4 + 0x80040400, // 0022 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_ReadRequestMessage +********************************************************************/ +extern const bclass be_class_Matter_IM_Message_base; +be_local_class(Matter_ReadRequestMessage, + 5, + &be_class_Matter_IM_Message_base, + be_nested_map(7, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(event_filters, -1), be_const_var(2) }, + { be_const_key_weak(fabric_filtered, 3), be_const_var(3) }, + { be_const_key_weak(to_TLV, -1), be_const_closure(Matter_ReadRequestMessage_to_TLV_closure) }, + { be_const_key_weak(from_TLV, -1), be_const_closure(Matter_ReadRequestMessage_from_TLV_closure) }, + { be_const_key_weak(data_version_filters, -1), be_const_var(4) }, + { be_const_key_weak(attributes_requests, -1), be_const_var(0) }, + { be_const_key_weak(event_requests, 0), be_const_var(1) }, + })), + be_str_weak(Matter_ReadRequestMessage) +); +/*******************************************************************/ + +void be_load_Matter_ReadRequestMessage_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_ReadRequestMessage); + be_setglobal(vm, "Matter_ReadRequestMessage"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_ReportDataMessage; + +/******************************************************************** +** Solidified function: from_TLV +********************************************************************/ +be_local_closure(Matter_ReportDataMessage_from_TLV, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[14]) { /* constants */ + /* K0 */ be_nested_str_weak(subscription_id), + /* K1 */ be_nested_str_weak(findsubval), + /* K2 */ be_const_int(0), + /* K3 */ be_nested_str_weak(attribute_reports), + /* K4 */ be_nested_str_weak(from_TLV_array), + /* K5 */ be_const_int(1), + /* K6 */ be_nested_str_weak(matter), + /* K7 */ be_nested_str_weak(AttributeReportIB), + /* K8 */ be_nested_str_weak(event_reports), + /* K9 */ be_const_int(2), + /* K10 */ be_nested_str_weak(EventReportIB), + /* K11 */ be_nested_str_weak(more_chunked_messages), + /* K12 */ be_const_int(3), + /* K13 */ be_nested_str_weak(suppress_response), + }), + be_str_weak(from_TLV), + &be_const_str_solidified, + ( &(const binstruction[34]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0001, // 0002 JMPF R2 #0005 + 0x4C080000, // 0003 LDNIL R2 + 0x80040400, // 0004 RET 1 R2 + 0x8C080301, // 0005 GETMET R2 R1 K1 + 0x58100002, // 0006 LDCONST R4 K2 + 0x7C080400, // 0007 CALL R2 2 + 0x90020002, // 0008 SETMBR R0 K0 R2 + 0x8C080104, // 0009 GETMET R2 R0 K4 + 0x8C100301, // 000A GETMET R4 R1 K1 + 0x58180005, // 000B LDCONST R6 K5 + 0x7C100400, // 000C CALL R4 2 + 0xB8160C00, // 000D GETNGBL R5 K6 + 0x88140B07, // 000E GETMBR R5 R5 K7 + 0x7C080600, // 000F CALL R2 3 + 0x90020602, // 0010 SETMBR R0 K3 R2 + 0x8C080104, // 0011 GETMET R2 R0 K4 + 0x8C100301, // 0012 GETMET R4 R1 K1 + 0x58180009, // 0013 LDCONST R6 K9 + 0x7C100400, // 0014 CALL R4 2 + 0xB8160C00, // 0015 GETNGBL R5 K6 + 0x88140B0A, // 0016 GETMBR R5 R5 K10 + 0x7C080600, // 0017 CALL R2 3 + 0x90021002, // 0018 SETMBR R0 K8 R2 + 0x8C080301, // 0019 GETMET R2 R1 K1 + 0x5810000C, // 001A LDCONST R4 K12 + 0x7C080400, // 001B CALL R2 2 + 0x90021602, // 001C SETMBR R0 K11 R2 + 0x8C080301, // 001D GETMET R2 R1 K1 + 0x54120003, // 001E LDINT R4 4 + 0x7C080400, // 001F CALL R2 2 + 0x90021A02, // 0020 SETMBR R0 K13 R2 + 0x80040000, // 0021 RET 1 R0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: to_TLV +********************************************************************/ +be_local_closure(Matter_ReportDataMessage_to_TLV, /* name */ + be_nested_proto( + 8, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[18]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(TLV), + /* K2 */ be_nested_str_weak(Matter_TLV_struct), + /* K3 */ be_nested_str_weak(add_TLV), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str_weak(U4), + /* K6 */ be_nested_str_weak(subscription_id), + /* K7 */ be_nested_str_weak(to_TLV_array), + /* K8 */ be_const_int(1), + /* K9 */ be_nested_str_weak(attribute_reports), + /* K10 */ be_const_int(2), + /* K11 */ be_nested_str_weak(event_reports), + /* K12 */ be_const_int(3), + /* K13 */ be_nested_str_weak(BOOL), + /* K14 */ be_nested_str_weak(more_chunked_messages), + /* K15 */ be_nested_str_weak(suppress_response), + /* K16 */ be_nested_str_weak(U1), + /* K17 */ be_nested_str_weak(InteractionModelRevision), + }), + be_str_weak(to_TLV), + &be_const_str_solidified, + ( &(const binstruction[35]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x88040301, // 0001 GETMBR R1 R1 K1 + 0x8C080302, // 0002 GETMET R2 R1 K2 + 0x7C080200, // 0003 CALL R2 1 + 0x8C0C0503, // 0004 GETMET R3 R2 K3 + 0x58140004, // 0005 LDCONST R5 K4 + 0x88180305, // 0006 GETMBR R6 R1 K5 + 0x881C0106, // 0007 GETMBR R7 R0 K6 + 0x7C0C0800, // 0008 CALL R3 4 + 0x8C0C0107, // 0009 GETMET R3 R0 K7 + 0x5C140400, // 000A MOVE R5 R2 + 0x58180008, // 000B LDCONST R6 K8 + 0x881C0109, // 000C GETMBR R7 R0 K9 + 0x7C0C0800, // 000D CALL R3 4 + 0x8C0C0107, // 000E GETMET R3 R0 K7 + 0x5C140400, // 000F MOVE R5 R2 + 0x5818000A, // 0010 LDCONST R6 K10 + 0x881C010B, // 0011 GETMBR R7 R0 K11 + 0x7C0C0800, // 0012 CALL R3 4 + 0x8C0C0503, // 0013 GETMET R3 R2 K3 + 0x5814000C, // 0014 LDCONST R5 K12 + 0x8818030D, // 0015 GETMBR R6 R1 K13 + 0x881C010E, // 0016 GETMBR R7 R0 K14 + 0x7C0C0800, // 0017 CALL R3 4 + 0x8C0C0503, // 0018 GETMET R3 R2 K3 + 0x54160003, // 0019 LDINT R5 4 + 0x8818030D, // 001A GETMBR R6 R1 K13 + 0x881C010F, // 001B GETMBR R7 R0 K15 + 0x7C0C0800, // 001C CALL R3 4 + 0x8C0C0503, // 001D GETMET R3 R2 K3 + 0x541600FE, // 001E LDINT R5 255 + 0x88180310, // 001F GETMBR R6 R1 K16 + 0x881C0111, // 0020 GETMBR R7 R0 K17 + 0x7C0C0800, // 0021 CALL R3 4 + 0x80040400, // 0022 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_ReportDataMessage +********************************************************************/ +extern const bclass be_class_Matter_IM_Message_base; +be_local_class(Matter_ReportDataMessage, + 5, + &be_class_Matter_IM_Message_base, + be_nested_map(7, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(attribute_reports, -1), be_const_var(1) }, + { be_const_key_weak(from_TLV, -1), be_const_closure(Matter_ReportDataMessage_from_TLV_closure) }, + { be_const_key_weak(to_TLV, -1), be_const_closure(Matter_ReportDataMessage_to_TLV_closure) }, + { be_const_key_weak(more_chunked_messages, -1), be_const_var(3) }, + { be_const_key_weak(event_reports, -1), be_const_var(2) }, + { be_const_key_weak(suppress_response, -1), be_const_var(4) }, + { be_const_key_weak(subscription_id, 5), be_const_var(0) }, + })), + be_str_weak(Matter_ReportDataMessage) +); +/*******************************************************************/ + +void be_load_Matter_ReportDataMessage_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_ReportDataMessage); + be_setglobal(vm, "Matter_ReportDataMessage"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_SubscribeRequestMessage; + +/******************************************************************** +** Solidified function: from_TLV +********************************************************************/ +be_local_closure(Matter_SubscribeRequestMessage_from_TLV, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[19]) { /* constants */ + /* K0 */ be_nested_str_weak(keep_subscriptions), + /* K1 */ be_nested_str_weak(findsubval), + /* K2 */ be_const_int(0), + /* K3 */ be_nested_str_weak(min_interval_floor), + /* K4 */ be_const_int(1), + /* K5 */ be_nested_str_weak(max_interval_ceiling), + /* K6 */ be_const_int(2), + /* K7 */ be_nested_str_weak(attribute_requests), + /* K8 */ be_nested_str_weak(from_TLV_array), + /* K9 */ be_const_int(3), + /* K10 */ be_nested_str_weak(matter), + /* K11 */ be_nested_str_weak(AttributePathIB), + /* K12 */ be_nested_str_weak(event_requests), + /* K13 */ be_nested_str_weak(EventPathIB), + /* K14 */ be_nested_str_weak(event_filters), + /* K15 */ be_nested_str_weak(EventFilterIB), + /* K16 */ be_nested_str_weak(fabric_filtered), + /* K17 */ be_nested_str_weak(data_version_filters), + /* K18 */ be_nested_str_weak(DataVersionFilterIB), + }), + be_str_weak(from_TLV), + &be_const_str_solidified, + ( &(const binstruction[54]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0001, // 0002 JMPF R2 #0005 + 0x4C080000, // 0003 LDNIL R2 + 0x80040400, // 0004 RET 1 R2 + 0x8C080301, // 0005 GETMET R2 R1 K1 + 0x58100002, // 0006 LDCONST R4 K2 + 0x7C080400, // 0007 CALL R2 2 + 0x90020002, // 0008 SETMBR R0 K0 R2 + 0x8C080301, // 0009 GETMET R2 R1 K1 + 0x58100004, // 000A LDCONST R4 K4 + 0x7C080400, // 000B CALL R2 2 + 0x90020602, // 000C SETMBR R0 K3 R2 + 0x8C080301, // 000D GETMET R2 R1 K1 + 0x58100006, // 000E LDCONST R4 K6 + 0x7C080400, // 000F CALL R2 2 + 0x90020A02, // 0010 SETMBR R0 K5 R2 + 0x8C080108, // 0011 GETMET R2 R0 K8 + 0x8C100301, // 0012 GETMET R4 R1 K1 + 0x58180009, // 0013 LDCONST R6 K9 + 0x7C100400, // 0014 CALL R4 2 + 0xB8161400, // 0015 GETNGBL R5 K10 + 0x88140B0B, // 0016 GETMBR R5 R5 K11 + 0x7C080600, // 0017 CALL R2 3 + 0x90020E02, // 0018 SETMBR R0 K7 R2 + 0x8C080108, // 0019 GETMET R2 R0 K8 + 0x8C100301, // 001A GETMET R4 R1 K1 + 0x541A0003, // 001B LDINT R6 4 + 0x7C100400, // 001C CALL R4 2 + 0xB8161400, // 001D GETNGBL R5 K10 + 0x88140B0D, // 001E GETMBR R5 R5 K13 + 0x7C080600, // 001F CALL R2 3 + 0x90021802, // 0020 SETMBR R0 K12 R2 + 0x8C080108, // 0021 GETMET R2 R0 K8 + 0x8C100301, // 0022 GETMET R4 R1 K1 + 0x541A0004, // 0023 LDINT R6 5 + 0x7C100400, // 0024 CALL R4 2 + 0xB8161400, // 0025 GETNGBL R5 K10 + 0x88140B0F, // 0026 GETMBR R5 R5 K15 + 0x7C080600, // 0027 CALL R2 3 + 0x90021C02, // 0028 SETMBR R0 K14 R2 + 0x8C080301, // 0029 GETMET R2 R1 K1 + 0x54120006, // 002A LDINT R4 7 + 0x7C080400, // 002B CALL R2 2 + 0x90022002, // 002C SETMBR R0 K16 R2 + 0x8C080108, // 002D GETMET R2 R0 K8 + 0x8C100301, // 002E GETMET R4 R1 K1 + 0x541A0007, // 002F LDINT R6 8 + 0x7C100400, // 0030 CALL R4 2 + 0xB8161400, // 0031 GETNGBL R5 K10 + 0x88140B12, // 0032 GETMBR R5 R5 K18 + 0x7C080600, // 0033 CALL R2 3 + 0x90022202, // 0034 SETMBR R0 K17 R2 + 0x80040000, // 0035 RET 1 R0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: to_TLV +********************************************************************/ +be_local_closure(Matter_SubscribeRequestMessage_to_TLV, /* name */ + be_nested_proto( + 8, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[21]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(TLV), + /* K2 */ be_nested_str_weak(Matter_TLV_struct), + /* K3 */ be_nested_str_weak(add_TLV), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str_weak(BOOL), + /* K6 */ be_nested_str_weak(keep_subscriptions), + /* K7 */ be_const_int(1), + /* K8 */ be_nested_str_weak(U2), + /* K9 */ be_nested_str_weak(min_interval_floor), + /* K10 */ be_const_int(2), + /* K11 */ be_nested_str_weak(max_interval_ceiling), + /* K12 */ be_nested_str_weak(to_TLV_array), + /* K13 */ be_const_int(3), + /* K14 */ be_nested_str_weak(attribute_requests), + /* K15 */ be_nested_str_weak(event_requests), + /* K16 */ be_nested_str_weak(event_filters), + /* K17 */ be_nested_str_weak(fabric_filtered), + /* K18 */ be_nested_str_weak(data_version_filters), + /* K19 */ be_nested_str_weak(U1), + /* K20 */ be_nested_str_weak(InteractionModelRevision), + }), + be_str_weak(to_TLV), + &be_const_str_solidified, + ( &(const binstruction[50]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x88040301, // 0001 GETMBR R1 R1 K1 + 0x8C080302, // 0002 GETMET R2 R1 K2 + 0x7C080200, // 0003 CALL R2 1 + 0x8C0C0503, // 0004 GETMET R3 R2 K3 + 0x58140004, // 0005 LDCONST R5 K4 + 0x88180305, // 0006 GETMBR R6 R1 K5 + 0x881C0106, // 0007 GETMBR R7 R0 K6 + 0x7C0C0800, // 0008 CALL R3 4 + 0x8C0C0503, // 0009 GETMET R3 R2 K3 + 0x58140007, // 000A LDCONST R5 K7 + 0x88180308, // 000B GETMBR R6 R1 K8 + 0x881C0109, // 000C GETMBR R7 R0 K9 + 0x7C0C0800, // 000D CALL R3 4 + 0x8C0C0503, // 000E GETMET R3 R2 K3 + 0x5814000A, // 000F LDCONST R5 K10 + 0x88180308, // 0010 GETMBR R6 R1 K8 + 0x881C010B, // 0011 GETMBR R7 R0 K11 + 0x7C0C0800, // 0012 CALL R3 4 + 0x8C0C010C, // 0013 GETMET R3 R0 K12 + 0x5C140400, // 0014 MOVE R5 R2 + 0x5818000D, // 0015 LDCONST R6 K13 + 0x881C010E, // 0016 GETMBR R7 R0 K14 + 0x7C0C0800, // 0017 CALL R3 4 + 0x8C0C010C, // 0018 GETMET R3 R0 K12 + 0x5C140400, // 0019 MOVE R5 R2 + 0x541A0003, // 001A LDINT R6 4 + 0x881C010F, // 001B GETMBR R7 R0 K15 + 0x7C0C0800, // 001C CALL R3 4 + 0x8C0C010C, // 001D GETMET R3 R0 K12 + 0x5C140400, // 001E MOVE R5 R2 + 0x541A0004, // 001F LDINT R6 5 + 0x881C0110, // 0020 GETMBR R7 R0 K16 + 0x7C0C0800, // 0021 CALL R3 4 + 0x8C0C0503, // 0022 GETMET R3 R2 K3 + 0x54160006, // 0023 LDINT R5 7 + 0x88180305, // 0024 GETMBR R6 R1 K5 + 0x881C0111, // 0025 GETMBR R7 R0 K17 + 0x7C0C0800, // 0026 CALL R3 4 + 0x8C0C010C, // 0027 GETMET R3 R0 K12 + 0x5C140400, // 0028 MOVE R5 R2 + 0x541A0007, // 0029 LDINT R6 8 + 0x881C0112, // 002A GETMBR R7 R0 K18 + 0x7C0C0800, // 002B CALL R3 4 + 0x8C0C0503, // 002C GETMET R3 R2 K3 + 0x541600FE, // 002D LDINT R5 255 + 0x88180313, // 002E GETMBR R6 R1 K19 + 0x881C0114, // 002F GETMBR R7 R0 K20 + 0x7C0C0800, // 0030 CALL R3 4 + 0x80040400, // 0031 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_SubscribeRequestMessage +********************************************************************/ +extern const bclass be_class_Matter_IM_Message_base; +be_local_class(Matter_SubscribeRequestMessage, + 8, + &be_class_Matter_IM_Message_base, + be_nested_map(10, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(to_TLV, -1), be_const_closure(Matter_SubscribeRequestMessage_to_TLV_closure) }, + { be_const_key_weak(event_filters, -1), be_const_var(5) }, + { be_const_key_weak(event_requests, 6), be_const_var(4) }, + { be_const_key_weak(min_interval_floor, -1), be_const_var(1) }, + { be_const_key_weak(data_version_filters, -1), be_const_var(7) }, + { be_const_key_weak(max_interval_ceiling, -1), be_const_var(2) }, + { be_const_key_weak(attribute_requests, 7), be_const_var(3) }, + { be_const_key_weak(fabric_filtered, 3), be_const_var(6) }, + { be_const_key_weak(from_TLV, -1), be_const_closure(Matter_SubscribeRequestMessage_from_TLV_closure) }, + { be_const_key_weak(keep_subscriptions, 0), be_const_var(0) }, + })), + be_str_weak(Matter_SubscribeRequestMessage) +); +/*******************************************************************/ + +void be_load_Matter_SubscribeRequestMessage_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_SubscribeRequestMessage); + be_setglobal(vm, "Matter_SubscribeRequestMessage"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_SubscribeResponseMessage; + +/******************************************************************** +** Solidified function: to_TLV +********************************************************************/ +be_local_closure(Matter_SubscribeResponseMessage_to_TLV, /* name */ + be_nested_proto( + 8, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[12]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(TLV), + /* K2 */ be_nested_str_weak(Matter_TLV_struct), + /* K3 */ be_nested_str_weak(add_TLV), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str_weak(U4), + /* K6 */ be_nested_str_weak(subscription_id), + /* K7 */ be_const_int(2), + /* K8 */ be_nested_str_weak(U2), + /* K9 */ be_nested_str_weak(max_interval), + /* K10 */ be_nested_str_weak(U1), + /* K11 */ be_nested_str_weak(InteractionModelRevision), + }), + be_str_weak(to_TLV), + &be_const_str_solidified, + ( &(const binstruction[20]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x88040301, // 0001 GETMBR R1 R1 K1 + 0x8C080302, // 0002 GETMET R2 R1 K2 + 0x7C080200, // 0003 CALL R2 1 + 0x8C0C0503, // 0004 GETMET R3 R2 K3 + 0x58140004, // 0005 LDCONST R5 K4 + 0x88180305, // 0006 GETMBR R6 R1 K5 + 0x881C0106, // 0007 GETMBR R7 R0 K6 + 0x7C0C0800, // 0008 CALL R3 4 + 0x8C0C0503, // 0009 GETMET R3 R2 K3 + 0x58140007, // 000A LDCONST R5 K7 + 0x88180308, // 000B GETMBR R6 R1 K8 + 0x881C0109, // 000C GETMBR R7 R0 K9 + 0x7C0C0800, // 000D CALL R3 4 + 0x8C0C0503, // 000E GETMET R3 R2 K3 + 0x541600FE, // 000F LDINT R5 255 + 0x8818030A, // 0010 GETMBR R6 R1 K10 + 0x881C010B, // 0011 GETMBR R7 R0 K11 + 0x7C0C0800, // 0012 CALL R3 4 + 0x80040400, // 0013 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: from_TLV +********************************************************************/ +be_local_closure(Matter_SubscribeResponseMessage_from_TLV, /* name */ + be_nested_proto( + 5, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(subscription_id), + /* K1 */ be_nested_str_weak(findsubval), + /* K2 */ be_const_int(0), + /* K3 */ be_nested_str_weak(max_interval), + /* K4 */ be_const_int(2), + }), + be_str_weak(from_TLV), + &be_const_str_solidified, + ( &(const binstruction[14]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0001, // 0002 JMPF R2 #0005 + 0x4C080000, // 0003 LDNIL R2 + 0x80040400, // 0004 RET 1 R2 + 0x8C080301, // 0005 GETMET R2 R1 K1 + 0x58100002, // 0006 LDCONST R4 K2 + 0x7C080400, // 0007 CALL R2 2 + 0x90020002, // 0008 SETMBR R0 K0 R2 + 0x8C080301, // 0009 GETMET R2 R1 K1 + 0x58100004, // 000A LDCONST R4 K4 + 0x7C080400, // 000B CALL R2 2 + 0x90020602, // 000C SETMBR R0 K3 R2 + 0x80040000, // 000D RET 1 R0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_SubscribeResponseMessage +********************************************************************/ +extern const bclass be_class_Matter_IM_Message_base; +be_local_class(Matter_SubscribeResponseMessage, + 2, + &be_class_Matter_IM_Message_base, + be_nested_map(4, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(subscription_id, 2), be_const_var(0) }, + { be_const_key_weak(to_TLV, -1), be_const_closure(Matter_SubscribeResponseMessage_to_TLV_closure) }, + { be_const_key_weak(from_TLV, -1), be_const_closure(Matter_SubscribeResponseMessage_from_TLV_closure) }, + { be_const_key_weak(max_interval, -1), be_const_var(1) }, + })), + be_str_weak(Matter_SubscribeResponseMessage) +); +/*******************************************************************/ + +void be_load_Matter_SubscribeResponseMessage_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_SubscribeResponseMessage); + be_setglobal(vm, "Matter_SubscribeResponseMessage"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_WriteRequestMessage; + +/******************************************************************** +** Solidified function: to_TLV +********************************************************************/ +be_local_closure(Matter_WriteRequestMessage_to_TLV, /* name */ + be_nested_proto( + 8, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[16]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(TLV), + /* K2 */ be_nested_str_weak(Matter_TLV_struct), + /* K3 */ be_nested_str_weak(add_TLV), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str_weak(BOOL), + /* K6 */ be_nested_str_weak(suppress_response), + /* K7 */ be_const_int(1), + /* K8 */ be_nested_str_weak(timed_request), + /* K9 */ be_nested_str_weak(to_TLV_array), + /* K10 */ be_const_int(2), + /* K11 */ be_nested_str_weak(write_requests), + /* K12 */ be_const_int(3), + /* K13 */ be_nested_str_weak(more_chunked_messages), + /* K14 */ be_nested_str_weak(U1), + /* K15 */ be_nested_str_weak(InteractionModelRevision), + }), + be_str_weak(to_TLV), + &be_const_str_solidified, + ( &(const binstruction[30]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x88040301, // 0001 GETMBR R1 R1 K1 + 0x8C080302, // 0002 GETMET R2 R1 K2 + 0x7C080200, // 0003 CALL R2 1 + 0x8C0C0503, // 0004 GETMET R3 R2 K3 + 0x58140004, // 0005 LDCONST R5 K4 + 0x88180305, // 0006 GETMBR R6 R1 K5 + 0x881C0106, // 0007 GETMBR R7 R0 K6 + 0x7C0C0800, // 0008 CALL R3 4 + 0x8C0C0503, // 0009 GETMET R3 R2 K3 + 0x58140007, // 000A LDCONST R5 K7 + 0x88180305, // 000B GETMBR R6 R1 K5 + 0x881C0108, // 000C GETMBR R7 R0 K8 + 0x7C0C0800, // 000D CALL R3 4 + 0x8C0C0109, // 000E GETMET R3 R0 K9 + 0x5C140400, // 000F MOVE R5 R2 + 0x5818000A, // 0010 LDCONST R6 K10 + 0x881C010B, // 0011 GETMBR R7 R0 K11 + 0x7C0C0800, // 0012 CALL R3 4 + 0x8C0C0503, // 0013 GETMET R3 R2 K3 + 0x5814000C, // 0014 LDCONST R5 K12 + 0x88180305, // 0015 GETMBR R6 R1 K5 + 0x881C010D, // 0016 GETMBR R7 R0 K13 + 0x7C0C0800, // 0017 CALL R3 4 + 0x8C0C0503, // 0018 GETMET R3 R2 K3 + 0x541600FE, // 0019 LDINT R5 255 + 0x8818030E, // 001A GETMBR R6 R1 K14 + 0x881C010F, // 001B GETMBR R7 R0 K15 + 0x7C0C0800, // 001C CALL R3 4 + 0x80040400, // 001D RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: from_TLV +********************************************************************/ +be_local_closure(Matter_WriteRequestMessage_from_TLV, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[12]) { /* constants */ + /* K0 */ be_nested_str_weak(suppress_response), + /* K1 */ be_nested_str_weak(findsubval), + /* K2 */ be_const_int(0), + /* K3 */ be_nested_str_weak(timed_request), + /* K4 */ be_const_int(1), + /* K5 */ be_nested_str_weak(write_requests), + /* K6 */ be_nested_str_weak(from_TLV_array), + /* K7 */ be_const_int(2), + /* K8 */ be_nested_str_weak(matter), + /* K9 */ be_nested_str_weak(AttributeDataIB), + /* K10 */ be_nested_str_weak(more_chunked_messages), + /* K11 */ be_const_int(3), + }), + be_str_weak(from_TLV), + &be_const_str_solidified, + ( &(const binstruction[26]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0001, // 0002 JMPF R2 #0005 + 0x4C080000, // 0003 LDNIL R2 + 0x80040400, // 0004 RET 1 R2 + 0x8C080301, // 0005 GETMET R2 R1 K1 + 0x58100002, // 0006 LDCONST R4 K2 + 0x7C080400, // 0007 CALL R2 2 + 0x90020002, // 0008 SETMBR R0 K0 R2 + 0x8C080301, // 0009 GETMET R2 R1 K1 + 0x58100004, // 000A LDCONST R4 K4 + 0x7C080400, // 000B CALL R2 2 + 0x90020602, // 000C SETMBR R0 K3 R2 + 0x8C080106, // 000D GETMET R2 R0 K6 + 0x8C100301, // 000E GETMET R4 R1 K1 + 0x58180007, // 000F LDCONST R6 K7 + 0x7C100400, // 0010 CALL R4 2 + 0xB8161000, // 0011 GETNGBL R5 K8 + 0x88140B09, // 0012 GETMBR R5 R5 K9 + 0x7C080600, // 0013 CALL R2 3 + 0x90020A02, // 0014 SETMBR R0 K5 R2 + 0x8C080301, // 0015 GETMET R2 R1 K1 + 0x5810000B, // 0016 LDCONST R4 K11 + 0x7C080400, // 0017 CALL R2 2 + 0x90021402, // 0018 SETMBR R0 K10 R2 + 0x80040000, // 0019 RET 1 R0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_WriteRequestMessage +********************************************************************/ +extern const bclass be_class_Matter_IM_Message_base; +be_local_class(Matter_WriteRequestMessage, + 4, + &be_class_Matter_IM_Message_base, + be_nested_map(6, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(suppress_response, 5), be_const_var(0) }, + { be_const_key_weak(to_TLV, -1), be_const_closure(Matter_WriteRequestMessage_to_TLV_closure) }, + { be_const_key_weak(timed_request, -1), be_const_var(1) }, + { be_const_key_weak(write_requests, -1), be_const_var(2) }, + { be_const_key_weak(more_chunked_messages, -1), be_const_var(3) }, + { be_const_key_weak(from_TLV, -1), be_const_closure(Matter_WriteRequestMessage_from_TLV_closure) }, + })), + be_str_weak(Matter_WriteRequestMessage) +); +/*******************************************************************/ + +void be_load_Matter_WriteRequestMessage_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_WriteRequestMessage); + be_setglobal(vm, "Matter_WriteRequestMessage"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_WriteResponseMessage; + +/******************************************************************** +** Solidified function: from_TLV +********************************************************************/ +be_local_closure(Matter_WriteResponseMessage_from_TLV, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(write_requests), + /* K1 */ be_nested_str_weak(from_TLV_array), + /* K2 */ be_nested_str_weak(findsubval), + /* K3 */ be_const_int(0), + /* K4 */ be_nested_str_weak(matter), + /* K5 */ be_nested_str_weak(AttributeStatusIB), + }), + be_str_weak(from_TLV), + &be_const_str_solidified, + ( &(const binstruction[14]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0001, // 0002 JMPF R2 #0005 + 0x4C080000, // 0003 LDNIL R2 + 0x80040400, // 0004 RET 1 R2 + 0x8C080101, // 0005 GETMET R2 R0 K1 + 0x8C100302, // 0006 GETMET R4 R1 K2 + 0x58180003, // 0007 LDCONST R6 K3 + 0x7C100400, // 0008 CALL R4 2 + 0xB8160800, // 0009 GETNGBL R5 K4 + 0x88140B05, // 000A GETMBR R5 R5 K5 + 0x7C080600, // 000B CALL R2 3 + 0x90020002, // 000C SETMBR R0 K0 R2 + 0x80040000, // 000D RET 1 R0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: to_TLV +********************************************************************/ +be_local_closure(Matter_WriteResponseMessage_to_TLV, /* name */ + be_nested_proto( + 8, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 9]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(TLV), + /* K2 */ be_nested_str_weak(Matter_TLV_struct), + /* K3 */ be_nested_str_weak(to_TLV_array), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str_weak(write_responses), + /* K6 */ be_nested_str_weak(add_TLV), + /* K7 */ be_nested_str_weak(U1), + /* K8 */ be_nested_str_weak(InteractionModelRevision), + }), + be_str_weak(to_TLV), + &be_const_str_solidified, + ( &(const binstruction[15]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x88040301, // 0001 GETMBR R1 R1 K1 + 0x8C080302, // 0002 GETMET R2 R1 K2 + 0x7C080200, // 0003 CALL R2 1 + 0x8C0C0103, // 0004 GETMET R3 R0 K3 + 0x5C140400, // 0005 MOVE R5 R2 + 0x58180004, // 0006 LDCONST R6 K4 + 0x881C0105, // 0007 GETMBR R7 R0 K5 + 0x7C0C0800, // 0008 CALL R3 4 + 0x8C0C0506, // 0009 GETMET R3 R2 K6 + 0x541600FE, // 000A LDINT R5 255 + 0x88180307, // 000B GETMBR R6 R1 K7 + 0x881C0108, // 000C GETMBR R7 R0 K8 + 0x7C0C0800, // 000D CALL R3 4 + 0x80040400, // 000E RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_WriteResponseMessage +********************************************************************/ +extern const bclass be_class_Matter_IM_Message_base; +be_local_class(Matter_WriteResponseMessage, + 1, + &be_class_Matter_IM_Message_base, + be_nested_map(3, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(from_TLV, 2), be_const_closure(Matter_WriteResponseMessage_from_TLV_closure) }, + { be_const_key_weak(to_TLV, -1), be_const_closure(Matter_WriteResponseMessage_to_TLV_closure) }, + { be_const_key_weak(write_responses, -1), be_const_var(0) }, + })), + be_str_weak(Matter_WriteResponseMessage) +); +/*******************************************************************/ + +void be_load_Matter_WriteResponseMessage_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_WriteResponseMessage); + be_setglobal(vm, "Matter_WriteResponseMessage"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_TimedRequestMessage; + +/******************************************************************** +** Solidified function: from_TLV +********************************************************************/ +be_local_closure(Matter_TimedRequestMessage_from_TLV, /* name */ + be_nested_proto( + 5, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(timeout), + /* K1 */ be_nested_str_weak(findsubval), + /* K2 */ be_const_int(0), + }), + be_str_weak(from_TLV), + &be_const_str_solidified, + ( &(const binstruction[10]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0001, // 0002 JMPF R2 #0005 + 0x4C080000, // 0003 LDNIL R2 + 0x80040400, // 0004 RET 1 R2 + 0x8C080301, // 0005 GETMET R2 R1 K1 + 0x58100002, // 0006 LDCONST R4 K2 + 0x7C080400, // 0007 CALL R2 2 + 0x90020002, // 0008 SETMBR R0 K0 R2 + 0x80040000, // 0009 RET 1 R0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: to_TLV +********************************************************************/ +be_local_closure(Matter_TimedRequestMessage_to_TLV, /* name */ + be_nested_proto( + 8, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 9]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(TLV), + /* K2 */ be_nested_str_weak(Matter_TLV_struct), + /* K3 */ be_nested_str_weak(add_TLV), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str_weak(U2), + /* K6 */ be_nested_str_weak(timeout), + /* K7 */ be_nested_str_weak(U1), + /* K8 */ be_nested_str_weak(InteractionModelRevision), + }), + be_str_weak(to_TLV), + &be_const_str_solidified, + ( &(const binstruction[15]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x88040301, // 0001 GETMBR R1 R1 K1 + 0x8C080302, // 0002 GETMET R2 R1 K2 + 0x7C080200, // 0003 CALL R2 1 + 0x8C0C0503, // 0004 GETMET R3 R2 K3 + 0x58140004, // 0005 LDCONST R5 K4 + 0x88180305, // 0006 GETMBR R6 R1 K5 + 0x881C0106, // 0007 GETMBR R7 R0 K6 + 0x7C0C0800, // 0008 CALL R3 4 + 0x8C0C0503, // 0009 GETMET R3 R2 K3 + 0x541600FE, // 000A LDINT R5 255 + 0x88180307, // 000B GETMBR R6 R1 K7 + 0x881C0108, // 000C GETMBR R7 R0 K8 + 0x7C0C0800, // 000D CALL R3 4 + 0x80040400, // 000E RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_TimedRequestMessage +********************************************************************/ +extern const bclass be_class_Matter_IM_Message_base; +be_local_class(Matter_TimedRequestMessage, + 1, + &be_class_Matter_IM_Message_base, + be_nested_map(3, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(from_TLV, -1), be_const_closure(Matter_TimedRequestMessage_from_TLV_closure) }, + { be_const_key_weak(timeout, 2), be_const_var(0) }, + { be_const_key_weak(to_TLV, -1), be_const_closure(Matter_TimedRequestMessage_to_TLV_closure) }, + })), + be_str_weak(Matter_TimedRequestMessage) +); +/*******************************************************************/ + +void be_load_Matter_TimedRequestMessage_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_TimedRequestMessage); + be_setglobal(vm, "Matter_TimedRequestMessage"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_InvokeRequestMessage; + +/******************************************************************** +** Solidified function: from_TLV +********************************************************************/ +be_local_closure(Matter_InvokeRequestMessage_from_TLV, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[10]) { /* constants */ + /* K0 */ be_nested_str_weak(suppress_response), + /* K1 */ be_nested_str_weak(findsubval), + /* K2 */ be_const_int(0), + /* K3 */ be_nested_str_weak(timed_request), + /* K4 */ be_const_int(1), + /* K5 */ be_nested_str_weak(invoke_requests), + /* K6 */ be_nested_str_weak(from_TLV_array), + /* K7 */ be_const_int(2), + /* K8 */ be_nested_str_weak(matter), + /* K9 */ be_nested_str_weak(CommandDataIB), + }), + be_str_weak(from_TLV), + &be_const_str_solidified, + ( &(const binstruction[22]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0001, // 0002 JMPF R2 #0005 + 0x4C080000, // 0003 LDNIL R2 + 0x80040400, // 0004 RET 1 R2 + 0x8C080301, // 0005 GETMET R2 R1 K1 + 0x58100002, // 0006 LDCONST R4 K2 + 0x7C080400, // 0007 CALL R2 2 + 0x90020002, // 0008 SETMBR R0 K0 R2 + 0x8C080301, // 0009 GETMET R2 R1 K1 + 0x58100004, // 000A LDCONST R4 K4 + 0x7C080400, // 000B CALL R2 2 + 0x90020602, // 000C SETMBR R0 K3 R2 + 0x8C080106, // 000D GETMET R2 R0 K6 + 0x8C100301, // 000E GETMET R4 R1 K1 + 0x58180007, // 000F LDCONST R6 K7 + 0x7C100400, // 0010 CALL R4 2 + 0xB8161000, // 0011 GETNGBL R5 K8 + 0x88140B09, // 0012 GETMBR R5 R5 K9 + 0x7C080600, // 0013 CALL R2 3 + 0x90020A02, // 0014 SETMBR R0 K5 R2 + 0x80040000, // 0015 RET 1 R0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: to_TLV +********************************************************************/ +be_local_closure(Matter_InvokeRequestMessage_to_TLV, /* name */ + be_nested_proto( + 8, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[14]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(TLV), + /* K2 */ be_nested_str_weak(Matter_TLV_struct), + /* K3 */ be_nested_str_weak(add_TLV), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str_weak(BOOL), + /* K6 */ be_nested_str_weak(suppress_response), + /* K7 */ be_const_int(1), + /* K8 */ be_nested_str_weak(timed_request), + /* K9 */ be_nested_str_weak(to_TLV_array), + /* K10 */ be_const_int(2), + /* K11 */ be_nested_str_weak(invoke_requests), + /* K12 */ be_nested_str_weak(U1), + /* K13 */ be_nested_str_weak(InteractionModelRevision), + }), + be_str_weak(to_TLV), + &be_const_str_solidified, + ( &(const binstruction[25]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x88040301, // 0001 GETMBR R1 R1 K1 + 0x8C080302, // 0002 GETMET R2 R1 K2 + 0x7C080200, // 0003 CALL R2 1 + 0x8C0C0503, // 0004 GETMET R3 R2 K3 + 0x58140004, // 0005 LDCONST R5 K4 + 0x88180305, // 0006 GETMBR R6 R1 K5 + 0x881C0106, // 0007 GETMBR R7 R0 K6 + 0x7C0C0800, // 0008 CALL R3 4 + 0x8C0C0503, // 0009 GETMET R3 R2 K3 + 0x58140007, // 000A LDCONST R5 K7 + 0x88180305, // 000B GETMBR R6 R1 K5 + 0x881C0108, // 000C GETMBR R7 R0 K8 + 0x7C0C0800, // 000D CALL R3 4 + 0x8C0C0109, // 000E GETMET R3 R0 K9 + 0x5C140400, // 000F MOVE R5 R2 + 0x5818000A, // 0010 LDCONST R6 K10 + 0x881C010B, // 0011 GETMBR R7 R0 K11 + 0x7C0C0800, // 0012 CALL R3 4 + 0x8C0C0503, // 0013 GETMET R3 R2 K3 + 0x541600FE, // 0014 LDINT R5 255 + 0x8818030C, // 0015 GETMBR R6 R1 K12 + 0x881C010D, // 0016 GETMBR R7 R0 K13 + 0x7C0C0800, // 0017 CALL R3 4 + 0x80040400, // 0018 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_InvokeRequestMessage +********************************************************************/ +extern const bclass be_class_Matter_IM_Message_base; +be_local_class(Matter_InvokeRequestMessage, + 3, + &be_class_Matter_IM_Message_base, + be_nested_map(5, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(invoke_requests, -1), be_const_var(2) }, + { be_const_key_weak(suppress_response, 2), be_const_var(0) }, + { be_const_key_weak(timed_request, -1), be_const_var(1) }, + { be_const_key_weak(from_TLV, -1), be_const_closure(Matter_InvokeRequestMessage_from_TLV_closure) }, + { be_const_key_weak(to_TLV, -1), be_const_closure(Matter_InvokeRequestMessage_to_TLV_closure) }, + })), + be_str_weak(Matter_InvokeRequestMessage) +); +/*******************************************************************/ + +void be_load_Matter_InvokeRequestMessage_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_InvokeRequestMessage); + be_setglobal(vm, "Matter_InvokeRequestMessage"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_InvokeResponseMessage; + +/******************************************************************** +** Solidified function: to_TLV +********************************************************************/ +be_local_closure(Matter_InvokeResponseMessage_to_TLV, /* name */ + be_nested_proto( + 8, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[12]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(TLV), + /* K2 */ be_nested_str_weak(Matter_TLV_struct), + /* K3 */ be_nested_str_weak(add_TLV), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str_weak(BOOL), + /* K6 */ be_nested_str_weak(suppress_response), + /* K7 */ be_nested_str_weak(to_TLV_array), + /* K8 */ be_const_int(1), + /* K9 */ be_nested_str_weak(invoke_responses), + /* K10 */ be_nested_str_weak(U1), + /* K11 */ be_nested_str_weak(InteractionModelRevision), + }), + be_str_weak(to_TLV), + &be_const_str_solidified, + ( &(const binstruction[20]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x88040301, // 0001 GETMBR R1 R1 K1 + 0x8C080302, // 0002 GETMET R2 R1 K2 + 0x7C080200, // 0003 CALL R2 1 + 0x8C0C0503, // 0004 GETMET R3 R2 K3 + 0x58140004, // 0005 LDCONST R5 K4 + 0x88180305, // 0006 GETMBR R6 R1 K5 + 0x881C0106, // 0007 GETMBR R7 R0 K6 + 0x7C0C0800, // 0008 CALL R3 4 + 0x8C0C0107, // 0009 GETMET R3 R0 K7 + 0x5C140400, // 000A MOVE R5 R2 + 0x58180008, // 000B LDCONST R6 K8 + 0x881C0109, // 000C GETMBR R7 R0 K9 + 0x7C0C0800, // 000D CALL R3 4 + 0x8C0C0503, // 000E GETMET R3 R2 K3 + 0x541600FE, // 000F LDINT R5 255 + 0x8818030A, // 0010 GETMBR R6 R1 K10 + 0x881C010B, // 0011 GETMBR R7 R0 K11 + 0x7C0C0800, // 0012 CALL R3 4 + 0x80040400, // 0013 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: from_TLV +********************************************************************/ +be_local_closure(Matter_InvokeResponseMessage_from_TLV, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(suppress_response), + /* K1 */ be_nested_str_weak(findsubval), + /* K2 */ be_const_int(0), + /* K3 */ be_nested_str_weak(invoke_responses), + /* K4 */ be_nested_str_weak(from_TLV_array), + /* K5 */ be_const_int(1), + /* K6 */ be_nested_str_weak(matter), + /* K7 */ be_nested_str_weak(InvokeResponseIB), + }), + be_str_weak(from_TLV), + &be_const_str_solidified, + ( &(const binstruction[18]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0001, // 0002 JMPF R2 #0005 + 0x4C080000, // 0003 LDNIL R2 + 0x80040400, // 0004 RET 1 R2 + 0x8C080301, // 0005 GETMET R2 R1 K1 + 0x58100002, // 0006 LDCONST R4 K2 + 0x7C080400, // 0007 CALL R2 2 + 0x90020002, // 0008 SETMBR R0 K0 R2 + 0x8C080104, // 0009 GETMET R2 R0 K4 + 0x8C100301, // 000A GETMET R4 R1 K1 + 0x58180005, // 000B LDCONST R6 K5 + 0x7C100400, // 000C CALL R4 2 + 0xB8160C00, // 000D GETNGBL R5 K6 + 0x88140B07, // 000E GETMBR R5 R5 K7 + 0x7C080600, // 000F CALL R2 3 + 0x90020602, // 0010 SETMBR R0 K3 R2 + 0x80040000, // 0011 RET 1 R0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_InvokeResponseMessage +********************************************************************/ +extern const bclass be_class_Matter_IM_Message_base; +be_local_class(Matter_InvokeResponseMessage, + 2, + &be_class_Matter_IM_Message_base, + be_nested_map(4, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(suppress_response, 3), be_const_var(0) }, + { be_const_key_weak(to_TLV, -1), be_const_closure(Matter_InvokeResponseMessage_to_TLV_closure) }, + { be_const_key_weak(invoke_responses, -1), be_const_var(1) }, + { be_const_key_weak(from_TLV, -1), be_const_closure(Matter_InvokeResponseMessage_from_TLV_closure) }, + })), + be_str_weak(Matter_InvokeResponseMessage) +); +/*******************************************************************/ + +void be_load_Matter_InvokeResponseMessage_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_InvokeResponseMessage); + be_setglobal(vm, "Matter_InvokeResponseMessage"); + be_pop(vm, 1); +} +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Message.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Message.h new file mode 100644 index 000000000..044e02159 --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Message.h @@ -0,0 +1,1227 @@ +/* Solidification of Matter_Message.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_Frame; + +/******************************************************************** +** Solidified function: decrypt +********************************************************************/ +be_local_closure(Matter_Frame_decrypt, /* name */ + be_nested_proto( + 16, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[30]) { /* constants */ + /* K0 */ be_nested_str_weak(crypto), + /* K1 */ be_nested_str_weak(session), + /* K2 */ be_nested_str_weak(raw), + /* K3 */ be_nested_str_weak(get_i2r), + /* K4 */ be_const_int(2147483647), + /* K5 */ be_const_int(0), + /* K6 */ be_nested_str_weak(payload_idx), + /* K7 */ be_const_int(1), + /* K8 */ be_nested_str_weak(add), + /* K9 */ be_nested_str_weak(flags), + /* K10 */ be_nested_str_weak(message_counter), + /* K11 */ be_nested_str_weak(source_node_id), + /* K12 */ be_nested_str_weak(peer_node_id), + /* K13 */ be_nested_str_weak(resize), + /* K14 */ be_nested_str_weak(tasmota), + /* K15 */ be_nested_str_weak(log), + /* K16 */ be_nested_str_weak(MTR_X3A_X20_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A), + /* K17 */ be_const_int(3), + /* K18 */ be_nested_str_weak(MTR_X3A_X20i2r_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), + /* K19 */ be_nested_str_weak(tohex), + /* K20 */ be_nested_str_weak(MTR_X3A_X20p_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), + /* K21 */ be_nested_str_weak(MTR_X3A_X20a_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), + /* K22 */ be_nested_str_weak(MTR_X3A_X20n_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), + /* K23 */ be_nested_str_weak(MTR_X3A_X20mic_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), + /* K24 */ be_nested_str_weak(AES_CCM), + /* K25 */ be_nested_str_weak(decrypt), + /* K26 */ be_nested_str_weak(tag), + /* K27 */ be_nested_str_weak(MTR_X3A_X20cleartext_X20_X20_X20_X3D), + /* K28 */ be_nested_str_weak(MTR_X3A_X20tag_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), + /* K29 */ be_nested_str_weak(MTR_X3A_X20rejected_X20packet_X20due_X20to_X20invalid_X20MIC), + }), + be_str_weak(decrypt), + &be_const_str_solidified, + ( &(const binstruction[125]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x88080101, // 0001 GETMBR R2 R0 K1 + 0x880C0102, // 0002 GETMBR R3 R0 K2 + 0x8C100503, // 0003 GETMET R4 R2 K3 + 0x7C100200, // 0004 CALL R4 1 + 0x5415FFEF, // 0005 LDINT R5 -16 + 0x40140B04, // 0006 CONNECT R5 R5 K4 + 0x94140605, // 0007 GETIDX R5 R3 R5 + 0x88180106, // 0008 GETMBR R6 R0 K6 + 0x04180D07, // 0009 SUB R6 R6 K7 + 0x401A0A06, // 000A CONNECT R6 K5 R6 + 0x94180606, // 000B GETIDX R6 R3 R6 + 0x881C0106, // 000C GETMBR R7 R0 K6 + 0x5421FFEE, // 000D LDINT R8 -17 + 0x401C0E08, // 000E CONNECT R7 R7 R8 + 0x941C0607, // 000F GETIDX R7 R3 R7 + 0x60200015, // 0010 GETGBL R8 G21 + 0x7C200000, // 0011 CALL R8 0 + 0x8C241108, // 0012 GETMET R9 R8 K8 + 0x882C0109, // 0013 GETMBR R11 R0 K9 + 0x58300007, // 0014 LDCONST R12 K7 + 0x7C240600, // 0015 CALL R9 3 + 0x8C241108, // 0016 GETMET R9 R8 K8 + 0x882C010A, // 0017 GETMBR R11 R0 K10 + 0x54320003, // 0018 LDINT R12 4 + 0x7C240600, // 0019 CALL R9 3 + 0x8824010B, // 001A GETMBR R9 R0 K11 + 0x78260001, // 001B JMPF R9 #001E + 0x40241104, // 001C CONNECT R9 R8 K4 + 0x70020006, // 001D JMP #0025 + 0x8824050C, // 001E GETMBR R9 R2 K12 + 0x78260001, // 001F JMPF R9 #0022 + 0x8824050C, // 0020 GETMBR R9 R2 K12 + 0x40241009, // 0021 CONNECT R9 R8 R9 + 0x8C24110D, // 0022 GETMET R9 R8 K13 + 0x542E000C, // 0023 LDINT R11 13 + 0x7C240400, // 0024 CALL R9 2 + 0xB8261C00, // 0025 GETNGBL R9 K14 + 0x8C24130F, // 0026 GETMET R9 R9 K15 + 0x582C0010, // 0027 LDCONST R11 K16 + 0x58300011, // 0028 LDCONST R12 K17 + 0x7C240600, // 0029 CALL R9 3 + 0xB8261C00, // 002A GETNGBL R9 K14 + 0x8C24130F, // 002B GETMET R9 R9 K15 + 0x8C2C0913, // 002C GETMET R11 R4 K19 + 0x7C2C0200, // 002D CALL R11 1 + 0x002E240B, // 002E ADD R11 K18 R11 + 0x58300011, // 002F LDCONST R12 K17 + 0x7C240600, // 0030 CALL R9 3 + 0xB8261C00, // 0031 GETNGBL R9 K14 + 0x8C24130F, // 0032 GETMET R9 R9 K15 + 0x8C2C0F13, // 0033 GETMET R11 R7 K19 + 0x7C2C0200, // 0034 CALL R11 1 + 0x002E280B, // 0035 ADD R11 K20 R11 + 0x58300011, // 0036 LDCONST R12 K17 + 0x7C240600, // 0037 CALL R9 3 + 0xB8261C00, // 0038 GETNGBL R9 K14 + 0x8C24130F, // 0039 GETMET R9 R9 K15 + 0x8C2C0D13, // 003A GETMET R11 R6 K19 + 0x7C2C0200, // 003B CALL R11 1 + 0x002E2A0B, // 003C ADD R11 K21 R11 + 0x58300011, // 003D LDCONST R12 K17 + 0x7C240600, // 003E CALL R9 3 + 0xB8261C00, // 003F GETNGBL R9 K14 + 0x8C24130F, // 0040 GETMET R9 R9 K15 + 0x8C2C1113, // 0041 GETMET R11 R8 K19 + 0x7C2C0200, // 0042 CALL R11 1 + 0x002E2C0B, // 0043 ADD R11 K22 R11 + 0x58300011, // 0044 LDCONST R12 K17 + 0x7C240600, // 0045 CALL R9 3 + 0xB8261C00, // 0046 GETNGBL R9 K14 + 0x8C24130F, // 0047 GETMET R9 R9 K15 + 0x8C2C0B13, // 0048 GETMET R11 R5 K19 + 0x7C2C0200, // 0049 CALL R11 1 + 0x002E2E0B, // 004A ADD R11 K23 R11 + 0x58300011, // 004B LDCONST R12 K17 + 0x7C240600, // 004C CALL R9 3 + 0x8C240318, // 004D GETMET R9 R1 K24 + 0x5C2C0800, // 004E MOVE R11 R4 + 0x5C301000, // 004F MOVE R12 R8 + 0x5C340C00, // 0050 MOVE R13 R6 + 0x6038000C, // 0051 GETGBL R14 G12 + 0x5C3C0E00, // 0052 MOVE R15 R7 + 0x7C380200, // 0053 CALL R14 1 + 0x543E000F, // 0054 LDINT R15 16 + 0x7C240C00, // 0055 CALL R9 6 + 0x8C281319, // 0056 GETMET R10 R9 K25 + 0x5C300E00, // 0057 MOVE R12 R7 + 0x7C280400, // 0058 CALL R10 2 + 0x8C2C131A, // 0059 GETMET R11 R9 K26 + 0x7C2C0200, // 005A CALL R11 1 + 0xB8321C00, // 005B GETNGBL R12 K14 + 0x8C30190F, // 005C GETMET R12 R12 K15 + 0x58380010, // 005D LDCONST R14 K16 + 0x583C0011, // 005E LDCONST R15 K17 + 0x7C300600, // 005F CALL R12 3 + 0xB8321C00, // 0060 GETNGBL R12 K14 + 0x8C30190F, // 0061 GETMET R12 R12 K15 + 0x8C381513, // 0062 GETMET R14 R10 K19 + 0x7C380200, // 0063 CALL R14 1 + 0x003A360E, // 0064 ADD R14 K27 R14 + 0x583C0011, // 0065 LDCONST R15 K17 + 0x7C300600, // 0066 CALL R12 3 + 0xB8321C00, // 0067 GETNGBL R12 K14 + 0x8C30190F, // 0068 GETMET R12 R12 K15 + 0x8C381713, // 0069 GETMET R14 R11 K19 + 0x7C380200, // 006A CALL R14 1 + 0x003A380E, // 006B ADD R14 K28 R14 + 0x583C0011, // 006C LDCONST R15 K17 + 0x7C300600, // 006D CALL R12 3 + 0xB8321C00, // 006E GETNGBL R12 K14 + 0x8C30190F, // 006F GETMET R12 R12 K15 + 0x58380010, // 0070 LDCONST R14 K16 + 0x583C0011, // 0071 LDCONST R15 K17 + 0x7C300600, // 0072 CALL R12 3 + 0x20301605, // 0073 NE R12 R11 R5 + 0x78320006, // 0074 JMPF R12 #007C + 0xB8321C00, // 0075 GETNGBL R12 K14 + 0x8C30190F, // 0076 GETMET R12 R12 K15 + 0x5838001D, // 0077 LDCONST R14 K29 + 0x583C0011, // 0078 LDCONST R15 K17 + 0x7C300600, // 0079 CALL R12 3 + 0x4C300000, // 007A LDNIL R12 + 0x80041800, // 007B RET 1 R12 + 0x80041400, // 007C RET 1 R10 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_Frame_init, /* name */ + be_nested_proto( + 3, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(message_handler), + /* K1 */ be_nested_str_weak(raw), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[ 3]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x90020202, // 0001 SETMBR R0 K1 R2 + 0x80000000, // 0002 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: decode_payload +********************************************************************/ +be_local_closure(Matter_Frame_decode_payload, /* name */ + be_nested_proto( + 7, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[19]) { /* constants */ + /* K0 */ be_nested_str_weak(payload_idx), + /* K1 */ be_nested_str_weak(raw), + /* K2 */ be_nested_str_weak(x_flags), + /* K3 */ be_nested_str_weak(get), + /* K4 */ be_const_int(1), + /* K5 */ be_nested_str_weak(x_flag_v), + /* K6 */ be_nested_str_weak(getbits), + /* K7 */ be_nested_str_weak(x_flag_sx), + /* K8 */ be_const_int(3), + /* K9 */ be_nested_str_weak(x_flag_r), + /* K10 */ be_const_int(2), + /* K11 */ be_nested_str_weak(x_flag_a), + /* K12 */ be_nested_str_weak(x_flag_i), + /* K13 */ be_nested_str_weak(opcode), + /* K14 */ be_nested_str_weak(exchange_id), + /* K15 */ be_nested_str_weak(protocol_id), + /* K16 */ be_nested_str_weak(vendor_id), + /* K17 */ be_nested_str_weak(ack_message_counter), + /* K18 */ be_nested_str_weak(app_payload_idx), + }), + be_str_weak(decode_payload), + &be_const_str_solidified, + ( &(const binstruction[87]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x88080101, // 0001 GETMBR R2 R0 K1 + 0x8C0C0503, // 0002 GETMET R3 R2 K3 + 0x5C140200, // 0003 MOVE R5 R1 + 0x58180004, // 0004 LDCONST R6 K4 + 0x7C0C0600, // 0005 CALL R3 3 + 0x90020403, // 0006 SETMBR R0 K2 R3 + 0x8C0C0506, // 0007 GETMET R3 R2 K6 + 0x54160007, // 0008 LDINT R5 8 + 0x08140205, // 0009 MUL R5 R1 R5 + 0x541A0003, // 000A LDINT R6 4 + 0x00140A06, // 000B ADD R5 R5 R6 + 0x58180004, // 000C LDCONST R6 K4 + 0x7C0C0600, // 000D CALL R3 3 + 0x90020A03, // 000E SETMBR R0 K5 R3 + 0x8C0C0506, // 000F GETMET R3 R2 K6 + 0x54160007, // 0010 LDINT R5 8 + 0x08140205, // 0011 MUL R5 R1 R5 + 0x00140B08, // 0012 ADD R5 R5 K8 + 0x58180004, // 0013 LDCONST R6 K4 + 0x7C0C0600, // 0014 CALL R3 3 + 0x90020E03, // 0015 SETMBR R0 K7 R3 + 0x8C0C0506, // 0016 GETMET R3 R2 K6 + 0x54160007, // 0017 LDINT R5 8 + 0x08140205, // 0018 MUL R5 R1 R5 + 0x00140B0A, // 0019 ADD R5 R5 K10 + 0x58180004, // 001A LDCONST R6 K4 + 0x7C0C0600, // 001B CALL R3 3 + 0x90021203, // 001C SETMBR R0 K9 R3 + 0x8C0C0506, // 001D GETMET R3 R2 K6 + 0x54160007, // 001E LDINT R5 8 + 0x08140205, // 001F MUL R5 R1 R5 + 0x00140B04, // 0020 ADD R5 R5 K4 + 0x58180004, // 0021 LDCONST R6 K4 + 0x7C0C0600, // 0022 CALL R3 3 + 0x90021603, // 0023 SETMBR R0 K11 R3 + 0x8C0C0506, // 0024 GETMET R3 R2 K6 + 0x54160007, // 0025 LDINT R5 8 + 0x08140205, // 0026 MUL R5 R1 R5 + 0x58180004, // 0027 LDCONST R6 K4 + 0x7C0C0600, // 0028 CALL R3 3 + 0x90021803, // 0029 SETMBR R0 K12 R3 + 0x8C0C0503, // 002A GETMET R3 R2 K3 + 0x00140304, // 002B ADD R5 R1 K4 + 0x58180004, // 002C LDCONST R6 K4 + 0x7C0C0600, // 002D CALL R3 3 + 0x90021A03, // 002E SETMBR R0 K13 R3 + 0x8C0C0503, // 002F GETMET R3 R2 K3 + 0x0014030A, // 0030 ADD R5 R1 K10 + 0x5818000A, // 0031 LDCONST R6 K10 + 0x7C0C0600, // 0032 CALL R3 3 + 0x90021C03, // 0033 SETMBR R0 K14 R3 + 0x8C0C0503, // 0034 GETMET R3 R2 K3 + 0x54160003, // 0035 LDINT R5 4 + 0x00140205, // 0036 ADD R5 R1 R5 + 0x5818000A, // 0037 LDCONST R6 K10 + 0x7C0C0600, // 0038 CALL R3 3 + 0x90021E03, // 0039 SETMBR R0 K15 R3 + 0x540E0005, // 003A LDINT R3 6 + 0x00040203, // 003B ADD R1 R1 R3 + 0x880C0105, // 003C GETMBR R3 R0 K5 + 0x780E0005, // 003D JMPF R3 #0044 + 0x8C0C0503, // 003E GETMET R3 R2 K3 + 0x5C140200, // 003F MOVE R5 R1 + 0x5818000A, // 0040 LDCONST R6 K10 + 0x7C0C0600, // 0041 CALL R3 3 + 0x90022003, // 0042 SETMBR R0 K16 R3 + 0x0004030A, // 0043 ADD R1 R1 K10 + 0x880C010B, // 0044 GETMBR R3 R0 K11 + 0x780E0006, // 0045 JMPF R3 #004D + 0x8C0C0503, // 0046 GETMET R3 R2 K3 + 0x5C140200, // 0047 MOVE R5 R1 + 0x541A0003, // 0048 LDINT R6 4 + 0x7C0C0600, // 0049 CALL R3 3 + 0x90022203, // 004A SETMBR R0 K17 R3 + 0x540E0003, // 004B LDINT R3 4 + 0x00040203, // 004C ADD R1 R1 R3 + 0x880C0107, // 004D GETMBR R3 R0 K7 + 0x780E0005, // 004E JMPF R3 #0055 + 0x8C0C0503, // 004F GETMET R3 R2 K3 + 0x5C140200, // 0050 MOVE R5 R1 + 0x5818000A, // 0051 LDCONST R6 K10 + 0x7C0C0600, // 0052 CALL R3 3 + 0x0010070A, // 0053 ADD R4 R3 K10 + 0x00040204, // 0054 ADD R1 R1 R4 + 0x90022401, // 0055 SETMBR R0 K18 R1 + 0x80040000, // 0056 RET 1 R0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: encrypt +********************************************************************/ +be_local_closure(Matter_Frame_encrypt, /* name */ + be_nested_proto( + 15, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[30]) { /* constants */ + /* K0 */ be_nested_str_weak(crypto), + /* K1 */ be_nested_str_weak(raw), + /* K2 */ be_nested_str_weak(session), + /* K3 */ be_nested_str_weak(get_r2i), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str_weak(payload_idx), + /* K6 */ be_const_int(1), + /* K7 */ be_const_int(2147483647), + /* K8 */ be_nested_str_weak(add), + /* K9 */ be_nested_str_weak(flags), + /* K10 */ be_nested_str_weak(message_counter), + /* K11 */ be_nested_str_weak(get_mode), + /* K12 */ be_nested_str_weak(__CASE), + /* K13 */ be_nested_str_weak(deviceid), + /* K14 */ be_nested_str_weak(resize), + /* K15 */ be_nested_str_weak(tasmota), + /* K16 */ be_nested_str_weak(log), + /* K17 */ be_nested_str_weak(MTR_X3A_X20cleartext_X3A_X20), + /* K18 */ be_nested_str_weak(tohex), + /* K19 */ be_const_int(3), + /* K20 */ be_nested_str_weak(MTR_X3A_X20_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A), + /* K21 */ be_nested_str_weak(MTR_X3A_X20r2i_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), + /* K22 */ be_nested_str_weak(MTR_X3A_X20p_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), + /* K23 */ be_nested_str_weak(MTR_X3A_X20a_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), + /* K24 */ be_nested_str_weak(MTR_X3A_X20n_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), + /* K25 */ be_nested_str_weak(AES_CCM), + /* K26 */ be_nested_str_weak(encrypt), + /* K27 */ be_nested_str_weak(tag), + /* K28 */ be_nested_str_weak(MTR_X3A_X20ciphertext_X20_X20_X3D), + /* K29 */ be_nested_str_weak(MTR_X3A_X20tag_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), + }), + be_str_weak(encrypt), + &be_const_str_solidified, + ( &(const binstruction[122]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x88080101, // 0001 GETMBR R2 R0 K1 + 0x880C0102, // 0002 GETMBR R3 R0 K2 + 0x8C100703, // 0003 GETMET R4 R3 K3 + 0x7C100200, // 0004 CALL R4 1 + 0x88140105, // 0005 GETMBR R5 R0 K5 + 0x04140B06, // 0006 SUB R5 R5 K6 + 0x40160805, // 0007 CONNECT R5 K4 R5 + 0x94140405, // 0008 GETIDX R5 R2 R5 + 0x88180105, // 0009 GETMBR R6 R0 K5 + 0x40180D07, // 000A CONNECT R6 R6 K7 + 0x94180406, // 000B GETIDX R6 R2 R6 + 0x601C0015, // 000C GETGBL R7 G21 + 0x7C1C0000, // 000D CALL R7 0 + 0x8C200F08, // 000E GETMET R8 R7 K8 + 0x88280109, // 000F GETMBR R10 R0 K9 + 0x582C0006, // 0010 LDCONST R11 K6 + 0x7C200600, // 0011 CALL R8 3 + 0x8C200F08, // 0012 GETMET R8 R7 K8 + 0x8828010A, // 0013 GETMBR R10 R0 K10 + 0x542E0003, // 0014 LDINT R11 4 + 0x7C200600, // 0015 CALL R8 3 + 0x8C20070B, // 0016 GETMET R8 R3 K11 + 0x7C200200, // 0017 CALL R8 1 + 0x8824070C, // 0018 GETMBR R9 R3 K12 + 0x1C201009, // 0019 EQ R8 R8 R9 + 0x78220003, // 001A JMPF R8 #001F + 0x8820070D, // 001B GETMBR R8 R3 K13 + 0x78220001, // 001C JMPF R8 #001F + 0x8820070D, // 001D GETMBR R8 R3 K13 + 0x40200E08, // 001E CONNECT R8 R7 R8 + 0x8C200F0E, // 001F GETMET R8 R7 K14 + 0x542A000C, // 0020 LDINT R10 13 + 0x7C200400, // 0021 CALL R8 2 + 0xB8221E00, // 0022 GETNGBL R8 K15 + 0x8C201110, // 0023 GETMET R8 R8 K16 + 0x88280101, // 0024 GETMBR R10 R0 K1 + 0x8C281512, // 0025 GETMET R10 R10 K18 + 0x7C280200, // 0026 CALL R10 1 + 0x002A220A, // 0027 ADD R10 K17 R10 + 0x582C0013, // 0028 LDCONST R11 K19 + 0x7C200600, // 0029 CALL R8 3 + 0xB8221E00, // 002A GETNGBL R8 K15 + 0x8C201110, // 002B GETMET R8 R8 K16 + 0x58280014, // 002C LDCONST R10 K20 + 0x582C0013, // 002D LDCONST R11 K19 + 0x7C200600, // 002E CALL R8 3 + 0xB8221E00, // 002F GETNGBL R8 K15 + 0x8C201110, // 0030 GETMET R8 R8 K16 + 0x8C280912, // 0031 GETMET R10 R4 K18 + 0x7C280200, // 0032 CALL R10 1 + 0x002A2A0A, // 0033 ADD R10 K21 R10 + 0x582C0013, // 0034 LDCONST R11 K19 + 0x7C200600, // 0035 CALL R8 3 + 0xB8221E00, // 0036 GETNGBL R8 K15 + 0x8C201110, // 0037 GETMET R8 R8 K16 + 0x8C280D12, // 0038 GETMET R10 R6 K18 + 0x7C280200, // 0039 CALL R10 1 + 0x002A2C0A, // 003A ADD R10 K22 R10 + 0x582C0013, // 003B LDCONST R11 K19 + 0x7C200600, // 003C CALL R8 3 + 0xB8221E00, // 003D GETNGBL R8 K15 + 0x8C201110, // 003E GETMET R8 R8 K16 + 0x8C280B12, // 003F GETMET R10 R5 K18 + 0x7C280200, // 0040 CALL R10 1 + 0x002A2E0A, // 0041 ADD R10 K23 R10 + 0x582C0013, // 0042 LDCONST R11 K19 + 0x7C200600, // 0043 CALL R8 3 + 0xB8221E00, // 0044 GETNGBL R8 K15 + 0x8C201110, // 0045 GETMET R8 R8 K16 + 0x8C280F12, // 0046 GETMET R10 R7 K18 + 0x7C280200, // 0047 CALL R10 1 + 0x002A300A, // 0048 ADD R10 K24 R10 + 0x582C0013, // 0049 LDCONST R11 K19 + 0x7C200600, // 004A CALL R8 3 + 0x8C200319, // 004B GETMET R8 R1 K25 + 0x5C280800, // 004C MOVE R10 R4 + 0x5C2C0E00, // 004D MOVE R11 R7 + 0x5C300A00, // 004E MOVE R12 R5 + 0x6034000C, // 004F GETGBL R13 G12 + 0x5C380C00, // 0050 MOVE R14 R6 + 0x7C340200, // 0051 CALL R13 1 + 0x543A000F, // 0052 LDINT R14 16 + 0x7C200C00, // 0053 CALL R8 6 + 0x8C24111A, // 0054 GETMET R9 R8 K26 + 0x5C2C0C00, // 0055 MOVE R11 R6 + 0x7C240400, // 0056 CALL R9 2 + 0x8C28111B, // 0057 GETMET R10 R8 K27 + 0x7C280200, // 0058 CALL R10 1 + 0xB82E1E00, // 0059 GETNGBL R11 K15 + 0x8C2C1710, // 005A GETMET R11 R11 K16 + 0x58340014, // 005B LDCONST R13 K20 + 0x58380013, // 005C LDCONST R14 K19 + 0x7C2C0600, // 005D CALL R11 3 + 0xB82E1E00, // 005E GETNGBL R11 K15 + 0x8C2C1710, // 005F GETMET R11 R11 K16 + 0x8C341312, // 0060 GETMET R13 R9 K18 + 0x7C340200, // 0061 CALL R13 1 + 0x0036380D, // 0062 ADD R13 K28 R13 + 0x58380013, // 0063 LDCONST R14 K19 + 0x7C2C0600, // 0064 CALL R11 3 + 0xB82E1E00, // 0065 GETNGBL R11 K15 + 0x8C2C1710, // 0066 GETMET R11 R11 K16 + 0x8C341512, // 0067 GETMET R13 R10 K18 + 0x7C340200, // 0068 CALL R13 1 + 0x00363A0D, // 0069 ADD R13 K29 R13 + 0x58380013, // 006A LDCONST R14 K19 + 0x7C2C0600, // 006B CALL R11 3 + 0xB82E1E00, // 006C GETNGBL R11 K15 + 0x8C2C1710, // 006D GETMET R11 R11 K16 + 0x58340014, // 006E LDCONST R13 K20 + 0x58380013, // 006F LDCONST R14 K19 + 0x7C2C0600, // 0070 CALL R11 3 + 0x882C0101, // 0071 GETMBR R11 R0 K1 + 0x8C2C170E, // 0072 GETMET R11 R11 K14 + 0x88340105, // 0073 GETMBR R13 R0 K5 + 0x7C2C0400, // 0074 CALL R11 2 + 0x882C0101, // 0075 GETMBR R11 R0 K1 + 0x402C1609, // 0076 CONNECT R11 R11 R9 + 0x882C0101, // 0077 GETMBR R11 R0 K1 + 0x402C160A, // 0078 CONNECT R11 R11 R10 + 0x80000000, // 0079 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: build_standalone_ack +********************************************************************/ +be_local_closure(Matter_Frame_build_standalone_ack, /* name */ + be_nested_proto( + 11, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[28]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(message_handler), + /* K2 */ be_nested_str_weak(flag_s), + /* K3 */ be_nested_str_weak(flag_dsiz), + /* K4 */ be_const_int(1), + /* K5 */ be_nested_str_weak(dest_node_id_8), + /* K6 */ be_nested_str_weak(source_node_id), + /* K7 */ be_const_int(0), + /* K8 */ be_nested_str_weak(session), + /* K9 */ be_nested_str_weak(message_counter), + /* K10 */ be_nested_str_weak(counter_snd), + /* K11 */ be_nested_str_weak(next), + /* K12 */ be_nested_str_weak(local_session_id), + /* K13 */ be_nested_str_weak(initiator_session_id), + /* K14 */ be_nested_str_weak(x_flag_i), + /* K15 */ be_nested_str_weak(opcode), + /* K16 */ be_nested_str_weak(exchange_id), + /* K17 */ be_nested_str_weak(protocol_id), + /* K18 */ be_nested_str_weak(x_flag_a), + /* K19 */ be_nested_str_weak(ack_message_counter), + /* K20 */ be_nested_str_weak(x_flag_r), + /* K21 */ be_nested_str_weak(tasmota), + /* K22 */ be_nested_str_weak(log), + /* K23 */ be_nested_str_weak(format), + /* K24 */ be_nested_str_weak(MTR_X3A_X20_X3CReplied_X20_X20_X20_X20_X20_X20_X20_X25s), + /* K25 */ be_nested_str_weak(matter), + /* K26 */ be_nested_str_weak(get_opcode_name), + /* K27 */ be_const_int(2), + }), + be_str_weak(build_standalone_ack), + &be_const_str_solidified, + ( &(const binstruction[45]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x60080006, // 0001 GETGBL R2 G6 + 0x5C0C0000, // 0002 MOVE R3 R0 + 0x7C080200, // 0003 CALL R2 1 + 0x880C0101, // 0004 GETMBR R3 R0 K1 + 0x7C080200, // 0005 CALL R2 1 + 0x880C0102, // 0006 GETMBR R3 R0 K2 + 0x780E0003, // 0007 JMPF R3 #000C + 0x900A0704, // 0008 SETMBR R2 K3 K4 + 0x880C0106, // 0009 GETMBR R3 R0 K6 + 0x900A0A03, // 000A SETMBR R2 K5 R3 + 0x70020000, // 000B JMP #000D + 0x900A0707, // 000C SETMBR R2 K3 K7 + 0x880C0108, // 000D GETMBR R3 R0 K8 + 0x900A1003, // 000E SETMBR R2 K8 R3 + 0x880C0108, // 000F GETMBR R3 R0 K8 + 0x880C070A, // 0010 GETMBR R3 R3 K10 + 0x8C0C070B, // 0011 GETMET R3 R3 K11 + 0x7C0C0200, // 0012 CALL R3 1 + 0x900A1203, // 0013 SETMBR R2 K9 R3 + 0x880C0108, // 0014 GETMBR R3 R0 K8 + 0x880C070D, // 0015 GETMBR R3 R3 K13 + 0x900A1803, // 0016 SETMBR R2 K12 R3 + 0x900A1D07, // 0017 SETMBR R2 K14 K7 + 0x540E000F, // 0018 LDINT R3 16 + 0x900A1E03, // 0019 SETMBR R2 K15 R3 + 0x880C0110, // 001A GETMBR R3 R0 K16 + 0x900A2003, // 001B SETMBR R2 K16 R3 + 0x900A2307, // 001C SETMBR R2 K17 K7 + 0x900A2504, // 001D SETMBR R2 K18 K4 + 0x880C0109, // 001E GETMBR R3 R0 K9 + 0x900A2603, // 001F SETMBR R2 K19 R3 + 0x900A2907, // 0020 SETMBR R2 K20 K7 + 0xB80E2A00, // 0021 GETNGBL R3 K21 + 0x8C0C0716, // 0022 GETMET R3 R3 K22 + 0x8C140317, // 0023 GETMET R5 R1 K23 + 0x581C0018, // 0024 LDCONST R7 K24 + 0xB8223200, // 0025 GETNGBL R8 K25 + 0x8C20111A, // 0026 GETMET R8 R8 K26 + 0x8828050F, // 0027 GETMBR R10 R2 K15 + 0x7C200400, // 0028 CALL R8 2 + 0x7C140600, // 0029 CALL R5 3 + 0x5818001B, // 002A LDCONST R6 K27 + 0x7C0C0600, // 002B CALL R3 3 + 0x80040400, // 002C RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: debug +********************************************************************/ +be_local_closure(Matter_Frame_debug, /* name */ + be_nested_proto( + 8, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[10]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(Frame), + /* K2 */ be_nested_str_weak(message_handler), + /* K3 */ be_nested_str_weak(decode_header), + /* K4 */ be_nested_str_weak(decode_payload), + /* K5 */ be_nested_str_weak(tasmota), + /* K6 */ be_nested_str_weak(log), + /* K7 */ be_nested_str_weak(MTR_X3A_X20sending_X20decode_X3A_X20), + /* K8 */ be_nested_str_weak(inspect), + /* K9 */ be_const_int(3), + }), + be_str_weak(debug), + &be_const_str_solidified, + ( &(const binstruction[19]) { /* code */ + 0xB80A0000, // 0000 GETNGBL R2 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x88100102, // 0002 GETMBR R4 R0 K2 + 0x5C140200, // 0003 MOVE R5 R1 + 0x7C080600, // 0004 CALL R2 3 + 0x8C0C0503, // 0005 GETMET R3 R2 K3 + 0x7C0C0200, // 0006 CALL R3 1 + 0x8C0C0504, // 0007 GETMET R3 R2 K4 + 0x7C0C0200, // 0008 CALL R3 1 + 0xB80E0A00, // 0009 GETNGBL R3 K5 + 0x8C0C0706, // 000A GETMET R3 R3 K6 + 0xB8160000, // 000B GETNGBL R5 K0 + 0x8C140B08, // 000C GETMET R5 R5 K8 + 0x5C1C0400, // 000D MOVE R7 R2 + 0x7C140400, // 000E CALL R5 2 + 0x00160E05, // 000F ADD R5 K7 R5 + 0x58180009, // 0010 LDCONST R6 K9 + 0x7C0C0600, // 0011 CALL R3 3 + 0x80000000, // 0012 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: encode +********************************************************************/ +be_local_closure(Matter_Frame_encode, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[30]) { /* constants */ + /* K0 */ be_nested_str_weak(flags), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str_weak(flag_s), + /* K3 */ be_nested_str_weak(flag_dsiz), + /* K4 */ be_const_int(3), + /* K5 */ be_nested_str_weak(add), + /* K6 */ be_const_int(1), + /* K7 */ be_nested_str_weak(local_session_id), + /* K8 */ be_const_int(2), + /* K9 */ be_nested_str_weak(sec_flags), + /* K10 */ be_nested_str_weak(sec_p), + /* K11 */ be_nested_str_weak(sec_c), + /* K12 */ be_nested_str_weak(sec_sesstype), + /* K13 */ be_nested_str_weak(message_counter), + /* K14 */ be_nested_str_weak(source_node_id), + /* K15 */ be_nested_str_weak(dest_node_id_8), + /* K16 */ be_nested_str_weak(dest_node_id_2), + /* K17 */ be_nested_str_weak(payload_idx), + /* K18 */ be_nested_str_weak(x_flags), + /* K19 */ be_nested_str_weak(x_flag_v), + /* K20 */ be_nested_str_weak(x_flag_r), + /* K21 */ be_nested_str_weak(x_flag_a), + /* K22 */ be_nested_str_weak(x_flag_i), + /* K23 */ be_nested_str_weak(opcode), + /* K24 */ be_nested_str_weak(exchange_id), + /* K25 */ be_nested_str_weak(protocol_id), + /* K26 */ be_nested_str_weak(ack_message_counter), + /* K27 */ be_nested_str_weak(app_payload_idx), + /* K28 */ be_nested_str_weak(debug), + /* K29 */ be_nested_str_weak(raw), + }), + be_str_weak(encode), + &be_const_str_solidified, + ( &(const binstruction[144]) { /* code */ + 0x60080015, // 0000 GETGBL R2 G21 + 0x7C080000, // 0001 CALL R2 0 + 0x880C0100, // 0002 GETMBR R3 R0 K0 + 0x4C100000, // 0003 LDNIL R4 + 0x1C0C0604, // 0004 EQ R3 R3 R4 + 0x780E000D, // 0005 JMPF R3 #0014 + 0x90020101, // 0006 SETMBR R0 K0 K1 + 0x880C0102, // 0007 GETMBR R3 R0 K2 + 0x780E0003, // 0008 JMPF R3 #000D + 0x880C0100, // 0009 GETMBR R3 R0 K0 + 0x54120003, // 000A LDINT R4 4 + 0x300C0604, // 000B OR R3 R3 R4 + 0x90020003, // 000C SETMBR R0 K0 R3 + 0x880C0103, // 000D GETMBR R3 R0 K3 + 0x780E0004, // 000E JMPF R3 #0014 + 0x880C0100, // 000F GETMBR R3 R0 K0 + 0x88100103, // 0010 GETMBR R4 R0 K3 + 0x2C100904, // 0011 AND R4 R4 K4 + 0x300C0604, // 0012 OR R3 R3 R4 + 0x90020003, // 0013 SETMBR R0 K0 R3 + 0x8C0C0505, // 0014 GETMET R3 R2 K5 + 0x88140100, // 0015 GETMBR R5 R0 K0 + 0x58180006, // 0016 LDCONST R6 K6 + 0x7C0C0600, // 0017 CALL R3 3 + 0x8C0C0505, // 0018 GETMET R3 R2 K5 + 0x88140107, // 0019 GETMBR R5 R0 K7 + 0x78160001, // 001A JMPF R5 #001D + 0x88140107, // 001B GETMBR R5 R0 K7 + 0x70020000, // 001C JMP #001E + 0x58140001, // 001D LDCONST R5 K1 + 0x58180008, // 001E LDCONST R6 K8 + 0x7C0C0600, // 001F CALL R3 3 + 0x880C0109, // 0020 GETMBR R3 R0 K9 + 0x4C100000, // 0021 LDNIL R4 + 0x1C0C0604, // 0022 EQ R3 R3 R4 + 0x780E0013, // 0023 JMPF R3 #0038 + 0x90021301, // 0024 SETMBR R0 K9 K1 + 0x880C010A, // 0025 GETMBR R3 R0 K10 + 0x780E0003, // 0026 JMPF R3 #002B + 0x880C0109, // 0027 GETMBR R3 R0 K9 + 0x5412007F, // 0028 LDINT R4 128 + 0x300C0604, // 0029 OR R3 R3 R4 + 0x90021203, // 002A SETMBR R0 K9 R3 + 0x880C010B, // 002B GETMBR R3 R0 K11 + 0x780E0003, // 002C JMPF R3 #0031 + 0x880C0109, // 002D GETMBR R3 R0 K9 + 0x5412003F, // 002E LDINT R4 64 + 0x300C0604, // 002F OR R3 R3 R4 + 0x90021203, // 0030 SETMBR R0 K9 R3 + 0x880C010C, // 0031 GETMBR R3 R0 K12 + 0x780E0004, // 0032 JMPF R3 #0038 + 0x880C0109, // 0033 GETMBR R3 R0 K9 + 0x8810010C, // 0034 GETMBR R4 R0 K12 + 0x2C100904, // 0035 AND R4 R4 K4 + 0x300C0604, // 0036 OR R3 R3 R4 + 0x90021203, // 0037 SETMBR R0 K9 R3 + 0x8C0C0505, // 0038 GETMET R3 R2 K5 + 0x88140109, // 0039 GETMBR R5 R0 K9 + 0x58180006, // 003A LDCONST R6 K6 + 0x7C0C0600, // 003B CALL R3 3 + 0x8C0C0505, // 003C GETMET R3 R2 K5 + 0x8814010D, // 003D GETMBR R5 R0 K13 + 0x541A0003, // 003E LDINT R6 4 + 0x7C0C0600, // 003F CALL R3 3 + 0x880C0102, // 0040 GETMBR R3 R0 K2 + 0x780E0001, // 0041 JMPF R3 #0044 + 0x880C010E, // 0042 GETMBR R3 R0 K14 + 0x400C0403, // 0043 CONNECT R3 R2 R3 + 0x880C0103, // 0044 GETMBR R3 R0 K3 + 0x1C0C0706, // 0045 EQ R3 R3 K6 + 0x780E0001, // 0046 JMPF R3 #0049 + 0x880C010F, // 0047 GETMBR R3 R0 K15 + 0x400C0403, // 0048 CONNECT R3 R2 R3 + 0x880C0103, // 0049 GETMBR R3 R0 K3 + 0x1C0C0708, // 004A EQ R3 R3 K8 + 0x780E0003, // 004B JMPF R3 #0050 + 0x8C0C0505, // 004C GETMET R3 R2 K5 + 0x88140110, // 004D GETMBR R5 R0 K16 + 0x58180008, // 004E LDCONST R6 K8 + 0x7C0C0600, // 004F CALL R3 3 + 0x600C000C, // 0050 GETGBL R3 G12 + 0x5C100400, // 0051 MOVE R4 R2 + 0x7C0C0200, // 0052 CALL R3 1 + 0x90022203, // 0053 SETMBR R0 K17 R3 + 0x880C0112, // 0054 GETMBR R3 R0 K18 + 0x4C100000, // 0055 LDNIL R4 + 0x1C0C0604, // 0056 EQ R3 R3 R4 + 0x780E0016, // 0057 JMPF R3 #006F + 0x90022501, // 0058 SETMBR R0 K18 K1 + 0x880C0113, // 0059 GETMBR R3 R0 K19 + 0x780E0003, // 005A JMPF R3 #005F + 0x880C0112, // 005B GETMBR R3 R0 K18 + 0x5412000F, // 005C LDINT R4 16 + 0x300C0604, // 005D OR R3 R3 R4 + 0x90022403, // 005E SETMBR R0 K18 R3 + 0x880C0114, // 005F GETMBR R3 R0 K20 + 0x780E0003, // 0060 JMPF R3 #0065 + 0x880C0112, // 0061 GETMBR R3 R0 K18 + 0x54120003, // 0062 LDINT R4 4 + 0x300C0604, // 0063 OR R3 R3 R4 + 0x90022403, // 0064 SETMBR R0 K18 R3 + 0x880C0115, // 0065 GETMBR R3 R0 K21 + 0x780E0002, // 0066 JMPF R3 #006A + 0x880C0112, // 0067 GETMBR R3 R0 K18 + 0x300C0708, // 0068 OR R3 R3 K8 + 0x90022403, // 0069 SETMBR R0 K18 R3 + 0x880C0116, // 006A GETMBR R3 R0 K22 + 0x780E0002, // 006B JMPF R3 #006F + 0x880C0112, // 006C GETMBR R3 R0 K18 + 0x300C0706, // 006D OR R3 R3 K6 + 0x90022403, // 006E SETMBR R0 K18 R3 + 0x8C0C0505, // 006F GETMET R3 R2 K5 + 0x88140112, // 0070 GETMBR R5 R0 K18 + 0x58180006, // 0071 LDCONST R6 K6 + 0x7C0C0600, // 0072 CALL R3 3 + 0x8C0C0505, // 0073 GETMET R3 R2 K5 + 0x88140117, // 0074 GETMBR R5 R0 K23 + 0x58180006, // 0075 LDCONST R6 K6 + 0x7C0C0600, // 0076 CALL R3 3 + 0x8C0C0505, // 0077 GETMET R3 R2 K5 + 0x88140118, // 0078 GETMBR R5 R0 K24 + 0x58180008, // 0079 LDCONST R6 K8 + 0x7C0C0600, // 007A CALL R3 3 + 0x8C0C0505, // 007B GETMET R3 R2 K5 + 0x88140119, // 007C GETMBR R5 R0 K25 + 0x58180008, // 007D LDCONST R6 K8 + 0x7C0C0600, // 007E CALL R3 3 + 0x880C0115, // 007F GETMBR R3 R0 K21 + 0x780E0003, // 0080 JMPF R3 #0085 + 0x8C0C0505, // 0081 GETMET R3 R2 K5 + 0x8814011A, // 0082 GETMBR R5 R0 K26 + 0x541A0003, // 0083 LDINT R6 4 + 0x7C0C0600, // 0084 CALL R3 3 + 0x600C000C, // 0085 GETGBL R3 G12 + 0x5C100400, // 0086 MOVE R4 R2 + 0x7C0C0200, // 0087 CALL R3 1 + 0x90023603, // 0088 SETMBR R0 K27 R3 + 0x78060000, // 0089 JMPF R1 #008B + 0x400C0401, // 008A CONNECT R3 R2 R1 + 0x8C0C011C, // 008B GETMET R3 R0 K28 + 0x5C140400, // 008C MOVE R5 R2 + 0x7C0C0400, // 008D CALL R3 2 + 0x90023A02, // 008E SETMBR R0 K29 R2 + 0x80040400, // 008F RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: build_response +********************************************************************/ +be_local_closure(Matter_Frame_build_response, /* name */ + be_nested_proto( + 12, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[30]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(message_handler), + /* K2 */ be_nested_str_weak(flag_s), + /* K3 */ be_nested_str_weak(flag_dsiz), + /* K4 */ be_const_int(1), + /* K5 */ be_nested_str_weak(dest_node_id_8), + /* K6 */ be_nested_str_weak(source_node_id), + /* K7 */ be_const_int(0), + /* K8 */ be_nested_str_weak(session), + /* K9 */ be_nested_str_weak(local_session_id), + /* K10 */ be_nested_str_weak(initiator_session_id), + /* K11 */ be_nested_str_weak(message_counter), + /* K12 */ be_nested_str_weak(counter_snd), + /* K13 */ be_nested_str_weak(next), + /* K14 */ be_nested_str_weak(_counter_insecure_snd), + /* K15 */ be_nested_str_weak(x_flag_i), + /* K16 */ be_nested_str_weak(opcode), + /* K17 */ be_nested_str_weak(exchange_id), + /* K18 */ be_nested_str_weak(protocol_id), + /* K19 */ be_nested_str_weak(x_flag_r), + /* K20 */ be_nested_str_weak(x_flag_a), + /* K21 */ be_nested_str_weak(ack_message_counter), + /* K22 */ be_nested_str_weak(matter), + /* K23 */ be_nested_str_weak(get_opcode_name), + /* K24 */ be_nested_str_weak(format), + /* K25 */ be_nested_str_weak(0x_X2502X), + /* K26 */ be_nested_str_weak(tasmota), + /* K27 */ be_nested_str_weak(log), + /* K28 */ be_nested_str_weak(MTR_X3A_X20_X3CReplied_X20_X20_X20_X20_X20_X20_X20_X25s), + /* K29 */ be_const_int(2), + }), + be_str_weak(build_response), + &be_const_str_solidified, + ( &(const binstruction[78]) { /* code */ + 0xA40E0000, // 0000 IMPORT R3 K0 + 0x60100006, // 0001 GETGBL R4 G6 + 0x5C140000, // 0002 MOVE R5 R0 + 0x7C100200, // 0003 CALL R4 1 + 0x88140101, // 0004 GETMBR R5 R0 K1 + 0x7C100200, // 0005 CALL R4 1 + 0x88140102, // 0006 GETMBR R5 R0 K2 + 0x78160003, // 0007 JMPF R5 #000C + 0x90120704, // 0008 SETMBR R4 K3 K4 + 0x88140106, // 0009 GETMBR R5 R0 K6 + 0x90120A05, // 000A SETMBR R4 K5 R5 + 0x70020000, // 000B JMP #000D + 0x90120707, // 000C SETMBR R4 K3 K7 + 0x88140108, // 000D GETMBR R5 R0 K8 + 0x90121005, // 000E SETMBR R4 K8 R5 + 0x88140109, // 000F GETMBR R5 R0 K9 + 0x20140B07, // 0010 NE R5 R5 K7 + 0x7816000E, // 0011 JMPF R5 #0021 + 0x88140108, // 0012 GETMBR R5 R0 K8 + 0x7816000C, // 0013 JMPF R5 #0021 + 0x88140108, // 0014 GETMBR R5 R0 K8 + 0x88140B0A, // 0015 GETMBR R5 R5 K10 + 0x20140B07, // 0016 NE R5 R5 K7 + 0x78160008, // 0017 JMPF R5 #0021 + 0x88140108, // 0018 GETMBR R5 R0 K8 + 0x88140B0C, // 0019 GETMBR R5 R5 K12 + 0x8C140B0D, // 001A GETMET R5 R5 K13 + 0x7C140200, // 001B CALL R5 1 + 0x90121605, // 001C SETMBR R4 K11 R5 + 0x88140108, // 001D GETMBR R5 R0 K8 + 0x88140B0A, // 001E GETMBR R5 R5 K10 + 0x90121205, // 001F SETMBR R4 K9 R5 + 0x70020005, // 0020 JMP #0027 + 0x88140108, // 0021 GETMBR R5 R0 K8 + 0x88140B0E, // 0022 GETMBR R5 R5 K14 + 0x8C140B0D, // 0023 GETMET R5 R5 K13 + 0x7C140200, // 0024 CALL R5 1 + 0x90121605, // 0025 SETMBR R4 K11 R5 + 0x90121307, // 0026 SETMBR R4 K9 K7 + 0x90121F07, // 0027 SETMBR R4 K15 K7 + 0x90122001, // 0028 SETMBR R4 K16 R1 + 0x88140111, // 0029 GETMBR R5 R0 K17 + 0x90122205, // 002A SETMBR R4 K17 R5 + 0x88140112, // 002B GETMBR R5 R0 K18 + 0x90122405, // 002C SETMBR R4 K18 R5 + 0x88140113, // 002D GETMBR R5 R0 K19 + 0x78160002, // 002E JMPF R5 #0032 + 0x90122904, // 002F SETMBR R4 K20 K4 + 0x8814010B, // 0030 GETMBR R5 R0 K11 + 0x90122A05, // 0031 SETMBR R4 K21 R5 + 0x780A0001, // 0032 JMPF R2 #0035 + 0x58140004, // 0033 LDCONST R5 K4 + 0x70020000, // 0034 JMP #0036 + 0x58140007, // 0035 LDCONST R5 K7 + 0x90122605, // 0036 SETMBR R4 K19 R5 + 0x88140909, // 0037 GETMBR R5 R4 K9 + 0x1C140B07, // 0038 EQ R5 R5 K7 + 0x78160012, // 0039 JMPF R5 #004D + 0xB8162C00, // 003A GETNGBL R5 K22 + 0x8C140B17, // 003B GETMET R5 R5 K23 + 0x881C0910, // 003C GETMBR R7 R4 K16 + 0x7C140400, // 003D CALL R5 2 + 0x5C180A00, // 003E MOVE R6 R5 + 0x741A0004, // 003F JMPT R6 #0045 + 0x8C180718, // 0040 GETMET R6 R3 K24 + 0x58200019, // 0041 LDCONST R8 K25 + 0x88240910, // 0042 GETMBR R9 R4 K16 + 0x7C180600, // 0043 CALL R6 3 + 0x5C140C00, // 0044 MOVE R5 R6 + 0xB81A3400, // 0045 GETNGBL R6 K26 + 0x8C180D1B, // 0046 GETMET R6 R6 K27 + 0x8C200718, // 0047 GETMET R8 R3 K24 + 0x5828001C, // 0048 LDCONST R10 K28 + 0x5C2C0A00, // 0049 MOVE R11 R5 + 0x7C200600, // 004A CALL R8 3 + 0x5824001D, // 004B LDCONST R9 K29 + 0x7C180600, // 004C CALL R6 3 + 0x80040800, // 004D RET 1 R4 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: decode_header +********************************************************************/ +be_local_closure(Matter_Frame_decode_header, /* name */ + be_nested_proto( + 7, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[21]) { /* constants */ + /* K0 */ be_const_int(0), + /* K1 */ be_nested_str_weak(raw), + /* K2 */ be_nested_str_weak(flags), + /* K3 */ be_nested_str_weak(get), + /* K4 */ be_const_int(1), + /* K5 */ be_nested_str_weak(flag_s), + /* K6 */ be_nested_str_weak(getbits), + /* K7 */ be_const_int(2), + /* K8 */ be_nested_str_weak(flag_dsiz), + /* K9 */ be_const_int(3), + /* K10 */ be_nested_str_weak(sec_flags), + /* K11 */ be_nested_str_weak(sec_p), + /* K12 */ be_nested_str_weak(sec_c), + /* K13 */ be_nested_str_weak(sec_mx), + /* K14 */ be_nested_str_weak(sec_sesstype), + /* K15 */ be_nested_str_weak(local_session_id), + /* K16 */ be_nested_str_weak(message_counter), + /* K17 */ be_nested_str_weak(source_node_id), + /* K18 */ be_nested_str_weak(dest_node_id_8), + /* K19 */ be_nested_str_weak(dest_node_id_2), + /* K20 */ be_nested_str_weak(payload_idx), + }), + be_str_weak(decode_header), + &be_const_str_solidified, + ( &(const binstruction[121]) { /* code */ + 0x58040000, // 0000 LDCONST R1 K0 + 0x88080101, // 0001 GETMBR R2 R0 K1 + 0x8C0C0503, // 0002 GETMET R3 R2 K3 + 0x58140000, // 0003 LDCONST R5 K0 + 0x58180004, // 0004 LDCONST R6 K4 + 0x7C0C0600, // 0005 CALL R3 3 + 0x90020403, // 0006 SETMBR R0 K2 R3 + 0x880C0102, // 0007 GETMBR R3 R0 K2 + 0x541200F7, // 0008 LDINT R4 248 + 0x2C0C0604, // 0009 AND R3 R3 R4 + 0x200C0700, // 000A NE R3 R3 K0 + 0x780E0001, // 000B JMPF R3 #000E + 0x500C0000, // 000C LDBOOL R3 0 0 + 0x80040600, // 000D RET 1 R3 + 0x8C0C0506, // 000E GETMET R3 R2 K6 + 0x58140007, // 000F LDCONST R5 K7 + 0x58180004, // 0010 LDCONST R6 K4 + 0x7C0C0600, // 0011 CALL R3 3 + 0x90020A03, // 0012 SETMBR R0 K5 R3 + 0x8C0C0506, // 0013 GETMET R3 R2 K6 + 0x58140000, // 0014 LDCONST R5 K0 + 0x58180007, // 0015 LDCONST R6 K7 + 0x7C0C0600, // 0016 CALL R3 3 + 0x90021003, // 0017 SETMBR R0 K8 R3 + 0x880C0108, // 0018 GETMBR R3 R0 K8 + 0x1C0C0709, // 0019 EQ R3 R3 K9 + 0x780E0001, // 001A JMPF R3 #001D + 0x500C0000, // 001B LDBOOL R3 0 0 + 0x80040600, // 001C RET 1 R3 + 0x8C0C0503, // 001D GETMET R3 R2 K3 + 0x58140009, // 001E LDCONST R5 K9 + 0x58180004, // 001F LDCONST R6 K4 + 0x7C0C0600, // 0020 CALL R3 3 + 0x90021403, // 0021 SETMBR R0 K10 R3 + 0x8C0C0506, // 0022 GETMET R3 R2 K6 + 0x54160007, // 0023 LDINT R5 8 + 0x08161205, // 0024 MUL R5 K9 R5 + 0x541A0006, // 0025 LDINT R6 7 + 0x00140A06, // 0026 ADD R5 R5 R6 + 0x58180004, // 0027 LDCONST R6 K4 + 0x7C0C0600, // 0028 CALL R3 3 + 0x90021603, // 0029 SETMBR R0 K11 R3 + 0x8C0C0506, // 002A GETMET R3 R2 K6 + 0x54160007, // 002B LDINT R5 8 + 0x08161205, // 002C MUL R5 K9 R5 + 0x541A0005, // 002D LDINT R6 6 + 0x00140A06, // 002E ADD R5 R5 R6 + 0x58180004, // 002F LDCONST R6 K4 + 0x7C0C0600, // 0030 CALL R3 3 + 0x90021803, // 0031 SETMBR R0 K12 R3 + 0x8C0C0506, // 0032 GETMET R3 R2 K6 + 0x54160007, // 0033 LDINT R5 8 + 0x08161205, // 0034 MUL R5 K9 R5 + 0x541A0004, // 0035 LDINT R6 5 + 0x00140A06, // 0036 ADD R5 R5 R6 + 0x58180004, // 0037 LDCONST R6 K4 + 0x7C0C0600, // 0038 CALL R3 3 + 0x90021A03, // 0039 SETMBR R0 K13 R3 + 0x8C0C0506, // 003A GETMET R3 R2 K6 + 0x54160007, // 003B LDINT R5 8 + 0x08161205, // 003C MUL R5 K9 R5 + 0x58180007, // 003D LDCONST R6 K7 + 0x7C0C0600, // 003E CALL R3 3 + 0x90021C03, // 003F SETMBR R0 K14 R3 + 0x880C010E, // 0040 GETMBR R3 R0 K14 + 0x240C0704, // 0041 GT R3 R3 K4 + 0x780E0001, // 0042 JMPF R3 #0045 + 0x500C0000, // 0043 LDBOOL R3 0 0 + 0x80040600, // 0044 RET 1 R3 + 0x8C0C0503, // 0045 GETMET R3 R2 K3 + 0x58140004, // 0046 LDCONST R5 K4 + 0x58180007, // 0047 LDCONST R6 K7 + 0x7C0C0600, // 0048 CALL R3 3 + 0x90021E03, // 0049 SETMBR R0 K15 R3 + 0x8C0C0503, // 004A GETMET R3 R2 K3 + 0x54160003, // 004B LDINT R5 4 + 0x541A0003, // 004C LDINT R6 4 + 0x7C0C0600, // 004D CALL R3 3 + 0x90022003, // 004E SETMBR R0 K16 R3 + 0x540E0007, // 004F LDINT R3 8 + 0x00040203, // 0050 ADD R1 R1 R3 + 0x880C0105, // 0051 GETMBR R3 R0 K5 + 0x780E0006, // 0052 JMPF R3 #005A + 0x540E0006, // 0053 LDINT R3 7 + 0x000C0203, // 0054 ADD R3 R1 R3 + 0x400C0203, // 0055 CONNECT R3 R1 R3 + 0x940C0403, // 0056 GETIDX R3 R2 R3 + 0x90022203, // 0057 SETMBR R0 K17 R3 + 0x540E0007, // 0058 LDINT R3 8 + 0x00040203, // 0059 ADD R1 R1 R3 + 0x880C0108, // 005A GETMBR R3 R0 K8 + 0x1C0C0704, // 005B EQ R3 R3 K4 + 0x780E0007, // 005C JMPF R3 #0065 + 0x540E0006, // 005D LDINT R3 7 + 0x000C0203, // 005E ADD R3 R1 R3 + 0x400C0203, // 005F CONNECT R3 R1 R3 + 0x940C0403, // 0060 GETIDX R3 R2 R3 + 0x90022403, // 0061 SETMBR R0 K18 R3 + 0x540E0007, // 0062 LDINT R3 8 + 0x00040203, // 0063 ADD R1 R1 R3 + 0x70020008, // 0064 JMP #006E + 0x880C0108, // 0065 GETMBR R3 R0 K8 + 0x1C0C0707, // 0066 EQ R3 R3 K7 + 0x780E0005, // 0067 JMPF R3 #006E + 0x8C0C0503, // 0068 GETMET R3 R2 K3 + 0x5C140200, // 0069 MOVE R5 R1 + 0x58180007, // 006A LDCONST R6 K7 + 0x7C0C0600, // 006B CALL R3 3 + 0x90022603, // 006C SETMBR R0 K19 R3 + 0x00040307, // 006D ADD R1 R1 K7 + 0x880C010D, // 006E GETMBR R3 R0 K13 + 0x780E0005, // 006F JMPF R3 #0076 + 0x8C0C0503, // 0070 GETMET R3 R2 K3 + 0x5C140200, // 0071 MOVE R5 R1 + 0x58180007, // 0072 LDCONST R6 K7 + 0x7C0C0600, // 0073 CALL R3 3 + 0x00100707, // 0074 ADD R4 R3 K7 + 0x00040204, // 0075 ADD R1 R1 R4 + 0x90022801, // 0076 SETMBR R0 K20 R1 + 0x500C0200, // 0077 LDBOOL R3 1 0 + 0x80040600, // 0078 RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_Frame +********************************************************************/ +be_local_class(Matter_Frame, + 30, + NULL, + be_nested_map(39, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(ack_message_counter, -1), be_const_var(27) }, + { be_const_key_weak(x_flag_r, -1), be_const_var(20) }, + { be_const_key_weak(dest_node_id_2, -1), be_const_var(15) }, + { be_const_key_weak(message_counter, -1), be_const_var(13) }, + { be_const_key_weak(sec_p, 15), be_const_var(9) }, + { be_const_key_weak(init, -1), be_const_closure(Matter_Frame_init_closure) }, + { be_const_key_weak(protocol_id, 31), be_const_var(25) }, + { be_const_key_weak(session, -1), be_const_var(1) }, + { be_const_key_weak(sec_flags, 13), be_const_var(8) }, + { be_const_key_weak(x_flag_sx, 20), be_const_var(19) }, + { be_const_key_weak(sec_mx, -1), be_const_var(11) }, + { be_const_key_weak(encode, -1), be_const_closure(Matter_Frame_encode_closure) }, + { be_const_key_weak(local_session_id, -1), be_const_var(7) }, + { be_const_key_weak(flags, 38), be_const_var(4) }, + { be_const_key_weak(exchange_id, -1), be_const_var(24) }, + { be_const_key_weak(payload_idx, 10), be_const_var(3) }, + { be_const_key_weak(dest_node_id_8, -1), be_const_var(16) }, + { be_const_key_weak(x_flag_i, -1), be_const_var(22) }, + { be_const_key_weak(flag_s, -1), be_const_var(5) }, + { be_const_key_weak(app_payload_idx, 14), be_const_var(29) }, + { be_const_key_weak(flag_dsiz, 12), be_const_var(6) }, + { be_const_key_weak(encrypt, -1), be_const_closure(Matter_Frame_encrypt_closure) }, + { be_const_key_weak(x_flags, -1), be_const_var(17) }, + { be_const_key_weak(x_flag_v, 22), be_const_var(18) }, + { be_const_key_weak(sec_sesstype, -1), be_const_var(12) }, + { be_const_key_weak(x_flag_a, -1), be_const_var(21) }, + { be_const_key_weak(message_handler, 28), be_const_var(0) }, + { be_const_key_weak(sec_extensions, 24), be_const_var(28) }, + { be_const_key_weak(raw, -1), be_const_var(2) }, + { be_const_key_weak(opcode, -1), be_const_var(23) }, + { be_const_key_weak(sec_c, 17), be_const_var(10) }, + { be_const_key_weak(decode_payload, 5), be_const_closure(Matter_Frame_decode_payload_closure) }, + { be_const_key_weak(build_standalone_ack, 2), be_const_closure(Matter_Frame_build_standalone_ack_closure) }, + { be_const_key_weak(vendor_id, -1), be_const_var(26) }, + { be_const_key_weak(debug, -1), be_const_closure(Matter_Frame_debug_closure) }, + { be_const_key_weak(source_node_id, 11), be_const_var(14) }, + { be_const_key_weak(build_response, -1), be_const_closure(Matter_Frame_build_response_closure) }, + { be_const_key_weak(decode_header, -1), be_const_closure(Matter_Frame_decode_header_closure) }, + { be_const_key_weak(decrypt, -1), be_const_closure(Matter_Frame_decrypt_closure) }, + })), + be_str_weak(Matter_Frame) +); +/*******************************************************************/ + +void be_load_Matter_Frame_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Frame); + be_setglobal(vm, "Matter_Frame"); + be_pop(vm, 1); +} +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_MessageHandler.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_MessageHandler.h new file mode 100644 index 000000000..d5e22cd1b --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_MessageHandler.h @@ -0,0 +1,582 @@ +/* Solidification of Matter_MessageHandler.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_MessageHandler; + +/******************************************************************** +** Solidified function: send_response +********************************************************************/ +be_local_closure(Matter_MessageHandler_send_response, /* name */ + be_nested_proto( + 11, /* nstack */ + 5, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(device), + /* K1 */ be_nested_str_weak(msg_send), + }), + be_str_weak(send_response), + &be_const_str_solidified, + ( &(const binstruction[ 8]) { /* code */ + 0x88140100, // 0000 GETMBR R5 R0 K0 + 0x8C140B01, // 0001 GETMET R5 R5 K1 + 0x5C1C0200, // 0002 MOVE R7 R1 + 0x5C200400, // 0003 MOVE R8 R2 + 0x5C240600, // 0004 MOVE R9 R3 + 0x5C280800, // 0005 MOVE R10 R4 + 0x7C140A00, // 0006 CALL R5 5 + 0x80000000, // 0007 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: msg_received +********************************************************************/ +be_local_closure(Matter_MessageHandler_msg_received, /* name */ + be_nested_proto( + 17, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[59]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(log), + /* K3 */ be_nested_str_weak(MTR_X3A_X20MessageHandler_X3A_X3Amsg_received_X20raw_X3D), + /* K4 */ be_nested_str_weak(tohex), + /* K5 */ be_nested_str_weak(matter), + /* K6 */ be_nested_str_weak(Frame), + /* K7 */ be_nested_str_weak(decode_header), + /* K8 */ be_nested_str_weak(local_session_id), + /* K9 */ be_const_int(0), + /* K10 */ be_nested_str_weak(sec_sesstype), + /* K11 */ be_nested_str_weak(device), + /* K12 */ be_nested_str_weak(sessions), + /* K13 */ be_nested_str_weak(find_session_source_id_unsecure), + /* K14 */ be_nested_str_weak(source_node_id), + /* K15 */ be_nested_str_weak(MTR_X3A_X20find_X20session_X20by_X20source_node_id_X20_X3D_X20), + /* K16 */ be_nested_str_weak(session_id_X20_X3D_X20), + /* K17 */ be_const_int(3), + /* K18 */ be_nested_str_weak(session), + /* K19 */ be_nested_str_weak(counter_rcv), + /* K20 */ be_nested_str_weak(validate), + /* K21 */ be_nested_str_weak(message_counter), + /* K22 */ be_nested_str_weak(format), + /* K23 */ be_nested_str_weak(MTR_X3A_X20rejected_X20duplicate_X20unencrypted_X20message_X20_X3D_X20_X25i_X20ref_X20_X3D_X20_X25i), + /* K24 */ be_nested_str_weak(val), + /* K25 */ be_nested_str_weak(decode_payload), + /* K26 */ be_nested_str_weak(packet_ack), + /* K27 */ be_nested_str_weak(ack_message_counter), + /* K28 */ be_nested_str_weak(opcode), + /* K29 */ be_nested_str_weak(get_opcode_name), + /* K30 */ be_nested_str_weak(0x_X2502X), + /* K31 */ be_nested_str_weak(MTR_X3A_X20_X3EReceived_X20_X20_X20_X20_X20_X20_X25s_X20from_X20_X5B_X25s_X5D_X3A_X25i), + /* K32 */ be_const_int(2), + /* K33 */ be_nested_str_weak(commissioning), + /* K34 */ be_nested_str_weak(process_incoming), + /* K35 */ be_nested_str_weak(MTR_X3A_X20decode_X20header_X3A_X20local_session_id_X3D_X25i_X20message_counter_X3D_X25i), + /* K36 */ be_nested_str_weak(get_session_by_local_session_id), + /* K37 */ be_nested_str_weak(MTR_X3A_X20unknown_X20local_session_id_X20), + /* K38 */ be_nested_str_weak(MTR_X3A_X20frame_X3D), + /* K39 */ be_nested_str_weak(inspect), + /* K40 */ be_nested_str_weak(MTR_X3A_X20rejected_X20duplicate_X20encrypted_X20message_X20_X3D_X20), + /* K41 */ be_nested_str_weak(_X20counter_X3D), + /* K42 */ be_nested_str_weak(decrypt), + /* K43 */ be_nested_str_weak(raw), + /* K44 */ be_nested_str_weak(payload_idx), + /* K45 */ be_const_int(1), + /* K46 */ be_nested_str_weak(MTR_X3A_X20idx_X3D_X25i_X20clear_X3D_X25s), + /* K47 */ be_nested_str_weak(MTR_X3A_X20decrypted_X20message_X3A_X20protocol_id_X3A), + /* K48 */ be_nested_str_weak(protocol_id), + /* K49 */ be_nested_str_weak(_X20opcode_X3D), + /* K50 */ be_nested_str_weak(_X20exchange_id), + /* K51 */ be_nested_str_weak(exchange_id), + /* K52 */ be_nested_str_weak(MTR_X3A_X20PROTOCOL_ID_SECURE_CHANNEL_X20), + /* K53 */ be_nested_str_weak(im), + /* K54 */ be_nested_str_weak(MTR_X3A_X20ignoring_X20unhandled_X20protocol_id_X3A), + /* K55 */ be_nested_str_weak(MTR_X3A_X20MessageHandler_X3A_X3Amsg_received_X20exception_X3A_X20), + /* K56 */ be_nested_str_weak(_X3B), + /* K57 */ be_nested_str_weak(debug), + /* K58 */ be_nested_str_weak(traceback), + }), + be_str_weak(msg_received), + &be_const_str_solidified, + ( &(const binstruction[289]) { /* code */ + 0xA4120000, // 0000 IMPORT R4 K0 + 0xA8020108, // 0001 EXBLK 0 #010B + 0xB8160200, // 0002 GETNGBL R5 K1 + 0x8C140B02, // 0003 GETMET R5 R5 K2 + 0x8C1C0304, // 0004 GETMET R7 R1 K4 + 0x7C1C0200, // 0005 CALL R7 1 + 0x001E0607, // 0006 ADD R7 K3 R7 + 0x54220003, // 0007 LDINT R8 4 + 0x7C140600, // 0008 CALL R5 3 + 0xB8160A00, // 0009 GETNGBL R5 K5 + 0x8C140B06, // 000A GETMET R5 R5 K6 + 0x5C1C0000, // 000B MOVE R7 R0 + 0x5C200200, // 000C MOVE R8 R1 + 0x7C140600, // 000D CALL R5 3 + 0x8C180B07, // 000E GETMET R6 R5 K7 + 0x7C180200, // 000F CALL R6 1 + 0x5C1C0C00, // 0010 MOVE R7 R6 + 0x741E0002, // 0011 JMPT R7 #0015 + 0x501C0000, // 0012 LDBOOL R7 0 0 + 0xA8040001, // 0013 EXBLK 1 1 + 0x80040E00, // 0014 RET 1 R7 + 0x881C0B08, // 0015 GETMBR R7 R5 K8 + 0x1C1C0F09, // 0016 EQ R7 R7 K9 + 0x781E0057, // 0017 JMPF R7 #0070 + 0x881C0B0A, // 0018 GETMBR R7 R5 K10 + 0x1C1C0F09, // 0019 EQ R7 R7 K9 + 0x781E0054, // 001A JMPF R7 #0070 + 0x881C010B, // 001B GETMBR R7 R0 K11 + 0x881C0F0C, // 001C GETMBR R7 R7 K12 + 0x8C1C0F0D, // 001D GETMET R7 R7 K13 + 0x88240B0E, // 001E GETMBR R9 R5 K14 + 0x542A0059, // 001F LDINT R10 90 + 0x7C1C0600, // 0020 CALL R7 3 + 0xB8220200, // 0021 GETNGBL R8 K1 + 0x8C201102, // 0022 GETMET R8 R8 K2 + 0x60280008, // 0023 GETGBL R10 G8 + 0x882C0B0E, // 0024 GETMBR R11 R5 K14 + 0x7C280200, // 0025 CALL R10 1 + 0x002A1E0A, // 0026 ADD R10 K15 R10 + 0x00281510, // 0027 ADD R10 R10 K16 + 0x602C0008, // 0028 GETGBL R11 G8 + 0x88300F08, // 0029 GETMBR R12 R7 K8 + 0x7C2C0200, // 002A CALL R11 1 + 0x0028140B, // 002B ADD R10 R10 R11 + 0x582C0011, // 002C LDCONST R11 K17 + 0x7C200600, // 002D CALL R8 3 + 0x90162407, // 002E SETMBR R5 K18 R7 + 0x88200113, // 002F GETMBR R8 R0 K19 + 0x8C201114, // 0030 GETMET R8 R8 K20 + 0x88280B15, // 0031 GETMBR R10 R5 K21 + 0x502C0000, // 0032 LDBOOL R11 0 0 + 0x7C200600, // 0033 CALL R8 3 + 0x7422000D, // 0034 JMPT R8 #0043 + 0xB8220200, // 0035 GETNGBL R8 K1 + 0x8C201102, // 0036 GETMET R8 R8 K2 + 0x8C280916, // 0037 GETMET R10 R4 K22 + 0x58300017, // 0038 LDCONST R12 K23 + 0x88340B15, // 0039 GETMBR R13 R5 K21 + 0x88380113, // 003A GETMBR R14 R0 K19 + 0x8C381D18, // 003B GETMET R14 R14 K24 + 0x7C380200, // 003C CALL R14 1 + 0x7C280800, // 003D CALL R10 4 + 0x582C0011, // 003E LDCONST R11 K17 + 0x7C200600, // 003F CALL R8 3 + 0x50200000, // 0040 LDBOOL R8 0 0 + 0xA8040001, // 0041 EXBLK 1 1 + 0x80041000, // 0042 RET 1 R8 + 0x8C200B19, // 0043 GETMET R8 R5 K25 + 0x7C200200, // 0044 CALL R8 1 + 0x74220002, // 0045 JMPT R8 #0049 + 0x50200000, // 0046 LDBOOL R8 0 0 + 0xA8040001, // 0047 EXBLK 1 1 + 0x80041000, // 0048 RET 1 R8 + 0x8820010B, // 0049 GETMBR R8 R0 K11 + 0x8C20111A, // 004A GETMET R8 R8 K26 + 0x88280B1B, // 004B GETMBR R10 R5 K27 + 0x7C200400, // 004C CALL R8 2 + 0x88200B1C, // 004D GETMBR R8 R5 K28 + 0x5426000F, // 004E LDINT R9 16 + 0x20201009, // 004F NE R8 R8 R9 + 0x78220014, // 0050 JMPF R8 #0066 + 0xB8220A00, // 0051 GETNGBL R8 K5 + 0x8C20111D, // 0052 GETMET R8 R8 K29 + 0x88280B1C, // 0053 GETMBR R10 R5 K28 + 0x7C200400, // 0054 CALL R8 2 + 0x5C241000, // 0055 MOVE R9 R8 + 0x74260004, // 0056 JMPT R9 #005C + 0x8C240916, // 0057 GETMET R9 R4 K22 + 0x582C001E, // 0058 LDCONST R11 K30 + 0x88300B1C, // 0059 GETMBR R12 R5 K28 + 0x7C240600, // 005A CALL R9 3 + 0x5C201200, // 005B MOVE R8 R9 + 0xB8260200, // 005C GETNGBL R9 K1 + 0x8C241302, // 005D GETMET R9 R9 K2 + 0x8C2C0916, // 005E GETMET R11 R4 K22 + 0x5834001F, // 005F LDCONST R13 K31 + 0x5C381000, // 0060 MOVE R14 R8 + 0x5C3C0400, // 0061 MOVE R15 R2 + 0x5C400600, // 0062 MOVE R16 R3 + 0x7C2C0A00, // 0063 CALL R11 5 + 0x58300020, // 0064 LDCONST R12 K32 + 0x7C240600, // 0065 CALL R9 3 + 0x88200121, // 0066 GETMBR R8 R0 K33 + 0x8C201122, // 0067 GETMET R8 R8 K34 + 0x5C280A00, // 0068 MOVE R10 R5 + 0x5C2C0400, // 0069 MOVE R11 R2 + 0x5C300600, // 006A MOVE R12 R3 + 0x7C200800, // 006B CALL R8 4 + 0x50200200, // 006C LDBOOL R8 1 0 + 0xA8040001, // 006D EXBLK 1 1 + 0x80041000, // 006E RET 1 R8 + 0x70020095, // 006F JMP #0106 + 0xB81E0200, // 0070 GETNGBL R7 K1 + 0x8C1C0F02, // 0071 GETMET R7 R7 K2 + 0x8C240916, // 0072 GETMET R9 R4 K22 + 0x582C0023, // 0073 LDCONST R11 K35 + 0x88300B08, // 0074 GETMBR R12 R5 K8 + 0x88340B15, // 0075 GETMBR R13 R5 K21 + 0x7C240800, // 0076 CALL R9 4 + 0x58280011, // 0077 LDCONST R10 K17 + 0x7C1C0600, // 0078 CALL R7 3 + 0x881C010B, // 0079 GETMBR R7 R0 K11 + 0x881C0F0C, // 007A GETMBR R7 R7 K12 + 0x8C1C0F24, // 007B GETMET R7 R7 K36 + 0x88240B08, // 007C GETMBR R9 R5 K8 + 0x7C1C0400, // 007D CALL R7 2 + 0x4C200000, // 007E LDNIL R8 + 0x1C200E08, // 007F EQ R8 R7 R8 + 0x78220013, // 0080 JMPF R8 #0095 + 0xB8220200, // 0081 GETNGBL R8 K1 + 0x8C201102, // 0082 GETMET R8 R8 K2 + 0x60280008, // 0083 GETGBL R10 G8 + 0x882C0B08, // 0084 GETMBR R11 R5 K8 + 0x7C280200, // 0085 CALL R10 1 + 0x002A4A0A, // 0086 ADD R10 K37 R10 + 0x582C0011, // 0087 LDCONST R11 K17 + 0x7C200600, // 0088 CALL R8 3 + 0xB8220200, // 0089 GETNGBL R8 K1 + 0x8C201102, // 008A GETMET R8 R8 K2 + 0xB82A0A00, // 008B GETNGBL R10 K5 + 0x8C281527, // 008C GETMET R10 R10 K39 + 0x5C300A00, // 008D MOVE R12 R5 + 0x7C280400, // 008E CALL R10 2 + 0x002A4C0A, // 008F ADD R10 K38 R10 + 0x582C0011, // 0090 LDCONST R11 K17 + 0x7C200600, // 0091 CALL R8 3 + 0x50200000, // 0092 LDBOOL R8 0 0 + 0xA8040001, // 0093 EXBLK 1 1 + 0x80041000, // 0094 RET 1 R8 + 0x90162407, // 0095 SETMBR R5 K18 R7 + 0x88200F13, // 0096 GETMBR R8 R7 K19 + 0x8C201114, // 0097 GETMET R8 R8 K20 + 0x88280B15, // 0098 GETMBR R10 R5 K21 + 0x502C0200, // 0099 LDBOOL R11 1 0 + 0x7C200600, // 009A CALL R8 3 + 0x74220011, // 009B JMPT R8 #00AE + 0xB8220200, // 009C GETNGBL R8 K1 + 0x8C201102, // 009D GETMET R8 R8 K2 + 0x60280008, // 009E GETGBL R10 G8 + 0x882C0B15, // 009F GETMBR R11 R5 K21 + 0x7C280200, // 00A0 CALL R10 1 + 0x002A500A, // 00A1 ADD R10 K40 R10 + 0x00281529, // 00A2 ADD R10 R10 K41 + 0x602C0008, // 00A3 GETGBL R11 G8 + 0x88300F13, // 00A4 GETMBR R12 R7 K19 + 0x8C301918, // 00A5 GETMET R12 R12 K24 + 0x7C300200, // 00A6 CALL R12 1 + 0x7C2C0200, // 00A7 CALL R11 1 + 0x0028140B, // 00A8 ADD R10 R10 R11 + 0x582C0011, // 00A9 LDCONST R11 K17 + 0x7C200600, // 00AA CALL R8 3 + 0x50200000, // 00AB LDBOOL R8 0 0 + 0xA8040001, // 00AC EXBLK 1 1 + 0x80041000, // 00AD RET 1 R8 + 0x8C200B2A, // 00AE GETMET R8 R5 K42 + 0x7C200200, // 00AF CALL R8 1 + 0x5C241000, // 00B0 MOVE R9 R8 + 0x74260002, // 00B1 JMPT R9 #00B5 + 0x50240000, // 00B2 LDBOOL R9 0 0 + 0xA8040001, // 00B3 EXBLK 1 1 + 0x80041200, // 00B4 RET 1 R9 + 0x88240B2C, // 00B5 GETMBR R9 R5 K44 + 0x0424132D, // 00B6 SUB R9 R9 K45 + 0x40261209, // 00B7 CONNECT R9 K9 R9 + 0x88280B2B, // 00B8 GETMBR R10 R5 K43 + 0x94241409, // 00B9 GETIDX R9 R10 R9 + 0x90165609, // 00BA SETMBR R5 K43 R9 + 0x88240B2B, // 00BB GETMBR R9 R5 K43 + 0x40241208, // 00BC CONNECT R9 R9 R8 + 0xB8260200, // 00BD GETNGBL R9 K1 + 0x8C241302, // 00BE GETMET R9 R9 K2 + 0x8C2C0916, // 00BF GETMET R11 R4 K22 + 0x5834002E, // 00C0 LDCONST R13 K46 + 0x88380B2C, // 00C1 GETMBR R14 R5 K44 + 0x883C0B2B, // 00C2 GETMBR R15 R5 K43 + 0x8C3C1F04, // 00C3 GETMET R15 R15 K4 + 0x7C3C0200, // 00C4 CALL R15 1 + 0x7C2C0800, // 00C5 CALL R11 4 + 0x58300011, // 00C6 LDCONST R12 K17 + 0x7C240600, // 00C7 CALL R9 3 + 0x8C240B19, // 00C8 GETMET R9 R5 K25 + 0x7C240200, // 00C9 CALL R9 1 + 0xB8260200, // 00CA GETNGBL R9 K1 + 0x8C241302, // 00CB GETMET R9 R9 K2 + 0x602C0008, // 00CC GETGBL R11 G8 + 0x88300B30, // 00CD GETMBR R12 R5 K48 + 0x7C2C0200, // 00CE CALL R11 1 + 0x002E5E0B, // 00CF ADD R11 K47 R11 + 0x002C1731, // 00D0 ADD R11 R11 K49 + 0x60300008, // 00D1 GETGBL R12 G8 + 0x88340B1C, // 00D2 GETMBR R13 R5 K28 + 0x7C300200, // 00D3 CALL R12 1 + 0x002C160C, // 00D4 ADD R11 R11 R12 + 0x002C1732, // 00D5 ADD R11 R11 K50 + 0x60300008, // 00D6 GETGBL R12 G8 + 0x88340B33, // 00D7 GETMBR R13 R5 K51 + 0x7C300200, // 00D8 CALL R12 1 + 0x002C160C, // 00D9 ADD R11 R11 R12 + 0x58300011, // 00DA LDCONST R12 K17 + 0x7C240600, // 00DB CALL R9 3 + 0x8824010B, // 00DC GETMBR R9 R0 K11 + 0x8C24131A, // 00DD GETMET R9 R9 K26 + 0x882C0B1B, // 00DE GETMBR R11 R5 K27 + 0x7C240400, // 00DF CALL R9 2 + 0x88240B30, // 00E0 GETMBR R9 R5 K48 + 0x1C281309, // 00E1 EQ R10 R9 K9 + 0x782A000C, // 00E2 JMPF R10 #00F0 + 0xB82A0200, // 00E3 GETNGBL R10 K1 + 0x8C281502, // 00E4 GETMET R10 R10 K2 + 0xB8320A00, // 00E5 GETNGBL R12 K5 + 0x8C301927, // 00E6 GETMET R12 R12 K39 + 0x5C380A00, // 00E7 MOVE R14 R5 + 0x7C300400, // 00E8 CALL R12 2 + 0x0032680C, // 00E9 ADD R12 K52 R12 + 0x58340011, // 00EA LDCONST R13 K17 + 0x7C280600, // 00EB CALL R10 3 + 0x50280200, // 00EC LDBOOL R10 1 0 + 0xA8040001, // 00ED EXBLK 1 1 + 0x80041400, // 00EE RET 1 R10 + 0x70020015, // 00EF JMP #0106 + 0x1C28132D, // 00F0 EQ R10 R9 K45 + 0x782A0008, // 00F1 JMPF R10 #00FB + 0x88280135, // 00F2 GETMBR R10 R0 K53 + 0x8C281522, // 00F3 GETMET R10 R10 K34 + 0x5C300A00, // 00F4 MOVE R12 R5 + 0x5C340400, // 00F5 MOVE R13 R2 + 0x5C380600, // 00F6 MOVE R14 R3 + 0x7C280800, // 00F7 CALL R10 4 + 0xA8040001, // 00F8 EXBLK 1 1 + 0x80041400, // 00F9 RET 1 R10 + 0x7002000A, // 00FA JMP #0106 + 0xB82A0200, // 00FB GETNGBL R10 K1 + 0x8C281502, // 00FC GETMET R10 R10 K2 + 0x60300008, // 00FD GETGBL R12 G8 + 0x5C341200, // 00FE MOVE R13 R9 + 0x7C300200, // 00FF CALL R12 1 + 0x00326C0C, // 0100 ADD R12 K54 R12 + 0x58340011, // 0101 LDCONST R13 K17 + 0x7C280600, // 0102 CALL R10 3 + 0x50280000, // 0103 LDBOOL R10 0 0 + 0xA8040001, // 0104 EXBLK 1 1 + 0x80041400, // 0105 RET 1 R10 + 0x501C0200, // 0106 LDBOOL R7 1 0 + 0xA8040001, // 0107 EXBLK 1 1 + 0x80040E00, // 0108 RET 1 R7 + 0xA8040001, // 0109 EXBLK 1 1 + 0x70020014, // 010A JMP #0120 + 0xAC140002, // 010B CATCH R5 0 2 + 0x70020011, // 010C JMP #011F + 0xB81E0200, // 010D GETNGBL R7 K1 + 0x8C1C0F02, // 010E GETMET R7 R7 K2 + 0x60240008, // 010F GETGBL R9 G8 + 0x5C280A00, // 0110 MOVE R10 R5 + 0x7C240200, // 0111 CALL R9 1 + 0x00266E09, // 0112 ADD R9 K55 R9 + 0x00241338, // 0113 ADD R9 R9 K56 + 0x60280008, // 0114 GETGBL R10 G8 + 0x5C2C0C00, // 0115 MOVE R11 R6 + 0x7C280200, // 0116 CALL R10 1 + 0x0024120A, // 0117 ADD R9 R9 R10 + 0x7C1C0400, // 0118 CALL R7 2 + 0xA41E7200, // 0119 IMPORT R7 K57 + 0x8C200F3A, // 011A GETMET R8 R7 K58 + 0x7C200200, // 011B CALL R8 1 + 0x50200000, // 011C LDBOOL R8 0 0 + 0x80041000, // 011D RET 1 R8 + 0x70020000, // 011E JMP #0120 + 0xB0080000, // 011F RAISE 2 R0 R0 + 0x80000000, // 0120 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: add_session +********************************************************************/ +be_local_closure(Matter_MessageHandler_add_session, /* name */ + be_nested_proto( + 15, /* nstack */ + 7, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[10]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(log), + /* K3 */ be_nested_str_weak(format), + /* K4 */ be_nested_str_weak(MTR_X3A_X20add_session_X20local_session_id_X3D_X25i_X20initiator_session_id_X3D_X25i), + /* K5 */ be_const_int(3), + /* K6 */ be_nested_str_weak(device), + /* K7 */ be_nested_str_weak(sessions), + /* K8 */ be_nested_str_weak(create_session), + /* K9 */ be_nested_str_weak(set_keys), + }), + be_str_weak(add_session), + &be_const_str_solidified, + ( &(const binstruction[23]) { /* code */ + 0xA41E0000, // 0000 IMPORT R7 K0 + 0xB8220200, // 0001 GETNGBL R8 K1 + 0x8C201102, // 0002 GETMET R8 R8 K2 + 0x8C280F03, // 0003 GETMET R10 R7 K3 + 0x58300004, // 0004 LDCONST R12 K4 + 0x5C340200, // 0005 MOVE R13 R1 + 0x5C380400, // 0006 MOVE R14 R2 + 0x7C280800, // 0007 CALL R10 4 + 0x582C0005, // 0008 LDCONST R11 K5 + 0x7C200600, // 0009 CALL R8 3 + 0x88200106, // 000A GETMBR R8 R0 K6 + 0x88201107, // 000B GETMBR R8 R8 K7 + 0x8C201108, // 000C GETMET R8 R8 K8 + 0x5C280200, // 000D MOVE R10 R1 + 0x5C2C0400, // 000E MOVE R11 R2 + 0x7C200600, // 000F CALL R8 3 + 0x8C241109, // 0010 GETMET R9 R8 K9 + 0x5C2C0600, // 0011 MOVE R11 R3 + 0x5C300800, // 0012 MOVE R12 R4 + 0x5C340A00, // 0013 MOVE R13 R5 + 0x5C380C00, // 0014 MOVE R14 R6 + 0x7C240A00, // 0015 CALL R9 5 + 0x80000000, // 0016 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_MessageHandler_init, /* name */ + be_nested_proto( + 5, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(device), + /* K1 */ be_nested_str_weak(commissioning), + /* K2 */ be_nested_str_weak(matter), + /* K3 */ be_nested_str_weak(Commisioning_Context), + /* K4 */ be_nested_str_weak(im), + /* K5 */ be_nested_str_weak(IM), + /* K6 */ be_nested_str_weak(counter_rcv), + /* K7 */ be_nested_str_weak(Counter), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[16]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0xB80A0400, // 0001 GETNGBL R2 K2 + 0x8C080503, // 0002 GETMET R2 R2 K3 + 0x5C100000, // 0003 MOVE R4 R0 + 0x7C080400, // 0004 CALL R2 2 + 0x90020202, // 0005 SETMBR R0 K1 R2 + 0xB80A0400, // 0006 GETNGBL R2 K2 + 0x8C080505, // 0007 GETMET R2 R2 K5 + 0x5C100000, // 0008 MOVE R4 R0 + 0x7C080400, // 0009 CALL R2 2 + 0x90020802, // 000A SETMBR R0 K4 R2 + 0xB80A0400, // 000B GETNGBL R2 K2 + 0x8C080507, // 000C GETMET R2 R2 K7 + 0x7C080200, // 000D CALL R2 1 + 0x90020C02, // 000E SETMBR R0 K6 R2 + 0x80000000, // 000F RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: every_second +********************************************************************/ +be_local_closure(Matter_MessageHandler_every_second, /* name */ + be_nested_proto( + 3, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(commissioning), + /* K1 */ be_nested_str_weak(every_second), + /* K2 */ be_nested_str_weak(im), + }), + be_str_weak(every_second), + &be_const_str_solidified, + ( &(const binstruction[ 7]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0x7C040200, // 0002 CALL R1 1 + 0x88040102, // 0003 GETMBR R1 R0 K2 + 0x8C040301, // 0004 GETMET R1 R1 K1 + 0x7C040200, // 0005 CALL R1 1 + 0x80000000, // 0006 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_MessageHandler +********************************************************************/ +be_local_class(Matter_MessageHandler, + 4, + NULL, + be_nested_map(9, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(every_second, -1), be_const_closure(Matter_MessageHandler_every_second_closure) }, + { be_const_key_weak(msg_received, -1), be_const_closure(Matter_MessageHandler_msg_received_closure) }, + { be_const_key_weak(counter_rcv, -1), be_const_var(3) }, + { be_const_key_weak(commissioning, 0), be_const_var(1) }, + { be_const_key_weak(device, 5), be_const_var(0) }, + { be_const_key_weak(init, 8), be_const_closure(Matter_MessageHandler_init_closure) }, + { be_const_key_weak(send_response, 4), be_const_closure(Matter_MessageHandler_send_response_closure) }, + { be_const_key_weak(add_session, 2), be_const_closure(Matter_MessageHandler_add_session_closure) }, + { be_const_key_weak(im, -1), be_const_var(2) }, + })), + be_str_weak(Matter_MessageHandler) +); +/*******************************************************************/ + +void be_load_Matter_MessageHandler_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_MessageHandler); + be_setglobal(vm, "Matter_MessageHandler"); + be_pop(vm, 1); +} +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Module.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Module.h new file mode 100644 index 000000000..727ae6d36 --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Module.h @@ -0,0 +1,90 @@ +/* Solidification of Matter_Module.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +/******************************************************************** +** Solidified function: setmember +********************************************************************/ +be_local_closure(matter_setmember, /* name */ + be_nested_proto( + 6, /* nstack */ + 2, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(global), + /* K1 */ be_nested_str_weak(contains), + /* K2 */ be_nested_str_weak(_X2Ematter), + }), + be_str_weak(setmember), + &be_const_str_solidified, + ( &(const binstruction[11]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0x8C0C0501, // 0001 GETMET R3 R2 K1 + 0x58140002, // 0002 LDCONST R5 K2 + 0x7C0C0400, // 0003 CALL R3 2 + 0x740E0002, // 0004 JMPT R3 #0008 + 0x600C0013, // 0005 GETGBL R3 G19 + 0x7C0C0000, // 0006 CALL R3 0 + 0x900A0403, // 0007 SETMBR R2 K2 R3 + 0x880C0502, // 0008 GETMBR R3 R2 K2 + 0x980C0001, // 0009 SETIDX R3 R0 R1 + 0x80000000, // 000A RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: member +********************************************************************/ +be_local_closure(matter_member, /* name */ + be_nested_proto( + 6, /* nstack */ + 1, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(global), + /* K1 */ be_nested_str_weak(undefined), + /* K2 */ be_nested_str_weak(contains), + /* K3 */ be_nested_str_weak(_X2Ematter), + }), + be_str_weak(member), + &be_const_str_solidified, + ( &(const binstruction[17]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0xA40A0200, // 0001 IMPORT R2 K1 + 0x8C0C0302, // 0002 GETMET R3 R1 K2 + 0x58140003, // 0003 LDCONST R5 K3 + 0x7C0C0400, // 0004 CALL R3 2 + 0x780E0008, // 0005 JMPF R3 #000F + 0x880C0303, // 0006 GETMBR R3 R1 K3 + 0x8C0C0702, // 0007 GETMET R3 R3 K2 + 0x5C140000, // 0008 MOVE R5 R0 + 0x7C0C0400, // 0009 CALL R3 2 + 0x780E0003, // 000A JMPF R3 #000F + 0x880C0303, // 000B GETMBR R3 R1 K3 + 0x940C0600, // 000C GETIDX R3 R3 R0 + 0x80040600, // 000D RET 1 R3 + 0x70020000, // 000E JMP #0010 + 0x80040400, // 000F RET 1 R2 + 0x80000000, // 0010 RET 0 + }) + ) +); +/*******************************************************************/ + +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin.h new file mode 100644 index 000000000..5ba1f7814 --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin.h @@ -0,0 +1,272 @@ +/* Solidification of Matter_Plugin.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_Plugin; + +/******************************************************************** +** Solidified function: get_endpoints +********************************************************************/ +be_local_closure(Matter_Plugin_get_endpoints, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(endpoints), + }), + be_str_weak(get_endpoints), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: invoke_request +********************************************************************/ +be_local_closure(Matter_Plugin_invoke_request, /* name */ + be_nested_proto( + 5, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + be_str_weak(invoke_request), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x4C100000, // 0000 LDNIL R4 + 0x80040800, // 0001 RET 1 R4 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_Plugin_init, /* name */ + be_nested_proto( + 3, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(device), + /* K1 */ be_nested_str_weak(endpoints), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x60080012, // 0001 GETGBL R2 G18 + 0x7C080000, // 0002 CALL R2 0 + 0x90020202, // 0003 SETMBR R0 K1 R2 + 0x80000000, // 0004 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: read_attribute +********************************************************************/ +be_local_closure(Matter_Plugin_read_attribute, /* name */ + be_nested_proto( + 6, /* nstack */ + 5, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + be_str_weak(read_attribute), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x4C140000, // 0000 LDNIL R5 + 0x80040A00, // 0001 RET 1 R5 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: read_event +********************************************************************/ +be_local_closure(Matter_Plugin_read_event, /* name */ + be_nested_proto( + 6, /* nstack */ + 5, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + be_str_weak(read_event), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x4C140000, // 0000 LDNIL R5 + 0x80040A00, // 0001 RET 1 R5 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: subscribe_attribute +********************************************************************/ +be_local_closure(Matter_Plugin_subscribe_attribute, /* name */ + be_nested_proto( + 6, /* nstack */ + 5, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + be_str_weak(subscribe_attribute), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x4C140000, // 0000 LDNIL R5 + 0x80040A00, // 0001 RET 1 R5 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: subscribe_event +********************************************************************/ +be_local_closure(Matter_Plugin_subscribe_event, /* name */ + be_nested_proto( + 6, /* nstack */ + 5, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + be_str_weak(subscribe_event), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x4C140000, // 0000 LDNIL R5 + 0x80040A00, // 0001 RET 1 R5 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: write_attribute +********************************************************************/ +be_local_closure(Matter_Plugin_write_attribute, /* name */ + be_nested_proto( + 6, /* nstack */ + 5, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + be_str_weak(write_attribute), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x4C140000, // 0000 LDNIL R5 + 0x80040A00, // 0001 RET 1 R5 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: timed_request +********************************************************************/ +be_local_closure(Matter_Plugin_timed_request, /* name */ + be_nested_proto( + 5, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + be_str_weak(timed_request), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x4C100000, // 0000 LDNIL R4 + 0x80040800, // 0001 RET 1 R4 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_Plugin +********************************************************************/ +be_local_class(Matter_Plugin, + 2, + NULL, + be_nested_map(11, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(get_endpoints, -1), be_const_closure(Matter_Plugin_get_endpoints_closure) }, + { be_const_key_weak(endpoints, 7), be_const_var(1) }, + { be_const_key_weak(timed_request, 8), be_const_closure(Matter_Plugin_timed_request_closure) }, + { be_const_key_weak(read_attribute, -1), be_const_closure(Matter_Plugin_read_attribute_closure) }, + { be_const_key_weak(read_event, -1), be_const_closure(Matter_Plugin_read_event_closure) }, + { be_const_key_weak(device, -1), be_const_var(0) }, + { be_const_key_weak(subscribe_attribute, -1), be_const_closure(Matter_Plugin_subscribe_attribute_closure) }, + { be_const_key_weak(write_attribute, -1), be_const_closure(Matter_Plugin_write_attribute_closure) }, + { be_const_key_weak(subscribe_event, -1), be_const_closure(Matter_Plugin_subscribe_event_closure) }, + { be_const_key_weak(init, 2), be_const_closure(Matter_Plugin_init_closure) }, + { be_const_key_weak(invoke_request, 1), be_const_closure(Matter_Plugin_invoke_request_closure) }, + })), + be_str_weak(Matter_Plugin) +); +/*******************************************************************/ + +void be_load_Matter_Plugin_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Plugin); + be_setglobal(vm, "Matter_Plugin"); + be_pop(vm, 1); +} +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Relay.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Relay.h new file mode 100644 index 000000000..f03a26eb5 --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Relay.h @@ -0,0 +1,118 @@ +/* Solidification of Matter_Plugin_Relay.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_Plugin_Relay; + +/******************************************************************** +** Solidified function: read_attribute +********************************************************************/ +be_local_closure(Matter_Plugin_Relay_read_attribute, /* name */ + be_nested_proto( + 5, /* nstack */ + 5, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + be_str_weak(read_attribute), + &be_const_str_solidified, + ( &(const binstruction[ 1]) { /* code */ + 0x80000000, // 0000 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_Plugin_Relay_init, /* name */ + be_nested_proto( + 5, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(init), + /* K1 */ be_nested_str_weak(endpoints), + /* K2 */ be_const_int(1), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[11]) { /* code */ + 0x60080003, // 0000 GETGBL R2 G3 + 0x5C0C0000, // 0001 MOVE R3 R0 + 0x7C080200, // 0002 CALL R2 1 + 0x8C080500, // 0003 GETMET R2 R2 K0 + 0x5C100200, // 0004 MOVE R4 R1 + 0x7C080400, // 0005 CALL R2 2 + 0x60080012, // 0006 GETGBL R2 G18 + 0x7C080000, // 0007 CALL R2 0 + 0x400C0502, // 0008 CONNECT R3 R2 K2 + 0x90020202, // 0009 SETMBR R0 K1 R2 + 0x80000000, // 000A RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: invoke_request +********************************************************************/ +be_local_closure(Matter_Plugin_Relay_invoke_request, /* name */ + be_nested_proto( + 4, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + be_str_weak(invoke_request), + &be_const_str_solidified, + ( &(const binstruction[ 1]) { /* code */ + 0x80000000, // 0000 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_Plugin_Relay +********************************************************************/ +extern const bclass be_class_Matter_Plugin; +be_local_class(Matter_Plugin_Relay, + 0, + &be_class_Matter_Plugin, + be_nested_map(3, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(read_attribute, 1), be_const_closure(Matter_Plugin_Relay_read_attribute_closure) }, + { be_const_key_weak(init, -1), be_const_closure(Matter_Plugin_Relay_init_closure) }, + { be_const_key_weak(invoke_request, -1), be_const_closure(Matter_Plugin_Relay_invoke_request_closure) }, + })), + be_str_weak(Matter_Plugin_Relay) +); +/*******************************************************************/ + +void be_load_Matter_Plugin_Relay_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Plugin_Relay); + be_setglobal(vm, "Matter_Plugin_Relay"); + be_pop(vm, 1); +} +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_core.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_core.h new file mode 100644 index 000000000..da9b01a97 --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_core.h @@ -0,0 +1,1053 @@ +/* Solidification of Matter_Plugin_core.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_Plugin_core; + +/******************************************************************** +** Solidified function: read_attribute +********************************************************************/ +be_local_closure(Matter_Plugin_core_read_attribute, /* name */ + be_nested_proto( + 14, /* nstack */ + 5, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[43]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(TLV), + /* K2 */ be_const_int(0), + /* K3 */ be_nested_str_weak(create_TLV), + /* K4 */ be_nested_str_weak(U8), + /* K5 */ be_nested_str_weak(session), + /* K6 */ be_nested_str_weak(breadcrumb), + /* K7 */ be_const_int(1), + /* K8 */ be_nested_str_weak(Matter_TLV_struct), + /* K9 */ be_nested_str_weak(add_TLV), + /* K10 */ be_nested_str_weak(U2), + /* K11 */ be_const_int(2), + /* K12 */ be_nested_str_weak(U1), + /* K13 */ be_const_int(3), + /* K14 */ be_nested_str_weak(BOOL), + /* K15 */ be_nested_str_weak(Matter_TLV_list), + /* K16 */ be_nested_str_weak(tasmota), + /* K17 */ be_nested_str_weak(cmd), + /* K18 */ be_nested_str_weak(Status_X201), + /* K19 */ be_nested_str_weak(StatusPRM), + /* K20 */ be_nested_str_weak(BootCount), + /* K21 */ be_nested_str_weak(U4), + /* K22 */ be_nested_str_weak(Status_X2011), + /* K23 */ be_nested_str_weak(StatusSTS), + /* K24 */ be_nested_str_weak(UptimeSec), + /* K25 */ be_nested_str_weak(int64), + /* K26 */ be_nested_str_weak(rtc), + /* K27 */ be_nested_str_weak(utc), + /* K28 */ be_const_int(1000000), + /* K29 */ be_nested_str_weak(local), + /* K30 */ be_nested_str_weak(UTF1), + /* K31 */ be_nested_str_weak(Tasmota), + /* K32 */ be_nested_str_weak(device), + /* K33 */ be_nested_str_weak(vendorid), + /* K34 */ be_nested_str_weak(DeviceName), + /* K35 */ be_nested_str_weak(FriendlyName), + /* K36 */ be_nested_str_weak(FriendlyName1), + /* K37 */ be_nested_str_weak(XX), + /* K38 */ be_nested_str_weak(Status_X202), + /* K39 */ be_nested_str_weak(StatusFWR), + /* K40 */ be_nested_str_weak(Hardware), + /* K41 */ be_nested_str_weak(Version), + /* K42 */ be_nested_str_weak(locale), + }), + be_str_weak(read_attribute), + &be_const_str_solidified, + ( &(const binstruction[391]) { /* code */ + 0xB8160000, // 0000 GETNGBL R5 K0 + 0x88140B01, // 0001 GETMBR R5 R5 K1 + 0x541A002F, // 0002 LDINT R6 48 + 0x1C180606, // 0003 EQ R6 R3 R6 + 0x781A0031, // 0004 JMPF R6 #0037 + 0x1C180902, // 0005 EQ R6 R4 K2 + 0x781A0006, // 0006 JMPF R6 #000E + 0x8C180B03, // 0007 GETMET R6 R5 K3 + 0x88200B04, // 0008 GETMBR R8 R5 K4 + 0x88240305, // 0009 GETMBR R9 R1 K5 + 0x88241306, // 000A GETMBR R9 R9 K6 + 0x7C180600, // 000B CALL R6 3 + 0x80040C00, // 000C RET 1 R6 + 0x70020027, // 000D JMP #0036 + 0x1C180907, // 000E EQ R6 R4 K7 + 0x781A000D, // 000F JMPF R6 #001E + 0x8C180B08, // 0010 GETMET R6 R5 K8 + 0x7C180200, // 0011 CALL R6 1 + 0x8C1C0D09, // 0012 GETMET R7 R6 K9 + 0x58240002, // 0013 LDCONST R9 K2 + 0x88280B0A, // 0014 GETMBR R10 R5 K10 + 0x542E003B, // 0015 LDINT R11 60 + 0x7C1C0800, // 0016 CALL R7 4 + 0x8C1C0D09, // 0017 GETMET R7 R6 K9 + 0x58240007, // 0018 LDCONST R9 K7 + 0x88280B0A, // 0019 GETMBR R10 R5 K10 + 0x542E0383, // 001A LDINT R11 900 + 0x7C1C0800, // 001B CALL R7 4 + 0x80040C00, // 001C RET 1 R6 + 0x70020017, // 001D JMP #0036 + 0x1C18090B, // 001E EQ R6 R4 K11 + 0x781A0005, // 001F JMPF R6 #0026 + 0x8C180B03, // 0020 GETMET R6 R5 K3 + 0x88200B0C, // 0021 GETMBR R8 R5 K12 + 0x5824000B, // 0022 LDCONST R9 K11 + 0x7C180600, // 0023 CALL R6 3 + 0x80040C00, // 0024 RET 1 R6 + 0x7002000F, // 0025 JMP #0036 + 0x1C18090D, // 0026 EQ R6 R4 K13 + 0x781A0005, // 0027 JMPF R6 #002E + 0x8C180B03, // 0028 GETMET R6 R5 K3 + 0x88200B0C, // 0029 GETMBR R8 R5 K12 + 0x5824000B, // 002A LDCONST R9 K11 + 0x7C180600, // 002B CALL R6 3 + 0x80040C00, // 002C RET 1 R6 + 0x70020007, // 002D JMP #0036 + 0x541A0003, // 002E LDINT R6 4 + 0x1C180806, // 002F EQ R6 R4 R6 + 0x781A0004, // 0030 JMPF R6 #0036 + 0x8C180B03, // 0031 GETMET R6 R5 K3 + 0x88200B0E, // 0032 GETMBR R8 R5 K14 + 0x50240000, // 0033 LDBOOL R9 0 0 + 0x7C180600, // 0034 CALL R6 3 + 0x80040C00, // 0035 RET 1 R6 + 0x7002014E, // 0036 JMP #0186 + 0x541A0031, // 0037 LDINT R6 50 + 0x1C180606, // 0038 EQ R6 R3 R6 + 0x781A0000, // 0039 JMPF R6 #003B + 0x7002014A, // 003A JMP #0186 + 0x541A0032, // 003B LDINT R6 51 + 0x1C180606, // 003C EQ R6 R3 R6 + 0x781A0028, // 003D JMPF R6 #0067 + 0x1C180902, // 003E EQ R6 R4 K2 + 0x781A0003, // 003F JMPF R6 #0044 + 0x8C180B0F, // 0040 GETMET R6 R5 K15 + 0x7C180200, // 0041 CALL R6 1 + 0x80040C00, // 0042 RET 1 R6 + 0x70020021, // 0043 JMP #0066 + 0x1C180907, // 0044 EQ R6 R4 K7 + 0x781A000A, // 0045 JMPF R6 #0051 + 0x8C180B03, // 0046 GETMET R6 R5 K3 + 0x88200B0A, // 0047 GETMBR R8 R5 K10 + 0xB8262000, // 0048 GETNGBL R9 K16 + 0x8C241311, // 0049 GETMET R9 R9 K17 + 0x582C0012, // 004A LDCONST R11 K18 + 0x7C240400, // 004B CALL R9 2 + 0x94241313, // 004C GETIDX R9 R9 K19 + 0x94241314, // 004D GETIDX R9 R9 K20 + 0x7C180600, // 004E CALL R6 3 + 0x80040C00, // 004F RET 1 R6 + 0x70020014, // 0050 JMP #0066 + 0x1C18090B, // 0051 EQ R6 R4 K11 + 0x781A000A, // 0052 JMPF R6 #005E + 0x8C180B03, // 0053 GETMET R6 R5 K3 + 0x88200B15, // 0054 GETMBR R8 R5 K21 + 0xB8262000, // 0055 GETNGBL R9 K16 + 0x8C241311, // 0056 GETMET R9 R9 K17 + 0x582C0016, // 0057 LDCONST R11 K22 + 0x7C240400, // 0058 CALL R9 2 + 0x94241317, // 0059 GETIDX R9 R9 K23 + 0x94241318, // 005A GETIDX R9 R9 K24 + 0x7C180600, // 005B CALL R6 3 + 0x80040C00, // 005C RET 1 R6 + 0x70020007, // 005D JMP #0066 + 0x541A0007, // 005E LDINT R6 8 + 0x1C180806, // 005F EQ R6 R4 R6 + 0x781A0004, // 0060 JMPF R6 #0066 + 0x8C180B03, // 0061 GETMET R6 R5 K3 + 0x88200B0E, // 0062 GETMBR R8 R5 K14 + 0x50240000, // 0063 LDBOOL R9 0 0 + 0x7C180600, // 0064 CALL R6 3 + 0x80040C00, // 0065 RET 1 R6 + 0x7002011E, // 0066 JMP #0186 + 0x541A0033, // 0067 LDINT R6 52 + 0x1C180606, // 0068 EQ R6 R3 R6 + 0x781A0000, // 0069 JMPF R6 #006B + 0x7002011A, // 006A JMP #0186 + 0x541A0037, // 006B LDINT R6 56 + 0x1C180606, // 006C EQ R6 R3 R6 + 0x781A002C, // 006D JMPF R6 #009B + 0x1C180902, // 006E EQ R6 R4 K2 + 0x781A000F, // 006F JMPF R6 #0080 + 0xB81A3200, // 0070 GETNGBL R6 K25 + 0xB81E2000, // 0071 GETNGBL R7 K16 + 0x8C1C0F1A, // 0072 GETMET R7 R7 K26 + 0x7C1C0200, // 0073 CALL R7 1 + 0x941C0F1B, // 0074 GETIDX R7 R7 K27 + 0x7C180200, // 0075 CALL R6 1 + 0xB81E3200, // 0076 GETNGBL R7 K25 + 0x5820001C, // 0077 LDCONST R8 K28 + 0x7C1C0200, // 0078 CALL R7 1 + 0x08180C07, // 0079 MUL R6 R6 R7 + 0x8C1C0B03, // 007A GETMET R7 R5 K3 + 0x88240B04, // 007B GETMBR R9 R5 K4 + 0x5C280C00, // 007C MOVE R10 R6 + 0x7C1C0600, // 007D CALL R7 3 + 0x80040E00, // 007E RET 1 R7 + 0x70020019, // 007F JMP #009A + 0x1C180907, // 0080 EQ R6 R4 K7 + 0x781A0005, // 0081 JMPF R6 #0088 + 0x8C180B03, // 0082 GETMET R6 R5 K3 + 0x88200B0C, // 0083 GETMBR R8 R5 K12 + 0x5824000D, // 0084 LDCONST R9 K13 + 0x7C180600, // 0085 CALL R6 3 + 0x80040C00, // 0086 RET 1 R6 + 0x70020011, // 0087 JMP #009A + 0x541A0006, // 0088 LDINT R6 7 + 0x1C180806, // 0089 EQ R6 R4 R6 + 0x781A000E, // 008A JMPF R6 #009A + 0xB81A3200, // 008B GETNGBL R6 K25 + 0xB81E2000, // 008C GETNGBL R7 K16 + 0x8C1C0F1A, // 008D GETMET R7 R7 K26 + 0x7C1C0200, // 008E CALL R7 1 + 0x941C0F1D, // 008F GETIDX R7 R7 K29 + 0x7C180200, // 0090 CALL R6 1 + 0xB81E3200, // 0091 GETNGBL R7 K25 + 0x5820001C, // 0092 LDCONST R8 K28 + 0x7C1C0200, // 0093 CALL R7 1 + 0x08180C07, // 0094 MUL R6 R6 R7 + 0x8C1C0B03, // 0095 GETMET R7 R5 K3 + 0x88240B04, // 0096 GETMBR R9 R5 K4 + 0x5C280C00, // 0097 MOVE R10 R6 + 0x7C1C0600, // 0098 CALL R7 3 + 0x80040E00, // 0099 RET 1 R7 + 0x700200EA, // 009A JMP #0186 + 0x541A003D, // 009B LDINT R6 62 + 0x1C180606, // 009C EQ R6 R3 R6 + 0x781A001D, // 009D JMPF R6 #00BC + 0x1C180902, // 009E EQ R6 R4 K2 + 0x781A0000, // 009F JMPF R6 #00A1 + 0x70020019, // 00A0 JMP #00BB + 0x1C180907, // 00A1 EQ R6 R4 K7 + 0x781A0000, // 00A2 JMPF R6 #00A4 + 0x70020016, // 00A3 JMP #00BB + 0x1C18090B, // 00A4 EQ R6 R4 K11 + 0x781A0005, // 00A5 JMPF R6 #00AC + 0x8C180B03, // 00A6 GETMET R6 R5 K3 + 0x88200B0C, // 00A7 GETMBR R8 R5 K12 + 0x54260004, // 00A8 LDINT R9 5 + 0x7C180600, // 00A9 CALL R6 3 + 0x80040C00, // 00AA RET 1 R6 + 0x7002000E, // 00AB JMP #00BB + 0x1C18090D, // 00AC EQ R6 R4 K13 + 0x781A0005, // 00AD JMPF R6 #00B4 + 0x8C180B03, // 00AE GETMET R6 R5 K3 + 0x88200B0C, // 00AF GETMBR R8 R5 K12 + 0x58240007, // 00B0 LDCONST R9 K7 + 0x7C180600, // 00B1 CALL R6 3 + 0x80040C00, // 00B2 RET 1 R6 + 0x70020006, // 00B3 JMP #00BB + 0x541A0003, // 00B4 LDINT R6 4 + 0x1C180806, // 00B5 EQ R6 R4 R6 + 0x781A0000, // 00B6 JMPF R6 #00B8 + 0x70020002, // 00B7 JMP #00BB + 0x541A0004, // 00B8 LDINT R6 5 + 0x1C180806, // 00B9 EQ R6 R4 R6 + 0x7819FFFF, // 00BA JMPF R6 #00BB + 0x700200C9, // 00BB JMP #0186 + 0x541A003B, // 00BC LDINT R6 60 + 0x1C180606, // 00BD EQ R6 R3 R6 + 0x781A0000, // 00BE JMPF R6 #00C0 + 0x700200C5, // 00BF JMP #0186 + 0x541A0027, // 00C0 LDINT R6 40 + 0x1C180606, // 00C1 EQ R6 R3 R6 + 0x781A0071, // 00C2 JMPF R6 #0135 + 0x1C180902, // 00C3 EQ R6 R4 K2 + 0x781A0005, // 00C4 JMPF R6 #00CB + 0x8C180B03, // 00C5 GETMET R6 R5 K3 + 0x88200B0A, // 00C6 GETMBR R8 R5 K10 + 0x58240002, // 00C7 LDCONST R9 K2 + 0x7C180600, // 00C8 CALL R6 3 + 0x80040C00, // 00C9 RET 1 R6 + 0x70020068, // 00CA JMP #0134 + 0x1C180907, // 00CB EQ R6 R4 K7 + 0x781A0005, // 00CC JMPF R6 #00D3 + 0x8C180B03, // 00CD GETMET R6 R5 K3 + 0x88200B1E, // 00CE GETMBR R8 R5 K30 + 0x5824001F, // 00CF LDCONST R9 K31 + 0x7C180600, // 00D0 CALL R6 3 + 0x80040C00, // 00D1 RET 1 R6 + 0x70020060, // 00D2 JMP #0134 + 0x1C18090B, // 00D3 EQ R6 R4 K11 + 0x781A0006, // 00D4 JMPF R6 #00DC + 0x8C180B03, // 00D5 GETMET R6 R5 K3 + 0x88200B0A, // 00D6 GETMBR R8 R5 K10 + 0x88240120, // 00D7 GETMBR R9 R0 K32 + 0x88241321, // 00D8 GETMBR R9 R9 K33 + 0x7C180600, // 00D9 CALL R6 3 + 0x80040C00, // 00DA RET 1 R6 + 0x70020057, // 00DB JMP #0134 + 0x1C18090D, // 00DC EQ R6 R4 K13 + 0x781A0009, // 00DD JMPF R6 #00E8 + 0x8C180B03, // 00DE GETMET R6 R5 K3 + 0x88200B1E, // 00DF GETMBR R8 R5 K30 + 0xB8262000, // 00E0 GETNGBL R9 K16 + 0x8C241311, // 00E1 GETMET R9 R9 K17 + 0x582C0022, // 00E2 LDCONST R11 K34 + 0x7C240400, // 00E3 CALL R9 2 + 0x94241322, // 00E4 GETIDX R9 R9 K34 + 0x7C180600, // 00E5 CALL R6 3 + 0x80040C00, // 00E6 RET 1 R6 + 0x7002004B, // 00E7 JMP #0134 + 0x541A0003, // 00E8 LDINT R6 4 + 0x1C180806, // 00E9 EQ R6 R4 R6 + 0x781A0005, // 00EA JMPF R6 #00F1 + 0x8C180B03, // 00EB GETMET R6 R5 K3 + 0x88200B0A, // 00EC GETMBR R8 R5 K10 + 0x54267FFF, // 00ED LDINT R9 32768 + 0x7C180600, // 00EE CALL R6 3 + 0x80040C00, // 00EF RET 1 R6 + 0x70020042, // 00F0 JMP #0134 + 0x541A0004, // 00F1 LDINT R6 5 + 0x1C180806, // 00F2 EQ R6 R4 R6 + 0x781A0009, // 00F3 JMPF R6 #00FE + 0x8C180B03, // 00F4 GETMET R6 R5 K3 + 0x88200B1E, // 00F5 GETMBR R8 R5 K30 + 0xB8262000, // 00F6 GETNGBL R9 K16 + 0x8C241311, // 00F7 GETMET R9 R9 K17 + 0x582C0023, // 00F8 LDCONST R11 K35 + 0x7C240400, // 00F9 CALL R9 2 + 0x94241324, // 00FA GETIDX R9 R9 K36 + 0x7C180600, // 00FB CALL R6 3 + 0x80040C00, // 00FC RET 1 R6 + 0x70020035, // 00FD JMP #0134 + 0x541A0005, // 00FE LDINT R6 6 + 0x1C180806, // 00FF EQ R6 R4 R6 + 0x781A0005, // 0100 JMPF R6 #0107 + 0x8C180B03, // 0101 GETMET R6 R5 K3 + 0x88200B1E, // 0102 GETMBR R8 R5 K30 + 0x58240025, // 0103 LDCONST R9 K37 + 0x7C180600, // 0104 CALL R6 3 + 0x80040C00, // 0105 RET 1 R6 + 0x7002002C, // 0106 JMP #0134 + 0x541A0006, // 0107 LDINT R6 7 + 0x1C180806, // 0108 EQ R6 R4 R6 + 0x781A0005, // 0109 JMPF R6 #0110 + 0x8C180B03, // 010A GETMET R6 R5 K3 + 0x88200B0A, // 010B GETMBR R8 R5 K10 + 0x58240002, // 010C LDCONST R9 K2 + 0x7C180600, // 010D CALL R6 3 + 0x80040C00, // 010E RET 1 R6 + 0x70020023, // 010F JMP #0134 + 0x541A0007, // 0110 LDINT R6 8 + 0x1C180806, // 0111 EQ R6 R4 R6 + 0x781A000A, // 0112 JMPF R6 #011E + 0x8C180B03, // 0113 GETMET R6 R5 K3 + 0x88200B1E, // 0114 GETMBR R8 R5 K30 + 0xB8262000, // 0115 GETNGBL R9 K16 + 0x8C241311, // 0116 GETMET R9 R9 K17 + 0x582C0026, // 0117 LDCONST R11 K38 + 0x7C240400, // 0118 CALL R9 2 + 0x94241327, // 0119 GETIDX R9 R9 K39 + 0x94241328, // 011A GETIDX R9 R9 K40 + 0x7C180600, // 011B CALL R6 3 + 0x80040C00, // 011C RET 1 R6 + 0x70020015, // 011D JMP #0134 + 0x541A0008, // 011E LDINT R6 9 + 0x1C180806, // 011F EQ R6 R4 R6 + 0x781A0005, // 0120 JMPF R6 #0127 + 0x8C180B03, // 0121 GETMET R6 R5 K3 + 0x88200B0A, // 0122 GETMBR R8 R5 K10 + 0x58240002, // 0123 LDCONST R9 K2 + 0x7C180600, // 0124 CALL R6 3 + 0x80040C00, // 0125 RET 1 R6 + 0x7002000C, // 0126 JMP #0134 + 0x541A0009, // 0127 LDINT R6 10 + 0x1C180806, // 0128 EQ R6 R4 R6 + 0x781A0009, // 0129 JMPF R6 #0134 + 0x8C180B03, // 012A GETMET R6 R5 K3 + 0x88200B1E, // 012B GETMBR R8 R5 K30 + 0xB8262000, // 012C GETNGBL R9 K16 + 0x8C241311, // 012D GETMET R9 R9 K17 + 0x582C0026, // 012E LDCONST R11 K38 + 0x7C240400, // 012F CALL R9 2 + 0x94241327, // 0130 GETIDX R9 R9 K39 + 0x94241329, // 0131 GETIDX R9 R9 K41 + 0x7C180600, // 0132 CALL R6 3 + 0x80040C00, // 0133 RET 1 R6 + 0x70020050, // 0134 JMP #0186 + 0x541A003E, // 0135 LDINT R6 63 + 0x1C180606, // 0136 EQ R6 R3 R6 + 0x781A0000, // 0137 JMPF R6 #0139 + 0x7002004C, // 0138 JMP #0186 + 0x541A002A, // 0139 LDINT R6 43 + 0x1C180606, // 013A EQ R6 R3 R6 + 0x781A0016, // 013B JMPF R6 #0153 + 0x1C180902, // 013C EQ R6 R4 K2 + 0x781A0007, // 013D JMPF R6 #0146 + 0x8C180B03, // 013E GETMET R6 R5 K3 + 0x88200B1E, // 013F GETMBR R8 R5 K30 + 0xB8262000, // 0140 GETNGBL R9 K16 + 0x8C24132A, // 0141 GETMET R9 R9 K42 + 0x7C240200, // 0142 CALL R9 1 + 0x7C180600, // 0143 CALL R6 3 + 0x80040C00, // 0144 RET 1 R6 + 0x7002000B, // 0145 JMP #0152 + 0x1C180907, // 0146 EQ R6 R4 K7 + 0x781A0009, // 0147 JMPF R6 #0152 + 0x8C180B0F, // 0148 GETMET R6 R5 K15 + 0x7C180200, // 0149 CALL R6 1 + 0x8C1C0D09, // 014A GETMET R7 R6 K9 + 0x4C240000, // 014B LDNIL R9 + 0x88280B1E, // 014C GETMBR R10 R5 K30 + 0xB82E2000, // 014D GETNGBL R11 K16 + 0x8C2C172A, // 014E GETMET R11 R11 K42 + 0x7C2C0200, // 014F CALL R11 1 + 0x7C1C0800, // 0150 CALL R7 4 + 0x80040C00, // 0151 RET 1 R6 + 0x70020032, // 0152 JMP #0186 + 0x541A002B, // 0153 LDINT R6 44 + 0x1C180606, // 0154 EQ R6 R3 R6 + 0x781A001C, // 0155 JMPF R6 #0173 + 0x1C180902, // 0156 EQ R6 R4 K2 + 0x781A0005, // 0157 JMPF R6 #015E + 0x8C180B03, // 0158 GETMET R6 R5 K3 + 0x88200B0C, // 0159 GETMBR R8 R5 K12 + 0x58240007, // 015A LDCONST R9 K7 + 0x7C180600, // 015B CALL R6 3 + 0x80040C00, // 015C RET 1 R6 + 0x70020013, // 015D JMP #0172 + 0x1C180907, // 015E EQ R6 R4 K7 + 0x781A0005, // 015F JMPF R6 #0166 + 0x8C180B03, // 0160 GETMET R6 R5 K3 + 0x88200B0C, // 0161 GETMBR R8 R5 K12 + 0x54260003, // 0162 LDINT R9 4 + 0x7C180600, // 0163 CALL R6 3 + 0x80040C00, // 0164 RET 1 R6 + 0x7002000B, // 0165 JMP #0172 + 0x1C18090B, // 0166 EQ R6 R4 K11 + 0x781A0009, // 0167 JMPF R6 #0172 + 0x8C180B0F, // 0168 GETMET R6 R5 K15 + 0x7C180200, // 0169 CALL R6 1 + 0x8C1C0D09, // 016A GETMET R7 R6 K9 + 0x4C240000, // 016B LDNIL R9 + 0x8C280B03, // 016C GETMET R10 R5 K3 + 0x88300B0C, // 016D GETMBR R12 R5 K12 + 0x54360003, // 016E LDINT R13 4 + 0x7C280600, // 016F CALL R10 3 + 0x7C1C0600, // 0170 CALL R7 3 + 0x80040C00, // 0171 RET 1 R6 + 0x70020012, // 0172 JMP #0186 + 0x541A0030, // 0173 LDINT R6 49 + 0x1C180606, // 0174 EQ R6 R3 R6 + 0x781A000F, // 0175 JMPF R6 #0186 + 0x1C18090D, // 0176 EQ R6 R4 K13 + 0x781A0005, // 0177 JMPF R6 #017E + 0x8C180B03, // 0178 GETMET R6 R5 K3 + 0x88200B0C, // 0179 GETMBR R8 R5 K12 + 0x5426001D, // 017A LDINT R9 30 + 0x7C180600, // 017B CALL R6 3 + 0x80040C00, // 017C RET 1 R6 + 0x70020007, // 017D JMP #0186 + 0x541AFFFB, // 017E LDINT R6 65532 + 0x1C180806, // 017F EQ R6 R4 R6 + 0x781A0004, // 0180 JMPF R6 #0186 + 0x8C180B03, // 0181 GETMET R6 R5 K3 + 0x88200B15, // 0182 GETMBR R8 R5 K21 + 0x58240002, // 0183 LDCONST R9 K2 + 0x7C180600, // 0184 CALL R6 3 + 0x80040C00, // 0185 RET 1 R6 + 0x80000000, // 0186 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_Plugin_core_init, /* name */ + be_nested_proto( + 5, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(init), + /* K1 */ be_nested_str_weak(endpoints), + /* K2 */ be_const_int(0), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[11]) { /* code */ + 0x60080003, // 0000 GETGBL R2 G3 + 0x5C0C0000, // 0001 MOVE R3 R0 + 0x7C080200, // 0002 CALL R2 1 + 0x8C080500, // 0003 GETMET R2 R2 K0 + 0x5C100200, // 0004 MOVE R4 R1 + 0x7C080400, // 0005 CALL R2 2 + 0x60080012, // 0006 GETGBL R2 G18 + 0x7C080000, // 0007 CALL R2 0 + 0x400C0502, // 0008 CONNECT R3 R2 K2 + 0x90020202, // 0009 SETMBR R0 K1 R2 + 0x80000000, // 000A RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: invoke_request +********************************************************************/ +be_local_closure(Matter_Plugin_core_invoke_request, /* name */ + be_nested_proto( + 29, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[66]) { /* constants */ + /* K0 */ be_nested_str_weak(crypto), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(TLV), + /* K3 */ be_nested_str_weak(cluster), + /* K4 */ be_nested_str_weak(command), + /* K5 */ be_nested_str_weak(session), + /* K6 */ be_const_int(0), + /* K7 */ be_nested_str_weak(findsubval), + /* K8 */ be_const_int(1), + /* K9 */ be_nested_str_weak(breadcrumb), + /* K10 */ be_nested_str_weak(Matter_TLV_struct), + /* K11 */ be_nested_str_weak(add_TLV), + /* K12 */ be_nested_str_weak(U1), + /* K13 */ be_nested_str_weak(UTF1), + /* K14 */ be_nested_str_weak(), + /* K15 */ be_const_int(2), + /* K16 */ be_nested_str_weak(XX), + /* K17 */ be_const_int(3), + /* K18 */ be_nested_str_weak(set_no_expiration), + /* K19 */ be_nested_str_weak(device), + /* K20 */ be_nested_str_weak(start_commissioning_complete_deferred), + /* K21 */ be_nested_str_weak(status), + /* K22 */ be_nested_str_weak(UNSUPPORTED_COMMAND), + /* K23 */ be_nested_str_weak(B2), + /* K24 */ be_nested_str_weak(DAC_Cert_FFF1_8000), + /* K25 */ be_nested_str_weak(PAI_Cert_FFF1), + /* K26 */ be_nested_str_weak(CD_FFF1_8000), + /* K27 */ be_nested_str_weak(B1), + /* K28 */ be_nested_str_weak(U4), + /* K29 */ be_nested_str_weak(tasmota), + /* K30 */ be_nested_str_weak(rtc), + /* K31 */ be_nested_str_weak(utc), + /* K32 */ be_nested_str_weak(encode), + /* K33 */ be_nested_str_weak(get_ac), + /* K34 */ be_nested_str_weak(log), + /* K35 */ be_nested_str_weak(MTR_X3A_X20attestation_tbs_X3D), + /* K36 */ be_nested_str_weak(tohex), + /* K37 */ be_nested_str_weak(EC_P256), + /* K38 */ be_nested_str_weak(ecdsa_sign_sha256), + /* K39 */ be_nested_str_weak(DAC_Priv_FFF1_8000), + /* K40 */ be_nested_str_weak(gen_CSR), + /* K41 */ be_nested_str_weak(MTR_X3A_X20nocsr_tbs_X3D), + /* K42 */ be_nested_str_weak(set_ca), + /* K43 */ be_nested_str_weak(MTR_X3A_X20received_X20ca_root_X3D), + /* K44 */ be_nested_str_weak(SUCCESS), + /* K45 */ be_nested_str_weak(get_ca), + /* K46 */ be_nested_str_weak(MTR_X3A_X20Error_X3A_X20AdNOC_X20without_X20CA), + /* K47 */ be_nested_str_weak(set_noc), + /* K48 */ be_nested_str_weak(set_ipk_epoch_key), + /* K49 */ be_nested_str_weak(admin_subject), + /* K50 */ be_nested_str_weak(admin_vendor), + /* K51 */ be_nested_str_weak(parse), + /* K52 */ be_nested_str_weak(findsub), + /* K53 */ be_nested_str_weak(MTR_X3A_X20Error_X3A_X20no_X20fabricid_X20nor_X20deviceid_X20in_X20NOC_X20certificate), + /* K54 */ be_nested_str_weak(int), + /* K55 */ be_nested_str_weak(int64), + /* K56 */ be_nested_str_weak(tobytes), + /* K57 */ be_const_int(2147483647), + /* K58 */ be_nested_str_weak(fromstring), + /* K59 */ be_nested_str_weak(CompressedFabric), + /* K60 */ be_nested_str_weak(HKDF_SHA256), + /* K61 */ be_nested_str_weak(copy), + /* K62 */ be_nested_str_weak(reverse), + /* K63 */ be_nested_str_weak(derive), + /* K64 */ be_nested_str_weak(set_fabric_device), + /* K65 */ be_nested_str_weak(start_operational_dicovery_deferred), + }), + be_str_weak(invoke_request), + &be_const_str_solidified, + ( &(const binstruction[435]) { /* code */ + 0xA4120000, // 0000 IMPORT R4 K0 + 0xB8160200, // 0001 GETNGBL R5 K1 + 0x88140B02, // 0002 GETMBR R5 R5 K2 + 0x88180703, // 0003 GETMBR R6 R3 K3 + 0x881C0704, // 0004 GETMBR R7 R3 K4 + 0x88200305, // 0005 GETMBR R8 R1 K5 + 0x5426002F, // 0006 LDINT R9 48 + 0x1C240C09, // 0007 EQ R9 R6 R9 + 0x78260050, // 0008 JMPF R9 #005A + 0x1C240F06, // 0009 EQ R9 R7 K6 + 0x78260017, // 000A JMPF R9 #0023 + 0x8C240507, // 000B GETMET R9 R2 K7 + 0x582C0006, // 000C LDCONST R11 K6 + 0x54320383, // 000D LDINT R12 900 + 0x7C240600, // 000E CALL R9 3 + 0x8C280507, // 000F GETMET R10 R2 K7 + 0x58300008, // 0010 LDCONST R12 K8 + 0x58340006, // 0011 LDCONST R13 K6 + 0x7C280600, // 0012 CALL R10 3 + 0x9022120A, // 0013 SETMBR R8 K9 R10 + 0x8C2C0B0A, // 0014 GETMET R11 R5 K10 + 0x7C2C0200, // 0015 CALL R11 1 + 0x8C30170B, // 0016 GETMET R12 R11 K11 + 0x58380006, // 0017 LDCONST R14 K6 + 0x883C0B0C, // 0018 GETMBR R15 R5 K12 + 0x58400006, // 0019 LDCONST R16 K6 + 0x7C300800, // 001A CALL R12 4 + 0x8C30170B, // 001B GETMET R12 R11 K11 + 0x58380008, // 001C LDCONST R14 K8 + 0x883C0B0D, // 001D GETMBR R15 R5 K13 + 0x5840000E, // 001E LDCONST R16 K14 + 0x7C300800, // 001F CALL R12 4 + 0x900E0908, // 0020 SETMBR R3 K4 K8 + 0x80041600, // 0021 RET 1 R11 + 0x70020035, // 0022 JMP #0059 + 0x1C240F0F, // 0023 EQ R9 R7 K15 + 0x7826001A, // 0024 JMPF R9 #0040 + 0x8C240507, // 0025 GETMET R9 R2 K7 + 0x582C0006, // 0026 LDCONST R11 K6 + 0x7C240400, // 0027 CALL R9 2 + 0x8C280507, // 0028 GETMET R10 R2 K7 + 0x58300008, // 0029 LDCONST R12 K8 + 0x58340010, // 002A LDCONST R13 K16 + 0x7C280600, // 002B CALL R10 3 + 0x8C2C0507, // 002C GETMET R11 R2 K7 + 0x5834000F, // 002D LDCONST R13 K15 + 0x58380006, // 002E LDCONST R14 K6 + 0x7C2C0600, // 002F CALL R11 3 + 0x9022120B, // 0030 SETMBR R8 K9 R11 + 0x8C300B0A, // 0031 GETMET R12 R5 K10 + 0x7C300200, // 0032 CALL R12 1 + 0x8C34190B, // 0033 GETMET R13 R12 K11 + 0x583C0006, // 0034 LDCONST R15 K6 + 0x88400B0C, // 0035 GETMBR R16 R5 K12 + 0x58440006, // 0036 LDCONST R17 K6 + 0x7C340800, // 0037 CALL R13 4 + 0x8C34190B, // 0038 GETMET R13 R12 K11 + 0x583C0008, // 0039 LDCONST R15 K8 + 0x88400B0D, // 003A GETMBR R16 R5 K13 + 0x5844000E, // 003B LDCONST R17 K14 + 0x7C340800, // 003C CALL R13 4 + 0x900E0911, // 003D SETMBR R3 K4 K17 + 0x80041800, // 003E RET 1 R12 + 0x70020018, // 003F JMP #0059 + 0x54260003, // 0040 LDINT R9 4 + 0x1C240E09, // 0041 EQ R9 R7 R9 + 0x78260015, // 0042 JMPF R9 #0059 + 0x90221306, // 0043 SETMBR R8 K9 K6 + 0x8C241112, // 0044 GETMET R9 R8 K18 + 0x7C240200, // 0045 CALL R9 1 + 0x8C240B0A, // 0046 GETMET R9 R5 K10 + 0x7C240200, // 0047 CALL R9 1 + 0x8C28130B, // 0048 GETMET R10 R9 K11 + 0x58300006, // 0049 LDCONST R12 K6 + 0x88340B0C, // 004A GETMBR R13 R5 K12 + 0x58380006, // 004B LDCONST R14 K6 + 0x7C280800, // 004C CALL R10 4 + 0x8C28130B, // 004D GETMET R10 R9 K11 + 0x58300008, // 004E LDCONST R12 K8 + 0x88340B0D, // 004F GETMBR R13 R5 K13 + 0x5838000E, // 0050 LDCONST R14 K14 + 0x7C280800, // 0051 CALL R10 4 + 0x542A0004, // 0052 LDINT R10 5 + 0x900E080A, // 0053 SETMBR R3 K4 R10 + 0x88280113, // 0054 GETMBR R10 R0 K19 + 0x8C281514, // 0055 GETMET R10 R10 K20 + 0x5C301000, // 0056 MOVE R12 R8 + 0x7C280400, // 0057 CALL R10 2 + 0x80041200, // 0058 RET 1 R9 + 0x70020157, // 0059 JMP #01B2 + 0x5426003D, // 005A LDINT R9 62 + 0x1C240C09, // 005B EQ R9 R6 R9 + 0x78260154, // 005C JMPF R9 #01B2 + 0x1C240F0F, // 005D EQ R9 R7 K15 + 0x7826001D, // 005E JMPF R9 #007D + 0x8C240507, // 005F GETMET R9 R2 K7 + 0x582C0006, // 0060 LDCONST R11 K6 + 0x7C240400, // 0061 CALL R9 2 + 0x20281308, // 0062 NE R10 R9 K8 + 0x782A0006, // 0063 JMPF R10 #006B + 0x2028130F, // 0064 NE R10 R9 K15 + 0x782A0004, // 0065 JMPF R10 #006B + 0xB82A0200, // 0066 GETNGBL R10 K1 + 0x88281516, // 0067 GETMBR R10 R10 K22 + 0x900E2A0A, // 0068 SETMBR R3 K21 R10 + 0x4C280000, // 0069 LDNIL R10 + 0x80041400, // 006A RET 1 R10 + 0x8C280B0A, // 006B GETMET R10 R5 K10 + 0x7C280200, // 006C CALL R10 1 + 0x8C2C150B, // 006D GETMET R11 R10 K11 + 0x58340006, // 006E LDCONST R13 K6 + 0x88380B17, // 006F GETMBR R14 R5 K23 + 0x1C3C1308, // 0070 EQ R15 R9 K8 + 0x783E0003, // 0071 JMPF R15 #0076 + 0xB83E0200, // 0072 GETNGBL R15 K1 + 0x8C3C1F18, // 0073 GETMET R15 R15 K24 + 0x7C3C0200, // 0074 CALL R15 1 + 0x70020002, // 0075 JMP #0079 + 0xB83E0200, // 0076 GETNGBL R15 K1 + 0x8C3C1F19, // 0077 GETMET R15 R15 K25 + 0x7C3C0200, // 0078 CALL R15 1 + 0x7C2C0800, // 0079 CALL R11 4 + 0x900E0911, // 007A SETMBR R3 K4 K17 + 0x80041400, // 007B RET 1 R10 + 0x70020134, // 007C JMP #01B2 + 0x1C240F06, // 007D EQ R9 R7 K6 + 0x78260044, // 007E JMPF R9 #00C4 + 0x8C240507, // 007F GETMET R9 R2 K7 + 0x582C0006, // 0080 LDCONST R11 K6 + 0x7C240400, // 0081 CALL R9 2 + 0x6028000C, // 0082 GETGBL R10 G12 + 0x5C2C1200, // 0083 MOVE R11 R9 + 0x7C280200, // 0084 CALL R10 1 + 0x542E001F, // 0085 LDINT R11 32 + 0x2028140B, // 0086 NE R10 R10 R11 + 0x782A0001, // 0087 JMPF R10 #008A + 0x4C280000, // 0088 LDNIL R10 + 0x80041400, // 0089 RET 1 R10 + 0x900E0908, // 008A SETMBR R3 K4 K8 + 0x8C280B0A, // 008B GETMET R10 R5 K10 + 0x7C280200, // 008C CALL R10 1 + 0x8C2C150B, // 008D GETMET R11 R10 K11 + 0x58340008, // 008E LDCONST R13 K8 + 0x88380B17, // 008F GETMBR R14 R5 K23 + 0xB83E0200, // 0090 GETNGBL R15 K1 + 0x8C3C1F1A, // 0091 GETMET R15 R15 K26 + 0x7C3C0200, // 0092 CALL R15 1 + 0x7C2C0800, // 0093 CALL R11 4 + 0x8C2C150B, // 0094 GETMET R11 R10 K11 + 0x5834000F, // 0095 LDCONST R13 K15 + 0x88380B1B, // 0096 GETMBR R14 R5 K27 + 0x5C3C1200, // 0097 MOVE R15 R9 + 0x7C2C0800, // 0098 CALL R11 4 + 0x8C2C150B, // 0099 GETMET R11 R10 K11 + 0x58340011, // 009A LDCONST R13 K17 + 0x88380B1C, // 009B GETMBR R14 R5 K28 + 0xB83E3A00, // 009C GETNGBL R15 K29 + 0x8C3C1F1E, // 009D GETMET R15 R15 K30 + 0x7C3C0200, // 009E CALL R15 1 + 0x943C1F1F, // 009F GETIDX R15 R15 K31 + 0x7C2C0800, // 00A0 CALL R11 4 + 0x8C2C1520, // 00A1 GETMET R11 R10 K32 + 0x7C2C0200, // 00A2 CALL R11 1 + 0x8C301121, // 00A3 GETMET R12 R8 K33 + 0x7C300200, // 00A4 CALL R12 1 + 0x0034160C, // 00A5 ADD R13 R11 R12 + 0xB83A3A00, // 00A6 GETNGBL R14 K29 + 0x8C381D22, // 00A7 GETMET R14 R14 K34 + 0x8C401B24, // 00A8 GETMET R16 R13 K36 + 0x7C400200, // 00A9 CALL R16 1 + 0x00424610, // 00AA ADD R16 K35 R16 + 0x58440011, // 00AB LDCONST R17 K17 + 0x7C380600, // 00AC CALL R14 3 + 0x8C380925, // 00AD GETMET R14 R4 K37 + 0x7C380200, // 00AE CALL R14 1 + 0x8C381D26, // 00AF GETMET R14 R14 K38 + 0xB8420200, // 00B0 GETNGBL R16 K1 + 0x8C402127, // 00B1 GETMET R16 R16 K39 + 0x7C400200, // 00B2 CALL R16 1 + 0x5C441A00, // 00B3 MOVE R17 R13 + 0x7C380600, // 00B4 CALL R14 3 + 0x8C3C0B0A, // 00B5 GETMET R15 R5 K10 + 0x7C3C0200, // 00B6 CALL R15 1 + 0x8C401F0B, // 00B7 GETMET R16 R15 K11 + 0x58480006, // 00B8 LDCONST R18 K6 + 0x884C0B17, // 00B9 GETMBR R19 R5 K23 + 0x5C501600, // 00BA MOVE R20 R11 + 0x7C400800, // 00BB CALL R16 4 + 0x8C401F0B, // 00BC GETMET R16 R15 K11 + 0x58480008, // 00BD LDCONST R18 K8 + 0x884C0B1B, // 00BE GETMBR R19 R5 K27 + 0x5C501C00, // 00BF MOVE R20 R14 + 0x7C400800, // 00C0 CALL R16 4 + 0x900E0908, // 00C1 SETMBR R3 K4 K8 + 0x80041E00, // 00C2 RET 1 R15 + 0x700200ED, // 00C3 JMP #01B2 + 0x54260003, // 00C4 LDINT R9 4 + 0x1C240E09, // 00C5 EQ R9 R7 R9 + 0x78260040, // 00C6 JMPF R9 #0108 + 0x8C240507, // 00C7 GETMET R9 R2 K7 + 0x582C0006, // 00C8 LDCONST R11 K6 + 0x7C240400, // 00C9 CALL R9 2 + 0x6028000C, // 00CA GETGBL R10 G12 + 0x5C2C1200, // 00CB MOVE R11 R9 + 0x7C280200, // 00CC CALL R10 1 + 0x542E001F, // 00CD LDINT R11 32 + 0x2028140B, // 00CE NE R10 R10 R11 + 0x782A0001, // 00CF JMPF R10 #00D2 + 0x4C280000, // 00D0 LDNIL R10 + 0x80041400, // 00D1 RET 1 R10 + 0x8C280507, // 00D2 GETMET R10 R2 K7 + 0x58300008, // 00D3 LDCONST R12 K8 + 0x50340000, // 00D4 LDBOOL R13 0 0 + 0x7C280600, // 00D5 CALL R10 3 + 0x8C2C1128, // 00D6 GETMET R11 R8 K40 + 0x7C2C0200, // 00D7 CALL R11 1 + 0x8C300B0A, // 00D8 GETMET R12 R5 K10 + 0x7C300200, // 00D9 CALL R12 1 + 0x8C34190B, // 00DA GETMET R13 R12 K11 + 0x583C0008, // 00DB LDCONST R15 K8 + 0x88400B17, // 00DC GETMBR R16 R5 K23 + 0x5C441600, // 00DD MOVE R17 R11 + 0x7C340800, // 00DE CALL R13 4 + 0x8C34190B, // 00DF GETMET R13 R12 K11 + 0x583C000F, // 00E0 LDCONST R15 K15 + 0x88400B1B, // 00E1 GETMBR R16 R5 K27 + 0x5C441200, // 00E2 MOVE R17 R9 + 0x7C340800, // 00E3 CALL R13 4 + 0x8C341920, // 00E4 GETMET R13 R12 K32 + 0x7C340200, // 00E5 CALL R13 1 + 0x8C381121, // 00E6 GETMET R14 R8 K33 + 0x7C380200, // 00E7 CALL R14 1 + 0x00381A0E, // 00E8 ADD R14 R13 R14 + 0xB83E3A00, // 00E9 GETNGBL R15 K29 + 0x8C3C1F22, // 00EA GETMET R15 R15 K34 + 0x8C441D24, // 00EB GETMET R17 R14 K36 + 0x7C440200, // 00EC CALL R17 1 + 0x00465211, // 00ED ADD R17 K41 R17 + 0x58480011, // 00EE LDCONST R18 K17 + 0x7C3C0600, // 00EF CALL R15 3 + 0x8C3C0925, // 00F0 GETMET R15 R4 K37 + 0x7C3C0200, // 00F1 CALL R15 1 + 0x8C3C1F26, // 00F2 GETMET R15 R15 K38 + 0xB8460200, // 00F3 GETNGBL R17 K1 + 0x8C442327, // 00F4 GETMET R17 R17 K39 + 0x7C440200, // 00F5 CALL R17 1 + 0x5C481C00, // 00F6 MOVE R18 R14 + 0x7C3C0600, // 00F7 CALL R15 3 + 0x8C400B0A, // 00F8 GETMET R16 R5 K10 + 0x7C400200, // 00F9 CALL R16 1 + 0x8C44210B, // 00FA GETMET R17 R16 K11 + 0x584C0006, // 00FB LDCONST R19 K6 + 0x88500B17, // 00FC GETMBR R20 R5 K23 + 0x5C541A00, // 00FD MOVE R21 R13 + 0x7C440800, // 00FE CALL R17 4 + 0x8C44210B, // 00FF GETMET R17 R16 K11 + 0x584C0008, // 0100 LDCONST R19 K8 + 0x88500B1B, // 0101 GETMBR R20 R5 K27 + 0x5C541E00, // 0102 MOVE R21 R15 + 0x7C440800, // 0103 CALL R17 4 + 0x54460004, // 0104 LDINT R17 5 + 0x900E0811, // 0105 SETMBR R3 K4 R17 + 0x80042000, // 0106 RET 1 R16 + 0x700200A9, // 0107 JMP #01B2 + 0x5426000A, // 0108 LDINT R9 11 + 0x1C240E09, // 0109 EQ R9 R7 R9 + 0x78260012, // 010A JMPF R9 #011E + 0x8C240507, // 010B GETMET R9 R2 K7 + 0x582C0006, // 010C LDCONST R11 K6 + 0x7C240400, // 010D CALL R9 2 + 0x8C28112A, // 010E GETMET R10 R8 K42 + 0x5C301200, // 010F MOVE R12 R9 + 0x7C280400, // 0110 CALL R10 2 + 0xB82A3A00, // 0111 GETNGBL R10 K29 + 0x8C281522, // 0112 GETMET R10 R10 K34 + 0x8C301324, // 0113 GETMET R12 R9 K36 + 0x7C300200, // 0114 CALL R12 1 + 0x0032560C, // 0115 ADD R12 K43 R12 + 0x58340011, // 0116 LDCONST R13 K17 + 0x7C280600, // 0117 CALL R10 3 + 0xB82A0200, // 0118 GETNGBL R10 K1 + 0x8828152C, // 0119 GETMBR R10 R10 K44 + 0x900E2A0A, // 011A SETMBR R3 K21 R10 + 0x4C280000, // 011B LDNIL R10 + 0x80041400, // 011C RET 1 R10 + 0x70020093, // 011D JMP #01B2 + 0x54260005, // 011E LDINT R9 6 + 0x1C240E09, // 011F EQ R9 R7 R9 + 0x78260090, // 0120 JMPF R9 #01B2 + 0x8C240507, // 0121 GETMET R9 R2 K7 + 0x582C0006, // 0122 LDCONST R11 K6 + 0x7C240400, // 0123 CALL R9 2 + 0x8C280507, // 0124 GETMET R10 R2 K7 + 0x58300008, // 0125 LDCONST R12 K8 + 0x7C280400, // 0126 CALL R10 2 + 0x8C2C0507, // 0127 GETMET R11 R2 K7 + 0x5834000F, // 0128 LDCONST R13 K15 + 0x7C2C0400, // 0129 CALL R11 2 + 0x8C300507, // 012A GETMET R12 R2 K7 + 0x58380011, // 012B LDCONST R14 K17 + 0x7C300400, // 012C CALL R12 2 + 0x8C340507, // 012D GETMET R13 R2 K7 + 0x543E0003, // 012E LDINT R15 4 + 0x7C340400, // 012F CALL R13 2 + 0x8C38112D, // 0130 GETMET R14 R8 K45 + 0x7C380200, // 0131 CALL R14 1 + 0x4C3C0000, // 0132 LDNIL R15 + 0x1C381C0F, // 0133 EQ R14 R14 R15 + 0x783A0006, // 0134 JMPF R14 #013C + 0xB83A3A00, // 0135 GETNGBL R14 K29 + 0x8C381D22, // 0136 GETMET R14 R14 K34 + 0x5840002E, // 0137 LDCONST R16 K46 + 0x5844000F, // 0138 LDCONST R17 K15 + 0x7C380600, // 0139 CALL R14 3 + 0x4C380000, // 013A LDNIL R14 + 0x80041C00, // 013B RET 1 R14 + 0x8C38112F, // 013C GETMET R14 R8 K47 + 0x5C401200, // 013D MOVE R16 R9 + 0x5C441400, // 013E MOVE R17 R10 + 0x7C380600, // 013F CALL R14 3 + 0x8C381130, // 0140 GETMET R14 R8 K48 + 0x5C401600, // 0141 MOVE R16 R11 + 0x7C380400, // 0142 CALL R14 2 + 0x9022620C, // 0143 SETMBR R8 K49 R12 + 0x9022640D, // 0144 SETMBR R8 K50 R13 + 0xB83A0200, // 0145 GETNGBL R14 K1 + 0x88381D02, // 0146 GETMBR R14 R14 K2 + 0x8C381D33, // 0147 GETMET R14 R14 K51 + 0x5C401200, // 0148 MOVE R16 R9 + 0x7C380400, // 0149 CALL R14 2 + 0x8C3C1D34, // 014A GETMET R15 R14 K52 + 0x54460005, // 014B LDINT R17 6 + 0x7C3C0400, // 014C CALL R15 2 + 0x8C401F07, // 014D GETMET R16 R15 K7 + 0x544A0014, // 014E LDINT R18 21 + 0x7C400400, // 014F CALL R16 2 + 0x8C441F07, // 0150 GETMET R17 R15 K7 + 0x544E0010, // 0151 LDINT R19 17 + 0x7C440400, // 0152 CALL R17 2 + 0x5C482000, // 0153 MOVE R18 R16 + 0x784A0001, // 0154 JMPF R18 #0157 + 0x5C482200, // 0155 MOVE R18 R17 + 0x744A0006, // 0156 JMPT R18 #015E + 0xB84A3A00, // 0157 GETNGBL R18 K29 + 0x8C482522, // 0158 GETMET R18 R18 K34 + 0x58500035, // 0159 LDCONST R20 K53 + 0x5854000F, // 015A LDCONST R21 K15 + 0x7C480600, // 015B CALL R18 3 + 0x50480000, // 015C LDBOOL R18 0 0 + 0x80042400, // 015D RET 1 R18 + 0x60480004, // 015E GETGBL R18 G4 + 0x5C4C2000, // 015F MOVE R19 R16 + 0x7C480200, // 0160 CALL R18 1 + 0x1C482536, // 0161 EQ R18 R18 K54 + 0x784A0006, // 0162 JMPF R18 #016A + 0xB84A6E00, // 0163 GETNGBL R18 K55 + 0x5C4C2000, // 0164 MOVE R19 R16 + 0x7C480200, // 0165 CALL R18 1 + 0x8C482538, // 0166 GETMET R18 R18 K56 + 0x7C480200, // 0167 CALL R18 1 + 0x5C402400, // 0168 MOVE R16 R18 + 0x70020002, // 0169 JMP #016D + 0x8C482138, // 016A GETMET R18 R16 K56 + 0x7C480200, // 016B CALL R18 1 + 0x5C402400, // 016C MOVE R16 R18 + 0x60480004, // 016D GETGBL R18 G4 + 0x5C4C2200, // 016E MOVE R19 R17 + 0x7C480200, // 016F CALL R18 1 + 0x1C482536, // 0170 EQ R18 R18 K54 + 0x784A0006, // 0171 JMPF R18 #0179 + 0xB84A6E00, // 0172 GETNGBL R18 K55 + 0x5C4C2200, // 0173 MOVE R19 R17 + 0x7C480200, // 0174 CALL R18 1 + 0x8C482538, // 0175 GETMET R18 R18 K56 + 0x7C480200, // 0176 CALL R18 1 + 0x5C442400, // 0177 MOVE R17 R18 + 0x70020002, // 0178 JMP #017C + 0x8C482338, // 0179 GETMET R18 R17 K56 + 0x7C480200, // 017A CALL R18 1 + 0x5C442400, // 017B MOVE R17 R18 + 0xB84A0200, // 017C GETNGBL R18 K1 + 0x88482502, // 017D GETMBR R18 R18 K2 + 0x8C482533, // 017E GETMET R18 R18 K51 + 0x8C50112D, // 017F GETMET R20 R8 K45 + 0x7C500200, // 0180 CALL R20 1 + 0x7C480400, // 0181 CALL R18 2 + 0x8C482507, // 0182 GETMET R18 R18 K7 + 0x54520008, // 0183 LDINT R20 9 + 0x7C480400, // 0184 CALL R18 2 + 0x404E1139, // 0185 CONNECT R19 K8 K57 + 0x94482413, // 0186 GETIDX R18 R18 R19 + 0x60500015, // 0187 GETGBL R20 G21 + 0x7C500000, // 0188 CALL R20 0 + 0x8C50293A, // 0189 GETMET R20 R20 K58 + 0x5858003B, // 018A LDCONST R22 K59 + 0x7C500400, // 018B CALL R20 2 + 0x5C4C2800, // 018C MOVE R19 R20 + 0x8C50093C, // 018D GETMET R20 R4 K60 + 0x7C500200, // 018E CALL R20 1 + 0x8C54213D, // 018F GETMET R21 R16 K61 + 0x7C540200, // 0190 CALL R21 1 + 0x8C542B3E, // 0191 GETMET R21 R21 K62 + 0x7C540200, // 0192 CALL R21 1 + 0x8C58293F, // 0193 GETMET R22 R20 K63 + 0x5C602400, // 0194 MOVE R24 R18 + 0x5C642A00, // 0195 MOVE R25 R21 + 0x5C682600, // 0196 MOVE R26 R19 + 0x546E0007, // 0197 LDINT R27 8 + 0x7C580A00, // 0198 CALL R22 5 + 0x8C5C1140, // 0199 GETMET R23 R8 K64 + 0x5C642000, // 019A MOVE R25 R16 + 0x5C682200, // 019B MOVE R26 R17 + 0x5C6C2C00, // 019C MOVE R27 R22 + 0x7C5C0800, // 019D CALL R23 4 + 0x885C0113, // 019E GETMBR R23 R0 K19 + 0x8C5C2F41, // 019F GETMET R23 R23 K65 + 0x5C641000, // 01A0 MOVE R25 R8 + 0x7C5C0400, // 01A1 CALL R23 2 + 0x8C5C0B0A, // 01A2 GETMET R23 R5 K10 + 0x7C5C0200, // 01A3 CALL R23 1 + 0x8C602F0B, // 01A4 GETMET R24 R23 K11 + 0x58680006, // 01A5 LDCONST R26 K6 + 0x886C0B0C, // 01A6 GETMBR R27 R5 K12 + 0xB8720200, // 01A7 GETNGBL R28 K1 + 0x8870392C, // 01A8 GETMBR R28 R28 K44 + 0x7C600800, // 01A9 CALL R24 4 + 0x8C602F0B, // 01AA GETMET R24 R23 K11 + 0x58680008, // 01AB LDCONST R26 K8 + 0x886C0B0C, // 01AC GETMBR R27 R5 K12 + 0x58700008, // 01AD LDCONST R28 K8 + 0x7C600800, // 01AE CALL R24 4 + 0x54620007, // 01AF LDINT R24 8 + 0x900E0818, // 01B0 SETMBR R3 K4 R24 + 0x80042E00, // 01B1 RET 1 R23 + 0x80000000, // 01B2 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_Plugin_core +********************************************************************/ +extern const bclass be_class_Matter_Plugin; +be_local_class(Matter_Plugin_core, + 0, + &be_class_Matter_Plugin, + be_nested_map(3, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(read_attribute, 1), be_const_closure(Matter_Plugin_core_read_attribute_closure) }, + { be_const_key_weak(init, -1), be_const_closure(Matter_Plugin_core_init_closure) }, + { be_const_key_weak(invoke_request, -1), be_const_closure(Matter_Plugin_core_invoke_request_closure) }, + })), + be_str_weak(Matter_Plugin_core) +); +/*******************************************************************/ + +void be_load_Matter_Plugin_core_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Plugin_core); + be_setglobal(vm, "Matter_Plugin_core"); + be_pop(vm, 1); +} +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Session.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Session.h new file mode 100644 index 000000000..30d718e06 --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Session.h @@ -0,0 +1,2239 @@ +/* Solidification of Matter_Session.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_Session; + +/******************************************************************** +** Solidified function: get_pk +********************************************************************/ +be_local_closure(Matter_Session_get_pk, /* name */ + be_nested_proto( + 5, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(no_private_key), + /* K1 */ be_nested_str_weak(crypto), + /* K2 */ be_nested_str_weak(random), + }), + be_str_weak(get_pk), + &be_const_str_solidified, + ( &(const binstruction[ 9]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x74060004, // 0001 JMPT R1 #0007 + 0xA4060200, // 0002 IMPORT R1 K1 + 0x8C080302, // 0003 GETMET R2 R1 K2 + 0x5412001F, // 0004 LDINT R4 32 + 0x7C080400, // 0005 CALL R2 2 + 0x90020002, // 0006 SETMBR R0 K0 R2 + 0x88040100, // 0007 GETMBR R1 R0 K0 + 0x80040200, // 0008 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_ac +********************************************************************/ +be_local_closure(Matter_Session_get_ac, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(attestation_challenge), + }), + be_str_weak(get_ac), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_ipk_group_key +********************************************************************/ +be_local_closure(Matter_Session_get_ipk_group_key, /* name */ + be_nested_proto( + 10, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 7]) { /* constants */ + /* K0 */ be_nested_str_weak(ipk_epoch_key), + /* K1 */ be_nested_str_weak(fabric_compressed), + /* K2 */ be_nested_str_weak(crypto), + /* K3 */ be_nested_str_weak(HKDF_SHA256), + /* K4 */ be_nested_str_weak(fromstring), + /* K5 */ be_nested_str_weak(__GROUP_KEY), + /* K6 */ be_nested_str_weak(derive), + }), + be_str_weak(get_ipk_group_key), + &be_const_str_solidified, + ( &(const binstruction[25]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x4C080000, // 0001 LDNIL R2 + 0x1C040202, // 0002 EQ R1 R1 R2 + 0x74060003, // 0003 JMPT R1 #0008 + 0x88040101, // 0004 GETMBR R1 R0 K1 + 0x4C080000, // 0005 LDNIL R2 + 0x1C040202, // 0006 EQ R1 R1 R2 + 0x78060001, // 0007 JMPF R1 #000A + 0x4C040000, // 0008 LDNIL R1 + 0x80040200, // 0009 RET 1 R1 + 0xA4060400, // 000A IMPORT R1 K2 + 0x8C080303, // 000B GETMET R2 R1 K3 + 0x7C080200, // 000C CALL R2 1 + 0x600C0015, // 000D GETGBL R3 G21 + 0x7C0C0000, // 000E CALL R3 0 + 0x8C0C0704, // 000F GETMET R3 R3 K4 + 0x88140105, // 0010 GETMBR R5 R0 K5 + 0x7C0C0400, // 0011 CALL R3 2 + 0x8C100506, // 0012 GETMET R4 R2 K6 + 0x88180100, // 0013 GETMBR R6 R0 K0 + 0x881C0101, // 0014 GETMBR R7 R0 K1 + 0x5C200600, // 0015 MOVE R8 R3 + 0x5426000F, // 0016 LDINT R9 16 + 0x7C100A00, // 0017 CALL R4 5 + 0x80040800, // 0018 RET 1 R4 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_ca +********************************************************************/ +be_local_closure(Matter_Session_set_ca, /* name */ + be_nested_proto( + 2, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(root_ca_certificate), + }), + be_str_weak(set_ca), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x80000000, // 0001 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: save +********************************************************************/ +be_local_closure(Matter_Session_save, /* name */ + be_nested_proto( + 3, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(__store), + /* K1 */ be_nested_str_weak(save), + }), + be_str_weak(save), + &be_const_str_solidified, + ( &(const binstruction[ 4]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0x7C040200, // 0002 CALL R1 1 + 0x80000000, // 0003 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_ipk_epoch_key +********************************************************************/ +be_local_closure(Matter_Session_set_ipk_epoch_key, /* name */ + be_nested_proto( + 2, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(ipk_epoch_key), + }), + be_str_weak(set_ipk_epoch_key), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x80000000, // 0001 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_expire_time +********************************************************************/ +be_local_closure(Matter_Session_set_expire_time, /* name */ + be_nested_proto( + 4, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(expiration), + }), + be_str_weak(set_expire_time), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x60080009, // 0000 GETGBL R2 G9 + 0x5C0C0200, // 0001 MOVE R3 R1 + 0x7C080200, // 0002 CALL R2 1 + 0x90020002, // 0003 SETMBR R0 K0 R2 + 0x80000000, // 0004 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_expire_in_seconds +********************************************************************/ +be_local_closure(Matter_Session_set_expire_in_seconds, /* name */ + be_nested_proto( + 6, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(tasmota), + /* K1 */ be_nested_str_weak(rtc), + /* K2 */ be_nested_str_weak(utc), + /* K3 */ be_nested_str_weak(set_expire_time), + }), + be_str_weak(set_expire_in_seconds), + &be_const_str_solidified, + ( &(const binstruction[15]) { /* code */ + 0x4C0C0000, // 0000 LDNIL R3 + 0x1C0C0203, // 0001 EQ R3 R1 R3 + 0x780E0000, // 0002 JMPF R3 #0004 + 0x80000600, // 0003 RET 0 + 0x4C0C0000, // 0004 LDNIL R3 + 0x1C0C0403, // 0005 EQ R3 R2 R3 + 0x780E0003, // 0006 JMPF R3 #000B + 0xB80E0000, // 0007 GETNGBL R3 K0 + 0x8C0C0701, // 0008 GETMET R3 R3 K1 + 0x7C0C0200, // 0009 CALL R3 1 + 0x94080702, // 000A GETIDX R2 R3 K2 + 0x8C0C0103, // 000B GETMET R3 R0 K3 + 0x00140401, // 000C ADD R5 R2 R1 + 0x7C0C0400, // 000D CALL R3 2 + 0x80000000, // 000E RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: tojson +********************************************************************/ +be_local_closure(Matter_Session_tojson, /* name */ + be_nested_proto( + 18, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[24]) { /* constants */ + /* K0 */ be_nested_str_weak(json), + /* K1 */ be_nested_str_weak(string), + /* K2 */ be_nested_str_weak(introspect), + /* K3 */ be_nested_str_weak(members), + /* K4 */ be_nested_str_weak(get), + /* K5 */ be_nested_str_weak(function), + /* K6 */ be_const_int(0), + /* K7 */ be_nested_str_weak(_), + /* K8 */ be_nested_str_weak(push), + /* K9 */ be_nested_str_weak(stop_iteration), + /* K10 */ be_nested_str_weak(matter), + /* K11 */ be_nested_str_weak(sort), + /* K12 */ be_nested_str_weak(counter_rcv), + /* K13 */ be_nested_str_weak(val), + /* K14 */ be_nested_str_weak(counter_snd), + /* K15 */ be_nested_str_weak(_X24_X24), + /* K16 */ be_nested_str_weak(tob64), + /* K17 */ be_nested_str_weak(format), + /* K18 */ be_nested_str_weak(_X25s_X3A_X25s), + /* K19 */ be_nested_str_weak(dump), + /* K20 */ be_nested_str_weak(_X7B), + /* K21 */ be_nested_str_weak(concat), + /* K22 */ be_nested_str_weak(_X2C), + /* K23 */ be_nested_str_weak(_X7D), + }), + be_str_weak(tojson), + &be_const_str_solidified, + ( &(const binstruction[98]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0xA40A0200, // 0001 IMPORT R2 K1 + 0xA40E0400, // 0002 IMPORT R3 K2 + 0x60100012, // 0003 GETGBL R4 G18 + 0x7C100000, // 0004 CALL R4 0 + 0x60140010, // 0005 GETGBL R5 G16 + 0x8C180703, // 0006 GETMET R6 R3 K3 + 0x5C200000, // 0007 MOVE R8 R0 + 0x7C180400, // 0008 CALL R6 2 + 0x7C140200, // 0009 CALL R5 1 + 0xA8020011, // 000A EXBLK 0 #001D + 0x5C180A00, // 000B MOVE R6 R5 + 0x7C180000, // 000C CALL R6 0 + 0x8C1C0704, // 000D GETMET R7 R3 K4 + 0x5C240000, // 000E MOVE R9 R0 + 0x5C280C00, // 000F MOVE R10 R6 + 0x7C1C0600, // 0010 CALL R7 3 + 0x60200004, // 0011 GETGBL R8 G4 + 0x5C240E00, // 0012 MOVE R9 R7 + 0x7C200200, // 0013 CALL R8 1 + 0x20201105, // 0014 NE R8 R8 K5 + 0x78220005, // 0015 JMPF R8 #001C + 0x94200D06, // 0016 GETIDX R8 R6 K6 + 0x20201107, // 0017 NE R8 R8 K7 + 0x78220002, // 0018 JMPF R8 #001C + 0x8C200908, // 0019 GETMET R8 R4 K8 + 0x5C280C00, // 001A MOVE R10 R6 + 0x7C200400, // 001B CALL R8 2 + 0x7001FFED, // 001C JMP #000B + 0x58140009, // 001D LDCONST R5 K9 + 0xAC140200, // 001E CATCH R5 1 0 + 0xB0080000, // 001F RAISE 2 R0 R0 + 0xB8161400, // 0020 GETNGBL R5 K10 + 0x8C140B0B, // 0021 GETMET R5 R5 K11 + 0x5C1C0800, // 0022 MOVE R7 R4 + 0x7C140400, // 0023 CALL R5 2 + 0x5C100A00, // 0024 MOVE R4 R5 + 0x60140012, // 0025 GETGBL R5 G18 + 0x7C140000, // 0026 CALL R5 0 + 0x60180010, // 0027 GETGBL R6 G16 + 0x5C1C0800, // 0028 MOVE R7 R4 + 0x7C180200, // 0029 CALL R6 1 + 0xA802002D, // 002A EXBLK 0 #0059 + 0x5C1C0C00, // 002B MOVE R7 R6 + 0x7C1C0000, // 002C CALL R7 0 + 0x8C200704, // 002D GETMET R8 R3 K4 + 0x5C280000, // 002E MOVE R10 R0 + 0x5C2C0E00, // 002F MOVE R11 R7 + 0x7C200600, // 0030 CALL R8 3 + 0x4C240000, // 0031 LDNIL R9 + 0x1C241009, // 0032 EQ R9 R8 R9 + 0x78260000, // 0033 JMPF R9 #0035 + 0x7001FFF5, // 0034 JMP #002B + 0x1C240F0C, // 0035 EQ R9 R7 K12 + 0x78260003, // 0036 JMPF R9 #003B + 0x8C24110D, // 0037 GETMET R9 R8 K13 + 0x7C240200, // 0038 CALL R9 1 + 0x5C201200, // 0039 MOVE R8 R9 + 0x70020006, // 003A JMP #0042 + 0x1C240F0E, // 003B EQ R9 R7 K14 + 0x78260004, // 003C JMPF R9 #0042 + 0x8C24110D, // 003D GETMET R9 R8 K13 + 0x7C240200, // 003E CALL R9 1 + 0x542A00FF, // 003F LDINT R10 256 + 0x0024120A, // 0040 ADD R9 R9 R10 + 0x5C201200, // 0041 MOVE R8 R9 + 0x6024000F, // 0042 GETGBL R9 G15 + 0x5C281000, // 0043 MOVE R10 R8 + 0x602C0015, // 0044 GETGBL R11 G21 + 0x7C240400, // 0045 CALL R9 2 + 0x78260003, // 0046 JMPF R9 #004B + 0x8C241110, // 0047 GETMET R9 R8 K16 + 0x7C240200, // 0048 CALL R9 1 + 0x00261E09, // 0049 ADD R9 K15 R9 + 0x5C201200, // 004A MOVE R8 R9 + 0x8C240B08, // 004B GETMET R9 R5 K8 + 0x8C2C0511, // 004C GETMET R11 R2 K17 + 0x58340012, // 004D LDCONST R13 K18 + 0x8C380313, // 004E GETMET R14 R1 K19 + 0x60400008, // 004F GETGBL R16 G8 + 0x5C440E00, // 0050 MOVE R17 R7 + 0x7C400200, // 0051 CALL R16 1 + 0x7C380400, // 0052 CALL R14 2 + 0x8C3C0313, // 0053 GETMET R15 R1 K19 + 0x5C441000, // 0054 MOVE R17 R8 + 0x7C3C0400, // 0055 CALL R15 2 + 0x7C2C0800, // 0056 CALL R11 4 + 0x7C240400, // 0057 CALL R9 2 + 0x7001FFD1, // 0058 JMP #002B + 0x58180009, // 0059 LDCONST R6 K9 + 0xAC180200, // 005A CATCH R6 1 0 + 0xB0080000, // 005B RAISE 2 R0 R0 + 0x8C180B15, // 005C GETMET R6 R5 K21 + 0x58200016, // 005D LDCONST R8 K22 + 0x7C180400, // 005E CALL R6 2 + 0x001A2806, // 005F ADD R6 K20 R6 + 0x00180D17, // 0060 ADD R6 R6 K23 + 0x80040C00, // 0061 RET 1 R6 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_noc +********************************************************************/ +be_local_closure(Matter_Session_get_noc, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(noc), + }), + be_str_weak(get_noc), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_fabric +********************************************************************/ +be_local_closure(Matter_Session_get_fabric, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(fabric), + }), + be_str_weak(get_fabric), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: has_expired +********************************************************************/ +be_local_closure(Matter_Session_has_expired, /* name */ + be_nested_proto( + 4, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(tasmota), + /* K1 */ be_nested_str_weak(rtc), + /* K2 */ be_nested_str_weak(utc), + /* K3 */ be_nested_str_weak(expiration), + }), + be_str_weak(has_expired), + &be_const_str_solidified, + ( &(const binstruction[16]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0003, // 0002 JMPF R2 #0007 + 0xB80A0000, // 0003 GETNGBL R2 K0 + 0x8C080501, // 0004 GETMET R2 R2 K1 + 0x7C080200, // 0005 CALL R2 1 + 0x94040502, // 0006 GETIDX R1 R2 K2 + 0x88080103, // 0007 GETMBR R2 R0 K3 + 0x4C0C0000, // 0008 LDNIL R3 + 0x20080403, // 0009 NE R2 R2 R3 + 0x780A0002, // 000A JMPF R2 #000E + 0x88080103, // 000B GETMBR R2 R0 K3 + 0x28080202, // 000C GE R2 R1 R2 + 0x80040400, // 000D RET 1 R2 + 0x50080000, // 000E LDBOOL R2 0 0 + 0x80040400, // 000F RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: fromjson +********************************************************************/ +be_local_closure(Matter_Session_fromjson, /* name */ + be_nested_proto( + 16, /* nstack */ + 2, /* argc */ + 4, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[19]) { /* constants */ + /* K0 */ be_const_class(be_class_Matter_Session), + /* K1 */ be_nested_str_weak(string), + /* K2 */ be_nested_str_weak(introspect), + /* K3 */ be_nested_str_weak(matter), + /* K4 */ be_nested_str_weak(Session), + /* K5 */ be_nested_str_weak(keys), + /* K6 */ be_nested_str_weak(counter_rcv), + /* K7 */ be_nested_str_weak(reset), + /* K8 */ be_nested_str_weak(counter_snd), + /* K9 */ be_nested_str_weak(find), + /* K10 */ be_nested_str_weak(0x), + /* K11 */ be_const_int(0), + /* K12 */ be_nested_str_weak(set), + /* K13 */ be_nested_str_weak(fromhex), + /* K14 */ be_const_int(2), + /* K15 */ be_const_int(2147483647), + /* K16 */ be_nested_str_weak(_X24_X24), + /* K17 */ be_nested_str_weak(fromb64), + /* K18 */ be_nested_str_weak(stop_iteration), + }), + be_str_weak(fromjson), + &be_const_str_solidified, + ( &(const binstruction[88]) { /* code */ + 0x58080000, // 0000 LDCONST R2 K0 + 0xA40E0200, // 0001 IMPORT R3 K1 + 0xA4120400, // 0002 IMPORT R4 K2 + 0xB8160600, // 0003 GETNGBL R5 K3 + 0x8C140B04, // 0004 GETMET R5 R5 K4 + 0x5C1C0000, // 0005 MOVE R7 R0 + 0x7C140400, // 0006 CALL R5 2 + 0x60180010, // 0007 GETGBL R6 G16 + 0x8C1C0305, // 0008 GETMET R7 R1 K5 + 0x7C1C0200, // 0009 CALL R7 1 + 0x7C180200, // 000A CALL R6 1 + 0xA8020047, // 000B EXBLK 0 #0054 + 0x5C1C0C00, // 000C MOVE R7 R6 + 0x7C1C0000, // 000D CALL R7 0 + 0x94200207, // 000E GETIDX R8 R1 R7 + 0x1C240F06, // 000F EQ R9 R7 K6 + 0x78260006, // 0010 JMPF R9 #0018 + 0x88240B06, // 0011 GETMBR R9 R5 K6 + 0x8C241307, // 0012 GETMET R9 R9 K7 + 0x602C0009, // 0013 GETGBL R11 G9 + 0x5C301000, // 0014 MOVE R12 R8 + 0x7C2C0200, // 0015 CALL R11 1 + 0x7C240400, // 0016 CALL R9 2 + 0x7002003A, // 0017 JMP #0053 + 0x1C240F08, // 0018 EQ R9 R7 K8 + 0x78260006, // 0019 JMPF R9 #0021 + 0x88240B08, // 001A GETMBR R9 R5 K8 + 0x8C241307, // 001B GETMET R9 R9 K7 + 0x602C0009, // 001C GETGBL R11 G9 + 0x5C301000, // 001D MOVE R12 R8 + 0x7C2C0200, // 001E CALL R11 1 + 0x7C240400, // 001F CALL R9 2 + 0x70020031, // 0020 JMP #0053 + 0x60240004, // 0021 GETGBL R9 G4 + 0x5C281000, // 0022 MOVE R10 R8 + 0x7C240200, // 0023 CALL R9 1 + 0x1C241301, // 0024 EQ R9 R9 K1 + 0x78260027, // 0025 JMPF R9 #004E + 0x8C240709, // 0026 GETMET R9 R3 K9 + 0x5C2C1000, // 0027 MOVE R11 R8 + 0x5830000A, // 0028 LDCONST R12 K10 + 0x7C240600, // 0029 CALL R9 3 + 0x1C24130B, // 002A EQ R9 R9 K11 + 0x7826000A, // 002B JMPF R9 #0037 + 0x8C24090C, // 002C GETMET R9 R4 K12 + 0x5C2C0A00, // 002D MOVE R11 R5 + 0x5C300E00, // 002E MOVE R12 R7 + 0x60340015, // 002F GETGBL R13 G21 + 0x7C340000, // 0030 CALL R13 0 + 0x8C341B0D, // 0031 GETMET R13 R13 K13 + 0x403E1D0F, // 0032 CONNECT R15 K14 K15 + 0x943C100F, // 0033 GETIDX R15 R8 R15 + 0x7C340400, // 0034 CALL R13 2 + 0x7C240800, // 0035 CALL R9 4 + 0x70020015, // 0036 JMP #004D + 0x8C240709, // 0037 GETMET R9 R3 K9 + 0x5C2C1000, // 0038 MOVE R11 R8 + 0x58300010, // 0039 LDCONST R12 K16 + 0x7C240600, // 003A CALL R9 3 + 0x1C24130B, // 003B EQ R9 R9 K11 + 0x7826000A, // 003C JMPF R9 #0048 + 0x8C24090C, // 003D GETMET R9 R4 K12 + 0x5C2C0A00, // 003E MOVE R11 R5 + 0x5C300E00, // 003F MOVE R12 R7 + 0x60340015, // 0040 GETGBL R13 G21 + 0x7C340000, // 0041 CALL R13 0 + 0x8C341B11, // 0042 GETMET R13 R13 K17 + 0x403E1D0F, // 0043 CONNECT R15 K14 K15 + 0x943C100F, // 0044 GETIDX R15 R8 R15 + 0x7C340400, // 0045 CALL R13 2 + 0x7C240800, // 0046 CALL R9 4 + 0x70020004, // 0047 JMP #004D + 0x8C24090C, // 0048 GETMET R9 R4 K12 + 0x5C2C0A00, // 0049 MOVE R11 R5 + 0x5C300E00, // 004A MOVE R12 R7 + 0x5C341000, // 004B MOVE R13 R8 + 0x7C240800, // 004C CALL R9 4 + 0x70020004, // 004D JMP #0053 + 0x8C24090C, // 004E GETMET R9 R4 K12 + 0x5C2C0A00, // 004F MOVE R11 R5 + 0x5C300E00, // 0050 MOVE R12 R7 + 0x5C341000, // 0051 MOVE R13 R8 + 0x7C240800, // 0052 CALL R9 4 + 0x7001FFB7, // 0053 JMP #000C + 0x58180012, // 0054 LDCONST R6 K18 + 0xAC180200, // 0055 CATCH R6 1 0 + 0xB0080000, // 0056 RAISE 2 R0 R0 + 0x80040A00, // 0057 RET 1 R5 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_no_expiration +********************************************************************/ +be_local_closure(Matter_Session_set_no_expiration, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(expiration), + }), + be_str_weak(set_no_expiration), + &be_const_str_solidified, + ( &(const binstruction[ 3]) { /* code */ + 0x4C040000, // 0000 LDNIL R1 + 0x90020001, // 0001 SETMBR R0 K0 R1 + 0x80000000, // 0002 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: gen_CSR +********************************************************************/ +be_local_closure(Matter_Session_gen_CSR, /* name */ + be_nested_proto( + 15, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[12]) { /* constants */ + /* K0 */ be_nested_str_weak(get_pk), + /* K1 */ be_nested_str_weak(crypto), + /* K2 */ be_nested_str_weak(EC_P256), + /* K3 */ be_nested_str_weak(public_key), + /* K4 */ be_nested_str_weak(3070020100300E310C300A060355040A0C034353523059301306072A8648CE3D020106082A8648CE3D030107034200), + /* K5 */ be_nested_str_weak(A000), + /* K6 */ be_nested_str_weak(300C06082A8648CE3D0403020500), + /* K7 */ be_nested_str_weak(ecdsa_sign_sha256_asn1), + /* K8 */ be_nested_str_weak(add), + /* K9 */ be_const_int(3), + /* K10 */ be_const_int(1), + /* K11 */ be_const_int(0), + }), + be_str_weak(gen_CSR), + &be_const_str_solidified, + ( &(const binstruction[73]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x7C040200, // 0001 CALL R1 1 + 0xA40A0200, // 0002 IMPORT R2 K1 + 0x8C0C0502, // 0003 GETMET R3 R2 K2 + 0x7C0C0200, // 0004 CALL R3 1 + 0x8C100703, // 0005 GETMET R4 R3 K3 + 0x5C180200, // 0006 MOVE R6 R1 + 0x7C100400, // 0007 CALL R4 2 + 0x60140015, // 0008 GETGBL R5 G21 + 0x58180004, // 0009 LDCONST R6 K4 + 0x7C140200, // 000A CALL R5 1 + 0x40180A04, // 000B CONNECT R6 R5 R4 + 0x60180015, // 000C GETGBL R6 G21 + 0x581C0005, // 000D LDCONST R7 K5 + 0x7C180200, // 000E CALL R6 1 + 0x40180A06, // 000F CONNECT R6 R5 R6 + 0x60180015, // 0010 GETGBL R6 G21 + 0x581C0006, // 0011 LDCONST R7 K6 + 0x7C180200, // 0012 CALL R6 1 + 0x8C1C0707, // 0013 GETMET R7 R3 K7 + 0x5C240200, // 0014 MOVE R9 R1 + 0x5C280A00, // 0015 MOVE R10 R5 + 0x7C1C0600, // 0016 CALL R7 3 + 0x60200015, // 0017 GETGBL R8 G21 + 0x5426007F, // 0018 LDINT R9 128 + 0x7C200200, // 0019 CALL R8 1 + 0x8C241108, // 001A GETMET R9 R8 K8 + 0x582C0009, // 001B LDCONST R11 K9 + 0x5830000A, // 001C LDCONST R12 K10 + 0x7C240600, // 001D CALL R9 3 + 0x8C241108, // 001E GETMET R9 R8 K8 + 0x602C000C, // 001F GETGBL R11 G12 + 0x5C300E00, // 0020 MOVE R12 R7 + 0x7C2C0200, // 0021 CALL R11 1 + 0x002C170A, // 0022 ADD R11 R11 K10 + 0x5830000A, // 0023 LDCONST R12 K10 + 0x7C240600, // 0024 CALL R9 3 + 0x8C241108, // 0025 GETMET R9 R8 K8 + 0x582C000B, // 0026 LDCONST R11 K11 + 0x5830000A, // 0027 LDCONST R12 K10 + 0x7C240600, // 0028 CALL R9 3 + 0x40241007, // 0029 CONNECT R9 R8 R7 + 0x6024000C, // 002A GETGBL R9 G12 + 0x5C280A00, // 002B MOVE R10 R5 + 0x7C240200, // 002C CALL R9 1 + 0x6028000C, // 002D GETGBL R10 G12 + 0x5C2C0C00, // 002E MOVE R11 R6 + 0x7C280200, // 002F CALL R10 1 + 0x0024120A, // 0030 ADD R9 R9 R10 + 0x6028000C, // 0031 GETGBL R10 G12 + 0x5C2C1000, // 0032 MOVE R11 R8 + 0x7C280200, // 0033 CALL R10 1 + 0x0024120A, // 0034 ADD R9 R9 R10 + 0x60280015, // 0035 GETGBL R10 G21 + 0x542E00CF, // 0036 LDINT R11 208 + 0x7C280200, // 0037 CALL R10 1 + 0x8C2C1508, // 0038 GETMET R11 R10 K8 + 0x5436002F, // 0039 LDINT R13 48 + 0x5838000A, // 003A LDCONST R14 K10 + 0x7C2C0600, // 003B CALL R11 3 + 0x8C2C1508, // 003C GETMET R11 R10 K8 + 0x54360080, // 003D LDINT R13 129 + 0x5838000A, // 003E LDCONST R14 K10 + 0x7C2C0600, // 003F CALL R11 3 + 0x8C2C1508, // 0040 GETMET R11 R10 K8 + 0x543600FE, // 0041 LDINT R13 255 + 0x2C34120D, // 0042 AND R13 R9 R13 + 0x5838000A, // 0043 LDCONST R14 K10 + 0x7C2C0600, // 0044 CALL R11 3 + 0x402C1405, // 0045 CONNECT R11 R10 R5 + 0x402C1406, // 0046 CONNECT R11 R10 R6 + 0x402C1408, // 0047 CONNECT R11 R10 R8 + 0x80041400, // 0048 RET 1 R10 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_r2i +********************************************************************/ +be_local_closure(Matter_Session_get_r2i, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(r2ikey), + }), + be_str_weak(get_r2i), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_keys +********************************************************************/ +be_local_closure(Matter_Session_set_keys, /* name */ + be_nested_proto( + 5, /* nstack */ + 5, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(i2rkey), + /* K1 */ be_nested_str_weak(r2ikey), + /* K2 */ be_nested_str_weak(attestation_challenge), + /* K3 */ be_nested_str_weak(session_timestamp), + }), + be_str_weak(set_keys), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x90020202, // 0001 SETMBR R0 K1 R2 + 0x90020403, // 0002 SETMBR R0 K2 R3 + 0x90020604, // 0003 SETMBR R0 K3 R4 + 0x80000000, // 0004 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_noc +********************************************************************/ +be_local_closure(Matter_Session_set_noc, /* name */ + be_nested_proto( + 3, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(noc), + /* K1 */ be_nested_str_weak(icac), + }), + be_str_weak(set_noc), + &be_const_str_solidified, + ( &(const binstruction[ 3]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x90020202, // 0001 SETMBR R0 K1 R2 + 0x80000000, // 0002 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_fabric_device +********************************************************************/ +be_local_closure(Matter_Session_set_fabric_device, /* name */ + be_nested_proto( + 7, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(fabric), + /* K1 */ be_nested_str_weak(deviceid), + /* K2 */ be_nested_str_weak(fabric_compressed), + /* K3 */ be_nested_str_weak(__store), + /* K4 */ be_nested_str_weak(remove_redundant_session), + }), + be_str_weak(set_fabric_device), + &be_const_str_solidified, + ( &(const binstruction[ 8]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x90020202, // 0001 SETMBR R0 K1 R2 + 0x90020403, // 0002 SETMBR R0 K2 R3 + 0x88100103, // 0003 GETMBR R4 R0 K3 + 0x8C100904, // 0004 GETMET R4 R4 K4 + 0x5C180000, // 0005 MOVE R6 R0 + 0x7C100400, // 0006 CALL R4 2 + 0x80000000, // 0007 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_ipk_epoch_key +********************************************************************/ +be_local_closure(Matter_Session_get_ipk_epoch_key, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(ipk_epoch_key), + }), + be_str_weak(get_ipk_epoch_key), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_mode +********************************************************************/ +be_local_closure(Matter_Session_get_mode, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(mode), + }), + be_str_weak(get_mode), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_fabric_compressed +********************************************************************/ +be_local_closure(Matter_Session_get_fabric_compressed, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(fabric_compressed), + }), + be_str_weak(get_fabric_compressed), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_mode +********************************************************************/ +be_local_closure(Matter_Session_set_mode, /* name */ + be_nested_proto( + 2, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(mode), + }), + be_str_weak(set_mode), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x80000000, // 0001 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_persist +********************************************************************/ +be_local_closure(Matter_Session_set_persist, /* name */ + be_nested_proto( + 4, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(_persist), + }), + be_str_weak(set_persist), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x60080017, // 0000 GETGBL R2 G23 + 0x5C0C0200, // 0001 MOVE R3 R1 + 0x7C080200, // 0002 CALL R2 1 + 0x90020002, // 0003 SETMBR R0 K0 R2 + 0x80000000, // 0004 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_ca_pub +********************************************************************/ +be_local_closure(Matter_Session_get_ca_pub, /* name */ + be_nested_proto( + 5, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(root_ca_certificate), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(TLV), + /* K3 */ be_nested_str_weak(parse), + /* K4 */ be_nested_str_weak(findsubval), + }), + be_str_weak(get_ca_pub), + &be_const_str_solidified, + ( &(const binstruction[12]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x78060008, // 0001 JMPF R1 #000B + 0xB8060200, // 0002 GETNGBL R1 K1 + 0x88040302, // 0003 GETMBR R1 R1 K2 + 0x8C040303, // 0004 GETMET R1 R1 K3 + 0x880C0100, // 0005 GETMBR R3 R0 K0 + 0x7C040400, // 0006 CALL R1 2 + 0x8C080304, // 0007 GETMET R2 R1 K4 + 0x54120008, // 0008 LDINT R4 9 + 0x7C080400, // 0009 CALL R2 2 + 0x80040400, // 000A RET 1 R2 + 0x80000000, // 000B RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_icac +********************************************************************/ +be_local_closure(Matter_Session_get_icac, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(icac), + }), + be_str_weak(get_icac), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: close +********************************************************************/ +be_local_closure(Matter_Session_close, /* name */ + be_nested_proto( + 9, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[21]) { /* constants */ + /* K0 */ be_nested_str_weak(_persist), + /* K1 */ be_nested_str_weak(local_session_id), + /* K2 */ be_nested_str_weak(_future_local_session_id), + /* K3 */ be_nested_str_weak(initiator_session_id), + /* K4 */ be_nested_str_weak(_future_initiator_session_id), + /* K5 */ be_nested_str_weak(source_node_id), + /* K6 */ be_nested_str_weak(counter_rcv), + /* K7 */ be_nested_str_weak(reset), + /* K8 */ be_nested_str_weak(counter_snd), + /* K9 */ be_nested_str_weak(i2rkey), + /* K10 */ be_nested_str_weak(r2ikey), + /* K11 */ be_nested_str_weak(attestation_challenge), + /* K12 */ be_nested_str_weak(introspect), + /* K13 */ be_nested_str_weak(members), + /* K14 */ be_nested_str_weak(get), + /* K15 */ be_nested_str_weak(function), + /* K16 */ be_nested_str_weak(instance), + /* K17 */ be_const_int(0), + /* K18 */ be_nested_str_weak(_), + /* K19 */ be_const_int(1), + /* K20 */ be_nested_str_weak(stop_iteration), + }), + be_str_weak(close), + &be_const_str_solidified, + ( &(const binstruction[56]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x88080102, // 0001 GETMBR R2 R0 K2 + 0x90020202, // 0002 SETMBR R0 K1 R2 + 0x88080104, // 0003 GETMBR R2 R0 K4 + 0x90020602, // 0004 SETMBR R0 K3 R2 + 0x4C080000, // 0005 LDNIL R2 + 0x90020A02, // 0006 SETMBR R0 K5 R2 + 0x88080106, // 0007 GETMBR R2 R0 K6 + 0x8C080507, // 0008 GETMET R2 R2 K7 + 0x7C080200, // 0009 CALL R2 1 + 0x88080108, // 000A GETMBR R2 R0 K8 + 0x8C080507, // 000B GETMET R2 R2 K7 + 0x7C080200, // 000C CALL R2 1 + 0x4C080000, // 000D LDNIL R2 + 0x90021202, // 000E SETMBR R0 K9 R2 + 0x4C080000, // 000F LDNIL R2 + 0x90021402, // 0010 SETMBR R0 K10 R2 + 0x4C080000, // 0011 LDNIL R2 + 0x90021602, // 0012 SETMBR R0 K11 R2 + 0xA40A1800, // 0013 IMPORT R2 K12 + 0x600C0010, // 0014 GETGBL R3 G16 + 0x8C10050D, // 0015 GETMET R4 R2 K13 + 0x5C180000, // 0016 MOVE R6 R0 + 0x7C100400, // 0017 CALL R4 2 + 0x7C0C0200, // 0018 CALL R3 1 + 0xA8020018, // 0019 EXBLK 0 #0033 + 0x5C100600, // 001A MOVE R4 R3 + 0x7C100000, // 001B CALL R4 0 + 0x8C14050E, // 001C GETMET R5 R2 K14 + 0x5C1C0000, // 001D MOVE R7 R0 + 0x5C200800, // 001E MOVE R8 R4 + 0x7C140600, // 001F CALL R5 3 + 0x60180004, // 0020 GETGBL R6 G4 + 0x5C1C0A00, // 0021 MOVE R7 R5 + 0x7C180200, // 0022 CALL R6 1 + 0x20180D0F, // 0023 NE R6 R6 K15 + 0x781A000C, // 0024 JMPF R6 #0032 + 0x60180004, // 0025 GETGBL R6 G4 + 0x5C1C0A00, // 0026 MOVE R7 R5 + 0x7C180200, // 0027 CALL R6 1 + 0x20180D10, // 0028 NE R6 R6 K16 + 0x781A0007, // 0029 JMPF R6 #0032 + 0x94180911, // 002A GETIDX R6 R4 K17 + 0x1C180D12, // 002B EQ R6 R6 K18 + 0x781A0004, // 002C JMPF R6 #0032 + 0x94180913, // 002D GETIDX R6 R4 K19 + 0x20180D12, // 002E NE R6 R6 K18 + 0x781A0001, // 002F JMPF R6 #0032 + 0x4C180000, // 0030 LDNIL R6 + 0x90000806, // 0031 SETMBR R0 R4 R6 + 0x7001FFE6, // 0032 JMP #001A + 0x580C0014, // 0033 LDCONST R3 K20 + 0xAC0C0200, // 0034 CATCH R3 1 0 + 0xB0080000, // 0035 RAISE 2 R0 R0 + 0x90020001, // 0036 SETMBR R0 K0 R1 + 0x80000000, // 0037 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_Session_init, /* name */ + be_nested_proto( + 6, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[13]) { /* constants */ + /* K0 */ be_nested_str_weak(__store), + /* K1 */ be_nested_str_weak(mode), + /* K2 */ be_const_int(0), + /* K3 */ be_nested_str_weak(local_session_id), + /* K4 */ be_nested_str_weak(initiator_session_id), + /* K5 */ be_nested_str_weak(counter_rcv), + /* K6 */ be_nested_str_weak(matter), + /* K7 */ be_nested_str_weak(Counter), + /* K8 */ be_nested_str_weak(counter_snd), + /* K9 */ be_nested_str_weak(_counter_insecure_rcv), + /* K10 */ be_nested_str_weak(_counter_insecure_snd), + /* K11 */ be_nested_str_weak(breadcrumb), + /* K12 */ be_nested_str_weak(int64), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[24]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x90020302, // 0001 SETMBR R0 K1 K2 + 0x90020602, // 0002 SETMBR R0 K3 R2 + 0x90020803, // 0003 SETMBR R0 K4 R3 + 0xB8120C00, // 0004 GETNGBL R4 K6 + 0x8C100907, // 0005 GETMET R4 R4 K7 + 0x7C100200, // 0006 CALL R4 1 + 0x90020A04, // 0007 SETMBR R0 K5 R4 + 0xB8120C00, // 0008 GETNGBL R4 K6 + 0x8C100907, // 0009 GETMET R4 R4 K7 + 0x7C100200, // 000A CALL R4 1 + 0x90021004, // 000B SETMBR R0 K8 R4 + 0xB8120C00, // 000C GETNGBL R4 K6 + 0x8C100907, // 000D GETMET R4 R4 K7 + 0x7C100200, // 000E CALL R4 1 + 0x90021204, // 000F SETMBR R0 K9 R4 + 0xB8120C00, // 0010 GETNGBL R4 K6 + 0x8C100907, // 0011 GETMET R4 R4 K7 + 0x7C100200, // 0012 CALL R4 1 + 0x90021404, // 0013 SETMBR R0 K10 R4 + 0xB8121800, // 0014 GETNGBL R4 K12 + 0x7C100000, // 0015 CALL R4 0 + 0x90021604, // 0016 SETMBR R0 K11 R4 + 0x80000000, // 0017 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_ca +********************************************************************/ +be_local_closure(Matter_Session_get_ca, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(root_ca_certificate), + }), + be_str_weak(get_ca), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_deviceid +********************************************************************/ +be_local_closure(Matter_Session_get_deviceid, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(deviceid), + }), + be_str_weak(get_deviceid), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_i2r +********************************************************************/ +be_local_closure(Matter_Session_get_i2r, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(i2rkey), + }), + be_str_weak(get_i2r), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_Session +********************************************************************/ +be_local_class(Matter_Session, + 33, + NULL, + be_nested_map(67, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(root_ca_certificate, -1), be_const_var(18) }, + { be_const_key_weak(ipk_epoch_key, -1), be_const_var(21) }, + { be_const_key_weak(get_deviceid, -1), be_const_closure(Matter_Session_get_deviceid_closure) }, + { be_const_key_weak(get_ca, -1), be_const_closure(Matter_Session_get_ca_closure) }, + { be_const_key_weak(resumption_id, 11), be_const_var(22) }, + { be_const_key_weak(expiration, -1), be_const_var(32) }, + { be_const_key_weak(get_pk, 41), be_const_closure(Matter_Session_get_pk_closure) }, + { be_const_key_weak(_Msg2, -1), be_const_var(30) }, + { be_const_key_weak(init, -1), be_const_closure(Matter_Session_init_closure) }, + { be_const_key_weak(get_ac, 29), be_const_closure(Matter_Session_get_ac_closure) }, + { be_const_key_weak(get_ipk_group_key, -1), be_const_closure(Matter_Session_get_ipk_group_key_closure) }, + { be_const_key_weak(session_timestamp, -1), be_const_var(4) }, + { be_const_key_weak(close, -1), be_const_closure(Matter_Session_close_closure) }, + { be_const_key_weak(save, 47), be_const_closure(Matter_Session_save_closure) }, + { be_const_key_weak(_persist, 61), be_const_var(31) }, + { be_const_key_weak(no_private_key, -1), be_const_var(17) }, + { be_const_key_weak(__CASE, -1), be_const_int(2) }, + { be_const_key_weak(_future_initiator_session_id, -1), be_const_var(6) }, + { be_const_key_weak(set_expire_time, -1), be_const_closure(Matter_Session_set_expire_time_closure) }, + { be_const_key_weak(set_ipk_epoch_key, 64), be_const_closure(Matter_Session_set_ipk_epoch_key_closure) }, + { be_const_key_weak(tojson, -1), be_const_closure(Matter_Session_tojson_closure) }, + { be_const_key_weak(mode, -1), be_const_var(1) }, + { be_const_key_weak(_Msg1, 28), be_const_var(29) }, + { be_const_key_weak(__store, 15), be_const_var(0) }, + { be_const_key_weak(fabric, -1), be_const_var(24) }, + { be_const_key_weak(get_noc, 54), be_const_closure(Matter_Session_get_noc_closure) }, + { be_const_key_weak(get_icac, -1), be_const_closure(Matter_Session_get_icac_closure) }, + { be_const_key_weak(has_expired, 12), be_const_closure(Matter_Session_has_expired_closure) }, + { be_const_key_weak(get_ca_pub, -1), be_const_closure(Matter_Session_get_ca_pub_closure) }, + { be_const_key_weak(__PASE, -1), be_const_int(1) }, + { be_const_key_weak(initiator_session_id, -1), be_const_var(3) }, + { be_const_key_weak(breadcrumb, -1), be_const_var(16) }, + { be_const_key_weak(_counter_insecure_snd, -1), be_const_var(11) }, + { be_const_key_weak(peer_node_id, -1), be_const_var(15) }, + { be_const_key_weak(set_persist, -1), be_const_closure(Matter_Session_set_persist_closure) }, + { be_const_key_weak(source_node_id, -1), be_const_var(5) }, + { be_const_key_weak(gen_CSR, -1), be_const_closure(Matter_Session_gen_CSR_closure) }, + { be_const_key_weak(get_r2i, -1), be_const_closure(Matter_Session_get_r2i_closure) }, + { be_const_key_weak(noc, -1), be_const_var(19) }, + { be_const_key_weak(counter_snd, 53), be_const_var(9) }, + { be_const_key_weak(_counter_insecure_rcv, -1), be_const_var(10) }, + { be_const_key_weak(set_mode, 60), be_const_closure(Matter_Session_set_mode_closure) }, + { be_const_key_weak(set_noc, -1), be_const_closure(Matter_Session_set_noc_closure) }, + { be_const_key_weak(set_ca, 57), be_const_closure(Matter_Session_set_ca_closure) }, + { be_const_key_weak(__GROUP_KEY, 3), be_nested_str_weak(GroupKey_X20v1_X2E0) }, + { be_const_key_weak(icac, 56), be_const_var(20) }, + { be_const_key_weak(get_ipk_epoch_key, -1), be_const_closure(Matter_Session_get_ipk_epoch_key_closure) }, + { be_const_key_weak(local_session_id, -1), be_const_var(2) }, + { be_const_key_weak(counter_rcv, -1), be_const_var(8) }, + { be_const_key_weak(r2ikey, -1), be_const_var(13) }, + { be_const_key_weak(shared_secret, -1), be_const_var(23) }, + { be_const_key_weak(deviceid, 49), be_const_var(26) }, + { be_const_key_weak(get_fabric_compressed, -1), be_const_closure(Matter_Session_get_fabric_compressed_closure) }, + { be_const_key_weak(set_keys, -1), be_const_closure(Matter_Session_set_keys_closure) }, + { be_const_key_weak(admin_subject, -1), be_const_var(27) }, + { be_const_key_weak(get_fabric, 34), be_const_closure(Matter_Session_get_fabric_closure) }, + { be_const_key_weak(attestation_challenge, 0), be_const_var(14) }, + { be_const_key_weak(set_fabric_device, -1), be_const_closure(Matter_Session_set_fabric_device_closure) }, + { be_const_key_weak(fabric_compressed, 26), be_const_var(25) }, + { be_const_key_weak(get_mode, 21), be_const_closure(Matter_Session_get_mode_closure) }, + { be_const_key_weak(set_no_expiration, -1), be_const_closure(Matter_Session_set_no_expiration_closure) }, + { be_const_key_weak(fromjson, -1), be_const_static_closure(Matter_Session_fromjson_closure) }, + { be_const_key_weak(admin_vendor, -1), be_const_var(28) }, + { be_const_key_weak(_future_local_session_id, 8), be_const_var(7) }, + { be_const_key_weak(set_expire_in_seconds, -1), be_const_closure(Matter_Session_set_expire_in_seconds_closure) }, + { be_const_key_weak(i2rkey, 2), be_const_var(12) }, + { be_const_key_weak(get_i2r, -1), be_const_closure(Matter_Session_get_i2r_closure) }, + })), + be_str_weak(Matter_Session) +); +/*******************************************************************/ + +void be_load_Matter_Session_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Session); + be_setglobal(vm, "Matter_Session"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_Session_Store; + +/******************************************************************** +** Solidified function: every_second +********************************************************************/ +be_local_closure(Matter_Session_Store_every_second, /* name */ + be_nested_proto( + 3, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(remove_expired), + }), + be_str_weak(every_second), + &be_const_str_solidified, + ( &(const binstruction[ 3]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x7C040200, // 0001 CALL R1 1 + 0x80000000, // 0002 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: remove_redundant_session +********************************************************************/ +be_local_closure(Matter_Session_Store_remove_redundant_session, /* name */ + be_nested_proto( + 8, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_const_int(0), + /* K1 */ be_nested_str_weak(sessions), + /* K2 */ be_nested_str_weak(fabric), + /* K3 */ be_nested_str_weak(deviceid), + /* K4 */ be_nested_str_weak(remove), + /* K5 */ be_const_int(1), + }), + be_str_weak(remove_redundant_session), + &be_const_str_solidified, + ( &(const binstruction[25]) { /* code */ + 0x58080000, // 0000 LDCONST R2 K0 + 0x880C0101, // 0001 GETMBR R3 R0 K1 + 0x6010000C, // 0002 GETGBL R4 G12 + 0x88140101, // 0003 GETMBR R5 R0 K1 + 0x7C100200, // 0004 CALL R4 1 + 0x14100404, // 0005 LT R4 R2 R4 + 0x78120010, // 0006 JMPF R4 #0018 + 0x94100602, // 0007 GETIDX R4 R3 R2 + 0x20140801, // 0008 NE R5 R4 R1 + 0x7816000B, // 0009 JMPF R5 #0016 + 0x88140902, // 000A GETMBR R5 R4 K2 + 0x88180302, // 000B GETMBR R6 R1 K2 + 0x1C140A06, // 000C EQ R5 R5 R6 + 0x78160007, // 000D JMPF R5 #0016 + 0x88140903, // 000E GETMBR R5 R4 K3 + 0x88180303, // 000F GETMBR R6 R1 K3 + 0x1C140A06, // 0010 EQ R5 R5 R6 + 0x78160003, // 0011 JMPF R5 #0016 + 0x8C140704, // 0012 GETMET R5 R3 K4 + 0x5C1C0400, // 0013 MOVE R7 R2 + 0x7C140400, // 0014 CALL R5 2 + 0x70020000, // 0015 JMP #0017 + 0x00080505, // 0016 ADD R2 R2 K5 + 0x7001FFE9, // 0017 JMP #0002 + 0x80000000, // 0018 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_session_by_source_node_id +********************************************************************/ +be_local_closure(Matter_Session_Store_get_session_by_source_node_id, /* name */ + be_nested_proto( + 6, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(sessions), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str_weak(source_node_id), + /* K3 */ be_const_int(1), + }), + be_str_weak(get_session_by_source_node_id), + &be_const_str_solidified, + ( &(const binstruction[21]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0001, // 0002 JMPF R2 #0005 + 0x4C080000, // 0003 LDNIL R2 + 0x80040400, // 0004 RET 1 R2 + 0x6008000C, // 0005 GETGBL R2 G12 + 0x880C0100, // 0006 GETMBR R3 R0 K0 + 0x7C080200, // 0007 CALL R2 1 + 0x580C0001, // 0008 LDCONST R3 K1 + 0x88100100, // 0009 GETMBR R4 R0 K0 + 0x14140602, // 000A LT R5 R3 R2 + 0x78160007, // 000B JMPF R5 #0014 + 0x94140803, // 000C GETIDX R5 R4 R3 + 0x88140B02, // 000D GETMBR R5 R5 K2 + 0x1C140A01, // 000E EQ R5 R5 R1 + 0x78160001, // 000F JMPF R5 #0012 + 0x94140803, // 0010 GETIDX R5 R4 R3 + 0x80040A00, // 0011 RET 1 R5 + 0x000C0703, // 0012 ADD R3 R3 K3 + 0x7001FFF5, // 0013 JMP #000A + 0x80000000, // 0014 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: remove_expired +********************************************************************/ +be_local_closure(Matter_Session_Store_remove_expired, /* name */ + be_nested_proto( + 7, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 7]) { /* constants */ + /* K0 */ be_const_int(0), + /* K1 */ be_nested_str_weak(sessions), + /* K2 */ be_nested_str_weak(has_expired), + /* K3 */ be_nested_str_weak(_persist), + /* K4 */ be_nested_str_weak(remove), + /* K5 */ be_const_int(1), + /* K6 */ be_nested_str_weak(save), + }), + be_str_weak(remove_expired), + &be_const_str_solidified, + ( &(const binstruction[26]) { /* code */ + 0x50040000, // 0000 LDBOOL R1 0 0 + 0x58080000, // 0001 LDCONST R2 K0 + 0x880C0101, // 0002 GETMBR R3 R0 K1 + 0x6010000C, // 0003 GETGBL R4 G12 + 0x88140101, // 0004 GETMBR R5 R0 K1 + 0x7C100200, // 0005 CALL R4 1 + 0x14100404, // 0006 LT R4 R2 R4 + 0x7812000D, // 0007 JMPF R4 #0016 + 0x94100602, // 0008 GETIDX R4 R3 R2 + 0x8C100902, // 0009 GETMET R4 R4 K2 + 0x7C100200, // 000A CALL R4 1 + 0x78120007, // 000B JMPF R4 #0014 + 0x94100602, // 000C GETIDX R4 R3 R2 + 0x88100903, // 000D GETMBR R4 R4 K3 + 0x78120000, // 000E JMPF R4 #0010 + 0x50040200, // 000F LDBOOL R1 1 0 + 0x8C100704, // 0010 GETMET R4 R3 K4 + 0x5C180400, // 0011 MOVE R6 R2 + 0x7C100400, // 0012 CALL R4 2 + 0x70020000, // 0013 JMP #0015 + 0x00080505, // 0014 ADD R2 R2 K5 + 0x7001FFEC, // 0015 JMP #0003 + 0x78060001, // 0016 JMPF R1 #0019 + 0x8C100106, // 0017 GETMET R4 R0 K6 + 0x7C100200, // 0018 CALL R4 1 + 0x80000000, // 0019 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: load +********************************************************************/ +be_local_closure(Matter_Session_Store_load, /* name */ + be_nested_proto( + 13, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[22]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(sessions), + /* K2 */ be_nested_str_weak(FILENAME), + /* K3 */ be_nested_str_weak(read), + /* K4 */ be_nested_str_weak(close), + /* K5 */ be_nested_str_weak(json), + /* K6 */ be_nested_str_weak(load), + /* K7 */ be_nested_str_weak(tasmota), + /* K8 */ be_nested_str_weak(gc), + /* K9 */ be_nested_str_weak(matter), + /* K10 */ be_nested_str_weak(Session), + /* K11 */ be_nested_str_weak(fromjson), + /* K12 */ be_nested_str_weak(add_session), + /* K13 */ be_nested_str_weak(stop_iteration), + /* K14 */ be_nested_str_weak(log), + /* K15 */ be_nested_str_weak(format), + /* K16 */ be_nested_str_weak(MTR_X3A_X20Loaded_X20_X25i_X20session_X28s_X29), + /* K17 */ be_const_int(2), + /* K18 */ be_nested_str_weak(io_error), + /* K19 */ be_nested_str_weak(MTR_X3A_X20Session_Store_X3A_X3Aload_X20Exception_X3A), + /* K20 */ be_nested_str_weak(_X7C), + /* K21 */ be_nested_str_weak(remove_expired), + }), + be_str_weak(load), + &be_const_str_solidified, + ( &(const binstruction[76]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0xA8020033, // 0001 EXBLK 0 #0036 + 0x60080012, // 0002 GETGBL R2 G18 + 0x7C080000, // 0003 CALL R2 0 + 0x90020202, // 0004 SETMBR R0 K1 R2 + 0x60080011, // 0005 GETGBL R2 G17 + 0x880C0102, // 0006 GETMBR R3 R0 K2 + 0x7C080200, // 0007 CALL R2 1 + 0x8C0C0503, // 0008 GETMET R3 R2 K3 + 0x7C0C0200, // 0009 CALL R3 1 + 0x8C100504, // 000A GETMET R4 R2 K4 + 0x7C100200, // 000B CALL R4 1 + 0xA4120A00, // 000C IMPORT R4 K5 + 0x8C140906, // 000D GETMET R5 R4 K6 + 0x5C1C0600, // 000E MOVE R7 R3 + 0x7C140400, // 000F CALL R5 2 + 0x4C0C0000, // 0010 LDNIL R3 + 0xB81A0E00, // 0011 GETNGBL R6 K7 + 0x8C180D08, // 0012 GETMET R6 R6 K8 + 0x7C180200, // 0013 CALL R6 1 + 0x60180010, // 0014 GETGBL R6 G16 + 0x5C1C0A00, // 0015 MOVE R7 R5 + 0x7C180200, // 0016 CALL R6 1 + 0xA802000E, // 0017 EXBLK 0 #0027 + 0x5C1C0C00, // 0018 MOVE R7 R6 + 0x7C1C0000, // 0019 CALL R7 0 + 0xB8221200, // 001A GETNGBL R8 K9 + 0x8820110A, // 001B GETMBR R8 R8 K10 + 0x8C20110B, // 001C GETMET R8 R8 K11 + 0x5C280000, // 001D MOVE R10 R0 + 0x5C2C0E00, // 001E MOVE R11 R7 + 0x7C200600, // 001F CALL R8 3 + 0x4C240000, // 0020 LDNIL R9 + 0x20241009, // 0021 NE R9 R8 R9 + 0x78260002, // 0022 JMPF R9 #0026 + 0x8C24010C, // 0023 GETMET R9 R0 K12 + 0x5C2C1000, // 0024 MOVE R11 R8 + 0x7C240400, // 0025 CALL R9 2 + 0x7001FFF0, // 0026 JMP #0018 + 0x5818000D, // 0027 LDCONST R6 K13 + 0xAC180200, // 0028 CATCH R6 1 0 + 0xB0080000, // 0029 RAISE 2 R0 R0 + 0xB81A0E00, // 002A GETNGBL R6 K7 + 0x8C180D0E, // 002B GETMET R6 R6 K14 + 0x8C20030F, // 002C GETMET R8 R1 K15 + 0x58280010, // 002D LDCONST R10 K16 + 0x602C000C, // 002E GETGBL R11 G12 + 0x88300101, // 002F GETMBR R12 R0 K1 + 0x7C2C0200, // 0030 CALL R11 1 + 0x7C200600, // 0031 CALL R8 3 + 0x58240011, // 0032 LDCONST R9 K17 + 0x7C180600, // 0033 CALL R6 3 + 0xA8040001, // 0034 EXBLK 1 1 + 0x70020012, // 0035 JMP #0049 + 0xAC080002, // 0036 CATCH R2 0 2 + 0x7002000F, // 0037 JMP #0048 + 0x20100512, // 0038 NE R4 R2 K18 + 0x7812000C, // 0039 JMPF R4 #0047 + 0xB8120E00, // 003A GETNGBL R4 K7 + 0x8C10090E, // 003B GETMET R4 R4 K14 + 0x60180008, // 003C GETGBL R6 G8 + 0x5C1C0400, // 003D MOVE R7 R2 + 0x7C180200, // 003E CALL R6 1 + 0x001A2606, // 003F ADD R6 K19 R6 + 0x00180D14, // 0040 ADD R6 R6 K20 + 0x601C0008, // 0041 GETGBL R7 G8 + 0x5C200600, // 0042 MOVE R8 R3 + 0x7C1C0200, // 0043 CALL R7 1 + 0x00180C07, // 0044 ADD R6 R6 R7 + 0x581C0011, // 0045 LDCONST R7 K17 + 0x7C100600, // 0046 CALL R4 3 + 0x70020000, // 0047 JMP #0049 + 0xB0080000, // 0048 RAISE 2 R0 R0 + 0x8C080115, // 0049 GETMET R2 R0 K21 + 0x7C080200, // 004A CALL R2 1 + 0x80000000, // 004B RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_Session_Store_init, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(sessions), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[ 4]) { /* code */ + 0x60040012, // 0000 GETGBL R1 G18 + 0x7C040000, // 0001 CALL R1 0 + 0x90020001, // 0002 SETMBR R0 K0 R1 + 0x80000000, // 0003 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: remove_session +********************************************************************/ +be_local_closure(Matter_Session_Store_remove_session, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_const_int(0), + /* K1 */ be_nested_str_weak(sessions), + /* K2 */ be_nested_str_weak(remove), + /* K3 */ be_const_int(1), + }), + be_str_weak(remove_session), + &be_const_str_solidified, + ( &(const binstruction[17]) { /* code */ + 0x58080000, // 0000 LDCONST R2 K0 + 0x880C0101, // 0001 GETMBR R3 R0 K1 + 0x6010000C, // 0002 GETGBL R4 G12 + 0x88140101, // 0003 GETMBR R5 R0 K1 + 0x7C100200, // 0004 CALL R4 1 + 0x14100404, // 0005 LT R4 R2 R4 + 0x78120008, // 0006 JMPF R4 #0010 + 0x94100602, // 0007 GETIDX R4 R3 R2 + 0x1C100801, // 0008 EQ R4 R4 R1 + 0x78120003, // 0009 JMPF R4 #000E + 0x8C100702, // 000A GETMET R4 R3 K2 + 0x5C180400, // 000B MOVE R6 R2 + 0x7C100400, // 000C CALL R4 2 + 0x70020000, // 000D JMP #000F + 0x00080503, // 000E ADD R2 R2 K3 + 0x7001FFF1, // 000F JMP #0002 + 0x80000000, // 0010 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: add_session +********************************************************************/ +be_local_closure(Matter_Session_Store_add_session, /* name */ + be_nested_proto( + 6, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(set_expire_in_seconds), + /* K1 */ be_nested_str_weak(sessions), + /* K2 */ be_nested_str_weak(push), + }), + be_str_weak(add_session), + &be_const_str_solidified, + ( &(const binstruction[11]) { /* code */ + 0x4C0C0000, // 0000 LDNIL R3 + 0x200C0403, // 0001 NE R3 R2 R3 + 0x780E0002, // 0002 JMPF R3 #0006 + 0x8C0C0300, // 0003 GETMET R3 R1 K0 + 0x5C140400, // 0004 MOVE R5 R2 + 0x7C0C0400, // 0005 CALL R3 2 + 0x880C0101, // 0006 GETMBR R3 R0 K1 + 0x8C0C0702, // 0007 GETMET R3 R3 K2 + 0x5C140200, // 0008 MOVE R5 R1 + 0x7C0C0400, // 0009 CALL R3 2 + 0x80000000, // 000A RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_session_by_local_session_id +********************************************************************/ +be_local_closure(Matter_Session_Store_get_session_by_local_session_id, /* name */ + be_nested_proto( + 6, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(sessions), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str_weak(local_session_id), + /* K3 */ be_const_int(1), + }), + be_str_weak(get_session_by_local_session_id), + &be_const_str_solidified, + ( &(const binstruction[21]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0001, // 0002 JMPF R2 #0005 + 0x4C080000, // 0003 LDNIL R2 + 0x80040400, // 0004 RET 1 R2 + 0x6008000C, // 0005 GETGBL R2 G12 + 0x880C0100, // 0006 GETMBR R3 R0 K0 + 0x7C080200, // 0007 CALL R2 1 + 0x580C0001, // 0008 LDCONST R3 K1 + 0x88100100, // 0009 GETMBR R4 R0 K0 + 0x14140602, // 000A LT R5 R3 R2 + 0x78160007, // 000B JMPF R5 #0014 + 0x94140803, // 000C GETIDX R5 R4 R3 + 0x88140B02, // 000D GETMBR R5 R5 K2 + 0x1C140A01, // 000E EQ R5 R5 R1 + 0x78160001, // 000F JMPF R5 #0012 + 0x94140803, // 0010 GETIDX R5 R4 R3 + 0x80040A00, // 0011 RET 1 R5 + 0x000C0703, // 0012 ADD R3 R3 K3 + 0x7001FFF5, // 0013 JMP #000A + 0x80000000, // 0014 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: find_session_source_id_unsecure +********************************************************************/ +be_local_closure(Matter_Session_Store_find_session_source_id_unsecure, /* name */ + be_nested_proto( + 9, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(get_session_by_source_node_id), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(Session), + /* K3 */ be_const_int(0), + /* K4 */ be_nested_str_weak(source_node_id), + /* K5 */ be_nested_str_weak(sessions), + /* K6 */ be_nested_str_weak(push), + /* K7 */ be_nested_str_weak(set_expire_in_seconds), + }), + be_str_weak(find_session_source_id_unsecure), + &be_const_str_solidified, + ( &(const binstruction[22]) { /* code */ + 0x8C0C0100, // 0000 GETMET R3 R0 K0 + 0x5C140200, // 0001 MOVE R5 R1 + 0x7C0C0400, // 0002 CALL R3 2 + 0x4C100000, // 0003 LDNIL R4 + 0x1C100604, // 0004 EQ R4 R3 R4 + 0x7812000B, // 0005 JMPF R4 #0012 + 0xB8120200, // 0006 GETNGBL R4 K1 + 0x8C100902, // 0007 GETMET R4 R4 K2 + 0x5C180000, // 0008 MOVE R6 R0 + 0x581C0003, // 0009 LDCONST R7 K3 + 0x58200003, // 000A LDCONST R8 K3 + 0x7C100800, // 000B CALL R4 4 + 0x5C0C0800, // 000C MOVE R3 R4 + 0x900E0801, // 000D SETMBR R3 K4 R1 + 0x88100105, // 000E GETMBR R4 R0 K5 + 0x8C100906, // 000F GETMET R4 R4 K6 + 0x5C180600, // 0010 MOVE R6 R3 + 0x7C100400, // 0011 CALL R4 2 + 0x8C100707, // 0012 GETMET R4 R3 K7 + 0x5C180400, // 0013 MOVE R6 R2 + 0x7C100400, // 0014 CALL R4 2 + 0x80040600, // 0015 RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: save +********************************************************************/ +be_local_closure(Matter_Session_Store_save, /* name */ + be_nested_proto( + 12, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[23]) { /* constants */ + /* K0 */ be_nested_str_weak(json), + /* K1 */ be_nested_str_weak(remove_expired), + /* K2 */ be_nested_str_weak(sessions), + /* K3 */ be_nested_str_weak(_persist), + /* K4 */ be_nested_str_weak(push), + /* K5 */ be_nested_str_weak(tojson), + /* K6 */ be_nested_str_weak(stop_iteration), + /* K7 */ be_nested_str_weak(_X5B), + /* K8 */ be_nested_str_weak(concat), + /* K9 */ be_nested_str_weak(_X2C), + /* K10 */ be_nested_str_weak(_X5D), + /* K11 */ be_nested_str_weak(string), + /* K12 */ be_nested_str_weak(FILENAME), + /* K13 */ be_nested_str_weak(w), + /* K14 */ be_nested_str_weak(write), + /* K15 */ be_nested_str_weak(close), + /* K16 */ be_nested_str_weak(tasmota), + /* K17 */ be_nested_str_weak(log), + /* K18 */ be_nested_str_weak(format), + /* K19 */ be_nested_str_weak(MTR_X3A_X20Saved_X20_X25i_X20session_X28s_X29), + /* K20 */ be_const_int(2), + /* K21 */ be_nested_str_weak(MTR_X3A_X20Session_Store_X3A_X3Asave_X20Exception_X3A), + /* K22 */ be_nested_str_weak(_X7C), + }), + be_str_weak(save), + &be_const_str_solidified, + ( &(const binstruction[72]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x8C080101, // 0001 GETMET R2 R0 K1 + 0x7C080200, // 0002 CALL R2 1 + 0x60080012, // 0003 GETGBL R2 G18 + 0x7C080000, // 0004 CALL R2 0 + 0x600C0010, // 0005 GETGBL R3 G16 + 0x88100102, // 0006 GETMBR R4 R0 K2 + 0x7C0C0200, // 0007 CALL R3 1 + 0xA8020008, // 0008 EXBLK 0 #0012 + 0x5C100600, // 0009 MOVE R4 R3 + 0x7C100000, // 000A CALL R4 0 + 0x88140903, // 000B GETMBR R5 R4 K3 + 0x78160003, // 000C JMPF R5 #0011 + 0x8C140504, // 000D GETMET R5 R2 K4 + 0x8C1C0905, // 000E GETMET R7 R4 K5 + 0x7C1C0200, // 000F CALL R7 1 + 0x7C140400, // 0010 CALL R5 2 + 0x7001FFF6, // 0011 JMP #0009 + 0x580C0006, // 0012 LDCONST R3 K6 + 0xAC0C0200, // 0013 CATCH R3 1 0 + 0xB0080000, // 0014 RAISE 2 R0 R0 + 0x600C000C, // 0015 GETGBL R3 G12 + 0x5C100400, // 0016 MOVE R4 R2 + 0x7C0C0200, // 0017 CALL R3 1 + 0x8C100508, // 0018 GETMET R4 R2 K8 + 0x58180009, // 0019 LDCONST R6 K9 + 0x7C100400, // 001A CALL R4 2 + 0x00120E04, // 001B ADD R4 K7 R4 + 0x0010090A, // 001C ADD R4 R4 K10 + 0x5C080800, // 001D MOVE R2 R4 + 0xA8020015, // 001E EXBLK 0 #0035 + 0xA4121600, // 001F IMPORT R4 K11 + 0x60140011, // 0020 GETGBL R5 G17 + 0x8818010C, // 0021 GETMBR R6 R0 K12 + 0x581C000D, // 0022 LDCONST R7 K13 + 0x7C140400, // 0023 CALL R5 2 + 0x8C180B0E, // 0024 GETMET R6 R5 K14 + 0x5C200400, // 0025 MOVE R8 R2 + 0x7C180400, // 0026 CALL R6 2 + 0x8C180B0F, // 0027 GETMET R6 R5 K15 + 0x7C180200, // 0028 CALL R6 1 + 0xB81A2000, // 0029 GETNGBL R6 K16 + 0x8C180D11, // 002A GETMET R6 R6 K17 + 0x8C200912, // 002B GETMET R8 R4 K18 + 0x58280013, // 002C LDCONST R10 K19 + 0x5C2C0600, // 002D MOVE R11 R3 + 0x7C200600, // 002E CALL R8 3 + 0x58240014, // 002F LDCONST R9 K20 + 0x7C180600, // 0030 CALL R6 3 + 0xA8040001, // 0031 EXBLK 1 1 + 0x80040400, // 0032 RET 1 R2 + 0xA8040001, // 0033 EXBLK 1 1 + 0x70020011, // 0034 JMP #0047 + 0xAC100002, // 0035 CATCH R4 0 2 + 0x7002000E, // 0036 JMP #0046 + 0xB81A2000, // 0037 GETNGBL R6 K16 + 0x8C180D11, // 0038 GETMET R6 R6 K17 + 0x60200008, // 0039 GETGBL R8 G8 + 0x5C240800, // 003A MOVE R9 R4 + 0x7C200200, // 003B CALL R8 1 + 0x00222A08, // 003C ADD R8 K21 R8 + 0x00201116, // 003D ADD R8 R8 K22 + 0x60240008, // 003E GETGBL R9 G8 + 0x5C280A00, // 003F MOVE R10 R5 + 0x7C240200, // 0040 CALL R9 1 + 0x00201009, // 0041 ADD R8 R8 R9 + 0x58240014, // 0042 LDCONST R9 K20 + 0x7C180600, // 0043 CALL R6 3 + 0x80040400, // 0044 RET 1 R2 + 0x70020000, // 0045 JMP #0047 + 0xB0080000, // 0046 RAISE 2 R0 R0 + 0x80000000, // 0047 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: gen_local_session_id +********************************************************************/ +be_local_closure(Matter_Session_Store_gen_local_session_id, /* name */ + be_nested_proto( + 6, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(crypto), + /* K1 */ be_nested_str_weak(random), + /* K2 */ be_const_int(2), + /* K3 */ be_nested_str_weak(get), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str_weak(get_session_by_local_session_id), + }), + be_str_weak(gen_local_session_id), + &be_const_str_solidified, + ( &(const binstruction[19]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x50080200, // 0001 LDBOOL R2 1 0 + 0x780A000E, // 0002 JMPF R2 #0012 + 0x8C080301, // 0003 GETMET R2 R1 K1 + 0x58100002, // 0004 LDCONST R4 K2 + 0x7C080400, // 0005 CALL R2 2 + 0x8C080503, // 0006 GETMET R2 R2 K3 + 0x58100004, // 0007 LDCONST R4 K4 + 0x58140002, // 0008 LDCONST R5 K2 + 0x7C080600, // 0009 CALL R2 3 + 0x8C0C0105, // 000A GETMET R3 R0 K5 + 0x5C140400, // 000B MOVE R5 R2 + 0x7C0C0400, // 000C CALL R3 2 + 0x4C100000, // 000D LDNIL R4 + 0x1C0C0604, // 000E EQ R3 R3 R4 + 0x780E0000, // 000F JMPF R3 #0011 + 0x80040400, // 0010 RET 1 R2 + 0x7001FFEE, // 0011 JMP #0001 + 0x80000000, // 0012 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: create_session +********************************************************************/ +be_local_closure(Matter_Session_Store_create_session, /* name */ + be_nested_proto( + 9, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(get_session_by_local_session_id), + /* K1 */ be_nested_str_weak(remove_session), + /* K2 */ be_nested_str_weak(matter), + /* K3 */ be_nested_str_weak(Session), + /* K4 */ be_nested_str_weak(sessions), + /* K5 */ be_nested_str_weak(push), + }), + be_str_weak(create_session), + &be_const_str_solidified, + ( &(const binstruction[21]) { /* code */ + 0x8C0C0100, // 0000 GETMET R3 R0 K0 + 0x5C140200, // 0001 MOVE R5 R1 + 0x7C0C0400, // 0002 CALL R3 2 + 0x4C100000, // 0003 LDNIL R4 + 0x20100604, // 0004 NE R4 R3 R4 + 0x78120002, // 0005 JMPF R4 #0009 + 0x8C100101, // 0006 GETMET R4 R0 K1 + 0x5C180600, // 0007 MOVE R6 R3 + 0x7C100400, // 0008 CALL R4 2 + 0xB8120400, // 0009 GETNGBL R4 K2 + 0x8C100903, // 000A GETMET R4 R4 K3 + 0x5C180000, // 000B MOVE R6 R0 + 0x5C1C0200, // 000C MOVE R7 R1 + 0x5C200400, // 000D MOVE R8 R2 + 0x7C100800, // 000E CALL R4 4 + 0x5C0C0800, // 000F MOVE R3 R4 + 0x88100104, // 0010 GETMBR R4 R0 K4 + 0x8C100905, // 0011 GETMET R4 R4 K5 + 0x5C180600, // 0012 MOVE R6 R3 + 0x7C100400, // 0013 CALL R4 2 + 0x80040600, // 0014 RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_Session_Store +********************************************************************/ +be_local_class(Matter_Session_Store, + 1, + NULL, + be_nested_map(15, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(every_second, 14), be_const_closure(Matter_Session_Store_every_second_closure) }, + { be_const_key_weak(remove_redundant_session, 9), be_const_closure(Matter_Session_Store_remove_redundant_session_closure) }, + { be_const_key_weak(get_session_by_source_node_id, 5), be_const_closure(Matter_Session_Store_get_session_by_source_node_id_closure) }, + { be_const_key_weak(remove_expired, -1), be_const_closure(Matter_Session_Store_remove_expired_closure) }, + { be_const_key_weak(load, -1), be_const_closure(Matter_Session_Store_load_closure) }, + { be_const_key_weak(FILENAME, 11), be_nested_str_weak(_matter_sessions_X2Ejson) }, + { be_const_key_weak(remove_session, -1), be_const_closure(Matter_Session_Store_remove_session_closure) }, + { be_const_key_weak(add_session, -1), be_const_closure(Matter_Session_Store_add_session_closure) }, + { be_const_key_weak(get_session_by_local_session_id, -1), be_const_closure(Matter_Session_Store_get_session_by_local_session_id_closure) }, + { be_const_key_weak(find_session_source_id_unsecure, -1), be_const_closure(Matter_Session_Store_find_session_source_id_unsecure_closure) }, + { be_const_key_weak(create_session, -1), be_const_closure(Matter_Session_Store_create_session_closure) }, + { be_const_key_weak(gen_local_session_id, -1), be_const_closure(Matter_Session_Store_gen_local_session_id_closure) }, + { be_const_key_weak(save, 10), be_const_closure(Matter_Session_Store_save_closure) }, + { be_const_key_weak(sessions, -1), be_const_var(0) }, + { be_const_key_weak(init, -1), be_const_closure(Matter_Session_Store_init_closure) }, + })), + be_str_weak(Matter_Session_Store) +); +/*******************************************************************/ + +void be_load_Matter_Session_Store_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Session_Store); + be_setglobal(vm, "Matter_Session_Store"); + be_pop(vm, 1); +} +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_TLV.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_TLV.h new file mode 100644 index 000000000..f27d81def --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_TLV.h @@ -0,0 +1,2909 @@ +/* Solidification of Matter_TLV.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_TLV_item; + +/******************************************************************** +** Solidified function: set_commonprofile +********************************************************************/ +be_local_closure(Matter_TLV_item_set_commonprofile, /* name */ + be_nested_proto( + 6, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(set_fulltag), + }), + be_str_weak(set_commonprofile), + &be_const_str_solidified, + ( &(const binstruction[ 6]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x4C0C0000, // 0001 LDNIL R3 + 0x5411FFFE, // 0002 LDINT R4 -1 + 0x4C140000, // 0003 LDNIL R5 + 0x7C040800, // 0004 CALL R1 4 + 0x80000000, // 0005 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: encode +********************************************************************/ +be_local_closure(Matter_TLV_item_encode, /* name */ + be_nested_proto( + 9, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[39]) { /* constants */ + /* K0 */ be_nested_str_weak(TLV), + /* K1 */ be_nested_str_weak(typ), + /* K2 */ be_nested_str_weak(BFALSE), + /* K3 */ be_nested_str_weak(BTRUE), + /* K4 */ be_nested_str_weak(val), + /* K5 */ be_nested_str_weak(I2), + /* K6 */ be_nested_str_weak(I4), + /* K7 */ be_nested_str_weak(I1), + /* K8 */ be_nested_str_weak(U2), + /* K9 */ be_nested_str_weak(U4), + /* K10 */ be_const_int(0), + /* K11 */ be_nested_str_weak(U1), + /* K12 */ be_nested_str_weak(B1), + /* K13 */ be_nested_str_weak(B8), + /* K14 */ be_nested_str_weak(B2), + /* K15 */ be_nested_str_weak(B4), + /* K16 */ be_nested_str_weak(UTF1), + /* K17 */ be_nested_str_weak(UTF8), + /* K18 */ be_nested_str_weak(UTF2), + /* K19 */ be_nested_str_weak(UTF4), + /* K20 */ be_nested_str_weak(_encode_tag), + /* K21 */ be_nested_str_weak(add), + /* K22 */ be_const_int(1), + /* K23 */ be_const_int(2), + /* K24 */ be_nested_str_weak(I8), + /* K25 */ be_nested_str_weak(U8), + /* K26 */ be_nested_str_weak(int64), + /* K27 */ be_nested_str_weak(tobytes), + /* K28 */ be_nested_str_weak(FLOAT), + /* K29 */ be_nested_str_weak(setfloat), + /* K30 */ be_nested_str_weak(DOUBLE), + /* K31 */ be_nested_str_weak(value_error), + /* K32 */ be_nested_str_weak(Unsupported_X20type_X20TLV_X2EDOUBLE), + /* K33 */ be_nested_str_weak(string_X20too_X20big), + /* K34 */ be_nested_str_weak(fromstring), + /* K35 */ be_nested_str_weak(frostring), + /* K36 */ be_nested_str_weak(bytes_X20too_X20big), + /* K37 */ be_nested_str_weak(NULL), + /* K38 */ be_nested_str_weak(unsupported_X20type_X20), + }), + be_str_weak(encode), + &be_const_str_solidified, + ( &(const binstruction[345]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x4C0C0000, // 0001 LDNIL R3 + 0x1C0C0203, // 0002 EQ R3 R1 R3 + 0x780E0002, // 0003 JMPF R3 #0007 + 0x600C0015, // 0004 GETGBL R3 G21 + 0x7C0C0000, // 0005 CALL R3 0 + 0x5C040600, // 0006 MOVE R1 R3 + 0x880C0101, // 0007 GETMBR R3 R0 K1 + 0x88100502, // 0008 GETMBR R4 R2 K2 + 0x1C0C0604, // 0009 EQ R3 R3 R4 + 0x740E0003, // 000A JMPT R3 #000F + 0x880C0101, // 000B GETMBR R3 R0 K1 + 0x88100503, // 000C GETMBR R4 R2 K3 + 0x1C0C0604, // 000D EQ R3 R3 R4 + 0x780E0008, // 000E JMPF R3 #0018 + 0x600C0017, // 000F GETGBL R3 G23 + 0x88100104, // 0010 GETMBR R4 R0 K4 + 0x7C0C0200, // 0011 CALL R3 1 + 0x780E0001, // 0012 JMPF R3 #0015 + 0x880C0503, // 0013 GETMBR R3 R2 K3 + 0x70020000, // 0014 JMP #0016 + 0x880C0502, // 0015 GETMBR R3 R2 K2 + 0x90020203, // 0016 SETMBR R0 K1 R3 + 0x70020070, // 0017 JMP #0089 + 0x880C0101, // 0018 GETMBR R3 R0 K1 + 0x88100505, // 0019 GETMBR R4 R2 K5 + 0x280C0604, // 001A GE R3 R3 R4 + 0x780E0018, // 001B JMPF R3 #0035 + 0x880C0101, // 001C GETMBR R3 R0 K1 + 0x88100506, // 001D GETMBR R4 R2 K6 + 0x180C0604, // 001E LE R3 R3 R4 + 0x780E0014, // 001F JMPF R3 #0035 + 0x600C0009, // 0020 GETGBL R3 G9 + 0x88100104, // 0021 GETMBR R4 R0 K4 + 0x7C0C0200, // 0022 CALL R3 1 + 0x5412007E, // 0023 LDINT R4 127 + 0x18100604, // 0024 LE R4 R3 R4 + 0x78120005, // 0025 JMPF R4 #002C + 0x5411FF7F, // 0026 LDINT R4 -128 + 0x28100604, // 0027 GE R4 R3 R4 + 0x78120002, // 0028 JMPF R4 #002C + 0x88100507, // 0029 GETMBR R4 R2 K7 + 0x90020204, // 002A SETMBR R0 K1 R4 + 0x70020007, // 002B JMP #0034 + 0x54127FFE, // 002C LDINT R4 32767 + 0x18100604, // 002D LE R4 R3 R4 + 0x78120004, // 002E JMPF R4 #0034 + 0x54117FFF, // 002F LDINT R4 -32768 + 0x28100604, // 0030 GE R4 R3 R4 + 0x78120001, // 0031 JMPF R4 #0034 + 0x88100505, // 0032 GETMBR R4 R2 K5 + 0x90020204, // 0033 SETMBR R0 K1 R4 + 0x70020053, // 0034 JMP #0089 + 0x880C0101, // 0035 GETMBR R3 R0 K1 + 0x88100508, // 0036 GETMBR R4 R2 K8 + 0x280C0604, // 0037 GE R3 R3 R4 + 0x780E0016, // 0038 JMPF R3 #0050 + 0x880C0101, // 0039 GETMBR R3 R0 K1 + 0x88100509, // 003A GETMBR R4 R2 K9 + 0x180C0604, // 003B LE R3 R3 R4 + 0x780E0012, // 003C JMPF R3 #0050 + 0x600C0009, // 003D GETGBL R3 G9 + 0x88100104, // 003E GETMBR R4 R0 K4 + 0x7C0C0200, // 003F CALL R3 1 + 0x541200FE, // 0040 LDINT R4 255 + 0x18100604, // 0041 LE R4 R3 R4 + 0x78120004, // 0042 JMPF R4 #0048 + 0x2810070A, // 0043 GE R4 R3 K10 + 0x78120002, // 0044 JMPF R4 #0048 + 0x8810050B, // 0045 GETMBR R4 R2 K11 + 0x90020204, // 0046 SETMBR R0 K1 R4 + 0x70020006, // 0047 JMP #004F + 0x5412FFFE, // 0048 LDINT R4 65535 + 0x18100604, // 0049 LE R4 R3 R4 + 0x78120003, // 004A JMPF R4 #004F + 0x2810070A, // 004B GE R4 R3 K10 + 0x78120001, // 004C JMPF R4 #004F + 0x88100508, // 004D GETMBR R4 R2 K8 + 0x90020204, // 004E SETMBR R0 K1 R4 + 0x70020038, // 004F JMP #0089 + 0x880C0101, // 0050 GETMBR R3 R0 K1 + 0x8810050C, // 0051 GETMBR R4 R2 K12 + 0x280C0604, // 0052 GE R3 R3 R4 + 0x780E0018, // 0053 JMPF R3 #006D + 0x880C0101, // 0054 GETMBR R3 R0 K1 + 0x8810050D, // 0055 GETMBR R4 R2 K13 + 0x180C0604, // 0056 LE R3 R3 R4 + 0x780E0014, // 0057 JMPF R3 #006D + 0x600C000C, // 0058 GETGBL R3 G12 + 0x88100104, // 0059 GETMBR R4 R0 K4 + 0x7C0C0200, // 005A CALL R3 1 + 0x541200FE, // 005B LDINT R4 255 + 0x180C0604, // 005C LE R3 R3 R4 + 0x780E0002, // 005D JMPF R3 #0061 + 0x880C050C, // 005E GETMBR R3 R2 K12 + 0x90020203, // 005F SETMBR R0 K1 R3 + 0x7002000A, // 0060 JMP #006C + 0x600C000C, // 0061 GETGBL R3 G12 + 0x88100104, // 0062 GETMBR R4 R0 K4 + 0x7C0C0200, // 0063 CALL R3 1 + 0x5412FFFE, // 0064 LDINT R4 65535 + 0x180C0604, // 0065 LE R3 R3 R4 + 0x780E0002, // 0066 JMPF R3 #006A + 0x880C050E, // 0067 GETMBR R3 R2 K14 + 0x90020203, // 0068 SETMBR R0 K1 R3 + 0x70020001, // 0069 JMP #006C + 0x880C050F, // 006A GETMBR R3 R2 K15 + 0x90020203, // 006B SETMBR R0 K1 R3 + 0x7002001B, // 006C JMP #0089 + 0x880C0101, // 006D GETMBR R3 R0 K1 + 0x88100510, // 006E GETMBR R4 R2 K16 + 0x280C0604, // 006F GE R3 R3 R4 + 0x780E0017, // 0070 JMPF R3 #0089 + 0x880C0101, // 0071 GETMBR R3 R0 K1 + 0x88100511, // 0072 GETMBR R4 R2 K17 + 0x180C0604, // 0073 LE R3 R3 R4 + 0x780E0013, // 0074 JMPF R3 #0089 + 0x600C000C, // 0075 GETGBL R3 G12 + 0x88100104, // 0076 GETMBR R4 R0 K4 + 0x7C0C0200, // 0077 CALL R3 1 + 0x541200FE, // 0078 LDINT R4 255 + 0x180C0604, // 0079 LE R3 R3 R4 + 0x780E0002, // 007A JMPF R3 #007E + 0x880C0510, // 007B GETMBR R3 R2 K16 + 0x90020203, // 007C SETMBR R0 K1 R3 + 0x7002000A, // 007D JMP #0089 + 0x600C000C, // 007E GETGBL R3 G12 + 0x88100104, // 007F GETMBR R4 R0 K4 + 0x7C0C0200, // 0080 CALL R3 1 + 0x5412FFFE, // 0081 LDINT R4 65535 + 0x180C0604, // 0082 LE R3 R3 R4 + 0x780E0002, // 0083 JMPF R3 #0087 + 0x880C0512, // 0084 GETMBR R3 R2 K18 + 0x90020203, // 0085 SETMBR R0 K1 R3 + 0x70020001, // 0086 JMP #0089 + 0x880C0513, // 0087 GETMBR R3 R2 K19 + 0x90020203, // 0088 SETMBR R0 K1 R3 + 0x8C0C0114, // 0089 GETMET R3 R0 K20 + 0x5C140200, // 008A MOVE R5 R1 + 0x7C0C0400, // 008B CALL R3 2 + 0x880C0101, // 008C GETMBR R3 R0 K1 + 0x88100507, // 008D GETMBR R4 R2 K7 + 0x1C0C0604, // 008E EQ R3 R3 R4 + 0x740E0003, // 008F JMPT R3 #0094 + 0x880C0101, // 0090 GETMBR R3 R0 K1 + 0x8810050B, // 0091 GETMBR R4 R2 K11 + 0x1C0C0604, // 0092 EQ R3 R3 R4 + 0x780E0006, // 0093 JMPF R3 #009B + 0x8C0C0315, // 0094 GETMET R3 R1 K21 + 0x60140009, // 0095 GETGBL R5 G9 + 0x88180104, // 0096 GETMBR R6 R0 K4 + 0x7C140200, // 0097 CALL R5 1 + 0x58180016, // 0098 LDCONST R6 K22 + 0x7C0C0600, // 0099 CALL R3 3 + 0x700200BC, // 009A JMP #0158 + 0x880C0101, // 009B GETMBR R3 R0 K1 + 0x88100505, // 009C GETMBR R4 R2 K5 + 0x1C0C0604, // 009D EQ R3 R3 R4 + 0x740E0003, // 009E JMPT R3 #00A3 + 0x880C0101, // 009F GETMBR R3 R0 K1 + 0x88100508, // 00A0 GETMBR R4 R2 K8 + 0x1C0C0604, // 00A1 EQ R3 R3 R4 + 0x780E0006, // 00A2 JMPF R3 #00AA + 0x8C0C0315, // 00A3 GETMET R3 R1 K21 + 0x60140009, // 00A4 GETGBL R5 G9 + 0x88180104, // 00A5 GETMBR R6 R0 K4 + 0x7C140200, // 00A6 CALL R5 1 + 0x58180017, // 00A7 LDCONST R6 K23 + 0x7C0C0600, // 00A8 CALL R3 3 + 0x700200AD, // 00A9 JMP #0158 + 0x880C0101, // 00AA GETMBR R3 R0 K1 + 0x88100506, // 00AB GETMBR R4 R2 K6 + 0x1C0C0604, // 00AC EQ R3 R3 R4 + 0x740E0003, // 00AD JMPT R3 #00B2 + 0x880C0101, // 00AE GETMBR R3 R0 K1 + 0x88100509, // 00AF GETMBR R4 R2 K9 + 0x1C0C0604, // 00B0 EQ R3 R3 R4 + 0x780E0006, // 00B1 JMPF R3 #00B9 + 0x8C0C0315, // 00B2 GETMET R3 R1 K21 + 0x60140009, // 00B3 GETGBL R5 G9 + 0x88180104, // 00B4 GETMBR R6 R0 K4 + 0x7C140200, // 00B5 CALL R5 1 + 0x541A0003, // 00B6 LDINT R6 4 + 0x7C0C0600, // 00B7 CALL R3 3 + 0x7002009E, // 00B8 JMP #0158 + 0x880C0101, // 00B9 GETMBR R3 R0 K1 + 0x88100518, // 00BA GETMBR R4 R2 K24 + 0x1C0C0604, // 00BB EQ R3 R3 R4 + 0x740E0003, // 00BC JMPT R3 #00C1 + 0x880C0101, // 00BD GETMBR R3 R0 K1 + 0x88100519, // 00BE GETMBR R4 R2 K25 + 0x1C0C0604, // 00BF EQ R3 R3 R4 + 0x780E000F, // 00C0 JMPF R3 #00D1 + 0x880C0104, // 00C1 GETMBR R3 R0 K4 + 0x6010000F, // 00C2 GETGBL R4 G15 + 0x5C140600, // 00C3 MOVE R5 R3 + 0xB81A3400, // 00C4 GETNGBL R6 K26 + 0x7C100400, // 00C5 CALL R4 2 + 0x74120005, // 00C6 JMPT R4 #00CD + 0xB8123400, // 00C7 GETNGBL R4 K26 + 0x60140009, // 00C8 GETGBL R5 G9 + 0x88180104, // 00C9 GETMBR R6 R0 K4 + 0x7C140200, // 00CA CALL R5 1 + 0x7C100200, // 00CB CALL R4 1 + 0x5C0C0800, // 00CC MOVE R3 R4 + 0x8C10071B, // 00CD GETMET R4 R3 K27 + 0x7C100200, // 00CE CALL R4 1 + 0x40100204, // 00CF CONNECT R4 R1 R4 + 0x70020086, // 00D0 JMP #0158 + 0x880C0101, // 00D1 GETMBR R3 R0 K1 + 0x88100502, // 00D2 GETMBR R4 R2 K2 + 0x1C0C0604, // 00D3 EQ R3 R3 R4 + 0x740E0003, // 00D4 JMPT R3 #00D9 + 0x880C0101, // 00D5 GETMBR R3 R0 K1 + 0x88100503, // 00D6 GETMBR R4 R2 K3 + 0x1C0C0604, // 00D7 EQ R3 R3 R4 + 0x780E0000, // 00D8 JMPF R3 #00DA + 0x7002007D, // 00D9 JMP #0158 + 0x880C0101, // 00DA GETMBR R3 R0 K1 + 0x8810051C, // 00DB GETMBR R4 R2 K28 + 0x1C0C0604, // 00DC EQ R3 R3 R4 + 0x780E000D, // 00DD JMPF R3 #00EC + 0x600C000C, // 00DE GETGBL R3 G12 + 0x5C100200, // 00DF MOVE R4 R1 + 0x7C0C0200, // 00E0 CALL R3 1 + 0x8C100315, // 00E1 GETMET R4 R1 K21 + 0x5818000A, // 00E2 LDCONST R6 K10 + 0x541E0003, // 00E3 LDINT R7 4 + 0x7C100600, // 00E4 CALL R4 3 + 0x8C10031D, // 00E5 GETMET R4 R1 K29 + 0x5C180600, // 00E6 MOVE R6 R3 + 0x601C000A, // 00E7 GETGBL R7 G10 + 0x88200104, // 00E8 GETMBR R8 R0 K4 + 0x7C1C0200, // 00E9 CALL R7 1 + 0x7C100600, // 00EA CALL R4 3 + 0x7002006B, // 00EB JMP #0158 + 0x880C0101, // 00EC GETMBR R3 R0 K1 + 0x8810051E, // 00ED GETMBR R4 R2 K30 + 0x1C0C0604, // 00EE EQ R3 R3 R4 + 0x780E0001, // 00EF JMPF R3 #00F2 + 0xB0063F20, // 00F0 RAISE 1 K31 K32 + 0x70020065, // 00F1 JMP #0158 + 0x880C0101, // 00F2 GETMBR R3 R0 K1 + 0x88100510, // 00F3 GETMBR R4 R2 K16 + 0x1C0C0604, // 00F4 EQ R3 R3 R4 + 0x780E0015, // 00F5 JMPF R3 #010C + 0x600C000C, // 00F6 GETGBL R3 G12 + 0x88100104, // 00F7 GETMBR R4 R0 K4 + 0x7C0C0200, // 00F8 CALL R3 1 + 0x541200FE, // 00F9 LDINT R4 255 + 0x240C0604, // 00FA GT R3 R3 R4 + 0x780E0000, // 00FB JMPF R3 #00FD + 0xB0063F21, // 00FC RAISE 1 K31 K33 + 0x8C0C0315, // 00FD GETMET R3 R1 K21 + 0x6014000C, // 00FE GETGBL R5 G12 + 0x88180104, // 00FF GETMBR R6 R0 K4 + 0x7C140200, // 0100 CALL R5 1 + 0x58180016, // 0101 LDCONST R6 K22 + 0x7C0C0600, // 0102 CALL R3 3 + 0x600C0015, // 0103 GETGBL R3 G21 + 0x7C0C0000, // 0104 CALL R3 0 + 0x8C0C0722, // 0105 GETMET R3 R3 K34 + 0x60140008, // 0106 GETGBL R5 G8 + 0x88180104, // 0107 GETMBR R6 R0 K4 + 0x7C140200, // 0108 CALL R5 1 + 0x7C0C0400, // 0109 CALL R3 2 + 0x400C0203, // 010A CONNECT R3 R1 R3 + 0x7002004B, // 010B JMP #0158 + 0x880C0101, // 010C GETMBR R3 R0 K1 + 0x88100512, // 010D GETMBR R4 R2 K18 + 0x1C0C0604, // 010E EQ R3 R3 R4 + 0x780E0015, // 010F JMPF R3 #0126 + 0x600C000C, // 0110 GETGBL R3 G12 + 0x88100104, // 0111 GETMBR R4 R0 K4 + 0x7C0C0200, // 0112 CALL R3 1 + 0x5412FFFE, // 0113 LDINT R4 65535 + 0x240C0604, // 0114 GT R3 R3 R4 + 0x780E0000, // 0115 JMPF R3 #0117 + 0xB0063F21, // 0116 RAISE 1 K31 K33 + 0x8C0C0315, // 0117 GETMET R3 R1 K21 + 0x6014000C, // 0118 GETGBL R5 G12 + 0x88180104, // 0119 GETMBR R6 R0 K4 + 0x7C140200, // 011A CALL R5 1 + 0x58180017, // 011B LDCONST R6 K23 + 0x7C0C0600, // 011C CALL R3 3 + 0x600C0015, // 011D GETGBL R3 G21 + 0x7C0C0000, // 011E CALL R3 0 + 0x8C0C0723, // 011F GETMET R3 R3 K35 + 0x60140008, // 0120 GETGBL R5 G8 + 0x88180104, // 0121 GETMBR R6 R0 K4 + 0x7C140200, // 0122 CALL R5 1 + 0x7C0C0400, // 0123 CALL R3 2 + 0x400C0203, // 0124 CONNECT R3 R1 R3 + 0x70020031, // 0125 JMP #0158 + 0x880C0101, // 0126 GETMBR R3 R0 K1 + 0x8810050C, // 0127 GETMBR R4 R2 K12 + 0x1C0C0604, // 0128 EQ R3 R3 R4 + 0x780E000F, // 0129 JMPF R3 #013A + 0x600C000C, // 012A GETGBL R3 G12 + 0x88100104, // 012B GETMBR R4 R0 K4 + 0x7C0C0200, // 012C CALL R3 1 + 0x541200FE, // 012D LDINT R4 255 + 0x240C0604, // 012E GT R3 R3 R4 + 0x780E0000, // 012F JMPF R3 #0131 + 0xB0063F24, // 0130 RAISE 1 K31 K36 + 0x8C0C0315, // 0131 GETMET R3 R1 K21 + 0x6014000C, // 0132 GETGBL R5 G12 + 0x88180104, // 0133 GETMBR R6 R0 K4 + 0x7C140200, // 0134 CALL R5 1 + 0x58180016, // 0135 LDCONST R6 K22 + 0x7C0C0600, // 0136 CALL R3 3 + 0x880C0104, // 0137 GETMBR R3 R0 K4 + 0x400C0203, // 0138 CONNECT R3 R1 R3 + 0x7002001D, // 0139 JMP #0158 + 0x880C0101, // 013A GETMBR R3 R0 K1 + 0x8810050E, // 013B GETMBR R4 R2 K14 + 0x1C0C0604, // 013C EQ R3 R3 R4 + 0x780E000F, // 013D JMPF R3 #014E + 0x600C000C, // 013E GETGBL R3 G12 + 0x88100104, // 013F GETMBR R4 R0 K4 + 0x7C0C0200, // 0140 CALL R3 1 + 0x5412FFFE, // 0141 LDINT R4 65535 + 0x240C0604, // 0142 GT R3 R3 R4 + 0x780E0000, // 0143 JMPF R3 #0145 + 0xB0063F24, // 0144 RAISE 1 K31 K36 + 0x8C0C0315, // 0145 GETMET R3 R1 K21 + 0x6014000C, // 0146 GETGBL R5 G12 + 0x88180104, // 0147 GETMBR R6 R0 K4 + 0x7C140200, // 0148 CALL R5 1 + 0x58180017, // 0149 LDCONST R6 K23 + 0x7C0C0600, // 014A CALL R3 3 + 0x880C0104, // 014B GETMBR R3 R0 K4 + 0x400C0203, // 014C CONNECT R3 R1 R3 + 0x70020009, // 014D JMP #0158 + 0x880C0101, // 014E GETMBR R3 R0 K1 + 0x88100525, // 014F GETMBR R4 R2 K37 + 0x1C0C0604, // 0150 EQ R3 R3 R4 + 0x780E0000, // 0151 JMPF R3 #0153 + 0x70020004, // 0152 JMP #0158 + 0x600C0008, // 0153 GETGBL R3 G8 + 0x88100101, // 0154 GETMBR R4 R0 K1 + 0x7C0C0200, // 0155 CALL R3 1 + 0x000E4C03, // 0156 ADD R3 K38 R3 + 0xB0063E03, // 0157 RAISE 1 K31 R3 + 0x80040200, // 0158 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: create_TLV +********************************************************************/ +be_local_closure(Matter_TLV_item_create_TLV, /* name */ + be_nested_proto( + 4, /* nstack */ + 2, /* argc */ + 4, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_const_class(be_class_Matter_TLV_item), + /* K1 */ be_nested_str_weak(typ), + /* K2 */ be_nested_str_weak(val), + }), + be_str_weak(create_TLV), + &be_const_str_solidified, + ( &(const binstruction[10]) { /* code */ + 0x58080000, // 0000 LDCONST R2 K0 + 0x4C0C0000, // 0001 LDNIL R3 + 0x200C0203, // 0002 NE R3 R1 R3 + 0x780E0004, // 0003 JMPF R3 #0009 + 0x5C0C0400, // 0004 MOVE R3 R2 + 0x7C0C0000, // 0005 CALL R3 0 + 0x900E0200, // 0006 SETMBR R3 K1 R0 + 0x900E0401, // 0007 SETMBR R3 K2 R1 + 0x80040600, // 0008 RET 1 R3 + 0x80000000, // 0009 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: _encode_tag +********************************************************************/ +be_local_closure(Matter_TLV_item__encode_tag, /* name */ + be_nested_proto( + 9, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 9]) { /* constants */ + /* K0 */ be_nested_str_weak(tag_number), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str_weak(tag_vendor), + /* K3 */ be_nested_str_weak(add), + /* K4 */ be_nested_str_weak(typ), + /* K5 */ be_const_int(1), + /* K6 */ be_const_int(2), + /* K7 */ be_nested_str_weak(tag_profile), + /* K8 */ be_nested_str_weak(tag_sub), + }), + be_str_weak(_encode_tag), + &be_const_str_solidified, + ( &(const binstruction[133]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x4C0C0000, // 0001 LDNIL R3 + 0x20080403, // 0002 NE R2 R2 R3 + 0x780A0001, // 0003 JMPF R2 #0006 + 0x88080100, // 0004 GETMBR R2 R0 K0 + 0x70020000, // 0005 JMP #0007 + 0x58080001, // 0006 LDCONST R2 K1 + 0x540EFFFF, // 0007 LDINT R3 65536 + 0x280C0403, // 0008 GE R3 R2 R3 + 0x740E0002, // 0009 JMPT R3 #000D + 0x140C0501, // 000A LT R3 R2 K1 + 0x740E0000, // 000B JMPT R3 #000D + 0x500C0001, // 000C LDBOOL R3 0 1 + 0x500C0200, // 000D LDBOOL R3 1 0 + 0x58100001, // 000E LDCONST R4 K1 + 0x88140102, // 000F GETMBR R5 R0 K2 + 0x4C180000, // 0010 LDNIL R6 + 0x20140A06, // 0011 NE R5 R5 R6 + 0x78160026, // 0012 JMPF R5 #003A + 0x780E0012, // 0013 JMPF R3 #0027 + 0x8C140303, // 0014 GETMET R5 R1 K3 + 0x541E00DF, // 0015 LDINT R7 224 + 0x88200104, // 0016 GETMBR R8 R0 K4 + 0x001C0E08, // 0017 ADD R7 R7 R8 + 0x58200005, // 0018 LDCONST R8 K5 + 0x7C140600, // 0019 CALL R5 3 + 0x8C140303, // 001A GETMET R5 R1 K3 + 0x881C0102, // 001B GETMBR R7 R0 K2 + 0x58200006, // 001C LDCONST R8 K6 + 0x7C140600, // 001D CALL R5 3 + 0x8C140303, // 001E GETMET R5 R1 K3 + 0x881C0107, // 001F GETMBR R7 R0 K7 + 0x58200006, // 0020 LDCONST R8 K6 + 0x7C140600, // 0021 CALL R5 3 + 0x8C140303, // 0022 GETMET R5 R1 K3 + 0x881C0100, // 0023 GETMBR R7 R0 K0 + 0x54220003, // 0024 LDINT R8 4 + 0x7C140600, // 0025 CALL R5 3 + 0x70020011, // 0026 JMP #0039 + 0x8C140303, // 0027 GETMET R5 R1 K3 + 0x541E00BF, // 0028 LDINT R7 192 + 0x88200104, // 0029 GETMBR R8 R0 K4 + 0x001C0E08, // 002A ADD R7 R7 R8 + 0x58200005, // 002B LDCONST R8 K5 + 0x7C140600, // 002C CALL R5 3 + 0x8C140303, // 002D GETMET R5 R1 K3 + 0x881C0102, // 002E GETMBR R7 R0 K2 + 0x58200006, // 002F LDCONST R8 K6 + 0x7C140600, // 0030 CALL R5 3 + 0x8C140303, // 0031 GETMET R5 R1 K3 + 0x881C0107, // 0032 GETMBR R7 R0 K7 + 0x58200006, // 0033 LDCONST R8 K6 + 0x7C140600, // 0034 CALL R5 3 + 0x8C140303, // 0035 GETMET R5 R1 K3 + 0x881C0100, // 0036 GETMBR R7 R0 K0 + 0x58200006, // 0037 LDCONST R8 K6 + 0x7C140600, // 0038 CALL R5 3 + 0x70020049, // 0039 JMP #0084 + 0x88140107, // 003A GETMBR R5 R0 K7 + 0x5419FFFE, // 003B LDINT R6 -1 + 0x1C140A06, // 003C EQ R5 R5 R6 + 0x78160016, // 003D JMPF R5 #0055 + 0x780E000A, // 003E JMPF R3 #004A + 0x8C140303, // 003F GETMET R5 R1 K3 + 0x541E005F, // 0040 LDINT R7 96 + 0x88200104, // 0041 GETMBR R8 R0 K4 + 0x001C0E08, // 0042 ADD R7 R7 R8 + 0x58200005, // 0043 LDCONST R8 K5 + 0x7C140600, // 0044 CALL R5 3 + 0x8C140303, // 0045 GETMET R5 R1 K3 + 0x881C0100, // 0046 GETMBR R7 R0 K0 + 0x54220003, // 0047 LDINT R8 4 + 0x7C140600, // 0048 CALL R5 3 + 0x70020009, // 0049 JMP #0054 + 0x8C140303, // 004A GETMET R5 R1 K3 + 0x541E003F, // 004B LDINT R7 64 + 0x88200104, // 004C GETMBR R8 R0 K4 + 0x001C0E08, // 004D ADD R7 R7 R8 + 0x58200005, // 004E LDCONST R8 K5 + 0x7C140600, // 004F CALL R5 3 + 0x8C140303, // 0050 GETMET R5 R1 K3 + 0x881C0100, // 0051 GETMBR R7 R0 K0 + 0x58200006, // 0052 LDCONST R8 K6 + 0x7C140600, // 0053 CALL R5 3 + 0x7002002E, // 0054 JMP #0084 + 0x88140107, // 0055 GETMBR R5 R0 K7 + 0x4C180000, // 0056 LDNIL R6 + 0x20140A06, // 0057 NE R5 R5 R6 + 0x78160016, // 0058 JMPF R5 #0070 + 0x780E000A, // 0059 JMPF R3 #0065 + 0x8C140303, // 005A GETMET R5 R1 K3 + 0x541E009F, // 005B LDINT R7 160 + 0x88200104, // 005C GETMBR R8 R0 K4 + 0x001C0E08, // 005D ADD R7 R7 R8 + 0x58200005, // 005E LDCONST R8 K5 + 0x7C140600, // 005F CALL R5 3 + 0x8C140303, // 0060 GETMET R5 R1 K3 + 0x881C0100, // 0061 GETMBR R7 R0 K0 + 0x54220003, // 0062 LDINT R8 4 + 0x7C140600, // 0063 CALL R5 3 + 0x70020009, // 0064 JMP #006F + 0x8C140303, // 0065 GETMET R5 R1 K3 + 0x541E007F, // 0066 LDINT R7 128 + 0x88200104, // 0067 GETMBR R8 R0 K4 + 0x001C0E08, // 0068 ADD R7 R7 R8 + 0x58200005, // 0069 LDCONST R8 K5 + 0x7C140600, // 006A CALL R5 3 + 0x8C140303, // 006B GETMET R5 R1 K3 + 0x881C0100, // 006C GETMBR R7 R0 K0 + 0x58200006, // 006D LDCONST R8 K6 + 0x7C140600, // 006E CALL R5 3 + 0x70020013, // 006F JMP #0084 + 0x88140108, // 0070 GETMBR R5 R0 K8 + 0x4C180000, // 0071 LDNIL R6 + 0x20140A06, // 0072 NE R5 R5 R6 + 0x7816000A, // 0073 JMPF R5 #007F + 0x8C140303, // 0074 GETMET R5 R1 K3 + 0x541E001F, // 0075 LDINT R7 32 + 0x88200104, // 0076 GETMBR R8 R0 K4 + 0x001C0E08, // 0077 ADD R7 R7 R8 + 0x58200005, // 0078 LDCONST R8 K5 + 0x7C140600, // 0079 CALL R5 3 + 0x8C140303, // 007A GETMET R5 R1 K3 + 0x881C0108, // 007B GETMBR R7 R0 K8 + 0x58200005, // 007C LDCONST R8 K5 + 0x7C140600, // 007D CALL R5 3 + 0x70020004, // 007E JMP #0084 + 0x8C140303, // 007F GETMET R5 R1 K3 + 0x881C0104, // 0080 GETMBR R7 R0 K4 + 0x001E0207, // 0081 ADD R7 K1 R7 + 0x58200005, // 0082 LDCONST R8 K5 + 0x7C140600, // 0083 CALL R5 3 + 0x80000000, // 0084 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_parent +********************************************************************/ +be_local_closure(Matter_TLV_item_set_parent, /* name */ + be_nested_proto( + 2, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(parent), + }), + be_str_weak(set_parent), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x80000000, // 0001 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_fulltag +********************************************************************/ +be_local_closure(Matter_TLV_item_set_fulltag, /* name */ + be_nested_proto( + 6, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(tag_vendor), + /* K1 */ be_nested_str_weak(tag_profile), + /* K2 */ be_nested_str_weak(tag_number), + /* K3 */ be_nested_str_weak(tag_sub), + }), + be_str_weak(set_fulltag), + &be_const_str_solidified, + ( &(const binstruction[15]) { /* code */ + 0x60100009, // 0000 GETGBL R4 G9 + 0x5C140200, // 0001 MOVE R5 R1 + 0x7C100200, // 0002 CALL R4 1 + 0x90020004, // 0003 SETMBR R0 K0 R4 + 0x60100009, // 0004 GETGBL R4 G9 + 0x5C140400, // 0005 MOVE R5 R2 + 0x7C100200, // 0006 CALL R4 1 + 0x90020204, // 0007 SETMBR R0 K1 R4 + 0x60100009, // 0008 GETGBL R4 G9 + 0x5C140600, // 0009 MOVE R5 R3 + 0x7C100200, // 000A CALL R4 1 + 0x90020404, // 000B SETMBR R0 K2 R4 + 0x4C100000, // 000C LDNIL R4 + 0x90020604, // 000D SETMBR R0 K3 R4 + 0x80000000, // 000E RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: to_TLV +********************************************************************/ +be_local_closure(Matter_TLV_item_to_TLV, /* name */ + be_nested_proto( + 1, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + be_str_weak(to_TLV), + &be_const_str_solidified, + ( &(const binstruction[ 1]) { /* code */ + 0x80040000, // 0000 RET 1 R0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: tostring +********************************************************************/ +be_local_closure(Matter_TLV_item_tostring, /* name */ + be_nested_proto( + 8, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[35]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(), + /* K2 */ be_nested_str_weak(tag_profile), + /* K3 */ be_nested_str_weak(Matter_X3A_X3A), + /* K4 */ be_nested_str_weak(tag_number), + /* K5 */ be_nested_str_weak(format), + /* K6 */ be_nested_str_weak(0x_X2508X_X20), + /* K7 */ be_nested_str_weak(tag_vendor), + /* K8 */ be_nested_str_weak(0x_X2504X_X3A_X3A), + /* K9 */ be_nested_str_weak(0x_X2504X_X3A), + /* K10 */ be_nested_str_weak(tag_sub), + /* K11 */ be_nested_str_weak(_X25i_X20), + /* K12 */ be_const_int(0), + /* K13 */ be_nested_str_weak(_X3D_X20), + /* K14 */ be_nested_str_weak(val), + /* K15 */ be_nested_str_weak(int), + /* K16 */ be_nested_str_weak(_X25i), + /* K17 */ be_nested_str_weak(typ), + /* K18 */ be_nested_str_weak(TLV), + /* K19 */ be_nested_str_weak(U1), + /* K20 */ be_nested_str_weak(U8), + /* K21 */ be_nested_str_weak(U), + /* K22 */ be_nested_str_weak(bool), + /* K23 */ be_nested_str_weak(true), + /* K24 */ be_nested_str_weak(false), + /* K25 */ be_nested_str_weak(null), + /* K26 */ be_nested_str_weak(real), + /* K27 */ be_nested_str_weak(_X25g), + /* K28 */ be_nested_str_weak(_X22_X25s_X22), + /* K29 */ be_nested_str_weak(int64), + /* K30 */ be_nested_str_weak(tostring), + /* K31 */ be_nested_str_weak(instance), + /* K32 */ be_nested_str_weak(_X25s), + /* K33 */ be_nested_str_weak(tohex), + /* K34 */ be_nested_str_weak(_X20), + }), + be_str_weak(tostring), + &be_const_str_solidified, + ( &(const binstruction[165]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x58080001, // 0001 LDCONST R2 K1 + 0xA8020099, // 0002 EXBLK 0 #009D + 0x880C0102, // 0003 GETMBR R3 R0 K2 + 0x5411FFFE, // 0004 LDINT R4 -1 + 0x1C0C0604, // 0005 EQ R3 R3 R4 + 0x780E000A, // 0006 JMPF R3 #0012 + 0x00080503, // 0007 ADD R2 R2 K3 + 0x880C0104, // 0008 GETMBR R3 R0 K4 + 0x4C100000, // 0009 LDNIL R4 + 0x200C0604, // 000A NE R3 R3 R4 + 0x780E0004, // 000B JMPF R3 #0011 + 0x8C0C0305, // 000C GETMET R3 R1 K5 + 0x58140006, // 000D LDCONST R5 K6 + 0x88180104, // 000E GETMBR R6 R0 K4 + 0x7C0C0600, // 000F CALL R3 3 + 0x00080403, // 0010 ADD R2 R2 R3 + 0x70020023, // 0011 JMP #0036 + 0x880C0107, // 0012 GETMBR R3 R0 K7 + 0x4C100000, // 0013 LDNIL R4 + 0x200C0604, // 0014 NE R3 R3 R4 + 0x780E0004, // 0015 JMPF R3 #001B + 0x8C0C0305, // 0016 GETMET R3 R1 K5 + 0x58140008, // 0017 LDCONST R5 K8 + 0x88180107, // 0018 GETMBR R6 R0 K7 + 0x7C0C0600, // 0019 CALL R3 3 + 0x00080403, // 001A ADD R2 R2 R3 + 0x880C0102, // 001B GETMBR R3 R0 K2 + 0x4C100000, // 001C LDNIL R4 + 0x200C0604, // 001D NE R3 R3 R4 + 0x780E0004, // 001E JMPF R3 #0024 + 0x8C0C0305, // 001F GETMET R3 R1 K5 + 0x58140009, // 0020 LDCONST R5 K9 + 0x88180102, // 0021 GETMBR R6 R0 K2 + 0x7C0C0600, // 0022 CALL R3 3 + 0x00080403, // 0023 ADD R2 R2 R3 + 0x880C0104, // 0024 GETMBR R3 R0 K4 + 0x4C100000, // 0025 LDNIL R4 + 0x200C0604, // 0026 NE R3 R3 R4 + 0x780E0004, // 0027 JMPF R3 #002D + 0x8C0C0305, // 0028 GETMET R3 R1 K5 + 0x58140006, // 0029 LDCONST R5 K6 + 0x88180104, // 002A GETMBR R6 R0 K4 + 0x7C0C0600, // 002B CALL R3 3 + 0x00080403, // 002C ADD R2 R2 R3 + 0x880C010A, // 002D GETMBR R3 R0 K10 + 0x4C100000, // 002E LDNIL R4 + 0x200C0604, // 002F NE R3 R3 R4 + 0x780E0004, // 0030 JMPF R3 #0036 + 0x8C0C0305, // 0031 GETMET R3 R1 K5 + 0x5814000B, // 0032 LDCONST R5 K11 + 0x8818010A, // 0033 GETMBR R6 R0 K10 + 0x7C0C0600, // 0034 CALL R3 3 + 0x00080403, // 0035 ADD R2 R2 R3 + 0x600C000C, // 0036 GETGBL R3 G12 + 0x5C100400, // 0037 MOVE R4 R2 + 0x7C0C0200, // 0038 CALL R3 1 + 0x240C070C, // 0039 GT R3 R3 K12 + 0x780E0000, // 003A JMPF R3 #003C + 0x0008050D, // 003B ADD R2 R2 K13 + 0x600C0004, // 003C GETGBL R3 G4 + 0x8810010E, // 003D GETMBR R4 R0 K14 + 0x7C0C0200, // 003E CALL R3 1 + 0x1C0C070F, // 003F EQ R3 R3 K15 + 0x780E0010, // 0040 JMPF R3 #0052 + 0x8C0C0305, // 0041 GETMET R3 R1 K5 + 0x58140010, // 0042 LDCONST R5 K16 + 0x8818010E, // 0043 GETMBR R6 R0 K14 + 0x7C0C0600, // 0044 CALL R3 3 + 0x00080403, // 0045 ADD R2 R2 R3 + 0x880C0111, // 0046 GETMBR R3 R0 K17 + 0x88100112, // 0047 GETMBR R4 R0 K18 + 0x88100913, // 0048 GETMBR R4 R4 K19 + 0x280C0604, // 0049 GE R3 R3 R4 + 0x780E0005, // 004A JMPF R3 #0051 + 0x880C0111, // 004B GETMBR R3 R0 K17 + 0x88100112, // 004C GETMBR R4 R0 K18 + 0x88100914, // 004D GETMBR R4 R4 K20 + 0x180C0604, // 004E LE R3 R3 R4 + 0x780E0000, // 004F JMPF R3 #0051 + 0x00080515, // 0050 ADD R2 R2 K21 + 0x70020048, // 0051 JMP #009B + 0x600C0004, // 0052 GETGBL R3 G4 + 0x8810010E, // 0053 GETMBR R4 R0 K14 + 0x7C0C0200, // 0054 CALL R3 1 + 0x1C0C0716, // 0055 EQ R3 R3 K22 + 0x780E0006, // 0056 JMPF R3 #005E + 0x880C010E, // 0057 GETMBR R3 R0 K14 + 0x780E0001, // 0058 JMPF R3 #005B + 0x580C0017, // 0059 LDCONST R3 K23 + 0x70020000, // 005A JMP #005C + 0x580C0018, // 005B LDCONST R3 K24 + 0x00080403, // 005C ADD R2 R2 R3 + 0x7002003C, // 005D JMP #009B + 0x880C010E, // 005E GETMBR R3 R0 K14 + 0x4C100000, // 005F LDNIL R4 + 0x1C0C0604, // 0060 EQ R3 R3 R4 + 0x780E0001, // 0061 JMPF R3 #0064 + 0x00080519, // 0062 ADD R2 R2 K25 + 0x70020036, // 0063 JMP #009B + 0x600C0004, // 0064 GETGBL R3 G4 + 0x8810010E, // 0065 GETMBR R4 R0 K14 + 0x7C0C0200, // 0066 CALL R3 1 + 0x1C0C071A, // 0067 EQ R3 R3 K26 + 0x780E0005, // 0068 JMPF R3 #006F + 0x8C0C0305, // 0069 GETMET R3 R1 K5 + 0x5814001B, // 006A LDCONST R5 K27 + 0x8818010E, // 006B GETMBR R6 R0 K14 + 0x7C0C0600, // 006C CALL R3 3 + 0x00080403, // 006D ADD R2 R2 R3 + 0x7002002B, // 006E JMP #009B + 0x600C0004, // 006F GETGBL R3 G4 + 0x8810010E, // 0070 GETMBR R4 R0 K14 + 0x7C0C0200, // 0071 CALL R3 1 + 0x1C0C0700, // 0072 EQ R3 R3 K0 + 0x780E0005, // 0073 JMPF R3 #007A + 0x8C0C0305, // 0074 GETMET R3 R1 K5 + 0x5814001C, // 0075 LDCONST R5 K28 + 0x8818010E, // 0076 GETMBR R6 R0 K14 + 0x7C0C0600, // 0077 CALL R3 3 + 0x00080403, // 0078 ADD R2 R2 R3 + 0x70020020, // 0079 JMP #009B + 0x600C000F, // 007A GETGBL R3 G15 + 0x8810010E, // 007B GETMBR R4 R0 K14 + 0xB8163A00, // 007C GETNGBL R5 K29 + 0x7C0C0400, // 007D CALL R3 2 + 0x780E000F, // 007E JMPF R3 #008F + 0x880C010E, // 007F GETMBR R3 R0 K14 + 0x8C0C071E, // 0080 GETMET R3 R3 K30 + 0x7C0C0200, // 0081 CALL R3 1 + 0x00080403, // 0082 ADD R2 R2 R3 + 0x880C0111, // 0083 GETMBR R3 R0 K17 + 0x88100112, // 0084 GETMBR R4 R0 K18 + 0x88100913, // 0085 GETMBR R4 R4 K19 + 0x280C0604, // 0086 GE R3 R3 R4 + 0x780E0005, // 0087 JMPF R3 #008E + 0x880C0111, // 0088 GETMBR R3 R0 K17 + 0x88100112, // 0089 GETMBR R4 R0 K18 + 0x88100914, // 008A GETMBR R4 R4 K20 + 0x180C0604, // 008B LE R3 R3 R4 + 0x780E0000, // 008C JMPF R3 #008E + 0x00080515, // 008D ADD R2 R2 K21 + 0x7002000B, // 008E JMP #009B + 0x600C0004, // 008F GETGBL R3 G4 + 0x8810010E, // 0090 GETMBR R4 R0 K14 + 0x7C0C0200, // 0091 CALL R3 1 + 0x1C0C071F, // 0092 EQ R3 R3 K31 + 0x780E0006, // 0093 JMPF R3 #009B + 0x8C0C0305, // 0094 GETMET R3 R1 K5 + 0x58140020, // 0095 LDCONST R5 K32 + 0x8818010E, // 0096 GETMBR R6 R0 K14 + 0x8C180D21, // 0097 GETMET R6 R6 K33 + 0x7C180200, // 0098 CALL R6 1 + 0x7C0C0600, // 0099 CALL R3 3 + 0x00080403, // 009A ADD R2 R2 R3 + 0xA8040001, // 009B EXBLK 1 1 + 0x70020006, // 009C JMP #00A4 + 0xAC0C0002, // 009D CATCH R3 0 2 + 0x70020003, // 009E JMP #00A3 + 0x00140722, // 009F ADD R5 R3 K34 + 0x00140A04, // 00A0 ADD R5 R5 R4 + 0x80040A00, // 00A1 RET 1 R5 + 0x70020000, // 00A2 JMP #00A4 + 0xB0080000, // 00A3 RAISE 2 R0 R0 + 0x80040400, // 00A4 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: parse +********************************************************************/ +be_local_closure(Matter_TLV_item_parse, /* name */ + be_nested_proto( + 10, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[25]) { /* constants */ + /* K0 */ be_nested_str_weak(typ), + /* K1 */ be_nested_str_weak(TLV), + /* K2 */ be_nested_str_weak(_len), + /* K3 */ be_nested_str_weak(val), + /* K4 */ be_nested_str_weak(int64), + /* K5 */ be_nested_str_weak(frombytes), + /* K6 */ be_nested_str_weak(BFALSE), + /* K7 */ be_nested_str_weak(BTRUE), + /* K8 */ be_nested_str_weak(U8), + /* K9 */ be_nested_str_weak(I8), + /* K10 */ be_nested_str_weak(geti), + /* K11 */ be_nested_str_weak(get), + /* K12 */ be_nested_str_weak(FLOAT), + /* K13 */ be_nested_str_weak(getfloat), + /* K14 */ be_const_int(1), + /* K15 */ be_nested_str_weak(UTF8), + /* K16 */ be_nested_str_weak(asstring), + /* K17 */ be_nested_str_weak(NULL), + /* K18 */ be_nested_str_weak(EOC), + /* K19 */ be_nested_str_weak(tasmota), + /* K20 */ be_nested_str_weak(log), + /* K21 */ be_nested_str_weak(MTR_X3A_X20unexpected_X20eoc), + /* K22 */ be_const_int(3), + /* K23 */ be_nested_str_weak(MTR_X3A_X20unexpected_X20type_X3A_X20), + /* K24 */ be_nested_str_weak(next_idx), + }), + be_str_weak(parse), + &be_const_str_solidified, + ( &(const binstruction[105]) { /* code */ + 0x880C0100, // 0000 GETMBR R3 R0 K0 + 0x88100101, // 0001 GETMBR R4 R0 K1 + 0x88140902, // 0002 GETMBR R5 R4 K2 + 0x94140A03, // 0003 GETIDX R5 R5 R3 + 0x541A0007, // 0004 LDINT R6 8 + 0x1C180A06, // 0005 EQ R6 R5 R6 + 0x781A000A, // 0006 JMPF R6 #0012 + 0xB81A0800, // 0007 GETNGBL R6 K4 + 0x7C180000, // 0008 CALL R6 0 + 0x90020606, // 0009 SETMBR R0 K3 R6 + 0x88180103, // 000A GETMBR R6 R0 K3 + 0x8C180D05, // 000B GETMET R6 R6 K5 + 0x5C200200, // 000C MOVE R8 R1 + 0x5C240400, // 000D MOVE R9 R2 + 0x7C180600, // 000E CALL R6 3 + 0x541A0007, // 000F LDINT R6 8 + 0x00080406, // 0010 ADD R2 R2 R6 + 0x70020054, // 0011 JMP #0067 + 0x88180906, // 0012 GETMBR R6 R4 K6 + 0x1C180606, // 0013 EQ R6 R3 R6 + 0x741A0002, // 0014 JMPT R6 #0018 + 0x88180907, // 0015 GETMBR R6 R4 K7 + 0x1C180606, // 0016 EQ R6 R3 R6 + 0x781A0003, // 0017 JMPF R6 #001C + 0x88180907, // 0018 GETMBR R6 R4 K7 + 0x1C180606, // 0019 EQ R6 R3 R6 + 0x90020606, // 001A SETMBR R0 K3 R6 + 0x7002004A, // 001B JMP #0067 + 0x88180908, // 001C GETMBR R6 R4 K8 + 0x14180606, // 001D LT R6 R3 R6 + 0x781A000E, // 001E JMPF R6 #002E + 0x88180909, // 001F GETMBR R6 R4 K9 + 0x18180606, // 0020 LE R6 R3 R6 + 0x781A0004, // 0021 JMPF R6 #0027 + 0x8C18030A, // 0022 GETMET R6 R1 K10 + 0x5C200400, // 0023 MOVE R8 R2 + 0x5C240A00, // 0024 MOVE R9 R5 + 0x7C180600, // 0025 CALL R6 3 + 0x70020003, // 0026 JMP #002B + 0x8C18030B, // 0027 GETMET R6 R1 K11 + 0x5C200400, // 0028 MOVE R8 R2 + 0x5C240A00, // 0029 MOVE R9 R5 + 0x7C180600, // 002A CALL R6 3 + 0x90020606, // 002B SETMBR R0 K3 R6 + 0x00080405, // 002C ADD R2 R2 R5 + 0x70020038, // 002D JMP #0067 + 0x8818090C, // 002E GETMBR R6 R4 K12 + 0x1C180606, // 002F EQ R6 R3 R6 + 0x781A0006, // 0030 JMPF R6 #0038 + 0x8C18030D, // 0031 GETMET R6 R1 K13 + 0x5C200400, // 0032 MOVE R8 R2 + 0x7C180400, // 0033 CALL R6 2 + 0x90020606, // 0034 SETMBR R0 K3 R6 + 0x541A0003, // 0035 LDINT R6 4 + 0x00080406, // 0036 ADD R2 R2 R6 + 0x7002002E, // 0037 JMP #0067 + 0x5419FFF7, // 0038 LDINT R6 -8 + 0x28180A06, // 0039 GE R6 R5 R6 + 0x781A0016, // 003A JMPF R6 #0052 + 0x5419FFFE, // 003B LDINT R6 -1 + 0x18180A06, // 003C LE R6 R5 R6 + 0x781A0013, // 003D JMPF R6 #0052 + 0x8C18030B, // 003E GETMET R6 R1 K11 + 0x5C200400, // 003F MOVE R8 R2 + 0x44240A00, // 0040 NEG R9 R5 + 0x7C180600, // 0041 CALL R6 3 + 0x441C0A00, // 0042 NEG R7 R5 + 0x00080407, // 0043 ADD R2 R2 R7 + 0x001C0406, // 0044 ADD R7 R2 R6 + 0x041C0F0E, // 0045 SUB R7 R7 K14 + 0x401C0407, // 0046 CONNECT R7 R2 R7 + 0x941C0207, // 0047 GETIDX R7 R1 R7 + 0x90020607, // 0048 SETMBR R0 K3 R7 + 0x00080406, // 0049 ADD R2 R2 R6 + 0x881C090F, // 004A GETMBR R7 R4 K15 + 0x181C0607, // 004B LE R7 R3 R7 + 0x781E0003, // 004C JMPF R7 #0051 + 0x881C0103, // 004D GETMBR R7 R0 K3 + 0x8C1C0F10, // 004E GETMET R7 R7 K16 + 0x7C1C0200, // 004F CALL R7 1 + 0x90020607, // 0050 SETMBR R0 K3 R7 + 0x70020014, // 0051 JMP #0067 + 0x88180911, // 0052 GETMBR R6 R4 K17 + 0x1C180606, // 0053 EQ R6 R3 R6 + 0x781A0000, // 0054 JMPF R6 #0056 + 0x70020010, // 0055 JMP #0067 + 0x88180912, // 0056 GETMBR R6 R4 K18 + 0x1C180606, // 0057 EQ R6 R3 R6 + 0x781A0005, // 0058 JMPF R6 #005F + 0xB81A2600, // 0059 GETNGBL R6 K19 + 0x8C180D14, // 005A GETMET R6 R6 K20 + 0x58200015, // 005B LDCONST R8 K21 + 0x58240016, // 005C LDCONST R9 K22 + 0x7C180600, // 005D CALL R6 3 + 0x70020007, // 005E JMP #0067 + 0xB81A2600, // 005F GETNGBL R6 K19 + 0x8C180D14, // 0060 GETMET R6 R6 K20 + 0x60200008, // 0061 GETGBL R8 G8 + 0x5C240600, // 0062 MOVE R9 R3 + 0x7C200200, // 0063 CALL R8 1 + 0x00222E08, // 0064 ADD R8 K23 R8 + 0x58240016, // 0065 LDCONST R9 K22 + 0x7C180600, // 0066 CALL R6 3 + 0x90023002, // 0067 SETMBR R0 K24 R2 + 0x80040400, // 0068 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_TLV_item_init, /* name */ + be_nested_proto( + 2, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(parent), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x80000000, // 0001 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: _cmp_gt +********************************************************************/ +be_local_closure(Matter_TLV_item__cmp_gt, /* name */ + be_nested_proto( + 4, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(tag_vendor), + /* K1 */ be_const_int(1), + /* K2 */ be_nested_str_weak(tag_profile), + /* K3 */ be_const_int(0), + /* K4 */ be_nested_str_weak(tag_number), + /* K5 */ be_nested_str_weak(tag_sub), + }), + be_str_weak(_cmp_gt), + &be_const_str_solidified, + ( &(const binstruction[72]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x4C0C0000, // 0001 LDNIL R3 + 0x20080403, // 0002 NE R2 R2 R3 + 0x780A0012, // 0003 JMPF R2 #0017 + 0x88080300, // 0004 GETMBR R2 R1 K0 + 0x4C0C0000, // 0005 LDNIL R3 + 0x1C080403, // 0006 EQ R2 R2 R3 + 0x780A0000, // 0007 JMPF R2 #0009 + 0x80060200, // 0008 RET 1 K1 + 0x88080100, // 0009 GETMBR R2 R0 K0 + 0x880C0300, // 000A GETMBR R3 R1 K0 + 0x24080403, // 000B GT R2 R2 R3 + 0x780A0000, // 000C JMPF R2 #000E + 0x80060200, // 000D RET 1 K1 + 0x88080100, // 000E GETMBR R2 R0 K0 + 0x880C0300, // 000F GETMBR R3 R1 K0 + 0x1C080403, // 0010 EQ R2 R2 R3 + 0x780A0004, // 0011 JMPF R2 #0017 + 0x88080102, // 0012 GETMBR R2 R0 K2 + 0x880C0302, // 0013 GETMBR R3 R1 K2 + 0x24080403, // 0014 GT R2 R2 R3 + 0x780A0000, // 0015 JMPF R2 #0017 + 0x80060200, // 0016 RET 1 K1 + 0x88080102, // 0017 GETMBR R2 R0 K2 + 0x540DFFFE, // 0018 LDINT R3 -1 + 0x1C080403, // 0019 EQ R2 R2 R3 + 0x780A0005, // 001A JMPF R2 #0021 + 0x88080302, // 001B GETMBR R2 R1 K2 + 0x4C0C0000, // 001C LDNIL R3 + 0x1C080403, // 001D EQ R2 R2 R3 + 0x780A0000, // 001E JMPF R2 #0020 + 0x80060200, // 001F RET 1 K1 + 0x70020008, // 0020 JMP #002A + 0x88080102, // 0021 GETMBR R2 R0 K2 + 0x4C0C0000, // 0022 LDNIL R3 + 0x1C080403, // 0023 EQ R2 R2 R3 + 0x780A0004, // 0024 JMPF R2 #002A + 0x88080302, // 0025 GETMBR R2 R1 K2 + 0x540DFFFE, // 0026 LDINT R3 -1 + 0x1C080403, // 0027 EQ R2 R2 R3 + 0x780A0000, // 0028 JMPF R2 #002A + 0x80060600, // 0029 RET 1 K3 + 0x88080104, // 002A GETMBR R2 R0 K4 + 0x4C0C0000, // 002B LDNIL R3 + 0x20080403, // 002C NE R2 R2 R3 + 0x780A000A, // 002D JMPF R2 #0039 + 0x88080304, // 002E GETMBR R2 R1 K4 + 0x4C0C0000, // 002F LDNIL R3 + 0x1C080403, // 0030 EQ R2 R2 R3 + 0x780A0000, // 0031 JMPF R2 #0033 + 0x80060200, // 0032 RET 1 K1 + 0x88080104, // 0033 GETMBR R2 R0 K4 + 0x880C0304, // 0034 GETMBR R3 R1 K4 + 0x24080403, // 0035 GT R2 R2 R3 + 0x780A0000, // 0036 JMPF R2 #0038 + 0x80060200, // 0037 RET 1 K1 + 0x80060600, // 0038 RET 1 K3 + 0x88080105, // 0039 GETMBR R2 R0 K5 + 0x4C0C0000, // 003A LDNIL R3 + 0x20080403, // 003B NE R2 R2 R3 + 0x780A0009, // 003C JMPF R2 #0047 + 0x88080305, // 003D GETMBR R2 R1 K5 + 0x4C0C0000, // 003E LDNIL R3 + 0x1C080403, // 003F EQ R2 R2 R3 + 0x780A0000, // 0040 JMPF R2 #0042 + 0x80060200, // 0041 RET 1 K1 + 0x88080105, // 0042 GETMBR R2 R0 K5 + 0x880C0305, // 0043 GETMBR R3 R1 K5 + 0x24080403, // 0044 GT R2 R2 R3 + 0x780A0000, // 0045 JMPF R2 #0047 + 0x80060200, // 0046 RET 1 K1 + 0x80060600, // 0047 RET 1 K3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: sort +********************************************************************/ +be_local_closure(Matter_TLV_item_sort, /* name */ + be_nested_proto( + 9, /* nstack */ + 1, /* argc */ + 4, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_const_class(be_class_Matter_TLV_item), + /* K1 */ be_const_int(1), + /* K2 */ be_const_int(0), + /* K3 */ be_nested_str_weak(_cmp_gt), + /* K4 */ be_nested_str_weak(stop_iteration), + }), + be_str_weak(sort), + &be_const_str_solidified, + ( &(const binstruction[33]) { /* code */ + 0x58040000, // 0000 LDCONST R1 K0 + 0x60080010, // 0001 GETGBL R2 G16 + 0x600C000C, // 0002 GETGBL R3 G12 + 0x5C100000, // 0003 MOVE R4 R0 + 0x7C0C0200, // 0004 CALL R3 1 + 0x040C0701, // 0005 SUB R3 R3 K1 + 0x400E0203, // 0006 CONNECT R3 K1 R3 + 0x7C080200, // 0007 CALL R2 1 + 0xA8020013, // 0008 EXBLK 0 #001D + 0x5C0C0400, // 0009 MOVE R3 R2 + 0x7C0C0000, // 000A CALL R3 0 + 0x94100003, // 000B GETIDX R4 R0 R3 + 0x5C140600, // 000C MOVE R5 R3 + 0x24180B02, // 000D GT R6 R5 K2 + 0x781A000B, // 000E JMPF R6 #001B + 0x04180B01, // 000F SUB R6 R5 K1 + 0x94180006, // 0010 GETIDX R6 R0 R6 + 0x8C180D03, // 0011 GETMET R6 R6 K3 + 0x5C200800, // 0012 MOVE R8 R4 + 0x7C180400, // 0013 CALL R6 2 + 0x24180D02, // 0014 GT R6 R6 K2 + 0x781A0004, // 0015 JMPF R6 #001B + 0x04180B01, // 0016 SUB R6 R5 K1 + 0x94180006, // 0017 GETIDX R6 R0 R6 + 0x98000A06, // 0018 SETIDX R0 R5 R6 + 0x04140B01, // 0019 SUB R5 R5 K1 + 0x7001FFF1, // 001A JMP #000D + 0x98000A04, // 001B SETIDX R0 R5 R4 + 0x7001FFEB, // 001C JMP #0009 + 0x58080004, // 001D LDCONST R2 K4 + 0xAC080200, // 001E CATCH R2 1 0 + 0xB0080000, // 001F RAISE 2 R0 R0 + 0x80040000, // 0020 RET 1 R0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_anonymoustag +********************************************************************/ +be_local_closure(Matter_TLV_item_set_anonymoustag, /* name */ + be_nested_proto( + 3, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(set_fulltag), + }), + be_str_weak(set_anonymoustag), + &be_const_str_solidified, + ( &(const binstruction[ 3]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x7C040200, // 0001 CALL R1 1 + 0x80000000, // 0002 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_contextspecific +********************************************************************/ +be_local_closure(Matter_TLV_item_set_contextspecific, /* name */ + be_nested_proto( + 4, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(set_fulltag), + /* K1 */ be_nested_str_weak(tag_sub), + }), + be_str_weak(set_contextspecific), + &be_const_str_solidified, + ( &(const binstruction[ 7]) { /* code */ + 0x8C080100, // 0000 GETMET R2 R0 K0 + 0x7C080200, // 0001 CALL R2 1 + 0x60080009, // 0002 GETGBL R2 G9 + 0x5C0C0200, // 0003 MOVE R3 R1 + 0x7C080200, // 0004 CALL R2 1 + 0x90020202, // 0005 SETMBR R0 K1 R2 + 0x80000000, // 0006 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_TLV_item +********************************************************************/ +be_local_class(Matter_TLV_item, + 8, + NULL, + be_nested_map(23, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(set_commonprofile, -1), be_const_closure(Matter_TLV_item_set_commonprofile_closure) }, + { be_const_key_weak(set_parent, -1), be_const_closure(Matter_TLV_item_set_parent_closure) }, + { be_const_key_weak(tag_profile, 3), be_const_var(3) }, + { be_const_key_weak(set_anonymoustag, 8), be_const_closure(Matter_TLV_item_set_anonymoustag_closure) }, + { be_const_key_weak(create_TLV, -1), be_const_static_closure(Matter_TLV_item_create_TLV_closure) }, + { be_const_key_weak(_encode_tag, -1), be_const_closure(Matter_TLV_item__encode_tag_closure) }, + { be_const_key_weak(val, -1), be_const_var(7) }, + { be_const_key_weak(TLV, 20), be_const_class(be_class_Matter_TLV) }, + { be_const_key_weak(tag_vendor, 1), be_const_var(2) }, + { be_const_key_weak(tostring, -1), be_const_closure(Matter_TLV_item_tostring_closure) }, + { be_const_key_weak(parse, -1), be_const_closure(Matter_TLV_item_parse_closure) }, + { be_const_key_weak(tag_number, -1), be_const_var(4) }, + { be_const_key_weak(sort, -1), be_const_static_closure(Matter_TLV_item_sort_closure) }, + { be_const_key_weak(next_idx, -1), be_const_var(1) }, + { be_const_key_weak(init, -1), be_const_closure(Matter_TLV_item_init_closure) }, + { be_const_key_weak(_cmp_gt, -1), be_const_closure(Matter_TLV_item__cmp_gt_closure) }, + { be_const_key_weak(encode, 12), be_const_closure(Matter_TLV_item_encode_closure) }, + { be_const_key_weak(typ, -1), be_const_var(6) }, + { be_const_key_weak(parent, -1), be_const_var(0) }, + { be_const_key_weak(to_TLV, 6), be_const_closure(Matter_TLV_item_to_TLV_closure) }, + { be_const_key_weak(set_fulltag, -1), be_const_closure(Matter_TLV_item_set_fulltag_closure) }, + { be_const_key_weak(tag_sub, 2), be_const_var(5) }, + { be_const_key_weak(set_contextspecific, -1), be_const_closure(Matter_TLV_item_set_contextspecific_closure) }, + })), + be_str_weak(Matter_TLV_item) +); +/*******************************************************************/ + +void be_load_Matter_TLV_item_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_TLV_item); + be_setglobal(vm, "Matter_TLV_item"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_TLV_list; + +/******************************************************************** +** Solidified function: add_struct +********************************************************************/ +be_local_closure(Matter_TLV_list_add_struct, /* name */ + be_nested_proto( + 6, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(TLV), + /* K1 */ be_nested_str_weak(Matter_TLV_struct), + /* K2 */ be_nested_str_weak(tag_sub), + /* K3 */ be_nested_str_weak(val), + /* K4 */ be_nested_str_weak(push), + }), + be_str_weak(add_struct), + &be_const_str_solidified, + ( &(const binstruction[10]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x5C100000, // 0002 MOVE R4 R0 + 0x7C080400, // 0003 CALL R2 2 + 0x900A0401, // 0004 SETMBR R2 K2 R1 + 0x880C0103, // 0005 GETMBR R3 R0 K3 + 0x8C0C0704, // 0006 GETMET R3 R3 K4 + 0x5C140400, // 0007 MOVE R5 R2 + 0x7C0C0400, // 0008 CALL R3 2 + 0x80040400, // 0009 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: _encode_inner +********************************************************************/ +be_local_closure(Matter_TLV_list__encode_inner, /* name */ + be_nested_proto( + 9, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[10]) { /* constants */ + /* K0 */ be_nested_str_weak(_encode_tag), + /* K1 */ be_nested_str_weak(val), + /* K2 */ be_nested_str_weak(copy), + /* K3 */ be_nested_str_weak(sort), + /* K4 */ be_nested_str_weak(encode), + /* K5 */ be_nested_str_weak(stop_iteration), + /* K6 */ be_nested_str_weak(add), + /* K7 */ be_nested_str_weak(TLV), + /* K8 */ be_nested_str_weak(EOC), + /* K9 */ be_const_int(1), + }), + be_str_weak(_encode_inner), + &be_const_str_solidified, + ( &(const binstruction[35]) { /* code */ + 0x4C0C0000, // 0000 LDNIL R3 + 0x1C0C0203, // 0001 EQ R3 R1 R3 + 0x780E0002, // 0002 JMPF R3 #0006 + 0x600C0015, // 0003 GETGBL R3 G21 + 0x7C0C0000, // 0004 CALL R3 0 + 0x5C040600, // 0005 MOVE R1 R3 + 0x8C0C0100, // 0006 GETMET R3 R0 K0 + 0x5C140200, // 0007 MOVE R5 R1 + 0x7C0C0400, // 0008 CALL R3 2 + 0x880C0101, // 0009 GETMBR R3 R0 K1 + 0x8C0C0702, // 000A GETMET R3 R3 K2 + 0x7C0C0200, // 000B CALL R3 1 + 0x780A0002, // 000C JMPF R2 #0010 + 0x8C100103, // 000D GETMET R4 R0 K3 + 0x5C180600, // 000E MOVE R6 R3 + 0x7C100400, // 000F CALL R4 2 + 0x60100010, // 0010 GETGBL R4 G16 + 0x5C140600, // 0011 MOVE R5 R3 + 0x7C100200, // 0012 CALL R4 1 + 0xA8020005, // 0013 EXBLK 0 #001A + 0x5C140800, // 0014 MOVE R5 R4 + 0x7C140000, // 0015 CALL R5 0 + 0x8C180B04, // 0016 GETMET R6 R5 K4 + 0x5C200200, // 0017 MOVE R8 R1 + 0x7C180400, // 0018 CALL R6 2 + 0x7001FFF9, // 0019 JMP #0014 + 0x58100005, // 001A LDCONST R4 K5 + 0xAC100200, // 001B CATCH R4 1 0 + 0xB0080000, // 001C RAISE 2 R0 R0 + 0x8C100306, // 001D GETMET R4 R1 K6 + 0x88180107, // 001E GETMBR R6 R0 K7 + 0x88180D08, // 001F GETMBR R6 R6 K8 + 0x581C0009, // 0020 LDCONST R7 K9 + 0x7C100600, // 0021 CALL R4 3 + 0x80040200, // 0022 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: add_array +********************************************************************/ +be_local_closure(Matter_TLV_list_add_array, /* name */ + be_nested_proto( + 6, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(TLV), + /* K1 */ be_nested_str_weak(Matter_TLV_array), + /* K2 */ be_nested_str_weak(tag_sub), + /* K3 */ be_nested_str_weak(val), + /* K4 */ be_nested_str_weak(push), + }), + be_str_weak(add_array), + &be_const_str_solidified, + ( &(const binstruction[10]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x5C100000, // 0002 MOVE R4 R0 + 0x7C080400, // 0003 CALL R2 2 + 0x900A0401, // 0004 SETMBR R2 K2 R1 + 0x880C0103, // 0005 GETMBR R3 R0 K3 + 0x8C0C0704, // 0006 GETMET R3 R3 K4 + 0x5C140400, // 0007 MOVE R5 R2 + 0x7C0C0400, // 0008 CALL R3 2 + 0x80040400, // 0009 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_TLV_list_init, /* name */ + be_nested_proto( + 5, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(init), + /* K1 */ be_nested_str_weak(typ), + /* K2 */ be_nested_str_weak(TLV), + /* K3 */ be_nested_str_weak(LIST), + /* K4 */ be_nested_str_weak(val), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[13]) { /* code */ + 0x60080003, // 0000 GETGBL R2 G3 + 0x5C0C0000, // 0001 MOVE R3 R0 + 0x7C080200, // 0002 CALL R2 1 + 0x8C080500, // 0003 GETMET R2 R2 K0 + 0x5C100200, // 0004 MOVE R4 R1 + 0x7C080400, // 0005 CALL R2 2 + 0x88080102, // 0006 GETMBR R2 R0 K2 + 0x88080503, // 0007 GETMBR R2 R2 K3 + 0x90020202, // 0008 SETMBR R0 K1 R2 + 0x60080012, // 0009 GETGBL R2 G18 + 0x7C080000, // 000A CALL R2 0 + 0x90020802, // 000B SETMBR R0 K4 R2 + 0x80000000, // 000C RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: size +********************************************************************/ +be_local_closure(Matter_TLV_list_size, /* name */ + be_nested_proto( + 3, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(val), + }), + be_str_weak(size), + &be_const_str_solidified, + ( &(const binstruction[ 4]) { /* code */ + 0x6004000C, // 0000 GETGBL R1 G12 + 0x88080100, // 0001 GETMBR R2 R0 K0 + 0x7C040200, // 0002 CALL R1 1 + 0x80040200, // 0003 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: add_list +********************************************************************/ +be_local_closure(Matter_TLV_list_add_list, /* name */ + be_nested_proto( + 6, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(TLV), + /* K1 */ be_nested_str_weak(Matter_TLV_list), + /* K2 */ be_nested_str_weak(tag_sub), + /* K3 */ be_nested_str_weak(val), + /* K4 */ be_nested_str_weak(push), + }), + be_str_weak(add_list), + &be_const_str_solidified, + ( &(const binstruction[10]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x5C100000, // 0002 MOVE R4 R0 + 0x7C080400, // 0003 CALL R2 2 + 0x900A0401, // 0004 SETMBR R2 K2 R1 + 0x880C0103, // 0005 GETMBR R3 R0 K3 + 0x8C0C0704, // 0006 GETMET R3 R3 K4 + 0x5C140400, // 0007 MOVE R5 R2 + 0x7C0C0400, // 0008 CALL R3 2 + 0x80040400, // 0009 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: item +********************************************************************/ +be_local_closure(Matter_TLV_list_item, /* name */ + be_nested_proto( + 3, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(val), + }), + be_str_weak(item), + &be_const_str_solidified, + ( &(const binstruction[ 3]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x94080401, // 0001 GETIDX R2 R2 R1 + 0x80040400, // 0002 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: tostring +********************************************************************/ +be_local_closure(Matter_TLV_list_tostring, /* name */ + be_nested_proto( + 6, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(tostring_inner), + /* K1 */ be_nested_str_weak(_X5B_X5B), + /* K2 */ be_nested_str_weak(_X5D_X5D), + }), + be_str_weak(tostring), + &be_const_str_solidified, + ( &(const binstruction[ 6]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x500C0000, // 0001 LDBOOL R3 0 0 + 0x58100001, // 0002 LDCONST R4 K1 + 0x58140002, // 0003 LDCONST R5 K2 + 0x7C040800, // 0004 CALL R1 4 + 0x80040200, // 0005 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: findsub +********************************************************************/ +be_local_closure(Matter_TLV_list_findsub, /* name */ + be_nested_proto( + 6, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(val), + /* K1 */ be_nested_str_weak(tag_sub), + /* K2 */ be_nested_str_weak(stop_iteration), + }), + be_str_weak(findsub), + &be_const_str_solidified, + ( &(const binstruction[16]) { /* code */ + 0x600C0010, // 0000 GETGBL R3 G16 + 0x88100100, // 0001 GETMBR R4 R0 K0 + 0x7C0C0200, // 0002 CALL R3 1 + 0xA8020007, // 0003 EXBLK 0 #000C + 0x5C100600, // 0004 MOVE R4 R3 + 0x7C100000, // 0005 CALL R4 0 + 0x88140901, // 0006 GETMBR R5 R4 K1 + 0x1C140A01, // 0007 EQ R5 R5 R1 + 0x78160001, // 0008 JMPF R5 #000B + 0xA8040001, // 0009 EXBLK 1 1 + 0x80040800, // 000A RET 1 R4 + 0x7001FFF7, // 000B JMP #0004 + 0x580C0002, // 000C LDCONST R3 K2 + 0xAC0C0200, // 000D CATCH R3 1 0 + 0xB0080000, // 000E RAISE 2 R0 R0 + 0x80040400, // 000F RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: findsubtyp +********************************************************************/ +be_local_closure(Matter_TLV_list_findsubtyp, /* name */ + be_nested_proto( + 5, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(findsub), + /* K1 */ be_nested_str_weak(typ), + }), + be_str_weak(findsubtyp), + &be_const_str_solidified, + ( &(const binstruction[10]) { /* code */ + 0x8C080100, // 0000 GETMET R2 R0 K0 + 0x5C100200, // 0001 MOVE R4 R1 + 0x7C080400, // 0002 CALL R2 2 + 0x4C0C0000, // 0003 LDNIL R3 + 0x200C0403, // 0004 NE R3 R2 R3 + 0x780E0001, // 0005 JMPF R3 #0008 + 0x880C0501, // 0006 GETMBR R3 R2 K1 + 0x80040600, // 0007 RET 1 R3 + 0x4C0C0000, // 0008 LDNIL R3 + 0x80040600, // 0009 RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: tostring_inner +********************************************************************/ +be_local_closure(Matter_TLV_list_tostring_inner, /* name */ + be_nested_proto( + 10, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[20]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(), + /* K2 */ be_nested_str_weak(tag_profile), + /* K3 */ be_nested_str_weak(Matter_X3A_X3A), + /* K4 */ be_nested_str_weak(tag_number), + /* K5 */ be_nested_str_weak(format), + /* K6 */ be_nested_str_weak(0x_X2508X_X20), + /* K7 */ be_nested_str_weak(tag_vendor), + /* K8 */ be_nested_str_weak(0x_X2504X_X3A_X3A), + /* K9 */ be_nested_str_weak(0x_X2504X_X3A), + /* K10 */ be_nested_str_weak(tag_sub), + /* K11 */ be_nested_str_weak(_X25i_X20), + /* K12 */ be_const_int(0), + /* K13 */ be_nested_str_weak(_X3D_X20), + /* K14 */ be_nested_str_weak(val), + /* K15 */ be_nested_str_weak(copy), + /* K16 */ be_nested_str_weak(sort), + /* K17 */ be_nested_str_weak(concat), + /* K18 */ be_nested_str_weak(_X2C_X20), + /* K19 */ be_nested_str_weak(_X20), + }), + be_str_weak(tostring_inner), + &be_const_str_solidified, + ( &(const binstruction[83]) { /* code */ + 0xA4120000, // 0000 IMPORT R4 K0 + 0x58140001, // 0001 LDCONST R5 K1 + 0xA8020047, // 0002 EXBLK 0 #004B + 0x88180102, // 0003 GETMBR R6 R0 K2 + 0x541DFFFE, // 0004 LDINT R7 -1 + 0x1C180C07, // 0005 EQ R6 R6 R7 + 0x781A000A, // 0006 JMPF R6 #0012 + 0x00140B03, // 0007 ADD R5 R5 K3 + 0x88180104, // 0008 GETMBR R6 R0 K4 + 0x4C1C0000, // 0009 LDNIL R7 + 0x20180C07, // 000A NE R6 R6 R7 + 0x781A0004, // 000B JMPF R6 #0011 + 0x8C180905, // 000C GETMET R6 R4 K5 + 0x58200006, // 000D LDCONST R8 K6 + 0x88240104, // 000E GETMBR R9 R0 K4 + 0x7C180600, // 000F CALL R6 3 + 0x00140A06, // 0010 ADD R5 R5 R6 + 0x70020023, // 0011 JMP #0036 + 0x88180107, // 0012 GETMBR R6 R0 K7 + 0x4C1C0000, // 0013 LDNIL R7 + 0x20180C07, // 0014 NE R6 R6 R7 + 0x781A0004, // 0015 JMPF R6 #001B + 0x8C180905, // 0016 GETMET R6 R4 K5 + 0x58200008, // 0017 LDCONST R8 K8 + 0x88240107, // 0018 GETMBR R9 R0 K7 + 0x7C180600, // 0019 CALL R6 3 + 0x00140A06, // 001A ADD R5 R5 R6 + 0x88180102, // 001B GETMBR R6 R0 K2 + 0x4C1C0000, // 001C LDNIL R7 + 0x20180C07, // 001D NE R6 R6 R7 + 0x781A0004, // 001E JMPF R6 #0024 + 0x8C180905, // 001F GETMET R6 R4 K5 + 0x58200009, // 0020 LDCONST R8 K9 + 0x88240102, // 0021 GETMBR R9 R0 K2 + 0x7C180600, // 0022 CALL R6 3 + 0x00140A06, // 0023 ADD R5 R5 R6 + 0x88180104, // 0024 GETMBR R6 R0 K4 + 0x4C1C0000, // 0025 LDNIL R7 + 0x20180C07, // 0026 NE R6 R6 R7 + 0x781A0004, // 0027 JMPF R6 #002D + 0x8C180905, // 0028 GETMET R6 R4 K5 + 0x58200006, // 0029 LDCONST R8 K6 + 0x88240104, // 002A GETMBR R9 R0 K4 + 0x7C180600, // 002B CALL R6 3 + 0x00140A06, // 002C ADD R5 R5 R6 + 0x8818010A, // 002D GETMBR R6 R0 K10 + 0x4C1C0000, // 002E LDNIL R7 + 0x20180C07, // 002F NE R6 R6 R7 + 0x781A0004, // 0030 JMPF R6 #0036 + 0x8C180905, // 0031 GETMET R6 R4 K5 + 0x5820000B, // 0032 LDCONST R8 K11 + 0x8824010A, // 0033 GETMBR R9 R0 K10 + 0x7C180600, // 0034 CALL R6 3 + 0x00140A06, // 0035 ADD R5 R5 R6 + 0x6018000C, // 0036 GETGBL R6 G12 + 0x5C1C0A00, // 0037 MOVE R7 R5 + 0x7C180200, // 0038 CALL R6 1 + 0x24180D0C, // 0039 GT R6 R6 K12 + 0x781A0000, // 003A JMPF R6 #003C + 0x00140B0D, // 003B ADD R5 R5 K13 + 0x00140A02, // 003C ADD R5 R5 R2 + 0x8818010E, // 003D GETMBR R6 R0 K14 + 0x8C180D0F, // 003E GETMET R6 R6 K15 + 0x7C180200, // 003F CALL R6 1 + 0x78060002, // 0040 JMPF R1 #0044 + 0x8C1C0110, // 0041 GETMET R7 R0 K16 + 0x5C240C00, // 0042 MOVE R9 R6 + 0x7C1C0400, // 0043 CALL R7 2 + 0x8C1C0D11, // 0044 GETMET R7 R6 K17 + 0x58240012, // 0045 LDCONST R9 K18 + 0x7C1C0400, // 0046 CALL R7 2 + 0x00140A07, // 0047 ADD R5 R5 R7 + 0x00140A03, // 0048 ADD R5 R5 R3 + 0xA8040001, // 0049 EXBLK 1 1 + 0x70020006, // 004A JMP #0052 + 0xAC180002, // 004B CATCH R6 0 2 + 0x70020003, // 004C JMP #0051 + 0x00200D13, // 004D ADD R8 R6 K19 + 0x00201007, // 004E ADD R8 R8 R7 + 0x80041000, // 004F RET 1 R8 + 0x70020000, // 0050 JMP #0052 + 0xB0080000, // 0051 RAISE 2 R0 R0 + 0x80040A00, // 0052 RET 1 R5 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: findsubval +********************************************************************/ +be_local_closure(Matter_TLV_list_findsubval, /* name */ + be_nested_proto( + 6, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(findsub), + /* K1 */ be_nested_str_weak(val), + }), + be_str_weak(findsubval), + &be_const_str_solidified, + ( &(const binstruction[ 9]) { /* code */ + 0x8C0C0100, // 0000 GETMET R3 R0 K0 + 0x5C140200, // 0001 MOVE R5 R1 + 0x7C0C0400, // 0002 CALL R3 2 + 0x4C100000, // 0003 LDNIL R4 + 0x20100604, // 0004 NE R4 R3 R4 + 0x78120001, // 0005 JMPF R4 #0008 + 0x88100701, // 0006 GETMBR R4 R3 K1 + 0x80040800, // 0007 RET 1 R4 + 0x80040400, // 0008 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: parse +********************************************************************/ +be_local_closure(Matter_TLV_list_parse, /* name */ + be_nested_proto( + 8, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 7]) { /* constants */ + /* K0 */ be_nested_str_weak(TLV), + /* K1 */ be_nested_str_weak(EOC), + /* K2 */ be_nested_str_weak(parse), + /* K3 */ be_nested_str_weak(next_idx), + /* K4 */ be_nested_str_weak(val), + /* K5 */ be_nested_str_weak(push), + /* K6 */ be_const_int(1), + }), + be_str_weak(parse), + &be_const_str_solidified, + ( &(const binstruction[20]) { /* code */ + 0x940C0202, // 0000 GETIDX R3 R1 R2 + 0x88100100, // 0001 GETMBR R4 R0 K0 + 0x88100901, // 0002 GETMBR R4 R4 K1 + 0x200C0604, // 0003 NE R3 R3 R4 + 0x780E000B, // 0004 JMPF R3 #0011 + 0x880C0100, // 0005 GETMBR R3 R0 K0 + 0x8C0C0702, // 0006 GETMET R3 R3 K2 + 0x5C140200, // 0007 MOVE R5 R1 + 0x5C180400, // 0008 MOVE R6 R2 + 0x5C1C0000, // 0009 MOVE R7 R0 + 0x7C0C0800, // 000A CALL R3 4 + 0x88080703, // 000B GETMBR R2 R3 K3 + 0x88100104, // 000C GETMBR R4 R0 K4 + 0x8C100905, // 000D GETMET R4 R4 K5 + 0x5C180600, // 000E MOVE R6 R3 + 0x7C100400, // 000F CALL R4 2 + 0x7001FFEE, // 0010 JMP #0000 + 0x00080506, // 0011 ADD R2 R2 K6 + 0x90020602, // 0012 SETMBR R0 K3 R2 + 0x80040400, // 0013 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: getsubval +********************************************************************/ +be_local_closure(Matter_TLV_list_getsubval, /* name */ + be_nested_proto( + 5, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(getsub), + /* K1 */ be_nested_str_weak(val), + }), + be_str_weak(getsubval), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x8C080100, // 0000 GETMET R2 R0 K0 + 0x5C100200, // 0001 MOVE R4 R1 + 0x7C080400, // 0002 CALL R2 2 + 0x88080501, // 0003 GETMBR R2 R2 K1 + 0x80040400, // 0004 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: add_obj +********************************************************************/ +be_local_closure(Matter_TLV_list_add_obj, /* name */ + be_nested_proto( + 7, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(to_TLV), + /* K1 */ be_nested_str_weak(tag_sub), + /* K2 */ be_nested_str_weak(val), + /* K3 */ be_nested_str_weak(push), + }), + be_str_weak(add_obj), + &be_const_str_solidified, + ( &(const binstruction[11]) { /* code */ + 0x4C0C0000, // 0000 LDNIL R3 + 0x200C0403, // 0001 NE R3 R2 R3 + 0x780E0006, // 0002 JMPF R3 #000A + 0x8C0C0500, // 0003 GETMET R3 R2 K0 + 0x7C0C0200, // 0004 CALL R3 1 + 0x900E0201, // 0005 SETMBR R3 K1 R1 + 0x88100102, // 0006 GETMBR R4 R0 K2 + 0x8C100903, // 0007 GETMET R4 R4 K3 + 0x5C180600, // 0008 MOVE R6 R3 + 0x7C100400, // 0009 CALL R4 2 + 0x80040000, // 000A RET 1 R0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: encode +********************************************************************/ +be_local_closure(Matter_TLV_list_encode, /* name */ + be_nested_proto( + 6, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(_encode_inner), + }), + be_str_weak(encode), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x8C080100, // 0000 GETMET R2 R0 K0 + 0x5C100200, // 0001 MOVE R4 R1 + 0x50140000, // 0002 LDBOOL R5 0 0 + 0x7C080600, // 0003 CALL R2 3 + 0x80040400, // 0004 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: setitem +********************************************************************/ +be_local_closure(Matter_TLV_list_setitem, /* name */ + be_nested_proto( + 4, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(val), + }), + be_str_weak(setitem), + &be_const_str_solidified, + ( &(const binstruction[ 3]) { /* code */ + 0x880C0100, // 0000 GETMBR R3 R0 K0 + 0x980C0202, // 0001 SETIDX R3 R1 R2 + 0x80000000, // 0002 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: push +********************************************************************/ +be_local_closure(Matter_TLV_list_push, /* name */ + be_nested_proto( + 5, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(val), + /* K1 */ be_nested_str_weak(push), + }), + be_str_weak(push), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x5C100200, // 0002 MOVE R4 R1 + 0x7C080400, // 0003 CALL R2 2 + 0x80000000, // 0004 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: add_TLV +********************************************************************/ +be_local_closure(Matter_TLV_list_add_TLV, /* name */ + be_nested_proto( + 8, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(TLV), + /* K1 */ be_nested_str_weak(Matter_TLV_item), + /* K2 */ be_nested_str_weak(tag_sub), + /* K3 */ be_nested_str_weak(typ), + /* K4 */ be_nested_str_weak(val), + /* K5 */ be_nested_str_weak(push), + }), + be_str_weak(add_TLV), + &be_const_str_solidified, + ( &(const binstruction[15]) { /* code */ + 0x4C100000, // 0000 LDNIL R4 + 0x20100604, // 0001 NE R4 R3 R4 + 0x7812000A, // 0002 JMPF R4 #000E + 0x88100100, // 0003 GETMBR R4 R0 K0 + 0x8C100901, // 0004 GETMET R4 R4 K1 + 0x5C180000, // 0005 MOVE R6 R0 + 0x7C100400, // 0006 CALL R4 2 + 0x90120401, // 0007 SETMBR R4 K2 R1 + 0x90120602, // 0008 SETMBR R4 K3 R2 + 0x90120803, // 0009 SETMBR R4 K4 R3 + 0x88140104, // 000A GETMBR R5 R0 K4 + 0x8C140B05, // 000B GETMET R5 R5 K5 + 0x5C1C0800, // 000C MOVE R7 R4 + 0x7C140400, // 000D CALL R5 2 + 0x80040000, // 000E RET 1 R0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: getsub +********************************************************************/ +be_local_closure(Matter_TLV_list_getsub, /* name */ + be_nested_proto( + 5, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(findsub), + /* K1 */ be_nested_str_weak(value_error), + /* K2 */ be_nested_str_weak(sub_X20not_X20found), + }), + be_str_weak(getsub), + &be_const_str_solidified, + ( &(const binstruction[ 8]) { /* code */ + 0x8C080100, // 0000 GETMET R2 R0 K0 + 0x5C100200, // 0001 MOVE R4 R1 + 0x7C080400, // 0002 CALL R2 2 + 0x4C0C0000, // 0003 LDNIL R3 + 0x1C0C0403, // 0004 EQ R3 R2 R3 + 0x780E0000, // 0005 JMPF R3 #0007 + 0xB0060302, // 0006 RAISE 1 K1 K2 + 0x80040400, // 0007 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_TLV_list +********************************************************************/ +extern const bclass be_class_Matter_TLV_item; +be_local_class(Matter_TLV_list, + 0, + &be_class_Matter_TLV_item, + be_nested_map(20, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(add_struct, -1), be_const_closure(Matter_TLV_list_add_struct_closure) }, + { be_const_key_weak(getsub, -1), be_const_closure(Matter_TLV_list_getsub_closure) }, + { be_const_key_weak(add_array, -1), be_const_closure(Matter_TLV_list_add_array_closure) }, + { be_const_key_weak(add_TLV, -1), be_const_closure(Matter_TLV_list_add_TLV_closure) }, + { be_const_key_weak(size, -1), be_const_closure(Matter_TLV_list_size_closure) }, + { be_const_key_weak(add_list, 18), be_const_closure(Matter_TLV_list_add_list_closure) }, + { be_const_key_weak(item, 13), be_const_closure(Matter_TLV_list_item_closure) }, + { be_const_key_weak(findsubval, -1), be_const_closure(Matter_TLV_list_findsubval_closure) }, + { be_const_key_weak(parse, -1), be_const_closure(Matter_TLV_list_parse_closure) }, + { be_const_key_weak(findsubtyp, 3), be_const_closure(Matter_TLV_list_findsubtyp_closure) }, + { be_const_key_weak(tostring_inner, -1), be_const_closure(Matter_TLV_list_tostring_inner_closure) }, + { be_const_key_weak(encode, 7), be_const_closure(Matter_TLV_list_encode_closure) }, + { be_const_key_weak(findsub, 8), be_const_closure(Matter_TLV_list_findsub_closure) }, + { be_const_key_weak(getsubval, -1), be_const_closure(Matter_TLV_list_getsubval_closure) }, + { be_const_key_weak(add_obj, -1), be_const_closure(Matter_TLV_list_add_obj_closure) }, + { be_const_key_weak(init, 11), be_const_closure(Matter_TLV_list_init_closure) }, + { be_const_key_weak(setitem, -1), be_const_closure(Matter_TLV_list_setitem_closure) }, + { be_const_key_weak(push, -1), be_const_closure(Matter_TLV_list_push_closure) }, + { be_const_key_weak(tostring, -1), be_const_closure(Matter_TLV_list_tostring_closure) }, + { be_const_key_weak(_encode_inner, 1), be_const_closure(Matter_TLV_list__encode_inner_closure) }, + })), + be_str_weak(Matter_TLV_list) +); +/*******************************************************************/ + +void be_load_Matter_TLV_list_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_TLV_list); + be_setglobal(vm, "Matter_TLV_list"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_TLV_struct; + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_TLV_struct_init, /* name */ + be_nested_proto( + 5, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(init), + /* K1 */ be_nested_str_weak(typ), + /* K2 */ be_nested_str_weak(TLV), + /* K3 */ be_nested_str_weak(STRUCT), + /* K4 */ be_nested_str_weak(val), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[13]) { /* code */ + 0x60080003, // 0000 GETGBL R2 G3 + 0x5C0C0000, // 0001 MOVE R3 R0 + 0x7C080200, // 0002 CALL R2 1 + 0x8C080500, // 0003 GETMET R2 R2 K0 + 0x5C100200, // 0004 MOVE R4 R1 + 0x7C080400, // 0005 CALL R2 2 + 0x88080102, // 0006 GETMBR R2 R0 K2 + 0x88080503, // 0007 GETMBR R2 R2 K3 + 0x90020202, // 0008 SETMBR R0 K1 R2 + 0x60080012, // 0009 GETGBL R2 G18 + 0x7C080000, // 000A CALL R2 0 + 0x90020802, // 000B SETMBR R0 K4 R2 + 0x80000000, // 000C RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: tostring +********************************************************************/ +be_local_closure(Matter_TLV_struct_tostring, /* name */ + be_nested_proto( + 6, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(tostring_inner), + /* K1 */ be_nested_str_weak(_X7B), + /* K2 */ be_nested_str_weak(_X7D), + }), + be_str_weak(tostring), + &be_const_str_solidified, + ( &(const binstruction[ 6]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x500C0200, // 0001 LDBOOL R3 1 0 + 0x58100001, // 0002 LDCONST R4 K1 + 0x58140002, // 0003 LDCONST R5 K2 + 0x7C040800, // 0004 CALL R1 4 + 0x80040200, // 0005 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: encode +********************************************************************/ +be_local_closure(Matter_TLV_struct_encode, /* name */ + be_nested_proto( + 6, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(_encode_inner), + }), + be_str_weak(encode), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x8C080100, // 0000 GETMET R2 R0 K0 + 0x5C100200, // 0001 MOVE R4 R1 + 0x50140200, // 0002 LDBOOL R5 1 0 + 0x7C080600, // 0003 CALL R2 3 + 0x80040400, // 0004 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_TLV_struct +********************************************************************/ +extern const bclass be_class_Matter_TLV_list; +be_local_class(Matter_TLV_struct, + 0, + &be_class_Matter_TLV_list, + be_nested_map(3, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(init, -1), be_const_closure(Matter_TLV_struct_init_closure) }, + { be_const_key_weak(tostring, -1), be_const_closure(Matter_TLV_struct_tostring_closure) }, + { be_const_key_weak(encode, -1), be_const_closure(Matter_TLV_struct_encode_closure) }, + })), + be_str_weak(Matter_TLV_struct) +); +/*******************************************************************/ + +void be_load_Matter_TLV_struct_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_TLV_struct); + be_setglobal(vm, "Matter_TLV_struct"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_TLV_array; + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_TLV_array_init, /* name */ + be_nested_proto( + 5, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(init), + /* K1 */ be_nested_str_weak(typ), + /* K2 */ be_nested_str_weak(TLV), + /* K3 */ be_nested_str_weak(ARRAY), + /* K4 */ be_nested_str_weak(val), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[13]) { /* code */ + 0x60080003, // 0000 GETGBL R2 G3 + 0x5C0C0000, // 0001 MOVE R3 R0 + 0x7C080200, // 0002 CALL R2 1 + 0x8C080500, // 0003 GETMET R2 R2 K0 + 0x5C100200, // 0004 MOVE R4 R1 + 0x7C080400, // 0005 CALL R2 2 + 0x88080102, // 0006 GETMBR R2 R0 K2 + 0x88080503, // 0007 GETMBR R2 R2 K3 + 0x90020202, // 0008 SETMBR R0 K1 R2 + 0x60080012, // 0009 GETGBL R2 G18 + 0x7C080000, // 000A CALL R2 0 + 0x90020802, // 000B SETMBR R0 K4 R2 + 0x80000000, // 000C RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: parse +********************************************************************/ +be_local_closure(Matter_TLV_array_parse, /* name */ + be_nested_proto( + 8, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[11]) { /* constants */ + /* K0 */ be_nested_str_weak(TLV), + /* K1 */ be_nested_str_weak(EOC), + /* K2 */ be_nested_str_weak(parse), + /* K3 */ be_nested_str_weak(next_idx), + /* K4 */ be_nested_str_weak(tag_vendor), + /* K5 */ be_nested_str_weak(tag_profile), + /* K6 */ be_nested_str_weak(tag_number), + /* K7 */ be_nested_str_weak(tag_sub), + /* K8 */ be_nested_str_weak(val), + /* K9 */ be_nested_str_weak(push), + /* K10 */ be_const_int(1), + }), + be_str_weak(parse), + &be_const_str_solidified, + ( &(const binstruction[28]) { /* code */ + 0x940C0202, // 0000 GETIDX R3 R1 R2 + 0x88100100, // 0001 GETMBR R4 R0 K0 + 0x88100901, // 0002 GETMBR R4 R4 K1 + 0x200C0604, // 0003 NE R3 R3 R4 + 0x780E0013, // 0004 JMPF R3 #0019 + 0x880C0100, // 0005 GETMBR R3 R0 K0 + 0x8C0C0702, // 0006 GETMET R3 R3 K2 + 0x5C140200, // 0007 MOVE R5 R1 + 0x5C180400, // 0008 MOVE R6 R2 + 0x5C1C0000, // 0009 MOVE R7 R0 + 0x7C0C0800, // 000A CALL R3 4 + 0x88080703, // 000B GETMBR R2 R3 K3 + 0x4C100000, // 000C LDNIL R4 + 0x900E0804, // 000D SETMBR R3 K4 R4 + 0x4C100000, // 000E LDNIL R4 + 0x900E0A04, // 000F SETMBR R3 K5 R4 + 0x4C100000, // 0010 LDNIL R4 + 0x900E0C04, // 0011 SETMBR R3 K6 R4 + 0x4C100000, // 0012 LDNIL R4 + 0x900E0E04, // 0013 SETMBR R3 K7 R4 + 0x88100108, // 0014 GETMBR R4 R0 K8 + 0x8C100909, // 0015 GETMET R4 R4 K9 + 0x5C180600, // 0016 MOVE R6 R3 + 0x7C100400, // 0017 CALL R4 2 + 0x7001FFE6, // 0018 JMP #0000 + 0x0008050A, // 0019 ADD R2 R2 K10 + 0x90020602, // 001A SETMBR R0 K3 R2 + 0x80040400, // 001B RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: tostring +********************************************************************/ +be_local_closure(Matter_TLV_array_tostring, /* name */ + be_nested_proto( + 6, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(tostring_inner), + /* K1 */ be_nested_str_weak(_X5B), + /* K2 */ be_nested_str_weak(_X5D), + }), + be_str_weak(tostring), + &be_const_str_solidified, + ( &(const binstruction[ 6]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x500C0000, // 0001 LDBOOL R3 0 0 + 0x58100001, // 0002 LDCONST R4 K1 + 0x58140002, // 0003 LDCONST R5 K2 + 0x7C040800, // 0004 CALL R1 4 + 0x80040200, // 0005 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_TLV_array +********************************************************************/ +extern const bclass be_class_Matter_TLV_list; +be_local_class(Matter_TLV_array, + 0, + &be_class_Matter_TLV_list, + be_nested_map(3, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(init, -1), be_const_closure(Matter_TLV_array_init_closure) }, + { be_const_key_weak(parse, 2), be_const_closure(Matter_TLV_array_parse_closure) }, + { be_const_key_weak(tostring, -1), be_const_closure(Matter_TLV_array_tostring_closure) }, + })), + be_str_weak(Matter_TLV_array) +); +/*******************************************************************/ + +void be_load_Matter_TLV_array_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_TLV_array); + be_setglobal(vm, "Matter_TLV_array"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_TLV; + +/******************************************************************** +** Solidified function: create_TLV +********************************************************************/ +be_local_closure(Matter_TLV_create_TLV, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 4, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_const_class(be_class_Matter_TLV), + /* K1 */ be_nested_str_weak(Matter_TLV_item), + /* K2 */ be_nested_str_weak(create_TLV), + }), + be_str_weak(create_TLV), + &be_const_str_solidified, + ( &(const binstruction[ 7]) { /* code */ + 0x58080000, // 0000 LDCONST R2 K0 + 0x880C0501, // 0001 GETMBR R3 R2 K1 + 0x8C0C0702, // 0002 GETMET R3 R3 K2 + 0x5C140000, // 0003 MOVE R5 R0 + 0x5C180200, // 0004 MOVE R6 R1 + 0x7C0C0600, // 0005 CALL R3 3 + 0x80040600, // 0006 RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: parse +********************************************************************/ +be_local_closure(Matter_TLV_parse, /* name */ + be_nested_proto( + 12, /* nstack */ + 3, /* argc */ + 4, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[21]) { /* constants */ + /* K0 */ be_const_class(be_class_Matter_TLV), + /* K1 */ be_const_int(0), + /* K2 */ be_const_int(1), + /* K3 */ be_nested_str_weak(EOC), + /* K4 */ be_nested_str_weak(invalid_X20TLV_X20type_X20), + /* K5 */ be_nested_str_weak(TLV_error), + /* K6 */ be_nested_str_weak(STRUCT), + /* K7 */ be_nested_str_weak(Matter_TLV_struct), + /* K8 */ be_nested_str_weak(ARRAY), + /* K9 */ be_nested_str_weak(Matter_TLV_array), + /* K10 */ be_nested_str_weak(LIST), + /* K11 */ be_nested_str_weak(Matter_TLV_list), + /* K12 */ be_nested_str_weak(Matter_TLV_item), + /* K13 */ be_nested_str_weak(typ), + /* K14 */ be_nested_str_weak(tag_vendor), + /* K15 */ be_nested_str_weak(get), + /* K16 */ be_const_int(2), + /* K17 */ be_nested_str_weak(tag_profile), + /* K18 */ be_nested_str_weak(tag_sub), + /* K19 */ be_nested_str_weak(tag_number), + /* K20 */ be_nested_str_weak(parse), + }), + be_str_weak(parse), + &be_const_str_solidified, + ( &(const binstruction[118]) { /* code */ + 0x580C0000, // 0000 LDCONST R3 K0 + 0x5C100600, // 0001 MOVE R4 R3 + 0x4C140000, // 0002 LDNIL R5 + 0x1C140205, // 0003 EQ R5 R1 R5 + 0x78160000, // 0004 JMPF R5 #0006 + 0x58040001, // 0005 LDCONST R1 K1 + 0x94140001, // 0006 GETIDX R5 R0 R1 + 0x541A001E, // 0007 LDINT R6 31 + 0x2C140A06, // 0008 AND R5 R5 R6 + 0x94180001, // 0009 GETIDX R6 R0 R1 + 0x541E00DF, // 000A LDINT R7 224 + 0x2C180C07, // 000B AND R6 R6 R7 + 0x00040302, // 000C ADD R1 R1 K2 + 0x881C0903, // 000D GETMBR R7 R4 K3 + 0x241C0A07, // 000E GT R7 R5 R7 + 0x781E0004, // 000F JMPF R7 #0015 + 0x601C0008, // 0010 GETGBL R7 G8 + 0x5C200A00, // 0011 MOVE R8 R5 + 0x7C1C0200, // 0012 CALL R7 1 + 0x001E0807, // 0013 ADD R7 K4 R7 + 0xB0060A07, // 0014 RAISE 1 K5 R7 + 0x4C1C0000, // 0015 LDNIL R7 + 0x88200906, // 0016 GETMBR R8 R4 K6 + 0x1C200A08, // 0017 EQ R8 R5 R8 + 0x78220004, // 0018 JMPF R8 #001E + 0x8C200707, // 0019 GETMET R8 R3 K7 + 0x5C280400, // 001A MOVE R10 R2 + 0x7C200400, // 001B CALL R8 2 + 0x5C1C1000, // 001C MOVE R7 R8 + 0x70020013, // 001D JMP #0032 + 0x88200908, // 001E GETMBR R8 R4 K8 + 0x1C200A08, // 001F EQ R8 R5 R8 + 0x78220004, // 0020 JMPF R8 #0026 + 0x8C200709, // 0021 GETMET R8 R3 K9 + 0x5C280400, // 0022 MOVE R10 R2 + 0x7C200400, // 0023 CALL R8 2 + 0x5C1C1000, // 0024 MOVE R7 R8 + 0x7002000B, // 0025 JMP #0032 + 0x8820090A, // 0026 GETMBR R8 R4 K10 + 0x1C200A08, // 0027 EQ R8 R5 R8 + 0x78220004, // 0028 JMPF R8 #002E + 0x8C20070B, // 0029 GETMET R8 R3 K11 + 0x5C280400, // 002A MOVE R10 R2 + 0x7C200400, // 002B CALL R8 2 + 0x5C1C1000, // 002C MOVE R7 R8 + 0x70020003, // 002D JMP #0032 + 0x8C20070C, // 002E GETMET R8 R3 K12 + 0x5C280400, // 002F MOVE R10 R2 + 0x7C200400, // 0030 CALL R8 2 + 0x5C1C1000, // 0031 MOVE R7 R8 + 0x901E1A05, // 0032 SETMBR R7 K13 R5 + 0x542200BF, // 0033 LDINT R8 192 + 0x1C200C08, // 0034 EQ R8 R6 R8 + 0x74220002, // 0035 JMPT R8 #0039 + 0x542200DF, // 0036 LDINT R8 224 + 0x1C200C08, // 0037 EQ R8 R6 R8 + 0x7822000B, // 0038 JMPF R8 #0045 + 0x8C20010F, // 0039 GETMET R8 R0 K15 + 0x5C280200, // 003A MOVE R10 R1 + 0x582C0010, // 003B LDCONST R11 K16 + 0x7C200600, // 003C CALL R8 3 + 0x901E1C08, // 003D SETMBR R7 K14 R8 + 0x8C20010F, // 003E GETMET R8 R0 K15 + 0x00280310, // 003F ADD R10 R1 K16 + 0x582C0010, // 0040 LDCONST R11 K16 + 0x7C200600, // 0041 CALL R8 3 + 0x901E2208, // 0042 SETMBR R7 K17 R8 + 0x54220003, // 0043 LDINT R8 4 + 0x00040208, // 0044 ADD R1 R1 R8 + 0x5422003F, // 0045 LDINT R8 64 + 0x1C200C08, // 0046 EQ R8 R6 R8 + 0x74220002, // 0047 JMPT R8 #004B + 0x5422005F, // 0048 LDINT R8 96 + 0x1C200C08, // 0049 EQ R8 R6 R8 + 0x78220003, // 004A JMPF R8 #004F + 0x4C200000, // 004B LDNIL R8 + 0x901E1C08, // 004C SETMBR R7 K14 R8 + 0x5421FFFE, // 004D LDINT R8 -1 + 0x901E2208, // 004E SETMBR R7 K17 R8 + 0x1C200D01, // 004F EQ R8 R6 K1 + 0x78220000, // 0050 JMPF R8 #0052 + 0x7002001D, // 0051 JMP #0070 + 0x5422001F, // 0052 LDINT R8 32 + 0x1C200C08, // 0053 EQ R8 R6 R8 + 0x78220003, // 0054 JMPF R8 #0059 + 0x94200001, // 0055 GETIDX R8 R0 R1 + 0x901E2408, // 0056 SETMBR R7 K18 R8 + 0x00040302, // 0057 ADD R1 R1 K2 + 0x70020016, // 0058 JMP #0070 + 0x542200BF, // 0059 LDINT R8 192 + 0x1C200C08, // 005A EQ R8 R6 R8 + 0x74220005, // 005B JMPT R8 #0062 + 0x5422007F, // 005C LDINT R8 128 + 0x1C200C08, // 005D EQ R8 R6 R8 + 0x74220002, // 005E JMPT R8 #0062 + 0x5422003F, // 005F LDINT R8 64 + 0x1C200C08, // 0060 EQ R8 R6 R8 + 0x78220006, // 0061 JMPF R8 #0069 + 0x8C20010F, // 0062 GETMET R8 R0 K15 + 0x5C280200, // 0063 MOVE R10 R1 + 0x582C0010, // 0064 LDCONST R11 K16 + 0x7C200600, // 0065 CALL R8 3 + 0x901E2608, // 0066 SETMBR R7 K19 R8 + 0x00040310, // 0067 ADD R1 R1 K16 + 0x70020006, // 0068 JMP #0070 + 0x8C20010F, // 0069 GETMET R8 R0 K15 + 0x5C280200, // 006A MOVE R10 R1 + 0x542E0003, // 006B LDINT R11 4 + 0x7C200600, // 006C CALL R8 3 + 0x901E2608, // 006D SETMBR R7 K19 R8 + 0x54220003, // 006E LDINT R8 4 + 0x00040208, // 006F ADD R1 R1 R8 + 0x8C200F14, // 0070 GETMET R8 R7 K20 + 0x5C280000, // 0071 MOVE R10 R0 + 0x5C2C0200, // 0072 MOVE R11 R1 + 0x7C200600, // 0073 CALL R8 3 + 0x5C041000, // 0074 MOVE R1 R8 + 0x80040E00, // 0075 RET 1 R7 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_TLV +********************************************************************/ +be_local_class(Matter_TLV, + 0, + NULL, + be_nested_map(34, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(Matter_TLV_array, -1), be_const_class(be_class_Matter_TLV_array) }, + { be_const_key_weak(BTRUE, -1), be_const_int(9) }, + { be_const_key_weak(create_TLV, 11), be_const_static_closure(Matter_TLV_create_TLV_closure) }, + { be_const_key_weak(UTF1, -1), be_const_int(12) }, + { be_const_key_weak(STRUCT, 23), be_const_int(21) }, + { be_const_key_weak(Matter_TLV_item, 24), be_const_class(be_class_Matter_TLV_item) }, + { be_const_key_weak(UTF4, 20), be_const_int(14) }, + { be_const_key_weak(FLOAT, -1), be_const_int(10) }, + { be_const_key_weak(I2, -1), be_const_int(1) }, + { be_const_key_weak(BOOL, 16), be_const_int(8) }, + { be_const_key_weak(B1, -1), be_const_int(16) }, + { be_const_key_weak(Matter_TLV_list, 28), be_const_class(be_class_Matter_TLV_list) }, + { be_const_key_weak(I8, -1), be_const_int(3) }, + { be_const_key_weak(_len, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(25, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(1), + be_const_int(2), + be_const_int(4), + be_const_int(8), + be_const_int(1), + be_const_int(2), + be_const_int(4), + be_const_int(8), + be_const_int(0), + be_const_int(0), + be_const_int(4), + be_const_int(8), + be_const_int(4294967295), + be_const_int(4294967294), + be_const_int(4294967292), + be_const_int(4294967288), + be_const_int(4294967295), + be_const_int(4294967294), + be_const_int(4294967292), + be_const_int(4294967288), + be_const_int(0), + be_const_int(4294967197), + be_const_int(4294967197), + be_const_int(4294967197), + be_const_int(0), + })) ) } )) }, + { be_const_key_weak(_type, 19), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(25, + ( (struct bvalue*) &(const bvalue[]) { + be_nested_str_weak(i1), + be_nested_str_weak(i2), + be_nested_str_weak(i4), + be_nested_str_weak(i8), + be_nested_str_weak(u1), + be_nested_str_weak(u2), + be_nested_str_weak(u4), + be_nested_str_weak(u8), + be_nested_str_weak(bool), + be_nested_str_weak(bool), + be_nested_str_weak(float), + be_nested_str_weak(double), + be_nested_str_weak(UTF1), + be_nested_str_weak(UTF2), + be_nested_str_weak(UTF4), + be_nested_str_weak(UTF8), + be_nested_str_weak(b1), + be_nested_str_weak(b2), + be_nested_str_weak(b4), + be_nested_str_weak(b8), + be_nested_str_weak(null), + be_nested_str_weak(struct), + be_nested_str_weak(array), + be_nested_str_weak(list), + be_nested_str_weak(end), + })) ) } )) }, + { be_const_key_weak(B2, -1), be_const_int(17) }, + { be_const_key_weak(LIST, -1), be_const_int(23) }, + { be_const_key_weak(U1, -1), be_const_int(4) }, + { be_const_key_weak(NULL, 12), be_const_int(20) }, + { be_const_key_weak(EOC, 27), be_const_int(24) }, + { be_const_key_weak(U8, -1), be_const_int(7) }, + { be_const_key_weak(U4, -1), be_const_int(6) }, + { be_const_key_weak(UTF8, 21), be_const_int(15) }, + { be_const_key_weak(UTF2, -1), be_const_int(13) }, + { be_const_key_weak(B4, -1), be_const_int(18) }, + { be_const_key_weak(B8, -1), be_const_int(19) }, + { be_const_key_weak(DOUBLE, -1), be_const_int(11) }, + { be_const_key_weak(ARRAY, 31), be_const_int(22) }, + { be_const_key_weak(parse, -1), be_const_static_closure(Matter_TLV_parse_closure) }, + { be_const_key_weak(I1, -1), be_const_int(0) }, + { be_const_key_weak(U2, -1), be_const_int(5) }, + { be_const_key_weak(BFALSE, -1), be_const_int(8) }, + { be_const_key_weak(I4, 4), be_const_int(2) }, + { be_const_key_weak(Matter_TLV_struct, 0), be_const_class(be_class_Matter_TLV_struct) }, + })), + be_str_weak(Matter_TLV) +); +/*******************************************************************/ + +void be_load_Matter_TLV_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_TLV); + be_setglobal(vm, "Matter_TLV"); + be_pop(vm, 1); +} +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_UDPServer.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_UDPServer.h new file mode 100644 index 000000000..9cf11d294 --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_UDPServer.h @@ -0,0 +1,626 @@ +/* Solidification of Matter_UDPServer.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_UDPPacket_sent; + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_UDPPacket_sent_init, /* name */ + be_nested_proto( + 7, /* nstack */ + 5, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[10]) { /* constants */ + /* K0 */ be_nested_str_weak(raw), + /* K1 */ be_nested_str_weak(addr), + /* K2 */ be_nested_str_weak(port), + /* K3 */ be_nested_str_weak(msg_id), + /* K4 */ be_nested_str_weak(retries), + /* K5 */ be_nested_str_weak(RETRIES), + /* K6 */ be_nested_str_weak(next_try), + /* K7 */ be_nested_str_weak(tasmota), + /* K8 */ be_nested_str_weak(millis), + /* K9 */ be_nested_str_weak(RETRY_MS), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[13]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x90020202, // 0001 SETMBR R0 K1 R2 + 0x90020403, // 0002 SETMBR R0 K2 R3 + 0x90020604, // 0003 SETMBR R0 K3 R4 + 0x88140105, // 0004 GETMBR R5 R0 K5 + 0x90020805, // 0005 SETMBR R0 K4 R5 + 0xB8160E00, // 0006 GETNGBL R5 K7 + 0x8C140B08, // 0007 GETMET R5 R5 K8 + 0x7C140200, // 0008 CALL R5 1 + 0x88180109, // 0009 GETMBR R6 R0 K9 + 0x00140A06, // 000A ADD R5 R5 R6 + 0x90020C05, // 000B SETMBR R0 K6 R5 + 0x80000000, // 000C RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: send +********************************************************************/ +be_local_closure(Matter_UDPPacket_sent_send, /* name */ + be_nested_proto( + 11, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[14]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(send), + /* K2 */ be_nested_str_weak(addr), + /* K3 */ be_nested_str_weak(remote_ip), + /* K4 */ be_nested_str_weak(port), + /* K5 */ be_nested_str_weak(remote_port), + /* K6 */ be_nested_str_weak(raw), + /* K7 */ be_nested_str_weak(tasmota), + /* K8 */ be_nested_str_weak(log), + /* K9 */ be_nested_str_weak(format), + /* K10 */ be_nested_str_weak(MTR_X3A_X20sending_X20packet_X20to_X20_X27_X5B_X25s_X5D_X3A_X25i_X27), + /* K11 */ be_const_int(3), + /* K12 */ be_nested_str_weak(MTR_X3A_X20failed_X20to_X20send_X20packet_X20to_X20_X27_X5B_X25s_X5D_X3A_X25i_X27), + /* K13 */ be_const_int(2), + }), + be_str_weak(send), + &be_const_str_solidified, + ( &(const binstruction[35]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0x8C0C0301, // 0001 GETMET R3 R1 K1 + 0x88140102, // 0002 GETMBR R5 R0 K2 + 0x78160001, // 0003 JMPF R5 #0006 + 0x88140102, // 0004 GETMBR R5 R0 K2 + 0x70020000, // 0005 JMP #0007 + 0x88140303, // 0006 GETMBR R5 R1 K3 + 0x88180104, // 0007 GETMBR R6 R0 K4 + 0x781A0001, // 0008 JMPF R6 #000B + 0x88180104, // 0009 GETMBR R6 R0 K4 + 0x70020000, // 000A JMP #000C + 0x88180305, // 000B GETMBR R6 R1 K5 + 0x881C0106, // 000C GETMBR R7 R0 K6 + 0x7C0C0800, // 000D CALL R3 4 + 0x780E0009, // 000E JMPF R3 #0019 + 0xB8120E00, // 000F GETNGBL R4 K7 + 0x8C100908, // 0010 GETMET R4 R4 K8 + 0x8C180509, // 0011 GETMET R6 R2 K9 + 0x5820000A, // 0012 LDCONST R8 K10 + 0x88240102, // 0013 GETMBR R9 R0 K2 + 0x88280104, // 0014 GETMBR R10 R0 K4 + 0x7C180800, // 0015 CALL R6 4 + 0x581C000B, // 0016 LDCONST R7 K11 + 0x7C100600, // 0017 CALL R4 3 + 0x70020008, // 0018 JMP #0022 + 0xB8120E00, // 0019 GETNGBL R4 K7 + 0x8C100908, // 001A GETMET R4 R4 K8 + 0x8C180509, // 001B GETMET R6 R2 K9 + 0x5820000C, // 001C LDCONST R8 K12 + 0x88240102, // 001D GETMBR R9 R0 K2 + 0x88280104, // 001E GETMBR R10 R0 K4 + 0x7C180800, // 001F CALL R6 4 + 0x581C000D, // 0020 LDCONST R7 K13 + 0x7C100600, // 0021 CALL R4 3 + 0x80000000, // 0022 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_UDPPacket_sent +********************************************************************/ +be_local_class(Matter_UDPPacket_sent, + 6, + NULL, + be_nested_map(10, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(RETRY_MS, 7), be_const_int(500) }, + { be_const_key_weak(raw, 4), be_const_var(0) }, + { be_const_key_weak(next_try, 9), be_const_var(5) }, + { be_const_key_weak(retries, -1), be_const_var(4) }, + { be_const_key_weak(send, 6), be_const_closure(Matter_UDPPacket_sent_send_closure) }, + { be_const_key_weak(init, -1), be_const_closure(Matter_UDPPacket_sent_init_closure) }, + { be_const_key_weak(RETRIES, -1), be_const_int(4) }, + { be_const_key_weak(port, -1), be_const_var(2) }, + { be_const_key_weak(addr, -1), be_const_var(1) }, + { be_const_key_weak(msg_id, -1), be_const_var(3) }, + })), + be_str_weak(Matter_UDPPacket_sent) +); +/*******************************************************************/ + +void be_load_Matter_UDPPacket_sent_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_UDPPacket_sent); + be_setglobal(vm, "Matter_UDPPacket_sent"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_UDPServer; + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_UDPServer_init, /* name */ + be_nested_proto( + 4, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(address), + /* K1 */ be_nested_str_weak(), + /* K2 */ be_nested_str_weak(port), + /* K3 */ be_nested_str_weak(listening), + /* K4 */ be_nested_str_weak(packets_sent), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[16]) { /* code */ + 0x78060001, // 0000 JMPF R1 #0003 + 0x5C0C0200, // 0001 MOVE R3 R1 + 0x70020000, // 0002 JMP #0004 + 0x580C0001, // 0003 LDCONST R3 K1 + 0x90020003, // 0004 SETMBR R0 K0 R3 + 0x780A0001, // 0005 JMPF R2 #0008 + 0x5C0C0400, // 0006 MOVE R3 R2 + 0x70020000, // 0007 JMP #0009 + 0x540E15A3, // 0008 LDINT R3 5540 + 0x90020403, // 0009 SETMBR R0 K2 R3 + 0x500C0000, // 000A LDBOOL R3 0 0 + 0x90020603, // 000B SETMBR R0 K3 R3 + 0x600C0013, // 000C GETGBL R3 G19 + 0x7C0C0000, // 000D CALL R3 0 + 0x90020803, // 000E SETMBR R0 K4 R3 + 0x80000000, // 000F RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: every_second +********************************************************************/ +be_local_closure(Matter_UDPServer_every_second, /* name */ + be_nested_proto( + 1, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + be_str_weak(every_second), + &be_const_str_solidified, + ( &(const binstruction[ 1]) { /* code */ + 0x80000000, // 0000 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: stop +********************************************************************/ +be_local_closure(Matter_UDPServer_stop, /* name */ + be_nested_proto( + 4, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(listening), + /* K1 */ be_nested_str_weak(udp_socket), + /* K2 */ be_nested_str_weak(stop), + /* K3 */ be_nested_str_weak(tasmota), + /* K4 */ be_nested_str_weak(remove_driver), + }), + be_str_weak(stop), + &be_const_str_solidified, + ( &(const binstruction[12]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x78060008, // 0001 JMPF R1 #000B + 0x88040101, // 0002 GETMBR R1 R0 K1 + 0x8C040302, // 0003 GETMET R1 R1 K2 + 0x7C040200, // 0004 CALL R1 1 + 0x50040000, // 0005 LDBOOL R1 0 0 + 0x90020001, // 0006 SETMBR R0 K0 R1 + 0xB8060600, // 0007 GETNGBL R1 K3 + 0x8C040304, // 0008 GETMET R1 R1 K4 + 0x5C0C0000, // 0009 MOVE R3 R0 + 0x7C040400, // 000A CALL R1 2 + 0x80000000, // 000B RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: every_50ms +********************************************************************/ +be_local_closure(Matter_UDPServer_every_50ms, /* name */ + be_nested_proto( + 13, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[14]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str_weak(udp_socket), + /* K3 */ be_nested_str_weak(read), + /* K4 */ be_const_int(1), + /* K5 */ be_nested_str_weak(remote_ip), + /* K6 */ be_nested_str_weak(remote_port), + /* K7 */ be_nested_str_weak(tasmota), + /* K8 */ be_nested_str_weak(log), + /* K9 */ be_nested_str_weak(format), + /* K10 */ be_nested_str_weak(MTR_X3A_X20UDP_X20received_X20from_X20_X5B_X25s_X5D_X3A_X25i), + /* K11 */ be_nested_str_weak(dispatch_cb), + /* K12 */ be_nested_str_weak(MAX_PACKETS_READ), + /* K13 */ be_nested_str_weak(resend_packets), + }), + be_str_weak(every_50ms), + &be_const_str_solidified, + ( &(const binstruction[47]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x58080001, // 0001 LDCONST R2 K1 + 0x880C0102, // 0002 GETMBR R3 R0 K2 + 0x4C100000, // 0003 LDNIL R4 + 0x1C0C0604, // 0004 EQ R3 R3 R4 + 0x780E0000, // 0005 JMPF R3 #0007 + 0x80000600, // 0006 RET 0 + 0x880C0102, // 0007 GETMBR R3 R0 K2 + 0x8C0C0703, // 0008 GETMET R3 R3 K3 + 0x7C0C0200, // 0009 CALL R3 1 + 0x4C100000, // 000A LDNIL R4 + 0x20100604, // 000B NE R4 R3 R4 + 0x7812001E, // 000C JMPF R4 #002C + 0x00080504, // 000D ADD R2 R2 K4 + 0x88100102, // 000E GETMBR R4 R0 K2 + 0x88100905, // 000F GETMBR R4 R4 K5 + 0x88140102, // 0010 GETMBR R5 R0 K2 + 0x88140B06, // 0011 GETMBR R5 R5 K6 + 0xB81A0E00, // 0012 GETNGBL R6 K7 + 0x8C180D08, // 0013 GETMET R6 R6 K8 + 0x8C200309, // 0014 GETMET R8 R1 K9 + 0x5828000A, // 0015 LDCONST R10 K10 + 0x5C2C0800, // 0016 MOVE R11 R4 + 0x5C300A00, // 0017 MOVE R12 R5 + 0x7C200800, // 0018 CALL R8 4 + 0x54260003, // 0019 LDINT R9 4 + 0x7C180600, // 001A CALL R6 3 + 0x8818010B, // 001B GETMBR R6 R0 K11 + 0x781A0004, // 001C JMPF R6 #0022 + 0x8C18010B, // 001D GETMET R6 R0 K11 + 0x5C200600, // 001E MOVE R8 R3 + 0x5C240800, // 001F MOVE R9 R4 + 0x5C280A00, // 0020 MOVE R10 R5 + 0x7C180800, // 0021 CALL R6 4 + 0x8818010C, // 0022 GETMBR R6 R0 K12 + 0x14180406, // 0023 LT R6 R2 R6 + 0x781A0004, // 0024 JMPF R6 #002A + 0x88180102, // 0025 GETMBR R6 R0 K2 + 0x8C180D03, // 0026 GETMET R6 R6 K3 + 0x7C180200, // 0027 CALL R6 1 + 0x5C0C0C00, // 0028 MOVE R3 R6 + 0x70020000, // 0029 JMP #002B + 0x4C0C0000, // 002A LDNIL R3 + 0x7001FFDD, // 002B JMP #000A + 0x8C10010D, // 002C GETMET R4 R0 K13 + 0x7C100200, // 002D CALL R4 1 + 0x80000000, // 002E RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: resend_packets +********************************************************************/ +be_local_closure(Matter_UDPServer_resend_packets, /* name */ + be_nested_proto( + 7, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[17]) { /* constants */ + /* K0 */ be_nested_str_weak(packets_sent), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(time_reached), + /* K3 */ be_nested_str_weak(next_try), + /* K4 */ be_nested_str_weak(log), + /* K5 */ be_nested_str_weak(MTR_X3A_X20resending_X20packet_X20id_X3D), + /* K6 */ be_nested_str_weak(msg_id), + /* K7 */ be_const_int(3), + /* K8 */ be_nested_str_weak(send), + /* K9 */ be_nested_str_weak(udp_socket), + /* K10 */ be_nested_str_weak(retries), + /* K11 */ be_const_int(1), + /* K12 */ be_const_int(0), + /* K13 */ be_nested_str_weak(remove), + /* K14 */ be_nested_str_weak(millis), + /* K15 */ be_nested_str_weak(RETRY_MS), + /* K16 */ be_nested_str_weak(stop_iteration), + }), + be_str_weak(resend_packets), + &be_const_str_solidified, + ( &(const binstruction[44]) { /* code */ + 0x60040010, // 0000 GETGBL R1 G16 + 0x88080100, // 0001 GETMBR R2 R0 K0 + 0x7C040200, // 0002 CALL R1 1 + 0xA8020023, // 0003 EXBLK 0 #0028 + 0x5C080200, // 0004 MOVE R2 R1 + 0x7C080000, // 0005 CALL R2 0 + 0xB80E0200, // 0006 GETNGBL R3 K1 + 0x8C0C0702, // 0007 GETMET R3 R3 K2 + 0x88140503, // 0008 GETMBR R5 R2 K3 + 0x7C0C0400, // 0009 CALL R3 2 + 0x780E001B, // 000A JMPF R3 #0027 + 0xB80E0200, // 000B GETNGBL R3 K1 + 0x8C0C0704, // 000C GETMET R3 R3 K4 + 0x60140008, // 000D GETGBL R5 G8 + 0x88180506, // 000E GETMBR R6 R2 K6 + 0x7C140200, // 000F CALL R5 1 + 0x00160A05, // 0010 ADD R5 K5 R5 + 0x58180007, // 0011 LDCONST R6 K7 + 0x7C0C0600, // 0012 CALL R3 3 + 0x8C0C0508, // 0013 GETMET R3 R2 K8 + 0x88140109, // 0014 GETMBR R5 R0 K9 + 0x7C0C0400, // 0015 CALL R3 2 + 0x880C050A, // 0016 GETMBR R3 R2 K10 + 0x040C070B, // 0017 SUB R3 R3 K11 + 0x900A1403, // 0018 SETMBR R2 K10 R3 + 0x880C050A, // 0019 GETMBR R3 R2 K10 + 0x180C070C, // 001A LE R3 R3 K12 + 0x780E0004, // 001B JMPF R3 #0021 + 0x880C0100, // 001C GETMBR R3 R0 K0 + 0x8C0C070D, // 001D GETMET R3 R3 K13 + 0x88140506, // 001E GETMBR R5 R2 K6 + 0x7C0C0400, // 001F CALL R3 2 + 0x70020005, // 0020 JMP #0027 + 0xB80E0200, // 0021 GETNGBL R3 K1 + 0x8C0C070E, // 0022 GETMET R3 R3 K14 + 0x7C0C0200, // 0023 CALL R3 1 + 0x8810050F, // 0024 GETMBR R4 R2 K15 + 0x000C0604, // 0025 ADD R3 R3 R4 + 0x900A0603, // 0026 SETMBR R2 K3 R3 + 0x7001FFDB, // 0027 JMP #0004 + 0x58040010, // 0028 LDCONST R1 K16 + 0xAC040200, // 0029 CATCH R1 1 0 + 0xB0080000, // 002A RAISE 2 R0 R0 + 0x80000000, // 002B RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: start +********************************************************************/ +be_local_closure(Matter_UDPServer_start, /* name */ + be_nested_proto( + 6, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[11]) { /* constants */ + /* K0 */ be_nested_str_weak(listening), + /* K1 */ be_nested_str_weak(udp_socket), + /* K2 */ be_nested_str_weak(udp), + /* K3 */ be_nested_str_weak(begin), + /* K4 */ be_nested_str_weak(address), + /* K5 */ be_nested_str_weak(port), + /* K6 */ be_nested_str_weak(network_error), + /* K7 */ be_nested_str_weak(could_X20not_X20open_X20UDP_X20server), + /* K8 */ be_nested_str_weak(dispatch_cb), + /* K9 */ be_nested_str_weak(tasmota), + /* K10 */ be_nested_str_weak(add_driver), + }), + be_str_weak(start), + &be_const_str_solidified, + ( &(const binstruction[21]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x740A0011, // 0001 JMPT R2 #0014 + 0xB80A0400, // 0002 GETNGBL R2 K2 + 0x7C080000, // 0003 CALL R2 0 + 0x90020202, // 0004 SETMBR R0 K1 R2 + 0x88080101, // 0005 GETMBR R2 R0 K1 + 0x8C080503, // 0006 GETMET R2 R2 K3 + 0x88100104, // 0007 GETMBR R4 R0 K4 + 0x88140105, // 0008 GETMBR R5 R0 K5 + 0x7C080600, // 0009 CALL R2 3 + 0x5C0C0400, // 000A MOVE R3 R2 + 0x740E0000, // 000B JMPT R3 #000D + 0xB0060D07, // 000C RAISE 1 K6 K7 + 0x500C0200, // 000D LDBOOL R3 1 0 + 0x90020003, // 000E SETMBR R0 K0 R3 + 0x90021001, // 000F SETMBR R0 K8 R1 + 0xB80E1200, // 0010 GETNGBL R3 K9 + 0x8C0C070A, // 0011 GETMET R3 R3 K10 + 0x5C140000, // 0012 MOVE R5 R0 + 0x7C0C0400, // 0013 CALL R3 2 + 0x80000000, // 0014 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: send_response +********************************************************************/ +be_local_closure(Matter_UDPServer_send_response, /* name */ + be_nested_proto( + 11, /* nstack */ + 5, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(UDPPacket_sent), + /* K2 */ be_nested_str_weak(send), + /* K3 */ be_nested_str_weak(udp_socket), + /* K4 */ be_nested_str_weak(packets_sent), + }), + be_str_weak(send_response), + &be_const_str_solidified, + ( &(const binstruction[14]) { /* code */ + 0xB8160000, // 0000 GETNGBL R5 K0 + 0x8C140B01, // 0001 GETMET R5 R5 K1 + 0x5C1C0200, // 0002 MOVE R7 R1 + 0x5C200400, // 0003 MOVE R8 R2 + 0x5C240600, // 0004 MOVE R9 R3 + 0x5C280800, // 0005 MOVE R10 R4 + 0x7C140A00, // 0006 CALL R5 5 + 0x8C180B02, // 0007 GETMET R6 R5 K2 + 0x88200103, // 0008 GETMBR R8 R0 K3 + 0x7C180400, // 0009 CALL R6 2 + 0x78120001, // 000A JMPF R4 #000D + 0x88180104, // 000B GETMBR R6 R0 K4 + 0x98180805, // 000C SETIDX R6 R4 R5 + 0x80000000, // 000D RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: packet_ack +********************************************************************/ +be_local_closure(Matter_UDPServer_packet_ack, /* name */ + be_nested_proto( + 6, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 7]) { /* constants */ + /* K0 */ be_nested_str_weak(packets_sent), + /* K1 */ be_nested_str_weak(contains), + /* K2 */ be_nested_str_weak(remove), + /* K3 */ be_nested_str_weak(tasmota), + /* K4 */ be_nested_str_weak(log), + /* K5 */ be_nested_str_weak(MTR_X3A_X20removed_X20packet_X20from_X20sending_X20list_X20id_X3D), + /* K6 */ be_const_int(3), + }), + be_str_weak(packet_ack), + &be_const_str_solidified, + ( &(const binstruction[22]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0000, // 0002 JMPF R2 #0004 + 0x80000400, // 0003 RET 0 + 0x88080100, // 0004 GETMBR R2 R0 K0 + 0x8C080501, // 0005 GETMET R2 R2 K1 + 0x5C100200, // 0006 MOVE R4 R1 + 0x7C080400, // 0007 CALL R2 2 + 0x780A000B, // 0008 JMPF R2 #0015 + 0x88080100, // 0009 GETMBR R2 R0 K0 + 0x8C080502, // 000A GETMET R2 R2 K2 + 0x5C100200, // 000B MOVE R4 R1 + 0x7C080400, // 000C CALL R2 2 + 0xB80A0600, // 000D GETNGBL R2 K3 + 0x8C080504, // 000E GETMET R2 R2 K4 + 0x60100008, // 000F GETGBL R4 G8 + 0x5C140200, // 0010 MOVE R5 R1 + 0x7C100200, // 0011 CALL R4 1 + 0x00120A04, // 0012 ADD R4 K5 R4 + 0x58140006, // 0013 LDCONST R5 K6 + 0x7C080600, // 0014 CALL R2 3 + 0x80000000, // 0015 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_UDPServer +********************************************************************/ +be_local_class(Matter_UDPServer, + 6, + NULL, + be_nested_map(15, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(init, 1), be_const_closure(Matter_UDPServer_init_closure) }, + { be_const_key_weak(every_second, -1), be_const_closure(Matter_UDPServer_every_second_closure) }, + { be_const_key_weak(stop, -1), be_const_closure(Matter_UDPServer_stop_closure) }, + { be_const_key_weak(udp_socket, -1), be_const_var(3) }, + { be_const_key_weak(address, -1), be_const_var(0) }, + { be_const_key_weak(dispatch_cb, -1), be_const_var(4) }, + { be_const_key_weak(packet_ack, 7), be_const_closure(Matter_UDPServer_packet_ack_closure) }, + { be_const_key_weak(MAX_PACKETS_READ, 13), be_const_int(4) }, + { be_const_key_weak(every_50ms, 6), be_const_closure(Matter_UDPServer_every_50ms_closure) }, + { be_const_key_weak(listening, -1), be_const_var(2) }, + { be_const_key_weak(port, -1), be_const_var(1) }, + { be_const_key_weak(start, -1), be_const_closure(Matter_UDPServer_start_closure) }, + { be_const_key_weak(send_response, -1), be_const_closure(Matter_UDPServer_send_response_closure) }, + { be_const_key_weak(resend_packets, -1), be_const_closure(Matter_UDPServer_resend_packets_closure) }, + { be_const_key_weak(packets_sent, -1), be_const_var(5) }, + })), + be_str_weak(Matter_UDPServer) +); +/*******************************************************************/ + +void be_load_Matter_UDPServer_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_UDPServer); + be_setglobal(vm, "Matter_UDPServer"); + be_pop(vm, 1); +} +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_UI.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_UI.h new file mode 100644 index 000000000..0eaee343f --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_UI.h @@ -0,0 +1,893 @@ +/* Solidification of Matter_UI.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_UI; + +/******************************************************************** +** Solidified function: show_commissioning_info +********************************************************************/ +be_local_closure(Matter_UI_show_commissioning_info, /* name */ + be_nested_proto( + 12, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[24]) { /* constants */ + /* K0 */ be_nested_str_weak(webserver), + /* K1 */ be_nested_str_weak(string), + /* K2 */ be_nested_str_weak(content_send), + /* K3 */ be_nested_str_weak(_X3Cfieldset_X3E_X3Clegend_X3E_X3Cb_X3E_X26nbsp_X3BMatter_X20Passcode_X26nbsp_X3B_X3C_X2Fb_X3E_X3C_X2Flegend_X3E_X3Cp_X3E_X3C_X2Fp_X3E), + /* K4 */ be_nested_str_weak(device), + /* K5 */ be_nested_str_weak(compute_manual_pairing_code), + /* K6 */ be_nested_str_weak(format), + /* K7 */ be_nested_str_weak(_X3Cp_X3EManual_X20pairing_X20code_X3A_X3Cbr_X3E_X3Cb_X3E_X25s_X2D_X25s_X2D_X25s_X3C_X2Fb_X3E_X3C_X2Fp_X3E_X3Chr_X3E), + /* K8 */ be_const_int(0), + /* K9 */ be_const_int(3), + /* K10 */ be_const_int(2147483647), + /* K11 */ be_nested_str_weak(compute_qrcode_content), + /* K12 */ be_nested_str_weak(_X3Cdiv_X20id_X3D_X22qrcode_X22_X3E_X3C_X2Fdiv_X3E), + /* K13 */ be_nested_str_weak(_X3Cscript_X20type_X3D_X22text_X2Fjavascript_X22_X3E_X20new_X20QRCode_X28document_X2EgetElementById_X28_X22qrcode_X22_X29_X2C_X20_X22_X25s_X22_X29_X3B_X3C_X2Fscript_X3E), + /* K14 */ be_nested_str_weak(_X3Cp_X3E_X25s_X3C_X2Fp_X3E_X3Chr_X3E), + /* K15 */ be_nested_str_weak(_X3Cform_X20action_X3D_X27_X2Fmatterc_X27_X20method_X3D_X27post_X27_X20_X3E), + /* K16 */ be_nested_str_weak(_X3Cp_X3EPasscode_X3A_X3C_X2Fp_X3E), + /* K17 */ be_nested_str_weak(_X3Cinput_X20type_X3D_X27number_X27_X20min_X3D_X271_X27_X20max_X3D_X2799999998_X27_X20name_X3D_X27passcode_X27_X20value_X3D_X27_X25i_X27_X3E), + /* K18 */ be_nested_str_weak(passcode), + /* K19 */ be_nested_str_weak(_X3Cp_X3EDistinguish_X20id_X3A_X3C_X2Fp_X3E), + /* K20 */ be_nested_str_weak(_X3Cinput_X20type_X3D_X27number_X27_X20min_X3D_X270_X27_X20max_X3D_X272047_X27_X20name_X3D_X27discriminator_X27_X20value_X3D_X27_X25i_X27_X3E), + /* K21 */ be_nested_str_weak(discriminator), + /* K22 */ be_nested_str_weak(_X3Cp_X3E_X3C_X2Fp_X3E_X3Cbutton_X20name_X3D_X27passcode_X27_X20class_X3D_X27button_X20bgrn_X27_X3EChange_X3C_X2Fbutton_X3E_X3C_X2Fform_X3E_X3C_X2Fp_X3E), + /* K23 */ be_nested_str_weak(_X3Cp_X3E_X3C_X2Fp_X3E_X3C_X2Ffieldset_X3E_X3Cp_X3E_X3C_X2Fp_X3E), + }), + be_str_weak(show_commissioning_info), + &be_const_str_solidified, + ( &(const binstruction[70]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0xA40A0200, // 0001 IMPORT R2 K1 + 0x8C0C0302, // 0002 GETMET R3 R1 K2 + 0x58140003, // 0003 LDCONST R5 K3 + 0x7C0C0400, // 0004 CALL R3 2 + 0x880C0104, // 0005 GETMBR R3 R0 K4 + 0x8C0C0705, // 0006 GETMET R3 R3 K5 + 0x7C0C0200, // 0007 CALL R3 1 + 0x8C100302, // 0008 GETMET R4 R1 K2 + 0x8C180506, // 0009 GETMET R6 R2 K6 + 0x58200007, // 000A LDCONST R8 K7 + 0x40261109, // 000B CONNECT R9 K8 K9 + 0x94240609, // 000C GETIDX R9 R3 R9 + 0x542A0003, // 000D LDINT R10 4 + 0x542E0005, // 000E LDINT R11 6 + 0x4028140B, // 000F CONNECT R10 R10 R11 + 0x9428060A, // 0010 GETIDX R10 R3 R10 + 0x542E0006, // 0011 LDINT R11 7 + 0x402C170A, // 0012 CONNECT R11 R11 K10 + 0x942C060B, // 0013 GETIDX R11 R3 R11 + 0x7C180A00, // 0014 CALL R6 5 + 0x7C100400, // 0015 CALL R4 2 + 0x88100104, // 0016 GETMBR R4 R0 K4 + 0x8C10090B, // 0017 GETMET R4 R4 K11 + 0x7C100200, // 0018 CALL R4 1 + 0x8C140302, // 0019 GETMET R5 R1 K2 + 0x581C000C, // 001A LDCONST R7 K12 + 0x7C140400, // 001B CALL R5 2 + 0x8C140302, // 001C GETMET R5 R1 K2 + 0x8C1C0506, // 001D GETMET R7 R2 K6 + 0x5824000D, // 001E LDCONST R9 K13 + 0x5C280800, // 001F MOVE R10 R4 + 0x7C1C0600, // 0020 CALL R7 3 + 0x7C140400, // 0021 CALL R5 2 + 0x8C140302, // 0022 GETMET R5 R1 K2 + 0x8C1C0506, // 0023 GETMET R7 R2 K6 + 0x5824000E, // 0024 LDCONST R9 K14 + 0x5C280800, // 0025 MOVE R10 R4 + 0x7C1C0600, // 0026 CALL R7 3 + 0x7C140400, // 0027 CALL R5 2 + 0x8C140302, // 0028 GETMET R5 R1 K2 + 0x581C000F, // 0029 LDCONST R7 K15 + 0x7C140400, // 002A CALL R5 2 + 0x8C140302, // 002B GETMET R5 R1 K2 + 0x581C0010, // 002C LDCONST R7 K16 + 0x7C140400, // 002D CALL R5 2 + 0x8C140302, // 002E GETMET R5 R1 K2 + 0x8C1C0506, // 002F GETMET R7 R2 K6 + 0x58240011, // 0030 LDCONST R9 K17 + 0x88280104, // 0031 GETMBR R10 R0 K4 + 0x88281512, // 0032 GETMBR R10 R10 K18 + 0x7C1C0600, // 0033 CALL R7 3 + 0x7C140400, // 0034 CALL R5 2 + 0x8C140302, // 0035 GETMET R5 R1 K2 + 0x581C0013, // 0036 LDCONST R7 K19 + 0x7C140400, // 0037 CALL R5 2 + 0x8C140302, // 0038 GETMET R5 R1 K2 + 0x8C1C0506, // 0039 GETMET R7 R2 K6 + 0x58240014, // 003A LDCONST R9 K20 + 0x88280104, // 003B GETMBR R10 R0 K4 + 0x88281515, // 003C GETMBR R10 R10 K21 + 0x7C1C0600, // 003D CALL R7 3 + 0x7C140400, // 003E CALL R5 2 + 0x8C140302, // 003F GETMET R5 R1 K2 + 0x581C0016, // 0040 LDCONST R7 K22 + 0x7C140400, // 0041 CALL R5 2 + 0x8C140302, // 0042 GETMET R5 R1 K2 + 0x581C0017, // 0043 LDCONST R7 K23 + 0x7C140400, // 0044 CALL R5 2 + 0x80000000, // 0045 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: web_add_handler +********************************************************************/ +be_local_closure(Matter_UI_web_add_handler, /* name */ + be_nested_proto( + 7, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 1, /* has sup protos */ + ( &(const struct bproto*[ 3]) { + be_nested_proto( + 2, /* nstack */ + 0, /* argc */ + 0, /* varg */ + 1, /* has upvals */ + ( &(const bupvaldesc[ 1]) { /* upvals */ + be_local_const_upval(1, 0), + }), + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(page_part_mgr), + }), + be_str_weak(_X3Clambda_X3E), + &be_const_str_solidified, + ( &(const binstruction[ 4]) { /* code */ + 0x68000000, // 0000 GETUPV R0 U0 + 0x8C000100, // 0001 GETMET R0 R0 K0 + 0x7C000200, // 0002 CALL R0 1 + 0x80040000, // 0003 RET 1 R0 + }) + ), + be_nested_proto( + 2, /* nstack */ + 0, /* argc */ + 0, /* varg */ + 1, /* has upvals */ + ( &(const bupvaldesc[ 1]) { /* upvals */ + be_local_const_upval(1, 0), + }), + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(page_part_ctl), + }), + be_str_weak(_X3Clambda_X3E), + &be_const_str_solidified, + ( &(const binstruction[ 4]) { /* code */ + 0x68000000, // 0000 GETUPV R0 U0 + 0x8C000100, // 0001 GETMET R0 R0 K0 + 0x7C000200, // 0002 CALL R0 1 + 0x80040000, // 0003 RET 1 R0 + }) + ), + be_nested_proto( + 2, /* nstack */ + 0, /* argc */ + 0, /* varg */ + 1, /* has upvals */ + ( &(const bupvaldesc[ 1]) { /* upvals */ + be_local_const_upval(1, 0), + }), + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(page_qrcode_min_js), + }), + be_str_weak(_X3Clambda_X3E), + &be_const_str_solidified, + ( &(const binstruction[ 4]) { /* code */ + 0x68000000, // 0000 GETUPV R0 U0 + 0x8C000100, // 0001 GETMET R0 R0 K0 + 0x7C000200, // 0002 CALL R0 1 + 0x80040000, // 0003 RET 1 R0 + }) + ), + }), + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(webserver), + /* K1 */ be_nested_str_weak(on), + /* K2 */ be_nested_str_weak(_X2Fmatterc), + /* K3 */ be_nested_str_weak(HTTP_GET), + /* K4 */ be_nested_str_weak(HTTP_POST), + /* K5 */ be_nested_str_weak(_X2Fqrcode_X2Emin_X2Ejs), + }), + be_str_weak(web_add_handler), + &be_const_str_solidified, + ( &(const binstruction[18]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x8C080301, // 0001 GETMET R2 R1 K1 + 0x58100002, // 0002 LDCONST R4 K2 + 0x84140000, // 0003 CLOSURE R5 P0 + 0x88180303, // 0004 GETMBR R6 R1 K3 + 0x7C080800, // 0005 CALL R2 4 + 0x8C080301, // 0006 GETMET R2 R1 K1 + 0x58100002, // 0007 LDCONST R4 K2 + 0x84140001, // 0008 CLOSURE R5 P1 + 0x88180304, // 0009 GETMBR R6 R1 K4 + 0x7C080800, // 000A CALL R2 4 + 0x8C080301, // 000B GETMET R2 R1 K1 + 0x58100005, // 000C LDCONST R4 K5 + 0x84140002, // 000D CLOSURE R5 P2 + 0x88180303, // 000E GETMBR R6 R1 K3 + 0x7C080800, // 000F CALL R2 4 + 0xA0000000, // 0010 CLOSE R0 + 0x80000000, // 0011 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: show_session_info +********************************************************************/ +be_local_closure(Matter_UI_show_session_info, /* name */ + be_nested_proto( + 16, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[26]) { /* constants */ + /* K0 */ be_nested_str_weak(webserver), + /* K1 */ be_nested_str_weak(string), + /* K2 */ be_nested_str_weak(content_send), + /* K3 */ be_nested_str_weak(_X3Cfieldset_X3E_X3Clegend_X3E_X3Cb_X3E_X26nbsp_X3BSessions_X26nbsp_X3B_X3C_X2Fb_X3E_X3C_X2Flegend_X3E_X3Cp_X3E_X3C_X2Fp_X3E), + /* K4 */ be_nested_str_weak(_X3Cp_X3EExisting_X20sessions_X3A_X3C_X2Fp_X3E), + /* K5 */ be_nested_str_weak(device), + /* K6 */ be_nested_str_weak(sessions), + /* K7 */ be_const_int(0), + /* K8 */ be_nested_str_weak(_X3Cp_X3E_X3Cb_X3ENone_X3C_X2Fb_X3E_X3C_X2Fp_X3E), + /* K9 */ be_nested_str_weak(fabric), + /* K10 */ be_nested_str_weak(format), + /* K11 */ be_nested_str_weak(_X3Cfieldset_X3E_X3Clegend_X3E_X3Cb_X3E_X26nbsp_X3BSession_X20_X25i_X26nbsp_X3B_X3C_X2Fb_X3E_X3C_X2Flegend_X3E_X3Cp_X3E_X3C_X2Fp_X3E), + /* K12 */ be_nested_str_weak(local_session_id), + /* K13 */ be_nested_str_weak(_X3Chr_X3E), + /* K14 */ be_nested_str_weak(copy), + /* K15 */ be_nested_str_weak(reverse), + /* K16 */ be_nested_str_weak(deviceid), + /* K17 */ be_nested_str_weak(Fabric_X3A_X20_X25s_X3Cbr_X3E), + /* K18 */ be_nested_str_weak(tohex), + /* K19 */ be_nested_str_weak(Device_X3A_X20_X25s_X3Cbr_X3E_X26nbsp_X3B), + /* K20 */ be_nested_str_weak(_X3Cform_X20action_X3D_X27_X2Fmatterc_X27_X20method_X3D_X27post_X27_X20), + /* K21 */ be_nested_str_weak(onsubmit_X3D_X27return_X20confirm_X28_X22This_X20will_X20cause_X20a_X20restart_X2E_X22_X29_X3B_X27_X3E), + /* K22 */ be_nested_str_weak(_X3Cinput_X20name_X3D_X27del_session_X27_X20type_X3D_X27hidden_X27_X20value_X3D_X27_X25d_X27_X3E), + /* K23 */ be_nested_str_weak(_X3Cbutton_X20name_X3D_X27del_X27_X20class_X3D_X27button_X20bgrn_X27_X3EDelete_X20Session_X3C_X2Fbutton_X3E_X3C_X2Fform_X3E_X3C_X2Fp_X3E), + /* K24 */ be_nested_str_weak(_X3Cp_X3E_X3C_X2Fp_X3E_X3C_X2Ffieldset_X3E_X3Cp_X3E_X3C_X2Fp_X3E), + /* K25 */ be_const_int(1), + }), + be_str_weak(show_session_info), + &be_const_str_solidified, + ( &(const binstruction[92]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0xA40E0200, // 0001 IMPORT R3 K1 + 0x8C100502, // 0002 GETMET R4 R2 K2 + 0x58180003, // 0003 LDCONST R6 K3 + 0x7C100400, // 0004 CALL R4 2 + 0x8C100502, // 0005 GETMET R4 R2 K2 + 0x58180004, // 0006 LDCONST R6 K4 + 0x7C100400, // 0007 CALL R4 2 + 0x6010000C, // 0008 GETGBL R4 G12 + 0x88140105, // 0009 GETMBR R5 R0 K5 + 0x88140B06, // 000A GETMBR R5 R5 K6 + 0x88140B06, // 000B GETMBR R5 R5 K6 + 0x7C100200, // 000C CALL R4 1 + 0x1C100907, // 000D EQ R4 R4 K7 + 0x78120003, // 000E JMPF R4 #0013 + 0x8C100502, // 000F GETMET R4 R2 K2 + 0x58180008, // 0010 LDCONST R6 K8 + 0x7C100400, // 0011 CALL R4 2 + 0x70020044, // 0012 JMP #0058 + 0x58100007, // 0013 LDCONST R4 K7 + 0x6014000C, // 0014 GETGBL R5 G12 + 0x88180105, // 0015 GETMBR R6 R0 K5 + 0x88180D06, // 0016 GETMBR R6 R6 K6 + 0x88180D06, // 0017 GETMBR R6 R6 K6 + 0x7C140200, // 0018 CALL R5 1 + 0x14180805, // 0019 LT R6 R4 R5 + 0x781A003C, // 001A JMPF R6 #0058 + 0x88180105, // 001B GETMBR R6 R0 K5 + 0x88180D06, // 001C GETMBR R6 R6 K6 + 0x88180D06, // 001D GETMBR R6 R6 K6 + 0x94180C04, // 001E GETIDX R6 R6 R4 + 0x881C0D09, // 001F GETMBR R7 R6 K9 + 0x781E0034, // 0020 JMPF R7 #0056 + 0x8C1C0502, // 0021 GETMET R7 R2 K2 + 0x8C24070A, // 0022 GETMET R9 R3 K10 + 0x582C000B, // 0023 LDCONST R11 K11 + 0x88300D0C, // 0024 GETMBR R12 R6 K12 + 0x7C240600, // 0025 CALL R9 3 + 0x7C1C0400, // 0026 CALL R7 2 + 0x201C0907, // 0027 NE R7 R4 K7 + 0x781E0002, // 0028 JMPF R7 #002C + 0x8C1C0502, // 0029 GETMET R7 R2 K2 + 0x5824000D, // 002A LDCONST R9 K13 + 0x7C1C0400, // 002B CALL R7 2 + 0x881C0D09, // 002C GETMBR R7 R6 K9 + 0x8C1C0F0E, // 002D GETMET R7 R7 K14 + 0x7C1C0200, // 002E CALL R7 1 + 0x8C1C0F0F, // 002F GETMET R7 R7 K15 + 0x7C1C0200, // 0030 CALL R7 1 + 0x88200D10, // 0031 GETMBR R8 R6 K16 + 0x8C20110E, // 0032 GETMET R8 R8 K14 + 0x7C200200, // 0033 CALL R8 1 + 0x8C20110F, // 0034 GETMET R8 R8 K15 + 0x7C200200, // 0035 CALL R8 1 + 0x8C240502, // 0036 GETMET R9 R2 K2 + 0x8C2C070A, // 0037 GETMET R11 R3 K10 + 0x58340011, // 0038 LDCONST R13 K17 + 0x8C380F12, // 0039 GETMET R14 R7 K18 + 0x7C380200, // 003A CALL R14 1 + 0x7C2C0600, // 003B CALL R11 3 + 0x7C240400, // 003C CALL R9 2 + 0x8C240502, // 003D GETMET R9 R2 K2 + 0x8C2C070A, // 003E GETMET R11 R3 K10 + 0x58340013, // 003F LDCONST R13 K19 + 0x8C381112, // 0040 GETMET R14 R8 K18 + 0x7C380200, // 0041 CALL R14 1 + 0x7C2C0600, // 0042 CALL R11 3 + 0x7C240400, // 0043 CALL R9 2 + 0x8C240502, // 0044 GETMET R9 R2 K2 + 0x582C0014, // 0045 LDCONST R11 K20 + 0x7C240400, // 0046 CALL R9 2 + 0x8C240502, // 0047 GETMET R9 R2 K2 + 0x582C0015, // 0048 LDCONST R11 K21 + 0x7C240400, // 0049 CALL R9 2 + 0x8C240502, // 004A GETMET R9 R2 K2 + 0x8C2C070A, // 004B GETMET R11 R3 K10 + 0x58340016, // 004C LDCONST R13 K22 + 0x88380D0C, // 004D GETMBR R14 R6 K12 + 0x7C2C0600, // 004E CALL R11 3 + 0x7C240400, // 004F CALL R9 2 + 0x8C240502, // 0050 GETMET R9 R2 K2 + 0x582C0017, // 0051 LDCONST R11 K23 + 0x7C240400, // 0052 CALL R9 2 + 0x8C240502, // 0053 GETMET R9 R2 K2 + 0x582C0018, // 0054 LDCONST R11 K24 + 0x7C240400, // 0055 CALL R9 2 + 0x00100919, // 0056 ADD R4 R4 K25 + 0x7001FFC0, // 0057 JMP #0019 + 0x8C100502, // 0058 GETMET R4 R2 K2 + 0x58180018, // 0059 LDCONST R6 K24 + 0x7C100400, // 005A CALL R4 2 + 0x80000000, // 005B RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: show_enable +********************************************************************/ +be_local_closure(Matter_UI_show_enable, /* name */ + be_nested_proto( + 11, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[20]) { /* constants */ + /* K0 */ be_nested_str_weak(webserver), + /* K1 */ be_nested_str_weak(string), + /* K2 */ be_nested_str_weak(tasmota), + /* K3 */ be_nested_str_weak(get_option), + /* K4 */ be_nested_str_weak(matter), + /* K5 */ be_nested_str_weak(MATTER_OPTION), + /* K6 */ be_nested_str_weak(content_send), + /* K7 */ be_nested_str_weak(format), + /* K8 */ be_nested_str_weak(_X3Cfieldset_X3E_X3Clegend_X3E_X3Cb_X3E_X26nbsp_X3BMatter_X20_X25s_X26nbsp_X3B_X3C_X2Fb_X3E_X3C_X2Flegend_X3E_X3Cp_X3E_X3C_X2Fp_X3E), + /* K9 */ be_nested_str_weak(Enabled), + /* K10 */ be_nested_str_weak(Disabled), + /* K11 */ be_nested_str_weak(_X3Cp_X20style_X3D_X27width_X3A320px_X3B_X27_X3EMatter_X20support_X20is_X20experimental_X2E_X3C_X2Fp_X3E), + /* K12 */ be_nested_str_weak(_X3Cform_X20action_X3D_X27_X2Fmatterc_X27_X20method_X3D_X27post_X27_X20onsubmit_X3D_X27return_X20confirm_X28_X22This_X20will_X20cause_X20a_X20restart_X2E_X22_X29_X3B_X27_X3E), + /* K13 */ be_nested_str_weak(_X3Cp_X3E_X3C_X2Fp_X3E_X3Cbutton_X20name_X3D_X27_X25s_X27_X20class_X3D_X27button_X20bgrn_X27_X3E), + /* K14 */ be_nested_str_weak(disable), + /* K15 */ be_nested_str_weak(enable), + /* K16 */ be_nested_str_weak(Disable), + /* K17 */ be_nested_str_weak(Enable), + /* K18 */ be_nested_str_weak(_X20Matter_X3C_X2Fbutton_X3E_X3C_X2Fform_X3E_X3C_X2Fp_X3E), + /* K19 */ be_nested_str_weak(_X3Cp_X3E_X3C_X2Fp_X3E_X3C_X2Ffieldset_X3E_X3Cp_X3E_X3C_X2Fp_X3E), + }), + be_str_weak(show_enable), + &be_const_str_solidified, + ( &(const binstruction[44]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0xA40E0200, // 0001 IMPORT R3 K1 + 0xB8120400, // 0002 GETNGBL R4 K2 + 0x8C100903, // 0003 GETMET R4 R4 K3 + 0xB81A0800, // 0004 GETNGBL R6 K4 + 0x88180D05, // 0005 GETMBR R6 R6 K5 + 0x7C100400, // 0006 CALL R4 2 + 0x8C140506, // 0007 GETMET R5 R2 K6 + 0x8C1C0707, // 0008 GETMET R7 R3 K7 + 0x58240008, // 0009 LDCONST R9 K8 + 0x78120001, // 000A JMPF R4 #000D + 0x58280009, // 000B LDCONST R10 K9 + 0x70020000, // 000C JMP #000E + 0x5828000A, // 000D LDCONST R10 K10 + 0x7C1C0600, // 000E CALL R7 3 + 0x7C140400, // 000F CALL R5 2 + 0x8C140506, // 0010 GETMET R5 R2 K6 + 0x581C000B, // 0011 LDCONST R7 K11 + 0x7C140400, // 0012 CALL R5 2 + 0x8C140506, // 0013 GETMET R5 R2 K6 + 0x581C000C, // 0014 LDCONST R7 K12 + 0x7C140400, // 0015 CALL R5 2 + 0x8C140506, // 0016 GETMET R5 R2 K6 + 0x8C1C0707, // 0017 GETMET R7 R3 K7 + 0x5824000D, // 0018 LDCONST R9 K13 + 0x78120001, // 0019 JMPF R4 #001C + 0x5828000E, // 001A LDCONST R10 K14 + 0x70020000, // 001B JMP #001D + 0x5828000F, // 001C LDCONST R10 K15 + 0x7C1C0600, // 001D CALL R7 3 + 0x7C140400, // 001E CALL R5 2 + 0x8C140506, // 001F GETMET R5 R2 K6 + 0x78120001, // 0020 JMPF R4 #0023 + 0x581C0010, // 0021 LDCONST R7 K16 + 0x70020000, // 0022 JMP #0024 + 0x581C0011, // 0023 LDCONST R7 K17 + 0x7C140400, // 0024 CALL R5 2 + 0x8C140506, // 0025 GETMET R5 R2 K6 + 0x581C0012, // 0026 LDCONST R7 K18 + 0x7C140400, // 0027 CALL R5 2 + 0x8C140506, // 0028 GETMET R5 R2 K6 + 0x581C0013, // 0029 LDCONST R7 K19 + 0x7C140400, // 002A CALL R5 2 + 0x80040800, // 002B RET 1 R4 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_UI_init, /* name */ + be_nested_proto( + 5, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(device), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(add_driver), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[ 6]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0xB80A0200, // 0001 GETNGBL R2 K1 + 0x8C080502, // 0002 GETMET R2 R2 K2 + 0x5C100000, // 0003 MOVE R4 R0 + 0x7C080400, // 0004 CALL R2 2 + 0x80000000, // 0005 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: page_part_ctl +********************************************************************/ +be_local_closure(Matter_UI_page_part_ctl, /* name */ + be_nested_proto( + 15, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[40]) { /* constants */ + /* K0 */ be_nested_str_weak(webserver), + /* K1 */ be_nested_str_weak(check_privileged_access), + /* K2 */ be_nested_str_weak(string), + /* K3 */ be_nested_str_weak(partition_core), + /* K4 */ be_nested_str_weak(persist), + /* K5 */ be_nested_str_weak(Partition), + /* K6 */ be_nested_str_weak(has_arg), + /* K7 */ be_nested_str_weak(passcode), + /* K8 */ be_nested_str_weak(discriminator), + /* K9 */ be_nested_str_weak(device), + /* K10 */ be_nested_str_weak(arg), + /* K11 */ be_nested_str_weak(save_param), + /* K12 */ be_nested_str_weak(redirect), + /* K13 */ be_nested_str_weak(_X2F_X3Frst_X3D), + /* K14 */ be_nested_str_weak(enable), + /* K15 */ be_nested_str_weak(tasmota), + /* K16 */ be_nested_str_weak(cmd), + /* K17 */ be_nested_str_weak(SetOption), + /* K18 */ be_nested_str_weak(matter), + /* K19 */ be_nested_str_weak(MATTER_OPTION), + /* K20 */ be_nested_str_weak(_X201), + /* K21 */ be_nested_str_weak(disable), + /* K22 */ be_nested_str_weak(_X200), + /* K23 */ be_nested_str_weak(del_session), + /* K24 */ be_nested_str_weak(sessions), + /* K25 */ be_nested_str_weak(get_session_by_local_session_id), + /* K26 */ be_nested_str_weak(remove_session), + /* K27 */ be_nested_str_weak(save), + /* K28 */ be_nested_str_weak(log), + /* K29 */ be_nested_str_weak(format), + /* K30 */ be_nested_str_weak(BRY_X3A_X20Exception_X3E_X20_X27_X25s_X27_X20_X2D_X20_X25s), + /* K31 */ be_const_int(2), + /* K32 */ be_nested_str_weak(content_start), + /* K33 */ be_nested_str_weak(Parameter_X20error), + /* K34 */ be_nested_str_weak(content_send_style), + /* K35 */ be_nested_str_weak(content_send), + /* K36 */ be_nested_str_weak(_X3Cp_X20style_X3D_X27width_X3A340px_X3B_X27_X3E_X3Cb_X3EException_X3A_X3C_X2Fb_X3E_X3Cbr_X3E_X27_X25s_X27_X3Cbr_X3E_X25s_X3C_X2Fp_X3E), + /* K37 */ be_nested_str_weak(content_button), + /* K38 */ be_nested_str_weak(BUTTON_MANAGEMENT), + /* K39 */ be_nested_str_weak(content_stop), + }), + be_str_weak(page_part_ctl), + &be_const_str_solidified, + ( &(const binstruction[144]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x8C080301, // 0001 GETMET R2 R1 K1 + 0x7C080200, // 0002 CALL R2 1 + 0x740A0001, // 0003 JMPT R2 #0006 + 0x4C080000, // 0004 LDNIL R2 + 0x80040400, // 0005 RET 1 R2 + 0xA40A0400, // 0006 IMPORT R2 K2 + 0xA40E0600, // 0007 IMPORT R3 K3 + 0xA4120800, // 0008 IMPORT R4 K4 + 0x8C140705, // 0009 GETMET R5 R3 K5 + 0x7C140200, // 000A CALL R5 1 + 0xA8020064, // 000B EXBLK 0 #0071 + 0x8C180306, // 000C GETMET R6 R1 K6 + 0x58200007, // 000D LDCONST R8 K7 + 0x7C180400, // 000E CALL R6 2 + 0x741A0003, // 000F JMPT R6 #0014 + 0x8C180306, // 0010 GETMET R6 R1 K6 + 0x58200008, // 0011 LDCONST R8 K8 + 0x7C180400, // 0012 CALL R6 2 + 0x781A001C, // 0013 JMPF R6 #0031 + 0x8C180306, // 0014 GETMET R6 R1 K6 + 0x58200007, // 0015 LDCONST R8 K7 + 0x7C180400, // 0016 CALL R6 2 + 0x781A0006, // 0017 JMPF R6 #001F + 0x88180109, // 0018 GETMBR R6 R0 K9 + 0x601C0009, // 0019 GETGBL R7 G9 + 0x8C20030A, // 001A GETMET R8 R1 K10 + 0x58280007, // 001B LDCONST R10 K7 + 0x7C200400, // 001C CALL R8 2 + 0x7C1C0200, // 001D CALL R7 1 + 0x901A0E07, // 001E SETMBR R6 K7 R7 + 0x8C180306, // 001F GETMET R6 R1 K6 + 0x58200008, // 0020 LDCONST R8 K8 + 0x7C180400, // 0021 CALL R6 2 + 0x781A0006, // 0022 JMPF R6 #002A + 0x88180109, // 0023 GETMBR R6 R0 K9 + 0x601C0009, // 0024 GETGBL R7 G9 + 0x8C20030A, // 0025 GETMET R8 R1 K10 + 0x58280008, // 0026 LDCONST R10 K8 + 0x7C200400, // 0027 CALL R8 2 + 0x7C1C0200, // 0028 CALL R7 1 + 0x901A1007, // 0029 SETMBR R6 K8 R7 + 0x88180109, // 002A GETMBR R6 R0 K9 + 0x8C180D0B, // 002B GETMET R6 R6 K11 + 0x7C180200, // 002C CALL R6 1 + 0x8C18030C, // 002D GETMET R6 R1 K12 + 0x5820000D, // 002E LDCONST R8 K13 + 0x7C180400, // 002F CALL R6 2 + 0x7002003D, // 0030 JMP #006F + 0x8C180306, // 0031 GETMET R6 R1 K6 + 0x5820000E, // 0032 LDCONST R8 K14 + 0x7C180400, // 0033 CALL R6 2 + 0x781A000C, // 0034 JMPF R6 #0042 + 0xB81A1E00, // 0035 GETNGBL R6 K15 + 0x8C180D10, // 0036 GETMET R6 R6 K16 + 0x60200008, // 0037 GETGBL R8 G8 + 0xB8262400, // 0038 GETNGBL R9 K18 + 0x88241313, // 0039 GETMBR R9 R9 K19 + 0x7C200200, // 003A CALL R8 1 + 0x00222208, // 003B ADD R8 K17 R8 + 0x00201114, // 003C ADD R8 R8 K20 + 0x7C180400, // 003D CALL R6 2 + 0x8C18030C, // 003E GETMET R6 R1 K12 + 0x5820000D, // 003F LDCONST R8 K13 + 0x7C180400, // 0040 CALL R6 2 + 0x7002002C, // 0041 JMP #006F + 0x8C180306, // 0042 GETMET R6 R1 K6 + 0x58200015, // 0043 LDCONST R8 K21 + 0x7C180400, // 0044 CALL R6 2 + 0x781A000C, // 0045 JMPF R6 #0053 + 0xB81A1E00, // 0046 GETNGBL R6 K15 + 0x8C180D10, // 0047 GETMET R6 R6 K16 + 0x60200008, // 0048 GETGBL R8 G8 + 0xB8262400, // 0049 GETNGBL R9 K18 + 0x88241313, // 004A GETMBR R9 R9 K19 + 0x7C200200, // 004B CALL R8 1 + 0x00222208, // 004C ADD R8 K17 R8 + 0x00201116, // 004D ADD R8 R8 K22 + 0x7C180400, // 004E CALL R6 2 + 0x8C18030C, // 004F GETMET R6 R1 K12 + 0x5820000D, // 0050 LDCONST R8 K13 + 0x7C180400, // 0051 CALL R6 2 + 0x7002001B, // 0052 JMP #006F + 0x8C180306, // 0053 GETMET R6 R1 K6 + 0x58200017, // 0054 LDCONST R8 K23 + 0x7C180400, // 0055 CALL R6 2 + 0x781A0017, // 0056 JMPF R6 #006F + 0x88180109, // 0057 GETMBR R6 R0 K9 + 0x88180D18, // 0058 GETMBR R6 R6 K24 + 0x8C180D19, // 0059 GETMET R6 R6 K25 + 0x60200009, // 005A GETGBL R8 G9 + 0x8C24030A, // 005B GETMET R9 R1 K10 + 0x582C0017, // 005C LDCONST R11 K23 + 0x7C240400, // 005D CALL R9 2 + 0x7C200200, // 005E CALL R8 1 + 0x7C180400, // 005F CALL R6 2 + 0x4C1C0000, // 0060 LDNIL R7 + 0x201C0C07, // 0061 NE R7 R6 R7 + 0x781E0008, // 0062 JMPF R7 #006C + 0x881C0109, // 0063 GETMBR R7 R0 K9 + 0x881C0F18, // 0064 GETMBR R7 R7 K24 + 0x8C1C0F1A, // 0065 GETMET R7 R7 K26 + 0x5C240C00, // 0066 MOVE R9 R6 + 0x7C1C0400, // 0067 CALL R7 2 + 0x881C0109, // 0068 GETMBR R7 R0 K9 + 0x881C0F18, // 0069 GETMBR R7 R7 K24 + 0x8C1C0F1B, // 006A GETMET R7 R7 K27 + 0x7C1C0200, // 006B CALL R7 1 + 0x8C1C030C, // 006C GETMET R7 R1 K12 + 0x5824000D, // 006D LDCONST R9 K13 + 0x7C1C0400, // 006E CALL R7 2 + 0xA8040001, // 006F EXBLK 1 1 + 0x7002001D, // 0070 JMP #008F + 0xAC180002, // 0071 CATCH R6 0 2 + 0x7002001A, // 0072 JMP #008E + 0xB8221E00, // 0073 GETNGBL R8 K15 + 0x8C20111C, // 0074 GETMET R8 R8 K28 + 0x8C28051D, // 0075 GETMET R10 R2 K29 + 0x5830001E, // 0076 LDCONST R12 K30 + 0x5C340C00, // 0077 MOVE R13 R6 + 0x5C380E00, // 0078 MOVE R14 R7 + 0x7C280800, // 0079 CALL R10 4 + 0x582C001F, // 007A LDCONST R11 K31 + 0x7C200600, // 007B CALL R8 3 + 0x8C200320, // 007C GETMET R8 R1 K32 + 0x58280021, // 007D LDCONST R10 K33 + 0x7C200400, // 007E CALL R8 2 + 0x8C200322, // 007F GETMET R8 R1 K34 + 0x7C200200, // 0080 CALL R8 1 + 0x8C200323, // 0081 GETMET R8 R1 K35 + 0x8C28051D, // 0082 GETMET R10 R2 K29 + 0x58300024, // 0083 LDCONST R12 K36 + 0x5C340C00, // 0084 MOVE R13 R6 + 0x5C380E00, // 0085 MOVE R14 R7 + 0x7C280800, // 0086 CALL R10 4 + 0x7C200400, // 0087 CALL R8 2 + 0x8C200325, // 0088 GETMET R8 R1 K37 + 0x88280326, // 0089 GETMBR R10 R1 K38 + 0x7C200400, // 008A CALL R8 2 + 0x8C200327, // 008B GETMET R8 R1 K39 + 0x7C200200, // 008C CALL R8 1 + 0x70020000, // 008D JMP #008F + 0xB0080000, // 008E RAISE 2 R0 R0 + 0x80000000, // 008F RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: web_add_config_button +********************************************************************/ +be_local_closure(Matter_UI_web_add_config_button, /* name */ + be_nested_proto( + 5, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(webserver), + /* K1 */ be_nested_str_weak(content_send), + /* K2 */ be_nested_str_weak(_X3Cp_X3E_X3Cform_X20id_X3Dac_X20action_X3D_X27matterc_X27_X20style_X3D_X27display_X3A_X20block_X3B_X27_X20method_X3D_X27get_X27_X3E_X3Cbutton_X3E), + /* K3 */ be_nested_str_weak(matter), + /* K4 */ be_nested_str_weak(_LOGO), + /* K5 */ be_nested_str_weak(_X20Configure_X20Matter_X3C_X2Fbutton_X3E_X3C_X2Fform_X3E_X3C_X2Fp_X3E), + }), + be_str_weak(web_add_config_button), + &be_const_str_solidified, + ( &(const binstruction[12]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x8C080301, // 0001 GETMET R2 R1 K1 + 0x58100002, // 0002 LDCONST R4 K2 + 0x7C080400, // 0003 CALL R2 2 + 0x8C080301, // 0004 GETMET R2 R1 K1 + 0xB8120600, // 0005 GETNGBL R4 K3 + 0x88100904, // 0006 GETMBR R4 R4 K4 + 0x7C080400, // 0007 CALL R2 2 + 0x8C080301, // 0008 GETMET R2 R1 K1 + 0x58100005, // 0009 LDCONST R4 K5 + 0x7C080400, // 000A CALL R2 2 + 0x80000000, // 000B RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: page_qrcode_min_js +********************************************************************/ +be_local_closure(Matter_UI_page_qrcode_min_js, /* name */ + be_nested_proto( + 6, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(webserver), + /* K1 */ be_nested_str_weak(content_open), + /* K2 */ be_nested_str_weak(text_X2Fjavascript), + /* K3 */ be_nested_str_weak(content_send), + /* K4 */ be_nested_str_weak(matter), + /* K5 */ be_nested_str_weak(_QRCODE_MINJS), + }), + be_str_weak(page_qrcode_min_js), + &be_const_str_solidified, + ( &(const binstruction[10]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x8C080301, // 0001 GETMET R2 R1 K1 + 0x541200C7, // 0002 LDINT R4 200 + 0x58140002, // 0003 LDCONST R5 K2 + 0x7C080600, // 0004 CALL R2 3 + 0x8C080303, // 0005 GETMET R2 R1 K3 + 0xB8120800, // 0006 GETNGBL R4 K4 + 0x88100905, // 0007 GETMBR R4 R4 K5 + 0x7C080400, // 0008 CALL R2 2 + 0x80000000, // 0009 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: page_part_mgr +********************************************************************/ +be_local_closure(Matter_UI_page_part_mgr, /* name */ + be_nested_proto( + 6, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[14]) { /* constants */ + /* K0 */ be_nested_str_weak(webserver), + /* K1 */ be_nested_str_weak(string), + /* K2 */ be_nested_str_weak(check_privileged_access), + /* K3 */ be_nested_str_weak(content_start), + /* K4 */ be_nested_str_weak(Matter), + /* K5 */ be_nested_str_weak(content_send_style), + /* K6 */ be_nested_str_weak(content_send), + /* K7 */ be_nested_str_weak(_X3Cscript_X20type_X3D_X22text_X2Fjavascript_X22_X20src_X3D_X22qrcode_X2Emin_X2Ejs_X22_X3E_X3C_X2Fscript_X3E), + /* K8 */ be_nested_str_weak(show_enable), + /* K9 */ be_nested_str_weak(show_commissioning_info), + /* K10 */ be_nested_str_weak(show_session_info), + /* K11 */ be_nested_str_weak(content_button), + /* K12 */ be_nested_str_weak(BUTTON_CONFIGURATION), + /* K13 */ be_nested_str_weak(content_stop), + }), + be_str_weak(page_part_mgr), + &be_const_str_solidified, + ( &(const binstruction[28]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0xA40A0200, // 0001 IMPORT R2 K1 + 0x8C0C0302, // 0002 GETMET R3 R1 K2 + 0x7C0C0200, // 0003 CALL R3 1 + 0x740E0001, // 0004 JMPT R3 #0007 + 0x4C0C0000, // 0005 LDNIL R3 + 0x80040600, // 0006 RET 1 R3 + 0x8C0C0303, // 0007 GETMET R3 R1 K3 + 0x58140004, // 0008 LDCONST R5 K4 + 0x7C0C0400, // 0009 CALL R3 2 + 0x8C0C0305, // 000A GETMET R3 R1 K5 + 0x7C0C0200, // 000B CALL R3 1 + 0x8C0C0306, // 000C GETMET R3 R1 K6 + 0x58140007, // 000D LDCONST R5 K7 + 0x7C0C0400, // 000E CALL R3 2 + 0x8C0C0108, // 000F GETMET R3 R0 K8 + 0x7C0C0200, // 0010 CALL R3 1 + 0x780E0003, // 0011 JMPF R3 #0016 + 0x8C0C0109, // 0012 GETMET R3 R0 K9 + 0x7C0C0200, // 0013 CALL R3 1 + 0x8C0C010A, // 0014 GETMET R3 R0 K10 + 0x7C0C0200, // 0015 CALL R3 1 + 0x8C0C030B, // 0016 GETMET R3 R1 K11 + 0x8814030C, // 0017 GETMBR R5 R1 K12 + 0x7C0C0400, // 0018 CALL R3 2 + 0x8C0C030D, // 0019 GETMET R3 R1 K13 + 0x7C0C0200, // 001A CALL R3 1 + 0x80000000, // 001B RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_UI +********************************************************************/ +be_local_class(Matter_UI, + 1, + NULL, + be_nested_map(10, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(init, -1), be_const_closure(Matter_UI_init_closure) }, + { be_const_key_weak(device, -1), be_const_var(0) }, + { be_const_key_weak(web_add_handler, -1), be_const_closure(Matter_UI_web_add_handler_closure) }, + { be_const_key_weak(page_part_ctl, -1), be_const_closure(Matter_UI_page_part_ctl_closure) }, + { be_const_key_weak(show_enable, -1), be_const_closure(Matter_UI_show_enable_closure) }, + { be_const_key_weak(show_commissioning_info, 7), be_const_closure(Matter_UI_show_commissioning_info_closure) }, + { be_const_key_weak(show_session_info, 3), be_const_closure(Matter_UI_show_session_info_closure) }, + { be_const_key_weak(web_add_config_button, 0), be_const_closure(Matter_UI_web_add_config_button_closure) }, + { be_const_key_weak(page_qrcode_min_js, -1), be_const_closure(Matter_UI_page_qrcode_min_js_closure) }, + { be_const_key_weak(page_part_mgr, -1), be_const_closure(Matter_UI_page_part_mgr_closure) }, + })), + be_str_weak(Matter_UI) +); +/*******************************************************************/ + +void be_load_Matter_UI_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_UI); + be_setglobal(vm, "Matter_UI"); + be_pop(vm, 1); +} +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_inspect.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_inspect.h new file mode 100644 index 000000000..3c038fc3a --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_inspect.h @@ -0,0 +1,189 @@ +/* Solidification of Matter_inspect.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +/******************************************************************** +** Solidified function: sort +********************************************************************/ +be_local_closure(matter_sort, /* name */ + be_nested_proto( + 6, /* nstack */ + 1, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_const_int(1), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str_weak(stop_iteration), + }), + be_str_weak(sort), + &be_const_str_solidified, + ( &(const binstruction[29]) { /* code */ + 0x60040010, // 0000 GETGBL R1 G16 + 0x6008000C, // 0001 GETGBL R2 G12 + 0x5C0C0000, // 0002 MOVE R3 R0 + 0x7C080200, // 0003 CALL R2 1 + 0x04080500, // 0004 SUB R2 R2 K0 + 0x400A0002, // 0005 CONNECT R2 K0 R2 + 0x7C040200, // 0006 CALL R1 1 + 0xA8020010, // 0007 EXBLK 0 #0019 + 0x5C080200, // 0008 MOVE R2 R1 + 0x7C080000, // 0009 CALL R2 0 + 0x940C0002, // 000A GETIDX R3 R0 R2 + 0x5C100400, // 000B MOVE R4 R2 + 0x24140901, // 000C GT R5 R4 K1 + 0x78160008, // 000D JMPF R5 #0017 + 0x04140900, // 000E SUB R5 R4 K0 + 0x94140005, // 000F GETIDX R5 R0 R5 + 0x24140A03, // 0010 GT R5 R5 R3 + 0x78160004, // 0011 JMPF R5 #0017 + 0x04140900, // 0012 SUB R5 R4 K0 + 0x94140005, // 0013 GETIDX R5 R0 R5 + 0x98000805, // 0014 SETIDX R0 R4 R5 + 0x04100900, // 0015 SUB R4 R4 K0 + 0x7001FFF4, // 0016 JMP #000C + 0x98000803, // 0017 SETIDX R0 R4 R3 + 0x7001FFEE, // 0018 JMP #0008 + 0x58040002, // 0019 LDCONST R1 K2 + 0xAC040200, // 001A CATCH R1 1 0 + 0xB0080000, // 001B RAISE 2 R0 R0 + 0x80040000, // 001C RET 1 R0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: inspect +********************************************************************/ +be_local_closure(matter_inspect, /* name */ + be_nested_proto( + 16, /* nstack */ + 1, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[17]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(introspect), + /* K2 */ be_nested_str_weak(members), + /* K3 */ be_nested_str_weak(get), + /* K4 */ be_nested_str_weak(function), + /* K5 */ be_nested_str_weak(push), + /* K6 */ be_nested_str_weak(stop_iteration), + /* K7 */ be_nested_str_weak(matter), + /* K8 */ be_nested_str_weak(sort), + /* K9 */ be_nested_str_weak(format), + /* K10 */ be_nested_str_weak(_X27_X25s_X27_X3A_X20_X25s), + /* K11 */ be_nested_str_weak(_X7B), + /* K12 */ be_nested_str_weak(concat), + /* K13 */ be_nested_str_weak(_X2C_X20), + /* K14 */ be_nested_str_weak(_X7D), + /* K15 */ be_nested_str_weak(Exception_X3A), + /* K16 */ be_nested_str_weak(_X7C), + }), + be_str_weak(inspect), + &be_const_str_solidified, + ( &(const binstruction[85]) { /* code */ + 0xA8020044, // 0000 EXBLK 0 #0046 + 0xA4060000, // 0001 IMPORT R1 K0 + 0xA40A0200, // 0002 IMPORT R2 K1 + 0x600C0012, // 0003 GETGBL R3 G18 + 0x7C0C0000, // 0004 CALL R3 0 + 0x60100010, // 0005 GETGBL R4 G16 + 0x8C140502, // 0006 GETMET R5 R2 K2 + 0x5C1C0000, // 0007 MOVE R7 R0 + 0x7C140400, // 0008 CALL R5 2 + 0x7C100200, // 0009 CALL R4 1 + 0xA802000E, // 000A EXBLK 0 #001A + 0x5C140800, // 000B MOVE R5 R4 + 0x7C140000, // 000C CALL R5 0 + 0x8C180503, // 000D GETMET R6 R2 K3 + 0x5C200000, // 000E MOVE R8 R0 + 0x5C240A00, // 000F MOVE R9 R5 + 0x7C180600, // 0010 CALL R6 3 + 0x601C0004, // 0011 GETGBL R7 G4 + 0x5C200C00, // 0012 MOVE R8 R6 + 0x7C1C0200, // 0013 CALL R7 1 + 0x201C0F04, // 0014 NE R7 R7 K4 + 0x781E0002, // 0015 JMPF R7 #0019 + 0x8C1C0705, // 0016 GETMET R7 R3 K5 + 0x5C240A00, // 0017 MOVE R9 R5 + 0x7C1C0400, // 0018 CALL R7 2 + 0x7001FFF0, // 0019 JMP #000B + 0x58100006, // 001A LDCONST R4 K6 + 0xAC100200, // 001B CATCH R4 1 0 + 0xB0080000, // 001C RAISE 2 R0 R0 + 0xB8120E00, // 001D GETNGBL R4 K7 + 0x8C100908, // 001E GETMET R4 R4 K8 + 0x5C180600, // 001F MOVE R6 R3 + 0x7C100400, // 0020 CALL R4 2 + 0x5C0C0800, // 0021 MOVE R3 R4 + 0x60100012, // 0022 GETGBL R4 G18 + 0x7C100000, // 0023 CALL R4 0 + 0x60140010, // 0024 GETGBL R5 G16 + 0x5C180600, // 0025 MOVE R6 R3 + 0x7C140200, // 0026 CALL R5 1 + 0xA8020011, // 0027 EXBLK 0 #003A + 0x5C180A00, // 0028 MOVE R6 R5 + 0x7C180000, // 0029 CALL R6 0 + 0x8C1C0503, // 002A GETMET R7 R2 K3 + 0x5C240000, // 002B MOVE R9 R0 + 0x5C280C00, // 002C MOVE R10 R6 + 0x7C1C0600, // 002D CALL R7 3 + 0x8C200905, // 002E GETMET R8 R4 K5 + 0x8C280309, // 002F GETMET R10 R1 K9 + 0x5830000A, // 0030 LDCONST R12 K10 + 0x60340008, // 0031 GETGBL R13 G8 + 0x5C380C00, // 0032 MOVE R14 R6 + 0x7C340200, // 0033 CALL R13 1 + 0x60380008, // 0034 GETGBL R14 G8 + 0x5C3C0E00, // 0035 MOVE R15 R7 + 0x7C380200, // 0036 CALL R14 1 + 0x7C280800, // 0037 CALL R10 4 + 0x7C200400, // 0038 CALL R8 2 + 0x7001FFED, // 0039 JMP #0028 + 0x58140006, // 003A LDCONST R5 K6 + 0xAC140200, // 003B CATCH R5 1 0 + 0xB0080000, // 003C RAISE 2 R0 R0 + 0x8C14090C, // 003D GETMET R5 R4 K12 + 0x581C000D, // 003E LDCONST R7 K13 + 0x7C140400, // 003F CALL R5 2 + 0x00161605, // 0040 ADD R5 K11 R5 + 0x00140B0E, // 0041 ADD R5 R5 K14 + 0xA8040001, // 0042 EXBLK 1 1 + 0x80040A00, // 0043 RET 1 R5 + 0xA8040001, // 0044 EXBLK 1 1 + 0x7002000D, // 0045 JMP #0054 + 0xAC040002, // 0046 CATCH R1 0 2 + 0x7002000A, // 0047 JMP #0053 + 0x600C0008, // 0048 GETGBL R3 G8 + 0x5C100200, // 0049 MOVE R4 R1 + 0x7C0C0200, // 004A CALL R3 1 + 0x000E1E03, // 004B ADD R3 K15 R3 + 0x000C0710, // 004C ADD R3 R3 K16 + 0x60100008, // 004D GETGBL R4 G8 + 0x5C140400, // 004E MOVE R5 R2 + 0x7C100200, // 004F CALL R4 1 + 0x000C0604, // 0050 ADD R3 R3 R4 + 0x80040600, // 0051 RET 1 R3 + 0x70020000, // 0052 JMP #0054 + 0xB0080000, // 0053 RAISE 2 R0 R0 + 0x80000000, // 0054 RET 0 + }) + ) +); +/*******************************************************************/ + +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_matter.h b/lib/libesp32/berry_matter/src/solidify/solidified_matter.h new file mode 100644 index 000000000..e0e4862f0 --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_matter.h @@ -0,0 +1,7 @@ +/* Solidification of matter.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_tasmota/solidify_all.be b/lib/libesp32/berry_tasmota/solidify_all.be index 7bfeae9dd..81f392870 100755 --- a/lib/libesp32/berry_tasmota/solidify_all.be +++ b/lib/libesp32/berry_tasmota/solidify_all.be @@ -14,10 +14,11 @@ import sys sys.path().push('src/embedded') # allow to import from src/embedded # globals that need to exist to make compilation succeed -var globs = "path,ctypes_bytes_dyn,tasmota,ccronexpr,gpio,light,webclient,load,MD5,lv,light_state," +var globs = "path,ctypes_bytes_dyn,tasmota,ccronexpr,gpio,light,webclient,load,MD5,lv,light_state,udp," "lv_clock,lv_clock_icon,lv_signal_arcs,lv_signal_bars,lv_wifi_arcs_icon,lv_wifi_arcs," "lv_wifi_bars_icon,lv_wifi_bars," - "_lvgl" + "_lvgl," + "int64" for g:string.split(globs, ",") global.(g) = nil diff --git a/lib/libesp32/berry_tasmota/src/embedded/autoconf_module.be b/lib/libesp32/berry_tasmota/src/embedded/autoconf_module.be index 80c3579ba..d285ee533 100644 --- a/lib/libesp32/berry_tasmota/src/embedded/autoconf_module.be +++ b/lib/libesp32/berry_tasmota/src/embedded/autoconf_module.be @@ -138,7 +138,7 @@ autoconf_module.init = def (m) # #################################################################################################### # Init web handlers # #################################################################################################### - # Displays a "Autocong" button on the configuration page + # Displays a "Autoconf" button on the configuration page def web_add_config_button() import webserver webserver.content_send("

") diff --git a/pio-tools/gen-berry-structures.py b/pio-tools/gen-berry-structures.py index de975a8e5..923ff723b 100644 --- a/pio-tools/gen-berry-structures.py +++ b/pio-tools/gen-berry-structures.py @@ -16,6 +16,6 @@ for filePath in fileList: # print("Deleting file : ", filePath) except: print("Error while deleting file : ", filePath) -cmd = (env["PYTHONEXE"],join("tools","coc","coc"),"-o","generate","src","default",join("..","berry_tasmota","src"),join("..","berry_tasmota","src","solidify"),join("..","berry_mapping","src"),join("..","berry_int64","src"),join("..","..","libesp32_lvgl","lv_binding_berry","src"),join("..","..","libesp32_lvgl","lv_binding_berry","src","solidify"),join("..","..","libesp32_lvgl","lv_binding_berry","generate"),"-c",join("default","berry_conf.h")) +cmd = (env["PYTHONEXE"],join("tools","coc","coc"),"-o","generate","src","default",join("..","berry_tasmota","src"),join("..","berry_matter","src","solidify"),join("..","berry_matter","src"),join("..","berry_tasmota","src","solidify"),join("..","berry_mapping","src"),join("..","berry_int64","src"),join("..","..","libesp32_lvgl","lv_binding_berry","src"),join("..","..","libesp32_lvgl","lv_binding_berry","src","solidify"),join("..","..","libesp32_lvgl","lv_binding_berry","generate"),"-c",join("default","berry_conf.h")) returncode = subprocess.call(cmd, shell=False) os.chdir(CURRENT_DIR) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_7_berry_embedded.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_7_berry_embedded.ino index 33c7692a6..f9e8a3db9 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_7_berry_embedded.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_7_berry_embedded.ino @@ -88,6 +88,11 @@ const char berry_prog[] = "import debug " "import solidify " #endif + +#ifdef USE_MATTER_DEVICE + "import matter " + "global.matter_device = matter.Device() " +#endif ; #endif // USE_BERRY diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_9_berry.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_9_berry.ino index 7bb20821c..d6e9fabf5 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_9_berry.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_9_berry.ino @@ -24,6 +24,9 @@ #include #include "berry_tasmota.h" +#ifdef USE_MATTER + #include "berry_matter.h" +#endif #include "be_vm.h" #include "ZipReadFS.h" #include "ccronexpr.h" From a581fc237d7a103ec0dcba396d4f3136a8807d33 Mon Sep 17 00:00:00 2001 From: bovirus <1262554+bovirus@users.noreply.github.com> Date: Sat, 4 Feb 2023 16:09:56 +0100 Subject: [PATCH 222/262] Italian language update (#17877) --- tasmota/language/it_IT.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tasmota/language/it_IT.h b/tasmota/language/it_IT.h index fc7f1ccc6..cd084b993 100644 --- a/tasmota/language/it_IT.h +++ b/tasmota/language/it_IT.h @@ -28,7 +28,7 @@ * Use online command StateText to translate ON, OFF, HOLD and TOGGLE. * Use online command Prefix to translate cmnd, stat and tele. * - * Updated until v9.4.0.1 - Last update 09.01.2023 + * Updated until v9.4.0.1 - Last update 04.02.2023 \*********************************************************************/ #define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -919,9 +919,9 @@ #define D_SENSOR_ME007_RX "ME007 - RX" #define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr - TX" #define D_SENSOR_TUYAMCUBR_RX "TuyaMCUBr - RX" -#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" -#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" -#define D_SENSOR_BIOPDU_BIT "BioPDU Bit" +#define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX - TX" +#define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 - RX" +#define D_SENSOR_BIOPDU_BIT "BioPDU Bit" // Units #define D_UNIT_AMPERE "A" From cfd34aa02cb18e46f86daf6d1bae0fb59fee4d0d Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sat, 4 Feb 2023 17:48:53 +0100 Subject: [PATCH 223/262] Fix Shelly Pro 4PM issues - Fix random ADE7935 measurements - Fix relay 1 toggle on restart - Add Shelly Pro 4PM display.ini --- .../displaydesc/ST7735S_Pro4PM_display.ini | 35 +++++++++++++++++++ .../tasmota_xdrv_driver/xdrv_13_display.ino | 19 +++++++--- .../xdrv_88_esp32_shelly_pro_v2.ino | 3 +- .../tasmota_xnrg_energy/xnrg_07_ade7953.ino | 21 +++++++---- 4 files changed, 66 insertions(+), 12 deletions(-) create mode 100644 tasmota/displaydesc/ST7735S_Pro4PM_display.ini diff --git a/tasmota/displaydesc/ST7735S_Pro4PM_display.ini b/tasmota/displaydesc/ST7735S_Pro4PM_display.ini new file mode 100644 index 000000000..46cb6a804 --- /dev/null +++ b/tasmota/displaydesc/ST7735S_Pro4PM_display.ini @@ -0,0 +1,35 @@ +:H,PRO_4PM,160,128,16,SPI,3,0,15,13,2,12,*,*,20 +:S,2,1,1,0,20,20 +:I +01,80 +11,80 +B1,3,01,2C,2D +B2,3,01,2C,2D +B3,6,01,2C,2D,01,2C,2D +B4,1,07 +C0,3,A2,04,84 +C1,1,C5 +C2,2,0A,00 +C3,2,8A,2A +C4,2,8A,EE +C5,1,0E +20,0 +36,1,C8 +3A,1,05 +2A,4,00,02,00,7F +2B,4,00,01,00,7F +E0,10,02,1C,07,12,37,32,29,2D,29,25,2B,39,00,01,03,10 +E1,10,03,1D,07,06,2E,2C,29,2D,2E,2E,37,3F,00,00,02,10 +13,80 +29,80 +:o,28 +:O,29 +:A,2A,2B,2C,16 +:R,36 +:0,68,00,00,00 +:1,CC,1A,01,01 +:2,A8,01,1A,02 +:3,08,1A,01,03 +:i,21,20 +:B,60,1 +# \ No newline at end of file diff --git a/tasmota/tasmota_xdrv_driver/xdrv_13_display.ino b/tasmota/tasmota_xdrv_driver/xdrv_13_display.ino index 05bc7db16..b956ac6cc 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_13_display.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_13_display.ino @@ -1838,14 +1838,21 @@ void DisplayLocalSensor(void) * Public \*********************************************************************************************/ -void DisplayInitDriver(void) -{ +void DisplayInitDriver(void) { + uint8_t devices_present = TasmotaGlobal.devices_present; // Save devices_present + TasmotaGlobal.devices_present++; + if (!PinUsed(GPIO_BACKLIGHT)) { + if (TasmotaGlobal.light_type && (4 == Settings->display_model)) { + TasmotaGlobal.devices_present--; // Assume PWM channel is used for backlight + } + } + disp_device = TasmotaGlobal.devices_present; // Set display device + XdspCall(FUNC_DISPLAY_INIT_DRIVER); // AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "Display model %d"), Settings->display_model); if (Settings->display_model) { -// ApplyDisplayDimmer(); // Not allowed here. Way too early in initi sequence. IE power state has not even been set at this point in time #ifdef USE_MULTI_DISPLAY Set_display(0); @@ -1874,6 +1881,7 @@ void DisplayInitDriver(void) for (uint8_t count = 0; count < NUM_GRAPHS; count++) { graph[count] = 0; } #endif +/* TasmotaGlobal.devices_present++; if (!PinUsed(GPIO_BACKLIGHT)) { if (TasmotaGlobal.light_type && (4 == Settings->display_model)) { @@ -1881,12 +1889,16 @@ void DisplayInitDriver(void) } } disp_device = TasmotaGlobal.devices_present; +*/ #ifndef USE_DISPLAY_MODES1TO5 Settings->display_mode = 0; #else DisplayLogBufferInit(); #endif // USE_DISPLAY_MODES1TO5 + } else { + TasmotaGlobal.devices_present = devices_present; // Restore devices_present + disp_device = 0; } } @@ -2009,7 +2021,6 @@ void ApplyDisplayDimmer(void) { // still call Berry virtual display in case it is not managed entirely by renderer Xdsp18(FUNC_DISPLAY_DIM); #endif // USE_BERRY - } else { XdspCall(FUNC_DISPLAY_DIM); } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v2.ino b/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v2.ino index 89de679c3..a5f4e63f9 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v2.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v2.ino @@ -27,8 +27,7 @@ * {"NAME":"Shelly Pro 1PM","GPIO":[9568,1,9472,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,3459,0,0,32,4736,0,160,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350"} * {"NAME":"Shelly Pro 2","GPIO":[0,1,0,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,0,0,0,32,4736,4737,160,161],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350;AdcParam2 2,5600,4700,3350"} * {"NAME":"Shelly Pro 2PM","GPIO":[9568,1,9472,1,768,0,0,0,672,704,736,9569,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,3460,0,0,32,4736,4737,160,161],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350;AdcParam2 2,5600,4700,3350"} - * {"NAME":"Shelly Pro 4PM","GPIO":[769,1,1,1,9568,0,0,0,1,705,9569,737,768,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,6214,736,704,3461,0,4736,1,0,672],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350"} - * {"NAME":"Shelly Pro 4PM No display","GPIO":[1,1,1,1,9568,0,0,0,1,1,9569,1,768,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,6214,736,704,3461,0,4736,1,0,672],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350"} + * {"NAME":"Shelly Pro 4PM","GPIO":[0,6210,0,6214,9568,0,0,0,0,0,9569,0,768,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,736,704,3461,0,4736,0,0,672],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350"} * * Shelly Pro 1/2 uses SPI to control one 74HC595 for relays/leds and one ADE7953 (1PM) or two ADE7953 (2PM) for energy monitoring * Shelly Pro 4 uses an SPI to control one MCP23S17 for buttons/switches/relays/leds and two ADE7953 for energy monitoring and a second SPI for the display diff --git a/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino b/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino index 0eda31567..dc088a947 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino @@ -32,7 +32,7 @@ * {"NAME":"Shelly Plus 2PM PCB v0.1.9","GPIO":[320,0,0,0,32,192,0,0,225,224,0,0,0,0,193,0,0,0,0,0,0,608,640,3458,0,0,0,0,0,9472,0,4736,0,0,0,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,10000,10000,3350"} * {"NAME":"Shelly Pro 1PM","GPIO":[9568,1,9472,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,3459,0,0,32,4736,0,160,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350"} * {"NAME":"Shelly Pro 2PM","GPIO":[9568,1,9472,1,768,0,0,0,672,704,736,9569,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,3460,0,0,32,4736,4737,160,161],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350;AdcParam2 2,5600,4700,3350"} - * {"NAME":"Shelly Pro 4PM No display","GPIO":[1,1,1,1,9568,0,0,0,1,1,9569,1,768,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,6214,736,704,3461,0,4736,1,0,672],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350"} + * {"NAME":"Shelly Pro 4PM","GPIO":[0,6210,0,6214,9568,0,0,0,0,0,9569,0,768,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,736,704,3461,0,4736,0,0,672],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350"} * * Based on datasheet from https://www.analog.com/en/products/ade7953.html * @@ -241,6 +241,7 @@ struct Ade7953 { SPISettings spi_settings; int8_t pin_cs[ADE7953_MAX_CHANNEL / 2]; #endif // USE_ESP32_SPI + bool use_spi; } Ade7953; /*********************************************************************************************/ @@ -283,7 +284,7 @@ void Ade7953Write(uint16_t reg, uint32_t val) { // AddLog(LOG_LEVEL_DEBUG, PSTR("DBG: Write %08X"), val); #ifdef USE_ESP32_SPI - if (Ade7953.pin_cs[0] >= 0) { + if (Ade7953.use_spi) { Ade7953SpiEnable(); SPI.transfer16(reg); SPI.transfer(0x00); // Write @@ -313,7 +314,7 @@ int32_t Ade7953Read(uint16_t reg) { int size = Ade7953RegSize(reg); if (size) { #ifdef USE_ESP32_SPI - if (Ade7953.pin_cs[0] >= 0) { + if (Ade7953.use_spi) { Ade7953SpiEnable(); SPI.transfer16(reg); SPI.transfer(0x80); // Read @@ -450,7 +451,7 @@ void Ade7953GetData(void) { int32_t reg[ADE7953_MAX_CHANNEL][ADE7953_REGISTERS]; #ifdef USE_ESP32_SPI - if (Ade7953.pin_cs[0] >= 0) { + if (Ade7953.use_spi) { uint32_t channel = 0; for (uint32_t chip = 0; chip < ADE7953_MAX_CHANNEL / 2; chip++) { if (Ade7953.pin_cs[chip] < 0) { continue; } @@ -705,6 +706,7 @@ void Ade7953DrvInit(void) { Ade7953.model = ADE7953_SHELLY_PRO_1PM; } Ade7953.cs_index = 0; + Ade7953.use_spi = true; SPI.begin(Pin(GPIO_SPI_CLK), Pin(GPIO_SPI_MISO), Pin(GPIO_SPI_MOSI), -1); Ade7953.spi_settings = SPISettings(1000000, MSBFIRST, SPI_MODE0); // Set up SPI at 1MHz, MSB first, Capture at rising edge AddLog(LOG_LEVEL_INFO, PSTR("SPI: ADE7953 found")); @@ -820,8 +822,15 @@ bool Xnrg07(uint32_t function) { bool result = false; switch (function) { - case FUNC_ENERGY_EVERY_SECOND: - Ade7953EnergyEverySecond(); + case FUNC_ENERGY_EVERY_SECOND: // Use energy interrupt timer (fails on SPI) + if (!Ade7953.use_spi) { // No SPI + Ade7953EnergyEverySecond(); + } + break; + case FUNC_EVERY_SECOND: // Use loop timer (without interrupt) + if (Ade7953.use_spi) { // SPI + Ade7953EnergyEverySecond(); + } break; case FUNC_COMMAND: result = Ade7953Command(); From 36b9e4ab78f37fd59ea583a8df5f272b924a1304 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sat, 4 Feb 2023 18:24:21 +0100 Subject: [PATCH 224/262] Fix universal display driver too early power control --- .../tasmota_xdrv_driver/xdrv_13_display.ino | 19 ++++--------------- .../xdsp_17_universal.ino | 2 +- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_13_display.ino b/tasmota/tasmota_xdrv_driver/xdrv_13_display.ino index b956ac6cc..05bc7db16 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_13_display.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_13_display.ino @@ -1838,21 +1838,14 @@ void DisplayLocalSensor(void) * Public \*********************************************************************************************/ -void DisplayInitDriver(void) { - uint8_t devices_present = TasmotaGlobal.devices_present; // Save devices_present - TasmotaGlobal.devices_present++; - if (!PinUsed(GPIO_BACKLIGHT)) { - if (TasmotaGlobal.light_type && (4 == Settings->display_model)) { - TasmotaGlobal.devices_present--; // Assume PWM channel is used for backlight - } - } - disp_device = TasmotaGlobal.devices_present; // Set display device - +void DisplayInitDriver(void) +{ XdspCall(FUNC_DISPLAY_INIT_DRIVER); // AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "Display model %d"), Settings->display_model); if (Settings->display_model) { +// ApplyDisplayDimmer(); // Not allowed here. Way too early in initi sequence. IE power state has not even been set at this point in time #ifdef USE_MULTI_DISPLAY Set_display(0); @@ -1881,7 +1874,6 @@ void DisplayInitDriver(void) { for (uint8_t count = 0; count < NUM_GRAPHS; count++) { graph[count] = 0; } #endif -/* TasmotaGlobal.devices_present++; if (!PinUsed(GPIO_BACKLIGHT)) { if (TasmotaGlobal.light_type && (4 == Settings->display_model)) { @@ -1889,16 +1881,12 @@ void DisplayInitDriver(void) { } } disp_device = TasmotaGlobal.devices_present; -*/ #ifndef USE_DISPLAY_MODES1TO5 Settings->display_mode = 0; #else DisplayLogBufferInit(); #endif // USE_DISPLAY_MODES1TO5 - } else { - TasmotaGlobal.devices_present = devices_present; // Restore devices_present - disp_device = 0; } } @@ -2021,6 +2009,7 @@ void ApplyDisplayDimmer(void) { // still call Berry virtual display in case it is not managed entirely by renderer Xdsp18(FUNC_DISPLAY_DIM); #endif // USE_BERRY + } else { XdspCall(FUNC_DISPLAY_DIM); } diff --git a/tasmota/tasmota_xdsp_display/xdsp_17_universal.ino b/tasmota/tasmota_xdsp_display/xdsp_17_universal.ino index c3154cd60..68dd09af1 100644 --- a/tasmota/tasmota_xdsp_display/xdsp_17_universal.ino +++ b/tasmota/tasmota_xdsp_display/xdsp_17_universal.ino @@ -436,7 +436,7 @@ int8_t cs; Settings->display_width = renderer->width(); Settings->display_height = renderer->height(); - ApplyDisplayDimmer(); +// ApplyDisplayDimmer(); // Not allowed here. Way too early in initi sequence. IE power state has not even been set at this point in time #ifdef SHOW_SPLASH if (!Settings->flag5.display_no_splash) { From 9bf1bd93c049dbe511ba74d7c2c749ecd64c85cd Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 5 Feb 2023 12:52:21 +0100 Subject: [PATCH 225/262] Add some display safeguards fixing power issues at restart --- .../tasmota_xdrv_driver/xdrv_13_display.ino | 22 ++++++++++++------- .../xdsp_17_universal.ino | 2 +- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_13_display.ino b/tasmota/tasmota_xdrv_driver/xdrv_13_display.ino index 05bc7db16..5c4ce996e 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_13_display.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_13_display.ino @@ -237,7 +237,7 @@ uint16_t dsp_rad; uint16_t dsp_color; int16_t dsp_len; -uint8_t disp_power = 0; +int8_t disp_power = -1; uint8_t disp_device = 0; uint8_t disp_refresh = 1; uint8_t disp_autodraw = 1; @@ -293,9 +293,10 @@ void DisplayDrawStringAt(uint16_t x, uint16_t y, char *str, uint16_t color, uint XdspCall(FUNC_DISPLAY_DRAW_STRING); } -void DisplayOnOff(uint8_t on) -{ - ExecuteCommandPower(disp_device, on, SRC_DISPLAY); +void DisplayOnOff(uint8_t on) { + if (disp_device) { + ExecuteCommandPower(disp_device, on, SRC_DISPLAY); + } } /*-------------------------------------------------------------------------------------------*/ @@ -1838,8 +1839,10 @@ void DisplayLocalSensor(void) * Public \*********************************************************************************************/ -void DisplayInitDriver(void) -{ +void DisplayInitDriver(void) { + + + XdspCall(FUNC_DISPLAY_INIT_DRIVER); // AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "Display model %d"), Settings->display_model); @@ -1890,8 +1893,9 @@ void DisplayInitDriver(void) } } -void DisplaySetPower(void) -{ +void DisplaySetPower(void) { + if (!disp_device) { return; } // Not initialized yet + disp_power = bitRead(XdrvMailbox.index, disp_device -1); //AddLog(LOG_LEVEL_DEBUG, PSTR("DSP: Power %d"), disp_power); @@ -1995,6 +1999,8 @@ void CmndDisplayMode(void) { // Apply the current display dimmer void ApplyDisplayDimmer(void) { + if ((disp_power < 0) || !disp_device) { return; } // Not initialized yet + uint8_t dimmer8 = changeUIntScale(GetDisplayDimmer(), 0, 100, 0, 255); uint16_t dimmer10_gamma = ledGamma10(dimmer8); if (dimmer8 && !(disp_power)) { diff --git a/tasmota/tasmota_xdsp_display/xdsp_17_universal.ino b/tasmota/tasmota_xdsp_display/xdsp_17_universal.ino index 68dd09af1..c3154cd60 100644 --- a/tasmota/tasmota_xdsp_display/xdsp_17_universal.ino +++ b/tasmota/tasmota_xdsp_display/xdsp_17_universal.ino @@ -436,7 +436,7 @@ int8_t cs; Settings->display_width = renderer->width(); Settings->display_height = renderer->height(); -// ApplyDisplayDimmer(); // Not allowed here. Way too early in initi sequence. IE power state has not even been set at this point in time + ApplyDisplayDimmer(); #ifdef SHOW_SPLASH if (!Settings->flag5.display_no_splash) { From 5025e86d75f77e9badf963850714c90148dfe6fd Mon Sep 17 00:00:00 2001 From: sfromis <47082390+sfromis@users.noreply.github.com> Date: Sun, 5 Feb 2023 13:34:02 +0100 Subject: [PATCH 226/262] Meaning of SetOption15 swapped (#17884) Noticed that the text incorrectly said value 1 for direct PWM control, and 0 for the default as a light. --- tools/decode-status.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/decode-status.py b/tools/decode-status.py index 52ddfc257..67f740ad6 100755 --- a/tools/decode-status.py +++ b/tools/decode-status.py @@ -65,7 +65,7 @@ a_setoption = [[ "(Settings) Switch between dynamic (0) or fixed (1) slot flash save location", "(Button) Support only single press (1) to speed up button press recognition", "(Interlock) Power interlock mode", - "(Light) Switch between commands PWM (1) or COLOR/DIMMER/CT/CHANNEL (0)", + "(Light) Switch between commands PWM (0) or COLOR/DIMMER/CT/CHANNEL (1)", "(WS2812) Switch between clockwise (0) or counter-clockwise (1)", "(Light) Switch between decimal (1) or hexadecimal (0) output", "(Light) Pair light signal (1) with CO2 sensor", From 8bc03bbc0677ca2759ee85864354a4f5c11058a2 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 5 Feb 2023 14:29:42 +0100 Subject: [PATCH 227/262] Bump version v12.3.1.6 - Add ESP32 preliminary support for Matter protocol, milestone 1 (commissioning) by Stephan Hadinger - Add basic support for Shelly Pro 4PM --- CHANGELOG.md | 18 +- RELEASENOTES.md | 8 +- tasmota/include/tasmota_types.h | 2 +- tasmota/include/tasmota_version.h | 2 +- tasmota/tasmota_support/support_features.ino | 5 +- .../xdrv_88_esp32_shelly_pro.ino | 463 +++++++++++++--- .../xdrv_88_esp32_shelly_pro_v2.ino | 498 ------------------ .../tasmota_xnrg_energy/xnrg_24_biopdu.ino | 21 +- tools/decode-status.py | 7 +- 9 files changed, 432 insertions(+), 592 deletions(-) delete mode 100644 tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v2.ino diff --git a/CHANGELOG.md b/CHANGELOG.md index 3377495c3..7d791e597 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,15 +3,27 @@ All notable changes to this project will be documented in this file. ## [Unreleased] - Development +## [12.3.1.6] +### Added +- ESP32 preliminary support for Matter protocol, milestone 1 (commissioning) by Stephan Hadinger +- Basic support for Shelly Pro 4PM + +### Breaking Changed + +### Changed + +### Fixed + +### Removed + ## [12.3.1.5] ### Added - ESP32 support for eigth energy phases/channels - ESP32 command ``EnergyCols 1..8`` to change number of GUI columns - ESP32 command ``EnergyDisplay 1..3`` to change GUI column presentation -- support for SEN5X gas and air quality sensor by Tyeth Gundry (#17736) +- Support for SEN5X gas and air quality sensor by Tyeth Gundry (#17736) - Berry add ``mdns`` advanced features and query - ESP32 support for Biomine BioPDU 625x12 (#17857) -- ESP32 preliminary support for Matter protocol, milestone 1 (commissioning) ### Breaking Changed - Berry energy_ctypes changed with new energy driver @@ -27,8 +39,6 @@ All notable changes to this project will be documented in this file. - Broken I2C priority regression from v12.3.1.3 (#17810) - Energy usage and return migrated too small (/10000) regression from v12.3.1.3 -### Removed - ## [12.3.1.4] 20230127 ### Added - Berry ``crypto.EC_P256`` ECDSA signature (required by Matter protocol) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 5f2183fd9..d78f13e59 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -110,24 +110,28 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm [Complete list](BUILDS.md) of available feature and sensors. -## Changelog v12.3.1.5 +## Changelog v12.3.1.6 ### Added -- Support for up to 3 single phase modbus energy monitoring device using generic Energy Modbus driver- Support for RGB displays [#17414](https://github.com/arendst/Tasmota/issues/17414) +- Support for up to 3 (ESP8266) or 8 (ESP32) phase modbus energy monitoring device using generic Energy Modbus driver +- Support for RGB displays [#17414](https://github.com/arendst/Tasmota/issues/17414) - Support for IPv6 DNS records (AAAA) and IPv6 ``Ping`` for ESP32 and ESP8266 [#17417](https://github.com/arendst/Tasmota/issues/17417) - Support for IPv6 only networks on Ethernet (not yet Wifi) - Support for TM1650 display as used in some clocks by Stefan Oskamp [#17594](https://github.com/arendst/Tasmota/issues/17594) - Support for PCA9632 4-channel 8-bit PWM driver as light driver by Pascal Heinrich [#17557](https://github.com/arendst/Tasmota/issues/17557) - support for SEN5X gas and air quality sensor by Tyeth Gundry [#17736](https://github.com/arendst/Tasmota/issues/17736) +- Basic support for Shelly Pro 4PM - Berry support for ``crypto.SHA256`` [#17430](https://github.com/arendst/Tasmota/issues/17430) - Berry crypto add ``EC_P256`` and ``PBKDF2_HMAC_SHA256`` algorithms required by Matter protocol [#17473](https://github.com/arendst/Tasmota/issues/17473) - Berry crypto add ``random`` to generate series of random bytes - Berry crypto add ``HKDF_HMAC_SHA256`` - Berry crypto add ``SPAKE2P_Matter`` for Matter support +- Berry add ``mdns`` advanced features and query - ESP32 command ``EnergyCols 1..8`` to change number of GUI columns - ESP32 command ``EnergyDisplay 1..3`` to change GUI column presentation - ESP32 support for eigth energy phases/channels - ESP32 support for BMPxxx sensors on two I2C busses [#17643](https://github.com/arendst/Tasmota/issues/17643) - ESP32 support for Biomine BioPDU 625x12 [#17857](https://github.com/arendst/Tasmota/issues/17857) +- ESP32 preliminary support for Matter protocol, milestone 1 (commissioning) by Stephan Hadinger ### Breaking Changed diff --git a/tasmota/include/tasmota_types.h b/tasmota/include/tasmota_types.h index bbb4fddbc..757a9f2bd 100644 --- a/tasmota/include/tasmota_types.h +++ b/tasmota/include/tasmota_types.h @@ -39,7 +39,7 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu uint32_t stop_flash_rotate : 1; // bit 12 (v5.2.0) - SetOption12 - (Settings) Switch between dynamic (0) or fixed (1) slot flash save location uint32_t button_single : 1; // bit 13 (v5.4.0) - SetOption13 - (Button) Support only single press (1) to speed up button press recognition uint32_t interlock : 1; // bit 14 (v5.6.0) - CMND_INTERLOCK - Enable (1) /disable (0) interlock - uint32_t pwm_control : 1; // bit 15 (v5.8.1) - SetOption15 - (Light) Switch between commands PWM (1) or COLOR/DIMMER/CT/CHANNEL (0) + uint32_t pwm_control : 1; // bit 15 (v5.8.1) - SetOption15 - (Light) Switch between commands PWM (0) or COLOR/DIMMER/CT/CHANNEL (1) uint32_t ws_clock_reverse : 1; // bit 16 (v5.8.1) - SetOption16 - (WS2812) Switch between clockwise (0) or counter-clockwise (1) uint32_t decimal_text : 1; // bit 17 (v5.8.1) - SetOption17 - (Light) Switch between decimal (1) or hexadecimal (0) output uint32_t light_signal : 1; // bit 18 (v5.10.0c) - SetOption18 - (Light) Pair light signal (1) with CO2 sensor diff --git a/tasmota/include/tasmota_version.h b/tasmota/include/tasmota_version.h index 93fc0e837..1ed1622ac 100644 --- a/tasmota/include/tasmota_version.h +++ b/tasmota/include/tasmota_version.h @@ -20,6 +20,6 @@ #ifndef _TASMOTA_VERSION_H_ #define _TASMOTA_VERSION_H_ -const uint32_t VERSION = 0x0C030105; // 12.3.1.5 +const uint32_t VERSION = 0x0C030106; // 12.3.1.6 #endif // _TASMOTA_VERSION_H_ diff --git a/tasmota/tasmota_support/support_features.ino b/tasmota/tasmota_support/support_features.ino index c1e816293..bae2916b3 100644 --- a/tasmota/tasmota_support/support_features.ino +++ b/tasmota/tasmota_support/support_features.ino @@ -873,8 +873,9 @@ void ResponseAppendFeatures(void) #if defined(USE_I2C) && defined(USE_SEN5X) feature9 |= 0x00008000; // xsns_103_sen5x.ino #endif - -// feature9 |= 0x00010000; +#if defined(USE_ENERGY_SENSOR) && defined(USE_BIOPDU) + feature9 |= 0x00010000; // xnrg_24_biopdu.ino +#endif // feature9 |= 0x00020000; // feature9 |= 0x00040000; // feature9 |= 0x00080000; diff --git a/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro.ino b/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro.ino index 94573422e..cb1d91a49 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro.ino @@ -1,5 +1,5 @@ /* - xdrv_88_shelly_pro.ino - Shelly pro family support for Tasmota + xdrv_88_esp32_shelly_pro.ino - Shelly pro family support for Tasmota Copyright (C) 2022 Theo Arends @@ -19,86 +19,393 @@ #ifdef ESP32 #ifdef USE_SPI -#ifdef USE_SHELLY_PRO_V1 +#ifdef USE_SHELLY_PRO /*********************************************************************************************\ * Shelly Pro support * - * {"NAME":"Shelly Pro 1","GPIO":[0,1,0,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,0,0,0,32,4736,0,160,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,10000,10000,3350"} - * {"NAME":"Shelly Pro 1PM","GPIO":[9568,1,9472,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,3459,0,0,32,4736,0,160,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,10000,10000,3350"} - * {"NAME":"Shelly Pro 2","GPIO":[0,1,0,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,0,0,0,32,4736,4737,160,161],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,10000,10000,3350;AdcParam2 2,10000,10000,3350"} - * {"NAME":"Shelly Pro 2PM","GPIO":[9568,1,9472,1,768,0,0,0,672,704,736,9569,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,3460,0,0,32,4736,4737,160,161],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,10000,10000,3350;AdcParam2 2,10000,10000,3350"} + * {"NAME":"Shelly Pro 1","GPIO":[0,1,0,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,0,0,0,32,4736,0,160,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350"} + * {"NAME":"Shelly Pro 1PM","GPIO":[9568,1,9472,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,3459,0,0,32,4736,0,160,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350"} + * {"NAME":"Shelly Pro 2","GPIO":[0,1,0,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,0,0,0,32,4736,4737,160,161],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350;AdcParam2 2,5600,4700,3350"} + * {"NAME":"Shelly Pro 2PM","GPIO":[9568,1,9472,1,768,0,0,0,672,704,736,9569,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,3460,0,0,32,4736,4737,160,161],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350;AdcParam2 2,5600,4700,3350"} + * {"NAME":"Shelly Pro 4PM","GPIO":[0,6210,0,6214,9568,0,0,0,0,0,9569,0,768,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,736,704,3461,0,4736,0,0,672],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350"} * - * Shelly Pro uses SPI to control one 74HC595 for relays/leds and one ADE7953 (1PM) or two ADE7953 (2PM) for energy monitoring + * Shelly Pro 1/2 uses SPI to control one 74HC595 for relays/leds and one ADE7953 (1PM) or two ADE7953 (2PM) for energy monitoring + * Shelly Pro 4 uses an SPI to control one MCP23S17 for buttons/switches/relays/leds and two ADE7953 for energy monitoring and a second SPI for the display + * To use display enable defines USE_DISPLAY, USE_UNIVERSAL_DISPLAY and SHOW_SPLASH. Load file ST7735S_Pro4PM_display.ini as display.ini \*********************************************************************************************/ -#define XDRV_88 88 +#define XDRV_88 88 + +#define SHELLY_PRO_PIN_LAN8720_RESET 5 +#define SHELLY_PRO_4_PIN_SPI_CS 16 +#define SHELLY_PRO_4_PIN_MCP23S17_INT 35 +#define SHELLY_PRO_4_MCP23S17_ADDRESS 0x40 struct SPro { uint32_t last_update; - uint8_t pin_shift595_rclk; + uint16_t input_state; + int8_t switch_offset; + int8_t button_offset; + uint8_t pin_register_cs; + uint8_t pin_mcp23s17_int; uint8_t ledlink; uint8_t power; - bool detected; + bool init_done; + uint8_t detected; } SPro; +/*********************************************************************************************\ + * Shelly Pro MCP23S17 support +\*********************************************************************************************/ + +enum SP4MCP23X17GPIORegisters { + // A side + SP4_MCP23S17_IODIRA = 0x00, + SP4_MCP23S17_IPOLA = 0x02, + SP4_MCP23S17_GPINTENA = 0x04, + SP4_MCP23S17_DEFVALA = 0x06, + SP4_MCP23S17_INTCONA = 0x08, + SP4_MCP23S17_IOCONA = 0x0A, + SP4_MCP23S17_GPPUA = 0x0C, + SP4_MCP23S17_INTFA = 0x0E, + SP4_MCP23S17_INTCAPA = 0x10, + SP4_MCP23S17_GPIOA = 0x12, + SP4_MCP23S17_OLATA = 0x14, + // B side + SP4_MCP23S17_IODIRB = 0x01, + SP4_MCP23S17_IPOLB = 0x03, + SP4_MCP23S17_GPINTENB = 0x05, + SP4_MCP23S17_DEFVALB = 0x07, + SP4_MCP23S17_INTCONB = 0x09, + SP4_MCP23S17_IOCONB = 0x0B, + SP4_MCP23S17_GPPUB = 0x0D, + SP4_MCP23S17_INTFB = 0x0F, + SP4_MCP23S17_INTCAPB = 0x11, + SP4_MCP23S17_GPIOB = 0x13, + SP4_MCP23S17_OLATB = 0x15, +}; + +uint8_t sp4_mcp23s17_olata = 0; +uint8_t sp4_mcp23s17_olatb = 0; + +void SP4Mcp23S17Enable(void) { + SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0)); + digitalWrite(SPro.pin_register_cs, 0); +} + +void SP4Mcp23S17Disable(void) { + SPI.endTransaction(); + digitalWrite(SPro.pin_register_cs, 1); +} + +uint32_t SP4Mcp23S17Read16(uint8_t reg) { + // Read 16-bit registers: (regb << 8) | rega + SP4Mcp23S17Enable(); + SPI.transfer(SHELLY_PRO_4_MCP23S17_ADDRESS | 1); + SPI.transfer(reg); + uint32_t value = SPI.transfer(0xFF); // RegA + value |= (SPI.transfer(0xFF) << 8); // RegB + SP4Mcp23S17Disable(); + return value; +} + +uint32_t SP4Mcp23S17Read(uint8_t reg) { + SP4Mcp23S17Enable(); + SPI.transfer(SHELLY_PRO_4_MCP23S17_ADDRESS | 1); + SPI.transfer(reg); + uint32_t value = SPI.transfer(0xFF); + SP4Mcp23S17Disable(); + return value; +} + +void SP4Mcp23S17Write(uint8_t reg, uint8_t value) { + SP4Mcp23S17Enable(); + SPI.transfer(SHELLY_PRO_4_MCP23S17_ADDRESS); + SPI.transfer(reg); + SPI.transfer(value); + SP4Mcp23S17Disable(); +} + +void SP4Mcp23S17Update(uint8_t pin, bool pin_value, uint8_t reg_addr) { + uint8_t bit = pin % 8; + uint8_t reg_value = 0; + if (reg_addr == SP4_MCP23S17_OLATA) { + reg_value = sp4_mcp23s17_olata; + } else if (reg_addr == SP4_MCP23S17_OLATB) { + reg_value = sp4_mcp23s17_olatb; + } else { + reg_value = SP4Mcp23S17Read(reg_addr); + } + if (pin_value) { + reg_value |= 1 << bit; + } else { + reg_value &= ~(1 << bit); + } + SP4Mcp23S17Write(reg_addr, reg_value); + if (reg_addr == SP4_MCP23S17_OLATA) { + sp4_mcp23s17_olata = reg_value; + } else if (reg_addr == SP4_MCP23S17_OLATB) { + sp4_mcp23s17_olatb = reg_value; + } +} + +void SP4Mcp23S17PinMode(uint8_t pin, uint8_t flags) { + uint8_t iodir = pin < 8 ? SP4_MCP23S17_IODIRA : SP4_MCP23S17_IODIRB; + uint8_t gppu = pin < 8 ? SP4_MCP23S17_GPPUA : SP4_MCP23S17_GPPUB; + if (flags == INPUT) { + SP4Mcp23S17Update(pin, true, iodir); + SP4Mcp23S17Update(pin, false, gppu); + } else if (flags == (INPUT | PULLUP)) { + SP4Mcp23S17Update(pin, true, iodir); + SP4Mcp23S17Update(pin, true, gppu); + } else if (flags == OUTPUT) { + SP4Mcp23S17Update(pin, false, iodir); + } +} + +bool SP4Mcp23S17DigitalRead(uint8_t pin) { + uint8_t bit = pin % 8; + uint8_t reg_addr = pin < 8 ? SP4_MCP23S17_GPIOA : SP4_MCP23S17_GPIOB; + uint8_t value = SP4Mcp23S17Read(reg_addr); + return value & (1 << bit); +} + +void SP4Mcp23S17DigitalWrite(uint8_t pin, bool value) { + uint8_t reg_addr = pin < 8 ? SP4_MCP23S17_OLATA : SP4_MCP23S17_OLATB; + SP4Mcp23S17Update(pin, value, reg_addr); +} + +/*********************************************************************************************\ + * Shelly Pro 4 +\*********************************************************************************************/ + +const uint8_t sp4_relay_pin[] = { 8, 13, 14, 12 }; +const uint8_t sp4_switch_pin[] = { 6, 1, 0, 15 }; +const uint8_t sp4_button_pin[] = { 5, 2, 3 }; + +void ShellyPro4Init(void) { + /* + Shelly Pro 4PM MCP23S17 registers + bit 0 = input, inverted - Switch3 + bit 1 = input, inverted - Switch2 + bit 2 = input - Button Down + bit 3 = input - Button OK + bit 4 = output - Reset, display, ADE7953 + bit 5 = input - Button Up + bit 6 = input, inverted - Switch1 + bit 7 + bit 8 = output - Relay O1 + bit 9 + bit 10 + bit 11 + bit 12 = output - Relay O4 + bit 13 = output - Relay O2 + bit 14 = output - Relay O3 + bit 15 = input, inverted - Switch4 + */ + SP4Mcp23S17Write(SP4_MCP23S17_IOCONA, 0b01011000); // Enable INT mirror, Slew rate disabled, HAEN pins for addressing + SP4Mcp23S17Write(SP4_MCP23S17_GPINTENA, 0x6F); // Enable interrupt on change + SP4Mcp23S17Write(SP4_MCP23S17_GPINTENB, 0x80); // Enable interrupt on change + + // Read current output register state + sp4_mcp23s17_olata = SP4Mcp23S17Read(SP4_MCP23S17_OLATA); + sp4_mcp23s17_olatb = SP4Mcp23S17Read(SP4_MCP23S17_OLATB); + + SP4Mcp23S17PinMode(4, OUTPUT); // Reset display, ADE7943 + SP4Mcp23S17DigitalWrite(4, 1); + + for (uint32_t i = 0; i < 3; i++) { + SP4Mcp23S17PinMode(sp4_button_pin[i], INPUT); // Button Up, Down, OK (RC with 10k to 3V3 and button shorting C) + } + SPro.button_offset = -1; + + for (uint32_t i = 0; i < 4; i++) { + SP4Mcp23S17PinMode(sp4_switch_pin[i], INPUT); // Switch1..4 + SP4Mcp23S17PinMode(sp4_relay_pin[i], OUTPUT); // Relay O1..O4 + } + SPro.switch_offset = -1; + + // Read current input register state + SPro.input_state = SP4Mcp23S17Read16(SP4_MCP23S17_GPIOA) & 0x806F; // Read gpio and clear interrupt + attachInterrupt(SPro.pin_mcp23s17_int, ShellyProUpdateIsr, CHANGE); +} + +void ShellyPro4Reset(void) { + SP4Mcp23S17DigitalWrite(4, 0); // Reset pin display, ADE7953 + delay(1); // To initiate a hardware reset, this pin must be brought low for a minimum of 10 μs. + SP4Mcp23S17DigitalWrite(4, 1); +} + +bool ShellyProAddButton(void) { + if (SPro.detected != 4) { return false; } // Only support Shelly Pro 4 + if (SPro.button_offset < 0) { SPro.button_offset = XdrvMailbox.index; } + uint32_t index = XdrvMailbox.index - SPro.button_offset; + if (index > 2) { return false; } // Support three buttons + uint32_t state = bitRead(SPro.input_state, sp4_button_pin[index]); // 1 on power on and restart + XdrvMailbox.index = state; + return true; +} + +bool ShellyProAddSwitch(void) { + if (SPro.detected != 4) { return false; } // Only support Shelly Pro 4 + if (SPro.switch_offset < 0) { SPro.switch_offset = XdrvMailbox.index; } + uint32_t index = XdrvMailbox.index - SPro.switch_offset; + if (index > 3) { return false; } // Support four switches + uint32_t state = bitRead(SPro.input_state, sp4_switch_pin[index]); // 0 on power on and restart + XdrvMailbox.index = state ^1; // Invert + return true; +} + +void ShellyProUpdateIsr(void) { + /* + The goal if this function is to minimize SPI and SetVirtualPinState calls + */ + uint32_t input_state = SP4Mcp23S17Read16(SP4_MCP23S17_INTCAPA); // Read intcap and clear interrupt + input_state &= 0x806F; // Only test input bits + +// AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Input from %04X to %04X"), SPro.input_state, input_state); + + if (TasmotaGlobal.uptime < 3) { return; } // Flush interrupt for 3 seconds after poweron + + uint32_t mask = 1; + for (uint32_t j = 0; j < 16; j++) { + if ((input_state & mask) != (SPro.input_state & mask)) { + uint32_t state = (input_state >> j) &1; + +// AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Change pin %d to %d"), j, state); + + for (uint32_t i = 0; i < 4; i++) { + if (j == sp4_switch_pin[i]) { + SwitchSetVirtualPinState(SPro.switch_offset +i, state ^1); // Invert + } + else if ((i < 3) && (j == sp4_button_pin[i])) { + ButtonSetVirtualPinState(SPro.button_offset +i, state); + } + } + } + mask <<= 1; + } + SPro.input_state = input_state; +} + +bool ShellyProButton(void) { + if (SPro.detected != 4) { return false; } // Only support Shelly Pro 4 + + uint32_t button_index = XdrvMailbox.index - SPro.button_offset; + if (button_index > 2) { return false; } // Only support Up, Down, Ok + + uint32_t button = XdrvMailbox.payload; + uint32_t last_state = XdrvMailbox.command_code; + if ((PRESSED == button) && (NOT_PRESSED == last_state)) { // Button pressed + + AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Button %d pressed"), button_index +1); + + // Do something with the Up,Down,Ok button + switch (button_index) { + case 0: // Up + break; + case 1: // Down + break; + case 2: // Ok + break; + } + } + return true; // Disable further button processing +} + +/*********************************************************************************************\ + * Shelly Pro 1/2 +\*********************************************************************************************/ + void ShellyProUpdate(void) { - // Shelly Pro 595 register - // bit 0 = relay/led 1 - // bit 1 = relay/led 2 - // bit 2 = wifi led blue - // bit 3 = wifi led green - // bit 4 = wifi led red - // bit 5 - 7 = nc - // OE is connected to Gnd with 470 ohm resistor R62 AND a capacitor C81 to 3V3 - // - this inhibits output of signals (also relay state) during power on for a few seconds + /* + Shelly Pro 1/2/PM 74HC595 register + bit 0 = relay/led 1 + bit 1 = relay/led 2 + bit 2 = wifi led blue + bit 3 = wifi led green + bit 4 = wifi led red + bit 5 - 7 = nc + OE is connected to Gnd with 470 ohm resistor R62 AND a capacitor C81 to 3V3 + - this inhibits output of signals (also relay state) during power on for a few seconds + */ uint8_t val = SPro.power | SPro.ledlink; SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0)); - SPI.transfer(val); // Write 74HC595 shift register + SPI.transfer(val); // Write 74HC595 shift register SPI.endTransaction(); -// delayMicroseconds(2); // Wait for SPI clock to stop - digitalWrite(SPro.pin_shift595_rclk, 1); // Latch data - delayMicroseconds(1); // Shelly 10mS - digitalWrite(SPro.pin_shift595_rclk, 0); +// delayMicroseconds(2); // Wait for SPI clock to stop + digitalWrite(SPro.pin_register_cs, 1); // Latch data + delayMicroseconds(1); // Shelly 10mS + digitalWrite(SPro.pin_register_cs, 0); } +/*********************************************************************************************\ + * Shelly Pro +\*********************************************************************************************/ + void ShellyProPreInit(void) { if ((SPI_MOSI_MISO == TasmotaGlobal.spi_enabled) && - PinUsed(GPIO_SPI_CS) && - TasmotaGlobal.gpio_optiona.shelly_pro) { // Option_A7 + PinUsed(GPIO_SPI_CS) && // 74HC595 rclk / MCP23S17 + TasmotaGlobal.gpio_optiona.shelly_pro) { // Option_A7 if (PinUsed(GPIO_SWT1) || PinUsed(GPIO_KEY1)) { - TasmotaGlobal.devices_present++; // Shelly Pro 1 + SPro.detected = 1; // Shelly Pro 1 if (PinUsed(GPIO_SWT1, 1) || PinUsed(GPIO_KEY1, 1)) { - TasmotaGlobal.devices_present++; // Shelly Pro 2 + SPro.detected = 2; // Shelly Pro 2 } + SPro.ledlink = 0x18; // Blue led on - set by first call ShellyProPower() - Shelly 1/2 + } + if (SHELLY_PRO_4_PIN_SPI_CS == Pin(GPIO_SPI_CS)) { + SPro.detected = 4; // Shelly Pro 4PM (No SWT or KEY) + } - SPro.pin_shift595_rclk = Pin(GPIO_SPI_CS); - digitalWrite(SPro.pin_shift595_rclk, 0); - pinMode(SPro.pin_shift595_rclk, OUTPUT); + if (SPro.detected) { + TasmotaGlobal.devices_present += SPro.detected; + + SPro.pin_register_cs = Pin(GPIO_SPI_CS); + digitalWrite(SPro.pin_register_cs, (4 == SPro.detected) ? 1 : 0); // Prep 74HC595 rclk + pinMode(SPro.pin_register_cs, OUTPUT); // Does nothing if SPI is already initiated (by ADE7953) so no harm done SPI.begin(Pin(GPIO_SPI_CLK), Pin(GPIO_SPI_MISO), Pin(GPIO_SPI_MOSI), -1); - SPro.ledlink = 0x18; // Blue led on - set by first call ShellyProPower() - SPro.detected = true; + if (4 == SPro.detected) { + SPro.pin_mcp23s17_int = SHELLY_PRO_4_PIN_MCP23S17_INT; // GPIO35 = MCP23S17 common interrupt + pinMode(SPro.pin_mcp23s17_int, INPUT); + ShellyPro4Init(); // Init MCP23S17 + } } } } void ShellyProInit(void) { - int pin_lan_reset = 5; // GPIO5 = LAN8720 nRST -// delay(30); // (t-purstd) This pin must be brought low for a minimum of 25 mS after power on + int pin_lan_reset = SHELLY_PRO_PIN_LAN8720_RESET; // GPIO5 = LAN8720 nRST +// delay(30); // (t-purstd) This pin must be brought low for a minimum of 25 mS after power on digitalWrite(pin_lan_reset, 0); pinMode(pin_lan_reset, OUTPUT); - delay(1); // (t-rstia) This pin must be brought low for a minimum of 100 uS + delay(1); // (t-rstia) This pin must be brought low for a minimum of 100 uS digitalWrite(pin_lan_reset, 1); AddLog(LOG_LEVEL_INFO, PSTR("HDW: Shelly Pro %d%s initialized"), - TasmotaGlobal.devices_present, (PinUsed(GPIO_ADE7953_CS))?"PM":""); + SPro.detected, (PinUsed(GPIO_ADE7953_CS))?"PM":""); + + SPro.init_done = true; } void ShellyProPower(void) { - SPro.power = XdrvMailbox.index &3; - ShellyProUpdate(); + if (SPro.detected != 4) { + SPro.power = XdrvMailbox.index &3; + ShellyProUpdate(); + } else { + +// AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Set Power 0x%08X"), XdrvMailbox.index); + + power_t rpower = XdrvMailbox.index; + for (uint32_t i = 0; i < 4; i++) { + power_t state = rpower &1; + SP4Mcp23S17DigitalWrite(sp4_relay_pin[i], state); + rpower >>= 1; // Select next power + } + } } void ShellyProUpdateLedLink(uint32_t ledlink) { @@ -109,37 +416,42 @@ void ShellyProUpdateLedLink(uint32_t ledlink) { } void ShellyProLedLink(void) { - /* - bit 2 = blue, 3 = green, 4 = red - Shelly Pro documentation - - Blue light indicator will be on if in AP mode. - - Red light indicator will be on if in STA mode and not connected to a Wi-Fi network. - - Yellow light indicator will be on if in STA mode and connected to a Wi-Fi network. - - Green light indicator will be on if in STA mode and connected to a Wi-Fi network and to the Shelly Cloud. - - The light indicator will be flashing Red/Blue if OTA update is in progress. - Tasmota behaviour - - Blue light indicator will blink if no wifi or mqtt. - - Green light indicator will be on if in STA mode and connected to a Wi-Fi network. - */ - SPro.last_update = TasmotaGlobal.uptime; - uint32_t ledlink = 0x1C; // All leds off - if (XdrvMailbox.index) { - ledlink &= 0xFB; // Blue blinks if wifi/mqtt lost + if (!SPro.init_done) { return; } // Block write before first power update + if (SPro.detected != 4) { + /* + bit 2 = blue, 3 = green, 4 = red + Shelly Pro documentation + - Blue light indicator will be on if in AP mode. + - Red light indicator will be on if in STA mode and not connected to a Wi-Fi network. + - Yellow light indicator will be on if in STA mode and connected to a Wi-Fi network. + - Green light indicator will be on if in STA mode and connected to a Wi-Fi network and to the Shelly Cloud. + - The light indicator will be flashing Red/Blue if OTA update is in progress. + Tasmota behaviour + - Blue light indicator will blink if no wifi or mqtt. + - Green light indicator will be on if in STA mode and connected to a Wi-Fi network. + */ + SPro.last_update = TasmotaGlobal.uptime; + uint32_t ledlink = 0x1C; // All leds off + if (XdrvMailbox.index) { + ledlink &= 0xFB; // Blue blinks if wifi/mqtt lost + } + else if (!TasmotaGlobal.global_state.wifi_down) { + ledlink &= 0xF7; // Green On + } + ShellyProUpdateLedLink(ledlink); } - else if (!TasmotaGlobal.global_state.wifi_down) { - ledlink &= 0xF7; // Green On - } - - ShellyProUpdateLedLink(ledlink); } void ShellyProLedLinkWifiOff(void) { - /* - bit 2 = blue, 3 = green, 4 = red - - Green light indicator will be on if in STA mode and connected to a Wi-Fi network. - */ - if (SPro.last_update +1 < TasmotaGlobal.uptime) { - ShellyProUpdateLedLink((TasmotaGlobal.global_state.wifi_down) ? 0x1C : 0x14); // Green off if wifi OFF + if (!SPro.init_done) { return; } + if (SPro.detected != 4) { + /* + bit 2 = blue, 3 = green, 4 = red + - Green light indicator will be on if in STA mode and connected to a Wi-Fi network. + */ + if (SPro.last_update +1 < TasmotaGlobal.uptime) { + ShellyProUpdateLedLink((TasmotaGlobal.global_state.wifi_down) ? 0x1C : 0x14); // Green off if wifi OFF + } } } @@ -150,22 +462,33 @@ void ShellyProLedLinkWifiOff(void) { bool Xdrv88(uint32_t function) { bool result = false; - if (FUNC_PRE_INIT == function) { + if (FUNC_MODULE_INIT == function) { ShellyProPreInit(); } else if (SPro.detected) { switch (function) { +/* + case FUNC_BUTTON_PRESSED: + result = ShellyProButton(); + break; +*/ case FUNC_EVERY_SECOND: ShellyProLedLinkWifiOff(); break; case FUNC_SET_POWER: ShellyProPower(); break; - case FUNC_LED_LINK: - ShellyProLedLink(); - break; case FUNC_INIT: ShellyProInit(); break; + case FUNC_ADD_BUTTON: + result = ShellyProAddButton(); + break; + case FUNC_ADD_SWITCH: + result = ShellyProAddSwitch(); + break; + case FUNC_LED_LINK: + ShellyProLedLink(); + break; } } return result; diff --git a/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v2.ino b/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v2.ino deleted file mode 100644 index a5f4e63f9..000000000 --- a/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v2.ino +++ /dev/null @@ -1,498 +0,0 @@ -/* - xdrv_88_shelly_pro.ino - Shelly pro family support for Tasmota - - Copyright (C) 2022 Theo Arends - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#ifdef ESP32 -#ifdef USE_SPI -#ifdef USE_SHELLY_PRO -/*********************************************************************************************\ - * Shelly Pro support - * - * {"NAME":"Shelly Pro 1","GPIO":[0,1,0,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,0,0,0,32,4736,0,160,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350"} - * {"NAME":"Shelly Pro 1PM","GPIO":[9568,1,9472,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,3459,0,0,32,4736,0,160,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350"} - * {"NAME":"Shelly Pro 2","GPIO":[0,1,0,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,0,0,0,32,4736,4737,160,161],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350;AdcParam2 2,5600,4700,3350"} - * {"NAME":"Shelly Pro 2PM","GPIO":[9568,1,9472,1,768,0,0,0,672,704,736,9569,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,3460,0,0,32,4736,4737,160,161],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350;AdcParam2 2,5600,4700,3350"} - * {"NAME":"Shelly Pro 4PM","GPIO":[0,6210,0,6214,9568,0,0,0,0,0,9569,0,768,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,736,704,3461,0,4736,0,0,672],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350"} - * - * Shelly Pro 1/2 uses SPI to control one 74HC595 for relays/leds and one ADE7953 (1PM) or two ADE7953 (2PM) for energy monitoring - * Shelly Pro 4 uses an SPI to control one MCP23S17 for buttons/switches/relays/leds and two ADE7953 for energy monitoring and a second SPI for the display -\*********************************************************************************************/ - -#define XDRV_88 88 - -#define SHELLY_PRO_PIN_LAN8720_RESET 5 -#define SHELLY_PRO_4_PIN_SPI_CS 16 -#define SHELLY_PRO_4_PIN_MCP23S17_INT 35 -#define SHELLY_PRO_4_MCP23S17_ADDRESS 0x40 - -struct SPro { - uint32_t last_update; - uint16_t input_state; - int8_t switch_offset; - int8_t button_offset; - uint8_t pin_register_cs; - uint8_t pin_mcp23s17_int; - uint8_t ledlink; - uint8_t power; - bool init_done; - uint8_t detected; -} SPro; - -/*********************************************************************************************\ - * Shelly Pro MCP23S17 support -\*********************************************************************************************/ - -enum SP4MCP23X17GPIORegisters { - // A side - SP4_MCP23S17_IODIRA = 0x00, - SP4_MCP23S17_IPOLA = 0x02, - SP4_MCP23S17_GPINTENA = 0x04, - SP4_MCP23S17_DEFVALA = 0x06, - SP4_MCP23S17_INTCONA = 0x08, - SP4_MCP23S17_IOCONA = 0x0A, - SP4_MCP23S17_GPPUA = 0x0C, - SP4_MCP23S17_INTFA = 0x0E, - SP4_MCP23S17_INTCAPA = 0x10, - SP4_MCP23S17_GPIOA = 0x12, - SP4_MCP23S17_OLATA = 0x14, - // B side - SP4_MCP23S17_IODIRB = 0x01, - SP4_MCP23S17_IPOLB = 0x03, - SP4_MCP23S17_GPINTENB = 0x05, - SP4_MCP23S17_DEFVALB = 0x07, - SP4_MCP23S17_INTCONB = 0x09, - SP4_MCP23S17_IOCONB = 0x0B, - SP4_MCP23S17_GPPUB = 0x0D, - SP4_MCP23S17_INTFB = 0x0F, - SP4_MCP23S17_INTCAPB = 0x11, - SP4_MCP23S17_GPIOB = 0x13, - SP4_MCP23S17_OLATB = 0x15, -}; - -uint8_t sp4_mcp23s17_olata = 0; -uint8_t sp4_mcp23s17_olatb = 0; - -void SP4Mcp23S17Enable(void) { - SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0)); - digitalWrite(SPro.pin_register_cs, 0); -} - -void SP4Mcp23S17Disable(void) { - SPI.endTransaction(); - digitalWrite(SPro.pin_register_cs, 1); -} - -uint32_t SP4Mcp23S17Read16(uint8_t reg) { - // Read 16-bit registers: (regb << 8) | rega - SP4Mcp23S17Enable(); - SPI.transfer(SHELLY_PRO_4_MCP23S17_ADDRESS | 1); - SPI.transfer(reg); - uint32_t value = SPI.transfer(0xFF); // RegA - value |= (SPI.transfer(0xFF) << 8); // RegB - SP4Mcp23S17Disable(); - return value; -} - -uint32_t SP4Mcp23S17Read(uint8_t reg) { - SP4Mcp23S17Enable(); - SPI.transfer(SHELLY_PRO_4_MCP23S17_ADDRESS | 1); - SPI.transfer(reg); - uint32_t value = SPI.transfer(0xFF); - SP4Mcp23S17Disable(); - return value; -} - -void SP4Mcp23S17Write(uint8_t reg, uint8_t value) { - SP4Mcp23S17Enable(); - SPI.transfer(SHELLY_PRO_4_MCP23S17_ADDRESS); - SPI.transfer(reg); - SPI.transfer(value); - SP4Mcp23S17Disable(); -} - -void SP4Mcp23S17Update(uint8_t pin, bool pin_value, uint8_t reg_addr) { - uint8_t bit = pin % 8; - uint8_t reg_value = 0; - if (reg_addr == SP4_MCP23S17_OLATA) { - reg_value = sp4_mcp23s17_olata; - } else if (reg_addr == SP4_MCP23S17_OLATB) { - reg_value = sp4_mcp23s17_olatb; - } else { - reg_value = SP4Mcp23S17Read(reg_addr); - } - if (pin_value) { - reg_value |= 1 << bit; - } else { - reg_value &= ~(1 << bit); - } - SP4Mcp23S17Write(reg_addr, reg_value); - if (reg_addr == SP4_MCP23S17_OLATA) { - sp4_mcp23s17_olata = reg_value; - } else if (reg_addr == SP4_MCP23S17_OLATB) { - sp4_mcp23s17_olatb = reg_value; - } -} - -void SP4Mcp23S17PinMode(uint8_t pin, uint8_t flags) { - uint8_t iodir = pin < 8 ? SP4_MCP23S17_IODIRA : SP4_MCP23S17_IODIRB; - uint8_t gppu = pin < 8 ? SP4_MCP23S17_GPPUA : SP4_MCP23S17_GPPUB; - if (flags == INPUT) { - SP4Mcp23S17Update(pin, true, iodir); - SP4Mcp23S17Update(pin, false, gppu); - } else if (flags == (INPUT | PULLUP)) { - SP4Mcp23S17Update(pin, true, iodir); - SP4Mcp23S17Update(pin, true, gppu); - } else if (flags == OUTPUT) { - SP4Mcp23S17Update(pin, false, iodir); - } -} - -bool SP4Mcp23S17DigitalRead(uint8_t pin) { - uint8_t bit = pin % 8; - uint8_t reg_addr = pin < 8 ? SP4_MCP23S17_GPIOA : SP4_MCP23S17_GPIOB; - uint8_t value = SP4Mcp23S17Read(reg_addr); - return value & (1 << bit); -} - -void SP4Mcp23S17DigitalWrite(uint8_t pin, bool value) { - uint8_t reg_addr = pin < 8 ? SP4_MCP23S17_OLATA : SP4_MCP23S17_OLATB; - SP4Mcp23S17Update(pin, value, reg_addr); -} - -/*********************************************************************************************\ - * Shelly Pro 4 -\*********************************************************************************************/ - -const uint8_t sp4_relay_pin[] = { 8, 13, 14, 12 }; -const uint8_t sp4_switch_pin[] = { 6, 1, 0, 15 }; -const uint8_t sp4_button_pin[] = { 5, 2, 3 }; - -void ShellyPro4Init(void) { - /* - Shelly Pro 4PM MCP23S17 registers - bit 0 = input, inverted - Switch3 - bit 1 = input, inverted - Switch2 - bit 2 = input - Button Down - bit 3 = input - Button OK - bit 4 = output - Reset, display, ADE7953 - bit 5 = input - Button Up - bit 6 = input, inverted - Switch1 - bit 7 - bit 8 = output - Relay O1 - bit 9 - bit 10 - bit 11 - bit 12 = output - Relay O4 - bit 13 = output - Relay O2 - bit 14 = output - Relay O3 - bit 15 = input, inverted - Switch4 - */ - SP4Mcp23S17Write(SP4_MCP23S17_IOCONA, 0b01011000); // Enable INT mirror, Slew rate disabled, HAEN pins for addressing - SP4Mcp23S17Write(SP4_MCP23S17_GPINTENA, 0x6F); // Enable interrupt on change - SP4Mcp23S17Write(SP4_MCP23S17_GPINTENB, 0x80); // Enable interrupt on change - - // Read current output register state - sp4_mcp23s17_olata = SP4Mcp23S17Read(SP4_MCP23S17_OLATA); - sp4_mcp23s17_olatb = SP4Mcp23S17Read(SP4_MCP23S17_OLATB); - - SP4Mcp23S17PinMode(4, OUTPUT); // Reset display, ADE7943 - SP4Mcp23S17DigitalWrite(4, 1); - - for (uint32_t i = 0; i < 3; i++) { - SP4Mcp23S17PinMode(sp4_button_pin[i], INPUT); // Button Up, Down, OK (RC with 10k to 3V3 and button shorting C) - } - SPro.button_offset = -1; - - for (uint32_t i = 0; i < 4; i++) { - SP4Mcp23S17PinMode(sp4_switch_pin[i], INPUT); // Switch1..4 - SP4Mcp23S17PinMode(sp4_relay_pin[i], OUTPUT); // Relay O1..O4 - } - SPro.switch_offset = -1; - - // Read current input register state - SPro.input_state = SP4Mcp23S17Read16(SP4_MCP23S17_GPIOA) & 0x806F; // Read gpio and clear interrupt - attachInterrupt(SPro.pin_mcp23s17_int, ShellyProUpdateIsr, CHANGE); -} - -void ShellyPro4Reset(void) { - SP4Mcp23S17DigitalWrite(4, 0); // Reset pin display, ADE7953 - delay(1); // To initiate a hardware reset, this pin must be brought low for a minimum of 10 μs. - SP4Mcp23S17DigitalWrite(4, 1); -} - -bool ShellyProAddButton(void) { - if (SPro.detected != 4) { return false; } // Only support Shelly Pro 4 - if (SPro.button_offset < 0) { SPro.button_offset = XdrvMailbox.index; } - uint32_t index = XdrvMailbox.index - SPro.button_offset; - if (index > 2) { return false; } // Support three buttons - uint32_t state = bitRead(SPro.input_state, sp4_button_pin[index]); // 1 on power on and restart - XdrvMailbox.index = state; - return true; -} - -bool ShellyProAddSwitch(void) { - if (SPro.detected != 4) { return false; } // Only support Shelly Pro 4 - if (SPro.switch_offset < 0) { SPro.switch_offset = XdrvMailbox.index; } - uint32_t index = XdrvMailbox.index - SPro.switch_offset; - if (index > 3) { return false; } // Support four switches - uint32_t state = bitRead(SPro.input_state, sp4_switch_pin[index]); // 0 on power on and restart - XdrvMailbox.index = state ^1; // Invert - return true; -} - -void ShellyProUpdateIsr(void) { - /* - The goal if this function is to minimize SPI and SetVirtualPinState calls - */ - uint32_t input_state = SP4Mcp23S17Read16(SP4_MCP23S17_INTCAPA); // Read intcap and clear interrupt - input_state &= 0x806F; // Only test input bits - -// AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Input from %04X to %04X"), SPro.input_state, input_state); - - if (TasmotaGlobal.uptime < 3) { return; } // Flush interrupt for 3 seconds after poweron - - uint32_t mask = 1; - for (uint32_t j = 0; j < 16; j++) { - if ((input_state & mask) != (SPro.input_state & mask)) { - uint32_t state = (input_state >> j) &1; - -// AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Change pin %d to %d"), j, state); - - for (uint32_t i = 0; i < 4; i++) { - if (j == sp4_switch_pin[i]) { - SwitchSetVirtualPinState(SPro.switch_offset +i, state ^1); // Invert - } - else if ((i < 3) && (j == sp4_button_pin[i])) { - ButtonSetVirtualPinState(SPro.button_offset +i, state); - } - } - } - mask <<= 1; - } - SPro.input_state = input_state; -} - -bool ShellyProButton(void) { - if (SPro.detected != 4) { return false; } // Only support Shelly Pro 4 - - uint32_t button_index = XdrvMailbox.index - SPro.button_offset; - if (button_index > 2) { return false; } // Only support Up, Down, Ok - - uint32_t button = XdrvMailbox.payload; - uint32_t last_state = XdrvMailbox.command_code; - if ((PRESSED == button) && (NOT_PRESSED == last_state)) { // Button pressed - - AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Button %d pressed"), button_index +1); - - // Do something with the Up,Down,Ok button - switch (button_index) { - case 0: // Up - break; - case 1: // Down - break; - case 2: // Ok - break; - } - } - return true; // Disable further button processing -} - -/*********************************************************************************************\ - * Shelly Pro 1/2 -\*********************************************************************************************/ - -void ShellyProUpdate(void) { - /* - Shelly Pro 1/2/PM 74HC595 register - bit 0 = relay/led 1 - bit 1 = relay/led 2 - bit 2 = wifi led blue - bit 3 = wifi led green - bit 4 = wifi led red - bit 5 - 7 = nc - OE is connected to Gnd with 470 ohm resistor R62 AND a capacitor C81 to 3V3 - - this inhibits output of signals (also relay state) during power on for a few seconds - */ - uint8_t val = SPro.power | SPro.ledlink; - SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0)); - SPI.transfer(val); // Write 74HC595 shift register - SPI.endTransaction(); -// delayMicroseconds(2); // Wait for SPI clock to stop - digitalWrite(SPro.pin_register_cs, 1); // Latch data - delayMicroseconds(1); // Shelly 10mS - digitalWrite(SPro.pin_register_cs, 0); -} - -/*********************************************************************************************\ - * Shelly Pro -\*********************************************************************************************/ - -void ShellyProPreInit(void) { - if ((SPI_MOSI_MISO == TasmotaGlobal.spi_enabled) && - PinUsed(GPIO_SPI_CS) && // 74HC595 rclk / MCP23S17 - TasmotaGlobal.gpio_optiona.shelly_pro) { // Option_A7 - - if (PinUsed(GPIO_SWT1) || PinUsed(GPIO_KEY1)) { - SPro.detected = 1; // Shelly Pro 1 - if (PinUsed(GPIO_SWT1, 1) || PinUsed(GPIO_KEY1, 1)) { - SPro.detected = 2; // Shelly Pro 2 - } - SPro.ledlink = 0x18; // Blue led on - set by first call ShellyProPower() - Shelly 1/2 - } - if (SHELLY_PRO_4_PIN_SPI_CS == Pin(GPIO_SPI_CS)) { - SPro.detected = 4; // Shelly Pro 4PM (No SWT or KEY) - } - - if (SPro.detected) { - TasmotaGlobal.devices_present += SPro.detected; - - SPro.pin_register_cs = Pin(GPIO_SPI_CS); - digitalWrite(SPro.pin_register_cs, (4 == SPro.detected) ? 1 : 0); // Prep 74HC595 rclk - pinMode(SPro.pin_register_cs, OUTPUT); - // Does nothing if SPI is already initiated (by ADE7953) so no harm done - SPI.begin(Pin(GPIO_SPI_CLK), Pin(GPIO_SPI_MISO), Pin(GPIO_SPI_MOSI), -1); - - if (4 == SPro.detected) { - SPro.pin_mcp23s17_int = SHELLY_PRO_4_PIN_MCP23S17_INT; // GPIO35 = MCP23S17 common interrupt - pinMode(SPro.pin_mcp23s17_int, INPUT); - ShellyPro4Init(); // Init MCP23S17 - } - } - } -} - -void ShellyProInit(void) { - int pin_lan_reset = SHELLY_PRO_PIN_LAN8720_RESET; // GPIO5 = LAN8720 nRST -// delay(30); // (t-purstd) This pin must be brought low for a minimum of 25 mS after power on - digitalWrite(pin_lan_reset, 0); - pinMode(pin_lan_reset, OUTPUT); - delay(1); // (t-rstia) This pin must be brought low for a minimum of 100 uS - digitalWrite(pin_lan_reset, 1); - - AddLog(LOG_LEVEL_INFO, PSTR("HDW: Shelly Pro %d%s initialized"), - SPro.detected, (PinUsed(GPIO_ADE7953_CS))?"PM":""); - - SPro.init_done = true; -} - -void ShellyProPower(void) { - if (SPro.detected != 4) { - SPro.power = XdrvMailbox.index &3; - ShellyProUpdate(); - } else { - -// AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Set Power 0x%08X"), XdrvMailbox.index); - - power_t rpower = XdrvMailbox.index; - for (uint32_t i = 0; i < 4; i++) { - power_t state = rpower &1; - SP4Mcp23S17DigitalWrite(sp4_relay_pin[i], state); - rpower >>= 1; // Select next power - } - } -} - -void ShellyProUpdateLedLink(uint32_t ledlink) { - if (ledlink != SPro.ledlink) { - SPro.ledlink = ledlink; - ShellyProUpdate(); - } -} - -void ShellyProLedLink(void) { - if (!SPro.init_done) { return; } // Block write before first power update - if (SPro.detected != 4) { - /* - bit 2 = blue, 3 = green, 4 = red - Shelly Pro documentation - - Blue light indicator will be on if in AP mode. - - Red light indicator will be on if in STA mode and not connected to a Wi-Fi network. - - Yellow light indicator will be on if in STA mode and connected to a Wi-Fi network. - - Green light indicator will be on if in STA mode and connected to a Wi-Fi network and to the Shelly Cloud. - - The light indicator will be flashing Red/Blue if OTA update is in progress. - Tasmota behaviour - - Blue light indicator will blink if no wifi or mqtt. - - Green light indicator will be on if in STA mode and connected to a Wi-Fi network. - */ - SPro.last_update = TasmotaGlobal.uptime; - uint32_t ledlink = 0x1C; // All leds off - if (XdrvMailbox.index) { - ledlink &= 0xFB; // Blue blinks if wifi/mqtt lost - } - else if (!TasmotaGlobal.global_state.wifi_down) { - ledlink &= 0xF7; // Green On - } - ShellyProUpdateLedLink(ledlink); - } -} - -void ShellyProLedLinkWifiOff(void) { - if (!SPro.init_done) { return; } - if (SPro.detected != 4) { - /* - bit 2 = blue, 3 = green, 4 = red - - Green light indicator will be on if in STA mode and connected to a Wi-Fi network. - */ - if (SPro.last_update +1 < TasmotaGlobal.uptime) { - ShellyProUpdateLedLink((TasmotaGlobal.global_state.wifi_down) ? 0x1C : 0x14); // Green off if wifi OFF - } - } -} - -/*********************************************************************************************\ - * Interface -\*********************************************************************************************/ - -bool Xdrv88(uint32_t function) { - bool result = false; - - if (FUNC_MODULE_INIT == function) { - ShellyProPreInit(); - } else if (SPro.detected) { - switch (function) { -/* - case FUNC_BUTTON_PRESSED: - result = ShellyProButton(); - break; -*/ - case FUNC_EVERY_SECOND: - ShellyProLedLinkWifiOff(); - break; - case FUNC_SET_POWER: - ShellyProPower(); - break; - case FUNC_INIT: - ShellyProInit(); - break; - case FUNC_ADD_BUTTON: - result = ShellyProAddButton(); - break; - case FUNC_ADD_SWITCH: - result = ShellyProAddSwitch(); - break; - case FUNC_LED_LINK: - ShellyProLedLink(); - break; - } - } - return result; -} - -#endif // USE_SHELLY_PRO -#endif // USE_SPI -#endif // ESP32 diff --git a/tasmota/tasmota_xnrg_energy/xnrg_24_biopdu.ino b/tasmota/tasmota_xnrg_energy/xnrg_24_biopdu.ino index e4413f814..680c2fbad 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_24_biopdu.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_24_biopdu.ino @@ -1,15 +1,7 @@ /* xnrg_24_biopdu.ino - BioPDU-625x12 (based on xnrg_05_pzem_ac.ino) - Biomine 625x12 Custom Board - 6 x 25A Relays - 6 x Independent PZEM-004V3 Modbus AC energy sensor - 3bit serial switch - Integrated MCP23008 - Template {"NAME":"Olimex ESP32-PoE-BioPDU","GPIO":[1,10209,10210,1,10144,1,0,0,5536,640,1,1,608,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,1,10208,1,1,10176,0,0,1],"FLAG":0,"BASE":1} - - Copyright (C) 2021 Theo Arends - Copyright (C) 2022-2023 Fabrizio Amodio + Copyright (C) 2023 Fabrizio Amodio This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -27,8 +19,15 @@ #if defined(USE_ENERGY_SENSOR_ESP32) && defined(USE_I2C) #ifdef USE_BIOPDU +/*********************************************************************************************\ + Biomine 625x12 Custom Board + 6 x 25A Relays + 6 x Independent PZEM-004V3 Modbus AC energy sensor + 3bit serial switch + Integrated MCP23008 + + Template {"NAME":"Olimex ESP32-PoE-BioPDU","GPIO":[1,10209,10210,1,10144,1,0,0,5536,640,1,1,608,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,1,10208,1,1,10176,0,0,1],"FLAG":0,"BASE":1} -/* BioPDU 625x12 Factory Settings: Template {"NAME":"Olimex ESP32-PoE-BioPDU","GPIO":[1,10209,10210,1,10144,1,0,0,5536,640,1,1,608,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,1,10208,1,1,10176,0,0,1],"FLAG":0,"BASE":1} @@ -62,7 +61,7 @@ USE_MCP230xx_ADDR=0x20 USE_MCP230xx_OUTPUT USE_BIOPDU -*/ +\*********************************************************************************************/ #define XNRG_24 24 diff --git a/tools/decode-status.py b/tools/decode-status.py index 67f740ad6..65c5c9a5f 100755 --- a/tools/decode-status.py +++ b/tools/decode-status.py @@ -206,7 +206,8 @@ a_setoption = [[ "(Light) start DMX ArtNet at boot, listen to UDP port as soon as network is up", "(Wifi) prefer IPv6 DNS resolution to IPv4 address when available. Requires `#define USE_IPV6`", "(Energy) Force no voltage/frequency common", - "","","", + "(Matter) Enable Matter protocol over Wifi", + "","", "","","","", "","","","", "","","","", @@ -292,7 +293,7 @@ a_features = [[ "USE_MODBUS_ENERGY","USE_SHELLY_PRO","USE_DALI","USE_BP1658CJ", "USE_DINGTIAN_RELAY","USE_HMC5883L","USE_LD2410","USE_ME007", "USE_DISPLAY_TM1650","USE_PCA9632","USE_TUYAMCUBR","USE_SEN5X", - "","","","", + "USE_BIOPDU","","","", "","","","", "","","","", "","","","" @@ -323,7 +324,7 @@ else: obj = json.load(fp) def StartDecode(): - print ("\n*** decode-status.py v12.3.1.5 by Theo Arends and Jacek Ziolkowski ***") + print ("\n*** decode-status.py v12.3.1.6 by Theo Arends and Jacek Ziolkowski ***") # print("Decoding\n{}".format(obj)) From 9126417836f064847a57f20185617d15ab27a364 Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Sun, 5 Feb 2023 15:11:51 +0100 Subject: [PATCH 228/262] Matter fully implement attribute 0030/0000 (#17885) --- .../berry_mapping/src/be_class_wrapper.c | 2 +- .../berry_matter/src/be_matter_misc.cpp | 47 + .../berry_matter/src/be_matter_module.c | 6 + .../src/embedded/Matter_Plugin_core.be | 37 +- .../berry_matter/src/embedded/Matter_TLV.be | 2 +- .../solidify/solidified_Matter_Plugin_core.h | 1073 ++++++++++------- .../src/solidify/solidified_Matter_TLV.h | 49 +- 7 files changed, 755 insertions(+), 461 deletions(-) create mode 100644 lib/libesp32/berry_matter/src/be_matter_misc.cpp diff --git a/lib/libesp32/berry_mapping/src/be_class_wrapper.c b/lib/libesp32/berry_mapping/src/be_class_wrapper.c index a1f6502bb..bbde814bb 100644 --- a/lib/libesp32/berry_mapping/src/be_class_wrapper.c +++ b/lib/libesp32/berry_mapping/src/be_class_wrapper.c @@ -479,7 +479,7 @@ int be_call_c_func(bvm *vm, const void * func, const char * return_type, const c case 'c': be_pushcomptr(vm, (void*) ret); break; case 's': if (ret) {be_pushstring(vm, (const char*) ret);} else {be_pushnil(vm);} break; // push `nil` if no string case '$': if (ret) {be_pushstring(vm, (const char*) ret); free((void*)ret);} else {be_pushnil(vm);} break; - case '&': be_pushbytes(vm, (void*) ret, return_len); break; + case '&': if (ret) {be_pushbytes(vm, (void*) ret, return_len);} else {be_pushnil(vm);} break; default: be_raise(vm, "internal_error", "Unsupported return type"); break; } be_return(vm); diff --git a/lib/libesp32/berry_matter/src/be_matter_misc.cpp b/lib/libesp32/berry_matter/src/be_matter_misc.cpp new file mode 100644 index 000000000..2ec805183 --- /dev/null +++ b/lib/libesp32/berry_matter/src/be_matter_misc.cpp @@ -0,0 +1,47 @@ +/* + be_matter_misc.c - misc functions for `matter` module + + Copyright (C) 2023 Stephan Hadinger & Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/******************************************************************** + * Matter global module + * + *******************************************************************/ + +#include "be_constobj.h" +#include "be_mapping.h" +#include "IPAddress.h" + +static uint8_t ip_bytes[16] = {}; +// Convert an IP address from string to raw bytes +extern "C" const void* matter_get_ip_bytes(const char* ip_str, size_t* ret_len) { + IPAddress ip; + if (ip.fromString(ip_str)) { + if (ip.isV4()) { + uint32_t ip_32 = ip; + memcpy(ip_bytes, &ip_32, 4); + *ret_len = 4; + } else { + memcpy(ip_bytes, ip.raw6(), 16); + *ret_len = 16; + } + return ip_bytes; + } else { + *ret_len = 0; + return nullptr; + } +} diff --git a/lib/libesp32/berry_matter/src/be_matter_module.c b/lib/libesp32/berry_matter/src/be_matter_module.c index b33a8939f..dce07d4f7 100644 --- a/lib/libesp32/berry_matter/src/be_matter_module.c +++ b/lib/libesp32/berry_matter/src/be_matter_module.c @@ -94,6 +94,11 @@ const char* matter_get_command_name(uint16_t cluster, uint16_t command) { } BE_FUNC_CTYPE_DECLARE(matter_get_command_name, "s", "ii") +// Convert an IP address from string to raw bytes +extern const void* matter_get_ip_bytes(const char* ip_str, size_t* ret_len); +BE_FUNC_CTYPE_DECLARE(matter_get_ip_bytes, "&", "s") + + #include "solidify/solidified_Matter_inspect.h" extern const bclass be_class_Matter_TLV; // need to declare it upfront because of circular reference @@ -149,6 +154,7 @@ module matter (scope: global) { Counter, class(be_class_Matter_Counter) setmember, closure(matter_setmember_closure) member, closure(matter_member_closure) + get_ip_bytes, ctype_func(matter_get_ip_bytes) get_cluster_name, ctype_func(matter_get_cluster_name) get_attribute_name, ctype_func(matter_get_attribute_name) diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_core.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_core.be index 57f516825..02ed99bde 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_core.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_core.be @@ -36,6 +36,7 @@ class Matter_Plugin_core : Matter_Plugin # read an attribute # def read_attribute(msg, endpoint, cluster, attribute) + import string var TLV = matter.TLV if cluster == 0x0030 # ========== GeneralCommissioning cluster 11.9 p.627 ========== @@ -62,7 +63,41 @@ class Matter_Plugin_core : Matter_Plugin elif cluster == 0x0033 # ========== General Diagnostics Cluster 11.11 p.642 ========== if attribute == 0x0000 # ---------- NetworkInterfaces ---------- - var nwi = TLV.Matter_TLV_list() # TODO list network interfaces, empty list for now + var nwi = TLV.Matter_TLV_array() # list network interfaces, empty list for now, p.647 + + var tas_eth = tasmota.eth() + if (tas_eth['up']) + var eth = nwi.add_struct(nil) + eth.add_TLV(0, TLV.UTF1, 'ethernet') # Name + eth.add_TLV(1, TLV.BOOL, 1) # IsOperational + eth.add_TLV(2, TLV.BOOL, 1) # OffPremiseServicesReachableIPv4 + eth.add_TLV(3, TLV.NULL, nil) # OffPremiseServicesReachableIPv6 + var mac = bytes().fromhex(string.replace(tas_eth.find("mac", ""), ":", "")) + eth.add_TLV(4, TLV.B1, mac) # HardwareAddress + var ip4 = eth.add_array(5) # IPv4Addresses + ip4.add_TLV(nil, TLV.B1, matter.get_ip_bytes(tas_eth.find("ip", ""))) + var ip6 = eth.add_array(6) # IPv6Addresses + ip6.add_TLV(nil, TLV.B1, matter.get_ip_bytes(tas_eth.find("ip6local", ""))) + ip6.add_TLV(nil, TLV.B1, matter.get_ip_bytes(tas_eth.find("ip6", ""))) + eth.add_TLV(7, TLV.U1, 2) # InterfaceType, p646 + end + + var tas_wif = tasmota.wifi() + if (tas_wif['up']) + var wif = nwi.add_struct(nil) + wif.add_TLV(0, TLV.UTF1, 'wifi') # Name + wif.add_TLV(1, TLV.BOOL, 1) # IsOperational + wif.add_TLV(2, TLV.BOOL, 1) # OffPremiseServicesReachableIPv4 + wif.add_TLV(3, TLV.NULL, nil) # OffPremiseServicesReachableIPv6 + var mac = bytes().fromhex(string.replace(tas_wif.find("mac", ""), ":", "")) + wif.add_TLV(4, TLV.B1, mac) # HardwareAddress + var ip4 = wif.add_array(5) # IPv4Addresses + ip4.add_TLV(nil, TLV.B1, matter.get_ip_bytes(tas_wif.find("ip", ""))) + var ip6 = wif.add_array(6) # IPv6Addresses + ip6.add_TLV(nil, TLV.B1, matter.get_ip_bytes(tas_wif.find("ip6local", ""))) + ip6.add_TLV(nil, TLV.B1, matter.get_ip_bytes(tas_wif.find("ip6", ""))) + wif.add_TLV(7, TLV.U1, 1) # InterfaceType, p646 + end return nwi elif attribute == 0x0001 # ---------- RebootCount u16 ---------- return TLV.create_TLV(TLV.U2, tasmota.cmd("Status 1")['StatusPRM']['BootCount']) diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_TLV.be b/lib/libesp32/berry_matter/src/embedded/Matter_TLV.be index 58a1e8e13..3f54f56a8 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_TLV.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_TLV.be @@ -563,7 +563,7 @@ class Matter_TLV ############################################################# # adders def add_TLV(tag, t, value) - if value != nil + if value != nil || t == matter.TLV.NULL var v = self.TLV.Matter_TLV_item(self) v.tag_sub = tag v.typ = t diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_core.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_core.h index da9b01a97..a68e124e2 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_core.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_core.h @@ -11,7 +11,7 @@ extern const bclass be_class_Matter_Plugin_core; ********************************************************************/ be_local_closure(Matter_Plugin_core_read_attribute, /* name */ be_nested_proto( - 14, /* nstack */ + 24, /* nstack */ 5, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -19,445 +19,644 @@ be_local_closure(Matter_Plugin_core_read_attribute, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[43]) { /* constants */ - /* K0 */ be_nested_str_weak(matter), - /* K1 */ be_nested_str_weak(TLV), - /* K2 */ be_const_int(0), - /* K3 */ be_nested_str_weak(create_TLV), - /* K4 */ be_nested_str_weak(U8), - /* K5 */ be_nested_str_weak(session), - /* K6 */ be_nested_str_weak(breadcrumb), - /* K7 */ be_const_int(1), - /* K8 */ be_nested_str_weak(Matter_TLV_struct), - /* K9 */ be_nested_str_weak(add_TLV), - /* K10 */ be_nested_str_weak(U2), - /* K11 */ be_const_int(2), - /* K12 */ be_nested_str_weak(U1), - /* K13 */ be_const_int(3), - /* K14 */ be_nested_str_weak(BOOL), - /* K15 */ be_nested_str_weak(Matter_TLV_list), - /* K16 */ be_nested_str_weak(tasmota), - /* K17 */ be_nested_str_weak(cmd), - /* K18 */ be_nested_str_weak(Status_X201), - /* K19 */ be_nested_str_weak(StatusPRM), - /* K20 */ be_nested_str_weak(BootCount), - /* K21 */ be_nested_str_weak(U4), - /* K22 */ be_nested_str_weak(Status_X2011), - /* K23 */ be_nested_str_weak(StatusSTS), - /* K24 */ be_nested_str_weak(UptimeSec), - /* K25 */ be_nested_str_weak(int64), - /* K26 */ be_nested_str_weak(rtc), - /* K27 */ be_nested_str_weak(utc), - /* K28 */ be_const_int(1000000), - /* K29 */ be_nested_str_weak(local), - /* K30 */ be_nested_str_weak(UTF1), - /* K31 */ be_nested_str_weak(Tasmota), - /* K32 */ be_nested_str_weak(device), - /* K33 */ be_nested_str_weak(vendorid), - /* K34 */ be_nested_str_weak(DeviceName), - /* K35 */ be_nested_str_weak(FriendlyName), - /* K36 */ be_nested_str_weak(FriendlyName1), - /* K37 */ be_nested_str_weak(XX), - /* K38 */ be_nested_str_weak(Status_X202), - /* K39 */ be_nested_str_weak(StatusFWR), - /* K40 */ be_nested_str_weak(Hardware), - /* K41 */ be_nested_str_weak(Version), - /* K42 */ be_nested_str_weak(locale), + ( &(const bvalue[63]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(TLV), + /* K3 */ be_const_int(0), + /* K4 */ be_nested_str_weak(create_TLV), + /* K5 */ be_nested_str_weak(U8), + /* K6 */ be_nested_str_weak(session), + /* K7 */ be_nested_str_weak(breadcrumb), + /* K8 */ be_const_int(1), + /* K9 */ be_nested_str_weak(Matter_TLV_struct), + /* K10 */ be_nested_str_weak(add_TLV), + /* K11 */ be_nested_str_weak(U2), + /* K12 */ be_const_int(2), + /* K13 */ be_nested_str_weak(U1), + /* K14 */ be_const_int(3), + /* K15 */ be_nested_str_weak(BOOL), + /* K16 */ be_nested_str_weak(Matter_TLV_array), + /* K17 */ be_nested_str_weak(tasmota), + /* K18 */ be_nested_str_weak(eth), + /* K19 */ be_nested_str_weak(up), + /* K20 */ be_nested_str_weak(add_struct), + /* K21 */ be_nested_str_weak(UTF1), + /* K22 */ be_nested_str_weak(ethernet), + /* K23 */ be_nested_str_weak(NULL), + /* K24 */ be_nested_str_weak(fromhex), + /* K25 */ be_nested_str_weak(replace), + /* K26 */ be_nested_str_weak(find), + /* K27 */ be_nested_str_weak(mac), + /* K28 */ be_nested_str_weak(), + /* K29 */ be_nested_str_weak(_X3A), + /* K30 */ be_nested_str_weak(B1), + /* K31 */ be_nested_str_weak(add_array), + /* K32 */ be_nested_str_weak(get_ip_bytes), + /* K33 */ be_nested_str_weak(ip), + /* K34 */ be_nested_str_weak(ip6local), + /* K35 */ be_nested_str_weak(ip6), + /* K36 */ be_nested_str_weak(wifi), + /* K37 */ be_nested_str_weak(cmd), + /* K38 */ be_nested_str_weak(Status_X201), + /* K39 */ be_nested_str_weak(StatusPRM), + /* K40 */ be_nested_str_weak(BootCount), + /* K41 */ be_nested_str_weak(U4), + /* K42 */ be_nested_str_weak(Status_X2011), + /* K43 */ be_nested_str_weak(StatusSTS), + /* K44 */ be_nested_str_weak(UptimeSec), + /* K45 */ be_nested_str_weak(int64), + /* K46 */ be_nested_str_weak(rtc), + /* K47 */ be_nested_str_weak(utc), + /* K48 */ be_const_int(1000000), + /* K49 */ be_nested_str_weak(local), + /* K50 */ be_nested_str_weak(Tasmota), + /* K51 */ be_nested_str_weak(device), + /* K52 */ be_nested_str_weak(vendorid), + /* K53 */ be_nested_str_weak(DeviceName), + /* K54 */ be_nested_str_weak(FriendlyName), + /* K55 */ be_nested_str_weak(FriendlyName1), + /* K56 */ be_nested_str_weak(XX), + /* K57 */ be_nested_str_weak(Status_X202), + /* K58 */ be_nested_str_weak(StatusFWR), + /* K59 */ be_nested_str_weak(Hardware), + /* K60 */ be_nested_str_weak(Version), + /* K61 */ be_nested_str_weak(locale), + /* K62 */ be_nested_str_weak(Matter_TLV_list), }), be_str_weak(read_attribute), &be_const_str_solidified, - ( &(const binstruction[391]) { /* code */ - 0xB8160000, // 0000 GETNGBL R5 K0 - 0x88140B01, // 0001 GETMBR R5 R5 K1 - 0x541A002F, // 0002 LDINT R6 48 - 0x1C180606, // 0003 EQ R6 R3 R6 - 0x781A0031, // 0004 JMPF R6 #0037 - 0x1C180902, // 0005 EQ R6 R4 K2 - 0x781A0006, // 0006 JMPF R6 #000E - 0x8C180B03, // 0007 GETMET R6 R5 K3 - 0x88200B04, // 0008 GETMBR R8 R5 K4 - 0x88240305, // 0009 GETMBR R9 R1 K5 - 0x88241306, // 000A GETMBR R9 R9 K6 - 0x7C180600, // 000B CALL R6 3 - 0x80040C00, // 000C RET 1 R6 - 0x70020027, // 000D JMP #0036 - 0x1C180907, // 000E EQ R6 R4 K7 - 0x781A000D, // 000F JMPF R6 #001E - 0x8C180B08, // 0010 GETMET R6 R5 K8 - 0x7C180200, // 0011 CALL R6 1 - 0x8C1C0D09, // 0012 GETMET R7 R6 K9 - 0x58240002, // 0013 LDCONST R9 K2 - 0x88280B0A, // 0014 GETMBR R10 R5 K10 - 0x542E003B, // 0015 LDINT R11 60 - 0x7C1C0800, // 0016 CALL R7 4 - 0x8C1C0D09, // 0017 GETMET R7 R6 K9 - 0x58240007, // 0018 LDCONST R9 K7 - 0x88280B0A, // 0019 GETMBR R10 R5 K10 - 0x542E0383, // 001A LDINT R11 900 - 0x7C1C0800, // 001B CALL R7 4 - 0x80040C00, // 001C RET 1 R6 - 0x70020017, // 001D JMP #0036 - 0x1C18090B, // 001E EQ R6 R4 K11 - 0x781A0005, // 001F JMPF R6 #0026 - 0x8C180B03, // 0020 GETMET R6 R5 K3 - 0x88200B0C, // 0021 GETMBR R8 R5 K12 - 0x5824000B, // 0022 LDCONST R9 K11 - 0x7C180600, // 0023 CALL R6 3 - 0x80040C00, // 0024 RET 1 R6 - 0x7002000F, // 0025 JMP #0036 - 0x1C18090D, // 0026 EQ R6 R4 K13 - 0x781A0005, // 0027 JMPF R6 #002E - 0x8C180B03, // 0028 GETMET R6 R5 K3 - 0x88200B0C, // 0029 GETMBR R8 R5 K12 - 0x5824000B, // 002A LDCONST R9 K11 - 0x7C180600, // 002B CALL R6 3 - 0x80040C00, // 002C RET 1 R6 - 0x70020007, // 002D JMP #0036 - 0x541A0003, // 002E LDINT R6 4 - 0x1C180806, // 002F EQ R6 R4 R6 - 0x781A0004, // 0030 JMPF R6 #0036 - 0x8C180B03, // 0031 GETMET R6 R5 K3 - 0x88200B0E, // 0032 GETMBR R8 R5 K14 - 0x50240000, // 0033 LDBOOL R9 0 0 - 0x7C180600, // 0034 CALL R6 3 - 0x80040C00, // 0035 RET 1 R6 - 0x7002014E, // 0036 JMP #0186 - 0x541A0031, // 0037 LDINT R6 50 - 0x1C180606, // 0038 EQ R6 R3 R6 - 0x781A0000, // 0039 JMPF R6 #003B - 0x7002014A, // 003A JMP #0186 - 0x541A0032, // 003B LDINT R6 51 - 0x1C180606, // 003C EQ R6 R3 R6 - 0x781A0028, // 003D JMPF R6 #0067 - 0x1C180902, // 003E EQ R6 R4 K2 - 0x781A0003, // 003F JMPF R6 #0044 - 0x8C180B0F, // 0040 GETMET R6 R5 K15 - 0x7C180200, // 0041 CALL R6 1 - 0x80040C00, // 0042 RET 1 R6 - 0x70020021, // 0043 JMP #0066 - 0x1C180907, // 0044 EQ R6 R4 K7 - 0x781A000A, // 0045 JMPF R6 #0051 - 0x8C180B03, // 0046 GETMET R6 R5 K3 - 0x88200B0A, // 0047 GETMBR R8 R5 K10 - 0xB8262000, // 0048 GETNGBL R9 K16 - 0x8C241311, // 0049 GETMET R9 R9 K17 - 0x582C0012, // 004A LDCONST R11 K18 - 0x7C240400, // 004B CALL R9 2 - 0x94241313, // 004C GETIDX R9 R9 K19 - 0x94241314, // 004D GETIDX R9 R9 K20 - 0x7C180600, // 004E CALL R6 3 - 0x80040C00, // 004F RET 1 R6 - 0x70020014, // 0050 JMP #0066 - 0x1C18090B, // 0051 EQ R6 R4 K11 - 0x781A000A, // 0052 JMPF R6 #005E - 0x8C180B03, // 0053 GETMET R6 R5 K3 - 0x88200B15, // 0054 GETMBR R8 R5 K21 - 0xB8262000, // 0055 GETNGBL R9 K16 - 0x8C241311, // 0056 GETMET R9 R9 K17 - 0x582C0016, // 0057 LDCONST R11 K22 - 0x7C240400, // 0058 CALL R9 2 - 0x94241317, // 0059 GETIDX R9 R9 K23 - 0x94241318, // 005A GETIDX R9 R9 K24 - 0x7C180600, // 005B CALL R6 3 - 0x80040C00, // 005C RET 1 R6 - 0x70020007, // 005D JMP #0066 - 0x541A0007, // 005E LDINT R6 8 - 0x1C180806, // 005F EQ R6 R4 R6 - 0x781A0004, // 0060 JMPF R6 #0066 - 0x8C180B03, // 0061 GETMET R6 R5 K3 - 0x88200B0E, // 0062 GETMBR R8 R5 K14 - 0x50240000, // 0063 LDBOOL R9 0 0 - 0x7C180600, // 0064 CALL R6 3 - 0x80040C00, // 0065 RET 1 R6 - 0x7002011E, // 0066 JMP #0186 - 0x541A0033, // 0067 LDINT R6 52 - 0x1C180606, // 0068 EQ R6 R3 R6 - 0x781A0000, // 0069 JMPF R6 #006B - 0x7002011A, // 006A JMP #0186 - 0x541A0037, // 006B LDINT R6 56 - 0x1C180606, // 006C EQ R6 R3 R6 - 0x781A002C, // 006D JMPF R6 #009B - 0x1C180902, // 006E EQ R6 R4 K2 - 0x781A000F, // 006F JMPF R6 #0080 - 0xB81A3200, // 0070 GETNGBL R6 K25 - 0xB81E2000, // 0071 GETNGBL R7 K16 - 0x8C1C0F1A, // 0072 GETMET R7 R7 K26 - 0x7C1C0200, // 0073 CALL R7 1 - 0x941C0F1B, // 0074 GETIDX R7 R7 K27 - 0x7C180200, // 0075 CALL R6 1 - 0xB81E3200, // 0076 GETNGBL R7 K25 - 0x5820001C, // 0077 LDCONST R8 K28 - 0x7C1C0200, // 0078 CALL R7 1 - 0x08180C07, // 0079 MUL R6 R6 R7 - 0x8C1C0B03, // 007A GETMET R7 R5 K3 - 0x88240B04, // 007B GETMBR R9 R5 K4 - 0x5C280C00, // 007C MOVE R10 R6 - 0x7C1C0600, // 007D CALL R7 3 - 0x80040E00, // 007E RET 1 R7 - 0x70020019, // 007F JMP #009A - 0x1C180907, // 0080 EQ R6 R4 K7 - 0x781A0005, // 0081 JMPF R6 #0088 - 0x8C180B03, // 0082 GETMET R6 R5 K3 - 0x88200B0C, // 0083 GETMBR R8 R5 K12 - 0x5824000D, // 0084 LDCONST R9 K13 - 0x7C180600, // 0085 CALL R6 3 - 0x80040C00, // 0086 RET 1 R6 - 0x70020011, // 0087 JMP #009A - 0x541A0006, // 0088 LDINT R6 7 - 0x1C180806, // 0089 EQ R6 R4 R6 - 0x781A000E, // 008A JMPF R6 #009A - 0xB81A3200, // 008B GETNGBL R6 K25 - 0xB81E2000, // 008C GETNGBL R7 K16 - 0x8C1C0F1A, // 008D GETMET R7 R7 K26 - 0x7C1C0200, // 008E CALL R7 1 - 0x941C0F1D, // 008F GETIDX R7 R7 K29 - 0x7C180200, // 0090 CALL R6 1 - 0xB81E3200, // 0091 GETNGBL R7 K25 - 0x5820001C, // 0092 LDCONST R8 K28 - 0x7C1C0200, // 0093 CALL R7 1 - 0x08180C07, // 0094 MUL R6 R6 R7 - 0x8C1C0B03, // 0095 GETMET R7 R5 K3 - 0x88240B04, // 0096 GETMBR R9 R5 K4 - 0x5C280C00, // 0097 MOVE R10 R6 - 0x7C1C0600, // 0098 CALL R7 3 - 0x80040E00, // 0099 RET 1 R7 - 0x700200EA, // 009A JMP #0186 - 0x541A003D, // 009B LDINT R6 62 - 0x1C180606, // 009C EQ R6 R3 R6 - 0x781A001D, // 009D JMPF R6 #00BC - 0x1C180902, // 009E EQ R6 R4 K2 - 0x781A0000, // 009F JMPF R6 #00A1 - 0x70020019, // 00A0 JMP #00BB - 0x1C180907, // 00A1 EQ R6 R4 K7 - 0x781A0000, // 00A2 JMPF R6 #00A4 - 0x70020016, // 00A3 JMP #00BB - 0x1C18090B, // 00A4 EQ R6 R4 K11 - 0x781A0005, // 00A5 JMPF R6 #00AC - 0x8C180B03, // 00A6 GETMET R6 R5 K3 - 0x88200B0C, // 00A7 GETMBR R8 R5 K12 - 0x54260004, // 00A8 LDINT R9 5 - 0x7C180600, // 00A9 CALL R6 3 - 0x80040C00, // 00AA RET 1 R6 - 0x7002000E, // 00AB JMP #00BB - 0x1C18090D, // 00AC EQ R6 R4 K13 - 0x781A0005, // 00AD JMPF R6 #00B4 - 0x8C180B03, // 00AE GETMET R6 R5 K3 - 0x88200B0C, // 00AF GETMBR R8 R5 K12 - 0x58240007, // 00B0 LDCONST R9 K7 - 0x7C180600, // 00B1 CALL R6 3 - 0x80040C00, // 00B2 RET 1 R6 - 0x70020006, // 00B3 JMP #00BB - 0x541A0003, // 00B4 LDINT R6 4 - 0x1C180806, // 00B5 EQ R6 R4 R6 - 0x781A0000, // 00B6 JMPF R6 #00B8 - 0x70020002, // 00B7 JMP #00BB - 0x541A0004, // 00B8 LDINT R6 5 - 0x1C180806, // 00B9 EQ R6 R4 R6 - 0x7819FFFF, // 00BA JMPF R6 #00BB - 0x700200C9, // 00BB JMP #0186 - 0x541A003B, // 00BC LDINT R6 60 - 0x1C180606, // 00BD EQ R6 R3 R6 - 0x781A0000, // 00BE JMPF R6 #00C0 - 0x700200C5, // 00BF JMP #0186 - 0x541A0027, // 00C0 LDINT R6 40 - 0x1C180606, // 00C1 EQ R6 R3 R6 - 0x781A0071, // 00C2 JMPF R6 #0135 - 0x1C180902, // 00C3 EQ R6 R4 K2 - 0x781A0005, // 00C4 JMPF R6 #00CB - 0x8C180B03, // 00C5 GETMET R6 R5 K3 - 0x88200B0A, // 00C6 GETMBR R8 R5 K10 - 0x58240002, // 00C7 LDCONST R9 K2 - 0x7C180600, // 00C8 CALL R6 3 - 0x80040C00, // 00C9 RET 1 R6 - 0x70020068, // 00CA JMP #0134 - 0x1C180907, // 00CB EQ R6 R4 K7 - 0x781A0005, // 00CC JMPF R6 #00D3 - 0x8C180B03, // 00CD GETMET R6 R5 K3 - 0x88200B1E, // 00CE GETMBR R8 R5 K30 - 0x5824001F, // 00CF LDCONST R9 K31 - 0x7C180600, // 00D0 CALL R6 3 - 0x80040C00, // 00D1 RET 1 R6 - 0x70020060, // 00D2 JMP #0134 - 0x1C18090B, // 00D3 EQ R6 R4 K11 - 0x781A0006, // 00D4 JMPF R6 #00DC - 0x8C180B03, // 00D5 GETMET R6 R5 K3 - 0x88200B0A, // 00D6 GETMBR R8 R5 K10 - 0x88240120, // 00D7 GETMBR R9 R0 K32 - 0x88241321, // 00D8 GETMBR R9 R9 K33 - 0x7C180600, // 00D9 CALL R6 3 - 0x80040C00, // 00DA RET 1 R6 - 0x70020057, // 00DB JMP #0134 - 0x1C18090D, // 00DC EQ R6 R4 K13 - 0x781A0009, // 00DD JMPF R6 #00E8 - 0x8C180B03, // 00DE GETMET R6 R5 K3 - 0x88200B1E, // 00DF GETMBR R8 R5 K30 - 0xB8262000, // 00E0 GETNGBL R9 K16 - 0x8C241311, // 00E1 GETMET R9 R9 K17 - 0x582C0022, // 00E2 LDCONST R11 K34 - 0x7C240400, // 00E3 CALL R9 2 - 0x94241322, // 00E4 GETIDX R9 R9 K34 - 0x7C180600, // 00E5 CALL R6 3 - 0x80040C00, // 00E6 RET 1 R6 - 0x7002004B, // 00E7 JMP #0134 - 0x541A0003, // 00E8 LDINT R6 4 - 0x1C180806, // 00E9 EQ R6 R4 R6 - 0x781A0005, // 00EA JMPF R6 #00F1 - 0x8C180B03, // 00EB GETMET R6 R5 K3 - 0x88200B0A, // 00EC GETMBR R8 R5 K10 - 0x54267FFF, // 00ED LDINT R9 32768 - 0x7C180600, // 00EE CALL R6 3 - 0x80040C00, // 00EF RET 1 R6 - 0x70020042, // 00F0 JMP #0134 - 0x541A0004, // 00F1 LDINT R6 5 - 0x1C180806, // 00F2 EQ R6 R4 R6 - 0x781A0009, // 00F3 JMPF R6 #00FE - 0x8C180B03, // 00F4 GETMET R6 R5 K3 - 0x88200B1E, // 00F5 GETMBR R8 R5 K30 - 0xB8262000, // 00F6 GETNGBL R9 K16 - 0x8C241311, // 00F7 GETMET R9 R9 K17 - 0x582C0023, // 00F8 LDCONST R11 K35 - 0x7C240400, // 00F9 CALL R9 2 - 0x94241324, // 00FA GETIDX R9 R9 K36 - 0x7C180600, // 00FB CALL R6 3 - 0x80040C00, // 00FC RET 1 R6 - 0x70020035, // 00FD JMP #0134 - 0x541A0005, // 00FE LDINT R6 6 - 0x1C180806, // 00FF EQ R6 R4 R6 - 0x781A0005, // 0100 JMPF R6 #0107 - 0x8C180B03, // 0101 GETMET R6 R5 K3 - 0x88200B1E, // 0102 GETMBR R8 R5 K30 - 0x58240025, // 0103 LDCONST R9 K37 - 0x7C180600, // 0104 CALL R6 3 - 0x80040C00, // 0105 RET 1 R6 - 0x7002002C, // 0106 JMP #0134 - 0x541A0006, // 0107 LDINT R6 7 - 0x1C180806, // 0108 EQ R6 R4 R6 - 0x781A0005, // 0109 JMPF R6 #0110 - 0x8C180B03, // 010A GETMET R6 R5 K3 - 0x88200B0A, // 010B GETMBR R8 R5 K10 - 0x58240002, // 010C LDCONST R9 K2 - 0x7C180600, // 010D CALL R6 3 - 0x80040C00, // 010E RET 1 R6 - 0x70020023, // 010F JMP #0134 - 0x541A0007, // 0110 LDINT R6 8 - 0x1C180806, // 0111 EQ R6 R4 R6 - 0x781A000A, // 0112 JMPF R6 #011E - 0x8C180B03, // 0113 GETMET R6 R5 K3 - 0x88200B1E, // 0114 GETMBR R8 R5 K30 - 0xB8262000, // 0115 GETNGBL R9 K16 - 0x8C241311, // 0116 GETMET R9 R9 K17 - 0x582C0026, // 0117 LDCONST R11 K38 - 0x7C240400, // 0118 CALL R9 2 - 0x94241327, // 0119 GETIDX R9 R9 K39 - 0x94241328, // 011A GETIDX R9 R9 K40 - 0x7C180600, // 011B CALL R6 3 - 0x80040C00, // 011C RET 1 R6 - 0x70020015, // 011D JMP #0134 - 0x541A0008, // 011E LDINT R6 9 - 0x1C180806, // 011F EQ R6 R4 R6 - 0x781A0005, // 0120 JMPF R6 #0127 - 0x8C180B03, // 0121 GETMET R6 R5 K3 - 0x88200B0A, // 0122 GETMBR R8 R5 K10 - 0x58240002, // 0123 LDCONST R9 K2 - 0x7C180600, // 0124 CALL R6 3 - 0x80040C00, // 0125 RET 1 R6 - 0x7002000C, // 0126 JMP #0134 - 0x541A0009, // 0127 LDINT R6 10 - 0x1C180806, // 0128 EQ R6 R4 R6 - 0x781A0009, // 0129 JMPF R6 #0134 - 0x8C180B03, // 012A GETMET R6 R5 K3 - 0x88200B1E, // 012B GETMBR R8 R5 K30 - 0xB8262000, // 012C GETNGBL R9 K16 - 0x8C241311, // 012D GETMET R9 R9 K17 - 0x582C0026, // 012E LDCONST R11 K38 - 0x7C240400, // 012F CALL R9 2 - 0x94241327, // 0130 GETIDX R9 R9 K39 - 0x94241329, // 0131 GETIDX R9 R9 K41 - 0x7C180600, // 0132 CALL R6 3 - 0x80040C00, // 0133 RET 1 R6 - 0x70020050, // 0134 JMP #0186 - 0x541A003E, // 0135 LDINT R6 63 - 0x1C180606, // 0136 EQ R6 R3 R6 - 0x781A0000, // 0137 JMPF R6 #0139 - 0x7002004C, // 0138 JMP #0186 - 0x541A002A, // 0139 LDINT R6 43 - 0x1C180606, // 013A EQ R6 R3 R6 - 0x781A0016, // 013B JMPF R6 #0153 - 0x1C180902, // 013C EQ R6 R4 K2 - 0x781A0007, // 013D JMPF R6 #0146 - 0x8C180B03, // 013E GETMET R6 R5 K3 - 0x88200B1E, // 013F GETMBR R8 R5 K30 - 0xB8262000, // 0140 GETNGBL R9 K16 - 0x8C24132A, // 0141 GETMET R9 R9 K42 - 0x7C240200, // 0142 CALL R9 1 - 0x7C180600, // 0143 CALL R6 3 - 0x80040C00, // 0144 RET 1 R6 - 0x7002000B, // 0145 JMP #0152 - 0x1C180907, // 0146 EQ R6 R4 K7 - 0x781A0009, // 0147 JMPF R6 #0152 - 0x8C180B0F, // 0148 GETMET R6 R5 K15 - 0x7C180200, // 0149 CALL R6 1 - 0x8C1C0D09, // 014A GETMET R7 R6 K9 - 0x4C240000, // 014B LDNIL R9 - 0x88280B1E, // 014C GETMBR R10 R5 K30 - 0xB82E2000, // 014D GETNGBL R11 K16 - 0x8C2C172A, // 014E GETMET R11 R11 K42 - 0x7C2C0200, // 014F CALL R11 1 - 0x7C1C0800, // 0150 CALL R7 4 - 0x80040C00, // 0151 RET 1 R6 - 0x70020032, // 0152 JMP #0186 - 0x541A002B, // 0153 LDINT R6 44 - 0x1C180606, // 0154 EQ R6 R3 R6 - 0x781A001C, // 0155 JMPF R6 #0173 - 0x1C180902, // 0156 EQ R6 R4 K2 - 0x781A0005, // 0157 JMPF R6 #015E - 0x8C180B03, // 0158 GETMET R6 R5 K3 - 0x88200B0C, // 0159 GETMBR R8 R5 K12 - 0x58240007, // 015A LDCONST R9 K7 - 0x7C180600, // 015B CALL R6 3 - 0x80040C00, // 015C RET 1 R6 - 0x70020013, // 015D JMP #0172 - 0x1C180907, // 015E EQ R6 R4 K7 - 0x781A0005, // 015F JMPF R6 #0166 - 0x8C180B03, // 0160 GETMET R6 R5 K3 - 0x88200B0C, // 0161 GETMBR R8 R5 K12 - 0x54260003, // 0162 LDINT R9 4 - 0x7C180600, // 0163 CALL R6 3 - 0x80040C00, // 0164 RET 1 R6 - 0x7002000B, // 0165 JMP #0172 - 0x1C18090B, // 0166 EQ R6 R4 K11 - 0x781A0009, // 0167 JMPF R6 #0172 - 0x8C180B0F, // 0168 GETMET R6 R5 K15 - 0x7C180200, // 0169 CALL R6 1 - 0x8C1C0D09, // 016A GETMET R7 R6 K9 - 0x4C240000, // 016B LDNIL R9 - 0x8C280B03, // 016C GETMET R10 R5 K3 - 0x88300B0C, // 016D GETMBR R12 R5 K12 - 0x54360003, // 016E LDINT R13 4 - 0x7C280600, // 016F CALL R10 3 - 0x7C1C0600, // 0170 CALL R7 3 - 0x80040C00, // 0171 RET 1 R6 - 0x70020012, // 0172 JMP #0186 - 0x541A0030, // 0173 LDINT R6 49 - 0x1C180606, // 0174 EQ R6 R3 R6 - 0x781A000F, // 0175 JMPF R6 #0186 - 0x1C18090D, // 0176 EQ R6 R4 K13 - 0x781A0005, // 0177 JMPF R6 #017E - 0x8C180B03, // 0178 GETMET R6 R5 K3 - 0x88200B0C, // 0179 GETMBR R8 R5 K12 - 0x5426001D, // 017A LDINT R9 30 - 0x7C180600, // 017B CALL R6 3 - 0x80040C00, // 017C RET 1 R6 - 0x70020007, // 017D JMP #0186 - 0x541AFFFB, // 017E LDINT R6 65532 - 0x1C180806, // 017F EQ R6 R4 R6 - 0x781A0004, // 0180 JMPF R6 #0186 - 0x8C180B03, // 0181 GETMET R6 R5 K3 - 0x88200B15, // 0182 GETMBR R8 R5 K21 - 0x58240002, // 0183 LDCONST R9 K2 - 0x7C180600, // 0184 CALL R6 3 - 0x80040C00, // 0185 RET 1 R6 - 0x80000000, // 0186 RET 0 + ( &(const binstruction[570]) { /* code */ + 0xA4160000, // 0000 IMPORT R5 K0 + 0xB81A0200, // 0001 GETNGBL R6 K1 + 0x88180D02, // 0002 GETMBR R6 R6 K2 + 0x541E002F, // 0003 LDINT R7 48 + 0x1C1C0607, // 0004 EQ R7 R3 R7 + 0x781E0031, // 0005 JMPF R7 #0038 + 0x1C1C0903, // 0006 EQ R7 R4 K3 + 0x781E0006, // 0007 JMPF R7 #000F + 0x8C1C0D04, // 0008 GETMET R7 R6 K4 + 0x88240D05, // 0009 GETMBR R9 R6 K5 + 0x88280306, // 000A GETMBR R10 R1 K6 + 0x88281507, // 000B GETMBR R10 R10 K7 + 0x7C1C0600, // 000C CALL R7 3 + 0x80040E00, // 000D RET 1 R7 + 0x70020027, // 000E JMP #0037 + 0x1C1C0908, // 000F EQ R7 R4 K8 + 0x781E000D, // 0010 JMPF R7 #001F + 0x8C1C0D09, // 0011 GETMET R7 R6 K9 + 0x7C1C0200, // 0012 CALL R7 1 + 0x8C200F0A, // 0013 GETMET R8 R7 K10 + 0x58280003, // 0014 LDCONST R10 K3 + 0x882C0D0B, // 0015 GETMBR R11 R6 K11 + 0x5432003B, // 0016 LDINT R12 60 + 0x7C200800, // 0017 CALL R8 4 + 0x8C200F0A, // 0018 GETMET R8 R7 K10 + 0x58280008, // 0019 LDCONST R10 K8 + 0x882C0D0B, // 001A GETMBR R11 R6 K11 + 0x54320383, // 001B LDINT R12 900 + 0x7C200800, // 001C CALL R8 4 + 0x80040E00, // 001D RET 1 R7 + 0x70020017, // 001E JMP #0037 + 0x1C1C090C, // 001F EQ R7 R4 K12 + 0x781E0005, // 0020 JMPF R7 #0027 + 0x8C1C0D04, // 0021 GETMET R7 R6 K4 + 0x88240D0D, // 0022 GETMBR R9 R6 K13 + 0x5828000C, // 0023 LDCONST R10 K12 + 0x7C1C0600, // 0024 CALL R7 3 + 0x80040E00, // 0025 RET 1 R7 + 0x7002000F, // 0026 JMP #0037 + 0x1C1C090E, // 0027 EQ R7 R4 K14 + 0x781E0005, // 0028 JMPF R7 #002F + 0x8C1C0D04, // 0029 GETMET R7 R6 K4 + 0x88240D0D, // 002A GETMBR R9 R6 K13 + 0x5828000C, // 002B LDCONST R10 K12 + 0x7C1C0600, // 002C CALL R7 3 + 0x80040E00, // 002D RET 1 R7 + 0x70020007, // 002E JMP #0037 + 0x541E0003, // 002F LDINT R7 4 + 0x1C1C0807, // 0030 EQ R7 R4 R7 + 0x781E0004, // 0031 JMPF R7 #0037 + 0x8C1C0D04, // 0032 GETMET R7 R6 K4 + 0x88240D0F, // 0033 GETMBR R9 R6 K15 + 0x50280000, // 0034 LDBOOL R10 0 0 + 0x7C1C0600, // 0035 CALL R7 3 + 0x80040E00, // 0036 RET 1 R7 + 0x70020200, // 0037 JMP #0239 + 0x541E0031, // 0038 LDINT R7 50 + 0x1C1C0607, // 0039 EQ R7 R3 R7 + 0x781E0000, // 003A JMPF R7 #003C + 0x700201FC, // 003B JMP #0239 + 0x541E0032, // 003C LDINT R7 51 + 0x1C1C0607, // 003D EQ R7 R3 R7 + 0x781E00DA, // 003E JMPF R7 #011A + 0x1C1C0903, // 003F EQ R7 R4 K3 + 0x781E00B5, // 0040 JMPF R7 #00F7 + 0x8C1C0D10, // 0041 GETMET R7 R6 K16 + 0x7C1C0200, // 0042 CALL R7 1 + 0xB8222200, // 0043 GETNGBL R8 K17 + 0x8C201112, // 0044 GETMET R8 R8 K18 + 0x7C200200, // 0045 CALL R8 1 + 0x94241113, // 0046 GETIDX R9 R8 K19 + 0x78260053, // 0047 JMPF R9 #009C + 0x8C240F14, // 0048 GETMET R9 R7 K20 + 0x4C2C0000, // 0049 LDNIL R11 + 0x7C240400, // 004A CALL R9 2 + 0x8C28130A, // 004B GETMET R10 R9 K10 + 0x58300003, // 004C LDCONST R12 K3 + 0x88340D15, // 004D GETMBR R13 R6 K21 + 0x58380016, // 004E LDCONST R14 K22 + 0x7C280800, // 004F CALL R10 4 + 0x8C28130A, // 0050 GETMET R10 R9 K10 + 0x58300008, // 0051 LDCONST R12 K8 + 0x88340D0F, // 0052 GETMBR R13 R6 K15 + 0x58380008, // 0053 LDCONST R14 K8 + 0x7C280800, // 0054 CALL R10 4 + 0x8C28130A, // 0055 GETMET R10 R9 K10 + 0x5830000C, // 0056 LDCONST R12 K12 + 0x88340D0F, // 0057 GETMBR R13 R6 K15 + 0x58380008, // 0058 LDCONST R14 K8 + 0x7C280800, // 0059 CALL R10 4 + 0x8C28130A, // 005A GETMET R10 R9 K10 + 0x5830000E, // 005B LDCONST R12 K14 + 0x88340D17, // 005C GETMBR R13 R6 K23 + 0x4C380000, // 005D LDNIL R14 + 0x7C280800, // 005E CALL R10 4 + 0x60280015, // 005F GETGBL R10 G21 + 0x7C280000, // 0060 CALL R10 0 + 0x8C281518, // 0061 GETMET R10 R10 K24 + 0x8C300B19, // 0062 GETMET R12 R5 K25 + 0x8C38111A, // 0063 GETMET R14 R8 K26 + 0x5840001B, // 0064 LDCONST R16 K27 + 0x5844001C, // 0065 LDCONST R17 K28 + 0x7C380600, // 0066 CALL R14 3 + 0x583C001D, // 0067 LDCONST R15 K29 + 0x5840001C, // 0068 LDCONST R16 K28 + 0x7C300800, // 0069 CALL R12 4 + 0x7C280400, // 006A CALL R10 2 + 0x8C2C130A, // 006B GETMET R11 R9 K10 + 0x54360003, // 006C LDINT R13 4 + 0x88380D1E, // 006D GETMBR R14 R6 K30 + 0x5C3C1400, // 006E MOVE R15 R10 + 0x7C2C0800, // 006F CALL R11 4 + 0x8C2C131F, // 0070 GETMET R11 R9 K31 + 0x54360004, // 0071 LDINT R13 5 + 0x7C2C0400, // 0072 CALL R11 2 + 0x8C30170A, // 0073 GETMET R12 R11 K10 + 0x4C380000, // 0074 LDNIL R14 + 0x883C0D1E, // 0075 GETMBR R15 R6 K30 + 0xB8420200, // 0076 GETNGBL R16 K1 + 0x8C402120, // 0077 GETMET R16 R16 K32 + 0x8C48111A, // 0078 GETMET R18 R8 K26 + 0x58500021, // 0079 LDCONST R20 K33 + 0x5854001C, // 007A LDCONST R21 K28 + 0x7C480600, // 007B CALL R18 3 + 0x7C400400, // 007C CALL R16 2 + 0x7C300800, // 007D CALL R12 4 + 0x8C30131F, // 007E GETMET R12 R9 K31 + 0x543A0005, // 007F LDINT R14 6 + 0x7C300400, // 0080 CALL R12 2 + 0x8C34190A, // 0081 GETMET R13 R12 K10 + 0x4C3C0000, // 0082 LDNIL R15 + 0x88400D1E, // 0083 GETMBR R16 R6 K30 + 0xB8460200, // 0084 GETNGBL R17 K1 + 0x8C442320, // 0085 GETMET R17 R17 K32 + 0x8C4C111A, // 0086 GETMET R19 R8 K26 + 0x58540022, // 0087 LDCONST R21 K34 + 0x5858001C, // 0088 LDCONST R22 K28 + 0x7C4C0600, // 0089 CALL R19 3 + 0x7C440400, // 008A CALL R17 2 + 0x7C340800, // 008B CALL R13 4 + 0x8C34190A, // 008C GETMET R13 R12 K10 + 0x4C3C0000, // 008D LDNIL R15 + 0x88400D1E, // 008E GETMBR R16 R6 K30 + 0xB8460200, // 008F GETNGBL R17 K1 + 0x8C442320, // 0090 GETMET R17 R17 K32 + 0x8C4C111A, // 0091 GETMET R19 R8 K26 + 0x58540023, // 0092 LDCONST R21 K35 + 0x5858001C, // 0093 LDCONST R22 K28 + 0x7C4C0600, // 0094 CALL R19 3 + 0x7C440400, // 0095 CALL R17 2 + 0x7C340800, // 0096 CALL R13 4 + 0x8C34130A, // 0097 GETMET R13 R9 K10 + 0x543E0006, // 0098 LDINT R15 7 + 0x88400D0D, // 0099 GETMBR R16 R6 K13 + 0x5844000C, // 009A LDCONST R17 K12 + 0x7C340800, // 009B CALL R13 4 + 0xB8262200, // 009C GETNGBL R9 K17 + 0x8C241324, // 009D GETMET R9 R9 K36 + 0x7C240200, // 009E CALL R9 1 + 0x94281313, // 009F GETIDX R10 R9 K19 + 0x782A0053, // 00A0 JMPF R10 #00F5 + 0x8C280F14, // 00A1 GETMET R10 R7 K20 + 0x4C300000, // 00A2 LDNIL R12 + 0x7C280400, // 00A3 CALL R10 2 + 0x8C2C150A, // 00A4 GETMET R11 R10 K10 + 0x58340003, // 00A5 LDCONST R13 K3 + 0x88380D15, // 00A6 GETMBR R14 R6 K21 + 0x583C0024, // 00A7 LDCONST R15 K36 + 0x7C2C0800, // 00A8 CALL R11 4 + 0x8C2C150A, // 00A9 GETMET R11 R10 K10 + 0x58340008, // 00AA LDCONST R13 K8 + 0x88380D0F, // 00AB GETMBR R14 R6 K15 + 0x583C0008, // 00AC LDCONST R15 K8 + 0x7C2C0800, // 00AD CALL R11 4 + 0x8C2C150A, // 00AE GETMET R11 R10 K10 + 0x5834000C, // 00AF LDCONST R13 K12 + 0x88380D0F, // 00B0 GETMBR R14 R6 K15 + 0x583C0008, // 00B1 LDCONST R15 K8 + 0x7C2C0800, // 00B2 CALL R11 4 + 0x8C2C150A, // 00B3 GETMET R11 R10 K10 + 0x5834000E, // 00B4 LDCONST R13 K14 + 0x88380D17, // 00B5 GETMBR R14 R6 K23 + 0x4C3C0000, // 00B6 LDNIL R15 + 0x7C2C0800, // 00B7 CALL R11 4 + 0x602C0015, // 00B8 GETGBL R11 G21 + 0x7C2C0000, // 00B9 CALL R11 0 + 0x8C2C1718, // 00BA GETMET R11 R11 K24 + 0x8C340B19, // 00BB GETMET R13 R5 K25 + 0x8C3C131A, // 00BC GETMET R15 R9 K26 + 0x5844001B, // 00BD LDCONST R17 K27 + 0x5848001C, // 00BE LDCONST R18 K28 + 0x7C3C0600, // 00BF CALL R15 3 + 0x5840001D, // 00C0 LDCONST R16 K29 + 0x5844001C, // 00C1 LDCONST R17 K28 + 0x7C340800, // 00C2 CALL R13 4 + 0x7C2C0400, // 00C3 CALL R11 2 + 0x8C30150A, // 00C4 GETMET R12 R10 K10 + 0x543A0003, // 00C5 LDINT R14 4 + 0x883C0D1E, // 00C6 GETMBR R15 R6 K30 + 0x5C401600, // 00C7 MOVE R16 R11 + 0x7C300800, // 00C8 CALL R12 4 + 0x8C30151F, // 00C9 GETMET R12 R10 K31 + 0x543A0004, // 00CA LDINT R14 5 + 0x7C300400, // 00CB CALL R12 2 + 0x8C34190A, // 00CC GETMET R13 R12 K10 + 0x4C3C0000, // 00CD LDNIL R15 + 0x88400D1E, // 00CE GETMBR R16 R6 K30 + 0xB8460200, // 00CF GETNGBL R17 K1 + 0x8C442320, // 00D0 GETMET R17 R17 K32 + 0x8C4C131A, // 00D1 GETMET R19 R9 K26 + 0x58540021, // 00D2 LDCONST R21 K33 + 0x5858001C, // 00D3 LDCONST R22 K28 + 0x7C4C0600, // 00D4 CALL R19 3 + 0x7C440400, // 00D5 CALL R17 2 + 0x7C340800, // 00D6 CALL R13 4 + 0x8C34151F, // 00D7 GETMET R13 R10 K31 + 0x543E0005, // 00D8 LDINT R15 6 + 0x7C340400, // 00D9 CALL R13 2 + 0x8C381B0A, // 00DA GETMET R14 R13 K10 + 0x4C400000, // 00DB LDNIL R16 + 0x88440D1E, // 00DC GETMBR R17 R6 K30 + 0xB84A0200, // 00DD GETNGBL R18 K1 + 0x8C482520, // 00DE GETMET R18 R18 K32 + 0x8C50131A, // 00DF GETMET R20 R9 K26 + 0x58580022, // 00E0 LDCONST R22 K34 + 0x585C001C, // 00E1 LDCONST R23 K28 + 0x7C500600, // 00E2 CALL R20 3 + 0x7C480400, // 00E3 CALL R18 2 + 0x7C380800, // 00E4 CALL R14 4 + 0x8C381B0A, // 00E5 GETMET R14 R13 K10 + 0x4C400000, // 00E6 LDNIL R16 + 0x88440D1E, // 00E7 GETMBR R17 R6 K30 + 0xB84A0200, // 00E8 GETNGBL R18 K1 + 0x8C482520, // 00E9 GETMET R18 R18 K32 + 0x8C50131A, // 00EA GETMET R20 R9 K26 + 0x58580023, // 00EB LDCONST R22 K35 + 0x585C001C, // 00EC LDCONST R23 K28 + 0x7C500600, // 00ED CALL R20 3 + 0x7C480400, // 00EE CALL R18 2 + 0x7C380800, // 00EF CALL R14 4 + 0x8C38150A, // 00F0 GETMET R14 R10 K10 + 0x54420006, // 00F1 LDINT R16 7 + 0x88440D0D, // 00F2 GETMBR R17 R6 K13 + 0x58480008, // 00F3 LDCONST R18 K8 + 0x7C380800, // 00F4 CALL R14 4 + 0x80040E00, // 00F5 RET 1 R7 + 0x70020021, // 00F6 JMP #0119 + 0x1C1C0908, // 00F7 EQ R7 R4 K8 + 0x781E000A, // 00F8 JMPF R7 #0104 + 0x8C1C0D04, // 00F9 GETMET R7 R6 K4 + 0x88240D0B, // 00FA GETMBR R9 R6 K11 + 0xB82A2200, // 00FB GETNGBL R10 K17 + 0x8C281525, // 00FC GETMET R10 R10 K37 + 0x58300026, // 00FD LDCONST R12 K38 + 0x7C280400, // 00FE CALL R10 2 + 0x94281527, // 00FF GETIDX R10 R10 K39 + 0x94281528, // 0100 GETIDX R10 R10 K40 + 0x7C1C0600, // 0101 CALL R7 3 + 0x80040E00, // 0102 RET 1 R7 + 0x70020014, // 0103 JMP #0119 + 0x1C1C090C, // 0104 EQ R7 R4 K12 + 0x781E000A, // 0105 JMPF R7 #0111 + 0x8C1C0D04, // 0106 GETMET R7 R6 K4 + 0x88240D29, // 0107 GETMBR R9 R6 K41 + 0xB82A2200, // 0108 GETNGBL R10 K17 + 0x8C281525, // 0109 GETMET R10 R10 K37 + 0x5830002A, // 010A LDCONST R12 K42 + 0x7C280400, // 010B CALL R10 2 + 0x9428152B, // 010C GETIDX R10 R10 K43 + 0x9428152C, // 010D GETIDX R10 R10 K44 + 0x7C1C0600, // 010E CALL R7 3 + 0x80040E00, // 010F RET 1 R7 + 0x70020007, // 0110 JMP #0119 + 0x541E0007, // 0111 LDINT R7 8 + 0x1C1C0807, // 0112 EQ R7 R4 R7 + 0x781E0004, // 0113 JMPF R7 #0119 + 0x8C1C0D04, // 0114 GETMET R7 R6 K4 + 0x88240D0F, // 0115 GETMBR R9 R6 K15 + 0x50280000, // 0116 LDBOOL R10 0 0 + 0x7C1C0600, // 0117 CALL R7 3 + 0x80040E00, // 0118 RET 1 R7 + 0x7002011E, // 0119 JMP #0239 + 0x541E0033, // 011A LDINT R7 52 + 0x1C1C0607, // 011B EQ R7 R3 R7 + 0x781E0000, // 011C JMPF R7 #011E + 0x7002011A, // 011D JMP #0239 + 0x541E0037, // 011E LDINT R7 56 + 0x1C1C0607, // 011F EQ R7 R3 R7 + 0x781E002C, // 0120 JMPF R7 #014E + 0x1C1C0903, // 0121 EQ R7 R4 K3 + 0x781E000F, // 0122 JMPF R7 #0133 + 0xB81E5A00, // 0123 GETNGBL R7 K45 + 0xB8222200, // 0124 GETNGBL R8 K17 + 0x8C20112E, // 0125 GETMET R8 R8 K46 + 0x7C200200, // 0126 CALL R8 1 + 0x9420112F, // 0127 GETIDX R8 R8 K47 + 0x7C1C0200, // 0128 CALL R7 1 + 0xB8225A00, // 0129 GETNGBL R8 K45 + 0x58240030, // 012A LDCONST R9 K48 + 0x7C200200, // 012B CALL R8 1 + 0x081C0E08, // 012C MUL R7 R7 R8 + 0x8C200D04, // 012D GETMET R8 R6 K4 + 0x88280D05, // 012E GETMBR R10 R6 K5 + 0x5C2C0E00, // 012F MOVE R11 R7 + 0x7C200600, // 0130 CALL R8 3 + 0x80041000, // 0131 RET 1 R8 + 0x70020019, // 0132 JMP #014D + 0x1C1C0908, // 0133 EQ R7 R4 K8 + 0x781E0005, // 0134 JMPF R7 #013B + 0x8C1C0D04, // 0135 GETMET R7 R6 K4 + 0x88240D0D, // 0136 GETMBR R9 R6 K13 + 0x5828000E, // 0137 LDCONST R10 K14 + 0x7C1C0600, // 0138 CALL R7 3 + 0x80040E00, // 0139 RET 1 R7 + 0x70020011, // 013A JMP #014D + 0x541E0006, // 013B LDINT R7 7 + 0x1C1C0807, // 013C EQ R7 R4 R7 + 0x781E000E, // 013D JMPF R7 #014D + 0xB81E5A00, // 013E GETNGBL R7 K45 + 0xB8222200, // 013F GETNGBL R8 K17 + 0x8C20112E, // 0140 GETMET R8 R8 K46 + 0x7C200200, // 0141 CALL R8 1 + 0x94201131, // 0142 GETIDX R8 R8 K49 + 0x7C1C0200, // 0143 CALL R7 1 + 0xB8225A00, // 0144 GETNGBL R8 K45 + 0x58240030, // 0145 LDCONST R9 K48 + 0x7C200200, // 0146 CALL R8 1 + 0x081C0E08, // 0147 MUL R7 R7 R8 + 0x8C200D04, // 0148 GETMET R8 R6 K4 + 0x88280D05, // 0149 GETMBR R10 R6 K5 + 0x5C2C0E00, // 014A MOVE R11 R7 + 0x7C200600, // 014B CALL R8 3 + 0x80041000, // 014C RET 1 R8 + 0x700200EA, // 014D JMP #0239 + 0x541E003D, // 014E LDINT R7 62 + 0x1C1C0607, // 014F EQ R7 R3 R7 + 0x781E001D, // 0150 JMPF R7 #016F + 0x1C1C0903, // 0151 EQ R7 R4 K3 + 0x781E0000, // 0152 JMPF R7 #0154 + 0x70020019, // 0153 JMP #016E + 0x1C1C0908, // 0154 EQ R7 R4 K8 + 0x781E0000, // 0155 JMPF R7 #0157 + 0x70020016, // 0156 JMP #016E + 0x1C1C090C, // 0157 EQ R7 R4 K12 + 0x781E0005, // 0158 JMPF R7 #015F + 0x8C1C0D04, // 0159 GETMET R7 R6 K4 + 0x88240D0D, // 015A GETMBR R9 R6 K13 + 0x542A0004, // 015B LDINT R10 5 + 0x7C1C0600, // 015C CALL R7 3 + 0x80040E00, // 015D RET 1 R7 + 0x7002000E, // 015E JMP #016E + 0x1C1C090E, // 015F EQ R7 R4 K14 + 0x781E0005, // 0160 JMPF R7 #0167 + 0x8C1C0D04, // 0161 GETMET R7 R6 K4 + 0x88240D0D, // 0162 GETMBR R9 R6 K13 + 0x58280008, // 0163 LDCONST R10 K8 + 0x7C1C0600, // 0164 CALL R7 3 + 0x80040E00, // 0165 RET 1 R7 + 0x70020006, // 0166 JMP #016E + 0x541E0003, // 0167 LDINT R7 4 + 0x1C1C0807, // 0168 EQ R7 R4 R7 + 0x781E0000, // 0169 JMPF R7 #016B + 0x70020002, // 016A JMP #016E + 0x541E0004, // 016B LDINT R7 5 + 0x1C1C0807, // 016C EQ R7 R4 R7 + 0x781DFFFF, // 016D JMPF R7 #016E + 0x700200C9, // 016E JMP #0239 + 0x541E003B, // 016F LDINT R7 60 + 0x1C1C0607, // 0170 EQ R7 R3 R7 + 0x781E0000, // 0171 JMPF R7 #0173 + 0x700200C5, // 0172 JMP #0239 + 0x541E0027, // 0173 LDINT R7 40 + 0x1C1C0607, // 0174 EQ R7 R3 R7 + 0x781E0071, // 0175 JMPF R7 #01E8 + 0x1C1C0903, // 0176 EQ R7 R4 K3 + 0x781E0005, // 0177 JMPF R7 #017E + 0x8C1C0D04, // 0178 GETMET R7 R6 K4 + 0x88240D0B, // 0179 GETMBR R9 R6 K11 + 0x58280003, // 017A LDCONST R10 K3 + 0x7C1C0600, // 017B CALL R7 3 + 0x80040E00, // 017C RET 1 R7 + 0x70020068, // 017D JMP #01E7 + 0x1C1C0908, // 017E EQ R7 R4 K8 + 0x781E0005, // 017F JMPF R7 #0186 + 0x8C1C0D04, // 0180 GETMET R7 R6 K4 + 0x88240D15, // 0181 GETMBR R9 R6 K21 + 0x58280032, // 0182 LDCONST R10 K50 + 0x7C1C0600, // 0183 CALL R7 3 + 0x80040E00, // 0184 RET 1 R7 + 0x70020060, // 0185 JMP #01E7 + 0x1C1C090C, // 0186 EQ R7 R4 K12 + 0x781E0006, // 0187 JMPF R7 #018F + 0x8C1C0D04, // 0188 GETMET R7 R6 K4 + 0x88240D0B, // 0189 GETMBR R9 R6 K11 + 0x88280133, // 018A GETMBR R10 R0 K51 + 0x88281534, // 018B GETMBR R10 R10 K52 + 0x7C1C0600, // 018C CALL R7 3 + 0x80040E00, // 018D RET 1 R7 + 0x70020057, // 018E JMP #01E7 + 0x1C1C090E, // 018F EQ R7 R4 K14 + 0x781E0009, // 0190 JMPF R7 #019B + 0x8C1C0D04, // 0191 GETMET R7 R6 K4 + 0x88240D15, // 0192 GETMBR R9 R6 K21 + 0xB82A2200, // 0193 GETNGBL R10 K17 + 0x8C281525, // 0194 GETMET R10 R10 K37 + 0x58300035, // 0195 LDCONST R12 K53 + 0x7C280400, // 0196 CALL R10 2 + 0x94281535, // 0197 GETIDX R10 R10 K53 + 0x7C1C0600, // 0198 CALL R7 3 + 0x80040E00, // 0199 RET 1 R7 + 0x7002004B, // 019A JMP #01E7 + 0x541E0003, // 019B LDINT R7 4 + 0x1C1C0807, // 019C EQ R7 R4 R7 + 0x781E0005, // 019D JMPF R7 #01A4 + 0x8C1C0D04, // 019E GETMET R7 R6 K4 + 0x88240D0B, // 019F GETMBR R9 R6 K11 + 0x542A7FFF, // 01A0 LDINT R10 32768 + 0x7C1C0600, // 01A1 CALL R7 3 + 0x80040E00, // 01A2 RET 1 R7 + 0x70020042, // 01A3 JMP #01E7 + 0x541E0004, // 01A4 LDINT R7 5 + 0x1C1C0807, // 01A5 EQ R7 R4 R7 + 0x781E0009, // 01A6 JMPF R7 #01B1 + 0x8C1C0D04, // 01A7 GETMET R7 R6 K4 + 0x88240D15, // 01A8 GETMBR R9 R6 K21 + 0xB82A2200, // 01A9 GETNGBL R10 K17 + 0x8C281525, // 01AA GETMET R10 R10 K37 + 0x58300036, // 01AB LDCONST R12 K54 + 0x7C280400, // 01AC CALL R10 2 + 0x94281537, // 01AD GETIDX R10 R10 K55 + 0x7C1C0600, // 01AE CALL R7 3 + 0x80040E00, // 01AF RET 1 R7 + 0x70020035, // 01B0 JMP #01E7 + 0x541E0005, // 01B1 LDINT R7 6 + 0x1C1C0807, // 01B2 EQ R7 R4 R7 + 0x781E0005, // 01B3 JMPF R7 #01BA + 0x8C1C0D04, // 01B4 GETMET R7 R6 K4 + 0x88240D15, // 01B5 GETMBR R9 R6 K21 + 0x58280038, // 01B6 LDCONST R10 K56 + 0x7C1C0600, // 01B7 CALL R7 3 + 0x80040E00, // 01B8 RET 1 R7 + 0x7002002C, // 01B9 JMP #01E7 + 0x541E0006, // 01BA LDINT R7 7 + 0x1C1C0807, // 01BB EQ R7 R4 R7 + 0x781E0005, // 01BC JMPF R7 #01C3 + 0x8C1C0D04, // 01BD GETMET R7 R6 K4 + 0x88240D0B, // 01BE GETMBR R9 R6 K11 + 0x58280003, // 01BF LDCONST R10 K3 + 0x7C1C0600, // 01C0 CALL R7 3 + 0x80040E00, // 01C1 RET 1 R7 + 0x70020023, // 01C2 JMP #01E7 + 0x541E0007, // 01C3 LDINT R7 8 + 0x1C1C0807, // 01C4 EQ R7 R4 R7 + 0x781E000A, // 01C5 JMPF R7 #01D1 + 0x8C1C0D04, // 01C6 GETMET R7 R6 K4 + 0x88240D15, // 01C7 GETMBR R9 R6 K21 + 0xB82A2200, // 01C8 GETNGBL R10 K17 + 0x8C281525, // 01C9 GETMET R10 R10 K37 + 0x58300039, // 01CA LDCONST R12 K57 + 0x7C280400, // 01CB CALL R10 2 + 0x9428153A, // 01CC GETIDX R10 R10 K58 + 0x9428153B, // 01CD GETIDX R10 R10 K59 + 0x7C1C0600, // 01CE CALL R7 3 + 0x80040E00, // 01CF RET 1 R7 + 0x70020015, // 01D0 JMP #01E7 + 0x541E0008, // 01D1 LDINT R7 9 + 0x1C1C0807, // 01D2 EQ R7 R4 R7 + 0x781E0005, // 01D3 JMPF R7 #01DA + 0x8C1C0D04, // 01D4 GETMET R7 R6 K4 + 0x88240D0B, // 01D5 GETMBR R9 R6 K11 + 0x58280003, // 01D6 LDCONST R10 K3 + 0x7C1C0600, // 01D7 CALL R7 3 + 0x80040E00, // 01D8 RET 1 R7 + 0x7002000C, // 01D9 JMP #01E7 + 0x541E0009, // 01DA LDINT R7 10 + 0x1C1C0807, // 01DB EQ R7 R4 R7 + 0x781E0009, // 01DC JMPF R7 #01E7 + 0x8C1C0D04, // 01DD GETMET R7 R6 K4 + 0x88240D15, // 01DE GETMBR R9 R6 K21 + 0xB82A2200, // 01DF GETNGBL R10 K17 + 0x8C281525, // 01E0 GETMET R10 R10 K37 + 0x58300039, // 01E1 LDCONST R12 K57 + 0x7C280400, // 01E2 CALL R10 2 + 0x9428153A, // 01E3 GETIDX R10 R10 K58 + 0x9428153C, // 01E4 GETIDX R10 R10 K60 + 0x7C1C0600, // 01E5 CALL R7 3 + 0x80040E00, // 01E6 RET 1 R7 + 0x70020050, // 01E7 JMP #0239 + 0x541E003E, // 01E8 LDINT R7 63 + 0x1C1C0607, // 01E9 EQ R7 R3 R7 + 0x781E0000, // 01EA JMPF R7 #01EC + 0x7002004C, // 01EB JMP #0239 + 0x541E002A, // 01EC LDINT R7 43 + 0x1C1C0607, // 01ED EQ R7 R3 R7 + 0x781E0016, // 01EE JMPF R7 #0206 + 0x1C1C0903, // 01EF EQ R7 R4 K3 + 0x781E0007, // 01F0 JMPF R7 #01F9 + 0x8C1C0D04, // 01F1 GETMET R7 R6 K4 + 0x88240D15, // 01F2 GETMBR R9 R6 K21 + 0xB82A2200, // 01F3 GETNGBL R10 K17 + 0x8C28153D, // 01F4 GETMET R10 R10 K61 + 0x7C280200, // 01F5 CALL R10 1 + 0x7C1C0600, // 01F6 CALL R7 3 + 0x80040E00, // 01F7 RET 1 R7 + 0x7002000B, // 01F8 JMP #0205 + 0x1C1C0908, // 01F9 EQ R7 R4 K8 + 0x781E0009, // 01FA JMPF R7 #0205 + 0x8C1C0D3E, // 01FB GETMET R7 R6 K62 + 0x7C1C0200, // 01FC CALL R7 1 + 0x8C200F0A, // 01FD GETMET R8 R7 K10 + 0x4C280000, // 01FE LDNIL R10 + 0x882C0D15, // 01FF GETMBR R11 R6 K21 + 0xB8322200, // 0200 GETNGBL R12 K17 + 0x8C30193D, // 0201 GETMET R12 R12 K61 + 0x7C300200, // 0202 CALL R12 1 + 0x7C200800, // 0203 CALL R8 4 + 0x80040E00, // 0204 RET 1 R7 + 0x70020032, // 0205 JMP #0239 + 0x541E002B, // 0206 LDINT R7 44 + 0x1C1C0607, // 0207 EQ R7 R3 R7 + 0x781E001C, // 0208 JMPF R7 #0226 + 0x1C1C0903, // 0209 EQ R7 R4 K3 + 0x781E0005, // 020A JMPF R7 #0211 + 0x8C1C0D04, // 020B GETMET R7 R6 K4 + 0x88240D0D, // 020C GETMBR R9 R6 K13 + 0x58280008, // 020D LDCONST R10 K8 + 0x7C1C0600, // 020E CALL R7 3 + 0x80040E00, // 020F RET 1 R7 + 0x70020013, // 0210 JMP #0225 + 0x1C1C0908, // 0211 EQ R7 R4 K8 + 0x781E0005, // 0212 JMPF R7 #0219 + 0x8C1C0D04, // 0213 GETMET R7 R6 K4 + 0x88240D0D, // 0214 GETMBR R9 R6 K13 + 0x542A0003, // 0215 LDINT R10 4 + 0x7C1C0600, // 0216 CALL R7 3 + 0x80040E00, // 0217 RET 1 R7 + 0x7002000B, // 0218 JMP #0225 + 0x1C1C090C, // 0219 EQ R7 R4 K12 + 0x781E0009, // 021A JMPF R7 #0225 + 0x8C1C0D3E, // 021B GETMET R7 R6 K62 + 0x7C1C0200, // 021C CALL R7 1 + 0x8C200F0A, // 021D GETMET R8 R7 K10 + 0x4C280000, // 021E LDNIL R10 + 0x8C2C0D04, // 021F GETMET R11 R6 K4 + 0x88340D0D, // 0220 GETMBR R13 R6 K13 + 0x543A0003, // 0221 LDINT R14 4 + 0x7C2C0600, // 0222 CALL R11 3 + 0x7C200600, // 0223 CALL R8 3 + 0x80040E00, // 0224 RET 1 R7 + 0x70020012, // 0225 JMP #0239 + 0x541E0030, // 0226 LDINT R7 49 + 0x1C1C0607, // 0227 EQ R7 R3 R7 + 0x781E000F, // 0228 JMPF R7 #0239 + 0x1C1C090E, // 0229 EQ R7 R4 K14 + 0x781E0005, // 022A JMPF R7 #0231 + 0x8C1C0D04, // 022B GETMET R7 R6 K4 + 0x88240D0D, // 022C GETMBR R9 R6 K13 + 0x542A001D, // 022D LDINT R10 30 + 0x7C1C0600, // 022E CALL R7 3 + 0x80040E00, // 022F RET 1 R7 + 0x70020007, // 0230 JMP #0239 + 0x541EFFFB, // 0231 LDINT R7 65532 + 0x1C1C0807, // 0232 EQ R7 R4 R7 + 0x781E0004, // 0233 JMPF R7 #0239 + 0x8C1C0D04, // 0234 GETMET R7 R6 K4 + 0x88240D29, // 0235 GETMBR R9 R6 K41 + 0x58280003, // 0236 LDCONST R10 K3 + 0x7C1C0600, // 0237 CALL R7 3 + 0x80040E00, // 0238 RET 1 R7 + 0x80000000, // 0239 RET 0 }) ) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_TLV.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_TLV.h index f27d81def..3132bd417 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_TLV.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_TLV.h @@ -2198,32 +2198,39 @@ be_local_closure(Matter_TLV_list_add_TLV, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 6]) { /* constants */ - /* K0 */ be_nested_str_weak(TLV), - /* K1 */ be_nested_str_weak(Matter_TLV_item), - /* K2 */ be_nested_str_weak(tag_sub), - /* K3 */ be_nested_str_weak(typ), - /* K4 */ be_nested_str_weak(val), - /* K5 */ be_nested_str_weak(push), + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(TLV), + /* K2 */ be_nested_str_weak(NULL), + /* K3 */ be_nested_str_weak(Matter_TLV_item), + /* K4 */ be_nested_str_weak(tag_sub), + /* K5 */ be_nested_str_weak(typ), + /* K6 */ be_nested_str_weak(val), + /* K7 */ be_nested_str_weak(push), }), be_str_weak(add_TLV), &be_const_str_solidified, - ( &(const binstruction[15]) { /* code */ + ( &(const binstruction[20]) { /* code */ 0x4C100000, // 0000 LDNIL R4 0x20100604, // 0001 NE R4 R3 R4 - 0x7812000A, // 0002 JMPF R4 #000E - 0x88100100, // 0003 GETMBR R4 R0 K0 - 0x8C100901, // 0004 GETMET R4 R4 K1 - 0x5C180000, // 0005 MOVE R6 R0 - 0x7C100400, // 0006 CALL R4 2 - 0x90120401, // 0007 SETMBR R4 K2 R1 - 0x90120602, // 0008 SETMBR R4 K3 R2 - 0x90120803, // 0009 SETMBR R4 K4 R3 - 0x88140104, // 000A GETMBR R5 R0 K4 - 0x8C140B05, // 000B GETMET R5 R5 K5 - 0x5C1C0800, // 000C MOVE R7 R4 - 0x7C140400, // 000D CALL R5 2 - 0x80040000, // 000E RET 1 R0 + 0x74120004, // 0002 JMPT R4 #0008 + 0xB8120000, // 0003 GETNGBL R4 K0 + 0x88100901, // 0004 GETMBR R4 R4 K1 + 0x88100902, // 0005 GETMBR R4 R4 K2 + 0x1C100404, // 0006 EQ R4 R2 R4 + 0x7812000A, // 0007 JMPF R4 #0013 + 0x88100101, // 0008 GETMBR R4 R0 K1 + 0x8C100903, // 0009 GETMET R4 R4 K3 + 0x5C180000, // 000A MOVE R6 R0 + 0x7C100400, // 000B CALL R4 2 + 0x90120801, // 000C SETMBR R4 K4 R1 + 0x90120A02, // 000D SETMBR R4 K5 R2 + 0x90120C03, // 000E SETMBR R4 K6 R3 + 0x88140106, // 000F GETMBR R5 R0 K6 + 0x8C140B07, // 0010 GETMET R5 R5 K7 + 0x5C1C0800, // 0011 MOVE R7 R4 + 0x7C140400, // 0012 CALL R5 2 + 0x80040000, // 0013 RET 1 R0 }) ) ); From 0ebcf1dc03d2bd3c6b6b8646c4ddfbfddb32fcca Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 5 Feb 2023 15:13:44 +0100 Subject: [PATCH 229/262] Fix exception on empty topic (#17879) --- tasmota/tasmota_support/support_command.ino | 43 ++++++++++----------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/tasmota/tasmota_support/support_command.ino b/tasmota/tasmota_support/support_command.ino index 4709fc309..5a98f24a8 100644 --- a/tasmota/tasmota_support/support_command.ino +++ b/tasmota/tasmota_support/support_command.ino @@ -366,8 +366,7 @@ void ExecuteCommand(const char *cmnd, uint32_t source) // topicBuf: cmnd/tasmotas/power1 dataBuf: toggle = Mqtt command using a group topic // topicBuf: cmnd/DVES_83BB10_fb/power1 dataBuf: toggle = Mqtt command using fallback topic -void CommandHandler(char* topicBuf, char* dataBuf, uint32_t data_len) -{ +void CommandHandler(char* topicBuf, char* dataBuf, uint32_t data_len) { SHOW_FREE_MEM(PSTR("CommandHandler")); bool grpflg = false; @@ -408,34 +407,32 @@ void CommandHandler(char* topicBuf, char* dataBuf, uint32_t data_len) user_index = true; } type[i] = '\0'; - } - bool binary_data = (index > 199); // Suppose binary data on topic index > 199 - if (!binary_data) { - bool keep_spaces = ((strstr_P(type, PSTR("SERIALSEND")) != nullptr) && (index > 9)); // Do not skip leading spaces on (s)serialsend10 and up - if (!keep_spaces) { - while (*dataBuf && isspace(*dataBuf)) { - dataBuf++; // Skip leading spaces in data - data_len--; + bool binary_data = (index > 199); // Suppose binary data on topic index > 199 + if (!binary_data) { + bool keep_spaces = ((strstr_P(type, PSTR("SERIALSEND")) != nullptr) && (index > 9)); // Do not skip leading spaces on (s)serialsend10 and up + if (!keep_spaces) { + while (*dataBuf && isspace(*dataBuf)) { + dataBuf++; // Skip leading spaces in data + data_len--; + } } } - } - int32_t payload = -99; - if (!binary_data) { - if (!strcmp(dataBuf,"?")) { data_len = 0; } + int32_t payload = -99; + if (!binary_data) { + if (!strcmp(dataBuf,"?")) { data_len = 0; } - char *p; - payload = strtol(dataBuf, &p, 0); // decimal, octal (0) or hex (0x) - if (p == dataBuf) { payload = -99; } - int temp_payload = GetStateNumber(dataBuf); - if (temp_payload > -1) { payload = temp_payload; } - } + char *p; + payload = strtol(dataBuf, &p, 0); // decimal, octal (0) or hex (0x) + if (p == dataBuf) { payload = -99; } + int temp_payload = GetStateNumber(dataBuf); + if (temp_payload > -1) { payload = temp_payload; } + } - AddLog(LOG_LEVEL_DEBUG, PSTR("CMD: Grp %d, Cmd '%s', Idx %d, Len %d, Pld %d, Data '%s'"), - grpflg, type, index, data_len, payload, (binary_data) ? HexToString((uint8_t*)dataBuf, data_len).c_str() : dataBuf); + AddLog(LOG_LEVEL_DEBUG, PSTR("CMD: Grp %d, Cmd '%s', Idx %d, Len %d, Pld %d, Data '%s'"), + grpflg, type, index, data_len, payload, (binary_data) ? HexToString((uint8_t*)dataBuf, data_len).c_str() : dataBuf); - if (type != nullptr) { Response_P(PSTR("{\"" D_JSON_COMMAND "\":\"" D_JSON_ERROR "\"}")); if (Settings->ledstate &0x02) { TasmotaGlobal.blinks++; } From c699131103cbf380d9a27f00e577a6c18fab9fae Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 5 Feb 2023 16:22:18 +0100 Subject: [PATCH 230/262] Add Shelly Pro 4PM to lvgl binary --- .../include/tasmota_configurations_ESP32.h | 5 +++- .../tasmota_xdrv_driver/xdrv_03_energy.ino | 9 ++------ .../xdrv_03_esp32_energy.ino | 9 ++------ ...24_biopdu.ino => xnrg_24_esp32_biopdu.ino} | 23 ++++++++----------- 4 files changed, 17 insertions(+), 29 deletions(-) rename tasmota/tasmota_xnrg_energy/{xnrg_24_biopdu.ino => xnrg_24_esp32_biopdu.ino} (91%) diff --git a/tasmota/include/tasmota_configurations_ESP32.h b/tasmota/include/tasmota_configurations_ESP32.h index 495d41652..69de06a24 100644 --- a/tasmota/include/tasmota_configurations_ESP32.h +++ b/tasmota/include/tasmota_configurations_ESP32.h @@ -346,7 +346,10 @@ #define USE_DS18x20 // Add support for DS18x20 sensors with id sort, single scan and read retry (+1k3 code) -#undef USE_ENERGY_SENSOR + +#define USE_ENERGY_SENSOR // Add energy to support Shelly Pro 4PM display (+38k code) +#define USE_ADE7953 +#define USE_SHELLY_PRO #define USE_I2C // I2C using library wire (+10k code, 0k2 mem, 124 iram) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino b/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino index bdba44bfa..67d891fe7 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino @@ -19,15 +19,9 @@ #ifdef ESP8266 #ifdef USE_ENERGY_SENSOR -#define USE_ENERGY_SENSOR_LEGACY -#endif // USE_ENERGY_SENSOR -#endif // ESP8266 - -#ifdef USE_ENERGY_SENSOR_LEGACY /*********************************************************************************************\ * Energy for ESP8266 and legacy ESP32 with max three phases/channels using Settings from flash \*********************************************************************************************/ -//#warning **** USE_ENERGY_SENSOR_LEGACY **** #define XDRV_03 3 #define XSNS_03 3 @@ -1518,4 +1512,5 @@ bool Xsns03(uint32_t function) return result; } -#endif // USE_ENERGY_SENSOR_V1 +#endif // USE_ENERGY_SENSOR +#endif // ESP8266 diff --git a/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino b/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino index cb5007ffc..85b146bb7 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino @@ -19,15 +19,9 @@ #ifdef ESP32 #ifdef USE_ENERGY_SENSOR -#define USE_ENERGY_SENSOR_ESP32 -#endif // USE_ENERGY_SENSOR -#endif // ESP32 - -#ifdef USE_ENERGY_SENSOR_ESP32 /*********************************************************************************************\ * Energy for ESP32 with max eight phases/channels using more RAM and Settings from filesystem \*********************************************************************************************/ -//#warning **** USE_ENERGY_SENSOR_ESP32 **** #define XDRV_03 3 #define XSNS_03 3 @@ -1798,4 +1792,5 @@ bool Xsns03(uint32_t function) return result; } -#endif // USE_ENERGY_SENSOR_ESP32 +#endif // USE_ENERGY_SENSOR +#endif // ESP32 diff --git a/tasmota/tasmota_xnrg_energy/xnrg_24_biopdu.ino b/tasmota/tasmota_xnrg_energy/xnrg_24_esp32_biopdu.ino similarity index 91% rename from tasmota/tasmota_xnrg_energy/xnrg_24_biopdu.ino rename to tasmota/tasmota_xnrg_energy/xnrg_24_esp32_biopdu.ino index 680c2fbad..8af5ecb85 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_24_biopdu.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_24_esp32_biopdu.ino @@ -17,7 +17,8 @@ along with this program. If not, see . */ -#if defined(USE_ENERGY_SENSOR_ESP32) && defined(USE_I2C) +#ifdef ESP32 +#if defined(USE_ENERGY_SENSOR) && defined(USE_I2C) #ifdef USE_BIOPDU /*********************************************************************************************\ Biomine 625x12 Custom Board @@ -26,11 +27,11 @@ 3bit serial switch Integrated MCP23008 - Template {"NAME":"Olimex ESP32-PoE-BioPDU","GPIO":[1,10209,10210,1,10144,1,0,0,5536,640,1,1,608,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,1,10208,1,1,10176,0,0,1],"FLAG":0,"BASE":1} + Template {"NAME":"Olimex ESP32-PoE-BioPDU","GPIO":[1,10209,10210,1,10144,1,0,0,5536,640,1,1,608,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,1,10208,1,1,10176,0,0,1],"FLAG":0,"BASE":1} BioPDU 625x12 Factory Settings: - Template {"NAME":"Olimex ESP32-PoE-BioPDU","GPIO":[1,10209,10210,1,10144,1,0,0,5536,640,1,1,608,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,1,10208,1,1,10176,0,0,1],"FLAG":0,"BASE":1} + Template {"NAME":"Olimex ESP32-PoE-BioPDU","GPIO":[1,10209,10210,1,10144,1,0,0,5536,640,1,1,608,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,1,10208,1,1,10176,0,0,1],"FLAG":0,"BASE":1} Module 0 EthType 0 EthAddress 0 @@ -65,14 +66,7 @@ #define XNRG_24 24 -#undef ENERGY_MAX_PHASES -#define ENERGY_MAX_PHASES 6 // BioPDU support max six phases/channels - -#undef ENERGY_GUI_MAX_COLS -#define ENERGY_GUI_MAX_COLS 6 // [EnergyCols] Number of GUI data columns - Preffered 6 - -#undef ENERGY_GUI_DISPLAY_MODE -#define ENERGY_GUI_DISPLAY_MODE ENERGY_DISPLAY_TABS // [EnergyDisplay] 1 = Rotate if over EnergyCols, 2 = Rotate only powered on if over EnergyCols, 3 = Use tabs if over EnergyCols +#define BIOPDU_MAX_PHASES 6 // BioPDU support max six phases/channels const uint8_t BIOPDU_DEVICE_ADDRESS = 0x01; // PZEM default address const uint32_t BIOPDU_STABILIZE = 30; // Number of seconds to stabilize configuration @@ -241,7 +235,7 @@ void BioPduDrvInit(void) } } - Energy->phase_count = std::min((uint8_t)(pow(2, BioPdu.pins) - 1), (uint8_t)ENERGY_MAX_PHASES); // Start off with 6 phases + Energy->phase_count = std::min((uint8_t)(pow(2, BioPdu.pins) - 1), (uint8_t)BIOPDU_MAX_PHASES); // Start off with 6 phases AddLog(LOG_LEVEL_DEBUG, PSTR("PDU: number of pins=%d, max_phase=%d"), BioPdu.pins, Energy->phase_count); } @@ -297,5 +291,6 @@ bool Xnrg24(uint32_t function) return result; } -#endif // USE_BIOPDU -#endif // USE_ENERGY_SENSOR +#endif // USE_BIOPDU +#endif // USE_ENERGY_SENSOR +#endif // ESP32 From 9517677fb29b6d9524de6516ebb9a61faffe4f3b Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 5 Feb 2023 16:54:25 +0100 Subject: [PATCH 231/262] Fix initial displaydimmer state --- tasmota/tasmota_xdrv_driver/xdrv_13_display.ino | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_13_display.ino b/tasmota/tasmota_xdrv_driver/xdrv_13_display.ino index 5c4ce996e..bbd9802aa 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_13_display.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_13_display.ino @@ -237,6 +237,7 @@ uint16_t dsp_rad; uint16_t dsp_color; int16_t dsp_len; +bool disp_apply_display_dimmer_request = false; int8_t disp_power = -1; uint8_t disp_device = 0; uint8_t disp_refresh = 1; @@ -1840,15 +1841,12 @@ void DisplayLocalSensor(void) \*********************************************************************************************/ void DisplayInitDriver(void) { - - - XdspCall(FUNC_DISPLAY_INIT_DRIVER); // AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "Display model %d"), Settings->display_model); if (Settings->display_model) { -// ApplyDisplayDimmer(); // Not allowed here. Way too early in initi sequence. IE power state has not even been set at this point in time +// ApplyDisplayDimmer(); // Not allowed here. Way too early in init sequence. Global power state has not been set at this point in time #ifdef USE_MULTI_DISPLAY Set_display(0); @@ -1999,7 +1997,9 @@ void CmndDisplayMode(void) { // Apply the current display dimmer void ApplyDisplayDimmer(void) { + disp_apply_display_dimmer_request = true; if ((disp_power < 0) || !disp_device) { return; } // Not initialized yet + disp_apply_display_dimmer_request = false; uint8_t dimmer8 = changeUIntScale(GetDisplayDimmer(), 0, 100, 0, 255); uint16_t dimmer10_gamma = ledGamma10(dimmer8); @@ -2896,6 +2896,11 @@ bool Xdrv13(uint32_t function) case FUNC_PRE_INIT: DisplayInitDriver(); break; + case FUNC_INIT: + if (disp_apply_display_dimmer_request) { + ApplyDisplayDimmer(); // Allowed here. + } + break; case FUNC_EVERY_50_MSECOND: if (Settings->display_model) { XdspCall(FUNC_DISPLAY_EVERY_50_MSECOND); } break; From da81d25fb5cd5a74e1cefaee31d339171f2b3aa5 Mon Sep 17 00:00:00 2001 From: Philipp Date: Sun, 5 Feb 2023 19:17:35 +0100 Subject: [PATCH 232/262] Use dark mode for Pro 4PM display (#17888) Use dark mode by default for the Shelly Pro 4PM display --- tasmota/displaydesc/ST7735S_Pro4PM_display.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tasmota/displaydesc/ST7735S_Pro4PM_display.ini b/tasmota/displaydesc/ST7735S_Pro4PM_display.ini index 46cb6a804..09579367c 100644 --- a/tasmota/displaydesc/ST7735S_Pro4PM_display.ini +++ b/tasmota/displaydesc/ST7735S_Pro4PM_display.ini @@ -30,6 +30,6 @@ E1,10,03,1D,07,06,2E,2C,29,2D,2E,2E,37,3F,00,00,02,10 :1,CC,1A,01,01 :2,A8,01,1A,02 :3,08,1A,01,03 -:i,21,20 +:i,20,21 :B,60,1 -# \ No newline at end of file +# From d23e598d6b47596f30a8a7c38d54f14a7256b812 Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Sun, 5 Feb 2023 23:05:51 +0100 Subject: [PATCH 233/262] Matter support Privacy decryption (#17891) --- .../src/embedded/Matter_Message.be | 15 +- .../src/embedded/Matter_Session.be | 11 + .../src/solidify/solidified_Matter_Message.h | 348 +-- .../src/solidify/solidified_Matter_Session.h | 1861 +++++++++-------- 4 files changed, 1183 insertions(+), 1052 deletions(-) diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Message.be b/lib/libesp32/berry_matter/src/embedded/Matter_Message.be index 3eadf0c55..c9473d68d 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Message.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Message.be @@ -301,9 +301,22 @@ class Matter_Frame import crypto var session = self.session var raw = self.raw + var mic = raw[-16..] # take last 16 bytes as signature + # decrypt the message with `i2r` key var i2r = session.get_i2r() - var mic = raw[-16..] # take last 16 bytes as signature + + # check privacy flag, p.127 + if self.sec_p + # compute privacy key, p.71 + var k = session.get_i2r_privacy() + var n = bytes().add(self.local_session_id, -2) + mic[5..15] # session in Big Endian + var m = self.raw[4 .. self.payload_idx-1] + var m_clear = crypto.AES_CTR(k).decrypt(m, n, 2) + # replace in-place + self.raw = self.raw[0..3] + m_clear + m[self.self.payload_idx .. ] + end + # use AES_CCM var a = raw[0 .. self.payload_idx - 1] var p = raw[self.payload_idx .. -17] diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Session.be b/lib/libesp32/berry_matter/src/embedded/Matter_Session.be index 8c1f56235..028f8a28d 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Session.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Session.be @@ -53,6 +53,7 @@ class Matter_Session # encryption keys and challenges var i2rkey # key initiator to receiver (incoming) var r2ikey # key receiver to initiator (outgoing) + var _i2r_privacy # cache for the i2r privacy key var attestation_challenge # Attestation challenge var peer_node_id # breadcrumb @@ -108,6 +109,7 @@ class Matter_Session self.counter_rcv.reset() self.counter_snd.reset() self.i2rkey = nil + self._i2r_privacy = nil self.r2ikey = nil self.attestation_challenge = nil # clear any attribute starting with `_` @@ -129,6 +131,7 @@ class Matter_Session end def set_keys(i2r, r2i, ac, st) self.i2rkey = i2r + self._i2r_privacy = nil # clear cache self.r2ikey = r2i self.attestation_challenge = ac self.session_timestamp = st @@ -160,6 +163,14 @@ class Matter_Session def get_i2r() return self.i2rkey end + def get_i2r_privacy() # get and cache privacy key + if self._i2r_privacy == nil + import crypto + # compute privacy key according to p.127 + self._i2r_privacy = crypto.HKDF_SHA256().derive(self.get_i2r(), bytes(), bytes().fromstring("PrivacyKey"), 16) + end + return self._i2r_privacy + end def get_r2i() return self.r2ikey end diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Message.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Message.h index 044e02159..4ea63aebd 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Message.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Message.h @@ -19,166 +19,212 @@ be_local_closure(Matter_Frame_decrypt, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[30]) { /* constants */ + ( &(const bvalue[36]) { /* constants */ /* K0 */ be_nested_str_weak(crypto), /* K1 */ be_nested_str_weak(session), /* K2 */ be_nested_str_weak(raw), - /* K3 */ be_nested_str_weak(get_i2r), - /* K4 */ be_const_int(2147483647), - /* K5 */ be_const_int(0), - /* K6 */ be_nested_str_weak(payload_idx), - /* K7 */ be_const_int(1), - /* K8 */ be_nested_str_weak(add), - /* K9 */ be_nested_str_weak(flags), - /* K10 */ be_nested_str_weak(message_counter), - /* K11 */ be_nested_str_weak(source_node_id), - /* K12 */ be_nested_str_weak(peer_node_id), - /* K13 */ be_nested_str_weak(resize), - /* K14 */ be_nested_str_weak(tasmota), - /* K15 */ be_nested_str_weak(log), - /* K16 */ be_nested_str_weak(MTR_X3A_X20_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A), - /* K17 */ be_const_int(3), - /* K18 */ be_nested_str_weak(MTR_X3A_X20i2r_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), - /* K19 */ be_nested_str_weak(tohex), - /* K20 */ be_nested_str_weak(MTR_X3A_X20p_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), - /* K21 */ be_nested_str_weak(MTR_X3A_X20a_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), - /* K22 */ be_nested_str_weak(MTR_X3A_X20n_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), - /* K23 */ be_nested_str_weak(MTR_X3A_X20mic_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), - /* K24 */ be_nested_str_weak(AES_CCM), - /* K25 */ be_nested_str_weak(decrypt), - /* K26 */ be_nested_str_weak(tag), - /* K27 */ be_nested_str_weak(MTR_X3A_X20cleartext_X20_X20_X20_X3D), - /* K28 */ be_nested_str_weak(MTR_X3A_X20tag_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), - /* K29 */ be_nested_str_weak(MTR_X3A_X20rejected_X20packet_X20due_X20to_X20invalid_X20MIC), + /* K3 */ be_const_int(2147483647), + /* K4 */ be_nested_str_weak(get_i2r), + /* K5 */ be_nested_str_weak(sec_p), + /* K6 */ be_nested_str_weak(get_i2r_privacy), + /* K7 */ be_nested_str_weak(add), + /* K8 */ be_nested_str_weak(local_session_id), + /* K9 */ be_nested_str_weak(payload_idx), + /* K10 */ be_const_int(1), + /* K11 */ be_nested_str_weak(AES_CTR), + /* K12 */ be_nested_str_weak(decrypt), + /* K13 */ be_const_int(2), + /* K14 */ be_const_int(0), + /* K15 */ be_const_int(3), + /* K16 */ be_nested_str_weak(self), + /* K17 */ be_nested_str_weak(flags), + /* K18 */ be_nested_str_weak(message_counter), + /* K19 */ be_nested_str_weak(source_node_id), + /* K20 */ be_nested_str_weak(peer_node_id), + /* K21 */ be_nested_str_weak(resize), + /* K22 */ be_nested_str_weak(tasmota), + /* K23 */ be_nested_str_weak(log), + /* K24 */ be_nested_str_weak(MTR_X3A_X20_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A), + /* K25 */ be_nested_str_weak(MTR_X3A_X20i2r_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), + /* K26 */ be_nested_str_weak(tohex), + /* K27 */ be_nested_str_weak(MTR_X3A_X20p_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), + /* K28 */ be_nested_str_weak(MTR_X3A_X20a_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), + /* K29 */ be_nested_str_weak(MTR_X3A_X20n_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), + /* K30 */ be_nested_str_weak(MTR_X3A_X20mic_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), + /* K31 */ be_nested_str_weak(AES_CCM), + /* K32 */ be_nested_str_weak(tag), + /* K33 */ be_nested_str_weak(MTR_X3A_X20cleartext_X20_X20_X20_X3D), + /* K34 */ be_nested_str_weak(MTR_X3A_X20tag_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), + /* K35 */ be_nested_str_weak(MTR_X3A_X20rejected_X20packet_X20due_X20to_X20invalid_X20MIC), }), be_str_weak(decrypt), &be_const_str_solidified, - ( &(const binstruction[125]) { /* code */ + ( &(const binstruction[165]) { /* code */ 0xA4060000, // 0000 IMPORT R1 K0 0x88080101, // 0001 GETMBR R2 R0 K1 0x880C0102, // 0002 GETMBR R3 R0 K2 - 0x8C100503, // 0003 GETMET R4 R2 K3 - 0x7C100200, // 0004 CALL R4 1 - 0x5415FFEF, // 0005 LDINT R5 -16 - 0x40140B04, // 0006 CONNECT R5 R5 K4 - 0x94140605, // 0007 GETIDX R5 R3 R5 - 0x88180106, // 0008 GETMBR R6 R0 K6 - 0x04180D07, // 0009 SUB R6 R6 K7 - 0x401A0A06, // 000A CONNECT R6 K5 R6 - 0x94180606, // 000B GETIDX R6 R3 R6 - 0x881C0106, // 000C GETMBR R7 R0 K6 - 0x5421FFEE, // 000D LDINT R8 -17 - 0x401C0E08, // 000E CONNECT R7 R7 R8 - 0x941C0607, // 000F GETIDX R7 R3 R7 - 0x60200015, // 0010 GETGBL R8 G21 - 0x7C200000, // 0011 CALL R8 0 - 0x8C241108, // 0012 GETMET R9 R8 K8 - 0x882C0109, // 0013 GETMBR R11 R0 K9 - 0x58300007, // 0014 LDCONST R12 K7 - 0x7C240600, // 0015 CALL R9 3 - 0x8C241108, // 0016 GETMET R9 R8 K8 - 0x882C010A, // 0017 GETMBR R11 R0 K10 - 0x54320003, // 0018 LDINT R12 4 - 0x7C240600, // 0019 CALL R9 3 - 0x8824010B, // 001A GETMBR R9 R0 K11 - 0x78260001, // 001B JMPF R9 #001E - 0x40241104, // 001C CONNECT R9 R8 K4 - 0x70020006, // 001D JMP #0025 - 0x8824050C, // 001E GETMBR R9 R2 K12 - 0x78260001, // 001F JMPF R9 #0022 - 0x8824050C, // 0020 GETMBR R9 R2 K12 - 0x40241009, // 0021 CONNECT R9 R8 R9 - 0x8C24110D, // 0022 GETMET R9 R8 K13 - 0x542E000C, // 0023 LDINT R11 13 - 0x7C240400, // 0024 CALL R9 2 - 0xB8261C00, // 0025 GETNGBL R9 K14 - 0x8C24130F, // 0026 GETMET R9 R9 K15 - 0x582C0010, // 0027 LDCONST R11 K16 - 0x58300011, // 0028 LDCONST R12 K17 - 0x7C240600, // 0029 CALL R9 3 - 0xB8261C00, // 002A GETNGBL R9 K14 - 0x8C24130F, // 002B GETMET R9 R9 K15 - 0x8C2C0913, // 002C GETMET R11 R4 K19 - 0x7C2C0200, // 002D CALL R11 1 - 0x002E240B, // 002E ADD R11 K18 R11 - 0x58300011, // 002F LDCONST R12 K17 - 0x7C240600, // 0030 CALL R9 3 - 0xB8261C00, // 0031 GETNGBL R9 K14 - 0x8C24130F, // 0032 GETMET R9 R9 K15 - 0x8C2C0F13, // 0033 GETMET R11 R7 K19 - 0x7C2C0200, // 0034 CALL R11 1 - 0x002E280B, // 0035 ADD R11 K20 R11 - 0x58300011, // 0036 LDCONST R12 K17 - 0x7C240600, // 0037 CALL R9 3 - 0xB8261C00, // 0038 GETNGBL R9 K14 - 0x8C24130F, // 0039 GETMET R9 R9 K15 - 0x8C2C0D13, // 003A GETMET R11 R6 K19 - 0x7C2C0200, // 003B CALL R11 1 - 0x002E2A0B, // 003C ADD R11 K21 R11 - 0x58300011, // 003D LDCONST R12 K17 - 0x7C240600, // 003E CALL R9 3 - 0xB8261C00, // 003F GETNGBL R9 K14 - 0x8C24130F, // 0040 GETMET R9 R9 K15 - 0x8C2C1113, // 0041 GETMET R11 R8 K19 - 0x7C2C0200, // 0042 CALL R11 1 - 0x002E2C0B, // 0043 ADD R11 K22 R11 - 0x58300011, // 0044 LDCONST R12 K17 - 0x7C240600, // 0045 CALL R9 3 - 0xB8261C00, // 0046 GETNGBL R9 K14 - 0x8C24130F, // 0047 GETMET R9 R9 K15 - 0x8C2C0B13, // 0048 GETMET R11 R5 K19 - 0x7C2C0200, // 0049 CALL R11 1 - 0x002E2E0B, // 004A ADD R11 K23 R11 - 0x58300011, // 004B LDCONST R12 K17 - 0x7C240600, // 004C CALL R9 3 - 0x8C240318, // 004D GETMET R9 R1 K24 - 0x5C2C0800, // 004E MOVE R11 R4 - 0x5C301000, // 004F MOVE R12 R8 - 0x5C340C00, // 0050 MOVE R13 R6 - 0x6038000C, // 0051 GETGBL R14 G12 - 0x5C3C0E00, // 0052 MOVE R15 R7 - 0x7C380200, // 0053 CALL R14 1 - 0x543E000F, // 0054 LDINT R15 16 - 0x7C240C00, // 0055 CALL R9 6 - 0x8C281319, // 0056 GETMET R10 R9 K25 - 0x5C300E00, // 0057 MOVE R12 R7 - 0x7C280400, // 0058 CALL R10 2 - 0x8C2C131A, // 0059 GETMET R11 R9 K26 - 0x7C2C0200, // 005A CALL R11 1 - 0xB8321C00, // 005B GETNGBL R12 K14 - 0x8C30190F, // 005C GETMET R12 R12 K15 - 0x58380010, // 005D LDCONST R14 K16 - 0x583C0011, // 005E LDCONST R15 K17 - 0x7C300600, // 005F CALL R12 3 - 0xB8321C00, // 0060 GETNGBL R12 K14 - 0x8C30190F, // 0061 GETMET R12 R12 K15 - 0x8C381513, // 0062 GETMET R14 R10 K19 - 0x7C380200, // 0063 CALL R14 1 - 0x003A360E, // 0064 ADD R14 K27 R14 - 0x583C0011, // 0065 LDCONST R15 K17 - 0x7C300600, // 0066 CALL R12 3 - 0xB8321C00, // 0067 GETNGBL R12 K14 - 0x8C30190F, // 0068 GETMET R12 R12 K15 - 0x8C381713, // 0069 GETMET R14 R11 K19 - 0x7C380200, // 006A CALL R14 1 - 0x003A380E, // 006B ADD R14 K28 R14 - 0x583C0011, // 006C LDCONST R15 K17 - 0x7C300600, // 006D CALL R12 3 - 0xB8321C00, // 006E GETNGBL R12 K14 - 0x8C30190F, // 006F GETMET R12 R12 K15 - 0x58380010, // 0070 LDCONST R14 K16 - 0x583C0011, // 0071 LDCONST R15 K17 - 0x7C300600, // 0072 CALL R12 3 - 0x20301605, // 0073 NE R12 R11 R5 - 0x78320006, // 0074 JMPF R12 #007C - 0xB8321C00, // 0075 GETNGBL R12 K14 - 0x8C30190F, // 0076 GETMET R12 R12 K15 - 0x5838001D, // 0077 LDCONST R14 K29 - 0x583C0011, // 0078 LDCONST R15 K17 - 0x7C300600, // 0079 CALL R12 3 - 0x4C300000, // 007A LDNIL R12 - 0x80041800, // 007B RET 1 R12 - 0x80041400, // 007C RET 1 R10 + 0x5411FFEF, // 0003 LDINT R4 -16 + 0x40100903, // 0004 CONNECT R4 R4 K3 + 0x94100604, // 0005 GETIDX R4 R3 R4 + 0x8C140504, // 0006 GETMET R5 R2 K4 + 0x7C140200, // 0007 CALL R5 1 + 0x88180105, // 0008 GETMBR R6 R0 K5 + 0x781A0025, // 0009 JMPF R6 #0030 + 0x8C180506, // 000A GETMET R6 R2 K6 + 0x7C180200, // 000B CALL R6 1 + 0x601C0015, // 000C GETGBL R7 G21 + 0x7C1C0000, // 000D CALL R7 0 + 0x8C1C0F07, // 000E GETMET R7 R7 K7 + 0x88240108, // 000F GETMBR R9 R0 K8 + 0x5429FFFD, // 0010 LDINT R10 -2 + 0x7C1C0600, // 0011 CALL R7 3 + 0x54220004, // 0012 LDINT R8 5 + 0x5426000E, // 0013 LDINT R9 15 + 0x40201009, // 0014 CONNECT R8 R8 R9 + 0x94200808, // 0015 GETIDX R8 R4 R8 + 0x001C0E08, // 0016 ADD R7 R7 R8 + 0x54220003, // 0017 LDINT R8 4 + 0x88240109, // 0018 GETMBR R9 R0 K9 + 0x0424130A, // 0019 SUB R9 R9 K10 + 0x40201009, // 001A CONNECT R8 R8 R9 + 0x88240102, // 001B GETMBR R9 R0 K2 + 0x94201208, // 001C GETIDX R8 R9 R8 + 0x8C28030B, // 001D GETMET R10 R1 K11 + 0x5C300C00, // 001E MOVE R12 R6 + 0x7C280400, // 001F CALL R10 2 + 0x8C28150C, // 0020 GETMET R10 R10 K12 + 0x5C301000, // 0021 MOVE R12 R8 + 0x5C340E00, // 0022 MOVE R13 R7 + 0x5838000D, // 0023 LDCONST R14 K13 + 0x7C280800, // 0024 CALL R10 4 + 0x5C241400, // 0025 MOVE R9 R10 + 0x402A1D0F, // 0026 CONNECT R10 K14 K15 + 0x882C0102, // 0027 GETMBR R11 R0 K2 + 0x9428160A, // 0028 GETIDX R10 R11 R10 + 0x00281409, // 0029 ADD R10 R10 R9 + 0x882C0110, // 002A GETMBR R11 R0 K16 + 0x882C1709, // 002B GETMBR R11 R11 K9 + 0x402C1703, // 002C CONNECT R11 R11 K3 + 0x942C100B, // 002D GETIDX R11 R8 R11 + 0x0028140B, // 002E ADD R10 R10 R11 + 0x9002040A, // 002F SETMBR R0 K2 R10 + 0x88180109, // 0030 GETMBR R6 R0 K9 + 0x04180D0A, // 0031 SUB R6 R6 K10 + 0x401A1C06, // 0032 CONNECT R6 K14 R6 + 0x94180606, // 0033 GETIDX R6 R3 R6 + 0x881C0109, // 0034 GETMBR R7 R0 K9 + 0x5421FFEE, // 0035 LDINT R8 -17 + 0x401C0E08, // 0036 CONNECT R7 R7 R8 + 0x941C0607, // 0037 GETIDX R7 R3 R7 + 0x60200015, // 0038 GETGBL R8 G21 + 0x7C200000, // 0039 CALL R8 0 + 0x8C241107, // 003A GETMET R9 R8 K7 + 0x882C0111, // 003B GETMBR R11 R0 K17 + 0x5830000A, // 003C LDCONST R12 K10 + 0x7C240600, // 003D CALL R9 3 + 0x8C241107, // 003E GETMET R9 R8 K7 + 0x882C0112, // 003F GETMBR R11 R0 K18 + 0x54320003, // 0040 LDINT R12 4 + 0x7C240600, // 0041 CALL R9 3 + 0x88240113, // 0042 GETMBR R9 R0 K19 + 0x78260001, // 0043 JMPF R9 #0046 + 0x40241103, // 0044 CONNECT R9 R8 K3 + 0x70020006, // 0045 JMP #004D + 0x88240514, // 0046 GETMBR R9 R2 K20 + 0x78260001, // 0047 JMPF R9 #004A + 0x88240514, // 0048 GETMBR R9 R2 K20 + 0x40241009, // 0049 CONNECT R9 R8 R9 + 0x8C241115, // 004A GETMET R9 R8 K21 + 0x542E000C, // 004B LDINT R11 13 + 0x7C240400, // 004C CALL R9 2 + 0xB8262C00, // 004D GETNGBL R9 K22 + 0x8C241317, // 004E GETMET R9 R9 K23 + 0x582C0018, // 004F LDCONST R11 K24 + 0x5830000F, // 0050 LDCONST R12 K15 + 0x7C240600, // 0051 CALL R9 3 + 0xB8262C00, // 0052 GETNGBL R9 K22 + 0x8C241317, // 0053 GETMET R9 R9 K23 + 0x8C2C0B1A, // 0054 GETMET R11 R5 K26 + 0x7C2C0200, // 0055 CALL R11 1 + 0x002E320B, // 0056 ADD R11 K25 R11 + 0x5830000F, // 0057 LDCONST R12 K15 + 0x7C240600, // 0058 CALL R9 3 + 0xB8262C00, // 0059 GETNGBL R9 K22 + 0x8C241317, // 005A GETMET R9 R9 K23 + 0x8C2C0F1A, // 005B GETMET R11 R7 K26 + 0x7C2C0200, // 005C CALL R11 1 + 0x002E360B, // 005D ADD R11 K27 R11 + 0x5830000F, // 005E LDCONST R12 K15 + 0x7C240600, // 005F CALL R9 3 + 0xB8262C00, // 0060 GETNGBL R9 K22 + 0x8C241317, // 0061 GETMET R9 R9 K23 + 0x8C2C0D1A, // 0062 GETMET R11 R6 K26 + 0x7C2C0200, // 0063 CALL R11 1 + 0x002E380B, // 0064 ADD R11 K28 R11 + 0x5830000F, // 0065 LDCONST R12 K15 + 0x7C240600, // 0066 CALL R9 3 + 0xB8262C00, // 0067 GETNGBL R9 K22 + 0x8C241317, // 0068 GETMET R9 R9 K23 + 0x8C2C111A, // 0069 GETMET R11 R8 K26 + 0x7C2C0200, // 006A CALL R11 1 + 0x002E3A0B, // 006B ADD R11 K29 R11 + 0x5830000F, // 006C LDCONST R12 K15 + 0x7C240600, // 006D CALL R9 3 + 0xB8262C00, // 006E GETNGBL R9 K22 + 0x8C241317, // 006F GETMET R9 R9 K23 + 0x8C2C091A, // 0070 GETMET R11 R4 K26 + 0x7C2C0200, // 0071 CALL R11 1 + 0x002E3C0B, // 0072 ADD R11 K30 R11 + 0x5830000F, // 0073 LDCONST R12 K15 + 0x7C240600, // 0074 CALL R9 3 + 0x8C24031F, // 0075 GETMET R9 R1 K31 + 0x5C2C0A00, // 0076 MOVE R11 R5 + 0x5C301000, // 0077 MOVE R12 R8 + 0x5C340C00, // 0078 MOVE R13 R6 + 0x6038000C, // 0079 GETGBL R14 G12 + 0x5C3C0E00, // 007A MOVE R15 R7 + 0x7C380200, // 007B CALL R14 1 + 0x543E000F, // 007C LDINT R15 16 + 0x7C240C00, // 007D CALL R9 6 + 0x8C28130C, // 007E GETMET R10 R9 K12 + 0x5C300E00, // 007F MOVE R12 R7 + 0x7C280400, // 0080 CALL R10 2 + 0x8C2C1320, // 0081 GETMET R11 R9 K32 + 0x7C2C0200, // 0082 CALL R11 1 + 0xB8322C00, // 0083 GETNGBL R12 K22 + 0x8C301917, // 0084 GETMET R12 R12 K23 + 0x58380018, // 0085 LDCONST R14 K24 + 0x583C000F, // 0086 LDCONST R15 K15 + 0x7C300600, // 0087 CALL R12 3 + 0xB8322C00, // 0088 GETNGBL R12 K22 + 0x8C301917, // 0089 GETMET R12 R12 K23 + 0x8C38151A, // 008A GETMET R14 R10 K26 + 0x7C380200, // 008B CALL R14 1 + 0x003A420E, // 008C ADD R14 K33 R14 + 0x583C000F, // 008D LDCONST R15 K15 + 0x7C300600, // 008E CALL R12 3 + 0xB8322C00, // 008F GETNGBL R12 K22 + 0x8C301917, // 0090 GETMET R12 R12 K23 + 0x8C38171A, // 0091 GETMET R14 R11 K26 + 0x7C380200, // 0092 CALL R14 1 + 0x003A440E, // 0093 ADD R14 K34 R14 + 0x583C000F, // 0094 LDCONST R15 K15 + 0x7C300600, // 0095 CALL R12 3 + 0xB8322C00, // 0096 GETNGBL R12 K22 + 0x8C301917, // 0097 GETMET R12 R12 K23 + 0x58380018, // 0098 LDCONST R14 K24 + 0x583C000F, // 0099 LDCONST R15 K15 + 0x7C300600, // 009A CALL R12 3 + 0x20301604, // 009B NE R12 R11 R4 + 0x78320006, // 009C JMPF R12 #00A4 + 0xB8322C00, // 009D GETNGBL R12 K22 + 0x8C301917, // 009E GETMET R12 R12 K23 + 0x58380023, // 009F LDCONST R14 K35 + 0x583C000F, // 00A0 LDCONST R15 K15 + 0x7C300600, // 00A1 CALL R12 3 + 0x4C300000, // 00A2 LDNIL R12 + 0x80041800, // 00A3 RET 1 R12 + 0x80041400, // 00A4 RET 1 R10 }) ) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Session.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Session.h index 30d718e06..3857f1e4d 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Session.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Session.h @@ -7,45 +7,9 @@ extern const bclass be_class_Matter_Session; /******************************************************************** -** Solidified function: get_pk +** Solidified function: get_fabric_compressed ********************************************************************/ -be_local_closure(Matter_Session_get_pk, /* name */ - be_nested_proto( - 5, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_nested_str_weak(no_private_key), - /* K1 */ be_nested_str_weak(crypto), - /* K2 */ be_nested_str_weak(random), - }), - be_str_weak(get_pk), - &be_const_str_solidified, - ( &(const binstruction[ 9]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x74060004, // 0001 JMPT R1 #0007 - 0xA4060200, // 0002 IMPORT R1 K1 - 0x8C080302, // 0003 GETMET R2 R1 K2 - 0x5412001F, // 0004 LDINT R4 32 - 0x7C080400, // 0005 CALL R2 2 - 0x90020002, // 0006 SETMBR R0 K0 R2 - 0x88040100, // 0007 GETMBR R1 R0 K0 - 0x80040200, // 0008 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_ac -********************************************************************/ -be_local_closure(Matter_Session_get_ac, /* name */ +be_local_closure(Matter_Session_get_fabric_compressed, /* name */ be_nested_proto( 2, /* nstack */ 1, /* argc */ @@ -56,9 +20,9 @@ be_local_closure(Matter_Session_get_ac, /* name */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(attestation_challenge), + /* K0 */ be_nested_str_weak(fabric_compressed), }), - be_str_weak(get_ac), + be_str_weak(get_fabric_compressed), &be_const_str_solidified, ( &(const binstruction[ 2]) { /* code */ 0x88040100, // 0000 GETMBR R1 R0 K0 @@ -69,6 +33,178 @@ be_local_closure(Matter_Session_get_ac, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: set_no_expiration +********************************************************************/ +be_local_closure(Matter_Session_set_no_expiration, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(expiration), + }), + be_str_weak(set_no_expiration), + &be_const_str_solidified, + ( &(const binstruction[ 3]) { /* code */ + 0x4C040000, // 0000 LDNIL R1 + 0x90020001, // 0001 SETMBR R0 K0 R1 + 0x80000000, // 0002 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_ca +********************************************************************/ +be_local_closure(Matter_Session_set_ca, /* name */ + be_nested_proto( + 2, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(root_ca_certificate), + }), + be_str_weak(set_ca), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x80000000, // 0001 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_fabric_device +********************************************************************/ +be_local_closure(Matter_Session_set_fabric_device, /* name */ + be_nested_proto( + 7, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(fabric), + /* K1 */ be_nested_str_weak(deviceid), + /* K2 */ be_nested_str_weak(fabric_compressed), + /* K3 */ be_nested_str_weak(__store), + /* K4 */ be_nested_str_weak(remove_redundant_session), + }), + be_str_weak(set_fabric_device), + &be_const_str_solidified, + ( &(const binstruction[ 8]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x90020202, // 0001 SETMBR R0 K1 R2 + 0x90020403, // 0002 SETMBR R0 K2 R3 + 0x88100103, // 0003 GETMBR R4 R0 K3 + 0x8C100904, // 0004 GETMET R4 R4 K4 + 0x5C180000, // 0005 MOVE R6 R0 + 0x7C100400, // 0006 CALL R4 2 + 0x80000000, // 0007 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_r2i +********************************************************************/ +be_local_closure(Matter_Session_get_r2i, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(r2ikey), + }), + be_str_weak(get_r2i), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_i2r_privacy +********************************************************************/ +be_local_closure(Matter_Session_get_i2r_privacy, /* name */ + be_nested_proto( + 9, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 7]) { /* constants */ + /* K0 */ be_nested_str_weak(_i2r_privacy), + /* K1 */ be_nested_str_weak(crypto), + /* K2 */ be_nested_str_weak(HKDF_SHA256), + /* K3 */ be_nested_str_weak(derive), + /* K4 */ be_nested_str_weak(get_i2r), + /* K5 */ be_nested_str_weak(fromstring), + /* K6 */ be_nested_str_weak(PrivacyKey), + }), + be_str_weak(get_i2r_privacy), + &be_const_str_solidified, + ( &(const binstruction[22]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x4C080000, // 0001 LDNIL R2 + 0x1C040202, // 0002 EQ R1 R1 R2 + 0x7806000F, // 0003 JMPF R1 #0014 + 0xA4060200, // 0004 IMPORT R1 K1 + 0x8C080302, // 0005 GETMET R2 R1 K2 + 0x7C080200, // 0006 CALL R2 1 + 0x8C080503, // 0007 GETMET R2 R2 K3 + 0x8C100104, // 0008 GETMET R4 R0 K4 + 0x7C100200, // 0009 CALL R4 1 + 0x60140015, // 000A GETGBL R5 G21 + 0x7C140000, // 000B CALL R5 0 + 0x60180015, // 000C GETGBL R6 G21 + 0x7C180000, // 000D CALL R6 0 + 0x8C180D05, // 000E GETMET R6 R6 K5 + 0x58200006, // 000F LDCONST R8 K6 + 0x7C180400, // 0010 CALL R6 2 + 0x541E000F, // 0011 LDINT R7 16 + 0x7C080A00, // 0012 CALL R2 5 + 0x90020002, // 0013 SETMBR R0 K0 R2 + 0x88040100, // 0014 GETMBR R1 R0 K0 + 0x80040200, // 0015 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: get_ipk_group_key ********************************************************************/ @@ -126,26 +262,130 @@ be_local_closure(Matter_Session_get_ipk_group_key, /* name */ /******************************************************************** -** Solidified function: set_ca +** Solidified function: fromjson ********************************************************************/ -be_local_closure(Matter_Session_set_ca, /* name */ +be_local_closure(Matter_Session_fromjson, /* name */ be_nested_proto( - 2, /* nstack */ + 16, /* nstack */ 2, /* argc */ - 2, /* varg */ + 4, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(root_ca_certificate), + ( &(const bvalue[19]) { /* constants */ + /* K0 */ be_const_class(be_class_Matter_Session), + /* K1 */ be_nested_str_weak(string), + /* K2 */ be_nested_str_weak(introspect), + /* K3 */ be_nested_str_weak(matter), + /* K4 */ be_nested_str_weak(Session), + /* K5 */ be_nested_str_weak(keys), + /* K6 */ be_nested_str_weak(counter_rcv), + /* K7 */ be_nested_str_weak(reset), + /* K8 */ be_nested_str_weak(counter_snd), + /* K9 */ be_nested_str_weak(find), + /* K10 */ be_nested_str_weak(0x), + /* K11 */ be_const_int(0), + /* K12 */ be_nested_str_weak(set), + /* K13 */ be_nested_str_weak(fromhex), + /* K14 */ be_const_int(2), + /* K15 */ be_const_int(2147483647), + /* K16 */ be_nested_str_weak(_X24_X24), + /* K17 */ be_nested_str_weak(fromb64), + /* K18 */ be_nested_str_weak(stop_iteration), }), - be_str_weak(set_ca), + be_str_weak(fromjson), &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x90020001, // 0000 SETMBR R0 K0 R1 - 0x80000000, // 0001 RET 0 + ( &(const binstruction[88]) { /* code */ + 0x58080000, // 0000 LDCONST R2 K0 + 0xA40E0200, // 0001 IMPORT R3 K1 + 0xA4120400, // 0002 IMPORT R4 K2 + 0xB8160600, // 0003 GETNGBL R5 K3 + 0x8C140B04, // 0004 GETMET R5 R5 K4 + 0x5C1C0000, // 0005 MOVE R7 R0 + 0x7C140400, // 0006 CALL R5 2 + 0x60180010, // 0007 GETGBL R6 G16 + 0x8C1C0305, // 0008 GETMET R7 R1 K5 + 0x7C1C0200, // 0009 CALL R7 1 + 0x7C180200, // 000A CALL R6 1 + 0xA8020047, // 000B EXBLK 0 #0054 + 0x5C1C0C00, // 000C MOVE R7 R6 + 0x7C1C0000, // 000D CALL R7 0 + 0x94200207, // 000E GETIDX R8 R1 R7 + 0x1C240F06, // 000F EQ R9 R7 K6 + 0x78260006, // 0010 JMPF R9 #0018 + 0x88240B06, // 0011 GETMBR R9 R5 K6 + 0x8C241307, // 0012 GETMET R9 R9 K7 + 0x602C0009, // 0013 GETGBL R11 G9 + 0x5C301000, // 0014 MOVE R12 R8 + 0x7C2C0200, // 0015 CALL R11 1 + 0x7C240400, // 0016 CALL R9 2 + 0x7002003A, // 0017 JMP #0053 + 0x1C240F08, // 0018 EQ R9 R7 K8 + 0x78260006, // 0019 JMPF R9 #0021 + 0x88240B08, // 001A GETMBR R9 R5 K8 + 0x8C241307, // 001B GETMET R9 R9 K7 + 0x602C0009, // 001C GETGBL R11 G9 + 0x5C301000, // 001D MOVE R12 R8 + 0x7C2C0200, // 001E CALL R11 1 + 0x7C240400, // 001F CALL R9 2 + 0x70020031, // 0020 JMP #0053 + 0x60240004, // 0021 GETGBL R9 G4 + 0x5C281000, // 0022 MOVE R10 R8 + 0x7C240200, // 0023 CALL R9 1 + 0x1C241301, // 0024 EQ R9 R9 K1 + 0x78260027, // 0025 JMPF R9 #004E + 0x8C240709, // 0026 GETMET R9 R3 K9 + 0x5C2C1000, // 0027 MOVE R11 R8 + 0x5830000A, // 0028 LDCONST R12 K10 + 0x7C240600, // 0029 CALL R9 3 + 0x1C24130B, // 002A EQ R9 R9 K11 + 0x7826000A, // 002B JMPF R9 #0037 + 0x8C24090C, // 002C GETMET R9 R4 K12 + 0x5C2C0A00, // 002D MOVE R11 R5 + 0x5C300E00, // 002E MOVE R12 R7 + 0x60340015, // 002F GETGBL R13 G21 + 0x7C340000, // 0030 CALL R13 0 + 0x8C341B0D, // 0031 GETMET R13 R13 K13 + 0x403E1D0F, // 0032 CONNECT R15 K14 K15 + 0x943C100F, // 0033 GETIDX R15 R8 R15 + 0x7C340400, // 0034 CALL R13 2 + 0x7C240800, // 0035 CALL R9 4 + 0x70020015, // 0036 JMP #004D + 0x8C240709, // 0037 GETMET R9 R3 K9 + 0x5C2C1000, // 0038 MOVE R11 R8 + 0x58300010, // 0039 LDCONST R12 K16 + 0x7C240600, // 003A CALL R9 3 + 0x1C24130B, // 003B EQ R9 R9 K11 + 0x7826000A, // 003C JMPF R9 #0048 + 0x8C24090C, // 003D GETMET R9 R4 K12 + 0x5C2C0A00, // 003E MOVE R11 R5 + 0x5C300E00, // 003F MOVE R12 R7 + 0x60340015, // 0040 GETGBL R13 G21 + 0x7C340000, // 0041 CALL R13 0 + 0x8C341B11, // 0042 GETMET R13 R13 K17 + 0x403E1D0F, // 0043 CONNECT R15 K14 K15 + 0x943C100F, // 0044 GETIDX R15 R8 R15 + 0x7C340400, // 0045 CALL R13 2 + 0x7C240800, // 0046 CALL R9 4 + 0x70020004, // 0047 JMP #004D + 0x8C24090C, // 0048 GETMET R9 R4 K12 + 0x5C2C0A00, // 0049 MOVE R11 R5 + 0x5C300E00, // 004A MOVE R12 R7 + 0x5C341000, // 004B MOVE R13 R8 + 0x7C240800, // 004C CALL R9 4 + 0x70020004, // 004D JMP #0053 + 0x8C24090C, // 004E GETMET R9 R4 K12 + 0x5C2C0A00, // 004F MOVE R11 R5 + 0x5C300E00, // 0050 MOVE R12 R7 + 0x5C341000, // 0051 MOVE R13 R8 + 0x7C240800, // 0052 CALL R9 4 + 0x7001FFB7, // 0053 JMP #000C + 0x58180012, // 0054 LDCONST R6 K18 + 0xAC180200, // 0055 CATCH R6 1 0 + 0xB0080000, // 0056 RAISE 2 R0 R0 + 0x80040A00, // 0057 RET 1 R5 }) ) ); @@ -153,11 +393,11 @@ be_local_closure(Matter_Session_set_ca, /* name */ /******************************************************************** -** Solidified function: save +** Solidified function: get_deviceid ********************************************************************/ -be_local_closure(Matter_Session_save, /* name */ +be_local_closure(Matter_Session_get_deviceid, /* name */ be_nested_proto( - 3, /* nstack */ + 2, /* nstack */ 1, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -165,44 +405,14 @@ be_local_closure(Matter_Session_save, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(__store), - /* K1 */ be_nested_str_weak(save), - }), - be_str_weak(save), - &be_const_str_solidified, - ( &(const binstruction[ 4]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x8C040301, // 0001 GETMET R1 R1 K1 - 0x7C040200, // 0002 CALL R1 1 - 0x80000000, // 0003 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: set_ipk_epoch_key -********************************************************************/ -be_local_closure(Matter_Session_set_ipk_epoch_key, /* name */ - be_nested_proto( - 2, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(ipk_epoch_key), + /* K0 */ be_nested_str_weak(deviceid), }), - be_str_weak(set_ipk_epoch_key), + be_str_weak(get_deviceid), &be_const_str_solidified, ( &(const binstruction[ 2]) { /* code */ - 0x90020001, // 0000 SETMBR R0 K0 R1 - 0x80000000, // 0001 RET 0 + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 }) ) ); @@ -210,29 +420,103 @@ be_local_closure(Matter_Session_set_ipk_epoch_key, /* name */ /******************************************************************** -** Solidified function: set_expire_time +** Solidified function: close ********************************************************************/ -be_local_closure(Matter_Session_set_expire_time, /* name */ +be_local_closure(Matter_Session_close, /* name */ be_nested_proto( - 4, /* nstack */ - 2, /* argc */ + 9, /* nstack */ + 1, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(expiration), + ( &(const bvalue[22]) { /* constants */ + /* K0 */ be_nested_str_weak(_persist), + /* K1 */ be_nested_str_weak(local_session_id), + /* K2 */ be_nested_str_weak(_future_local_session_id), + /* K3 */ be_nested_str_weak(initiator_session_id), + /* K4 */ be_nested_str_weak(_future_initiator_session_id), + /* K5 */ be_nested_str_weak(source_node_id), + /* K6 */ be_nested_str_weak(counter_rcv), + /* K7 */ be_nested_str_weak(reset), + /* K8 */ be_nested_str_weak(counter_snd), + /* K9 */ be_nested_str_weak(i2rkey), + /* K10 */ be_nested_str_weak(_i2r_privacy), + /* K11 */ be_nested_str_weak(r2ikey), + /* K12 */ be_nested_str_weak(attestation_challenge), + /* K13 */ be_nested_str_weak(introspect), + /* K14 */ be_nested_str_weak(members), + /* K15 */ be_nested_str_weak(get), + /* K16 */ be_nested_str_weak(function), + /* K17 */ be_nested_str_weak(instance), + /* K18 */ be_const_int(0), + /* K19 */ be_nested_str_weak(_), + /* K20 */ be_const_int(1), + /* K21 */ be_nested_str_weak(stop_iteration), }), - be_str_weak(set_expire_time), + be_str_weak(close), &be_const_str_solidified, - ( &(const binstruction[ 5]) { /* code */ - 0x60080009, // 0000 GETGBL R2 G9 - 0x5C0C0200, // 0001 MOVE R3 R1 - 0x7C080200, // 0002 CALL R2 1 - 0x90020002, // 0003 SETMBR R0 K0 R2 - 0x80000000, // 0004 RET 0 + ( &(const binstruction[58]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x88080102, // 0001 GETMBR R2 R0 K2 + 0x90020202, // 0002 SETMBR R0 K1 R2 + 0x88080104, // 0003 GETMBR R2 R0 K4 + 0x90020602, // 0004 SETMBR R0 K3 R2 + 0x4C080000, // 0005 LDNIL R2 + 0x90020A02, // 0006 SETMBR R0 K5 R2 + 0x88080106, // 0007 GETMBR R2 R0 K6 + 0x8C080507, // 0008 GETMET R2 R2 K7 + 0x7C080200, // 0009 CALL R2 1 + 0x88080108, // 000A GETMBR R2 R0 K8 + 0x8C080507, // 000B GETMET R2 R2 K7 + 0x7C080200, // 000C CALL R2 1 + 0x4C080000, // 000D LDNIL R2 + 0x90021202, // 000E SETMBR R0 K9 R2 + 0x4C080000, // 000F LDNIL R2 + 0x90021402, // 0010 SETMBR R0 K10 R2 + 0x4C080000, // 0011 LDNIL R2 + 0x90021602, // 0012 SETMBR R0 K11 R2 + 0x4C080000, // 0013 LDNIL R2 + 0x90021802, // 0014 SETMBR R0 K12 R2 + 0xA40A1A00, // 0015 IMPORT R2 K13 + 0x600C0010, // 0016 GETGBL R3 G16 + 0x8C10050E, // 0017 GETMET R4 R2 K14 + 0x5C180000, // 0018 MOVE R6 R0 + 0x7C100400, // 0019 CALL R4 2 + 0x7C0C0200, // 001A CALL R3 1 + 0xA8020018, // 001B EXBLK 0 #0035 + 0x5C100600, // 001C MOVE R4 R3 + 0x7C100000, // 001D CALL R4 0 + 0x8C14050F, // 001E GETMET R5 R2 K15 + 0x5C1C0000, // 001F MOVE R7 R0 + 0x5C200800, // 0020 MOVE R8 R4 + 0x7C140600, // 0021 CALL R5 3 + 0x60180004, // 0022 GETGBL R6 G4 + 0x5C1C0A00, // 0023 MOVE R7 R5 + 0x7C180200, // 0024 CALL R6 1 + 0x20180D10, // 0025 NE R6 R6 K16 + 0x781A000C, // 0026 JMPF R6 #0034 + 0x60180004, // 0027 GETGBL R6 G4 + 0x5C1C0A00, // 0028 MOVE R7 R5 + 0x7C180200, // 0029 CALL R6 1 + 0x20180D11, // 002A NE R6 R6 K17 + 0x781A0007, // 002B JMPF R6 #0034 + 0x94180912, // 002C GETIDX R6 R4 K18 + 0x1C180D13, // 002D EQ R6 R6 K19 + 0x781A0004, // 002E JMPF R6 #0034 + 0x94180914, // 002F GETIDX R6 R4 K20 + 0x20180D13, // 0030 NE R6 R6 K19 + 0x781A0001, // 0031 JMPF R6 #0034 + 0x4C180000, // 0032 LDNIL R6 + 0x90000806, // 0033 SETMBR R0 R4 R6 + 0x7001FFE6, // 0034 JMP #001C + 0x580C0015, // 0035 LDCONST R3 K21 + 0xAC0C0200, // 0036 CATCH R3 1 0 + 0xB0080000, // 0037 RAISE 2 R0 R0 + 0x90020001, // 0038 SETMBR R0 K0 R1 + 0x80000000, // 0039 RET 0 }) ) ); @@ -240,42 +524,35 @@ be_local_closure(Matter_Session_set_expire_time, /* name */ /******************************************************************** -** Solidified function: set_expire_in_seconds +** Solidified function: get_pk ********************************************************************/ -be_local_closure(Matter_Session_set_expire_in_seconds, /* name */ +be_local_closure(Matter_Session_get_pk, /* name */ be_nested_proto( - 6, /* nstack */ - 3, /* argc */ + 5, /* nstack */ + 1, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 4]) { /* constants */ - /* K0 */ be_nested_str_weak(tasmota), - /* K1 */ be_nested_str_weak(rtc), - /* K2 */ be_nested_str_weak(utc), - /* K3 */ be_nested_str_weak(set_expire_time), + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(no_private_key), + /* K1 */ be_nested_str_weak(crypto), + /* K2 */ be_nested_str_weak(random), }), - be_str_weak(set_expire_in_seconds), + be_str_weak(get_pk), &be_const_str_solidified, - ( &(const binstruction[15]) { /* code */ - 0x4C0C0000, // 0000 LDNIL R3 - 0x1C0C0203, // 0001 EQ R3 R1 R3 - 0x780E0000, // 0002 JMPF R3 #0004 - 0x80000600, // 0003 RET 0 - 0x4C0C0000, // 0004 LDNIL R3 - 0x1C0C0403, // 0005 EQ R3 R2 R3 - 0x780E0003, // 0006 JMPF R3 #000B - 0xB80E0000, // 0007 GETNGBL R3 K0 - 0x8C0C0701, // 0008 GETMET R3 R3 K1 - 0x7C0C0200, // 0009 CALL R3 1 - 0x94080702, // 000A GETIDX R2 R3 K2 - 0x8C0C0103, // 000B GETMET R3 R0 K3 - 0x00140401, // 000C ADD R5 R2 R1 - 0x7C0C0400, // 000D CALL R3 2 - 0x80000000, // 000E RET 0 + ( &(const binstruction[ 9]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x74060004, // 0001 JMPT R1 #0007 + 0xA4060200, // 0002 IMPORT R1 K1 + 0x8C080302, // 0003 GETMET R2 R1 K2 + 0x5412001F, // 0004 LDINT R4 32 + 0x7C080400, // 0005 CALL R2 2 + 0x90020002, // 0006 SETMBR R0 K0 R2 + 0x88040100, // 0007 GETMBR R1 R0 K0 + 0x80040200, // 0008 RET 1 R1 }) ) ); @@ -429,9 +706,66 @@ be_local_closure(Matter_Session_tojson, /* name */ /******************************************************************** -** Solidified function: get_noc +** Solidified function: set_expire_time ********************************************************************/ -be_local_closure(Matter_Session_get_noc, /* name */ +be_local_closure(Matter_Session_set_expire_time, /* name */ + be_nested_proto( + 4, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(expiration), + }), + be_str_weak(set_expire_time), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x60080009, // 0000 GETGBL R2 G9 + 0x5C0C0200, // 0001 MOVE R3 R1 + 0x7C080200, // 0002 CALL R2 1 + 0x90020002, // 0003 SETMBR R0 K0 R2 + 0x80000000, // 0004 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_mode +********************************************************************/ +be_local_closure(Matter_Session_set_mode, /* name */ + be_nested_proto( + 2, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(mode), + }), + be_str_weak(set_mode), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x80000000, // 0001 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_icac +********************************************************************/ +be_local_closure(Matter_Session_get_icac, /* name */ be_nested_proto( 2, /* nstack */ 1, /* argc */ @@ -442,9 +776,301 @@ be_local_closure(Matter_Session_get_noc, /* name */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(noc), + /* K0 */ be_nested_str_weak(icac), }), - be_str_weak(get_noc), + be_str_weak(get_icac), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_persist +********************************************************************/ +be_local_closure(Matter_Session_set_persist, /* name */ + be_nested_proto( + 4, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(_persist), + }), + be_str_weak(set_persist), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x60080017, // 0000 GETGBL R2 G23 + 0x5C0C0200, // 0001 MOVE R3 R1 + 0x7C080200, // 0002 CALL R2 1 + 0x90020002, // 0003 SETMBR R0 K0 R2 + 0x80000000, // 0004 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_ipk_epoch_key +********************************************************************/ +be_local_closure(Matter_Session_set_ipk_epoch_key, /* name */ + be_nested_proto( + 2, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(ipk_epoch_key), + }), + be_str_weak(set_ipk_epoch_key), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x80000000, // 0001 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_mode +********************************************************************/ +be_local_closure(Matter_Session_get_mode, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(mode), + }), + be_str_weak(get_mode), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_ca +********************************************************************/ +be_local_closure(Matter_Session_get_ca, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(root_ca_certificate), + }), + be_str_weak(get_ca), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: save +********************************************************************/ +be_local_closure(Matter_Session_save, /* name */ + be_nested_proto( + 3, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(__store), + /* K1 */ be_nested_str_weak(save), + }), + be_str_weak(save), + &be_const_str_solidified, + ( &(const binstruction[ 4]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0x7C040200, // 0002 CALL R1 1 + 0x80000000, // 0003 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_ca_pub +********************************************************************/ +be_local_closure(Matter_Session_get_ca_pub, /* name */ + be_nested_proto( + 5, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(root_ca_certificate), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(TLV), + /* K3 */ be_nested_str_weak(parse), + /* K4 */ be_nested_str_weak(findsubval), + }), + be_str_weak(get_ca_pub), + &be_const_str_solidified, + ( &(const binstruction[12]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x78060008, // 0001 JMPF R1 #000B + 0xB8060200, // 0002 GETNGBL R1 K1 + 0x88040302, // 0003 GETMBR R1 R1 K2 + 0x8C040303, // 0004 GETMET R1 R1 K3 + 0x880C0100, // 0005 GETMBR R3 R0 K0 + 0x7C040400, // 0006 CALL R1 2 + 0x8C080304, // 0007 GETMET R2 R1 K4 + 0x54120008, // 0008 LDINT R4 9 + 0x7C080400, // 0009 CALL R2 2 + 0x80040400, // 000A RET 1 R2 + 0x80000000, // 000B RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_ipk_epoch_key +********************************************************************/ +be_local_closure(Matter_Session_get_ipk_epoch_key, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(ipk_epoch_key), + }), + be_str_weak(get_ipk_epoch_key), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_ac +********************************************************************/ +be_local_closure(Matter_Session_get_ac, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(attestation_challenge), + }), + be_str_weak(get_ac), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_noc +********************************************************************/ +be_local_closure(Matter_Session_set_noc, /* name */ + be_nested_proto( + 3, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(noc), + /* K1 */ be_nested_str_weak(icac), + }), + be_str_weak(set_noc), + &be_const_str_solidified, + ( &(const binstruction[ 3]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x90020202, // 0001 SETMBR R0 K1 R2 + 0x80000000, // 0002 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_i2r +********************************************************************/ +be_local_closure(Matter_Session_get_i2r, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(i2rkey), + }), + be_str_weak(get_i2r), &be_const_str_solidified, ( &(const binstruction[ 2]) { /* code */ 0x88040100, // 0000 GETMBR R1 R0 K0 @@ -483,43 +1109,35 @@ be_local_closure(Matter_Session_get_fabric, /* name */ /******************************************************************** -** Solidified function: has_expired +** Solidified function: set_keys ********************************************************************/ -be_local_closure(Matter_Session_has_expired, /* name */ +be_local_closure(Matter_Session_set_keys, /* name */ be_nested_proto( - 4, /* nstack */ - 2, /* argc */ + 6, /* nstack */ + 5, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 4]) { /* constants */ - /* K0 */ be_nested_str_weak(tasmota), - /* K1 */ be_nested_str_weak(rtc), - /* K2 */ be_nested_str_weak(utc), - /* K3 */ be_nested_str_weak(expiration), + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(i2rkey), + /* K1 */ be_nested_str_weak(_i2r_privacy), + /* K2 */ be_nested_str_weak(r2ikey), + /* K3 */ be_nested_str_weak(attestation_challenge), + /* K4 */ be_nested_str_weak(session_timestamp), }), - be_str_weak(has_expired), + be_str_weak(set_keys), &be_const_str_solidified, - ( &(const binstruction[16]) { /* code */ - 0x4C080000, // 0000 LDNIL R2 - 0x1C080202, // 0001 EQ R2 R1 R2 - 0x780A0003, // 0002 JMPF R2 #0007 - 0xB80A0000, // 0003 GETNGBL R2 K0 - 0x8C080501, // 0004 GETMET R2 R2 K1 - 0x7C080200, // 0005 CALL R2 1 - 0x94040502, // 0006 GETIDX R1 R2 K2 - 0x88080103, // 0007 GETMBR R2 R0 K3 - 0x4C0C0000, // 0008 LDNIL R3 - 0x20080403, // 0009 NE R2 R2 R3 - 0x780A0002, // 000A JMPF R2 #000E - 0x88080103, // 000B GETMBR R2 R0 K3 - 0x28080202, // 000C GE R2 R1 R2 - 0x80040400, // 000D RET 1 R2 - 0x50080000, // 000E LDBOOL R2 0 0 - 0x80040400, // 000F RET 1 R2 + ( &(const binstruction[ 7]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x4C140000, // 0001 LDNIL R5 + 0x90020205, // 0002 SETMBR R0 K1 R5 + 0x90020402, // 0003 SETMBR R0 K2 R2 + 0x90020603, // 0004 SETMBR R0 K3 R3 + 0x90020804, // 0005 SETMBR R0 K4 R4 + 0x80000000, // 0006 RET 0 }) ) ); @@ -527,140 +1145,9 @@ be_local_closure(Matter_Session_has_expired, /* name */ /******************************************************************** -** Solidified function: fromjson +** Solidified function: get_noc ********************************************************************/ -be_local_closure(Matter_Session_fromjson, /* name */ - be_nested_proto( - 16, /* nstack */ - 2, /* argc */ - 4, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[19]) { /* constants */ - /* K0 */ be_const_class(be_class_Matter_Session), - /* K1 */ be_nested_str_weak(string), - /* K2 */ be_nested_str_weak(introspect), - /* K3 */ be_nested_str_weak(matter), - /* K4 */ be_nested_str_weak(Session), - /* K5 */ be_nested_str_weak(keys), - /* K6 */ be_nested_str_weak(counter_rcv), - /* K7 */ be_nested_str_weak(reset), - /* K8 */ be_nested_str_weak(counter_snd), - /* K9 */ be_nested_str_weak(find), - /* K10 */ be_nested_str_weak(0x), - /* K11 */ be_const_int(0), - /* K12 */ be_nested_str_weak(set), - /* K13 */ be_nested_str_weak(fromhex), - /* K14 */ be_const_int(2), - /* K15 */ be_const_int(2147483647), - /* K16 */ be_nested_str_weak(_X24_X24), - /* K17 */ be_nested_str_weak(fromb64), - /* K18 */ be_nested_str_weak(stop_iteration), - }), - be_str_weak(fromjson), - &be_const_str_solidified, - ( &(const binstruction[88]) { /* code */ - 0x58080000, // 0000 LDCONST R2 K0 - 0xA40E0200, // 0001 IMPORT R3 K1 - 0xA4120400, // 0002 IMPORT R4 K2 - 0xB8160600, // 0003 GETNGBL R5 K3 - 0x8C140B04, // 0004 GETMET R5 R5 K4 - 0x5C1C0000, // 0005 MOVE R7 R0 - 0x7C140400, // 0006 CALL R5 2 - 0x60180010, // 0007 GETGBL R6 G16 - 0x8C1C0305, // 0008 GETMET R7 R1 K5 - 0x7C1C0200, // 0009 CALL R7 1 - 0x7C180200, // 000A CALL R6 1 - 0xA8020047, // 000B EXBLK 0 #0054 - 0x5C1C0C00, // 000C MOVE R7 R6 - 0x7C1C0000, // 000D CALL R7 0 - 0x94200207, // 000E GETIDX R8 R1 R7 - 0x1C240F06, // 000F EQ R9 R7 K6 - 0x78260006, // 0010 JMPF R9 #0018 - 0x88240B06, // 0011 GETMBR R9 R5 K6 - 0x8C241307, // 0012 GETMET R9 R9 K7 - 0x602C0009, // 0013 GETGBL R11 G9 - 0x5C301000, // 0014 MOVE R12 R8 - 0x7C2C0200, // 0015 CALL R11 1 - 0x7C240400, // 0016 CALL R9 2 - 0x7002003A, // 0017 JMP #0053 - 0x1C240F08, // 0018 EQ R9 R7 K8 - 0x78260006, // 0019 JMPF R9 #0021 - 0x88240B08, // 001A GETMBR R9 R5 K8 - 0x8C241307, // 001B GETMET R9 R9 K7 - 0x602C0009, // 001C GETGBL R11 G9 - 0x5C301000, // 001D MOVE R12 R8 - 0x7C2C0200, // 001E CALL R11 1 - 0x7C240400, // 001F CALL R9 2 - 0x70020031, // 0020 JMP #0053 - 0x60240004, // 0021 GETGBL R9 G4 - 0x5C281000, // 0022 MOVE R10 R8 - 0x7C240200, // 0023 CALL R9 1 - 0x1C241301, // 0024 EQ R9 R9 K1 - 0x78260027, // 0025 JMPF R9 #004E - 0x8C240709, // 0026 GETMET R9 R3 K9 - 0x5C2C1000, // 0027 MOVE R11 R8 - 0x5830000A, // 0028 LDCONST R12 K10 - 0x7C240600, // 0029 CALL R9 3 - 0x1C24130B, // 002A EQ R9 R9 K11 - 0x7826000A, // 002B JMPF R9 #0037 - 0x8C24090C, // 002C GETMET R9 R4 K12 - 0x5C2C0A00, // 002D MOVE R11 R5 - 0x5C300E00, // 002E MOVE R12 R7 - 0x60340015, // 002F GETGBL R13 G21 - 0x7C340000, // 0030 CALL R13 0 - 0x8C341B0D, // 0031 GETMET R13 R13 K13 - 0x403E1D0F, // 0032 CONNECT R15 K14 K15 - 0x943C100F, // 0033 GETIDX R15 R8 R15 - 0x7C340400, // 0034 CALL R13 2 - 0x7C240800, // 0035 CALL R9 4 - 0x70020015, // 0036 JMP #004D - 0x8C240709, // 0037 GETMET R9 R3 K9 - 0x5C2C1000, // 0038 MOVE R11 R8 - 0x58300010, // 0039 LDCONST R12 K16 - 0x7C240600, // 003A CALL R9 3 - 0x1C24130B, // 003B EQ R9 R9 K11 - 0x7826000A, // 003C JMPF R9 #0048 - 0x8C24090C, // 003D GETMET R9 R4 K12 - 0x5C2C0A00, // 003E MOVE R11 R5 - 0x5C300E00, // 003F MOVE R12 R7 - 0x60340015, // 0040 GETGBL R13 G21 - 0x7C340000, // 0041 CALL R13 0 - 0x8C341B11, // 0042 GETMET R13 R13 K17 - 0x403E1D0F, // 0043 CONNECT R15 K14 K15 - 0x943C100F, // 0044 GETIDX R15 R8 R15 - 0x7C340400, // 0045 CALL R13 2 - 0x7C240800, // 0046 CALL R9 4 - 0x70020004, // 0047 JMP #004D - 0x8C24090C, // 0048 GETMET R9 R4 K12 - 0x5C2C0A00, // 0049 MOVE R11 R5 - 0x5C300E00, // 004A MOVE R12 R7 - 0x5C341000, // 004B MOVE R13 R8 - 0x7C240800, // 004C CALL R9 4 - 0x70020004, // 004D JMP #0053 - 0x8C24090C, // 004E GETMET R9 R4 K12 - 0x5C2C0A00, // 004F MOVE R11 R5 - 0x5C300E00, // 0050 MOVE R12 R7 - 0x5C341000, // 0051 MOVE R13 R8 - 0x7C240800, // 0052 CALL R9 4 - 0x7001FFB7, // 0053 JMP #000C - 0x58180012, // 0054 LDCONST R6 K18 - 0xAC180200, // 0055 CATCH R6 1 0 - 0xB0080000, // 0056 RAISE 2 R0 R0 - 0x80040A00, // 0057 RET 1 R5 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: set_no_expiration -********************************************************************/ -be_local_closure(Matter_Session_set_no_expiration, /* name */ +be_local_closure(Matter_Session_get_noc, /* name */ be_nested_proto( 2, /* nstack */ 1, /* argc */ @@ -671,14 +1158,74 @@ be_local_closure(Matter_Session_set_no_expiration, /* name */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(expiration), + /* K0 */ be_nested_str_weak(noc), }), - be_str_weak(set_no_expiration), + be_str_weak(get_noc), &be_const_str_solidified, - ( &(const binstruction[ 3]) { /* code */ - 0x4C040000, // 0000 LDNIL R1 - 0x90020001, // 0001 SETMBR R0 K0 R1 - 0x80000000, // 0002 RET 0 + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_Session_init, /* name */ + be_nested_proto( + 6, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[13]) { /* constants */ + /* K0 */ be_nested_str_weak(__store), + /* K1 */ be_nested_str_weak(mode), + /* K2 */ be_const_int(0), + /* K3 */ be_nested_str_weak(local_session_id), + /* K4 */ be_nested_str_weak(initiator_session_id), + /* K5 */ be_nested_str_weak(counter_rcv), + /* K6 */ be_nested_str_weak(matter), + /* K7 */ be_nested_str_weak(Counter), + /* K8 */ be_nested_str_weak(counter_snd), + /* K9 */ be_nested_str_weak(_counter_insecure_rcv), + /* K10 */ be_nested_str_weak(_counter_insecure_snd), + /* K11 */ be_nested_str_weak(breadcrumb), + /* K12 */ be_nested_str_weak(int64), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[24]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x90020302, // 0001 SETMBR R0 K1 K2 + 0x90020602, // 0002 SETMBR R0 K3 R2 + 0x90020803, // 0003 SETMBR R0 K4 R3 + 0xB8120C00, // 0004 GETNGBL R4 K6 + 0x8C100907, // 0005 GETMET R4 R4 K7 + 0x7C100200, // 0006 CALL R4 1 + 0x90020A04, // 0007 SETMBR R0 K5 R4 + 0xB8120C00, // 0008 GETNGBL R4 K6 + 0x8C100907, // 0009 GETMET R4 R4 K7 + 0x7C100200, // 000A CALL R4 1 + 0x90021004, // 000B SETMBR R0 K8 R4 + 0xB8120C00, // 000C GETNGBL R4 K6 + 0x8C100907, // 000D GETMET R4 R4 K7 + 0x7C100200, // 000E CALL R4 1 + 0x90021204, // 000F SETMBR R0 K9 R4 + 0xB8120C00, // 0010 GETNGBL R4 K6 + 0x8C100907, // 0011 GETMET R4 R4 K7 + 0x7C100200, // 0012 CALL R4 1 + 0x90021404, // 0013 SETMBR R0 K10 R4 + 0xB8121800, // 0014 GETNGBL R4 K12 + 0x7C100000, // 0015 CALL R4 0 + 0x90021604, // 0016 SETMBR R0 K11 R4 + 0x80000000, // 0017 RET 0 }) ) ); @@ -795,71 +1342,11 @@ be_local_closure(Matter_Session_gen_CSR, /* name */ /******************************************************************** -** Solidified function: get_r2i +** Solidified function: set_expire_in_seconds ********************************************************************/ -be_local_closure(Matter_Session_get_r2i, /* name */ +be_local_closure(Matter_Session_set_expire_in_seconds, /* name */ be_nested_proto( - 2, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(r2ikey), - }), - be_str_weak(get_r2i), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: set_keys -********************************************************************/ -be_local_closure(Matter_Session_set_keys, /* name */ - be_nested_proto( - 5, /* nstack */ - 5, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 4]) { /* constants */ - /* K0 */ be_nested_str_weak(i2rkey), - /* K1 */ be_nested_str_weak(r2ikey), - /* K2 */ be_nested_str_weak(attestation_challenge), - /* K3 */ be_nested_str_weak(session_timestamp), - }), - be_str_weak(set_keys), - &be_const_str_solidified, - ( &(const binstruction[ 5]) { /* code */ - 0x90020001, // 0000 SETMBR R0 K0 R1 - 0x90020202, // 0001 SETMBR R0 K1 R2 - 0x90020403, // 0002 SETMBR R0 K2 R3 - 0x90020604, // 0003 SETMBR R0 K3 R4 - 0x80000000, // 0004 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: set_noc -********************************************************************/ -be_local_closure(Matter_Session_set_noc, /* name */ - be_nested_proto( - 3, /* nstack */ + 6, /* nstack */ 3, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -867,16 +1354,30 @@ be_local_closure(Matter_Session_set_noc, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(noc), - /* K1 */ be_nested_str_weak(icac), + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(tasmota), + /* K1 */ be_nested_str_weak(rtc), + /* K2 */ be_nested_str_weak(utc), + /* K3 */ be_nested_str_weak(set_expire_time), }), - be_str_weak(set_noc), + be_str_weak(set_expire_in_seconds), &be_const_str_solidified, - ( &(const binstruction[ 3]) { /* code */ - 0x90020001, // 0000 SETMBR R0 K0 R1 - 0x90020202, // 0001 SETMBR R0 K1 R2 - 0x80000000, // 0002 RET 0 + ( &(const binstruction[15]) { /* code */ + 0x4C0C0000, // 0000 LDNIL R3 + 0x1C0C0203, // 0001 EQ R3 R1 R3 + 0x780E0000, // 0002 JMPF R3 #0004 + 0x80000600, // 0003 RET 0 + 0x4C0C0000, // 0004 LDNIL R3 + 0x1C0C0403, // 0005 EQ R3 R2 R3 + 0x780E0003, // 0006 JMPF R3 #000B + 0xB80E0000, // 0007 GETNGBL R3 K0 + 0x8C0C0701, // 0008 GETMET R3 R3 K1 + 0x7C0C0200, // 0009 CALL R3 1 + 0x94080702, // 000A GETIDX R2 R3 K2 + 0x8C0C0103, // 000B GETMET R3 R0 K3 + 0x00140401, // 000C ADD R5 R2 R1 + 0x7C0C0400, // 000D CALL R3 2 + 0x80000000, // 000E RET 0 }) ) ); @@ -884,154 +1385,9 @@ be_local_closure(Matter_Session_set_noc, /* name */ /******************************************************************** -** Solidified function: set_fabric_device +** Solidified function: has_expired ********************************************************************/ -be_local_closure(Matter_Session_set_fabric_device, /* name */ - be_nested_proto( - 7, /* nstack */ - 4, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 5]) { /* constants */ - /* K0 */ be_nested_str_weak(fabric), - /* K1 */ be_nested_str_weak(deviceid), - /* K2 */ be_nested_str_weak(fabric_compressed), - /* K3 */ be_nested_str_weak(__store), - /* K4 */ be_nested_str_weak(remove_redundant_session), - }), - be_str_weak(set_fabric_device), - &be_const_str_solidified, - ( &(const binstruction[ 8]) { /* code */ - 0x90020001, // 0000 SETMBR R0 K0 R1 - 0x90020202, // 0001 SETMBR R0 K1 R2 - 0x90020403, // 0002 SETMBR R0 K2 R3 - 0x88100103, // 0003 GETMBR R4 R0 K3 - 0x8C100904, // 0004 GETMET R4 R4 K4 - 0x5C180000, // 0005 MOVE R6 R0 - 0x7C100400, // 0006 CALL R4 2 - 0x80000000, // 0007 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_ipk_epoch_key -********************************************************************/ -be_local_closure(Matter_Session_get_ipk_epoch_key, /* name */ - be_nested_proto( - 2, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(ipk_epoch_key), - }), - be_str_weak(get_ipk_epoch_key), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_mode -********************************************************************/ -be_local_closure(Matter_Session_get_mode, /* name */ - be_nested_proto( - 2, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(mode), - }), - be_str_weak(get_mode), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_fabric_compressed -********************************************************************/ -be_local_closure(Matter_Session_get_fabric_compressed, /* name */ - be_nested_proto( - 2, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(fabric_compressed), - }), - be_str_weak(get_fabric_compressed), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: set_mode -********************************************************************/ -be_local_closure(Matter_Session_set_mode, /* name */ - be_nested_proto( - 2, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(mode), - }), - be_str_weak(set_mode), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x90020001, // 0000 SETMBR R0 K0 R1 - 0x80000000, // 0001 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: set_persist -********************************************************************/ -be_local_closure(Matter_Session_set_persist, /* name */ +be_local_closure(Matter_Session_has_expired, /* name */ be_nested_proto( 4, /* nstack */ 2, /* argc */ @@ -1041,328 +1397,31 @@ be_local_closure(Matter_Session_set_persist, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(_persist), + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(tasmota), + /* K1 */ be_nested_str_weak(rtc), + /* K2 */ be_nested_str_weak(utc), + /* K3 */ be_nested_str_weak(expiration), }), - be_str_weak(set_persist), + be_str_weak(has_expired), &be_const_str_solidified, - ( &(const binstruction[ 5]) { /* code */ - 0x60080017, // 0000 GETGBL R2 G23 - 0x5C0C0200, // 0001 MOVE R3 R1 - 0x7C080200, // 0002 CALL R2 1 - 0x90020002, // 0003 SETMBR R0 K0 R2 - 0x80000000, // 0004 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_ca_pub -********************************************************************/ -be_local_closure(Matter_Session_get_ca_pub, /* name */ - be_nested_proto( - 5, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 5]) { /* constants */ - /* K0 */ be_nested_str_weak(root_ca_certificate), - /* K1 */ be_nested_str_weak(matter), - /* K2 */ be_nested_str_weak(TLV), - /* K3 */ be_nested_str_weak(parse), - /* K4 */ be_nested_str_weak(findsubval), - }), - be_str_weak(get_ca_pub), - &be_const_str_solidified, - ( &(const binstruction[12]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x78060008, // 0001 JMPF R1 #000B - 0xB8060200, // 0002 GETNGBL R1 K1 - 0x88040302, // 0003 GETMBR R1 R1 K2 - 0x8C040303, // 0004 GETMET R1 R1 K3 - 0x880C0100, // 0005 GETMBR R3 R0 K0 - 0x7C040400, // 0006 CALL R1 2 - 0x8C080304, // 0007 GETMET R2 R1 K4 - 0x54120008, // 0008 LDINT R4 9 - 0x7C080400, // 0009 CALL R2 2 - 0x80040400, // 000A RET 1 R2 - 0x80000000, // 000B RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_icac -********************************************************************/ -be_local_closure(Matter_Session_get_icac, /* name */ - be_nested_proto( - 2, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(icac), - }), - be_str_weak(get_icac), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: close -********************************************************************/ -be_local_closure(Matter_Session_close, /* name */ - be_nested_proto( - 9, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[21]) { /* constants */ - /* K0 */ be_nested_str_weak(_persist), - /* K1 */ be_nested_str_weak(local_session_id), - /* K2 */ be_nested_str_weak(_future_local_session_id), - /* K3 */ be_nested_str_weak(initiator_session_id), - /* K4 */ be_nested_str_weak(_future_initiator_session_id), - /* K5 */ be_nested_str_weak(source_node_id), - /* K6 */ be_nested_str_weak(counter_rcv), - /* K7 */ be_nested_str_weak(reset), - /* K8 */ be_nested_str_weak(counter_snd), - /* K9 */ be_nested_str_weak(i2rkey), - /* K10 */ be_nested_str_weak(r2ikey), - /* K11 */ be_nested_str_weak(attestation_challenge), - /* K12 */ be_nested_str_weak(introspect), - /* K13 */ be_nested_str_weak(members), - /* K14 */ be_nested_str_weak(get), - /* K15 */ be_nested_str_weak(function), - /* K16 */ be_nested_str_weak(instance), - /* K17 */ be_const_int(0), - /* K18 */ be_nested_str_weak(_), - /* K19 */ be_const_int(1), - /* K20 */ be_nested_str_weak(stop_iteration), - }), - be_str_weak(close), - &be_const_str_solidified, - ( &(const binstruction[56]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x88080102, // 0001 GETMBR R2 R0 K2 - 0x90020202, // 0002 SETMBR R0 K1 R2 - 0x88080104, // 0003 GETMBR R2 R0 K4 - 0x90020602, // 0004 SETMBR R0 K3 R2 - 0x4C080000, // 0005 LDNIL R2 - 0x90020A02, // 0006 SETMBR R0 K5 R2 - 0x88080106, // 0007 GETMBR R2 R0 K6 - 0x8C080507, // 0008 GETMET R2 R2 K7 - 0x7C080200, // 0009 CALL R2 1 - 0x88080108, // 000A GETMBR R2 R0 K8 - 0x8C080507, // 000B GETMET R2 R2 K7 - 0x7C080200, // 000C CALL R2 1 - 0x4C080000, // 000D LDNIL R2 - 0x90021202, // 000E SETMBR R0 K9 R2 - 0x4C080000, // 000F LDNIL R2 - 0x90021402, // 0010 SETMBR R0 K10 R2 - 0x4C080000, // 0011 LDNIL R2 - 0x90021602, // 0012 SETMBR R0 K11 R2 - 0xA40A1800, // 0013 IMPORT R2 K12 - 0x600C0010, // 0014 GETGBL R3 G16 - 0x8C10050D, // 0015 GETMET R4 R2 K13 - 0x5C180000, // 0016 MOVE R6 R0 - 0x7C100400, // 0017 CALL R4 2 - 0x7C0C0200, // 0018 CALL R3 1 - 0xA8020018, // 0019 EXBLK 0 #0033 - 0x5C100600, // 001A MOVE R4 R3 - 0x7C100000, // 001B CALL R4 0 - 0x8C14050E, // 001C GETMET R5 R2 K14 - 0x5C1C0000, // 001D MOVE R7 R0 - 0x5C200800, // 001E MOVE R8 R4 - 0x7C140600, // 001F CALL R5 3 - 0x60180004, // 0020 GETGBL R6 G4 - 0x5C1C0A00, // 0021 MOVE R7 R5 - 0x7C180200, // 0022 CALL R6 1 - 0x20180D0F, // 0023 NE R6 R6 K15 - 0x781A000C, // 0024 JMPF R6 #0032 - 0x60180004, // 0025 GETGBL R6 G4 - 0x5C1C0A00, // 0026 MOVE R7 R5 - 0x7C180200, // 0027 CALL R6 1 - 0x20180D10, // 0028 NE R6 R6 K16 - 0x781A0007, // 0029 JMPF R6 #0032 - 0x94180911, // 002A GETIDX R6 R4 K17 - 0x1C180D12, // 002B EQ R6 R6 K18 - 0x781A0004, // 002C JMPF R6 #0032 - 0x94180913, // 002D GETIDX R6 R4 K19 - 0x20180D12, // 002E NE R6 R6 K18 - 0x781A0001, // 002F JMPF R6 #0032 - 0x4C180000, // 0030 LDNIL R6 - 0x90000806, // 0031 SETMBR R0 R4 R6 - 0x7001FFE6, // 0032 JMP #001A - 0x580C0014, // 0033 LDCONST R3 K20 - 0xAC0C0200, // 0034 CATCH R3 1 0 - 0xB0080000, // 0035 RAISE 2 R0 R0 - 0x90020001, // 0036 SETMBR R0 K0 R1 - 0x80000000, // 0037 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: init -********************************************************************/ -be_local_closure(Matter_Session_init, /* name */ - be_nested_proto( - 6, /* nstack */ - 4, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[13]) { /* constants */ - /* K0 */ be_nested_str_weak(__store), - /* K1 */ be_nested_str_weak(mode), - /* K2 */ be_const_int(0), - /* K3 */ be_nested_str_weak(local_session_id), - /* K4 */ be_nested_str_weak(initiator_session_id), - /* K5 */ be_nested_str_weak(counter_rcv), - /* K6 */ be_nested_str_weak(matter), - /* K7 */ be_nested_str_weak(Counter), - /* K8 */ be_nested_str_weak(counter_snd), - /* K9 */ be_nested_str_weak(_counter_insecure_rcv), - /* K10 */ be_nested_str_weak(_counter_insecure_snd), - /* K11 */ be_nested_str_weak(breadcrumb), - /* K12 */ be_nested_str_weak(int64), - }), - be_str_weak(init), - &be_const_str_solidified, - ( &(const binstruction[24]) { /* code */ - 0x90020001, // 0000 SETMBR R0 K0 R1 - 0x90020302, // 0001 SETMBR R0 K1 K2 - 0x90020602, // 0002 SETMBR R0 K3 R2 - 0x90020803, // 0003 SETMBR R0 K4 R3 - 0xB8120C00, // 0004 GETNGBL R4 K6 - 0x8C100907, // 0005 GETMET R4 R4 K7 - 0x7C100200, // 0006 CALL R4 1 - 0x90020A04, // 0007 SETMBR R0 K5 R4 - 0xB8120C00, // 0008 GETNGBL R4 K6 - 0x8C100907, // 0009 GETMET R4 R4 K7 - 0x7C100200, // 000A CALL R4 1 - 0x90021004, // 000B SETMBR R0 K8 R4 - 0xB8120C00, // 000C GETNGBL R4 K6 - 0x8C100907, // 000D GETMET R4 R4 K7 - 0x7C100200, // 000E CALL R4 1 - 0x90021204, // 000F SETMBR R0 K9 R4 - 0xB8120C00, // 0010 GETNGBL R4 K6 - 0x8C100907, // 0011 GETMET R4 R4 K7 - 0x7C100200, // 0012 CALL R4 1 - 0x90021404, // 0013 SETMBR R0 K10 R4 - 0xB8121800, // 0014 GETNGBL R4 K12 - 0x7C100000, // 0015 CALL R4 0 - 0x90021604, // 0016 SETMBR R0 K11 R4 - 0x80000000, // 0017 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_ca -********************************************************************/ -be_local_closure(Matter_Session_get_ca, /* name */ - be_nested_proto( - 2, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(root_ca_certificate), - }), - be_str_weak(get_ca), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_deviceid -********************************************************************/ -be_local_closure(Matter_Session_get_deviceid, /* name */ - be_nested_proto( - 2, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(deviceid), - }), - be_str_weak(get_deviceid), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_i2r -********************************************************************/ -be_local_closure(Matter_Session_get_i2r, /* name */ - be_nested_proto( - 2, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(i2rkey), - }), - be_str_weak(get_i2r), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 + ( &(const binstruction[16]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0003, // 0002 JMPF R2 #0007 + 0xB80A0000, // 0003 GETNGBL R2 K0 + 0x8C080501, // 0004 GETMET R2 R2 K1 + 0x7C080200, // 0005 CALL R2 1 + 0x94040502, // 0006 GETIDX R1 R2 K2 + 0x88080103, // 0007 GETMBR R2 R0 K3 + 0x4C0C0000, // 0008 LDNIL R3 + 0x20080403, // 0009 NE R2 R2 R3 + 0x780A0002, // 000A JMPF R2 #000E + 0x88080103, // 000B GETMBR R2 R0 K3 + 0x28080202, // 000C GE R2 R1 R2 + 0x80040400, // 000D RET 1 R2 + 0x50080000, // 000E LDBOOL R2 0 0 + 0x80040400, // 000F RET 1 R2 }) ) ); @@ -1373,77 +1432,79 @@ be_local_closure(Matter_Session_get_i2r, /* name */ ** Solidified class: Matter_Session ********************************************************************/ be_local_class(Matter_Session, - 33, + 34, NULL, - be_nested_map(67, + be_nested_map(69, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(root_ca_certificate, -1), be_const_var(18) }, - { be_const_key_weak(ipk_epoch_key, -1), be_const_var(21) }, - { be_const_key_weak(get_deviceid, -1), be_const_closure(Matter_Session_get_deviceid_closure) }, - { be_const_key_weak(get_ca, -1), be_const_closure(Matter_Session_get_ca_closure) }, - { be_const_key_weak(resumption_id, 11), be_const_var(22) }, - { be_const_key_weak(expiration, -1), be_const_var(32) }, - { be_const_key_weak(get_pk, 41), be_const_closure(Matter_Session_get_pk_closure) }, - { be_const_key_weak(_Msg2, -1), be_const_var(30) }, - { be_const_key_weak(init, -1), be_const_closure(Matter_Session_init_closure) }, - { be_const_key_weak(get_ac, 29), be_const_closure(Matter_Session_get_ac_closure) }, - { be_const_key_weak(get_ipk_group_key, -1), be_const_closure(Matter_Session_get_ipk_group_key_closure) }, - { be_const_key_weak(session_timestamp, -1), be_const_var(4) }, - { be_const_key_weak(close, -1), be_const_closure(Matter_Session_close_closure) }, - { be_const_key_weak(save, 47), be_const_closure(Matter_Session_save_closure) }, - { be_const_key_weak(_persist, 61), be_const_var(31) }, - { be_const_key_weak(no_private_key, -1), be_const_var(17) }, - { be_const_key_weak(__CASE, -1), be_const_int(2) }, - { be_const_key_weak(_future_initiator_session_id, -1), be_const_var(6) }, - { be_const_key_weak(set_expire_time, -1), be_const_closure(Matter_Session_set_expire_time_closure) }, - { be_const_key_weak(set_ipk_epoch_key, 64), be_const_closure(Matter_Session_set_ipk_epoch_key_closure) }, - { be_const_key_weak(tojson, -1), be_const_closure(Matter_Session_tojson_closure) }, { be_const_key_weak(mode, -1), be_const_var(1) }, - { be_const_key_weak(_Msg1, 28), be_const_var(29) }, - { be_const_key_weak(__store, 15), be_const_var(0) }, - { be_const_key_weak(fabric, -1), be_const_var(24) }, - { be_const_key_weak(get_noc, 54), be_const_closure(Matter_Session_get_noc_closure) }, - { be_const_key_weak(get_icac, -1), be_const_closure(Matter_Session_get_icac_closure) }, - { be_const_key_weak(has_expired, 12), be_const_closure(Matter_Session_has_expired_closure) }, - { be_const_key_weak(get_ca_pub, -1), be_const_closure(Matter_Session_get_ca_pub_closure) }, - { be_const_key_weak(__PASE, -1), be_const_int(1) }, - { be_const_key_weak(initiator_session_id, -1), be_const_var(3) }, - { be_const_key_weak(breadcrumb, -1), be_const_var(16) }, - { be_const_key_weak(_counter_insecure_snd, -1), be_const_var(11) }, - { be_const_key_weak(peer_node_id, -1), be_const_var(15) }, - { be_const_key_weak(set_persist, -1), be_const_closure(Matter_Session_set_persist_closure) }, - { be_const_key_weak(source_node_id, -1), be_const_var(5) }, - { be_const_key_weak(gen_CSR, -1), be_const_closure(Matter_Session_gen_CSR_closure) }, - { be_const_key_weak(get_r2i, -1), be_const_closure(Matter_Session_get_r2i_closure) }, - { be_const_key_weak(noc, -1), be_const_var(19) }, - { be_const_key_weak(counter_snd, 53), be_const_var(9) }, - { be_const_key_weak(_counter_insecure_rcv, -1), be_const_var(10) }, - { be_const_key_weak(set_mode, 60), be_const_closure(Matter_Session_set_mode_closure) }, - { be_const_key_weak(set_noc, -1), be_const_closure(Matter_Session_set_noc_closure) }, - { be_const_key_weak(set_ca, 57), be_const_closure(Matter_Session_set_ca_closure) }, - { be_const_key_weak(__GROUP_KEY, 3), be_nested_str_weak(GroupKey_X20v1_X2E0) }, - { be_const_key_weak(icac, 56), be_const_var(20) }, - { be_const_key_weak(get_ipk_epoch_key, -1), be_const_closure(Matter_Session_get_ipk_epoch_key_closure) }, - { be_const_key_weak(local_session_id, -1), be_const_var(2) }, - { be_const_key_weak(counter_rcv, -1), be_const_var(8) }, - { be_const_key_weak(r2ikey, -1), be_const_var(13) }, - { be_const_key_weak(shared_secret, -1), be_const_var(23) }, - { be_const_key_weak(deviceid, 49), be_const_var(26) }, - { be_const_key_weak(get_fabric_compressed, -1), be_const_closure(Matter_Session_get_fabric_compressed_closure) }, - { be_const_key_weak(set_keys, -1), be_const_closure(Matter_Session_set_keys_closure) }, - { be_const_key_weak(admin_subject, -1), be_const_var(27) }, - { be_const_key_weak(get_fabric, 34), be_const_closure(Matter_Session_get_fabric_closure) }, - { be_const_key_weak(attestation_challenge, 0), be_const_var(14) }, - { be_const_key_weak(set_fabric_device, -1), be_const_closure(Matter_Session_set_fabric_device_closure) }, - { be_const_key_weak(fabric_compressed, 26), be_const_var(25) }, - { be_const_key_weak(get_mode, 21), be_const_closure(Matter_Session_get_mode_closure) }, - { be_const_key_weak(set_no_expiration, -1), be_const_closure(Matter_Session_set_no_expiration_closure) }, + { be_const_key_weak(shared_secret, 45), be_const_var(24) }, + { be_const_key_weak(set_ca, 68), be_const_closure(Matter_Session_set_ca_closure) }, + { be_const_key_weak(has_expired, -1), be_const_closure(Matter_Session_has_expired_closure) }, + { be_const_key_weak(ipk_epoch_key, 2), be_const_var(22) }, + { be_const_key_weak(breadcrumb, 34), be_const_var(17) }, { be_const_key_weak(fromjson, -1), be_const_static_closure(Matter_Session_fromjson_closure) }, - { be_const_key_weak(admin_vendor, -1), be_const_var(28) }, - { be_const_key_weak(_future_local_session_id, 8), be_const_var(7) }, - { be_const_key_weak(set_expire_in_seconds, -1), be_const_closure(Matter_Session_set_expire_in_seconds_closure) }, - { be_const_key_weak(i2rkey, 2), be_const_var(12) }, + { be_const_key_weak(counter_rcv, -1), be_const_var(8) }, + { be_const_key_weak(_Msg1, 6), be_const_var(30) }, + { be_const_key_weak(noc, -1), be_const_var(20) }, + { be_const_key_weak(__PASE, -1), be_const_int(1) }, + { be_const_key_weak(get_deviceid, -1), be_const_closure(Matter_Session_get_deviceid_closure) }, + { be_const_key_weak(_i2r_privacy, 4), be_const_var(14) }, + { be_const_key_weak(counter_snd, -1), be_const_var(9) }, + { be_const_key_weak(set_no_expiration, -1), be_const_closure(Matter_Session_set_no_expiration_closure) }, + { be_const_key_weak(_Msg2, 67), be_const_var(31) }, + { be_const_key_weak(gen_CSR, -1), be_const_closure(Matter_Session_gen_CSR_closure) }, + { be_const_key_weak(set_fabric_device, 18), be_const_closure(Matter_Session_set_fabric_device_closure) }, + { be_const_key_weak(fabric_compressed, -1), be_const_var(26) }, + { be_const_key_weak(get_fabric_compressed, 56), be_const_closure(Matter_Session_get_fabric_compressed_closure) }, + { be_const_key_weak(_counter_insecure_snd, 21), be_const_var(11) }, + { be_const_key_weak(get_noc, 64), be_const_closure(Matter_Session_get_noc_closure) }, + { be_const_key_weak(_future_local_session_id, 11), be_const_var(7) }, + { be_const_key_weak(r2ikey, -1), be_const_var(13) }, + { be_const_key_weak(get_pk, 1), be_const_closure(Matter_Session_get_pk_closure) }, + { be_const_key_weak(set_keys, -1), be_const_closure(Matter_Session_set_keys_closure) }, + { be_const_key_weak(tojson, -1), be_const_closure(Matter_Session_tojson_closure) }, + { be_const_key_weak(set_expire_time, -1), be_const_closure(Matter_Session_set_expire_time_closure) }, + { be_const_key_weak(get_i2r_privacy, -1), be_const_closure(Matter_Session_get_i2r_privacy_closure) }, + { be_const_key_weak(_persist, -1), be_const_var(32) }, + { be_const_key_weak(save, -1), be_const_closure(Matter_Session_save_closure) }, + { be_const_key_weak(root_ca_certificate, -1), be_const_var(19) }, + { be_const_key_weak(set_mode, -1), be_const_closure(Matter_Session_set_mode_closure) }, + { be_const_key_weak(get_r2i, 59), be_const_closure(Matter_Session_get_r2i_closure) }, + { be_const_key_weak(peer_node_id, -1), be_const_var(16) }, + { be_const_key_weak(__store, 23), be_const_var(0) }, + { be_const_key_weak(admin_vendor, -1), be_const_var(29) }, + { be_const_key_weak(set_ipk_epoch_key, -1), be_const_closure(Matter_Session_set_ipk_epoch_key_closure) }, + { be_const_key_weak(set_noc, -1), be_const_closure(Matter_Session_set_noc_closure) }, + { be_const_key_weak(close, -1), be_const_closure(Matter_Session_close_closure) }, + { be_const_key_weak(get_mode, -1), be_const_closure(Matter_Session_get_mode_closure) }, + { be_const_key_weak(get_ca, -1), be_const_closure(Matter_Session_get_ca_closure) }, + { be_const_key_weak(i2rkey, 50), be_const_var(12) }, + { be_const_key_weak(_future_initiator_session_id, 46), be_const_var(6) }, + { be_const_key_weak(get_ac, -1), be_const_closure(Matter_Session_get_ac_closure) }, + { be_const_key_weak(get_ca_pub, 54), be_const_closure(Matter_Session_get_ca_pub_closure) }, + { be_const_key_weak(source_node_id, -1), be_const_var(5) }, + { be_const_key_weak(resumption_id, 43), be_const_var(23) }, + { be_const_key_weak(get_ipk_epoch_key, 0), be_const_closure(Matter_Session_get_ipk_epoch_key_closure) }, + { be_const_key_weak(session_timestamp, 44), be_const_var(4) }, + { be_const_key_weak(icac, 30), be_const_var(21) }, + { be_const_key_weak(initiator_session_id, -1), be_const_var(3) }, + { be_const_key_weak(set_persist, 38), be_const_closure(Matter_Session_set_persist_closure) }, + { be_const_key_weak(__CASE, 36), be_const_int(2) }, + { be_const_key_weak(expiration, -1), be_const_var(33) }, { be_const_key_weak(get_i2r, -1), be_const_closure(Matter_Session_get_i2r_closure) }, + { be_const_key_weak(no_private_key, 28), be_const_var(18) }, + { be_const_key_weak(admin_subject, 25), be_const_var(28) }, + { be_const_key_weak(deviceid, -1), be_const_var(27) }, + { be_const_key_weak(get_icac, 39), be_const_closure(Matter_Session_get_icac_closure) }, + { be_const_key_weak(init, -1), be_const_closure(Matter_Session_init_closure) }, + { be_const_key_weak(fabric, 16), be_const_var(25) }, + { be_const_key_weak(set_expire_in_seconds, -1), be_const_closure(Matter_Session_set_expire_in_seconds_closure) }, + { be_const_key_weak(_counter_insecure_rcv, -1), be_const_var(10) }, + { be_const_key_weak(get_ipk_group_key, -1), be_const_closure(Matter_Session_get_ipk_group_key_closure) }, + { be_const_key_weak(get_fabric, 3), be_const_closure(Matter_Session_get_fabric_closure) }, + { be_const_key_weak(local_session_id, -1), be_const_var(2) }, + { be_const_key_weak(attestation_challenge, -1), be_const_var(15) }, + { be_const_key_weak(__GROUP_KEY, -1), be_nested_str_weak(GroupKey_X20v1_X2E0) }, })), be_str_weak(Matter_Session) ); From 6ccacb4af1c4e93ad63eecb12e176cd57117c952 Mon Sep 17 00:00:00 2001 From: gemu Date: Mon, 6 Feb 2023 09:42:09 +0100 Subject: [PATCH 234/262] Sml fix (#17893) * fix compile with NO_USE_SML_DECRYPT * dumplog info --- tasmota/tasmota_xsns_sensor/xsns_53_sml.ino | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino b/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino index 71e8e1696..b07d9025c 100755 --- a/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino @@ -625,7 +625,7 @@ void dump2log(void) { logsiz = mp->sbsiz; } memmove(mp->sbuff, payload, logsiz); - AddLog(LOG_LEVEL_DEBUG, PSTR("SML: decrypted block: %d bytes"), logsiz); + AddLog(LOG_LEVEL_INFO PSTR("SML: decrypted block: %d bytes"), logsiz); uint16_t index = 0; while (logsiz) { sml_dump_start('>'); @@ -1448,6 +1448,7 @@ uint8_t *sml_find(uint8_t *src, uint16_t ssize, uint8_t *pattern, uint16_t psize return 0; } +#ifdef USE_SML_DECRYPT double sml_get_obis_value(uint8_t *data) { double out = 0; CosemData *item = (CosemData *)data; @@ -1479,7 +1480,7 @@ double sml_get_obis_value(uint8_t *data) { } return out; } - +#endif // USE_SML_DECRYPT @@ -1701,6 +1702,7 @@ void SML_Decode(uint8_t index) { // check auto type if (aflg & 1) { // METER_ID_SIZE +#ifdef USE_SML_DECRYPT CosemData *item = (CosemData *)cp; switch (item->base.type) { case CosemTypeString: @@ -1714,6 +1716,7 @@ void SML_Decode(uint8_t index) { default: ebus_dval = sml_get_obis_value(cp); } +#endif } } break; From 9673cca8b0a6aa9f378a217fad5ebf915725f61e Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 6 Feb 2023 11:45:28 +0100 Subject: [PATCH 235/262] Extent ESP8266 virtual switch support --- tasmota/include/tasmota.h | 1 + tasmota/tasmota_support/support_command.ino | 4 +-- tasmota/tasmota_support/support_switch_v4.ino | 31 +++++++++++-------- tasmota/tasmota_support/support_tasmota.ino | 4 +-- tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino | 4 +-- .../tasmota_xdrv_driver/xdrv_12_discovery.ino | 8 ++--- .../xdrv_12_home_assistant.ino | 12 +++---- .../xdrv_52_3_berry_tasmota.ino | 6 ++-- 8 files changed, 38 insertions(+), 32 deletions(-) diff --git a/tasmota/include/tasmota.h b/tasmota/include/tasmota.h index 2410d0a42..6b60bcb41 100644 --- a/tasmota/include/tasmota.h +++ b/tasmota/include/tasmota.h @@ -57,6 +57,7 @@ const uint8_t MAX_INTERLOCKS = 14; // Max number of interlock groups (u const uint8_t MAX_SWITCHES = 28; // Max number of switches (up to MAX_SWITCHES_SET) const uint8_t MAX_KEYS = 28; // Max number of keys or buttons (up to 28) #endif // ESP32 +const uint8_t MAX_KEYS_SET = 28; // Max number of keys // Changes to the following MAX_ defines will impact settings layout const uint8_t MAX_INTERLOCKS_SET = 14; // Max number of interlock groups (MAX_RELAYS / 2) diff --git a/tasmota/tasmota_support/support_command.ino b/tasmota/tasmota_support/support_command.ino index 5a98f24a8..9bdf91b37 100644 --- a/tasmota/tasmota_support/support_command.ino +++ b/tasmota/tasmota_support/support_command.ino @@ -700,7 +700,7 @@ void CmndStatus(void) snprintf_P(stemp, sizeof(stemp), PSTR("%s%s\"%s\"" ), stemp, (i > 0 ? "," : ""), EscapeJSONString(SettingsText(SET_FRIENDLYNAME1 +i)).c_str()); } stemp2[0] = '\0'; - for (uint32_t i = 0; i < MAX_SWITCHES; i++) { + for (uint32_t i = 0; i < MAX_SWITCHES_SET; i++) { snprintf_P(stemp2, sizeof(stemp2), PSTR("%s%s%d" ), stemp2, (i > 0 ? "," : ""), Settings->switchmode[i]); } Response_P(PSTR("{\"" D_CMND_STATUS "\":{\"" D_CMND_MODULE "\":%d,\"" D_CMND_DEVICENAME "\":\"%s\",\"" D_CMND_FRIENDLYNAME "\":[%s],\"" D_CMND_TOPIC "\":\"%s\",\"" @@ -2137,7 +2137,7 @@ void CmndSwitchText(void) { void CmndSwitchMode(void) { - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_SWITCHES)) { + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_SWITCHES_SET)) { if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < MAX_SWITCH_OPTION)) { Settings->switchmode[XdrvMailbox.index -1] = XdrvMailbox.payload; } diff --git a/tasmota/tasmota_support/support_switch_v4.ino b/tasmota/tasmota_support/support_switch_v4.ino index a4546b66d..81a49f4e4 100644 --- a/tasmota/tasmota_support/support_switch_v4.ino +++ b/tasmota/tasmota_support/support_switch_v4.ino @@ -44,15 +44,15 @@ const char kSwitchPressStates[] PROGMEM = Ticker TickerSwitch; struct SWITCH { - uint32_t debounce = 0; // Switch debounce timer - uint32_t no_pullup_mask = 0; // Switch pull-up bitmask flags - uint32_t pulldown_mask = 0; // Switch pull-down bitmask flags - uint32_t virtual_pin_used = 0; // Switch used bitmask - uint32_t virtual_pin = 0; // Switch state bitmask - uint8_t state[MAX_SWITCHES] = { 0 }; - uint8_t last_state[MAX_SWITCHES]; // Last wall switch states - uint8_t hold_timer[MAX_SWITCHES] = { 0 }; // Timer for wallswitch push button hold - uint8_t debounced_state[MAX_SWITCHES]; // Switch debounced states + uint32_t debounce = 0; // Switch debounce timer + uint32_t no_pullup_mask = 0; // Switch pull-up bitmask flags + uint32_t pulldown_mask = 0; // Switch pull-down bitmask flags + uint32_t virtual_pin_used = 0; // Switch used bitmask + uint32_t virtual_pin = 0; // Switch state bitmask + uint8_t state[MAX_SWITCHES_SET] = { 0 }; + uint8_t last_state[MAX_SWITCHES_SET]; // Last wall switch states + uint8_t hold_timer[MAX_SWITCHES_SET] = { 0 }; // Timer for wallswitch push button hold + uint8_t debounced_state[MAX_SWITCHES_SET]; // Switch debounced states uint8_t first_change = 0; uint8_t present = 0; bool probe_mutex; @@ -68,6 +68,10 @@ void SwitchPulldownFlag(uint32 switch_bit) { bitSet(Switch.pulldown_mask, switch_bit); } +bool SwitchUsed(uint32_t index) { + return (PinUsed(GPIO_SWT1, index) || bitRead(Switch.virtual_pin_used, index)); +} + // Preffered virtual switch support since v12.3.1.4 void SwitchSetVirtualPinState(uint32_t index, uint32_t state) { bitWrite(Switch.virtual_pin, index, state); @@ -127,7 +131,7 @@ void SwitchProbe(void) { } uint32_t not_activated; - for (uint32_t i = 0; i < MAX_SWITCHES; i++) { + for (uint32_t i = 0; i < MAX_SWITCHES_SET; i++) { if (PinUsed(GPIO_SWT1, i)) { not_activated = digitalRead(Pin(GPIO_SWT1, i)); } @@ -220,7 +224,7 @@ void SwitchInit(void) { Switch.present = 0; Switch.virtual_pin_used = 0; - for (uint32_t i = 0; i < MAX_SWITCHES; i++) { + for (uint32_t i = 0; i < MAX_SWITCHES_SET; i++) { Switch.last_state[i] = NOT_PRESSED; // Init global to virtual switch state; bool used = false; @@ -280,8 +284,9 @@ void SwitchHandler(uint32_t mode) { uint32_t loops_per_second = 1000 / Settings->switch_debounce; - for (uint32_t i = 0; i < MAX_SWITCHES; i++) { - if (PinUsed(GPIO_SWT1, i) || bitRead(Switch.virtual_pin_used, i)) { + for (uint32_t i = 0; i < MAX_SWITCHES_SET; i++) { +// if (PinUsed(GPIO_SWT1, i) || bitRead(Switch.virtual_pin_used, i)) { + if (SwitchUsed(i)) { uint32_t button = Switch.debounced_state[i]; uint32_t switchflag = POWER_TOGGLE +1; uint32_t mqtt_action = POWER_NONE; diff --git a/tasmota/tasmota_support/support_tasmota.ino b/tasmota/tasmota_support/support_tasmota.ino index 0e8f7f7fd..54ecd4a29 100644 --- a/tasmota/tasmota_support/support_tasmota.ino +++ b/tasmota/tasmota_support/support_tasmota.ino @@ -962,11 +962,11 @@ bool MqttShowSensor(bool call_show_sensor) { ResponseAppendTime(); int json_data_start = ResponseLength(); - for (uint32_t i = 0; i < MAX_SWITCHES; i++) { + for (uint32_t i = 0; i < MAX_SWITCHES_SET; i++) { #ifdef USE_TM1638 if (PinUsed(GPIO_SWT1, i) || (PinUsed(GPIO_TM1638CLK) && PinUsed(GPIO_TM1638DIO) && PinUsed(GPIO_TM1638STB))) { #else - if (PinUsed(GPIO_SWT1, i)) { + if (SwitchUsed(i)) { #endif // USE_TM1638 ResponseAppend_P(PSTR(",\"%s\":\"%s\""), GetSwitchText(i).c_str(), GetStateText(SwitchState(i))); } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino b/tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino index 0454646a0..6ad3cc646 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino @@ -964,11 +964,11 @@ void RulesEvery50ms(void) RulesProcessEvent(json_event); } // Boot time SWITCHES Status - for (uint32_t i = 0; i < MAX_SWITCHES; i++) { + for (uint32_t i = 0; i < MAX_SWITCHES_SET; i++) { #ifdef USE_TM1638 if (PinUsed(GPIO_SWT1, i) || (PinUsed(GPIO_TM1638CLK) && PinUsed(GPIO_TM1638DIO) && PinUsed(GPIO_TM1638STB))) { #else - if (PinUsed(GPIO_SWT1, i)) { + if (SwitchUsed(i)) { #endif // USE_TM1638 snprintf_P(json_event, sizeof(json_event), PSTR("{\"%s\":{\"Boot\":%d}}"), GetSwitchText(i).c_str(), (SwitchState(i))); RulesProcessEvent(json_event); diff --git a/tasmota/tasmota_xdrv_driver/xdrv_12_discovery.ino b/tasmota/tasmota_xdrv_driver/xdrv_12_discovery.ino index a7cbe6c6e..9d58aaae5 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_12_discovery.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_12_discovery.ino @@ -144,18 +144,18 @@ void TasDiscoverMessage(void) { "\"swc\":[")); // Switch modes (start) // Enable Discovery for Switches only if SetOption114 is enabled - for (uint32_t i = 0; i < MAX_SWITCHES; i++) { - ResponseAppend_P(PSTR("%s%d"), (i > 0 ? "," : ""), (PinUsed(GPIO_SWT1, i) && Settings->flag5.mqtt_switches) ? Settings->switchmode[i] : -1); + for (uint32_t i = 0; i < MAX_SWITCHES_SET; i++) { + ResponseAppend_P(PSTR("%s%d"), (i > 0 ? "," : ""), (SwitchUsed(i) && Settings->flag5.mqtt_switches) ? Settings->switchmode[i] : -1); } ResponseAppend_P(PSTR("]," // Switch modes (end) "\"swn\":[")); // Switch names (start) // Enable Discovery for Switches only if SetOption114 is enabled - for (uint32_t i = 0; i < MAX_SWITCHES; i++) { + for (uint32_t i = 0; i < MAX_SWITCHES_SET; i++) { char sname[TOPSZ]; snprintf_P(sname, sizeof(sname), PSTR("\"%s\""), GetSwitchText(i).c_str()); - ResponseAppend_P(PSTR("%s%s"), (i > 0 ? "," : ""), (PinUsed(GPIO_SWT1, i) && Settings->flag5.mqtt_switches) ? sname : PSTR("null")); + ResponseAppend_P(PSTR("%s%s"), (i > 0 ? "," : ""), (SwitchUsed(i) && Settings->flag5.mqtt_switches) ? sname : PSTR("null")); } ResponseAppend_P(PSTR("]," // Switch names (end) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_12_home_assistant.ino b/tasmota/tasmota_xdrv_driver/xdrv_12_home_assistant.ino index 531d8463e..998715498 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_12_home_assistant.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_12_home_assistant.ino @@ -338,18 +338,18 @@ void HassDiscoverMessage(void) { "\"swc\":[")); // Switch modes (start) // Enable Discovery for Switches only if SetOption114 is enabled - for (uint32_t i = 0; i < MAX_SWITCHES; i++) { - ResponseAppend_P(PSTR("%s%d"), (i > 0 ? "," : ""), (PinUsed(GPIO_SWT1, i) && Settings->flag5.mqtt_switches) ? Settings->switchmode[i] : -1); + for (uint32_t i = 0; i < MAX_SWITCHES_SET; i++) { + ResponseAppend_P(PSTR("%s%d"), (i > 0 ? "," : ""), (SwitchUsed(i) && Settings->flag5.mqtt_switches) ? Settings->switchmode[i] : -1); } ResponseAppend_P(PSTR("]," // Switch modes (end) "\"swn\":[")); // Switch names (start) // Enable Discovery for Switches only if SetOption114 is enabled - for (uint32_t i = 0; i < MAX_SWITCHES; i++) { + for (uint32_t i = 0; i < MAX_SWITCHES_SET; i++) { char sname[TOPSZ]; snprintf_P(sname, sizeof(sname), PSTR("\"%s\""), GetSwitchText(i).c_str()); - ResponseAppend_P(PSTR("%s%s"), (i > 0 ? "," : ""), (PinUsed(GPIO_SWT1, i) && Settings->flag5.mqtt_switches) ? sname : PSTR("null")); + ResponseAppend_P(PSTR("%s%s"), (i > 0 ? "," : ""), (SwitchUsed(i) && Settings->flag5.mqtt_switches) ? sname : PSTR("null")); } ResponseAppend_P(PSTR("]," // Switch names (end) @@ -790,7 +790,7 @@ void HAssAnnouncerBinSensors(uint8_t device, uint8_t present, uint8_t dual, uint void HAssAnnounceSwitches(void) { - for (uint32_t switch_index = 0; switch_index < MAX_SWITCHES; switch_index++) + for (uint32_t switch_index = 0; switch_index < MAX_SWITCHES_SET; switch_index++) { uint8_t switch_present = 0; uint8_t dual = 0; @@ -798,7 +798,7 @@ void HAssAnnounceSwitches(void) uint8_t hold = 0; uint8_t pir = 0; - if (PinUsed(GPIO_SWT1, switch_index)) { switch_present = 1; } + if (SwitchUsed(switch_index)) { switch_present = 1; } if (KeyTopicActive(1) && strcmp(SettingsText(SET_MQTT_SWITCH_TOPIC), TasmotaGlobal.mqtt_topic)) // Enable Discovery for Switches only if SwitchTopic is set to a custom name { diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota.ino index 5bb9488bc..0f7deff83 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota.ino @@ -157,7 +157,7 @@ extern "C" { } be_raise(vm, kTypeError, nullptr); } - + // Berry: tasmota.locale() -> string // int32_t l_locale(struct bvm *vm); @@ -586,8 +586,8 @@ extern "C" { int32_t l_getswitch(bvm *vm); int32_t l_getswitch(bvm *vm) { be_newobject(vm, "list"); - for (uint32_t i = 0; i < MAX_SWITCHES; i++) { - if (PinUsed(GPIO_SWT1, i)) { + for (uint32_t i = 0; i < MAX_SWITCHES_SET; i++) { + if (SwitchUsed(i)) { be_pushbool(vm, SwitchGetVirtual(i) == PRESSED); be_data_push(vm, -2); be_pop(vm, 1); From ce29bc38d753c3070479ea4897238c3a4c9f1a86 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 6 Feb 2023 12:03:32 +0100 Subject: [PATCH 236/262] Extent ESP8266 virtual button support --- tasmota/tasmota_support/support_button_v4.ino | 47 ++++++++++--------- .../tasmota_xdrv_driver/xdrv_10_scripter.ino | 6 +-- .../tasmota_xdrv_driver/xdrv_12_discovery.ino | 4 +- .../xdrv_12_home_assistant.ino | 8 ++-- 4 files changed, 34 insertions(+), 31 deletions(-) diff --git a/tasmota/tasmota_support/support_button_v4.ino b/tasmota/tasmota_support/support_button_v4.ino index 3b1ce159f..c86bda264 100644 --- a/tasmota/tasmota_support/support_button_v4.ino +++ b/tasmota/tasmota_support/support_button_v4.ino @@ -40,30 +40,30 @@ const char kMultiPress[] PROGMEM = "|SINGLE|DOUBLE|TRIPLE|QUAD|PENTA|CLEAR|"; Ticker TickerButton; struct BUTTON { - uint32_t debounce = 0; // Button debounce timer - uint32_t no_pullup_mask = 0; // key no pullup flag (1 = no pullup) - uint32_t pulldown_mask = 0; // key pulldown flag (1 = pulldown) - uint32_t inverted_mask = 0; // Key inverted flag (1 = inverted) - uint32_t virtual_pin_used = 0; // Key used bitmask - uint32_t virtual_pin = 0; // Key state bitmask - uint16_t hold_timer[MAX_KEYS] = { 0 }; // Timer for button hold - uint16_t dual_code = 0; // Sonoff dual received code - uint8_t state[MAX_KEYS] = { 0 }; - uint8_t last_state[MAX_KEYS]; // Last button states - uint8_t debounced_state[MAX_KEYS]; // Button debounced states - uint8_t window_timer[MAX_KEYS] = { 0 }; // Max time between button presses to record press count - uint8_t press_counter[MAX_KEYS] = { 0 }; // Number of button presses within Button.window_timer - uint8_t dual_receive_count = 0; // Sonoff dual input flag + uint32_t debounce = 0; // Button debounce timer + uint32_t no_pullup_mask = 0; // key no pullup flag (1 = no pullup) + uint32_t pulldown_mask = 0; // key pulldown flag (1 = pulldown) + uint32_t inverted_mask = 0; // Key inverted flag (1 = inverted) + uint32_t virtual_pin_used = 0; // Key used bitmask + uint32_t virtual_pin = 0; // Key state bitmask + uint16_t hold_timer[MAX_KEYS_SET] = { 0 }; // Timer for button hold + uint16_t dual_code = 0; // Sonoff dual received code + uint8_t state[MAX_KEYS_SET] = { 0 }; + uint8_t last_state[MAX_KEYS_SET]; // Last button states + uint8_t debounced_state[MAX_KEYS_SET]; // Button debounced states + uint8_t window_timer[MAX_KEYS_SET] = { 0 }; // Max time between button presses to record press count + uint8_t press_counter[MAX_KEYS_SET] = { 0 }; // Number of button presses within Button.window_timer + uint8_t dual_receive_count = 0; // Sonoff dual input flag uint8_t first_change = 0; - uint8_t present = 0; // Number of buttons found flag + uint8_t present = 0; // Number of buttons found flag bool probe_mutex; } Button; #if defined(SOC_TOUCH_VERSION_1) || defined(SOC_TOUCH_VERSION_2) struct TOUCH_BUTTON { - uint32_t touch_mask = 0; // Touch flag (1 = enabled) - uint32_t calibration = 0; // Bitfield - uint8_t hits[MAX_KEYS] = { 0 }; // Hits in a row to filter out noise + uint32_t touch_mask = 0; // Touch flag (1 = enabled) + uint32_t calibration = 0; // Bitfield + uint8_t hits[MAX_KEYS_SET] = { 0 }; // Hits in a row to filter out noise } TouchButton; #endif // ESP32 SOC_TOUCH_VERSION_1 or SOC_TOUCH_VERSION_2 @@ -87,6 +87,9 @@ void ButtonTouchFlag(uint32_t button_bit) { } #endif // ESP32 SOC_TOUCH_VERSION_1 or SOC_TOUCH_VERSION_2 +bool ButtonUsed(uint32_t index) { + return (PinUsed(GPIO_KEY1, index) || bitRead(Button.virtual_pin_used, index)); +} void ButtonSetVirtualPinState(uint32_t index, uint32_t state) { bitWrite(Button.virtual_pin, index, state); @@ -118,7 +121,7 @@ void ButtonProbe(void) { } uint32_t not_activated; - for (uint32_t i = 0; i < MAX_KEYS; i++) { + for (uint32_t i = 0; i < MAX_KEYS_SET; i++) { if (PinUsed(GPIO_KEY1, i)) { #if defined(SOC_TOUCH_VERSION_1) || defined(SOC_TOUCH_VERSION_2) if (bitRead(TouchButton.touch_mask, i)) { @@ -227,7 +230,7 @@ void ButtonInit(void) { } #endif // ESP8266 - for (uint32_t i = 0; i < MAX_KEYS; i++) { + for (uint32_t i = 0; i < MAX_KEYS_SET; i++) { Button.last_state[i] = NOT_PRESSED; bool used = false; @@ -327,7 +330,7 @@ void ButtonHandler(void) { uint16_t loops_per_second = 1000 / Settings->button_debounce; // ButtonDebounce (50) char scmnd[20]; - for (uint32_t button_index = 0; button_index < MAX_KEYS; button_index++) { + for (uint32_t button_index = 0; button_index < MAX_KEYS_SET; button_index++) { uint8_t button = NOT_PRESSED; uint8_t button_present = 0; @@ -584,4 +587,4 @@ void ButtonLoop(void) { } } -#endif // BUTTON_V3 +#endif // BUTTON_V4 diff --git a/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino b/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino index f9faa90fb..314aab45b 100755 --- a/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino @@ -484,7 +484,7 @@ struct SCRIPT_MEM { uint32_t script_lastmillis; bool event_handeled = false; #ifdef USE_BUTTON_EVENT - int8_t script_button[MAX_KEYS]; + int8_t script_button[MAX_KEYS_SET]; #endif //USE_BUTTON_EVENT #ifdef USE_HOMEKIT @@ -2731,7 +2731,7 @@ chknext: // tasmota button state lp = GetNumericArgument(lp + 3, OPER_EQU, &fvar, gv); uint32_t index = fvar; - if (index<1 || index>MAX_KEYS) index = 1; + if (index<1 || index>MAX_KEYS_SET) index = 1; fvar = glob_script_mem.script_button[index - 1]; glob_script_mem.script_button[index - 1] |= 0x80; goto nfuncexit; @@ -11688,7 +11688,7 @@ bool Xdrv10(uint32_t function) bitWrite(Settings->rule_once, 7, 1); #ifdef USE_BUTTON_EVENT - for (uint32_t cnt = 0; cnt < MAX_KEYS; cnt++) { + for (uint32_t cnt = 0; cnt < MAX_KEYS_SET; cnt++) { glob_script_mem.script_button[cnt] = -1; } #endif //USE_BUTTON_EVENT diff --git a/tasmota/tasmota_xdrv_driver/xdrv_12_discovery.ino b/tasmota/tasmota_xdrv_driver/xdrv_12_discovery.ino index 9d58aaae5..d0486f2a8 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_12_discovery.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_12_discovery.ino @@ -163,11 +163,11 @@ void TasDiscoverMessage(void) { bool SerialButton = false; // Enable Discovery for Buttons only if SetOption73 is enabled - for (uint32_t i = 0; i < MAX_KEYS; i++) { + for (uint32_t i = 0; i < MAX_KEYS_SET; i++) { #ifdef ESP8266 SerialButton = ((0 == i) && (SONOFF_DUAL == TasmotaGlobal.module_type )); #endif // ESP8266 - ResponseAppend_P(PSTR("%s%d"), (i > 0 ? "," : ""), (SerialButton ? 1 : (PinUsed(GPIO_KEY1, i)) && Settings->flag3.mqtt_buttons)); + ResponseAppend_P(PSTR("%s%d"), (i > 0 ? "," : ""), (SerialButton ? 1 : (ButtonUsed(i)) && Settings->flag3.mqtt_buttons)); } ResponseAppend_P(PSTR("]," // Button flag (end) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_12_home_assistant.ino b/tasmota/tasmota_xdrv_driver/xdrv_12_home_assistant.ino index 998715498..5cc138881 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_12_home_assistant.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_12_home_assistant.ino @@ -357,11 +357,11 @@ void HassDiscoverMessage(void) { bool SerialButton = false; // Enable Discovery for Buttons only if SetOption73 is enabled - for (uint32_t i = 0; i < MAX_KEYS; i++) { + for (uint32_t i = 0; i < MAX_KEYS_SET; i++) { #ifdef ESP8266 SerialButton = ((0 == i) && (SONOFF_DUAL == TasmotaGlobal.module_type )); #endif // ESP8266 - ResponseAppend_P(PSTR("%s%d"), (i > 0 ? "," : ""), (SerialButton ? 1 : (PinUsed(GPIO_KEY1, i)) && Settings->flag3.mqtt_buttons)); + ResponseAppend_P(PSTR("%s%d"), (i > 0 ? "," : ""), (SerialButton ? 1 : (ButtonUsed(i)) && Settings->flag3.mqtt_buttons)); } ResponseAppend_P(PSTR("]," // Button flag (end) @@ -866,7 +866,7 @@ void HAssAnnounceSwitches(void) void HAssAnnounceButtons(void) { - for (uint32_t button_index = 0; button_index < MAX_KEYS; button_index++) + for (uint32_t button_index = 0; button_index < MAX_KEYS_SET; button_index++) { uint8_t button_present = 0; uint8_t single = 0; @@ -878,7 +878,7 @@ void HAssAnnounceButtons(void) } else #endif // ESP8266 { - if (PinUsed(GPIO_KEY1, button_index)) { + if (ButtonUsed(button_index)) { button_present = 1; } } From 055331d2ab1a1aedaab4f4385ffbed9cadd39b40 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 6 Feb 2023 15:57:27 +0100 Subject: [PATCH 237/262] Breaking change TM1638 button and led support Breaking change TM1638 button and led support are handled as virtual switches and relays (#11031) --- CHANGELOG.md | 1 + RELEASENOTES.md | 1 + tasmota/tasmota_support/support_features.ino | 2 +- tasmota/tasmota_support/support_tasmota.ino | 4 - tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino | 4 - .../tasmota_xdrv_driver/xdrv_66_tm1638.ino | 269 ++++++++++++++++++ .../tasmota_xsns_sensor/xsns_28_tm1638.ino | 228 --------------- 7 files changed, 272 insertions(+), 237 deletions(-) create mode 100644 tasmota/tasmota_xdrv_driver/xdrv_66_tm1638.ino delete mode 100644 tasmota/tasmota_xsns_sensor/xsns_28_tm1638.ino diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d791e597..c6f83fd81 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ All notable changes to this project will be documented in this file. - Basic support for Shelly Pro 4PM ### Breaking Changed +- TM1638 button and led support are handled as virtual switches and relays (#11031) ### Changed diff --git a/RELEASENOTES.md b/RELEASENOTES.md index d78f13e59..f73949263 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -134,6 +134,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm - ESP32 preliminary support for Matter protocol, milestone 1 (commissioning) by Stephan Hadinger ### Breaking Changed +- TM1638 button and led support are handled as virtual switches and relays [#11031](https://github.com/arendst/Tasmota/issues/11031) ### Changed - ESP32 Framework (Core) from v2.0.5.3 to v2.0.6 (IPv6 support) diff --git a/tasmota/tasmota_support/support_features.ino b/tasmota/tasmota_support/support_features.ino index bae2916b3..c576f5d07 100644 --- a/tasmota/tasmota_support/support_features.ino +++ b/tasmota/tasmota_support/support_features.ino @@ -319,7 +319,7 @@ void ResponseAppendFeatures(void) feature3 |= 0x40000000; // xsns_27_apds9960.ino #endif #ifdef USE_TM1638 - feature3 |= 0x80000000; // xsns_28_tm1638.ino + feature3 |= 0x80000000; // xdrv_66_tm1638.ino #endif } diff --git a/tasmota/tasmota_support/support_tasmota.ino b/tasmota/tasmota_support/support_tasmota.ino index 54ecd4a29..416ee8c0e 100644 --- a/tasmota/tasmota_support/support_tasmota.ino +++ b/tasmota/tasmota_support/support_tasmota.ino @@ -963,11 +963,7 @@ bool MqttShowSensor(bool call_show_sensor) { int json_data_start = ResponseLength(); for (uint32_t i = 0; i < MAX_SWITCHES_SET; i++) { -#ifdef USE_TM1638 - if (PinUsed(GPIO_SWT1, i) || (PinUsed(GPIO_TM1638CLK) && PinUsed(GPIO_TM1638DIO) && PinUsed(GPIO_TM1638STB))) { -#else if (SwitchUsed(i)) { -#endif // USE_TM1638 ResponseAppend_P(PSTR(",\"%s\":\"%s\""), GetSwitchText(i).c_str(), GetStateText(SwitchState(i))); } } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino b/tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino index 6ad3cc646..d8ad9eed2 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino @@ -965,11 +965,7 @@ void RulesEvery50ms(void) } // Boot time SWITCHES Status for (uint32_t i = 0; i < MAX_SWITCHES_SET; i++) { -#ifdef USE_TM1638 - if (PinUsed(GPIO_SWT1, i) || (PinUsed(GPIO_TM1638CLK) && PinUsed(GPIO_TM1638DIO) && PinUsed(GPIO_TM1638STB))) { -#else if (SwitchUsed(i)) { -#endif // USE_TM1638 snprintf_P(json_event, sizeof(json_event), PSTR("{\"%s\":{\"Boot\":%d}}"), GetSwitchText(i).c_str(), (SwitchState(i))); RulesProcessEvent(json_event); } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_66_tm1638.ino b/tasmota/tasmota_xdrv_driver/xdrv_66_tm1638.ino new file mode 100644 index 000000000..145122472 --- /dev/null +++ b/tasmota/tasmota_xdrv_driver/xdrv_66_tm1638.ino @@ -0,0 +1,269 @@ +/* + xdrv_66_tm1638.ino - TM1638 8 switch, led and 7 segment unit support for Tasmota + + Copyright (C) 2021 Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifdef USE_TM1638 +/*********************************************************************************************\ + * TM1638 8 switch, led and 7 segment + * + * Uses GPIO TM1638 DIO, TM1638 CLK and TM1638 STB +\*********************************************************************************************/ + +#define XDRV_66 66 + +#ifdef TM1638_USE_AS_BUTTON +#define TM1638_USE_BUTTONS // Use keys as buttons +#endif +#ifdef TM1638_USE_AS_SWITCH +#undef TM1638_USE_BUTTONS // Use keys as switches +#endif +#ifndef TM1638_MAX_DISPLAYS +#define TM1638_MAX_DISPLAYS 8 +#endif +#ifndef TM1638_MAX_KEYS +#define TM1638_MAX_KEYS 8 +#endif +#ifndef TM1638_MAX_LEDS +#define TM1638_MAX_LEDS 8 +#endif + +#define TM1638_COLOR_NONE 0 +#define TM1638_COLOR_RED 1 +#define TM1638_COLOR_GREEN 2 + +#define TM1638_CLOCK_DELAY 1 // uSec + +struct TM1638 { + int8_t clock_pin = 0; + int8_t data_pin = 0; + int8_t strobe_pin = 0; + int8_t key_offset; + int8_t led_offset; + uint8_t displays; + uint8_t power; + + uint8_t active_display = 1; + uint8_t intensity = 0; + bool detected = false; +} Tm1638; + +/*********************************************************************************************\ + * Pieces from library https://github.com/rjbatista/tm1638-library + * and from library https://github.com/MartyMacGyver/TM1638-demos-and-examples +\*********************************************************************************************/ + +void Tm16XXSend(uint8_t data) { + for (uint32_t i = 0; i < 8; i++) { + digitalWrite(Tm1638.data_pin, !!(data & (1 << i))); + digitalWrite(Tm1638.clock_pin, LOW); + delayMicroseconds(TM1638_CLOCK_DELAY); + digitalWrite(Tm1638.clock_pin, HIGH); + } +} + +void Tm16XXSendCommand(uint8_t cmd) { + digitalWrite(Tm1638.strobe_pin, LOW); + Tm16XXSend(cmd); + digitalWrite(Tm1638.strobe_pin, HIGH); +} + +void TM16XXSendData(uint8_t address, uint8_t data) { + Tm16XXSendCommand(0x44); + digitalWrite(Tm1638.strobe_pin, LOW); + Tm16XXSend(0xC0 | address); + Tm16XXSend(data); + digitalWrite(Tm1638.strobe_pin, HIGH); +} + +uint8_t Tm16XXReceive(void) { + uint8_t temp = 0; + + // Pull-up on + pinMode(Tm1638.data_pin, INPUT); + digitalWrite(Tm1638.data_pin, HIGH); + + for (uint32_t i = 0; i < 8; ++i) { + digitalWrite(Tm1638.clock_pin, LOW); + delayMicroseconds(TM1638_CLOCK_DELAY); + temp |= digitalRead(Tm1638.data_pin) << i; + digitalWrite(Tm1638.clock_pin, HIGH); + } + + // Pull-up off + pinMode(Tm1638.data_pin, OUTPUT); + digitalWrite(Tm1638.data_pin, LOW); + + return temp; +} + +/*********************************************************************************************/ + +void Tm16XXClearDisplay(void) { + for (uint32_t i = 0; i < Tm1638.displays; i++) { + TM16XXSendData(i << 1, 0); + } +} + +void Tm1638SetLED(uint8_t color, uint8_t pos) { + TM16XXSendData((pos << 1) + 1, color); +} + +void Tm1638SetLEDs(word leds) { + for (uint32_t i = 0; i < Tm1638.displays; i++) { + uint8_t color = 0; + + if ((leds & (1 << i)) != 0) { + color |= TM1638_COLOR_RED; + } + + if ((leds & (1 << (i + 8))) != 0) { + color |= TM1638_COLOR_GREEN; + } + + Tm1638SetLED(color, i); + } +} + +uint8_t Tm1638GetButtons(void) { + uint8_t keys = 0; + + digitalWrite(Tm1638.strobe_pin, LOW); + Tm16XXSend(0x42); + for (uint32_t i = 0; i < 4; i++) { + keys |= Tm16XXReceive() << i; + } + digitalWrite(Tm1638.strobe_pin, HIGH); + + return keys; +} + +/*********************************************************************************************/ + +void TmInit(void) { + if (PinUsed(GPIO_TM1638CLK) && PinUsed(GPIO_TM1638DIO) && PinUsed(GPIO_TM1638STB)) { + Tm1638.clock_pin = Pin(GPIO_TM1638CLK); + Tm1638.data_pin = Pin(GPIO_TM1638DIO); + Tm1638.strobe_pin = Pin(GPIO_TM1638STB); + + pinMode(Tm1638.data_pin, OUTPUT); + pinMode(Tm1638.clock_pin, OUTPUT); + pinMode(Tm1638.strobe_pin, OUTPUT); + + digitalWrite(Tm1638.strobe_pin, HIGH); + digitalWrite(Tm1638.clock_pin, HIGH); + + Tm16XXSendCommand(0x40); + Tm16XXSendCommand(0x80 | (Tm1638.active_display ? 8 : 0) | tmin(7, Tm1638.intensity)); + + digitalWrite(Tm1638.strobe_pin, LOW); + Tm16XXSend(0xC0); + for (uint32_t i = 0; i < 16; i++) { + Tm16XXSend(0x00); + } + digitalWrite(Tm1638.strobe_pin, HIGH); + + // Dirty hack to offset TM1638 leds from GPIO relays + // At this time in code sequence the number of GPIO relays has not been established + uint32_t bi_device = 0; + uint32_t devices_present = 0; + for (uint32_t i = 0; i < MAX_RELAYS; i++) { + if (PinUsed(GPIO_REL1, i)) { + devices_present++; + if (bitRead(TasmotaGlobal.rel_bistable, i)) { + if (bi_device &1) { devices_present--; } + bi_device++; + } + } + } + + Tm1638.led_offset = devices_present; + TasmotaGlobal.devices_present += TM1638_MAX_LEDS; + Tm1638.key_offset = -1; + Tm1638.displays = TM1638_MAX_DISPLAYS; + Tm1638.detected = true; + } +} + +void TmLoop(void) { + uint8_t buttons = Tm1638GetButtons(); + for (uint32_t i = 0; i < TM1638_MAX_KEYS; i++) { + uint32_t state = buttons &1; +#ifdef TM1638_USE_BUTTONS + ButtonSetVirtualPinState(Tm1638.key_offset +i, state); +#else + SwitchSetVirtualPinState(Tm1638.key_offset +i, state ^1); +#endif + buttons >>= 1; + } +} + +void TmPower(void) { + power_t rpower = XdrvMailbox.index >> Tm1638.led_offset; + for (uint32_t i = 0; i < TM1638_MAX_LEDS; i++) { + uint32_t state = rpower &1; + uint8_t color = (state) ? TM1638_COLOR_RED : TM1638_COLOR_NONE; + Tm1638SetLED(color, i); + rpower >>= 1; // Select next power + } +} + +bool TmAddKey(void) { + // XdrvMailbox.index = button/switch index + if (Tm1638.key_offset < 0) { Tm1638.key_offset = XdrvMailbox.index; } + uint32_t index = XdrvMailbox.index - Tm1638.key_offset; + if (index >= TM1638_MAX_KEYS) { return false; } + uint8_t buttons = Tm1638GetButtons(); + uint32_t state = bitRead(buttons, index); +#ifdef TM1638_USE_BUTTONS + XdrvMailbox.index = state | BUTTON_INVERT; // Invert - default is 0 +#else + XdrvMailbox.index = state ^1; // Invert - default is 0 +#endif + return true; +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xdrv66(uint32_t function) { + bool result = false; + + if (FUNC_MODULE_INIT == function) { + TmInit(); + } else if (Tm1638.detected) { + switch (function) { + case FUNC_EVERY_50_MSECOND: + TmLoop(); + break; + case FUNC_SET_POWER: + TmPower(); + break; +#ifdef TM1638_USE_BUTTONS + case FUNC_ADD_BUTTON: +#else + case FUNC_ADD_SWITCH: +#endif + result = TmAddKey(); + break; + } + } + return result; +} + +#endif // USE_TM1638 \ No newline at end of file diff --git a/tasmota/tasmota_xsns_sensor/xsns_28_tm1638.ino b/tasmota/tasmota_xsns_sensor/xsns_28_tm1638.ino deleted file mode 100644 index 8a0cdb8f8..000000000 --- a/tasmota/tasmota_xsns_sensor/xsns_28_tm1638.ino +++ /dev/null @@ -1,228 +0,0 @@ -/* - xsns_28_tm1638.ino - TM1638 8 switch, led and 7 segment unit support for Tasmota - - Copyright (C) 2021 Theo Arends - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#ifdef USE_TM1638 -/*********************************************************************************************\ - * TM1638 8 switch, led and 7 segment - * - * Uses GPIO TM1638 DIO, TM1638 CLK and TM1638 STB -\*********************************************************************************************/ - -#define XSNS_28 28 - -#define TM1638_COLOR_NONE 0 -#define TM1638_COLOR_RED 1 -#define TM1638_COLOR_GREEN 2 - -#define TM1638_CLOCK_DELAY 1 // uSec - -uint8_t tm1638_type = 1; -int8_t tm1638_clock_pin = 0; -int8_t tm1638_data_pin = 0; -int8_t tm1638_strobe_pin = 0; -uint8_t tm1638_displays = 8; -uint8_t tm1638_active_display = 1; -uint8_t tm1638_intensity = 0; -uint8_t tm1638_state = 0; - -/*********************************************************************************************\ - * Pieces from library https://github.com/rjbatista/tm1638-library - * and from library https://github.com/MartyMacGyver/TM1638-demos-and-examples -\*********************************************************************************************/ - -void Tm16XXSend(uint8_t data) -{ - for (uint32_t i = 0; i < 8; i++) { - digitalWrite(tm1638_data_pin, !!(data & (1 << i))); - digitalWrite(tm1638_clock_pin, LOW); - delayMicroseconds(TM1638_CLOCK_DELAY); - digitalWrite(tm1638_clock_pin, HIGH); - } -} - -void Tm16XXSendCommand(uint8_t cmd) -{ - digitalWrite(tm1638_strobe_pin, LOW); - Tm16XXSend(cmd); - digitalWrite(tm1638_strobe_pin, HIGH); -} - -void TM16XXSendData(uint8_t address, uint8_t data) -{ - Tm16XXSendCommand(0x44); - digitalWrite(tm1638_strobe_pin, LOW); - Tm16XXSend(0xC0 | address); - Tm16XXSend(data); - digitalWrite(tm1638_strobe_pin, HIGH); -} - -uint8_t Tm16XXReceive(void) -{ - uint8_t temp = 0; - - // Pull-up on - pinMode(tm1638_data_pin, INPUT); - digitalWrite(tm1638_data_pin, HIGH); - - for (uint32_t i = 0; i < 8; ++i) { - digitalWrite(tm1638_clock_pin, LOW); - delayMicroseconds(TM1638_CLOCK_DELAY); - temp |= digitalRead(tm1638_data_pin) << i; - digitalWrite(tm1638_clock_pin, HIGH); - } - - // Pull-up off - pinMode(tm1638_data_pin, OUTPUT); - digitalWrite(tm1638_data_pin, LOW); - - return temp; -} - -/*********************************************************************************************/ - -void Tm16XXClearDisplay(void) -{ - for (uint32_t i = 0; i < tm1638_displays; i++) { - TM16XXSendData(i << 1, 0); - } -} - -void Tm1638SetLED(uint8_t color, uint8_t pos) -{ - TM16XXSendData((pos << 1) + 1, color); -} - -void Tm1638SetLEDs(word leds) -{ - for (uint32_t i = 0; i < tm1638_displays; i++) { - uint8_t color = 0; - - if ((leds & (1 << i)) != 0) { - color |= TM1638_COLOR_RED; - } - - if ((leds & (1 << (i + 8))) != 0) { - color |= TM1638_COLOR_GREEN; - } - - Tm1638SetLED(color, i); - } -} - -uint8_t Tm1638GetButtons(void) -{ - uint8_t keys = 0; - - digitalWrite(tm1638_strobe_pin, LOW); - Tm16XXSend(0x42); - for (uint32_t i = 0; i < 4; i++) { - keys |= Tm16XXReceive() << i; - } - digitalWrite(tm1638_strobe_pin, HIGH); - - return keys; -} - -/*********************************************************************************************/ - -void TmInit(void) -{ - tm1638_type = 0; - if (PinUsed(GPIO_TM1638CLK) && PinUsed(GPIO_TM1638DIO) && PinUsed(GPIO_TM1638STB)) { - tm1638_clock_pin = Pin(GPIO_TM1638CLK); - tm1638_data_pin = Pin(GPIO_TM1638DIO); - tm1638_strobe_pin = Pin(GPIO_TM1638STB); - - pinMode(tm1638_data_pin, OUTPUT); - pinMode(tm1638_clock_pin, OUTPUT); - pinMode(tm1638_strobe_pin, OUTPUT); - - digitalWrite(tm1638_strobe_pin, HIGH); - digitalWrite(tm1638_clock_pin, HIGH); - - Tm16XXSendCommand(0x40); - Tm16XXSendCommand(0x80 | (tm1638_active_display ? 8 : 0) | tmin(7, tm1638_intensity)); - - digitalWrite(tm1638_strobe_pin, LOW); - Tm16XXSend(0xC0); - for (uint32_t i = 0; i < 16; i++) { - Tm16XXSend(0x00); - } - digitalWrite(tm1638_strobe_pin, HIGH); - - tm1638_type = 1; - tm1638_state = 1; - } -} - -void TmLoop(void) -{ - if (tm1638_state) { - uint8_t buttons = Tm1638GetButtons(); - for (uint32_t i = 0; i < MAX_SWITCHES; i++) { - SwitchSetVirtual(i, (buttons &1) ^1); - uint8_t color = (SwitchGetVirtual(i)) ? TM1638_COLOR_NONE : TM1638_COLOR_RED; - Tm1638SetLED(color, i); - buttons >>= 1; - } - SwitchHandler(1); - } -} - -/* -void TmShow(bool json) -{ - if (tm1638_type) { - - } -} -*/ - -/*********************************************************************************************\ - * Interface -\*********************************************************************************************/ - -bool Xsns28(uint32_t function) -{ - bool result = false; - - if (tm1638_type) { - switch (function) { - case FUNC_INIT: - TmInit(); - break; - case FUNC_EVERY_50_MSECOND: - TmLoop(); - break; -/* - case FUNC_JSON_APPEND: - TmShow(1); - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - TmShow(0); - break; -#endif // USE_WEBSERVER -*/ - } - } - return result; -} - -#endif // USE_TM1638 \ No newline at end of file From 289703c97a9c0553e0ab6f5301eb1ea70aaf663d Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 6 Feb 2023 16:03:50 +0100 Subject: [PATCH 238/262] Update my_user_config.h --- tasmota/my_user_config.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index 542cc0128..1105b2fb8 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -987,6 +987,11 @@ #define SHIFT595_DEVICE_COUNT 1 // [Shift595DeviceCount] Set the number of connected 74x595 shift registers //#define USE_TM1638 // Add support for TM1638 switches copying Switch1 .. Switch8 (+1k code) +// #define TM1638_USE_AS_BUTTON // Add support for buttons +// #define TM1638_USE_AS_SWITCH // Add support for switches (default) +// #define TM1638_MAX_DISPLAYS 8 // Add support for power control 8 displays +// #define TM1638_MAX_KEYS 8 // Add support for 8 keys +// #define TM1638_MAX_LEDS 8 // Add support for 8 leds //#define USE_HX711 // Add support for HX711 load cell (+1k5 code) // #define USE_HX711_GUI // Add optional web GUI to HX711 as scale (+1k8 code) From f76d7ee8cf194190e5b53cc1030aeb081def76da Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 6 Feb 2023 18:07:05 +0100 Subject: [PATCH 239/262] Tune TM1638 key/leds --- .../tasmota_xdrv_driver/xdrv_66_tm1638.ino | 57 +++++++------------ 1 file changed, 21 insertions(+), 36 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_66_tm1638.ino b/tasmota/tasmota_xdrv_driver/xdrv_66_tm1638.ino index 145122472..435d48843 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_66_tm1638.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_66_tm1638.ino @@ -41,6 +41,12 @@ #ifndef TM1638_MAX_LEDS #define TM1638_MAX_LEDS 8 #endif +#ifndef TM1638_BRIGHTNESS +#define TM1638_BRIGHTNESS 0 // Brightness from 0 to 7 +#endif +#ifndef TM1638_DISPLAY_ON +#define TM1638_DISPLAY_ON 1 // Display off (0) or on (1) +#endif #define TM1638_COLOR_NONE 0 #define TM1638_COLOR_RED 1 @@ -54,11 +60,6 @@ struct TM1638 { int8_t strobe_pin = 0; int8_t key_offset; int8_t led_offset; - uint8_t displays; - uint8_t power; - - uint8_t active_display = 1; - uint8_t intensity = 0; bool detected = false; } Tm1638; @@ -68,7 +69,7 @@ struct TM1638 { \*********************************************************************************************/ void Tm16XXSend(uint8_t data) { - for (uint32_t i = 0; i < 8; i++) { + for (uint32_t i = 0; i < 8; i++) { // 8 bits digitalWrite(Tm1638.data_pin, !!(data & (1 << i))); digitalWrite(Tm1638.clock_pin, LOW); delayMicroseconds(TM1638_CLOCK_DELAY); @@ -83,6 +84,9 @@ void Tm16XXSendCommand(uint8_t cmd) { } void TM16XXSendData(uint8_t address, uint8_t data) { + // TM_WRITE_LOC 0x44 - Write to a location + // TM_SEG_ADR 0xC0 - leftmost segment Address C0 C2 C4 C6 C8 CA CC CE + // TM_LEDS_ADR 0xC1 - Leftmost LED address C1 C3 C5 C7 C9 CB CD CF Tm16XXSendCommand(0x44); digitalWrite(Tm1638.strobe_pin, LOW); Tm16XXSend(0xC0 | address); @@ -97,7 +101,7 @@ uint8_t Tm16XXReceive(void) { pinMode(Tm1638.data_pin, INPUT); digitalWrite(Tm1638.data_pin, HIGH); - for (uint32_t i = 0; i < 8; ++i) { + for (uint32_t i = 0; i < 8; ++i) { // 8 bits digitalWrite(Tm1638.clock_pin, LOW); delayMicroseconds(TM1638_CLOCK_DELAY); temp |= digitalRead(Tm1638.data_pin) << i; @@ -113,37 +117,15 @@ uint8_t Tm16XXReceive(void) { /*********************************************************************************************/ -void Tm16XXClearDisplay(void) { - for (uint32_t i = 0; i < Tm1638.displays; i++) { - TM16XXSendData(i << 1, 0); - } -} - void Tm1638SetLED(uint8_t color, uint8_t pos) { TM16XXSendData((pos << 1) + 1, color); } -void Tm1638SetLEDs(word leds) { - for (uint32_t i = 0; i < Tm1638.displays; i++) { - uint8_t color = 0; - - if ((leds & (1 << i)) != 0) { - color |= TM1638_COLOR_RED; - } - - if ((leds & (1 << (i + 8))) != 0) { - color |= TM1638_COLOR_GREEN; - } - - Tm1638SetLED(color, i); - } -} - uint8_t Tm1638GetButtons(void) { - uint8_t keys = 0; - + // TM_BUTTONS_MODE 0x42 - Buttons mode digitalWrite(Tm1638.strobe_pin, LOW); Tm16XXSend(0x42); + uint8_t keys = 0; for (uint32_t i = 0; i < 4; i++) { keys |= Tm16XXReceive() << i; } @@ -167,13 +149,17 @@ void TmInit(void) { digitalWrite(Tm1638.strobe_pin, HIGH); digitalWrite(Tm1638.clock_pin, HIGH); + // TM_WRITE_INC 0x40 - Incremental write Tm16XXSendCommand(0x40); - Tm16XXSendCommand(0x80 | (Tm1638.active_display ? 8 : 0) | tmin(7, Tm1638.intensity)); + // TM_BRIGHT_ADR 0x88 - Brightness address + Tm16XXSendCommand(0x80 | TM1638_DISPLAY_ON << 3 | TM1638_BRIGHTNESS); + // TM_SEG_ADR 0xC0 - leftmost segment Address C0 C2 C4 C6 C8 CA CC CE + // TM_LEDS_ADR 0xC1 - Leftmost LED address C1 C3 C5 C7 C9 CB CD CF digitalWrite(Tm1638.strobe_pin, LOW); - Tm16XXSend(0xC0); - for (uint32_t i = 0; i < 16; i++) { - Tm16XXSend(0x00); + Tm16XXSend(0xC0); // TM_SEG_ADR left most + for (uint32_t i = 0; i < TM1638_MAX_DISPLAYS * 2; i++) { + Tm16XXSend(0x00); // Init displays and leds } digitalWrite(Tm1638.strobe_pin, HIGH); @@ -194,7 +180,6 @@ void TmInit(void) { Tm1638.led_offset = devices_present; TasmotaGlobal.devices_present += TM1638_MAX_LEDS; Tm1638.key_offset = -1; - Tm1638.displays = TM1638_MAX_DISPLAYS; Tm1638.detected = true; } } From 1d5da9b73bc78698ad0e1982845b5b5418868acb Mon Sep 17 00:00:00 2001 From: SteWers <42718143+SteWers@users.noreply.github.com> Date: Mon, 6 Feb 2023 20:18:38 +0100 Subject: [PATCH 240/262] [SolaxX1] Updated safety descriptions (#17887) * [SolaxX1] Updated safety descriptions Updated safety descriptions * [Solax X1] disable `#define SOLAXX1_READCONFIG` by default disable `#define SOLAXX1_READCONFIG` by default --- tasmota/tasmota_xnrg_energy/xnrg_12_solaxX1.ino | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tasmota/tasmota_xnrg_energy/xnrg_12_solaxX1.ino b/tasmota/tasmota_xnrg_energy/xnrg_12_solaxX1.ino index 6915d1411..a087295b9 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_12_solaxX1.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_12_solaxX1.ino @@ -30,7 +30,7 @@ #define SOLAXX1_SPEED 9600 // default solax rs485 speed #endif -#define SOLAXX1_READCONFIG // enable to read inverters config; disable to save codespace (3k1) +// #define SOLAXX1_READCONFIG // enable to read inverters config; disable to save codespace (3k1) #define INVERTER_ADDRESS 0x0A @@ -48,9 +48,10 @@ const char kSolaxError[] PROGMEM = #ifdef SOLAXX1_READCONFIG const char kSolaxSafetyType[] PROGMEM = - "VDE0126|ARN4105|AS4777_AU|G98/1|C10/11|OVE/ONORME8001|EN50438_NL|EN50438_DK|CEB|CEI021|NRS097_2_1|" - "VDE0126_Gr_Is|UTE_C15_712|IEC61727|G99/1|VDE0126_Gr_Co|France_VFR2014|C15_712_is_50|C15_712_is_60|" - "AS4777_NZ|RD1699|Chile|EN50438_Ireland|Philippines|Czech_PPDS|Czech_50438"; + "VDE 0126|VDE-AR-N 4105|AS 4777|G98|C10/11|ÖVE/ÖNORM E 8001|EN 50438 NL|EN 50438 DK|CEB|CEI021|NRS 097-2-1|VDE 0126 Greece/Iceland|" + "UTE C15-712|IEC 61727|G99|VDE 0126 Greece/Co|Guyana|C15-712 France/Iceland 50|C15-712 France/Iceland 60|New Zeeland|RD1699|Chile|" + "EN 50438 Ireland|Philippines|Czech PPDS|Czech 50438|EN 50549 EU|Denmark 2019 EU|RD 1699 Island|EN50549 Poland|MEA Thailand|" + "PEA Thailand|ACEA|AS 4777 2020 B|AS 4777 2020 C|Sri Lanka|BRAZIL 240|EN 50549 SK|EN 50549 EU|G98/NI|Denmark 2019 EU|RD 1699 Island"; #endif // SOLAXX1_READCONFIG union { @@ -267,7 +268,7 @@ void solaxX1_250MSecond(void) // Every 250 milliseconds { uint8_t DataRead[80] = {0}; uint8_t TempData[16] = {0}; - char TempDataChar[16]; + char TempDataChar[32]; float TempFloat; if (solaxX1Serial->available()) { From 4cb9acec65f2d9e36aea4dc5f77229574381adff Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Mon, 6 Feb 2023 22:21:16 +0100 Subject: [PATCH 241/262] Fix PR#17893 (#17901) --- tasmota/tasmota_xsns_sensor/xsns_53_sml.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino b/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino index b07d9025c..0df0973f7 100755 --- a/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino @@ -625,7 +625,7 @@ void dump2log(void) { logsiz = mp->sbsiz; } memmove(mp->sbuff, payload, logsiz); - AddLog(LOG_LEVEL_INFO PSTR("SML: decrypted block: %d bytes"), logsiz); + AddLog(LOG_LEVEL_INFO, PSTR("SML: decrypted block: %d bytes"), logsiz); uint16_t index = 0; while (logsiz) { sml_dump_start('>'); From dc245c57b15a770e7b7af6492a82c9b2adaa1a46 Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Tue, 7 Feb 2023 02:55:12 +0100 Subject: [PATCH 242/262] Berry allow bool key (#17902) --- lib/libesp32/berry/src/be_map.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/libesp32/berry/src/be_map.c b/lib/libesp32/berry/src/be_map.c index e425a09f5..ea3b81c6f 100644 --- a/lib/libesp32/berry/src/be_map.c +++ b/lib/libesp32/berry/src/be_map.c @@ -112,6 +112,7 @@ static int eqnode(bvm *vm, bmapnode *node, bvalue *key, uint32_t hash) #endif if(keytype(k) == key->type && hashcode(k) == hash) { switch (key->type) { + case BE_BOOL: return var_tobool(key) == var_tobool(k); case BE_INT: return var_toint(key) == var_toint(k); case BE_REAL: return var_toreal(key) == var_toreal(k); case BE_STRING: return be_eqstr(var_tostr(key), var_tostr(k)); From 43b6f91cf2c88af7bf8ada1e042623f81294c58c Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Tue, 7 Feb 2023 02:55:20 +0100 Subject: [PATCH 243/262] Berry implement more attributes and commands (#17903) --- .../src/embedded/Matter_Plugin_core.be | 40 +- .../src/embedded/Matter_Session.be | 24 + .../berry_matter/src/embedded/Matter_TLV.be | 11 +- .../solidify/solidified_Matter_Plugin_core.h | 683 +++-- .../src/solidify/solidified_Matter_Session.h | 2399 +++++++++-------- .../src/solidify/solidified_Matter_TLV.h | 350 +-- 6 files changed, 1920 insertions(+), 1587 deletions(-) diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_core.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_core.be index 02ed99bde..217c76c23 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_core.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_core.be @@ -129,9 +129,25 @@ class Matter_Plugin_core : Matter_Plugin elif cluster == 0x003E # ========== Node Operational Credentials Cluster 11.17 p.704 ========== if attribute == 0x0000 # ---------- NOCs / list[NOCStruct] ---------- - # TODO + var nocl = TLV.Matter_TLV_array() # NOCs, p.711 + for session: self.device.sessions.sessions_active() + var nocs = nocl.add_struct(nil) + nocs.add_TLV(1, TLV.B2, session.noc) # NOC + nocs.add_TLV(2, TLV.B2, session.icac) # ICAC + end + return nocl elif attribute == 0x0001 # ---------- Fabrics / list[FabricDescriptorStruct] ---------- - # TODO + var fabrics = TLV.Matter_TLV_array() # Fabrics, p.711 + for session: self.device.sessions.sessions_active() + var root_ca_tlv = TLV.parse(session.get_ca()) + var fab = fabrics.add_struct(nil) # encoding see p.303 + fab.add_TLV(1, TLV.B2, root_ca_tlv.findsubval(9)) # RootPublicKey + fab.add_TLV(2, TLV.U2, session.admin_vendor) # VendorID + fab.add_TLV(3, TLV.U8, session.fabric) # FabricID + fab.add_TLV(4, TLV.U8, session.deviceid) # NodeID + fab.add_TLV(5, TLV.UTF1, session.fabric_label) # Label + end + return fabrics elif attribute == 0x0002 # ---------- SupportedFabrics / u1 ---------- return TLV.create_TLV(TLV.U1, 5) # Max 5 fabrics elif attribute == 0x0003 # ---------- CommissionedFabrics / u1 ---------- @@ -398,6 +414,26 @@ class Matter_Plugin_core : Matter_Plugin ctx.command = 0x08 # NOCResponse return nocr + elif command == 0x0009 # ---------- UpdateFabricLabel ---------- + var label = val.findsubval(0) # Label string max 32 + session.set_fabric_label(label) + ctx.status = matter.SUCCESS # OK + return nil # trigger a standalone ack + + elif command == 0x000A # ---------- RemoveFabric ---------- + var index = val.findsubval(0) # FabricIndex + var sessions_act = self.device.sessions.sessions_active() + if index >= 1 && index <= size(sessions_act) + var session_deleted = sessions_act[index - 1] + tasmota.log("MTR: removing fabric " + session.fabric.copy().reverse().tohex()) + self.device.sessions.remove_session() + self.device.sessions.save() + else + # TODO return error 11 InvalidFabricIndex + end + ctx.status = matter.SUCCESS # OK + return nil # trigger a standalone ack + end end diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Session.be b/lib/libesp32/berry_matter/src/embedded/Matter_Session.be index 028f8a28d..340dccc4c 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Session.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Session.be @@ -72,6 +72,7 @@ class Matter_Session var fabric # fabric identifier as bytes(8) little endian var fabric_compressed # comrpessed fabric identifier, hashed with root_ca public key var deviceid # our own device id bytes(8) little endian + var fabric_label # set by UpdateFabricLabel # Admin info extracted from NOC/ICAC var admin_subject var admin_vendor @@ -112,6 +113,7 @@ class Matter_Session self._i2r_privacy = nil self.r2ikey = nil self.attestation_challenge = nil + self.fabric_label = "" # clear any attribute starting with `_` import introspect for k : introspect.members(self) @@ -155,6 +157,11 @@ class Matter_Session def set_persist(p) self._persist = bool(p) end + def set_fabric_label(s) + if type(s) == 'string' + self.fabric_label = s + end + end ############################################################# def get_mode() @@ -505,6 +512,23 @@ class Matter_Session_Store return session end + ############################################################# + # list of sessions that are active, i.e. have been + # successfully commissioned + # + def sessions_active() + var ret = [] + var idx = 0 + while idx < size(self.sessions) + var session = self.sessions[idx] + if session.get_deviceid() && session.get_fabric() + ret.push(session) + end + idx += 1 + end + return ret + end + ############################################################# def save() import json diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_TLV.be b/lib/libesp32/berry_matter/src/embedded/Matter_TLV.be index 3f54f56a8..1571af07a 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_TLV.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_TLV.be @@ -254,11 +254,16 @@ class Matter_TLV elif self.typ == TLV.I4 || self.typ == TLV.U4 b.add(int(self.val), 4) elif self.typ == TLV.I8 || self.typ == TLV.U8 + # I8/U8 can be encoded from bytes(8)/int64/int var i64 = self.val - if !isinstance(i64, int64) - i64 = int64(int(self.val)) + if isinstance(i64, bytes) + i64 = i64.copy().resize(8) # bytes(8) + elif isinstance(i64, int64) + i64 = i64.tobytes() # bytes(8) + else + i64 = int64(int(i64)).tobytes() # bytes(8) end - b .. i64.tobytes() + b .. i64 elif self.typ == TLV.BFALSE || self.typ == TLV.BTRUE # push nothing elif self.typ == TLV.FLOAT diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_core.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_core.h index a68e124e2..de1617ce8 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_core.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_core.h @@ -19,7 +19,7 @@ be_local_closure(Matter_Plugin_core_read_attribute, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[63]) { /* constants */ + ( &(const bvalue[76]) { /* constants */ /* K0 */ be_nested_str_weak(string), /* K1 */ be_nested_str_weak(matter), /* K2 */ be_nested_str_weak(TLV), @@ -70,23 +70,36 @@ be_local_closure(Matter_Plugin_core_read_attribute, /* name */ /* K47 */ be_nested_str_weak(utc), /* K48 */ be_const_int(1000000), /* K49 */ be_nested_str_weak(local), - /* K50 */ be_nested_str_weak(Tasmota), - /* K51 */ be_nested_str_weak(device), - /* K52 */ be_nested_str_weak(vendorid), - /* K53 */ be_nested_str_weak(DeviceName), - /* K54 */ be_nested_str_weak(FriendlyName), - /* K55 */ be_nested_str_weak(FriendlyName1), - /* K56 */ be_nested_str_weak(XX), - /* K57 */ be_nested_str_weak(Status_X202), - /* K58 */ be_nested_str_weak(StatusFWR), - /* K59 */ be_nested_str_weak(Hardware), - /* K60 */ be_nested_str_weak(Version), - /* K61 */ be_nested_str_weak(locale), - /* K62 */ be_nested_str_weak(Matter_TLV_list), + /* K50 */ be_nested_str_weak(device), + /* K51 */ be_nested_str_weak(sessions), + /* K52 */ be_nested_str_weak(sessions_active), + /* K53 */ be_nested_str_weak(B2), + /* K54 */ be_nested_str_weak(noc), + /* K55 */ be_nested_str_weak(icac), + /* K56 */ be_nested_str_weak(stop_iteration), + /* K57 */ be_nested_str_weak(parse), + /* K58 */ be_nested_str_weak(get_ca), + /* K59 */ be_nested_str_weak(findsubval), + /* K60 */ be_nested_str_weak(admin_vendor), + /* K61 */ be_nested_str_weak(fabric), + /* K62 */ be_nested_str_weak(deviceid), + /* K63 */ be_nested_str_weak(fabric_label), + /* K64 */ be_nested_str_weak(Tasmota), + /* K65 */ be_nested_str_weak(vendorid), + /* K66 */ be_nested_str_weak(DeviceName), + /* K67 */ be_nested_str_weak(FriendlyName), + /* K68 */ be_nested_str_weak(FriendlyName1), + /* K69 */ be_nested_str_weak(XX), + /* K70 */ be_nested_str_weak(Status_X202), + /* K71 */ be_nested_str_weak(StatusFWR), + /* K72 */ be_nested_str_weak(Hardware), + /* K73 */ be_nested_str_weak(Version), + /* K74 */ be_nested_str_weak(locale), + /* K75 */ be_nested_str_weak(Matter_TLV_list), }), be_str_weak(read_attribute), &be_const_str_solidified, - ( &(const binstruction[570]) { /* code */ + ( &(const binstruction[649]) { /* code */ 0xA4160000, // 0000 IMPORT R5 K0 0xB81A0200, // 0001 GETNGBL R6 K1 0x88180D02, // 0002 GETMBR R6 R6 K2 @@ -142,11 +155,11 @@ be_local_closure(Matter_Plugin_core_read_attribute, /* name */ 0x50280000, // 0034 LDBOOL R10 0 0 0x7C1C0600, // 0035 CALL R7 3 0x80040E00, // 0036 RET 1 R7 - 0x70020200, // 0037 JMP #0239 + 0x7002024F, // 0037 JMP #0288 0x541E0031, // 0038 LDINT R7 50 0x1C1C0607, // 0039 EQ R7 R3 R7 0x781E0000, // 003A JMPF R7 #003C - 0x700201FC, // 003B JMP #0239 + 0x7002024B, // 003B JMP #0288 0x541E0032, // 003C LDINT R7 51 0x1C1C0607, // 003D EQ R7 R3 R7 0x781E00DA, // 003E JMPF R7 #011A @@ -368,11 +381,11 @@ be_local_closure(Matter_Plugin_core_read_attribute, /* name */ 0x50280000, // 0116 LDBOOL R10 0 0 0x7C1C0600, // 0117 CALL R7 3 0x80040E00, // 0118 RET 1 R7 - 0x7002011E, // 0119 JMP #0239 + 0x7002016D, // 0119 JMP #0288 0x541E0033, // 011A LDINT R7 52 0x1C1C0607, // 011B EQ R7 R3 R7 0x781E0000, // 011C JMPF R7 #011E - 0x7002011A, // 011D JMP #0239 + 0x70020169, // 011D JMP #0288 0x541E0037, // 011E LDINT R7 56 0x1C1C0607, // 011F EQ R7 R3 R7 0x781E002C, // 0120 JMPF R7 #014E @@ -420,243 +433,322 @@ be_local_closure(Matter_Plugin_core_read_attribute, /* name */ 0x5C2C0E00, // 014A MOVE R11 R7 0x7C200600, // 014B CALL R8 3 0x80041000, // 014C RET 1 R8 - 0x700200EA, // 014D JMP #0239 + 0x70020139, // 014D JMP #0288 0x541E003D, // 014E LDINT R7 62 0x1C1C0607, // 014F EQ R7 R3 R7 - 0x781E001D, // 0150 JMPF R7 #016F + 0x781E006C, // 0150 JMPF R7 #01BE 0x1C1C0903, // 0151 EQ R7 R4 K3 - 0x781E0000, // 0152 JMPF R7 #0154 - 0x70020019, // 0153 JMP #016E - 0x1C1C0908, // 0154 EQ R7 R4 K8 - 0x781E0000, // 0155 JMPF R7 #0157 - 0x70020016, // 0156 JMP #016E - 0x1C1C090C, // 0157 EQ R7 R4 K12 - 0x781E0005, // 0158 JMPF R7 #015F - 0x8C1C0D04, // 0159 GETMET R7 R6 K4 - 0x88240D0D, // 015A GETMBR R9 R6 K13 - 0x542A0004, // 015B LDINT R10 5 - 0x7C1C0600, // 015C CALL R7 3 - 0x80040E00, // 015D RET 1 R7 - 0x7002000E, // 015E JMP #016E - 0x1C1C090E, // 015F EQ R7 R4 K14 - 0x781E0005, // 0160 JMPF R7 #0167 - 0x8C1C0D04, // 0161 GETMET R7 R6 K4 - 0x88240D0D, // 0162 GETMBR R9 R6 K13 - 0x58280008, // 0163 LDCONST R10 K8 - 0x7C1C0600, // 0164 CALL R7 3 - 0x80040E00, // 0165 RET 1 R7 - 0x70020006, // 0166 JMP #016E - 0x541E0003, // 0167 LDINT R7 4 - 0x1C1C0807, // 0168 EQ R7 R4 R7 - 0x781E0000, // 0169 JMPF R7 #016B - 0x70020002, // 016A JMP #016E - 0x541E0004, // 016B LDINT R7 5 - 0x1C1C0807, // 016C EQ R7 R4 R7 - 0x781DFFFF, // 016D JMPF R7 #016E - 0x700200C9, // 016E JMP #0239 - 0x541E003B, // 016F LDINT R7 60 - 0x1C1C0607, // 0170 EQ R7 R3 R7 - 0x781E0000, // 0171 JMPF R7 #0173 - 0x700200C5, // 0172 JMP #0239 - 0x541E0027, // 0173 LDINT R7 40 - 0x1C1C0607, // 0174 EQ R7 R3 R7 - 0x781E0071, // 0175 JMPF R7 #01E8 - 0x1C1C0903, // 0176 EQ R7 R4 K3 - 0x781E0005, // 0177 JMPF R7 #017E - 0x8C1C0D04, // 0178 GETMET R7 R6 K4 - 0x88240D0B, // 0179 GETMBR R9 R6 K11 - 0x58280003, // 017A LDCONST R10 K3 - 0x7C1C0600, // 017B CALL R7 3 - 0x80040E00, // 017C RET 1 R7 - 0x70020068, // 017D JMP #01E7 - 0x1C1C0908, // 017E EQ R7 R4 K8 - 0x781E0005, // 017F JMPF R7 #0186 - 0x8C1C0D04, // 0180 GETMET R7 R6 K4 - 0x88240D15, // 0181 GETMBR R9 R6 K21 - 0x58280032, // 0182 LDCONST R10 K50 - 0x7C1C0600, // 0183 CALL R7 3 - 0x80040E00, // 0184 RET 1 R7 - 0x70020060, // 0185 JMP #01E7 - 0x1C1C090C, // 0186 EQ R7 R4 K12 - 0x781E0006, // 0187 JMPF R7 #018F - 0x8C1C0D04, // 0188 GETMET R7 R6 K4 - 0x88240D0B, // 0189 GETMBR R9 R6 K11 - 0x88280133, // 018A GETMBR R10 R0 K51 - 0x88281534, // 018B GETMBR R10 R10 K52 - 0x7C1C0600, // 018C CALL R7 3 - 0x80040E00, // 018D RET 1 R7 - 0x70020057, // 018E JMP #01E7 - 0x1C1C090E, // 018F EQ R7 R4 K14 - 0x781E0009, // 0190 JMPF R7 #019B - 0x8C1C0D04, // 0191 GETMET R7 R6 K4 - 0x88240D15, // 0192 GETMBR R9 R6 K21 - 0xB82A2200, // 0193 GETNGBL R10 K17 - 0x8C281525, // 0194 GETMET R10 R10 K37 - 0x58300035, // 0195 LDCONST R12 K53 - 0x7C280400, // 0196 CALL R10 2 - 0x94281535, // 0197 GETIDX R10 R10 K53 - 0x7C1C0600, // 0198 CALL R7 3 - 0x80040E00, // 0199 RET 1 R7 - 0x7002004B, // 019A JMP #01E7 - 0x541E0003, // 019B LDINT R7 4 - 0x1C1C0807, // 019C EQ R7 R4 R7 - 0x781E0005, // 019D JMPF R7 #01A4 - 0x8C1C0D04, // 019E GETMET R7 R6 K4 - 0x88240D0B, // 019F GETMBR R9 R6 K11 - 0x542A7FFF, // 01A0 LDINT R10 32768 - 0x7C1C0600, // 01A1 CALL R7 3 - 0x80040E00, // 01A2 RET 1 R7 - 0x70020042, // 01A3 JMP #01E7 - 0x541E0004, // 01A4 LDINT R7 5 - 0x1C1C0807, // 01A5 EQ R7 R4 R7 - 0x781E0009, // 01A6 JMPF R7 #01B1 - 0x8C1C0D04, // 01A7 GETMET R7 R6 K4 - 0x88240D15, // 01A8 GETMBR R9 R6 K21 - 0xB82A2200, // 01A9 GETNGBL R10 K17 - 0x8C281525, // 01AA GETMET R10 R10 K37 - 0x58300036, // 01AB LDCONST R12 K54 - 0x7C280400, // 01AC CALL R10 2 - 0x94281537, // 01AD GETIDX R10 R10 K55 - 0x7C1C0600, // 01AE CALL R7 3 - 0x80040E00, // 01AF RET 1 R7 - 0x70020035, // 01B0 JMP #01E7 - 0x541E0005, // 01B1 LDINT R7 6 - 0x1C1C0807, // 01B2 EQ R7 R4 R7 - 0x781E0005, // 01B3 JMPF R7 #01BA - 0x8C1C0D04, // 01B4 GETMET R7 R6 K4 - 0x88240D15, // 01B5 GETMBR R9 R6 K21 - 0x58280038, // 01B6 LDCONST R10 K56 - 0x7C1C0600, // 01B7 CALL R7 3 - 0x80040E00, // 01B8 RET 1 R7 - 0x7002002C, // 01B9 JMP #01E7 - 0x541E0006, // 01BA LDINT R7 7 + 0x781E001D, // 0152 JMPF R7 #0171 + 0x8C1C0D10, // 0153 GETMET R7 R6 K16 + 0x7C1C0200, // 0154 CALL R7 1 + 0x60200010, // 0155 GETGBL R8 G16 + 0x88240132, // 0156 GETMBR R9 R0 K50 + 0x88241333, // 0157 GETMBR R9 R9 K51 + 0x8C241334, // 0158 GETMET R9 R9 K52 + 0x7C240200, // 0159 CALL R9 1 + 0x7C200200, // 015A CALL R8 1 + 0xA802000F, // 015B EXBLK 0 #016C + 0x5C241000, // 015C MOVE R9 R8 + 0x7C240000, // 015D CALL R9 0 + 0x8C280F14, // 015E GETMET R10 R7 K20 + 0x4C300000, // 015F LDNIL R12 + 0x7C280400, // 0160 CALL R10 2 + 0x8C2C150A, // 0161 GETMET R11 R10 K10 + 0x58340008, // 0162 LDCONST R13 K8 + 0x88380D35, // 0163 GETMBR R14 R6 K53 + 0x883C1336, // 0164 GETMBR R15 R9 K54 + 0x7C2C0800, // 0165 CALL R11 4 + 0x8C2C150A, // 0166 GETMET R11 R10 K10 + 0x5834000C, // 0167 LDCONST R13 K12 + 0x88380D35, // 0168 GETMBR R14 R6 K53 + 0x883C1337, // 0169 GETMBR R15 R9 K55 + 0x7C2C0800, // 016A CALL R11 4 + 0x7001FFEF, // 016B JMP #015C + 0x58200038, // 016C LDCONST R8 K56 + 0xAC200200, // 016D CATCH R8 1 0 + 0xB0080000, // 016E RAISE 2 R0 R0 + 0x80040E00, // 016F RET 1 R7 + 0x7002004B, // 0170 JMP #01BD + 0x1C1C0908, // 0171 EQ R7 R4 K8 + 0x781E0032, // 0172 JMPF R7 #01A6 + 0x8C1C0D10, // 0173 GETMET R7 R6 K16 + 0x7C1C0200, // 0174 CALL R7 1 + 0x60200010, // 0175 GETGBL R8 G16 + 0x88240132, // 0176 GETMBR R9 R0 K50 + 0x88241333, // 0177 GETMBR R9 R9 K51 + 0x8C241334, // 0178 GETMET R9 R9 K52 + 0x7C240200, // 0179 CALL R9 1 + 0x7C200200, // 017A CALL R8 1 + 0xA8020024, // 017B EXBLK 0 #01A1 + 0x5C241000, // 017C MOVE R9 R8 + 0x7C240000, // 017D CALL R9 0 + 0x8C280D39, // 017E GETMET R10 R6 K57 + 0x8C30133A, // 017F GETMET R12 R9 K58 + 0x7C300200, // 0180 CALL R12 1 + 0x7C280400, // 0181 CALL R10 2 + 0x8C2C0F14, // 0182 GETMET R11 R7 K20 + 0x4C340000, // 0183 LDNIL R13 + 0x7C2C0400, // 0184 CALL R11 2 + 0x8C30170A, // 0185 GETMET R12 R11 K10 + 0x58380008, // 0186 LDCONST R14 K8 + 0x883C0D35, // 0187 GETMBR R15 R6 K53 + 0x8C40153B, // 0188 GETMET R16 R10 K59 + 0x544A0008, // 0189 LDINT R18 9 + 0x7C400400, // 018A CALL R16 2 + 0x7C300800, // 018B CALL R12 4 + 0x8C30170A, // 018C GETMET R12 R11 K10 + 0x5838000C, // 018D LDCONST R14 K12 + 0x883C0D0B, // 018E GETMBR R15 R6 K11 + 0x8840133C, // 018F GETMBR R16 R9 K60 + 0x7C300800, // 0190 CALL R12 4 + 0x8C30170A, // 0191 GETMET R12 R11 K10 + 0x5838000E, // 0192 LDCONST R14 K14 + 0x883C0D05, // 0193 GETMBR R15 R6 K5 + 0x8840133D, // 0194 GETMBR R16 R9 K61 + 0x7C300800, // 0195 CALL R12 4 + 0x8C30170A, // 0196 GETMET R12 R11 K10 + 0x543A0003, // 0197 LDINT R14 4 + 0x883C0D05, // 0198 GETMBR R15 R6 K5 + 0x8840133E, // 0199 GETMBR R16 R9 K62 + 0x7C300800, // 019A CALL R12 4 + 0x8C30170A, // 019B GETMET R12 R11 K10 + 0x543A0004, // 019C LDINT R14 5 + 0x883C0D15, // 019D GETMBR R15 R6 K21 + 0x8840133F, // 019E GETMBR R16 R9 K63 + 0x7C300800, // 019F CALL R12 4 + 0x7001FFDA, // 01A0 JMP #017C + 0x58200038, // 01A1 LDCONST R8 K56 + 0xAC200200, // 01A2 CATCH R8 1 0 + 0xB0080000, // 01A3 RAISE 2 R0 R0 + 0x80040E00, // 01A4 RET 1 R7 + 0x70020016, // 01A5 JMP #01BD + 0x1C1C090C, // 01A6 EQ R7 R4 K12 + 0x781E0005, // 01A7 JMPF R7 #01AE + 0x8C1C0D04, // 01A8 GETMET R7 R6 K4 + 0x88240D0D, // 01A9 GETMBR R9 R6 K13 + 0x542A0004, // 01AA LDINT R10 5 + 0x7C1C0600, // 01AB CALL R7 3 + 0x80040E00, // 01AC RET 1 R7 + 0x7002000E, // 01AD JMP #01BD + 0x1C1C090E, // 01AE EQ R7 R4 K14 + 0x781E0005, // 01AF JMPF R7 #01B6 + 0x8C1C0D04, // 01B0 GETMET R7 R6 K4 + 0x88240D0D, // 01B1 GETMBR R9 R6 K13 + 0x58280008, // 01B2 LDCONST R10 K8 + 0x7C1C0600, // 01B3 CALL R7 3 + 0x80040E00, // 01B4 RET 1 R7 + 0x70020006, // 01B5 JMP #01BD + 0x541E0003, // 01B6 LDINT R7 4 + 0x1C1C0807, // 01B7 EQ R7 R4 R7 + 0x781E0000, // 01B8 JMPF R7 #01BA + 0x70020002, // 01B9 JMP #01BD + 0x541E0004, // 01BA LDINT R7 5 0x1C1C0807, // 01BB EQ R7 R4 R7 - 0x781E0005, // 01BC JMPF R7 #01C3 - 0x8C1C0D04, // 01BD GETMET R7 R6 K4 - 0x88240D0B, // 01BE GETMBR R9 R6 K11 - 0x58280003, // 01BF LDCONST R10 K3 - 0x7C1C0600, // 01C0 CALL R7 3 - 0x80040E00, // 01C1 RET 1 R7 - 0x70020023, // 01C2 JMP #01E7 - 0x541E0007, // 01C3 LDINT R7 8 - 0x1C1C0807, // 01C4 EQ R7 R4 R7 - 0x781E000A, // 01C5 JMPF R7 #01D1 - 0x8C1C0D04, // 01C6 GETMET R7 R6 K4 - 0x88240D15, // 01C7 GETMBR R9 R6 K21 - 0xB82A2200, // 01C8 GETNGBL R10 K17 - 0x8C281525, // 01C9 GETMET R10 R10 K37 - 0x58300039, // 01CA LDCONST R12 K57 - 0x7C280400, // 01CB CALL R10 2 - 0x9428153A, // 01CC GETIDX R10 R10 K58 - 0x9428153B, // 01CD GETIDX R10 R10 K59 - 0x7C1C0600, // 01CE CALL R7 3 - 0x80040E00, // 01CF RET 1 R7 - 0x70020015, // 01D0 JMP #01E7 - 0x541E0008, // 01D1 LDINT R7 9 - 0x1C1C0807, // 01D2 EQ R7 R4 R7 - 0x781E0005, // 01D3 JMPF R7 #01DA - 0x8C1C0D04, // 01D4 GETMET R7 R6 K4 - 0x88240D0B, // 01D5 GETMBR R9 R6 K11 - 0x58280003, // 01D6 LDCONST R10 K3 - 0x7C1C0600, // 01D7 CALL R7 3 - 0x80040E00, // 01D8 RET 1 R7 - 0x7002000C, // 01D9 JMP #01E7 - 0x541E0009, // 01DA LDINT R7 10 - 0x1C1C0807, // 01DB EQ R7 R4 R7 - 0x781E0009, // 01DC JMPF R7 #01E7 - 0x8C1C0D04, // 01DD GETMET R7 R6 K4 - 0x88240D15, // 01DE GETMBR R9 R6 K21 - 0xB82A2200, // 01DF GETNGBL R10 K17 - 0x8C281525, // 01E0 GETMET R10 R10 K37 - 0x58300039, // 01E1 LDCONST R12 K57 - 0x7C280400, // 01E2 CALL R10 2 - 0x9428153A, // 01E3 GETIDX R10 R10 K58 - 0x9428153C, // 01E4 GETIDX R10 R10 K60 - 0x7C1C0600, // 01E5 CALL R7 3 - 0x80040E00, // 01E6 RET 1 R7 - 0x70020050, // 01E7 JMP #0239 - 0x541E003E, // 01E8 LDINT R7 63 - 0x1C1C0607, // 01E9 EQ R7 R3 R7 - 0x781E0000, // 01EA JMPF R7 #01EC - 0x7002004C, // 01EB JMP #0239 - 0x541E002A, // 01EC LDINT R7 43 - 0x1C1C0607, // 01ED EQ R7 R3 R7 - 0x781E0016, // 01EE JMPF R7 #0206 - 0x1C1C0903, // 01EF EQ R7 R4 K3 - 0x781E0007, // 01F0 JMPF R7 #01F9 - 0x8C1C0D04, // 01F1 GETMET R7 R6 K4 - 0x88240D15, // 01F2 GETMBR R9 R6 K21 - 0xB82A2200, // 01F3 GETNGBL R10 K17 - 0x8C28153D, // 01F4 GETMET R10 R10 K61 - 0x7C280200, // 01F5 CALL R10 1 - 0x7C1C0600, // 01F6 CALL R7 3 - 0x80040E00, // 01F7 RET 1 R7 - 0x7002000B, // 01F8 JMP #0205 - 0x1C1C0908, // 01F9 EQ R7 R4 K8 - 0x781E0009, // 01FA JMPF R7 #0205 - 0x8C1C0D3E, // 01FB GETMET R7 R6 K62 - 0x7C1C0200, // 01FC CALL R7 1 - 0x8C200F0A, // 01FD GETMET R8 R7 K10 - 0x4C280000, // 01FE LDNIL R10 - 0x882C0D15, // 01FF GETMBR R11 R6 K21 - 0xB8322200, // 0200 GETNGBL R12 K17 - 0x8C30193D, // 0201 GETMET R12 R12 K61 - 0x7C300200, // 0202 CALL R12 1 - 0x7C200800, // 0203 CALL R8 4 - 0x80040E00, // 0204 RET 1 R7 - 0x70020032, // 0205 JMP #0239 - 0x541E002B, // 0206 LDINT R7 44 - 0x1C1C0607, // 0207 EQ R7 R3 R7 - 0x781E001C, // 0208 JMPF R7 #0226 - 0x1C1C0903, // 0209 EQ R7 R4 K3 - 0x781E0005, // 020A JMPF R7 #0211 - 0x8C1C0D04, // 020B GETMET R7 R6 K4 - 0x88240D0D, // 020C GETMBR R9 R6 K13 - 0x58280008, // 020D LDCONST R10 K8 - 0x7C1C0600, // 020E CALL R7 3 - 0x80040E00, // 020F RET 1 R7 - 0x70020013, // 0210 JMP #0225 - 0x1C1C0908, // 0211 EQ R7 R4 K8 - 0x781E0005, // 0212 JMPF R7 #0219 - 0x8C1C0D04, // 0213 GETMET R7 R6 K4 - 0x88240D0D, // 0214 GETMBR R9 R6 K13 - 0x542A0003, // 0215 LDINT R10 4 - 0x7C1C0600, // 0216 CALL R7 3 - 0x80040E00, // 0217 RET 1 R7 - 0x7002000B, // 0218 JMP #0225 - 0x1C1C090C, // 0219 EQ R7 R4 K12 - 0x781E0009, // 021A JMPF R7 #0225 - 0x8C1C0D3E, // 021B GETMET R7 R6 K62 - 0x7C1C0200, // 021C CALL R7 1 - 0x8C200F0A, // 021D GETMET R8 R7 K10 - 0x4C280000, // 021E LDNIL R10 - 0x8C2C0D04, // 021F GETMET R11 R6 K4 - 0x88340D0D, // 0220 GETMBR R13 R6 K13 - 0x543A0003, // 0221 LDINT R14 4 - 0x7C2C0600, // 0222 CALL R11 3 - 0x7C200600, // 0223 CALL R8 3 - 0x80040E00, // 0224 RET 1 R7 - 0x70020012, // 0225 JMP #0239 - 0x541E0030, // 0226 LDINT R7 49 - 0x1C1C0607, // 0227 EQ R7 R3 R7 - 0x781E000F, // 0228 JMPF R7 #0239 - 0x1C1C090E, // 0229 EQ R7 R4 K14 - 0x781E0005, // 022A JMPF R7 #0231 - 0x8C1C0D04, // 022B GETMET R7 R6 K4 - 0x88240D0D, // 022C GETMBR R9 R6 K13 - 0x542A001D, // 022D LDINT R10 30 - 0x7C1C0600, // 022E CALL R7 3 - 0x80040E00, // 022F RET 1 R7 - 0x70020007, // 0230 JMP #0239 - 0x541EFFFB, // 0231 LDINT R7 65532 - 0x1C1C0807, // 0232 EQ R7 R4 R7 - 0x781E0004, // 0233 JMPF R7 #0239 - 0x8C1C0D04, // 0234 GETMET R7 R6 K4 - 0x88240D29, // 0235 GETMBR R9 R6 K41 - 0x58280003, // 0236 LDCONST R10 K3 - 0x7C1C0600, // 0237 CALL R7 3 - 0x80040E00, // 0238 RET 1 R7 - 0x80000000, // 0239 RET 0 + 0x781DFFFF, // 01BC JMPF R7 #01BD + 0x700200C9, // 01BD JMP #0288 + 0x541E003B, // 01BE LDINT R7 60 + 0x1C1C0607, // 01BF EQ R7 R3 R7 + 0x781E0000, // 01C0 JMPF R7 #01C2 + 0x700200C5, // 01C1 JMP #0288 + 0x541E0027, // 01C2 LDINT R7 40 + 0x1C1C0607, // 01C3 EQ R7 R3 R7 + 0x781E0071, // 01C4 JMPF R7 #0237 + 0x1C1C0903, // 01C5 EQ R7 R4 K3 + 0x781E0005, // 01C6 JMPF R7 #01CD + 0x8C1C0D04, // 01C7 GETMET R7 R6 K4 + 0x88240D0B, // 01C8 GETMBR R9 R6 K11 + 0x58280003, // 01C9 LDCONST R10 K3 + 0x7C1C0600, // 01CA CALL R7 3 + 0x80040E00, // 01CB RET 1 R7 + 0x70020068, // 01CC JMP #0236 + 0x1C1C0908, // 01CD EQ R7 R4 K8 + 0x781E0005, // 01CE JMPF R7 #01D5 + 0x8C1C0D04, // 01CF GETMET R7 R6 K4 + 0x88240D15, // 01D0 GETMBR R9 R6 K21 + 0x58280040, // 01D1 LDCONST R10 K64 + 0x7C1C0600, // 01D2 CALL R7 3 + 0x80040E00, // 01D3 RET 1 R7 + 0x70020060, // 01D4 JMP #0236 + 0x1C1C090C, // 01D5 EQ R7 R4 K12 + 0x781E0006, // 01D6 JMPF R7 #01DE + 0x8C1C0D04, // 01D7 GETMET R7 R6 K4 + 0x88240D0B, // 01D8 GETMBR R9 R6 K11 + 0x88280132, // 01D9 GETMBR R10 R0 K50 + 0x88281541, // 01DA GETMBR R10 R10 K65 + 0x7C1C0600, // 01DB CALL R7 3 + 0x80040E00, // 01DC RET 1 R7 + 0x70020057, // 01DD JMP #0236 + 0x1C1C090E, // 01DE EQ R7 R4 K14 + 0x781E0009, // 01DF JMPF R7 #01EA + 0x8C1C0D04, // 01E0 GETMET R7 R6 K4 + 0x88240D15, // 01E1 GETMBR R9 R6 K21 + 0xB82A2200, // 01E2 GETNGBL R10 K17 + 0x8C281525, // 01E3 GETMET R10 R10 K37 + 0x58300042, // 01E4 LDCONST R12 K66 + 0x7C280400, // 01E5 CALL R10 2 + 0x94281542, // 01E6 GETIDX R10 R10 K66 + 0x7C1C0600, // 01E7 CALL R7 3 + 0x80040E00, // 01E8 RET 1 R7 + 0x7002004B, // 01E9 JMP #0236 + 0x541E0003, // 01EA LDINT R7 4 + 0x1C1C0807, // 01EB EQ R7 R4 R7 + 0x781E0005, // 01EC JMPF R7 #01F3 + 0x8C1C0D04, // 01ED GETMET R7 R6 K4 + 0x88240D0B, // 01EE GETMBR R9 R6 K11 + 0x542A7FFF, // 01EF LDINT R10 32768 + 0x7C1C0600, // 01F0 CALL R7 3 + 0x80040E00, // 01F1 RET 1 R7 + 0x70020042, // 01F2 JMP #0236 + 0x541E0004, // 01F3 LDINT R7 5 + 0x1C1C0807, // 01F4 EQ R7 R4 R7 + 0x781E0009, // 01F5 JMPF R7 #0200 + 0x8C1C0D04, // 01F6 GETMET R7 R6 K4 + 0x88240D15, // 01F7 GETMBR R9 R6 K21 + 0xB82A2200, // 01F8 GETNGBL R10 K17 + 0x8C281525, // 01F9 GETMET R10 R10 K37 + 0x58300043, // 01FA LDCONST R12 K67 + 0x7C280400, // 01FB CALL R10 2 + 0x94281544, // 01FC GETIDX R10 R10 K68 + 0x7C1C0600, // 01FD CALL R7 3 + 0x80040E00, // 01FE RET 1 R7 + 0x70020035, // 01FF JMP #0236 + 0x541E0005, // 0200 LDINT R7 6 + 0x1C1C0807, // 0201 EQ R7 R4 R7 + 0x781E0005, // 0202 JMPF R7 #0209 + 0x8C1C0D04, // 0203 GETMET R7 R6 K4 + 0x88240D15, // 0204 GETMBR R9 R6 K21 + 0x58280045, // 0205 LDCONST R10 K69 + 0x7C1C0600, // 0206 CALL R7 3 + 0x80040E00, // 0207 RET 1 R7 + 0x7002002C, // 0208 JMP #0236 + 0x541E0006, // 0209 LDINT R7 7 + 0x1C1C0807, // 020A EQ R7 R4 R7 + 0x781E0005, // 020B JMPF R7 #0212 + 0x8C1C0D04, // 020C GETMET R7 R6 K4 + 0x88240D0B, // 020D GETMBR R9 R6 K11 + 0x58280003, // 020E LDCONST R10 K3 + 0x7C1C0600, // 020F CALL R7 3 + 0x80040E00, // 0210 RET 1 R7 + 0x70020023, // 0211 JMP #0236 + 0x541E0007, // 0212 LDINT R7 8 + 0x1C1C0807, // 0213 EQ R7 R4 R7 + 0x781E000A, // 0214 JMPF R7 #0220 + 0x8C1C0D04, // 0215 GETMET R7 R6 K4 + 0x88240D15, // 0216 GETMBR R9 R6 K21 + 0xB82A2200, // 0217 GETNGBL R10 K17 + 0x8C281525, // 0218 GETMET R10 R10 K37 + 0x58300046, // 0219 LDCONST R12 K70 + 0x7C280400, // 021A CALL R10 2 + 0x94281547, // 021B GETIDX R10 R10 K71 + 0x94281548, // 021C GETIDX R10 R10 K72 + 0x7C1C0600, // 021D CALL R7 3 + 0x80040E00, // 021E RET 1 R7 + 0x70020015, // 021F JMP #0236 + 0x541E0008, // 0220 LDINT R7 9 + 0x1C1C0807, // 0221 EQ R7 R4 R7 + 0x781E0005, // 0222 JMPF R7 #0229 + 0x8C1C0D04, // 0223 GETMET R7 R6 K4 + 0x88240D0B, // 0224 GETMBR R9 R6 K11 + 0x58280003, // 0225 LDCONST R10 K3 + 0x7C1C0600, // 0226 CALL R7 3 + 0x80040E00, // 0227 RET 1 R7 + 0x7002000C, // 0228 JMP #0236 + 0x541E0009, // 0229 LDINT R7 10 + 0x1C1C0807, // 022A EQ R7 R4 R7 + 0x781E0009, // 022B JMPF R7 #0236 + 0x8C1C0D04, // 022C GETMET R7 R6 K4 + 0x88240D15, // 022D GETMBR R9 R6 K21 + 0xB82A2200, // 022E GETNGBL R10 K17 + 0x8C281525, // 022F GETMET R10 R10 K37 + 0x58300046, // 0230 LDCONST R12 K70 + 0x7C280400, // 0231 CALL R10 2 + 0x94281547, // 0232 GETIDX R10 R10 K71 + 0x94281549, // 0233 GETIDX R10 R10 K73 + 0x7C1C0600, // 0234 CALL R7 3 + 0x80040E00, // 0235 RET 1 R7 + 0x70020050, // 0236 JMP #0288 + 0x541E003E, // 0237 LDINT R7 63 + 0x1C1C0607, // 0238 EQ R7 R3 R7 + 0x781E0000, // 0239 JMPF R7 #023B + 0x7002004C, // 023A JMP #0288 + 0x541E002A, // 023B LDINT R7 43 + 0x1C1C0607, // 023C EQ R7 R3 R7 + 0x781E0016, // 023D JMPF R7 #0255 + 0x1C1C0903, // 023E EQ R7 R4 K3 + 0x781E0007, // 023F JMPF R7 #0248 + 0x8C1C0D04, // 0240 GETMET R7 R6 K4 + 0x88240D15, // 0241 GETMBR R9 R6 K21 + 0xB82A2200, // 0242 GETNGBL R10 K17 + 0x8C28154A, // 0243 GETMET R10 R10 K74 + 0x7C280200, // 0244 CALL R10 1 + 0x7C1C0600, // 0245 CALL R7 3 + 0x80040E00, // 0246 RET 1 R7 + 0x7002000B, // 0247 JMP #0254 + 0x1C1C0908, // 0248 EQ R7 R4 K8 + 0x781E0009, // 0249 JMPF R7 #0254 + 0x8C1C0D4B, // 024A GETMET R7 R6 K75 + 0x7C1C0200, // 024B CALL R7 1 + 0x8C200F0A, // 024C GETMET R8 R7 K10 + 0x4C280000, // 024D LDNIL R10 + 0x882C0D15, // 024E GETMBR R11 R6 K21 + 0xB8322200, // 024F GETNGBL R12 K17 + 0x8C30194A, // 0250 GETMET R12 R12 K74 + 0x7C300200, // 0251 CALL R12 1 + 0x7C200800, // 0252 CALL R8 4 + 0x80040E00, // 0253 RET 1 R7 + 0x70020032, // 0254 JMP #0288 + 0x541E002B, // 0255 LDINT R7 44 + 0x1C1C0607, // 0256 EQ R7 R3 R7 + 0x781E001C, // 0257 JMPF R7 #0275 + 0x1C1C0903, // 0258 EQ R7 R4 K3 + 0x781E0005, // 0259 JMPF R7 #0260 + 0x8C1C0D04, // 025A GETMET R7 R6 K4 + 0x88240D0D, // 025B GETMBR R9 R6 K13 + 0x58280008, // 025C LDCONST R10 K8 + 0x7C1C0600, // 025D CALL R7 3 + 0x80040E00, // 025E RET 1 R7 + 0x70020013, // 025F JMP #0274 + 0x1C1C0908, // 0260 EQ R7 R4 K8 + 0x781E0005, // 0261 JMPF R7 #0268 + 0x8C1C0D04, // 0262 GETMET R7 R6 K4 + 0x88240D0D, // 0263 GETMBR R9 R6 K13 + 0x542A0003, // 0264 LDINT R10 4 + 0x7C1C0600, // 0265 CALL R7 3 + 0x80040E00, // 0266 RET 1 R7 + 0x7002000B, // 0267 JMP #0274 + 0x1C1C090C, // 0268 EQ R7 R4 K12 + 0x781E0009, // 0269 JMPF R7 #0274 + 0x8C1C0D4B, // 026A GETMET R7 R6 K75 + 0x7C1C0200, // 026B CALL R7 1 + 0x8C200F0A, // 026C GETMET R8 R7 K10 + 0x4C280000, // 026D LDNIL R10 + 0x8C2C0D04, // 026E GETMET R11 R6 K4 + 0x88340D0D, // 026F GETMBR R13 R6 K13 + 0x543A0003, // 0270 LDINT R14 4 + 0x7C2C0600, // 0271 CALL R11 3 + 0x7C200600, // 0272 CALL R8 3 + 0x80040E00, // 0273 RET 1 R7 + 0x70020012, // 0274 JMP #0288 + 0x541E0030, // 0275 LDINT R7 49 + 0x1C1C0607, // 0276 EQ R7 R3 R7 + 0x781E000F, // 0277 JMPF R7 #0288 + 0x1C1C090E, // 0278 EQ R7 R4 K14 + 0x781E0005, // 0279 JMPF R7 #0280 + 0x8C1C0D04, // 027A GETMET R7 R6 K4 + 0x88240D0D, // 027B GETMBR R9 R6 K13 + 0x542A001D, // 027C LDINT R10 30 + 0x7C1C0600, // 027D CALL R7 3 + 0x80040E00, // 027E RET 1 R7 + 0x70020007, // 027F JMP #0288 + 0x541EFFFB, // 0280 LDINT R7 65532 + 0x1C1C0807, // 0281 EQ R7 R4 R7 + 0x781E0004, // 0282 JMPF R7 #0288 + 0x8C1C0D04, // 0283 GETMET R7 R6 K4 + 0x88240D29, // 0284 GETMBR R9 R6 K41 + 0x58280003, // 0285 LDCONST R10 K3 + 0x7C1C0600, // 0286 CALL R7 3 + 0x80040E00, // 0287 RET 1 R7 + 0x80000000, // 0288 RET 0 }) ) ); @@ -714,7 +806,7 @@ be_local_closure(Matter_Plugin_core_invoke_request, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[66]) { /* constants */ + ( &(const bvalue[73]) { /* constants */ /* K0 */ be_nested_str_weak(crypto), /* K1 */ be_nested_str_weak(matter), /* K2 */ be_nested_str_weak(TLV), @@ -781,10 +873,17 @@ be_local_closure(Matter_Plugin_core_invoke_request, /* name */ /* K63 */ be_nested_str_weak(derive), /* K64 */ be_nested_str_weak(set_fabric_device), /* K65 */ be_nested_str_weak(start_operational_dicovery_deferred), + /* K66 */ be_nested_str_weak(set_fabric_label), + /* K67 */ be_nested_str_weak(sessions), + /* K68 */ be_nested_str_weak(sessions_active), + /* K69 */ be_nested_str_weak(MTR_X3A_X20removing_X20fabric_X20), + /* K70 */ be_nested_str_weak(fabric), + /* K71 */ be_nested_str_weak(remove_session), + /* K72 */ be_nested_str_weak(save), }), be_str_weak(invoke_request), &be_const_str_solidified, - ( &(const binstruction[435]) { /* code */ + ( &(const binstruction[495]) { /* code */ 0xA4120000, // 0000 IMPORT R4 K0 0xB8160200, // 0001 GETNGBL R5 K1 0x88140B02, // 0002 GETMBR R5 R5 K2 @@ -874,10 +973,10 @@ be_local_closure(Matter_Plugin_core_invoke_request, /* name */ 0x5C301000, // 0056 MOVE R12 R8 0x7C280400, // 0057 CALL R10 2 0x80041200, // 0058 RET 1 R9 - 0x70020157, // 0059 JMP #01B2 + 0x70020193, // 0059 JMP #01EE 0x5426003D, // 005A LDINT R9 62 0x1C240C09, // 005B EQ R9 R6 R9 - 0x78260154, // 005C JMPF R9 #01B2 + 0x78260190, // 005C JMPF R9 #01EE 0x1C240F0F, // 005D EQ R9 R7 K15 0x7826001D, // 005E JMPF R9 #007D 0x8C240507, // 005F GETMET R9 R2 K7 @@ -909,7 +1008,7 @@ be_local_closure(Matter_Plugin_core_invoke_request, /* name */ 0x7C2C0800, // 0079 CALL R11 4 0x900E0911, // 007A SETMBR R3 K4 K17 0x80041400, // 007B RET 1 R10 - 0x70020134, // 007C JMP #01B2 + 0x70020170, // 007C JMP #01EE 0x1C240F06, // 007D EQ R9 R7 K6 0x78260044, // 007E JMPF R9 #00C4 0x8C240507, // 007F GETMET R9 R2 K7 @@ -980,7 +1079,7 @@ be_local_closure(Matter_Plugin_core_invoke_request, /* name */ 0x7C400800, // 00C0 CALL R16 4 0x900E0908, // 00C1 SETMBR R3 K4 K8 0x80041E00, // 00C2 RET 1 R15 - 0x700200ED, // 00C3 JMP #01B2 + 0x70020129, // 00C3 JMP #01EE 0x54260003, // 00C4 LDINT R9 4 0x1C240E09, // 00C5 EQ R9 R7 R9 0x78260040, // 00C6 JMPF R9 #0108 @@ -1048,7 +1147,7 @@ be_local_closure(Matter_Plugin_core_invoke_request, /* name */ 0x54460004, // 0104 LDINT R17 5 0x900E0811, // 0105 SETMBR R3 K4 R17 0x80042000, // 0106 RET 1 R16 - 0x700200A9, // 0107 JMP #01B2 + 0x700200E5, // 0107 JMP #01EE 0x5426000A, // 0108 LDINT R9 11 0x1C240E09, // 0109 EQ R9 R7 R9 0x78260012, // 010A JMPF R9 #011E @@ -1070,10 +1169,10 @@ be_local_closure(Matter_Plugin_core_invoke_request, /* name */ 0x900E2A0A, // 011A SETMBR R3 K21 R10 0x4C280000, // 011B LDNIL R10 0x80041400, // 011C RET 1 R10 - 0x70020093, // 011D JMP #01B2 + 0x700200CF, // 011D JMP #01EE 0x54260005, // 011E LDINT R9 6 0x1C240E09, // 011F EQ R9 R7 R9 - 0x78260090, // 0120 JMPF R9 #01B2 + 0x78260091, // 0120 JMPF R9 #01B3 0x8C240507, // 0121 GETMET R9 R2 K7 0x582C0006, // 0122 LDCONST R11 K6 0x7C240400, // 0123 CALL R9 2 @@ -1219,7 +1318,67 @@ be_local_closure(Matter_Plugin_core_invoke_request, /* name */ 0x54620007, // 01AF LDINT R24 8 0x900E0818, // 01B0 SETMBR R3 K4 R24 0x80042E00, // 01B1 RET 1 R23 - 0x80000000, // 01B2 RET 0 + 0x7002003A, // 01B2 JMP #01EE + 0x54260008, // 01B3 LDINT R9 9 + 0x1C240E09, // 01B4 EQ R9 R7 R9 + 0x7826000B, // 01B5 JMPF R9 #01C2 + 0x8C240507, // 01B6 GETMET R9 R2 K7 + 0x582C0006, // 01B7 LDCONST R11 K6 + 0x7C240400, // 01B8 CALL R9 2 + 0x8C281142, // 01B9 GETMET R10 R8 K66 + 0x5C301200, // 01BA MOVE R12 R9 + 0x7C280400, // 01BB CALL R10 2 + 0xB82A0200, // 01BC GETNGBL R10 K1 + 0x8828152C, // 01BD GETMBR R10 R10 K44 + 0x900E2A0A, // 01BE SETMBR R3 K21 R10 + 0x4C280000, // 01BF LDNIL R10 + 0x80041400, // 01C0 RET 1 R10 + 0x7002002B, // 01C1 JMP #01EE + 0x54260009, // 01C2 LDINT R9 10 + 0x1C240E09, // 01C3 EQ R9 R7 R9 + 0x78260028, // 01C4 JMPF R9 #01EE + 0x8C240507, // 01C5 GETMET R9 R2 K7 + 0x582C0006, // 01C6 LDCONST R11 K6 + 0x7C240400, // 01C7 CALL R9 2 + 0x88280113, // 01C8 GETMBR R10 R0 K19 + 0x88281543, // 01C9 GETMBR R10 R10 K67 + 0x8C281544, // 01CA GETMET R10 R10 K68 + 0x7C280200, // 01CB CALL R10 1 + 0x282C1308, // 01CC GE R11 R9 K8 + 0x782E001A, // 01CD JMPF R11 #01E9 + 0x602C000C, // 01CE GETGBL R11 G12 + 0x5C301400, // 01CF MOVE R12 R10 + 0x7C2C0200, // 01D0 CALL R11 1 + 0x182C120B, // 01D1 LE R11 R9 R11 + 0x782E0015, // 01D2 JMPF R11 #01E9 + 0x042C1308, // 01D3 SUB R11 R9 K8 + 0x942C140B, // 01D4 GETIDX R11 R10 R11 + 0xB8323A00, // 01D5 GETNGBL R12 K29 + 0x8C301922, // 01D6 GETMET R12 R12 K34 + 0x88381146, // 01D7 GETMBR R14 R8 K70 + 0x8C381D3D, // 01D8 GETMET R14 R14 K61 + 0x7C380200, // 01D9 CALL R14 1 + 0x8C381D3E, // 01DA GETMET R14 R14 K62 + 0x7C380200, // 01DB CALL R14 1 + 0x8C381D24, // 01DC GETMET R14 R14 K36 + 0x7C380200, // 01DD CALL R14 1 + 0x003A8A0E, // 01DE ADD R14 K69 R14 + 0x7C300400, // 01DF CALL R12 2 + 0x88300113, // 01E0 GETMBR R12 R0 K19 + 0x88301943, // 01E1 GETMBR R12 R12 K67 + 0x8C301947, // 01E2 GETMET R12 R12 K71 + 0x7C300200, // 01E3 CALL R12 1 + 0x88300113, // 01E4 GETMBR R12 R0 K19 + 0x88301943, // 01E5 GETMBR R12 R12 K67 + 0x8C301948, // 01E6 GETMET R12 R12 K72 + 0x7C300200, // 01E7 CALL R12 1 + 0x7001FFFF, // 01E8 JMP #01E9 + 0xB82E0200, // 01E9 GETNGBL R11 K1 + 0x882C172C, // 01EA GETMBR R11 R11 K44 + 0x900E2A0B, // 01EB SETMBR R3 K21 R11 + 0x4C2C0000, // 01EC LDNIL R11 + 0x80041600, // 01ED RET 1 R11 + 0x80000000, // 01EE RET 0 }) ) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Session.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Session.h index 3857f1e4d..3b4a450b0 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Session.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Session.h @@ -7,11 +7,11 @@ extern const bclass be_class_Matter_Session; /******************************************************************** -** Solidified function: get_fabric_compressed +** Solidified function: get_ca_pub ********************************************************************/ -be_local_closure(Matter_Session_get_fabric_compressed, /* name */ +be_local_closure(Matter_Session_get_ca_pub, /* name */ be_nested_proto( - 2, /* nstack */ + 5, /* nstack */ 1, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -19,242 +19,28 @@ be_local_closure(Matter_Session_get_fabric_compressed, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(fabric_compressed), - }), - be_str_weak(get_fabric_compressed), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: set_no_expiration -********************************************************************/ -be_local_closure(Matter_Session_set_no_expiration, /* name */ - be_nested_proto( - 2, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(expiration), - }), - be_str_weak(set_no_expiration), - &be_const_str_solidified, - ( &(const binstruction[ 3]) { /* code */ - 0x4C040000, // 0000 LDNIL R1 - 0x90020001, // 0001 SETMBR R0 K0 R1 - 0x80000000, // 0002 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: set_ca -********************************************************************/ -be_local_closure(Matter_Session_set_ca, /* name */ - be_nested_proto( - 2, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(root_ca_certificate), - }), - be_str_weak(set_ca), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x90020001, // 0000 SETMBR R0 K0 R1 - 0x80000000, // 0001 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: set_fabric_device -********************************************************************/ -be_local_closure(Matter_Session_set_fabric_device, /* name */ - be_nested_proto( - 7, /* nstack */ - 4, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ ( &(const bvalue[ 5]) { /* constants */ - /* K0 */ be_nested_str_weak(fabric), - /* K1 */ be_nested_str_weak(deviceid), - /* K2 */ be_nested_str_weak(fabric_compressed), - /* K3 */ be_nested_str_weak(__store), - /* K4 */ be_nested_str_weak(remove_redundant_session), + /* K0 */ be_nested_str_weak(root_ca_certificate), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(TLV), + /* K3 */ be_nested_str_weak(parse), + /* K4 */ be_nested_str_weak(findsubval), }), - be_str_weak(set_fabric_device), + be_str_weak(get_ca_pub), &be_const_str_solidified, - ( &(const binstruction[ 8]) { /* code */ - 0x90020001, // 0000 SETMBR R0 K0 R1 - 0x90020202, // 0001 SETMBR R0 K1 R2 - 0x90020403, // 0002 SETMBR R0 K2 R3 - 0x88100103, // 0003 GETMBR R4 R0 K3 - 0x8C100904, // 0004 GETMET R4 R4 K4 - 0x5C180000, // 0005 MOVE R6 R0 - 0x7C100400, // 0006 CALL R4 2 - 0x80000000, // 0007 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_r2i -********************************************************************/ -be_local_closure(Matter_Session_get_r2i, /* name */ - be_nested_proto( - 2, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(r2ikey), - }), - be_str_weak(get_r2i), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ + ( &(const binstruction[12]) { /* code */ 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_i2r_privacy -********************************************************************/ -be_local_closure(Matter_Session_get_i2r_privacy, /* name */ - be_nested_proto( - 9, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 7]) { /* constants */ - /* K0 */ be_nested_str_weak(_i2r_privacy), - /* K1 */ be_nested_str_weak(crypto), - /* K2 */ be_nested_str_weak(HKDF_SHA256), - /* K3 */ be_nested_str_weak(derive), - /* K4 */ be_nested_str_weak(get_i2r), - /* K5 */ be_nested_str_weak(fromstring), - /* K6 */ be_nested_str_weak(PrivacyKey), - }), - be_str_weak(get_i2r_privacy), - &be_const_str_solidified, - ( &(const binstruction[22]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x4C080000, // 0001 LDNIL R2 - 0x1C040202, // 0002 EQ R1 R1 R2 - 0x7806000F, // 0003 JMPF R1 #0014 - 0xA4060200, // 0004 IMPORT R1 K1 - 0x8C080302, // 0005 GETMET R2 R1 K2 - 0x7C080200, // 0006 CALL R2 1 - 0x8C080503, // 0007 GETMET R2 R2 K3 - 0x8C100104, // 0008 GETMET R4 R0 K4 - 0x7C100200, // 0009 CALL R4 1 - 0x60140015, // 000A GETGBL R5 G21 - 0x7C140000, // 000B CALL R5 0 - 0x60180015, // 000C GETGBL R6 G21 - 0x7C180000, // 000D CALL R6 0 - 0x8C180D05, // 000E GETMET R6 R6 K5 - 0x58200006, // 000F LDCONST R8 K6 - 0x7C180400, // 0010 CALL R6 2 - 0x541E000F, // 0011 LDINT R7 16 - 0x7C080A00, // 0012 CALL R2 5 - 0x90020002, // 0013 SETMBR R0 K0 R2 - 0x88040100, // 0014 GETMBR R1 R0 K0 - 0x80040200, // 0015 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_ipk_group_key -********************************************************************/ -be_local_closure(Matter_Session_get_ipk_group_key, /* name */ - be_nested_proto( - 10, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 7]) { /* constants */ - /* K0 */ be_nested_str_weak(ipk_epoch_key), - /* K1 */ be_nested_str_weak(fabric_compressed), - /* K2 */ be_nested_str_weak(crypto), - /* K3 */ be_nested_str_weak(HKDF_SHA256), - /* K4 */ be_nested_str_weak(fromstring), - /* K5 */ be_nested_str_weak(__GROUP_KEY), - /* K6 */ be_nested_str_weak(derive), - }), - be_str_weak(get_ipk_group_key), - &be_const_str_solidified, - ( &(const binstruction[25]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x4C080000, // 0001 LDNIL R2 - 0x1C040202, // 0002 EQ R1 R1 R2 - 0x74060003, // 0003 JMPT R1 #0008 - 0x88040101, // 0004 GETMBR R1 R0 K1 - 0x4C080000, // 0005 LDNIL R2 - 0x1C040202, // 0006 EQ R1 R1 R2 - 0x78060001, // 0007 JMPF R1 #000A - 0x4C040000, // 0008 LDNIL R1 - 0x80040200, // 0009 RET 1 R1 - 0xA4060400, // 000A IMPORT R1 K2 - 0x8C080303, // 000B GETMET R2 R1 K3 - 0x7C080200, // 000C CALL R2 1 - 0x600C0015, // 000D GETGBL R3 G21 - 0x7C0C0000, // 000E CALL R3 0 - 0x8C0C0704, // 000F GETMET R3 R3 K4 - 0x88140105, // 0010 GETMBR R5 R0 K5 - 0x7C0C0400, // 0011 CALL R3 2 - 0x8C100506, // 0012 GETMET R4 R2 K6 - 0x88180100, // 0013 GETMBR R6 R0 K0 - 0x881C0101, // 0014 GETMBR R7 R0 K1 - 0x5C200600, // 0015 MOVE R8 R3 - 0x5426000F, // 0016 LDINT R9 16 - 0x7C100A00, // 0017 CALL R4 5 - 0x80040800, // 0018 RET 1 R4 + 0x78060008, // 0001 JMPF R1 #000B + 0xB8060200, // 0002 GETNGBL R1 K1 + 0x88040302, // 0003 GETMBR R1 R1 K2 + 0x8C040303, // 0004 GETMET R1 R1 K3 + 0x880C0100, // 0005 GETMBR R3 R0 K0 + 0x7C040400, // 0006 CALL R1 2 + 0x8C080304, // 0007 GETMET R2 R1 K4 + 0x54120008, // 0008 LDINT R4 9 + 0x7C080400, // 0009 CALL R2 2 + 0x80040400, // 000A RET 1 R2 + 0x80000000, // 000B RET 0 }) ) ); @@ -393,9 +179,9 @@ be_local_closure(Matter_Session_fromjson, /* name */ /******************************************************************** -** Solidified function: get_deviceid +** Solidified function: get_fabric_compressed ********************************************************************/ -be_local_closure(Matter_Session_get_deviceid, /* name */ +be_local_closure(Matter_Session_get_fabric_compressed, /* name */ be_nested_proto( 2, /* nstack */ 1, /* argc */ @@ -406,9 +192,9 @@ be_local_closure(Matter_Session_get_deviceid, /* name */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(deviceid), + /* K0 */ be_nested_str_weak(fabric_compressed), }), - be_str_weak(get_deviceid), + be_str_weak(get_fabric_compressed), &be_const_str_solidified, ( &(const binstruction[ 2]) { /* code */ 0x88040100, // 0000 GETMBR R1 R0 K0 @@ -420,103 +206,29 @@ be_local_closure(Matter_Session_get_deviceid, /* name */ /******************************************************************** -** Solidified function: close +** Solidified function: set_expire_time ********************************************************************/ -be_local_closure(Matter_Session_close, /* name */ +be_local_closure(Matter_Session_set_expire_time, /* name */ be_nested_proto( - 9, /* nstack */ - 1, /* argc */ + 4, /* nstack */ + 2, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[22]) { /* constants */ - /* K0 */ be_nested_str_weak(_persist), - /* K1 */ be_nested_str_weak(local_session_id), - /* K2 */ be_nested_str_weak(_future_local_session_id), - /* K3 */ be_nested_str_weak(initiator_session_id), - /* K4 */ be_nested_str_weak(_future_initiator_session_id), - /* K5 */ be_nested_str_weak(source_node_id), - /* K6 */ be_nested_str_weak(counter_rcv), - /* K7 */ be_nested_str_weak(reset), - /* K8 */ be_nested_str_weak(counter_snd), - /* K9 */ be_nested_str_weak(i2rkey), - /* K10 */ be_nested_str_weak(_i2r_privacy), - /* K11 */ be_nested_str_weak(r2ikey), - /* K12 */ be_nested_str_weak(attestation_challenge), - /* K13 */ be_nested_str_weak(introspect), - /* K14 */ be_nested_str_weak(members), - /* K15 */ be_nested_str_weak(get), - /* K16 */ be_nested_str_weak(function), - /* K17 */ be_nested_str_weak(instance), - /* K18 */ be_const_int(0), - /* K19 */ be_nested_str_weak(_), - /* K20 */ be_const_int(1), - /* K21 */ be_nested_str_weak(stop_iteration), + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(expiration), }), - be_str_weak(close), + be_str_weak(set_expire_time), &be_const_str_solidified, - ( &(const binstruction[58]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x88080102, // 0001 GETMBR R2 R0 K2 - 0x90020202, // 0002 SETMBR R0 K1 R2 - 0x88080104, // 0003 GETMBR R2 R0 K4 - 0x90020602, // 0004 SETMBR R0 K3 R2 - 0x4C080000, // 0005 LDNIL R2 - 0x90020A02, // 0006 SETMBR R0 K5 R2 - 0x88080106, // 0007 GETMBR R2 R0 K6 - 0x8C080507, // 0008 GETMET R2 R2 K7 - 0x7C080200, // 0009 CALL R2 1 - 0x88080108, // 000A GETMBR R2 R0 K8 - 0x8C080507, // 000B GETMET R2 R2 K7 - 0x7C080200, // 000C CALL R2 1 - 0x4C080000, // 000D LDNIL R2 - 0x90021202, // 000E SETMBR R0 K9 R2 - 0x4C080000, // 000F LDNIL R2 - 0x90021402, // 0010 SETMBR R0 K10 R2 - 0x4C080000, // 0011 LDNIL R2 - 0x90021602, // 0012 SETMBR R0 K11 R2 - 0x4C080000, // 0013 LDNIL R2 - 0x90021802, // 0014 SETMBR R0 K12 R2 - 0xA40A1A00, // 0015 IMPORT R2 K13 - 0x600C0010, // 0016 GETGBL R3 G16 - 0x8C10050E, // 0017 GETMET R4 R2 K14 - 0x5C180000, // 0018 MOVE R6 R0 - 0x7C100400, // 0019 CALL R4 2 - 0x7C0C0200, // 001A CALL R3 1 - 0xA8020018, // 001B EXBLK 0 #0035 - 0x5C100600, // 001C MOVE R4 R3 - 0x7C100000, // 001D CALL R4 0 - 0x8C14050F, // 001E GETMET R5 R2 K15 - 0x5C1C0000, // 001F MOVE R7 R0 - 0x5C200800, // 0020 MOVE R8 R4 - 0x7C140600, // 0021 CALL R5 3 - 0x60180004, // 0022 GETGBL R6 G4 - 0x5C1C0A00, // 0023 MOVE R7 R5 - 0x7C180200, // 0024 CALL R6 1 - 0x20180D10, // 0025 NE R6 R6 K16 - 0x781A000C, // 0026 JMPF R6 #0034 - 0x60180004, // 0027 GETGBL R6 G4 - 0x5C1C0A00, // 0028 MOVE R7 R5 - 0x7C180200, // 0029 CALL R6 1 - 0x20180D11, // 002A NE R6 R6 K17 - 0x781A0007, // 002B JMPF R6 #0034 - 0x94180912, // 002C GETIDX R6 R4 K18 - 0x1C180D13, // 002D EQ R6 R6 K19 - 0x781A0004, // 002E JMPF R6 #0034 - 0x94180914, // 002F GETIDX R6 R4 K20 - 0x20180D13, // 0030 NE R6 R6 K19 - 0x781A0001, // 0031 JMPF R6 #0034 - 0x4C180000, // 0032 LDNIL R6 - 0x90000806, // 0033 SETMBR R0 R4 R6 - 0x7001FFE6, // 0034 JMP #001C - 0x580C0015, // 0035 LDCONST R3 K21 - 0xAC0C0200, // 0036 CATCH R3 1 0 - 0xB0080000, // 0037 RAISE 2 R0 R0 - 0x90020001, // 0038 SETMBR R0 K0 R1 - 0x80000000, // 0039 RET 0 + ( &(const binstruction[ 5]) { /* code */ + 0x60080009, // 0000 GETGBL R2 G9 + 0x5C0C0200, // 0001 MOVE R3 R1 + 0x7C080200, // 0002 CALL R2 1 + 0x90020002, // 0003 SETMBR R0 K0 R2 + 0x80000000, // 0004 RET 0 }) ) ); @@ -524,11 +236,81 @@ be_local_closure(Matter_Session_close, /* name */ /******************************************************************** -** Solidified function: get_pk +** Solidified function: set_expire_in_seconds ********************************************************************/ -be_local_closure(Matter_Session_get_pk, /* name */ +be_local_closure(Matter_Session_set_expire_in_seconds, /* name */ be_nested_proto( - 5, /* nstack */ + 6, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(tasmota), + /* K1 */ be_nested_str_weak(rtc), + /* K2 */ be_nested_str_weak(utc), + /* K3 */ be_nested_str_weak(set_expire_time), + }), + be_str_weak(set_expire_in_seconds), + &be_const_str_solidified, + ( &(const binstruction[15]) { /* code */ + 0x4C0C0000, // 0000 LDNIL R3 + 0x1C0C0203, // 0001 EQ R3 R1 R3 + 0x780E0000, // 0002 JMPF R3 #0004 + 0x80000600, // 0003 RET 0 + 0x4C0C0000, // 0004 LDNIL R3 + 0x1C0C0403, // 0005 EQ R3 R2 R3 + 0x780E0003, // 0006 JMPF R3 #000B + 0xB80E0000, // 0007 GETNGBL R3 K0 + 0x8C0C0701, // 0008 GETMET R3 R3 K1 + 0x7C0C0200, // 0009 CALL R3 1 + 0x94080702, // 000A GETIDX R2 R3 K2 + 0x8C0C0103, // 000B GETMET R3 R0 K3 + 0x00140401, // 000C ADD R5 R2 R1 + 0x7C0C0400, // 000D CALL R3 2 + 0x80000000, // 000E RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_ipk_epoch_key +********************************************************************/ +be_local_closure(Matter_Session_set_ipk_epoch_key, /* name */ + be_nested_proto( + 2, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(ipk_epoch_key), + }), + be_str_weak(set_ipk_epoch_key), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x80000000, // 0001 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_noc +********************************************************************/ +be_local_closure(Matter_Session_get_noc, /* name */ + be_nested_proto( + 2, /* nstack */ 1, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -536,23 +318,14 @@ be_local_closure(Matter_Session_get_pk, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_nested_str_weak(no_private_key), - /* K1 */ be_nested_str_weak(crypto), - /* K2 */ be_nested_str_weak(random), + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(noc), }), - be_str_weak(get_pk), + be_str_weak(get_noc), &be_const_str_solidified, - ( &(const binstruction[ 9]) { /* code */ + ( &(const binstruction[ 2]) { /* code */ 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x74060004, // 0001 JMPT R1 #0007 - 0xA4060200, // 0002 IMPORT R1 K1 - 0x8C080302, // 0003 GETMET R2 R1 K2 - 0x5412001F, // 0004 LDINT R4 32 - 0x7C080400, // 0005 CALL R2 2 - 0x90020002, // 0006 SETMBR R0 K0 R2 - 0x88040100, // 0007 GETMBR R1 R0 K0 - 0x80040200, // 0008 RET 1 R1 + 0x80040200, // 0001 RET 1 R1 }) ) ); @@ -706,237 +479,12 @@ be_local_closure(Matter_Session_tojson, /* name */ /******************************************************************** -** Solidified function: set_expire_time +** Solidified function: set_fabric_device ********************************************************************/ -be_local_closure(Matter_Session_set_expire_time, /* name */ +be_local_closure(Matter_Session_set_fabric_device, /* name */ be_nested_proto( - 4, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(expiration), - }), - be_str_weak(set_expire_time), - &be_const_str_solidified, - ( &(const binstruction[ 5]) { /* code */ - 0x60080009, // 0000 GETGBL R2 G9 - 0x5C0C0200, // 0001 MOVE R3 R1 - 0x7C080200, // 0002 CALL R2 1 - 0x90020002, // 0003 SETMBR R0 K0 R2 - 0x80000000, // 0004 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: set_mode -********************************************************************/ -be_local_closure(Matter_Session_set_mode, /* name */ - be_nested_proto( - 2, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(mode), - }), - be_str_weak(set_mode), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x90020001, // 0000 SETMBR R0 K0 R1 - 0x80000000, // 0001 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_icac -********************************************************************/ -be_local_closure(Matter_Session_get_icac, /* name */ - be_nested_proto( - 2, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(icac), - }), - be_str_weak(get_icac), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: set_persist -********************************************************************/ -be_local_closure(Matter_Session_set_persist, /* name */ - be_nested_proto( - 4, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(_persist), - }), - be_str_weak(set_persist), - &be_const_str_solidified, - ( &(const binstruction[ 5]) { /* code */ - 0x60080017, // 0000 GETGBL R2 G23 - 0x5C0C0200, // 0001 MOVE R3 R1 - 0x7C080200, // 0002 CALL R2 1 - 0x90020002, // 0003 SETMBR R0 K0 R2 - 0x80000000, // 0004 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: set_ipk_epoch_key -********************************************************************/ -be_local_closure(Matter_Session_set_ipk_epoch_key, /* name */ - be_nested_proto( - 2, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(ipk_epoch_key), - }), - be_str_weak(set_ipk_epoch_key), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x90020001, // 0000 SETMBR R0 K0 R1 - 0x80000000, // 0001 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_mode -********************************************************************/ -be_local_closure(Matter_Session_get_mode, /* name */ - be_nested_proto( - 2, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(mode), - }), - be_str_weak(get_mode), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_ca -********************************************************************/ -be_local_closure(Matter_Session_get_ca, /* name */ - be_nested_proto( - 2, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(root_ca_certificate), - }), - be_str_weak(get_ca), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: save -********************************************************************/ -be_local_closure(Matter_Session_save, /* name */ - be_nested_proto( - 3, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(__store), - /* K1 */ be_nested_str_weak(save), - }), - be_str_weak(save), - &be_const_str_solidified, - ( &(const binstruction[ 4]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x8C040301, // 0001 GETMET R1 R1 K1 - 0x7C040200, // 0002 CALL R1 1 - 0x80000000, // 0003 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_ca_pub -********************************************************************/ -be_local_closure(Matter_Session_get_ca_pub, /* name */ - be_nested_proto( - 5, /* nstack */ - 1, /* argc */ + 7, /* nstack */ + 4, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ @@ -944,27 +492,23 @@ be_local_closure(Matter_Session_get_ca_pub, /* name */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 5]) { /* constants */ - /* K0 */ be_nested_str_weak(root_ca_certificate), - /* K1 */ be_nested_str_weak(matter), - /* K2 */ be_nested_str_weak(TLV), - /* K3 */ be_nested_str_weak(parse), - /* K4 */ be_nested_str_weak(findsubval), + /* K0 */ be_nested_str_weak(fabric), + /* K1 */ be_nested_str_weak(deviceid), + /* K2 */ be_nested_str_weak(fabric_compressed), + /* K3 */ be_nested_str_weak(__store), + /* K4 */ be_nested_str_weak(remove_redundant_session), }), - be_str_weak(get_ca_pub), + be_str_weak(set_fabric_device), &be_const_str_solidified, - ( &(const binstruction[12]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x78060008, // 0001 JMPF R1 #000B - 0xB8060200, // 0002 GETNGBL R1 K1 - 0x88040302, // 0003 GETMBR R1 R1 K2 - 0x8C040303, // 0004 GETMET R1 R1 K3 - 0x880C0100, // 0005 GETMBR R3 R0 K0 - 0x7C040400, // 0006 CALL R1 2 - 0x8C080304, // 0007 GETMET R2 R1 K4 - 0x54120008, // 0008 LDINT R4 9 - 0x7C080400, // 0009 CALL R2 2 - 0x80040400, // 000A RET 1 R2 - 0x80000000, // 000B RET 0 + ( &(const binstruction[ 8]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x90020202, // 0001 SETMBR R0 K1 R2 + 0x90020403, // 0002 SETMBR R0 K2 R3 + 0x88100103, // 0003 GETMBR R4 R0 K3 + 0x8C100904, // 0004 GETMET R4 R4 K4 + 0x5C180000, // 0005 MOVE R6 R0 + 0x7C100400, // 0006 CALL R4 2 + 0x80000000, // 0007 RET 0 }) ) ); @@ -972,9 +516,9 @@ be_local_closure(Matter_Session_get_ca_pub, /* name */ /******************************************************************** -** Solidified function: get_ipk_epoch_key +** Solidified function: get_deviceid ********************************************************************/ -be_local_closure(Matter_Session_get_ipk_epoch_key, /* name */ +be_local_closure(Matter_Session_get_deviceid, /* name */ be_nested_proto( 2, /* nstack */ 1, /* argc */ @@ -985,9 +529,9 @@ be_local_closure(Matter_Session_get_ipk_epoch_key, /* name */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(ipk_epoch_key), + /* K0 */ be_nested_str_weak(deviceid), }), - be_str_weak(get_ipk_epoch_key), + be_str_weak(get_deviceid), &be_const_str_solidified, ( &(const binstruction[ 2]) { /* code */ 0x88040100, // 0000 GETMBR R1 R0 K0 @@ -999,9 +543,9 @@ be_local_closure(Matter_Session_get_ipk_epoch_key, /* name */ /******************************************************************** -** Solidified function: get_ac +** Solidified function: get_r2i ********************************************************************/ -be_local_closure(Matter_Session_get_ac, /* name */ +be_local_closure(Matter_Session_get_r2i, /* name */ be_nested_proto( 2, /* nstack */ 1, /* argc */ @@ -1012,9 +556,9 @@ be_local_closure(Matter_Session_get_ac, /* name */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(attestation_challenge), + /* K0 */ be_nested_str_weak(r2ikey), }), - be_str_weak(get_ac), + be_str_weak(get_r2i), &be_const_str_solidified, ( &(const binstruction[ 2]) { /* code */ 0x88040100, // 0000 GETMBR R1 R0 K0 @@ -1025,6 +569,146 @@ be_local_closure(Matter_Session_get_ac, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: set_fabric_label +********************************************************************/ +be_local_closure(Matter_Session_set_fabric_label, /* name */ + be_nested_proto( + 4, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(fabric_label), + }), + be_str_weak(set_fabric_label), + &be_const_str_solidified, + ( &(const binstruction[ 7]) { /* code */ + 0x60080004, // 0000 GETGBL R2 G4 + 0x5C0C0200, // 0001 MOVE R3 R1 + 0x7C080200, // 0002 CALL R2 1 + 0x1C080500, // 0003 EQ R2 R2 K0 + 0x780A0000, // 0004 JMPF R2 #0006 + 0x90020201, // 0005 SETMBR R0 K1 R1 + 0x80000000, // 0006 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: close +********************************************************************/ +be_local_closure(Matter_Session_close, /* name */ + be_nested_proto( + 9, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[24]) { /* constants */ + /* K0 */ be_nested_str_weak(_persist), + /* K1 */ be_nested_str_weak(local_session_id), + /* K2 */ be_nested_str_weak(_future_local_session_id), + /* K3 */ be_nested_str_weak(initiator_session_id), + /* K4 */ be_nested_str_weak(_future_initiator_session_id), + /* K5 */ be_nested_str_weak(source_node_id), + /* K6 */ be_nested_str_weak(counter_rcv), + /* K7 */ be_nested_str_weak(reset), + /* K8 */ be_nested_str_weak(counter_snd), + /* K9 */ be_nested_str_weak(i2rkey), + /* K10 */ be_nested_str_weak(_i2r_privacy), + /* K11 */ be_nested_str_weak(r2ikey), + /* K12 */ be_nested_str_weak(attestation_challenge), + /* K13 */ be_nested_str_weak(fabric_label), + /* K14 */ be_nested_str_weak(), + /* K15 */ be_nested_str_weak(introspect), + /* K16 */ be_nested_str_weak(members), + /* K17 */ be_nested_str_weak(get), + /* K18 */ be_nested_str_weak(function), + /* K19 */ be_nested_str_weak(instance), + /* K20 */ be_const_int(0), + /* K21 */ be_nested_str_weak(_), + /* K22 */ be_const_int(1), + /* K23 */ be_nested_str_weak(stop_iteration), + }), + be_str_weak(close), + &be_const_str_solidified, + ( &(const binstruction[59]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x88080102, // 0001 GETMBR R2 R0 K2 + 0x90020202, // 0002 SETMBR R0 K1 R2 + 0x88080104, // 0003 GETMBR R2 R0 K4 + 0x90020602, // 0004 SETMBR R0 K3 R2 + 0x4C080000, // 0005 LDNIL R2 + 0x90020A02, // 0006 SETMBR R0 K5 R2 + 0x88080106, // 0007 GETMBR R2 R0 K6 + 0x8C080507, // 0008 GETMET R2 R2 K7 + 0x7C080200, // 0009 CALL R2 1 + 0x88080108, // 000A GETMBR R2 R0 K8 + 0x8C080507, // 000B GETMET R2 R2 K7 + 0x7C080200, // 000C CALL R2 1 + 0x4C080000, // 000D LDNIL R2 + 0x90021202, // 000E SETMBR R0 K9 R2 + 0x4C080000, // 000F LDNIL R2 + 0x90021402, // 0010 SETMBR R0 K10 R2 + 0x4C080000, // 0011 LDNIL R2 + 0x90021602, // 0012 SETMBR R0 K11 R2 + 0x4C080000, // 0013 LDNIL R2 + 0x90021802, // 0014 SETMBR R0 K12 R2 + 0x90021B0E, // 0015 SETMBR R0 K13 K14 + 0xA40A1E00, // 0016 IMPORT R2 K15 + 0x600C0010, // 0017 GETGBL R3 G16 + 0x8C100510, // 0018 GETMET R4 R2 K16 + 0x5C180000, // 0019 MOVE R6 R0 + 0x7C100400, // 001A CALL R4 2 + 0x7C0C0200, // 001B CALL R3 1 + 0xA8020018, // 001C EXBLK 0 #0036 + 0x5C100600, // 001D MOVE R4 R3 + 0x7C100000, // 001E CALL R4 0 + 0x8C140511, // 001F GETMET R5 R2 K17 + 0x5C1C0000, // 0020 MOVE R7 R0 + 0x5C200800, // 0021 MOVE R8 R4 + 0x7C140600, // 0022 CALL R5 3 + 0x60180004, // 0023 GETGBL R6 G4 + 0x5C1C0A00, // 0024 MOVE R7 R5 + 0x7C180200, // 0025 CALL R6 1 + 0x20180D12, // 0026 NE R6 R6 K18 + 0x781A000C, // 0027 JMPF R6 #0035 + 0x60180004, // 0028 GETGBL R6 G4 + 0x5C1C0A00, // 0029 MOVE R7 R5 + 0x7C180200, // 002A CALL R6 1 + 0x20180D13, // 002B NE R6 R6 K19 + 0x781A0007, // 002C JMPF R6 #0035 + 0x94180914, // 002D GETIDX R6 R4 K20 + 0x1C180D15, // 002E EQ R6 R6 K21 + 0x781A0004, // 002F JMPF R6 #0035 + 0x94180916, // 0030 GETIDX R6 R4 K22 + 0x20180D15, // 0031 NE R6 R6 K21 + 0x781A0001, // 0032 JMPF R6 #0035 + 0x4C180000, // 0033 LDNIL R6 + 0x90000806, // 0034 SETMBR R0 R4 R6 + 0x7001FFE6, // 0035 JMP #001D + 0x580C0017, // 0036 LDCONST R3 K23 + 0xAC0C0200, // 0037 CATCH R3 1 0 + 0xB0080000, // 0038 RAISE 2 R0 R0 + 0x90020001, // 0039 SETMBR R0 K0 R1 + 0x80000000, // 003A RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: set_noc ********************************************************************/ @@ -1055,9 +739,9 @@ be_local_closure(Matter_Session_set_noc, /* name */ /******************************************************************** -** Solidified function: get_i2r +** Solidified function: get_mode ********************************************************************/ -be_local_closure(Matter_Session_get_i2r, /* name */ +be_local_closure(Matter_Session_get_mode, /* name */ be_nested_proto( 2, /* nstack */ 1, /* argc */ @@ -1068,9 +752,9 @@ be_local_closure(Matter_Session_get_i2r, /* name */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(i2rkey), + /* K0 */ be_nested_str_weak(mode), }), - be_str_weak(get_i2r), + be_str_weak(get_mode), &be_const_str_solidified, ( &(const binstruction[ 2]) { /* code */ 0x88040100, // 0000 GETMBR R1 R0 K0 @@ -1082,9 +766,9 @@ be_local_closure(Matter_Session_get_i2r, /* name */ /******************************************************************** -** Solidified function: get_fabric +** Solidified function: get_ipk_epoch_key ********************************************************************/ -be_local_closure(Matter_Session_get_fabric, /* name */ +be_local_closure(Matter_Session_get_ipk_epoch_key, /* name */ be_nested_proto( 2, /* nstack */ 1, /* argc */ @@ -1095,9 +779,9 @@ be_local_closure(Matter_Session_get_fabric, /* name */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(fabric), + /* K0 */ be_nested_str_weak(ipk_epoch_key), }), - be_str_weak(get_fabric), + be_str_weak(get_ipk_epoch_key), &be_const_str_solidified, ( &(const binstruction[ 2]) { /* code */ 0x88040100, // 0000 GETMBR R1 R0 K0 @@ -1109,35 +793,55 @@ be_local_closure(Matter_Session_get_fabric, /* name */ /******************************************************************** -** Solidified function: set_keys +** Solidified function: get_ipk_group_key ********************************************************************/ -be_local_closure(Matter_Session_set_keys, /* name */ +be_local_closure(Matter_Session_get_ipk_group_key, /* name */ be_nested_proto( - 6, /* nstack */ - 5, /* argc */ + 10, /* nstack */ + 1, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 5]) { /* constants */ - /* K0 */ be_nested_str_weak(i2rkey), - /* K1 */ be_nested_str_weak(_i2r_privacy), - /* K2 */ be_nested_str_weak(r2ikey), - /* K3 */ be_nested_str_weak(attestation_challenge), - /* K4 */ be_nested_str_weak(session_timestamp), + ( &(const bvalue[ 7]) { /* constants */ + /* K0 */ be_nested_str_weak(ipk_epoch_key), + /* K1 */ be_nested_str_weak(fabric_compressed), + /* K2 */ be_nested_str_weak(crypto), + /* K3 */ be_nested_str_weak(HKDF_SHA256), + /* K4 */ be_nested_str_weak(fromstring), + /* K5 */ be_nested_str_weak(__GROUP_KEY), + /* K6 */ be_nested_str_weak(derive), }), - be_str_weak(set_keys), + be_str_weak(get_ipk_group_key), &be_const_str_solidified, - ( &(const binstruction[ 7]) { /* code */ - 0x90020001, // 0000 SETMBR R0 K0 R1 - 0x4C140000, // 0001 LDNIL R5 - 0x90020205, // 0002 SETMBR R0 K1 R5 - 0x90020402, // 0003 SETMBR R0 K2 R2 - 0x90020603, // 0004 SETMBR R0 K3 R3 - 0x90020804, // 0005 SETMBR R0 K4 R4 - 0x80000000, // 0006 RET 0 + ( &(const binstruction[25]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x4C080000, // 0001 LDNIL R2 + 0x1C040202, // 0002 EQ R1 R1 R2 + 0x74060003, // 0003 JMPT R1 #0008 + 0x88040101, // 0004 GETMBR R1 R0 K1 + 0x4C080000, // 0005 LDNIL R2 + 0x1C040202, // 0006 EQ R1 R1 R2 + 0x78060001, // 0007 JMPF R1 #000A + 0x4C040000, // 0008 LDNIL R1 + 0x80040200, // 0009 RET 1 R1 + 0xA4060400, // 000A IMPORT R1 K2 + 0x8C080303, // 000B GETMET R2 R1 K3 + 0x7C080200, // 000C CALL R2 1 + 0x600C0015, // 000D GETGBL R3 G21 + 0x7C0C0000, // 000E CALL R3 0 + 0x8C0C0704, // 000F GETMET R3 R3 K4 + 0x88140105, // 0010 GETMBR R5 R0 K5 + 0x7C0C0400, // 0011 CALL R3 2 + 0x8C100506, // 0012 GETMET R4 R2 K6 + 0x88180100, // 0013 GETMBR R6 R0 K0 + 0x881C0101, // 0014 GETMBR R7 R0 K1 + 0x5C200600, // 0015 MOVE R8 R3 + 0x5426000F, // 0016 LDINT R9 16 + 0x7C100A00, // 0017 CALL R4 5 + 0x80040800, // 0018 RET 1 R4 }) ) ); @@ -1145,9 +849,45 @@ be_local_closure(Matter_Session_set_keys, /* name */ /******************************************************************** -** Solidified function: get_noc +** Solidified function: get_pk ********************************************************************/ -be_local_closure(Matter_Session_get_noc, /* name */ +be_local_closure(Matter_Session_get_pk, /* name */ + be_nested_proto( + 5, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(no_private_key), + /* K1 */ be_nested_str_weak(crypto), + /* K2 */ be_nested_str_weak(random), + }), + be_str_weak(get_pk), + &be_const_str_solidified, + ( &(const binstruction[ 9]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x74060004, // 0001 JMPT R1 #0007 + 0xA4060200, // 0002 IMPORT R1 K1 + 0x8C080302, // 0003 GETMET R2 R1 K2 + 0x5412001F, // 0004 LDINT R4 32 + 0x7C080400, // 0005 CALL R2 2 + 0x90020002, // 0006 SETMBR R0 K0 R2 + 0x88040100, // 0007 GETMBR R1 R0 K0 + 0x80040200, // 0008 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_ac +********************************************************************/ +be_local_closure(Matter_Session_get_ac, /* name */ be_nested_proto( 2, /* nstack */ 1, /* argc */ @@ -1158,9 +898,9 @@ be_local_closure(Matter_Session_get_noc, /* name */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(noc), + /* K0 */ be_nested_str_weak(attestation_challenge), }), - be_str_weak(get_noc), + be_str_weak(get_ac), &be_const_str_solidified, ( &(const binstruction[ 2]) { /* code */ 0x88040100, // 0000 GETMBR R1 R0 K0 @@ -1171,67 +911,6 @@ be_local_closure(Matter_Session_get_noc, /* name */ /*******************************************************************/ -/******************************************************************** -** Solidified function: init -********************************************************************/ -be_local_closure(Matter_Session_init, /* name */ - be_nested_proto( - 6, /* nstack */ - 4, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[13]) { /* constants */ - /* K0 */ be_nested_str_weak(__store), - /* K1 */ be_nested_str_weak(mode), - /* K2 */ be_const_int(0), - /* K3 */ be_nested_str_weak(local_session_id), - /* K4 */ be_nested_str_weak(initiator_session_id), - /* K5 */ be_nested_str_weak(counter_rcv), - /* K6 */ be_nested_str_weak(matter), - /* K7 */ be_nested_str_weak(Counter), - /* K8 */ be_nested_str_weak(counter_snd), - /* K9 */ be_nested_str_weak(_counter_insecure_rcv), - /* K10 */ be_nested_str_weak(_counter_insecure_snd), - /* K11 */ be_nested_str_weak(breadcrumb), - /* K12 */ be_nested_str_weak(int64), - }), - be_str_weak(init), - &be_const_str_solidified, - ( &(const binstruction[24]) { /* code */ - 0x90020001, // 0000 SETMBR R0 K0 R1 - 0x90020302, // 0001 SETMBR R0 K1 K2 - 0x90020602, // 0002 SETMBR R0 K3 R2 - 0x90020803, // 0003 SETMBR R0 K4 R3 - 0xB8120C00, // 0004 GETNGBL R4 K6 - 0x8C100907, // 0005 GETMET R4 R4 K7 - 0x7C100200, // 0006 CALL R4 1 - 0x90020A04, // 0007 SETMBR R0 K5 R4 - 0xB8120C00, // 0008 GETNGBL R4 K6 - 0x8C100907, // 0009 GETMET R4 R4 K7 - 0x7C100200, // 000A CALL R4 1 - 0x90021004, // 000B SETMBR R0 K8 R4 - 0xB8120C00, // 000C GETNGBL R4 K6 - 0x8C100907, // 000D GETMET R4 R4 K7 - 0x7C100200, // 000E CALL R4 1 - 0x90021204, // 000F SETMBR R0 K9 R4 - 0xB8120C00, // 0010 GETNGBL R4 K6 - 0x8C100907, // 0011 GETMET R4 R4 K7 - 0x7C100200, // 0012 CALL R4 1 - 0x90021404, // 0013 SETMBR R0 K10 R4 - 0xB8121800, // 0014 GETNGBL R4 K12 - 0x7C100000, // 0015 CALL R4 0 - 0x90021604, // 0016 SETMBR R0 K11 R4 - 0x80000000, // 0017 RET 0 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified function: gen_CSR ********************************************************************/ @@ -1342,42 +1021,137 @@ be_local_closure(Matter_Session_gen_CSR, /* name */ /******************************************************************** -** Solidified function: set_expire_in_seconds +** Solidified function: set_persist ********************************************************************/ -be_local_closure(Matter_Session_set_expire_in_seconds, /* name */ +be_local_closure(Matter_Session_set_persist, /* name */ be_nested_proto( - 6, /* nstack */ - 3, /* argc */ + 4, /* nstack */ + 2, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 4]) { /* constants */ - /* K0 */ be_nested_str_weak(tasmota), - /* K1 */ be_nested_str_weak(rtc), - /* K2 */ be_nested_str_weak(utc), - /* K3 */ be_nested_str_weak(set_expire_time), + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(_persist), }), - be_str_weak(set_expire_in_seconds), + be_str_weak(set_persist), &be_const_str_solidified, - ( &(const binstruction[15]) { /* code */ - 0x4C0C0000, // 0000 LDNIL R3 - 0x1C0C0203, // 0001 EQ R3 R1 R3 - 0x780E0000, // 0002 JMPF R3 #0004 - 0x80000600, // 0003 RET 0 - 0x4C0C0000, // 0004 LDNIL R3 - 0x1C0C0403, // 0005 EQ R3 R2 R3 - 0x780E0003, // 0006 JMPF R3 #000B - 0xB80E0000, // 0007 GETNGBL R3 K0 - 0x8C0C0701, // 0008 GETMET R3 R3 K1 - 0x7C0C0200, // 0009 CALL R3 1 - 0x94080702, // 000A GETIDX R2 R3 K2 - 0x8C0C0103, // 000B GETMET R3 R0 K3 - 0x00140401, // 000C ADD R5 R2 R1 - 0x7C0C0400, // 000D CALL R3 2 - 0x80000000, // 000E RET 0 + ( &(const binstruction[ 5]) { /* code */ + 0x60080017, // 0000 GETGBL R2 G23 + 0x5C0C0200, // 0001 MOVE R3 R1 + 0x7C080200, // 0002 CALL R2 1 + 0x90020002, // 0003 SETMBR R0 K0 R2 + 0x80000000, // 0004 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_icac +********************************************************************/ +be_local_closure(Matter_Session_get_icac, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(icac), + }), + be_str_weak(get_icac), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_ca +********************************************************************/ +be_local_closure(Matter_Session_set_ca, /* name */ + be_nested_proto( + 2, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(root_ca_certificate), + }), + be_str_weak(set_ca), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x80000000, // 0001 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_fabric +********************************************************************/ +be_local_closure(Matter_Session_get_fabric, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(fabric), + }), + be_str_weak(get_fabric), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_i2r +********************************************************************/ +be_local_closure(Matter_Session_get_i2r, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(i2rkey), + }), + be_str_weak(get_i2r), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 }) ) ); @@ -1428,83 +1202,347 @@ be_local_closure(Matter_Session_has_expired, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: get_ca +********************************************************************/ +be_local_closure(Matter_Session_get_ca, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(root_ca_certificate), + }), + be_str_weak(get_ca), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_mode +********************************************************************/ +be_local_closure(Matter_Session_set_mode, /* name */ + be_nested_proto( + 2, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(mode), + }), + be_str_weak(set_mode), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x80000000, // 0001 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_Session_init, /* name */ + be_nested_proto( + 6, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[13]) { /* constants */ + /* K0 */ be_nested_str_weak(__store), + /* K1 */ be_nested_str_weak(mode), + /* K2 */ be_const_int(0), + /* K3 */ be_nested_str_weak(local_session_id), + /* K4 */ be_nested_str_weak(initiator_session_id), + /* K5 */ be_nested_str_weak(counter_rcv), + /* K6 */ be_nested_str_weak(matter), + /* K7 */ be_nested_str_weak(Counter), + /* K8 */ be_nested_str_weak(counter_snd), + /* K9 */ be_nested_str_weak(_counter_insecure_rcv), + /* K10 */ be_nested_str_weak(_counter_insecure_snd), + /* K11 */ be_nested_str_weak(breadcrumb), + /* K12 */ be_nested_str_weak(int64), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[24]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x90020302, // 0001 SETMBR R0 K1 K2 + 0x90020602, // 0002 SETMBR R0 K3 R2 + 0x90020803, // 0003 SETMBR R0 K4 R3 + 0xB8120C00, // 0004 GETNGBL R4 K6 + 0x8C100907, // 0005 GETMET R4 R4 K7 + 0x7C100200, // 0006 CALL R4 1 + 0x90020A04, // 0007 SETMBR R0 K5 R4 + 0xB8120C00, // 0008 GETNGBL R4 K6 + 0x8C100907, // 0009 GETMET R4 R4 K7 + 0x7C100200, // 000A CALL R4 1 + 0x90021004, // 000B SETMBR R0 K8 R4 + 0xB8120C00, // 000C GETNGBL R4 K6 + 0x8C100907, // 000D GETMET R4 R4 K7 + 0x7C100200, // 000E CALL R4 1 + 0x90021204, // 000F SETMBR R0 K9 R4 + 0xB8120C00, // 0010 GETNGBL R4 K6 + 0x8C100907, // 0011 GETMET R4 R4 K7 + 0x7C100200, // 0012 CALL R4 1 + 0x90021404, // 0013 SETMBR R0 K10 R4 + 0xB8121800, // 0014 GETNGBL R4 K12 + 0x7C100000, // 0015 CALL R4 0 + 0x90021604, // 0016 SETMBR R0 K11 R4 + 0x80000000, // 0017 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_i2r_privacy +********************************************************************/ +be_local_closure(Matter_Session_get_i2r_privacy, /* name */ + be_nested_proto( + 9, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 7]) { /* constants */ + /* K0 */ be_nested_str_weak(_i2r_privacy), + /* K1 */ be_nested_str_weak(crypto), + /* K2 */ be_nested_str_weak(HKDF_SHA256), + /* K3 */ be_nested_str_weak(derive), + /* K4 */ be_nested_str_weak(get_i2r), + /* K5 */ be_nested_str_weak(fromstring), + /* K6 */ be_nested_str_weak(PrivacyKey), + }), + be_str_weak(get_i2r_privacy), + &be_const_str_solidified, + ( &(const binstruction[22]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x4C080000, // 0001 LDNIL R2 + 0x1C040202, // 0002 EQ R1 R1 R2 + 0x7806000F, // 0003 JMPF R1 #0014 + 0xA4060200, // 0004 IMPORT R1 K1 + 0x8C080302, // 0005 GETMET R2 R1 K2 + 0x7C080200, // 0006 CALL R2 1 + 0x8C080503, // 0007 GETMET R2 R2 K3 + 0x8C100104, // 0008 GETMET R4 R0 K4 + 0x7C100200, // 0009 CALL R4 1 + 0x60140015, // 000A GETGBL R5 G21 + 0x7C140000, // 000B CALL R5 0 + 0x60180015, // 000C GETGBL R6 G21 + 0x7C180000, // 000D CALL R6 0 + 0x8C180D05, // 000E GETMET R6 R6 K5 + 0x58200006, // 000F LDCONST R8 K6 + 0x7C180400, // 0010 CALL R6 2 + 0x541E000F, // 0011 LDINT R7 16 + 0x7C080A00, // 0012 CALL R2 5 + 0x90020002, // 0013 SETMBR R0 K0 R2 + 0x88040100, // 0014 GETMBR R1 R0 K0 + 0x80040200, // 0015 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: save +********************************************************************/ +be_local_closure(Matter_Session_save, /* name */ + be_nested_proto( + 3, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(__store), + /* K1 */ be_nested_str_weak(save), + }), + be_str_weak(save), + &be_const_str_solidified, + ( &(const binstruction[ 4]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0x7C040200, // 0002 CALL R1 1 + 0x80000000, // 0003 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_no_expiration +********************************************************************/ +be_local_closure(Matter_Session_set_no_expiration, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(expiration), + }), + be_str_weak(set_no_expiration), + &be_const_str_solidified, + ( &(const binstruction[ 3]) { /* code */ + 0x4C040000, // 0000 LDNIL R1 + 0x90020001, // 0001 SETMBR R0 K0 R1 + 0x80000000, // 0002 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_keys +********************************************************************/ +be_local_closure(Matter_Session_set_keys, /* name */ + be_nested_proto( + 6, /* nstack */ + 5, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(i2rkey), + /* K1 */ be_nested_str_weak(_i2r_privacy), + /* K2 */ be_nested_str_weak(r2ikey), + /* K3 */ be_nested_str_weak(attestation_challenge), + /* K4 */ be_nested_str_weak(session_timestamp), + }), + be_str_weak(set_keys), + &be_const_str_solidified, + ( &(const binstruction[ 7]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x4C140000, // 0001 LDNIL R5 + 0x90020205, // 0002 SETMBR R0 K1 R5 + 0x90020402, // 0003 SETMBR R0 K2 R2 + 0x90020603, // 0004 SETMBR R0 K3 R3 + 0x90020804, // 0005 SETMBR R0 K4 R4 + 0x80000000, // 0006 RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified class: Matter_Session ********************************************************************/ be_local_class(Matter_Session, - 34, + 35, NULL, - be_nested_map(69, + be_nested_map(71, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(mode, -1), be_const_var(1) }, - { be_const_key_weak(shared_secret, 45), be_const_var(24) }, - { be_const_key_weak(set_ca, 68), be_const_closure(Matter_Session_set_ca_closure) }, - { be_const_key_weak(has_expired, -1), be_const_closure(Matter_Session_has_expired_closure) }, - { be_const_key_weak(ipk_epoch_key, 2), be_const_var(22) }, - { be_const_key_weak(breadcrumb, 34), be_const_var(17) }, - { be_const_key_weak(fromjson, -1), be_const_static_closure(Matter_Session_fromjson_closure) }, - { be_const_key_weak(counter_rcv, -1), be_const_var(8) }, - { be_const_key_weak(_Msg1, 6), be_const_var(30) }, - { be_const_key_weak(noc, -1), be_const_var(20) }, - { be_const_key_weak(__PASE, -1), be_const_int(1) }, - { be_const_key_weak(get_deviceid, -1), be_const_closure(Matter_Session_get_deviceid_closure) }, - { be_const_key_weak(_i2r_privacy, 4), be_const_var(14) }, - { be_const_key_weak(counter_snd, -1), be_const_var(9) }, - { be_const_key_weak(set_no_expiration, -1), be_const_closure(Matter_Session_set_no_expiration_closure) }, - { be_const_key_weak(_Msg2, 67), be_const_var(31) }, - { be_const_key_weak(gen_CSR, -1), be_const_closure(Matter_Session_gen_CSR_closure) }, - { be_const_key_weak(set_fabric_device, 18), be_const_closure(Matter_Session_set_fabric_device_closure) }, - { be_const_key_weak(fabric_compressed, -1), be_const_var(26) }, - { be_const_key_weak(get_fabric_compressed, 56), be_const_closure(Matter_Session_get_fabric_compressed_closure) }, - { be_const_key_weak(_counter_insecure_snd, 21), be_const_var(11) }, - { be_const_key_weak(get_noc, 64), be_const_closure(Matter_Session_get_noc_closure) }, - { be_const_key_weak(_future_local_session_id, 11), be_const_var(7) }, - { be_const_key_weak(r2ikey, -1), be_const_var(13) }, - { be_const_key_weak(get_pk, 1), be_const_closure(Matter_Session_get_pk_closure) }, - { be_const_key_weak(set_keys, -1), be_const_closure(Matter_Session_set_keys_closure) }, - { be_const_key_weak(tojson, -1), be_const_closure(Matter_Session_tojson_closure) }, - { be_const_key_weak(set_expire_time, -1), be_const_closure(Matter_Session_set_expire_time_closure) }, - { be_const_key_weak(get_i2r_privacy, -1), be_const_closure(Matter_Session_get_i2r_privacy_closure) }, - { be_const_key_weak(_persist, -1), be_const_var(32) }, - { be_const_key_weak(save, -1), be_const_closure(Matter_Session_save_closure) }, - { be_const_key_weak(root_ca_certificate, -1), be_const_var(19) }, - { be_const_key_weak(set_mode, -1), be_const_closure(Matter_Session_set_mode_closure) }, - { be_const_key_weak(get_r2i, 59), be_const_closure(Matter_Session_get_r2i_closure) }, - { be_const_key_weak(peer_node_id, -1), be_const_var(16) }, - { be_const_key_weak(__store, 23), be_const_var(0) }, - { be_const_key_weak(admin_vendor, -1), be_const_var(29) }, - { be_const_key_weak(set_ipk_epoch_key, -1), be_const_closure(Matter_Session_set_ipk_epoch_key_closure) }, - { be_const_key_weak(set_noc, -1), be_const_closure(Matter_Session_set_noc_closure) }, - { be_const_key_weak(close, -1), be_const_closure(Matter_Session_close_closure) }, - { be_const_key_weak(get_mode, -1), be_const_closure(Matter_Session_get_mode_closure) }, - { be_const_key_weak(get_ca, -1), be_const_closure(Matter_Session_get_ca_closure) }, - { be_const_key_weak(i2rkey, 50), be_const_var(12) }, - { be_const_key_weak(_future_initiator_session_id, 46), be_const_var(6) }, - { be_const_key_weak(get_ac, -1), be_const_closure(Matter_Session_get_ac_closure) }, - { be_const_key_weak(get_ca_pub, 54), be_const_closure(Matter_Session_get_ca_pub_closure) }, + { be_const_key_weak(get_ca_pub, -1), be_const_closure(Matter_Session_get_ca_pub_closure) }, { be_const_key_weak(source_node_id, -1), be_const_var(5) }, - { be_const_key_weak(resumption_id, 43), be_const_var(23) }, - { be_const_key_weak(get_ipk_epoch_key, 0), be_const_closure(Matter_Session_get_ipk_epoch_key_closure) }, - { be_const_key_weak(session_timestamp, 44), be_const_var(4) }, - { be_const_key_weak(icac, 30), be_const_var(21) }, - { be_const_key_weak(initiator_session_id, -1), be_const_var(3) }, - { be_const_key_weak(set_persist, 38), be_const_closure(Matter_Session_set_persist_closure) }, - { be_const_key_weak(__CASE, 36), be_const_int(2) }, - { be_const_key_weak(expiration, -1), be_const_var(33) }, - { be_const_key_weak(get_i2r, -1), be_const_closure(Matter_Session_get_i2r_closure) }, - { be_const_key_weak(no_private_key, 28), be_const_var(18) }, - { be_const_key_weak(admin_subject, 25), be_const_var(28) }, - { be_const_key_weak(deviceid, -1), be_const_var(27) }, - { be_const_key_weak(get_icac, 39), be_const_closure(Matter_Session_get_icac_closure) }, - { be_const_key_weak(init, -1), be_const_closure(Matter_Session_init_closure) }, - { be_const_key_weak(fabric, 16), be_const_var(25) }, + { be_const_key_weak(breadcrumb, -1), be_const_var(17) }, + { be_const_key_weak(set_expire_time, 55), be_const_closure(Matter_Session_set_expire_time_closure) }, + { be_const_key_weak(attestation_challenge, 70), be_const_var(15) }, + { be_const_key_weak(set_no_expiration, -1), be_const_closure(Matter_Session_set_no_expiration_closure) }, + { be_const_key_weak(_i2r_privacy, 51), be_const_var(14) }, { be_const_key_weak(set_expire_in_seconds, -1), be_const_closure(Matter_Session_set_expire_in_seconds_closure) }, + { be_const_key_weak(set_ipk_epoch_key, -1), be_const_closure(Matter_Session_set_ipk_epoch_key_closure) }, + { be_const_key_weak(deviceid, -1), be_const_var(27) }, + { be_const_key_weak(get_noc, -1), be_const_closure(Matter_Session_get_noc_closure) }, + { be_const_key_weak(tojson, -1), be_const_closure(Matter_Session_tojson_closure) }, + { be_const_key_weak(save, -1), be_const_closure(Matter_Session_save_closure) }, + { be_const_key_weak(get_i2r_privacy, 43), be_const_closure(Matter_Session_get_i2r_privacy_closure) }, + { be_const_key_weak(set_fabric_device, -1), be_const_closure(Matter_Session_set_fabric_device_closure) }, + { be_const_key_weak(get_deviceid, -1), be_const_closure(Matter_Session_get_deviceid_closure) }, + { be_const_key_weak(r2ikey, -1), be_const_var(13) }, + { be_const_key_weak(fromjson, 2), be_const_static_closure(Matter_Session_fromjson_closure) }, + { be_const_key_weak(set_fabric_label, -1), be_const_closure(Matter_Session_set_fabric_label_closure) }, + { be_const_key_weak(no_private_key, 50), be_const_var(18) }, + { be_const_key_weak(i2rkey, -1), be_const_var(12) }, + { be_const_key_weak(__CASE, -1), be_const_int(2) }, + { be_const_key_weak(local_session_id, 20), be_const_var(2) }, + { be_const_key_weak(set_noc, -1), be_const_closure(Matter_Session_set_noc_closure) }, + { be_const_key_weak(get_mode, 27), be_const_closure(Matter_Session_get_mode_closure) }, + { be_const_key_weak(peer_node_id, 66), be_const_var(16) }, + { be_const_key_weak(_persist, 19), be_const_var(33) }, + { be_const_key_weak(set_persist, -1), be_const_closure(Matter_Session_set_persist_closure) }, + { be_const_key_weak(initiator_session_id, -1), be_const_var(3) }, + { be_const_key_weak(set_ca, 28), be_const_closure(Matter_Session_set_ca_closure) }, + { be_const_key_weak(get_ipk_epoch_key, 41), be_const_closure(Matter_Session_get_ipk_epoch_key_closure) }, + { be_const_key_weak(_future_initiator_session_id, 22), be_const_var(6) }, + { be_const_key_weak(get_ipk_group_key, 39), be_const_closure(Matter_Session_get_ipk_group_key_closure) }, + { be_const_key_weak(get_pk, 56), be_const_closure(Matter_Session_get_pk_closure) }, + { be_const_key_weak(get_ac, -1), be_const_closure(Matter_Session_get_ac_closure) }, + { be_const_key_weak(gen_CSR, 1), be_const_closure(Matter_Session_gen_CSR_closure) }, + { be_const_key_weak(set_mode, -1), be_const_closure(Matter_Session_set_mode_closure) }, + { be_const_key_weak(resumption_id, 29), be_const_var(23) }, + { be_const_key_weak(get_icac, -1), be_const_closure(Matter_Session_get_icac_closure) }, + { be_const_key_weak(_Msg1, -1), be_const_var(31) }, + { be_const_key_weak(__PASE, -1), be_const_int(1) }, + { be_const_key_weak(get_ca, -1), be_const_closure(Matter_Session_get_ca_closure) }, + { be_const_key_weak(root_ca_certificate, -1), be_const_var(19) }, + { be_const_key_weak(expiration, -1), be_const_var(34) }, + { be_const_key_weak(get_fabric, -1), be_const_closure(Matter_Session_get_fabric_closure) }, + { be_const_key_weak(fabric_label, -1), be_const_var(28) }, + { be_const_key_weak(_future_local_session_id, -1), be_const_var(7) }, + { be_const_key_weak(close, 45), be_const_closure(Matter_Session_close_closure) }, + { be_const_key_weak(admin_vendor, 64), be_const_var(30) }, + { be_const_key_weak(icac, -1), be_const_var(21) }, + { be_const_key_weak(counter_snd, 48), be_const_var(9) }, + { be_const_key_weak(get_i2r, 63), be_const_closure(Matter_Session_get_i2r_closure) }, + { be_const_key_weak(has_expired, -1), be_const_closure(Matter_Session_has_expired_closure) }, + { be_const_key_weak(__GROUP_KEY, 12), be_nested_str_weak(GroupKey_X20v1_X2E0) }, + { be_const_key_weak(session_timestamp, -1), be_const_var(4) }, + { be_const_key_weak(shared_secret, -1), be_const_var(24) }, + { be_const_key_weak(fabric_compressed, -1), be_const_var(26) }, + { be_const_key_weak(get_fabric_compressed, 36), be_const_closure(Matter_Session_get_fabric_compressed_closure) }, + { be_const_key_weak(noc, 16), be_const_var(20) }, { be_const_key_weak(_counter_insecure_rcv, -1), be_const_var(10) }, - { be_const_key_weak(get_ipk_group_key, -1), be_const_closure(Matter_Session_get_ipk_group_key_closure) }, - { be_const_key_weak(get_fabric, 3), be_const_closure(Matter_Session_get_fabric_closure) }, - { be_const_key_weak(local_session_id, -1), be_const_var(2) }, - { be_const_key_weak(attestation_challenge, -1), be_const_var(15) }, - { be_const_key_weak(__GROUP_KEY, -1), be_nested_str_weak(GroupKey_X20v1_X2E0) }, + { be_const_key_weak(admin_subject, -1), be_const_var(29) }, + { be_const_key_weak(init, -1), be_const_closure(Matter_Session_init_closure) }, + { be_const_key_weak(ipk_epoch_key, -1), be_const_var(22) }, + { be_const_key_weak(counter_rcv, -1), be_const_var(8) }, + { be_const_key_weak(fabric, -1), be_const_var(25) }, + { be_const_key_weak(__store, 13), be_const_var(0) }, + { be_const_key_weak(mode, -1), be_const_var(1) }, + { be_const_key_weak(_counter_insecure_snd, 6), be_const_var(11) }, + { be_const_key_weak(_Msg2, 5), be_const_var(32) }, + { be_const_key_weak(set_keys, -1), be_const_closure(Matter_Session_set_keys_closure) }, + { be_const_key_weak(get_r2i, -1), be_const_closure(Matter_Session_get_r2i_closure) }, })), be_str_weak(Matter_Session) ); @@ -1518,34 +1556,6 @@ void be_load_Matter_Session_class(bvm *vm) { extern const bclass be_class_Matter_Session_Store; -/******************************************************************** -** Solidified function: every_second -********************************************************************/ -be_local_closure(Matter_Session_Store_every_second, /* name */ - be_nested_proto( - 3, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(remove_expired), - }), - be_str_weak(every_second), - &be_const_str_solidified, - ( &(const binstruction[ 3]) { /* code */ - 0x8C040100, // 0000 GETMET R1 R0 K0 - 0x7C040200, // 0001 CALL R1 1 - 0x80000000, // 0002 RET 0 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified function: remove_redundant_session ********************************************************************/ @@ -1602,11 +1612,160 @@ be_local_closure(Matter_Session_Store_remove_redundant_session, /* name */ /******************************************************************** -** Solidified function: get_session_by_source_node_id +** Solidified function: init ********************************************************************/ -be_local_closure(Matter_Session_Store_get_session_by_source_node_id, /* name */ +be_local_closure(Matter_Session_Store_init, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(sessions), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[ 4]) { /* code */ + 0x60040012, // 0000 GETGBL R1 G18 + 0x7C040000, // 0001 CALL R1 0 + 0x90020001, // 0002 SETMBR R0 K0 R1 + 0x80000000, // 0003 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: find_session_source_id_unsecure +********************************************************************/ +be_local_closure(Matter_Session_Store_find_session_source_id_unsecure, /* name */ + be_nested_proto( + 9, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(get_session_by_source_node_id), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(Session), + /* K3 */ be_const_int(0), + /* K4 */ be_nested_str_weak(source_node_id), + /* K5 */ be_nested_str_weak(sessions), + /* K6 */ be_nested_str_weak(push), + /* K7 */ be_nested_str_weak(set_expire_in_seconds), + }), + be_str_weak(find_session_source_id_unsecure), + &be_const_str_solidified, + ( &(const binstruction[22]) { /* code */ + 0x8C0C0100, // 0000 GETMET R3 R0 K0 + 0x5C140200, // 0001 MOVE R5 R1 + 0x7C0C0400, // 0002 CALL R3 2 + 0x4C100000, // 0003 LDNIL R4 + 0x1C100604, // 0004 EQ R4 R3 R4 + 0x7812000B, // 0005 JMPF R4 #0012 + 0xB8120200, // 0006 GETNGBL R4 K1 + 0x8C100902, // 0007 GETMET R4 R4 K2 + 0x5C180000, // 0008 MOVE R6 R0 + 0x581C0003, // 0009 LDCONST R7 K3 + 0x58200003, // 000A LDCONST R8 K3 + 0x7C100800, // 000B CALL R4 4 + 0x5C0C0800, // 000C MOVE R3 R4 + 0x900E0801, // 000D SETMBR R3 K4 R1 + 0x88100105, // 000E GETMBR R4 R0 K5 + 0x8C100906, // 000F GETMET R4 R4 K6 + 0x5C180600, // 0010 MOVE R6 R3 + 0x7C100400, // 0011 CALL R4 2 + 0x8C100707, // 0012 GETMET R4 R3 K7 + 0x5C180400, // 0013 MOVE R6 R2 + 0x7C100400, // 0014 CALL R4 2 + 0x80040600, // 0015 RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: add_session +********************************************************************/ +be_local_closure(Matter_Session_Store_add_session, /* name */ be_nested_proto( 6, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(set_expire_in_seconds), + /* K1 */ be_nested_str_weak(sessions), + /* K2 */ be_nested_str_weak(push), + }), + be_str_weak(add_session), + &be_const_str_solidified, + ( &(const binstruction[11]) { /* code */ + 0x4C0C0000, // 0000 LDNIL R3 + 0x200C0403, // 0001 NE R3 R2 R3 + 0x780E0002, // 0002 JMPF R3 #0006 + 0x8C0C0300, // 0003 GETMET R3 R1 K0 + 0x5C140400, // 0004 MOVE R5 R2 + 0x7C0C0400, // 0005 CALL R3 2 + 0x880C0101, // 0006 GETMBR R3 R0 K1 + 0x8C0C0702, // 0007 GETMET R3 R3 K2 + 0x5C140200, // 0008 MOVE R5 R1 + 0x7C0C0400, // 0009 CALL R3 2 + 0x80000000, // 000A RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: every_second +********************************************************************/ +be_local_closure(Matter_Session_Store_every_second, /* name */ + be_nested_proto( + 3, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(remove_expired), + }), + be_str_weak(every_second), + &be_const_str_solidified, + ( &(const binstruction[ 3]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x7C040200, // 0001 CALL R1 1 + 0x80000000, // 0002 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: remove_session +********************************************************************/ +be_local_closure(Matter_Session_Store_remove_session, /* name */ + be_nested_proto( + 7, /* nstack */ 2, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -1615,35 +1774,31 @@ be_local_closure(Matter_Session_Store_get_session_by_source_node_id, /* name * NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 4]) { /* constants */ - /* K0 */ be_nested_str_weak(sessions), - /* K1 */ be_const_int(0), - /* K2 */ be_nested_str_weak(source_node_id), + /* K0 */ be_const_int(0), + /* K1 */ be_nested_str_weak(sessions), + /* K2 */ be_nested_str_weak(remove), /* K3 */ be_const_int(1), }), - be_str_weak(get_session_by_source_node_id), + be_str_weak(remove_session), &be_const_str_solidified, - ( &(const binstruction[21]) { /* code */ - 0x4C080000, // 0000 LDNIL R2 - 0x1C080202, // 0001 EQ R2 R1 R2 - 0x780A0001, // 0002 JMPF R2 #0005 - 0x4C080000, // 0003 LDNIL R2 - 0x80040400, // 0004 RET 1 R2 - 0x6008000C, // 0005 GETGBL R2 G12 - 0x880C0100, // 0006 GETMBR R3 R0 K0 - 0x7C080200, // 0007 CALL R2 1 - 0x580C0001, // 0008 LDCONST R3 K1 - 0x88100100, // 0009 GETMBR R4 R0 K0 - 0x14140602, // 000A LT R5 R3 R2 - 0x78160007, // 000B JMPF R5 #0014 - 0x94140803, // 000C GETIDX R5 R4 R3 - 0x88140B02, // 000D GETMBR R5 R5 K2 - 0x1C140A01, // 000E EQ R5 R5 R1 - 0x78160001, // 000F JMPF R5 #0012 - 0x94140803, // 0010 GETIDX R5 R4 R3 - 0x80040A00, // 0011 RET 1 R5 - 0x000C0703, // 0012 ADD R3 R3 K3 - 0x7001FFF5, // 0013 JMP #000A - 0x80000000, // 0014 RET 0 + ( &(const binstruction[17]) { /* code */ + 0x58080000, // 0000 LDCONST R2 K0 + 0x880C0101, // 0001 GETMBR R3 R0 K1 + 0x6010000C, // 0002 GETGBL R4 G12 + 0x88140101, // 0003 GETMBR R5 R0 K1 + 0x7C100200, // 0004 CALL R4 1 + 0x14100404, // 0005 LT R4 R2 R4 + 0x78120008, // 0006 JMPF R4 #0010 + 0x94100602, // 0007 GETIDX R4 R3 R2 + 0x1C100801, // 0008 EQ R4 R4 R1 + 0x78120003, // 0009 JMPF R4 #000E + 0x8C100702, // 000A GETMET R4 R3 K2 + 0x5C180400, // 000B MOVE R6 R2 + 0x7C100400, // 000C CALL R4 2 + 0x70020000, // 000D JMP #000F + 0x00080503, // 000E ADD R2 R2 K3 + 0x7001FFF1, // 000F JMP #0002 + 0x80000000, // 0010 RET 0 }) ) ); @@ -1707,6 +1862,125 @@ be_local_closure(Matter_Session_Store_remove_expired, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: save +********************************************************************/ +be_local_closure(Matter_Session_Store_save, /* name */ + be_nested_proto( + 12, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[23]) { /* constants */ + /* K0 */ be_nested_str_weak(json), + /* K1 */ be_nested_str_weak(remove_expired), + /* K2 */ be_nested_str_weak(sessions), + /* K3 */ be_nested_str_weak(_persist), + /* K4 */ be_nested_str_weak(push), + /* K5 */ be_nested_str_weak(tojson), + /* K6 */ be_nested_str_weak(stop_iteration), + /* K7 */ be_nested_str_weak(_X5B), + /* K8 */ be_nested_str_weak(concat), + /* K9 */ be_nested_str_weak(_X2C), + /* K10 */ be_nested_str_weak(_X5D), + /* K11 */ be_nested_str_weak(string), + /* K12 */ be_nested_str_weak(FILENAME), + /* K13 */ be_nested_str_weak(w), + /* K14 */ be_nested_str_weak(write), + /* K15 */ be_nested_str_weak(close), + /* K16 */ be_nested_str_weak(tasmota), + /* K17 */ be_nested_str_weak(log), + /* K18 */ be_nested_str_weak(format), + /* K19 */ be_nested_str_weak(MTR_X3A_X20Saved_X20_X25i_X20session_X28s_X29), + /* K20 */ be_const_int(2), + /* K21 */ be_nested_str_weak(MTR_X3A_X20Session_Store_X3A_X3Asave_X20Exception_X3A), + /* K22 */ be_nested_str_weak(_X7C), + }), + be_str_weak(save), + &be_const_str_solidified, + ( &(const binstruction[72]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x8C080101, // 0001 GETMET R2 R0 K1 + 0x7C080200, // 0002 CALL R2 1 + 0x60080012, // 0003 GETGBL R2 G18 + 0x7C080000, // 0004 CALL R2 0 + 0x600C0010, // 0005 GETGBL R3 G16 + 0x88100102, // 0006 GETMBR R4 R0 K2 + 0x7C0C0200, // 0007 CALL R3 1 + 0xA8020008, // 0008 EXBLK 0 #0012 + 0x5C100600, // 0009 MOVE R4 R3 + 0x7C100000, // 000A CALL R4 0 + 0x88140903, // 000B GETMBR R5 R4 K3 + 0x78160003, // 000C JMPF R5 #0011 + 0x8C140504, // 000D GETMET R5 R2 K4 + 0x8C1C0905, // 000E GETMET R7 R4 K5 + 0x7C1C0200, // 000F CALL R7 1 + 0x7C140400, // 0010 CALL R5 2 + 0x7001FFF6, // 0011 JMP #0009 + 0x580C0006, // 0012 LDCONST R3 K6 + 0xAC0C0200, // 0013 CATCH R3 1 0 + 0xB0080000, // 0014 RAISE 2 R0 R0 + 0x600C000C, // 0015 GETGBL R3 G12 + 0x5C100400, // 0016 MOVE R4 R2 + 0x7C0C0200, // 0017 CALL R3 1 + 0x8C100508, // 0018 GETMET R4 R2 K8 + 0x58180009, // 0019 LDCONST R6 K9 + 0x7C100400, // 001A CALL R4 2 + 0x00120E04, // 001B ADD R4 K7 R4 + 0x0010090A, // 001C ADD R4 R4 K10 + 0x5C080800, // 001D MOVE R2 R4 + 0xA8020015, // 001E EXBLK 0 #0035 + 0xA4121600, // 001F IMPORT R4 K11 + 0x60140011, // 0020 GETGBL R5 G17 + 0x8818010C, // 0021 GETMBR R6 R0 K12 + 0x581C000D, // 0022 LDCONST R7 K13 + 0x7C140400, // 0023 CALL R5 2 + 0x8C180B0E, // 0024 GETMET R6 R5 K14 + 0x5C200400, // 0025 MOVE R8 R2 + 0x7C180400, // 0026 CALL R6 2 + 0x8C180B0F, // 0027 GETMET R6 R5 K15 + 0x7C180200, // 0028 CALL R6 1 + 0xB81A2000, // 0029 GETNGBL R6 K16 + 0x8C180D11, // 002A GETMET R6 R6 K17 + 0x8C200912, // 002B GETMET R8 R4 K18 + 0x58280013, // 002C LDCONST R10 K19 + 0x5C2C0600, // 002D MOVE R11 R3 + 0x7C200600, // 002E CALL R8 3 + 0x58240014, // 002F LDCONST R9 K20 + 0x7C180600, // 0030 CALL R6 3 + 0xA8040001, // 0031 EXBLK 1 1 + 0x80040400, // 0032 RET 1 R2 + 0xA8040001, // 0033 EXBLK 1 1 + 0x70020011, // 0034 JMP #0047 + 0xAC100002, // 0035 CATCH R4 0 2 + 0x7002000E, // 0036 JMP #0046 + 0xB81A2000, // 0037 GETNGBL R6 K16 + 0x8C180D11, // 0038 GETMET R6 R6 K17 + 0x60200008, // 0039 GETGBL R8 G8 + 0x5C240800, // 003A MOVE R9 R4 + 0x7C200200, // 003B CALL R8 1 + 0x00222A08, // 003C ADD R8 K21 R8 + 0x00201116, // 003D ADD R8 R8 K22 + 0x60240008, // 003E GETGBL R9 G8 + 0x5C280A00, // 003F MOVE R10 R5 + 0x7C240200, // 0040 CALL R9 1 + 0x00201009, // 0041 ADD R8 R8 R9 + 0x58240014, // 0042 LDCONST R9 K20 + 0x7C180600, // 0043 CALL R6 3 + 0x80040400, // 0044 RET 1 R2 + 0x70020000, // 0045 JMP #0047 + 0xB0080000, // 0046 RAISE 2 R0 R0 + 0x80000000, // 0047 RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: load ********************************************************************/ @@ -1830,85 +2104,11 @@ be_local_closure(Matter_Session_Store_load, /* name */ /******************************************************************** -** Solidified function: init +** Solidified function: create_session ********************************************************************/ -be_local_closure(Matter_Session_Store_init, /* name */ +be_local_closure(Matter_Session_Store_create_session, /* name */ be_nested_proto( - 2, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(sessions), - }), - be_str_weak(init), - &be_const_str_solidified, - ( &(const binstruction[ 4]) { /* code */ - 0x60040012, // 0000 GETGBL R1 G18 - 0x7C040000, // 0001 CALL R1 0 - 0x90020001, // 0002 SETMBR R0 K0 R1 - 0x80000000, // 0003 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: remove_session -********************************************************************/ -be_local_closure(Matter_Session_Store_remove_session, /* name */ - be_nested_proto( - 7, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 4]) { /* constants */ - /* K0 */ be_const_int(0), - /* K1 */ be_nested_str_weak(sessions), - /* K2 */ be_nested_str_weak(remove), - /* K3 */ be_const_int(1), - }), - be_str_weak(remove_session), - &be_const_str_solidified, - ( &(const binstruction[17]) { /* code */ - 0x58080000, // 0000 LDCONST R2 K0 - 0x880C0101, // 0001 GETMBR R3 R0 K1 - 0x6010000C, // 0002 GETGBL R4 G12 - 0x88140101, // 0003 GETMBR R5 R0 K1 - 0x7C100200, // 0004 CALL R4 1 - 0x14100404, // 0005 LT R4 R2 R4 - 0x78120008, // 0006 JMPF R4 #0010 - 0x94100602, // 0007 GETIDX R4 R3 R2 - 0x1C100801, // 0008 EQ R4 R4 R1 - 0x78120003, // 0009 JMPF R4 #000E - 0x8C100702, // 000A GETMET R4 R3 K2 - 0x5C180400, // 000B MOVE R6 R2 - 0x7C100400, // 000C CALL R4 2 - 0x70020000, // 000D JMP #000F - 0x00080503, // 000E ADD R2 R2 K3 - 0x7001FFF1, // 000F JMP #0002 - 0x80000000, // 0010 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: add_session -********************************************************************/ -be_local_closure(Matter_Session_Store_add_session, /* name */ - be_nested_proto( - 6, /* nstack */ + 9, /* nstack */ 3, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -1916,25 +2116,90 @@ be_local_closure(Matter_Session_Store_add_session, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_nested_str_weak(set_expire_in_seconds), - /* K1 */ be_nested_str_weak(sessions), - /* K2 */ be_nested_str_weak(push), + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(get_session_by_local_session_id), + /* K1 */ be_nested_str_weak(remove_session), + /* K2 */ be_nested_str_weak(matter), + /* K3 */ be_nested_str_weak(Session), + /* K4 */ be_nested_str_weak(sessions), + /* K5 */ be_nested_str_weak(push), }), - be_str_weak(add_session), + be_str_weak(create_session), &be_const_str_solidified, - ( &(const binstruction[11]) { /* code */ - 0x4C0C0000, // 0000 LDNIL R3 - 0x200C0403, // 0001 NE R3 R2 R3 - 0x780E0002, // 0002 JMPF R3 #0006 - 0x8C0C0300, // 0003 GETMET R3 R1 K0 - 0x5C140400, // 0004 MOVE R5 R2 - 0x7C0C0400, // 0005 CALL R3 2 - 0x880C0101, // 0006 GETMBR R3 R0 K1 - 0x8C0C0702, // 0007 GETMET R3 R3 K2 - 0x5C140200, // 0008 MOVE R5 R1 - 0x7C0C0400, // 0009 CALL R3 2 - 0x80000000, // 000A RET 0 + ( &(const binstruction[21]) { /* code */ + 0x8C0C0100, // 0000 GETMET R3 R0 K0 + 0x5C140200, // 0001 MOVE R5 R1 + 0x7C0C0400, // 0002 CALL R3 2 + 0x4C100000, // 0003 LDNIL R4 + 0x20100604, // 0004 NE R4 R3 R4 + 0x78120002, // 0005 JMPF R4 #0009 + 0x8C100101, // 0006 GETMET R4 R0 K1 + 0x5C180600, // 0007 MOVE R6 R3 + 0x7C100400, // 0008 CALL R4 2 + 0xB8120400, // 0009 GETNGBL R4 K2 + 0x8C100903, // 000A GETMET R4 R4 K3 + 0x5C180000, // 000B MOVE R6 R0 + 0x5C1C0200, // 000C MOVE R7 R1 + 0x5C200400, // 000D MOVE R8 R2 + 0x7C100800, // 000E CALL R4 4 + 0x5C0C0800, // 000F MOVE R3 R4 + 0x88100104, // 0010 GETMBR R4 R0 K4 + 0x8C100905, // 0011 GETMET R4 R4 K5 + 0x5C180600, // 0012 MOVE R6 R3 + 0x7C100400, // 0013 CALL R4 2 + 0x80040600, // 0014 RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: sessions_active +********************************************************************/ +be_local_closure(Matter_Session_Store_sessions_active, /* name */ + be_nested_proto( + 7, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_const_int(0), + /* K1 */ be_nested_str_weak(sessions), + /* K2 */ be_nested_str_weak(get_deviceid), + /* K3 */ be_nested_str_weak(get_fabric), + /* K4 */ be_nested_str_weak(push), + /* K5 */ be_const_int(1), + }), + be_str_weak(sessions_active), + &be_const_str_solidified, + ( &(const binstruction[22]) { /* code */ + 0x60040012, // 0000 GETGBL R1 G18 + 0x7C040000, // 0001 CALL R1 0 + 0x58080000, // 0002 LDCONST R2 K0 + 0x600C000C, // 0003 GETGBL R3 G12 + 0x88100101, // 0004 GETMBR R4 R0 K1 + 0x7C0C0200, // 0005 CALL R3 1 + 0x140C0403, // 0006 LT R3 R2 R3 + 0x780E000C, // 0007 JMPF R3 #0015 + 0x880C0101, // 0008 GETMBR R3 R0 K1 + 0x940C0602, // 0009 GETIDX R3 R3 R2 + 0x8C100702, // 000A GETMET R4 R3 K2 + 0x7C100200, // 000B CALL R4 1 + 0x78120005, // 000C JMPF R4 #0013 + 0x8C100703, // 000D GETMET R4 R3 K3 + 0x7C100200, // 000E CALL R4 1 + 0x78120002, // 000F JMPF R4 #0013 + 0x8C100304, // 0010 GETMET R4 R1 K4 + 0x5C180600, // 0011 MOVE R6 R3 + 0x7C100400, // 0012 CALL R4 2 + 0x00080505, // 0013 ADD R2 R2 K5 + 0x7001FFED, // 0014 JMP #0003 + 0x80040200, // 0015 RET 1 R1 }) ) ); @@ -1990,179 +2255,6 @@ be_local_closure(Matter_Session_Store_get_session_by_local_session_id, /* name /*******************************************************************/ -/******************************************************************** -** Solidified function: find_session_source_id_unsecure -********************************************************************/ -be_local_closure(Matter_Session_Store_find_session_source_id_unsecure, /* name */ - be_nested_proto( - 9, /* nstack */ - 3, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 8]) { /* constants */ - /* K0 */ be_nested_str_weak(get_session_by_source_node_id), - /* K1 */ be_nested_str_weak(matter), - /* K2 */ be_nested_str_weak(Session), - /* K3 */ be_const_int(0), - /* K4 */ be_nested_str_weak(source_node_id), - /* K5 */ be_nested_str_weak(sessions), - /* K6 */ be_nested_str_weak(push), - /* K7 */ be_nested_str_weak(set_expire_in_seconds), - }), - be_str_weak(find_session_source_id_unsecure), - &be_const_str_solidified, - ( &(const binstruction[22]) { /* code */ - 0x8C0C0100, // 0000 GETMET R3 R0 K0 - 0x5C140200, // 0001 MOVE R5 R1 - 0x7C0C0400, // 0002 CALL R3 2 - 0x4C100000, // 0003 LDNIL R4 - 0x1C100604, // 0004 EQ R4 R3 R4 - 0x7812000B, // 0005 JMPF R4 #0012 - 0xB8120200, // 0006 GETNGBL R4 K1 - 0x8C100902, // 0007 GETMET R4 R4 K2 - 0x5C180000, // 0008 MOVE R6 R0 - 0x581C0003, // 0009 LDCONST R7 K3 - 0x58200003, // 000A LDCONST R8 K3 - 0x7C100800, // 000B CALL R4 4 - 0x5C0C0800, // 000C MOVE R3 R4 - 0x900E0801, // 000D SETMBR R3 K4 R1 - 0x88100105, // 000E GETMBR R4 R0 K5 - 0x8C100906, // 000F GETMET R4 R4 K6 - 0x5C180600, // 0010 MOVE R6 R3 - 0x7C100400, // 0011 CALL R4 2 - 0x8C100707, // 0012 GETMET R4 R3 K7 - 0x5C180400, // 0013 MOVE R6 R2 - 0x7C100400, // 0014 CALL R4 2 - 0x80040600, // 0015 RET 1 R3 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: save -********************************************************************/ -be_local_closure(Matter_Session_Store_save, /* name */ - be_nested_proto( - 12, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[23]) { /* constants */ - /* K0 */ be_nested_str_weak(json), - /* K1 */ be_nested_str_weak(remove_expired), - /* K2 */ be_nested_str_weak(sessions), - /* K3 */ be_nested_str_weak(_persist), - /* K4 */ be_nested_str_weak(push), - /* K5 */ be_nested_str_weak(tojson), - /* K6 */ be_nested_str_weak(stop_iteration), - /* K7 */ be_nested_str_weak(_X5B), - /* K8 */ be_nested_str_weak(concat), - /* K9 */ be_nested_str_weak(_X2C), - /* K10 */ be_nested_str_weak(_X5D), - /* K11 */ be_nested_str_weak(string), - /* K12 */ be_nested_str_weak(FILENAME), - /* K13 */ be_nested_str_weak(w), - /* K14 */ be_nested_str_weak(write), - /* K15 */ be_nested_str_weak(close), - /* K16 */ be_nested_str_weak(tasmota), - /* K17 */ be_nested_str_weak(log), - /* K18 */ be_nested_str_weak(format), - /* K19 */ be_nested_str_weak(MTR_X3A_X20Saved_X20_X25i_X20session_X28s_X29), - /* K20 */ be_const_int(2), - /* K21 */ be_nested_str_weak(MTR_X3A_X20Session_Store_X3A_X3Asave_X20Exception_X3A), - /* K22 */ be_nested_str_weak(_X7C), - }), - be_str_weak(save), - &be_const_str_solidified, - ( &(const binstruction[72]) { /* code */ - 0xA4060000, // 0000 IMPORT R1 K0 - 0x8C080101, // 0001 GETMET R2 R0 K1 - 0x7C080200, // 0002 CALL R2 1 - 0x60080012, // 0003 GETGBL R2 G18 - 0x7C080000, // 0004 CALL R2 0 - 0x600C0010, // 0005 GETGBL R3 G16 - 0x88100102, // 0006 GETMBR R4 R0 K2 - 0x7C0C0200, // 0007 CALL R3 1 - 0xA8020008, // 0008 EXBLK 0 #0012 - 0x5C100600, // 0009 MOVE R4 R3 - 0x7C100000, // 000A CALL R4 0 - 0x88140903, // 000B GETMBR R5 R4 K3 - 0x78160003, // 000C JMPF R5 #0011 - 0x8C140504, // 000D GETMET R5 R2 K4 - 0x8C1C0905, // 000E GETMET R7 R4 K5 - 0x7C1C0200, // 000F CALL R7 1 - 0x7C140400, // 0010 CALL R5 2 - 0x7001FFF6, // 0011 JMP #0009 - 0x580C0006, // 0012 LDCONST R3 K6 - 0xAC0C0200, // 0013 CATCH R3 1 0 - 0xB0080000, // 0014 RAISE 2 R0 R0 - 0x600C000C, // 0015 GETGBL R3 G12 - 0x5C100400, // 0016 MOVE R4 R2 - 0x7C0C0200, // 0017 CALL R3 1 - 0x8C100508, // 0018 GETMET R4 R2 K8 - 0x58180009, // 0019 LDCONST R6 K9 - 0x7C100400, // 001A CALL R4 2 - 0x00120E04, // 001B ADD R4 K7 R4 - 0x0010090A, // 001C ADD R4 R4 K10 - 0x5C080800, // 001D MOVE R2 R4 - 0xA8020015, // 001E EXBLK 0 #0035 - 0xA4121600, // 001F IMPORT R4 K11 - 0x60140011, // 0020 GETGBL R5 G17 - 0x8818010C, // 0021 GETMBR R6 R0 K12 - 0x581C000D, // 0022 LDCONST R7 K13 - 0x7C140400, // 0023 CALL R5 2 - 0x8C180B0E, // 0024 GETMET R6 R5 K14 - 0x5C200400, // 0025 MOVE R8 R2 - 0x7C180400, // 0026 CALL R6 2 - 0x8C180B0F, // 0027 GETMET R6 R5 K15 - 0x7C180200, // 0028 CALL R6 1 - 0xB81A2000, // 0029 GETNGBL R6 K16 - 0x8C180D11, // 002A GETMET R6 R6 K17 - 0x8C200912, // 002B GETMET R8 R4 K18 - 0x58280013, // 002C LDCONST R10 K19 - 0x5C2C0600, // 002D MOVE R11 R3 - 0x7C200600, // 002E CALL R8 3 - 0x58240014, // 002F LDCONST R9 K20 - 0x7C180600, // 0030 CALL R6 3 - 0xA8040001, // 0031 EXBLK 1 1 - 0x80040400, // 0032 RET 1 R2 - 0xA8040001, // 0033 EXBLK 1 1 - 0x70020011, // 0034 JMP #0047 - 0xAC100002, // 0035 CATCH R4 0 2 - 0x7002000E, // 0036 JMP #0046 - 0xB81A2000, // 0037 GETNGBL R6 K16 - 0x8C180D11, // 0038 GETMET R6 R6 K17 - 0x60200008, // 0039 GETGBL R8 G8 - 0x5C240800, // 003A MOVE R9 R4 - 0x7C200200, // 003B CALL R8 1 - 0x00222A08, // 003C ADD R8 K21 R8 - 0x00201116, // 003D ADD R8 R8 K22 - 0x60240008, // 003E GETGBL R9 G8 - 0x5C280A00, // 003F MOVE R10 R5 - 0x7C240200, // 0040 CALL R9 1 - 0x00201009, // 0041 ADD R8 R8 R9 - 0x58240014, // 0042 LDCONST R9 K20 - 0x7C180600, // 0043 CALL R6 3 - 0x80040400, // 0044 RET 1 R2 - 0x70020000, // 0045 JMP #0047 - 0xB0080000, // 0046 RAISE 2 R0 R0 - 0x80000000, // 0047 RET 0 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified function: gen_local_session_id ********************************************************************/ @@ -2213,50 +2305,48 @@ be_local_closure(Matter_Session_Store_gen_local_session_id, /* name */ /******************************************************************** -** Solidified function: create_session +** Solidified function: get_session_by_source_node_id ********************************************************************/ -be_local_closure(Matter_Session_Store_create_session, /* name */ +be_local_closure(Matter_Session_Store_get_session_by_source_node_id, /* name */ be_nested_proto( - 9, /* nstack */ - 3, /* argc */ + 6, /* nstack */ + 2, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 6]) { /* constants */ - /* K0 */ be_nested_str_weak(get_session_by_local_session_id), - /* K1 */ be_nested_str_weak(remove_session), - /* K2 */ be_nested_str_weak(matter), - /* K3 */ be_nested_str_weak(Session), - /* K4 */ be_nested_str_weak(sessions), - /* K5 */ be_nested_str_weak(push), + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(sessions), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str_weak(source_node_id), + /* K3 */ be_const_int(1), }), - be_str_weak(create_session), + be_str_weak(get_session_by_source_node_id), &be_const_str_solidified, ( &(const binstruction[21]) { /* code */ - 0x8C0C0100, // 0000 GETMET R3 R0 K0 - 0x5C140200, // 0001 MOVE R5 R1 - 0x7C0C0400, // 0002 CALL R3 2 - 0x4C100000, // 0003 LDNIL R4 - 0x20100604, // 0004 NE R4 R3 R4 - 0x78120002, // 0005 JMPF R4 #0009 - 0x8C100101, // 0006 GETMET R4 R0 K1 - 0x5C180600, // 0007 MOVE R6 R3 - 0x7C100400, // 0008 CALL R4 2 - 0xB8120400, // 0009 GETNGBL R4 K2 - 0x8C100903, // 000A GETMET R4 R4 K3 - 0x5C180000, // 000B MOVE R6 R0 - 0x5C1C0200, // 000C MOVE R7 R1 - 0x5C200400, // 000D MOVE R8 R2 - 0x7C100800, // 000E CALL R4 4 - 0x5C0C0800, // 000F MOVE R3 R4 - 0x88100104, // 0010 GETMBR R4 R0 K4 - 0x8C100905, // 0011 GETMET R4 R4 K5 - 0x5C180600, // 0012 MOVE R6 R3 - 0x7C100400, // 0013 CALL R4 2 - 0x80040600, // 0014 RET 1 R3 + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0001, // 0002 JMPF R2 #0005 + 0x4C080000, // 0003 LDNIL R2 + 0x80040400, // 0004 RET 1 R2 + 0x6008000C, // 0005 GETGBL R2 G12 + 0x880C0100, // 0006 GETMBR R3 R0 K0 + 0x7C080200, // 0007 CALL R2 1 + 0x580C0001, // 0008 LDCONST R3 K1 + 0x88100100, // 0009 GETMBR R4 R0 K0 + 0x14140602, // 000A LT R5 R3 R2 + 0x78160007, // 000B JMPF R5 #0014 + 0x94140803, // 000C GETIDX R5 R4 R3 + 0x88140B02, // 000D GETMBR R5 R5 K2 + 0x1C140A01, // 000E EQ R5 R5 R1 + 0x78160001, // 000F JMPF R5 #0012 + 0x94140803, // 0010 GETIDX R5 R4 R3 + 0x80040A00, // 0011 RET 1 R5 + 0x000C0703, // 0012 ADD R3 R3 K3 + 0x7001FFF5, // 0013 JMP #000A + 0x80000000, // 0014 RET 0 }) ) ); @@ -2269,23 +2359,24 @@ be_local_closure(Matter_Session_Store_create_session, /* name */ be_local_class(Matter_Session_Store, 1, NULL, - be_nested_map(15, + be_nested_map(16, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(every_second, 14), be_const_closure(Matter_Session_Store_every_second_closure) }, - { be_const_key_weak(remove_redundant_session, 9), be_const_closure(Matter_Session_Store_remove_redundant_session_closure) }, - { be_const_key_weak(get_session_by_source_node_id, 5), be_const_closure(Matter_Session_Store_get_session_by_source_node_id_closure) }, - { be_const_key_weak(remove_expired, -1), be_const_closure(Matter_Session_Store_remove_expired_closure) }, + { be_const_key_weak(remove_redundant_session, 15), be_const_closure(Matter_Session_Store_remove_redundant_session_closure) }, + { be_const_key_weak(get_session_by_source_node_id, 14), be_const_closure(Matter_Session_Store_get_session_by_source_node_id_closure) }, + { be_const_key_weak(gen_local_session_id, 6), be_const_closure(Matter_Session_Store_gen_local_session_id_closure) }, + { be_const_key_weak(init, 1), be_const_closure(Matter_Session_Store_init_closure) }, + { be_const_key_weak(save, -1), be_const_closure(Matter_Session_Store_save_closure) }, { be_const_key_weak(load, -1), be_const_closure(Matter_Session_Store_load_closure) }, - { be_const_key_weak(FILENAME, 11), be_nested_str_weak(_matter_sessions_X2Ejson) }, - { be_const_key_weak(remove_session, -1), be_const_closure(Matter_Session_Store_remove_session_closure) }, - { be_const_key_weak(add_session, -1), be_const_closure(Matter_Session_Store_add_session_closure) }, - { be_const_key_weak(get_session_by_local_session_id, -1), be_const_closure(Matter_Session_Store_get_session_by_local_session_id_closure) }, - { be_const_key_weak(find_session_source_id_unsecure, -1), be_const_closure(Matter_Session_Store_find_session_source_id_unsecure_closure) }, { be_const_key_weak(create_session, -1), be_const_closure(Matter_Session_Store_create_session_closure) }, - { be_const_key_weak(gen_local_session_id, -1), be_const_closure(Matter_Session_Store_gen_local_session_id_closure) }, - { be_const_key_weak(save, 10), be_const_closure(Matter_Session_Store_save_closure) }, + { be_const_key_weak(remove_expired, -1), be_const_closure(Matter_Session_Store_remove_expired_closure) }, + { be_const_key_weak(FILENAME, 4), be_nested_str_weak(_matter_sessions_X2Ejson) }, + { be_const_key_weak(every_second, 5), be_const_closure(Matter_Session_Store_every_second_closure) }, + { be_const_key_weak(remove_session, 2), be_const_closure(Matter_Session_Store_remove_session_closure) }, + { be_const_key_weak(sessions_active, -1), be_const_closure(Matter_Session_Store_sessions_active_closure) }, { be_const_key_weak(sessions, -1), be_const_var(0) }, - { be_const_key_weak(init, -1), be_const_closure(Matter_Session_Store_init_closure) }, + { be_const_key_weak(get_session_by_local_session_id, -1), be_const_closure(Matter_Session_Store_get_session_by_local_session_id_closure) }, + { be_const_key_weak(add_session, -1), be_const_closure(Matter_Session_Store_add_session_closure) }, + { be_const_key_weak(find_session_source_id_unsecure, -1), be_const_closure(Matter_Session_Store_find_session_source_id_unsecure_closure) }, })), be_str_weak(Matter_Session_Store) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_TLV.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_TLV.h index 3132bd417..13d316a47 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_TLV.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_TLV.h @@ -50,7 +50,7 @@ be_local_closure(Matter_TLV_item_encode, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[39]) { /* constants */ + ( &(const bvalue[41]) { /* constants */ /* K0 */ be_nested_str_weak(TLV), /* K1 */ be_nested_str_weak(typ), /* K2 */ be_nested_str_weak(BFALSE), @@ -77,23 +77,25 @@ be_local_closure(Matter_TLV_item_encode, /* name */ /* K23 */ be_const_int(2), /* K24 */ be_nested_str_weak(I8), /* K25 */ be_nested_str_weak(U8), - /* K26 */ be_nested_str_weak(int64), - /* K27 */ be_nested_str_weak(tobytes), - /* K28 */ be_nested_str_weak(FLOAT), - /* K29 */ be_nested_str_weak(setfloat), - /* K30 */ be_nested_str_weak(DOUBLE), - /* K31 */ be_nested_str_weak(value_error), - /* K32 */ be_nested_str_weak(Unsupported_X20type_X20TLV_X2EDOUBLE), - /* K33 */ be_nested_str_weak(string_X20too_X20big), - /* K34 */ be_nested_str_weak(fromstring), - /* K35 */ be_nested_str_weak(frostring), - /* K36 */ be_nested_str_weak(bytes_X20too_X20big), - /* K37 */ be_nested_str_weak(NULL), - /* K38 */ be_nested_str_weak(unsupported_X20type_X20), + /* K26 */ be_nested_str_weak(copy), + /* K27 */ be_nested_str_weak(resize), + /* K28 */ be_nested_str_weak(int64), + /* K29 */ be_nested_str_weak(tobytes), + /* K30 */ be_nested_str_weak(FLOAT), + /* K31 */ be_nested_str_weak(setfloat), + /* K32 */ be_nested_str_weak(DOUBLE), + /* K33 */ be_nested_str_weak(value_error), + /* K34 */ be_nested_str_weak(Unsupported_X20type_X20TLV_X2EDOUBLE), + /* K35 */ be_nested_str_weak(string_X20too_X20big), + /* K36 */ be_nested_str_weak(fromstring), + /* K37 */ be_nested_str_weak(frostring), + /* K38 */ be_nested_str_weak(bytes_X20too_X20big), + /* K39 */ be_nested_str_weak(NULL), + /* K40 */ be_nested_str_weak(unsupported_X20type_X20), }), be_str_weak(encode), &be_const_str_solidified, - ( &(const binstruction[345]) { /* code */ + ( &(const binstruction[361]) { /* code */ 0x88080100, // 0000 GETMBR R2 R0 K0 0x4C0C0000, // 0001 LDNIL R3 0x1C0C0203, // 0002 EQ R3 R1 R3 @@ -248,7 +250,7 @@ be_local_closure(Matter_TLV_item_encode, /* name */ 0x7C140200, // 0097 CALL R5 1 0x58180016, // 0098 LDCONST R6 K22 0x7C0C0600, // 0099 CALL R3 3 - 0x700200BC, // 009A JMP #0158 + 0x700200CC, // 009A JMP #0168 0x880C0101, // 009B GETMBR R3 R0 K1 0x88100505, // 009C GETMBR R4 R2 K5 0x1C0C0604, // 009D EQ R3 R3 R4 @@ -263,7 +265,7 @@ be_local_closure(Matter_TLV_item_encode, /* name */ 0x7C140200, // 00A6 CALL R5 1 0x58180017, // 00A7 LDCONST R6 K23 0x7C0C0600, // 00A8 CALL R3 3 - 0x700200AD, // 00A9 JMP #0158 + 0x700200BD, // 00A9 JMP #0168 0x880C0101, // 00AA GETMBR R3 R0 K1 0x88100506, // 00AB GETMBR R4 R2 K6 0x1C0C0604, // 00AC EQ R3 R3 R4 @@ -278,7 +280,7 @@ be_local_closure(Matter_TLV_item_encode, /* name */ 0x7C140200, // 00B5 CALL R5 1 0x541A0003, // 00B6 LDINT R6 4 0x7C0C0600, // 00B7 CALL R3 3 - 0x7002009E, // 00B8 JMP #0158 + 0x700200AE, // 00B8 JMP #0168 0x880C0101, // 00B9 GETMBR R3 R0 K1 0x88100518, // 00BA GETMBR R4 R2 K24 0x1C0C0604, // 00BB EQ R3 R3 R4 @@ -286,159 +288,175 @@ be_local_closure(Matter_TLV_item_encode, /* name */ 0x880C0101, // 00BD GETMBR R3 R0 K1 0x88100519, // 00BE GETMBR R4 R2 K25 0x1C0C0604, // 00BF EQ R3 R3 R4 - 0x780E000F, // 00C0 JMPF R3 #00D1 + 0x780E001F, // 00C0 JMPF R3 #00E1 0x880C0104, // 00C1 GETMBR R3 R0 K4 0x6010000F, // 00C2 GETGBL R4 G15 0x5C140600, // 00C3 MOVE R5 R3 - 0xB81A3400, // 00C4 GETNGBL R6 K26 + 0x60180015, // 00C4 GETGBL R6 G21 0x7C100400, // 00C5 CALL R4 2 - 0x74120005, // 00C6 JMPT R4 #00CD - 0xB8123400, // 00C7 GETNGBL R4 K26 - 0x60140009, // 00C8 GETGBL R5 G9 - 0x88180104, // 00C9 GETMBR R6 R0 K4 - 0x7C140200, // 00CA CALL R5 1 - 0x7C100200, // 00CB CALL R4 1 + 0x78120006, // 00C6 JMPF R4 #00CE + 0x8C10071A, // 00C7 GETMET R4 R3 K26 + 0x7C100200, // 00C8 CALL R4 1 + 0x8C10091B, // 00C9 GETMET R4 R4 K27 + 0x541A0007, // 00CA LDINT R6 8 + 0x7C100400, // 00CB CALL R4 2 0x5C0C0800, // 00CC MOVE R3 R4 - 0x8C10071B, // 00CD GETMET R4 R3 K27 - 0x7C100200, // 00CE CALL R4 1 - 0x40100204, // 00CF CONNECT R4 R1 R4 - 0x70020086, // 00D0 JMP #0158 - 0x880C0101, // 00D1 GETMBR R3 R0 K1 - 0x88100502, // 00D2 GETMBR R4 R2 K2 - 0x1C0C0604, // 00D3 EQ R3 R3 R4 - 0x740E0003, // 00D4 JMPT R3 #00D9 - 0x880C0101, // 00D5 GETMBR R3 R0 K1 - 0x88100503, // 00D6 GETMBR R4 R2 K3 - 0x1C0C0604, // 00D7 EQ R3 R3 R4 - 0x780E0000, // 00D8 JMPF R3 #00DA - 0x7002007D, // 00D9 JMP #0158 - 0x880C0101, // 00DA GETMBR R3 R0 K1 - 0x8810051C, // 00DB GETMBR R4 R2 K28 - 0x1C0C0604, // 00DC EQ R3 R3 R4 - 0x780E000D, // 00DD JMPF R3 #00EC - 0x600C000C, // 00DE GETGBL R3 G12 - 0x5C100200, // 00DF MOVE R4 R1 - 0x7C0C0200, // 00E0 CALL R3 1 - 0x8C100315, // 00E1 GETMET R4 R1 K21 - 0x5818000A, // 00E2 LDCONST R6 K10 - 0x541E0003, // 00E3 LDINT R7 4 - 0x7C100600, // 00E4 CALL R4 3 - 0x8C10031D, // 00E5 GETMET R4 R1 K29 - 0x5C180600, // 00E6 MOVE R6 R3 - 0x601C000A, // 00E7 GETGBL R7 G10 - 0x88200104, // 00E8 GETMBR R8 R0 K4 - 0x7C1C0200, // 00E9 CALL R7 1 - 0x7C100600, // 00EA CALL R4 3 - 0x7002006B, // 00EB JMP #0158 - 0x880C0101, // 00EC GETMBR R3 R0 K1 - 0x8810051E, // 00ED GETMBR R4 R2 K30 - 0x1C0C0604, // 00EE EQ R3 R3 R4 - 0x780E0001, // 00EF JMPF R3 #00F2 - 0xB0063F20, // 00F0 RAISE 1 K31 K32 - 0x70020065, // 00F1 JMP #0158 - 0x880C0101, // 00F2 GETMBR R3 R0 K1 - 0x88100510, // 00F3 GETMBR R4 R2 K16 - 0x1C0C0604, // 00F4 EQ R3 R3 R4 - 0x780E0015, // 00F5 JMPF R3 #010C - 0x600C000C, // 00F6 GETGBL R3 G12 - 0x88100104, // 00F7 GETMBR R4 R0 K4 - 0x7C0C0200, // 00F8 CALL R3 1 - 0x541200FE, // 00F9 LDINT R4 255 - 0x240C0604, // 00FA GT R3 R3 R4 - 0x780E0000, // 00FB JMPF R3 #00FD - 0xB0063F21, // 00FC RAISE 1 K31 K33 - 0x8C0C0315, // 00FD GETMET R3 R1 K21 - 0x6014000C, // 00FE GETGBL R5 G12 - 0x88180104, // 00FF GETMBR R6 R0 K4 - 0x7C140200, // 0100 CALL R5 1 - 0x58180016, // 0101 LDCONST R6 K22 - 0x7C0C0600, // 0102 CALL R3 3 - 0x600C0015, // 0103 GETGBL R3 G21 - 0x7C0C0000, // 0104 CALL R3 0 - 0x8C0C0722, // 0105 GETMET R3 R3 K34 - 0x60140008, // 0106 GETGBL R5 G8 - 0x88180104, // 0107 GETMBR R6 R0 K4 - 0x7C140200, // 0108 CALL R5 1 - 0x7C0C0400, // 0109 CALL R3 2 - 0x400C0203, // 010A CONNECT R3 R1 R3 - 0x7002004B, // 010B JMP #0158 - 0x880C0101, // 010C GETMBR R3 R0 K1 - 0x88100512, // 010D GETMBR R4 R2 K18 - 0x1C0C0604, // 010E EQ R3 R3 R4 - 0x780E0015, // 010F JMPF R3 #0126 - 0x600C000C, // 0110 GETGBL R3 G12 - 0x88100104, // 0111 GETMBR R4 R0 K4 - 0x7C0C0200, // 0112 CALL R3 1 - 0x5412FFFE, // 0113 LDINT R4 65535 - 0x240C0604, // 0114 GT R3 R3 R4 - 0x780E0000, // 0115 JMPF R3 #0117 - 0xB0063F21, // 0116 RAISE 1 K31 K33 - 0x8C0C0315, // 0117 GETMET R3 R1 K21 - 0x6014000C, // 0118 GETGBL R5 G12 - 0x88180104, // 0119 GETMBR R6 R0 K4 - 0x7C140200, // 011A CALL R5 1 - 0x58180017, // 011B LDCONST R6 K23 - 0x7C0C0600, // 011C CALL R3 3 - 0x600C0015, // 011D GETGBL R3 G21 - 0x7C0C0000, // 011E CALL R3 0 - 0x8C0C0723, // 011F GETMET R3 R3 K35 - 0x60140008, // 0120 GETGBL R5 G8 - 0x88180104, // 0121 GETMBR R6 R0 K4 - 0x7C140200, // 0122 CALL R5 1 - 0x7C0C0400, // 0123 CALL R3 2 - 0x400C0203, // 0124 CONNECT R3 R1 R3 - 0x70020031, // 0125 JMP #0158 - 0x880C0101, // 0126 GETMBR R3 R0 K1 - 0x8810050C, // 0127 GETMBR R4 R2 K12 - 0x1C0C0604, // 0128 EQ R3 R3 R4 - 0x780E000F, // 0129 JMPF R3 #013A - 0x600C000C, // 012A GETGBL R3 G12 - 0x88100104, // 012B GETMBR R4 R0 K4 - 0x7C0C0200, // 012C CALL R3 1 - 0x541200FE, // 012D LDINT R4 255 - 0x240C0604, // 012E GT R3 R3 R4 - 0x780E0000, // 012F JMPF R3 #0131 - 0xB0063F24, // 0130 RAISE 1 K31 K36 - 0x8C0C0315, // 0131 GETMET R3 R1 K21 - 0x6014000C, // 0132 GETGBL R5 G12 - 0x88180104, // 0133 GETMBR R6 R0 K4 - 0x7C140200, // 0134 CALL R5 1 - 0x58180016, // 0135 LDCONST R6 K22 - 0x7C0C0600, // 0136 CALL R3 3 - 0x880C0104, // 0137 GETMBR R3 R0 K4 - 0x400C0203, // 0138 CONNECT R3 R1 R3 - 0x7002001D, // 0139 JMP #0158 - 0x880C0101, // 013A GETMBR R3 R0 K1 - 0x8810050E, // 013B GETMBR R4 R2 K14 - 0x1C0C0604, // 013C EQ R3 R3 R4 - 0x780E000F, // 013D JMPF R3 #014E - 0x600C000C, // 013E GETGBL R3 G12 - 0x88100104, // 013F GETMBR R4 R0 K4 - 0x7C0C0200, // 0140 CALL R3 1 - 0x5412FFFE, // 0141 LDINT R4 65535 - 0x240C0604, // 0142 GT R3 R3 R4 - 0x780E0000, // 0143 JMPF R3 #0145 - 0xB0063F24, // 0144 RAISE 1 K31 K36 - 0x8C0C0315, // 0145 GETMET R3 R1 K21 - 0x6014000C, // 0146 GETGBL R5 G12 - 0x88180104, // 0147 GETMBR R6 R0 K4 - 0x7C140200, // 0148 CALL R5 1 - 0x58180017, // 0149 LDCONST R6 K23 - 0x7C0C0600, // 014A CALL R3 3 - 0x880C0104, // 014B GETMBR R3 R0 K4 - 0x400C0203, // 014C CONNECT R3 R1 R3 - 0x70020009, // 014D JMP #0158 - 0x880C0101, // 014E GETMBR R3 R0 K1 - 0x88100525, // 014F GETMBR R4 R2 K37 - 0x1C0C0604, // 0150 EQ R3 R3 R4 - 0x780E0000, // 0151 JMPF R3 #0153 - 0x70020004, // 0152 JMP #0158 - 0x600C0008, // 0153 GETGBL R3 G8 - 0x88100101, // 0154 GETMBR R4 R0 K1 - 0x7C0C0200, // 0155 CALL R3 1 - 0x000E4C03, // 0156 ADD R3 K38 R3 - 0xB0063E03, // 0157 RAISE 1 K31 R3 - 0x80040200, // 0158 RET 1 R1 + 0x70020010, // 00CD JMP #00DF + 0x6010000F, // 00CE GETGBL R4 G15 + 0x5C140600, // 00CF MOVE R5 R3 + 0xB81A3800, // 00D0 GETNGBL R6 K28 + 0x7C100400, // 00D1 CALL R4 2 + 0x78120003, // 00D2 JMPF R4 #00D7 + 0x8C10071D, // 00D3 GETMET R4 R3 K29 + 0x7C100200, // 00D4 CALL R4 1 + 0x5C0C0800, // 00D5 MOVE R3 R4 + 0x70020007, // 00D6 JMP #00DF + 0xB8123800, // 00D7 GETNGBL R4 K28 + 0x60140009, // 00D8 GETGBL R5 G9 + 0x5C180600, // 00D9 MOVE R6 R3 + 0x7C140200, // 00DA CALL R5 1 + 0x7C100200, // 00DB CALL R4 1 + 0x8C10091D, // 00DC GETMET R4 R4 K29 + 0x7C100200, // 00DD CALL R4 1 + 0x5C0C0800, // 00DE MOVE R3 R4 + 0x40100203, // 00DF CONNECT R4 R1 R3 + 0x70020086, // 00E0 JMP #0168 + 0x880C0101, // 00E1 GETMBR R3 R0 K1 + 0x88100502, // 00E2 GETMBR R4 R2 K2 + 0x1C0C0604, // 00E3 EQ R3 R3 R4 + 0x740E0003, // 00E4 JMPT R3 #00E9 + 0x880C0101, // 00E5 GETMBR R3 R0 K1 + 0x88100503, // 00E6 GETMBR R4 R2 K3 + 0x1C0C0604, // 00E7 EQ R3 R3 R4 + 0x780E0000, // 00E8 JMPF R3 #00EA + 0x7002007D, // 00E9 JMP #0168 + 0x880C0101, // 00EA GETMBR R3 R0 K1 + 0x8810051E, // 00EB GETMBR R4 R2 K30 + 0x1C0C0604, // 00EC EQ R3 R3 R4 + 0x780E000D, // 00ED JMPF R3 #00FC + 0x600C000C, // 00EE GETGBL R3 G12 + 0x5C100200, // 00EF MOVE R4 R1 + 0x7C0C0200, // 00F0 CALL R3 1 + 0x8C100315, // 00F1 GETMET R4 R1 K21 + 0x5818000A, // 00F2 LDCONST R6 K10 + 0x541E0003, // 00F3 LDINT R7 4 + 0x7C100600, // 00F4 CALL R4 3 + 0x8C10031F, // 00F5 GETMET R4 R1 K31 + 0x5C180600, // 00F6 MOVE R6 R3 + 0x601C000A, // 00F7 GETGBL R7 G10 + 0x88200104, // 00F8 GETMBR R8 R0 K4 + 0x7C1C0200, // 00F9 CALL R7 1 + 0x7C100600, // 00FA CALL R4 3 + 0x7002006B, // 00FB JMP #0168 + 0x880C0101, // 00FC GETMBR R3 R0 K1 + 0x88100520, // 00FD GETMBR R4 R2 K32 + 0x1C0C0604, // 00FE EQ R3 R3 R4 + 0x780E0001, // 00FF JMPF R3 #0102 + 0xB0064322, // 0100 RAISE 1 K33 K34 + 0x70020065, // 0101 JMP #0168 + 0x880C0101, // 0102 GETMBR R3 R0 K1 + 0x88100510, // 0103 GETMBR R4 R2 K16 + 0x1C0C0604, // 0104 EQ R3 R3 R4 + 0x780E0015, // 0105 JMPF R3 #011C + 0x600C000C, // 0106 GETGBL R3 G12 + 0x88100104, // 0107 GETMBR R4 R0 K4 + 0x7C0C0200, // 0108 CALL R3 1 + 0x541200FE, // 0109 LDINT R4 255 + 0x240C0604, // 010A GT R3 R3 R4 + 0x780E0000, // 010B JMPF R3 #010D + 0xB0064323, // 010C RAISE 1 K33 K35 + 0x8C0C0315, // 010D GETMET R3 R1 K21 + 0x6014000C, // 010E GETGBL R5 G12 + 0x88180104, // 010F GETMBR R6 R0 K4 + 0x7C140200, // 0110 CALL R5 1 + 0x58180016, // 0111 LDCONST R6 K22 + 0x7C0C0600, // 0112 CALL R3 3 + 0x600C0015, // 0113 GETGBL R3 G21 + 0x7C0C0000, // 0114 CALL R3 0 + 0x8C0C0724, // 0115 GETMET R3 R3 K36 + 0x60140008, // 0116 GETGBL R5 G8 + 0x88180104, // 0117 GETMBR R6 R0 K4 + 0x7C140200, // 0118 CALL R5 1 + 0x7C0C0400, // 0119 CALL R3 2 + 0x400C0203, // 011A CONNECT R3 R1 R3 + 0x7002004B, // 011B JMP #0168 + 0x880C0101, // 011C GETMBR R3 R0 K1 + 0x88100512, // 011D GETMBR R4 R2 K18 + 0x1C0C0604, // 011E EQ R3 R3 R4 + 0x780E0015, // 011F JMPF R3 #0136 + 0x600C000C, // 0120 GETGBL R3 G12 + 0x88100104, // 0121 GETMBR R4 R0 K4 + 0x7C0C0200, // 0122 CALL R3 1 + 0x5412FFFE, // 0123 LDINT R4 65535 + 0x240C0604, // 0124 GT R3 R3 R4 + 0x780E0000, // 0125 JMPF R3 #0127 + 0xB0064323, // 0126 RAISE 1 K33 K35 + 0x8C0C0315, // 0127 GETMET R3 R1 K21 + 0x6014000C, // 0128 GETGBL R5 G12 + 0x88180104, // 0129 GETMBR R6 R0 K4 + 0x7C140200, // 012A CALL R5 1 + 0x58180017, // 012B LDCONST R6 K23 + 0x7C0C0600, // 012C CALL R3 3 + 0x600C0015, // 012D GETGBL R3 G21 + 0x7C0C0000, // 012E CALL R3 0 + 0x8C0C0725, // 012F GETMET R3 R3 K37 + 0x60140008, // 0130 GETGBL R5 G8 + 0x88180104, // 0131 GETMBR R6 R0 K4 + 0x7C140200, // 0132 CALL R5 1 + 0x7C0C0400, // 0133 CALL R3 2 + 0x400C0203, // 0134 CONNECT R3 R1 R3 + 0x70020031, // 0135 JMP #0168 + 0x880C0101, // 0136 GETMBR R3 R0 K1 + 0x8810050C, // 0137 GETMBR R4 R2 K12 + 0x1C0C0604, // 0138 EQ R3 R3 R4 + 0x780E000F, // 0139 JMPF R3 #014A + 0x600C000C, // 013A GETGBL R3 G12 + 0x88100104, // 013B GETMBR R4 R0 K4 + 0x7C0C0200, // 013C CALL R3 1 + 0x541200FE, // 013D LDINT R4 255 + 0x240C0604, // 013E GT R3 R3 R4 + 0x780E0000, // 013F JMPF R3 #0141 + 0xB0064326, // 0140 RAISE 1 K33 K38 + 0x8C0C0315, // 0141 GETMET R3 R1 K21 + 0x6014000C, // 0142 GETGBL R5 G12 + 0x88180104, // 0143 GETMBR R6 R0 K4 + 0x7C140200, // 0144 CALL R5 1 + 0x58180016, // 0145 LDCONST R6 K22 + 0x7C0C0600, // 0146 CALL R3 3 + 0x880C0104, // 0147 GETMBR R3 R0 K4 + 0x400C0203, // 0148 CONNECT R3 R1 R3 + 0x7002001D, // 0149 JMP #0168 + 0x880C0101, // 014A GETMBR R3 R0 K1 + 0x8810050E, // 014B GETMBR R4 R2 K14 + 0x1C0C0604, // 014C EQ R3 R3 R4 + 0x780E000F, // 014D JMPF R3 #015E + 0x600C000C, // 014E GETGBL R3 G12 + 0x88100104, // 014F GETMBR R4 R0 K4 + 0x7C0C0200, // 0150 CALL R3 1 + 0x5412FFFE, // 0151 LDINT R4 65535 + 0x240C0604, // 0152 GT R3 R3 R4 + 0x780E0000, // 0153 JMPF R3 #0155 + 0xB0064326, // 0154 RAISE 1 K33 K38 + 0x8C0C0315, // 0155 GETMET R3 R1 K21 + 0x6014000C, // 0156 GETGBL R5 G12 + 0x88180104, // 0157 GETMBR R6 R0 K4 + 0x7C140200, // 0158 CALL R5 1 + 0x58180017, // 0159 LDCONST R6 K23 + 0x7C0C0600, // 015A CALL R3 3 + 0x880C0104, // 015B GETMBR R3 R0 K4 + 0x400C0203, // 015C CONNECT R3 R1 R3 + 0x70020009, // 015D JMP #0168 + 0x880C0101, // 015E GETMBR R3 R0 K1 + 0x88100527, // 015F GETMBR R4 R2 K39 + 0x1C0C0604, // 0160 EQ R3 R3 R4 + 0x780E0000, // 0161 JMPF R3 #0163 + 0x70020004, // 0162 JMP #0168 + 0x600C0008, // 0163 GETGBL R3 G8 + 0x88100101, // 0164 GETMBR R4 R0 K1 + 0x7C0C0200, // 0165 CALL R3 1 + 0x000E5003, // 0166 ADD R3 K40 R3 + 0xB0064203, // 0167 RAISE 1 K33 R3 + 0x80040200, // 0168 RET 1 R1 }) ) ); From 6f0b646b5633231192e891eb9237e49875d1ac3c Mon Sep 17 00:00:00 2001 From: gemu Date: Tue, 7 Feb 2023 09:11:04 +0100 Subject: [PATCH 244/262] fix missing comma (#17904) From ff165bfe8ccc74da76cdb9b4a9c423ea6930a4c7 Mon Sep 17 00:00:00 2001 From: gemu Date: Tue, 7 Feb 2023 09:11:40 +0100 Subject: [PATCH 245/262] reduce display frequency (#17906) --- tasmota/displaydesc/ST7262_rgb16_display.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasmota/displaydesc/ST7262_rgb16_display.ini b/tasmota/displaydesc/ST7262_rgb16_display.ini index 80b210600..06f8be337 100644 --- a/tasmota/displaydesc/ST7262_rgb16_display.ini +++ b/tasmota/displaydesc/ST7262_rgb16_display.ini @@ -1,4 +1,4 @@ -:H,ST7262,800,480,16,RGB,40,41,39,42,2,15,16,4,45,48,47,21,14,8,3,46,9,1,5,6,7,14 +:H,ST7262,800,480,16,RGB,40,41,39,42,2,15,16,4,45,48,47,21,14,8,3,46,9,1,5,6,7,12 :S,2,1,1,0,40,20 :V,0,8,4,8,0,8,4,8,1 :0,00 From 387d3486d527e4baadc0bbf00a70c54a4b4bd674 Mon Sep 17 00:00:00 2001 From: sfromis <47082390+sfromis@users.noreply.github.com> Date: Tue, 7 Feb 2023 13:52:33 +0100 Subject: [PATCH 246/262] Typo in I2CDEVICES (#17908) Sensor name TSL2591 was misspelled. Is this file automatically duplicated on docs, or should I fix the copy there? --- I2CDEVICES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/I2CDEVICES.md b/I2CDEVICES.md index 28818c562..86090c403 100644 --- a/I2CDEVICES.md +++ b/I2CDEVICES.md @@ -61,7 +61,7 @@ Index | Define | Driver | Device | Address(es) | Description 37 | USE_24C256 | xdrv_10 | 24C256 | 0x50 | Scripter EEPROM storage 38 | USE_DISPLAY_ILI9488 | xdsp_08 | FT6236 | 0x38 | Touch panel controller 39 | USE_DISPLAY_RA8876 | xdsp_10 | FT5316 | 0x38 | Touch panel controller - 40 | USE_TSL2591 | xsns_57 | TLS2591 | 0x29 | Light intensity sensor + 40 | USE_TSL2591 | xsns_57 | TSL2591 | 0x29 | Light intensity sensor 41 | USE_DHT12 | xsns_58 | DHT12 | 0x5C | Temperature and humidity sensor 42 | USE_DS1624 | xsns_59 | DS1621 | 0x48 - 0x4F | Temperature sensor 42 | USE_DS1624 | xsns_59 | DS1624 | 0x48 - 0x4F | Temperature sensor From 1c1f6c638f3a39acbcc53c16076385ee64a52dc9 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Wed, 8 Feb 2023 10:50:34 +0100 Subject: [PATCH 247/262] Add commands PowerCal, VoltageCal and CurrentCall Add commands PowerCal, VoltageCal and CurrentCall to CSE7766/HLW8032 energy driver --- tasmota/tasmota_xnrg_energy/xnrg_02_cse7766.ino | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tasmota/tasmota_xnrg_energy/xnrg_02_cse7766.ino b/tasmota/tasmota_xnrg_energy/xnrg_02_cse7766.ino index 023480298..9ca4c5ce8 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_02_cse7766.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_02_cse7766.ino @@ -255,7 +255,10 @@ void CseDrvInit(void) { bool CseCommand(void) { bool serviced = true; - if (CMND_POWERSET == Energy->command_code) { + if ((CMND_POWERCAL == Energy->command_code) || (CMND_VOLTAGECAL == Energy->command_code) || (CMND_CURRENTCAL == Energy->command_code)) { + // Service in xdrv_03_energy.ino + } + else if (CMND_POWERSET == Energy->command_code) { if (XdrvMailbox.data_len && Cse.power_cycle) { XdrvMailbox.payload = (unsigned long)(CharToFloat(XdrvMailbox.data) * Cse.power_cycle) / CSE_PREF; } From 40be97e6d94b28c26ad6e8641335b04708ec9cdf Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Wed, 8 Feb 2023 12:38:10 +0100 Subject: [PATCH 248/262] SD Card support for >1MB tasmota (#17916) --- tasmota/include/tasmota_configurations.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tasmota/include/tasmota_configurations.h b/tasmota/include/tasmota_configurations.h index f29eb254c..c8beda51b 100644 --- a/tasmota/include/tasmota_configurations.h +++ b/tasmota/include/tasmota_configurations.h @@ -1023,6 +1023,8 @@ #define USE_UFILESYS #define GUI_TRASH_FILE #define GUI_EDIT_FILE + #define USE_SPI + #define USE_SDCARD #define USE_PING #endif // FIRMWARE_MINIMAL From 7a2b5177acf616c9b3bfb756db9a8b48e36ba0bc Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Wed, 8 Feb 2023 14:14:49 +0100 Subject: [PATCH 249/262] Fix Shelly Pro 4PM calibration regs --- .../tasmota_xnrg_energy/xnrg_07_ade7953.ino | 38 +++++++++++++------ 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino b/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino index dc088a947..cd6056cc5 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino @@ -42,11 +42,12 @@ * Shelly 2.5 EM Plus2PM Pro1PM Pro2PM Pro4PM * Processor ESP8266 ESP8266 ESP32 ESP32 ESP32 ESP32 * Interface I2C I2C I2C SPI SPI SPI Interface type used + * Number of inputs 2 2 2 1 2 4 Count of ADE9753 inputs used * Number of ADE9753 chips 1 1 1 1 2 2 Count of ADE9753 chips * ADE9753 IRQ 1 2 3 4 5 6 Index defines model number * Current measurement device shunt CT shunt shunt shunt shunt CT = Current Transformer - * Common voltage Yes Yes Yes No No No Show common voltage in GUI/JSON - * Common frequency Yes Yes Yes No No No Show common frequency in GUI/JSON + * Common voltage Yes Yes Yes No No Yes Show common voltage in GUI/JSON + * Common frequency Yes Yes Yes No No Yes Show common frequency in GUI/JSON * Swapped channel A/B Yes No No No No No Defined by hardware design - Fixed by Tasmota * Support Export Active No Yes No No No No Only EM supports correct negative value detection * Show negative (reactive) power No Yes No No No No Only EM supports correct negative value detection @@ -374,7 +375,6 @@ void Ade7953DumpRegs(void) { #endif // ADE7953_DUMP_REGS void Ade7953SetCalibration(uint32_t regset, uint32_t calibset) { - Ade7953.cs_index = calibset; for (uint32_t i = 0; i < ADE7953_CALIBREGS; i++) { int32_t value = Ade7953.calib_data[calibset][i]; if (ADE7943_CAL_PHCAL == i) { @@ -393,6 +393,8 @@ void Ade7953Init(void) { #ifdef USE_ESP32_SPI chips = (Ade7953.pin_cs[1] >= 0) ? 2 : 1; #endif // USE_ESP32_SPI + + // Init ADE7953 with calibration settings for (uint32_t chip = 0; chip < chips; chip++) { Ade7953.cs_index = chip; @@ -406,18 +408,32 @@ void Ade7953Init(void) { #ifdef USE_ESP32_SPI // int32_t value = Ade7953Read(0x702); // Silicon version // AddLog(LOG_LEVEL_DEBUG, PSTR("ADE: Chip%d version %d"), chip +1, value); + if (1 == chip) { + switch (Ade7953.model) { + case ADE7953_SHELLY_PRO_2PM: + Ade7953SetCalibration(0, 1); // Second ADE7953 A registers set with calibration set 1 + break; + case ADE7953_SHELLY_PRO_4PM: + Ade7953SetCalibration(0, 2); // Second ADE7953 A registers set with calibration set 2 + Ade7953SetCalibration(1, 3); // Second ADE7953 B registers set with calibration set 3 + } + } else { #endif // USE_ESP32_SPI - } - - Ade7953SetCalibration(0, 0); // First ADE7953 A registers set with calibration set 0 + Ade7953SetCalibration(0, 0); // First ADE7953 A registers set with calibration set 0 + switch (Ade7953.model) { + case ADE7953_SHELLY_25: + case ADE7953_SHELLY_EM: + case ADE7953_SHELLY_PLUS_2PM: +// case ADE7953_SHELLY_PRO_1PM: // Uses defaults for B registers + case ADE7953_SHELLY_PRO_4PM: + Ade7953SetCalibration(1, 1); // First ADE7953 B registers set with calibration set 1 + } #ifdef USE_ESP32_SPI - if (Ade7953.pin_cs[1] >= 0) { // Second ADE7953 using SPI - Ade7953SetCalibration(0, 1); // Second ADE7953 A registers set with calibration set 1 - } - else if (Ade7953.pin_cs[0] == -1) // No first ADE7953 using SPI so set register set B + } #endif // USE_ESP32_SPI - Ade7953SetCalibration(1, 1); // First ADE7953 B register set with calibration set 1 + } + // Report set calibration settings int32_t regs[ADE7953_CALIBREGS]; for (uint32_t chip = 0; chip < chips; chip++) { Ade7953.cs_index = chip; From d029d8bcbcf2391c7e7c58e68871ba7ac2671787 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Wed, 8 Feb 2023 17:08:13 +0100 Subject: [PATCH 250/262] Fix Shelly Pro 4PM switch states --- tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro.ino b/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro.ino index cb1d91a49..b9b6020b4 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro.ino @@ -252,7 +252,7 @@ bool ShellyProAddSwitch(void) { uint32_t index = XdrvMailbox.index - SPro.switch_offset; if (index > 3) { return false; } // Support four switches uint32_t state = bitRead(SPro.input_state, sp4_switch_pin[index]); // 0 on power on and restart - XdrvMailbox.index = state ^1; // Invert + XdrvMailbox.index = state; return true; } @@ -276,7 +276,7 @@ void ShellyProUpdateIsr(void) { for (uint32_t i = 0; i < 4; i++) { if (j == sp4_switch_pin[i]) { - SwitchSetVirtualPinState(SPro.switch_offset +i, state ^1); // Invert + SwitchSetVirtualPinState(SPro.switch_offset +i, state); } else if ((i < 3) && (j == sp4_button_pin[i])) { ButtonSetVirtualPinState(SPro.button_offset +i, state); From 8cbb62d8c94674cdc5543c03aeb1f4b746109f08 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Thu, 9 Feb 2023 14:46:54 +0100 Subject: [PATCH 251/262] Simplify virtual buttons/switches --- tasmota/tasmota_support/support_button_v4.ino | 11 ++++------ tasmota/tasmota_support/support_switch_v4.ino | 2 +- .../tasmota_xdrv_driver/xdrv_66_tm1638.ino | 22 +++++++++---------- .../xdrv_88_esp32_shelly_pro.ino | 8 +++++++ .../tasmota_xnrg_energy/xnrg_07_ade7953.ino | 10 ++++----- 5 files changed, 28 insertions(+), 25 deletions(-) diff --git a/tasmota/tasmota_support/support_button_v4.ino b/tasmota/tasmota_support/support_button_v4.ino index c86bda264..927b43ea3 100644 --- a/tasmota/tasmota_support/support_button_v4.ino +++ b/tasmota/tasmota_support/support_button_v4.ino @@ -27,8 +27,6 @@ #define MAX_RELAY_BUTTON1 5 // Max number of relay controlled by BUTTON1 -#define BUTTON_INVERT 0x02 // Invert bitmask - const uint8_t BUTTON_PROBE_INTERVAL = 10; // Time in milliseconds between button input probe const uint8_t BUTTON_FAST_PROBE_INTERVAL = 2; // Time in milliseconds between button input probe for AC detection const uint8_t BUTTON_AC_PERIOD = (20 + BUTTON_FAST_PROBE_INTERVAL - 1) / BUTTON_FAST_PROBE_INTERVAL; // Duration of an AC wave in probe intervals @@ -256,20 +254,19 @@ void ButtonInit(void) { if (XdrvCall(FUNC_ADD_BUTTON)) { /* At entry: - XdrvMailbox.index = key index + XdrvMailbox.index = button index At exit: XdrvMailbox.index bit 0 = current state - XdrvMailbox.index bit 1 = invert signal */ Button.present++; bitSet(Button.virtual_pin_used, i); // This pin is used bool state = (XdrvMailbox.index &1); ButtonSetVirtualPinState(i, state); // Virtual hardware pin state - bool invert = (XdrvMailbox.index &BUTTON_INVERT); - if (invert) { ButtonInvertFlag(i); } // Set inverted flag + if (!state) { ButtonInvertFlag(i); } // Set inverted flag + // last_state[i] must be 1 to indicate no button pressed Button.last_state[i] = (bitRead(Button.virtual_pin, i) != bitRead(Button.inverted_mask, i)); - AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: Add vButton%d, State %d, Info %02X"), Button.present, Button.last_state[i], XdrvMailbox.index); + AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: Add vButton%d, State %d"), Button.present, Button.last_state[i]); used = true; } diff --git a/tasmota/tasmota_support/support_switch_v4.ino b/tasmota/tasmota_support/support_switch_v4.ino index 81a49f4e4..9af56e25c 100644 --- a/tasmota/tasmota_support/support_switch_v4.ino +++ b/tasmota/tasmota_support/support_switch_v4.ino @@ -254,7 +254,7 @@ void SwitchInit(void) { SwitchSetVirtualPinState(i, state); // Virtual hardware pin state Switch.last_state[i] = bitRead(Switch.virtual_pin, i); - AddLog(LOG_LEVEL_DEBUG, PSTR("SWT: Add vSwitch%d, State %d, Info %02X"), Switch.present, Switch.last_state[i], XdrvMailbox.index); + AddLog(LOG_LEVEL_DEBUG, PSTR("SWT: Add vSwitch%d, State %d"), Switch.present, Switch.last_state[i]); used = true; } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_66_tm1638.ino b/tasmota/tasmota_xdrv_driver/xdrv_66_tm1638.ino index 435d48843..41dc91d10 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_66_tm1638.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_66_tm1638.ino @@ -185,15 +185,15 @@ void TmInit(void) { } void TmLoop(void) { - uint8_t buttons = Tm1638GetButtons(); + uint8_t keys = Tm1638GetButtons(); for (uint32_t i = 0; i < TM1638_MAX_KEYS; i++) { - uint32_t state = buttons &1; + uint32_t state = keys &1; #ifdef TM1638_USE_BUTTONS ButtonSetVirtualPinState(Tm1638.key_offset +i, state); #else - SwitchSetVirtualPinState(Tm1638.key_offset +i, state ^1); + SwitchSetVirtualPinState(Tm1638.key_offset +i, state); #endif - buttons >>= 1; + keys >>= 1; } } @@ -212,13 +212,13 @@ bool TmAddKey(void) { if (Tm1638.key_offset < 0) { Tm1638.key_offset = XdrvMailbox.index; } uint32_t index = XdrvMailbox.index - Tm1638.key_offset; if (index >= TM1638_MAX_KEYS) { return false; } - uint8_t buttons = Tm1638GetButtons(); - uint32_t state = bitRead(buttons, index); -#ifdef TM1638_USE_BUTTONS - XdrvMailbox.index = state | BUTTON_INVERT; // Invert - default is 0 -#else - XdrvMailbox.index = state ^1; // Invert - default is 0 -#endif +/* + uint8_t keys = Tm1638GetButtons(); + uint32_t state = bitRead(keys, index); + AddLog(LOG_LEVEL_DEBUG, PSTR("DBG: Default state %d"), state); + XdrvMailbox.index = state; // Default is 0 - Button will also set invert +*/ + XdrvMailbox.index = 0; // Default is 0 - Button will also set invert return true; } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro.ino b/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro.ino index b9b6020b4..d6f3d1d10 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro.ino @@ -241,8 +241,12 @@ bool ShellyProAddButton(void) { if (SPro.button_offset < 0) { SPro.button_offset = XdrvMailbox.index; } uint32_t index = XdrvMailbox.index - SPro.button_offset; if (index > 2) { return false; } // Support three buttons +/* uint32_t state = bitRead(SPro.input_state, sp4_button_pin[index]); // 1 on power on and restart + AddLog(LOG_LEVEL_DEBUG, PSTR("DBG: Button default state %d"), state); XdrvMailbox.index = state; +*/ + XdrvMailbox.index = 1; // 1 on power on and restart return true; } @@ -251,8 +255,12 @@ bool ShellyProAddSwitch(void) { if (SPro.switch_offset < 0) { SPro.switch_offset = XdrvMailbox.index; } uint32_t index = XdrvMailbox.index - SPro.switch_offset; if (index > 3) { return false; } // Support four switches +/* uint32_t state = bitRead(SPro.input_state, sp4_switch_pin[index]); // 0 on power on and restart + AddLog(LOG_LEVEL_DEBUG, PSTR("DBG: Switch default state %d"), state); XdrvMailbox.index = state; +*/ + XdrvMailbox.index = 0; // 0 on power on and restart return true; } diff --git a/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino b/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino index cd6056cc5..8f5fb7237 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino @@ -239,7 +239,6 @@ struct Ade7953 { uint8_t model = 0; // 0 = Shelly 2.5, 1 = Shelly EM, 2 = Shelly Plus 2PM, 3 = Shelly Pro 1PM, 4 = Shelly Pro 2PM, 5 = Shelly Pro 4PM uint8_t cs_index; #ifdef USE_ESP32_SPI - SPISettings spi_settings; int8_t pin_cs[ADE7953_MAX_CHANNEL / 2]; #endif // USE_ESP32_SPI bool use_spi; @@ -343,8 +342,8 @@ int32_t Ade7953Read(uint16_t reg) { } #ifdef ADE7953_DUMP_REGS -void Ade7953DumpRegs(void) { - AddLog(LOG_LEVEL_DEBUG, PSTR("ADE: *** SAGCYC DISNOLD Resrvd Resrvd LCYCMOD Resrvd Resrvd PGAV PGAIA PGAIB")); +void Ade7953DumpRegs(uint32_t chip) { + AddLog(LOG_LEVEL_DEBUG, PSTR("ADE: *** Chip%d **** SAGCYC DISNOLD Resrvd Resrvd LCYCMOD Resrvd Resrvd PGAV PGAIA PGAIB"), chip +1); char data[200] = { 0 }; for (uint32_t i = 0; i < 10; i++) { int32_t value = Ade7953Read(ADE7953_SAGCYC + i); @@ -399,7 +398,7 @@ void Ade7953Init(void) { Ade7953.cs_index = chip; #ifdef ADE7953_DUMP_REGS - Ade7953DumpRegs(); + Ade7953DumpRegs(chip); #endif // ADE7953_DUMP_REGS Ade7953Write(ADE7953_CONFIG, 0x0004); // Locking the communication interface (Clear bit COMM_LOCK), Enable HPF @@ -457,7 +456,7 @@ void Ade7953Init(void) { } #ifdef ADE7953_DUMP_REGS - Ade7953DumpRegs(); + Ade7953DumpRegs(chip); #endif // ADE7953_DUMP_REGS } } @@ -724,7 +723,6 @@ void Ade7953DrvInit(void) { Ade7953.cs_index = 0; Ade7953.use_spi = true; SPI.begin(Pin(GPIO_SPI_CLK), Pin(GPIO_SPI_MISO), Pin(GPIO_SPI_MOSI), -1); - Ade7953.spi_settings = SPISettings(1000000, MSBFIRST, SPI_MODE0); // Set up SPI at 1MHz, MSB first, Capture at rising edge AddLog(LOG_LEVEL_INFO, PSTR("SPI: ADE7953 found")); } else { return; // No CS pin defined From 134c8392449a9d93d45c7e18dd8dbcdecba30d18 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Thu, 9 Feb 2023 15:34:05 +0100 Subject: [PATCH 252/262] Fix virtual relays multi press --- tasmota/tasmota_support/support_button_v4.ino | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/tasmota/tasmota_support/support_button_v4.ino b/tasmota/tasmota_support/support_button_v4.ino index 927b43ea3..af9bfc29a 100644 --- a/tasmota/tasmota_support/support_button_v4.ino +++ b/tasmota/tasmota_support/support_button_v4.ino @@ -500,6 +500,7 @@ void ButtonHandler(void) { XdrvMailbox.payload = Button.press_counter[button_index]; if (XdrvCall(FUNC_BUTTON_MULTI_PRESSED)) { // Serviced +// AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: FUNC_BUTTON_MULTI_PRESSED serviced")); } else #ifdef ROTARY_V1 @@ -518,20 +519,9 @@ void ButtonHandler(void) { } else { SendKey(KEY_BUTTON, button_index +1, Button.press_counter[button_index] +9); // 2,3,4 and 5 press send just the key value (11,12,13 and 14) for rules if (0 == button_index) { // BUTTON1 can toggle up to 5 relays if present. If a relay is not present will send out the key value (2,11,12,13 and 14) for rules - bool valid_relay = PinUsed(GPIO_REL1, Button.press_counter[button_index]-1); -#ifdef ESP8266 - if ((SONOFF_DUAL == TasmotaGlobal.module_type) || (CH4 == TasmotaGlobal.module_type)) { - valid_relay = (Button.press_counter[button_index] <= TasmotaGlobal.devices_present); - } -#endif // ESP8266 -#ifdef USE_SHELLY_PRO - if (TasmotaGlobal.gpio_optiona.shelly_pro) { - valid_relay = (Button.press_counter[button_index] <= TasmotaGlobal.devices_present); - } -#endif // USE_SHELLY_PRO - if ((Button.press_counter[button_index] > 1) && valid_relay && (Button.press_counter[button_index] <= MAX_RELAY_BUTTON1)) { + uint32_t max_device = (TasmotaGlobal.devices_present < MAX_RELAY_BUTTON1) ? TasmotaGlobal.devices_present : MAX_RELAY_BUTTON1; + if ((Button.press_counter[button_index] > 1) && (Button.press_counter[button_index] <= max_device)) { ExecuteCommandPower(button_index + Button.press_counter[button_index], POWER_TOGGLE, SRC_BUTTON); // Execute Toggle command internally -// AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: Relay%d found on GPIO%d"), Button.press_counter[button_index], Pin(GPIO_REL1, Button.press_counter[button_index]-1)); } } } From 5d3f2cc316892f7034407bdf7c23a99077c7d102 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Thu, 9 Feb 2023 16:02:06 +0100 Subject: [PATCH 253/262] ESP8266 increase number of discovery relays --- tasmota/include/tasmota.h | 16 +++++++++------- .../tasmota_xdrv_driver/xdrv_12_discovery.ino | 8 ++++---- .../xdrv_12_home_assistant.ino | 8 ++++---- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/tasmota/include/tasmota.h b/tasmota/include/tasmota.h index 6b60bcb41..40a8a3050 100644 --- a/tasmota/include/tasmota.h +++ b/tasmota/include/tasmota.h @@ -45,22 +45,24 @@ const uint32_t POWER_SIZE = 32; // Power (relay) bit count * Constants \*********************************************************************************************/ +// Why 28? Because in addition to relays there may be lights and uint32_t bitmap can hold up to 32 devices #ifdef ESP8266 -const uint8_t MAX_RELAYS = 8; // Max number of relays (up to 28) +const uint8_t MAX_RELAYS = 8; // Max number of relays selectable on GPIO const uint8_t MAX_INTERLOCKS = 4; // Max number of interlock groups (up to MAX_INTERLOCKS_SET) -const uint8_t MAX_SWITCHES = 8; // Max number of switches (up to MAX_SWITCHES_SET) -const uint8_t MAX_KEYS = 8; // Max number of keys or buttons (up to 28) +const uint8_t MAX_SWITCHES = 8; // Max number of switches selectable on GPIO +const uint8_t MAX_KEYS = 8; // Max number of keys or buttons selectable on GPIO #endif // ESP8266 #ifdef ESP32 -const uint8_t MAX_RELAYS = 28; // Max number of relays (up to 28) +const uint8_t MAX_RELAYS = 28; // Max number of relays selectable on GPIO const uint8_t MAX_INTERLOCKS = 14; // Max number of interlock groups (up to MAX_INTERLOCKS_SET) -const uint8_t MAX_SWITCHES = 28; // Max number of switches (up to MAX_SWITCHES_SET) -const uint8_t MAX_KEYS = 28; // Max number of keys or buttons (up to 28) +const uint8_t MAX_SWITCHES = 28; // Max number of switches selectable on GPIO +const uint8_t MAX_KEYS = 28; // Max number of keys or buttons selectable on GPIO #endif // ESP32 +const uint8_t MAX_RELAYS_SET = 28; // Max number of relays const uint8_t MAX_KEYS_SET = 28; // Max number of keys // Changes to the following MAX_ defines will impact settings layout -const uint8_t MAX_INTERLOCKS_SET = 14; // Max number of interlock groups (MAX_RELAYS / 2) +const uint8_t MAX_INTERLOCKS_SET = 14; // Max number of interlock groups (MAX_RELAYS_SET / 2) const uint8_t MAX_SWITCHES_SET = 28; // Max number of switches const uint8_t MAX_LEDS = 4; // Max number of leds const uint8_t MAX_PWMS_LEGACY = 5; // Max number of PWM channels in first settings block - Legacy limit for ESP8266, but extended for ESP32 (see below) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_12_discovery.ino b/tasmota/tasmota_xdrv_driver/xdrv_12_discovery.ino index d0486f2a8..cd5bcb71b 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_12_discovery.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_12_discovery.ino @@ -88,7 +88,7 @@ void TasDiscoverMessage(void) { SettingsText(SET_MQTTPREFIX2), SettingsText(SET_MQTTPREFIX3)); - uint8_t light_idx = MAX_RELAYS + 1; // Will store the starting position of the lights + uint8_t light_idx = MAX_RELAYS_SET + 1; // Will store the starting position of the lights uint8_t light_subtype = 0; bool light_controller_isCTRGBLinked = false; #ifdef USE_LIGHT @@ -107,9 +107,9 @@ void TasDiscoverMessage(void) { } #endif // USE_LIGHT - uint16_t Relay[MAX_RELAYS] = { 0 }; // Base array to store the relay type - uint16_t Shutter[MAX_RELAYS] = { 0 }; // Array to store a temp list for shutters - for (uint32_t i = 0; i < MAX_RELAYS; i++) { + uint16_t Relay[MAX_RELAYS_SET] = { 0 }; // Base array to store the relay type + uint16_t Shutter[MAX_RELAYS_SET] = { 0 }; // Array to store a temp list for shutters + for (uint32_t i = 0; i < MAX_RELAYS_SET; i++) { if (i < TasmotaGlobal.devices_present) { #ifdef USE_SHUTTER diff --git a/tasmota/tasmota_xdrv_driver/xdrv_12_home_assistant.ino b/tasmota/tasmota_xdrv_driver/xdrv_12_home_assistant.ino index 5cc138881..2790bade4 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_12_home_assistant.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_12_home_assistant.ino @@ -282,7 +282,7 @@ void HassDiscoverMessage(void) { SettingsText(SET_MQTTPREFIX2), SettingsText(SET_MQTTPREFIX3)); - uint8_t light_idx = MAX_RELAYS + 1; // Will store the starting position of the lights + uint8_t light_idx = MAX_RELAYS_SET + 1; // Will store the starting position of the lights uint8_t light_subtype = 0; bool light_controller_isCTRGBLinked = false; #ifdef USE_LIGHT @@ -301,9 +301,9 @@ void HassDiscoverMessage(void) { } #endif // USE_LIGHT - uint16_t Relay[MAX_RELAYS] = { 0 }; // Base array to store the relay type - uint16_t Shutter[MAX_RELAYS] = { 0 }; // Array to store a temp list for shutters - for (uint32_t i = 0; i < MAX_RELAYS; i++) { + uint16_t Relay[MAX_RELAYS_SET] = { 0 }; // Base array to store the relay type + uint16_t Shutter[MAX_RELAYS_SET] = { 0 }; // Array to store a temp list for shutters + for (uint32_t i = 0; i < MAX_RELAYS_SET; i++) { if (i < TasmotaGlobal.devices_present) { #ifdef USE_SHUTTER From 4ad6807d7e0a79b5da226f3640409bf8dbb25c77 Mon Sep 17 00:00:00 2001 From: Barbudor Date: Sun, 12 Feb 2023 08:44:40 +0100 Subject: [PATCH 254/262] Fixes GPS bad year + drift calculation (#17932) --- tasmota/tasmota_xsns_sensor/xsns_60_GPS.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tasmota/tasmota_xsns_sensor/xsns_60_GPS.ino b/tasmota/tasmota_xsns_sensor/xsns_60_GPS.ino index b128af960..c170e1b0e 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_60_GPS.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_60_GPS.ino @@ -628,7 +628,7 @@ bool UBXHandlePOSLLH() DEBUG_SENSOR_LOG(PSTR("UBX: iTOW: %u"),UBX.Message.navPosllh.iTOW); if (UBX.state.gpsFix>1) { if (UBX.mode.filter_noise) { - if ((UBX.Message.navPosllh.lat-UBX.rec_buffer.values.lat= 2023)) { UBX.state.timeOffset = millis(); // iTOW%1000 should be 0 here, when NTP-server is enabled and in "pure mode" DEBUG_SENSOR_LOG(PSTR("UBX: UTC-Time is valid")); bool resync = (Rtc.utc_time > UBX.utc_time); // Sync local time every hour From dbffcac195fa944b4a43a6160881209049d66da3 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 12 Feb 2023 12:19:02 +0100 Subject: [PATCH 255/262] Shelly Pro 4PM reduce number of SPI updates --- .../xdrv_88_esp32_shelly_pro.ino | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro.ino b/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro.ino index d6f3d1d10..16dd8db3e 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro.ino @@ -88,7 +88,10 @@ enum SP4MCP23X17GPIORegisters { uint8_t sp4_mcp23s17_olata = 0; uint8_t sp4_mcp23s17_olatb = 0; +bool sp4_spi_busy; + void SP4Mcp23S17Enable(void) { + sp4_spi_busy = true; SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0)); digitalWrite(SPro.pin_register_cs, 0); } @@ -96,6 +99,7 @@ void SP4Mcp23S17Enable(void) { void SP4Mcp23S17Disable(void) { SPI.endTransaction(); digitalWrite(SPro.pin_register_cs, 1); + sp4_spi_busy = false; } uint32_t SP4Mcp23S17Read16(uint8_t reg) { @@ -408,11 +412,21 @@ void ShellyProPower(void) { // AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Set Power 0x%08X"), XdrvMailbox.index); power_t rpower = XdrvMailbox.index; +/* for (uint32_t i = 0; i < 4; i++) { power_t state = rpower &1; - SP4Mcp23S17DigitalWrite(sp4_relay_pin[i], state); + SP4Mcp23S17DigitalWrite(sp4_relay_pin[i], state); // 4 SPI writes rpower >>= 1; // Select next power } +*/ + for (uint32_t i = 0; i < 4; i++) { + power_t state = rpower &1; + uint32_t bit = sp4_relay_pin[i] -8; // Adjust by 8 bits + bitWrite(sp4_mcp23s17_olatb, bit, state); + rpower >>= 1; // Select next power + } + SP4Mcp23S17Write(SP4_MCP23S17_OLATB, sp4_mcp23s17_olatb); // 1 SPI write + } } From ec564736311d798e2e539eb9473c61025c0dc135 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 12 Feb 2023 14:05:33 +0100 Subject: [PATCH 256/262] Refactor XxxSet and XxxCal energy commands --- .../tasmota_xdrv_driver/xdrv_03_energy.ino | 64 +++++---------- .../xdrv_03_esp32_energy.ino | 78 ++++++++----------- 2 files changed, 54 insertions(+), 88 deletions(-) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino b/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino index 67d891fe7..45613230e 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino @@ -911,69 +911,45 @@ void EnergyCommandCalSetResponse(uint32_t cal_type) { } void EnergyCommandCalResponse(uint32_t cal_type) { - Response_P(PSTR("{\"%s\":"), XdrvMailbox.command); - EnergyCommandCalSetResponse(cal_type); -} - -void EnergyCommandSetCalResponse(uint32_t cal_type) { - Response_P(PSTR("{\"%sCal\":"), XdrvMailbox.command); - EnergyCommandCalSetResponse(cal_type); + Energy->command_code = cal_type; // Is XxxCal command too + if (XnrgCall(FUNC_COMMAND)) { // XxxCal + Response_P(PSTR("{\"%s\":"), XdrvMailbox.command); + EnergyCommandCalSetResponse(cal_type); + } } void CmndPowerCal(void) { - Energy->command_code = CMND_POWERCAL; - if (XnrgCall(FUNC_COMMAND)) { // microseconds - EnergyCommandCalResponse(ENERGY_POWER_CALIBRATION); - } + EnergyCommandCalResponse(ENERGY_POWER_CALIBRATION); } - void CmndVoltageCal(void) { - Energy->command_code = CMND_VOLTAGECAL; - if (XnrgCall(FUNC_COMMAND)) { // microseconds - EnergyCommandCalResponse(ENERGY_VOLTAGE_CALIBRATION); - } + EnergyCommandCalResponse(ENERGY_VOLTAGE_CALIBRATION); } - void CmndCurrentCal(void) { - Energy->command_code = CMND_CURRENTCAL; - if (XnrgCall(FUNC_COMMAND)) { // microseconds - EnergyCommandCalResponse(ENERGY_CURRENT_CALIBRATION); - } + EnergyCommandCalResponse(ENERGY_CURRENT_CALIBRATION); +} +void CmndFrequencyCal(void) { + EnergyCommandCalResponse(ENERGY_FREQUENCY_CALIBRATION); } -void CmndFrequencyCal(void) { - Energy->command_code = CMND_FREQUENCYCAL; - if (XnrgCall(FUNC_COMMAND)) { // microseconds - EnergyCommandCalResponse(ENERGY_FREQUENCY_CALIBRATION); +void EnergyCommandSetCalResponse(uint32_t cal_type) { + Energy->command_code = CMND_POWERSET + cal_type; // Adjust for XxxSet command + if (XnrgCall(FUNC_COMMAND)) { // XxxSet + Response_P(PSTR("{\"%sCal\":"), XdrvMailbox.command); + EnergyCommandCalSetResponse(cal_type); } } void CmndPowerSet(void) { - Energy->command_code = CMND_POWERSET; - if (XnrgCall(FUNC_COMMAND)) { // Watt - EnergyCommandSetCalResponse(ENERGY_POWER_CALIBRATION); - } + EnergyCommandSetCalResponse(ENERGY_POWER_CALIBRATION); } - void CmndVoltageSet(void) { - Energy->command_code = CMND_VOLTAGESET; - if (XnrgCall(FUNC_COMMAND)) { // Volt - EnergyCommandSetCalResponse(ENERGY_VOLTAGE_CALIBRATION); - } + EnergyCommandSetCalResponse(ENERGY_VOLTAGE_CALIBRATION); } - void CmndCurrentSet(void) { - Energy->command_code = CMND_CURRENTSET; - if (XnrgCall(FUNC_COMMAND)) { // milliAmpere - EnergyCommandSetCalResponse(ENERGY_CURRENT_CALIBRATION); - } + EnergyCommandSetCalResponse(ENERGY_CURRENT_CALIBRATION); } - void CmndFrequencySet(void) { - Energy->command_code = CMND_FREQUENCYSET; - if (XnrgCall(FUNC_COMMAND)) { // Hz - EnergyCommandSetCalResponse(ENERGY_FREQUENCY_CALIBRATION); - } + EnergyCommandSetCalResponse(ENERGY_FREQUENCY_CALIBRATION); } void CmndModuleAddress(void) { diff --git a/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino b/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino index 85b146bb7..603a6fa2e 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino @@ -1125,69 +1125,59 @@ void EnergyCommandCalSetResponse(uint32_t cal_type) { } void EnergyCommandCalResponse(uint32_t cal_type) { - Response_P(PSTR("{\"%s\":"), XdrvMailbox.command); - EnergyCommandCalSetResponse(cal_type); -} - -void EnergyCommandSetCalResponse(uint32_t cal_type) { - Response_P(PSTR("{\"%sCal\":"), XdrvMailbox.command); - EnergyCommandCalSetResponse(cal_type); + Energy->command_code = cal_type; // Is XxxCal command too + if (XnrgCall(FUNC_COMMAND)) { // XxxCal + Response_P(PSTR("{\"%s\":"), XdrvMailbox.command); + EnergyCommandCalSetResponse(cal_type); + } } void CmndPowerCal(void) { - Energy->command_code = CMND_POWERCAL; - if (XnrgCall(FUNC_COMMAND)) { // microseconds - EnergyCommandCalResponse(ENERGY_POWER_CALIBRATION); - } + EnergyCommandCalResponse(ENERGY_POWER_CALIBRATION); } - void CmndVoltageCal(void) { - Energy->command_code = CMND_VOLTAGECAL; - if (XnrgCall(FUNC_COMMAND)) { // microseconds - EnergyCommandCalResponse(ENERGY_VOLTAGE_CALIBRATION); - } + EnergyCommandCalResponse(ENERGY_VOLTAGE_CALIBRATION); } - void CmndCurrentCal(void) { - Energy->command_code = CMND_CURRENTCAL; - if (XnrgCall(FUNC_COMMAND)) { // microseconds - EnergyCommandCalResponse(ENERGY_CURRENT_CALIBRATION); - } + EnergyCommandCalResponse(ENERGY_CURRENT_CALIBRATION); +} +void CmndFrequencyCal(void) { + EnergyCommandCalResponse(ENERGY_FREQUENCY_CALIBRATION); } -void CmndFrequencyCal(void) { - Energy->command_code = CMND_FREQUENCYCAL; - if (XnrgCall(FUNC_COMMAND)) { // microseconds - EnergyCommandCalResponse(ENERGY_FREQUENCY_CALIBRATION); +void EnergyCommandSetCalResponse(uint32_t cal_type) { + bool serviced = false; + Energy->command_code = CMND_POWERSET + cal_type; // Adjust for XxxSet command + if (0 == XdrvMailbox.index) { // XxxSet0 + for (XdrvMailbox.index = 1; XdrvMailbox.index <= Energy->phase_count; XdrvMailbox.index++) { + if (XnrgCall(FUNC_COMMAND)) { + if (XdrvMailbox.payload > 99) { + EnergySetCalibration(cal_type, XdrvMailbox.payload, XdrvMailbox.index -1); + } + } + } + XdrvMailbox.payload = 2; // No more updates but response only + serviced = true; + } else { + serviced = (XnrgCall(FUNC_COMMAND)); // XxxSet + } + if (serviced) { + Response_P(PSTR("{\"%sCal\":"), XdrvMailbox.command); + EnergyCommandCalSetResponse(cal_type); } } void CmndPowerSet(void) { - Energy->command_code = CMND_POWERSET; - if (XnrgCall(FUNC_COMMAND)) { // Watt - EnergyCommandSetCalResponse(ENERGY_POWER_CALIBRATION); - } + EnergyCommandSetCalResponse(ENERGY_POWER_CALIBRATION); } - void CmndVoltageSet(void) { - Energy->command_code = CMND_VOLTAGESET; - if (XnrgCall(FUNC_COMMAND)) { // Volt - EnergyCommandSetCalResponse(ENERGY_VOLTAGE_CALIBRATION); - } + EnergyCommandSetCalResponse(ENERGY_VOLTAGE_CALIBRATION); } - void CmndCurrentSet(void) { - Energy->command_code = CMND_CURRENTSET; - if (XnrgCall(FUNC_COMMAND)) { // milliAmpere - EnergyCommandSetCalResponse(ENERGY_CURRENT_CALIBRATION); - } + EnergyCommandSetCalResponse(ENERGY_CURRENT_CALIBRATION); } - void CmndFrequencySet(void) { - Energy->command_code = CMND_FREQUENCYSET; - if (XnrgCall(FUNC_COMMAND)) { // Hz - EnergyCommandSetCalResponse(ENERGY_FREQUENCY_CALIBRATION); - } + EnergyCommandSetCalResponse(ENERGY_FREQUENCY_CALIBRATION); } void CmndModuleAddress(void) { From e0584b2157c041c6d6676a75e2e4976e6c294f45 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 12 Feb 2023 16:09:28 +0100 Subject: [PATCH 257/262] Refactor switches and buttons - Fix Tuya switches --- tasmota/tasmota_support/support_button_v2.ino | 419 -------------- tasmota/tasmota_support/support_button_v3.ino | 536 ------------------ tasmota/tasmota_support/support_button_v4.ino | 28 +- tasmota/tasmota_support/support_switch_v3.ino | 454 --------------- tasmota/tasmota_support/support_switch_v4.ino | 65 +-- .../tasmota_xdrv_driver/xdrv_10_scripter.ino | 2 +- .../xdrv_16_tuyamcu_v1.ino | 24 +- .../xdrv_16_tuyamcu_v2.ino | 42 +- .../xdrv_39_thermostat.ino | 2 +- .../xdrv_52_3_berry_tasmota.ino | 2 +- 10 files changed, 87 insertions(+), 1487 deletions(-) delete mode 100644 tasmota/tasmota_support/support_button_v2.ino delete mode 100644 tasmota/tasmota_support/support_button_v3.ino delete mode 100644 tasmota/tasmota_support/support_switch_v3.ino diff --git a/tasmota/tasmota_support/support_button_v2.ino b/tasmota/tasmota_support/support_button_v2.ino deleted file mode 100644 index cbd6eb612..000000000 --- a/tasmota/tasmota_support/support_button_v2.ino +++ /dev/null @@ -1,419 +0,0 @@ -/* - support_button.ino - button support for Tasmota - - Copyright (C) 2021 Federico Leoni and Theo Arends - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -//#define BUTTON_V2 -#ifdef BUTTON_V2 -/*********************************************************************************************\ - * Button support -\*********************************************************************************************/ - -#define MAX_RELAY_BUTTON1 5 // Max number of relay controlled by BUTTON1 - -#define TOUCH_PIN_THRESHOLD 12 // Smaller value will treated as button press -#define TOUCH_HIT_THRESHOLD 3 // successful hits to filter out noise - -const char kMultiPress[] PROGMEM = "|SINGLE|DOUBLE|TRIPLE|QUAD|PENTA|CLEAR|"; - -struct BUTTON { - uint32_t debounce = 0; // Button debounce timer - uint32_t no_pullup_mask = 0; // key no pullup flag (1 = no pullup) - uint32_t pulldown_mask = 0; // key pulldown flag (1 = pulldown) - uint32_t inverted_mask = 0; // Key inverted flag (1 = inverted) -#ifdef ESP32 - uint32_t touch_mask = 0; // Touch flag (1 = inverted) -#endif // ESP32 - uint16_t hold_timer[MAX_KEYS] = { 0 }; // Timer for button hold - uint16_t dual_code = 0; // Sonoff dual received code - - uint8_t last_state[MAX_KEYS]; // Last button states - uint8_t window_timer[MAX_KEYS] = { 0 }; // Max time between button presses to record press count - uint8_t press_counter[MAX_KEYS] = { 0 }; // Number of button presses within Button.window_timer - - uint8_t dual_receive_count = 0; // Sonoff dual input flag -#ifdef ESP32 - uint8_t touch_hits[MAX_KEYS] = { 0 }; // Hits in a row to filter out noise -#endif // ESP32 - uint8_t present = 0; // Number of buttons found flag -} Button; - -#ifdef ESP32 -struct TOUCH_BUTTON { - uint32_t calibration = 0; // Bitfield - uint32_t pin_threshold = TOUCH_PIN_THRESHOLD; - uint8_t hit_threshold = TOUCH_HIT_THRESHOLD; -} TouchButton; -#endif // ESP32 - -/********************************************************************************************/ - -void ButtonPullupFlag(uint32_t button_bit) { - bitSet(Button.no_pullup_mask, button_bit); -} - -void ButtonPulldownFlag(uint32_t button_bit) { - bitSet(Button.pulldown_mask, button_bit); -} - -void ButtonInvertFlag(uint32_t button_bit) { - bitSet(Button.inverted_mask, button_bit); -} - -#ifdef ESP32 -void ButtonTouchFlag(uint32_t button_bit) { - bitSet(Button.touch_mask, button_bit); -} -#endif // ESP32 - -void ButtonInit(void) { - Button.present = 0; -#ifdef ESP8266 - if ((SONOFF_DUAL == TasmotaGlobal.module_type) || (CH4 == TasmotaGlobal.module_type)) { - Button.present++; - } -#endif // ESP8266 - for (uint32_t i = 0; i < MAX_KEYS; i++) { - Button.last_state[i] = NOT_PRESSED; - if (PinUsed(GPIO_KEY1, i)) { - Button.present++; -#ifdef ESP8266 - pinMode(Pin(GPIO_KEY1, i), bitRead(Button.no_pullup_mask, i) ? INPUT : ((16 == Pin(GPIO_KEY1, i)) ? INPUT_PULLDOWN_16 : INPUT_PULLUP)); -#endif // ESP8266 -#ifdef ESP32 - pinMode(Pin(GPIO_KEY1, i), bitRead(Button.pulldown_mask, i) ? INPUT_PULLDOWN : bitRead(Button.no_pullup_mask, i) ? INPUT : INPUT_PULLUP); -#endif // ESP32 - } -#ifdef USE_ADC - else if (PinUsed(GPIO_ADC_BUTTON, i) || PinUsed(GPIO_ADC_BUTTON_INV, i)) { - Button.present++; - } -#endif // USE_ADC - } -} - -uint8_t ButtonSerial(uint8_t serial_in_byte) { - if (Button.dual_receive_count) { - Button.dual_receive_count--; - if (Button.dual_receive_count) { - Button.dual_code = (Button.dual_code << 8) | serial_in_byte; - serial_in_byte = 0; - } else { - if (serial_in_byte != 0xA1) { - Button.dual_code = 0; // 0xA1 - End of Sonoff dual button code - } - } - } - if (0xA0 == serial_in_byte) { // 0xA0 - Start of Sonoff dual button code - serial_in_byte = 0; - Button.dual_code = 0; - Button.dual_receive_count = 3; - } - - return serial_in_byte; -} - -/*********************************************************************************************\ - * Button handler with single press only or multi-press and hold on all buttons - * - * ButtonDebounce (50) - Debounce time in mSec - * SetOption1 (0) - If set do not execute commands WifiConfig and Reset - * SetOption11 (0) - If set perform single press action on double press and reverse (on two relay devices only) - * SetOption13 (0) - If set act on single press only - * SetOption73 (0) - Decouple button from relay and send just mqtt topic -\*********************************************************************************************/ - -void ButtonHandler(void) { - if (TasmotaGlobal.uptime < 4) { return; } // Block GPIO for 4 seconds after poweron to workaround Wemos D1 / Obi RTS circuit - - uint8_t hold_time_extent = IMMINENT_RESET_FACTOR; // Extent hold time factor in case of iminnent Reset command - uint16_t loops_per_second = 1000 / Settings->button_debounce; // ButtonDebounce (50) - char scmnd[20]; - - for (uint32_t button_index = 0; button_index < MAX_KEYS; button_index++) { - uint8_t button = NOT_PRESSED; - uint8_t button_present = 0; - -#ifdef ESP8266 - if (!button_index && ((SONOFF_DUAL == TasmotaGlobal.module_type) || (CH4 == TasmotaGlobal.module_type))) { - button_present = 1; - if (Button.dual_code) { - AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_BUTTON " " D_CODE " %04X"), Button.dual_code); - button = PRESSED; - if (0xF500 == Button.dual_code) { // Button hold - Button.hold_timer[button_index] = (loops_per_second * Settings->param[P_HOLD_TIME] / 10) -1; // SetOption32 (40) - hold_time_extent = 1; - } - Button.dual_code = 0; - } - } else -#endif // ESP8266 - if (PinUsed(GPIO_KEY1, button_index)) { - button_present = 1; -#ifdef ESP32 -#ifndef CONFIG_IDF_TARGET_ESP32C3 - if (bitRead(Button.touch_mask, button_index)) { // Touch - uint32_t _value = touchRead(Pin(GPIO_KEY1, button_index)); - button = NOT_PRESSED; - if (_value != 0) { // Probably read-error - if (_value < TouchButton.pin_threshold) { - if (++Button.touch_hits[button_index] > TouchButton.hit_threshold) { - if (!bitRead(TouchButton.calibration, button_index+1)) { - button = PRESSED; - } - } - } else { - Button.touch_hits[button_index] = 0; - } - } else { - Button.touch_hits[button_index] = 0; - } - if (bitRead(TouchButton.calibration, button_index+1)) { - AddLog(LOG_LEVEL_INFO, PSTR("PLOT: %u, %u, %u,"), button_index+1, _value, Button.touch_hits[button_index]); // Button number (1..4), value, continuous hits under threshold - } - } else -#endif // not ESP32C3 -#endif // ESP32 - { // Normal button - button = (digitalRead(Pin(GPIO_KEY1, button_index)) != bitRead(Button.inverted_mask, button_index)); - } - } -#ifdef USE_ADC - else if (PinUsed(GPIO_ADC_BUTTON, button_index)) { - button_present = 1; - button = AdcGetButton(Pin(GPIO_ADC_BUTTON, button_index)); - } - else if (PinUsed(GPIO_ADC_BUTTON_INV, button_index)) { - button_present = 1; - button = AdcGetButton(Pin(GPIO_ADC_BUTTON_INV, button_index)); - } -#endif // USE_ADC - if (button_present) { - XdrvMailbox.index = button_index; - XdrvMailbox.payload = button; - if (XdrvCall(FUNC_BUTTON_PRESSED)) { - // Serviced - } -#ifdef ESP8266 - else if (SONOFF_4CHPRO == TasmotaGlobal.module_type) { - if (Button.hold_timer[button_index]) { Button.hold_timer[button_index]--; } - - bool button_pressed = false; - if ((PRESSED == button) && (NOT_PRESSED == Button.last_state[button_index])) { - AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_LEVEL_10), button_index +1); - Button.hold_timer[button_index] = loops_per_second; - button_pressed = true; - } - if ((NOT_PRESSED == button) && (PRESSED == Button.last_state[button_index])) { - AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_LEVEL_01), button_index +1); - if (!Button.hold_timer[button_index]) { button_pressed = true; } // Do not allow within 1 second - } - if (button_pressed) { - if (!Settings->flag3.mqtt_buttons) { // SetOption73 (0) - Decouple button from relay and send just mqtt topic - if (!SendKey(KEY_BUTTON, button_index +1, POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set - ExecuteCommandPower(button_index +1, POWER_TOGGLE, SRC_BUTTON); // Execute Toggle command internally - } - } else { - MqttButtonTopic(button_index +1, 1, 0); // SetOption73 (0) - Decouple button from relay and send just mqtt topic - } - } - } -#endif // ESP8266 - else { - if ((PRESSED == button) && (NOT_PRESSED == Button.last_state[button_index])) { - - if (Settings->flag.button_single) { // SetOption13 (0) - Allow only single button press for immediate action, - if (!Settings->flag3.mqtt_buttons) { // SetOption73 (0) - Decouple button from relay and send just mqtt topic - AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_IMMEDIATE), button_index +1); - if (!SendKey(KEY_BUTTON, button_index +1, POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set - ExecuteCommandPower(button_index +1, POWER_TOGGLE, SRC_BUTTON); // Execute Toggle command internally - } - } else { - MqttButtonTopic(button_index +1, 1, 0); // SetOption73 1 - Decouple button from relay and send just mqtt topic - } - } else { - Button.press_counter[button_index] = (Button.window_timer[button_index]) ? Button.press_counter[button_index] +1 : 1; - AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_BUTTON "%d " D_MULTI_PRESS " %d"), button_index +1, Button.press_counter[button_index]); - Button.window_timer[button_index] = loops_per_second / 2; // 0.5 second multi press window - } - TasmotaGlobal.blinks = 201; - } - - if (NOT_PRESSED == button) { - Button.hold_timer[button_index] = 0; - if (Settings->flag3.mqtt_buttons && (PRESSED == Button.last_state[button_index]) && !Button.press_counter[button_index]) { // SetOption73 (0) - Decouple button from relay and send just mqtt topic - MqttButtonTopic(button_index +1, 6, 0); - } - } else { - Button.hold_timer[button_index]++; - if (Settings->flag.button_single) { // SetOption13 (0) - Allow only single button press for immediate action - if (Button.hold_timer[button_index] == loops_per_second * hold_time_extent * Settings->param[P_HOLD_TIME] / 10) { // SetOption32 (40) - Button held for factor times longer - snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_SETOPTION "13 0")); // Disable single press only - ExecuteCommand(scmnd, SRC_BUTTON); - } - } else { - if (Button.hold_timer[button_index] == loops_per_second * Settings->param[P_HOLD_TIME] / 10) { // SetOption32 (40) - Button hold - Button.press_counter[button_index] = 0; - if (Settings->flag3.mqtt_buttons) { // SetOption73 (0) - Decouple button from relay and send just mqtt topic - MqttButtonTopic(button_index +1, 3, 1); - } else { - SendKey(KEY_BUTTON, button_index +1, POWER_HOLD); // Execute Hold command via MQTT if ButtonTopic is set - } - } else { - if (Settings->flag.button_restrict) { // SetOption1 (0) - Control button multipress - if (Settings->param[P_HOLD_IGNORE] > 0) { // SetOption40 (0) - Do not ignore button hold - if (Button.hold_timer[button_index] > loops_per_second * Settings->param[P_HOLD_IGNORE] / 10) { - Button.hold_timer[button_index] = 0; // Reset button hold counter to stay below hold trigger - Button.press_counter[button_index] = 0; // Discard button press to disable functionality - } - } - } else { - if ((Button.hold_timer[button_index] == loops_per_second * hold_time_extent * Settings->param[P_HOLD_TIME] / 10)) { // SetOption32 (40) - Button held for factor times longer - Button.press_counter[button_index] = 0; - snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_RESET " 1")); - ExecuteCommand(scmnd, SRC_BUTTON); - } - } - } - } - } - - if (!Settings->flag.button_single) { // SetOption13 (0) - Allow multi-press - if (Button.window_timer[button_index]) { - Button.window_timer[button_index]--; - } else { - if (!TasmotaGlobal.restart_flag && !Button.hold_timer[button_index] && (Button.press_counter[button_index] > 0) && (Button.press_counter[button_index] < 7)) { - - bool single_press = false; - if (Button.press_counter[button_index] < 3) { // Single or Double press -#ifdef ESP8266 - if ((SONOFF_DUAL_R2 == TasmotaGlobal.module_type) || (SONOFF_DUAL == TasmotaGlobal.module_type) || (CH4 == TasmotaGlobal.module_type)) { - single_press = true; - } else -#endif // ESP8266 - { - single_press = (Settings->flag.button_swap +1 == Button.press_counter[button_index]); // SetOption11 (0) - if ((1 == Button.present) && (2 == TasmotaGlobal.devices_present)) { // Single Button with two devices only - if (Settings->flag.button_swap) { // SetOption11 (0) - Button.press_counter[button_index] = (single_press) ? 1 : 2; - } - } - } - } - - XdrvMailbox.index = button_index; - XdrvMailbox.payload = Button.press_counter[button_index]; - if (XdrvCall(FUNC_BUTTON_MULTI_PRESSED)) { - // Serviced - } else - -#ifdef ROTARY_V1 - if (!RotaryButtonPressed(button_index)) { -#endif - if (!Settings->flag3.mqtt_buttons && single_press && SendKey(KEY_BUTTON, button_index + Button.press_counter[button_index], POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set - // Success - } else { - if (Button.press_counter[button_index] < 6) { // Single to Penta press -// if (WifiState() > WIFI_RESTART) { // Wifimanager active -// TasmotaGlobal.restart_flag = 1; -// } - if (!Settings->flag3.mqtt_buttons) { // SetOption73 - Detach buttons from relays and enable MQTT action state for multipress - if (Button.press_counter[button_index] == 1) { // By default first press always send a TOGGLE (2) - ExecuteCommandPower(button_index + Button.press_counter[button_index], POWER_TOGGLE, SRC_BUTTON); - } else { - SendKey(KEY_BUTTON, button_index +1, Button.press_counter[button_index] +9); // 2,3,4 and 5 press send just the key value (11,12,13 and 14) for rules - if (0 == button_index) { // BUTTON1 can toggle up to 5 relays if present. If a relay is not present will send out the key value (2,11,12,13 and 14) for rules - bool valid_relay = PinUsed(GPIO_REL1, Button.press_counter[button_index]-1); -#ifdef ESP8266 - if ((SONOFF_DUAL == TasmotaGlobal.module_type) || (CH4 == TasmotaGlobal.module_type)) { - valid_relay = (Button.press_counter[button_index] <= TasmotaGlobal.devices_present); - } -#endif // ESP8266 - if ((Button.press_counter[button_index] > 1) && valid_relay && (Button.press_counter[button_index] <= MAX_RELAY_BUTTON1)) { - ExecuteCommandPower(button_index + Button.press_counter[button_index], POWER_TOGGLE, SRC_BUTTON); // Execute Toggle command internally -// AddLog(LOG_LEVEL_DEBUG, PSTR("DBG: Relay%d found on GPIO%d"), Button.press_counter[button_index], Pin(GPIO_REL1, Button.press_counter[button_index]-1)); - } - } - } - } - - } else { // 6 press start wificonfig 2 - if (!Settings->flag.button_restrict) { // SetOption1 - Control button multipress - snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_WIFICONFIG " 2")); - ExecuteCommand(scmnd, SRC_BUTTON); - } - } - if (Settings->flag3.mqtt_buttons) { // SetOption73 (0) - Decouple button from relay and send just mqtt topic - if (Button.press_counter[button_index] >= 1 && Button.press_counter[button_index] <= 5) { - MqttButtonTopic(button_index +1, Button.press_counter[button_index], 0); - } - } - } -#ifdef ROTARY_V1 - } -#endif - Button.press_counter[button_index] = 0; - } - } - } - - } - } - Button.last_state[button_index] = button; - } -} - -/* -void MqttButtonTopic(uint8_t button_id, uint8_t action, uint8_t hold) { - char scommand[CMDSZ]; - char stopic[TOPSZ]; - char mqttstate[7]; - - SendKey(KEY_BUTTON, button_id, (hold) ? 3 : action +9); - - if (!Settings->flag.hass_discovery) { - GetTextIndexed(mqttstate, sizeof(mqttstate), action, kMultiPress); - snprintf_P(scommand, sizeof(scommand), PSTR("BUTTON%d"), button_id); - GetTopic_P(stopic, STAT, TasmotaGlobal.mqtt_topic, scommand); - Response_P(S_JSON_COMMAND_SVALUE, "ACTION", (hold) ? SettingsText(SET_STATE_TXT4) : mqttstate); - MqttPublish(stopic); - } -} -*/ - -void MqttButtonTopic(uint32_t button_id, uint32_t action, uint32_t hold) { - SendKey(KEY_BUTTON, button_id, (hold) ? 3 : action +9); - - if (!Settings->flag.hass_discovery) { // SetOption19 - Control Home Assistant automatic discovery (See SetOption59) - char scommand[10]; - snprintf_P(scommand, sizeof(scommand), PSTR(D_JSON_BUTTON "%d"), button_id); - char mqttstate[7]; - Response_P(S_JSON_SVALUE_ACTION_SVALUE, scommand, (hold) ? SettingsText(SET_STATE_TXT4) : GetTextIndexed(mqttstate, sizeof(mqttstate), action, kMultiPress)); - MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_STAT, scommand); - } -} - -void ButtonLoop(void) { - if (Button.present) { - if (TimeReached(Button.debounce)) { - SetNextTimeInterval(Button.debounce, Settings->button_debounce); // ButtonDebounce (50) - ButtonHandler(); - } - } -} - -#endif // BUTTON_V2 diff --git a/tasmota/tasmota_support/support_button_v3.ino b/tasmota/tasmota_support/support_button_v3.ino deleted file mode 100644 index 92e278ec0..000000000 --- a/tasmota/tasmota_support/support_button_v3.ino +++ /dev/null @@ -1,536 +0,0 @@ -/* - support_button.ino - button support for Tasmota - - Copyright (C) 2022 Federico Leoni and Theo Arends - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -//#define BUTTON_V3 -#ifdef BUTTON_V3 -/*********************************************************************************************\ - * Button support with input filter - * - * Inspired by (https://github.com/OLIMEX/olimex-iot-firmware-esp8266/blob/master/olimex/user/user_switch2.c) -\*********************************************************************************************/ - -#define MAX_RELAY_BUTTON1 5 // Max number of relay controlled by BUTTON1 - -const uint8_t BUTTON_PROBE_INTERVAL = 10; // Time in milliseconds between button input probe -const uint8_t BUTTON_FAST_PROBE_INTERVAL = 2; // Time in milliseconds between button input probe for AC detection -const uint8_t BUTTON_AC_PERIOD = (20 + BUTTON_FAST_PROBE_INTERVAL - 1) / BUTTON_FAST_PROBE_INTERVAL; // Duration of an AC wave in probe intervals - -const char kMultiPress[] PROGMEM = "|SINGLE|DOUBLE|TRIPLE|QUAD|PENTA|CLEAR|"; - -#include - -Ticker TickerButton; - -struct BUTTON { - uint32_t debounce = 0; // Button debounce timer - uint32_t no_pullup_mask = 0; // key no pullup flag (1 = no pullup) - uint32_t pulldown_mask = 0; // key pulldown flag (1 = pulldown) - uint32_t inverted_mask = 0; // Key inverted flag (1 = inverted) - uint16_t hold_timer[MAX_KEYS] = { 0 }; // Timer for button hold - uint16_t dual_code = 0; // Sonoff dual received code - uint8_t state[MAX_KEYS] = { 0 }; - uint8_t last_state[MAX_KEYS]; // Last button states - uint8_t virtual_state[MAX_KEYS]; // Virtual button states - uint8_t window_timer[MAX_KEYS] = { 0 }; // Max time between button presses to record press count - uint8_t press_counter[MAX_KEYS] = { 0 }; // Number of button presses within Button.window_timer - uint8_t dual_receive_count = 0; // Sonoff dual input flag - uint8_t first_change = 0; - uint8_t present = 0; // Number of buttons found flag - uint8_t mutex; -} Button; - -#if defined(SOC_TOUCH_VERSION_1) || defined(SOC_TOUCH_VERSION_2) -struct TOUCH_BUTTON { - uint32_t touch_mask = 0; // Touch flag (1 = enabled) - uint32_t calibration = 0; // Bitfield - uint8_t hits[MAX_KEYS] = { 0 }; // Hits in a row to filter out noise -} TouchButton; -#endif // ESP32 SOC_TOUCH_VERSION_1 or SOC_TOUCH_VERSION_2 - -/********************************************************************************************/ - -void ButtonPullupFlag(uint32_t button_bit) { - bitSet(Button.no_pullup_mask, button_bit); -} - -void ButtonPulldownFlag(uint32_t button_bit) { - bitSet(Button.pulldown_mask, button_bit); -} - -void ButtonInvertFlag(uint32_t button_bit) { - bitSet(Button.inverted_mask, button_bit); -} - -#if defined(SOC_TOUCH_VERSION_1) || defined(SOC_TOUCH_VERSION_2) -void ButtonTouchFlag(uint32_t button_bit) { - bitSet(TouchButton.touch_mask, button_bit); -} -#endif // ESP32 SOC_TOUCH_VERSION_1 or SOC_TOUCH_VERSION_2 - -/*********************************************************************************************/ - -void ButtonProbe(void) { - if (Button.mutex || (TasmotaGlobal.uptime < 4)) { return; } // Block GPIO for 4 seconds after poweron to workaround Wemos D1 / Obi RTS circuit - Button.mutex = 1; - - uint32_t state_filter; - uint32_t first_change = Button.first_change; - uint32_t debounce_flags = Settings->button_debounce % 10; - bool force_high = (debounce_flags &1); // 51, 101, 151 etc - bool force_low = (debounce_flags &2); // 52, 102, 152 etc - bool ac_detect = (debounce_flags == 9); // 39, 49, 59 etc - - if (ac_detect) { - if (Settings->button_debounce < 2 * BUTTON_AC_PERIOD * BUTTON_FAST_PROBE_INTERVAL + 9) { - state_filter = 2 * BUTTON_AC_PERIOD; - } else if (Settings->button_debounce > (0x7f - 2 * BUTTON_AC_PERIOD) * BUTTON_FAST_PROBE_INTERVAL) { - state_filter = 0x7f; - } else { - state_filter = (Settings->button_debounce - 9) / BUTTON_FAST_PROBE_INTERVAL; - } - } else { - state_filter = Settings->button_debounce / BUTTON_PROBE_INTERVAL; // 5, 10, 15 - } - - for (uint32_t i = 0; i < MAX_KEYS; i++) { - if (!PinUsed(GPIO_KEY1, i)) { continue; } - - bool button_not_activated; -#if defined(SOC_TOUCH_VERSION_1) || defined(SOC_TOUCH_VERSION_2) - if (bitRead(TouchButton.touch_mask, i)) { - if (ac_detect || bitRead(TouchButton.calibration, i +1)) { continue; } // Touch is slow. Takes 21mS to read - uint32_t value = touchRead(Pin(GPIO_KEY1, i)); -#ifdef SOC_TOUCH_VERSION_2 - button_not_activated = (value < Settings->touch_threshold); // ESPS3 No touch = 24200, Touch > 40000 -#else - button_not_activated = ((value == 0) || (value > Settings->touch_threshold)); // ESP32 No touch = 74, Touch < 40 -#endif - } else -#endif // ESP32 SOC_TOUCH_VERSION_1 or SOC_TOUCH_VERSION_2 - button_not_activated = (digitalRead(Pin(GPIO_KEY1, i)) != bitRead(Button.inverted_mask, i)); - - if (button_not_activated) { - - if (ac_detect) { // Enabled with ButtonDebounce x9 - Button.state[i] |= 0x80; - if (Button.state[i] > 0x80) { - Button.state[i]--; - if (0x80 == Button.state[i]) { - Button.virtual_state[i] = 0; - Button.first_change = false; - } - } - } else { - - if (force_high) { // Enabled with ButtonDebounce x1 - if (1 == Button.virtual_state[i]) { - Button.state[i] = state_filter; // With noisy input keep current state 1 unless constant 0 - } - } - - if (Button.state[i] < state_filter) { - Button.state[i]++; - if (state_filter == Button.state[i]) { - Button.virtual_state[i] = 1; - } - } - } - } else { - - if (ac_detect) { // Enabled with ButtonDebounce x9 - /* - * Moes MS-104B and similar devices using an AC detection circuitry - * on their switch inputs generating an ~4 ms long low pulse every - * AC wave. We start the time measurement on the falling edge. - * - * state: bit7: previous state, bit6..0: counter - */ - if (Button.state[i] & 0x80) { - Button.state[i] &= 0x7f; - if (Button.state[i] < state_filter - 2 * BUTTON_AC_PERIOD) { - Button.state[i] += 2 * BUTTON_AC_PERIOD; - } else { - Button.state[i] = state_filter; - Button.virtual_state[i] = 1; - if (first_change) { - Button.last_state[i] = 1; - Button.first_change = false; - } - } - } else { - if (Button.state[i] > 0x00) { - Button.state[i]--; - if (0x00 == Button.state[i]) { - Button.virtual_state[i] = 0; - Button.first_change = false; - } - } - } - } else { - - if (force_low) { // Enabled with ButtonDebounce x2 - if (0 == Button.virtual_state[i]) { - Button.state[i] = 0; // With noisy input keep current state 0 unless constant 1 - } - } - - if (Button.state[i] > 0) { - Button.state[i]--; - if (0 == Button.state[i]) { - Button.virtual_state[i] = 0; - } - } - } - } - } - Button.mutex = 0; -} - -void ButtonInit(void) { - bool ac_detect = (Settings->button_debounce % 10 == 9); - - Button.present = 0; -#ifdef ESP8266 - if ((SONOFF_DUAL == TasmotaGlobal.module_type) || (CH4 == TasmotaGlobal.module_type)) { - Button.present++; - } -#endif // ESP8266 - for (uint32_t i = 0; i < MAX_KEYS; i++) { - Button.last_state[i] = NOT_PRESSED; - if (PinUsed(GPIO_KEY1, i)) { - Button.present++; -#ifdef ESP8266 - pinMode(Pin(GPIO_KEY1, i), bitRead(Button.no_pullup_mask, i) ? INPUT : ((16 == Pin(GPIO_KEY1, i)) ? INPUT_PULLDOWN_16 : INPUT_PULLUP)); -#endif // ESP8266 -#ifdef ESP32 - pinMode(Pin(GPIO_KEY1, i), bitRead(Button.pulldown_mask, i) ? INPUT_PULLDOWN : bitRead(Button.no_pullup_mask, i) ? INPUT : INPUT_PULLUP); -#endif // ESP32 - if (ac_detect) { - Button.state[i] = 0x80 + 2 * BUTTON_AC_PERIOD; - Button.last_state[i] = 0; // Will set later in the debouncing code - } else { - // Set global now so doesn't change the saved power state on first button check - Button.last_state[i] = (digitalRead(Pin(GPIO_KEY1, i)) != bitRead(Button.inverted_mask, i)); - } - } -#ifdef USE_ADC - else if (PinUsed(GPIO_ADC_BUTTON, i) || PinUsed(GPIO_ADC_BUTTON_INV, i)) { - Button.present++; - } -#endif // USE_ADC - Button.virtual_state[i] = Button.last_state[i]; - } - if (Button.present) { - Button.first_change = true; - TickerButton.attach_ms((ac_detect) ? BUTTON_FAST_PROBE_INTERVAL : BUTTON_PROBE_INTERVAL, ButtonProbe); - } -} - -uint8_t ButtonSerial(uint8_t serial_in_byte) { - if (Button.dual_receive_count) { - Button.dual_receive_count--; - if (Button.dual_receive_count) { - Button.dual_code = (Button.dual_code << 8) | serial_in_byte; - serial_in_byte = 0; - } else { - if (serial_in_byte != 0xA1) { - Button.dual_code = 0; // 0xA1 - End of Sonoff dual button code - } - } - } - if (0xA0 == serial_in_byte) { // 0xA0 - Start of Sonoff dual button code - serial_in_byte = 0; - Button.dual_code = 0; - Button.dual_receive_count = 3; - } - - return serial_in_byte; -} - -/*********************************************************************************************\ - * Button handler with single press only or multi-press and hold on all buttons - * - * ButtonDebounce (50) - Debounce time in mSec - * SetOption1 (0) - If set do not execute commands WifiConfig and Reset - * SetOption11 (0) - If set perform single press action on double press and reverse (on two relay devices only) - * SetOption13 (0) - If set act on single press only - * SetOption32 (40) - Button held for factor times longer - * SetOption40 (0) - Do not ignore button hold - * SetOption73 (0) - Decouple button from relay and send just mqtt topic -\*********************************************************************************************/ - -void ButtonHandler(void) { - if (TasmotaGlobal.uptime < 4) { return; } // Block GPIO for 4 seconds after poweron to workaround Wemos D1 / Obi RTS circuit - - uint8_t hold_time_extent = IMMINENT_RESET_FACTOR; // Extent hold time factor in case of iminnent Reset command - uint16_t loops_per_second = 1000 / Settings->button_debounce; // ButtonDebounce (50) - char scmnd[20]; - - for (uint32_t button_index = 0; button_index < MAX_KEYS; button_index++) { - uint8_t button = NOT_PRESSED; - uint8_t button_present = 0; - -#ifdef ESP8266 - if (!button_index && ((SONOFF_DUAL == TasmotaGlobal.module_type) || (CH4 == TasmotaGlobal.module_type))) { - button_present = 1; - if (Button.dual_code) { - AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: Code %04X"), Button.dual_code); - button = PRESSED; - if (0xF500 == Button.dual_code) { // Button hold - Button.hold_timer[button_index] = (loops_per_second * Settings->param[P_HOLD_TIME] / 10) -1; // SetOption32 (40) - hold_time_extent = 1; - } - Button.dual_code = 0; - } - } else -#endif // ESP8266 - if (PinUsed(GPIO_KEY1, button_index)) { - -#if defined(SOC_TOUCH_VERSION_1) || defined(SOC_TOUCH_VERSION_2) - if (bitRead(TouchButton.touch_mask, button_index) && bitRead(TouchButton.calibration, button_index +1)) { // Touch - uint32_t _value = touchRead(Pin(GPIO_KEY1, button_index)); -#ifdef SOC_TOUCH_VERSION_2 - if (_value > Settings->touch_threshold) { // ESPS3 No touch = 24200, Touch = 100000 -#else - if ((_value > 0) && (_value < Settings->touch_threshold)) { // ESP32 No touch = 74, Touch = 20 (Probably read-error (0)) -#endif - TouchButton.hits[button_index]++; - } else { - TouchButton.hits[button_index] = 0; - } - AddLog(LOG_LEVEL_INFO, PSTR("PLOT: %u, %u, %u,"), button_index +1, _value, TouchButton.hits[button_index]); // Button number (1..4), value, continuous hits under threshold - continue; - } else -#endif // ESP32 SOC_TOUCH_VERSION_1 or SOC_TOUCH_VERSION_2 - - button_present = 1; - button = Button.virtual_state[button_index]; - } -#ifdef USE_ADC - else if (PinUsed(GPIO_ADC_BUTTON, button_index)) { - button_present = 1; - button = AdcGetButton(Pin(GPIO_ADC_BUTTON, button_index)); - } - else if (PinUsed(GPIO_ADC_BUTTON_INV, button_index)) { - button_present = 1; - button = AdcGetButton(Pin(GPIO_ADC_BUTTON_INV, button_index)); - } -#endif // USE_ADC - if (button_present) { - XdrvMailbox.index = button_index; - XdrvMailbox.payload = button; - if (XdrvCall(FUNC_BUTTON_PRESSED)) { - // Serviced - } -#ifdef ESP8266 - else if (SONOFF_4CHPRO == TasmotaGlobal.module_type) { - if (Button.hold_timer[button_index]) { Button.hold_timer[button_index]--; } - - bool button_pressed = false; - if ((PRESSED == button) && (NOT_PRESSED == Button.last_state[button_index])) { - AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: Button%d level 1-0"), button_index +1); - Button.hold_timer[button_index] = loops_per_second; - button_pressed = true; - } - if ((NOT_PRESSED == button) && (PRESSED == Button.last_state[button_index])) { - AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: Button%d level 0-1"), button_index +1); - if (!Button.hold_timer[button_index]) { button_pressed = true; } // Do not allow within 1 second - } - if (button_pressed) { - if (!Settings->flag3.mqtt_buttons) { // SetOption73 (0) - Decouple button from relay and send just mqtt topic - if (!SendKey(KEY_BUTTON, button_index +1, POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set - ExecuteCommandPower(button_index +1, POWER_TOGGLE, SRC_BUTTON); // Execute Toggle command internally - } - } else { - MqttButtonTopic(button_index +1, 1, 0); // SetOption73 (0) - Decouple button from relay and send just mqtt topic - } - } - } -#endif // ESP8266 - else { - if ((PRESSED == button) && (NOT_PRESSED == Button.last_state[button_index])) { - - if (Settings->flag.button_single) { // SetOption13 (0) - Allow only single button press for immediate action, - if (!Settings->flag3.mqtt_buttons) { // SetOption73 (0) - Decouple button from relay and send just mqtt topic - AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: Button%d immediate"), button_index +1); - if (!SendKey(KEY_BUTTON, button_index +1, POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set - ExecuteCommandPower(button_index +1, POWER_TOGGLE, SRC_BUTTON); // Execute Toggle command internally - } - } else { - MqttButtonTopic(button_index +1, 1, 0); // SetOption73 1 - Decouple button from relay and send just mqtt topic - } - } else { - Button.press_counter[button_index] = (Button.window_timer[button_index]) ? Button.press_counter[button_index] +1 : 1; - AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: Button%d multi-press %d"), button_index +1, Button.press_counter[button_index]); - Button.window_timer[button_index] = loops_per_second / 2; // 0.5 second multi press window - } - TasmotaGlobal.blinks = 201; - } - - if (NOT_PRESSED == button) { - Button.hold_timer[button_index] = 0; - if (Settings->flag3.mqtt_buttons && (PRESSED == Button.last_state[button_index]) && !Button.press_counter[button_index]) { // SetOption73 (0) - Decouple button from relay and send just mqtt topic - MqttButtonTopic(button_index +1, 6, 0); - } - } else { - Button.hold_timer[button_index]++; - if (Settings->flag.button_single) { // SetOption13 (0) - Allow only single button press for immediate action - if (Button.hold_timer[button_index] == loops_per_second * hold_time_extent * Settings->param[P_HOLD_TIME] / 10) { // SetOption32 (40) - Button held for factor times longer - snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_SETOPTION "13 0")); // Disable single press only - ExecuteCommand(scmnd, SRC_BUTTON); - } - } else { - if (Button.hold_timer[button_index] == loops_per_second * Settings->param[P_HOLD_TIME] / 10) { // SetOption32 (40) - Button hold - Button.press_counter[button_index] = 0; - if (Settings->flag3.mqtt_buttons) { // SetOption73 (0) - Decouple button from relay and send just mqtt topic - MqttButtonTopic(button_index +1, 3, 1); - } else { - SendKey(KEY_BUTTON, button_index +1, POWER_HOLD); // Execute Hold command via MQTT if ButtonTopic is set - } - } else { - if (Settings->flag.button_restrict) { // SetOption1 (0) - Control button multipress - if (Settings->param[P_HOLD_IGNORE] > 0) { // SetOption40 (0) - Do not ignore button hold - if (Button.hold_timer[button_index] > loops_per_second * Settings->param[P_HOLD_IGNORE] / 10) { - Button.hold_timer[button_index] = 0; // Reset button hold counter to stay below hold trigger - Button.press_counter[button_index] = 0; // Discard button press to disable functionality - } - } - } else { - if ((Button.hold_timer[button_index] == loops_per_second * hold_time_extent * Settings->param[P_HOLD_TIME] / 10)) { // SetOption32 (40) - Button held for factor times longer - Button.press_counter[button_index] = 0; - snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_RESET " 1")); - ExecuteCommand(scmnd, SRC_BUTTON); - } - } - } - } - } - - if (!Settings->flag.button_single) { // SetOption13 (0) - Allow multi-press - if (Button.window_timer[button_index]) { - Button.window_timer[button_index]--; - } else { - if (!TasmotaGlobal.restart_flag && !Button.hold_timer[button_index] && (Button.press_counter[button_index] > 0) && (Button.press_counter[button_index] < 7)) { - - bool single_press = false; - if (Button.press_counter[button_index] < 3) { // Single or Double press -#ifdef ESP8266 - if ((SONOFF_DUAL_R2 == TasmotaGlobal.module_type) || (SONOFF_DUAL == TasmotaGlobal.module_type) || (CH4 == TasmotaGlobal.module_type)) { - single_press = true; - } else -#endif // ESP8266 - { - single_press = (Settings->flag.button_swap +1 == Button.press_counter[button_index]); // SetOption11 (0) - if ((1 == Button.present) && (2 == TasmotaGlobal.devices_present)) { // Single Button with two devices only - if (Settings->flag.button_swap) { // SetOption11 (0) - Button.press_counter[button_index] = (single_press) ? 1 : 2; - } - } - } - } - - XdrvMailbox.index = button_index; - XdrvMailbox.payload = Button.press_counter[button_index]; - if (XdrvCall(FUNC_BUTTON_MULTI_PRESSED)) { - // Serviced - } else - -#ifdef ROTARY_V1 - if (!RotaryButtonPressed(button_index)) { -#endif - if (!Settings->flag3.mqtt_buttons && single_press && SendKey(KEY_BUTTON, button_index + Button.press_counter[button_index], POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set - // Success - } else { - if (Button.press_counter[button_index] < 6) { // Single to Penta press -// if (WifiState() > WIFI_RESTART) { // Wifimanager active -// TasmotaGlobal.restart_flag = 1; -// } - if (!Settings->flag3.mqtt_buttons) { // SetOption73 - Detach buttons from relays and enable MQTT action state for multipress - if (Button.press_counter[button_index] == 1) { // By default first press always send a TOGGLE (2) - ExecuteCommandPower(button_index + Button.press_counter[button_index], POWER_TOGGLE, SRC_BUTTON); - } else { - SendKey(KEY_BUTTON, button_index +1, Button.press_counter[button_index] +9); // 2,3,4 and 5 press send just the key value (11,12,13 and 14) for rules - if (0 == button_index) { // BUTTON1 can toggle up to 5 relays if present. If a relay is not present will send out the key value (2,11,12,13 and 14) for rules - bool valid_relay = PinUsed(GPIO_REL1, Button.press_counter[button_index]-1); -#ifdef ESP8266 - if ((SONOFF_DUAL == TasmotaGlobal.module_type) || (CH4 == TasmotaGlobal.module_type)) { - valid_relay = (Button.press_counter[button_index] <= TasmotaGlobal.devices_present); - } -#endif // ESP8266 -#ifdef USE_SHELLY_PRO - if (TasmotaGlobal.gpio_optiona.shelly_pro) { - valid_relay = (Button.press_counter[button_index] <= TasmotaGlobal.devices_present); - } -#endif // USE_SHELLY_PRO - if ((Button.press_counter[button_index] > 1) && valid_relay && (Button.press_counter[button_index] <= MAX_RELAY_BUTTON1)) { - ExecuteCommandPower(button_index + Button.press_counter[button_index], POWER_TOGGLE, SRC_BUTTON); // Execute Toggle command internally -// AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: Relay%d found on GPIO%d"), Button.press_counter[button_index], Pin(GPIO_REL1, Button.press_counter[button_index]-1)); - } - } - } - } - - } else { // 6 press start wificonfig 2 - if (!Settings->flag.button_restrict) { // SetOption1 - Control button multipress - snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_WIFICONFIG " 2")); - ExecuteCommand(scmnd, SRC_BUTTON); - } - } - if (Settings->flag3.mqtt_buttons) { // SetOption73 (0) - Decouple button from relay and send just mqtt topic - if (Button.press_counter[button_index] >= 1 && Button.press_counter[button_index] <= 5) { - MqttButtonTopic(button_index +1, Button.press_counter[button_index], 0); - } - } - } -#ifdef ROTARY_V1 - } -#endif - Button.press_counter[button_index] = 0; - } - } - } - - } - } - Button.last_state[button_index] = button; - } -} - -void MqttButtonTopic(uint32_t button_id, uint32_t action, uint32_t hold) { - SendKey(KEY_BUTTON, button_id, (hold) ? 3 : action +9); - - if (!Settings->flag.hass_discovery) { // SetOption19 - Control Home Assistant automatic discovery (See SetOption59) - char scommand[10]; - snprintf_P(scommand, sizeof(scommand), PSTR(D_JSON_BUTTON "%d"), button_id); - char mqttstate[7]; - Response_P(S_JSON_SVALUE_ACTION_SVALUE, scommand, (hold) ? SettingsText(SET_STATE_TXT4) : GetTextIndexed(mqttstate, sizeof(mqttstate), action, kMultiPress)); - MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_STAT, scommand); - } -} - -void ButtonLoop(void) { - if (Button.present) { - if (TimeReached(Button.debounce)) { - SetNextTimeInterval(Button.debounce, Settings->button_debounce); // ButtonDebounce (50) - ButtonHandler(); - } - } -} - -#endif // BUTTON_V3 diff --git a/tasmota/tasmota_support/support_button_v4.ino b/tasmota/tasmota_support/support_button_v4.ino index af9bfc29a..1c8483b54 100644 --- a/tasmota/tasmota_support/support_button_v4.ino +++ b/tasmota/tasmota_support/support_button_v4.ino @@ -42,7 +42,7 @@ struct BUTTON { uint32_t no_pullup_mask = 0; // key no pullup flag (1 = no pullup) uint32_t pulldown_mask = 0; // key pulldown flag (1 = pulldown) uint32_t inverted_mask = 0; // Key inverted flag (1 = inverted) - uint32_t virtual_pin_used = 0; // Key used bitmask + uint32_t used = 0; // Key used bitmask uint32_t virtual_pin = 0; // Key state bitmask uint16_t hold_timer[MAX_KEYS_SET] = { 0 }; // Timer for button hold uint16_t dual_code = 0; // Sonoff dual received code @@ -85,14 +85,24 @@ void ButtonTouchFlag(uint32_t button_bit) { } #endif // ESP32 SOC_TOUCH_VERSION_1 or SOC_TOUCH_VERSION_2 -bool ButtonUsed(uint32_t index) { - return (PinUsed(GPIO_KEY1, index) || bitRead(Button.virtual_pin_used, index)); -} +/*------------------------------------------------------------------------------------------*/ void ButtonSetVirtualPinState(uint32_t index, uint32_t state) { + // Set virtual pin state to be debounced as used by early detected buttons bitWrite(Button.virtual_pin, index, state); } +uint8_t ButtonLastState(uint32_t index) { + // Get last state + return Button.last_state[index]; +} + +/*------------------------------------------------------------------------------------------*/ + +bool ButtonUsed(uint32_t index) { + return (PinUsed(GPIO_KEY1, index) || bitRead(Button.used, index)); +} + /*********************************************************************************************/ void ButtonProbe(void) { @@ -134,7 +144,7 @@ void ButtonProbe(void) { #endif // ESP32 SOC_TOUCH_VERSION_1 or SOC_TOUCH_VERSION_2 not_activated = (digitalRead(Pin(GPIO_KEY1, i)) != bitRead(Button.inverted_mask, i)); } - else if (bitRead(Button.virtual_pin_used, i)) { + else if (bitRead(Button.used, i)) { not_activated = (bitRead(Button.virtual_pin, i) != bitRead(Button.inverted_mask, i)); } else { continue; } @@ -220,7 +230,7 @@ void ButtonInit(void) { bool ac_detect = (Settings->button_debounce % 10 == 9); Button.present = 0; - Button.virtual_pin_used = 0; + Button.used = 0; #ifdef ESP8266 if ((SONOFF_DUAL == TasmotaGlobal.module_type) || (CH4 == TasmotaGlobal.module_type)) { @@ -259,7 +269,7 @@ void ButtonInit(void) { XdrvMailbox.index bit 0 = current state */ Button.present++; - bitSet(Button.virtual_pin_used, i); // This pin is used + bitSet(Button.used, i); // This pin is used bool state = (XdrvMailbox.index &1); ButtonSetVirtualPinState(i, state); // Virtual hardware pin state if (!state) { ButtonInvertFlag(i); } // Set inverted flag @@ -279,7 +289,7 @@ void ButtonInit(void) { Button.debounced_state[i] = Button.last_state[i]; } -// AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: vPinUsed %08X, State %08X, Invert %08X"), Button.virtual_pin_used, Button.virtual_pin, Button.inverted_mask); +// AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: vPinUsed %08X, State %08X, Invert %08X"), Button.used, Button.virtual_pin, Button.inverted_mask); if (Button.present) { Button.first_change = true; @@ -377,7 +387,7 @@ void ButtonHandler(void) { button = AdcGetButton(Pin(GPIO_ADC_BUTTON_INV, button_index)); } #endif // USE_ADC - else if (bitRead(Button.virtual_pin_used, button_index)) { + else if (bitRead(Button.used, button_index)) { button_present = 1; button = Button.debounced_state[button_index]; } diff --git a/tasmota/tasmota_support/support_switch_v3.ino b/tasmota/tasmota_support/support_switch_v3.ino deleted file mode 100644 index 392c0afda..000000000 --- a/tasmota/tasmota_support/support_switch_v3.ino +++ /dev/null @@ -1,454 +0,0 @@ -/* - support_switch.ino - switch support for Tasmota - - Copyright (C) 2021 Theo Arends - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -//#define SWITCH_V3 -#ifdef SWITCH_V3 -/*********************************************************************************************\ - * Switch support with input filter - * - * Inspired by (https://github.com/OLIMEX/olimex-iot-firmware-esp8266/blob/master/olimex/user/user_switch2.c) -\*********************************************************************************************/ - -const uint8_t SWITCH_PROBE_INTERVAL = 10; // Time in milliseconds between switch input probe -const uint8_t SWITCH_FAST_PROBE_INTERVAL = 2; // Time in milliseconds between switch input probe for AC detection -const uint8_t AC_PERIOD = (20 + SWITCH_FAST_PROBE_INTERVAL - 1) / SWITCH_FAST_PROBE_INTERVAL; // Duration of an AC wave in probe intervals - -// Switch Mode definietions -#define SM_TIMER_MASK 0x3F -#define SM_NO_TIMER_MASK 0xFF -#define SM_FIRST_PRESS 0x40 -#define SM_SECOND_PRESS 0x80 -#define POWER_NONE 99 - -const char kSwitchPressStates[] PROGMEM = - "||||POWER_INCREMENT|POWER_INV|POWER_CLEAR|POWER_RELEASE|POWER_100||POWER_DELAYED"; - -#include - -Ticker TickerSwitch; - -struct SWITCH { - uint32_t debounce = 0; // Switch debounce timer - uint32_t no_pullup_mask = 0; // Switch pull-up bitmask flags - uint32_t pulldown_mask = 0; // Switch pull-down bitmask flags - uint8_t state[MAX_SWITCHES] = { 0 }; - uint8_t last_state[MAX_SWITCHES]; // Last wall switch states - uint8_t hold_timer[MAX_SWITCHES] = { 0 }; // Timer for wallswitch push button hold - uint8_t virtual_state[MAX_SWITCHES]; // Virtual switch states - uint8_t first_change = 0; - uint8_t present = 0; -} Switch; - -/********************************************************************************************/ - -void SwitchPullupFlag(uint32 switch_bit) { - bitSet(Switch.no_pullup_mask, switch_bit); -} - -void SwitchPulldownFlag(uint32 switch_bit) { - bitSet(Switch.pulldown_mask, switch_bit); -} - -void SwitchSetVirtual(uint32_t index, uint32_t state) { - Switch.virtual_state[index] = state; -} - -uint8_t SwitchGetVirtual(uint32_t index) { - return Switch.virtual_state[index]; -} - -uint8_t SwitchLastState(uint32_t index) { - return Switch.last_state[index]; -} - -bool SwitchState(uint32_t index) { - uint32_t switchmode = Settings->switchmode[index]; - return ((FOLLOW_INV == switchmode) || - (PUSHBUTTON_INV == switchmode) || - (PUSHBUTTONHOLD_INV == switchmode) || - (FOLLOWMULTI_INV == switchmode) || - (PUSHHOLDMULTI_INV == switchmode) || - (PUSHON_INV == switchmode) || - (PUSH_IGNORE_INV == switchmode) - ) ^ Switch.last_state[index]; -} - -/*********************************************************************************************/ - -void SwitchProbe(void) { - if (TasmotaGlobal.uptime < 4) { return; } // Block GPIO for 4 seconds after poweron to workaround Wemos D1 / Obi RTS circuit - - uint32_t state_filter; - uint32_t first_change = Switch.first_change; - uint32_t debounce_flags = Settings->switch_debounce % 10; - bool force_high = (debounce_flags &1); // 51, 101, 151 etc - bool force_low = (debounce_flags &2); // 52, 102, 152 etc - bool ac_detect = (debounce_flags == 9); - - if (ac_detect) { - if (Settings->switch_debounce < 2 * AC_PERIOD * SWITCH_FAST_PROBE_INTERVAL + 9) { - state_filter = 2 * AC_PERIOD; - } else if (Settings->switch_debounce > (0x7f - 2 * AC_PERIOD) * SWITCH_FAST_PROBE_INTERVAL) { - state_filter = 0x7f; - } else { - state_filter = (Settings->switch_debounce - 9) / SWITCH_FAST_PROBE_INTERVAL; - } - } else { - state_filter = Settings->switch_debounce / SWITCH_PROBE_INTERVAL; // 5, 10, 15 - } - - for (uint32_t i = 0; i < MAX_SWITCHES; i++) { - if (!PinUsed(GPIO_SWT1, i)) { continue; } - - // Olimex user_switch2.c code to fix 50Hz induced pulses - if (1 == digitalRead(Pin(GPIO_SWT1, i))) { - - if (ac_detect) { // Enabled with SwitchDebounce x9 - Switch.state[i] |= 0x80; - if (Switch.state[i] > 0x80) { - Switch.state[i]--; - if (0x80 == Switch.state[i]) { - Switch.virtual_state[i] = 0; - Switch.first_change = false; - } - } - } else { - - if (force_high) { // Enabled with SwitchDebounce x1 - if (1 == Switch.virtual_state[i]) { - Switch.state[i] = state_filter; // With noisy input keep current state 1 unless constant 0 - } - } - - if (Switch.state[i] < state_filter) { - Switch.state[i]++; - if (state_filter == Switch.state[i]) { - Switch.virtual_state[i] = 1; - } - } - } - } else { - - if (ac_detect) { // Enabled with SwitchDebounce x9 - /* - * Moes MS-104B and similar devices using an AC detection circuitry - * on their switch inputs generating an ~4 ms long low pulse every - * AC wave. We start the time measurement on the falling edge. - * - * state: bit7: previous state, bit6..0: counter - */ - if (Switch.state[i] & 0x80) { - Switch.state[i] &= 0x7f; - if (Switch.state[i] < state_filter - 2 * AC_PERIOD) { - Switch.state[i] += 2 * AC_PERIOD; - } else { - Switch.state[i] = state_filter; - Switch.virtual_state[i] = 1; - if (first_change) { - Switch.last_state[i] = 1; - Switch.first_change = false; - } - } - } else { - if (Switch.state[i] > 0x00) { - Switch.state[i]--; - if (0x00 == Switch.state[i]) { - Switch.virtual_state[i] = 0; - Switch.first_change = false; - } - } - } - } else { - - if (force_low) { // Enabled with SwitchDebounce x2 - if (0 == Switch.virtual_state[i]) { - Switch.state[i] = 0; // With noisy input keep current state 0 unless constant 1 - } - } - - if (Switch.state[i] > 0) { - Switch.state[i]--; - if (0 == Switch.state[i]) { - Switch.virtual_state[i] = 0; - } - } - } - } - } -} - -void SwitchInit(void) { - bool ac_detect = (Settings->switch_debounce % 10 == 9); - - Switch.present = 0; - for (uint32_t i = 0; i < MAX_SWITCHES; i++) { - Switch.last_state[i] = NOT_PRESSED; // Init global to virtual switch state; - if (PinUsed(GPIO_SWT1, i)) { - Switch.present++; -#ifdef ESP8266 - pinMode(Pin(GPIO_SWT1, i), bitRead(Switch.no_pullup_mask, i) ? INPUT : ((16 == Pin(GPIO_SWT1, i)) ? INPUT_PULLDOWN_16 : INPUT_PULLUP)); -#endif // ESP8266 -#ifdef ESP32 - pinMode(Pin(GPIO_SWT1, i), bitRead(Switch.pulldown_mask, i) ? INPUT_PULLDOWN : bitRead(Switch.no_pullup_mask, i) ? INPUT : INPUT_PULLUP); -#endif // ESP32 - if (ac_detect) { - Switch.state[i] = 0x80 + 2 * AC_PERIOD; - Switch.last_state[i] = 0; // Will set later in the debouncing code - } else { - Switch.last_state[i] = digitalRead(Pin(GPIO_SWT1, i)); // Set global now so doesn't change the saved power state on first switch check - } - } - Switch.virtual_state[i] = Switch.last_state[i]; - } - if (Switch.present) { - Switch.first_change = true; - TickerSwitch.attach_ms((ac_detect) ? SWITCH_FAST_PROBE_INTERVAL : SWITCH_PROBE_INTERVAL, SwitchProbe); - } -} - -/*********************************************************************************************\ - * Switch handler -\*********************************************************************************************/ - -void SwitchHandler(uint32_t mode) { - if (TasmotaGlobal.uptime < 4) { return; } // Block GPIO for 4 seconds after poweron to workaround Wemos D1 / Obi RTS circuit - - uint32_t loops_per_second = 1000 / Settings->switch_debounce; - - for (uint32_t i = 0; i < MAX_SWITCHES; i++) { - if (PinUsed(GPIO_SWT1, i) || (mode)) { - uint32_t button = Switch.virtual_state[i]; - uint32_t switchflag = POWER_TOGGLE +1; - uint32_t mqtt_action = POWER_NONE; - uint32_t switchmode = Settings->switchmode[i]; - - if (Switch.hold_timer[i] & (((switchmode == PUSHHOLDMULTI) | (switchmode == PUSHHOLDMULTI_INV)) ? SM_TIMER_MASK: SM_NO_TIMER_MASK)) { - Switch.hold_timer[i]--; - if ((Switch.hold_timer[i] & SM_TIMER_MASK) == loops_per_second * Settings->param[P_HOLD_TIME] / 25) { - if ((switchmode == PUSHHOLDMULTI) | (switchmode == PUSHHOLDMULTI_INV)){ - if (((switchmode == PUSHHOLDMULTI) & (NOT_PRESSED == Switch.last_state[i])) | ((switchmode == PUSHHOLDMULTI_INV) & (PRESSED == Switch.last_state[i]))) { - SendKey(KEY_SWITCH, i +1, POWER_INCREMENT); // Execute command via MQTT - } - else if ((Switch.hold_timer[i] & ~SM_TIMER_MASK) == SM_FIRST_PRESS) { - SendKey(KEY_SWITCH, i +1, POWER_DELAYED); // Execute command via MQTT - mqtt_action = POWER_DELAYED; - Switch.hold_timer[i] = 0; - } - } - } - if (0 == (Switch.hold_timer[i] & (((switchmode == PUSHHOLDMULTI) | (switchmode == PUSHHOLDMULTI_INV)) ? SM_TIMER_MASK: SM_NO_TIMER_MASK))) { - switch (switchmode) { - case TOGGLEMULTI: - switchflag = POWER_TOGGLE; // Toggle after hold - break; - case FOLLOWMULTI: - switchflag = button &1; // Follow wall switch state after hold - break; - case FOLLOWMULTI_INV: - switchflag = ~button &1; // Follow inverted wall switch state after hold - break; - case PUSHHOLDMULTI: - if (NOT_PRESSED == button) { - Switch.hold_timer[i] = loops_per_second * Settings->param[P_HOLD_TIME] / 25; - SendKey(KEY_SWITCH, i +1, POWER_INCREMENT); // Execute command via MQTT - mqtt_action = POWER_INCREMENT; - } else { - Switch.hold_timer[i]= 0; - SendKey(KEY_SWITCH, i +1, POWER_CLEAR); // Execute command via MQTT - mqtt_action = POWER_CLEAR; - } - break; - case PUSHHOLDMULTI_INV: - if (PRESSED == button) { - Switch.hold_timer[i] = loops_per_second * Settings->param[P_HOLD_TIME] / 25; - SendKey(KEY_SWITCH, i +1, POWER_INCREMENT); // Execute command via MQTT - mqtt_action = POWER_INCREMENT; - } else { - Switch.hold_timer[i]= 0; - SendKey(KEY_SWITCH, i +1, POWER_CLEAR); // Execute command via MQTT - mqtt_action = POWER_CLEAR; - } - break; - default: - SendKey(KEY_SWITCH, i +1, POWER_HOLD); // Execute command via MQTT - mqtt_action = POWER_HOLD; - break; - } - } - } - - if (button != Switch.last_state[i]) { // This implies if ((PRESSED == button) then (NOT_PRESSED == Switch.last_state[i])) - switch (switchmode) { - case TOGGLE: - case PUSHBUTTON_TOGGLE: - switchflag = POWER_TOGGLE; // Toggle - break; - case FOLLOW: - switchflag = button &1; // Follow wall switch state - break; - case FOLLOW_INV: - switchflag = ~button &1; // Follow inverted wall switch state - break; - case PUSHBUTTON: - if (PRESSED == button) { - switchflag = POWER_TOGGLE; // Toggle with pushbutton to Gnd - } - break; - case PUSHBUTTON_INV: - if (NOT_PRESSED == button) { - switchflag = POWER_TOGGLE; // Toggle with releasing pushbutton from Gnd - } - break; - case PUSHBUTTONHOLD: - if (PRESSED == button) { - Switch.hold_timer[i] = loops_per_second * Settings->param[P_HOLD_TIME] / 10; // Start timer on button press - } - if ((NOT_PRESSED == button) && (Switch.hold_timer[i])) { - Switch.hold_timer[i] = 0; // Button released and hold timer not expired : stop timer... - switchflag = POWER_TOGGLE; // ...and Toggle - } - break; - case PUSHBUTTONHOLD_INV: - if (NOT_PRESSED == button) { - Switch.hold_timer[i] = loops_per_second * Settings->param[P_HOLD_TIME] / 10; // Start timer on button press... - } - if ((PRESSED == button) && (Switch.hold_timer[i])) { - Switch.hold_timer[i] = 0; // Button released and hold timer not expired : stop timer. - switchflag = POWER_TOGGLE; // ...and Toggle - } - break; - case TOGGLEMULTI: - case FOLLOWMULTI: - case FOLLOWMULTI_INV: - if (Switch.hold_timer[i]) { - Switch.hold_timer[i] = 0; - SendKey(KEY_SWITCH, i +1, POWER_HOLD); // Execute command via MQTT - mqtt_action = POWER_HOLD; - } else { - Switch.hold_timer[i] = loops_per_second / 2; // 0.5 second multi press window - } - break; - case PUSHHOLDMULTI: - if (NOT_PRESSED == button) { - if ((Switch.hold_timer[i] & SM_TIMER_MASK) != 0) { - Switch.hold_timer[i] = ((Switch.hold_timer[i] & ~SM_TIMER_MASK) == SM_FIRST_PRESS) ? SM_SECOND_PRESS : 0; - SendKey(KEY_SWITCH, i +1, POWER_INV); // Execute command via MQTT - mqtt_action = POWER_INV; - } - } else { - if ((Switch.hold_timer[i] & SM_TIMER_MASK) > loops_per_second * Settings->param[P_HOLD_TIME] / 25) { - if ((Switch.hold_timer[i] & ~SM_TIMER_MASK) != SM_SECOND_PRESS) { - Switch.hold_timer[i]= SM_FIRST_PRESS; - switchflag = POWER_TOGGLE; // Toggle with pushbutton - } - else{ - SendKey(KEY_SWITCH, i +1, POWER_100); // Execute command via MQTT - mqtt_action = POWER_100; - Switch.hold_timer[i]= 0; - } - } else { - Switch.hold_timer[i]= 0; - SendKey(KEY_SWITCH, i +1, POWER_RELEASE); // Execute command via MQTT - mqtt_action = POWER_RELEASE; - } - } - Switch.hold_timer[i] = (Switch.hold_timer[i] & ~SM_TIMER_MASK) | loops_per_second * Settings->param[P_HOLD_TIME] / 10; - break; - case PUSHHOLDMULTI_INV: - if (PRESSED == button) { - if ((Switch.hold_timer[i] & SM_TIMER_MASK) != 0) { - Switch.hold_timer[i] = ((Switch.hold_timer[i] & ~SM_TIMER_MASK) == SM_FIRST_PRESS) ? SM_SECOND_PRESS : 0; - SendKey(KEY_SWITCH, i +1, POWER_INV); // Execute command via MQTT - mqtt_action = POWER_INV; - } - } else { - if ((Switch.hold_timer[i] & SM_TIMER_MASK)> loops_per_second * Settings->param[P_HOLD_TIME] / 25) { - if ((Switch.hold_timer[i] & ~SM_TIMER_MASK) != SM_SECOND_PRESS) { - Switch.hold_timer[i]= SM_FIRST_PRESS; - switchflag = POWER_TOGGLE; // Toggle with pushbutton - } - else{ - SendKey(KEY_SWITCH, i +1, POWER_100); // Execute command via MQTT - mqtt_action = POWER_100; - Switch.hold_timer[i]= 0; - } - } else { - Switch.hold_timer[i]= 0; - SendKey(KEY_SWITCH, i +1, POWER_RELEASE); // Execute command via MQTT - mqtt_action = POWER_RELEASE; - } - } - Switch.hold_timer[i] = (Switch.hold_timer[i] & ~SM_TIMER_MASK) | loops_per_second * Settings->param[P_HOLD_TIME] / 10; - break; - case PUSHON: - if (PRESSED == button) { - switchflag = POWER_ON; // Power ON with pushbutton to Gnd - } - break; - case PUSHON_INV: - if (NOT_PRESSED == button) { - switchflag = POWER_ON; // Power ON with releasing pushbutton from Gnd - } - break; - case PUSH_IGNORE: - case PUSH_IGNORE_INV: - Switch.last_state[i] = button; // Update switch state before publishing - MqttPublishSensor(); - break; - } - Switch.last_state[i] = button; - } - if (switchflag <= POWER_TOGGLE) { - if (!Settings->flag5.mqtt_switches) { // SetOption114 (0) - Detach Switches from relays and enable MQTT action state for all the SwitchModes - if (!SendKey(KEY_SWITCH, i +1, switchflag)) { // Execute command via MQTT - ExecuteCommandPower(i +1, switchflag, SRC_SWITCH); // Execute command internally (if i < TasmotaGlobal.devices_present) - } - } else { mqtt_action = switchflag; } - } - if ((mqtt_action != POWER_NONE) && Settings->flag5.mqtt_switches) { // SetOption114 (0) - Detach Switches from relays and enable MQTT action state for all the SwitchModes - if (!Settings->flag.hass_discovery) { // SetOption19 - Control Home Assistant automatic discovery (See SetOption59) - char mqtt_state_str[16]; - char *mqtt_state = mqtt_state_str; - if (mqtt_action <= 3) { - if (mqtt_action != 3) { SendKey(KEY_SWITCH, i +1, mqtt_action); } - mqtt_state = SettingsText(SET_STATE_TXT1 + mqtt_action); - } else { - GetTextIndexed(mqtt_state_str, sizeof(mqtt_state_str), mqtt_action, kSwitchPressStates); - } - Response_P(S_JSON_SVALUE_ACTION_SVALUE, GetSwitchText(i).c_str(), mqtt_state); - char scommand[10]; - snprintf_P(scommand, sizeof(scommand), PSTR(D_JSON_SWITCH "%d"), i +1); - MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_STAT, scommand); - } - mqtt_action = POWER_NONE; - } - } - } -} - -void SwitchLoop(void) { - if (Switch.present) { - if (TimeReached(Switch.debounce)) { - SetNextTimeInterval(Switch.debounce, Settings->switch_debounce); - SwitchHandler(0); - } - } -} - -#endif // SWITCH_V3 diff --git a/tasmota/tasmota_support/support_switch_v4.ino b/tasmota/tasmota_support/support_switch_v4.ino index 9af56e25c..4e45a9fed 100644 --- a/tasmota/tasmota_support/support_switch_v4.ino +++ b/tasmota/tasmota_support/support_switch_v4.ino @@ -47,14 +47,13 @@ struct SWITCH { uint32_t debounce = 0; // Switch debounce timer uint32_t no_pullup_mask = 0; // Switch pull-up bitmask flags uint32_t pulldown_mask = 0; // Switch pull-down bitmask flags - uint32_t virtual_pin_used = 0; // Switch used bitmask + uint32_t used = 0; // Switch used bitmask uint32_t virtual_pin = 0; // Switch state bitmask uint8_t state[MAX_SWITCHES_SET] = { 0 }; uint8_t last_state[MAX_SWITCHES_SET]; // Last wall switch states uint8_t hold_timer[MAX_SWITCHES_SET] = { 0 }; // Timer for wallswitch push button hold uint8_t debounced_state[MAX_SWITCHES_SET]; // Switch debounced states uint8_t first_change = 0; - uint8_t present = 0; bool probe_mutex; } Switch; @@ -68,31 +67,35 @@ void SwitchPulldownFlag(uint32 switch_bit) { bitSet(Switch.pulldown_mask, switch_bit); } -bool SwitchUsed(uint32_t index) { - return (PinUsed(GPIO_SWT1, index) || bitRead(Switch.virtual_pin_used, index)); -} +/*------------------------------------------------------------------------------------------*/ -// Preffered virtual switch support since v12.3.1.4 void SwitchSetVirtualPinState(uint32_t index, uint32_t state) { + // Set virtual pin state to be debounced as used by early detected switches bitWrite(Switch.virtual_pin, index, state); } -// Legacy virtual switch support -void SwitchSetVirtual(uint32_t index, uint32_t state) { -// bitSet(Switch.virtual_pin_used, index); +void SwitchSetState(uint32_t index, uint32_t state) { + // Set debounced pin state to be used by late detected switches + bitSet(Switch.used, index); // Force use bit as call maybe late Switch.debounced_state[index] = state; } -// Legacy virtual switch support -uint8_t SwitchGetVirtual(uint32_t index) { +uint8_t SwitchGetState(uint32_t index) { + // Get current state return Switch.debounced_state[index]; } -// Legacy virtual switch support uint8_t SwitchLastState(uint32_t index) { + // Get last state return Switch.last_state[index]; } +/*------------------------------------------------------------------------------------------*/ + +bool SwitchUsed(uint32_t index) { + return bitRead(Switch.used, index); +} + bool SwitchState(uint32_t index) { uint32_t switchmode = Settings->switchmode[index]; return ((FOLLOW_INV == switchmode) || @@ -135,7 +138,7 @@ void SwitchProbe(void) { if (PinUsed(GPIO_SWT1, i)) { not_activated = digitalRead(Pin(GPIO_SWT1, i)); } - else if (bitRead(Switch.virtual_pin_used, i)) { + else if (bitRead(Switch.used, i)) { not_activated = bitRead(Switch.virtual_pin, i); } else { continue; } @@ -222,14 +225,11 @@ void SwitchProbe(void) { void SwitchInit(void) { bool ac_detect = (Settings->switch_debounce % 10 == 9); - Switch.present = 0; - Switch.virtual_pin_used = 0; + Switch.used = 0; for (uint32_t i = 0; i < MAX_SWITCHES_SET; i++) { Switch.last_state[i] = NOT_PRESSED; // Init global to virtual switch state; - bool used = false; - if (PinUsed(GPIO_SWT1, i)) { - Switch.present++; + bitSet(Switch.used, i); // This pin is used #ifdef ESP8266 pinMode(Pin(GPIO_SWT1, i), bitRead(Switch.no_pullup_mask, i) ? INPUT : ((16 == Pin(GPIO_SWT1, i)) ? INPUT_PULLDOWN_16 : INPUT_PULLUP)); #endif // ESP8266 @@ -237,7 +237,6 @@ void SwitchInit(void) { pinMode(Pin(GPIO_SWT1, i), bitRead(Switch.pulldown_mask, i) ? INPUT_PULLDOWN : bitRead(Switch.no_pullup_mask, i) ? INPUT : INPUT_PULLUP); #endif // ESP32 Switch.last_state[i] = digitalRead(Pin(GPIO_SWT1, i)); // Set global now so doesn't change the saved power state on first switch check - used = true; } else { XdrvMailbox.index = i; @@ -248,28 +247,25 @@ void SwitchInit(void) { At exit: XdrvMailbox.index bit 0 = current state */ - Switch.present++; - bitSet(Switch.virtual_pin_used, i); // This pin is used + bitSet(Switch.used, i); // This pin is used bool state = (XdrvMailbox.index &1); - SwitchSetVirtualPinState(i, state); // Virtual hardware pin state + SwitchSetVirtualPinState(i, state); // Virtual hardware pin state Switch.last_state[i] = bitRead(Switch.virtual_pin, i); - AddLog(LOG_LEVEL_DEBUG, PSTR("SWT: Add vSwitch%d, State %d"), Switch.present, Switch.last_state[i]); - - used = true; + AddLog(LOG_LEVEL_DEBUG, PSTR("SWT: Add vSwitch%d, State %d"), i +1, Switch.last_state[i]); } } - if (used && ac_detect) { + if (bitRead(Switch.used, i) && ac_detect) { Switch.state[i] = 0x80 + 2 * SWITCH_AC_PERIOD; - Switch.last_state[i] = 0; // Will set later in the debouncing code + Switch.last_state[i] = 0; // Will set later in the debouncing code } Switch.debounced_state[i] = Switch.last_state[i]; } -// AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: vPinUsed %08X, State %08X"), Switch.virtual_pin_used, Switch.virtual_pin); +// AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: vPinUsed %08X, State %08X"), Switch.used, Switch.virtual_pin); - if (Switch.present) { + if (Switch.used) { // Any bit set Switch.first_change = true; TickerSwitch.attach_ms((ac_detect) ? SWITCH_FAST_PROBE_INTERVAL : SWITCH_PROBE_INTERVAL, SwitchProbe); } @@ -279,14 +275,13 @@ void SwitchInit(void) { * Switch handler \*********************************************************************************************/ -void SwitchHandler(uint32_t mode) { +void SwitchHandler(void) { if (TasmotaGlobal.uptime < 4) { return; } // Block GPIO for 4 seconds after poweron to workaround Wemos D1 / Obi RTS circuit uint32_t loops_per_second = 1000 / Settings->switch_debounce; for (uint32_t i = 0; i < MAX_SWITCHES_SET; i++) { -// if (PinUsed(GPIO_SWT1, i) || bitRead(Switch.virtual_pin_used, i)) { - if (SwitchUsed(i)) { + if (bitRead(Switch.used, i)) { uint32_t button = Switch.debounced_state[i]; uint32_t switchflag = POWER_TOGGLE +1; uint32_t mqtt_action = POWER_NONE; @@ -497,12 +492,12 @@ void SwitchHandler(uint32_t mode) { } void SwitchLoop(void) { - if (Switch.present) { + if (Switch.used) { if (TimeReached(Switch.debounce)) { SetNextTimeInterval(Switch.debounce, Settings->switch_debounce); - SwitchHandler(0); + SwitchHandler(); } } } -#endif // SWITCH_V3 +#endif // SWITCH_V4 diff --git a/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino b/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino index 314aab45b..76bf4f07b 100755 --- a/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino @@ -5779,7 +5779,7 @@ int32_t UpdVar(char *vname, float *fvar, uint32_t mode) { return 1; break; case 'b': - *fvar = Button.last_state[index - 1]; + *fvar = ButtonLastState(index - 1); return 1; break; } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v1.ino b/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v1.ino index 431ac2979..82bac2396 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v1.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v1.ino @@ -86,6 +86,7 @@ struct TUYA { #endif // USE_ENERGY_SENSOR char *buffer = nullptr; // Serial receive buffer int byte_counter = 0; // Index in serial receive buffer + uint8_t last_button; bool low_power_mode = false; // Normal or Low power mode protocol bool send_success_next_second = false; // Second command success in low power mode uint32_t ignore_dimmer_cmd_timeout = 0; // Time until which received dimmer commands should be ignored @@ -847,11 +848,10 @@ void TuyaProcessStatePacket(void) { if (Tuya.buffer[dpidStart + 4]) { PowerOff = true; } } } else if (fnId >= TUYA_MCU_FUNC_SWT1 && fnId <= TUYA_MCU_FUNC_SWT4) { - AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: RX Switch-%d --> MCU State: %d Current State:%d"),fnId - TUYA_MCU_FUNC_SWT1 + 1,Tuya.buffer[dpidStart + 4], SwitchGetVirtual(fnId - TUYA_MCU_FUNC_SWT1)); - - if (SwitchGetVirtual(fnId - TUYA_MCU_FUNC_SWT1) != Tuya.buffer[dpidStart + 4]) { - SwitchSetVirtual(fnId - TUYA_MCU_FUNC_SWT1, Tuya.buffer[dpidStart + 4]); - SwitchHandler(1); + uint32_t switch_state = SwitchGetState(fnId - TUYA_MCU_FUNC_SWT1); + AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: RX Switch-%d --> MCU State: %d Current State:%d"),fnId - TUYA_MCU_FUNC_SWT1 + 1,Tuya.buffer[dpidStart + 4], switch_state); + if (switch_state != Tuya.buffer[dpidStart + 4]) { + SwitchSetState(fnId - TUYA_MCU_FUNC_SWT1, Tuya.buffer[dpidStart + 4]); } } if (PowerOff) { Tuya.ignore_dimmer_cmd_timeout = millis() + 250; } @@ -1133,7 +1133,7 @@ void TuyaNormalPowerModePacketProcess(void) } TuyaRequestState(0); break; - case TUYA_CMD_GET_WIFI_STRENGTH: + case TUYA_CMD_GET_WIFI_STRENGTH: TuyaSetWifiStrength(); break; case TUYA_CMD_TEST_WIFI: @@ -1382,14 +1382,16 @@ void TuyaSerialInput(void) } } -bool TuyaButtonPressed(void) -{ - if (!XdrvMailbox.index && ((PRESSED == XdrvMailbox.payload) && (NOT_PRESSED == Button.last_state[XdrvMailbox.index]))) { +bool TuyaButtonPressed(void) { + bool result = false; + uint32_t button = XdrvMailbox.payload; + if (!XdrvMailbox.index && ((PRESSED == button) && (NOT_PRESSED == Tuya.last_button))) { AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: Reset GPIO triggered")); TuyaResetWifi(); - return true; // Reset GPIO served here + result = true; // Reset GPIO served here } - return false; // Don't serve other buttons + Tuya.last_button = button; + return result; // Don't serve other buttons } uint8_t TuyaGetTuyaWifiState(void) { diff --git a/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v2.ino b/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v2.ino index d78b1bec3..640f5574e 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v2.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v2.ino @@ -253,6 +253,8 @@ typedef struct TUYA_STRUCT_tag { uint8_t dimCmdEnable; // we are allowed to send a dim command - bitfield uint8_t dimDebug; // enables a single dim debug - bitfield + uint8_t last_button; + int sends; int rxs; @@ -265,9 +267,8 @@ void TuyaSendState(uint8_t id, uint8_t type, uint8_t* value, int len); int init_tuya_struct() { if (pTuya) return 0; // done already - pTuya = (TUYA_STRUCT *)malloc(sizeof(TUYA_STRUCT)); + pTuya = (TUYA_STRUCT *)calloc(sizeof(TUYA_STRUCT), 1); if (!pTuya) return 0; - memset(pTuya, 0, sizeof(TUYA_STRUCT)); strcpy(pTuya->RGBColor, "000000"); // Stores RGB Color string in Hex format pTuya->CTMin = 153; // Minimum CT level allowed - When SetOption82 is enabled will default to 200 pTuya->CTMax = 500; // Maximum CT level allowed - When SetOption82 is enabled will default to 380 @@ -1626,23 +1627,22 @@ void TuyaProcessRxedDP(uint8_t dpid, uint8_t type, uint8_t *data, int dpDataLen) case TUYA_TYPE_BOOL: { // Data Type 1 if (fnId >= TUYA_MCU_FUNC_REL1 && fnId <= TUYA_MCU_FUNC_REL8) { - AddLog(LOG_LEVEL_DEBUG, PSTR("T:fn%d Relay%d-->M%s T%s"), fnId, fnId - TUYA_MCU_FUNC_REL1 + 1, value?"On":"Off",bitRead(TasmotaGlobal.power, fnId - TUYA_MCU_FUNC_REL1)?"On":"Off"); - if (value != bitRead(TasmotaGlobal.power, fnId - TUYA_MCU_FUNC_REL1)) { - if (!value) { PowerOff = true; } - ExecuteCommandPower(fnId - TUYA_MCU_FUNC_REL1 + 1, value, SRC_SWITCH); // send SRC_SWITCH? to use as flag to prevent loop from inbound states from faceplate interaction + AddLog(LOG_LEVEL_DEBUG, PSTR("T:fn%d Relay%d-->M%s T%s"), fnId, fnId - TUYA_MCU_FUNC_REL1 + 1, value?"On":"Off",bitRead(TasmotaGlobal.power, fnId - TUYA_MCU_FUNC_REL1)?"On":"Off"); + if (value != bitRead(TasmotaGlobal.power, fnId - TUYA_MCU_FUNC_REL1)) { + if (!value) { PowerOff = true; } + ExecuteCommandPower(fnId - TUYA_MCU_FUNC_REL1 + 1, value, SRC_SWITCH); // send SRC_SWITCH? to use as flag to prevent loop from inbound states from faceplate interaction } } else if (fnId >= TUYA_MCU_FUNC_REL1_INV && fnId <= TUYA_MCU_FUNC_REL8_INV) { - AddLog(LOG_LEVEL_DEBUG, PSTR("T:fn%d Relay%d-Inv-->M%s T%s"), fnId, fnId - TUYA_MCU_FUNC_REL1_INV + 1, value?"Off":"On",bitRead(TasmotaGlobal.power, fnId - TUYA_MCU_FUNC_REL1_INV) ^ 1?"Off":"On"); - if (value != bitRead(TasmotaGlobal.power, fnId - TUYA_MCU_FUNC_REL1_INV) ^ 1) { - ExecuteCommandPower(fnId - TUYA_MCU_FUNC_REL1_INV + 1, value ^ 1, SRC_SWITCH); // send SRC_SWITCH? to use as flag to prevent loop from inbound states from faceplate interaction - if (value) { PowerOff = true; } + AddLog(LOG_LEVEL_DEBUG, PSTR("T:fn%d Relay%d-Inv-->M%s T%s"), fnId, fnId - TUYA_MCU_FUNC_REL1_INV + 1, value?"Off":"On",bitRead(TasmotaGlobal.power, fnId - TUYA_MCU_FUNC_REL1_INV) ^ 1?"Off":"On"); + if (value != bitRead(TasmotaGlobal.power, fnId - TUYA_MCU_FUNC_REL1_INV) ^ 1) { + ExecuteCommandPower(fnId - TUYA_MCU_FUNC_REL1_INV + 1, value ^ 1, SRC_SWITCH); // send SRC_SWITCH? to use as flag to prevent loop from inbound states from faceplate interaction + if (value) { PowerOff = true; } } } else if (fnId >= TUYA_MCU_FUNC_SWT1 && fnId <= TUYA_MCU_FUNC_SWT4) { - AddLog(LOG_LEVEL_DEBUG, PSTR("T:fn%d Switch%d --> M%d T%d"),fnId, fnId - TUYA_MCU_FUNC_SWT1 + 1, value, SwitchGetVirtual(fnId - TUYA_MCU_FUNC_SWT1)); - - if (SwitchGetVirtual(fnId - TUYA_MCU_FUNC_SWT1) != value) { - SwitchSetVirtual(fnId - TUYA_MCU_FUNC_SWT1, value); - SwitchHandler(1); + uint32_t switch_state = SwitchGetState(fnId - TUYA_MCU_FUNC_SWT1); + AddLog(LOG_LEVEL_DEBUG, PSTR("T:fn%d Switch%d --> M%d T%d"),fnId, fnId - TUYA_MCU_FUNC_SWT1 + 1, value, switch_state); + if (switch_state != value) { + SwitchSetState(fnId - TUYA_MCU_FUNC_SWT1, value); } } //if (PowerOff) { pTuya->ignore_dimmer_cmd_timeout = millis() + 250; } @@ -2261,14 +2261,16 @@ void TuyaSerialInput(void) } } -bool TuyaButtonPressed(void) -{ - if (!XdrvMailbox.index && ((PRESSED == XdrvMailbox.payload) && (NOT_PRESSED == Button.last_state[XdrvMailbox.index]))) { +bool TuyaButtonPressed(void) { + bool result = false; + uint32_t button = XdrvMailbox.payload; + if (!XdrvMailbox.index && ((PRESSED == button) && (NOT_PRESSED == pTuya->last_button))) { AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: Reset GPIO triggered")); TuyaResetWifi(); - return true; // Reset GPIO served here + result = true; // Reset GPIO served here } - return false; // Don't serve other buttons + pTuya->last_button = button; + return result; // Don't serve other buttons } uint8_t TuyaGetTuyaWifiState(void) { diff --git a/tasmota/tasmota_xdrv_driver/xdrv_39_thermostat.ino b/tasmota/tasmota_xdrv_driver/xdrv_39_thermostat.ino index ed721bb22..d301aa0d7 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_39_thermostat.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_39_thermostat.ino @@ -316,7 +316,7 @@ uint8_t ThermostatInputStatus(uint8_t input_switch) bool ifId = ThermostatSwitchIdValid(input_switch); uint8_t value = 0; if(ifId) { - value = SwitchGetVirtual(ifId - THERMOSTAT_INPUT_SWT1); + value = SwitchGetState(ifId - THERMOSTAT_INPUT_SWT1); } return value; } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota.ino index 0f7deff83..cd44292ad 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota.ino @@ -588,7 +588,7 @@ extern "C" { be_newobject(vm, "list"); for (uint32_t i = 0; i < MAX_SWITCHES_SET; i++) { if (SwitchUsed(i)) { - be_pushbool(vm, SwitchGetVirtual(i) == PRESSED); + be_pushbool(vm, SwitchGetState(i) == PRESSED); be_data_push(vm, -2); be_pop(vm, 1); } From dab80f9d290f1c8770ebc60341fc199fa10dc6be Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 12 Feb 2023 17:23:22 +0100 Subject: [PATCH 258/262] Refactor buttons and switches Pt.2 --- tasmota/tasmota_support/support_button_v4.ino | 319 +++++++------- tasmota/tasmota_support/support_switch_v4.ino | 390 +++++++++--------- 2 files changed, 347 insertions(+), 362 deletions(-) diff --git a/tasmota/tasmota_support/support_button_v4.ino b/tasmota/tasmota_support/support_button_v4.ino index 1c8483b54..3b7850ed7 100644 --- a/tasmota/tasmota_support/support_button_v4.ino +++ b/tasmota/tasmota_support/support_button_v4.ino @@ -53,7 +53,6 @@ struct BUTTON { uint8_t press_counter[MAX_KEYS_SET] = { 0 }; // Number of button presses within Button.window_timer uint8_t dual_receive_count = 0; // Sonoff dual input flag uint8_t first_change = 0; - uint8_t present = 0; // Number of buttons found flag bool probe_mutex; } Button; @@ -92,6 +91,11 @@ void ButtonSetVirtualPinState(uint32_t index, uint32_t state) { bitWrite(Button.virtual_pin, index, state); } +uint8_t ButtonGetState(uint32_t index) { + // Get current state + return Button.debounced_state[index]; +} + uint8_t ButtonLastState(uint32_t index) { // Get last state return Button.last_state[index]; @@ -228,22 +232,16 @@ void ButtonProbe(void) { void ButtonInit(void) { bool ac_detect = (Settings->button_debounce % 10 == 9); - - Button.present = 0; Button.used = 0; - -#ifdef ESP8266 - if ((SONOFF_DUAL == TasmotaGlobal.module_type) || (CH4 == TasmotaGlobal.module_type)) { - Button.present++; - } -#endif // ESP8266 - for (uint32_t i = 0; i < MAX_KEYS_SET; i++) { Button.last_state[i] = NOT_PRESSED; - bool used = false; - +#ifdef ESP8266 + if ((0 == i) && ((SONOFF_DUAL == TasmotaGlobal.module_type) || (CH4 == TasmotaGlobal.module_type))) { + bitSet(Button.used, i); // This pin is used + } else +#endif // ESP8266 if (PinUsed(GPIO_KEY1, i)) { - Button.present++; + bitSet(Button.used, i); // This pin is used #ifdef ESP8266 pinMode(Pin(GPIO_KEY1, i), bitRead(Button.no_pullup_mask, i) ? INPUT : ((16 == Pin(GPIO_KEY1, i)) ? INPUT_PULLDOWN_16 : INPUT_PULLUP)); #endif // ESP8266 @@ -252,11 +250,14 @@ void ButtonInit(void) { #endif // ESP32 // Set global now so doesn't change the saved power state on first button check Button.last_state[i] = (digitalRead(Pin(GPIO_KEY1, i)) != bitRead(Button.inverted_mask, i)); - used = true; + if (ac_detect) { + Button.state[i] = 0x80 + 2 * BUTTON_AC_PERIOD; + Button.last_state[i] = 0; // Will set later in the debouncing code + } } #ifdef USE_ADC else if (PinUsed(GPIO_ADC_BUTTON, i) || PinUsed(GPIO_ADC_BUTTON_INV, i)) { - Button.present++; + bitSet(Button.used, i); // This pin is used } #endif // USE_ADC else { @@ -268,7 +269,6 @@ void ButtonInit(void) { At exit: XdrvMailbox.index bit 0 = current state */ - Button.present++; bitSet(Button.used, i); // This pin is used bool state = (XdrvMailbox.index &1); ButtonSetVirtualPinState(i, state); // Virtual hardware pin state @@ -276,22 +276,15 @@ void ButtonInit(void) { // last_state[i] must be 1 to indicate no button pressed Button.last_state[i] = (bitRead(Button.virtual_pin, i) != bitRead(Button.inverted_mask, i)); - AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: Add vButton%d, State %d"), Button.present, Button.last_state[i]); - - used = true; + AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: Add vButton%d, State %d"), i +1, Button.last_state[i]); } } - - if (used && ac_detect) { - Button.state[i] = 0x80 + 2 * BUTTON_AC_PERIOD; - Button.last_state[i] = 0; // Will set later in the debouncing code - } Button.debounced_state[i] = Button.last_state[i]; } // AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: vPinUsed %08X, State %08X, Invert %08X"), Button.used, Button.virtual_pin, Button.inverted_mask); - if (Button.present) { + if (Button.used) { // Any bit set Button.first_change = true; TickerButton.attach_ms((ac_detect) ? BUTTON_FAST_PROBE_INTERVAL : BUTTON_PROBE_INTERVAL, ButtonProbe); } @@ -338,12 +331,12 @@ void ButtonHandler(void) { char scmnd[20]; for (uint32_t button_index = 0; button_index < MAX_KEYS_SET; button_index++) { - uint8_t button = NOT_PRESSED; - uint8_t button_present = 0; + if (!bitRead(Button.used, button_index)) { return; } + + uint8_t button = Button.debounced_state[button_index]; #ifdef ESP8266 if (!button_index && ((SONOFF_DUAL == TasmotaGlobal.module_type) || (CH4 == TasmotaGlobal.module_type))) { - button_present = 1; if (Button.dual_code) { AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: Code %04X"), Button.dual_code); button = PRESSED; @@ -352,6 +345,8 @@ void ButtonHandler(void) { hold_time_extent = 1; } Button.dual_code = 0; + } else { + button = NOT_PRESSED; } } else #endif // ESP8266 @@ -371,193 +366,183 @@ void ButtonHandler(void) { } AddLog(LOG_LEVEL_INFO, PSTR("PLOT: %u, %u, %u,"), button_index +1, _value, TouchButton.hits[button_index]); // Button number (1..4), value, continuous hits under threshold continue; - } else + } #endif // ESP32 SOC_TOUCH_VERSION_1 or SOC_TOUCH_VERSION_2 - button_present = 1; - button = Button.debounced_state[button_index]; } #ifdef USE_ADC else if (PinUsed(GPIO_ADC_BUTTON, button_index)) { - button_present = 1; button = AdcGetButton(Pin(GPIO_ADC_BUTTON, button_index)); } else if (PinUsed(GPIO_ADC_BUTTON_INV, button_index)) { - button_present = 1; button = AdcGetButton(Pin(GPIO_ADC_BUTTON_INV, button_index)); } #endif // USE_ADC - else if (bitRead(Button.used, button_index)) { - button_present = 1; - button = Button.debounced_state[button_index]; + + XdrvMailbox.index = button_index; + XdrvMailbox.payload = button; + XdrvMailbox.command_code = Button.last_state[button_index]; + if (XdrvCall(FUNC_BUTTON_PRESSED)) { + // Serviced } - - if (button_present) { - XdrvMailbox.index = button_index; - XdrvMailbox.payload = button; - XdrvMailbox.command_code = Button.last_state[button_index]; - if (XdrvCall(FUNC_BUTTON_PRESSED)) { - // Serviced - } #ifdef ESP8266 - else if (SONOFF_4CHPRO == TasmotaGlobal.module_type) { - if (Button.hold_timer[button_index]) { Button.hold_timer[button_index]--; } + else if (SONOFF_4CHPRO == TasmotaGlobal.module_type) { + if (Button.hold_timer[button_index]) { Button.hold_timer[button_index]--; } - bool button_pressed = false; - if ((PRESSED == button) && (NOT_PRESSED == Button.last_state[button_index])) { - AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: Button%d level 1-0"), button_index +1); - Button.hold_timer[button_index] = loops_per_second; - button_pressed = true; + bool button_pressed = false; + if ((PRESSED == button) && (NOT_PRESSED == Button.last_state[button_index])) { + AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: Button%d level 1-0"), button_index +1); + Button.hold_timer[button_index] = loops_per_second; + button_pressed = true; + } + if ((NOT_PRESSED == button) && (PRESSED == Button.last_state[button_index])) { + AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: Button%d level 0-1"), button_index +1); + if (!Button.hold_timer[button_index]) { button_pressed = true; } // Do not allow within 1 second + } + if (button_pressed) { + if (!Settings->flag3.mqtt_buttons) { // SetOption73 (0) - Decouple button from relay and send just mqtt topic + if (!SendKey(KEY_BUTTON, button_index +1, POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set + ExecuteCommandPower(button_index +1, POWER_TOGGLE, SRC_BUTTON); // Execute Toggle command internally + } + } else { + MqttButtonTopic(button_index +1, 1, 0); // SetOption73 (0) - Decouple button from relay and send just mqtt topic } - if ((NOT_PRESSED == button) && (PRESSED == Button.last_state[button_index])) { - AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: Button%d level 0-1"), button_index +1); - if (!Button.hold_timer[button_index]) { button_pressed = true; } // Do not allow within 1 second - } - if (button_pressed) { - if (!Settings->flag3.mqtt_buttons) { // SetOption73 (0) - Decouple button from relay and send just mqtt topic + } + } +#endif // ESP8266 + else { + if ((PRESSED == button) && (NOT_PRESSED == Button.last_state[button_index])) { + + if (Settings->flag.button_single) { // SetOption13 (0) - Allow only single button press for immediate action, + if (!Settings->flag3.mqtt_buttons) { // SetOption73 (0) - Decouple button from relay and send just mqtt topic + AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: Button%d immediate"), button_index +1); if (!SendKey(KEY_BUTTON, button_index +1, POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set ExecuteCommandPower(button_index +1, POWER_TOGGLE, SRC_BUTTON); // Execute Toggle command internally } } else { - MqttButtonTopic(button_index +1, 1, 0); // SetOption73 (0) - Decouple button from relay and send just mqtt topic + MqttButtonTopic(button_index +1, 1, 0); // SetOption73 1 - Decouple button from relay and send just mqtt topic + } + } else { + Button.press_counter[button_index] = (Button.window_timer[button_index]) ? Button.press_counter[button_index] +1 : 1; + AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: Button%d multi-press %d"), button_index +1, Button.press_counter[button_index]); + Button.window_timer[button_index] = loops_per_second / 2; // 0.5 second multi press window + } + TasmotaGlobal.blinks = 201; + } + + if (NOT_PRESSED == button) { + Button.hold_timer[button_index] = 0; + if (Settings->flag3.mqtt_buttons && (PRESSED == Button.last_state[button_index]) && !Button.press_counter[button_index]) { // SetOption73 (0) - Decouple button from relay and send just mqtt topic + MqttButtonTopic(button_index +1, 6, 0); + } + } else { + Button.hold_timer[button_index]++; + if (Settings->flag.button_single) { // SetOption13 (0) - Allow only single button press for immediate action + if (Button.hold_timer[button_index] == loops_per_second * hold_time_extent * Settings->param[P_HOLD_TIME] / 10) { // SetOption32 (40) - Button held for factor times longer + snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_SETOPTION "13 0")); // Disable single press only + ExecuteCommand(scmnd, SRC_BUTTON); + } + } else { + if (Button.hold_timer[button_index] == loops_per_second * Settings->param[P_HOLD_TIME] / 10) { // SetOption32 (40) - Button hold + Button.press_counter[button_index] = 0; + if (Settings->flag3.mqtt_buttons) { // SetOption73 (0) - Decouple button from relay and send just mqtt topic + MqttButtonTopic(button_index +1, 3, 1); + } else { + SendKey(KEY_BUTTON, button_index +1, POWER_HOLD); // Execute Hold command via MQTT if ButtonTopic is set + } + } else { + if (Settings->flag.button_restrict) { // SetOption1 (0) - Control button multipress + if (Settings->param[P_HOLD_IGNORE] > 0) { // SetOption40 (0) - Do not ignore button hold + if (Button.hold_timer[button_index] > loops_per_second * Settings->param[P_HOLD_IGNORE] / 10) { + Button.hold_timer[button_index] = 0; // Reset button hold counter to stay below hold trigger + Button.press_counter[button_index] = 0; // Discard button press to disable functionality + } + } + } else { + if ((Button.hold_timer[button_index] == loops_per_second * hold_time_extent * Settings->param[P_HOLD_TIME] / 10)) { // SetOption32 (40) - Button held for factor times longer + Button.press_counter[button_index] = 0; + snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_RESET " 1")); + ExecuteCommand(scmnd, SRC_BUTTON); + } + } } } } -#endif // ESP8266 - else { - if ((PRESSED == button) && (NOT_PRESSED == Button.last_state[button_index])) { - if (Settings->flag.button_single) { // SetOption13 (0) - Allow only single button press for immediate action, - if (!Settings->flag3.mqtt_buttons) { // SetOption73 (0) - Decouple button from relay and send just mqtt topic - AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: Button%d immediate"), button_index +1); - if (!SendKey(KEY_BUTTON, button_index +1, POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set - ExecuteCommandPower(button_index +1, POWER_TOGGLE, SRC_BUTTON); // Execute Toggle command internally - } - } else { - MqttButtonTopic(button_index +1, 1, 0); // SetOption73 1 - Decouple button from relay and send just mqtt topic - } - } else { - Button.press_counter[button_index] = (Button.window_timer[button_index]) ? Button.press_counter[button_index] +1 : 1; - AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: Button%d multi-press %d"), button_index +1, Button.press_counter[button_index]); - Button.window_timer[button_index] = loops_per_second / 2; // 0.5 second multi press window - } - TasmotaGlobal.blinks = 201; - } - - if (NOT_PRESSED == button) { - Button.hold_timer[button_index] = 0; - if (Settings->flag3.mqtt_buttons && (PRESSED == Button.last_state[button_index]) && !Button.press_counter[button_index]) { // SetOption73 (0) - Decouple button from relay and send just mqtt topic - MqttButtonTopic(button_index +1, 6, 0); - } + if (!Settings->flag.button_single) { // SetOption13 (0) - Allow multi-press + if (Button.window_timer[button_index]) { + Button.window_timer[button_index]--; } else { - Button.hold_timer[button_index]++; - if (Settings->flag.button_single) { // SetOption13 (0) - Allow only single button press for immediate action - if (Button.hold_timer[button_index] == loops_per_second * hold_time_extent * Settings->param[P_HOLD_TIME] / 10) { // SetOption32 (40) - Button held for factor times longer - snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_SETOPTION "13 0")); // Disable single press only - ExecuteCommand(scmnd, SRC_BUTTON); - } - } else { - if (Button.hold_timer[button_index] == loops_per_second * Settings->param[P_HOLD_TIME] / 10) { // SetOption32 (40) - Button hold - Button.press_counter[button_index] = 0; - if (Settings->flag3.mqtt_buttons) { // SetOption73 (0) - Decouple button from relay and send just mqtt topic - MqttButtonTopic(button_index +1, 3, 1); - } else { - SendKey(KEY_BUTTON, button_index +1, POWER_HOLD); // Execute Hold command via MQTT if ButtonTopic is set - } - } else { - if (Settings->flag.button_restrict) { // SetOption1 (0) - Control button multipress - if (Settings->param[P_HOLD_IGNORE] > 0) { // SetOption40 (0) - Do not ignore button hold - if (Button.hold_timer[button_index] > loops_per_second * Settings->param[P_HOLD_IGNORE] / 10) { - Button.hold_timer[button_index] = 0; // Reset button hold counter to stay below hold trigger - Button.press_counter[button_index] = 0; // Discard button press to disable functionality - } - } - } else { - if ((Button.hold_timer[button_index] == loops_per_second * hold_time_extent * Settings->param[P_HOLD_TIME] / 10)) { // SetOption32 (40) - Button held for factor times longer - Button.press_counter[button_index] = 0; - snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_RESET " 1")); - ExecuteCommand(scmnd, SRC_BUTTON); - } - } - } - } - } + if (!TasmotaGlobal.restart_flag && !Button.hold_timer[button_index] && (Button.press_counter[button_index] > 0) && (Button.press_counter[button_index] < 7)) { - if (!Settings->flag.button_single) { // SetOption13 (0) - Allow multi-press - if (Button.window_timer[button_index]) { - Button.window_timer[button_index]--; - } else { - if (!TasmotaGlobal.restart_flag && !Button.hold_timer[button_index] && (Button.press_counter[button_index] > 0) && (Button.press_counter[button_index] < 7)) { - - bool single_press = false; - if (Button.press_counter[button_index] < 3) { // Single or Double press + bool single_press = false; + if (Button.press_counter[button_index] < 3) { // Single or Double press #ifdef ESP8266 - if ((SONOFF_DUAL_R2 == TasmotaGlobal.module_type) || (SONOFF_DUAL == TasmotaGlobal.module_type) || (CH4 == TasmotaGlobal.module_type)) { - single_press = true; - } else + if ((SONOFF_DUAL_R2 == TasmotaGlobal.module_type) || (SONOFF_DUAL == TasmotaGlobal.module_type) || (CH4 == TasmotaGlobal.module_type)) { + single_press = true; + } else #endif // ESP8266 - { - single_press = (Settings->flag.button_swap +1 == Button.press_counter[button_index]); // SetOption11 (0) - if ((1 == Button.present) && (2 == TasmotaGlobal.devices_present)) { // Single Button with two devices only - if (Settings->flag.button_swap) { // SetOption11 (0) - Button.press_counter[button_index] = (single_press) ? 1 : 2; - } + { + single_press = (Settings->flag.button_swap +1 == Button.press_counter[button_index]); // SetOption11 (0) + if ((1 == Button.used) && (2 == TasmotaGlobal.devices_present)) { // Single Button with two devices only + if (Settings->flag.button_swap) { // SetOption11 (0) + Button.press_counter[button_index] = (single_press) ? 1 : 2; } } } + } - XdrvMailbox.index = button_index; - XdrvMailbox.payload = Button.press_counter[button_index]; - if (XdrvCall(FUNC_BUTTON_MULTI_PRESSED)) { - // Serviced + XdrvMailbox.index = button_index; + XdrvMailbox.payload = Button.press_counter[button_index]; + if (XdrvCall(FUNC_BUTTON_MULTI_PRESSED)) { + // Serviced // AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: FUNC_BUTTON_MULTI_PRESSED serviced")); - } else + } else #ifdef ROTARY_V1 - if (!RotaryButtonPressed(button_index)) { + if (!RotaryButtonPressed(button_index)) { #endif - if (!Settings->flag3.mqtt_buttons && single_press && SendKey(KEY_BUTTON, button_index + Button.press_counter[button_index], POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set - // Success - } else { - if (Button.press_counter[button_index] < 6) { // Single to Penta press + if (!Settings->flag3.mqtt_buttons && single_press && SendKey(KEY_BUTTON, button_index + Button.press_counter[button_index], POWER_TOGGLE)) { // Execute Toggle command via MQTT if ButtonTopic is set + // Success + } else { + if (Button.press_counter[button_index] < 6) { // Single to Penta press // if (WifiState() > WIFI_RESTART) { // Wifimanager active // TasmotaGlobal.restart_flag = 1; // } - if (!Settings->flag3.mqtt_buttons) { // SetOption73 - Detach buttons from relays and enable MQTT action state for multipress - if (Button.press_counter[button_index] == 1) { // By default first press always send a TOGGLE (2) - ExecuteCommandPower(button_index + Button.press_counter[button_index], POWER_TOGGLE, SRC_BUTTON); - } else { - SendKey(KEY_BUTTON, button_index +1, Button.press_counter[button_index] +9); // 2,3,4 and 5 press send just the key value (11,12,13 and 14) for rules - if (0 == button_index) { // BUTTON1 can toggle up to 5 relays if present. If a relay is not present will send out the key value (2,11,12,13 and 14) for rules - uint32_t max_device = (TasmotaGlobal.devices_present < MAX_RELAY_BUTTON1) ? TasmotaGlobal.devices_present : MAX_RELAY_BUTTON1; - if ((Button.press_counter[button_index] > 1) && (Button.press_counter[button_index] <= max_device)) { - ExecuteCommandPower(button_index + Button.press_counter[button_index], POWER_TOGGLE, SRC_BUTTON); // Execute Toggle command internally - } + if (!Settings->flag3.mqtt_buttons) { // SetOption73 - Detach buttons from relays and enable MQTT action state for multipress + if (Button.press_counter[button_index] == 1) { // By default first press always send a TOGGLE (2) + ExecuteCommandPower(button_index + Button.press_counter[button_index], POWER_TOGGLE, SRC_BUTTON); + } else { + SendKey(KEY_BUTTON, button_index +1, Button.press_counter[button_index] +9); // 2,3,4 and 5 press send just the key value (11,12,13 and 14) for rules + if (0 == button_index) { // BUTTON1 can toggle up to 5 relays if present. If a relay is not present will send out the key value (2,11,12,13 and 14) for rules + uint32_t max_device = (TasmotaGlobal.devices_present < MAX_RELAY_BUTTON1) ? TasmotaGlobal.devices_present : MAX_RELAY_BUTTON1; + if ((Button.press_counter[button_index] > 1) && (Button.press_counter[button_index] <= max_device)) { + ExecuteCommandPower(button_index + Button.press_counter[button_index], POWER_TOGGLE, SRC_BUTTON); // Execute Toggle command internally } } } - - } else { // 6 press start wificonfig 2 - if (!Settings->flag.button_restrict) { // SetOption1 - Control button multipress - snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_WIFICONFIG " 2")); - ExecuteCommand(scmnd, SRC_BUTTON); - } } - if (Settings->flag3.mqtt_buttons) { // SetOption73 (0) - Decouple button from relay and send just mqtt topic - if (Button.press_counter[button_index] >= 1 && Button.press_counter[button_index] <= 5) { - MqttButtonTopic(button_index +1, Button.press_counter[button_index], 0); - } + + } else { // 6 press start wificonfig 2 + if (!Settings->flag.button_restrict) { // SetOption1 - Control button multipress + snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_WIFICONFIG " 2")); + ExecuteCommand(scmnd, SRC_BUTTON); + } + } + if (Settings->flag3.mqtt_buttons) { // SetOption73 (0) - Decouple button from relay and send just mqtt topic + if (Button.press_counter[button_index] >= 1 && Button.press_counter[button_index] <= 5) { + MqttButtonTopic(button_index +1, Button.press_counter[button_index], 0); } } -#ifdef ROTARY_V1 } -#endif - Button.press_counter[button_index] = 0; +#ifdef ROTARY_V1 } +#endif + Button.press_counter[button_index] = 0; } } - } + } Button.last_state[button_index] = button; } @@ -576,7 +561,7 @@ void MqttButtonTopic(uint32_t button_id, uint32_t action, uint32_t hold) { } void ButtonLoop(void) { - if (Button.present) { + if (Button.used) { if (TimeReached(Button.debounce)) { SetNextTimeInterval(Button.debounce, Settings->button_debounce); // ButtonDebounce (50) ButtonHandler(); diff --git a/tasmota/tasmota_support/support_switch_v4.ino b/tasmota/tasmota_support/support_switch_v4.ino index 4e45a9fed..d2871ca08 100644 --- a/tasmota/tasmota_support/support_switch_v4.ino +++ b/tasmota/tasmota_support/support_switch_v4.ino @@ -76,7 +76,10 @@ void SwitchSetVirtualPinState(uint32_t index, uint32_t state) { void SwitchSetState(uint32_t index, uint32_t state) { // Set debounced pin state to be used by late detected switches - bitSet(Switch.used, index); // Force use bit as call maybe late + if (!bitRead(Switch.used, index)) { + bitSet(Switch.used, index); + AddLog(LOG_LEVEL_DEBUG, PSTR("SWT: Add vSwitch%d, State %d"), index +1, state); + } Switch.debounced_state[index] = state; } @@ -218,16 +221,14 @@ void SwitchProbe(void) { } } } - Switch.probe_mutex = false; } void SwitchInit(void) { bool ac_detect = (Settings->switch_debounce % 10 == 9); - Switch.used = 0; for (uint32_t i = 0; i < MAX_SWITCHES_SET; i++) { - Switch.last_state[i] = NOT_PRESSED; // Init global to virtual switch state; + Switch.last_state[i] = NOT_PRESSED; if (PinUsed(GPIO_SWT1, i)) { bitSet(Switch.used, i); // This pin is used #ifdef ESP8266 @@ -237,6 +238,10 @@ void SwitchInit(void) { pinMode(Pin(GPIO_SWT1, i), bitRead(Switch.pulldown_mask, i) ? INPUT_PULLDOWN : bitRead(Switch.no_pullup_mask, i) ? INPUT : INPUT_PULLUP); #endif // ESP32 Switch.last_state[i] = digitalRead(Pin(GPIO_SWT1, i)); // Set global now so doesn't change the saved power state on first switch check + if (ac_detect) { + Switch.state[i] = 0x80 + 2 * SWITCH_AC_PERIOD; + Switch.last_state[i] = 0; // Will set later in the debouncing code + } } else { XdrvMailbox.index = i; @@ -255,11 +260,6 @@ void SwitchInit(void) { AddLog(LOG_LEVEL_DEBUG, PSTR("SWT: Add vSwitch%d, State %d"), i +1, Switch.last_state[i]); } } - - if (bitRead(Switch.used, i) && ac_detect) { - Switch.state[i] = 0x80 + 2 * SWITCH_AC_PERIOD; - Switch.last_state[i] = 0; // Will set later in the debouncing code - } Switch.debounced_state[i] = Switch.last_state[i]; } @@ -281,212 +281,212 @@ void SwitchHandler(void) { uint32_t loops_per_second = 1000 / Settings->switch_debounce; for (uint32_t i = 0; i < MAX_SWITCHES_SET; i++) { - if (bitRead(Switch.used, i)) { - uint32_t button = Switch.debounced_state[i]; - uint32_t switchflag = POWER_TOGGLE +1; - uint32_t mqtt_action = POWER_NONE; - uint32_t switchmode = Settings->switchmode[i]; + if (!bitRead(Switch.used, i)) { return; } - if (Switch.hold_timer[i] & (((switchmode == PUSHHOLDMULTI) | (switchmode == PUSHHOLDMULTI_INV)) ? SM_TIMER_MASK: SM_NO_TIMER_MASK)) { - Switch.hold_timer[i]--; - if ((Switch.hold_timer[i] & SM_TIMER_MASK) == loops_per_second * Settings->param[P_HOLD_TIME] / 25) { - if ((switchmode == PUSHHOLDMULTI) | (switchmode == PUSHHOLDMULTI_INV)){ - if (((switchmode == PUSHHOLDMULTI) & (NOT_PRESSED == Switch.last_state[i])) | ((switchmode == PUSHHOLDMULTI_INV) & (PRESSED == Switch.last_state[i]))) { - SendKey(KEY_SWITCH, i +1, POWER_INCREMENT); // Execute command via MQTT - } - else if ((Switch.hold_timer[i] & ~SM_TIMER_MASK) == SM_FIRST_PRESS) { - SendKey(KEY_SWITCH, i +1, POWER_DELAYED); // Execute command via MQTT - mqtt_action = POWER_DELAYED; - Switch.hold_timer[i] = 0; - } + uint32_t button = Switch.debounced_state[i]; + uint32_t switchflag = POWER_TOGGLE +1; + uint32_t mqtt_action = POWER_NONE; + uint32_t switchmode = Settings->switchmode[i]; + + if (Switch.hold_timer[i] & (((switchmode == PUSHHOLDMULTI) | (switchmode == PUSHHOLDMULTI_INV)) ? SM_TIMER_MASK: SM_NO_TIMER_MASK)) { + Switch.hold_timer[i]--; + if ((Switch.hold_timer[i] & SM_TIMER_MASK) == loops_per_second * Settings->param[P_HOLD_TIME] / 25) { + if ((switchmode == PUSHHOLDMULTI) | (switchmode == PUSHHOLDMULTI_INV)){ + if (((switchmode == PUSHHOLDMULTI) & (NOT_PRESSED == Switch.last_state[i])) | ((switchmode == PUSHHOLDMULTI_INV) & (PRESSED == Switch.last_state[i]))) { + SendKey(KEY_SWITCH, i +1, POWER_INCREMENT); // Execute command via MQTT } - } - if (0 == (Switch.hold_timer[i] & (((switchmode == PUSHHOLDMULTI) | (switchmode == PUSHHOLDMULTI_INV)) ? SM_TIMER_MASK: SM_NO_TIMER_MASK))) { - switch (switchmode) { - case TOGGLEMULTI: - switchflag = POWER_TOGGLE; // Toggle after hold - break; - case FOLLOWMULTI: - switchflag = button &1; // Follow wall switch state after hold - break; - case FOLLOWMULTI_INV: - switchflag = ~button &1; // Follow inverted wall switch state after hold - break; - case PUSHHOLDMULTI: - if (NOT_PRESSED == button) { - Switch.hold_timer[i] = loops_per_second * Settings->param[P_HOLD_TIME] / 25; - SendKey(KEY_SWITCH, i +1, POWER_INCREMENT); // Execute command via MQTT - mqtt_action = POWER_INCREMENT; - } else { - Switch.hold_timer[i]= 0; - SendKey(KEY_SWITCH, i +1, POWER_CLEAR); // Execute command via MQTT - mqtt_action = POWER_CLEAR; - } - break; - case PUSHHOLDMULTI_INV: - if (PRESSED == button) { - Switch.hold_timer[i] = loops_per_second * Settings->param[P_HOLD_TIME] / 25; - SendKey(KEY_SWITCH, i +1, POWER_INCREMENT); // Execute command via MQTT - mqtt_action = POWER_INCREMENT; - } else { - Switch.hold_timer[i]= 0; - SendKey(KEY_SWITCH, i +1, POWER_CLEAR); // Execute command via MQTT - mqtt_action = POWER_CLEAR; - } - break; - default: - SendKey(KEY_SWITCH, i +1, POWER_HOLD); // Execute command via MQTT - mqtt_action = POWER_HOLD; - break; + else if ((Switch.hold_timer[i] & ~SM_TIMER_MASK) == SM_FIRST_PRESS) { + SendKey(KEY_SWITCH, i +1, POWER_DELAYED); // Execute command via MQTT + mqtt_action = POWER_DELAYED; + Switch.hold_timer[i] = 0; } } } - - if (button != Switch.last_state[i]) { // This implies if ((PRESSED == button) then (NOT_PRESSED == Switch.last_state[i])) + if (0 == (Switch.hold_timer[i] & (((switchmode == PUSHHOLDMULTI) | (switchmode == PUSHHOLDMULTI_INV)) ? SM_TIMER_MASK: SM_NO_TIMER_MASK))) { switch (switchmode) { - case TOGGLE: - case PUSHBUTTON_TOGGLE: - switchflag = POWER_TOGGLE; // Toggle - break; - case FOLLOW: - switchflag = button &1; // Follow wall switch state - break; - case FOLLOW_INV: - switchflag = ~button &1; // Follow inverted wall switch state - break; - case PUSHBUTTON: - if (PRESSED == button) { - switchflag = POWER_TOGGLE; // Toggle with pushbutton to Gnd - } - break; - case PUSHBUTTON_INV: - if (NOT_PRESSED == button) { - switchflag = POWER_TOGGLE; // Toggle with releasing pushbutton from Gnd - } - break; - case PUSHBUTTONHOLD: - if (PRESSED == button) { - Switch.hold_timer[i] = loops_per_second * Settings->param[P_HOLD_TIME] / 10; // Start timer on button press - } - if ((NOT_PRESSED == button) && (Switch.hold_timer[i])) { - Switch.hold_timer[i] = 0; // Button released and hold timer not expired : stop timer... - switchflag = POWER_TOGGLE; // ...and Toggle - } - break; - case PUSHBUTTONHOLD_INV: - if (NOT_PRESSED == button) { - Switch.hold_timer[i] = loops_per_second * Settings->param[P_HOLD_TIME] / 10; // Start timer on button press... - } - if ((PRESSED == button) && (Switch.hold_timer[i])) { - Switch.hold_timer[i] = 0; // Button released and hold timer not expired : stop timer. - switchflag = POWER_TOGGLE; // ...and Toggle - } - break; - case TOGGLEMULTI: - case FOLLOWMULTI: - case FOLLOWMULTI_INV: - if (Switch.hold_timer[i]) { - Switch.hold_timer[i] = 0; - SendKey(KEY_SWITCH, i +1, POWER_HOLD); // Execute command via MQTT - mqtt_action = POWER_HOLD; - } else { - Switch.hold_timer[i] = loops_per_second / 2; // 0.5 second multi press window - } - break; - case PUSHHOLDMULTI: - if (NOT_PRESSED == button) { - if ((Switch.hold_timer[i] & SM_TIMER_MASK) != 0) { - Switch.hold_timer[i] = ((Switch.hold_timer[i] & ~SM_TIMER_MASK) == SM_FIRST_PRESS) ? SM_SECOND_PRESS : 0; - SendKey(KEY_SWITCH, i +1, POWER_INV); // Execute command via MQTT - mqtt_action = POWER_INV; - } - } else { - if ((Switch.hold_timer[i] & SM_TIMER_MASK) > loops_per_second * Settings->param[P_HOLD_TIME] / 25) { - if ((Switch.hold_timer[i] & ~SM_TIMER_MASK) != SM_SECOND_PRESS) { - Switch.hold_timer[i]= SM_FIRST_PRESS; - switchflag = POWER_TOGGLE; // Toggle with pushbutton - } - else{ - SendKey(KEY_SWITCH, i +1, POWER_100); // Execute command via MQTT - mqtt_action = POWER_100; - Switch.hold_timer[i]= 0; - } + case TOGGLEMULTI: + switchflag = POWER_TOGGLE; // Toggle after hold + break; + case FOLLOWMULTI: + switchflag = button &1; // Follow wall switch state after hold + break; + case FOLLOWMULTI_INV: + switchflag = ~button &1; // Follow inverted wall switch state after hold + break; + case PUSHHOLDMULTI: + if (NOT_PRESSED == button) { + Switch.hold_timer[i] = loops_per_second * Settings->param[P_HOLD_TIME] / 25; + SendKey(KEY_SWITCH, i +1, POWER_INCREMENT); // Execute command via MQTT + mqtt_action = POWER_INCREMENT; } else { Switch.hold_timer[i]= 0; - SendKey(KEY_SWITCH, i +1, POWER_RELEASE); // Execute command via MQTT - mqtt_action = POWER_RELEASE; + SendKey(KEY_SWITCH, i +1, POWER_CLEAR); // Execute command via MQTT + mqtt_action = POWER_CLEAR; } - } - Switch.hold_timer[i] = (Switch.hold_timer[i] & ~SM_TIMER_MASK) | loops_per_second * Settings->param[P_HOLD_TIME] / 10; - break; - case PUSHHOLDMULTI_INV: - if (PRESSED == button) { - if ((Switch.hold_timer[i] & SM_TIMER_MASK) != 0) { - Switch.hold_timer[i] = ((Switch.hold_timer[i] & ~SM_TIMER_MASK) == SM_FIRST_PRESS) ? SM_SECOND_PRESS : 0; - SendKey(KEY_SWITCH, i +1, POWER_INV); // Execute command via MQTT - mqtt_action = POWER_INV; - } - } else { - if ((Switch.hold_timer[i] & SM_TIMER_MASK)> loops_per_second * Settings->param[P_HOLD_TIME] / 25) { - if ((Switch.hold_timer[i] & ~SM_TIMER_MASK) != SM_SECOND_PRESS) { - Switch.hold_timer[i]= SM_FIRST_PRESS; - switchflag = POWER_TOGGLE; // Toggle with pushbutton - } - else{ - SendKey(KEY_SWITCH, i +1, POWER_100); // Execute command via MQTT - mqtt_action = POWER_100; - Switch.hold_timer[i]= 0; - } + break; + case PUSHHOLDMULTI_INV: + if (PRESSED == button) { + Switch.hold_timer[i] = loops_per_second * Settings->param[P_HOLD_TIME] / 25; + SendKey(KEY_SWITCH, i +1, POWER_INCREMENT); // Execute command via MQTT + mqtt_action = POWER_INCREMENT; } else { Switch.hold_timer[i]= 0; - SendKey(KEY_SWITCH, i +1, POWER_RELEASE); // Execute command via MQTT - mqtt_action = POWER_RELEASE; + SendKey(KEY_SWITCH, i +1, POWER_CLEAR); // Execute command via MQTT + mqtt_action = POWER_CLEAR; } - } - Switch.hold_timer[i] = (Switch.hold_timer[i] & ~SM_TIMER_MASK) | loops_per_second * Settings->param[P_HOLD_TIME] / 10; - break; - case PUSHON: - if (PRESSED == button) { - switchflag = POWER_ON; // Power ON with pushbutton to Gnd - } - break; - case PUSHON_INV: - if (NOT_PRESSED == button) { - switchflag = POWER_ON; // Power ON with releasing pushbutton from Gnd - } - break; - case PUSH_IGNORE: - case PUSH_IGNORE_INV: - Switch.last_state[i] = button; // Update switch state before publishing - MqttPublishSensor(); + break; + default: + SendKey(KEY_SWITCH, i +1, POWER_HOLD); // Execute command via MQTT + mqtt_action = POWER_HOLD; break; } - Switch.last_state[i] = button; } - if (switchflag <= POWER_TOGGLE) { - if (!Settings->flag5.mqtt_switches) { // SetOption114 (0) - Detach Switches from relays and enable MQTT action state for all the SwitchModes - if (!SendKey(KEY_SWITCH, i +1, switchflag)) { // Execute command via MQTT - ExecuteCommandPower(i +1, switchflag, SRC_SWITCH); // Execute command internally (if i < TasmotaGlobal.devices_present) + } + + if (button != Switch.last_state[i]) { // This implies if ((PRESSED == button) then (NOT_PRESSED == Switch.last_state[i])) + switch (switchmode) { + case TOGGLE: + case PUSHBUTTON_TOGGLE: + switchflag = POWER_TOGGLE; // Toggle + break; + case FOLLOW: + switchflag = button &1; // Follow wall switch state + break; + case FOLLOW_INV: + switchflag = ~button &1; // Follow inverted wall switch state + break; + case PUSHBUTTON: + if (PRESSED == button) { + switchflag = POWER_TOGGLE; // Toggle with pushbutton to Gnd + } + break; + case PUSHBUTTON_INV: + if (NOT_PRESSED == button) { + switchflag = POWER_TOGGLE; // Toggle with releasing pushbutton from Gnd + } + break; + case PUSHBUTTONHOLD: + if (PRESSED == button) { + Switch.hold_timer[i] = loops_per_second * Settings->param[P_HOLD_TIME] / 10; // Start timer on button press + } + if ((NOT_PRESSED == button) && (Switch.hold_timer[i])) { + Switch.hold_timer[i] = 0; // Button released and hold timer not expired : stop timer... + switchflag = POWER_TOGGLE; // ...and Toggle + } + break; + case PUSHBUTTONHOLD_INV: + if (NOT_PRESSED == button) { + Switch.hold_timer[i] = loops_per_second * Settings->param[P_HOLD_TIME] / 10; // Start timer on button press... + } + if ((PRESSED == button) && (Switch.hold_timer[i])) { + Switch.hold_timer[i] = 0; // Button released and hold timer not expired : stop timer. + switchflag = POWER_TOGGLE; // ...and Toggle + } + break; + case TOGGLEMULTI: + case FOLLOWMULTI: + case FOLLOWMULTI_INV: + if (Switch.hold_timer[i]) { + Switch.hold_timer[i] = 0; + SendKey(KEY_SWITCH, i +1, POWER_HOLD); // Execute command via MQTT + mqtt_action = POWER_HOLD; + } else { + Switch.hold_timer[i] = loops_per_second / 2; // 0.5 second multi press window + } + break; + case PUSHHOLDMULTI: + if (NOT_PRESSED == button) { + if ((Switch.hold_timer[i] & SM_TIMER_MASK) != 0) { + Switch.hold_timer[i] = ((Switch.hold_timer[i] & ~SM_TIMER_MASK) == SM_FIRST_PRESS) ? SM_SECOND_PRESS : 0; + SendKey(KEY_SWITCH, i +1, POWER_INV); // Execute command via MQTT + mqtt_action = POWER_INV; } - } else { mqtt_action = switchflag; } - } - if ((mqtt_action != POWER_NONE) && Settings->flag5.mqtt_switches) { // SetOption114 (0) - Detach Switches from relays and enable MQTT action state for all the SwitchModes - if (!Settings->flag.hass_discovery) { // SetOption19 - Control Home Assistant automatic discovery (See SetOption59) - char mqtt_state_str[16]; - char *mqtt_state = mqtt_state_str; - if (mqtt_action <= 3) { - if (mqtt_action != 3) { SendKey(KEY_SWITCH, i +1, mqtt_action); } - mqtt_state = SettingsText(SET_STATE_TXT1 + mqtt_action); + } else { + if ((Switch.hold_timer[i] & SM_TIMER_MASK) > loops_per_second * Settings->param[P_HOLD_TIME] / 25) { + if ((Switch.hold_timer[i] & ~SM_TIMER_MASK) != SM_SECOND_PRESS) { + Switch.hold_timer[i]= SM_FIRST_PRESS; + switchflag = POWER_TOGGLE; // Toggle with pushbutton + } + else{ + SendKey(KEY_SWITCH, i +1, POWER_100); // Execute command via MQTT + mqtt_action = POWER_100; + Switch.hold_timer[i]= 0; + } } else { - GetTextIndexed(mqtt_state_str, sizeof(mqtt_state_str), mqtt_action, kSwitchPressStates); + Switch.hold_timer[i]= 0; + SendKey(KEY_SWITCH, i +1, POWER_RELEASE); // Execute command via MQTT + mqtt_action = POWER_RELEASE; } - Response_P(S_JSON_SVALUE_ACTION_SVALUE, GetSwitchText(i).c_str(), mqtt_state); - char scommand[10]; - snprintf_P(scommand, sizeof(scommand), PSTR(D_JSON_SWITCH "%d"), i +1); - MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_STAT, scommand); } - mqtt_action = POWER_NONE; + Switch.hold_timer[i] = (Switch.hold_timer[i] & ~SM_TIMER_MASK) | loops_per_second * Settings->param[P_HOLD_TIME] / 10; + break; + case PUSHHOLDMULTI_INV: + if (PRESSED == button) { + if ((Switch.hold_timer[i] & SM_TIMER_MASK) != 0) { + Switch.hold_timer[i] = ((Switch.hold_timer[i] & ~SM_TIMER_MASK) == SM_FIRST_PRESS) ? SM_SECOND_PRESS : 0; + SendKey(KEY_SWITCH, i +1, POWER_INV); // Execute command via MQTT + mqtt_action = POWER_INV; + } + } else { + if ((Switch.hold_timer[i] & SM_TIMER_MASK)> loops_per_second * Settings->param[P_HOLD_TIME] / 25) { + if ((Switch.hold_timer[i] & ~SM_TIMER_MASK) != SM_SECOND_PRESS) { + Switch.hold_timer[i]= SM_FIRST_PRESS; + switchflag = POWER_TOGGLE; // Toggle with pushbutton + } + else{ + SendKey(KEY_SWITCH, i +1, POWER_100); // Execute command via MQTT + mqtt_action = POWER_100; + Switch.hold_timer[i]= 0; + } + } else { + Switch.hold_timer[i]= 0; + SendKey(KEY_SWITCH, i +1, POWER_RELEASE); // Execute command via MQTT + mqtt_action = POWER_RELEASE; + } + } + Switch.hold_timer[i] = (Switch.hold_timer[i] & ~SM_TIMER_MASK) | loops_per_second * Settings->param[P_HOLD_TIME] / 10; + break; + case PUSHON: + if (PRESSED == button) { + switchflag = POWER_ON; // Power ON with pushbutton to Gnd + } + break; + case PUSHON_INV: + if (NOT_PRESSED == button) { + switchflag = POWER_ON; // Power ON with releasing pushbutton from Gnd + } + break; + case PUSH_IGNORE: + case PUSH_IGNORE_INV: + Switch.last_state[i] = button; // Update switch state before publishing + MqttPublishSensor(); + break; } + Switch.last_state[i] = button; + } + if (switchflag <= POWER_TOGGLE) { + if (!Settings->flag5.mqtt_switches) { // SetOption114 (0) - Detach Switches from relays and enable MQTT action state for all the SwitchModes + if (!SendKey(KEY_SWITCH, i +1, switchflag)) { // Execute command via MQTT + ExecuteCommandPower(i +1, switchflag, SRC_SWITCH); // Execute command internally (if i < TasmotaGlobal.devices_present) + } + } else { mqtt_action = switchflag; } + } + if ((mqtt_action != POWER_NONE) && Settings->flag5.mqtt_switches) { // SetOption114 (0) - Detach Switches from relays and enable MQTT action state for all the SwitchModes + if (!Settings->flag.hass_discovery) { // SetOption19 - Control Home Assistant automatic discovery (See SetOption59) + char mqtt_state_str[16]; + char *mqtt_state = mqtt_state_str; + if (mqtt_action <= 3) { + if (mqtt_action != 3) { SendKey(KEY_SWITCH, i +1, mqtt_action); } + mqtt_state = SettingsText(SET_STATE_TXT1 + mqtt_action); + } else { + GetTextIndexed(mqtt_state_str, sizeof(mqtt_state_str), mqtt_action, kSwitchPressStates); + } + Response_P(S_JSON_SVALUE_ACTION_SVALUE, GetSwitchText(i).c_str(), mqtt_state); + char scommand[10]; + snprintf_P(scommand, sizeof(scommand), PSTR(D_JSON_SWITCH "%d"), i +1); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_STAT, scommand); + } + mqtt_action = POWER_NONE; } } } From b72cf69d2c7d3a0087f9f93c3773ab64b072e5ce Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 12 Feb 2023 17:40:24 +0100 Subject: [PATCH 259/262] Refactor buttons and switches Pt.3 - Quick return from interrupts --- tasmota/tasmota_support/support_button_v4.ino | 9 ++++++--- tasmota/tasmota_support/support_switch_v4.ino | 9 ++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/tasmota/tasmota_support/support_button_v4.ino b/tasmota/tasmota_support/support_button_v4.ino index 3b7850ed7..cf85b6dd5 100644 --- a/tasmota/tasmota_support/support_button_v4.ino +++ b/tasmota/tasmota_support/support_button_v4.ino @@ -134,6 +134,11 @@ void ButtonProbe(void) { uint32_t not_activated; for (uint32_t i = 0; i < MAX_KEYS_SET; i++) { + if (!bitRead(Button.used, i)) { + Button.probe_mutex = false; + return; + } + if (PinUsed(GPIO_KEY1, i)) { #if defined(SOC_TOUCH_VERSION_1) || defined(SOC_TOUCH_VERSION_2) if (bitRead(TouchButton.touch_mask, i)) { @@ -147,11 +152,9 @@ void ButtonProbe(void) { } else #endif // ESP32 SOC_TOUCH_VERSION_1 or SOC_TOUCH_VERSION_2 not_activated = (digitalRead(Pin(GPIO_KEY1, i)) != bitRead(Button.inverted_mask, i)); - } - else if (bitRead(Button.used, i)) { + } else { not_activated = (bitRead(Button.virtual_pin, i) != bitRead(Button.inverted_mask, i)); } - else { continue; } if (not_activated) { diff --git a/tasmota/tasmota_support/support_switch_v4.ino b/tasmota/tasmota_support/support_switch_v4.ino index d2871ca08..50bc7d428 100644 --- a/tasmota/tasmota_support/support_switch_v4.ino +++ b/tasmota/tasmota_support/support_switch_v4.ino @@ -138,13 +138,16 @@ void SwitchProbe(void) { uint32_t not_activated; for (uint32_t i = 0; i < MAX_SWITCHES_SET; i++) { + if (!bitRead(Switch.used, i)) { + Switch.probe_mutex = false; + return; + } + if (PinUsed(GPIO_SWT1, i)) { not_activated = digitalRead(Pin(GPIO_SWT1, i)); - } - else if (bitRead(Switch.used, i)) { + } else { not_activated = bitRead(Switch.virtual_pin, i); } - else { continue; } // Olimex user_switch2.c code to fix 50Hz induced pulses if (not_activated) { From 3ea69f7d7bd1f4a5482cfd842272ccdf4c8f9564 Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Sun, 12 Feb 2023 20:45:28 +0100 Subject: [PATCH 260/262] Many matter improvements (#17935) --- .../src/embedded/Matter_Commissioning.be | 47 +- .../src/embedded/Matter_Device.be | 130 +- .../berry_matter/src/embedded/Matter_IM.be | 224 +- .../src/embedded/Matter_IM_Data.be | 2 +- .../src/embedded/Matter_Message.be | 9 +- .../src/embedded/Matter_MessageHandler.be | 4 +- .../src/embedded/Matter_Plugin.be | 31 +- .../src/embedded/Matter_Plugin_Relay.be | 47 +- .../src/embedded/Matter_Plugin_core.be | 57 +- .../src/embedded/Matter_Session.be | 17 + .../berry_matter/src/embedded/Matter_TLV.be | 15 +- .../solidified_Matter_Commissioning.h | 3526 +++++++++-------- .../src/solidify/solidified_Matter_Device.h | 2359 ++++++----- .../src/solidify/solidified_Matter_IM.h | 2574 +++++++----- .../src/solidify/solidified_Matter_IM_Data.h | 2 +- .../src/solidify/solidified_Matter_Message.h | 1656 ++++---- .../solidified_Matter_MessageHandler.h | 575 +-- .../src/solidify/solidified_Matter_Plugin.h | 375 +- .../solidify/solidified_Matter_Plugin_Relay.h | 156 +- .../solidify/solidified_Matter_Plugin_core.h | 1775 +++++---- .../src/solidify/solidified_Matter_Session.h | 2226 ++++++----- .../src/solidify/solidified_Matter_TLV.h | 810 ++-- 22 files changed, 9137 insertions(+), 7480 deletions(-) diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Commissioning.be b/lib/libesp32/berry_matter/src/embedded/Matter_Commissioning.be index 0a027affd..d2a5a0fa9 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Commissioning.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Commissioning.be @@ -63,7 +63,7 @@ class Matter_Commisioning_Context self.window_open = true # auto-commissioning for now end - def process_incoming(msg, remote_ip, remote_port) + def process_incoming(msg) # if !self.window_open tasmota.log("MTR: commissioning not open", 2) @@ -72,21 +72,21 @@ class Matter_Commisioning_Context tasmota.log("MTR: received message " + matter.inspect(msg), 3) if msg.opcode == 0x20 - return self.parse_PBKDFParamRequest(msg, remote_ip, remote_port) + return self.parse_PBKDFParamRequest(msg) elif msg.opcode == 0x22 - return self.parse_Pake1(msg, remote_ip, remote_port) + return self.parse_Pake1(msg) elif msg.opcode == 0x24 - return self.parse_Pake3(msg, remote_ip, remote_port) + return self.parse_Pake3(msg) elif msg.opcode == 0x30 - return self.parse_Sigma1(msg, remote_ip, remote_port) + return self.parse_Sigma1(msg) elif msg.opcode == 0x32 - return self.parse_Sigma3(msg, remote_ip, remote_port) + return self.parse_Sigma3(msg) end return false end - def parse_PBKDFParamRequest(msg, addr, port) + def parse_PBKDFParamRequest(msg) import crypto # sanity checks if msg.opcode != 0x20 || msg.local_session_id != 0 || msg.protocol_id != 0 @@ -122,10 +122,10 @@ class Matter_Commisioning_Context var resp = msg.build_response(0x21 #-PBKDR Response-#, true) var raw = resp.encode(pbkdfparamresp_raw) - self.responder.send_response(raw, addr, port, resp.message_counter) + self.responder.send_response(raw, msg.remote_ip, msg.remote_port, resp.message_counter) end - def parse_Pake1(msg, addr, port) + def parse_Pake1(msg) import crypto # sanity checks if msg.opcode != 0x22 || msg.local_session_id != 0 || msg.protocol_id != 0 @@ -200,10 +200,10 @@ class Matter_Commisioning_Context var resp = msg.build_response(0x23 #-pake-2-#, true) # no reliable flag var raw = resp.encode(pake2_raw) - self.responder.send_response(raw, addr, port, resp.message_counter) + self.responder.send_response(raw, msg.remote_ip, msg.remote_port, resp.message_counter) end - def parse_Pake3(msg, addr, port) + def parse_Pake3(msg) import crypto # sanity checks if msg.opcode != 0x24 || msg.local_session_id != 0 || msg.protocol_id != 0 @@ -241,7 +241,7 @@ class Matter_Commisioning_Context var raw = resp.encode(status_raw) - self.responder.send_response(raw, addr, port, nil) + self.responder.send_response(raw, msg.remote_ip, msg.remote_port, nil) self.responder.add_session(self.future_local_session_id, self.future_initiator_session_id, self.I2RKey, self.R2IKey, self.AttestationChallenge, self.session_timestamp) end @@ -268,7 +268,7 @@ class Matter_Commisioning_Context return nil end - def parse_Sigma1(msg, addr, port) + def parse_Sigma1(msg) import crypto # sanity checks if msg.opcode != 0x30 || msg.local_session_id != 0 || msg.protocol_id != 0 @@ -279,7 +279,15 @@ class Matter_Commisioning_Context self.initiatorEph_pub = sigma1.initiatorEphPubKey # find session - var session = self.find_session_by_destination_id(sigma1.destinationId, sigma1.initiatorRandom) + var is_resumption = (sigma1.resumptionID != nil && sigma1.initiatorResumeMIC != nil) + + # Check that it's a resumption + var session + if is_resumption + session = self.device.sessions.find_session_by_resumption_id(sigma1.resumptionID) + else + session = self.find_session_by_destination_id(sigma1.destinationId, sigma1.initiatorRandom) + end if session == nil raise "valuer_error", "StatusReport(GeneralCode: FAILURE, ProtocolId: SECURE_CHANNEL, ProtocolCode: NO_SHARED_TRUST_ROOTS)" end session.source_node_id = msg.source_node_id session.set_mode(matter.Session.__CASE) @@ -294,8 +302,7 @@ class Matter_Commisioning_Context # Check that it's a resumption - if sigma1.resumptionID != nil && sigma1.initiatorResumeMIC != nil && - session.shared_secret != nil + if is_resumption && session.shared_secret != nil # Resumption p.169 var s1rk_salt = sigma1.initiatorRandom + sigma1.resumptionID var s1rk_info = bytes().fromstring("Sigma1_Resume") @@ -356,7 +363,7 @@ class Matter_Commisioning_Context var resp = msg.build_response(0x33 #-sigma-2-resume-#, true) var raw = resp.encode(sigma2resume_raw) - self.responder.send_response(raw, addr, port, resp.message_counter) + self.responder.send_response(raw, msg.remote_ip, msg.remote_port, resp.message_counter) session.close() session.set_keys(i2r, r2i, ac, session_timestamp) @@ -431,14 +438,14 @@ class Matter_Commisioning_Context var resp = msg.build_response(0x31 #-sigma-2-#, true) # no reliable flag var raw = resp.encode(sigma2_raw) - self.responder.send_response(raw, addr, port, resp.message_counter) + self.responder.send_response(raw, msg.remote_ip, msg.remote_port, resp.message_counter) return true end return true end - def parse_Sigma3(msg, addr, port) + def parse_Sigma3(msg) import crypto # sanity checks if msg.opcode != 0x32 || msg.local_session_id != 0 || msg.protocol_id != 0 @@ -546,7 +553,7 @@ class Matter_Commisioning_Context var raw = resp.encode(status_raw) - self.responder.send_response(raw, addr, port, resp.message_counter) + self.responder.send_response(raw, msg.remote_ip, msg.remote_port, resp.message_counter) session.close() session.set_keys(i2r, r2i, ac, session_timestamp) diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Device.be b/lib/libesp32/berry_matter/src/embedded/Matter_Device.be index 96463cac2..39ba91160 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Device.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Device.be @@ -70,6 +70,7 @@ class Matter_Device # add the default plugin self.plugins.push(matter.Plugin_core(self)) + self.plugins.push(matter.Plugin_Relay(self)) self.start_mdns_announce_hostnames() @@ -267,21 +268,134 @@ class Matter_Device ############################################################# # read an attribute # - def read_attribute(msg, endpoint, cluster, attribute) - var idx = 0 - while idx < size(self.plugins) - var plugin = self.plugins[idx] + # def read_attribute(msg, ctx) + # # dispatch only to plugins that support this endpoint and cluster + # var endpoint = ctx.endpoint + # var cluster = ctx.cluster - var ret = plugin.read_attribute(msg, endpoint, cluster, attribute) - if ret != nil - return ret + # var idx = 0 + # while idx < size(self.plugins) + # var plugin = self.plugins[idx] + + # if plugin.has(cluster, endpoint) + # var ret = plugin.read_attribute(msg, ctx) + # if ret != nil + # return ret + # end + # end + + # idx += 1 + # end + # end + + ############################################################# + # expand attribute list based + # + # called only when expansion is needed, + # so we don't need to report any error since they are ignored + def process_attribute_expansion(ctx, cb) + import string + var endpoint = ctx.endpoint + var endpoint_mono = [ endpoint ] + var endpoint_found = false # did any endpoint match + var cluster = ctx.cluster + var cluster_mono = [ cluster ] + var cluster_found = false + var attribute = ctx.attribute + var attribute_mono = [ attribute ] + var attribute_found = false + + var direct = (ctx.endpoint != nil) && (ctx.cluster != nil) && (ctx.attribute != nil) # true if the target is a precise attribute, false if it results from an expansion and error are ignored + + tasmota.log(string.format("MTR: process_attribute_expansion %s", str(ctx)), 3) + for pi: self.plugins + var ep_list = pi.get_endpoints() # get supported endpoints for this plugin + tasmota.log(string.format("MTR: ep_list %s %s", str(pi), str(ep_list)), 3) + if endpoint != nil + # we have a specific endpoint, make sure it's in the list + if ep_list.find(endpoint) != nil + ep_list = endpoint_mono + endpoint_found = true + else + continue + end end + # ep_list is the actual list of candidate endpoints for this plugin + # iterate on endpoints + for ep: ep_list + # now filter on clusters + var cluster_list = pi.get_cluster_list(ep) + tasmota.log(string.format("MTR: cluster_list %s %s", str(ep), str(cluster_list)), 3) + if cluster != nil + # we have a specific cluster, make sure it's in the list + if cluster_list.find(cluster) != nil + cluster_list = cluster_mono + cluster_found = true + else + continue + end + end + # cluster_list is the actual list of candidate cluster for this pluging and endpoint + for cl: cluster_list + # now filter on attribute + var attr_list = pi.get_attribute_list(ep, cluster) + tasmota.log(string.format("MTR: attr_list %s %s", str(cl), str(attr_list)), 3) + if attribute != nil + # we have a specific attribute, make sure it's in the list + if attr_list.find(attribute) != nil + attr_list = attribute_mono + attribute_found = true + else + continue + end + for at: attr_list + # we now have the complete candidate: ep/cl/at + tasmota.log(string.format("MTR: expansion [%02X]%04X/%04X", ep, cl, at), 3) + ctx.endpoint = ep + ctx.cluster = cl + ctx.attribute = at + var finished = cb(pi, ctx, direct) # call the callback with the plugin and the context + if finished return end + end + end + end + end + end - idx += 1 + # we didn't have any successful match, report an error if direct (non-expansion request) + if direct + # since it's a direct request, ctx has already the correct endpoint/cluster/attribute + if !endpoint_found ctx.status = matter.UNSUPPORTED_ENDPOINT + elif !cluster_found ctx.status = matter.UNSUPPORTED_CLUSTER + elif !attribute_found ctx.status = matter.UNSUPPORTED_ATTRIBUTE + else ctx.status = matter.UNREPORTABLE_ATTRIBUTE + end + cb(nil, ctx, true) end end + # def process_read_attribute(ctx) + # self.process_attribute_expansion(ctx, + # / pi, ctx, direct -> pi.read_attribute(ctx)) + # end + ############################################################# + # get active endpoints + # + # return the list of endpoints from all plugins (distinct) + def get_active_endpoints(exclude_zero) + var ret = [] + for p:self.plugins + var e = p.get_endpoints() + for elt:e + if exclude_zero && elt == 0 continue end + if ret.find(elt) == nil + ret.push(elt) + end + end + end + return ret + end ############################################################# # Persistance of Matter Device parameters diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_IM.be b/lib/libesp32/berry_matter/src/embedded/Matter_IM.be index 35fdb74d7..e03f17aeb 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_IM.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_IM.be @@ -33,6 +33,21 @@ class Matter_Response_container var attribute var command var status + + def tostring() + try + import string + var s = "" + s += (self.endpoint != nil ? string.format("[%02X]", self.endpoint) : "[**]") + s += (self.cluster != nil ? string.format("%04X/", self.cluster) : "****/") + s += (self.attribute != nil ? string.format("%04X", self.attribute) : "") + s += (self.command != nil ? string.format("%04X", self.attribute) : "") + return s + except .. as e, m + return "Exception> " + str(e) + ", " + str(m) + end + end + end matter.Response_container = Matter_Response_container @@ -40,13 +55,17 @@ matter.Response_container = Matter_Response_container # Matter_IM class ################################################################################# class Matter_IM + static var MAX_MESSAGE = 1200 + static var MSG_TIMEOUT = 10000 # 10s var responder + var device - def init(responder) + def init(responder, device) self.responder = responder + self.device = device end - def process_incoming(msg, remote_ip, remote_port) + def process_incoming(msg) # messages are always TLV, decode payload tasmota.log("MTR: received IM message " + matter.inspect(msg), 3) @@ -59,25 +78,25 @@ class Matter_IM var opcode = msg.opcode if opcode == 0x01 # Status Response - return self.process_status_response(msg, val, remote_ip, remote_port) + return self.process_status_response(msg, val) elif opcode == 0x02 # Read Request - return self.process_read_request(msg, val, remote_ip, remote_port) + return self.process_read_request(msg, val) elif opcode == 0x03 # Subscribe Request - return self.subscribe_request(msg, val, remote_ip, remote_port) + return self.subscribe_request(msg, val) elif opcode == 0x04 # Subscribe Response - return self.subscribe_response(msg, val, remote_ip, remote_port) + return self.subscribe_response(msg, val) elif opcode == 0x05 # Report Data - return self.report_data(msg, val, remote_ip, remote_port) + return self.report_data(msg, val) elif opcode == 0x06 # Write Request - return self.process_write_request(msg, val, remote_ip, remote_port) + return self.process_write_request(msg, val) elif opcode == 0x07 # Write Response - return self.process_write_response(msg, val, remote_ip, remote_port) + return self.process_write_response(msg, val) elif opcode == 0x08 # Invoke Request - return self.process_invoke_request(msg, val, remote_ip, remote_port) + return self.process_invoke_request(msg, val) elif opcode == 0x09 # Invoke Response - return self.process_invoke_response(msg, val, remote_ip, remote_port) + return self.process_invoke_response(msg, val) elif opcode == 0x0A # Timed Request - return self.process_timed_request(msg, val, remote_ip, remote_port) + return self.process_timed_request(msg, val) end return false @@ -89,7 +108,7 @@ class Matter_IM # val is the TLV structure # returns `true` if processed, `false` if silently ignored, # or raises an exception - def process_status_response(msg, val, remote_ip, remote_port) + def process_status_response(msg, val) import string var status = val.findsubval(0, 0xFF) tasmota.log(string.format("MTR: Status Response = 0x%02X", status), 3) @@ -102,64 +121,157 @@ class Matter_IM # val is the TLV structure # returns `true` if processed, `false` if silently ignored, # or raises an exception - def process_read_request(msg, val, remote_ip, remote_port) + def process_read_request(msg, val) + var endpoints = self.device.get_active_endpoints() + + ### Inner function to be iterated upon + # ret is the ReportDataMessage list to send back + # ctx is the context with endpoint/cluster/attribute + # direct is true if error is reported, false if error is silently ignored + # + # if `pi` is nil, just report the status for ctx.status + # + # should return true if answered, false if passing to next handler + def read_single_attribute(ret, pi, ctx, direct) + import string + var attr_name = matter.get_attribute_name(ctx.cluster, ctx.attribute) + attr_name = attr_name ? " (" + attr_name + ")" : "" + # tasmota.log(string.format("MTR: Read Attribute " + str(ctx) + (attr_name ? " (" + attr_name + ")" : ""), 2) + # Special case to report unsupported item, if pi==nil + var res = (pi != nil) ? pi.read_attribute(msg, ctx) : nil + if res != nil + var a1 = matter.AttributeReportIB() + a1.attribute_data = matter.AttributeDataIB() + a1.attribute_data.data_version = 1 + a1.attribute_data.path = matter.AttributePathIB() + a1.attribute_data.path.endpoint = ctx.endpoint + a1.attribute_data.path.cluster = ctx.cluster + a1.attribute_data.path.attribute = ctx.attribute + a1.attribute_data.data = res + + ret.attribute_reports.push(a1) + tasmota.log(string.format("MTR: Read_Attr %s%s - %s", str(ctx), attr_name, str(res)), 2) + return true # stop expansion since we have a value + elif ctx.status != nil + if direct + var a1 = matter.AttributeReportIB() + a1.attribute_status = matter.AttributeStatusIB() + a1.attribute_status.path = matter.AttributePathIB() + a1.attribute_status.status = matter.StatusIB() + a1.attribute_status.path.endpoint = ctx.endpoint + a1.attribute_status.path.cluster = ctx.cluster + a1.attribute_status.path.attribute = ctx.attribute + a1.attribute_status.status.status = ctx.status + + ret.attribute_reports.push(a1) + tasmota.log(string.format("MTR: Read_Attr %s%s - STATUS: 0x%02X %s", str(ctx), attr_name, ctx.status, ctx.status == matter.UNSUPPORTED_ATTRIBUTE ? "UNSUPPORTED_ATTRIBUTE" : ""), 2) + return true + end + else + tasmota.log(string.format("MTR: Read_Attr %s%s - IGNORED", str(ctx), attr_name), 2) + # ignore if content is nil and status is undefined + end + end + # structure is `ReadRequestMessage` 10.6.2 p.558 tasmota.log("MTR: IM:read_request processing start", 3) + var ctx = matter.Response_container() var query = matter.ReadRequestMessage().from_TLV(val) if query.attributes_requests != nil # prepare the response var ret = matter.ReportDataMessage() - ret.suppress_response = true + # ret.suppress_response = true ret.attribute_reports = [] - # TODO - we need to implement Concrete path expansion here - for q:query.attributes_requests - var attr_name = matter.get_attribute_name(q.cluster, q.attribute) - tasmota.log("MTR: Read Attribute " + str(q) + (attr_name ? " (" + attr_name + ")" : ""), 2) - var res = self.responder.device.read_attribute(msg, q.endpoint, q.cluster, q.attribute) - if res != nil - var a1 = matter.AttributeReportIB() - # a1.attribute_status = matter.AttributeStatusIB() - # a1.attribute_status.path = matter.AttributePathIB() - # a1.attribute_status.status = matter.StatusIB() - # a1.attribute_status.path.endpoint = 0 - # a1.attribute_status.path.cluster = q.cluster - # a1.attribute_status.path.attribute = q.attribute - # a1.attribute_status.status.status = matter.SUCCESS - a1.attribute_data = matter.AttributeDataIB() - a1.attribute_data.data_version = 1 - a1.attribute_data.path = matter.AttributePathIB() - a1.attribute_data.path.endpoint = 0 - a1.attribute_data.path.cluster = q.cluster - a1.attribute_data.path.attribute = q.attribute - a1.attribute_data.data = res - - ret.attribute_reports.push(a1) + # need to do expansion here + ctx.endpoint = q.endpoint + ctx.cluster = q.cluster + ctx.attribute = q.attribute + ctx.status = matter.UNSUPPORTED_ATTRIBUTE #default error if returned `nil` + + # expand endpoint + if ctx.endpoint == nil || ctx.cluster == nil || ctx.attribute == nil + # we need expansion, log first + if ctx.cluster != nil && ctx.attribute != nil + var attr_name = matter.get_attribute_name(ctx.cluster, ctx.attribute) + tasmota.log("MTR: Read_Attr " + str(ctx) + (attr_name ? " (" + attr_name + ")" : ""), 2) + else + tasmota.log("MTR: Read_Attr " + str(ctx), 2) + end + end + + # implement concrete expansion + self.device.process_attribute_expansion(ctx, + / pi, ctx, direct -> read_single_attribute(ret, pi, ctx, direct) + ) end tasmota.log("MTR: ReportDataMessage=" + str(ret), 3) tasmota.log("MTR: ReportDataMessageTLV=" + str(ret.to_TLV()), 3) - var resp = msg.build_response(0x05 #-Report Data-#, true) - resp.encode(ret.to_TLV().encode()) # payload in cleartext - resp.encrypt() - - self.responder.send_response(resp.raw, remote_ip, remote_port, resp.message_counter) + # send the reponse that may need to be chunked if too large to fit in a single UDP message + self.send_attr_report(msg, ret) end return true end + def send_attr_report(msg, ret) + # class to keep the current chunked reponse + class Matter_Attr_Report + var ret # return structure as ReportDataMessage TLV structure + var resp # response Frame (to keep all fields like session or remote_ip/port) + var expiration + end + + # compute the acceptable size + + var msg_sz = 0 + var elements = 0 + if size(ret.attribute_reports) > 0 + msg_sz = size(ret.attribute_reports[0].to_TLV().encode()) + elements = 1 + end + while msg_sz < self.MAX_MESSAGE && elements < size(ret.attribute_reports) + var next_sz = size(ret.attribute_reports[elements].to_TLV().encode()) + if msg_sz + next_sz < self.MAX_MESSAGE + msg_sz += next_sz + elements += 1 + end + end + + var next_elemnts = ret.attribute_reports[elements .. ] + ret.attribute_reports = ret.attribute_reports[0 .. elements - 1] + + if size(next_elemnts) > 0 + ret.more_chunked_messages = true + end + + var resp = msg.build_response(0x05 #-Report Data-#, true) + resp.encode(ret.to_TLV().encode()) # payload in cleartext + resp.encrypt() + self.responder.send_response(resp.raw, msg.remote_ip, msg.remote_port, resp.message_counter) + + if size(next_elemnts) > 0 + ret.attribute_reports = next_elemnts + var chunked_next = Matter_Attr_Report() + chunked_next.ret = ret + chunked_next.resp = resp + chunked_next.expiration = tasmota.millis() + self.MSG_TIMEOUT + end + + end + ############################################################# # process IM 0x08 Invoke Request # # val is the TLV structure # returns `true` if processed, `false` if silently ignored, # or raises an exception - def process_invoke_request(msg, val, remote_ip, remote_port) + def process_invoke_request(msg, val) import string # structure is `ReadRequestMessage` 10.6.2 p.558 tasmota.log("MTR: IM:invoke_request processing start", 3) @@ -180,7 +292,7 @@ class Matter_IM var cmd_name = matter.get_command_name(ctx.cluster, ctx.command) if cmd_name == nil cmd_name = string.format("0x%04X/0x02X", ctx.cluster, ctx.command) end - tasmota.log(string.format("MTR: >Received_cmd %s from [%s]:%i", cmd_name, remote_ip, remote_port), 2) + tasmota.log(string.format("MTR: >Received_cmd %s from [%s]:%i", cmd_name, msg.remote_ip, msg.remote_port), 2) var res = self.responder.device.invoke_request(msg, q.command_fields, ctx) var a1 = matter.InvokeResponseIB() if res != nil @@ -218,13 +330,13 @@ class Matter_IM resp.encode(ret.to_TLV().encode()) # payload in cleartext resp.encrypt() - self.responder.send_response(resp.raw, remote_ip, remote_port, resp.message_counter) + self.responder.send_response(resp.raw, msg.remote_ip, msg.remote_port, resp.message_counter) elif msg.x_flag_r # nothing to respond, check if we need a standalone ack var resp = msg.build_standalone_ack() resp.encode() resp.encrypt() # no ecnryption required for ACK - self.responder.send_response(resp.raw, remote_ip, remote_port, resp.message_counter) + self.responder.send_response(resp.raw, msg.remote_ip, msg.remote_port, resp.message_counter) end end end @@ -232,7 +344,7 @@ class Matter_IM ############################################################# # process IM 0x03 Subscribe Request # - def subscribe_request(msg, val, remote_ip, remote_port) + def subscribe_request(msg, val) import string var query = matter.SubscribeRequestMessage().from_TLV(val) tasmota.log("MTR: received SubscribeRequestMessage=" + str(query), 3) @@ -242,7 +354,7 @@ class Matter_IM ############################################################# # process IM 0x04 Subscribe Response # - def subscribe_response(msg, val, remote_ip, remote_port) + def subscribe_response(msg, val) import string var query = matter.SubscribeResponseMessage().from_TLV(val) tasmota.log("MTR: received SubscribeResponsetMessage=" + str(query), 3) @@ -252,7 +364,7 @@ class Matter_IM ############################################################# # process IM 0x05 ReportData # - def report_data(msg, val, remote_ip, remote_port) + def report_data(msg, val) import string var query = matter.ReportDataMessage().from_TLV(val) tasmota.log("MTR: received ReportDataMessage=" + str(query), 3) @@ -262,7 +374,7 @@ class Matter_IM ############################################################# # process IM 0x06 Write Request # - def process_write_request(msg, val, remote_ip, remote_port) + def process_write_request(msg, val) import string var query = matter.WriteRequestMessage().from_TLV(val) tasmota.log("MTR: received WriteRequestMessage=" + str(query), 3) @@ -272,7 +384,7 @@ class Matter_IM ############################################################# # process IM 0x07 Write Response # - def process_write_response(msg, val, remote_ip, remote_port) + def process_write_response(msg, val) import string var query = matter.WriteResponseMessage().from_TLV(val) tasmota.log("MTR: received WriteResponseMessage=" + str(query), 3) @@ -282,7 +394,7 @@ class Matter_IM ############################################################# # process IM 0x09 Invoke Response # - def process_invoke_response(msg, val, remote_ip, remote_port) + def process_invoke_response(msg, val) import string var query = matter.InvokeResponseMessage().from_TLV(val) tasmota.log("MTR: received InvokeResponseMessage=" + str(query), 3) @@ -292,12 +404,12 @@ class Matter_IM ############################################################# # process IM 0x0A Timed Request # - def process_timed_request(msg, val, remote_ip, remote_port) + def process_timed_request(msg, val) import string var query = matter.TimedRequestMessage().from_TLV(val) tasmota.log("MTR: received TimedRequestMessage=" + str(query), 3) - tasmota.log(string.format("MTR: >Received_IM TimedRequest=%i from [%s]:%i", query.timeout, remote_ip, remote_port), 2) + tasmota.log(string.format("MTR: >Received_IM TimedRequest=%i from [%s]:%i", query.timeout, msg.remote_ip, msg.remote_port), 2) # Send success status report var sr = matter.StatusResponseMessage() @@ -305,7 +417,7 @@ class Matter_IM var resp = msg.build_response(0x01 #-Status Response-#, true #-reliable-#) resp.encode(sr.to_TLV().encode()) # payload in cleartext resp.encrypt() - self.responder.send_response(resp.raw, remote_ip, remote_port, resp.message_counter) + self.responder.send_response(resp.raw, msg.remote_ip, msg.remote_port, resp.message_counter) return true end diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_IM_Data.be b/lib/libesp32/berry_matter/src/embedded/Matter_IM_Data.be index b6f367bc9..f1159ff36 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_IM_Data.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_IM_Data.be @@ -546,7 +546,7 @@ class Matter_StatusIB : Matter_IM_base def to_TLV() var TLV = matter.TLV - var s = TLV.Matter_TLV_list() + var s = TLV.Matter_TLV_struct() s.add_TLV(0, TLV.U2, self.status) s.add_TLV(1, TLV.U2, self.cluster_status) return s diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Message.be b/lib/libesp32/berry_matter/src/embedded/Matter_Message.be index c9473d68d..8ca41200b 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Message.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Message.be @@ -59,13 +59,17 @@ class Matter_Frame var sec_extensions # var var app_payload_idx # index where the application payload starts + # for UDP, remote_ip and remote_port to send back to + var remote_ip, remote_port ############################################################# # keep track of the message_handler object # - def init(message_handler, raw) + def init(message_handler, raw, addr, port) self.message_handler = message_handler self.raw = raw + self.remote_ip = addr + self.remote_port = port end ############################################################# @@ -259,6 +263,9 @@ class Matter_Frame # send back response var resp = classof(self)(self.message_handler) + resp.remote_ip = self.remote_ip + resp.remote_port = self.remote_port + if self.flag_s resp.flag_dsiz = 0x01 resp.dest_node_id_8 = self.source_node_id diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_MessageHandler.be b/lib/libesp32/berry_matter/src/embedded/Matter_MessageHandler.be index 1da587803..4da3c5668 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_MessageHandler.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_MessageHandler.be @@ -35,7 +35,7 @@ class Matter_MessageHandler def init(device) self.device = device self.commissioning = matter.Commisioning_Context(self) - self.im = matter.IM(self) + self.im = matter.IM(self, device) self.counter_rcv = matter.Counter() end @@ -49,7 +49,7 @@ class Matter_MessageHandler import string try tasmota.log("MTR: MessageHandler::msg_received raw="+raw.tohex(), 4) - var frame = matter.Frame(self, raw) + var frame = matter.Frame(self, raw, addr, port) var ok = frame.decode_header() if !ok return false end diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin.be index fb3c170de..d66ecbe92 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin.be @@ -23,14 +23,18 @@ #@ solidify:Matter_Plugin,weak class Matter_Plugin - var device - var endpoints + static var EMPTY_LIST = [] + static var EMPTY_MAP = {} + var device # reference to the `device` global object + var endpoints # list of supported endpoints + var clusters # map from cluster to list of attributes ############################################################# # Constructor def init(device) self.device = device - self.endpoints = [] + self.endpoints = self.EMPTY_LIST + self.clusters = self.EMPTY_LIST end ############################################################# @@ -38,10 +42,29 @@ class Matter_Plugin def get_endpoints() return self.endpoints end + def get_cluster_map() + return self.clusters + end + def get_cluster_list(ep) + var ret = [] + for k: self.clusters.keys() + ret.push(k) + end + return ret + end + def get_attribute_list(ep, cluster) + return self.clusters.find(cluster, self.EMPTY_LIST) + end + + ############################################################# + # Does it handle this endpoint and this cluster + def has(cluster, endpoint) + return self.clusters.contains(cluster) && self.endpoints.find(endpoint) != nil + end ############################################################# # read attribute - def read_attribute(msg, endpoint, cluster, attribute) + def read_attribute(msg, ctx) return nil end diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Relay.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Relay.be index 3a923246d..8721cca93 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Relay.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Relay.be @@ -25,18 +25,59 @@ class Matter_Plugin end #@ solidify:Matter_Plugin_Relay,weak class Matter_Plugin_Relay : Matter_Plugin + static var ENDPOINTS = [ 1 ] + static var CLUSTERS = { + 0x001D: [0,1,2,3], + 0x0003: [], + 0x0004: [], + 0x0005: [], + 0x0006: [0], + 0x0008: [], +# 0x0406: [] + } + static var TYPES = [ 0x0100 ] # On/Off Light + ############################################################# # Constructor def init(device) super(self).init(device) - self.endpoints = [ 1 ] + self.endpoints = self.ENDPOINTS + self.clusters = self.CLUSTERS end ############################################################# # read an attribute # - def read_attribute(msg, endpoint, cluster, attribute) - # no match found, return that the attribute is unsupported + def read_attribute(msg, ctx) + import string + var TLV = matter.TLV + var cluster = ctx.cluster + var attribute = ctx.attribute + + if cluster == 0x001D # ========== Descriptor Cluster 9.5 p.453 ========== + + if attribute == 0x0000 # ---------- DeviceTypeList / list[DeviceTypeStruct] ---------- + var dtl = TLV.Matter_TLV_array() + var d1 = dtl.add_struct() + d1.add_TLV(0, TLV.U2, self.TYPES[0]) # DeviceType + d1.add_TLV(1, TLV.U2, 1) # Revision + return dtl + elif attribute == 0x0001 # ---------- ServerList / list[cluster-id] ---------- + var sl = TLV.Matter_TLV_array() + for cl: self.get_cluster_list() + sl.add_TLV(nil, TLV.U4, cl) + end + return sl + elif attribute == 0x0002 # ---------- ClientList / list[cluster-id] ---------- + var cl = TLV.Matter_TLV_array() + cl.add_TLV(nil, TLV.U2, 0x0006) + return cl + elif attribute == 0x0003 # ---------- PartsList / list[endpoint-no]---------- + var pl = TLV.Matter_TLV_array() + return pl + end + end + # no match found, return that the attribute is unsupported end end ############################################################# diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_core.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_core.be index 217c76c23..4c8929cff 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_core.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_core.be @@ -25,19 +25,39 @@ class Matter_Plugin end #@ solidify:Matter_Plugin_core,weak class Matter_Plugin_core : Matter_Plugin + static var ENDPOINTS = [ 0 ] + static var CLUSTERS = { + 0x001D: [0,1,2,3], + 0x0028: [0,1,2,3,4,5,6,7,8,9], + 0x002B: [0,1], + 0x002C: [0,1,2], + 0x0030: [0,1,2,3,4], + 0x0031: [3,0xFFFC], + 0x0032: [], + 0x0033: [0,1,2,8], + 0x0034: [], + 0x0038: [0,1,7], + 0x003E: [0,1,2,3,4,5], + 0x003C: [], + 0x003F: [] + } + ############################################################# # Constructor def init(device) super(self).init(device) - self.endpoints = [ 0 ] + self.endpoints = self.ENDPOINTS + self.clusters = self.CLUSTERS end ############################################################# # read an attribute # - def read_attribute(msg, endpoint, cluster, attribute) + def read_attribute(msg, ctx) import string var TLV = matter.TLV + var cluster = ctx.cluster + var attribute = ctx.attribute if cluster == 0x0030 # ========== GeneralCommissioning cluster 11.9 p.627 ========== @@ -151,11 +171,15 @@ class Matter_Plugin_core : Matter_Plugin elif attribute == 0x0002 # ---------- SupportedFabrics / u1 ---------- return TLV.create_TLV(TLV.U1, 5) # Max 5 fabrics elif attribute == 0x0003 # ---------- CommissionedFabrics / u1 ---------- - return TLV.create_TLV(TLV.U1, 1) # TODO + var sessions_active = self.device.sessions.sessions_active() + return TLV.create_TLV(TLV.U1, size(sessions_active)) # number of active sessions elif attribute == 0x0004 # ---------- TrustedRootCertificates / list[octstr] ---------- # TODO elif attribute == 0x0005 # ---------- Current­ FabricIndex / u1 ---------- - # TODO + var sessions_active = self.device.sessions.sessions_active() + var fabric_index = sessions_active.find(msg.session) + if fabric_index == nil fabric_index = 0 end + return TLV.create_TLV(TLV.U1, fabric_index) # number of active sessions end # ==================================================================================================== @@ -224,6 +248,31 @@ class Matter_Plugin_core : Matter_Plugin elif attribute == 0xFFFC # ---------- FeatureMap / map32 ---------- return TLV.create_TLV(TLV.U4, 0) # 15s ??? TOOD what should we put here? end + + # ==================================================================================================== + elif cluster == 0x001D # ========== Descriptor Cluster 9.5 p.453 ========== + if attribute == 0x0000 # ---------- DeviceTypeList / list[DeviceTypeStruct] ---------- + elif attribute == 0x0001 # ---------- ServerList / list[cluster-id] ---------- + var sl = TLV.Matter_TLV_array() + for cl: self.get_cluster_list() + sl.add_TLV(nil, TLV.U4, cl) + end + return sl + elif attribute == 0x0002 # ---------- ClientList / list[cluster-id] ---------- + var cl = TLV.Matter_TLV_array() + return cl + elif attribute == 0x0003 # ---------- PartsList / list[endpoint-no]---------- + var eps = self.device.get_active_endpoints(true) + var pl = TLV.Matter_TLV_array() + for ep: eps + pl.add_TLV(nil, TLV.U2, ep) # add each endpoint + end + return pl + end + + else + ctx.status = matter.UNSUPPORTED_CLUSTER + end # no match found, return that the attribute is unsupported end diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Session.be b/lib/libesp32/berry_matter/src/embedded/Matter_Session.be index 340dccc4c..1f46e0f32 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Session.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Session.be @@ -82,6 +82,9 @@ class Matter_Session var _persist # do we persist this sessions or is it remporary var expiration # if not `nil` the entry is removed after this timestamp + # below are placeholders for ongoing transactions or chunked responses + var _chunked_attr_reports # if not `nil` holds a container for the current _chuked_attr_reports + # Group Key Derivation static var __GROUP_KEY = "GroupKey v1.0" # starting with double `_` means it's not writable @@ -512,6 +515,20 @@ class Matter_Session_Store return session end + ############################################################# + # find session by resumption id + def find_session_by_resumption_id(resumption_id) + if !resumption_id return nil end + var i = 0 + var sessions = self.sessions + while i < size(sessions) + if sessions[i].resumption_id == resumption_id + return sessions[i] + end + i += 1 + end + end + ############################################################# # list of sessions that are active, i.e. have been # successfully commissioned diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_TLV.be b/lib/libesp32/berry_matter/src/embedded/Matter_TLV.be index 1571af07a..8e927da7c 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_TLV.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_TLV.be @@ -428,6 +428,8 @@ class Matter_TLV # class Matter_TLV_struct var _ end static class Matter_TLV_list : Matter_TLV_item + static var is_struct = false + ################################################################################# def init(parent) super(self).init(parent) @@ -517,8 +519,9 @@ class Matter_TLV end ############################################################# + # encode to bytes def encode(b) - return self._encode_inner(b, false) + return self._encode_inner(b, self.is_struct) end ############################################################# @@ -618,6 +621,8 @@ class Matter_TLV # Matter_TLV_struct class ################################################################################# static class Matter_TLV_struct : Matter_TLV_list + static var is_struct = true + def init(parent) super(self).init(parent) self.typ = self.TLV.STRUCT @@ -628,14 +633,6 @@ class Matter_TLV def tostring() return self.tostring_inner(true, "{", "}") end - - ############################################################# - # encode TLV - # - # appends to the bytes() object - def encode(b) - return self._encode_inner(b, true) - end end ################################################################################# diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Commissioning.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Commissioning.h index 4f922fc06..8888f26c3 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Commissioning.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Commissioning.h @@ -11,15 +11,15 @@ extern const bclass be_class_Matter_Commisioning_Context; ********************************************************************/ be_local_closure(Matter_Commisioning_Context_parse_PBKDFParamRequest, /* name */ be_nested_proto( - 16, /* nstack */ - 4, /* argc */ + 14, /* nstack */ + 2, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[46]) { /* constants */ + ( &(const bvalue[48]) { /* constants */ /* K0 */ be_nested_str_weak(crypto), /* K1 */ be_nested_str_weak(opcode), /* K2 */ be_nested_str_weak(local_session_id), @@ -65,104 +65,106 @@ be_local_closure(Matter_Commisioning_Context_parse_PBKDFParamRequest, /* name /* K42 */ be_nested_str_weak(build_response), /* K43 */ be_nested_str_weak(responder), /* K44 */ be_nested_str_weak(send_response), - /* K45 */ be_nested_str_weak(message_counter), + /* K45 */ be_nested_str_weak(remote_ip), + /* K46 */ be_nested_str_weak(remote_port), + /* K47 */ be_nested_str_weak(message_counter), }), be_str_weak(parse_PBKDFParamRequest), &be_const_str_solidified, ( &(const binstruction[94]) { /* code */ - 0xA4120000, // 0000 IMPORT R4 K0 - 0x88140301, // 0001 GETMBR R5 R1 K1 - 0x541A001F, // 0002 LDINT R6 32 - 0x20140A06, // 0003 NE R5 R5 R6 - 0x74160005, // 0004 JMPT R5 #000B - 0x88140302, // 0005 GETMBR R5 R1 K2 - 0x20140B03, // 0006 NE R5 R5 K3 - 0x74160002, // 0007 JMPT R5 #000B - 0x88140304, // 0008 GETMBR R5 R1 K4 - 0x20140B03, // 0009 NE R5 R5 K3 - 0x78160000, // 000A JMPF R5 #000C + 0xA40A0000, // 0000 IMPORT R2 K0 + 0x880C0301, // 0001 GETMBR R3 R1 K1 + 0x5412001F, // 0002 LDINT R4 32 + 0x200C0604, // 0003 NE R3 R3 R4 + 0x740E0005, // 0004 JMPT R3 #000B + 0x880C0302, // 0005 GETMBR R3 R1 K2 + 0x200C0703, // 0006 NE R3 R3 K3 + 0x740E0002, // 0007 JMPT R3 #000B + 0x880C0304, // 0008 GETMBR R3 R1 K4 + 0x200C0703, // 0009 NE R3 R3 K3 + 0x780E0000, // 000A JMPF R3 #000C 0xB0060B06, // 000B RAISE 1 K5 K6 - 0xB8160E00, // 000C GETNGBL R5 K7 - 0x8C140B08, // 000D GETMET R5 R5 K8 - 0x7C140200, // 000E CALL R5 1 - 0x8C140B09, // 000F GETMET R5 R5 K9 - 0x881C030A, // 0010 GETMBR R7 R1 K10 - 0x8820030B, // 0011 GETMBR R8 R1 K11 - 0x7C140600, // 0012 CALL R5 3 - 0x8818030C, // 0013 GETMBR R6 R1 K12 - 0x8C180D0D, // 0014 GETMET R6 R6 K13 - 0xB8220E00, // 0015 GETNGBL R8 K7 - 0x8820110E, // 0016 GETMBR R8 R8 K14 - 0x8820110F, // 0017 GETMBR R8 R8 K15 - 0x7C180400, // 0018 CALL R6 2 - 0x8818030B, // 0019 GETMBR R6 R1 K11 - 0x40180D10, // 001A CONNECT R6 R6 K16 - 0x881C030A, // 001B GETMBR R7 R1 K10 - 0x94180E06, // 001C GETIDX R6 R7 R6 - 0x90021006, // 001D SETMBR R0 K8 R6 - 0x88180B11, // 001E GETMBR R6 R5 K17 - 0x20180D03, // 001F NE R6 R6 K3 - 0x781A0000, // 0020 JMPF R6 #0022 + 0xB80E0E00, // 000C GETNGBL R3 K7 + 0x8C0C0708, // 000D GETMET R3 R3 K8 + 0x7C0C0200, // 000E CALL R3 1 + 0x8C0C0709, // 000F GETMET R3 R3 K9 + 0x8814030A, // 0010 GETMBR R5 R1 K10 + 0x8818030B, // 0011 GETMBR R6 R1 K11 + 0x7C0C0600, // 0012 CALL R3 3 + 0x8810030C, // 0013 GETMBR R4 R1 K12 + 0x8C10090D, // 0014 GETMET R4 R4 K13 + 0xB81A0E00, // 0015 GETNGBL R6 K7 + 0x88180D0E, // 0016 GETMBR R6 R6 K14 + 0x88180D0F, // 0017 GETMBR R6 R6 K15 + 0x7C100400, // 0018 CALL R4 2 + 0x8810030B, // 0019 GETMBR R4 R1 K11 + 0x40100910, // 001A CONNECT R4 R4 K16 + 0x8814030A, // 001B GETMBR R5 R1 K10 + 0x94100A04, // 001C GETIDX R4 R5 R4 + 0x90021004, // 001D SETMBR R0 K8 R4 + 0x88100711, // 001E GETMBR R4 R3 K17 + 0x20100903, // 001F NE R4 R4 K3 + 0x78120000, // 0020 JMPF R4 #0022 0xB0060B12, // 0021 RAISE 1 K5 K18 - 0x88180B14, // 0022 GETMBR R6 R5 K20 - 0x90022606, // 0023 SETMBR R0 K19 R6 - 0x88180116, // 0024 GETMBR R6 R0 K22 - 0x88180D17, // 0025 GETMBR R6 R6 K23 - 0x8C180D18, // 0026 GETMET R6 R6 K24 - 0x7C180200, // 0027 CALL R6 1 - 0x90022A06, // 0028 SETMBR R0 K21 R6 - 0xB81A0E00, // 0029 GETNGBL R6 K7 - 0x8C180D19, // 002A GETMET R6 R6 K25 - 0x7C180200, // 002B CALL R6 1 - 0x881C0B1A, // 002C GETMBR R7 R5 K26 - 0x901A3407, // 002D SETMBR R6 K26 R7 - 0x8C1C091C, // 002E GETMET R7 R4 K28 - 0x5426001F, // 002F LDINT R9 32 - 0x7C1C0400, // 0030 CALL R7 2 - 0x901A3607, // 0031 SETMBR R6 K27 R7 - 0x881C0115, // 0032 GETMBR R7 R0 K21 - 0x901A3A07, // 0033 SETMBR R6 K29 R7 - 0x881C0116, // 0034 GETMBR R7 R0 K22 - 0x881C0F1F, // 0035 GETMBR R7 R7 K31 - 0x901A3C07, // 0036 SETMBR R6 K30 R7 - 0x881C0116, // 0037 GETMBR R7 R0 K22 - 0x881C0F21, // 0038 GETMBR R7 R7 K33 - 0x901A4007, // 0039 SETMBR R6 K32 R7 - 0xB81E4400, // 003A GETNGBL R7 K34 - 0x8C1C0F23, // 003B GETMET R7 R7 K35 - 0x60240008, // 003C GETGBL R9 G8 - 0xB82A0E00, // 003D GETNGBL R10 K7 - 0x8C281525, // 003E GETMET R10 R10 K37 - 0x5C300C00, // 003F MOVE R12 R6 - 0x7C280400, // 0040 CALL R10 2 - 0x7C240200, // 0041 CALL R9 1 - 0x00264809, // 0042 ADD R9 K36 R9 - 0x58280026, // 0043 LDCONST R10 K38 - 0x7C1C0600, // 0044 CALL R7 3 - 0x8C1C0D27, // 0045 GETMET R7 R6 K39 - 0x7C1C0200, // 0046 CALL R7 1 - 0xB8224400, // 0047 GETNGBL R8 K34 - 0x8C201123, // 0048 GETMET R8 R8 K35 - 0x8C280F29, // 0049 GETMET R10 R7 K41 - 0x7C280200, // 004A CALL R10 1 - 0x002A500A, // 004B ADD R10 K40 R10 - 0x582C0026, // 004C LDCONST R11 K38 - 0x7C200600, // 004D CALL R8 3 - 0x90023207, // 004E SETMBR R0 K25 R7 - 0x8C20032A, // 004F GETMET R8 R1 K42 - 0x542A0020, // 0050 LDINT R10 33 - 0x502C0200, // 0051 LDBOOL R11 1 0 - 0x7C200600, // 0052 CALL R8 3 - 0x8C241127, // 0053 GETMET R9 R8 K39 - 0x5C2C0E00, // 0054 MOVE R11 R7 - 0x7C240400, // 0055 CALL R9 2 - 0x8828012B, // 0056 GETMBR R10 R0 K43 - 0x8C28152C, // 0057 GETMET R10 R10 K44 - 0x5C301200, // 0058 MOVE R12 R9 - 0x5C340400, // 0059 MOVE R13 R2 - 0x5C380600, // 005A MOVE R14 R3 - 0x883C112D, // 005B GETMBR R15 R8 K45 - 0x7C280A00, // 005C CALL R10 5 + 0x88100714, // 0022 GETMBR R4 R3 K20 + 0x90022604, // 0023 SETMBR R0 K19 R4 + 0x88100116, // 0024 GETMBR R4 R0 K22 + 0x88100917, // 0025 GETMBR R4 R4 K23 + 0x8C100918, // 0026 GETMET R4 R4 K24 + 0x7C100200, // 0027 CALL R4 1 + 0x90022A04, // 0028 SETMBR R0 K21 R4 + 0xB8120E00, // 0029 GETNGBL R4 K7 + 0x8C100919, // 002A GETMET R4 R4 K25 + 0x7C100200, // 002B CALL R4 1 + 0x8814071A, // 002C GETMBR R5 R3 K26 + 0x90123405, // 002D SETMBR R4 K26 R5 + 0x8C14051C, // 002E GETMET R5 R2 K28 + 0x541E001F, // 002F LDINT R7 32 + 0x7C140400, // 0030 CALL R5 2 + 0x90123605, // 0031 SETMBR R4 K27 R5 + 0x88140115, // 0032 GETMBR R5 R0 K21 + 0x90123A05, // 0033 SETMBR R4 K29 R5 + 0x88140116, // 0034 GETMBR R5 R0 K22 + 0x88140B1F, // 0035 GETMBR R5 R5 K31 + 0x90123C05, // 0036 SETMBR R4 K30 R5 + 0x88140116, // 0037 GETMBR R5 R0 K22 + 0x88140B21, // 0038 GETMBR R5 R5 K33 + 0x90124005, // 0039 SETMBR R4 K32 R5 + 0xB8164400, // 003A GETNGBL R5 K34 + 0x8C140B23, // 003B GETMET R5 R5 K35 + 0x601C0008, // 003C GETGBL R7 G8 + 0xB8220E00, // 003D GETNGBL R8 K7 + 0x8C201125, // 003E GETMET R8 R8 K37 + 0x5C280800, // 003F MOVE R10 R4 + 0x7C200400, // 0040 CALL R8 2 + 0x7C1C0200, // 0041 CALL R7 1 + 0x001E4807, // 0042 ADD R7 K36 R7 + 0x58200026, // 0043 LDCONST R8 K38 + 0x7C140600, // 0044 CALL R5 3 + 0x8C140927, // 0045 GETMET R5 R4 K39 + 0x7C140200, // 0046 CALL R5 1 + 0xB81A4400, // 0047 GETNGBL R6 K34 + 0x8C180D23, // 0048 GETMET R6 R6 K35 + 0x8C200B29, // 0049 GETMET R8 R5 K41 + 0x7C200200, // 004A CALL R8 1 + 0x00225008, // 004B ADD R8 K40 R8 + 0x58240026, // 004C LDCONST R9 K38 + 0x7C180600, // 004D CALL R6 3 + 0x90023205, // 004E SETMBR R0 K25 R5 + 0x8C18032A, // 004F GETMET R6 R1 K42 + 0x54220020, // 0050 LDINT R8 33 + 0x50240200, // 0051 LDBOOL R9 1 0 + 0x7C180600, // 0052 CALL R6 3 + 0x8C1C0D27, // 0053 GETMET R7 R6 K39 + 0x5C240A00, // 0054 MOVE R9 R5 + 0x7C1C0400, // 0055 CALL R7 2 + 0x8820012B, // 0056 GETMBR R8 R0 K43 + 0x8C20112C, // 0057 GETMET R8 R8 K44 + 0x5C280E00, // 0058 MOVE R10 R7 + 0x882C032D, // 0059 GETMBR R11 R1 K45 + 0x8830032E, // 005A GETMBR R12 R1 K46 + 0x88340D2F, // 005B GETMBR R13 R6 K47 + 0x7C200A00, // 005C CALL R8 5 0x80000000, // 005D RET 0 }) ) @@ -216,15 +218,15 @@ be_local_closure(Matter_Commisioning_Context_init, /* name */ ********************************************************************/ be_local_closure(Matter_Commisioning_Context_parse_Pake1, /* name */ be_nested_proto( - 18, /* nstack */ - 4, /* argc */ + 16, /* nstack */ + 2, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[82]) { /* constants */ + ( &(const bvalue[84]) { /* constants */ /* K0 */ be_nested_str_weak(crypto), /* K1 */ be_nested_str_weak(opcode), /* K2 */ be_nested_str_weak(local_session_id), @@ -306,336 +308,338 @@ be_local_closure(Matter_Commisioning_Context_parse_Pake1, /* name */ /* K78 */ be_nested_str_weak(build_response), /* K79 */ be_nested_str_weak(responder), /* K80 */ be_nested_str_weak(send_response), - /* K81 */ be_nested_str_weak(message_counter), + /* K81 */ be_nested_str_weak(remote_ip), + /* K82 */ be_nested_str_weak(remote_port), + /* K83 */ be_nested_str_weak(message_counter), }), be_str_weak(parse_Pake1), &be_const_str_solidified, ( &(const binstruction[326]) { /* code */ - 0xA4120000, // 0000 IMPORT R4 K0 - 0x88140301, // 0001 GETMBR R5 R1 K1 - 0x541A0021, // 0002 LDINT R6 34 - 0x20140A06, // 0003 NE R5 R5 R6 - 0x74160005, // 0004 JMPT R5 #000B - 0x88140302, // 0005 GETMBR R5 R1 K2 - 0x20140B03, // 0006 NE R5 R5 K3 - 0x74160002, // 0007 JMPT R5 #000B - 0x88140304, // 0008 GETMBR R5 R1 K4 - 0x20140B03, // 0009 NE R5 R5 K3 - 0x78160000, // 000A JMPF R5 #000C + 0xA40A0000, // 0000 IMPORT R2 K0 + 0x880C0301, // 0001 GETMBR R3 R1 K1 + 0x54120021, // 0002 LDINT R4 34 + 0x200C0604, // 0003 NE R3 R3 R4 + 0x740E0005, // 0004 JMPT R3 #000B + 0x880C0302, // 0005 GETMBR R3 R1 K2 + 0x200C0703, // 0006 NE R3 R3 K3 + 0x740E0002, // 0007 JMPT R3 #000B + 0x880C0304, // 0008 GETMBR R3 R1 K4 + 0x200C0703, // 0009 NE R3 R3 K3 + 0x780E0000, // 000A JMPF R3 #000C 0xB0060B06, // 000B RAISE 1 K5 K6 - 0xB8160E00, // 000C GETNGBL R5 K7 - 0x8C140B08, // 000D GETMET R5 R5 K8 - 0x7C140200, // 000E CALL R5 1 - 0x8C140B09, // 000F GETMET R5 R5 K9 - 0x881C030A, // 0010 GETMBR R7 R1 K10 - 0x8820030B, // 0011 GETMBR R8 R1 K11 - 0x7C140600, // 0012 CALL R5 3 - 0x88180B0C, // 0013 GETMBR R6 R5 K12 - 0x90021806, // 0014 SETMBR R0 K12 R6 - 0xB81A1A00, // 0015 GETNGBL R6 K13 - 0x8C180D0E, // 0016 GETMET R6 R6 K14 - 0x8820010C, // 0017 GETMBR R8 R0 K12 - 0x8C201110, // 0018 GETMET R8 R8 K16 - 0x7C200200, // 0019 CALL R8 1 - 0x00221E08, // 001A ADD R8 K15 R8 - 0x58240011, // 001B LDCONST R9 K17 - 0x7C180600, // 001C CALL R6 3 - 0xB81A1A00, // 001D GETNGBL R6 K13 - 0x8C180D0E, // 001E GETMET R6 R6 K14 - 0xB8220E00, // 001F GETNGBL R8 K7 - 0x8C201113, // 0020 GETMET R8 R8 K19 - 0x88280114, // 0021 GETMBR R10 R0 K20 - 0x7C200400, // 0022 CALL R8 2 - 0x00222408, // 0023 ADD R8 K18 R8 - 0x58240011, // 0024 LDCONST R9 K17 - 0x7C180600, // 0025 CALL R6 3 - 0x8C180915, // 0026 GETMET R6 R4 K21 - 0x88200116, // 0027 GETMBR R8 R0 K22 - 0x88201117, // 0028 GETMBR R8 R8 K23 - 0x88240116, // 0029 GETMBR R9 R0 K22 - 0x88241318, // 002A GETMBR R9 R9 K24 - 0x88280116, // 002B GETMBR R10 R0 K22 - 0x88281519, // 002C GETMBR R10 R10 K25 - 0x7C180800, // 002D CALL R6 4 - 0x90022806, // 002E SETMBR R0 K20 R6 - 0x88180114, // 002F GETMBR R6 R0 K20 - 0x8C180D1A, // 0030 GETMET R6 R6 K26 - 0x8820011B, // 0031 GETMBR R8 R0 K27 - 0x7C180400, // 0032 CALL R6 2 - 0x88180114, // 0033 GETMBR R6 R0 K20 - 0x88180D1C, // 0034 GETMBR R6 R6 K28 - 0x90023806, // 0035 SETMBR R0 K28 R6 - 0xB81A1A00, // 0036 GETNGBL R6 K13 - 0x8C180D0E, // 0037 GETMET R6 R6 K14 - 0x8820011B, // 0038 GETMBR R8 R0 K27 - 0x8C201110, // 0039 GETMET R8 R8 K16 - 0x7C200200, // 003A CALL R8 1 - 0x00223A08, // 003B ADD R8 K29 R8 - 0x58240011, // 003C LDCONST R9 K17 - 0x7C180600, // 003D CALL R6 3 - 0xB81A1A00, // 003E GETNGBL R6 K13 - 0x8C180D0E, // 003F GETMET R6 R6 K14 - 0x8820011C, // 0040 GETMBR R8 R0 K28 - 0x8C201110, // 0041 GETMET R8 R8 K16 - 0x7C200200, // 0042 CALL R8 1 - 0x00223C08, // 0043 ADD R8 K30 R8 - 0x58240011, // 0044 LDCONST R9 K17 - 0x7C180600, // 0045 CALL R6 3 - 0x88180114, // 0046 GETMBR R6 R0 K20 - 0x8C180D1F, // 0047 GETMET R6 R6 K31 - 0x8820010C, // 0048 GETMBR R8 R0 K12 - 0x7C180400, // 0049 CALL R6 2 - 0xB81A1A00, // 004A GETNGBL R6 K13 - 0x8C180D0E, // 004B GETMET R6 R6 K14 - 0x88200114, // 004C GETMBR R8 R0 K20 - 0x88201121, // 004D GETMBR R8 R8 K33 - 0x8C201110, // 004E GETMET R8 R8 K16 - 0x7C200200, // 004F CALL R8 1 - 0x00224008, // 0050 ADD R8 K32 R8 - 0x58240011, // 0051 LDCONST R9 K17 - 0x7C180600, // 0052 CALL R6 3 - 0xB81A1A00, // 0053 GETNGBL R6 K13 - 0x8C180D0E, // 0054 GETMET R6 R6 K14 - 0x88200114, // 0055 GETMBR R8 R0 K20 - 0x88201123, // 0056 GETMBR R8 R8 K35 - 0x8C201110, // 0057 GETMET R8 R8 K16 - 0x7C200200, // 0058 CALL R8 1 - 0x00224408, // 0059 ADD R8 K34 R8 - 0x58240011, // 005A LDCONST R9 K17 - 0x7C180600, // 005B CALL R6 3 - 0x8C180924, // 005C GETMET R6 R4 K36 - 0x7C180200, // 005D CALL R6 1 - 0x8C1C0D25, // 005E GETMET R7 R6 K37 - 0x60240015, // 005F GETGBL R9 G21 - 0x7C240000, // 0060 CALL R9 0 - 0x8C241326, // 0061 GETMET R9 R9 K38 - 0x882C0127, // 0062 GETMBR R11 R0 K39 - 0x7C240400, // 0063 CALL R9 2 - 0x7C1C0400, // 0064 CALL R7 2 - 0x8C1C0D25, // 0065 GETMET R7 R6 K37 - 0x88240128, // 0066 GETMBR R9 R0 K40 - 0x7C1C0400, // 0067 CALL R7 2 - 0x8C1C0D25, // 0068 GETMET R7 R6 K37 - 0x88240129, // 0069 GETMBR R9 R0 K41 - 0x7C1C0400, // 006A CALL R7 2 - 0x8C1C0D2A, // 006B GETMET R7 R6 K42 - 0x7C1C0200, // 006C CALL R7 1 - 0xB8221A00, // 006D GETNGBL R8 K13 - 0x8C20110E, // 006E GETMET R8 R8 K14 - 0x8C280F10, // 006F GETMET R10 R7 K16 - 0x7C280200, // 0070 CALL R10 1 - 0x002A560A, // 0071 ADD R10 K43 R10 - 0x582C0011, // 0072 LDCONST R11 K17 - 0x7C200600, // 0073 CALL R8 3 - 0x88200114, // 0074 GETMBR R8 R0 K20 - 0x8824010C, // 0075 GETMBR R9 R0 K12 - 0x90221809, // 0076 SETMBR R8 K12 R9 - 0x88200114, // 0077 GETMBR R8 R0 K20 - 0x8C20112C, // 0078 GETMET R8 R8 K44 - 0x5C280E00, // 0079 MOVE R10 R7 - 0x7C200400, // 007A CALL R8 2 - 0x88200114, // 007B GETMBR R8 R0 K20 - 0x8C20112D, // 007C GETMET R8 R8 K45 - 0x50280200, // 007D LDBOOL R10 1 0 - 0x7C200400, // 007E CALL R8 2 - 0xB8221A00, // 007F GETNGBL R8 K13 - 0x8C20110E, // 0080 GETMET R8 R8 K14 - 0x5828002E, // 0081 LDCONST R10 K46 - 0x582C0011, // 0082 LDCONST R11 K17 - 0x7C200600, // 0083 CALL R8 3 - 0xB8221A00, // 0084 GETNGBL R8 K13 - 0x8C20110E, // 0085 GETMET R8 R8 K14 - 0x88280114, // 0086 GETMBR R10 R0 K20 - 0x88281530, // 0087 GETMBR R10 R10 K48 - 0x8C281510, // 0088 GETMET R10 R10 K16 - 0x7C280200, // 0089 CALL R10 1 - 0x002A5E0A, // 008A ADD R10 K47 R10 - 0x582C0011, // 008B LDCONST R11 K17 - 0x7C200600, // 008C CALL R8 3 - 0xB8221A00, // 008D GETNGBL R8 K13 - 0x8C20110E, // 008E GETMET R8 R8 K14 - 0x88280114, // 008F GETMBR R10 R0 K20 - 0x88281532, // 0090 GETMBR R10 R10 K50 - 0x8C281510, // 0091 GETMET R10 R10 K16 - 0x7C280200, // 0092 CALL R10 1 - 0x002A620A, // 0093 ADD R10 K49 R10 - 0x582C0011, // 0094 LDCONST R11 K17 - 0x7C200600, // 0095 CALL R8 3 - 0xB8221A00, // 0096 GETNGBL R8 K13 - 0x8C20110E, // 0097 GETMET R8 R8 K14 - 0x88280114, // 0098 GETMBR R10 R0 K20 - 0x88281534, // 0099 GETMBR R10 R10 K52 - 0x8C281510, // 009A GETMET R10 R10 K16 - 0x7C280200, // 009B CALL R10 1 - 0x002A660A, // 009C ADD R10 K51 R10 - 0x582C0011, // 009D LDCONST R11 K17 - 0x7C200600, // 009E CALL R8 3 - 0xB8221A00, // 009F GETNGBL R8 K13 - 0x8C20110E, // 00A0 GETMET R8 R8 K14 - 0x88280114, // 00A1 GETMBR R10 R0 K20 - 0x88281536, // 00A2 GETMBR R10 R10 K54 - 0x8C281510, // 00A3 GETMET R10 R10 K16 - 0x7C280200, // 00A4 CALL R10 1 - 0x002A6A0A, // 00A5 ADD R10 K53 R10 - 0x582C0011, // 00A6 LDCONST R11 K17 - 0x7C200600, // 00A7 CALL R8 3 - 0xB8221A00, // 00A8 GETNGBL R8 K13 - 0x8C20110E, // 00A9 GETMET R8 R8 K14 - 0x88280114, // 00AA GETMBR R10 R0 K20 - 0x88281538, // 00AB GETMBR R10 R10 K56 - 0x8C281510, // 00AC GETMET R10 R10 K16 - 0x7C280200, // 00AD CALL R10 1 - 0x002A6E0A, // 00AE ADD R10 K55 R10 - 0x582C0011, // 00AF LDCONST R11 K17 - 0x7C200600, // 00B0 CALL R8 3 - 0xB8221A00, // 00B1 GETNGBL R8 K13 - 0x8C20110E, // 00B2 GETMET R8 R8 K14 - 0x88280114, // 00B3 GETMBR R10 R0 K20 - 0x8828150C, // 00B4 GETMBR R10 R10 K12 - 0x8C281510, // 00B5 GETMET R10 R10 K16 - 0x7C280200, // 00B6 CALL R10 1 - 0x002A720A, // 00B7 ADD R10 K57 R10 - 0x582C0011, // 00B8 LDCONST R11 K17 - 0x7C200600, // 00B9 CALL R8 3 - 0xB8221A00, // 00BA GETNGBL R8 K13 - 0x8C20110E, // 00BB GETMET R8 R8 K14 - 0x88280114, // 00BC GETMBR R10 R0 K20 - 0x8828151C, // 00BD GETMBR R10 R10 K28 - 0x8C281510, // 00BE GETMET R10 R10 K16 - 0x7C280200, // 00BF CALL R10 1 - 0x002A740A, // 00C0 ADD R10 K58 R10 - 0x582C0011, // 00C1 LDCONST R11 K17 - 0x7C200600, // 00C2 CALL R8 3 - 0xB8221A00, // 00C3 GETNGBL R8 K13 - 0x8C20110E, // 00C4 GETMET R8 R8 K14 - 0x88280114, // 00C5 GETMBR R10 R0 K20 - 0x88281521, // 00C6 GETMBR R10 R10 K33 - 0x8C281510, // 00C7 GETMET R10 R10 K16 - 0x7C280200, // 00C8 CALL R10 1 - 0x002A760A, // 00C9 ADD R10 K59 R10 - 0x582C0011, // 00CA LDCONST R11 K17 - 0x7C200600, // 00CB CALL R8 3 - 0xB8221A00, // 00CC GETNGBL R8 K13 - 0x8C20110E, // 00CD GETMET R8 R8 K14 - 0x88280114, // 00CE GETMBR R10 R0 K20 - 0x88281523, // 00CF GETMBR R10 R10 K35 - 0x8C281510, // 00D0 GETMET R10 R10 K16 - 0x7C280200, // 00D1 CALL R10 1 - 0x002A780A, // 00D2 ADD R10 K60 R10 - 0x582C0011, // 00D3 LDCONST R11 K17 - 0x7C200600, // 00D4 CALL R8 3 - 0xB8221A00, // 00D5 GETNGBL R8 K13 - 0x8C20110E, // 00D6 GETMET R8 R8 K14 - 0x88280114, // 00D7 GETMBR R10 R0 K20 - 0x88281517, // 00D8 GETMBR R10 R10 K23 - 0x8C281510, // 00D9 GETMET R10 R10 K16 - 0x7C280200, // 00DA CALL R10 1 - 0x002A7A0A, // 00DB ADD R10 K61 R10 - 0x582C0011, // 00DC LDCONST R11 K17 - 0x7C200600, // 00DD CALL R8 3 - 0xB8221A00, // 00DE GETNGBL R8 K13 - 0x8C20110E, // 00DF GETMET R8 R8 K14 - 0x5828002E, // 00E0 LDCONST R10 K46 - 0x582C0011, // 00E1 LDCONST R11 K17 - 0x7C200600, // 00E2 CALL R8 3 - 0xB8221A00, // 00E3 GETNGBL R8 K13 - 0x8C20110E, // 00E4 GETMET R8 R8 K14 - 0x88280114, // 00E5 GETMBR R10 R0 K20 - 0x8828153F, // 00E6 GETMBR R10 R10 K63 - 0x8C281510, // 00E7 GETMET R10 R10 K16 - 0x7C280200, // 00E8 CALL R10 1 - 0x002A7C0A, // 00E9 ADD R10 K62 R10 - 0x582C0011, // 00EA LDCONST R11 K17 - 0x7C200600, // 00EB CALL R8 3 - 0xB8221A00, // 00EC GETNGBL R8 K13 - 0x8C20110E, // 00ED GETMET R8 R8 K14 - 0x88280114, // 00EE GETMBR R10 R0 K20 - 0x88281541, // 00EF GETMBR R10 R10 K65 - 0x8C281510, // 00F0 GETMET R10 R10 K16 - 0x7C280200, // 00F1 CALL R10 1 - 0x002A800A, // 00F2 ADD R10 K64 R10 - 0x582C0011, // 00F3 LDCONST R11 K17 - 0x7C200600, // 00F4 CALL R8 3 - 0xB8221A00, // 00F5 GETNGBL R8 K13 - 0x8C20110E, // 00F6 GETMET R8 R8 K14 - 0x88280114, // 00F7 GETMBR R10 R0 K20 - 0x88281543, // 00F8 GETMBR R10 R10 K67 - 0x8C281510, // 00F9 GETMET R10 R10 K16 - 0x7C280200, // 00FA CALL R10 1 - 0x002A840A, // 00FB ADD R10 K66 R10 - 0x582C0011, // 00FC LDCONST R11 K17 - 0x7C200600, // 00FD CALL R8 3 - 0xB8221A00, // 00FE GETNGBL R8 K13 - 0x8C20110E, // 00FF GETMET R8 R8 K14 - 0x88280114, // 0100 GETMBR R10 R0 K20 - 0x88281545, // 0101 GETMBR R10 R10 K69 - 0x8C281510, // 0102 GETMET R10 R10 K16 - 0x7C280200, // 0103 CALL R10 1 - 0x002A880A, // 0104 ADD R10 K68 R10 - 0x582C0011, // 0105 LDCONST R11 K17 - 0x7C200600, // 0106 CALL R8 3 - 0xB8221A00, // 0107 GETNGBL R8 K13 - 0x8C20110E, // 0108 GETMET R8 R8 K14 - 0x88280114, // 0109 GETMBR R10 R0 K20 - 0x88281547, // 010A GETMBR R10 R10 K71 - 0x8C281510, // 010B GETMET R10 R10 K16 - 0x7C280200, // 010C CALL R10 1 - 0x002A8C0A, // 010D ADD R10 K70 R10 - 0x582C0011, // 010E LDCONST R11 K17 - 0x7C200600, // 010F CALL R8 3 - 0x88200114, // 0110 GETMBR R8 R0 K20 - 0x88201148, // 0111 GETMBR R8 R8 K72 - 0x90029008, // 0112 SETMBR R0 K72 R8 - 0x88200114, // 0113 GETMBR R8 R0 K20 - 0x88201147, // 0114 GETMBR R8 R8 K71 - 0x90028E08, // 0115 SETMBR R0 K71 R8 - 0xB8221A00, // 0116 GETNGBL R8 K13 - 0x8C20110E, // 0117 GETMET R8 R8 K14 - 0x88280148, // 0118 GETMBR R10 R0 K72 - 0x8C281510, // 0119 GETMET R10 R10 K16 - 0x7C280200, // 011A CALL R10 1 - 0x002A920A, // 011B ADD R10 K73 R10 - 0x582C0011, // 011C LDCONST R11 K17 - 0x7C200600, // 011D CALL R8 3 - 0xB8220E00, // 011E GETNGBL R8 K7 - 0x8C20114A, // 011F GETMET R8 R8 K74 - 0x7C200200, // 0120 CALL R8 1 - 0x8824011C, // 0121 GETMBR R9 R0 K28 - 0x90223809, // 0122 SETMBR R8 K28 R9 - 0x88240148, // 0123 GETMBR R9 R0 K72 - 0x90229009, // 0124 SETMBR R8 K72 R9 - 0xB8261A00, // 0125 GETNGBL R9 K13 - 0x8C24130E, // 0126 GETMET R9 R9 K14 - 0xB82E0E00, // 0127 GETNGBL R11 K7 - 0x8C2C1713, // 0128 GETMET R11 R11 K19 - 0x5C341000, // 0129 MOVE R13 R8 - 0x7C2C0400, // 012A CALL R11 2 - 0x002E960B, // 012B ADD R11 K75 R11 - 0x58300011, // 012C LDCONST R12 K17 - 0x7C240600, // 012D CALL R9 3 - 0x8C24114C, // 012E GETMET R9 R8 K76 - 0x7C240200, // 012F CALL R9 1 - 0xB82A1A00, // 0130 GETNGBL R10 K13 - 0x8C28150E, // 0131 GETMET R10 R10 K14 - 0x8C301310, // 0132 GETMET R12 R9 K16 - 0x7C300200, // 0133 CALL R12 1 - 0x00329A0C, // 0134 ADD R12 K77 R12 - 0x58340011, // 0135 LDCONST R13 K17 - 0x7C280600, // 0136 CALL R10 3 - 0x8C28034E, // 0137 GETMET R10 R1 K78 - 0x54320022, // 0138 LDINT R12 35 - 0x50340200, // 0139 LDBOOL R13 1 0 - 0x7C280600, // 013A CALL R10 3 - 0x8C2C154C, // 013B GETMET R11 R10 K76 - 0x5C341200, // 013C MOVE R13 R9 - 0x7C2C0400, // 013D CALL R11 2 - 0x8830014F, // 013E GETMBR R12 R0 K79 - 0x8C301950, // 013F GETMET R12 R12 K80 - 0x5C381600, // 0140 MOVE R14 R11 - 0x5C3C0400, // 0141 MOVE R15 R2 - 0x5C400600, // 0142 MOVE R16 R3 - 0x88441551, // 0143 GETMBR R17 R10 K81 - 0x7C300A00, // 0144 CALL R12 5 + 0xB80E0E00, // 000C GETNGBL R3 K7 + 0x8C0C0708, // 000D GETMET R3 R3 K8 + 0x7C0C0200, // 000E CALL R3 1 + 0x8C0C0709, // 000F GETMET R3 R3 K9 + 0x8814030A, // 0010 GETMBR R5 R1 K10 + 0x8818030B, // 0011 GETMBR R6 R1 K11 + 0x7C0C0600, // 0012 CALL R3 3 + 0x8810070C, // 0013 GETMBR R4 R3 K12 + 0x90021804, // 0014 SETMBR R0 K12 R4 + 0xB8121A00, // 0015 GETNGBL R4 K13 + 0x8C10090E, // 0016 GETMET R4 R4 K14 + 0x8818010C, // 0017 GETMBR R6 R0 K12 + 0x8C180D10, // 0018 GETMET R6 R6 K16 + 0x7C180200, // 0019 CALL R6 1 + 0x001A1E06, // 001A ADD R6 K15 R6 + 0x581C0011, // 001B LDCONST R7 K17 + 0x7C100600, // 001C CALL R4 3 + 0xB8121A00, // 001D GETNGBL R4 K13 + 0x8C10090E, // 001E GETMET R4 R4 K14 + 0xB81A0E00, // 001F GETNGBL R6 K7 + 0x8C180D13, // 0020 GETMET R6 R6 K19 + 0x88200114, // 0021 GETMBR R8 R0 K20 + 0x7C180400, // 0022 CALL R6 2 + 0x001A2406, // 0023 ADD R6 K18 R6 + 0x581C0011, // 0024 LDCONST R7 K17 + 0x7C100600, // 0025 CALL R4 3 + 0x8C100515, // 0026 GETMET R4 R2 K21 + 0x88180116, // 0027 GETMBR R6 R0 K22 + 0x88180D17, // 0028 GETMBR R6 R6 K23 + 0x881C0116, // 0029 GETMBR R7 R0 K22 + 0x881C0F18, // 002A GETMBR R7 R7 K24 + 0x88200116, // 002B GETMBR R8 R0 K22 + 0x88201119, // 002C GETMBR R8 R8 K25 + 0x7C100800, // 002D CALL R4 4 + 0x90022804, // 002E SETMBR R0 K20 R4 + 0x88100114, // 002F GETMBR R4 R0 K20 + 0x8C10091A, // 0030 GETMET R4 R4 K26 + 0x8818011B, // 0031 GETMBR R6 R0 K27 + 0x7C100400, // 0032 CALL R4 2 + 0x88100114, // 0033 GETMBR R4 R0 K20 + 0x8810091C, // 0034 GETMBR R4 R4 K28 + 0x90023804, // 0035 SETMBR R0 K28 R4 + 0xB8121A00, // 0036 GETNGBL R4 K13 + 0x8C10090E, // 0037 GETMET R4 R4 K14 + 0x8818011B, // 0038 GETMBR R6 R0 K27 + 0x8C180D10, // 0039 GETMET R6 R6 K16 + 0x7C180200, // 003A CALL R6 1 + 0x001A3A06, // 003B ADD R6 K29 R6 + 0x581C0011, // 003C LDCONST R7 K17 + 0x7C100600, // 003D CALL R4 3 + 0xB8121A00, // 003E GETNGBL R4 K13 + 0x8C10090E, // 003F GETMET R4 R4 K14 + 0x8818011C, // 0040 GETMBR R6 R0 K28 + 0x8C180D10, // 0041 GETMET R6 R6 K16 + 0x7C180200, // 0042 CALL R6 1 + 0x001A3C06, // 0043 ADD R6 K30 R6 + 0x581C0011, // 0044 LDCONST R7 K17 + 0x7C100600, // 0045 CALL R4 3 + 0x88100114, // 0046 GETMBR R4 R0 K20 + 0x8C10091F, // 0047 GETMET R4 R4 K31 + 0x8818010C, // 0048 GETMBR R6 R0 K12 + 0x7C100400, // 0049 CALL R4 2 + 0xB8121A00, // 004A GETNGBL R4 K13 + 0x8C10090E, // 004B GETMET R4 R4 K14 + 0x88180114, // 004C GETMBR R6 R0 K20 + 0x88180D21, // 004D GETMBR R6 R6 K33 + 0x8C180D10, // 004E GETMET R6 R6 K16 + 0x7C180200, // 004F CALL R6 1 + 0x001A4006, // 0050 ADD R6 K32 R6 + 0x581C0011, // 0051 LDCONST R7 K17 + 0x7C100600, // 0052 CALL R4 3 + 0xB8121A00, // 0053 GETNGBL R4 K13 + 0x8C10090E, // 0054 GETMET R4 R4 K14 + 0x88180114, // 0055 GETMBR R6 R0 K20 + 0x88180D23, // 0056 GETMBR R6 R6 K35 + 0x8C180D10, // 0057 GETMET R6 R6 K16 + 0x7C180200, // 0058 CALL R6 1 + 0x001A4406, // 0059 ADD R6 K34 R6 + 0x581C0011, // 005A LDCONST R7 K17 + 0x7C100600, // 005B CALL R4 3 + 0x8C100524, // 005C GETMET R4 R2 K36 + 0x7C100200, // 005D CALL R4 1 + 0x8C140925, // 005E GETMET R5 R4 K37 + 0x601C0015, // 005F GETGBL R7 G21 + 0x7C1C0000, // 0060 CALL R7 0 + 0x8C1C0F26, // 0061 GETMET R7 R7 K38 + 0x88240127, // 0062 GETMBR R9 R0 K39 + 0x7C1C0400, // 0063 CALL R7 2 + 0x7C140400, // 0064 CALL R5 2 + 0x8C140925, // 0065 GETMET R5 R4 K37 + 0x881C0128, // 0066 GETMBR R7 R0 K40 + 0x7C140400, // 0067 CALL R5 2 + 0x8C140925, // 0068 GETMET R5 R4 K37 + 0x881C0129, // 0069 GETMBR R7 R0 K41 + 0x7C140400, // 006A CALL R5 2 + 0x8C14092A, // 006B GETMET R5 R4 K42 + 0x7C140200, // 006C CALL R5 1 + 0xB81A1A00, // 006D GETNGBL R6 K13 + 0x8C180D0E, // 006E GETMET R6 R6 K14 + 0x8C200B10, // 006F GETMET R8 R5 K16 + 0x7C200200, // 0070 CALL R8 1 + 0x00225608, // 0071 ADD R8 K43 R8 + 0x58240011, // 0072 LDCONST R9 K17 + 0x7C180600, // 0073 CALL R6 3 + 0x88180114, // 0074 GETMBR R6 R0 K20 + 0x881C010C, // 0075 GETMBR R7 R0 K12 + 0x901A1807, // 0076 SETMBR R6 K12 R7 + 0x88180114, // 0077 GETMBR R6 R0 K20 + 0x8C180D2C, // 0078 GETMET R6 R6 K44 + 0x5C200A00, // 0079 MOVE R8 R5 + 0x7C180400, // 007A CALL R6 2 + 0x88180114, // 007B GETMBR R6 R0 K20 + 0x8C180D2D, // 007C GETMET R6 R6 K45 + 0x50200200, // 007D LDBOOL R8 1 0 + 0x7C180400, // 007E CALL R6 2 + 0xB81A1A00, // 007F GETNGBL R6 K13 + 0x8C180D0E, // 0080 GETMET R6 R6 K14 + 0x5820002E, // 0081 LDCONST R8 K46 + 0x58240011, // 0082 LDCONST R9 K17 + 0x7C180600, // 0083 CALL R6 3 + 0xB81A1A00, // 0084 GETNGBL R6 K13 + 0x8C180D0E, // 0085 GETMET R6 R6 K14 + 0x88200114, // 0086 GETMBR R8 R0 K20 + 0x88201130, // 0087 GETMBR R8 R8 K48 + 0x8C201110, // 0088 GETMET R8 R8 K16 + 0x7C200200, // 0089 CALL R8 1 + 0x00225E08, // 008A ADD R8 K47 R8 + 0x58240011, // 008B LDCONST R9 K17 + 0x7C180600, // 008C CALL R6 3 + 0xB81A1A00, // 008D GETNGBL R6 K13 + 0x8C180D0E, // 008E GETMET R6 R6 K14 + 0x88200114, // 008F GETMBR R8 R0 K20 + 0x88201132, // 0090 GETMBR R8 R8 K50 + 0x8C201110, // 0091 GETMET R8 R8 K16 + 0x7C200200, // 0092 CALL R8 1 + 0x00226208, // 0093 ADD R8 K49 R8 + 0x58240011, // 0094 LDCONST R9 K17 + 0x7C180600, // 0095 CALL R6 3 + 0xB81A1A00, // 0096 GETNGBL R6 K13 + 0x8C180D0E, // 0097 GETMET R6 R6 K14 + 0x88200114, // 0098 GETMBR R8 R0 K20 + 0x88201134, // 0099 GETMBR R8 R8 K52 + 0x8C201110, // 009A GETMET R8 R8 K16 + 0x7C200200, // 009B CALL R8 1 + 0x00226608, // 009C ADD R8 K51 R8 + 0x58240011, // 009D LDCONST R9 K17 + 0x7C180600, // 009E CALL R6 3 + 0xB81A1A00, // 009F GETNGBL R6 K13 + 0x8C180D0E, // 00A0 GETMET R6 R6 K14 + 0x88200114, // 00A1 GETMBR R8 R0 K20 + 0x88201136, // 00A2 GETMBR R8 R8 K54 + 0x8C201110, // 00A3 GETMET R8 R8 K16 + 0x7C200200, // 00A4 CALL R8 1 + 0x00226A08, // 00A5 ADD R8 K53 R8 + 0x58240011, // 00A6 LDCONST R9 K17 + 0x7C180600, // 00A7 CALL R6 3 + 0xB81A1A00, // 00A8 GETNGBL R6 K13 + 0x8C180D0E, // 00A9 GETMET R6 R6 K14 + 0x88200114, // 00AA GETMBR R8 R0 K20 + 0x88201138, // 00AB GETMBR R8 R8 K56 + 0x8C201110, // 00AC GETMET R8 R8 K16 + 0x7C200200, // 00AD CALL R8 1 + 0x00226E08, // 00AE ADD R8 K55 R8 + 0x58240011, // 00AF LDCONST R9 K17 + 0x7C180600, // 00B0 CALL R6 3 + 0xB81A1A00, // 00B1 GETNGBL R6 K13 + 0x8C180D0E, // 00B2 GETMET R6 R6 K14 + 0x88200114, // 00B3 GETMBR R8 R0 K20 + 0x8820110C, // 00B4 GETMBR R8 R8 K12 + 0x8C201110, // 00B5 GETMET R8 R8 K16 + 0x7C200200, // 00B6 CALL R8 1 + 0x00227208, // 00B7 ADD R8 K57 R8 + 0x58240011, // 00B8 LDCONST R9 K17 + 0x7C180600, // 00B9 CALL R6 3 + 0xB81A1A00, // 00BA GETNGBL R6 K13 + 0x8C180D0E, // 00BB GETMET R6 R6 K14 + 0x88200114, // 00BC GETMBR R8 R0 K20 + 0x8820111C, // 00BD GETMBR R8 R8 K28 + 0x8C201110, // 00BE GETMET R8 R8 K16 + 0x7C200200, // 00BF CALL R8 1 + 0x00227408, // 00C0 ADD R8 K58 R8 + 0x58240011, // 00C1 LDCONST R9 K17 + 0x7C180600, // 00C2 CALL R6 3 + 0xB81A1A00, // 00C3 GETNGBL R6 K13 + 0x8C180D0E, // 00C4 GETMET R6 R6 K14 + 0x88200114, // 00C5 GETMBR R8 R0 K20 + 0x88201121, // 00C6 GETMBR R8 R8 K33 + 0x8C201110, // 00C7 GETMET R8 R8 K16 + 0x7C200200, // 00C8 CALL R8 1 + 0x00227608, // 00C9 ADD R8 K59 R8 + 0x58240011, // 00CA LDCONST R9 K17 + 0x7C180600, // 00CB CALL R6 3 + 0xB81A1A00, // 00CC GETNGBL R6 K13 + 0x8C180D0E, // 00CD GETMET R6 R6 K14 + 0x88200114, // 00CE GETMBR R8 R0 K20 + 0x88201123, // 00CF GETMBR R8 R8 K35 + 0x8C201110, // 00D0 GETMET R8 R8 K16 + 0x7C200200, // 00D1 CALL R8 1 + 0x00227808, // 00D2 ADD R8 K60 R8 + 0x58240011, // 00D3 LDCONST R9 K17 + 0x7C180600, // 00D4 CALL R6 3 + 0xB81A1A00, // 00D5 GETNGBL R6 K13 + 0x8C180D0E, // 00D6 GETMET R6 R6 K14 + 0x88200114, // 00D7 GETMBR R8 R0 K20 + 0x88201117, // 00D8 GETMBR R8 R8 K23 + 0x8C201110, // 00D9 GETMET R8 R8 K16 + 0x7C200200, // 00DA CALL R8 1 + 0x00227A08, // 00DB ADD R8 K61 R8 + 0x58240011, // 00DC LDCONST R9 K17 + 0x7C180600, // 00DD CALL R6 3 + 0xB81A1A00, // 00DE GETNGBL R6 K13 + 0x8C180D0E, // 00DF GETMET R6 R6 K14 + 0x5820002E, // 00E0 LDCONST R8 K46 + 0x58240011, // 00E1 LDCONST R9 K17 + 0x7C180600, // 00E2 CALL R6 3 + 0xB81A1A00, // 00E3 GETNGBL R6 K13 + 0x8C180D0E, // 00E4 GETMET R6 R6 K14 + 0x88200114, // 00E5 GETMBR R8 R0 K20 + 0x8820113F, // 00E6 GETMBR R8 R8 K63 + 0x8C201110, // 00E7 GETMET R8 R8 K16 + 0x7C200200, // 00E8 CALL R8 1 + 0x00227C08, // 00E9 ADD R8 K62 R8 + 0x58240011, // 00EA LDCONST R9 K17 + 0x7C180600, // 00EB CALL R6 3 + 0xB81A1A00, // 00EC GETNGBL R6 K13 + 0x8C180D0E, // 00ED GETMET R6 R6 K14 + 0x88200114, // 00EE GETMBR R8 R0 K20 + 0x88201141, // 00EF GETMBR R8 R8 K65 + 0x8C201110, // 00F0 GETMET R8 R8 K16 + 0x7C200200, // 00F1 CALL R8 1 + 0x00228008, // 00F2 ADD R8 K64 R8 + 0x58240011, // 00F3 LDCONST R9 K17 + 0x7C180600, // 00F4 CALL R6 3 + 0xB81A1A00, // 00F5 GETNGBL R6 K13 + 0x8C180D0E, // 00F6 GETMET R6 R6 K14 + 0x88200114, // 00F7 GETMBR R8 R0 K20 + 0x88201143, // 00F8 GETMBR R8 R8 K67 + 0x8C201110, // 00F9 GETMET R8 R8 K16 + 0x7C200200, // 00FA CALL R8 1 + 0x00228408, // 00FB ADD R8 K66 R8 + 0x58240011, // 00FC LDCONST R9 K17 + 0x7C180600, // 00FD CALL R6 3 + 0xB81A1A00, // 00FE GETNGBL R6 K13 + 0x8C180D0E, // 00FF GETMET R6 R6 K14 + 0x88200114, // 0100 GETMBR R8 R0 K20 + 0x88201145, // 0101 GETMBR R8 R8 K69 + 0x8C201110, // 0102 GETMET R8 R8 K16 + 0x7C200200, // 0103 CALL R8 1 + 0x00228808, // 0104 ADD R8 K68 R8 + 0x58240011, // 0105 LDCONST R9 K17 + 0x7C180600, // 0106 CALL R6 3 + 0xB81A1A00, // 0107 GETNGBL R6 K13 + 0x8C180D0E, // 0108 GETMET R6 R6 K14 + 0x88200114, // 0109 GETMBR R8 R0 K20 + 0x88201147, // 010A GETMBR R8 R8 K71 + 0x8C201110, // 010B GETMET R8 R8 K16 + 0x7C200200, // 010C CALL R8 1 + 0x00228C08, // 010D ADD R8 K70 R8 + 0x58240011, // 010E LDCONST R9 K17 + 0x7C180600, // 010F CALL R6 3 + 0x88180114, // 0110 GETMBR R6 R0 K20 + 0x88180D48, // 0111 GETMBR R6 R6 K72 + 0x90029006, // 0112 SETMBR R0 K72 R6 + 0x88180114, // 0113 GETMBR R6 R0 K20 + 0x88180D47, // 0114 GETMBR R6 R6 K71 + 0x90028E06, // 0115 SETMBR R0 K71 R6 + 0xB81A1A00, // 0116 GETNGBL R6 K13 + 0x8C180D0E, // 0117 GETMET R6 R6 K14 + 0x88200148, // 0118 GETMBR R8 R0 K72 + 0x8C201110, // 0119 GETMET R8 R8 K16 + 0x7C200200, // 011A CALL R8 1 + 0x00229208, // 011B ADD R8 K73 R8 + 0x58240011, // 011C LDCONST R9 K17 + 0x7C180600, // 011D CALL R6 3 + 0xB81A0E00, // 011E GETNGBL R6 K7 + 0x8C180D4A, // 011F GETMET R6 R6 K74 + 0x7C180200, // 0120 CALL R6 1 + 0x881C011C, // 0121 GETMBR R7 R0 K28 + 0x901A3807, // 0122 SETMBR R6 K28 R7 + 0x881C0148, // 0123 GETMBR R7 R0 K72 + 0x901A9007, // 0124 SETMBR R6 K72 R7 + 0xB81E1A00, // 0125 GETNGBL R7 K13 + 0x8C1C0F0E, // 0126 GETMET R7 R7 K14 + 0xB8260E00, // 0127 GETNGBL R9 K7 + 0x8C241313, // 0128 GETMET R9 R9 K19 + 0x5C2C0C00, // 0129 MOVE R11 R6 + 0x7C240400, // 012A CALL R9 2 + 0x00269609, // 012B ADD R9 K75 R9 + 0x58280011, // 012C LDCONST R10 K17 + 0x7C1C0600, // 012D CALL R7 3 + 0x8C1C0D4C, // 012E GETMET R7 R6 K76 + 0x7C1C0200, // 012F CALL R7 1 + 0xB8221A00, // 0130 GETNGBL R8 K13 + 0x8C20110E, // 0131 GETMET R8 R8 K14 + 0x8C280F10, // 0132 GETMET R10 R7 K16 + 0x7C280200, // 0133 CALL R10 1 + 0x002A9A0A, // 0134 ADD R10 K77 R10 + 0x582C0011, // 0135 LDCONST R11 K17 + 0x7C200600, // 0136 CALL R8 3 + 0x8C20034E, // 0137 GETMET R8 R1 K78 + 0x542A0022, // 0138 LDINT R10 35 + 0x502C0200, // 0139 LDBOOL R11 1 0 + 0x7C200600, // 013A CALL R8 3 + 0x8C24114C, // 013B GETMET R9 R8 K76 + 0x5C2C0E00, // 013C MOVE R11 R7 + 0x7C240400, // 013D CALL R9 2 + 0x8828014F, // 013E GETMBR R10 R0 K79 + 0x8C281550, // 013F GETMET R10 R10 K80 + 0x5C301200, // 0140 MOVE R12 R9 + 0x88340351, // 0141 GETMBR R13 R1 K81 + 0x88380352, // 0142 GETMBR R14 R1 K82 + 0x883C1153, // 0143 GETMBR R15 R8 K83 + 0x7C280A00, // 0144 CALL R10 5 0x80000000, // 0145 RET 0 }) ) @@ -797,15 +801,15 @@ be_local_closure(Matter_Commisioning_Context_every_second, /* name */ ********************************************************************/ be_local_closure(Matter_Commisioning_Context_parse_Sigma3, /* name */ be_nested_proto( - 40, /* nstack */ - 4, /* argc */ + 38, /* nstack */ + 2, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[92]) { /* constants */ + ( &(const bvalue[94]) { /* constants */ /* K0 */ be_nested_str_weak(crypto), /* K1 */ be_nested_str_weak(opcode), /* K2 */ be_nested_str_weak(local_session_id), @@ -892,461 +896,463 @@ be_local_closure(Matter_Commisioning_Context_parse_Sigma3, /* name */ /* K83 */ be_nested_str_weak(add), /* K84 */ be_nested_str_weak(responder), /* K85 */ be_nested_str_weak(send_response), - /* K86 */ be_nested_str_weak(message_counter), - /* K87 */ be_nested_str_weak(close), - /* K88 */ be_nested_str_weak(set_keys), - /* K89 */ be_nested_str_weak(set_persist), - /* K90 */ be_nested_str_weak(set_no_expiration), - /* K91 */ be_nested_str_weak(save), + /* K86 */ be_nested_str_weak(remote_ip), + /* K87 */ be_nested_str_weak(remote_port), + /* K88 */ be_nested_str_weak(message_counter), + /* K89 */ be_nested_str_weak(close), + /* K90 */ be_nested_str_weak(set_keys), + /* K91 */ be_nested_str_weak(set_persist), + /* K92 */ be_nested_str_weak(set_no_expiration), + /* K93 */ be_nested_str_weak(save), }), be_str_weak(parse_Sigma3), &be_const_str_solidified, ( &(const binstruction[445]) { /* code */ - 0xA4120000, // 0000 IMPORT R4 K0 - 0x88140301, // 0001 GETMBR R5 R1 K1 - 0x541A0031, // 0002 LDINT R6 50 - 0x20140A06, // 0003 NE R5 R5 R6 - 0x74160005, // 0004 JMPT R5 #000B - 0x88140302, // 0005 GETMBR R5 R1 K2 - 0x20140B03, // 0006 NE R5 R5 K3 - 0x74160002, // 0007 JMPT R5 #000B - 0x88140304, // 0008 GETMBR R5 R1 K4 - 0x20140B03, // 0009 NE R5 R5 K3 - 0x78160000, // 000A JMPF R5 #000C + 0xA40A0000, // 0000 IMPORT R2 K0 + 0x880C0301, // 0001 GETMBR R3 R1 K1 + 0x54120031, // 0002 LDINT R4 50 + 0x200C0604, // 0003 NE R3 R3 R4 + 0x740E0005, // 0004 JMPT R3 #000B + 0x880C0302, // 0005 GETMBR R3 R1 K2 + 0x200C0703, // 0006 NE R3 R3 K3 + 0x740E0002, // 0007 JMPT R3 #000B + 0x880C0304, // 0008 GETMBR R3 R1 K4 + 0x200C0703, // 0009 NE R3 R3 K3 + 0x780E0000, // 000A JMPF R3 #000C 0xB0060B06, // 000B RAISE 1 K5 K6 - 0x88140307, // 000C GETMBR R5 R1 K7 - 0xB81A1000, // 000D GETNGBL R6 K8 - 0x8C180D09, // 000E GETMET R6 R6 K9 - 0x7C180200, // 000F CALL R6 1 - 0x8C180D0A, // 0010 GETMET R6 R6 K10 - 0x8820030B, // 0011 GETMBR R8 R1 K11 - 0x8824030C, // 0012 GETMBR R9 R1 K12 - 0x7C180600, // 0013 CALL R6 3 - 0xB81E1A00, // 0014 GETNGBL R7 K13 - 0x8C1C0F0E, // 0015 GETMET R7 R7 K14 - 0x5824000F, // 0016 LDCONST R9 K15 - 0x58280010, // 0017 LDCONST R10 K16 - 0x7C1C0600, // 0018 CALL R7 3 - 0x8C1C0911, // 0019 GETMET R7 R4 K17 - 0x7C1C0200, // 001A CALL R7 1 - 0x8C1C0F12, // 001B GETMET R7 R7 K18 - 0x88240B13, // 001C GETMBR R9 R5 K19 - 0x7C1C0400, // 001D CALL R7 2 - 0x8C1C0F12, // 001E GETMET R7 R7 K18 - 0x88240B14, // 001F GETMBR R9 R5 K20 - 0x7C1C0400, // 0020 CALL R7 2 - 0x8C1C0F15, // 0021 GETMET R7 R7 K21 - 0x7C1C0200, // 0022 CALL R7 1 - 0xB8221A00, // 0023 GETNGBL R8 K13 - 0x8C20110E, // 0024 GETMET R8 R8 K14 - 0x60280008, // 0025 GETGBL R10 G8 - 0x5C2C0A00, // 0026 MOVE R11 R5 - 0x7C280200, // 0027 CALL R10 1 - 0x002A2C0A, // 0028 ADD R10 K22 R10 - 0x582C0010, // 0029 LDCONST R11 K16 - 0x7C200600, // 002A CALL R8 3 - 0xB8221A00, // 002B GETNGBL R8 K13 - 0x8C20110E, // 002C GETMET R8 R8 K14 - 0x60280008, // 002D GETGBL R10 G8 - 0x882C0B18, // 002E GETMBR R11 R5 K24 - 0x7C280200, // 002F CALL R10 1 - 0x002A2E0A, // 0030 ADD R10 K23 R10 - 0x582C0010, // 0031 LDCONST R11 K16 - 0x7C200600, // 0032 CALL R8 3 - 0xB8221A00, // 0033 GETNGBL R8 K13 - 0x8C20110E, // 0034 GETMET R8 R8 K14 - 0x60280008, // 0035 GETGBL R10 G8 - 0x882C0B1A, // 0036 GETMBR R11 R5 K26 - 0x7C280200, // 0037 CALL R10 1 - 0x002A320A, // 0038 ADD R10 K25 R10 - 0x582C0010, // 0039 LDCONST R11 K16 - 0x7C200600, // 003A CALL R8 3 - 0xB8221A00, // 003B GETNGBL R8 K13 - 0x8C20110E, // 003C GETMET R8 R8 K14 - 0x8C280B1C, // 003D GETMET R10 R5 K28 - 0x7C280200, // 003E CALL R10 1 - 0x8C28151D, // 003F GETMET R10 R10 K29 - 0x7C280200, // 0040 CALL R10 1 - 0x002A360A, // 0041 ADD R10 K27 R10 - 0x582C0010, // 0042 LDCONST R11 K16 - 0x7C200600, // 0043 CALL R8 3 - 0xB8221A00, // 0044 GETNGBL R8 K13 - 0x8C20110E, // 0045 GETMET R8 R8 K14 - 0x8C280F1D, // 0046 GETMET R10 R7 K29 - 0x7C280200, // 0047 CALL R10 1 - 0x002A3C0A, // 0048 ADD R10 K30 R10 - 0x582C0010, // 0049 LDCONST R11 K16 - 0x7C200600, // 004A CALL R8 3 - 0x60200015, // 004B GETGBL R8 G21 - 0x7C200000, // 004C CALL R8 0 - 0x8C20111F, // 004D GETMET R8 R8 K31 - 0x88280120, // 004E GETMBR R10 R0 K32 - 0x7C200400, // 004F CALL R8 2 - 0x8C240921, // 0050 GETMET R9 R4 K33 - 0x7C240200, // 0051 CALL R9 1 - 0x8C241322, // 0052 GETMET R9 R9 K34 - 0x882C0B23, // 0053 GETMBR R11 R5 K35 - 0x8C300B1C, // 0054 GETMET R12 R5 K28 - 0x7C300200, // 0055 CALL R12 1 - 0x00301807, // 0056 ADD R12 R12 R7 - 0x5C341000, // 0057 MOVE R13 R8 - 0x543A000F, // 0058 LDINT R14 16 - 0x7C240A00, // 0059 CALL R9 5 - 0xB82A1A00, // 005A GETNGBL R10 K13 - 0x8C28150E, // 005B GETMET R10 R10 K14 - 0x5830000F, // 005C LDCONST R12 K15 - 0x58340010, // 005D LDCONST R13 K16 - 0x7C280600, // 005E CALL R10 3 - 0xB82A1A00, // 005F GETNGBL R10 K13 - 0x8C28150E, // 0060 GETMET R10 R10 K14 - 0x8C300B1C, // 0061 GETMET R12 R5 K28 - 0x7C300200, // 0062 CALL R12 1 - 0x00301807, // 0063 ADD R12 R12 R7 - 0x8C30191D, // 0064 GETMET R12 R12 K29 - 0x7C300200, // 0065 CALL R12 1 - 0x0032480C, // 0066 ADD R12 K36 R12 - 0x58340010, // 0067 LDCONST R13 K16 - 0x7C280600, // 0068 CALL R10 3 - 0xB82A1A00, // 0069 GETNGBL R10 K13 - 0x8C28150E, // 006A GETMET R10 R10 K14 - 0x8C30131D, // 006B GETMET R12 R9 K29 - 0x7C300200, // 006C CALL R12 1 - 0x00324A0C, // 006D ADD R12 K37 R12 - 0x58340010, // 006E LDCONST R13 K16 - 0x7C280600, // 006F CALL R10 3 - 0xB82A1A00, // 0070 GETNGBL R10 K13 - 0x8C28150E, // 0071 GETMET R10 R10 K14 - 0x5830000F, // 0072 LDCONST R12 K15 - 0x58340010, // 0073 LDCONST R13 K16 - 0x7C280600, // 0074 CALL R10 3 - 0x5429FFEE, // 0075 LDINT R10 -17 - 0x402A060A, // 0076 CONNECT R10 K3 R10 - 0x882C0D26, // 0077 GETMBR R11 R6 K38 - 0x9428160A, // 0078 GETIDX R10 R11 R10 - 0x5431FFEF, // 0079 LDINT R12 -16 - 0x40301927, // 007A CONNECT R12 R12 K39 - 0x88340D26, // 007B GETMBR R13 R6 K38 - 0x942C1A0C, // 007C GETIDX R11 R13 R12 - 0x8C380928, // 007D GETMET R14 R4 K40 - 0x5C401200, // 007E MOVE R16 R9 - 0x60440015, // 007F GETGBL R17 G21 - 0x7C440000, // 0080 CALL R17 0 - 0x8C44231F, // 0081 GETMET R17 R17 K31 - 0x884C0129, // 0082 GETMBR R19 R0 K41 - 0x7C440400, // 0083 CALL R17 2 - 0x60480015, // 0084 GETGBL R18 G21 - 0x7C480000, // 0085 CALL R18 0 - 0x604C000C, // 0086 GETGBL R19 G12 - 0x5C501400, // 0087 MOVE R20 R10 - 0x7C4C0200, // 0088 CALL R19 1 - 0x5452000F, // 0089 LDINT R20 16 - 0x7C380C00, // 008A CALL R14 6 - 0x5C301C00, // 008B MOVE R12 R14 - 0x8C38192A, // 008C GETMET R14 R12 K42 - 0x5C401400, // 008D MOVE R16 R10 - 0x7C380400, // 008E CALL R14 2 - 0x5C341C00, // 008F MOVE R13 R14 - 0x8C38192B, // 0090 GETMET R14 R12 K43 - 0x7C380200, // 0091 CALL R14 1 - 0xB83E1A00, // 0092 GETNGBL R15 K13 - 0x8C3C1F0E, // 0093 GETMET R15 R15 K14 - 0x8C441B1D, // 0094 GETMET R17 R13 K29 - 0x7C440200, // 0095 CALL R17 1 - 0x00465811, // 0096 ADD R17 K44 R17 - 0x58480010, // 0097 LDCONST R18 K16 - 0x7C3C0600, // 0098 CALL R15 3 - 0xB83E1A00, // 0099 GETNGBL R15 K13 - 0x8C3C1F0E, // 009A GETMET R15 R15 K14 - 0x8C441D1D, // 009B GETMET R17 R14 K29 - 0x7C440200, // 009C CALL R17 1 - 0x00465A11, // 009D ADD R17 K45 R17 - 0x58480010, // 009E LDCONST R18 K16 - 0x7C3C0600, // 009F CALL R15 3 - 0xB83E1A00, // 00A0 GETNGBL R15 K13 - 0x8C3C1F0E, // 00A1 GETMET R15 R15 K14 - 0x8C44171D, // 00A2 GETMET R17 R11 K29 - 0x7C440200, // 00A3 CALL R17 1 - 0x00465C11, // 00A4 ADD R17 K46 R17 - 0x58480010, // 00A5 LDCONST R18 K16 - 0x7C3C0600, // 00A6 CALL R15 3 - 0xB83E1A00, // 00A7 GETNGBL R15 K13 - 0x8C3C1F0E, // 00A8 GETMET R15 R15 K14 - 0x5844000F, // 00A9 LDCONST R17 K15 - 0x58480010, // 00AA LDCONST R18 K16 - 0x7C3C0600, // 00AB CALL R15 3 - 0x203C1C0B, // 00AC NE R15 R14 R11 - 0x783E0000, // 00AD JMPF R15 #00AF + 0x880C0307, // 000C GETMBR R3 R1 K7 + 0xB8121000, // 000D GETNGBL R4 K8 + 0x8C100909, // 000E GETMET R4 R4 K9 + 0x7C100200, // 000F CALL R4 1 + 0x8C10090A, // 0010 GETMET R4 R4 K10 + 0x8818030B, // 0011 GETMBR R6 R1 K11 + 0x881C030C, // 0012 GETMBR R7 R1 K12 + 0x7C100600, // 0013 CALL R4 3 + 0xB8161A00, // 0014 GETNGBL R5 K13 + 0x8C140B0E, // 0015 GETMET R5 R5 K14 + 0x581C000F, // 0016 LDCONST R7 K15 + 0x58200010, // 0017 LDCONST R8 K16 + 0x7C140600, // 0018 CALL R5 3 + 0x8C140511, // 0019 GETMET R5 R2 K17 + 0x7C140200, // 001A CALL R5 1 + 0x8C140B12, // 001B GETMET R5 R5 K18 + 0x881C0713, // 001C GETMBR R7 R3 K19 + 0x7C140400, // 001D CALL R5 2 + 0x8C140B12, // 001E GETMET R5 R5 K18 + 0x881C0714, // 001F GETMBR R7 R3 K20 + 0x7C140400, // 0020 CALL R5 2 + 0x8C140B15, // 0021 GETMET R5 R5 K21 + 0x7C140200, // 0022 CALL R5 1 + 0xB81A1A00, // 0023 GETNGBL R6 K13 + 0x8C180D0E, // 0024 GETMET R6 R6 K14 + 0x60200008, // 0025 GETGBL R8 G8 + 0x5C240600, // 0026 MOVE R9 R3 + 0x7C200200, // 0027 CALL R8 1 + 0x00222C08, // 0028 ADD R8 K22 R8 + 0x58240010, // 0029 LDCONST R9 K16 + 0x7C180600, // 002A CALL R6 3 + 0xB81A1A00, // 002B GETNGBL R6 K13 + 0x8C180D0E, // 002C GETMET R6 R6 K14 + 0x60200008, // 002D GETGBL R8 G8 + 0x88240718, // 002E GETMBR R9 R3 K24 + 0x7C200200, // 002F CALL R8 1 + 0x00222E08, // 0030 ADD R8 K23 R8 + 0x58240010, // 0031 LDCONST R9 K16 + 0x7C180600, // 0032 CALL R6 3 + 0xB81A1A00, // 0033 GETNGBL R6 K13 + 0x8C180D0E, // 0034 GETMET R6 R6 K14 + 0x60200008, // 0035 GETGBL R8 G8 + 0x8824071A, // 0036 GETMBR R9 R3 K26 + 0x7C200200, // 0037 CALL R8 1 + 0x00223208, // 0038 ADD R8 K25 R8 + 0x58240010, // 0039 LDCONST R9 K16 + 0x7C180600, // 003A CALL R6 3 + 0xB81A1A00, // 003B GETNGBL R6 K13 + 0x8C180D0E, // 003C GETMET R6 R6 K14 + 0x8C20071C, // 003D GETMET R8 R3 K28 + 0x7C200200, // 003E CALL R8 1 + 0x8C20111D, // 003F GETMET R8 R8 K29 + 0x7C200200, // 0040 CALL R8 1 + 0x00223608, // 0041 ADD R8 K27 R8 + 0x58240010, // 0042 LDCONST R9 K16 + 0x7C180600, // 0043 CALL R6 3 + 0xB81A1A00, // 0044 GETNGBL R6 K13 + 0x8C180D0E, // 0045 GETMET R6 R6 K14 + 0x8C200B1D, // 0046 GETMET R8 R5 K29 + 0x7C200200, // 0047 CALL R8 1 + 0x00223C08, // 0048 ADD R8 K30 R8 + 0x58240010, // 0049 LDCONST R9 K16 + 0x7C180600, // 004A CALL R6 3 + 0x60180015, // 004B GETGBL R6 G21 + 0x7C180000, // 004C CALL R6 0 + 0x8C180D1F, // 004D GETMET R6 R6 K31 + 0x88200120, // 004E GETMBR R8 R0 K32 + 0x7C180400, // 004F CALL R6 2 + 0x8C1C0521, // 0050 GETMET R7 R2 K33 + 0x7C1C0200, // 0051 CALL R7 1 + 0x8C1C0F22, // 0052 GETMET R7 R7 K34 + 0x88240723, // 0053 GETMBR R9 R3 K35 + 0x8C28071C, // 0054 GETMET R10 R3 K28 + 0x7C280200, // 0055 CALL R10 1 + 0x00281405, // 0056 ADD R10 R10 R5 + 0x5C2C0C00, // 0057 MOVE R11 R6 + 0x5432000F, // 0058 LDINT R12 16 + 0x7C1C0A00, // 0059 CALL R7 5 + 0xB8221A00, // 005A GETNGBL R8 K13 + 0x8C20110E, // 005B GETMET R8 R8 K14 + 0x5828000F, // 005C LDCONST R10 K15 + 0x582C0010, // 005D LDCONST R11 K16 + 0x7C200600, // 005E CALL R8 3 + 0xB8221A00, // 005F GETNGBL R8 K13 + 0x8C20110E, // 0060 GETMET R8 R8 K14 + 0x8C28071C, // 0061 GETMET R10 R3 K28 + 0x7C280200, // 0062 CALL R10 1 + 0x00281405, // 0063 ADD R10 R10 R5 + 0x8C28151D, // 0064 GETMET R10 R10 K29 + 0x7C280200, // 0065 CALL R10 1 + 0x002A480A, // 0066 ADD R10 K36 R10 + 0x582C0010, // 0067 LDCONST R11 K16 + 0x7C200600, // 0068 CALL R8 3 + 0xB8221A00, // 0069 GETNGBL R8 K13 + 0x8C20110E, // 006A GETMET R8 R8 K14 + 0x8C280F1D, // 006B GETMET R10 R7 K29 + 0x7C280200, // 006C CALL R10 1 + 0x002A4A0A, // 006D ADD R10 K37 R10 + 0x582C0010, // 006E LDCONST R11 K16 + 0x7C200600, // 006F CALL R8 3 + 0xB8221A00, // 0070 GETNGBL R8 K13 + 0x8C20110E, // 0071 GETMET R8 R8 K14 + 0x5828000F, // 0072 LDCONST R10 K15 + 0x582C0010, // 0073 LDCONST R11 K16 + 0x7C200600, // 0074 CALL R8 3 + 0x5421FFEE, // 0075 LDINT R8 -17 + 0x40220608, // 0076 CONNECT R8 K3 R8 + 0x88240926, // 0077 GETMBR R9 R4 K38 + 0x94201208, // 0078 GETIDX R8 R9 R8 + 0x5429FFEF, // 0079 LDINT R10 -16 + 0x40281527, // 007A CONNECT R10 R10 K39 + 0x882C0926, // 007B GETMBR R11 R4 K38 + 0x9424160A, // 007C GETIDX R9 R11 R10 + 0x8C300528, // 007D GETMET R12 R2 K40 + 0x5C380E00, // 007E MOVE R14 R7 + 0x603C0015, // 007F GETGBL R15 G21 + 0x7C3C0000, // 0080 CALL R15 0 + 0x8C3C1F1F, // 0081 GETMET R15 R15 K31 + 0x88440129, // 0082 GETMBR R17 R0 K41 + 0x7C3C0400, // 0083 CALL R15 2 + 0x60400015, // 0084 GETGBL R16 G21 + 0x7C400000, // 0085 CALL R16 0 + 0x6044000C, // 0086 GETGBL R17 G12 + 0x5C481000, // 0087 MOVE R18 R8 + 0x7C440200, // 0088 CALL R17 1 + 0x544A000F, // 0089 LDINT R18 16 + 0x7C300C00, // 008A CALL R12 6 + 0x5C281800, // 008B MOVE R10 R12 + 0x8C30152A, // 008C GETMET R12 R10 K42 + 0x5C381000, // 008D MOVE R14 R8 + 0x7C300400, // 008E CALL R12 2 + 0x5C2C1800, // 008F MOVE R11 R12 + 0x8C30152B, // 0090 GETMET R12 R10 K43 + 0x7C300200, // 0091 CALL R12 1 + 0xB8361A00, // 0092 GETNGBL R13 K13 + 0x8C341B0E, // 0093 GETMET R13 R13 K14 + 0x8C3C171D, // 0094 GETMET R15 R11 K29 + 0x7C3C0200, // 0095 CALL R15 1 + 0x003E580F, // 0096 ADD R15 K44 R15 + 0x58400010, // 0097 LDCONST R16 K16 + 0x7C340600, // 0098 CALL R13 3 + 0xB8361A00, // 0099 GETNGBL R13 K13 + 0x8C341B0E, // 009A GETMET R13 R13 K14 + 0x8C3C191D, // 009B GETMET R15 R12 K29 + 0x7C3C0200, // 009C CALL R15 1 + 0x003E5A0F, // 009D ADD R15 K45 R15 + 0x58400010, // 009E LDCONST R16 K16 + 0x7C340600, // 009F CALL R13 3 + 0xB8361A00, // 00A0 GETNGBL R13 K13 + 0x8C341B0E, // 00A1 GETMET R13 R13 K14 + 0x8C3C131D, // 00A2 GETMET R15 R9 K29 + 0x7C3C0200, // 00A3 CALL R15 1 + 0x003E5C0F, // 00A4 ADD R15 K46 R15 + 0x58400010, // 00A5 LDCONST R16 K16 + 0x7C340600, // 00A6 CALL R13 3 + 0xB8361A00, // 00A7 GETNGBL R13 K13 + 0x8C341B0E, // 00A8 GETMET R13 R13 K14 + 0x583C000F, // 00A9 LDCONST R15 K15 + 0x58400010, // 00AA LDCONST R16 K16 + 0x7C340600, // 00AB CALL R13 3 + 0x20341809, // 00AC NE R13 R12 R9 + 0x78360000, // 00AD JMPF R13 #00AF 0xB0065F30, // 00AE RAISE 1 K47 K48 - 0xB83E1000, // 00AF GETNGBL R15 K8 - 0x883C1F31, // 00B0 GETMBR R15 R15 K49 - 0x8C3C1F0A, // 00B1 GETMET R15 R15 K10 - 0x5C441A00, // 00B2 MOVE R17 R13 - 0x7C3C0400, // 00B3 CALL R15 2 - 0x8C401F32, // 00B4 GETMET R16 R15 K50 - 0x58480033, // 00B5 LDCONST R18 K51 - 0x7C400400, // 00B6 CALL R16 2 - 0x8C441F32, // 00B7 GETMET R17 R15 K50 - 0x584C0034, // 00B8 LDCONST R19 K52 - 0x7C440400, // 00B9 CALL R17 2 - 0x8C481F32, // 00BA GETMET R18 R15 K50 - 0x58500010, // 00BB LDCONST R20 K16 - 0x7C480400, // 00BC CALL R18 2 - 0xB84E1000, // 00BD GETNGBL R19 K8 - 0x884C2731, // 00BE GETMBR R19 R19 K49 - 0x8C4C270A, // 00BF GETMET R19 R19 K10 - 0x5C542000, // 00C0 MOVE R21 R16 - 0x7C4C0400, // 00C1 CALL R19 2 - 0xB8521A00, // 00C2 GETNGBL R20 K13 - 0x8C50290E, // 00C3 GETMET R20 R20 K14 - 0x60580008, // 00C4 GETGBL R22 G8 - 0x5C5C2600, // 00C5 MOVE R23 R19 - 0x7C580200, // 00C6 CALL R22 1 - 0x005A6A16, // 00C7 ADD R22 K53 R22 - 0x585C0010, // 00C8 LDCONST R23 K16 - 0x7C500600, // 00C9 CALL R20 3 - 0x8C502732, // 00CA GETMET R20 R19 K50 - 0x545A0008, // 00CB LDINT R22 9 - 0x7C500400, // 00CC CALL R20 2 - 0x8C542736, // 00CD GETMET R21 R19 K54 - 0x545E0005, // 00CE LDINT R23 6 - 0x7C540400, // 00CF CALL R21 2 - 0x8C582B32, // 00D0 GETMET R22 R21 K50 - 0x54620010, // 00D1 LDINT R24 17 - 0x7C580400, // 00D2 CALL R22 2 - 0x605C0004, // 00D3 GETGBL R23 G4 - 0x5C602C00, // 00D4 MOVE R24 R22 - 0x7C5C0200, // 00D5 CALL R23 1 - 0x1C5C2F37, // 00D6 EQ R23 R23 K55 - 0x785E0003, // 00D7 JMPF R23 #00DC - 0xB85E7000, // 00D8 GETNGBL R23 K56 - 0x5C602C00, // 00D9 MOVE R24 R22 - 0x7C5C0200, // 00DA CALL R23 1 - 0x5C582E00, // 00DB MOVE R22 R23 - 0x8C5C2D3A, // 00DC GETMET R23 R22 K58 - 0x7C5C0200, // 00DD CALL R23 1 - 0x90167217, // 00DE SETMBR R5 K57 R23 - 0xB85E1A00, // 00DF GETNGBL R23 K13 - 0x8C5C2F0E, // 00E0 GETMET R23 R23 K14 - 0x60640008, // 00E1 GETGBL R25 G8 - 0x88680B39, // 00E2 GETMBR R26 R5 K57 - 0x7C640200, // 00E3 CALL R25 1 - 0x00667619, // 00E4 ADD R25 K59 R25 - 0x58680010, // 00E5 LDCONST R26 K16 - 0x7C5C0600, // 00E6 CALL R23 3 - 0xB85E1000, // 00E7 GETNGBL R23 K8 - 0x885C2F31, // 00E8 GETMBR R23 R23 K49 - 0x8C5C2F3C, // 00E9 GETMET R23 R23 K60 - 0x7C5C0200, // 00EA CALL R23 1 - 0x8C602F3D, // 00EB GETMET R24 R23 K61 - 0x58680033, // 00EC LDCONST R26 K51 - 0xB86E1000, // 00ED GETNGBL R27 K8 - 0x886C3731, // 00EE GETMBR R27 R27 K49 - 0x886C373E, // 00EF GETMBR R27 R27 K62 - 0x5C702000, // 00F0 MOVE R28 R16 - 0x7C600800, // 00F1 CALL R24 4 - 0x8C602F3D, // 00F2 GETMET R24 R23 K61 - 0x58680034, // 00F3 LDCONST R26 K52 - 0xB86E1000, // 00F4 GETNGBL R27 K8 - 0x886C3731, // 00F5 GETMBR R27 R27 K49 - 0x886C373E, // 00F6 GETMBR R27 R27 K62 - 0x5C702200, // 00F7 MOVE R28 R17 - 0x7C600800, // 00F8 CALL R24 4 - 0x8C602F3D, // 00F9 GETMET R24 R23 K61 - 0x58680010, // 00FA LDCONST R26 K16 - 0xB86E1000, // 00FB GETNGBL R27 K8 - 0x886C3731, // 00FC GETMBR R27 R27 K49 - 0x886C373E, // 00FD GETMBR R27 R27 K62 - 0x8870013F, // 00FE GETMBR R28 R0 K63 - 0x7C600800, // 00FF CALL R24 4 - 0x8C602F3D, // 0100 GETMET R24 R23 K61 - 0x546A0003, // 0101 LDINT R26 4 - 0xB86E1000, // 0102 GETNGBL R27 K8 - 0x886C3731, // 0103 GETMBR R27 R27 K49 - 0x886C373E, // 0104 GETMBR R27 R27 K62 - 0x88700140, // 0105 GETMBR R28 R0 K64 - 0x7C600800, // 0106 CALL R24 4 - 0x8C602F41, // 0107 GETMET R24 R23 K65 - 0x7C600200, // 0108 CALL R24 1 - 0xB8661A00, // 0109 GETNGBL R25 K13 - 0x8C64330E, // 010A GETMET R25 R25 K14 - 0x8C6C291D, // 010B GETMET R27 R20 K29 - 0x7C6C0200, // 010C CALL R27 1 - 0x006E841B, // 010D ADD R27 K66 R27 - 0x58700010, // 010E LDCONST R28 K16 - 0x7C640600, // 010F CALL R25 3 - 0xB8661A00, // 0110 GETNGBL R25 K13 - 0x8C64330E, // 0111 GETMET R25 R25 K14 - 0x8C6C251D, // 0112 GETMET R27 R18 K29 - 0x7C6C0200, // 0113 CALL R27 1 - 0x006E861B, // 0114 ADD R27 K67 R27 - 0x58700010, // 0115 LDCONST R28 K16 - 0x7C640600, // 0116 CALL R25 3 - 0xB8661A00, // 0117 GETNGBL R25 K13 - 0x8C64330E, // 0118 GETMET R25 R25 K14 - 0x586C000F, // 0119 LDCONST R27 K15 - 0x58700010, // 011A LDCONST R28 K16 - 0x7C640600, // 011B CALL R25 3 - 0x8C640944, // 011C GETMET R25 R4 K68 - 0x7C640200, // 011D CALL R25 1 - 0x8C643345, // 011E GETMET R25 R25 K69 - 0x5C6C2800, // 011F MOVE R27 R20 - 0x5C703000, // 0120 MOVE R28 R24 - 0x5C742400, // 0121 MOVE R29 R18 - 0x7C640800, // 0122 CALL R25 4 - 0x5C683200, // 0123 MOVE R26 R25 - 0x746A0000, // 0124 JMPT R26 #0126 + 0xB8361000, // 00AF GETNGBL R13 K8 + 0x88341B31, // 00B0 GETMBR R13 R13 K49 + 0x8C341B0A, // 00B1 GETMET R13 R13 K10 + 0x5C3C1600, // 00B2 MOVE R15 R11 + 0x7C340400, // 00B3 CALL R13 2 + 0x8C381B32, // 00B4 GETMET R14 R13 K50 + 0x58400033, // 00B5 LDCONST R16 K51 + 0x7C380400, // 00B6 CALL R14 2 + 0x8C3C1B32, // 00B7 GETMET R15 R13 K50 + 0x58440034, // 00B8 LDCONST R17 K52 + 0x7C3C0400, // 00B9 CALL R15 2 + 0x8C401B32, // 00BA GETMET R16 R13 K50 + 0x58480010, // 00BB LDCONST R18 K16 + 0x7C400400, // 00BC CALL R16 2 + 0xB8461000, // 00BD GETNGBL R17 K8 + 0x88442331, // 00BE GETMBR R17 R17 K49 + 0x8C44230A, // 00BF GETMET R17 R17 K10 + 0x5C4C1C00, // 00C0 MOVE R19 R14 + 0x7C440400, // 00C1 CALL R17 2 + 0xB84A1A00, // 00C2 GETNGBL R18 K13 + 0x8C48250E, // 00C3 GETMET R18 R18 K14 + 0x60500008, // 00C4 GETGBL R20 G8 + 0x5C542200, // 00C5 MOVE R21 R17 + 0x7C500200, // 00C6 CALL R20 1 + 0x00526A14, // 00C7 ADD R20 K53 R20 + 0x58540010, // 00C8 LDCONST R21 K16 + 0x7C480600, // 00C9 CALL R18 3 + 0x8C482332, // 00CA GETMET R18 R17 K50 + 0x54520008, // 00CB LDINT R20 9 + 0x7C480400, // 00CC CALL R18 2 + 0x8C4C2336, // 00CD GETMET R19 R17 K54 + 0x54560005, // 00CE LDINT R21 6 + 0x7C4C0400, // 00CF CALL R19 2 + 0x8C502732, // 00D0 GETMET R20 R19 K50 + 0x545A0010, // 00D1 LDINT R22 17 + 0x7C500400, // 00D2 CALL R20 2 + 0x60540004, // 00D3 GETGBL R21 G4 + 0x5C582800, // 00D4 MOVE R22 R20 + 0x7C540200, // 00D5 CALL R21 1 + 0x1C542B37, // 00D6 EQ R21 R21 K55 + 0x78560003, // 00D7 JMPF R21 #00DC + 0xB8567000, // 00D8 GETNGBL R21 K56 + 0x5C582800, // 00D9 MOVE R22 R20 + 0x7C540200, // 00DA CALL R21 1 + 0x5C502A00, // 00DB MOVE R20 R21 + 0x8C54293A, // 00DC GETMET R21 R20 K58 + 0x7C540200, // 00DD CALL R21 1 + 0x900E7215, // 00DE SETMBR R3 K57 R21 + 0xB8561A00, // 00DF GETNGBL R21 K13 + 0x8C542B0E, // 00E0 GETMET R21 R21 K14 + 0x605C0008, // 00E1 GETGBL R23 G8 + 0x88600739, // 00E2 GETMBR R24 R3 K57 + 0x7C5C0200, // 00E3 CALL R23 1 + 0x005E7617, // 00E4 ADD R23 K59 R23 + 0x58600010, // 00E5 LDCONST R24 K16 + 0x7C540600, // 00E6 CALL R21 3 + 0xB8561000, // 00E7 GETNGBL R21 K8 + 0x88542B31, // 00E8 GETMBR R21 R21 K49 + 0x8C542B3C, // 00E9 GETMET R21 R21 K60 + 0x7C540200, // 00EA CALL R21 1 + 0x8C582B3D, // 00EB GETMET R22 R21 K61 + 0x58600033, // 00EC LDCONST R24 K51 + 0xB8661000, // 00ED GETNGBL R25 K8 + 0x88643331, // 00EE GETMBR R25 R25 K49 + 0x8864333E, // 00EF GETMBR R25 R25 K62 + 0x5C681C00, // 00F0 MOVE R26 R14 + 0x7C580800, // 00F1 CALL R22 4 + 0x8C582B3D, // 00F2 GETMET R22 R21 K61 + 0x58600034, // 00F3 LDCONST R24 K52 + 0xB8661000, // 00F4 GETNGBL R25 K8 + 0x88643331, // 00F5 GETMBR R25 R25 K49 + 0x8864333E, // 00F6 GETMBR R25 R25 K62 + 0x5C681E00, // 00F7 MOVE R26 R15 + 0x7C580800, // 00F8 CALL R22 4 + 0x8C582B3D, // 00F9 GETMET R22 R21 K61 + 0x58600010, // 00FA LDCONST R24 K16 + 0xB8661000, // 00FB GETNGBL R25 K8 + 0x88643331, // 00FC GETMBR R25 R25 K49 + 0x8864333E, // 00FD GETMBR R25 R25 K62 + 0x8868013F, // 00FE GETMBR R26 R0 K63 + 0x7C580800, // 00FF CALL R22 4 + 0x8C582B3D, // 0100 GETMET R22 R21 K61 + 0x54620003, // 0101 LDINT R24 4 + 0xB8661000, // 0102 GETNGBL R25 K8 + 0x88643331, // 0103 GETMBR R25 R25 K49 + 0x8864333E, // 0104 GETMBR R25 R25 K62 + 0x88680140, // 0105 GETMBR R26 R0 K64 + 0x7C580800, // 0106 CALL R22 4 + 0x8C582B41, // 0107 GETMET R22 R21 K65 + 0x7C580200, // 0108 CALL R22 1 + 0xB85E1A00, // 0109 GETNGBL R23 K13 + 0x8C5C2F0E, // 010A GETMET R23 R23 K14 + 0x8C64251D, // 010B GETMET R25 R18 K29 + 0x7C640200, // 010C CALL R25 1 + 0x00668419, // 010D ADD R25 K66 R25 + 0x58680010, // 010E LDCONST R26 K16 + 0x7C5C0600, // 010F CALL R23 3 + 0xB85E1A00, // 0110 GETNGBL R23 K13 + 0x8C5C2F0E, // 0111 GETMET R23 R23 K14 + 0x8C64211D, // 0112 GETMET R25 R16 K29 + 0x7C640200, // 0113 CALL R25 1 + 0x00668619, // 0114 ADD R25 K67 R25 + 0x58680010, // 0115 LDCONST R26 K16 + 0x7C5C0600, // 0116 CALL R23 3 + 0xB85E1A00, // 0117 GETNGBL R23 K13 + 0x8C5C2F0E, // 0118 GETMET R23 R23 K14 + 0x5864000F, // 0119 LDCONST R25 K15 + 0x58680010, // 011A LDCONST R26 K16 + 0x7C5C0600, // 011B CALL R23 3 + 0x8C5C0544, // 011C GETMET R23 R2 K68 + 0x7C5C0200, // 011D CALL R23 1 + 0x8C5C2F45, // 011E GETMET R23 R23 K69 + 0x5C642400, // 011F MOVE R25 R18 + 0x5C682C00, // 0120 MOVE R26 R22 + 0x5C6C2000, // 0121 MOVE R27 R16 + 0x7C5C0800, // 0122 CALL R23 4 + 0x5C602E00, // 0123 MOVE R24 R23 + 0x74620000, // 0124 JMPT R24 #0126 0xB0065F46, // 0125 RAISE 1 K47 K70 - 0xB86A1A00, // 0126 GETNGBL R26 K13 - 0x8C68350E, // 0127 GETMET R26 R26 K14 - 0x58700047, // 0128 LDCONST R28 K71 - 0x58740010, // 0129 LDCONST R29 K16 - 0x7C680600, // 012A CALL R26 3 - 0x8C680911, // 012B GETMET R26 R4 K17 - 0x7C680200, // 012C CALL R26 1 - 0x8C683512, // 012D GETMET R26 R26 K18 - 0x88700B13, // 012E GETMBR R28 R5 K19 - 0x7C680400, // 012F CALL R26 2 - 0x8C683512, // 0130 GETMET R26 R26 K18 - 0x88700B14, // 0131 GETMBR R28 R5 K20 - 0x7C680400, // 0132 CALL R26 2 - 0x8C683512, // 0133 GETMET R26 R26 K18 - 0x88700D48, // 0134 GETMBR R28 R6 K72 - 0x7C680400, // 0135 CALL R26 2 - 0x8C683515, // 0136 GETMET R26 R26 K21 - 0x7C680200, // 0137 CALL R26 1 - 0x5C1C3400, // 0138 MOVE R7 R26 - 0x4C680000, // 0139 LDNIL R26 - 0x9016261A, // 013A SETMBR R5 K19 R26 - 0x4C680000, // 013B LDNIL R26 - 0x9016281A, // 013C SETMBR R5 K20 R26 - 0xB86A1A00, // 013D GETNGBL R26 K13 - 0x8C68350E, // 013E GETMET R26 R26 K14 - 0x58700049, // 013F LDCONST R28 K73 - 0x58740010, // 0140 LDCONST R29 K16 - 0x7C680600, // 0141 CALL R26 3 - 0xB86A1A00, // 0142 GETNGBL R26 K13 - 0x8C68350E, // 0143 GETMET R26 R26 K14 - 0x88700B23, // 0144 GETMBR R28 R5 K35 - 0x8C70391D, // 0145 GETMET R28 R28 K29 - 0x7C700200, // 0146 CALL R28 1 - 0x0072941C, // 0147 ADD R28 K74 R28 - 0x58740010, // 0148 LDCONST R29 K16 - 0x7C680600, // 0149 CALL R26 3 - 0xB86A1A00, // 014A GETNGBL R26 K13 - 0x8C68350E, // 014B GETMET R26 R26 K14 - 0x8C700B1C, // 014C GETMET R28 R5 K28 - 0x7C700200, // 014D CALL R28 1 - 0x00703807, // 014E ADD R28 R28 R7 - 0x8C70391D, // 014F GETMET R28 R28 K29 - 0x7C700200, // 0150 CALL R28 1 - 0x0072961C, // 0151 ADD R28 K75 R28 - 0x58740010, // 0152 LDCONST R29 K16 - 0x7C680600, // 0153 CALL R26 3 - 0x8C680921, // 0154 GETMET R26 R4 K33 - 0x7C680200, // 0155 CALL R26 1 - 0x8C683522, // 0156 GETMET R26 R26 K34 - 0x88700B23, // 0157 GETMBR R28 R5 K35 - 0x8C740B1C, // 0158 GETMET R29 R5 K28 - 0x7C740200, // 0159 CALL R29 1 - 0x00743A07, // 015A ADD R29 R29 R7 - 0x60780015, // 015B GETGBL R30 G21 - 0x7C780000, // 015C CALL R30 0 - 0x8C783D1F, // 015D GETMET R30 R30 K31 - 0x8880014C, // 015E GETMBR R32 R0 K76 - 0x7C780400, // 015F CALL R30 2 - 0x547E002F, // 0160 LDINT R31 48 - 0x7C680A00, // 0161 CALL R26 5 - 0x546E000E, // 0162 LDINT R27 15 - 0x406E061B, // 0163 CONNECT R27 K3 R27 - 0x946C341B, // 0164 GETIDX R27 R26 R27 - 0x5472000F, // 0165 LDINT R28 16 - 0x5476001E, // 0166 LDINT R29 31 - 0x4070381D, // 0167 CONNECT R28 R28 R29 - 0x9470341C, // 0168 GETIDX R28 R26 R28 - 0x5476001F, // 0169 LDINT R29 32 - 0x547A002E, // 016A LDINT R30 47 - 0x40743A1E, // 016B CONNECT R29 R29 R30 - 0x9474341D, // 016C GETIDX R29 R26 R29 - 0xB87A1A00, // 016D GETNGBL R30 K13 - 0x8C783D4D, // 016E GETMET R30 R30 K77 - 0x7C780200, // 016F CALL R30 1 - 0x94783D4E, // 0170 GETIDX R30 R30 K78 - 0xB87E1A00, // 0171 GETNGBL R31 K13 - 0x8C7C3F0E, // 0172 GETMET R31 R31 K14 - 0x58840049, // 0173 LDCONST R33 K73 - 0x58880010, // 0174 LDCONST R34 K16 - 0x7C7C0600, // 0175 CALL R31 3 - 0xB87E1A00, // 0176 GETNGBL R31 K13 - 0x8C7C3F0E, // 0177 GETMET R31 R31 K14 - 0x8C84371D, // 0178 GETMET R33 R27 K29 - 0x7C840200, // 0179 CALL R33 1 - 0x00869E21, // 017A ADD R33 K79 R33 - 0x58880010, // 017B LDCONST R34 K16 - 0x7C7C0600, // 017C CALL R31 3 - 0xB87E1A00, // 017D GETNGBL R31 K13 - 0x8C7C3F0E, // 017E GETMET R31 R31 K14 - 0x8C84391D, // 017F GETMET R33 R28 K29 - 0x7C840200, // 0180 CALL R33 1 - 0x0086A021, // 0181 ADD R33 K80 R33 - 0x58880010, // 0182 LDCONST R34 K16 - 0x7C7C0600, // 0183 CALL R31 3 - 0xB87E1A00, // 0184 GETNGBL R31 K13 - 0x8C7C3F0E, // 0185 GETMET R31 R31 K14 - 0x8C843B1D, // 0186 GETMET R33 R29 K29 - 0x7C840200, // 0187 CALL R33 1 - 0x0086A221, // 0188 ADD R33 K81 R33 - 0x58880010, // 0189 LDCONST R34 K16 - 0x7C7C0600, // 018A CALL R31 3 - 0xB87E1A00, // 018B GETNGBL R31 K13 - 0x8C7C3F0E, // 018C GETMET R31 R31 K14 - 0x58840049, // 018D LDCONST R33 K73 - 0x58880010, // 018E LDCONST R34 K16 - 0x7C7C0600, // 018F CALL R31 3 - 0x8C7C0352, // 0190 GETMET R31 R1 K82 - 0x5486003F, // 0191 LDINT R33 64 - 0x50880200, // 0192 LDBOOL R34 1 0 - 0x7C7C0600, // 0193 CALL R31 3 - 0x60800015, // 0194 GETGBL R32 G21 - 0x7C800000, // 0195 CALL R32 0 - 0x8C844153, // 0196 GETMET R33 R32 K83 - 0x588C0003, // 0197 LDCONST R35 K3 - 0x58900034, // 0198 LDCONST R36 K52 - 0x7C840600, // 0199 CALL R33 3 - 0x8C844153, // 019A GETMET R33 R32 K83 - 0x588C0003, // 019B LDCONST R35 K3 - 0x54920003, // 019C LDINT R36 4 - 0x7C840600, // 019D CALL R33 3 - 0x8C844153, // 019E GETMET R33 R32 K83 - 0x588C0003, // 019F LDCONST R35 K3 - 0x54920003, // 01A0 LDINT R36 4 - 0x7C840600, // 01A1 CALL R33 3 - 0x8C843F41, // 01A2 GETMET R33 R31 K65 - 0x5C8C4000, // 01A3 MOVE R35 R32 - 0x7C840400, // 01A4 CALL R33 2 - 0x88880154, // 01A5 GETMBR R34 R0 K84 - 0x8C884555, // 01A6 GETMET R34 R34 K85 - 0x5C904200, // 01A7 MOVE R36 R33 - 0x5C940400, // 01A8 MOVE R37 R2 - 0x5C980600, // 01A9 MOVE R38 R3 - 0x889C3F56, // 01AA GETMBR R39 R31 K86 - 0x7C880A00, // 01AB CALL R34 5 - 0x8C880B57, // 01AC GETMET R34 R5 K87 - 0x7C880200, // 01AD CALL R34 1 - 0x8C880B58, // 01AE GETMET R34 R5 K88 - 0x5C903600, // 01AF MOVE R36 R27 - 0x5C943800, // 01B0 MOVE R37 R28 - 0x5C983A00, // 01B1 MOVE R38 R29 - 0x5C9C3C00, // 01B2 MOVE R39 R30 - 0x7C880A00, // 01B3 CALL R34 5 - 0x8C880B59, // 01B4 GETMET R34 R5 K89 - 0x50900200, // 01B5 LDBOOL R36 1 0 - 0x7C880400, // 01B6 CALL R34 2 - 0x8C880B5A, // 01B7 GETMET R34 R5 K90 - 0x7C880200, // 01B8 CALL R34 1 - 0x8C880B5B, // 01B9 GETMET R34 R5 K91 - 0x7C880200, // 01BA CALL R34 1 - 0x50880200, // 01BB LDBOOL R34 1 0 - 0x80044400, // 01BC RET 1 R34 + 0xB8621A00, // 0126 GETNGBL R24 K13 + 0x8C60310E, // 0127 GETMET R24 R24 K14 + 0x58680047, // 0128 LDCONST R26 K71 + 0x586C0010, // 0129 LDCONST R27 K16 + 0x7C600600, // 012A CALL R24 3 + 0x8C600511, // 012B GETMET R24 R2 K17 + 0x7C600200, // 012C CALL R24 1 + 0x8C603112, // 012D GETMET R24 R24 K18 + 0x88680713, // 012E GETMBR R26 R3 K19 + 0x7C600400, // 012F CALL R24 2 + 0x8C603112, // 0130 GETMET R24 R24 K18 + 0x88680714, // 0131 GETMBR R26 R3 K20 + 0x7C600400, // 0132 CALL R24 2 + 0x8C603112, // 0133 GETMET R24 R24 K18 + 0x88680948, // 0134 GETMBR R26 R4 K72 + 0x7C600400, // 0135 CALL R24 2 + 0x8C603115, // 0136 GETMET R24 R24 K21 + 0x7C600200, // 0137 CALL R24 1 + 0x5C143000, // 0138 MOVE R5 R24 + 0x4C600000, // 0139 LDNIL R24 + 0x900E2618, // 013A SETMBR R3 K19 R24 + 0x4C600000, // 013B LDNIL R24 + 0x900E2818, // 013C SETMBR R3 K20 R24 + 0xB8621A00, // 013D GETNGBL R24 K13 + 0x8C60310E, // 013E GETMET R24 R24 K14 + 0x58680049, // 013F LDCONST R26 K73 + 0x586C0010, // 0140 LDCONST R27 K16 + 0x7C600600, // 0141 CALL R24 3 + 0xB8621A00, // 0142 GETNGBL R24 K13 + 0x8C60310E, // 0143 GETMET R24 R24 K14 + 0x88680723, // 0144 GETMBR R26 R3 K35 + 0x8C68351D, // 0145 GETMET R26 R26 K29 + 0x7C680200, // 0146 CALL R26 1 + 0x006A941A, // 0147 ADD R26 K74 R26 + 0x586C0010, // 0148 LDCONST R27 K16 + 0x7C600600, // 0149 CALL R24 3 + 0xB8621A00, // 014A GETNGBL R24 K13 + 0x8C60310E, // 014B GETMET R24 R24 K14 + 0x8C68071C, // 014C GETMET R26 R3 K28 + 0x7C680200, // 014D CALL R26 1 + 0x00683405, // 014E ADD R26 R26 R5 + 0x8C68351D, // 014F GETMET R26 R26 K29 + 0x7C680200, // 0150 CALL R26 1 + 0x006A961A, // 0151 ADD R26 K75 R26 + 0x586C0010, // 0152 LDCONST R27 K16 + 0x7C600600, // 0153 CALL R24 3 + 0x8C600521, // 0154 GETMET R24 R2 K33 + 0x7C600200, // 0155 CALL R24 1 + 0x8C603122, // 0156 GETMET R24 R24 K34 + 0x88680723, // 0157 GETMBR R26 R3 K35 + 0x8C6C071C, // 0158 GETMET R27 R3 K28 + 0x7C6C0200, // 0159 CALL R27 1 + 0x006C3605, // 015A ADD R27 R27 R5 + 0x60700015, // 015B GETGBL R28 G21 + 0x7C700000, // 015C CALL R28 0 + 0x8C70391F, // 015D GETMET R28 R28 K31 + 0x8878014C, // 015E GETMBR R30 R0 K76 + 0x7C700400, // 015F CALL R28 2 + 0x5476002F, // 0160 LDINT R29 48 + 0x7C600A00, // 0161 CALL R24 5 + 0x5466000E, // 0162 LDINT R25 15 + 0x40660619, // 0163 CONNECT R25 K3 R25 + 0x94643019, // 0164 GETIDX R25 R24 R25 + 0x546A000F, // 0165 LDINT R26 16 + 0x546E001E, // 0166 LDINT R27 31 + 0x4068341B, // 0167 CONNECT R26 R26 R27 + 0x9468301A, // 0168 GETIDX R26 R24 R26 + 0x546E001F, // 0169 LDINT R27 32 + 0x5472002E, // 016A LDINT R28 47 + 0x406C361C, // 016B CONNECT R27 R27 R28 + 0x946C301B, // 016C GETIDX R27 R24 R27 + 0xB8721A00, // 016D GETNGBL R28 K13 + 0x8C70394D, // 016E GETMET R28 R28 K77 + 0x7C700200, // 016F CALL R28 1 + 0x9470394E, // 0170 GETIDX R28 R28 K78 + 0xB8761A00, // 0171 GETNGBL R29 K13 + 0x8C743B0E, // 0172 GETMET R29 R29 K14 + 0x587C0049, // 0173 LDCONST R31 K73 + 0x58800010, // 0174 LDCONST R32 K16 + 0x7C740600, // 0175 CALL R29 3 + 0xB8761A00, // 0176 GETNGBL R29 K13 + 0x8C743B0E, // 0177 GETMET R29 R29 K14 + 0x8C7C331D, // 0178 GETMET R31 R25 K29 + 0x7C7C0200, // 0179 CALL R31 1 + 0x007E9E1F, // 017A ADD R31 K79 R31 + 0x58800010, // 017B LDCONST R32 K16 + 0x7C740600, // 017C CALL R29 3 + 0xB8761A00, // 017D GETNGBL R29 K13 + 0x8C743B0E, // 017E GETMET R29 R29 K14 + 0x8C7C351D, // 017F GETMET R31 R26 K29 + 0x7C7C0200, // 0180 CALL R31 1 + 0x007EA01F, // 0181 ADD R31 K80 R31 + 0x58800010, // 0182 LDCONST R32 K16 + 0x7C740600, // 0183 CALL R29 3 + 0xB8761A00, // 0184 GETNGBL R29 K13 + 0x8C743B0E, // 0185 GETMET R29 R29 K14 + 0x8C7C371D, // 0186 GETMET R31 R27 K29 + 0x7C7C0200, // 0187 CALL R31 1 + 0x007EA21F, // 0188 ADD R31 K81 R31 + 0x58800010, // 0189 LDCONST R32 K16 + 0x7C740600, // 018A CALL R29 3 + 0xB8761A00, // 018B GETNGBL R29 K13 + 0x8C743B0E, // 018C GETMET R29 R29 K14 + 0x587C0049, // 018D LDCONST R31 K73 + 0x58800010, // 018E LDCONST R32 K16 + 0x7C740600, // 018F CALL R29 3 + 0x8C740352, // 0190 GETMET R29 R1 K82 + 0x547E003F, // 0191 LDINT R31 64 + 0x50800200, // 0192 LDBOOL R32 1 0 + 0x7C740600, // 0193 CALL R29 3 + 0x60780015, // 0194 GETGBL R30 G21 + 0x7C780000, // 0195 CALL R30 0 + 0x8C7C3D53, // 0196 GETMET R31 R30 K83 + 0x58840003, // 0197 LDCONST R33 K3 + 0x58880034, // 0198 LDCONST R34 K52 + 0x7C7C0600, // 0199 CALL R31 3 + 0x8C7C3D53, // 019A GETMET R31 R30 K83 + 0x58840003, // 019B LDCONST R33 K3 + 0x548A0003, // 019C LDINT R34 4 + 0x7C7C0600, // 019D CALL R31 3 + 0x8C7C3D53, // 019E GETMET R31 R30 K83 + 0x58840003, // 019F LDCONST R33 K3 + 0x548A0003, // 01A0 LDINT R34 4 + 0x7C7C0600, // 01A1 CALL R31 3 + 0x8C7C3B41, // 01A2 GETMET R31 R29 K65 + 0x5C843C00, // 01A3 MOVE R33 R30 + 0x7C7C0400, // 01A4 CALL R31 2 + 0x88800154, // 01A5 GETMBR R32 R0 K84 + 0x8C804155, // 01A6 GETMET R32 R32 K85 + 0x5C883E00, // 01A7 MOVE R34 R31 + 0x888C0356, // 01A8 GETMBR R35 R1 K86 + 0x88900357, // 01A9 GETMBR R36 R1 K87 + 0x88943B58, // 01AA GETMBR R37 R29 K88 + 0x7C800A00, // 01AB CALL R32 5 + 0x8C800759, // 01AC GETMET R32 R3 K89 + 0x7C800200, // 01AD CALL R32 1 + 0x8C80075A, // 01AE GETMET R32 R3 K90 + 0x5C883200, // 01AF MOVE R34 R25 + 0x5C8C3400, // 01B0 MOVE R35 R26 + 0x5C903600, // 01B1 MOVE R36 R27 + 0x5C943800, // 01B2 MOVE R37 R28 + 0x7C800A00, // 01B3 CALL R32 5 + 0x8C80075B, // 01B4 GETMET R32 R3 K91 + 0x50880200, // 01B5 LDBOOL R34 1 0 + 0x7C800400, // 01B6 CALL R32 2 + 0x8C80075C, // 01B7 GETMET R32 R3 K92 + 0x7C800200, // 01B8 CALL R32 1 + 0x8C80075D, // 01B9 GETMET R32 R3 K93 + 0x7C800200, // 01BA CALL R32 1 + 0x50800200, // 01BB LDBOOL R32 1 0 + 0x80044000, // 01BC RET 1 R32 }) ) ); @@ -1358,15 +1364,15 @@ be_local_closure(Matter_Commisioning_Context_parse_Sigma3, /* name */ ********************************************************************/ be_local_closure(Matter_Commisioning_Context_parse_Sigma1, /* name */ be_nested_proto( - 36, /* nstack */ - 4, /* argc */ + 35, /* nstack */ + 2, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[116]) { /* constants */ + ( &(const bvalue[119]) { /* constants */ /* K0 */ be_nested_str_weak(crypto), /* K1 */ be_nested_str_weak(opcode), /* K2 */ be_nested_str_weak(local_session_id), @@ -1381,663 +1387,679 @@ be_local_closure(Matter_Commisioning_Context_parse_Sigma1, /* name */ /* K11 */ be_nested_str_weak(app_payload_idx), /* K12 */ be_nested_str_weak(initiatorEph_pub), /* K13 */ be_nested_str_weak(initiatorEphPubKey), - /* K14 */ be_nested_str_weak(find_session_by_destination_id), - /* K15 */ be_nested_str_weak(destinationId), - /* K16 */ be_nested_str_weak(initiatorRandom), - /* K17 */ be_nested_str_weak(valuer_error), - /* K18 */ be_nested_str_weak(StatusReport_X28GeneralCode_X3A_X20FAILURE_X2C_X20ProtocolId_X3A_X20SECURE_CHANNEL_X2C_X20ProtocolCode_X3A_X20NO_SHARED_TRUST_ROOTS_X29), - /* K19 */ be_nested_str_weak(source_node_id), - /* K20 */ be_nested_str_weak(set_mode), - /* K21 */ be_nested_str_weak(Session), - /* K22 */ be_nested_str_weak(__CASE), - /* K23 */ be_nested_str_weak(session), - /* K24 */ be_nested_str_weak(device), - /* K25 */ be_nested_str_weak(sessions), - /* K26 */ be_nested_str_weak(remove_session), - /* K27 */ be_nested_str_weak(_future_initiator_session_id), - /* K28 */ be_nested_str_weak(initiator_session_id), - /* K29 */ be_nested_str_weak(_future_local_session_id), - /* K30 */ be_nested_str_weak(gen_local_session_id), - /* K31 */ be_nested_str_weak(future_local_session_id), - /* K32 */ be_nested_str_weak(resumptionID), - /* K33 */ be_nested_str_weak(initiatorResumeMIC), - /* K34 */ be_nested_str_weak(shared_secret), - /* K35 */ be_nested_str_weak(fromstring), - /* K36 */ be_nested_str_weak(Sigma1_Resume), - /* K37 */ be_nested_str_weak(HKDF_SHA256), - /* K38 */ be_nested_str_weak(derive), - /* K39 */ be_nested_str_weak(NCASE_SigmaR1), - /* K40 */ be_const_int(2147483647), - /* K41 */ be_nested_str_weak(AES_CCM), - /* K42 */ be_nested_str_weak(decrypt), - /* K43 */ be_nested_str_weak(tag), - /* K44 */ be_nested_str_weak(tasmota), - /* K45 */ be_nested_str_weak(log), - /* K46 */ be_nested_str_weak(_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A), - /* K47 */ be_const_int(3), - /* K48 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20s1rk_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D_X20), - /* K49 */ be_nested_str_weak(tohex), - /* K50 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20tag_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D_X20), - /* K51 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20Resume1MICPayload_X20_X3D_X20), - /* K52 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20decrypted_tag_X20_X20_X20_X20_X20_X3D_X20), - /* K53 */ be_nested_str_weak(resumption_id), - /* K54 */ be_nested_str_weak(random), - /* K55 */ be_nested_str_weak(Sigma2_Resume), - /* K56 */ be_nested_str_weak(NCASE_SigmaR2), - /* K57 */ be_nested_str_weak(Sigma2Resume), - /* K58 */ be_nested_str_weak(responderSessionID), - /* K59 */ be_nested_str_weak(sigma2ResumeMIC), - /* K60 */ be_nested_str_weak(SessionResumptionKeys), - /* K61 */ be_nested_str_weak(rtc), - /* K62 */ be_nested_str_weak(utc), - /* K63 */ be_nested_str_weak(MTR_X3A_X20_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A), - /* K64 */ be_nested_str_weak(MTR_X3A_X20I2RKey_X20_X20_X20_X20_X20_X20_X3D), - /* K65 */ be_nested_str_weak(MTR_X3A_X20R2IKey_X20_X20_X20_X20_X20_X20_X3D), - /* K66 */ be_nested_str_weak(MTR_X3A_X20AC_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), - /* K67 */ be_nested_str_weak(encode), - /* K68 */ be_nested_str_weak(_Msg1), - /* K69 */ be_nested_str_weak(MTR_X3A_X20sigma2resume_raw_X3A_X20), - /* K70 */ be_nested_str_weak(build_response), - /* K71 */ be_nested_str_weak(responder), - /* K72 */ be_nested_str_weak(send_response), - /* K73 */ be_nested_str_weak(message_counter), - /* K74 */ be_nested_str_weak(close), - /* K75 */ be_nested_str_weak(set_keys), - /* K76 */ be_nested_str_weak(set_persist), - /* K77 */ be_nested_str_weak(set_no_expiration), - /* K78 */ be_nested_str_weak(save), - /* K79 */ be_nested_str_weak(ResponderEph_priv), - /* K80 */ be_nested_str_weak(ResponderEph_pub), - /* K81 */ be_nested_str_weak(EC_P256), - /* K82 */ be_nested_str_weak(public_key), - /* K83 */ be_nested_str_weak(shared_key), - /* K84 */ be_nested_str_weak(TLV), - /* K85 */ be_nested_str_weak(Matter_TLV_struct), - /* K86 */ be_nested_str_weak(add_TLV), - /* K87 */ be_const_int(1), - /* K88 */ be_nested_str_weak(B2), - /* K89 */ be_nested_str_weak(get_noc), - /* K90 */ be_const_int(2), - /* K91 */ be_nested_str_weak(get_icac), - /* K92 */ be_nested_str_weak(ecdsa_sign_sha256), - /* K93 */ be_nested_str_weak(get_pk), - /* K94 */ be_nested_str_weak(Msg1), - /* K95 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20MSG1_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D_X20), - /* K96 */ be_nested_str_weak(SHA256), - /* K97 */ be_nested_str_weak(update), - /* K98 */ be_nested_str_weak(out), - /* K99 */ be_nested_str_weak(S2K_Info), - /* K100 */ be_nested_str_weak(get_ipk_group_key), - /* K101 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20SharedSecret_X20_X20_X3D_X20), - /* K102 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20s2k_salt_X20_X20_X20_X20_X20_X20_X3D_X20), - /* K103 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20s2k_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D_X20), - /* K104 */ be_nested_str_weak(TBEData2_Nonce), - /* K105 */ be_nested_str_weak(encrypt), - /* K106 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20TBEData2Enc_X20_X20_X20_X3D_X20), - /* K107 */ be_nested_str_weak(Sigma2), - /* K108 */ be_nested_str_weak(responderRandom), - /* K109 */ be_nested_str_weak(responderSessionId), - /* K110 */ be_nested_str_weak(responderEphPubKey), - /* K111 */ be_nested_str_weak(encrypted2), - /* K112 */ be_nested_str_weak(MTR_X3A_X20sigma2_X3A_X20), - /* K113 */ be_nested_str_weak(inspect), - /* K114 */ be_nested_str_weak(_Msg2), - /* K115 */ be_nested_str_weak(MTR_X3A_X20sigma2_raw_X3A_X20), + /* K14 */ be_nested_str_weak(resumptionID), + /* K15 */ be_nested_str_weak(initiatorResumeMIC), + /* K16 */ be_nested_str_weak(device), + /* K17 */ be_nested_str_weak(sessions), + /* K18 */ be_nested_str_weak(find_session_by_resumption_id), + /* K19 */ be_nested_str_weak(find_session_by_destination_id), + /* K20 */ be_nested_str_weak(destinationId), + /* K21 */ be_nested_str_weak(initiatorRandom), + /* K22 */ be_nested_str_weak(valuer_error), + /* K23 */ be_nested_str_weak(StatusReport_X28GeneralCode_X3A_X20FAILURE_X2C_X20ProtocolId_X3A_X20SECURE_CHANNEL_X2C_X20ProtocolCode_X3A_X20NO_SHARED_TRUST_ROOTS_X29), + /* K24 */ be_nested_str_weak(source_node_id), + /* K25 */ be_nested_str_weak(set_mode), + /* K26 */ be_nested_str_weak(Session), + /* K27 */ be_nested_str_weak(__CASE), + /* K28 */ be_nested_str_weak(session), + /* K29 */ be_nested_str_weak(remove_session), + /* K30 */ be_nested_str_weak(_future_initiator_session_id), + /* K31 */ be_nested_str_weak(initiator_session_id), + /* K32 */ be_nested_str_weak(_future_local_session_id), + /* K33 */ be_nested_str_weak(gen_local_session_id), + /* K34 */ be_nested_str_weak(future_local_session_id), + /* K35 */ be_nested_str_weak(shared_secret), + /* K36 */ be_nested_str_weak(fromstring), + /* K37 */ be_nested_str_weak(Sigma1_Resume), + /* K38 */ be_nested_str_weak(HKDF_SHA256), + /* K39 */ be_nested_str_weak(derive), + /* K40 */ be_nested_str_weak(NCASE_SigmaR1), + /* K41 */ be_const_int(2147483647), + /* K42 */ be_nested_str_weak(AES_CCM), + /* K43 */ be_nested_str_weak(decrypt), + /* K44 */ be_nested_str_weak(tag), + /* K45 */ be_nested_str_weak(tasmota), + /* K46 */ be_nested_str_weak(log), + /* K47 */ be_nested_str_weak(_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A), + /* K48 */ be_const_int(3), + /* K49 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20s1rk_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K50 */ be_nested_str_weak(tohex), + /* K51 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20tag_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K52 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20Resume1MICPayload_X20_X3D_X20), + /* K53 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20decrypted_tag_X20_X20_X20_X20_X20_X3D_X20), + /* K54 */ be_nested_str_weak(resumption_id), + /* K55 */ be_nested_str_weak(random), + /* K56 */ be_nested_str_weak(Sigma2_Resume), + /* K57 */ be_nested_str_weak(NCASE_SigmaR2), + /* K58 */ be_nested_str_weak(Sigma2Resume), + /* K59 */ be_nested_str_weak(responderSessionID), + /* K60 */ be_nested_str_weak(sigma2ResumeMIC), + /* K61 */ be_nested_str_weak(SessionResumptionKeys), + /* K62 */ be_nested_str_weak(rtc), + /* K63 */ be_nested_str_weak(utc), + /* K64 */ be_nested_str_weak(MTR_X3A_X20_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A), + /* K65 */ be_nested_str_weak(MTR_X3A_X20I2RKey_X20_X20_X20_X20_X20_X20_X3D), + /* K66 */ be_nested_str_weak(MTR_X3A_X20R2IKey_X20_X20_X20_X20_X20_X20_X3D), + /* K67 */ be_nested_str_weak(MTR_X3A_X20AC_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), + /* K68 */ be_nested_str_weak(encode), + /* K69 */ be_nested_str_weak(_Msg1), + /* K70 */ be_nested_str_weak(MTR_X3A_X20sigma2resume_raw_X3A_X20), + /* K71 */ be_nested_str_weak(build_response), + /* K72 */ be_nested_str_weak(responder), + /* K73 */ be_nested_str_weak(send_response), + /* K74 */ be_nested_str_weak(remote_ip), + /* K75 */ be_nested_str_weak(remote_port), + /* K76 */ be_nested_str_weak(message_counter), + /* K77 */ be_nested_str_weak(close), + /* K78 */ be_nested_str_weak(set_keys), + /* K79 */ be_nested_str_weak(set_persist), + /* K80 */ be_nested_str_weak(set_no_expiration), + /* K81 */ be_nested_str_weak(save), + /* K82 */ be_nested_str_weak(ResponderEph_priv), + /* K83 */ be_nested_str_weak(ResponderEph_pub), + /* K84 */ be_nested_str_weak(EC_P256), + /* K85 */ be_nested_str_weak(public_key), + /* K86 */ be_nested_str_weak(shared_key), + /* K87 */ be_nested_str_weak(TLV), + /* K88 */ be_nested_str_weak(Matter_TLV_struct), + /* K89 */ be_nested_str_weak(add_TLV), + /* K90 */ be_const_int(1), + /* K91 */ be_nested_str_weak(B2), + /* K92 */ be_nested_str_weak(get_noc), + /* K93 */ be_const_int(2), + /* K94 */ be_nested_str_weak(get_icac), + /* K95 */ be_nested_str_weak(ecdsa_sign_sha256), + /* K96 */ be_nested_str_weak(get_pk), + /* K97 */ be_nested_str_weak(Msg1), + /* K98 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20MSG1_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K99 */ be_nested_str_weak(SHA256), + /* K100 */ be_nested_str_weak(update), + /* K101 */ be_nested_str_weak(out), + /* K102 */ be_nested_str_weak(S2K_Info), + /* K103 */ be_nested_str_weak(get_ipk_group_key), + /* K104 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20SharedSecret_X20_X20_X3D_X20), + /* K105 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20s2k_salt_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K106 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20s2k_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K107 */ be_nested_str_weak(TBEData2_Nonce), + /* K108 */ be_nested_str_weak(encrypt), + /* K109 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20TBEData2Enc_X20_X20_X20_X3D_X20), + /* K110 */ be_nested_str_weak(Sigma2), + /* K111 */ be_nested_str_weak(responderRandom), + /* K112 */ be_nested_str_weak(responderSessionId), + /* K113 */ be_nested_str_weak(responderEphPubKey), + /* K114 */ be_nested_str_weak(encrypted2), + /* K115 */ be_nested_str_weak(MTR_X3A_X20sigma2_X3A_X20), + /* K116 */ be_nested_str_weak(inspect), + /* K117 */ be_nested_str_weak(_Msg2), + /* K118 */ be_nested_str_weak(MTR_X3A_X20sigma2_raw_X3A_X20), }), be_str_weak(parse_Sigma1), &be_const_str_solidified, - ( &(const binstruction[551]) { /* code */ - 0xA4120000, // 0000 IMPORT R4 K0 - 0x88140301, // 0001 GETMBR R5 R1 K1 - 0x541A002F, // 0002 LDINT R6 48 - 0x20140A06, // 0003 NE R5 R5 R6 - 0x74160005, // 0004 JMPT R5 #000B - 0x88140302, // 0005 GETMBR R5 R1 K2 - 0x20140B03, // 0006 NE R5 R5 K3 - 0x74160002, // 0007 JMPT R5 #000B - 0x88140304, // 0008 GETMBR R5 R1 K4 - 0x20140B03, // 0009 NE R5 R5 K3 - 0x78160000, // 000A JMPF R5 #000C + ( &(const binstruction[564]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0x880C0301, // 0001 GETMBR R3 R1 K1 + 0x5412002F, // 0002 LDINT R4 48 + 0x200C0604, // 0003 NE R3 R3 R4 + 0x740E0005, // 0004 JMPT R3 #000B + 0x880C0302, // 0005 GETMBR R3 R1 K2 + 0x200C0703, // 0006 NE R3 R3 K3 + 0x740E0002, // 0007 JMPT R3 #000B + 0x880C0304, // 0008 GETMBR R3 R1 K4 + 0x200C0703, // 0009 NE R3 R3 K3 + 0x780E0000, // 000A JMPF R3 #000C 0xB0060B06, // 000B RAISE 1 K5 K6 - 0xB8160E00, // 000C GETNGBL R5 K7 - 0x8C140B08, // 000D GETMET R5 R5 K8 - 0x7C140200, // 000E CALL R5 1 - 0x8C140B09, // 000F GETMET R5 R5 K9 - 0x881C030A, // 0010 GETMBR R7 R1 K10 - 0x8820030B, // 0011 GETMBR R8 R1 K11 - 0x7C140600, // 0012 CALL R5 3 - 0x88180B0D, // 0013 GETMBR R6 R5 K13 - 0x90021806, // 0014 SETMBR R0 K12 R6 - 0x8C18010E, // 0015 GETMET R6 R0 K14 - 0x88200B0F, // 0016 GETMBR R8 R5 K15 - 0x88240B10, // 0017 GETMBR R9 R5 K16 - 0x7C180600, // 0018 CALL R6 3 - 0x4C1C0000, // 0019 LDNIL R7 - 0x1C1C0C07, // 001A EQ R7 R6 R7 - 0x781E0000, // 001B JMPF R7 #001D - 0xB0062312, // 001C RAISE 1 K17 K18 - 0x881C0313, // 001D GETMBR R7 R1 K19 - 0x901A2607, // 001E SETMBR R6 K19 R7 - 0x8C1C0D14, // 001F GETMET R7 R6 K20 - 0xB8260E00, // 0020 GETNGBL R9 K7 - 0x88241315, // 0021 GETMBR R9 R9 K21 - 0x88241316, // 0022 GETMBR R9 R9 K22 - 0x7C1C0400, // 0023 CALL R7 2 - 0x881C0317, // 0024 GETMBR R7 R1 K23 - 0x781E0004, // 0025 JMPF R7 #002B - 0x881C0118, // 0026 GETMBR R7 R0 K24 - 0x881C0F19, // 0027 GETMBR R7 R7 K25 - 0x8C1C0F1A, // 0028 GETMET R7 R7 K26 - 0x88240317, // 0029 GETMBR R9 R1 K23 - 0x7C1C0400, // 002A CALL R7 2 - 0x90062E06, // 002B SETMBR R1 K23 R6 - 0x881C0B1C, // 002C GETMBR R7 R5 K28 - 0x901A3607, // 002D SETMBR R6 K27 R7 - 0x881C0118, // 002E GETMBR R7 R0 K24 - 0x881C0F19, // 002F GETMBR R7 R7 K25 - 0x8C1C0F1E, // 0030 GETMET R7 R7 K30 - 0x7C1C0200, // 0031 CALL R7 1 - 0x901A3A07, // 0032 SETMBR R6 K29 R7 - 0x881C0D1D, // 0033 GETMBR R7 R6 K29 - 0x90023E07, // 0034 SETMBR R0 K31 R7 - 0x881C0B20, // 0035 GETMBR R7 R5 K32 - 0x4C200000, // 0036 LDNIL R8 - 0x201C0E08, // 0037 NE R7 R7 R8 - 0x781E00F2, // 0038 JMPF R7 #012C - 0x881C0B21, // 0039 GETMBR R7 R5 K33 - 0x4C200000, // 003A LDNIL R8 - 0x201C0E08, // 003B NE R7 R7 R8 - 0x781E00EE, // 003C JMPF R7 #012C - 0x881C0D22, // 003D GETMBR R7 R6 K34 - 0x4C200000, // 003E LDNIL R8 - 0x201C0E08, // 003F NE R7 R7 R8 - 0x781E00EA, // 0040 JMPF R7 #012C - 0x881C0B10, // 0041 GETMBR R7 R5 K16 - 0x88200B20, // 0042 GETMBR R8 R5 K32 - 0x001C0E08, // 0043 ADD R7 R7 R8 - 0x60200015, // 0044 GETGBL R8 G21 - 0x7C200000, // 0045 CALL R8 0 - 0x8C201123, // 0046 GETMET R8 R8 K35 - 0x58280024, // 0047 LDCONST R10 K36 - 0x7C200400, // 0048 CALL R8 2 - 0x8C240925, // 0049 GETMET R9 R4 K37 - 0x7C240200, // 004A CALL R9 1 - 0x8C241326, // 004B GETMET R9 R9 K38 - 0x882C0D22, // 004C GETMBR R11 R6 K34 - 0x5C300E00, // 004D MOVE R12 R7 - 0x5C341000, // 004E MOVE R13 R8 - 0x543A000F, // 004F LDINT R14 16 - 0x7C240A00, // 0050 CALL R9 5 - 0x60280015, // 0051 GETGBL R10 G21 - 0x7C280000, // 0052 CALL R10 0 - 0x8C281523, // 0053 GETMET R10 R10 K35 - 0x58300027, // 0054 LDCONST R12 K39 - 0x7C280400, // 0055 CALL R10 2 - 0x542DFFEE, // 0056 LDINT R11 -17 - 0x402E060B, // 0057 CONNECT R11 K3 R11 - 0x88300B21, // 0058 GETMBR R12 R5 K33 - 0x942C180B, // 0059 GETIDX R11 R12 R11 - 0x5435FFEF, // 005A LDINT R13 -16 - 0x40341B28, // 005B CONNECT R13 R13 K40 - 0x88380B21, // 005C GETMBR R14 R5 K33 - 0x94301C0D, // 005D GETIDX R12 R14 R13 - 0x8C3C0929, // 005E GETMET R15 R4 K41 - 0x5C441200, // 005F MOVE R17 R9 - 0x5C481400, // 0060 MOVE R18 R10 - 0x604C0015, // 0061 GETGBL R19 G21 - 0x7C4C0000, // 0062 CALL R19 0 - 0x6050000C, // 0063 GETGBL R20 G12 - 0x5C541600, // 0064 MOVE R21 R11 - 0x7C500200, // 0065 CALL R20 1 - 0x5456000F, // 0066 LDINT R21 16 - 0x7C3C0C00, // 0067 CALL R15 6 - 0x5C341E00, // 0068 MOVE R13 R15 - 0x8C3C1B2A, // 0069 GETMET R15 R13 K42 - 0x5C441600, // 006A MOVE R17 R11 - 0x7C3C0400, // 006B CALL R15 2 - 0x5C381E00, // 006C MOVE R14 R15 - 0x8C3C1B2B, // 006D GETMET R15 R13 K43 - 0x7C3C0200, // 006E CALL R15 1 - 0xB8425800, // 006F GETNGBL R16 K44 - 0x8C40212D, // 0070 GETMET R16 R16 K45 - 0x5848002E, // 0071 LDCONST R18 K46 - 0x584C002F, // 0072 LDCONST R19 K47 - 0x7C400600, // 0073 CALL R16 3 - 0xB8425800, // 0074 GETNGBL R16 K44 - 0x8C40212D, // 0075 GETMET R16 R16 K45 - 0x8C481331, // 0076 GETMET R18 R9 K49 - 0x7C480200, // 0077 CALL R18 1 - 0x004A6012, // 0078 ADD R18 K48 R18 - 0x584C002F, // 0079 LDCONST R19 K47 - 0x7C400600, // 007A CALL R16 3 - 0xB8425800, // 007B GETNGBL R16 K44 - 0x8C40212D, // 007C GETMET R16 R16 K45 - 0x8C481931, // 007D GETMET R18 R12 K49 - 0x7C480200, // 007E CALL R18 1 - 0x004A6412, // 007F ADD R18 K50 R18 - 0x584C002F, // 0080 LDCONST R19 K47 - 0x7C400600, // 0081 CALL R16 3 - 0xB8425800, // 0082 GETNGBL R16 K44 - 0x8C40212D, // 0083 GETMET R16 R16 K45 - 0x8C481D31, // 0084 GETMET R18 R14 K49 - 0x7C480200, // 0085 CALL R18 1 - 0x004A6612, // 0086 ADD R18 K51 R18 - 0x584C002F, // 0087 LDCONST R19 K47 - 0x7C400600, // 0088 CALL R16 3 - 0xB8425800, // 0089 GETNGBL R16 K44 - 0x8C40212D, // 008A GETMET R16 R16 K45 - 0x8C481F31, // 008B GETMET R18 R15 K49 - 0x7C480200, // 008C CALL R18 1 - 0x004A6812, // 008D ADD R18 K52 R18 - 0x584C002F, // 008E LDCONST R19 K47 - 0x7C400600, // 008F CALL R16 3 - 0xB8425800, // 0090 GETNGBL R16 K44 - 0x8C40212D, // 0091 GETMET R16 R16 K45 - 0x5848002E, // 0092 LDCONST R18 K46 - 0x584C002F, // 0093 LDCONST R19 K47 - 0x7C400600, // 0094 CALL R16 3 - 0x1C40180F, // 0095 EQ R16 R12 R15 - 0x78420092, // 0096 JMPF R16 #012A - 0x8C400936, // 0097 GETMET R16 R4 K54 - 0x544A000F, // 0098 LDINT R18 16 - 0x7C400400, // 0099 CALL R16 2 - 0x901A6A10, // 009A SETMBR R6 K53 R16 - 0x60400015, // 009B GETGBL R16 G21 - 0x7C400000, // 009C CALL R16 0 - 0x8C402123, // 009D GETMET R16 R16 K35 - 0x58480037, // 009E LDCONST R18 K55 - 0x7C400400, // 009F CALL R16 2 - 0x88440D35, // 00A0 GETMBR R17 R6 K53 - 0x00402011, // 00A1 ADD R16 R16 R17 - 0x88440B10, // 00A2 GETMBR R17 R5 K16 - 0x88480B20, // 00A3 GETMBR R18 R5 K32 - 0x00442212, // 00A4 ADD R17 R17 R18 - 0x8C480925, // 00A5 GETMET R18 R4 K37 - 0x7C480200, // 00A6 CALL R18 1 - 0x8C482526, // 00A7 GETMET R18 R18 K38 - 0x88500D22, // 00A8 GETMBR R20 R6 K34 - 0x5C542200, // 00A9 MOVE R21 R17 - 0x5C582000, // 00AA MOVE R22 R16 - 0x545E000F, // 00AB LDINT R23 16 - 0x7C480A00, // 00AC CALL R18 5 - 0x8C4C0929, // 00AD GETMET R19 R4 K41 - 0x5C542400, // 00AE MOVE R21 R18 - 0x60580015, // 00AF GETGBL R22 G21 - 0x7C580000, // 00B0 CALL R22 0 - 0x8C582D23, // 00B1 GETMET R22 R22 K35 - 0x58600038, // 00B2 LDCONST R24 K56 - 0x7C580400, // 00B3 CALL R22 2 - 0x605C0015, // 00B4 GETGBL R23 G21 - 0x7C5C0000, // 00B5 CALL R23 0 - 0x58600003, // 00B6 LDCONST R24 K3 - 0x5466000F, // 00B7 LDINT R25 16 - 0x7C4C0C00, // 00B8 CALL R19 6 - 0x8C50272B, // 00B9 GETMET R20 R19 K43 - 0x7C500200, // 00BA CALL R20 1 - 0xB8560E00, // 00BB GETNGBL R21 K7 - 0x8C542B39, // 00BC GETMET R21 R21 K57 - 0x7C540200, // 00BD CALL R21 1 - 0x88580D35, // 00BE GETMBR R22 R6 K53 - 0x90564016, // 00BF SETMBR R21 K32 R22 - 0x88580D1D, // 00C0 GETMBR R22 R6 K29 - 0x90567416, // 00C1 SETMBR R21 K58 R22 - 0x90567614, // 00C2 SETMBR R21 K59 R20 - 0x8C580925, // 00C3 GETMET R22 R4 K37 - 0x7C580200, // 00C4 CALL R22 1 - 0x8C582D26, // 00C5 GETMET R22 R22 K38 - 0x88600D22, // 00C6 GETMBR R24 R6 K34 - 0x88640B10, // 00C7 GETMBR R25 R5 K16 - 0x88680B20, // 00C8 GETMBR R26 R5 K32 - 0x0064321A, // 00C9 ADD R25 R25 R26 - 0x60680015, // 00CA GETGBL R26 G21 - 0x7C680000, // 00CB CALL R26 0 - 0x8C683523, // 00CC GETMET R26 R26 K35 - 0x5870003C, // 00CD LDCONST R28 K60 - 0x7C680400, // 00CE CALL R26 2 - 0x546E002F, // 00CF LDINT R27 48 - 0x7C580A00, // 00D0 CALL R22 5 - 0x545E000E, // 00D1 LDINT R23 15 - 0x405E0617, // 00D2 CONNECT R23 K3 R23 - 0x945C2C17, // 00D3 GETIDX R23 R22 R23 - 0x5462000F, // 00D4 LDINT R24 16 - 0x5466001E, // 00D5 LDINT R25 31 - 0x40603019, // 00D6 CONNECT R24 R24 R25 - 0x94602C18, // 00D7 GETIDX R24 R22 R24 - 0x5466001F, // 00D8 LDINT R25 32 - 0x546A002E, // 00D9 LDINT R26 47 - 0x4064321A, // 00DA CONNECT R25 R25 R26 - 0x94642C19, // 00DB GETIDX R25 R22 R25 - 0xB86A5800, // 00DC GETNGBL R26 K44 - 0x8C68353D, // 00DD GETMET R26 R26 K61 - 0x7C680200, // 00DE CALL R26 1 - 0x9468353E, // 00DF GETIDX R26 R26 K62 - 0xB86E5800, // 00E0 GETNGBL R27 K44 - 0x8C6C372D, // 00E1 GETMET R27 R27 K45 - 0x5874003F, // 00E2 LDCONST R29 K63 - 0x5878002F, // 00E3 LDCONST R30 K47 - 0x7C6C0600, // 00E4 CALL R27 3 - 0xB86E5800, // 00E5 GETNGBL R27 K44 - 0x8C6C372D, // 00E6 GETMET R27 R27 K45 - 0x8C742F31, // 00E7 GETMET R29 R23 K49 - 0x7C740200, // 00E8 CALL R29 1 - 0x0076801D, // 00E9 ADD R29 K64 R29 - 0x5878002F, // 00EA LDCONST R30 K47 - 0x7C6C0600, // 00EB CALL R27 3 - 0xB86E5800, // 00EC GETNGBL R27 K44 - 0x8C6C372D, // 00ED GETMET R27 R27 K45 - 0x8C743131, // 00EE GETMET R29 R24 K49 - 0x7C740200, // 00EF CALL R29 1 - 0x0076821D, // 00F0 ADD R29 K65 R29 - 0x5878002F, // 00F1 LDCONST R30 K47 - 0x7C6C0600, // 00F2 CALL R27 3 - 0xB86E5800, // 00F3 GETNGBL R27 K44 - 0x8C6C372D, // 00F4 GETMET R27 R27 K45 - 0x8C743331, // 00F5 GETMET R29 R25 K49 - 0x7C740200, // 00F6 CALL R29 1 - 0x0076841D, // 00F7 ADD R29 K66 R29 - 0x5878002F, // 00F8 LDCONST R30 K47 - 0x7C6C0600, // 00F9 CALL R27 3 - 0xB86E5800, // 00FA GETNGBL R27 K44 - 0x8C6C372D, // 00FB GETMET R27 R27 K45 - 0x5874003F, // 00FC LDCONST R29 K63 - 0x5878002F, // 00FD LDCONST R30 K47 - 0x7C6C0600, // 00FE CALL R27 3 - 0x8C6C2B43, // 00FF GETMET R27 R21 K67 - 0x7C6C0200, // 0100 CALL R27 1 - 0x4C700000, // 0101 LDNIL R28 - 0x901A881C, // 0102 SETMBR R6 K68 R28 - 0xB8725800, // 0103 GETNGBL R28 K44 - 0x8C70392D, // 0104 GETMET R28 R28 K45 - 0x8C783731, // 0105 GETMET R30 R27 K49 - 0x7C780200, // 0106 CALL R30 1 - 0x007A8A1E, // 0107 ADD R30 K69 R30 - 0x587C002F, // 0108 LDCONST R31 K47 - 0x7C700600, // 0109 CALL R28 3 - 0x8C700346, // 010A GETMET R28 R1 K70 - 0x547A0032, // 010B LDINT R30 51 - 0x507C0200, // 010C LDBOOL R31 1 0 - 0x7C700600, // 010D CALL R28 3 - 0x8C743943, // 010E GETMET R29 R28 K67 - 0x5C7C3600, // 010F MOVE R31 R27 - 0x7C740400, // 0110 CALL R29 2 - 0x88780147, // 0111 GETMBR R30 R0 K71 - 0x8C783D48, // 0112 GETMET R30 R30 K72 - 0x5C803A00, // 0113 MOVE R32 R29 - 0x5C840400, // 0114 MOVE R33 R2 - 0x5C880600, // 0115 MOVE R34 R3 - 0x888C3949, // 0116 GETMBR R35 R28 K73 - 0x7C780A00, // 0117 CALL R30 5 - 0x8C780D4A, // 0118 GETMET R30 R6 K74 - 0x7C780200, // 0119 CALL R30 1 - 0x8C780D4B, // 011A GETMET R30 R6 K75 - 0x5C802E00, // 011B MOVE R32 R23 - 0x5C843000, // 011C MOVE R33 R24 - 0x5C883200, // 011D MOVE R34 R25 - 0x5C8C3400, // 011E MOVE R35 R26 - 0x7C780A00, // 011F CALL R30 5 - 0x8C780D4C, // 0120 GETMET R30 R6 K76 - 0x50800200, // 0121 LDBOOL R32 1 0 - 0x7C780400, // 0122 CALL R30 2 - 0x8C780D4D, // 0123 GETMET R30 R6 K77 - 0x7C780200, // 0124 CALL R30 1 - 0x8C780D4E, // 0125 GETMET R30 R6 K78 - 0x7C780200, // 0126 CALL R30 1 - 0x50780200, // 0127 LDBOOL R30 1 0 - 0x80043C00, // 0128 RET 1 R30 - 0x70020001, // 0129 JMP #012C - 0x4C400000, // 012A LDNIL R16 - 0x90164010, // 012B SETMBR R5 K32 R16 - 0x881C0B20, // 012C GETMBR R7 R5 K32 - 0x4C200000, // 012D LDNIL R8 - 0x1C1C0E08, // 012E EQ R7 R7 R8 - 0x741E0003, // 012F JMPT R7 #0134 - 0x881C0B21, // 0130 GETMBR R7 R5 K33 - 0x4C200000, // 0131 LDNIL R8 - 0x1C1C0E08, // 0132 EQ R7 R7 R8 - 0x781E00F0, // 0133 JMPF R7 #0225 - 0x8C1C0936, // 0134 GETMET R7 R4 K54 - 0x5426000F, // 0135 LDINT R9 16 - 0x7C1C0400, // 0136 CALL R7 2 - 0x901A6A07, // 0137 SETMBR R6 K53 R7 - 0x8C1C0936, // 0138 GETMET R7 R4 K54 - 0x5426001F, // 0139 LDINT R9 32 - 0x7C1C0400, // 013A CALL R7 2 - 0x90029E07, // 013B SETMBR R0 K79 R7 - 0x8C1C0951, // 013C GETMET R7 R4 K81 - 0x7C1C0200, // 013D CALL R7 1 - 0x8C1C0F52, // 013E GETMET R7 R7 K82 - 0x8824014F, // 013F GETMBR R9 R0 K79 - 0x7C1C0400, // 0140 CALL R7 2 - 0x9002A007, // 0141 SETMBR R0 K80 R7 - 0x8C1C0936, // 0142 GETMET R7 R4 K54 - 0x5426001F, // 0143 LDINT R9 32 - 0x7C1C0400, // 0144 CALL R7 2 - 0x8C200951, // 0145 GETMET R8 R4 K81 - 0x7C200200, // 0146 CALL R8 1 - 0x8C201153, // 0147 GETMET R8 R8 K83 - 0x8828014F, // 0148 GETMBR R10 R0 K79 - 0x882C0B0D, // 0149 GETMBR R11 R5 K13 - 0x7C200600, // 014A CALL R8 3 - 0x901A4408, // 014B SETMBR R6 K34 R8 - 0xB8220E00, // 014C GETNGBL R8 K7 - 0x88201154, // 014D GETMBR R8 R8 K84 - 0x8C201155, // 014E GETMET R8 R8 K85 - 0x7C200200, // 014F CALL R8 1 - 0x8C241156, // 0150 GETMET R9 R8 K86 - 0x582C0057, // 0151 LDCONST R11 K87 - 0xB8320E00, // 0152 GETNGBL R12 K7 - 0x88301954, // 0153 GETMBR R12 R12 K84 - 0x88301958, // 0154 GETMBR R12 R12 K88 - 0x8C340D59, // 0155 GETMET R13 R6 K89 - 0x7C340200, // 0156 CALL R13 1 - 0x7C240800, // 0157 CALL R9 4 - 0x8C241156, // 0158 GETMET R9 R8 K86 - 0x582C005A, // 0159 LDCONST R11 K90 - 0xB8320E00, // 015A GETNGBL R12 K7 - 0x88301954, // 015B GETMBR R12 R12 K84 - 0x88301958, // 015C GETMBR R12 R12 K88 - 0x8C340D5B, // 015D GETMET R13 R6 K91 - 0x7C340200, // 015E CALL R13 1 - 0x7C240800, // 015F CALL R9 4 - 0x8C241156, // 0160 GETMET R9 R8 K86 - 0x582C002F, // 0161 LDCONST R11 K47 - 0xB8320E00, // 0162 GETNGBL R12 K7 - 0x88301954, // 0163 GETMBR R12 R12 K84 - 0x88301958, // 0164 GETMBR R12 R12 K88 - 0x88340150, // 0165 GETMBR R13 R0 K80 - 0x7C240800, // 0166 CALL R9 4 - 0x8C241156, // 0167 GETMET R9 R8 K86 - 0x542E0003, // 0168 LDINT R11 4 - 0xB8320E00, // 0169 GETNGBL R12 K7 - 0x88301954, // 016A GETMBR R12 R12 K84 - 0x88301958, // 016B GETMBR R12 R12 K88 - 0x88340B0D, // 016C GETMBR R13 R5 K13 - 0x7C240800, // 016D CALL R9 4 - 0x8C240951, // 016E GETMET R9 R4 K81 - 0x7C240200, // 016F CALL R9 1 - 0x8C24135C, // 0170 GETMET R9 R9 K92 - 0x8C2C0D5D, // 0171 GETMET R11 R6 K93 - 0x7C2C0200, // 0172 CALL R11 1 - 0x8C301143, // 0173 GETMET R12 R8 K67 - 0x7C300200, // 0174 CALL R12 1 - 0x7C240600, // 0175 CALL R9 3 - 0xB82A0E00, // 0176 GETNGBL R10 K7 - 0x88281554, // 0177 GETMBR R10 R10 K84 - 0x8C281555, // 0178 GETMET R10 R10 K85 - 0x7C280200, // 0179 CALL R10 1 - 0x8C2C1556, // 017A GETMET R11 R10 K86 - 0x58340057, // 017B LDCONST R13 K87 - 0xB83A0E00, // 017C GETNGBL R14 K7 - 0x88381D54, // 017D GETMBR R14 R14 K84 - 0x88381D58, // 017E GETMBR R14 R14 K88 - 0x8C3C0D59, // 017F GETMET R15 R6 K89 - 0x7C3C0200, // 0180 CALL R15 1 - 0x7C2C0800, // 0181 CALL R11 4 - 0x8C2C1556, // 0182 GETMET R11 R10 K86 - 0x5834005A, // 0183 LDCONST R13 K90 - 0xB83A0E00, // 0184 GETNGBL R14 K7 - 0x88381D54, // 0185 GETMBR R14 R14 K84 - 0x88381D58, // 0186 GETMBR R14 R14 K88 - 0x8C3C0D5B, // 0187 GETMET R15 R6 K91 - 0x7C3C0200, // 0188 CALL R15 1 - 0x7C2C0800, // 0189 CALL R11 4 - 0x8C2C1556, // 018A GETMET R11 R10 K86 - 0x5834002F, // 018B LDCONST R13 K47 - 0xB83A0E00, // 018C GETNGBL R14 K7 - 0x88381D54, // 018D GETMBR R14 R14 K84 - 0x88381D58, // 018E GETMBR R14 R14 K88 - 0x5C3C1200, // 018F MOVE R15 R9 - 0x7C2C0800, // 0190 CALL R11 4 - 0x8C2C1556, // 0191 GETMET R11 R10 K86 - 0x54360003, // 0192 LDINT R13 4 - 0xB83A0E00, // 0193 GETNGBL R14 K7 - 0x88381D54, // 0194 GETMBR R14 R14 K84 - 0x88381D58, // 0195 GETMBR R14 R14 K88 - 0x883C0D35, // 0196 GETMBR R15 R6 K53 - 0x7C2C0800, // 0197 CALL R11 4 - 0xB82E5800, // 0198 GETNGBL R11 K44 - 0x8C2C172D, // 0199 GETMET R11 R11 K45 - 0x5834002E, // 019A LDCONST R13 K46 - 0x5838002F, // 019B LDCONST R14 K47 - 0x7C2C0600, // 019C CALL R11 3 - 0x882C0B5E, // 019D GETMBR R11 R5 K94 - 0x901A880B, // 019E SETMBR R6 K68 R11 - 0xB82E5800, // 019F GETNGBL R11 K44 - 0x8C2C172D, // 01A0 GETMET R11 R11 K45 - 0x88340D44, // 01A1 GETMBR R13 R6 K68 - 0x8C341B31, // 01A2 GETMET R13 R13 K49 - 0x7C340200, // 01A3 CALL R13 1 - 0x0036BE0D, // 01A4 ADD R13 K95 R13 - 0x5838002F, // 01A5 LDCONST R14 K47 - 0x7C2C0600, // 01A6 CALL R11 3 - 0x8C2C0960, // 01A7 GETMET R11 R4 K96 - 0x7C2C0200, // 01A8 CALL R11 1 - 0x8C2C1761, // 01A9 GETMET R11 R11 K97 - 0x88340D44, // 01AA GETMBR R13 R6 K68 - 0x7C2C0400, // 01AB CALL R11 2 - 0x8C2C1762, // 01AC GETMET R11 R11 K98 - 0x7C2C0200, // 01AD CALL R11 1 - 0x60300015, // 01AE GETGBL R12 G21 - 0x7C300000, // 01AF CALL R12 0 - 0x8C301923, // 01B0 GETMET R12 R12 K35 - 0x88380163, // 01B1 GETMBR R14 R0 K99 - 0x7C300400, // 01B2 CALL R12 2 - 0x8C340D64, // 01B3 GETMET R13 R6 K100 - 0x7C340200, // 01B4 CALL R13 1 - 0x00341A07, // 01B5 ADD R13 R13 R7 - 0x88380150, // 01B6 GETMBR R14 R0 K80 - 0x00341A0E, // 01B7 ADD R13 R13 R14 - 0x00341A0B, // 01B8 ADD R13 R13 R11 - 0x8C380925, // 01B9 GETMET R14 R4 K37 - 0x7C380200, // 01BA CALL R14 1 - 0x8C381D26, // 01BB GETMET R14 R14 K38 - 0x88400D22, // 01BC GETMBR R16 R6 K34 - 0x5C441A00, // 01BD MOVE R17 R13 - 0x5C481800, // 01BE MOVE R18 R12 - 0x544E000F, // 01BF LDINT R19 16 - 0x7C380A00, // 01C0 CALL R14 5 - 0xB83E5800, // 01C1 GETNGBL R15 K44 - 0x8C3C1F2D, // 01C2 GETMET R15 R15 K45 - 0x88440D22, // 01C3 GETMBR R17 R6 K34 - 0x8C442331, // 01C4 GETMET R17 R17 K49 - 0x7C440200, // 01C5 CALL R17 1 - 0x0046CA11, // 01C6 ADD R17 K101 R17 - 0x5848002F, // 01C7 LDCONST R18 K47 - 0x7C3C0600, // 01C8 CALL R15 3 - 0xB83E5800, // 01C9 GETNGBL R15 K44 - 0x8C3C1F2D, // 01CA GETMET R15 R15 K45 - 0x8C441B31, // 01CB GETMET R17 R13 K49 - 0x7C440200, // 01CC CALL R17 1 - 0x0046CC11, // 01CD ADD R17 K102 R17 - 0x5848002F, // 01CE LDCONST R18 K47 - 0x7C3C0600, // 01CF CALL R15 3 - 0xB83E5800, // 01D0 GETNGBL R15 K44 - 0x8C3C1F2D, // 01D1 GETMET R15 R15 K45 - 0x8C441D31, // 01D2 GETMET R17 R14 K49 - 0x7C440200, // 01D3 CALL R17 1 - 0x0046CE11, // 01D4 ADD R17 K103 R17 - 0x5848002F, // 01D5 LDCONST R18 K47 - 0x7C3C0600, // 01D6 CALL R15 3 - 0x8C3C1543, // 01D7 GETMET R15 R10 K67 - 0x7C3C0200, // 01D8 CALL R15 1 - 0x8C400929, // 01D9 GETMET R16 R4 K41 - 0x5C481C00, // 01DA MOVE R18 R14 - 0x604C0015, // 01DB GETGBL R19 G21 - 0x7C4C0000, // 01DC CALL R19 0 - 0x8C4C2723, // 01DD GETMET R19 R19 K35 - 0x88540168, // 01DE GETMBR R21 R0 K104 - 0x7C4C0400, // 01DF CALL R19 2 - 0x60500015, // 01E0 GETGBL R20 G21 - 0x7C500000, // 01E1 CALL R20 0 - 0x6054000C, // 01E2 GETGBL R21 G12 - 0x5C581E00, // 01E3 MOVE R22 R15 - 0x7C540200, // 01E4 CALL R21 1 - 0x545A000F, // 01E5 LDINT R22 16 - 0x7C400C00, // 01E6 CALL R16 6 - 0x8C442169, // 01E7 GETMET R17 R16 K105 - 0x5C4C1E00, // 01E8 MOVE R19 R15 - 0x7C440400, // 01E9 CALL R17 2 - 0x8C48212B, // 01EA GETMET R18 R16 K43 - 0x7C480200, // 01EB CALL R18 1 - 0x00442212, // 01EC ADD R17 R17 R18 - 0xB84A5800, // 01ED GETNGBL R18 K44 - 0x8C48252D, // 01EE GETMET R18 R18 K45 - 0x8C502331, // 01EF GETMET R20 R17 K49 - 0x7C500200, // 01F0 CALL R20 1 - 0x0052D414, // 01F1 ADD R20 K106 R20 - 0x5854002F, // 01F2 LDCONST R21 K47 - 0x7C480600, // 01F3 CALL R18 3 - 0xB84A5800, // 01F4 GETNGBL R18 K44 - 0x8C48252D, // 01F5 GETMET R18 R18 K45 - 0x5850002E, // 01F6 LDCONST R20 K46 - 0x5854002F, // 01F7 LDCONST R21 K47 - 0x7C480600, // 01F8 CALL R18 3 - 0xB84A0E00, // 01F9 GETNGBL R18 K7 - 0x8C48256B, // 01FA GETMET R18 R18 K107 - 0x7C480200, // 01FB CALL R18 1 - 0x904AD807, // 01FC SETMBR R18 K108 R7 - 0x884C011F, // 01FD GETMBR R19 R0 K31 - 0x904ADA13, // 01FE SETMBR R18 K109 R19 - 0x884C0150, // 01FF GETMBR R19 R0 K80 - 0x904ADC13, // 0200 SETMBR R18 K110 R19 - 0x904ADE11, // 0201 SETMBR R18 K111 R17 - 0xB84E5800, // 0202 GETNGBL R19 K44 - 0x8C4C272D, // 0203 GETMET R19 R19 K45 - 0xB8560E00, // 0204 GETNGBL R21 K7 - 0x8C542B71, // 0205 GETMET R21 R21 K113 - 0x5C5C2400, // 0206 MOVE R23 R18 - 0x7C540400, // 0207 CALL R21 2 - 0x0056E015, // 0208 ADD R21 K112 R21 - 0x5858002F, // 0209 LDCONST R22 K47 - 0x7C4C0600, // 020A CALL R19 3 - 0x8C4C2543, // 020B GETMET R19 R18 K67 - 0x7C4C0200, // 020C CALL R19 1 - 0x901AE413, // 020D SETMBR R6 K114 R19 - 0xB8525800, // 020E GETNGBL R20 K44 - 0x8C50292D, // 020F GETMET R20 R20 K45 - 0x8C582731, // 0210 GETMET R22 R19 K49 - 0x7C580200, // 0211 CALL R22 1 - 0x005AE616, // 0212 ADD R22 K115 R22 - 0x585C002F, // 0213 LDCONST R23 K47 - 0x7C500600, // 0214 CALL R20 3 - 0x8C500346, // 0215 GETMET R20 R1 K70 - 0x545A0030, // 0216 LDINT R22 49 - 0x505C0200, // 0217 LDBOOL R23 1 0 - 0x7C500600, // 0218 CALL R20 3 - 0x8C542943, // 0219 GETMET R21 R20 K67 - 0x5C5C2600, // 021A MOVE R23 R19 - 0x7C540400, // 021B CALL R21 2 - 0x88580147, // 021C GETMBR R22 R0 K71 - 0x8C582D48, // 021D GETMET R22 R22 K72 - 0x5C602A00, // 021E MOVE R24 R21 - 0x5C640400, // 021F MOVE R25 R2 - 0x5C680600, // 0220 MOVE R26 R3 - 0x886C2949, // 0221 GETMBR R27 R20 K73 - 0x7C580A00, // 0222 CALL R22 5 - 0x50580200, // 0223 LDBOOL R22 1 0 - 0x80042C00, // 0224 RET 1 R22 - 0x501C0200, // 0225 LDBOOL R7 1 0 - 0x80040E00, // 0226 RET 1 R7 + 0xB80E0E00, // 000C GETNGBL R3 K7 + 0x8C0C0708, // 000D GETMET R3 R3 K8 + 0x7C0C0200, // 000E CALL R3 1 + 0x8C0C0709, // 000F GETMET R3 R3 K9 + 0x8814030A, // 0010 GETMBR R5 R1 K10 + 0x8818030B, // 0011 GETMBR R6 R1 K11 + 0x7C0C0600, // 0012 CALL R3 3 + 0x8810070D, // 0013 GETMBR R4 R3 K13 + 0x90021804, // 0014 SETMBR R0 K12 R4 + 0x8810070E, // 0015 GETMBR R4 R3 K14 + 0x4C140000, // 0016 LDNIL R5 + 0x20100805, // 0017 NE R4 R4 R5 + 0x78120003, // 0018 JMPF R4 #001D + 0x8810070F, // 0019 GETMBR R4 R3 K15 + 0x4C140000, // 001A LDNIL R5 + 0x20100805, // 001B NE R4 R4 R5 + 0x74120000, // 001C JMPT R4 #001E + 0x50100001, // 001D LDBOOL R4 0 1 + 0x50100200, // 001E LDBOOL R4 1 0 + 0x4C140000, // 001F LDNIL R5 + 0x78120006, // 0020 JMPF R4 #0028 + 0x88180110, // 0021 GETMBR R6 R0 K16 + 0x88180D11, // 0022 GETMBR R6 R6 K17 + 0x8C180D12, // 0023 GETMET R6 R6 K18 + 0x8820070E, // 0024 GETMBR R8 R3 K14 + 0x7C180400, // 0025 CALL R6 2 + 0x5C140C00, // 0026 MOVE R5 R6 + 0x70020004, // 0027 JMP #002D + 0x8C180113, // 0028 GETMET R6 R0 K19 + 0x88200714, // 0029 GETMBR R8 R3 K20 + 0x88240715, // 002A GETMBR R9 R3 K21 + 0x7C180600, // 002B CALL R6 3 + 0x5C140C00, // 002C MOVE R5 R6 + 0x4C180000, // 002D LDNIL R6 + 0x1C180A06, // 002E EQ R6 R5 R6 + 0x781A0000, // 002F JMPF R6 #0031 + 0xB0062D17, // 0030 RAISE 1 K22 K23 + 0x88180318, // 0031 GETMBR R6 R1 K24 + 0x90163006, // 0032 SETMBR R5 K24 R6 + 0x8C180B19, // 0033 GETMET R6 R5 K25 + 0xB8220E00, // 0034 GETNGBL R8 K7 + 0x8820111A, // 0035 GETMBR R8 R8 K26 + 0x8820111B, // 0036 GETMBR R8 R8 K27 + 0x7C180400, // 0037 CALL R6 2 + 0x8818031C, // 0038 GETMBR R6 R1 K28 + 0x781A0004, // 0039 JMPF R6 #003F + 0x88180110, // 003A GETMBR R6 R0 K16 + 0x88180D11, // 003B GETMBR R6 R6 K17 + 0x8C180D1D, // 003C GETMET R6 R6 K29 + 0x8820031C, // 003D GETMBR R8 R1 K28 + 0x7C180400, // 003E CALL R6 2 + 0x90063805, // 003F SETMBR R1 K28 R5 + 0x8818071F, // 0040 GETMBR R6 R3 K31 + 0x90163C06, // 0041 SETMBR R5 K30 R6 + 0x88180110, // 0042 GETMBR R6 R0 K16 + 0x88180D11, // 0043 GETMBR R6 R6 K17 + 0x8C180D21, // 0044 GETMET R6 R6 K33 + 0x7C180200, // 0045 CALL R6 1 + 0x90164006, // 0046 SETMBR R5 K32 R6 + 0x88180B20, // 0047 GETMBR R6 R5 K32 + 0x90024406, // 0048 SETMBR R0 K34 R6 + 0x781200EE, // 0049 JMPF R4 #0139 + 0x88180B23, // 004A GETMBR R6 R5 K35 + 0x4C1C0000, // 004B LDNIL R7 + 0x20180C07, // 004C NE R6 R6 R7 + 0x781A00EA, // 004D JMPF R6 #0139 + 0x88180715, // 004E GETMBR R6 R3 K21 + 0x881C070E, // 004F GETMBR R7 R3 K14 + 0x00180C07, // 0050 ADD R6 R6 R7 + 0x601C0015, // 0051 GETGBL R7 G21 + 0x7C1C0000, // 0052 CALL R7 0 + 0x8C1C0F24, // 0053 GETMET R7 R7 K36 + 0x58240025, // 0054 LDCONST R9 K37 + 0x7C1C0400, // 0055 CALL R7 2 + 0x8C200526, // 0056 GETMET R8 R2 K38 + 0x7C200200, // 0057 CALL R8 1 + 0x8C201127, // 0058 GETMET R8 R8 K39 + 0x88280B23, // 0059 GETMBR R10 R5 K35 + 0x5C2C0C00, // 005A MOVE R11 R6 + 0x5C300E00, // 005B MOVE R12 R7 + 0x5436000F, // 005C LDINT R13 16 + 0x7C200A00, // 005D CALL R8 5 + 0x60240015, // 005E GETGBL R9 G21 + 0x7C240000, // 005F CALL R9 0 + 0x8C241324, // 0060 GETMET R9 R9 K36 + 0x582C0028, // 0061 LDCONST R11 K40 + 0x7C240400, // 0062 CALL R9 2 + 0x5429FFEE, // 0063 LDINT R10 -17 + 0x402A060A, // 0064 CONNECT R10 K3 R10 + 0x882C070F, // 0065 GETMBR R11 R3 K15 + 0x9428160A, // 0066 GETIDX R10 R11 R10 + 0x5431FFEF, // 0067 LDINT R12 -16 + 0x40301929, // 0068 CONNECT R12 R12 K41 + 0x8834070F, // 0069 GETMBR R13 R3 K15 + 0x942C1A0C, // 006A GETIDX R11 R13 R12 + 0x8C38052A, // 006B GETMET R14 R2 K42 + 0x5C401000, // 006C MOVE R16 R8 + 0x5C441200, // 006D MOVE R17 R9 + 0x60480015, // 006E GETGBL R18 G21 + 0x7C480000, // 006F CALL R18 0 + 0x604C000C, // 0070 GETGBL R19 G12 + 0x5C501400, // 0071 MOVE R20 R10 + 0x7C4C0200, // 0072 CALL R19 1 + 0x5452000F, // 0073 LDINT R20 16 + 0x7C380C00, // 0074 CALL R14 6 + 0x5C301C00, // 0075 MOVE R12 R14 + 0x8C38192B, // 0076 GETMET R14 R12 K43 + 0x5C401400, // 0077 MOVE R16 R10 + 0x7C380400, // 0078 CALL R14 2 + 0x5C341C00, // 0079 MOVE R13 R14 + 0x8C38192C, // 007A GETMET R14 R12 K44 + 0x7C380200, // 007B CALL R14 1 + 0xB83E5A00, // 007C GETNGBL R15 K45 + 0x8C3C1F2E, // 007D GETMET R15 R15 K46 + 0x5844002F, // 007E LDCONST R17 K47 + 0x58480030, // 007F LDCONST R18 K48 + 0x7C3C0600, // 0080 CALL R15 3 + 0xB83E5A00, // 0081 GETNGBL R15 K45 + 0x8C3C1F2E, // 0082 GETMET R15 R15 K46 + 0x8C441132, // 0083 GETMET R17 R8 K50 + 0x7C440200, // 0084 CALL R17 1 + 0x00466211, // 0085 ADD R17 K49 R17 + 0x58480030, // 0086 LDCONST R18 K48 + 0x7C3C0600, // 0087 CALL R15 3 + 0xB83E5A00, // 0088 GETNGBL R15 K45 + 0x8C3C1F2E, // 0089 GETMET R15 R15 K46 + 0x8C441732, // 008A GETMET R17 R11 K50 + 0x7C440200, // 008B CALL R17 1 + 0x00466611, // 008C ADD R17 K51 R17 + 0x58480030, // 008D LDCONST R18 K48 + 0x7C3C0600, // 008E CALL R15 3 + 0xB83E5A00, // 008F GETNGBL R15 K45 + 0x8C3C1F2E, // 0090 GETMET R15 R15 K46 + 0x8C441B32, // 0091 GETMET R17 R13 K50 + 0x7C440200, // 0092 CALL R17 1 + 0x00466811, // 0093 ADD R17 K52 R17 + 0x58480030, // 0094 LDCONST R18 K48 + 0x7C3C0600, // 0095 CALL R15 3 + 0xB83E5A00, // 0096 GETNGBL R15 K45 + 0x8C3C1F2E, // 0097 GETMET R15 R15 K46 + 0x8C441D32, // 0098 GETMET R17 R14 K50 + 0x7C440200, // 0099 CALL R17 1 + 0x00466A11, // 009A ADD R17 K53 R17 + 0x58480030, // 009B LDCONST R18 K48 + 0x7C3C0600, // 009C CALL R15 3 + 0xB83E5A00, // 009D GETNGBL R15 K45 + 0x8C3C1F2E, // 009E GETMET R15 R15 K46 + 0x5844002F, // 009F LDCONST R17 K47 + 0x58480030, // 00A0 LDCONST R18 K48 + 0x7C3C0600, // 00A1 CALL R15 3 + 0x1C3C160E, // 00A2 EQ R15 R11 R14 + 0x783E0092, // 00A3 JMPF R15 #0137 + 0x8C3C0537, // 00A4 GETMET R15 R2 K55 + 0x5446000F, // 00A5 LDINT R17 16 + 0x7C3C0400, // 00A6 CALL R15 2 + 0x90166C0F, // 00A7 SETMBR R5 K54 R15 + 0x603C0015, // 00A8 GETGBL R15 G21 + 0x7C3C0000, // 00A9 CALL R15 0 + 0x8C3C1F24, // 00AA GETMET R15 R15 K36 + 0x58440038, // 00AB LDCONST R17 K56 + 0x7C3C0400, // 00AC CALL R15 2 + 0x88400B36, // 00AD GETMBR R16 R5 K54 + 0x003C1E10, // 00AE ADD R15 R15 R16 + 0x88400715, // 00AF GETMBR R16 R3 K21 + 0x8844070E, // 00B0 GETMBR R17 R3 K14 + 0x00402011, // 00B1 ADD R16 R16 R17 + 0x8C440526, // 00B2 GETMET R17 R2 K38 + 0x7C440200, // 00B3 CALL R17 1 + 0x8C442327, // 00B4 GETMET R17 R17 K39 + 0x884C0B23, // 00B5 GETMBR R19 R5 K35 + 0x5C502000, // 00B6 MOVE R20 R16 + 0x5C541E00, // 00B7 MOVE R21 R15 + 0x545A000F, // 00B8 LDINT R22 16 + 0x7C440A00, // 00B9 CALL R17 5 + 0x8C48052A, // 00BA GETMET R18 R2 K42 + 0x5C502200, // 00BB MOVE R20 R17 + 0x60540015, // 00BC GETGBL R21 G21 + 0x7C540000, // 00BD CALL R21 0 + 0x8C542B24, // 00BE GETMET R21 R21 K36 + 0x585C0039, // 00BF LDCONST R23 K57 + 0x7C540400, // 00C0 CALL R21 2 + 0x60580015, // 00C1 GETGBL R22 G21 + 0x7C580000, // 00C2 CALL R22 0 + 0x585C0003, // 00C3 LDCONST R23 K3 + 0x5462000F, // 00C4 LDINT R24 16 + 0x7C480C00, // 00C5 CALL R18 6 + 0x8C4C252C, // 00C6 GETMET R19 R18 K44 + 0x7C4C0200, // 00C7 CALL R19 1 + 0xB8520E00, // 00C8 GETNGBL R20 K7 + 0x8C50293A, // 00C9 GETMET R20 R20 K58 + 0x7C500200, // 00CA CALL R20 1 + 0x88540B36, // 00CB GETMBR R21 R5 K54 + 0x90521C15, // 00CC SETMBR R20 K14 R21 + 0x88540B20, // 00CD GETMBR R21 R5 K32 + 0x90527615, // 00CE SETMBR R20 K59 R21 + 0x90527813, // 00CF SETMBR R20 K60 R19 + 0x8C540526, // 00D0 GETMET R21 R2 K38 + 0x7C540200, // 00D1 CALL R21 1 + 0x8C542B27, // 00D2 GETMET R21 R21 K39 + 0x885C0B23, // 00D3 GETMBR R23 R5 K35 + 0x88600715, // 00D4 GETMBR R24 R3 K21 + 0x8864070E, // 00D5 GETMBR R25 R3 K14 + 0x00603019, // 00D6 ADD R24 R24 R25 + 0x60640015, // 00D7 GETGBL R25 G21 + 0x7C640000, // 00D8 CALL R25 0 + 0x8C643324, // 00D9 GETMET R25 R25 K36 + 0x586C003D, // 00DA LDCONST R27 K61 + 0x7C640400, // 00DB CALL R25 2 + 0x546A002F, // 00DC LDINT R26 48 + 0x7C540A00, // 00DD CALL R21 5 + 0x545A000E, // 00DE LDINT R22 15 + 0x405A0616, // 00DF CONNECT R22 K3 R22 + 0x94582A16, // 00E0 GETIDX R22 R21 R22 + 0x545E000F, // 00E1 LDINT R23 16 + 0x5462001E, // 00E2 LDINT R24 31 + 0x405C2E18, // 00E3 CONNECT R23 R23 R24 + 0x945C2A17, // 00E4 GETIDX R23 R21 R23 + 0x5462001F, // 00E5 LDINT R24 32 + 0x5466002E, // 00E6 LDINT R25 47 + 0x40603019, // 00E7 CONNECT R24 R24 R25 + 0x94602A18, // 00E8 GETIDX R24 R21 R24 + 0xB8665A00, // 00E9 GETNGBL R25 K45 + 0x8C64333E, // 00EA GETMET R25 R25 K62 + 0x7C640200, // 00EB CALL R25 1 + 0x9464333F, // 00EC GETIDX R25 R25 K63 + 0xB86A5A00, // 00ED GETNGBL R26 K45 + 0x8C68352E, // 00EE GETMET R26 R26 K46 + 0x58700040, // 00EF LDCONST R28 K64 + 0x58740030, // 00F0 LDCONST R29 K48 + 0x7C680600, // 00F1 CALL R26 3 + 0xB86A5A00, // 00F2 GETNGBL R26 K45 + 0x8C68352E, // 00F3 GETMET R26 R26 K46 + 0x8C702D32, // 00F4 GETMET R28 R22 K50 + 0x7C700200, // 00F5 CALL R28 1 + 0x0072821C, // 00F6 ADD R28 K65 R28 + 0x58740030, // 00F7 LDCONST R29 K48 + 0x7C680600, // 00F8 CALL R26 3 + 0xB86A5A00, // 00F9 GETNGBL R26 K45 + 0x8C68352E, // 00FA GETMET R26 R26 K46 + 0x8C702F32, // 00FB GETMET R28 R23 K50 + 0x7C700200, // 00FC CALL R28 1 + 0x0072841C, // 00FD ADD R28 K66 R28 + 0x58740030, // 00FE LDCONST R29 K48 + 0x7C680600, // 00FF CALL R26 3 + 0xB86A5A00, // 0100 GETNGBL R26 K45 + 0x8C68352E, // 0101 GETMET R26 R26 K46 + 0x8C703132, // 0102 GETMET R28 R24 K50 + 0x7C700200, // 0103 CALL R28 1 + 0x0072861C, // 0104 ADD R28 K67 R28 + 0x58740030, // 0105 LDCONST R29 K48 + 0x7C680600, // 0106 CALL R26 3 + 0xB86A5A00, // 0107 GETNGBL R26 K45 + 0x8C68352E, // 0108 GETMET R26 R26 K46 + 0x58700040, // 0109 LDCONST R28 K64 + 0x58740030, // 010A LDCONST R29 K48 + 0x7C680600, // 010B CALL R26 3 + 0x8C682944, // 010C GETMET R26 R20 K68 + 0x7C680200, // 010D CALL R26 1 + 0x4C6C0000, // 010E LDNIL R27 + 0x90168A1B, // 010F SETMBR R5 K69 R27 + 0xB86E5A00, // 0110 GETNGBL R27 K45 + 0x8C6C372E, // 0111 GETMET R27 R27 K46 + 0x8C743532, // 0112 GETMET R29 R26 K50 + 0x7C740200, // 0113 CALL R29 1 + 0x00768C1D, // 0114 ADD R29 K70 R29 + 0x58780030, // 0115 LDCONST R30 K48 + 0x7C6C0600, // 0116 CALL R27 3 + 0x8C6C0347, // 0117 GETMET R27 R1 K71 + 0x54760032, // 0118 LDINT R29 51 + 0x50780200, // 0119 LDBOOL R30 1 0 + 0x7C6C0600, // 011A CALL R27 3 + 0x8C703744, // 011B GETMET R28 R27 K68 + 0x5C783400, // 011C MOVE R30 R26 + 0x7C700400, // 011D CALL R28 2 + 0x88740148, // 011E GETMBR R29 R0 K72 + 0x8C743B49, // 011F GETMET R29 R29 K73 + 0x5C7C3800, // 0120 MOVE R31 R28 + 0x8880034A, // 0121 GETMBR R32 R1 K74 + 0x8884034B, // 0122 GETMBR R33 R1 K75 + 0x8888374C, // 0123 GETMBR R34 R27 K76 + 0x7C740A00, // 0124 CALL R29 5 + 0x8C740B4D, // 0125 GETMET R29 R5 K77 + 0x7C740200, // 0126 CALL R29 1 + 0x8C740B4E, // 0127 GETMET R29 R5 K78 + 0x5C7C2C00, // 0128 MOVE R31 R22 + 0x5C802E00, // 0129 MOVE R32 R23 + 0x5C843000, // 012A MOVE R33 R24 + 0x5C883200, // 012B MOVE R34 R25 + 0x7C740A00, // 012C CALL R29 5 + 0x8C740B4F, // 012D GETMET R29 R5 K79 + 0x507C0200, // 012E LDBOOL R31 1 0 + 0x7C740400, // 012F CALL R29 2 + 0x8C740B50, // 0130 GETMET R29 R5 K80 + 0x7C740200, // 0131 CALL R29 1 + 0x8C740B51, // 0132 GETMET R29 R5 K81 + 0x7C740200, // 0133 CALL R29 1 + 0x50740200, // 0134 LDBOOL R29 1 0 + 0x80043A00, // 0135 RET 1 R29 + 0x70020001, // 0136 JMP #0139 + 0x4C3C0000, // 0137 LDNIL R15 + 0x900E1C0F, // 0138 SETMBR R3 K14 R15 + 0x8818070E, // 0139 GETMBR R6 R3 K14 + 0x4C1C0000, // 013A LDNIL R7 + 0x1C180C07, // 013B EQ R6 R6 R7 + 0x741A0003, // 013C JMPT R6 #0141 + 0x8818070F, // 013D GETMBR R6 R3 K15 + 0x4C1C0000, // 013E LDNIL R7 + 0x1C180C07, // 013F EQ R6 R6 R7 + 0x781A00F0, // 0140 JMPF R6 #0232 + 0x8C180537, // 0141 GETMET R6 R2 K55 + 0x5422000F, // 0142 LDINT R8 16 + 0x7C180400, // 0143 CALL R6 2 + 0x90166C06, // 0144 SETMBR R5 K54 R6 + 0x8C180537, // 0145 GETMET R6 R2 K55 + 0x5422001F, // 0146 LDINT R8 32 + 0x7C180400, // 0147 CALL R6 2 + 0x9002A406, // 0148 SETMBR R0 K82 R6 + 0x8C180554, // 0149 GETMET R6 R2 K84 + 0x7C180200, // 014A CALL R6 1 + 0x8C180D55, // 014B GETMET R6 R6 K85 + 0x88200152, // 014C GETMBR R8 R0 K82 + 0x7C180400, // 014D CALL R6 2 + 0x9002A606, // 014E SETMBR R0 K83 R6 + 0x8C180537, // 014F GETMET R6 R2 K55 + 0x5422001F, // 0150 LDINT R8 32 + 0x7C180400, // 0151 CALL R6 2 + 0x8C1C0554, // 0152 GETMET R7 R2 K84 + 0x7C1C0200, // 0153 CALL R7 1 + 0x8C1C0F56, // 0154 GETMET R7 R7 K86 + 0x88240152, // 0155 GETMBR R9 R0 K82 + 0x8828070D, // 0156 GETMBR R10 R3 K13 + 0x7C1C0600, // 0157 CALL R7 3 + 0x90164607, // 0158 SETMBR R5 K35 R7 + 0xB81E0E00, // 0159 GETNGBL R7 K7 + 0x881C0F57, // 015A GETMBR R7 R7 K87 + 0x8C1C0F58, // 015B GETMET R7 R7 K88 + 0x7C1C0200, // 015C CALL R7 1 + 0x8C200F59, // 015D GETMET R8 R7 K89 + 0x5828005A, // 015E LDCONST R10 K90 + 0xB82E0E00, // 015F GETNGBL R11 K7 + 0x882C1757, // 0160 GETMBR R11 R11 K87 + 0x882C175B, // 0161 GETMBR R11 R11 K91 + 0x8C300B5C, // 0162 GETMET R12 R5 K92 + 0x7C300200, // 0163 CALL R12 1 + 0x7C200800, // 0164 CALL R8 4 + 0x8C200F59, // 0165 GETMET R8 R7 K89 + 0x5828005D, // 0166 LDCONST R10 K93 + 0xB82E0E00, // 0167 GETNGBL R11 K7 + 0x882C1757, // 0168 GETMBR R11 R11 K87 + 0x882C175B, // 0169 GETMBR R11 R11 K91 + 0x8C300B5E, // 016A GETMET R12 R5 K94 + 0x7C300200, // 016B CALL R12 1 + 0x7C200800, // 016C CALL R8 4 + 0x8C200F59, // 016D GETMET R8 R7 K89 + 0x58280030, // 016E LDCONST R10 K48 + 0xB82E0E00, // 016F GETNGBL R11 K7 + 0x882C1757, // 0170 GETMBR R11 R11 K87 + 0x882C175B, // 0171 GETMBR R11 R11 K91 + 0x88300153, // 0172 GETMBR R12 R0 K83 + 0x7C200800, // 0173 CALL R8 4 + 0x8C200F59, // 0174 GETMET R8 R7 K89 + 0x542A0003, // 0175 LDINT R10 4 + 0xB82E0E00, // 0176 GETNGBL R11 K7 + 0x882C1757, // 0177 GETMBR R11 R11 K87 + 0x882C175B, // 0178 GETMBR R11 R11 K91 + 0x8830070D, // 0179 GETMBR R12 R3 K13 + 0x7C200800, // 017A CALL R8 4 + 0x8C200554, // 017B GETMET R8 R2 K84 + 0x7C200200, // 017C CALL R8 1 + 0x8C20115F, // 017D GETMET R8 R8 K95 + 0x8C280B60, // 017E GETMET R10 R5 K96 + 0x7C280200, // 017F CALL R10 1 + 0x8C2C0F44, // 0180 GETMET R11 R7 K68 + 0x7C2C0200, // 0181 CALL R11 1 + 0x7C200600, // 0182 CALL R8 3 + 0xB8260E00, // 0183 GETNGBL R9 K7 + 0x88241357, // 0184 GETMBR R9 R9 K87 + 0x8C241358, // 0185 GETMET R9 R9 K88 + 0x7C240200, // 0186 CALL R9 1 + 0x8C281359, // 0187 GETMET R10 R9 K89 + 0x5830005A, // 0188 LDCONST R12 K90 + 0xB8360E00, // 0189 GETNGBL R13 K7 + 0x88341B57, // 018A GETMBR R13 R13 K87 + 0x88341B5B, // 018B GETMBR R13 R13 K91 + 0x8C380B5C, // 018C GETMET R14 R5 K92 + 0x7C380200, // 018D CALL R14 1 + 0x7C280800, // 018E CALL R10 4 + 0x8C281359, // 018F GETMET R10 R9 K89 + 0x5830005D, // 0190 LDCONST R12 K93 + 0xB8360E00, // 0191 GETNGBL R13 K7 + 0x88341B57, // 0192 GETMBR R13 R13 K87 + 0x88341B5B, // 0193 GETMBR R13 R13 K91 + 0x8C380B5E, // 0194 GETMET R14 R5 K94 + 0x7C380200, // 0195 CALL R14 1 + 0x7C280800, // 0196 CALL R10 4 + 0x8C281359, // 0197 GETMET R10 R9 K89 + 0x58300030, // 0198 LDCONST R12 K48 + 0xB8360E00, // 0199 GETNGBL R13 K7 + 0x88341B57, // 019A GETMBR R13 R13 K87 + 0x88341B5B, // 019B GETMBR R13 R13 K91 + 0x5C381000, // 019C MOVE R14 R8 + 0x7C280800, // 019D CALL R10 4 + 0x8C281359, // 019E GETMET R10 R9 K89 + 0x54320003, // 019F LDINT R12 4 + 0xB8360E00, // 01A0 GETNGBL R13 K7 + 0x88341B57, // 01A1 GETMBR R13 R13 K87 + 0x88341B5B, // 01A2 GETMBR R13 R13 K91 + 0x88380B36, // 01A3 GETMBR R14 R5 K54 + 0x7C280800, // 01A4 CALL R10 4 + 0xB82A5A00, // 01A5 GETNGBL R10 K45 + 0x8C28152E, // 01A6 GETMET R10 R10 K46 + 0x5830002F, // 01A7 LDCONST R12 K47 + 0x58340030, // 01A8 LDCONST R13 K48 + 0x7C280600, // 01A9 CALL R10 3 + 0x88280761, // 01AA GETMBR R10 R3 K97 + 0x90168A0A, // 01AB SETMBR R5 K69 R10 + 0xB82A5A00, // 01AC GETNGBL R10 K45 + 0x8C28152E, // 01AD GETMET R10 R10 K46 + 0x88300B45, // 01AE GETMBR R12 R5 K69 + 0x8C301932, // 01AF GETMET R12 R12 K50 + 0x7C300200, // 01B0 CALL R12 1 + 0x0032C40C, // 01B1 ADD R12 K98 R12 + 0x58340030, // 01B2 LDCONST R13 K48 + 0x7C280600, // 01B3 CALL R10 3 + 0x8C280563, // 01B4 GETMET R10 R2 K99 + 0x7C280200, // 01B5 CALL R10 1 + 0x8C281564, // 01B6 GETMET R10 R10 K100 + 0x88300B45, // 01B7 GETMBR R12 R5 K69 + 0x7C280400, // 01B8 CALL R10 2 + 0x8C281565, // 01B9 GETMET R10 R10 K101 + 0x7C280200, // 01BA CALL R10 1 + 0x602C0015, // 01BB GETGBL R11 G21 + 0x7C2C0000, // 01BC CALL R11 0 + 0x8C2C1724, // 01BD GETMET R11 R11 K36 + 0x88340166, // 01BE GETMBR R13 R0 K102 + 0x7C2C0400, // 01BF CALL R11 2 + 0x8C300B67, // 01C0 GETMET R12 R5 K103 + 0x7C300200, // 01C1 CALL R12 1 + 0x00301806, // 01C2 ADD R12 R12 R6 + 0x88340153, // 01C3 GETMBR R13 R0 K83 + 0x0030180D, // 01C4 ADD R12 R12 R13 + 0x0030180A, // 01C5 ADD R12 R12 R10 + 0x8C340526, // 01C6 GETMET R13 R2 K38 + 0x7C340200, // 01C7 CALL R13 1 + 0x8C341B27, // 01C8 GETMET R13 R13 K39 + 0x883C0B23, // 01C9 GETMBR R15 R5 K35 + 0x5C401800, // 01CA MOVE R16 R12 + 0x5C441600, // 01CB MOVE R17 R11 + 0x544A000F, // 01CC LDINT R18 16 + 0x7C340A00, // 01CD CALL R13 5 + 0xB83A5A00, // 01CE GETNGBL R14 K45 + 0x8C381D2E, // 01CF GETMET R14 R14 K46 + 0x88400B23, // 01D0 GETMBR R16 R5 K35 + 0x8C402132, // 01D1 GETMET R16 R16 K50 + 0x7C400200, // 01D2 CALL R16 1 + 0x0042D010, // 01D3 ADD R16 K104 R16 + 0x58440030, // 01D4 LDCONST R17 K48 + 0x7C380600, // 01D5 CALL R14 3 + 0xB83A5A00, // 01D6 GETNGBL R14 K45 + 0x8C381D2E, // 01D7 GETMET R14 R14 K46 + 0x8C401932, // 01D8 GETMET R16 R12 K50 + 0x7C400200, // 01D9 CALL R16 1 + 0x0042D210, // 01DA ADD R16 K105 R16 + 0x58440030, // 01DB LDCONST R17 K48 + 0x7C380600, // 01DC CALL R14 3 + 0xB83A5A00, // 01DD GETNGBL R14 K45 + 0x8C381D2E, // 01DE GETMET R14 R14 K46 + 0x8C401B32, // 01DF GETMET R16 R13 K50 + 0x7C400200, // 01E0 CALL R16 1 + 0x0042D410, // 01E1 ADD R16 K106 R16 + 0x58440030, // 01E2 LDCONST R17 K48 + 0x7C380600, // 01E3 CALL R14 3 + 0x8C381344, // 01E4 GETMET R14 R9 K68 + 0x7C380200, // 01E5 CALL R14 1 + 0x8C3C052A, // 01E6 GETMET R15 R2 K42 + 0x5C441A00, // 01E7 MOVE R17 R13 + 0x60480015, // 01E8 GETGBL R18 G21 + 0x7C480000, // 01E9 CALL R18 0 + 0x8C482524, // 01EA GETMET R18 R18 K36 + 0x8850016B, // 01EB GETMBR R20 R0 K107 + 0x7C480400, // 01EC CALL R18 2 + 0x604C0015, // 01ED GETGBL R19 G21 + 0x7C4C0000, // 01EE CALL R19 0 + 0x6050000C, // 01EF GETGBL R20 G12 + 0x5C541C00, // 01F0 MOVE R21 R14 + 0x7C500200, // 01F1 CALL R20 1 + 0x5456000F, // 01F2 LDINT R21 16 + 0x7C3C0C00, // 01F3 CALL R15 6 + 0x8C401F6C, // 01F4 GETMET R16 R15 K108 + 0x5C481C00, // 01F5 MOVE R18 R14 + 0x7C400400, // 01F6 CALL R16 2 + 0x8C441F2C, // 01F7 GETMET R17 R15 K44 + 0x7C440200, // 01F8 CALL R17 1 + 0x00402011, // 01F9 ADD R16 R16 R17 + 0xB8465A00, // 01FA GETNGBL R17 K45 + 0x8C44232E, // 01FB GETMET R17 R17 K46 + 0x8C4C2132, // 01FC GETMET R19 R16 K50 + 0x7C4C0200, // 01FD CALL R19 1 + 0x004EDA13, // 01FE ADD R19 K109 R19 + 0x58500030, // 01FF LDCONST R20 K48 + 0x7C440600, // 0200 CALL R17 3 + 0xB8465A00, // 0201 GETNGBL R17 K45 + 0x8C44232E, // 0202 GETMET R17 R17 K46 + 0x584C002F, // 0203 LDCONST R19 K47 + 0x58500030, // 0204 LDCONST R20 K48 + 0x7C440600, // 0205 CALL R17 3 + 0xB8460E00, // 0206 GETNGBL R17 K7 + 0x8C44236E, // 0207 GETMET R17 R17 K110 + 0x7C440200, // 0208 CALL R17 1 + 0x9046DE06, // 0209 SETMBR R17 K111 R6 + 0x88480122, // 020A GETMBR R18 R0 K34 + 0x9046E012, // 020B SETMBR R17 K112 R18 + 0x88480153, // 020C GETMBR R18 R0 K83 + 0x9046E212, // 020D SETMBR R17 K113 R18 + 0x9046E410, // 020E SETMBR R17 K114 R16 + 0xB84A5A00, // 020F GETNGBL R18 K45 + 0x8C48252E, // 0210 GETMET R18 R18 K46 + 0xB8520E00, // 0211 GETNGBL R20 K7 + 0x8C502974, // 0212 GETMET R20 R20 K116 + 0x5C582200, // 0213 MOVE R22 R17 + 0x7C500400, // 0214 CALL R20 2 + 0x0052E614, // 0215 ADD R20 K115 R20 + 0x58540030, // 0216 LDCONST R21 K48 + 0x7C480600, // 0217 CALL R18 3 + 0x8C482344, // 0218 GETMET R18 R17 K68 + 0x7C480200, // 0219 CALL R18 1 + 0x9016EA12, // 021A SETMBR R5 K117 R18 + 0xB84E5A00, // 021B GETNGBL R19 K45 + 0x8C4C272E, // 021C GETMET R19 R19 K46 + 0x8C542532, // 021D GETMET R21 R18 K50 + 0x7C540200, // 021E CALL R21 1 + 0x0056EC15, // 021F ADD R21 K118 R21 + 0x58580030, // 0220 LDCONST R22 K48 + 0x7C4C0600, // 0221 CALL R19 3 + 0x8C4C0347, // 0222 GETMET R19 R1 K71 + 0x54560030, // 0223 LDINT R21 49 + 0x50580200, // 0224 LDBOOL R22 1 0 + 0x7C4C0600, // 0225 CALL R19 3 + 0x8C502744, // 0226 GETMET R20 R19 K68 + 0x5C582400, // 0227 MOVE R22 R18 + 0x7C500400, // 0228 CALL R20 2 + 0x88540148, // 0229 GETMBR R21 R0 K72 + 0x8C542B49, // 022A GETMET R21 R21 K73 + 0x5C5C2800, // 022B MOVE R23 R20 + 0x8860034A, // 022C GETMBR R24 R1 K74 + 0x8864034B, // 022D GETMBR R25 R1 K75 + 0x8868274C, // 022E GETMBR R26 R19 K76 + 0x7C540A00, // 022F CALL R21 5 + 0x50540200, // 0230 LDBOOL R21 1 0 + 0x80042A00, // 0231 RET 1 R21 + 0x50180200, // 0232 LDBOOL R6 1 0 + 0x80040C00, // 0233 RET 1 R6 }) ) ); @@ -2049,15 +2071,15 @@ be_local_closure(Matter_Commisioning_Context_parse_Sigma1, /* name */ ********************************************************************/ be_local_closure(Matter_Commisioning_Context_parse_Pake3, /* name */ be_nested_proto( - 18, /* nstack */ - 4, /* argc */ + 16, /* nstack */ + 2, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[45]) { /* constants */ + ( &(const bvalue[47]) { /* constants */ /* K0 */ be_nested_str_weak(crypto), /* K1 */ be_nested_str_weak(opcode), /* K2 */ be_nested_str_weak(local_session_id), @@ -2100,158 +2122,160 @@ be_local_closure(Matter_Commisioning_Context_parse_Pake3, /* name */ /* K39 */ be_nested_str_weak(encode), /* K40 */ be_nested_str_weak(responder), /* K41 */ be_nested_str_weak(send_response), - /* K42 */ be_nested_str_weak(add_session), - /* K43 */ be_nested_str_weak(future_local_session_id), - /* K44 */ be_nested_str_weak(future_initiator_session_id), + /* K42 */ be_nested_str_weak(remote_ip), + /* K43 */ be_nested_str_weak(remote_port), + /* K44 */ be_nested_str_weak(add_session), + /* K45 */ be_nested_str_weak(future_local_session_id), + /* K46 */ be_nested_str_weak(future_initiator_session_id), }), be_str_weak(parse_Pake3), &be_const_str_solidified, ( &(const binstruction[146]) { /* code */ - 0xA4120000, // 0000 IMPORT R4 K0 - 0x88140301, // 0001 GETMBR R5 R1 K1 - 0x541A0023, // 0002 LDINT R6 36 - 0x20140A06, // 0003 NE R5 R5 R6 - 0x74160005, // 0004 JMPT R5 #000B - 0x88140302, // 0005 GETMBR R5 R1 K2 - 0x20140B03, // 0006 NE R5 R5 K3 - 0x74160002, // 0007 JMPT R5 #000B - 0x88140304, // 0008 GETMBR R5 R1 K4 - 0x20140B03, // 0009 NE R5 R5 K3 - 0x78160000, // 000A JMPF R5 #000C + 0xA40A0000, // 0000 IMPORT R2 K0 + 0x880C0301, // 0001 GETMBR R3 R1 K1 + 0x54120023, // 0002 LDINT R4 36 + 0x200C0604, // 0003 NE R3 R3 R4 + 0x740E0005, // 0004 JMPT R3 #000B + 0x880C0302, // 0005 GETMBR R3 R1 K2 + 0x200C0703, // 0006 NE R3 R3 K3 + 0x740E0002, // 0007 JMPT R3 #000B + 0x880C0304, // 0008 GETMBR R3 R1 K4 + 0x200C0703, // 0009 NE R3 R3 K3 + 0x780E0000, // 000A JMPF R3 #000C 0xB0060B06, // 000B RAISE 1 K5 K6 - 0xB8160E00, // 000C GETNGBL R5 K7 - 0x8C140B08, // 000D GETMET R5 R5 K8 - 0x7C140200, // 000E CALL R5 1 - 0x8C140B09, // 000F GETMET R5 R5 K9 - 0x881C030A, // 0010 GETMBR R7 R1 K10 - 0x8820030B, // 0011 GETMBR R8 R1 K11 - 0x7C140600, // 0012 CALL R5 3 - 0x88180B0C, // 0013 GETMBR R6 R5 K12 - 0x90021806, // 0014 SETMBR R0 K12 R6 - 0xB81A1A00, // 0015 GETNGBL R6 K13 - 0x8C180D0E, // 0016 GETMET R6 R6 K14 - 0x8820010C, // 0017 GETMBR R8 R0 K12 - 0x8C201110, // 0018 GETMET R8 R8 K16 - 0x7C200200, // 0019 CALL R8 1 - 0x00221E08, // 001A ADD R8 K15 R8 - 0x58240011, // 001B LDCONST R9 K17 - 0x7C180600, // 001C CALL R6 3 - 0x8818010C, // 001D GETMBR R6 R0 K12 - 0x881C0112, // 001E GETMBR R7 R0 K18 - 0x881C0F0C, // 001F GETMBR R7 R7 K12 - 0x20180C07, // 0020 NE R6 R6 R7 - 0x781A0000, // 0021 JMPF R6 #0023 + 0xB80E0E00, // 000C GETNGBL R3 K7 + 0x8C0C0708, // 000D GETMET R3 R3 K8 + 0x7C0C0200, // 000E CALL R3 1 + 0x8C0C0709, // 000F GETMET R3 R3 K9 + 0x8814030A, // 0010 GETMBR R5 R1 K10 + 0x8818030B, // 0011 GETMBR R6 R1 K11 + 0x7C0C0600, // 0012 CALL R3 3 + 0x8810070C, // 0013 GETMBR R4 R3 K12 + 0x90021804, // 0014 SETMBR R0 K12 R4 + 0xB8121A00, // 0015 GETNGBL R4 K13 + 0x8C10090E, // 0016 GETMET R4 R4 K14 + 0x8818010C, // 0017 GETMBR R6 R0 K12 + 0x8C180D10, // 0018 GETMET R6 R6 K16 + 0x7C180200, // 0019 CALL R6 1 + 0x001A1E06, // 001A ADD R6 K15 R6 + 0x581C0011, // 001B LDCONST R7 K17 + 0x7C100600, // 001C CALL R4 3 + 0x8810010C, // 001D GETMBR R4 R0 K12 + 0x88140112, // 001E GETMBR R5 R0 K18 + 0x88140B0C, // 001F GETMBR R5 R5 K12 + 0x20100805, // 0020 NE R4 R4 R5 + 0x78120000, // 0021 JMPF R4 #0023 0xB0060B13, // 0022 RAISE 1 K5 K19 - 0xB81A1A00, // 0023 GETNGBL R6 K13 - 0x8C180D15, // 0024 GETMET R6 R6 K21 - 0x7C180200, // 0025 CALL R6 1 - 0x94180D16, // 0026 GETIDX R6 R6 K22 - 0x90022806, // 0027 SETMBR R0 K20 R6 - 0x8C180917, // 0028 GETMET R6 R4 K23 - 0x7C180200, // 0029 CALL R6 1 - 0x8C180D18, // 002A GETMET R6 R6 K24 - 0x88200119, // 002B GETMBR R8 R0 K25 - 0x60240015, // 002C GETGBL R9 G21 - 0x7C240000, // 002D CALL R9 0 - 0x60280015, // 002E GETGBL R10 G21 - 0x7C280000, // 002F CALL R10 0 - 0x8C28151A, // 0030 GETMET R10 R10 K26 - 0x8830011B, // 0031 GETMBR R12 R0 K27 - 0x7C280400, // 0032 CALL R10 2 - 0x542E002F, // 0033 LDINT R11 48 - 0x7C180A00, // 0034 CALL R6 5 - 0x541E000E, // 0035 LDINT R7 15 - 0x401E0607, // 0036 CONNECT R7 K3 R7 - 0x941C0C07, // 0037 GETIDX R7 R6 R7 - 0x90023807, // 0038 SETMBR R0 K28 R7 - 0x541E000F, // 0039 LDINT R7 16 - 0x5422001E, // 003A LDINT R8 31 - 0x401C0E08, // 003B CONNECT R7 R7 R8 - 0x941C0C07, // 003C GETIDX R7 R6 R7 - 0x90023A07, // 003D SETMBR R0 K29 R7 - 0x541E001F, // 003E LDINT R7 32 - 0x5422002E, // 003F LDINT R8 47 - 0x401C0E08, // 0040 CONNECT R7 R7 R8 - 0x941C0C07, // 0041 GETIDX R7 R6 R7 - 0x90023C07, // 0042 SETMBR R0 K30 R7 - 0xB81E1A00, // 0043 GETNGBL R7 K13 - 0x8C1C0F0E, // 0044 GETMET R7 R7 K14 - 0x5824001F, // 0045 LDCONST R9 K31 - 0x58280011, // 0046 LDCONST R10 K17 - 0x7C1C0600, // 0047 CALL R7 3 - 0xB81E1A00, // 0048 GETNGBL R7 K13 - 0x8C1C0F0E, // 0049 GETMET R7 R7 K14 - 0x8C240D10, // 004A GETMET R9 R6 K16 - 0x7C240200, // 004B CALL R9 1 - 0x00264009, // 004C ADD R9 K32 R9 - 0x58280011, // 004D LDCONST R10 K17 - 0x7C1C0600, // 004E CALL R7 3 - 0xB81E1A00, // 004F GETNGBL R7 K13 - 0x8C1C0F0E, // 0050 GETMET R7 R7 K14 - 0x8824011C, // 0051 GETMBR R9 R0 K28 - 0x8C241310, // 0052 GETMET R9 R9 K16 - 0x7C240200, // 0053 CALL R9 1 - 0x00264209, // 0054 ADD R9 K33 R9 - 0x58280011, // 0055 LDCONST R10 K17 - 0x7C1C0600, // 0056 CALL R7 3 - 0xB81E1A00, // 0057 GETNGBL R7 K13 - 0x8C1C0F0E, // 0058 GETMET R7 R7 K14 - 0x8824011D, // 0059 GETMBR R9 R0 K29 - 0x8C241310, // 005A GETMET R9 R9 K16 - 0x7C240200, // 005B CALL R9 1 - 0x00264409, // 005C ADD R9 K34 R9 - 0x58280011, // 005D LDCONST R10 K17 - 0x7C1C0600, // 005E CALL R7 3 - 0xB81E1A00, // 005F GETNGBL R7 K13 - 0x8C1C0F0E, // 0060 GETMET R7 R7 K14 - 0x8824011E, // 0061 GETMBR R9 R0 K30 - 0x8C241310, // 0062 GETMET R9 R9 K16 - 0x7C240200, // 0063 CALL R9 1 - 0x00264609, // 0064 ADD R9 K35 R9 - 0x58280011, // 0065 LDCONST R10 K17 - 0x7C1C0600, // 0066 CALL R7 3 - 0xB81E1A00, // 0067 GETNGBL R7 K13 - 0x8C1C0F0E, // 0068 GETMET R7 R7 K14 - 0x5824001F, // 0069 LDCONST R9 K31 - 0x58280011, // 006A LDCONST R10 K17 - 0x7C1C0600, // 006B CALL R7 3 - 0x8C1C0324, // 006C GETMET R7 R1 K36 - 0x5426003F, // 006D LDINT R9 64 - 0x50280000, // 006E LDBOOL R10 0 0 - 0x7C1C0600, // 006F CALL R7 3 - 0x60200015, // 0070 GETGBL R8 G21 - 0x7C200000, // 0071 CALL R8 0 - 0x8C241125, // 0072 GETMET R9 R8 K37 - 0x582C0003, // 0073 LDCONST R11 K3 - 0x58300026, // 0074 LDCONST R12 K38 - 0x7C240600, // 0075 CALL R9 3 - 0x8C241125, // 0076 GETMET R9 R8 K37 - 0x582C0003, // 0077 LDCONST R11 K3 - 0x54320003, // 0078 LDINT R12 4 - 0x7C240600, // 0079 CALL R9 3 - 0x8C241125, // 007A GETMET R9 R8 K37 - 0x582C0003, // 007B LDCONST R11 K3 - 0x54320003, // 007C LDINT R12 4 - 0x7C240600, // 007D CALL R9 3 - 0x8C240F27, // 007E GETMET R9 R7 K39 - 0x5C2C1000, // 007F MOVE R11 R8 - 0x7C240400, // 0080 CALL R9 2 - 0x88280128, // 0081 GETMBR R10 R0 K40 - 0x8C281529, // 0082 GETMET R10 R10 K41 - 0x5C301200, // 0083 MOVE R12 R9 - 0x5C340400, // 0084 MOVE R13 R2 - 0x5C380600, // 0085 MOVE R14 R3 - 0x4C3C0000, // 0086 LDNIL R15 - 0x7C280A00, // 0087 CALL R10 5 - 0x88280128, // 0088 GETMBR R10 R0 K40 - 0x8C28152A, // 0089 GETMET R10 R10 K42 - 0x8830012B, // 008A GETMBR R12 R0 K43 - 0x8834012C, // 008B GETMBR R13 R0 K44 - 0x8838011C, // 008C GETMBR R14 R0 K28 - 0x883C011D, // 008D GETMBR R15 R0 K29 - 0x8840011E, // 008E GETMBR R16 R0 K30 - 0x88440114, // 008F GETMBR R17 R0 K20 - 0x7C280E00, // 0090 CALL R10 7 + 0xB8121A00, // 0023 GETNGBL R4 K13 + 0x8C100915, // 0024 GETMET R4 R4 K21 + 0x7C100200, // 0025 CALL R4 1 + 0x94100916, // 0026 GETIDX R4 R4 K22 + 0x90022804, // 0027 SETMBR R0 K20 R4 + 0x8C100517, // 0028 GETMET R4 R2 K23 + 0x7C100200, // 0029 CALL R4 1 + 0x8C100918, // 002A GETMET R4 R4 K24 + 0x88180119, // 002B GETMBR R6 R0 K25 + 0x601C0015, // 002C GETGBL R7 G21 + 0x7C1C0000, // 002D CALL R7 0 + 0x60200015, // 002E GETGBL R8 G21 + 0x7C200000, // 002F CALL R8 0 + 0x8C20111A, // 0030 GETMET R8 R8 K26 + 0x8828011B, // 0031 GETMBR R10 R0 K27 + 0x7C200400, // 0032 CALL R8 2 + 0x5426002F, // 0033 LDINT R9 48 + 0x7C100A00, // 0034 CALL R4 5 + 0x5416000E, // 0035 LDINT R5 15 + 0x40160605, // 0036 CONNECT R5 K3 R5 + 0x94140805, // 0037 GETIDX R5 R4 R5 + 0x90023805, // 0038 SETMBR R0 K28 R5 + 0x5416000F, // 0039 LDINT R5 16 + 0x541A001E, // 003A LDINT R6 31 + 0x40140A06, // 003B CONNECT R5 R5 R6 + 0x94140805, // 003C GETIDX R5 R4 R5 + 0x90023A05, // 003D SETMBR R0 K29 R5 + 0x5416001F, // 003E LDINT R5 32 + 0x541A002E, // 003F LDINT R6 47 + 0x40140A06, // 0040 CONNECT R5 R5 R6 + 0x94140805, // 0041 GETIDX R5 R4 R5 + 0x90023C05, // 0042 SETMBR R0 K30 R5 + 0xB8161A00, // 0043 GETNGBL R5 K13 + 0x8C140B0E, // 0044 GETMET R5 R5 K14 + 0x581C001F, // 0045 LDCONST R7 K31 + 0x58200011, // 0046 LDCONST R8 K17 + 0x7C140600, // 0047 CALL R5 3 + 0xB8161A00, // 0048 GETNGBL R5 K13 + 0x8C140B0E, // 0049 GETMET R5 R5 K14 + 0x8C1C0910, // 004A GETMET R7 R4 K16 + 0x7C1C0200, // 004B CALL R7 1 + 0x001E4007, // 004C ADD R7 K32 R7 + 0x58200011, // 004D LDCONST R8 K17 + 0x7C140600, // 004E CALL R5 3 + 0xB8161A00, // 004F GETNGBL R5 K13 + 0x8C140B0E, // 0050 GETMET R5 R5 K14 + 0x881C011C, // 0051 GETMBR R7 R0 K28 + 0x8C1C0F10, // 0052 GETMET R7 R7 K16 + 0x7C1C0200, // 0053 CALL R7 1 + 0x001E4207, // 0054 ADD R7 K33 R7 + 0x58200011, // 0055 LDCONST R8 K17 + 0x7C140600, // 0056 CALL R5 3 + 0xB8161A00, // 0057 GETNGBL R5 K13 + 0x8C140B0E, // 0058 GETMET R5 R5 K14 + 0x881C011D, // 0059 GETMBR R7 R0 K29 + 0x8C1C0F10, // 005A GETMET R7 R7 K16 + 0x7C1C0200, // 005B CALL R7 1 + 0x001E4407, // 005C ADD R7 K34 R7 + 0x58200011, // 005D LDCONST R8 K17 + 0x7C140600, // 005E CALL R5 3 + 0xB8161A00, // 005F GETNGBL R5 K13 + 0x8C140B0E, // 0060 GETMET R5 R5 K14 + 0x881C011E, // 0061 GETMBR R7 R0 K30 + 0x8C1C0F10, // 0062 GETMET R7 R7 K16 + 0x7C1C0200, // 0063 CALL R7 1 + 0x001E4607, // 0064 ADD R7 K35 R7 + 0x58200011, // 0065 LDCONST R8 K17 + 0x7C140600, // 0066 CALL R5 3 + 0xB8161A00, // 0067 GETNGBL R5 K13 + 0x8C140B0E, // 0068 GETMET R5 R5 K14 + 0x581C001F, // 0069 LDCONST R7 K31 + 0x58200011, // 006A LDCONST R8 K17 + 0x7C140600, // 006B CALL R5 3 + 0x8C140324, // 006C GETMET R5 R1 K36 + 0x541E003F, // 006D LDINT R7 64 + 0x50200000, // 006E LDBOOL R8 0 0 + 0x7C140600, // 006F CALL R5 3 + 0x60180015, // 0070 GETGBL R6 G21 + 0x7C180000, // 0071 CALL R6 0 + 0x8C1C0D25, // 0072 GETMET R7 R6 K37 + 0x58240003, // 0073 LDCONST R9 K3 + 0x58280026, // 0074 LDCONST R10 K38 + 0x7C1C0600, // 0075 CALL R7 3 + 0x8C1C0D25, // 0076 GETMET R7 R6 K37 + 0x58240003, // 0077 LDCONST R9 K3 + 0x542A0003, // 0078 LDINT R10 4 + 0x7C1C0600, // 0079 CALL R7 3 + 0x8C1C0D25, // 007A GETMET R7 R6 K37 + 0x58240003, // 007B LDCONST R9 K3 + 0x542A0003, // 007C LDINT R10 4 + 0x7C1C0600, // 007D CALL R7 3 + 0x8C1C0B27, // 007E GETMET R7 R5 K39 + 0x5C240C00, // 007F MOVE R9 R6 + 0x7C1C0400, // 0080 CALL R7 2 + 0x88200128, // 0081 GETMBR R8 R0 K40 + 0x8C201129, // 0082 GETMET R8 R8 K41 + 0x5C280E00, // 0083 MOVE R10 R7 + 0x882C032A, // 0084 GETMBR R11 R1 K42 + 0x8830032B, // 0085 GETMBR R12 R1 K43 + 0x4C340000, // 0086 LDNIL R13 + 0x7C200A00, // 0087 CALL R8 5 + 0x88200128, // 0088 GETMBR R8 R0 K40 + 0x8C20112C, // 0089 GETMET R8 R8 K44 + 0x8828012D, // 008A GETMBR R10 R0 K45 + 0x882C012E, // 008B GETMBR R11 R0 K46 + 0x8830011C, // 008C GETMBR R12 R0 K28 + 0x8834011D, // 008D GETMBR R13 R0 K29 + 0x8838011E, // 008E GETMBR R14 R0 K30 + 0x883C0114, // 008F GETMBR R15 R0 K20 + 0x7C200E00, // 0090 CALL R8 7 0x80000000, // 0091 RET 0 }) ) @@ -2264,8 +2288,8 @@ be_local_closure(Matter_Commisioning_Context_parse_Pake3, /* name */ ********************************************************************/ be_local_closure(Matter_Commisioning_Context_process_incoming, /* name */ be_nested_proto( - 9, /* nstack */ - 4, /* argc */ + 7, /* nstack */ + 2, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ @@ -2291,81 +2315,71 @@ be_local_closure(Matter_Commisioning_Context_process_incoming, /* name */ }), be_str_weak(process_incoming), &be_const_str_solidified, - ( &(const binstruction[74]) { /* code */ - 0x88100100, // 0000 GETMBR R4 R0 K0 - 0x74120006, // 0001 JMPT R4 #0009 - 0xB8120200, // 0002 GETNGBL R4 K1 - 0x8C100902, // 0003 GETMET R4 R4 K2 - 0x58180003, // 0004 LDCONST R6 K3 - 0x581C0004, // 0005 LDCONST R7 K4 - 0x7C100600, // 0006 CALL R4 3 - 0x50100000, // 0007 LDBOOL R4 0 0 - 0x80040800, // 0008 RET 1 R4 - 0xB8120200, // 0009 GETNGBL R4 K1 - 0x8C100902, // 000A GETMET R4 R4 K2 - 0xB81A0C00, // 000B GETNGBL R6 K6 - 0x8C180D07, // 000C GETMET R6 R6 K7 - 0x5C200200, // 000D MOVE R8 R1 - 0x7C180400, // 000E CALL R6 2 - 0x001A0A06, // 000F ADD R6 K5 R6 - 0x581C0008, // 0010 LDCONST R7 K8 - 0x7C100600, // 0011 CALL R4 3 - 0x88100309, // 0012 GETMBR R4 R1 K9 - 0x5416001F, // 0013 LDINT R5 32 - 0x1C100805, // 0014 EQ R4 R4 R5 - 0x78120006, // 0015 JMPF R4 #001D - 0x8C10010A, // 0016 GETMET R4 R0 K10 - 0x5C180200, // 0017 MOVE R6 R1 - 0x5C1C0400, // 0018 MOVE R7 R2 - 0x5C200600, // 0019 MOVE R8 R3 - 0x7C100800, // 001A CALL R4 4 - 0x80040800, // 001B RET 1 R4 - 0x7002002A, // 001C JMP #0048 - 0x88100309, // 001D GETMBR R4 R1 K9 - 0x54160021, // 001E LDINT R5 34 - 0x1C100805, // 001F EQ R4 R4 R5 - 0x78120006, // 0020 JMPF R4 #0028 - 0x8C10010B, // 0021 GETMET R4 R0 K11 - 0x5C180200, // 0022 MOVE R6 R1 - 0x5C1C0400, // 0023 MOVE R7 R2 - 0x5C200600, // 0024 MOVE R8 R3 - 0x7C100800, // 0025 CALL R4 4 - 0x80040800, // 0026 RET 1 R4 - 0x7002001F, // 0027 JMP #0048 - 0x88100309, // 0028 GETMBR R4 R1 K9 - 0x54160023, // 0029 LDINT R5 36 - 0x1C100805, // 002A EQ R4 R4 R5 - 0x78120006, // 002B JMPF R4 #0033 - 0x8C10010C, // 002C GETMET R4 R0 K12 - 0x5C180200, // 002D MOVE R6 R1 - 0x5C1C0400, // 002E MOVE R7 R2 - 0x5C200600, // 002F MOVE R8 R3 - 0x7C100800, // 0030 CALL R4 4 - 0x80040800, // 0031 RET 1 R4 - 0x70020014, // 0032 JMP #0048 - 0x88100309, // 0033 GETMBR R4 R1 K9 - 0x5416002F, // 0034 LDINT R5 48 - 0x1C100805, // 0035 EQ R4 R4 R5 - 0x78120006, // 0036 JMPF R4 #003E - 0x8C10010D, // 0037 GETMET R4 R0 K13 - 0x5C180200, // 0038 MOVE R6 R1 - 0x5C1C0400, // 0039 MOVE R7 R2 - 0x5C200600, // 003A MOVE R8 R3 - 0x7C100800, // 003B CALL R4 4 - 0x80040800, // 003C RET 1 R4 - 0x70020009, // 003D JMP #0048 - 0x88100309, // 003E GETMBR R4 R1 K9 - 0x54160031, // 003F LDINT R5 50 - 0x1C100805, // 0040 EQ R4 R4 R5 - 0x78120005, // 0041 JMPF R4 #0048 - 0x8C10010E, // 0042 GETMET R4 R0 K14 - 0x5C180200, // 0043 MOVE R6 R1 - 0x5C1C0400, // 0044 MOVE R7 R2 - 0x5C200600, // 0045 MOVE R8 R3 - 0x7C100800, // 0046 CALL R4 4 - 0x80040800, // 0047 RET 1 R4 - 0x50100000, // 0048 LDBOOL R4 0 0 - 0x80040800, // 0049 RET 1 R4 + ( &(const binstruction[64]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x740A0006, // 0001 JMPT R2 #0009 + 0xB80A0200, // 0002 GETNGBL R2 K1 + 0x8C080502, // 0003 GETMET R2 R2 K2 + 0x58100003, // 0004 LDCONST R4 K3 + 0x58140004, // 0005 LDCONST R5 K4 + 0x7C080600, // 0006 CALL R2 3 + 0x50080000, // 0007 LDBOOL R2 0 0 + 0x80040400, // 0008 RET 1 R2 + 0xB80A0200, // 0009 GETNGBL R2 K1 + 0x8C080502, // 000A GETMET R2 R2 K2 + 0xB8120C00, // 000B GETNGBL R4 K6 + 0x8C100907, // 000C GETMET R4 R4 K7 + 0x5C180200, // 000D MOVE R6 R1 + 0x7C100400, // 000E CALL R4 2 + 0x00120A04, // 000F ADD R4 K5 R4 + 0x58140008, // 0010 LDCONST R5 K8 + 0x7C080600, // 0011 CALL R2 3 + 0x88080309, // 0012 GETMBR R2 R1 K9 + 0x540E001F, // 0013 LDINT R3 32 + 0x1C080403, // 0014 EQ R2 R2 R3 + 0x780A0004, // 0015 JMPF R2 #001B + 0x8C08010A, // 0016 GETMET R2 R0 K10 + 0x5C100200, // 0017 MOVE R4 R1 + 0x7C080400, // 0018 CALL R2 2 + 0x80040400, // 0019 RET 1 R2 + 0x70020022, // 001A JMP #003E + 0x88080309, // 001B GETMBR R2 R1 K9 + 0x540E0021, // 001C LDINT R3 34 + 0x1C080403, // 001D EQ R2 R2 R3 + 0x780A0004, // 001E JMPF R2 #0024 + 0x8C08010B, // 001F GETMET R2 R0 K11 + 0x5C100200, // 0020 MOVE R4 R1 + 0x7C080400, // 0021 CALL R2 2 + 0x80040400, // 0022 RET 1 R2 + 0x70020019, // 0023 JMP #003E + 0x88080309, // 0024 GETMBR R2 R1 K9 + 0x540E0023, // 0025 LDINT R3 36 + 0x1C080403, // 0026 EQ R2 R2 R3 + 0x780A0004, // 0027 JMPF R2 #002D + 0x8C08010C, // 0028 GETMET R2 R0 K12 + 0x5C100200, // 0029 MOVE R4 R1 + 0x7C080400, // 002A CALL R2 2 + 0x80040400, // 002B RET 1 R2 + 0x70020010, // 002C JMP #003E + 0x88080309, // 002D GETMBR R2 R1 K9 + 0x540E002F, // 002E LDINT R3 48 + 0x1C080403, // 002F EQ R2 R2 R3 + 0x780A0004, // 0030 JMPF R2 #0036 + 0x8C08010D, // 0031 GETMET R2 R0 K13 + 0x5C100200, // 0032 MOVE R4 R1 + 0x7C080400, // 0033 CALL R2 2 + 0x80040400, // 0034 RET 1 R2 + 0x70020007, // 0035 JMP #003E + 0x88080309, // 0036 GETMBR R2 R1 K9 + 0x540E0031, // 0037 LDINT R3 50 + 0x1C080403, // 0038 EQ R2 R2 R3 + 0x780A0003, // 0039 JMPF R2 #003E + 0x8C08010E, // 003A GETMET R2 R0 K14 + 0x5C100200, // 003B MOVE R4 R1 + 0x7C080400, // 003C CALL R2 2 + 0x80040400, // 003D RET 1 R2 + 0x50080000, // 003E LDBOOL R2 0 0 + 0x80040400, // 003F RET 1 R2 }) ) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Device.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Device.h index 8040cef05..982db1afd 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Device.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Device.h @@ -7,196 +7,11 @@ extern const bclass be_class_Matter_Device; /******************************************************************** -** Solidified function: msg_send +** Solidified function: compute_manual_pairing_code ********************************************************************/ -be_local_closure(Matter_Device_msg_send, /* name */ +be_local_closure(Matter_Device_compute_manual_pairing_code, /* name */ be_nested_proto( 11, /* nstack */ - 5, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(udp_server), - /* K1 */ be_nested_str_weak(send_response), - }), - be_str_weak(msg_send), - &be_const_str_solidified, - ( &(const binstruction[ 8]) { /* code */ - 0x88140100, // 0000 GETMBR R5 R0 K0 - 0x8C140B01, // 0001 GETMET R5 R5 K1 - 0x5C1C0200, // 0002 MOVE R7 R1 - 0x5C200400, // 0003 MOVE R8 R2 - 0x5C240600, // 0004 MOVE R9 R3 - 0x5C280800, // 0005 MOVE R10 R4 - 0x7C140A00, // 0006 CALL R5 5 - 0x80040A00, // 0007 RET 1 R5 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: start_operational_dicovery_deferred -********************************************************************/ -be_local_closure(Matter_Device_start_operational_dicovery_deferred, /* name */ - be_nested_proto( - 6, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 1, /* has sup protos */ - ( &(const struct bproto*[ 1]) { - be_nested_proto( - 3, /* nstack */ - 0, /* argc */ - 0, /* varg */ - 1, /* has upvals */ - ( &(const bupvaldesc[ 2]) { /* upvals */ - be_local_const_upval(1, 0), - be_local_const_upval(1, 1), - }), - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(start_operational_dicovery), - }), - be_str_weak(_X3Clambda_X3E), - &be_const_str_solidified, - ( &(const binstruction[ 5]) { /* code */ - 0x68000000, // 0000 GETUPV R0 U0 - 0x8C000100, // 0001 GETMET R0 R0 K0 - 0x68080001, // 0002 GETUPV R2 U1 - 0x7C000400, // 0003 CALL R0 2 - 0x80040000, // 0004 RET 1 R0 - }) - ), - }), - 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_nested_str_weak(tasmota), - /* K1 */ be_nested_str_weak(set_timer), - /* K2 */ be_const_int(0), - }), - be_str_weak(start_operational_dicovery_deferred), - &be_const_str_solidified, - ( &(const binstruction[ 7]) { /* code */ - 0xB80A0000, // 0000 GETNGBL R2 K0 - 0x8C080501, // 0001 GETMET R2 R2 K1 - 0x58100002, // 0002 LDCONST R4 K2 - 0x84140000, // 0003 CLOSURE R5 P0 - 0x7C080600, // 0004 CALL R2 3 - 0xA0000000, // 0005 CLOSE R0 - 0x80000000, // 0006 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: start_commissioning_complete_deferred -********************************************************************/ -be_local_closure(Matter_Device_start_commissioning_complete_deferred, /* name */ - be_nested_proto( - 6, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 1, /* has sup protos */ - ( &(const struct bproto*[ 1]) { - be_nested_proto( - 3, /* nstack */ - 0, /* argc */ - 0, /* varg */ - 1, /* has upvals */ - ( &(const bupvaldesc[ 2]) { /* upvals */ - be_local_const_upval(1, 0), - be_local_const_upval(1, 1), - }), - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(start_commissioning_complete), - }), - be_str_weak(_X3Clambda_X3E), - &be_const_str_solidified, - ( &(const binstruction[ 5]) { /* code */ - 0x68000000, // 0000 GETUPV R0 U0 - 0x8C000100, // 0001 GETMET R0 R0 K0 - 0x68080001, // 0002 GETUPV R2 U1 - 0x7C000400, // 0003 CALL R0 2 - 0x80040000, // 0004 RET 1 R0 - }) - ), - }), - 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_nested_str_weak(tasmota), - /* K1 */ be_nested_str_weak(set_timer), - /* K2 */ be_const_int(0), - }), - be_str_weak(start_commissioning_complete_deferred), - &be_const_str_solidified, - ( &(const binstruction[ 7]) { /* code */ - 0xB80A0000, // 0000 GETNGBL R2 K0 - 0x8C080501, // 0001 GETMET R2 R2 K1 - 0x58100002, // 0002 LDCONST R4 K2 - 0x84140000, // 0003 CLOSURE R5 P0 - 0x7C080600, // 0004 CALL R2 3 - 0xA0000000, // 0005 CLOSE R0 - 0x80000000, // 0006 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: packet_ack -********************************************************************/ -be_local_closure(Matter_Device_packet_ack, /* name */ - be_nested_proto( - 5, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(udp_server), - /* K1 */ be_nested_str_weak(packet_ack), - }), - be_str_weak(packet_ack), - &be_const_str_solidified, - ( &(const binstruction[ 5]) { /* code */ - 0x88080100, // 0000 GETMBR R2 R0 K0 - 0x8C080501, // 0001 GETMET R2 R2 K1 - 0x5C100200, // 0002 MOVE R4 R1 - 0x7C080400, // 0003 CALL R2 2 - 0x80040400, // 0004 RET 1 R2 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: stop -********************************************************************/ -be_local_closure(Matter_Device_stop, /* name */ - be_nested_proto( - 3, /* nstack */ 1, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -204,19 +19,484 @@ be_local_closure(Matter_Device_stop, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(udp_server), - /* K1 */ be_nested_str_weak(stop), + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(discriminator), + /* K2 */ be_nested_str_weak(passcode), + /* K3 */ be_nested_str_weak(format), + /* K4 */ be_nested_str_weak(_X251i_X2505i_X2504i), + /* K5 */ be_nested_str_weak(matter), + /* K6 */ be_nested_str_weak(Verhoeff), + /* K7 */ be_nested_str_weak(checksum), }), - be_str_weak(stop), + be_str_weak(compute_manual_pairing_code), &be_const_str_solidified, - ( &(const binstruction[ 6]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x78060002, // 0001 JMPF R1 #0005 - 0x88040100, // 0002 GETMBR R1 R0 K0 - 0x8C040301, // 0003 GETMET R1 R1 K1 - 0x7C040200, // 0004 CALL R1 1 - 0x80000000, // 0005 RET 0 + ( &(const binstruction[31]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x88080101, // 0001 GETMBR R2 R0 K1 + 0x540E0FFE, // 0002 LDINT R3 4095 + 0x2C080403, // 0003 AND R2 R2 R3 + 0x540E0009, // 0004 LDINT R3 10 + 0x3C080403, // 0005 SHR R2 R2 R3 + 0x880C0101, // 0006 GETMBR R3 R0 K1 + 0x541202FF, // 0007 LDINT R4 768 + 0x2C0C0604, // 0008 AND R3 R3 R4 + 0x54120005, // 0009 LDINT R4 6 + 0x380C0604, // 000A SHL R3 R3 R4 + 0x88100102, // 000B GETMBR R4 R0 K2 + 0x54163FFE, // 000C LDINT R5 16383 + 0x2C100805, // 000D AND R4 R4 R5 + 0x300C0604, // 000E OR R3 R3 R4 + 0x88100102, // 000F GETMBR R4 R0 K2 + 0x5416000D, // 0010 LDINT R5 14 + 0x3C100805, // 0011 SHR R4 R4 R5 + 0x8C140303, // 0012 GETMET R5 R1 K3 + 0x581C0004, // 0013 LDCONST R7 K4 + 0x5C200400, // 0014 MOVE R8 R2 + 0x5C240600, // 0015 MOVE R9 R3 + 0x5C280800, // 0016 MOVE R10 R4 + 0x7C140A00, // 0017 CALL R5 5 + 0xB81A0A00, // 0018 GETNGBL R6 K5 + 0x88180D06, // 0019 GETMBR R6 R6 K6 + 0x8C180D07, // 001A GETMET R6 R6 K7 + 0x5C200A00, // 001B MOVE R8 R5 + 0x7C180400, // 001C CALL R6 2 + 0x00140A06, // 001D ADD R5 R5 R6 + 0x80040A00, // 001E RET 1 R5 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: process_attribute_expansion +********************************************************************/ +be_local_closure(Matter_Device_process_attribute_expansion, /* name */ + be_nested_proto( + 33, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[25]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(endpoint), + /* K2 */ be_nested_str_weak(cluster), + /* K3 */ be_nested_str_weak(attribute), + /* K4 */ be_nested_str_weak(tasmota), + /* K5 */ be_nested_str_weak(log), + /* K6 */ be_nested_str_weak(format), + /* K7 */ be_nested_str_weak(MTR_X3A_X20process_attribute_expansion_X20_X25s), + /* K8 */ be_const_int(3), + /* K9 */ be_nested_str_weak(plugins), + /* K10 */ be_nested_str_weak(get_endpoints), + /* K11 */ be_nested_str_weak(MTR_X3A_X20ep_list_X20_X25s_X20_X25s), + /* K12 */ be_nested_str_weak(find), + /* K13 */ be_nested_str_weak(get_cluster_list), + /* K14 */ be_nested_str_weak(MTR_X3A_X20cluster_list_X20_X25s_X20_X25s), + /* K15 */ be_nested_str_weak(get_attribute_list), + /* K16 */ be_nested_str_weak(MTR_X3A_X20attr_list_X20_X25s_X20_X25s), + /* K17 */ be_nested_str_weak(MTR_X3A_X20expansion_X20_X5B_X2502X_X5D_X2504X_X2F_X2504X), + /* K18 */ be_nested_str_weak(stop_iteration), + /* K19 */ be_nested_str_weak(status), + /* K20 */ be_nested_str_weak(matter), + /* K21 */ be_nested_str_weak(UNSUPPORTED_ENDPOINT), + /* K22 */ be_nested_str_weak(UNSUPPORTED_CLUSTER), + /* K23 */ be_nested_str_weak(UNSUPPORTED_ATTRIBUTE), + /* K24 */ be_nested_str_weak(UNREPORTABLE_ATTRIBUTE), + }), + be_str_weak(process_attribute_expansion), + &be_const_str_solidified, + ( &(const binstruction[216]) { /* code */ + 0xA40E0000, // 0000 IMPORT R3 K0 + 0x88100301, // 0001 GETMBR R4 R1 K1 + 0x60140012, // 0002 GETGBL R5 G18 + 0x7C140000, // 0003 CALL R5 0 + 0x40180A04, // 0004 CONNECT R6 R5 R4 + 0x50180000, // 0005 LDBOOL R6 0 0 + 0x881C0302, // 0006 GETMBR R7 R1 K2 + 0x60200012, // 0007 GETGBL R8 G18 + 0x7C200000, // 0008 CALL R8 0 + 0x40241007, // 0009 CONNECT R9 R8 R7 + 0x50240000, // 000A LDBOOL R9 0 0 + 0x88280303, // 000B GETMBR R10 R1 K3 + 0x602C0012, // 000C GETGBL R11 G18 + 0x7C2C0000, // 000D CALL R11 0 + 0x4030160A, // 000E CONNECT R12 R11 R10 + 0x50300000, // 000F LDBOOL R12 0 0 + 0x88340301, // 0010 GETMBR R13 R1 K1 + 0x4C380000, // 0011 LDNIL R14 + 0x20341A0E, // 0012 NE R13 R13 R14 + 0x78360007, // 0013 JMPF R13 #001C + 0x88340302, // 0014 GETMBR R13 R1 K2 + 0x4C380000, // 0015 LDNIL R14 + 0x20341A0E, // 0016 NE R13 R13 R14 + 0x78360003, // 0017 JMPF R13 #001C + 0x88340303, // 0018 GETMBR R13 R1 K3 + 0x4C380000, // 0019 LDNIL R14 + 0x20341A0E, // 001A NE R13 R13 R14 + 0x74360000, // 001B JMPT R13 #001D + 0x50340001, // 001C LDBOOL R13 0 1 + 0x50340200, // 001D LDBOOL R13 1 0 + 0xB83A0800, // 001E GETNGBL R14 K4 + 0x8C381D05, // 001F GETMET R14 R14 K5 + 0x8C400706, // 0020 GETMET R16 R3 K6 + 0x58480007, // 0021 LDCONST R18 K7 + 0x604C0008, // 0022 GETGBL R19 G8 + 0x5C500200, // 0023 MOVE R20 R1 + 0x7C4C0200, // 0024 CALL R19 1 + 0x7C400600, // 0025 CALL R16 3 + 0x58440008, // 0026 LDCONST R17 K8 + 0x7C380600, // 0027 CALL R14 3 + 0x60380010, // 0028 GETGBL R14 G16 + 0x883C0109, // 0029 GETMBR R15 R0 K9 + 0x7C380200, // 002A CALL R14 1 + 0xA802008C, // 002B EXBLK 0 #00B9 + 0x5C3C1C00, // 002C MOVE R15 R14 + 0x7C3C0000, // 002D CALL R15 0 + 0x8C401F0A, // 002E GETMET R16 R15 K10 + 0x7C400200, // 002F CALL R16 1 + 0xB8460800, // 0030 GETNGBL R17 K4 + 0x8C442305, // 0031 GETMET R17 R17 K5 + 0x8C4C0706, // 0032 GETMET R19 R3 K6 + 0x5854000B, // 0033 LDCONST R21 K11 + 0x60580008, // 0034 GETGBL R22 G8 + 0x5C5C1E00, // 0035 MOVE R23 R15 + 0x7C580200, // 0036 CALL R22 1 + 0x605C0008, // 0037 GETGBL R23 G8 + 0x5C602000, // 0038 MOVE R24 R16 + 0x7C5C0200, // 0039 CALL R23 1 + 0x7C4C0800, // 003A CALL R19 4 + 0x58500008, // 003B LDCONST R20 K8 + 0x7C440600, // 003C CALL R17 3 + 0x4C440000, // 003D LDNIL R17 + 0x20440811, // 003E NE R17 R4 R17 + 0x78460009, // 003F JMPF R17 #004A + 0x8C44210C, // 0040 GETMET R17 R16 K12 + 0x5C4C0800, // 0041 MOVE R19 R4 + 0x7C440400, // 0042 CALL R17 2 + 0x4C480000, // 0043 LDNIL R18 + 0x20442212, // 0044 NE R17 R17 R18 + 0x78460002, // 0045 JMPF R17 #0049 + 0x5C400A00, // 0046 MOVE R16 R5 + 0x50180200, // 0047 LDBOOL R6 1 0 + 0x70020000, // 0048 JMP #004A + 0x7001FFE1, // 0049 JMP #002C + 0x60440010, // 004A GETGBL R17 G16 + 0x5C482000, // 004B MOVE R18 R16 + 0x7C440200, // 004C CALL R17 1 + 0xA8020066, // 004D EXBLK 0 #00B5 + 0x5C482200, // 004E MOVE R18 R17 + 0x7C480000, // 004F CALL R18 0 + 0x8C4C1F0D, // 0050 GETMET R19 R15 K13 + 0x5C542400, // 0051 MOVE R21 R18 + 0x7C4C0400, // 0052 CALL R19 2 + 0xB8520800, // 0053 GETNGBL R20 K4 + 0x8C502905, // 0054 GETMET R20 R20 K5 + 0x8C580706, // 0055 GETMET R22 R3 K6 + 0x5860000E, // 0056 LDCONST R24 K14 + 0x60640008, // 0057 GETGBL R25 G8 + 0x5C682400, // 0058 MOVE R26 R18 + 0x7C640200, // 0059 CALL R25 1 + 0x60680008, // 005A GETGBL R26 G8 + 0x5C6C2600, // 005B MOVE R27 R19 + 0x7C680200, // 005C CALL R26 1 + 0x7C580800, // 005D CALL R22 4 + 0x585C0008, // 005E LDCONST R23 K8 + 0x7C500600, // 005F CALL R20 3 + 0x4C500000, // 0060 LDNIL R20 + 0x20500E14, // 0061 NE R20 R7 R20 + 0x78520009, // 0062 JMPF R20 #006D + 0x8C50270C, // 0063 GETMET R20 R19 K12 + 0x5C580E00, // 0064 MOVE R22 R7 + 0x7C500400, // 0065 CALL R20 2 + 0x4C540000, // 0066 LDNIL R21 + 0x20502815, // 0067 NE R20 R20 R21 + 0x78520002, // 0068 JMPF R20 #006C + 0x5C4C1000, // 0069 MOVE R19 R8 + 0x50240200, // 006A LDBOOL R9 1 0 + 0x70020000, // 006B JMP #006D + 0x7001FFE0, // 006C JMP #004E + 0x60500010, // 006D GETGBL R20 G16 + 0x5C542600, // 006E MOVE R21 R19 + 0x7C500200, // 006F CALL R20 1 + 0xA802003F, // 0070 EXBLK 0 #00B1 + 0x5C542800, // 0071 MOVE R21 R20 + 0x7C540000, // 0072 CALL R21 0 + 0x8C581F0F, // 0073 GETMET R22 R15 K15 + 0x5C602400, // 0074 MOVE R24 R18 + 0x5C640E00, // 0075 MOVE R25 R7 + 0x7C580600, // 0076 CALL R22 3 + 0xB85E0800, // 0077 GETNGBL R23 K4 + 0x8C5C2F05, // 0078 GETMET R23 R23 K5 + 0x8C640706, // 0079 GETMET R25 R3 K6 + 0x586C0010, // 007A LDCONST R27 K16 + 0x60700008, // 007B GETGBL R28 G8 + 0x5C742A00, // 007C MOVE R29 R21 + 0x7C700200, // 007D CALL R28 1 + 0x60740008, // 007E GETGBL R29 G8 + 0x5C782C00, // 007F MOVE R30 R22 + 0x7C740200, // 0080 CALL R29 1 + 0x7C640800, // 0081 CALL R25 4 + 0x58680008, // 0082 LDCONST R26 K8 + 0x7C5C0600, // 0083 CALL R23 3 + 0x4C5C0000, // 0084 LDNIL R23 + 0x205C1417, // 0085 NE R23 R10 R23 + 0x785E0028, // 0086 JMPF R23 #00B0 + 0x8C5C2D0C, // 0087 GETMET R23 R22 K12 + 0x5C641400, // 0088 MOVE R25 R10 + 0x7C5C0400, // 0089 CALL R23 2 + 0x4C600000, // 008A LDNIL R24 + 0x205C2E18, // 008B NE R23 R23 R24 + 0x785E0002, // 008C JMPF R23 #0090 + 0x5C581600, // 008D MOVE R22 R11 + 0x50300200, // 008E LDBOOL R12 1 0 + 0x70020000, // 008F JMP #0091 + 0x7001FFDF, // 0090 JMP #0071 + 0x605C0010, // 0091 GETGBL R23 G16 + 0x5C602C00, // 0092 MOVE R24 R22 + 0x7C5C0200, // 0093 CALL R23 1 + 0xA8020017, // 0094 EXBLK 0 #00AD + 0x5C602E00, // 0095 MOVE R24 R23 + 0x7C600000, // 0096 CALL R24 0 + 0xB8660800, // 0097 GETNGBL R25 K4 + 0x8C643305, // 0098 GETMET R25 R25 K5 + 0x8C6C0706, // 0099 GETMET R27 R3 K6 + 0x58740011, // 009A LDCONST R29 K17 + 0x5C782400, // 009B MOVE R30 R18 + 0x5C7C2A00, // 009C MOVE R31 R21 + 0x5C803000, // 009D MOVE R32 R24 + 0x7C6C0A00, // 009E CALL R27 5 + 0x58700008, // 009F LDCONST R28 K8 + 0x7C640600, // 00A0 CALL R25 3 + 0x90060212, // 00A1 SETMBR R1 K1 R18 + 0x90060415, // 00A2 SETMBR R1 K2 R21 + 0x90060618, // 00A3 SETMBR R1 K3 R24 + 0x5C640400, // 00A4 MOVE R25 R2 + 0x5C681E00, // 00A5 MOVE R26 R15 + 0x5C6C0200, // 00A6 MOVE R27 R1 + 0x5C701A00, // 00A7 MOVE R28 R13 + 0x7C640600, // 00A8 CALL R25 3 + 0x78660001, // 00A9 JMPF R25 #00AC + 0xA8040004, // 00AA EXBLK 1 4 + 0x80003400, // 00AB RET 0 + 0x7001FFE7, // 00AC JMP #0095 + 0x585C0012, // 00AD LDCONST R23 K18 + 0xAC5C0200, // 00AE CATCH R23 1 0 + 0xB0080000, // 00AF RAISE 2 R0 R0 + 0x7001FFBF, // 00B0 JMP #0071 + 0x58500012, // 00B1 LDCONST R20 K18 + 0xAC500200, // 00B2 CATCH R20 1 0 + 0xB0080000, // 00B3 RAISE 2 R0 R0 + 0x7001FF98, // 00B4 JMP #004E + 0x58440012, // 00B5 LDCONST R17 K18 + 0xAC440200, // 00B6 CATCH R17 1 0 + 0xB0080000, // 00B7 RAISE 2 R0 R0 + 0x7001FF72, // 00B8 JMP #002C + 0x58380012, // 00B9 LDCONST R14 K18 + 0xAC380200, // 00BA CATCH R14 1 0 + 0xB0080000, // 00BB RAISE 2 R0 R0 + 0x78360019, // 00BC JMPF R13 #00D7 + 0x5C380C00, // 00BD MOVE R14 R6 + 0x743A0003, // 00BE JMPT R14 #00C3 + 0xB83A2800, // 00BF GETNGBL R14 K20 + 0x88381D15, // 00C0 GETMBR R14 R14 K21 + 0x9006260E, // 00C1 SETMBR R1 K19 R14 + 0x7002000E, // 00C2 JMP #00D2 + 0x5C381200, // 00C3 MOVE R14 R9 + 0x743A0003, // 00C4 JMPT R14 #00C9 + 0xB83A2800, // 00C5 GETNGBL R14 K20 + 0x88381D16, // 00C6 GETMBR R14 R14 K22 + 0x9006260E, // 00C7 SETMBR R1 K19 R14 + 0x70020008, // 00C8 JMP #00D2 + 0x5C381800, // 00C9 MOVE R14 R12 + 0x743A0003, // 00CA JMPT R14 #00CF + 0xB83A2800, // 00CB GETNGBL R14 K20 + 0x88381D17, // 00CC GETMBR R14 R14 K23 + 0x9006260E, // 00CD SETMBR R1 K19 R14 + 0x70020002, // 00CE JMP #00D2 + 0xB83A2800, // 00CF GETNGBL R14 K20 + 0x88381D18, // 00D0 GETMBR R14 R14 K24 + 0x9006260E, // 00D1 SETMBR R1 K19 R14 + 0x5C380400, // 00D2 MOVE R14 R2 + 0x4C3C0000, // 00D3 LDNIL R15 + 0x5C400200, // 00D4 MOVE R16 R1 + 0x50440200, // 00D5 LDBOOL R17 1 0 + 0x7C380600, // 00D6 CALL R14 3 + 0x80000000, // 00D7 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: save_param +********************************************************************/ +be_local_closure(Matter_Device_save_param, /* name */ + be_nested_proto( + 10, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[15]) { /* constants */ + /* K0 */ be_nested_str_weak(json), + /* K1 */ be_nested_str_weak(dump), + /* K2 */ be_nested_str_weak(distinguish), + /* K3 */ be_nested_str_weak(discriminator), + /* K4 */ be_nested_str_weak(passcode), + /* K5 */ be_nested_str_weak(string), + /* K6 */ be_nested_str_weak(FILENAME), + /* K7 */ be_nested_str_weak(w), + /* K8 */ be_nested_str_weak(write), + /* K9 */ be_nested_str_weak(close), + /* K10 */ be_nested_str_weak(tasmota), + /* K11 */ be_nested_str_weak(log), + /* K12 */ be_nested_str_weak(MTR_X3A_X20Session_Store_X3A_X3Asave_X20Exception_X3A), + /* K13 */ be_nested_str_weak(_X7C), + /* K14 */ be_const_int(2), + }), + be_str_weak(save_param), + &be_const_str_solidified, + ( &(const binstruction[43]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x8C080301, // 0001 GETMET R2 R1 K1 + 0x60100013, // 0002 GETGBL R4 G19 + 0x7C100000, // 0003 CALL R4 0 + 0x88140103, // 0004 GETMBR R5 R0 K3 + 0x98120405, // 0005 SETIDX R4 K2 R5 + 0x88140104, // 0006 GETMBR R5 R0 K4 + 0x98120805, // 0007 SETIDX R4 K4 R5 + 0x7C080400, // 0008 CALL R2 2 + 0xA802000D, // 0009 EXBLK 0 #0018 + 0xA40E0A00, // 000A IMPORT R3 K5 + 0x60100011, // 000B GETGBL R4 G17 + 0x88140106, // 000C GETMBR R5 R0 K6 + 0x58180007, // 000D LDCONST R6 K7 + 0x7C100400, // 000E CALL R4 2 + 0x8C140908, // 000F GETMET R5 R4 K8 + 0x5C1C0400, // 0010 MOVE R7 R2 + 0x7C140400, // 0011 CALL R5 2 + 0x8C140909, // 0012 GETMET R5 R4 K9 + 0x7C140200, // 0013 CALL R5 1 + 0xA8040001, // 0014 EXBLK 1 1 + 0x80040400, // 0015 RET 1 R2 + 0xA8040001, // 0016 EXBLK 1 1 + 0x70020011, // 0017 JMP #002A + 0xAC0C0002, // 0018 CATCH R3 0 2 + 0x7002000E, // 0019 JMP #0029 + 0xB8161400, // 001A GETNGBL R5 K10 + 0x8C140B0B, // 001B GETMET R5 R5 K11 + 0x601C0008, // 001C GETGBL R7 G8 + 0x5C200600, // 001D MOVE R8 R3 + 0x7C1C0200, // 001E CALL R7 1 + 0x001E1807, // 001F ADD R7 K12 R7 + 0x001C0F0D, // 0020 ADD R7 R7 K13 + 0x60200008, // 0021 GETGBL R8 G8 + 0x5C240800, // 0022 MOVE R9 R4 + 0x7C200200, // 0023 CALL R8 1 + 0x001C0E08, // 0024 ADD R7 R7 R8 + 0x5820000E, // 0025 LDCONST R8 K14 + 0x7C140600, // 0026 CALL R5 3 + 0x80040400, // 0027 RET 1 R2 + 0x70020000, // 0028 JMP #002A + 0xB0080000, // 0029 RAISE 2 R0 R0 + 0x80000000, // 002A RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: start_udp +********************************************************************/ +be_local_closure(Matter_Device_start_udp, /* name */ + be_nested_proto( + 6, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 1, /* has sup protos */ + ( &(const struct bproto*[ 1]) { + be_nested_proto( + 8, /* nstack */ + 3, /* argc */ + 0, /* varg */ + 1, /* has upvals */ + ( &(const bupvaldesc[ 1]) { /* upvals */ + be_local_const_upval(1, 0), + }), + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(msg_received), + }), + be_str_weak(_X3Clambda_X3E), + &be_const_str_solidified, + ( &(const binstruction[ 7]) { /* code */ + 0x680C0000, // 0000 GETUPV R3 U0 + 0x8C0C0700, // 0001 GETMET R3 R3 K0 + 0x5C140000, // 0002 MOVE R5 R0 + 0x5C180200, // 0003 MOVE R6 R1 + 0x5C1C0400, // 0004 MOVE R7 R2 + 0x7C0C0800, // 0005 CALL R3 4 + 0x80040600, // 0006 RET 1 R3 + }) + ), + }), + 1, /* has constants */ + ( &(const bvalue[ 9]) { /* constants */ + /* K0 */ be_nested_str_weak(udp_server), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(log), + /* K3 */ be_nested_str_weak(MTR_X3A_X20starting_X20UDP_X20server_X20on_X20port_X3A_X20), + /* K4 */ be_const_int(2), + /* K5 */ be_nested_str_weak(matter), + /* K6 */ be_nested_str_weak(UDPServer), + /* K7 */ be_nested_str_weak(), + /* K8 */ be_nested_str_weak(start), + }), + be_str_weak(start_udp), + &be_const_str_solidified, + ( &(const binstruction[27]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x780A0000, // 0001 JMPF R2 #0003 + 0x80000400, // 0002 RET 0 + 0x4C080000, // 0003 LDNIL R2 + 0x1C080202, // 0004 EQ R2 R1 R2 + 0x780A0000, // 0005 JMPF R2 #0007 + 0x540615A3, // 0006 LDINT R1 5540 + 0xB80A0200, // 0007 GETNGBL R2 K1 + 0x8C080502, // 0008 GETMET R2 R2 K2 + 0x60100008, // 0009 GETGBL R4 G8 + 0x5C140200, // 000A MOVE R5 R1 + 0x7C100200, // 000B CALL R4 1 + 0x00120604, // 000C ADD R4 K3 R4 + 0x58140004, // 000D LDCONST R5 K4 + 0x7C080600, // 000E CALL R2 3 + 0xB80A0A00, // 000F GETNGBL R2 K5 + 0x8C080506, // 0010 GETMET R2 R2 K6 + 0x58100007, // 0011 LDCONST R4 K7 + 0x5C140200, // 0012 MOVE R5 R1 + 0x7C080600, // 0013 CALL R2 3 + 0x90020002, // 0014 SETMBR R0 K0 R2 + 0x88080100, // 0015 GETMBR R2 R0 K0 + 0x8C080508, // 0016 GETMET R2 R2 K8 + 0x84100000, // 0017 CLOSURE R4 P0 + 0x7C080400, // 0018 CALL R2 2 + 0xA0000000, // 0019 CLOSE R0 + 0x80000000, // 001A RET 0 }) ) ); @@ -340,250 +620,9 @@ be_local_closure(Matter_Device_load_param, /* name */ /******************************************************************** -** Solidified function: every_second +** Solidified function: start_operational_dicovery_deferred ********************************************************************/ -be_local_closure(Matter_Device_every_second, /* name */ - be_nested_proto( - 3, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_nested_str_weak(sessions), - /* K1 */ be_nested_str_weak(every_second), - /* K2 */ be_nested_str_weak(msg_handler), - }), - be_str_weak(every_second), - &be_const_str_solidified, - ( &(const binstruction[ 7]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x8C040301, // 0001 GETMET R1 R1 K1 - 0x7C040200, // 0002 CALL R1 1 - 0x88040102, // 0003 GETMBR R1 R0 K2 - 0x8C040301, // 0004 GETMET R1 R1 K1 - 0x7C040200, // 0005 CALL R1 1 - 0x80000000, // 0006 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: save_param -********************************************************************/ -be_local_closure(Matter_Device_save_param, /* name */ - be_nested_proto( - 10, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[15]) { /* constants */ - /* K0 */ be_nested_str_weak(json), - /* K1 */ be_nested_str_weak(dump), - /* K2 */ be_nested_str_weak(distinguish), - /* K3 */ be_nested_str_weak(discriminator), - /* K4 */ be_nested_str_weak(passcode), - /* K5 */ be_nested_str_weak(string), - /* K6 */ be_nested_str_weak(FILENAME), - /* K7 */ be_nested_str_weak(w), - /* K8 */ be_nested_str_weak(write), - /* K9 */ be_nested_str_weak(close), - /* K10 */ be_nested_str_weak(tasmota), - /* K11 */ be_nested_str_weak(log), - /* K12 */ be_nested_str_weak(MTR_X3A_X20Session_Store_X3A_X3Asave_X20Exception_X3A), - /* K13 */ be_nested_str_weak(_X7C), - /* K14 */ be_const_int(2), - }), - be_str_weak(save_param), - &be_const_str_solidified, - ( &(const binstruction[43]) { /* code */ - 0xA4060000, // 0000 IMPORT R1 K0 - 0x8C080301, // 0001 GETMET R2 R1 K1 - 0x60100013, // 0002 GETGBL R4 G19 - 0x7C100000, // 0003 CALL R4 0 - 0x88140103, // 0004 GETMBR R5 R0 K3 - 0x98120405, // 0005 SETIDX R4 K2 R5 - 0x88140104, // 0006 GETMBR R5 R0 K4 - 0x98120805, // 0007 SETIDX R4 K4 R5 - 0x7C080400, // 0008 CALL R2 2 - 0xA802000D, // 0009 EXBLK 0 #0018 - 0xA40E0A00, // 000A IMPORT R3 K5 - 0x60100011, // 000B GETGBL R4 G17 - 0x88140106, // 000C GETMBR R5 R0 K6 - 0x58180007, // 000D LDCONST R6 K7 - 0x7C100400, // 000E CALL R4 2 - 0x8C140908, // 000F GETMET R5 R4 K8 - 0x5C1C0400, // 0010 MOVE R7 R2 - 0x7C140400, // 0011 CALL R5 2 - 0x8C140909, // 0012 GETMET R5 R4 K9 - 0x7C140200, // 0013 CALL R5 1 - 0xA8040001, // 0014 EXBLK 1 1 - 0x80040400, // 0015 RET 1 R2 - 0xA8040001, // 0016 EXBLK 1 1 - 0x70020011, // 0017 JMP #002A - 0xAC0C0002, // 0018 CATCH R3 0 2 - 0x7002000E, // 0019 JMP #0029 - 0xB8161400, // 001A GETNGBL R5 K10 - 0x8C140B0B, // 001B GETMET R5 R5 K11 - 0x601C0008, // 001C GETGBL R7 G8 - 0x5C200600, // 001D MOVE R8 R3 - 0x7C1C0200, // 001E CALL R7 1 - 0x001E1807, // 001F ADD R7 K12 R7 - 0x001C0F0D, // 0020 ADD R7 R7 K13 - 0x60200008, // 0021 GETGBL R8 G8 - 0x5C240800, // 0022 MOVE R9 R4 - 0x7C200200, // 0023 CALL R8 1 - 0x001C0E08, // 0024 ADD R7 R7 R8 - 0x5820000E, // 0025 LDCONST R8 K14 - 0x7C140600, // 0026 CALL R5 3 - 0x80040400, // 0027 RET 1 R2 - 0x70020000, // 0028 JMP #002A - 0xB0080000, // 0029 RAISE 2 R0 R0 - 0x80000000, // 002A RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: start_operational_dicovery -********************************************************************/ -be_local_closure(Matter_Device_start_operational_dicovery, /* name */ - be_nested_proto( - 8, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[13]) { /* constants */ - /* K0 */ be_nested_str_weak(crypto), - /* K1 */ be_nested_str_weak(mdns), - /* K2 */ be_nested_str_weak(string), - /* K3 */ be_nested_str_weak(salt), - /* K4 */ be_nested_str_weak(w0), - /* K5 */ be_nested_str_weak(w1), - /* K6 */ be_nested_str_weak(L), - /* K7 */ be_nested_str_weak(set_no_expiration), - /* K8 */ be_nested_str_weak(set_persist), - /* K9 */ be_nested_str_weak(close), - /* K10 */ be_nested_str_weak(sessions), - /* K11 */ be_nested_str_weak(save), - /* K12 */ be_nested_str_weak(mdns_announce_op_discovery), - }), - be_str_weak(start_operational_dicovery), - &be_const_str_solidified, - ( &(const binstruction[25]) { /* code */ - 0xA40A0000, // 0000 IMPORT R2 K0 - 0xA40E0200, // 0001 IMPORT R3 K1 - 0xA4120400, // 0002 IMPORT R4 K2 - 0x4C140000, // 0003 LDNIL R5 - 0x90020605, // 0004 SETMBR R0 K3 R5 - 0x4C140000, // 0005 LDNIL R5 - 0x90020805, // 0006 SETMBR R0 K4 R5 - 0x4C140000, // 0007 LDNIL R5 - 0x90020A05, // 0008 SETMBR R0 K5 R5 - 0x4C140000, // 0009 LDNIL R5 - 0x90020C05, // 000A SETMBR R0 K6 R5 - 0x8C140307, // 000B GETMET R5 R1 K7 - 0x7C140200, // 000C CALL R5 1 - 0x8C140308, // 000D GETMET R5 R1 K8 - 0x501C0200, // 000E LDBOOL R7 1 0 - 0x7C140400, // 000F CALL R5 2 - 0x8C140309, // 0010 GETMET R5 R1 K9 - 0x7C140200, // 0011 CALL R5 1 - 0x8814010A, // 0012 GETMBR R5 R0 K10 - 0x8C140B0B, // 0013 GETMET R5 R5 K11 - 0x7C140200, // 0014 CALL R5 1 - 0x8C14010C, // 0015 GETMET R5 R0 K12 - 0x5C1C0200, // 0016 MOVE R7 R1 - 0x7C140400, // 0017 CALL R5 2 - 0x80000000, // 0018 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: compute_manual_pairing_code -********************************************************************/ -be_local_closure(Matter_Device_compute_manual_pairing_code, /* name */ - be_nested_proto( - 11, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 8]) { /* constants */ - /* K0 */ be_nested_str_weak(string), - /* K1 */ be_nested_str_weak(discriminator), - /* K2 */ be_nested_str_weak(passcode), - /* K3 */ be_nested_str_weak(format), - /* K4 */ be_nested_str_weak(_X251i_X2505i_X2504i), - /* K5 */ be_nested_str_weak(matter), - /* K6 */ be_nested_str_weak(Verhoeff), - /* K7 */ be_nested_str_weak(checksum), - }), - be_str_weak(compute_manual_pairing_code), - &be_const_str_solidified, - ( &(const binstruction[31]) { /* code */ - 0xA4060000, // 0000 IMPORT R1 K0 - 0x88080101, // 0001 GETMBR R2 R0 K1 - 0x540E0FFE, // 0002 LDINT R3 4095 - 0x2C080403, // 0003 AND R2 R2 R3 - 0x540E0009, // 0004 LDINT R3 10 - 0x3C080403, // 0005 SHR R2 R2 R3 - 0x880C0101, // 0006 GETMBR R3 R0 K1 - 0x541202FF, // 0007 LDINT R4 768 - 0x2C0C0604, // 0008 AND R3 R3 R4 - 0x54120005, // 0009 LDINT R4 6 - 0x380C0604, // 000A SHL R3 R3 R4 - 0x88100102, // 000B GETMBR R4 R0 K2 - 0x54163FFE, // 000C LDINT R5 16383 - 0x2C100805, // 000D AND R4 R4 R5 - 0x300C0604, // 000E OR R3 R3 R4 - 0x88100102, // 000F GETMBR R4 R0 K2 - 0x5416000D, // 0010 LDINT R5 14 - 0x3C100805, // 0011 SHR R4 R4 R5 - 0x8C140303, // 0012 GETMET R5 R1 K3 - 0x581C0004, // 0013 LDCONST R7 K4 - 0x5C200400, // 0014 MOVE R8 R2 - 0x5C240600, // 0015 MOVE R9 R3 - 0x5C280800, // 0016 MOVE R10 R4 - 0x7C140A00, // 0017 CALL R5 5 - 0xB81A0A00, // 0018 GETNGBL R6 K5 - 0x88180D06, // 0019 GETMBR R6 R6 K6 - 0x8C180D07, // 001A GETMET R6 R6 K7 - 0x5C200A00, // 001B MOVE R8 R5 - 0x7C180400, // 001C CALL R6 2 - 0x00140A06, // 001D ADD R5 R5 R6 - 0x80040A00, // 001E RET 1 R5 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: start_udp -********************************************************************/ -be_local_closure(Matter_Device_start_udp, /* name */ +be_local_closure(Matter_Device_start_operational_dicovery_deferred, /* name */ be_nested_proto( 6, /* nstack */ 2, /* argc */ @@ -593,74 +632,47 @@ be_local_closure(Matter_Device_start_udp, /* name */ 1, /* has sup protos */ ( &(const struct bproto*[ 1]) { be_nested_proto( - 8, /* nstack */ - 3, /* argc */ + 3, /* nstack */ + 0, /* argc */ 0, /* varg */ 1, /* has upvals */ - ( &(const bupvaldesc[ 1]) { /* upvals */ + ( &(const bupvaldesc[ 2]) { /* upvals */ be_local_const_upval(1, 0), + be_local_const_upval(1, 1), }), 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(msg_received), + /* K0 */ be_nested_str_weak(start_operational_dicovery), }), be_str_weak(_X3Clambda_X3E), &be_const_str_solidified, - ( &(const binstruction[ 7]) { /* code */ - 0x680C0000, // 0000 GETUPV R3 U0 - 0x8C0C0700, // 0001 GETMET R3 R3 K0 - 0x5C140000, // 0002 MOVE R5 R0 - 0x5C180200, // 0003 MOVE R6 R1 - 0x5C1C0400, // 0004 MOVE R7 R2 - 0x7C0C0800, // 0005 CALL R3 4 - 0x80040600, // 0006 RET 1 R3 + ( &(const binstruction[ 5]) { /* code */ + 0x68000000, // 0000 GETUPV R0 U0 + 0x8C000100, // 0001 GETMET R0 R0 K0 + 0x68080001, // 0002 GETUPV R2 U1 + 0x7C000400, // 0003 CALL R0 2 + 0x80040000, // 0004 RET 1 R0 }) ), }), 1, /* has constants */ - ( &(const bvalue[ 9]) { /* constants */ - /* K0 */ be_nested_str_weak(udp_server), - /* K1 */ be_nested_str_weak(tasmota), - /* K2 */ be_nested_str_weak(log), - /* K3 */ be_nested_str_weak(MTR_X3A_X20starting_X20UDP_X20server_X20on_X20port_X3A_X20), - /* K4 */ be_const_int(2), - /* K5 */ be_nested_str_weak(matter), - /* K6 */ be_nested_str_weak(UDPServer), - /* K7 */ be_nested_str_weak(), - /* K8 */ be_nested_str_weak(start), + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(tasmota), + /* K1 */ be_nested_str_weak(set_timer), + /* K2 */ be_const_int(0), }), - be_str_weak(start_udp), + be_str_weak(start_operational_dicovery_deferred), &be_const_str_solidified, - ( &(const binstruction[27]) { /* code */ - 0x88080100, // 0000 GETMBR R2 R0 K0 - 0x780A0000, // 0001 JMPF R2 #0003 - 0x80000400, // 0002 RET 0 - 0x4C080000, // 0003 LDNIL R2 - 0x1C080202, // 0004 EQ R2 R1 R2 - 0x780A0000, // 0005 JMPF R2 #0007 - 0x540615A3, // 0006 LDINT R1 5540 - 0xB80A0200, // 0007 GETNGBL R2 K1 - 0x8C080502, // 0008 GETMET R2 R2 K2 - 0x60100008, // 0009 GETGBL R4 G8 - 0x5C140200, // 000A MOVE R5 R1 - 0x7C100200, // 000B CALL R4 1 - 0x00120604, // 000C ADD R4 K3 R4 - 0x58140004, // 000D LDCONST R5 K4 - 0x7C080600, // 000E CALL R2 3 - 0xB80A0A00, // 000F GETNGBL R2 K5 - 0x8C080506, // 0010 GETMET R2 R2 K6 - 0x58100007, // 0011 LDCONST R4 K7 - 0x5C140200, // 0012 MOVE R5 R1 - 0x7C080600, // 0013 CALL R2 3 - 0x90020002, // 0014 SETMBR R0 K0 R2 - 0x88080100, // 0015 GETMBR R2 R0 K0 - 0x8C080508, // 0016 GETMET R2 R2 K8 - 0x84100000, // 0017 CLOSURE R4 P0 - 0x7C080400, // 0018 CALL R2 2 - 0xA0000000, // 0019 CLOSE R0 - 0x80000000, // 001A RET 0 + ( &(const binstruction[ 7]) { /* code */ + 0xB80A0000, // 0000 GETNGBL R2 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x58100002, // 0002 LDCONST R4 K2 + 0x84140000, // 0003 CLOSURE R5 P0 + 0x7C080600, // 0004 CALL R2 3 + 0xA0000000, // 0005 CLOSE R0 + 0x80000000, // 0006 RET 0 }) ) ); @@ -668,23 +680,87 @@ be_local_closure(Matter_Device_start_udp, /* name */ /******************************************************************** -** Solidified function: finish_commissioning +** Solidified function: stop ********************************************************************/ -be_local_closure(Matter_Device_finish_commissioning, /* name */ +be_local_closure(Matter_Device_stop, /* name */ be_nested_proto( - 1, /* nstack */ + 3, /* nstack */ 1, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ - 0, /* has constants */ - NULL, /* no const */ - be_str_weak(finish_commissioning), + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(udp_server), + /* K1 */ be_nested_str_weak(stop), + }), + be_str_weak(stop), &be_const_str_solidified, - ( &(const binstruction[ 1]) { /* code */ - 0x80000000, // 0000 RET 0 + ( &(const binstruction[ 6]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x78060002, // 0001 JMPF R1 #0005 + 0x88040100, // 0002 GETMBR R1 R0 K0 + 0x8C040301, // 0003 GETMET R1 R1 K1 + 0x7C040200, // 0004 CALL R1 1 + 0x80000000, // 0005 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: invoke_request +********************************************************************/ +be_local_closure(Matter_Device_invoke_request, /* name */ + be_nested_proto( + 11, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 7]) { /* constants */ + /* K0 */ be_const_int(0), + /* K1 */ be_nested_str_weak(plugins), + /* K2 */ be_nested_str_weak(invoke_request), + /* K3 */ be_nested_str_weak(status), + /* K4 */ be_nested_str_weak(matter), + /* K5 */ be_nested_str_weak(UNSUPPORTED_COMMAND), + /* K6 */ be_const_int(1), + }), + be_str_weak(invoke_request), + &be_const_str_solidified, + ( &(const binstruction[25]) { /* code */ + 0x58100000, // 0000 LDCONST R4 K0 + 0x6014000C, // 0001 GETGBL R5 G12 + 0x88180101, // 0002 GETMBR R6 R0 K1 + 0x7C140200, // 0003 CALL R5 1 + 0x14140805, // 0004 LT R5 R4 R5 + 0x78160011, // 0005 JMPF R5 #0018 + 0x88140101, // 0006 GETMBR R5 R0 K1 + 0x94140A04, // 0007 GETIDX R5 R5 R4 + 0x8C180B02, // 0008 GETMET R6 R5 K2 + 0x5C200200, // 0009 MOVE R8 R1 + 0x5C240400, // 000A MOVE R9 R2 + 0x5C280600, // 000B MOVE R10 R3 + 0x7C180800, // 000C CALL R6 4 + 0x4C1C0000, // 000D LDNIL R7 + 0x201C0C07, // 000E NE R7 R6 R7 + 0x741E0004, // 000F JMPT R7 #0015 + 0x881C0703, // 0010 GETMBR R7 R3 K3 + 0xB8220800, // 0011 GETNGBL R8 K4 + 0x88201105, // 0012 GETMBR R8 R8 K5 + 0x201C0E08, // 0013 NE R7 R7 R8 + 0x781E0000, // 0014 JMPF R7 #0016 + 0x80040C00, // 0015 RET 1 R6 + 0x00100906, // 0016 ADD R4 R4 K6 + 0x7001FFE8, // 0017 JMP #0001 + 0x80000000, // 0018 RET 0 }) ) ); @@ -822,6 +898,557 @@ be_local_closure(Matter_Device_start_mdns_announce_hostnames, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: mdns_announce_op_discovery_all_sessions +********************************************************************/ +be_local_closure(Matter_Device_mdns_announce_op_discovery_all_sessions, /* name */ + be_nested_proto( + 6, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(sessions), + /* K1 */ be_nested_str_weak(get_deviceid), + /* K2 */ be_nested_str_weak(get_fabric), + /* K3 */ be_nested_str_weak(mdns_announce_op_discovery), + /* K4 */ be_nested_str_weak(stop_iteration), + }), + be_str_weak(mdns_announce_op_discovery_all_sessions), + &be_const_str_solidified, + ( &(const binstruction[21]) { /* code */ + 0x60040010, // 0000 GETGBL R1 G16 + 0x88080100, // 0001 GETMBR R2 R0 K0 + 0x88080500, // 0002 GETMBR R2 R2 K0 + 0x7C040200, // 0003 CALL R1 1 + 0xA802000B, // 0004 EXBLK 0 #0011 + 0x5C080200, // 0005 MOVE R2 R1 + 0x7C080000, // 0006 CALL R2 0 + 0x8C0C0501, // 0007 GETMET R3 R2 K1 + 0x7C0C0200, // 0008 CALL R3 1 + 0x780E0005, // 0009 JMPF R3 #0010 + 0x8C0C0502, // 000A GETMET R3 R2 K2 + 0x7C0C0200, // 000B CALL R3 1 + 0x780E0002, // 000C JMPF R3 #0010 + 0x8C0C0103, // 000D GETMET R3 R0 K3 + 0x5C140400, // 000E MOVE R5 R2 + 0x7C0C0400, // 000F CALL R3 2 + 0x7001FFF3, // 0010 JMP #0005 + 0x58040004, // 0011 LDCONST R1 K4 + 0xAC040200, // 0012 CATCH R1 1 0 + 0xB0080000, // 0013 RAISE 2 R0 R0 + 0x80000000, // 0014 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: every_second +********************************************************************/ +be_local_closure(Matter_Device_every_second, /* name */ + be_nested_proto( + 3, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(sessions), + /* K1 */ be_nested_str_weak(every_second), + /* K2 */ be_nested_str_weak(msg_handler), + }), + be_str_weak(every_second), + &be_const_str_solidified, + ( &(const binstruction[ 7]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0x7C040200, // 0002 CALL R1 1 + 0x88040102, // 0003 GETMBR R1 R0 K2 + 0x8C040301, // 0004 GETMET R1 R1 K1 + 0x7C040200, // 0005 CALL R1 1 + 0x80000000, // 0006 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_Device_init, /* name */ + be_nested_proto( + 8, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 1, /* has sup protos */ + ( &(const struct bproto*[ 2]) { + be_nested_proto( + 4, /* nstack */ + 0, /* argc */ + 0, /* varg */ + 1, /* has upvals */ + ( &(const bupvaldesc[ 1]) { /* upvals */ + be_local_const_upval(1, 0), + }), + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(start_udp), + /* K1 */ be_nested_str_weak(UDP_PORT), + /* K2 */ be_nested_str_weak(tasmota), + /* K3 */ be_nested_str_weak(remove_rule), + /* K4 */ be_nested_str_weak(Wifi_X23Connected), + /* K5 */ be_nested_str_weak(matter_device_udp), + }), + be_str_weak(_anonymous_), + &be_const_str_solidified, + ( &(const binstruction[11]) { /* code */ + 0x68000000, // 0000 GETUPV R0 U0 + 0x8C000100, // 0001 GETMET R0 R0 K0 + 0x68080000, // 0002 GETUPV R2 U0 + 0x88080501, // 0003 GETMBR R2 R2 K1 + 0x7C000400, // 0004 CALL R0 2 + 0xB8020400, // 0005 GETNGBL R0 K2 + 0x8C000103, // 0006 GETMET R0 R0 K3 + 0x58080004, // 0007 LDCONST R2 K4 + 0x580C0005, // 0008 LDCONST R3 K5 + 0x7C000600, // 0009 CALL R0 3 + 0x80000000, // 000A RET 0 + }) + ), + be_nested_proto( + 4, /* nstack */ + 0, /* argc */ + 0, /* varg */ + 1, /* has upvals */ + ( &(const bupvaldesc[ 1]) { /* upvals */ + be_local_const_upval(1, 0), + }), + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(start_udp), + /* K1 */ be_nested_str_weak(UDP_PORT), + /* K2 */ be_nested_str_weak(tasmota), + /* K3 */ be_nested_str_weak(remove_rule), + /* K4 */ be_nested_str_weak(Eth_X23Connected), + /* K5 */ be_nested_str_weak(matter_device_udp), + }), + be_str_weak(_anonymous_), + &be_const_str_solidified, + ( &(const binstruction[11]) { /* code */ + 0x68000000, // 0000 GETUPV R0 U0 + 0x8C000100, // 0001 GETMET R0 R0 K0 + 0x68080000, // 0002 GETUPV R2 U0 + 0x88080501, // 0003 GETMBR R2 R2 K1 + 0x7C000400, // 0004 CALL R0 2 + 0xB8020400, // 0005 GETNGBL R0 K2 + 0x8C000103, // 0006 GETMET R0 R0 K3 + 0x58080004, // 0007 LDCONST R2 K4 + 0x580C0005, // 0008 LDCONST R3 K5 + 0x7C000600, // 0009 CALL R0 3 + 0x80000000, // 000A RET 0 + }) + ), + }), + 1, /* has constants */ + ( &(const bvalue[39]) { /* constants */ + /* K0 */ be_nested_str_weak(crypto), + /* K1 */ be_nested_str_weak(string), + /* K2 */ be_nested_str_weak(tasmota), + /* K3 */ be_nested_str_weak(get_option), + /* K4 */ be_nested_str_weak(matter), + /* K5 */ be_nested_str_weak(MATTER_OPTION), + /* K6 */ be_nested_str_weak(UI), + /* K7 */ be_nested_str_weak(plugins), + /* K8 */ be_nested_str_weak(vendorid), + /* K9 */ be_nested_str_weak(VENDOR_ID), + /* K10 */ be_nested_str_weak(productid), + /* K11 */ be_nested_str_weak(PRODUCT_ID), + /* K12 */ be_nested_str_weak(iterations), + /* K13 */ be_nested_str_weak(PBKDF_ITERATIONS), + /* K14 */ be_nested_str_weak(load_param), + /* K15 */ be_nested_str_weak(commissioning_instance_wifi), + /* K16 */ be_nested_str_weak(random), + /* K17 */ be_nested_str_weak(tohex), + /* K18 */ be_nested_str_weak(commissioning_instance_eth), + /* K19 */ be_nested_str_weak(sessions), + /* K20 */ be_nested_str_weak(Session_Store), + /* K21 */ be_nested_str_weak(load), + /* K22 */ be_nested_str_weak(msg_handler), + /* K23 */ be_nested_str_weak(MessageHandler), + /* K24 */ be_nested_str_weak(ui), + /* K25 */ be_nested_str_weak(push), + /* K26 */ be_nested_str_weak(Plugin_core), + /* K27 */ be_nested_str_weak(Plugin_Relay), + /* K28 */ be_nested_str_weak(start_mdns_announce_hostnames), + /* K29 */ be_nested_str_weak(wifi), + /* K30 */ be_nested_str_weak(up), + /* K31 */ be_nested_str_weak(start_udp), + /* K32 */ be_nested_str_weak(UDP_PORT), + /* K33 */ be_nested_str_weak(add_rule), + /* K34 */ be_nested_str_weak(Wifi_X23Connected), + /* K35 */ be_nested_str_weak(eth), + /* K36 */ be_nested_str_weak(Eth_X23Connected), + /* K37 */ be_nested_str_weak(start_basic_commissioning), + /* K38 */ be_nested_str_weak(add_driver), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[107]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0xA40A0200, // 0001 IMPORT R2 K1 + 0xB80E0400, // 0002 GETNGBL R3 K2 + 0x8C0C0703, // 0003 GETMET R3 R3 K3 + 0xB8160800, // 0004 GETNGBL R5 K4 + 0x88140B05, // 0005 GETMBR R5 R5 K5 + 0x7C0C0400, // 0006 CALL R3 2 + 0x740E0004, // 0007 JMPT R3 #000D + 0xB80E0800, // 0008 GETNGBL R3 K4 + 0x8C0C0706, // 0009 GETMET R3 R3 K6 + 0x5C140000, // 000A MOVE R5 R0 + 0x7C0C0400, // 000B CALL R3 2 + 0x80000600, // 000C RET 0 + 0x600C0012, // 000D GETGBL R3 G18 + 0x7C0C0000, // 000E CALL R3 0 + 0x90020E03, // 000F SETMBR R0 K7 R3 + 0x880C0109, // 0010 GETMBR R3 R0 K9 + 0x90021003, // 0011 SETMBR R0 K8 R3 + 0x880C010B, // 0012 GETMBR R3 R0 K11 + 0x90021403, // 0013 SETMBR R0 K10 R3 + 0x880C010D, // 0014 GETMBR R3 R0 K13 + 0x90021803, // 0015 SETMBR R0 K12 R3 + 0x8C0C010E, // 0016 GETMET R3 R0 K14 + 0x7C0C0200, // 0017 CALL R3 1 + 0x8C0C0310, // 0018 GETMET R3 R1 K16 + 0x54160007, // 0019 LDINT R5 8 + 0x7C0C0400, // 001A CALL R3 2 + 0x8C0C0711, // 001B GETMET R3 R3 K17 + 0x7C0C0200, // 001C CALL R3 1 + 0x90021E03, // 001D SETMBR R0 K15 R3 + 0x8C0C0310, // 001E GETMET R3 R1 K16 + 0x54160007, // 001F LDINT R5 8 + 0x7C0C0400, // 0020 CALL R3 2 + 0x8C0C0711, // 0021 GETMET R3 R3 K17 + 0x7C0C0200, // 0022 CALL R3 1 + 0x90022403, // 0023 SETMBR R0 K18 R3 + 0xB80E0800, // 0024 GETNGBL R3 K4 + 0x8C0C0714, // 0025 GETMET R3 R3 K20 + 0x7C0C0200, // 0026 CALL R3 1 + 0x90022603, // 0027 SETMBR R0 K19 R3 + 0x880C0113, // 0028 GETMBR R3 R0 K19 + 0x8C0C0715, // 0029 GETMET R3 R3 K21 + 0x7C0C0200, // 002A CALL R3 1 + 0xB80E0800, // 002B GETNGBL R3 K4 + 0x8C0C0717, // 002C GETMET R3 R3 K23 + 0x5C140000, // 002D MOVE R5 R0 + 0x7C0C0400, // 002E CALL R3 2 + 0x90022C03, // 002F SETMBR R0 K22 R3 + 0xB80E0800, // 0030 GETNGBL R3 K4 + 0x8C0C0706, // 0031 GETMET R3 R3 K6 + 0x5C140000, // 0032 MOVE R5 R0 + 0x7C0C0400, // 0033 CALL R3 2 + 0x90023003, // 0034 SETMBR R0 K24 R3 + 0x880C0107, // 0035 GETMBR R3 R0 K7 + 0x8C0C0719, // 0036 GETMET R3 R3 K25 + 0xB8160800, // 0037 GETNGBL R5 K4 + 0x8C140B1A, // 0038 GETMET R5 R5 K26 + 0x5C1C0000, // 0039 MOVE R7 R0 + 0x7C140400, // 003A CALL R5 2 + 0x7C0C0400, // 003B CALL R3 2 + 0x880C0107, // 003C GETMBR R3 R0 K7 + 0x8C0C0719, // 003D GETMET R3 R3 K25 + 0xB8160800, // 003E GETNGBL R5 K4 + 0x8C140B1B, // 003F GETMET R5 R5 K27 + 0x5C1C0000, // 0040 MOVE R7 R0 + 0x7C140400, // 0041 CALL R5 2 + 0x7C0C0400, // 0042 CALL R3 2 + 0x8C0C011C, // 0043 GETMET R3 R0 K28 + 0x7C0C0200, // 0044 CALL R3 1 + 0xB80E0400, // 0045 GETNGBL R3 K2 + 0x8C0C071D, // 0046 GETMET R3 R3 K29 + 0x7C0C0200, // 0047 CALL R3 1 + 0x940C071E, // 0048 GETIDX R3 R3 K30 + 0x780E0003, // 0049 JMPF R3 #004E + 0x8C0C011F, // 004A GETMET R3 R0 K31 + 0x88140120, // 004B GETMBR R5 R0 K32 + 0x7C0C0400, // 004C CALL R3 2 + 0x70020005, // 004D JMP #0054 + 0xB80E0400, // 004E GETNGBL R3 K2 + 0x8C0C0721, // 004F GETMET R3 R3 K33 + 0x58140022, // 0050 LDCONST R5 K34 + 0x84180000, // 0051 CLOSURE R6 P0 + 0x5C1C0000, // 0052 MOVE R7 R0 + 0x7C0C0800, // 0053 CALL R3 4 + 0xB80E0400, // 0054 GETNGBL R3 K2 + 0x8C0C0723, // 0055 GETMET R3 R3 K35 + 0x7C0C0200, // 0056 CALL R3 1 + 0x940C071E, // 0057 GETIDX R3 R3 K30 + 0x780E0003, // 0058 JMPF R3 #005D + 0x8C0C011F, // 0059 GETMET R3 R0 K31 + 0x88140120, // 005A GETMBR R5 R0 K32 + 0x7C0C0400, // 005B CALL R3 2 + 0x70020005, // 005C JMP #0063 + 0xB80E0400, // 005D GETNGBL R3 K2 + 0x8C0C0721, // 005E GETMET R3 R3 K33 + 0x58140024, // 005F LDCONST R5 K36 + 0x84180001, // 0060 CLOSURE R6 P1 + 0x5C1C0000, // 0061 MOVE R7 R0 + 0x7C0C0800, // 0062 CALL R3 4 + 0x8C0C0125, // 0063 GETMET R3 R0 K37 + 0x7C0C0200, // 0064 CALL R3 1 + 0xB80E0400, // 0065 GETNGBL R3 K2 + 0x8C0C0726, // 0066 GETMET R3 R3 K38 + 0x5C140000, // 0067 MOVE R5 R0 + 0x7C0C0400, // 0068 CALL R3 2 + 0xA0000000, // 0069 CLOSE R0 + 0x80000000, // 006A RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: start_basic_commissioning +********************************************************************/ +be_local_closure(Matter_Device_start_basic_commissioning, /* name */ + be_nested_proto( + 4, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(compute_pbkdf), + /* K1 */ be_nested_str_weak(passcode), + }), + be_str_weak(start_basic_commissioning), + &be_const_str_solidified, + ( &(const binstruction[ 4]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x880C0101, // 0001 GETMBR R3 R0 K1 + 0x7C040400, // 0002 CALL R1 2 + 0x80000000, // 0003 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: start_operational_dicovery +********************************************************************/ +be_local_closure(Matter_Device_start_operational_dicovery, /* name */ + be_nested_proto( + 8, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[13]) { /* constants */ + /* K0 */ be_nested_str_weak(crypto), + /* K1 */ be_nested_str_weak(mdns), + /* K2 */ be_nested_str_weak(string), + /* K3 */ be_nested_str_weak(salt), + /* K4 */ be_nested_str_weak(w0), + /* K5 */ be_nested_str_weak(w1), + /* K6 */ be_nested_str_weak(L), + /* K7 */ be_nested_str_weak(set_no_expiration), + /* K8 */ be_nested_str_weak(set_persist), + /* K9 */ be_nested_str_weak(close), + /* K10 */ be_nested_str_weak(sessions), + /* K11 */ be_nested_str_weak(save), + /* K12 */ be_nested_str_weak(mdns_announce_op_discovery), + }), + be_str_weak(start_operational_dicovery), + &be_const_str_solidified, + ( &(const binstruction[25]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0xA40E0200, // 0001 IMPORT R3 K1 + 0xA4120400, // 0002 IMPORT R4 K2 + 0x4C140000, // 0003 LDNIL R5 + 0x90020605, // 0004 SETMBR R0 K3 R5 + 0x4C140000, // 0005 LDNIL R5 + 0x90020805, // 0006 SETMBR R0 K4 R5 + 0x4C140000, // 0007 LDNIL R5 + 0x90020A05, // 0008 SETMBR R0 K5 R5 + 0x4C140000, // 0009 LDNIL R5 + 0x90020C05, // 000A SETMBR R0 K6 R5 + 0x8C140307, // 000B GETMET R5 R1 K7 + 0x7C140200, // 000C CALL R5 1 + 0x8C140308, // 000D GETMET R5 R1 K8 + 0x501C0200, // 000E LDBOOL R7 1 0 + 0x7C140400, // 000F CALL R5 2 + 0x8C140309, // 0010 GETMET R5 R1 K9 + 0x7C140200, // 0011 CALL R5 1 + 0x8814010A, // 0012 GETMBR R5 R0 K10 + 0x8C140B0B, // 0013 GETMET R5 R5 K11 + 0x7C140200, // 0014 CALL R5 1 + 0x8C14010C, // 0015 GETMET R5 R0 K12 + 0x5C1C0200, // 0016 MOVE R7 R1 + 0x7C140400, // 0017 CALL R5 2 + 0x80000000, // 0018 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: start_commissioning_complete +********************************************************************/ +be_local_closure(Matter_Device_start_commissioning_complete, /* name */ + be_nested_proto( + 6, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(tasmota), + /* K1 */ be_nested_str_weak(log), + /* K2 */ be_nested_str_weak(MTR_X3A_X20_X2A_X2A_X2A_X20Commissioning_X20complete_X20_X2A_X2A_X2A), + /* K3 */ be_const_int(2), + }), + be_str_weak(start_commissioning_complete), + &be_const_str_solidified, + ( &(const binstruction[ 6]) { /* code */ + 0xB80A0000, // 0000 GETNGBL R2 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x58100002, // 0002 LDCONST R4 K2 + 0x58140003, // 0003 LDCONST R5 K3 + 0x7C080600, // 0004 CALL R2 3 + 0x80000000, // 0005 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: compute_qrcode_content +********************************************************************/ +be_local_closure(Matter_Device_compute_qrcode_content, /* name */ + be_nested_proto( + 8, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[12]) { /* constants */ + /* K0 */ be_nested_str_weak(resize), + /* K1 */ be_nested_str_weak(setbits), + /* K2 */ be_const_int(3), + /* K3 */ be_nested_str_weak(vendorid), + /* K4 */ be_nested_str_weak(productid), + /* K5 */ be_nested_str_weak(discriminator), + /* K6 */ be_nested_str_weak(passcode), + /* K7 */ be_const_int(134217727), + /* K8 */ be_nested_str_weak(MT_X3A), + /* K9 */ be_nested_str_weak(matter), + /* K10 */ be_nested_str_weak(Base38), + /* K11 */ be_nested_str_weak(encode), + }), + be_str_weak(compute_qrcode_content), + &be_const_str_solidified, + ( &(const binstruction[40]) { /* code */ + 0x60040015, // 0000 GETGBL R1 G21 + 0x7C040000, // 0001 CALL R1 0 + 0x8C040300, // 0002 GETMET R1 R1 K0 + 0x540E000A, // 0003 LDINT R3 11 + 0x7C040400, // 0004 CALL R1 2 + 0x8C080301, // 0005 GETMET R2 R1 K1 + 0x58100002, // 0006 LDCONST R4 K2 + 0x5416000F, // 0007 LDINT R5 16 + 0x88180103, // 0008 GETMBR R6 R0 K3 + 0x7C080800, // 0009 CALL R2 4 + 0x8C080301, // 000A GETMET R2 R1 K1 + 0x54120012, // 000B LDINT R4 19 + 0x5416000F, // 000C LDINT R5 16 + 0x88180104, // 000D GETMBR R6 R0 K4 + 0x7C080800, // 000E CALL R2 4 + 0x8C080301, // 000F GETMET R2 R1 K1 + 0x54120024, // 0010 LDINT R4 37 + 0x54160007, // 0011 LDINT R5 8 + 0x541A0003, // 0012 LDINT R6 4 + 0x7C080800, // 0013 CALL R2 4 + 0x8C080301, // 0014 GETMET R2 R1 K1 + 0x5412002C, // 0015 LDINT R4 45 + 0x5416000B, // 0016 LDINT R5 12 + 0x88180105, // 0017 GETMBR R6 R0 K5 + 0x541E0FFE, // 0018 LDINT R7 4095 + 0x2C180C07, // 0019 AND R6 R6 R7 + 0x7C080800, // 001A CALL R2 4 + 0x8C080301, // 001B GETMET R2 R1 K1 + 0x54120038, // 001C LDINT R4 57 + 0x5416001A, // 001D LDINT R5 27 + 0x88180106, // 001E GETMBR R6 R0 K6 + 0x2C180D07, // 001F AND R6 R6 K7 + 0x7C080800, // 0020 CALL R2 4 + 0xB80A1200, // 0021 GETNGBL R2 K9 + 0x8808050A, // 0022 GETMBR R2 R2 K10 + 0x8C08050B, // 0023 GETMET R2 R2 K11 + 0x5C100200, // 0024 MOVE R4 R1 + 0x7C080400, // 0025 CALL R2 2 + 0x000A1002, // 0026 ADD R2 K8 R2 + 0x80040400, // 0027 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: finish_commissioning +********************************************************************/ +be_local_closure(Matter_Device_finish_commissioning, /* name */ + be_nested_proto( + 1, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + be_str_weak(finish_commissioning), + &be_const_str_solidified, + ( &(const binstruction[ 1]) { /* code */ + 0x80000000, // 0000 RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: mdns_announce_op_discovery ********************************************************************/ @@ -998,63 +1625,59 @@ be_local_closure(Matter_Device_mdns_announce_op_discovery, /* name */ /******************************************************************** -** Solidified function: start_commissioning_complete +** Solidified function: start_commissioning_complete_deferred ********************************************************************/ -be_local_closure(Matter_Device_start_commissioning_complete, /* name */ +be_local_closure(Matter_Device_start_commissioning_complete_deferred, /* name */ be_nested_proto( 6, /* nstack */ 2, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 4]) { /* constants */ - /* K0 */ be_nested_str_weak(tasmota), - /* K1 */ be_nested_str_weak(log), - /* K2 */ be_nested_str_weak(MTR_X3A_X20_X2A_X2A_X2A_X20Commissioning_X20complete_X20_X2A_X2A_X2A), - /* K3 */ be_const_int(2), + 1, /* has sup protos */ + ( &(const struct bproto*[ 1]) { + be_nested_proto( + 3, /* nstack */ + 0, /* argc */ + 0, /* varg */ + 1, /* has upvals */ + ( &(const bupvaldesc[ 2]) { /* upvals */ + be_local_const_upval(1, 0), + be_local_const_upval(1, 1), + }), + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(start_commissioning_complete), + }), + be_str_weak(_X3Clambda_X3E), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x68000000, // 0000 GETUPV R0 U0 + 0x8C000100, // 0001 GETMET R0 R0 K0 + 0x68080001, // 0002 GETUPV R2 U1 + 0x7C000400, // 0003 CALL R0 2 + 0x80040000, // 0004 RET 1 R0 + }) + ), }), - be_str_weak(start_commissioning_complete), + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(tasmota), + /* K1 */ be_nested_str_weak(set_timer), + /* K2 */ be_const_int(0), + }), + be_str_weak(start_commissioning_complete_deferred), &be_const_str_solidified, - ( &(const binstruction[ 6]) { /* code */ + ( &(const binstruction[ 7]) { /* code */ 0xB80A0000, // 0000 GETNGBL R2 K0 0x8C080501, // 0001 GETMET R2 R2 K1 0x58100002, // 0002 LDCONST R4 K2 - 0x58140003, // 0003 LDCONST R5 K3 + 0x84140000, // 0003 CLOSURE R5 P0 0x7C080600, // 0004 CALL R2 3 - 0x80000000, // 0005 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: start_basic_commissioning -********************************************************************/ -be_local_closure(Matter_Device_start_basic_commissioning, /* name */ - be_nested_proto( - 4, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(compute_pbkdf), - /* K1 */ be_nested_str_weak(passcode), - }), - be_str_weak(start_basic_commissioning), - &be_const_str_solidified, - ( &(const binstruction[ 4]) { /* code */ - 0x8C040100, // 0000 GETMET R1 R0 K0 - 0x880C0101, // 0001 GETMBR R3 R0 K1 - 0x7C040400, // 0002 CALL R1 2 - 0x80000000, // 0003 RET 0 + 0xA0000000, // 0005 CLOSE R0 + 0x80000000, // 0006 RET 0 }) ) ); @@ -1204,232 +1827,100 @@ be_local_closure(Matter_Device_compute_pbkdf, /* name */ /******************************************************************** -** Solidified function: init +** Solidified function: get_active_endpoints ********************************************************************/ -be_local_closure(Matter_Device_init, /* name */ +be_local_closure(Matter_Device_get_active_endpoints, /* name */ be_nested_proto( - 8, /* nstack */ - 1, /* argc */ + 11, /* nstack */ + 2, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ - 1, /* has sup protos */ - ( &(const struct bproto*[ 2]) { - be_nested_proto( - 4, /* nstack */ - 0, /* argc */ - 0, /* varg */ - 1, /* has upvals */ - ( &(const bupvaldesc[ 1]) { /* upvals */ - be_local_const_upval(1, 0), - }), - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 6]) { /* constants */ - /* K0 */ be_nested_str_weak(start_udp), - /* K1 */ be_nested_str_weak(UDP_PORT), - /* K2 */ be_nested_str_weak(tasmota), - /* K3 */ be_nested_str_weak(remove_rule), - /* K4 */ be_nested_str_weak(Wifi_X23Connected), - /* K5 */ be_nested_str_weak(matter_device_udp), - }), - be_str_weak(_anonymous_), - &be_const_str_solidified, - ( &(const binstruction[11]) { /* code */ - 0x68000000, // 0000 GETUPV R0 U0 - 0x8C000100, // 0001 GETMET R0 R0 K0 - 0x68080000, // 0002 GETUPV R2 U0 - 0x88080501, // 0003 GETMBR R2 R2 K1 - 0x7C000400, // 0004 CALL R0 2 - 0xB8020400, // 0005 GETNGBL R0 K2 - 0x8C000103, // 0006 GETMET R0 R0 K3 - 0x58080004, // 0007 LDCONST R2 K4 - 0x580C0005, // 0008 LDCONST R3 K5 - 0x7C000600, // 0009 CALL R0 3 - 0x80000000, // 000A RET 0 - }) - ), - be_nested_proto( - 4, /* nstack */ - 0, /* argc */ - 0, /* varg */ - 1, /* has upvals */ - ( &(const bupvaldesc[ 1]) { /* upvals */ - be_local_const_upval(1, 0), - }), - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 6]) { /* constants */ - /* K0 */ be_nested_str_weak(start_udp), - /* K1 */ be_nested_str_weak(UDP_PORT), - /* K2 */ be_nested_str_weak(tasmota), - /* K3 */ be_nested_str_weak(remove_rule), - /* K4 */ be_nested_str_weak(Eth_X23Connected), - /* K5 */ be_nested_str_weak(matter_device_udp), - }), - be_str_weak(_anonymous_), - &be_const_str_solidified, - ( &(const binstruction[11]) { /* code */ - 0x68000000, // 0000 GETUPV R0 U0 - 0x8C000100, // 0001 GETMET R0 R0 K0 - 0x68080000, // 0002 GETUPV R2 U0 - 0x88080501, // 0003 GETMBR R2 R2 K1 - 0x7C000400, // 0004 CALL R0 2 - 0xB8020400, // 0005 GETNGBL R0 K2 - 0x8C000103, // 0006 GETMET R0 R0 K3 - 0x58080004, // 0007 LDCONST R2 K4 - 0x580C0005, // 0008 LDCONST R3 K5 - 0x7C000600, // 0009 CALL R0 3 - 0x80000000, // 000A RET 0 - }) - ), - }), + 0, /* has sup protos */ + NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[38]) { /* constants */ - /* K0 */ be_nested_str_weak(crypto), - /* K1 */ be_nested_str_weak(string), - /* K2 */ be_nested_str_weak(tasmota), - /* K3 */ be_nested_str_weak(get_option), - /* K4 */ be_nested_str_weak(matter), - /* K5 */ be_nested_str_weak(MATTER_OPTION), - /* K6 */ be_nested_str_weak(UI), - /* K7 */ be_nested_str_weak(plugins), - /* K8 */ be_nested_str_weak(vendorid), - /* K9 */ be_nested_str_weak(VENDOR_ID), - /* K10 */ be_nested_str_weak(productid), - /* K11 */ be_nested_str_weak(PRODUCT_ID), - /* K12 */ be_nested_str_weak(iterations), - /* K13 */ be_nested_str_weak(PBKDF_ITERATIONS), - /* K14 */ be_nested_str_weak(load_param), - /* K15 */ be_nested_str_weak(commissioning_instance_wifi), - /* K16 */ be_nested_str_weak(random), - /* K17 */ be_nested_str_weak(tohex), - /* K18 */ be_nested_str_weak(commissioning_instance_eth), - /* K19 */ be_nested_str_weak(sessions), - /* K20 */ be_nested_str_weak(Session_Store), - /* K21 */ be_nested_str_weak(load), - /* K22 */ be_nested_str_weak(msg_handler), - /* K23 */ be_nested_str_weak(MessageHandler), - /* K24 */ be_nested_str_weak(ui), - /* K25 */ be_nested_str_weak(push), - /* K26 */ be_nested_str_weak(Plugin_core), - /* K27 */ be_nested_str_weak(start_mdns_announce_hostnames), - /* K28 */ be_nested_str_weak(wifi), - /* K29 */ be_nested_str_weak(up), - /* K30 */ be_nested_str_weak(start_udp), - /* K31 */ be_nested_str_weak(UDP_PORT), - /* K32 */ be_nested_str_weak(add_rule), - /* K33 */ be_nested_str_weak(Wifi_X23Connected), - /* K34 */ be_nested_str_weak(eth), - /* K35 */ be_nested_str_weak(Eth_X23Connected), - /* K36 */ be_nested_str_weak(start_basic_commissioning), - /* K37 */ be_nested_str_weak(add_driver), + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(plugins), + /* K1 */ be_nested_str_weak(get_endpoints), + /* K2 */ be_const_int(0), + /* K3 */ be_nested_str_weak(find), + /* K4 */ be_nested_str_weak(push), + /* K5 */ be_nested_str_weak(stop_iteration), }), - be_str_weak(init), + be_str_weak(get_active_endpoints), &be_const_str_solidified, - ( &(const binstruction[100]) { /* code */ - 0xA4060000, // 0000 IMPORT R1 K0 - 0xA40A0200, // 0001 IMPORT R2 K1 - 0xB80E0400, // 0002 GETNGBL R3 K2 - 0x8C0C0703, // 0003 GETMET R3 R3 K3 - 0xB8160800, // 0004 GETNGBL R5 K4 - 0x88140B05, // 0005 GETMBR R5 R5 K5 - 0x7C0C0400, // 0006 CALL R3 2 - 0x740E0004, // 0007 JMPT R3 #000D - 0xB80E0800, // 0008 GETNGBL R3 K4 - 0x8C0C0706, // 0009 GETMET R3 R3 K6 - 0x5C140000, // 000A MOVE R5 R0 - 0x7C0C0400, // 000B CALL R3 2 - 0x80000600, // 000C RET 0 - 0x600C0012, // 000D GETGBL R3 G18 - 0x7C0C0000, // 000E CALL R3 0 - 0x90020E03, // 000F SETMBR R0 K7 R3 - 0x880C0109, // 0010 GETMBR R3 R0 K9 - 0x90021003, // 0011 SETMBR R0 K8 R3 - 0x880C010B, // 0012 GETMBR R3 R0 K11 - 0x90021403, // 0013 SETMBR R0 K10 R3 - 0x880C010D, // 0014 GETMBR R3 R0 K13 - 0x90021803, // 0015 SETMBR R0 K12 R3 - 0x8C0C010E, // 0016 GETMET R3 R0 K14 - 0x7C0C0200, // 0017 CALL R3 1 - 0x8C0C0310, // 0018 GETMET R3 R1 K16 - 0x54160007, // 0019 LDINT R5 8 - 0x7C0C0400, // 001A CALL R3 2 - 0x8C0C0711, // 001B GETMET R3 R3 K17 - 0x7C0C0200, // 001C CALL R3 1 - 0x90021E03, // 001D SETMBR R0 K15 R3 - 0x8C0C0310, // 001E GETMET R3 R1 K16 - 0x54160007, // 001F LDINT R5 8 - 0x7C0C0400, // 0020 CALL R3 2 - 0x8C0C0711, // 0021 GETMET R3 R3 K17 - 0x7C0C0200, // 0022 CALL R3 1 - 0x90022403, // 0023 SETMBR R0 K18 R3 - 0xB80E0800, // 0024 GETNGBL R3 K4 - 0x8C0C0714, // 0025 GETMET R3 R3 K20 - 0x7C0C0200, // 0026 CALL R3 1 - 0x90022603, // 0027 SETMBR R0 K19 R3 - 0x880C0113, // 0028 GETMBR R3 R0 K19 - 0x8C0C0715, // 0029 GETMET R3 R3 K21 - 0x7C0C0200, // 002A CALL R3 1 - 0xB80E0800, // 002B GETNGBL R3 K4 - 0x8C0C0717, // 002C GETMET R3 R3 K23 - 0x5C140000, // 002D MOVE R5 R0 - 0x7C0C0400, // 002E CALL R3 2 - 0x90022C03, // 002F SETMBR R0 K22 R3 - 0xB80E0800, // 0030 GETNGBL R3 K4 - 0x8C0C0706, // 0031 GETMET R3 R3 K6 - 0x5C140000, // 0032 MOVE R5 R0 - 0x7C0C0400, // 0033 CALL R3 2 - 0x90023003, // 0034 SETMBR R0 K24 R3 - 0x880C0107, // 0035 GETMBR R3 R0 K7 - 0x8C0C0719, // 0036 GETMET R3 R3 K25 - 0xB8160800, // 0037 GETNGBL R5 K4 - 0x8C140B1A, // 0038 GETMET R5 R5 K26 - 0x5C1C0000, // 0039 MOVE R7 R0 - 0x7C140400, // 003A CALL R5 2 - 0x7C0C0400, // 003B CALL R3 2 - 0x8C0C011B, // 003C GETMET R3 R0 K27 - 0x7C0C0200, // 003D CALL R3 1 - 0xB80E0400, // 003E GETNGBL R3 K2 - 0x8C0C071C, // 003F GETMET R3 R3 K28 - 0x7C0C0200, // 0040 CALL R3 1 - 0x940C071D, // 0041 GETIDX R3 R3 K29 - 0x780E0003, // 0042 JMPF R3 #0047 - 0x8C0C011E, // 0043 GETMET R3 R0 K30 - 0x8814011F, // 0044 GETMBR R5 R0 K31 - 0x7C0C0400, // 0045 CALL R3 2 - 0x70020005, // 0046 JMP #004D - 0xB80E0400, // 0047 GETNGBL R3 K2 - 0x8C0C0720, // 0048 GETMET R3 R3 K32 - 0x58140021, // 0049 LDCONST R5 K33 - 0x84180000, // 004A CLOSURE R6 P0 - 0x5C1C0000, // 004B MOVE R7 R0 - 0x7C0C0800, // 004C CALL R3 4 - 0xB80E0400, // 004D GETNGBL R3 K2 - 0x8C0C0722, // 004E GETMET R3 R3 K34 - 0x7C0C0200, // 004F CALL R3 1 - 0x940C071D, // 0050 GETIDX R3 R3 K29 - 0x780E0003, // 0051 JMPF R3 #0056 - 0x8C0C011E, // 0052 GETMET R3 R0 K30 - 0x8814011F, // 0053 GETMBR R5 R0 K31 - 0x7C0C0400, // 0054 CALL R3 2 - 0x70020005, // 0055 JMP #005C - 0xB80E0400, // 0056 GETNGBL R3 K2 - 0x8C0C0720, // 0057 GETMET R3 R3 K32 - 0x58140023, // 0058 LDCONST R5 K35 - 0x84180001, // 0059 CLOSURE R6 P1 - 0x5C1C0000, // 005A MOVE R7 R0 - 0x7C0C0800, // 005B CALL R3 4 - 0x8C0C0124, // 005C GETMET R3 R0 K36 - 0x7C0C0200, // 005D CALL R3 1 - 0xB80E0400, // 005E GETNGBL R3 K2 - 0x8C0C0725, // 005F GETMET R3 R3 K37 - 0x5C140000, // 0060 MOVE R5 R0 - 0x7C0C0400, // 0061 CALL R3 2 - 0xA0000000, // 0062 CLOSE R0 - 0x80000000, // 0063 RET 0 + ( &(const binstruction[38]) { /* code */ + 0x60080012, // 0000 GETGBL R2 G18 + 0x7C080000, // 0001 CALL R2 0 + 0x600C0010, // 0002 GETGBL R3 G16 + 0x88100100, // 0003 GETMBR R4 R0 K0 + 0x7C0C0200, // 0004 CALL R3 1 + 0xA802001B, // 0005 EXBLK 0 #0022 + 0x5C100600, // 0006 MOVE R4 R3 + 0x7C100000, // 0007 CALL R4 0 + 0x8C140901, // 0008 GETMET R5 R4 K1 + 0x7C140200, // 0009 CALL R5 1 + 0x60180010, // 000A GETGBL R6 G16 + 0x5C1C0A00, // 000B MOVE R7 R5 + 0x7C180200, // 000C CALL R6 1 + 0xA802000F, // 000D EXBLK 0 #001E + 0x5C1C0C00, // 000E MOVE R7 R6 + 0x7C1C0000, // 000F CALL R7 0 + 0x78060002, // 0010 JMPF R1 #0014 + 0x1C200F02, // 0011 EQ R8 R7 K2 + 0x78220000, // 0012 JMPF R8 #0014 + 0x7001FFF9, // 0013 JMP #000E + 0x8C200503, // 0014 GETMET R8 R2 K3 + 0x5C280E00, // 0015 MOVE R10 R7 + 0x7C200400, // 0016 CALL R8 2 + 0x4C240000, // 0017 LDNIL R9 + 0x1C201009, // 0018 EQ R8 R8 R9 + 0x78220002, // 0019 JMPF R8 #001D + 0x8C200504, // 001A GETMET R8 R2 K4 + 0x5C280E00, // 001B MOVE R10 R7 + 0x7C200400, // 001C CALL R8 2 + 0x7001FFEF, // 001D JMP #000E + 0x58180005, // 001E LDCONST R6 K5 + 0xAC180200, // 001F CATCH R6 1 0 + 0xB0080000, // 0020 RAISE 2 R0 R0 + 0x7001FFE3, // 0021 JMP #0006 + 0x580C0005, // 0022 LDCONST R3 K5 + 0xAC0C0200, // 0023 CATCH R3 1 0 + 0xB0080000, // 0024 RAISE 2 R0 R0 + 0x80040400, // 0025 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: msg_received +********************************************************************/ +be_local_closure(Matter_Device_msg_received, /* name */ + be_nested_proto( + 9, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(msg_handler), + /* K1 */ be_nested_str_weak(msg_received), + }), + be_str_weak(msg_received), + &be_const_str_solidified, + ( &(const binstruction[ 7]) { /* code */ + 0x88100100, // 0000 GETMBR R4 R0 K0 + 0x8C100901, // 0001 GETMET R4 R4 K1 + 0x5C180200, // 0002 MOVE R6 R1 + 0x5C1C0400, // 0003 MOVE R7 R2 + 0x5C200600, // 0004 MOVE R8 R3 + 0x7C100800, // 0005 CALL R4 4 + 0x80040800, // 0006 RET 1 R4 }) ) ); @@ -1803,88 +2294,12 @@ be_local_closure(Matter_Device__start_mdns_announce, /* name */ /******************************************************************** -** Solidified function: compute_qrcode_content +** Solidified function: packet_ack ********************************************************************/ -be_local_closure(Matter_Device_compute_qrcode_content, /* name */ +be_local_closure(Matter_Device_packet_ack, /* name */ be_nested_proto( - 8, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[12]) { /* constants */ - /* K0 */ be_nested_str_weak(resize), - /* K1 */ be_nested_str_weak(setbits), - /* K2 */ be_const_int(3), - /* K3 */ be_nested_str_weak(vendorid), - /* K4 */ be_nested_str_weak(productid), - /* K5 */ be_nested_str_weak(discriminator), - /* K6 */ be_nested_str_weak(passcode), - /* K7 */ be_const_int(134217727), - /* K8 */ be_nested_str_weak(MT_X3A), - /* K9 */ be_nested_str_weak(matter), - /* K10 */ be_nested_str_weak(Base38), - /* K11 */ be_nested_str_weak(encode), - }), - be_str_weak(compute_qrcode_content), - &be_const_str_solidified, - ( &(const binstruction[40]) { /* code */ - 0x60040015, // 0000 GETGBL R1 G21 - 0x7C040000, // 0001 CALL R1 0 - 0x8C040300, // 0002 GETMET R1 R1 K0 - 0x540E000A, // 0003 LDINT R3 11 - 0x7C040400, // 0004 CALL R1 2 - 0x8C080301, // 0005 GETMET R2 R1 K1 - 0x58100002, // 0006 LDCONST R4 K2 - 0x5416000F, // 0007 LDINT R5 16 - 0x88180103, // 0008 GETMBR R6 R0 K3 - 0x7C080800, // 0009 CALL R2 4 - 0x8C080301, // 000A GETMET R2 R1 K1 - 0x54120012, // 000B LDINT R4 19 - 0x5416000F, // 000C LDINT R5 16 - 0x88180104, // 000D GETMBR R6 R0 K4 - 0x7C080800, // 000E CALL R2 4 - 0x8C080301, // 000F GETMET R2 R1 K1 - 0x54120024, // 0010 LDINT R4 37 - 0x54160007, // 0011 LDINT R5 8 - 0x541A0003, // 0012 LDINT R6 4 - 0x7C080800, // 0013 CALL R2 4 - 0x8C080301, // 0014 GETMET R2 R1 K1 - 0x5412002C, // 0015 LDINT R4 45 - 0x5416000B, // 0016 LDINT R5 12 - 0x88180105, // 0017 GETMBR R6 R0 K5 - 0x541E0FFE, // 0018 LDINT R7 4095 - 0x2C180C07, // 0019 AND R6 R6 R7 - 0x7C080800, // 001A CALL R2 4 - 0x8C080301, // 001B GETMET R2 R1 K1 - 0x54120038, // 001C LDINT R4 57 - 0x5416001A, // 001D LDINT R5 27 - 0x88180106, // 001E GETMBR R6 R0 K6 - 0x2C180D07, // 001F AND R6 R6 K7 - 0x7C080800, // 0020 CALL R2 4 - 0xB80A1200, // 0021 GETNGBL R2 K9 - 0x8808050A, // 0022 GETMBR R2 R2 K10 - 0x8C08050B, // 0023 GETMET R2 R2 K11 - 0x5C100200, // 0024 MOVE R4 R1 - 0x7C080400, // 0025 CALL R2 2 - 0x000A1002, // 0026 ADD R2 K8 R2 - 0x80040400, // 0027 RET 1 R2 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: msg_received -********************************************************************/ -be_local_closure(Matter_Device_msg_received, /* name */ - be_nested_proto( - 9, /* nstack */ - 4, /* argc */ + 5, /* nstack */ + 2, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ @@ -1892,19 +2307,17 @@ be_local_closure(Matter_Device_msg_received, /* name */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(msg_handler), - /* K1 */ be_nested_str_weak(msg_received), + /* K0 */ be_nested_str_weak(udp_server), + /* K1 */ be_nested_str_weak(packet_ack), }), - be_str_weak(msg_received), + be_str_weak(packet_ack), &be_const_str_solidified, - ( &(const binstruction[ 7]) { /* code */ - 0x88100100, // 0000 GETMBR R4 R0 K0 - 0x8C100901, // 0001 GETMET R4 R4 K1 - 0x5C180200, // 0002 MOVE R6 R1 - 0x5C1C0400, // 0003 MOVE R7 R2 - 0x5C200600, // 0004 MOVE R8 R3 - 0x7C100800, // 0005 CALL R4 4 - 0x80040800, // 0006 RET 1 R4 + ( &(const binstruction[ 5]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x5C100200, // 0002 MOVE R4 R1 + 0x7C080400, // 0003 CALL R2 2 + 0x80040400, // 0004 RET 1 R2 }) ) ); @@ -1912,117 +2325,11 @@ be_local_closure(Matter_Device_msg_received, /* name */ /******************************************************************** -** Solidified function: mdns_announce_op_discovery_all_sessions +** Solidified function: msg_send ********************************************************************/ -be_local_closure(Matter_Device_mdns_announce_op_discovery_all_sessions, /* name */ - be_nested_proto( - 6, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 5]) { /* constants */ - /* K0 */ be_nested_str_weak(sessions), - /* K1 */ be_nested_str_weak(get_deviceid), - /* K2 */ be_nested_str_weak(get_fabric), - /* K3 */ be_nested_str_weak(mdns_announce_op_discovery), - /* K4 */ be_nested_str_weak(stop_iteration), - }), - be_str_weak(mdns_announce_op_discovery_all_sessions), - &be_const_str_solidified, - ( &(const binstruction[21]) { /* code */ - 0x60040010, // 0000 GETGBL R1 G16 - 0x88080100, // 0001 GETMBR R2 R0 K0 - 0x88080500, // 0002 GETMBR R2 R2 K0 - 0x7C040200, // 0003 CALL R1 1 - 0xA802000B, // 0004 EXBLK 0 #0011 - 0x5C080200, // 0005 MOVE R2 R1 - 0x7C080000, // 0006 CALL R2 0 - 0x8C0C0501, // 0007 GETMET R3 R2 K1 - 0x7C0C0200, // 0008 CALL R3 1 - 0x780E0005, // 0009 JMPF R3 #0010 - 0x8C0C0502, // 000A GETMET R3 R2 K2 - 0x7C0C0200, // 000B CALL R3 1 - 0x780E0002, // 000C JMPF R3 #0010 - 0x8C0C0103, // 000D GETMET R3 R0 K3 - 0x5C140400, // 000E MOVE R5 R2 - 0x7C0C0400, // 000F CALL R3 2 - 0x7001FFF3, // 0010 JMP #0005 - 0x58040004, // 0011 LDCONST R1 K4 - 0xAC040200, // 0012 CATCH R1 1 0 - 0xB0080000, // 0013 RAISE 2 R0 R0 - 0x80000000, // 0014 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: invoke_request -********************************************************************/ -be_local_closure(Matter_Device_invoke_request, /* name */ +be_local_closure(Matter_Device_msg_send, /* name */ be_nested_proto( 11, /* nstack */ - 4, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 7]) { /* constants */ - /* K0 */ be_const_int(0), - /* K1 */ be_nested_str_weak(plugins), - /* K2 */ be_nested_str_weak(invoke_request), - /* K3 */ be_nested_str_weak(status), - /* K4 */ be_nested_str_weak(matter), - /* K5 */ be_nested_str_weak(UNSUPPORTED_COMMAND), - /* K6 */ be_const_int(1), - }), - be_str_weak(invoke_request), - &be_const_str_solidified, - ( &(const binstruction[25]) { /* code */ - 0x58100000, // 0000 LDCONST R4 K0 - 0x6014000C, // 0001 GETGBL R5 G12 - 0x88180101, // 0002 GETMBR R6 R0 K1 - 0x7C140200, // 0003 CALL R5 1 - 0x14140805, // 0004 LT R5 R4 R5 - 0x78160011, // 0005 JMPF R5 #0018 - 0x88140101, // 0006 GETMBR R5 R0 K1 - 0x94140A04, // 0007 GETIDX R5 R5 R4 - 0x8C180B02, // 0008 GETMET R6 R5 K2 - 0x5C200200, // 0009 MOVE R8 R1 - 0x5C240400, // 000A MOVE R9 R2 - 0x5C280600, // 000B MOVE R10 R3 - 0x7C180800, // 000C CALL R6 4 - 0x4C1C0000, // 000D LDNIL R7 - 0x201C0C07, // 000E NE R7 R6 R7 - 0x741E0004, // 000F JMPT R7 #0015 - 0x881C0703, // 0010 GETMBR R7 R3 K3 - 0xB8220800, // 0011 GETNGBL R8 K4 - 0x88201105, // 0012 GETMBR R8 R8 K5 - 0x201C0E08, // 0013 NE R7 R7 R8 - 0x781E0000, // 0014 JMPF R7 #0016 - 0x80040C00, // 0015 RET 1 R6 - 0x00100906, // 0016 ADD R4 R4 K6 - 0x7001FFE8, // 0017 JMP #0001 - 0x80000000, // 0018 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: read_attribute -********************************************************************/ -be_local_closure(Matter_Device_read_attribute, /* name */ - be_nested_proto( - 13, /* nstack */ 5, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -2030,36 +2337,21 @@ be_local_closure(Matter_Device_read_attribute, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 4]) { /* constants */ - /* K0 */ be_const_int(0), - /* K1 */ be_nested_str_weak(plugins), - /* K2 */ be_nested_str_weak(read_attribute), - /* K3 */ be_const_int(1), + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(udp_server), + /* K1 */ be_nested_str_weak(send_response), }), - be_str_weak(read_attribute), + be_str_weak(msg_send), &be_const_str_solidified, - ( &(const binstruction[21]) { /* code */ - 0x58140000, // 0000 LDCONST R5 K0 - 0x6018000C, // 0001 GETGBL R6 G12 - 0x881C0101, // 0002 GETMBR R7 R0 K1 - 0x7C180200, // 0003 CALL R6 1 - 0x14180A06, // 0004 LT R6 R5 R6 - 0x781A000D, // 0005 JMPF R6 #0014 - 0x88180101, // 0006 GETMBR R6 R0 K1 - 0x94180C05, // 0007 GETIDX R6 R6 R5 - 0x8C1C0D02, // 0008 GETMET R7 R6 K2 - 0x5C240200, // 0009 MOVE R9 R1 - 0x5C280400, // 000A MOVE R10 R2 - 0x5C2C0600, // 000B MOVE R11 R3 - 0x5C300800, // 000C MOVE R12 R4 - 0x7C1C0A00, // 000D CALL R7 5 - 0x4C200000, // 000E LDNIL R8 - 0x20200E08, // 000F NE R8 R7 R8 - 0x78220000, // 0010 JMPF R8 #0012 - 0x80040E00, // 0011 RET 1 R7 - 0x00140B03, // 0012 ADD R5 R5 K3 - 0x7001FFEC, // 0013 JMP #0001 - 0x80000000, // 0014 RET 0 + ( &(const binstruction[ 8]) { /* code */ + 0x88140100, // 0000 GETMBR R5 R0 K0 + 0x8C140B01, // 0001 GETMET R5 R5 K1 + 0x5C1C0200, // 0002 MOVE R7 R1 + 0x5C200400, // 0003 MOVE R8 R2 + 0x5C240600, // 0004 MOVE R9 R3 + 0x5C280800, // 0005 MOVE R10 R4 + 0x7C140A00, // 0006 CALL R5 5 + 0x80040A00, // 0007 RET 1 R5 }) ) ); @@ -2072,55 +2364,56 @@ be_local_closure(Matter_Device_read_attribute, /* name */ be_local_class(Matter_Device, 18, NULL, - be_nested_map(48, + be_nested_map(49, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(read_attribute, 15), be_const_closure(Matter_Device_read_attribute_closure) }, + { be_const_key_weak(compute_manual_pairing_code, 12), be_const_closure(Matter_Device_compute_manual_pairing_code_closure) }, + { be_const_key_weak(msg_handler, 45), be_const_var(2) }, + { be_const_key_weak(FILENAME, 20), be_nested_str_weak(_matter_device_X2Ejson) }, + { be_const_key_weak(plugins, 40), be_const_var(0) }, + { be_const_key_weak(process_attribute_expansion, -1), be_const_closure(Matter_Device_process_attribute_expansion_closure) }, { be_const_key_weak(msg_send, -1), be_const_closure(Matter_Device_msg_send_closure) }, - { be_const_key_weak(start_operational_dicovery_deferred, 32), be_const_closure(Matter_Device_start_operational_dicovery_deferred_closure) }, - { be_const_key_weak(start_commissioning_complete_deferred, 30), be_const_closure(Matter_Device_start_commissioning_complete_deferred_closure) }, - { be_const_key_weak(invoke_request, -1), be_const_closure(Matter_Device_invoke_request_closure) }, - { be_const_key_weak(stop, -1), be_const_closure(Matter_Device_stop_closure) }, - { be_const_key_weak(udp_server, -1), be_const_var(1) }, - { be_const_key_weak(mdns_announce_op_discovery, -1), be_const_closure(Matter_Device_mdns_announce_op_discovery_closure) }, - { be_const_key_weak(hostname_eth, 38), be_const_var(8) }, - { be_const_key_weak(every_second, -1), be_const_closure(Matter_Device_every_second_closure) }, - { be_const_key_weak(start_commissioning_complete, -1), be_const_closure(Matter_Device_start_commissioning_complete_closure) }, - { be_const_key_weak(ui, 4), be_const_var(4) }, - { be_const_key_weak(PRODUCT_ID, -1), be_const_int(32768) }, - { be_const_key_weak(L, -1), be_const_var(17) }, - { be_const_key_weak(vendorid, -1), be_const_var(9) }, - { be_const_key_weak(mdns_announce_op_discovery_all_sessions, -1), be_const_closure(Matter_Device_mdns_announce_op_discovery_all_sessions_closure) }, - { be_const_key_weak(start_operational_dicovery, -1), be_const_closure(Matter_Device_start_operational_dicovery_closure) }, - { be_const_key_weak(productid, -1), be_const_var(10) }, - { be_const_key_weak(compute_manual_pairing_code, -1), be_const_closure(Matter_Device_compute_manual_pairing_code_closure) }, - { be_const_key_weak(start_udp, -1), be_const_closure(Matter_Device_start_udp_closure) }, - { be_const_key_weak(sessions, -1), be_const_var(3) }, - { be_const_key_weak(start_mdns_announce_hostnames, -1), be_const_closure(Matter_Device_start_mdns_announce_hostnames_closure) }, - { be_const_key_weak(finish_commissioning, 7), be_const_closure(Matter_Device_finish_commissioning_closure) }, - { be_const_key_weak(packet_ack, 10), be_const_closure(Matter_Device_packet_ack_closure) }, - { be_const_key_weak(discriminator, -1), be_const_var(11) }, - { be_const_key_weak(VENDOR_ID, -1), be_const_int(65521) }, - { be_const_key_weak(start_basic_commissioning, 41), be_const_closure(Matter_Device_start_basic_commissioning_closure) }, - { be_const_key_weak(plugins, 24), be_const_var(0) }, - { be_const_key_weak(compute_pbkdf, 20), be_const_closure(Matter_Device_compute_pbkdf_closure) }, - { be_const_key_weak(passcode, -1), be_const_var(12) }, - { be_const_key_weak(init, 47), be_const_closure(Matter_Device_init_closure) }, - { be_const_key_weak(PBKDF_ITERATIONS, -1), be_const_int(1000) }, - { be_const_key_weak(w0, 46), be_const_var(15) }, - { be_const_key_weak(salt, 36), be_const_var(14) }, - { be_const_key_weak(UDP_PORT, -1), be_const_int(5540) }, + { be_const_key_weak(packet_ack, -1), be_const_closure(Matter_Device_packet_ack_closure) }, + { be_const_key_weak(save_param, 48), be_const_closure(Matter_Device_save_param_closure) }, { be_const_key_weak(_start_mdns_announce, -1), be_const_closure(Matter_Device__start_mdns_announce_closure) }, - { be_const_key_weak(msg_handler, -1), be_const_var(2) }, - { be_const_key_weak(w1, 35), be_const_var(16) }, - { be_const_key_weak(FILENAME, -1), be_nested_str_weak(_matter_device_X2Ejson) }, - { be_const_key_weak(compute_qrcode_content, -1), be_const_closure(Matter_Device_compute_qrcode_content_closure) }, - { be_const_key_weak(msg_received, -1), be_const_closure(Matter_Device_msg_received_closure) }, + { be_const_key_weak(start_operational_dicovery_deferred, -1), be_const_closure(Matter_Device_start_operational_dicovery_deferred_closure) }, + { be_const_key_weak(ui, 47), be_const_var(4) }, + { be_const_key_weak(w0, -1), be_const_var(15) }, + { be_const_key_weak(invoke_request, -1), be_const_closure(Matter_Device_invoke_request_closure) }, + { be_const_key_weak(passcode, 15), be_const_var(12) }, + { be_const_key_weak(start_mdns_announce_hostnames, -1), be_const_closure(Matter_Device_start_mdns_announce_hostnames_closure) }, + { be_const_key_weak(hostname_eth, 31), be_const_var(8) }, + { be_const_key_weak(L, -1), be_const_var(17) }, + { be_const_key_weak(every_second, 8), be_const_closure(Matter_Device_every_second_closure) }, + { be_const_key_weak(VENDOR_ID, -1), be_const_int(65521) }, + { be_const_key_weak(init, -1), be_const_closure(Matter_Device_init_closure) }, + { be_const_key_weak(get_active_endpoints, -1), be_const_closure(Matter_Device_get_active_endpoints_closure) }, + { be_const_key_weak(iterations, 43), be_const_var(13) }, { be_const_key_weak(commissioning_instance_eth, -1), be_const_var(6) }, - { be_const_key_weak(commissioning_instance_wifi, 0), be_const_var(5) }, - { be_const_key_weak(PASSCODE_DEFAULT, 13), be_const_int(20202021) }, + { be_const_key_weak(start_operational_dicovery, 41), be_const_closure(Matter_Device_start_operational_dicovery_closure) }, + { be_const_key_weak(start_commissioning_complete, 16), be_const_closure(Matter_Device_start_commissioning_complete_closure) }, + { be_const_key_weak(start_basic_commissioning, 42), be_const_closure(Matter_Device_start_basic_commissioning_closure) }, + { be_const_key_weak(productid, -1), be_const_var(10) }, + { be_const_key_weak(PRODUCT_ID, -1), be_const_int(32768) }, + { be_const_key_weak(PBKDF_ITERATIONS, 36), be_const_int(1000) }, + { be_const_key_weak(salt, 5), be_const_var(14) }, + { be_const_key_weak(w1, -1), be_const_var(16) }, + { be_const_key_weak(start_commissioning_complete_deferred, -1), be_const_closure(Matter_Device_start_commissioning_complete_deferred_closure) }, + { be_const_key_weak(mdns_announce_op_discovery, 27), be_const_closure(Matter_Device_mdns_announce_op_discovery_closure) }, + { be_const_key_weak(discriminator, -1), be_const_var(11) }, + { be_const_key_weak(commissioning_instance_wifi, -1), be_const_var(5) }, + { be_const_key_weak(start_udp, 34), be_const_closure(Matter_Device_start_udp_closure) }, + { be_const_key_weak(UDP_PORT, -1), be_const_int(5540) }, + { be_const_key_weak(compute_pbkdf, -1), be_const_closure(Matter_Device_compute_pbkdf_closure) }, { be_const_key_weak(hostname_wifi, -1), be_const_var(7) }, - { be_const_key_weak(iterations, -1), be_const_var(13) }, - { be_const_key_weak(save_param, -1), be_const_closure(Matter_Device_save_param_closure) }, + { be_const_key_weak(udp_server, 2), be_const_var(1) }, + { be_const_key_weak(finish_commissioning, -1), be_const_closure(Matter_Device_finish_commissioning_closure) }, + { be_const_key_weak(compute_qrcode_content, -1), be_const_closure(Matter_Device_compute_qrcode_content_closure) }, + { be_const_key_weak(PASSCODE_DEFAULT, -1), be_const_int(20202021) }, + { be_const_key_weak(vendorid, 44), be_const_var(9) }, + { be_const_key_weak(sessions, -1), be_const_var(3) }, + { be_const_key_weak(mdns_announce_op_discovery_all_sessions, -1), be_const_closure(Matter_Device_mdns_announce_op_discovery_all_sessions_closure) }, + { be_const_key_weak(msg_received, 6), be_const_closure(Matter_Device_msg_received_closure) }, + { be_const_key_weak(stop, -1), be_const_closure(Matter_Device_stop_closure) }, { be_const_key_weak(load_param, -1), be_const_closure(Matter_Device_load_param_closure) }, })), be_str_weak(Matter_Device) diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM.h index 2c89b8f4f..1e828f15b 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM.h @@ -6,19 +6,124 @@ extern const bclass be_class_Matter_Response_container; +/******************************************************************** +** Solidified function: tostring +********************************************************************/ +be_local_closure(Matter_Response_container_tostring, /* name */ + be_nested_proto( + 7, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[14]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(), + /* K2 */ be_nested_str_weak(endpoint), + /* K3 */ be_nested_str_weak(format), + /* K4 */ be_nested_str_weak(_X5B_X2502X_X5D), + /* K5 */ be_nested_str_weak(_X5B_X2A_X2A_X5D), + /* K6 */ be_nested_str_weak(cluster), + /* K7 */ be_nested_str_weak(_X2504X_X2F), + /* K8 */ be_nested_str_weak(_X2A_X2A_X2A_X2A_X2F), + /* K9 */ be_nested_str_weak(attribute), + /* K10 */ be_nested_str_weak(_X2504X), + /* K11 */ be_nested_str_weak(command), + /* K12 */ be_nested_str_weak(Exception_X3E_X20), + /* K13 */ be_nested_str_weak(_X2C_X20), + }), + be_str_weak(tostring), + &be_const_str_solidified, + ( &(const binstruction[66]) { /* code */ + 0xA8020031, // 0000 EXBLK 0 #0033 + 0xA4060000, // 0001 IMPORT R1 K0 + 0x58080001, // 0002 LDCONST R2 K1 + 0x880C0102, // 0003 GETMBR R3 R0 K2 + 0x4C100000, // 0004 LDNIL R4 + 0x200C0604, // 0005 NE R3 R3 R4 + 0x780E0004, // 0006 JMPF R3 #000C + 0x8C0C0303, // 0007 GETMET R3 R1 K3 + 0x58140004, // 0008 LDCONST R5 K4 + 0x88180102, // 0009 GETMBR R6 R0 K2 + 0x7C0C0600, // 000A CALL R3 3 + 0x70020000, // 000B JMP #000D + 0x580C0005, // 000C LDCONST R3 K5 + 0x00080403, // 000D ADD R2 R2 R3 + 0x880C0106, // 000E GETMBR R3 R0 K6 + 0x4C100000, // 000F LDNIL R4 + 0x200C0604, // 0010 NE R3 R3 R4 + 0x780E0004, // 0011 JMPF R3 #0017 + 0x8C0C0303, // 0012 GETMET R3 R1 K3 + 0x58140007, // 0013 LDCONST R5 K7 + 0x88180106, // 0014 GETMBR R6 R0 K6 + 0x7C0C0600, // 0015 CALL R3 3 + 0x70020000, // 0016 JMP #0018 + 0x580C0008, // 0017 LDCONST R3 K8 + 0x00080403, // 0018 ADD R2 R2 R3 + 0x880C0109, // 0019 GETMBR R3 R0 K9 + 0x4C100000, // 001A LDNIL R4 + 0x200C0604, // 001B NE R3 R3 R4 + 0x780E0004, // 001C JMPF R3 #0022 + 0x8C0C0303, // 001D GETMET R3 R1 K3 + 0x5814000A, // 001E LDCONST R5 K10 + 0x88180109, // 001F GETMBR R6 R0 K9 + 0x7C0C0600, // 0020 CALL R3 3 + 0x70020000, // 0021 JMP #0023 + 0x580C0001, // 0022 LDCONST R3 K1 + 0x00080403, // 0023 ADD R2 R2 R3 + 0x880C010B, // 0024 GETMBR R3 R0 K11 + 0x4C100000, // 0025 LDNIL R4 + 0x200C0604, // 0026 NE R3 R3 R4 + 0x780E0004, // 0027 JMPF R3 #002D + 0x8C0C0303, // 0028 GETMET R3 R1 K3 + 0x5814000A, // 0029 LDCONST R5 K10 + 0x88180109, // 002A GETMBR R6 R0 K9 + 0x7C0C0600, // 002B CALL R3 3 + 0x70020000, // 002C JMP #002E + 0x580C0001, // 002D LDCONST R3 K1 + 0x00080403, // 002E ADD R2 R2 R3 + 0xA8040001, // 002F EXBLK 1 1 + 0x80040400, // 0030 RET 1 R2 + 0xA8040001, // 0031 EXBLK 1 1 + 0x7002000D, // 0032 JMP #0041 + 0xAC040002, // 0033 CATCH R1 0 2 + 0x7002000A, // 0034 JMP #0040 + 0x600C0008, // 0035 GETGBL R3 G8 + 0x5C100200, // 0036 MOVE R4 R1 + 0x7C0C0200, // 0037 CALL R3 1 + 0x000E1803, // 0038 ADD R3 K12 R3 + 0x000C070D, // 0039 ADD R3 R3 K13 + 0x60100008, // 003A GETGBL R4 G8 + 0x5C140400, // 003B MOVE R5 R2 + 0x7C100200, // 003C CALL R4 1 + 0x000C0604, // 003D ADD R3 R3 R4 + 0x80040600, // 003E RET 1 R3 + 0x70020000, // 003F JMP #0041 + 0xB0080000, // 0040 RAISE 2 R0 R0 + 0x80000000, // 0041 RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified class: Matter_Response_container ********************************************************************/ be_local_class(Matter_Response_container, 5, NULL, - be_nested_map(5, + be_nested_map(6, ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(tostring, -1), be_const_closure(Matter_Response_container_tostring_closure) }, + { be_const_key_weak(cluster, 3), be_const_var(1) }, { be_const_key_weak(command, -1), be_const_var(3) }, + { be_const_key_weak(status, 0), be_const_var(4) }, + { be_const_key_weak(endpoint, -1), be_const_var(0) }, { be_const_key_weak(attribute, -1), be_const_var(2) }, - { be_const_key_weak(cluster, -1), be_const_var(1) }, - { be_const_key_weak(endpoint, 0), be_const_var(0) }, - { be_const_key_weak(status, -1), be_const_var(4) }, })), be_str_weak(Matter_Response_container) ); @@ -37,15 +142,15 @@ extern const bclass be_class_Matter_IM; ********************************************************************/ be_local_closure(Matter_IM_process_timed_request, /* name */ be_nested_proto( - 15, /* nstack */ - 5, /* argc */ + 13, /* nstack */ + 3, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[24]) { /* constants */ + ( &(const bvalue[26]) { /* constants */ /* K0 */ be_nested_str_weak(string), /* K1 */ be_nested_str_weak(matter), /* K2 */ be_nested_str_weak(TimedRequestMessage), @@ -57,75 +162,77 @@ be_local_closure(Matter_IM_process_timed_request, /* name */ /* K8 */ be_nested_str_weak(format), /* K9 */ be_nested_str_weak(MTR_X3A_X20_X3EReceived_IM_X20_X20_X20TimedRequest_X3D_X25i_X20from_X20_X5B_X25s_X5D_X3A_X25i), /* K10 */ be_nested_str_weak(timeout), - /* K11 */ be_const_int(2), - /* K12 */ be_nested_str_weak(StatusResponseMessage), - /* K13 */ be_nested_str_weak(status), - /* K14 */ be_nested_str_weak(SUCCESS), - /* K15 */ be_nested_str_weak(build_response), - /* K16 */ be_const_int(1), - /* K17 */ be_nested_str_weak(encode), - /* K18 */ be_nested_str_weak(to_TLV), - /* K19 */ be_nested_str_weak(encrypt), - /* K20 */ be_nested_str_weak(responder), - /* K21 */ be_nested_str_weak(send_response), - /* K22 */ be_nested_str_weak(raw), - /* K23 */ be_nested_str_weak(message_counter), + /* K11 */ be_nested_str_weak(remote_ip), + /* K12 */ be_nested_str_weak(remote_port), + /* K13 */ be_const_int(2), + /* K14 */ be_nested_str_weak(StatusResponseMessage), + /* K15 */ be_nested_str_weak(status), + /* K16 */ be_nested_str_weak(SUCCESS), + /* K17 */ be_nested_str_weak(build_response), + /* K18 */ be_const_int(1), + /* K19 */ be_nested_str_weak(encode), + /* K20 */ be_nested_str_weak(to_TLV), + /* K21 */ be_nested_str_weak(encrypt), + /* K22 */ be_nested_str_weak(responder), + /* K23 */ be_nested_str_weak(send_response), + /* K24 */ be_nested_str_weak(raw), + /* K25 */ be_nested_str_weak(message_counter), }), be_str_weak(process_timed_request), &be_const_str_solidified, ( &(const binstruction[52]) { /* code */ - 0xA4160000, // 0000 IMPORT R5 K0 - 0xB81A0200, // 0001 GETNGBL R6 K1 - 0x8C180D02, // 0002 GETMET R6 R6 K2 - 0x7C180200, // 0003 CALL R6 1 - 0x8C180D03, // 0004 GETMET R6 R6 K3 - 0x5C200400, // 0005 MOVE R8 R2 - 0x7C180400, // 0006 CALL R6 2 - 0xB81E0800, // 0007 GETNGBL R7 K4 - 0x8C1C0F05, // 0008 GETMET R7 R7 K5 - 0x60240008, // 0009 GETGBL R9 G8 - 0x5C280C00, // 000A MOVE R10 R6 - 0x7C240200, // 000B CALL R9 1 - 0x00260C09, // 000C ADD R9 K6 R9 - 0x58280007, // 000D LDCONST R10 K7 - 0x7C1C0600, // 000E CALL R7 3 - 0xB81E0800, // 000F GETNGBL R7 K4 - 0x8C1C0F05, // 0010 GETMET R7 R7 K5 - 0x8C240B08, // 0011 GETMET R9 R5 K8 - 0x582C0009, // 0012 LDCONST R11 K9 - 0x88300D0A, // 0013 GETMBR R12 R6 K10 - 0x5C340600, // 0014 MOVE R13 R3 - 0x5C380800, // 0015 MOVE R14 R4 - 0x7C240A00, // 0016 CALL R9 5 - 0x5828000B, // 0017 LDCONST R10 K11 - 0x7C1C0600, // 0018 CALL R7 3 - 0xB81E0200, // 0019 GETNGBL R7 K1 - 0x8C1C0F0C, // 001A GETMET R7 R7 K12 - 0x7C1C0200, // 001B CALL R7 1 - 0xB8220200, // 001C GETNGBL R8 K1 - 0x8820110E, // 001D GETMBR R8 R8 K14 - 0x901E1A08, // 001E SETMBR R7 K13 R8 - 0x8C20030F, // 001F GETMET R8 R1 K15 - 0x58280010, // 0020 LDCONST R10 K16 - 0x502C0200, // 0021 LDBOOL R11 1 0 - 0x7C200600, // 0022 CALL R8 3 - 0x8C241111, // 0023 GETMET R9 R8 K17 - 0x8C2C0F12, // 0024 GETMET R11 R7 K18 - 0x7C2C0200, // 0025 CALL R11 1 - 0x8C2C1711, // 0026 GETMET R11 R11 K17 - 0x7C2C0200, // 0027 CALL R11 1 - 0x7C240400, // 0028 CALL R9 2 - 0x8C241113, // 0029 GETMET R9 R8 K19 - 0x7C240200, // 002A CALL R9 1 - 0x88240114, // 002B GETMBR R9 R0 K20 - 0x8C241315, // 002C GETMET R9 R9 K21 - 0x882C1116, // 002D GETMBR R11 R8 K22 - 0x5C300600, // 002E MOVE R12 R3 - 0x5C340800, // 002F MOVE R13 R4 - 0x88381117, // 0030 GETMBR R14 R8 K23 - 0x7C240A00, // 0031 CALL R9 5 - 0x50240200, // 0032 LDBOOL R9 1 0 - 0x80041200, // 0033 RET 1 R9 + 0xA40E0000, // 0000 IMPORT R3 K0 + 0xB8120200, // 0001 GETNGBL R4 K1 + 0x8C100902, // 0002 GETMET R4 R4 K2 + 0x7C100200, // 0003 CALL R4 1 + 0x8C100903, // 0004 GETMET R4 R4 K3 + 0x5C180400, // 0005 MOVE R6 R2 + 0x7C100400, // 0006 CALL R4 2 + 0xB8160800, // 0007 GETNGBL R5 K4 + 0x8C140B05, // 0008 GETMET R5 R5 K5 + 0x601C0008, // 0009 GETGBL R7 G8 + 0x5C200800, // 000A MOVE R8 R4 + 0x7C1C0200, // 000B CALL R7 1 + 0x001E0C07, // 000C ADD R7 K6 R7 + 0x58200007, // 000D LDCONST R8 K7 + 0x7C140600, // 000E CALL R5 3 + 0xB8160800, // 000F GETNGBL R5 K4 + 0x8C140B05, // 0010 GETMET R5 R5 K5 + 0x8C1C0708, // 0011 GETMET R7 R3 K8 + 0x58240009, // 0012 LDCONST R9 K9 + 0x8828090A, // 0013 GETMBR R10 R4 K10 + 0x882C030B, // 0014 GETMBR R11 R1 K11 + 0x8830030C, // 0015 GETMBR R12 R1 K12 + 0x7C1C0A00, // 0016 CALL R7 5 + 0x5820000D, // 0017 LDCONST R8 K13 + 0x7C140600, // 0018 CALL R5 3 + 0xB8160200, // 0019 GETNGBL R5 K1 + 0x8C140B0E, // 001A GETMET R5 R5 K14 + 0x7C140200, // 001B CALL R5 1 + 0xB81A0200, // 001C GETNGBL R6 K1 + 0x88180D10, // 001D GETMBR R6 R6 K16 + 0x90161E06, // 001E SETMBR R5 K15 R6 + 0x8C180311, // 001F GETMET R6 R1 K17 + 0x58200012, // 0020 LDCONST R8 K18 + 0x50240200, // 0021 LDBOOL R9 1 0 + 0x7C180600, // 0022 CALL R6 3 + 0x8C1C0D13, // 0023 GETMET R7 R6 K19 + 0x8C240B14, // 0024 GETMET R9 R5 K20 + 0x7C240200, // 0025 CALL R9 1 + 0x8C241313, // 0026 GETMET R9 R9 K19 + 0x7C240200, // 0027 CALL R9 1 + 0x7C1C0400, // 0028 CALL R7 2 + 0x8C1C0D15, // 0029 GETMET R7 R6 K21 + 0x7C1C0200, // 002A CALL R7 1 + 0x881C0116, // 002B GETMBR R7 R0 K22 + 0x8C1C0F17, // 002C GETMET R7 R7 K23 + 0x88240D18, // 002D GETMBR R9 R6 K24 + 0x8828030B, // 002E GETMBR R10 R1 K11 + 0x882C030C, // 002F GETMBR R11 R1 K12 + 0x88300D19, // 0030 GETMBR R12 R6 K25 + 0x7C1C0A00, // 0031 CALL R7 5 + 0x501C0200, // 0032 LDBOOL R7 1 0 + 0x80040E00, // 0033 RET 1 R7 }) ) ); @@ -137,8 +244,8 @@ be_local_closure(Matter_IM_process_timed_request, /* name */ ********************************************************************/ be_local_closure(Matter_IM_process_status_response, /* name */ be_nested_proto( - 13, /* nstack */ - 5, /* argc */ + 11, /* nstack */ + 3, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ @@ -158,48 +265,21 @@ be_local_closure(Matter_IM_process_status_response, /* name */ be_str_weak(process_status_response), &be_const_str_solidified, ( &(const binstruction[15]) { /* code */ - 0xA4160000, // 0000 IMPORT R5 K0 - 0x8C180501, // 0001 GETMET R6 R2 K1 - 0x58200002, // 0002 LDCONST R8 K2 - 0x542600FE, // 0003 LDINT R9 255 - 0x7C180600, // 0004 CALL R6 3 - 0xB81E0600, // 0005 GETNGBL R7 K3 - 0x8C1C0F04, // 0006 GETMET R7 R7 K4 - 0x8C240B05, // 0007 GETMET R9 R5 K5 - 0x582C0006, // 0008 LDCONST R11 K6 - 0x5C300C00, // 0009 MOVE R12 R6 - 0x7C240600, // 000A CALL R9 3 - 0x58280007, // 000B LDCONST R10 K7 - 0x7C1C0600, // 000C CALL R7 3 - 0x501C0200, // 000D LDBOOL R7 1 0 - 0x80040E00, // 000E RET 1 R7 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: init -********************************************************************/ -be_local_closure(Matter_IM_init, /* name */ - be_nested_proto( - 2, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(responder), - }), - be_str_weak(init), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x90020001, // 0000 SETMBR R0 K0 R1 - 0x80000000, // 0001 RET 0 + 0xA40E0000, // 0000 IMPORT R3 K0 + 0x8C100501, // 0001 GETMET R4 R2 K1 + 0x58180002, // 0002 LDCONST R6 K2 + 0x541E00FE, // 0003 LDINT R7 255 + 0x7C100600, // 0004 CALL R4 3 + 0xB8160600, // 0005 GETNGBL R5 K3 + 0x8C140B04, // 0006 GETMET R5 R5 K4 + 0x8C1C0705, // 0007 GETMET R7 R3 K5 + 0x58240006, // 0008 LDCONST R9 K6 + 0x5C280800, // 0009 MOVE R10 R4 + 0x7C1C0600, // 000A CALL R7 3 + 0x58200007, // 000B LDCONST R8 K7 + 0x7C140600, // 000C CALL R5 3 + 0x50140200, // 000D LDBOOL R5 1 0 + 0x80040A00, // 000E RET 1 R5 }) ) ); @@ -230,13 +310,1167 @@ be_local_closure(Matter_IM_every_second, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: report_data +********************************************************************/ +be_local_closure(Matter_IM_report_data, /* name */ + be_nested_proto( + 9, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(ReportDataMessage), + /* K3 */ be_nested_str_weak(from_TLV), + /* K4 */ be_nested_str_weak(tasmota), + /* K5 */ be_nested_str_weak(log), + /* K6 */ be_nested_str_weak(MTR_X3A_X20received_X20ReportDataMessage_X3D), + /* K7 */ be_const_int(3), + }), + be_str_weak(report_data), + &be_const_str_solidified, + ( &(const binstruction[17]) { /* code */ + 0xA40E0000, // 0000 IMPORT R3 K0 + 0xB8120200, // 0001 GETNGBL R4 K1 + 0x8C100902, // 0002 GETMET R4 R4 K2 + 0x7C100200, // 0003 CALL R4 1 + 0x8C100903, // 0004 GETMET R4 R4 K3 + 0x5C180400, // 0005 MOVE R6 R2 + 0x7C100400, // 0006 CALL R4 2 + 0xB8160800, // 0007 GETNGBL R5 K4 + 0x8C140B05, // 0008 GETMET R5 R5 K5 + 0x601C0008, // 0009 GETGBL R7 G8 + 0x5C200800, // 000A MOVE R8 R4 + 0x7C1C0200, // 000B CALL R7 1 + 0x001E0C07, // 000C ADD R7 K6 R7 + 0x58200007, // 000D LDCONST R8 K7 + 0x7C140600, // 000E CALL R5 3 + 0x50140000, // 000F LDBOOL R5 0 0 + 0x80040A00, // 0010 RET 1 R5 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: process_invoke_response +********************************************************************/ +be_local_closure(Matter_IM_process_invoke_response, /* name */ + be_nested_proto( + 9, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(InvokeResponseMessage), + /* K3 */ be_nested_str_weak(from_TLV), + /* K4 */ be_nested_str_weak(tasmota), + /* K5 */ be_nested_str_weak(log), + /* K6 */ be_nested_str_weak(MTR_X3A_X20received_X20InvokeResponseMessage_X3D), + /* K7 */ be_const_int(3), + }), + be_str_weak(process_invoke_response), + &be_const_str_solidified, + ( &(const binstruction[17]) { /* code */ + 0xA40E0000, // 0000 IMPORT R3 K0 + 0xB8120200, // 0001 GETNGBL R4 K1 + 0x8C100902, // 0002 GETMET R4 R4 K2 + 0x7C100200, // 0003 CALL R4 1 + 0x8C100903, // 0004 GETMET R4 R4 K3 + 0x5C180400, // 0005 MOVE R6 R2 + 0x7C100400, // 0006 CALL R4 2 + 0xB8160800, // 0007 GETNGBL R5 K4 + 0x8C140B05, // 0008 GETMET R5 R5 K5 + 0x601C0008, // 0009 GETGBL R7 G8 + 0x5C200800, // 000A MOVE R8 R4 + 0x7C1C0200, // 000B CALL R7 1 + 0x001E0C07, // 000C ADD R7 K6 R7 + 0x58200007, // 000D LDCONST R8 K7 + 0x7C140600, // 000E CALL R5 3 + 0x50140000, // 000F LDBOOL R5 0 0 + 0x80040A00, // 0010 RET 1 R5 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: process_read_request +********************************************************************/ +be_local_closure(Matter_IM_process_read_request, /* name */ + be_nested_proto( + 15, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 1, /* has sup protos */ + ( &(const struct bproto*[ 2]) { + be_nested_proto( + 18, /* nstack */ + 4, /* argc */ + 0, /* varg */ + 1, /* has upvals */ + ( &(const bupvaldesc[ 1]) { /* upvals */ + be_local_const_upval(1, 1), + }), + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[32]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(get_attribute_name), + /* K3 */ be_nested_str_weak(cluster), + /* K4 */ be_nested_str_weak(attribute), + /* K5 */ be_nested_str_weak(_X20_X28), + /* K6 */ be_nested_str_weak(_X29), + /* K7 */ be_nested_str_weak(), + /* K8 */ be_nested_str_weak(read_attribute), + /* K9 */ be_nested_str_weak(AttributeReportIB), + /* K10 */ be_nested_str_weak(attribute_data), + /* K11 */ be_nested_str_weak(AttributeDataIB), + /* K12 */ be_nested_str_weak(data_version), + /* K13 */ be_const_int(1), + /* K14 */ be_nested_str_weak(path), + /* K15 */ be_nested_str_weak(AttributePathIB), + /* K16 */ be_nested_str_weak(endpoint), + /* K17 */ be_nested_str_weak(data), + /* K18 */ be_nested_str_weak(attribute_reports), + /* K19 */ be_nested_str_weak(push), + /* K20 */ be_nested_str_weak(tasmota), + /* K21 */ be_nested_str_weak(log), + /* K22 */ be_nested_str_weak(format), + /* K23 */ be_nested_str_weak(MTR_X3A_X20Read_Attr_X20_X25s_X25s_X20_X2D_X20_X25s), + /* K24 */ be_const_int(2), + /* K25 */ be_nested_str_weak(status), + /* K26 */ be_nested_str_weak(attribute_status), + /* K27 */ be_nested_str_weak(AttributeStatusIB), + /* K28 */ be_nested_str_weak(StatusIB), + /* K29 */ be_nested_str_weak(MTR_X3A_X20Read_Attr_X20_X25s_X25s_X20_X2D_X20STATUS_X3A_X200x_X2502X_X20_X25s), + /* K30 */ be_nested_str_weak(UNSUPPORTED_ATTRIBUTE), + /* K31 */ be_nested_str_weak(MTR_X3A_X20Read_Attr_X20_X25s_X25s_X20_X2D_X20IGNORED), + }), + be_str_weak(read_single_attribute), + &be_const_str_solidified, + ( &(const binstruction[150]) { /* code */ + 0xA4120000, // 0000 IMPORT R4 K0 + 0xB8160200, // 0001 GETNGBL R5 K1 + 0x8C140B02, // 0002 GETMET R5 R5 K2 + 0x881C0503, // 0003 GETMBR R7 R2 K3 + 0x88200504, // 0004 GETMBR R8 R2 K4 + 0x7C140600, // 0005 CALL R5 3 + 0x78160002, // 0006 JMPF R5 #000A + 0x001A0A05, // 0007 ADD R6 K5 R5 + 0x00180D06, // 0008 ADD R6 R6 K6 + 0x70020000, // 0009 JMP #000B + 0x58180007, // 000A LDCONST R6 K7 + 0x5C140C00, // 000B MOVE R5 R6 + 0x4C180000, // 000C LDNIL R6 + 0x20180206, // 000D NE R6 R1 R6 + 0x781A0004, // 000E JMPF R6 #0014 + 0x8C180308, // 000F GETMET R6 R1 K8 + 0x68200000, // 0010 GETUPV R8 U0 + 0x5C240400, // 0011 MOVE R9 R2 + 0x7C180600, // 0012 CALL R6 3 + 0x70020000, // 0013 JMP #0015 + 0x4C180000, // 0014 LDNIL R6 + 0x4C1C0000, // 0015 LDNIL R7 + 0x201C0C07, // 0016 NE R7 R6 R7 + 0x781E0030, // 0017 JMPF R7 #0049 + 0xB81E0200, // 0018 GETNGBL R7 K1 + 0x8C1C0F09, // 0019 GETMET R7 R7 K9 + 0x7C1C0200, // 001A CALL R7 1 + 0xB8220200, // 001B GETNGBL R8 K1 + 0x8C20110B, // 001C GETMET R8 R8 K11 + 0x7C200200, // 001D CALL R8 1 + 0x901E1408, // 001E SETMBR R7 K10 R8 + 0x88200F0A, // 001F GETMBR R8 R7 K10 + 0x9022190D, // 0020 SETMBR R8 K12 K13 + 0x88200F0A, // 0021 GETMBR R8 R7 K10 + 0xB8260200, // 0022 GETNGBL R9 K1 + 0x8C24130F, // 0023 GETMET R9 R9 K15 + 0x7C240200, // 0024 CALL R9 1 + 0x90221C09, // 0025 SETMBR R8 K14 R9 + 0x88200F0A, // 0026 GETMBR R8 R7 K10 + 0x8820110E, // 0027 GETMBR R8 R8 K14 + 0x88240510, // 0028 GETMBR R9 R2 K16 + 0x90222009, // 0029 SETMBR R8 K16 R9 + 0x88200F0A, // 002A GETMBR R8 R7 K10 + 0x8820110E, // 002B GETMBR R8 R8 K14 + 0x88240503, // 002C GETMBR R9 R2 K3 + 0x90220609, // 002D SETMBR R8 K3 R9 + 0x88200F0A, // 002E GETMBR R8 R7 K10 + 0x8820110E, // 002F GETMBR R8 R8 K14 + 0x88240504, // 0030 GETMBR R9 R2 K4 + 0x90220809, // 0031 SETMBR R8 K4 R9 + 0x88200F0A, // 0032 GETMBR R8 R7 K10 + 0x90222206, // 0033 SETMBR R8 K17 R6 + 0x88200112, // 0034 GETMBR R8 R0 K18 + 0x8C201113, // 0035 GETMET R8 R8 K19 + 0x5C280E00, // 0036 MOVE R10 R7 + 0x7C200400, // 0037 CALL R8 2 + 0xB8222800, // 0038 GETNGBL R8 K20 + 0x8C201115, // 0039 GETMET R8 R8 K21 + 0x8C280916, // 003A GETMET R10 R4 K22 + 0x58300017, // 003B LDCONST R12 K23 + 0x60340008, // 003C GETGBL R13 G8 + 0x5C380400, // 003D MOVE R14 R2 + 0x7C340200, // 003E CALL R13 1 + 0x5C380A00, // 003F MOVE R14 R5 + 0x603C0008, // 0040 GETGBL R15 G8 + 0x5C400C00, // 0041 MOVE R16 R6 + 0x7C3C0200, // 0042 CALL R15 1 + 0x7C280A00, // 0043 CALL R10 5 + 0x582C0018, // 0044 LDCONST R11 K24 + 0x7C200600, // 0045 CALL R8 3 + 0x50200200, // 0046 LDBOOL R8 1 0 + 0x80041000, // 0047 RET 1 R8 + 0x7002004B, // 0048 JMP #0095 + 0x881C0519, // 0049 GETMBR R7 R2 K25 + 0x4C200000, // 004A LDNIL R8 + 0x201C0E08, // 004B NE R7 R7 R8 + 0x781E003C, // 004C JMPF R7 #008A + 0x780E003A, // 004D JMPF R3 #0089 + 0xB81E0200, // 004E GETNGBL R7 K1 + 0x8C1C0F09, // 004F GETMET R7 R7 K9 + 0x7C1C0200, // 0050 CALL R7 1 + 0xB8220200, // 0051 GETNGBL R8 K1 + 0x8C20111B, // 0052 GETMET R8 R8 K27 + 0x7C200200, // 0053 CALL R8 1 + 0x901E3408, // 0054 SETMBR R7 K26 R8 + 0x88200F1A, // 0055 GETMBR R8 R7 K26 + 0xB8260200, // 0056 GETNGBL R9 K1 + 0x8C24130F, // 0057 GETMET R9 R9 K15 + 0x7C240200, // 0058 CALL R9 1 + 0x90221C09, // 0059 SETMBR R8 K14 R9 + 0x88200F1A, // 005A GETMBR R8 R7 K26 + 0xB8260200, // 005B GETNGBL R9 K1 + 0x8C24131C, // 005C GETMET R9 R9 K28 + 0x7C240200, // 005D CALL R9 1 + 0x90223209, // 005E SETMBR R8 K25 R9 + 0x88200F1A, // 005F GETMBR R8 R7 K26 + 0x8820110E, // 0060 GETMBR R8 R8 K14 + 0x88240510, // 0061 GETMBR R9 R2 K16 + 0x90222009, // 0062 SETMBR R8 K16 R9 + 0x88200F1A, // 0063 GETMBR R8 R7 K26 + 0x8820110E, // 0064 GETMBR R8 R8 K14 + 0x88240503, // 0065 GETMBR R9 R2 K3 + 0x90220609, // 0066 SETMBR R8 K3 R9 + 0x88200F1A, // 0067 GETMBR R8 R7 K26 + 0x8820110E, // 0068 GETMBR R8 R8 K14 + 0x88240504, // 0069 GETMBR R9 R2 K4 + 0x90220809, // 006A SETMBR R8 K4 R9 + 0x88200F1A, // 006B GETMBR R8 R7 K26 + 0x88201119, // 006C GETMBR R8 R8 K25 + 0x88240519, // 006D GETMBR R9 R2 K25 + 0x90223209, // 006E SETMBR R8 K25 R9 + 0x88200112, // 006F GETMBR R8 R0 K18 + 0x8C201113, // 0070 GETMET R8 R8 K19 + 0x5C280E00, // 0071 MOVE R10 R7 + 0x7C200400, // 0072 CALL R8 2 + 0xB8222800, // 0073 GETNGBL R8 K20 + 0x8C201115, // 0074 GETMET R8 R8 K21 + 0x8C280916, // 0075 GETMET R10 R4 K22 + 0x5830001D, // 0076 LDCONST R12 K29 + 0x60340008, // 0077 GETGBL R13 G8 + 0x5C380400, // 0078 MOVE R14 R2 + 0x7C340200, // 0079 CALL R13 1 + 0x5C380A00, // 007A MOVE R14 R5 + 0x883C0519, // 007B GETMBR R15 R2 K25 + 0x88400519, // 007C GETMBR R16 R2 K25 + 0xB8460200, // 007D GETNGBL R17 K1 + 0x8844231E, // 007E GETMBR R17 R17 K30 + 0x1C402011, // 007F EQ R16 R16 R17 + 0x78420001, // 0080 JMPF R16 #0083 + 0x5840001E, // 0081 LDCONST R16 K30 + 0x70020000, // 0082 JMP #0084 + 0x58400007, // 0083 LDCONST R16 K7 + 0x7C280C00, // 0084 CALL R10 6 + 0x582C0018, // 0085 LDCONST R11 K24 + 0x7C200600, // 0086 CALL R8 3 + 0x50200200, // 0087 LDBOOL R8 1 0 + 0x80041000, // 0088 RET 1 R8 + 0x7002000A, // 0089 JMP #0095 + 0xB81E2800, // 008A GETNGBL R7 K20 + 0x8C1C0F15, // 008B GETMET R7 R7 K21 + 0x8C240916, // 008C GETMET R9 R4 K22 + 0x582C001F, // 008D LDCONST R11 K31 + 0x60300008, // 008E GETGBL R12 G8 + 0x5C340400, // 008F MOVE R13 R2 + 0x7C300200, // 0090 CALL R12 1 + 0x5C340A00, // 0091 MOVE R13 R5 + 0x7C240800, // 0092 CALL R9 4 + 0x58280018, // 0093 LDCONST R10 K24 + 0x7C1C0600, // 0094 CALL R7 3 + 0x80000000, // 0095 RET 0 + }) + ), + be_nested_proto( + 8, /* nstack */ + 3, /* argc */ + 0, /* varg */ + 1, /* has upvals */ + ( &(const bupvaldesc[ 2]) { /* upvals */ + be_local_const_upval(1, 4), + be_local_const_upval(1, 7), + }), + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + be_str_weak(_X3Clambda_X3E), + &be_const_str_solidified, + ( &(const binstruction[ 7]) { /* code */ + 0x680C0000, // 0000 GETUPV R3 U0 + 0x68100001, // 0001 GETUPV R4 U1 + 0x5C140000, // 0002 MOVE R5 R0 + 0x5C180200, // 0003 MOVE R6 R1 + 0x5C1C0400, // 0004 MOVE R7 R2 + 0x7C0C0800, // 0005 CALL R3 4 + 0x80040600, // 0006 RET 1 R3 + }) + ), + }), + 1, /* has constants */ + ( &(const bvalue[30]) { /* constants */ + /* K0 */ be_nested_str_weak(device), + /* K1 */ be_nested_str_weak(get_active_endpoints), + /* K2 */ be_nested_str_weak(tasmota), + /* K3 */ be_nested_str_weak(log), + /* K4 */ be_nested_str_weak(MTR_X3A_X20IM_X3Aread_request_X20processing_X20start), + /* K5 */ be_const_int(3), + /* K6 */ be_nested_str_weak(matter), + /* K7 */ be_nested_str_weak(Response_container), + /* K8 */ be_nested_str_weak(ReadRequestMessage), + /* K9 */ be_nested_str_weak(from_TLV), + /* K10 */ be_nested_str_weak(attributes_requests), + /* K11 */ be_nested_str_weak(ReportDataMessage), + /* K12 */ be_nested_str_weak(attribute_reports), + /* K13 */ be_nested_str_weak(endpoint), + /* K14 */ be_nested_str_weak(cluster), + /* K15 */ be_nested_str_weak(attribute), + /* K16 */ be_nested_str_weak(status), + /* K17 */ be_nested_str_weak(UNSUPPORTED_ATTRIBUTE), + /* K18 */ be_nested_str_weak(get_attribute_name), + /* K19 */ be_nested_str_weak(MTR_X3A_X20Read_Attr_X20), + /* K20 */ be_nested_str_weak(_X20_X28), + /* K21 */ be_nested_str_weak(_X29), + /* K22 */ be_nested_str_weak(), + /* K23 */ be_const_int(2), + /* K24 */ be_nested_str_weak(process_attribute_expansion), + /* K25 */ be_nested_str_weak(stop_iteration), + /* K26 */ be_nested_str_weak(MTR_X3A_X20ReportDataMessage_X3D), + /* K27 */ be_nested_str_weak(MTR_X3A_X20ReportDataMessageTLV_X3D), + /* K28 */ be_nested_str_weak(to_TLV), + /* K29 */ be_nested_str_weak(send_attr_report), + }), + be_str_weak(process_read_request), + &be_const_str_solidified, + ( &(const binstruction[125]) { /* code */ + 0x880C0100, // 0000 GETMBR R3 R0 K0 + 0x8C0C0701, // 0001 GETMET R3 R3 K1 + 0x7C0C0200, // 0002 CALL R3 1 + 0x84100000, // 0003 CLOSURE R4 P0 + 0xB8160400, // 0004 GETNGBL R5 K2 + 0x8C140B03, // 0005 GETMET R5 R5 K3 + 0x581C0004, // 0006 LDCONST R7 K4 + 0x58200005, // 0007 LDCONST R8 K5 + 0x7C140600, // 0008 CALL R5 3 + 0xB8160C00, // 0009 GETNGBL R5 K6 + 0x8C140B07, // 000A GETMET R5 R5 K7 + 0x7C140200, // 000B CALL R5 1 + 0xB81A0C00, // 000C GETNGBL R6 K6 + 0x8C180D08, // 000D GETMET R6 R6 K8 + 0x7C180200, // 000E CALL R6 1 + 0x8C180D09, // 000F GETMET R6 R6 K9 + 0x5C200400, // 0010 MOVE R8 R2 + 0x7C180400, // 0011 CALL R6 2 + 0x881C0D0A, // 0012 GETMBR R7 R6 K10 + 0x4C200000, // 0013 LDNIL R8 + 0x201C0E08, // 0014 NE R7 R7 R8 + 0x781E0063, // 0015 JMPF R7 #007A + 0xB81E0C00, // 0016 GETNGBL R7 K6 + 0x8C1C0F0B, // 0017 GETMET R7 R7 K11 + 0x7C1C0200, // 0018 CALL R7 1 + 0x60200012, // 0019 GETGBL R8 G18 + 0x7C200000, // 001A CALL R8 0 + 0x901E1808, // 001B SETMBR R7 K12 R8 + 0x60200010, // 001C GETGBL R8 G16 + 0x88240D0A, // 001D GETMBR R9 R6 K10 + 0x7C200200, // 001E CALL R8 1 + 0xA8020040, // 001F EXBLK 0 #0061 + 0x5C241000, // 0020 MOVE R9 R8 + 0x7C240000, // 0021 CALL R9 0 + 0x8828130D, // 0022 GETMBR R10 R9 K13 + 0x90161A0A, // 0023 SETMBR R5 K13 R10 + 0x8828130E, // 0024 GETMBR R10 R9 K14 + 0x90161C0A, // 0025 SETMBR R5 K14 R10 + 0x8828130F, // 0026 GETMBR R10 R9 K15 + 0x90161E0A, // 0027 SETMBR R5 K15 R10 + 0xB82A0C00, // 0028 GETNGBL R10 K6 + 0x88281511, // 0029 GETMBR R10 R10 K17 + 0x9016200A, // 002A SETMBR R5 K16 R10 + 0x88280B0D, // 002B GETMBR R10 R5 K13 + 0x4C2C0000, // 002C LDNIL R11 + 0x1C28140B, // 002D EQ R10 R10 R11 + 0x742A0007, // 002E JMPT R10 #0037 + 0x88280B0E, // 002F GETMBR R10 R5 K14 + 0x4C2C0000, // 0030 LDNIL R11 + 0x1C28140B, // 0031 EQ R10 R10 R11 + 0x742A0003, // 0032 JMPT R10 #0037 + 0x88280B0F, // 0033 GETMBR R10 R5 K15 + 0x4C2C0000, // 0034 LDNIL R11 + 0x1C28140B, // 0035 EQ R10 R10 R11 + 0x782A0023, // 0036 JMPF R10 #005B + 0x88280B0E, // 0037 GETMBR R10 R5 K14 + 0x4C2C0000, // 0038 LDNIL R11 + 0x2028140B, // 0039 NE R10 R10 R11 + 0x782A0017, // 003A JMPF R10 #0053 + 0x88280B0F, // 003B GETMBR R10 R5 K15 + 0x4C2C0000, // 003C LDNIL R11 + 0x2028140B, // 003D NE R10 R10 R11 + 0x782A0013, // 003E JMPF R10 #0053 + 0xB82A0C00, // 003F GETNGBL R10 K6 + 0x8C281512, // 0040 GETMET R10 R10 K18 + 0x88300B0E, // 0041 GETMBR R12 R5 K14 + 0x88340B0F, // 0042 GETMBR R13 R5 K15 + 0x7C280600, // 0043 CALL R10 3 + 0xB82E0400, // 0044 GETNGBL R11 K2 + 0x8C2C1703, // 0045 GETMET R11 R11 K3 + 0x60340008, // 0046 GETGBL R13 G8 + 0x5C380A00, // 0047 MOVE R14 R5 + 0x7C340200, // 0048 CALL R13 1 + 0x0036260D, // 0049 ADD R13 K19 R13 + 0x782A0002, // 004A JMPF R10 #004E + 0x003A280A, // 004B ADD R14 K20 R10 + 0x00381D15, // 004C ADD R14 R14 K21 + 0x70020000, // 004D JMP #004F + 0x58380016, // 004E LDCONST R14 K22 + 0x00341A0E, // 004F ADD R13 R13 R14 + 0x58380017, // 0050 LDCONST R14 K23 + 0x7C2C0600, // 0051 CALL R11 3 + 0x70020007, // 0052 JMP #005B + 0xB82A0400, // 0053 GETNGBL R10 K2 + 0x8C281503, // 0054 GETMET R10 R10 K3 + 0x60300008, // 0055 GETGBL R12 G8 + 0x5C340A00, // 0056 MOVE R13 R5 + 0x7C300200, // 0057 CALL R12 1 + 0x0032260C, // 0058 ADD R12 K19 R12 + 0x58340017, // 0059 LDCONST R13 K23 + 0x7C280600, // 005A CALL R10 3 + 0x88280100, // 005B GETMBR R10 R0 K0 + 0x8C281518, // 005C GETMET R10 R10 K24 + 0x5C300A00, // 005D MOVE R12 R5 + 0x84340001, // 005E CLOSURE R13 P1 + 0x7C280600, // 005F CALL R10 3 + 0x7001FFBE, // 0060 JMP #0020 + 0x58200019, // 0061 LDCONST R8 K25 + 0xAC200200, // 0062 CATCH R8 1 0 + 0xB0080000, // 0063 RAISE 2 R0 R0 + 0xB8220400, // 0064 GETNGBL R8 K2 + 0x8C201103, // 0065 GETMET R8 R8 K3 + 0x60280008, // 0066 GETGBL R10 G8 + 0x5C2C0E00, // 0067 MOVE R11 R7 + 0x7C280200, // 0068 CALL R10 1 + 0x002A340A, // 0069 ADD R10 K26 R10 + 0x582C0005, // 006A LDCONST R11 K5 + 0x7C200600, // 006B CALL R8 3 + 0xB8220400, // 006C GETNGBL R8 K2 + 0x8C201103, // 006D GETMET R8 R8 K3 + 0x60280008, // 006E GETGBL R10 G8 + 0x8C2C0F1C, // 006F GETMET R11 R7 K28 + 0x7C2C0200, // 0070 CALL R11 1 + 0x7C280200, // 0071 CALL R10 1 + 0x002A360A, // 0072 ADD R10 K27 R10 + 0x582C0005, // 0073 LDCONST R11 K5 + 0x7C200600, // 0074 CALL R8 3 + 0x8C20011D, // 0075 GETMET R8 R0 K29 + 0x5C280200, // 0076 MOVE R10 R1 + 0x5C2C0E00, // 0077 MOVE R11 R7 + 0x7C200600, // 0078 CALL R8 3 + 0xA01C0000, // 0079 CLOSE R7 + 0x501C0200, // 007A LDBOOL R7 1 0 + 0xA0000000, // 007B CLOSE R0 + 0x80040E00, // 007C RET 1 R7 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: process_write_request +********************************************************************/ +be_local_closure(Matter_IM_process_write_request, /* name */ + be_nested_proto( + 9, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(WriteRequestMessage), + /* K3 */ be_nested_str_weak(from_TLV), + /* K4 */ be_nested_str_weak(tasmota), + /* K5 */ be_nested_str_weak(log), + /* K6 */ be_nested_str_weak(MTR_X3A_X20received_X20WriteRequestMessage_X3D), + /* K7 */ be_const_int(3), + }), + be_str_weak(process_write_request), + &be_const_str_solidified, + ( &(const binstruction[17]) { /* code */ + 0xA40E0000, // 0000 IMPORT R3 K0 + 0xB8120200, // 0001 GETNGBL R4 K1 + 0x8C100902, // 0002 GETMET R4 R4 K2 + 0x7C100200, // 0003 CALL R4 1 + 0x8C100903, // 0004 GETMET R4 R4 K3 + 0x5C180400, // 0005 MOVE R6 R2 + 0x7C100400, // 0006 CALL R4 2 + 0xB8160800, // 0007 GETNGBL R5 K4 + 0x8C140B05, // 0008 GETMET R5 R5 K5 + 0x601C0008, // 0009 GETGBL R7 G8 + 0x5C200800, // 000A MOVE R8 R4 + 0x7C1C0200, // 000B CALL R7 1 + 0x001E0C07, // 000C ADD R7 K6 R7 + 0x58200007, // 000D LDCONST R8 K7 + 0x7C140600, // 000E CALL R5 3 + 0x50140000, // 000F LDBOOL R5 0 0 + 0x80040A00, // 0010 RET 1 R5 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: process_invoke_request +********************************************************************/ +be_local_closure(Matter_IM_process_invoke_request, /* name */ + be_nested_proto( + 18, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[52]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(log), + /* K3 */ be_nested_str_weak(MTR_X3A_X20IM_X3Ainvoke_request_X20processing_X20start), + /* K4 */ be_const_int(3), + /* K5 */ be_nested_str_weak(matter), + /* K6 */ be_nested_str_weak(Response_container), + /* K7 */ be_nested_str_weak(InvokeRequestMessage), + /* K8 */ be_nested_str_weak(from_TLV), + /* K9 */ be_nested_str_weak(invoke_requests), + /* K10 */ be_nested_str_weak(InvokeResponseMessage), + /* K11 */ be_nested_str_weak(suppress_response), + /* K12 */ be_nested_str_weak(invoke_responses), + /* K13 */ be_nested_str_weak(endpoint), + /* K14 */ be_nested_str_weak(command_path), + /* K15 */ be_nested_str_weak(cluster), + /* K16 */ be_nested_str_weak(command), + /* K17 */ be_nested_str_weak(status), + /* K18 */ be_nested_str_weak(UNSUPPORTED_COMMAND), + /* K19 */ be_nested_str_weak(get_command_name), + /* K20 */ be_nested_str_weak(format), + /* K21 */ be_nested_str_weak(0x_X2504X_X2F0x02X), + /* K22 */ be_nested_str_weak(MTR_X3A_X20_X3EReceived_cmd_X20_X20_X25s_X20from_X20_X5B_X25s_X5D_X3A_X25i), + /* K23 */ be_nested_str_weak(remote_ip), + /* K24 */ be_nested_str_weak(remote_port), + /* K25 */ be_const_int(2), + /* K26 */ be_nested_str_weak(responder), + /* K27 */ be_nested_str_weak(device), + /* K28 */ be_nested_str_weak(invoke_request), + /* K29 */ be_nested_str_weak(command_fields), + /* K30 */ be_nested_str_weak(InvokeResponseIB), + /* K31 */ be_nested_str_weak(CommandDataIB), + /* K32 */ be_nested_str_weak(CommandPathIB), + /* K33 */ be_nested_str_weak(push), + /* K34 */ be_nested_str_weak(0x_X2504X_X2F0x_X2502X), + /* K35 */ be_nested_str_weak(MTR_X3A_X20_X3CReplied_cmd_X20_X20_X20_X25s), + /* K36 */ be_nested_str_weak(CommandStatusIB), + /* K37 */ be_nested_str_weak(StatusIB), + /* K38 */ be_nested_str_weak(stop_iteration), + /* K39 */ be_nested_str_weak(MTR_X3A_X20invoke_responses_X3D), + /* K40 */ be_const_int(0), + /* K41 */ be_nested_str_weak(MTR_X3A_X20InvokeResponse_X3D), + /* K42 */ be_nested_str_weak(MTR_X3A_X20InvokeResponseTLV_X3D), + /* K43 */ be_nested_str_weak(to_TLV), + /* K44 */ be_nested_str_weak(build_response), + /* K45 */ be_nested_str_weak(encode), + /* K46 */ be_nested_str_weak(encrypt), + /* K47 */ be_nested_str_weak(send_response), + /* K48 */ be_nested_str_weak(raw), + /* K49 */ be_nested_str_weak(message_counter), + /* K50 */ be_nested_str_weak(x_flag_r), + /* K51 */ be_nested_str_weak(build_standalone_ack), + }), + be_str_weak(process_invoke_request), + &be_const_str_solidified, + ( &(const binstruction[242]) { /* code */ + 0xA40E0000, // 0000 IMPORT R3 K0 + 0xB8120200, // 0001 GETNGBL R4 K1 + 0x8C100902, // 0002 GETMET R4 R4 K2 + 0x58180003, // 0003 LDCONST R6 K3 + 0x581C0004, // 0004 LDCONST R7 K4 + 0x7C100600, // 0005 CALL R4 3 + 0xB8120A00, // 0006 GETNGBL R4 K5 + 0x8C100906, // 0007 GETMET R4 R4 K6 + 0x7C100200, // 0008 CALL R4 1 + 0xB8160A00, // 0009 GETNGBL R5 K5 + 0x8C140B07, // 000A GETMET R5 R5 K7 + 0x7C140200, // 000B CALL R5 1 + 0x8C140B08, // 000C GETMET R5 R5 K8 + 0x5C1C0400, // 000D MOVE R7 R2 + 0x7C140400, // 000E CALL R5 2 + 0x88180B09, // 000F GETMBR R6 R5 K9 + 0x4C1C0000, // 0010 LDNIL R7 + 0x20180C07, // 0011 NE R6 R6 R7 + 0x781A00DD, // 0012 JMPF R6 #00F1 + 0xB81A0A00, // 0013 GETNGBL R6 K5 + 0x8C180D0A, // 0014 GETMET R6 R6 K10 + 0x7C180200, // 0015 CALL R6 1 + 0x501C0000, // 0016 LDBOOL R7 0 0 + 0x901A1607, // 0017 SETMBR R6 K11 R7 + 0x601C0012, // 0018 GETGBL R7 G18 + 0x7C1C0000, // 0019 CALL R7 0 + 0x901A1807, // 001A SETMBR R6 K12 R7 + 0x601C0010, // 001B GETGBL R7 G16 + 0x88200B09, // 001C GETMBR R8 R5 K9 + 0x7C1C0200, // 001D CALL R7 1 + 0xA802008D, // 001E EXBLK 0 #00AD + 0x5C200E00, // 001F MOVE R8 R7 + 0x7C200000, // 0020 CALL R8 0 + 0x8824110E, // 0021 GETMBR R9 R8 K14 + 0x8824130D, // 0022 GETMBR R9 R9 K13 + 0x90121A09, // 0023 SETMBR R4 K13 R9 + 0x8824110E, // 0024 GETMBR R9 R8 K14 + 0x8824130F, // 0025 GETMBR R9 R9 K15 + 0x90121E09, // 0026 SETMBR R4 K15 R9 + 0x8824110E, // 0027 GETMBR R9 R8 K14 + 0x88241310, // 0028 GETMBR R9 R9 K16 + 0x90122009, // 0029 SETMBR R4 K16 R9 + 0xB8260A00, // 002A GETNGBL R9 K5 + 0x88241312, // 002B GETMBR R9 R9 K18 + 0x90122209, // 002C SETMBR R4 K17 R9 + 0xB8260A00, // 002D GETNGBL R9 K5 + 0x8C241313, // 002E GETMET R9 R9 K19 + 0x882C090F, // 002F GETMBR R11 R4 K15 + 0x88300910, // 0030 GETMBR R12 R4 K16 + 0x7C240600, // 0031 CALL R9 3 + 0x4C280000, // 0032 LDNIL R10 + 0x1C28120A, // 0033 EQ R10 R9 R10 + 0x782A0005, // 0034 JMPF R10 #003B + 0x8C280714, // 0035 GETMET R10 R3 K20 + 0x58300015, // 0036 LDCONST R12 K21 + 0x8834090F, // 0037 GETMBR R13 R4 K15 + 0x88380910, // 0038 GETMBR R14 R4 K16 + 0x7C280800, // 0039 CALL R10 4 + 0x5C241400, // 003A MOVE R9 R10 + 0xB82A0200, // 003B GETNGBL R10 K1 + 0x8C281502, // 003C GETMET R10 R10 K2 + 0x8C300714, // 003D GETMET R12 R3 K20 + 0x58380016, // 003E LDCONST R14 K22 + 0x5C3C1200, // 003F MOVE R15 R9 + 0x88400317, // 0040 GETMBR R16 R1 K23 + 0x88440318, // 0041 GETMBR R17 R1 K24 + 0x7C300A00, // 0042 CALL R12 5 + 0x58340019, // 0043 LDCONST R13 K25 + 0x7C280600, // 0044 CALL R10 3 + 0x8828011A, // 0045 GETMBR R10 R0 K26 + 0x8828151B, // 0046 GETMBR R10 R10 K27 + 0x8C28151C, // 0047 GETMET R10 R10 K28 + 0x5C300200, // 0048 MOVE R12 R1 + 0x8834111D, // 0049 GETMBR R13 R8 K29 + 0x5C380800, // 004A MOVE R14 R4 + 0x7C280800, // 004B CALL R10 4 + 0xB82E0A00, // 004C GETNGBL R11 K5 + 0x8C2C171E, // 004D GETMET R11 R11 K30 + 0x7C2C0200, // 004E CALL R11 1 + 0x4C300000, // 004F LDNIL R12 + 0x2030140C, // 0050 NE R12 R10 R12 + 0x78320032, // 0051 JMPF R12 #0085 + 0xB8320A00, // 0052 GETNGBL R12 K5 + 0x8C30191F, // 0053 GETMET R12 R12 K31 + 0x7C300200, // 0054 CALL R12 1 + 0x902E200C, // 0055 SETMBR R11 K16 R12 + 0x88301710, // 0056 GETMBR R12 R11 K16 + 0xB8360A00, // 0057 GETNGBL R13 K5 + 0x8C341B20, // 0058 GETMET R13 R13 K32 + 0x7C340200, // 0059 CALL R13 1 + 0x90321C0D, // 005A SETMBR R12 K14 R13 + 0x88301710, // 005B GETMBR R12 R11 K16 + 0x8830190E, // 005C GETMBR R12 R12 K14 + 0x8834090D, // 005D GETMBR R13 R4 K13 + 0x90321A0D, // 005E SETMBR R12 K13 R13 + 0x88301710, // 005F GETMBR R12 R11 K16 + 0x8830190E, // 0060 GETMBR R12 R12 K14 + 0x8834090F, // 0061 GETMBR R13 R4 K15 + 0x90321E0D, // 0062 SETMBR R12 K15 R13 + 0x88301710, // 0063 GETMBR R12 R11 K16 + 0x8830190E, // 0064 GETMBR R12 R12 K14 + 0x88340910, // 0065 GETMBR R13 R4 K16 + 0x9032200D, // 0066 SETMBR R12 K16 R13 + 0x88301710, // 0067 GETMBR R12 R11 K16 + 0x90323A0A, // 0068 SETMBR R12 K29 R10 + 0x88300D0C, // 0069 GETMBR R12 R6 K12 + 0x8C301921, // 006A GETMET R12 R12 K33 + 0x5C381600, // 006B MOVE R14 R11 + 0x7C300400, // 006C CALL R12 2 + 0xB8320A00, // 006D GETNGBL R12 K5 + 0x8C301913, // 006E GETMET R12 R12 K19 + 0x8838090F, // 006F GETMBR R14 R4 K15 + 0x883C0910, // 0070 GETMBR R15 R4 K16 + 0x7C300600, // 0071 CALL R12 3 + 0x5C241800, // 0072 MOVE R9 R12 + 0x4C300000, // 0073 LDNIL R12 + 0x1C30120C, // 0074 EQ R12 R9 R12 + 0x78320005, // 0075 JMPF R12 #007C + 0x8C300714, // 0076 GETMET R12 R3 K20 + 0x58380022, // 0077 LDCONST R14 K34 + 0x883C090F, // 0078 GETMBR R15 R4 K15 + 0x88400910, // 0079 GETMBR R16 R4 K16 + 0x7C300800, // 007A CALL R12 4 + 0x5C241800, // 007B MOVE R9 R12 + 0xB8320200, // 007C GETNGBL R12 K1 + 0x8C301902, // 007D GETMET R12 R12 K2 + 0x8C380714, // 007E GETMET R14 R3 K20 + 0x58400023, // 007F LDCONST R16 K35 + 0x5C441200, // 0080 MOVE R17 R9 + 0x7C380600, // 0081 CALL R14 3 + 0x583C0019, // 0082 LDCONST R15 K25 + 0x7C300600, // 0083 CALL R12 3 + 0x70020026, // 0084 JMP #00AC + 0x88300911, // 0085 GETMBR R12 R4 K17 + 0x4C340000, // 0086 LDNIL R13 + 0x2030180D, // 0087 NE R12 R12 R13 + 0x78320022, // 0088 JMPF R12 #00AC + 0xB8320A00, // 0089 GETNGBL R12 K5 + 0x8C301924, // 008A GETMET R12 R12 K36 + 0x7C300200, // 008B CALL R12 1 + 0x902E220C, // 008C SETMBR R11 K17 R12 + 0x88301711, // 008D GETMBR R12 R11 K17 + 0xB8360A00, // 008E GETNGBL R13 K5 + 0x8C341B20, // 008F GETMET R13 R13 K32 + 0x7C340200, // 0090 CALL R13 1 + 0x90321C0D, // 0091 SETMBR R12 K14 R13 + 0x88301711, // 0092 GETMBR R12 R11 K17 + 0x8830190E, // 0093 GETMBR R12 R12 K14 + 0x8834090D, // 0094 GETMBR R13 R4 K13 + 0x90321A0D, // 0095 SETMBR R12 K13 R13 + 0x88301711, // 0096 GETMBR R12 R11 K17 + 0x8830190E, // 0097 GETMBR R12 R12 K14 + 0x8834090F, // 0098 GETMBR R13 R4 K15 + 0x90321E0D, // 0099 SETMBR R12 K15 R13 + 0x88301711, // 009A GETMBR R12 R11 K17 + 0x8830190E, // 009B GETMBR R12 R12 K14 + 0x88340910, // 009C GETMBR R13 R4 K16 + 0x9032200D, // 009D SETMBR R12 K16 R13 + 0x88301711, // 009E GETMBR R12 R11 K17 + 0xB8360A00, // 009F GETNGBL R13 K5 + 0x8C341B25, // 00A0 GETMET R13 R13 K37 + 0x7C340200, // 00A1 CALL R13 1 + 0x9032220D, // 00A2 SETMBR R12 K17 R13 + 0x88301711, // 00A3 GETMBR R12 R11 K17 + 0x88301911, // 00A4 GETMBR R12 R12 K17 + 0x88340911, // 00A5 GETMBR R13 R4 K17 + 0x9032220D, // 00A6 SETMBR R12 K17 R13 + 0x88300D0C, // 00A7 GETMBR R12 R6 K12 + 0x8C301921, // 00A8 GETMET R12 R12 K33 + 0x5C381600, // 00A9 MOVE R14 R11 + 0x7C300400, // 00AA CALL R12 2 + 0x7001FFFF, // 00AB JMP #00AC + 0x7001FF71, // 00AC JMP #001F + 0x581C0026, // 00AD LDCONST R7 K38 + 0xAC1C0200, // 00AE CATCH R7 1 0 + 0xB0080000, // 00AF RAISE 2 R0 R0 + 0xB81E0200, // 00B0 GETNGBL R7 K1 + 0x8C1C0F02, // 00B1 GETMET R7 R7 K2 + 0x60240008, // 00B2 GETGBL R9 G8 + 0x88280D0C, // 00B3 GETMBR R10 R6 K12 + 0x7C240200, // 00B4 CALL R9 1 + 0x00264E09, // 00B5 ADD R9 K39 R9 + 0x58280004, // 00B6 LDCONST R10 K4 + 0x7C1C0600, // 00B7 CALL R7 3 + 0x601C000C, // 00B8 GETGBL R7 G12 + 0x88200D0C, // 00B9 GETMBR R8 R6 K12 + 0x7C1C0200, // 00BA CALL R7 1 + 0x241C0F28, // 00BB GT R7 R7 K40 + 0x781E0024, // 00BC JMPF R7 #00E2 + 0xB81E0200, // 00BD GETNGBL R7 K1 + 0x8C1C0F02, // 00BE GETMET R7 R7 K2 + 0x60240008, // 00BF GETGBL R9 G8 + 0x5C280C00, // 00C0 MOVE R10 R6 + 0x7C240200, // 00C1 CALL R9 1 + 0x00265209, // 00C2 ADD R9 K41 R9 + 0x58280004, // 00C3 LDCONST R10 K4 + 0x7C1C0600, // 00C4 CALL R7 3 + 0xB81E0200, // 00C5 GETNGBL R7 K1 + 0x8C1C0F02, // 00C6 GETMET R7 R7 K2 + 0x60240008, // 00C7 GETGBL R9 G8 + 0x8C280D2B, // 00C8 GETMET R10 R6 K43 + 0x7C280200, // 00C9 CALL R10 1 + 0x7C240200, // 00CA CALL R9 1 + 0x00265409, // 00CB ADD R9 K42 R9 + 0x58280004, // 00CC LDCONST R10 K4 + 0x7C1C0600, // 00CD CALL R7 3 + 0x8C1C032C, // 00CE GETMET R7 R1 K44 + 0x54260008, // 00CF LDINT R9 9 + 0x50280200, // 00D0 LDBOOL R10 1 0 + 0x7C1C0600, // 00D1 CALL R7 3 + 0x8C200F2D, // 00D2 GETMET R8 R7 K45 + 0x8C280D2B, // 00D3 GETMET R10 R6 K43 + 0x7C280200, // 00D4 CALL R10 1 + 0x8C28152D, // 00D5 GETMET R10 R10 K45 + 0x7C280200, // 00D6 CALL R10 1 + 0x7C200400, // 00D7 CALL R8 2 + 0x8C200F2E, // 00D8 GETMET R8 R7 K46 + 0x7C200200, // 00D9 CALL R8 1 + 0x8820011A, // 00DA GETMBR R8 R0 K26 + 0x8C20112F, // 00DB GETMET R8 R8 K47 + 0x88280F30, // 00DC GETMBR R10 R7 K48 + 0x882C0317, // 00DD GETMBR R11 R1 K23 + 0x88300318, // 00DE GETMBR R12 R1 K24 + 0x88340F31, // 00DF GETMBR R13 R7 K49 + 0x7C200A00, // 00E0 CALL R8 5 + 0x7002000E, // 00E1 JMP #00F1 + 0x881C0332, // 00E2 GETMBR R7 R1 K50 + 0x781E000C, // 00E3 JMPF R7 #00F1 + 0x8C1C0333, // 00E4 GETMET R7 R1 K51 + 0x7C1C0200, // 00E5 CALL R7 1 + 0x8C200F2D, // 00E6 GETMET R8 R7 K45 + 0x7C200200, // 00E7 CALL R8 1 + 0x8C200F2E, // 00E8 GETMET R8 R7 K46 + 0x7C200200, // 00E9 CALL R8 1 + 0x8820011A, // 00EA GETMBR R8 R0 K26 + 0x8C20112F, // 00EB GETMET R8 R8 K47 + 0x88280F30, // 00EC GETMBR R10 R7 K48 + 0x882C0317, // 00ED GETMBR R11 R1 K23 + 0x88300318, // 00EE GETMBR R12 R1 K24 + 0x88340F31, // 00EF GETMBR R13 R7 K49 + 0x7C200A00, // 00F0 CALL R8 5 + 0x80000000, // 00F1 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_IM_init, /* name */ + be_nested_proto( + 3, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(responder), + /* K1 */ be_nested_str_weak(device), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[ 3]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x90020202, // 0001 SETMBR R0 K1 R2 + 0x80000000, // 0002 RET 0 + }) + ) +); +/*******************************************************************/ + + +extern const bclass be_class_Matter_Attr_Report; + +/******************************************************************** +** Solidified class: Matter_Attr_Report +********************************************************************/ +be_local_class(Matter_Attr_Report, + 3, + NULL, + be_nested_map(3, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(ret, 1), be_const_var(0) }, + { be_const_key_weak(expiration, 2), be_const_var(2) }, + { be_const_key_weak(resp, -1), be_const_var(1) }, + })), + be_str_weak(Matter_Attr_Report) +); + +/******************************************************************** +** Solidified function: send_attr_report +********************************************************************/ +be_local_closure(Matter_IM_send_attr_report, /* name */ + be_nested_proto( + 14, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[23]) { /* constants */ + /* K0 */ be_const_class(be_class_Matter_Attr_Report), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str_weak(attribute_reports), + /* K3 */ be_nested_str_weak(to_TLV), + /* K4 */ be_nested_str_weak(encode), + /* K5 */ be_const_int(1), + /* K6 */ be_nested_str_weak(MAX_MESSAGE), + /* K7 */ be_const_int(2147483647), + /* K8 */ be_nested_str_weak(more_chunked_messages), + /* K9 */ be_nested_str_weak(build_response), + /* K10 */ be_nested_str_weak(encrypt), + /* K11 */ be_nested_str_weak(responder), + /* K12 */ be_nested_str_weak(send_response), + /* K13 */ be_nested_str_weak(raw), + /* K14 */ be_nested_str_weak(remote_ip), + /* K15 */ be_nested_str_weak(remote_port), + /* K16 */ be_nested_str_weak(message_counter), + /* K17 */ be_nested_str_weak(ret), + /* K18 */ be_nested_str_weak(resp), + /* K19 */ be_nested_str_weak(expiration), + /* K20 */ be_nested_str_weak(tasmota), + /* K21 */ be_nested_str_weak(millis), + /* K22 */ be_nested_str_weak(MSG_TIMEOUT), + }), + be_str_weak(send_attr_report), + &be_const_str_solidified, + ( &(const binstruction[93]) { /* code */ + 0x580C0000, // 0000 LDCONST R3 K0 + 0xB4000000, // 0001 CLASS K0 + 0x58100001, // 0002 LDCONST R4 K1 + 0x58140001, // 0003 LDCONST R5 K1 + 0x6018000C, // 0004 GETGBL R6 G12 + 0x881C0502, // 0005 GETMBR R7 R2 K2 + 0x7C180200, // 0006 CALL R6 1 + 0x24180D01, // 0007 GT R6 R6 K1 + 0x781A0009, // 0008 JMPF R6 #0013 + 0x6018000C, // 0009 GETGBL R6 G12 + 0x881C0502, // 000A GETMBR R7 R2 K2 + 0x941C0F01, // 000B GETIDX R7 R7 K1 + 0x8C1C0F03, // 000C GETMET R7 R7 K3 + 0x7C1C0200, // 000D CALL R7 1 + 0x8C1C0F04, // 000E GETMET R7 R7 K4 + 0x7C1C0200, // 000F CALL R7 1 + 0x7C180200, // 0010 CALL R6 1 + 0x5C100C00, // 0011 MOVE R4 R6 + 0x58140005, // 0012 LDCONST R5 K5 + 0x88180106, // 0013 GETMBR R6 R0 K6 + 0x14180806, // 0014 LT R6 R4 R6 + 0x781A0013, // 0015 JMPF R6 #002A + 0x6018000C, // 0016 GETGBL R6 G12 + 0x881C0502, // 0017 GETMBR R7 R2 K2 + 0x7C180200, // 0018 CALL R6 1 + 0x14180A06, // 0019 LT R6 R5 R6 + 0x781A000E, // 001A JMPF R6 #002A + 0x6018000C, // 001B GETGBL R6 G12 + 0x881C0502, // 001C GETMBR R7 R2 K2 + 0x941C0E05, // 001D GETIDX R7 R7 R5 + 0x8C1C0F03, // 001E GETMET R7 R7 K3 + 0x7C1C0200, // 001F CALL R7 1 + 0x8C1C0F04, // 0020 GETMET R7 R7 K4 + 0x7C1C0200, // 0021 CALL R7 1 + 0x7C180200, // 0022 CALL R6 1 + 0x001C0806, // 0023 ADD R7 R4 R6 + 0x88200106, // 0024 GETMBR R8 R0 K6 + 0x141C0E08, // 0025 LT R7 R7 R8 + 0x781E0001, // 0026 JMPF R7 #0029 + 0x00100806, // 0027 ADD R4 R4 R6 + 0x00140B05, // 0028 ADD R5 R5 K5 + 0x7001FFE8, // 0029 JMP #0013 + 0x40180B07, // 002A CONNECT R6 R5 K7 + 0x881C0502, // 002B GETMBR R7 R2 K2 + 0x94180E06, // 002C GETIDX R6 R7 R6 + 0x04200B05, // 002D SUB R8 R5 K5 + 0x40220208, // 002E CONNECT R8 K1 R8 + 0x88240502, // 002F GETMBR R9 R2 K2 + 0x94201208, // 0030 GETIDX R8 R9 R8 + 0x900A0408, // 0031 SETMBR R2 K2 R8 + 0x6020000C, // 0032 GETGBL R8 G12 + 0x5C240C00, // 0033 MOVE R9 R6 + 0x7C200200, // 0034 CALL R8 1 + 0x24201101, // 0035 GT R8 R8 K1 + 0x78220001, // 0036 JMPF R8 #0039 + 0x50200200, // 0037 LDBOOL R8 1 0 + 0x900A1008, // 0038 SETMBR R2 K8 R8 + 0x8C1C0309, // 0039 GETMET R7 R1 K9 + 0x54260004, // 003A LDINT R9 5 + 0x50280200, // 003B LDBOOL R10 1 0 + 0x7C1C0600, // 003C CALL R7 3 + 0x8C200F04, // 003D GETMET R8 R7 K4 + 0x8C280503, // 003E GETMET R10 R2 K3 + 0x7C280200, // 003F CALL R10 1 + 0x8C281504, // 0040 GETMET R10 R10 K4 + 0x7C280200, // 0041 CALL R10 1 + 0x7C200400, // 0042 CALL R8 2 + 0x8C200F0A, // 0043 GETMET R8 R7 K10 + 0x7C200200, // 0044 CALL R8 1 + 0x8820010B, // 0045 GETMBR R8 R0 K11 + 0x8C20110C, // 0046 GETMET R8 R8 K12 + 0x88280F0D, // 0047 GETMBR R10 R7 K13 + 0x882C030E, // 0048 GETMBR R11 R1 K14 + 0x8830030F, // 0049 GETMBR R12 R1 K15 + 0x88340F10, // 004A GETMBR R13 R7 K16 + 0x7C200A00, // 004B CALL R8 5 + 0x6020000C, // 004C GETGBL R8 G12 + 0x5C240C00, // 004D MOVE R9 R6 + 0x7C200200, // 004E CALL R8 1 + 0x24201101, // 004F GT R8 R8 K1 + 0x7822000A, // 0050 JMPF R8 #005C + 0x900A0406, // 0051 SETMBR R2 K2 R6 + 0x5C200600, // 0052 MOVE R8 R3 + 0x7C200000, // 0053 CALL R8 0 + 0x90222202, // 0054 SETMBR R8 K17 R2 + 0x90222407, // 0055 SETMBR R8 K18 R7 + 0xB8262800, // 0056 GETNGBL R9 K20 + 0x8C241315, // 0057 GETMET R9 R9 K21 + 0x7C240200, // 0058 CALL R9 1 + 0x88280116, // 0059 GETMBR R10 R0 K22 + 0x0024120A, // 005A ADD R9 R9 R10 + 0x90222609, // 005B SETMBR R8 K19 R9 + 0x80000000, // 005C RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: subscribe_response +********************************************************************/ +be_local_closure(Matter_IM_subscribe_response, /* name */ + be_nested_proto( + 9, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(SubscribeResponseMessage), + /* K3 */ be_nested_str_weak(from_TLV), + /* K4 */ be_nested_str_weak(tasmota), + /* K5 */ be_nested_str_weak(log), + /* K6 */ be_nested_str_weak(MTR_X3A_X20received_X20SubscribeResponsetMessage_X3D), + /* K7 */ be_const_int(3), + }), + be_str_weak(subscribe_response), + &be_const_str_solidified, + ( &(const binstruction[17]) { /* code */ + 0xA40E0000, // 0000 IMPORT R3 K0 + 0xB8120200, // 0001 GETNGBL R4 K1 + 0x8C100902, // 0002 GETMET R4 R4 K2 + 0x7C100200, // 0003 CALL R4 1 + 0x8C100903, // 0004 GETMET R4 R4 K3 + 0x5C180400, // 0005 MOVE R6 R2 + 0x7C100400, // 0006 CALL R4 2 + 0xB8160800, // 0007 GETNGBL R5 K4 + 0x8C140B05, // 0008 GETMET R5 R5 K5 + 0x601C0008, // 0009 GETGBL R7 G8 + 0x5C200800, // 000A MOVE R8 R4 + 0x7C1C0200, // 000B CALL R7 1 + 0x001E0C07, // 000C ADD R7 K6 R7 + 0x58200007, // 000D LDCONST R8 K7 + 0x7C140600, // 000E CALL R5 3 + 0x50140000, // 000F LDBOOL R5 0 0 + 0x80040A00, // 0010 RET 1 R5 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: subscribe_request +********************************************************************/ +be_local_closure(Matter_IM_subscribe_request, /* name */ + be_nested_proto( + 9, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(SubscribeRequestMessage), + /* K3 */ be_nested_str_weak(from_TLV), + /* K4 */ be_nested_str_weak(tasmota), + /* K5 */ be_nested_str_weak(log), + /* K6 */ be_nested_str_weak(MTR_X3A_X20received_X20SubscribeRequestMessage_X3D), + /* K7 */ be_const_int(3), + }), + be_str_weak(subscribe_request), + &be_const_str_solidified, + ( &(const binstruction[17]) { /* code */ + 0xA40E0000, // 0000 IMPORT R3 K0 + 0xB8120200, // 0001 GETNGBL R4 K1 + 0x8C100902, // 0002 GETMET R4 R4 K2 + 0x7C100200, // 0003 CALL R4 1 + 0x8C100903, // 0004 GETMET R4 R4 K3 + 0x5C180400, // 0005 MOVE R6 R2 + 0x7C100400, // 0006 CALL R4 2 + 0xB8160800, // 0007 GETNGBL R5 K4 + 0x8C140B05, // 0008 GETMET R5 R5 K5 + 0x601C0008, // 0009 GETGBL R7 G8 + 0x5C200800, // 000A MOVE R8 R4 + 0x7C1C0200, // 000B CALL R7 1 + 0x001E0C07, // 000C ADD R7 K6 R7 + 0x58200007, // 000D LDCONST R8 K7 + 0x7C140600, // 000E CALL R5 3 + 0x50140000, // 000F LDBOOL R5 0 0 + 0x80040A00, // 0010 RET 1 R5 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: process_write_response ********************************************************************/ be_local_closure(Matter_IM_process_write_response, /* name */ be_nested_proto( - 11, /* nstack */ - 5, /* argc */ + 9, /* nstack */ + 3, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ @@ -256,23 +1490,23 @@ be_local_closure(Matter_IM_process_write_response, /* name */ be_str_weak(process_write_response), &be_const_str_solidified, ( &(const binstruction[17]) { /* code */ - 0xA4160000, // 0000 IMPORT R5 K0 - 0xB81A0200, // 0001 GETNGBL R6 K1 - 0x8C180D02, // 0002 GETMET R6 R6 K2 - 0x7C180200, // 0003 CALL R6 1 - 0x8C180D03, // 0004 GETMET R6 R6 K3 - 0x5C200400, // 0005 MOVE R8 R2 - 0x7C180400, // 0006 CALL R6 2 - 0xB81E0800, // 0007 GETNGBL R7 K4 - 0x8C1C0F05, // 0008 GETMET R7 R7 K5 - 0x60240008, // 0009 GETGBL R9 G8 - 0x5C280C00, // 000A MOVE R10 R6 - 0x7C240200, // 000B CALL R9 1 - 0x00260C09, // 000C ADD R9 K6 R9 - 0x58280007, // 000D LDCONST R10 K7 - 0x7C1C0600, // 000E CALL R7 3 - 0x501C0000, // 000F LDBOOL R7 0 0 - 0x80040E00, // 0010 RET 1 R7 + 0xA40E0000, // 0000 IMPORT R3 K0 + 0xB8120200, // 0001 GETNGBL R4 K1 + 0x8C100902, // 0002 GETMET R4 R4 K2 + 0x7C100200, // 0003 CALL R4 1 + 0x8C100903, // 0004 GETMET R4 R4 K3 + 0x5C180400, // 0005 MOVE R6 R2 + 0x7C100400, // 0006 CALL R4 2 + 0xB8160800, // 0007 GETNGBL R5 K4 + 0x8C140B05, // 0008 GETMET R5 R5 K5 + 0x601C0008, // 0009 GETGBL R7 G8 + 0x5C200800, // 000A MOVE R8 R4 + 0x7C1C0200, // 000B CALL R7 1 + 0x001E0C07, // 000C ADD R7 K6 R7 + 0x58200007, // 000D LDCONST R8 K7 + 0x7C140600, // 000E CALL R5 3 + 0x50140000, // 000F LDBOOL R5 0 0 + 0x80040A00, // 0010 RET 1 R5 }) ) ); @@ -284,8 +1518,8 @@ be_local_closure(Matter_IM_process_write_response, /* name */ ********************************************************************/ be_local_closure(Matter_IM_process_incoming, /* name */ be_nested_proto( - 13, /* nstack */ - 4, /* argc */ + 9, /* nstack */ + 2, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ @@ -323,915 +1557,135 @@ be_local_closure(Matter_IM_process_incoming, /* name */ }), be_str_weak(process_incoming), &be_const_str_solidified, - ( &(const binstruction[148]) { /* code */ - 0xB8120000, // 0000 GETNGBL R4 K0 - 0x8C100901, // 0001 GETMET R4 R4 K1 - 0xB81A0600, // 0002 GETNGBL R6 K3 - 0x8C180D04, // 0003 GETMET R6 R6 K4 - 0x5C200200, // 0004 MOVE R8 R1 - 0x7C180400, // 0005 CALL R6 2 - 0x001A0406, // 0006 ADD R6 K2 R6 - 0x581C0005, // 0007 LDCONST R7 K5 - 0x7C100600, // 0008 CALL R4 3 - 0xB8120600, // 0009 GETNGBL R4 K3 - 0x88100906, // 000A GETMBR R4 R4 K6 - 0x8C100907, // 000B GETMET R4 R4 K7 - 0x88180308, // 000C GETMBR R6 R1 K8 - 0x881C0309, // 000D GETMBR R7 R1 K9 - 0x7C100600, // 000E CALL R4 3 - 0xB8160000, // 000F GETNGBL R5 K0 - 0x8C140B01, // 0010 GETMET R5 R5 K1 - 0x601C0008, // 0011 GETGBL R7 G8 - 0x5C200800, // 0012 MOVE R8 R4 - 0x7C1C0200, // 0013 CALL R7 1 - 0x001E1407, // 0014 ADD R7 K10 R7 - 0x58200005, // 0015 LDCONST R8 K5 - 0x7C140600, // 0016 CALL R5 3 - 0x8C14090B, // 0017 GETMET R5 R4 K11 - 0x541E00FE, // 0018 LDINT R7 255 - 0x7C140400, // 0019 CALL R5 2 - 0xB81A0000, // 001A GETNGBL R6 K0 - 0x8C180D01, // 001B GETMET R6 R6 K1 - 0x4C200000, // 001C LDNIL R8 - 0x20200A08, // 001D NE R8 R5 R8 - 0x78220003, // 001E JMPF R8 #0023 - 0x60200008, // 001F GETGBL R8 G8 - 0x5C240A00, // 0020 MOVE R9 R5 - 0x7C200200, // 0021 CALL R8 1 + ( &(const binstruction[128]) { /* code */ + 0xB80A0000, // 0000 GETNGBL R2 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0xB8120600, // 0002 GETNGBL R4 K3 + 0x8C100904, // 0003 GETMET R4 R4 K4 + 0x5C180200, // 0004 MOVE R6 R1 + 0x7C100400, // 0005 CALL R4 2 + 0x00120404, // 0006 ADD R4 K2 R4 + 0x58140005, // 0007 LDCONST R5 K5 + 0x7C080600, // 0008 CALL R2 3 + 0xB80A0600, // 0009 GETNGBL R2 K3 + 0x88080506, // 000A GETMBR R2 R2 K6 + 0x8C080507, // 000B GETMET R2 R2 K7 + 0x88100308, // 000C GETMBR R4 R1 K8 + 0x88140309, // 000D GETMBR R5 R1 K9 + 0x7C080600, // 000E CALL R2 3 + 0xB80E0000, // 000F GETNGBL R3 K0 + 0x8C0C0701, // 0010 GETMET R3 R3 K1 + 0x60140008, // 0011 GETGBL R5 G8 + 0x5C180400, // 0012 MOVE R6 R2 + 0x7C140200, // 0013 CALL R5 1 + 0x00161405, // 0014 ADD R5 K10 R5 + 0x58180005, // 0015 LDCONST R6 K5 + 0x7C0C0600, // 0016 CALL R3 3 + 0x8C0C050B, // 0017 GETMET R3 R2 K11 + 0x541600FE, // 0018 LDINT R5 255 + 0x7C0C0400, // 0019 CALL R3 2 + 0xB8120000, // 001A GETNGBL R4 K0 + 0x8C100901, // 001B GETMET R4 R4 K1 + 0x4C180000, // 001C LDNIL R6 + 0x20180606, // 001D NE R6 R3 R6 + 0x781A0003, // 001E JMPF R6 #0023 + 0x60180008, // 001F GETGBL R6 G8 + 0x5C1C0600, // 0020 MOVE R7 R3 + 0x7C180200, // 0021 CALL R6 1 0x70020000, // 0022 JMP #0024 - 0x5820000D, // 0023 LDCONST R8 K13 - 0x00221808, // 0024 ADD R8 K12 R8 - 0x58240005, // 0025 LDCONST R9 K5 - 0x7C180600, // 0026 CALL R6 3 - 0x8818030E, // 0027 GETMBR R6 R1 K14 - 0x1C1C0D0F, // 0028 EQ R7 R6 K15 - 0x781E0007, // 0029 JMPF R7 #0032 - 0x8C1C0110, // 002A GETMET R7 R0 K16 - 0x5C240200, // 002B MOVE R9 R1 - 0x5C280800, // 002C MOVE R10 R4 - 0x5C2C0400, // 002D MOVE R11 R2 - 0x5C300600, // 002E MOVE R12 R3 - 0x7C1C0A00, // 002F CALL R7 5 - 0x80040E00, // 0030 RET 1 R7 - 0x7002005F, // 0031 JMP #0092 - 0x1C1C0D11, // 0032 EQ R7 R6 K17 - 0x781E0007, // 0033 JMPF R7 #003C - 0x8C1C0112, // 0034 GETMET R7 R0 K18 - 0x5C240200, // 0035 MOVE R9 R1 - 0x5C280800, // 0036 MOVE R10 R4 - 0x5C2C0400, // 0037 MOVE R11 R2 - 0x5C300600, // 0038 MOVE R12 R3 - 0x7C1C0A00, // 0039 CALL R7 5 - 0x80040E00, // 003A RET 1 R7 - 0x70020055, // 003B JMP #0092 - 0x1C1C0D05, // 003C EQ R7 R6 K5 - 0x781E0007, // 003D JMPF R7 #0046 - 0x8C1C0113, // 003E GETMET R7 R0 K19 - 0x5C240200, // 003F MOVE R9 R1 - 0x5C280800, // 0040 MOVE R10 R4 - 0x5C2C0400, // 0041 MOVE R11 R2 - 0x5C300600, // 0042 MOVE R12 R3 - 0x7C1C0A00, // 0043 CALL R7 5 - 0x80040E00, // 0044 RET 1 R7 - 0x7002004B, // 0045 JMP #0092 - 0x541E0003, // 0046 LDINT R7 4 - 0x1C1C0C07, // 0047 EQ R7 R6 R7 - 0x781E0007, // 0048 JMPF R7 #0051 - 0x8C1C0114, // 0049 GETMET R7 R0 K20 - 0x5C240200, // 004A MOVE R9 R1 - 0x5C280800, // 004B MOVE R10 R4 - 0x5C2C0400, // 004C MOVE R11 R2 - 0x5C300600, // 004D MOVE R12 R3 - 0x7C1C0A00, // 004E CALL R7 5 - 0x80040E00, // 004F RET 1 R7 - 0x70020040, // 0050 JMP #0092 - 0x541E0004, // 0051 LDINT R7 5 - 0x1C1C0C07, // 0052 EQ R7 R6 R7 - 0x781E0007, // 0053 JMPF R7 #005C - 0x8C1C0115, // 0054 GETMET R7 R0 K21 - 0x5C240200, // 0055 MOVE R9 R1 - 0x5C280800, // 0056 MOVE R10 R4 - 0x5C2C0400, // 0057 MOVE R11 R2 - 0x5C300600, // 0058 MOVE R12 R3 - 0x7C1C0A00, // 0059 CALL R7 5 - 0x80040E00, // 005A RET 1 R7 - 0x70020035, // 005B JMP #0092 - 0x541E0005, // 005C LDINT R7 6 - 0x1C1C0C07, // 005D EQ R7 R6 R7 - 0x781E0007, // 005E JMPF R7 #0067 - 0x8C1C0116, // 005F GETMET R7 R0 K22 - 0x5C240200, // 0060 MOVE R9 R1 - 0x5C280800, // 0061 MOVE R10 R4 - 0x5C2C0400, // 0062 MOVE R11 R2 - 0x5C300600, // 0063 MOVE R12 R3 - 0x7C1C0A00, // 0064 CALL R7 5 - 0x80040E00, // 0065 RET 1 R7 - 0x7002002A, // 0066 JMP #0092 - 0x541E0006, // 0067 LDINT R7 7 - 0x1C1C0C07, // 0068 EQ R7 R6 R7 - 0x781E0007, // 0069 JMPF R7 #0072 - 0x8C1C0117, // 006A GETMET R7 R0 K23 - 0x5C240200, // 006B MOVE R9 R1 - 0x5C280800, // 006C MOVE R10 R4 - 0x5C2C0400, // 006D MOVE R11 R2 - 0x5C300600, // 006E MOVE R12 R3 - 0x7C1C0A00, // 006F CALL R7 5 - 0x80040E00, // 0070 RET 1 R7 - 0x7002001F, // 0071 JMP #0092 - 0x541E0007, // 0072 LDINT R7 8 - 0x1C1C0C07, // 0073 EQ R7 R6 R7 - 0x781E0007, // 0074 JMPF R7 #007D - 0x8C1C0118, // 0075 GETMET R7 R0 K24 - 0x5C240200, // 0076 MOVE R9 R1 - 0x5C280800, // 0077 MOVE R10 R4 - 0x5C2C0400, // 0078 MOVE R11 R2 - 0x5C300600, // 0079 MOVE R12 R3 - 0x7C1C0A00, // 007A CALL R7 5 - 0x80040E00, // 007B RET 1 R7 - 0x70020014, // 007C JMP #0092 - 0x541E0008, // 007D LDINT R7 9 - 0x1C1C0C07, // 007E EQ R7 R6 R7 - 0x781E0007, // 007F JMPF R7 #0088 - 0x8C1C0119, // 0080 GETMET R7 R0 K25 - 0x5C240200, // 0081 MOVE R9 R1 - 0x5C280800, // 0082 MOVE R10 R4 - 0x5C2C0400, // 0083 MOVE R11 R2 - 0x5C300600, // 0084 MOVE R12 R3 - 0x7C1C0A00, // 0085 CALL R7 5 - 0x80040E00, // 0086 RET 1 R7 - 0x70020009, // 0087 JMP #0092 - 0x541E0009, // 0088 LDINT R7 10 - 0x1C1C0C07, // 0089 EQ R7 R6 R7 - 0x781E0006, // 008A JMPF R7 #0092 - 0x8C1C011A, // 008B GETMET R7 R0 K26 - 0x5C240200, // 008C MOVE R9 R1 - 0x5C280800, // 008D MOVE R10 R4 - 0x5C2C0400, // 008E MOVE R11 R2 - 0x5C300600, // 008F MOVE R12 R3 - 0x7C1C0A00, // 0090 CALL R7 5 - 0x80040E00, // 0091 RET 1 R7 - 0x501C0000, // 0092 LDBOOL R7 0 0 - 0x80040E00, // 0093 RET 1 R7 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: process_write_request -********************************************************************/ -be_local_closure(Matter_IM_process_write_request, /* name */ - be_nested_proto( - 11, /* nstack */ - 5, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 8]) { /* constants */ - /* K0 */ be_nested_str_weak(string), - /* K1 */ be_nested_str_weak(matter), - /* K2 */ be_nested_str_weak(WriteRequestMessage), - /* K3 */ be_nested_str_weak(from_TLV), - /* K4 */ be_nested_str_weak(tasmota), - /* K5 */ be_nested_str_weak(log), - /* K6 */ be_nested_str_weak(MTR_X3A_X20received_X20WriteRequestMessage_X3D), - /* K7 */ be_const_int(3), - }), - be_str_weak(process_write_request), - &be_const_str_solidified, - ( &(const binstruction[17]) { /* code */ - 0xA4160000, // 0000 IMPORT R5 K0 - 0xB81A0200, // 0001 GETNGBL R6 K1 - 0x8C180D02, // 0002 GETMET R6 R6 K2 - 0x7C180200, // 0003 CALL R6 1 - 0x8C180D03, // 0004 GETMET R6 R6 K3 - 0x5C200400, // 0005 MOVE R8 R2 - 0x7C180400, // 0006 CALL R6 2 - 0xB81E0800, // 0007 GETNGBL R7 K4 - 0x8C1C0F05, // 0008 GETMET R7 R7 K5 - 0x60240008, // 0009 GETGBL R9 G8 - 0x5C280C00, // 000A MOVE R10 R6 - 0x7C240200, // 000B CALL R9 1 - 0x00260C09, // 000C ADD R9 K6 R9 - 0x58280007, // 000D LDCONST R10 K7 - 0x7C1C0600, // 000E CALL R7 3 - 0x501C0000, // 000F LDBOOL R7 0 0 - 0x80040E00, // 0010 RET 1 R7 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: process_invoke_request -********************************************************************/ -be_local_closure(Matter_IM_process_invoke_request, /* name */ - be_nested_proto( - 20, /* nstack */ - 5, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[50]) { /* constants */ - /* K0 */ be_nested_str_weak(string), - /* K1 */ be_nested_str_weak(tasmota), - /* K2 */ be_nested_str_weak(log), - /* K3 */ be_nested_str_weak(MTR_X3A_X20IM_X3Ainvoke_request_X20processing_X20start), - /* K4 */ be_const_int(3), - /* K5 */ be_nested_str_weak(matter), - /* K6 */ be_nested_str_weak(Response_container), - /* K7 */ be_nested_str_weak(InvokeRequestMessage), - /* K8 */ be_nested_str_weak(from_TLV), - /* K9 */ be_nested_str_weak(invoke_requests), - /* K10 */ be_nested_str_weak(InvokeResponseMessage), - /* K11 */ be_nested_str_weak(suppress_response), - /* K12 */ be_nested_str_weak(invoke_responses), - /* K13 */ be_nested_str_weak(endpoint), - /* K14 */ be_nested_str_weak(command_path), - /* K15 */ be_nested_str_weak(cluster), - /* K16 */ be_nested_str_weak(command), - /* K17 */ be_nested_str_weak(status), - /* K18 */ be_nested_str_weak(UNSUPPORTED_COMMAND), - /* K19 */ be_nested_str_weak(get_command_name), - /* K20 */ be_nested_str_weak(format), - /* K21 */ be_nested_str_weak(0x_X2504X_X2F0x02X), - /* K22 */ be_nested_str_weak(MTR_X3A_X20_X3EReceived_cmd_X20_X20_X25s_X20from_X20_X5B_X25s_X5D_X3A_X25i), - /* K23 */ be_const_int(2), - /* K24 */ be_nested_str_weak(responder), - /* K25 */ be_nested_str_weak(device), - /* K26 */ be_nested_str_weak(invoke_request), - /* K27 */ be_nested_str_weak(command_fields), - /* K28 */ be_nested_str_weak(InvokeResponseIB), - /* K29 */ be_nested_str_weak(CommandDataIB), - /* K30 */ be_nested_str_weak(CommandPathIB), - /* K31 */ be_nested_str_weak(push), - /* K32 */ be_nested_str_weak(0x_X2504X_X2F0x_X2502X), - /* K33 */ be_nested_str_weak(MTR_X3A_X20_X3CReplied_cmd_X20_X20_X20_X25s), - /* K34 */ be_nested_str_weak(CommandStatusIB), - /* K35 */ be_nested_str_weak(StatusIB), - /* K36 */ be_nested_str_weak(stop_iteration), - /* K37 */ be_nested_str_weak(MTR_X3A_X20invoke_responses_X3D), - /* K38 */ be_const_int(0), - /* K39 */ be_nested_str_weak(MTR_X3A_X20InvokeResponse_X3D), - /* K40 */ be_nested_str_weak(MTR_X3A_X20InvokeResponseTLV_X3D), - /* K41 */ be_nested_str_weak(to_TLV), - /* K42 */ be_nested_str_weak(build_response), - /* K43 */ be_nested_str_weak(encode), - /* K44 */ be_nested_str_weak(encrypt), - /* K45 */ be_nested_str_weak(send_response), - /* K46 */ be_nested_str_weak(raw), - /* K47 */ be_nested_str_weak(message_counter), - /* K48 */ be_nested_str_weak(x_flag_r), - /* K49 */ be_nested_str_weak(build_standalone_ack), - }), - be_str_weak(process_invoke_request), - &be_const_str_solidified, - ( &(const binstruction[242]) { /* code */ - 0xA4160000, // 0000 IMPORT R5 K0 - 0xB81A0200, // 0001 GETNGBL R6 K1 - 0x8C180D02, // 0002 GETMET R6 R6 K2 - 0x58200003, // 0003 LDCONST R8 K3 - 0x58240004, // 0004 LDCONST R9 K4 - 0x7C180600, // 0005 CALL R6 3 - 0xB81A0A00, // 0006 GETNGBL R6 K5 - 0x8C180D06, // 0007 GETMET R6 R6 K6 - 0x7C180200, // 0008 CALL R6 1 - 0xB81E0A00, // 0009 GETNGBL R7 K5 - 0x8C1C0F07, // 000A GETMET R7 R7 K7 - 0x7C1C0200, // 000B CALL R7 1 - 0x8C1C0F08, // 000C GETMET R7 R7 K8 - 0x5C240400, // 000D MOVE R9 R2 - 0x7C1C0400, // 000E CALL R7 2 - 0x88200F09, // 000F GETMBR R8 R7 K9 - 0x4C240000, // 0010 LDNIL R9 - 0x20201009, // 0011 NE R8 R8 R9 - 0x782200DD, // 0012 JMPF R8 #00F1 - 0xB8220A00, // 0013 GETNGBL R8 K5 - 0x8C20110A, // 0014 GETMET R8 R8 K10 - 0x7C200200, // 0015 CALL R8 1 - 0x50240000, // 0016 LDBOOL R9 0 0 - 0x90221609, // 0017 SETMBR R8 K11 R9 - 0x60240012, // 0018 GETGBL R9 G18 - 0x7C240000, // 0019 CALL R9 0 - 0x90221809, // 001A SETMBR R8 K12 R9 - 0x60240010, // 001B GETGBL R9 G16 - 0x88280F09, // 001C GETMBR R10 R7 K9 - 0x7C240200, // 001D CALL R9 1 - 0xA802008D, // 001E EXBLK 0 #00AD - 0x5C281200, // 001F MOVE R10 R9 - 0x7C280000, // 0020 CALL R10 0 - 0x882C150E, // 0021 GETMBR R11 R10 K14 - 0x882C170D, // 0022 GETMBR R11 R11 K13 - 0x901A1A0B, // 0023 SETMBR R6 K13 R11 - 0x882C150E, // 0024 GETMBR R11 R10 K14 - 0x882C170F, // 0025 GETMBR R11 R11 K15 - 0x901A1E0B, // 0026 SETMBR R6 K15 R11 - 0x882C150E, // 0027 GETMBR R11 R10 K14 - 0x882C1710, // 0028 GETMBR R11 R11 K16 - 0x901A200B, // 0029 SETMBR R6 K16 R11 - 0xB82E0A00, // 002A GETNGBL R11 K5 - 0x882C1712, // 002B GETMBR R11 R11 K18 - 0x901A220B, // 002C SETMBR R6 K17 R11 - 0xB82E0A00, // 002D GETNGBL R11 K5 - 0x8C2C1713, // 002E GETMET R11 R11 K19 - 0x88340D0F, // 002F GETMBR R13 R6 K15 - 0x88380D10, // 0030 GETMBR R14 R6 K16 - 0x7C2C0600, // 0031 CALL R11 3 - 0x4C300000, // 0032 LDNIL R12 - 0x1C30160C, // 0033 EQ R12 R11 R12 - 0x78320005, // 0034 JMPF R12 #003B - 0x8C300B14, // 0035 GETMET R12 R5 K20 - 0x58380015, // 0036 LDCONST R14 K21 - 0x883C0D0F, // 0037 GETMBR R15 R6 K15 - 0x88400D10, // 0038 GETMBR R16 R6 K16 - 0x7C300800, // 0039 CALL R12 4 - 0x5C2C1800, // 003A MOVE R11 R12 - 0xB8320200, // 003B GETNGBL R12 K1 - 0x8C301902, // 003C GETMET R12 R12 K2 - 0x8C380B14, // 003D GETMET R14 R5 K20 - 0x58400016, // 003E LDCONST R16 K22 - 0x5C441600, // 003F MOVE R17 R11 - 0x5C480600, // 0040 MOVE R18 R3 - 0x5C4C0800, // 0041 MOVE R19 R4 - 0x7C380A00, // 0042 CALL R14 5 - 0x583C0017, // 0043 LDCONST R15 K23 - 0x7C300600, // 0044 CALL R12 3 - 0x88300118, // 0045 GETMBR R12 R0 K24 - 0x88301919, // 0046 GETMBR R12 R12 K25 - 0x8C30191A, // 0047 GETMET R12 R12 K26 - 0x5C380200, // 0048 MOVE R14 R1 - 0x883C151B, // 0049 GETMBR R15 R10 K27 - 0x5C400C00, // 004A MOVE R16 R6 - 0x7C300800, // 004B CALL R12 4 - 0xB8360A00, // 004C GETNGBL R13 K5 - 0x8C341B1C, // 004D GETMET R13 R13 K28 - 0x7C340200, // 004E CALL R13 1 - 0x4C380000, // 004F LDNIL R14 - 0x2038180E, // 0050 NE R14 R12 R14 - 0x783A0032, // 0051 JMPF R14 #0085 - 0xB83A0A00, // 0052 GETNGBL R14 K5 - 0x8C381D1D, // 0053 GETMET R14 R14 K29 - 0x7C380200, // 0054 CALL R14 1 - 0x9036200E, // 0055 SETMBR R13 K16 R14 - 0x88381B10, // 0056 GETMBR R14 R13 K16 - 0xB83E0A00, // 0057 GETNGBL R15 K5 - 0x8C3C1F1E, // 0058 GETMET R15 R15 K30 - 0x7C3C0200, // 0059 CALL R15 1 - 0x903A1C0F, // 005A SETMBR R14 K14 R15 - 0x88381B10, // 005B GETMBR R14 R13 K16 - 0x88381D0E, // 005C GETMBR R14 R14 K14 - 0x883C0D0D, // 005D GETMBR R15 R6 K13 - 0x903A1A0F, // 005E SETMBR R14 K13 R15 - 0x88381B10, // 005F GETMBR R14 R13 K16 - 0x88381D0E, // 0060 GETMBR R14 R14 K14 - 0x883C0D0F, // 0061 GETMBR R15 R6 K15 - 0x903A1E0F, // 0062 SETMBR R14 K15 R15 - 0x88381B10, // 0063 GETMBR R14 R13 K16 - 0x88381D0E, // 0064 GETMBR R14 R14 K14 - 0x883C0D10, // 0065 GETMBR R15 R6 K16 - 0x903A200F, // 0066 SETMBR R14 K16 R15 - 0x88381B10, // 0067 GETMBR R14 R13 K16 - 0x903A360C, // 0068 SETMBR R14 K27 R12 - 0x8838110C, // 0069 GETMBR R14 R8 K12 - 0x8C381D1F, // 006A GETMET R14 R14 K31 - 0x5C401A00, // 006B MOVE R16 R13 - 0x7C380400, // 006C CALL R14 2 - 0xB83A0A00, // 006D GETNGBL R14 K5 - 0x8C381D13, // 006E GETMET R14 R14 K19 - 0x88400D0F, // 006F GETMBR R16 R6 K15 - 0x88440D10, // 0070 GETMBR R17 R6 K16 - 0x7C380600, // 0071 CALL R14 3 - 0x5C2C1C00, // 0072 MOVE R11 R14 - 0x4C380000, // 0073 LDNIL R14 - 0x1C38160E, // 0074 EQ R14 R11 R14 - 0x783A0005, // 0075 JMPF R14 #007C - 0x8C380B14, // 0076 GETMET R14 R5 K20 - 0x58400020, // 0077 LDCONST R16 K32 - 0x88440D0F, // 0078 GETMBR R17 R6 K15 - 0x88480D10, // 0079 GETMBR R18 R6 K16 - 0x7C380800, // 007A CALL R14 4 - 0x5C2C1C00, // 007B MOVE R11 R14 - 0xB83A0200, // 007C GETNGBL R14 K1 - 0x8C381D02, // 007D GETMET R14 R14 K2 - 0x8C400B14, // 007E GETMET R16 R5 K20 - 0x58480021, // 007F LDCONST R18 K33 - 0x5C4C1600, // 0080 MOVE R19 R11 - 0x7C400600, // 0081 CALL R16 3 - 0x58440017, // 0082 LDCONST R17 K23 - 0x7C380600, // 0083 CALL R14 3 - 0x70020026, // 0084 JMP #00AC - 0x88380D11, // 0085 GETMBR R14 R6 K17 - 0x4C3C0000, // 0086 LDNIL R15 - 0x20381C0F, // 0087 NE R14 R14 R15 - 0x783A0022, // 0088 JMPF R14 #00AC - 0xB83A0A00, // 0089 GETNGBL R14 K5 - 0x8C381D22, // 008A GETMET R14 R14 K34 - 0x7C380200, // 008B CALL R14 1 - 0x9036220E, // 008C SETMBR R13 K17 R14 - 0x88381B11, // 008D GETMBR R14 R13 K17 - 0xB83E0A00, // 008E GETNGBL R15 K5 - 0x8C3C1F1E, // 008F GETMET R15 R15 K30 - 0x7C3C0200, // 0090 CALL R15 1 - 0x903A1C0F, // 0091 SETMBR R14 K14 R15 - 0x88381B11, // 0092 GETMBR R14 R13 K17 - 0x88381D0E, // 0093 GETMBR R14 R14 K14 - 0x883C0D0D, // 0094 GETMBR R15 R6 K13 - 0x903A1A0F, // 0095 SETMBR R14 K13 R15 - 0x88381B11, // 0096 GETMBR R14 R13 K17 - 0x88381D0E, // 0097 GETMBR R14 R14 K14 - 0x883C0D0F, // 0098 GETMBR R15 R6 K15 - 0x903A1E0F, // 0099 SETMBR R14 K15 R15 - 0x88381B11, // 009A GETMBR R14 R13 K17 - 0x88381D0E, // 009B GETMBR R14 R14 K14 - 0x883C0D10, // 009C GETMBR R15 R6 K16 - 0x903A200F, // 009D SETMBR R14 K16 R15 - 0x88381B11, // 009E GETMBR R14 R13 K17 - 0xB83E0A00, // 009F GETNGBL R15 K5 - 0x8C3C1F23, // 00A0 GETMET R15 R15 K35 - 0x7C3C0200, // 00A1 CALL R15 1 - 0x903A220F, // 00A2 SETMBR R14 K17 R15 - 0x88381B11, // 00A3 GETMBR R14 R13 K17 - 0x88381D11, // 00A4 GETMBR R14 R14 K17 - 0x883C0D11, // 00A5 GETMBR R15 R6 K17 - 0x903A220F, // 00A6 SETMBR R14 K17 R15 - 0x8838110C, // 00A7 GETMBR R14 R8 K12 - 0x8C381D1F, // 00A8 GETMET R14 R14 K31 - 0x5C401A00, // 00A9 MOVE R16 R13 - 0x7C380400, // 00AA CALL R14 2 - 0x7001FFFF, // 00AB JMP #00AC - 0x7001FF71, // 00AC JMP #001F - 0x58240024, // 00AD LDCONST R9 K36 - 0xAC240200, // 00AE CATCH R9 1 0 - 0xB0080000, // 00AF RAISE 2 R0 R0 - 0xB8260200, // 00B0 GETNGBL R9 K1 - 0x8C241302, // 00B1 GETMET R9 R9 K2 - 0x602C0008, // 00B2 GETGBL R11 G8 - 0x8830110C, // 00B3 GETMBR R12 R8 K12 - 0x7C2C0200, // 00B4 CALL R11 1 - 0x002E4A0B, // 00B5 ADD R11 K37 R11 - 0x58300004, // 00B6 LDCONST R12 K4 - 0x7C240600, // 00B7 CALL R9 3 - 0x6024000C, // 00B8 GETGBL R9 G12 - 0x8828110C, // 00B9 GETMBR R10 R8 K12 - 0x7C240200, // 00BA CALL R9 1 - 0x24241326, // 00BB GT R9 R9 K38 - 0x78260024, // 00BC JMPF R9 #00E2 - 0xB8260200, // 00BD GETNGBL R9 K1 - 0x8C241302, // 00BE GETMET R9 R9 K2 - 0x602C0008, // 00BF GETGBL R11 G8 - 0x5C301000, // 00C0 MOVE R12 R8 - 0x7C2C0200, // 00C1 CALL R11 1 - 0x002E4E0B, // 00C2 ADD R11 K39 R11 - 0x58300004, // 00C3 LDCONST R12 K4 - 0x7C240600, // 00C4 CALL R9 3 - 0xB8260200, // 00C5 GETNGBL R9 K1 - 0x8C241302, // 00C6 GETMET R9 R9 K2 - 0x602C0008, // 00C7 GETGBL R11 G8 - 0x8C301129, // 00C8 GETMET R12 R8 K41 - 0x7C300200, // 00C9 CALL R12 1 - 0x7C2C0200, // 00CA CALL R11 1 - 0x002E500B, // 00CB ADD R11 K40 R11 - 0x58300004, // 00CC LDCONST R12 K4 - 0x7C240600, // 00CD CALL R9 3 - 0x8C24032A, // 00CE GETMET R9 R1 K42 - 0x542E0008, // 00CF LDINT R11 9 - 0x50300200, // 00D0 LDBOOL R12 1 0 - 0x7C240600, // 00D1 CALL R9 3 - 0x8C28132B, // 00D2 GETMET R10 R9 K43 - 0x8C301129, // 00D3 GETMET R12 R8 K41 - 0x7C300200, // 00D4 CALL R12 1 - 0x8C30192B, // 00D5 GETMET R12 R12 K43 - 0x7C300200, // 00D6 CALL R12 1 - 0x7C280400, // 00D7 CALL R10 2 - 0x8C28132C, // 00D8 GETMET R10 R9 K44 - 0x7C280200, // 00D9 CALL R10 1 - 0x88280118, // 00DA GETMBR R10 R0 K24 - 0x8C28152D, // 00DB GETMET R10 R10 K45 - 0x8830132E, // 00DC GETMBR R12 R9 K46 - 0x5C340600, // 00DD MOVE R13 R3 - 0x5C380800, // 00DE MOVE R14 R4 - 0x883C132F, // 00DF GETMBR R15 R9 K47 - 0x7C280A00, // 00E0 CALL R10 5 - 0x7002000E, // 00E1 JMP #00F1 - 0x88240330, // 00E2 GETMBR R9 R1 K48 - 0x7826000C, // 00E3 JMPF R9 #00F1 - 0x8C240331, // 00E4 GETMET R9 R1 K49 - 0x7C240200, // 00E5 CALL R9 1 - 0x8C28132B, // 00E6 GETMET R10 R9 K43 - 0x7C280200, // 00E7 CALL R10 1 - 0x8C28132C, // 00E8 GETMET R10 R9 K44 - 0x7C280200, // 00E9 CALL R10 1 - 0x88280118, // 00EA GETMBR R10 R0 K24 - 0x8C28152D, // 00EB GETMET R10 R10 K45 - 0x8830132E, // 00EC GETMBR R12 R9 K46 - 0x5C340600, // 00ED MOVE R13 R3 - 0x5C380800, // 00EE MOVE R14 R4 - 0x883C132F, // 00EF GETMBR R15 R9 K47 - 0x7C280A00, // 00F0 CALL R10 5 - 0x80000000, // 00F1 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: subscribe_response -********************************************************************/ -be_local_closure(Matter_IM_subscribe_response, /* name */ - be_nested_proto( - 11, /* nstack */ - 5, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 8]) { /* constants */ - /* K0 */ be_nested_str_weak(string), - /* K1 */ be_nested_str_weak(matter), - /* K2 */ be_nested_str_weak(SubscribeResponseMessage), - /* K3 */ be_nested_str_weak(from_TLV), - /* K4 */ be_nested_str_weak(tasmota), - /* K5 */ be_nested_str_weak(log), - /* K6 */ be_nested_str_weak(MTR_X3A_X20received_X20SubscribeResponsetMessage_X3D), - /* K7 */ be_const_int(3), - }), - be_str_weak(subscribe_response), - &be_const_str_solidified, - ( &(const binstruction[17]) { /* code */ - 0xA4160000, // 0000 IMPORT R5 K0 - 0xB81A0200, // 0001 GETNGBL R6 K1 - 0x8C180D02, // 0002 GETMET R6 R6 K2 - 0x7C180200, // 0003 CALL R6 1 - 0x8C180D03, // 0004 GETMET R6 R6 K3 - 0x5C200400, // 0005 MOVE R8 R2 - 0x7C180400, // 0006 CALL R6 2 - 0xB81E0800, // 0007 GETNGBL R7 K4 - 0x8C1C0F05, // 0008 GETMET R7 R7 K5 - 0x60240008, // 0009 GETGBL R9 G8 - 0x5C280C00, // 000A MOVE R10 R6 - 0x7C240200, // 000B CALL R9 1 - 0x00260C09, // 000C ADD R9 K6 R9 - 0x58280007, // 000D LDCONST R10 K7 - 0x7C1C0600, // 000E CALL R7 3 - 0x501C0000, // 000F LDBOOL R7 0 0 - 0x80040E00, // 0010 RET 1 R7 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: subscribe_request -********************************************************************/ -be_local_closure(Matter_IM_subscribe_request, /* name */ - be_nested_proto( - 11, /* nstack */ - 5, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 8]) { /* constants */ - /* K0 */ be_nested_str_weak(string), - /* K1 */ be_nested_str_weak(matter), - /* K2 */ be_nested_str_weak(SubscribeRequestMessage), - /* K3 */ be_nested_str_weak(from_TLV), - /* K4 */ be_nested_str_weak(tasmota), - /* K5 */ be_nested_str_weak(log), - /* K6 */ be_nested_str_weak(MTR_X3A_X20received_X20SubscribeRequestMessage_X3D), - /* K7 */ be_const_int(3), - }), - be_str_weak(subscribe_request), - &be_const_str_solidified, - ( &(const binstruction[17]) { /* code */ - 0xA4160000, // 0000 IMPORT R5 K0 - 0xB81A0200, // 0001 GETNGBL R6 K1 - 0x8C180D02, // 0002 GETMET R6 R6 K2 - 0x7C180200, // 0003 CALL R6 1 - 0x8C180D03, // 0004 GETMET R6 R6 K3 - 0x5C200400, // 0005 MOVE R8 R2 - 0x7C180400, // 0006 CALL R6 2 - 0xB81E0800, // 0007 GETNGBL R7 K4 - 0x8C1C0F05, // 0008 GETMET R7 R7 K5 - 0x60240008, // 0009 GETGBL R9 G8 - 0x5C280C00, // 000A MOVE R10 R6 - 0x7C240200, // 000B CALL R9 1 - 0x00260C09, // 000C ADD R9 K6 R9 - 0x58280007, // 000D LDCONST R10 K7 - 0x7C1C0600, // 000E CALL R7 3 - 0x501C0000, // 000F LDBOOL R7 0 0 - 0x80040E00, // 0010 RET 1 R7 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: process_read_request -********************************************************************/ -be_local_closure(Matter_IM_process_read_request, /* name */ - be_nested_proto( - 16, /* nstack */ - 5, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[43]) { /* constants */ - /* K0 */ be_nested_str_weak(tasmota), - /* K1 */ be_nested_str_weak(log), - /* K2 */ be_nested_str_weak(MTR_X3A_X20IM_X3Aread_request_X20processing_X20start), - /* K3 */ be_const_int(3), - /* K4 */ be_nested_str_weak(matter), - /* K5 */ be_nested_str_weak(ReadRequestMessage), - /* K6 */ be_nested_str_weak(from_TLV), - /* K7 */ be_nested_str_weak(attributes_requests), - /* K8 */ be_nested_str_weak(ReportDataMessage), - /* K9 */ be_nested_str_weak(suppress_response), - /* K10 */ be_nested_str_weak(attribute_reports), - /* K11 */ be_nested_str_weak(get_attribute_name), - /* K12 */ be_nested_str_weak(cluster), - /* K13 */ be_nested_str_weak(attribute), - /* K14 */ be_nested_str_weak(MTR_X3A_X20Read_X20Attribute_X20), - /* K15 */ be_nested_str_weak(_X20_X28), - /* K16 */ be_nested_str_weak(_X29), - /* K17 */ be_nested_str_weak(), - /* K18 */ be_const_int(2), - /* K19 */ be_nested_str_weak(responder), - /* K20 */ be_nested_str_weak(device), - /* K21 */ be_nested_str_weak(read_attribute), - /* K22 */ be_nested_str_weak(endpoint), - /* K23 */ be_nested_str_weak(AttributeReportIB), - /* K24 */ be_nested_str_weak(attribute_data), - /* K25 */ be_nested_str_weak(AttributeDataIB), - /* K26 */ be_nested_str_weak(data_version), - /* K27 */ be_const_int(1), - /* K28 */ be_nested_str_weak(path), - /* K29 */ be_nested_str_weak(AttributePathIB), - /* K30 */ be_const_int(0), - /* K31 */ be_nested_str_weak(data), - /* K32 */ be_nested_str_weak(push), - /* K33 */ be_nested_str_weak(stop_iteration), - /* K34 */ be_nested_str_weak(MTR_X3A_X20ReportDataMessage_X3D), - /* K35 */ be_nested_str_weak(MTR_X3A_X20ReportDataMessageTLV_X3D), - /* K36 */ be_nested_str_weak(to_TLV), - /* K37 */ be_nested_str_weak(build_response), - /* K38 */ be_nested_str_weak(encode), - /* K39 */ be_nested_str_weak(encrypt), - /* K40 */ be_nested_str_weak(send_response), - /* K41 */ be_nested_str_weak(raw), - /* K42 */ be_nested_str_weak(message_counter), - }), - be_str_weak(process_read_request), - &be_const_str_solidified, - ( &(const binstruction[132]) { /* code */ - 0xB8160000, // 0000 GETNGBL R5 K0 - 0x8C140B01, // 0001 GETMET R5 R5 K1 - 0x581C0002, // 0002 LDCONST R7 K2 - 0x58200003, // 0003 LDCONST R8 K3 - 0x7C140600, // 0004 CALL R5 3 - 0xB8160800, // 0005 GETNGBL R5 K4 - 0x8C140B05, // 0006 GETMET R5 R5 K5 - 0x7C140200, // 0007 CALL R5 1 - 0x8C140B06, // 0008 GETMET R5 R5 K6 - 0x5C1C0400, // 0009 MOVE R7 R2 - 0x7C140400, // 000A CALL R5 2 - 0x88180B07, // 000B GETMBR R6 R5 K7 - 0x4C1C0000, // 000C LDNIL R7 - 0x20180C07, // 000D NE R6 R6 R7 - 0x781A0072, // 000E JMPF R6 #0082 - 0xB81A0800, // 000F GETNGBL R6 K4 - 0x8C180D08, // 0010 GETMET R6 R6 K8 - 0x7C180200, // 0011 CALL R6 1 - 0x501C0200, // 0012 LDBOOL R7 1 0 - 0x901A1207, // 0013 SETMBR R6 K9 R7 - 0x601C0012, // 0014 GETGBL R7 G18 - 0x7C1C0000, // 0015 CALL R7 0 - 0x901A1407, // 0016 SETMBR R6 K10 R7 - 0x601C0010, // 0017 GETGBL R7 G16 - 0x88200B07, // 0018 GETMBR R8 R5 K7 - 0x7C1C0200, // 0019 CALL R7 1 - 0xA802003F, // 001A EXBLK 0 #005B - 0x5C200E00, // 001B MOVE R8 R7 - 0x7C200000, // 001C CALL R8 0 - 0xB8260800, // 001D GETNGBL R9 K4 - 0x8C24130B, // 001E GETMET R9 R9 K11 - 0x882C110C, // 001F GETMBR R11 R8 K12 - 0x8830110D, // 0020 GETMBR R12 R8 K13 - 0x7C240600, // 0021 CALL R9 3 - 0xB82A0000, // 0022 GETNGBL R10 K0 - 0x8C281501, // 0023 GETMET R10 R10 K1 - 0x60300008, // 0024 GETGBL R12 G8 - 0x5C341000, // 0025 MOVE R13 R8 - 0x7C300200, // 0026 CALL R12 1 - 0x00321C0C, // 0027 ADD R12 K14 R12 - 0x78260002, // 0028 JMPF R9 #002C - 0x00361E09, // 0029 ADD R13 K15 R9 - 0x00341B10, // 002A ADD R13 R13 K16 - 0x70020000, // 002B JMP #002D - 0x58340011, // 002C LDCONST R13 K17 - 0x0030180D, // 002D ADD R12 R12 R13 - 0x58340012, // 002E LDCONST R13 K18 - 0x7C280600, // 002F CALL R10 3 - 0x88280113, // 0030 GETMBR R10 R0 K19 - 0x88281514, // 0031 GETMBR R10 R10 K20 - 0x8C281515, // 0032 GETMET R10 R10 K21 - 0x5C300200, // 0033 MOVE R12 R1 - 0x88341116, // 0034 GETMBR R13 R8 K22 - 0x8838110C, // 0035 GETMBR R14 R8 K12 - 0x883C110D, // 0036 GETMBR R15 R8 K13 - 0x7C280A00, // 0037 CALL R10 5 - 0x4C2C0000, // 0038 LDNIL R11 - 0x202C140B, // 0039 NE R11 R10 R11 - 0x782E001E, // 003A JMPF R11 #005A - 0xB82E0800, // 003B GETNGBL R11 K4 - 0x8C2C1717, // 003C GETMET R11 R11 K23 - 0x7C2C0200, // 003D CALL R11 1 - 0xB8320800, // 003E GETNGBL R12 K4 - 0x8C301919, // 003F GETMET R12 R12 K25 - 0x7C300200, // 0040 CALL R12 1 - 0x902E300C, // 0041 SETMBR R11 K24 R12 - 0x88301718, // 0042 GETMBR R12 R11 K24 - 0x9032351B, // 0043 SETMBR R12 K26 K27 - 0x88301718, // 0044 GETMBR R12 R11 K24 - 0xB8360800, // 0045 GETNGBL R13 K4 - 0x8C341B1D, // 0046 GETMET R13 R13 K29 - 0x7C340200, // 0047 CALL R13 1 - 0x9032380D, // 0048 SETMBR R12 K28 R13 - 0x88301718, // 0049 GETMBR R12 R11 K24 - 0x8830191C, // 004A GETMBR R12 R12 K28 - 0x90322D1E, // 004B SETMBR R12 K22 K30 - 0x88301718, // 004C GETMBR R12 R11 K24 - 0x8830191C, // 004D GETMBR R12 R12 K28 - 0x8834110C, // 004E GETMBR R13 R8 K12 - 0x9032180D, // 004F SETMBR R12 K12 R13 - 0x88301718, // 0050 GETMBR R12 R11 K24 - 0x8830191C, // 0051 GETMBR R12 R12 K28 - 0x8834110D, // 0052 GETMBR R13 R8 K13 - 0x90321A0D, // 0053 SETMBR R12 K13 R13 - 0x88301718, // 0054 GETMBR R12 R11 K24 - 0x90323E0A, // 0055 SETMBR R12 K31 R10 - 0x88300D0A, // 0056 GETMBR R12 R6 K10 - 0x8C301920, // 0057 GETMET R12 R12 K32 - 0x5C381600, // 0058 MOVE R14 R11 - 0x7C300400, // 0059 CALL R12 2 - 0x7001FFBF, // 005A JMP #001B - 0x581C0021, // 005B LDCONST R7 K33 - 0xAC1C0200, // 005C CATCH R7 1 0 - 0xB0080000, // 005D RAISE 2 R0 R0 - 0xB81E0000, // 005E GETNGBL R7 K0 - 0x8C1C0F01, // 005F GETMET R7 R7 K1 - 0x60240008, // 0060 GETGBL R9 G8 - 0x5C280C00, // 0061 MOVE R10 R6 - 0x7C240200, // 0062 CALL R9 1 - 0x00264409, // 0063 ADD R9 K34 R9 - 0x58280003, // 0064 LDCONST R10 K3 - 0x7C1C0600, // 0065 CALL R7 3 - 0xB81E0000, // 0066 GETNGBL R7 K0 - 0x8C1C0F01, // 0067 GETMET R7 R7 K1 - 0x60240008, // 0068 GETGBL R9 G8 - 0x8C280D24, // 0069 GETMET R10 R6 K36 - 0x7C280200, // 006A CALL R10 1 - 0x7C240200, // 006B CALL R9 1 - 0x00264609, // 006C ADD R9 K35 R9 - 0x58280003, // 006D LDCONST R10 K3 - 0x7C1C0600, // 006E CALL R7 3 - 0x8C1C0325, // 006F GETMET R7 R1 K37 - 0x54260004, // 0070 LDINT R9 5 - 0x50280200, // 0071 LDBOOL R10 1 0 - 0x7C1C0600, // 0072 CALL R7 3 - 0x8C200F26, // 0073 GETMET R8 R7 K38 - 0x8C280D24, // 0074 GETMET R10 R6 K36 - 0x7C280200, // 0075 CALL R10 1 - 0x8C281526, // 0076 GETMET R10 R10 K38 - 0x7C280200, // 0077 CALL R10 1 - 0x7C200400, // 0078 CALL R8 2 - 0x8C200F27, // 0079 GETMET R8 R7 K39 - 0x7C200200, // 007A CALL R8 1 - 0x88200113, // 007B GETMBR R8 R0 K19 - 0x8C201128, // 007C GETMET R8 R8 K40 - 0x88280F29, // 007D GETMBR R10 R7 K41 - 0x5C2C0600, // 007E MOVE R11 R3 - 0x5C300800, // 007F MOVE R12 R4 - 0x88340F2A, // 0080 GETMBR R13 R7 K42 - 0x7C200A00, // 0081 CALL R8 5 - 0x50180200, // 0082 LDBOOL R6 1 0 - 0x80040C00, // 0083 RET 1 R6 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: report_data -********************************************************************/ -be_local_closure(Matter_IM_report_data, /* name */ - be_nested_proto( - 11, /* nstack */ - 5, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 8]) { /* constants */ - /* K0 */ be_nested_str_weak(string), - /* K1 */ be_nested_str_weak(matter), - /* K2 */ be_nested_str_weak(ReportDataMessage), - /* K3 */ be_nested_str_weak(from_TLV), - /* K4 */ be_nested_str_weak(tasmota), - /* K5 */ be_nested_str_weak(log), - /* K6 */ be_nested_str_weak(MTR_X3A_X20received_X20ReportDataMessage_X3D), - /* K7 */ be_const_int(3), - }), - be_str_weak(report_data), - &be_const_str_solidified, - ( &(const binstruction[17]) { /* code */ - 0xA4160000, // 0000 IMPORT R5 K0 - 0xB81A0200, // 0001 GETNGBL R6 K1 - 0x8C180D02, // 0002 GETMET R6 R6 K2 - 0x7C180200, // 0003 CALL R6 1 - 0x8C180D03, // 0004 GETMET R6 R6 K3 - 0x5C200400, // 0005 MOVE R8 R2 - 0x7C180400, // 0006 CALL R6 2 - 0xB81E0800, // 0007 GETNGBL R7 K4 - 0x8C1C0F05, // 0008 GETMET R7 R7 K5 - 0x60240008, // 0009 GETGBL R9 G8 - 0x5C280C00, // 000A MOVE R10 R6 - 0x7C240200, // 000B CALL R9 1 - 0x00260C09, // 000C ADD R9 K6 R9 - 0x58280007, // 000D LDCONST R10 K7 - 0x7C1C0600, // 000E CALL R7 3 - 0x501C0000, // 000F LDBOOL R7 0 0 - 0x80040E00, // 0010 RET 1 R7 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: process_invoke_response -********************************************************************/ -be_local_closure(Matter_IM_process_invoke_response, /* name */ - be_nested_proto( - 11, /* nstack */ - 5, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 8]) { /* constants */ - /* K0 */ be_nested_str_weak(string), - /* K1 */ be_nested_str_weak(matter), - /* K2 */ be_nested_str_weak(InvokeResponseMessage), - /* K3 */ be_nested_str_weak(from_TLV), - /* K4 */ be_nested_str_weak(tasmota), - /* K5 */ be_nested_str_weak(log), - /* K6 */ be_nested_str_weak(MTR_X3A_X20received_X20InvokeResponseMessage_X3D), - /* K7 */ be_const_int(3), - }), - be_str_weak(process_invoke_response), - &be_const_str_solidified, - ( &(const binstruction[17]) { /* code */ - 0xA4160000, // 0000 IMPORT R5 K0 - 0xB81A0200, // 0001 GETNGBL R6 K1 - 0x8C180D02, // 0002 GETMET R6 R6 K2 - 0x7C180200, // 0003 CALL R6 1 - 0x8C180D03, // 0004 GETMET R6 R6 K3 - 0x5C200400, // 0005 MOVE R8 R2 - 0x7C180400, // 0006 CALL R6 2 - 0xB81E0800, // 0007 GETNGBL R7 K4 - 0x8C1C0F05, // 0008 GETMET R7 R7 K5 - 0x60240008, // 0009 GETGBL R9 G8 - 0x5C280C00, // 000A MOVE R10 R6 - 0x7C240200, // 000B CALL R9 1 - 0x00260C09, // 000C ADD R9 K6 R9 - 0x58280007, // 000D LDCONST R10 K7 - 0x7C1C0600, // 000E CALL R7 3 - 0x501C0000, // 000F LDBOOL R7 0 0 - 0x80040E00, // 0010 RET 1 R7 + 0x5818000D, // 0023 LDCONST R6 K13 + 0x001A1806, // 0024 ADD R6 K12 R6 + 0x581C0005, // 0025 LDCONST R7 K5 + 0x7C100600, // 0026 CALL R4 3 + 0x8810030E, // 0027 GETMBR R4 R1 K14 + 0x1C14090F, // 0028 EQ R5 R4 K15 + 0x78160005, // 0029 JMPF R5 #0030 + 0x8C140110, // 002A GETMET R5 R0 K16 + 0x5C1C0200, // 002B MOVE R7 R1 + 0x5C200400, // 002C MOVE R8 R2 + 0x7C140600, // 002D CALL R5 3 + 0x80040A00, // 002E RET 1 R5 + 0x7002004D, // 002F JMP #007E + 0x1C140911, // 0030 EQ R5 R4 K17 + 0x78160005, // 0031 JMPF R5 #0038 + 0x8C140112, // 0032 GETMET R5 R0 K18 + 0x5C1C0200, // 0033 MOVE R7 R1 + 0x5C200400, // 0034 MOVE R8 R2 + 0x7C140600, // 0035 CALL R5 3 + 0x80040A00, // 0036 RET 1 R5 + 0x70020045, // 0037 JMP #007E + 0x1C140905, // 0038 EQ R5 R4 K5 + 0x78160005, // 0039 JMPF R5 #0040 + 0x8C140113, // 003A GETMET R5 R0 K19 + 0x5C1C0200, // 003B MOVE R7 R1 + 0x5C200400, // 003C MOVE R8 R2 + 0x7C140600, // 003D CALL R5 3 + 0x80040A00, // 003E RET 1 R5 + 0x7002003D, // 003F JMP #007E + 0x54160003, // 0040 LDINT R5 4 + 0x1C140805, // 0041 EQ R5 R4 R5 + 0x78160005, // 0042 JMPF R5 #0049 + 0x8C140114, // 0043 GETMET R5 R0 K20 + 0x5C1C0200, // 0044 MOVE R7 R1 + 0x5C200400, // 0045 MOVE R8 R2 + 0x7C140600, // 0046 CALL R5 3 + 0x80040A00, // 0047 RET 1 R5 + 0x70020034, // 0048 JMP #007E + 0x54160004, // 0049 LDINT R5 5 + 0x1C140805, // 004A EQ R5 R4 R5 + 0x78160005, // 004B JMPF R5 #0052 + 0x8C140115, // 004C GETMET R5 R0 K21 + 0x5C1C0200, // 004D MOVE R7 R1 + 0x5C200400, // 004E MOVE R8 R2 + 0x7C140600, // 004F CALL R5 3 + 0x80040A00, // 0050 RET 1 R5 + 0x7002002B, // 0051 JMP #007E + 0x54160005, // 0052 LDINT R5 6 + 0x1C140805, // 0053 EQ R5 R4 R5 + 0x78160005, // 0054 JMPF R5 #005B + 0x8C140116, // 0055 GETMET R5 R0 K22 + 0x5C1C0200, // 0056 MOVE R7 R1 + 0x5C200400, // 0057 MOVE R8 R2 + 0x7C140600, // 0058 CALL R5 3 + 0x80040A00, // 0059 RET 1 R5 + 0x70020022, // 005A JMP #007E + 0x54160006, // 005B LDINT R5 7 + 0x1C140805, // 005C EQ R5 R4 R5 + 0x78160005, // 005D JMPF R5 #0064 + 0x8C140117, // 005E GETMET R5 R0 K23 + 0x5C1C0200, // 005F MOVE R7 R1 + 0x5C200400, // 0060 MOVE R8 R2 + 0x7C140600, // 0061 CALL R5 3 + 0x80040A00, // 0062 RET 1 R5 + 0x70020019, // 0063 JMP #007E + 0x54160007, // 0064 LDINT R5 8 + 0x1C140805, // 0065 EQ R5 R4 R5 + 0x78160005, // 0066 JMPF R5 #006D + 0x8C140118, // 0067 GETMET R5 R0 K24 + 0x5C1C0200, // 0068 MOVE R7 R1 + 0x5C200400, // 0069 MOVE R8 R2 + 0x7C140600, // 006A CALL R5 3 + 0x80040A00, // 006B RET 1 R5 + 0x70020010, // 006C JMP #007E + 0x54160008, // 006D LDINT R5 9 + 0x1C140805, // 006E EQ R5 R4 R5 + 0x78160005, // 006F JMPF R5 #0076 + 0x8C140119, // 0070 GETMET R5 R0 K25 + 0x5C1C0200, // 0071 MOVE R7 R1 + 0x5C200400, // 0072 MOVE R8 R2 + 0x7C140600, // 0073 CALL R5 3 + 0x80040A00, // 0074 RET 1 R5 + 0x70020007, // 0075 JMP #007E + 0x54160009, // 0076 LDINT R5 10 + 0x1C140805, // 0077 EQ R5 R4 R5 + 0x78160004, // 0078 JMPF R5 #007E + 0x8C14011A, // 0079 GETMET R5 R0 K26 + 0x5C1C0200, // 007A MOVE R7 R1 + 0x5C200400, // 007B MOVE R8 R2 + 0x7C140600, // 007C CALL R5 3 + 0x80040A00, // 007D RET 1 R5 + 0x50140000, // 007E LDBOOL R5 0 0 + 0x80040A00, // 007F RET 1 R5 }) ) ); @@ -1242,24 +1696,28 @@ be_local_closure(Matter_IM_process_invoke_response, /* name */ ** Solidified class: Matter_IM ********************************************************************/ be_local_class(Matter_IM, - 1, + 2, NULL, - be_nested_map(14, + be_nested_map(18, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(process_timed_request, -1), be_const_closure(Matter_IM_process_timed_request_closure) }, - { be_const_key_weak(process_status_response, -1), be_const_closure(Matter_IM_process_status_response_closure) }, - { be_const_key_weak(process_incoming, -1), be_const_closure(Matter_IM_process_incoming_closure) }, - { be_const_key_weak(every_second, -1), be_const_closure(Matter_IM_every_second_closure) }, - { be_const_key_weak(process_write_response, -1), be_const_closure(Matter_IM_process_write_response_closure) }, - { be_const_key_weak(init, 10), be_const_closure(Matter_IM_init_closure) }, - { be_const_key_weak(process_write_request, -1), be_const_closure(Matter_IM_process_write_request_closure) }, - { be_const_key_weak(process_invoke_request, 2), be_const_closure(Matter_IM_process_invoke_request_closure) }, + { be_const_key_weak(process_timed_request, 14), be_const_closure(Matter_IM_process_timed_request_closure) }, + { be_const_key_weak(responder, -1), be_const_var(0) }, { be_const_key_weak(process_read_request, -1), be_const_closure(Matter_IM_process_read_request_closure) }, - { be_const_key_weak(subscribe_response, -1), be_const_closure(Matter_IM_subscribe_response_closure) }, - { be_const_key_weak(subscribe_request, 7), be_const_closure(Matter_IM_subscribe_request_closure) }, - { be_const_key_weak(responder, 8), be_const_var(0) }, + { be_const_key_weak(every_second, 2), be_const_closure(Matter_IM_every_second_closure) }, { be_const_key_weak(report_data, -1), be_const_closure(Matter_IM_report_data_closure) }, { be_const_key_weak(process_invoke_response, -1), be_const_closure(Matter_IM_process_invoke_response_closure) }, + { be_const_key_weak(process_write_response, -1), be_const_closure(Matter_IM_process_write_response_closure) }, + { be_const_key_weak(device, -1), be_const_var(1) }, + { be_const_key_weak(subscribe_request, -1), be_const_closure(Matter_IM_subscribe_request_closure) }, + { be_const_key_weak(process_invoke_request, -1), be_const_closure(Matter_IM_process_invoke_request_closure) }, + { be_const_key_weak(MAX_MESSAGE, -1), be_const_int(1200) }, + { be_const_key_weak(process_status_response, 10), be_const_closure(Matter_IM_process_status_response_closure) }, + { be_const_key_weak(send_attr_report, -1), be_const_closure(Matter_IM_send_attr_report_closure) }, + { be_const_key_weak(subscribe_response, 8), be_const_closure(Matter_IM_subscribe_response_closure) }, + { be_const_key_weak(process_write_request, -1), be_const_closure(Matter_IM_process_write_request_closure) }, + { be_const_key_weak(init, 7), be_const_closure(Matter_IM_init_closure) }, + { be_const_key_weak(MSG_TIMEOUT, 6), be_const_int(10000) }, + { be_const_key_weak(process_incoming, -1), be_const_closure(Matter_IM_process_incoming_closure) }, })), be_str_weak(Matter_IM) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM_Data.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM_Data.h index b0fe641e7..738b9ec91 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM_Data.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM_Data.h @@ -2429,7 +2429,7 @@ be_local_closure(Matter_StatusIB_to_TLV, /* name */ ( &(const bvalue[ 9]) { /* constants */ /* K0 */ be_nested_str_weak(matter), /* K1 */ be_nested_str_weak(TLV), - /* K2 */ be_nested_str_weak(Matter_TLV_list), + /* K2 */ be_nested_str_weak(Matter_TLV_struct), /* K3 */ be_nested_str_weak(add_TLV), /* K4 */ be_const_int(0), /* K5 */ be_nested_str_weak(U2), diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Message.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Message.h index 4ea63aebd..76f644b3a 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Message.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Message.h @@ -6,6 +6,799 @@ extern const bclass be_class_Matter_Frame; +/******************************************************************** +** Solidified function: encrypt +********************************************************************/ +be_local_closure(Matter_Frame_encrypt, /* name */ + be_nested_proto( + 15, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[30]) { /* constants */ + /* K0 */ be_nested_str_weak(crypto), + /* K1 */ be_nested_str_weak(raw), + /* K2 */ be_nested_str_weak(session), + /* K3 */ be_nested_str_weak(get_r2i), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str_weak(payload_idx), + /* K6 */ be_const_int(1), + /* K7 */ be_const_int(2147483647), + /* K8 */ be_nested_str_weak(add), + /* K9 */ be_nested_str_weak(flags), + /* K10 */ be_nested_str_weak(message_counter), + /* K11 */ be_nested_str_weak(get_mode), + /* K12 */ be_nested_str_weak(__CASE), + /* K13 */ be_nested_str_weak(deviceid), + /* K14 */ be_nested_str_weak(resize), + /* K15 */ be_nested_str_weak(tasmota), + /* K16 */ be_nested_str_weak(log), + /* K17 */ be_nested_str_weak(MTR_X3A_X20cleartext_X3A_X20), + /* K18 */ be_nested_str_weak(tohex), + /* K19 */ be_const_int(3), + /* K20 */ be_nested_str_weak(MTR_X3A_X20_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A), + /* K21 */ be_nested_str_weak(MTR_X3A_X20r2i_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), + /* K22 */ be_nested_str_weak(MTR_X3A_X20p_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), + /* K23 */ be_nested_str_weak(MTR_X3A_X20a_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), + /* K24 */ be_nested_str_weak(MTR_X3A_X20n_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), + /* K25 */ be_nested_str_weak(AES_CCM), + /* K26 */ be_nested_str_weak(encrypt), + /* K27 */ be_nested_str_weak(tag), + /* K28 */ be_nested_str_weak(MTR_X3A_X20ciphertext_X20_X20_X3D), + /* K29 */ be_nested_str_weak(MTR_X3A_X20tag_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), + }), + be_str_weak(encrypt), + &be_const_str_solidified, + ( &(const binstruction[122]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x88080101, // 0001 GETMBR R2 R0 K1 + 0x880C0102, // 0002 GETMBR R3 R0 K2 + 0x8C100703, // 0003 GETMET R4 R3 K3 + 0x7C100200, // 0004 CALL R4 1 + 0x88140105, // 0005 GETMBR R5 R0 K5 + 0x04140B06, // 0006 SUB R5 R5 K6 + 0x40160805, // 0007 CONNECT R5 K4 R5 + 0x94140405, // 0008 GETIDX R5 R2 R5 + 0x88180105, // 0009 GETMBR R6 R0 K5 + 0x40180D07, // 000A CONNECT R6 R6 K7 + 0x94180406, // 000B GETIDX R6 R2 R6 + 0x601C0015, // 000C GETGBL R7 G21 + 0x7C1C0000, // 000D CALL R7 0 + 0x8C200F08, // 000E GETMET R8 R7 K8 + 0x88280109, // 000F GETMBR R10 R0 K9 + 0x582C0006, // 0010 LDCONST R11 K6 + 0x7C200600, // 0011 CALL R8 3 + 0x8C200F08, // 0012 GETMET R8 R7 K8 + 0x8828010A, // 0013 GETMBR R10 R0 K10 + 0x542E0003, // 0014 LDINT R11 4 + 0x7C200600, // 0015 CALL R8 3 + 0x8C20070B, // 0016 GETMET R8 R3 K11 + 0x7C200200, // 0017 CALL R8 1 + 0x8824070C, // 0018 GETMBR R9 R3 K12 + 0x1C201009, // 0019 EQ R8 R8 R9 + 0x78220003, // 001A JMPF R8 #001F + 0x8820070D, // 001B GETMBR R8 R3 K13 + 0x78220001, // 001C JMPF R8 #001F + 0x8820070D, // 001D GETMBR R8 R3 K13 + 0x40200E08, // 001E CONNECT R8 R7 R8 + 0x8C200F0E, // 001F GETMET R8 R7 K14 + 0x542A000C, // 0020 LDINT R10 13 + 0x7C200400, // 0021 CALL R8 2 + 0xB8221E00, // 0022 GETNGBL R8 K15 + 0x8C201110, // 0023 GETMET R8 R8 K16 + 0x88280101, // 0024 GETMBR R10 R0 K1 + 0x8C281512, // 0025 GETMET R10 R10 K18 + 0x7C280200, // 0026 CALL R10 1 + 0x002A220A, // 0027 ADD R10 K17 R10 + 0x582C0013, // 0028 LDCONST R11 K19 + 0x7C200600, // 0029 CALL R8 3 + 0xB8221E00, // 002A GETNGBL R8 K15 + 0x8C201110, // 002B GETMET R8 R8 K16 + 0x58280014, // 002C LDCONST R10 K20 + 0x582C0013, // 002D LDCONST R11 K19 + 0x7C200600, // 002E CALL R8 3 + 0xB8221E00, // 002F GETNGBL R8 K15 + 0x8C201110, // 0030 GETMET R8 R8 K16 + 0x8C280912, // 0031 GETMET R10 R4 K18 + 0x7C280200, // 0032 CALL R10 1 + 0x002A2A0A, // 0033 ADD R10 K21 R10 + 0x582C0013, // 0034 LDCONST R11 K19 + 0x7C200600, // 0035 CALL R8 3 + 0xB8221E00, // 0036 GETNGBL R8 K15 + 0x8C201110, // 0037 GETMET R8 R8 K16 + 0x8C280D12, // 0038 GETMET R10 R6 K18 + 0x7C280200, // 0039 CALL R10 1 + 0x002A2C0A, // 003A ADD R10 K22 R10 + 0x582C0013, // 003B LDCONST R11 K19 + 0x7C200600, // 003C CALL R8 3 + 0xB8221E00, // 003D GETNGBL R8 K15 + 0x8C201110, // 003E GETMET R8 R8 K16 + 0x8C280B12, // 003F GETMET R10 R5 K18 + 0x7C280200, // 0040 CALL R10 1 + 0x002A2E0A, // 0041 ADD R10 K23 R10 + 0x582C0013, // 0042 LDCONST R11 K19 + 0x7C200600, // 0043 CALL R8 3 + 0xB8221E00, // 0044 GETNGBL R8 K15 + 0x8C201110, // 0045 GETMET R8 R8 K16 + 0x8C280F12, // 0046 GETMET R10 R7 K18 + 0x7C280200, // 0047 CALL R10 1 + 0x002A300A, // 0048 ADD R10 K24 R10 + 0x582C0013, // 0049 LDCONST R11 K19 + 0x7C200600, // 004A CALL R8 3 + 0x8C200319, // 004B GETMET R8 R1 K25 + 0x5C280800, // 004C MOVE R10 R4 + 0x5C2C0E00, // 004D MOVE R11 R7 + 0x5C300A00, // 004E MOVE R12 R5 + 0x6034000C, // 004F GETGBL R13 G12 + 0x5C380C00, // 0050 MOVE R14 R6 + 0x7C340200, // 0051 CALL R13 1 + 0x543A000F, // 0052 LDINT R14 16 + 0x7C200C00, // 0053 CALL R8 6 + 0x8C24111A, // 0054 GETMET R9 R8 K26 + 0x5C2C0C00, // 0055 MOVE R11 R6 + 0x7C240400, // 0056 CALL R9 2 + 0x8C28111B, // 0057 GETMET R10 R8 K27 + 0x7C280200, // 0058 CALL R10 1 + 0xB82E1E00, // 0059 GETNGBL R11 K15 + 0x8C2C1710, // 005A GETMET R11 R11 K16 + 0x58340014, // 005B LDCONST R13 K20 + 0x58380013, // 005C LDCONST R14 K19 + 0x7C2C0600, // 005D CALL R11 3 + 0xB82E1E00, // 005E GETNGBL R11 K15 + 0x8C2C1710, // 005F GETMET R11 R11 K16 + 0x8C341312, // 0060 GETMET R13 R9 K18 + 0x7C340200, // 0061 CALL R13 1 + 0x0036380D, // 0062 ADD R13 K28 R13 + 0x58380013, // 0063 LDCONST R14 K19 + 0x7C2C0600, // 0064 CALL R11 3 + 0xB82E1E00, // 0065 GETNGBL R11 K15 + 0x8C2C1710, // 0066 GETMET R11 R11 K16 + 0x8C341512, // 0067 GETMET R13 R10 K18 + 0x7C340200, // 0068 CALL R13 1 + 0x00363A0D, // 0069 ADD R13 K29 R13 + 0x58380013, // 006A LDCONST R14 K19 + 0x7C2C0600, // 006B CALL R11 3 + 0xB82E1E00, // 006C GETNGBL R11 K15 + 0x8C2C1710, // 006D GETMET R11 R11 K16 + 0x58340014, // 006E LDCONST R13 K20 + 0x58380013, // 006F LDCONST R14 K19 + 0x7C2C0600, // 0070 CALL R11 3 + 0x882C0101, // 0071 GETMBR R11 R0 K1 + 0x8C2C170E, // 0072 GETMET R11 R11 K14 + 0x88340105, // 0073 GETMBR R13 R0 K5 + 0x7C2C0400, // 0074 CALL R11 2 + 0x882C0101, // 0075 GETMBR R11 R0 K1 + 0x402C1609, // 0076 CONNECT R11 R11 R9 + 0x882C0101, // 0077 GETMBR R11 R0 K1 + 0x402C160A, // 0078 CONNECT R11 R11 R10 + 0x80000000, // 0079 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: build_response +********************************************************************/ +be_local_closure(Matter_Frame_build_response, /* name */ + be_nested_proto( + 12, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[32]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(message_handler), + /* K2 */ be_nested_str_weak(remote_ip), + /* K3 */ be_nested_str_weak(remote_port), + /* K4 */ be_nested_str_weak(flag_s), + /* K5 */ be_nested_str_weak(flag_dsiz), + /* K6 */ be_const_int(1), + /* K7 */ be_nested_str_weak(dest_node_id_8), + /* K8 */ be_nested_str_weak(source_node_id), + /* K9 */ be_const_int(0), + /* K10 */ be_nested_str_weak(session), + /* K11 */ be_nested_str_weak(local_session_id), + /* K12 */ be_nested_str_weak(initiator_session_id), + /* K13 */ be_nested_str_weak(message_counter), + /* K14 */ be_nested_str_weak(counter_snd), + /* K15 */ be_nested_str_weak(next), + /* K16 */ be_nested_str_weak(_counter_insecure_snd), + /* K17 */ be_nested_str_weak(x_flag_i), + /* K18 */ be_nested_str_weak(opcode), + /* K19 */ be_nested_str_weak(exchange_id), + /* K20 */ be_nested_str_weak(protocol_id), + /* K21 */ be_nested_str_weak(x_flag_r), + /* K22 */ be_nested_str_weak(x_flag_a), + /* K23 */ be_nested_str_weak(ack_message_counter), + /* K24 */ be_nested_str_weak(matter), + /* K25 */ be_nested_str_weak(get_opcode_name), + /* K26 */ be_nested_str_weak(format), + /* K27 */ be_nested_str_weak(0x_X2502X), + /* K28 */ be_nested_str_weak(tasmota), + /* K29 */ be_nested_str_weak(log), + /* K30 */ be_nested_str_weak(MTR_X3A_X20_X3CReplied_X20_X20_X20_X20_X20_X20_X20_X25s), + /* K31 */ be_const_int(2), + }), + be_str_weak(build_response), + &be_const_str_solidified, + ( &(const binstruction[82]) { /* code */ + 0xA40E0000, // 0000 IMPORT R3 K0 + 0x60100006, // 0001 GETGBL R4 G6 + 0x5C140000, // 0002 MOVE R5 R0 + 0x7C100200, // 0003 CALL R4 1 + 0x88140101, // 0004 GETMBR R5 R0 K1 + 0x7C100200, // 0005 CALL R4 1 + 0x88140102, // 0006 GETMBR R5 R0 K2 + 0x90120405, // 0007 SETMBR R4 K2 R5 + 0x88140103, // 0008 GETMBR R5 R0 K3 + 0x90120605, // 0009 SETMBR R4 K3 R5 + 0x88140104, // 000A GETMBR R5 R0 K4 + 0x78160003, // 000B JMPF R5 #0010 + 0x90120B06, // 000C SETMBR R4 K5 K6 + 0x88140108, // 000D GETMBR R5 R0 K8 + 0x90120E05, // 000E SETMBR R4 K7 R5 + 0x70020000, // 000F JMP #0011 + 0x90120B09, // 0010 SETMBR R4 K5 K9 + 0x8814010A, // 0011 GETMBR R5 R0 K10 + 0x90121405, // 0012 SETMBR R4 K10 R5 + 0x8814010B, // 0013 GETMBR R5 R0 K11 + 0x20140B09, // 0014 NE R5 R5 K9 + 0x7816000E, // 0015 JMPF R5 #0025 + 0x8814010A, // 0016 GETMBR R5 R0 K10 + 0x7816000C, // 0017 JMPF R5 #0025 + 0x8814010A, // 0018 GETMBR R5 R0 K10 + 0x88140B0C, // 0019 GETMBR R5 R5 K12 + 0x20140B09, // 001A NE R5 R5 K9 + 0x78160008, // 001B JMPF R5 #0025 + 0x8814010A, // 001C GETMBR R5 R0 K10 + 0x88140B0E, // 001D GETMBR R5 R5 K14 + 0x8C140B0F, // 001E GETMET R5 R5 K15 + 0x7C140200, // 001F CALL R5 1 + 0x90121A05, // 0020 SETMBR R4 K13 R5 + 0x8814010A, // 0021 GETMBR R5 R0 K10 + 0x88140B0C, // 0022 GETMBR R5 R5 K12 + 0x90121605, // 0023 SETMBR R4 K11 R5 + 0x70020005, // 0024 JMP #002B + 0x8814010A, // 0025 GETMBR R5 R0 K10 + 0x88140B10, // 0026 GETMBR R5 R5 K16 + 0x8C140B0F, // 0027 GETMET R5 R5 K15 + 0x7C140200, // 0028 CALL R5 1 + 0x90121A05, // 0029 SETMBR R4 K13 R5 + 0x90121709, // 002A SETMBR R4 K11 K9 + 0x90122309, // 002B SETMBR R4 K17 K9 + 0x90122401, // 002C SETMBR R4 K18 R1 + 0x88140113, // 002D GETMBR R5 R0 K19 + 0x90122605, // 002E SETMBR R4 K19 R5 + 0x88140114, // 002F GETMBR R5 R0 K20 + 0x90122805, // 0030 SETMBR R4 K20 R5 + 0x88140115, // 0031 GETMBR R5 R0 K21 + 0x78160002, // 0032 JMPF R5 #0036 + 0x90122D06, // 0033 SETMBR R4 K22 K6 + 0x8814010D, // 0034 GETMBR R5 R0 K13 + 0x90122E05, // 0035 SETMBR R4 K23 R5 + 0x780A0001, // 0036 JMPF R2 #0039 + 0x58140006, // 0037 LDCONST R5 K6 + 0x70020000, // 0038 JMP #003A + 0x58140009, // 0039 LDCONST R5 K9 + 0x90122A05, // 003A SETMBR R4 K21 R5 + 0x8814090B, // 003B GETMBR R5 R4 K11 + 0x1C140B09, // 003C EQ R5 R5 K9 + 0x78160012, // 003D JMPF R5 #0051 + 0xB8163000, // 003E GETNGBL R5 K24 + 0x8C140B19, // 003F GETMET R5 R5 K25 + 0x881C0912, // 0040 GETMBR R7 R4 K18 + 0x7C140400, // 0041 CALL R5 2 + 0x5C180A00, // 0042 MOVE R6 R5 + 0x741A0004, // 0043 JMPT R6 #0049 + 0x8C18071A, // 0044 GETMET R6 R3 K26 + 0x5820001B, // 0045 LDCONST R8 K27 + 0x88240912, // 0046 GETMBR R9 R4 K18 + 0x7C180600, // 0047 CALL R6 3 + 0x5C140C00, // 0048 MOVE R5 R6 + 0xB81A3800, // 0049 GETNGBL R6 K28 + 0x8C180D1D, // 004A GETMET R6 R6 K29 + 0x8C20071A, // 004B GETMET R8 R3 K26 + 0x5828001E, // 004C LDCONST R10 K30 + 0x5C2C0A00, // 004D MOVE R11 R5 + 0x7C200600, // 004E CALL R8 3 + 0x5824001F, // 004F LDCONST R9 K31 + 0x7C180600, // 0050 CALL R6 3 + 0x80040800, // 0051 RET 1 R4 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_Frame_init, /* name */ + be_nested_proto( + 5, /* nstack */ + 5, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(message_handler), + /* K1 */ be_nested_str_weak(raw), + /* K2 */ be_nested_str_weak(remote_ip), + /* K3 */ be_nested_str_weak(remote_port), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x90020202, // 0001 SETMBR R0 K1 R2 + 0x90020403, // 0002 SETMBR R0 K2 R3 + 0x90020604, // 0003 SETMBR R0 K3 R4 + 0x80000000, // 0004 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: decode_header +********************************************************************/ +be_local_closure(Matter_Frame_decode_header, /* name */ + be_nested_proto( + 7, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[21]) { /* constants */ + /* K0 */ be_const_int(0), + /* K1 */ be_nested_str_weak(raw), + /* K2 */ be_nested_str_weak(flags), + /* K3 */ be_nested_str_weak(get), + /* K4 */ be_const_int(1), + /* K5 */ be_nested_str_weak(flag_s), + /* K6 */ be_nested_str_weak(getbits), + /* K7 */ be_const_int(2), + /* K8 */ be_nested_str_weak(flag_dsiz), + /* K9 */ be_const_int(3), + /* K10 */ be_nested_str_weak(sec_flags), + /* K11 */ be_nested_str_weak(sec_p), + /* K12 */ be_nested_str_weak(sec_c), + /* K13 */ be_nested_str_weak(sec_mx), + /* K14 */ be_nested_str_weak(sec_sesstype), + /* K15 */ be_nested_str_weak(local_session_id), + /* K16 */ be_nested_str_weak(message_counter), + /* K17 */ be_nested_str_weak(source_node_id), + /* K18 */ be_nested_str_weak(dest_node_id_8), + /* K19 */ be_nested_str_weak(dest_node_id_2), + /* K20 */ be_nested_str_weak(payload_idx), + }), + be_str_weak(decode_header), + &be_const_str_solidified, + ( &(const binstruction[121]) { /* code */ + 0x58040000, // 0000 LDCONST R1 K0 + 0x88080101, // 0001 GETMBR R2 R0 K1 + 0x8C0C0503, // 0002 GETMET R3 R2 K3 + 0x58140000, // 0003 LDCONST R5 K0 + 0x58180004, // 0004 LDCONST R6 K4 + 0x7C0C0600, // 0005 CALL R3 3 + 0x90020403, // 0006 SETMBR R0 K2 R3 + 0x880C0102, // 0007 GETMBR R3 R0 K2 + 0x541200F7, // 0008 LDINT R4 248 + 0x2C0C0604, // 0009 AND R3 R3 R4 + 0x200C0700, // 000A NE R3 R3 K0 + 0x780E0001, // 000B JMPF R3 #000E + 0x500C0000, // 000C LDBOOL R3 0 0 + 0x80040600, // 000D RET 1 R3 + 0x8C0C0506, // 000E GETMET R3 R2 K6 + 0x58140007, // 000F LDCONST R5 K7 + 0x58180004, // 0010 LDCONST R6 K4 + 0x7C0C0600, // 0011 CALL R3 3 + 0x90020A03, // 0012 SETMBR R0 K5 R3 + 0x8C0C0506, // 0013 GETMET R3 R2 K6 + 0x58140000, // 0014 LDCONST R5 K0 + 0x58180007, // 0015 LDCONST R6 K7 + 0x7C0C0600, // 0016 CALL R3 3 + 0x90021003, // 0017 SETMBR R0 K8 R3 + 0x880C0108, // 0018 GETMBR R3 R0 K8 + 0x1C0C0709, // 0019 EQ R3 R3 K9 + 0x780E0001, // 001A JMPF R3 #001D + 0x500C0000, // 001B LDBOOL R3 0 0 + 0x80040600, // 001C RET 1 R3 + 0x8C0C0503, // 001D GETMET R3 R2 K3 + 0x58140009, // 001E LDCONST R5 K9 + 0x58180004, // 001F LDCONST R6 K4 + 0x7C0C0600, // 0020 CALL R3 3 + 0x90021403, // 0021 SETMBR R0 K10 R3 + 0x8C0C0506, // 0022 GETMET R3 R2 K6 + 0x54160007, // 0023 LDINT R5 8 + 0x08161205, // 0024 MUL R5 K9 R5 + 0x541A0006, // 0025 LDINT R6 7 + 0x00140A06, // 0026 ADD R5 R5 R6 + 0x58180004, // 0027 LDCONST R6 K4 + 0x7C0C0600, // 0028 CALL R3 3 + 0x90021603, // 0029 SETMBR R0 K11 R3 + 0x8C0C0506, // 002A GETMET R3 R2 K6 + 0x54160007, // 002B LDINT R5 8 + 0x08161205, // 002C MUL R5 K9 R5 + 0x541A0005, // 002D LDINT R6 6 + 0x00140A06, // 002E ADD R5 R5 R6 + 0x58180004, // 002F LDCONST R6 K4 + 0x7C0C0600, // 0030 CALL R3 3 + 0x90021803, // 0031 SETMBR R0 K12 R3 + 0x8C0C0506, // 0032 GETMET R3 R2 K6 + 0x54160007, // 0033 LDINT R5 8 + 0x08161205, // 0034 MUL R5 K9 R5 + 0x541A0004, // 0035 LDINT R6 5 + 0x00140A06, // 0036 ADD R5 R5 R6 + 0x58180004, // 0037 LDCONST R6 K4 + 0x7C0C0600, // 0038 CALL R3 3 + 0x90021A03, // 0039 SETMBR R0 K13 R3 + 0x8C0C0506, // 003A GETMET R3 R2 K6 + 0x54160007, // 003B LDINT R5 8 + 0x08161205, // 003C MUL R5 K9 R5 + 0x58180007, // 003D LDCONST R6 K7 + 0x7C0C0600, // 003E CALL R3 3 + 0x90021C03, // 003F SETMBR R0 K14 R3 + 0x880C010E, // 0040 GETMBR R3 R0 K14 + 0x240C0704, // 0041 GT R3 R3 K4 + 0x780E0001, // 0042 JMPF R3 #0045 + 0x500C0000, // 0043 LDBOOL R3 0 0 + 0x80040600, // 0044 RET 1 R3 + 0x8C0C0503, // 0045 GETMET R3 R2 K3 + 0x58140004, // 0046 LDCONST R5 K4 + 0x58180007, // 0047 LDCONST R6 K7 + 0x7C0C0600, // 0048 CALL R3 3 + 0x90021E03, // 0049 SETMBR R0 K15 R3 + 0x8C0C0503, // 004A GETMET R3 R2 K3 + 0x54160003, // 004B LDINT R5 4 + 0x541A0003, // 004C LDINT R6 4 + 0x7C0C0600, // 004D CALL R3 3 + 0x90022003, // 004E SETMBR R0 K16 R3 + 0x540E0007, // 004F LDINT R3 8 + 0x00040203, // 0050 ADD R1 R1 R3 + 0x880C0105, // 0051 GETMBR R3 R0 K5 + 0x780E0006, // 0052 JMPF R3 #005A + 0x540E0006, // 0053 LDINT R3 7 + 0x000C0203, // 0054 ADD R3 R1 R3 + 0x400C0203, // 0055 CONNECT R3 R1 R3 + 0x940C0403, // 0056 GETIDX R3 R2 R3 + 0x90022203, // 0057 SETMBR R0 K17 R3 + 0x540E0007, // 0058 LDINT R3 8 + 0x00040203, // 0059 ADD R1 R1 R3 + 0x880C0108, // 005A GETMBR R3 R0 K8 + 0x1C0C0704, // 005B EQ R3 R3 K4 + 0x780E0007, // 005C JMPF R3 #0065 + 0x540E0006, // 005D LDINT R3 7 + 0x000C0203, // 005E ADD R3 R1 R3 + 0x400C0203, // 005F CONNECT R3 R1 R3 + 0x940C0403, // 0060 GETIDX R3 R2 R3 + 0x90022403, // 0061 SETMBR R0 K18 R3 + 0x540E0007, // 0062 LDINT R3 8 + 0x00040203, // 0063 ADD R1 R1 R3 + 0x70020008, // 0064 JMP #006E + 0x880C0108, // 0065 GETMBR R3 R0 K8 + 0x1C0C0707, // 0066 EQ R3 R3 K7 + 0x780E0005, // 0067 JMPF R3 #006E + 0x8C0C0503, // 0068 GETMET R3 R2 K3 + 0x5C140200, // 0069 MOVE R5 R1 + 0x58180007, // 006A LDCONST R6 K7 + 0x7C0C0600, // 006B CALL R3 3 + 0x90022603, // 006C SETMBR R0 K19 R3 + 0x00040307, // 006D ADD R1 R1 K7 + 0x880C010D, // 006E GETMBR R3 R0 K13 + 0x780E0005, // 006F JMPF R3 #0076 + 0x8C0C0503, // 0070 GETMET R3 R2 K3 + 0x5C140200, // 0071 MOVE R5 R1 + 0x58180007, // 0072 LDCONST R6 K7 + 0x7C0C0600, // 0073 CALL R3 3 + 0x00100707, // 0074 ADD R4 R3 K7 + 0x00040204, // 0075 ADD R1 R1 R4 + 0x90022801, // 0076 SETMBR R0 K20 R1 + 0x500C0200, // 0077 LDBOOL R3 1 0 + 0x80040600, // 0078 RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: decode_payload +********************************************************************/ +be_local_closure(Matter_Frame_decode_payload, /* name */ + be_nested_proto( + 7, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[19]) { /* constants */ + /* K0 */ be_nested_str_weak(payload_idx), + /* K1 */ be_nested_str_weak(raw), + /* K2 */ be_nested_str_weak(x_flags), + /* K3 */ be_nested_str_weak(get), + /* K4 */ be_const_int(1), + /* K5 */ be_nested_str_weak(x_flag_v), + /* K6 */ be_nested_str_weak(getbits), + /* K7 */ be_nested_str_weak(x_flag_sx), + /* K8 */ be_const_int(3), + /* K9 */ be_nested_str_weak(x_flag_r), + /* K10 */ be_const_int(2), + /* K11 */ be_nested_str_weak(x_flag_a), + /* K12 */ be_nested_str_weak(x_flag_i), + /* K13 */ be_nested_str_weak(opcode), + /* K14 */ be_nested_str_weak(exchange_id), + /* K15 */ be_nested_str_weak(protocol_id), + /* K16 */ be_nested_str_weak(vendor_id), + /* K17 */ be_nested_str_weak(ack_message_counter), + /* K18 */ be_nested_str_weak(app_payload_idx), + }), + be_str_weak(decode_payload), + &be_const_str_solidified, + ( &(const binstruction[87]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x88080101, // 0001 GETMBR R2 R0 K1 + 0x8C0C0503, // 0002 GETMET R3 R2 K3 + 0x5C140200, // 0003 MOVE R5 R1 + 0x58180004, // 0004 LDCONST R6 K4 + 0x7C0C0600, // 0005 CALL R3 3 + 0x90020403, // 0006 SETMBR R0 K2 R3 + 0x8C0C0506, // 0007 GETMET R3 R2 K6 + 0x54160007, // 0008 LDINT R5 8 + 0x08140205, // 0009 MUL R5 R1 R5 + 0x541A0003, // 000A LDINT R6 4 + 0x00140A06, // 000B ADD R5 R5 R6 + 0x58180004, // 000C LDCONST R6 K4 + 0x7C0C0600, // 000D CALL R3 3 + 0x90020A03, // 000E SETMBR R0 K5 R3 + 0x8C0C0506, // 000F GETMET R3 R2 K6 + 0x54160007, // 0010 LDINT R5 8 + 0x08140205, // 0011 MUL R5 R1 R5 + 0x00140B08, // 0012 ADD R5 R5 K8 + 0x58180004, // 0013 LDCONST R6 K4 + 0x7C0C0600, // 0014 CALL R3 3 + 0x90020E03, // 0015 SETMBR R0 K7 R3 + 0x8C0C0506, // 0016 GETMET R3 R2 K6 + 0x54160007, // 0017 LDINT R5 8 + 0x08140205, // 0018 MUL R5 R1 R5 + 0x00140B0A, // 0019 ADD R5 R5 K10 + 0x58180004, // 001A LDCONST R6 K4 + 0x7C0C0600, // 001B CALL R3 3 + 0x90021203, // 001C SETMBR R0 K9 R3 + 0x8C0C0506, // 001D GETMET R3 R2 K6 + 0x54160007, // 001E LDINT R5 8 + 0x08140205, // 001F MUL R5 R1 R5 + 0x00140B04, // 0020 ADD R5 R5 K4 + 0x58180004, // 0021 LDCONST R6 K4 + 0x7C0C0600, // 0022 CALL R3 3 + 0x90021603, // 0023 SETMBR R0 K11 R3 + 0x8C0C0506, // 0024 GETMET R3 R2 K6 + 0x54160007, // 0025 LDINT R5 8 + 0x08140205, // 0026 MUL R5 R1 R5 + 0x58180004, // 0027 LDCONST R6 K4 + 0x7C0C0600, // 0028 CALL R3 3 + 0x90021803, // 0029 SETMBR R0 K12 R3 + 0x8C0C0503, // 002A GETMET R3 R2 K3 + 0x00140304, // 002B ADD R5 R1 K4 + 0x58180004, // 002C LDCONST R6 K4 + 0x7C0C0600, // 002D CALL R3 3 + 0x90021A03, // 002E SETMBR R0 K13 R3 + 0x8C0C0503, // 002F GETMET R3 R2 K3 + 0x0014030A, // 0030 ADD R5 R1 K10 + 0x5818000A, // 0031 LDCONST R6 K10 + 0x7C0C0600, // 0032 CALL R3 3 + 0x90021C03, // 0033 SETMBR R0 K14 R3 + 0x8C0C0503, // 0034 GETMET R3 R2 K3 + 0x54160003, // 0035 LDINT R5 4 + 0x00140205, // 0036 ADD R5 R1 R5 + 0x5818000A, // 0037 LDCONST R6 K10 + 0x7C0C0600, // 0038 CALL R3 3 + 0x90021E03, // 0039 SETMBR R0 K15 R3 + 0x540E0005, // 003A LDINT R3 6 + 0x00040203, // 003B ADD R1 R1 R3 + 0x880C0105, // 003C GETMBR R3 R0 K5 + 0x780E0005, // 003D JMPF R3 #0044 + 0x8C0C0503, // 003E GETMET R3 R2 K3 + 0x5C140200, // 003F MOVE R5 R1 + 0x5818000A, // 0040 LDCONST R6 K10 + 0x7C0C0600, // 0041 CALL R3 3 + 0x90022003, // 0042 SETMBR R0 K16 R3 + 0x0004030A, // 0043 ADD R1 R1 K10 + 0x880C010B, // 0044 GETMBR R3 R0 K11 + 0x780E0006, // 0045 JMPF R3 #004D + 0x8C0C0503, // 0046 GETMET R3 R2 K3 + 0x5C140200, // 0047 MOVE R5 R1 + 0x541A0003, // 0048 LDINT R6 4 + 0x7C0C0600, // 0049 CALL R3 3 + 0x90022203, // 004A SETMBR R0 K17 R3 + 0x540E0003, // 004B LDINT R3 4 + 0x00040203, // 004C ADD R1 R1 R3 + 0x880C0107, // 004D GETMBR R3 R0 K7 + 0x780E0005, // 004E JMPF R3 #0055 + 0x8C0C0503, // 004F GETMET R3 R2 K3 + 0x5C140200, // 0050 MOVE R5 R1 + 0x5818000A, // 0051 LDCONST R6 K10 + 0x7C0C0600, // 0052 CALL R3 3 + 0x0010070A, // 0053 ADD R4 R3 K10 + 0x00040204, // 0054 ADD R1 R1 R4 + 0x90022401, // 0055 SETMBR R0 K18 R1 + 0x80040000, // 0056 RET 1 R0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: debug +********************************************************************/ +be_local_closure(Matter_Frame_debug, /* name */ + be_nested_proto( + 8, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[10]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(Frame), + /* K2 */ be_nested_str_weak(message_handler), + /* K3 */ be_nested_str_weak(decode_header), + /* K4 */ be_nested_str_weak(decode_payload), + /* K5 */ be_nested_str_weak(tasmota), + /* K6 */ be_nested_str_weak(log), + /* K7 */ be_nested_str_weak(MTR_X3A_X20sending_X20decode_X3A_X20), + /* K8 */ be_nested_str_weak(inspect), + /* K9 */ be_const_int(3), + }), + be_str_weak(debug), + &be_const_str_solidified, + ( &(const binstruction[19]) { /* code */ + 0xB80A0000, // 0000 GETNGBL R2 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x88100102, // 0002 GETMBR R4 R0 K2 + 0x5C140200, // 0003 MOVE R5 R1 + 0x7C080600, // 0004 CALL R2 3 + 0x8C0C0503, // 0005 GETMET R3 R2 K3 + 0x7C0C0200, // 0006 CALL R3 1 + 0x8C0C0504, // 0007 GETMET R3 R2 K4 + 0x7C0C0200, // 0008 CALL R3 1 + 0xB80E0A00, // 0009 GETNGBL R3 K5 + 0x8C0C0706, // 000A GETMET R3 R3 K6 + 0xB8160000, // 000B GETNGBL R5 K0 + 0x8C140B08, // 000C GETMET R5 R5 K8 + 0x5C1C0400, // 000D MOVE R7 R2 + 0x7C140400, // 000E CALL R5 2 + 0x00160E05, // 000F ADD R5 K7 R5 + 0x58180009, // 0010 LDCONST R6 K9 + 0x7C0C0600, // 0011 CALL R3 3 + 0x80000000, // 0012 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: build_standalone_ack +********************************************************************/ +be_local_closure(Matter_Frame_build_standalone_ack, /* name */ + be_nested_proto( + 11, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[28]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(message_handler), + /* K2 */ be_nested_str_weak(flag_s), + /* K3 */ be_nested_str_weak(flag_dsiz), + /* K4 */ be_const_int(1), + /* K5 */ be_nested_str_weak(dest_node_id_8), + /* K6 */ be_nested_str_weak(source_node_id), + /* K7 */ be_const_int(0), + /* K8 */ be_nested_str_weak(session), + /* K9 */ be_nested_str_weak(message_counter), + /* K10 */ be_nested_str_weak(counter_snd), + /* K11 */ be_nested_str_weak(next), + /* K12 */ be_nested_str_weak(local_session_id), + /* K13 */ be_nested_str_weak(initiator_session_id), + /* K14 */ be_nested_str_weak(x_flag_i), + /* K15 */ be_nested_str_weak(opcode), + /* K16 */ be_nested_str_weak(exchange_id), + /* K17 */ be_nested_str_weak(protocol_id), + /* K18 */ be_nested_str_weak(x_flag_a), + /* K19 */ be_nested_str_weak(ack_message_counter), + /* K20 */ be_nested_str_weak(x_flag_r), + /* K21 */ be_nested_str_weak(tasmota), + /* K22 */ be_nested_str_weak(log), + /* K23 */ be_nested_str_weak(format), + /* K24 */ be_nested_str_weak(MTR_X3A_X20_X3CReplied_X20_X20_X20_X20_X20_X20_X20_X25s), + /* K25 */ be_nested_str_weak(matter), + /* K26 */ be_nested_str_weak(get_opcode_name), + /* K27 */ be_const_int(2), + }), + be_str_weak(build_standalone_ack), + &be_const_str_solidified, + ( &(const binstruction[45]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x60080006, // 0001 GETGBL R2 G6 + 0x5C0C0000, // 0002 MOVE R3 R0 + 0x7C080200, // 0003 CALL R2 1 + 0x880C0101, // 0004 GETMBR R3 R0 K1 + 0x7C080200, // 0005 CALL R2 1 + 0x880C0102, // 0006 GETMBR R3 R0 K2 + 0x780E0003, // 0007 JMPF R3 #000C + 0x900A0704, // 0008 SETMBR R2 K3 K4 + 0x880C0106, // 0009 GETMBR R3 R0 K6 + 0x900A0A03, // 000A SETMBR R2 K5 R3 + 0x70020000, // 000B JMP #000D + 0x900A0707, // 000C SETMBR R2 K3 K7 + 0x880C0108, // 000D GETMBR R3 R0 K8 + 0x900A1003, // 000E SETMBR R2 K8 R3 + 0x880C0108, // 000F GETMBR R3 R0 K8 + 0x880C070A, // 0010 GETMBR R3 R3 K10 + 0x8C0C070B, // 0011 GETMET R3 R3 K11 + 0x7C0C0200, // 0012 CALL R3 1 + 0x900A1203, // 0013 SETMBR R2 K9 R3 + 0x880C0108, // 0014 GETMBR R3 R0 K8 + 0x880C070D, // 0015 GETMBR R3 R3 K13 + 0x900A1803, // 0016 SETMBR R2 K12 R3 + 0x900A1D07, // 0017 SETMBR R2 K14 K7 + 0x540E000F, // 0018 LDINT R3 16 + 0x900A1E03, // 0019 SETMBR R2 K15 R3 + 0x880C0110, // 001A GETMBR R3 R0 K16 + 0x900A2003, // 001B SETMBR R2 K16 R3 + 0x900A2307, // 001C SETMBR R2 K17 K7 + 0x900A2504, // 001D SETMBR R2 K18 K4 + 0x880C0109, // 001E GETMBR R3 R0 K9 + 0x900A2603, // 001F SETMBR R2 K19 R3 + 0x900A2907, // 0020 SETMBR R2 K20 K7 + 0xB80E2A00, // 0021 GETNGBL R3 K21 + 0x8C0C0716, // 0022 GETMET R3 R3 K22 + 0x8C140317, // 0023 GETMET R5 R1 K23 + 0x581C0018, // 0024 LDCONST R7 K24 + 0xB8223200, // 0025 GETNGBL R8 K25 + 0x8C20111A, // 0026 GETMET R8 R8 K26 + 0x8828050F, // 0027 GETMBR R10 R2 K15 + 0x7C200400, // 0028 CALL R8 2 + 0x7C140600, // 0029 CALL R5 3 + 0x5818001B, // 002A LDCONST R6 K27 + 0x7C0C0600, // 002B CALL R3 3 + 0x80040400, // 002C RET 1 R2 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: decrypt ********************************************************************/ @@ -231,491 +1024,6 @@ be_local_closure(Matter_Frame_decrypt, /* name */ /*******************************************************************/ -/******************************************************************** -** Solidified function: init -********************************************************************/ -be_local_closure(Matter_Frame_init, /* name */ - be_nested_proto( - 3, /* nstack */ - 3, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(message_handler), - /* K1 */ be_nested_str_weak(raw), - }), - be_str_weak(init), - &be_const_str_solidified, - ( &(const binstruction[ 3]) { /* code */ - 0x90020001, // 0000 SETMBR R0 K0 R1 - 0x90020202, // 0001 SETMBR R0 K1 R2 - 0x80000000, // 0002 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: decode_payload -********************************************************************/ -be_local_closure(Matter_Frame_decode_payload, /* name */ - be_nested_proto( - 7, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[19]) { /* constants */ - /* K0 */ be_nested_str_weak(payload_idx), - /* K1 */ be_nested_str_weak(raw), - /* K2 */ be_nested_str_weak(x_flags), - /* K3 */ be_nested_str_weak(get), - /* K4 */ be_const_int(1), - /* K5 */ be_nested_str_weak(x_flag_v), - /* K6 */ be_nested_str_weak(getbits), - /* K7 */ be_nested_str_weak(x_flag_sx), - /* K8 */ be_const_int(3), - /* K9 */ be_nested_str_weak(x_flag_r), - /* K10 */ be_const_int(2), - /* K11 */ be_nested_str_weak(x_flag_a), - /* K12 */ be_nested_str_weak(x_flag_i), - /* K13 */ be_nested_str_weak(opcode), - /* K14 */ be_nested_str_weak(exchange_id), - /* K15 */ be_nested_str_weak(protocol_id), - /* K16 */ be_nested_str_weak(vendor_id), - /* K17 */ be_nested_str_weak(ack_message_counter), - /* K18 */ be_nested_str_weak(app_payload_idx), - }), - be_str_weak(decode_payload), - &be_const_str_solidified, - ( &(const binstruction[87]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x88080101, // 0001 GETMBR R2 R0 K1 - 0x8C0C0503, // 0002 GETMET R3 R2 K3 - 0x5C140200, // 0003 MOVE R5 R1 - 0x58180004, // 0004 LDCONST R6 K4 - 0x7C0C0600, // 0005 CALL R3 3 - 0x90020403, // 0006 SETMBR R0 K2 R3 - 0x8C0C0506, // 0007 GETMET R3 R2 K6 - 0x54160007, // 0008 LDINT R5 8 - 0x08140205, // 0009 MUL R5 R1 R5 - 0x541A0003, // 000A LDINT R6 4 - 0x00140A06, // 000B ADD R5 R5 R6 - 0x58180004, // 000C LDCONST R6 K4 - 0x7C0C0600, // 000D CALL R3 3 - 0x90020A03, // 000E SETMBR R0 K5 R3 - 0x8C0C0506, // 000F GETMET R3 R2 K6 - 0x54160007, // 0010 LDINT R5 8 - 0x08140205, // 0011 MUL R5 R1 R5 - 0x00140B08, // 0012 ADD R5 R5 K8 - 0x58180004, // 0013 LDCONST R6 K4 - 0x7C0C0600, // 0014 CALL R3 3 - 0x90020E03, // 0015 SETMBR R0 K7 R3 - 0x8C0C0506, // 0016 GETMET R3 R2 K6 - 0x54160007, // 0017 LDINT R5 8 - 0x08140205, // 0018 MUL R5 R1 R5 - 0x00140B0A, // 0019 ADD R5 R5 K10 - 0x58180004, // 001A LDCONST R6 K4 - 0x7C0C0600, // 001B CALL R3 3 - 0x90021203, // 001C SETMBR R0 K9 R3 - 0x8C0C0506, // 001D GETMET R3 R2 K6 - 0x54160007, // 001E LDINT R5 8 - 0x08140205, // 001F MUL R5 R1 R5 - 0x00140B04, // 0020 ADD R5 R5 K4 - 0x58180004, // 0021 LDCONST R6 K4 - 0x7C0C0600, // 0022 CALL R3 3 - 0x90021603, // 0023 SETMBR R0 K11 R3 - 0x8C0C0506, // 0024 GETMET R3 R2 K6 - 0x54160007, // 0025 LDINT R5 8 - 0x08140205, // 0026 MUL R5 R1 R5 - 0x58180004, // 0027 LDCONST R6 K4 - 0x7C0C0600, // 0028 CALL R3 3 - 0x90021803, // 0029 SETMBR R0 K12 R3 - 0x8C0C0503, // 002A GETMET R3 R2 K3 - 0x00140304, // 002B ADD R5 R1 K4 - 0x58180004, // 002C LDCONST R6 K4 - 0x7C0C0600, // 002D CALL R3 3 - 0x90021A03, // 002E SETMBR R0 K13 R3 - 0x8C0C0503, // 002F GETMET R3 R2 K3 - 0x0014030A, // 0030 ADD R5 R1 K10 - 0x5818000A, // 0031 LDCONST R6 K10 - 0x7C0C0600, // 0032 CALL R3 3 - 0x90021C03, // 0033 SETMBR R0 K14 R3 - 0x8C0C0503, // 0034 GETMET R3 R2 K3 - 0x54160003, // 0035 LDINT R5 4 - 0x00140205, // 0036 ADD R5 R1 R5 - 0x5818000A, // 0037 LDCONST R6 K10 - 0x7C0C0600, // 0038 CALL R3 3 - 0x90021E03, // 0039 SETMBR R0 K15 R3 - 0x540E0005, // 003A LDINT R3 6 - 0x00040203, // 003B ADD R1 R1 R3 - 0x880C0105, // 003C GETMBR R3 R0 K5 - 0x780E0005, // 003D JMPF R3 #0044 - 0x8C0C0503, // 003E GETMET R3 R2 K3 - 0x5C140200, // 003F MOVE R5 R1 - 0x5818000A, // 0040 LDCONST R6 K10 - 0x7C0C0600, // 0041 CALL R3 3 - 0x90022003, // 0042 SETMBR R0 K16 R3 - 0x0004030A, // 0043 ADD R1 R1 K10 - 0x880C010B, // 0044 GETMBR R3 R0 K11 - 0x780E0006, // 0045 JMPF R3 #004D - 0x8C0C0503, // 0046 GETMET R3 R2 K3 - 0x5C140200, // 0047 MOVE R5 R1 - 0x541A0003, // 0048 LDINT R6 4 - 0x7C0C0600, // 0049 CALL R3 3 - 0x90022203, // 004A SETMBR R0 K17 R3 - 0x540E0003, // 004B LDINT R3 4 - 0x00040203, // 004C ADD R1 R1 R3 - 0x880C0107, // 004D GETMBR R3 R0 K7 - 0x780E0005, // 004E JMPF R3 #0055 - 0x8C0C0503, // 004F GETMET R3 R2 K3 - 0x5C140200, // 0050 MOVE R5 R1 - 0x5818000A, // 0051 LDCONST R6 K10 - 0x7C0C0600, // 0052 CALL R3 3 - 0x0010070A, // 0053 ADD R4 R3 K10 - 0x00040204, // 0054 ADD R1 R1 R4 - 0x90022401, // 0055 SETMBR R0 K18 R1 - 0x80040000, // 0056 RET 1 R0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: encrypt -********************************************************************/ -be_local_closure(Matter_Frame_encrypt, /* name */ - be_nested_proto( - 15, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[30]) { /* constants */ - /* K0 */ be_nested_str_weak(crypto), - /* K1 */ be_nested_str_weak(raw), - /* K2 */ be_nested_str_weak(session), - /* K3 */ be_nested_str_weak(get_r2i), - /* K4 */ be_const_int(0), - /* K5 */ be_nested_str_weak(payload_idx), - /* K6 */ be_const_int(1), - /* K7 */ be_const_int(2147483647), - /* K8 */ be_nested_str_weak(add), - /* K9 */ be_nested_str_weak(flags), - /* K10 */ be_nested_str_weak(message_counter), - /* K11 */ be_nested_str_weak(get_mode), - /* K12 */ be_nested_str_weak(__CASE), - /* K13 */ be_nested_str_weak(deviceid), - /* K14 */ be_nested_str_weak(resize), - /* K15 */ be_nested_str_weak(tasmota), - /* K16 */ be_nested_str_weak(log), - /* K17 */ be_nested_str_weak(MTR_X3A_X20cleartext_X3A_X20), - /* K18 */ be_nested_str_weak(tohex), - /* K19 */ be_const_int(3), - /* K20 */ be_nested_str_weak(MTR_X3A_X20_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A), - /* K21 */ be_nested_str_weak(MTR_X3A_X20r2i_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), - /* K22 */ be_nested_str_weak(MTR_X3A_X20p_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), - /* K23 */ be_nested_str_weak(MTR_X3A_X20a_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), - /* K24 */ be_nested_str_weak(MTR_X3A_X20n_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), - /* K25 */ be_nested_str_weak(AES_CCM), - /* K26 */ be_nested_str_weak(encrypt), - /* K27 */ be_nested_str_weak(tag), - /* K28 */ be_nested_str_weak(MTR_X3A_X20ciphertext_X20_X20_X3D), - /* K29 */ be_nested_str_weak(MTR_X3A_X20tag_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), - }), - be_str_weak(encrypt), - &be_const_str_solidified, - ( &(const binstruction[122]) { /* code */ - 0xA4060000, // 0000 IMPORT R1 K0 - 0x88080101, // 0001 GETMBR R2 R0 K1 - 0x880C0102, // 0002 GETMBR R3 R0 K2 - 0x8C100703, // 0003 GETMET R4 R3 K3 - 0x7C100200, // 0004 CALL R4 1 - 0x88140105, // 0005 GETMBR R5 R0 K5 - 0x04140B06, // 0006 SUB R5 R5 K6 - 0x40160805, // 0007 CONNECT R5 K4 R5 - 0x94140405, // 0008 GETIDX R5 R2 R5 - 0x88180105, // 0009 GETMBR R6 R0 K5 - 0x40180D07, // 000A CONNECT R6 R6 K7 - 0x94180406, // 000B GETIDX R6 R2 R6 - 0x601C0015, // 000C GETGBL R7 G21 - 0x7C1C0000, // 000D CALL R7 0 - 0x8C200F08, // 000E GETMET R8 R7 K8 - 0x88280109, // 000F GETMBR R10 R0 K9 - 0x582C0006, // 0010 LDCONST R11 K6 - 0x7C200600, // 0011 CALL R8 3 - 0x8C200F08, // 0012 GETMET R8 R7 K8 - 0x8828010A, // 0013 GETMBR R10 R0 K10 - 0x542E0003, // 0014 LDINT R11 4 - 0x7C200600, // 0015 CALL R8 3 - 0x8C20070B, // 0016 GETMET R8 R3 K11 - 0x7C200200, // 0017 CALL R8 1 - 0x8824070C, // 0018 GETMBR R9 R3 K12 - 0x1C201009, // 0019 EQ R8 R8 R9 - 0x78220003, // 001A JMPF R8 #001F - 0x8820070D, // 001B GETMBR R8 R3 K13 - 0x78220001, // 001C JMPF R8 #001F - 0x8820070D, // 001D GETMBR R8 R3 K13 - 0x40200E08, // 001E CONNECT R8 R7 R8 - 0x8C200F0E, // 001F GETMET R8 R7 K14 - 0x542A000C, // 0020 LDINT R10 13 - 0x7C200400, // 0021 CALL R8 2 - 0xB8221E00, // 0022 GETNGBL R8 K15 - 0x8C201110, // 0023 GETMET R8 R8 K16 - 0x88280101, // 0024 GETMBR R10 R0 K1 - 0x8C281512, // 0025 GETMET R10 R10 K18 - 0x7C280200, // 0026 CALL R10 1 - 0x002A220A, // 0027 ADD R10 K17 R10 - 0x582C0013, // 0028 LDCONST R11 K19 - 0x7C200600, // 0029 CALL R8 3 - 0xB8221E00, // 002A GETNGBL R8 K15 - 0x8C201110, // 002B GETMET R8 R8 K16 - 0x58280014, // 002C LDCONST R10 K20 - 0x582C0013, // 002D LDCONST R11 K19 - 0x7C200600, // 002E CALL R8 3 - 0xB8221E00, // 002F GETNGBL R8 K15 - 0x8C201110, // 0030 GETMET R8 R8 K16 - 0x8C280912, // 0031 GETMET R10 R4 K18 - 0x7C280200, // 0032 CALL R10 1 - 0x002A2A0A, // 0033 ADD R10 K21 R10 - 0x582C0013, // 0034 LDCONST R11 K19 - 0x7C200600, // 0035 CALL R8 3 - 0xB8221E00, // 0036 GETNGBL R8 K15 - 0x8C201110, // 0037 GETMET R8 R8 K16 - 0x8C280D12, // 0038 GETMET R10 R6 K18 - 0x7C280200, // 0039 CALL R10 1 - 0x002A2C0A, // 003A ADD R10 K22 R10 - 0x582C0013, // 003B LDCONST R11 K19 - 0x7C200600, // 003C CALL R8 3 - 0xB8221E00, // 003D GETNGBL R8 K15 - 0x8C201110, // 003E GETMET R8 R8 K16 - 0x8C280B12, // 003F GETMET R10 R5 K18 - 0x7C280200, // 0040 CALL R10 1 - 0x002A2E0A, // 0041 ADD R10 K23 R10 - 0x582C0013, // 0042 LDCONST R11 K19 - 0x7C200600, // 0043 CALL R8 3 - 0xB8221E00, // 0044 GETNGBL R8 K15 - 0x8C201110, // 0045 GETMET R8 R8 K16 - 0x8C280F12, // 0046 GETMET R10 R7 K18 - 0x7C280200, // 0047 CALL R10 1 - 0x002A300A, // 0048 ADD R10 K24 R10 - 0x582C0013, // 0049 LDCONST R11 K19 - 0x7C200600, // 004A CALL R8 3 - 0x8C200319, // 004B GETMET R8 R1 K25 - 0x5C280800, // 004C MOVE R10 R4 - 0x5C2C0E00, // 004D MOVE R11 R7 - 0x5C300A00, // 004E MOVE R12 R5 - 0x6034000C, // 004F GETGBL R13 G12 - 0x5C380C00, // 0050 MOVE R14 R6 - 0x7C340200, // 0051 CALL R13 1 - 0x543A000F, // 0052 LDINT R14 16 - 0x7C200C00, // 0053 CALL R8 6 - 0x8C24111A, // 0054 GETMET R9 R8 K26 - 0x5C2C0C00, // 0055 MOVE R11 R6 - 0x7C240400, // 0056 CALL R9 2 - 0x8C28111B, // 0057 GETMET R10 R8 K27 - 0x7C280200, // 0058 CALL R10 1 - 0xB82E1E00, // 0059 GETNGBL R11 K15 - 0x8C2C1710, // 005A GETMET R11 R11 K16 - 0x58340014, // 005B LDCONST R13 K20 - 0x58380013, // 005C LDCONST R14 K19 - 0x7C2C0600, // 005D CALL R11 3 - 0xB82E1E00, // 005E GETNGBL R11 K15 - 0x8C2C1710, // 005F GETMET R11 R11 K16 - 0x8C341312, // 0060 GETMET R13 R9 K18 - 0x7C340200, // 0061 CALL R13 1 - 0x0036380D, // 0062 ADD R13 K28 R13 - 0x58380013, // 0063 LDCONST R14 K19 - 0x7C2C0600, // 0064 CALL R11 3 - 0xB82E1E00, // 0065 GETNGBL R11 K15 - 0x8C2C1710, // 0066 GETMET R11 R11 K16 - 0x8C341512, // 0067 GETMET R13 R10 K18 - 0x7C340200, // 0068 CALL R13 1 - 0x00363A0D, // 0069 ADD R13 K29 R13 - 0x58380013, // 006A LDCONST R14 K19 - 0x7C2C0600, // 006B CALL R11 3 - 0xB82E1E00, // 006C GETNGBL R11 K15 - 0x8C2C1710, // 006D GETMET R11 R11 K16 - 0x58340014, // 006E LDCONST R13 K20 - 0x58380013, // 006F LDCONST R14 K19 - 0x7C2C0600, // 0070 CALL R11 3 - 0x882C0101, // 0071 GETMBR R11 R0 K1 - 0x8C2C170E, // 0072 GETMET R11 R11 K14 - 0x88340105, // 0073 GETMBR R13 R0 K5 - 0x7C2C0400, // 0074 CALL R11 2 - 0x882C0101, // 0075 GETMBR R11 R0 K1 - 0x402C1609, // 0076 CONNECT R11 R11 R9 - 0x882C0101, // 0077 GETMBR R11 R0 K1 - 0x402C160A, // 0078 CONNECT R11 R11 R10 - 0x80000000, // 0079 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: build_standalone_ack -********************************************************************/ -be_local_closure(Matter_Frame_build_standalone_ack, /* name */ - be_nested_proto( - 11, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[28]) { /* constants */ - /* K0 */ be_nested_str_weak(string), - /* K1 */ be_nested_str_weak(message_handler), - /* K2 */ be_nested_str_weak(flag_s), - /* K3 */ be_nested_str_weak(flag_dsiz), - /* K4 */ be_const_int(1), - /* K5 */ be_nested_str_weak(dest_node_id_8), - /* K6 */ be_nested_str_weak(source_node_id), - /* K7 */ be_const_int(0), - /* K8 */ be_nested_str_weak(session), - /* K9 */ be_nested_str_weak(message_counter), - /* K10 */ be_nested_str_weak(counter_snd), - /* K11 */ be_nested_str_weak(next), - /* K12 */ be_nested_str_weak(local_session_id), - /* K13 */ be_nested_str_weak(initiator_session_id), - /* K14 */ be_nested_str_weak(x_flag_i), - /* K15 */ be_nested_str_weak(opcode), - /* K16 */ be_nested_str_weak(exchange_id), - /* K17 */ be_nested_str_weak(protocol_id), - /* K18 */ be_nested_str_weak(x_flag_a), - /* K19 */ be_nested_str_weak(ack_message_counter), - /* K20 */ be_nested_str_weak(x_flag_r), - /* K21 */ be_nested_str_weak(tasmota), - /* K22 */ be_nested_str_weak(log), - /* K23 */ be_nested_str_weak(format), - /* K24 */ be_nested_str_weak(MTR_X3A_X20_X3CReplied_X20_X20_X20_X20_X20_X20_X20_X25s), - /* K25 */ be_nested_str_weak(matter), - /* K26 */ be_nested_str_weak(get_opcode_name), - /* K27 */ be_const_int(2), - }), - be_str_weak(build_standalone_ack), - &be_const_str_solidified, - ( &(const binstruction[45]) { /* code */ - 0xA4060000, // 0000 IMPORT R1 K0 - 0x60080006, // 0001 GETGBL R2 G6 - 0x5C0C0000, // 0002 MOVE R3 R0 - 0x7C080200, // 0003 CALL R2 1 - 0x880C0101, // 0004 GETMBR R3 R0 K1 - 0x7C080200, // 0005 CALL R2 1 - 0x880C0102, // 0006 GETMBR R3 R0 K2 - 0x780E0003, // 0007 JMPF R3 #000C - 0x900A0704, // 0008 SETMBR R2 K3 K4 - 0x880C0106, // 0009 GETMBR R3 R0 K6 - 0x900A0A03, // 000A SETMBR R2 K5 R3 - 0x70020000, // 000B JMP #000D - 0x900A0707, // 000C SETMBR R2 K3 K7 - 0x880C0108, // 000D GETMBR R3 R0 K8 - 0x900A1003, // 000E SETMBR R2 K8 R3 - 0x880C0108, // 000F GETMBR R3 R0 K8 - 0x880C070A, // 0010 GETMBR R3 R3 K10 - 0x8C0C070B, // 0011 GETMET R3 R3 K11 - 0x7C0C0200, // 0012 CALL R3 1 - 0x900A1203, // 0013 SETMBR R2 K9 R3 - 0x880C0108, // 0014 GETMBR R3 R0 K8 - 0x880C070D, // 0015 GETMBR R3 R3 K13 - 0x900A1803, // 0016 SETMBR R2 K12 R3 - 0x900A1D07, // 0017 SETMBR R2 K14 K7 - 0x540E000F, // 0018 LDINT R3 16 - 0x900A1E03, // 0019 SETMBR R2 K15 R3 - 0x880C0110, // 001A GETMBR R3 R0 K16 - 0x900A2003, // 001B SETMBR R2 K16 R3 - 0x900A2307, // 001C SETMBR R2 K17 K7 - 0x900A2504, // 001D SETMBR R2 K18 K4 - 0x880C0109, // 001E GETMBR R3 R0 K9 - 0x900A2603, // 001F SETMBR R2 K19 R3 - 0x900A2907, // 0020 SETMBR R2 K20 K7 - 0xB80E2A00, // 0021 GETNGBL R3 K21 - 0x8C0C0716, // 0022 GETMET R3 R3 K22 - 0x8C140317, // 0023 GETMET R5 R1 K23 - 0x581C0018, // 0024 LDCONST R7 K24 - 0xB8223200, // 0025 GETNGBL R8 K25 - 0x8C20111A, // 0026 GETMET R8 R8 K26 - 0x8828050F, // 0027 GETMBR R10 R2 K15 - 0x7C200400, // 0028 CALL R8 2 - 0x7C140600, // 0029 CALL R5 3 - 0x5818001B, // 002A LDCONST R6 K27 - 0x7C0C0600, // 002B CALL R3 3 - 0x80040400, // 002C RET 1 R2 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: debug -********************************************************************/ -be_local_closure(Matter_Frame_debug, /* name */ - be_nested_proto( - 8, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[10]) { /* constants */ - /* K0 */ be_nested_str_weak(matter), - /* K1 */ be_nested_str_weak(Frame), - /* K2 */ be_nested_str_weak(message_handler), - /* K3 */ be_nested_str_weak(decode_header), - /* K4 */ be_nested_str_weak(decode_payload), - /* K5 */ be_nested_str_weak(tasmota), - /* K6 */ be_nested_str_weak(log), - /* K7 */ be_nested_str_weak(MTR_X3A_X20sending_X20decode_X3A_X20), - /* K8 */ be_nested_str_weak(inspect), - /* K9 */ be_const_int(3), - }), - be_str_weak(debug), - &be_const_str_solidified, - ( &(const binstruction[19]) { /* code */ - 0xB80A0000, // 0000 GETNGBL R2 K0 - 0x8C080501, // 0001 GETMET R2 R2 K1 - 0x88100102, // 0002 GETMBR R4 R0 K2 - 0x5C140200, // 0003 MOVE R5 R1 - 0x7C080600, // 0004 CALL R2 3 - 0x8C0C0503, // 0005 GETMET R3 R2 K3 - 0x7C0C0200, // 0006 CALL R3 1 - 0x8C0C0504, // 0007 GETMET R3 R2 K4 - 0x7C0C0200, // 0008 CALL R3 1 - 0xB80E0A00, // 0009 GETNGBL R3 K5 - 0x8C0C0706, // 000A GETMET R3 R3 K6 - 0xB8160000, // 000B GETNGBL R5 K0 - 0x8C140B08, // 000C GETMET R5 R5 K8 - 0x5C1C0400, // 000D MOVE R7 R2 - 0x7C140400, // 000E CALL R5 2 - 0x00160E05, // 000F ADD R5 K7 R5 - 0x58180009, // 0010 LDCONST R6 K9 - 0x7C0C0600, // 0011 CALL R3 3 - 0x80000000, // 0012 RET 0 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified function: encode ********************************************************************/ @@ -914,351 +1222,55 @@ be_local_closure(Matter_Frame_encode, /* name */ /*******************************************************************/ -/******************************************************************** -** Solidified function: build_response -********************************************************************/ -be_local_closure(Matter_Frame_build_response, /* name */ - be_nested_proto( - 12, /* nstack */ - 3, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[30]) { /* constants */ - /* K0 */ be_nested_str_weak(string), - /* K1 */ be_nested_str_weak(message_handler), - /* K2 */ be_nested_str_weak(flag_s), - /* K3 */ be_nested_str_weak(flag_dsiz), - /* K4 */ be_const_int(1), - /* K5 */ be_nested_str_weak(dest_node_id_8), - /* K6 */ be_nested_str_weak(source_node_id), - /* K7 */ be_const_int(0), - /* K8 */ be_nested_str_weak(session), - /* K9 */ be_nested_str_weak(local_session_id), - /* K10 */ be_nested_str_weak(initiator_session_id), - /* K11 */ be_nested_str_weak(message_counter), - /* K12 */ be_nested_str_weak(counter_snd), - /* K13 */ be_nested_str_weak(next), - /* K14 */ be_nested_str_weak(_counter_insecure_snd), - /* K15 */ be_nested_str_weak(x_flag_i), - /* K16 */ be_nested_str_weak(opcode), - /* K17 */ be_nested_str_weak(exchange_id), - /* K18 */ be_nested_str_weak(protocol_id), - /* K19 */ be_nested_str_weak(x_flag_r), - /* K20 */ be_nested_str_weak(x_flag_a), - /* K21 */ be_nested_str_weak(ack_message_counter), - /* K22 */ be_nested_str_weak(matter), - /* K23 */ be_nested_str_weak(get_opcode_name), - /* K24 */ be_nested_str_weak(format), - /* K25 */ be_nested_str_weak(0x_X2502X), - /* K26 */ be_nested_str_weak(tasmota), - /* K27 */ be_nested_str_weak(log), - /* K28 */ be_nested_str_weak(MTR_X3A_X20_X3CReplied_X20_X20_X20_X20_X20_X20_X20_X25s), - /* K29 */ be_const_int(2), - }), - be_str_weak(build_response), - &be_const_str_solidified, - ( &(const binstruction[78]) { /* code */ - 0xA40E0000, // 0000 IMPORT R3 K0 - 0x60100006, // 0001 GETGBL R4 G6 - 0x5C140000, // 0002 MOVE R5 R0 - 0x7C100200, // 0003 CALL R4 1 - 0x88140101, // 0004 GETMBR R5 R0 K1 - 0x7C100200, // 0005 CALL R4 1 - 0x88140102, // 0006 GETMBR R5 R0 K2 - 0x78160003, // 0007 JMPF R5 #000C - 0x90120704, // 0008 SETMBR R4 K3 K4 - 0x88140106, // 0009 GETMBR R5 R0 K6 - 0x90120A05, // 000A SETMBR R4 K5 R5 - 0x70020000, // 000B JMP #000D - 0x90120707, // 000C SETMBR R4 K3 K7 - 0x88140108, // 000D GETMBR R5 R0 K8 - 0x90121005, // 000E SETMBR R4 K8 R5 - 0x88140109, // 000F GETMBR R5 R0 K9 - 0x20140B07, // 0010 NE R5 R5 K7 - 0x7816000E, // 0011 JMPF R5 #0021 - 0x88140108, // 0012 GETMBR R5 R0 K8 - 0x7816000C, // 0013 JMPF R5 #0021 - 0x88140108, // 0014 GETMBR R5 R0 K8 - 0x88140B0A, // 0015 GETMBR R5 R5 K10 - 0x20140B07, // 0016 NE R5 R5 K7 - 0x78160008, // 0017 JMPF R5 #0021 - 0x88140108, // 0018 GETMBR R5 R0 K8 - 0x88140B0C, // 0019 GETMBR R5 R5 K12 - 0x8C140B0D, // 001A GETMET R5 R5 K13 - 0x7C140200, // 001B CALL R5 1 - 0x90121605, // 001C SETMBR R4 K11 R5 - 0x88140108, // 001D GETMBR R5 R0 K8 - 0x88140B0A, // 001E GETMBR R5 R5 K10 - 0x90121205, // 001F SETMBR R4 K9 R5 - 0x70020005, // 0020 JMP #0027 - 0x88140108, // 0021 GETMBR R5 R0 K8 - 0x88140B0E, // 0022 GETMBR R5 R5 K14 - 0x8C140B0D, // 0023 GETMET R5 R5 K13 - 0x7C140200, // 0024 CALL R5 1 - 0x90121605, // 0025 SETMBR R4 K11 R5 - 0x90121307, // 0026 SETMBR R4 K9 K7 - 0x90121F07, // 0027 SETMBR R4 K15 K7 - 0x90122001, // 0028 SETMBR R4 K16 R1 - 0x88140111, // 0029 GETMBR R5 R0 K17 - 0x90122205, // 002A SETMBR R4 K17 R5 - 0x88140112, // 002B GETMBR R5 R0 K18 - 0x90122405, // 002C SETMBR R4 K18 R5 - 0x88140113, // 002D GETMBR R5 R0 K19 - 0x78160002, // 002E JMPF R5 #0032 - 0x90122904, // 002F SETMBR R4 K20 K4 - 0x8814010B, // 0030 GETMBR R5 R0 K11 - 0x90122A05, // 0031 SETMBR R4 K21 R5 - 0x780A0001, // 0032 JMPF R2 #0035 - 0x58140004, // 0033 LDCONST R5 K4 - 0x70020000, // 0034 JMP #0036 - 0x58140007, // 0035 LDCONST R5 K7 - 0x90122605, // 0036 SETMBR R4 K19 R5 - 0x88140909, // 0037 GETMBR R5 R4 K9 - 0x1C140B07, // 0038 EQ R5 R5 K7 - 0x78160012, // 0039 JMPF R5 #004D - 0xB8162C00, // 003A GETNGBL R5 K22 - 0x8C140B17, // 003B GETMET R5 R5 K23 - 0x881C0910, // 003C GETMBR R7 R4 K16 - 0x7C140400, // 003D CALL R5 2 - 0x5C180A00, // 003E MOVE R6 R5 - 0x741A0004, // 003F JMPT R6 #0045 - 0x8C180718, // 0040 GETMET R6 R3 K24 - 0x58200019, // 0041 LDCONST R8 K25 - 0x88240910, // 0042 GETMBR R9 R4 K16 - 0x7C180600, // 0043 CALL R6 3 - 0x5C140C00, // 0044 MOVE R5 R6 - 0xB81A3400, // 0045 GETNGBL R6 K26 - 0x8C180D1B, // 0046 GETMET R6 R6 K27 - 0x8C200718, // 0047 GETMET R8 R3 K24 - 0x5828001C, // 0048 LDCONST R10 K28 - 0x5C2C0A00, // 0049 MOVE R11 R5 - 0x7C200600, // 004A CALL R8 3 - 0x5824001D, // 004B LDCONST R9 K29 - 0x7C180600, // 004C CALL R6 3 - 0x80040800, // 004D RET 1 R4 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: decode_header -********************************************************************/ -be_local_closure(Matter_Frame_decode_header, /* name */ - be_nested_proto( - 7, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[21]) { /* constants */ - /* K0 */ be_const_int(0), - /* K1 */ be_nested_str_weak(raw), - /* K2 */ be_nested_str_weak(flags), - /* K3 */ be_nested_str_weak(get), - /* K4 */ be_const_int(1), - /* K5 */ be_nested_str_weak(flag_s), - /* K6 */ be_nested_str_weak(getbits), - /* K7 */ be_const_int(2), - /* K8 */ be_nested_str_weak(flag_dsiz), - /* K9 */ be_const_int(3), - /* K10 */ be_nested_str_weak(sec_flags), - /* K11 */ be_nested_str_weak(sec_p), - /* K12 */ be_nested_str_weak(sec_c), - /* K13 */ be_nested_str_weak(sec_mx), - /* K14 */ be_nested_str_weak(sec_sesstype), - /* K15 */ be_nested_str_weak(local_session_id), - /* K16 */ be_nested_str_weak(message_counter), - /* K17 */ be_nested_str_weak(source_node_id), - /* K18 */ be_nested_str_weak(dest_node_id_8), - /* K19 */ be_nested_str_weak(dest_node_id_2), - /* K20 */ be_nested_str_weak(payload_idx), - }), - be_str_weak(decode_header), - &be_const_str_solidified, - ( &(const binstruction[121]) { /* code */ - 0x58040000, // 0000 LDCONST R1 K0 - 0x88080101, // 0001 GETMBR R2 R0 K1 - 0x8C0C0503, // 0002 GETMET R3 R2 K3 - 0x58140000, // 0003 LDCONST R5 K0 - 0x58180004, // 0004 LDCONST R6 K4 - 0x7C0C0600, // 0005 CALL R3 3 - 0x90020403, // 0006 SETMBR R0 K2 R3 - 0x880C0102, // 0007 GETMBR R3 R0 K2 - 0x541200F7, // 0008 LDINT R4 248 - 0x2C0C0604, // 0009 AND R3 R3 R4 - 0x200C0700, // 000A NE R3 R3 K0 - 0x780E0001, // 000B JMPF R3 #000E - 0x500C0000, // 000C LDBOOL R3 0 0 - 0x80040600, // 000D RET 1 R3 - 0x8C0C0506, // 000E GETMET R3 R2 K6 - 0x58140007, // 000F LDCONST R5 K7 - 0x58180004, // 0010 LDCONST R6 K4 - 0x7C0C0600, // 0011 CALL R3 3 - 0x90020A03, // 0012 SETMBR R0 K5 R3 - 0x8C0C0506, // 0013 GETMET R3 R2 K6 - 0x58140000, // 0014 LDCONST R5 K0 - 0x58180007, // 0015 LDCONST R6 K7 - 0x7C0C0600, // 0016 CALL R3 3 - 0x90021003, // 0017 SETMBR R0 K8 R3 - 0x880C0108, // 0018 GETMBR R3 R0 K8 - 0x1C0C0709, // 0019 EQ R3 R3 K9 - 0x780E0001, // 001A JMPF R3 #001D - 0x500C0000, // 001B LDBOOL R3 0 0 - 0x80040600, // 001C RET 1 R3 - 0x8C0C0503, // 001D GETMET R3 R2 K3 - 0x58140009, // 001E LDCONST R5 K9 - 0x58180004, // 001F LDCONST R6 K4 - 0x7C0C0600, // 0020 CALL R3 3 - 0x90021403, // 0021 SETMBR R0 K10 R3 - 0x8C0C0506, // 0022 GETMET R3 R2 K6 - 0x54160007, // 0023 LDINT R5 8 - 0x08161205, // 0024 MUL R5 K9 R5 - 0x541A0006, // 0025 LDINT R6 7 - 0x00140A06, // 0026 ADD R5 R5 R6 - 0x58180004, // 0027 LDCONST R6 K4 - 0x7C0C0600, // 0028 CALL R3 3 - 0x90021603, // 0029 SETMBR R0 K11 R3 - 0x8C0C0506, // 002A GETMET R3 R2 K6 - 0x54160007, // 002B LDINT R5 8 - 0x08161205, // 002C MUL R5 K9 R5 - 0x541A0005, // 002D LDINT R6 6 - 0x00140A06, // 002E ADD R5 R5 R6 - 0x58180004, // 002F LDCONST R6 K4 - 0x7C0C0600, // 0030 CALL R3 3 - 0x90021803, // 0031 SETMBR R0 K12 R3 - 0x8C0C0506, // 0032 GETMET R3 R2 K6 - 0x54160007, // 0033 LDINT R5 8 - 0x08161205, // 0034 MUL R5 K9 R5 - 0x541A0004, // 0035 LDINT R6 5 - 0x00140A06, // 0036 ADD R5 R5 R6 - 0x58180004, // 0037 LDCONST R6 K4 - 0x7C0C0600, // 0038 CALL R3 3 - 0x90021A03, // 0039 SETMBR R0 K13 R3 - 0x8C0C0506, // 003A GETMET R3 R2 K6 - 0x54160007, // 003B LDINT R5 8 - 0x08161205, // 003C MUL R5 K9 R5 - 0x58180007, // 003D LDCONST R6 K7 - 0x7C0C0600, // 003E CALL R3 3 - 0x90021C03, // 003F SETMBR R0 K14 R3 - 0x880C010E, // 0040 GETMBR R3 R0 K14 - 0x240C0704, // 0041 GT R3 R3 K4 - 0x780E0001, // 0042 JMPF R3 #0045 - 0x500C0000, // 0043 LDBOOL R3 0 0 - 0x80040600, // 0044 RET 1 R3 - 0x8C0C0503, // 0045 GETMET R3 R2 K3 - 0x58140004, // 0046 LDCONST R5 K4 - 0x58180007, // 0047 LDCONST R6 K7 - 0x7C0C0600, // 0048 CALL R3 3 - 0x90021E03, // 0049 SETMBR R0 K15 R3 - 0x8C0C0503, // 004A GETMET R3 R2 K3 - 0x54160003, // 004B LDINT R5 4 - 0x541A0003, // 004C LDINT R6 4 - 0x7C0C0600, // 004D CALL R3 3 - 0x90022003, // 004E SETMBR R0 K16 R3 - 0x540E0007, // 004F LDINT R3 8 - 0x00040203, // 0050 ADD R1 R1 R3 - 0x880C0105, // 0051 GETMBR R3 R0 K5 - 0x780E0006, // 0052 JMPF R3 #005A - 0x540E0006, // 0053 LDINT R3 7 - 0x000C0203, // 0054 ADD R3 R1 R3 - 0x400C0203, // 0055 CONNECT R3 R1 R3 - 0x940C0403, // 0056 GETIDX R3 R2 R3 - 0x90022203, // 0057 SETMBR R0 K17 R3 - 0x540E0007, // 0058 LDINT R3 8 - 0x00040203, // 0059 ADD R1 R1 R3 - 0x880C0108, // 005A GETMBR R3 R0 K8 - 0x1C0C0704, // 005B EQ R3 R3 K4 - 0x780E0007, // 005C JMPF R3 #0065 - 0x540E0006, // 005D LDINT R3 7 - 0x000C0203, // 005E ADD R3 R1 R3 - 0x400C0203, // 005F CONNECT R3 R1 R3 - 0x940C0403, // 0060 GETIDX R3 R2 R3 - 0x90022403, // 0061 SETMBR R0 K18 R3 - 0x540E0007, // 0062 LDINT R3 8 - 0x00040203, // 0063 ADD R1 R1 R3 - 0x70020008, // 0064 JMP #006E - 0x880C0108, // 0065 GETMBR R3 R0 K8 - 0x1C0C0707, // 0066 EQ R3 R3 K7 - 0x780E0005, // 0067 JMPF R3 #006E - 0x8C0C0503, // 0068 GETMET R3 R2 K3 - 0x5C140200, // 0069 MOVE R5 R1 - 0x58180007, // 006A LDCONST R6 K7 - 0x7C0C0600, // 006B CALL R3 3 - 0x90022603, // 006C SETMBR R0 K19 R3 - 0x00040307, // 006D ADD R1 R1 K7 - 0x880C010D, // 006E GETMBR R3 R0 K13 - 0x780E0005, // 006F JMPF R3 #0076 - 0x8C0C0503, // 0070 GETMET R3 R2 K3 - 0x5C140200, // 0071 MOVE R5 R1 - 0x58180007, // 0072 LDCONST R6 K7 - 0x7C0C0600, // 0073 CALL R3 3 - 0x00100707, // 0074 ADD R4 R3 K7 - 0x00040204, // 0075 ADD R1 R1 R4 - 0x90022801, // 0076 SETMBR R0 K20 R1 - 0x500C0200, // 0077 LDBOOL R3 1 0 - 0x80040600, // 0078 RET 1 R3 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified class: Matter_Frame ********************************************************************/ be_local_class(Matter_Frame, - 30, + 32, NULL, - be_nested_map(39, + be_nested_map(41, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(ack_message_counter, -1), be_const_var(27) }, - { be_const_key_weak(x_flag_r, -1), be_const_var(20) }, - { be_const_key_weak(dest_node_id_2, -1), be_const_var(15) }, - { be_const_key_weak(message_counter, -1), be_const_var(13) }, - { be_const_key_weak(sec_p, 15), be_const_var(9) }, - { be_const_key_weak(init, -1), be_const_closure(Matter_Frame_init_closure) }, - { be_const_key_weak(protocol_id, 31), be_const_var(25) }, - { be_const_key_weak(session, -1), be_const_var(1) }, - { be_const_key_weak(sec_flags, 13), be_const_var(8) }, - { be_const_key_weak(x_flag_sx, 20), be_const_var(19) }, - { be_const_key_weak(sec_mx, -1), be_const_var(11) }, - { be_const_key_weak(encode, -1), be_const_closure(Matter_Frame_encode_closure) }, - { be_const_key_weak(local_session_id, -1), be_const_var(7) }, - { be_const_key_weak(flags, 38), be_const_var(4) }, - { be_const_key_weak(exchange_id, -1), be_const_var(24) }, - { be_const_key_weak(payload_idx, 10), be_const_var(3) }, - { be_const_key_weak(dest_node_id_8, -1), be_const_var(16) }, - { be_const_key_weak(x_flag_i, -1), be_const_var(22) }, - { be_const_key_weak(flag_s, -1), be_const_var(5) }, - { be_const_key_weak(app_payload_idx, 14), be_const_var(29) }, - { be_const_key_weak(flag_dsiz, 12), be_const_var(6) }, - { be_const_key_weak(encrypt, -1), be_const_closure(Matter_Frame_encrypt_closure) }, + { be_const_key_weak(x_flag_a, 8), be_const_var(21) }, { be_const_key_weak(x_flags, -1), be_const_var(17) }, - { be_const_key_weak(x_flag_v, 22), be_const_var(18) }, - { be_const_key_weak(sec_sesstype, -1), be_const_var(12) }, - { be_const_key_weak(x_flag_a, -1), be_const_var(21) }, - { be_const_key_weak(message_handler, 28), be_const_var(0) }, - { be_const_key_weak(sec_extensions, 24), be_const_var(28) }, - { be_const_key_weak(raw, -1), be_const_var(2) }, - { be_const_key_weak(opcode, -1), be_const_var(23) }, - { be_const_key_weak(sec_c, 17), be_const_var(10) }, - { be_const_key_weak(decode_payload, 5), be_const_closure(Matter_Frame_decode_payload_closure) }, - { be_const_key_weak(build_standalone_ack, 2), be_const_closure(Matter_Frame_build_standalone_ack_closure) }, - { be_const_key_weak(vendor_id, -1), be_const_var(26) }, - { be_const_key_weak(debug, -1), be_const_closure(Matter_Frame_debug_closure) }, - { be_const_key_weak(source_node_id, 11), be_const_var(14) }, - { be_const_key_weak(build_response, -1), be_const_closure(Matter_Frame_build_response_closure) }, - { be_const_key_weak(decode_header, -1), be_const_closure(Matter_Frame_decode_header_closure) }, + { be_const_key_weak(raw, 37), be_const_var(2) }, + { be_const_key_weak(sec_sesstype, 0), be_const_var(12) }, + { be_const_key_weak(build_response, 5), be_const_closure(Matter_Frame_build_response_closure) }, + { be_const_key_weak(sec_mx, -1), be_const_var(11) }, + { be_const_key_weak(dest_node_id_2, 32), be_const_var(15) }, + { be_const_key_weak(encode, -1), be_const_closure(Matter_Frame_encode_closure) }, { be_const_key_weak(decrypt, -1), be_const_closure(Matter_Frame_decrypt_closure) }, + { be_const_key_weak(sec_extensions, -1), be_const_var(28) }, + { be_const_key_weak(remote_ip, 7), be_const_var(30) }, + { be_const_key_weak(message_counter, 33), be_const_var(13) }, + { be_const_key_weak(ack_message_counter, -1), be_const_var(27) }, + { be_const_key_weak(x_flag_i, -1), be_const_var(22) }, + { be_const_key_weak(dest_node_id_8, -1), be_const_var(16) }, + { be_const_key_weak(x_flag_r, 2), be_const_var(20) }, + { be_const_key_weak(x_flag_v, -1), be_const_var(18) }, + { be_const_key_weak(opcode, -1), be_const_var(23) }, + { be_const_key_weak(sec_c, 25), be_const_var(10) }, + { be_const_key_weak(sec_p, -1), be_const_var(9) }, + { be_const_key_weak(protocol_id, 29), be_const_var(25) }, + { be_const_key_weak(sec_flags, -1), be_const_var(8) }, + { be_const_key_weak(message_handler, -1), be_const_var(0) }, + { be_const_key_weak(init, -1), be_const_closure(Matter_Frame_init_closure) }, + { be_const_key_weak(encrypt, 19), be_const_closure(Matter_Frame_encrypt_closure) }, + { be_const_key_weak(build_standalone_ack, 27), be_const_closure(Matter_Frame_build_standalone_ack_closure) }, + { be_const_key_weak(decode_payload, -1), be_const_closure(Matter_Frame_decode_payload_closure) }, + { be_const_key_weak(remote_port, 36), be_const_var(31) }, + { be_const_key_weak(flag_dsiz, -1), be_const_var(6) }, + { be_const_key_weak(vendor_id, 16), be_const_var(26) }, + { be_const_key_weak(payload_idx, -1), be_const_var(3) }, + { be_const_key_weak(debug, -1), be_const_closure(Matter_Frame_debug_closure) }, + { be_const_key_weak(x_flag_sx, 39), be_const_var(19) }, + { be_const_key_weak(decode_header, -1), be_const_closure(Matter_Frame_decode_header_closure) }, + { be_const_key_weak(flag_s, -1), be_const_var(5) }, + { be_const_key_weak(app_payload_idx, -1), be_const_var(29) }, + { be_const_key_weak(source_node_id, -1), be_const_var(14) }, + { be_const_key_weak(session, -1), be_const_var(1) }, + { be_const_key_weak(flags, -1), be_const_var(4) }, + { be_const_key_weak(local_session_id, 40), be_const_var(7) }, + { be_const_key_weak(exchange_id, -1), be_const_var(24) }, })), be_str_weak(Matter_Frame) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_MessageHandler.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_MessageHandler.h index d5e22cd1b..453348f65 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_MessageHandler.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_MessageHandler.h @@ -116,9 +116,9 @@ be_local_closure(Matter_MessageHandler_msg_received, /* name */ }), be_str_weak(msg_received), &be_const_str_solidified, - ( &(const binstruction[289]) { /* code */ + ( &(const binstruction[291]) { /* code */ 0xA4120000, // 0000 IMPORT R4 K0 - 0xA8020108, // 0001 EXBLK 0 #010B + 0xA802010A, // 0001 EXBLK 0 #010D 0xB8160200, // 0002 GETNGBL R5 K1 0x8C140B02, // 0003 GETMET R5 R5 K2 0x8C1C0304, // 0004 GETMET R7 R1 K4 @@ -130,282 +130,284 @@ be_local_closure(Matter_MessageHandler_msg_received, /* name */ 0x8C140B06, // 000A GETMET R5 R5 K6 0x5C1C0000, // 000B MOVE R7 R0 0x5C200200, // 000C MOVE R8 R1 - 0x7C140600, // 000D CALL R5 3 - 0x8C180B07, // 000E GETMET R6 R5 K7 - 0x7C180200, // 000F CALL R6 1 - 0x5C1C0C00, // 0010 MOVE R7 R6 - 0x741E0002, // 0011 JMPT R7 #0015 - 0x501C0000, // 0012 LDBOOL R7 0 0 - 0xA8040001, // 0013 EXBLK 1 1 - 0x80040E00, // 0014 RET 1 R7 - 0x881C0B08, // 0015 GETMBR R7 R5 K8 - 0x1C1C0F09, // 0016 EQ R7 R7 K9 - 0x781E0057, // 0017 JMPF R7 #0070 - 0x881C0B0A, // 0018 GETMBR R7 R5 K10 - 0x1C1C0F09, // 0019 EQ R7 R7 K9 - 0x781E0054, // 001A JMPF R7 #0070 - 0x881C010B, // 001B GETMBR R7 R0 K11 - 0x881C0F0C, // 001C GETMBR R7 R7 K12 - 0x8C1C0F0D, // 001D GETMET R7 R7 K13 - 0x88240B0E, // 001E GETMBR R9 R5 K14 - 0x542A0059, // 001F LDINT R10 90 - 0x7C1C0600, // 0020 CALL R7 3 - 0xB8220200, // 0021 GETNGBL R8 K1 - 0x8C201102, // 0022 GETMET R8 R8 K2 - 0x60280008, // 0023 GETGBL R10 G8 - 0x882C0B0E, // 0024 GETMBR R11 R5 K14 - 0x7C280200, // 0025 CALL R10 1 - 0x002A1E0A, // 0026 ADD R10 K15 R10 - 0x00281510, // 0027 ADD R10 R10 K16 - 0x602C0008, // 0028 GETGBL R11 G8 - 0x88300F08, // 0029 GETMBR R12 R7 K8 - 0x7C2C0200, // 002A CALL R11 1 - 0x0028140B, // 002B ADD R10 R10 R11 - 0x582C0011, // 002C LDCONST R11 K17 - 0x7C200600, // 002D CALL R8 3 - 0x90162407, // 002E SETMBR R5 K18 R7 - 0x88200113, // 002F GETMBR R8 R0 K19 - 0x8C201114, // 0030 GETMET R8 R8 K20 - 0x88280B15, // 0031 GETMBR R10 R5 K21 - 0x502C0000, // 0032 LDBOOL R11 0 0 - 0x7C200600, // 0033 CALL R8 3 - 0x7422000D, // 0034 JMPT R8 #0043 - 0xB8220200, // 0035 GETNGBL R8 K1 - 0x8C201102, // 0036 GETMET R8 R8 K2 - 0x8C280916, // 0037 GETMET R10 R4 K22 - 0x58300017, // 0038 LDCONST R12 K23 - 0x88340B15, // 0039 GETMBR R13 R5 K21 - 0x88380113, // 003A GETMBR R14 R0 K19 - 0x8C381D18, // 003B GETMET R14 R14 K24 - 0x7C380200, // 003C CALL R14 1 - 0x7C280800, // 003D CALL R10 4 - 0x582C0011, // 003E LDCONST R11 K17 - 0x7C200600, // 003F CALL R8 3 - 0x50200000, // 0040 LDBOOL R8 0 0 - 0xA8040001, // 0041 EXBLK 1 1 - 0x80041000, // 0042 RET 1 R8 - 0x8C200B19, // 0043 GETMET R8 R5 K25 - 0x7C200200, // 0044 CALL R8 1 - 0x74220002, // 0045 JMPT R8 #0049 - 0x50200000, // 0046 LDBOOL R8 0 0 - 0xA8040001, // 0047 EXBLK 1 1 - 0x80041000, // 0048 RET 1 R8 - 0x8820010B, // 0049 GETMBR R8 R0 K11 - 0x8C20111A, // 004A GETMET R8 R8 K26 - 0x88280B1B, // 004B GETMBR R10 R5 K27 - 0x7C200400, // 004C CALL R8 2 - 0x88200B1C, // 004D GETMBR R8 R5 K28 - 0x5426000F, // 004E LDINT R9 16 - 0x20201009, // 004F NE R8 R8 R9 - 0x78220014, // 0050 JMPF R8 #0066 - 0xB8220A00, // 0051 GETNGBL R8 K5 - 0x8C20111D, // 0052 GETMET R8 R8 K29 - 0x88280B1C, // 0053 GETMBR R10 R5 K28 - 0x7C200400, // 0054 CALL R8 2 - 0x5C241000, // 0055 MOVE R9 R8 - 0x74260004, // 0056 JMPT R9 #005C - 0x8C240916, // 0057 GETMET R9 R4 K22 - 0x582C001E, // 0058 LDCONST R11 K30 - 0x88300B1C, // 0059 GETMBR R12 R5 K28 - 0x7C240600, // 005A CALL R9 3 - 0x5C201200, // 005B MOVE R8 R9 - 0xB8260200, // 005C GETNGBL R9 K1 - 0x8C241302, // 005D GETMET R9 R9 K2 - 0x8C2C0916, // 005E GETMET R11 R4 K22 - 0x5834001F, // 005F LDCONST R13 K31 - 0x5C381000, // 0060 MOVE R14 R8 - 0x5C3C0400, // 0061 MOVE R15 R2 - 0x5C400600, // 0062 MOVE R16 R3 - 0x7C2C0A00, // 0063 CALL R11 5 - 0x58300020, // 0064 LDCONST R12 K32 - 0x7C240600, // 0065 CALL R9 3 - 0x88200121, // 0066 GETMBR R8 R0 K33 - 0x8C201122, // 0067 GETMET R8 R8 K34 - 0x5C280A00, // 0068 MOVE R10 R5 - 0x5C2C0400, // 0069 MOVE R11 R2 - 0x5C300600, // 006A MOVE R12 R3 - 0x7C200800, // 006B CALL R8 4 - 0x50200200, // 006C LDBOOL R8 1 0 - 0xA8040001, // 006D EXBLK 1 1 - 0x80041000, // 006E RET 1 R8 - 0x70020095, // 006F JMP #0106 - 0xB81E0200, // 0070 GETNGBL R7 K1 - 0x8C1C0F02, // 0071 GETMET R7 R7 K2 - 0x8C240916, // 0072 GETMET R9 R4 K22 - 0x582C0023, // 0073 LDCONST R11 K35 - 0x88300B08, // 0074 GETMBR R12 R5 K8 - 0x88340B15, // 0075 GETMBR R13 R5 K21 - 0x7C240800, // 0076 CALL R9 4 - 0x58280011, // 0077 LDCONST R10 K17 - 0x7C1C0600, // 0078 CALL R7 3 - 0x881C010B, // 0079 GETMBR R7 R0 K11 - 0x881C0F0C, // 007A GETMBR R7 R7 K12 - 0x8C1C0F24, // 007B GETMET R7 R7 K36 - 0x88240B08, // 007C GETMBR R9 R5 K8 - 0x7C1C0400, // 007D CALL R7 2 - 0x4C200000, // 007E LDNIL R8 - 0x1C200E08, // 007F EQ R8 R7 R8 - 0x78220013, // 0080 JMPF R8 #0095 - 0xB8220200, // 0081 GETNGBL R8 K1 - 0x8C201102, // 0082 GETMET R8 R8 K2 - 0x60280008, // 0083 GETGBL R10 G8 - 0x882C0B08, // 0084 GETMBR R11 R5 K8 - 0x7C280200, // 0085 CALL R10 1 - 0x002A4A0A, // 0086 ADD R10 K37 R10 - 0x582C0011, // 0087 LDCONST R11 K17 - 0x7C200600, // 0088 CALL R8 3 - 0xB8220200, // 0089 GETNGBL R8 K1 - 0x8C201102, // 008A GETMET R8 R8 K2 - 0xB82A0A00, // 008B GETNGBL R10 K5 - 0x8C281527, // 008C GETMET R10 R10 K39 - 0x5C300A00, // 008D MOVE R12 R5 - 0x7C280400, // 008E CALL R10 2 - 0x002A4C0A, // 008F ADD R10 K38 R10 - 0x582C0011, // 0090 LDCONST R11 K17 - 0x7C200600, // 0091 CALL R8 3 - 0x50200000, // 0092 LDBOOL R8 0 0 - 0xA8040001, // 0093 EXBLK 1 1 - 0x80041000, // 0094 RET 1 R8 - 0x90162407, // 0095 SETMBR R5 K18 R7 - 0x88200F13, // 0096 GETMBR R8 R7 K19 - 0x8C201114, // 0097 GETMET R8 R8 K20 - 0x88280B15, // 0098 GETMBR R10 R5 K21 - 0x502C0200, // 0099 LDBOOL R11 1 0 - 0x7C200600, // 009A CALL R8 3 - 0x74220011, // 009B JMPT R8 #00AE - 0xB8220200, // 009C GETNGBL R8 K1 - 0x8C201102, // 009D GETMET R8 R8 K2 - 0x60280008, // 009E GETGBL R10 G8 - 0x882C0B15, // 009F GETMBR R11 R5 K21 - 0x7C280200, // 00A0 CALL R10 1 - 0x002A500A, // 00A1 ADD R10 K40 R10 - 0x00281529, // 00A2 ADD R10 R10 K41 - 0x602C0008, // 00A3 GETGBL R11 G8 - 0x88300F13, // 00A4 GETMBR R12 R7 K19 - 0x8C301918, // 00A5 GETMET R12 R12 K24 - 0x7C300200, // 00A6 CALL R12 1 - 0x7C2C0200, // 00A7 CALL R11 1 - 0x0028140B, // 00A8 ADD R10 R10 R11 - 0x582C0011, // 00A9 LDCONST R11 K17 - 0x7C200600, // 00AA CALL R8 3 - 0x50200000, // 00AB LDBOOL R8 0 0 - 0xA8040001, // 00AC EXBLK 1 1 - 0x80041000, // 00AD RET 1 R8 - 0x8C200B2A, // 00AE GETMET R8 R5 K42 - 0x7C200200, // 00AF CALL R8 1 - 0x5C241000, // 00B0 MOVE R9 R8 - 0x74260002, // 00B1 JMPT R9 #00B5 - 0x50240000, // 00B2 LDBOOL R9 0 0 - 0xA8040001, // 00B3 EXBLK 1 1 - 0x80041200, // 00B4 RET 1 R9 - 0x88240B2C, // 00B5 GETMBR R9 R5 K44 - 0x0424132D, // 00B6 SUB R9 R9 K45 - 0x40261209, // 00B7 CONNECT R9 K9 R9 - 0x88280B2B, // 00B8 GETMBR R10 R5 K43 - 0x94241409, // 00B9 GETIDX R9 R10 R9 - 0x90165609, // 00BA SETMBR R5 K43 R9 - 0x88240B2B, // 00BB GETMBR R9 R5 K43 - 0x40241208, // 00BC CONNECT R9 R9 R8 - 0xB8260200, // 00BD GETNGBL R9 K1 - 0x8C241302, // 00BE GETMET R9 R9 K2 - 0x8C2C0916, // 00BF GETMET R11 R4 K22 - 0x5834002E, // 00C0 LDCONST R13 K46 - 0x88380B2C, // 00C1 GETMBR R14 R5 K44 - 0x883C0B2B, // 00C2 GETMBR R15 R5 K43 - 0x8C3C1F04, // 00C3 GETMET R15 R15 K4 - 0x7C3C0200, // 00C4 CALL R15 1 - 0x7C2C0800, // 00C5 CALL R11 4 - 0x58300011, // 00C6 LDCONST R12 K17 - 0x7C240600, // 00C7 CALL R9 3 - 0x8C240B19, // 00C8 GETMET R9 R5 K25 - 0x7C240200, // 00C9 CALL R9 1 - 0xB8260200, // 00CA GETNGBL R9 K1 - 0x8C241302, // 00CB GETMET R9 R9 K2 - 0x602C0008, // 00CC GETGBL R11 G8 - 0x88300B30, // 00CD GETMBR R12 R5 K48 - 0x7C2C0200, // 00CE CALL R11 1 - 0x002E5E0B, // 00CF ADD R11 K47 R11 - 0x002C1731, // 00D0 ADD R11 R11 K49 - 0x60300008, // 00D1 GETGBL R12 G8 - 0x88340B1C, // 00D2 GETMBR R13 R5 K28 - 0x7C300200, // 00D3 CALL R12 1 - 0x002C160C, // 00D4 ADD R11 R11 R12 - 0x002C1732, // 00D5 ADD R11 R11 K50 - 0x60300008, // 00D6 GETGBL R12 G8 - 0x88340B33, // 00D7 GETMBR R13 R5 K51 - 0x7C300200, // 00D8 CALL R12 1 - 0x002C160C, // 00D9 ADD R11 R11 R12 - 0x58300011, // 00DA LDCONST R12 K17 - 0x7C240600, // 00DB CALL R9 3 - 0x8824010B, // 00DC GETMBR R9 R0 K11 - 0x8C24131A, // 00DD GETMET R9 R9 K26 - 0x882C0B1B, // 00DE GETMBR R11 R5 K27 - 0x7C240400, // 00DF CALL R9 2 - 0x88240B30, // 00E0 GETMBR R9 R5 K48 - 0x1C281309, // 00E1 EQ R10 R9 K9 - 0x782A000C, // 00E2 JMPF R10 #00F0 - 0xB82A0200, // 00E3 GETNGBL R10 K1 - 0x8C281502, // 00E4 GETMET R10 R10 K2 - 0xB8320A00, // 00E5 GETNGBL R12 K5 - 0x8C301927, // 00E6 GETMET R12 R12 K39 - 0x5C380A00, // 00E7 MOVE R14 R5 - 0x7C300400, // 00E8 CALL R12 2 - 0x0032680C, // 00E9 ADD R12 K52 R12 - 0x58340011, // 00EA LDCONST R13 K17 - 0x7C280600, // 00EB CALL R10 3 - 0x50280200, // 00EC LDBOOL R10 1 0 - 0xA8040001, // 00ED EXBLK 1 1 - 0x80041400, // 00EE RET 1 R10 - 0x70020015, // 00EF JMP #0106 - 0x1C28132D, // 00F0 EQ R10 R9 K45 - 0x782A0008, // 00F1 JMPF R10 #00FB - 0x88280135, // 00F2 GETMBR R10 R0 K53 - 0x8C281522, // 00F3 GETMET R10 R10 K34 - 0x5C300A00, // 00F4 MOVE R12 R5 - 0x5C340400, // 00F5 MOVE R13 R2 - 0x5C380600, // 00F6 MOVE R14 R3 - 0x7C280800, // 00F7 CALL R10 4 - 0xA8040001, // 00F8 EXBLK 1 1 - 0x80041400, // 00F9 RET 1 R10 - 0x7002000A, // 00FA JMP #0106 - 0xB82A0200, // 00FB GETNGBL R10 K1 - 0x8C281502, // 00FC GETMET R10 R10 K2 - 0x60300008, // 00FD GETGBL R12 G8 - 0x5C341200, // 00FE MOVE R13 R9 - 0x7C300200, // 00FF CALL R12 1 - 0x00326C0C, // 0100 ADD R12 K54 R12 - 0x58340011, // 0101 LDCONST R13 K17 - 0x7C280600, // 0102 CALL R10 3 - 0x50280000, // 0103 LDBOOL R10 0 0 - 0xA8040001, // 0104 EXBLK 1 1 - 0x80041400, // 0105 RET 1 R10 - 0x501C0200, // 0106 LDBOOL R7 1 0 - 0xA8040001, // 0107 EXBLK 1 1 - 0x80040E00, // 0108 RET 1 R7 + 0x5C240400, // 000D MOVE R9 R2 + 0x5C280600, // 000E MOVE R10 R3 + 0x7C140A00, // 000F CALL R5 5 + 0x8C180B07, // 0010 GETMET R6 R5 K7 + 0x7C180200, // 0011 CALL R6 1 + 0x5C1C0C00, // 0012 MOVE R7 R6 + 0x741E0002, // 0013 JMPT R7 #0017 + 0x501C0000, // 0014 LDBOOL R7 0 0 + 0xA8040001, // 0015 EXBLK 1 1 + 0x80040E00, // 0016 RET 1 R7 + 0x881C0B08, // 0017 GETMBR R7 R5 K8 + 0x1C1C0F09, // 0018 EQ R7 R7 K9 + 0x781E0057, // 0019 JMPF R7 #0072 + 0x881C0B0A, // 001A GETMBR R7 R5 K10 + 0x1C1C0F09, // 001B EQ R7 R7 K9 + 0x781E0054, // 001C JMPF R7 #0072 + 0x881C010B, // 001D GETMBR R7 R0 K11 + 0x881C0F0C, // 001E GETMBR R7 R7 K12 + 0x8C1C0F0D, // 001F GETMET R7 R7 K13 + 0x88240B0E, // 0020 GETMBR R9 R5 K14 + 0x542A0059, // 0021 LDINT R10 90 + 0x7C1C0600, // 0022 CALL R7 3 + 0xB8220200, // 0023 GETNGBL R8 K1 + 0x8C201102, // 0024 GETMET R8 R8 K2 + 0x60280008, // 0025 GETGBL R10 G8 + 0x882C0B0E, // 0026 GETMBR R11 R5 K14 + 0x7C280200, // 0027 CALL R10 1 + 0x002A1E0A, // 0028 ADD R10 K15 R10 + 0x00281510, // 0029 ADD R10 R10 K16 + 0x602C0008, // 002A GETGBL R11 G8 + 0x88300F08, // 002B GETMBR R12 R7 K8 + 0x7C2C0200, // 002C CALL R11 1 + 0x0028140B, // 002D ADD R10 R10 R11 + 0x582C0011, // 002E LDCONST R11 K17 + 0x7C200600, // 002F CALL R8 3 + 0x90162407, // 0030 SETMBR R5 K18 R7 + 0x88200113, // 0031 GETMBR R8 R0 K19 + 0x8C201114, // 0032 GETMET R8 R8 K20 + 0x88280B15, // 0033 GETMBR R10 R5 K21 + 0x502C0000, // 0034 LDBOOL R11 0 0 + 0x7C200600, // 0035 CALL R8 3 + 0x7422000D, // 0036 JMPT R8 #0045 + 0xB8220200, // 0037 GETNGBL R8 K1 + 0x8C201102, // 0038 GETMET R8 R8 K2 + 0x8C280916, // 0039 GETMET R10 R4 K22 + 0x58300017, // 003A LDCONST R12 K23 + 0x88340B15, // 003B GETMBR R13 R5 K21 + 0x88380113, // 003C GETMBR R14 R0 K19 + 0x8C381D18, // 003D GETMET R14 R14 K24 + 0x7C380200, // 003E CALL R14 1 + 0x7C280800, // 003F CALL R10 4 + 0x582C0011, // 0040 LDCONST R11 K17 + 0x7C200600, // 0041 CALL R8 3 + 0x50200000, // 0042 LDBOOL R8 0 0 + 0xA8040001, // 0043 EXBLK 1 1 + 0x80041000, // 0044 RET 1 R8 + 0x8C200B19, // 0045 GETMET R8 R5 K25 + 0x7C200200, // 0046 CALL R8 1 + 0x74220002, // 0047 JMPT R8 #004B + 0x50200000, // 0048 LDBOOL R8 0 0 + 0xA8040001, // 0049 EXBLK 1 1 + 0x80041000, // 004A RET 1 R8 + 0x8820010B, // 004B GETMBR R8 R0 K11 + 0x8C20111A, // 004C GETMET R8 R8 K26 + 0x88280B1B, // 004D GETMBR R10 R5 K27 + 0x7C200400, // 004E CALL R8 2 + 0x88200B1C, // 004F GETMBR R8 R5 K28 + 0x5426000F, // 0050 LDINT R9 16 + 0x20201009, // 0051 NE R8 R8 R9 + 0x78220014, // 0052 JMPF R8 #0068 + 0xB8220A00, // 0053 GETNGBL R8 K5 + 0x8C20111D, // 0054 GETMET R8 R8 K29 + 0x88280B1C, // 0055 GETMBR R10 R5 K28 + 0x7C200400, // 0056 CALL R8 2 + 0x5C241000, // 0057 MOVE R9 R8 + 0x74260004, // 0058 JMPT R9 #005E + 0x8C240916, // 0059 GETMET R9 R4 K22 + 0x582C001E, // 005A LDCONST R11 K30 + 0x88300B1C, // 005B GETMBR R12 R5 K28 + 0x7C240600, // 005C CALL R9 3 + 0x5C201200, // 005D MOVE R8 R9 + 0xB8260200, // 005E GETNGBL R9 K1 + 0x8C241302, // 005F GETMET R9 R9 K2 + 0x8C2C0916, // 0060 GETMET R11 R4 K22 + 0x5834001F, // 0061 LDCONST R13 K31 + 0x5C381000, // 0062 MOVE R14 R8 + 0x5C3C0400, // 0063 MOVE R15 R2 + 0x5C400600, // 0064 MOVE R16 R3 + 0x7C2C0A00, // 0065 CALL R11 5 + 0x58300020, // 0066 LDCONST R12 K32 + 0x7C240600, // 0067 CALL R9 3 + 0x88200121, // 0068 GETMBR R8 R0 K33 + 0x8C201122, // 0069 GETMET R8 R8 K34 + 0x5C280A00, // 006A MOVE R10 R5 + 0x5C2C0400, // 006B MOVE R11 R2 + 0x5C300600, // 006C MOVE R12 R3 + 0x7C200800, // 006D CALL R8 4 + 0x50200200, // 006E LDBOOL R8 1 0 + 0xA8040001, // 006F EXBLK 1 1 + 0x80041000, // 0070 RET 1 R8 + 0x70020095, // 0071 JMP #0108 + 0xB81E0200, // 0072 GETNGBL R7 K1 + 0x8C1C0F02, // 0073 GETMET R7 R7 K2 + 0x8C240916, // 0074 GETMET R9 R4 K22 + 0x582C0023, // 0075 LDCONST R11 K35 + 0x88300B08, // 0076 GETMBR R12 R5 K8 + 0x88340B15, // 0077 GETMBR R13 R5 K21 + 0x7C240800, // 0078 CALL R9 4 + 0x58280011, // 0079 LDCONST R10 K17 + 0x7C1C0600, // 007A CALL R7 3 + 0x881C010B, // 007B GETMBR R7 R0 K11 + 0x881C0F0C, // 007C GETMBR R7 R7 K12 + 0x8C1C0F24, // 007D GETMET R7 R7 K36 + 0x88240B08, // 007E GETMBR R9 R5 K8 + 0x7C1C0400, // 007F CALL R7 2 + 0x4C200000, // 0080 LDNIL R8 + 0x1C200E08, // 0081 EQ R8 R7 R8 + 0x78220013, // 0082 JMPF R8 #0097 + 0xB8220200, // 0083 GETNGBL R8 K1 + 0x8C201102, // 0084 GETMET R8 R8 K2 + 0x60280008, // 0085 GETGBL R10 G8 + 0x882C0B08, // 0086 GETMBR R11 R5 K8 + 0x7C280200, // 0087 CALL R10 1 + 0x002A4A0A, // 0088 ADD R10 K37 R10 + 0x582C0011, // 0089 LDCONST R11 K17 + 0x7C200600, // 008A CALL R8 3 + 0xB8220200, // 008B GETNGBL R8 K1 + 0x8C201102, // 008C GETMET R8 R8 K2 + 0xB82A0A00, // 008D GETNGBL R10 K5 + 0x8C281527, // 008E GETMET R10 R10 K39 + 0x5C300A00, // 008F MOVE R12 R5 + 0x7C280400, // 0090 CALL R10 2 + 0x002A4C0A, // 0091 ADD R10 K38 R10 + 0x582C0011, // 0092 LDCONST R11 K17 + 0x7C200600, // 0093 CALL R8 3 + 0x50200000, // 0094 LDBOOL R8 0 0 + 0xA8040001, // 0095 EXBLK 1 1 + 0x80041000, // 0096 RET 1 R8 + 0x90162407, // 0097 SETMBR R5 K18 R7 + 0x88200F13, // 0098 GETMBR R8 R7 K19 + 0x8C201114, // 0099 GETMET R8 R8 K20 + 0x88280B15, // 009A GETMBR R10 R5 K21 + 0x502C0200, // 009B LDBOOL R11 1 0 + 0x7C200600, // 009C CALL R8 3 + 0x74220011, // 009D JMPT R8 #00B0 + 0xB8220200, // 009E GETNGBL R8 K1 + 0x8C201102, // 009F GETMET R8 R8 K2 + 0x60280008, // 00A0 GETGBL R10 G8 + 0x882C0B15, // 00A1 GETMBR R11 R5 K21 + 0x7C280200, // 00A2 CALL R10 1 + 0x002A500A, // 00A3 ADD R10 K40 R10 + 0x00281529, // 00A4 ADD R10 R10 K41 + 0x602C0008, // 00A5 GETGBL R11 G8 + 0x88300F13, // 00A6 GETMBR R12 R7 K19 + 0x8C301918, // 00A7 GETMET R12 R12 K24 + 0x7C300200, // 00A8 CALL R12 1 + 0x7C2C0200, // 00A9 CALL R11 1 + 0x0028140B, // 00AA ADD R10 R10 R11 + 0x582C0011, // 00AB LDCONST R11 K17 + 0x7C200600, // 00AC CALL R8 3 + 0x50200000, // 00AD LDBOOL R8 0 0 + 0xA8040001, // 00AE EXBLK 1 1 + 0x80041000, // 00AF RET 1 R8 + 0x8C200B2A, // 00B0 GETMET R8 R5 K42 + 0x7C200200, // 00B1 CALL R8 1 + 0x5C241000, // 00B2 MOVE R9 R8 + 0x74260002, // 00B3 JMPT R9 #00B7 + 0x50240000, // 00B4 LDBOOL R9 0 0 + 0xA8040001, // 00B5 EXBLK 1 1 + 0x80041200, // 00B6 RET 1 R9 + 0x88240B2C, // 00B7 GETMBR R9 R5 K44 + 0x0424132D, // 00B8 SUB R9 R9 K45 + 0x40261209, // 00B9 CONNECT R9 K9 R9 + 0x88280B2B, // 00BA GETMBR R10 R5 K43 + 0x94241409, // 00BB GETIDX R9 R10 R9 + 0x90165609, // 00BC SETMBR R5 K43 R9 + 0x88240B2B, // 00BD GETMBR R9 R5 K43 + 0x40241208, // 00BE CONNECT R9 R9 R8 + 0xB8260200, // 00BF GETNGBL R9 K1 + 0x8C241302, // 00C0 GETMET R9 R9 K2 + 0x8C2C0916, // 00C1 GETMET R11 R4 K22 + 0x5834002E, // 00C2 LDCONST R13 K46 + 0x88380B2C, // 00C3 GETMBR R14 R5 K44 + 0x883C0B2B, // 00C4 GETMBR R15 R5 K43 + 0x8C3C1F04, // 00C5 GETMET R15 R15 K4 + 0x7C3C0200, // 00C6 CALL R15 1 + 0x7C2C0800, // 00C7 CALL R11 4 + 0x58300011, // 00C8 LDCONST R12 K17 + 0x7C240600, // 00C9 CALL R9 3 + 0x8C240B19, // 00CA GETMET R9 R5 K25 + 0x7C240200, // 00CB CALL R9 1 + 0xB8260200, // 00CC GETNGBL R9 K1 + 0x8C241302, // 00CD GETMET R9 R9 K2 + 0x602C0008, // 00CE GETGBL R11 G8 + 0x88300B30, // 00CF GETMBR R12 R5 K48 + 0x7C2C0200, // 00D0 CALL R11 1 + 0x002E5E0B, // 00D1 ADD R11 K47 R11 + 0x002C1731, // 00D2 ADD R11 R11 K49 + 0x60300008, // 00D3 GETGBL R12 G8 + 0x88340B1C, // 00D4 GETMBR R13 R5 K28 + 0x7C300200, // 00D5 CALL R12 1 + 0x002C160C, // 00D6 ADD R11 R11 R12 + 0x002C1732, // 00D7 ADD R11 R11 K50 + 0x60300008, // 00D8 GETGBL R12 G8 + 0x88340B33, // 00D9 GETMBR R13 R5 K51 + 0x7C300200, // 00DA CALL R12 1 + 0x002C160C, // 00DB ADD R11 R11 R12 + 0x58300011, // 00DC LDCONST R12 K17 + 0x7C240600, // 00DD CALL R9 3 + 0x8824010B, // 00DE GETMBR R9 R0 K11 + 0x8C24131A, // 00DF GETMET R9 R9 K26 + 0x882C0B1B, // 00E0 GETMBR R11 R5 K27 + 0x7C240400, // 00E1 CALL R9 2 + 0x88240B30, // 00E2 GETMBR R9 R5 K48 + 0x1C281309, // 00E3 EQ R10 R9 K9 + 0x782A000C, // 00E4 JMPF R10 #00F2 + 0xB82A0200, // 00E5 GETNGBL R10 K1 + 0x8C281502, // 00E6 GETMET R10 R10 K2 + 0xB8320A00, // 00E7 GETNGBL R12 K5 + 0x8C301927, // 00E8 GETMET R12 R12 K39 + 0x5C380A00, // 00E9 MOVE R14 R5 + 0x7C300400, // 00EA CALL R12 2 + 0x0032680C, // 00EB ADD R12 K52 R12 + 0x58340011, // 00EC LDCONST R13 K17 + 0x7C280600, // 00ED CALL R10 3 + 0x50280200, // 00EE LDBOOL R10 1 0 + 0xA8040001, // 00EF EXBLK 1 1 + 0x80041400, // 00F0 RET 1 R10 + 0x70020015, // 00F1 JMP #0108 + 0x1C28132D, // 00F2 EQ R10 R9 K45 + 0x782A0008, // 00F3 JMPF R10 #00FD + 0x88280135, // 00F4 GETMBR R10 R0 K53 + 0x8C281522, // 00F5 GETMET R10 R10 K34 + 0x5C300A00, // 00F6 MOVE R12 R5 + 0x5C340400, // 00F7 MOVE R13 R2 + 0x5C380600, // 00F8 MOVE R14 R3 + 0x7C280800, // 00F9 CALL R10 4 + 0xA8040001, // 00FA EXBLK 1 1 + 0x80041400, // 00FB RET 1 R10 + 0x7002000A, // 00FC JMP #0108 + 0xB82A0200, // 00FD GETNGBL R10 K1 + 0x8C281502, // 00FE GETMET R10 R10 K2 + 0x60300008, // 00FF GETGBL R12 G8 + 0x5C341200, // 0100 MOVE R13 R9 + 0x7C300200, // 0101 CALL R12 1 + 0x00326C0C, // 0102 ADD R12 K54 R12 + 0x58340011, // 0103 LDCONST R13 K17 + 0x7C280600, // 0104 CALL R10 3 + 0x50280000, // 0105 LDBOOL R10 0 0 + 0xA8040001, // 0106 EXBLK 1 1 + 0x80041400, // 0107 RET 1 R10 + 0x501C0200, // 0108 LDBOOL R7 1 0 0xA8040001, // 0109 EXBLK 1 1 - 0x70020014, // 010A JMP #0120 - 0xAC140002, // 010B CATCH R5 0 2 - 0x70020011, // 010C JMP #011F - 0xB81E0200, // 010D GETNGBL R7 K1 - 0x8C1C0F02, // 010E GETMET R7 R7 K2 - 0x60240008, // 010F GETGBL R9 G8 - 0x5C280A00, // 0110 MOVE R10 R5 - 0x7C240200, // 0111 CALL R9 1 - 0x00266E09, // 0112 ADD R9 K55 R9 - 0x00241338, // 0113 ADD R9 R9 K56 - 0x60280008, // 0114 GETGBL R10 G8 - 0x5C2C0C00, // 0115 MOVE R11 R6 - 0x7C280200, // 0116 CALL R10 1 - 0x0024120A, // 0117 ADD R9 R9 R10 - 0x7C1C0400, // 0118 CALL R7 2 - 0xA41E7200, // 0119 IMPORT R7 K57 - 0x8C200F3A, // 011A GETMET R8 R7 K58 - 0x7C200200, // 011B CALL R8 1 - 0x50200000, // 011C LDBOOL R8 0 0 - 0x80041000, // 011D RET 1 R8 - 0x70020000, // 011E JMP #0120 - 0xB0080000, // 011F RAISE 2 R0 R0 - 0x80000000, // 0120 RET 0 + 0x80040E00, // 010A RET 1 R7 + 0xA8040001, // 010B EXBLK 1 1 + 0x70020014, // 010C JMP #0122 + 0xAC140002, // 010D CATCH R5 0 2 + 0x70020011, // 010E JMP #0121 + 0xB81E0200, // 010F GETNGBL R7 K1 + 0x8C1C0F02, // 0110 GETMET R7 R7 K2 + 0x60240008, // 0111 GETGBL R9 G8 + 0x5C280A00, // 0112 MOVE R10 R5 + 0x7C240200, // 0113 CALL R9 1 + 0x00266E09, // 0114 ADD R9 K55 R9 + 0x00241338, // 0115 ADD R9 R9 K56 + 0x60280008, // 0116 GETGBL R10 G8 + 0x5C2C0C00, // 0117 MOVE R11 R6 + 0x7C280200, // 0118 CALL R10 1 + 0x0024120A, // 0119 ADD R9 R9 R10 + 0x7C1C0400, // 011A CALL R7 2 + 0xA41E7200, // 011B IMPORT R7 K57 + 0x8C200F3A, // 011C GETMET R8 R7 K58 + 0x7C200200, // 011D CALL R8 1 + 0x50200000, // 011E LDBOOL R8 0 0 + 0x80041000, // 011F RET 1 R8 + 0x70020000, // 0120 JMP #0122 + 0xB0080000, // 0121 RAISE 2 R0 R0 + 0x80000000, // 0122 RET 0 }) ) ); @@ -474,7 +476,7 @@ be_local_closure(Matter_MessageHandler_add_session, /* name */ ********************************************************************/ be_local_closure(Matter_MessageHandler_init, /* name */ be_nested_proto( - 5, /* nstack */ + 6, /* nstack */ 2, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -494,7 +496,7 @@ be_local_closure(Matter_MessageHandler_init, /* name */ }), be_str_weak(init), &be_const_str_solidified, - ( &(const binstruction[16]) { /* code */ + ( &(const binstruction[17]) { /* code */ 0x90020001, // 0000 SETMBR R0 K0 R1 0xB80A0400, // 0001 GETNGBL R2 K2 0x8C080503, // 0002 GETMET R2 R2 K3 @@ -504,13 +506,14 @@ be_local_closure(Matter_MessageHandler_init, /* name */ 0xB80A0400, // 0006 GETNGBL R2 K2 0x8C080505, // 0007 GETMET R2 R2 K5 0x5C100000, // 0008 MOVE R4 R0 - 0x7C080400, // 0009 CALL R2 2 - 0x90020802, // 000A SETMBR R0 K4 R2 - 0xB80A0400, // 000B GETNGBL R2 K2 - 0x8C080507, // 000C GETMET R2 R2 K7 - 0x7C080200, // 000D CALL R2 1 - 0x90020C02, // 000E SETMBR R0 K6 R2 - 0x80000000, // 000F RET 0 + 0x5C140200, // 0009 MOVE R5 R1 + 0x7C080600, // 000A CALL R2 3 + 0x90020802, // 000B SETMBR R0 K4 R2 + 0xB80A0400, // 000C GETNGBL R2 K2 + 0x8C080507, // 000D GETMET R2 R2 K7 + 0x7C080200, // 000E CALL R2 1 + 0x90020C02, // 000F SETMBR R0 K6 R2 + 0x80000000, // 0010 RET 0 }) ) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin.h index 5ba1f7814..8091439a8 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin.h @@ -7,26 +7,180 @@ extern const bclass be_class_Matter_Plugin; /******************************************************************** -** Solidified function: get_endpoints +** Solidified function: read_event ********************************************************************/ -be_local_closure(Matter_Plugin_get_endpoints, /* name */ +be_local_closure(Matter_Plugin_read_event, /* name */ be_nested_proto( - 2, /* nstack */ - 1, /* argc */ + 6, /* nstack */ + 5, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + be_str_weak(read_event), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x4C140000, // 0000 LDNIL R5 + 0x80040A00, // 0001 RET 1 R5 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_Plugin_init, /* name */ + be_nested_proto( + 3, /* nstack */ + 2, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(endpoints), + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(device), + /* K1 */ be_nested_str_weak(endpoints), + /* K2 */ be_nested_str_weak(EMPTY_LIST), + /* K3 */ be_nested_str_weak(clusters), }), - be_str_weak(get_endpoints), + be_str_weak(init), &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 + ( &(const binstruction[ 6]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x88080102, // 0001 GETMBR R2 R0 K2 + 0x90020202, // 0002 SETMBR R0 K1 R2 + 0x88080102, // 0003 GETMBR R2 R0 K2 + 0x90020602, // 0004 SETMBR R0 K3 R2 + 0x80000000, // 0005 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: has +********************************************************************/ +be_local_closure(Matter_Plugin_has, /* name */ + be_nested_proto( + 6, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(clusters), + /* K1 */ be_nested_str_weak(contains), + /* K2 */ be_nested_str_weak(endpoints), + /* K3 */ be_nested_str_weak(find), + }), + be_str_weak(has), + &be_const_str_solidified, + ( &(const binstruction[15]) { /* code */ + 0x880C0100, // 0000 GETMBR R3 R0 K0 + 0x8C0C0701, // 0001 GETMET R3 R3 K1 + 0x5C140200, // 0002 MOVE R5 R1 + 0x7C0C0400, // 0003 CALL R3 2 + 0x780E0006, // 0004 JMPF R3 #000C + 0x880C0102, // 0005 GETMBR R3 R0 K2 + 0x8C0C0703, // 0006 GETMET R3 R3 K3 + 0x5C140400, // 0007 MOVE R5 R2 + 0x7C0C0400, // 0008 CALL R3 2 + 0x4C100000, // 0009 LDNIL R4 + 0x200C0604, // 000A NE R3 R3 R4 + 0x740E0000, // 000B JMPT R3 #000D + 0x500C0001, // 000C LDBOOL R3 0 1 + 0x500C0200, // 000D LDBOOL R3 1 0 + 0x80040600, // 000E RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_attribute_list +********************************************************************/ +be_local_closure(Matter_Plugin_get_attribute_list, /* name */ + be_nested_proto( + 7, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(clusters), + /* K1 */ be_nested_str_weak(find), + /* K2 */ be_nested_str_weak(EMPTY_LIST), + }), + be_str_weak(get_attribute_list), + &be_const_str_solidified, + ( &(const binstruction[ 6]) { /* code */ + 0x880C0100, // 0000 GETMBR R3 R0 K0 + 0x8C0C0701, // 0001 GETMET R3 R3 K1 + 0x5C140400, // 0002 MOVE R5 R2 + 0x88180102, // 0003 GETMBR R6 R0 K2 + 0x7C0C0600, // 0004 CALL R3 3 + 0x80040600, // 0005 RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_cluster_list +********************************************************************/ +be_local_closure(Matter_Plugin_get_cluster_list, /* name */ + be_nested_proto( + 8, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(clusters), + /* K1 */ be_nested_str_weak(keys), + /* K2 */ be_nested_str_weak(push), + /* K3 */ be_nested_str_weak(stop_iteration), + }), + be_str_weak(get_cluster_list), + &be_const_str_solidified, + ( &(const binstruction[18]) { /* code */ + 0x60080012, // 0000 GETGBL R2 G18 + 0x7C080000, // 0001 CALL R2 0 + 0x600C0010, // 0002 GETGBL R3 G16 + 0x88100100, // 0003 GETMBR R4 R0 K0 + 0x8C100901, // 0004 GETMET R4 R4 K1 + 0x7C100200, // 0005 CALL R4 1 + 0x7C0C0200, // 0006 CALL R3 1 + 0xA8020005, // 0007 EXBLK 0 #000E + 0x5C100600, // 0008 MOVE R4 R3 + 0x7C100000, // 0009 CALL R4 0 + 0x8C140502, // 000A GETMET R5 R2 K2 + 0x5C1C0800, // 000B MOVE R7 R4 + 0x7C140400, // 000C CALL R5 2 + 0x7001FFF9, // 000D JMP #0008 + 0x580C0003, // 000E LDCONST R3 K3 + 0xAC0C0200, // 000F CATCH R3 1 0 + 0xB0080000, // 0010 RAISE 2 R0 R0 + 0x80040400, // 0011 RET 1 R2 }) ) ); @@ -58,44 +212,13 @@ be_local_closure(Matter_Plugin_invoke_request, /* name */ /*******************************************************************/ -/******************************************************************** -** Solidified function: init -********************************************************************/ -be_local_closure(Matter_Plugin_init, /* name */ - be_nested_proto( - 3, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(device), - /* K1 */ be_nested_str_weak(endpoints), - }), - be_str_weak(init), - &be_const_str_solidified, - ( &(const binstruction[ 5]) { /* code */ - 0x90020001, // 0000 SETMBR R0 K0 R1 - 0x60080012, // 0001 GETGBL R2 G18 - 0x7C080000, // 0002 CALL R2 0 - 0x90020202, // 0003 SETMBR R0 K1 R2 - 0x80000000, // 0004 RET 0 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified function: read_attribute ********************************************************************/ be_local_closure(Matter_Plugin_read_attribute, /* name */ be_nested_proto( - 6, /* nstack */ - 5, /* argc */ + 4, /* nstack */ + 3, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ @@ -106,58 +229,8 @@ be_local_closure(Matter_Plugin_read_attribute, /* name */ be_str_weak(read_attribute), &be_const_str_solidified, ( &(const binstruction[ 2]) { /* code */ - 0x4C140000, // 0000 LDNIL R5 - 0x80040A00, // 0001 RET 1 R5 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: read_event -********************************************************************/ -be_local_closure(Matter_Plugin_read_event, /* name */ - be_nested_proto( - 6, /* nstack */ - 5, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 0, /* has constants */ - NULL, /* no const */ - be_str_weak(read_event), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x4C140000, // 0000 LDNIL R5 - 0x80040A00, // 0001 RET 1 R5 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: subscribe_attribute -********************************************************************/ -be_local_closure(Matter_Plugin_subscribe_attribute, /* name */ - be_nested_proto( - 6, /* nstack */ - 5, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 0, /* has constants */ - NULL, /* no const */ - be_str_weak(subscribe_attribute), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x4C140000, // 0000 LDNIL R5 - 0x80040A00, // 0001 RET 1 R5 + 0x4C0C0000, // 0000 LDNIL R3 + 0x80040600, // 0001 RET 1 R3 }) ) ); @@ -189,6 +262,60 @@ be_local_closure(Matter_Plugin_subscribe_event, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: get_cluster_map +********************************************************************/ +be_local_closure(Matter_Plugin_get_cluster_map, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(clusters), + }), + be_str_weak(get_cluster_map), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_endpoints +********************************************************************/ +be_local_closure(Matter_Plugin_get_endpoints, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(endpoints), + }), + be_str_weak(get_endpoints), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: write_attribute ********************************************************************/ @@ -239,25 +366,63 @@ be_local_closure(Matter_Plugin_timed_request, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: subscribe_attribute +********************************************************************/ +be_local_closure(Matter_Plugin_subscribe_attribute, /* name */ + be_nested_proto( + 6, /* nstack */ + 5, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + be_str_weak(subscribe_attribute), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x4C140000, // 0000 LDNIL R5 + 0x80040A00, // 0001 RET 1 R5 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified class: Matter_Plugin ********************************************************************/ be_local_class(Matter_Plugin, - 2, + 3, NULL, - be_nested_map(11, + be_nested_map(18, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(get_endpoints, -1), be_const_closure(Matter_Plugin_get_endpoints_closure) }, - { be_const_key_weak(endpoints, 7), be_const_var(1) }, - { be_const_key_weak(timed_request, 8), be_const_closure(Matter_Plugin_timed_request_closure) }, - { be_const_key_weak(read_attribute, -1), be_const_closure(Matter_Plugin_read_attribute_closure) }, { be_const_key_weak(read_event, -1), be_const_closure(Matter_Plugin_read_event_closure) }, + { be_const_key_weak(get_cluster_list, -1), be_const_closure(Matter_Plugin_get_cluster_list_closure) }, + { be_const_key_weak(endpoints, 1), be_const_var(1) }, + { be_const_key_weak(get_attribute_list, 9), be_const_closure(Matter_Plugin_get_attribute_list_closure) }, { be_const_key_weak(device, -1), be_const_var(0) }, - { be_const_key_weak(subscribe_attribute, -1), be_const_closure(Matter_Plugin_subscribe_attribute_closure) }, - { be_const_key_weak(write_attribute, -1), be_const_closure(Matter_Plugin_write_attribute_closure) }, + { be_const_key_weak(invoke_request, -1), be_const_closure(Matter_Plugin_invoke_request_closure) }, + { be_const_key_weak(read_attribute, -1), be_const_closure(Matter_Plugin_read_attribute_closure) }, + { be_const_key_weak(has, 13), be_const_closure(Matter_Plugin_has_closure) }, { be_const_key_weak(subscribe_event, -1), be_const_closure(Matter_Plugin_subscribe_event_closure) }, - { be_const_key_weak(init, 2), be_const_closure(Matter_Plugin_init_closure) }, - { be_const_key_weak(invoke_request, 1), be_const_closure(Matter_Plugin_invoke_request_closure) }, + { be_const_key_weak(get_cluster_map, -1), be_const_closure(Matter_Plugin_get_cluster_map_closure) }, + { be_const_key_weak(clusters, -1), be_const_var(2) }, + { be_const_key_weak(EMPTY_MAP, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + be_const_map( * be_nested_map(0, + ( (struct bmapnode*) &(const bmapnode[]) { + })) ) } )) }, + { be_const_key_weak(get_endpoints, -1), be_const_closure(Matter_Plugin_get_endpoints_closure) }, + { be_const_key_weak(write_attribute, 2), be_const_closure(Matter_Plugin_write_attribute_closure) }, + { be_const_key_weak(timed_request, -1), be_const_closure(Matter_Plugin_timed_request_closure) }, + { be_const_key_weak(init, 4), be_const_closure(Matter_Plugin_init_closure) }, + { be_const_key_weak(subscribe_attribute, -1), be_const_closure(Matter_Plugin_subscribe_attribute_closure) }, + { be_const_key_weak(EMPTY_LIST, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(0, + ( (struct bvalue*) &(const bvalue[]) { + })) ) } )) }, })), be_str_weak(Matter_Plugin) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Relay.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Relay.h index f03a26eb5..8a68d6822 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Relay.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Relay.h @@ -11,19 +11,102 @@ extern const bclass be_class_Matter_Plugin_Relay; ********************************************************************/ be_local_closure(Matter_Plugin_Relay_read_attribute, /* name */ be_nested_proto( - 5, /* nstack */ - 5, /* argc */ + 15, /* nstack */ + 3, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ - 0, /* has constants */ - NULL, /* no const */ + 1, /* has constants */ + ( &(const bvalue[17]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(TLV), + /* K3 */ be_nested_str_weak(cluster), + /* K4 */ be_nested_str_weak(attribute), + /* K5 */ be_const_int(0), + /* K6 */ be_nested_str_weak(Matter_TLV_array), + /* K7 */ be_nested_str_weak(add_struct), + /* K8 */ be_nested_str_weak(add_TLV), + /* K9 */ be_nested_str_weak(U2), + /* K10 */ be_nested_str_weak(TYPES), + /* K11 */ be_const_int(1), + /* K12 */ be_nested_str_weak(get_cluster_list), + /* K13 */ be_nested_str_weak(U4), + /* K14 */ be_nested_str_weak(stop_iteration), + /* K15 */ be_const_int(2), + /* K16 */ be_const_int(3), + }), be_str_weak(read_attribute), &be_const_str_solidified, - ( &(const binstruction[ 1]) { /* code */ - 0x80000000, // 0000 RET 0 + ( &(const binstruction[66]) { /* code */ + 0xA40E0000, // 0000 IMPORT R3 K0 + 0xB8120200, // 0001 GETNGBL R4 K1 + 0x88100902, // 0002 GETMBR R4 R4 K2 + 0x88140503, // 0003 GETMBR R5 R2 K3 + 0x88180504, // 0004 GETMBR R6 R2 K4 + 0x541E001C, // 0005 LDINT R7 29 + 0x1C1C0A07, // 0006 EQ R7 R5 R7 + 0x781E0038, // 0007 JMPF R7 #0041 + 0x1C1C0D05, // 0008 EQ R7 R6 K5 + 0x781E0010, // 0009 JMPF R7 #001B + 0x8C1C0906, // 000A GETMET R7 R4 K6 + 0x7C1C0200, // 000B CALL R7 1 + 0x8C200F07, // 000C GETMET R8 R7 K7 + 0x7C200200, // 000D CALL R8 1 + 0x8C241108, // 000E GETMET R9 R8 K8 + 0x582C0005, // 000F LDCONST R11 K5 + 0x88300909, // 0010 GETMBR R12 R4 K9 + 0x8834010A, // 0011 GETMBR R13 R0 K10 + 0x94341B05, // 0012 GETIDX R13 R13 K5 + 0x7C240800, // 0013 CALL R9 4 + 0x8C241108, // 0014 GETMET R9 R8 K8 + 0x582C000B, // 0015 LDCONST R11 K11 + 0x88300909, // 0016 GETMBR R12 R4 K9 + 0x5834000B, // 0017 LDCONST R13 K11 + 0x7C240800, // 0018 CALL R9 4 + 0x80040E00, // 0019 RET 1 R7 + 0x70020025, // 001A JMP #0041 + 0x1C1C0D0B, // 001B EQ R7 R6 K11 + 0x781E0013, // 001C JMPF R7 #0031 + 0x8C1C0906, // 001D GETMET R7 R4 K6 + 0x7C1C0200, // 001E CALL R7 1 + 0x60200010, // 001F GETGBL R8 G16 + 0x8C24010C, // 0020 GETMET R9 R0 K12 + 0x7C240200, // 0021 CALL R9 1 + 0x7C200200, // 0022 CALL R8 1 + 0xA8020007, // 0023 EXBLK 0 #002C + 0x5C241000, // 0024 MOVE R9 R8 + 0x7C240000, // 0025 CALL R9 0 + 0x8C280F08, // 0026 GETMET R10 R7 K8 + 0x4C300000, // 0027 LDNIL R12 + 0x8834090D, // 0028 GETMBR R13 R4 K13 + 0x5C381200, // 0029 MOVE R14 R9 + 0x7C280800, // 002A CALL R10 4 + 0x7001FFF7, // 002B JMP #0024 + 0x5820000E, // 002C LDCONST R8 K14 + 0xAC200200, // 002D CATCH R8 1 0 + 0xB0080000, // 002E RAISE 2 R0 R0 + 0x80040E00, // 002F RET 1 R7 + 0x7002000F, // 0030 JMP #0041 + 0x1C1C0D0F, // 0031 EQ R7 R6 K15 + 0x781E0008, // 0032 JMPF R7 #003C + 0x8C1C0906, // 0033 GETMET R7 R4 K6 + 0x7C1C0200, // 0034 CALL R7 1 + 0x8C200F08, // 0035 GETMET R8 R7 K8 + 0x4C280000, // 0036 LDNIL R10 + 0x882C0909, // 0037 GETMBR R11 R4 K9 + 0x54320005, // 0038 LDINT R12 6 + 0x7C200800, // 0039 CALL R8 4 + 0x80040E00, // 003A RET 1 R7 + 0x70020004, // 003B JMP #0041 + 0x1C1C0D10, // 003C EQ R7 R6 K16 + 0x781E0002, // 003D JMPF R7 #0041 + 0x8C1C0906, // 003E GETMET R7 R4 K6 + 0x7C1C0200, // 003F CALL R7 1 + 0x80040E00, // 0040 RET 1 R7 + 0x80000000, // 0041 RET 0 }) ) ); @@ -43,10 +126,12 @@ be_local_closure(Matter_Plugin_Relay_init, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ + ( &(const bvalue[ 5]) { /* constants */ /* K0 */ be_nested_str_weak(init), /* K1 */ be_nested_str_weak(endpoints), - /* K2 */ be_const_int(1), + /* K2 */ be_nested_str_weak(ENDPOINTS), + /* K3 */ be_nested_str_weak(clusters), + /* K4 */ be_nested_str_weak(CLUSTERS), }), be_str_weak(init), &be_const_str_solidified, @@ -57,10 +142,10 @@ be_local_closure(Matter_Plugin_Relay_init, /* name */ 0x8C080500, // 0003 GETMET R2 R2 K0 0x5C100200, // 0004 MOVE R4 R1 0x7C080400, // 0005 CALL R2 2 - 0x60080012, // 0006 GETGBL R2 G18 - 0x7C080000, // 0007 CALL R2 0 - 0x400C0502, // 0008 CONNECT R3 R2 K2 - 0x90020202, // 0009 SETMBR R0 K1 R2 + 0x88080102, // 0006 GETMBR R2 R0 K2 + 0x90020202, // 0007 SETMBR R0 K1 R2 + 0x88080104, // 0008 GETMBR R2 R0 K4 + 0x90020602, // 0009 SETMBR R0 K3 R2 0x80000000, // 000A RET 0 }) ) @@ -99,10 +184,53 @@ extern const bclass be_class_Matter_Plugin; be_local_class(Matter_Plugin_Relay, 0, &be_class_Matter_Plugin, - be_nested_map(3, + be_nested_map(6, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(read_attribute, 1), be_const_closure(Matter_Plugin_Relay_read_attribute_closure) }, + { be_const_key_weak(read_attribute, -1), be_const_closure(Matter_Plugin_Relay_read_attribute_closure) }, + { be_const_key_weak(ENDPOINTS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(1, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(1), + })) ) } )) }, + { be_const_key_weak(TYPES, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(1, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(256), + })) ) } )) }, { be_const_key_weak(init, -1), be_const_closure(Matter_Plugin_Relay_init_closure) }, + { be_const_key_weak(CLUSTERS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + be_const_map( * be_nested_map(6, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_int(6, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(1, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + })) ) } )) }, + { be_const_key_int(29, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(4, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + })) ) } )) }, + { be_const_key_int(8, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(0, + ( (struct bvalue*) &(const bvalue[]) { + })) ) } )) }, + { be_const_key_int(3, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(0, + ( (struct bvalue*) &(const bvalue[]) { + })) ) } )) }, + { be_const_key_int(4, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(0, + ( (struct bvalue*) &(const bvalue[]) { + })) ) } )) }, + { be_const_key_int(5, 1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(0, + ( (struct bvalue*) &(const bvalue[]) { + })) ) } )) }, + })) ) } )) }, { be_const_key_weak(invoke_request, -1), be_const_closure(Matter_Plugin_Relay_invoke_request_closure) }, })), be_str_weak(Matter_Plugin_Relay) diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_core.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_core.h index de1617ce8..10592a17a 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_core.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_core.h @@ -6,793 +6,6 @@ extern const bclass be_class_Matter_Plugin_core; -/******************************************************************** -** Solidified function: read_attribute -********************************************************************/ -be_local_closure(Matter_Plugin_core_read_attribute, /* name */ - be_nested_proto( - 24, /* nstack */ - 5, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[76]) { /* constants */ - /* K0 */ be_nested_str_weak(string), - /* K1 */ be_nested_str_weak(matter), - /* K2 */ be_nested_str_weak(TLV), - /* K3 */ be_const_int(0), - /* K4 */ be_nested_str_weak(create_TLV), - /* K5 */ be_nested_str_weak(U8), - /* K6 */ be_nested_str_weak(session), - /* K7 */ be_nested_str_weak(breadcrumb), - /* K8 */ be_const_int(1), - /* K9 */ be_nested_str_weak(Matter_TLV_struct), - /* K10 */ be_nested_str_weak(add_TLV), - /* K11 */ be_nested_str_weak(U2), - /* K12 */ be_const_int(2), - /* K13 */ be_nested_str_weak(U1), - /* K14 */ be_const_int(3), - /* K15 */ be_nested_str_weak(BOOL), - /* K16 */ be_nested_str_weak(Matter_TLV_array), - /* K17 */ be_nested_str_weak(tasmota), - /* K18 */ be_nested_str_weak(eth), - /* K19 */ be_nested_str_weak(up), - /* K20 */ be_nested_str_weak(add_struct), - /* K21 */ be_nested_str_weak(UTF1), - /* K22 */ be_nested_str_weak(ethernet), - /* K23 */ be_nested_str_weak(NULL), - /* K24 */ be_nested_str_weak(fromhex), - /* K25 */ be_nested_str_weak(replace), - /* K26 */ be_nested_str_weak(find), - /* K27 */ be_nested_str_weak(mac), - /* K28 */ be_nested_str_weak(), - /* K29 */ be_nested_str_weak(_X3A), - /* K30 */ be_nested_str_weak(B1), - /* K31 */ be_nested_str_weak(add_array), - /* K32 */ be_nested_str_weak(get_ip_bytes), - /* K33 */ be_nested_str_weak(ip), - /* K34 */ be_nested_str_weak(ip6local), - /* K35 */ be_nested_str_weak(ip6), - /* K36 */ be_nested_str_weak(wifi), - /* K37 */ be_nested_str_weak(cmd), - /* K38 */ be_nested_str_weak(Status_X201), - /* K39 */ be_nested_str_weak(StatusPRM), - /* K40 */ be_nested_str_weak(BootCount), - /* K41 */ be_nested_str_weak(U4), - /* K42 */ be_nested_str_weak(Status_X2011), - /* K43 */ be_nested_str_weak(StatusSTS), - /* K44 */ be_nested_str_weak(UptimeSec), - /* K45 */ be_nested_str_weak(int64), - /* K46 */ be_nested_str_weak(rtc), - /* K47 */ be_nested_str_weak(utc), - /* K48 */ be_const_int(1000000), - /* K49 */ be_nested_str_weak(local), - /* K50 */ be_nested_str_weak(device), - /* K51 */ be_nested_str_weak(sessions), - /* K52 */ be_nested_str_weak(sessions_active), - /* K53 */ be_nested_str_weak(B2), - /* K54 */ be_nested_str_weak(noc), - /* K55 */ be_nested_str_weak(icac), - /* K56 */ be_nested_str_weak(stop_iteration), - /* K57 */ be_nested_str_weak(parse), - /* K58 */ be_nested_str_weak(get_ca), - /* K59 */ be_nested_str_weak(findsubval), - /* K60 */ be_nested_str_weak(admin_vendor), - /* K61 */ be_nested_str_weak(fabric), - /* K62 */ be_nested_str_weak(deviceid), - /* K63 */ be_nested_str_weak(fabric_label), - /* K64 */ be_nested_str_weak(Tasmota), - /* K65 */ be_nested_str_weak(vendorid), - /* K66 */ be_nested_str_weak(DeviceName), - /* K67 */ be_nested_str_weak(FriendlyName), - /* K68 */ be_nested_str_weak(FriendlyName1), - /* K69 */ be_nested_str_weak(XX), - /* K70 */ be_nested_str_weak(Status_X202), - /* K71 */ be_nested_str_weak(StatusFWR), - /* K72 */ be_nested_str_weak(Hardware), - /* K73 */ be_nested_str_weak(Version), - /* K74 */ be_nested_str_weak(locale), - /* K75 */ be_nested_str_weak(Matter_TLV_list), - }), - be_str_weak(read_attribute), - &be_const_str_solidified, - ( &(const binstruction[649]) { /* code */ - 0xA4160000, // 0000 IMPORT R5 K0 - 0xB81A0200, // 0001 GETNGBL R6 K1 - 0x88180D02, // 0002 GETMBR R6 R6 K2 - 0x541E002F, // 0003 LDINT R7 48 - 0x1C1C0607, // 0004 EQ R7 R3 R7 - 0x781E0031, // 0005 JMPF R7 #0038 - 0x1C1C0903, // 0006 EQ R7 R4 K3 - 0x781E0006, // 0007 JMPF R7 #000F - 0x8C1C0D04, // 0008 GETMET R7 R6 K4 - 0x88240D05, // 0009 GETMBR R9 R6 K5 - 0x88280306, // 000A GETMBR R10 R1 K6 - 0x88281507, // 000B GETMBR R10 R10 K7 - 0x7C1C0600, // 000C CALL R7 3 - 0x80040E00, // 000D RET 1 R7 - 0x70020027, // 000E JMP #0037 - 0x1C1C0908, // 000F EQ R7 R4 K8 - 0x781E000D, // 0010 JMPF R7 #001F - 0x8C1C0D09, // 0011 GETMET R7 R6 K9 - 0x7C1C0200, // 0012 CALL R7 1 - 0x8C200F0A, // 0013 GETMET R8 R7 K10 - 0x58280003, // 0014 LDCONST R10 K3 - 0x882C0D0B, // 0015 GETMBR R11 R6 K11 - 0x5432003B, // 0016 LDINT R12 60 - 0x7C200800, // 0017 CALL R8 4 - 0x8C200F0A, // 0018 GETMET R8 R7 K10 - 0x58280008, // 0019 LDCONST R10 K8 - 0x882C0D0B, // 001A GETMBR R11 R6 K11 - 0x54320383, // 001B LDINT R12 900 - 0x7C200800, // 001C CALL R8 4 - 0x80040E00, // 001D RET 1 R7 - 0x70020017, // 001E JMP #0037 - 0x1C1C090C, // 001F EQ R7 R4 K12 - 0x781E0005, // 0020 JMPF R7 #0027 - 0x8C1C0D04, // 0021 GETMET R7 R6 K4 - 0x88240D0D, // 0022 GETMBR R9 R6 K13 - 0x5828000C, // 0023 LDCONST R10 K12 - 0x7C1C0600, // 0024 CALL R7 3 - 0x80040E00, // 0025 RET 1 R7 - 0x7002000F, // 0026 JMP #0037 - 0x1C1C090E, // 0027 EQ R7 R4 K14 - 0x781E0005, // 0028 JMPF R7 #002F - 0x8C1C0D04, // 0029 GETMET R7 R6 K4 - 0x88240D0D, // 002A GETMBR R9 R6 K13 - 0x5828000C, // 002B LDCONST R10 K12 - 0x7C1C0600, // 002C CALL R7 3 - 0x80040E00, // 002D RET 1 R7 - 0x70020007, // 002E JMP #0037 - 0x541E0003, // 002F LDINT R7 4 - 0x1C1C0807, // 0030 EQ R7 R4 R7 - 0x781E0004, // 0031 JMPF R7 #0037 - 0x8C1C0D04, // 0032 GETMET R7 R6 K4 - 0x88240D0F, // 0033 GETMBR R9 R6 K15 - 0x50280000, // 0034 LDBOOL R10 0 0 - 0x7C1C0600, // 0035 CALL R7 3 - 0x80040E00, // 0036 RET 1 R7 - 0x7002024F, // 0037 JMP #0288 - 0x541E0031, // 0038 LDINT R7 50 - 0x1C1C0607, // 0039 EQ R7 R3 R7 - 0x781E0000, // 003A JMPF R7 #003C - 0x7002024B, // 003B JMP #0288 - 0x541E0032, // 003C LDINT R7 51 - 0x1C1C0607, // 003D EQ R7 R3 R7 - 0x781E00DA, // 003E JMPF R7 #011A - 0x1C1C0903, // 003F EQ R7 R4 K3 - 0x781E00B5, // 0040 JMPF R7 #00F7 - 0x8C1C0D10, // 0041 GETMET R7 R6 K16 - 0x7C1C0200, // 0042 CALL R7 1 - 0xB8222200, // 0043 GETNGBL R8 K17 - 0x8C201112, // 0044 GETMET R8 R8 K18 - 0x7C200200, // 0045 CALL R8 1 - 0x94241113, // 0046 GETIDX R9 R8 K19 - 0x78260053, // 0047 JMPF R9 #009C - 0x8C240F14, // 0048 GETMET R9 R7 K20 - 0x4C2C0000, // 0049 LDNIL R11 - 0x7C240400, // 004A CALL R9 2 - 0x8C28130A, // 004B GETMET R10 R9 K10 - 0x58300003, // 004C LDCONST R12 K3 - 0x88340D15, // 004D GETMBR R13 R6 K21 - 0x58380016, // 004E LDCONST R14 K22 - 0x7C280800, // 004F CALL R10 4 - 0x8C28130A, // 0050 GETMET R10 R9 K10 - 0x58300008, // 0051 LDCONST R12 K8 - 0x88340D0F, // 0052 GETMBR R13 R6 K15 - 0x58380008, // 0053 LDCONST R14 K8 - 0x7C280800, // 0054 CALL R10 4 - 0x8C28130A, // 0055 GETMET R10 R9 K10 - 0x5830000C, // 0056 LDCONST R12 K12 - 0x88340D0F, // 0057 GETMBR R13 R6 K15 - 0x58380008, // 0058 LDCONST R14 K8 - 0x7C280800, // 0059 CALL R10 4 - 0x8C28130A, // 005A GETMET R10 R9 K10 - 0x5830000E, // 005B LDCONST R12 K14 - 0x88340D17, // 005C GETMBR R13 R6 K23 - 0x4C380000, // 005D LDNIL R14 - 0x7C280800, // 005E CALL R10 4 - 0x60280015, // 005F GETGBL R10 G21 - 0x7C280000, // 0060 CALL R10 0 - 0x8C281518, // 0061 GETMET R10 R10 K24 - 0x8C300B19, // 0062 GETMET R12 R5 K25 - 0x8C38111A, // 0063 GETMET R14 R8 K26 - 0x5840001B, // 0064 LDCONST R16 K27 - 0x5844001C, // 0065 LDCONST R17 K28 - 0x7C380600, // 0066 CALL R14 3 - 0x583C001D, // 0067 LDCONST R15 K29 - 0x5840001C, // 0068 LDCONST R16 K28 - 0x7C300800, // 0069 CALL R12 4 - 0x7C280400, // 006A CALL R10 2 - 0x8C2C130A, // 006B GETMET R11 R9 K10 - 0x54360003, // 006C LDINT R13 4 - 0x88380D1E, // 006D GETMBR R14 R6 K30 - 0x5C3C1400, // 006E MOVE R15 R10 - 0x7C2C0800, // 006F CALL R11 4 - 0x8C2C131F, // 0070 GETMET R11 R9 K31 - 0x54360004, // 0071 LDINT R13 5 - 0x7C2C0400, // 0072 CALL R11 2 - 0x8C30170A, // 0073 GETMET R12 R11 K10 - 0x4C380000, // 0074 LDNIL R14 - 0x883C0D1E, // 0075 GETMBR R15 R6 K30 - 0xB8420200, // 0076 GETNGBL R16 K1 - 0x8C402120, // 0077 GETMET R16 R16 K32 - 0x8C48111A, // 0078 GETMET R18 R8 K26 - 0x58500021, // 0079 LDCONST R20 K33 - 0x5854001C, // 007A LDCONST R21 K28 - 0x7C480600, // 007B CALL R18 3 - 0x7C400400, // 007C CALL R16 2 - 0x7C300800, // 007D CALL R12 4 - 0x8C30131F, // 007E GETMET R12 R9 K31 - 0x543A0005, // 007F LDINT R14 6 - 0x7C300400, // 0080 CALL R12 2 - 0x8C34190A, // 0081 GETMET R13 R12 K10 - 0x4C3C0000, // 0082 LDNIL R15 - 0x88400D1E, // 0083 GETMBR R16 R6 K30 - 0xB8460200, // 0084 GETNGBL R17 K1 - 0x8C442320, // 0085 GETMET R17 R17 K32 - 0x8C4C111A, // 0086 GETMET R19 R8 K26 - 0x58540022, // 0087 LDCONST R21 K34 - 0x5858001C, // 0088 LDCONST R22 K28 - 0x7C4C0600, // 0089 CALL R19 3 - 0x7C440400, // 008A CALL R17 2 - 0x7C340800, // 008B CALL R13 4 - 0x8C34190A, // 008C GETMET R13 R12 K10 - 0x4C3C0000, // 008D LDNIL R15 - 0x88400D1E, // 008E GETMBR R16 R6 K30 - 0xB8460200, // 008F GETNGBL R17 K1 - 0x8C442320, // 0090 GETMET R17 R17 K32 - 0x8C4C111A, // 0091 GETMET R19 R8 K26 - 0x58540023, // 0092 LDCONST R21 K35 - 0x5858001C, // 0093 LDCONST R22 K28 - 0x7C4C0600, // 0094 CALL R19 3 - 0x7C440400, // 0095 CALL R17 2 - 0x7C340800, // 0096 CALL R13 4 - 0x8C34130A, // 0097 GETMET R13 R9 K10 - 0x543E0006, // 0098 LDINT R15 7 - 0x88400D0D, // 0099 GETMBR R16 R6 K13 - 0x5844000C, // 009A LDCONST R17 K12 - 0x7C340800, // 009B CALL R13 4 - 0xB8262200, // 009C GETNGBL R9 K17 - 0x8C241324, // 009D GETMET R9 R9 K36 - 0x7C240200, // 009E CALL R9 1 - 0x94281313, // 009F GETIDX R10 R9 K19 - 0x782A0053, // 00A0 JMPF R10 #00F5 - 0x8C280F14, // 00A1 GETMET R10 R7 K20 - 0x4C300000, // 00A2 LDNIL R12 - 0x7C280400, // 00A3 CALL R10 2 - 0x8C2C150A, // 00A4 GETMET R11 R10 K10 - 0x58340003, // 00A5 LDCONST R13 K3 - 0x88380D15, // 00A6 GETMBR R14 R6 K21 - 0x583C0024, // 00A7 LDCONST R15 K36 - 0x7C2C0800, // 00A8 CALL R11 4 - 0x8C2C150A, // 00A9 GETMET R11 R10 K10 - 0x58340008, // 00AA LDCONST R13 K8 - 0x88380D0F, // 00AB GETMBR R14 R6 K15 - 0x583C0008, // 00AC LDCONST R15 K8 - 0x7C2C0800, // 00AD CALL R11 4 - 0x8C2C150A, // 00AE GETMET R11 R10 K10 - 0x5834000C, // 00AF LDCONST R13 K12 - 0x88380D0F, // 00B0 GETMBR R14 R6 K15 - 0x583C0008, // 00B1 LDCONST R15 K8 - 0x7C2C0800, // 00B2 CALL R11 4 - 0x8C2C150A, // 00B3 GETMET R11 R10 K10 - 0x5834000E, // 00B4 LDCONST R13 K14 - 0x88380D17, // 00B5 GETMBR R14 R6 K23 - 0x4C3C0000, // 00B6 LDNIL R15 - 0x7C2C0800, // 00B7 CALL R11 4 - 0x602C0015, // 00B8 GETGBL R11 G21 - 0x7C2C0000, // 00B9 CALL R11 0 - 0x8C2C1718, // 00BA GETMET R11 R11 K24 - 0x8C340B19, // 00BB GETMET R13 R5 K25 - 0x8C3C131A, // 00BC GETMET R15 R9 K26 - 0x5844001B, // 00BD LDCONST R17 K27 - 0x5848001C, // 00BE LDCONST R18 K28 - 0x7C3C0600, // 00BF CALL R15 3 - 0x5840001D, // 00C0 LDCONST R16 K29 - 0x5844001C, // 00C1 LDCONST R17 K28 - 0x7C340800, // 00C2 CALL R13 4 - 0x7C2C0400, // 00C3 CALL R11 2 - 0x8C30150A, // 00C4 GETMET R12 R10 K10 - 0x543A0003, // 00C5 LDINT R14 4 - 0x883C0D1E, // 00C6 GETMBR R15 R6 K30 - 0x5C401600, // 00C7 MOVE R16 R11 - 0x7C300800, // 00C8 CALL R12 4 - 0x8C30151F, // 00C9 GETMET R12 R10 K31 - 0x543A0004, // 00CA LDINT R14 5 - 0x7C300400, // 00CB CALL R12 2 - 0x8C34190A, // 00CC GETMET R13 R12 K10 - 0x4C3C0000, // 00CD LDNIL R15 - 0x88400D1E, // 00CE GETMBR R16 R6 K30 - 0xB8460200, // 00CF GETNGBL R17 K1 - 0x8C442320, // 00D0 GETMET R17 R17 K32 - 0x8C4C131A, // 00D1 GETMET R19 R9 K26 - 0x58540021, // 00D2 LDCONST R21 K33 - 0x5858001C, // 00D3 LDCONST R22 K28 - 0x7C4C0600, // 00D4 CALL R19 3 - 0x7C440400, // 00D5 CALL R17 2 - 0x7C340800, // 00D6 CALL R13 4 - 0x8C34151F, // 00D7 GETMET R13 R10 K31 - 0x543E0005, // 00D8 LDINT R15 6 - 0x7C340400, // 00D9 CALL R13 2 - 0x8C381B0A, // 00DA GETMET R14 R13 K10 - 0x4C400000, // 00DB LDNIL R16 - 0x88440D1E, // 00DC GETMBR R17 R6 K30 - 0xB84A0200, // 00DD GETNGBL R18 K1 - 0x8C482520, // 00DE GETMET R18 R18 K32 - 0x8C50131A, // 00DF GETMET R20 R9 K26 - 0x58580022, // 00E0 LDCONST R22 K34 - 0x585C001C, // 00E1 LDCONST R23 K28 - 0x7C500600, // 00E2 CALL R20 3 - 0x7C480400, // 00E3 CALL R18 2 - 0x7C380800, // 00E4 CALL R14 4 - 0x8C381B0A, // 00E5 GETMET R14 R13 K10 - 0x4C400000, // 00E6 LDNIL R16 - 0x88440D1E, // 00E7 GETMBR R17 R6 K30 - 0xB84A0200, // 00E8 GETNGBL R18 K1 - 0x8C482520, // 00E9 GETMET R18 R18 K32 - 0x8C50131A, // 00EA GETMET R20 R9 K26 - 0x58580023, // 00EB LDCONST R22 K35 - 0x585C001C, // 00EC LDCONST R23 K28 - 0x7C500600, // 00ED CALL R20 3 - 0x7C480400, // 00EE CALL R18 2 - 0x7C380800, // 00EF CALL R14 4 - 0x8C38150A, // 00F0 GETMET R14 R10 K10 - 0x54420006, // 00F1 LDINT R16 7 - 0x88440D0D, // 00F2 GETMBR R17 R6 K13 - 0x58480008, // 00F3 LDCONST R18 K8 - 0x7C380800, // 00F4 CALL R14 4 - 0x80040E00, // 00F5 RET 1 R7 - 0x70020021, // 00F6 JMP #0119 - 0x1C1C0908, // 00F7 EQ R7 R4 K8 - 0x781E000A, // 00F8 JMPF R7 #0104 - 0x8C1C0D04, // 00F9 GETMET R7 R6 K4 - 0x88240D0B, // 00FA GETMBR R9 R6 K11 - 0xB82A2200, // 00FB GETNGBL R10 K17 - 0x8C281525, // 00FC GETMET R10 R10 K37 - 0x58300026, // 00FD LDCONST R12 K38 - 0x7C280400, // 00FE CALL R10 2 - 0x94281527, // 00FF GETIDX R10 R10 K39 - 0x94281528, // 0100 GETIDX R10 R10 K40 - 0x7C1C0600, // 0101 CALL R7 3 - 0x80040E00, // 0102 RET 1 R7 - 0x70020014, // 0103 JMP #0119 - 0x1C1C090C, // 0104 EQ R7 R4 K12 - 0x781E000A, // 0105 JMPF R7 #0111 - 0x8C1C0D04, // 0106 GETMET R7 R6 K4 - 0x88240D29, // 0107 GETMBR R9 R6 K41 - 0xB82A2200, // 0108 GETNGBL R10 K17 - 0x8C281525, // 0109 GETMET R10 R10 K37 - 0x5830002A, // 010A LDCONST R12 K42 - 0x7C280400, // 010B CALL R10 2 - 0x9428152B, // 010C GETIDX R10 R10 K43 - 0x9428152C, // 010D GETIDX R10 R10 K44 - 0x7C1C0600, // 010E CALL R7 3 - 0x80040E00, // 010F RET 1 R7 - 0x70020007, // 0110 JMP #0119 - 0x541E0007, // 0111 LDINT R7 8 - 0x1C1C0807, // 0112 EQ R7 R4 R7 - 0x781E0004, // 0113 JMPF R7 #0119 - 0x8C1C0D04, // 0114 GETMET R7 R6 K4 - 0x88240D0F, // 0115 GETMBR R9 R6 K15 - 0x50280000, // 0116 LDBOOL R10 0 0 - 0x7C1C0600, // 0117 CALL R7 3 - 0x80040E00, // 0118 RET 1 R7 - 0x7002016D, // 0119 JMP #0288 - 0x541E0033, // 011A LDINT R7 52 - 0x1C1C0607, // 011B EQ R7 R3 R7 - 0x781E0000, // 011C JMPF R7 #011E - 0x70020169, // 011D JMP #0288 - 0x541E0037, // 011E LDINT R7 56 - 0x1C1C0607, // 011F EQ R7 R3 R7 - 0x781E002C, // 0120 JMPF R7 #014E - 0x1C1C0903, // 0121 EQ R7 R4 K3 - 0x781E000F, // 0122 JMPF R7 #0133 - 0xB81E5A00, // 0123 GETNGBL R7 K45 - 0xB8222200, // 0124 GETNGBL R8 K17 - 0x8C20112E, // 0125 GETMET R8 R8 K46 - 0x7C200200, // 0126 CALL R8 1 - 0x9420112F, // 0127 GETIDX R8 R8 K47 - 0x7C1C0200, // 0128 CALL R7 1 - 0xB8225A00, // 0129 GETNGBL R8 K45 - 0x58240030, // 012A LDCONST R9 K48 - 0x7C200200, // 012B CALL R8 1 - 0x081C0E08, // 012C MUL R7 R7 R8 - 0x8C200D04, // 012D GETMET R8 R6 K4 - 0x88280D05, // 012E GETMBR R10 R6 K5 - 0x5C2C0E00, // 012F MOVE R11 R7 - 0x7C200600, // 0130 CALL R8 3 - 0x80041000, // 0131 RET 1 R8 - 0x70020019, // 0132 JMP #014D - 0x1C1C0908, // 0133 EQ R7 R4 K8 - 0x781E0005, // 0134 JMPF R7 #013B - 0x8C1C0D04, // 0135 GETMET R7 R6 K4 - 0x88240D0D, // 0136 GETMBR R9 R6 K13 - 0x5828000E, // 0137 LDCONST R10 K14 - 0x7C1C0600, // 0138 CALL R7 3 - 0x80040E00, // 0139 RET 1 R7 - 0x70020011, // 013A JMP #014D - 0x541E0006, // 013B LDINT R7 7 - 0x1C1C0807, // 013C EQ R7 R4 R7 - 0x781E000E, // 013D JMPF R7 #014D - 0xB81E5A00, // 013E GETNGBL R7 K45 - 0xB8222200, // 013F GETNGBL R8 K17 - 0x8C20112E, // 0140 GETMET R8 R8 K46 - 0x7C200200, // 0141 CALL R8 1 - 0x94201131, // 0142 GETIDX R8 R8 K49 - 0x7C1C0200, // 0143 CALL R7 1 - 0xB8225A00, // 0144 GETNGBL R8 K45 - 0x58240030, // 0145 LDCONST R9 K48 - 0x7C200200, // 0146 CALL R8 1 - 0x081C0E08, // 0147 MUL R7 R7 R8 - 0x8C200D04, // 0148 GETMET R8 R6 K4 - 0x88280D05, // 0149 GETMBR R10 R6 K5 - 0x5C2C0E00, // 014A MOVE R11 R7 - 0x7C200600, // 014B CALL R8 3 - 0x80041000, // 014C RET 1 R8 - 0x70020139, // 014D JMP #0288 - 0x541E003D, // 014E LDINT R7 62 - 0x1C1C0607, // 014F EQ R7 R3 R7 - 0x781E006C, // 0150 JMPF R7 #01BE - 0x1C1C0903, // 0151 EQ R7 R4 K3 - 0x781E001D, // 0152 JMPF R7 #0171 - 0x8C1C0D10, // 0153 GETMET R7 R6 K16 - 0x7C1C0200, // 0154 CALL R7 1 - 0x60200010, // 0155 GETGBL R8 G16 - 0x88240132, // 0156 GETMBR R9 R0 K50 - 0x88241333, // 0157 GETMBR R9 R9 K51 - 0x8C241334, // 0158 GETMET R9 R9 K52 - 0x7C240200, // 0159 CALL R9 1 - 0x7C200200, // 015A CALL R8 1 - 0xA802000F, // 015B EXBLK 0 #016C - 0x5C241000, // 015C MOVE R9 R8 - 0x7C240000, // 015D CALL R9 0 - 0x8C280F14, // 015E GETMET R10 R7 K20 - 0x4C300000, // 015F LDNIL R12 - 0x7C280400, // 0160 CALL R10 2 - 0x8C2C150A, // 0161 GETMET R11 R10 K10 - 0x58340008, // 0162 LDCONST R13 K8 - 0x88380D35, // 0163 GETMBR R14 R6 K53 - 0x883C1336, // 0164 GETMBR R15 R9 K54 - 0x7C2C0800, // 0165 CALL R11 4 - 0x8C2C150A, // 0166 GETMET R11 R10 K10 - 0x5834000C, // 0167 LDCONST R13 K12 - 0x88380D35, // 0168 GETMBR R14 R6 K53 - 0x883C1337, // 0169 GETMBR R15 R9 K55 - 0x7C2C0800, // 016A CALL R11 4 - 0x7001FFEF, // 016B JMP #015C - 0x58200038, // 016C LDCONST R8 K56 - 0xAC200200, // 016D CATCH R8 1 0 - 0xB0080000, // 016E RAISE 2 R0 R0 - 0x80040E00, // 016F RET 1 R7 - 0x7002004B, // 0170 JMP #01BD - 0x1C1C0908, // 0171 EQ R7 R4 K8 - 0x781E0032, // 0172 JMPF R7 #01A6 - 0x8C1C0D10, // 0173 GETMET R7 R6 K16 - 0x7C1C0200, // 0174 CALL R7 1 - 0x60200010, // 0175 GETGBL R8 G16 - 0x88240132, // 0176 GETMBR R9 R0 K50 - 0x88241333, // 0177 GETMBR R9 R9 K51 - 0x8C241334, // 0178 GETMET R9 R9 K52 - 0x7C240200, // 0179 CALL R9 1 - 0x7C200200, // 017A CALL R8 1 - 0xA8020024, // 017B EXBLK 0 #01A1 - 0x5C241000, // 017C MOVE R9 R8 - 0x7C240000, // 017D CALL R9 0 - 0x8C280D39, // 017E GETMET R10 R6 K57 - 0x8C30133A, // 017F GETMET R12 R9 K58 - 0x7C300200, // 0180 CALL R12 1 - 0x7C280400, // 0181 CALL R10 2 - 0x8C2C0F14, // 0182 GETMET R11 R7 K20 - 0x4C340000, // 0183 LDNIL R13 - 0x7C2C0400, // 0184 CALL R11 2 - 0x8C30170A, // 0185 GETMET R12 R11 K10 - 0x58380008, // 0186 LDCONST R14 K8 - 0x883C0D35, // 0187 GETMBR R15 R6 K53 - 0x8C40153B, // 0188 GETMET R16 R10 K59 - 0x544A0008, // 0189 LDINT R18 9 - 0x7C400400, // 018A CALL R16 2 - 0x7C300800, // 018B CALL R12 4 - 0x8C30170A, // 018C GETMET R12 R11 K10 - 0x5838000C, // 018D LDCONST R14 K12 - 0x883C0D0B, // 018E GETMBR R15 R6 K11 - 0x8840133C, // 018F GETMBR R16 R9 K60 - 0x7C300800, // 0190 CALL R12 4 - 0x8C30170A, // 0191 GETMET R12 R11 K10 - 0x5838000E, // 0192 LDCONST R14 K14 - 0x883C0D05, // 0193 GETMBR R15 R6 K5 - 0x8840133D, // 0194 GETMBR R16 R9 K61 - 0x7C300800, // 0195 CALL R12 4 - 0x8C30170A, // 0196 GETMET R12 R11 K10 - 0x543A0003, // 0197 LDINT R14 4 - 0x883C0D05, // 0198 GETMBR R15 R6 K5 - 0x8840133E, // 0199 GETMBR R16 R9 K62 - 0x7C300800, // 019A CALL R12 4 - 0x8C30170A, // 019B GETMET R12 R11 K10 - 0x543A0004, // 019C LDINT R14 5 - 0x883C0D15, // 019D GETMBR R15 R6 K21 - 0x8840133F, // 019E GETMBR R16 R9 K63 - 0x7C300800, // 019F CALL R12 4 - 0x7001FFDA, // 01A0 JMP #017C - 0x58200038, // 01A1 LDCONST R8 K56 - 0xAC200200, // 01A2 CATCH R8 1 0 - 0xB0080000, // 01A3 RAISE 2 R0 R0 - 0x80040E00, // 01A4 RET 1 R7 - 0x70020016, // 01A5 JMP #01BD - 0x1C1C090C, // 01A6 EQ R7 R4 K12 - 0x781E0005, // 01A7 JMPF R7 #01AE - 0x8C1C0D04, // 01A8 GETMET R7 R6 K4 - 0x88240D0D, // 01A9 GETMBR R9 R6 K13 - 0x542A0004, // 01AA LDINT R10 5 - 0x7C1C0600, // 01AB CALL R7 3 - 0x80040E00, // 01AC RET 1 R7 - 0x7002000E, // 01AD JMP #01BD - 0x1C1C090E, // 01AE EQ R7 R4 K14 - 0x781E0005, // 01AF JMPF R7 #01B6 - 0x8C1C0D04, // 01B0 GETMET R7 R6 K4 - 0x88240D0D, // 01B1 GETMBR R9 R6 K13 - 0x58280008, // 01B2 LDCONST R10 K8 - 0x7C1C0600, // 01B3 CALL R7 3 - 0x80040E00, // 01B4 RET 1 R7 - 0x70020006, // 01B5 JMP #01BD - 0x541E0003, // 01B6 LDINT R7 4 - 0x1C1C0807, // 01B7 EQ R7 R4 R7 - 0x781E0000, // 01B8 JMPF R7 #01BA - 0x70020002, // 01B9 JMP #01BD - 0x541E0004, // 01BA LDINT R7 5 - 0x1C1C0807, // 01BB EQ R7 R4 R7 - 0x781DFFFF, // 01BC JMPF R7 #01BD - 0x700200C9, // 01BD JMP #0288 - 0x541E003B, // 01BE LDINT R7 60 - 0x1C1C0607, // 01BF EQ R7 R3 R7 - 0x781E0000, // 01C0 JMPF R7 #01C2 - 0x700200C5, // 01C1 JMP #0288 - 0x541E0027, // 01C2 LDINT R7 40 - 0x1C1C0607, // 01C3 EQ R7 R3 R7 - 0x781E0071, // 01C4 JMPF R7 #0237 - 0x1C1C0903, // 01C5 EQ R7 R4 K3 - 0x781E0005, // 01C6 JMPF R7 #01CD - 0x8C1C0D04, // 01C7 GETMET R7 R6 K4 - 0x88240D0B, // 01C8 GETMBR R9 R6 K11 - 0x58280003, // 01C9 LDCONST R10 K3 - 0x7C1C0600, // 01CA CALL R7 3 - 0x80040E00, // 01CB RET 1 R7 - 0x70020068, // 01CC JMP #0236 - 0x1C1C0908, // 01CD EQ R7 R4 K8 - 0x781E0005, // 01CE JMPF R7 #01D5 - 0x8C1C0D04, // 01CF GETMET R7 R6 K4 - 0x88240D15, // 01D0 GETMBR R9 R6 K21 - 0x58280040, // 01D1 LDCONST R10 K64 - 0x7C1C0600, // 01D2 CALL R7 3 - 0x80040E00, // 01D3 RET 1 R7 - 0x70020060, // 01D4 JMP #0236 - 0x1C1C090C, // 01D5 EQ R7 R4 K12 - 0x781E0006, // 01D6 JMPF R7 #01DE - 0x8C1C0D04, // 01D7 GETMET R7 R6 K4 - 0x88240D0B, // 01D8 GETMBR R9 R6 K11 - 0x88280132, // 01D9 GETMBR R10 R0 K50 - 0x88281541, // 01DA GETMBR R10 R10 K65 - 0x7C1C0600, // 01DB CALL R7 3 - 0x80040E00, // 01DC RET 1 R7 - 0x70020057, // 01DD JMP #0236 - 0x1C1C090E, // 01DE EQ R7 R4 K14 - 0x781E0009, // 01DF JMPF R7 #01EA - 0x8C1C0D04, // 01E0 GETMET R7 R6 K4 - 0x88240D15, // 01E1 GETMBR R9 R6 K21 - 0xB82A2200, // 01E2 GETNGBL R10 K17 - 0x8C281525, // 01E3 GETMET R10 R10 K37 - 0x58300042, // 01E4 LDCONST R12 K66 - 0x7C280400, // 01E5 CALL R10 2 - 0x94281542, // 01E6 GETIDX R10 R10 K66 - 0x7C1C0600, // 01E7 CALL R7 3 - 0x80040E00, // 01E8 RET 1 R7 - 0x7002004B, // 01E9 JMP #0236 - 0x541E0003, // 01EA LDINT R7 4 - 0x1C1C0807, // 01EB EQ R7 R4 R7 - 0x781E0005, // 01EC JMPF R7 #01F3 - 0x8C1C0D04, // 01ED GETMET R7 R6 K4 - 0x88240D0B, // 01EE GETMBR R9 R6 K11 - 0x542A7FFF, // 01EF LDINT R10 32768 - 0x7C1C0600, // 01F0 CALL R7 3 - 0x80040E00, // 01F1 RET 1 R7 - 0x70020042, // 01F2 JMP #0236 - 0x541E0004, // 01F3 LDINT R7 5 - 0x1C1C0807, // 01F4 EQ R7 R4 R7 - 0x781E0009, // 01F5 JMPF R7 #0200 - 0x8C1C0D04, // 01F6 GETMET R7 R6 K4 - 0x88240D15, // 01F7 GETMBR R9 R6 K21 - 0xB82A2200, // 01F8 GETNGBL R10 K17 - 0x8C281525, // 01F9 GETMET R10 R10 K37 - 0x58300043, // 01FA LDCONST R12 K67 - 0x7C280400, // 01FB CALL R10 2 - 0x94281544, // 01FC GETIDX R10 R10 K68 - 0x7C1C0600, // 01FD CALL R7 3 - 0x80040E00, // 01FE RET 1 R7 - 0x70020035, // 01FF JMP #0236 - 0x541E0005, // 0200 LDINT R7 6 - 0x1C1C0807, // 0201 EQ R7 R4 R7 - 0x781E0005, // 0202 JMPF R7 #0209 - 0x8C1C0D04, // 0203 GETMET R7 R6 K4 - 0x88240D15, // 0204 GETMBR R9 R6 K21 - 0x58280045, // 0205 LDCONST R10 K69 - 0x7C1C0600, // 0206 CALL R7 3 - 0x80040E00, // 0207 RET 1 R7 - 0x7002002C, // 0208 JMP #0236 - 0x541E0006, // 0209 LDINT R7 7 - 0x1C1C0807, // 020A EQ R7 R4 R7 - 0x781E0005, // 020B JMPF R7 #0212 - 0x8C1C0D04, // 020C GETMET R7 R6 K4 - 0x88240D0B, // 020D GETMBR R9 R6 K11 - 0x58280003, // 020E LDCONST R10 K3 - 0x7C1C0600, // 020F CALL R7 3 - 0x80040E00, // 0210 RET 1 R7 - 0x70020023, // 0211 JMP #0236 - 0x541E0007, // 0212 LDINT R7 8 - 0x1C1C0807, // 0213 EQ R7 R4 R7 - 0x781E000A, // 0214 JMPF R7 #0220 - 0x8C1C0D04, // 0215 GETMET R7 R6 K4 - 0x88240D15, // 0216 GETMBR R9 R6 K21 - 0xB82A2200, // 0217 GETNGBL R10 K17 - 0x8C281525, // 0218 GETMET R10 R10 K37 - 0x58300046, // 0219 LDCONST R12 K70 - 0x7C280400, // 021A CALL R10 2 - 0x94281547, // 021B GETIDX R10 R10 K71 - 0x94281548, // 021C GETIDX R10 R10 K72 - 0x7C1C0600, // 021D CALL R7 3 - 0x80040E00, // 021E RET 1 R7 - 0x70020015, // 021F JMP #0236 - 0x541E0008, // 0220 LDINT R7 9 - 0x1C1C0807, // 0221 EQ R7 R4 R7 - 0x781E0005, // 0222 JMPF R7 #0229 - 0x8C1C0D04, // 0223 GETMET R7 R6 K4 - 0x88240D0B, // 0224 GETMBR R9 R6 K11 - 0x58280003, // 0225 LDCONST R10 K3 - 0x7C1C0600, // 0226 CALL R7 3 - 0x80040E00, // 0227 RET 1 R7 - 0x7002000C, // 0228 JMP #0236 - 0x541E0009, // 0229 LDINT R7 10 - 0x1C1C0807, // 022A EQ R7 R4 R7 - 0x781E0009, // 022B JMPF R7 #0236 - 0x8C1C0D04, // 022C GETMET R7 R6 K4 - 0x88240D15, // 022D GETMBR R9 R6 K21 - 0xB82A2200, // 022E GETNGBL R10 K17 - 0x8C281525, // 022F GETMET R10 R10 K37 - 0x58300046, // 0230 LDCONST R12 K70 - 0x7C280400, // 0231 CALL R10 2 - 0x94281547, // 0232 GETIDX R10 R10 K71 - 0x94281549, // 0233 GETIDX R10 R10 K73 - 0x7C1C0600, // 0234 CALL R7 3 - 0x80040E00, // 0235 RET 1 R7 - 0x70020050, // 0236 JMP #0288 - 0x541E003E, // 0237 LDINT R7 63 - 0x1C1C0607, // 0238 EQ R7 R3 R7 - 0x781E0000, // 0239 JMPF R7 #023B - 0x7002004C, // 023A JMP #0288 - 0x541E002A, // 023B LDINT R7 43 - 0x1C1C0607, // 023C EQ R7 R3 R7 - 0x781E0016, // 023D JMPF R7 #0255 - 0x1C1C0903, // 023E EQ R7 R4 K3 - 0x781E0007, // 023F JMPF R7 #0248 - 0x8C1C0D04, // 0240 GETMET R7 R6 K4 - 0x88240D15, // 0241 GETMBR R9 R6 K21 - 0xB82A2200, // 0242 GETNGBL R10 K17 - 0x8C28154A, // 0243 GETMET R10 R10 K74 - 0x7C280200, // 0244 CALL R10 1 - 0x7C1C0600, // 0245 CALL R7 3 - 0x80040E00, // 0246 RET 1 R7 - 0x7002000B, // 0247 JMP #0254 - 0x1C1C0908, // 0248 EQ R7 R4 K8 - 0x781E0009, // 0249 JMPF R7 #0254 - 0x8C1C0D4B, // 024A GETMET R7 R6 K75 - 0x7C1C0200, // 024B CALL R7 1 - 0x8C200F0A, // 024C GETMET R8 R7 K10 - 0x4C280000, // 024D LDNIL R10 - 0x882C0D15, // 024E GETMBR R11 R6 K21 - 0xB8322200, // 024F GETNGBL R12 K17 - 0x8C30194A, // 0250 GETMET R12 R12 K74 - 0x7C300200, // 0251 CALL R12 1 - 0x7C200800, // 0252 CALL R8 4 - 0x80040E00, // 0253 RET 1 R7 - 0x70020032, // 0254 JMP #0288 - 0x541E002B, // 0255 LDINT R7 44 - 0x1C1C0607, // 0256 EQ R7 R3 R7 - 0x781E001C, // 0257 JMPF R7 #0275 - 0x1C1C0903, // 0258 EQ R7 R4 K3 - 0x781E0005, // 0259 JMPF R7 #0260 - 0x8C1C0D04, // 025A GETMET R7 R6 K4 - 0x88240D0D, // 025B GETMBR R9 R6 K13 - 0x58280008, // 025C LDCONST R10 K8 - 0x7C1C0600, // 025D CALL R7 3 - 0x80040E00, // 025E RET 1 R7 - 0x70020013, // 025F JMP #0274 - 0x1C1C0908, // 0260 EQ R7 R4 K8 - 0x781E0005, // 0261 JMPF R7 #0268 - 0x8C1C0D04, // 0262 GETMET R7 R6 K4 - 0x88240D0D, // 0263 GETMBR R9 R6 K13 - 0x542A0003, // 0264 LDINT R10 4 - 0x7C1C0600, // 0265 CALL R7 3 - 0x80040E00, // 0266 RET 1 R7 - 0x7002000B, // 0267 JMP #0274 - 0x1C1C090C, // 0268 EQ R7 R4 K12 - 0x781E0009, // 0269 JMPF R7 #0274 - 0x8C1C0D4B, // 026A GETMET R7 R6 K75 - 0x7C1C0200, // 026B CALL R7 1 - 0x8C200F0A, // 026C GETMET R8 R7 K10 - 0x4C280000, // 026D LDNIL R10 - 0x8C2C0D04, // 026E GETMET R11 R6 K4 - 0x88340D0D, // 026F GETMBR R13 R6 K13 - 0x543A0003, // 0270 LDINT R14 4 - 0x7C2C0600, // 0271 CALL R11 3 - 0x7C200600, // 0272 CALL R8 3 - 0x80040E00, // 0273 RET 1 R7 - 0x70020012, // 0274 JMP #0288 - 0x541E0030, // 0275 LDINT R7 49 - 0x1C1C0607, // 0276 EQ R7 R3 R7 - 0x781E000F, // 0277 JMPF R7 #0288 - 0x1C1C090E, // 0278 EQ R7 R4 K14 - 0x781E0005, // 0279 JMPF R7 #0280 - 0x8C1C0D04, // 027A GETMET R7 R6 K4 - 0x88240D0D, // 027B GETMBR R9 R6 K13 - 0x542A001D, // 027C LDINT R10 30 - 0x7C1C0600, // 027D CALL R7 3 - 0x80040E00, // 027E RET 1 R7 - 0x70020007, // 027F JMP #0288 - 0x541EFFFB, // 0280 LDINT R7 65532 - 0x1C1C0807, // 0281 EQ R7 R4 R7 - 0x781E0004, // 0282 JMPF R7 #0288 - 0x8C1C0D04, // 0283 GETMET R7 R6 K4 - 0x88240D29, // 0284 GETMBR R9 R6 K41 - 0x58280003, // 0285 LDCONST R10 K3 - 0x7C1C0600, // 0286 CALL R7 3 - 0x80040E00, // 0287 RET 1 R7 - 0x80000000, // 0288 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: init -********************************************************************/ -be_local_closure(Matter_Plugin_core_init, /* name */ - be_nested_proto( - 5, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_nested_str_weak(init), - /* K1 */ be_nested_str_weak(endpoints), - /* K2 */ be_const_int(0), - }), - be_str_weak(init), - &be_const_str_solidified, - ( &(const binstruction[11]) { /* code */ - 0x60080003, // 0000 GETGBL R2 G3 - 0x5C0C0000, // 0001 MOVE R3 R0 - 0x7C080200, // 0002 CALL R2 1 - 0x8C080500, // 0003 GETMET R2 R2 K0 - 0x5C100200, // 0004 MOVE R4 R1 - 0x7C080400, // 0005 CALL R2 2 - 0x60080012, // 0006 GETGBL R2 G18 - 0x7C080000, // 0007 CALL R2 0 - 0x400C0502, // 0008 CONNECT R3 R2 K2 - 0x90020202, // 0009 SETMBR R0 K1 R2 - 0x80000000, // 000A RET 0 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified function: invoke_request ********************************************************************/ @@ -1385,6 +598,888 @@ be_local_closure(Matter_Plugin_core_invoke_request, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: read_attribute +********************************************************************/ +be_local_closure(Matter_Plugin_core_read_attribute, /* name */ + be_nested_proto( + 24, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[82]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(TLV), + /* K3 */ be_nested_str_weak(cluster), + /* K4 */ be_nested_str_weak(attribute), + /* K5 */ be_const_int(0), + /* K6 */ be_nested_str_weak(create_TLV), + /* K7 */ be_nested_str_weak(U8), + /* K8 */ be_nested_str_weak(session), + /* K9 */ be_nested_str_weak(breadcrumb), + /* K10 */ be_const_int(1), + /* K11 */ be_nested_str_weak(Matter_TLV_struct), + /* K12 */ be_nested_str_weak(add_TLV), + /* K13 */ be_nested_str_weak(U2), + /* K14 */ be_const_int(2), + /* K15 */ be_nested_str_weak(U1), + /* K16 */ be_const_int(3), + /* K17 */ be_nested_str_weak(BOOL), + /* K18 */ be_nested_str_weak(Matter_TLV_array), + /* K19 */ be_nested_str_weak(tasmota), + /* K20 */ be_nested_str_weak(eth), + /* K21 */ be_nested_str_weak(up), + /* K22 */ be_nested_str_weak(add_struct), + /* K23 */ be_nested_str_weak(UTF1), + /* K24 */ be_nested_str_weak(ethernet), + /* K25 */ be_nested_str_weak(NULL), + /* K26 */ be_nested_str_weak(fromhex), + /* K27 */ be_nested_str_weak(replace), + /* K28 */ be_nested_str_weak(find), + /* K29 */ be_nested_str_weak(mac), + /* K30 */ be_nested_str_weak(), + /* K31 */ be_nested_str_weak(_X3A), + /* K32 */ be_nested_str_weak(B1), + /* K33 */ be_nested_str_weak(add_array), + /* K34 */ be_nested_str_weak(get_ip_bytes), + /* K35 */ be_nested_str_weak(ip), + /* K36 */ be_nested_str_weak(ip6local), + /* K37 */ be_nested_str_weak(ip6), + /* K38 */ be_nested_str_weak(wifi), + /* K39 */ be_nested_str_weak(cmd), + /* K40 */ be_nested_str_weak(Status_X201), + /* K41 */ be_nested_str_weak(StatusPRM), + /* K42 */ be_nested_str_weak(BootCount), + /* K43 */ be_nested_str_weak(U4), + /* K44 */ be_nested_str_weak(Status_X2011), + /* K45 */ be_nested_str_weak(StatusSTS), + /* K46 */ be_nested_str_weak(UptimeSec), + /* K47 */ be_nested_str_weak(int64), + /* K48 */ be_nested_str_weak(rtc), + /* K49 */ be_nested_str_weak(utc), + /* K50 */ be_const_int(1000000), + /* K51 */ be_nested_str_weak(local), + /* K52 */ be_nested_str_weak(device), + /* K53 */ be_nested_str_weak(sessions), + /* K54 */ be_nested_str_weak(sessions_active), + /* K55 */ be_nested_str_weak(B2), + /* K56 */ be_nested_str_weak(noc), + /* K57 */ be_nested_str_weak(icac), + /* K58 */ be_nested_str_weak(stop_iteration), + /* K59 */ be_nested_str_weak(parse), + /* K60 */ be_nested_str_weak(get_ca), + /* K61 */ be_nested_str_weak(findsubval), + /* K62 */ be_nested_str_weak(admin_vendor), + /* K63 */ be_nested_str_weak(fabric), + /* K64 */ be_nested_str_weak(deviceid), + /* K65 */ be_nested_str_weak(fabric_label), + /* K66 */ be_nested_str_weak(Tasmota), + /* K67 */ be_nested_str_weak(vendorid), + /* K68 */ be_nested_str_weak(DeviceName), + /* K69 */ be_nested_str_weak(FriendlyName), + /* K70 */ be_nested_str_weak(FriendlyName1), + /* K71 */ be_nested_str_weak(XX), + /* K72 */ be_nested_str_weak(Status_X202), + /* K73 */ be_nested_str_weak(StatusFWR), + /* K74 */ be_nested_str_weak(Hardware), + /* K75 */ be_nested_str_weak(Version), + /* K76 */ be_nested_str_weak(locale), + /* K77 */ be_nested_str_weak(Matter_TLV_list), + /* K78 */ be_nested_str_weak(get_cluster_list), + /* K79 */ be_nested_str_weak(get_active_endpoints), + /* K80 */ be_nested_str_weak(status), + /* K81 */ be_nested_str_weak(UNSUPPORTED_CLUSTER), + }), + be_str_weak(read_attribute), + &be_const_str_solidified, + ( &(const binstruction[736]) { /* code */ + 0xA40E0000, // 0000 IMPORT R3 K0 + 0xB8120200, // 0001 GETNGBL R4 K1 + 0x88100902, // 0002 GETMBR R4 R4 K2 + 0x88140503, // 0003 GETMBR R5 R2 K3 + 0x88180504, // 0004 GETMBR R6 R2 K4 + 0x541E002F, // 0005 LDINT R7 48 + 0x1C1C0A07, // 0006 EQ R7 R5 R7 + 0x781E0031, // 0007 JMPF R7 #003A + 0x1C1C0D05, // 0008 EQ R7 R6 K5 + 0x781E0006, // 0009 JMPF R7 #0011 + 0x8C1C0906, // 000A GETMET R7 R4 K6 + 0x88240907, // 000B GETMBR R9 R4 K7 + 0x88280308, // 000C GETMBR R10 R1 K8 + 0x88281509, // 000D GETMBR R10 R10 K9 + 0x7C1C0600, // 000E CALL R7 3 + 0x80040E00, // 000F RET 1 R7 + 0x70020027, // 0010 JMP #0039 + 0x1C1C0D0A, // 0011 EQ R7 R6 K10 + 0x781E000D, // 0012 JMPF R7 #0021 + 0x8C1C090B, // 0013 GETMET R7 R4 K11 + 0x7C1C0200, // 0014 CALL R7 1 + 0x8C200F0C, // 0015 GETMET R8 R7 K12 + 0x58280005, // 0016 LDCONST R10 K5 + 0x882C090D, // 0017 GETMBR R11 R4 K13 + 0x5432003B, // 0018 LDINT R12 60 + 0x7C200800, // 0019 CALL R8 4 + 0x8C200F0C, // 001A GETMET R8 R7 K12 + 0x5828000A, // 001B LDCONST R10 K10 + 0x882C090D, // 001C GETMBR R11 R4 K13 + 0x54320383, // 001D LDINT R12 900 + 0x7C200800, // 001E CALL R8 4 + 0x80040E00, // 001F RET 1 R7 + 0x70020017, // 0020 JMP #0039 + 0x1C1C0D0E, // 0021 EQ R7 R6 K14 + 0x781E0005, // 0022 JMPF R7 #0029 + 0x8C1C0906, // 0023 GETMET R7 R4 K6 + 0x8824090F, // 0024 GETMBR R9 R4 K15 + 0x5828000E, // 0025 LDCONST R10 K14 + 0x7C1C0600, // 0026 CALL R7 3 + 0x80040E00, // 0027 RET 1 R7 + 0x7002000F, // 0028 JMP #0039 + 0x1C1C0D10, // 0029 EQ R7 R6 K16 + 0x781E0005, // 002A JMPF R7 #0031 + 0x8C1C0906, // 002B GETMET R7 R4 K6 + 0x8824090F, // 002C GETMBR R9 R4 K15 + 0x5828000E, // 002D LDCONST R10 K14 + 0x7C1C0600, // 002E CALL R7 3 + 0x80040E00, // 002F RET 1 R7 + 0x70020007, // 0030 JMP #0039 + 0x541E0003, // 0031 LDINT R7 4 + 0x1C1C0C07, // 0032 EQ R7 R6 R7 + 0x781E0004, // 0033 JMPF R7 #0039 + 0x8C1C0906, // 0034 GETMET R7 R4 K6 + 0x88240911, // 0035 GETMBR R9 R4 K17 + 0x50280000, // 0036 LDBOOL R10 0 0 + 0x7C1C0600, // 0037 CALL R7 3 + 0x80040E00, // 0038 RET 1 R7 + 0x700202A4, // 0039 JMP #02DF + 0x541E0031, // 003A LDINT R7 50 + 0x1C1C0A07, // 003B EQ R7 R5 R7 + 0x781E0000, // 003C JMPF R7 #003E + 0x700202A0, // 003D JMP #02DF + 0x541E0032, // 003E LDINT R7 51 + 0x1C1C0A07, // 003F EQ R7 R5 R7 + 0x781E00DA, // 0040 JMPF R7 #011C + 0x1C1C0D05, // 0041 EQ R7 R6 K5 + 0x781E00B5, // 0042 JMPF R7 #00F9 + 0x8C1C0912, // 0043 GETMET R7 R4 K18 + 0x7C1C0200, // 0044 CALL R7 1 + 0xB8222600, // 0045 GETNGBL R8 K19 + 0x8C201114, // 0046 GETMET R8 R8 K20 + 0x7C200200, // 0047 CALL R8 1 + 0x94241115, // 0048 GETIDX R9 R8 K21 + 0x78260053, // 0049 JMPF R9 #009E + 0x8C240F16, // 004A GETMET R9 R7 K22 + 0x4C2C0000, // 004B LDNIL R11 + 0x7C240400, // 004C CALL R9 2 + 0x8C28130C, // 004D GETMET R10 R9 K12 + 0x58300005, // 004E LDCONST R12 K5 + 0x88340917, // 004F GETMBR R13 R4 K23 + 0x58380018, // 0050 LDCONST R14 K24 + 0x7C280800, // 0051 CALL R10 4 + 0x8C28130C, // 0052 GETMET R10 R9 K12 + 0x5830000A, // 0053 LDCONST R12 K10 + 0x88340911, // 0054 GETMBR R13 R4 K17 + 0x5838000A, // 0055 LDCONST R14 K10 + 0x7C280800, // 0056 CALL R10 4 + 0x8C28130C, // 0057 GETMET R10 R9 K12 + 0x5830000E, // 0058 LDCONST R12 K14 + 0x88340911, // 0059 GETMBR R13 R4 K17 + 0x5838000A, // 005A LDCONST R14 K10 + 0x7C280800, // 005B CALL R10 4 + 0x8C28130C, // 005C GETMET R10 R9 K12 + 0x58300010, // 005D LDCONST R12 K16 + 0x88340919, // 005E GETMBR R13 R4 K25 + 0x4C380000, // 005F LDNIL R14 + 0x7C280800, // 0060 CALL R10 4 + 0x60280015, // 0061 GETGBL R10 G21 + 0x7C280000, // 0062 CALL R10 0 + 0x8C28151A, // 0063 GETMET R10 R10 K26 + 0x8C30071B, // 0064 GETMET R12 R3 K27 + 0x8C38111C, // 0065 GETMET R14 R8 K28 + 0x5840001D, // 0066 LDCONST R16 K29 + 0x5844001E, // 0067 LDCONST R17 K30 + 0x7C380600, // 0068 CALL R14 3 + 0x583C001F, // 0069 LDCONST R15 K31 + 0x5840001E, // 006A LDCONST R16 K30 + 0x7C300800, // 006B CALL R12 4 + 0x7C280400, // 006C CALL R10 2 + 0x8C2C130C, // 006D GETMET R11 R9 K12 + 0x54360003, // 006E LDINT R13 4 + 0x88380920, // 006F GETMBR R14 R4 K32 + 0x5C3C1400, // 0070 MOVE R15 R10 + 0x7C2C0800, // 0071 CALL R11 4 + 0x8C2C1321, // 0072 GETMET R11 R9 K33 + 0x54360004, // 0073 LDINT R13 5 + 0x7C2C0400, // 0074 CALL R11 2 + 0x8C30170C, // 0075 GETMET R12 R11 K12 + 0x4C380000, // 0076 LDNIL R14 + 0x883C0920, // 0077 GETMBR R15 R4 K32 + 0xB8420200, // 0078 GETNGBL R16 K1 + 0x8C402122, // 0079 GETMET R16 R16 K34 + 0x8C48111C, // 007A GETMET R18 R8 K28 + 0x58500023, // 007B LDCONST R20 K35 + 0x5854001E, // 007C LDCONST R21 K30 + 0x7C480600, // 007D CALL R18 3 + 0x7C400400, // 007E CALL R16 2 + 0x7C300800, // 007F CALL R12 4 + 0x8C301321, // 0080 GETMET R12 R9 K33 + 0x543A0005, // 0081 LDINT R14 6 + 0x7C300400, // 0082 CALL R12 2 + 0x8C34190C, // 0083 GETMET R13 R12 K12 + 0x4C3C0000, // 0084 LDNIL R15 + 0x88400920, // 0085 GETMBR R16 R4 K32 + 0xB8460200, // 0086 GETNGBL R17 K1 + 0x8C442322, // 0087 GETMET R17 R17 K34 + 0x8C4C111C, // 0088 GETMET R19 R8 K28 + 0x58540024, // 0089 LDCONST R21 K36 + 0x5858001E, // 008A LDCONST R22 K30 + 0x7C4C0600, // 008B CALL R19 3 + 0x7C440400, // 008C CALL R17 2 + 0x7C340800, // 008D CALL R13 4 + 0x8C34190C, // 008E GETMET R13 R12 K12 + 0x4C3C0000, // 008F LDNIL R15 + 0x88400920, // 0090 GETMBR R16 R4 K32 + 0xB8460200, // 0091 GETNGBL R17 K1 + 0x8C442322, // 0092 GETMET R17 R17 K34 + 0x8C4C111C, // 0093 GETMET R19 R8 K28 + 0x58540025, // 0094 LDCONST R21 K37 + 0x5858001E, // 0095 LDCONST R22 K30 + 0x7C4C0600, // 0096 CALL R19 3 + 0x7C440400, // 0097 CALL R17 2 + 0x7C340800, // 0098 CALL R13 4 + 0x8C34130C, // 0099 GETMET R13 R9 K12 + 0x543E0006, // 009A LDINT R15 7 + 0x8840090F, // 009B GETMBR R16 R4 K15 + 0x5844000E, // 009C LDCONST R17 K14 + 0x7C340800, // 009D CALL R13 4 + 0xB8262600, // 009E GETNGBL R9 K19 + 0x8C241326, // 009F GETMET R9 R9 K38 + 0x7C240200, // 00A0 CALL R9 1 + 0x94281315, // 00A1 GETIDX R10 R9 K21 + 0x782A0053, // 00A2 JMPF R10 #00F7 + 0x8C280F16, // 00A3 GETMET R10 R7 K22 + 0x4C300000, // 00A4 LDNIL R12 + 0x7C280400, // 00A5 CALL R10 2 + 0x8C2C150C, // 00A6 GETMET R11 R10 K12 + 0x58340005, // 00A7 LDCONST R13 K5 + 0x88380917, // 00A8 GETMBR R14 R4 K23 + 0x583C0026, // 00A9 LDCONST R15 K38 + 0x7C2C0800, // 00AA CALL R11 4 + 0x8C2C150C, // 00AB GETMET R11 R10 K12 + 0x5834000A, // 00AC LDCONST R13 K10 + 0x88380911, // 00AD GETMBR R14 R4 K17 + 0x583C000A, // 00AE LDCONST R15 K10 + 0x7C2C0800, // 00AF CALL R11 4 + 0x8C2C150C, // 00B0 GETMET R11 R10 K12 + 0x5834000E, // 00B1 LDCONST R13 K14 + 0x88380911, // 00B2 GETMBR R14 R4 K17 + 0x583C000A, // 00B3 LDCONST R15 K10 + 0x7C2C0800, // 00B4 CALL R11 4 + 0x8C2C150C, // 00B5 GETMET R11 R10 K12 + 0x58340010, // 00B6 LDCONST R13 K16 + 0x88380919, // 00B7 GETMBR R14 R4 K25 + 0x4C3C0000, // 00B8 LDNIL R15 + 0x7C2C0800, // 00B9 CALL R11 4 + 0x602C0015, // 00BA GETGBL R11 G21 + 0x7C2C0000, // 00BB CALL R11 0 + 0x8C2C171A, // 00BC GETMET R11 R11 K26 + 0x8C34071B, // 00BD GETMET R13 R3 K27 + 0x8C3C131C, // 00BE GETMET R15 R9 K28 + 0x5844001D, // 00BF LDCONST R17 K29 + 0x5848001E, // 00C0 LDCONST R18 K30 + 0x7C3C0600, // 00C1 CALL R15 3 + 0x5840001F, // 00C2 LDCONST R16 K31 + 0x5844001E, // 00C3 LDCONST R17 K30 + 0x7C340800, // 00C4 CALL R13 4 + 0x7C2C0400, // 00C5 CALL R11 2 + 0x8C30150C, // 00C6 GETMET R12 R10 K12 + 0x543A0003, // 00C7 LDINT R14 4 + 0x883C0920, // 00C8 GETMBR R15 R4 K32 + 0x5C401600, // 00C9 MOVE R16 R11 + 0x7C300800, // 00CA CALL R12 4 + 0x8C301521, // 00CB GETMET R12 R10 K33 + 0x543A0004, // 00CC LDINT R14 5 + 0x7C300400, // 00CD CALL R12 2 + 0x8C34190C, // 00CE GETMET R13 R12 K12 + 0x4C3C0000, // 00CF LDNIL R15 + 0x88400920, // 00D0 GETMBR R16 R4 K32 + 0xB8460200, // 00D1 GETNGBL R17 K1 + 0x8C442322, // 00D2 GETMET R17 R17 K34 + 0x8C4C131C, // 00D3 GETMET R19 R9 K28 + 0x58540023, // 00D4 LDCONST R21 K35 + 0x5858001E, // 00D5 LDCONST R22 K30 + 0x7C4C0600, // 00D6 CALL R19 3 + 0x7C440400, // 00D7 CALL R17 2 + 0x7C340800, // 00D8 CALL R13 4 + 0x8C341521, // 00D9 GETMET R13 R10 K33 + 0x543E0005, // 00DA LDINT R15 6 + 0x7C340400, // 00DB CALL R13 2 + 0x8C381B0C, // 00DC GETMET R14 R13 K12 + 0x4C400000, // 00DD LDNIL R16 + 0x88440920, // 00DE GETMBR R17 R4 K32 + 0xB84A0200, // 00DF GETNGBL R18 K1 + 0x8C482522, // 00E0 GETMET R18 R18 K34 + 0x8C50131C, // 00E1 GETMET R20 R9 K28 + 0x58580024, // 00E2 LDCONST R22 K36 + 0x585C001E, // 00E3 LDCONST R23 K30 + 0x7C500600, // 00E4 CALL R20 3 + 0x7C480400, // 00E5 CALL R18 2 + 0x7C380800, // 00E6 CALL R14 4 + 0x8C381B0C, // 00E7 GETMET R14 R13 K12 + 0x4C400000, // 00E8 LDNIL R16 + 0x88440920, // 00E9 GETMBR R17 R4 K32 + 0xB84A0200, // 00EA GETNGBL R18 K1 + 0x8C482522, // 00EB GETMET R18 R18 K34 + 0x8C50131C, // 00EC GETMET R20 R9 K28 + 0x58580025, // 00ED LDCONST R22 K37 + 0x585C001E, // 00EE LDCONST R23 K30 + 0x7C500600, // 00EF CALL R20 3 + 0x7C480400, // 00F0 CALL R18 2 + 0x7C380800, // 00F1 CALL R14 4 + 0x8C38150C, // 00F2 GETMET R14 R10 K12 + 0x54420006, // 00F3 LDINT R16 7 + 0x8844090F, // 00F4 GETMBR R17 R4 K15 + 0x5848000A, // 00F5 LDCONST R18 K10 + 0x7C380800, // 00F6 CALL R14 4 + 0x80040E00, // 00F7 RET 1 R7 + 0x70020021, // 00F8 JMP #011B + 0x1C1C0D0A, // 00F9 EQ R7 R6 K10 + 0x781E000A, // 00FA JMPF R7 #0106 + 0x8C1C0906, // 00FB GETMET R7 R4 K6 + 0x8824090D, // 00FC GETMBR R9 R4 K13 + 0xB82A2600, // 00FD GETNGBL R10 K19 + 0x8C281527, // 00FE GETMET R10 R10 K39 + 0x58300028, // 00FF LDCONST R12 K40 + 0x7C280400, // 0100 CALL R10 2 + 0x94281529, // 0101 GETIDX R10 R10 K41 + 0x9428152A, // 0102 GETIDX R10 R10 K42 + 0x7C1C0600, // 0103 CALL R7 3 + 0x80040E00, // 0104 RET 1 R7 + 0x70020014, // 0105 JMP #011B + 0x1C1C0D0E, // 0106 EQ R7 R6 K14 + 0x781E000A, // 0107 JMPF R7 #0113 + 0x8C1C0906, // 0108 GETMET R7 R4 K6 + 0x8824092B, // 0109 GETMBR R9 R4 K43 + 0xB82A2600, // 010A GETNGBL R10 K19 + 0x8C281527, // 010B GETMET R10 R10 K39 + 0x5830002C, // 010C LDCONST R12 K44 + 0x7C280400, // 010D CALL R10 2 + 0x9428152D, // 010E GETIDX R10 R10 K45 + 0x9428152E, // 010F GETIDX R10 R10 K46 + 0x7C1C0600, // 0110 CALL R7 3 + 0x80040E00, // 0111 RET 1 R7 + 0x70020007, // 0112 JMP #011B + 0x541E0007, // 0113 LDINT R7 8 + 0x1C1C0C07, // 0114 EQ R7 R6 R7 + 0x781E0004, // 0115 JMPF R7 #011B + 0x8C1C0906, // 0116 GETMET R7 R4 K6 + 0x88240911, // 0117 GETMBR R9 R4 K17 + 0x50280000, // 0118 LDBOOL R10 0 0 + 0x7C1C0600, // 0119 CALL R7 3 + 0x80040E00, // 011A RET 1 R7 + 0x700201C2, // 011B JMP #02DF + 0x541E0033, // 011C LDINT R7 52 + 0x1C1C0A07, // 011D EQ R7 R5 R7 + 0x781E0000, // 011E JMPF R7 #0120 + 0x700201BE, // 011F JMP #02DF + 0x541E0037, // 0120 LDINT R7 56 + 0x1C1C0A07, // 0121 EQ R7 R5 R7 + 0x781E002C, // 0122 JMPF R7 #0150 + 0x1C1C0D05, // 0123 EQ R7 R6 K5 + 0x781E000F, // 0124 JMPF R7 #0135 + 0xB81E5E00, // 0125 GETNGBL R7 K47 + 0xB8222600, // 0126 GETNGBL R8 K19 + 0x8C201130, // 0127 GETMET R8 R8 K48 + 0x7C200200, // 0128 CALL R8 1 + 0x94201131, // 0129 GETIDX R8 R8 K49 + 0x7C1C0200, // 012A CALL R7 1 + 0xB8225E00, // 012B GETNGBL R8 K47 + 0x58240032, // 012C LDCONST R9 K50 + 0x7C200200, // 012D CALL R8 1 + 0x081C0E08, // 012E MUL R7 R7 R8 + 0x8C200906, // 012F GETMET R8 R4 K6 + 0x88280907, // 0130 GETMBR R10 R4 K7 + 0x5C2C0E00, // 0131 MOVE R11 R7 + 0x7C200600, // 0132 CALL R8 3 + 0x80041000, // 0133 RET 1 R8 + 0x70020019, // 0134 JMP #014F + 0x1C1C0D0A, // 0135 EQ R7 R6 K10 + 0x781E0005, // 0136 JMPF R7 #013D + 0x8C1C0906, // 0137 GETMET R7 R4 K6 + 0x8824090F, // 0138 GETMBR R9 R4 K15 + 0x58280010, // 0139 LDCONST R10 K16 + 0x7C1C0600, // 013A CALL R7 3 + 0x80040E00, // 013B RET 1 R7 + 0x70020011, // 013C JMP #014F + 0x541E0006, // 013D LDINT R7 7 + 0x1C1C0C07, // 013E EQ R7 R6 R7 + 0x781E000E, // 013F JMPF R7 #014F + 0xB81E5E00, // 0140 GETNGBL R7 K47 + 0xB8222600, // 0141 GETNGBL R8 K19 + 0x8C201130, // 0142 GETMET R8 R8 K48 + 0x7C200200, // 0143 CALL R8 1 + 0x94201133, // 0144 GETIDX R8 R8 K51 + 0x7C1C0200, // 0145 CALL R7 1 + 0xB8225E00, // 0146 GETNGBL R8 K47 + 0x58240032, // 0147 LDCONST R9 K50 + 0x7C200200, // 0148 CALL R8 1 + 0x081C0E08, // 0149 MUL R7 R7 R8 + 0x8C200906, // 014A GETMET R8 R4 K6 + 0x88280907, // 014B GETMBR R10 R4 K7 + 0x5C2C0E00, // 014C MOVE R11 R7 + 0x7C200600, // 014D CALL R8 3 + 0x80041000, // 014E RET 1 R8 + 0x7002018E, // 014F JMP #02DF + 0x541E003D, // 0150 LDINT R7 62 + 0x1C1C0A07, // 0151 EQ R7 R5 R7 + 0x781E0082, // 0152 JMPF R7 #01D6 + 0x1C1C0D05, // 0153 EQ R7 R6 K5 + 0x781E001D, // 0154 JMPF R7 #0173 + 0x8C1C0912, // 0155 GETMET R7 R4 K18 + 0x7C1C0200, // 0156 CALL R7 1 + 0x60200010, // 0157 GETGBL R8 G16 + 0x88240134, // 0158 GETMBR R9 R0 K52 + 0x88241335, // 0159 GETMBR R9 R9 K53 + 0x8C241336, // 015A GETMET R9 R9 K54 + 0x7C240200, // 015B CALL R9 1 + 0x7C200200, // 015C CALL R8 1 + 0xA802000F, // 015D EXBLK 0 #016E + 0x5C241000, // 015E MOVE R9 R8 + 0x7C240000, // 015F CALL R9 0 + 0x8C280F16, // 0160 GETMET R10 R7 K22 + 0x4C300000, // 0161 LDNIL R12 + 0x7C280400, // 0162 CALL R10 2 + 0x8C2C150C, // 0163 GETMET R11 R10 K12 + 0x5834000A, // 0164 LDCONST R13 K10 + 0x88380937, // 0165 GETMBR R14 R4 K55 + 0x883C1338, // 0166 GETMBR R15 R9 K56 + 0x7C2C0800, // 0167 CALL R11 4 + 0x8C2C150C, // 0168 GETMET R11 R10 K12 + 0x5834000E, // 0169 LDCONST R13 K14 + 0x88380937, // 016A GETMBR R14 R4 K55 + 0x883C1339, // 016B GETMBR R15 R9 K57 + 0x7C2C0800, // 016C CALL R11 4 + 0x7001FFEF, // 016D JMP #015E + 0x5820003A, // 016E LDCONST R8 K58 + 0xAC200200, // 016F CATCH R8 1 0 + 0xB0080000, // 0170 RAISE 2 R0 R0 + 0x80040E00, // 0171 RET 1 R7 + 0x70020061, // 0172 JMP #01D5 + 0x1C1C0D0A, // 0173 EQ R7 R6 K10 + 0x781E0032, // 0174 JMPF R7 #01A8 + 0x8C1C0912, // 0175 GETMET R7 R4 K18 + 0x7C1C0200, // 0176 CALL R7 1 + 0x60200010, // 0177 GETGBL R8 G16 + 0x88240134, // 0178 GETMBR R9 R0 K52 + 0x88241335, // 0179 GETMBR R9 R9 K53 + 0x8C241336, // 017A GETMET R9 R9 K54 + 0x7C240200, // 017B CALL R9 1 + 0x7C200200, // 017C CALL R8 1 + 0xA8020024, // 017D EXBLK 0 #01A3 + 0x5C241000, // 017E MOVE R9 R8 + 0x7C240000, // 017F CALL R9 0 + 0x8C28093B, // 0180 GETMET R10 R4 K59 + 0x8C30133C, // 0181 GETMET R12 R9 K60 + 0x7C300200, // 0182 CALL R12 1 + 0x7C280400, // 0183 CALL R10 2 + 0x8C2C0F16, // 0184 GETMET R11 R7 K22 + 0x4C340000, // 0185 LDNIL R13 + 0x7C2C0400, // 0186 CALL R11 2 + 0x8C30170C, // 0187 GETMET R12 R11 K12 + 0x5838000A, // 0188 LDCONST R14 K10 + 0x883C0937, // 0189 GETMBR R15 R4 K55 + 0x8C40153D, // 018A GETMET R16 R10 K61 + 0x544A0008, // 018B LDINT R18 9 + 0x7C400400, // 018C CALL R16 2 + 0x7C300800, // 018D CALL R12 4 + 0x8C30170C, // 018E GETMET R12 R11 K12 + 0x5838000E, // 018F LDCONST R14 K14 + 0x883C090D, // 0190 GETMBR R15 R4 K13 + 0x8840133E, // 0191 GETMBR R16 R9 K62 + 0x7C300800, // 0192 CALL R12 4 + 0x8C30170C, // 0193 GETMET R12 R11 K12 + 0x58380010, // 0194 LDCONST R14 K16 + 0x883C0907, // 0195 GETMBR R15 R4 K7 + 0x8840133F, // 0196 GETMBR R16 R9 K63 + 0x7C300800, // 0197 CALL R12 4 + 0x8C30170C, // 0198 GETMET R12 R11 K12 + 0x543A0003, // 0199 LDINT R14 4 + 0x883C0907, // 019A GETMBR R15 R4 K7 + 0x88401340, // 019B GETMBR R16 R9 K64 + 0x7C300800, // 019C CALL R12 4 + 0x8C30170C, // 019D GETMET R12 R11 K12 + 0x543A0004, // 019E LDINT R14 5 + 0x883C0917, // 019F GETMBR R15 R4 K23 + 0x88401341, // 01A0 GETMBR R16 R9 K65 + 0x7C300800, // 01A1 CALL R12 4 + 0x7001FFDA, // 01A2 JMP #017E + 0x5820003A, // 01A3 LDCONST R8 K58 + 0xAC200200, // 01A4 CATCH R8 1 0 + 0xB0080000, // 01A5 RAISE 2 R0 R0 + 0x80040E00, // 01A6 RET 1 R7 + 0x7002002C, // 01A7 JMP #01D5 + 0x1C1C0D0E, // 01A8 EQ R7 R6 K14 + 0x781E0005, // 01A9 JMPF R7 #01B0 + 0x8C1C0906, // 01AA GETMET R7 R4 K6 + 0x8824090F, // 01AB GETMBR R9 R4 K15 + 0x542A0004, // 01AC LDINT R10 5 + 0x7C1C0600, // 01AD CALL R7 3 + 0x80040E00, // 01AE RET 1 R7 + 0x70020024, // 01AF JMP #01D5 + 0x1C1C0D10, // 01B0 EQ R7 R6 K16 + 0x781E000B, // 01B1 JMPF R7 #01BE + 0x881C0134, // 01B2 GETMBR R7 R0 K52 + 0x881C0F35, // 01B3 GETMBR R7 R7 K53 + 0x8C1C0F36, // 01B4 GETMET R7 R7 K54 + 0x7C1C0200, // 01B5 CALL R7 1 + 0x8C200906, // 01B6 GETMET R8 R4 K6 + 0x8828090F, // 01B7 GETMBR R10 R4 K15 + 0x602C000C, // 01B8 GETGBL R11 G12 + 0x5C300E00, // 01B9 MOVE R12 R7 + 0x7C2C0200, // 01BA CALL R11 1 + 0x7C200600, // 01BB CALL R8 3 + 0x80041000, // 01BC RET 1 R8 + 0x70020016, // 01BD JMP #01D5 + 0x541E0003, // 01BE LDINT R7 4 + 0x1C1C0C07, // 01BF EQ R7 R6 R7 + 0x781E0000, // 01C0 JMPF R7 #01C2 + 0x70020012, // 01C1 JMP #01D5 + 0x541E0004, // 01C2 LDINT R7 5 + 0x1C1C0C07, // 01C3 EQ R7 R6 R7 + 0x781E000F, // 01C4 JMPF R7 #01D5 + 0x881C0134, // 01C5 GETMBR R7 R0 K52 + 0x881C0F35, // 01C6 GETMBR R7 R7 K53 + 0x8C1C0F36, // 01C7 GETMET R7 R7 K54 + 0x7C1C0200, // 01C8 CALL R7 1 + 0x8C200F1C, // 01C9 GETMET R8 R7 K28 + 0x88280308, // 01CA GETMBR R10 R1 K8 + 0x7C200400, // 01CB CALL R8 2 + 0x4C240000, // 01CC LDNIL R9 + 0x1C241009, // 01CD EQ R9 R8 R9 + 0x78260000, // 01CE JMPF R9 #01D0 + 0x58200005, // 01CF LDCONST R8 K5 + 0x8C240906, // 01D0 GETMET R9 R4 K6 + 0x882C090F, // 01D1 GETMBR R11 R4 K15 + 0x5C301000, // 01D2 MOVE R12 R8 + 0x7C240600, // 01D3 CALL R9 3 + 0x80041200, // 01D4 RET 1 R9 + 0x70020108, // 01D5 JMP #02DF + 0x541E003B, // 01D6 LDINT R7 60 + 0x1C1C0A07, // 01D7 EQ R7 R5 R7 + 0x781E0000, // 01D8 JMPF R7 #01DA + 0x70020104, // 01D9 JMP #02DF + 0x541E0027, // 01DA LDINT R7 40 + 0x1C1C0A07, // 01DB EQ R7 R5 R7 + 0x781E0071, // 01DC JMPF R7 #024F + 0x1C1C0D05, // 01DD EQ R7 R6 K5 + 0x781E0005, // 01DE JMPF R7 #01E5 + 0x8C1C0906, // 01DF GETMET R7 R4 K6 + 0x8824090D, // 01E0 GETMBR R9 R4 K13 + 0x58280005, // 01E1 LDCONST R10 K5 + 0x7C1C0600, // 01E2 CALL R7 3 + 0x80040E00, // 01E3 RET 1 R7 + 0x70020068, // 01E4 JMP #024E + 0x1C1C0D0A, // 01E5 EQ R7 R6 K10 + 0x781E0005, // 01E6 JMPF R7 #01ED + 0x8C1C0906, // 01E7 GETMET R7 R4 K6 + 0x88240917, // 01E8 GETMBR R9 R4 K23 + 0x58280042, // 01E9 LDCONST R10 K66 + 0x7C1C0600, // 01EA CALL R7 3 + 0x80040E00, // 01EB RET 1 R7 + 0x70020060, // 01EC JMP #024E + 0x1C1C0D0E, // 01ED EQ R7 R6 K14 + 0x781E0006, // 01EE JMPF R7 #01F6 + 0x8C1C0906, // 01EF GETMET R7 R4 K6 + 0x8824090D, // 01F0 GETMBR R9 R4 K13 + 0x88280134, // 01F1 GETMBR R10 R0 K52 + 0x88281543, // 01F2 GETMBR R10 R10 K67 + 0x7C1C0600, // 01F3 CALL R7 3 + 0x80040E00, // 01F4 RET 1 R7 + 0x70020057, // 01F5 JMP #024E + 0x1C1C0D10, // 01F6 EQ R7 R6 K16 + 0x781E0009, // 01F7 JMPF R7 #0202 + 0x8C1C0906, // 01F8 GETMET R7 R4 K6 + 0x88240917, // 01F9 GETMBR R9 R4 K23 + 0xB82A2600, // 01FA GETNGBL R10 K19 + 0x8C281527, // 01FB GETMET R10 R10 K39 + 0x58300044, // 01FC LDCONST R12 K68 + 0x7C280400, // 01FD CALL R10 2 + 0x94281544, // 01FE GETIDX R10 R10 K68 + 0x7C1C0600, // 01FF CALL R7 3 + 0x80040E00, // 0200 RET 1 R7 + 0x7002004B, // 0201 JMP #024E + 0x541E0003, // 0202 LDINT R7 4 + 0x1C1C0C07, // 0203 EQ R7 R6 R7 + 0x781E0005, // 0204 JMPF R7 #020B + 0x8C1C0906, // 0205 GETMET R7 R4 K6 + 0x8824090D, // 0206 GETMBR R9 R4 K13 + 0x542A7FFF, // 0207 LDINT R10 32768 + 0x7C1C0600, // 0208 CALL R7 3 + 0x80040E00, // 0209 RET 1 R7 + 0x70020042, // 020A JMP #024E + 0x541E0004, // 020B LDINT R7 5 + 0x1C1C0C07, // 020C EQ R7 R6 R7 + 0x781E0009, // 020D JMPF R7 #0218 + 0x8C1C0906, // 020E GETMET R7 R4 K6 + 0x88240917, // 020F GETMBR R9 R4 K23 + 0xB82A2600, // 0210 GETNGBL R10 K19 + 0x8C281527, // 0211 GETMET R10 R10 K39 + 0x58300045, // 0212 LDCONST R12 K69 + 0x7C280400, // 0213 CALL R10 2 + 0x94281546, // 0214 GETIDX R10 R10 K70 + 0x7C1C0600, // 0215 CALL R7 3 + 0x80040E00, // 0216 RET 1 R7 + 0x70020035, // 0217 JMP #024E + 0x541E0005, // 0218 LDINT R7 6 + 0x1C1C0C07, // 0219 EQ R7 R6 R7 + 0x781E0005, // 021A JMPF R7 #0221 + 0x8C1C0906, // 021B GETMET R7 R4 K6 + 0x88240917, // 021C GETMBR R9 R4 K23 + 0x58280047, // 021D LDCONST R10 K71 + 0x7C1C0600, // 021E CALL R7 3 + 0x80040E00, // 021F RET 1 R7 + 0x7002002C, // 0220 JMP #024E + 0x541E0006, // 0221 LDINT R7 7 + 0x1C1C0C07, // 0222 EQ R7 R6 R7 + 0x781E0005, // 0223 JMPF R7 #022A + 0x8C1C0906, // 0224 GETMET R7 R4 K6 + 0x8824090D, // 0225 GETMBR R9 R4 K13 + 0x58280005, // 0226 LDCONST R10 K5 + 0x7C1C0600, // 0227 CALL R7 3 + 0x80040E00, // 0228 RET 1 R7 + 0x70020023, // 0229 JMP #024E + 0x541E0007, // 022A LDINT R7 8 + 0x1C1C0C07, // 022B EQ R7 R6 R7 + 0x781E000A, // 022C JMPF R7 #0238 + 0x8C1C0906, // 022D GETMET R7 R4 K6 + 0x88240917, // 022E GETMBR R9 R4 K23 + 0xB82A2600, // 022F GETNGBL R10 K19 + 0x8C281527, // 0230 GETMET R10 R10 K39 + 0x58300048, // 0231 LDCONST R12 K72 + 0x7C280400, // 0232 CALL R10 2 + 0x94281549, // 0233 GETIDX R10 R10 K73 + 0x9428154A, // 0234 GETIDX R10 R10 K74 + 0x7C1C0600, // 0235 CALL R7 3 + 0x80040E00, // 0236 RET 1 R7 + 0x70020015, // 0237 JMP #024E + 0x541E0008, // 0238 LDINT R7 9 + 0x1C1C0C07, // 0239 EQ R7 R6 R7 + 0x781E0005, // 023A JMPF R7 #0241 + 0x8C1C0906, // 023B GETMET R7 R4 K6 + 0x8824090D, // 023C GETMBR R9 R4 K13 + 0x58280005, // 023D LDCONST R10 K5 + 0x7C1C0600, // 023E CALL R7 3 + 0x80040E00, // 023F RET 1 R7 + 0x7002000C, // 0240 JMP #024E + 0x541E0009, // 0241 LDINT R7 10 + 0x1C1C0C07, // 0242 EQ R7 R6 R7 + 0x781E0009, // 0243 JMPF R7 #024E + 0x8C1C0906, // 0244 GETMET R7 R4 K6 + 0x88240917, // 0245 GETMBR R9 R4 K23 + 0xB82A2600, // 0246 GETNGBL R10 K19 + 0x8C281527, // 0247 GETMET R10 R10 K39 + 0x58300048, // 0248 LDCONST R12 K72 + 0x7C280400, // 0249 CALL R10 2 + 0x94281549, // 024A GETIDX R10 R10 K73 + 0x9428154B, // 024B GETIDX R10 R10 K75 + 0x7C1C0600, // 024C CALL R7 3 + 0x80040E00, // 024D RET 1 R7 + 0x7002008F, // 024E JMP #02DF + 0x541E003E, // 024F LDINT R7 63 + 0x1C1C0A07, // 0250 EQ R7 R5 R7 + 0x781E0000, // 0251 JMPF R7 #0253 + 0x7002008B, // 0252 JMP #02DF + 0x541E002A, // 0253 LDINT R7 43 + 0x1C1C0A07, // 0254 EQ R7 R5 R7 + 0x781E0016, // 0255 JMPF R7 #026D + 0x1C1C0D05, // 0256 EQ R7 R6 K5 + 0x781E0007, // 0257 JMPF R7 #0260 + 0x8C1C0906, // 0258 GETMET R7 R4 K6 + 0x88240917, // 0259 GETMBR R9 R4 K23 + 0xB82A2600, // 025A GETNGBL R10 K19 + 0x8C28154C, // 025B GETMET R10 R10 K76 + 0x7C280200, // 025C CALL R10 1 + 0x7C1C0600, // 025D CALL R7 3 + 0x80040E00, // 025E RET 1 R7 + 0x7002000B, // 025F JMP #026C + 0x1C1C0D0A, // 0260 EQ R7 R6 K10 + 0x781E0009, // 0261 JMPF R7 #026C + 0x8C1C094D, // 0262 GETMET R7 R4 K77 + 0x7C1C0200, // 0263 CALL R7 1 + 0x8C200F0C, // 0264 GETMET R8 R7 K12 + 0x4C280000, // 0265 LDNIL R10 + 0x882C0917, // 0266 GETMBR R11 R4 K23 + 0xB8322600, // 0267 GETNGBL R12 K19 + 0x8C30194C, // 0268 GETMET R12 R12 K76 + 0x7C300200, // 0269 CALL R12 1 + 0x7C200800, // 026A CALL R8 4 + 0x80040E00, // 026B RET 1 R7 + 0x70020071, // 026C JMP #02DF + 0x541E002B, // 026D LDINT R7 44 + 0x1C1C0A07, // 026E EQ R7 R5 R7 + 0x781E001C, // 026F JMPF R7 #028D + 0x1C1C0D05, // 0270 EQ R7 R6 K5 + 0x781E0005, // 0271 JMPF R7 #0278 + 0x8C1C0906, // 0272 GETMET R7 R4 K6 + 0x8824090F, // 0273 GETMBR R9 R4 K15 + 0x5828000A, // 0274 LDCONST R10 K10 + 0x7C1C0600, // 0275 CALL R7 3 + 0x80040E00, // 0276 RET 1 R7 + 0x70020013, // 0277 JMP #028C + 0x1C1C0D0A, // 0278 EQ R7 R6 K10 + 0x781E0005, // 0279 JMPF R7 #0280 + 0x8C1C0906, // 027A GETMET R7 R4 K6 + 0x8824090F, // 027B GETMBR R9 R4 K15 + 0x542A0003, // 027C LDINT R10 4 + 0x7C1C0600, // 027D CALL R7 3 + 0x80040E00, // 027E RET 1 R7 + 0x7002000B, // 027F JMP #028C + 0x1C1C0D0E, // 0280 EQ R7 R6 K14 + 0x781E0009, // 0281 JMPF R7 #028C + 0x8C1C094D, // 0282 GETMET R7 R4 K77 + 0x7C1C0200, // 0283 CALL R7 1 + 0x8C200F0C, // 0284 GETMET R8 R7 K12 + 0x4C280000, // 0285 LDNIL R10 + 0x8C2C0906, // 0286 GETMET R11 R4 K6 + 0x8834090F, // 0287 GETMBR R13 R4 K15 + 0x543A0003, // 0288 LDINT R14 4 + 0x7C2C0600, // 0289 CALL R11 3 + 0x7C200600, // 028A CALL R8 3 + 0x80040E00, // 028B RET 1 R7 + 0x70020051, // 028C JMP #02DF + 0x541E0030, // 028D LDINT R7 49 + 0x1C1C0A07, // 028E EQ R7 R5 R7 + 0x781E0010, // 028F JMPF R7 #02A1 + 0x1C1C0D10, // 0290 EQ R7 R6 K16 + 0x781E0005, // 0291 JMPF R7 #0298 + 0x8C1C0906, // 0292 GETMET R7 R4 K6 + 0x8824090F, // 0293 GETMBR R9 R4 K15 + 0x542A001D, // 0294 LDINT R10 30 + 0x7C1C0600, // 0295 CALL R7 3 + 0x80040E00, // 0296 RET 1 R7 + 0x70020007, // 0297 JMP #02A0 + 0x541EFFFB, // 0298 LDINT R7 65532 + 0x1C1C0C07, // 0299 EQ R7 R6 R7 + 0x781E0004, // 029A JMPF R7 #02A0 + 0x8C1C0906, // 029B GETMET R7 R4 K6 + 0x8824092B, // 029C GETMBR R9 R4 K43 + 0x58280005, // 029D LDCONST R10 K5 + 0x7C1C0600, // 029E CALL R7 3 + 0x80040E00, // 029F RET 1 R7 + 0x7002003D, // 02A0 JMP #02DF + 0x541E001C, // 02A1 LDINT R7 29 + 0x1C1C0A07, // 02A2 EQ R7 R5 R7 + 0x781E0037, // 02A3 JMPF R7 #02DC + 0x1C1C0D05, // 02A4 EQ R7 R6 K5 + 0x781E0000, // 02A5 JMPF R7 #02A7 + 0x70020033, // 02A6 JMP #02DB + 0x1C1C0D0A, // 02A7 EQ R7 R6 K10 + 0x781E0013, // 02A8 JMPF R7 #02BD + 0x8C1C0912, // 02A9 GETMET R7 R4 K18 + 0x7C1C0200, // 02AA CALL R7 1 + 0x60200010, // 02AB GETGBL R8 G16 + 0x8C24014E, // 02AC GETMET R9 R0 K78 + 0x7C240200, // 02AD CALL R9 1 + 0x7C200200, // 02AE CALL R8 1 + 0xA8020007, // 02AF EXBLK 0 #02B8 + 0x5C241000, // 02B0 MOVE R9 R8 + 0x7C240000, // 02B1 CALL R9 0 + 0x8C280F0C, // 02B2 GETMET R10 R7 K12 + 0x4C300000, // 02B3 LDNIL R12 + 0x8834092B, // 02B4 GETMBR R13 R4 K43 + 0x5C381200, // 02B5 MOVE R14 R9 + 0x7C280800, // 02B6 CALL R10 4 + 0x7001FFF7, // 02B7 JMP #02B0 + 0x5820003A, // 02B8 LDCONST R8 K58 + 0xAC200200, // 02B9 CATCH R8 1 0 + 0xB0080000, // 02BA RAISE 2 R0 R0 + 0x80040E00, // 02BB RET 1 R7 + 0x7002001D, // 02BC JMP #02DB + 0x1C1C0D0E, // 02BD EQ R7 R6 K14 + 0x781E0003, // 02BE JMPF R7 #02C3 + 0x8C1C0912, // 02BF GETMET R7 R4 K18 + 0x7C1C0200, // 02C0 CALL R7 1 + 0x80040E00, // 02C1 RET 1 R7 + 0x70020017, // 02C2 JMP #02DB + 0x1C1C0D10, // 02C3 EQ R7 R6 K16 + 0x781E0015, // 02C4 JMPF R7 #02DB + 0x881C0134, // 02C5 GETMBR R7 R0 K52 + 0x8C1C0F4F, // 02C6 GETMET R7 R7 K79 + 0x50240200, // 02C7 LDBOOL R9 1 0 + 0x7C1C0400, // 02C8 CALL R7 2 + 0x8C200912, // 02C9 GETMET R8 R4 K18 + 0x7C200200, // 02CA CALL R8 1 + 0x60240010, // 02CB GETGBL R9 G16 + 0x5C280E00, // 02CC MOVE R10 R7 + 0x7C240200, // 02CD CALL R9 1 + 0xA8020007, // 02CE EXBLK 0 #02D7 + 0x5C281200, // 02CF MOVE R10 R9 + 0x7C280000, // 02D0 CALL R10 0 + 0x8C2C110C, // 02D1 GETMET R11 R8 K12 + 0x4C340000, // 02D2 LDNIL R13 + 0x8838090D, // 02D3 GETMBR R14 R4 K13 + 0x5C3C1400, // 02D4 MOVE R15 R10 + 0x7C2C0800, // 02D5 CALL R11 4 + 0x7001FFF7, // 02D6 JMP #02CF + 0x5824003A, // 02D7 LDCONST R9 K58 + 0xAC240200, // 02D8 CATCH R9 1 0 + 0xB0080000, // 02D9 RAISE 2 R0 R0 + 0x80041000, // 02DA RET 1 R8 + 0x70020002, // 02DB JMP #02DF + 0xB81E0200, // 02DC GETNGBL R7 K1 + 0x881C0F51, // 02DD GETMBR R7 R7 K81 + 0x900AA007, // 02DE SETMBR R2 K80 R7 + 0x80000000, // 02DF RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_Plugin_core_init, /* name */ + be_nested_proto( + 5, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(init), + /* K1 */ be_nested_str_weak(endpoints), + /* K2 */ be_nested_str_weak(ENDPOINTS), + /* K3 */ be_nested_str_weak(clusters), + /* K4 */ be_nested_str_weak(CLUSTERS), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[11]) { /* code */ + 0x60080003, // 0000 GETGBL R2 G3 + 0x5C0C0000, // 0001 MOVE R3 R0 + 0x7C080200, // 0002 CALL R2 1 + 0x8C080500, // 0003 GETMET R2 R2 K0 + 0x5C100200, // 0004 MOVE R4 R1 + 0x7C080400, // 0005 CALL R2 2 + 0x88080102, // 0006 GETMBR R2 R0 K2 + 0x90020202, // 0007 SETMBR R0 K1 R2 + 0x88080104, // 0008 GETMBR R2 R0 K4 + 0x90020602, // 0009 SETMBR R0 K3 R2 + 0x80000000, // 000A RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified class: Matter_Plugin_core ********************************************************************/ @@ -1392,11 +1487,111 @@ extern const bclass be_class_Matter_Plugin; be_local_class(Matter_Plugin_core, 0, &be_class_Matter_Plugin, - be_nested_map(3, + be_nested_map(5, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(read_attribute, 1), be_const_closure(Matter_Plugin_core_read_attribute_closure) }, + { be_const_key_weak(ENDPOINTS, 3), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(1, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + })) ) } )) }, + { be_const_key_weak(read_attribute, -1), be_const_closure(Matter_Plugin_core_read_attribute_closure) }, + { be_const_key_weak(invoke_request, 1), be_const_closure(Matter_Plugin_core_invoke_request_closure) }, { be_const_key_weak(init, -1), be_const_closure(Matter_Plugin_core_init_closure) }, - { be_const_key_weak(invoke_request, -1), be_const_closure(Matter_Plugin_core_invoke_request_closure) }, + { be_const_key_weak(CLUSTERS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + be_const_map( * be_nested_map(13, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_int(52, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(0, + ( (struct bvalue*) &(const bvalue[]) { + })) ) } )) }, + { be_const_key_int(40, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(10, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(4), + be_const_int(5), + be_const_int(6), + be_const_int(7), + be_const_int(8), + be_const_int(9), + })) ) } )) }, + { be_const_key_int(43, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(2, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + })) ) } )) }, + { be_const_key_int(29, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(4, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + })) ) } )) }, + { be_const_key_int(56, 2), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(3, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(7), + })) ) } )) }, + { be_const_key_int(44, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(3, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + })) ) } )) }, + { be_const_key_int(62, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(6, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(4), + be_const_int(5), + })) ) } )) }, + { be_const_key_int(50, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(0, + ( (struct bvalue*) &(const bvalue[]) { + })) ) } )) }, + { be_const_key_int(60, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(0, + ( (struct bvalue*) &(const bvalue[]) { + })) ) } )) }, + { be_const_key_int(48, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(5, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(4), + })) ) } )) }, + { be_const_key_int(49, 6), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(2, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(3), + be_const_int(65532), + })) ) } )) }, + { be_const_key_int(63, 7), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(0, + ( (struct bvalue*) &(const bvalue[]) { + })) ) } )) }, + { be_const_key_int(51, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(4, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(8), + })) ) } )) }, + })) ) } )) }, })), be_str_weak(Matter_Plugin_core) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Session.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Session.h index 3b4a450b0..45fcfe981 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Session.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Session.h @@ -7,11 +7,11 @@ extern const bclass be_class_Matter_Session; /******************************************************************** -** Solidified function: get_ca_pub +** Solidified function: save ********************************************************************/ -be_local_closure(Matter_Session_get_ca_pub, /* name */ +be_local_closure(Matter_Session_save, /* name */ be_nested_proto( - 5, /* nstack */ + 3, /* nstack */ 1, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -19,28 +19,345 @@ be_local_closure(Matter_Session_get_ca_pub, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 5]) { /* constants */ - /* K0 */ be_nested_str_weak(root_ca_certificate), - /* K1 */ be_nested_str_weak(matter), - /* K2 */ be_nested_str_weak(TLV), - /* K3 */ be_nested_str_weak(parse), - /* K4 */ be_nested_str_weak(findsubval), + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(__store), + /* K1 */ be_nested_str_weak(save), }), - be_str_weak(get_ca_pub), + be_str_weak(save), &be_const_str_solidified, - ( &(const binstruction[12]) { /* code */ + ( &(const binstruction[ 4]) { /* code */ 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x78060008, // 0001 JMPF R1 #000B - 0xB8060200, // 0002 GETNGBL R1 K1 - 0x88040302, // 0003 GETMBR R1 R1 K2 - 0x8C040303, // 0004 GETMET R1 R1 K3 - 0x880C0100, // 0005 GETMBR R3 R0 K0 - 0x7C040400, // 0006 CALL R1 2 - 0x8C080304, // 0007 GETMET R2 R1 K4 - 0x54120008, // 0008 LDINT R4 9 - 0x7C080400, // 0009 CALL R2 2 - 0x80040400, // 000A RET 1 R2 - 0x80000000, // 000B RET 0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0x7C040200, // 0002 CALL R1 1 + 0x80000000, // 0003 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_expire_in_seconds +********************************************************************/ +be_local_closure(Matter_Session_set_expire_in_seconds, /* name */ + be_nested_proto( + 6, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(tasmota), + /* K1 */ be_nested_str_weak(rtc), + /* K2 */ be_nested_str_weak(utc), + /* K3 */ be_nested_str_weak(set_expire_time), + }), + be_str_weak(set_expire_in_seconds), + &be_const_str_solidified, + ( &(const binstruction[15]) { /* code */ + 0x4C0C0000, // 0000 LDNIL R3 + 0x1C0C0203, // 0001 EQ R3 R1 R3 + 0x780E0000, // 0002 JMPF R3 #0004 + 0x80000600, // 0003 RET 0 + 0x4C0C0000, // 0004 LDNIL R3 + 0x1C0C0403, // 0005 EQ R3 R2 R3 + 0x780E0003, // 0006 JMPF R3 #000B + 0xB80E0000, // 0007 GETNGBL R3 K0 + 0x8C0C0701, // 0008 GETMET R3 R3 K1 + 0x7C0C0200, // 0009 CALL R3 1 + 0x94080702, // 000A GETIDX R2 R3 K2 + 0x8C0C0103, // 000B GETMET R3 R0 K3 + 0x00140401, // 000C ADD R5 R2 R1 + 0x7C0C0400, // 000D CALL R3 2 + 0x80000000, // 000E RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_i2r_privacy +********************************************************************/ +be_local_closure(Matter_Session_get_i2r_privacy, /* name */ + be_nested_proto( + 9, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 7]) { /* constants */ + /* K0 */ be_nested_str_weak(_i2r_privacy), + /* K1 */ be_nested_str_weak(crypto), + /* K2 */ be_nested_str_weak(HKDF_SHA256), + /* K3 */ be_nested_str_weak(derive), + /* K4 */ be_nested_str_weak(get_i2r), + /* K5 */ be_nested_str_weak(fromstring), + /* K6 */ be_nested_str_weak(PrivacyKey), + }), + be_str_weak(get_i2r_privacy), + &be_const_str_solidified, + ( &(const binstruction[22]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x4C080000, // 0001 LDNIL R2 + 0x1C040202, // 0002 EQ R1 R1 R2 + 0x7806000F, // 0003 JMPF R1 #0014 + 0xA4060200, // 0004 IMPORT R1 K1 + 0x8C080302, // 0005 GETMET R2 R1 K2 + 0x7C080200, // 0006 CALL R2 1 + 0x8C080503, // 0007 GETMET R2 R2 K3 + 0x8C100104, // 0008 GETMET R4 R0 K4 + 0x7C100200, // 0009 CALL R4 1 + 0x60140015, // 000A GETGBL R5 G21 + 0x7C140000, // 000B CALL R5 0 + 0x60180015, // 000C GETGBL R6 G21 + 0x7C180000, // 000D CALL R6 0 + 0x8C180D05, // 000E GETMET R6 R6 K5 + 0x58200006, // 000F LDCONST R8 K6 + 0x7C180400, // 0010 CALL R6 2 + 0x541E000F, // 0011 LDINT R7 16 + 0x7C080A00, // 0012 CALL R2 5 + 0x90020002, // 0013 SETMBR R0 K0 R2 + 0x88040100, // 0014 GETMBR R1 R0 K0 + 0x80040200, // 0015 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: has_expired +********************************************************************/ +be_local_closure(Matter_Session_has_expired, /* name */ + be_nested_proto( + 4, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(tasmota), + /* K1 */ be_nested_str_weak(rtc), + /* K2 */ be_nested_str_weak(utc), + /* K3 */ be_nested_str_weak(expiration), + }), + be_str_weak(has_expired), + &be_const_str_solidified, + ( &(const binstruction[16]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0003, // 0002 JMPF R2 #0007 + 0xB80A0000, // 0003 GETNGBL R2 K0 + 0x8C080501, // 0004 GETMET R2 R2 K1 + 0x7C080200, // 0005 CALL R2 1 + 0x94040502, // 0006 GETIDX R1 R2 K2 + 0x88080103, // 0007 GETMBR R2 R0 K3 + 0x4C0C0000, // 0008 LDNIL R3 + 0x20080403, // 0009 NE R2 R2 R3 + 0x780A0002, // 000A JMPF R2 #000E + 0x88080103, // 000B GETMBR R2 R0 K3 + 0x28080202, // 000C GE R2 R1 R2 + 0x80040400, // 000D RET 1 R2 + 0x50080000, // 000E LDBOOL R2 0 0 + 0x80040400, // 000F RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_icac +********************************************************************/ +be_local_closure(Matter_Session_get_icac, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(icac), + }), + be_str_weak(get_icac), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_deviceid +********************************************************************/ +be_local_closure(Matter_Session_get_deviceid, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(deviceid), + }), + be_str_weak(get_deviceid), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_noc +********************************************************************/ +be_local_closure(Matter_Session_get_noc, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(noc), + }), + be_str_weak(get_noc), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: close +********************************************************************/ +be_local_closure(Matter_Session_close, /* name */ + be_nested_proto( + 9, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[24]) { /* constants */ + /* K0 */ be_nested_str_weak(_persist), + /* K1 */ be_nested_str_weak(local_session_id), + /* K2 */ be_nested_str_weak(_future_local_session_id), + /* K3 */ be_nested_str_weak(initiator_session_id), + /* K4 */ be_nested_str_weak(_future_initiator_session_id), + /* K5 */ be_nested_str_weak(source_node_id), + /* K6 */ be_nested_str_weak(counter_rcv), + /* K7 */ be_nested_str_weak(reset), + /* K8 */ be_nested_str_weak(counter_snd), + /* K9 */ be_nested_str_weak(i2rkey), + /* K10 */ be_nested_str_weak(_i2r_privacy), + /* K11 */ be_nested_str_weak(r2ikey), + /* K12 */ be_nested_str_weak(attestation_challenge), + /* K13 */ be_nested_str_weak(fabric_label), + /* K14 */ be_nested_str_weak(), + /* K15 */ be_nested_str_weak(introspect), + /* K16 */ be_nested_str_weak(members), + /* K17 */ be_nested_str_weak(get), + /* K18 */ be_nested_str_weak(function), + /* K19 */ be_nested_str_weak(instance), + /* K20 */ be_const_int(0), + /* K21 */ be_nested_str_weak(_), + /* K22 */ be_const_int(1), + /* K23 */ be_nested_str_weak(stop_iteration), + }), + be_str_weak(close), + &be_const_str_solidified, + ( &(const binstruction[59]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x88080102, // 0001 GETMBR R2 R0 K2 + 0x90020202, // 0002 SETMBR R0 K1 R2 + 0x88080104, // 0003 GETMBR R2 R0 K4 + 0x90020602, // 0004 SETMBR R0 K3 R2 + 0x4C080000, // 0005 LDNIL R2 + 0x90020A02, // 0006 SETMBR R0 K5 R2 + 0x88080106, // 0007 GETMBR R2 R0 K6 + 0x8C080507, // 0008 GETMET R2 R2 K7 + 0x7C080200, // 0009 CALL R2 1 + 0x88080108, // 000A GETMBR R2 R0 K8 + 0x8C080507, // 000B GETMET R2 R2 K7 + 0x7C080200, // 000C CALL R2 1 + 0x4C080000, // 000D LDNIL R2 + 0x90021202, // 000E SETMBR R0 K9 R2 + 0x4C080000, // 000F LDNIL R2 + 0x90021402, // 0010 SETMBR R0 K10 R2 + 0x4C080000, // 0011 LDNIL R2 + 0x90021602, // 0012 SETMBR R0 K11 R2 + 0x4C080000, // 0013 LDNIL R2 + 0x90021802, // 0014 SETMBR R0 K12 R2 + 0x90021B0E, // 0015 SETMBR R0 K13 K14 + 0xA40A1E00, // 0016 IMPORT R2 K15 + 0x600C0010, // 0017 GETGBL R3 G16 + 0x8C100510, // 0018 GETMET R4 R2 K16 + 0x5C180000, // 0019 MOVE R6 R0 + 0x7C100400, // 001A CALL R4 2 + 0x7C0C0200, // 001B CALL R3 1 + 0xA8020018, // 001C EXBLK 0 #0036 + 0x5C100600, // 001D MOVE R4 R3 + 0x7C100000, // 001E CALL R4 0 + 0x8C140511, // 001F GETMET R5 R2 K17 + 0x5C1C0000, // 0020 MOVE R7 R0 + 0x5C200800, // 0021 MOVE R8 R4 + 0x7C140600, // 0022 CALL R5 3 + 0x60180004, // 0023 GETGBL R6 G4 + 0x5C1C0A00, // 0024 MOVE R7 R5 + 0x7C180200, // 0025 CALL R6 1 + 0x20180D12, // 0026 NE R6 R6 K18 + 0x781A000C, // 0027 JMPF R6 #0035 + 0x60180004, // 0028 GETGBL R6 G4 + 0x5C1C0A00, // 0029 MOVE R7 R5 + 0x7C180200, // 002A CALL R6 1 + 0x20180D13, // 002B NE R6 R6 K19 + 0x781A0007, // 002C JMPF R6 #0035 + 0x94180914, // 002D GETIDX R6 R4 K20 + 0x1C180D15, // 002E EQ R6 R6 K21 + 0x781A0004, // 002F JMPF R6 #0035 + 0x94180916, // 0030 GETIDX R6 R4 K22 + 0x20180D15, // 0031 NE R6 R6 K21 + 0x781A0001, // 0032 JMPF R6 #0035 + 0x4C180000, // 0033 LDNIL R6 + 0x90000806, // 0034 SETMBR R0 R4 R6 + 0x7001FFE6, // 0035 JMP #001D + 0x580C0017, // 0036 LDCONST R3 K23 + 0xAC0C0200, // 0037 CATCH R3 1 0 + 0xB0080000, // 0038 RAISE 2 R0 R0 + 0x90020001, // 0039 SETMBR R0 K0 R1 + 0x80000000, // 003A RET 0 }) ) ); @@ -179,9 +496,9 @@ be_local_closure(Matter_Session_fromjson, /* name */ /******************************************************************** -** Solidified function: get_fabric_compressed +** Solidified function: get_ipk_epoch_key ********************************************************************/ -be_local_closure(Matter_Session_get_fabric_compressed, /* name */ +be_local_closure(Matter_Session_get_ipk_epoch_key, /* name */ be_nested_proto( 2, /* nstack */ 1, /* argc */ @@ -192,136 +509,9 @@ be_local_closure(Matter_Session_get_fabric_compressed, /* name */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(fabric_compressed), - }), - be_str_weak(get_fabric_compressed), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: set_expire_time -********************************************************************/ -be_local_closure(Matter_Session_set_expire_time, /* name */ - be_nested_proto( - 4, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(expiration), - }), - be_str_weak(set_expire_time), - &be_const_str_solidified, - ( &(const binstruction[ 5]) { /* code */ - 0x60080009, // 0000 GETGBL R2 G9 - 0x5C0C0200, // 0001 MOVE R3 R1 - 0x7C080200, // 0002 CALL R2 1 - 0x90020002, // 0003 SETMBR R0 K0 R2 - 0x80000000, // 0004 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: set_expire_in_seconds -********************************************************************/ -be_local_closure(Matter_Session_set_expire_in_seconds, /* name */ - be_nested_proto( - 6, /* nstack */ - 3, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 4]) { /* constants */ - /* K0 */ be_nested_str_weak(tasmota), - /* K1 */ be_nested_str_weak(rtc), - /* K2 */ be_nested_str_weak(utc), - /* K3 */ be_nested_str_weak(set_expire_time), - }), - be_str_weak(set_expire_in_seconds), - &be_const_str_solidified, - ( &(const binstruction[15]) { /* code */ - 0x4C0C0000, // 0000 LDNIL R3 - 0x1C0C0203, // 0001 EQ R3 R1 R3 - 0x780E0000, // 0002 JMPF R3 #0004 - 0x80000600, // 0003 RET 0 - 0x4C0C0000, // 0004 LDNIL R3 - 0x1C0C0403, // 0005 EQ R3 R2 R3 - 0x780E0003, // 0006 JMPF R3 #000B - 0xB80E0000, // 0007 GETNGBL R3 K0 - 0x8C0C0701, // 0008 GETMET R3 R3 K1 - 0x7C0C0200, // 0009 CALL R3 1 - 0x94080702, // 000A GETIDX R2 R3 K2 - 0x8C0C0103, // 000B GETMET R3 R0 K3 - 0x00140401, // 000C ADD R5 R2 R1 - 0x7C0C0400, // 000D CALL R3 2 - 0x80000000, // 000E RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: set_ipk_epoch_key -********************************************************************/ -be_local_closure(Matter_Session_set_ipk_epoch_key, /* name */ - be_nested_proto( - 2, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ /* K0 */ be_nested_str_weak(ipk_epoch_key), }), - be_str_weak(set_ipk_epoch_key), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x90020001, // 0000 SETMBR R0 K0 R1 - 0x80000000, // 0001 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_noc -********************************************************************/ -be_local_closure(Matter_Session_get_noc, /* name */ - be_nested_proto( - 2, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(noc), - }), - be_str_weak(get_noc), + be_str_weak(get_ipk_epoch_key), &be_const_str_solidified, ( &(const binstruction[ 2]) { /* code */ 0x88040100, // 0000 GETMBR R1 R0 K0 @@ -479,46 +669,9 @@ be_local_closure(Matter_Session_tojson, /* name */ /******************************************************************** -** Solidified function: set_fabric_device +** Solidified function: get_ac ********************************************************************/ -be_local_closure(Matter_Session_set_fabric_device, /* name */ - be_nested_proto( - 7, /* nstack */ - 4, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 5]) { /* constants */ - /* K0 */ be_nested_str_weak(fabric), - /* K1 */ be_nested_str_weak(deviceid), - /* K2 */ be_nested_str_weak(fabric_compressed), - /* K3 */ be_nested_str_weak(__store), - /* K4 */ be_nested_str_weak(remove_redundant_session), - }), - be_str_weak(set_fabric_device), - &be_const_str_solidified, - ( &(const binstruction[ 8]) { /* code */ - 0x90020001, // 0000 SETMBR R0 K0 R1 - 0x90020202, // 0001 SETMBR R0 K1 R2 - 0x90020403, // 0002 SETMBR R0 K2 R3 - 0x88100103, // 0003 GETMBR R4 R0 K3 - 0x8C100904, // 0004 GETMET R4 R4 K4 - 0x5C180000, // 0005 MOVE R6 R0 - 0x7C100400, // 0006 CALL R4 2 - 0x80000000, // 0007 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_deviceid -********************************************************************/ -be_local_closure(Matter_Session_get_deviceid, /* name */ +be_local_closure(Matter_Session_get_ac, /* name */ be_nested_proto( 2, /* nstack */ 1, /* argc */ @@ -529,9 +682,9 @@ be_local_closure(Matter_Session_get_deviceid, /* name */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(deviceid), + /* K0 */ be_nested_str_weak(attestation_challenge), }), - be_str_weak(get_deviceid), + be_str_weak(get_ac), &be_const_str_solidified, ( &(const binstruction[ 2]) { /* code */ 0x88040100, // 0000 GETMBR R1 R0 K0 @@ -542,6 +695,34 @@ be_local_closure(Matter_Session_get_deviceid, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: set_no_expiration +********************************************************************/ +be_local_closure(Matter_Session_set_no_expiration, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(expiration), + }), + be_str_weak(set_no_expiration), + &be_const_str_solidified, + ( &(const binstruction[ 3]) { /* code */ + 0x4C040000, // 0000 LDNIL R1 + 0x90020001, // 0001 SETMBR R0 K0 R1 + 0x80000000, // 0002 RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: get_r2i ********************************************************************/ @@ -569,6 +750,33 @@ be_local_closure(Matter_Session_get_r2i, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: get_fabric_compressed +********************************************************************/ +be_local_closure(Matter_Session_get_fabric_compressed, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(fabric_compressed), + }), + be_str_weak(get_fabric_compressed), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: set_fabric_label ********************************************************************/ @@ -603,106 +811,26 @@ be_local_closure(Matter_Session_set_fabric_label, /* name */ /******************************************************************** -** Solidified function: close +** Solidified function: set_ipk_epoch_key ********************************************************************/ -be_local_closure(Matter_Session_close, /* name */ +be_local_closure(Matter_Session_set_ipk_epoch_key, /* name */ be_nested_proto( - 9, /* nstack */ - 1, /* argc */ + 2, /* nstack */ + 2, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[24]) { /* constants */ - /* K0 */ be_nested_str_weak(_persist), - /* K1 */ be_nested_str_weak(local_session_id), - /* K2 */ be_nested_str_weak(_future_local_session_id), - /* K3 */ be_nested_str_weak(initiator_session_id), - /* K4 */ be_nested_str_weak(_future_initiator_session_id), - /* K5 */ be_nested_str_weak(source_node_id), - /* K6 */ be_nested_str_weak(counter_rcv), - /* K7 */ be_nested_str_weak(reset), - /* K8 */ be_nested_str_weak(counter_snd), - /* K9 */ be_nested_str_weak(i2rkey), - /* K10 */ be_nested_str_weak(_i2r_privacy), - /* K11 */ be_nested_str_weak(r2ikey), - /* K12 */ be_nested_str_weak(attestation_challenge), - /* K13 */ be_nested_str_weak(fabric_label), - /* K14 */ be_nested_str_weak(), - /* K15 */ be_nested_str_weak(introspect), - /* K16 */ be_nested_str_weak(members), - /* K17 */ be_nested_str_weak(get), - /* K18 */ be_nested_str_weak(function), - /* K19 */ be_nested_str_weak(instance), - /* K20 */ be_const_int(0), - /* K21 */ be_nested_str_weak(_), - /* K22 */ be_const_int(1), - /* K23 */ be_nested_str_weak(stop_iteration), + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(ipk_epoch_key), }), - be_str_weak(close), + be_str_weak(set_ipk_epoch_key), &be_const_str_solidified, - ( &(const binstruction[59]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x88080102, // 0001 GETMBR R2 R0 K2 - 0x90020202, // 0002 SETMBR R0 K1 R2 - 0x88080104, // 0003 GETMBR R2 R0 K4 - 0x90020602, // 0004 SETMBR R0 K3 R2 - 0x4C080000, // 0005 LDNIL R2 - 0x90020A02, // 0006 SETMBR R0 K5 R2 - 0x88080106, // 0007 GETMBR R2 R0 K6 - 0x8C080507, // 0008 GETMET R2 R2 K7 - 0x7C080200, // 0009 CALL R2 1 - 0x88080108, // 000A GETMBR R2 R0 K8 - 0x8C080507, // 000B GETMET R2 R2 K7 - 0x7C080200, // 000C CALL R2 1 - 0x4C080000, // 000D LDNIL R2 - 0x90021202, // 000E SETMBR R0 K9 R2 - 0x4C080000, // 000F LDNIL R2 - 0x90021402, // 0010 SETMBR R0 K10 R2 - 0x4C080000, // 0011 LDNIL R2 - 0x90021602, // 0012 SETMBR R0 K11 R2 - 0x4C080000, // 0013 LDNIL R2 - 0x90021802, // 0014 SETMBR R0 K12 R2 - 0x90021B0E, // 0015 SETMBR R0 K13 K14 - 0xA40A1E00, // 0016 IMPORT R2 K15 - 0x600C0010, // 0017 GETGBL R3 G16 - 0x8C100510, // 0018 GETMET R4 R2 K16 - 0x5C180000, // 0019 MOVE R6 R0 - 0x7C100400, // 001A CALL R4 2 - 0x7C0C0200, // 001B CALL R3 1 - 0xA8020018, // 001C EXBLK 0 #0036 - 0x5C100600, // 001D MOVE R4 R3 - 0x7C100000, // 001E CALL R4 0 - 0x8C140511, // 001F GETMET R5 R2 K17 - 0x5C1C0000, // 0020 MOVE R7 R0 - 0x5C200800, // 0021 MOVE R8 R4 - 0x7C140600, // 0022 CALL R5 3 - 0x60180004, // 0023 GETGBL R6 G4 - 0x5C1C0A00, // 0024 MOVE R7 R5 - 0x7C180200, // 0025 CALL R6 1 - 0x20180D12, // 0026 NE R6 R6 K18 - 0x781A000C, // 0027 JMPF R6 #0035 - 0x60180004, // 0028 GETGBL R6 G4 - 0x5C1C0A00, // 0029 MOVE R7 R5 - 0x7C180200, // 002A CALL R6 1 - 0x20180D13, // 002B NE R6 R6 K19 - 0x781A0007, // 002C JMPF R6 #0035 - 0x94180914, // 002D GETIDX R6 R4 K20 - 0x1C180D15, // 002E EQ R6 R6 K21 - 0x781A0004, // 002F JMPF R6 #0035 - 0x94180916, // 0030 GETIDX R6 R4 K22 - 0x20180D15, // 0031 NE R6 R6 K21 - 0x781A0001, // 0032 JMPF R6 #0035 - 0x4C180000, // 0033 LDNIL R6 - 0x90000806, // 0034 SETMBR R0 R4 R6 - 0x7001FFE6, // 0035 JMP #001D - 0x580C0017, // 0036 LDCONST R3 K23 - 0xAC0C0200, // 0037 CATCH R3 1 0 - 0xB0080000, // 0038 RAISE 2 R0 R0 - 0x90020001, // 0039 SETMBR R0 K0 R1 - 0x80000000, // 003A RET 0 + ( &(const binstruction[ 2]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x80000000, // 0001 RET 0 }) ) ); @@ -710,28 +838,36 @@ be_local_closure(Matter_Session_close, /* name */ /******************************************************************** -** Solidified function: set_noc +** Solidified function: set_fabric_device ********************************************************************/ -be_local_closure(Matter_Session_set_noc, /* name */ +be_local_closure(Matter_Session_set_fabric_device, /* name */ be_nested_proto( - 3, /* nstack */ - 3, /* argc */ + 7, /* nstack */ + 4, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(noc), - /* K1 */ be_nested_str_weak(icac), + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(fabric), + /* K1 */ be_nested_str_weak(deviceid), + /* K2 */ be_nested_str_weak(fabric_compressed), + /* K3 */ be_nested_str_weak(__store), + /* K4 */ be_nested_str_weak(remove_redundant_session), }), - be_str_weak(set_noc), + be_str_weak(set_fabric_device), &be_const_str_solidified, - ( &(const binstruction[ 3]) { /* code */ + ( &(const binstruction[ 8]) { /* code */ 0x90020001, // 0000 SETMBR R0 K0 R1 0x90020202, // 0001 SETMBR R0 K1 R2 - 0x80000000, // 0002 RET 0 + 0x90020403, // 0002 SETMBR R0 K2 R3 + 0x88100103, // 0003 GETMBR R4 R0 K3 + 0x8C100904, // 0004 GETMET R4 R4 K4 + 0x5C180000, // 0005 MOVE R6 R0 + 0x7C100400, // 0006 CALL R4 2 + 0x80000000, // 0007 RET 0 }) ) ); @@ -739,12 +875,12 @@ be_local_closure(Matter_Session_set_noc, /* name */ /******************************************************************** -** Solidified function: get_mode +** Solidified function: set_persist ********************************************************************/ -be_local_closure(Matter_Session_get_mode, /* name */ +be_local_closure(Matter_Session_set_persist, /* name */ be_nested_proto( - 2, /* nstack */ - 1, /* argc */ + 4, /* nstack */ + 2, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ @@ -752,159 +888,16 @@ be_local_closure(Matter_Session_get_mode, /* name */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(mode), + /* K0 */ be_nested_str_weak(_persist), }), - be_str_weak(get_mode), + be_str_weak(set_persist), &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_ipk_epoch_key -********************************************************************/ -be_local_closure(Matter_Session_get_ipk_epoch_key, /* name */ - be_nested_proto( - 2, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(ipk_epoch_key), - }), - be_str_weak(get_ipk_epoch_key), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_ipk_group_key -********************************************************************/ -be_local_closure(Matter_Session_get_ipk_group_key, /* name */ - be_nested_proto( - 10, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 7]) { /* constants */ - /* K0 */ be_nested_str_weak(ipk_epoch_key), - /* K1 */ be_nested_str_weak(fabric_compressed), - /* K2 */ be_nested_str_weak(crypto), - /* K3 */ be_nested_str_weak(HKDF_SHA256), - /* K4 */ be_nested_str_weak(fromstring), - /* K5 */ be_nested_str_weak(__GROUP_KEY), - /* K6 */ be_nested_str_weak(derive), - }), - be_str_weak(get_ipk_group_key), - &be_const_str_solidified, - ( &(const binstruction[25]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x4C080000, // 0001 LDNIL R2 - 0x1C040202, // 0002 EQ R1 R1 R2 - 0x74060003, // 0003 JMPT R1 #0008 - 0x88040101, // 0004 GETMBR R1 R0 K1 - 0x4C080000, // 0005 LDNIL R2 - 0x1C040202, // 0006 EQ R1 R1 R2 - 0x78060001, // 0007 JMPF R1 #000A - 0x4C040000, // 0008 LDNIL R1 - 0x80040200, // 0009 RET 1 R1 - 0xA4060400, // 000A IMPORT R1 K2 - 0x8C080303, // 000B GETMET R2 R1 K3 - 0x7C080200, // 000C CALL R2 1 - 0x600C0015, // 000D GETGBL R3 G21 - 0x7C0C0000, // 000E CALL R3 0 - 0x8C0C0704, // 000F GETMET R3 R3 K4 - 0x88140105, // 0010 GETMBR R5 R0 K5 - 0x7C0C0400, // 0011 CALL R3 2 - 0x8C100506, // 0012 GETMET R4 R2 K6 - 0x88180100, // 0013 GETMBR R6 R0 K0 - 0x881C0101, // 0014 GETMBR R7 R0 K1 - 0x5C200600, // 0015 MOVE R8 R3 - 0x5426000F, // 0016 LDINT R9 16 - 0x7C100A00, // 0017 CALL R4 5 - 0x80040800, // 0018 RET 1 R4 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_pk -********************************************************************/ -be_local_closure(Matter_Session_get_pk, /* name */ - be_nested_proto( - 5, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_nested_str_weak(no_private_key), - /* K1 */ be_nested_str_weak(crypto), - /* K2 */ be_nested_str_weak(random), - }), - be_str_weak(get_pk), - &be_const_str_solidified, - ( &(const binstruction[ 9]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x74060004, // 0001 JMPT R1 #0007 - 0xA4060200, // 0002 IMPORT R1 K1 - 0x8C080302, // 0003 GETMET R2 R1 K2 - 0x5412001F, // 0004 LDINT R4 32 - 0x7C080400, // 0005 CALL R2 2 - 0x90020002, // 0006 SETMBR R0 K0 R2 - 0x88040100, // 0007 GETMBR R1 R0 K0 - 0x80040200, // 0008 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_ac -********************************************************************/ -be_local_closure(Matter_Session_get_ac, /* name */ - be_nested_proto( - 2, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(attestation_challenge), - }), - be_str_weak(get_ac), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 + ( &(const binstruction[ 5]) { /* code */ + 0x60080017, // 0000 GETGBL R2 G23 + 0x5C0C0200, // 0001 MOVE R3 R1 + 0x7C080200, // 0002 CALL R2 1 + 0x90020002, // 0003 SETMBR R0 K0 R2 + 0x80000000, // 0004 RET 0 }) ) ); @@ -1020,63 +1013,6 @@ be_local_closure(Matter_Session_gen_CSR, /* name */ /*******************************************************************/ -/******************************************************************** -** Solidified function: set_persist -********************************************************************/ -be_local_closure(Matter_Session_set_persist, /* name */ - be_nested_proto( - 4, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(_persist), - }), - be_str_weak(set_persist), - &be_const_str_solidified, - ( &(const binstruction[ 5]) { /* code */ - 0x60080017, // 0000 GETGBL R2 G23 - 0x5C0C0200, // 0001 MOVE R3 R1 - 0x7C080200, // 0002 CALL R2 1 - 0x90020002, // 0003 SETMBR R0 K0 R2 - 0x80000000, // 0004 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_icac -********************************************************************/ -be_local_closure(Matter_Session_get_icac, /* name */ - be_nested_proto( - 2, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(icac), - }), - be_str_weak(get_icac), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified function: set_ca ********************************************************************/ @@ -1105,12 +1041,12 @@ be_local_closure(Matter_Session_set_ca, /* name */ /******************************************************************** -** Solidified function: get_fabric +** Solidified function: set_expire_time ********************************************************************/ -be_local_closure(Matter_Session_get_fabric, /* name */ +be_local_closure(Matter_Session_set_expire_time, /* name */ be_nested_proto( - 2, /* nstack */ - 1, /* argc */ + 4, /* nstack */ + 2, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ @@ -1118,13 +1054,16 @@ be_local_closure(Matter_Session_get_fabric, /* name */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(fabric), + /* K0 */ be_nested_str_weak(expiration), }), - be_str_weak(get_fabric), + be_str_weak(set_expire_time), &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 + ( &(const binstruction[ 5]) { /* code */ + 0x60080009, // 0000 GETGBL R2 G9 + 0x5C0C0200, // 0001 MOVE R3 R1 + 0x7C080200, // 0002 CALL R2 1 + 0x90020002, // 0003 SETMBR R0 K0 R2 + 0x80000000, // 0004 RET 0 }) ) ); @@ -1159,43 +1098,35 @@ be_local_closure(Matter_Session_get_i2r, /* name */ /******************************************************************** -** Solidified function: has_expired +** Solidified function: set_keys ********************************************************************/ -be_local_closure(Matter_Session_has_expired, /* name */ +be_local_closure(Matter_Session_set_keys, /* name */ be_nested_proto( - 4, /* nstack */ - 2, /* argc */ + 6, /* nstack */ + 5, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 4]) { /* constants */ - /* K0 */ be_nested_str_weak(tasmota), - /* K1 */ be_nested_str_weak(rtc), - /* K2 */ be_nested_str_weak(utc), - /* K3 */ be_nested_str_weak(expiration), + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(i2rkey), + /* K1 */ be_nested_str_weak(_i2r_privacy), + /* K2 */ be_nested_str_weak(r2ikey), + /* K3 */ be_nested_str_weak(attestation_challenge), + /* K4 */ be_nested_str_weak(session_timestamp), }), - be_str_weak(has_expired), + be_str_weak(set_keys), &be_const_str_solidified, - ( &(const binstruction[16]) { /* code */ - 0x4C080000, // 0000 LDNIL R2 - 0x1C080202, // 0001 EQ R2 R1 R2 - 0x780A0003, // 0002 JMPF R2 #0007 - 0xB80A0000, // 0003 GETNGBL R2 K0 - 0x8C080501, // 0004 GETMET R2 R2 K1 - 0x7C080200, // 0005 CALL R2 1 - 0x94040502, // 0006 GETIDX R1 R2 K2 - 0x88080103, // 0007 GETMBR R2 R0 K3 - 0x4C0C0000, // 0008 LDNIL R3 - 0x20080403, // 0009 NE R2 R2 R3 - 0x780A0002, // 000A JMPF R2 #000E - 0x88080103, // 000B GETMBR R2 R0 K3 - 0x28080202, // 000C GE R2 R1 R2 - 0x80040400, // 000D RET 1 R2 - 0x50080000, // 000E LDBOOL R2 0 0 - 0x80040400, // 000F RET 1 R2 + ( &(const binstruction[ 7]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x4C140000, // 0001 LDNIL R5 + 0x90020205, // 0002 SETMBR R0 K1 R5 + 0x90020402, // 0003 SETMBR R0 K2 R2 + 0x90020603, // 0004 SETMBR R0 K3 R3 + 0x90020804, // 0005 SETMBR R0 K4 R4 + 0x80000000, // 0006 RET 0 }) ) ); @@ -1230,26 +1161,76 @@ be_local_closure(Matter_Session_get_ca, /* name */ /******************************************************************** -** Solidified function: set_mode +** Solidified function: get_pk ********************************************************************/ -be_local_closure(Matter_Session_set_mode, /* name */ +be_local_closure(Matter_Session_get_pk, /* name */ be_nested_proto( - 2, /* nstack */ - 2, /* argc */ + 5, /* nstack */ + 1, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(mode), + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(no_private_key), + /* K1 */ be_nested_str_weak(crypto), + /* K2 */ be_nested_str_weak(random), }), - be_str_weak(set_mode), + be_str_weak(get_pk), &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x90020001, // 0000 SETMBR R0 K0 R1 - 0x80000000, // 0001 RET 0 + ( &(const binstruction[ 9]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x74060004, // 0001 JMPT R1 #0007 + 0xA4060200, // 0002 IMPORT R1 K1 + 0x8C080302, // 0003 GETMET R2 R1 K2 + 0x5412001F, // 0004 LDINT R4 32 + 0x7C080400, // 0005 CALL R2 2 + 0x90020002, // 0006 SETMBR R0 K0 R2 + 0x88040100, // 0007 GETMBR R1 R0 K0 + 0x80040200, // 0008 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_ca_pub +********************************************************************/ +be_local_closure(Matter_Session_get_ca_pub, /* name */ + be_nested_proto( + 5, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(root_ca_certificate), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(TLV), + /* K3 */ be_nested_str_weak(parse), + /* K4 */ be_nested_str_weak(findsubval), + }), + be_str_weak(get_ca_pub), + &be_const_str_solidified, + ( &(const binstruction[12]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x78060008, // 0001 JMPF R1 #000B + 0xB8060200, // 0002 GETNGBL R1 K1 + 0x88040302, // 0003 GETMBR R1 R1 K2 + 0x8C040303, // 0004 GETMET R1 R1 K3 + 0x880C0100, // 0005 GETMBR R3 R0 K0 + 0x7C040400, // 0006 CALL R1 2 + 0x8C080304, // 0007 GETMET R2 R1 K4 + 0x54120008, // 0008 LDINT R4 9 + 0x7C080400, // 0009 CALL R2 2 + 0x80040400, // 000A RET 1 R2 + 0x80000000, // 000B RET 0 }) ) ); @@ -1318,11 +1299,11 @@ be_local_closure(Matter_Session_init, /* name */ /******************************************************************** -** Solidified function: get_i2r_privacy +** Solidified function: get_ipk_group_key ********************************************************************/ -be_local_closure(Matter_Session_get_i2r_privacy, /* name */ +be_local_closure(Matter_Session_get_ipk_group_key, /* name */ be_nested_proto( - 9, /* nstack */ + 10, /* nstack */ 1, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -1331,39 +1312,42 @@ be_local_closure(Matter_Session_get_i2r_privacy, /* name */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 7]) { /* constants */ - /* K0 */ be_nested_str_weak(_i2r_privacy), - /* K1 */ be_nested_str_weak(crypto), - /* K2 */ be_nested_str_weak(HKDF_SHA256), - /* K3 */ be_nested_str_weak(derive), - /* K4 */ be_nested_str_weak(get_i2r), - /* K5 */ be_nested_str_weak(fromstring), - /* K6 */ be_nested_str_weak(PrivacyKey), + /* K0 */ be_nested_str_weak(ipk_epoch_key), + /* K1 */ be_nested_str_weak(fabric_compressed), + /* K2 */ be_nested_str_weak(crypto), + /* K3 */ be_nested_str_weak(HKDF_SHA256), + /* K4 */ be_nested_str_weak(fromstring), + /* K5 */ be_nested_str_weak(__GROUP_KEY), + /* K6 */ be_nested_str_weak(derive), }), - be_str_weak(get_i2r_privacy), + be_str_weak(get_ipk_group_key), &be_const_str_solidified, - ( &(const binstruction[22]) { /* code */ + ( &(const binstruction[25]) { /* code */ 0x88040100, // 0000 GETMBR R1 R0 K0 0x4C080000, // 0001 LDNIL R2 0x1C040202, // 0002 EQ R1 R1 R2 - 0x7806000F, // 0003 JMPF R1 #0014 - 0xA4060200, // 0004 IMPORT R1 K1 - 0x8C080302, // 0005 GETMET R2 R1 K2 - 0x7C080200, // 0006 CALL R2 1 - 0x8C080503, // 0007 GETMET R2 R2 K3 - 0x8C100104, // 0008 GETMET R4 R0 K4 - 0x7C100200, // 0009 CALL R4 1 - 0x60140015, // 000A GETGBL R5 G21 - 0x7C140000, // 000B CALL R5 0 - 0x60180015, // 000C GETGBL R6 G21 - 0x7C180000, // 000D CALL R6 0 - 0x8C180D05, // 000E GETMET R6 R6 K5 - 0x58200006, // 000F LDCONST R8 K6 - 0x7C180400, // 0010 CALL R6 2 - 0x541E000F, // 0011 LDINT R7 16 - 0x7C080A00, // 0012 CALL R2 5 - 0x90020002, // 0013 SETMBR R0 K0 R2 - 0x88040100, // 0014 GETMBR R1 R0 K0 - 0x80040200, // 0015 RET 1 R1 + 0x74060003, // 0003 JMPT R1 #0008 + 0x88040101, // 0004 GETMBR R1 R0 K1 + 0x4C080000, // 0005 LDNIL R2 + 0x1C040202, // 0006 EQ R1 R1 R2 + 0x78060001, // 0007 JMPF R1 #000A + 0x4C040000, // 0008 LDNIL R1 + 0x80040200, // 0009 RET 1 R1 + 0xA4060400, // 000A IMPORT R1 K2 + 0x8C080303, // 000B GETMET R2 R1 K3 + 0x7C080200, // 000C CALL R2 1 + 0x600C0015, // 000D GETGBL R3 G21 + 0x7C0C0000, // 000E CALL R3 0 + 0x8C0C0704, // 000F GETMET R3 R3 K4 + 0x88140105, // 0010 GETMBR R5 R0 K5 + 0x7C0C0400, // 0011 CALL R3 2 + 0x8C100506, // 0012 GETMET R4 R2 K6 + 0x88180100, // 0013 GETMBR R6 R0 K0 + 0x881C0101, // 0014 GETMBR R7 R0 K1 + 0x5C200600, // 0015 MOVE R8 R3 + 0x5426000F, // 0016 LDINT R9 16 + 0x7C100A00, // 0017 CALL R4 5 + 0x80040800, // 0018 RET 1 R4 }) ) ); @@ -1371,12 +1355,12 @@ be_local_closure(Matter_Session_get_i2r_privacy, /* name */ /******************************************************************** -** Solidified function: save +** Solidified function: set_noc ********************************************************************/ -be_local_closure(Matter_Session_save, /* name */ +be_local_closure(Matter_Session_set_noc, /* name */ be_nested_proto( 3, /* nstack */ - 1, /* argc */ + 3, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ @@ -1384,16 +1368,15 @@ be_local_closure(Matter_Session_save, /* name */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(__store), - /* K1 */ be_nested_str_weak(save), + /* K0 */ be_nested_str_weak(noc), + /* K1 */ be_nested_str_weak(icac), }), - be_str_weak(save), + be_str_weak(set_noc), &be_const_str_solidified, - ( &(const binstruction[ 4]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x8C040301, // 0001 GETMET R1 R1 K1 - 0x7C040200, // 0002 CALL R1 1 - 0x80000000, // 0003 RET 0 + ( &(const binstruction[ 3]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x90020202, // 0001 SETMBR R0 K1 R2 + 0x80000000, // 0002 RET 0 }) ) ); @@ -1401,9 +1384,9 @@ be_local_closure(Matter_Session_save, /* name */ /******************************************************************** -** Solidified function: set_no_expiration +** Solidified function: get_fabric ********************************************************************/ -be_local_closure(Matter_Session_set_no_expiration, /* name */ +be_local_closure(Matter_Session_get_fabric, /* name */ be_nested_proto( 2, /* nstack */ 1, /* argc */ @@ -1414,14 +1397,13 @@ be_local_closure(Matter_Session_set_no_expiration, /* name */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(expiration), + /* K0 */ be_nested_str_weak(fabric), }), - be_str_weak(set_no_expiration), + be_str_weak(get_fabric), &be_const_str_solidified, - ( &(const binstruction[ 3]) { /* code */ - 0x4C040000, // 0000 LDNIL R1 - 0x90020001, // 0001 SETMBR R0 K0 R1 - 0x80000000, // 0002 RET 0 + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 }) ) ); @@ -1429,35 +1411,53 @@ be_local_closure(Matter_Session_set_no_expiration, /* name */ /******************************************************************** -** Solidified function: set_keys +** Solidified function: get_mode ********************************************************************/ -be_local_closure(Matter_Session_set_keys, /* name */ +be_local_closure(Matter_Session_get_mode, /* name */ be_nested_proto( - 6, /* nstack */ - 5, /* argc */ + 2, /* nstack */ + 1, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 5]) { /* constants */ - /* K0 */ be_nested_str_weak(i2rkey), - /* K1 */ be_nested_str_weak(_i2r_privacy), - /* K2 */ be_nested_str_weak(r2ikey), - /* K3 */ be_nested_str_weak(attestation_challenge), - /* K4 */ be_nested_str_weak(session_timestamp), + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(mode), }), - be_str_weak(set_keys), + be_str_weak(get_mode), &be_const_str_solidified, - ( &(const binstruction[ 7]) { /* code */ + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_mode +********************************************************************/ +be_local_closure(Matter_Session_set_mode, /* name */ + be_nested_proto( + 2, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(mode), + }), + be_str_weak(set_mode), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ 0x90020001, // 0000 SETMBR R0 K0 R1 - 0x4C140000, // 0001 LDNIL R5 - 0x90020205, // 0002 SETMBR R0 K1 R5 - 0x90020402, // 0003 SETMBR R0 K2 R2 - 0x90020603, // 0004 SETMBR R0 K3 R3 - 0x90020804, // 0005 SETMBR R0 K4 R4 - 0x80000000, // 0006 RET 0 + 0x80000000, // 0001 RET 0 }) ) ); @@ -1468,81 +1468,82 @@ be_local_closure(Matter_Session_set_keys, /* name */ ** Solidified class: Matter_Session ********************************************************************/ be_local_class(Matter_Session, - 35, + 36, NULL, - be_nested_map(71, + be_nested_map(72, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(get_ca_pub, -1), be_const_closure(Matter_Session_get_ca_pub_closure) }, - { be_const_key_weak(source_node_id, -1), be_const_var(5) }, - { be_const_key_weak(breadcrumb, -1), be_const_var(17) }, - { be_const_key_weak(set_expire_time, 55), be_const_closure(Matter_Session_set_expire_time_closure) }, - { be_const_key_weak(attestation_challenge, 70), be_const_var(15) }, - { be_const_key_weak(set_no_expiration, -1), be_const_closure(Matter_Session_set_no_expiration_closure) }, - { be_const_key_weak(_i2r_privacy, 51), be_const_var(14) }, - { be_const_key_weak(set_expire_in_seconds, -1), be_const_closure(Matter_Session_set_expire_in_seconds_closure) }, - { be_const_key_weak(set_ipk_epoch_key, -1), be_const_closure(Matter_Session_set_ipk_epoch_key_closure) }, - { be_const_key_weak(deviceid, -1), be_const_var(27) }, - { be_const_key_weak(get_noc, -1), be_const_closure(Matter_Session_get_noc_closure) }, - { be_const_key_weak(tojson, -1), be_const_closure(Matter_Session_tojson_closure) }, { be_const_key_weak(save, -1), be_const_closure(Matter_Session_save_closure) }, - { be_const_key_weak(get_i2r_privacy, 43), be_const_closure(Matter_Session_get_i2r_privacy_closure) }, - { be_const_key_weak(set_fabric_device, -1), be_const_closure(Matter_Session_set_fabric_device_closure) }, - { be_const_key_weak(get_deviceid, -1), be_const_closure(Matter_Session_get_deviceid_closure) }, - { be_const_key_weak(r2ikey, -1), be_const_var(13) }, - { be_const_key_weak(fromjson, 2), be_const_static_closure(Matter_Session_fromjson_closure) }, - { be_const_key_weak(set_fabric_label, -1), be_const_closure(Matter_Session_set_fabric_label_closure) }, - { be_const_key_weak(no_private_key, 50), be_const_var(18) }, - { be_const_key_weak(i2rkey, -1), be_const_var(12) }, - { be_const_key_weak(__CASE, -1), be_const_int(2) }, - { be_const_key_weak(local_session_id, 20), be_const_var(2) }, - { be_const_key_weak(set_noc, -1), be_const_closure(Matter_Session_set_noc_closure) }, - { be_const_key_weak(get_mode, 27), be_const_closure(Matter_Session_get_mode_closure) }, - { be_const_key_weak(peer_node_id, 66), be_const_var(16) }, - { be_const_key_weak(_persist, 19), be_const_var(33) }, - { be_const_key_weak(set_persist, -1), be_const_closure(Matter_Session_set_persist_closure) }, - { be_const_key_weak(initiator_session_id, -1), be_const_var(3) }, - { be_const_key_weak(set_ca, 28), be_const_closure(Matter_Session_set_ca_closure) }, - { be_const_key_weak(get_ipk_epoch_key, 41), be_const_closure(Matter_Session_get_ipk_epoch_key_closure) }, - { be_const_key_weak(_future_initiator_session_id, 22), be_const_var(6) }, - { be_const_key_weak(get_ipk_group_key, 39), be_const_closure(Matter_Session_get_ipk_group_key_closure) }, - { be_const_key_weak(get_pk, 56), be_const_closure(Matter_Session_get_pk_closure) }, - { be_const_key_weak(get_ac, -1), be_const_closure(Matter_Session_get_ac_closure) }, - { be_const_key_weak(gen_CSR, 1), be_const_closure(Matter_Session_gen_CSR_closure) }, { be_const_key_weak(set_mode, -1), be_const_closure(Matter_Session_set_mode_closure) }, - { be_const_key_weak(resumption_id, 29), be_const_var(23) }, - { be_const_key_weak(get_icac, -1), be_const_closure(Matter_Session_get_icac_closure) }, - { be_const_key_weak(_Msg1, -1), be_const_var(31) }, - { be_const_key_weak(__PASE, -1), be_const_int(1) }, - { be_const_key_weak(get_ca, -1), be_const_closure(Matter_Session_get_ca_closure) }, { be_const_key_weak(root_ca_certificate, -1), be_const_var(19) }, - { be_const_key_weak(expiration, -1), be_const_var(34) }, - { be_const_key_weak(get_fabric, -1), be_const_closure(Matter_Session_get_fabric_closure) }, - { be_const_key_weak(fabric_label, -1), be_const_var(28) }, - { be_const_key_weak(_future_local_session_id, -1), be_const_var(7) }, - { be_const_key_weak(close, 45), be_const_closure(Matter_Session_close_closure) }, - { be_const_key_weak(admin_vendor, 64), be_const_var(30) }, - { be_const_key_weak(icac, -1), be_const_var(21) }, - { be_const_key_weak(counter_snd, 48), be_const_var(9) }, - { be_const_key_weak(get_i2r, 63), be_const_closure(Matter_Session_get_i2r_closure) }, + { be_const_key_weak(admin_subject, 29), be_const_var(29) }, + { be_const_key_weak(get_i2r_privacy, 25), be_const_closure(Matter_Session_get_i2r_privacy_closure) }, { be_const_key_weak(has_expired, -1), be_const_closure(Matter_Session_has_expired_closure) }, - { be_const_key_weak(__GROUP_KEY, 12), be_nested_str_weak(GroupKey_X20v1_X2E0) }, - { be_const_key_weak(session_timestamp, -1), be_const_var(4) }, - { be_const_key_weak(shared_secret, -1), be_const_var(24) }, - { be_const_key_weak(fabric_compressed, -1), be_const_var(26) }, - { be_const_key_weak(get_fabric_compressed, 36), be_const_closure(Matter_Session_get_fabric_compressed_closure) }, - { be_const_key_weak(noc, 16), be_const_var(20) }, - { be_const_key_weak(_counter_insecure_rcv, -1), be_const_var(10) }, - { be_const_key_weak(admin_subject, -1), be_const_var(29) }, - { be_const_key_weak(init, -1), be_const_closure(Matter_Session_init_closure) }, - { be_const_key_weak(ipk_epoch_key, -1), be_const_var(22) }, - { be_const_key_weak(counter_rcv, -1), be_const_var(8) }, - { be_const_key_weak(fabric, -1), be_const_var(25) }, - { be_const_key_weak(__store, 13), be_const_var(0) }, - { be_const_key_weak(mode, -1), be_const_var(1) }, + { be_const_key_weak(set_no_expiration, -1), be_const_closure(Matter_Session_set_no_expiration_closure) }, + { be_const_key_weak(get_deviceid, 61), be_const_closure(Matter_Session_get_deviceid_closure) }, + { be_const_key_weak(local_session_id, -1), be_const_var(2) }, + { be_const_key_weak(get_mode, -1), be_const_closure(Matter_Session_get_mode_closure) }, + { be_const_key_weak(set_fabric_device, -1), be_const_closure(Matter_Session_set_fabric_device_closure) }, + { be_const_key_weak(fromjson, -1), be_const_static_closure(Matter_Session_fromjson_closure) }, + { be_const_key_weak(get_ipk_epoch_key, -1), be_const_closure(Matter_Session_get_ipk_epoch_key_closure) }, + { be_const_key_weak(get_fabric, 33), be_const_closure(Matter_Session_get_fabric_closure) }, + { be_const_key_weak(tojson, -1), be_const_closure(Matter_Session_tojson_closure) }, + { be_const_key_weak(set_noc, 37), be_const_closure(Matter_Session_set_noc_closure) }, + { be_const_key_weak(get_ac, -1), be_const_closure(Matter_Session_get_ac_closure) }, { be_const_key_weak(_counter_insecure_snd, 6), be_const_var(11) }, - { be_const_key_weak(_Msg2, 5), be_const_var(32) }, - { be_const_key_weak(set_keys, -1), be_const_closure(Matter_Session_set_keys_closure) }, - { be_const_key_weak(get_r2i, -1), be_const_closure(Matter_Session_get_r2i_closure) }, + { be_const_key_weak(initiator_session_id, -1), be_const_var(3) }, + { be_const_key_weak(get_fabric_compressed, -1), be_const_closure(Matter_Session_get_fabric_compressed_closure) }, + { be_const_key_weak(set_fabric_label, -1), be_const_closure(Matter_Session_set_fabric_label_closure) }, + { be_const_key_weak(shared_secret, 8), be_const_var(24) }, + { be_const_key_weak(get_ipk_group_key, 43), be_const_closure(Matter_Session_get_ipk_group_key_closure) }, + { be_const_key_weak(init, 42), be_const_closure(Matter_Session_init_closure) }, + { be_const_key_weak(_chunked_attr_reports, -1), be_const_var(35) }, + { be_const_key_weak(set_persist, -1), be_const_closure(Matter_Session_set_persist_closure) }, + { be_const_key_weak(_future_initiator_session_id, -1), be_const_var(6) }, + { be_const_key_weak(_Msg2, -1), be_const_var(32) }, + { be_const_key_weak(fabric, -1), be_const_var(25) }, + { be_const_key_weak(close, -1), be_const_closure(Matter_Session_close_closure) }, + { be_const_key_weak(_i2r_privacy, -1), be_const_var(14) }, + { be_const_key_weak(ipk_epoch_key, -1), be_const_var(22) }, + { be_const_key_weak(get_ca, 10), be_const_closure(Matter_Session_get_ca_closure) }, + { be_const_key_weak(resumption_id, -1), be_const_var(23) }, + { be_const_key_weak(gen_CSR, 38), be_const_closure(Matter_Session_gen_CSR_closure) }, + { be_const_key_weak(source_node_id, -1), be_const_var(5) }, + { be_const_key_weak(set_ca, -1), be_const_closure(Matter_Session_set_ca_closure) }, + { be_const_key_weak(set_ipk_epoch_key, -1), be_const_closure(Matter_Session_set_ipk_epoch_key_closure) }, + { be_const_key_weak(_future_local_session_id, -1), be_const_var(7) }, + { be_const_key_weak(get_r2i, 31), be_const_closure(Matter_Session_get_r2i_closure) }, + { be_const_key_weak(icac, -1), be_const_var(21) }, + { be_const_key_weak(fabric_label, -1), be_const_var(28) }, + { be_const_key_weak(attestation_challenge, -1), be_const_var(15) }, + { be_const_key_weak(peer_node_id, 49), be_const_var(16) }, + { be_const_key_weak(get_noc, 53), be_const_closure(Matter_Session_get_noc_closure) }, + { be_const_key_weak(set_expire_time, 40), be_const_closure(Matter_Session_set_expire_time_closure) }, + { be_const_key_weak(deviceid, -1), be_const_var(27) }, + { be_const_key_weak(__CASE, -1), be_const_int(2) }, + { be_const_key_weak(get_icac, 50), be_const_closure(Matter_Session_get_icac_closure) }, + { be_const_key_weak(_Msg1, -1), be_const_var(31) }, + { be_const_key_weak(set_keys, 58), be_const_closure(Matter_Session_set_keys_closure) }, + { be_const_key_weak(noc, 23), be_const_var(20) }, + { be_const_key_weak(__PASE, -1), be_const_int(1) }, + { be_const_key_weak(breadcrumb, 26), be_const_var(17) }, + { be_const_key_weak(__GROUP_KEY, -1), be_nested_str_weak(GroupKey_X20v1_X2E0) }, + { be_const_key_weak(counter_snd, -1), be_const_var(9) }, + { be_const_key_weak(fabric_compressed, 32), be_const_var(26) }, + { be_const_key_weak(get_pk, -1), be_const_closure(Matter_Session_get_pk_closure) }, + { be_const_key_weak(expiration, -1), be_const_var(34) }, + { be_const_key_weak(r2ikey, -1), be_const_var(13) }, + { be_const_key_weak(get_ca_pub, -1), be_const_closure(Matter_Session_get_ca_pub_closure) }, + { be_const_key_weak(counter_rcv, -1), be_const_var(8) }, + { be_const_key_weak(_persist, 22), be_const_var(33) }, + { be_const_key_weak(i2rkey, 18), be_const_var(12) }, + { be_const_key_weak(session_timestamp, 15), be_const_var(4) }, + { be_const_key_weak(set_expire_in_seconds, 13), be_const_closure(Matter_Session_set_expire_in_seconds_closure) }, + { be_const_key_weak(mode, -1), be_const_var(1) }, + { be_const_key_weak(get_i2r, 9), be_const_closure(Matter_Session_get_i2r_closure) }, + { be_const_key_weak(__store, -1), be_const_var(0) }, + { be_const_key_weak(_counter_insecure_rcv, -1), be_const_var(10) }, + { be_const_key_weak(no_private_key, 2), be_const_var(18) }, + { be_const_key_weak(admin_vendor, 1), be_const_var(30) }, })), be_str_weak(Matter_Session) ); @@ -1556,6 +1557,63 @@ void be_load_Matter_Session_class(bvm *vm) { extern const bclass be_class_Matter_Session_Store; +/******************************************************************** +** Solidified function: remove_expired +********************************************************************/ +be_local_closure(Matter_Session_Store_remove_expired, /* name */ + be_nested_proto( + 7, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 7]) { /* constants */ + /* K0 */ be_const_int(0), + /* K1 */ be_nested_str_weak(sessions), + /* K2 */ be_nested_str_weak(has_expired), + /* K3 */ be_nested_str_weak(_persist), + /* K4 */ be_nested_str_weak(remove), + /* K5 */ be_const_int(1), + /* K6 */ be_nested_str_weak(save), + }), + be_str_weak(remove_expired), + &be_const_str_solidified, + ( &(const binstruction[26]) { /* code */ + 0x50040000, // 0000 LDBOOL R1 0 0 + 0x58080000, // 0001 LDCONST R2 K0 + 0x880C0101, // 0002 GETMBR R3 R0 K1 + 0x6010000C, // 0003 GETGBL R4 G12 + 0x88140101, // 0004 GETMBR R5 R0 K1 + 0x7C100200, // 0005 CALL R4 1 + 0x14100404, // 0006 LT R4 R2 R4 + 0x7812000D, // 0007 JMPF R4 #0016 + 0x94100602, // 0008 GETIDX R4 R3 R2 + 0x8C100902, // 0009 GETMET R4 R4 K2 + 0x7C100200, // 000A CALL R4 1 + 0x78120007, // 000B JMPF R4 #0014 + 0x94100602, // 000C GETIDX R4 R3 R2 + 0x88100903, // 000D GETMBR R4 R4 K3 + 0x78120000, // 000E JMPF R4 #0010 + 0x50040200, // 000F LDBOOL R1 1 0 + 0x8C100704, // 0010 GETMET R4 R3 K4 + 0x5C180400, // 0011 MOVE R6 R2 + 0x7C100400, // 0012 CALL R4 2 + 0x70020000, // 0013 JMP #0015 + 0x00080505, // 0014 ADD R2 R2 K5 + 0x7001FFEC, // 0015 JMP #0003 + 0x78060001, // 0016 JMPF R1 #0019 + 0x8C100106, // 0017 GETMET R4 R0 K6 + 0x7C100200, // 0018 CALL R4 1 + 0x80000000, // 0019 RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: remove_redundant_session ********************************************************************/ @@ -1611,89 +1669,6 @@ be_local_closure(Matter_Session_Store_remove_redundant_session, /* name */ /*******************************************************************/ -/******************************************************************** -** Solidified function: init -********************************************************************/ -be_local_closure(Matter_Session_Store_init, /* name */ - be_nested_proto( - 2, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(sessions), - }), - be_str_weak(init), - &be_const_str_solidified, - ( &(const binstruction[ 4]) { /* code */ - 0x60040012, // 0000 GETGBL R1 G18 - 0x7C040000, // 0001 CALL R1 0 - 0x90020001, // 0002 SETMBR R0 K0 R1 - 0x80000000, // 0003 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: find_session_source_id_unsecure -********************************************************************/ -be_local_closure(Matter_Session_Store_find_session_source_id_unsecure, /* name */ - be_nested_proto( - 9, /* nstack */ - 3, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 8]) { /* constants */ - /* K0 */ be_nested_str_weak(get_session_by_source_node_id), - /* K1 */ be_nested_str_weak(matter), - /* K2 */ be_nested_str_weak(Session), - /* K3 */ be_const_int(0), - /* K4 */ be_nested_str_weak(source_node_id), - /* K5 */ be_nested_str_weak(sessions), - /* K6 */ be_nested_str_weak(push), - /* K7 */ be_nested_str_weak(set_expire_in_seconds), - }), - be_str_weak(find_session_source_id_unsecure), - &be_const_str_solidified, - ( &(const binstruction[22]) { /* code */ - 0x8C0C0100, // 0000 GETMET R3 R0 K0 - 0x5C140200, // 0001 MOVE R5 R1 - 0x7C0C0400, // 0002 CALL R3 2 - 0x4C100000, // 0003 LDNIL R4 - 0x1C100604, // 0004 EQ R4 R3 R4 - 0x7812000B, // 0005 JMPF R4 #0012 - 0xB8120200, // 0006 GETNGBL R4 K1 - 0x8C100902, // 0007 GETMET R4 R4 K2 - 0x5C180000, // 0008 MOVE R6 R0 - 0x581C0003, // 0009 LDCONST R7 K3 - 0x58200003, // 000A LDCONST R8 K3 - 0x7C100800, // 000B CALL R4 4 - 0x5C0C0800, // 000C MOVE R3 R4 - 0x900E0801, // 000D SETMBR R3 K4 R1 - 0x88100105, // 000E GETMBR R4 R0 K5 - 0x8C100906, // 000F GETMET R4 R4 K6 - 0x5C180600, // 0010 MOVE R6 R3 - 0x7C100400, // 0011 CALL R4 2 - 0x8C100707, // 0012 GETMET R4 R3 K7 - 0x5C180400, // 0013 MOVE R6 R2 - 0x7C100400, // 0014 CALL R4 2 - 0x80040600, // 0015 RET 1 R3 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified function: add_session ********************************************************************/ @@ -1732,6 +1707,58 @@ be_local_closure(Matter_Session_Store_add_session, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: sessions_active +********************************************************************/ +be_local_closure(Matter_Session_Store_sessions_active, /* name */ + be_nested_proto( + 7, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_const_int(0), + /* K1 */ be_nested_str_weak(sessions), + /* K2 */ be_nested_str_weak(get_deviceid), + /* K3 */ be_nested_str_weak(get_fabric), + /* K4 */ be_nested_str_weak(push), + /* K5 */ be_const_int(1), + }), + be_str_weak(sessions_active), + &be_const_str_solidified, + ( &(const binstruction[22]) { /* code */ + 0x60040012, // 0000 GETGBL R1 G18 + 0x7C040000, // 0001 CALL R1 0 + 0x58080000, // 0002 LDCONST R2 K0 + 0x600C000C, // 0003 GETGBL R3 G12 + 0x88100101, // 0004 GETMBR R4 R0 K1 + 0x7C0C0200, // 0005 CALL R3 1 + 0x140C0403, // 0006 LT R3 R2 R3 + 0x780E000C, // 0007 JMPF R3 #0015 + 0x880C0101, // 0008 GETMBR R3 R0 K1 + 0x940C0602, // 0009 GETIDX R3 R3 R2 + 0x8C100702, // 000A GETMET R4 R3 K2 + 0x7C100200, // 000B CALL R4 1 + 0x78120005, // 000C JMPF R4 #0013 + 0x8C100703, // 000D GETMET R4 R3 K3 + 0x7C100200, // 000E CALL R4 1 + 0x78120002, // 000F JMPF R4 #0013 + 0x8C100304, // 0010 GETMET R4 R1 K4 + 0x5C180600, // 0011 MOVE R6 R3 + 0x7C100400, // 0012 CALL R4 2 + 0x00080505, // 0013 ADD R2 R2 K5 + 0x7001FFED, // 0014 JMP #0003 + 0x80040200, // 0015 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: every_second ********************************************************************/ @@ -1760,108 +1787,6 @@ be_local_closure(Matter_Session_Store_every_second, /* name */ /*******************************************************************/ -/******************************************************************** -** Solidified function: remove_session -********************************************************************/ -be_local_closure(Matter_Session_Store_remove_session, /* name */ - be_nested_proto( - 7, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 4]) { /* constants */ - /* K0 */ be_const_int(0), - /* K1 */ be_nested_str_weak(sessions), - /* K2 */ be_nested_str_weak(remove), - /* K3 */ be_const_int(1), - }), - be_str_weak(remove_session), - &be_const_str_solidified, - ( &(const binstruction[17]) { /* code */ - 0x58080000, // 0000 LDCONST R2 K0 - 0x880C0101, // 0001 GETMBR R3 R0 K1 - 0x6010000C, // 0002 GETGBL R4 G12 - 0x88140101, // 0003 GETMBR R5 R0 K1 - 0x7C100200, // 0004 CALL R4 1 - 0x14100404, // 0005 LT R4 R2 R4 - 0x78120008, // 0006 JMPF R4 #0010 - 0x94100602, // 0007 GETIDX R4 R3 R2 - 0x1C100801, // 0008 EQ R4 R4 R1 - 0x78120003, // 0009 JMPF R4 #000E - 0x8C100702, // 000A GETMET R4 R3 K2 - 0x5C180400, // 000B MOVE R6 R2 - 0x7C100400, // 000C CALL R4 2 - 0x70020000, // 000D JMP #000F - 0x00080503, // 000E ADD R2 R2 K3 - 0x7001FFF1, // 000F JMP #0002 - 0x80000000, // 0010 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: remove_expired -********************************************************************/ -be_local_closure(Matter_Session_Store_remove_expired, /* name */ - be_nested_proto( - 7, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 7]) { /* constants */ - /* K0 */ be_const_int(0), - /* K1 */ be_nested_str_weak(sessions), - /* K2 */ be_nested_str_weak(has_expired), - /* K3 */ be_nested_str_weak(_persist), - /* K4 */ be_nested_str_weak(remove), - /* K5 */ be_const_int(1), - /* K6 */ be_nested_str_weak(save), - }), - be_str_weak(remove_expired), - &be_const_str_solidified, - ( &(const binstruction[26]) { /* code */ - 0x50040000, // 0000 LDBOOL R1 0 0 - 0x58080000, // 0001 LDCONST R2 K0 - 0x880C0101, // 0002 GETMBR R3 R0 K1 - 0x6010000C, // 0003 GETGBL R4 G12 - 0x88140101, // 0004 GETMBR R5 R0 K1 - 0x7C100200, // 0005 CALL R4 1 - 0x14100404, // 0006 LT R4 R2 R4 - 0x7812000D, // 0007 JMPF R4 #0016 - 0x94100602, // 0008 GETIDX R4 R3 R2 - 0x8C100902, // 0009 GETMET R4 R4 K2 - 0x7C100200, // 000A CALL R4 1 - 0x78120007, // 000B JMPF R4 #0014 - 0x94100602, // 000C GETIDX R4 R3 R2 - 0x88100903, // 000D GETMBR R4 R4 K3 - 0x78120000, // 000E JMPF R4 #0010 - 0x50040200, // 000F LDBOOL R1 1 0 - 0x8C100704, // 0010 GETMET R4 R3 K4 - 0x5C180400, // 0011 MOVE R6 R2 - 0x7C100400, // 0012 CALL R4 2 - 0x70020000, // 0013 JMP #0015 - 0x00080505, // 0014 ADD R2 R2 K5 - 0x7001FFEC, // 0015 JMP #0003 - 0x78060001, // 0016 JMPF R1 #0019 - 0x8C100106, // 0017 GETMET R4 R0 K6 - 0x7C100200, // 0018 CALL R4 1 - 0x80000000, // 0019 RET 0 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified function: save ********************************************************************/ @@ -1981,6 +1906,331 @@ be_local_closure(Matter_Session_Store_save, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: find_session_by_resumption_id +********************************************************************/ +be_local_closure(Matter_Session_Store_find_session_by_resumption_id, /* name */ + be_nested_proto( + 6, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_const_int(0), + /* K1 */ be_nested_str_weak(sessions), + /* K2 */ be_nested_str_weak(resumption_id), + /* K3 */ be_const_int(1), + }), + be_str_weak(find_session_by_resumption_id), + &be_const_str_solidified, + ( &(const binstruction[20]) { /* code */ + 0x5C080200, // 0000 MOVE R2 R1 + 0x740A0001, // 0001 JMPT R2 #0004 + 0x4C080000, // 0002 LDNIL R2 + 0x80040400, // 0003 RET 1 R2 + 0x58080000, // 0004 LDCONST R2 K0 + 0x880C0101, // 0005 GETMBR R3 R0 K1 + 0x6010000C, // 0006 GETGBL R4 G12 + 0x5C140600, // 0007 MOVE R5 R3 + 0x7C100200, // 0008 CALL R4 1 + 0x14100404, // 0009 LT R4 R2 R4 + 0x78120007, // 000A JMPF R4 #0013 + 0x94100602, // 000B GETIDX R4 R3 R2 + 0x88100902, // 000C GETMBR R4 R4 K2 + 0x1C100801, // 000D EQ R4 R4 R1 + 0x78120001, // 000E JMPF R4 #0011 + 0x94100602, // 000F GETIDX R4 R3 R2 + 0x80040800, // 0010 RET 1 R4 + 0x00080503, // 0011 ADD R2 R2 K3 + 0x7001FFF2, // 0012 JMP #0006 + 0x80000000, // 0013 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: gen_local_session_id +********************************************************************/ +be_local_closure(Matter_Session_Store_gen_local_session_id, /* name */ + be_nested_proto( + 6, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(crypto), + /* K1 */ be_nested_str_weak(random), + /* K2 */ be_const_int(2), + /* K3 */ be_nested_str_weak(get), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str_weak(get_session_by_local_session_id), + }), + be_str_weak(gen_local_session_id), + &be_const_str_solidified, + ( &(const binstruction[19]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x50080200, // 0001 LDBOOL R2 1 0 + 0x780A000E, // 0002 JMPF R2 #0012 + 0x8C080301, // 0003 GETMET R2 R1 K1 + 0x58100002, // 0004 LDCONST R4 K2 + 0x7C080400, // 0005 CALL R2 2 + 0x8C080503, // 0006 GETMET R2 R2 K3 + 0x58100004, // 0007 LDCONST R4 K4 + 0x58140002, // 0008 LDCONST R5 K2 + 0x7C080600, // 0009 CALL R2 3 + 0x8C0C0105, // 000A GETMET R3 R0 K5 + 0x5C140400, // 000B MOVE R5 R2 + 0x7C0C0400, // 000C CALL R3 2 + 0x4C100000, // 000D LDNIL R4 + 0x1C0C0604, // 000E EQ R3 R3 R4 + 0x780E0000, // 000F JMPF R3 #0011 + 0x80040400, // 0010 RET 1 R2 + 0x7001FFEE, // 0011 JMP #0001 + 0x80000000, // 0012 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_session_by_local_session_id +********************************************************************/ +be_local_closure(Matter_Session_Store_get_session_by_local_session_id, /* name */ + be_nested_proto( + 6, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(sessions), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str_weak(local_session_id), + /* K3 */ be_const_int(1), + }), + be_str_weak(get_session_by_local_session_id), + &be_const_str_solidified, + ( &(const binstruction[21]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0001, // 0002 JMPF R2 #0005 + 0x4C080000, // 0003 LDNIL R2 + 0x80040400, // 0004 RET 1 R2 + 0x6008000C, // 0005 GETGBL R2 G12 + 0x880C0100, // 0006 GETMBR R3 R0 K0 + 0x7C080200, // 0007 CALL R2 1 + 0x580C0001, // 0008 LDCONST R3 K1 + 0x88100100, // 0009 GETMBR R4 R0 K0 + 0x14140602, // 000A LT R5 R3 R2 + 0x78160007, // 000B JMPF R5 #0014 + 0x94140803, // 000C GETIDX R5 R4 R3 + 0x88140B02, // 000D GETMBR R5 R5 K2 + 0x1C140A01, // 000E EQ R5 R5 R1 + 0x78160001, // 000F JMPF R5 #0012 + 0x94140803, // 0010 GETIDX R5 R4 R3 + 0x80040A00, // 0011 RET 1 R5 + 0x000C0703, // 0012 ADD R3 R3 K3 + 0x7001FFF5, // 0013 JMP #000A + 0x80000000, // 0014 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_Session_Store_init, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(sessions), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[ 4]) { /* code */ + 0x60040012, // 0000 GETGBL R1 G18 + 0x7C040000, // 0001 CALL R1 0 + 0x90020001, // 0002 SETMBR R0 K0 R1 + 0x80000000, // 0003 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: find_session_source_id_unsecure +********************************************************************/ +be_local_closure(Matter_Session_Store_find_session_source_id_unsecure, /* name */ + be_nested_proto( + 9, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(get_session_by_source_node_id), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(Session), + /* K3 */ be_const_int(0), + /* K4 */ be_nested_str_weak(source_node_id), + /* K5 */ be_nested_str_weak(sessions), + /* K6 */ be_nested_str_weak(push), + /* K7 */ be_nested_str_weak(set_expire_in_seconds), + }), + be_str_weak(find_session_source_id_unsecure), + &be_const_str_solidified, + ( &(const binstruction[22]) { /* code */ + 0x8C0C0100, // 0000 GETMET R3 R0 K0 + 0x5C140200, // 0001 MOVE R5 R1 + 0x7C0C0400, // 0002 CALL R3 2 + 0x4C100000, // 0003 LDNIL R4 + 0x1C100604, // 0004 EQ R4 R3 R4 + 0x7812000B, // 0005 JMPF R4 #0012 + 0xB8120200, // 0006 GETNGBL R4 K1 + 0x8C100902, // 0007 GETMET R4 R4 K2 + 0x5C180000, // 0008 MOVE R6 R0 + 0x581C0003, // 0009 LDCONST R7 K3 + 0x58200003, // 000A LDCONST R8 K3 + 0x7C100800, // 000B CALL R4 4 + 0x5C0C0800, // 000C MOVE R3 R4 + 0x900E0801, // 000D SETMBR R3 K4 R1 + 0x88100105, // 000E GETMBR R4 R0 K5 + 0x8C100906, // 000F GETMET R4 R4 K6 + 0x5C180600, // 0010 MOVE R6 R3 + 0x7C100400, // 0011 CALL R4 2 + 0x8C100707, // 0012 GETMET R4 R3 K7 + 0x5C180400, // 0013 MOVE R6 R2 + 0x7C100400, // 0014 CALL R4 2 + 0x80040600, // 0015 RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: remove_session +********************************************************************/ +be_local_closure(Matter_Session_Store_remove_session, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_const_int(0), + /* K1 */ be_nested_str_weak(sessions), + /* K2 */ be_nested_str_weak(remove), + /* K3 */ be_const_int(1), + }), + be_str_weak(remove_session), + &be_const_str_solidified, + ( &(const binstruction[17]) { /* code */ + 0x58080000, // 0000 LDCONST R2 K0 + 0x880C0101, // 0001 GETMBR R3 R0 K1 + 0x6010000C, // 0002 GETGBL R4 G12 + 0x88140101, // 0003 GETMBR R5 R0 K1 + 0x7C100200, // 0004 CALL R4 1 + 0x14100404, // 0005 LT R4 R2 R4 + 0x78120008, // 0006 JMPF R4 #0010 + 0x94100602, // 0007 GETIDX R4 R3 R2 + 0x1C100801, // 0008 EQ R4 R4 R1 + 0x78120003, // 0009 JMPF R4 #000E + 0x8C100702, // 000A GETMET R4 R3 K2 + 0x5C180400, // 000B MOVE R6 R2 + 0x7C100400, // 000C CALL R4 2 + 0x70020000, // 000D JMP #000F + 0x00080503, // 000E ADD R2 R2 K3 + 0x7001FFF1, // 000F JMP #0002 + 0x80000000, // 0010 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: create_session +********************************************************************/ +be_local_closure(Matter_Session_Store_create_session, /* name */ + be_nested_proto( + 9, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(get_session_by_local_session_id), + /* K1 */ be_nested_str_weak(remove_session), + /* K2 */ be_nested_str_weak(matter), + /* K3 */ be_nested_str_weak(Session), + /* K4 */ be_nested_str_weak(sessions), + /* K5 */ be_nested_str_weak(push), + }), + be_str_weak(create_session), + &be_const_str_solidified, + ( &(const binstruction[21]) { /* code */ + 0x8C0C0100, // 0000 GETMET R3 R0 K0 + 0x5C140200, // 0001 MOVE R5 R1 + 0x7C0C0400, // 0002 CALL R3 2 + 0x4C100000, // 0003 LDNIL R4 + 0x20100604, // 0004 NE R4 R3 R4 + 0x78120002, // 0005 JMPF R4 #0009 + 0x8C100101, // 0006 GETMET R4 R0 K1 + 0x5C180600, // 0007 MOVE R6 R3 + 0x7C100400, // 0008 CALL R4 2 + 0xB8120400, // 0009 GETNGBL R4 K2 + 0x8C100903, // 000A GETMET R4 R4 K3 + 0x5C180000, // 000B MOVE R6 R0 + 0x5C1C0200, // 000C MOVE R7 R1 + 0x5C200400, // 000D MOVE R8 R2 + 0x7C100800, // 000E CALL R4 4 + 0x5C0C0800, // 000F MOVE R3 R4 + 0x88100104, // 0010 GETMBR R4 R0 K4 + 0x8C100905, // 0011 GETMET R4 R4 K5 + 0x5C180600, // 0012 MOVE R6 R3 + 0x7C100400, // 0013 CALL R4 2 + 0x80040600, // 0014 RET 1 R3 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: load ********************************************************************/ @@ -2103,207 +2353,6 @@ be_local_closure(Matter_Session_Store_load, /* name */ /*******************************************************************/ -/******************************************************************** -** Solidified function: create_session -********************************************************************/ -be_local_closure(Matter_Session_Store_create_session, /* name */ - be_nested_proto( - 9, /* nstack */ - 3, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 6]) { /* constants */ - /* K0 */ be_nested_str_weak(get_session_by_local_session_id), - /* K1 */ be_nested_str_weak(remove_session), - /* K2 */ be_nested_str_weak(matter), - /* K3 */ be_nested_str_weak(Session), - /* K4 */ be_nested_str_weak(sessions), - /* K5 */ be_nested_str_weak(push), - }), - be_str_weak(create_session), - &be_const_str_solidified, - ( &(const binstruction[21]) { /* code */ - 0x8C0C0100, // 0000 GETMET R3 R0 K0 - 0x5C140200, // 0001 MOVE R5 R1 - 0x7C0C0400, // 0002 CALL R3 2 - 0x4C100000, // 0003 LDNIL R4 - 0x20100604, // 0004 NE R4 R3 R4 - 0x78120002, // 0005 JMPF R4 #0009 - 0x8C100101, // 0006 GETMET R4 R0 K1 - 0x5C180600, // 0007 MOVE R6 R3 - 0x7C100400, // 0008 CALL R4 2 - 0xB8120400, // 0009 GETNGBL R4 K2 - 0x8C100903, // 000A GETMET R4 R4 K3 - 0x5C180000, // 000B MOVE R6 R0 - 0x5C1C0200, // 000C MOVE R7 R1 - 0x5C200400, // 000D MOVE R8 R2 - 0x7C100800, // 000E CALL R4 4 - 0x5C0C0800, // 000F MOVE R3 R4 - 0x88100104, // 0010 GETMBR R4 R0 K4 - 0x8C100905, // 0011 GETMET R4 R4 K5 - 0x5C180600, // 0012 MOVE R6 R3 - 0x7C100400, // 0013 CALL R4 2 - 0x80040600, // 0014 RET 1 R3 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: sessions_active -********************************************************************/ -be_local_closure(Matter_Session_Store_sessions_active, /* name */ - be_nested_proto( - 7, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 6]) { /* constants */ - /* K0 */ be_const_int(0), - /* K1 */ be_nested_str_weak(sessions), - /* K2 */ be_nested_str_weak(get_deviceid), - /* K3 */ be_nested_str_weak(get_fabric), - /* K4 */ be_nested_str_weak(push), - /* K5 */ be_const_int(1), - }), - be_str_weak(sessions_active), - &be_const_str_solidified, - ( &(const binstruction[22]) { /* code */ - 0x60040012, // 0000 GETGBL R1 G18 - 0x7C040000, // 0001 CALL R1 0 - 0x58080000, // 0002 LDCONST R2 K0 - 0x600C000C, // 0003 GETGBL R3 G12 - 0x88100101, // 0004 GETMBR R4 R0 K1 - 0x7C0C0200, // 0005 CALL R3 1 - 0x140C0403, // 0006 LT R3 R2 R3 - 0x780E000C, // 0007 JMPF R3 #0015 - 0x880C0101, // 0008 GETMBR R3 R0 K1 - 0x940C0602, // 0009 GETIDX R3 R3 R2 - 0x8C100702, // 000A GETMET R4 R3 K2 - 0x7C100200, // 000B CALL R4 1 - 0x78120005, // 000C JMPF R4 #0013 - 0x8C100703, // 000D GETMET R4 R3 K3 - 0x7C100200, // 000E CALL R4 1 - 0x78120002, // 000F JMPF R4 #0013 - 0x8C100304, // 0010 GETMET R4 R1 K4 - 0x5C180600, // 0011 MOVE R6 R3 - 0x7C100400, // 0012 CALL R4 2 - 0x00080505, // 0013 ADD R2 R2 K5 - 0x7001FFED, // 0014 JMP #0003 - 0x80040200, // 0015 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_session_by_local_session_id -********************************************************************/ -be_local_closure(Matter_Session_Store_get_session_by_local_session_id, /* name */ - be_nested_proto( - 6, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 4]) { /* constants */ - /* K0 */ be_nested_str_weak(sessions), - /* K1 */ be_const_int(0), - /* K2 */ be_nested_str_weak(local_session_id), - /* K3 */ be_const_int(1), - }), - be_str_weak(get_session_by_local_session_id), - &be_const_str_solidified, - ( &(const binstruction[21]) { /* code */ - 0x4C080000, // 0000 LDNIL R2 - 0x1C080202, // 0001 EQ R2 R1 R2 - 0x780A0001, // 0002 JMPF R2 #0005 - 0x4C080000, // 0003 LDNIL R2 - 0x80040400, // 0004 RET 1 R2 - 0x6008000C, // 0005 GETGBL R2 G12 - 0x880C0100, // 0006 GETMBR R3 R0 K0 - 0x7C080200, // 0007 CALL R2 1 - 0x580C0001, // 0008 LDCONST R3 K1 - 0x88100100, // 0009 GETMBR R4 R0 K0 - 0x14140602, // 000A LT R5 R3 R2 - 0x78160007, // 000B JMPF R5 #0014 - 0x94140803, // 000C GETIDX R5 R4 R3 - 0x88140B02, // 000D GETMBR R5 R5 K2 - 0x1C140A01, // 000E EQ R5 R5 R1 - 0x78160001, // 000F JMPF R5 #0012 - 0x94140803, // 0010 GETIDX R5 R4 R3 - 0x80040A00, // 0011 RET 1 R5 - 0x000C0703, // 0012 ADD R3 R3 K3 - 0x7001FFF5, // 0013 JMP #000A - 0x80000000, // 0014 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: gen_local_session_id -********************************************************************/ -be_local_closure(Matter_Session_Store_gen_local_session_id, /* name */ - be_nested_proto( - 6, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 6]) { /* constants */ - /* K0 */ be_nested_str_weak(crypto), - /* K1 */ be_nested_str_weak(random), - /* K2 */ be_const_int(2), - /* K3 */ be_nested_str_weak(get), - /* K4 */ be_const_int(0), - /* K5 */ be_nested_str_weak(get_session_by_local_session_id), - }), - be_str_weak(gen_local_session_id), - &be_const_str_solidified, - ( &(const binstruction[19]) { /* code */ - 0xA4060000, // 0000 IMPORT R1 K0 - 0x50080200, // 0001 LDBOOL R2 1 0 - 0x780A000E, // 0002 JMPF R2 #0012 - 0x8C080301, // 0003 GETMET R2 R1 K1 - 0x58100002, // 0004 LDCONST R4 K2 - 0x7C080400, // 0005 CALL R2 2 - 0x8C080503, // 0006 GETMET R2 R2 K3 - 0x58100004, // 0007 LDCONST R4 K4 - 0x58140002, // 0008 LDCONST R5 K2 - 0x7C080600, // 0009 CALL R2 3 - 0x8C0C0105, // 000A GETMET R3 R0 K5 - 0x5C140400, // 000B MOVE R5 R2 - 0x7C0C0400, // 000C CALL R3 2 - 0x4C100000, // 000D LDNIL R4 - 0x1C0C0604, // 000E EQ R3 R3 R4 - 0x780E0000, // 000F JMPF R3 #0011 - 0x80040400, // 0010 RET 1 R2 - 0x7001FFEE, // 0011 JMP #0001 - 0x80000000, // 0012 RET 0 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified function: get_session_by_source_node_id ********************************************************************/ @@ -2359,24 +2408,25 @@ be_local_closure(Matter_Session_Store_get_session_by_source_node_id, /* name * be_local_class(Matter_Session_Store, 1, NULL, - be_nested_map(16, + be_nested_map(17, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(remove_redundant_session, 15), be_const_closure(Matter_Session_Store_remove_redundant_session_closure) }, - { be_const_key_weak(get_session_by_source_node_id, 14), be_const_closure(Matter_Session_Store_get_session_by_source_node_id_closure) }, - { be_const_key_weak(gen_local_session_id, 6), be_const_closure(Matter_Session_Store_gen_local_session_id_closure) }, - { be_const_key_weak(init, 1), be_const_closure(Matter_Session_Store_init_closure) }, - { be_const_key_weak(save, -1), be_const_closure(Matter_Session_Store_save_closure) }, - { be_const_key_weak(load, -1), be_const_closure(Matter_Session_Store_load_closure) }, - { be_const_key_weak(create_session, -1), be_const_closure(Matter_Session_Store_create_session_closure) }, - { be_const_key_weak(remove_expired, -1), be_const_closure(Matter_Session_Store_remove_expired_closure) }, - { be_const_key_weak(FILENAME, 4), be_nested_str_weak(_matter_sessions_X2Ejson) }, - { be_const_key_weak(every_second, 5), be_const_closure(Matter_Session_Store_every_second_closure) }, - { be_const_key_weak(remove_session, 2), be_const_closure(Matter_Session_Store_remove_session_closure) }, - { be_const_key_weak(sessions_active, -1), be_const_closure(Matter_Session_Store_sessions_active_closure) }, - { be_const_key_weak(sessions, -1), be_const_var(0) }, - { be_const_key_weak(get_session_by_local_session_id, -1), be_const_closure(Matter_Session_Store_get_session_by_local_session_id_closure) }, + { be_const_key_weak(remove_expired, 6), be_const_closure(Matter_Session_Store_remove_expired_closure) }, + { be_const_key_weak(remove_redundant_session, -1), be_const_closure(Matter_Session_Store_remove_redundant_session_closure) }, { be_const_key_weak(add_session, -1), be_const_closure(Matter_Session_Store_add_session_closure) }, + { be_const_key_weak(sessions, 12), be_const_var(0) }, + { be_const_key_weak(sessions_active, -1), be_const_closure(Matter_Session_Store_sessions_active_closure) }, + { be_const_key_weak(every_second, 9), be_const_closure(Matter_Session_Store_every_second_closure) }, + { be_const_key_weak(find_session_by_resumption_id, -1), be_const_closure(Matter_Session_Store_find_session_by_resumption_id_closure) }, + { be_const_key_weak(load, -1), be_const_closure(Matter_Session_Store_load_closure) }, + { be_const_key_weak(gen_local_session_id, -1), be_const_closure(Matter_Session_Store_gen_local_session_id_closure) }, + { be_const_key_weak(get_session_by_local_session_id, -1), be_const_closure(Matter_Session_Store_get_session_by_local_session_id_closure) }, + { be_const_key_weak(FILENAME, -1), be_nested_str_weak(_matter_sessions_X2Ejson) }, + { be_const_key_weak(save, 10), be_const_closure(Matter_Session_Store_save_closure) }, { be_const_key_weak(find_session_source_id_unsecure, -1), be_const_closure(Matter_Session_Store_find_session_source_id_unsecure_closure) }, + { be_const_key_weak(remove_session, -1), be_const_closure(Matter_Session_Store_remove_session_closure) }, + { be_const_key_weak(create_session, -1), be_const_closure(Matter_Session_Store_create_session_closure) }, + { be_const_key_weak(init, 7), be_const_closure(Matter_Session_Store_init_closure) }, + { be_const_key_weak(get_session_by_source_node_id, -1), be_const_closure(Matter_Session_Store_get_session_by_source_node_id_closure) }, })), be_str_weak(Matter_Session_Store) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_TLV.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_TLV.h index 13d316a47..dc225d633 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_TLV.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_TLV.h @@ -1434,6 +1434,45 @@ void be_load_Matter_TLV_item_class(bvm *vm) { extern const bclass be_class_Matter_TLV_list; +/******************************************************************** +** Solidified function: add_obj +********************************************************************/ +be_local_closure(Matter_TLV_list_add_obj, /* name */ + be_nested_proto( + 7, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(to_TLV), + /* K1 */ be_nested_str_weak(tag_sub), + /* K2 */ be_nested_str_weak(val), + /* K3 */ be_nested_str_weak(push), + }), + be_str_weak(add_obj), + &be_const_str_solidified, + ( &(const binstruction[11]) { /* code */ + 0x4C0C0000, // 0000 LDNIL R3 + 0x200C0403, // 0001 NE R3 R2 R3 + 0x780E0006, // 0002 JMPF R3 #000A + 0x8C0C0500, // 0003 GETMET R3 R2 K0 + 0x7C0C0200, // 0004 CALL R3 1 + 0x900E0201, // 0005 SETMBR R3 K1 R1 + 0x88100102, // 0006 GETMBR R4 R0 K2 + 0x8C100903, // 0007 GETMET R4 R4 K3 + 0x5C180600, // 0008 MOVE R6 R3 + 0x7C100400, // 0009 CALL R4 2 + 0x80040000, // 000A RET 1 R0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: add_struct ********************************************************************/ @@ -1474,117 +1513,9 @@ be_local_closure(Matter_TLV_list_add_struct, /* name */ /******************************************************************** -** Solidified function: _encode_inner +** Solidified function: push ********************************************************************/ -be_local_closure(Matter_TLV_list__encode_inner, /* name */ - be_nested_proto( - 9, /* nstack */ - 3, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[10]) { /* constants */ - /* K0 */ be_nested_str_weak(_encode_tag), - /* K1 */ be_nested_str_weak(val), - /* K2 */ be_nested_str_weak(copy), - /* K3 */ be_nested_str_weak(sort), - /* K4 */ be_nested_str_weak(encode), - /* K5 */ be_nested_str_weak(stop_iteration), - /* K6 */ be_nested_str_weak(add), - /* K7 */ be_nested_str_weak(TLV), - /* K8 */ be_nested_str_weak(EOC), - /* K9 */ be_const_int(1), - }), - be_str_weak(_encode_inner), - &be_const_str_solidified, - ( &(const binstruction[35]) { /* code */ - 0x4C0C0000, // 0000 LDNIL R3 - 0x1C0C0203, // 0001 EQ R3 R1 R3 - 0x780E0002, // 0002 JMPF R3 #0006 - 0x600C0015, // 0003 GETGBL R3 G21 - 0x7C0C0000, // 0004 CALL R3 0 - 0x5C040600, // 0005 MOVE R1 R3 - 0x8C0C0100, // 0006 GETMET R3 R0 K0 - 0x5C140200, // 0007 MOVE R5 R1 - 0x7C0C0400, // 0008 CALL R3 2 - 0x880C0101, // 0009 GETMBR R3 R0 K1 - 0x8C0C0702, // 000A GETMET R3 R3 K2 - 0x7C0C0200, // 000B CALL R3 1 - 0x780A0002, // 000C JMPF R2 #0010 - 0x8C100103, // 000D GETMET R4 R0 K3 - 0x5C180600, // 000E MOVE R6 R3 - 0x7C100400, // 000F CALL R4 2 - 0x60100010, // 0010 GETGBL R4 G16 - 0x5C140600, // 0011 MOVE R5 R3 - 0x7C100200, // 0012 CALL R4 1 - 0xA8020005, // 0013 EXBLK 0 #001A - 0x5C140800, // 0014 MOVE R5 R4 - 0x7C140000, // 0015 CALL R5 0 - 0x8C180B04, // 0016 GETMET R6 R5 K4 - 0x5C200200, // 0017 MOVE R8 R1 - 0x7C180400, // 0018 CALL R6 2 - 0x7001FFF9, // 0019 JMP #0014 - 0x58100005, // 001A LDCONST R4 K5 - 0xAC100200, // 001B CATCH R4 1 0 - 0xB0080000, // 001C RAISE 2 R0 R0 - 0x8C100306, // 001D GETMET R4 R1 K6 - 0x88180107, // 001E GETMBR R6 R0 K7 - 0x88180D08, // 001F GETMBR R6 R6 K8 - 0x581C0009, // 0020 LDCONST R7 K9 - 0x7C100600, // 0021 CALL R4 3 - 0x80040200, // 0022 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: add_array -********************************************************************/ -be_local_closure(Matter_TLV_list_add_array, /* name */ - be_nested_proto( - 6, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 5]) { /* constants */ - /* K0 */ be_nested_str_weak(TLV), - /* K1 */ be_nested_str_weak(Matter_TLV_array), - /* K2 */ be_nested_str_weak(tag_sub), - /* K3 */ be_nested_str_weak(val), - /* K4 */ be_nested_str_weak(push), - }), - be_str_weak(add_array), - &be_const_str_solidified, - ( &(const binstruction[10]) { /* code */ - 0x88080100, // 0000 GETMBR R2 R0 K0 - 0x8C080501, // 0001 GETMET R2 R2 K1 - 0x5C100000, // 0002 MOVE R4 R0 - 0x7C080400, // 0003 CALL R2 2 - 0x900A0401, // 0004 SETMBR R2 K2 R1 - 0x880C0103, // 0005 GETMBR R3 R0 K3 - 0x8C0C0704, // 0006 GETMET R3 R3 K4 - 0x5C140400, // 0007 MOVE R5 R2 - 0x7C0C0400, // 0008 CALL R3 2 - 0x80040400, // 0009 RET 1 R2 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: init -********************************************************************/ -be_local_closure(Matter_TLV_list_init, /* name */ +be_local_closure(Matter_TLV_list_push, /* name */ be_nested_proto( 5, /* nstack */ 2, /* argc */ @@ -1594,29 +1525,18 @@ be_local_closure(Matter_TLV_list_init, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 5]) { /* constants */ - /* K0 */ be_nested_str_weak(init), - /* K1 */ be_nested_str_weak(typ), - /* K2 */ be_nested_str_weak(TLV), - /* K3 */ be_nested_str_weak(LIST), - /* K4 */ be_nested_str_weak(val), + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(val), + /* K1 */ be_nested_str_weak(push), }), - be_str_weak(init), + be_str_weak(push), &be_const_str_solidified, - ( &(const binstruction[13]) { /* code */ - 0x60080003, // 0000 GETGBL R2 G3 - 0x5C0C0000, // 0001 MOVE R3 R0 - 0x7C080200, // 0002 CALL R2 1 - 0x8C080500, // 0003 GETMET R2 R2 K0 - 0x5C100200, // 0004 MOVE R4 R1 - 0x7C080400, // 0005 CALL R2 2 - 0x88080102, // 0006 GETMBR R2 R0 K2 - 0x88080503, // 0007 GETMBR R2 R2 K3 - 0x90020202, // 0008 SETMBR R0 K1 R2 - 0x60080012, // 0009 GETGBL R2 G18 - 0x7C080000, // 000A CALL R2 0 - 0x90020802, // 000B SETMBR R0 K4 R2 - 0x80000000, // 000C RET 0 + ( &(const binstruction[ 5]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x5C100200, // 0002 MOVE R4 R1 + 0x7C080400, // 0003 CALL R2 2 + 0x80000000, // 0004 RET 0 }) ) ); @@ -1624,28 +1544,30 @@ be_local_closure(Matter_TLV_list_init, /* name */ /******************************************************************** -** Solidified function: size +** Solidified function: getsubval ********************************************************************/ -be_local_closure(Matter_TLV_list_size, /* name */ +be_local_closure(Matter_TLV_list_getsubval, /* name */ be_nested_proto( - 3, /* nstack */ - 1, /* argc */ + 5, /* nstack */ + 2, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(val), + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(getsub), + /* K1 */ be_nested_str_weak(val), }), - be_str_weak(size), + be_str_weak(getsubval), &be_const_str_solidified, - ( &(const binstruction[ 4]) { /* code */ - 0x6004000C, // 0000 GETGBL R1 G12 - 0x88080100, // 0001 GETMBR R2 R0 K0 - 0x7C040200, // 0002 CALL R1 1 - 0x80040200, // 0003 RET 1 R1 + ( &(const binstruction[ 5]) { /* code */ + 0x8C080100, // 0000 GETMET R2 R0 K0 + 0x5C100200, // 0001 MOVE R4 R1 + 0x7C080400, // 0002 CALL R2 2 + 0x88080501, // 0003 GETMBR R2 R2 K1 + 0x80040400, // 0004 RET 1 R2 }) ) ); @@ -1720,11 +1642,11 @@ be_local_closure(Matter_TLV_list_item, /* name */ /******************************************************************** -** Solidified function: tostring +** Solidified function: size ********************************************************************/ -be_local_closure(Matter_TLV_list_tostring, /* name */ +be_local_closure(Matter_TLV_list_size, /* name */ be_nested_proto( - 6, /* nstack */ + 3, /* nstack */ 1, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -1732,63 +1654,16 @@ be_local_closure(Matter_TLV_list_tostring, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_nested_str_weak(tostring_inner), - /* K1 */ be_nested_str_weak(_X5B_X5B), - /* K2 */ be_nested_str_weak(_X5D_X5D), - }), - be_str_weak(tostring), - &be_const_str_solidified, - ( &(const binstruction[ 6]) { /* code */ - 0x8C040100, // 0000 GETMET R1 R0 K0 - 0x500C0000, // 0001 LDBOOL R3 0 0 - 0x58100001, // 0002 LDCONST R4 K1 - 0x58140002, // 0003 LDCONST R5 K2 - 0x7C040800, // 0004 CALL R1 4 - 0x80040200, // 0005 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: findsub -********************************************************************/ -be_local_closure(Matter_TLV_list_findsub, /* name */ - be_nested_proto( - 6, /* nstack */ - 3, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ + ( &(const bvalue[ 1]) { /* constants */ /* K0 */ be_nested_str_weak(val), - /* K1 */ be_nested_str_weak(tag_sub), - /* K2 */ be_nested_str_weak(stop_iteration), }), - be_str_weak(findsub), + be_str_weak(size), &be_const_str_solidified, - ( &(const binstruction[16]) { /* code */ - 0x600C0010, // 0000 GETGBL R3 G16 - 0x88100100, // 0001 GETMBR R4 R0 K0 - 0x7C0C0200, // 0002 CALL R3 1 - 0xA8020007, // 0003 EXBLK 0 #000C - 0x5C100600, // 0004 MOVE R4 R3 - 0x7C100000, // 0005 CALL R4 0 - 0x88140901, // 0006 GETMBR R5 R4 K1 - 0x1C140A01, // 0007 EQ R5 R5 R1 - 0x78160001, // 0008 JMPF R5 #000B - 0xA8040001, // 0009 EXBLK 1 1 - 0x80040800, // 000A RET 1 R4 - 0x7001FFF7, // 000B JMP #0004 - 0x580C0002, // 000C LDCONST R3 K2 - 0xAC0C0200, // 000D CATCH R3 1 0 - 0xB0080000, // 000E RAISE 2 R0 R0 - 0x80040400, // 000F RET 1 R2 + ( &(const binstruction[ 4]) { /* code */ + 0x6004000C, // 0000 GETGBL R1 G12 + 0x88080100, // 0001 GETMBR R2 R0 K0 + 0x7C040200, // 0002 CALL R1 1 + 0x80040200, // 0003 RET 1 R1 }) ) ); @@ -1831,6 +1706,37 @@ be_local_closure(Matter_TLV_list_findsubtyp, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: encode +********************************************************************/ +be_local_closure(Matter_TLV_list_encode, /* name */ + be_nested_proto( + 6, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(_encode_inner), + /* K1 */ be_nested_str_weak(is_struct), + }), + be_str_weak(encode), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x8C080100, // 0000 GETMET R2 R0 K0 + 0x5C100200, // 0001 MOVE R4 R1 + 0x88140101, // 0002 GETMBR R5 R0 K1 + 0x7C080600, // 0003 CALL R2 3 + 0x80040400, // 0004 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: tostring_inner ********************************************************************/ @@ -1958,6 +1864,39 @@ be_local_closure(Matter_TLV_list_tostring_inner, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: tostring +********************************************************************/ +be_local_closure(Matter_TLV_list_tostring, /* name */ + be_nested_proto( + 6, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(tostring_inner), + /* K1 */ be_nested_str_weak(_X5B_X5B), + /* K2 */ be_nested_str_weak(_X5D_X5D), + }), + be_str_weak(tostring), + &be_const_str_solidified, + ( &(const binstruction[ 6]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x500C0000, // 0001 LDBOOL R3 0 0 + 0x58100001, // 0002 LDCONST R4 K1 + 0x58140002, // 0003 LDCONST R5 K2 + 0x7C040800, // 0004 CALL R1 4 + 0x80040200, // 0005 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: findsubval ********************************************************************/ @@ -1994,60 +1933,9 @@ be_local_closure(Matter_TLV_list_findsubval, /* name */ /******************************************************************** -** Solidified function: parse +** Solidified function: init ********************************************************************/ -be_local_closure(Matter_TLV_list_parse, /* name */ - be_nested_proto( - 8, /* nstack */ - 3, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 7]) { /* constants */ - /* K0 */ be_nested_str_weak(TLV), - /* K1 */ be_nested_str_weak(EOC), - /* K2 */ be_nested_str_weak(parse), - /* K3 */ be_nested_str_weak(next_idx), - /* K4 */ be_nested_str_weak(val), - /* K5 */ be_nested_str_weak(push), - /* K6 */ be_const_int(1), - }), - be_str_weak(parse), - &be_const_str_solidified, - ( &(const binstruction[20]) { /* code */ - 0x940C0202, // 0000 GETIDX R3 R1 R2 - 0x88100100, // 0001 GETMBR R4 R0 K0 - 0x88100901, // 0002 GETMBR R4 R4 K1 - 0x200C0604, // 0003 NE R3 R3 R4 - 0x780E000B, // 0004 JMPF R3 #0011 - 0x880C0100, // 0005 GETMBR R3 R0 K0 - 0x8C0C0702, // 0006 GETMET R3 R3 K2 - 0x5C140200, // 0007 MOVE R5 R1 - 0x5C180400, // 0008 MOVE R6 R2 - 0x5C1C0000, // 0009 MOVE R7 R0 - 0x7C0C0800, // 000A CALL R3 4 - 0x88080703, // 000B GETMBR R2 R3 K3 - 0x88100104, // 000C GETMBR R4 R0 K4 - 0x8C100905, // 000D GETMET R4 R4 K5 - 0x5C180600, // 000E MOVE R6 R3 - 0x7C100400, // 000F CALL R4 2 - 0x7001FFEE, // 0010 JMP #0000 - 0x00080506, // 0011 ADD R2 R2 K6 - 0x90020602, // 0012 SETMBR R0 K3 R2 - 0x80040400, // 0013 RET 1 R2 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: getsubval -********************************************************************/ -be_local_closure(Matter_TLV_list_getsubval, /* name */ +be_local_closure(Matter_TLV_list_init, /* name */ be_nested_proto( 5, /* nstack */ 2, /* argc */ @@ -2057,18 +1945,29 @@ be_local_closure(Matter_TLV_list_getsubval, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(getsub), - /* K1 */ be_nested_str_weak(val), + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(init), + /* K1 */ be_nested_str_weak(typ), + /* K2 */ be_nested_str_weak(TLV), + /* K3 */ be_nested_str_weak(LIST), + /* K4 */ be_nested_str_weak(val), }), - be_str_weak(getsubval), + be_str_weak(init), &be_const_str_solidified, - ( &(const binstruction[ 5]) { /* code */ - 0x8C080100, // 0000 GETMET R2 R0 K0 - 0x5C100200, // 0001 MOVE R4 R1 - 0x7C080400, // 0002 CALL R2 2 - 0x88080501, // 0003 GETMBR R2 R2 K1 - 0x80040400, // 0004 RET 1 R2 + ( &(const binstruction[13]) { /* code */ + 0x60080003, // 0000 GETGBL R2 G3 + 0x5C0C0000, // 0001 MOVE R3 R0 + 0x7C080200, // 0002 CALL R2 1 + 0x8C080500, // 0003 GETMET R2 R2 K0 + 0x5C100200, // 0004 MOVE R4 R1 + 0x7C080400, // 0005 CALL R2 2 + 0x88080102, // 0006 GETMBR R2 R0 K2 + 0x88080503, // 0007 GETMBR R2 R2 K3 + 0x90020202, // 0008 SETMBR R0 K1 R2 + 0x60080012, // 0009 GETGBL R2 G18 + 0x7C080000, // 000A CALL R2 0 + 0x90020802, // 000B SETMBR R0 K4 R2 + 0x80000000, // 000C RET 0 }) ) ); @@ -2076,48 +1975,9 @@ be_local_closure(Matter_TLV_list_getsubval, /* name */ /******************************************************************** -** Solidified function: add_obj +** Solidified function: add_array ********************************************************************/ -be_local_closure(Matter_TLV_list_add_obj, /* name */ - be_nested_proto( - 7, /* nstack */ - 3, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 4]) { /* constants */ - /* K0 */ be_nested_str_weak(to_TLV), - /* K1 */ be_nested_str_weak(tag_sub), - /* K2 */ be_nested_str_weak(val), - /* K3 */ be_nested_str_weak(push), - }), - be_str_weak(add_obj), - &be_const_str_solidified, - ( &(const binstruction[11]) { /* code */ - 0x4C0C0000, // 0000 LDNIL R3 - 0x200C0403, // 0001 NE R3 R2 R3 - 0x780E0006, // 0002 JMPF R3 #000A - 0x8C0C0500, // 0003 GETMET R3 R2 K0 - 0x7C0C0200, // 0004 CALL R3 1 - 0x900E0201, // 0005 SETMBR R3 K1 R1 - 0x88100102, // 0006 GETMBR R4 R0 K2 - 0x8C100903, // 0007 GETMET R4 R4 K3 - 0x5C180600, // 0008 MOVE R6 R3 - 0x7C100400, // 0009 CALL R4 2 - 0x80040000, // 000A RET 1 R0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: encode -********************************************************************/ -be_local_closure(Matter_TLV_list_encode, /* name */ +be_local_closure(Matter_TLV_list_add_array, /* name */ be_nested_proto( 6, /* nstack */ 2, /* argc */ @@ -2127,76 +1987,26 @@ be_local_closure(Matter_TLV_list_encode, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(_encode_inner), + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(TLV), + /* K1 */ be_nested_str_weak(Matter_TLV_array), + /* K2 */ be_nested_str_weak(tag_sub), + /* K3 */ be_nested_str_weak(val), + /* K4 */ be_nested_str_weak(push), }), - be_str_weak(encode), + be_str_weak(add_array), &be_const_str_solidified, - ( &(const binstruction[ 5]) { /* code */ - 0x8C080100, // 0000 GETMET R2 R0 K0 - 0x5C100200, // 0001 MOVE R4 R1 - 0x50140000, // 0002 LDBOOL R5 0 0 - 0x7C080600, // 0003 CALL R2 3 - 0x80040400, // 0004 RET 1 R2 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: setitem -********************************************************************/ -be_local_closure(Matter_TLV_list_setitem, /* name */ - be_nested_proto( - 4, /* nstack */ - 3, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(val), - }), - be_str_weak(setitem), - &be_const_str_solidified, - ( &(const binstruction[ 3]) { /* code */ - 0x880C0100, // 0000 GETMBR R3 R0 K0 - 0x980C0202, // 0001 SETIDX R3 R1 R2 - 0x80000000, // 0002 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: push -********************************************************************/ -be_local_closure(Matter_TLV_list_push, /* name */ - be_nested_proto( - 5, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(val), - /* K1 */ be_nested_str_weak(push), - }), - be_str_weak(push), - &be_const_str_solidified, - ( &(const binstruction[ 5]) { /* code */ + ( &(const binstruction[10]) { /* code */ 0x88080100, // 0000 GETMBR R2 R0 K0 0x8C080501, // 0001 GETMET R2 R2 K1 - 0x5C100200, // 0002 MOVE R4 R1 + 0x5C100000, // 0002 MOVE R4 R0 0x7C080400, // 0003 CALL R2 2 - 0x80000000, // 0004 RET 0 + 0x900A0401, // 0004 SETMBR R2 K2 R1 + 0x880C0103, // 0005 GETMBR R3 R0 K3 + 0x8C0C0704, // 0006 GETMET R3 R3 K4 + 0x5C140400, // 0007 MOVE R5 R2 + 0x7C0C0400, // 0008 CALL R3 2 + 0x80040400, // 0009 RET 1 R2 }) ) ); @@ -2255,6 +2065,197 @@ be_local_closure(Matter_TLV_list_add_TLV, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: setitem +********************************************************************/ +be_local_closure(Matter_TLV_list_setitem, /* name */ + be_nested_proto( + 4, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(val), + }), + be_str_weak(setitem), + &be_const_str_solidified, + ( &(const binstruction[ 3]) { /* code */ + 0x880C0100, // 0000 GETMBR R3 R0 K0 + 0x980C0202, // 0001 SETIDX R3 R1 R2 + 0x80000000, // 0002 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: _encode_inner +********************************************************************/ +be_local_closure(Matter_TLV_list__encode_inner, /* name */ + be_nested_proto( + 9, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[10]) { /* constants */ + /* K0 */ be_nested_str_weak(_encode_tag), + /* K1 */ be_nested_str_weak(val), + /* K2 */ be_nested_str_weak(copy), + /* K3 */ be_nested_str_weak(sort), + /* K4 */ be_nested_str_weak(encode), + /* K5 */ be_nested_str_weak(stop_iteration), + /* K6 */ be_nested_str_weak(add), + /* K7 */ be_nested_str_weak(TLV), + /* K8 */ be_nested_str_weak(EOC), + /* K9 */ be_const_int(1), + }), + be_str_weak(_encode_inner), + &be_const_str_solidified, + ( &(const binstruction[35]) { /* code */ + 0x4C0C0000, // 0000 LDNIL R3 + 0x1C0C0203, // 0001 EQ R3 R1 R3 + 0x780E0002, // 0002 JMPF R3 #0006 + 0x600C0015, // 0003 GETGBL R3 G21 + 0x7C0C0000, // 0004 CALL R3 0 + 0x5C040600, // 0005 MOVE R1 R3 + 0x8C0C0100, // 0006 GETMET R3 R0 K0 + 0x5C140200, // 0007 MOVE R5 R1 + 0x7C0C0400, // 0008 CALL R3 2 + 0x880C0101, // 0009 GETMBR R3 R0 K1 + 0x8C0C0702, // 000A GETMET R3 R3 K2 + 0x7C0C0200, // 000B CALL R3 1 + 0x780A0002, // 000C JMPF R2 #0010 + 0x8C100103, // 000D GETMET R4 R0 K3 + 0x5C180600, // 000E MOVE R6 R3 + 0x7C100400, // 000F CALL R4 2 + 0x60100010, // 0010 GETGBL R4 G16 + 0x5C140600, // 0011 MOVE R5 R3 + 0x7C100200, // 0012 CALL R4 1 + 0xA8020005, // 0013 EXBLK 0 #001A + 0x5C140800, // 0014 MOVE R5 R4 + 0x7C140000, // 0015 CALL R5 0 + 0x8C180B04, // 0016 GETMET R6 R5 K4 + 0x5C200200, // 0017 MOVE R8 R1 + 0x7C180400, // 0018 CALL R6 2 + 0x7001FFF9, // 0019 JMP #0014 + 0x58100005, // 001A LDCONST R4 K5 + 0xAC100200, // 001B CATCH R4 1 0 + 0xB0080000, // 001C RAISE 2 R0 R0 + 0x8C100306, // 001D GETMET R4 R1 K6 + 0x88180107, // 001E GETMBR R6 R0 K7 + 0x88180D08, // 001F GETMBR R6 R6 K8 + 0x581C0009, // 0020 LDCONST R7 K9 + 0x7C100600, // 0021 CALL R4 3 + 0x80040200, // 0022 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: findsub +********************************************************************/ +be_local_closure(Matter_TLV_list_findsub, /* name */ + be_nested_proto( + 6, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(val), + /* K1 */ be_nested_str_weak(tag_sub), + /* K2 */ be_nested_str_weak(stop_iteration), + }), + be_str_weak(findsub), + &be_const_str_solidified, + ( &(const binstruction[16]) { /* code */ + 0x600C0010, // 0000 GETGBL R3 G16 + 0x88100100, // 0001 GETMBR R4 R0 K0 + 0x7C0C0200, // 0002 CALL R3 1 + 0xA8020007, // 0003 EXBLK 0 #000C + 0x5C100600, // 0004 MOVE R4 R3 + 0x7C100000, // 0005 CALL R4 0 + 0x88140901, // 0006 GETMBR R5 R4 K1 + 0x1C140A01, // 0007 EQ R5 R5 R1 + 0x78160001, // 0008 JMPF R5 #000B + 0xA8040001, // 0009 EXBLK 1 1 + 0x80040800, // 000A RET 1 R4 + 0x7001FFF7, // 000B JMP #0004 + 0x580C0002, // 000C LDCONST R3 K2 + 0xAC0C0200, // 000D CATCH R3 1 0 + 0xB0080000, // 000E RAISE 2 R0 R0 + 0x80040400, // 000F RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: parse +********************************************************************/ +be_local_closure(Matter_TLV_list_parse, /* name */ + be_nested_proto( + 8, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 7]) { /* constants */ + /* K0 */ be_nested_str_weak(TLV), + /* K1 */ be_nested_str_weak(EOC), + /* K2 */ be_nested_str_weak(parse), + /* K3 */ be_nested_str_weak(next_idx), + /* K4 */ be_nested_str_weak(val), + /* K5 */ be_nested_str_weak(push), + /* K6 */ be_const_int(1), + }), + be_str_weak(parse), + &be_const_str_solidified, + ( &(const binstruction[20]) { /* code */ + 0x940C0202, // 0000 GETIDX R3 R1 R2 + 0x88100100, // 0001 GETMBR R4 R0 K0 + 0x88100901, // 0002 GETMBR R4 R4 K1 + 0x200C0604, // 0003 NE R3 R3 R4 + 0x780E000B, // 0004 JMPF R3 #0011 + 0x880C0100, // 0005 GETMBR R3 R0 K0 + 0x8C0C0702, // 0006 GETMET R3 R3 K2 + 0x5C140200, // 0007 MOVE R5 R1 + 0x5C180400, // 0008 MOVE R6 R2 + 0x5C1C0000, // 0009 MOVE R7 R0 + 0x7C0C0800, // 000A CALL R3 4 + 0x88080703, // 000B GETMBR R2 R3 K3 + 0x88100104, // 000C GETMBR R4 R0 K4 + 0x8C100905, // 000D GETMET R4 R4 K5 + 0x5C180600, // 000E MOVE R6 R3 + 0x7C100400, // 000F CALL R4 2 + 0x7001FFEE, // 0010 JMP #0000 + 0x00080506, // 0011 ADD R2 R2 K6 + 0x90020602, // 0012 SETMBR R0 K3 R2 + 0x80040400, // 0013 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: getsub ********************************************************************/ @@ -2297,28 +2298,29 @@ extern const bclass be_class_Matter_TLV_item; be_local_class(Matter_TLV_list, 0, &be_class_Matter_TLV_item, - be_nested_map(20, + be_nested_map(21, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(add_struct, -1), be_const_closure(Matter_TLV_list_add_struct_closure) }, - { be_const_key_weak(getsub, -1), be_const_closure(Matter_TLV_list_getsub_closure) }, - { be_const_key_weak(add_array, -1), be_const_closure(Matter_TLV_list_add_array_closure) }, - { be_const_key_weak(add_TLV, -1), be_const_closure(Matter_TLV_list_add_TLV_closure) }, - { be_const_key_weak(size, -1), be_const_closure(Matter_TLV_list_size_closure) }, - { be_const_key_weak(add_list, 18), be_const_closure(Matter_TLV_list_add_list_closure) }, - { be_const_key_weak(item, 13), be_const_closure(Matter_TLV_list_item_closure) }, - { be_const_key_weak(findsubval, -1), be_const_closure(Matter_TLV_list_findsubval_closure) }, - { be_const_key_weak(parse, -1), be_const_closure(Matter_TLV_list_parse_closure) }, - { be_const_key_weak(findsubtyp, 3), be_const_closure(Matter_TLV_list_findsubtyp_closure) }, - { be_const_key_weak(tostring_inner, -1), be_const_closure(Matter_TLV_list_tostring_inner_closure) }, - { be_const_key_weak(encode, 7), be_const_closure(Matter_TLV_list_encode_closure) }, - { be_const_key_weak(findsub, 8), be_const_closure(Matter_TLV_list_findsub_closure) }, - { be_const_key_weak(getsubval, -1), be_const_closure(Matter_TLV_list_getsubval_closure) }, { be_const_key_weak(add_obj, -1), be_const_closure(Matter_TLV_list_add_obj_closure) }, - { be_const_key_weak(init, 11), be_const_closure(Matter_TLV_list_init_closure) }, - { be_const_key_weak(setitem, -1), be_const_closure(Matter_TLV_list_setitem_closure) }, + { be_const_key_weak(add_struct, -1), be_const_closure(Matter_TLV_list_add_struct_closure) }, { be_const_key_weak(push, -1), be_const_closure(Matter_TLV_list_push_closure) }, - { be_const_key_weak(tostring, -1), be_const_closure(Matter_TLV_list_tostring_closure) }, - { be_const_key_weak(_encode_inner, 1), be_const_closure(Matter_TLV_list__encode_inner_closure) }, + { be_const_key_weak(getsubval, 20), be_const_closure(Matter_TLV_list_getsubval_closure) }, + { be_const_key_weak(getsub, -1), be_const_closure(Matter_TLV_list_getsub_closure) }, + { be_const_key_weak(parse, -1), be_const_closure(Matter_TLV_list_parse_closure) }, + { be_const_key_weak(size, -1), be_const_closure(Matter_TLV_list_size_closure) }, + { be_const_key_weak(findsubtyp, -1), be_const_closure(Matter_TLV_list_findsubtyp_closure) }, + { be_const_key_weak(encode, -1), be_const_closure(Matter_TLV_list_encode_closure) }, + { be_const_key_weak(tostring_inner, 4), be_const_closure(Matter_TLV_list_tostring_inner_closure) }, + { be_const_key_weak(tostring, 16), be_const_closure(Matter_TLV_list_tostring_closure) }, + { be_const_key_weak(findsubval, -1), be_const_closure(Matter_TLV_list_findsubval_closure) }, + { be_const_key_weak(init, -1), be_const_closure(Matter_TLV_list_init_closure) }, + { be_const_key_weak(add_array, 15), be_const_closure(Matter_TLV_list_add_array_closure) }, + { be_const_key_weak(add_TLV, 18), be_const_closure(Matter_TLV_list_add_TLV_closure) }, + { be_const_key_weak(findsub, -1), be_const_closure(Matter_TLV_list_findsub_closure) }, + { be_const_key_weak(_encode_inner, -1), be_const_closure(Matter_TLV_list__encode_inner_closure) }, + { be_const_key_weak(is_struct, -1), be_const_bool(0) }, + { be_const_key_weak(setitem, -1), be_const_closure(Matter_TLV_list_setitem_closure) }, + { be_const_key_weak(item, 5), be_const_closure(Matter_TLV_list_item_closure) }, + { be_const_key_weak(add_list, -1), be_const_closure(Matter_TLV_list_add_list_closure) }, })), be_str_weak(Matter_TLV_list) ); @@ -2407,36 +2409,6 @@ be_local_closure(Matter_TLV_struct_tostring, /* name */ /*******************************************************************/ -/******************************************************************** -** Solidified function: encode -********************************************************************/ -be_local_closure(Matter_TLV_struct_encode, /* name */ - be_nested_proto( - 6, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(_encode_inner), - }), - be_str_weak(encode), - &be_const_str_solidified, - ( &(const binstruction[ 5]) { /* code */ - 0x8C080100, // 0000 GETMET R2 R0 K0 - 0x5C100200, // 0001 MOVE R4 R1 - 0x50140200, // 0002 LDBOOL R5 1 0 - 0x7C080600, // 0003 CALL R2 3 - 0x80040400, // 0004 RET 1 R2 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified class: Matter_TLV_struct ********************************************************************/ @@ -2448,7 +2420,7 @@ be_local_class(Matter_TLV_struct, ( (struct bmapnode*) &(const bmapnode[]) { { be_const_key_weak(init, -1), be_const_closure(Matter_TLV_struct_init_closure) }, { be_const_key_weak(tostring, -1), be_const_closure(Matter_TLV_struct_tostring_closure) }, - { be_const_key_weak(encode, -1), be_const_closure(Matter_TLV_struct_encode_closure) }, + { be_const_key_weak(is_struct, -1), be_const_bool(1) }, })), be_str_weak(Matter_TLV_struct) ); From bc7ef89b3ceefd0477c9b4abb3bbc1ea6575ab7d Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Sun, 12 Feb 2023 21:33:13 +0100 Subject: [PATCH 261/262] ESP8266 Fix TLS SNI which would prevent AWS IoT connection (#17936) --- CHANGELOG.md | 1 + lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c6f83fd81..1dc28b1f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ All notable changes to this project will be documented in this file. ### Changed ### Fixed +- ESP8266 Fix TLS SNI which would prevent AWS IoT connection ### Removed diff --git a/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.cpp b/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.cpp index aa1aab9dd..6887ff594 100755 --- a/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.cpp +++ b/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.cpp @@ -309,7 +309,7 @@ int WiFiClientSecure_light::connect(IPAddress ip, uint16_t port) { setLastError(ERR_TCP_CONNECT); return 0; } - return _connectSSL(nullptr); + return _connectSSL(_domain.isEmpty() ? nullptr : _domain.c_str()); } #endif From 87686c0d52a7db6db1197d8e88fa5492ce4b4dbc Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 13 Feb 2023 16:07:38 +0100 Subject: [PATCH 262/262] update changelogs --- CHANGELOG.md | 2 +- RELEASENOTES.md | 7 +++---- TEMPLATES.md | 14 +++++++------- tasmota/tasmota_support/support_features.ino | 2 +- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1dc28b1f5..488cceee7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,7 @@ All notable changes to this project will be documented in this file. ### Changed ### Fixed -- ESP8266 Fix TLS SNI which would prevent AWS IoT connection +- ESP8266 Fix TLS SNI which would prevent AWS IoT connection (#17936) ### Removed diff --git a/RELEASENOTES.md b/RELEASENOTES.md index f73949263..643d9943a 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -141,17 +141,16 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm - Energy totals max supported value from +/-21474.83647 to +/-2147483.647 kWh - Removed delays in TasmotaSerial and TasmotaModbus Tx enable switching - Keep webserver enabled on command ``upload`` +- Better support for virtual buttons and switches up to a total of 28 - Increase rule event buffer from 100 to 256 characters [#16943](https://github.com/arendst/Tasmota/issues/16943) -- TuyaMcu rewrite by btsimonh [#17051](https://github.com/arendst/Tasmota/issues/17051) - Tasmota OTA scripts now support both unzipped and gzipped file uploads [#17378](https://github.com/arendst/Tasmota/issues/17378) ### Fixed - Modbus transmit enable GPIO enabled once during write buffer - Energy dummy switched voltage and power regression from v12.2.0.2 -- ESP8266 set GPIO's to input on power on fixing relay spikes [#17531](https://github.com/arendst/Tasmota/issues/17531) - Shutter default motorstop set to 0 [#17403](https://github.com/arendst/Tasmota/issues/17403) - Shutter default tilt configuration [#17484](https://github.com/arendst/Tasmota/issues/17484) - Orno WE517 modbus serial config 8E1 setting [#17545](https://github.com/arendst/Tasmota/issues/17545) - Rename ``tasmota4M.bin`` to ``tasmota-4M.bin`` to solve use of ``tasmota-minimal.bin`` [#17674](https://github.com/arendst/Tasmota/issues/17674) - -### Removed +- ESP8266 set GPIO's to input on power on fixing relay spikes [#17531](https://github.com/arendst/Tasmota/issues/17531) +- ESP8266 TLS SNI which would prevent AWS IoT connection [#17936](https://github.com/arendst/Tasmota/issues/17936) \ No newline at end of file diff --git a/TEMPLATES.md b/TEMPLATES.md index a3e22fdc5..440eb0942 100644 --- a/TEMPLATES.md +++ b/TEMPLATES.md @@ -5,7 +5,7 @@ # Templates -Find below the available templates as of January 2023. More template information can be found in the [Tasmota Device Templates Repository](http://blakadder.github.io/templates) +Find below the available templates as of February 2023. More template information can be found in the [Tasmota Device Templates Repository](http://blakadder.github.io/templates) ## Adapter Board ``` @@ -302,7 +302,7 @@ Silicognition wESP32 {"NAME":"wESP32","GPIO":[0,0,1,0,1,1,0,0,1,1,1,1,55 TZT ESP8266 Weather Station Kit {"NAME":"TZT Weather Station","GPIO":[32,0,640,0,1,1184,0,0,1,1,608,1,1,1],"FLAG":0,"BASE":18} Wemos D1 Mini ESP32 {"NAME":"Wemos D1 Mini ESP32","GPIO":[0,0,1,0,1,1,0,0,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0],"FLAG":0,"BASE":1} Wemos LOLIN32 Lite V1.0.0 (ESP32) {"NAME":"Wemos LOLIN32 Lite V1.0.0","GPIO":[1,0,1,0,1,1,0,0,1,1,1,1,1,1,1,1,0,0,0,1,0,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0],"FLAG":0,"BASE":1} -Wireless Tag ESP32 Ethernet {"NAME":"WT32-ETH01","GPIO":[1,1,1,1,1,1,0,0,1,0,1,1,3840,576,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,1,1,0,1,1,0,0,1],"FLAG":0,"BASE":1} +Wireless Tag ESP32 Ethernet {"NAME":"WT32_ETH01","GPIO":[1,1,1,1,1,1,0,0,1,0,1,1,3840,576,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,1,1,0,1,1,0,0,1],"FLAG":0,"BASE":1} Witty Cloud {"NAME":"Witty Cloud","GPIO":[1,1,320,1,32,1,0,0,417,418,1,416,1,4704],"FLAG":0,"BASE":32} Yison ESP-01/ESP-202 {"NAME":"Yison Dev Board","GPIO":[259,544,258,1,260,261,1,1,416,418,257,417,256,1],"FLAG":0,"BASE":18} ``` @@ -533,7 +533,7 @@ Goldair SleepSmart GCPF315 {"NAME":"Goldair Fan","GPIO":[0,0,0,0,0,0,0,0,0,230 Holmes 36" Oscillating Tower {"NAME":"Generic","GPIO":[1,1,1,1,1,1,1,1,1,1,1,1,1,1],"FLAG":0,"BASE":54,"CMND":"TuyaMcu 11,1 | TuyaMcu 12,5 | WebButton1 Power | WebButton2 Oscillation "} Lucci Connect Remote Control {"NAME":"Lucci Fan","GPIO":[0,0,0,0,0,0,0,0,0,2304,0,2272,0,0],"FLAG":0,"BASE":54} QuietCool Gable Mount Attic {"NAME":"QuietCool-AFG-SMT-PRO-2.0","GPIO":[0,0,0,0,0,224,0,0,0,0,0,0,0,0,640,608,0,0,0,225,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":1,"CMND":"Interlock 1|WebButton1 Low|WebButton2 High|SO8 1"} -Sichler Haushaltsger�te Column {"NAME":"Sichler Fan","GPIO":[0,2272,0,2304,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54} +Sichler Haushaltsgeraete Column {"NAME":"Sichler Fan","GPIO":[0,2272,0,2304,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54} Technical Pro {"NAME":"FXA16 Fan","GPIO":[0,2272,0,2304,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54,"CMND":"TuyaMCU 12,8"} Zemismart Bladeless {"NAME":"Bladeless Fan","GPIO":[1,2272,1,2304,1,1,0,0,1,1,1,1,1,0],"FLAG":0,"BASE":54} ``` @@ -688,7 +688,7 @@ RGB 12-24V {"NAME":"WS03","GPIO":[0,0,0,0,0,0,0,0,418,417,416, RGB+CCT 12-24V {"NAME":"WS05","GPIO":[0,0,0,0,0,420,0,0,418,417,416,419,0,0],"FLAG":0,"BASE":18} RGBW 12-24V {"NAME":"*WS04","GPIO":[0,0,0,0,0,0,0,0,417,418,416,419,0,0],"FLAG":0,"BASE":18} Shelly RGBW2 {"NAME":"Shelly RGBW2","GPIO":[0,0,288,0,419,1,0,0,416,32,418,417,0,0],"FLAG":0,"BASE":18} -Spectrum Smart RGBCCT {"NAME":"Spectrum Smart WOJ+05641","GPIO":[32,0,0,0,0,416,0,0,0,417,0,0,0,0],"FLAG":0,"BASE":18} +Spectrum Smart RGBCCT {"NAME":"Spectrum Smart RGB CCT Controller","GPIO":[32,0,0,0,416,419,0,0,417,420,418,0,0,0],"FLAG":0,"BASE":18} Xunata Led Controller High Voltage 110/220V {"NAME":"KL-LED-WIFI-AC","GPIO":[0,0,0,0,0,0,0,0,0,416,0,0,0,0],"FLAG":0,"BASE":18} ZJ-WF-ESP-A v1.1 {"NAME":"RGB2","GPIO":[0,0,0,0,0,0,0,0,417,416,418,0,0,0],"FLAG":0,"BASE":18} ``` @@ -901,7 +901,7 @@ Dewenwils Heavy Duty 40A {"NAME":"Dewenwils HOWT01A","GPIO":[0,0,544,0,0,0,0 ECF-SOP03 {"NAME":"Outdoor3Outlet","GPIO":[0,0,0,226,320,0,0,0,224,32,225,0,0,0],"FLAG":0,"BASE":18} Ecoolbuy 4 Socket IP44 {"NAME":"ECCOLBUY 4","GPIO":[0,0,0,0,225,226,0,0,224,321,32,0,227,0],"FLAG":0,"BASE":18} Edimax 2AC {"NAME":"EDI SP-1122WTO","GPIO":[0,0,0,0,225,576,0,0,224,0,32,0,0,0],"FLAG":0,"BASE":18} -Emax IP44 {"NAME":"Emax Smart Socket","GPIO":[0,0,0,0,320,0,0,0,224,0,32,0,0,0],"FLAG":0,"BASE":18} +Emax IP44 {"NAME":"Emax Smart Socket","GPIO":[0,0,0,0,320,0,0,0,224,321,32,0,0,0],"FLAG":0,"BASE":18} Energizer 2AC Weather Resistant {"NAME":"Energizer EOX3-1001-BLK","GPIO":[0,0,0,0,320,576,0,0,224,0,32,0,0,0],"FLAG":0,"BASE":18} Etekcity {"NAME":"ES015-TB","GPIO":[0,0,0,0,224,225,288,0,2656,2688,32,2592,289,0],"FLAG":0,"BASE":18} Feit Electric PLUG/WIFI/WP {"NAME":"Prime Smart ou","GPIO":[0,1,0,1,544,320,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18} @@ -2620,7 +2620,7 @@ Shelly EM {"NAME":"Shelly EM","GPIO":[0,0,0,0,0,0,0,0,640,345 Shelly i3 Action and Scenes Activation Device {"NAME":"Shelly i3","GPIO":[0,0,0,0,0,320,0,0,193,194,192,0,0,4736],"FLAG":0,"BASE":18} Shelly Plus 1 {"NAME":"Shelly Plus 1 ","GPIO":[288,0,0,0,192,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,32,224,0,0,0,0,0,4736,4705,0,0,0,0,0,0],"FLAG":0,"BASE":1} Shelly Plus 1PM {"NAME":"Shelly Plus 1PM","GPIO":[0,0,0,0,192,2720,0,0,0,0,0,0,0,0,2656,0,0,0,0,2624,0,32,224,0,0,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":1} -Shelly Plus 2PM {"NAME":"Shelly Plus 2PM PCB v0.1.9","GPIO":[320,0,0,0,32,192,0,0,225,224,0,0,0,0,193,0,0,0,0,0,0,608,640,3456,0,0,0,0,0,0,0,4736,0,0,0,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,10000,10000,3350"} +Shelly Plus 2PM {"NAME":"Shelly Plus 2PM PCB v0.1.9","GPIO":[320,0,0,0,34,192,0,0,225,224,0,0,0,0,193,0,0,0,0,0,0,608,640,3458,0,0,0,0,0,9472,0,4736,0,0,0,0],"FLAG":0,"BASE":1} Shelly Plus i4 {"NAME":"Shelly Plus i4","GPIO":[0,0,0,0,0,0,0,0,192,0,193,0,0,0,0,0,0,0,0,0,0,0,195,194,0,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":1,"CMND":"SwitchMode1 1 | SwitchMode2 1 | SwitchMode3 1 | SwitchMode4 1 | SwitchTopic 0 | SetOption114 1"} Sinilink USB {"NAME":"XY-WFUSB","GPIO":[1,1,0,1,32,224,0,0,0,0,320,0,544,0],"FLAG":0,"BASE":18} Smarsecur Smart Switch {"NAME":"ESP-02S","GPIO":[0,0,0,32,0,0,0,0,0,0,224,0,0,0],"FLAG":0,"BASE":18} @@ -2720,7 +2720,7 @@ Kapok T16 {"NAME":"tiltech-t16","GPIO":[0,320,0,32,192,0,0,0, Kesen KS-604 {"NAME":"KS-604","GPIO":[1,1,288,1,1,33,0,0,225,224,1,1,32,0],"FLAG":0,"BASE":18} Kesen KS-604S {"NAME":"KS-604S","GPIO":[1,1,258,1,1,33,0,0,225,224,1,1,32,4704],"FLAG":0,"BASE":18} Keygma KS-15TW {"NAME":"Keygma KS-15T","GPIO":[0,0,0,0,0,320,0,0,224,160,0,0,0,0],"FLAG":0,"BASE":18} -Knightsbridge Dual Waterproof {"NAME":"Knightsbridge Dual Socket","GPIO":[321,544,320,544,225,0,0,0,0,33,0,224,32,0],"FLAG":0,"BASE":18} +Knightsbridge Dual Waterproof {"NAME":"Knightsbridge Dual Socket","GPIO":[321,544,320,544,225,2720,0,0,2624,33,2656,224,32,0],"FLAG":0,"BASE":18} KS-621 {"NAME":"KS-621","GPIO":[32,0,0,0,2688,2656,0,0,2592,288,0,224,65,1],"FLAG":0,"BASE":18} Makegood MG-AUWF01 {"NAME":"MG-AUWF01","GPIO":[320,161,544,323,2720,2656,0,0,2624,225,321,224,160,0],"FLAG":0,"BASE":18} Makegood MG-UKWSG01 {"NAME":"Aseer 2-Gang","GPIO":[321,160,544,323,2720,2656,0,0,2624,224,320,225,161,0],"FLAG":0,"BASE":18} diff --git a/tasmota/tasmota_support/support_features.ino b/tasmota/tasmota_support/support_features.ino index c576f5d07..72ba87771 100644 --- a/tasmota/tasmota_support/support_features.ino +++ b/tasmota/tasmota_support/support_features.ino @@ -865,7 +865,7 @@ void ResponseAppendFeatures(void) feature9 |= 0x00001000; // xdsp_20_tm1650.ino #endif #if defined(USE_I2C) && defined(USE_PCA9632) - feature9 |= 0x00002000; + feature9 |= 0x00002000; // xdrv_64_pca9632.ino #endif #ifdef USE_TUYAMCUBR feature9 |= 0x00004000; // xdrv_65_tuyamcubr.ino