Merge branch 'development' into prerelease-15.0.0

This commit is contained in:
Theo Arends 2025-06-10 17:19:01 +02:00
commit ef7b83eb2c
957 changed files with 164676 additions and 21571 deletions

View File

@ -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.8
- [ ] The code change is tested and works with Tasmota core ESP32 V.3.1.3.250411
- [ ] The code change is tested and works with Tasmota core ESP32 V.3.1.3.250504
- [ ] 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**_

View File

@ -24,7 +24,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
python-version: '3.13'
- name: Make Berry and Solidify code
run: |
@ -61,7 +61,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
python-version: '3.13'
- uses: actions/download-artifact@v4
with:
pattern: berry
@ -105,7 +105,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
python-version: '3.13'
- name: Install dependencies
run: |
pip install wheel
@ -117,6 +117,9 @@ jobs:
SHA=${COMMIT_SHA_LONG::7}
sed -i -e "s/TASMOTA_SHA_SHORT/TASMOTA_SHA_SHORT $SHA-/g" ./tasmota/include/tasmota_version.h
- name: Run PlatformIO
env:
PYTHONIOENCODING: utf-8
PYTHONUTF8: '1'
run: platformio run -e ${{ matrix.variant }}
#- name: Use esp32-solo1 safeboot for esp32 too
#run: |
@ -152,7 +155,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
python-version: '3.13'
- name: Install dependencies
run: |
pip install wheel
@ -163,6 +166,9 @@ jobs:
SHA=${COMMIT_SHA_LONG::7}
sed -i -e "s/TASMOTA_SHA_SHORT/TASMOTA_SHA_SHORT $SHA-/g" ./tasmota/include/tasmota_version.h
- name: Run PlatformIO
env:
PYTHONIOENCODING: utf-8
PYTHONUTF8: '1'
run: platformio run -e ${{ matrix.variant }}
- name: Upload firmware artifacts
uses: actions/upload-artifact@v4
@ -200,7 +206,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
python-version: '3.13'
- name: Install dependencies
run: |
pip install wheel
@ -221,6 +227,9 @@ jobs:
SHA=${COMMIT_SHA_LONG::7}
sed -i -e "s/TASMOTA_SHA_SHORT/TASMOTA_SHA_SHORT $SHA-/g" ./tasmota/include/tasmota_version.h
- name: Run PlatformIO
env:
PYTHONIOENCODING: utf-8
PYTHONUTF8: '1'
run: platformio run -e ${{ matrix.variant }}
- name: Upload firmware artifacts
uses: actions/upload-artifact@v4
@ -244,7 +253,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
python-version: '3.13'
- name: Install dependencies
run: |
pip install wheel
@ -265,6 +274,9 @@ jobs:
SHA=${COMMIT_SHA_LONG::7}
sed -i -e "s/TASMOTA_SHA_SHORT/TASMOTA_SHA_SHORT $SHA-/g" ./tasmota/include/tasmota_version.h
- name: Run PlatformIO
env:
PYTHONIOENCODING: utf-8
PYTHONUTF8: '1'
run: platformio run -e ${{ matrix.variant }}-${{ matrix.language }}
- name: Upload language firmware artifacts
uses: actions/upload-artifact@v4

View File

@ -39,7 +39,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
python-version: '3.13'
- name: Install dependencies
run: |
pip install wheel
@ -49,6 +49,9 @@ jobs:
run: |
sed -i -e "s/TASMOTA_SHA_SHORT/TASMOTA_SHA_SHORT release-/g" ./tasmota/include/tasmota_version.h
- name: Run PlatformIO
env:
PYTHONIOENCODING: utf-8
PYTHONUTF8: '1'
run: platformio run -e ${{ matrix.variant }}
- name: Upload safeboot firmware artifacts
uses: actions/upload-artifact@v4
@ -80,7 +83,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
python-version: '3.13'
- name: Install dependencies
run: |
pip install wheel
@ -90,6 +93,9 @@ jobs:
run: |
sed -i -e "s/TASMOTA_SHA_SHORT/TASMOTA_SHA_SHORT release-/g" ./tasmota/include/tasmota_version.h
- name: Run PlatformIO
env:
PYTHONIOENCODING: utf-8
PYTHONUTF8: '1'
run: platformio run -e ${{ matrix.variant }}
- name: Upload firmware artifacts
uses: actions/upload-artifact@v4
@ -127,7 +133,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
python-version: '3.13'
- name: Install dependencies
run: |
pip install wheel
@ -146,6 +152,9 @@ jobs:
run: |
sed -i -e "s/TASMOTA_SHA_SHORT/TASMOTA_SHA_SHORT release-/g" ./tasmota/include/tasmota_version.h
- name: Run PlatformIO
env:
PYTHONIOENCODING: utf-8
PYTHONUTF8: '1'
run: platformio run -e ${{ matrix.variant }}
- name: Upload firmware artifacts
uses: actions/upload-artifact@v4
@ -169,7 +178,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
python-version: '3.13'
- name: Install dependencies
run: |
pip install wheel
@ -188,6 +197,9 @@ jobs:
run: |
sed -i -e "s/TASMOTA_SHA_SHORT/TASMOTA_SHA_SHORT release-/g" ./tasmota/include/tasmota_version.h
- name: Run PlatformIO
env:
PYTHONIOENCODING: utf-8
PYTHONUTF8: '1'
run: platformio run -e ${{ matrix.variant }}-${{ matrix.language }}
- name: Upload language firmware artifacts
uses: actions/upload-artifact@v4

View File

@ -31,15 +31,15 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
python-version: '3.13'
- name: Install dependencies
run: |
pip install wheel
#python -m pip install --upgrade pip
pip install -U platformio
#platformio upgrade --dev
#platformio update
- name: Run PlatformIO
env:
PYTHONIOENCODING: utf-8
PYTHONUTF8: '1'
run: platformio run -e ${{ matrix.variant }}
- uses: actions/upload-artifact@v4
with:
@ -59,15 +59,15 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
python-version: '3.13'
- name: Install dependencies
run: |
pip install wheel
#python -m pip install --upgrade pip
pip install -U platformio
#platformio upgrade --dev
#platformio update
- name: Run PlatformIO
env:
PYTHONIOENCODING: utf-8
PYTHONUTF8: '1'
run: platformio run -e ${{ matrix.variant }}
- uses: actions/upload-artifact@v4
with:
@ -117,16 +117,16 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
python-version: '3.13'
- name: Install dependencies
run: |
pip install wheel
#python -m pip install --upgrade pip
pip install -U platformio
#platformio upgrade --dev
#platformio update
cp ./platformio_override_sample.ini ./platformio_override.ini
- name: Run PlatformIO
env:
PYTHONIOENCODING: utf-8
PYTHONUTF8: '1'
run: platformio run -e ${{ matrix.variant }}
- uses: actions/upload-artifact@v4
with:
@ -146,15 +146,15 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
python-version: '3.13'
- name: Install dependencies
run: |
pip install wheel
#python -m pip install --upgrade pip
pip install -U platformio
#platformio upgrade --dev
#platformio update
- name: Run PlatformIO
env:
PYTHONIOENCODING: utf-8
PYTHONUTF8: '1'
run: platformio run -e ${{ matrix.variant }}-${{ matrix.language }}
- uses: actions/upload-artifact@v4
with:

1
.gitignore vendored
View File

@ -19,6 +19,7 @@ managed_components
.cache
.dummy
sdkconfig.*
sdkconfig.defaults
data
unpacked_fs
unpacked_boards

View File

@ -3,6 +3,65 @@ All notable changes to this project will be documented in this file.
## [Released]
## [14.6.0] 20250613
- Release Sharon
## [14.6.0.2] 20250613
### Added
- Allow temporary change of DisplayDimmer (#23406)
- Support for LoRaWan Rx1 and Rx2 profiles (#23394)
- HASPmota auto-dimming when no touch (#23425)
- Provide serial upload port from VSC to PIO (#23436)
- Berry support for `sortedmap` (#23441)
- Berry `introspect.module` option to not cache module entry (#23451)
- Berry `webserver.remove_route` to revert `webserver.on` (#23452)
- Berry `compile` and `tasmota.compile` option to compile in local context (#23457)
- Support for AP33772S USB PD Sink Controller as used in CentyLab RotoPD
- Berry mqtt publish rule processing
### Changed
- ESP32 Platform from 2025.04.30 to 2025.05.40, Framework (Arduino Core) from v3.1.3.250411 to v3.2.0.250504 and IDF from v5.3.2.250403 to v5.4.1.250501 (#23397)
- ESP32 Platform from 2025.05.40 to 2025.05.30, Framework (Arduino Core) from v3.2.0.250504 to v3.1.3.250504 and IDF from v5.4.1.250501 to v5.3.3.250501 (#23404)
- ESP8266 platform update from 2024.09.00 to 2025.05.00 (#23448)
- Increase number of supported LoRaWan nodes from 4 to 16
- Berry change number parser for json to reuse same parser as lexer (#23505)
- Berry increase web hooks from 16 to 32 (#23507)
- ESP32 LVGL library from v9.2.2 to v9.3.0 (#23518)
- Zigbee improved message when coordinator failed to start (#23525)
- Format syslog messages according to RFC5424 adding local log time (#23509)
### Fixed
- Haspmota `haspmota.parse()` page parsing (#23403)
- ESP32-S3 display stability regression from #23397 (#23404)
- DNS setting with `IPAddress4/5` not persisted (#23426)
- Berry avoid json parsing for unmatched commands (#23494)
- Berry integer and real parser to handle overflows (#23495)
- Berry potential pointer underflow with `string.endswith` (#23496)
## [14.6.0.1] 20250510
### Added
- Command `JsonPP 0..7` to enable (>0) JSON Pretty Print on user interfaces and set number of indents
- Command `JsonPP <command>|backlog <command>;...` to enable JSON PP only once
- WebUI status line for MQTT and TLS, added `FUNC_WEB_STATUS` event (#23326)
- Wireguard VPN (#23347)
- Optional Wifi strength indicator in WebUI status line (#23352)
- WebUI status line left and renamed events `FUNC_WEB_STATUS_LEFT` and `FUNC_WEB_STATUS_RIGHT` (#23354)
- WebUI heap status (#23356)
- Support for multi channel AU915-928 LoRaWanBridge by Rob Clark (#23372)
- HASPmota `antiburn()` (#23400)
### Changed
- Allow command `WebRefresh` minimum from 1000 to 400 mSec
- GPIOViewer from v1.6.2 to v1.6.3 (No functional change)
### Fixed
- Berry `bytes().asstring()` now truncates a string if buffer contains NULL (#23311)
- Berry string literals containing NULL are truncated (#23312)
- Berry `display.touch_update` wrongly applies resistive calibration (#23363)
- NimBLE log_level definition conflict (#23366)
- Matter and mDNS can be enabled at the same time (#23373)
- Berry `introspect.module()` failed to load modules in files (#23376)
## [14.6.0] 20250416
- Release Ryan

View File

@ -91,7 +91,7 @@ In addition to @arendst the following code is mainly owned by:
| xdrv_77_wizmote | @arendst
| xdrv_78_telnet | @arendst
| xdrv_79_esp32_ble | @staars, @btsimonh
| xdrv_80 |
| xdrv_80_wireguard_client | @s-hadinger
| xdrv_81_esp32_webcam | @gemu, @philrich
| xdrv_82_esp32_ethernet | @arendst
| xdrv_83_esp32_watch | @gemu
@ -101,11 +101,12 @@ In addition to @arendst the following code is mainly owned by:
| xdrv_88_esp32_shelly_pro | @arendst
| xdrv_89_ |
| xdrv_90_esp32_dingtian_relay | @barbudor
| xdrv_91_ |
| xdrv_91_esp32_twai | @arendst
| xdrv_92_ |
| xdrv_93_ |
| xdrv_94_ |
| |
| xdrv_119_i2c_ap33772s | @arendst
| xdrv_120_xyzmodem | @arendst
| xdrv_121_gpioviewer | @arendst
| xdrv_122_file_settings_demo | @arendst

View File

@ -130,5 +130,6 @@ Index | Define | Driver | Device | Address(es) | Bus2 | Descrip
90 | USE_RX8010 | xdrv_56 | RX8010 | 0x32 | Yes | RX8010 RTC from IOTTIMER
91 | USE_MS5837 | xsns_116 | MS5837 | 0x76 | | Pressure and temperature sensor
92 | USE_PCF85063 | xdrv_56 | PCF85063 | 0x51 | | PCF85063 Real time clock
93 | USE_AS33772S | xdrv_119 | AS33772S | 0x52 | Yes | AS33772S USB PD Sink Controller
NOTE: Bus2 supported on ESP32 only.

View File

@ -36,9 +36,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.8** 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 **v3.1.3.250411**.
This release will be supported from ESP32/Arduino library Core version **v3.1.3.250504**.
Support of ESP8266 Core versions before 2.7.8 and ESP32 Core versions before v3.1.3.250411 have been removed.
Support of ESP8266 Core versions before 2.7.8 and ESP32 Core versions before v3.1.3.250504 have been removed.
## Support of TLS
@ -75,12 +75,12 @@ 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-14.6.0
- http://ota.tasmota.com/tasmota/release-15.0.0
The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmota.com/tasmota/release/tasmota.bin.gz``
### ESP32, ESP32-C2, ESP32-C3, ESP32-C6, ESP32-S2 and ESP32-S3 based
The following binary downloads have been compiled with ESP32/Arduino library core version **v3.1.3.250411**.
The following binary downloads have been compiled with ESP32/Arduino library core version **v3.1.3.250504**.
- **tasmota32.bin** = The Tasmota version with most drivers including additional sensors and KNX for 4M+ flash. **RECOMMENDED RELEASE BINARY**
- **tasmota32solo1.bin** = The Tasmota version with most drivers including additional sensors and KNX for single core ESP32 and 4M+ flash.
@ -104,7 +104,7 @@ Latest released binaries can be downloaded from
- https://ota.tasmota.com/tasmota32/release
Historical binaries can be downloaded from
- https://ota.tasmota.com/tasmota32/release-14.6.0
- https://ota.tasmota.com/tasmota32/release-15.0.0
The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasmota.com/tasmota32/release/tasmota32.bin``
@ -114,58 +114,52 @@ 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 v14.6.0 Ryan
## Changelog v15.0.0 Sharon
### Added
- Filesystem command ``UfsList[2]``
- Extend command `GPIO` with different display options and allowing updating of module GPIO's in one go
- Support Vango Technologies V924x ultralow power, single-phase, power measurement [#23127](https://github.com/arendst/Tasmota/issues/23127)
- Support for HLK-LD2402 24GHz smart wave motion sensor [#23133](https://github.com/arendst/Tasmota/issues/23133)
- Support for Telnet server using command `Telnet <0|1|port>[,<IP filter>]` if enabled with `#define USE_TELNET`
- Support for XMODEM over serial and telnet if enabled with `#define USE_XYZMODEM`
- PZEM_AC device address in JSON and GUI [#23268](https://github.com/arendst/Tasmota/issues/23268)
- Allow acl in mqtt when client certificate is in use with `#define USE_MQTT_CLIENT_CERT` [#22998](https://github.com/arendst/Tasmota/issues/22998)
- AlpineJS 2.8.2 - optional for now [#23259](https://github.com/arendst/Tasmota/issues/23259)
- ESP32 show network interface priority in `Status 5` debug logging [#23302](https://github.com/arendst/Tasmota/issues/23302)
- Berry experimental driver for AXP2101 for M5Core2v1.1 [#23039](https://github.com/arendst/Tasmota/issues/23039)
- Berry `tasmota.when_network_up()` and simplified Matter using it [#23057](https://github.com/arendst/Tasmota/issues/23057)
- Berry `introspect.solidified()` to know if a Berry object is solidified or in RAM [#23063](https://github.com/arendst/Tasmota/issues/23063)
- Berry `global.undef()` to undefine a global variable [#23073](https://github.com/arendst/Tasmota/issues/23073)
- Berry load `.tapp` files in `/.extensions/` then in `/` [#23113](https://github.com/arendst/Tasmota/issues/23113)
- Berry `re.dump()` [#23162](https://github.com/arendst/Tasmota/issues/23162)
- Berry `bytes.add()` now accepts 3-bytes values [#23200](https://github.com/arendst/Tasmota/issues/23200)
- Berry expose `esp_http_server` for websockets [#23206](https://github.com/arendst/Tasmota/issues/23206)
- Matter prepare for ICD cluster [#23158](https://github.com/arendst/Tasmota/issues/23158)
- LVGL experimental mirroring of display on Web UI [#23041](https://github.com/arendst/Tasmota/issues/23041)
- HASPmota autostart when `pages.jsonl` exists [#23181](https://github.com/arendst/Tasmota/issues/23181)
- Provide serial upload port from VSC to PIO [#23436](https://github.com/arendst/Tasmota/issues/23436)
- Command `JsonPP 0..7` to enable (>0) JSON Pretty Print on user interfaces and set number of indents
- Command `JsonPP <command>|backlog <command>;...` to enable JSON PP only once
- Support for multi channel AU915-928 LoRaWanBridge by Rob Clark [#23372](https://github.com/arendst/Tasmota/issues/23372)
- Support for LoRaWan Rx1 and Rx2 profiles [#23394](https://github.com/arendst/Tasmota/issues/23394)
- Support for AP33772S USB PD Sink Controller as used in CentyLab RotoPD
- Allow temporary change of DisplayDimmer [#23406](https://github.com/arendst/Tasmota/issues/23406)
- WebUI status line for MQTT and TLS, added `FUNC_WEB_STATUS_LEFT` and `FUNC_WEB_STATUS_RIGHT` event [#23354](https://github.com/arendst/Tasmota/issues/23354)
- WebUI heap status [#23356](https://github.com/arendst/Tasmota/issues/23356)
- Optional Wifi strength indicator in WebUI status line [#23352](https://github.com/arendst/Tasmota/issues/23352)
- Wireguard VPN [#23347](https://github.com/arendst/Tasmota/issues/23347)
- Berry mqtt publish rule processing
- Berry support for `sortedmap` [#23441](https://github.com/arendst/Tasmota/issues/23441)
- Berry `introspect.module` option to not cache module entry [#23451](https://github.com/arendst/Tasmota/issues/23451)
- Berry `webserver.remove_route` to revert `webserver.on` [#23452](https://github.com/arendst/Tasmota/issues/23452)
- Berry `compile` and `tasmota.compile` option to compile in local context [#23457](https://github.com/arendst/Tasmota/issues/23457)
- HASPmota `antiburn()` [#23400](https://github.com/arendst/Tasmota/issues/23400)
- HASPmota auto-dimming when no touch [#23425](https://github.com/arendst/Tasmota/issues/23425)
### Breaking Changed
- Berry remove `Leds.create_matrix` from the standard library waiting for reimplementation [#23114](https://github.com/arendst/Tasmota/issues/23114)
- HASPmota added `y2_min` and `y2_max` to control the second series of `chart` [#23287](https://github.com/arendst/Tasmota/issues/23287)
- HASPmota default theme is now Tasmota-style [#23288](https://github.com/arendst/Tasmota/issues/23288)
### Changed
- ESP32 Platform from 2025.02.30 to 2025.04.30, Framework (Arduino Core) from v3.1.1.250203 to v3.1.3.250411 and IDF from v5.3.2.250120 to 5.3.2.250403 [#23280](https://github.com/arendst/Tasmota/issues/23280)
- Output of commands `GPIO` and `GPIOs` swapped
- Smoothen light gamma curve when using `Fade` [#23230](https://github.com/arendst/Tasmota/issues/23230)
- RCSwitch `RCSWITCH_SEPARATION_LIMIT` from 4100 to 3600
- GPIOViewer from v1.6.1 to v1.6.2 (No functional change)
- HLK-LD2402 updates for firmware 3.3.5+ [#23281](https://github.com/arendst/Tasmota/issues/23281)
- ESP8266 enable FTP for >= 4MB variants [#23120](https://github.com/arendst/Tasmota/issues/23120)
- ESP32 enable webcam version 2 [#18732](https://github.com/arendst/Tasmota/issues/18732)
- Berry update flasher for Sonoff ZBBridge Pro [#23136](https://github.com/arendst/Tasmota/issues/23136)
- Berry `re` now accepts `bytes()` as precompiled patterns, added `re.compilebytes()` [#23149](https://github.com/arendst/Tasmota/issues/23149)
- LVGL, prepare for HASPmota theme, change: no-grow when clicked, DPI set to 160 [#23040](https://github.com/arendst/Tasmota/issues/23040)
- LVGL Mirroring add checkbox to enable/disable the feature (in the iterim for a better solution) [#23047](https://github.com/arendst/Tasmota/issues/23047)
- Leds Panel add checkbox to enable/disable the feature (in the iterim for a better solution) [#23048](https://github.com/arendst/Tasmota/issues/23048)
- ESP8266 platform update from 2024.09.00 to 2025.05.00 [#23448](https://github.com/arendst/Tasmota/issues/23448)
- ESP32 Platform from 2025.04.30 to 2025.05.30, Framework (Arduino Core) from v3.1.3.250411 to v3.1.3.250504 and IDF from v5.3.2.250403 to v5.3.3.250501 [#23404](https://github.com/arendst/Tasmota/issues/23404)
- ESP32 LVGL library from v9.2.2 to v9.3.0 [#23518](https://github.com/arendst/Tasmota/issues/23518)
- GPIOViewer from v1.6.2 to v1.6.3 (No functional change)
- Allow command `WebRefresh` minimum from 1000 to 400 mSec
- Increase number of supported LoRaWan nodes from 4 to 16
- Format syslog messages according to RFC5424 adding local log time [#23509](https://github.com/arendst/Tasmota/issues/23509)
- Zigbee improved message when coordinator failed to start [#23525](https://github.com/arendst/Tasmota/issues/23525)
- Berry change number parser for json to reuse same parser as lexer [#23505](https://github.com/arendst/Tasmota/issues/23505)
- Berry increase web hooks from 16 to 32 [#23507](https://github.com/arendst/Tasmota/issues/23507)
### Fixed
- Too many zeros in RCSwitch received data regression from v14.4.1.4 [#23050](https://github.com/arendst/Tasmota/issues/23050)
- INA226 driver fixes [#23197](https://github.com/arendst/Tasmota/issues/23197)
- TLS increase timeout and fix crash [#23249](https://github.com/arendst/Tasmota/issues/23249)
- ESP32 receive incomplete serial data over 128 bytes [#23156](https://github.com/arendst/Tasmota/issues/23156)
- ESP32 intermittent exception on WiFi AP cannot be reached [#23115](https://github.com/arendst/Tasmota/issues/23115)
- ESP32-C3 WiFi sleep [#23096](https://github.com/arendst/Tasmota/issues/23096)
- Berry prevent `import` from hiding a solidified class [#23112](https://github.com/arendst/Tasmota/issues/23112)
- Berry `readline` when a line is exactly 98 characters [#23276](https://github.com/arendst/Tasmota/issues/23276)
- DNS setting with `IPAddress4/5` not persisted [#23426](https://github.com/arendst/Tasmota/issues/23426)
- NimBLE log_level definition conflict [#23366](https://github.com/arendst/Tasmota/issues/23366)
- Berry `bytes().asstring()` now truncates a string if buffer contains NULL [#23311](https://github.com/arendst/Tasmota/issues/23311)
- Berry string literals containing NULL are truncated [#23312](https://github.com/arendst/Tasmota/issues/23312)
- Berry `display.touch_update` wrongly applies resistive calibration [#23363](https://github.com/arendst/Tasmota/issues/23363)
- Berry `introspect.module()` failed to load modules in files [#23376](https://github.com/arendst/Tasmota/issues/23376)
- Berry avoid json parsing for unmatched commands [#23494](https://github.com/arendst/Tasmota/issues/23494)
- Berry integer and real parser to handle overflows [#23495](https://github.com/arendst/Tasmota/issues/23495)
- Berry potential pointer underflow with `string.endswith` [#23496](https://github.com/arendst/Tasmota/issues/23496)
- Matter and mDNS can be enabled at the same time [#23373](https://github.com/arendst/Tasmota/issues/23373)
- Haspmota `haspmota.parse()` page parsing [#23403](https://github.com/arendst/Tasmota/issues/23403)
### Removed

View File

@ -5,7 +5,7 @@
# Templates
Find below the available templates as of April 2025. More template information can be found in the [Tasmota Device Templates Repository](http://blakadder.github.io/templates)
Find below the available templates as of June 2025. More template information can be found in the [Tasmota Device Templates Repository](http://blakadder.github.io/templates)
## Adapter Board
```
@ -403,7 +403,6 @@ Shelly Vintage 4W 260lm 2700k {"NAME":"Shelly Vintage","GPIO":[0,0,0,0,416,0,0,
Shelly Vintage 7W 750lm 2700k {"NAME":"Shelly Vintage","GPIO":[0,0,0,0,416,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18}
Shelly Vintage 7W 750lm 2700k {"NAME":"Shelly Vintage","GPIO":[0,0,0,0,416,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18}
SmartDGM 9W 806lm {"NAME":"L-WB9W1","GPIO":[0,0,0,0,0,416,0,0,160,0,0,0,0,0],"FLAG":0,"BASE":18}
Smitch 10W 6500K {"NAME":"Smitch Ambience SB-0110","GPIO":[0,0,0,0,416,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18}
Smitch 10W 6500K {"NAME":"Smitch 10W 6500K Dimmable Bulb (SB0110 - E27)","GPIO":[0,0,0,0,0,416,0,0,0,417,0,0,0,0],"FLAG":0,"BASE":1}
TCP Smart 806lm Warm White {"NAME":"TCP Smart Clas","GPIO":[0,0,0,0,0,0,0,0,0,416,0,0,0,0],"FLAG":0,"BASE":1}
TCP Smart 810lm Filament {"NAME":"TCP Filament","GPIO":[0,0,0,0,0,0,0,0,0,0,448,0,0,0],"FLAG":0,"BASE":18}
@ -464,7 +463,7 @@ QS-WiFi-D01-TRIAC 150W {"NAME":"QS-WiFi-D01-TRIAC","GPIO":[0,3200,0,3232,0
RJWF-02A {"NAME":"RJWF-02A","GPIO":[32,2272,0,2304,0,0,0,0,0,0,288,0,0,0],"FLAG":0,"BASE":54}
Shelly Dimmer {"NAME":"Shelly Dimmer 1","GPIO":[0,3200,0,3232,5568,5600,0,0,192,0,193,288,0,4736],"FLAG":0,"BASE":18}
Shelly Dimmer 2 {"NAME":"Shelly Dimmer 2","GPIO":[0,3200,0,3232,5568,5600,0,0,193,0,192,0,320,4736],"FLAG":0,"BASE":18}
Shelly Plus 0-10V Dimmer {"NAME":"Shelly Plus 0-10V Dimmer","GPIO":[288,0,0,0,192,0,0,0,0,0,0,0,0,0,193,1,0,0,0,0,0,32,416,0,0,0,0,0,4736,0,0,0,0,0,0,0],"FLAG":0,"BASE":1}
Shelly Plus 0-10V Dimmer {"NAME":"Shelly Plus 0-10V Dimmer","GPIO":[288,0,0,0,192,0,0,0,0,0,0,0,0,0,193,1,0,0,0,0,0,32,448,0,0,0,0,0,4736,0,0,0,0,0,0,0],"FLAG":0,"BASE":1}
Sonoff D1 {"NAME":"Sonoff D1","GPIO":[1,3200,0,3232,0,0,0,0,0,320,0,0,0,0],"FLAG":0,"BASE":74}
```

View File

@ -41,6 +41,11 @@
"download": {
"speed": 230400
},
"espidf": {
"custom_sdkconfig": [
"CONFIG_FREERTOS_UNICORE=y"
]
},
"url": "https://www.espressif.com/sites/default/files/documentation/esp32-solo-1_datasheet_en.pdf",
"vendor": "Espressif"
}

View File

@ -39,6 +39,6 @@
"download": {
"speed": 230400
},
"url": "https://docs.espressif.com/projects/espressif-esp-dev-kits/en/latest/esp32c6/esp32-c6-devkitc-1/index.html",
"url": "https://docs.espressif.com/projects/espressif-esp-dev-kits/en/latest/esp8684/esp8684-devkitm-1/user_guide.html",
"vendor": "Espressif"
}

View File

@ -39,6 +39,6 @@
"download": {
"speed": 230400
},
"url": "https://docs.espressif.com/projects/espressif-esp-dev-kits/en/latest/esp32c6/esp32-c6-devkitc-1/index.html",
"url": "https://docs.espressif.com/projects/espressif-esp-dev-kits/en/latest/esp8684/esp8684-devkitm-1/user_guide.html",
"vendor": "Espressif"
}

View File

@ -27,8 +27,8 @@ enum LoggingLevels {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_D
#ifdef USE_IPV6
ip_addr_t dns_save4[DNS_MAX_SERVERS] = {}; // IPv4 DNS servers
ip_addr_t dns_save6[DNS_MAX_SERVERS] = {}; // IPv6 DNS servers
ip_addr_t dns_save4[2] = {}; // IPv4 DNS servers
ip_addr_t dns_save6[2] = {}; // IPv6 DNS servers
#endif // USE_IPV6
#include "tasmota_options.h"
@ -76,48 +76,72 @@ extern bool WifiHasIPv6(void);
extern bool EthernetHasIPv6(void);
void WiFiHelper::scrubDNS(void) {
// AddLog(LOG_LEVEL_DEBUG, "IP>1: dns_save4 %s %s dns_save6 %s %s",
// IPAddress(&dns_save4[0]).toString().c_str(),IPAddress(&dns_save4[1]).toString().c_str(),
// IPAddress(&dns_save6[0]).toString().c_str(),IPAddress(&dns_save6[1]).toString().c_str());
// String dns_entry0 = IPAddress(dns_getserver(0)).toString();
// String dns_entry1 = IPAddress(dns_getserver(1)).toString();
// scan DNS entries
bool has_v4 = WifiHasIPv4() || EthernetHasIPv4();
bool has_v6 = false;
#ifdef USE_IPV6
has_v6 = WifiHasIPv6() || EthernetHasIPv6();
#endif
// AddLog(LOG_LEVEL_DEBUG, "IP>1: DNS: (%s %s) has4/6:%i-%i", dns_entry0.c_str(), dns_entry1.c_str(), has_v4, has_v6);
// First pass, save values
for (uint32_t i=0; i<DNS_MAX_SERVERS; i++) {
#ifdef USE_IPV6
// First pass, save values
for (uint32_t i=0; i<2; i++) {
const IPAddress ip_dns = IPAddress(dns_getserver(i));
// Step 1. save valid values from DNS
if (!ip_addr_isany_val((const ip_addr_t &)ip_dns)) {
if (ip_dns.type() == IPv4 && has_v4) {
ip_dns.to_ip_addr_t(&dns_save4[i]);
// dns_save4[i] = (ip_addr_t) ip_dns; // dns entry is populated, save it in v4 slot
if (ip_dns.type() == IPv4 && (has_v4 || !has_v6)) {
ip_dns.to_ip_addr_t(&dns_save4[i]); // dns entry is populated, save it in v4 slot
} else if (has_v6) {
ip_dns.to_ip_addr_t(&dns_save6[i]);
// dns_save6[i] = (ip_addr_t) ip_dns; // dns entry is populated, save it in v6 slot
ip_dns.to_ip_addr_t(&dns_save6[i]); // dns entry is populated, save it in v6 slot
}
}
// Step 2. scrub addresses not supported
if (!has_v4) { dns_save4[i] = *IP4_ADDR_ANY; }
if (!has_v6) { dns_save6[i] = *IP_ADDR_ANY; }
// Step 3. restore saved value
if (has_v4 && has_v6) { // if both IPv4 and IPv6 are active, prefer IPv4
if (!ip_addr_isany_val(dns_save4[i])) { dns_setserver(i, &dns_save4[i]); }
else { dns_setserver(i, &dns_save6[i]); }
} else if (has_v4) {
dns_setserver(i, &dns_save4[i]);
} else if (has_v6) {
dns_setserver(i, &dns_save6[i]);
} else {
dns_setserver(i, IP4_ADDR_ANY);
}
#endif // USE_IPV6
}
// AddLog(LOG_LEVEL_DEBUG, "IP>: 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);
// Step 2. scrub addresses not supported
if (!has_v4 && has_v6) { // v6 only
dns_save4[0] = *IP4_ADDR_ANY;
dns_save4[1] = *IP4_ADDR_ANY;
}
if (!has_v6) {
dns_save6[0] = *IP_ADDR_ANY;
dns_save6[1] = *IP_ADDR_ANY;
}
// Step 3. restore saved value
if (has_v4 && has_v6) { // if both IPv4 and IPv6 are active, prefer IPv4 for first and IPv6 for second
if (!ip_addr_isany_val(dns_save4[0])) {
// First DNS IPv4
dns_setserver(0, &dns_save4[0]);
if (!ip_addr_isany_val(dns_save6[0])) {
dns_setserver(1, &dns_save6[0]); // take first IPv6 as second DNS
} else {
dns_setserver(1, &dns_save4[1]); // or revert to second IPv4
}
} else {
// If no DNS IPv4, use IPv6
dns_setserver(0, &dns_save6[0]);
dns_setserver(1, &dns_save6[1]);
}
} else if (has_v6) { // v6 and no v4
dns_setserver(0, &dns_save6[0]);
dns_setserver(1, &dns_save6[1]);
} else { // no v6, we use v4 even if not connected
dns_setserver(0, &dns_save4[0]);
dns_setserver(1, &dns_save4[1]);
}
#endif // USE_IPV6
// AddLog(LOG_LEVEL_DEBUG, "IP>2: 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);
// AddLog(LOG_LEVEL_DEBUG, "IP>2: dns_save4 %s %s dns_save6 %s %s",
// IPAddress(&dns_save4[0]).toString().c_str(),IPAddress(&dns_save4[1]).toString().c_str(),
// IPAddress(&dns_save6[0]).toString().c_str(),IPAddress(&dns_save6[1]).toString().c_str());
}

View File

@ -0,0 +1,128 @@
/**
* Base64 encoding and decoding of strings. Uses '+' for 62, '/' for 63, '=' for padding
*/
#include "base64.hpp"
unsigned char binary_to_base64(unsigned char v) {
// Capital letters - 'A' is ascii 65 and base64 0
if(v < 26) return v + 'A';
// Lowercase letters - 'a' is ascii 97 and base64 26
if(v < 52) return v + 71;
// Digits - '0' is ascii 48 and base64 52
if(v < 62) return v - 4;
// '+' is ascii 43 and base64 62
if(v == 62) return '+';
// '/' is ascii 47 and base64 63
if(v == 63) return '/';
return 64;
}
unsigned char base64_to_binary(unsigned char c) {
// Capital letters - 'A' is ascii 65 and base64 0
if('A' <= c && c <= 'Z') return c - 'A';
// Lowercase letters - 'a' is ascii 97 and base64 26
if('a' <= c && c <= 'z') return c - 71;
// Digits - '0' is ascii 48 and base64 52
if('0' <= c && c <= '9') return c + 4;
// '+' is ascii 43 and base64 62
if(c == '+') return 62;
// '/' is ascii 47 and base64 63
if(c == '/') return 63;
return 255;
}
unsigned int encode_base64_length(unsigned int input_length) {
return (input_length + 2)/3*4;
}
unsigned int decode_base64_length(unsigned char input[]) {
unsigned char *start = input;
while(base64_to_binary(input[0]) < 64) {
++input;
}
unsigned int input_length = input - start;
unsigned int output_length = input_length/4*3;
switch(input_length % 4) {
default: return output_length;
case 2: return output_length + 1;
case 3: return output_length + 2;
}
}
unsigned int encode_base64(unsigned char input[], unsigned int input_length, unsigned char output[]) {
unsigned int full_sets = input_length/3;
// While there are still full sets of 24 bits...
for(unsigned int i = 0; i < full_sets; ++i) {
output[0] = binary_to_base64( input[0] >> 2);
output[1] = binary_to_base64((input[0] & 0x03) << 4 | input[1] >> 4);
output[2] = binary_to_base64((input[1] & 0x0F) << 2 | input[2] >> 6);
output[3] = binary_to_base64( input[2] & 0x3F);
input += 3;
output += 4;
}
switch(input_length % 3) {
case 0:
output[0] = '\0';
break;
case 1:
output[0] = binary_to_base64( input[0] >> 2);
output[1] = binary_to_base64((input[0] & 0x03) << 4);
output[2] = '=';
output[3] = '=';
output[4] = '\0';
break;
case 2:
output[0] = binary_to_base64( input[0] >> 2);
output[1] = binary_to_base64((input[0] & 0x03) << 4 | input[1] >> 4);
output[2] = binary_to_base64((input[1] & 0x0F) << 2);
output[3] = '=';
output[4] = '\0';
break;
}
return encode_base64_length(input_length);
}
unsigned int decode_base64(unsigned char input[], unsigned char output[]) {
unsigned int output_length = decode_base64_length(input);
// While there are still full sets of 24 bits...
for(unsigned int i = 2; i < output_length; i += 3) {
output[0] = base64_to_binary(input[0]) << 2 | base64_to_binary(input[1]) >> 4;
output[1] = base64_to_binary(input[1]) << 4 | base64_to_binary(input[2]) >> 2;
output[2] = base64_to_binary(input[2]) << 6 | base64_to_binary(input[3]);
input += 4;
output += 3;
}
switch(output_length % 3) {
case 1:
output[0] = base64_to_binary(input[0]) << 2 | base64_to_binary(input[1]) >> 4;
break;
case 2:
output[0] = base64_to_binary(input[0]) << 2 | base64_to_binary(input[1]) >> 4;
output[1] = base64_to_binary(input[1]) << 4 | base64_to_binary(input[2]) >> 2;
break;
}
return output_length;
}

View File

@ -69,127 +69,4 @@ unsigned int encode_base64(unsigned char input[], unsigned int input_length, uns
*/
unsigned int decode_base64(unsigned char input[], unsigned char output[]);
unsigned char binary_to_base64(unsigned char v) {
// Capital letters - 'A' is ascii 65 and base64 0
if(v < 26) return v + 'A';
// Lowercase letters - 'a' is ascii 97 and base64 26
if(v < 52) return v + 71;
// Digits - '0' is ascii 48 and base64 52
if(v < 62) return v - 4;
// '+' is ascii 43 and base64 62
if(v == 62) return '+';
// '/' is ascii 47 and base64 63
if(v == 63) return '/';
return 64;
}
unsigned char base64_to_binary(unsigned char c) {
// Capital letters - 'A' is ascii 65 and base64 0
if('A' <= c && c <= 'Z') return c - 'A';
// Lowercase letters - 'a' is ascii 97 and base64 26
if('a' <= c && c <= 'z') return c - 71;
// Digits - '0' is ascii 48 and base64 52
if('0' <= c && c <= '9') return c + 4;
// '+' is ascii 43 and base64 62
if(c == '+') return 62;
// '/' is ascii 47 and base64 63
if(c == '/') return 63;
return 255;
}
unsigned int encode_base64_length(unsigned int input_length) {
return (input_length + 2)/3*4;
}
unsigned int decode_base64_length(unsigned char input[]) {
unsigned char *start = input;
while(base64_to_binary(input[0]) < 64) {
++input;
}
unsigned int input_length = input - start;
unsigned int output_length = input_length/4*3;
switch(input_length % 4) {
default: return output_length;
case 2: return output_length + 1;
case 3: return output_length + 2;
}
}
unsigned int encode_base64(unsigned char input[], unsigned int input_length, unsigned char output[]) {
unsigned int full_sets = input_length/3;
// While there are still full sets of 24 bits...
for(unsigned int i = 0; i < full_sets; ++i) {
output[0] = binary_to_base64( input[0] >> 2);
output[1] = binary_to_base64((input[0] & 0x03) << 4 | input[1] >> 4);
output[2] = binary_to_base64((input[1] & 0x0F) << 2 | input[2] >> 6);
output[3] = binary_to_base64( input[2] & 0x3F);
input += 3;
output += 4;
}
switch(input_length % 3) {
case 0:
output[0] = '\0';
break;
case 1:
output[0] = binary_to_base64( input[0] >> 2);
output[1] = binary_to_base64((input[0] & 0x03) << 4);
output[2] = '=';
output[3] = '=';
output[4] = '\0';
break;
case 2:
output[0] = binary_to_base64( input[0] >> 2);
output[1] = binary_to_base64((input[0] & 0x03) << 4 | input[1] >> 4);
output[2] = binary_to_base64((input[1] & 0x0F) << 2);
output[3] = '=';
output[4] = '\0';
break;
}
return encode_base64_length(input_length);
}
unsigned int decode_base64(unsigned char input[], unsigned char output[]) {
unsigned int output_length = decode_base64_length(input);
// While there are still full sets of 24 bits...
for(unsigned int i = 2; i < output_length; i += 3) {
output[0] = base64_to_binary(input[0]) << 2 | base64_to_binary(input[1]) >> 4;
output[1] = base64_to_binary(input[1]) << 4 | base64_to_binary(input[2]) >> 2;
output[2] = base64_to_binary(input[2]) << 6 | base64_to_binary(input[3]);
input += 4;
output += 3;
}
switch(output_length % 3) {
case 1:
output[0] = base64_to_binary(input[0]) << 2 | base64_to_binary(input[1]) >> 4;
break;
case 2:
output[0] = base64_to_binary(input[0]) << 2 | base64_to_binary(input[1]) >> 4;
output[1] = base64_to_binary(input[1]) << 4 | base64_to_binary(input[2]) >> 2;
break;
}
return output_length;
}
#endif // ifndef

View File

@ -25,9 +25,6 @@
#include <stdlib.h>
#include <Arduino.h>
// #define strcmp_P(x, y) strcmp(x,y)
// #define strcasecmp_P(x,y) strcasecmp(x,y)
// #define pgm_read_byte(x) (*(uint8_t*)(x))
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#endif

View File

@ -402,8 +402,10 @@ void IRac::airton(IRAirtonAc *ac,
const int16_t sleep) {
ac->begin();
ac->setPower(on);
ac->setMode(ac->convertMode(mode));
ac->setTemp(degrees);
// Mode needs to be set after temp as Fan-only uses a special temp.
ac->setMode(ac->convertMode(mode));
// Fan needs to be set after mode, as setMode can change the fan speed.
ac->setFan(ac->convertFan(fan));
ac->setSwingV(swingv != stdAc::swingv_t::kOff);
// No Quiet setting available.

View File

@ -0,0 +1,504 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
(This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.)
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
{description}
Copyright (C) {year} {fullname}
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 Street, Fifth Floor, Boston, MA 02110-1301
USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random
Hacker.
{signature of Ty Coon}, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

View File

@ -0,0 +1,101 @@
# IniFile
IniFile is an Arduino library for reading ini files. The format is
similar to that seen in Microsoft `.ini` files but the implementation
is completely independent. IniFile is designed to use minimal memory
requirements, and the only buffer used is one supplied by the user,
thus the user remains in charge of memory usage.
The ini file is separated into sections, where the section names are
written inside square brackets. If you don't wish to use sections then
pass a `NULL` pointer for the section name. Under each section are a
set of key-value pairs, separated by an equals sign (`=`). Spaces
around keys and values are ignored, but extra spaces inside the key
are significant. Whitespace inside the value string is preserved; if
leading or trailing whitespace is important you must quote the value
string inside the ini file, and you must strip out the quotes
yourself. If multiple entries for the same key exist inside the
selected section (if using) then only the first value is returned. If
a section is defined more than once only the first is used. The .ini
file can contain comments, which begin with a semicolon (`;`) or hash
(`#`). The user-supplied buffer must be large enough to accomodate the
longest line in the file.
## Example file format
; Semi-colon comment
[network]
mac = 01:23:45:67:89:AB
# hash comment, leading spaces below
gateway = 192.168.1.1
# extraneous spaces before and after key and value
ip = 192.168.1.2
hosts allow = example.com
# A similarly-named section
[network2]
mac = ee:ee:ee:ee:ee:ee
subnet mask=255.255.255.0
; Extra whitespace around the key and value is permitted
; (and ignored)
hosts allow = sloppy.example.com
[misc]
string = 123456789012345678901234567890123456789001234567890
string2 = a string with spaces in it
; This section is a repeat of en existing section and will be ignored.
[network]
mac = 01:23:45:67:89:ab
ip = 192.168.1.2
gateway = 192.168.1.1
## Write support
Write support is a feature that has been requested on several
occasions but as I am no longer using the IniFile library I will not
add this feature. For anyone planning to add such support the
information below may be useful.
One goal of the `IniFile` implementation was to limit the amount of
memory required. For use in embedded systems `malloc` and `new` are
deliberately not used. Another goal was that tasks which take a longer
duration were broken down into smaller chunks of work, eg
`IniFile::getValue(const char* section, const char* key, char* buffer,
int len, IniFileState &state)`. This was because I wanted my `WwwServer`
library, which uses `IniFile`, to avoid interfering with time-critical
code.
I don't think that write support can meet the time-critical goal but
that doesn't prevent its inclusion. I think the way I would choose to
implement write support is to use `IniFile::findKey()` to find where the
desired key is located in the file. I'd then copy everything up to
that point to a temporary file, insert a line for the value and new
key, skip the current line in the existing file (using
`IniFile::readline()`) and then write out the reminder of the existing
file into the temporary file. I'd like to move or rename the temporary
file over the existing file but the Arduino SD library doesn't provide
this functionality; I'd probably just copy the temporary file over the
old one and then delete the temporary one.
The code has been written under a standard Linux environment, using a
compatibility header file to mimic the SD library. This was far more
convenient than doing everything on the Arduino and enabled me to use
`gdb` to debug the code and core dumps. You'll find `arduino_compat.h`
inside the test directory, along with a `Makefile` which can be used for
regression testing. Any proposed changes must pass the regression
tests.
## Contributors
* [Steve Marple](https://github.com/stevemarple)
* [per1234](https://github.com/per1234)
* [OscarVanL](https://github.com/OscarVanL)
* [MikuX2](https://github.com/toybox01)
* [kaixxx](https://github.com/kaixxx)

View File

@ -0,0 +1,135 @@
#include <SD.h>
#include <SPI.h>
#include <IPAddress.h>
#include <IniFile.h>
// The select pin used for the SD card
#define SD_SELECT 10
//#define ETHERNET_SELECT 10
void printErrorMessage(uint8_t e, bool eol = true)
{
switch (e) {
case IniFile::errorNoError:
Serial.print("no error");
break;
case IniFile::errorFileNotFound:
Serial.print("file not found");
break;
case IniFile::errorFileNotOpen:
Serial.print("file not open");
break;
case IniFile::errorBufferTooSmall:
Serial.print("buffer too small");
break;
case IniFile::errorSeekError:
Serial.print("seek error");
break;
case IniFile::errorSectionNotFound:
Serial.print("section not found");
break;
case IniFile::errorKeyNotFound:
Serial.print("key not found");
break;
case IniFile::errorEndOfFile:
Serial.print("end of file");
break;
case IniFile::errorUnknownError:
Serial.print("unknown error");
break;
default:
Serial.print("unknown error value");
break;
}
if (eol)
Serial.println();
}
void setup()
{
// Configure all of the SPI select pins as outputs and make SPI
// devices inactive, otherwise the earlier init routines may fail
// for devices which have not yet been configured.
pinMode(SD_SELECT, OUTPUT);
digitalWrite(SD_SELECT, HIGH); // disable SD card
// pinMode(ETHERNET_SELECT, OUTPUT);
// digitalWrite(ETHERNET_SELECT, HIGH); // disable Ethernet
const size_t bufferLen = 80;
char buffer[bufferLen];
const char *filename = "/lunch.ini";
Serial.begin(9600);
SPI.begin();
if (!SD.begin(SD_SELECT))
while (1)
Serial.println("SD.begin() failed");
IniFile ini(filename);
if (!ini.open()) {
Serial.print("Ini file ");
Serial.print(filename);
Serial.println(" does not exist");
// Cannot do anything else
while (1)
;
}
Serial.println("Ini file exists");
// Check the file is valid. This can be used to warn if any lines
// are longer than the buffer.
if (!ini.validate(buffer, bufferLen)) {
Serial.print("ini file ");
Serial.print(ini.getFilename());
Serial.print(" not valid: ");
printErrorMessage(ini.getError());
// Cannot do anything else
while (1)
;
}
// Browse through all sections and print contents:
IniFileState state;
char sectName[bufferLen];
Serial.println();
while (ini.browseSections(sectName, bufferLen, state)) {
Serial.print("> ");
Serial.print(sectName);
if (ini.getValue(sectName, "meal", buffer, bufferLen)) {
Serial.print(" eats ");
Serial.print(buffer);
} else
Serial.print(" eats nothing");
if (ini.getValue(sectName, "drinks", buffer, bufferLen)) {
Serial.print(", drinks ");
Serial.print(buffer);
} else
Serial.print(", drinks nothing");
if (ini.getValue(sectName, "dessert", buffer, bufferLen)) {
Serial.print(" and has ");
Serial.print(buffer);
Serial.println(" for dessert.");
} else
Serial.println(" and has no dessert.");
}
// finished!
Serial.println();
printErrorMessage(ini.getError());
// Cannot do anything else
while (1)
;
}
void loop()
{
}

View File

@ -0,0 +1,35 @@
# IniFile browsing example
Shows how to browse through an ini file with an unknown number of sections
which all contain the same elements. This can be useful to store different
profiles which are selectable on your device.
## Instructions for use
* Copy the `lunch.ini` file to the root directory of your (micro)SD card.
* Modify the `IniBrowseExample.ino` file so that `SD_SELECT` defines
the correct pin number.
* Compile and upload the sketch.
## Expected output
It may take a few seconds from the sketch starting before anything is
printed to the serial port, be patient. If the sketch runs correctly
the output should appear as below:
Ini file exists
> Karen eats burger, drinks beer and has chocolate for dessert.
> Peter eats falafel, drinks tea without milk and has vegan icecream for dessert.
> Noel eats sushi, drinks water and has no dessert.
> Jessica eats sandwich, drinks nothing and has muffin for dessert.
end of file
If the SD card is missing or cannot be read the sketch will print:
SD.begin() failed

View File

@ -0,0 +1,22 @@
; A list of settings/profiles stored as sections.
; Each profile has the same elements.
[Karen]
meal = burger
drinks = beer
dessert = chocolate
[Peter]
meal = falafel
drinks = tea without milk
dessert = vegan icecream
[Noel]
meal = sushi
drinks = water
; note: dessert is missing here
[Jessica]
meal = sandwich
; no drinks
dessert = muffin

View File

@ -0,0 +1,143 @@
#include <SD.h>
#include <SPI.h>
#include <IPAddress.h>
#include <IniFile.h>
// The select pin used for the SD card
//#define SD_SELECT 4
#define SD_SELECT 22
#define ETHERNET_SELECT 10
void printErrorMessage(uint8_t e, bool eol = true)
{
switch (e) {
case IniFile::errorNoError:
Serial.print("no error");
break;
case IniFile::errorFileNotFound:
Serial.print("file not found");
break;
case IniFile::errorFileNotOpen:
Serial.print("file not open");
break;
case IniFile::errorBufferTooSmall:
Serial.print("buffer too small");
break;
case IniFile::errorSeekError:
Serial.print("seek error");
break;
case IniFile::errorSectionNotFound:
Serial.print("section not found");
break;
case IniFile::errorKeyNotFound:
Serial.print("key not found");
break;
case IniFile::errorEndOfFile:
Serial.print("end of file");
break;
case IniFile::errorUnknownError:
Serial.print("unknown error");
break;
default:
Serial.print("unknown error value");
break;
}
if (eol)
Serial.println();
}
void setup()
{
// Configure all of the SPI select pins as outputs and make SPI
// devices inactive, otherwise the earlier init routines may fail
// for devices which have not yet been configured.
pinMode(SD_SELECT, OUTPUT);
digitalWrite(SD_SELECT, HIGH); // disable SD card
pinMode(ETHERNET_SELECT, OUTPUT);
digitalWrite(ETHERNET_SELECT, HIGH); // disable Ethernet
const size_t bufferLen = 80;
char buffer[bufferLen];
const char *filename = "/net.ini";
Serial.begin(9600);
SPI.begin();
if (!SD.begin(SD_SELECT))
while (1)
Serial.println("SD.begin() failed");
IniFile ini(filename);
if (!ini.open()) {
Serial.print("Ini file ");
Serial.print(filename);
Serial.println(" does not exist");
// Cannot do anything else
while (1)
;
}
Serial.println("Ini file exists");
// Check the file is valid. This can be used to warn if any lines
// are longer than the buffer.
if (!ini.validate(buffer, bufferLen)) {
Serial.print("ini file ");
Serial.print(ini.getFilename());
Serial.print(" not valid: ");
printErrorMessage(ini.getError());
// Cannot do anything else
while (1)
;
}
// Fetch a value from a key which is present
if (ini.getValue("network", "mac", buffer, bufferLen)) {
Serial.print("section 'network' has an entry 'mac' with value ");
Serial.println(buffer);
}
else {
Serial.print("Could not read 'mac' from section 'network', error was ");
printErrorMessage(ini.getError());
}
// Try fetching a value from a missing key (but section is present)
if (ini.getValue("network", "nosuchkey", buffer, bufferLen)) {
Serial.print("section 'network' has an entry 'nosuchkey' with value ");
Serial.println(buffer);
}
else {
Serial.print("Could not read 'nosuchkey' from section 'network', error was ");
printErrorMessage(ini.getError());
}
// Try fetching a key from a section which is not present
if (ini.getValue("nosuchsection", "nosuchkey", buffer, bufferLen)) {
Serial.print("section 'nosuchsection' has an entry 'nosuchkey' with value ");
Serial.println(buffer);
}
else {
Serial.print("Could not read 'nosuchkey' from section 'nosuchsection', error was ");
printErrorMessage(ini.getError());
}
// Fetch a boolean value
bool allowPut; // variable where result will be stored
bool found = ini.getValue("/upload", "allow put", buffer, bufferLen, allowPut);
if (found) {
Serial.print("The value of 'allow put' in section '/upload' is ");
// Print value, converting boolean to a string
Serial.println(allowPut ? "TRUE" : "FALSE");
}
else {
Serial.print("Could not get the value of 'allow put' in section '/upload': ");
printErrorMessage(ini.getError());
}
}
void loop()
{
}

View File

@ -0,0 +1,29 @@
# IniFile example
## Instructions for use
* Copy the `net.ini` file to the root directory of your (micro)SD card.
* Modify the `IniFileExample.ino` file so that `SD_SELECT` defines
the correct pin number.
* Compile and upload the sketch.
## Expected output
It may take a few seconds from the sketch starting before anything is
printed to the serial port, be patient. If the sketch runs correctly
the output should appear as below:
Ini file exists
section 'network' has an entry 'mac' with value 01:23:45:67:89:AB
Could not read 'nosuchkey' from section 'network', error was key not found
Could not read 'nosuchkey' from section 'nosuchsection', error was section not found
The value of 'allow put' in section '/upload' is TRUE
If the SD card is missing or cannot be read the sketch will print:
SD.begin() failed

View File

@ -0,0 +1,68 @@
; Semi-colon comment
[network]
mac = 01:23:45:67:89:AB
# hash comment, leading spaces below
gateway = 192.168.1.1
# extraneous spaces before and after key and value
ip = 192.168.1.2
hosts allow = example.com
# A similarly-named section
[network2]
mac = ee:ee:ee:ee:ee:ee
subnet mask=255.255.255.0
; Test extra whitespace in keys and value
hosts allow = sloppy.example.com
[misc]
string = 123456789012345678901234567890123456789001234567890
string2 = a string with spaces in it
; ini file for WwwServerExample
[mime types]
default = text/plain
htm = text/html
bin = application/octet-stream
pdf = application/pdf
[/]
; no access to root of SD filesystem
handler = default
error document 403 = /errordoc/403.htm
[/www.ini]
handler = default
[/data]
handler = default
[/data/private]
; Block access to this directory
handler = prohibit
error document 403 = /data/private/403.htm
[/data/noaccess.txt]
; Block access to this file
handler = prohibit
[/status]
; built-in status handler
handler = status
[/cgi]
; User-defined handler
handler = cgi
[/src]
; A redirect
handler = temporary redirect
location = http://github.com/stevemarple/WwwServer
[/upload]
allow put = true

View File

@ -0,0 +1,9 @@
name=IniFile
version=1.3.0+tasmota
author=Steve Marple <stevemarple@googlemail.com>, Stephan Hadiger
maintainer=Steve Marple <stevemarple@googlemail.com>, Stephan Hadiger
sentence=Library to read and parse .ini files, adapted for Tasmota
paragraph=IniFile is a library to read and parse .ini files as used by Microsoft Windows. IniFile is designed to use minimal memory requirements, and the only buffer used is one supplied by the user, thus the user remains in charge of memory usage. GNU LGPL v2.1.
category=Other
url=https://github.com/stevemarple/IniFile
architectures=*

View File

@ -0,0 +1,498 @@
#include "IniFile.h"
#include <Arduino.h>
#include "base64.hpp"
//**************************************************************************************************************
// enable AddLog support within a C++ library
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 FS *ffsp;
IniFile::IniFile(File &file)
{
_file = file;
}
IniFile::~IniFile()
{
//if (_file)
// _file.close();
}
IniFile::error_t IniFile::getError(void)
{
return _error;
}
void IniFile::clearError(void)
{
_error = errorNoError;
}
bool IniFile::getValue(const char* section, const char* key, IniFileState &state)
{
char *cp = nullptr;
char *bufptr = buffer;
bool done = false;
if (!_file) {
_error = errorFileNotOpen;
return true;
}
switch (state.getValueState) {
case IniFileState::funcUnset:
state.getValueState = (section == NULL ? IniFileState::funcFindKey
: IniFileState::funcFindSection);
state.readLinePosition = 0;
break;
case IniFileState::funcFindSection:
if (findSection(section, state)) {
if (_error != errorNoError)
return true;
state.getValueState = IniFileState::funcFindKey;
}
break;
case IniFileState::funcFindKey:
if (findKey(section, key, &cp, state)) {
if (_error != errorNoError)
return true;
// Found key line in correct section
cp = skipWhiteSpace(cp);
removeTrailingWhiteSpace(cp);
// Copy from cp to buffer, but the strings overlap so strcpy is out
while (*cp != '\0')
*bufptr++ = *cp++;
*bufptr = '\0';
return true;
}
break;
default:
// How did this happen?
_error = errorUnknownError;
done = true;
break;
}
return done;
}
bool IniFile::getValue(const char* section, const char* key)
{
IniFileState state;
while (!getValue(section, key, state))
;
return _error == errorNoError;
}
bool IniFile::getValueStr(const char* section, const char* key, char *value, size_t vlen)
{
if (!getValue(section, key)) return false; // error
if (strlen(buffer) >= vlen) return false;
strcpy(value, buffer);
return true;
}
bool IniFile::getValueString(const char* section, const char* key, String &value)
{
if (!getValue(section, key)) return false; // error
value = buffer;
return true;
}
// For true accept: true, yes, 1
// For false accept: false, no, 0
bool IniFile::getValueBool(const char* section, const char* key, bool& val)
{
if (!getValue(section, key))
return false; // error
if (strcasecmp_P(buffer, PSTR("true")) == 0 ||
strcasecmp_P(buffer, PSTR("yes")) == 0 ||
strcasecmp_P(buffer, PSTR("1")) == 0) {
val = true;
return true;
}
if (strcasecmp_P(buffer, PSTR("false")) == 0 ||
strcasecmp_P(buffer, PSTR("no")) == 0 ||
strcasecmp_P(buffer, PSTR("0")) == 0) {
val = false;
return true;
}
return false; // does not match any known strings
}
bool IniFile::getValueInt(const char* section, const char* key, int32_t& val)
{
if (!getValue(section, key)) return false; // error
val = atoi(buffer);
return true;
}
bool IniFile::getValueUInt16(const char* section, const char* key, uint16_t& val)
{
int32_t val32;
if (!getValue(section, key)) return false; // error
val32 = atoi(buffer);
if (val32 < 0 || val32 > 65535) return false;
val = (uint16_t) val32;
return true;
}
bool IniFile::getValueFloat(const char* section, const char* key, float & val)
{
if (!getValue(section, key))
return false; // error
char *endptr;
float tmp = strtod(buffer, &endptr);
if (endptr == buffer)
return false; // no conversion
if (*endptr == '\0') {
val = tmp;
return true; // valid conversion
}
// buffer has trailing non-numeric characters, and since the buffer
// already had whitespace removed discard the entire results
return false;
}
bool IniFile::getIPAddress(const char* section, const char* key, ip_addr_t *ip)
{
if (!getValue(section, key)) return false; // error
IPAddress ipaddr;
if (!ipaddr.fromString(buffer)) { return false; }
#ifdef ESP32
ipaddr.to_ip_addr_t(ip);
#else
*ip = ipaddr;
#endif
return true;
}
bool IniFile::getMACAddress(const char* section, const char* key,
uint8_t mac[6])
{
// Need 18 chars: 6 * 2 hex digits, 5 : or - and a null char
if (bufferLen < 18)
return false;
if (!getValue(section, key))
return false; // error
int i = 0;
char* cp = buffer;
memset(mac, 0, 6);
while (*cp != '\0' && i < 6) {
if (*cp == ':' || *cp == '-') {
++i;
++cp;
continue;
}
if (isdigit(*cp)) {
mac[i] *= 16; // working in hex!
mac[i] += (*cp - '0');
}
else {
if (isxdigit(*cp)) {
mac[i] *= 16; // working in hex!
mac[i] += (toupper(*cp) - 55); // convert A to 0xA, F to 0xF
}
else {
memset(mac, 0, 6);
return false;
}
}
++cp;
}
return true;
}
bool IniFile::getValueBase64(const char* section, const char* key, uint8_t *value, size_t vlen)
{
if (!getValue(section, key)) return false; // error
size_t len = decode_base64_length((unsigned char*)buffer);
if (len != vlen) return false;
len = decode_base64((unsigned char*)buffer, value);
return true;
}
bool IniFile::parseCIDR(String& cidr, ip_addr_t *ip, ip_addr_t *mask)
{
int32_t slash = cidr.indexOf('/');
if (slash < 0) { return false; }
IPAddress ipaddr;
if (!ipaddr.fromString(cidr.substring(0, slash))) { return false; }
#ifdef ESP32
ipaddr.to_ip_addr_t(ip);
#else
*ip = ipaddr;
#endif
int32_t prefixLen = cidr.substring(slash + 1).toInt();
if (prefixLen < 0 || prefixLen > 32) { return false; }
IPAddress maskaddr((prefixLen <= 0) ? 0 : (0xFFFFFFFF >> (32 - prefixLen)));
#ifdef ESP32
maskaddr.to_ip_addr_t(mask);
#else
*mask = maskaddr;
#endif
return true;
}
bool IniFile::getCIDR(const char* section, const char* key, ip_addr_t *ip, ip_addr_t *mask)
{
String cidr;
if (!getValueString(section, key, cidr)) return false; // error
return parseCIDR(cidr, ip, mask);
}
bool IniFile::getDomainPort(const char* section, const char* key, String &domain, uint16_t &port, uint16_t default_port)
{
if (!getValueString(section, key, domain)) return false; // error
int32_t colon = domain.indexOf(':');
if (colon == 0) { return false; } // having an empty domain is wrong
if (colon > 0) {
port = domain.substring(colon + 1).toInt();
domain = domain.substring(0, colon);
} else {
port = default_port;
}
return true;
}
// From the file location saved in 'state' look for the next section and read its name.
// The name will be in the buffer. Returns false if no section found.
bool IniFile::browseSections(IniFileState &state)
{
error_t err = errorNoError;
char *bufptr = &buffer[0];
do {
err = IniFile::readLine(_file, state.readLinePosition);
if (err != errorNoError) {
// end of file or other error
_error = err;
return false;
} else {
char *cp = skipWhiteSpace(buffer);
if (*cp == '[') {
// Found a section, read the name
++cp;
cp = skipWhiteSpace(cp);
char *ep = strchr(cp, ']');
if (ep != NULL) {
*ep = '\0'; // make ] be end of string
removeTrailingWhiteSpace(cp);
// Copy from cp to buffer, but the strings overlap so strcpy is out
while (*cp != '\0')
*bufptr++ = *cp++;
*bufptr = '\0';
_error = errorNoError;
return true;
}
}
}
// continue searching
} while (err == errorNoError);
// we should never get here...
_error = err;
return false;
}
IniFile::error_t IniFile::readLine(File &file, uint32_t &pos)
{
if (!file)
return errorFileNotOpen;
if (bufferLen < 3)
return errorBufferTooSmall;
if (!file.seek(pos))
return errorSeekError;
size_t bytesRead = file.readBytes(buffer, bufferLen);
if (!bytesRead) {
buffer[0] = '\0';
//return 1; // done
return errorEndOfFile;
}
for (size_t i = 0; i < bytesRead && i < bufferLen-1; ++i) {
// Test for '\n' with optional '\r' too
// if (endOfLineTest(i, '\n', '\r')
if (buffer[i] == '\n' || buffer[i] == '\r') {
char match = buffer[i];
char otherNewline = (match == '\n' ? '\r' : '\n');
// end of line, discard any trailing character of the other sort
// of newline
buffer[i] = '\0';
if (buffer[i+1] == otherNewline)
++i;
pos += (i + 1); // skip past newline(s)
//return (i+1 == bytesRead && !file.available());
return errorNoError;
}
}
if (!file.available()) {
// end of file without a newline
buffer[bytesRead] = '\0';
// return 1; //done
return errorEndOfFile;
}
buffer[bufferLen-1] = '\0'; // terminate the string
return errorBufferTooSmall;
}
bool IniFile::isCommentChar(char c)
{
return (c == ';' || c == '#');
}
char* IniFile::skipWhiteSpace(char* str)
{
char *cp = str;
if (cp)
while (isspace(*cp))
++cp;
return cp;
}
void IniFile::removeTrailingWhiteSpace(char* str)
{
if (str == nullptr)
return;
char *cp = str + strlen(str) - 1;
while (cp >= str && isspace(*cp))
*cp-- = '\0';
}
bool IniFile::findSection(const char* section, IniFileState &state)
{
if (section == NULL) {
_error = errorSectionNotFound;
return true;
}
error_t err = IniFile::readLine(_file, state.readLinePosition);
if (err != errorNoError && err != errorEndOfFile) {
// Signal to caller to stop looking and any error value
_error = err;
return true;
}
char *cp = skipWhiteSpace(buffer);
//if (isCommentChar(*cp))
//return (done ? errorSectionNotFound : 0);
if (isCommentChar(*cp)) {
// return (err == errorEndOfFile ? errorSectionNotFound : errorNoError);
if (err == errorEndOfFile) {
_error = errorSectionNotFound;
return true;
}
else
return false; // Continue searching
}
if (*cp == '[') {
// Start of section
++cp;
cp = skipWhiteSpace(cp);
char *ep = strchr(cp, ']');
if (ep != NULL) {
*ep = '\0'; // make ] be end of string
removeTrailingWhiteSpace(cp);
if (strcmp(cp, section) == 0) {
_error = errorNoError;
return true;
}
}
}
// Not a valid section line
//return (done ? errorSectionNotFound : 0);
if (err == errorEndOfFile) {
_error = errorSectionNotFound;
return true;
}
return false;
}
// From the current file location look for the matching key. If
// section is non-NULL don't look in the next section
bool IniFile::findKey(const char* section, const char* key,
char** keyptr,
IniFileState &state)
{
if (key == NULL || *key == '\0') {
_error = errorKeyNotFound;
return true;
}
error_t err = IniFile::readLine(_file, state.readLinePosition);
if (err != errorNoError && err != errorEndOfFile) {
_error = err;
return true;
}
char *cp = skipWhiteSpace(buffer);
// if (isCommentChar(*cp))
// return (done ? errorKeyNotFound : 0);
if (isCommentChar(*cp)) {
if (err == errorEndOfFile) {
_error = errorKeyNotFound;
return true;
}
else
return false; // Continue searching
}
if (section && *cp == '[') {
// Start of a new section
_error = errorKeyNotFound;
return true;
}
// Find '='
char *ep = strchr(cp, '=');
if (ep != NULL) {
*ep = '\0'; // make = be the end of string
removeTrailingWhiteSpace(cp);
if (strcmp(cp, key) == 0) {
*keyptr = ep + 1;
_error = errorNoError;
return true;
}
}
// Not the valid key line
if (err == errorEndOfFile) {
_error = errorKeyNotFound;
return true;
}
return false;
}
IniFileState::IniFileState()
{
readLinePosition = 0;
getValueState = funcUnset;
}

View File

@ -0,0 +1,117 @@
#ifndef _INIFILE_H
#define _INIFILE_H
#include <stdint.h>
#include <FS.h>
#include "IPAddress.h"
#define INIFILE_VERSION "1.3.0"
class IniFileState;
class IniFile {
public:
enum error_t {
errorNoError = 0,
errorFileNotFound,
errorFileNotOpen,
errorBufferTooSmall,
errorSeekError,
errorSectionNotFound,
errorKeyNotFound,
errorEndOfFile,
errorUnknownError,
};
// Create an IniFile object. It isn't opened until open() is called on it.
IniFile(File &file);
~IniFile();
error_t getError(void);
void clearError(void);
// Get value from the file, but split into many short tasks. Return
// value: false means continue, true means stop. Call getError() to
// find out if any error
bool getValue(const char* section, const char* key, IniFileState &state);
// Get value, as one big task. Return = true means value is present
// in buffer
bool getValue(const char* section, const char* key);
// Get the value as a string, storing the result in a new buffer
// (not the working buffer)
bool getValueStr(const char* section, const char* key, char *value, size_t vlen);
bool getValueString(const char* section, const char* key, String &value);
// Get a boolean value
bool getValueBool(const char* section, const char* key, bool& b);
// Get an integer value
bool getValueInt(const char* section, const char* key, int32_t& val);
// Get an uint16_t value
bool getValueUInt16(const char* section, const char* key, uint16_t& val);
// Get a float value
bool getValueFloat(const char* section, const char* key, float& val);
bool getIPAddress(const char* section, const char* key, ip_addr_t *ip);
bool getMACAddress(const char* section, const char* key,uint8_t mac[6]);
bool getValueBase64(const char* section, const char* key, uint8_t *value, size_t vlen);
static bool parseCIDR(String& str, ip_addr_t *ip, ip_addr_t *mask);
bool getCIDR(const char* section, const char* key, ip_addr_t *ip, ip_addr_t *mask);
bool getDomainPort(const char* section, const char* key, String &domain, uint16_t &port, uint16_t default_port);
// From the file location saved in 'state' look for the next section and read its name.
// The name will be in the buffer. Returns false if no section found.
bool browseSections(IniFileState &state);
// Utility function to read a line from a file, make available to all
//static int8_t readLine(File &file, char *buffer, size_t len, uint32_t &pos);
error_t readLine(File &file, uint32_t &pos);
static bool isCommentChar(char c);
static char* skipWhiteSpace(char* str);
static void removeTrailingWhiteSpace(char* str);
protected:
// True means stop looking, false means not yet found
bool findSection(const char* section, IniFileState &state);
bool findKey(const char* section, const char* key, char** keyptr, IniFileState &state);
private:
String _filename;
error_t _error;
File _file;
static constexpr size_t bufferLen = 80;
char buffer[bufferLen];
};
class IniFileState {
public:
IniFileState();
private:
enum {funcUnset = 0,
funcFindSection,
funcFindKey,
};
uint32_t readLinePosition;
uint8_t getValueState;
friend class IniFile;
};
#endif

View File

@ -0,0 +1,32 @@
Copyright (c) 2021 Kenta Ida (fuga@fugafuga.org)
Copyright (c) 2022 Tomoyuki Sakurai (y@trombik.org)
Copyright (c) 2023-2024 Simone Rossetto (simros85@gmail.com)
The original license is below:
Copyright (c) 2021 Daniel Hope (www.floorsense.nz)
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 "Floorsense Ltd", "Agile Workspace Ltd" 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 OWNER 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.
Author: Daniel Hope <daniel.hope@smartalock.com>

View File

@ -0,0 +1,55 @@
# WireGuard implementation for ESPHome
This is an implementation of [WireGuard&reg;](https://www.wireguard.com/) VPN
for [ESPHome](https://esphome.io/), based on
[Wireguard Implementation for ESP-IDF](https://github.com/trombik/esp_wireguard)
(by [@trombik](https://github.com/trombik)).
[![PlatformIO Registry](https://badges.registry.platformio.org/packages/droscy/library/esp_wireguard.svg)](https://registry.platformio.org/libraries/droscy/esp_wireguard)
## Usage
Please refer to the official documentation of [WireGuard Component](https://esphome.io/components/wireguard)
in ESPHome website.
## Compatibility
This code targets only ESPHome and has been tested on the following platforms:
* ESP32 (with both frameworks)
* ESP8266
* LibreTiny (with `bk72` microcontrollers only)
## References
For additional information see:
* the original feature-request [esphome/feature-requests#1444](https://github.com/esphome/feature-requests/issues/1444)
* the first pull-request [esphome/esphome#4256](https://github.com/esphome/esphome/pull/4256)
* `esp8266` support [esphome/esphome#6365](https://github.com/esphome/esphome/pull/6365)
* LibreTiny support [droscy/esp_wireguard#4](https://github.com/droscy/esp_wireguard/pull/4)
## License
BSD 3-Clause License (SPDX ID: BSD-3-Clause)
This project is licensed under [BSD 3-Clause License](https://spdx.org/licenses/BSD-3-Clause.html)
except where explicitly written in files themselves or when other license files state differently.
"WireGuard" and the "WireGuard" logo are registered trademarks of Jason A. Donenfeld.
Please see ["WireGuard" Trademark Usage Policy](https://www.wireguard.com/trademark-policy/)
for additional information.
## Authors
* Simone Rossetto (simros85@gmail.com)
* Tomoyuki Sakurai (y@trombik.org)
* Daniel Hope (daniel.hope@smartalock.com)
* Kenta Ida (fuga@fugafuga.org)
* Matthew Dempsky
* D. J. Bernstein

View File

@ -0,0 +1,167 @@
/*
* Copyright (c) 2022 Tomoyuki Sakurai <y@trombik.org>
* Copyright (c) 2023-2024 Simone Rossetto <simros85@gmail.com>
* 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 "Floorsense Ltd", "Agile Workspace Ltd" 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 OWNER 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.
*
*/
#if !defined(__ESP_WIREGUARD__H__)
#define __ESP_WIREGUARD__H__
#ifdef __cplusplus
extern "C" {
#endif
#include "esp_wireguard_err.h"
#include <stdint.h>
#include <time.h>
#include <lwip/netif.h>
#define WG_KEY_LEN (32)
#define WG_B64_KEY_LEN (4 * ((WG_KEY_LEN + 2) / 3))
typedef uint8_t wg_key_t[WG_KEY_LEN];
typedef struct {
/* interface config */
wg_key_t private_key2; /**< private key generated by wg genkey. Required. */
uint16_t listen_port; /**< a 16-bit port for listening */
uint32_t fw_mark; /**< a 32-bit fwmark for outgoing packets */
/* peer config */
wg_key_t public_key2; /**< public key calculated by wg pubkey from a private key. Required. */
wg_key_t preshared_key2; /**< preshared key generated by wg genpsk. */
ip_addr_t address2; /**< a local IP address. */
ip_addr_t subnet; /**< a subnet mask of the local IP address. */
ip_addr_t netmask2; /**< the global subnet for the netif. */
const char* endpoint; /**< an endpoint IP address or hostname. */
ip_addr_t endpoint_ip; /**< endpoint IP address (internal use, resolved through dns query) */
uint16_t port; /**< a port number of remote endpoint. Default is 51820. */
uint16_t persistent_keepalive; /**< a seconds interval, between 1 and 65535 inclusive, of how often to send an
authenticated empty packet to the peer for the purpose of keeping a stateful
firewall or NAT mapping valid persistently. Set zero to disable the feature.
Default is zero. */
} wireguard_config_t;
typedef struct {
wireguard_config_t* config; /**< a pointer to wireguard config */
struct netif* netif; /**< a pointer to configured netif */
} wireguard_ctx_t;
/**
* @brief Initialize WireGuard
*
* Call this function to initialize the context of WireGuard.
*
* Do not call this function multiple times.
*
* To connect to other peer, use `esp_wireguard_disconnect()`, and
* `esp_wireguard_init()` with a new configuration. To reconnect to
* the same peer just use `esp_wireguard_disconnect()` and then
* `esp_wireguard_connect()`.
*
* @param config WireGuard configuration.
* @param[out] ctx Context of WireGuard.
*
* @return
* - ESP_OK: Successfully initilized WireGuard interface.
* - ESP_ERR_INVALID_ARG: given argument is invalid.
* - ESP_ERR_INVALID_STATE: hostname dns resolution cannot start
* - ESP_FAIL: Other error.
*/
esp_err_t esp_wireguard_init(wireguard_config_t *config, wireguard_ctx_t *ctx);
/**
* @brief Create a WireGuard interface and start establishing the connection
* to the peer.
*
* Call this function to start establishing the connection. Note that `ESP_OK`
* does not mean the connection is established. To see if the connection is
* established, or the peer is up, use `esp_wireguard_peer_is_up()`.
*
* Do not call this function multiple times.
*
* @param ctx Context of WireGuard.
* @return
* - ESP_OK on success.
* - ESP_ERR_INVALID_ARG if input arguments are invalid
* - ESP_ERR_RETRY dns query still ongoing for endpoint hostname resolution (retry connection)
* - ESP_ERR_INVALID_IP if endpoint IP address is missing or invalid (dns query failed)
* - ESP_FAIL on failure.
*/
esp_err_t esp_wireguard_connect(wireguard_ctx_t *ctx);
/**
* @brief Test if the peer is up.
* @param ctx Context of WireGuard
* @return
* - ESP_OK on peer up.
* - ESP_ERR_INVALID_ARG if ctx is NULL.
* - ESP_FAIL on peer still down.
*/
esp_err_t esp_wireguard_peer_is_up(const wireguard_ctx_t *ctx);
/**
* @brief Get timestamp of the latest handshake (with seconds resolution since unix epoch)
* @param ctx Context of WireGuard
* @param result the output timestamp
* @return
* - ESP_OK on success
* - ESP_FAIL if no handshake already completed
* - ESP_ERR_INVALID_ARG if ctx is NULL
* - ESP_ERR_INVALID_STATE if data inside ctx is not valid
*/
esp_err_t esp_wireguard_latest_handshake(const wireguard_ctx_t *ctx, time_t *result);
/**
* @brief Add new allowed IP/mask to the list of allowed ip/mask
* @param ctx Context of WireGuard
* @param allowed_ip The new IP to be allowed through tunnel
* @param allowed_ip_mask The mask of the new IP
* @return
* - ESP_OK on success
* - ESP_FAIL if the adding failed
* - ESP_ERR_INVALID_ARG if ctx, allowed_ip or allowed_ip_mask are invalid or empty
* - ESP_ERR_INVALID_STATE if data inside ctx is not valid
*/
esp_err_t esp_wireguard_add_allowed_ip(const wireguard_ctx_t *ctx, const ip_addr_t& allowed_ip, const ip_addr_t& allowed_ip_mask);
/**
* @brief Disconnect from the peer
*
* @param ctx Context of WireGuard.
* @return
* - ESP_OK on success.
*/
esp_err_t esp_wireguard_disconnect(wireguard_ctx_t *ctx);
#ifdef __cplusplus
}
#endif
#endif
// vim: expandtab tabstop=4

View File

@ -0,0 +1,55 @@
{
"name": "esp_wireguard_tasmota",
"version": "0.4.2",
"description": "WireGuard implementation for Tasmota, based on the version for ESPHome",
"keywords":[
"tasmota",
"communication",
"network",
"wireguard",
"vpn"
],
"authors":[
{
"name": "Stephan Hadinger",
"email": "stephan.hadinger@gmail.com",
"url": "https://github.com/arendst/Tasmota",
"maintainer": true
},
{
"name": "Simone Rossetto",
"email": "simros85@gmail.com",
"url": "https://github.com/droscy",
"maintainer": true
},
{
"name": "Tomoyuki Sakurai",
"email": "y@trombik.org",
"url": "https://github.com/trombik"
},
{
"name": "Daniel Hope",
"email": "daniel.hope@smartalock.com",
"url": "https://github.com/smartalock"
},
{
"name": "Kenta Ida",
"email": "fuga@fugafuga.org"
},
{
"name": "Matthew Dempsky"
},
{
"name": "D. J. Bernstein"
}
],
"license": "BSD-3-Clause",
"platforms": [
"espressif32",
"espressif8266"
],
"frameworks":[
"espidf",
"arduino"
]
}

View File

@ -0,0 +1,25 @@
#include "crypto.h"
#include <stdlib.h>
#include <stdint.h>
void crypto_zero(void *dest, size_t len) {
volatile uint8_t *p = (uint8_t *)dest;
while (len--) {
*p++ = 0;
}
}
bool crypto_equal(const void *a, const void *b, size_t size) {
uint8_t neq = 0;
while (size > 0) {
neq |= *(uint8_t *)a ^ *(uint8_t *)b;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpointer-arith"
a += 1;
b += 1;
#pragma GCC diagnostic pop
size -= 1;
}
return (neq) ? false : true;
}

View File

@ -0,0 +1,106 @@
#ifndef _CRYPTO_H_
#define _CRYPTO_H_
#ifdef __cplusplus
extern "C" {
#endif
// BLAKE2S IMPLEMENTATION
#include "crypto/refc/blake2s.h"
#define wireguard_blake2s_ctx blake2s_ctx
#define wireguard_blake2s_init(ctx,outlen,key,keylen) blake2s_init(ctx,outlen,key,keylen)
#define wireguard_blake2s_update(ctx,in,inlen) blake2s_update(ctx,in,inlen)
#define wireguard_blake2s_final(ctx,out) blake2s_final(ctx,out)
#define wireguard_blake2s(out,outlen,key,keylen,in,inlen) blake2s(out,outlen,key,keylen,in,inlen)
// X25519 IMPLEMENTATION
int crypto_scalarmult_curve25519(unsigned char *q, const unsigned char *n,const unsigned char *p);
#define wireguard_x25519(a,b,c) crypto_scalarmult_curve25519(a,b,c)
// CHACHA20POLY1305 IMPLEMENTATION
#include "crypto/refc/chacha20poly1305.h"
#define wireguard_aead_encrypt(dst,src,srclen,ad,adlen,nonce,key) chacha20poly1305_encrypt(dst,src,srclen,ad,adlen,nonce,key)
#define wireguard_aead_decrypt(dst,src,srclen,ad,adlen,nonce,key) chacha20poly1305_decrypt(dst,src,srclen,ad,adlen,nonce,key)
#define wireguard_xaead_encrypt(dst,src,srclen,ad,adlen,nonce,key) xchacha20poly1305_encrypt(dst,src,srclen,ad,adlen,nonce,key)
#define wireguard_xaead_decrypt(dst,src,srclen,ad,adlen,nonce,key) xchacha20poly1305_decrypt(dst,src,srclen,ad,adlen,nonce,key)
// Endian / unaligned helper macros
#define U8C(v) (v##U)
#define U32C(v) (v##U)
#define U8V(v) ((uint8_t)(v) & U8C(0xFF))
#define U32V(v) ((uint32_t)(v) & U32C(0xFFFFFFFF))
#define U8TO32_LITTLE(p) \
(((uint32_t)((p)[0]) ) | \
((uint32_t)((p)[1]) << 8) | \
((uint32_t)((p)[2]) << 16) | \
((uint32_t)((p)[3]) << 24))
#define U8TO64_LITTLE(p) \
(((uint64_t)((p)[0]) ) | \
((uint64_t)((p)[1]) << 8) | \
((uint64_t)((p)[2]) << 16) | \
((uint64_t)((p)[3]) << 24) | \
((uint64_t)((p)[4]) << 32) | \
((uint64_t)((p)[5]) << 40) | \
((uint64_t)((p)[6]) << 48) | \
((uint64_t)((p)[7]) << 56))
#define U16TO8_BIG(p, v) \
do { \
(p)[1] = U8V((v) ); \
(p)[0] = U8V((v) >> 8); \
} while (0)
#define U32TO8_LITTLE(p, v) \
do { \
(p)[0] = U8V((v) ); \
(p)[1] = U8V((v) >> 8); \
(p)[2] = U8V((v) >> 16); \
(p)[3] = U8V((v) >> 24); \
} while (0)
#define U32TO8_BIG(p, v) \
do { \
(p)[3] = U8V((v) ); \
(p)[2] = U8V((v) >> 8); \
(p)[1] = U8V((v) >> 16); \
(p)[0] = U8V((v) >> 24); \
} while (0)
#define U64TO8_LITTLE(p, v) \
do { \
(p)[0] = U8V((v) ); \
(p)[1] = U8V((v) >> 8); \
(p)[2] = U8V((v) >> 16); \
(p)[3] = U8V((v) >> 24); \
(p)[4] = U8V((v) >> 32); \
(p)[5] = U8V((v) >> 40); \
(p)[6] = U8V((v) >> 48); \
(p)[7] = U8V((v) >> 56); \
} while (0)
#define U64TO8_BIG(p, v) \
do { \
(p)[7] = U8V((v) ); \
(p)[6] = U8V((v) >> 8); \
(p)[5] = U8V((v) >> 16); \
(p)[4] = U8V((v) >> 24); \
(p)[3] = U8V((v) >> 32); \
(p)[2] = U8V((v) >> 40); \
(p)[1] = U8V((v) >> 48); \
(p)[0] = U8V((v) >> 56); \
} while (0)
void crypto_zero(void *dest, size_t len);
bool crypto_equal(const void *a, const void *b, size_t size);
#ifdef __cplusplus
}
#endif
#endif /* _CRYPTO_H_ */

View File

@ -0,0 +1,158 @@
// Taken from RFC7693 - https://tools.ietf.org/html/rfc7693
#include <Arduino.h>
#include "blake2s.h"
#include "../../crypto.h"
// Cyclic right rotation.
#ifndef ROTR32
#define ROTR32(x, y) (((x) >> (y)) ^ ((x) << (32 - (y))))
#endif
// Mixing function G.
#define B2S_G(a, b, c, d, x, y) { \
v[a] = v[a] + v[b] + x; \
v[d] = ROTR32(v[d] ^ v[a], 16); \
v[c] = v[c] + v[d]; \
v[b] = ROTR32(v[b] ^ v[c], 12); \
v[a] = v[a] + v[b] + y; \
v[d] = ROTR32(v[d] ^ v[a], 8); \
v[c] = v[c] + v[d]; \
v[b] = ROTR32(v[b] ^ v[c], 7); }
// Initialization Vector.
static const uint32_t blake2s_iv[8] =
{
0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19
};
// Compression function. "last" flag indicates last block.
static void blake2s_compress(blake2s_ctx *ctx, int last)
{
const uint8_t sigma[10][16] = {
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
{ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
{ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
{ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
{ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
{ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 }
};
int i;
uint32_t v[16], m[16];
for (i = 0; i < 8; i++) { // init work variables
v[i] = ctx->h[i];
v[i + 8] = blake2s_iv[i];
}
v[12] ^= ctx->t[0]; // low 32 bits of offset
v[13] ^= ctx->t[1]; // high 32 bits
if (last) // last block flag set ?
v[14] = ~v[14];
for (i = 0; i < 16; i++) // get little-endian words
m[i] = U8TO32_LITTLE(&ctx->b[4 * i]);
for (i = 0; i < 10; i++) { // ten rounds
B2S_G( 0, 4, 8, 12, m[sigma[i][ 0]], m[sigma[i][ 1]]);
B2S_G( 1, 5, 9, 13, m[sigma[i][ 2]], m[sigma[i][ 3]]);
B2S_G( 2, 6, 10, 14, m[sigma[i][ 4]], m[sigma[i][ 5]]);
B2S_G( 3, 7, 11, 15, m[sigma[i][ 6]], m[sigma[i][ 7]]);
B2S_G( 0, 5, 10, 15, m[sigma[i][ 8]], m[sigma[i][ 9]]);
B2S_G( 1, 6, 11, 12, m[sigma[i][10]], m[sigma[i][11]]);
B2S_G( 2, 7, 8, 13, m[sigma[i][12]], m[sigma[i][13]]);
B2S_G( 3, 4, 9, 14, m[sigma[i][14]], m[sigma[i][15]]);
}
for( i = 0; i < 8; ++i )
ctx->h[i] ^= v[i] ^ v[i + 8];
}
// Initialize the hashing context "ctx" with optional key "key".
// 1 <= outlen <= 32 gives the digest size in bytes.
// Secret key (also <= 32 bytes) is optional (keylen = 0).
int blake2s_init(blake2s_ctx *ctx, size_t outlen,
const void *key, size_t keylen) // (keylen=0: no key)
{
size_t i;
if (outlen == 0 || outlen > 32 || keylen > 32)
return -1; // illegal parameters
for (i = 0; i < 8; i++) // state, "param block"
ctx->h[i] = blake2s_iv[i];
ctx->h[0] ^= 0x01010000 ^ (keylen << 8) ^ outlen;
ctx->t[0] = 0; // input count low word
ctx->t[1] = 0; // input count high word
ctx->c = 0; // pointer within buffer
ctx->outlen = outlen;
for (i = keylen; i < 64; i++) // zero input block
ctx->b[i] = 0;
if (keylen > 0) {
blake2s_update(ctx, key, keylen);
ctx->c = 64; // at the end
}
return 0;
}
// Add "inlen" bytes from "in" into the hash.
void blake2s_update(blake2s_ctx *ctx,
const void *in, size_t inlen) // data bytes
{
size_t i;
for (i = 0; i < inlen; i++) {
if (ctx->c == 64) { // buffer full ?
ctx->t[0] += ctx->c; // add counters
if (ctx->t[0] < ctx->c) // carry overflow ?
ctx->t[1]++; // high word
blake2s_compress(ctx, 0); // compress (not last)
ctx->c = 0; // counter to zero
}
// ctx->b[ctx->c++] = ((const uint8_t *) in)[i];
ctx->b[ctx->c++] = pgm_read_byte(&((const uint8_t *)in)[i]); // PROGMEM compatible
}
}
// Generate the message digest (size given in init).
// Result placed in "out".
void blake2s_final(blake2s_ctx *ctx, void *out)
{
size_t i;
ctx->t[0] += ctx->c; // mark last block offset
if (ctx->t[0] < ctx->c) // carry overflow
ctx->t[1]++; // high word
while (ctx->c < 64) // fill up with zeros
ctx->b[ctx->c++] = 0;
blake2s_compress(ctx, 1); // final block flag = 1
// little endian convert and store
for (i = 0; i < ctx->outlen; i++) {
((uint8_t *) out)[i] =
(ctx->h[i >> 2] >> (8 * (i & 3))) & 0xFF;
}
}
// Convenience function for all-in-one computation.
int blake2s(void *out, size_t outlen,
const void *key, size_t keylen,
const void *in, size_t inlen)
{
blake2s_ctx ctx;
if (blake2s_init(&ctx, outlen, key, keylen))
return -1;
blake2s_update(&ctx, in, inlen);
blake2s_final(&ctx, out);
return 0;
}

View File

@ -0,0 +1,47 @@
// Taken from RFC7693 - https://tools.ietf.org/html/rfc7693
// BLAKE2s Hashing Context and API Prototypes
#ifndef _BLAKE2S_H
#define _BLAKE2S_H
#ifdef __cplusplus
extern "C" {
#endif
#define BLAKE2S_BLOCK_SIZE 64
#include <stdint.h>
#include <stddef.h>
// state context
typedef struct {
uint8_t b[64]; // input buffer
uint32_t h[8]; // chained state
uint32_t t[2]; // total number of bytes
size_t c; // pointer for b[]
size_t outlen; // digest size
} blake2s_ctx;
// Initialize the hashing context "ctx" with optional key "key".
// 1 <= outlen <= 32 gives the digest size in bytes.
// Secret key (also <= 32 bytes) is optional (keylen = 0).
int blake2s_init(blake2s_ctx *ctx, size_t outlen,
const void *key, size_t keylen); // secret key
// Add "inlen" bytes from "in" into the hash.
void blake2s_update(blake2s_ctx *ctx, // context
const void *in, size_t inlen); // data to be hashed
// Generate the message digest (size given in init).
// Result placed in "out".
void blake2s_final(blake2s_ctx *ctx, void *out);
// All-in-one convenience function.
int blake2s(void *out, size_t outlen, // return buffer for digest
const void *key, size_t keylen, // optional secret key
const void *in, size_t inlen); // data to be hashed
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,202 @@
/*
* Copyright (c) 2021 Daniel Hope (www.floorsense.nz)
* 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 "Floorsense Ltd", "Agile Workspace Ltd" 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 OWNER 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.
*
* Author: Daniel Hope <daniel.hope@smartalock.com>
*/
// RFC7539 implementation of ChaCha20 with modified nonce size for WireGuard
// https://tools.ietf.org/html/rfc7539
// Adapted from https://cr.yp.to/streamciphers/timings/estreambench/submissions/salsa20/chacha8/ref/chacha.c by D. J. Bernstein (Public Domain)
// HChaCha20 is described here: https://tools.ietf.org/id/draft-arciszewski-xchacha-02.html
#include "chacha20.h"
#include <string.h>
#include <stdint.h>
#include "../../crypto.h"
// 2.3. The ChaCha20 Block Function
// The first four words (0-3) are constants: 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574
static const uint32_t CHACHA20_CONSTANT_1 = 0x61707865;
static const uint32_t CHACHA20_CONSTANT_2 = 0x3320646e;
static const uint32_t CHACHA20_CONSTANT_3 = 0x79622d32;
static const uint32_t CHACHA20_CONSTANT_4 = 0x6b206574;
#define ROTL32(v, n) (U32V((v) << (n)) | ((v) >> (32 - (n))))
#define PLUS(v,w) (U32V((v) + (w)))
#define PLUSONE(v) (PLUS((v),1))
// 2.1. The ChaCha Quarter Round
// 1. a += b; d ^= a; d <<<= 16;
// 2. c += d; b ^= c; b <<<= 12;
// 3. a += b; d ^= a; d <<<= 8;
// 4. c += d; b ^= c; b <<<= 7;
#define QUARTERROUND(a, b, c, d) \
a += b; d ^= a; d = ROTL32(d, 16); \
c += d; b ^= c; b = ROTL32(b, 12); \
a += b; d ^= a; d = ROTL32(d, 8); \
c += d; b ^= c; b = ROTL32(b, 7)
static inline void INNER_BLOCK(uint32_t *block) {
QUARTERROUND(block[0], block[4], block[ 8], block[12]); // column 0
QUARTERROUND(block[1], block[5], block[ 9], block[13]); // column 1
QUARTERROUND(block[2], block[6], block[10], block[14]); // column 2
QUARTERROUND(block[3], block[7], block[11], block[15]); // column 3
QUARTERROUND(block[0], block[5], block[10], block[15]); // diagonal 1
QUARTERROUND(block[1], block[6], block[11], block[12]); // diagonal 2
QUARTERROUND(block[2], block[7], block[ 8], block[13]); // diagonal 3
QUARTERROUND(block[3], block[4], block[ 9], block[14]); // diagonal 4
}
#define TWENTY_ROUNDS(x) ( \
INNER_BLOCK(x), \
INNER_BLOCK(x), \
INNER_BLOCK(x), \
INNER_BLOCK(x), \
INNER_BLOCK(x), \
INNER_BLOCK(x), \
INNER_BLOCK(x), \
INNER_BLOCK(x), \
INNER_BLOCK(x), \
INNER_BLOCK(x) \
)
// 2.3. The ChaCha20 Block Function
// chacha20_block(key, counter, nonce):
// state = constants | key | counter | nonce
// working_state = state
// for i=1 upto 10
// inner_block(working_state)
// end
// state += working_state
// return serialize(state)
// end
static void chacha20_block(struct chacha20_ctx *ctx, uint8_t *stream) {
uint32_t working_state[16];
int i;
for (i = 0; i < 16; ++i) {
working_state[i] = ctx->state[i];
}
TWENTY_ROUNDS(working_state);
for (i = 0; i < 16; ++i) {
U32TO8_LITTLE(stream + (4 * i), PLUS(working_state[i], ctx->state[i]));
}
}
void chacha20(struct chacha20_ctx *ctx, uint8_t *out, const uint8_t *in, uint32_t len) {
uint8_t output[CHACHA20_BLOCK_SIZE];
int i;
if (len) {
for (;;) {
chacha20_block(ctx, output);
// Word 12 is a block counter
ctx->state[12] = PLUSONE(ctx->state[12]);
if (len <= 64) {
for (i = 0;i < len;++i) {
out[i] = in[i] ^ output[i];
}
return;
}
for (i = 0;i < 64;++i) {
out[i] = in[i] ^ output[i];
}
len -= 64;
out += 64;
in += 64;
}
}
}
// 2.3. The ChaCha20 Block Function
// The first four words (0-3) are constants: 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574
// The next eight words (4-11) are taken from the 256-bit key by reading the bytes in little-endian order, in 4-byte chunks.
// Word 12 is a block counter. Since each block is 64-byte, a 32-bit word is enough for 256 gigabytes of data.
// Words 13-15 are a nonce, which should not be repeated for the same key.
// For wireguard: "nonce being composed of 32 bits of zeros followed by the 64-bit little-endian value of counter." where counter comes from the Wireguard layer and is separate from the block counter in word 12
void chacha20_init(struct chacha20_ctx *ctx, const uint8_t *key, const uint64_t nonce) {
ctx->state[0] = CHACHA20_CONSTANT_1;
ctx->state[1] = CHACHA20_CONSTANT_2;
ctx->state[2] = CHACHA20_CONSTANT_3;
ctx->state[3] = CHACHA20_CONSTANT_4;
ctx->state[4] = U8TO32_LITTLE(key + 0);
ctx->state[5] = U8TO32_LITTLE(key + 4);
ctx->state[6] = U8TO32_LITTLE(key + 8);
ctx->state[7] = U8TO32_LITTLE(key + 12);
ctx->state[8] = U8TO32_LITTLE(key + 16);
ctx->state[9] = U8TO32_LITTLE(key + 20);
ctx->state[10] = U8TO32_LITTLE(key + 24);
ctx->state[11] = U8TO32_LITTLE(key + 28);
ctx->state[12] = 0;
ctx->state[13] = 0;
ctx->state[14] = nonce & 0xFFFFFFFF;
ctx->state[15] = nonce >> 32;
}
// 2.2. HChaCha20
// HChaCha20 is initialized the same way as the ChaCha cipher, except that HChaCha20 uses a 128-bit nonce and has no counter.
// After initialization, proceed through the ChaCha rounds as usual.
// Once the 20 ChaCha rounds have been completed, the first 128 bits and last 128 bits of the ChaCha state (both little-endian) are concatenated, and this 256-bit subkey is returned.
void hchacha20(uint8_t *out, const uint8_t *nonce, const uint8_t *key) {
uint32_t state[16];
state[0] = CHACHA20_CONSTANT_1;
state[1] = CHACHA20_CONSTANT_2;
state[2] = CHACHA20_CONSTANT_3;
state[3] = CHACHA20_CONSTANT_4;
state[4] = U8TO32_LITTLE(key + 0);
state[5] = U8TO32_LITTLE(key + 4);
state[6] = U8TO32_LITTLE(key + 8);
state[7] = U8TO32_LITTLE(key + 12);
state[8] = U8TO32_LITTLE(key + 16);
state[9] = U8TO32_LITTLE(key + 20);
state[10] = U8TO32_LITTLE(key + 24);
state[11] = U8TO32_LITTLE(key + 28);
state[12] = U8TO32_LITTLE(nonce + 0);
state[13] = U8TO32_LITTLE(nonce + 4);
state[14] = U8TO32_LITTLE(nonce + 8);
state[15] = U8TO32_LITTLE(nonce + 12);
TWENTY_ROUNDS(state);
// Concatenate first/last 128 bits into 256bit output (as little endian)
U32TO8_LITTLE(out + 0, state[0]);
U32TO8_LITTLE(out + 4, state[1]);
U32TO8_LITTLE(out + 8, state[2]);
U32TO8_LITTLE(out + 12, state[3]);
U32TO8_LITTLE(out + 16, state[12]);
U32TO8_LITTLE(out + 20, state[13]);
U32TO8_LITTLE(out + 24, state[14]);
U32TO8_LITTLE(out + 28, state[15]);
}

View File

@ -0,0 +1,61 @@
/*
* Copyright (c) 2021 Daniel Hope (www.floorsense.nz)
* 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 "Floorsense Ltd", "Agile Workspace Ltd" 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 OWNER 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.
*
* Author: Daniel Hope <daniel.hope@smartalock.com>
*/
// RFC7539 implementation of ChaCha20 with modified nonce size for WireGuard
// https://tools.ietf.org/html/rfc7539
// Adapted from https://cr.yp.to/streamciphers/timings/estreambench/submissions/salsa20/chacha8/ref/chacha.c by D. J. Bernstein (Public Domain)
// HChaCha20 is described here: https://tools.ietf.org/id/draft-arciszewski-xchacha-02.html
#ifndef _CHACHA20_H_
#define _CHACHA20_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#define CHACHA20_BLOCK_SIZE (64)
#define CHACHA20_KEY_SIZE (32)
struct chacha20_ctx {
uint32_t state[16];
};
void chacha20_init(struct chacha20_ctx *ctx, const uint8_t *key, const uint64_t nonce);
void chacha20(struct chacha20_ctx *ctx, uint8_t *out, const uint8_t *in, uint32_t len);
void hchacha20(uint8_t *out, const uint8_t *nonce, const uint8_t *key);
#ifdef __cplusplus
}
#endif
#endif /* _CHACHA20_H_ */

View File

@ -0,0 +1,193 @@
/*
* Copyright (c) 2021 Daniel Hope (www.floorsense.nz)
* 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 "Floorsense Ltd", "Agile Workspace Ltd" 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 OWNER 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.
*
* Author: Daniel Hope <daniel.hope@smartalock.com>
*/
// AEAD_CHACHA20_POLY1305 as described in https://tools.ietf.org/html/rfc7539
// AEAD_XChaCha20_Poly1305 as described in https://tools.ietf.org/id/draft-arciszewski-xchacha-02.html
#include "chacha20poly1305.h"
#include "chacha20.h"
#include "poly1305-donna.h"
#include <stdlib.h>
#include <stdint.h>
#include "../../crypto.h"
#define POLY1305_KEY_SIZE 32
#define POLY1305_MAC_SIZE 16
static const uint8_t zero[CHACHA20_BLOCK_SIZE] = { 0 };
// 2.6. Generating the Poly1305 Key Using ChaCha20
static void generate_poly1305_key(struct poly1305_context *poly1305_state, struct chacha20_ctx *chacha20_state, const uint8_t *key, uint64_t nonce) {
uint8_t block[POLY1305_KEY_SIZE] = {0};
// The method is to call the block function with the following parameters:
// - The 256-bit session integrity key is used as the ChaCha20 key.
// - The block counter is set to zero.
// - The protocol will specify a 96-bit or 64-bit nonce
chacha20_init(chacha20_state, key, nonce);
// We take the first 256 bits or the serialized state, and use those as the one-time Poly1305 key
chacha20(chacha20_state, block, block, sizeof(block));
poly1305_init(poly1305_state, block);
crypto_zero(&block, sizeof(block));
}
// 2.8. AEAD Construction (Encryption)
void chacha20poly1305_encrypt(uint8_t *dst, const uint8_t *src, size_t src_len, const uint8_t *ad, size_t ad_len, uint64_t nonce, const uint8_t *key) {
struct poly1305_context poly1305_state;
struct chacha20_ctx chacha20_state;
uint8_t block[8];
size_t padded_len;
// First, a Poly1305 one-time key is generated from the 256-bit key and nonce using the procedure described in Section 2.6.
generate_poly1305_key(&poly1305_state, &chacha20_state, key, nonce);
// Next, the ChaCha20 encryption function is called to encrypt the plaintext, using the same key and nonce, and with the initial counter set to 1.
chacha20(&chacha20_state, dst, src, src_len);
// Finally, the Poly1305 function is called with the Poly1305 key calculated above, and a message constructed as a concatenation of the following:
// - The AAD
poly1305_update(&poly1305_state, ad, ad_len);
// - padding1 -- the padding is up to 15 zero bytes, and it brings the total length so far to an integral multiple of 16
padded_len = (ad_len + 15) & 0xFFFFFFF0; // Round up to next 16 bytes
poly1305_update(&poly1305_state, zero, padded_len - ad_len);
// - The ciphertext
poly1305_update(&poly1305_state, dst, src_len);
// - padding2 -- the padding is up to 15 zero bytes, and it brings the total length so far to an integral multiple of 16.
padded_len = (src_len + 15) & 0xFFFFFFF0; // Round up to next 16 bytes
poly1305_update(&poly1305_state, zero, padded_len - src_len);
// - The length of the additional data in octets (as a 64-bit little-endian integer)
U64TO8_LITTLE(block, (uint64_t)ad_len);
poly1305_update(&poly1305_state, block, sizeof(block));
// - The length of the ciphertext in octets (as a 64-bit little-endian integer).
U64TO8_LITTLE(block, (uint64_t)src_len);
poly1305_update(&poly1305_state, block, sizeof(block));
// The output from the AEAD is twofold:
// - A ciphertext of the same length as the plaintext. (above, output of chacha20 into dst)
// - A 128-bit tag, which is the output of the Poly1305 function. (append to dst)
poly1305_finish(&poly1305_state, dst + src_len);
// Make sure we leave nothing sensitive on the stack
crypto_zero(&chacha20_state, sizeof(chacha20_state));
crypto_zero(&block, sizeof(block));
}
// 2.8. AEAD Construction (Decryption)
bool chacha20poly1305_decrypt(uint8_t *dst, const uint8_t *src, size_t src_len, const uint8_t *ad, size_t ad_len, uint64_t nonce, const uint8_t *key) {
struct poly1305_context poly1305_state;
struct chacha20_ctx chacha20_state;
uint8_t block[8];
uint8_t mac[POLY1305_MAC_SIZE];
size_t padded_len;
int dst_len;
bool result = false;
// Decryption is similar [to encryption] with the following differences:
// - The roles of ciphertext and plaintext are reversed, so the ChaCha20 encryption function is applied to the ciphertext, producing the plaintext.
// - The Poly1305 function is still run on the AAD and the ciphertext, not the plaintext.
// - The calculated tag is bitwise compared to the received tag. The message is authenticated if and only if the tags match.
if (src_len >= POLY1305_MAC_SIZE) {
dst_len = src_len - POLY1305_MAC_SIZE;
// First, a Poly1305 one-time key is generated from the 256-bit key and nonce using the procedure described in Section 2.6.
generate_poly1305_key(&poly1305_state, &chacha20_state, key, nonce);
// Calculate the MAC before attempting decryption
// the Poly1305 function is called with the Poly1305 key calculated above, and a message constructed as a concatenation of the following:
// - The AAD
poly1305_update(&poly1305_state, ad, ad_len);
// - padding1 -- the padding is up to 15 zero bytes, and it brings the total length so far to an integral multiple of 16
padded_len = (ad_len + 15) & 0xFFFFFFF0; // Round up to next 16 bytes
poly1305_update(&poly1305_state, zero, padded_len - ad_len);
// - The ciphertext (note the Poly1305 function is still run on the AAD and the ciphertext, not the plaintext)
poly1305_update(&poly1305_state, src, dst_len);
// - padding2 -- the padding is up to 15 zero bytes, and it brings the total length so far to an integral multiple of 16.
padded_len = (dst_len + 15) & 0xFFFFFFF0; // Round up to next 16 bytes
poly1305_update(&poly1305_state, zero, padded_len - dst_len);
// - The length of the additional data in octets (as a 64-bit little-endian integer)
U64TO8_LITTLE(block, (uint64_t)ad_len);
poly1305_update(&poly1305_state, block, sizeof(block));
// - The length of the ciphertext in octets (as a 64-bit little-endian integer).
U64TO8_LITTLE(block, (uint64_t)dst_len);
poly1305_update(&poly1305_state, block, sizeof(block));
// The output from the AEAD is twofold:
// - A plaintext of the same length as the ciphertext. (below, output of chacha20 into dst)
// - A 128-bit tag, which is the output of the Poly1305 function. (into mac for checking against passed mac)
poly1305_finish(&poly1305_state, mac);
if (crypto_equal(mac, src + dst_len, POLY1305_MAC_SIZE)) {
// mac is correct - do the decryption
// Next, the ChaCha20 encryption function is called to decrypt the ciphertext, using the same key and nonce, and with the initial counter set to 1.
chacha20(&chacha20_state, dst, src, dst_len);
result = true;
}
}
return result;
}
// AEAD_XChaCha20_Poly1305
// XChaCha20-Poly1305 is a variant of the ChaCha20-Poly1305 AEAD construction as defined in [RFC7539] that uses a 192-bit nonce instead of a 96-bit nonce.
// The algorithm for XChaCha20-Poly1305 is as follows:
// 1. Calculate a subkey from the first 16 bytes of the nonce and the key, using HChaCha20 (Section 2.2).
// 2. Use the subkey and remaining 8 bytes of the nonce (prefixed with 4 NUL bytes) with AEAD_CHACHA20_POLY1305 from [RFC7539] as normal. The definition for XChaCha20 is given in Section 2.3.
void xchacha20poly1305_encrypt(uint8_t *dst, const uint8_t *src, size_t src_len, const uint8_t *ad, size_t ad_len, const uint8_t *nonce, const uint8_t *key) {
uint8_t subkey[CHACHA20_KEY_SIZE];
uint64_t new_nonce;
new_nonce = U8TO64_LITTLE(nonce + 16);
hchacha20(subkey, nonce, key);
chacha20poly1305_encrypt(dst, src, src_len, ad, ad_len, new_nonce, subkey);
crypto_zero(subkey, sizeof(subkey));
}
bool xchacha20poly1305_decrypt(uint8_t *dst, const uint8_t *src, size_t src_len, const uint8_t *ad, size_t ad_len, const uint8_t *nonce, const uint8_t *key) {
uint8_t subkey[CHACHA20_KEY_SIZE];
uint64_t new_nonce;
bool result;
new_nonce = U8TO64_LITTLE(nonce + 16);
hchacha20(subkey, nonce, key);
result = chacha20poly1305_decrypt(dst, src, src_len, ad, ad_len, new_nonce, subkey);
crypto_zero(subkey, sizeof(subkey));
return result;
}

View File

@ -0,0 +1,58 @@
/*
* Copyright (c) 2021 Daniel Hope (www.floorsense.nz)
* 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 "Floorsense Ltd", "Agile Workspace Ltd" 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 OWNER 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.
*
* Author: Daniel Hope <daniel.hope@smartalock.com>
*/
#ifndef _CHACHA20POLY1305_H_
#define _CHACHA20POLY1305_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>
// Aead(key, counter, plain text, auth text) ChaCha20Poly1305 AEAD, as specified in RFC7539 [17], with its nonce being composed of 32 bits of zeros followed by the 64-bit little-endian value of counter.
// AEAD_CHACHA20_POLY1305 as described in https://tools.ietf.org/html/rfc7539
void chacha20poly1305_encrypt(uint8_t *dst, const uint8_t *src, size_t src_len, const uint8_t *ad, size_t ad_len, uint64_t nonce, const uint8_t *key);
bool chacha20poly1305_decrypt(uint8_t *dst, const uint8_t *src, size_t src_len, const uint8_t *ad, size_t ad_len, uint64_t nonce, const uint8_t *key);
// Xaead(key, nonce, plain text, auth text) XChaCha20Poly1305 AEAD, with a 24-byte random nonce, instantiated using HChaCha20 [6] and ChaCha20Poly1305.
// AEAD_XChaCha20_Poly1305 as described in https://tools.ietf.org/id/draft-arciszewski-xchacha-02.html
void xchacha20poly1305_encrypt(uint8_t *dst, const uint8_t *src, size_t src_len, const uint8_t *ad, size_t ad_len, const uint8_t *nonce, const uint8_t *key);
bool xchacha20poly1305_decrypt(uint8_t *dst, const uint8_t *src, size_t src_len, const uint8_t *ad, size_t ad_len, const uint8_t *nonce, const uint8_t *key);
#ifdef __cplusplus
}
#endif
#endif /* _CHACHA20POLY1305_H_ */

View File

@ -0,0 +1,203 @@
/*
poly1305 implementation using 16 bit * 16 bit = 32 bit multiplication and 32 bit addition
*/
#pragma GCC optimize ("Os")
#if defined(_MSC_VER)
#define POLY1305_NOINLINE __declspec(noinline)
#elif defined(__GNUC__)
#define POLY1305_NOINLINE __attribute__((noinline))
#else
#define POLY1305_NOINLINE
#endif
#define poly1305_block_size 16
/* 17 + sizeof(size_t) + 18*sizeof(unsigned short) */
typedef struct poly1305_state_internal_t {
unsigned char buffer[poly1305_block_size];
size_t leftover;
unsigned short r[10];
unsigned short h[10];
unsigned short pad[8];
unsigned char final;
} poly1305_state_internal_t;
/* interpret two 8 bit unsigned integers as a 16 bit unsigned integer in little endian */
static unsigned short
U8TO16(const unsigned char *p) {
return
(((unsigned short)(p[0] & 0xff) ) |
((unsigned short)(p[1] & 0xff) << 8));
}
/* store a 16 bit unsigned integer as two 8 bit unsigned integers in little endian */
static void
U16TO8(unsigned char *p, unsigned short v) {
p[0] = (v ) & 0xff;
p[1] = (v >> 8) & 0xff;
}
void
poly1305_init(poly1305_context *ctx, const unsigned char key[32]) {
poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx;
unsigned short t0,t1,t2,t3,t4,t5,t6,t7;
size_t i;
/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
t0 = U8TO16(&key[ 0]); st->r[0] = ( t0 ) & 0x1fff;
t1 = U8TO16(&key[ 2]); st->r[1] = ((t0 >> 13) | (t1 << 3)) & 0x1fff;
t2 = U8TO16(&key[ 4]); st->r[2] = ((t1 >> 10) | (t2 << 6)) & 0x1f03;
t3 = U8TO16(&key[ 6]); st->r[3] = ((t2 >> 7) | (t3 << 9)) & 0x1fff;
t4 = U8TO16(&key[ 8]); st->r[4] = ((t3 >> 4) | (t4 << 12)) & 0x00ff;
st->r[5] = ((t4 >> 1) ) & 0x1ffe;
t5 = U8TO16(&key[10]); st->r[6] = ((t4 >> 14) | (t5 << 2)) & 0x1fff;
t6 = U8TO16(&key[12]); st->r[7] = ((t5 >> 11) | (t6 << 5)) & 0x1f81;
t7 = U8TO16(&key[14]); st->r[8] = ((t6 >> 8) | (t7 << 8)) & 0x1fff;
st->r[9] = ((t7 >> 5) ) & 0x007f;
/* h = 0 */
for (i = 0; i < 10; i++)
st->h[i] = 0;
/* save pad for later */
for (i = 0; i < 8; i++)
st->pad[i] = U8TO16(&key[16 + (2 * i)]);
st->leftover = 0;
st->final = 0;
}
static void
poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, size_t bytes) {
const unsigned short hibit = (st->final) ? 0 : (1 << 11); /* 1 << 128 */
unsigned short t0,t1,t2,t3,t4,t5,t6,t7;
unsigned long d[10];
unsigned long c;
while (bytes >= poly1305_block_size) {
size_t i, j;
/* h += m[i] */
t0 = U8TO16(&m[ 0]); st->h[0] += ( t0 ) & 0x1fff;
t1 = U8TO16(&m[ 2]); st->h[1] += ((t0 >> 13) | (t1 << 3)) & 0x1fff;
t2 = U8TO16(&m[ 4]); st->h[2] += ((t1 >> 10) | (t2 << 6)) & 0x1fff;
t3 = U8TO16(&m[ 6]); st->h[3] += ((t2 >> 7) | (t3 << 9)) & 0x1fff;
t4 = U8TO16(&m[ 8]); st->h[4] += ((t3 >> 4) | (t4 << 12)) & 0x1fff;
st->h[5] += ((t4 >> 1) ) & 0x1fff;
t5 = U8TO16(&m[10]); st->h[6] += ((t4 >> 14) | (t5 << 2)) & 0x1fff;
t6 = U8TO16(&m[12]); st->h[7] += ((t5 >> 11) | (t6 << 5)) & 0x1fff;
t7 = U8TO16(&m[14]); st->h[8] += ((t6 >> 8) | (t7 << 8)) & 0x1fff;
st->h[9] += ((t7 >> 5) ) | hibit;
/* h *= r, (partial) h %= p */
for (i = 0, c = 0; i < 10; i++) {
d[i] = c;
for (j = 0; j < 10; j++) {
d[i] += (unsigned long)st->h[j] * ((j <= i) ? st->r[i - j] : (5 * st->r[i + 10 - j]));
/* Sum(h[i] * r[i] * 5) will overflow slightly above 6 products with an unclamped r, so carry at 5 */
if (j == 4) {
c = (d[i] >> 13);
d[i] &= 0x1fff;
}
}
c += (d[i] >> 13);
d[i] &= 0x1fff;
}
c = ((c << 2) + c); /* c *= 5 */
c += d[0];
d[0] = ((unsigned short)c & 0x1fff);
c = (c >> 13);
d[1] += c;
for (i = 0; i < 10; i++)
st->h[i] = (unsigned short)d[i];
m += poly1305_block_size;
bytes -= poly1305_block_size;
}
}
POLY1305_NOINLINE void
poly1305_finish(poly1305_context *ctx, unsigned char mac[16]) {
poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx;
unsigned short c;
unsigned short g[10];
unsigned short mask;
unsigned long f;
size_t i;
/* process the remaining block */
if (st->leftover) {
size_t i = st->leftover;
st->buffer[i++] = 1;
for (; i < poly1305_block_size; i++)
st->buffer[i] = 0;
st->final = 1;
poly1305_blocks(st, st->buffer, poly1305_block_size);
}
/* fully carry h */
c = st->h[1] >> 13;
st->h[1] &= 0x1fff;
for (i = 2; i < 10; i++) {
st->h[i] += c;
c = st->h[i] >> 13;
st->h[i] &= 0x1fff;
}
st->h[0] += (c * 5);
c = st->h[0] >> 13;
st->h[0] &= 0x1fff;
st->h[1] += c;
c = st->h[1] >> 13;
st->h[1] &= 0x1fff;
st->h[2] += c;
/* compute h + -p */
g[0] = st->h[0] + 5;
c = g[0] >> 13;
g[0] &= 0x1fff;
for (i = 1; i < 10; i++) {
g[i] = st->h[i] + c;
c = g[i] >> 13;
g[i] &= 0x1fff;
}
/* select h if h < p, or h + -p if h >= p */
mask = (c ^ 1) - 1;
for (i = 0; i < 10; i++)
g[i] &= mask;
mask = ~mask;
for (i = 0; i < 10; i++)
st->h[i] = (st->h[i] & mask) | g[i];
/* h = h % (2^128) */
st->h[0] = ((st->h[0] ) | (st->h[1] << 13) ) & 0xffff;
st->h[1] = ((st->h[1] >> 3) | (st->h[2] << 10) ) & 0xffff;
st->h[2] = ((st->h[2] >> 6) | (st->h[3] << 7) ) & 0xffff;
st->h[3] = ((st->h[3] >> 9) | (st->h[4] << 4) ) & 0xffff;
st->h[4] = ((st->h[4] >> 12) | (st->h[5] << 1) | (st->h[6] << 14)) & 0xffff;
st->h[5] = ((st->h[6] >> 2) | (st->h[7] << 11) ) & 0xffff;
st->h[6] = ((st->h[7] >> 5) | (st->h[8] << 8) ) & 0xffff;
st->h[7] = ((st->h[8] >> 8) | (st->h[9] << 5) ) & 0xffff;
/* mac = (h + pad) % (2^128) */
f = (unsigned long)st->h[0] + st->pad[0];
st->h[0] = (unsigned short)f;
for (i = 1; i < 8; i++) {
f = (unsigned long)st->h[i] + st->pad[i] + (f >> 16);
st->h[i] = (unsigned short)f;
}
for (i = 0; i < 8; i++)
U16TO8(mac + (i * 2), st->h[i]);
/* zero out the state */
for (i = 0; i < 10; i++)
st->h[i] = 0;
for (i = 0; i < 10; i++)
st->r[i] = 0;
for (i = 0; i < 8; i++)
st->pad[i] = 0;
}

View File

@ -0,0 +1,227 @@
// Taken from https://github.com/floodyberry/poly1305-donna - public domain or MIT
/*
poly1305 implementation using 32 bit * 32 bit = 64 bit multiplication and 64 bit addition
*/
#ifdef __cplusplus
extern "C" {
#endif
#if defined(_MSC_VER)
#define POLY1305_NOINLINE __declspec(noinline)
#elif defined(__GNUC__)
#define POLY1305_NOINLINE __attribute__((noinline))
#else
#define POLY1305_NOINLINE
#endif
#define poly1305_block_size 16
/* 17 + sizeof(size_t) + 14*sizeof(unsigned long) */
typedef struct poly1305_state_internal_t {
unsigned long r[5];
unsigned long h[5];
unsigned long pad[4];
size_t leftover;
unsigned char buffer[poly1305_block_size];
unsigned char final;
} poly1305_state_internal_t;
/* interpret four 8 bit unsigned integers as a 32 bit unsigned integer in little endian */
static unsigned long
U8TO32(const unsigned char *p) {
return
(((unsigned long)(p[0] & 0xff) ) |
((unsigned long)(p[1] & 0xff) << 8) |
((unsigned long)(p[2] & 0xff) << 16) |
((unsigned long)(p[3] & 0xff) << 24));
}
/* store a 32 bit unsigned integer as four 8 bit unsigned integers in little endian */
static void
U32TO8(unsigned char *p, unsigned long v) {
p[0] = (v ) & 0xff;
p[1] = (v >> 8) & 0xff;
p[2] = (v >> 16) & 0xff;
p[3] = (v >> 24) & 0xff;
}
void
poly1305_init(poly1305_context *ctx, const unsigned char key[32]) {
poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx;
/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
st->r[0] = (U8TO32(&key[ 0]) ) & 0x3ffffff;
st->r[1] = (U8TO32(&key[ 3]) >> 2) & 0x3ffff03;
st->r[2] = (U8TO32(&key[ 6]) >> 4) & 0x3ffc0ff;
st->r[3] = (U8TO32(&key[ 9]) >> 6) & 0x3f03fff;
st->r[4] = (U8TO32(&key[12]) >> 8) & 0x00fffff;
/* h = 0 */
st->h[0] = 0;
st->h[1] = 0;
st->h[2] = 0;
st->h[3] = 0;
st->h[4] = 0;
/* save pad for later */
st->pad[0] = U8TO32(&key[16]);
st->pad[1] = U8TO32(&key[20]);
st->pad[2] = U8TO32(&key[24]);
st->pad[3] = U8TO32(&key[28]);
st->leftover = 0;
st->final = 0;
}
static void
poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, size_t bytes) {
const unsigned long hibit = (st->final) ? 0 : (1UL << 24); /* 1 << 128 */
unsigned long r0,r1,r2,r3,r4;
unsigned long s1,s2,s3,s4;
unsigned long h0,h1,h2,h3,h4;
unsigned long long d0,d1,d2,d3,d4;
unsigned long c;
r0 = st->r[0];
r1 = st->r[1];
r2 = st->r[2];
r3 = st->r[3];
r4 = st->r[4];
s1 = r1 * 5;
s2 = r2 * 5;
s3 = r3 * 5;
s4 = r4 * 5;
h0 = st->h[0];
h1 = st->h[1];
h2 = st->h[2];
h3 = st->h[3];
h4 = st->h[4];
while (bytes >= poly1305_block_size) {
/* h += m[i] */
h0 += (U8TO32(m+ 0) ) & 0x3ffffff;
h1 += (U8TO32(m+ 3) >> 2) & 0x3ffffff;
h2 += (U8TO32(m+ 6) >> 4) & 0x3ffffff;
h3 += (U8TO32(m+ 9) >> 6) & 0x3ffffff;
h4 += (U8TO32(m+12) >> 8) | hibit;
/* h *= r */
d0 = ((unsigned long long)h0 * r0) + ((unsigned long long)h1 * s4) + ((unsigned long long)h2 * s3) + ((unsigned long long)h3 * s2) + ((unsigned long long)h4 * s1);
d1 = ((unsigned long long)h0 * r1) + ((unsigned long long)h1 * r0) + ((unsigned long long)h2 * s4) + ((unsigned long long)h3 * s3) + ((unsigned long long)h4 * s2);
d2 = ((unsigned long long)h0 * r2) + ((unsigned long long)h1 * r1) + ((unsigned long long)h2 * r0) + ((unsigned long long)h3 * s4) + ((unsigned long long)h4 * s3);
d3 = ((unsigned long long)h0 * r3) + ((unsigned long long)h1 * r2) + ((unsigned long long)h2 * r1) + ((unsigned long long)h3 * r0) + ((unsigned long long)h4 * s4);
d4 = ((unsigned long long)h0 * r4) + ((unsigned long long)h1 * r3) + ((unsigned long long)h2 * r2) + ((unsigned long long)h3 * r1) + ((unsigned long long)h4 * r0);
/* (partial) h %= p */
c = (unsigned long)(d0 >> 26); h0 = (unsigned long)d0 & 0x3ffffff;
d1 += c; c = (unsigned long)(d1 >> 26); h1 = (unsigned long)d1 & 0x3ffffff;
d2 += c; c = (unsigned long)(d2 >> 26); h2 = (unsigned long)d2 & 0x3ffffff;
d3 += c; c = (unsigned long)(d3 >> 26); h3 = (unsigned long)d3 & 0x3ffffff;
d4 += c; c = (unsigned long)(d4 >> 26); h4 = (unsigned long)d4 & 0x3ffffff;
h0 += c * 5; c = (h0 >> 26); h0 = h0 & 0x3ffffff;
h1 += c;
m += poly1305_block_size;
bytes -= poly1305_block_size;
}
st->h[0] = h0;
st->h[1] = h1;
st->h[2] = h2;
st->h[3] = h3;
st->h[4] = h4;
}
POLY1305_NOINLINE void
poly1305_finish(poly1305_context *ctx, unsigned char mac[16]) {
poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx;
unsigned long h0,h1,h2,h3,h4,c;
unsigned long g0,g1,g2,g3,g4;
unsigned long long f;
unsigned long mask;
/* process the remaining block */
if (st->leftover) {
size_t i = st->leftover;
st->buffer[i++] = 1;
for (; i < poly1305_block_size; i++)
st->buffer[i] = 0;
st->final = 1;
poly1305_blocks(st, st->buffer, poly1305_block_size);
}
/* fully carry h */
h0 = st->h[0];
h1 = st->h[1];
h2 = st->h[2];
h3 = st->h[3];
h4 = st->h[4];
c = h1 >> 26; h1 = h1 & 0x3ffffff;
h2 += c; c = h2 >> 26; h2 = h2 & 0x3ffffff;
h3 += c; c = h3 >> 26; h3 = h3 & 0x3ffffff;
h4 += c; c = h4 >> 26; h4 = h4 & 0x3ffffff;
h0 += c * 5; c = h0 >> 26; h0 = h0 & 0x3ffffff;
h1 += c;
/* compute h + -p */
g0 = h0 + 5; c = g0 >> 26; g0 &= 0x3ffffff;
g1 = h1 + c; c = g1 >> 26; g1 &= 0x3ffffff;
g2 = h2 + c; c = g2 >> 26; g2 &= 0x3ffffff;
g3 = h3 + c; c = g3 >> 26; g3 &= 0x3ffffff;
g4 = h4 + c - (1UL << 26);
/* select h if h < p, or h + -p if h >= p */
mask = (g4 >> ((sizeof(unsigned long) * 8) - 1)) - 1;
g0 &= mask;
g1 &= mask;
g2 &= mask;
g3 &= mask;
g4 &= mask;
mask = ~mask;
h0 = (h0 & mask) | g0;
h1 = (h1 & mask) | g1;
h2 = (h2 & mask) | g2;
h3 = (h3 & mask) | g3;
h4 = (h4 & mask) | g4;
/* h = h % (2^128) */
h0 = ((h0 ) | (h1 << 26)) & 0xffffffff;
h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff;
h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff;
h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff;
/* mac = (h + pad) % (2^128) */
f = (unsigned long long)h0 + st->pad[0] ; h0 = (unsigned long)f;
f = (unsigned long long)h1 + st->pad[1] + (f >> 32); h1 = (unsigned long)f;
f = (unsigned long long)h2 + st->pad[2] + (f >> 32); h2 = (unsigned long)f;
f = (unsigned long long)h3 + st->pad[3] + (f >> 32); h3 = (unsigned long)f;
U32TO8(mac + 0, h0);
U32TO8(mac + 4, h1);
U32TO8(mac + 8, h2);
U32TO8(mac + 12, h3);
/* zero out the state */
st->h[0] = 0;
st->h[1] = 0;
st->h[2] = 0;
st->h[3] = 0;
st->h[4] = 0;
st->r[0] = 0;
st->r[1] = 0;
st->r[2] = 0;
st->r[3] = 0;
st->r[4] = 0;
st->pad[0] = 0;
st->pad[1] = 0;
st->pad[2] = 0;
st->pad[3] = 0;
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,42 @@
// Taken from https://github.com/floodyberry/poly1305-donna - public domain or MIT
#include "poly1305-donna.h"
#include "poly1305-donna-16.h"
// #include "poly1305-donna-32.h"
void
poly1305_update(poly1305_context *ctx, const unsigned char *m, size_t bytes) {
poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx;
size_t i;
/* handle leftover */
if (st->leftover) {
size_t want = (poly1305_block_size - st->leftover);
if (want > bytes)
want = bytes;
for (i = 0; i < want; i++)
st->buffer[st->leftover + i] = m[i];
bytes -= want;
m += want;
st->leftover += want;
if (st->leftover < poly1305_block_size)
return;
poly1305_blocks(st, st->buffer, poly1305_block_size);
st->leftover = 0;
}
/* process full blocks */
if (bytes >= poly1305_block_size) {
size_t want = (bytes & ~(poly1305_block_size - 1));
poly1305_blocks(st, m, want);
m += want;
bytes -= want;
}
/* store leftover */
if (bytes) {
for (i = 0; i < bytes; i++)
st->buffer[st->leftover + i] = m[i];
st->leftover += bytes;
}
}

View File

@ -0,0 +1,24 @@
// Taken from https://github.com/floodyberry/poly1305-donna - public domain or MIT
#ifndef POLY1305_DONNA_H
#define POLY1305_DONNA_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h>
typedef struct poly1305_context {
size_t aligner;
unsigned char opaque[136];
} poly1305_context;
void poly1305_init(poly1305_context *ctx, const unsigned char key[32]);
void poly1305_update(poly1305_context *ctx, const unsigned char *m, size_t bytes);
void poly1305_finish(poly1305_context *ctx, unsigned char mac[16]);
#ifdef __cplusplus
}
#endif
#endif /* POLY1305_DONNA_H */

View File

@ -0,0 +1,259 @@
/*
* Copyright (c) 2022 Tomoyuki Sakurai <y@trombik.org>
* Copyright (c) 2023-2024 Simone Rossetto <simros85@gmail.com>
* Copyright (c) 2025 Stephan Hadinger
* 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 "Floorsense Ltd", "Agile Workspace Ltd" 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 OWNER 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 <Arduino.h>
#include "esp_wireguard.h"
#include "WiFiHelper.h"
#include "lwip/ip.h"
#include "lwip/ip_addr.h"
#include "lwip/netdb.h"
#include "lwip/dns.h"
#include "lwip/err.h"
#include "wireguard-platform.h"
#include "wireguardif.h"
//**************************************************************************************************************
// enable AddLog support within a C++ library
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};
//**************************************************************************************************************
#if defined(CONFIG_LWIP_IPV6)
#define WG_ADDRSTRLEN INET6_ADDRSTRLEN
#else
#define WG_ADDRSTRLEN INET_ADDRSTRLEN
#endif
static struct netif wg_netif_struct = {0};
static struct netif *wg_netif = NULL;
static wireguardif_peer_t peer = {0};
static uint8_t wireguard_peer_index = WIREGUARDIF_INVALID_INDEX;
static esp_err_t esp_wireguard_peer_init(const wireguard_config_t *config, wireguardif_peer_t *peer)
{
if (!config || !peer) { return ESP_ERR_INVALID_ARG; }
if (ip_addr_isany(&(config->endpoint_ip))) {
AddLog(LOG_LEVEL_INFO, PSTR("WG : peer_init: invalid endpoint ip: `%s`"), ipaddr_ntoa(&(config->endpoint_ip)));
return ESP_ERR_INVALID_ARG;
}
ip_addr_copy(peer->endpoint_ip, config->endpoint_ip);
memmove(peer->public_key2, config->public_key2, WG_KEY_LEN);
memmove(peer->preshared_key2, config->preshared_key2, WG_KEY_LEN);
peer->keep_alive = config->persistent_keepalive;
/* Allow device's own address through tunnel */
peer->allowed_ip = config->address2;
peer->allowed_mask = config->subnet;
AddLog(LOG_LEVEL_DEBUG, PSTR("WG : Default allowed_ips %s/%s"), IPAddress(&peer->allowed_ip).toString().c_str(),
IPAddress(&peer->allowed_mask).toString().c_str());
peer->endport_port = config->port;
peer->keep_alive = config->persistent_keepalive;
return ESP_OK;
}
static esp_err_t esp_wireguard_netif_create(const wireguard_config_t *config)
{
esp_err_t err;
ip_addr_t gateway = IPADDR4_INIT_BYTES(0, 0, 0, 0);
struct wireguardif_init_data wg = {0};
if (!config) { return ESP_ERR_INVALID_ARG;}
/* Setup the WireGuard device structure */
memmove(wg.private_key2, config->private_key2, WG_KEY_LEN);
wg.listen_port = config->listen_port;
wg.bind_netif = NULL;
/* Register the new WireGuard network interface with lwIP */
// AddLog(LOG_LEVEL_DEBUG, "WG : Creating netif addr %_I mask %_I gateway %_I",
// config->address2.u_addr.ip4.addr, config->netmask2.u_addr.ip4.addr, gateway.u_addr.ip4.addr);
wg_netif = netif_add(
&wg_netif_struct,
ip_2_ip4(&config->address2),
ip_2_ip4(&config->netmask2),
ip_2_ip4(&gateway),
&wg, &wireguardif_init,
&ip_input);
if (wg_netif == NULL) {
AddLog(LOG_LEVEL_INFO, PSTR("WG : netif_add: failed"));
return ESP_FAIL;
}
/* Mark the interface as administratively up, link up flag is set
* automatically when peer connects */
netif_set_up(wg_netif);
return ESP_OK;
}
esp_err_t esp_wireguard_init(wireguard_config_t *config, wireguard_ctx_t *ctx)
{
if (!config || !ctx) { return ESP_ERR_INVALID_ARG; }
ctx->config = config;
ctx->netif = NULL;
return ESP_OK;
}
esp_err_t esp_wireguard_connect(wireguard_ctx_t *ctx)
{
esp_err_t err = ESP_FAIL;
err_t lwip_err = -1;
IPAddress remote_addr;
if (!ctx) {
err = ESP_ERR_INVALID_ARG;
goto fail;
}
if (ctx->netif == NULL) {
err = esp_wireguard_netif_create(ctx->config);
if (err != ESP_OK) {
AddLog(LOG_LEVEL_INFO, PSTR("WG : netif_create err %d"), err);
goto fail;
}
ctx->netif = wg_netif;
// ctx->netif_default = netif_default;
}
// Add include "ESP8266WiFi.h" for this to work
if (!WiFiHelper::hostByName(ctx->config->endpoint, remote_addr)) {
AddLog(LOG_LEVEL_INFO, PSTR("WG : hostByName failed '%s'"), ctx->config->endpoint);
goto fail;
}
#ifdef ESP32
remote_addr.to_ip_addr_t(&ctx->config->endpoint_ip);
#else
ctx->config->endpoint_ip = remote_addr;
#endif
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("WG : hostByName '%s' resolved to %s"), ctx->config->endpoint, remote_addr.toString().c_str());
/* Initialize the first WireGuard peer structure */
err = esp_wireguard_peer_init(ctx->config, &peer);
if (err != ESP_OK) {
AddLog(LOG_LEVEL_INFO, PSTR("WG : peer_init: %d"), err);
goto fail;
}
/* Register the new WireGuard peer with the network interface */
lwip_err = wireguardif_add_peer(ctx->netif, &peer, &wireguard_peer_index);
if (lwip_err != ERR_OK || wireguard_peer_index == WIREGUARDIF_INVALID_INDEX) {
AddLog(LOG_LEVEL_INFO, PSTR("WG : wireguardif_add_peer: %i"), lwip_err);
err = ESP_FAIL;
goto fail;
}
if (ip_addr_isany(&peer.endpoint_ip)) {
err = ESP_FAIL;
goto fail;
}
AddLog(LOG_LEVEL_DEBUG, PSTR("WG : Connecting to %s (%s) port %i"), ctx->config->endpoint, ipaddr_ntoa(&(peer.endpoint_ip)), peer.endport_port);
lwip_err = wireguardif_connect(ctx->netif, wireguard_peer_index);
if (lwip_err != ERR_OK) {
AddLog(LOG_LEVEL_INFO, PSTR("WG : wireguardif_connect: %i"), lwip_err);
err = ESP_FAIL;
goto fail;
}
err = ESP_OK;
fail:
// AddLog(LOG_LEVEL_DEBUG, ">>>: OUT esp_wireguard_connect %d", err);
return err;
}
esp_err_t esp_wireguard_disconnect(wireguard_ctx_t *ctx)
{
err_t lwip_err;
if (!ctx || !ctx->netif) { return ESP_ERR_INVALID_ARG; }
// Clear the IP address to gracefully disconnect any clients while the
// peers are still valid
netif_set_ipaddr(ctx->netif, IP4_ADDR_ANY4);
lwip_err = wireguardif_disconnect(ctx->netif, wireguard_peer_index);
if (lwip_err != ERR_OK) {
AddLog(LOG_LEVEL_INFO, PSTR("WG : wireguardif_disconnect: peer_index: %" PRIu8 " err: %i"), wireguard_peer_index, lwip_err);
}
lwip_err = wireguardif_remove_peer(ctx->netif, wireguard_peer_index);
if (lwip_err != ERR_OK) {
AddLog(LOG_LEVEL_INFO, PSTR("WG : wireguardif_remove_peer: peer_index: %" PRIu8 " err: %i"), wireguard_peer_index, lwip_err);
}
wireguard_peer_index = WIREGUARDIF_INVALID_INDEX;
wireguardif_shutdown(ctx->netif);
netif_remove(ctx->netif);
wireguardif_fini(ctx->netif);
ctx->netif = NULL;
return ESP_OK;
}
esp_err_t esp_wireguard_peer_is_up(const wireguard_ctx_t *ctx)
{
err_t lwip_err;
if (!ctx || !ctx->netif) { return ESP_ERR_INVALID_ARG; }
lwip_err = wireguardif_peer_is_up(
ctx->netif,
wireguard_peer_index,
&peer.endpoint_ip,
&peer.endport_port);
return (lwip_err != ERR_OK) ? ESP_FAIL : ESP_OK;
}
esp_err_t esp_wireguard_latest_handshake(const wireguard_ctx_t *ctx, time_t *result)
{
if (!ctx || !ctx->netif) { return ESP_ERR_INVALID_ARG; }
*result = wireguardif_latest_handshake(ctx->netif, wireguard_peer_index);
return (*result > 0) ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_wireguard_add_allowed_ip(const wireguard_ctx_t *ctx, const ip_addr_t& allowed_ip, const ip_addr_t& allowed_ip_mask)
{
err_t lwip_err;
if (!ctx || !ctx->netif) { return ESP_ERR_INVALID_ARG; }
// AddLog(LOG_LEVEL_DEBUG, "WG : Added allowed_ips %_I/%_I", allowed_ip.u_addr.ip4.addr, allowed_ip_mask.u_addr.ip4.addr);
lwip_err = wireguardif_add_allowed_ip(ctx->netif, wireguard_peer_index, allowed_ip, allowed_ip_mask);
return (lwip_err == ERR_OK ? ESP_OK : ESP_FAIL);
}

View File

@ -0,0 +1,63 @@
/*
* Copyright (c) 2024 Simone Rossetto <simros85@gmail.com>
*
* 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.
*/
#if !defined(__ESP_WIREGUARD_ERR__H__)
#define __ESP_WIREGUARD_ERR__H__
#if defined(ESP8266)
typedef int esp_err_t;
#define ESP_OK 0 /*!< esp_err_t value indicating success (no error) */
#define ESP_FAIL -1 /*!< Generic esp_err_t code indicating failure */
#define ESP_ERR_NO_MEM 0x101 /*!< Out of memory */
#define ESP_ERR_INVALID_ARG 0x102 /*!< Invalid argument */
#define ESP_ERR_INVALID_STATE 0x103 /*!< Invalid state */
#define ESP_ERR_INVALID_SIZE 0x104 /*!< Invalid size */
#define ESP_ERR_NOT_FOUND 0x105 /*!< Requested resource not found */
#define ESP_ERR_NOT_SUPPORTED 0x106 /*!< Operation or feature not supported */
#define ESP_ERR_TIMEOUT 0x107 /*!< Operation timed out */
#define ESP_ERR_INVALID_RESPONSE 0x108 /*!< Received response was invalid */
#define ESP_ERR_INVALID_CRC 0x109 /*!< CRC or checksum was invalid */
#define ESP_ERR_INVALID_VERSION 0x10A /*!< Version was invalid */
#define ESP_ERR_INVALID_MAC 0x10B /*!< MAC address was invalid */
#define ESP_ERR_NOT_FINISHED 0x10C /*!< There are items remained to retrieve */
#define ESP_ERR_WIFI_BASE 0x3000 /*!< Starting number of WiFi error codes */
#define ESP_ERR_MESH_BASE 0x4000 /*!< Starting number of MESH error codes */
#define ESP_ERR_FLASH_BASE 0x6000 /*!< Starting number of flash error codes */
#define ESP_ERR_HW_CRYPTO_BASE 0xc000 /*!< Starting number of HW cryptography module error codes */
#define ESP_ERR_MEMPROT_BASE 0xd000 /*!< Starting number of Memory Protection API error codes */
#else
#include <esp_err.h>
#endif
#endif // __ESP_WIREGUARD_ERR__H__

View File

@ -0,0 +1,83 @@
/*
tasmota_crypto.cpp - crypto layer to call bearssl from wireguard
Copyright (C) 2025 Theo Arends, Stephan Hadinger
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 <http://www.gnu.org/licenses/>.
*/
#include <Arduino.h>
#include <t_bearssl.h>
#ifdef ESP32
#include "freertos/task.h"
#include "freertos/FreeRTOS.h"
#include "esp_expression_with_stack.h"
#endif // ESP32
//**************************************************************************************************************
// enable AddLog support within a C++ library
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};
//**************************************************************************************************************
#define BR_EC25519_IMPL br_ec_c25519_m15 // BearSSL implementation for Curve 25519
// we need a global
static struct dh_curve25519_t {
uint8_t q[32];
uint8_t n[32];
int result;
} g_dh_curve25519;
static void run_crypto_scalarmult_curve25519(void) {
g_dh_curve25519.result = BR_EC25519_IMPL.mul(g_dh_curve25519.q, 32, g_dh_curve25519.n, 32, BR_EC_curve25519);
}
extern "C" int crypto_scalarmult_curve25519(unsigned char *q, const unsigned char *n,const unsigned char *p) {
for (int32_t i=0; i<32; i++) {
g_dh_curve25519.q[i] = p[i];
g_dh_curve25519.n[i] = n[31-i];
}
#ifdef ESP32
const char *taskName = pcTaskGetName(NULL);
if (uxTaskGetStackHighWaterMark(nullptr) < 2000) {
//Allocate a stack buffer, from heap or as a static form:
StackType_t *shared_stack = (StackType_t*) heap_caps_malloc(4096 * sizeof(StackType_t), MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
//Allocate a mutex to protect its usage:
SemaphoreHandle_t lock = xSemaphoreCreateMutex();
//Call the desired function using the macro helper:
esp_execute_shared_stack_function(lock,
shared_stack,
4096,
run_crypto_scalarmult_curve25519);
vSemaphoreDelete(lock);
free(shared_stack);
} else {
run_crypto_scalarmult_curve25519();
}
#else
run_crypto_scalarmult_curve25519();
#endif
if (g_dh_curve25519.result) {
for (int32_t i=0; i<32; i++) {
q[i] = g_dh_curve25519.q[i];
}
return 0; // Success
} else {
return 1; // Failure
}
}

View File

@ -0,0 +1,76 @@
/*
* Copyright (c) 2022 Tomoyuki Sakurai <y@trombik.org>
* Copyright (c) 2023-2024 Simone Rossetto <simros85@gmail.com>
* Copyright (c) 2025 Stephan Hadinger
*
* 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.
*/
#include "wireguard-platform.h"
#include "lwip/sys.h"
#include "crypto.h"
#define ENTROPY_MINIMUM_REQUIRED_THRESHOLD (134)
#define ENTROPY_FUNCTION_DATA NULL
#define ENTROPY_CUSTOM_DATA NULL
#define ENTROPY_CUSTOM_DATA_LENGTH (0)
extern "C" uint32_t phy_get_rand(void); // From the ESP8266 SDK
void wireguard_random_bytes(void *bytes, size_t size) {
#ifdef ESP32
esp_fill_random(bytes, size);
#elif defined(ESP8266)
for (int32_t i=0; i<size; i++) {
*((uint8_t*)bytes + i) = phy_get_rand();
}
#endif
}
uint32_t wireguard_sys_now() {
// Default to the LwIP system time
return sys_now();
}
void wireguard_tai64n_now(uint8_t *output) {
// See https://cr.yp.to/libtai/tai64.html
// 64 bit seconds from 1970 = 8 bytes
// 32 bit nano seconds from current second
struct timeval tv;
gettimeofday(&tv, NULL);
uint64_t seconds = 0x400000000000000aULL + tv.tv_sec;
uint32_t nanos = tv.tv_usec * 1000;
U64TO8_BIG(output + 0, seconds);
U32TO8_BIG(output + 8, nanos);
}
bool wireguard_is_under_load() { // actually not called, we have inlined the fact that it's always false
return false;
}

View File

@ -0,0 +1,71 @@
/*
* Copyright (c) 2021 Daniel Hope (www.floorsense.nz)
* Copyright (c) 2024 Simone Rossetto <simros85@gmail.com>
* Copyright (c) 2025 Stephan Hadinger
* 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 "Floorsense Ltd", "Agile Workspace Ltd" 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 OWNER 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.
*
* Author: Daniel Hope <daniel.hope@smartalock.com>
*/
#ifndef _WIREGUARD_PLATFORM_H_
#define _WIREGUARD_PLATFORM_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#define WIREGUARD_MAX_PEERS (1)
#define WIREGUARD_MAX_SRC_IPS (4) // TASMOTA
// Per device limit on accepting (valid) initiation requests - per peer
#define MAX_INITIATIONS_PER_SECOND (2)
// The number of milliseconds since system boot - for LwIP systems this could be sys_now()
uint32_t wireguard_sys_now();
// Fill the supplied buffer with random data - random data is used for generating new session keys periodically
void wireguard_random_bytes(void *bytes, size_t size);
// Get the current time in tai64n format - 8 byte seconds, 4 byte nano sub-second - see https://cr.yp.to/libtai/tai64.html for details
// Output buffer passed is 12 bytes
// The Wireguard implementation doesn't strictly need this to be a time, but instead an increasing value
// The remote end of the Wireguard tunnel will use this value in handshake replay detection
void wireguard_tai64n_now(uint8_t *output);
// Is the system under load - i.e. should we generate cookie reply message in response to initiation messages
bool wireguard_is_under_load();
#ifdef __cplusplus
}
#endif
#endif /* _WIREGUARD_PLATFORM_H_ */

View File

@ -0,0 +1,997 @@
/*
* Copyright (c) 2021 Daniel Hope (www.floorsense.nz)
* Copyright (c) 2024 Simone Rossetto <simros85@gmail.com>
* Copyright (c) 2025 Stephan Hadinger
* 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 "Floorsense Ltd", "Agile Workspace Ltd" 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 OWNER 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.
*
* Author: Daniel Hope <daniel.hope@smartalock.com>
*/
#include <Arduino.h>
#include "wireguard.h"
#include "crypto.h"
// For HMAC calculation
#define WIREGUARD_BLAKE2S_BLOCK_SIZE (64)
//**************************************************************************************************************
// enable AddLog support within a C++ library
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};
//**************************************************************************************************************
// 5.4 Messages
// Constants
static const uint8_t PROGMEM CONSTRUCTION[] = "Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s"; // The UTF-8 string literal "Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s", 37 bytes of output
static const uint8_t PROGMEM IDENTIFIER[] = "WireGuard v1 zx2c4 Jason@zx2c4.com"; // The UTF-8 string literal "WireGuard v1 zx2c4 Jason@zx2c4.com", 34 bytes of output
static const uint8_t PROGMEM LABEL_MAC1[] = "mac1----"; // Label-Mac1 The UTF-8 string literal "mac1----", 8 bytes of output.
static const uint8_t PROGMEM LABEL_COOKIE[] = "cookie--"; // Label-Cookie The UTF-8 string literal "cookie--", 8 bytes of output
static const uint8_t zero_key[WIREGUARD_PUBLIC_KEY_LEN] = { 0 };
// Calculated in wireguard_init
static uint8_t construction_hash[WIREGUARD_HASH_LEN];
static uint8_t identifier_hash[WIREGUARD_HASH_LEN];
void wireguard_init() {
wireguard_blake2s_ctx ctx;
// Pre-calculate chaining key hash
wireguard_blake2s_init(&ctx, WIREGUARD_HASH_LEN, NULL, 0);
wireguard_blake2s_update(&ctx, CONSTRUCTION, sizeof(CONSTRUCTION) - 1); // remove terminating NULL char
wireguard_blake2s_final(&ctx, construction_hash);
// Pre-calculate initial handshake hash - uses construction_hash calculated above
wireguard_blake2s_init(&ctx, WIREGUARD_HASH_LEN, NULL, 0);
wireguard_blake2s_update(&ctx, construction_hash, sizeof(construction_hash));
wireguard_blake2s_update(&ctx, IDENTIFIER, sizeof(IDENTIFIER) - 1); // remove terminating NULL char
wireguard_blake2s_final(&ctx, identifier_hash);
}
wireguard_peer_t *wireguard_peer_alloc(wireguard_device_t *device) {
for (uint32_t x=0; x < WIREGUARD_MAX_PEERS; x++) {
if (!device->peers[x].valid) {
return &device->peers[x];
}
}
return NULL;
}
wireguard_peer_t *wireguard_peer_lookup_by_pubkey(struct wireguard_device *device, uint8_t *public_key) {
wireguard_peer_t *result = NULL;
wireguard_peer_t *tmp;
for (int32_t x=0; x < WIREGUARD_MAX_PEERS; x++) {
if (device->peers[x].valid) {
if (memcmp(device->peers[x].public_key, public_key, WIREGUARD_PUBLIC_KEY_LEN) == 0) {
return &device->peers[x];
}
}
}
return NULL;
}
uint8_t wireguard_peer_index(struct wireguard_device *device, wireguard_peer_t *peer) {
for (int32_t x=0; x < WIREGUARD_MAX_PEERS; x++) {
if (peer == &device->peers[x]) {
return x;
}
}
return 0xFF; // not found
}
wireguard_peer_t *wireguard_peer_lookup_by_peer_index(struct wireguard_device *device, uint8_t peer_index) {
if (peer_index < WIREGUARD_MAX_PEERS) {
if (device->peers[peer_index].valid) {
return &device->peers[peer_index];
}
}
return NULL;
}
wireguard_peer_t *wireguard_peer_lookup_by_receiver(struct wireguard_device *device, uint32_t receiver) {
for (int32_t x=0; x < WIREGUARD_MAX_PEERS; x++) {
wireguard_peer_t *cur_key = &device->peers[x];
if (cur_key->valid) {
if ((cur_key->curr_keypair.valid && (cur_key->curr_keypair.local_index == receiver)) ||
(cur_key->next_keypair.valid && (cur_key->next_keypair.local_index == receiver)) ||
(cur_key->prev_keypair.valid && (cur_key->prev_keypair.local_index == receiver))
) {
return cur_key;
}
}
}
return NULL;
}
wireguard_peer_t *wireguard_peer_lookup_by_handshake(struct wireguard_device *device, uint32_t receiver) {
for (int32_t x=0; x < WIREGUARD_MAX_PEERS; x++) {
wireguard_peer_t *cur_key = &device->peers[x];
if (cur_key->valid) {
if (cur_key->handshake.valid && cur_key->handshake.initiator && (cur_key->handshake.local_index == receiver)) {
return cur_key;
}
}
}
return NULL;
}
bool wireguard_expired(uint32_t created_millis, uint32_t valid_seconds) {
uint32_t diff = wireguard_sys_now() - created_millis;
return (diff >= (valid_seconds * 1000));
}
static void generate_cookie_secret(struct wireguard_device *device) {
wireguard_random_bytes(device->cookie_secret, WIREGUARD_HASH_LEN);
device->cookie_secret_millis = wireguard_sys_now();
}
static void generate_peer_cookie(struct wireguard_device *device, uint8_t *cookie, uint8_t *source_addr_port, size_t source_length) {
wireguard_blake2s_ctx ctx;
if (wireguard_expired(device->cookie_secret_millis, COOKIE_SECRET_MAX_AGE)) {
// Generate new random bytes
generate_cookie_secret(device);
}
// Mac(key, input) Keyed-Blake2s(key, input, 16), the keyed MAC variant of the BLAKE2s hash function, returning 16 bytes of output
wireguard_blake2s_init(&ctx, WIREGUARD_COOKIE_LEN, device->cookie_secret, WIREGUARD_HASH_LEN);
// 5.4.7 Under Load: Cookie Reply Message
// Mix in the IP address and port - have the IP layer pass this in as byte array to avoid using Lwip specific APIs in this module
if ((source_addr_port) && (source_length > 0)) {
wireguard_blake2s_update(&ctx, source_addr_port, source_length);
}
wireguard_blake2s_final(&ctx, cookie);
}
static void wireguard_mac(uint8_t *dst, const void *message, size_t len, const uint8_t *key, size_t keylen) {
wireguard_blake2s(dst, WIREGUARD_COOKIE_LEN, key, keylen, message, len);
}
static void wireguard_mac_key(uint8_t *key, const uint8_t *public_key, const uint8_t *label, size_t label_len) {
blake2s_ctx ctx;
blake2s_init(&ctx, WIREGUARD_SESSION_KEY_LEN, NULL, 0);
blake2s_update(&ctx, label, label_len);
blake2s_update(&ctx, public_key, WIREGUARD_PUBLIC_KEY_LEN);
blake2s_final(&ctx, key);
}
static void wireguard_mix_hash(uint8_t *hash, const uint8_t *src, size_t src_len) {
wireguard_blake2s_ctx ctx;
wireguard_blake2s_init(&ctx, WIREGUARD_HASH_LEN, NULL, 0);
wireguard_blake2s_update(&ctx, hash, WIREGUARD_HASH_LEN);
wireguard_blake2s_update(&ctx, src, src_len);
wireguard_blake2s_final(&ctx, hash);
}
static void wireguard_hmac(uint8_t *digest, const uint8_t *key, size_t key_len, const uint8_t *text, size_t text_len) {
// Adapted from appendix example in RFC2104 to use BLAKE2S instead of MD5 - https://tools.ietf.org/html/rfc2104
wireguard_blake2s_ctx ctx;
uint8_t k_ipad[WIREGUARD_BLAKE2S_BLOCK_SIZE]; // inner padding - key XORd with ipad
uint8_t k_opad[WIREGUARD_BLAKE2S_BLOCK_SIZE]; // outer padding - key XORd with opad
uint8_t tk[WIREGUARD_HASH_LEN];
int i;
// if key is longer than BLAKE2S_BLOCK_SIZE bytes reset it to key=BLAKE2S(key)
if (key_len > WIREGUARD_BLAKE2S_BLOCK_SIZE) {
wireguard_blake2s_ctx tctx;
wireguard_blake2s_init(&tctx, WIREGUARD_HASH_LEN, NULL, 0);
wireguard_blake2s_update(&tctx, key, key_len);
wireguard_blake2s_final(&tctx, tk);
key = tk;
key_len = WIREGUARD_HASH_LEN;
}
// the HMAC transform looks like:
// HASH(K XOR opad, HASH(K XOR ipad, text))
// where K is an n byte key
// ipad is the byte 0x36 repeated BLAKE2S_BLOCK_SIZE times
// opad is the byte 0x5c repeated BLAKE2S_BLOCK_SIZE times
// and text is the data being protected
memset(k_ipad, 0, sizeof(k_ipad));
memset(k_opad, 0, sizeof(k_opad));
memcpy(k_ipad, key, key_len);
memcpy(k_opad, key, key_len);
// XOR key with ipad and opad values
for (i=0; i < WIREGUARD_BLAKE2S_BLOCK_SIZE; i++) {
k_ipad[i] ^= 0x36;
k_opad[i] ^= 0x5c;
}
// perform inner HASH
wireguard_blake2s_init(&ctx, WIREGUARD_HASH_LEN, NULL, 0); // init context for 1st pass
wireguard_blake2s_update(&ctx, k_ipad, WIREGUARD_BLAKE2S_BLOCK_SIZE); // start with inner pad
wireguard_blake2s_update(&ctx, text, text_len); // then text of datagram
wireguard_blake2s_final(&ctx, digest); // finish up 1st pass
// perform outer HASH
wireguard_blake2s_init(&ctx, WIREGUARD_HASH_LEN, NULL, 0); // init context for 2nd pass
wireguard_blake2s_update(&ctx, k_opad, WIREGUARD_BLAKE2S_BLOCK_SIZE); // start with outer pad
wireguard_blake2s_update(&ctx, digest, WIREGUARD_HASH_LEN); // then results of 1st hash
wireguard_blake2s_final(&ctx, digest); // finish up 2nd pass
}
static void wireguard_kdf1(uint8_t *tau1, const uint8_t *chaining_key, const uint8_t *data, size_t data_len) {
uint8_t tau0[WIREGUARD_HASH_LEN];
uint8_t output[WIREGUARD_HASH_LEN + 1];
// tau0 = Hmac(key, input)
wireguard_hmac(tau0, chaining_key, WIREGUARD_HASH_LEN, data, data_len);
// tau1 := Hmac(tau0, 0x1)
output[0] = 1;
wireguard_hmac(output, tau0, WIREGUARD_HASH_LEN, output, 1);
memcpy(tau1, output, WIREGUARD_HASH_LEN);
// Wipe intermediates
crypto_zero(tau0, sizeof(tau0));
crypto_zero(output, sizeof(output));
}
static void wireguard_kdf2(uint8_t *tau1, uint8_t *tau2, const uint8_t *chaining_key, const uint8_t *data, size_t data_len) {
uint8_t tau0[WIREGUARD_HASH_LEN];
uint8_t output[WIREGUARD_HASH_LEN + 1];
// tau0 = Hmac(key, input)
wireguard_hmac(tau0, chaining_key, WIREGUARD_HASH_LEN, data, data_len);
// tau1 := Hmac(tau0, 0x1)
output[0] = 1;
wireguard_hmac(output, tau0, WIREGUARD_HASH_LEN, output, 1);
memcpy(tau1, output, WIREGUARD_HASH_LEN);
// tau2 := Hmac(tau0,tau1 || 0x2)
output[WIREGUARD_HASH_LEN] = 2;
wireguard_hmac(output, tau0, WIREGUARD_HASH_LEN, output, WIREGUARD_HASH_LEN + 1);
memcpy(tau2, output, WIREGUARD_HASH_LEN);
// Wipe intermediates
crypto_zero(tau0, sizeof(tau0));
crypto_zero(output, sizeof(output));
}
static void wireguard_kdf3(uint8_t *tau1, uint8_t *tau2, uint8_t *tau3, const uint8_t *chaining_key, const uint8_t *data, size_t data_len) {
uint8_t tau0[WIREGUARD_HASH_LEN];
uint8_t output[WIREGUARD_HASH_LEN + 1];
// tau0 = Hmac(key, input)
wireguard_hmac(tau0, chaining_key, WIREGUARD_HASH_LEN, data, data_len);
// tau1 := Hmac(tau0, 0x1)
output[0] = 1;
wireguard_hmac(output, tau0, WIREGUARD_HASH_LEN, output, 1);
memcpy(tau1, output, WIREGUARD_HASH_LEN);
// tau2 := Hmac(tau0,tau1 || 0x2)
output[WIREGUARD_HASH_LEN] = 2;
wireguard_hmac(output, tau0, WIREGUARD_HASH_LEN, output, WIREGUARD_HASH_LEN + 1);
memcpy(tau2, output, WIREGUARD_HASH_LEN);
// tau3 := Hmac(tau0,tau1,tau2 || 0x3)
output[WIREGUARD_HASH_LEN] = 3;
wireguard_hmac(output, tau0, WIREGUARD_HASH_LEN, output, WIREGUARD_HASH_LEN + 1);
memcpy(tau3, output, WIREGUARD_HASH_LEN);
// Wipe intermediates
crypto_zero(tau0, sizeof(tau0));
crypto_zero(output, sizeof(output));
}
bool wireguard_check_replay(wireguard_keypair_t *keypair, uint64_t seq) {
// AddLog(LOG_LEVEL_INFO, ">>>: wireguard_check_replay");
// Implementation of packet replay window - as per RFC2401
// Adapted from code in Appendix C at https://tools.ietf.org/html/rfc2401
uint32_t diff;
bool result = false;
size_t ReplayWindowSize = sizeof(keypair->replay_bitmap) * CHAR_BIT; // 32 bits
// WireGuard data packet counter starts from 0 but algorithm expects packet numbers to start from 1
seq++;
if (seq != 0) {
if (seq > keypair->replay_counter) {
// new larger sequence number
diff = seq - keypair->replay_counter;
if (diff < ReplayWindowSize) {
// In window
keypair->replay_bitmap <<= diff;
// set bit for this packet
keypair->replay_bitmap |= 1;
} else {
// This packet has a "way larger"
keypair->replay_bitmap = 1;
}
keypair->replay_counter = seq;
// larger is good
result = true;
} else {
diff = keypair->replay_counter - seq;
if (diff < ReplayWindowSize) {
if (keypair->replay_bitmap & ((uint32_t)1 << diff)) {
// already seen
} else {
// mark as seen
keypair->replay_bitmap |= ((uint32_t)1 << diff);
// out of order but good
result = true;
}
} else {
// too old or wrapped
}
}
} else {
// first == 0 or wrapped
}
return result;
}
wireguard_keypair_t *get_peer_keypair_for_idx(wireguard_peer_t *peer, uint32_t idx) {
if (peer->curr_keypair.valid && peer->curr_keypair.local_index == idx) {
return &peer->curr_keypair;
} else if (peer->next_keypair.valid && peer->next_keypair.local_index == idx) {
return &peer->next_keypair;
} else if (peer->prev_keypair.valid && peer->prev_keypair.local_index == idx) {
return &peer->prev_keypair;
}
return NULL;
}
static uint32_t wireguard_generate_unique_index(struct wireguard_device *device) {
// We need a random 32-bit number but make sure it's not already been used in the context of this device
uint32_t result;
uint8_t buf[4];
wireguard_peer_t *peer;
bool existing = false;
do {
do {
wireguard_random_bytes(buf, 4);
result = U8TO32_LITTLE(buf);
} while ((result == 0) || (result == 0xFFFFFFFF)); // Don't allow 0 or 0xFFFFFFFF as valid values
existing = false;
for (int32_t x=0; x < WIREGUARD_MAX_PEERS; x++) {
peer = &device->peers[x];
existing = (result == peer->curr_keypair.local_index) ||
(result == peer->prev_keypair.local_index) ||
(result == peer->next_keypair.local_index) ||
(result == peer->handshake.local_index);
}
} while (existing);
return result;
}
static void wireguard_clamp_private_key(uint8_t *key) {
key[0] &= 248;
key[31] = (key[31] & 127) | 64;
}
static void wireguard_generate_private_key(uint8_t *key) {
wireguard_random_bytes(key, WIREGUARD_PRIVATE_KEY_LEN);
wireguard_clamp_private_key(key);
}
static bool wireguard_generate_public_key(uint8_t *public_key, const uint8_t *private_key) {
static const uint8_t basepoint[WIREGUARD_PUBLIC_KEY_LEN] = { 9 };
bool result = false;
if (memcmp(private_key, zero_key, WIREGUARD_PUBLIC_KEY_LEN) != 0) {
result = (wireguard_x25519(public_key, private_key, basepoint) == 0);
}
return result;
}
bool wireguard_check_mac1(struct wireguard_device *device, const uint8_t *data, size_t len, const uint8_t *mac1) {
bool result = false;
uint8_t calculated[WIREGUARD_COOKIE_LEN];
wireguard_mac(calculated, data, len, device->label_mac1_key, WIREGUARD_SESSION_KEY_LEN);
if (crypto_equal(calculated, mac1, WIREGUARD_COOKIE_LEN)) {
result = true;
}
return result;
}
bool wireguard_check_mac2(struct wireguard_device *device, const uint8_t *data, size_t len, uint8_t *source_addr_port, size_t source_length, const uint8_t *mac2) {
// AddLog(LOG_LEVEL_INFO, ">>>: wireguard_check_mac2");
bool result = false;
uint8_t cookie[WIREGUARD_COOKIE_LEN];
uint8_t calculated[WIREGUARD_COOKIE_LEN];
generate_peer_cookie(device, cookie, source_addr_port, source_length);
wireguard_mac(calculated, data, len, cookie, WIREGUARD_COOKIE_LEN);
if (crypto_equal(calculated, mac2, WIREGUARD_COOKIE_LEN)) {
result = true;
}
return result;
}
void keypair_destroy(wireguard_keypair_t *keypair) {
crypto_zero(keypair, sizeof(wireguard_keypair_t));
keypair->valid = false;
}
void keypair_update(wireguard_peer_t *peer, wireguard_keypair_t *received_keypair) {
bool key_is_next = (received_keypair == &peer->next_keypair);
if (key_is_next) {
peer->prev_keypair = peer->curr_keypair;
peer->curr_keypair = peer->next_keypair;
keypair_destroy(&peer->next_keypair);
}
}
static void add_new_keypair(wireguard_peer_t *peer, wireguard_keypair_t new_keypair) {
if (new_keypair.initiator) {
if (peer->next_keypair.valid) {
peer->prev_keypair = peer->next_keypair;
keypair_destroy(&peer->next_keypair);
} else {
peer->prev_keypair = peer->curr_keypair;
}
peer->curr_keypair = new_keypair;
} else {
peer->next_keypair = new_keypair;
keypair_destroy(&peer->prev_keypair);
}
peer->latest_handshake_millis = new_keypair.keypair_millis;
}
void wireguard_start_session(wireguard_peer_t *peer, bool initiator) {
wireguard_handshake_t *handshake = &peer->handshake;
wireguard_keypair_t new_keypair;
crypto_zero(&new_keypair, sizeof(wireguard_keypair_t));
new_keypair.initiator = initiator;
new_keypair.local_index = handshake->local_index;
new_keypair.remote_index = handshake->remote_index;
new_keypair.keypair_millis = wireguard_sys_now();
new_keypair.sending_valid = true;
new_keypair.receiving_valid = true;
// 5.4.5 Transport Data Key Derivation
// (Tsendi = Trecvr, Trecvi = Tsendr) := Kdf2(Ci = Cr,E)
if (new_keypair.initiator) {
wireguard_kdf2(new_keypair.sending_key, new_keypair.receiving_key, handshake->chaining_key, NULL, 0);
} else {
wireguard_kdf2(new_keypair.receiving_key, new_keypair.sending_key, handshake->chaining_key, NULL, 0);
}
new_keypair.replay_bitmap = 0;
new_keypair.replay_counter = 0;
new_keypair.last_tx = 0;
new_keypair.last_rx = 0; // No packets received yet
new_keypair.valid = true;
// Eprivi = Epubi = Eprivr = Epubr = Ci = Cr := E
crypto_zero(handshake->ephemeral_private, WIREGUARD_PUBLIC_KEY_LEN);
crypto_zero(handshake->remote_ephemeral, WIREGUARD_PUBLIC_KEY_LEN);
crypto_zero(handshake->hash, WIREGUARD_HASH_LEN);
crypto_zero(handshake->chaining_key, WIREGUARD_HASH_LEN);
handshake->remote_index = 0;
handshake->local_index = 0;
handshake->valid = false;
add_new_keypair(peer, new_keypair);
}
uint8_t wireguard_get_message_type(const uint8_t *data, size_t len) {
uint8_t result = MESSAGE_INVALID;
if (len >= 4) {
if ((data[1] == 0) && (data[2] == 0) && (data[3] == 0)) {
switch (data[0]) {
case MESSAGE_HANDSHAKE_INITIATION:
if (len == sizeof(struct message_handshake_initiation)) {
result = MESSAGE_HANDSHAKE_INITIATION;
}
break;
case MESSAGE_HANDSHAKE_RESPONSE:
if (len == sizeof(struct message_handshake_response)) {
result = MESSAGE_HANDSHAKE_RESPONSE;
}
break;
case MESSAGE_COOKIE_REPLY:
if (len == sizeof(struct message_cookie_reply)) {
result = MESSAGE_COOKIE_REPLY;
}
break;
case MESSAGE_TRANSPORT_DATA:
if (len >= sizeof(struct message_transport_data) + WIREGUARD_AUTHTAG_LEN) {
result = MESSAGE_TRANSPORT_DATA;
}
break;
default:
break;
}
}
}
return result;
}
wireguard_peer_t *wireguard_process_initiation_message(struct wireguard_device *device, struct message_handshake_initiation *msg) {
// AddLog(LOG_LEVEL_DEBUG, ">>>: wireguard_process_initiation_message");
wireguard_peer_t *ret_peer = NULL;
wireguard_peer_t *peer = NULL;
wireguard_handshake_t *handshake;
uint8_t key[WIREGUARD_SESSION_KEY_LEN];
uint8_t chaining_key[WIREGUARD_HASH_LEN];
uint8_t hash[WIREGUARD_HASH_LEN];
uint8_t s[WIREGUARD_PUBLIC_KEY_LEN];
uint8_t e[WIREGUARD_PUBLIC_KEY_LEN];
uint8_t t[WIREGUARD_TAI64N_LEN];
uint8_t dh_calculation[WIREGUARD_PUBLIC_KEY_LEN];
uint32_t now;
bool rate_limit;
bool replay;
// We are the responder, other end is the initiator
// Ci := Hash(Construction) (precalculated hash)
memcpy(chaining_key, construction_hash, WIREGUARD_HASH_LEN);
// Hi := Hash(Ci || Identifier
memcpy(hash, identifier_hash, WIREGUARD_HASH_LEN);
// Hi := Hash(Hi || Spubr)
wireguard_mix_hash(hash, device->public_key, WIREGUARD_PUBLIC_KEY_LEN);
// Ci := Kdf1(Ci, Epubi)
wireguard_kdf1(chaining_key, chaining_key, msg->ephemeral, WIREGUARD_PUBLIC_KEY_LEN);
// msg.ephemeral := Epubi
memcpy(e, msg->ephemeral, WIREGUARD_PUBLIC_KEY_LEN);
// Hi := Hash(Hi || msg.ephemeral)
wireguard_mix_hash(hash, msg->ephemeral, WIREGUARD_PUBLIC_KEY_LEN);
// Calculate DH(Eprivi,Spubr)
wireguard_x25519(dh_calculation, device->private_key, e);
if (!crypto_equal(dh_calculation, zero_key, WIREGUARD_PUBLIC_KEY_LEN)) {
// (Ci,k) := Kdf2(Ci,DH(Eprivi,Spubr))
wireguard_kdf2(chaining_key, key, chaining_key, dh_calculation, WIREGUARD_PUBLIC_KEY_LEN);
// msg.static := AEAD(k, 0, Spubi, Hi)
if (wireguard_aead_decrypt(s, msg->enc_static, sizeof(msg->enc_static), hash, WIREGUARD_HASH_LEN, 0, key)) {
// Hi := Hash(Hi || msg.static)
wireguard_mix_hash(hash, msg->enc_static, sizeof(msg->enc_static));
peer = wireguard_peer_lookup_by_pubkey(device, s);
if (peer) {
handshake = &peer->handshake;
// (Ci,k) := Kdf2(Ci,DH(Sprivi,Spubr))
wireguard_kdf2(chaining_key, key, chaining_key, peer->public_key_dh, WIREGUARD_PUBLIC_KEY_LEN);
// msg.timestamp := AEAD(k, 0, Timestamp(), Hi)
if (wireguard_aead_decrypt(t, msg->enc_timestamp, sizeof(msg->enc_timestamp), hash, WIREGUARD_HASH_LEN, 0, key)) {
// Hi := Hash(Hi || msg.timestamp)
wireguard_mix_hash(hash, msg->enc_timestamp, sizeof(msg->enc_timestamp));
now = wireguard_sys_now();
// Check that timestamp is increasing and we haven't had too many initiations (should only get one per peer every 5 seconds max?)
replay = (memcmp(t, peer->greatest_timestamp, WIREGUARD_TAI64N_LEN) <= 0); // tai64n is big endian so we can use memcmp to compare
rate_limit = (peer->last_initiation_rx - now) < (1000 / MAX_INITIATIONS_PER_SECOND);
if (!replay && !rate_limit) {
// Success! Copy everything to peer
peer->last_initiation_rx = now;
if (memcmp(t, peer->greatest_timestamp, WIREGUARD_TAI64N_LEN) > 0) {
memcpy(peer->greatest_timestamp, t, WIREGUARD_TAI64N_LEN);
// TODO: Need to notify if the higher layers want to persist latest timestamp/nonce somewhere
}
memcpy(handshake->remote_ephemeral, e, WIREGUARD_PUBLIC_KEY_LEN);
memcpy(handshake->hash, hash, WIREGUARD_HASH_LEN);
memcpy(handshake->chaining_key, chaining_key, WIREGUARD_HASH_LEN);
handshake->remote_index = msg->sender;
handshake->valid = true;
handshake->initiator = false;
ret_peer = peer;
} else {
// Ignore
}
} else {
AddLog(LOG_LEVEL_INFO, PSTR("WG : wireguard_process_initiation_message: failed to decrypt"));
}
} else {
AddLog(LOG_LEVEL_INFO, PSTR("WG : peer not found"));
}
} else {
AddLog(LOG_LEVEL_INFO, PSTR("WG : Failed to decrypt"));
}
} else {
AddLog(LOG_LEVEL_INFO, PSTR("WG : Bad X25519"));
}
crypto_zero(key, sizeof(key));
crypto_zero(hash, sizeof(hash));
crypto_zero(chaining_key, sizeof(chaining_key));
crypto_zero(dh_calculation, sizeof(dh_calculation));
return ret_peer;
}
bool wireguard_process_handshake_response(struct wireguard_device *device, wireguard_peer_t *peer, struct message_handshake_response *src) {
wireguard_handshake_t *handshake = &peer->handshake;
bool result = false;
uint8_t key[WIREGUARD_SESSION_KEY_LEN];
uint8_t hash[WIREGUARD_HASH_LEN];
uint8_t chaining_key[WIREGUARD_HASH_LEN];
uint8_t e[WIREGUARD_PUBLIC_KEY_LEN];
uint8_t ephemeral_private[WIREGUARD_PUBLIC_KEY_LEN];
uint8_t static_private[WIREGUARD_PUBLIC_KEY_LEN];
uint8_t preshared_key[WIREGUARD_SESSION_KEY_LEN];
uint8_t dh_calculation[WIREGUARD_PUBLIC_KEY_LEN];
uint8_t tau[WIREGUARD_PUBLIC_KEY_LEN];
if (handshake->valid && handshake->initiator) {
memcpy(hash, handshake->hash, WIREGUARD_HASH_LEN);
memcpy(chaining_key, handshake->chaining_key, WIREGUARD_HASH_LEN);
memcpy(ephemeral_private, handshake->ephemeral_private, WIREGUARD_PUBLIC_KEY_LEN);
memcpy(preshared_key, peer->preshared_key, WIREGUARD_SESSION_KEY_LEN);
// (Eprivr, Epubr) := DH-Generate()
// Not required
// Cr := Kdf1(Cr,Epubr)
wireguard_kdf1(chaining_key, chaining_key, src->ephemeral, WIREGUARD_PUBLIC_KEY_LEN);
// msg.ephemeral := Epubr
memcpy(e, src->ephemeral, WIREGUARD_PUBLIC_KEY_LEN);
// Hr := Hash(Hr || msg.ephemeral)
wireguard_mix_hash(hash, src->ephemeral, WIREGUARD_PUBLIC_KEY_LEN);
// Cr := Kdf1(Cr, DH(Eprivr, Epubi))
// Calculate DH(Eprivr, Epubi)
wireguard_x25519(dh_calculation, ephemeral_private, e);
if (!crypto_equal(dh_calculation, zero_key, WIREGUARD_PUBLIC_KEY_LEN)) {
wireguard_kdf1(chaining_key, chaining_key, dh_calculation, WIREGUARD_PUBLIC_KEY_LEN);
// Cr := Kdf1(Cr, DH(Eprivr, Spubi))
// CalculateDH(Eprivr, Spubi)
wireguard_x25519(dh_calculation, device->private_key, e);
if (!crypto_equal(dh_calculation, zero_key, WIREGUARD_PUBLIC_KEY_LEN)) {
wireguard_kdf1(chaining_key, chaining_key, dh_calculation, WIREGUARD_PUBLIC_KEY_LEN);
// (Cr, t, k) := Kdf3(Cr, Q)
wireguard_kdf3(chaining_key, tau, key, chaining_key, peer->preshared_key, WIREGUARD_SESSION_KEY_LEN);
// Hr := Hash(Hr | t)
wireguard_mix_hash(hash, tau, WIREGUARD_HASH_LEN);
// msg.empty := AEAD(k, 0, E, Hr)
if (wireguard_aead_decrypt(NULL, src->enc_empty, sizeof(src->enc_empty), hash, WIREGUARD_HASH_LEN, 0, key)) {
// Hr := Hash(Hr | msg.empty)
// Not required as discarded
//Copy details to handshake
memcpy(handshake->remote_ephemeral, e, WIREGUARD_HASH_LEN);
memcpy(handshake->hash, hash, WIREGUARD_HASH_LEN);
memcpy(handshake->chaining_key, chaining_key, WIREGUARD_HASH_LEN);
handshake->remote_index = src->sender;
result = true;
} else {
AddLog(LOG_LEVEL_DEBUG, PSTR("WG : Decrypt failed"));
}
} else {
AddLog(LOG_LEVEL_DEBUG, PSTR("WG : X25519 fail"));
}
} else {
AddLog(LOG_LEVEL_DEBUG, PSTR("WG : X25519 fail 2"));
}
}
crypto_zero(key, sizeof(key));
crypto_zero(hash, sizeof(hash));
crypto_zero(chaining_key, sizeof(chaining_key));
crypto_zero(ephemeral_private, sizeof(ephemeral_private));
crypto_zero(static_private, sizeof(static_private));
crypto_zero(preshared_key, sizeof(preshared_key));
crypto_zero(tau, sizeof(tau));
// AddLog(LOG_LEVEL_DEBUG, ">>>: OUT wireguard_process_handshake_response result %d (1==SUCCESS)");
return result;
}
bool wireguard_process_cookie_message(struct wireguard_device *device, wireguard_peer_t *peer, struct message_cookie_reply *src) {
// AddLog(LOG_LEVEL_INFO, ">>>: wireguard_process_cookie_message");
uint8_t cookie[WIREGUARD_COOKIE_LEN];
bool result = false;
if (peer->handshake_mac1_valid) {
result = wireguard_xaead_decrypt(cookie, src->enc_cookie, sizeof(src->enc_cookie), peer->handshake_mac1, WIREGUARD_COOKIE_LEN, src->nonce, peer->label_cookie_key);
if (result) {
// 5.4.7 Under Load: Cookie Reply Message
// Upon receiving this message, if it is valid, the only thing the recipient of this message should do is store the cookie along with the time at which it was received
memcpy(peer->cookie, cookie, WIREGUARD_COOKIE_LEN);
peer->cookie_millis = wireguard_sys_now();
peer->handshake_mac1_valid = false;
}
} else {
// We didn't send any initiation packet so we shouldn't be getting a cookie reply!
}
return result;
}
bool wireguard_create_handshake_initiation(struct wireguard_device *device, wireguard_peer_t *peer, struct message_handshake_initiation *dst) {
uint8_t timestamp[WIREGUARD_TAI64N_LEN];
uint8_t key[WIREGUARD_SESSION_KEY_LEN];
uint8_t dh_calculation[WIREGUARD_PUBLIC_KEY_LEN];
bool result = false;
wireguard_handshake_t *handshake = &peer->handshake;
memset(dst, 0, sizeof(struct message_handshake_initiation));
// Ci := Hash(Construction) (precalculated hash)
memcpy(handshake->chaining_key, construction_hash, WIREGUARD_HASH_LEN);
// Hi := Hash(Ci || Identifier)
memcpy(handshake->hash, identifier_hash, WIREGUARD_HASH_LEN);
// Hi := Hash(Hi || Spubr)
wireguard_mix_hash(handshake->hash, peer->public_key, WIREGUARD_PUBLIC_KEY_LEN);
// (Eprivi, Epubi) := DH-Generate()
wireguard_generate_private_key(handshake->ephemeral_private);
if (wireguard_generate_public_key(dst->ephemeral, handshake->ephemeral_private)) {
// Ci := Kdf1(Ci, Epubi)
wireguard_kdf1(handshake->chaining_key, handshake->chaining_key, dst->ephemeral, WIREGUARD_PUBLIC_KEY_LEN);
// msg.ephemeral := Epubi
// Done above - public keys is calculated into dst->ephemeral
// Hi := Hash(Hi || msg.ephemeral)
wireguard_mix_hash(handshake->hash, dst->ephemeral, WIREGUARD_PUBLIC_KEY_LEN);
// Calculate DH(Eprivi,Spubr)
wireguard_x25519(dh_calculation, handshake->ephemeral_private, peer->public_key);
if (!crypto_equal(dh_calculation, zero_key, WIREGUARD_PUBLIC_KEY_LEN)) {
// (Ci,k) := Kdf2(Ci,DH(Eprivi,Spubr))
wireguard_kdf2(handshake->chaining_key, key, handshake->chaining_key, dh_calculation, WIREGUARD_PUBLIC_KEY_LEN);
// msg.static := AEAD(k,0,Spubi, Hi)
wireguard_aead_encrypt(dst->enc_static, device->public_key, WIREGUARD_PUBLIC_KEY_LEN, handshake->hash, WIREGUARD_HASH_LEN, 0, key);
// Hi := Hash(Hi || msg.static)
wireguard_mix_hash(handshake->hash, dst->enc_static, sizeof(dst->enc_static));
// (Ci,k) := Kdf2(Ci,DH(Sprivi,Spubr))
// note DH(Sprivi,Spubr) is precomputed per peer
wireguard_kdf2(handshake->chaining_key, key, handshake->chaining_key, peer->public_key_dh, WIREGUARD_PUBLIC_KEY_LEN);
// msg.timestamp := AEAD(k, 0, Timestamp(), Hi)
wireguard_tai64n_now(timestamp);
wireguard_aead_encrypt(dst->enc_timestamp, timestamp, WIREGUARD_TAI64N_LEN, handshake->hash, WIREGUARD_HASH_LEN, 0, key);
// Hi := Hash(Hi || msg.timestamp)
wireguard_mix_hash(handshake->hash, dst->enc_timestamp, sizeof(dst->enc_timestamp));
dst->type = MESSAGE_HANDSHAKE_INITIATION;
dst->sender = wireguard_generate_unique_index(device);
handshake->valid = true;
handshake->initiator = true;
handshake->local_index = dst->sender;
result = true;
}
}
if (result) {
// 5.4.4 Cookie MACs
// msg.mac1 := Mac(Hash(Label-Mac1 || Spubm' ), msgA)
// The value Hash(Label-Mac1 || Spubm' ) above can be pre-computed
wireguard_mac(dst->mac1, dst, (sizeof(struct message_handshake_initiation)-(2*WIREGUARD_COOKIE_LEN)), peer->label_mac1_key, WIREGUARD_SESSION_KEY_LEN);
// if Lm = E or Lm ≥ 120:
if ((peer->cookie_millis == 0) || wireguard_expired(peer->cookie_millis, COOKIE_SECRET_MAX_AGE)) {
// msg.mac2 := 0
crypto_zero(dst->mac2, WIREGUARD_COOKIE_LEN);
} else {
// msg.mac2 := Mac(Lm, msgB)
wireguard_mac(dst->mac2, dst, (sizeof(struct message_handshake_initiation)-(WIREGUARD_COOKIE_LEN)), peer->cookie, WIREGUARD_COOKIE_LEN);
}
}
crypto_zero(key, sizeof(key));
crypto_zero(dh_calculation, sizeof(dh_calculation));
return result;
}
bool wireguard_create_handshake_response(struct wireguard_device *device, wireguard_peer_t *peer, struct message_handshake_response *dst) {
wireguard_handshake_t *handshake = &peer->handshake;
uint8_t key[WIREGUARD_SESSION_KEY_LEN];
uint8_t dh_calculation[WIREGUARD_PUBLIC_KEY_LEN];
uint8_t tau[WIREGUARD_HASH_LEN];
bool result = false;
memset(dst, 0, sizeof(struct message_handshake_response));
if (handshake->valid && !handshake->initiator) {
// (Eprivr, Epubr) := DH-Generate()
wireguard_generate_private_key(handshake->ephemeral_private);
if (wireguard_generate_public_key(dst->ephemeral, handshake->ephemeral_private)) {
// Cr := Kdf1(Cr,Epubr)
wireguard_kdf1(handshake->chaining_key, handshake->chaining_key, dst->ephemeral, WIREGUARD_PUBLIC_KEY_LEN);
// msg.ephemeral := Epubr
// Copied above when generated
// Hr := Hash(Hr || msg.ephemeral)
wireguard_mix_hash(handshake->hash, dst->ephemeral, WIREGUARD_PUBLIC_KEY_LEN);
// Cr := Kdf1(Cr, DH(Eprivr, Epubi))
// Calculate DH(Eprivi,Spubr)
wireguard_x25519(dh_calculation, handshake->ephemeral_private, handshake->remote_ephemeral);
if (!crypto_equal(dh_calculation, zero_key, WIREGUARD_PUBLIC_KEY_LEN)) {
wireguard_kdf1(handshake->chaining_key, handshake->chaining_key, dh_calculation, WIREGUARD_PUBLIC_KEY_LEN);
// Cr := Kdf1(Cr, DH(Eprivr, Spubi))
// Calculate DH(Eprivi,Spubr)
wireguard_x25519(dh_calculation, handshake->ephemeral_private, peer->public_key);
if (!crypto_equal(dh_calculation, zero_key, WIREGUARD_PUBLIC_KEY_LEN)) {
wireguard_kdf1(handshake->chaining_key, handshake->chaining_key, dh_calculation, WIREGUARD_PUBLIC_KEY_LEN);
// (Cr, t, k) := Kdf3(Cr, Q)
wireguard_kdf3(handshake->chaining_key, tau, key, handshake->chaining_key, peer->preshared_key, WIREGUARD_SESSION_KEY_LEN);
// Hr := Hash(Hr | t)
wireguard_mix_hash(handshake->hash, tau, WIREGUARD_HASH_LEN);
// msg.empty := AEAD(k, 0, E, Hr)
wireguard_aead_encrypt(dst->enc_empty, NULL, 0, handshake->hash, WIREGUARD_HASH_LEN, 0, key);
// Hr := Hash(Hr | msg.empty)
wireguard_mix_hash(handshake->hash, dst->enc_empty, sizeof(dst->enc_empty));
dst->type = MESSAGE_HANDSHAKE_RESPONSE;
dst->receiver = handshake->remote_index;
dst->sender = wireguard_generate_unique_index(device);
// Update handshake object too
handshake->local_index = dst->sender;
result = true;
} else {
// Bad x25519
}
} else {
// Bad x25519
}
} else {
// Failed to generate DH
}
}
if (result) {
// 5.4.4 Cookie MACs
// msg.mac1 := Mac(Hash(Label-Mac1 || Spubm' ), msgA)
// The value Hash(Label-Mac1 || Spubm' ) above can be pre-computed
wireguard_mac(dst->mac1, dst, (sizeof(struct message_handshake_response)-(2*WIREGUARD_COOKIE_LEN)), peer->label_mac1_key, WIREGUARD_SESSION_KEY_LEN);
// if Lm = E or Lm ≥ 120:
if ((peer->cookie_millis == 0) || wireguard_expired(peer->cookie_millis, COOKIE_SECRET_MAX_AGE)) {
// msg.mac2 := 0
crypto_zero(dst->mac2, WIREGUARD_COOKIE_LEN);
} else {
// msg.mac2 := Mac(Lm, msgB)
wireguard_mac(dst->mac2, dst, (sizeof(struct message_handshake_response)-(WIREGUARD_COOKIE_LEN)), peer->cookie, WIREGUARD_COOKIE_LEN);
}
}
crypto_zero(key, sizeof(key));
crypto_zero(dh_calculation, sizeof(dh_calculation));
crypto_zero(tau, sizeof(tau));
return result;
}
void wireguard_create_cookie_reply(struct wireguard_device *device, struct message_cookie_reply *dst, const uint8_t *mac1, uint32_t index, uint8_t *source_addr_port, size_t source_length) {
uint8_t cookie[WIREGUARD_COOKIE_LEN];
crypto_zero(dst, sizeof(struct message_cookie_reply));
dst->type = MESSAGE_COOKIE_REPLY;
dst->receiver = index;
wireguard_random_bytes(dst->nonce, COOKIE_NONCE_LEN);
generate_peer_cookie(device, cookie, source_addr_port, source_length);
wireguard_xaead_encrypt(dst->enc_cookie, cookie, WIREGUARD_COOKIE_LEN, mac1, WIREGUARD_COOKIE_LEN, dst->nonce, device->label_cookie_key);
}
bool wireguard_peer_init(struct wireguard_device *device, wireguard_peer_t *peer, const uint8_t *public_key, const uint8_t *preshared_key) {
// Clear out structure
memset(peer, 0, sizeof(wireguard_peer_t));
if (device->valid) {
// Copy across the public key into our peer structure
memcpy(peer->public_key, public_key, WIREGUARD_PUBLIC_KEY_LEN);
memcpy(peer->preshared_key, preshared_key, WIREGUARD_SESSION_KEY_LEN);
// AddLog(LOG_LEVEL_INFO, ">>>: wireguard_peer_init pub_key %*_H priv_key %*_H peer_pub %*_H", 32, peer->public_key_dh, 32, device->private_key, 32, peer->public_key);
if (wireguard_x25519(peer->public_key_dh, device->private_key, peer->public_key) == 0) {
// Zero out handshake
memset(&peer->handshake, 0, sizeof(wireguard_handshake_t));
peer->handshake.valid = false;
// Zero out any cookie info - we haven't received one yet
peer->cookie_millis = 0;
memset(&peer->cookie, 0, WIREGUARD_COOKIE_LEN);
// Precompute keys to deal with mac1/2 calculation
wireguard_mac_key(peer->label_mac1_key, peer->public_key, LABEL_MAC1, sizeof(LABEL_MAC1) - 1);
wireguard_mac_key(peer->label_cookie_key, peer->public_key, LABEL_COOKIE, sizeof(LABEL_COOKIE) - 1);
peer->valid = true;
} else {
crypto_zero(peer->public_key_dh, WIREGUARD_PUBLIC_KEY_LEN);
}
}
return peer->valid;
}
bool wireguard_device_init(struct wireguard_device *device, const uint8_t *private_key) {
// Set the private key and calculate public key from it
memcpy(device->private_key, private_key, WIREGUARD_PRIVATE_KEY_LEN);
// Ensure private key is correctly "clamped"
wireguard_clamp_private_key(device->private_key);
device->valid = wireguard_generate_public_key(device->public_key, private_key);
if (device->valid) {
// AddLog(LOG_LEVEL_DEBUG, ">>>: wireguard_device_init public_key %*_H", 32, device->public_key);
generate_cookie_secret(device);
// AddLog(LOG_LEVEL_DEBUG, ">>>: wireguard_device_init cookie secret %*_H", 32, device->cookie_secret);
// 5.4.4 Cookie MACs - The value Hash(Label-Mac1 || Spubm' ) above can be pre-computed.
wireguard_mac_key(device->label_mac1_key, device->public_key, LABEL_MAC1, sizeof(LABEL_MAC1) - 1);
// AddLog(LOG_LEVEL_DEBUG, ">>>: wireguard_device_init label_mac1_key %*_H", 32, device->label_mac1_key);
// 5.4.7 Under Load: Cookie Reply Message - The value Hash(Label-Cookie || Spubm) above can be pre-computed.
wireguard_mac_key(device->label_cookie_key, device->public_key, LABEL_COOKIE, sizeof(LABEL_COOKIE) - 1);
// AddLog(LOG_LEVEL_DEBUG, ">>>: wireguard_device_init label_cookie_key %*_H", 32, device->label_cookie_key);
} else {
crypto_zero(device->private_key, WIREGUARD_PRIVATE_KEY_LEN);
}
return device->valid;
}
void wireguard_encrypt_packet(uint8_t *dst, const uint8_t *src, size_t src_len, wireguard_keypair_t *keypair) {
wireguard_aead_encrypt(dst, src, src_len, NULL, 0, keypair->sending_counter, keypair->sending_key);
keypair->sending_counter++;
}
bool wireguard_decrypt_packet(uint8_t *dst, const uint8_t *src, size_t src_len, uint64_t counter, wireguard_keypair_t *keypair) {
return wireguard_aead_decrypt(dst, src, src_len, NULL, 0, counter, keypair->receiving_key);
}

View File

@ -0,0 +1,288 @@
/*
* Copyright (c) 2021 Daniel Hope (www.floorsense.nz)
* Copyright (c) 2025 Stephan Hadinger
* 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 "Floorsense Ltd", "Agile Workspace Ltd" 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 OWNER 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.
*
* Author: Daniel Hope <daniel.hope@smartalock.com>
*/
#ifndef _WIREGUARD_H_
#define _WIREGUARD_H_
#ifdef __cplusplus
extern "C" {
#endif
// Note: these are only required for definitions in device/peer for netif, udp_pcb, ip_addr_t and u16_t
#include "lwip/netif.h"
#include "lwip/ip_addr.h"
#include "lwip/arch.h"
// Platform-specific functions that need to be implemented per-platform
#include "wireguard-platform.h"
// tai64n contains 64-bit seconds and 32-bit nano offset (12 bytes)
#define WIREGUARD_TAI64N_LEN (12)
// Auth algorithm is chacha20pol1305 which is 128bit (16 byte) authenticator
#define WIREGUARD_AUTHTAG_LEN (16)
// Hash algorithm is blake2s which makes 32 byte hashes
#define WIREGUARD_HASH_LEN (32)
// Public key algo is curve22519 which uses 32 byte keys
#define WIREGUARD_PUBLIC_KEY_LEN (32)
// Public key algo is curve22519 which uses 32 byte keys
#define WIREGUARD_PRIVATE_KEY_LEN (32)
// Symmetric session keys are chacha20/poly1305 which uses 32 byte keys
#define WIREGUARD_SESSION_KEY_LEN (32)
// Timers / Limits
#define WIREGUARD_COOKIE_LEN (16)
#define COOKIE_SECRET_MAX_AGE (2 * 60)
#define COOKIE_NONCE_LEN (24)
#define REKEY_AFTER_MESSAGES (1ULL << 60)
#define REJECT_AFTER_MESSAGES (0xFFFFFFFFFFFFFFFFULL - (1ULL << 13))
#define REKEY_AFTER_TIME (120)
#define REJECT_AFTER_TIME (180)
#define REKEY_TIMEOUT (5)
typedef struct wireguard_keypair {
bool valid;
bool initiator; // Did we initiate this session (send the initiation packet rather than sending the response packet)
uint32_t keypair_millis;
uint8_t sending_key[WIREGUARD_SESSION_KEY_LEN];
bool sending_valid;
uint64_t sending_counter;
uint8_t receiving_key[WIREGUARD_SESSION_KEY_LEN];
bool receiving_valid;
uint32_t last_tx;
uint32_t last_rx;
uint32_t replay_bitmap;
uint64_t replay_counter;
uint32_t local_index; // This is the index we generated for our end
uint32_t remote_index; // This is the index on the other end
} wireguard_keypair_t;
typedef struct wireguard_handshake {
bool valid;
bool initiator;
uint32_t local_index;
uint32_t remote_index;
uint8_t ephemeral_private[WIREGUARD_PRIVATE_KEY_LEN];
uint8_t remote_ephemeral[WIREGUARD_PUBLIC_KEY_LEN];
uint8_t hash[WIREGUARD_HASH_LEN];
uint8_t chaining_key[WIREGUARD_HASH_LEN];
} wireguard_handshake_t;
typedef struct wireguard_allowed_ip {
bool valid;
ip_addr_t ip;
ip_addr_t mask;
} wireguard_allowed_ip_t;
typedef struct wireguard_peer {
bool valid; // Is this peer initialised?
bool active; // Should we be actively trying to connect?
// This is the configured IP of the peer (endpoint)
ip_addr_t connect_ip;
u16_t connect_port;
// This is the latest received IP/port
ip_addr_t ip;
u16_t port;
// keep-alive interval in seconds, 0 is disable
uint16_t keepalive_interval;
struct wireguard_allowed_ip allowed_source_ips[WIREGUARD_MAX_SRC_IPS];
uint8_t public_key[WIREGUARD_PUBLIC_KEY_LEN];
uint8_t preshared_key[WIREGUARD_SESSION_KEY_LEN];
// Precomputed DH(Sprivi,Spubr) with device private key, and peer public key
uint8_t public_key_dh[WIREGUARD_PUBLIC_KEY_LEN];
// Session keypairs
struct wireguard_keypair curr_keypair;
struct wireguard_keypair prev_keypair;
struct wireguard_keypair next_keypair;
// 5.1 Silence is a Virtue: The responder keeps track of the greatest timestamp received per peer
uint8_t greatest_timestamp[WIREGUARD_TAI64N_LEN];
// The active handshake that is happening
struct wireguard_handshake handshake;
// The time of the latest completed handshake
uint32_t latest_handshake_millis;
// Decrypted cookie from the responder
uint32_t cookie_millis;
uint8_t cookie[WIREGUARD_COOKIE_LEN];
// The latest mac1 we sent with initiation
bool handshake_mac1_valid;
uint8_t handshake_mac1[WIREGUARD_COOKIE_LEN];
// Precomputed keys for use in mac validation
uint8_t label_cookie_key[WIREGUARD_SESSION_KEY_LEN];
uint8_t label_mac1_key[WIREGUARD_SESSION_KEY_LEN];
// The last time we received a valid initiation message
uint32_t last_initiation_rx;
// The last time we sent an initiation message to this peer
uint32_t last_initiation_tx;
// last_tx and last_rx of data packets
uint32_t last_tx;
uint32_t last_rx;
// We set this flag on RX/TX of packets if we think that we should initiate a new handshake
bool send_handshake;
} wireguard_peer_t;
typedef struct wireguard_device {
// Maybe have a "Device private" member to abstract these?
struct netif *netif;
struct udp_pcb *udp_pcb;
struct netif *underlying_netif;
uint8_t public_key[WIREGUARD_PUBLIC_KEY_LEN];
uint8_t private_key[WIREGUARD_PRIVATE_KEY_LEN];
uint8_t cookie_secret[WIREGUARD_HASH_LEN];
uint32_t cookie_secret_millis;
// Precalculated
uint8_t label_cookie_key[WIREGUARD_SESSION_KEY_LEN];
uint8_t label_mac1_key[WIREGUARD_SESSION_KEY_LEN];
// List of peers associated with this device
struct wireguard_peer peers[WIREGUARD_MAX_PEERS];
bool valid;
} wireguard_device_t;
#define MESSAGE_INVALID 0
#define MESSAGE_HANDSHAKE_INITIATION 1
#define MESSAGE_HANDSHAKE_RESPONSE 2
#define MESSAGE_COOKIE_REPLY 3
#define MESSAGE_TRANSPORT_DATA 4
// 5.4.2 First Message: Initiator to Responder
typedef struct message_handshake_initiation {
uint8_t type;
uint8_t reserved[3];
uint32_t sender;
uint8_t ephemeral[32];
uint8_t enc_static[32 + WIREGUARD_AUTHTAG_LEN];
uint8_t enc_timestamp[WIREGUARD_TAI64N_LEN + WIREGUARD_AUTHTAG_LEN];
uint8_t mac1[WIREGUARD_COOKIE_LEN];
uint8_t mac2[WIREGUARD_COOKIE_LEN];
} __attribute__ ((__packed__)) message_handshake_initiation_t;
// 5.4.3 Second Message: Responder to Initiator
typedef struct message_handshake_response {
uint8_t type;
uint8_t reserved[3];
uint32_t sender;
uint32_t receiver;
uint8_t ephemeral[32];
uint8_t enc_empty[0 + WIREGUARD_AUTHTAG_LEN];
uint8_t mac1[WIREGUARD_COOKIE_LEN];
uint8_t mac2[WIREGUARD_COOKIE_LEN];
} __attribute__ ((__packed__)) message_handshake_response_t;
// 5.4.7 Under Load: Cookie Reply Message
typedef struct message_cookie_reply {
uint8_t type;
uint8_t reserved[3];
uint32_t receiver;
uint8_t nonce[COOKIE_NONCE_LEN];
uint8_t enc_cookie[WIREGUARD_COOKIE_LEN + WIREGUARD_AUTHTAG_LEN];
} __attribute__ ((__packed__)) message_cookie_reply_t;
// 5.4.6 Subsequent Messages: Transport Data Messages
typedef struct message_transport_data {
uint8_t type;
uint8_t reserved[3];
uint32_t receiver;
uint8_t counter[8];
// Followed by encrypted data
uint8_t enc_packet[];
} __attribute__ ((__packed__)) message_transport_data_t;
// Initialise the WireGuard system - need to call this before anything else
void wireguard_init(void);
bool wireguard_device_init(struct wireguard_device *device, const uint8_t *private_key);
bool wireguard_peer_init(struct wireguard_device *device, wireguard_peer_t *peer, const uint8_t *public_key, const uint8_t *preshared_key);
wireguard_peer_t *wireguard_peer_alloc(wireguard_device_t *device);
uint8_t wireguard_peer_index(struct wireguard_device *device, wireguard_peer_t *peer);
wireguard_peer_t *wireguard_peer_lookup_by_pubkey(struct wireguard_device *device, uint8_t *public_key);
wireguard_peer_t *wireguard_peer_lookup_by_peer_index(struct wireguard_device *device, uint8_t peer_index);
wireguard_peer_t *wireguard_peer_lookup_by_receiver(struct wireguard_device *device, uint32_t receiver);
wireguard_peer_t *wireguard_peer_lookup_by_handshake(struct wireguard_device *device, uint32_t receiver);
void wireguard_start_session(wireguard_peer_t *peer, bool initiator);
void keypair_update(wireguard_peer_t *peer, wireguard_keypair_t *received_keypair);
void keypair_destroy(wireguard_keypair_t *keypair);
wireguard_keypair_t *get_peer_keypair_for_idx(wireguard_peer_t *peer, uint32_t idx);
bool wireguard_check_replay(wireguard_keypair_t *keypair, uint64_t seq);
uint8_t wireguard_get_message_type(const uint8_t *data, size_t len);
wireguard_peer_t *wireguard_process_initiation_message(struct wireguard_device *device, struct message_handshake_initiation *msg);
bool wireguard_process_handshake_response(struct wireguard_device *device, wireguard_peer_t *peer, struct message_handshake_response *src);
bool wireguard_process_cookie_message(struct wireguard_device *device, wireguard_peer_t *peer, struct message_cookie_reply *src);
bool wireguard_create_handshake_initiation(struct wireguard_device *device, wireguard_peer_t *peer, struct message_handshake_initiation *dst);
bool wireguard_create_handshake_response(struct wireguard_device *device, wireguard_peer_t *peer, struct message_handshake_response *dst);
void wireguard_create_cookie_reply(struct wireguard_device *device, struct message_cookie_reply *dst, const uint8_t *mac1, uint32_t index, uint8_t *source_addr_port, size_t source_length);
bool wireguard_check_mac1(struct wireguard_device *device, const uint8_t *data, size_t len, const uint8_t *mac1);
bool wireguard_check_mac2(struct wireguard_device *device, const uint8_t *data, size_t len, uint8_t *source_addr_port, size_t source_length, const uint8_t *mac2);
bool wireguard_expired(uint32_t created_millis, uint32_t valid_seconds);
void wireguard_encrypt_packet(uint8_t *dst, const uint8_t *src, size_t src_len, wireguard_keypair_t *keypair);
bool wireguard_decrypt_packet(uint8_t *dst, const uint8_t *src, size_t src_len, uint64_t counter, wireguard_keypair_t *keypair);
#ifdef __cplusplus
}
#endif
#endif /* _WIREGUARD_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,122 @@
/*
* Copyright (c) 2021 Daniel Hope (www.floorsense.nz)
* Copyright (c) 2023 Simone Rossetto <simros85@gmail.com>
* Copyright (c) 2025 Stephan Hadinger
* 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 "Floorsense Ltd", "Agile Workspace Ltd" 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 OWNER 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.
*
* Author: Daniel Hope <daniel.hope@smartalock.com>
*/
#ifndef _WIREGUARDIF_H_
#define _WIREGUARDIF_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "esp_wireguard.h"
#include <time.h>
#include "lwip/arch.h"
#include "lwip/netif.h"
#include "lwip/ip_addr.h"
// Default MTU for WireGuard is 1420 bytes
#define WIREGUARDIF_MTU (1420)
#define WIREGUARDIF_DEFAULT_PORT (51820)
typedef struct wireguardif_init_data {
// Required: the private key of this WireGuard network interface
wg_key_t private_key2;
// Required: What UDP port to listen on
uint16_t listen_port;
// Optional: restrict send/receive of encapsulated WireGuard traffic to this network interface only (NULL to use routing table)
struct netif *bind_netif;
} wireguardif_init_data_t;
typedef struct wireguardif_peer {
wg_key_t public_key2;
// Optional pre-shared key (32 bytes) - make sure this is NULL if not to be used
wg_key_t preshared_key2;
// tai64n of largest timestamp we have seen during handshake to avoid replays
uint8_t greatest_timestamp[12];
// Allowed ip/netmask (can add additional later but at least one is required)
ip_addr_t allowed_ip;
ip_addr_t allowed_mask;
// End-point details (may be blank)
ip_addr_t endpoint_ip;
uint16_t endport_port;
uint16_t keep_alive;
} wireguardif_peer_t;
#define WIREGUARDIF_INVALID_INDEX (0xFF)
// Initialise a new WireGuard network interface (netif)
err_t wireguardif_init(struct netif *netif);
// Helper to initialise the peer struct with defaults
void wireguardif_peer_init(wireguardif_peer_t *peer);
// Add a new peer to the specified interface - see wireguard.h for maximum number of peers allowed
// On success the peer_index can be used to reference this peer in future function calls
err_t wireguardif_add_peer(struct netif *netif, wireguardif_peer_t *peer, u8_t *peer_index);
// Remove the given peer from the network interface
err_t wireguardif_remove_peer(struct netif *netif, u8_t peer_index);
// Try and connect to the given peer
err_t wireguardif_connect(struct netif *netif, u8_t peer_index);
// Stop trying to connect to the given peer
err_t wireguardif_disconnect(struct netif *netif, u8_t peer_index);
// Shutdown the WireGuard interface
void wireguardif_shutdown(struct netif *netif);
// Finalize the WireGuard interface after the netif is removed
void wireguardif_fini(struct netif *netif);
// Is the given peer "up"? A peer is up if it has a valid session key it can communicate with
err_t wireguardif_peer_is_up(struct netif *netif, u8_t peer_index, ip_addr_t *current_ip, u16_t *current_port);
// Get timestamp of latest handshake (with seconds resolution)
// Return 0 if no handshake already done or in case of errors
time_t wireguardif_latest_handshake(struct netif *netif, u8_t peer_index);
// Add ip/mask to the list of allowed ips of the given peer
err_t wireguardif_add_allowed_ip(struct netif *netif, u8_t peer_index, const ip_addr_t& ip, const ip_addr_t& mask);
#ifdef __cplusplus
}
#endif
#endif /* _WIREGUARDIF_H_ */

View File

@ -1,4 +1,4 @@
CFLAGS = -Wall -Wextra -std=c99 -O2 -Wno-zero-length-array -Wno-empty-translation-unit -DUSE_BERRY_INT64
CFLAGS = -Wall -Wextra -std=c99 -O2 -Wno-zero-length-array -Wno-empty-translation-unit -ffp-contract=off -DUSE_BERRY_INT64
DEBUG_FLAGS = -O0 -g -DBE_DEBUG
TEST_FLAGS = $(DEBUG_FLAGS) --coverage -fno-omit-frame-pointer -fsanitize=address -fsanitize=undefined
LIBS = -lm

View File

@ -224,6 +224,7 @@ BERRY_LOCAL const bntvmodule_t* const be_module_table[] = {
};
be_extern_native_class(dyn);
be_extern_native_class(sortedmap);
be_extern_native_class(tasmota);
be_extern_native_class(Trigger);
be_extern_native_class(Driver);
@ -281,6 +282,7 @@ BERRY_LOCAL bclass_array be_class_table = {
#ifdef TASMOTA
/* first list are direct classes */
&be_native_class(dyn),
&be_native_class(sortedmap),
&be_native_class(tasmota),
&be_native_class(Trigger),
&be_native_class(Driver),

View File

@ -412,21 +412,21 @@ static int raise_compile_error(bvm *vm)
return 0;
}
static int m_compile_str(bvm *vm)
static int m_compile_str(bvm *vm, bbool islocal)
{
int len = be_strlen(vm, 1);
const char *src = be_tostring(vm, 1);
int res = be_loadbuffer(vm, "string", src, len);
int res = be_loadbuffer_local(vm, "string", src, len, islocal);
if (res == BE_OK) {
be_return(vm);
}
return raise_compile_error(vm);
}
static int m_compile_file(bvm *vm)
static int m_compile_file(bvm *vm, bbool islocal)
{
const char *fname = be_tostring(vm, 1);
int res = be_loadfile(vm, fname);
int res = be_loadfile_local(vm, fname, islocal);
if (res == BE_OK) {
be_return(vm);
} else if (res == BE_IO_ERROR) {
@ -443,14 +443,18 @@ int be_baselib_compile(bvm *vm)
if (be_top(vm) && be_isstring(vm, 1)) {
if (be_top(vm) >= 2 && be_isstring(vm, 2)) {
const char *s = be_tostring(vm, 2);
bbool islocal = bfalse;
if (be_top(vm) >= 3 && be_isbool(vm, 3)) {
islocal = be_tobool(vm, 3);
}
if (!strcmp(s, "string")) {
return m_compile_str(vm);
return m_compile_str(vm, islocal);
}
if (!strcmp(s, "file")) {
return m_compile_file(vm);
return m_compile_file(vm, islocal);
}
} else {
return m_compile_str(vm);
return m_compile_str(vm, bfalse); /* default to global context */
}
}
#endif

View File

@ -806,7 +806,8 @@ static int m_asstring(bvm *vm)
{
buf_impl attr = bytes_check_data(vm, 0);
check_ptr(vm, &attr);
be_pushnstring(vm, (const char*) attr.bufptr, attr.len);
size_t safe_len = strnlen((const char*) attr.bufptr, attr.len);
be_pushnstring(vm, (const char*) attr.bufptr, safe_len);
be_return(vm);
}

View File

@ -219,6 +219,15 @@ BERRY_API int be_loadbuffer(bvm *vm,
return be_protectedparser(vm, name, _sgets, &sbuf, bfalse);
}
BERRY_API int be_loadbuffer_local(bvm *vm,
const char *name, const char *buffer, size_t length, bbool islocal)
{
struct strbuf sbuf;
sbuf.s = buffer;
sbuf.len = length;
return be_protectedparser(vm, name, _sgets, &sbuf, islocal);
}
static int fileparser(bvm *vm, const char *name, bbool islocal)
{
int res = BE_IO_ERROR;

View File

@ -182,7 +182,11 @@ static int m_getmodule(bvm *vm)
if (top >= 1) {
bvalue *v = be_indexof(vm, 1);
if (var_isstr(v)) {
int ret = be_module_load(vm, var_tostr(v));
bbool no_cache = bfalse;
if (top >= 2) {
no_cache = be_tobool(vm, 2);
}
int ret = be_module_load_nocache(vm, var_tostr(v), no_cache);
if (ret == BE_OK) {
be_return(vm);
}

View File

@ -13,6 +13,9 @@
#if BE_USE_JSON_MODULE
#define is_space(c) ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == '\n')
#define is_digit(c) ((c) >= '0' && (c) <= '9')
#define MAX_INDENT 24
#define INDENT_WIDTH 2
#define INDENT_CHAR ' '
@ -30,11 +33,6 @@ static const char* skip_space(const char *s)
return s;
}
static int is_digit(int c)
{
return c >= '0' && c <= '9';
}
static const char* match_char(const char *json, int ch)
{
json = skip_space(json);
@ -249,90 +247,114 @@ static const char* parser_array(bvm *vm, const char *json)
return json;
}
enum {
JSON_NUMBER_INVALID = 0,
JSON_NUMBER_INTEGER = 1,
JSON_NUMBER_REAL = 2
};
int check_json_number(const char *json) {
if (!json || *json == '\0') {
return JSON_NUMBER_INVALID;
}
const char *p = json;
bbool has_fraction = bfalse;
bbool has_exponent = bfalse;
// Skip leading whitespace
while (is_space(*p)) {
p++;
}
if (*p == '\0') {
return JSON_NUMBER_INVALID;
}
// Handle optional minus sign
if (*p == '-') {
p++;
if (*p == '\0') {
return JSON_NUMBER_INVALID;
}
}
// Integer part
if (*p == '0') {
// If starts with 0, next char must not be a digit (unless it's decimal point or exponent)
p++;
if (is_digit(*p)) {
return JSON_NUMBER_INVALID; // Leading zeros not allowed (except standalone 0)
}
} else if (is_digit(*p)) {
// First digit must be 1-9, then any digits
p++;
while (is_digit(*p)) {
p++;
}
} else {
return JSON_NUMBER_INVALID; // Must start with digit
}
// Optional fractional part
if (*p == '.') {
has_fraction = btrue;
p++;
if (!is_digit(*p)) {
return JSON_NUMBER_INVALID; // Must have at least one digit after decimal point
}
while (is_digit(*p)) {
p++;
}
}
// Optional exponent part
if (*p == 'e' || *p == 'E') {
has_exponent = btrue;
p++;
// Optional sign in exponent
if (*p == '+' || *p == '-') {
p++;
}
if (!is_digit(*p)) {
return JSON_NUMBER_INVALID; // Must have at least one digit in exponent
}
while (is_digit(*p)) {
p++;
}
}
// Number ends here - check that next char is not a continuation
// Valid JSON number termination: whitespace, null, or JSON delimiters
if (*p != '\0' && !is_space(*p) && *p != ',' && *p != ']' && *p != '}' && *p != ':') {
return JSON_NUMBER_INVALID;
}
// Determine return value based on what was found
// Any number with exponent (e/E) is always real, regardless of fractional part
if (has_exponent || has_fraction) {
return JSON_NUMBER_REAL; // real number
} else {
return JSON_NUMBER_INTEGER; // integer
}
}
static const char* parser_number(bvm *vm, const char *json)
{
char c = *json++;
bbool is_neg = c == '-';
if(is_neg) {
c = *json++;
if(!is_digit(c)) {
/* minus must be followed by digit */
return NULL;
}
const char *endstr = NULL;
int number_type = check_json_number(json);
switch (number_type) {
case JSON_NUMBER_INTEGER:
be_pushint(vm, be_str2int(json, &endstr));
break;
case JSON_NUMBER_REAL:
be_pushreal(vm, be_str2real(json, &endstr));
break;
default:
endstr = NULL;
}
bint intv = 0;
if(c != '0') {
/* parse integer part */
while(is_digit(c)) {
intv = intv * 10 + c - '0';
c = *json++;
}
} else {
/*
Number starts with zero, this is only allowed
if the number is just '0' or
it has a fractional part or exponent.
*/
c = *json++;
}
if(c != '.' && c != 'e' && c != 'E') {
/*
No fractional part or exponent follows, this is an integer.
If digits follow after it (for example due to a leading zero)
this will cause an error in the calling function.
*/
be_pushint(vm, intv * (is_neg ? -1 : 1));
json--;
return json;
}
breal realval = (breal) intv;
if(c == '.') {
breal deci = 0.0, point = 0.1;
/* fractional part */
c = *json++;
if(!is_digit(c)) {
/* decimal point must be followed by digit */
return NULL;
}
while (is_digit(c)) {
deci = deci + ((breal)c - '0') * point;
point *= (breal)0.1;
c = *json++;
}
realval += deci;
}
if(c == 'e' || c == 'E') {
c = *json++;
/* exponent part */
breal ratio = c == '-' ? (breal)0.1 : 10;
if (c == '+' || c == '-') {
c = *json++;
if(!is_digit(c)) {
return NULL;
}
}
if(!is_digit(c)) {
/* e and sign must be followed by digit */
return NULL;
}
unsigned int e = 0;
while (is_digit(c)) {
e = e * 10 + c - '0';
c = *json++;
}
/* e > 0 must be here to prevent infinite loops when e overflows */
while (e--) {
realval *= ratio;
}
}
be_pushreal(vm, realval * (is_neg ? -1.0 : 1.0));
json--;
return json;
return endstr;
}
/* parser json value */

View File

@ -284,7 +284,8 @@ static void tr_string(blexer *lexer)
break;
}
}
lexer->buf.len = dst - lexbuf(lexer);
size_t len = dst - lexbuf(lexer);
lexer->buf.len = strnlen(lexbuf(lexer), len);
}
static int skip_newline(blexer *lexer)

View File

@ -270,7 +270,7 @@ static void free_from_pool(bvm *vm, void* ptr, size_t old_size) {
while (pool16) {
int32_t offset = (uint8_t*)ptr - (uint8_t*) &pool16->lines[0];
// serial_debug("free_from_pool ptr=%p pool=%p offset=%i\n", ptr,pool16, offset);
if ((offset >= 0) && (offset < POOL16_SLOTS*16) && ((offset & 0x0F) == 0)) {
if ((offset >= 0) && (offset < POOL16_SLOTS*POOL16_SIZE) && ((offset & 0x0F) == 0)) {
int bit = offset >> 4;
// serial_debug("free_from_pool ptr=%p fond pool=%p bit=%i\n", ptr, pool16, bit);
// bitSet(pool16->bitmap, bit);
@ -285,7 +285,7 @@ static void free_from_pool(bvm *vm, void* ptr, size_t old_size) {
while (pool32) {
int32_t offset = (uint8_t*)ptr - (uint8_t*) &pool32->lines[0];
// serial_debug("free_from_pool pool=%p offset=%i\n", pool32, offset);
if ((offset >= 0) && (offset < POOL16_SLOTS*16) && ((offset & 0x1F) == 0)) {
if ((offset >= 0) && (offset < POOL32_SLOTS*POOL32_SIZE) && ((offset & 0x1F) == 0)) {
int bit = offset >> 5;
// serial_debug("free_from_pool ptr=%p fond pool=%p bit=%i\n", ptr, pool32, bit);
// bitSet(pool32->bitmap, bit);

View File

@ -132,10 +132,10 @@ static char* fixpath(bvm *vm, bstring *path, size_t *size)
if (var_isclosure(func)) {
base = str(cl->proto->source); /* get the source file path */
} else {
base = "/";
base = "";
}
#else
base = "/";
base = "";
#endif
split = be_splitpath(base);
*size = split - base + (size_t)str_len(path) + SUFFIX_LEN;
@ -183,11 +183,14 @@ static int open_libfile(bvm *vm, char *path, size_t size)
strcpy(path + size - SUFFIX_LEN, sfxs[idx]);
res = open_script(vm, path);
} while (idx++ < 2 && res == BE_IO_ERROR);
if (res == BE_IO_ERROR) {
#if BE_USE_SHARED_LIB
if (res == BE_IO_ERROR) {
strcpy(path + size - SUFFIX_LEN, DLL_SUFFIX);
res = open_dllib(vm, path);
}
#endif
if (res == BE_EXCEPTION) {
be_dumpexcept(vm);
}
be_free(vm, path, size);
return res;
@ -275,8 +278,8 @@ static void module_init(bvm *vm) {
}
}
/* load module to vm->top */
int be_module_load(bvm *vm, bstring *path)
/* load module to vm->top, option to cache or not */
int be_module_load_nocache(bvm *vm, bstring *path, bbool nocache)
{
int res = BE_OK;
if (!load_cached(vm, path)) {
@ -284,14 +287,22 @@ int be_module_load(bvm *vm, bstring *path)
if (res == BE_IO_ERROR)
res = load_package(vm, path);
if (res == BE_OK) {
/* on first load of the module, try running the '()' function */
/* on first load of the module, try running the 'init' function */
module_init(vm);
be_cache_module(vm, path);
if (!nocache) { /* cache the module if it is loaded successfully */
be_cache_module(vm, path);
}
}
}
return res;
}
/* load module to vm->top */
int be_module_load(bvm *vm, bstring *path)
{
return be_module_load_nocache(vm, path, bfalse);
}
BERRY_API bbool be_getmodule(bvm *vm, const char *k)
{
int res = be_module_load(vm, be_newstr(vm, k));

View File

@ -34,6 +34,7 @@ typedef struct bmodule {
bmodule* be_module_new(bvm *vm);
void be_module_delete(bvm *vm, bmodule *module);
int be_module_load(bvm *vm, bstring *path);
int be_module_load_nocache(bvm *vm, bstring *path, bbool cache);
void be_cache_module(bvm *vm, bstring *name);
int be_module_attr(bvm *vm, bmodule *module, bstring *attr, bvalue *dst);
bbool be_module_setmember(bvm *vm, bmodule *module, bstring *attr, bvalue *src);

View File

@ -69,7 +69,7 @@ static unsigned toidentifier_length(const char *s)
unsigned len = 1;
const char * p = s;
while (*p) {
if (p[0] == '_' && p[1] == 'X') {
if (p[0] == '_' && p[1] != '\0' && p[1] == 'X') {
len += 3;
p += 2;
} else if (isalnum(p[0]) || p[0] == '_') {

View File

@ -16,6 +16,28 @@
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <limits.h>
#include <float.h>
#include <math.h>
#if BE_INTGER_TYPE == 0 /* int */
#define M_IMAX INT_MAX
#define M_IMIN INT_MIN
#elif BE_INTGER_TYPE == 1 /* long */
#define M_IMAX LONG_MAX
#define M_IMIN LONG_MIN
#else /* int64_t (long long) */
#define M_IMAX LLONG_MAX
#define M_IMIN LLONG_MIN
#endif
#if BE_USE_SINGLE_FLOAT == 0 /* double */
#define BREAL_MAX DBL_MAX
#define BREAL_MIN DBL_MIN
#else
#define BREAL_MAX FLT_MAX
#define BREAL_MIN FLT_MIN
#endif
#define is_space(c) ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == '\n')
#define is_digit(c) ((c) >= '0' && (c) <= '9')
@ -279,7 +301,9 @@ BERRY_API bint be_str2int(const char *str, const char **endstr)
/* hex literal */
str += 2; /* skip 0x or 0X */
while ((c = be_char2hex(*str++)) >= 0) {
if (sum > M_IMAX / 16) goto overflow_pos;
sum = sum * 16 + c;
if (sum < 0) goto overflow_pos; /* overflow check */
}
if (endstr) {
*endstr = str - 1;
@ -292,14 +316,30 @@ BERRY_API bint be_str2int(const char *str, const char **endstr)
c = *str++;
}
while (is_digit(c)) {
sum = sum * 10 + c - '0';
if (sign == '-') {
if (sum < M_IMIN / 10) goto overflow_neg;
sum = sum * 10 - (c - '0');
if (sum > 0) goto overflow_neg; /* overflow check */
} else {
if (sum > M_IMAX / 10) goto overflow_pos;
sum = sum * 10 + (c - '0');
if (sum < 0) goto overflow_pos; /* overflow check */
}
c = *str++;
}
if (endstr) {
*endstr = str - 1;
}
return sign == '-' ? -sum : sum;
return sum;
}
overflow_pos:
if (endstr) *endstr = str - 1;
return M_IMAX;
overflow_neg:
if (endstr) *endstr = str - 1;
return M_IMIN;
}
/*******************************************************************
@ -317,42 +357,67 @@ BERRY_API breal be_str2real(const char *str, const char **endstr)
{
int c, sign;
breal sum = 0, deci = 0, point = (breal)0.1;
skip_space(str);
sign = c = *str++;
if (c == '+' || c == '-') {
c = *str++;
}
if (c == '+' || c == '-') c = *str++; /* skip sign if present */
/* Integer part with overflow check */
while (is_digit(c)) {
sum = sum * 10 + c - '0';
if (sum > BREAL_MAX / 10) goto overflow;
sum = sum * 10 + (c - '0');
if (sum > BREAL_MAX) goto overflow;
c = *str++;
}
/* Fractional part */
if (c == '.') {
c = *str++;
while (is_digit(c)) {
deci = deci + ((breal)c - '0') * point;
breal digit = (c - '0') * point;
if (deci + digit < deci) break; /* precision limit reached */
deci += digit;
point *= (breal)0.1;
c = *str++;
}
}
sum = sum + deci;
sum += deci;
if (sum > BREAL_MAX) goto overflow;
/* Scientific notation */
if (c == 'e' || c == 'E') {
int e = 0;
breal ratio = (c = *str++) == '-' ? (breal)0.1 : 10;
if (c == '+' || c == '-') {
c = *str++;
}
int e = 0, esign = 1;
c = *str++;
if (c == '-') { esign = -1; c = *str++; }
else if (c == '+') c = *str++;
while (is_digit(c)) {
e = e * 10 + c - '0';
if (e > 300) goto overflow;
e = e * 10 + (c - '0');
c = *str++;
}
e *= esign;
breal ratio = (e < 0) ? (breal)0.1 : 10;
if (e < 0) e = -e;
while (e--) {
if (e > 0 && sum > BREAL_MAX / ratio) goto overflow;
sum *= ratio;
}
}
if (endstr) {
*endstr = str - 1;
}
if (endstr) *endstr = str - 1;
return sign == '-' ? -sum : sum;
overflow:
if (endstr) *endstr = str - 1;
#if BE_USE_SINGLE_FLOAT == 0
return sign == '-' ? -HUGE_VAL : HUGE_VAL;
#else
return sign == '-' ? -HUGE_VALF : HUGE_VALF;
#endif
}
/* convert a string to a number (integer or real).
@ -1009,14 +1074,17 @@ static int str_endswith(bvm *vm)
bbool result = bfalse;
const char *s = be_tostring(vm, 1);
const char *p = be_tostring(vm, 2);
size_t len = (size_t)be_strlen(vm, 2);
if (case_insensitive) {
if (str_strncasecmp(s + (int)strlen(s) - (int)len, p, len) == 0) {
result = btrue;
}
} else {
if (strncmp(s + (int)strlen(s) - (int)len, p, len) == 0) {
result = btrue;
size_t len_s = (size_t)be_strlen(vm, 1);
size_t len_p = (size_t)be_strlen(vm, 2);
if (len_s >= len_p) {
if (case_insensitive) {
if (str_strncasecmp(s + (int)len_s - (int)len_p, p, len_p) == 0) {
result = btrue;
}
} else {
if (strncmp(s + (int)len_s - (int)len_p, p, len_p) == 0) {
result = btrue;
}
}
}
be_pushbool(vm, result);

View File

@ -725,6 +725,16 @@ typedef int (*bctypefunc)(bvm*, const void*); /**< bctypefunc */
*/
#define be_loadfile(vm, name) be_loadmode((vm), (name), 0)
/**
* @def be_loadfile
* @note FFI function
* @brief be_loadfile
*
* @param vm virtual machine instance virtual machine instance
* @param name (???)
*/
#define be_loadfile_local(vm, name, islocal) be_loadmode((vm), (name), islocal)
/**
* @def be_loadmodule
* @note FFI function
@ -742,12 +752,24 @@ typedef int (*bctypefunc)(bvm*, const void*); /**< bctypefunc */
* @brief be_loadstring
*
* @param vm virtual machine instance virtual machine instance
* @param str (???)
* @param str Berry code to be compiled in global context
*
*/
#define be_loadstring(vm, str) \
be_loadbuffer((vm), "string", (str), strlen(str))
/**
* @def be_loadstring_local
* @note FFI function
* @brief be_loadstring
*
* @param vm virtual machine instance virtual machine instance
* @param str Berry code to be compiled in local or global context
*
*/
#define be_loadstring_local(vm, str, islocal) \
be_loadbuffer_local((vm), "string", (str), strlen(str), islocal)
/**
* @def be_dostring
* @note FFI function
@ -2190,7 +2212,7 @@ BERRY_API bctypefunc be_get_ctype_func_hanlder(bvm *vm);
/**
* @fn int be_loadbuffer(bvm*, const char*, const char*, size_t)
* @note code load API
* @brief load a piece of source code from the buffer and compile it into bytecode
* @brief load a piece of source code from the buffer and compile it into bytecode, in global context
*
* f the compilation is successful, be_loadbuffer will compile the source code into a Berry function and place
* it on the top of the virtual stack. If the compilation encounters an error, be_loadbuffer will return
@ -2205,6 +2227,24 @@ BERRY_API bctypefunc be_get_ctype_func_hanlder(bvm *vm);
*/
BERRY_API int be_loadbuffer(bvm *vm, const char *name, const char *buffer, size_t length);
/**
* @fn int be_loadbuffer_local(bvm*, const char*, const char*, size_t)
* @note code load API
* @brief load a piece of source code from the buffer and compile it into bytecode, in local or global context
*
* f the compilation is successful, be_loadbuffer will compile the source code into a Berry function and place
* it on the top of the virtual stack. If the compilation encounters an error, be_loadbuffer will return
* an error value of type berrorcode (Section errorcode), and if possible, will store the
* specific error message string at the top of the virtual stack.
*
* @param vm virtual machine instance
* @param name string, which is usually used to mark the source of the source code
* @param buffer buffer for storing the source code
* @param length length of the buffer
* @return (???)
*/
BERRY_API int be_loadbuffer_local(bvm *vm, const char *name, const char *buffer, size_t length, bbool islocal);
/**
* @fn int be_loadmode(bvm *vm, const char *name, bbool islocal)
* @note code load API

View File

@ -354,3 +354,9 @@ assert(b.appendb64(c, 2) == bytes("AABBCC49673D3D"))
b = bytes("AABBCC")
assert(bytes().fromstring(bytes("11").tob64()) == bytes('45513D3D'))
assert(b.appendb64(c, 1, 1) == bytes("AABBCC45513D3D"))
#- asstring truncates if NULL is present -#
s=bytes("414243").asstring()
assert(size(s) == 3)
s=bytes("410000").asstring()
assert(size(s) == 1)

View File

@ -84,3 +84,6 @@ var malformed_numbers = [
for i : malformed_numbers
test_source(i, 'malformed number')
end
#- ensure that string literal with NULL character is truncated -#
assert(size('aa\000bb\000cc') == 2)

View File

@ -32,6 +32,9 @@ extern int m_aes_ctr_tag(bvm *vm);
extern int m_aes_cbc_encrypt1(bvm *vm);
extern int m_aes_cbc_decrypt1(bvm *vm);
extern int m_chacha20_run(bvm *vm);
extern int m_poly1305_run(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);
@ -46,6 +49,10 @@ extern int m_ec_p256_mul(bvm *vm);
extern int m_ec_c25519_pubkey(bvm *vm);
extern int m_ec_c25519_sharedkey(bvm *vm);
extern int m_ed25519_sign(bvm *vm);
extern int m_ed25519_verify(bvm *vm);
extern int m_ed25519_secret_key(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);
@ -68,8 +75,10 @@ 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_aes_cbc.h"
#include "be_fixed_be_class_chacha_poly.h"
#include "be_fixed_be_class_ec_p256.h"
#include "be_fixed_be_class_ec_c25519.h"
#include "be_fixed_be_class_ed25519.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"
@ -95,6 +104,10 @@ const be_const_member_t be_crypto_members[] = {
{ "/AES_GCM", (intptr_t) &be_class_aes_gcm },
#endif // USE_BERRY_CRYPTO_AES_GCM
#ifdef USE_BERRY_CRYPTO_CHACHA_POLY
{ "/CHACHA20_POLY1305", (intptr_t) &be_class_chacha_poly },
#endif // USE_BERRY_CRYPTO_CHACHA_POLY
#ifdef USE_BERRY_CRYPTO_EC_C25519
{ "/EC_C25519", (intptr_t) &be_class_ec_c25519 },
#endif // USE_BERRY_CRYPTO_EC_C25519
@ -103,6 +116,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_ED25519
{ "/ED25519", (intptr_t) &be_class_ed25519 },
#endif // USE_BERRY_CRYPTO_ED25519
#ifdef USE_BERRY_CRYPTO_HKDF_SHA256
{ "/HKDF_SHA256", (intptr_t) &be_class_hkdf_sha256 },
#endif // USE_BERRY_CRYPTO_HKDF_SHA256
@ -175,6 +192,11 @@ class be_class_aes_cbc (scope: global, name: AES_CBC) {
encrypt1, static_func(m_aes_cbc_encrypt1)
}
class be_class_chacha_poly (scope: global, name: CHACHA20_POLY1305) {
chacha_run, static_func(m_chacha20_run)
poly_run, static_func(m_poly1305_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)
@ -193,6 +215,12 @@ class be_class_ec_c25519 (scope: global, name: EC_C25519) {
shared_key, func(m_ec_c25519_sharedkey)
}
class be_class_ed25519 (scope: global, name: ED25519) {
sign, func(m_ed25519_sign)
verify, func(m_ed25519_verify)
secret_key, func(m_ed25519_secret_key)
}
class be_class_sha256 (scope: global, name: SHA256) {
.p, var

View File

@ -0,0 +1,4 @@
/********************************************************************
* Tasmota dyn class
*******************************************************************/
#include "solidify/solidified_sortedmap.h"

View File

@ -14,6 +14,7 @@
extern int w_webserver_member(bvm *vm);
extern int w_webserver_on(bvm *vm);
extern int w_webserver_remove_route(bvm *vm);
extern int w_webserver_state(bvm *vm);
extern int w_webserver_check_privileged_access(bvm *vm);
@ -27,6 +28,7 @@ extern int w_webserver_content_flush(bvm *vm);
extern int w_webserver_content_stop(bvm *vm);
extern int w_webserver_content_close(bvm *vm);
extern int w_webserver_content_button(bvm *vm);
extern int w_webserver_content_status_sticker(bvm *vm);
extern int w_webserver_html_escape(bvm *vm);
@ -41,7 +43,7 @@ extern int w_webserver_header(bvm *vm);
// model from Arduino framework.
// We use our own list of callbacks
#define WEBSERVER_REQ_HANDLER_HOOK_MAX 16 // max number of callbacks, each callback requires a distinct address
#define WEBSERVER_REQ_HANDLER_HOOK_MAX 32 // max number of callbacks, each callback requires a distinct address
typedef struct be_webserver_callback_hook_t {
bvm *vm; // make sure we are using the same VM
bvalue f; // the Berry function to call
@ -69,6 +71,22 @@ WEBSERVER_HOOK_CB(12);
WEBSERVER_HOOK_CB(13);
WEBSERVER_HOOK_CB(14);
WEBSERVER_HOOK_CB(15);
WEBSERVER_HOOK_CB(16);
WEBSERVER_HOOK_CB(17);
WEBSERVER_HOOK_CB(18);
WEBSERVER_HOOK_CB(19);
WEBSERVER_HOOK_CB(20);
WEBSERVER_HOOK_CB(21);
WEBSERVER_HOOK_CB(22);
WEBSERVER_HOOK_CB(23);
WEBSERVER_HOOK_CB(24);
WEBSERVER_HOOK_CB(25);
WEBSERVER_HOOK_CB(26);
WEBSERVER_HOOK_CB(27);
WEBSERVER_HOOK_CB(28);
WEBSERVER_HOOK_CB(29);
WEBSERVER_HOOK_CB(30);
WEBSERVER_HOOK_CB(31);
// array of callbacks
static const berry_webserver_cb_t berry_callback_array[WEBSERVER_REQ_HANDLER_HOOK_MAX] = {
@ -88,17 +106,46 @@ static const berry_webserver_cb_t berry_callback_array[WEBSERVER_REQ_HANDLER_HOO
berry_webserver_cb_13,
berry_webserver_cb_14,
berry_webserver_cb_15,
berry_webserver_cb_16,
berry_webserver_cb_17,
berry_webserver_cb_18,
berry_webserver_cb_19,
berry_webserver_cb_20,
berry_webserver_cb_21,
berry_webserver_cb_22,
berry_webserver_cb_23,
berry_webserver_cb_24,
berry_webserver_cb_25,
berry_webserver_cb_26,
berry_webserver_cb_27,
berry_webserver_cb_28,
berry_webserver_cb_29,
berry_webserver_cb_30,
berry_webserver_cb_31,
};
// Return slot number
// -1 if no more available
berry_webserver_cb_t be_webserver_allocate_hook(bvm *vm, int32_t slot, bvalue *f) {
if (slot < 0 || slot >= WEBSERVER_REQ_HANDLER_HOOK_MAX) return NULL; // invalid call, avoid a crash
if (be_isgcobj(f)) {
be_gc_fix_set(vm, f->v.gc, btrue); // mark the function as non-gc
}
be_webserver_cb_hooks[slot].vm = vm;
be_webserver_cb_hooks[slot].f = *f;
return berry_callback_array[slot];
}
bbool be_webserver_deallocate_hook(bvm *vm, int32_t slot) {
if (slot < 0 || slot >= WEBSERVER_REQ_HANDLER_HOOK_MAX) return bfalse; // invalid call, avoid a crash
bvalue f = be_webserver_cb_hooks[slot].f;
if (be_isgcobj(&f)) {
be_gc_fix_set(vm, f.v.gc, bfalse); // remove the marker for non-gc
}
var_setnil(&be_webserver_cb_hooks[slot].f);
return btrue;
}
/*********************************************************************************************\
* `be_webserver_cb_deinit`:
* Clean any callback for this VM
@ -143,6 +190,7 @@ module webserver (scope: global) {
member, func(w_webserver_member)
on, func(w_webserver_on)
remove_route, func(w_webserver_remove_route)
state, func(w_webserver_state)
check_privileged_access, func(w_webserver_check_privileged_access)
@ -157,6 +205,8 @@ module webserver (scope: global) {
content_close, func(w_webserver_content_close)
content_button, func(w_webserver_content_button)
content_status_sticker, func(w_webserver_content_status_sticker)
html_escape, func(w_webserver_html_escape)
arg_size, func(w_webserver_argsize)

View File

@ -8,6 +8,5 @@ python_compat.init = def (m)
global.True = true
global.False = false
global.None = nil
global.b = bytes
return m
end

View File

@ -0,0 +1,306 @@
#################################################################################
# sortedmap class
#
# Allows to use a map with members
# see https://github.com/berry-lang/berry/wiki/Chapter-8
#################################################################################
#@ solidify:sortedmap
class sortedmap
var _data # internal map for storing key-value pairs
var _keys # list for maintaining sorted keys
# Constructor
def init()
self._data = {}
self._keys = []
end
# Insert a new key-value pair or update existing value
def insert(key, value)
var is_new = !self._data.contains(key)
self._data[key] = value
if is_new
# Binary search to find insert position to maintain sorted order
var pos = self._find_insert_position(key)
self._keys.insert(pos, key)
return true
end
return false
end
# Remove a key-value pair
def remove(key)
if self._data.contains(key)
self._data.remove(key)
# Find key position in the list
var idx = self._keys.find(key)
if idx != nil
self._keys.remove(idx)
end
return true
end
return false
end
# Get a value by key, with optional default if key doesn't exist
def find(key, default)
return self._data.find(key, default)
end
# Access a value by key
def item(key)
return self._data[key]
end
# Set a value by key
def setitem(key, value)
return self.insert(key, value)
end
# Return true if map contains key
def contains(key)
return self._data.contains(key)
end
# Return number of key-value pairs
def size()
return self._data.size()
end
# Return all sorted keys
def get_keys()
return self._keys
end
# Return iterator to keys in sorted order
def keys()
return self._keys.iter()
end
# String representation
def tostring()
import string
var result = "{"
var first = true
for i : 0..self._keys.size()-1
var key = self._keys[i]
var val = self._data[key]
if !first
result += ", "
end
first = false
if type(key) == 'string'
result += string.format("'%s': ", key)
else
result += string.format("%s: ", str(key))
end
if type(val) == 'string'
result += string.format("'%s'", val)
else
result += str(val)
end
end
result += "}"
return result
end
# Iterator method for 'for x: map' style iteration
def iter()
return self._data.iter()
end
# Clear all key-value pairs
def clear()
self._data = {}
self._keys = []
end
# Remove entries with a specific value
def remove_by_value(value)
var keys_to_remove = []
# First pass: identify all keys with matching values
for i : 0..self._keys.size()-1
var key = self._keys[i]
if self._data[key] == value
keys_to_remove.push(key)
end
end
# Second pass: remove all identified keys
var removed = 0
for key : keys_to_remove
self.remove(key)
removed += 1
end
return removed # Return the number of entries removed
end
# Binary search to find insertion position for a new key
def _find_insert_position(key)
var low = 0
var high = self._keys.size() - 1
while low <= high
var mid = int((low + high) / 2)
var mid_key = self._keys[mid]
# Compare keys - this is the tricky part since Berry doesn't have
# a generic comparison operator for different types
var should_insert_after
if type(key) == type(mid_key)
# Same types, we can compare directly
should_insert_after = (key > mid_key)
else
# Different types, use string representation for ordering
should_insert_after = (str(key) > str(mid_key))
end
if should_insert_after
low = mid + 1
else
high = mid - 1
end
end
return low
end
end
#-
# Example usage:
m = sortedmap()
# Insert elements
m.insert('c', 3)
m.insert('a', 1)
m.insert('b', 2)
m.insert(1, 'number one')
m.insert(10, 'ten')
m.insert(2, 'two')
# Access using different syntaxes
print(m) # Prints in sorted key order
print(m['a']) # Access by key
print(m.get_keys()) # Get list of sorted keys
# Iteration through key-value pairs
for k : m.get_keys()
print(k, m[k])
end
# Remove elements
m.remove('b')
print(m)
-#
#-
# Test case
var m = sortedmap()
# Test initial state
assert(m.size() == 0)
assert(m.get_keys().size() == 0)
# Test insertion
m.insert('c', 3)
m.insert('a', 1)
m.insert('b', 2)
# Test size
assert(m.size() == 3)
# Test key order
assert(m.get_keys()[0] == 'a')
assert(m.get_keys()[1] == 'b')
assert(m.get_keys()[2] == 'c')
# Test retrieval
assert(m['a'] == 1)
assert(m['b'] == 2)
assert(m['c'] == 3)
# Test contains
assert(m.contains('a'))
assert(!m.contains('d'))
# Test find with default
assert(m.find('a', 0) == 1)
assert(m.find('d', 0) == 0)
# Test mixed types
m.insert(1, 'number one')
m.insert(10, 'ten')
m.insert(2, 'two')
# Check size again
assert(m.size() == 6)
# Test remove
m.remove('b')
assert(m.size() == 5)
assert(!m.contains('b'))
# Test key order after removing
var keys = m.get_keys()
assert(keys[0] == 1)
assert(keys[1] == 2)
assert(keys[2] == 10)
assert(keys[3] == 'a')
assert(keys[4] == 'c')
# Test clear
m.clear()
assert(m.size() == 0)
assert(m.get_keys().size() == 0)
# Test remove_by_value
m = sortedmap()
m.insert('a', 1)
m.insert('b', 2)
m.insert('c', 2)
m.insert('d', 3)
m.insert('e', 2)
m.insert('f', 4)
# Test removing multiple entries with the same value
var removed = m.remove_by_value(2)
assert(removed == 3, "Expected to remove 3 entries, got " + str(removed))
assert(m.size() == 3, "Expected 3 entries remaining, got " + str(m.size()))
assert(!m.contains('b'), "Key 'b' should be removed")
assert(!m.contains('c'), "Key 'c' should be removed")
assert(!m.contains('e'), "Key 'e' should be removed")
assert(m.contains('a'), "Key 'a' should still exist")
assert(m.contains('d'), "Key 'd' should still exist")
assert(m.contains('f'), "Key 'f' should still exist")
# Test removing a value that doesn't exist
removed = m.remove_by_value(100)
assert(removed == 0, "Expected to remove 0 entries, got " + str(removed))
assert(m.size() == 3, "Map size should remain unchanged")
# Test removing the last remaining entries
removed = m.remove_by_value(1)
assert(removed == 1, "Expected to remove 1 entry, got " + str(removed))
assert(m.size() == 2, "Expected 2 entries remaining, got " + str(m.size()))
# Test removing all remaining entries
m.insert('g', 3)
removed = m.remove_by_value(3)
assert(removed == 2, "Expected to remove 2 entries, got " + str(removed))
removed = m.remove_by_value(4)
assert(removed == 1, "Expected to remove 1 entry, got " + str(removed))
assert(m.size() == 0, "Map should be empty")
-#

View File

@ -423,10 +423,10 @@ class Tasmota
# Execute custom command
def exec_cmd(cmd, idx, payload)
if self._ccmd
import json
var payload_json = json.load(payload)
var cmd_found = self.find_key_i(self._ccmd, cmd) # name of the command as registered (case insensitive search)
if cmd_found != nil
import json
var payload_json = json.load(payload)
self.resolvecmnd(cmd_found) # set the command name in XdrvMailbox.command as it was registered first
self._ccmd[cmd_found](cmd_found, idx, payload, payload_json)
return true
@ -477,7 +477,7 @@ class Tasmota
# compile in-memory
var compiled_code
try
compiled_code = compile(f_name, 'file')
compiled_code = compile(f_name, 'file', true)
if (compiled_code == nil)
print(f"BRY: empty compiled file")
return false

View File

@ -17,16 +17,15 @@ be_local_closure(_anonymous_, /* name */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[ 5]) { /* constants */
( &(const bvalue[ 4]) { /* constants */
/* K0 */ be_nested_str(global),
/* K1 */ be_nested_str(True),
/* K2 */ be_nested_str(False),
/* K3 */ be_nested_str(None),
/* K4 */ be_nested_str(b),
}),
&be_const_str__anonymous_,
&be_const_str_solidified,
( &(const binstruction[10]) { /* code */
( &(const binstruction[ 8]) { /* code */
0xA4060000, // 0000 IMPORT R1 K0
0x50080200, // 0001 LDBOOL R2 1 0
0x90060202, // 0002 SETMBR R1 K1 R2
@ -34,9 +33,7 @@ be_local_closure(_anonymous_, /* name */
0x90060402, // 0004 SETMBR R1 K2 R2
0x4C080000, // 0005 LDNIL R2
0x90060602, // 0006 SETMBR R1 K3 R2
0x60080015, // 0007 GETGBL R2 G21
0x90060802, // 0008 SETMBR R1 K4 R2
0x80040000, // 0009 RET 1 R0
0x80040000, // 0007 RET 1 R0
})
)
);

View File

@ -0,0 +1,644 @@
/* Solidification of sortedmap.h */
/********************************************************************\
* Generated code, don't edit *
\********************************************************************/
#include "be_constobj.h"
// compact class 'sortedmap' ktab size: 22, total: 54 (saved 256 bytes)
static const bvalue be_ktab_class_sortedmap[22] = {
/* K0 */ be_nested_str(_data),
/* K1 */ be_nested_str(_keys),
/* K2 */ be_nested_str(insert),
/* K3 */ be_nested_str(string),
/* K4 */ be_nested_str(_X7B),
/* K5 */ be_const_int(0),
/* K6 */ be_nested_str(size),
/* K7 */ be_const_int(1),
/* K8 */ be_nested_str(_X2C_X20),
/* K9 */ be_nested_str(format),
/* K10 */ be_nested_str(_X27_X25s_X27_X3A_X20),
/* K11 */ be_nested_str(_X25s_X3A_X20),
/* K12 */ be_nested_str(_X27_X25s_X27),
/* K13 */ be_nested_str(stop_iteration),
/* K14 */ be_nested_str(_X7D),
/* K15 */ be_const_int(2),
/* K16 */ be_nested_str(push),
/* K17 */ be_nested_str(remove),
/* K18 */ be_nested_str(find),
/* K19 */ be_nested_str(contains),
/* K20 */ be_nested_str(_find_insert_position),
/* K21 */ be_nested_str(iter),
};
extern const bclass be_class_sortedmap;
/********************************************************************
** Solidified function: clear
********************************************************************/
be_local_closure(class_sortedmap_clear, /* name */
be_nested_proto(
2, /* nstack */
1, /* argc */
10, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
&be_ktab_class_sortedmap, /* shared constants */
&be_const_str_clear,
&be_const_str_solidified,
( &(const binstruction[ 7]) { /* code */
0x60040013, // 0000 GETGBL R1 G19
0x7C040000, // 0001 CALL R1 0
0x90020001, // 0002 SETMBR R0 K0 R1
0x60040012, // 0003 GETGBL R1 G18
0x7C040000, // 0004 CALL R1 0
0x90020201, // 0005 SETMBR R0 K1 R1
0x80000000, // 0006 RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: setitem
********************************************************************/
be_local_closure(class_sortedmap_setitem, /* name */
be_nested_proto(
7, /* nstack */
3, /* argc */
10, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
&be_ktab_class_sortedmap, /* shared constants */
&be_const_str_setitem,
&be_const_str_solidified,
( &(const binstruction[ 5]) { /* code */
0x8C0C0102, // 0000 GETMET R3 R0 K2
0x5C140200, // 0001 MOVE R5 R1
0x5C180400, // 0002 MOVE R6 R2
0x7C0C0600, // 0003 CALL R3 3
0x80040600, // 0004 RET 1 R3
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: tostring
********************************************************************/
be_local_closure(class_sortedmap_tostring, /* name */
be_nested_proto(
13, /* nstack */
1, /* argc */
10, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
&be_ktab_class_sortedmap, /* shared constants */
&be_const_str_tostring,
&be_const_str_solidified,
( &(const binstruction[60]) { /* code */
0xA4060600, // 0000 IMPORT R1 K3
0x58080004, // 0001 LDCONST R2 K4
0x500C0200, // 0002 LDBOOL R3 1 0
0x60100010, // 0003 GETGBL R4 G16
0x88140101, // 0004 GETMBR R5 R0 K1
0x8C140B06, // 0005 GETMET R5 R5 K6
0x7C140200, // 0006 CALL R5 1
0x04140B07, // 0007 SUB R5 R5 K7
0x40160A05, // 0008 CONNECT R5 K5 R5
0x7C100200, // 0009 CALL R4 1
0xA802002B, // 000A EXBLK 0 #0037
0x5C140800, // 000B MOVE R5 R4
0x7C140000, // 000C CALL R5 0
0x88180101, // 000D GETMBR R6 R0 K1
0x94180C05, // 000E GETIDX R6 R6 R5
0x881C0100, // 000F GETMBR R7 R0 K0
0x941C0E06, // 0010 GETIDX R7 R7 R6
0x5C200600, // 0011 MOVE R8 R3
0x74220000, // 0012 JMPT R8 #0014
0x00080508, // 0013 ADD R2 R2 K8
0x500C0000, // 0014 LDBOOL R3 0 0
0x60200004, // 0015 GETGBL R8 G4
0x5C240C00, // 0016 MOVE R9 R6
0x7C200200, // 0017 CALL R8 1
0x1C201103, // 0018 EQ R8 R8 K3
0x78220005, // 0019 JMPF R8 #0020
0x8C200309, // 001A GETMET R8 R1 K9
0x5828000A, // 001B LDCONST R10 K10
0x5C2C0C00, // 001C MOVE R11 R6
0x7C200600, // 001D CALL R8 3
0x00080408, // 001E ADD R2 R2 R8
0x70020006, // 001F JMP #0027
0x8C200309, // 0020 GETMET R8 R1 K9
0x5828000B, // 0021 LDCONST R10 K11
0x602C0008, // 0022 GETGBL R11 G8
0x5C300C00, // 0023 MOVE R12 R6
0x7C2C0200, // 0024 CALL R11 1
0x7C200600, // 0025 CALL R8 3
0x00080408, // 0026 ADD R2 R2 R8
0x60200004, // 0027 GETGBL R8 G4
0x5C240E00, // 0028 MOVE R9 R7
0x7C200200, // 0029 CALL R8 1
0x1C201103, // 002A EQ R8 R8 K3
0x78220005, // 002B JMPF R8 #0032
0x8C200309, // 002C GETMET R8 R1 K9
0x5828000C, // 002D LDCONST R10 K12
0x5C2C0E00, // 002E MOVE R11 R7
0x7C200600, // 002F CALL R8 3
0x00080408, // 0030 ADD R2 R2 R8
0x70020003, // 0031 JMP #0036
0x60200008, // 0032 GETGBL R8 G8
0x5C240E00, // 0033 MOVE R9 R7
0x7C200200, // 0034 CALL R8 1
0x00080408, // 0035 ADD R2 R2 R8
0x7001FFD3, // 0036 JMP #000B
0x5810000D, // 0037 LDCONST R4 K13
0xAC100200, // 0038 CATCH R4 1 0
0xB0080000, // 0039 RAISE 2 R0 R0
0x0008050E, // 003A ADD R2 R2 K14
0x80040400, // 003B RET 1 R2
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: item
********************************************************************/
be_local_closure(class_sortedmap_item, /* name */
be_nested_proto(
3, /* nstack */
2, /* argc */
10, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
&be_ktab_class_sortedmap, /* shared constants */
&be_const_str_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: _find_insert_position
********************************************************************/
be_local_closure(class_sortedmap__find_insert_position, /* name */
be_nested_proto(
10, /* nstack */
2, /* argc */
10, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
&be_ktab_class_sortedmap, /* shared constants */
&be_const_str__find_insert_position,
&be_const_str_solidified,
( &(const binstruction[41]) { /* code */
0x58080005, // 0000 LDCONST R2 K5
0x880C0101, // 0001 GETMBR R3 R0 K1
0x8C0C0706, // 0002 GETMET R3 R3 K6
0x7C0C0200, // 0003 CALL R3 1
0x040C0707, // 0004 SUB R3 R3 K7
0x18100403, // 0005 LE R4 R2 R3
0x78120020, // 0006 JMPF R4 #0028
0x60100009, // 0007 GETGBL R4 G9
0x00140403, // 0008 ADD R5 R2 R3
0x0C140B0F, // 0009 DIV R5 R5 K15
0x7C100200, // 000A CALL R4 1
0x88140101, // 000B GETMBR R5 R0 K1
0x94140A04, // 000C GETIDX R5 R5 R4
0x4C180000, // 000D LDNIL R6
0x601C0004, // 000E GETGBL R7 G4
0x5C200200, // 000F MOVE R8 R1
0x7C1C0200, // 0010 CALL R7 1
0x60200004, // 0011 GETGBL R8 G4
0x5C240A00, // 0012 MOVE R9 R5
0x7C200200, // 0013 CALL R8 1
0x1C1C0E08, // 0014 EQ R7 R7 R8
0x781E0002, // 0015 JMPF R7 #0019
0x241C0205, // 0016 GT R7 R1 R5
0x5C180E00, // 0017 MOVE R6 R7
0x70020007, // 0018 JMP #0021
0x601C0008, // 0019 GETGBL R7 G8
0x5C200200, // 001A MOVE R8 R1
0x7C1C0200, // 001B CALL R7 1
0x60200008, // 001C GETGBL R8 G8
0x5C240A00, // 001D MOVE R9 R5
0x7C200200, // 001E CALL R8 1
0x241C0E08, // 001F GT R7 R7 R8
0x5C180E00, // 0020 MOVE R6 R7
0x781A0002, // 0021 JMPF R6 #0025
0x001C0907, // 0022 ADD R7 R4 K7
0x5C080E00, // 0023 MOVE R2 R7
0x70020001, // 0024 JMP #0027
0x041C0907, // 0025 SUB R7 R4 K7
0x5C0C0E00, // 0026 MOVE R3 R7
0x7001FFDC, // 0027 JMP #0005
0x80040400, // 0028 RET 1 R2
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: remove_by_value
********************************************************************/
be_local_closure(class_sortedmap_remove_by_value, /* name */
be_nested_proto(
9, /* nstack */
2, /* argc */
10, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
&be_ktab_class_sortedmap, /* shared constants */
&be_const_str_remove_by_value,
&be_const_str_solidified,
( &(const binstruction[41]) { /* code */
0x60080012, // 0000 GETGBL R2 G18
0x7C080000, // 0001 CALL R2 0
0x600C0010, // 0002 GETGBL R3 G16
0x88100101, // 0003 GETMBR R4 R0 K1
0x8C100906, // 0004 GETMET R4 R4 K6
0x7C100200, // 0005 CALL R4 1
0x04100907, // 0006 SUB R4 R4 K7
0x40120A04, // 0007 CONNECT R4 K5 R4
0x7C0C0200, // 0008 CALL R3 1
0xA802000B, // 0009 EXBLK 0 #0016
0x5C100600, // 000A MOVE R4 R3
0x7C100000, // 000B CALL R4 0
0x88140101, // 000C GETMBR R5 R0 K1
0x94140A04, // 000D GETIDX R5 R5 R4
0x88180100, // 000E GETMBR R6 R0 K0
0x94180C05, // 000F GETIDX R6 R6 R5
0x1C180C01, // 0010 EQ R6 R6 R1
0x781A0002, // 0011 JMPF R6 #0015
0x8C180510, // 0012 GETMET R6 R2 K16
0x5C200A00, // 0013 MOVE R8 R5
0x7C180400, // 0014 CALL R6 2
0x7001FFF3, // 0015 JMP #000A
0x580C000D, // 0016 LDCONST R3 K13
0xAC0C0200, // 0017 CATCH R3 1 0
0xB0080000, // 0018 RAISE 2 R0 R0
0x580C0005, // 0019 LDCONST R3 K5
0x60100010, // 001A GETGBL R4 G16
0x5C140400, // 001B MOVE R5 R2
0x7C100200, // 001C CALL R4 1
0xA8020006, // 001D EXBLK 0 #0025
0x5C140800, // 001E MOVE R5 R4
0x7C140000, // 001F CALL R5 0
0x8C180111, // 0020 GETMET R6 R0 K17
0x5C200A00, // 0021 MOVE R8 R5
0x7C180400, // 0022 CALL R6 2
0x000C0707, // 0023 ADD R3 R3 K7
0x7001FFF8, // 0024 JMP #001E
0x5810000D, // 0025 LDCONST R4 K13
0xAC100200, // 0026 CATCH R4 1 0
0xB0080000, // 0027 RAISE 2 R0 R0
0x80040600, // 0028 RET 1 R3
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: find
********************************************************************/
be_local_closure(class_sortedmap_find, /* name */
be_nested_proto(
7, /* nstack */
3, /* argc */
10, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
&be_ktab_class_sortedmap, /* shared constants */
&be_const_str_find,
&be_const_str_solidified,
( &(const binstruction[ 6]) { /* code */
0x880C0100, // 0000 GETMBR R3 R0 K0
0x8C0C0712, // 0001 GETMET R3 R3 K18
0x5C140200, // 0002 MOVE R5 R1
0x5C180400, // 0003 MOVE R6 R2
0x7C0C0600, // 0004 CALL R3 3
0x80040600, // 0005 RET 1 R3
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: insert
********************************************************************/
be_local_closure(class_sortedmap_insert, /* name */
be_nested_proto(
9, /* nstack */
3, /* argc */
10, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
&be_ktab_class_sortedmap, /* shared constants */
&be_const_str_insert,
&be_const_str_solidified,
( &(const binstruction[22]) { /* code */
0x880C0100, // 0000 GETMBR R3 R0 K0
0x8C0C0713, // 0001 GETMET R3 R3 K19
0x5C140200, // 0002 MOVE R5 R1
0x7C0C0400, // 0003 CALL R3 2
0x780E0000, // 0004 JMPF R3 #0006
0x500C0001, // 0005 LDBOOL R3 0 1
0x500C0200, // 0006 LDBOOL R3 1 0
0x88100100, // 0007 GETMBR R4 R0 K0
0x98100202, // 0008 SETIDX R4 R1 R2
0x780E0009, // 0009 JMPF R3 #0014
0x8C100114, // 000A GETMET R4 R0 K20
0x5C180200, // 000B MOVE R6 R1
0x7C100400, // 000C CALL R4 2
0x88140101, // 000D GETMBR R5 R0 K1
0x8C140B02, // 000E GETMET R5 R5 K2
0x5C1C0800, // 000F MOVE R7 R4
0x5C200200, // 0010 MOVE R8 R1
0x7C140600, // 0011 CALL R5 3
0x50140200, // 0012 LDBOOL R5 1 0
0x80040A00, // 0013 RET 1 R5
0x50100000, // 0014 LDBOOL R4 0 0
0x80040800, // 0015 RET 1 R4
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: get_keys
********************************************************************/
be_local_closure(class_sortedmap_get_keys, /* name */
be_nested_proto(
2, /* nstack */
1, /* argc */
10, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
&be_ktab_class_sortedmap, /* shared constants */
&be_const_str_get_keys,
&be_const_str_solidified,
( &(const binstruction[ 2]) { /* code */
0x88040101, // 0000 GETMBR R1 R0 K1
0x80040200, // 0001 RET 1 R1
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: keys
********************************************************************/
be_local_closure(class_sortedmap_keys, /* name */
be_nested_proto(
3, /* nstack */
1, /* argc */
10, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
&be_ktab_class_sortedmap, /* shared constants */
&be_const_str_keys,
&be_const_str_solidified,
( &(const binstruction[ 4]) { /* code */
0x88040101, // 0000 GETMBR R1 R0 K1
0x8C040315, // 0001 GETMET R1 R1 K21
0x7C040200, // 0002 CALL R1 1
0x80040200, // 0003 RET 1 R1
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: remove
********************************************************************/
be_local_closure(class_sortedmap_remove, /* name */
be_nested_proto(
6, /* nstack */
2, /* argc */
10, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
&be_ktab_class_sortedmap, /* shared constants */
&be_const_str_remove,
&be_const_str_solidified,
( &(const binstruction[24]) { /* code */
0x88080100, // 0000 GETMBR R2 R0 K0
0x8C080513, // 0001 GETMET R2 R2 K19
0x5C100200, // 0002 MOVE R4 R1
0x7C080400, // 0003 CALL R2 2
0x780A0010, // 0004 JMPF R2 #0016
0x88080100, // 0005 GETMBR R2 R0 K0
0x8C080511, // 0006 GETMET R2 R2 K17
0x5C100200, // 0007 MOVE R4 R1
0x7C080400, // 0008 CALL R2 2
0x88080101, // 0009 GETMBR R2 R0 K1
0x8C080512, // 000A GETMET R2 R2 K18
0x5C100200, // 000B MOVE R4 R1
0x7C080400, // 000C CALL R2 2
0x4C0C0000, // 000D LDNIL R3
0x200C0403, // 000E NE R3 R2 R3
0x780E0003, // 000F JMPF R3 #0014
0x880C0101, // 0010 GETMBR R3 R0 K1
0x8C0C0711, // 0011 GETMET R3 R3 K17
0x5C140400, // 0012 MOVE R5 R2
0x7C0C0400, // 0013 CALL R3 2
0x500C0200, // 0014 LDBOOL R3 1 0
0x80040600, // 0015 RET 1 R3
0x50080000, // 0016 LDBOOL R2 0 0
0x80040400, // 0017 RET 1 R2
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: size
********************************************************************/
be_local_closure(class_sortedmap_size, /* name */
be_nested_proto(
3, /* nstack */
1, /* argc */
10, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
&be_ktab_class_sortedmap, /* shared constants */
&be_const_str_size,
&be_const_str_solidified,
( &(const binstruction[ 4]) { /* code */
0x88040100, // 0000 GETMBR R1 R0 K0
0x8C040306, // 0001 GETMET R1 R1 K6
0x7C040200, // 0002 CALL R1 1
0x80040200, // 0003 RET 1 R1
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: contains
********************************************************************/
be_local_closure(class_sortedmap_contains, /* name */
be_nested_proto(
5, /* nstack */
2, /* argc */
10, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
&be_ktab_class_sortedmap, /* shared constants */
&be_const_str_contains,
&be_const_str_solidified,
( &(const binstruction[ 5]) { /* code */
0x88080100, // 0000 GETMBR R2 R0 K0
0x8C080513, // 0001 GETMET R2 R2 K19
0x5C100200, // 0002 MOVE R4 R1
0x7C080400, // 0003 CALL R2 2
0x80040400, // 0004 RET 1 R2
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: iter
********************************************************************/
be_local_closure(class_sortedmap_iter, /* name */
be_nested_proto(
3, /* nstack */
1, /* argc */
10, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
&be_ktab_class_sortedmap, /* shared constants */
&be_const_str_iter,
&be_const_str_solidified,
( &(const binstruction[ 4]) { /* code */
0x88040100, // 0000 GETMBR R1 R0 K0
0x8C040315, // 0001 GETMET R1 R1 K21
0x7C040200, // 0002 CALL R1 1
0x80040200, // 0003 RET 1 R1
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified function: init
********************************************************************/
be_local_closure(class_sortedmap_init, /* name */
be_nested_proto(
2, /* nstack */
1, /* argc */
10, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
&be_ktab_class_sortedmap, /* shared constants */
&be_const_str_init,
&be_const_str_solidified,
( &(const binstruction[ 7]) { /* code */
0x60040013, // 0000 GETGBL R1 G19
0x7C040000, // 0001 CALL R1 0
0x90020001, // 0002 SETMBR R0 K0 R1
0x60040012, // 0003 GETGBL R1 G18
0x7C040000, // 0004 CALL R1 0
0x90020201, // 0005 SETMBR R0 K1 R1
0x80000000, // 0006 RET 0
})
)
);
/*******************************************************************/
/********************************************************************
** Solidified class: sortedmap
********************************************************************/
be_local_class(sortedmap,
2,
NULL,
be_nested_map(17,
( (struct bmapnode*) &(const bmapnode[]) {
{ be_const_key(_data, -1), be_const_var(0) },
{ be_const_key(remove, -1), be_const_closure(class_sortedmap_remove_closure) },
{ be_const_key(tostring, -1), be_const_closure(class_sortedmap_tostring_closure) },
{ be_const_key(item, -1), be_const_closure(class_sortedmap_item_closure) },
{ be_const_key(_find_insert_position, -1), be_const_closure(class_sortedmap__find_insert_position_closure) },
{ be_const_key(remove_by_value, -1), be_const_closure(class_sortedmap_remove_by_value_closure) },
{ be_const_key(find, -1), be_const_closure(class_sortedmap_find_closure) },
{ be_const_key(insert, -1), be_const_closure(class_sortedmap_insert_closure) },
{ be_const_key(get_keys, -1), be_const_closure(class_sortedmap_get_keys_closure) },
{ be_const_key(keys, 13), be_const_closure(class_sortedmap_keys_closure) },
{ be_const_key(setitem, 1), be_const_closure(class_sortedmap_setitem_closure) },
{ be_const_key(size, -1), be_const_closure(class_sortedmap_size_closure) },
{ be_const_key(contains, -1), be_const_closure(class_sortedmap_contains_closure) },
{ be_const_key(_keys, -1), be_const_var(1) },
{ be_const_key(iter, -1), be_const_closure(class_sortedmap_iter_closure) },
{ be_const_key(init, -1), be_const_closure(class_sortedmap_init_closure) },
{ be_const_key(clear, 0), be_const_closure(class_sortedmap_clear_closure) },
})),
(bstring*) &be_const_str_sortedmap
);
/********************************************************************/
/* End of solidification */

View File

@ -37,9 +37,9 @@ static const bvalue be_ktab_class_Tasmota[164] = {
/* K28 */ be_nested_str(_timers),
/* K29 */ be_nested_str(millis),
/* K30 */ be_nested_str(_ccmd),
/* K31 */ be_nested_str(json),
/* K32 */ be_nested_str(load),
/* K33 */ be_nested_str(find_key_i),
/* K31 */ be_nested_str(find_key_i),
/* K32 */ be_nested_str(json),
/* K33 */ be_nested_str(load),
/* K34 */ be_nested_str(resolvecmnd),
/* K35 */ be_nested_str(wifi),
/* K36 */ be_nested_str(up),
@ -527,26 +527,26 @@ be_local_closure(class_Tasmota_exec_cmd, /* name */
( &(const binstruction[27]) { /* code */
0x8810011E, // 0000 GETMBR R4 R0 K30
0x78120016, // 0001 JMPF R4 #0019
0xA4123E00, // 0002 IMPORT R4 K31
0x8C140920, // 0003 GETMET R5 R4 K32
0x5C1C0600, // 0004 MOVE R7 R3
0x7C140400, // 0005 CALL R5 2
0x8C180121, // 0006 GETMET R6 R0 K33
0x8820011E, // 0007 GETMBR R8 R0 K30
0x5C240200, // 0008 MOVE R9 R1
0x7C180600, // 0009 CALL R6 3
0x4C1C0000, // 000A LDNIL R7
0x201C0C07, // 000B NE R7 R6 R7
0x781E000B, // 000C JMPF R7 #0019
0x8C10011F, // 0002 GETMET R4 R0 K31
0x8818011E, // 0003 GETMBR R6 R0 K30
0x5C1C0200, // 0004 MOVE R7 R1
0x7C100600, // 0005 CALL R4 3
0x4C140000, // 0006 LDNIL R5
0x20140805, // 0007 NE R5 R4 R5
0x7816000F, // 0008 JMPF R5 #0019
0xA4164000, // 0009 IMPORT R5 K32
0x8C180B21, // 000A GETMET R6 R5 K33
0x5C200600, // 000B MOVE R8 R3
0x7C180400, // 000C CALL R6 2
0x8C1C0122, // 000D GETMET R7 R0 K34
0x5C240C00, // 000E MOVE R9 R6
0x5C240800, // 000E MOVE R9 R4
0x7C1C0400, // 000F CALL R7 2
0x881C011E, // 0010 GETMBR R7 R0 K30
0x941C0E06, // 0011 GETIDX R7 R7 R6
0x5C200C00, // 0012 MOVE R8 R6
0x941C0E04, // 0011 GETIDX R7 R7 R4
0x5C200800, // 0012 MOVE R8 R4
0x5C240400, // 0013 MOVE R9 R2
0x5C280600, // 0014 MOVE R10 R3
0x5C2C0A00, // 0015 MOVE R11 R5
0x5C2C0C00, // 0015 MOVE R11 R6
0x7C1C0800, // 0016 CALL R7 4
0x501C0200, // 0017 LDBOOL R7 1 0
0x80040E00, // 0018 RET 1 R7
@ -1549,8 +1549,8 @@ be_local_closure(class_Tasmota_exec_tele, /* name */
( &(const binstruction[41]) { /* code */
0x88080106, // 0000 GETMBR R2 R0 K6
0x780A0024, // 0001 JMPF R2 #0027
0xA40A3E00, // 0002 IMPORT R2 K31
0x8C0C0520, // 0003 GETMET R3 R2 K32
0xA40A4000, // 0002 IMPORT R2 K32
0x8C0C0521, // 0003 GETMET R3 R2 K33
0x5C140200, // 0004 MOVE R5 R1
0x7C0C0400, // 0005 CALL R3 2
0x50100000, // 0006 LDBOOL R4 0 0
@ -2250,11 +2250,11 @@ be_local_closure(class_Tasmota_exec_rules, /* name */
0x4C100000, // 0003 LDNIL R4
0x20100604, // 0004 NE R4 R3 R4
0x78120033, // 0005 JMPF R4 #003A
0xA4123E00, // 0006 IMPORT R4 K31
0xA4124000, // 0006 IMPORT R4 K32
0x4C140000, // 0007 LDNIL R5
0x90025605, // 0008 SETMBR R0 K43 R5
0x50140000, // 0009 LDBOOL R5 0 0
0x8C180920, // 000A GETMET R6 R4 K32
0x8C180921, // 000A GETMET R6 R4 K33
0x5C200200, // 000B MOVE R8 R1
0x7C180400, // 000C CALL R6 2
0x4C1C0000, // 000D LDNIL R7
@ -2652,7 +2652,7 @@ be_local_closure(class_Tasmota_compile, /* name */
&be_ktab_class_Tasmota, /* shared constants */
&be_const_str_compile,
&be_const_str_solidified,
( &(const binstruction[84]) { /* code */
( &(const binstruction[85]) { /* code */
0xA40A7800, // 0000 IMPORT R2 K60
0x8C0C0574, // 0001 GETMET R3 R2 K116
0x5C140200, // 0002 MOVE R5 R1
@ -2681,62 +2681,63 @@ be_local_closure(class_Tasmota_compile, /* name */
0x500C0000, // 0019 LDBOOL R3 0 0
0x80040600, // 001A RET 1 R3
0x4C0C0000, // 001B LDNIL R3
0xA8020011, // 001C EXBLK 0 #002F
0xA8020012, // 001C EXBLK 0 #0030
0x6010000D, // 001D GETGBL R4 G13
0x5C140200, // 001E MOVE R5 R1
0x58180092, // 001F LDCONST R6 K146
0x7C100400, // 0020 CALL R4 2
0x5C0C0800, // 0021 MOVE R3 R4
0x4C100000, // 0022 LDNIL R4
0x1C100604, // 0023 EQ R4 R3 R4
0x78120007, // 0024 JMPF R4 #002D
0x60100001, // 0025 GETGBL R4 G1
0x60140018, // 0026 GETGBL R5 G24
0x58180093, // 0027 LDCONST R6 K147
0x7C140200, // 0028 CALL R5 1
0x7C100200, // 0029 CALL R4 1
0x50100000, // 002A LDBOOL R4 0 0
0xA8040001, // 002B EXBLK 1 1
0x80040800, // 002C RET 1 R4
0xA8040001, // 002D EXBLK 1 1
0x7002000D, // 002E JMP #003D
0xAC100002, // 002F CATCH R4 0 2
0x7002000A, // 0030 JMP #003C
0x60180001, // 0031 GETGBL R6 G1
0x601C0018, // 0032 GETGBL R7 G24
0x58200094, // 0033 LDCONST R8 K148
0x5C240200, // 0034 MOVE R9 R1
0x5C280800, // 0035 MOVE R10 R4
0x5C2C0A00, // 0036 MOVE R11 R5
0x7C1C0800, // 0037 CALL R7 4
0x7C180200, // 0038 CALL R6 1
0x50180000, // 0039 LDBOOL R6 0 0
0x80040C00, // 003A RET 1 R6
0x70020000, // 003B JMP #003D
0xB0080000, // 003C RAISE 2 R0 R0
0x00100376, // 003D ADD R4 R1 K118
0xA8020005, // 003E EXBLK 0 #0045
0x8C14018D, // 003F GETMET R5 R0 K141
0x5C1C0800, // 0040 MOVE R7 R4
0x5C200600, // 0041 MOVE R8 R3
0x7C140600, // 0042 CALL R5 3
0xA8040001, // 0043 EXBLK 1 1
0x7002000C, // 0044 JMP #0052
0xAC140001, // 0045 CATCH R5 0 1
0x70020009, // 0046 JMP #0051
0x60180001, // 0047 GETGBL R6 G1
0x601C0018, // 0048 GETGBL R7 G24
0x58200095, // 0049 LDCONST R8 K149
0x5C240800, // 004A MOVE R9 R4
0x5C280A00, // 004B MOVE R10 R5
0x7C1C0600, // 004C CALL R7 3
0x7C180200, // 004D CALL R6 1
0x50180000, // 004E LDBOOL R6 0 0
0x80040C00, // 004F RET 1 R6
0x70020000, // 0050 JMP #0052
0xB0080000, // 0051 RAISE 2 R0 R0
0x50140200, // 0052 LDBOOL R5 1 0
0x80040A00, // 0053 RET 1 R5
0x501C0200, // 0020 LDBOOL R7 1 0
0x7C100600, // 0021 CALL R4 3
0x5C0C0800, // 0022 MOVE R3 R4
0x4C100000, // 0023 LDNIL R4
0x1C100604, // 0024 EQ R4 R3 R4
0x78120007, // 0025 JMPF R4 #002E
0x60100001, // 0026 GETGBL R4 G1
0x60140018, // 0027 GETGBL R5 G24
0x58180093, // 0028 LDCONST R6 K147
0x7C140200, // 0029 CALL R5 1
0x7C100200, // 002A CALL R4 1
0x50100000, // 002B LDBOOL R4 0 0
0xA8040001, // 002C EXBLK 1 1
0x80040800, // 002D RET 1 R4
0xA8040001, // 002E EXBLK 1 1
0x7002000D, // 002F JMP #003E
0xAC100002, // 0030 CATCH R4 0 2
0x7002000A, // 0031 JMP #003D
0x60180001, // 0032 GETGBL R6 G1
0x601C0018, // 0033 GETGBL R7 G24
0x58200094, // 0034 LDCONST R8 K148
0x5C240200, // 0035 MOVE R9 R1
0x5C280800, // 0036 MOVE R10 R4
0x5C2C0A00, // 0037 MOVE R11 R5
0x7C1C0800, // 0038 CALL R7 4
0x7C180200, // 0039 CALL R6 1
0x50180000, // 003A LDBOOL R6 0 0
0x80040C00, // 003B RET 1 R6
0x70020000, // 003C JMP #003E
0xB0080000, // 003D RAISE 2 R0 R0
0x00100376, // 003E ADD R4 R1 K118
0xA8020005, // 003F EXBLK 0 #0046
0x8C14018D, // 0040 GETMET R5 R0 K141
0x5C1C0800, // 0041 MOVE R7 R4
0x5C200600, // 0042 MOVE R8 R3
0x7C140600, // 0043 CALL R5 3
0xA8040001, // 0044 EXBLK 1 1
0x7002000C, // 0045 JMP #0053
0xAC140001, // 0046 CATCH R5 0 1
0x70020009, // 0047 JMP #0052
0x60180001, // 0048 GETGBL R6 G1
0x601C0018, // 0049 GETGBL R7 G24
0x58200095, // 004A LDCONST R8 K149
0x5C240800, // 004B MOVE R9 R4
0x5C280A00, // 004C MOVE R10 R5
0x7C1C0600, // 004D CALL R7 3
0x7C180200, // 004E CALL R6 1
0x50180000, // 004F LDBOOL R6 0 0
0x80040C00, // 0050 RET 1 R6
0x70020000, // 0051 JMP #0053
0xB0080000, // 0052 RAISE 2 R0 R0
0x50140200, // 0053 LDBOOL R5 1 0
0x80040A00, // 0054 RET 1 R5
})
)
);

View File

@ -75,5 +75,28 @@
#define NIMBLE_LOGC( tag, format, ... ) console_printf("CRIT %s: " format "\n", tag, ##__VA_ARGS__)
// The LOG_LEVEL macros are used to set the log level for the NimBLE stack, but they pollute the global namespace and would override the loglevel enum of Tasmota.
// So we undefine them here to avoid conflicts.
#ifdef LOG_LEVEL_DEBUG
#undef LOG_LEVEL_DEBUG
#endif
#ifdef LOG_LEVEL_DEBUG_MORE
#undef LOG_LEVEL_DEBUG_MORE
#endif
#ifdef LOG_LEVEL_INFO
#undef LOG_LEVEL_INFO
#endif
#ifdef LOG_LEVEL_NONE
#undef LOG_LEVEL_NONE
#endif
#ifdef LOG_LEVEL_ERROR
#undef LOG_LEVEL_ERROR
#endif
#endif /* CONFIG_BT_ENABLED */
#endif /* MAIN_NIMBLELOG_H_ */

View File

@ -176,9 +176,6 @@ struct _haspmota_theme_t {
bool inited;
haspmota_theme_styles_t styles;
lv_color_filter_dsc_t dark_filter;
lv_color_filter_dsc_t grey_filter;
#if LV_THEME_DEFAULT_TRANSITION_TIME
lv_style_transition_dsc_t trans_delayed;
lv_style_transition_dsc_t trans_normal;
@ -226,7 +223,8 @@ static void style_init(haspmota_theme_t * theme)
LV_STYLE_TRANSLATE_Y, LV_STYLE_TRANSLATE_X,
LV_STYLE_TRANSFORM_ROTATION,
LV_STYLE_TRANSFORM_SCALE_X, LV_STYLE_TRANSFORM_SCALE_Y,
LV_STYLE_COLOR_FILTER_OPA, LV_STYLE_COLOR_FILTER_DSC,
LV_STYLE_RECOLOR_OPA, LV_STYLE_RECOLOR,
// LV_STYLE_COLOR_FILTER_OPA, LV_STYLE_COLOR_FILTER_DSC,
0
};
#endif
@ -301,30 +299,28 @@ static void style_init(haspmota_theme_t * theme)
LV_DPX_CALC(theme->disp_dpi, theme->disp_size == DISP_LARGE ? 16 : theme->disp_size == DISP_MEDIUM ? 12 : 10)); // Tasmota min 10
lv_style_set_bg_opa(&theme->styles.btn, LV_OPA_COVER);
lv_style_set_bg_color(&theme->styles.btn, theme->color_grey);
// if(!(theme->base.flags & MODE_DARK)) {
// lv_style_set_shadow_color(&theme->styles.btn, lv_palette_main(LV_PALETTE_GREY));
// lv_style_set_shadow_width(&theme->styles.btn, LV_DPX(3));
// lv_style_set_shadow_opa(&theme->styles.btn, LV_OPA_50);
// lv_style_set_shadow_offset_y(&theme->styles.btn, LV_DPX_CALC(theme->disp_dpi, LV_DPX(4)));
// }
lv_style_set_text_color(&theme->styles.btn, theme->color_text);
lv_style_set_pad_hor(&theme->styles.btn, PAD_DEF);
lv_style_set_pad_ver(&theme->styles.btn, PAD_SMALL);
lv_style_set_pad_column(&theme->styles.btn, LV_DPX_CALC(theme->disp_dpi, 5));
lv_style_set_pad_row(&theme->styles.btn, LV_DPX_CALC(theme->disp_dpi, 5));
style_init_reset(&theme->styles.btn_border_color);
lv_style_set_border_color(&theme->styles.btn_border_color, lv_color_mix(theme->color_text, theme->color_grey, LV_OPA_80));
style_init_reset(&theme->styles.btn_border);
lv_style_set_border_width(&theme->styles.btn_border, BORDER_WIDTH);
lv_style_set_border_side(&theme->styles.btn_border, LV_BORDER_SIDE_FULL);
lv_style_set_border_opa(&theme->styles.btn_border, LV_OPA_COVER);
lv_color_filter_dsc_init(&theme->dark_filter, dark_color_filter_cb);
lv_color_filter_dsc_init(&theme->grey_filter, grey_filter_cb);
style_init_reset(&theme->styles.pressed);
lv_style_set_color_filter_dsc(&theme->styles.pressed, &theme->dark_filter);
lv_style_set_color_filter_opa(&theme->styles.pressed, LV_OPA_60); // Tasmota from 35 ot LV_OPA_60 (153)
lv_style_set_recolor(&theme->styles.pressed, lv_color_black());
lv_style_set_recolor_opa(&theme->styles.pressed, 70);
style_init_reset(&theme->styles.disabled);
lv_style_set_color_filter_dsc(&theme->styles.disabled, &theme->grey_filter);
lv_style_set_color_filter_opa(&theme->styles.disabled, LV_OPA_50);
if(theme_def->base.flags & MODE_DARK)
lv_style_set_recolor(&theme->styles.disabled, lv_palette_darken(LV_PALETTE_GREY, 2));
else
lv_style_set_recolor(&theme->styles.disabled, lv_palette_lighten(LV_PALETTE_GREY, 2));
lv_style_set_recolor_opa(&theme->styles.disabled, LV_OPA_50);
style_init_reset(&theme->styles.clip_corner);
lv_style_set_clip_corner(&theme->styles.clip_corner, true);
@ -430,7 +426,6 @@ static void style_init(haspmota_theme_t * theme)
style_init_reset(&theme->styles.dropdown_list);
lv_style_set_max_height(&theme->styles.dropdown_list, LV_DPI_DEF * 2);
#endif
#if LV_USE_CHECKBOX
style_init_reset(&theme->styles.cb_marker);
lv_style_set_pad_all(&theme->styles.cb_marker, LV_DPX_CALC(theme->disp_dpi, 3));
@ -1083,6 +1078,13 @@ static void theme_apply(lv_theme_t * th, lv_obj_t * obj)
lv_obj_add_style(obj, &theme->styles.bg_color_secondary_muted, LV_PART_ITEMS | LV_STATE_EDITED);
}
#endif
#if LV_USE_LABEL && LV_USE_TEXTAREA
else if(lv_obj_check_type(obj, &lv_label_class) && lv_obj_check_type(parent, &lv_textarea_class)) {
lv_obj_add_style(obj, &theme->styles.bg_color_primary, LV_PART_SELECTED);
}
#endif
#if LV_USE_LIST
else if(lv_obj_check_type(obj, &lv_list_class)) {
lv_obj_add_style(obj, &theme->styles.card, 0);

View File

@ -18,6 +18,7 @@
"+<base/ftbitmap.c>",
"+<base/ftbase.c>",
"+<base/ftstroke.c>",
"+<base/ftbbox.c>",
"+<base/ftglyph.c>",

View File

@ -15,6 +15,7 @@ anim_delete_all|||[lv_anim_delete_all](https://docs.lvgl.io/9.0/search.html?q=lv
anim_get|\<any\>, comptr|lv.anim|[lv_anim_get](https://docs.lvgl.io/9.0/search.html?q=lv_anim_get)
anim_get_timer||lv.timer|[lv_anim_get_timer](https://docs.lvgl.io/9.0/search.html?q=lv_anim_get_timer)
anim_refr_now|||[lv_anim_refr_now](https://docs.lvgl.io/9.0/search.html?q=lv_anim_refr_now)
anim_resolve_speed|int, int, int|int|[lv_anim_resolve_speed](https://docs.lvgl.io/9.0/search.html?q=lv_anim_resolve_speed)
anim_speed|int|int|[lv_anim_speed](https://docs.lvgl.io/9.0/search.html?q=lv_anim_speed)
anim_speed_clamped|int, int, int|int|[lv_anim_speed_clamped](https://docs.lvgl.io/9.0/search.html?q=lv_anim_speed_clamped)
anim_speed_to_time|int, int, int|int|[lv_anim_speed_to_time](https://docs.lvgl.io/9.0/search.html?q=lv_anim_speed_to_time)
@ -50,7 +51,10 @@ color_luminance|lv.color|int|[lv_color_luminance](https://docs.lvgl.io/9.0/searc
color_make|int, int, int|lv.color|[lv_color_make](https://docs.lvgl.io/9.0/search.html?q=lv_color_make)
color_mix|lv.color, lv.color, int|lv.color|[lv_color_mix](https://docs.lvgl.io/9.0/search.html?q=lv_color_mix)
color_mix32|int, int|int|[lv_color_mix32](https://docs.lvgl.io/9.0/search.html?q=lv_color_mix32)
color_mix32_premultiplied|int, int|int|[lv_color_mix32_premultiplied](https://docs.lvgl.io/9.0/search.html?q=lv_color_mix32_premultiplied)
color_over32|int, int|int|[lv_color_over32](https://docs.lvgl.io/9.0/search.html?q=lv_color_over32)
color_rgb_to_hsv|int, int, int|int|[lv_color_rgb_to_hsv](https://docs.lvgl.io/9.0/search.html?q=lv_color_rgb_to_hsv)
color_swap_16|int|int|[lv_color_swap_16](https://docs.lvgl.io/9.0/search.html?q=lv_color_swap_16)
color_to_32|lv.color, int|int|[lv_color_to_32](https://docs.lvgl.io/9.0/search.html?q=lv_color_to_32)
color_to_hsv|lv.color|int|[lv_color_to_hsv](https://docs.lvgl.io/9.0/search.html?q=lv_color_to_hsv)
color_to_int|lv.color|int|[lv_color_to_int](https://docs.lvgl.io/9.0/search.html?q=lv_color_to_int)
@ -59,6 +63,7 @@ color_to_u32|lv.color|int|[lv_color_to_u32](https://docs.lvgl.io/9.0/search.html
color_white||lv.color|[lv_color_white](https://docs.lvgl.io/9.0/search.html?q=lv_color_white)
display_create|int, int|lv.display|[lv_display_create](https://docs.lvgl.io/9.0/search.html?q=lv_display_create)
display_get_default||lv.display|[lv_display_get_default](https://docs.lvgl.io/9.0/search.html?q=lv_display_get_default)
display_refr_timer|lv.timer||[lv_display_refr_timer](https://docs.lvgl.io/9.0/search.html?q=lv_display_refr_timer)
dpx|int|int|[lv_dpx](https://docs.lvgl.io/9.0/search.html?q=lv_dpx)
draw_arc|lv.layer, lv.draw_arc_dsc||[lv_draw_arc](https://docs.lvgl.io/9.0/search.html?q=lv_draw_arc)
draw_arc_dsc_init|lv.draw_arc_dsc||[lv_draw_arc_dsc_init](https://docs.lvgl.io/9.0/search.html?q=lv_draw_arc_dsc_init)
@ -77,17 +82,24 @@ draw_label_dsc_init|lv.draw_label_dsc||[lv_draw_label_dsc_init](https://docs.lvg
draw_layer_alloc_buf|lv.layer|comptr|[lv_draw_layer_alloc_buf](https://docs.lvgl.io/9.0/search.html?q=lv_draw_layer_alloc_buf)
draw_layer_create|lv.layer, int, lv.area|lv.layer|[lv_draw_layer_create](https://docs.lvgl.io/9.0/search.html?q=lv_draw_layer_create)
draw_layer_go_to_xy|lv.layer, int, int|comptr|[lv_draw_layer_go_to_xy](https://docs.lvgl.io/9.0/search.html?q=lv_draw_layer_go_to_xy)
draw_layer_init|lv.layer, lv.layer, int, lv.area||[lv_draw_layer_init](https://docs.lvgl.io/9.0/search.html?q=lv_draw_layer_init)
draw_letter|lv.layer, lv.draw_letter_dsc, comptr||[lv_draw_letter](https://docs.lvgl.io/9.0/search.html?q=lv_draw_letter)
draw_letter_dsc_init|lv.draw_letter_dsc||[lv_draw_letter_dsc_init](https://docs.lvgl.io/9.0/search.html?q=lv_draw_letter_dsc_init)
draw_line|lv.layer, lv.draw_line_dsc||[lv_draw_line](https://docs.lvgl.io/9.0/search.html?q=lv_draw_line)
draw_line_dsc_init|lv.draw_line_dsc||[lv_draw_line_dsc_init](https://docs.lvgl.io/9.0/search.html?q=lv_draw_line_dsc_init)
draw_rect|lv.layer, lv.draw_rect_dsc, lv.area||[lv_draw_rect](https://docs.lvgl.io/9.0/search.html?q=lv_draw_rect)
draw_rect_dsc_init|lv.draw_rect_dsc||[lv_draw_rect_dsc_init](https://docs.lvgl.io/9.0/search.html?q=lv_draw_rect_dsc_init)
draw_wait_for_finish|||[lv_draw_wait_for_finish](https://docs.lvgl.io/9.0/search.html?q=lv_draw_wait_for_finish)
event_code_get_name|int|string|[lv_event_code_get_name](https://docs.lvgl.io/9.0/search.html?q=lv_event_code_get_name)
event_dsc_get_cb|lv.event_dsc|lv.event_cb|[lv_event_dsc_get_cb](https://docs.lvgl.io/9.0/search.html?q=lv_event_dsc_get_cb)
event_dsc_get_user_data|lv.event_dsc|comptr|[lv_event_dsc_get_user_data](https://docs.lvgl.io/9.0/search.html?q=lv_event_dsc_get_user_data)
event_register_id||int|[lv_event_register_id](https://docs.lvgl.io/9.0/search.html?q=lv_event_register_id)
flex_init|||[lv_flex_init](https://docs.lvgl.io/9.0/search.html?q=lv_flex_init)
font_get_default||lv.font|[lv_font_get_default](https://docs.lvgl.io/9.0/search.html?q=lv_font_get_default)
font_get_glyph_width|lv.font, int, int|int|[lv_font_get_glyph_width](https://docs.lvgl.io/9.0/search.html?q=lv_font_get_glyph_width)
font_get_line_height|lv.font|int|[lv_font_get_line_height](https://docs.lvgl.io/9.0/search.html?q=lv_font_get_line_height)
font_has_static_bitmap|lv.font|bool|[lv_font_has_static_bitmap](https://docs.lvgl.io/9.0/search.html?q=lv_font_has_static_bitmap)
font_info_is_equal|lv.font_info, lv.font_info|bool|[lv_font_info_is_equal](https://docs.lvgl.io/9.0/search.html?q=lv_font_info_is_equal)
font_set_kerning|lv.font, int||[lv_font_set_kerning](https://docs.lvgl.io/9.0/search.html?q=lv_font_set_kerning)
get_hor_res||int|[lv_get_hor_res](https://docs.lvgl.io/9.0/search.html?q=lv_get_hor_res)
get_ts_calibration||lv.ts_calibration|[lv_get_ts_calibration](https://docs.lvgl.io/9.0/search.html?q=lv_get_ts_calibration)
@ -102,6 +114,8 @@ indev_create||lv.indev|[lv_indev_create](https://docs.lvgl.io/9.0/search.html?q=
indev_get_active_obj||lv.obj|[lv_indev_get_active_obj](https://docs.lvgl.io/9.0/search.html?q=lv_indev_get_active_obj)
indev_read_timer_cb|lv.timer||[lv_indev_read_timer_cb](https://docs.lvgl.io/9.0/search.html?q=lv_indev_read_timer_cb)
layer_bottom||lv.obj|[lv_layer_bottom](https://docs.lvgl.io/9.0/search.html?q=lv_layer_bottom)
layer_init|lv.layer||[lv_layer_init](https://docs.lvgl.io/9.0/search.html?q=lv_layer_init)
layer_reset|lv.layer||[lv_layer_reset](https://docs.lvgl.io/9.0/search.html?q=lv_layer_reset)
layer_sys||lv.obj|[lv_layer_sys](https://docs.lvgl.io/9.0/search.html?q=lv_layer_sys)
layer_top||lv.obj|[lv_layer_top](https://docs.lvgl.io/9.0/search.html?q=lv_layer_top)
obj_assign_id|lv.obj_class, lv.obj||[lv_obj_assign_id](https://docs.lvgl.io/9.0/search.html?q=lv_obj_assign_id)
@ -145,6 +159,8 @@ style_register_prop|int|int|[lv_style_register_prop](https://docs.lvgl.io/9.0/se
task_handler||int|[lv_task_handler](https://docs.lvgl.io/9.0/search.html?q=lv_task_handler)
text_get_size|comptr, string, lv.font, int, int, int, int||[lv_text_get_size](https://docs.lvgl.io/9.0/search.html?q=lv_text_get_size)
text_get_width|string, int, lv.font, int|int|[lv_text_get_width](https://docs.lvgl.io/9.0/search.html?q=lv_text_get_width)
text_get_width_with_flags|string, int, lv.font, int, int|int|[lv_text_get_width_with_flags](https://docs.lvgl.io/9.0/search.html?q=lv_text_get_width_with_flags)
text_is_cmd|comptr, int|bool|[lv_text_is_cmd](https://docs.lvgl.io/9.0/search.html?q=lv_text_is_cmd)
theme_apply|lv.obj||[lv_theme_apply](https://docs.lvgl.io/9.0/search.html?q=lv_theme_apply)
theme_get_color_primary|lv.obj|lv.color|[lv_theme_get_color_primary](https://docs.lvgl.io/9.0/search.html?q=lv_theme_get_color_primary)
theme_get_color_secondary|lv.obj|lv.color|[lv_theme_get_color_secondary](https://docs.lvgl.io/9.0/search.html?q=lv_theme_get_color_secondary)
@ -182,6 +198,10 @@ get_repeat_count||int|[lv_anim_get_repeat_count](https://docs.lvgl.io/9.0/search
get_time||int|[lv_anim_get_time](https://docs.lvgl.io/9.0/search.html?q=lv_anim_get_time)
get_user_data||comptr|[lv_anim_get_user_data](https://docs.lvgl.io/9.0/search.html?q=lv_anim_get_user_data)
init|||[lv_anim_init](https://docs.lvgl.io/9.0/search.html?q=lv_anim_init)
is_paused||bool|[lv_anim_is_paused](https://docs.lvgl.io/9.0/search.html?q=lv_anim_is_paused)
pause|||[lv_anim_pause](https://docs.lvgl.io/9.0/search.html?q=lv_anim_pause)
pause_for|int||[lv_anim_pause_for](https://docs.lvgl.io/9.0/search.html?q=lv_anim_pause_for)
resume|||[lv_anim_resume](https://docs.lvgl.io/9.0/search.html?q=lv_anim_resume)
set_bezier3_param|int, int, int, int||[lv_anim_set_bezier3_param](https://docs.lvgl.io/9.0/search.html?q=lv_anim_set_bezier3_param)
set_completed_cb|comptr||[lv_anim_set_completed_cb](https://docs.lvgl.io/9.0/search.html?q=lv_anim_set_completed_cb)
set_custom_exec_cb|comptr||[lv_anim_set_custom_exec_cb](https://docs.lvgl.io/9.0/search.html?q=lv_anim_set_custom_exec_cb)
@ -191,14 +211,13 @@ set_early_apply|bool||[lv_anim_set_early_apply](https://docs.lvgl.io/9.0/search.
set_exec_cb|comptr||[lv_anim_set_exec_cb](https://docs.lvgl.io/9.0/search.html?q=lv_anim_set_exec_cb)
set_get_value_cb|comptr||[lv_anim_set_get_value_cb](https://docs.lvgl.io/9.0/search.html?q=lv_anim_set_get_value_cb)
set_path_cb|comptr||[lv_anim_set_path_cb](https://docs.lvgl.io/9.0/search.html?q=lv_anim_set_path_cb)
set_playback_delay|int||[lv_anim_set_playback_delay](https://docs.lvgl.io/9.0/search.html?q=lv_anim_set_playback_delay)
set_playback_duration|int||[lv_anim_set_playback_duration](https://docs.lvgl.io/9.0/search.html?q=lv_anim_set_playback_duration)
set_playback_time|int||[lv_anim_set_playback_time](https://docs.lvgl.io/9.0/search.html?q=lv_anim_set_playback_time)
set_ready_cb|comptr||[lv_anim_set_completed_cb](https://docs.lvgl.io/9.0/search.html?q=lv_anim_set_completed_cb)
set_repeat_count|int||[lv_anim_set_repeat_count](https://docs.lvgl.io/9.0/search.html?q=lv_anim_set_repeat_count)
set_repeat_delay|int||[lv_anim_set_repeat_delay](https://docs.lvgl.io/9.0/search.html?q=lv_anim_set_repeat_delay)
set_reverse_delay|int||[lv_anim_set_reverse_delay](https://docs.lvgl.io/9.0/search.html?q=lv_anim_set_reverse_delay)
set_reverse_duration|int||[lv_anim_set_reverse_duration](https://docs.lvgl.io/9.0/search.html?q=lv_anim_set_reverse_duration)
set_reverse_time|int||[lv_anim_set_reverse_time](https://docs.lvgl.io/9.0/search.html?q=lv_anim_set_reverse_time)
set_start_cb|comptr||[lv_anim_set_start_cb](https://docs.lvgl.io/9.0/search.html?q=lv_anim_set_start_cb)
set_time|int||[lv_anim_set_time](https://docs.lvgl.io/9.0/search.html?q=lv_anim_set_time)
set_user_data|\<any\>||[lv_anim_set_user_data](https://docs.lvgl.io/9.0/search.html?q=lv_anim_set_user_data)
set_values|int, int||[lv_anim_set_values](https://docs.lvgl.io/9.0/search.html?q=lv_anim_set_values)
set_var|\<any\>||[lv_anim_set_var](https://docs.lvgl.io/9.0/search.html?q=lv_anim_set_var)
@ -222,6 +241,7 @@ get_antialiasing||bool|[lv_display_get_antialiasing](https://docs.lvgl.io/9.0/se
get_color_format||int|[lv_display_get_color_format](https://docs.lvgl.io/9.0/search.html?q=lv_display_get_color_format)
get_dpi||int|[lv_display_get_dpi](https://docs.lvgl.io/9.0/search.html?q=lv_display_get_dpi)
get_dpi||int|[lv_display_get_dpi](https://docs.lvgl.io/9.0/search.html?q=lv_display_get_dpi)
get_draw_buf_size||int|[lv_display_get_draw_buf_size](https://docs.lvgl.io/9.0/search.html?q=lv_display_get_draw_buf_size)
get_driver_data||comptr|[lv_display_get_driver_data](https://docs.lvgl.io/9.0/search.html?q=lv_display_get_driver_data)
get_event_count||int|[lv_display_get_event_count](https://docs.lvgl.io/9.0/search.html?q=lv_display_get_event_count)
get_event_dsc|int|lv.event_dsc|[lv_display_get_event_dsc](https://docs.lvgl.io/9.0/search.html?q=lv_display_get_event_dsc)
@ -229,17 +249,21 @@ get_hor_res||int|[lv_display_get_horizontal_resolution](https://docs.lvgl.io/9.0
get_horizontal_resolution||int|[lv_display_get_horizontal_resolution](https://docs.lvgl.io/9.0/search.html?q=lv_display_get_horizontal_resolution)
get_inactive_time||int|[lv_display_get_inactive_time](https://docs.lvgl.io/9.0/search.html?q=lv_display_get_inactive_time)
get_inactive_time||int|[lv_display_get_inactive_time](https://docs.lvgl.io/9.0/search.html?q=lv_display_get_inactive_time)
get_invalidated_draw_buf_size|int, int|int|[lv_display_get_invalidated_draw_buf_size](https://docs.lvgl.io/9.0/search.html?q=lv_display_get_invalidated_draw_buf_size)
get_layer_bottom||lv.obj|[lv_display_get_layer_bottom](https://docs.lvgl.io/9.0/search.html?q=lv_display_get_layer_bottom)
get_layer_sys||lv.obj|[lv_display_get_layer_sys](https://docs.lvgl.io/9.0/search.html?q=lv_display_get_layer_sys)
get_layer_sys||lv.obj|[lv_display_get_layer_sys](https://docs.lvgl.io/9.0/search.html?q=lv_display_get_layer_sys)
get_layer_top||lv.obj|[lv_display_get_layer_top](https://docs.lvgl.io/9.0/search.html?q=lv_display_get_layer_top)
get_layer_top||lv.obj|[lv_display_get_layer_top](https://docs.lvgl.io/9.0/search.html?q=lv_display_get_layer_top)
get_matrix_rotation||bool|[lv_display_get_matrix_rotation](https://docs.lvgl.io/9.0/search.html?q=lv_display_get_matrix_rotation)
get_next||lv.display|[lv_display_get_next](https://docs.lvgl.io/9.0/search.html?q=lv_display_get_next)
get_next||lv.display|[lv_display_get_next](https://docs.lvgl.io/9.0/search.html?q=lv_display_get_next)
get_offset_x||int|[lv_display_get_offset_x](https://docs.lvgl.io/9.0/search.html?q=lv_display_get_offset_x)
get_offset_x||int|[lv_display_get_offset_x](https://docs.lvgl.io/9.0/search.html?q=lv_display_get_offset_x)
get_offset_y||int|[lv_display_get_offset_y](https://docs.lvgl.io/9.0/search.html?q=lv_display_get_offset_y)
get_offset_y||int|[lv_display_get_offset_y](https://docs.lvgl.io/9.0/search.html?q=lv_display_get_offset_y)
get_original_horizontal_resolution||int|[lv_display_get_original_horizontal_resolution](https://docs.lvgl.io/9.0/search.html?q=lv_display_get_original_horizontal_resolution)
get_original_vertical_resolution||int|[lv_display_get_original_vertical_resolution](https://docs.lvgl.io/9.0/search.html?q=lv_display_get_original_vertical_resolution)
get_physical_hor_res||int|[lv_display_get_physical_horizontal_resolution](https://docs.lvgl.io/9.0/search.html?q=lv_display_get_physical_horizontal_resolution)
get_physical_horizontal_resolution||int|[lv_display_get_physical_horizontal_resolution](https://docs.lvgl.io/9.0/search.html?q=lv_display_get_physical_horizontal_resolution)
get_physical_ver_res||int|[lv_display_get_physical_vertical_resolution](https://docs.lvgl.io/9.0/search.html?q=lv_display_get_physical_vertical_resolution)
@ -253,25 +277,30 @@ get_screen_active||lv.obj|[lv_display_get_screen_active](https://docs.lvgl.io/9.
get_screen_prev||lv.obj|[lv_display_get_screen_prev](https://docs.lvgl.io/9.0/search.html?q=lv_display_get_screen_prev)
get_theme||lv.theme|[lv_display_get_theme](https://docs.lvgl.io/9.0/search.html?q=lv_display_get_theme)
get_theme||lv.theme|[lv_display_get_theme](https://docs.lvgl.io/9.0/search.html?q=lv_display_get_theme)
get_tile_cnt||int|[lv_display_get_tile_cnt](https://docs.lvgl.io/9.0/search.html?q=lv_display_get_tile_cnt)
get_user_data||comptr|[lv_display_get_user_data](https://docs.lvgl.io/9.0/search.html?q=lv_display_get_user_data)
get_ver_res||int|[lv_display_get_vertical_resolution](https://docs.lvgl.io/9.0/search.html?q=lv_display_get_vertical_resolution)
get_vertical_resolution||int|[lv_display_get_vertical_resolution](https://docs.lvgl.io/9.0/search.html?q=lv_display_get_vertical_resolution)
is_double_buffered||bool|[lv_display_is_double_buffered](https://docs.lvgl.io/9.0/search.html?q=lv_display_is_double_buffered)
is_invalidation_enabled||bool|[lv_display_is_invalidation_enabled](https://docs.lvgl.io/9.0/search.html?q=lv_display_is_invalidation_enabled)
is_invalidation_enabled||bool|[lv_display_is_invalidation_enabled](https://docs.lvgl.io/9.0/search.html?q=lv_display_is_invalidation_enabled)
register_vsync_event|\<closure\>, \<any\>|bool|[lv_display_register_vsync_event](https://docs.lvgl.io/9.0/search.html?q=lv_display_register_vsync_event)
remove|||[lv_display_delete](https://docs.lvgl.io/9.0/search.html?q=lv_display_delete)
remove_event_cb_with_user_data|\<any\>, \<any\>|int|[lv_display_remove_event_cb_with_user_data](https://docs.lvgl.io/9.0/search.html?q=lv_display_remove_event_cb_with_user_data)
rotate_area|lv.area||[lv_display_rotate_area](https://docs.lvgl.io/9.0/search.html?q=lv_display_rotate_area)
send_event|int, \<any\>|int|[lv_display_send_event](https://docs.lvgl.io/9.0/search.html?q=lv_display_send_event)
send_event|int, \<any\>|int|[lv_display_send_event](https://docs.lvgl.io/9.0/search.html?q=lv_display_send_event)
send_vsync_event|\<any\>|int|[lv_display_send_vsync_event](https://docs.lvgl.io/9.0/search.html?q=lv_display_send_vsync_event)
set_angle|int||[lv_display_set_rotation](https://docs.lvgl.io/9.0/search.html?q=lv_display_set_rotation)
set_antialiasing|bool||[lv_display_set_antialiasing](https://docs.lvgl.io/9.0/search.html?q=lv_display_set_antialiasing)
set_buffers|\<any\>, \<any\>, int, int||[lv_display_set_buffers](https://docs.lvgl.io/9.0/search.html?q=lv_display_set_buffers)
set_buffers_with_stride|\<any\>, \<any\>, int, int, int||[lv_display_set_buffers_with_stride](https://docs.lvgl.io/9.0/search.html?q=lv_display_set_buffers_with_stride)
set_color_format|int||[lv_display_set_color_format](https://docs.lvgl.io/9.0/search.html?q=lv_display_set_color_format)
set_default|||[lv_display_set_default](https://docs.lvgl.io/9.0/search.html?q=lv_display_set_default)
set_default|||[lv_display_set_default](https://docs.lvgl.io/9.0/search.html?q=lv_display_set_default)
set_dpi|int||[lv_display_set_dpi](https://docs.lvgl.io/9.0/search.html?q=lv_display_set_dpi)
set_driver_data|\<any\>||[lv_display_set_driver_data](https://docs.lvgl.io/9.0/search.html?q=lv_display_set_driver_data)
set_matrix_rotation|bool||[lv_display_set_matrix_rotation](https://docs.lvgl.io/9.0/search.html?q=lv_display_set_matrix_rotation)
set_offset|int, int||[lv_display_set_offset](https://docs.lvgl.io/9.0/search.html?q=lv_display_set_offset)
set_physical_resolution|int, int||[lv_display_set_physical_resolution](https://docs.lvgl.io/9.0/search.html?q=lv_display_set_physical_resolution)
set_render_mode|int||[lv_display_set_render_mode](https://docs.lvgl.io/9.0/search.html?q=lv_display_set_render_mode)
@ -280,9 +309,11 @@ set_rotation|int||[lv_display_set_rotation](https://docs.lvgl.io/9.0/search.html
set_rotation|int||[lv_display_set_rotation](https://docs.lvgl.io/9.0/search.html?q=lv_display_set_rotation)
set_theme|lv.theme||[lv_display_set_theme](https://docs.lvgl.io/9.0/search.html?q=lv_display_set_theme)
set_theme|lv.theme||[lv_display_set_theme](https://docs.lvgl.io/9.0/search.html?q=lv_display_set_theme)
set_tile_cnt|int||[lv_display_set_tile_cnt](https://docs.lvgl.io/9.0/search.html?q=lv_display_set_tile_cnt)
set_user_data|\<any\>||[lv_display_set_user_data](https://docs.lvgl.io/9.0/search.html?q=lv_display_set_user_data)
trig_activity|||[lv_display_trigger_activity](https://docs.lvgl.io/9.0/search.html?q=lv_display_trigger_activity)
trigger_activity|||[lv_display_trigger_activity](https://docs.lvgl.io/9.0/search.html?q=lv_display_trigger_activity)
unregister_vsync_event|\<closure\>, \<any\>|bool|[lv_display_unregister_vsync_event](https://docs.lvgl.io/9.0/search.html?q=lv_display_unregister_vsync_event)
### class `lv.event`
@ -294,6 +325,7 @@ get_current_target||comptr|[lv_event_get_current_target](https://docs.lvgl.io/9.
get_current_target_obj||lv.obj|[lv_event_get_current_target_obj](https://docs.lvgl.io/9.0/search.html?q=lv_event_get_current_target_obj)
get_hit_test_info||comptr|[lv_event_get_hit_test_info](https://docs.lvgl.io/9.0/search.html?q=lv_event_get_hit_test_info)
get_indev||lv.indev|[lv_event_get_indev](https://docs.lvgl.io/9.0/search.html?q=lv_event_get_indev)
get_invalidated_area||lv.area|[lv_event_get_invalidated_area](https://docs.lvgl.io/9.0/search.html?q=lv_event_get_invalidated_area)
get_key||int|[lv_event_get_key](https://docs.lvgl.io/9.0/search.html?q=lv_event_get_key)
get_layer||lv.layer|[lv_event_get_layer](https://docs.lvgl.io/9.0/search.html?q=lv_event_get_layer)
get_old_size||lv.area|[lv_event_get_old_size](https://docs.lvgl.io/9.0/search.html?q=lv_event_get_old_size)
@ -347,6 +379,7 @@ add_event_cb|\<closure\>, int, \<any\>||[lv_indev_add_event_cb](https://docs.lvg
del|||[lv_indev_delete](https://docs.lvgl.io/9.0/search.html?q=lv_indev_delete)
delete|||[lv_indev_delete](https://docs.lvgl.io/9.0/search.html?q=lv_indev_delete)
enable|bool||[lv_indev_enable](https://docs.lvgl.io/9.0/search.html?q=lv_indev_enable)
get_cursor||lv.obj|[lv_indev_get_cursor](https://docs.lvgl.io/9.0/search.html?q=lv_indev_get_cursor)
get_disp||lv.display|[lv_indev_get_display](https://docs.lvgl.io/9.0/search.html?q=lv_indev_get_display)
get_display||lv.display|[lv_indev_get_display](https://docs.lvgl.io/9.0/search.html?q=lv_indev_get_display)
get_driver_data||comptr|[lv_indev_get_driver_data](https://docs.lvgl.io/9.0/search.html?q=lv_indev_get_driver_data)
@ -363,6 +396,7 @@ get_press_moved||bool|[lv_indev_get_press_moved](https://docs.lvgl.io/9.0/search
get_read_timer||lv.timer|[lv_indev_get_read_timer](https://docs.lvgl.io/9.0/search.html?q=lv_indev_get_read_timer)
get_scroll_dir||int|[lv_indev_get_scroll_dir](https://docs.lvgl.io/9.0/search.html?q=lv_indev_get_scroll_dir)
get_scroll_obj||lv.obj|[lv_indev_get_scroll_obj](https://docs.lvgl.io/9.0/search.html?q=lv_indev_get_scroll_obj)
get_short_click_streak||int|[lv_indev_get_short_click_streak](https://docs.lvgl.io/9.0/search.html?q=lv_indev_get_short_click_streak)
get_state||int|[lv_indev_get_state](https://docs.lvgl.io/9.0/search.html?q=lv_indev_get_state)
get_type||int|[lv_indev_get_type](https://docs.lvgl.io/9.0/search.html?q=lv_indev_get_type)
get_user_data||comptr|[lv_indev_get_user_data](https://docs.lvgl.io/9.0/search.html?q=lv_indev_get_user_data)
@ -382,6 +416,7 @@ set_disp|lv.display||[lv_indev_set_display](https://docs.lvgl.io/9.0/search.html
set_display|lv.display||[lv_indev_set_display](https://docs.lvgl.io/9.0/search.html?q=lv_indev_set_display)
set_driver_data|\<any\>||[lv_indev_set_driver_data](https://docs.lvgl.io/9.0/search.html?q=lv_indev_set_driver_data)
set_group|lv.group||[lv_indev_set_group](https://docs.lvgl.io/9.0/search.html?q=lv_indev_set_group)
set_long_press_repeat_time|int||[lv_indev_set_long_press_repeat_time](https://docs.lvgl.io/9.0/search.html?q=lv_indev_set_long_press_repeat_time)
set_long_press_time|int||[lv_indev_set_long_press_time](https://docs.lvgl.io/9.0/search.html?q=lv_indev_set_long_press_time)
set_mode|int||[lv_indev_set_mode](https://docs.lvgl.io/9.0/search.html?q=lv_indev_set_mode)
set_scroll_limit|int||[lv_indev_set_scroll_limit](https://docs.lvgl.io/9.0/search.html?q=lv_indev_set_scroll_limit)
@ -395,6 +430,7 @@ wait_release|||[lv_indev_wait_release](https://docs.lvgl.io/9.0/search.html?q=lv
Method|Arguments|Return type|LVGL equivalent
:---|:---|:---|:---
copy|lv.style||[lv_style_copy](https://docs.lvgl.io/9.0/search.html?q=lv_style_copy)
is_const||bool|[lv_style_is_const](https://docs.lvgl.io/9.0/search.html?q=lv_style_is_const)
is_empty||bool|[lv_style_is_empty](https://docs.lvgl.io/9.0/search.html?q=lv_style_is_empty)
remove_prop|int|bool|[lv_style_remove_prop](https://docs.lvgl.io/9.0/search.html?q=lv_style_remove_prop)
@ -468,10 +504,13 @@ set_line_dash_width|int||[lv_style_set_line_dash_width](https://docs.lvgl.io/9.0
set_line_opa|int||[lv_style_set_line_opa](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_line_opa)
set_line_rounded|bool||[lv_style_set_line_rounded](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_line_rounded)
set_line_width|int||[lv_style_set_line_width](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_line_width)
set_margin_all|int||[lv_style_set_margin_all](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_margin_all)
set_margin_bottom|int||[lv_style_set_margin_bottom](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_margin_bottom)
set_margin_hor|int||[lv_style_set_margin_hor](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_margin_hor)
set_margin_left|int||[lv_style_set_margin_left](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_margin_left)
set_margin_right|int||[lv_style_set_margin_right](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_margin_right)
set_margin_top|int||[lv_style_set_margin_top](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_margin_top)
set_margin_ver|int||[lv_style_set_margin_ver](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_margin_ver)
set_max_height|int||[lv_style_set_max_height](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_max_height)
set_max_width|int||[lv_style_set_max_width](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_max_width)
set_min_height|int||[lv_style_set_min_height](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_min_height)
@ -488,12 +527,16 @@ set_pad_column|int||[lv_style_set_pad_column](https://docs.lvgl.io/9.0/search.ht
set_pad_gap|int||[lv_style_set_pad_gap](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_pad_gap)
set_pad_hor|int||[lv_style_set_pad_hor](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_pad_hor)
set_pad_left|int||[lv_style_set_pad_left](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_pad_left)
set_pad_radial|int||[lv_style_set_pad_radial](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_pad_radial)
set_pad_right|int||[lv_style_set_pad_right](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_pad_right)
set_pad_row|int||[lv_style_set_pad_row](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_pad_row)
set_pad_top|int||[lv_style_set_pad_top](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_pad_top)
set_pad_ver|int||[lv_style_set_pad_ver](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_pad_ver)
set_prop|int, int||[lv_style_set_prop](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_prop)
set_radial_offset|int||[lv_style_set_radial_offset](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_radial_offset)
set_radius|int||[lv_style_set_radius](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_radius)
set_recolor|lv.color||[lv_style_set_recolor](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_recolor)
set_recolor_opa|int||[lv_style_set_recolor_opa](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_recolor_opa)
set_rotary_sensitivity|int||[lv_style_set_rotary_sensitivity](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_rotary_sensitivity)
set_shadow_color|lv.color||[lv_style_set_shadow_color](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_shadow_color)
set_shadow_offset_x|int||[lv_style_set_shadow_offset_x](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_shadow_offset_x)
@ -511,6 +554,9 @@ set_text_font|lv.font||[lv_style_set_text_font](https://docs.lvgl.io/9.0/search.
set_text_letter_space|int||[lv_style_set_text_letter_space](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_text_letter_space)
set_text_line_space|int||[lv_style_set_text_line_space](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_text_line_space)
set_text_opa|int||[lv_style_set_text_opa](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_text_opa)
set_text_outline_stroke_color|lv.color||[lv_style_set_text_outline_stroke_color](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_text_outline_stroke_color)
set_text_outline_stroke_opa|int||[lv_style_set_text_outline_stroke_opa](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_text_outline_stroke_opa)
set_text_outline_stroke_width|int||[lv_style_set_text_outline_stroke_width](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_text_outline_stroke_width)
set_transform_angle|int||[lv_style_set_transform_rotation](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_transform_rotation)
set_transform_height|int||[lv_style_set_transform_height](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_transform_height)
set_transform_pivot_x|int||[lv_style_set_transform_pivot_x](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_transform_pivot_x)
@ -524,6 +570,7 @@ set_transform_skew_y|int||[lv_style_set_transform_skew_y](https://docs.lvgl.io/9
set_transform_width|int||[lv_style_set_transform_width](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_transform_width)
set_transform_zoom|int||[lv_style_set_transform_scale](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_transform_scale)
set_transition|lv.style_transition_dsc||[lv_style_set_transition](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_transition)
set_translate_radial|int||[lv_style_set_translate_radial](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_translate_radial)
set_translate_x|int||[lv_style_set_translate_x](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_translate_x)
set_translate_y|int||[lv_style_set_translate_y](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_translate_y)
set_width|int||[lv_style_set_width](https://docs.lvgl.io/9.0/search.html?q=lv_style_set_width)
@ -581,9 +628,9 @@ delete_delayed|int||[lv_obj_delete_delayed](https://docs.lvgl.io/9.0/search.html
dump_tree|||[lv_obj_dump_tree](https://docs.lvgl.io/9.0/search.html?q=lv_obj_dump_tree)
fade_in|int, int||[lv_obj_fade_in](https://docs.lvgl.io/9.0/search.html?q=lv_obj_fade_in)
fade_out|int, int||[lv_obj_fade_out](https://docs.lvgl.io/9.0/search.html?q=lv_obj_fade_out)
find_by_id|\<any\>|lv.obj|[lv_obj_find_by_id](https://docs.lvgl.io/9.0/search.html?q=lv_obj_find_by_id)
free_id|||[lv_obj_free_id](https://docs.lvgl.io/9.0/search.html?q=lv_obj_free_id)
get_child|int|lv.obj|[lv_obj_get_child](https://docs.lvgl.io/9.0/search.html?q=lv_obj_get_child)
get_child_by_id|\<any\>|lv.obj|[lv_obj_get_child_by_id](https://docs.lvgl.io/9.0/search.html?q=lv_obj_get_child_by_id)
get_child_by_type|int, lv.obj_class|lv.obj|[lv_obj_get_child_by_type](https://docs.lvgl.io/9.0/search.html?q=lv_obj_get_child_by_type)
get_child_cnt||int|[lv_obj_get_child_count](https://docs.lvgl.io/9.0/search.html?q=lv_obj_get_child_count)
get_child_count||int|[lv_obj_get_child_count](https://docs.lvgl.io/9.0/search.html?q=lv_obj_get_child_count)
@ -713,11 +760,16 @@ get_style_outline_width|int|int|[lv_obj_get_style_outline_width](https://docs.lv
get_style_pad_bottom|int|int|[lv_obj_get_style_pad_bottom](https://docs.lvgl.io/9.0/search.html?q=lv_obj_get_style_pad_bottom)
get_style_pad_column|int|int|[lv_obj_get_style_pad_column](https://docs.lvgl.io/9.0/search.html?q=lv_obj_get_style_pad_column)
get_style_pad_left|int|int|[lv_obj_get_style_pad_left](https://docs.lvgl.io/9.0/search.html?q=lv_obj_get_style_pad_left)
get_style_pad_radial|int|int|[lv_obj_get_style_pad_radial](https://docs.lvgl.io/9.0/search.html?q=lv_obj_get_style_pad_radial)
get_style_pad_right|int|int|[lv_obj_get_style_pad_right](https://docs.lvgl.io/9.0/search.html?q=lv_obj_get_style_pad_right)
get_style_pad_row|int|int|[lv_obj_get_style_pad_row](https://docs.lvgl.io/9.0/search.html?q=lv_obj_get_style_pad_row)
get_style_pad_top|int|int|[lv_obj_get_style_pad_top](https://docs.lvgl.io/9.0/search.html?q=lv_obj_get_style_pad_top)
get_style_prop|int, int|int|[lv_obj_get_style_prop](https://docs.lvgl.io/9.0/search.html?q=lv_obj_get_style_prop)
get_style_radial_offset|int|int|[lv_obj_get_style_radial_offset](https://docs.lvgl.io/9.0/search.html?q=lv_obj_get_style_radial_offset)
get_style_radius|int|int|[lv_obj_get_style_radius](https://docs.lvgl.io/9.0/search.html?q=lv_obj_get_style_radius)
get_style_recolor|int|lv.color|[lv_obj_get_style_recolor](https://docs.lvgl.io/9.0/search.html?q=lv_obj_get_style_recolor)
get_style_recolor_opa|int|int|[lv_obj_get_style_recolor_opa](https://docs.lvgl.io/9.0/search.html?q=lv_obj_get_style_recolor_opa)
get_style_recolor_recursive|int|int|[lv_obj_get_style_recolor_recursive](https://docs.lvgl.io/9.0/search.html?q=lv_obj_get_style_recolor_recursive)
get_style_rotary_sensitivity|int|int|[lv_obj_get_style_rotary_sensitivity](https://docs.lvgl.io/9.0/search.html?q=lv_obj_get_style_rotary_sensitivity)
get_style_shadow_color|int|lv.color|[lv_obj_get_style_shadow_color](https://docs.lvgl.io/9.0/search.html?q=lv_obj_get_style_shadow_color)
get_style_shadow_color_filtered|int|lv.color|[lv_obj_get_style_shadow_color_filtered](https://docs.lvgl.io/9.0/search.html?q=lv_obj_get_style_shadow_color_filtered)
@ -740,6 +792,10 @@ get_style_text_font|int|lv.font|[lv_obj_get_style_text_font](https://docs.lvgl.i
get_style_text_letter_space|int|int|[lv_obj_get_style_text_letter_space](https://docs.lvgl.io/9.0/search.html?q=lv_obj_get_style_text_letter_space)
get_style_text_line_space|int|int|[lv_obj_get_style_text_line_space](https://docs.lvgl.io/9.0/search.html?q=lv_obj_get_style_text_line_space)
get_style_text_opa|int|int|[lv_obj_get_style_text_opa](https://docs.lvgl.io/9.0/search.html?q=lv_obj_get_style_text_opa)
get_style_text_outline_stroke_color|int|lv.color|[lv_obj_get_style_text_outline_stroke_color](https://docs.lvgl.io/9.0/search.html?q=lv_obj_get_style_text_outline_stroke_color)
get_style_text_outline_stroke_color_filtered|int|lv.color|[lv_obj_get_style_text_outline_stroke_color_filtered](https://docs.lvgl.io/9.0/search.html?q=lv_obj_get_style_text_outline_stroke_color_filtered)
get_style_text_outline_stroke_opa|int|int|[lv_obj_get_style_text_outline_stroke_opa](https://docs.lvgl.io/9.0/search.html?q=lv_obj_get_style_text_outline_stroke_opa)
get_style_text_outline_stroke_width|int|int|[lv_obj_get_style_text_outline_stroke_width](https://docs.lvgl.io/9.0/search.html?q=lv_obj_get_style_text_outline_stroke_width)
get_style_transform_angle|int|int|[lv_obj_get_style_transform_rotation](https://docs.lvgl.io/9.0/search.html?q=lv_obj_get_style_transform_rotation)
get_style_transform_height|int|int|[lv_obj_get_style_transform_height](https://docs.lvgl.io/9.0/search.html?q=lv_obj_get_style_transform_height)
get_style_transform_pivot_x|int|int|[lv_obj_get_style_transform_pivot_x](https://docs.lvgl.io/9.0/search.html?q=lv_obj_get_style_transform_pivot_x)
@ -753,6 +809,7 @@ get_style_transform_skew_x|int|int|[lv_obj_get_style_transform_skew_x](https://d
get_style_transform_skew_y|int|int|[lv_obj_get_style_transform_skew_y](https://docs.lvgl.io/9.0/search.html?q=lv_obj_get_style_transform_skew_y)
get_style_transform_width|int|int|[lv_obj_get_style_transform_width](https://docs.lvgl.io/9.0/search.html?q=lv_obj_get_style_transform_width)
get_style_transition|int|lv.style_transition_dsc|[lv_obj_get_style_transition](https://docs.lvgl.io/9.0/search.html?q=lv_obj_get_style_transition)
get_style_translate_radial|int|int|[lv_obj_get_style_translate_radial](https://docs.lvgl.io/9.0/search.html?q=lv_obj_get_style_translate_radial)
get_style_translate_x|int|int|[lv_obj_get_style_translate_x](https://docs.lvgl.io/9.0/search.html?q=lv_obj_get_style_translate_x)
get_style_translate_y|int|int|[lv_obj_get_style_translate_y](https://docs.lvgl.io/9.0/search.html?q=lv_obj_get_style_translate_y)
get_style_width|int|int|[lv_obj_get_style_width](https://docs.lvgl.io/9.0/search.html?q=lv_obj_get_style_width)
@ -801,7 +858,7 @@ refresh_self_size||bool|[lv_obj_refresh_self_size](https://docs.lvgl.io/9.0/sear
refresh_style|int, int||[lv_obj_refresh_style](https://docs.lvgl.io/9.0/search.html?q=lv_obj_refresh_style)
remove|||[lv_obj_delete](https://docs.lvgl.io/9.0/search.html?q=lv_obj_delete)
remove_event|int|bool|[lv_obj_remove_event](https://docs.lvgl.io/9.0/search.html?q=lv_obj_remove_event)
remove_event_cb|\<any\>|bool|[lv_obj_remove_event_cb](https://docs.lvgl.io/9.0/search.html?q=lv_obj_remove_event_cb)
remove_event_cb|\<any\>|int|[lv_obj_remove_event_cb](https://docs.lvgl.io/9.0/search.html?q=lv_obj_remove_event_cb)
remove_event_cb_with_user_data|\<any\>, \<any\>|int|[lv_obj_remove_event_cb_with_user_data](https://docs.lvgl.io/9.0/search.html?q=lv_obj_remove_event_cb_with_user_data)
remove_event_dsc|lv.event_dsc|bool|[lv_obj_remove_event_dsc](https://docs.lvgl.io/9.0/search.html?q=lv_obj_remove_event_dsc)
remove_flag|int||[lv_obj_remove_flag](https://docs.lvgl.io/9.0/search.html?q=lv_obj_remove_flag)
@ -810,6 +867,7 @@ remove_state|int||[lv_obj_remove_state](https://docs.lvgl.io/9.0/search.html?q=l
remove_style|lv.style, int||[lv_obj_remove_style](https://docs.lvgl.io/9.0/search.html?q=lv_obj_remove_style)
remove_style_all|||[lv_obj_remove_style_all](https://docs.lvgl.io/9.0/search.html?q=lv_obj_remove_style_all)
replace_style|lv.style, lv.style, int|bool|[lv_obj_replace_style](https://docs.lvgl.io/9.0/search.html?q=lv_obj_replace_style)
reset_transform|||[lv_obj_reset_transform](https://docs.lvgl.io/9.0/search.html?q=lv_obj_reset_transform)
scroll_by|int, int, int||[lv_obj_scroll_by](https://docs.lvgl.io/9.0/search.html?q=lv_obj_scroll_by)
scroll_by_bounded|int, int, int||[lv_obj_scroll_by_bounded](https://docs.lvgl.io/9.0/search.html?q=lv_obj_scroll_by_bounded)
scroll_to|int, int, int||[lv_obj_scroll_to](https://docs.lvgl.io/9.0/search.html?q=lv_obj_scroll_to)
@ -824,6 +882,7 @@ set_align|int||[lv_obj_set_align](https://docs.lvgl.io/9.0/search.html?q=lv_obj_
set_content_height|int||[lv_obj_set_content_height](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_content_height)
set_content_width|int||[lv_obj_set_content_width](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_content_width)
set_ext_click_area|int||[lv_obj_set_ext_click_area](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_ext_click_area)
set_flag|int, bool||[lv_obj_set_flag](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_flag)
set_flex_align|int, int, int||[lv_obj_set_flex_align](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_flex_align)
set_flex_flow|int||[lv_obj_set_flex_flow](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_flex_flow)
set_flex_grow|int||[lv_obj_set_flex_grow](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_flex_grow)
@ -929,11 +988,15 @@ set_style_pad_column|int, int||[lv_obj_set_style_pad_column](https://docs.lvgl.i
set_style_pad_gap|int, int||[lv_obj_set_style_pad_gap](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_style_pad_gap)
set_style_pad_hor|int, int||[lv_obj_set_style_pad_hor](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_style_pad_hor)
set_style_pad_left|int, int||[lv_obj_set_style_pad_left](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_style_pad_left)
set_style_pad_radial|int, int||[lv_obj_set_style_pad_radial](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_style_pad_radial)
set_style_pad_right|int, int||[lv_obj_set_style_pad_right](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_style_pad_right)
set_style_pad_row|int, int||[lv_obj_set_style_pad_row](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_style_pad_row)
set_style_pad_top|int, int||[lv_obj_set_style_pad_top](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_style_pad_top)
set_style_pad_ver|int, int||[lv_obj_set_style_pad_ver](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_style_pad_ver)
set_style_radial_offset|int, int||[lv_obj_set_style_radial_offset](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_style_radial_offset)
set_style_radius|int, int||[lv_obj_set_style_radius](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_style_radius)
set_style_recolor|lv.color, int||[lv_obj_set_style_recolor](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_style_recolor)
set_style_recolor_opa|int, int||[lv_obj_set_style_recolor_opa](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_style_recolor_opa)
set_style_rotary_sensitivity|int, int||[lv_obj_set_style_rotary_sensitivity](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_style_rotary_sensitivity)
set_style_shadow_color|lv.color, int||[lv_obj_set_style_shadow_color](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_style_shadow_color)
set_style_shadow_offset_x|int, int||[lv_obj_set_style_shadow_offset_x](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_style_shadow_offset_x)
@ -951,6 +1014,9 @@ set_style_text_font|lv.font, int||[lv_obj_set_style_text_font](https://docs.lvgl
set_style_text_letter_space|int, int||[lv_obj_set_style_text_letter_space](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_style_text_letter_space)
set_style_text_line_space|int, int||[lv_obj_set_style_text_line_space](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_style_text_line_space)
set_style_text_opa|int, int||[lv_obj_set_style_text_opa](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_style_text_opa)
set_style_text_outline_stroke_color|lv.color, int||[lv_obj_set_style_text_outline_stroke_color](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_style_text_outline_stroke_color)
set_style_text_outline_stroke_opa|int, int||[lv_obj_set_style_text_outline_stroke_opa](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_style_text_outline_stroke_opa)
set_style_text_outline_stroke_width|int, int||[lv_obj_set_style_text_outline_stroke_width](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_style_text_outline_stroke_width)
set_style_transform_angle|int, int||[lv_obj_set_style_transform_rotation](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_style_transform_rotation)
set_style_transform_height|int, int||[lv_obj_set_style_transform_height](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_style_transform_height)
set_style_transform_pivot_x|int, int||[lv_obj_set_style_transform_pivot_x](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_style_transform_pivot_x)
@ -964,6 +1030,7 @@ set_style_transform_skew_y|int, int||[lv_obj_set_style_transform_skew_y](https:/
set_style_transform_width|int, int||[lv_obj_set_style_transform_width](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_style_transform_width)
set_style_transform_zoom|int, int||[lv_obj_set_style_transform_scale](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_style_transform_scale)
set_style_transition|lv.style_transition_dsc, int||[lv_obj_set_style_transition](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_style_transition)
set_style_translate_radial|int, int||[lv_obj_set_style_translate_radial](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_style_translate_radial)
set_style_translate_x|int, int||[lv_obj_set_style_translate_x](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_style_translate_x)
set_style_translate_y|int, int||[lv_obj_set_style_translate_y](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_style_translate_y)
set_style_width|int, int||[lv_obj_set_style_width](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_style_width)
@ -973,12 +1040,13 @@ set_user_data|\<any\>||[lv_obj_set_user_data](https://docs.lvgl.io/9.0/search.ht
set_width|int||[lv_obj_set_width](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_width)
set_x|int||[lv_obj_set_x](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_x)
set_y|int||[lv_obj_set_y](https://docs.lvgl.io/9.0/search.html?q=lv_obj_set_y)
stop_scroll_anim|||[lv_obj_stop_scroll_anim](https://docs.lvgl.io/9.0/search.html?q=lv_obj_stop_scroll_anim)
stringify_id|comptr, int|string|[lv_obj_stringify_id](https://docs.lvgl.io/9.0/search.html?q=lv_obj_stringify_id)
style_apply_color_filter|int, int|int|[lv_obj_style_apply_color_filter](https://docs.lvgl.io/9.0/search.html?q=lv_obj_style_apply_color_filter)
style_apply_recolor|int, int|int|[lv_obj_style_apply_recolor](https://docs.lvgl.io/9.0/search.html?q=lv_obj_style_apply_recolor)
swap|lv.obj||[lv_obj_swap](https://docs.lvgl.io/9.0/search.html?q=lv_obj_swap)
transform_point|comptr, int||[lv_obj_transform_point](https://docs.lvgl.io/9.0/search.html?q=lv_obj_transform_point)
transform_point_array|lv.point_arr, int, int||[lv_obj_transform_point_array](https://docs.lvgl.io/9.0/search.html?q=lv_obj_transform_point_array)
update_flag|int, bool||[lv_obj_update_flag](https://docs.lvgl.io/9.0/search.html?q=lv_obj_update_flag)
update_layout|||[lv_obj_update_layout](https://docs.lvgl.io/9.0/search.html?q=lv_obj_update_layout)
update_snap|int||[lv_obj_update_snap](https://docs.lvgl.io/9.0/search.html?q=lv_obj_update_snap)
@ -1127,6 +1195,10 @@ get_scale||int|[lv_image_get_scale](https://docs.lvgl.io/9.0/search.html?q=lv_im
get_scale_x||int|[lv_image_get_scale_x](https://docs.lvgl.io/9.0/search.html?q=lv_image_get_scale_x)
get_scale_y||int|[lv_image_get_scale_y](https://docs.lvgl.io/9.0/search.html?q=lv_image_get_scale_y)
get_src||comptr|[lv_image_get_src](https://docs.lvgl.io/9.0/search.html?q=lv_image_get_src)
get_src_height||int|[lv_image_get_src_height](https://docs.lvgl.io/9.0/search.html?q=lv_image_get_src_height)
get_src_width||int|[lv_image_get_src_width](https://docs.lvgl.io/9.0/search.html?q=lv_image_get_src_width)
get_transformed_height||int|[lv_image_get_transformed_height](https://docs.lvgl.io/9.0/search.html?q=lv_image_get_transformed_height)
get_transformed_width||int|[lv_image_get_transformed_width](https://docs.lvgl.io/9.0/search.html?q=lv_image_get_transformed_width)
get_zoom||int|[lv_image_get_scale](https://docs.lvgl.io/9.0/search.html?q=lv_image_get_scale)
set_angle|int||[lv_image_set_rotation](https://docs.lvgl.io/9.0/search.html?q=lv_image_set_rotation)
set_antialias|bool||[lv_image_set_antialias](https://docs.lvgl.io/9.0/search.html?q=lv_image_set_antialias)
@ -1153,12 +1225,14 @@ cut_text|int, int||[lv_label_cut_text](https://docs.lvgl.io/9.0/search.html?q=lv
get_letter_on|comptr, bool|int|[lv_label_get_letter_on](https://docs.lvgl.io/9.0/search.html?q=lv_label_get_letter_on)
get_letter_pos|int, comptr||[lv_label_get_letter_pos](https://docs.lvgl.io/9.0/search.html?q=lv_label_get_letter_pos)
get_long_mode||int|[lv_label_get_long_mode](https://docs.lvgl.io/9.0/search.html?q=lv_label_get_long_mode)
get_recolor||bool|[lv_label_get_recolor](https://docs.lvgl.io/9.0/search.html?q=lv_label_get_recolor)
get_text||string|[lv_label_get_text](https://docs.lvgl.io/9.0/search.html?q=lv_label_get_text)
get_text_selection_end||int|[lv_label_get_text_selection_end](https://docs.lvgl.io/9.0/search.html?q=lv_label_get_text_selection_end)
get_text_selection_start||int|[lv_label_get_text_selection_start](https://docs.lvgl.io/9.0/search.html?q=lv_label_get_text_selection_start)
ins_text|int, string||[lv_label_ins_text](https://docs.lvgl.io/9.0/search.html?q=lv_label_ins_text)
is_char_under_pos|comptr|bool|[lv_label_is_char_under_pos](https://docs.lvgl.io/9.0/search.html?q=lv_label_is_char_under_pos)
set_long_mode|int||[lv_label_set_long_mode](https://docs.lvgl.io/9.0/search.html?q=lv_label_set_long_mode)
set_recolor|bool||[lv_label_set_recolor](https://docs.lvgl.io/9.0/search.html?q=lv_label_set_recolor)
set_text|string||[lv_label_set_text](https://docs.lvgl.io/9.0/search.html?q=lv_label_set_text)
set_text_fmt|string, [\<any\>]||[lv_label_set_text_fmt](https://docs.lvgl.io/9.0/search.html?q=lv_label_set_text_fmt)
set_text_selection_end|int||[lv_label_set_text_selection_end](https://docs.lvgl.io/9.0/search.html?q=lv_label_set_text_selection_end)
@ -1189,6 +1263,7 @@ get_selected||int|[lv_roller_get_selected](https://docs.lvgl.io/9.0/search.html?
get_selected_str|comptr, int||[lv_roller_get_selected_str](https://docs.lvgl.io/9.0/search.html?q=lv_roller_get_selected_str)
set_options|string, int||[lv_roller_set_options](https://docs.lvgl.io/9.0/search.html?q=lv_roller_set_options)
set_selected|int, int||[lv_roller_set_selected](https://docs.lvgl.io/9.0/search.html?q=lv_roller_set_selected)
set_selected_str|string, int|bool|[lv_roller_set_selected_str](https://docs.lvgl.io/9.0/search.html?q=lv_roller_set_selected_str)
set_visible_row_cnt|int||[lv_roller_set_visible_row_count](https://docs.lvgl.io/9.0/search.html?q=lv_roller_set_visible_row_count)
set_visible_row_count|int||[lv_roller_set_visible_row_count](https://docs.lvgl.io/9.0/search.html?q=lv_roller_set_visible_row_count)
@ -1200,24 +1275,27 @@ get_left_value||int|[lv_slider_get_left_value](https://docs.lvgl.io/9.0/search.h
get_max_value||int|[lv_slider_get_max_value](https://docs.lvgl.io/9.0/search.html?q=lv_slider_get_max_value)
get_min_value||int|[lv_slider_get_min_value](https://docs.lvgl.io/9.0/search.html?q=lv_slider_get_min_value)
get_mode||int|[lv_slider_get_mode](https://docs.lvgl.io/9.0/search.html?q=lv_slider_get_mode)
get_orientation||int|[lv_slider_get_orientation](https://docs.lvgl.io/9.0/search.html?q=lv_slider_get_orientation)
get_value||int|[lv_slider_get_value](https://docs.lvgl.io/9.0/search.html?q=lv_slider_get_value)
is_dragged||bool|[lv_slider_is_dragged](https://docs.lvgl.io/9.0/search.html?q=lv_slider_is_dragged)
is_symmetrical||bool|[lv_slider_is_symmetrical](https://docs.lvgl.io/9.0/search.html?q=lv_slider_is_symmetrical)
set_left_value|int, int||[lv_slider_set_left_value](https://docs.lvgl.io/9.0/search.html?q=lv_slider_set_left_value)
set_mode|int||[lv_slider_set_mode](https://docs.lvgl.io/9.0/search.html?q=lv_slider_set_mode)
set_orientation|int||[lv_slider_set_orientation](https://docs.lvgl.io/9.0/search.html?q=lv_slider_set_orientation)
set_range|int, int||[lv_slider_set_range](https://docs.lvgl.io/9.0/search.html?q=lv_slider_set_range)
set_start_value|int, int||[lv_slider_set_start_value](https://docs.lvgl.io/9.0/search.html?q=lv_slider_set_start_value)
set_value|int, int||[lv_slider_set_value](https://docs.lvgl.io/9.0/search.html?q=lv_slider_set_value)
### widget `lv.switch`
Method|Arguments|Return type|LVGL equivalent
:---|:---|:---|:---
get_orientation||int|[lv_switch_get_orientation](https://docs.lvgl.io/9.0/search.html?q=lv_switch_get_orientation)
set_orientation|int||[lv_switch_set_orientation](https://docs.lvgl.io/9.0/search.html?q=lv_switch_set_orientation)
### widget `lv.table`
Method|Arguments|Return type|LVGL equivalent
:---|:---|:---|:---
add_cell_ctrl|int, int, int||[lv_table_add_cell_ctrl](https://docs.lvgl.io/9.0/search.html?q=lv_table_add_cell_ctrl)
clear_cell_ctrl|int, int, int||[lv_table_clear_cell_ctrl](https://docs.lvgl.io/9.0/search.html?q=lv_table_clear_cell_ctrl)
get_cell_user_data|int, int|comptr|[lv_table_get_cell_user_data](https://docs.lvgl.io/9.0/search.html?q=lv_table_get_cell_user_data)
get_cell_value|int, int|string|[lv_table_get_cell_value](https://docs.lvgl.io/9.0/search.html?q=lv_table_get_cell_value)
@ -1229,6 +1307,7 @@ get_row_cnt||int|[lv_table_get_row_count](https://docs.lvgl.io/9.0/search.html?q
get_row_count||int|[lv_table_get_row_count](https://docs.lvgl.io/9.0/search.html?q=lv_table_get_row_count)
get_selected_cell|lv.int_arr, lv.int_arr||[lv_table_get_selected_cell](https://docs.lvgl.io/9.0/search.html?q=lv_table_get_selected_cell)
has_cell_ctrl|int, int, int|bool|[lv_table_has_cell_ctrl](https://docs.lvgl.io/9.0/search.html?q=lv_table_has_cell_ctrl)
set_cell_ctrl|int, int, int||[lv_table_set_cell_ctrl](https://docs.lvgl.io/9.0/search.html?q=lv_table_set_cell_ctrl)
set_cell_user_data|int, int, \<any\>||[lv_table_set_cell_user_data](https://docs.lvgl.io/9.0/search.html?q=lv_table_set_cell_user_data)
set_cell_value|int, int, string||[lv_table_set_cell_value](https://docs.lvgl.io/9.0/search.html?q=lv_table_set_cell_value)
set_cell_value_fmt|int, int, string, [\<any\>]||[lv_table_set_cell_value_fmt](https://docs.lvgl.io/9.0/search.html?q=lv_table_set_cell_value_fmt)
@ -1285,6 +1364,7 @@ text_is_selected||bool|[lv_textarea_text_is_selected](https://docs.lvgl.io/9.0/s
Method|Arguments|Return type|LVGL equivalent
:---|:---|:---|:---
add_span||lv.span|[lv_spangroup_add_span](https://docs.lvgl.io/9.0/search.html?q=lv_spangroup_add_span)
delete_span|lv.span||[lv_spangroup_delete_span](https://docs.lvgl.io/9.0/search.html?q=lv_spangroup_delete_span)
get_align||int|[lv_spangroup_get_align](https://docs.lvgl.io/9.0/search.html?q=lv_spangroup_get_align)
get_child|int|lv.span|[lv_spangroup_get_child](https://docs.lvgl.io/9.0/search.html?q=lv_spangroup_get_child)
@ -1295,22 +1375,28 @@ get_max_line_height||int|[lv_spangroup_get_max_line_height](https://docs.lvgl.io
get_max_lines||int|[lv_spangroup_get_max_lines](https://docs.lvgl.io/9.0/search.html?q=lv_spangroup_get_max_lines)
get_mode||int|[lv_spangroup_get_mode](https://docs.lvgl.io/9.0/search.html?q=lv_spangroup_get_mode)
get_overflow||int|[lv_spangroup_get_overflow](https://docs.lvgl.io/9.0/search.html?q=lv_spangroup_get_overflow)
get_span_by_point|comptr|lv.span|[lv_spangroup_get_span_by_point](https://docs.lvgl.io/9.0/search.html?q=lv_spangroup_get_span_by_point)
get_span_coords|lv.span|lv.span_coords|[lv_spangroup_get_span_coords](https://docs.lvgl.io/9.0/search.html?q=lv_spangroup_get_span_coords)
get_span_count||int|[lv_spangroup_get_span_count](https://docs.lvgl.io/9.0/search.html?q=lv_spangroup_get_span_count)
new_span||lv.span|[lv_spangroup_new_span](https://docs.lvgl.io/9.0/search.html?q=lv_spangroup_new_span)
refr_mode|||[lv_spangroup_refr_mode](https://docs.lvgl.io/9.0/search.html?q=lv_spangroup_refr_mode)
refresh|||[lv_spangroup_refresh](https://docs.lvgl.io/9.0/search.html?q=lv_spangroup_refresh)
set_align|int||[lv_spangroup_set_align](https://docs.lvgl.io/9.0/search.html?q=lv_spangroup_set_align)
set_indent|int||[lv_spangroup_set_indent](https://docs.lvgl.io/9.0/search.html?q=lv_spangroup_set_indent)
set_max_lines|int||[lv_spangroup_set_max_lines](https://docs.lvgl.io/9.0/search.html?q=lv_spangroup_set_max_lines)
set_mode|int||[lv_spangroup_set_mode](https://docs.lvgl.io/9.0/search.html?q=lv_spangroup_set_mode)
set_overflow|int||[lv_spangroup_set_overflow](https://docs.lvgl.io/9.0/search.html?q=lv_spangroup_set_overflow)
set_span_style|lv.span, lv.style||[lv_spangroup_set_span_style](https://docs.lvgl.io/9.0/search.html?q=lv_spangroup_set_span_style)
set_span_text|lv.span, string||[lv_spangroup_set_span_text](https://docs.lvgl.io/9.0/search.html?q=lv_spangroup_set_span_text)
set_span_text_static|lv.span, string||[lv_spangroup_set_span_text_static](https://docs.lvgl.io/9.0/search.html?q=lv_spangroup_set_span_text_static)
### widget `lv.span`
Method|Arguments|Return type|LVGL equivalent
:---|:---|:---|:---
get_style||lv.style|[lv_span_get_style](https://docs.lvgl.io/9.0/search.html?q=lv_span_get_style)
get_text||string|[lv_span_get_text](https://docs.lvgl.io/9.0/search.html?q=lv_span_get_text)
set_text|string||[lv_span_set_text](https://docs.lvgl.io/9.0/search.html?q=lv_span_set_text)
set_text_static|string||[lv_span_set_text_static](https://docs.lvgl.io/9.0/search.html?q=lv_span_set_text_static)
set_text_static|string||[lv_span_set_text_static](https://docs.lvgl.io/9.0/search.html?q=lv_span_set_text_static)
### widget `lv.scale_section`
@ -1324,12 +1410,15 @@ set_style|int, lv.style||[lv_scale_section_set_style](https://docs.lvgl.io/9.0/s
Method|Arguments|Return type|LVGL equivalent
:---|:---|:---|:---
add_section||lv.scale_section|[lv_scale_add_section](https://docs.lvgl.io/9.0/search.html?q=lv_scale_add_section)
get_angle||int|[lv_scale_get_rotation](https://docs.lvgl.io/9.0/search.html?q=lv_scale_get_rotation)
get_angle_range||int|[lv_scale_get_angle_range](https://docs.lvgl.io/9.0/search.html?q=lv_scale_get_angle_range)
get_label_show||bool|[lv_scale_get_label_show](https://docs.lvgl.io/9.0/search.html?q=lv_scale_get_label_show)
get_major_tick_every||int|[lv_scale_get_major_tick_every](https://docs.lvgl.io/9.0/search.html?q=lv_scale_get_major_tick_every)
get_mode||int|[lv_scale_get_mode](https://docs.lvgl.io/9.0/search.html?q=lv_scale_get_mode)
get_range_max_value||int|[lv_scale_get_range_max_value](https://docs.lvgl.io/9.0/search.html?q=lv_scale_get_range_max_value)
get_range_min_value||int|[lv_scale_get_range_min_value](https://docs.lvgl.io/9.0/search.html?q=lv_scale_get_range_min_value)
get_rotation||int|[lv_scale_get_rotation](https://docs.lvgl.io/9.0/search.html?q=lv_scale_get_rotation)
get_rotation||int|[lv_scale_get_rotation](https://docs.lvgl.io/9.0/search.html?q=lv_scale_get_rotation)
get_total_tick_count||int|[lv_scale_get_total_tick_count](https://docs.lvgl.io/9.0/search.html?q=lv_scale_get_total_tick_count)
set_angle|int||[lv_scale_set_rotation](https://docs.lvgl.io/9.0/search.html?q=lv_scale_set_rotation)
set_angle_range|int||[lv_scale_set_angle_range](https://docs.lvgl.io/9.0/search.html?q=lv_scale_set_angle_range)
@ -1343,6 +1432,10 @@ set_post_draw|bool||[lv_scale_set_post_draw](https://docs.lvgl.io/9.0/search.htm
set_range|int, int||[lv_scale_set_range](https://docs.lvgl.io/9.0/search.html?q=lv_scale_set_range)
set_rotation|int||[lv_scale_set_rotation](https://docs.lvgl.io/9.0/search.html?q=lv_scale_set_rotation)
set_rotation|int||[lv_scale_set_rotation](https://docs.lvgl.io/9.0/search.html?q=lv_scale_set_rotation)
set_section_range|lv.scale_section, int, int||[lv_scale_set_section_range](https://docs.lvgl.io/9.0/search.html?q=lv_scale_set_section_range)
set_section_style_indicator|lv.scale_section, lv.style||[lv_scale_set_section_style_indicator](https://docs.lvgl.io/9.0/search.html?q=lv_scale_set_section_style_indicator)
set_section_style_items|lv.scale_section, lv.style||[lv_scale_set_section_style_items](https://docs.lvgl.io/9.0/search.html?q=lv_scale_set_section_style_items)
set_section_style_main|lv.scale_section, lv.style||[lv_scale_set_section_style_main](https://docs.lvgl.io/9.0/search.html?q=lv_scale_set_section_style_main)
set_text_src|lv.str_arr||[lv_scale_set_text_src](https://docs.lvgl.io/9.0/search.html?q=lv_scale_set_text_src)
set_total_tick_count|int||[lv_scale_set_total_tick_count](https://docs.lvgl.io/9.0/search.html?q=lv_scale_set_total_tick_count)
@ -1359,28 +1452,32 @@ get_point_pos_by_id|lv.chart_series, int, comptr||[lv_chart_get_point_pos_by_id]
get_pressed_point||int|[lv_chart_get_pressed_point](https://docs.lvgl.io/9.0/search.html?q=lv_chart_get_pressed_point)
get_series_color|lv.chart_series|lv.color|[lv_chart_get_series_color](https://docs.lvgl.io/9.0/search.html?q=lv_chart_get_series_color)
get_series_next|lv.chart_series|lv.chart_series|[lv_chart_get_series_next](https://docs.lvgl.io/9.0/search.html?q=lv_chart_get_series_next)
get_series_x_array|lv.chart_series|lv.int_arr|[lv_chart_get_series_x_array](https://docs.lvgl.io/9.0/search.html?q=lv_chart_get_series_x_array)
get_series_y_array|lv.chart_series|lv.int_arr|[lv_chart_get_series_y_array](https://docs.lvgl.io/9.0/search.html?q=lv_chart_get_series_y_array)
get_type||int|[lv_chart_get_type](https://docs.lvgl.io/9.0/search.html?q=lv_chart_get_type)
get_x_array|lv.chart_series|lv.int_arr|[lv_chart_get_x_array](https://docs.lvgl.io/9.0/search.html?q=lv_chart_get_x_array)
get_x_start_point|lv.chart_series|int|[lv_chart_get_x_start_point](https://docs.lvgl.io/9.0/search.html?q=lv_chart_get_x_start_point)
get_y_array|lv.chart_series|lv.int_arr|[lv_chart_get_y_array](https://docs.lvgl.io/9.0/search.html?q=lv_chart_get_y_array)
hide_series|lv.chart_series, bool||[lv_chart_hide_series](https://docs.lvgl.io/9.0/search.html?q=lv_chart_hide_series)
refresh|||[lv_chart_refresh](https://docs.lvgl.io/9.0/search.html?q=lv_chart_refresh)
remove_series|lv.chart_series||[lv_chart_remove_series](https://docs.lvgl.io/9.0/search.html?q=lv_chart_remove_series)
set_all_value|lv.chart_series, int||[lv_chart_set_all_value](https://docs.lvgl.io/9.0/search.html?q=lv_chart_set_all_value)
set_all_values|lv.chart_series, int||[lv_chart_set_all_values](https://docs.lvgl.io/9.0/search.html?q=lv_chart_set_all_values)
set_axis_range|int, int, int||[lv_chart_set_axis_range](https://docs.lvgl.io/9.0/search.html?q=lv_chart_set_axis_range)
set_cursor_point|lv.chart_cursor, lv.chart_series, int||[lv_chart_set_cursor_point](https://docs.lvgl.io/9.0/search.html?q=lv_chart_set_cursor_point)
set_cursor_pos|lv.chart_cursor, comptr||[lv_chart_set_cursor_pos](https://docs.lvgl.io/9.0/search.html?q=lv_chart_set_cursor_pos)
set_cursor_pos_x|lv.chart_cursor, int||[lv_chart_set_cursor_pos_x](https://docs.lvgl.io/9.0/search.html?q=lv_chart_set_cursor_pos_x)
set_cursor_pos_y|lv.chart_cursor, int||[lv_chart_set_cursor_pos_y](https://docs.lvgl.io/9.0/search.html?q=lv_chart_set_cursor_pos_y)
set_div_line_count|int, int||[lv_chart_set_div_line_count](https://docs.lvgl.io/9.0/search.html?q=lv_chart_set_div_line_count)
set_ext_x_array|lv.chart_series, lv.int_arr||[lv_chart_set_ext_x_array](https://docs.lvgl.io/9.0/search.html?q=lv_chart_set_ext_x_array)
set_ext_y_array|lv.chart_series, lv.int_arr||[lv_chart_set_ext_y_array](https://docs.lvgl.io/9.0/search.html?q=lv_chart_set_ext_y_array)
set_next_value|lv.chart_series, int||[lv_chart_set_next_value](https://docs.lvgl.io/9.0/search.html?q=lv_chart_set_next_value)
set_next_value2|lv.chart_series, int, int||[lv_chart_set_next_value2](https://docs.lvgl.io/9.0/search.html?q=lv_chart_set_next_value2)
set_point_count|int||[lv_chart_set_point_count](https://docs.lvgl.io/9.0/search.html?q=lv_chart_set_point_count)
set_range|int, int, int||[lv_chart_set_range](https://docs.lvgl.io/9.0/search.html?q=lv_chart_set_range)
set_series_color|lv.chart_series, lv.color||[lv_chart_set_series_color](https://docs.lvgl.io/9.0/search.html?q=lv_chart_set_series_color)
set_series_ext_x_array|lv.chart_series, lv.int_arr||[lv_chart_set_series_ext_x_array](https://docs.lvgl.io/9.0/search.html?q=lv_chart_set_series_ext_x_array)
set_series_ext_y_array|lv.chart_series, lv.int_arr||[lv_chart_set_series_ext_y_array](https://docs.lvgl.io/9.0/search.html?q=lv_chart_set_series_ext_y_array)
set_series_value_by_id|lv.chart_series, int, int||[lv_chart_set_series_value_by_id](https://docs.lvgl.io/9.0/search.html?q=lv_chart_set_series_value_by_id)
set_series_value_by_id2|lv.chart_series, int, int, int||[lv_chart_set_series_value_by_id2](https://docs.lvgl.io/9.0/search.html?q=lv_chart_set_series_value_by_id2)
set_series_values|lv.chart_series, lv.int_arr, int||[lv_chart_set_series_values](https://docs.lvgl.io/9.0/search.html?q=lv_chart_set_series_values)
set_series_values2|lv.chart_series, lv.int_arr, lv.int_arr, int||[lv_chart_set_series_values2](https://docs.lvgl.io/9.0/search.html?q=lv_chart_set_series_values2)
set_type|int||[lv_chart_set_type](https://docs.lvgl.io/9.0/search.html?q=lv_chart_set_type)
set_update_mode|int||[lv_chart_set_update_mode](https://docs.lvgl.io/9.0/search.html?q=lv_chart_set_update_mode)
set_value_by_id|lv.chart_series, int, int||[lv_chart_set_value_by_id](https://docs.lvgl.io/9.0/search.html?q=lv_chart_set_value_by_id)
set_value_by_id2|lv.chart_series, int, int, int||[lv_chart_set_value_by_id2](https://docs.lvgl.io/9.0/search.html?q=lv_chart_set_value_by_id2)
set_x_start_point|lv.chart_series, int||[lv_chart_set_x_start_point](https://docs.lvgl.io/9.0/search.html?q=lv_chart_set_x_start_point)
### widget `lv.imagebutton`
@ -1501,25 +1598,36 @@ set_button_text|lv.obj, string||[lv_list_set_button_text](https://docs.lvgl.io/9
Method|Arguments|Return type|LVGL equivalent
:---|:---|:---|:---
del||bool|[lv_animimg_delete](https://docs.lvgl.io/9.0/search.html?q=lv_animimg_delete)
delete||bool|[lv_animimg_delete](https://docs.lvgl.io/9.0/search.html?q=lv_animimg_delete)
get_anim||lv.anim|[lv_animimg_get_anim](https://docs.lvgl.io/9.0/search.html?q=lv_animimg_get_anim)
get_duration||int|[lv_animimg_get_duration](https://docs.lvgl.io/9.0/search.html?q=lv_animimg_get_duration)
get_repeat_count||int|[lv_animimg_get_repeat_count](https://docs.lvgl.io/9.0/search.html?q=lv_animimg_get_repeat_count)
get_src_count||int|[lv_animimg_get_src_count](https://docs.lvgl.io/9.0/search.html?q=lv_animimg_get_src_count)
remove||bool|[lv_animimg_delete](https://docs.lvgl.io/9.0/search.html?q=lv_animimg_delete)
set_completed_cb|comptr||[lv_animimg_set_completed_cb](https://docs.lvgl.io/9.0/search.html?q=lv_animimg_set_completed_cb)
set_duration|int||[lv_animimg_set_duration](https://docs.lvgl.io/9.0/search.html?q=lv_animimg_set_duration)
set_ready_cb|comptr||[lv_animimg_set_completed_cb](https://docs.lvgl.io/9.0/search.html?q=lv_animimg_set_completed_cb)
set_repeat_count|int||[lv_animimg_set_repeat_count](https://docs.lvgl.io/9.0/search.html?q=lv_animimg_set_repeat_count)
set_reverse_delay|int||[lv_animimg_set_reverse_delay](https://docs.lvgl.io/9.0/search.html?q=lv_animimg_set_reverse_delay)
set_reverse_duration|int||[lv_animimg_set_reverse_duration](https://docs.lvgl.io/9.0/search.html?q=lv_animimg_set_reverse_duration)
set_src|comptr, int||[lv_animimg_set_src](https://docs.lvgl.io/9.0/search.html?q=lv_animimg_set_src)
set_src_reverse|comptr, int||[lv_animimg_set_src_reverse](https://docs.lvgl.io/9.0/search.html?q=lv_animimg_set_src_reverse)
set_start_cb|comptr||[lv_animimg_set_start_cb](https://docs.lvgl.io/9.0/search.html?q=lv_animimg_set_start_cb)
start|||[lv_animimg_start](https://docs.lvgl.io/9.0/search.html?q=lv_animimg_start)
### widget `lv.calendar`
Method|Arguments|Return type|LVGL equivalent
:---|:---|:---|:---
add_header_arrow||lv.obj|[lv_calendar_add_header_arrow](https://docs.lvgl.io/9.0/search.html?q=lv_calendar_add_header_arrow)
add_header_dropdown||lv.obj|[lv_calendar_add_header_dropdown](https://docs.lvgl.io/9.0/search.html?q=lv_calendar_add_header_dropdown)
get_btnmatrix||lv.obj|[lv_calendar_get_btnmatrix](https://docs.lvgl.io/9.0/search.html?q=lv_calendar_get_btnmatrix)
get_highlighted_dates_num||int|[lv_calendar_get_highlighted_dates_num](https://docs.lvgl.io/9.0/search.html?q=lv_calendar_get_highlighted_dates_num)
header_dropdown_set_year_list|string||[lv_calendar_header_dropdown_set_year_list](https://docs.lvgl.io/9.0/search.html?q=lv_calendar_header_dropdown_set_year_list)
set_chinese_mode|bool||[lv_calendar_set_chinese_mode](https://docs.lvgl.io/9.0/search.html?q=lv_calendar_set_chinese_mode)
set_day_names|comptr||[lv_calendar_set_day_names](https://docs.lvgl.io/9.0/search.html?q=lv_calendar_set_day_names)
set_showed_date|int, int||[lv_calendar_set_showed_date](https://docs.lvgl.io/9.0/search.html?q=lv_calendar_set_showed_date)
set_month_shown|int, int||[lv_calendar_set_month_shown](https://docs.lvgl.io/9.0/search.html?q=lv_calendar_set_month_shown)
set_today_date|int, int, int||[lv_calendar_set_today_date](https://docs.lvgl.io/9.0/search.html?q=lv_calendar_set_today_date)
### widget `lv.menu_page`

View File

@ -13,6 +13,7 @@ extern "C" {
/* `lv_style` methods */
const be_ntv_func_def_t lv_style_func[] = {
{ "copy", { (const void*) &lv_style_copy, "", "(lv.style)(lv.style)" } },
{ "is_const", { (const void*) &lv_style_is_const, "b", "(lv.style)" } },
{ "is_empty", { (const void*) &lv_style_is_empty, "b", "(lv.style)" } },
{ "remove_prop", { (const void*) &lv_style_remove_prop, "b", "(lv.style)i" } },
@ -86,10 +87,13 @@ const be_ntv_func_def_t lv_style_func[] = {
{ "set_line_opa", { (const void*) &lv_style_set_line_opa, "", "(lv.style)i" } },
{ "set_line_rounded", { (const void*) &lv_style_set_line_rounded, "", "(lv.style)b" } },
{ "set_line_width", { (const void*) &lv_style_set_line_width, "", "(lv.style)i" } },
{ "set_margin_all", { (const void*) &lv_style_set_margin_all, "", "(lv.style)i" } },
{ "set_margin_bottom", { (const void*) &lv_style_set_margin_bottom, "", "(lv.style)i" } },
{ "set_margin_hor", { (const void*) &lv_style_set_margin_hor, "", "(lv.style)i" } },
{ "set_margin_left", { (const void*) &lv_style_set_margin_left, "", "(lv.style)i" } },
{ "set_margin_right", { (const void*) &lv_style_set_margin_right, "", "(lv.style)i" } },
{ "set_margin_top", { (const void*) &lv_style_set_margin_top, "", "(lv.style)i" } },
{ "set_margin_ver", { (const void*) &lv_style_set_margin_ver, "", "(lv.style)i" } },
{ "set_max_height", { (const void*) &lv_style_set_max_height, "", "(lv.style)i" } },
{ "set_max_width", { (const void*) &lv_style_set_max_width, "", "(lv.style)i" } },
{ "set_min_height", { (const void*) &lv_style_set_min_height, "", "(lv.style)i" } },
@ -106,12 +110,16 @@ const be_ntv_func_def_t lv_style_func[] = {
{ "set_pad_gap", { (const void*) &lv_style_set_pad_gap, "", "(lv.style)i" } },
{ "set_pad_hor", { (const void*) &lv_style_set_pad_hor, "", "(lv.style)i" } },
{ "set_pad_left", { (const void*) &lv_style_set_pad_left, "", "(lv.style)i" } },
{ "set_pad_radial", { (const void*) &lv_style_set_pad_radial, "", "(lv.style)i" } },
{ "set_pad_right", { (const void*) &lv_style_set_pad_right, "", "(lv.style)i" } },
{ "set_pad_row", { (const void*) &lv_style_set_pad_row, "", "(lv.style)i" } },
{ "set_pad_top", { (const void*) &lv_style_set_pad_top, "", "(lv.style)i" } },
{ "set_pad_ver", { (const void*) &lv_style_set_pad_ver, "", "(lv.style)i" } },
{ "set_prop", { (const void*) &lv_style_set_prop, "", "(lv.style)ii" } },
{ "set_radial_offset", { (const void*) &lv_style_set_radial_offset, "", "(lv.style)i" } },
{ "set_radius", { (const void*) &lv_style_set_radius, "", "(lv.style)i" } },
{ "set_recolor", { (const void*) &lv_style_set_recolor, "", "(lv.style)(lv.color)" } },
{ "set_recolor_opa", { (const void*) &lv_style_set_recolor_opa, "", "(lv.style)i" } },
{ "set_rotary_sensitivity", { (const void*) &lv_style_set_rotary_sensitivity, "", "(lv.style)i" } },
{ "set_shadow_color", { (const void*) &lv_style_set_shadow_color, "", "(lv.style)(lv.color)" } },
{ "set_shadow_offset_x", { (const void*) &lv_style_set_shadow_offset_x, "", "(lv.style)i" } },
@ -129,6 +137,9 @@ const be_ntv_func_def_t lv_style_func[] = {
{ "set_text_letter_space", { (const void*) &lv_style_set_text_letter_space, "", "(lv.style)i" } },
{ "set_text_line_space", { (const void*) &lv_style_set_text_line_space, "", "(lv.style)i" } },
{ "set_text_opa", { (const void*) &lv_style_set_text_opa, "", "(lv.style)i" } },
{ "set_text_outline_stroke_color", { (const void*) &lv_style_set_text_outline_stroke_color, "", "(lv.style)(lv.color)" } },
{ "set_text_outline_stroke_opa", { (const void*) &lv_style_set_text_outline_stroke_opa, "", "(lv.style)i" } },
{ "set_text_outline_stroke_width", { (const void*) &lv_style_set_text_outline_stroke_width, "", "(lv.style)i" } },
{ "set_transform_angle", { (const void*) &lv_style_set_transform_rotation, "", "(lv.style)i" } },
{ "set_transform_height", { (const void*) &lv_style_set_transform_height, "", "(lv.style)i" } },
{ "set_transform_pivot_x", { (const void*) &lv_style_set_transform_pivot_x, "", "(lv.style)i" } },
@ -142,6 +153,7 @@ const be_ntv_func_def_t lv_style_func[] = {
{ "set_transform_width", { (const void*) &lv_style_set_transform_width, "", "(lv.style)i" } },
{ "set_transform_zoom", { (const void*) &lv_style_set_transform_scale, "", "(lv.style)i" } },
{ "set_transition", { (const void*) &lv_style_set_transition, "", "(lv.style)(lv.style_transition_dsc)" } },
{ "set_translate_radial", { (const void*) &lv_style_set_translate_radial, "", "(lv.style)i" } },
{ "set_translate_x", { (const void*) &lv_style_set_translate_x, "", "(lv.style)i" } },
{ "set_translate_y", { (const void*) &lv_style_set_translate_y, "", "(lv.style)i" } },
{ "set_width", { (const void*) &lv_style_set_width, "", "(lv.style)i" } },
@ -216,9 +228,9 @@ const be_ntv_func_def_t lv_obj_func[] = {
{ "dump_tree", { (const void*) &lv_obj_dump_tree, "", "(lv.obj)" } },
{ "fade_in", { (const void*) &lv_obj_fade_in, "", "(lv.obj)ii" } },
{ "fade_out", { (const void*) &lv_obj_fade_out, "", "(lv.obj)ii" } },
{ "find_by_id", { (const void*) &lv_obj_find_by_id, "lv.obj", "(lv.obj)." } },
{ "free_id", { (const void*) &lv_obj_free_id, "", "(lv.obj)" } },
{ "get_child", { (const void*) &lv_obj_get_child, "lv.obj", "(lv.obj)i" } },
{ "get_child_by_id", { (const void*) &lv_obj_get_child_by_id, "lv.obj", "(lv.obj)." } },
{ "get_child_by_type", { (const void*) &lv_obj_get_child_by_type, "lv.obj", "(lv.obj)i(lv.obj_class)" } },
{ "get_child_cnt", { (const void*) &lv_obj_get_child_count, "i", "(lv.obj)" } },
{ "get_child_count", { (const void*) &lv_obj_get_child_count, "i", "(lv.obj)" } },
@ -348,11 +360,16 @@ const be_ntv_func_def_t lv_obj_func[] = {
{ "get_style_pad_bottom", { (const void*) &lv_obj_get_style_pad_bottom, "i", "(lv.obj)i" } },
{ "get_style_pad_column", { (const void*) &lv_obj_get_style_pad_column, "i", "(lv.obj)i" } },
{ "get_style_pad_left", { (const void*) &lv_obj_get_style_pad_left, "i", "(lv.obj)i" } },
{ "get_style_pad_radial", { (const void*) &lv_obj_get_style_pad_radial, "i", "(lv.obj)i" } },
{ "get_style_pad_right", { (const void*) &lv_obj_get_style_pad_right, "i", "(lv.obj)i" } },
{ "get_style_pad_row", { (const void*) &lv_obj_get_style_pad_row, "i", "(lv.obj)i" } },
{ "get_style_pad_top", { (const void*) &lv_obj_get_style_pad_top, "i", "(lv.obj)i" } },
{ "get_style_prop", { (const void*) &lv_obj_get_style_prop, "i", "(lv.obj)ii" } },
{ "get_style_radial_offset", { (const void*) &lv_obj_get_style_radial_offset, "i", "(lv.obj)i" } },
{ "get_style_radius", { (const void*) &lv_obj_get_style_radius, "i", "(lv.obj)i" } },
{ "get_style_recolor", { (const void*) &lv_obj_get_style_recolor, "lv.color", "(lv.obj)i" } },
{ "get_style_recolor_opa", { (const void*) &lv_obj_get_style_recolor_opa, "i", "(lv.obj)i" } },
{ "get_style_recolor_recursive", { (const void*) &lv_obj_get_style_recolor_recursive, "i", "(lv.obj)i" } },
{ "get_style_rotary_sensitivity", { (const void*) &lv_obj_get_style_rotary_sensitivity, "i", "(lv.obj)i" } },
{ "get_style_shadow_color", { (const void*) &lv_obj_get_style_shadow_color, "lv.color", "(lv.obj)i" } },
{ "get_style_shadow_color_filtered", { (const void*) &lv_obj_get_style_shadow_color_filtered, "lv.color", "(lv.obj)i" } },
@ -375,6 +392,10 @@ const be_ntv_func_def_t lv_obj_func[] = {
{ "get_style_text_letter_space", { (const void*) &lv_obj_get_style_text_letter_space, "i", "(lv.obj)i" } },
{ "get_style_text_line_space", { (const void*) &lv_obj_get_style_text_line_space, "i", "(lv.obj)i" } },
{ "get_style_text_opa", { (const void*) &lv_obj_get_style_text_opa, "i", "(lv.obj)i" } },
{ "get_style_text_outline_stroke_color", { (const void*) &lv_obj_get_style_text_outline_stroke_color, "lv.color", "(lv.obj)i" } },
{ "get_style_text_outline_stroke_color_filtered", { (const void*) &lv_obj_get_style_text_outline_stroke_color_filtered, "lv.color", "(lv.obj)i" } },
{ "get_style_text_outline_stroke_opa", { (const void*) &lv_obj_get_style_text_outline_stroke_opa, "i", "(lv.obj)i" } },
{ "get_style_text_outline_stroke_width", { (const void*) &lv_obj_get_style_text_outline_stroke_width, "i", "(lv.obj)i" } },
{ "get_style_transform_angle", { (const void*) &lv_obj_get_style_transform_rotation, "i", "(lv.obj)i" } },
{ "get_style_transform_height", { (const void*) &lv_obj_get_style_transform_height, "i", "(lv.obj)i" } },
{ "get_style_transform_pivot_x", { (const void*) &lv_obj_get_style_transform_pivot_x, "i", "(lv.obj)i" } },
@ -388,6 +409,7 @@ const be_ntv_func_def_t lv_obj_func[] = {
{ "get_style_transform_skew_y", { (const void*) &lv_obj_get_style_transform_skew_y, "i", "(lv.obj)i" } },
{ "get_style_transform_width", { (const void*) &lv_obj_get_style_transform_width, "i", "(lv.obj)i" } },
{ "get_style_transition", { (const void*) &lv_obj_get_style_transition, "lv.style_transition_dsc", "(lv.obj)i" } },
{ "get_style_translate_radial", { (const void*) &lv_obj_get_style_translate_radial, "i", "(lv.obj)i" } },
{ "get_style_translate_x", { (const void*) &lv_obj_get_style_translate_x, "i", "(lv.obj)i" } },
{ "get_style_translate_y", { (const void*) &lv_obj_get_style_translate_y, "i", "(lv.obj)i" } },
{ "get_style_width", { (const void*) &lv_obj_get_style_width, "i", "(lv.obj)i" } },
@ -435,7 +457,7 @@ const be_ntv_func_def_t lv_obj_func[] = {
{ "refresh_style", { (const void*) &lv_obj_refresh_style, "", "(lv.obj)ii" } },
{ "remove", { (const void*) &lv_obj_delete, "", "(lv.obj)" } },
{ "remove_event", { (const void*) &lv_obj_remove_event, "b", "(lv.obj)i" } },
{ "remove_event_cb", { (const void*) &lv_obj_remove_event_cb, "b", "(lv.obj)." } },
{ "remove_event_cb", { (const void*) &lv_obj_remove_event_cb, "i", "(lv.obj)." } },
{ "remove_event_cb_with_user_data", { (const void*) &lv_obj_remove_event_cb_with_user_data, "i", "(lv.obj).." } },
{ "remove_event_dsc", { (const void*) &lv_obj_remove_event_dsc, "b", "(lv.obj)(lv.event_dsc)" } },
{ "remove_flag", { (const void*) &lv_obj_remove_flag, "", "(lv.obj)i" } },
@ -444,6 +466,7 @@ const be_ntv_func_def_t lv_obj_func[] = {
{ "remove_style", { (const void*) &lv_obj_remove_style, "", "(lv.obj)(lv.style)i" } },
{ "remove_style_all", { (const void*) &lv_obj_remove_style_all, "", "(lv.obj)" } },
{ "replace_style", { (const void*) &lv_obj_replace_style, "b", "(lv.obj)(lv.style)(lv.style)i" } },
{ "reset_transform", { (const void*) &lv_obj_reset_transform, "", "(lv.obj)" } },
{ "scroll_by", { (const void*) &lv_obj_scroll_by, "", "(lv.obj)iii" } },
{ "scroll_by_bounded", { (const void*) &lv_obj_scroll_by_bounded, "", "(lv.obj)iii" } },
{ "scroll_to", { (const void*) &lv_obj_scroll_to, "", "(lv.obj)iii" } },
@ -457,6 +480,7 @@ const be_ntv_func_def_t lv_obj_func[] = {
{ "set_content_height", { (const void*) &lv_obj_set_content_height, "", "(lv.obj)i" } },
{ "set_content_width", { (const void*) &lv_obj_set_content_width, "", "(lv.obj)i" } },
{ "set_ext_click_area", { (const void*) &lv_obj_set_ext_click_area, "", "(lv.obj)i" } },
{ "set_flag", { (const void*) &lv_obj_set_flag, "", "(lv.obj)ib" } },
{ "set_flex_align", { (const void*) &lv_obj_set_flex_align, "", "(lv.obj)iii" } },
{ "set_flex_flow", { (const void*) &lv_obj_set_flex_flow, "", "(lv.obj)i" } },
{ "set_flex_grow", { (const void*) &lv_obj_set_flex_grow, "", "(lv.obj)i" } },
@ -562,11 +586,15 @@ const be_ntv_func_def_t lv_obj_func[] = {
{ "set_style_pad_gap", { (const void*) &lv_obj_set_style_pad_gap, "", "(lv.obj)ii" } },
{ "set_style_pad_hor", { (const void*) &lv_obj_set_style_pad_hor, "", "(lv.obj)ii" } },
{ "set_style_pad_left", { (const void*) &lv_obj_set_style_pad_left, "", "(lv.obj)ii" } },
{ "set_style_pad_radial", { (const void*) &lv_obj_set_style_pad_radial, "", "(lv.obj)ii" } },
{ "set_style_pad_right", { (const void*) &lv_obj_set_style_pad_right, "", "(lv.obj)ii" } },
{ "set_style_pad_row", { (const void*) &lv_obj_set_style_pad_row, "", "(lv.obj)ii" } },
{ "set_style_pad_top", { (const void*) &lv_obj_set_style_pad_top, "", "(lv.obj)ii" } },
{ "set_style_pad_ver", { (const void*) &lv_obj_set_style_pad_ver, "", "(lv.obj)ii" } },
{ "set_style_radial_offset", { (const void*) &lv_obj_set_style_radial_offset, "", "(lv.obj)ii" } },
{ "set_style_radius", { (const void*) &lv_obj_set_style_radius, "", "(lv.obj)ii" } },
{ "set_style_recolor", { (const void*) &lv_obj_set_style_recolor, "", "(lv.obj)(lv.color)i" } },
{ "set_style_recolor_opa", { (const void*) &lv_obj_set_style_recolor_opa, "", "(lv.obj)ii" } },
{ "set_style_rotary_sensitivity", { (const void*) &lv_obj_set_style_rotary_sensitivity, "", "(lv.obj)ii" } },
{ "set_style_shadow_color", { (const void*) &lv_obj_set_style_shadow_color, "", "(lv.obj)(lv.color)i" } },
{ "set_style_shadow_offset_x", { (const void*) &lv_obj_set_style_shadow_offset_x, "", "(lv.obj)ii" } },
@ -584,6 +612,9 @@ const be_ntv_func_def_t lv_obj_func[] = {
{ "set_style_text_letter_space", { (const void*) &lv_obj_set_style_text_letter_space, "", "(lv.obj)ii" } },
{ "set_style_text_line_space", { (const void*) &lv_obj_set_style_text_line_space, "", "(lv.obj)ii" } },
{ "set_style_text_opa", { (const void*) &lv_obj_set_style_text_opa, "", "(lv.obj)ii" } },
{ "set_style_text_outline_stroke_color", { (const void*) &lv_obj_set_style_text_outline_stroke_color, "", "(lv.obj)(lv.color)i" } },
{ "set_style_text_outline_stroke_opa", { (const void*) &lv_obj_set_style_text_outline_stroke_opa, "", "(lv.obj)ii" } },
{ "set_style_text_outline_stroke_width", { (const void*) &lv_obj_set_style_text_outline_stroke_width, "", "(lv.obj)ii" } },
{ "set_style_transform_angle", { (const void*) &lv_obj_set_style_transform_rotation, "", "(lv.obj)ii" } },
{ "set_style_transform_height", { (const void*) &lv_obj_set_style_transform_height, "", "(lv.obj)ii" } },
{ "set_style_transform_pivot_x", { (const void*) &lv_obj_set_style_transform_pivot_x, "", "(lv.obj)ii" } },
@ -597,6 +628,7 @@ const be_ntv_func_def_t lv_obj_func[] = {
{ "set_style_transform_width", { (const void*) &lv_obj_set_style_transform_width, "", "(lv.obj)ii" } },
{ "set_style_transform_zoom", { (const void*) &lv_obj_set_style_transform_scale, "", "(lv.obj)ii" } },
{ "set_style_transition", { (const void*) &lv_obj_set_style_transition, "", "(lv.obj)(lv.style_transition_dsc)i" } },
{ "set_style_translate_radial", { (const void*) &lv_obj_set_style_translate_radial, "", "(lv.obj)ii" } },
{ "set_style_translate_x", { (const void*) &lv_obj_set_style_translate_x, "", "(lv.obj)ii" } },
{ "set_style_translate_y", { (const void*) &lv_obj_set_style_translate_y, "", "(lv.obj)ii" } },
{ "set_style_width", { (const void*) &lv_obj_set_style_width, "", "(lv.obj)ii" } },
@ -606,12 +638,13 @@ const be_ntv_func_def_t lv_obj_func[] = {
{ "set_width", { (const void*) &lv_obj_set_width, "", "(lv.obj)i" } },
{ "set_x", { (const void*) &lv_obj_set_x, "", "(lv.obj)i" } },
{ "set_y", { (const void*) &lv_obj_set_y, "", "(lv.obj)i" } },
{ "stop_scroll_anim", { (const void*) &lv_obj_stop_scroll_anim, "", "(lv.obj)" } },
{ "stringify_id", { (const void*) &lv_obj_stringify_id, "s", "(lv.obj)ci" } },
{ "style_apply_color_filter", { (const void*) &lv_obj_style_apply_color_filter, "i", "(lv.obj)ii" } },
{ "style_apply_recolor", { (const void*) &lv_obj_style_apply_recolor, "i", "(lv.obj)ii" } },
{ "swap", { (const void*) &lv_obj_swap, "", "(lv.obj)(lv.obj)" } },
{ "transform_point", { (const void*) &lv_obj_transform_point, "", "(lv.obj)ci" } },
{ "transform_point_array", { (const void*) &lv_obj_transform_point_array, "", "(lv.obj)(lv.point_arr)ii" } },
{ "update_flag", { (const void*) &lv_obj_update_flag, "", "(lv.obj)ib" } },
{ "update_layout", { (const void*) &lv_obj_update_layout, "", "(lv.obj)" } },
{ "update_snap", { (const void*) &lv_obj_update_snap, "", "(lv.obj)i" } },
};
@ -625,6 +658,7 @@ const be_ntv_func_def_t lv_event_func[] = {
{ "get_current_target_obj", { (const void*) &lv_event_get_current_target_obj, "lv.obj", "(lv.event)" } },
{ "get_hit_test_info", { (const void*) &lv_event_get_hit_test_info, "c", "(lv.event)" } },
{ "get_indev", { (const void*) &lv_event_get_indev, "lv.indev", "(lv.event)" } },
{ "get_invalidated_area", { (const void*) &lv_event_get_invalidated_area, "lv.area", "(lv.event)" } },
{ "get_key", { (const void*) &lv_event_get_key, "i", "(lv.event)" } },
{ "get_layer", { (const void*) &lv_event_get_layer, "lv.layer", "(lv.event)" } },
{ "get_old_size", { (const void*) &lv_event_get_old_size, "lv.area", "(lv.event)" } },
@ -654,18 +688,23 @@ const be_ntv_func_def_t lv_display_func[] = {
{ "get_antialiasing", { (const void*) &lv_display_get_antialiasing, "b", "(lv.display)" } },
{ "get_color_format", { (const void*) &lv_display_get_color_format, "i", "(lv.display)" } },
{ "get_dpi", { (const void*) &lv_display_get_dpi, "i", "(lv.display)" } },
{ "get_draw_buf_size", { (const void*) &lv_display_get_draw_buf_size, "i", "(lv.display)" } },
{ "get_driver_data", { (const void*) &lv_display_get_driver_data, "c", "(lv.display)" } },
{ "get_event_count", { (const void*) &lv_display_get_event_count, "i", "(lv.display)" } },
{ "get_event_dsc", { (const void*) &lv_display_get_event_dsc, "lv.event_dsc", "(lv.display)i" } },
{ "get_hor_res", { (const void*) &lv_display_get_horizontal_resolution, "i", "(lv.display)" } },
{ "get_horizontal_resolution", { (const void*) &lv_display_get_horizontal_resolution, "i", "(lv.display)" } },
{ "get_inactive_time", { (const void*) &lv_display_get_inactive_time, "i", "(lv.display)" } },
{ "get_invalidated_draw_buf_size", { (const void*) &lv_display_get_invalidated_draw_buf_size, "i", "(lv.display)ii" } },
{ "get_layer_bottom", { (const void*) &lv_display_get_layer_bottom, "lv.obj", "(lv.display)" } },
{ "get_layer_sys", { (const void*) &lv_display_get_layer_sys, "lv.obj", "(lv.display)" } },
{ "get_layer_top", { (const void*) &lv_display_get_layer_top, "lv.obj", "(lv.display)" } },
{ "get_matrix_rotation", { (const void*) &lv_display_get_matrix_rotation, "b", "(lv.display)" } },
{ "get_next", { (const void*) &lv_display_get_next, "lv.display", "(lv.display)" } },
{ "get_offset_x", { (const void*) &lv_display_get_offset_x, "i", "(lv.display)" } },
{ "get_offset_y", { (const void*) &lv_display_get_offset_y, "i", "(lv.display)" } },
{ "get_original_horizontal_resolution", { (const void*) &lv_display_get_original_horizontal_resolution, "i", "(lv.display)" } },
{ "get_original_vertical_resolution", { (const void*) &lv_display_get_original_vertical_resolution, "i", "(lv.display)" } },
{ "get_physical_hor_res", { (const void*) &lv_display_get_physical_horizontal_resolution, "i", "(lv.display)" } },
{ "get_physical_horizontal_resolution", { (const void*) &lv_display_get_physical_horizontal_resolution, "i", "(lv.display)" } },
{ "get_physical_ver_res", { (const void*) &lv_display_get_physical_vertical_resolution, "i", "(lv.display)" } },
@ -677,31 +716,38 @@ const be_ntv_func_def_t lv_display_func[] = {
{ "get_screen_active", { (const void*) &lv_display_get_screen_active, "lv.obj", "(lv.display)" } },
{ "get_screen_prev", { (const void*) &lv_display_get_screen_prev, "lv.obj", "(lv.display)" } },
{ "get_theme", { (const void*) &lv_display_get_theme, "lv.theme", "(lv.display)" } },
{ "get_tile_cnt", { (const void*) &lv_display_get_tile_cnt, "i", "(lv.display)" } },
{ "get_user_data", { (const void*) &lv_display_get_user_data, "c", "(lv.display)" } },
{ "get_ver_res", { (const void*) &lv_display_get_vertical_resolution, "i", "(lv.display)" } },
{ "get_vertical_resolution", { (const void*) &lv_display_get_vertical_resolution, "i", "(lv.display)" } },
{ "is_double_buffered", { (const void*) &lv_display_is_double_buffered, "b", "(lv.display)" } },
{ "is_invalidation_enabled", { (const void*) &lv_display_is_invalidation_enabled, "b", "(lv.display)" } },
{ "register_vsync_event", { (const void*) &lv_display_register_vsync_event, "b", "(lv.display)^lv_event_cb^." } },
{ "remove", { (const void*) &lv_display_delete, "", "(lv.display)" } },
{ "remove_event_cb_with_user_data", { (const void*) &lv_display_remove_event_cb_with_user_data, "i", "(lv.display).." } },
{ "rotate_area", { (const void*) &lv_display_rotate_area, "", "(lv.display)(lv.area)" } },
{ "send_event", { (const void*) &lv_display_send_event, "i", "(lv.display)i." } },
{ "send_vsync_event", { (const void*) &lv_display_send_vsync_event, "i", "(lv.display)." } },
{ "set_angle", { (const void*) &lv_display_set_rotation, "", "(lv.display)i" } },
{ "set_antialiasing", { (const void*) &lv_display_set_antialiasing, "", "(lv.display)b" } },
{ "set_buffers", { (const void*) &lv_display_set_buffers, "", "(lv.display)..ii" } },
{ "set_buffers_with_stride", { (const void*) &lv_display_set_buffers_with_stride, "", "(lv.display)..iii" } },
{ "set_color_format", { (const void*) &lv_display_set_color_format, "", "(lv.display)i" } },
{ "set_default", { (const void*) &lv_display_set_default, "", "(lv.display)" } },
{ "set_dpi", { (const void*) &lv_display_set_dpi, "", "(lv.display)i" } },
{ "set_driver_data", { (const void*) &lv_display_set_driver_data, "", "(lv.display)." } },
{ "set_matrix_rotation", { (const void*) &lv_display_set_matrix_rotation, "", "(lv.display)b" } },
{ "set_offset", { (const void*) &lv_display_set_offset, "", "(lv.display)ii" } },
{ "set_physical_resolution", { (const void*) &lv_display_set_physical_resolution, "", "(lv.display)ii" } },
{ "set_render_mode", { (const void*) &lv_display_set_render_mode, "", "(lv.display)i" } },
{ "set_resolution", { (const void*) &lv_display_set_resolution, "", "(lv.display)ii" } },
{ "set_rotation", { (const void*) &lv_display_set_rotation, "", "(lv.display)i" } },
{ "set_theme", { (const void*) &lv_display_set_theme, "", "(lv.display)(lv.theme)" } },
{ "set_tile_cnt", { (const void*) &lv_display_set_tile_cnt, "", "(lv.display)i" } },
{ "set_user_data", { (const void*) &lv_display_set_user_data, "", "(lv.display)." } },
{ "trig_activity", { (const void*) &lv_display_trigger_activity, "", "(lv.display)" } },
{ "trigger_activity", { (const void*) &lv_display_trigger_activity, "", "(lv.display)" } },
{ "unregister_vsync_event", { (const void*) &lv_display_unregister_vsync_event, "b", "(lv.display)^lv_event_cb^." } },
};
/* `lv_indev` methods */
@ -710,6 +756,7 @@ const be_ntv_func_def_t lv_indev_func[] = {
{ "del", { (const void*) &lv_indev_delete, "", "(lv.indev)" } },
{ "delete", { (const void*) &lv_indev_delete, "", "(lv.indev)" } },
{ "enable", { (const void*) &lv_indev_enable, "", "(lv.indev)b" } },
{ "get_cursor", { (const void*) &lv_indev_get_cursor, "lv.obj", "(lv.indev)" } },
{ "get_disp", { (const void*) &lv_indev_get_display, "lv.display", "(lv.indev)" } },
{ "get_display", { (const void*) &lv_indev_get_display, "lv.display", "(lv.indev)" } },
{ "get_driver_data", { (const void*) &lv_indev_get_driver_data, "c", "(lv.indev)" } },
@ -725,6 +772,7 @@ const be_ntv_func_def_t lv_indev_func[] = {
{ "get_read_timer", { (const void*) &lv_indev_get_read_timer, "lv.timer", "(lv.indev)" } },
{ "get_scroll_dir", { (const void*) &lv_indev_get_scroll_dir, "i", "(lv.indev)" } },
{ "get_scroll_obj", { (const void*) &lv_indev_get_scroll_obj, "lv.obj", "(lv.indev)" } },
{ "get_short_click_streak", { (const void*) &lv_indev_get_short_click_streak, "i", "(lv.indev)" } },
{ "get_state", { (const void*) &lv_indev_get_state, "i", "(lv.indev)" } },
{ "get_type", { (const void*) &lv_indev_get_type, "i", "(lv.indev)" } },
{ "get_user_data", { (const void*) &lv_indev_get_user_data, "c", "(lv.indev)" } },
@ -743,6 +791,7 @@ const be_ntv_func_def_t lv_indev_func[] = {
{ "set_display", { (const void*) &lv_indev_set_display, "", "(lv.indev)(lv.display)" } },
{ "set_driver_data", { (const void*) &lv_indev_set_driver_data, "", "(lv.indev)." } },
{ "set_group", { (const void*) &lv_indev_set_group, "", "(lv.indev)(lv.group)" } },
{ "set_long_press_repeat_time", { (const void*) &lv_indev_set_long_press_repeat_time, "", "(lv.indev)i" } },
{ "set_long_press_time", { (const void*) &lv_indev_set_long_press_time, "", "(lv.indev)i" } },
{ "set_mode", { (const void*) &lv_indev_set_mode, "", "(lv.indev)i" } },
{ "set_scroll_limit", { (const void*) &lv_indev_set_scroll_limit, "", "(lv.indev)i" } },
@ -773,6 +822,10 @@ const be_ntv_func_def_t lv_anim_func[] = {
{ "get_time", { (const void*) &lv_anim_get_time, "i", "(lv.anim)" } },
{ "get_user_data", { (const void*) &lv_anim_get_user_data, "c", "(lv.anim)" } },
{ "init", { (const void*) &lv_anim_init, "", "(lv.anim)" } },
{ "is_paused", { (const void*) &lv_anim_is_paused, "b", "(lv.anim)" } },
{ "pause", { (const void*) &lv_anim_pause, "", "(lv.anim)" } },
{ "pause_for", { (const void*) &lv_anim_pause_for, "", "(lv.anim)i" } },
{ "resume", { (const void*) &lv_anim_resume, "", "(lv.anim)" } },
{ "set_bezier3_param", { (const void*) &lv_anim_set_bezier3_param, "", "(lv.anim)iiii" } },
{ "set_completed_cb", { (const void*) &lv_anim_set_completed_cb, "", "(lv.anim)c" } },
{ "set_custom_exec_cb", { (const void*) &lv_anim_set_custom_exec_cb, "", "(lv.anim)c" } },
@ -782,14 +835,13 @@ const be_ntv_func_def_t lv_anim_func[] = {
{ "set_exec_cb", { (const void*) &lv_anim_set_exec_cb, "", "(lv.anim)c" } },
{ "set_get_value_cb", { (const void*) &lv_anim_set_get_value_cb, "", "(lv.anim)c" } },
{ "set_path_cb", { (const void*) &lv_anim_set_path_cb, "", "(lv.anim)c" } },
{ "set_playback_delay", { (const void*) &lv_anim_set_playback_delay, "", "(lv.anim)i" } },
{ "set_playback_duration", { (const void*) &lv_anim_set_playback_duration, "", "(lv.anim)i" } },
{ "set_playback_time", { (const void*) &lv_anim_set_playback_time, "", "(lv.anim)i" } },
{ "set_ready_cb", { (const void*) &lv_anim_set_completed_cb, "", "(lv.anim)c" } },
{ "set_repeat_count", { (const void*) &lv_anim_set_repeat_count, "", "(lv.anim)i" } },
{ "set_repeat_delay", { (const void*) &lv_anim_set_repeat_delay, "", "(lv.anim)i" } },
{ "set_reverse_delay", { (const void*) &lv_anim_set_reverse_delay, "", "(lv.anim)i" } },
{ "set_reverse_duration", { (const void*) &lv_anim_set_reverse_duration, "", "(lv.anim)i" } },
{ "set_reverse_time", { (const void*) &lv_anim_set_reverse_time, "", "(lv.anim)i" } },
{ "set_start_cb", { (const void*) &lv_anim_set_start_cb, "", "(lv.anim)c" } },
{ "set_time", { (const void*) &lv_anim_set_time, "", "(lv.anim)i" } },
{ "set_user_data", { (const void*) &lv_anim_set_user_data, "", "(lv.anim)." } },
{ "set_values", { (const void*) &lv_anim_set_values, "", "(lv.anim)ii" } },
{ "set_var", { (const void*) &lv_anim_set_var, "", "(lv.anim)." } },
@ -818,13 +870,22 @@ const be_ntv_func_def_t lv_timer_func[] = {
/* `lv_animimg` methods */
#ifdef BE_LV_WIDGET_ANIMIMG
const be_ntv_func_def_t lv_animimg_func[] = {
{ "del", { (const void*) &lv_animimg_delete, "b", "(lv.obj)" } },
{ "delete", { (const void*) &lv_animimg_delete, "b", "(lv.obj)" } },
{ "get_anim", { (const void*) &lv_animimg_get_anim, "lv.anim", "(lv.obj)" } },
{ "get_duration", { (const void*) &lv_animimg_get_duration, "i", "(lv.obj)" } },
{ "get_repeat_count", { (const void*) &lv_animimg_get_repeat_count, "i", "(lv.obj)" } },
{ "get_src_count", { (const void*) &lv_animimg_get_src_count, "i", "(lv.obj)" } },
{ "remove", { (const void*) &lv_animimg_delete, "b", "(lv.obj)" } },
{ "set_completed_cb", { (const void*) &lv_animimg_set_completed_cb, "", "(lv.obj)c" } },
{ "set_duration", { (const void*) &lv_animimg_set_duration, "", "(lv.obj)i" } },
{ "set_ready_cb", { (const void*) &lv_animimg_set_completed_cb, "", "(lv.obj)c" } },
{ "set_repeat_count", { (const void*) &lv_animimg_set_repeat_count, "", "(lv.obj)i" } },
{ "set_reverse_delay", { (const void*) &lv_animimg_set_reverse_delay, "", "(lv.obj)i" } },
{ "set_reverse_duration", { (const void*) &lv_animimg_set_reverse_duration, "", "(lv.obj)i" } },
{ "set_src", { (const void*) &lv_animimg_set_src, "", "(lv.obj)ci" } },
{ "set_src_reverse", { (const void*) &lv_animimg_set_src_reverse, "", "(lv.obj)ci" } },
{ "set_start_cb", { (const void*) &lv_animimg_set_start_cb, "", "(lv.obj)c" } },
{ "start", { (const void*) &lv_animimg_start, "", "(lv.obj)" } },
};
#endif // BE_LV_WIDGET_ANIMIMG
@ -909,12 +970,14 @@ const be_ntv_func_def_t lv_buttonmatrix_func[] = {
/* `lv_calendar` methods */
#ifdef BE_LV_WIDGET_CALENDAR
const be_ntv_func_def_t lv_calendar_func[] = {
{ "add_header_arrow", { (const void*) &lv_calendar_add_header_arrow, "lv.obj", "(lv.obj)" } },
{ "add_header_dropdown", { (const void*) &lv_calendar_add_header_dropdown, "lv.obj", "(lv.obj)" } },
{ "get_btnmatrix", { (const void*) &lv_calendar_get_btnmatrix, "lv.obj", "(lv.obj)" } },
{ "get_highlighted_dates_num", { (const void*) &lv_calendar_get_highlighted_dates_num, "i", "(lv.obj)" } },
{ "header_dropdown_set_year_list", { (const void*) &lv_calendar_header_dropdown_set_year_list, "", "(lv.obj)s" } },
{ "set_chinese_mode", { (const void*) &lv_calendar_set_chinese_mode, "", "(lv.obj)b" } },
{ "set_day_names", { (const void*) &lv_calendar_set_day_names, "", "(lv.obj)c" } },
{ "set_showed_date", { (const void*) &lv_calendar_set_showed_date, "", "(lv.obj)ii" } },
{ "set_month_shown", { (const void*) &lv_calendar_set_month_shown, "", "(lv.obj)ii" } },
{ "set_today_date", { (const void*) &lv_calendar_set_today_date, "", "(lv.obj)iii" } },
};
#endif // BE_LV_WIDGET_CALENDAR
@ -946,28 +1009,32 @@ const be_ntv_func_def_t lv_chart_func[] = {
{ "get_pressed_point", { (const void*) &lv_chart_get_pressed_point, "i", "(lv.obj)" } },
{ "get_series_color", { (const void*) &lv_chart_get_series_color, "lv.color", "(lv.obj)(lv.chart_series)" } },
{ "get_series_next", { (const void*) &lv_chart_get_series_next, "lv.chart_series", "(lv.obj)(lv.chart_series)" } },
{ "get_series_x_array", { (const void*) &lv_chart_get_series_x_array, "lv.int_arr", "(lv.obj)(lv.chart_series)" } },
{ "get_series_y_array", { (const void*) &lv_chart_get_series_y_array, "lv.int_arr", "(lv.obj)(lv.chart_series)" } },
{ "get_type", { (const void*) &lv_chart_get_type, "i", "(lv.obj)" } },
{ "get_x_array", { (const void*) &lv_chart_get_x_array, "lv.int_arr", "(lv.obj)(lv.chart_series)" } },
{ "get_x_start_point", { (const void*) &lv_chart_get_x_start_point, "i", "(lv.obj)(lv.chart_series)" } },
{ "get_y_array", { (const void*) &lv_chart_get_y_array, "lv.int_arr", "(lv.obj)(lv.chart_series)" } },
{ "hide_series", { (const void*) &lv_chart_hide_series, "", "(lv.obj)(lv.chart_series)b" } },
{ "refresh", { (const void*) &lv_chart_refresh, "", "(lv.obj)" } },
{ "remove_series", { (const void*) &lv_chart_remove_series, "", "(lv.obj)(lv.chart_series)" } },
{ "set_all_value", { (const void*) &lv_chart_set_all_value, "", "(lv.obj)(lv.chart_series)i" } },
{ "set_all_values", { (const void*) &lv_chart_set_all_values, "", "(lv.obj)(lv.chart_series)i" } },
{ "set_axis_range", { (const void*) &lv_chart_set_axis_range, "", "(lv.obj)iii" } },
{ "set_cursor_point", { (const void*) &lv_chart_set_cursor_point, "", "(lv.obj)(lv.chart_cursor)(lv.chart_series)i" } },
{ "set_cursor_pos", { (const void*) &lv_chart_set_cursor_pos, "", "(lv.obj)(lv.chart_cursor)c" } },
{ "set_cursor_pos_x", { (const void*) &lv_chart_set_cursor_pos_x, "", "(lv.obj)(lv.chart_cursor)i" } },
{ "set_cursor_pos_y", { (const void*) &lv_chart_set_cursor_pos_y, "", "(lv.obj)(lv.chart_cursor)i" } },
{ "set_div_line_count", { (const void*) &lv_chart_set_div_line_count, "", "(lv.obj)ii" } },
{ "set_ext_x_array", { (const void*) &lv_chart_set_ext_x_array, "", "(lv.obj)(lv.chart_series)(lv.int_arr)" } },
{ "set_ext_y_array", { (const void*) &lv_chart_set_ext_y_array, "", "(lv.obj)(lv.chart_series)(lv.int_arr)" } },
{ "set_next_value", { (const void*) &lv_chart_set_next_value, "", "(lv.obj)(lv.chart_series)i" } },
{ "set_next_value2", { (const void*) &lv_chart_set_next_value2, "", "(lv.obj)(lv.chart_series)ii" } },
{ "set_point_count", { (const void*) &lv_chart_set_point_count, "", "(lv.obj)i" } },
{ "set_range", { (const void*) &lv_chart_set_range, "", "(lv.obj)iii" } },
{ "set_series_color", { (const void*) &lv_chart_set_series_color, "", "(lv.obj)(lv.chart_series)(lv.color)" } },
{ "set_series_ext_x_array", { (const void*) &lv_chart_set_series_ext_x_array, "", "(lv.obj)(lv.chart_series)(lv.int_arr)" } },
{ "set_series_ext_y_array", { (const void*) &lv_chart_set_series_ext_y_array, "", "(lv.obj)(lv.chart_series)(lv.int_arr)" } },
{ "set_series_value_by_id", { (const void*) &lv_chart_set_series_value_by_id, "", "(lv.obj)(lv.chart_series)ii" } },
{ "set_series_value_by_id2", { (const void*) &lv_chart_set_series_value_by_id2, "", "(lv.obj)(lv.chart_series)iii" } },
{ "set_series_values", { (const void*) &lv_chart_set_series_values, "", "(lv.obj)(lv.chart_series)(lv.int_arr)i" } },
{ "set_series_values2", { (const void*) &lv_chart_set_series_values2, "", "(lv.obj)(lv.chart_series)(lv.int_arr)(lv.int_arr)i" } },
{ "set_type", { (const void*) &lv_chart_set_type, "", "(lv.obj)i" } },
{ "set_update_mode", { (const void*) &lv_chart_set_update_mode, "", "(lv.obj)i" } },
{ "set_value_by_id", { (const void*) &lv_chart_set_value_by_id, "", "(lv.obj)(lv.chart_series)ii" } },
{ "set_value_by_id2", { (const void*) &lv_chart_set_value_by_id2, "", "(lv.obj)(lv.chart_series)iii" } },
{ "set_x_start_point", { (const void*) &lv_chart_set_x_start_point, "", "(lv.obj)(lv.chart_series)i" } },
};
#endif // BE_LV_WIDGET_CHART
@ -1026,6 +1093,10 @@ const be_ntv_func_def_t lv_image_func[] = {
{ "get_scale_x", { (const void*) &lv_image_get_scale_x, "i", "(lv.obj)" } },
{ "get_scale_y", { (const void*) &lv_image_get_scale_y, "i", "(lv.obj)" } },
{ "get_src", { (const void*) &lv_image_get_src, "c", "(lv.obj)" } },
{ "get_src_height", { (const void*) &lv_image_get_src_height, "i", "(lv.obj)" } },
{ "get_src_width", { (const void*) &lv_image_get_src_width, "i", "(lv.obj)" } },
{ "get_transformed_height", { (const void*) &lv_image_get_transformed_height, "i", "(lv.obj)" } },
{ "get_transformed_width", { (const void*) &lv_image_get_transformed_width, "i", "(lv.obj)" } },
{ "get_zoom", { (const void*) &lv_image_get_scale, "i", "(lv.obj)" } },
{ "set_angle", { (const void*) &lv_image_set_rotation, "", "(lv.obj)i" } },
{ "set_antialias", { (const void*) &lv_image_set_antialias, "", "(lv.obj)b" } },
@ -1076,12 +1147,14 @@ const be_ntv_func_def_t lv_label_func[] = {
{ "get_letter_on", { (const void*) &lv_label_get_letter_on, "i", "(lv.obj)cb" } },
{ "get_letter_pos", { (const void*) &lv_label_get_letter_pos, "", "(lv.obj)ic" } },
{ "get_long_mode", { (const void*) &lv_label_get_long_mode, "i", "(lv.obj)" } },
{ "get_recolor", { (const void*) &lv_label_get_recolor, "b", "(lv.obj)" } },
{ "get_text", { (const void*) &lv_label_get_text, "s", "(lv.obj)" } },
{ "get_text_selection_end", { (const void*) &lv_label_get_text_selection_end, "i", "(lv.obj)" } },
{ "get_text_selection_start", { (const void*) &lv_label_get_text_selection_start, "i", "(lv.obj)" } },
{ "ins_text", { (const void*) &lv_label_ins_text, "", "(lv.obj)is" } },
{ "is_char_under_pos", { (const void*) &lv_label_is_char_under_pos, "b", "(lv.obj)c" } },
{ "set_long_mode", { (const void*) &lv_label_set_long_mode, "", "(lv.obj)i" } },
{ "set_recolor", { (const void*) &lv_label_set_recolor, "", "(lv.obj)b" } },
{ "set_text", { (const void*) &lv_label_set_text, "", "(lv.obj)s" } },
{ "set_text_fmt", { (const void*) &lv_label_set_text_fmt, "", "(lv.obj)s[......]" } },
{ "set_text_selection_end", { (const void*) &lv_label_set_text_selection_end, "", "(lv.obj)i" } },
@ -1201,6 +1274,7 @@ const be_ntv_func_def_t lv_roller_func[] = {
{ "get_selected_str", { (const void*) &lv_roller_get_selected_str, "", "(lv.obj)ci" } },
{ "set_options", { (const void*) &lv_roller_set_options, "", "(lv.obj)si" } },
{ "set_selected", { (const void*) &lv_roller_set_selected, "", "(lv.obj)ii" } },
{ "set_selected_str", { (const void*) &lv_roller_set_selected_str, "b", "(lv.obj)si" } },
{ "set_visible_row_cnt", { (const void*) &lv_roller_set_visible_row_count, "", "(lv.obj)i" } },
{ "set_visible_row_count", { (const void*) &lv_roller_set_visible_row_count, "", "(lv.obj)i" } },
};
@ -1210,12 +1284,14 @@ const be_ntv_func_def_t lv_roller_func[] = {
#ifdef BE_LV_WIDGET_SCALE
const be_ntv_func_def_t lv_scale_func[] = {
{ "add_section", { (const void*) &lv_scale_add_section, "lv.scale_section", "(lv.obj)" } },
{ "get_angle", { (const void*) &lv_scale_get_rotation, "i", "(lv.obj)" } },
{ "get_angle_range", { (const void*) &lv_scale_get_angle_range, "i", "(lv.obj)" } },
{ "get_label_show", { (const void*) &lv_scale_get_label_show, "b", "(lv.obj)" } },
{ "get_major_tick_every", { (const void*) &lv_scale_get_major_tick_every, "i", "(lv.obj)" } },
{ "get_mode", { (const void*) &lv_scale_get_mode, "i", "(lv.obj)" } },
{ "get_range_max_value", { (const void*) &lv_scale_get_range_max_value, "i", "(lv.obj)" } },
{ "get_range_min_value", { (const void*) &lv_scale_get_range_min_value, "i", "(lv.obj)" } },
{ "get_rotation", { (const void*) &lv_scale_get_rotation, "i", "(lv.obj)" } },
{ "get_total_tick_count", { (const void*) &lv_scale_get_total_tick_count, "i", "(lv.obj)" } },
{ "set_angle", { (const void*) &lv_scale_set_rotation, "", "(lv.obj)i" } },
{ "set_angle_range", { (const void*) &lv_scale_set_angle_range, "", "(lv.obj)i" } },
@ -1228,6 +1304,10 @@ const be_ntv_func_def_t lv_scale_func[] = {
{ "set_post_draw", { (const void*) &lv_scale_set_post_draw, "", "(lv.obj)b" } },
{ "set_range", { (const void*) &lv_scale_set_range, "", "(lv.obj)ii" } },
{ "set_rotation", { (const void*) &lv_scale_set_rotation, "", "(lv.obj)i" } },
{ "set_section_range", { (const void*) &lv_scale_set_section_range, "", "(lv.obj)(lv.scale_section)ii" } },
{ "set_section_style_indicator", { (const void*) &lv_scale_set_section_style_indicator, "", "(lv.obj)(lv.scale_section)(lv.style)" } },
{ "set_section_style_items", { (const void*) &lv_scale_set_section_style_items, "", "(lv.obj)(lv.scale_section)(lv.style)" } },
{ "set_section_style_main", { (const void*) &lv_scale_set_section_style_main, "", "(lv.obj)(lv.scale_section)(lv.style)" } },
{ "set_text_src", { (const void*) &lv_scale_set_text_src, "", "(lv.obj)(lv.str_arr)" } },
{ "set_total_tick_count", { (const void*) &lv_scale_set_total_tick_count, "", "(lv.obj)i" } },
};
@ -1248,12 +1328,14 @@ const be_ntv_func_def_t lv_slider_func[] = {
{ "get_max_value", { (const void*) &lv_slider_get_max_value, "i", "(lv.obj)" } },
{ "get_min_value", { (const void*) &lv_slider_get_min_value, "i", "(lv.obj)" } },
{ "get_mode", { (const void*) &lv_slider_get_mode, "i", "(lv.obj)" } },
{ "get_orientation", { (const void*) &lv_slider_get_orientation, "i", "(lv.obj)" } },
{ "get_value", { (const void*) &lv_slider_get_value, "i", "(lv.obj)" } },
{ "is_dragged", { (const void*) &lv_slider_is_dragged, "b", "(lv.obj)" } },
{ "is_symmetrical", { (const void*) &lv_slider_is_symmetrical, "b", "(lv.obj)" } },
{ "set_left_value", { (const void*) &lv_slider_set_left_value, "", "(lv.obj)ii" } },
{ "set_mode", { (const void*) &lv_slider_set_mode, "", "(lv.obj)i" } },
{ "set_orientation", { (const void*) &lv_slider_set_orientation, "", "(lv.obj)i" } },
{ "set_range", { (const void*) &lv_slider_set_range, "", "(lv.obj)ii" } },
{ "set_start_value", { (const void*) &lv_slider_set_start_value, "", "(lv.obj)ii" } },
{ "set_value", { (const void*) &lv_slider_set_value, "", "(lv.obj)ii" } },
};
#endif // BE_LV_WIDGET_SLIDER
@ -1262,6 +1344,7 @@ const be_ntv_func_def_t lv_slider_func[] = {
#ifdef BE_LV_WIDGET_SPAN
const be_ntv_func_def_t lv_span_func[] = {
{ "get_style", { (const void*) &lv_span_get_style, "lv.style", "(lv.span)" } },
{ "get_text", { (const void*) &lv_span_get_text, "s", "(lv.span)" } },
{ "set_text", { (const void*) &lv_span_set_text, "", "(lv.span)s" } },
{ "set_text_static", { (const void*) &lv_span_set_text_static, "", "(lv.span)s" } },
};
@ -1270,6 +1353,7 @@ const be_ntv_func_def_t lv_span_func[] = {
/* `lv_spangroup` methods */
#ifdef BE_LV_WIDGET_SPANGROUP
const be_ntv_func_def_t lv_spangroup_func[] = {
{ "add_span", { (const void*) &lv_spangroup_add_span, "lv.span", "(lv.obj)" } },
{ "delete_span", { (const void*) &lv_spangroup_delete_span, "", "(lv.obj)(lv.span)" } },
{ "get_align", { (const void*) &lv_spangroup_get_align, "i", "(lv.obj)" } },
{ "get_child", { (const void*) &lv_spangroup_get_child, "lv.span", "(lv.obj)i" } },
@ -1280,14 +1364,18 @@ const be_ntv_func_def_t lv_spangroup_func[] = {
{ "get_max_lines", { (const void*) &lv_spangroup_get_max_lines, "i", "(lv.obj)" } },
{ "get_mode", { (const void*) &lv_spangroup_get_mode, "i", "(lv.obj)" } },
{ "get_overflow", { (const void*) &lv_spangroup_get_overflow, "i", "(lv.obj)" } },
{ "get_span_by_point", { (const void*) &lv_spangroup_get_span_by_point, "lv.span", "(lv.obj)c" } },
{ "get_span_coords", { (const void*) &lv_spangroup_get_span_coords, "lv.span_coords", "(lv.obj)(lv.span)" } },
{ "get_span_count", { (const void*) &lv_spangroup_get_span_count, "i", "(lv.obj)" } },
{ "new_span", { (const void*) &lv_spangroup_new_span, "lv.span", "(lv.obj)" } },
{ "refr_mode", { (const void*) &lv_spangroup_refr_mode, "", "(lv.obj)" } },
{ "refresh", { (const void*) &lv_spangroup_refresh, "", "(lv.obj)" } },
{ "set_align", { (const void*) &lv_spangroup_set_align, "", "(lv.obj)i" } },
{ "set_indent", { (const void*) &lv_spangroup_set_indent, "", "(lv.obj)i" } },
{ "set_max_lines", { (const void*) &lv_spangroup_set_max_lines, "", "(lv.obj)i" } },
{ "set_mode", { (const void*) &lv_spangroup_set_mode, "", "(lv.obj)i" } },
{ "set_overflow", { (const void*) &lv_spangroup_set_overflow, "", "(lv.obj)i" } },
{ "set_span_style", { (const void*) &lv_spangroup_set_span_style, "", "(lv.obj)(lv.span)(lv.style)" } },
{ "set_span_text", { (const void*) &lv_spangroup_set_span_text, "", "(lv.obj)(lv.span)s" } },
{ "set_span_text_static", { (const void*) &lv_spangroup_set_span_text_static, "", "(lv.obj)(lv.span)s" } },
};
#endif // BE_LV_WIDGET_SPANGROUP
@ -1321,13 +1409,14 @@ const be_ntv_func_def_t lv_spinner_func[] = {
/* `lv_switch` methods */
#ifdef BE_LV_WIDGET_SWITCH
const be_ntv_func_def_t lv_switch_func[] = {
{ "get_orientation", { (const void*) &lv_switch_get_orientation, "i", "(lv.obj)" } },
{ "set_orientation", { (const void*) &lv_switch_set_orientation, "", "(lv.obj)i" } },
};
#endif // BE_LV_WIDGET_SWITCH
/* `lv_table` methods */
#ifdef BE_LV_WIDGET_TABLE
const be_ntv_func_def_t lv_table_func[] = {
{ "add_cell_ctrl", { (const void*) &lv_table_add_cell_ctrl, "", "(lv.obj)iii" } },
{ "clear_cell_ctrl", { (const void*) &lv_table_clear_cell_ctrl, "", "(lv.obj)iii" } },
{ "get_cell_user_data", { (const void*) &lv_table_get_cell_user_data, "c", "(lv.obj)ii" } },
{ "get_cell_value", { (const void*) &lv_table_get_cell_value, "s", "(lv.obj)ii" } },
@ -1339,6 +1428,7 @@ const be_ntv_func_def_t lv_table_func[] = {
{ "get_row_count", { (const void*) &lv_table_get_row_count, "i", "(lv.obj)" } },
{ "get_selected_cell", { (const void*) &lv_table_get_selected_cell, "", "(lv.obj)(lv.int_arr)(lv.int_arr)" } },
{ "has_cell_ctrl", { (const void*) &lv_table_has_cell_ctrl, "b", "(lv.obj)iii" } },
{ "set_cell_ctrl", { (const void*) &lv_table_set_cell_ctrl, "", "(lv.obj)iii" } },
{ "set_cell_user_data", { (const void*) &lv_table_set_cell_user_data, "", "(lv.obj)ii." } },
{ "set_cell_value", { (const void*) &lv_table_set_cell_value, "", "(lv.obj)iis" } },
{ "set_cell_value_fmt", { (const void*) &lv_table_set_cell_value_fmt, "", "(lv.obj)iis[......]" } },
@ -1663,12 +1753,6 @@ const size_t lv_classes_size = sizeof(lv_classes) / sizeof(lv_classes[0]);
/* `lv_calendar` methods */
#ifdef BE_LV_WIDGET_CALENDAR
int be_ntv_lv_calendar_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_calendar_create, "+_p", "(lv.obj)"); }
#endif // BE_LV_WIDGET_CALENDAR
#ifdef BE_LV_WIDGET_CALENDAR
int be_ntv_lv_calendar_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_calendar_header_arrow_create, "+_p", "(lv.obj)"); }
#endif // BE_LV_WIDGET_CALENDAR
#ifdef BE_LV_WIDGET_CALENDAR
int be_ntv_lv_calendar_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_calendar_header_dropdown_create, "+_p", "(lv.obj)"); }
#endif // BE_LV_WIDGET_CALENDAR
/* `lv_canvas` methods */
#ifdef BE_LV_WIDGET_CANVAS

View File

@ -37,6 +37,7 @@ const be_ntv_func_def_t lv_func[] = {
{ "anim_get", { (const void*) &lv_anim_get, "lv.anim", ".c" } },
{ "anim_get_timer", { (const void*) &lv_anim_get_timer, "lv.timer", "" } },
{ "anim_refr_now", { (const void*) &lv_anim_refr_now, "", "" } },
{ "anim_resolve_speed", { (const void*) &lv_anim_resolve_speed, "i", "iii" } },
{ "anim_speed", { (const void*) &lv_anim_speed, "i", "i" } },
{ "anim_speed_clamped", { (const void*) &lv_anim_speed_clamped, "i", "iii" } },
{ "anim_speed_to_time", { (const void*) &lv_anim_speed_to_time, "i", "iii" } },
@ -72,7 +73,10 @@ const be_ntv_func_def_t lv_func[] = {
{ "color_make", { (const void*) &lv_color_make, "lv.color", "iii" } },
{ "color_mix", { (const void*) &lv_color_mix, "lv.color", "(lv.color)(lv.color)i" } },
{ "color_mix32", { (const void*) &lv_color_mix32, "i", "ii" } },
{ "color_mix32_premultiplied", { (const void*) &lv_color_mix32_premultiplied, "i", "ii" } },
{ "color_over32", { (const void*) &lv_color_over32, "i", "ii" } },
{ "color_rgb_to_hsv", { (const void*) &lv_color_rgb_to_hsv, "i", "iii" } },
{ "color_swap_16", { (const void*) &lv_color_swap_16, "i", "i" } },
{ "color_to_32", { (const void*) &lv_color_to_32, "i", "(lv.color)i" } },
{ "color_to_hsv", { (const void*) &lv_color_to_hsv, "i", "(lv.color)" } },
{ "color_to_int", { (const void*) &lv_color_to_int, "i", "(lv.color)" } },
@ -81,6 +85,7 @@ const be_ntv_func_def_t lv_func[] = {
{ "color_white", { (const void*) &lv_color_white, "lv.color", "" } },
{ "display_create", { (const void*) &lv_display_create, "lv.display", "ii" } },
{ "display_get_default", { (const void*) &lv_display_get_default, "lv.display", "" } },
{ "display_refr_timer", { (const void*) &lv_display_refr_timer, "", "(lv.timer)" } },
{ "dpx", { (const void*) &lv_dpx, "i", "i" } },
{ "draw_arc", { (const void*) &lv_draw_arc, "", "(lv.layer)(lv.draw_arc_dsc)" } },
{ "draw_arc_dsc_init", { (const void*) &lv_draw_arc_dsc_init, "", "(lv.draw_arc_dsc)" } },
@ -99,17 +104,24 @@ const be_ntv_func_def_t lv_func[] = {
{ "draw_layer_alloc_buf", { (const void*) &lv_draw_layer_alloc_buf, "c", "(lv.layer)" } },
{ "draw_layer_create", { (const void*) &lv_draw_layer_create, "lv.layer", "(lv.layer)i(lv.area)" } },
{ "draw_layer_go_to_xy", { (const void*) &lv_draw_layer_go_to_xy, "c", "(lv.layer)ii" } },
{ "draw_layer_init", { (const void*) &lv_draw_layer_init, "", "(lv.layer)(lv.layer)i(lv.area)" } },
{ "draw_letter", { (const void*) &lv_draw_letter, "", "(lv.layer)(lv.draw_letter_dsc)c" } },
{ "draw_letter_dsc_init", { (const void*) &lv_draw_letter_dsc_init, "", "(lv.draw_letter_dsc)" } },
{ "draw_line", { (const void*) &lv_draw_line, "", "(lv.layer)(lv.draw_line_dsc)" } },
{ "draw_line_dsc_init", { (const void*) &lv_draw_line_dsc_init, "", "(lv.draw_line_dsc)" } },
{ "draw_rect", { (const void*) &lv_draw_rect, "", "(lv.layer)(lv.draw_rect_dsc)(lv.area)" } },
{ "draw_rect_dsc_init", { (const void*) &lv_draw_rect_dsc_init, "", "(lv.draw_rect_dsc)" } },
{ "draw_wait_for_finish", { (const void*) &lv_draw_wait_for_finish, "", "" } },
{ "event_code_get_name", { (const void*) &lv_event_code_get_name, "s", "i" } },
{ "event_dsc_get_cb", { (const void*) &lv_event_dsc_get_cb, "lv.event_cb", "(lv.event_dsc)" } },
{ "event_dsc_get_user_data", { (const void*) &lv_event_dsc_get_user_data, "c", "(lv.event_dsc)" } },
{ "event_register_id", { (const void*) &lv_event_register_id, "i", "" } },
{ "flex_init", { (const void*) &lv_flex_init, "", "" } },
{ "font_get_default", { (const void*) &lv_font_get_default, "lv.font", "" } },
{ "font_get_glyph_width", { (const void*) &lv_font_get_glyph_width, "i", "(lv.font)ii" } },
{ "font_get_line_height", { (const void*) &lv_font_get_line_height, "i", "(lv.font)" } },
{ "font_has_static_bitmap", { (const void*) &lv_font_has_static_bitmap, "b", "(lv.font)" } },
{ "font_info_is_equal", { (const void*) &lv_font_info_is_equal, "b", "(lv.font_info)(lv.font_info)" } },
{ "font_set_kerning", { (const void*) &lv_font_set_kerning, "", "(lv.font)i" } },
{ "get_hor_res", { (const void*) &lv_get_hor_res, "i", "" } },
{ "get_ts_calibration", { (const void*) &lv_get_ts_calibration, "lv.ts_calibration", "" } },
@ -124,6 +136,8 @@ const be_ntv_func_def_t lv_func[] = {
{ "indev_get_active_obj", { (const void*) &lv_indev_get_active_obj, "lv.obj", "" } },
{ "indev_read_timer_cb", { (const void*) &lv_indev_read_timer_cb, "", "(lv.timer)" } },
{ "layer_bottom", { (const void*) &lv_layer_bottom, "lv.obj", "" } },
{ "layer_init", { (const void*) &lv_layer_init, "", "(lv.layer)" } },
{ "layer_reset", { (const void*) &lv_layer_reset, "", "(lv.layer)" } },
{ "layer_sys", { (const void*) &lv_layer_sys, "lv.obj", "" } },
{ "layer_top", { (const void*) &lv_layer_top, "lv.obj", "" } },
{ "obj_assign_id", { (const void*) &lv_obj_assign_id, "", "(lv.obj_class)(lv.obj)" } },
@ -167,6 +181,8 @@ const be_ntv_func_def_t lv_func[] = {
{ "task_handler", { (const void*) &lv_task_handler, "i", "" } },
{ "text_get_size", { (const void*) &lv_text_get_size, "", "cs(lv.font)iiii" } },
{ "text_get_width", { (const void*) &lv_text_get_width, "i", "si(lv.font)i" } },
{ "text_get_width_with_flags", { (const void*) &lv_text_get_width_with_flags, "i", "si(lv.font)ii" } },
{ "text_is_cmd", { (const void*) &lv_text_is_cmd, "b", "ci" } },
{ "theme_apply", { (const void*) &lv_theme_apply, "", "(lv.obj)" } },
{ "theme_get_color_primary", { (const void*) &lv_theme_get_color_primary, "lv.color", "(lv.obj)" } },
{ "theme_get_color_secondary", { (const void*) &lv_theme_get_color_secondary, "lv.color", "(lv.obj)" } },
@ -221,8 +237,6 @@ const be_const_member_t lv0_constants[] = {
{ "ALIGN_TOP_MID", be_cconst_int(LV_ALIGN_TOP_MID) },
{ "ALIGN_TOP_RIGHT", be_cconst_int(LV_ALIGN_TOP_RIGHT) },
{ "ANIM_IMAGE_PART_MAIN", be_cconst_int(LV_ANIM_IMAGE_PART_MAIN) },
{ "ANIM_OFF", be_cconst_int(LV_ANIM_OFF) },
{ "ANIM_ON", be_cconst_int(LV_ANIM_ON) },
{ "ANIM_PLAYTIME_INFINITE", be_cconst_int(LV_ANIM_PLAYTIME_INFINITE) },
{ "ANIM_REPEAT_INFINITE", be_cconst_int(LV_ANIM_REPEAT_INFINITE) },
{ "ARC_MODE_NORMAL", be_cconst_int(LV_ARC_MODE_NORMAL) },
@ -240,6 +254,7 @@ const be_const_member_t lv0_constants[] = {
{ "BASE_DIR_RTL", be_cconst_int(LV_BASE_DIR_RTL) },
{ "BASE_DIR_WEAK", be_cconst_int(LV_BASE_DIR_WEAK) },
{ "BLEND_MODE_ADDITIVE", be_cconst_int(LV_BLEND_MODE_ADDITIVE) },
{ "BLEND_MODE_DIFFERENCE", be_cconst_int(LV_BLEND_MODE_DIFFERENCE) },
{ "BLEND_MODE_MULTIPLY", be_cconst_int(LV_BLEND_MODE_MULTIPLY) },
{ "BLEND_MODE_NORMAL", be_cconst_int(LV_BLEND_MODE_NORMAL) },
{ "BLEND_MODE_SUBTRACTIVE", be_cconst_int(LV_BLEND_MODE_SUBTRACTIVE) },
@ -268,11 +283,27 @@ const be_const_member_t lv0_constants[] = {
{ "BUTTONMATRIX_CTRL_CUSTOM_2", be_cconst_int(LV_BUTTONMATRIX_CTRL_CUSTOM_2) },
{ "BUTTONMATRIX_CTRL_DISABLED", be_cconst_int(LV_BUTTONMATRIX_CTRL_DISABLED) },
{ "BUTTONMATRIX_CTRL_HIDDEN", be_cconst_int(LV_BUTTONMATRIX_CTRL_HIDDEN) },
{ "BUTTONMATRIX_CTRL_NONE", be_cconst_int(LV_BUTTONMATRIX_CTRL_NONE) },
{ "BUTTONMATRIX_CTRL_NO_REPEAT", be_cconst_int(LV_BUTTONMATRIX_CTRL_NO_REPEAT) },
{ "BUTTONMATRIX_CTRL_POPOVER", be_cconst_int(LV_BUTTONMATRIX_CTRL_POPOVER) },
{ "BUTTONMATRIX_CTRL_RECOLOR", be_cconst_int(LV_BUTTONMATRIX_CTRL_RECOLOR) },
{ "BUTTONMATRIX_CTRL_RESERVED_1", be_cconst_int(LV_BUTTONMATRIX_CTRL_RESERVED_1) },
{ "BUTTONMATRIX_CTRL_RESERVED_2", be_cconst_int(LV_BUTTONMATRIX_CTRL_RESERVED_2) },
{ "BUTTONMATRIX_CTRL_RESERVED_3", be_cconst_int(LV_BUTTONMATRIX_CTRL_RESERVED_3) },
{ "BUTTONMATRIX_CTRL_WIDTH_1", be_cconst_int(LV_BUTTONMATRIX_CTRL_WIDTH_1) },
{ "BUTTONMATRIX_CTRL_WIDTH_10", be_cconst_int(LV_BUTTONMATRIX_CTRL_WIDTH_10) },
{ "BUTTONMATRIX_CTRL_WIDTH_11", be_cconst_int(LV_BUTTONMATRIX_CTRL_WIDTH_11) },
{ "BUTTONMATRIX_CTRL_WIDTH_12", be_cconst_int(LV_BUTTONMATRIX_CTRL_WIDTH_12) },
{ "BUTTONMATRIX_CTRL_WIDTH_13", be_cconst_int(LV_BUTTONMATRIX_CTRL_WIDTH_13) },
{ "BUTTONMATRIX_CTRL_WIDTH_14", be_cconst_int(LV_BUTTONMATRIX_CTRL_WIDTH_14) },
{ "BUTTONMATRIX_CTRL_WIDTH_15", be_cconst_int(LV_BUTTONMATRIX_CTRL_WIDTH_15) },
{ "BUTTONMATRIX_CTRL_WIDTH_2", be_cconst_int(LV_BUTTONMATRIX_CTRL_WIDTH_2) },
{ "BUTTONMATRIX_CTRL_WIDTH_3", be_cconst_int(LV_BUTTONMATRIX_CTRL_WIDTH_3) },
{ "BUTTONMATRIX_CTRL_WIDTH_4", be_cconst_int(LV_BUTTONMATRIX_CTRL_WIDTH_4) },
{ "BUTTONMATRIX_CTRL_WIDTH_5", be_cconst_int(LV_BUTTONMATRIX_CTRL_WIDTH_5) },
{ "BUTTONMATRIX_CTRL_WIDTH_6", be_cconst_int(LV_BUTTONMATRIX_CTRL_WIDTH_6) },
{ "BUTTONMATRIX_CTRL_WIDTH_7", be_cconst_int(LV_BUTTONMATRIX_CTRL_WIDTH_7) },
{ "BUTTONMATRIX_CTRL_WIDTH_8", be_cconst_int(LV_BUTTONMATRIX_CTRL_WIDTH_8) },
{ "BUTTONMATRIX_CTRL_WIDTH_9", be_cconst_int(LV_BUTTONMATRIX_CTRL_WIDTH_9) },
{ "CHART_AXIS_LAST", be_cconst_int(LV_CHART_AXIS_LAST) },
{ "CHART_AXIS_PRIMARY_X", be_cconst_int(LV_CHART_AXIS_PRIMARY_X) },
{ "CHART_AXIS_PRIMARY_Y", be_cconst_int(LV_CHART_AXIS_PRIMARY_Y) },
@ -301,8 +332,12 @@ const be_const_member_t lv0_constants[] = {
{ "COLOR_FORMAT_A4", be_cconst_int(LV_COLOR_FORMAT_A4) },
{ "COLOR_FORMAT_A8", be_cconst_int(LV_COLOR_FORMAT_A8) },
{ "COLOR_FORMAT_AL88", be_cconst_int(LV_COLOR_FORMAT_AL88) },
{ "COLOR_FORMAT_ARGB1555", be_cconst_int(LV_COLOR_FORMAT_ARGB1555) },
{ "COLOR_FORMAT_ARGB2222", be_cconst_int(LV_COLOR_FORMAT_ARGB2222) },
{ "COLOR_FORMAT_ARGB4444", be_cconst_int(LV_COLOR_FORMAT_ARGB4444) },
{ "COLOR_FORMAT_ARGB8565", be_cconst_int(LV_COLOR_FORMAT_ARGB8565) },
{ "COLOR_FORMAT_ARGB8888", be_cconst_int(LV_COLOR_FORMAT_ARGB8888) },
{ "COLOR_FORMAT_ARGB8888_PREMULTIPLIED", be_cconst_int(LV_COLOR_FORMAT_ARGB8888_PREMULTIPLIED) },
{ "COLOR_FORMAT_I1", be_cconst_int(LV_COLOR_FORMAT_I1) },
{ "COLOR_FORMAT_I2", be_cconst_int(LV_COLOR_FORMAT_I2) },
{ "COLOR_FORMAT_I4", be_cconst_int(LV_COLOR_FORMAT_I4) },
@ -314,12 +349,22 @@ const be_const_member_t lv0_constants[] = {
{ "COLOR_FORMAT_L8", be_cconst_int(LV_COLOR_FORMAT_L8) },
{ "COLOR_FORMAT_NATIVE", be_cconst_int(LV_COLOR_FORMAT_NATIVE) },
{ "COLOR_FORMAT_NATIVE_WITH_ALPHA", be_cconst_int(LV_COLOR_FORMAT_NATIVE_WITH_ALPHA) },
{ "COLOR_FORMAT_NEMA_TSC12", be_cconst_int(LV_COLOR_FORMAT_NEMA_TSC12) },
{ "COLOR_FORMAT_NEMA_TSC12A", be_cconst_int(LV_COLOR_FORMAT_NEMA_TSC12A) },
{ "COLOR_FORMAT_NEMA_TSC4", be_cconst_int(LV_COLOR_FORMAT_NEMA_TSC4) },
{ "COLOR_FORMAT_NEMA_TSC6", be_cconst_int(LV_COLOR_FORMAT_NEMA_TSC6) },
{ "COLOR_FORMAT_NEMA_TSC6A", be_cconst_int(LV_COLOR_FORMAT_NEMA_TSC6A) },
{ "COLOR_FORMAT_NEMA_TSC6AP", be_cconst_int(LV_COLOR_FORMAT_NEMA_TSC6AP) },
{ "COLOR_FORMAT_NEMA_TSC_END", be_cconst_int(LV_COLOR_FORMAT_NEMA_TSC_END) },
{ "COLOR_FORMAT_NEMA_TSC_START", be_cconst_int(LV_COLOR_FORMAT_NEMA_TSC_START) },
{ "COLOR_FORMAT_NV12", be_cconst_int(LV_COLOR_FORMAT_NV12) },
{ "COLOR_FORMAT_NV21", be_cconst_int(LV_COLOR_FORMAT_NV21) },
{ "COLOR_FORMAT_PROPRIETARY_START", be_cconst_int(LV_COLOR_FORMAT_PROPRIETARY_START) },
{ "COLOR_FORMAT_RAW", be_cconst_int(LV_COLOR_FORMAT_RAW) },
{ "COLOR_FORMAT_RAW_ALPHA", be_cconst_int(LV_COLOR_FORMAT_RAW_ALPHA) },
{ "COLOR_FORMAT_RGB565", be_cconst_int(LV_COLOR_FORMAT_RGB565) },
{ "COLOR_FORMAT_RGB565A8", be_cconst_int(LV_COLOR_FORMAT_RGB565A8) },
{ "COLOR_FORMAT_RGB565_SWAPPED", be_cconst_int(LV_COLOR_FORMAT_RGB565_SWAPPED) },
{ "COLOR_FORMAT_RGB888", be_cconst_int(LV_COLOR_FORMAT_RGB888) },
{ "COLOR_FORMAT_UNKNOWN", be_cconst_int(LV_COLOR_FORMAT_UNKNOWN) },
{ "COLOR_FORMAT_UYVY", be_cconst_int(LV_COLOR_FORMAT_UYVY) },
@ -397,12 +442,12 @@ const be_const_member_t lv0_constants[] = {
{ "DRAW_TASK_TYPE_IMAGE", be_cconst_int(LV_DRAW_TASK_TYPE_IMAGE) },
{ "DRAW_TASK_TYPE_LABEL", be_cconst_int(LV_DRAW_TASK_TYPE_LABEL) },
{ "DRAW_TASK_TYPE_LAYER", be_cconst_int(LV_DRAW_TASK_TYPE_LAYER) },
{ "DRAW_TASK_TYPE_LETTER", be_cconst_int(LV_DRAW_TASK_TYPE_LETTER) },
{ "DRAW_TASK_TYPE_LINE", be_cconst_int(LV_DRAW_TASK_TYPE_LINE) },
{ "DRAW_TASK_TYPE_MASK_BITMAP", be_cconst_int(LV_DRAW_TASK_TYPE_MASK_BITMAP) },
{ "DRAW_TASK_TYPE_MASK_RECTANGLE", be_cconst_int(LV_DRAW_TASK_TYPE_MASK_RECTANGLE) },
{ "DRAW_TASK_TYPE_NONE", be_cconst_int(LV_DRAW_TASK_TYPE_NONE) },
{ "DRAW_TASK_TYPE_TRIANGLE", be_cconst_int(LV_DRAW_TASK_TYPE_TRIANGLE) },
{ "DRAW_TASK_TYPE_VECTOR", be_cconst_int(LV_DRAW_TASK_TYPE_VECTOR) },
{ "DROPDOWN_POS_LAST", be_cconst_int(LV_DROPDOWN_POS_LAST) },
{ "EVENT_ALL", be_cconst_int(LV_EVENT_ALL) },
{ "EVENT_CANCEL", be_cconst_int(LV_EVENT_CANCEL) },
@ -415,6 +460,7 @@ const be_const_member_t lv0_constants[] = {
{ "EVENT_CREATE", be_cconst_int(LV_EVENT_CREATE) },
{ "EVENT_DEFOCUSED", be_cconst_int(LV_EVENT_DEFOCUSED) },
{ "EVENT_DELETE", be_cconst_int(LV_EVENT_DELETE) },
{ "EVENT_DOUBLE_CLICKED", be_cconst_int(LV_EVENT_DOUBLE_CLICKED) },
{ "EVENT_DRAW_MAIN", be_cconst_int(LV_EVENT_DRAW_MAIN) },
{ "EVENT_DRAW_MAIN_BEGIN", be_cconst_int(LV_EVENT_DRAW_MAIN_BEGIN) },
{ "EVENT_DRAW_MAIN_END", be_cconst_int(LV_EVENT_DRAW_MAIN_END) },
@ -441,6 +487,7 @@ const be_const_member_t lv0_constants[] = {
{ "EVENT_LEAVE", be_cconst_int(LV_EVENT_LEAVE) },
{ "EVENT_LONG_PRESSED", be_cconst_int(LV_EVENT_LONG_PRESSED) },
{ "EVENT_LONG_PRESSED_REPEAT", be_cconst_int(LV_EVENT_LONG_PRESSED_REPEAT) },
{ "EVENT_MARKED_DELETING", be_cconst_int(LV_EVENT_MARKED_DELETING) },
{ "EVENT_PREPROCESS", be_cconst_int(LV_EVENT_PREPROCESS) },
{ "EVENT_PRESSED", be_cconst_int(LV_EVENT_PRESSED) },
{ "EVENT_PRESSING", be_cconst_int(LV_EVENT_PRESSING) },
@ -465,10 +512,13 @@ const be_const_member_t lv0_constants[] = {
{ "EVENT_SCROLL_END", be_cconst_int(LV_EVENT_SCROLL_END) },
{ "EVENT_SCROLL_THROW_BEGIN", be_cconst_int(LV_EVENT_SCROLL_THROW_BEGIN) },
{ "EVENT_SHORT_CLICKED", be_cconst_int(LV_EVENT_SHORT_CLICKED) },
{ "EVENT_SINGLE_CLICKED", be_cconst_int(LV_EVENT_SINGLE_CLICKED) },
{ "EVENT_SIZE_CHANGED", be_cconst_int(LV_EVENT_SIZE_CHANGED) },
{ "EVENT_STYLE_CHANGED", be_cconst_int(LV_EVENT_STYLE_CHANGED) },
{ "EVENT_TRIPLE_CLICKED", be_cconst_int(LV_EVENT_TRIPLE_CLICKED) },
{ "EVENT_VALUE_CHANGED", be_cconst_int(LV_EVENT_VALUE_CHANGED) },
{ "EVENT_VSYNC", be_cconst_int(LV_EVENT_VSYNC) },
{ "EVENT_VSYNC_REQUEST", be_cconst_int(LV_EVENT_VSYNC_REQUEST) },
{ "FLEX_ALIGN_CENTER", be_cconst_int(LV_FLEX_ALIGN_CENTER) },
{ "FLEX_ALIGN_END", be_cconst_int(LV_FLEX_ALIGN_END) },
{ "FLEX_ALIGN_SPACE_AROUND", be_cconst_int(LV_FLEX_ALIGN_SPACE_AROUND) },
@ -537,6 +587,8 @@ const be_const_member_t lv0_constants[] = {
{ "IMAGE_ALIGN_BOTTOM_MID", be_cconst_int(LV_IMAGE_ALIGN_BOTTOM_MID) },
{ "IMAGE_ALIGN_BOTTOM_RIGHT", be_cconst_int(LV_IMAGE_ALIGN_BOTTOM_RIGHT) },
{ "IMAGE_ALIGN_CENTER", be_cconst_int(LV_IMAGE_ALIGN_CENTER) },
{ "IMAGE_ALIGN_CONTAIN", be_cconst_int(LV_IMAGE_ALIGN_CONTAIN) },
{ "IMAGE_ALIGN_COVER", be_cconst_int(LV_IMAGE_ALIGN_COVER) },
{ "IMAGE_ALIGN_DEFAULT", be_cconst_int(LV_IMAGE_ALIGN_DEFAULT) },
{ "IMAGE_ALIGN_LEFT_MID", be_cconst_int(LV_IMAGE_ALIGN_LEFT_MID) },
{ "IMAGE_ALIGN_RIGHT_MID", be_cconst_int(LV_IMAGE_ALIGN_RIGHT_MID) },
@ -550,6 +602,7 @@ const be_const_member_t lv0_constants[] = {
{ "IMAGE_COMPRESS_RLE", be_cconst_int(LV_IMAGE_COMPRESS_RLE) },
{ "IMAGE_FLAGS_ALLOCATED", be_cconst_int(LV_IMAGE_FLAGS_ALLOCATED) },
{ "IMAGE_FLAGS_COMPRESSED", be_cconst_int(LV_IMAGE_FLAGS_COMPRESSED) },
{ "IMAGE_FLAGS_CUSTOM_DRAW", be_cconst_int(LV_IMAGE_FLAGS_CUSTOM_DRAW) },
{ "IMAGE_FLAGS_MODIFIABLE", be_cconst_int(LV_IMAGE_FLAGS_MODIFIABLE) },
{ "IMAGE_FLAGS_PREMULTIPLIED", be_cconst_int(LV_IMAGE_FLAGS_PREMULTIPLIED) },
{ "IMAGE_FLAGS_USER1", be_cconst_int(LV_IMAGE_FLAGS_USER1) },
@ -588,11 +641,16 @@ const be_const_member_t lv0_constants[] = {
{ "KEY_RIGHT", be_cconst_int(LV_KEY_RIGHT) },
{ "KEY_UP", be_cconst_int(LV_KEY_UP) },
{ "LABEL_DOT_NUM", be_cconst_int(LV_LABEL_DOT_NUM) },
{ "LABEL_LONG_CLIP", be_cconst_int(LV_LABEL_LONG_CLIP) },
{ "LABEL_LONG_DOT", be_cconst_int(LV_LABEL_LONG_DOT) },
{ "LABEL_LONG_SCROLL", be_cconst_int(LV_LABEL_LONG_SCROLL) },
{ "LABEL_LONG_SCROLL_CIRCULAR", be_cconst_int(LV_LABEL_LONG_SCROLL_CIRCULAR) },
{ "LABEL_LONG_WRAP", be_cconst_int(LV_LABEL_LONG_WRAP) },
{ "LABEL_LONG_CLIP", be_cconst_int(LV_LABEL_LONG_MODE_CLIP) },
{ "LABEL_LONG_DOT", be_cconst_int(LV_LABEL_LONG_MODE_DOTS) },
{ "LABEL_LONG_MODE_CLIP", be_cconst_int(LV_LABEL_LONG_MODE_CLIP) },
{ "LABEL_LONG_MODE_DOTS", be_cconst_int(LV_LABEL_LONG_MODE_DOTS) },
{ "LABEL_LONG_MODE_SCROLL", be_cconst_int(LV_LABEL_LONG_MODE_SCROLL) },
{ "LABEL_LONG_MODE_SCROLL_CIRCULAR", be_cconst_int(LV_LABEL_LONG_MODE_SCROLL_CIRCULAR) },
{ "LABEL_LONG_MODE_WRAP", be_cconst_int(LV_LABEL_LONG_MODE_WRAP) },
{ "LABEL_LONG_SCROLL", be_cconst_int(LV_LABEL_LONG_MODE_SCROLL) },
{ "LABEL_LONG_SCROLL_CIRCULAR", be_cconst_int(LV_LABEL_LONG_MODE_SCROLL_CIRCULAR) },
{ "LABEL_LONG_WRAP", be_cconst_int(LV_LABEL_LONG_MODE_WRAP) },
{ "LABEL_POS_LAST", be_cconst_int(LV_LABEL_POS_LAST) },
{ "LABEL_TEXT_SELECTION_OFF", be_cconst_int(LV_LABEL_TEXT_SELECTION_OFF) },
{ "LAYER_TYPE_NONE", be_cconst_int(LV_LAYER_TYPE_NONE) },
@ -713,6 +771,8 @@ const be_const_member_t lv0_constants[] = {
{ "ROLLER_MODE_INFINITE", be_cconst_int(LV_ROLLER_MODE_INFINITE) },
{ "ROLLER_MODE_NORMAL", be_cconst_int(LV_ROLLER_MODE_NORMAL) },
{ "SCALE_LABEL_ENABLED_DEFAULT", be_cconst_int(LV_SCALE_LABEL_ENABLED_DEFAULT) },
{ "SCALE_LABEL_ROTATE_KEEP_UPRIGHT", be_cconst_int(LV_SCALE_LABEL_ROTATE_KEEP_UPRIGHT) },
{ "SCALE_LABEL_ROTATE_MATCH_TICKS", be_cconst_int(LV_SCALE_LABEL_ROTATE_MATCH_TICKS) },
{ "SCALE_MAJOR_TICK_EVERY_DEFAULT", be_cconst_int(LV_SCALE_MAJOR_TICK_EVERY_DEFAULT) },
{ "SCALE_MODE_HORIZONTAL_BOTTOM", be_cconst_int(LV_SCALE_MODE_HORIZONTAL_BOTTOM) },
{ "SCALE_MODE_HORIZONTAL_TOP", be_cconst_int(LV_SCALE_MODE_HORIZONTAL_TOP) },
@ -722,6 +782,7 @@ const be_const_member_t lv0_constants[] = {
{ "SCALE_MODE_VERTICAL_LEFT", be_cconst_int(LV_SCALE_MODE_VERTICAL_LEFT) },
{ "SCALE_MODE_VERTICAL_RIGHT", be_cconst_int(LV_SCALE_MODE_VERTICAL_RIGHT) },
{ "SCALE_NONE", be_cconst_int(LV_SCALE_NONE) },
{ "SCALE_ROTATION_ANGLE_MASK", be_cconst_int(LV_SCALE_ROTATION_ANGLE_MASK) },
{ "SCALE_TOTAL_TICK_COUNT_DEFAULT", be_cconst_int(LV_SCALE_TOTAL_TICK_COUNT_DEFAULT) },
{ "SCROLLBAR_MODE_ACTIVE", be_cconst_int(LV_SCROLLBAR_MODE_ACTIVE) },
{ "SCROLLBAR_MODE_AUTO", be_cconst_int(LV_SCROLLBAR_MODE_AUTO) },
@ -751,6 +812,9 @@ const be_const_member_t lv0_constants[] = {
{ "SLIDER_MODE_NORMAL", be_cconst_int(LV_SLIDER_MODE_NORMAL) },
{ "SLIDER_MODE_RANGE", be_cconst_int(LV_SLIDER_MODE_RANGE) },
{ "SLIDER_MODE_SYMMETRICAL", be_cconst_int(LV_SLIDER_MODE_SYMMETRICAL) },
{ "SLIDER_ORIENTATION_AUTO", be_cconst_int(LV_SLIDER_ORIENTATION_AUTO) },
{ "SLIDER_ORIENTATION_HORIZONTAL", be_cconst_int(LV_SLIDER_ORIENTATION_HORIZONTAL) },
{ "SLIDER_ORIENTATION_VERTICAL", be_cconst_int(LV_SLIDER_ORIENTATION_VERTICAL) },
{ "SPAN_MODE_BREAK", be_cconst_int(LV_SPAN_MODE_BREAK) },
{ "SPAN_MODE_EXPAND", be_cconst_int(LV_SPAN_MODE_EXPAND) },
{ "SPAN_MODE_FIXED", be_cconst_int(LV_SPAN_MODE_FIXED) },
@ -856,13 +920,17 @@ const be_const_member_t lv0_constants[] = {
{ "STYLE_PAD_BOTTOM", be_cconst_int(LV_STYLE_PAD_BOTTOM) },
{ "STYLE_PAD_COLUMN", be_cconst_int(LV_STYLE_PAD_COLUMN) },
{ "STYLE_PAD_LEFT", be_cconst_int(LV_STYLE_PAD_LEFT) },
{ "STYLE_PAD_RADIAL", be_cconst_int(LV_STYLE_PAD_RADIAL) },
{ "STYLE_PAD_RIGHT", be_cconst_int(LV_STYLE_PAD_RIGHT) },
{ "STYLE_PAD_ROW", be_cconst_int(LV_STYLE_PAD_ROW) },
{ "STYLE_PAD_TOP", be_cconst_int(LV_STYLE_PAD_TOP) },
{ "STYLE_PROP_ANY", be_cconst_int(LV_STYLE_PROP_ANY) },
{ "STYLE_PROP_CONST", be_cconst_int(LV_STYLE_PROP_CONST) },
{ "STYLE_PROP_INV", be_cconst_int(LV_STYLE_PROP_INV) },
{ "STYLE_RADIAL_OFFSET", be_cconst_int(LV_STYLE_RADIAL_OFFSET) },
{ "STYLE_RADIUS", be_cconst_int(LV_STYLE_RADIUS) },
{ "STYLE_RECOLOR", be_cconst_int(LV_STYLE_RECOLOR) },
{ "STYLE_RECOLOR_OPA", be_cconst_int(LV_STYLE_RECOLOR_OPA) },
{ "STYLE_RES_FOUND", be_cconst_int(LV_STYLE_RES_FOUND) },
{ "STYLE_RES_NOT_FOUND", be_cconst_int(LV_STYLE_RES_NOT_FOUND) },
{ "STYLE_ROTARY_SENSITIVITY", be_cconst_int(LV_STYLE_ROTARY_SENSITIVITY) },
@ -885,6 +953,9 @@ const be_const_member_t lv0_constants[] = {
{ "STYLE_TEXT_LETTER_SPACE", be_cconst_int(LV_STYLE_TEXT_LETTER_SPACE) },
{ "STYLE_TEXT_LINE_SPACE", be_cconst_int(LV_STYLE_TEXT_LINE_SPACE) },
{ "STYLE_TEXT_OPA", be_cconst_int(LV_STYLE_TEXT_OPA) },
{ "STYLE_TEXT_OUTLINE_STROKE_COLOR", be_cconst_int(LV_STYLE_TEXT_OUTLINE_STROKE_COLOR) },
{ "STYLE_TEXT_OUTLINE_STROKE_OPA", be_cconst_int(LV_STYLE_TEXT_OUTLINE_STROKE_OPA) },
{ "STYLE_TEXT_OUTLINE_STROKE_WIDTH", be_cconst_int(LV_STYLE_TEXT_OUTLINE_STROKE_WIDTH) },
{ "STYLE_TRANSFORM_ANGLE", be_cconst_int(LV_STYLE_TRANSFORM_ROTATION) },
{ "STYLE_TRANSFORM_HEIGHT", be_cconst_int(LV_STYLE_TRANSFORM_HEIGHT) },
{ "STYLE_TRANSFORM_PIVOT_X", be_cconst_int(LV_STYLE_TRANSFORM_PIVOT_X) },
@ -896,11 +967,15 @@ const be_const_member_t lv0_constants[] = {
{ "STYLE_TRANSFORM_SKEW_Y", be_cconst_int(LV_STYLE_TRANSFORM_SKEW_Y) },
{ "STYLE_TRANSFORM_WIDTH", be_cconst_int(LV_STYLE_TRANSFORM_WIDTH) },
{ "STYLE_TRANSITION", be_cconst_int(LV_STYLE_TRANSITION) },
{ "STYLE_TRANSLATE_RADIAL", be_cconst_int(LV_STYLE_TRANSLATE_RADIAL) },
{ "STYLE_TRANSLATE_X", be_cconst_int(LV_STYLE_TRANSLATE_X) },
{ "STYLE_TRANSLATE_Y", be_cconst_int(LV_STYLE_TRANSLATE_Y) },
{ "STYLE_WIDTH", be_cconst_int(LV_STYLE_WIDTH) },
{ "STYLE_X", be_cconst_int(LV_STYLE_X) },
{ "STYLE_Y", be_cconst_int(LV_STYLE_Y) },
{ "SWITCH_ORIENTATION_AUTO", be_cconst_int(LV_SWITCH_ORIENTATION_AUTO) },
{ "SWITCH_ORIENTATION_HORIZONTAL", be_cconst_int(LV_SWITCH_ORIENTATION_HORIZONTAL) },
{ "SWITCH_ORIENTATION_VERTICAL", be_cconst_int(LV_SWITCH_ORIENTATION_VERTICAL) },
{ "$SYMBOL_AUDIO", be_cconst_string("\xef\x80\x81") },
{ "$SYMBOL_BACKSPACE", be_cconst_string("\xef\x95\x9A") },
{ "$SYMBOL_BATTERY_1", be_cconst_string("\xef\x89\x83") },
@ -965,6 +1040,7 @@ const be_const_member_t lv0_constants[] = {
{ "TABLE_CELL_CTRL_CUSTOM_3", be_cconst_int(LV_TABLE_CELL_CTRL_CUSTOM_3) },
{ "TABLE_CELL_CTRL_CUSTOM_4", be_cconst_int(LV_TABLE_CELL_CTRL_CUSTOM_4) },
{ "TABLE_CELL_CTRL_MERGE_RIGHT", be_cconst_int(LV_TABLE_CELL_CTRL_MERGE_RIGHT) },
{ "TABLE_CELL_CTRL_NONE", be_cconst_int(LV_TABLE_CELL_CTRL_NONE) },
{ "TABLE_CELL_CTRL_TEXT_CROP", be_cconst_int(LV_TABLE_CELL_CTRL_TEXT_CROP) },
{ "TABLE_CELL_NONE", be_cconst_int(LV_TABLE_CELL_NONE) },
{ "TEXTAREA_CURSOR_LAST", be_cconst_int(LV_TEXTAREA_CURSOR_LAST) },
@ -972,6 +1048,9 @@ const be_const_member_t lv0_constants[] = {
{ "TEXT_ALIGN_CENTER", be_cconst_int(LV_TEXT_ALIGN_CENTER) },
{ "TEXT_ALIGN_LEFT", be_cconst_int(LV_TEXT_ALIGN_LEFT) },
{ "TEXT_ALIGN_RIGHT", be_cconst_int(LV_TEXT_ALIGN_RIGHT) },
{ "TEXT_CMD_STATE_IN", be_cconst_int(LV_TEXT_CMD_STATE_IN) },
{ "TEXT_CMD_STATE_PAR", be_cconst_int(LV_TEXT_CMD_STATE_PAR) },
{ "TEXT_CMD_STATE_WAIT", be_cconst_int(LV_TEXT_CMD_STATE_WAIT) },
{ "TEXT_DECOR_NONE", be_cconst_int(LV_TEXT_DECOR_NONE) },
{ "TEXT_DECOR_STRIKETHROUGH", be_cconst_int(LV_TEXT_DECOR_STRIKETHROUGH) },
{ "TEXT_DECOR_UNDERLINE", be_cconst_int(LV_TEXT_DECOR_UNDERLINE) },
@ -979,6 +1058,9 @@ const be_const_member_t lv0_constants[] = {
{ "TEXT_FLAG_EXPAND", be_cconst_int(LV_TEXT_FLAG_EXPAND) },
{ "TEXT_FLAG_FIT", be_cconst_int(LV_TEXT_FLAG_FIT) },
{ "TEXT_FLAG_NONE", be_cconst_int(LV_TEXT_FLAG_NONE) },
{ "TEXT_FLAG_RECOLOR", be_cconst_int(LV_TEXT_FLAG_RECOLOR) },
{ "TREE_WALK_POST_ORDER", be_cconst_int(LV_TREE_WALK_POST_ORDER) },
{ "TREE_WALK_PRE_ORDER", be_cconst_int(LV_TREE_WALK_PRE_ORDER) },
{ "ZOOM_NONE", be_cconst_int(LV_SCALE_NONE) },
{ "&anim_path_bounce", be_cconst_ptr(&lv_anim_path_bounce) },
{ "&anim_path_ease_in", be_cconst_ptr(&lv_anim_path_ease_in) },

File diff suppressed because it is too large Load Diff

View File

@ -17,7 +17,6 @@ lv_coord_t lv_get_ver_res(void);
// Generated from headers
// ======================================================================
// ../../lvgl/src/../lvgl.h
static inline int lv_version_major(void)
static inline int lv_version_minor(void)
@ -60,7 +59,7 @@ lv_group_t * lv_group_by_index(uint32_t index)
lv_obj_t * lv_obj_create(lv_obj_t * parent)
void lv_obj_add_flag(lv_obj_t * obj, lv_obj_flag_t f)
void lv_obj_remove_flag(lv_obj_t * obj, lv_obj_flag_t f)
void lv_obj_update_flag(lv_obj_t * obj, lv_obj_flag_t f, bool v)
void lv_obj_set_flag(lv_obj_t * obj, lv_obj_flag_t f, bool v)
void lv_obj_add_state(lv_obj_t * obj, lv_state_t state)
void lv_obj_remove_state(lv_obj_t * obj, lv_state_t state)
void lv_obj_set_state(lv_obj_t * obj, lv_state_t state, bool v)
@ -79,7 +78,7 @@ bool lv_obj_is_valid(const lv_obj_t * obj)
void lv_obj_null_on_delete(lv_obj_t ** obj_ptr)
void lv_obj_set_id(lv_obj_t * obj, void * id)
void * lv_obj_get_id(const lv_obj_t * obj)
lv_obj_t * lv_obj_get_child_by_id(const lv_obj_t * obj, const void * id)
lv_obj_t * lv_obj_find_by_id(const lv_obj_t * obj, const void * id)
void lv_obj_assign_id(const lv_obj_class_t * class_p, lv_obj_t * obj)
void lv_obj_free_id(lv_obj_t * obj)
int lv_obj_id_compare(const void * id1, const void * id2)
@ -110,8 +109,8 @@ lv_event_dsc_t * lv_obj_add_event_cb(lv_obj_t * obj, lv_event_cb_t event_cb, lv_
uint32_t lv_obj_get_event_count(lv_obj_t * obj)
lv_event_dsc_t * lv_obj_get_event_dsc(lv_obj_t * obj, uint32_t index)
bool lv_obj_remove_event(lv_obj_t * obj, uint32_t index)
bool lv_obj_remove_event_cb(lv_obj_t * obj, lv_event_cb_t event_cb)
bool lv_obj_remove_event_dsc(lv_obj_t * obj, lv_event_dsc_t * dsc)
uint32_t lv_obj_remove_event_cb(lv_obj_t * obj, lv_event_cb_t event_cb)
uint32_t lv_obj_remove_event_cb_with_user_data(lv_obj_t * obj, lv_event_cb_t event_cb, void * user_data)
lv_indev_t * lv_event_get_indev(lv_event_t * e)
lv_layer_t * lv_event_get_layer(lv_event_t * e)
@ -144,6 +143,8 @@ void lv_obj_set_align(lv_obj_t * obj, lv_align_t align)
void lv_obj_align(lv_obj_t * obj, lv_align_t align, int32_t x_ofs, int32_t y_ofs)
void lv_obj_align_to(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, int32_t x_ofs, int32_t y_ofs)
void lv_obj_center(lv_obj_t * obj)
void lv_obj_set_transform(lv_obj_t * obj, const lv_matrix_t * matrix)
void lv_obj_reset_transform(lv_obj_t * obj)
void lv_obj_get_coords(const lv_obj_t * obj, lv_area_t * coords)
int32_t lv_obj_get_x(const lv_obj_t * obj)
int32_t lv_obj_get_x2(const lv_obj_t * obj)
@ -162,6 +163,7 @@ bool lv_obj_refresh_self_size(lv_obj_t * obj)
void lv_obj_refr_pos(lv_obj_t * obj)
void lv_obj_move_to(lv_obj_t * obj, int32_t x, int32_t y)
void lv_obj_move_children_by(lv_obj_t * obj, int32_t x_diff, int32_t y_diff, bool ignore_floating)
const lv_matrix_t * lv_obj_get_transform(const lv_obj_t * obj)
void lv_obj_transform_point(const lv_obj_t * obj, lv_point_t * p, lv_obj_point_transform_flag_t flags)
void lv_obj_transform_point_array(const lv_obj_t * obj, lv_point_t points[], size_t count, lv_obj_point_transform_flag_t flags)
void lv_obj_get_transformed_area(const lv_obj_t * obj, lv_area_t * area, lv_obj_point_transform_flag_t flags)
@ -186,12 +188,12 @@ lv_scroll_snap_t lv_obj_get_scroll_snap_x(const lv_obj_t * obj)
lv_scroll_snap_t lv_obj_get_scroll_snap_y(const lv_obj_t * obj)
int32_t lv_obj_get_scroll_x(const lv_obj_t * obj)
int32_t lv_obj_get_scroll_y(const lv_obj_t * obj)
int32_t lv_obj_get_scroll_top(lv_obj_t * obj)
int32_t lv_obj_get_scroll_bottom(lv_obj_t * obj)
int32_t lv_obj_get_scroll_left(lv_obj_t * obj)
int32_t lv_obj_get_scroll_right(lv_obj_t * obj)
int32_t lv_obj_get_scroll_top(const lv_obj_t * obj)
int32_t lv_obj_get_scroll_bottom(const lv_obj_t * obj)
int32_t lv_obj_get_scroll_left(const lv_obj_t * obj)
int32_t lv_obj_get_scroll_right(const lv_obj_t * obj)
void lv_obj_get_scroll_end(lv_obj_t * obj, lv_point_t * end)
void lv_obj_scroll_by(lv_obj_t * obj, int32_t x, int32_t y, lv_anim_enable_t anim_en)
void lv_obj_scroll_by(lv_obj_t * obj, int32_t dx, int32_t dy, lv_anim_enable_t anim_en)
void lv_obj_scroll_by_bounded(lv_obj_t * obj, int32_t dx, int32_t dy, lv_anim_enable_t anim_en)
void lv_obj_scroll_to(lv_obj_t * obj, int32_t x, int32_t y, lv_anim_enable_t anim_en)
void lv_obj_scroll_to_x(lv_obj_t * obj, int32_t x, lv_anim_enable_t anim_en)
@ -199,6 +201,7 @@ void lv_obj_scroll_to_y(lv_obj_t * obj, int32_t y, lv_anim_enable_t anim_en)
void lv_obj_scroll_to_view(lv_obj_t * obj, lv_anim_enable_t anim_en)
void lv_obj_scroll_to_view_recursive(lv_obj_t * obj, lv_anim_enable_t anim_en)
bool lv_obj_is_scrolling(const lv_obj_t * obj)
void lv_obj_stop_scroll_anim(const lv_obj_t * obj)
void lv_obj_update_snap(lv_obj_t * obj, lv_anim_enable_t anim_en)
void lv_obj_get_scrollbar_area(lv_obj_t * obj, lv_area_t * hor, lv_area_t * ver)
void lv_obj_scrollbar_invalidate(lv_obj_t * obj)
@ -239,6 +242,8 @@ lv_text_align_t lv_obj_calculate_style_text_align(const lv_obj_t * obj, lv_part_
static inline int32_t lv_obj_get_style_transform_scale_x_safe(const lv_obj_t * obj, lv_part_t part)
static inline int32_t lv_obj_get_style_transform_scale_y_safe(const lv_obj_t * obj, lv_part_t part)
lv_opa_t lv_obj_get_style_opa_recursive(const lv_obj_t * obj, lv_part_t part)
lv_color32_t lv_obj_style_apply_recolor(const lv_obj_t * obj, lv_part_t part, lv_color32_t color)
lv_color32_t lv_obj_get_style_recolor_recursive(const lv_obj_t * obj, lv_part_t part)
// ../../lvgl/src/core/lv_obj_style_gen.h
static inline int32_t lv_obj_get_style_width(const lv_obj_t * obj, lv_part_t part)
@ -255,6 +260,7 @@ static inline int32_t lv_obj_get_style_transform_width(const lv_obj_t * obj, lv_
static inline int32_t lv_obj_get_style_transform_height(const lv_obj_t * obj, lv_part_t part)
static inline int32_t lv_obj_get_style_translate_x(const lv_obj_t * obj, lv_part_t part)
static inline int32_t lv_obj_get_style_translate_y(const lv_obj_t * obj, lv_part_t part)
static inline int32_t lv_obj_get_style_translate_radial(const lv_obj_t * obj, lv_part_t part)
static inline int32_t lv_obj_get_style_transform_scale_x(const lv_obj_t * obj, lv_part_t part)
static inline int32_t lv_obj_get_style_transform_scale_y(const lv_obj_t * obj, lv_part_t part)
static inline int32_t lv_obj_get_style_transform_rotation(const lv_obj_t * obj, lv_part_t part)
@ -268,6 +274,7 @@ static inline int32_t lv_obj_get_style_pad_left(const lv_obj_t * obj, lv_part_t
static inline int32_t lv_obj_get_style_pad_right(const lv_obj_t * obj, lv_part_t part)
static inline int32_t lv_obj_get_style_pad_row(const lv_obj_t * obj, lv_part_t part)
static inline int32_t lv_obj_get_style_pad_column(const lv_obj_t * obj, lv_part_t part)
static inline int32_t lv_obj_get_style_pad_radial(const lv_obj_t * obj, lv_part_t part)
static inline int32_t lv_obj_get_style_margin_top(const lv_obj_t * obj, lv_part_t part)
static inline int32_t lv_obj_get_style_margin_bottom(const lv_obj_t * obj, lv_part_t part)
static inline int32_t lv_obj_get_style_margin_left(const lv_obj_t * obj, lv_part_t part)
@ -332,12 +339,19 @@ static inline int32_t lv_obj_get_style_text_letter_space(const lv_obj_t * obj, l
static inline int32_t lv_obj_get_style_text_line_space(const lv_obj_t * obj, lv_part_t part)
static inline lv_text_decor_t lv_obj_get_style_text_decor(const lv_obj_t * obj, lv_part_t part)
static inline lv_text_align_t lv_obj_get_style_text_align(const lv_obj_t * obj, lv_part_t part)
static inline lv_color_t lv_obj_get_style_text_outline_stroke_color(const lv_obj_t * obj, lv_part_t part)
static inline lv_color_t lv_obj_get_style_text_outline_stroke_color_filtered(const lv_obj_t * obj, lv_part_t part)
static inline int32_t lv_obj_get_style_text_outline_stroke_width(const lv_obj_t * obj, lv_part_t part)
static inline lv_opa_t lv_obj_get_style_text_outline_stroke_opa(const lv_obj_t * obj, lv_part_t part)
static inline int32_t lv_obj_get_style_radius(const lv_obj_t * obj, lv_part_t part)
static inline int32_t lv_obj_get_style_radial_offset(const lv_obj_t * obj, lv_part_t part)
static inline bool lv_obj_get_style_clip_corner(const lv_obj_t * obj, lv_part_t part)
static inline lv_opa_t lv_obj_get_style_opa(const lv_obj_t * obj, lv_part_t part)
static inline lv_opa_t lv_obj_get_style_opa_layered(const lv_obj_t * obj, lv_part_t part)
static inline const lv_color_filter_dsc_t * lv_obj_get_style_color_filter_dsc(const lv_obj_t * obj, lv_part_t part)
static inline lv_opa_t lv_obj_get_style_color_filter_opa(const lv_obj_t * obj, lv_part_t part)
static inline lv_color_t lv_obj_get_style_recolor(const lv_obj_t * obj, lv_part_t part)
static inline lv_opa_t lv_obj_get_style_recolor_opa(const lv_obj_t * obj, lv_part_t part)
static inline const lv_anim_t * lv_obj_get_style_anim(const lv_obj_t * obj, lv_part_t part)
static inline uint32_t lv_obj_get_style_anim_duration(const lv_obj_t * obj, lv_part_t part)
static inline const lv_style_transition_dsc_t * lv_obj_get_style_transition(const lv_obj_t * obj, lv_part_t part)
@ -375,6 +389,7 @@ void lv_obj_set_style_transform_width(lv_obj_t * obj, int32_t value, lv_style_se
void lv_obj_set_style_transform_height(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
void lv_obj_set_style_translate_x(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
void lv_obj_set_style_translate_y(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
void lv_obj_set_style_translate_radial(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
void lv_obj_set_style_transform_scale_x(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
void lv_obj_set_style_transform_scale_y(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
void lv_obj_set_style_transform_rotation(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
@ -388,6 +403,7 @@ void lv_obj_set_style_pad_left(lv_obj_t * obj, int32_t value, lv_style_selector_
void lv_obj_set_style_pad_right(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
void lv_obj_set_style_pad_row(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
void lv_obj_set_style_pad_column(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
void lv_obj_set_style_pad_radial(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
void lv_obj_set_style_margin_top(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
void lv_obj_set_style_margin_bottom(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
void lv_obj_set_style_margin_left(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
@ -442,12 +458,18 @@ void lv_obj_set_style_text_letter_space(lv_obj_t * obj, int32_t value, lv_style_
void lv_obj_set_style_text_line_space(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
void lv_obj_set_style_text_decor(lv_obj_t * obj, lv_text_decor_t value, lv_style_selector_t selector)
void lv_obj_set_style_text_align(lv_obj_t * obj, lv_text_align_t value, lv_style_selector_t selector)
void lv_obj_set_style_text_outline_stroke_color(lv_obj_t * obj, lv_color_t value, lv_style_selector_t selector)
void lv_obj_set_style_text_outline_stroke_width(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
void lv_obj_set_style_text_outline_stroke_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector)
void lv_obj_set_style_radius(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
void lv_obj_set_style_radial_offset(lv_obj_t * obj, int32_t value, lv_style_selector_t selector)
void lv_obj_set_style_clip_corner(lv_obj_t * obj, bool value, lv_style_selector_t selector)
void lv_obj_set_style_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector)
void lv_obj_set_style_opa_layered(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector)
void lv_obj_set_style_color_filter_dsc(lv_obj_t * obj, const lv_color_filter_dsc_t * value, lv_style_selector_t selector)
void lv_obj_set_style_color_filter_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector)
void lv_obj_set_style_recolor(lv_obj_t * obj, lv_color_t value, lv_style_selector_t selector)
void lv_obj_set_style_recolor_opa(lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector)
void lv_obj_set_style_anim(lv_obj_t * obj, const lv_anim_t * value, lv_style_selector_t selector)
void lv_obj_set_style_anim_duration(lv_obj_t * obj, uint32_t value, lv_style_selector_t selector)
void lv_obj_set_style_transition(lv_obj_t * obj, const lv_style_transition_dsc_t * value, lv_style_selector_t selector)
@ -498,6 +520,7 @@ void lv_obj_dump_tree(lv_obj_t * start_obj)
// ../../lvgl/src/core/lv_refr.h
void lv_refr_now(lv_display_t * disp)
void lv_obj_redraw(lv_layer_t * layer, lv_obj_t * obj)
void lv_display_refr_timer(lv_timer_t * timer)
// ../../lvgl/src/display/lv_display.h
lv_display_t * lv_display_create(int32_t hor_res, int32_t ver_res)
@ -509,22 +532,30 @@ void lv_display_set_resolution(lv_display_t * disp, int32_t hor_res, int32_t ver
void lv_display_set_physical_resolution(lv_display_t * disp, int32_t hor_res, int32_t ver_res)
void lv_display_set_offset(lv_display_t * disp, int32_t x, int32_t y)
void lv_display_set_rotation(lv_display_t * disp, lv_display_rotation_t rotation)
void lv_display_set_matrix_rotation(lv_display_t * disp, bool enable)
void lv_display_set_dpi(lv_display_t * disp, int32_t dpi)
int32_t lv_display_get_horizontal_resolution(const lv_display_t * disp)
int32_t lv_display_get_vertical_resolution(const lv_display_t * disp)
int32_t lv_display_get_original_horizontal_resolution(const lv_display_t * disp)
int32_t lv_display_get_original_vertical_resolution(const lv_display_t * disp)
int32_t lv_display_get_physical_horizontal_resolution(const lv_display_t * disp)
int32_t lv_display_get_physical_vertical_resolution(const lv_display_t * disp)
int32_t lv_display_get_offset_x(const lv_display_t * disp)
int32_t lv_display_get_offset_y(const lv_display_t * disp)
lv_display_rotation_t lv_display_get_rotation(lv_display_t * disp)
bool lv_display_get_matrix_rotation(lv_display_t * disp)
int32_t lv_display_get_dpi(const lv_display_t * disp)
void lv_display_set_buffers(lv_display_t * disp, void * buf1, void * buf2, uint32_t buf_size, lv_display_render_mode_t render_mode)
void lv_display_set_buffers_with_stride(lv_display_t * disp, void * buf1, void * buf2, uint32_t buf_size, uint32_t stride, lv_display_render_mode_t render_mode)
void lv_display_set_draw_buffers(lv_display_t * disp, lv_draw_buf_t * buf1, lv_draw_buf_t * buf2)
void lv_display_set_3rd_draw_buffer(lv_display_t * disp, lv_draw_buf_t * buf3)
void lv_display_set_render_mode(lv_display_t * disp, lv_display_render_mode_t render_mode)
void lv_display_set_flush_cb(lv_display_t * disp, lv_display_flush_cb_t flush_cb)
void lv_display_set_flush_wait_cb(lv_display_t * disp, lv_display_flush_wait_cb_t wait_cb)
void lv_display_set_color_format(lv_display_t * disp, lv_color_format_t color_format)
lv_color_format_t lv_display_get_color_format(lv_display_t * disp)
void lv_display_set_tile_cnt(lv_display_t * disp, uint32_t tile_cnt)
uint32_t lv_display_get_tile_cnt(lv_display_t * disp)
void lv_display_set_antialiasing(lv_display_t * disp, bool en)
bool lv_display_get_antialiasing(lv_display_t * disp)
bool lv_display_is_double_buffered(lv_display_t * disp)
@ -533,7 +564,7 @@ lv_obj_t * lv_display_get_screen_prev(lv_display_t * disp)
lv_obj_t * lv_display_get_layer_top(lv_display_t * disp)
lv_obj_t * lv_display_get_layer_sys(lv_display_t * disp)
lv_obj_t * lv_display_get_layer_bottom(lv_display_t * disp)
void lv_screen_load(struct lv_obj_t * scr)
void lv_screen_load(struct _lv_obj_t * scr)
void lv_screen_load_anim(lv_obj_t * scr, lv_screen_load_anim_t anim_type, uint32_t time, uint32_t delay, bool auto_del)
lv_obj_t * lv_screen_active(void)
lv_obj_t * lv_layer_top(void)
@ -545,6 +576,7 @@ lv_event_dsc_t * lv_display_get_event_dsc(lv_display_t * disp, uint32_t index)
bool lv_display_delete_event(lv_display_t * disp, uint32_t index)
uint32_t lv_display_remove_event_cb_with_user_data(lv_display_t * disp, lv_event_cb_t event_cb, void * user_data)
lv_result_t lv_display_send_event(lv_display_t * disp, lv_event_code_t code, void * param)
lv_area_t * lv_event_get_invalidated_area(lv_event_t * e)
void lv_display_set_theme(lv_display_t * disp, lv_theme_t * th)
lv_theme_t * lv_display_get_theme(lv_display_t * disp)
uint32_t lv_display_get_inactive_time(const lv_display_t * disp)
@ -553,12 +585,17 @@ void lv_display_enable_invalidation(lv_display_t * disp, bool en)
bool lv_display_is_invalidation_enabled(lv_display_t * disp)
lv_timer_t * lv_display_get_refr_timer(lv_display_t * disp)
void lv_display_delete_refr_timer(lv_display_t * disp)
bool lv_display_register_vsync_event(lv_display_t * disp, lv_event_cb_t event_cb, void * user_data)
bool lv_display_unregister_vsync_event(lv_display_t * disp, lv_event_cb_t event_cb, void * user_data)
lv_result_t lv_display_send_vsync_event(lv_display_t * disp, void * param)
void lv_display_set_user_data(lv_display_t * disp, void * user_data)
void lv_display_set_driver_data(lv_display_t * disp, void * driver_data)
void * lv_display_get_user_data(lv_display_t * disp)
void * lv_display_get_driver_data(lv_display_t * disp)
lv_draw_buf_t * lv_display_get_buf_active(lv_display_t * disp)
void lv_display_rotate_area(lv_display_t * disp, lv_area_t * area)
uint32_t lv_display_get_draw_buf_size(lv_display_t * disp)
uint32_t lv_display_get_invalidated_draw_buf_size(lv_display_t * disp, uint32_t width, uint32_t height)
int32_t lv_dpx(int32_t n)
int32_t lv_display_dpx(const lv_display_t * disp, int32_t n)
@ -566,7 +603,7 @@ int32_t lv_display_dpx(const lv_display_t * disp, int32_t n)
void lv_draw_init(void)
void lv_draw_deinit(void)
void * lv_draw_create_unit(size_t size)
lv_draw_task_t * lv_draw_add_task(lv_layer_t * layer, const lv_area_t * coords)
lv_draw_task_t * lv_draw_add_task(lv_layer_t * layer, const lv_area_t * coords, lv_draw_task_type_t type)
void lv_draw_finalize_task_creation(lv_layer_t * layer, lv_draw_task_t * t)
void lv_draw_dispatch(void)
bool lv_draw_dispatch_layer(lv_display_t * disp, lv_layer_t * layer)
@ -574,9 +611,13 @@ void lv_draw_dispatch_wait_for_request(void)
void lv_draw_wait_for_finish(void)
void lv_draw_dispatch_request(void)
uint32_t lv_draw_get_unit_count(void)
lv_draw_task_t * lv_draw_get_available_task(lv_layer_t * layer, lv_draw_task_t * t_prev, uint8_t draw_unit_id)
lv_draw_task_t * lv_draw_get_next_available_task(lv_layer_t * layer, lv_draw_task_t * t_prev, uint8_t draw_unit_id)
uint32_t lv_draw_get_dependent_count(lv_draw_task_t * t_check)
void lv_layer_init(lv_layer_t * layer)
void lv_layer_reset(lv_layer_t * layer)
lv_layer_t * lv_draw_layer_create(lv_layer_t * parent_layer, lv_color_format_t color_format, const lv_area_t * area)
void lv_draw_layer_init(lv_layer_t * layer, lv_layer_t * parent_layer, lv_color_format_t color_format, const lv_area_t * area)
void * lv_draw_layer_alloc_buf(lv_layer_t * layer)
void * lv_draw_layer_go_to_xy(lv_layer_t * layer, int32_t x, int32_t y)
lv_draw_task_type_t lv_draw_task_get_type(const lv_draw_task_t * t)
@ -590,12 +631,15 @@ void lv_draw_arc(lv_layer_t * layer, const lv_draw_arc_dsc_t * dsc)
void lv_draw_arc_get_area(int32_t x, int32_t y, uint16_t radius, lv_value_precise_t start_angle, lv_value_precise_t end_angle, int32_t w, bool rounded, lv_area_t * area)
// ../../lvgl/src/draw/lv_draw_label.h
void lv_draw_letter_dsc_init(lv_draw_letter_dsc_t * dsc)
void lv_draw_label_dsc_init(lv_draw_label_dsc_t * dsc)
lv_draw_label_dsc_t * lv_draw_task_get_label_dsc(lv_draw_task_t * task)
void lv_draw_glyph_dsc_init(lv_draw_glyph_dsc_t * dsc)
void lv_draw_label(lv_layer_t * layer, const lv_draw_label_dsc_t * dsc, const lv_area_t * coords)
void lv_draw_character(lv_layer_t * layer, lv_draw_label_dsc_t * dsc, const lv_point_t * point, uint32_t unicode_letter)
void lv_draw_label_iterate_characters(lv_draw_unit_t * draw_unit, const lv_draw_label_dsc_t * dsc, const lv_area_t * coords, lv_draw_glyph_cb_t cb)
void lv_draw_letter(lv_layer_t * layer, lv_draw_letter_dsc_t * dsc, const lv_point_t * point)
void lv_draw_label_iterate_characters(lv_draw_task_t * t, const lv_draw_label_dsc_t * dsc, const lv_area_t * coords, lv_draw_glyph_cb_t cb)
void lv_draw_unit_draw_letter(lv_draw_task_t * t, lv_draw_glyph_dsc_t * dsc, const lv_point_t * pos, const lv_font_t * font, uint32_t letter, lv_draw_glyph_cb_t cb)
// ../../lvgl/src/draw/lv_draw_line.h
void lv_draw_line_dsc_init(lv_draw_line_dsc_t * dsc)
@ -611,10 +655,13 @@ void lv_draw_mask_rect(lv_layer_t * layer, const lv_draw_mask_rect_dsc_t * dsc)
void lv_draw_rect_dsc_init(lv_draw_rect_dsc_t * dsc)
void lv_draw_fill_dsc_init(lv_draw_fill_dsc_t * dsc)
lv_draw_fill_dsc_t * lv_draw_task_get_fill_dsc(lv_draw_task_t * task)
void lv_draw_fill(lv_layer_t * layer, const lv_draw_fill_dsc_t * dsc, const lv_area_t * coords)
void lv_draw_border_dsc_init(lv_draw_border_dsc_t * dsc)
lv_draw_border_dsc_t * lv_draw_task_get_border_dsc(lv_draw_task_t * task)
void lv_draw_border(lv_layer_t * layer, const lv_draw_border_dsc_t * dsc, const lv_area_t * coords)
void lv_draw_box_shadow_dsc_init(lv_draw_box_shadow_dsc_t * dsc)
lv_draw_box_shadow_dsc_t * lv_draw_task_get_box_shadow_dsc(lv_draw_task_t * task)
void lv_draw_box_shadow(lv_layer_t * layer, const lv_draw_box_shadow_dsc_t * dsc, const lv_area_t * coords)
void lv_draw_rect(lv_layer_t * layer, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords)
// ../../lvgl/src/draw/lv_draw_triangle.h
@ -624,11 +671,15 @@ void lv_draw_triangle(lv_layer_t * layer, const lv_draw_triangle_dsc_t * draw_ds
// ../../lvgl/src/font/lv_font.h
const void * lv_font_get_glyph_bitmap(lv_font_glyph_dsc_t * g_dsc, lv_draw_buf_t * draw_buf)
const void * lv_font_get_glyph_static_bitmap(lv_font_glyph_dsc_t * g_dsc)
bool lv_font_get_glyph_dsc(const lv_font_t * font, lv_font_glyph_dsc_t * dsc_out, uint32_t letter, uint32_t letter_next)
void lv_font_glyph_release_draw_data(lv_font_glyph_dsc_t * g_dsc)
uint16_t lv_font_get_glyph_width(const lv_font_t * font, uint32_t letter, uint32_t letter_next)
int32_t lv_font_get_line_height(const lv_font_t * font)
void lv_font_set_kerning(lv_font_t * font, lv_font_kerning_t kerning)
const lv_font_t * lv_font_get_default(void)
bool lv_font_info_is_equal(const lv_font_info_t * ft_info_1, const lv_font_info_t * ft_info_2)
bool lv_font_has_static_bitmap(const lv_font_t * font)
// ../../lvgl/src/indev/lv_indev.h
lv_indev_t * lv_indev_create(void)
@ -642,8 +693,9 @@ void lv_indev_set_type(lv_indev_t * indev, lv_indev_type_t indev_type)
void lv_indev_set_read_cb(lv_indev_t * indev, lv_indev_read_cb_t read_cb)
void lv_indev_set_user_data(lv_indev_t * indev, void * user_data)
void lv_indev_set_driver_data(lv_indev_t * indev, void * driver_data)
void lv_indev_set_display(lv_indev_t * indev, struct lv_display_t * disp)
void lv_indev_set_display(lv_indev_t * indev, struct _lv_display_t * disp)
void lv_indev_set_long_press_time(lv_indev_t * indev, uint16_t long_press_time)
void lv_indev_set_long_press_repeat_time(lv_indev_t * indev, uint16_t long_press_repeat_time)
void lv_indev_set_scroll_limit(lv_indev_t * indev, uint8_t scroll_limit)
void lv_indev_set_scroll_throw(lv_indev_t * indev, uint8_t scroll_throw)
lv_indev_type_t lv_indev_get_type(const lv_indev_t * indev)
@ -663,9 +715,11 @@ void lv_indev_set_button_points(lv_indev_t * indev, const lv_point_t points[])
void lv_indev_get_point(const lv_indev_t * indev, lv_point_t * point)
lv_dir_t lv_indev_get_gesture_dir(const lv_indev_t * indev)
uint32_t lv_indev_get_key(const lv_indev_t * indev)
uint8_t lv_indev_get_short_click_streak(const lv_indev_t * indev)
lv_dir_t lv_indev_get_scroll_dir(const lv_indev_t * indev)
lv_obj_t * lv_indev_get_scroll_obj(const lv_indev_t * indev)
void lv_indev_get_vect(const lv_indev_t * indev, lv_point_t * point)
lv_obj_t * lv_indev_get_cursor(lv_indev_t * indev)
void lv_indev_wait_release(lv_indev_t * indev)
lv_obj_t * lv_indev_get_active_obj(void)
lv_timer_t * lv_indev_get_read_timer(lv_indev_t * indev)
@ -713,8 +767,11 @@ void lv_anim_init(lv_anim_t * a)
void lv_anim_set_var(lv_anim_t * a, void * var)
void lv_anim_set_exec_cb(lv_anim_t * a, lv_anim_exec_xcb_t exec_cb)
void lv_anim_set_duration(lv_anim_t * a, uint32_t duration)
void lv_anim_set_time(lv_anim_t * a, uint32_t duration)
void lv_anim_set_delay(lv_anim_t * a, uint32_t delay)
void lv_anim_resume(lv_anim_t * a)
void lv_anim_pause(lv_anim_t * a)
void lv_anim_pause_for(lv_anim_t * a, uint32_t ms)
bool lv_anim_is_paused(lv_anim_t * a)
void lv_anim_set_values(lv_anim_t * a, int32_t start, int32_t end)
void lv_anim_set_custom_exec_cb(lv_anim_t * a, lv_anim_custom_exec_cb_t exec_cb)
void lv_anim_set_path_cb(lv_anim_t * a, lv_anim_path_cb_t path_cb)
@ -722,9 +779,9 @@ void lv_anim_set_start_cb(lv_anim_t * a, lv_anim_start_cb_t start_cb)
void lv_anim_set_get_value_cb(lv_anim_t * a, lv_anim_get_value_cb_t get_value_cb)
void lv_anim_set_completed_cb(lv_anim_t * a, lv_anim_completed_cb_t completed_cb)
void lv_anim_set_deleted_cb(lv_anim_t * a, lv_anim_deleted_cb_t deleted_cb)
void lv_anim_set_playback_duration(lv_anim_t * a, uint32_t duration)
void lv_anim_set_playback_time(lv_anim_t * a, uint32_t duration)
void lv_anim_set_playback_delay(lv_anim_t * a, uint32_t delay)
void lv_anim_set_reverse_duration(lv_anim_t * a, uint32_t duration)
void lv_anim_set_reverse_time(lv_anim_t * a, uint32_t duration)
void lv_anim_set_reverse_delay(lv_anim_t * a, uint32_t delay)
void lv_anim_set_repeat_count(lv_anim_t * a, uint32_t cnt)
void lv_anim_set_repeat_delay(lv_anim_t * a, uint32_t delay)
void lv_anim_set_early_apply(lv_anim_t * a, bool en)
@ -745,6 +802,7 @@ lv_anim_t * lv_anim_custom_get(lv_anim_t * a, lv_anim_custom_exec_cb_t exec_cb)
uint16_t lv_anim_count_running(void)
uint32_t lv_anim_speed(uint32_t speed)
uint32_t lv_anim_speed_clamped(uint32_t speed, uint32_t min_time, uint32_t max_time)
uint32_t lv_anim_resolve_speed(uint32_t speed, int32_t start, int32_t end)
uint32_t lv_anim_speed_to_time(uint32_t speed, int32_t start, int32_t end)
void lv_anim_refr_now(void)
@ -798,12 +856,15 @@ uint8_t lv_color_luminance(lv_color_t c)
uint8_t lv_color16_luminance(const lv_color16_t c)
uint8_t lv_color24_luminance(const uint8_t * c)
uint8_t lv_color32_luminance(lv_color32_t c)
static inline uint16_t lv_color_swap_16(uint16_t c)
// ../../lvgl/src/misc/lv_color_op.h
lv_color_t lv_color_mix(lv_color_t c1, lv_color_t c2, uint8_t mix)
lv_color32_t lv_color_mix32(lv_color32_t fg, lv_color32_t bg)
lv_color32_t lv_color_mix32_premultiplied(lv_color32_t fg, lv_color32_t bg)
uint8_t lv_color_brightness(lv_color_t c)
void lv_color_filter_dsc_init(lv_color_filter_dsc_t * dsc, lv_color_filter_cb_t cb)
lv_color32_t lv_color_over32(lv_color32_t fg, lv_color32_t bg)
// ../../lvgl/src/misc/lv_event.h
lv_result_t lv_event_send(lv_event_list_t * list, lv_event_t * e, bool preprocess)
@ -823,6 +884,7 @@ void * lv_event_get_user_data(lv_event_t * e)
void lv_event_stop_bubbling(lv_event_t * e)
void lv_event_stop_processing(lv_event_t * e)
uint32_t lv_event_register_id(void)
const char * lv_event_code_get_name(lv_event_code_t code)
// ../../lvgl/src/misc/lv_palette.h
lv_color_t lv_palette_main(lv_palette_t p)
@ -832,6 +894,7 @@ lv_color_t lv_palette_darken(lv_palette_t p, uint8_t lvl)
// ../../lvgl/src/misc/lv_style.h
void lv_style_init(lv_style_t * style)
void lv_style_reset(lv_style_t * style)
void lv_style_copy(lv_style_t * dst, const lv_style_t * src)
static inline bool lv_style_is_const(const lv_style_t * style)
lv_style_prop_t lv_style_register_prop(uint8_t flag)
lv_style_prop_t lv_style_get_num_custom_props(void)
@ -849,6 +912,9 @@ static inline void lv_style_set_pad_all(lv_style_t * style, int32_t value)
static inline void lv_style_set_pad_hor(lv_style_t * style, int32_t value)
static inline void lv_style_set_pad_ver(lv_style_t * style, int32_t value)
static inline void lv_style_set_pad_gap(lv_style_t * style, int32_t value)
static inline void lv_style_set_margin_hor(lv_style_t * style, int32_t value)
static inline void lv_style_set_margin_ver(lv_style_t * style, int32_t value)
static inline void lv_style_set_margin_all(lv_style_t * style, int32_t value)
static inline void lv_style_set_transform_scale(lv_style_t * style, int32_t value)
static inline bool lv_style_prop_has_flag(lv_style_prop_t prop, uint8_t flag)
@ -867,6 +933,7 @@ void lv_style_set_transform_width(lv_style_t * style, int32_t value)
void lv_style_set_transform_height(lv_style_t * style, int32_t value)
void lv_style_set_translate_x(lv_style_t * style, int32_t value)
void lv_style_set_translate_y(lv_style_t * style, int32_t value)
void lv_style_set_translate_radial(lv_style_t * style, int32_t value)
void lv_style_set_transform_scale_x(lv_style_t * style, int32_t value)
void lv_style_set_transform_scale_y(lv_style_t * style, int32_t value)
void lv_style_set_transform_rotation(lv_style_t * style, int32_t value)
@ -880,6 +947,7 @@ void lv_style_set_pad_left(lv_style_t * style, int32_t value)
void lv_style_set_pad_right(lv_style_t * style, int32_t value)
void lv_style_set_pad_row(lv_style_t * style, int32_t value)
void lv_style_set_pad_column(lv_style_t * style, int32_t value)
void lv_style_set_pad_radial(lv_style_t * style, int32_t value)
void lv_style_set_margin_top(lv_style_t * style, int32_t value)
void lv_style_set_margin_bottom(lv_style_t * style, int32_t value)
void lv_style_set_margin_left(lv_style_t * style, int32_t value)
@ -934,12 +1002,18 @@ void lv_style_set_text_letter_space(lv_style_t * style, int32_t value)
void lv_style_set_text_line_space(lv_style_t * style, int32_t value)
void lv_style_set_text_decor(lv_style_t * style, lv_text_decor_t value)
void lv_style_set_text_align(lv_style_t * style, lv_text_align_t value)
void lv_style_set_text_outline_stroke_color(lv_style_t * style, lv_color_t value)
void lv_style_set_text_outline_stroke_width(lv_style_t * style, int32_t value)
void lv_style_set_text_outline_stroke_opa(lv_style_t * style, lv_opa_t value)
void lv_style_set_radius(lv_style_t * style, int32_t value)
void lv_style_set_radial_offset(lv_style_t * style, int32_t value)
void lv_style_set_clip_corner(lv_style_t * style, bool value)
void lv_style_set_opa(lv_style_t * style, lv_opa_t value)
void lv_style_set_opa_layered(lv_style_t * style, lv_opa_t value)
void lv_style_set_color_filter_dsc(lv_style_t * style, const lv_color_filter_dsc_t * value)
void lv_style_set_color_filter_opa(lv_style_t * style, lv_opa_t value)
void lv_style_set_recolor(lv_style_t * style, lv_color_t value)
void lv_style_set_recolor_opa(lv_style_t * style, lv_opa_t value)
void lv_style_set_anim(lv_style_t * style, const lv_anim_t * value)
void lv_style_set_anim_duration(lv_style_t * style, uint32_t value)
void lv_style_set_transition(lv_style_t * style, const lv_style_transition_dsc_t * value)
@ -967,6 +1041,8 @@ void lv_style_set_grid_cell_row_span(lv_style_t * style, int32_t value)
// ../../lvgl/src/misc/lv_text.h
void lv_text_get_size(lv_point_t * size_res, const char * text, const lv_font_t * font, int32_t letter_space, int32_t line_space, int32_t max_width, lv_text_flag_t flag)
int32_t lv_text_get_width(const char * txt, uint32_t length, const lv_font_t * font, int32_t letter_space)
int32_t lv_text_get_width_with_flags(const char * txt, uint32_t length, const lv_font_t * font, int32_t letter_space, lv_text_flag_t flags)
bool lv_text_is_cmd(lv_text_cmd_state_t * state, uint32_t c)
// ../../lvgl/src/misc/lv_timer.h
uint32_t lv_timer_handler(void)
@ -1005,15 +1081,21 @@ lv_color_t lv_theme_get_color_secondary(lv_obj_t * obj)
// ../../lvgl/src/widgets/animimage/lv_animimage.h
lv_obj_t * lv_animimg_create(lv_obj_t * parent)
void lv_animimg_set_src(lv_obj_t * img, const void * dsc[], size_t num)
void lv_animimg_set_src(lv_obj_t * obj, const void * dsc[], size_t num)
void lv_animimg_set_src_reverse(lv_obj_t * obj, const void * dsc[], size_t num)
void lv_animimg_start(lv_obj_t * obj)
void lv_animimg_set_duration(lv_obj_t * img, uint32_t duration)
void lv_animimg_set_repeat_count(lv_obj_t * img, uint32_t count)
const void ** lv_animimg_get_src(lv_obj_t * img)
uint8_t lv_animimg_get_src_count(lv_obj_t * img)
uint32_t lv_animimg_get_duration(lv_obj_t * img)
uint32_t lv_animimg_get_repeat_count(lv_obj_t * img)
lv_anim_t * lv_animimg_get_anim(lv_obj_t * img)
bool lv_animimg_delete(lv_obj_t * obj)
void lv_animimg_set_duration(lv_obj_t * obj, uint32_t duration)
void lv_animimg_set_repeat_count(lv_obj_t * obj, uint32_t count)
void lv_animimg_set_reverse_duration(lv_obj_t * obj, uint32_t duration)
void lv_animimg_set_reverse_delay(lv_obj_t * obj, uint32_t duration)
void lv_animimg_set_start_cb(lv_obj_t * obj, lv_anim_start_cb_t start_cb)
void lv_animimg_set_completed_cb(lv_obj_t * obj, lv_anim_completed_cb_t completed_cb)
const void ** lv_animimg_get_src(lv_obj_t * obj)
uint8_t lv_animimg_get_src_count(lv_obj_t * obj)
uint32_t lv_animimg_get_duration(lv_obj_t * obj)
uint32_t lv_animimg_get_repeat_count(lv_obj_t * obj)
lv_anim_t * lv_animimg_get_anim(lv_obj_t * obj)
// ../../lvgl/src/widgets/arc/lv_arc.h
lv_obj_t * lv_arc_create(lv_obj_t * parent)
@ -1080,7 +1162,7 @@ bool lv_buttonmatrix_get_one_checked(const lv_obj_t * obj)
// ../../lvgl/src/widgets/calendar/lv_calendar.h
lv_obj_t * lv_calendar_create(lv_obj_t * parent)
void lv_calendar_set_today_date(lv_obj_t * obj, uint32_t year, uint32_t month, uint32_t day)
void lv_calendar_set_showed_date(lv_obj_t * obj, uint32_t year, uint32_t month)
void lv_calendar_set_month_shown(lv_obj_t * obj, uint32_t year, uint32_t month)
void lv_calendar_set_highlighted_dates(lv_obj_t * obj, lv_calendar_date_t highlighted[], size_t date_num)
void lv_calendar_set_day_names(lv_obj_t * obj, const char ** day_names)
lv_obj_t * lv_calendar_get_btnmatrix(const lv_obj_t * obj)
@ -1096,10 +1178,10 @@ const char * lv_calendar_get_day_name(lv_calendar_date_t * gregorian)
void lv_calendar_gregorian_to_chinese(lv_calendar_date_t * gregorian_time, lv_calendar_chinese_t * chinese_time)
// ../../lvgl/src/widgets/calendar/lv_calendar_header_arrow.h
lv_obj_t * lv_calendar_header_arrow_create(lv_obj_t * parent)
lv_obj_t * lv_calendar_add_header_arrow(lv_obj_t * parent)
// ../../lvgl/src/widgets/calendar/lv_calendar_header_dropdown.h
lv_obj_t * lv_calendar_header_dropdown_create(lv_obj_t * parent)
lv_obj_t * lv_calendar_add_header_dropdown(lv_obj_t * parent)
void lv_calendar_header_dropdown_set_year_list(lv_obj_t * parent, const char * years_list)
// ../../lvgl/src/widgets/canvas/lv_canvas.h
@ -1122,7 +1204,7 @@ uint32_t lv_canvas_buf_size(int32_t w, int32_t h, uint8_t bpp, uint8_t stride)
lv_obj_t * lv_chart_create(lv_obj_t * parent)
void lv_chart_set_type(lv_obj_t * obj, lv_chart_type_t type)
void lv_chart_set_point_count(lv_obj_t * obj, uint32_t cnt)
void lv_chart_set_range(lv_obj_t * obj, lv_chart_axis_t axis, int32_t min, int32_t max)
void lv_chart_set_axis_range(lv_obj_t * obj, lv_chart_axis_t axis, int32_t min, int32_t max)
void lv_chart_set_update_mode(lv_obj_t * obj, lv_chart_update_mode_t update_mode)
void lv_chart_set_div_line_count(lv_obj_t * obj, uint8_t hdiv, uint8_t vdiv)
lv_chart_type_t lv_chart_get_type(const lv_obj_t * obj)
@ -1139,17 +1221,21 @@ void lv_chart_set_x_start_point(lv_obj_t * obj, lv_chart_series_t * ser, uint32_
lv_chart_series_t * lv_chart_get_series_next(const lv_obj_t * chart, const lv_chart_series_t * ser)
lv_chart_cursor_t * lv_chart_add_cursor(lv_obj_t * obj, lv_color_t color, lv_dir_t dir)
void lv_chart_set_cursor_pos(lv_obj_t * chart, lv_chart_cursor_t * cursor, lv_point_t * pos)
void lv_chart_set_cursor_pos_x(lv_obj_t * chart, lv_chart_cursor_t * cursor, int32_t x)
void lv_chart_set_cursor_pos_y(lv_obj_t * chart, lv_chart_cursor_t * cursor, int32_t y)
void lv_chart_set_cursor_point(lv_obj_t * chart, lv_chart_cursor_t * cursor, lv_chart_series_t * ser, uint32_t point_id)
lv_point_t lv_chart_get_cursor_point(lv_obj_t * chart, lv_chart_cursor_t * cursor)
void lv_chart_set_all_value(lv_obj_t * obj, lv_chart_series_t * ser, int32_t value)
void lv_chart_set_all_values(lv_obj_t * obj, lv_chart_series_t * ser, int32_t value)
void lv_chart_set_next_value(lv_obj_t * obj, lv_chart_series_t * ser, int32_t value)
void lv_chart_set_next_value2(lv_obj_t * obj, lv_chart_series_t * ser, int32_t x_value, int32_t y_value)
void lv_chart_set_value_by_id(lv_obj_t * obj, lv_chart_series_t * ser, uint32_t id, int32_t value)
void lv_chart_set_value_by_id2(lv_obj_t * obj, lv_chart_series_t * ser, uint32_t id, int32_t x_value, int32_t y_value)
void lv_chart_set_ext_y_array(lv_obj_t * obj, lv_chart_series_t * ser, int32_t array[])
void lv_chart_set_ext_x_array(lv_obj_t * obj, lv_chart_series_t * ser, int32_t array[])
int32_t * lv_chart_get_y_array(const lv_obj_t * obj, lv_chart_series_t * ser)
int32_t * lv_chart_get_x_array(const lv_obj_t * obj, lv_chart_series_t * ser)
void lv_chart_set_series_values(lv_obj_t * obj, lv_chart_series_t * ser, const int32_t values[], size_t values_cnt)
void lv_chart_set_series_values2(lv_obj_t * obj, lv_chart_series_t * ser, const int32_t x_values[], const int32_t y_values[], size_t values_cnt)
void lv_chart_set_series_value_by_id(lv_obj_t * obj, lv_chart_series_t * ser, uint32_t id, int32_t value)
void lv_chart_set_series_value_by_id2(lv_obj_t * obj, lv_chart_series_t * ser, uint32_t id, int32_t x_value, int32_t y_value)
void lv_chart_set_series_ext_y_array(lv_obj_t * obj, lv_chart_series_t * ser, int32_t array[])
void lv_chart_set_series_ext_x_array(lv_obj_t * obj, lv_chart_series_t * ser, int32_t array[])
int32_t * lv_chart_get_series_y_array(const lv_obj_t * obj, lv_chart_series_t * ser)
int32_t * lv_chart_get_series_x_array(const lv_obj_t * obj, lv_chart_series_t * ser)
uint32_t lv_chart_get_pressed_point(const lv_obj_t * obj)
int32_t lv_chart_get_first_point_center_offset(lv_obj_t * obj)
@ -1206,6 +1292,10 @@ void lv_image_get_pivot(lv_obj_t * obj, lv_point_t * pivot)
int32_t lv_image_get_scale(lv_obj_t * obj)
int32_t lv_image_get_scale_x(lv_obj_t * obj)
int32_t lv_image_get_scale_y(lv_obj_t * obj)
int32_t lv_image_get_src_width(lv_obj_t * obj)
int32_t lv_image_get_src_height(lv_obj_t * obj)
int32_t lv_image_get_transformed_width(lv_obj_t * obj)
int32_t lv_image_get_transformed_height(lv_obj_t * obj)
lv_blend_mode_t lv_image_get_blend_mode(lv_obj_t * obj)
bool lv_image_get_antialias(lv_obj_t * obj)
lv_image_align_t lv_image_get_inner_align(lv_obj_t * obj)
@ -1237,6 +1327,7 @@ void lv_label_set_text_static(lv_obj_t * obj, const char * text)
void lv_label_set_long_mode(lv_obj_t * obj, lv_label_long_mode_t long_mode)
void lv_label_set_text_selection_start(lv_obj_t * obj, uint32_t index)
void lv_label_set_text_selection_end(lv_obj_t * obj, uint32_t index)
void lv_label_set_recolor(lv_obj_t * obj, bool en)
char * lv_label_get_text(const lv_obj_t * obj)
lv_label_long_mode_t lv_label_get_long_mode(const lv_obj_t * obj)
void lv_label_get_letter_pos(const lv_obj_t * obj, uint32_t char_id, lv_point_t * pos)
@ -1244,6 +1335,7 @@ uint32_t lv_label_get_letter_on(const lv_obj_t * obj, lv_point_t * pos_in, bool
bool lv_label_is_char_under_pos(const lv_obj_t * obj, lv_point_t * pos)
uint32_t lv_label_get_text_selection_start(const lv_obj_t * obj)
uint32_t lv_label_get_text_selection_end(const lv_obj_t * obj)
bool lv_label_get_recolor(const lv_obj_t * obj)
void lv_label_ins_text(lv_obj_t * obj, uint32_t pos, const char * txt)
void lv_label_cut_text(lv_obj_t * obj, uint32_t pos, uint32_t cnt)
@ -1276,7 +1368,7 @@ void lv_list_set_button_text(lv_obj_t * list, lv_obj_t * btn, const char * txt)
// ../../lvgl/src/widgets/menu/lv_menu.h
lv_obj_t * lv_menu_create(lv_obj_t * parent)
lv_obj_t * lv_menu_page_create(lv_obj_t * parent, char const * const title)
lv_obj_t * lv_menu_page_create(lv_obj_t * menu, char const * const title)
lv_obj_t * lv_menu_cont_create(lv_obj_t * parent)
lv_obj_t * lv_menu_section_create(lv_obj_t * parent)
lv_obj_t * lv_menu_separator_create(lv_obj_t * parent)
@ -1316,6 +1408,7 @@ void lv_msgbox_close_async(lv_obj_t * mbox)
lv_obj_t * lv_roller_create(lv_obj_t * parent)
void lv_roller_set_options(lv_obj_t * obj, const char * options, lv_roller_mode_t mode)
void lv_roller_set_selected(lv_obj_t * obj, uint32_t sel_opt, lv_anim_enable_t anim)
bool lv_roller_set_selected_str(lv_obj_t * obj, const char * sel_opt, lv_anim_enable_t anim)
void lv_roller_set_visible_row_count(lv_obj_t * obj, uint32_t row_cnt)
uint32_t lv_roller_get_selected(const lv_obj_t * obj)
void lv_roller_get_selected_str(const lv_obj_t * obj, char * buf, uint32_t buf_size)
@ -1337,11 +1430,16 @@ void lv_scale_set_text_src(lv_obj_t * obj, const char * txt_src[])
void lv_scale_set_post_draw(lv_obj_t * obj, bool en)
void lv_scale_set_draw_ticks_on_top(lv_obj_t * obj, bool en)
lv_scale_section_t * lv_scale_add_section(lv_obj_t * obj)
void lv_scale_section_set_range(lv_scale_section_t * section, int32_t minor_range, int32_t major_range)
void lv_scale_section_set_range(lv_scale_section_t * section, int32_t min, int32_t max)
void lv_scale_set_section_range(lv_obj_t * scale, lv_scale_section_t * section, int32_t min, int32_t max)
void lv_scale_section_set_style(lv_scale_section_t * section, lv_part_t part, lv_style_t * section_part_style)
void lv_scale_set_section_style_main(lv_obj_t * scale, lv_scale_section_t * section, const lv_style_t * style)
void lv_scale_set_section_style_indicator(lv_obj_t * scale, lv_scale_section_t * section, const lv_style_t * style)
void lv_scale_set_section_style_items(lv_obj_t * scale, lv_scale_section_t * section, const lv_style_t * style)
lv_scale_mode_t lv_scale_get_mode(lv_obj_t * obj)
int32_t lv_scale_get_total_tick_count(lv_obj_t * obj)
int32_t lv_scale_get_major_tick_every(lv_obj_t * obj)
int32_t lv_scale_get_rotation(lv_obj_t * obj)
bool lv_scale_get_label_show(lv_obj_t * obj)
uint32_t lv_scale_get_angle_range(lv_obj_t * obj)
int32_t lv_scale_get_range_min_value(lv_obj_t * obj)
@ -1350,31 +1448,38 @@ int32_t lv_scale_get_range_max_value(lv_obj_t * obj)
// ../../lvgl/src/widgets/slider/lv_slider.h
lv_obj_t * lv_slider_create(lv_obj_t * parent)
void lv_slider_set_value(lv_obj_t * obj, int32_t value, lv_anim_enable_t anim)
void lv_slider_set_left_value(lv_obj_t * obj, int32_t value, lv_anim_enable_t anim)
void lv_slider_set_start_value(lv_obj_t * obj, int32_t value, lv_anim_enable_t anim)
void lv_slider_set_range(lv_obj_t * obj, int32_t min, int32_t max)
void lv_slider_set_mode(lv_obj_t * obj, lv_slider_mode_t mode)
void lv_slider_set_orientation(lv_obj_t * obj, lv_slider_orientation_t orientation)
int32_t lv_slider_get_value(const lv_obj_t * obj)
int32_t lv_slider_get_left_value(const lv_obj_t * obj)
int32_t lv_slider_get_min_value(const lv_obj_t * obj)
int32_t lv_slider_get_max_value(const lv_obj_t * obj)
bool lv_slider_is_dragged(const lv_obj_t * obj)
lv_slider_mode_t lv_slider_get_mode(lv_obj_t * slider)
lv_slider_orientation_t lv_slider_get_orientation(lv_obj_t * slider)
bool lv_slider_is_symmetrical(lv_obj_t * obj)
// ../../lvgl/src/widgets/span/lv_span.h
void lv_span_stack_init(void)
void lv_span_stack_deinit(void)
lv_obj_t * lv_spangroup_create(lv_obj_t * parent)
lv_span_t * lv_spangroup_new_span(lv_obj_t * obj)
lv_span_t * lv_spangroup_add_span(lv_obj_t * obj)
void lv_spangroup_delete_span(lv_obj_t * obj, lv_span_t * span)
void lv_span_set_text(lv_span_t * span, const char * text)
void lv_span_set_text_static(lv_span_t * span, const char * text)
void lv_spangroup_set_span_text(lv_obj_t * obj, lv_span_t * span, const char * text)
void lv_spangroup_set_span_text_static(lv_obj_t * obj, lv_span_t * span, const char * text)
void lv_span_set_text_static(lv_span_t * span, const char * text)
void lv_spangroup_set_span_style(lv_obj_t * obj, lv_span_t * span, const lv_style_t * style)
void lv_spangroup_set_align(lv_obj_t * obj, lv_text_align_t align)
void lv_spangroup_set_overflow(lv_obj_t * obj, lv_span_overflow_t overflow)
void lv_spangroup_set_indent(lv_obj_t * obj, int32_t indent)
void lv_spangroup_set_mode(lv_obj_t * obj, lv_span_mode_t mode)
void lv_spangroup_set_max_lines(lv_obj_t * obj, int32_t lines)
lv_style_t * lv_span_get_style(lv_span_t * span)
const char * lv_span_get_text(lv_span_t * span)
lv_span_t * lv_spangroup_get_child(const lv_obj_t * obj, int32_t id)
uint32_t lv_spangroup_get_span_count(const lv_obj_t * obj)
lv_text_align_t lv_spangroup_get_align(lv_obj_t * obj)
@ -1385,7 +1490,9 @@ int32_t lv_spangroup_get_max_lines(lv_obj_t * obj)
int32_t lv_spangroup_get_max_line_height(lv_obj_t * obj)
uint32_t lv_spangroup_get_expand_width(lv_obj_t * obj, uint32_t max_width)
int32_t lv_spangroup_get_expand_height(lv_obj_t * obj, int32_t width)
void lv_spangroup_refr_mode(lv_obj_t * obj)
lv_span_coords_t lv_spangroup_get_span_coords(lv_obj_t * obj, const lv_span_t * span)
lv_span_t * lv_spangroup_get_span_by_point(lv_obj_t * obj, const lv_point_t * point)
void lv_spangroup_refresh(lv_obj_t * obj)
// ../../lvgl/src/widgets/spinbox/lv_spinbox.h
lv_obj_t * lv_spinbox_create(lv_obj_t * parent)
@ -1410,6 +1517,8 @@ void lv_spinner_set_anim_params(lv_obj_t * obj, uint32_t t, uint32_t angle)
// ../../lvgl/src/widgets/switch/lv_switch.h
lv_obj_t * lv_switch_create(lv_obj_t * parent)
void lv_switch_set_orientation(lv_obj_t * obj, lv_switch_orientation_t orientation)
lv_switch_orientation_t lv_switch_get_orientation(lv_obj_t * obj)
// ../../lvgl/src/widgets/table/lv_table.h
lv_obj_t * lv_table_create(lv_obj_t * parent)
@ -1418,7 +1527,7 @@ void lv_table_set_cell_value_fmt(lv_obj_t * obj, uint32_t row, uint32_t col, con
void lv_table_set_row_count(lv_obj_t * obj, uint32_t row_cnt)
void lv_table_set_column_count(lv_obj_t * obj, uint32_t col_cnt)
void lv_table_set_column_width(lv_obj_t * obj, uint32_t col_id, int32_t w)
void lv_table_add_cell_ctrl(lv_obj_t * obj, uint32_t row, uint32_t col, lv_table_cell_ctrl_t ctrl)
void lv_table_set_cell_ctrl(lv_obj_t * obj, uint32_t row, uint32_t col, lv_table_cell_ctrl_t ctrl)
void lv_table_clear_cell_ctrl(lv_obj_t * obj, uint32_t row, uint32_t col, lv_table_cell_ctrl_t ctrl)
void lv_table_set_cell_user_data(lv_obj_t * obj, uint16_t row, uint16_t col, void * user_data)
void lv_table_set_selected_cell(lv_obj_t * obj, uint16_t row, uint16_t col)

View File

@ -41,6 +41,16 @@ const be_ctypes_structure_t be_lv_area = {
{ "y2", 12, 0, 0, ctypes_i32, 0 },
}};
const be_ctypes_structure_t be_lv_grad_stop = {
8, /* size in bytes */
3, /* number of elements */
be_ctypes_instance_mappings,
(const be_ctypes_structure_item_t[3]) {
{ "color", 0, 0, 0, ctypes_u24, 1 },
{ "frac", 4, 0, 0, ctypes_u8, 0 },
{ "opa", 3, 0, 0, ctypes_u8, 0 },
}};
const be_ctypes_structure_t be_lv_gradient_stop = {
8, /* size in bytes */
3, /* number of elements */
@ -56,8 +66,8 @@ const be_ctypes_structure_t be_lv_grad_dsc = {
9, /* number of elements */
be_ctypes_instance_mappings,
(const be_ctypes_structure_item_t[9]) {
{ "dir", 11, 0, 3, ctypes_bf, 0 },
{ "extend", 11, 3, 2, ctypes_bf, 0 },
{ "dir", 11, 0, 4, ctypes_bf, 0 },
{ "extend", 11, 4, 3, ctypes_bf, 0 },
{ "stops_0_color", 0, 0, 0, ctypes_u24, 1 },
{ "stops_0_frac", 4, 0, 0, ctypes_u8, 0 },
{ "stops_0_opa", 3, 0, 0, ctypes_u8, 0 },
@ -94,8 +104,8 @@ const be_ctypes_structure_t be_lv_draw_rect_dsc = {
{ "base_part", 4, 0, 0, ctypes_u32, 0 },
{ "base_user_data", 24, 0, 0, ctypes_ptr32, 0 },
{ "bg_color", 33, 0, 0, ctypes_u24, 1 },
{ "bg_grad_dir", 47, 0, 3, ctypes_bf, 0 },
{ "bg_grad_extend", 47, 3, 2, ctypes_bf, 0 },
{ "bg_grad_dir", 47, 0, 4, ctypes_bf, 0 },
{ "bg_grad_extend", 47, 4, 3, ctypes_bf, 0 },
{ "bg_grad_stops_0_color", 36, 0, 0, ctypes_u24, 1 },
{ "bg_grad_stops_0_frac", 40, 0, 0, ctypes_u8, 0 },
{ "bg_grad_stops_0_opa", 39, 0, 0, ctypes_u8, 0 },
@ -130,9 +140,9 @@ const be_ctypes_structure_t be_lv_draw_rect_dsc = {
const be_ctypes_structure_t be_lv_draw_line_dsc = {
64, /* size in bytes */
20, /* number of elements */
19, /* number of elements */
be_ctypes_instance_mappings,
(const be_ctypes_structure_item_t[20]) {
(const be_ctypes_structure_item_t[19]) {
{ "base_dsc_size", 20, 0, 0, ctypes_u32, 0 },
{ "base_id1", 8, 0, 0, ctypes_u32, 0 },
{ "base_id2", 12, 0, 0, ctypes_u32, 0 },
@ -140,7 +150,6 @@ const be_ctypes_structure_t be_lv_draw_line_dsc = {
{ "base_obj", 0, 0, 0, ctypes_ptr32, 0 },
{ "base_part", 4, 0, 0, ctypes_u32, 0 },
{ "base_user_data", 24, 0, 0, ctypes_ptr32, 0 },
{ "blend_mode", 61, 0, 2, ctypes_bf, 0 },
{ "color", 44, 0, 0, ctypes_u24, 1 },
{ "dash_gap", 56, 0, 0, ctypes_i32, 0 },
{ "dash_width", 52, 0, 0, ctypes_i32, 0 },
@ -149,9 +158,9 @@ const be_ctypes_structure_t be_lv_draw_line_dsc = {
{ "p1_y", 32, 0, 0, ctypes_i32, 0 },
{ "p2_x", 36, 0, 0, ctypes_i32, 0 },
{ "p2_y", 40, 0, 0, ctypes_i32, 0 },
{ "raw_end", 61, 4, 1, ctypes_bf, 0 },
{ "round_end", 61, 3, 1, ctypes_bf, 0 },
{ "round_start", 61, 2, 1, ctypes_bf, 0 },
{ "raw_end", 61, 2, 1, ctypes_bf, 0 },
{ "round_end", 61, 1, 1, ctypes_bf, 0 },
{ "round_start", 61, 0, 1, ctypes_bf, 0 },
{ "width", 48, 0, 0, ctypes_i32, 0 },
}};
@ -198,7 +207,7 @@ const be_ctypes_structure_t be_lv_draw_image_dsc = {
35, /* number of elements */
be_ctypes_instance_mappings,
(const be_ctypes_structure_item_t[35]) {
{ "antialias", 77, 4, 1, ctypes_bf, 0 },
{ "antialias", 81, 4, 1, ctypes_bf, 0 },
{ "base_dsc_size", 20, 0, 0, ctypes_u32, 0 },
{ "base_id1", 8, 0, 0, ctypes_u32, 0 },
{ "base_id2", 12, 0, 0, ctypes_u32, 0 },
@ -207,8 +216,8 @@ const be_ctypes_structure_t be_lv_draw_image_dsc = {
{ "base_part", 4, 0, 0, ctypes_u32, 0 },
{ "base_user_data", 24, 0, 0, ctypes_ptr32, 0 },
{ "bitmap_mask_src", 104, 0, 0, ctypes_ptr32, 0 },
{ "blend_mode", 77, 0, 4, ctypes_bf, 0 },
{ "clip_radius", 100, 0, 0, ctypes_i32, 0 },
{ "blend_mode", 81, 0, 4, ctypes_bf, 0 },
{ "clip_radius", 44, 0, 0, ctypes_i32, 0 },
{ "header_cf", 33, 0, 0, ctypes_u8, 0 },
{ "header_flags", 34, 0, 0, ctypes_u16, 0 },
{ "header_h", 38, 0, 0, ctypes_u16, 0 },
@ -216,31 +225,31 @@ const be_ctypes_structure_t be_lv_draw_image_dsc = {
{ "header_reserved_2", 42, 0, 0, ctypes_u16, 0 },
{ "header_stride", 40, 0, 0, ctypes_u16, 0 },
{ "header_w", 36, 0, 0, ctypes_u16, 0 },
{ "image_area_x1", 84, 0, 0, ctypes_i32, 0 },
{ "image_area_x2", 92, 0, 0, ctypes_i32, 0 },
{ "image_area_y1", 88, 0, 0, ctypes_i32, 0 },
{ "image_area_y2", 96, 0, 0, ctypes_i32, 0 },
{ "opa", 76, 0, 0, ctypes_u8, 0 },
{ "pivot_x", 64, 0, 0, ctypes_i32, 0 },
{ "pivot_y", 68, 0, 0, ctypes_i32, 0 },
{ "recolor", 72, 0, 0, ctypes_u24, 1 },
{ "recolor_opa", 75, 0, 0, ctypes_u8, 0 },
{ "rotation", 44, 0, 0, ctypes_i32, 0 },
{ "scale_x", 48, 0, 0, ctypes_i32, 0 },
{ "scale_y", 52, 0, 0, ctypes_i32, 0 },
{ "skew_x", 56, 0, 0, ctypes_i32, 0 },
{ "skew_y", 60, 0, 0, ctypes_i32, 0 },
{ "image_area_x1", 88, 0, 0, ctypes_i32, 0 },
{ "image_area_x2", 96, 0, 0, ctypes_i32, 0 },
{ "image_area_y1", 92, 0, 0, ctypes_i32, 0 },
{ "image_area_y2", 100, 0, 0, ctypes_i32, 0 },
{ "opa", 80, 0, 0, ctypes_u8, 0 },
{ "pivot_x", 68, 0, 0, ctypes_i32, 0 },
{ "pivot_y", 72, 0, 0, ctypes_i32, 0 },
{ "recolor", 76, 0, 0, ctypes_u24, 1 },
{ "recolor_opa", 79, 0, 0, ctypes_u8, 0 },
{ "rotation", 48, 0, 0, ctypes_i32, 0 },
{ "scale_x", 52, 0, 0, ctypes_i32, 0 },
{ "scale_y", 56, 0, 0, ctypes_i32, 0 },
{ "skew_x", 60, 0, 0, ctypes_i32, 0 },
{ "skew_y", 64, 0, 0, ctypes_i32, 0 },
{ "src", 28, 0, 0, ctypes_ptr32, 0 },
{ "sup", 80, 0, 0, ctypes_ptr32, 0 },
{ "tile", 77, 5, 1, ctypes_bf, 0 },
{ "sup", 84, 0, 0, ctypes_ptr32, 0 },
{ "tile", 81, 5, 1, ctypes_bf, 0 },
}};
const be_ctypes_structure_t be_lv_draw_label_dsc = {
84, /* size in bytes */
26, /* number of elements */
108, /* size in bytes */
35, /* number of elements */
be_ctypes_instance_mappings,
(const be_ctypes_structure_item_t[26]) {
{ "align", 74, 0, 0, ctypes_u8, 0 },
(const be_ctypes_structure_item_t[35]) {
{ "align", 89, 0, 0, ctypes_u8, 0 },
{ "base_dsc_size", 20, 0, 0, ctypes_u32, 0 },
{ "base_id1", 8, 0, 0, ctypes_u32, 0 },
{ "base_id2", 12, 0, 0, ctypes_u32, 0 },
@ -248,24 +257,33 @@ const be_ctypes_structure_t be_lv_draw_label_dsc = {
{ "base_obj", 0, 0, 0, ctypes_ptr32, 0 },
{ "base_part", 4, 0, 0, ctypes_u32, 0 },
{ "base_user_data", 24, 0, 0, ctypes_ptr32, 0 },
{ "bidi_dir", 73, 0, 0, ctypes_u8, 0 },
{ "blend_mode", 76, 3, 3, ctypes_bf, 0 },
{ "bidi_dir", 90, 0, 0, ctypes_u8, 0 },
{ "blend_mode", 93, 0, 3, ctypes_bf, 0 },
{ "color", 44, 0, 0, ctypes_u24, 1 },
{ "decor", 76, 0, 3, ctypes_bf, 0 },
{ "flag", 75, 0, 0, ctypes_u8, 0 },
{ "font", 32, 0, 0, ctypes_ptr32, 0 },
{ "hint", 80, 0, 0, ctypes_ptr32, 0 },
{ "letter_space", 60, 0, 0, ctypes_i32, 0 },
{ "line_space", 56, 0, 0, ctypes_i32, 0 },
{ "ofs_x", 64, 0, 0, ctypes_i32, 0 },
{ "ofs_y", 68, 0, 0, ctypes_i32, 0 },
{ "opa", 72, 0, 0, ctypes_u8, 0 },
{ "sel_bg_color", 50, 0, 0, ctypes_u24, 1 },
{ "sel_color", 47, 0, 0, ctypes_u24, 1 },
{ "sel_end", 40, 0, 0, ctypes_u32, 0 },
{ "sel_start", 36, 0, 0, ctypes_u32, 0 },
{ "decor", 92, 0, 3, ctypes_bf, 0 },
{ "flag", 92, 3, 5, ctypes_bf, 0 },
{ "font", 40, 0, 0, ctypes_ptr32, 0 },
{ "has_bided", 93, 5, 1, ctypes_bf, 0 },
{ "hint", 96, 0, 0, ctypes_ptr32, 0 },
{ "letter_space", 52, 0, 0, ctypes_i32, 0 },
{ "line_space", 48, 0, 0, ctypes_i32, 0 },
{ "ofs_x", 56, 0, 0, ctypes_i32, 0 },
{ "ofs_y", 60, 0, 0, ctypes_i32, 0 },
{ "opa", 88, 0, 0, ctypes_u8, 0 },
{ "outline_stroke_color", 101, 0, 0, ctypes_u24, 1 },
{ "outline_stroke_opa", 100, 0, 0, ctypes_u8, 0 },
{ "outline_stroke_width", 104, 0, 0, ctypes_i32, 0 },
{ "rotation", 64, 0, 0, ctypes_i32, 0 },
{ "sel_bg_color", 79, 0, 0, ctypes_u24, 1 },
{ "sel_color", 76, 0, 0, ctypes_u24, 1 },
{ "sel_end", 72, 0, 0, ctypes_u32, 0 },
{ "sel_start", 68, 0, 0, ctypes_u32, 0 },
{ "text", 28, 0, 0, ctypes_ptr32, 0 },
{ "text_local", 76, 6, 1, ctypes_bf, 0 },
{ "text_length", 84, 0, 0, ctypes_u32, 0 },
{ "text_local", 93, 3, 1, ctypes_bf, 0 },
{ "text_size_x", 32, 0, 0, ctypes_i32, 0 },
{ "text_size_y", 36, 0, 0, ctypes_i32, 0 },
{ "text_static", 93, 4, 1, ctypes_bf, 0 },
}};
const be_ctypes_structure_t be_lv_chart_series = {
@ -334,10 +352,10 @@ const be_ctypes_structure_t be_lv_event = {
}};
const be_ctypes_structure_t be_lv_image_dsc = {
24, /* size in bytes */
10, /* number of elements */
28, /* size in bytes */
11, /* number of elements */
be_ctypes_instance_mappings,
(const be_ctypes_structure_item_t[10]) {
(const be_ctypes_structure_item_t[11]) {
{ "data", 16, 0, 0, ctypes_ptr32, 0 },
{ "data_size", 12, 0, 0, ctypes_u32, 0 },
{ "header_cf", 1, 0, 0, ctypes_u8, 0 },
@ -348,6 +366,7 @@ const be_ctypes_structure_t be_lv_image_dsc = {
{ "header_stride", 8, 0, 0, ctypes_u16, 0 },
{ "header_w", 4, 0, 0, ctypes_u16, 0 },
{ "reserved", 20, 0, 0, ctypes_ptr32, 0 },
{ "reserved_2", 24, 0, 0, ctypes_ptr32, 0 },
}};
const be_ctypes_structure_t be_lv_style_transition_dsc = {
@ -363,10 +382,10 @@ const be_ctypes_structure_t be_lv_style_transition_dsc = {
}};
const be_ctypes_structure_t be_lv_layer = {
72, /* size in bytes */
18, /* number of elements */
84, /* size in bytes */
21, /* number of elements */
be_ctypes_instance_mappings,
(const be_ctypes_structure_item_t[18]) {
(const be_ctypes_structure_item_t[21]) {
{ "_clip_area_x1", 24, 0, 0, ctypes_i32, 0 },
{ "_clip_area_x2", 32, 0, 0, ctypes_i32, 0 },
{ "_clip_area_y1", 28, 0, 0, ctypes_i32, 0 },
@ -377,14 +396,17 @@ const be_ctypes_structure_t be_lv_layer = {
{ "buf_area_y2", 16, 0, 0, ctypes_i32, 0 },
{ "color_format", 20, 0, 0, ctypes_u32, 0 },
{ "draw_buf", 0, 0, 0, ctypes_ptr32, 0 },
{ "draw_task_head", 56, 0, 0, ctypes_ptr32, 0 },
{ "next", 64, 0, 0, ctypes_ptr32, 0 },
{ "parent", 60, 0, 0, ctypes_ptr32, 0 },
{ "draw_task_head", 68, 0, 0, ctypes_ptr32, 0 },
{ "next", 76, 0, 0, ctypes_ptr32, 0 },
{ "opa", 56, 0, 0, ctypes_u8, 0 },
{ "parent", 72, 0, 0, ctypes_ptr32, 0 },
{ "partial_y_offset", 64, 0, 0, ctypes_i32, 0 },
{ "phy_clip_area_x1", 40, 0, 0, ctypes_i32, 0 },
{ "phy_clip_area_x2", 48, 0, 0, ctypes_i32, 0 },
{ "phy_clip_area_y1", 44, 0, 0, ctypes_i32, 0 },
{ "phy_clip_area_y2", 52, 0, 0, ctypes_i32, 0 },
{ "user_data", 68, 0, 0, ctypes_ptr32, 0 },
{ "recolor", 60, 0, 0, ctypes_u32, 0 },
{ "user_data", 80, 0, 0, ctypes_ptr32, 0 },
}};
const be_ctypes_structure_t be_lv_color_filter_dsc = {
@ -432,6 +454,68 @@ const be_ctypes_structure_t be_lv_ts_calibration = {
{ "y", 12, 0, 0, ctypes_i32, 0 },
}};
const be_ctypes_structure_t be_lv_span_coords = {
48, /* size in bytes */
12, /* number of elements */
be_ctypes_instance_mappings,
(const be_ctypes_structure_item_t[12]) {
{ "heading_x1", 0, 0, 0, ctypes_i32, 0 },
{ "heading_x2", 8, 0, 0, ctypes_i32, 0 },
{ "heading_y1", 4, 0, 0, ctypes_i32, 0 },
{ "heading_y2", 12, 0, 0, ctypes_i32, 0 },
{ "middle_x1", 16, 0, 0, ctypes_i32, 0 },
{ "middle_x2", 24, 0, 0, ctypes_i32, 0 },
{ "middle_y1", 20, 0, 0, ctypes_i32, 0 },
{ "middle_y2", 28, 0, 0, ctypes_i32, 0 },
{ "trailing_x1", 32, 0, 0, ctypes_i32, 0 },
{ "trailing_x2", 40, 0, 0, ctypes_i32, 0 },
{ "trailing_y1", 36, 0, 0, ctypes_i32, 0 },
{ "trailing_y2", 44, 0, 0, ctypes_i32, 0 },
}};
const be_ctypes_structure_t be_lv_font_info = {
24, /* size in bytes */
6, /* number of elements */
be_ctypes_instance_mappings,
(const be_ctypes_structure_item_t[6]) {
{ "class_p", 4, 0, 0, ctypes_ptr32, 0 },
{ "kerning", 20, 0, 0, ctypes_u32, 0 },
{ "name", 0, 0, 0, ctypes_ptr32, 0 },
{ "render_mode", 12, 0, 0, ctypes_u32, 0 },
{ "size", 8, 0, 0, ctypes_u32, 0 },
{ "style", 16, 0, 0, ctypes_u32, 0 },
}};
const be_ctypes_structure_t be_lv_draw_letter_dsc = {
80, /* size in bytes */
23, /* number of elements */
be_ctypes_instance_mappings,
(const be_ctypes_structure_item_t[23]) {
{ "base_dsc_size", 20, 0, 0, ctypes_u32, 0 },
{ "base_id1", 8, 0, 0, ctypes_u32, 0 },
{ "base_id2", 12, 0, 0, ctypes_u32, 0 },
{ "base_layer", 16, 0, 0, ctypes_ptr32, 0 },
{ "base_obj", 0, 0, 0, ctypes_ptr32, 0 },
{ "base_part", 4, 0, 0, ctypes_u32, 0 },
{ "base_user_data", 24, 0, 0, ctypes_ptr32, 0 },
{ "blend_mode", 69, 3, 3, ctypes_bf, 0 },
{ "color", 36, 0, 0, ctypes_u24, 1 },
{ "decor", 69, 0, 3, ctypes_bf, 0 },
{ "font", 32, 0, 0, ctypes_ptr32, 0 },
{ "opa", 68, 0, 0, ctypes_u8, 0 },
{ "outline_stroke_color", 76, 0, 0, ctypes_u24, 1 },
{ "outline_stroke_opa", 70, 0, 0, ctypes_u8, 0 },
{ "outline_stroke_width", 72, 0, 0, ctypes_i32, 0 },
{ "pivot_x", 60, 0, 0, ctypes_i32, 0 },
{ "pivot_y", 64, 0, 0, ctypes_i32, 0 },
{ "rotation", 40, 0, 0, ctypes_i32, 0 },
{ "scale_x", 44, 0, 0, ctypes_i32, 0 },
{ "scale_y", 48, 0, 0, ctypes_i32, 0 },
{ "skew_x", 52, 0, 0, ctypes_i32, 0 },
{ "skew_y", 56, 0, 0, ctypes_i32, 0 },
{ "unicode", 28, 0, 0, ctypes_u32, 0 },
}};
static const char * be_ctypes_instance_mappings[] = {
"lv.color",
NULL
@ -445,11 +529,14 @@ static be_define_ctypes_class(lv_draw_arc_dsc, &be_lv_draw_arc_dsc, &be_class_ct
static be_define_ctypes_class(lv_draw_dsc_base, &be_lv_draw_dsc_base, &be_class_ctypes_bytes, "lv_draw_dsc_base");
static be_define_ctypes_class(lv_draw_image_dsc, &be_lv_draw_image_dsc, &be_class_ctypes_bytes, "lv_draw_image_dsc");
static be_define_ctypes_class(lv_draw_label_dsc, &be_lv_draw_label_dsc, &be_class_ctypes_bytes, "lv_draw_label_dsc");
static be_define_ctypes_class(lv_draw_letter_dsc, &be_lv_draw_letter_dsc, &be_class_ctypes_bytes, "lv_draw_letter_dsc");
static be_define_ctypes_class(lv_draw_line_dsc, &be_lv_draw_line_dsc, &be_class_ctypes_bytes, "lv_draw_line_dsc");
static be_define_ctypes_class(lv_draw_rect_dsc, &be_lv_draw_rect_dsc, &be_class_ctypes_bytes, "lv_draw_rect_dsc");
static be_define_ctypes_class(lv_event, &be_lv_event, &be_class_ctypes_bytes, "lv_event");
static be_define_ctypes_class(lv_event_dsc, &be_lv_event_dsc, &be_class_ctypes_bytes, "lv_event_dsc");
static be_define_ctypes_class(lv_font_info, &be_lv_font_info, &be_class_ctypes_bytes, "lv_font_info");
static be_define_ctypes_class(lv_grad_dsc, &be_lv_grad_dsc, &be_class_ctypes_bytes, "lv_grad_dsc");
static be_define_ctypes_class(lv_grad_stop, &be_lv_grad_stop, &be_class_ctypes_bytes, "lv_grad_stop");
static be_define_ctypes_class(lv_gradient_stop, &be_lv_gradient_stop, &be_class_ctypes_bytes, "lv_gradient_stop");
static be_define_ctypes_class(lv_image_dsc, &be_lv_image_dsc, &be_class_ctypes_bytes, "lv_image_dsc");
static be_define_ctypes_class(lv_image_header, &be_lv_image_header, &be_class_ctypes_bytes, "lv_image_header");
@ -457,6 +544,7 @@ static be_define_ctypes_class(lv_layer, &be_lv_layer, &be_class_ctypes_bytes, "l
static be_define_ctypes_class(lv_obj_class, &be_lv_obj_class, &be_class_ctypes_bytes, "lv_obj_class");
static be_define_ctypes_class(lv_point, &be_lv_point, &be_class_ctypes_bytes, "lv_point");
static be_define_ctypes_class(lv_point_precise, &be_lv_point_precise, &be_class_ctypes_bytes, "lv_point_precise");
static be_define_ctypes_class(lv_span_coords, &be_lv_span_coords, &be_class_ctypes_bytes, "lv_span_coords");
static be_define_ctypes_class(lv_style_transition_dsc, &be_lv_style_transition_dsc, &be_class_ctypes_bytes, "lv_style_transition_dsc");
static be_define_ctypes_class(lv_timer_ntv, &be_lv_timer_ntv, &be_class_ctypes_bytes, "lv_timer_ntv");
static be_define_ctypes_class(lv_ts_calibration, &be_lv_ts_calibration, &be_class_ctypes_bytes, "lv_ts_calibration");
@ -470,11 +558,14 @@ be_ctypes_class_by_name_t be_ctypes_lvgl_classes[] = {
{ "lv_draw_dsc_base", &be_class_lv_draw_dsc_base },
{ "lv_draw_image_dsc", &be_class_lv_draw_image_dsc },
{ "lv_draw_label_dsc", &be_class_lv_draw_label_dsc },
{ "lv_draw_letter_dsc", &be_class_lv_draw_letter_dsc },
{ "lv_draw_line_dsc", &be_class_lv_draw_line_dsc },
{ "lv_draw_rect_dsc", &be_class_lv_draw_rect_dsc },
{ "lv_event", &be_class_lv_event },
{ "lv_event_dsc", &be_class_lv_event_dsc },
{ "lv_font_info", &be_class_lv_font_info },
{ "lv_grad_dsc", &be_class_lv_grad_dsc },
{ "lv_grad_stop", &be_class_lv_grad_stop },
{ "lv_gradient_stop", &be_class_lv_gradient_stop },
{ "lv_image_dsc", &be_class_lv_image_dsc },
{ "lv_image_header", &be_class_lv_image_header },
@ -482,6 +573,7 @@ be_ctypes_class_by_name_t be_ctypes_lvgl_classes[] = {
{ "lv_obj_class", &be_class_lv_obj_class },
{ "lv_point", &be_class_lv_point },
{ "lv_point_precise", &be_class_lv_point_precise },
{ "lv_span_coords", &be_class_lv_span_coords },
{ "lv_style_transition_dsc", &be_class_lv_style_transition_dsc },
{ "lv_timer_ntv", &be_class_lv_timer_ntv },
{ "lv_ts_calibration", &be_class_lv_ts_calibration },

View File

@ -18,6 +18,7 @@ ct.print_types()
lv_style_int = ct.i16
lv_color = [ct.u24, "lv.color"] # cast to the class instance, constructor is called with 2 args: (nil, value)
lv_color32 = ct.u32
lv_grad_dir = ct.u8
lv_meter_indicator_type_t = ct.u8
lv_opa = ct.u8
@ -51,7 +52,7 @@ int32_t = ct.i32
size_t = ct.u32
ptr = ct.ptr32
lv_point = [ # valid LVGL92
lv_point = [ # valid LVGL93
[int32_t, "x"],
[int32_t, "y"],
]
@ -61,13 +62,13 @@ lv_point = ct.structure(lv_point, "lv_point")
# lv_value_precise_t x;
# lv_value_precise_t y;
# } lv_point_precise_t;
lv_point_precise = [ # valid LVGL92
lv_point_precise = [ # valid LVGL93
[lv_value_precise, "x"],
[lv_value_precise, "y"],
]
lv_point_precise = ct.structure(lv_point_precise, "lv_point_precise")
lv_area = [ # valid LVGL92
lv_area = [ # valid LVGL93
[int32_t, "x1"],
[int32_t, "y1"],
[int32_t, "x2"],
@ -81,24 +82,49 @@ lv_area = ct.structure(lv_area, "lv_area")
# lv_color_t color; /**< The stop color */
# lv_opa_t opa; /**< The opacity of the color*/
# uint8_t frac; /**< The stop position in 1/255 unit */
# } lv_gradient_stop_t;
lv_gradient_stop = [ # valid LVGL92
# } lv_grad_stop_t;
lv_gradient_stop = [ # valid LVGL93
[lv_color, "color"],
[lv_opa, "opa"],
[uint8_t, "frac"],
]
lv_grad_stop = ct.structure(lv_gradient_stop, "lv_grad_stop")
lv_gradient_stop = ct.structure(lv_gradient_stop, "lv_gradient_stop")
# typedef struct {
# lv_gradient_stop_t stops[LV_GRADIENT_MAX_STOPS]; /**< A gradient stop array */
# uint8_t stops_count; /**< The number of used stops in the array */
# lv_grad_dir_t dir : 3; /**< The gradient direction.
# lv_grad_stop_t stops[LV_GRADIENT_MAX_STOPS]; /**< A gradient stop array */
# uint8_t stops_count; /**< The number of used stops in the array */
# lv_grad_dir_t dir : 4; /**< The gradient direction.
# * Any of LV_GRAD_DIR_NONE, LV_GRAD_DIR_VER, LV_GRAD_DIR_HOR,
# * LV_GRAD_TYPE_LINEAR, LV_GRAD_TYPE_RADIAL, LV_GRAD_TYPE_CONICAL */
# lv_grad_extend_t extend : 2; /**< Behaviour outside the defined range.
# * Any of LV_GRAD_DIR_HOR, LV_GRAD_DIR_VER, LV_GRAD_DIR_NONE */
# lv_grad_extend_t extend : 3; /**< Behaviour outside the defined range.
# * LV_GRAD_EXTEND_NONE, LV_GRAD_EXTEND_PAD, LV_GRAD_EXTEND_REPEAT, LV_GRAD_EXTEND_REFLECT */
# #if LV_USE_DRAW_SW_COMPLEX_GRADIENTS
# union {
# /*Linear gradient parameters*/
# struct {
# lv_point_t start; /**< Linear gradient vector start point */
# lv_point_t end; /**< Linear gradient vector end point */
# } linear;
# /*Radial gradient parameters*/
# struct {
# lv_point_t focal; /**< Center of the focal (starting) circle in local coordinates */
# /* (can be the same as the ending circle to create concentric circles) */
# lv_point_t focal_extent; /**< Point on the circle (can be the same as the center) */
# lv_point_t end; /**< Center of the ending circle in local coordinates */
# lv_point_t end_extent; /**< Point on the circle determining the radius of the gradient */
# } radial;
# /*Conical gradient parameters*/
# struct {
# lv_point_t center; /**< Conical gradient center point */
# int16_t start_angle; /**< Start angle 0..3600 */
# int16_t end_angle; /**< End angle 0..3600 */
# } conical;
# } params;
# void * state;
# #endif
# } lv_grad_dsc_t;
lv_grad_dsc = [ # valid LVGL92
lv_grad_dsc = [ # valid LVGL93
# since it's an array and not two structures, we need to explicitly unroll it here or the alignment is wrong
# [lv_gradient_stop, "stops_0"],
[lv_color, "stops_0_color"],
@ -110,22 +136,35 @@ lv_grad_dsc = [ # valid LVGL92
[uint8_t, "stops_1_frac"],
[uint8_t, "stops_count"],
[uint8_t_3, "dir"],
[uint8_t_2, "extend"],
[uint8_t_4, "dir"],
[uint8_t_3, "extend"],
]
lv_grad_dsc = ct.structure(lv_grad_dsc, "lv_grad_dsc")
# typedef struct {
# /**The widget for which draw descriptor was created */
# lv_obj_t * obj;
# uint32_t part;
# /**The widget part for which draw descriptor was created */
# lv_part_t part;
# /**A widget type specific ID (e.g. table row index). See the docs of the given widget.*/
# uint32_t id1;
# /**A widget type specific ID (e.g. table column index). See the docs of the given widget.*/
# uint32_t id2;
# /**The target layer */
# lv_layer_t * layer;
# /**Size of the specific draw descriptor into which this base descriptor is embedded*/
# size_t dsc_size;
# /**Any custom user data*/
# void * user_data;
# } lv_draw_dsc_base_t;
lv_draw_dsc_base = [ # valid LVGL92
lv_draw_dsc_base = [ # valid LVGL93
[ptr, "obj"],
[uint32_t, "part"],
[uint32_t, "id1"],
@ -175,7 +214,7 @@ lv_draw_dsc_base = ct.structure(lv_draw_dsc_base, "lv_draw_dsc_base")
# int32_t shadow_spread;
# lv_opa_t shadow_opa;
# } lv_draw_rect_dsc_t;
lv_draw_rect_dsc = [ # valid LVGL92
lv_draw_rect_dsc = [ # valid LVGL93
[lv_draw_dsc_base, "base"],
[int32_t, "radius"],
@ -219,19 +258,38 @@ lv_draw_rect_dsc = ct.structure(lv_draw_rect_dsc, "lv_draw_rect_dsc")
# typedef struct {
# lv_draw_dsc_base_t base;
# /**The first point of the line. If `LV_USE_FLOAT` is enabled float number can be also used*/
# lv_point_precise_t p1;
# /**The second point of the line. If `LV_USE_FLOAT` is enabled float number can be also used*/
# lv_point_precise_t p2;
# /**The color of the line*/
# lv_color_t color;
# /**The width (thickness) of the line*/
# int32_t width;
# /** The length of a dash (0: don't dash)*/
# int32_t dash_width;
# /** The length of the gaps between dashes (0: don't dash)*/
# int32_t dash_gap;
# /**Opacity of the line in 0...255 range.
# * LV_OPA_TRANSP, LV_OPA_10, LV_OPA_20, .. LV_OPA_COVER can be used as well*/
# lv_opa_t opa;
# lv_blend_mode_t blend_mode : 2;
# /**Make the line start rounded*/
# uint8_t round_start : 1;
# /**Make the line end rounded*/
# uint8_t round_end : 1;
# uint8_t raw_end : 1; /*Do not bother with perpendicular line ending if it's not visible for any reason*/
# /**1: Do not bother with line ending (if it's not visible for any reason) */
# uint8_t raw_end : 1;
# } lv_draw_line_dsc_t;
lv_draw_line_dsc = [ # valid LVGL92
lv_draw_line_dsc = [ # valid LVGL93
[lv_draw_dsc_base, "base"],
[lv_point_precise, "p1"],
@ -241,7 +299,6 @@ lv_draw_line_dsc = [ # valid LVGL92
[int32_t, "dash_width"],
[int32_t, "dash_gap"],
[lv_opa, "opa"],
[uint8_t_2, "blend_mode"],
[uint8_t_1, "round_start"],
[uint8_t_1, "round_end"],
[uint8_t_1, "raw_end"],
@ -251,17 +308,36 @@ lv_draw_line_dsc = ct.structure(lv_draw_line_dsc, "lv_draw_line_dsc")
# typedef struct {
# lv_draw_dsc_base_t base;
# /**The color of the arc*/
# lv_color_t color;
# /**The width (thickness) of the arc */
# int32_t width;
# /**The start angle in 1 degree units (if `LV_USE_FLOAT` is enabled a float number can be also used)
# * 0° is the 3 o'clock position, 90° is the 6 o'clock, etc. */
# lv_value_precise_t start_angle;
# /**The end angle, similarly to start_angle. */
# lv_value_precise_t end_angle;
# /**The center point of the arc. */
# lv_point_t center;
# /**The outer radius of the arc*/
# uint16_t radius;
# /**An image source to be used instead of `color`. `NULL` if unused*/
# const void * img_src;
# /**Opacity of the arc in 0...255 range.
# * LV_OPA_TRANSP, LV_OPA_10, LV_OPA_20, .. LV_OPA_COVER can be used as well*/
# lv_opa_t opa;
# /**1: Make the arc ends rounded*/
# uint8_t rounded : 1;
# } lv_draw_arc_dsc_t;
lv_draw_arc_dsc = [ # valid LVGL92
lv_draw_arc_dsc = [ # valid LVGL93
[lv_draw_dsc_base, "base"],
[lv_color, "color"],
@ -278,16 +354,16 @@ lv_draw_arc_dsc = ct.structure(lv_draw_arc_dsc, "lv_draw_arc_dsc")
# typedef struct {
# uint32_t magic: 8; /*Magic number. Must be LV_IMAGE_HEADER_MAGIC*/
# uint32_t cf : 8; /*Color format: See `lv_color_format_t`*/
# uint32_t flags: 16; /*Image flags, see `lv_image_flags_t`*/
# uint32_t magic: 8; /**< Magic number. Must be LV_IMAGE_HEADER_MAGIC*/
# uint32_t cf : 8; /**< Color format: See `lv_color_format_t`*/
# uint32_t flags: 16; /**< Image flags, see `lv_image_flags_t`*/
# uint32_t w: 16;
# uint32_t h: 16;
# uint32_t stride: 16; /*Number of bytes in a row*/
# uint32_t reserved_2: 16; /*Reserved to be used later*/
# uint32_t stride: 16; /**< Number of bytes in a row*/
# uint32_t reserved_2: 16; /**< Reserved to be used later*/
# } lv_image_header_t;
lv_image_header = [ # valid LVGL92
lv_image_header = [ # valid LVGL93
[uint8_t, "magic"],
[uint8_t, "cf"],
[uint16_t, "flags"],
@ -299,40 +375,83 @@ lv_image_header = [ # valid LVGL92
]
lv_image_header = ct.structure(lv_image_header, "lv_image_header")
# typedef struct _lv_draw_image_dsc_t {
# struct _lv_draw_image_dsc_t {
# lv_draw_dsc_base_t base;
# /**The image source: pointer to `lv_image_dsc_t` or a path to a file*/
# const void * src;
# /**The header of the image. Initialized internally in `lv_draw_image` */
# lv_image_header_t header;
# /**Clip the corner of the image with this radius. Use `LV_RADIUS_CIRCLE` for max. radius */
# int32_t clip_radius;
# /**The rotation of the image in 0.1 degree unit. E.g. 234 means 23.4° */
# int32_t rotation;
# /**Horizontal scale (zoom) of the image.
# * 256 (LV_SCALE_NONE): means no zoom, 512 double size, 128 half size.*/
# int32_t scale_x;
# /**Same as `scale_y` but vertically*/
# int32_t scale_y;
# /**Parallelogram like transformation of the image horizontally in 0.1 degree unit. E.g. 456 means 45.6°.*/
# int32_t skew_x;
# /**Same as `skew_x` but vertically*/
# int32_t skew_y;
# /**The pivot point of transformation (scale and rotation).
# * 0;0 is the top left corner of the image. Can be outside of the image too.*/
# lv_point_t pivot;
# /**Mix this color to the images. In case of `LV_COLOR_FORMAT_A8` it will be the color of the visible pixels*/
# lv_color_t recolor;
# /**The intensity of recoloring. 0 means, no recolor, 255 means full cover (transparent pixels remain transparent)*/
# lv_opa_t recolor_opa;
# /**Opacity in 0...255 range.
# * LV_OPA_TRANSP, LV_OPA_10, LV_OPA_20, .. LV_OPA_COVER can be used as well*/
# lv_opa_t opa;
# /**Describes how to blend the pixels of the image to the background.
# * See `lv_blend_mode_t` for more details.
# */
# lv_blend_mode_t blend_mode : 4;
# /**1: perform the transformation with anti-alaising */
# uint16_t antialias : 1;
# /**If the image is smaller than the `image_area` field of `lv_draw_image_dsc_t`
# * tile the image (repeat is both horizontally and vertically) to fill the
# * `image_area` area*/
# uint16_t tile : 1;
# /**Used internally to store some information about the palette or the color of A8 images*/
# lv_draw_image_sup_t * sup;
# /** Might be used to indicate the original size of the image if only a small portion is rendered now.
# * Used when a part of a layer is rendered to show the total layer size*/
# lv_area_t original_area;
# /** Used to indicate the entire original, non-clipped area where the image is to be drawn.
# * This is important for:
# * 1. Layer rendering, where it might happen that only a smaller area of the layer is rendered and e.g.
# * `clip_radius` needs to know what the original image was.
# * 2. Tiled images, where the target draw area is larger than the image to be tiled.
# */
# lv_area_t image_area;
# /**Pointer to an A8 or L8 image descriptor to mask the image with.
# * The mask is always center aligned. */
# const lv_image_dsc_t * bitmap_mask_src;
# } lv_draw_image_dsc_t;
lv_draw_image_dsc = [ # valid LVGL92
# };
lv_draw_image_dsc = [ # valid LVGL93
[lv_draw_dsc_base, "base"],
[ptr, "src"],
[lv_image_header, "header"],
[int32_t, "clip_radius"],
[int32_t, "rotation"],
[int32_t, "scale_x"],
[int32_t, "scale_y"],
@ -350,62 +469,126 @@ lv_draw_image_dsc = [ # valid LVGL92
[ptr, "sup"],
[lv_area, "image_area"],
[int32_t, "clip_radius"],
[ptr, "bitmap_mask_src"],
]
lv_draw_image_dsc = ct.structure(lv_draw_image_dsc, "lv_draw_image_dsc")
# typedef struct {
# lv_draw_dsc_base_t base;
# /**The text to draw*/
# const char * text;
# /**The size of the text*/
# lv_point_t text_size;
# /**The font to use. Fallback fonts are also handled.*/
# const lv_font_t * font;
# uint32_t sel_start;
# uint32_t sel_end;
# /**Color of the text*/
# lv_color_t color;
# lv_color_t sel_color;
# lv_color_t sel_bg_color;
# /**Extra space between the lines*/
# int32_t line_space;
# /**Extra space between the characters*/
# int32_t letter_space;
# /**Offset the text with this value horizontally*/
# int32_t ofs_x;
# /**Offset the text with this value vertically*/
# int32_t ofs_y;
# /**Rotation of the letters in 0.1 degree unit*/
# int32_t rotation;
# /**The first characters index for selection (not byte index). `LV_DRAW_LABEL_NO_TXT_SEL` for no selection*/
# uint32_t sel_start;
# /**The last characters's index for selection (not byte index). `LV_DRAW_LABEL_NO_TXT_SEL` for no selection*/
# uint32_t sel_end;
# /**Color of the selected characters*/
# lv_color_t sel_color;
# /**Background color of the selected characters*/
# lv_color_t sel_bg_color;
# /**The number of characters to render. 0: means render until reaching the `\0` termination.*/
# uint32_t text_length;
# /**Opacity of the text in 0...255 range.
# * LV_OPA_TRANSP, LV_OPA_10, LV_OPA_20, .. LV_OPA_COVER can be used as well*/
# lv_opa_t opa;
# lv_base_dir_t bidi_dir;
# /**The alignment of the text `LV_TEXT_ALIGN_LEFT/RIGHT/CENTER`*/
# lv_text_align_t align;
# lv_text_flag_t flag;
# /**The base direction. Used when type setting Right-to-left (e.g. Arabic) texts*/
# lv_base_dir_t bidi_dir;
# /**Text decoration, e.g. underline*/
# lv_text_decor_t decor : 3;
# lv_blend_mode_t blend_mode : 3;
# /**
# * < 1: malloc buffer and copy `text` there.
# * 0: `text` is const and it's pointer will be valid during rendering.*/
# /**Some flags to control type setting*/
# lv_text_flag_t flag : 5;
# /**1: malloc a buffer and copy `text` there.
# * 0: `text` will be valid during rendering.*/
# uint8_t text_local : 1;
# /**Indicate that the text is constant and its pointer can be safely saved e.g. in a cache.*/
# uint8_t text_static : 1;
# /**1: already executed lv_bidi_process_paragraph.
# * 0: has not been executed lv_bidi_process_paragraph.*/
# uint8_t has_bided : 1;
# /**Pointer to an externally stored struct where some data can be cached to speed up rendering*/
# lv_draw_label_hint_t * hint;
# /* Properties of the letter outlines */
# lv_opa_t outline_stroke_opa;
# lv_color_t outline_stroke_color;
# int32_t outline_stroke_width;
# } lv_draw_label_dsc_t;
lv_draw_label_dsc = [ # valid LVGL92
lv_draw_label_dsc = [ # valid LVGL93
[lv_draw_dsc_base, "base"],
[ptr, "text"],
[lv_point, "text_size"],
[ptr, "font"],
[uint32_t, "sel_start"],
[uint32_t, "sel_end"],
[lv_color, "color"],
[lv_color, "sel_color"],
[lv_color, "sel_bg_color"],
[int32_t, "line_space"],
[int32_t, "letter_space"],
[int32_t, "ofs_x"],
[int32_t, "ofs_y"],
[int32_t, "rotation"],
[uint32_t, "sel_start"],
[uint32_t, "sel_end"],
[lv_color, "sel_color"],
[lv_color, "sel_bg_color"],
[uint32_t, "text_length"],
[lv_opa, "opa"],
[lv_base_dir, "bidi_dir"],
[lv_text_align, "align"],
[lv_base_dir, "bidi_dir"],
[lv_text_flag, "flag"],
[uint8_t_3, "decor"],
[uint8_t_5, "flag"],
[uint8_t_3, "blend_mode"],
[uint8_t_1, "text_local"],
[uint8_t_1, "text_static"],
[uint8_t_1, "has_bided"],
[ptr, "hint"],
[lv_opa, "outline_stroke_opa"],
[lv_color, "outline_stroke_color"],
[int32_t, "outline_stroke_width"],
]
lv_draw_label_dsc = ct.structure(lv_draw_label_dsc, "lv_draw_label_dsc")
# typedef struct {
# struct _lv_chart_series_t {
# int32_t * x_points;
# int32_t * y_points;
# lv_color_t color;
@ -415,8 +598,8 @@ lv_draw_label_dsc = ct.structure(lv_draw_label_dsc, "lv_draw_label_dsc")
# uint32_t y_ext_buf_assigned : 1;
# uint32_t x_axis_sec : 1;
# uint32_t y_axis_sec : 1;
# } lv_chart_series_t;
lv_chart_series = [ # valid LVGL92
# };
lv_chart_series = [ # valid LVGL93
[ptr, "x_points"],
[ptr, "y_points"],
[lv_color, "color"],
@ -429,15 +612,15 @@ lv_chart_series = [ # valid LVGL92
]
lv_chart_series = ct.structure(lv_chart_series, "lv_chart_series")
# typedef struct {
# struct _lv_chart_cursor_t {
# lv_point_t pos;
# int32_t point_id;
# lv_color_t color;
# lv_chart_series_t * ser;
# lv_dir_t dir;
# uint32_t pos_set: 1; /*1: pos is set; 0: point_id is set*/
# } lv_chart_cursor_t;
lv_chart_cursor = [ # valid LVGL92
# uint32_t pos_set: 1; /**< 1: pos is set; 0: point_id is set */
# };
lv_chart_cursor = [ # valid LVGL93
[lv_point, "pos"],
[int32_t, "point_id"],
[lv_color, "color"],
@ -457,15 +640,28 @@ event_cb = ptr # callback
lv_event_code = ct.i32
# struct lv_obj_class_t {
# struct _lv_obj_class_t {
# const lv_obj_class_t * base_class;
# /** class_p is the final class while obj->class_p is the class currently being [de]constructed. */
# void (*constructor_cb)(const lv_obj_class_t * class_p, lv_obj_t * obj);
# void (*destructor_cb)(const lv_obj_class_t * class_p, lv_obj_t * obj);
#
# /** class_p is the class in which event is being processed. */
# void (*event_cb)(const lv_obj_class_t * class_p, lv_event_t * e); /**< Widget type specific event function*/
#
# #if LV_USE_OBJ_PROPERTY
# uint32_t prop_index_start;
# uint32_t prop_index_end;
# const lv_property_ops_t * properties;
# uint32_t properties_count;
# #if LV_USE_OBJ_PROPERTY_NAME
# /* An array of property ID and name */
# const lv_property_name_t * property_names;
# uint32_t names_count;
# #endif
# #endif
# void * user_data;
# const char * name;
# int32_t width_def;
@ -475,7 +671,7 @@ lv_event_code = ct.i32
# uint32_t instance_size : 16;
# uint32_t theme_inheritable : 1; /**< Value from ::lv_obj_class_theme_inheritable_t*/
# };
lv_obj_class = [ # valid LVGL92
lv_obj_class = [ # valid LVGL93
[lv_obj_class_ptr, "base_class"],
[constructor_cb, "constructor_cb"],
[destructor_cb, "destructor_cb"],
@ -491,7 +687,7 @@ lv_obj_class = [ # valid LVGL92
]
lv_obj_class = ct.structure(lv_obj_class, "lv_obj_class")
# struct lv_event_t {
# struct _lv_event_t {
# void * current_target;
# void * original_target;
# lv_event_code_t code;
@ -502,7 +698,7 @@ lv_obj_class = ct.structure(lv_obj_class, "lv_obj_class")
# uint8_t stop_processing : 1;
# uint8_t stop_bubbling : 1;
# };
lv_event = [ # valid LVGL92
lv_event = [ # valid LVGL93
[lv_obj_ptr, "current_target"],
[lv_obj_ptr, "original_target"],
[lv_event_code, "code"],
@ -523,12 +719,14 @@ lv_event = ct.structure(lv_event, "lv_event")
# uint32_t data_size; /**< Size of the image in bytes*/
# const uint8_t * data; /**< Pointer to the data of the image*/
# const void * reserved; /**< A reserved field to make it has same size as lv_draw_buf_t*/
# const void * reserved_2; /**< A reserved field to make it has same size as lv_draw_buf_t*/
# } lv_image_dsc_t;
lv_image_dsc = [ # valid LVGL92
lv_image_dsc = [ # valid LVGL93
[lv_image_header, "header"],
[uint32_t, "data_size"],
[ptr, "data"],
[ptr, "reserved"],
[ptr, "reserved_2"],
]
lv_image_dsc = ct.structure(lv_image_dsc, "lv_image_dsc")
@ -538,11 +736,11 @@ lv_image_dsc = ct.structure(lv_image_dsc, "lv_image_dsc")
# typedef struct {
# const lv_style_prop_t * props; /**< An array with the properties to animate.*/
# void * user_data; /**< A custom user data that will be passed to the animation's user_data */
# lv_anim_path_cb_t path_xcb; /**< A path for the animation.*/
# lv_anim_path_cb_t path_xcb; /**< A path for the animation.*/
# uint32_t time; /**< Duration of the transition in [ms]*/
# uint32_t delay; /**< Delay before the transition in [ms]*/
# } lv_style_transition_dsc_t;
lv_style_transition_dsc = [ # valid LVGL92
lv_style_transition_dsc = [ # valid LVGL93
[ptr, "props"],
[ptr, "user_data"],
[ptr, "path_xcb"],
@ -552,17 +750,17 @@ lv_style_transition_dsc = [ # valid LVGL92
lv_style_transition_dsc = ct.structure(lv_style_transition_dsc, "lv_style_transition_dsc")
# struct lv_layer_t {
#
# struct _lv_layer_t {
# /** Target draw buffer of the layer*/
# lv_draw_buf_t * draw_buf;
#
# /** The absolute coordinates of the buffer */
# lv_area_t buf_area;
#
# /** The color format of the layer. LV_COLOR_FORMAT_... */
# lv_color_format_t color_format;
#
# /**
# * NEVER USE IT DRAW UNITS. USED INTERNALLY DURING DRAW TASK CREATION.
# * The current clip area with absolute coordinates, always the same or smaller than `buf_area`
@ -572,31 +770,43 @@ lv_style_transition_dsc = ct.structure(lv_style_transition_dsc, "lv_style_transi
# * During drawing the layer's clip area shouldn't be used as it might be already changed for other draw tasks.
# */
# lv_area_t _clip_area;
#
# /**
# * The physical clipping area relative to the display.
# */
# lv_area_t phy_clip_area;
#
# #if LV_DRAW_TRANSFORM_USE_MATRIX
# /** Transform matrix to be applied when rendering the layer */
# lv_matrix_t matrix;
# #endif
#
# /** Opacity of the layer */
# lv_opa_t opa;
# /*Recolor of the layer*/
# lv_color32_t recolor;
# /** Partial y offset */
# int32_t partial_y_offset;
# /** Linked list of draw tasks */
# lv_draw_task_t * draw_task_head;
#
# lv_layer_t * parent;
# lv_layer_t * next;
# bool all_tasks_added;
# void * user_data;
# };
lv_layer = [ # valid LVGL92
lv_layer = [ # valid LVGL93
[ptr, "draw_buf"],
[lv_area, "buf_area"],
[uint32_t, "color_format"],
[lv_area, "_clip_area"],
[lv_area, "phy_clip_area"],
[lv_opa, "opa"],
[lv_color32, "recolor"],
[int32_t, "partial_y_offset"],
[ptr, "draw_task_head"],
[ptr, "parent"],
[ptr, "next"],
@ -608,11 +818,11 @@ lv_layer = ct.structure(lv_layer, "lv_layer")
#######################################################################
# lv_color
# typedef struct _lv_color_filter_dsc_t {
# struct _lv_color_filter_dsc_t {
# lv_color_filter_cb_t filter_cb;
# void * user_data;
# } lv_color_filter_dsc_t;
lv_color_filter_dsc = [ # valid LVGL92
# };
lv_color_filter_dsc = [ # valid LVGL93
[ptr, "filter_cb"],
[ptr, "user_data"],
]
@ -621,7 +831,7 @@ lv_color_filter_dsc = ct.structure(lv_color_filter_dsc, "lv_color_filter_dsc")
#######################################################################
# lv_timer native, superseded by lv_timer
# struct lv_timer_t {
# struct _lv_timer_t {
# uint32_t period; /**< How often the timer should run */
# uint32_t last_run; /**< Last time the timer ran */
# lv_timer_cb_t timer_cb; /**< Timer function */
@ -630,7 +840,7 @@ lv_color_filter_dsc = ct.structure(lv_color_filter_dsc, "lv_color_filter_dsc")
# uint32_t paused : 1;
# uint32_t auto_delete : 1;
# };
lv_timer_ntv = [ # valid LVGL92
lv_timer_ntv = [ # valid LVGL93
[uint32_t, "period"],
[uint32_t, "last_run"],
[ptr, "timer_cb"],
@ -644,12 +854,12 @@ lv_timer_ntv = ct.structure(lv_timer_ntv, "lv_timer_ntv")
#######################################################################
# lv_event_dsc
# typedef struct {
# struct _lv_event_dsc_t {
# lv_event_cb_t cb;
# void * user_data;
# uint32_t filter;
# } lv_event_dsc_t;
lv_event_dsc = [ # valid LVGL92
# };
lv_event_dsc = [ # valid LVGL93
[ptr, "cb"],
[ptr, "user_data"],
[uint32_t, "filter"],
@ -659,7 +869,7 @@ lv_event_dsc = ct.structure(lv_event_dsc, "lv_event_dsc")
#######################################################################
# Special structure used to calibrate resistive touchscreens
#######################################################################
lv_ts_calibration = [ # valid LVGL91
lv_ts_calibration = [ # valid LVGL93
[lv_coord_t, "raw_x"],
[lv_coord_t, "raw_y"],
[lv_coord_t, "x"],
@ -668,5 +878,91 @@ lv_ts_calibration = [ # valid LVGL91
]
lv_ts_calibration = ct.structure(lv_ts_calibration, "lv_ts_calibration")
#######################################################################
# New in LVGL 9.3.0
#######################################################################
# /** Coords of a span */
# typedef struct _lv_span_coords_t {
# lv_area_t heading;
# lv_area_t middle;
# lv_area_t trailing;
# } lv_span_coords_t;
lv_span_coords = [
[lv_area, "heading"],
[lv_area, "middle"],
[lv_area, "trailing"],
]
lv_span_coords = ct.structure(lv_span_coords, "lv_span_coords")
#######################################################################
# lv_font_info
# struct _lv_font_info_t {
# const char * name; /**< Font name, used to distinguish different font resources*/
# const lv_font_class_t * class_p; /**< Font backend implementation*/
# uint32_t size; /**< Font size in pixel*/
# uint32_t render_mode; /**< Font rendering mode, see `lv_freetype_font_render_mode_t`*/
# uint32_t style; /**< Font style, see `lv_freetype_font_style_t`*/
# lv_font_kerning_t kerning; /**< Font kerning, see `lv_font_kerning_t`*/
# };
lv_font_info = [ # valid LVGL92
[ptr, "name"],
[ptr, "class_p"],
[uint32_t, "size"],
[uint32_t, "render_mode"],
[uint32_t, "style"],
[uint32_t, "kerning"],
]
lv_font_info = ct.structure(lv_font_info, "lv_font_info")
#######################################################################
# lv_draw_letter
# typedef struct {
# lv_draw_dsc_base_t base;
# uint32_t unicode;
# const lv_font_t * font;
# lv_color_t color;
# int32_t rotation;
# int32_t scale_x;
# int32_t scale_y;
# int32_t skew_x;
# int32_t skew_y;
# lv_point_t pivot;
# lv_opa_t opa;
# lv_text_decor_t decor : 3;
# lv_blend_mode_t blend_mode : 3;
# /* Properties of the letter outlines */
# lv_opa_t outline_stroke_opa;
# int32_t outline_stroke_width;
# lv_color_t outline_stroke_color;
# } lv_draw_letter_dsc_t;
lv_draw_letter_dsc = [ # valid LVGL93
[lv_draw_dsc_base, "base"],
[uint32_t, "unicode"],
[ptr, "font"],
[lv_color, "color"],
[int32_t, "rotation"],
[int32_t, "scale_x"],
[int32_t, "scale_y"],
[int32_t, "skew_x"],
[int32_t, "skew_y"],
[lv_point, "pivot"],
[lv_opa, "opa"],
[uint8_t_3, "decor"],
[uint8_t_3, "blend_mode"],
[lv_opa, "outline_stroke_opa"],
[int32_t, "outline_stroke_width"],
[lv_color, "outline_stroke_color"],
]
lv_draw_letter_dsc = ct.structure(lv_draw_letter_dsc, "lv_draw_letter_dsc")
#
ct.print_classes("lvgl")

View File

@ -431,8 +431,9 @@ class type_mapper_class:
"lv_point_precise_t *": "lv_point_precise",
"lv_draw_image_dsc_t *": "lv_draw_image_dsc",
"lv_event_dsc_t *": "lv_event_dsc",
"lv_span_coords_t": "lv_span_coords",
# "_lv_obj_t *": "lv_obj", // no more used in LVGL 9.2
"_lv_obj_t *": "lv_obj",
"lv_obj_t *": "lv_obj",
"lv_event_t *": "lv_event",
"lv_color_t": "lv_color",
@ -441,7 +442,7 @@ class type_mapper_class:
"lv_font_t *": "lv_font",
"lv_theme_t *": "lv_theme",
"lv_display_t *": "lv_display",
# '_lv_display_t *': "lv_display", // no more used in LVGL 9.2
'_lv_display_t *': "lv_display",
"lv_indev_t *": "lv_indev",
"lv_point_t []": "lv_point_arr",
"lv_span_t *": "lv_span",
@ -461,6 +462,12 @@ class type_mapper_class:
"constchar **": "c", # treat as a simple pointer, decoding needs to be done at Berry level
"void * []": "c", # treat as a simple pointer, decoding needs to be done at Berry level
"constchar * *": "c",
# new in 9.3.0
"lv_text_cmd_state_t *": "c",
"lv_font_info_t *": "lv_font_info",
"lv_switch_orientation_t": "i",
"lv_slider_orientation_t": "i",
"lv_draw_letter_dsc_t *": "lv_draw_letter_dsc",
# callbacks
"lv_group_focus_cb_t": "lv_group_focus_cb",

View File

@ -1,105 +1,265 @@
#!/usr/bin/env python3
"""
LVGL Header Preprocessor
Extracts function signatures and enums from LVGL header files.
Generates mapping files for Berry scripting integration.
"""
import re
import sys
import glob
import argparse
from pathlib import Path
from typing import List, Set, Tuple, Optional
import logging
# https://stackoverflow.com/a/241506
def comment_remover(text):
def replacer(match):
s = match.group(0)
if s.startswith('/'):
return " " # note: a space and not an empty string
else:
return s
pattern = re.compile(
r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"',
re.DOTALL | re.MULTILINE
)
return re.sub(pattern, replacer, text)
# Configure logging
logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s')
logger = logging.getLogger(__name__)
# compute a sorted list of files from a prefix and a list of glob patterns
def list_files(prefix, glob_list):
r = []
for g in glob_list:
r += glob.glob(prefix + g, recursive=True)
return sorted(r)
def clean_source(raw):
raw = comment_remover(raw) # remove comments
# convert cr/lf or cr to lf
raw = re.sub(r'\r\n ', '\n', raw)
raw = re.sub(r'\r', '\n', raw)
# group multilines into a single line, i.e. if line ends with '\', put in a single line
raw = re.sub(r'\\\n', ' ', raw)
# remove preprocessor directives
raw = re.sub(r'\n[ \t]*#[^\n]*(?=\n)', '', raw)
raw = re.sub(r'^[ \t]*#[^\n]*\n', '', raw)
raw = re.sub(r'\n[ \t]*#[^\n]*$', '', raw)
class LVGLPreprocessor:
"""Main preprocessor class for LVGL headers."""
def __init__(self, lv_src_prefix: str = "../../lvgl/src/"):
self.lv_src_prefix = Path(lv_src_prefix)
self.headers_exclude_suffix = {
"_private.h",
"lv_lottie.h",
"lv_obj_property.h",
"lv_obj_property_names.h",
"lv_style_properties.h",
"lv_3dtexture.h",
}
# Function exclusion patterns
self.function_exclude_patterns = [
r"^_", # skip if function name starts with '_'
r"^lv_debug", # all debug functions
r"^lv_init", r"^lv_deinit",
r"^lv_templ_",
r"^lv_imagebutton_get_src_", # LV_IMGBTN_TILED == 0
r"^lv_imagebitton_set_src_tiled", # !LV_IMGBTN_TILED
r"^lv_refr_get_fps_", # no LV_USE_PERF_MONITOR
r"^lv_image_cache_",
r"^lv_image_decoder_",
r"^lv_image_cf_",
r"^lv_image_buf_",
r"^lv_indev_scroll_",
r"^lv_pow",
r"^lv_keyboard_def_event_cb", # need to fix conditional include
r"^lv_refr_reset_fps_counter",
r"^lv_refr_get_fps_avg",
r"^lv_anim_path_", # callbacks for animation are moved to constants
r"^lv_obj_set_property", # LV_USE_OBJ_PROPERTY 0
r"^lv_obj_set_properties",
r"^lv_obj_get_property",
r"^lv_win_",
r"^lv_obj.*name", # we don't enable #if LV_USE_OBJ_NAME
]
# Enum exclusion patterns
self.enum_exclude_prefixes = {
"_", "LV_BIDI_DIR_", "LV_FONT_", "LV_SIGNAL_", "LV_TEMPL_",
"LV_TASK_PRIO_", "LV_THEME_", "LV_LRU_", "LV_VECTOR_",
"LV_KEYBOARD_MODE_TEXT_ARABIC", "LV_DRAW_TASK_TYPE_3D",
"LV_DRAW_TASK_TYPE_VECTOR",
}
# remove extern "C" {}
raw = re.sub(r'extern\s+"C"\s+{(.*)}', '\\1', raw, flags=re.DOTALL)
def comment_remover(self, text: str) -> str:
"""Remove C/C++ style comments from source code."""
def replacer(match):
s = match.group(0)
return " " if s.startswith('/') else s
pattern = re.compile(
r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"',
re.DOTALL | re.MULTILINE
)
return re.sub(pattern, replacer, text)
# remove empty lines
raw = re.sub(r'\n[ \t]*(?=\n)', '', raw)
raw = re.sub(r'^[ \t]*\n', '', raw) # remove first empty line
raw = re.sub(r'\n[ \t]*$', '', raw) # remove last empty line
return raw
def list_files(self, prefix: Path, glob_patterns: List[str]) -> List[Path]:
"""Compute a sorted list of files from a prefix and glob patterns."""
files = []
for pattern in glob_patterns:
files.extend(Path(prefix).glob(pattern))
return sorted(files)
# ################################################################################
# Parse function signatures
# ################################################################################
def clean_source(self, raw: str) -> str:
"""Clean source code by removing comments, preprocessor directives, etc."""
raw = self.comment_remover(raw)
# Normalize line endings
raw = re.sub(r'\r\n', '\n', raw)
raw = re.sub(r'\r', '\n', raw)
# Handle line continuations
raw = re.sub(r'\\\n', ' ', raw)
# Remove preprocessor directives
raw = re.sub(r'\n[ \t]*#[^\n]*(?=\n)', '', raw)
raw = re.sub(r'^[ \t]*#[^\n]*\n', '', raw)
raw = re.sub(r'\n[ \t]*#[^\n]*$', '', raw)
lv_src_prefix = "../../lvgl/src/"
lv_fun_globs = [
"lv_api*.h",
"widgets/*/*.h", # all widgets
"libs/qrcode/lv_qrcode.h",
"core/*.h",
"indev/lv_indev.h",
"layouts/*/*.h",
# "draw/*.h",
"themes/lv_theme.h",
"draw/lv_draw_arc.h",
"draw/lv_draw_label.h",
"draw/lv_draw_line.h",
"draw/lv_draw_mask.h",
"draw/lv_draw_rect.h",
"draw/lv_draw_triangle.h",
# "draw/lv_draw_vector.h",
"draw/lv_draw.h",
"display/*.h",
"misc/lv_anim.h",
"misc/lv_area.h",
"misc/lv_color.h",
"misc/lv_color_op.h",
"misc/lv_palette.h",
"misc/lv_event.h",
"misc/lv_style_gen.h",
"misc/lv_style.h",
"misc/lv_timer.h",
"misc/lv_text.h",
"font/lv_font.h",
# add version information
"../lvgl.h",
]
headers_exlude_suffix = [
"_private.h",
"lv_lottie.h",
"lv_obj_property.h",
"lv_obj_property_names.h",
"lv_style_properties.h",
]
# Remove extern "C" blocks
raw = re.sub(r'extern\s+"C"\s+{(.*)}', r'\1', raw, flags=re.DOTALL)
headers_names = list_files(lv_src_prefix, lv_fun_globs)
headers_names += list_files("../../LVGL_assets/src/", ["lv_theme_haspmota.h"])
headers_names += list_files("../src/", ["lv_berry.h", "lv_colorwheel.h"])
# Remove empty lines
raw = re.sub(r'\n[ \t]*(?=\n)', '', raw)
raw = re.sub(r'^[ \t]*\n', '', raw)
raw = re.sub(r'\n[ \t]*$', '', raw)
return raw
# filter out from headers_exlude_suffix
headers_names = [x for x in headers_names if not any(x.endswith(suffix) for suffix in headers_exlude_suffix)]
def extract_functions(self, source: str) -> List[str]:
"""Extract function signatures from cleaned source code."""
# Remove content within braces
while True:
source, repl_count = re.subn(r'\{[^{]*?\}', ';', source, flags=re.DOTALL)
if repl_count == 0:
break
output_filename = "../mapping/lv_funcs.h"
sys.stdout = open(output_filename, 'w', encoding='utf-8')
# Find function signatures
pattern = r'(^|;|})\s*([^;{}]+\(.*?\))\s*(?=(;|{))'
matches = re.findall(pattern, source, flags=re.DOTALL)
functions = []
for match in matches:
func_def = match[1]
# Clean up whitespace
func_def = re.sub(r'[ \t\r\n]+', ' ', func_def)
# Remove LVGL-specific attributes
func_def = re.sub(r'LV_ATTRIBUTE_FAST_MEM ', '', func_def)
func_def = re.sub(r'LV_ATTRIBUTE_TIMER_HANDLER ', '', func_def)
func_def = re.sub(r'extern ', '', func_def)
# Skip excluded function types
if any(func_def.startswith(prefix) for prefix in ["typedef", "_LV_", "LV_"]):
continue
# Extract function name
name_match = re.search(r'\s(\w+)\([^\(]*$', func_def)
if not name_match:
continue
func_name = name_match.group(1)
# Check exclusion patterns
if any(re.search(pattern, func_name) for pattern in self.function_exclude_patterns):
continue
functions.append(func_def)
return functions
print("""
def extract_enums(self, source: str) -> Set[str]:
"""Extract enum values from cleaned source code."""
enum_values = set()
# Find enum definitions
enum_matches = re.findall(r'enum\s+\w*\s*{(.*?)}', source, flags=re.DOTALL)
for enum_content in enum_matches:
# Skip LV_PROPERTY_ID enums (disabled feature)
if 'LV_PROPERTY_ID' in enum_content:
continue
# Remove macro-defined enums
enum_content = re.sub(r'\S+\((.*?),.*?\),', r'\1,', enum_content)
# Split by commas and clean up
for item in enum_content.split(','):
item = re.sub(r'[ \t\n]', '', item) # Remove whitespace
item = re.sub(r'=.*$', '', item) # Remove assignment
if not item: # Skip empty items
continue
# Check exclusion patterns
if any(item.startswith(prefix) for prefix in self.enum_exclude_prefixes):
continue
enum_values.add(item)
# Extract LV_EXPORT_CONST_INT constants
const_ints = re.findall(r'LV_EXPORT_CONST_INT\((\w+)\)', source, flags=re.DOTALL)
enum_values.update(const_ints)
return enum_values
def get_function_headers(self) -> List[Path]:
"""Get list of header files for function extraction."""
patterns = [
"lv_api*.h",
"widgets/*/*.h",
"libs/qrcode/lv_qrcode.h",
"core/*.h",
"indev/lv_indev.h",
"layouts/*/*.h",
"themes/lv_theme.h",
"draw/lv_draw_arc.h",
"draw/lv_draw_label.h",
"draw/lv_draw_line.h",
"draw/lv_draw_mask.h",
"draw/lv_draw_rect.h",
"draw/lv_draw_triangle.h",
"draw/lv_draw.h",
"display/*.h",
"misc/lv_anim.h",
"misc/lv_area.h",
"misc/lv_color.h",
"misc/lv_color_op.h",
"misc/lv_palette.h",
"misc/lv_event.h",
"misc/lv_style_gen.h",
"misc/lv_style.h",
"misc/lv_timer.h",
"misc/lv_text.h",
"font/lv_font.h",
"../lvgl.h",
]
headers = self.list_files(self.lv_src_prefix, patterns)
# Add additional headers
additional_paths = [
Path("../../LVGL_assets/src/lv_theme_haspmota.h"),
Path("../src/lv_berry.h"),
Path("../src/lv_colorwheel.h"),
]
for path in additional_paths:
if path.exists():
headers.append(path)
# Filter out excluded files
return [h for h in headers if not any(str(h).endswith(suffix) for suffix in self.headers_exclude_suffix)]
def get_enum_headers(self) -> List[Path]:
"""Get list of header files for enum extraction."""
patterns = [
"core/*.h",
"draw/*.h",
"hal/*.h",
"misc/*.h",
"widgets/*/*.h",
"display/lv_display.h",
"layouts/**/*.h",
]
headers = self.list_files(self.lv_src_prefix, patterns)
return [h for h in headers if not any(str(h).endswith(suffix) for suffix in self.headers_exclude_suffix)]
def generate_functions_header(self, output_path: Path):
"""Generate the functions header file."""
logger.info(f"Generating functions header: {output_path}")
headers = self.get_function_headers()
with open(output_path, 'w', encoding='utf-8') as f:
f.write("""
// Automatically generated from LVGL source with `python3 preprocessor.py`
// Extract function signatures from LVGL APIs in headers
@ -119,105 +279,51 @@ lv_coord_t lv_get_ver_res(void);
// ======================================================================
""")
for header_path in headers:
try:
with open(header_path, encoding='utf-8-sig') as header_file:
f.write(f"// {header_path}\n")
raw_content = self.clean_source(header_file.read())
functions = self.extract_functions(raw_content)
for func in functions:
f.write(f"{func}\n")
f.write("\n")
except Exception as e:
logger.error(f"Error processing {header_path}: {e}")
for header_name in headers_names:
with open(header_name, encoding='utf-8-sig') as f:
print("// " + header_name)
raw = clean_source(f.read())
# remove anything in '{' '}'
while True:
(raw, repl) = re.subn(r'\{[^{]*?\}', ';', raw, flags=re.DOTALL) # replace with ';' to make pattern matching still work
if (repl == 0): break # no more replace, stop
raw_f = re.findall(r'(^|;|})\s*([^;{}]+\(.*?\))\s*(?=(;|{))', raw, flags=re.DOTALL)
fun_defs = [ x[1] for x in raw_f]
# remove any CRLF or multi-space
fun_defs = [ re.sub(r'[ \t\r\n]+', ' ', x) for x in fun_defs]
# parse individual
for fun in fun_defs:
# remove LV_ATTRIBUTE_FAST_MEM
fun = re.sub(r'LV_ATTRIBUTE_FAST_MEM ', '', fun)
# remove LV_ATTRIBUTE_TIMER_HANDLER
fun = re.sub(r'LV_ATTRIBUTE_TIMER_HANDLER ', '', fun)
# remove extern
fun = re.sub(r'extern ', '', fun)
exclude = False
for exclude_prefix in ["typedef", "_LV_", "LV_"]:
if fun.startswith(exclude_prefix): exclude = True
if exclude: continue
# extrac the function name
fun_name = re.search(r'\s(\w+)\([^\(]*$', fun)
if fun_name != None:
fun_name = fun_name.group(1) # we now have the function name
def generate_enums_header(self, output_path: Path):
"""Generate the enums header file."""
logger.info(f"Generating enums header: {output_path}")
# exclude specific names
for exclude_pattern in [
"^_", # skip if function name starts with '_'
"^lv_debug", # all debug functions
"^lv_init", "^lv_deinit",
"^lv_templ_",
"^lv_imagebutton_get_src_", # LV_IMGBTN_TILED == 0
"^lv_imagebitton_set_src_tiled",# !LV_IMGBTN_TILED
#"^lv_disp_",
"^lv_refr_get_fps_", # no LV_USE_PERF_MONITOR
"^lv_image_cache_",
"^lv_image_decoder_",
"^lv_image_cf_",
"^lv_image_buf_",
"^lv_indev_scroll_",
"^lv_pow",
"^lv_keyboard_def_event_cb", # need to fix conditional include
# "^lv_event_get_", # event_getters not needed
"^lv_refr_reset_fps_counter",
"^lv_refr_get_fps_avg",
"^lv_anim_path_", # callbacks for animation are moved to constants
# LV_USE_OBJ_PROPERTY 0
"^lv_obj_set_property",
"^lv_obj_set_properties",
"^lv_obj_get_property",
"^lv_win_",
]:
if re.search(exclude_pattern, fun_name): exclude = True
if exclude: continue
print(fun)
print()
headers = self.get_enum_headers()
with open(output_path, 'w', encoding='utf-8') as f:
# Write the static content first
f.write(self._get_static_enum_content())
# Process headers for dynamic enums
for header_path in headers:
try:
with open(header_path, encoding='utf-8-sig') as header_file:
f.write(f"// File: {header_path}\n")
raw_content = self.clean_source(header_file.read())
enum_values = self.extract_enums(raw_content)
for enum_value in sorted(enum_values):
f.write(f"{enum_value}\n")
f.write("\n")
except Exception as e:
logger.error(f"Error processing {header_path}: {e}")
sys.stdout.close()
# ################################################################################
# Parse 'enum'
# ################################################################################
lv_src_prefix = "../../lvgl/src/"
lv_fun_globs = [
"core/*.h",
"draw/*.h",
"hal/*.h",
"misc/*.h",
"widgets/*/*.h",
"display/lv_display.h",
"layouts/**/*.h",
]
headers_exlude_suffix = [
"_private.h",
"lv_lottie.h",
"lv_obj_property.h",
"lv_obj_property_names.h",
"lv_style_properties.h",
]
headers_names = list_files(lv_src_prefix, lv_fun_globs)
# filter out from headers_exlude_suffix
headers_names = [x for x in headers_names if not any(x.endswith(suffix) for suffix in headers_exlude_suffix)]
output_filename = "../mapping/lv_enum.h"
sys.stdout = open(output_filename, 'w', encoding='utf-8')
print("""// ======================================================================
def _get_static_enum_content(self) -> str:
"""Get the static content for enum header."""
return """// ======================================================================
// Functions
// ======================================================================
@ -268,7 +374,6 @@ COLOR_IVORY=0xFFFFF0
COLOR_LINEN=0xFAF0E6
COLOR_BEIGE=0xF5F5DC
COLOR_AZURE=0xF0FFFF
COLOR_SILVER=0xC0C0C0
COLOR_PINK=0xFFC0CB
COLOR_PLUM=0xDDA0DD
COLOR_ORCHID=0xDA70D6
@ -397,47 +502,59 @@ LV_STYLE_TRANSFORM_ANGLE=LV_STYLE_TRANSFORM_ROTATION
LV_ZOOM_NONE=LV_SCALE_NONE
// LVGL 9.3
LV_LABEL_LONG_WRAP=LV_LABEL_LONG_MODE_WRAP
LV_LABEL_LONG_DOT=LV_LABEL_LONG_MODE_DOTS
LV_LABEL_LONG_SCROLL=LV_LABEL_LONG_MODE_SCROLL
LV_LABEL_LONG_SCROLL_CIRCULAR=LV_LABEL_LONG_MODE_SCROLL_CIRCULAR
LV_LABEL_LONG_CLIP=LV_LABEL_LONG_MODE_CLIP
// ======================================================================
// Generated from headers
// ======================================================================
""")
"""
for header_name in headers_names:
with open(header_name) as f:
raw = clean_source(f.read())
def run(self, functions_output: str = "../mapping/lv_funcs.h",
enums_output: str = "../mapping/lv_enum.h"):
"""Run the complete preprocessing pipeline."""
functions_path = Path(functions_output)
enums_path = Path(enums_output)
# Create output directories if they don't exist
functions_path.parent.mkdir(parents=True, exist_ok=True)
enums_path.parent.mkdir(parents=True, exist_ok=True)
# Generate both files
self.generate_functions_header(functions_path)
self.generate_enums_header(enums_path)
logger.info("Preprocessing complete!")
print(f"// File: {header_name}")
# extract enums
enums = re.findall(r'enum\s+\w*\s*{(.*?)}', raw, flags=re.DOTALL)
for enum in enums: # iterate on all matches
# exclude LV_PROPERTY_ID
# we compile with `#define LV_USE_OBJ_PROPERTY 0`
# and remove all instances of `LV_PROPERTY_ID(OBJ, FLAG_START, LV_PROPERTY_TYPE_INT, 0),`
if re.search('LV_PROPERTY_ID', enum): continue
# remove enums defined via a macro
enum = re.sub(r'\S+\((.*?),.*?\),', '\\1,', enum) # turn 'LV_STYLE_PROP_INIT(LV_STYLE_SIZE, 0x0, LV_STYLE_ID_VALUE + 3, LV_STYLE_ATTR_NONE),' into 'LV_STYLE_SIZE'
#
enum_elt = enum.split(",")
for enum_item in enum_elt:
# remove any space
enum_item = re.sub(r'[ \t\n]', '', enum_item)
# remove anything after '='
enum_item = re.sub(r'=.*$', '', enum_item)
# item is ready
exclude = False
for exclude_prefix in ["_", "LV_BIDI_DIR_", "LV_FONT_",
"LV_SIGNAL_", "LV_TEMPL_", "LV_TASK_PRIO_", "LV_THEME_",
"LV_LRU_",
"LV_VECTOR_",
"LV_KEYBOARD_MODE_TEXT_ARABIC"]:
if enum_item.startswith(exclude_prefix): exclude = True
if exclude: continue
def main():
"""Main entry point with command line argument parsing."""
parser = argparse.ArgumentParser(description="LVGL Header Preprocessor")
parser.add_argument("--lv-src", default="../../lvgl/src/",
help="Path to LVGL source directory")
parser.add_argument("--functions-output", default="../mapping/lv_funcs.h",
help="Output path for functions header")
parser.add_argument("--enums-output", default="../mapping/lv_enum.h",
help="Output path for enums header")
parser.add_argument("--verbose", "-v", action="store_true",
help="Enable verbose logging")
args = parser.parse_args()
if args.verbose:
logging.getLogger().setLevel(logging.DEBUG)
try:
preprocessor = LVGLPreprocessor(args.lv_src)
preprocessor.run(args.functions_output, args.enums_output)
except Exception as e:
logger.error(f"Preprocessing failed: {e}")
sys.exit(1)
print(enum_item)
# extract `LV_EXPORT_CONST_INT()` int constants
constints = re.findall(r'LV_EXPORT_CONST_INT\((\w+)\)', raw, flags=re.DOTALL)
for constint in constints:
print(constint)
sys.stdout.close()
if __name__ == "__main__":
main()

View File

@ -1,5 +1,5 @@
# LVGL integer constants
# LVGL version 9
# LVGL version 9.3.0
lv.ALIGN_BOTTOM_LEFT = 4
lv.ALIGN_BOTTOM_MID = 5
@ -24,8 +24,6 @@ lv.ALIGN_TOP_LEFT = 1
lv.ALIGN_TOP_MID = 2
lv.ALIGN_TOP_RIGHT = 3
lv.ANIM_IMAGE_PART_MAIN = 0
lv.ANIM_OFF = 0
lv.ANIM_ON = 1
lv.ANIM_PLAYTIME_INFINITE = -1
lv.ANIM_REPEAT_INFINITE = -1
lv.ARC_MODE_NORMAL = 0
@ -43,6 +41,7 @@ lv.BASE_DIR_NEUTRAL = 32
lv.BASE_DIR_RTL = 1
lv.BASE_DIR_WEAK = 33
lv.BLEND_MODE_ADDITIVE = 1
lv.BLEND_MODE_DIFFERENCE = 4
lv.BLEND_MODE_MULTIPLY = 3
lv.BLEND_MODE_NORMAL = 0
lv.BLEND_MODE_SUBTRACTIVE = 2
@ -71,11 +70,27 @@ lv.BUTTONMATRIX_CTRL_CUSTOM_1 = 16384
lv.BUTTONMATRIX_CTRL_CUSTOM_2 = 32768
lv.BUTTONMATRIX_CTRL_DISABLED = 64
lv.BUTTONMATRIX_CTRL_HIDDEN = 16
lv.BUTTONMATRIX_CTRL_NONE = 0
lv.BUTTONMATRIX_CTRL_NO_REPEAT = 32
lv.BUTTONMATRIX_CTRL_POPOVER = 1024
lv.BUTTONMATRIX_CTRL_RESERVED_1 = 2048
lv.BUTTONMATRIX_CTRL_RESERVED_2 = 4096
lv.BUTTONMATRIX_CTRL_RESERVED_3 = 8192
lv.BUTTONMATRIX_CTRL_RECOLOR = 2048
lv.BUTTONMATRIX_CTRL_RESERVED_1 = 4096
lv.BUTTONMATRIX_CTRL_RESERVED_2 = 8192
lv.BUTTONMATRIX_CTRL_WIDTH_1 = 1
lv.BUTTONMATRIX_CTRL_WIDTH_10 = 10
lv.BUTTONMATRIX_CTRL_WIDTH_11 = 11
lv.BUTTONMATRIX_CTRL_WIDTH_12 = 12
lv.BUTTONMATRIX_CTRL_WIDTH_13 = 13
lv.BUTTONMATRIX_CTRL_WIDTH_14 = 14
lv.BUTTONMATRIX_CTRL_WIDTH_15 = 15
lv.BUTTONMATRIX_CTRL_WIDTH_2 = 2
lv.BUTTONMATRIX_CTRL_WIDTH_3 = 3
lv.BUTTONMATRIX_CTRL_WIDTH_4 = 4
lv.BUTTONMATRIX_CTRL_WIDTH_5 = 5
lv.BUTTONMATRIX_CTRL_WIDTH_6 = 6
lv.BUTTONMATRIX_CTRL_WIDTH_7 = 7
lv.BUTTONMATRIX_CTRL_WIDTH_8 = 8
lv.BUTTONMATRIX_CTRL_WIDTH_9 = 9
lv.CHART_AXIS_LAST = 5
lv.CHART_AXIS_PRIMARY_X = 2
lv.CHART_AXIS_PRIMARY_Y = 0
@ -89,8 +104,14 @@ lv.CHART_TYPE_SCATTER = 3
lv.CHART_UPDATE_MODE_CIRCULAR = 1
lv.CHART_UPDATE_MODE_SHIFT = 0
lv.COLOR_AQUA = 65535
lv.COLOR_AZURE = 15794175
lv.COLOR_BEIGE = 16119260
lv.COLOR_BISQUE = 16770244
lv.COLOR_BLACK = 0
lv.COLOR_BLUE = 255
lv.COLOR_BLUSH = 11534336
lv.COLOR_BROWN = 10824234
lv.COLOR_CORAL = 16744272
lv.COLOR_CYAN = 65535
lv.COLOR_DEPTH = 16
lv.COLOR_FORMAT_A1 = 11
@ -98,8 +119,12 @@ lv.COLOR_FORMAT_A2 = 12
lv.COLOR_FORMAT_A4 = 13
lv.COLOR_FORMAT_A8 = 14
lv.COLOR_FORMAT_AL88 = 21
lv.COLOR_FORMAT_ARGB1555 = 22
lv.COLOR_FORMAT_ARGB2222 = 24
lv.COLOR_FORMAT_ARGB4444 = 23
lv.COLOR_FORMAT_ARGB8565 = 19
lv.COLOR_FORMAT_ARGB8888 = 16
lv.COLOR_FORMAT_ARGB8888_PREMULTIPLIED = 26
lv.COLOR_FORMAT_I1 = 7
lv.COLOR_FORMAT_I2 = 8
lv.COLOR_FORMAT_I4 = 9
@ -111,12 +136,22 @@ lv.COLOR_FORMAT_I8 = 10
lv.COLOR_FORMAT_L8 = 6
lv.COLOR_FORMAT_NATIVE = 18
lv.COLOR_FORMAT_NATIVE_WITH_ALPHA = 20
lv.COLOR_FORMAT_NEMA_TSC12 = 52
lv.COLOR_FORMAT_NEMA_TSC12A = 53
lv.COLOR_FORMAT_NEMA_TSC4 = 48
lv.COLOR_FORMAT_NEMA_TSC6 = 49
lv.COLOR_FORMAT_NEMA_TSC6A = 50
lv.COLOR_FORMAT_NEMA_TSC6AP = 51
lv.COLOR_FORMAT_NEMA_TSC_END = 53
lv.COLOR_FORMAT_NEMA_TSC_START = 48
lv.COLOR_FORMAT_NV12 = 37
lv.COLOR_FORMAT_NV21 = 36
lv.COLOR_FORMAT_PROPRIETARY_START = 48
lv.COLOR_FORMAT_RAW = 1
lv.COLOR_FORMAT_RAW_ALPHA = 2
lv.COLOR_FORMAT_RGB565 = 18
lv.COLOR_FORMAT_RGB565A8 = 20
lv.COLOR_FORMAT_RGB565_SWAPPED = 27
lv.COLOR_FORMAT_RGB888 = 15
lv.COLOR_FORMAT_UNKNOWN = 0
lv.COLOR_FORMAT_UYVY = 39
@ -124,18 +159,36 @@ lv.COLOR_FORMAT_XRGB8888 = 17
lv.COLOR_FORMAT_YUV_END = 39
lv.COLOR_FORMAT_YUV_START = 32
lv.COLOR_FORMAT_YUY2 = 38
lv.COLOR_FUCHSIA = 16711935
lv.COLOR_GOLD = 16766720
lv.COLOR_GRAY = 8421504
lv.COLOR_GREEN = 32768
lv.COLOR_GREY = 8421504
lv.COLOR_INDIGO = 4915330
lv.COLOR_IVORY = 16777200
lv.COLOR_KHAKI = 15787660
lv.COLOR_LIME = 65280
lv.COLOR_LINEN = 16445670
lv.COLOR_MAGENTA = 16711935
lv.COLOR_MAROON = 8388608
lv.COLOR_NAVY = 128
lv.COLOR_OLIVE = 8421376
lv.COLOR_ORANGE = 16744192
lv.COLOR_ORANGE = 16753920
lv.COLOR_ORCHID = 14315734
lv.COLOR_PERU = 13468991
lv.COLOR_PINK = 16761035
lv.COLOR_PLUM = 14524637
lv.COLOR_PURPLE = 8388736
lv.COLOR_RED = 16711680
lv.COLOR_SALMON = 16416882
lv.COLOR_SIENNA = 10506797
lv.COLOR_SILVER = 12632256
lv.COLOR_SNOW = 16775930
lv.COLOR_TAN = 13808780
lv.COLOR_TEAL = 32896
lv.COLOR_TOMATO = 16737095
lv.COLOR_VIOLET = 15631086
lv.COLOR_WHEAT = 16113331
lv.COLOR_WHITE = 16777215
lv.COLOR_YELLOW = 16776960
lv.COORD_MAX = 536870911
@ -169,85 +222,90 @@ lv.DRAW_TASK_STATE_IN_PROGRESS = 2
lv.DRAW_TASK_STATE_QUEUED = 1
lv.DRAW_TASK_STATE_READY = 3
lv.DRAW_TASK_STATE_WAITING = 0
lv.DRAW_TASK_TYPE_ARC = 8
lv.DRAW_TASK_TYPE_ARC = 9
lv.DRAW_TASK_TYPE_BORDER = 2
lv.DRAW_TASK_TYPE_BOX_SHADOW = 3
lv.DRAW_TASK_TYPE_FILL = 1
lv.DRAW_TASK_TYPE_IMAGE = 5
lv.DRAW_TASK_TYPE_LABEL = 4
lv.DRAW_TASK_TYPE_LAYER = 6
lv.DRAW_TASK_TYPE_LINE = 7
lv.DRAW_TASK_TYPE_MASK_BITMAP = 11
lv.DRAW_TASK_TYPE_MASK_RECTANGLE = 10
lv.DRAW_TASK_TYPE_IMAGE = 6
lv.DRAW_TASK_TYPE_LABEL = 5
lv.DRAW_TASK_TYPE_LAYER = 7
lv.DRAW_TASK_TYPE_LETTER = 4
lv.DRAW_TASK_TYPE_LINE = 8
lv.DRAW_TASK_TYPE_MASK_BITMAP = 12
lv.DRAW_TASK_TYPE_MASK_RECTANGLE = 11
lv.DRAW_TASK_TYPE_NONE = 0
lv.DRAW_TASK_TYPE_TRIANGLE = 9
lv.DRAW_TASK_TYPE_VECTOR = 12
lv.DRAW_TASK_TYPE_TRIANGLE = 10
lv.DROPDOWN_POS_LAST = 65535
lv.EVENT_ALL = 0
lv.EVENT_CANCEL = 36
lv.EVENT_CHILD_CHANGED = 39
lv.EVENT_CHILD_CREATED = 40
lv.EVENT_CHILD_DELETED = 41
lv.EVENT_CLICKED = 7
lv.EVENT_COLOR_FORMAT_CHANGED = 52
lv.EVENT_COVER_CHECK = 23
lv.EVENT_CREATE = 37
lv.EVENT_DEFOCUSED = 17
lv.EVENT_DELETE = 38
lv.EVENT_DRAW_MAIN = 26
lv.EVENT_DRAW_MAIN_BEGIN = 25
lv.EVENT_DRAW_MAIN_END = 27
lv.EVENT_DRAW_POST = 29
lv.EVENT_DRAW_POST_BEGIN = 28
lv.EVENT_DRAW_POST_END = 30
lv.EVENT_DRAW_TASK_ADDED = 31
lv.EVENT_FLUSH_FINISH = 59
lv.EVENT_FLUSH_START = 58
lv.EVENT_FLUSH_WAIT_FINISH = 61
lv.EVENT_FLUSH_WAIT_START = 60
lv.EVENT_FOCUSED = 16
lv.EVENT_GESTURE = 13
lv.EVENT_GET_SELF_SIZE = 49
lv.EVENT_HIT_TEST = 19
lv.EVENT_HOVER_LEAVE = 22
lv.EVENT_HOVER_OVER = 21
lv.EVENT_INDEV_RESET = 20
lv.EVENT_INSERT = 33
lv.EVENT_INVALIDATE_AREA = 50
lv.EVENT_KEY = 14
lv.EVENT_LAST = 63
lv.EVENT_LAYOUT_CHANGED = 48
lv.EVENT_LEAVE = 18
lv.EVENT_LONG_PRESSED = 5
lv.EVENT_LONG_PRESSED_REPEAT = 6
lv.EVENT_CANCEL = 39
lv.EVENT_CHILD_CHANGED = 42
lv.EVENT_CHILD_CREATED = 43
lv.EVENT_CHILD_DELETED = 44
lv.EVENT_CLICKED = 10
lv.EVENT_COLOR_FORMAT_CHANGED = 55
lv.EVENT_COVER_CHECK = 26
lv.EVENT_CREATE = 40
lv.EVENT_DEFOCUSED = 20
lv.EVENT_DELETE = 41
lv.EVENT_DOUBLE_CLICKED = 6
lv.EVENT_DRAW_MAIN = 29
lv.EVENT_DRAW_MAIN_BEGIN = 28
lv.EVENT_DRAW_MAIN_END = 30
lv.EVENT_DRAW_POST = 32
lv.EVENT_DRAW_POST_BEGIN = 31
lv.EVENT_DRAW_POST_END = 33
lv.EVENT_DRAW_TASK_ADDED = 34
lv.EVENT_FLUSH_FINISH = 62
lv.EVENT_FLUSH_START = 61
lv.EVENT_FLUSH_WAIT_FINISH = 64
lv.EVENT_FLUSH_WAIT_START = 63
lv.EVENT_FOCUSED = 19
lv.EVENT_GESTURE = 16
lv.EVENT_GET_SELF_SIZE = 52
lv.EVENT_HIT_TEST = 22
lv.EVENT_HOVER_LEAVE = 25
lv.EVENT_HOVER_OVER = 24
lv.EVENT_INDEV_RESET = 23
lv.EVENT_INSERT = 36
lv.EVENT_INVALIDATE_AREA = 53
lv.EVENT_KEY = 17
lv.EVENT_LAST = 67
lv.EVENT_LAYOUT_CHANGED = 51
lv.EVENT_LEAVE = 21
lv.EVENT_LONG_PRESSED = 8
lv.EVENT_LONG_PRESSED_REPEAT = 9
lv.EVENT_MARKED_DELETING = 65536
lv.EVENT_PREPROCESS = 32768
lv.EVENT_PRESSED = 1
lv.EVENT_PRESSING = 2
lv.EVENT_PRESS_LOST = 3
lv.EVENT_READY = 35
lv.EVENT_REFRESH = 34
lv.EVENT_REFR_EXT_DRAW_SIZE = 24
lv.EVENT_REFR_READY = 55
lv.EVENT_REFR_REQUEST = 53
lv.EVENT_REFR_START = 54
lv.EVENT_RELEASED = 8
lv.EVENT_RENDER_READY = 57
lv.EVENT_RENDER_START = 56
lv.EVENT_RESOLUTION_CHANGED = 51
lv.EVENT_ROTARY = 15
lv.EVENT_SCREEN_LOADED = 44
lv.EVENT_SCREEN_LOAD_START = 43
lv.EVENT_SCREEN_UNLOADED = 45
lv.EVENT_SCREEN_UNLOAD_START = 42
lv.EVENT_SCROLL = 12
lv.EVENT_SCROLL_BEGIN = 9
lv.EVENT_SCROLL_END = 11
lv.EVENT_SCROLL_THROW_BEGIN = 10
lv.EVENT_READY = 38
lv.EVENT_REFRESH = 37
lv.EVENT_REFR_EXT_DRAW_SIZE = 27
lv.EVENT_REFR_READY = 58
lv.EVENT_REFR_REQUEST = 56
lv.EVENT_REFR_START = 57
lv.EVENT_RELEASED = 11
lv.EVENT_RENDER_READY = 60
lv.EVENT_RENDER_START = 59
lv.EVENT_RESOLUTION_CHANGED = 54
lv.EVENT_ROTARY = 18
lv.EVENT_SCREEN_LOADED = 47
lv.EVENT_SCREEN_LOAD_START = 46
lv.EVENT_SCREEN_UNLOADED = 48
lv.EVENT_SCREEN_UNLOAD_START = 45
lv.EVENT_SCROLL = 15
lv.EVENT_SCROLL_BEGIN = 12
lv.EVENT_SCROLL_END = 14
lv.EVENT_SCROLL_THROW_BEGIN = 13
lv.EVENT_SHORT_CLICKED = 4
lv.EVENT_SIZE_CHANGED = 46
lv.EVENT_STYLE_CHANGED = 47
lv.EVENT_VALUE_CHANGED = 32
lv.EVENT_VSYNC = 62
lv.EVENT_SINGLE_CLICKED = 5
lv.EVENT_SIZE_CHANGED = 49
lv.EVENT_STYLE_CHANGED = 50
lv.EVENT_TRIPLE_CLICKED = 7
lv.EVENT_VALUE_CHANGED = 35
lv.EVENT_VSYNC = 65
lv.EVENT_VSYNC_REQUEST = 66
lv.FLEX_ALIGN_CENTER = 2
lv.FLEX_ALIGN_END = 1
lv.FLEX_ALIGN_SPACE_AROUND = 4
@ -316,6 +374,8 @@ lv.IMAGE_ALIGN_BOTTOM_LEFT = 4
lv.IMAGE_ALIGN_BOTTOM_MID = 5
lv.IMAGE_ALIGN_BOTTOM_RIGHT = 6
lv.IMAGE_ALIGN_CENTER = 9
lv.IMAGE_ALIGN_CONTAIN = 13
lv.IMAGE_ALIGN_COVER = 14
lv.IMAGE_ALIGN_DEFAULT = 0
lv.IMAGE_ALIGN_LEFT_MID = 7
lv.IMAGE_ALIGN_RIGHT_MID = 8
@ -329,6 +389,7 @@ lv.IMAGE_COMPRESS_NONE = 0
lv.IMAGE_COMPRESS_RLE = 1
lv.IMAGE_FLAGS_ALLOCATED = 16
lv.IMAGE_FLAGS_COMPRESSED = 8
lv.IMAGE_FLAGS_CUSTOM_DRAW = 64
lv.IMAGE_FLAGS_MODIFIABLE = 32
lv.IMAGE_FLAGS_PREMULTIPLIED = 1
lv.IMAGE_FLAGS_USER1 = 256
@ -367,11 +428,11 @@ lv.KEY_PREV = 11
lv.KEY_RIGHT = 19
lv.KEY_UP = 17
lv.LABEL_DOT_NUM = 3
lv.LABEL_LONG_CLIP = 4
lv.LABEL_LONG_DOT = 1
lv.LABEL_LONG_SCROLL = 2
lv.LABEL_LONG_SCROLL_CIRCULAR = 3
lv.LABEL_LONG_WRAP = 0
lv.LABEL_LONG_MODE_CLIP = 4
lv.LABEL_LONG_MODE_DOTS = 1
lv.LABEL_LONG_MODE_SCROLL = 2
lv.LABEL_LONG_MODE_SCROLL_CIRCULAR = 3
lv.LABEL_LONG_MODE_WRAP = 0
lv.LABEL_POS_LAST = 65535
lv.LABEL_TEXT_SELECTION_OFF = 65535
lv.LAYER_TYPE_NONE = 0
@ -492,6 +553,8 @@ lv.RES_OK = 1
lv.ROLLER_MODE_INFINITE = 1
lv.ROLLER_MODE_NORMAL = 0
lv.SCALE_LABEL_ENABLED_DEFAULT = 1
lv.SCALE_LABEL_ROTATE_KEEP_UPRIGHT = 524288
lv.SCALE_LABEL_ROTATE_MATCH_TICKS = 1048576
lv.SCALE_MAJOR_TICK_EVERY_DEFAULT = 5
lv.SCALE_MODE_HORIZONTAL_BOTTOM = 1
lv.SCALE_MODE_HORIZONTAL_TOP = 0
@ -501,6 +564,7 @@ lv.SCALE_MODE_ROUND_OUTER = 16
lv.SCALE_MODE_VERTICAL_LEFT = 2
lv.SCALE_MODE_VERTICAL_RIGHT = 4
lv.SCALE_NONE = 256
lv.SCALE_ROTATION_ANGLE_MASK = 524287
lv.SCALE_TOTAL_TICK_COUNT_DEFAULT = 11
lv.SCROLLBAR_MODE_ACTIVE = 2
lv.SCROLLBAR_MODE_AUTO = 3
@ -530,6 +594,9 @@ lv.SIZE_CONTENT = 1073741823
lv.SLIDER_MODE_NORMAL = 0
lv.SLIDER_MODE_RANGE = 2
lv.SLIDER_MODE_SYMMETRICAL = 1
lv.SLIDER_ORIENTATION_AUTO = 0
lv.SLIDER_ORIENTATION_HORIZONTAL = 1
lv.SLIDER_ORIENTATION_VERTICAL = 2
lv.SPAN_MODE_BREAK = 2
lv.SPAN_MODE_EXPAND = 1
lv.SPAN_MODE_FIXED = 0
@ -553,9 +620,9 @@ lv.STATE_USER_3 = 16384
lv.STATE_USER_4 = 32768
lv.STRIDE_AUTO = 0
lv.STYLE_ALIGN = 10
lv.STYLE_ANIM = 99
lv.STYLE_ANIM_DURATION = 100
lv.STYLE_ANIM_TIME = 100
lv.STYLE_ANIM = 102
lv.STYLE_ANIM_DURATION = 103
lv.STYLE_ANIM_TIME = 103
lv.STYLE_ARC_COLOR = 82
lv.STYLE_ARC_IMAGE_SRC = 84
lv.STYLE_ARC_OPA = 83
@ -576,31 +643,31 @@ lv.STYLE_BG_IMAGE_TILED = 44
lv.STYLE_BG_MAIN_OPA = 36
lv.STYLE_BG_MAIN_STOP = 33
lv.STYLE_BG_OPA = 29
lv.STYLE_BITMAP_MASK_SRC = 115
lv.STYLE_BLEND_MODE = 103
lv.STYLE_BITMAP_MASK_SRC = 117
lv.STYLE_BLEND_MODE = 105
lv.STYLE_BORDER_COLOR = 49
lv.STYLE_BORDER_OPA = 50
lv.STYLE_BORDER_POST = 53
lv.STYLE_BORDER_SIDE = 52
lv.STYLE_BORDER_WIDTH = 48
lv.STYLE_CLIP_CORNER = 45
lv.STYLE_COLOR_FILTER_DSC = 97
lv.STYLE_COLOR_FILTER_OPA = 98
lv.STYLE_FLEX_CROSS_PLACE = 127
lv.STYLE_FLEX_FLOW = 125
lv.STYLE_FLEX_GROW = 129
lv.STYLE_FLEX_MAIN_PLACE = 126
lv.STYLE_FLEX_TRACK_PLACE = 128
lv.STYLE_GRID_CELL_COLUMN_POS = 134
lv.STYLE_GRID_CELL_COLUMN_SPAN = 135
lv.STYLE_GRID_CELL_ROW_POS = 137
lv.STYLE_GRID_CELL_ROW_SPAN = 138
lv.STYLE_GRID_CELL_X_ALIGN = 136
lv.STYLE_GRID_CELL_Y_ALIGN = 139
lv.STYLE_GRID_COLUMN_ALIGN = 130
lv.STYLE_GRID_COLUMN_DSC_ARRAY = 133
lv.STYLE_GRID_ROW_ALIGN = 131
lv.STYLE_GRID_ROW_DSC_ARRAY = 132
lv.STYLE_COLOR_FILTER_DSC = 100
lv.STYLE_COLOR_FILTER_OPA = 101
lv.STYLE_FLEX_CROSS_PLACE = 124
lv.STYLE_FLEX_FLOW = 122
lv.STYLE_FLEX_GROW = 126
lv.STYLE_FLEX_MAIN_PLACE = 123
lv.STYLE_FLEX_TRACK_PLACE = 125
lv.STYLE_GRID_CELL_COLUMN_POS = 131
lv.STYLE_GRID_CELL_COLUMN_SPAN = 132
lv.STYLE_GRID_CELL_ROW_POS = 134
lv.STYLE_GRID_CELL_ROW_SPAN = 135
lv.STYLE_GRID_CELL_X_ALIGN = 133
lv.STYLE_GRID_CELL_Y_ALIGN = 136
lv.STYLE_GRID_COLUMN_ALIGN = 127
lv.STYLE_GRID_COLUMN_DSC_ARRAY = 130
lv.STYLE_GRID_ROW_ALIGN = 128
lv.STYLE_GRID_ROW_DSC_ARRAY = 129
lv.STYLE_HEIGHT = 2
lv.STYLE_IMAGE_OPA = 68
lv.STYLE_IMAGE_RECOLOR = 69
@ -608,7 +675,7 @@ lv.STYLE_IMAGE_RECOLOR_OPA = 70
lv.STYLE_IMG_OPA = 68
lv.STYLE_IMG_RECOLOR = 69
lv.STYLE_IMG_RECOLOR_OPA = 70
lv.STYLE_LAST_BUILT_IN_PROP = 140
lv.STYLE_LAST_BUILT_IN_PROP = 137
lv.STYLE_LAYOUT = 22
lv.STYLE_LENGTH = 3
lv.STYLE_LINE_COLOR = 76
@ -625,9 +692,9 @@ lv.STYLE_MAX_HEIGHT = 7
lv.STYLE_MAX_WIDTH = 5
lv.STYLE_MIN_HEIGHT = 6
lv.STYLE_MIN_WIDTH = 4
lv.STYLE_NUM_BUILT_IN_PROPS = 141
lv.STYLE_OPA = 95
lv.STYLE_OPA_LAYERED = 96
lv.STYLE_NUM_BUILT_IN_PROPS = 138
lv.STYLE_OPA = 98
lv.STYLE_OPA_LAYERED = 99
lv.STYLE_OUTLINE_COLOR = 57
lv.STYLE_OUTLINE_OPA = 58
lv.STYLE_OUTLINE_PAD = 59
@ -635,16 +702,20 @@ lv.STYLE_OUTLINE_WIDTH = 56
lv.STYLE_PAD_BOTTOM = 17
lv.STYLE_PAD_COLUMN = 21
lv.STYLE_PAD_LEFT = 18
lv.STYLE_PAD_RADIAL = 14
lv.STYLE_PAD_RIGHT = 19
lv.STYLE_PAD_ROW = 20
lv.STYLE_PAD_TOP = 16
lv.STYLE_PROP_ANY = 255
lv.STYLE_PROP_CONST = 255
lv.STYLE_PROP_INV = 0
lv.STYLE_RADIAL_OFFSET = 13
lv.STYLE_RADIUS = 12
lv.STYLE_RECOLOR = 120
lv.STYLE_RECOLOR_OPA = 121
lv.STYLE_RES_FOUND = 1
lv.STYLE_RES_NOT_FOUND = 0
lv.STYLE_ROTARY_SENSITIVITY = 116
lv.STYLE_ROTARY_SENSITIVITY = 118
lv.STYLE_SHADOW_COLOR = 61
lv.STYLE_SHADOW_OFFSET_X = 64
lv.STYLE_SHADOW_OFFSET_Y = 65
@ -664,27 +735,35 @@ lv.STYLE_TEXT_FONT = 90
lv.STYLE_TEXT_LETTER_SPACE = 91
lv.STYLE_TEXT_LINE_SPACE = 92
lv.STYLE_TEXT_OPA = 89
lv.STYLE_TRANSFORM_ANGLE = 110
lv.STYLE_TRANSFORM_HEIGHT = 105
lv.STYLE_TRANSFORM_PIVOT_X = 111
lv.STYLE_TRANSFORM_PIVOT_Y = 112
lv.STYLE_TRANSFORM_ROTATION = 110
lv.STYLE_TRANSFORM_SCALE_X = 108
lv.STYLE_TRANSFORM_SCALE_Y = 109
lv.STYLE_TRANSFORM_SKEW_X = 113
lv.STYLE_TRANSFORM_SKEW_Y = 114
lv.STYLE_TRANSFORM_WIDTH = 104
lv.STYLE_TRANSITION = 102
lv.STYLE_TRANSLATE_X = 106
lv.STYLE_TRANSLATE_Y = 107
lv.STYLE_TEXT_OUTLINE_STROKE_COLOR = 97
lv.STYLE_TEXT_OUTLINE_STROKE_OPA = 96
lv.STYLE_TEXT_OUTLINE_STROKE_WIDTH = 95
lv.STYLE_TRANSFORM_ANGLE = 112
lv.STYLE_TRANSFORM_HEIGHT = 107
lv.STYLE_TRANSFORM_PIVOT_X = 113
lv.STYLE_TRANSFORM_PIVOT_Y = 114
lv.STYLE_TRANSFORM_ROTATION = 112
lv.STYLE_TRANSFORM_SCALE_X = 110
lv.STYLE_TRANSFORM_SCALE_Y = 111
lv.STYLE_TRANSFORM_SKEW_X = 115
lv.STYLE_TRANSFORM_SKEW_Y = 116
lv.STYLE_TRANSFORM_WIDTH = 106
lv.STYLE_TRANSITION = 104
lv.STYLE_TRANSLATE_RADIAL = 119
lv.STYLE_TRANSLATE_X = 108
lv.STYLE_TRANSLATE_Y = 109
lv.STYLE_WIDTH = 1
lv.STYLE_X = 8
lv.STYLE_Y = 9
lv.SWITCH_ORIENTATION_AUTO = 0
lv.SWITCH_ORIENTATION_HORIZONTAL = 1
lv.SWITCH_ORIENTATION_VERTICAL = 2
lv.TABLE_CELL_CTRL_CUSTOM_1 = 16
lv.TABLE_CELL_CTRL_CUSTOM_2 = 32
lv.TABLE_CELL_CTRL_CUSTOM_3 = 64
lv.TABLE_CELL_CTRL_CUSTOM_4 = 128
lv.TABLE_CELL_CTRL_MERGE_RIGHT = 1
lv.TABLE_CELL_CTRL_NONE = 0
lv.TABLE_CELL_CTRL_TEXT_CROP = 2
lv.TABLE_CELL_NONE = 65535
lv.TEXTAREA_CURSOR_LAST = 32767
@ -692,6 +771,9 @@ lv.TEXT_ALIGN_AUTO = 0
lv.TEXT_ALIGN_CENTER = 2
lv.TEXT_ALIGN_LEFT = 1
lv.TEXT_ALIGN_RIGHT = 3
lv.TEXT_CMD_STATE_IN = 2
lv.TEXT_CMD_STATE_PAR = 1
lv.TEXT_CMD_STATE_WAIT = 0
lv.TEXT_DECOR_NONE = 0
lv.TEXT_DECOR_STRIKETHROUGH = 2
lv.TEXT_DECOR_UNDERLINE = 1
@ -699,4 +781,7 @@ lv.TEXT_FLAG_BREAK_ALL = 4
lv.TEXT_FLAG_EXPAND = 1
lv.TEXT_FLAG_FIT = 2
lv.TEXT_FLAG_NONE = 0
lv.TEXT_FLAG_RECOLOR = 8
lv.TREE_WALK_POST_ORDER = 1
lv.TREE_WALK_PRE_ORDER = 0
lv.ZOOM_NONE = 256

View File

@ -26,6 +26,105 @@ def list_to_bytes(l)
return b
end
#################################################################################
# Class Antiburn now embedded in HASPmota
#################################################################################
#@ solidify:Antiburn,weak
class Antiburn
var antiburn # the lv_obj object used as a plain color
var running
static colors = [
0x000000,
0xff0000,
0x00ff00,
0x0000ff,
0xffffff
]
def init()
self.running = false
end
def start()
if self.running
return
else
lv.start()
if self.antiburn == nil
var antiburn = lv.obj(lv.layer_sys())
antiburn.set_style_radius(0, 0)
antiburn.set_style_border_width(0, 0)
antiburn.set_style_bg_opa(255, 0)
antiburn.set_pos(0, 0)
antiburn.set_width(lv.get_hor_res())
antiburn.set_height(lv.get_ver_res())
antiburn.add_event_cb(/->self.stop(), lv.EVENT_PRESSED, 0)
self.antiburn = antiburn
end
self.antiburn.set_style_bg_opa(255, 0)
self.antiburn.add_flag(lv.OBJ_FLAG_CLICKABLE)
self.antiburn.move_foreground()
self.running = true
self.cycle(0)
end
end
def cycle(i)
if !self.running || self.antiburn == nil return nil end
if i < 30
self.antiburn.set_style_bg_color(lv.color_hex(self.colors[i % 5]), 0)
tasmota.set_timer(1000, /->self.cycle(i+1))
else
self.stop()
end
end
def stop()
if self.running && self.antiburn != nil
self.antiburn.set_style_bg_opa(0, 0)
self.antiburn.clear_flag(lv.OBJ_FLAG_CLICKABLE)
self.running = false
self.antiburn.del()
self.antiburn = nil
end
end
end
#################################################################################
# Class DimmedPanel
#
# The screen is dimmed so we disable any touch action except to
# get out of dimmed mode
#################################################################################
#@ solidify:DimmedPanel,weak
class DimmedPanel
var panel # the lv_obj object used as a plain color
def init()
if self.panel == nil
var panel = lv.obj(lv.layer_sys())
panel.set_style_radius(0, 0)
panel.set_style_border_width(0, 0)
panel.set_style_bg_opa(0, 0)
panel.set_pos(0, 0)
panel.set_width(lv.get_hor_res())
panel.set_height(lv.get_ver_res())
panel.add_flag(lv.OBJ_FLAG_CLICKABLE)
panel.add_event_cb(/->self.stop(), lv.EVENT_PRESSED, 0)
self.panel = panel
end
self.panel.move_foreground()
end
def stop()
if (self.panel != nil)
self.panel.del()
self.panel = nil
end
end
end
#################################################################################
# Pre-defined events lists
#################################################################################
@ -56,9 +155,6 @@ class lvh_root
"page",
"comment",
"parentid",
# "auto_size", # TODO not sure it's still needed in LVGL8
# attributes for page
"prev", "next", "back",
"berry_run", # run Berry code after the object is created
]
@ -290,7 +386,7 @@ class lvh_root
else
self._lv_obj = obj
end
self.post_init()
self.post_init(jline)
end
#====================================================================
@ -599,7 +695,7 @@ class lvh_obj : lvh_root
#====================================================================
# post-init, to be overriden and used by certain classes
#====================================================================
def post_init()
def post_init(jline)
self.register_event_cb()
end
@ -1177,8 +1273,8 @@ class lvh_fixed : lvh_obj
# static var _EVENTS = EVENTS_ALL
# label do not need a sub-label
def post_init()
super(self).post_init() # call super
def post_init(jline)
super(self).post_init(jline) # call super
var obj = self._lv_obj
obj.set_style_pad_all(0, 0)
obj.set_style_radius(0, 0)
@ -1197,8 +1293,8 @@ class lvh_flex : lvh_fixed
# static var _lv_class = lv.obj # from parent class
static var _EVENTS = EVENTS_NONE # inhetited
# label do not need a sub-label
def post_init()
super(self).post_init() # call super
def post_init(jline)
super(self).post_init(jline) # call super
var obj = self._lv_obj
obj.set_flex_flow(lv.FLEX_FLOW_ROW)
end
@ -1211,9 +1307,9 @@ end
class lvh_label : lvh_obj
static var _lv_class = lv.label
# label do not need a sub-label
def post_init()
def post_init(jline)
self._lv_label = self._lv_obj # the label is also the object itself
super(self).post_init() # call super
super(self).post_init(jline) # call super
end
end
@ -1349,6 +1445,21 @@ class lvh_msgbox : lvh_obj
self.bg_opa = 255 # can be overriden
end
#====================================================================
# post_init
#
# We need to instanciate all buttons first before applying attributes
#====================================================================
def post_init(jline)
# need to apply options first, and remove to avoid being handled again
if jline.contains('options')
self.set_options(jline['options'])
jline.remove('options')
end
# rest of attributes
super(self).post_init(jline)
end
#====================================================================
# register_event_cb
#
@ -1740,7 +1851,7 @@ class lvh_dropdown_list : lvh_obj
static var _lv_class = nil
# static var _EVENTS = EVENTS_NONE
def post_init()
def post_init(jline)
self._lv_obj = nil # default to nil object, whatever it was initialized with
# check if it is the parent is a spangroup
if isinstance(self._parent_lvh, self._page._hm.lvh_dropdown)
@ -1748,7 +1859,7 @@ class lvh_dropdown_list : lvh_obj
else
print("HSP: 'dropdown_list' should have a parent of type 'dropdown'")
end
super(self).post_init()
super(self).post_init(jline)
end
end
@ -1759,8 +1870,8 @@ end
class lvh_bar : lvh_obj
static var _lv_class = lv.bar
def post_init()
super(self).post_init()
def post_init(jline)
super(self).post_init(jline)
if isinstance(self._parent_lvh, self._page._hm.lvh_scale)
# if sub-object of scale, copy min and max
var min = self._parent_lvh._lv_obj.get_range_min_value()
@ -1864,7 +1975,7 @@ class lvh_scale_section : lvh_root
var _style30 # style for LV_PART_ITEMS
var _min, _max
def post_init()
def post_init(jline)
self._lv_obj = nil # default to nil object, whatever it was initialized with
self._min = 0 # default value by LVGL
self._max = 0 # default value by LVGL
@ -1881,7 +1992,7 @@ class lvh_scale_section : lvh_root
else
print("HSP: 'scale_section' should have a parent of type 'scale'")
end
# super(self).post_init() # call super - not needed for lvh_root
# super(self).post_init(jline) # call super - not needed for lvh_root
end
def set_min(t)
@ -1998,14 +2109,14 @@ class lvh_scale_line : lvh_line
var _needle_length
# var _lv_points # in superclass
def post_init()
def post_init(jline)
# check if it is the parent is a spangroup
if !isinstance(self._parent_lvh, self._page._hm.lvh_scale)
print("HSP: 'scale_line' should have a parent of type 'scale'")
end
self._needle_length = 0
self._lv_points = lv.point_arr([lv.point(), lv.point()]) # create an array with 2 points
super(self).post_init()
super(self).post_init(jline)
end
def set_needle_length(t)
@ -2040,10 +2151,10 @@ end
class lvh_spangroup : lvh_obj
static var _lv_class = lv.spangroup
# label do not need a sub-label
def post_init()
def post_init(jline)
self._lv_obj.set_mode(lv.SPAN_MODE_BREAK) # use lv.SPAN_MODE_BREAK by default
self._lv_obj.refr_mode()
super(self).post_init() # call super -- not needed
super(self).post_init(jline) # call super -- not needed
end
# refresh mode
def refr_mode()
@ -2060,7 +2171,7 @@ class lvh_span : lvh_root
# label do not need a sub-label
var _style # style object
def post_init()
def post_init(jline)
self._lv_obj = nil # default to nil object, whatever it was initialized with
# check if it is the parent is a spangroup
if isinstance(self._parent_lvh, self._page._hm.lvh_spangroup)
@ -2070,7 +2181,7 @@ class lvh_span : lvh_root
else
print("HSP: 'span' should have a parent of type 'spangroup'")
end
# super(self).post_init() # call super - not needed for lvh_root
# super(self).post_init(jline) # call super - not needed for lvh_root
end
#====================================================================
@ -2182,9 +2293,9 @@ class lvh_tabview : lvh_obj
var _tab_list # list of tabs
# label do not need a sub-label
def post_init()
def post_init(jline)
self._tab_list = []
super(self).post_init() # call super -- not needed
super(self).post_init(jline) # call super -- not needed
end
#====================================================================
@ -2271,7 +2382,7 @@ class lvh_tab : lvh_obj
#====================================================================
# specific post-init wihtout events
#====================================================================
def post_init()
def post_init(jline)
self._lv_obj.set_style_radius(0, 0) # set default radius to `0` for rectangle tabs
# self.register_event_cb()
end
@ -2291,7 +2402,7 @@ class lvh_tab : lvh_obj
super(self).init(parent, page, jline, lv_instance, parent_obj)
end
def post_init()
def post_init(jline)
self._lv_obj = nil # default to nil object, whatever it was initialized with
# check if it is the parent is a spangroup
if isinstance(self._parent_lvh, self._page._hm.lvh_tabview)
@ -2313,7 +2424,7 @@ class lvh_tab : lvh_obj
else
print("HSP: 'tab' should have a parent of type 'tabview'")
end
# super(self).post_init() # call super - not needed for lvh_root
# super(self).post_init(jline) # call super - not needed for lvh_root
end
#====================================================================
@ -2364,7 +2475,7 @@ class lvh_chart : lvh_obj
# h_div/v_div contain the horizontal and vertical divisions, we need to memorize values because both are set from same API
var _h_div, _v_div
def post_init()
def post_init(jline)
# default values from LVGL are 0..100
self._y_min = 0
self._y_max = 100
@ -2380,6 +2491,7 @@ class lvh_chart : lvh_obj
self._ser1 = self._lv_obj.add_series(lv.color(0xEE4444), lv.CHART_AXIS_PRIMARY_Y)
self._ser2 = self._lv_obj.add_series(lv.color(0x44EE44), lv.CHART_AXIS_SECONDARY_Y)
super(self).post_init(jline)
end
def add_point(v)
@ -2812,6 +2924,14 @@ class HASPmota
# specific event_cb handling for less memory usage since we are registering a lot of callbacks
var event # try to keep the event object around and reuse it
var event_cb # the low-level callback for the closure to be registered
# auto-dimming for inactivity
var antiburn_time # number of minutes to perdiodically trigger antiburn for LCD
var dimming_time # number of minutes of inactivity to trigger auto-dimming (or 0 if disabled)
var dimming_min # minimum dimming value (1..100), by default it divides dimmer value by 4
var dimming_duration # number of seconds to keep low dimming before turning screen off
static var DIMMING_DURATION = 30 # default dimming duration is 30 seconds
var dimming_state # the current dimming state: 100=normal 25=dimmed_low 0=off
var dimmed_panel # the object used to mask any touch event with the screen is dimmed
# assign lvh_page to a static attribute
static lvh_root = lvh_root
@ -2854,6 +2974,9 @@ class HASPmota
static lvh_qrcode = lvh_qrcode
# special cases
static lvh_chart = lvh_chart
# other helper classes
static var Antiburn = Antiburn
static var DimmedPanel = DimmedPanel
static var PAGES_JSONL = "pages.jsonl" # default template name
@ -2862,6 +2985,14 @@ class HASPmota
import re
self.re_page_target = re.compilebytes("p\\d+")
# nothing to put here up to now
# defaulting values
self.antiburn_time = 0
self.dimming_time = 0
self.dimming_min = 1
self.dimming_duration = self.DIMMING_DURATION
self.dimming_state = 100 # normal brightness from Settings
# register as driver
tasmota.add_driver(self)
end
# make sure that `lv.version` returns a version number
@ -2949,6 +3080,7 @@ class HASPmota
# load from JSONL
self._load(templ_name)
self.started = true
log("HSP: HASPmota initialized")
end
#################################################################################
@ -2970,6 +3102,81 @@ class HASPmota
return l
end
#################################################################################
# Antiburn
#################################################################################
def antiburn()
self.Antiburn().start()
end
#################################################################################
# auto_dimming
#################################################################################
def auto_dimming()
if (self.dimming_time <= 0) return end # fast return if not enabled
var dim_event = nil
import display
var dimming_time_ms = self.dimming_time * 60000
var inactive_time_ms = lv.disp().get_inactive_time()
if (inactive_time_ms < dimming_time_ms)
# no dimming
if (self.dimmed_panel != nil)
self.dimmed_panel.stop()
self.dimmed_panel = nil
end
if (self.dimming_state < 100)
self.dimming_state = 100
display.dimmer(display.dimmer()) # restore dimmer value from settings
# trigger event
dim_event = "off"
end
elif (inactive_time_ms < dimming_time_ms + self.dimming_duration * 1000)
# low brightness dimming
if (self.dimmed_panel == nil)
self.dimmed_panel = self.DimmedPanel()
end
if (self.dimming_state > 25)
# lower dimmer
self.dimming_state = 25
var cur_dim = display.dimmer()
var relative_dim = (cur_dim > self.dimming_min) ? cur_dim - self.dimming_min : self.dimming_min
var low_dim = (relative_dim / 4) + self.dimming_min
display.dimmer(low_dim, true #-no settings-#)
# no event
dim_event = "short"
end
else
if (self.dimmed_panel == nil)
self.dimmed_panel = self.DimmedPanel()
end
# dimmer off
if (self.dimming_state > 0)
# needs to turn off
self.dimming_state = 0
display.dimmer(0, true #-no settings-#)
# trigger event
dim_event = "long"
end
end
# send event if any
if (dim_event != nil)
var tas_event = format('{"hasp":{"p0b0":{"idle":"%s"}}}', dim_event)
# print("val=",val)
tasmota.defer(def ()
tasmota.publish_rule(tas_event)
tasmota.log(f"HSP: publish {tas_event}", 4)
end)
end
end
#################################################################################
# every_100ms
#################################################################################
def every_100ms()
self.auto_dimming()
end
#####################################################################
# General Setters and Getters
@ -3014,6 +3221,7 @@ class HASPmota
var jline = json.load(line)
if type(jline) == 'instance'
if tasmota.loglevel(4)
if string.endswith(line, "\n") line = line[0..-2] end # remove unwanted last '\n'
tasmota.log(f"HSP: parsing line '{line}'", 4)
end
self.parse_page(jline) # parse page first to create any page related objects, may change self.lvh_page_cur_idx_parsing
@ -3051,9 +3259,10 @@ class HASPmota
var jline = json.load(j)
if type(jline) == 'instance'
self.lvh_page_cur_idx_parsing = self.lvh_page_cur_idx
self.parse_page(jline) # parse page first to create any page related objects, may change self.lvh_page_cur_idx_parsing
# objects are created in the current page
self.parse_obj(jline, self.lvh_pages[self.lvh_page_cur_idx]) # then parse object within this page
self.parse_obj(jline, self.lvh_pages[self.lvh_page_cur_idx_parsing]) # then parse object within this page
else
raise "value_error", "unable to parse JSON line"
end
@ -3206,7 +3415,7 @@ class HASPmota
def parse_page(jline)
if jline.has("page") && type(jline["page"]) == 'int'
var page = int(jline["page"])
# print(f">>> parsing page {page}")
# print(f">>> parsing page {page} {jline=}")
self.lvh_page_cur_idx_parsing = page # change current page
if (self.lvh_page_cur_idx == nil) # also set current page if we haven't any yet
self.lvh_page_cur_idx = page
@ -3217,13 +3426,27 @@ class HASPmota
var lvh_page_class = self.lvh_page
self.lvh_pages[page] = lvh_page_class(page, self)
end
end
# check if there is "id":0
if jline.find("id") == 0
var lvh_page_cur = self.get_page_cur_parsing()
lvh_page_cur.prev = int(jline.find("prev", nil))
lvh_page_cur.next = int(jline.find("next", nil))
lvh_page_cur.back = int(jline.find("back", nil))
# check if there is "id":0
if jline.find("id") == 0
var lvh_page_cur = self.get_page_cur_parsing()
lvh_page_cur.prev = int(jline.find("prev", nil))
lvh_page_cur.next = int(jline.find("next", nil))
lvh_page_cur.back = int(jline.find("back", nil))
jline.remove("prev")
jline.remove("next")
jline.remove("back")
# special case if it's also "page == 0"
if (lvh_page_cur._page_id == 0)
self.dimming_time = int(jline.find("dimming_time", self.dimming_time))
self.dimming_min = int(jline.find("dimming_min", self.dimming_min))
self.dimming_duration = int(jline.find("dimming_duration", self.dimming_duration))
self.antiburn_time = int(jline.find("antiburn", self.dimming_time))
jline.remove("dimming_time")
jline.remove("dimming_min")
jline.remove("dimming_duration")
jline.remove("antiburn")
end
end
end

View File

@ -1,5 +1,5 @@
MIT licence
Copyright (c) 2021 LVGL Kft
Copyright (c) 2025 LVGL Kft
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:

View File

@ -2,7 +2,7 @@
<a href="https://github.com/sponsors/lvgl" target="_blank"><img align="left" src="https://lvgl.io/github-assets/sponsor.png" height="32px"></a>
<p align="right">
<b>English</b> | <a href="./docs/README_zh.rst">中文</a> | <a href="./docs/README_pt_BR.rst">Português do Brasil</a> | <a href="./docs/README_jp.rst">日本語</a>
<b>English</b> | <a href="./docs/README_zh.md">中文</a> | <a href="./docs/README_pt_BR.md">Português do Brasil</a> | <a href="./docs/README_jp.md">日本語</a>
</p>
<br>
@ -44,31 +44,31 @@ Our team is ready to help you with graphics design, UI implementation and consul
**Free and Portable**
- A fully portable C (C++ compatible) library with no external dependencies.
- Can be compiled to any MCU or MPU, with any (RT)OS.
- Supports monochrome, ePaper, OLED or TFT displays, or even monitors. [Porting Guide](https://docs.lvgl.io/master/porting/project.html)
- Supports monochrome, ePaper, OLED or TFT displays, or even monitors. [Displays](https://docs.lvgl.io/master/details/main-modules/display/index.html)
- Distributed under the MIT license, so you can easily use it in commercial projects too.
- Needs only 32kB RAM and 128 kB Flash, a frame buffer, and at least an 1/10 screen sized buffer for rendering.
- OS, External memory and GPU are supported but not required.
**Widgets, Styles, Layouts and more**
- 30+ built-in [Widgets](https://docs.lvgl.io/master/widgets/index.html):  Button, Label, Slider, Chart, Keyboard, Meter, Arc, Table and many more.
- Flexible [Style system](https://docs.lvgl.io/master/overview/style.html) with  ~100 style properties to customize any part of the widgets in any state.
- [Flexbox](https://docs.lvgl.io/master/layouts/flex.html) and [Grid](https://docs.lvgl.io/master/layouts/grid.html)-like layouts engines to automatically size and position the widgets in a responsive way.
- 30+ built-in [Widgets](https://docs.lvgl.io/master/details/widgets/index.html):  Button, Label, Slider, Chart, Keyboard, Meter, Arc, Table and many more.
- Flexible [Style system](https://docs.lvgl.io/master/details/common-widget-features/styles/style.html) with  ~100 style properties to customize any part of the widgets in any state.
- [Flexbox](https://docs.lvgl.io/master/details/common-widget-features/layouts/flex.html) and [Grid](https://docs.lvgl.io/master/details/common-widget-features/layouts/grid.html)-like layouts engines to automatically size and position the widgets in a responsive way.
- Texts are rendered with UTF-8 encoding supporting CJK, Thai, Hindi, Arabic, Persian writing systems.
- Word wrapping, kerning, text scrolling, sub-pixel rendering, Pinyin-IME Chinese input, Emojis in texts.
- Rendering engine supporting animations, anti-aliasing, opacity, smooth scrolling, shadows, image transformation, etc  
- Supports Mouse, Touchpad, Keypad, Keyboard, External buttons, Encoder [Input devices](https://docs.lvgl.io/master/porting/indev.html).
- [Multiple display](https://docs.lvgl.io/master/overview/display.html#multiple-display-support) support.
- Supports Mouse, Touchpad, Keypad, Keyboard, External buttons, Encoder [Input devices](https://docs.lvgl.io/master/details/main-modules/indev.html).
- [Multiple display](https://docs.lvgl.io/master/details/main-modules/display/overview.html#how-many-displays-can-lvgl-use) support.
**Binding and Build Support**
- [MicroPython Binding](https://blog.lvgl.io/2019-02-20/micropython-bindings) exposes LVGL API
- [PikaScript Binding](https://blog.lvgl.io/2022-08-24/pikascript-and-lvgl) python on MCU lighter and easier.
- No custom build system is used. You can build LVGL as you build the other files of your project.
- Support for Make and [CMake](https://docs.lvgl.io/master/integration/building/cmake.html) is included out of the box.
- [Develop on PC](https://docs.lvgl.io/master/integration/ide/pc-simulator.html) and use the same UI code on embedded hardware.
- Support for Make and [CMake](https://docs.lvgl.io/master/details/integration/building/cmake.html) is included out of the box.
- [Develop on PC](https://docs.lvgl.io/master/details/integration/ide/pc-simulator.html) and use the same UI code on embedded hardware.
- Convert the C UI code to HTML file with our [Emscripten port](https://github.com/lvgl/lv_web_emscripten).
**Docs, Tools, and Services**
- Detailed [Documentation](https://docs.lvgl.io/) with [100+ simple examples](https://docs.lvgl.io/master/index.html)
- Detailed [Documentation](https://docs.lvgl.io/) with [100+ simple examples](https://docs.lvgl.io/master/examples.html)
- [Services](https://lvgl.io/services) such as User interface design, Implementation and Consulting to make UI development simpler and faster.
## :heart: Sponsor
@ -88,17 +88,17 @@ If someone implements or fixes an issue labeled as [Sponsored](https://github.co
[![Sponsors of LVGL](https://opencollective.com/lvgl/organizations.svg?width=600)](https://opencollective.com/lvgl)
**Individuals supporting LVGL**<br>
[![Backers of LVGL](https://opencollective.com/lvgl/individuals.svg?width=600)](https://opencollective.com/lvgl)
[![Backers of LVGL](https://contrib.rocks/image?repo=lvgl/lvgl&max=48)](https://opencollective.com/lvgl)
## :package: Packages
LVGL is available as:
- [Arduino library](https://docs.lvgl.io/master/integration/framework/arduino.html)
- [Arduino library](https://docs.lvgl.io/master/details/integration/framework/arduino.html)
- [PlatformIO package](https://registry.platformio.org/libraries/lvgl/lvgl)
- [Zephyr library](https://docs.lvgl.io/master/integration/os/zephyr.html)
- [Zephyr library](https://docs.lvgl.io/master/details/integration/os/zephyr.html)
- [ESP-IDF(ESP32) component](https://components.espressif.com/components/lvgl/lvgl)
- [NXP MCUXpresso component](https://www.nxp.com/design/software/embedded-software/lvgl-open-source-graphics-library:LITTLEVGL-OPEN-SOURCE-GRAPHICS-LIBRARY)
- [NuttX library](https://docs.lvgl.io/master/integration/os/nuttx.html)
- [RT-Thread RTOS](https://docs.lvgl.io/master/integration/os/rt-thread.html)
- [NuttX library](https://docs.lvgl.io/master/details/integration/os/nuttx.html)
- [RT-Thread RTOS](https://docs.lvgl.io/master/details/integration/os/rt-thread.html)
- CMSIS-Pack
- [RIOT OS package](https://doc.riot-os.org/group__pkg__lvgl.html#details)
@ -378,7 +378,7 @@ lv_obj_align(rtl_label, LV_ALIGN_LEFT_MID, 5, 0);
lv_obj_t * cz_label = lv_label_create(lv_screen_active());
lv_label_set_text(cz_label,
"嵌入式系统Embedded System\n是一种嵌入机械或电气系统内部、具有专一功能和实时计算性能的计算机系统。");
lv_obj_set_style_text_font(cz_label, &lv_font_simsun_16_cjk, 0);
lv_obj_set_style_text_font(cz_label, &lv_font_source_han_sans_sc_16_cjk, 0);
lv_obj_set_width(cz_label, 310);
lv_obj_align(cz_label, LV_ALIGN_BOTTOM_LEFT, 5, -5);
```
@ -403,10 +403,10 @@ rtl_label.set_style_text_font(lv.font_dejavu_16_persian_hebrew, 0)
rtl_label.set_width(310)
rtl_label.align(lv.ALIGN.LEFT_MID, 5, 0)
font_simsun_16_cjk = lv.font_load("S:../../assets/font/lv_font_simsun_16_cjk.fnt")
font_hans_sans_16_cjk = lv.font_load("S:../../assets/font/lv_font_source_han_sans_sc_16_cjk.fnt")
cz_label = lv.label(lv.screen_active())
cz_label.set_style_text_font(font_simsun_16_cjk, 0)
cz_label.set_style_text_font(font_hans_sans_16_cjk, 0)
cz_label.set_text("嵌入式系统Embedded System\n是一种嵌入机械或电气系统内部、具有专一功能和实时计算性能的计算机系统。")
cz_label.set_width(310)
cz_label.align(lv.ALIGN.BOTTOM_LEFT, 5, -5)
@ -419,25 +419,25 @@ This list will guide you to get started with LVGL step-by-step.
**Get Familiar with LVGL**
1. Check the [Online demos](https://lvgl.io/demos) to see LVGL in action (3 minutes)
2. Read the [Introduction](https://docs.lvgl.io/master/intro/index.html) page of the documentation (5 minutes)
3. Get familiar with the basics on the [Quick overview](https://docs.lvgl.io/master/get-started/quick-overview.html) page (15 minutes)
1. Check the [Online demos](https://lvgl.io/demos) to see LVGL in action (3 minutes).
2. Read the [Introduction](https://docs.lvgl.io/master/intro/index.html) page of the documentation (5 minutes).
3. Get familiar with the basics on the [Quick overview](https://docs.lvgl.io/master/intro/getting_started.html#lvgl-basics) page (15 minutes).
**Start to Use LVGL**
4. Set up a [Simulator](https://docs.lvgl.io/master/integration/ide/pc-simulator.html#simulator) (10 minutes)
5. Try out some [Examples](https://github.com/lvgl/lvgl/tree/master/examples)
6. Port LVGL to a board. See the [Porting](https://docs.lvgl.io/master/porting/index.html) guide or check the ready to use [Projects](https://github.com/lvgl?q=lv_port_)
4. Set up a [Simulator](https://docs.lvgl.io/master/details/integration/ide/pc-simulator.html#simulator) (10 minutes).
5. Try out some [Examples](https://github.com/lvgl/lvgl/tree/master/examples).
6. Port LVGL to a board. See the [Porting](https://docs.lvgl.io/master/details/integration/adding-lvgl-to-your-project/index.html) guide or check out the ready-to-use [Projects](https://github.com/lvgl?q=lv_port_).
**Become a Pro**
7. Read the [Overview](https://docs.lvgl.io/master/overview/index.html) page to get a better understanding of the library (2-3 hours)
8. Check the documentation of the [Widgets](https://docs.lvgl.io/master/widgets/index.html) to see their features and usage
7. Read the [Main-Modules](https://docs.lvgl.io/master/details/main-modules/index.html) page to get a better understanding of the library (2-3 hours)
8. Check the documentation of the [Widgets](https://docs.lvgl.io/master/details/widgets/index.html) to see their features and usage
**Get Help and Help Others**
9. If you have questions go to the [Forum](http://forum.lvgl.io/)
10. Read the [Contributing](https://docs.lvgl.io/master/CONTRIBUTING.html) guide to see how you can help to improve LVGL (15 minutes)
10. Read the [Contributing](https://docs.lvgl.io/master/contributing/index.html) guide to see how you can help to improve LVGL (15 minutes)
## :handshake: Services
@ -457,7 +457,7 @@ Check out our [Demos](https://lvgl.io/demos) as reference. For more information
## :star2: Contributing
LVGL is an open project and contribution is very welcome. There are many ways to contribute from simply speaking about your project, through writing examples, improving the documentation, fixing bugs or even hosting your own project under the LVGL organization.
For a detailed description of contribution opportunities visit the [Contributing](https://docs.lvgl.io/master/CONTRIBUTING.html) section of the documentation.
For a detailed description of contribution opportunities visit the [Contributing](https://docs.lvgl.io/master/contributing/index.html) section of the documentation.
More than 300 people already left their fingerprint in LVGL. Be one them! See you here! :slightly_smiling_face:

View File

@ -1,6 +1,6 @@
{
"name": "lvgl",
"version": "9.2.2",
"version": "9.3.0",
"keywords": "graphics, gui, embedded, tft, lvgl",
"description": "Graphics library to create embedded GUI with easy-to-use graphical elements, beautiful visual effects and low memory footprint. It offers anti-aliasing, opacity, and animations using only one frame buffer.",
"repository": {

View File

@ -1,5 +1,5 @@
name=lvgl
version=9.2.2
version=9.3.0
author=kisvegabor
maintainer=kisvegabor,embeddedt,pete-pjb
sentence=Full-featured Graphics Library for Embedded Systems

File diff suppressed because it is too large Load Diff

View File

@ -7,8 +7,8 @@
#define LVGL_VERSION_H
#define LVGL_VERSION_MAJOR 9
#define LVGL_VERSION_MINOR 2
#define LVGL_VERSION_PATCH 2
#define LVGL_VERSION_MINOR 3
#define LVGL_VERSION_PATCH 0
#define LVGL_VERSION_INFO ""
#endif /* LVGL_VERSION_H */

Some files were not shown because too many files have changed in this diff Show More