190 Commits

Author SHA1 Message Date
Kuba Szczodrzyński
fb04b1830e [release] v0.8.0
Some checks failed
Lint check / Lint with clang-format (push) Has been cancelled
Lint check / Lint with black (push) Has been cancelled
PlatformIO Publish / publish (push) Has been cancelled
2022-07-26 11:11:52 +02:00
Kuba Szczodrzyński
9509194bd0 [beken-72xx] Correct sys_config.h path 2022-07-26 11:11:14 +02:00
Kuba Szczodrzyński
60322a243a [boards] Fix missing vendor field in generic boards 2022-07-26 11:10:45 +02:00
Kuba Szczodrzyński
4ed7067537 [boards] Add generic definitions for each family 2022-07-25 19:59:53 +02:00
Kuba Szczodrzyński
69086e8fba [boards] Rename small/large base boards to show size 2022-07-25 19:58:16 +02:00
Kuba Szczodrzyński
a4b63bb037 [tools] Make util/markdown.py pre-Python 3.10 compatible 2022-07-21 23:08:53 +02:00
Kuba Szczodrzyński
5ffb2f6619 [boards] Add BW15 board definition, update boardgen 2022-07-21 23:08:49 +02:00
Kuba Szczodrzyński
41eaf9b9e4 [realtek-ambz2] Add initial AmebaZ2 support 2022-07-21 23:08:45 +02:00
Kuba Szczodrzyński
28bb777399 [core] Move family config to separate dir, define Realtek parent 2022-07-21 23:08:39 +02:00
Kuba Szczodrzyński
f375a35cc8 [core] Move library include wrappers to common 2022-07-21 23:08:39 +02:00
Kuba Szczodrzyński
1d41d84083 [boards] Move common partitions to base JSON 2022-07-21 23:08:28 +02:00
Kuba Szczodrzyński
357be177fc [core] Make WiFi sleep & TX power methods weak 2022-07-12 21:12:54 +02:00
Kuba Szczodrzyński
23c3335de8 [beken-72xx] Use Hostapd MD5 implementation 2022-07-12 13:05:02 +02:00
Kuba Szczodrzyński
963b164783 [beken-72xx] Define struct ip_addr as IPv4 2022-07-12 13:01:46 +02:00
Kuba Szczodrzyński
0c22a02641 [beken-72xx] Use mbedTLS MD5 implementation 2022-07-12 12:48:27 +02:00
Kuba Szczodrzyński
10cb5c2c76 [core] Add missing C++ stdlib includes 2022-07-12 12:48:02 +02:00
Kuba Szczodrzyński
6d36c9ef7b [boards] Add remaining WB2x and WB3x boards 2022-07-11 16:42:45 +02:00
Kuba Szczodrzyński
aed97a5e92 [boards] Add remaining WR2x and WR3x boards 2022-07-11 14:23:10 +02:00
Kuba Szczodrzyński
b6008fc9bb [docs] Add family flashing guides 2022-07-11 12:03:28 +02:00
Kuba Szczodrzyński
f9359679ad [docs] Add Getting started guide 2022-07-11 10:54:16 +02:00
Kuba Szczodrzyński
052d7be1a9 [beken-72xx] Move to GNU++11 2022-07-10 20:18:12 +02:00
Kuba Szczodrzyński
ead577a116 [release] v0.7.0
Some checks failed
Lint check / Lint with clang-format (push) Has been cancelled
Lint check / Lint with black (push) Has been cancelled
PlatformIO Publish / publish (push) Has been cancelled
2022-07-10 19:50:07 +02:00
Kuba Szczodrzyński
ccf7d972ce [beken-72xx] Implement WiFi events 2022-07-10 19:49:14 +02:00
Kuba Szczodrzyński
b2df9e6a8b [beken-72xx] Use chip ID based on MAC address 2022-07-07 18:01:35 +02:00
Kuba Szczodrzyński
e37014ebd6 [beken-72xx] Wrap BkDriverFlash for correct partition offsets 2022-07-07 17:45:58 +02:00
Kuba Szczodrzyński
c96ef2ff7a [beken-72xx] Add draft BK7231N support 2022-07-07 17:18:25 +02:00
Kuba Szczodrzyński
c19dd0d87e [beken-72xx] Fix WiFi using DHCP 2022-07-07 17:15:52 +02:00
Kuba Szczodrzyński
02f972bd5f [boards] Add CB2S board definition 2022-07-07 14:57:35 +02:00
Kuba Szczodrzyński
15facd8866 [realtek-ambz] Fix reading MAC address without WiFi enabled 2022-07-05 13:16:51 +02:00
Kuba Szczodrzyński
cf584c3bd6 [tools] Fix link2bin with long command line 2022-07-04 22:37:25 +02:00
Kuba Szczodrzyński
4744351964 [core] Allow changing SDK, logger & Serial output ports 2022-07-04 13:56:03 +02:00
Kuba Szczodrzyński
31b753ab5a [core] Allow configuring silencing of SDK output 2022-07-04 13:55:58 +02:00
Kuba Szczodrzyński
3cb944dde2 [realtek-ambz] Implement SoftwareSerial class 2022-07-03 22:54:18 +02:00
Kuba Szczodrzyński
1b4265f522 [docs] Add TODO list 2022-07-03 19:50:27 +02:00
Kuba Szczodrzyński
5d16338faa [realtek-ambz] Add missing #define 2022-07-03 19:48:24 +02:00
Kuba Szczodrzyński
673b8233e5 [realtek-ambz] Refactor Serial class 2022-07-03 19:15:33 +02:00
Kuba Szczodrzyński
0dd2e2583b [core] Rename init() to initArduino() 2022-07-03 16:49:46 +02:00
Kuba Szczodrzyński
c19f24cbfd [beken-72xx] Implement WiFi Access Point mode 2022-07-01 19:16:48 +02:00
Kuba Szczodrzyński
cfb6830d95 [beken-72xx] Revert scanning before connecting 2022-07-01 19:15:14 +02:00
Kuba Szczodrzyński
27dea356cf [beken-72xx] Fix station with static IP 2022-07-01 19:14:41 +02:00
Kuba Szczodrzyński
352a425c4f [beken-72xx] Wait for init_thread to start TCP/IP 2022-07-01 18:49:14 +02:00
Kuba Szczodrzyński
4beaa79d02 [beken-72xx] Revert to standard station config struct 2022-07-01 18:48:11 +02:00
Kuba Szczodrzyński
e54eab83f2 [beken-72xx] Use station data structs in WiFiData 2022-07-01 16:17:48 +02:00
Kuba Szczodrzyński
e74a491b4a [core] Move SSID & passphrase validation to common 2022-07-01 15:36:49 +02:00
Kuba Szczodrzyński
a9415c1db7 [core] Fix compilation and linking on Linux 2022-07-01 12:47:32 +02:00
Kuba Szczodrzyński
a83959ab5f [release] v0.6.1
Some checks failed
Lint check / Lint with clang-format (push) Has been cancelled
Lint check / Lint with black (push) Has been cancelled
PlatformIO Publish / publish (push) Has been cancelled
2022-06-30 21:22:12 +02:00
Kuba Szczodrzyński
b1896002e5 [boards] Add missing URL field in generic-native.json 2022-06-30 21:21:29 +02:00
Kuba Szczodrzyński
cc39de9b04 [core] Fix beken-72xx-arduino.py formatting 2022-06-30 20:47:54 +02:00
Kuba Szczodrzyński
a286b5d067 [release] v0.6.0
Some checks failed
Lint check / Lint with clang-format (push) Has been cancelled
Lint check / Lint with black (push) Has been cancelled
PlatformIO Publish / publish (push) Has been cancelled
2022-06-30 20:34:38 +02:00
Kuba Szczodrzyński
f071f57abf [beken-72xx] Enable mDNS responder, set IGMP flag on netif 2022-06-30 20:33:08 +02:00
Kuba Szczodrzyński
0e0fe334cd [beken-72xx] Scan networks before connecting, if needed 2022-06-30 20:30:52 +02:00
Kuba Szczodrzyński
23410c618d [beken-72xx] Mark SSL client as broken 2022-06-30 19:35:43 +02:00
Kuba Szczodrzyński
b44898f08d [core] Update verbose messages in MbedTLSClient 2022-06-30 19:34:45 +02:00
Kuba Szczodrzyński
165f356439 [core] Fix MbedTLSClient memory leak 2022-06-30 19:33:56 +02:00
Kuba Szczodrzyński
1d0df2936b [beken-72xx] Increase main task stack size 2022-06-30 19:32:37 +02:00
Kuba Szczodrzyński
1684d63e04 [beken-72xx] Fix lwip_ioctl() given wrong argument size 2022-06-30 16:28:29 +02:00
Kuba Szczodrzyński
cf5dfb43d6 [beken-72xx] Fix WiFi station connection 2022-06-29 19:00:15 +02:00
Kuba Szczodrzyński
ded6638ef6 [beken-72xx] Implement broken WiFi station 2022-06-28 22:49:28 +02:00
Kuba Szczodrzyński
a8228851d9 [realtek-ambz] Make WiFi SDK code less verbose 2022-06-27 21:04:22 +02:00
Kuba Szczodrzyński
633289def6 [realtek-ambz] Fix reporting invalid networks after scanning 2022-06-27 21:04:19 +02:00
Kuba Szczodrzyński
f4ff13d6b7 [realtek-ambz] Move WiFiClient and WiFiServer to NetUtils library 2022-06-27 21:04:15 +02:00
Kuba Szczodrzyński
0493ec2245 [beken-72xx] Implement WiFi scanning 2022-06-27 13:03:52 +02:00
Kuba Szczodrzyński
4c6bbb8aae [realtek-ambz] Simplify WiFi scan result handler 2022-06-27 13:01:06 +02:00
Kuba Szczodrzyński
b625f636be [libs] Fix WiFiMulti compiling with debugging enabled 2022-06-27 12:57:33 +02:00
Kuba Szczodrzyński
3bfd62d075 [boards] Update BK7231T partition layout 2022-06-26 19:12:12 +02:00
Kuba Szczodrzyński
b405adb359 [realtek-ambz] Add a wrapper around WiFi::mode() 2022-06-26 18:10:13 +02:00
Kuba Szczodrzyński
accf37de39 [core] Specify toolchain prefix in board.json 2022-06-26 16:04:49 +02:00
Kuba Szczodrzyński
582eed3be8 [core] Fix return types for some methods, check feature flags 2022-06-26 16:03:30 +02:00
Kuba Szczodrzyński
35d5ec03a3 [core] Fix platform.py for frameworks without package 2022-06-26 16:00:55 +02:00
Kuba Szczodrzyński
737c627d44 [boards] Add generic-native board template 2022-06-26 14:42:43 +02:00
Kuba Szczodrzyński
84a3120c7f [docs] Support generic boards in update_docs.py 2022-06-26 14:41:55 +02:00
Kuba Szczodrzyński
99b9ed1181 [docs] Make update_docs.py errors clearer, check for build.variant 2022-06-26 14:41:22 +02:00
Kuba Szczodrzyński
0d636a3285 [docs] Clarify family configuration variables 2022-06-25 10:19:43 +02:00
Kuba Szczodrzyński
79ccd47f71 [beken-72xx] Fix compilation without WiFi implemented 2022-06-25 10:19:20 +02:00
Kuba Szczodrzyński
3ffc70abe5 [realtek-ambz] Fix reading chip MAC address from eFuse 2022-06-24 21:47:00 +02:00
Kuba Szczodrzyński
f4f2eda481 [docs] Fix RTL8710BX clock speed & chip ID 2022-06-24 21:13:58 +02:00
Kuba Szczodrzyński
f4b2c74b0e [realtek-ambz] Fix issues without ADC2, use correct 468k linker script 2022-06-24 21:13:35 +02:00
Kuba Szczodrzyński
111e5a66b6 [core] Fix import errors on latest PIO Core 2022-06-24 21:11:19 +02:00
Kuba Szczodrzyński
b90723130d [boards] Add BW12 board, update boardgen to v0.4.2 2022-06-24 20:05:44 +02:00
Kuba Szczodrzyński
e6179761d4 [boards] Remove unneeded linker scripts 2022-06-24 20:04:16 +02:00
Kuba Szczodrzyński
b371fd3468 [tools] Fix merge_dicts for d2 immutability 2022-06-24 12:18:36 +02:00
Kuba Szczodrzyński
c8fccdbb47 [realtek-ambz] Move common WiFi code to LT API 2022-06-23 23:30:28 +02:00
Kuba Szczodrzyński
4876401809 [beken-72xx] Implement Serial classes 2022-06-23 17:06:44 +02:00
Kuba Szczodrzyński
45af7c188a [beken-72xx] Add UF2 uploading based on bk7231tools 2022-06-23 14:23:22 +02:00
Kuba Szczodrzyński
236e9ccda6 [beken-72xx] Generate UF2 firmware images 2022-06-23 13:32:31 +02:00
Kuba Szczodrzyński
94e8b9f87e [beken-72xx] Fix suppressing SDK output during init 2022-06-22 23:37:12 +02:00
Kuba Szczodrzyński
c9580d6627 [core] Fix hexdump() line formatting 2022-06-22 23:36:36 +02:00
Kuba Szczodrzyński
87929373e2 [realtek-ambz] Declare all wrapped printf() methods 2022-06-21 23:42:02 +02:00
Kuba Szczodrzyński
4e2aec9ced [tools] Fix link2bin issues when having spaces in project name 2022-06-21 19:25:44 +02:00
Kuba Szczodrzyński
fa7957f5e2 [beken-72xx] Fix linking with SDK framework 2022-06-21 18:53:02 +02:00
Kuba Szczodrzyński
4f15805246 [beken-72xx] Implement analogRead() 2022-06-21 18:49:12 +02:00
Kuba Szczodrzyński
cf67c815e9 [docs] Update LT API main page 2022-06-20 21:43:06 +02:00
Kuba Szczodrzyński
5533dc807f [beken-72xx] Implement Wiring core, digital I/O and PWM 2022-06-20 21:34:11 +02:00
Kuba Szczodrzyński
ac2aabe6e3 [beken-72xx] Implement API reboot() and getCpuFreq() 2022-06-20 21:29:02 +02:00
Kuba Szczodrzyński
c6a428ddd4 [core] Rename PinInfo features fields 2022-06-20 21:28:32 +02:00
Kuba Szczodrzyński
a83a845d5a [realtek-ambz] Move common digital/analog utils into core 2022-06-20 21:28:24 +02:00
Kuba Szczodrzyński
c91b188f96 [beken-72xx] Fix Arduino delay(), fix reading heap size 2022-06-20 15:54:20 +02:00
Kuba Szczodrzyński
53a6f4593e [core] Add macros for wrapping and disabling SDK printf() 2022-06-20 15:54:13 +02:00
Kuba Szczodrzyński
0dda769d0f [beken-72xx] Add preliminary Arduino framework core 2022-06-19 23:53:15 +02:00
Kuba Szczodrzyński
848df066c4 [boards] Add WB2L variant definition 2022-06-19 23:42:40 +02:00
Kuba Szczodrzyński
b4005d8bad [realtek-ambz] Standardize all stdio output with printf library 2022-06-19 23:30:40 +02:00
Kuba Szczodrzyński
34c0df2761 [core] Disable FAL info logging 2022-06-19 18:38:22 +02:00
Kuba Szczodrzyński
cedfc2c8db [core] Fix compilation warnings 2022-06-19 17:33:02 +02:00
Kuba Szczodrzyński
c9fe63ec7b [core] Add defines for enabling implemented features 2022-06-19 17:31:14 +02:00
Kuba Szczodrzyński
2fedcb61b5 [core] Migrate Flash library to common code based on FAL 2022-06-19 17:23:16 +02:00
Kuba Szczodrzyński
272b033253 [core] Provide entire flash as "root" partition 2022-06-19 14:18:13 +02:00
Kuba Szczodrzyński
cae03d54d6 [core] Move startup code to libretuya/common 2022-06-19 14:13:51 +02:00
Kuba Szczodrzyński
e70f1a591f [core] Migrate to auto-generated variant definitions 2022-06-18 23:19:28 +02:00
Kuba Szczodrzyński
0e768ac6e4 [core] Move Arduino flags to arduino-common 2022-06-18 21:57:51 +02:00
Kuba Szczodrzyński
bc056eaca2 [docs] Add auto-generated module support page 2022-06-18 21:08:29 +02:00
Kuba Szczodrzyński
a6ad84a3b8 [docs] Use note tag and include-markdown 2022-06-18 21:05:31 +02:00
Kuba Szczodrzyński
a5b953dc80 [core] Add a prefix to ChipFamily enum 2022-06-18 21:04:17 +02:00
Kuba Szczodrzyński
d446b05387 [boards] Add WB2L pinout 2022-06-15 23:23:45 +02:00
Kuba Szczodrzyński
e864e5ef24 [boards] Move PCB definitions to subdir, use base IC pinouts 2022-06-15 23:20:59 +02:00
Kuba Szczodrzyński
e669507759 [beken-72xx] Support C++11 2022-06-14 18:54:31 +02:00
Kuba Szczodrzyński
e50c04cbe1 [beken-72xx] Don't init everything by default, make it quiet 2022-06-14 18:18:49 +02:00
Kuba Szczodrzyński
56dd57f4a0 [beken-72xx] Remove unused components 2022-06-14 17:28:00 +02:00
Kuba Szczodrzyński
f2abb564c7 [beken-72xx] Fix BK7231S 1.0.5 bootloader compatibility 2022-06-14 16:33:13 +02:00
Kuba Szczodrzyński
4e7abb2350 [beken-72xx] Move family fixups to parent 2022-06-14 16:11:25 +02:00
Kuba Szczodrzyński
540e499389 [beken-72xx] Implement SDK binary building 2022-06-14 15:39:28 +02:00
Kuba Szczodrzyński
191a2bdd2a [docs] Add debugging info for RPi 4, fix GPIO numbers 2022-06-14 11:43:07 +02:00
Kuba Szczodrzyński
4d1c8357b4 [realtek-ambz] Move C++ flags to SDK builder 2022-06-13 17:08:20 +02:00
Kuba Szczodrzyński
85b5b1df91 [beken-72xx] Add base BK7231 support config 2022-06-13 16:58:46 +02:00
Kuba Szczodrzyński
c3e2c105d4 [core] Build with properties from Family object 2022-06-12 12:49:04 +02:00
Kuba Szczodrzyński
dba602a081 [tools] Add Beken binary crypto utility 2022-06-11 23:00:00 +02:00
Kuba Szczodrzyński
c3f2ce57f0 [tools] Move functions to utilities, add universal CRC16 class 2022-06-11 18:25:10 +02:00
Kuba Szczodrzyński
bbf8e0b6b6 [realtek-ambz] Better handle WiFi events 2022-06-06 21:45:18 +02:00
Kuba Szczodrzyński
03ab020dc8 [realtek-ambz] Fix ADC reading 2022-06-06 21:44:54 +02:00
Kuba Szczodrzyński
9c1f3225a6 [core] Refactor LibreTuyaAPI into separate units 2022-06-06 16:17:02 +02:00
Kuba Szczodrzyński
f72dd3b7d7 [realtek-ambz] Fix PWM output 2022-06-06 14:52:11 +02:00
Kuba Szczodrzyński
48f6210607 [realtek-ambz] Add gpioRecover() to disable SWD 2022-06-04 22:32:36 +02:00
Kuba Szczodrzyński
6f9be2b139 [realtek-ambz] Fix float abi linking errors 2022-06-04 20:40:09 +02:00
Kuba Szczodrzyński
3217525873 [realtek-ambz] Implement attachInterruptParam 2022-06-04 20:39:24 +02:00
Kuba Szczodrzyński
e26972bd2f [core] Fix OTA not resetting buffer after partial writes 2022-06-04 16:36:37 +02:00
Kuba Szczodrzyński
bf31533306 [core] Add LT.getCpuFreq() method 2022-06-04 16:36:13 +02:00
Kuba Szczodrzyński
0ca0577667 [core] Add cbuf and StreamString libraries 2022-06-04 14:12:36 +02:00
Kuba Szczodrzyński
0e797e7e04 [core] Fix logger color formatting 2022-06-04 13:37:29 +02:00
Kuba Szczodrzyński
a661ef3a3f [core] Add more compat code 2022-06-04 13:37:15 +02:00
Kuba Szczodrzyński
17dc1dcf8c [core] Allow specifying custom UF2 firmware name and version 2022-06-03 12:11:12 +02:00
Kuba Szczodrzyński
4c27aa57b1 [core] Add MD5 library 2022-06-03 12:08:41 +02:00
Kuba Szczodrzyński
a21c07fa03 [release] v0.5.0
Some checks failed
Lint check / Lint with clang-format (push) Has been cancelled
Lint check / Lint with black (push) Has been cancelled
PlatformIO Publish / publish (push) Has been cancelled
2022-06-02 23:06:11 +02:00
Kuba Szczodrzyński
bdffa7ef53 [core] Add UF2-based uploader 2022-06-02 23:05:35 +02:00
Kuba Szczodrzyński
22d40825bb [tools] Extract common utilities to separate modules 2022-06-02 22:22:23 +02:00
Kuba Szczodrzyński
50f26f546c [core] Use term "family" instead of "platform" 2022-06-02 22:22:19 +02:00
Kuba Szczodrzyński
9c7ea46ec3 [core] Build UF2 OTA image after linking 2022-06-02 22:21:51 +02:00
Kuba Szczodrzyński
5b4cf53d8a [tools] uf2ota: embed build date in extension tags 2022-06-02 14:14:16 +02:00
Kuba Szczodrzyński
79a701a4d4 [tools] uf2ota: fix for Python 3.7, fix Windows path compatibility 2022-06-02 14:12:03 +02:00
Kuba Szczodrzyński
81897e634c [realtek-ambz] Export both OTA images after linking 2022-06-01 21:41:04 +02:00
Kuba Szczodrzyński
3e11da4dd4 [docs] Add resources page 2022-05-31 12:06:24 +02:00
Kuba Szczodrzyński
12aa7fef04 [docs] Move sections from README to docs, add uf2families.json 2022-05-31 11:54:05 +02:00
Kuba Szczodrzyński
1ea6420bbc [core] Add Update library 2022-05-30 22:31:04 +02:00
Kuba Szczodrzyński
f3f1f36525 [core] Add uf2ota library source 2022-05-30 22:23:40 +02:00
Kuba Szczodrzyński
dee9a98cc3 [core] Update OTA API 2022-05-30 21:59:22 +02:00
Kuba Szczodrzyński
3345ce3fb9 [docs] Add missing documents to SUMMARY.md 2022-05-28 20:13:01 +02:00
Kuba Szczodrzyński
de70583838 [core] Put full UF2 Family ID in ChipFamily 2022-05-28 20:09:10 +02:00
Kuba Szczodrzyński
a43a737004 [realtek-ambz] Implement API class methods, fix CPU clock 2022-05-28 19:41:44 +02:00
Kuba Szczodrzyński
1f6899354f [core] Add LT class API methods 2022-05-28 19:39:43 +02:00
Kuba Szczodrzyński
9110a0c47e [docs] Document the UF2 OTA format 2022-05-28 14:48:07 +02:00
Kuba Szczodrzyński
b549790798 [tools] Implement UF2 binary patching, add dumping images 2022-05-28 14:47:45 +02:00
Kuba Szczodrzyński
5df430f3be [tools] Add UF2 OTA writer tool 2022-05-27 20:53:08 +02:00
Kuba Szczodrzyński
f3e8bcd74a [realtek-ambz] Add KVS partition, update boardgen 2022-05-27 15:29:46 +02:00
Kuba Szczodrzyński
4b050e11cf [core] Add dynamic FAL_PART_TABLE generation 2022-05-27 15:29:21 +02:00
Kuba Szczodrzyński
7ddbc09564 [core] Workaround LwIPmDNS compilation 2022-05-26 14:24:51 +02:00
Kuba Szczodrzyński
d3d62f80fd [realtek-ambz] Fix WiFi encryption type conversion 2022-05-26 14:24:29 +02:00
Kuba Szczodrzyński
bc7dbe6eec [api] Fix hexdump() default parameters 2022-05-25 12:27:52 +02:00
Kuba Szczodrzyński
e625f55353 [api] Add hexdump() utility 2022-05-24 17:55:12 +02:00
Kuba Szczodrzyński
aeebff9d5d [realtek-ambz] Fix WiFiEvents linking when not needed 2022-05-24 17:47:45 +02:00
Kuba Szczodrzyński
9a3c077ef1 [core] Add FlashDB KVS library 2022-05-24 17:43:30 +02:00
Kuba Szczodrzyński
91ae692058 [core] Fix gathering external library dependencies 2022-05-24 17:30:14 +02:00
Kuba Szczodrzyński
ad590d1eb2 [release] v0.4.0
Some checks failed
Lint check / Lint with clang-format (push) Has been cancelled
Lint check / Lint with black (push) Has been cancelled
PlatformIO Publish / publish (push) Has been cancelled
2022-05-23 14:21:19 +02:00
Kuba Szczodrzyński
8b00358901 [core] Add lwIP-based mDNS responder library 2022-05-23 14:20:41 +02:00
Kuba Szczodrzyński
bf4d8bb9be [realtek-ambz] Update to external lwIP v2.0.0 2022-05-23 12:49:18 +02:00
Kuba Szczodrzyński
157dd2f407 [realtek-ambz] Move to external lwIP v1.4.1 2022-05-23 12:49:18 +02:00
Kuba Szczodrzyński
1dc47878d4 [core] Allow using external framework parts 2022-05-18 20:57:09 +02:00
Kuba Szczodrzyński
36e4b6fd45 [core] Write manifests when installing packages 2022-05-18 20:47:40 +02:00
Kuba Szczodrzyński
36d9a6e7e4 [realtek-ambz] Support WiFi events 2022-05-17 19:27:35 +02:00
Kuba Szczodrzyński
b7cceed4d3 [core] Create POSIX utils module 2022-05-16 15:54:52 +02:00
Kuba Szczodrzyński
694c06e7f5 [core] Allow using "arduino" as framework 2022-05-16 15:53:51 +02:00
Kuba Szczodrzyński
12338747bf [realtek-ambz] Add Wire library 2022-05-14 21:47:56 +02:00
Kuba Szczodrzyński
f4f9788f68 [github] Add board readme generated with boardgen 2022-05-14 20:20:39 +02:00
Kuba Szczodrzyński
b9cdcad262 [core] Add boardgen submodule 2022-05-14 14:21:15 +02:00
Kuba Szczodrzyński
e4cd2ddec8 [core] Split boards as base files 2022-05-10 17:48:41 +02:00
Kuba Szczodrzyński
1477649a50 [core] Move LibreTuyaAPI to core directory 2022-05-09 15:41:22 +02:00
Kuba Szczodrzyński
2e80469ab3 [core] Fix and enable SSL client support 2022-05-08 18:43:10 +02:00
Kuba Szczodrzyński
ccf63a4cdb [realtek-ambz] Add platform configs to fixups 2022-05-08 18:42:19 +02:00
Kuba Szczodrzyński
b464871f73 [realtek-ambz] Remove PolarSSL completely, fix errno 2022-05-08 18:41:56 +02:00
Kuba Szczodrzyński
e44834a95e [docs] Fix mkdocs deployment, again, again 2022-05-07 20:47:34 +02:00
Kuba Szczodrzyński
4efefc5c6c [docs] Fix mkdocs deployment, again 2022-05-07 20:38:13 +02:00
Kuba Szczodrzyński
dfd852b2db [docs] Fix mkdocs deployment 2022-05-07 20:36:41 +02:00
Kuba Szczodrzyński
afa7141ceb [docs] Add Doxygen 2022-05-07 20:35:03 +02:00
450 changed files with 30723 additions and 4860 deletions

View File

@@ -1,11 +1,12 @@
name: Deploy docs on GitHub Pages
on:
push:
branches:
- master
jobs:
build:
docs:
name: Deploy docs
runs-on: ubuntu-latest
steps:
@@ -17,5 +18,5 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CONFIG_FILE: mkdocs.yml
EXTRA_PACKAGES: build-base
EXTRA_PACKAGES: build-base doxygen
REQUIREMENTS: docs/requirements.txt

7
.gitignore vendored
View File

@@ -252,3 +252,10 @@ cython_debug/
# End of https://www.toptal.com/developers/gitignore/api/c,c++,visualstudiocode,python
.vscode/settings.json
# mkdocs
xml/
ltapi/
ltambz/
hashChanges.yaml
.piopm

2
.gitmodules vendored Normal file
View File

@@ -0,0 +1,2 @@
[submodule "tools/boardgen"]
url = https://github.com/kuba2k2/boardgen

201
README.md
View File

@@ -2,26 +2,27 @@
<div align="center" markdown>
[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/kuba2k2/libretuya/docs?label=docs)](https://kuba2k2.github.io/libretuya/)
![GitHub last commit](https://img.shields.io/github/last-commit/kuba2k2/libretuya)
[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/kuba2k2/libretuya/Deploy%20docs%20on%20GitHub%20Pages?label=docs&logo=markdown)](https://kuba2k2.github.io/libretuya/)
![GitHub last commit](https://img.shields.io/github/last-commit/kuba2k2/libretuya?logo=github)
[![Code style: clang-format](https://img.shields.io/badge/code%20style-clang--format-purple.svg)](https://github.com/psf/black)
[![Code style: clang-format](https://img.shields.io/badge/code%20style-clang--format-purple.svg)](.clang-format)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
[![Discord](https://img.shields.io/discord/967863521511608370?color=%235865F2&label=Discord&logo=discord&logoColor=white)](https://discord.gg/SyGCB9Xwtf)
[![PlatformIO Registry](https://badges.registry.platformio.org/packages/kuba2k2/platform/libretuya.svg)](https://registry.platformio.org/platforms/kuba2k2/libretuya)
![RTL8710BN](https://img.shields.io/badge/-rtl8710bn-blue)
![BK7231](https://img.shields.io/badge/-bk7231-blue)
<!-- [![PlatformIO Registry](https://badges.registry.platformio.org/packages/kuba2k2/platform/libretuya.svg)](https://registry.platformio.org/platforms/kuba2k2/libretuya) -->
</div>
PlatformIO development platform for IoT modules manufactured by Tuya Inc.
The main goal of this project is to provide a usable build environment for IoT developers. While also providing vendor SDKs as PlatformIO cores,
the project focuses on developing working Arduino-compatible cores for supported platforms. The cores are inspired by Espressif's official core for ESP32,
which should make it easier to port/run existing ESP apps on Tuya IoT (and 3-rd party) platforms.
the project focuses on developing working Arduino-compatible cores for supported families. The cores are inspired by Espressif's official core for ESP32,
which should make it easier to port/run existing ESP apps on Tuya IoT (and 3-rd party) modules.
LibreTuya also provides a common interface for all platform implementations. The interface is based on ESP32 official libraries.
LibreTuya also provides a common interface for all family implementations. The interface is based on ESP32 official libraries.
**Note:** this project is work-in-progress.
@@ -34,168 +35,40 @@ LibreTuya also provides a common interface for all platform implementations. The
## Board List
A (mostly) complete* list of Tuya wireless module boards.
&nbsp; | Module Name | MCU | Flash | RAM | Pins** | Wi-Fi | BLE | Platform name
------------------------------|------------------------------------------------------------------------------------------------|-------------------------|-------|----------|-------------|-------|-----|---------------
❌ | [WB1S](https://developer.tuya.com/en/docs/iot/wb1s?id=K9duevbj3ol4x) | BK7231T @ 120 MHz | 2 MiB | 256 KiB | 18 (11 I/O) | ✔️ | ✔️ | -
❌ | [WB2L](https://developer.tuya.com/en/docs/iot/wb2l-datasheet?id=K9duegc9bualu) | BK7231T @ 120 MHz | 2 MiB | 256 KiB | 7 (5 I/O) | ✔️ | ✔️ | -
❌ | [WB2S](https://developer.tuya.com/en/docs/iot/wb2s-module-datasheet?id=K9ghecl7kc479) | BK7231T @ 120 MHz | 2 MiB | 256 KiB | 11 (8 I/O) | ✔️ | ✔️ | -
❌ | [WB3L](https://developer.tuya.com/en/docs/iot/wb3l-module-datasheet?id=K9duiggw2v8sp) | BK7231T @ 120 MHz | 2 MiB | 256 KiB | 16 (12 I/O) | ✔️ | ✔️ | -
❌ | [WB3S](https://developer.tuya.com/en/docs/iot/wb3s-module-datasheet?id=K9dx20n6hz5n4) | BK7231T @ 120 MHz | 2 MiB | 256 KiB | 16 (11 I/O) | ✔️ | ✔️ | -
❌ | [WB3S-IPEX](https://developer.tuya.com/en/docs/iot/wb3sipex-module-datasheet?id=K9irq0laun21z) | BK7231T @ 120 MHz | 2 MiB | 256 KiB | 16 (11 I/O) | ✔️ | ✔️ | -
❌ | [WB8P](https://developer.tuya.com/en/docs/iot/wb8p-module-datasheet?id=K9fwx4f89tvzd) | BK7231T @ 120 MHz | 2 MiB | 256 KiB | 10 (8 I/O) | ✔️ | ✔️ | -
❌ | [WBLC5](https://developer.tuya.com/en/docs/iot/wblc5-module-datasheet?id=K9duilns1f3gi) | BK7231T @ 120 MHz | 2 MiB | 256 KiB | 6 (3 I/O) | ✔️ | ✔️ | -
❌ | [WBLC9](https://developer.tuya.com/en/docs/iot/wblc9-module-datasheet?id=K9hgglry2jp5h) | BK7231T @ 120 MHz | 2 MiB | 256 KiB | 8 (6 I/O) | ✔️ | ✔️ | -
❌ | [CB1S](https://developer.tuya.com/en/docs/iot/cb1s-module-datasheet?id=Kaij1abmwyjq2) | BK7231N @ 120 MHz | 2 MiB | 256 KiB | 18 (11 I/O) | ✔️ | ✔️ | -
❌ | [CB2L](https://developer.tuya.com/en/docs/iot/cb2l-module-datasheet?id=Kai2eku1m3pyl) | BK7231N @ 120 MHz | 2 MiB | 256 KiB | 7 (5 I/O) | ✔️ | ✔️ | -
❌ | [CB2S](https://developer.tuya.com/en/docs/iot/cb2s-module-datasheet?id=Kafgfsa2aaypq) | BK7231N @ 120 MHz | 2 MiB | 256 KiB | 11 (8 I/O) | ✔️ | ✔️ | -
❌ | [CB3L](https://developer.tuya.com/en/docs/iot/cb3l-module-datasheet?id=Kai51ngmrh3qm) | BK7231N @ 120 MHz | 2 MiB | 256 KiB | 16 (11 I/O) | ✔️ | ✔️ | -
❌ | [CB3S](https://developer.tuya.com/en/docs/iot/cb3s?id=Kai94mec0s076) | BK7231N @ 120 MHz | 2 MiB | 256 KiB | 22 (14 I/O) | ✔️ | ✔️ | -
❌ | [CB3S-NL](https://developer.tuya.com/en/docs/iot/CB3S-NL-module-datasheet?id=Kbaesan0vyoms) | BK7231NL (?) @ 120 MHz | 2 MiB | 256 KiB | 22 (14 I/O) | ✔️ | ✔️ | -
❌ | [CB3SE](https://developer.tuya.com/en/docs/iot/CB3SE-Module-Datasheet?id=Kanoiluul7nl2) | BK7231N @ 120 MHz | 2 MiB | 256 KiB | 22 (17 I/O) | ✔️ | ✔️ | -
❌ | [CB8P](https://developer.tuya.com/en/docs/iot/cb8p-module-datasheet?id=Kahvig14r1yk9) | BK7231N @ 120 MHz | 2 MiB | 256 KiB | 10 (8 I/O) | ✔️ | ✔️ | -
❌ | [CBLC5](https://developer.tuya.com/en/docs/iot/cblc5-module-datasheet?id=Ka07iqyusq1wm) | BK7231N @ 120 MHz | 2 MiB | 256 KiB | 6 (3 I/O) | ✔️ | ✔️ | -
❌ | [CBLC9](https://developer.tuya.com/en/docs/iot/cblc9-module-datasheet?id=Ka42cqnj9r0i5) | BK7231N @ 120 MHz | 2 MiB | 256 KiB | 8 (6 I/O) | ✔️ | ✔️ | -
❌ | [CBU](https://developer.tuya.com/en/docs/iot/cbu-module-datasheet?id=Ka07pykl5dk4u) | BK7231N @ 120 MHz | 2 MiB | 256 KiB | 21 (18 I/O) | ✔️ | ✔️ | -
❌ | [CBU-IPEX](https://developer.tuya.com/en/docs/iot/cbuipex-module-datasheet?id=Kaedsyurckrhu) | BK7231N @ 120 MHz | 2 MiB | 256 KiB | 21 (18 I/O) | ✔️ | ✔️ | -
❌ | [CBU-NL](https://developer.tuya.com/en/docs/iot/CBU-NL-module-datasheet?id=Kbaeq6j53y0yg) | BK7231N (?) @ 120 MHz | 2 MiB | 256 KiB | 21 (18 I/O) | ✔️ | ✔️ | -
❌ | [WR1](https://developer.tuya.com/en/docs/iot/wifiwr1module?id=K9605tc0k90t3) | RTL8710BN @ 125 MHz | 1 MiB | 256 KiB | 18 (11 I/O) | ✔️ | ❌ | -
❌ | [WR1-IPEX](https://developer.tuya.com/en/docs/iot/wifiwr1ipexmodule?id=K9605t977tx5u) | RTL8710BN @ 125 MHz | 1 MiB | 256 KiB | 18 (11 I/O) | ✔️ | ❌ | -
❌ | [WR1E](https://developer.tuya.com/en/docs/iot/wr1e?id=K96smbbeycxtf) | RTL8710BN @ 125 MHz | 2 MiB | 256 KiB | 18 (11 I/O) | ✔️ | ❌ | -
❌ | [WR2](https://developer.tuya.com/en/docs/iot/wifiwr2module?id=K9605tko0juc3) | RTL8710BN @ 125 MHz | 2 MiB | 256 KiB | 11 (8 I/O) | ✔️ | ❌ | -
❌ | [WR2E](https://developer.tuya.com/en/docs/iot/wr2e?id=K97scnsjhue4h) | RTL8710BN @ 125 MHz | 2 MiB | 256 KiB | 11 (8 I/O) | ✔️ | ❌ | -
❌ | [WR2L](https://developer.tuya.com/en/docs/iot/wifiwr2lmodule?id=K9605tnbj7gva) | RTL8710BX @ 62.5 MHz | 2 MiB | 256 KiB | 7 (5 I/O) | ✔️ | ❌ | -
❌ | [WR2LE](https://developer.tuya.com/en/docs/iot/wr2le?id=K9eio9y9e8i8c) | RTL8710BX @ 62.5 MHz | 2 MiB | 256 KiB | 7 (5 I/O) | ✔️ | ❌ | -
[`wr3`](boards/wr3/README.md) | [WR3](https://developer.tuya.com/en/docs/iot/wr3-module-datasheet?id=K9g3ainzbj9z1) | RTL8710BN @ 125 MHz | 2 MiB | 256 KiB | 16 (12 I/O) | ✔️ | ❌ | `realtek-ambz`
❌ | [WR3E](https://developer.tuya.com/en/docs/iot/wr3e-module-datasheet?id=K9elwlqbfosbc) | RTL8710BN @ 125 MHz | 2 MiB | 256 KiB | 16 (12 I/O) | ✔️ | ❌ | -
❌ | [WR3L](https://developer.tuya.com/en/docs/iot/wifiwr3lmodule?id=K9605tt0kveqm) | RTL8710BX @ 125 MHz (?) | 2 MiB | 256 KiB | 16 (12 I/O) | ✔️ | ❌ | -
❌ | [WR3LE](https://developer.tuya.com/en/docs/iot/wr3le?id=K986l7a1ha8tm) | RTL8710BX @ 62.5 MHz | 2 MiB | 256 KiB | 16 (12 I/O) | ✔️ | ❌ | -
❌ | [WR3N](https://developer.tuya.com/en/docs/iot/wr3n-datasheet?id=K98zdx31ztdge) | RTL8710BN @ 125 MHz | 2 MiB | 256 KiB | 16 (10 I/O) | ✔️ | ❌ | -
❌ | [WR4](https://developer.tuya.com/en/docs/iot/wifiwr4module?id=K9605tvu78p3e) | RTL8710BN @ 125 MHz | 1 MiB | 256 KiB | 16 (12 I/O) | ✔️ | ❌ | -
❌ | [WR5E](https://developer.tuya.com/en/docs/iot/wr5e?id=K986r9pxqxa8i) | RTL8710BX @ 62.5 MHz | 2 MiB | 256 KiB | 15 (12 I/O) | ✔️ | ❌ | -
❌ | [WR6-H](https://developer.tuya.com/en/docs/iot/wr6h-module-datasheet?id=K9pork8eeowgl) | RTL8710BN @ 125 MHz | 2 MiB | 256 KiB | 18 (12 I/O) | ✔️ | ❌ | -
❌ | [WR6](https://developer.tuya.com/en/docs/iot/wr6-datasheet?id=K97rp45u6gff9) | RTL8710BN @ 125 MHz | 2 MiB | 256 KiB | 18 (12 I/O) | ✔️ | ❌ | -
❌ | [WRG1](https://developer.tuya.com/en/docs/iot/wr6-datasheet?id=K97rp45u6gff9) | RTL8711AM @ 166 MHz | 4 MiB | 2048 KiB | 25 (20 I/O) | ✔️ | ❌ | -
❌ | [XR1](https://developer.tuya.com/en/docs/iot/xr1?id=K9lq3y9xo0zkx) | XR809 @ 160 MHz | 2 MiB | 384 KiB | 18 (11 I/O) | ✔️ | ❌ | -
❌ | [XR1-IPEX](https://developer.tuya.com/en/docs/iot/xr1ipex-module-datasheet?id=K9razqu9gqele) | XR809 @ 160 MHz | 2 MiB | 384 KiB | 18 (11 I/O) | ✔️ | ❌ | -
❌ | [XR3](https://developer.tuya.com/en/docs/iot/xr3-datasheet?id=K98s9168qi49g) | XR809 @ 160 MHz | 2 MiB | 384 KiB | 22 (17 I/O) | ✔️ | ❌ | -
❌ | [WE1S](https://developer.tuya.com/en/docs/iot/wifie1smodule?id=K9605thnvg3e7) | ESP8266EX @ 80/160 MHz | 2 MiB | 36 KiB | 18 (11 I/O) | ✔️ | ❌ | -
❌ | [WE2L](https://developer.tuya.com/en/docs/iot/wifie2lmodule?id=K9605ud0gkjmh) | ESP8285 @ 80/160 MHz | 1 MiB | 50 KiB | 7 (5 I/O) | ✔️ | ❌ | -
❌ | [WE2S](https://developer.tuya.com/en/docs/iot/wifie2smodule?id=K9605u79tgxug) | ESP8285 @ 80/160 MHz | 1 MiB | 50 KiB | 11 (8 I/O) | ✔️ | ❌ | -
❌ | [WE3L](https://developer.tuya.com/en/docs/iot/wifie3lpinmodule?id=K9605uj1ar87n) | ESP8266 @ 80/160 MHz | 2 MiB | 50 KiB | 16 (12 I/O) | ✔️ | ❌ | -
❌ | [WE3S](https://developer.tuya.com/en/docs/iot/wifie3smodule?id=K9605ua1cx9tv) | ESP8266 @ 80/160 MHz | 2 MiB | 50 KiB | 16 (12 I/O) | ✔️ | ❌ | -
❌ | [WE3SE](https://developer.tuya.com/en/docs/iot/we3se?id=K97qv6ab7oh8d) | ESP32 @ 240 MHz | 4 MiB | 520 KiB | 22 (17 I/O) | ✔️ | ✔️ | -
❌ | [WE5P](https://developer.tuya.com/en/docs/iot/wifie5pmodule?id=K9605um3dtjbx) | ESP8266 @ 80/160 MHz | 1 MiB | 50 KiB | 15 (11 I/O) | ✔️ | ❌ | -
\* Only modules featuring at least Wi-Fi. WBR, JWBR, CR, (TY)JW and (TY)LC Series are not included here
** I/O count includes GPIOs, ADCs, PWM outputs and UART, but doesn't count CEN/RST and power pins.
## Project structure
```
arduino/
├─ <platform name>/ Arduino Core for specific SoC
│ ├─ cores/ Wiring core files
│ ├─ libraries/ Supported built-in platform libraries
├─ libretuya/
│ ├─ api/ LibreTuya API (interfaces + LT class) for Arduino frameworks
│ ├─ common/ Units common to all platforms
│ ├─ compat/ Fixes for compatibility with ESP32 framework
│ ├─ libraries/ Built-in platform-independent libraries
boards/
├─ <board name>/ Board-specific code
│ ├─ variant.cpp Arduino variant initialization
│ ├─ variant.h Arduino variant pin configs
├─ <board name>.json PlatformIO board description
builder/
├─ frameworks/ Framework builders for PlatformIO
│ ├─ <platform name>-sdk.py Vanilla SDK build system
│ ├─ <platform name>-arduino.py Arduino Core build system
├─ arduino-common.py Builder to provide ArduinoCore-API and LibreTuya APIs
├─ main.py Main PlatformIO builder
├─ utils.py SCons utils used during the build
docs/ Project documentation, guides, tips, etc.
platform/
├─ <platform name>/ Platform-specific configurations
│ ├─ bin/ Binary blobs (bootloaders, etc.)
│ ├─ fixups/ Code fix-ups to replace SDK parts
│ ├─ ld/ Linker scripts
│ ├─ openocd/ OpenOCD configuration files
tools/
├─ <tool name>/ Tools used during the build
platform.json PlatformIO manifest
platform.py Custom PlatformIO script
```
## Platforms
A list of platforms currently available in this project.
Platform name | Supported MCU(s) | Arduino Core | Source SDK (PIO framework)
---------------|------------------------------------------------------------------------|--------------|--------------------------------------------------------------------------
`realtek-ambz` | Realtek [AmebaZ](https://www.amebaiot.com/en/amebaz/) SoC (`RTL87xxB`) | ✔️ | `framework-realtek-amb1` ([amb1_sdk](https://github.com/ambiot/amb1_sdk))
### Realtek Ameba
The logic behind naming of Realtek chips and their series took me some time to figure out:
- RTL8xxxA - Ameba1/Ameba Series
- RTL8xxxB - AmebaZ Series
- RTL8xxxC - AmebaZ2/ZII Series
- RTL8xxxD - AmebaD Series
As such, there are numerous CPUs with the same numbers but different series, which makes them require different code and SDKs.
- [RTL8195AM](https://www.realtek.com/en/products/communications-network-ics/item/rtl8195am)
- RTL8710AF (found in amb1_arduino)
- [RTL8711AM](https://www.realtek.com/en/products/communications-network-ics/item/rtl8711am)
- [RTL8710BN](https://www.realtek.com/en/products/communications-network-ics/item/rtl8710bn)
- RTL8710BX (found in Tuya product pages)
- RTL8710B? (found in amb1_sdk)
- RTL8711B? (found in amb1_sdk)
- [RTL8710CM](https://www.realtek.com/en/products/communications-network-ics/item/rtl8710cm)
- RTL8722CSM (found in ambd_arduino)
- RTL8720DN (found in ambd_arduino)
- [RTL8721DM](https://www.realtek.com/en/products/communications-network-ics/item/rtl8721dm)
- RTL8722DM (found in ambd_arduino)
- and probably many more
Different Ameba series are not compatible with each other. Apparently, there isn't an official public SDK for AmebaZ that can support C++ properly.
See [Boards & CPU list](https://kuba2k2.github.io/libretuya/docs/supported/).
## Arduino Core support status
Note: this list will probably change with each functionality update.
&nbsp; | `realtek-ambz`
--------------------|---------------
Core functions | ✔️
GPIO/PWM/IRQ | ✔️/❓/✔️
Analog input |
UART I/O | ✔️
Flash I/O | ❓
**CORE LIBRARIES** |
SoftwareSerial |
SPI | ❌
Wire | ❌
**OTHER LIBRARIES** |
Wi-Fi STA/AP/Mixed | ✔️
Wi-Fi Client (SSL) | ✔️ (✔️)
Wi-Fi Server | ✔️
Wi-Fi Events |
IPv6 | ❌
HTTP Client (SSL) | ✔️ (❌)
HTTP Server | ✔️
NVS / Preferences | ❌
SPIFFS | ❌
BLE | -
HTTP | ❌
NTP | ❌
OTA | ❌
MDNS |
MQTT | ✅
SD | ❌
&nbsp; | `realtek-ambz` | `beken-72xx`
--------------------|----------------|-------------
Core functions | ✔️ | ✔️
GPIO/PWM/IRQ | ✔️/✔️/✔️ | ❓/✔️/❌
Analog input (ADC) | ✔️ | ✔️
Serial | ✔️ | ✔️
Serial (extra) | 0, 1, 2 | 1, 2
Flash I/O | ✔️ | ✔️
**CORE LIBRARIES** | |
SoftwareSerial | ✔️ | ❌
SPI | ❌ | ❌
Wire | ❗ | ❌
**OTHER LIBRARIES** | |
Wi-Fi STA/AP/Mixed | ✔️ | ✔️
Wi-Fi Events | ✔️ | ✔️
TCP Client (SSL) | ✔️ (✔️) | ✔️ (❗)
TCP Server | ✔️ | ✔️
IPv6 | ❌ | ❌
HTTP Client (SSL) | ✔️ (✔️) |
HTTP Server | ✔️ | ✔️
NVS / Preferences | ❌ | ❌
SPIFFS | ❌ |
BLE | - | ❌
NTP | ❌ | ❌
OTA | ✔️ |
MDNS | ✔️ | ✔️
MQTT | ✅ | ❌
SD | ❌ | ❌
Symbols:

59
SUMMARY.md Normal file
View File

@@ -0,0 +1,59 @@
* [Home](README.md)
* [Getting started](docs/getting-started.md)
* [💻 Boards & CPU list](docs/supported.md)
* [✔️ Implementation status](docs/implementation-status.md)
* [🔧 Configuration](docs/config.md)
* [📁 Project structure](docs/project-structure.md)
* 🔖 Code reference
* [LibreTuya API](docs/reference/lt-api.md)
* [LT class reference](ltapi/class_libre_tuya.md)
* [Common methods](ltapi/_libre_tuya_a_p_i_8h.md)
* [Wiring custom methods](ltapi/_libre_tuya_custom_8h.md)
* [Logger](ltapi/lt__logger_8h.md)
* [Chip & family IDs](ltapi/_chip_type_8h_source.md)
* [POSIX utilities](ltapi/lt__posix__api_8h.md)
* Common API
* [FS](ltapi/classfs_1_1_f_s.md)
* [Preferences](ltapi/class_i_preferences.md)
* [SoftwareSerial](ltapi/class_software_serial.md)
* [WiFi API](ltapi/class_wi_fi_class.md)
* [TCP Client](ltapi/class_i_wi_fi_client.md)
* [SSL Client](ltapi/class_i_wi_fi_client_secure.md)
* [TCP Server](ltapi/class_i_wi_fi_server.md)
* [LibreTuya libraries](docs/libs-built-in.md)
* [base64](ltapi/classbase64.md)
* [Flash](ltapi/class_flash_class.md)
* [HTTPClient](ltapi/class_h_t_t_p_client.md)
* [mDNS](ltapi/classm_d_n_s.md)
* NetUtils
* [ssl/MbedTLSClient](ltapi/class_mbed_t_l_s_client.md)
* [IPv6Address](ltapi/classarduino_1_1_i_pv6_address.md)
* [LwIPRxBuffer](ltapi/class_lw_i_p_rx_buffer.md)
* [Update](ltapi/class_update_class.md)
* [WebServer](ltapi/class_web_server.md)
* [WiFiMulti](ltapi/class_wi_fi_multi.md)
* [Third party libraries](docs/libs-3rd-party.md)
* Full documentation
* [Classes](ltapi/classes.md)
* [Functions](ltapi/functions.md)
* [Macros](ltapi/macros.md)
* [File list](ltapi/files.md)
* [✈️ OTA format](docs/ota/README.md)
* [uf2ota.py tool](docs/ota/uf2ota.md)
* [uf2ota.h library](docs/ota/library.md)
* [uf2ota.h reference](ltapi/uf2ota_8h.md)
* Families
* Beken BK72xx
* [General info](docs/platform/beken-72xx/README.md)
* [Flashing](docs/platform/beken-72xx/flashing.md)
* Realtek AmebaZ Series
* [General info](docs/platform/realtek/README.md)
* [Flashing (AmebaZ)](docs/platform/realtek-ambz/flashing.md)
* [Debugging](docs/platform/realtek/debugging.md)
* [Exception decoder](docs/platform/realtek/exception-decoder.md)
* C library
* [Built-in functions](docs/platform/realtek-ambz/stdlib.md)
* [Memory management](docs/platform/realtek-ambz/memory-management.md)
* [All supported boards](boards/)
* [📓 TODO](TODO.md)
* [🔗 Resources](docs/resources.md)

47
TODO.md Normal file
View File

@@ -0,0 +1,47 @@
# TODO list
## General
### New families
- BL602
- RTL8710A
- RTL8720C
- RTL8720D
- W600 and/or W800
- LN8825
- host-native family
### Tools
- move all UF2 assembling/uploading/processing tools (as well as `uf2ota` C library) to a separate repository, possibly rewriting parts of it again. Make these tools CLI-usable
- write OpenOCD flashers, using uf2ota library + FAL for partitions (same repo as above)
### Serial
- configuration of RX/TX pins
- SoftwareSerial library - receiving + Beken family
### Other
- watchdog API
- `Preferences` library
- test/fix IPv6 on different families
- what is `PowerManagement` at all? probably useless -> remove
## BK7231
- WiFi events
- implement OTA
- fix WiFi on BK7231N, test other functionality
- add generic board definition
- fix SSL (mbedTLS)
- I2C (Wire)
- SPI
- BLE
## RTL8710B
- add generic board definition
- move to GNU++11 (and verify that it works) - take all stdio functions from stdio.h
- rewrite most of Wiring (it was copied from `ambd_arduino`, and is ugly)

View File

@@ -0,0 +1,30 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-14. */
#pragma once
#ifdef __cplusplus
#include "WCharacterFixup.h"
#endif
#include <api/ArduinoAPI.h>
#include <core/LibreTuyaAPI.h>
// Include family-specific code
#include "WVariant.h"
// Include board variant
#include "variant.h"
// Choose the main UART output port
#ifndef LT_UART_DEFAULT_PORT
#if defined(PIN_SERIAL2_TX)
#define LT_UART_DEFAULT_PORT 2
#else
#define LT_UART_DEFAULT_PORT 1
#endif
#endif
// Define available serial ports
#ifdef __cplusplus
#include "SerialClass.h"
#include <core/SerialExtern.h>
#endif

View File

@@ -0,0 +1,134 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-19. */
#include <LibreTuyaAPI.h>
// can't include <flash.h> as it collides with <Flash.h> on Windows -_-
#define REG_FLASH_BASE 0x00803000
#define REG_FLASH_OPERATE_SW (REG_FLASH_BASE + 0 * 4)
#define REG_FLASH_RDID (REG_FLASH_BASE + 4 * 4)
#define FLASH_BUSY_SW (0x01UL << 31)
#define FLASH_WP_VALUE (0x01UL << 30)
#define FLASH_OP_SW (0x01UL << 29)
#define FLASH_OP_TYPE_POS 24
#define FLASH_OP_RDID 20
extern "C" {
#include <flash_pub.h>
#include <param_config.h>
#include <sys_ctrl.h>
#include <sys_rtos.h>
#include <wlan_ui_pub.h>
extern uint8_t system_mac[];
} // extern "C"
void LibreTuya::restart() {
bk_reboot();
}
/* CPU-related */
ChipType LibreTuya::getChipType() {
uint8_t chipId = *(uint8_t *)(SCTRL_CHIP_ID);
return CHIP_TYPE_ENUM(FAMILY, chipId);
}
const char *LibreTuya::getChipModel() {
return STRINGIFY_MACRO(MCU);
}
uint32_t LibreTuya::getChipId() {
uint8_t mac[6];
cfg_load_mac(mac); // force loading MAC from TLV (ignore user-set WiFi MAC)
return (mac[3]) | (mac[4] << 8) | (mac[5] << 16);
}
uint8_t LibreTuya::getChipCores() {
return 1;
}
const char *LibreTuya::getChipCoreType() {
return "ARM968E-S";
}
uint32_t LibreTuya::getCpuFreq() {
return configCPU_CLOCK_HZ;
}
uint32_t LibreTuya::getCycleCount() {
// TODO
return 0;
}
/* Flash memory utilities */
FlashId LibreTuya::getFlashChipId() {
uint32_t data = (FLASH_OP_RDID << FLASH_OP_TYPE_POS) | FLASH_OP_SW | FLASH_WP_VALUE;
REG_WRITE(REG_FLASH_OPERATE_SW, data);
while (REG_READ(REG_FLASH_OPERATE_SW) & FLASH_BUSY_SW) {}
FlashId id = {
.manufacturerId = REG_RD8(REG_FLASH_RDID, 2),
.chipId = REG_RD8(REG_FLASH_RDID, 1),
.chipSizeId = REG_RD8(REG_FLASH_RDID, 0),
};
return id;
}
/* Memory management */
uint32_t LibreTuya::getRamSize() {
return 256 * 1024;
}
uint32_t LibreTuya::getHeapSize() {
#if configDYNAMIC_HEAP_SIZE
extern unsigned char _empty_ram;
#if CFG_SOC_NAME == SOC_BK7231N
return (0x00400000 + 192 * 1024) - (uint32_t)(&_empty_ram);
#else
return (0x00400000 + 256 * 1024) - (uint32_t)(&_empty_ram);
#endif
#else
return configTOTAL_HEAP_SIZE;
#endif
}
uint32_t LibreTuya::getFreeHeap() {
return xPortGetFreeHeapSize();
}
uint32_t LibreTuya::getMinFreeHeap() {
return xPortGetMinimumEverFreeHeapSize();
}
uint32_t LibreTuya::getMaxAllocHeap() {
return 0;
}
/* OTA-related */
uint8_t LibreTuya::otaGetStoredIndex() {
return 1;
}
bool LibreTuya::otaSupportsDual() {
return false;
}
bool LibreTuya::otaHasImage1() {
return true;
}
bool LibreTuya::otaHasImage2() {
return false;
}
bool LibreTuya::otaSwitch(bool force) {
return true;
}
/* Global instance */
LibreTuya LT;

View File

@@ -0,0 +1,79 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-23. */
#include "SerialClass.h"
extern "C" {
#include <uart_pub.h>
extern void bk_send_byte(uint8_t uport, uint8_t data);
extern void uart_hw_set_change(uint8_t uport, bk_uart_config_t *uart_config);
extern int uart_rx_callback_set(int uport, uart_callback callback, void *param);
} // extern "C"
#ifdef PIN_SERIAL1_TX
SerialClass Serial1(UART1_PORT);
#endif
#ifdef PIN_SERIAL2_TX
SerialClass Serial2(UART2_PORT);
#endif
SerialClass::SerialClass(uint8_t port) {
this->port = port;
this->buf = NULL;
}
static void callback(int port, void *param) {
RingBuffer *buf = (RingBuffer *)param;
buf->store_char(uart_read_byte(port));
}
void SerialClass::begin(unsigned long baudrate, uint16_t config) {
uint8_t dataWidth = ((config & SERIAL_DATA_MASK) >> 8) - 1; // 0x100..0x400 -> 0..3
uint8_t parity = 3 - (config & SERIAL_PARITY_MASK); // 0x3..0x1 -> 0..2
uint8_t stopBits = (config & SERIAL_STOP_BIT_MASK) == SERIAL_STOP_BIT_2; // 0x10..0x30 -> 0..1
bk_uart_config_t cfg = {
.baud_rate = baudrate,
.data_width = (uart_data_width_t)dataWidth,
.parity = (uart_parity_t)parity,
.stop_bits = (uart_stop_bits_t)stopBits,
.flow_control = FLOW_CTRL_DISABLED,
};
if (this->buf) {
this->buf->clear();
} else {
this->buf = new RingBuffer();
}
uart_hw_set_change(port, &cfg);
uart_rx_callback_set(port, callback, this->buf);
}
void SerialClass::end() {
uart_rx_callback_set(port, NULL, NULL);
delete this->buf;
}
int SerialClass::available() {
return buf->available();
}
int SerialClass::peek() {
return buf->peek();
}
int SerialClass::read() {
return buf->read_char();
}
void SerialClass::flush() {
uart_wait_tx_over();
}
size_t SerialClass::write(uint8_t c) {
bk_send_byte(port, c);
return 1;
}

View File

@@ -0,0 +1,38 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-23. */
#pragma once
#include <Arduino.h>
#include <api/HardwareSerial.h>
#include <api/RingBuffer.h>
using namespace arduino;
class SerialClass : public HardwareSerial {
private:
uint8_t port;
RingBuffer *buf;
public:
SerialClass(uint8_t port);
inline void begin(unsigned long baudrate) {
begin(baudrate, SERIAL_8N1);
}
void begin(unsigned long baudrate, uint16_t config);
void end();
int available();
int peek();
int read();
void flush();
size_t write(uint8_t c);
operator bool() {
return !!buf;
}
using Print::write;
};
#define HAS_SERIAL_CLASS 1

View File

@@ -0,0 +1,21 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-18. */
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "sdk_extern.h"
#include "sdk_mem.h"
// allow BDK use its own delay() and let Arduino code use delayMilliseconds()
void delayMilliseconds(unsigned long);
#define delay delayMilliseconds
// from fixups/arch_main.c
extern unsigned char __bk_rf_is_init;
#ifdef __cplusplus
} // extern "C"
#endif

View File

@@ -0,0 +1,34 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-19. */
#include <Arduino.h>
extern "C" {
#include <rtos_pub.h>
#include <sys_rtos.h>
extern int uart_print_port;
} // extern "C"
beken_thread_t mainThread;
void initArduino() {
// set default UART output port
uart_print_port = LT_UART_DEFAULT_PORT - 1;
}
bool startMainTask() {
OSStatus ret = rtos_create_thread(
&mainThread,
THD_APPLICATION_PRIORITY,
"main",
(beken_thread_function_t)main_task,
8192,
NULL
);
if (ret != kNoErr)
return false;
vTaskStartScheduler();
return true;
}

View File

@@ -0,0 +1,30 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-18. */
#pragma once
// for printf() etc (they are wrapped anyway)
#include <stdio.h>
// most stuff is here
#include <include.h>
// for os_printf
#include <uart_pub.h>
// for GPIO names
#include <gpio_pub.h>
// conflict with stl_algobase.h
#undef min
#undef max
// include printf() wrapper disable methods
#include <printf_port.h>
// make non-SDK code call the proper printf()
#undef bk_printf
#undef os_printf
#undef warning_prf
#undef fatal_prf
#define bk_printf printf
#define os_printf printf
#define warning_prf printf
#define fatal_prf printf

View File

@@ -0,0 +1,20 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-18. */
#pragma once
#include <stddef.h>
// Beken SDK is actually pretty good, in terms of declaring
// stdlib functions properly! So no need for any #define hell.
#include <mem_pub.h>
// All the MemMang functions are in stdlib, just wrapped
// during linking.
#include <stdlib.h>
// for memcpy etc.
#include <string.h>
// ...except zalloc, which is apparently not in the stdlib
#define zalloc os_zalloc
#define LT_HEAP_FUNC xPortGetFreeHeapSize

View File

@@ -0,0 +1,32 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-19. */
#include <Arduino.h>
#include <rtos_pub.h>
#include <sys_rtos.h>
void delayMilliseconds(unsigned long ms) {
rtos_delay_milliseconds(ms);
}
void delayMicroseconds(unsigned int us) {
// TODO implement this properly
us /= 10;
volatile uint32_t i, j;
for (i = 0; i < us; i++) {
for (j = 0; j < 100; j++) {}
}
}
unsigned long millis() {
return xTaskGetTickCount() * portTICK_PERIOD_MS;
}
unsigned long micros() {
// TODO implement this properly
return millis() * 1000;
}
void yield() {
vTaskDelay(1);
taskYIELD();
}

View File

@@ -0,0 +1,132 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-20. */
#include <Arduino.h>
#include <pwm_pub.h>
#include <saradc_pub.h>
static GPIO_INDEX pwmToGpio[] = {
GPIO6, // PWM0
GPIO7, // PWM1
GPIO8, // PWM2
GPIO9, // PWM3
GPIO24, // PWM4
GPIO26, // PWM5
};
#if CFG_SOC_NAME == SOC_BK7231N
static GPIO_INDEX adcToGpio[] = {
-1, // ADC0 - VBAT
GPIONUM, // ADC1
GPIONUM, // ADC2
GPIO23, // ADC3
GPIONUM, // ADC4
GPIONUM, // ADC5
GPIONUM, // ADC6
GPIONUM, // ADC7
};
#else
static GPIO_INDEX adcToGpio[] = {
-1, // ADC0 - VBAT
GPIO4, // ADC1
GPIO5, // ADC2
GPIO23, // ADC3
GPIO2, // ADC4
GPIO3, // ADC5
GPIO12, // ADC6
GPIO13, // ADC7
};
#endif
static uint8_t gpioToPwm(GPIO_INDEX gpio) {
for (uint8_t i = 0; i < sizeof(pwmToGpio); i++) {
if (pwmToGpio[i] == gpio)
return i;
}
return 0;
}
static uint8_t gpioToAdc(GPIO_INDEX gpio) {
for (uint8_t i = 0; i < sizeof(adcToGpio); i++) {
if (adcToGpio[i] == gpio)
return i;
}
return 0;
}
static pwm_param_t pwm;
static uint16_t adcData[1];
uint16_t analogReadVoltage(pin_size_t pinNumber) {
PinInfo *pin = pinInfo(pinNumber);
if (!pin)
return 0;
if (!pinSupported(pin, PIN_ADC))
return 0;
UINT32 status;
saradc_desc_t adc;
DD_HANDLE handle;
saradc_config_param_init(&adc);
adc.channel = gpioToAdc(pin->gpio);
adc.mode = ADC_CONFIG_MODE_CONTINUE;
adc.pData = adcData;
adc.data_buff_size = 1;
handle = ddev_open(SARADC_DEV_NAME, &status, (uint32_t)&adc);
if (status)
return 0;
// wait for data
while (!adc.has_data || adc.current_sample_data_cnt < 1) {
delay(1);
}
ddev_control(handle, SARADC_CMD_RUN_OR_STOP_ADC, (void *)false);
ddev_close(handle);
return adcData[0];
}
uint16_t analogReadMaxVoltage(pin_size_t pinNumber) {
return 3300;
}
void analogWrite(pin_size_t pinNumber, int value) {
PinInfo *pin = pinInfo(pinNumber);
if (!pin)
return;
if (!pinSupported(pin, PIN_PWM))
return;
float percent = value * 1.0 / (1 << _analogWriteResolution);
uint32_t dutyCycle = percent * _analogWritePeriod * 26 - 1;
pwm.channel = gpioToPwm(pin->gpio);
#if CFG_SOC_NAME != SOC_BK7231N
pwm.duty_cycle = dutyCycle;
#else
pwm.duty_cycle1 = dutyCycle;
pwm.duty_cycle2 = dutyCycle;
pwm.duty_cycle3 = dutyCycle;
#endif
if (!pinEnabled(pin, PIN_PWM)) {
// enable PWM and set its value
pwm.cfg.bits.en = PWM_ENABLE;
pwm.cfg.bits.int_en = PWM_INT_DIS;
pwm.cfg.bits.mode = PWM_PWM_MODE;
pwm.cfg.bits.clk = PWM_CLK_26M;
pwm.end_value = 26 * _analogWritePeriod - 1;
pwm.p_Int_Handler = NULL;
__wrap_bk_printf_disable();
sddev_control(PWM_DEV_NAME, CMD_PWM_INIT_PARAM, &pwm);
__wrap_bk_printf_enable();
pin->enabled &= ~PIN_GPIO;
pin->enabled |= PIN_PWM;
} else if (value == 0) {
// disable PWM
pwm.cfg.bits.en = PWM_DISABLE;
__wrap_bk_printf_disable();
sddev_control(PWM_DEV_NAME, CMD_PWM_DEINIT_PARAM, &pwm);
__wrap_bk_printf_enable();
pin->enabled &= ~PIN_PWM;
} else {
// update duty cycle
sddev_control(PWM_DEV_NAME, CMD_PWM_SET_DUTY_CYCLE, &pwm);
}
}

View File

@@ -0,0 +1,62 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-20. */
#include <Arduino.h>
void pinMode(pin_size_t pinNumber, PinMode pinMode) {
PinInfo *pin = pinInfo(pinNumber);
if (!pin)
return;
if (!pinSupported(pin, PIN_GPIO))
return;
if (pinEnabled(pin, PIN_PWM))
// disable PWM before using the pin
analogWrite(pinNumber, 0);
if (pinEnabled(pin, PIN_GPIO) && pin->mode == pinMode)
return;
switch (pinMode) {
case INPUT:
gpio_config(pin->gpio, GMODE_INPUT);
break;
case OUTPUT:
gpio_config(pin->gpio, GMODE_OUTPUT);
break;
case INPUT_PULLUP:
gpio_config(pin->gpio, GMODE_INPUT_PULLUP);
break;
case INPUT_PULLDOWN:
gpio_config(pin->gpio, GMODE_INPUT_PULLDOWN);
break;
case OUTPUT_OPENDRAIN:
gpio_config(pin->gpio, GMODE_SET_HIGH_IMPENDANCE);
break;
}
pin->enabled |= PIN_GPIO;
pin->mode = pinMode;
}
void digitalWrite(pin_size_t pinNumber, PinStatus status) {
// verify level is 0 or 1
if (status > HIGH)
return;
PinInfo *pin = pinInfo(pinNumber);
if (!pin)
return;
// pin is not GPIO yet or not OUTPUT; enable or disable input pullup
if (!pinEnabled(pin, PIN_GPIO) || !pinIsOutput(pin)) {
pinMode(pinNumber, status * INPUT_PULLUP);
return;
}
// write the new state
gpio_output(pin->gpio, status);
}
PinStatus digitalRead(pin_size_t pinNumber) {
PinInfo *pin = pinInfo(pinNumber);
if (!pin)
return 0;
// pin is not GPIO yet or not INPUT; change the mode
if (!pinEnabled(pin, PIN_GPIO) || !pinIsOutput(pin))
pinMode(pinNumber, INPUT);
// read the value
return gpio_input(pin->gpio);
}

View File

@@ -0,0 +1,5 @@
/* Copyright (c) Kuba Szczodrzyński 2022-07-11. */
#pragma once
#define LT_MD5_USE_HOSTAPD 1

View File

@@ -0,0 +1,56 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-26. */
#include "WiFiPriv.h"
WiFiClass::WiFiClass() {
data.scanSem = xSemaphoreCreateBinary();
}
WiFiClass::~WiFiClass() {
vSemaphoreDelete(data.scanSem);
}
WiFiStatus eventTypeToStatus(uint8_t type) {
// rw_msg_pub.h:9
switch (type) {
case RW_EVT_STA_IDLE:
return WL_IDLE_STATUS;
case RW_EVT_STA_NO_AP_FOUND:
return WL_NO_SSID_AVAIL;
case RW_EVT_STA_CONNECTING:
case RW_EVT_STA_CONNECTED:
return WL_SCAN_COMPLETED;
case RW_EVT_STA_GOT_IP:
return WL_CONNECTED;
case RW_EVT_STA_PASSWORD_WRONG:
case RW_EVT_STA_ASSOC_FULL:
case RW_EVT_STA_CONNECT_FAILED:
return WL_CONNECT_FAILED;
case RW_EVT_STA_BEACON_LOSE:
return WL_CONNECTION_LOST;
case RW_EVT_STA_DISCONNECTED:
return WL_DISCONNECTED;
}
}
WiFiAuthMode securityTypeToAuthMode(uint8_t type) {
// wlan_ui_pub.h:62
switch (type) {
case BK_SECURITY_TYPE_NONE:
return WIFI_AUTH_OPEN;
case BK_SECURITY_TYPE_WEP:
return WIFI_AUTH_WEP;
case BK_SECURITY_TYPE_WPA_TKIP:
case BK_SECURITY_TYPE_WPA_AES:
return WIFI_AUTH_WPA_PSK;
case BK_SECURITY_TYPE_WPA2_TKIP:
case BK_SECURITY_TYPE_WPA2_AES:
case BK_SECURITY_TYPE_WPA2_MIXED:
return WIFI_AUTH_WPA2_PSK;
case BK_SECURITY_TYPE_WPA3_SAE:
return WIFI_AUTH_WPA3_PSK;
case BK_SECURITY_TYPE_WPA3_WPA2_MIXED:
return WIFI_AUTH_WPA2_WPA3_PSK;
}
return WIFI_AUTH_INVALID;
}

View File

@@ -0,0 +1,10 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-26. */
#pragma once
#include <Arduino.h>
#include <api/WiFi/WiFi.h>
#include "WiFiClient.h"
#include "WiFiClientSecure.h"
#include "WiFiServer.h"

View File

@@ -0,0 +1,112 @@
/* Copyright (c) Kuba Szczodrzyński 2022-07-01. */
#include "WiFiPriv.h"
bool WiFiClass::softAP(const char *ssid, const char *passphrase, int channel, bool ssidHidden, int maxClients) {
if (!enableAP(true))
return WL_CONNECT_FAILED;
if (!validate(ssid, passphrase))
return WL_CONNECT_FAILED;
LT_HEAP_I();
strcpy(AP_CFG->wifi_ssid, ssid);
if (passphrase) {
strcpy(AP_CFG->wifi_key, passphrase);
AP_CFG->security = BK_SECURITY_TYPE_WPA2_MIXED;
} else {
AP_CFG->wifi_key[0] = '\0';
AP_CFG->security = BK_SECURITY_TYPE_NONE;
}
AP_CFG->channel = channel;
AP_CFG->ssid_hidden = ssidHidden;
AP_CFG->max_con = maxClients;
AP_CFG->dhcp_mode = DHCP_SERVER;
AP_CFG->wifi_retry_interval = 100;
LT_I("Creating SoftAP %s", ssid);
__wrap_bk_printf_disable();
OSStatus ret = bk_wlan_start_ap_adv(AP_CFG);
__wrap_bk_printf_enable();
if (ret != 0) {
LT_E("SoftAP failed; ret=%d", ret);
return false;
}
LT_D_WG("Start OK");
return true;
}
bool WiFiClass::softAPConfig(IPAddress localIP, IPAddress gateway, IPAddress subnet) {
if (!localIP) {
localIP = gateway = IPAddress(192, 168, 43, 1);
subnet = IPAddress(255, 255, 255, 0);
}
sprintf(AP_CFG->local_ip_addr, IP_FMT, localIP[0], localIP[1], localIP[2], localIP[3]);
sprintf(AP_CFG->net_mask, IP_FMT, subnet[0], subnet[1], subnet[2], subnet[3]);
sprintf(AP_CFG->gateway_ip_addr, IP_FMT, gateway[0], gateway[1], gateway[2], gateway[3]);
// from wlan_ui.c:1370
if (uap_ip_is_start()) {
uap_ip_down();
ip_address_set(
BK_STATION,
AP_CFG->dhcp_mode,
AP_CFG->local_ip_addr,
AP_CFG->net_mask,
AP_CFG->gateway_ip_addr,
AP_CFG->dns_server_ip_addr
);
uap_ip_start();
}
return true;
}
bool WiFiClass::softAPdisconnect(bool wifiOff) {
return bk_wlan_stop(BK_SOFT_AP) == kNoErr;
}
uint8_t WiFiClass::softAPgetStationNum() {
return 0;
}
IPAddress WiFiClass::softAPIP() {
bk_wlan_get_ip_status(IP_STATUS, BK_SOFT_AP);
IPAddress ip;
ip.fromString(IP_STATUS->ip);
return ip;
}
IPAddress WiFiClass::softAPSubnetMask() {
bk_wlan_get_ip_status(IP_STATUS, BK_SOFT_AP);
IPAddress ip;
ip.fromString(IP_STATUS->mask);
return ip;
}
const char *WiFiClass::softAPgetHostname() {
struct netif *ifs = (struct netif *)net_get_uap_handle();
return netif_get_hostname(ifs);
}
bool WiFiClass::softAPsetHostname(const char *hostname) {
struct netif *ifs = (struct netif *)net_get_uap_handle();
netif_set_hostname(ifs, (char *)hostname);
return true;
}
uint8_t *WiFiClass::softAPmacAddress(uint8_t *mac) {
setMacAddress(mac);
return mac;
}
String WiFiClass::softAPmacAddress(void) {
uint8_t mac[ETH_ALEN];
wifi_get_mac_address((char *)mac, CONFIG_ROLE_AP);
return macToString(mac);
}
const String WiFiClass::softAPSSID(void) {
return AP_CFG->wifi_ssid;
}

View File

@@ -0,0 +1,8 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-27. */
#pragma once
#include <api/WiFi/WiFi.h>
#include <lwip/LwIPClient.h>
typedef LwIPClient WiFiClient;

View File

@@ -0,0 +1,8 @@
/* Copyright (c) Kuba Szczodrzyński 2022-05-04. */
#pragma once
#include <api/WiFi/WiFi.h>
#include <ssl/MbedTLSClient.h>
typedef MbedTLSClient WiFiClientSecure;

View File

@@ -0,0 +1,21 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-26. */
#pragma once
#include <Arduino.h>
extern "C" {
#include <FreeRTOS.h>
#include <semphr.h>
} // extern "C"
typedef struct {
void *configSta;
void *configAp;
unsigned long scannedAt;
SemaphoreHandle_t scanSem;
void *statusIp;
void *statusLink;
} WiFiData;

View File

@@ -0,0 +1,144 @@
/* Copyright (c) Kuba Szczodrzyński 2022-07-10. */
#include "WiFiPriv.h"
#include <vector>
static xQueueHandle wifiEventQueueHandle = NULL;
static xTaskHandle wifiEventTaskHandle = NULL;
static const rw_evt_type eventConnected = RW_EVT_STA_CONNECTED;
// callback for bk_wlan_status_register_cb()
static void wifiStatusCallback(rw_evt_type *pEvent) {
if (wifiEventQueueHandle && wifiEventTaskHandle) {
xQueueSend(wifiEventQueueHandle, pEvent, portMAX_DELAY);
} else {
wifiEventHandler(*pEvent);
}
}
static void wifiEventTask(void *arg) {
rw_evt_type event = RW_EVT_MAX;
for (;;) {
if (xQueueReceive(wifiEventQueueHandle, &event, portMAX_DELAY) == pdTRUE) {
wifiEventHandler(event);
}
}
}
void wifiEventSendArduino(EventId event) {
event = (EventId)(RW_EVT_ARDUINO | event);
wifiStatusCallback((rw_evt_type *)&event);
}
void startWifiTask() {
if (!wifiEventQueueHandle) {
LT_HEAP_I();
wifiEventQueueHandle = xQueueCreate(32, sizeof(rw_evt_type));
LT_HEAP_I();
}
if (!wifiEventTaskHandle) {
LT_HEAP_I();
xTaskCreate(wifiEventTask, "wifievent", 512, NULL, 4, &wifiEventTaskHandle);
LT_HEAP_I();
}
bk_wlan_status_register_cb((FUNC_1PARAM_PTR)wifiStatusCallback);
}
void wifiEventHandler(rw_evt_type event) {
if (!pWiFi)
return; // failsafe
LT_D_WG("WiFi event %u", event);
EventId eventId;
EventInfo eventInfo;
String ssid;
memset(&eventInfo, 0, sizeof(EventInfo));
switch (event) {
case RW_EVT_STA_IDLE:
eventId = ARDUINO_EVENT_WIFI_READY;
break;
case RW_EVT_STA_BEACON_LOSE:
case RW_EVT_STA_PASSWORD_WRONG:
case RW_EVT_STA_NO_AP_FOUND:
case RW_EVT_STA_ASSOC_FULL:
case RW_EVT_STA_DISCONNECTED:
case RW_EVT_STA_CONNECT_FAILED:
eventId = ARDUINO_EVENT_WIFI_STA_DISCONNECTED;
eventInfo.wifi_sta_disconnected.ssid_len = 0;
switch (event) {
case RW_EVT_STA_BEACON_LOSE:
eventInfo.wifi_sta_disconnected.reason = WIFI_REASON_BEACON_TIMEOUT;
break;
case RW_EVT_STA_PASSWORD_WRONG:
eventInfo.wifi_sta_disconnected.reason = WIFI_REASON_AUTH_FAIL;
break;
case RW_EVT_STA_NO_AP_FOUND:
eventInfo.wifi_sta_disconnected.reason = WIFI_REASON_NO_AP_FOUND;
break;
case RW_EVT_STA_ASSOC_FULL:
eventInfo.wifi_sta_disconnected.reason = WIFI_REASON_ASSOC_TOOMANY;
break;
case RW_EVT_STA_DISCONNECTED:
eventInfo.wifi_sta_disconnected.reason = WIFI_REASON_ASSOC_LEAVE;
break;
case RW_EVT_STA_CONNECT_FAILED:
eventInfo.wifi_sta_disconnected.reason = WIFI_REASON_CONNECTION_FAIL;
break;
default:
eventInfo.wifi_sta_disconnected.reason = WIFI_REASON_UNSPECIFIED;
break;
}
break;
case RW_EVT_STA_CONNECTED:
eventId = ARDUINO_EVENT_WIFI_STA_CONNECTED;
ssid = pWiFi->SSID();
eventInfo.wifi_sta_connected.ssid_len = ssid.length();
eventInfo.wifi_sta_connected.channel = pWiFi->channel();
eventInfo.wifi_sta_connected.authmode = pWiFi->getEncryption();
memcpy(eventInfo.wifi_sta_connected.ssid, ssid.c_str(), eventInfo.wifi_sta_connected.ssid_len + 1);
memcpy(eventInfo.wifi_sta_connected.bssid, pWiFi->BSSID(), 6);
break;
case RW_EVT_STA_GOT_IP:
eventId = ARDUINO_EVENT_WIFI_STA_GOT_IP;
eventInfo.got_ip.if_index = 0;
eventInfo.got_ip.ip_changed = true;
eventInfo.got_ip.ip_info.ip.addr = WiFi.localIP();
eventInfo.got_ip.ip_info.netmask.addr = WiFi.subnetMask();
eventInfo.got_ip.ip_info.gw.addr = WiFi.gatewayIP();
break;
case RW_EVT_AP_CONNECTED:
eventId = ARDUINO_EVENT_WIFI_AP_STACONNECTED;
// TODO station MAC
break;
case RW_EVT_AP_DISCONNECTED:
eventId = ARDUINO_EVENT_WIFI_AP_STADISCONNECTED;
// TODO station MAC
break;
case RW_EVT_ARDUINO | ARDUINO_EVENT_WIFI_SCAN_DONE:
eventId = ARDUINO_EVENT_WIFI_SCAN_DONE;
eventInfo.wifi_scan_done.status = 0;
if (pWiFi->scan)
eventInfo.wifi_scan_done.number = pWiFi->scan->count;
eventInfo.wifi_scan_done.scan_id = 0;
break;
default:
if (event < RW_EVT_ARDUINO)
return;
eventId = (EventId)(event - RW_EVT_ARDUINO);
break;
}
pWiFi->postEvent(eventId, eventInfo);
}

View File

@@ -0,0 +1,93 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-26. */
#include "WiFiPriv.h"
bool WiFiClass::modePriv(WiFiMode mode, WiFiModeAction sta, WiFiModeAction ap) {
__wrap_bk_printf_disable();
startWifiTask();
if (mode && !data.statusIp) {
data.configSta = zalloc(sizeof(network_InitTypeDef_st));
data.configAp = zalloc(sizeof(network_InitTypeDef_ap_st));
data.statusIp = malloc(sizeof(IPStatusTypedef));
data.statusLink = malloc(sizeof(LinkStatusTypeDef));
STA_CFG->dhcp_mode = DHCP_CLIENT;
}
if (!__bk_rf_is_init) {
LT_D_WG("Initializing func&app");
func_init_extended();
app_pre_start();
// wait for the init_thread to finish its job
while (xTaskGetHandle("init_thread")) {
LT_V_WG("Waiting for init_thread");
delay(10);
}
LT_D_WG("Success");
__bk_rf_is_init = true;
}
LT_HEAP_I();
if (sta == WLMODE_ENABLE) {
LT_D_WG("Enabling STA");
bk_wlan_sta_init(NULL);
wifiEventSendArduino(ARDUINO_EVENT_WIFI_STA_START);
} else if (sta == WLMODE_DISABLE) {
LT_D_WG("Disabling STA");
bk_wlan_stop(BK_STATION);
wifiEventSendArduino(ARDUINO_EVENT_WIFI_STA_STOP);
}
LT_HEAP_I();
if (ap == WLMODE_ENABLE) {
LT_D_WG("Enabling AP");
bk_wlan_ap_init(NULL);
wifiEventSendArduino(ARDUINO_EVENT_WIFI_AP_START);
} else if (ap == WLMODE_DISABLE) {
LT_D_WG("Disabling AP");
bk_wlan_stop(BK_SOFT_AP);
wifiEventSendArduino(ARDUINO_EVENT_WIFI_AP_STOP);
}
if (!mode) {
free(data.configSta);
free(data.configAp);
free(data.statusIp);
free(data.statusLink);
data.configSta = NULL;
data.configAp = NULL;
data.statusIp = NULL;
data.statusLink = NULL;
}
LT_HEAP_I();
__wrap_bk_printf_enable();
return true;
}
WiFiMode WiFiClass::getMode() {
if (!g_wlan_general_param)
return WIFI_MODE_NULL;
uint8_t role = g_wlan_general_param->role;
// change 1->2, 2->1
return (WiFiMode)(role + (role == 1) - (role == 2));
}
WiFiStatus WiFiClass::status() {
rw_evt_type status = mhdr_get_station_status();
if (status == RW_EVT_STA_CONNECTED && STA_CFG->dhcp_mode == DHCP_DISABLE)
status = RW_EVT_STA_GOT_IP;
return eventTypeToStatus(status);
}
IPAddress WiFiClass::hostByName(const char *hostname) {
ip_addr_t ip;
int ret = netconn_gethostbyname(hostname, &ip);
if (ret == ERR_OK) {
return ip.addr;
}
return IPAddress();
}

View File

@@ -0,0 +1,57 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-26. */
#pragma once
#include <api/WiFi/WiFi.h>
extern "C" {
#include <lwip/api.h>
#include <lwip/ip_addr.h>
#include <lwip/netif.h>
// port/net.h
#include <net.h>
#include <FreeRTOS.h>
#include <semphr.h>
#include <common.h>
#include <config.h>
#include <main_none.h>
#include <param_config.h>
#include <rw_msg_rx.h>
#include <wlan_ui_pub.h>
#include <wpa_supplicant_i.h>
extern void func_init_extended();
extern void app_pre_start();
extern void bk_wlan_ap_init(network_InitTypeDef_st *inNetworkInitPara);
// func/hostapd-2.5/wpa_supplicant/main_supplicant.c
extern struct wpa_ssid_value *wpas_connect_ssid;
// app/param_config.c
extern general_param_t *g_wlan_general_param;
extern ap_param_t *g_ap_param_ptr;
extern sta_param_t *g_sta_param_ptr;
extern uint8_t system_mac[6];
// WiFi.cpp
WiFiStatus eventTypeToStatus(uint8_t type);
WiFiAuthMode securityTypeToAuthMode(uint8_t type);
// WiFiEvents.cpp
extern void wifiEventSendArduino(EventId event);
extern void startWifiTask();
extern void wifiEventHandler(rw_evt_type event);
#define RW_EVT_ARDUINO (1 << 7)
#define IP_FMT "%u.%u.%u.%u"
#define STA_CFG ((network_InitTypeDef_st *)data.configSta)
#define AP_CFG ((network_InitTypeDef_ap_st *)data.configAp)
#define IP_STATUS ((IPStatusTypedef *)data.statusIp)
#define LINK_STATUS ((LinkStatusTypeDef *)data.statusLink)
} // extern "C"

View File

@@ -0,0 +1,207 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-27. */
#include "WiFiPriv.h"
WiFiStatus
WiFiClass::begin(const char *ssid, const char *passphrase, int32_t channel, const uint8_t *bssid, bool connect) {
if (!enableSTA(true))
return WL_CONNECT_FAILED;
if (!validate(ssid, passphrase))
return WL_CONNECT_FAILED;
LT_HEAP_I();
strcpy(STA_CFG->wifi_ssid, ssid);
if (passphrase) {
strcpy(STA_CFG->wifi_key, passphrase);
} else {
STA_CFG->wifi_bssid[0] = '\0';
}
if (reconnect(bssid))
return WL_CONNECTED;
return WL_CONNECT_FAILED;
}
bool WiFiClass::config(IPAddress localIP, IPAddress gateway, IPAddress subnet, IPAddress dns1, IPAddress dns2) {
// need to initialize data struct first
enableSTA(true);
STA_CFG->dhcp_mode = localIP ? DHCP_DISABLE : DHCP_CLIENT;
if (localIP) {
sprintf(STA_CFG->local_ip_addr, IP_FMT, localIP[0], localIP[1], localIP[2], localIP[3]);
sprintf(STA_CFG->net_mask, IP_FMT, subnet[0], subnet[1], subnet[2], subnet[3]);
sprintf(STA_CFG->gateway_ip_addr, IP_FMT, gateway[0], gateway[1], gateway[2], gateway[3]);
if (dns1) {
sprintf(STA_CFG->dns_server_ip_addr, IP_FMT, dns1[0], dns1[1], dns1[2], dns1[3]);
}
}
// from wlan_ui.c:1370
if (sta_ip_is_start()) {
sta_ip_down();
ip_address_set(
BK_STATION,
STA_CFG->dhcp_mode,
STA_CFG->local_ip_addr,
STA_CFG->net_mask,
STA_CFG->gateway_ip_addr,
STA_CFG->dns_server_ip_addr
);
sta_ip_start();
}
return true;
}
bool WiFiClass::reconnect(const uint8_t *bssid) {
if (!bssid && !STA_CFG->wifi_ssid[0]) {
LT_E("(B)SSID not specified");
goto error;
}
if (bssid) {
LT_D_WG("Connecting to " MACSTR, MAC2STR(bssid));
} else {
LT_D_WG("Connecting to %s", STA_CFG->wifi_ssid);
}
STA_CFG->wifi_mode = BK_STATION;
STA_CFG->wifi_retry_interval = 100;
if (bssid)
memcpy(STA_CFG->wifi_bssid, bssid, 6);
else
memset(STA_CFG->wifi_bssid, 0x00, 6);
if (STA_CFG->dhcp_mode == DHCP_DISABLE) {
LT_D_WG("Static IP: %s / %s / %s", STA_CFG->local_ip_addr, STA_CFG->net_mask, STA_CFG->gateway_ip_addr);
LT_D_WG("Static DNS: %s", STA_CFG->dns_server_ip_addr);
} else {
LT_D_WG("Using DHCP");
}
LT_D_WG("Starting WiFi...");
__wrap_bk_printf_disable();
bk_wlan_start_sta(STA_CFG);
__wrap_bk_printf_enable();
LT_D_WG("Start OK");
return true;
error:
return false;
}
bool WiFiClass::disconnect(bool wifiOff) {
bk_wlan_connection_loss();
if (wifiOff)
enableSTA(false);
return true;
}
bool WiFiClass::setAutoReconnect(bool autoReconnect) {
return false;
}
bool WiFiClass::getAutoReconnect() {
return false;
}
IPAddress WiFiClass::localIP() {
bk_wlan_get_ip_status(IP_STATUS, BK_STATION);
IPAddress ip;
ip.fromString(IP_STATUS->ip);
return ip;
}
IPAddress WiFiClass::subnetMask() {
bk_wlan_get_ip_status(IP_STATUS, BK_STATION);
IPAddress ip;
ip.fromString(IP_STATUS->mask);
return ip;
}
IPAddress WiFiClass::gatewayIP() {
bk_wlan_get_ip_status(IP_STATUS, BK_STATION);
IPAddress ip;
ip.fromString(IP_STATUS->gate);
return ip;
}
IPAddress WiFiClass::dnsIP(uint8_t dns_no) {
bk_wlan_get_ip_status(IP_STATUS, BK_STATION);
IPAddress ip;
ip.fromString(IP_STATUS->dns);
return ip;
}
IPAddress WiFiClass::broadcastIP() {
return calculateBroadcast(localIP(), subnetMask());
}
const char *WiFiClass::getHostname() {
struct netif *ifs = (struct netif *)net_get_sta_handle();
return netif_get_hostname(ifs);
}
bool WiFiClass::setHostname(const char *hostname) {
struct netif *ifs = (struct netif *)net_get_sta_handle();
netif_set_hostname(ifs, (char *)hostname);
return true;
}
uint8_t *WiFiClass::macAddress(uint8_t *mac) {
wifi_get_mac_address((char *)mac, CONFIG_ROLE_STA);
return mac;
}
bool WiFiClass::setMacAddress(const uint8_t *mac) {
if (mac[0] & 0x01) {
LT_E("Invalid MAC address");
return false;
}
// ensure "mac_inited" is true
wifi_get_mac_address((char *)system_mac, BK_STATION);
// store the MAC globally
memcpy(system_mac, mac, 6);
WiFiMode previousMode = getMode();
if (previousMode) {
mode(WIFI_MODE_NULL);
mode(previousMode);
}
return true;
}
const String WiFiClass::SSID() {
bk_wlan_get_link_status(LINK_STATUS);
return (char *)LINK_STATUS->ssid;
}
const String WiFiClass::psk() {
if (!isConnected())
return "";
struct wpa_supplicant *wpas = wpa_suppliant_ctrl_get_wpas();
if (!wpas || !wpas->conf || !wpas->conf->ssid)
return "";
return (char *)wpas->conf->ssid->passphrase;
}
uint8_t *WiFiClass::BSSID() {
bk_wlan_get_link_status(LINK_STATUS);
return LINK_STATUS->bssid;
}
int32_t WiFiClass::channel() {
bk_wlan_get_link_status(LINK_STATUS);
return LINK_STATUS->channel;
}
int8_t WiFiClass::RSSI() {
bk_wlan_get_link_status(LINK_STATUS);
return LINK_STATUS->wifi_strength;
}
WiFiAuthMode WiFiClass::getEncryption() {
bk_wlan_get_link_status(LINK_STATUS);
return securityTypeToAuthMode(LINK_STATUS->security);
}

View File

@@ -0,0 +1,84 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-27. */
#include "WiFiPriv.h"
static void scanHandler(void *ctx, uint8_t param) {
LT_HEAP_I();
WiFiClass *cls = (WiFiClass *)ctx;
if (!cls) {
LT_W("Called without ctx");
return;
}
WiFiScanData *scan = cls->scan;
if (!scan) {
LT_W("Called without cls->scan");
return;
}
ScanResult_adv result;
if (wlan_sta_scan_result(&result)) {
LT_E("Failed to get scan result");
goto end;
}
LT_D_WG("Found %d APs", result.ApNum);
cls->scanAlloc(result.ApNum);
if (!scan->ap) {
LT_W("scan->ap alloc failed");
goto end;
}
for (uint8_t i = 0; i < result.ApNum; i++) {
scan->ap[i].ssid = strdup(result.ApList[i].ssid);
scan->ap[i].auth = securityTypeToAuthMode(result.ApList[i].security);
scan->ap[i].rssi = result.ApList[i].ApPower;
scan->ap[i].channel = result.ApList[i].channel;
memcpy(scan->ap[i].bssid.addr, result.ApList[i].bssid, 6);
}
cls->data.scannedAt = millis();
wifiEventSendArduino(ARDUINO_EVENT_WIFI_SCAN_DONE);
end:
scan->running = false;
xSemaphoreGive(cls->data.scanSem);
LT_HEAP_I();
return;
}
int16_t WiFiClass::scanNetworks(bool async, bool showHidden, bool passive, uint32_t maxMsPerChannel, uint8_t channel) {
if (scan && scan->running)
return WIFI_SCAN_RUNNING;
enableSTA(true);
scanDelete();
scanInit();
LT_I("Starting WiFi scan");
__wrap_bk_printf_disable();
mhdr_scanu_reg_cb(scanHandler, this);
bk_wlan_start_scan();
LT_HEAP_I();
scan->running = true;
int16_t ret = WIFI_SCAN_RUNNING;
if (!async) {
LT_I("Waiting for results");
xSemaphoreTake(data.scanSem, 1); // reset the semaphore quickly
xSemaphoreTake(data.scanSem, pdMS_TO_TICKS(maxMsPerChannel * 20));
if (scan->running) {
scanDelete();
ret = WIFI_SCAN_FAILED;
goto exit;
}
ret = scan->count;
goto exit;
}
exit:
__wrap_bk_printf_enable();
return ret;
}

View File

@@ -0,0 +1,8 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-27. */
#pragma once
#include <api/WiFi/WiFi.h>
#include <lwip/LwIPServer.h>
typedef LwIPServer WiFiServer;

View File

@@ -0,0 +1,45 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-19. */
#include <sdk_extern.h>
#include <fal.h>
#include <flash_pub.h>
#define FLASH_ERASE_MIN_SIZE (4 * 1024)
extern uint32_t flash_ctrl(uint32_t cmd, void *param);
static int init() {
__wrap_bk_printf_disable();
flash_init();
__wrap_bk_printf_enable();
return 0;
}
static int read(long offset, uint8_t *buf, size_t size) {
flash_read((char *)buf, size, offset);
return size;
}
static int write(long offset, const uint8_t *buf, size_t size) {
flash_write((char *)buf, size, offset);
return size;
}
static int erase(long offset, size_t size) {
size = ((size - 1) / FLASH_ERASE_MIN_SIZE) + 1;
for (uint16_t i = 0; i < size; i++) {
uint32_t addr = offset + i * FLASH_ERASE_MIN_SIZE;
flash_ctrl(CMD_FLASH_ERASE_SECTOR, &addr);
}
return size * FLASH_ERASE_MIN_SIZE;
}
const struct fal_flash_dev flash0 = {
.name = FAL_FLASH_DEV_NAME,
.addr = 0x0,
.len = FLASH_LENGTH,
.blk_size = FLASH_ERASE_MIN_SIZE,
.ops = {init, read, write, erase},
.write_gran = 1,
};

View File

@@ -0,0 +1,21 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-19. */
#include <printf_config.h>
#include <printf/printf.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
extern void bk_send_byte(uint8_t uport, uint8_t data);
extern int uart_print_port;
void putchar_(char c) {
bk_send_byte(uart_print_port, c);
}
void putchar_p(char c, unsigned long port) {
bk_send_byte(port & 0xFF, c);
}
WRAP_PRINTF(bk_printf);

View File

@@ -0,0 +1,7 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-20. */
#pragma once
#include <printf_config.h>
WRAP_DISABLE_DEF(bk_printf);

View File

@@ -1,2 +0,0 @@
realtek-ambz Realtek AmebaZ Arduino Core
libretuya Interfaces for LibreTuya Arduino cores

View File

@@ -0,0 +1,5 @@
/* Copyright (c) Kuba Szczodrzyński 2022-05-17. */
#include "Events.h"
uint16_t EventHandler_s::lastId = 1;

View File

@@ -0,0 +1,117 @@
/*
ESP8266WiFiGeneric.h - esp8266 Wifi support.
Based on WiFi.h from Ardiono WiFi shield library.
Copyright (c) 2011-2014 Arduino. All right reserved.
Modified by Ivan Grokhotkov, December 2014
Reworked by Markus Sattler, December 2015
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#include <Arduino.h>
#include <api/WiFi/WiFiEvents.h>
#include <functional>
typedef enum {
ARDUINO_EVENT_WIFI_READY = 0, /**< ESP32 WiFi ready */
ARDUINO_EVENT_WIFI_SCAN_DONE, /**< ESP32 finish scanning AP */
ARDUINO_EVENT_WIFI_STA_START, /**< ESP32 station start */
ARDUINO_EVENT_WIFI_STA_STOP, /**< ESP32 station stop */
ARDUINO_EVENT_WIFI_STA_CONNECTED, /**< ESP32 station connected to AP */
ARDUINO_EVENT_WIFI_STA_DISCONNECTED, /**< ESP32 station disconnected from AP */
ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE, /**< the auth mode of AP connected by ESP32 station changed */
ARDUINO_EVENT_WIFI_STA_GOT_IP,
ARDUINO_EVENT_WIFI_STA_GOT_IP6,
ARDUINO_EVENT_WIFI_STA_LOST_IP,
ARDUINO_EVENT_WIFI_AP_START, /**< ESP32 soft-AP start */
ARDUINO_EVENT_WIFI_AP_STOP, /**< ESP32 soft-AP stop */
ARDUINO_EVENT_WIFI_AP_STACONNECTED, /**< a station connected to ESP32 soft-AP */
ARDUINO_EVENT_WIFI_AP_STADISCONNECTED, /**< a station disconnected from ESP32 soft-AP */
ARDUINO_EVENT_WIFI_AP_STAIPASSIGNED,
ARDUINO_EVENT_WIFI_AP_PROBEREQRECVED, /**< Receive probe request packet in soft-AP interface */
ARDUINO_EVENT_WIFI_AP_GOT_IP6,
ARDUINO_EVENT_WIFI_FTM_REPORT, /**< Receive report of FTM procedure */
ARDUINO_EVENT_ETH_START,
ARDUINO_EVENT_ETH_STOP,
ARDUINO_EVENT_ETH_CONNECTED,
ARDUINO_EVENT_ETH_DISCONNECTED,
ARDUINO_EVENT_ETH_GOT_IP,
ARDUINO_EVENT_ETH_GOT_IP6,
ARDUINO_EVENT_WPS_ER_SUCCESS, /**< ESP32 station wps succeeds in enrollee mode */
ARDUINO_EVENT_WPS_ER_FAILED, /**< ESP32 station wps fails in enrollee mode */
ARDUINO_EVENT_WPS_ER_TIMEOUT, /**< ESP32 station wps timeout in enrollee mode */
ARDUINO_EVENT_WPS_ER_PIN, /**< ESP32 station wps pin code in enrollee mode */
ARDUINO_EVENT_WPS_ER_PBC_OVERLAP, /**< ESP32 station wps overlap in enrollee mode */
ARDUINO_EVENT_SC_SCAN_DONE,
ARDUINO_EVENT_SC_FOUND_CHANNEL,
ARDUINO_EVENT_SC_GOT_SSID_PSWD,
ARDUINO_EVENT_SC_SEND_ACK_DONE,
ARDUINO_EVENT_PROV_INIT,
ARDUINO_EVENT_PROV_DEINIT,
ARDUINO_EVENT_PROV_START,
ARDUINO_EVENT_PROV_END,
ARDUINO_EVENT_PROV_CRED_RECV,
ARDUINO_EVENT_PROV_CRED_FAIL,
ARDUINO_EVENT_PROV_CRED_SUCCESS,
ARDUINO_EVENT_MAX
} arduino_event_id_t;
typedef union {
wifi_event_sta_scan_done_t wifi_scan_done;
wifi_event_sta_authmode_change_t wifi_sta_authmode_change;
wifi_event_sta_connected_t wifi_sta_connected;
wifi_event_sta_disconnected_t wifi_sta_disconnected;
wifi_event_sta_wps_er_pin_t wps_er_pin;
wifi_event_sta_wps_fail_reason_t wps_fail_reason;
wifi_event_ap_probe_req_rx_t wifi_ap_probereqrecved;
wifi_event_ap_staconnected_t wifi_ap_staconnected;
wifi_event_ap_stadisconnected_t wifi_ap_stadisconnected;
wifi_event_ftm_report_t wifi_ftm_report;
ip_event_ap_staipassigned_t wifi_ap_staipassigned;
ip_event_got_ip_t got_ip;
ip_event_got_ip6_t got_ip6;
// smartconfig_event_got_ssid_pswd_t sc_got_ssid_pswd;
// esp_eth_handle_t eth_connected;
// wifi_sta_config_t prov_cred_recv;
// wifi_prov_sta_fail_reason_t prov_fail_reason;
} arduino_event_info_t;
typedef struct {
arduino_event_id_t event_id;
arduino_event_info_t event_info;
} arduino_event_t;
#define EventId arduino_event_id_t
#define EventId_t arduino_event_id_t
#define EventInfo arduino_event_info_t
#define EventInfo_t arduino_event_info_t
#define Event_t arduino_event_t
typedef void (*EventCb)(EventId event);
typedef std::function<void(EventId event, EventInfo info)> EventFuncCb;
typedef void (*EventSysCb)(Event_t *event);
typedef struct EventHandler_s {
static uint16_t lastId;
uint16_t id;
EventCb cb;
EventFuncCb fcb;
EventSysCb scb;
EventId eventId;
EventHandler_s() : id(lastId++), cb(NULL), fcb(NULL), scb(NULL) {}
} EventHandler;

View File

@@ -1,27 +0,0 @@
/* Copyright (c) Kuba Szczodrzyński 2022-04-24. */
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
typedef struct {
uint8_t manufacturerId;
uint8_t chipId;
uint8_t chipSizeId;
} FlashId;
class IFlashClass {
public:
IFlashClass() {}
~IFlashClass() {}
virtual FlashId getChipId() = 0;
virtual uint32_t getSize() = 0;
virtual bool eraseSector(uint32_t sector) = 0;
virtual bool readBlock(uint32_t offset, uint8_t *data, size_t size) = 0;
virtual bool writeBlock(uint32_t offset, uint8_t *data, size_t size) = 0;
};

View File

@@ -1,17 +0,0 @@
/* Copyright (c) Kuba Szczodrzyński 2022-04-29. */
#include "LibreTuyaAPI.h"
__weak char *strdup(const char *s) {
size_t len = strlen(s) + 1;
void *newp = malloc(len);
if (newp == NULL)
return NULL;
return (char *)memcpy(newp, s, len);
}
String ipToString(const IPAddress &ip) {
char szRet[16];
sprintf(szRet, "%hhu.%hhu.%hhu.%hhu", ip[0], ip[1], ip[2], ip[3]);
return String(szRet);
}

View File

@@ -17,7 +17,7 @@
#include <stdint.h>
#include <stdlib.h>
#include "api/String.h"
#include <api/String.h>
typedef enum {
PT_I8,

View File

@@ -0,0 +1,41 @@
/* Copyright (c) Kuba Szczodrzyński 2022-07-03. */
#include "SoftwareSerial.h"
SoftwareSerial::SoftwareSerial(pin_size_t receivePin, pin_size_t transmitPin, bool inverted) {
data.rx.buf = NULL;
data.tx.buf = NULL;
data.rx.pin = receivePin;
data.tx.pin = transmitPin;
data.invert = inverted == true;
}
int SoftwareSerial::available() {
return data.rx.buf->available();
}
int SoftwareSerial::peek() {
return data.rx.buf->peek();
}
int SoftwareSerial::read() {
return data.rx.buf->read_char();
}
void SoftwareSerial::flush() {
while (data.rx.buf->available()) {
yield();
}
}
size_t SoftwareSerial::write(uint8_t c) {
while (data.tx.buf->isFull()) {
yield();
}
data.tx.buf->store_char(c);
if (data.tx.state == SS_IDLE) {
data.tx.state = SS_START;
this->startTx();
}
return 1;
}

View File

@@ -0,0 +1,74 @@
/* Copyright (c) Kuba Szczodrzyński 2022-07-03. */
#pragma once
#include <Arduino.h>
#include <api/HardwareSerial.h>
#include <api/RingBuffer.h>
using namespace arduino;
typedef enum {
SS_IDLE = 0,
SS_START,
SS_DATA0,
SS_DATA1,
SS_DATA2,
SS_DATA3,
SS_DATA4,
SS_DATA5,
SS_DATA6,
SS_DATA7,
SS_STOP,
SS_END,
} SoftState;
typedef struct {
SoftState state;
RingBuffer *buf;
uint8_t byte;
pin_size_t pin;
void *param;
} SoftData;
typedef struct {
SoftData rx;
SoftData tx;
uint8_t invert;
void *param;
} SoftSerial;
class SoftwareSerial : public HardwareSerial {
private:
SoftSerial data;
void *param;
public:
SoftwareSerial(pin_size_t receivePin, pin_size_t transmitPin, bool inverted = false);
inline void begin(unsigned long baudrate) {
begin(baudrate, SERIAL_8N1);
}
int available();
int peek();
int read();
void flush();
size_t write(uint8_t c);
operator bool() {
return data.rx.buf || data.tx.buf;
}
public: // Family needs to implement these methods only
void begin(unsigned long baudrate, uint16_t config);
void end();
private:
void startTx();
void endTx();
using Print::write;
};
#define HAS_SERIAL_CLASS 1

View File

@@ -1,177 +0,0 @@
/*
WiFi.h - esp32 Wifi support.
Based on WiFi.h from Arduino WiFi shield library.
Copyright (c) 2011-2014 Arduino. All right reserved.
Modified by Ivan Grokhotkov, December 2014
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#include <stdint.h>
#include <api/IPAddress.h>
#include <api/IPv6Address.h>
#include <api/Print.h>
#include "WiFiType.h"
// TODO wifi events
// TODO WiFiMulti library
class IWiFiClass {
public:
virtual void printDiag(Print &dest) = 0;
};
class IWiFiGenericClass {
public:
virtual int32_t channel(void) = 0;
virtual bool mode(WiFiMode mode) = 0;
virtual WiFiMode getMode() = 0;
virtual WiFiStatus status() = 0;
virtual bool enableSTA(bool enable) = 0;
virtual bool enableAP(bool enable) = 0;
virtual bool setSleep(bool enable) = 0;
virtual bool getSleep() = 0;
virtual bool setTxPower(int power) = 0;
virtual int getTxPower() = 0;
virtual int hostByName(const char *hostname, IPAddress &aResult) {
aResult = hostByName(hostname);
return true;
}
virtual IPAddress hostByName(const char *hostname) = 0;
static IPAddress calculateNetworkID(IPAddress ip, IPAddress subnet);
static IPAddress calculateBroadcast(IPAddress ip, IPAddress subnet);
static uint8_t calculateSubnetCIDR(IPAddress subnetMask);
static String macToString(uint8_t *mac);
};
class IWiFiSTAClass {
public:
virtual WiFiStatus begin(
const char *ssid,
const char *passphrase = NULL,
int32_t channel = 0,
const uint8_t *bssid = NULL,
bool connect = true
) = 0;
virtual WiFiStatus begin(
char *ssid, char *passphrase = NULL, int32_t channel = 0, const uint8_t *bssid = NULL, bool connect = true
) = 0;
virtual bool config(
IPAddress localIP,
IPAddress gateway,
IPAddress subnet,
IPAddress dns1 = (uint32_t)0x00000000,
IPAddress dns2 = (uint32_t)0x00000000
) = 0;
virtual bool reconnect() = 0;
virtual bool disconnect(bool wifiOff = false) = 0;
virtual bool isConnected();
virtual bool setAutoReconnect(bool autoReconnect) = 0;
virtual bool getAutoReconnect() = 0;
virtual WiFiStatus waitForConnectResult(unsigned long timeout) = 0;
virtual IPAddress localIP() = 0;
virtual uint8_t *macAddress(uint8_t *mac) = 0;
virtual String macAddress() = 0;
virtual IPAddress subnetMask() = 0;
virtual IPAddress gatewayIP() = 0;
virtual IPAddress dnsIP(uint8_t dns_no = 0) = 0;
virtual IPAddress broadcastIP() = 0;
virtual IPAddress networkID() = 0;
virtual uint8_t subnetCIDR() = 0;
virtual bool enableIpV6() = 0;
virtual IPv6Address localIPv6() = 0;
virtual const char *getHostname() = 0;
virtual bool setHostname(const char *hostname) = 0;
virtual bool setMacAddress(const uint8_t *mac) = 0;
inline bool hostname(const String &aHostname) {
return setHostname(aHostname.c_str());
}
virtual const String SSID() = 0;
virtual const String psk() = 0;
virtual uint8_t *BSSID() = 0;
virtual String BSSIDstr() = 0;
virtual int8_t RSSI() = 0;
virtual WiFiAuthMode getEncryption() = 0;
};
class IWiFiScanClass {
public:
virtual int16_t scanNetworks(
bool async = false,
bool showHidden = false,
bool passive = false,
uint32_t maxMsPerChannel = 300,
uint8_t channel = 0
) = 0;
virtual bool getNetworkInfo(
uint8_t networkItem,
String &ssid,
WiFiAuthMode &encryptionType,
int32_t &RSSI,
uint8_t *&BSSID,
int32_t &channel
) = 0;
virtual int16_t scanComplete() = 0;
virtual void scanDelete() = 0;
virtual String SSID(uint8_t networkItem) = 0;
virtual WiFiAuthMode encryptionType(uint8_t networkItem) = 0;
virtual int32_t RSSI(uint8_t networkItem) = 0;
virtual uint8_t *BSSID(uint8_t networkItem) = 0;
virtual String BSSIDstr(uint8_t networkItem) = 0;
virtual int32_t channel(uint8_t networkItem) = 0;
};
class IWiFiAPClass {
public:
virtual bool softAP(
const char *ssid, const char *passphrase = NULL, int channel = 1, bool ssidHidden = false, int maxClients = 4
) = 0;
virtual bool softAPConfig(IPAddress localIP, IPAddress gateway, IPAddress subnet) = 0;
virtual bool softAPdisconnect(bool wifiOff = false) = 0;
virtual uint8_t softAPgetStationNum() = 0;
virtual IPAddress softAPIP() = 0;
virtual IPAddress softAPBroadcastIP() = 0;
virtual IPAddress softAPNetworkID() = 0;
virtual uint8_t softAPSubnetCIDR() = 0;
virtual bool softAPenableIpV6() = 0;
virtual IPv6Address softAPIPv6() = 0;
virtual const char *softAPgetHostname() = 0;
virtual bool softAPsetHostname(const char *hostname) = 0;
virtual uint8_t *softAPmacAddress(uint8_t *mac) = 0;
virtual String softAPmacAddress(void) = 0;
virtual const String softAPSSID(void) = 0;
};

View File

@@ -0,0 +1,67 @@
/* Copyright (c) Kuba Szczodrzyński 2022-04-25. */
#include "WiFi.h"
void WiFiClass::printDiag(Print &dest) {
const char *modes[] = {"NULL", "STA", "AP", "STA+AP"};
const char *enc[] = {"Open", "WEP", "WPA PSK", "WPA2 PSK", "WPA/WPA2", "WPA", "WPA2"};
dest.print("Mode: ");
dest.println(modes[getMode()]);
if (getMode() & WIFI_MODE_STA) {
dest.println("-- Station --");
dest.print("SSID: ");
dest.println(SSID());
if (isConnected()) {
dest.print("Channel: ");
dest.println(channel());
dest.print("BSSID: ");
dest.println(BSSIDstr());
dest.print("RSSI: ");
dest.println(RSSI());
dest.print("Encryption: ");
dest.println(enc[getEncryption()]);
dest.print("IP: ");
dest.println(localIP());
dest.print("MAC: ");
dest.println(macAddress());
dest.print("Hostname: ");
dest.println(getHostname());
}
}
if (getMode() & WIFI_MODE_AP) {
dest.println("-- Access Point --");
dest.print("SSID: ");
dest.println(softAPSSID());
dest.print("IP: ");
dest.println(softAPIP());
dest.print("MAC: ");
dest.println(softAPmacAddress());
dest.print("Hostname: ");
dest.println(softAPgetHostname());
}
}
bool WiFiClass::validate(const char *ssid, const char *passphrase) {
if (!ssid || *ssid == 0x00 || strlen(ssid) > 32) {
LT_W("SSID not specified or too long");
return false;
}
if (passphrase) {
uint16_t length = strlen(passphrase);
if (length < 8) {
LT_W("Passphrase too short (%u)", length);
return false;
}
if (length > 63) {
LT_W("Passphrase too long (%u)", length);
return false;
}
}
return true;
}
WiFiClass WiFi;
WiFiClass *pWiFi = NULL;

View File

@@ -0,0 +1,195 @@
/*
WiFi.h - esp32 Wifi support.
Based on WiFi.h from Arduino WiFi shield library.
Copyright (c) 2011-2014 Arduino. All right reserved.
Modified by Ivan Grokhotkov, December 2014
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#include <Arduino.h>
#include <api/Events.h>
#include <api/IPAddress.h>
#include <api/IPv6Address.h>
#include <vector>
#include "WiFiType.h"
#ifdef LT_ARD_HAS_WIFI
// family's data structure
#include <WiFiData.h>
#endif
class WiFiClass {
public:
#ifdef LT_ARD_HAS_WIFI
// must be public for WiFiEvents & WiFiScan static handlers
WiFiData data;
#endif
WiFiScanData *scan = NULL;
public: /* WiFi.cpp */
WiFiClass();
~WiFiClass();
void printDiag(Print &dest);
bool validate(const char *ssid, const char *passphrase);
public: /* WiFiGeneric.cpp */
bool mode(WiFiMode mode);
bool modePriv(WiFiMode mode, WiFiModeAction sta, WiFiModeAction ap);
WiFiMode getMode();
WiFiStatus status();
bool enableSTA(bool enable);
bool enableAP(bool enable);
bool setSleep(bool enable);
bool getSleep();
bool setTxPower(int power);
int getTxPower();
int hostByName(const char *hostname, IPAddress &aResult);
IPAddress hostByName(const char *hostname);
static IPAddress calculateNetworkID(IPAddress ip, IPAddress subnet);
static IPAddress calculateBroadcast(IPAddress ip, IPAddress subnet);
static uint8_t calculateSubnetCIDR(IPAddress subnetMask);
static String macToString(uint8_t *mac);
protected: /* WiFiEvents.cpp */
static std::vector<EventHandler> handlers;
public: /* WiFiEvents.cpp */
uint16_t onEvent(EventCb callback, EventId eventId = ARDUINO_EVENT_MAX);
uint16_t onEvent(EventFuncCb callback, EventId eventId = ARDUINO_EVENT_MAX);
uint16_t onEvent(EventSysCb callback, EventId eventId = ARDUINO_EVENT_MAX);
void removeEvent(EventCb callback, EventId eventId);
void removeEvent(EventSysCb callback, EventId eventId);
void removeEvent(uint16_t id);
static void postEvent(EventId eventId, EventInfo eventInfo);
public: /* WiFiSTA.cpp */
WiFiStatus begin(
const char *ssid,
const char *passphrase = NULL,
int32_t channel = 0,
const uint8_t *bssid = NULL,
bool connect = true
);
WiFiStatus
begin(char *ssid, char *passphrase = NULL, int32_t channel = 0, const uint8_t *bssid = NULL, bool connect = true);
bool config(
IPAddress localIP,
IPAddress gateway,
IPAddress subnet,
IPAddress dns1 = (uint32_t)0x00000000,
IPAddress dns2 = (uint32_t)0x00000000
);
bool reconnect(const uint8_t *bssid = NULL);
bool disconnect(bool wifiOff = false);
bool isConnected();
bool setAutoReconnect(bool autoReconnect);
bool getAutoReconnect();
WiFiStatus waitForConnectResult(unsigned long timeout);
IPAddress localIP();
uint8_t *macAddress(uint8_t *mac);
String macAddress();
IPAddress subnetMask();
IPAddress gatewayIP();
IPAddress dnsIP(uint8_t dns_no = 0);
IPAddress broadcastIP();
IPAddress networkID();
uint8_t subnetCIDR();
bool enableIpV6();
IPv6Address localIPv6();
const char *getHostname();
bool setHostname(const char *hostname);
bool setMacAddress(const uint8_t *mac);
inline bool hostname(const String &aHostname) {
return setHostname(aHostname.c_str());
}
const String SSID();
const String psk();
uint8_t *BSSID();
String BSSIDstr();
int32_t channel();
int8_t RSSI();
WiFiAuthMode getEncryption();
public: /* WiFiScan.cpp */
int16_t scanNetworks(
bool async = false,
bool showHidden = false,
bool passive = false,
uint32_t maxMsPerChannel = 300,
uint8_t channel = 0
);
bool getNetworkInfo(
uint8_t networkItem,
String &ssid,
WiFiAuthMode &encryptionType,
int32_t &RSSI,
uint8_t *&BSSID,
int32_t &channel
);
int16_t scanComplete();
uint8_t scanAlloc(uint8_t count);
void scanInit();
void scanDelete();
String SSID(uint8_t networkItem);
WiFiAuthMode encryptionType(uint8_t networkItem);
int32_t RSSI(uint8_t networkItem);
uint8_t *BSSID(uint8_t networkItem);
String BSSIDstr(uint8_t networkItem);
int32_t channel(uint8_t networkItem);
public: /* WiFiAP.cpp */
bool softAP(
const char *ssid, const char *passphrase = NULL, int channel = 1, bool ssidHidden = false, int maxClients = 4
);
bool softAPConfig(IPAddress localIP, IPAddress gateway, IPAddress subnet);
bool softAPdisconnect(bool wifiOff = false);
uint8_t softAPgetStationNum();
IPAddress softAPIP();
IPAddress softAPBroadcastIP();
IPAddress softAPNetworkID();
uint8_t softAPSubnetCIDR();
IPAddress softAPSubnetMask();
bool softAPenableIpV6();
IPv6Address softAPIPv6();
const char *softAPgetHostname();
bool softAPsetHostname(const char *hostname);
uint8_t *softAPmacAddress(uint8_t *mac);
String softAPmacAddress(void);
const String softAPSSID(void);
};
extern WiFiClass WiFi;
extern WiFiClass *pWiFi;

View File

@@ -0,0 +1,23 @@
/* Copyright (c) Kuba Szczodrzyński 2022-04-25. */
#include "WiFi.h"
IPAddress WiFiClass::softAPBroadcastIP() {
return calculateBroadcast(softAPIP(), softAPSubnetMask());
}
IPAddress WiFiClass::softAPNetworkID() {
return calculateNetworkID(softAPIP(), softAPSubnetMask());
}
uint8_t WiFiClass::softAPSubnetCIDR() {
return calculateSubnetCIDR(softAPSubnetMask());
}
__attribute__((weak)) bool WiFiClass::softAPenableIpV6() {
return false;
}
__attribute__((weak)) IPv6Address WiFiClass::softAPIPv6() {
return IPv6Address();
}

View File

@@ -0,0 +1,84 @@
/* Copyright (c) Kuba Szczodrzyński 2022-05-17. */
#include "WiFi.h"
std::vector<EventHandler> WiFiClass::handlers;
uint16_t WiFiClass::onEvent(EventCb callback, EventId eventId) {
if (!callback)
return 0;
EventHandler handler;
handler.cb = callback;
handler.eventId = eventId;
handlers.push_back(handler);
return handler.id;
}
uint16_t WiFiClass::onEvent(EventFuncCb callback, EventId eventId) {
if (!callback)
return 0;
EventHandler handler;
handler.fcb = callback;
handler.eventId = eventId;
handlers.push_back(handler);
return handler.id;
}
uint16_t WiFiClass::onEvent(EventSysCb callback, EventId eventId) {
if (!callback)
return 0;
EventHandler handler;
handler.scb = callback;
handler.eventId = eventId;
handlers.push_back(handler);
return handler.id;
}
void WiFiClass::removeEvent(EventCb callback, EventId eventId) {
if (!callback)
return;
for (uint16_t i = 0; i < handlers.size(); i++) {
EventHandler handler = handlers[i];
if (handler.cb == callback && handler.eventId == eventId) {
handlers.erase(handlers.begin() + i);
}
}
}
void WiFiClass::removeEvent(EventSysCb callback, EventId eventId) {
if (!callback)
return;
for (uint16_t i = 0; i < handlers.size(); i++) {
EventHandler handler = handlers[i];
if (handler.scb == callback && handler.eventId == eventId) {
handlers.erase(handlers.begin() + i);
}
}
}
void WiFiClass::removeEvent(uint16_t id) {
for (uint16_t i = 0; i < handlers.size(); i++) {
EventHandler handler = handlers[i];
if (handler.id == id) {
handlers.erase(handlers.begin() + i);
}
}
}
void WiFiClass::postEvent(EventId eventId, EventInfo eventInfo) {
for (auto handler : handlers) {
if (handler.eventId != ARDUINO_EVENT_MAX && handler.eventId != eventId)
continue;
if (handler.cb) {
handler.cb(eventId);
} else if (handler.fcb) {
handler.fcb(eventId, eventInfo);
} else if (handler.scb) {
Event_t event = {
.event_id = eventId,
.event_info = eventInfo,
};
handler.scb(&event);
}
}
}

View File

@@ -0,0 +1,173 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "WiFiType.h"
/** Argument structure for WIFI_EVENT_SCAN_DONE event */
typedef struct {
uint32_t status; /**< status of scanning APs: 0 - success, 1 - failure */
uint8_t number; /**< number of scan results */
uint8_t scan_id; /**< scan sequence number, used for block scan */
} wifi_event_sta_scan_done_t;
/** Argument structure for WIFI_EVENT_STA_CONNECTED event */
typedef struct {
uint8_t ssid[32]; /**< SSID of connected AP */
uint8_t ssid_len; /**< SSID length of connected AP */
uint8_t bssid[6]; /**< BSSID of connected AP*/
uint8_t channel; /**< channel of connected AP*/
wifi_auth_mode_t authmode; /**< authentication mode used by AP*/
} wifi_event_sta_connected_t;
/** Argument structure for WIFI_EVENT_STA_DISCONNECTED event */
typedef struct {
uint8_t ssid[32]; /**< SSID of disconnected AP */
uint8_t ssid_len; /**< SSID length of disconnected AP */
uint8_t bssid[6]; /**< BSSID of disconnected AP */
uint8_t reason; /**< reason of disconnection */
} wifi_event_sta_disconnected_t;
/** Argument structure for WIFI_EVENT_STA_AUTHMODE_CHANGE event */
typedef struct {
wifi_auth_mode_t old_mode; /**< the old auth mode of AP */
wifi_auth_mode_t new_mode; /**< the new auth mode of AP */
} wifi_event_sta_authmode_change_t;
/** Argument structure for WIFI_EVENT_STA_WPS_ER_PIN event */
typedef struct {
uint8_t pin_code[8]; /**< PIN code of station in enrollee mode */
} wifi_event_sta_wps_er_pin_t;
/** Argument structure for WIFI_EVENT_STA_WPS_ER_FAILED event */
typedef enum {
WPS_FAIL_REASON_NORMAL = 0, /**< ESP32 WPS normal fail reason */
WPS_FAIL_REASON_RECV_M2D, /**< ESP32 WPS receive M2D frame */
WPS_FAIL_REASON_MAX
} wifi_event_sta_wps_fail_reason_t;
#define MAX_SSID_LEN 32
#define MAX_PASSPHRASE_LEN 64
#define MAX_WPS_AP_CRED 3
/** Argument structure for WIFI_EVENT_STA_WPS_ER_SUCCESS event */
typedef struct {
uint8_t ap_cred_cnt; /**< Number of AP credentials received */
struct {
uint8_t ssid[MAX_SSID_LEN]; /**< SSID of AP */
uint8_t passphrase[MAX_PASSPHRASE_LEN]; /**< Passphrase for the AP */
} ap_cred[MAX_WPS_AP_CRED]; /**< All AP credentials received from WPS handshake */
} wifi_event_sta_wps_er_success_t;
/** Argument structure for WIFI_EVENT_AP_STACONNECTED event */
typedef struct {
uint8_t mac[6]; /**< MAC address of the station connected to ESP32 soft-AP */
uint8_t aid; /**< the aid that ESP32 soft-AP gives to the station connected to */
bool is_mesh_child; /**< flag to identify mesh child */
} wifi_event_ap_staconnected_t;
/** Argument structure for WIFI_EVENT_AP_STADISCONNECTED event */
typedef struct {
uint8_t mac[6]; /**< MAC address of the station disconnects to ESP32 soft-AP */
uint8_t aid; /**< the aid that ESP32 soft-AP gave to the station disconnects to */
bool is_mesh_child; /**< flag to identify mesh child */
} wifi_event_ap_stadisconnected_t;
/** Argument structure for WIFI_EVENT_AP_PROBEREQRECVED event */
typedef struct {
int rssi; /**< Received probe request signal strength */
uint8_t mac[6]; /**< MAC address of the station which send probe request */
} wifi_event_ap_probe_req_rx_t;
/**
* @brief FTM operation status types
*
*/
typedef enum {
FTM_STATUS_SUCCESS = 0, /**< FTM exchange is successful */
FTM_STATUS_UNSUPPORTED, /**< Peer does not support FTM */
FTM_STATUS_CONF_REJECTED, /**< Peer rejected FTM configuration in FTM Request */
FTM_STATUS_NO_RESPONSE, /**< Peer did not respond to FTM Requests */
FTM_STATUS_FAIL, /**< Unknown error during FTM exchange */
} wifi_ftm_status_t;
/** Argument structure for */
typedef struct {
uint8_t dlog_token; /**< Dialog Token of the FTM frame */
int8_t rssi; /**< RSSI of the FTM frame received */
uint32_t rtt; /**< Round Trip Time in pSec with a peer */
uint64_t t1; /**< Time of departure of FTM frame from FTM Responder in pSec */
uint64_t t2; /**< Time of arrival of FTM frame at FTM Initiator in pSec */
uint64_t t3; /**< Time of departure of ACK from FTM Initiator in pSec */
uint64_t t4; /**< Time of arrival of ACK at FTM Responder in pSec */
} wifi_ftm_report_entry_t;
/** Argument structure for WIFI_EVENT_FTM_REPORT event */
typedef struct {
uint8_t peer_mac[6]; /**< MAC address of the FTM Peer */
wifi_ftm_status_t status; /**< Status of the FTM operation */
uint32_t rtt_raw; /**< Raw average Round-Trip-Time with peer in Nano-Seconds */
uint32_t rtt_est; /**< Estimated Round-Trip-Time with peer in Nano-Seconds */
uint32_t dist_est; /**< Estimated one-way distance in Centi-Meters */
wifi_ftm_report_entry_t
*ftm_report_data; /**< Pointer to FTM Report with multiple entries, should be freed after use */
uint8_t ftm_report_num_entries; /**< Number of entries in the FTM Report data */
} wifi_event_ftm_report_t;
#define WIFI_STATIS_BUFFER (1 << 0)
#define WIFI_STATIS_RXTX (1 << 1)
#define WIFI_STATIS_HW (1 << 2)
#define WIFI_STATIS_DIAG (1 << 3)
#define WIFI_STATIS_PS (1 << 4)
#define WIFI_STATIS_ALL (-1)
/** Argument structure for WIFI_EVENT_ACTION_TX_STATUS event */
typedef struct {
int ifx; /**< WiFi interface to send request to */
uint32_t context; /**< Context to identify the request */
uint8_t da[6]; /**< Destination MAC address */
uint8_t status; /**< Status of the operation */
} wifi_event_action_tx_status_t;
/** Argument structure for WIFI_EVENT_ROC_DONE event */
typedef struct {
uint32_t context; /**< Context to identify the request */
} wifi_event_roc_done_t;
/** Event structure for IP_EVENT_STA_GOT_IP, IP_EVENT_ETH_GOT_IP events */
typedef struct {
esp_ip4_addr_t ip; /**< Interface IPV4 address */
esp_ip4_addr_t netmask; /**< Interface IPV4 netmask */
esp_ip4_addr_t gw; /**< Interface IPV4 gateway address */
} esp_netif_ip_info_t;
/** @brief IPV6 IP address information
*/
typedef struct {
esp_ip6_addr_t ip; /**< Interface IPV6 address */
} esp_netif_ip6_info_t;
typedef struct {
int if_index; /*!< Interface index for which the event is received (left for legacy compilation) */
void *esp_netif; /*!< Pointer to corresponding esp-netif object */
esp_netif_ip_info_t ip_info; /*!< IP address, netmask, gatway IP address */
bool ip_changed; /*!< Whether the assigned IP has changed or not */
} ip_event_got_ip_t;
/** Event structure for IP_EVENT_GOT_IP6 event */
typedef struct {
int if_index; /*!< Interface index for which the event is received (left for legacy compilation) */
void *esp_netif; /*!< Pointer to corresponding esp-netif object */
esp_netif_ip6_info_t ip6_info; /*!< IPv6 address of the interface */
int ip_index; /*!< IPv6 address index */
} ip_event_got_ip6_t;
/** Event structure for IP_EVENT_AP_STAIPASSIGNED event */
typedef struct {
esp_ip4_addr_t ip; /*!< IP address which was assigned to the station */
} ip_event_ap_staipassigned_t;

View File

@@ -0,0 +1,109 @@
/* Copyright (c) Kuba Szczodrzyński 2022-04-25. */
#include "WiFi.h"
bool WiFiClass::mode(WiFiMode mode) {
// store a pointer to WiFi for WiFiEvents.cpp
pWiFi = this;
WiFiMode currentMode = getMode();
LT_D_WG("Mode changing %u -> %u", currentMode, mode);
if (mode == currentMode)
return true;
// get mode changes as 0/1
WiFiModeAction sta = WiFiModeAction((mode & WIFI_MODE_STA) != (currentMode & WIFI_MODE_STA));
WiFiModeAction ap = WiFiModeAction((mode & WIFI_MODE_AP) != (currentMode & WIFI_MODE_AP));
// change 0/1 to 1/2
sta = WiFiModeAction(sta + sta * (mode & WIFI_MODE_STA));
ap = WiFiModeAction(ap + ap * (mode & WIFI_MODE_AP));
// actually change the mode
LT_HEAP_I();
return modePriv(mode, sta, ap);
}
bool WiFiClass::enableSTA(bool enable) {
WiFiMode currentMode = getMode();
if (((currentMode & WIFI_MODE_STA) != 0) != enable) {
return mode((WiFiMode)(currentMode ^ WIFI_MODE_STA));
}
return true;
}
bool WiFiClass::enableAP(bool enable) {
WiFiMode currentMode = getMode();
if (((currentMode & WIFI_MODE_AP) != 0) != enable) {
return mode((WiFiMode)(currentMode ^ WIFI_MODE_AP));
}
return true;
}
__attribute__((weak)) bool WiFiClass::setSleep(bool enable) {
return false;
}
__attribute__((weak)) bool WiFiClass::getSleep() {
return false;
}
__attribute__((weak)) bool WiFiClass::setTxPower(int power) {
return false;
}
__attribute__((weak)) int WiFiClass::getTxPower() {
return 0;
}
int WiFiClass::hostByName(const char *hostname, IPAddress &aResult) {
aResult = hostByName(hostname);
return true;
}
IPAddress WiFiClass::calculateNetworkID(IPAddress ip, IPAddress subnet) {
IPAddress networkID;
for (size_t i = 0; i < 4; i++)
networkID[i] = subnet[i] & ip[i];
return networkID;
}
IPAddress WiFiClass::calculateBroadcast(IPAddress ip, IPAddress subnet) {
IPAddress broadcastIp;
for (int i = 0; i < 4; i++)
broadcastIp[i] = ~subnet[i] | ip[i];
return broadcastIp;
}
uint8_t WiFiClass::calculateSubnetCIDR(IPAddress subnetMask) {
uint8_t CIDR = 0;
for (uint8_t i = 0; i < 4; i++) {
if (subnetMask[i] == 0x80) // 128
CIDR += 1;
else if (subnetMask[i] == 0xC0) // 192
CIDR += 2;
else if (subnetMask[i] == 0xE0) // 224
CIDR += 3;
else if (subnetMask[i] == 0xF0) // 242
CIDR += 4;
else if (subnetMask[i] == 0xF8) // 248
CIDR += 5;
else if (subnetMask[i] == 0xFC) // 252
CIDR += 6;
else if (subnetMask[i] == 0xFE) // 254
CIDR += 7;
else if (subnetMask[i] == 0xFF) // 255
CIDR += 8;
}
return CIDR;
}
String WiFiClass::macToString(uint8_t *mac) {
char macStr[18]; // 6*2 + 5*':' + '\0'
sprintf(macStr, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
return macStr;
}

View File

@@ -0,0 +1,48 @@
/* Copyright (c) Kuba Szczodrzyński 2022-04-25. */
#include "WiFi.h"
WiFiStatus WiFiClass::begin(char *ssid, char *passphrase, int32_t channel, const uint8_t *bssid, bool connect) {
return begin((const char *)ssid, (const char *)passphrase, channel, bssid, connect);
}
bool WiFiClass::isConnected() {
return status() == WL_CONNECTED;
}
WiFiStatus WiFiClass::waitForConnectResult(unsigned long timeout) {
if ((getMode() & WIFI_MODE_STA) == 0) {
return WL_DISCONNECTED;
}
unsigned long start = millis();
while ((!status() || status() >= WL_DISCONNECTED) && (millis() - start) < timeout) {
delay(100);
}
return status();
}
String WiFiClass::macAddress(void) {
uint8_t mac[6];
macAddress(mac);
return macToString(mac);
}
IPAddress WiFiClass::networkID() {
return calculateNetworkID(gatewayIP(), subnetMask());
}
uint8_t WiFiClass::subnetCIDR() {
return calculateSubnetCIDR(subnetMask());
}
String WiFiClass::BSSIDstr() {
return macToString(BSSID());
}
__attribute__((weak)) bool WiFiClass::enableIpV6() {
return false;
}
__attribute__((weak)) IPv6Address WiFiClass::localIPv6() {
return IPv6Address();
}

View File

@@ -0,0 +1,83 @@
/* Copyright (c) Kuba Szczodrzyński 2022-04-25. */
#include "WiFi.h"
bool WiFiClass::getNetworkInfo(
uint8_t networkItem, String &ssid, WiFiAuthMode &encType, int32_t &rssi, uint8_t *&bssid, int32_t &channel
) {
ssid = SSID(networkItem);
encType = encryptionType(networkItem);
rssi = RSSI(networkItem);
bssid = BSSID(networkItem);
channel = this->channel(networkItem);
return true;
}
int16_t WiFiClass::scanComplete() {
if (!scan)
return 0;
if (scan->running)
return WIFI_SCAN_RUNNING;
return scan->count;
}
void WiFiClass::scanInit() {
if (scan)
return;
scan = (WiFiScanData *)zalloc(sizeof(WiFiScanData));
}
void WiFiClass::scanDelete() {
if (!scan)
return;
for (uint8_t i = 0; i < scan->count; i++) {
free(scan->ap[i].ssid);
}
free(scan->ap);
free(scan);
scan = NULL;
}
uint8_t WiFiClass::scanAlloc(uint8_t count) {
uint8_t last = scan->count;
scan->count = count;
scan->ap = (WiFiScanAP *)realloc(scan->ap, count * sizeof(WiFiScanAP));
if (!scan->ap)
return 255;
memset(scan->ap + last, 0, sizeof(WiFiScanAP));
return last;
}
String WiFiClass::SSID(uint8_t networkItem) {
if (!scan || networkItem >= scan->count)
return "";
return scan->ap[networkItem].ssid;
}
WiFiAuthMode WiFiClass::encryptionType(uint8_t networkItem) {
if (!scan || networkItem >= scan->count)
return WIFI_AUTH_INVALID;
return scan->ap[networkItem].auth;
}
int32_t WiFiClass::RSSI(uint8_t networkItem) {
if (!scan || networkItem >= scan->count)
return 0;
return scan->ap[networkItem].rssi;
}
uint8_t *WiFiClass::BSSID(uint8_t networkItem) {
if (!scan || networkItem >= scan->count)
return NULL;
return scan->ap[networkItem].bssid.addr;
}
String WiFiClass::BSSIDstr(uint8_t networkItem) {
return macToString(BSSID(networkItem));
}
int32_t WiFiClass::channel(uint8_t networkItem) {
if (!scan || networkItem >= scan->count)
return 0;
return scan->ap[networkItem].channel;
}

View File

@@ -0,0 +1,149 @@
/*
ESP8266WiFiType.h - esp8266 Wifi support.
Copyright (c) 2011-2014 Arduino. All right reserved.
Modified by Ivan Grokhotkov, December 2014
Reworked by Markus Sattler, December 2015
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#include <Arduino.h>
#define WIFI_SCAN_RUNNING (-1)
#define WIFI_SCAN_FAILED (-2)
#define WiFiMode_t wifi_mode_t
#define WiFiMode wifi_mode_t
#define WiFiStatus wl_status_t
#define WiFiAuthMode wifi_auth_mode_t
#define WIFI_OFF WIFI_MODE_NULL
#define WIFI_STA WIFI_MODE_STA
#define WIFI_AP WIFI_MODE_AP
#define WIFI_AP_STA WIFI_MODE_APSTA
#define WiFiEvent_t arduino_event_id_t
#define WiFiEventInfo_t arduino_event_info_t
#define WiFiEventId_t uint16_t
typedef struct {
uint8_t addr[6];
} WiFiMacAddr;
struct esp_ip6_addr {
uint32_t addr[4];
uint8_t zone;
};
struct esp_ip4_addr {
uint32_t addr;
};
typedef struct esp_ip4_addr esp_ip4_addr_t;
typedef struct esp_ip6_addr esp_ip6_addr_t;
typedef enum {
WIFI_MODE_NULL = 0, /**< null mode */
WIFI_MODE_STA, /**< WiFi station mode */
WIFI_MODE_AP, /**< WiFi soft-AP mode */
WIFI_MODE_APSTA, /**< WiFi station + soft-AP mode */
WIFI_MODE_MAX
} wifi_mode_t;
typedef enum {
WL_NO_SHIELD = 255, // for compatibility with WiFi Shield library
WL_IDLE_STATUS = 0,
WL_NO_SSID_AVAIL = 1,
WL_SCAN_COMPLETED = 2,
WL_CONNECTED = 3,
WL_CONNECT_FAILED = 4,
WL_CONNECTION_LOST = 5,
WL_DISCONNECTED = 6,
} wl_status_t;
typedef enum {
WIFI_AUTH_OPEN = 0, /**< authenticate mode : open */
WIFI_AUTH_WEP, /**< authenticate mode : WEP */
WIFI_AUTH_WPA_PSK, /**< authenticate mode : WPA_PSK */
WIFI_AUTH_WPA2_PSK, /**< authenticate mode : WPA2_PSK */
WIFI_AUTH_WPA_WPA2_PSK, /**< authenticate mode : WPA_WPA2_PSK */
WIFI_AUTH_WPA2_ENTERPRISE, /**< authenticate mode : WPA2_ENTERPRISE */
WIFI_AUTH_WPA3_PSK, /**< authenticate mode : WPA3_PSK */
WIFI_AUTH_WPA2_WPA3_PSK, /**< authenticate mode : WPA2_WPA3_PSK */
WIFI_AUTH_WAPI_PSK, /**< authenticate mode : WAPI_PSK */
WIFI_AUTH_WPA,
WIFI_AUTH_WPA2,
WIFI_AUTH_AUTO = 200,
WIFI_AUTH_INVALID = 255,
WIFI_AUTH_MAX
} wifi_auth_mode_t;
typedef enum {
WIFI_REASON_UNSPECIFIED = 1,
WIFI_REASON_AUTH_EXPIRE = 2,
WIFI_REASON_AUTH_LEAVE = 3,
WIFI_REASON_ASSOC_EXPIRE = 4,
WIFI_REASON_ASSOC_TOOMANY = 5,
WIFI_REASON_NOT_AUTHED = 6,
WIFI_REASON_NOT_ASSOCED = 7,
WIFI_REASON_ASSOC_LEAVE = 8,
WIFI_REASON_ASSOC_NOT_AUTHED = 9,
WIFI_REASON_DISASSOC_PWRCAP_BAD = 10,
WIFI_REASON_DISASSOC_SUPCHAN_BAD = 11,
WIFI_REASON_BSS_TRANSITION_DISASSOC = 12,
WIFI_REASON_IE_INVALID = 13,
WIFI_REASON_MIC_FAILURE = 14,
WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT = 15,
WIFI_REASON_GROUP_KEY_UPDATE_TIMEOUT = 16,
WIFI_REASON_IE_IN_4WAY_DIFFERS = 17,
WIFI_REASON_GROUP_CIPHER_INVALID = 18,
WIFI_REASON_PAIRWISE_CIPHER_INVALID = 19,
WIFI_REASON_AKMP_INVALID = 20,
WIFI_REASON_UNSUPP_RSN_IE_VERSION = 21,
WIFI_REASON_INVALID_RSN_IE_CAP = 22,
WIFI_REASON_802_1X_AUTH_FAILED = 23,
WIFI_REASON_CIPHER_SUITE_REJECTED = 24,
WIFI_REASON_INVALID_PMKID = 53,
WIFI_REASON_BEACON_TIMEOUT = 200,
WIFI_REASON_NO_AP_FOUND = 201,
WIFI_REASON_AUTH_FAIL = 202,
WIFI_REASON_ASSOC_FAIL = 203,
WIFI_REASON_HANDSHAKE_TIMEOUT = 204,
WIFI_REASON_CONNECTION_FAIL = 205,
WIFI_REASON_AP_TSF_RESET = 206,
WIFI_REASON_ROAMING = 207,
} wifi_err_reason_t;
typedef struct {
char *ssid;
WiFiAuthMode auth;
int32_t rssi;
WiFiMacAddr bssid;
int32_t channel;
} WiFiScanAP;
typedef struct {
bool running = false;
uint8_t count = 0;
WiFiScanAP *ap = NULL;
} WiFiScanData;
typedef enum {
WLMODE_NONE = 0,
WLMODE_DISABLE = 1,
WLMODE_ENABLE = 2,
} WiFiModeAction;

View File

@@ -1,66 +0,0 @@
/*
ESP8266WiFiType.h - esp8266 Wifi support.
Copyright (c) 2011-2014 Arduino. All right reserved.
Modified by Ivan Grokhotkov, December 2014
Reworked by Markus Sattler, December 2015
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#define WIFI_SCAN_RUNNING (-1)
#define WIFI_SCAN_FAILED (-2)
#define WiFiMode_t wifi_mode_t
#define WiFiMode wifi_mode_t
#define WiFiStatus wl_status_t
#define WiFiAuthMode wifi_auth_mode_t
#define WIFI_OFF WIFI_MODE_NULL
#define WIFI_STA WIFI_MODE_STA
#define WIFI_AP WIFI_MODE_AP
#define WIFI_AP_STA WIFI_MODE_APSTA
typedef enum {
WIFI_MODE_NULL = 0,
WIFI_MODE_STA,
WIFI_MODE_AP,
WIFI_MODE_APSTA,
WIFI_MODE_MAX,
} wifi_mode_t;
typedef enum {
WL_NO_SHIELD = 255, // for compatibility with WiFi Shield library
WL_IDLE_STATUS = 0,
WL_NO_SSID_AVAIL = 1,
WL_SCAN_COMPLETED = 2,
WL_CONNECTED = 3,
WL_CONNECT_FAILED = 4,
WL_CONNECTION_LOST = 5,
WL_DISCONNECTED = 6,
} wl_status_t;
typedef enum {
WIFI_AUTH_INVALID = 255,
WIFI_AUTH_AUTO = 200,
WIFI_AUTH_OPEN = 0,
WIFI_AUTH_WEP = 1,
WIFI_AUTH_WPA = 5,
WIFI_AUTH_WPA2 = 6,
WIFI_AUTH_WPA_PSK = 2,
WIFI_AUTH_WPA2_PSK = 3,
WIFI_AUTH_WPA_WPA2_PSK = 4,
} wifi_auth_mode_t;

View File

@@ -0,0 +1,66 @@
/* Copyright (c) Kuba Szczodrzyński 2022-05-09. */
#include <api/Stream.h>
class ITwoWire : public Stream {
protected:
int8_t _sda = -1;
int8_t _scl = -1;
uint32_t _freq = 0;
void (*onRequestCallback)(void);
void (*onReceiveCallback)(int);
public:
bool begin() {
return begin(_sda, _scl, _freq);
}
bool begin(uint8_t address) {
return begin(address, _sda, _scl, _freq);
}
virtual bool setPins(int8_t sda, int8_t scl) = 0;
virtual bool begin(int8_t sda, int8_t scl, uint32_t frequency = 0) = 0;
virtual bool begin(uint8_t address, int8_t sda, int8_t scl, uint32_t frequency = 0) = 0;
virtual bool end() = 0;
virtual bool setClock(uint32_t freq) = 0;
virtual void beginTransmission(uint8_t address) = 0;
virtual uint8_t endTransmission(bool stopBit) = 0;
virtual size_t requestFrom(uint8_t address, size_t len, bool stopBit) = 0;
virtual size_t write(const uint8_t *data, size_t len) = 0;
virtual int available() = 0;
virtual int read() = 0;
virtual int peek() = 0;
virtual void flush() = 0;
uint32_t getClock() {
return _freq;
}
uint8_t endTransmission() {
return endTransmission(true);
}
size_t requestFrom(uint8_t address, size_t len) {
return requestFrom(address, len, true);
}
virtual size_t write(uint8_t data) {
return write(&data, 1);
}
void onReceive(void (*cb)(int)) {
onReceiveCallback = cb;
}
void onRequest(void (*cb)(void)) {
onRequestCallback = cb;
}
};

View File

@@ -0,0 +1,53 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-19. */
#include <Arduino.h>
#include <api/HardwareSerial.h>
using namespace arduino;
extern "C" {
#include <fal.h>
fal_partition_t fal_root_part = NULL;
}
// Arduino framework initialization.
// May be redefined by family files.
void initArduino() __attribute__((weak));
// Weak empty variant initialization function.
// May be redefined by variant files.
void initVariant() __attribute__((weak));
// Initialize C library
extern "C" void __libc_init_array(void);
void main_task(const void *arg) {
setup();
for (;;) {
loop();
if (serialEventRun)
serialEventRun();
yield();
}
}
int main(void) {
// print a startup banner
LT_BANNER();
// initialize Arduino framework
initArduino();
// initialize C library
__libc_init_array();
// optionally initialize per-variant code
initVariant();
// initialize FAL
fal_init();
// provide root partition
fal_root_part = (fal_partition_t)fal_partition_find("root");
// start the main task and OS kernel
startMainTask();
while (1) {}
return 0;
}

View File

@@ -0,0 +1,11 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-19. */
#include <Arduino.h>
void serialEvent() __attribute__((weak));
bool Serial_available() __attribute__((weak));
void serialEventRun(void) {
if (Serial_available && serialEvent && Serial_available())
serialEvent();
}

View File

@@ -0,0 +1,6 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-04. */
#pragma once
// lowercase "md5.h" to allow including actual MD5.h on case-sensitive OSes
#include <MD5.h>

View File

@@ -0,0 +1,32 @@
/* Copyright (c) Kuba Szczodrzyński 2022-05-28. */
#define CHIP_TYPE(family, chip_id) (((family >> 24) << 8) | chip_id)
#define CHIP_TYPE_ENUM(family, chip_id) (ChipType) CHIP_TYPE(family, chip_id)
enum ChipFamily {
// used in UF2 Family ID
F_RTL8710A = 0x9FFFD543, // Realtek Ameba1
F_RTL8710B = 0x22E0D6FC, // Realtek AmebaZ (realtek-ambz)
F_RTL8720C = 0xE08F7564, // Realtek AmebaZ2
F_RTL8720D = 0x3379CFE2, // Realtek AmebaD
F_BK7231T = 0x675A40B0, // Beken 7231T
F_BK7231N = 0x7B3EF230, // Beken 7231N
F_BL602 = 0xDE1270B7, // Boufallo 602
F_XR809 = 0x51E903A8, // Xradiotech 809
F_NATIVE = 0xDEADBEEF, // Host-native
};
enum ChipType {
// Realtek AmebaZ
// IDs copied from rtl8710b_efuse.h
RTL8710BL = CHIP_TYPE(F_RTL8710B, 0xE0), // ???
RTL8710BN = CHIP_TYPE(F_RTL8710B, 0xFF), // CHIPID_8710BN / QFN32
RTL8710BU = CHIP_TYPE(F_RTL8710B, 0xFE), // CHIPID_8710BU / QFN48
RTL8710BX = CHIP_TYPE(F_RTL8710B, 0xF6), // found on an actual RTL8710BX
RTL8710L0 = CHIP_TYPE(F_RTL8710B, 0xFB), // CHIPID_8710BN_L0 / QFN32
RTL8711BN = CHIP_TYPE(F_RTL8710B, 0xFD), // CHIPID_8711BN / QFN48
RTL8711BU = CHIP_TYPE(F_RTL8710B, 0xFC), // CHIPID_8711BG / QFN68
// Beken 72XX
BK7231T = CHIP_TYPE(F_BK7231T, 0x1A), // *SCTRL_CHIP_ID = 0x7231a
BK7231N = CHIP_TYPE(F_BK7231N, 0x1C), // *SCTRL_CHIP_ID = 0x7231c
};

View File

@@ -0,0 +1,63 @@
/* Copyright (c) Kuba Szczodrzyński 2022-04-29. */
#include "LibreTuyaAPI.h"
String ipToString(const IPAddress &ip) {
char szRet[16];
sprintf(szRet, "%hhu.%hhu.%hhu.%hhu", ip[0], ip[1], ip[2], ip[3]);
return String(szRet);
}
/**
* @brief Generate random bytes using rand().
*
* @param buf destination pointer
* @param len how many bytes to generate
*/
void lt_rand_bytes(uint8_t *buf, size_t len) {
int *data = (int *)buf;
size_t i;
for (i = 0; len >= sizeof(int); len -= sizeof(int)) {
data[i++] = rand();
}
if (len) {
int rem = rand();
unsigned char *pRem = (unsigned char *)&rem;
memcpy(buf + i * sizeof(int), pRem, len);
}
}
#undef putchar
/**
* @brief Print data pointed to by buf in hexdump-like format (hex+ASCII).
*
* @param buf source pointer
* @param len how many bytes to print
* @param offset increment printed offset by this value
* @param width how many bytes on a line
*/
void hexdump(uint8_t *buf, size_t len, uint32_t offset, uint8_t width) {
uint16_t pos = 0;
while (pos < len) {
// print hex offset
printf("%06x ", offset + pos);
// calculate current line width
uint8_t lineWidth = min(width, len - pos);
// print hexadecimal representation
for (uint8_t i = 0; i < lineWidth; i++) {
if (i % 8 == 0) {
printf(" ");
}
printf("%02x ", buf[pos + i]);
}
// print ascii representation
printf(" |");
for (uint8_t i = 0; i < lineWidth; i++) {
char c = buf[pos + i];
putchar((c >= 0x20 && c <= 0x7f) ? c : '.');
}
puts("|\r");
pos += lineWidth;
}
}

View File

@@ -2,6 +2,28 @@
#pragma once
// C standard libraries
#include <inttypes.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// C++ standard libraries
#ifdef __cplusplus
#include <algorithm>
#include <cmath>
using ::round;
using std::abs;
using std::isinf;
using std::isnan;
using std::max;
using std::min;
#endif
// LibreTuya version macros
#ifndef LT_VERSION
#define LT_VERSION 1.0.0
@@ -15,7 +37,10 @@
#define LT_BOARD_STR STRINGIFY_MACRO(LT_BOARD)
// Includes
#include "LibreTuyaConfig.h"
#include "LibreTuyaClass.h" // global LT class
#include "LibreTuyaCompat.h" // compatibility methods
#include "LibreTuyaConfig.h" // configuration macros
#include "LibreTuyaCustom.h" // family-defined methods (Wiring custom)
#include <Arduino.h>
// C includes
@@ -24,6 +49,7 @@ extern "C" {
#endif // __cplusplus
#include "lt_logger.h"
#include "lt_posix_api.h"
#ifdef __cplusplus
} // extern "C"
@@ -38,14 +64,11 @@ extern "C" {
"LibreTuya v" LT_VERSION_STR " on " LT_BOARD_STR ", compiled at " __DATE__ " " __TIME__ \
)
// ArduinoCore-API doesn't define these anymore
#define FPSTR(pstr_pointer) (reinterpret_cast<const __FlashStringHelper *>(pstr_pointer))
#define PGM_VOID_P const void *
void lt_rand_bytes(uint8_t *buf, size_t len);
// C functions
extern char *strdup(const char *);
// C++ only functions
#ifdef __cplusplus
String ipToString(const IPAddress &ip);
void hexdump(uint8_t *buf, size_t len, uint32_t offset = 0, uint8_t width = 16);
#else
void hexdump(uint8_t *buf, size_t len, uint32_t offset, uint8_t width);
#endif

View File

@@ -0,0 +1,132 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-06. */
#include "LibreTuyaClass.h"
/**
* @brief Get LibreTuya version string.
*/
const char *LibreTuya::getVersion() {
return LT_VERSION_STR;
}
/**
* @brief Get board name.
*/
const char *LibreTuya::getBoard() {
return LT_BOARD_STR;
}
/**
* @brief Get CPU family ID.
*/
ChipFamily LibreTuya::getChipFamily() {
return FAMILY;
}
/**
* @brief Get CPU family name as string.
*/
const char *LibreTuya::getChipFamilyName() {
return STRINGIFY_MACRO(FAMILY) + 2;
}
static char *deviceName = NULL;
/**
* @brief Get device friendly name in format "LT-<board>-<chip id>".
* Can be used as hostname.
*/
const char *LibreTuya::getDeviceName() {
if (deviceName)
return deviceName;
uint32_t chipId = getChipId();
uint8_t *id = (uint8_t *)&chipId;
const char *board = getBoard();
uint8_t boardLen = strlen(board);
deviceName = (char *)malloc(3 + boardLen + 1 + 6 + 1);
sprintf(deviceName, "LT-%s-%02x%02x%02x", board, id[0], id[1], id[2]);
return deviceName;
}
/**
* @brief Get CPU frequency in MHz.
*/
uint32_t LibreTuya::getCpuFreqMHz() {
return getCpuFreq() / 1000000;
}
/**
* @brief Get flash chip total size.
* The default implementation uses the least significant
* byte of the chip ID to determine the size.
*/
__attribute__((weak)) uint32_t LibreTuya::getFlashChipSize() {
FlashId id = getFlashChipId();
if (id.chipSizeId >= 0x14 && id.chipSizeId <= 0x19) {
return (1 << id.chipSizeId);
}
#ifdef FLASH_LENGTH
return FLASH_LENGTH;
#else
return 0;
#endif
}
static uint8_t otaRunningIndex = 0;
/**
* @brief Get the currently running firmware OTA index.
*/
uint8_t LibreTuya::otaGetRunning() {
if (otaRunningIndex)
return otaRunningIndex;
// otaRunningIndex will be correct even after switchOta()
return otaRunningIndex = otaGetStoredIndex();
}
/**
* @brief Get the OTA index for updated firmware.
*
* Note: returns 1 for chips without dual-OTA.
*/
uint8_t LibreTuya::otaGetTarget() {
if (!otaSupportsDual())
return 1;
return otaGetRunning() ^ 0b11;
}
/**
* @brief Perform OTA rollback.
*
* @return false if no second image to run, writing failed or dual-OTA not supported
*/
bool LibreTuya::otaRollback() {
if (!otaCanRollback())
return false;
if (otaGetRunning() != otaGetStoredIndex())
// force switching back to current image
return otaSwitch(true);
return true;
}
/**
* @brief Check if OTA rollback is supported and available (there is another image to run).
* @return false if no second image to run or dual-OTA not supported
*/
bool LibreTuya::otaCanRollback() {
if (!otaSupportsDual())
return false;
if (otaGetRunning() == otaGetStoredIndex())
return true;
if (otaGetRunning() == 1 && otaHasImage1())
return true;
if (otaGetRunning() == 2 && otaHasImage2())
return true;
return false;
}
__attribute__((weak)) void LibreTuya::gpioRecover() {
// nop by default
}

View File

@@ -0,0 +1,142 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-06. */
#pragma once
#ifdef __cplusplus
#include "LibreTuyaAPI.h"
#include <core/ChipType.h>
/**
* @brief Flash chip ID structure.
*/
typedef struct {
uint8_t manufacturerId;
uint8_t chipId;
uint8_t chipSizeId;
} FlashId;
/**
* @brief Main LibreTuya API class.
*
* This class contains all functions common amongst all families.
* Implementations of these methods may vary between families.
*
* The class is accessible using the `LT` global object (defined by the family).
*/
class LibreTuya {
public: /* Common methods - note: these are documented in LibreTuyaAPI.cpp */
const char *getVersion();
const char *getBoard();
ChipFamily getChipFamily();
const char *getChipFamilyName();
const char *getDeviceName();
uint32_t getCpuFreqMHz();
uint32_t getFlashChipSize();
uint8_t otaGetRunning();
uint8_t otaGetTarget();
bool otaRollback();
bool otaCanRollback();
public: /* Family-defined methods */
/**
* @brief Reboot the CPU.
*/
void restart();
/**
* @brief Reconfigure GPIO pins used for debugging
* (SWD/JTAG), so that they can be used as normal I/O.
*/
void gpioRecover();
public: /* CPU-related */
/**
* @brief Get CPU model ID.
*/
ChipType getChipType();
/**
* @brief Get CPU model name as string.
*/
const char *getChipModel();
/**
* @brief Get CPU unique ID. This may be based on MAC, eFuse, etc.
* Note: the number should be 24-bit (with most significant byte being zero).
*/
uint32_t getChipId();
/**
* @brief Get CPU core count.
*/
uint8_t getChipCores();
/**
* @brief Get CPU core type name as string.
*/
const char *getChipCoreType();
/**
* @brief Get CPU frequency in Hz.
*/
uint32_t getCpuFreq();
/**
* @brief Get CPU cycle count.
*/
uint32_t getCycleCount();
public: /* Flash memory utilities */
/**
* @brief Read flash chip ID and return a FlashId struct.
*/
FlashId getFlashChipId();
public: /* Memory management */
/**
* @brief Get total RAM size.
*/
uint32_t getRamSize();
/**
* @brief Get total heap size.
*/
uint32_t getHeapSize();
/**
* @brief Get free heap size.
*/
uint32_t getFreeHeap();
/**
* @brief Get lowest level of free heap memory.
*/
uint32_t getMinFreeHeap();
/**
* @brief Get largest block of heap that can be allocated at once.
*/
uint32_t getMaxAllocHeap();
public: /* OTA-related */
/**
* @brief Read the currently active OTA index, i.e. the one that will boot upon restart.
*/
uint8_t otaGetStoredIndex();
/**
* @brief Check if the chip supports dual-OTA.
*/
bool otaSupportsDual();
/**
* @brief Check if OTA1 image is valid.
*/
bool otaHasImage1();
/**
* @brief Check if OTA2 image is valid.
*/
bool otaHasImage2();
/**
* @brief Try to switch OTA index to the other image.
*
* Note: should return true for chips without dual-OTA. Should return false if one of two images is not valid.
*
* @param force switch even if other image already marked as active
* @return false if writing failed; true otherwise
*/
bool otaSwitch(bool force = false);
};
extern LibreTuya LT;
extern LibreTuya ESP;
#endif

View File

@@ -0,0 +1,33 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-04. */
#include "LibreTuyaCompat.h"
#if LT_HAS_FREERTOS
BaseType_t xTaskCreateUniversal(
TaskFunction_t pxTaskCode,
const char *const pcName,
const uint32_t usStackDepth,
void *const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t *const pxCreatedTask,
const BaseType_t xCoreID
) {
// #ifndef CONFIG_FREERTOS_UNICORE
// if (xCoreID >= 0 && xCoreID < 2) {
// return xTaskCreatePinnedToCore(
// pxTaskCode,
// pcName,
// usStackDepth,
// pvParameters,
// uxPriority,
// pxCreatedTask,
// xCoreID
// );
// } else {
// #endif
return xTaskCreate(pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask);
// #ifndef CONFIG_FREERTOS_UNICORE
// }
// #endif
}
#endif

View File

@@ -0,0 +1,42 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-04. */
#pragma once
#include <Arduino.h>
#if LT_HAS_FREERTOS
#include <FreeRTOS.h>
#include <task.h>
#endif
// Definitions for error constants.
#define esp_err_t int
#define ESP_OK 0 /*!< esp_err_t value indicating success (no error) */
#define ESP_FAIL -1 /*!< Generic esp_err_t code indicating failure */
// ArduinoCore-API doesn't define these anymore
#define FPSTR(pstr_pointer) (reinterpret_cast<const __FlashStringHelper *>(pstr_pointer))
#define PGM_VOID_P const void *
#define vsnprintf_P vsnprintf
#define OUTPUT_OPEN_DRAIN OUTPUT_OPENDRAIN
#define attachInterruptArg attachInterruptParam
#define voidFuncPtrArg voidFuncPtrParam
// FreeRTOS utilities
#if LT_HAS_FREERTOS
// if xCoreID < 0 or CPU is unicore, it will use xTaskCreate, else xTaskCreatePinnedToCore
// allows to easily handle all possible situations without repetitive code
BaseType_t xTaskCreateUniversal(
TaskFunction_t pxTaskCode,
const char *const pcName,
const uint32_t usStackDepth,
void *const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t *const pxCreatedTask,
const BaseType_t xCoreID
);
#define xTaskCreatePinnedToCore xTaskCreateUniversal
#endif
// Default values from sdkconfig.h
#define CONFIG_LWIP_MAX_ACTIVE_TCP 16

View File

@@ -44,6 +44,33 @@
#define LT_LOGLEVEL LT_LEVEL_INFO
#endif
// Free heap size debugging
#ifndef LT_LOG_HEAP
#define LT_LOG_HEAP 0
#endif
// Debug errno values using LT_ERRNO()
#ifndef LT_LOG_ERRNO
#define LT_LOG_ERRNO 0
#endif
// Serial output options
#ifndef LT_UART_SILENT_ENABLED
#define LT_UART_SILENT_ENABLED 1
#endif
#ifndef LT_UART_SILENT_ALL
#define LT_UART_SILENT_ALL 0
#endif
#ifndef LT_UART_DEFAULT_LOGGER
#define LT_UART_DEFAULT_LOGGER LT_UART_DEFAULT_PORT
#endif
#ifndef LT_UART_DEFAULT_SERIAL
#define LT_UART_DEFAULT_SERIAL LT_UART_DEFAULT_PORT
#endif
// Per-module debugging
#ifndef LT_DEBUG_WIFI
#define LT_DEBUG_WIFI 0

View File

@@ -0,0 +1,103 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-20. */
#include "LibreTuyaCustom.h"
int _analogReadResolution = 10; // 0-1023
int _analogWriteResolution = 8; // 0-255
int _analogWritePeriod = 20000; // 50 Hz
/**
* @brief Check if pin is invalid (too low or too high).
*/
bool pinInvalid(pin_size_t pinNumber) {
#ifdef PINS_COUNT
return pinNumber < 0 || pinNumber >= PINS_COUNT;
#else
return false;
#endif
}
/**
* @brief Get PinInfo struct for the specified number.
* Returns NULL if pin number is invalid.
*/
PinInfo *pinInfo(pin_size_t pinNumber) {
if (pinInvalid(pinNumber))
return NULL;
return &(pinTable[pinNumber]);
}
/**
* @brief Check if pin supports all features represented by 'mask'.
*/
bool pinSupported(PinInfo *pin, uint32_t mask) {
return (pin->supported & mask) == mask;
}
/**
* @brief Check if pin has all features represented by 'mask' enabled.
*/
bool pinEnabled(PinInfo *pin, uint32_t mask) {
return (pin->enabled & mask) == mask;
}
/**
* @brief Check if GPIO pin is configured as output.
*/
bool pinIsOutput(PinInfo *pin) {
return pin->mode == OUTPUT || pin->mode == OUTPUT_OPENDRAIN;
}
/**
* @brief Check if GPIO pin is configured as output.
*/
bool pinIsInput(PinInfo *pin) {
return pin->mode == INPUT || pin->mode == INPUT_PULLUP || pin->mode == INPUT_PULLDOWN;
}
/**
* @brief Read voltage from ADC and return a value between 0 and
* the current reading resolution.
*/
int analogRead(pin_size_t pinNumber) {
float voltage = analogReadVoltage(pinNumber);
float maxVoltage = analogReadMaxVoltage(pinNumber);
uint16_t ret = round((1 << _analogReadResolution) * voltage / maxVoltage);
if (ret >= (1 << _analogReadResolution))
ret = (1 << _analogReadResolution) - 1;
return ret;
}
/**
* @brief Set resolution of values (in bits) returned by analogRead().
* Defaults to 10 bit (0-1023).
*/
void analogReadResolution(int res) {
_analogReadResolution = res;
}
/**
* @brief Set resolution of values (in bits) expected by analogWrite().
* Defaults to 8 bit (0-255).
*/
void analogWriteResolution(int res) {
_analogWriteResolution = res;
}
/**
* @brief Set PWM output frequency (in Hz).
* Defaults to 50 Hz (20,000 uS).
*/
void analogWriteFrequency(int hz) {
_analogWritePeriod = 1E6 / hz;
}
/**
* @brief Set PWM output frequency (cycle period) in microseconds.
* Defaults to 20,000 uS (50 Hz).
*/
void analogWritePeriod(int us) {
_analogWritePeriod = us;
}
__attribute__((weak)) void analogReference(uint8_t mode) {}

View File

@@ -0,0 +1,87 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-06. */
#pragma once
#include "LibreTuyaAPI.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Run main_task & start OS kernel (family-defined)
*/
extern bool startMainTask();
/**
* @brief Main setup() and loop() task.
* Not to be called directly.
*/
extern void main_task(const void *arg);
#define PIN_NONE (1 << 0)
#define PIN_GPIO (1 << 1)
#define PIN_IRQ (1 << 2)
#define PIN_PWM (1 << 3)
#define PIN_ADC (1 << 4)
#define PIN_DAC (1 << 5)
#define PIN_I2C (1 << 6)
#define PIN_I2S (1 << 7)
#define PIN_JTAG (1 << 8)
#define PIN_SPI (1 << 9)
#define PIN_SWD (1 << 10)
#define PIN_UART (1 << 11)
typedef struct {
/**
* @brief GPIO name in the family SDK.
*/
uint32_t gpio;
/**
* @brief Supported pin functions.
*/
uint32_t supported;
/**
* @brief Enabled pin functions. Used values are family-specific.
*/
uint32_t enabled;
/**
* @brief Pin mode (direction, IRQ level, etc.).
*/
uint32_t mode;
} PinInfo;
extern PinInfo pinTable[];
// Custom Wiring methods
bool pinInvalid(pin_size_t pinNumber);
PinInfo *pinInfo(pin_size_t pinNumber);
bool pinSupported(PinInfo *pin, uint32_t mask);
bool pinEnabled(PinInfo *pin, uint32_t mask);
bool pinIsOutput(PinInfo *pin);
bool pinIsInput(PinInfo *pin);
int analogRead(pin_size_t pinNumber);
void analogReadResolution(int res);
void analogWriteResolution(int res);
void analogWriteFrequency(int hz);
void analogWritePeriod(int us);
extern int _analogReadResolution;
extern int _analogWriteResolution;
extern int _analogWritePeriod;
/**
* @brief Read voltage from analog input (in millivolts).
*/
uint16_t analogReadVoltage(pin_size_t pinNumber);
/**
* @brief Get max reading voltage for the specified pin (millivolts).
*/
uint16_t analogReadMaxVoltage(pin_size_t pinNumber);
#ifdef __cplusplus
} // extern "C"
#endif

View File

@@ -0,0 +1,25 @@
/* Copyright (c) Kuba Szczodrzyński 2022-07-04. */
#pragma once
#include <Arduino.h>
#ifdef HAS_SERIAL_CLASS // failsafe for circular inclusion
#ifdef PIN_SERIAL0_TX
extern SerialClass Serial0;
#endif
#ifdef PIN_SERIAL1_TX
extern SerialClass Serial1;
#endif
#ifdef PIN_SERIAL2_TX
extern SerialClass Serial2;
#endif
#define SerialN(x) Serial##x
#define SerialM(x) SerialN(x)
#define Serial SerialM(LT_UART_DEFAULT_SERIAL)
#endif

View File

@@ -3,8 +3,9 @@
#include "lt_logger.h"
#include <Arduino.h>
#include <printf/printf.h>
#if LT_LOGGER_TASK
#if LT_LOGGER_TASK && LT_HAS_FREERTOS
#include <FreeRTOS.h>
#include <task.h>
#endif
@@ -27,10 +28,11 @@
#define COLOR_BRIGHT_CYAN 0x16
#define COLOR_BRIGHT_WHITE 0x17
const char levels[] = {'V', 'D', 'I', 'W', 'E', 'F'};
static uint32_t uart_port = LT_UART_DEFAULT_LOGGER;
static const char levels[] = {'V', 'D', 'I', 'W', 'E', 'F'};
#if LT_LOGGER_COLOR
const uint8_t colors[] = {
static const uint8_t colors[] = {
COLOR_BRIGHT_CYAN,
COLOR_BRIGHT_BLUE,
COLOR_BRIGHT_GREEN,
@@ -57,7 +59,7 @@ void lt_log(const uint8_t level, const char *format, ...) {
#endif
#endif
#if LT_LOGGER_TASK
#if LT_LOGGER_TASK && LT_HAS_FREERTOS
char task_colon = ':';
TaskHandle_t task = xTaskGetCurrentTaskHandle();
char *task_name = pcTaskGetTaskName(task);
@@ -72,7 +74,10 @@ void lt_log(const uint8_t level, const char *format, ...) {
char c_value = '0' + (colors[level] & 0x7);
#endif
printf(
fctprintf(
(void (*)(char, void *))putchar_p,
(void *)uart_port,
// format:
#if LT_LOGGER_COLOR
"\e[%c;3%cm"
#endif
@@ -90,16 +95,16 @@ void lt_log(const uint8_t level, const char *format, ...) {
#if LT_LOGGER_CALLER
"%s():%hu: "
#endif
#if LT_LOGGER_TASK
#if LT_LOGGER_TASK && LT_HAS_FREERTOS
"%s%c "
#endif
,
levels[level]
// arguments:
#if LT_LOGGER_COLOR
,
c_bright, // whether text is bright
c_value // text color
c_value, // text color
#endif
levels[level]
#if LT_LOGGER_TIMESTAMP
,
seconds // float
@@ -113,7 +118,7 @@ void lt_log(const uint8_t level, const char *format, ...) {
caller,
line
#endif
#if LT_LOGGER_TASK
#if LT_LOGGER_TASK && LT_HAS_FREERTOS
,
task_name,
task_colon // printing outside of tasks
@@ -122,7 +127,12 @@ void lt_log(const uint8_t level, const char *format, ...) {
va_list va_args;
va_start(va_args, format);
vprintf(format, va_args);
vfctprintf((void (*)(char, void *))putchar_p, (void *)uart_port, format, va_args);
va_end(va_args);
printf("\r\n");
putchar_p('\r', uart_port);
putchar_p('\n', uart_port);
}
void lt_log_set_port(uint8_t port) {
uart_port = port;
}

View File

@@ -13,6 +13,13 @@ void lt_log(const uint8_t level, const char *caller, const unsigned short line,
void lt_log(const uint8_t level, const char *format, ...);
#endif
/**
* @brief Change log output port.
*
* @param port UART port index - can be 0, 1 or 2
*/
void lt_log_set_port(uint8_t port);
#if LT_LEVEL_TRACE >= LT_LOGLEVEL
#define LT_T(...) LT_LOG(LT_LEVEL_TRACE, __FUNCTION__, __LINE__, __VA_ARGS__)
#define LT_V(...) LT_LOG(LT_LEVEL_TRACE, __FUNCTION__, __LINE__, __VA_ARGS__)
@@ -51,6 +58,12 @@ void lt_log(const uint8_t level, const char *format, ...);
#define LT_F(...)
#endif
#if LT_LOG_HEAP
#define LT_HEAP_I() LT_I("Free heap: %u", LT_HEAP_FUNC());
#else
#define LT_HEAP_I()
#endif
// ESP32 compat
#define log_printf(...) LT_I(__VA_ARGS__)
#define log_v(...) LT_V(__VA_ARGS__)
@@ -75,6 +88,8 @@ void lt_log(const uint8_t level, const char *format, ...);
#define ESP_EARLY_LOGI(...) LT_I(__VA_ARGS__)
#define ESP_EARLY_LOGW(...) LT_W(__VA_ARGS__)
#define ESP_EARLY_LOGE(...) LT_E(__VA_ARGS__)
#define ets_printf(...) LT_I(__VA_ARGS__)
#define ETS_PRINTF(...) LT_I(__VA_ARGS__)
#define LT_T_MOD(module, ...) \
do { \
@@ -126,6 +141,16 @@ void lt_log(const uint8_t level, const char *format, ...);
return ret; \
}
#if LT_LOG_ERRNO
#define LT_ERRNO() \
if (errno) { \
LT_E("errno=%d", errno); \
errno = 0; \
}
#else
#define LT_ERRNO()
#endif
// WiFi.cpp
#define LT_T_WG(...) LT_T_MOD(LT_DEBUG_WIFI, __VA_ARGS__)
#define LT_V_WG(...) LT_T_MOD(LT_DEBUG_WIFI, __VA_ARGS__)

View File

@@ -0,0 +1,30 @@
/* Copyright (c) Kuba Szczodrzyński 2022-04-24. */
#include "Flash.h"
extern "C" {
#include <fal.h>
}
// Global Flash object.
FlashClass Flash;
FlashId FlashClass::getChipId() {
return LT.getFlashChipId();
}
uint32_t FlashClass::getSize() {
return LT.getFlashChipSize();
}
bool FlashClass::eraseSector(uint32_t offset) {
return fal_partition_erase(fal_root_part, offset, 1) >= 0;
}
bool FlashClass::readBlock(uint32_t offset, uint8_t *data, size_t size) {
return fal_partition_read(fal_root_part, offset, data, size) >= 0;
}
bool FlashClass::writeBlock(uint32_t offset, uint8_t *data, size_t size) {
return fal_partition_write(fal_root_part, offset, data, size) >= 0;
}

View File

@@ -2,20 +2,10 @@
#pragma once
#include "api/Flash.h"
struct flash_s;
typedef struct flash_s flash_t;
class FlashClass : public IFlashClass {
private:
flash_t *flash;
void initialize();
#include <Arduino.h>
class FlashClass {
public:
FlashClass();
~FlashClass();
FlashId getChipId();
uint32_t getSize();

View File

@@ -25,11 +25,13 @@
* Adapted in October 2018
*/
#if LT_ARD_HAS_WIFI
#include <Arduino.h>
#ifdef HTTPCLIENT_1_1_COMPATIBLE
#include <WiFi.h>
// #include <WiFiClientSecure.h>
#include <WiFiClientSecure.h>
#endif
// #include <StreamString.h>
@@ -63,7 +65,7 @@ class TLSTraits : public TransportTraits {
TLSTraits(const char *CAcert, const char *clicert = nullptr, const char *clikey = nullptr)
: _cacert(CAcert), _clicert(clicert), _clikey(clikey) {}
/* std::unique_ptr<WiFiClient> create() override {
std::unique_ptr<WiFiClient> create() override {
return std::unique_ptr<WiFiClient>(new WiFiClientSecure());
}
@@ -77,7 +79,7 @@ class TLSTraits : public TransportTraits {
wcs.setPrivateKey(_clikey);
}
return true;
} */
}
protected:
const char *_cacert;
@@ -1623,3 +1625,5 @@ bool HTTPClient::generateCookieString(String *cookieString) {
return found;
}
#endif // LT_ARD_HAS_WIFI

View File

@@ -33,7 +33,7 @@
#include <Arduino.h>
#include <WiFiClient.h>
// #include <WiFiClientSecure.h>
#include <WiFiClientSecure.h>
#include <memory>
/// Cookie jar support

View File

@@ -0,0 +1,37 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-03. */
#pragma once
#include <Arduino.h>
#include <MD5Impl.h>
// available built-in implementations
#if LT_MD5_USE_POLARSSL
#include "MD5PolarSSLImpl.h"
#endif
#if LT_MD5_USE_MBEDTLS
#include "MD5MbedTLSImpl.h"
#endif
#if LT_MD5_USE_HOSTAPD
#include "MD5HostapdImpl.h"
#endif
// common API
#ifdef __cplusplus
extern "C" {
#endif
#ifndef LT_MD5_CTX_T
#define LT_MD5_CTX_T void
#endif
// for compatibility with ESP8266
typedef LT_MD5_CTX_T md5_context_t;
void MD5Init(LT_MD5_CTX_T *context);
void MD5Update(LT_MD5_CTX_T *context, const unsigned char *buf, unsigned len);
void MD5Final(unsigned char digest[16], LT_MD5_CTX_T *context);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,14 @@
/* Copyright (c) Kuba Szczodrzyński 2022-07-12. */
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <crypto/md5_i.h>
#define LT_MD5_CTX_T struct MD5Context
#ifdef __cplusplus
} // extern "C"
#endif

View File

@@ -0,0 +1,28 @@
/* Copyright (c) Kuba Szczodrzyński 2022-07-11. */
#if LT_ARD_HAS_MD5
#include "MD5.h"
#if LT_MD5_USE_MBEDTLS
extern "C" {
void MD5Init(LT_MD5_CTX_T *context) {
mbedtls_md5_init(context);
mbedtls_md5_starts(context);
}
void MD5Update(LT_MD5_CTX_T *context, const unsigned char *buf, unsigned len) {
mbedtls_md5_update(context, buf, len);
}
void MD5Final(unsigned char digest[16], LT_MD5_CTX_T *context) {
mbedtls_md5_finish(context, digest);
}
} // extern "C"
#endif // LT_MD5_USE_MBEDTLS
#endif // LT_ARD_HAS_MD5

View File

@@ -0,0 +1,14 @@
/* Copyright (c) Kuba Szczodrzyński 2022-07-11. */
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <mbedtls/md5.h>
#define LT_MD5_CTX_T mbedtls_md5_context
#ifdef __cplusplus
} // extern "C"
#endif

View File

@@ -0,0 +1,28 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-03. */
#if LT_ARD_HAS_MD5
#include "MD5.h"
#if LT_MD5_USE_POLARSSL
extern "C" {
void MD5Init(LT_MD5_CTX_T *context) {
md5_init(context);
md5_starts(context);
}
void MD5Update(LT_MD5_CTX_T *context, const unsigned char *buf, unsigned len) {
md5_update(context, buf, len);
}
void MD5Final(unsigned char digest[16], LT_MD5_CTX_T *context) {
md5_finish(context, digest);
}
} // extern "C"
#endif // LT_MD5_USE_POLARSSL
#endif // LT_ARD_HAS_MD5

View File

@@ -0,0 +1,14 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-03. */
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <polarssl/md5.h>
#define LT_MD5_CTX_T md5_context
#ifdef __cplusplus
} // extern "C"
#endif

View File

@@ -1,7 +1,29 @@
/* Copyright (c) Kuba Szczodrzyński 2022-04-26. */
#include "WiFiClient.h"
#include "WiFiPriv.h"
#if LT_ARD_HAS_WIFI && LT_HAS_LWIP
#include "LwIPClient.h"
#define MAX_SOCK_NUM 4
#define WIFI_CLIENT_CONNECT_TIMEOUT 3000
#define WIFI_CLIENT_READ_TIMEOUT 3000
#define WIFI_CLIENT_WRITE_RETRY 10
#define WIFI_CLIENT_SELECT_TIMEOUT 1000
#define WIFI_CLIENT_FLUSH_BUF_SIZE 1024
// disable #defines removing lwip_ prefix
#undef LWIP_COMPAT_SOCKETS
#define LWIP_COMPAT_SOCKETS 0
extern "C" {
#include <lwip/api.h>
#include <lwip/dns.h>
#include <lwip/err.h>
#include <lwip/sockets.h>
#include <sys/time.h>
} // extern "C"
class SocketHandle {
public:
@@ -14,28 +36,28 @@ class SocketHandle {
}
};
WiFiClient::WiFiClient() {
LT_V_WC("WiFiClient()");
LwIPClient::LwIPClient() {
LT_V_WC("LwIPClient()");
_connected = false;
_sock = NULL;
_rxBuffer = NULL;
_timeout = WIFI_CLIENT_CONNECT_TIMEOUT;
}
WiFiClient::WiFiClient(int sock) {
LT_V_WC("WiFiClient(%d)", sock);
LwIPClient::LwIPClient(int sock) {
LT_V_WC("LwIPClient(%d)", sock);
_connected = true;
_sock = std::make_shared<SocketHandle>(sock);
_rxBuffer = std::make_shared<LwIPRxBuffer>(sock);
_timeout = WIFI_CLIENT_CONNECT_TIMEOUT;
}
WiFiClient::~WiFiClient() {
LT_V_WC("~WiFiClient()");
LwIPClient::~LwIPClient() {
LT_V_WC("~LwIPClient()");
stop();
}
WiFiClient &WiFiClient::operator=(const WiFiClient &other) {
LwIPClient &LwIPClient::operator=(const LwIPClient &other) {
stop();
_connected = other._connected;
_sock = other._sock;
@@ -47,29 +69,37 @@ bool IWiFiClient::operator==(const IWiFiClient &other) const {
return fd() == other.fd() && remoteIP() == other.remoteIP() && remotePort() == other.remotePort();
}
int WiFiClient::connect(IPAddress ip, uint16_t port) {
int LwIPClient::connect(IPAddress ip, uint16_t port) {
return connect(ip, port, _timeout);
}
int WiFiClient::connect(const char *host, uint16_t port) {
int LwIPClient::connect(const char *host, uint16_t port) {
return connect(host, port, _timeout);
}
int WiFiClient::connect(const char *host, uint16_t port, int32_t timeout) {
int LwIPClient::connect(const char *host, uint16_t port, int32_t timeout) {
IPAddress ip = WiFi.hostByName(host);
if (!ip)
return 0;
return connect(ip, port, timeout);
}
int WiFiClient::connect(IPAddress ip, uint16_t port, int32_t timeout) {
int LwIPClient::connect(IPAddress ip, uint16_t port, int32_t timeout) {
if (_connected)
stop();
int sock = lwip_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock < 0) {
LT_D_WC("socket failed");
return -1;
}
if (timeout <= 0)
timeout = _timeout; // use default when -1 passed as timeout
lwip_fcntl(sock, F_SETFL, lwip_fcntl(sock, F_GETFL, 0) | O_NONBLOCK);
LT_ERRNO();
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
@@ -80,7 +110,7 @@ int WiFiClient::connect(IPAddress ip, uint16_t port, int32_t timeout) {
FD_ZERO(&fdset);
FD_SET(sock, &fdset);
tv.tv_sec = 0;
tv.tv_usec = timeout * 1000;
tv.tv_usec = timeout * 1000; // millis -> micros
int res = lwip_connect(sock, (struct sockaddr *)&addr, sizeof(addr));
if (res < 0 && errno != EINPROGRESS) {
@@ -117,19 +147,23 @@ int WiFiClient::connect(IPAddress ip, uint16_t port, int32_t timeout) {
lwip_setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &enable, sizeof(enable));
lwip_setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable));
LT_ERRNO();
lwip_fcntl(sock, F_SETFL, lwip_fcntl(sock, F_GETFL, 0) & ~O_NONBLOCK);
LT_ERRNO();
_connected = true;
_sock = std::make_shared<SocketHandle>(sock);
_rxBuffer = std::make_shared<LwIPRxBuffer>(sock);
return 1;
}
size_t WiFiClient::write(uint8_t data) {
size_t LwIPClient::write(uint8_t data) {
return write(&data, 1);
}
size_t WiFiClient::write(Stream &stream) {
size_t LwIPClient::write(Stream &stream) {
uint8_t *buf = (uint8_t *)malloc(1360);
if (!buf) {
return 0;
@@ -146,7 +180,7 @@ size_t WiFiClient::write(Stream &stream) {
return written;
}
size_t WiFiClient::write(const uint8_t *buf, size_t size) {
size_t LwIPClient::write(const uint8_t *buf, size_t size) {
if (_sock < 0 || !_connected || !size) {
setWriteError();
return 0;
@@ -189,36 +223,38 @@ size_t WiFiClient::write(const uint8_t *buf, size_t size) {
}
}
}
LT_D_WC("wrote %d bytes", written);
return written;
}
int WiFiClient::available() {
int LwIPClient::available() {
if (!_connected || !_rxBuffer)
return 0;
int res = _rxBuffer->available();
if (_rxBuffer->failed()) {
LT_ERRNO();
stop();
}
return res;
}
int WiFiClient::fd() const {
int LwIPClient::fd() const {
if (!_sock)
return -1;
return _sock->fd;
}
int WiFiClient::socket() {
int LwIPClient::socket() {
return fd();
}
int WiFiClient::setTimeout(uint32_t seconds) {
int LwIPClient::setTimeout(uint32_t seconds) {
Client::setTimeout(seconds * 1000);
lwip_setsockopt(fd(), SOL_SOCKET, SO_RCVTIMEO, &_timeout, sizeof(_timeout));
return lwip_setsockopt(fd(), SOL_SOCKET, SO_SNDTIMEO, &_timeout, sizeof(_timeout));
}
int WiFiClient::read() {
int LwIPClient::read() {
uint8_t data;
int res = read(&data, 1);
if (res < 0)
@@ -228,7 +264,7 @@ int WiFiClient::read() {
return data;
}
int WiFiClient::read(uint8_t *buf, size_t size) {
int LwIPClient::read(uint8_t *buf, size_t size) {
int res = -1;
if (_rxBuffer) {
res = _rxBuffer->read(buf, size);
@@ -239,7 +275,7 @@ int WiFiClient::read(uint8_t *buf, size_t size) {
return res;
}
int WiFiClient::peek() {
int LwIPClient::peek() {
int res = -1;
if (_rxBuffer) {
res = _rxBuffer->peek();
@@ -250,7 +286,7 @@ int WiFiClient::peek() {
return res;
}
void WiFiClient::flush() {
void LwIPClient::flush() {
int res;
size_t len = available();
if (!len)
@@ -269,14 +305,14 @@ void WiFiClient::flush() {
free(buf);
}
void WiFiClient::stop() {
LT_V_WC("stop()");
void LwIPClient::stop() {
LT_V_WC("Stopping TCP");
_connected = false;
_sock = NULL;
_rxBuffer = NULL;
}
uint8_t WiFiClient::connected() {
uint8_t LwIPClient::connected() {
if (_connected) {
uint8_t dummy;
if (lwip_recv(fd(), &dummy, 0, MSG_DONTWAIT) <= 0) {
@@ -320,34 +356,36 @@ uint16_t __attribute__((noinline)) getport(int sock, int (*func)(int, struct soc
return ntohs(s->sin_port);
}
IPAddress WiFiClient::remoteIP() const {
IPAddress LwIPClient::remoteIP() const {
return getaddr(fd(), lwip_getpeername);
}
IPAddress WiFiClient::remoteIP(int fd) const {
IPAddress LwIPClient::remoteIP(int fd) const {
return getaddr(fd, lwip_getpeername);
}
uint16_t WiFiClient::remotePort() const {
uint16_t LwIPClient::remotePort() const {
return getport(fd(), lwip_getpeername);
}
uint16_t WiFiClient::remotePort(int fd) const {
uint16_t LwIPClient::remotePort(int fd) const {
return getport(fd, lwip_getpeername);
}
IPAddress WiFiClient::localIP() const {
IPAddress LwIPClient::localIP() const {
return getaddr(fd(), lwip_getsockname);
}
IPAddress WiFiClient::localIP(int fd) const {
IPAddress LwIPClient::localIP(int fd) const {
return getaddr(fd, lwip_getsockname);
}
uint16_t WiFiClient::localPort() const {
uint16_t LwIPClient::localPort() const {
return getport(fd(), lwip_getsockname);
}
uint16_t WiFiClient::localPort(int fd) const {
uint16_t LwIPClient::localPort(int fd) const {
return getport(fd, lwip_getsockname);
}
#endif

View File

@@ -0,0 +1,56 @@
/* Copyright (c) Kuba Szczodrzyński 2022-04-26. */
#pragma once
#include <api/WiFi/WiFi.h>
#include <api/WiFiClient.h>
#include <lwip/LwIPRxBuffer.h>
#include <memory>
class SocketHandle;
class LwIPClient : public IWiFiClient {
private:
bool _connected;
std::shared_ptr<SocketHandle> _sock;
std::shared_ptr<LwIPRxBuffer> _rxBuffer;
public:
LwIPClient();
LwIPClient(int sock);
~LwIPClient();
int connect(IPAddress ip, uint16_t port);
int connect(const char *host, uint16_t port);
int connect(IPAddress ip, uint16_t port, int32_t timeout);
int connect(const char *host, uint16_t port, int32_t timeout);
size_t write(uint8_t data);
size_t write(const uint8_t *buf, size_t size);
size_t write(Stream &stream);
int available();
int fd() const;
int socket();
int setTimeout(uint32_t seconds);
int read();
int read(uint8_t *buf, size_t size);
int peek();
void flush();
void stop();
uint8_t connected();
LwIPClient &operator=(const LwIPClient &other);
IPAddress remoteIP() const;
IPAddress remoteIP(int sock) const;
uint16_t remotePort() const;
uint16_t remotePort(int sock) const;
IPAddress localIP() const;
IPAddress localIP(int sock) const;
uint16_t localPort() const;
uint16_t localPort(int sock) const;
using Print::write;
};

View File

@@ -1,26 +1,26 @@
#ifdef LT_HAS_LWIP
#if LT_HAS_LWIP
#include "LwIPRxBuffer.h"
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
// disable #defines removing lwip_ prefix
#undef LWIP_COMPAT_SOCKETS
#define LWIP_COMPAT_SOCKETS 0
extern "C" {
#include <lwip/sockets.h>
#ifdef __cplusplus
} // extern "C"
#endif
size_t LwIPRxBuffer::r_available() {
if (_sock < 0) {
LT_D_WC("_sock < 0");
return 0;
}
uint16_t count = 0;
int res = lwip_ioctl(_sock, FIONREAD, &count);
int count = 0; // must be of same size as in lwip_ioctl()
int res = lwip_ioctl(_sock, FIONREAD, &count);
if (res < 0) {
LT_D_WC("lwip_ioctl()=%d, errno=%d", res, errno);
_failed = true;
return 0;
}
@@ -31,7 +31,7 @@ size_t LwIPRxBuffer::fillBuffer() {
if (!_buffer) {
_buffer = (uint8_t *)malloc(_size);
if (!_buffer) {
printf("[e] Not enough memory to allocate buffer\r\n");
LT_E("buffer alloc failed");
_failed = true;
return 0;
}
@@ -46,6 +46,7 @@ size_t LwIPRxBuffer::fillBuffer() {
int res = lwip_recv(_sock, _buffer + _fill, _size - _fill, MSG_DONTWAIT);
if (res < 0) {
if (errno != EWOULDBLOCK) {
LT_ERRNO();
_failed = true;
}
return 0;

View File

@@ -1,17 +1,30 @@
/* Copyright (c) Kuba Szczodrzyński 2022-04-26. */
#include "WiFiServer.h"
#include "WiFiPriv.h"
#if LT_ARD_HAS_WIFI && LT_HAS_LWIP
WiFiServer::WiFiServer(uint32_t addr, uint16_t port, uint8_t maxClients)
#include "LwIPServer.h"
// disable #defines removing lwip_ prefix
#undef LWIP_COMPAT_SOCKETS
#define LWIP_COMPAT_SOCKETS 0
extern "C" {
#include <lwip/api.h>
// #include <lwip/dns.h>
#include <lwip/err.h>
#include <lwip/sockets.h>
#include <sys/time.h>
}
LwIPServer::LwIPServer(uint32_t addr, uint16_t port, uint8_t maxClients)
: _sock(-1), _sockAccepted(-1), _addr(addr), _port(port), _maxClients(maxClients), _active(false), _noDelay(false) {
}
WiFiServer::operator bool() {
LwIPServer::operator bool() {
return _active;
}
bool WiFiServer::begin(uint16_t port, bool reuseAddr) {
bool LwIPServer::begin(uint16_t port, bool reuseAddr) {
if (_active)
return true;
if (port)
@@ -50,7 +63,7 @@ bool WiFiServer::begin(uint16_t port, bool reuseAddr) {
_sockAccepted = -1;
}
void WiFiServer::end() {
void LwIPServer::end() {
if (_sock == -1)
return;
lwip_close(_sock);
@@ -58,7 +71,7 @@ void WiFiServer::end() {
_active = -1;
}
WiFiClient WiFiServer::accept() {
WiFiClient LwIPServer::accept() {
if (!_active)
return WiFiClient();
@@ -96,7 +109,7 @@ WiFiClient WiFiServer::accept() {
return WiFiClient();
}
int WiFiServer::setTimeout(uint32_t seconds) {
int LwIPServer::setTimeout(uint32_t seconds) {
struct timeval tv;
tv.tv_sec = seconds;
tv.tv_usec = 0;
@@ -105,15 +118,15 @@ int WiFiServer::setTimeout(uint32_t seconds) {
return lwip_setsockopt(_sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
}
void WiFiServer::setNoDelay(bool noDelay) {
void LwIPServer::setNoDelay(bool noDelay) {
_noDelay = noDelay;
}
bool WiFiServer::getNoDelay() {
bool LwIPServer::getNoDelay() {
return _noDelay;
}
bool WiFiServer::hasClient() {
bool LwIPServer::hasClient() {
if (_sockAccepted >= 0) {
return true;
}
@@ -125,3 +138,5 @@ bool WiFiServer::hasClient() {
}
return false;
}
#endif

View File

@@ -0,0 +1,47 @@
/* Copyright (c) Kuba Szczodrzyński 2022-04-26. */
#pragma once
#include <api/WiFi/WiFi.h>
#include <api/WiFiServer.h>
#include <WiFiClient.h>
class LwIPServer : public IWiFiServer<WiFiClient> {
private:
int _sock;
int _sockAccepted;
uint32_t _addr;
uint16_t _port;
uint8_t _maxClients;
bool _active;
bool _noDelay = false;
private:
LwIPServer(uint32_t addr, uint16_t port = 80, uint8_t maxClients = 4);
public:
LwIPServer(uint16_t port = 80, uint8_t maxClients = 4) : LwIPServer((uint32_t)0, port, maxClients) {}
LwIPServer(int port = 80, uint8_t maxClients = 4) : LwIPServer((uint32_t)0, port, maxClients) {}
LwIPServer(const IPAddress &addr, uint16_t port = 80, uint8_t maxClients = 4)
: LwIPServer((uint32_t)addr, port, maxClients) {}
operator bool();
bool begin(uint16_t port = 0, bool reuseAddr = true);
void end();
WiFiClient accept();
size_t write(const uint8_t *buffer, size_t size) {
return 0;
}
void stopAll() {}
int setTimeout(uint32_t seconds);
void setNoDelay(bool noDelay);
bool getNoDelay();
bool hasClient();
};

View File

@@ -1,31 +1,33 @@
/* Copyright (c) Kuba Szczodrzyński 2022-04-30. */
#if LT_ARD_HAS_WIFI && LT_HAS_MBEDTLS
#include "MbedTLSClient.h"
#include <IPAddress.h>
#include <WiFi.h>
#include <WiFiClient.h>
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#include <mbedtls/debug.h>
#include <mbedtls/platform.h>
#include <mbedtls/sha256.h>
#include <mbedtls/ssl.h>
#ifdef __cplusplus
} // extern "C"
#endif
MbedTLSClient::MbedTLSClient() : WiFiClient() {}
MbedTLSClient::MbedTLSClient() : WiFiClient() {
init(); // ensure the context is zero filled
}
MbedTLSClient::MbedTLSClient(int sock) : WiFiClient(sock) {}
MbedTLSClient::MbedTLSClient(int sock) : WiFiClient(sock) {
init(); // ensure the context is zero filled
}
MbedTLSClient::~MbedTLSClient() {
LT_V_WC("~MbedTLSClient()");
stop();
}
void MbedTLSClient::stop() {
WiFiClient::stop();
LT_V_SSL("Closing SSL connection");
LT_V_SSL("Stopping SSL");
if (_sslCfg.ca_chain) {
mbedtls_x509_crt_free(&_caCert);
@@ -36,6 +38,7 @@ void MbedTLSClient::stop() {
}
mbedtls_ssl_free(&_sslCtx);
mbedtls_ssl_config_free(&_sslCfg);
LT_HEAP_I();
}
void MbedTLSClient::init() {
@@ -46,73 +49,71 @@ void MbedTLSClient::init() {
}
int MbedTLSClient::connect(IPAddress ip, uint16_t port, int32_t timeout) {
return connect(ipToString(ip).c_str(), port, timeout) == 0;
return connect(ipToString(ip).c_str(), port, timeout);
}
int MbedTLSClient::connect(const char *host, uint16_t port, int32_t timeout) {
if (_pskIdentStr && _pskStr)
return connect(host, port, NULL, NULL, NULL, _pskIdentStr, _pskStr, _alpnProtocols) == 0;
return connect(host, port, _caCertStr, _clientCertStr, _clientKeyStr, NULL, NULL, _alpnProtocols) == 0;
return connect(host, port, timeout, NULL, NULL, NULL, _pskIdentStr, _pskStr) == 0;
return connect(host, port, timeout, _caCertStr, _clientCertStr, _clientKeyStr, NULL, NULL) == 0;
}
int MbedTLSClient::connect(
IPAddress ip, uint16_t port, const char *rootCABuf, const char *clientCert, const char *clientKey
) {
return connect(ipToString(ip).c_str(), port, rootCABuf, clientCert, clientKey, NULL, NULL, _alpnProtocols) == 0;
return connect(ipToString(ip).c_str(), port, 0, rootCABuf, clientCert, clientKey, NULL, NULL) == 0;
}
int MbedTLSClient::connect(
const char *host, uint16_t port, const char *rootCABuf, const char *clientCert, const char *clientKey
) {
return connect(host, port, rootCABuf, clientCert, clientKey, NULL, NULL, _alpnProtocols) == 0;
return connect(host, port, 0, rootCABuf, clientCert, clientKey, NULL, NULL) == 0;
}
int MbedTLSClient::connect(IPAddress ip, uint16_t port, const char *pskIdent, const char *psk) {
return connect(ipToString(ip).c_str(), port, NULL, NULL, NULL, pskIdent, psk, _alpnProtocols) == 0;
return connect(ipToString(ip).c_str(), port, 0, NULL, NULL, NULL, pskIdent, psk) == 0;
}
int MbedTLSClient::connect(const char *host, uint16_t port, const char *pskIdent, const char *psk) {
return connect(host, port, NULL, NULL, NULL, pskIdent, psk, _alpnProtocols) == 0;
return connect(host, port, 0, NULL, NULL, NULL, pskIdent, psk) == 0;
}
static int ssl_random(void *data, unsigned char *output, size_t len) {
int *buf = (int *)output;
size_t i;
for (i = 0; len >= sizeof(int); len -= sizeof(int)) {
buf[i++] = rand();
}
if (len) {
int rem = rand();
unsigned char *pRem = (unsigned char *)&rem;
memcpy(output + i * sizeof(int), pRem, len);
}
lt_rand_bytes((uint8_t *)output, len);
return 0;
}
void debug_cb(void *ctx, int level, const char *file, int line, const char *str) {
LT_I("%04d: |%d| %s", line, level, str);
// do not print the trailing \n
uint16_t len = strlen(str);
char *msg = (char *)str;
msg[len - 1] = '\0';
LT_I("%04d: |%d| %s", line, level, msg);
}
int MbedTLSClient::connect(
const char *host,
uint16_t port,
int32_t timeout,
const char *rootCABuf,
const char *clientCert,
const char *clientKey,
const char *pskIdent,
const char *psk,
const char **alpnProtocols
const char *psk
) {
LT_D_SSL("Free heap before TLS: TODO");
LT_HEAP_I();
if (!rootCABuf && !pskIdent && !psk && !_insecure && !_useRootCA)
return -1;
if (timeout <= 0)
timeout = _timeout; // use default when -1 passed as timeout
IPAddress addr = WiFi.hostByName(host);
if (!(uint32_t)addr)
return -1;
int ret = WiFiClient::connect(addr, port, _timeout);
int ret = WiFiClient::connect(addr, port, timeout);
if (ret < 0) {
LT_E("SSL socket failed");
return ret;
@@ -122,6 +123,7 @@ int MbedTLSClient::connect(
LT_V_SSL("Init SSL");
init();
LT_HEAP_I();
// mbedtls_debug_set_threshold(4);
// mbedtls_ssl_conf_dbg(&_sslCfg, debug_cb, NULL);
@@ -135,8 +137,8 @@ int MbedTLSClient::connect(
LT_RET_NZ(ret);
#ifdef MBEDTLS_SSL_ALPN
if (alpnProtocols) {
ret = mbedtls_ssl_conf_alpn_protocols(&_sslCfg, alpnProtocols);
if (_alpnProtocols) {
ret = mbedtls_ssl_conf_alpn_protocols(&_sslCfg, _alpnProtocols);
LT_RET_NZ(ret);
}
#endif
@@ -208,10 +210,13 @@ int MbedTLSClient::connect(
_sockTls = fd();
mbedtls_ssl_set_bio(&_sslCtx, &_sockTls, mbedtls_net_send, mbedtls_net_recv, NULL);
mbedtls_net_set_nonblock((mbedtls_net_context *)&_sockTls);
LT_HEAP_I();
LT_V_SSL("SSL handshake");
if (_handshakeTimeout == 0)
_handshakeTimeout = _timeout * 1000;
_handshakeTimeout = timeout;
unsigned long start = millis();
while (ret = mbedtls_ssl_handshake(&_sslCtx)) {
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
@@ -224,6 +229,8 @@ int MbedTLSClient::connect(
delay(2);
}
LT_HEAP_I();
if (clientCert && clientKey) {
LT_D_SSL(
"Protocol %s, ciphersuite %s",
@@ -441,3 +448,5 @@ bool MbedTLSClient::getFingerprintSHA256(uint8_t result[32]) {
mbedtls_sha256_finish(&shaCtx, result);
return true;
}
#endif // LT_ARD_HAS_WIFI && LT_HAS_MBEDTLS

View File

@@ -2,20 +2,17 @@
#pragma once
#include <api/WiFi/WiFi.h>
#include <api/WiFiClient.h>
#include <api/WiFiClientSecure.h>
#include <WiFiClient.h> // extend platform's WiFiClient impl
#include <WiFiClient.h> // extend family's WiFiClient impl
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#include <mbedtls/net.h>
#ifdef __cplusplus
} // extern "C"
#endif
class MbedTLSClient : public WiFiClient, public IWiFiClientSecure {
private:
@@ -42,17 +39,18 @@ class MbedTLSClient : public WiFiClient, public IWiFiClientSecure {
int connect(
const char *host,
uint16_t port,
int32_t timeout,
const char *rootCABuf,
const char *clientCert,
const char *clientKey,
const char *pskIdent,
const char *psk,
const char **alpnProtocols
const char *psk
);
public:
MbedTLSClient();
MbedTLSClient(int sock);
~MbedTLSClient();
int connect(IPAddress ip, uint16_t port, int32_t timeout);
int connect(const char *host, uint16_t port, int32_t timeout);

View File

@@ -0,0 +1,66 @@
/**
StreamString.cpp
Copyright (c) 2015 Markus Sattler. All rights reserved.
This file is part of the esp8266 core for Arduino environment.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <Arduino.h>
#include "StreamString.h"
size_t StreamString::write(const uint8_t *data, size_t size) {
if(size && data) {
const unsigned int newlen = len + size;
if(reserve(newlen + 1)) {
memcpy((void *) (buffer + len), (const void *) data, size);
changeBuffer(newlen);
*(buffer + newlen) = 0x00; // add null for string end
return size;
}
}
return 0;
}
size_t StreamString::write(uint8_t data) {
return concat((char) data);
}
int StreamString::available() {
return length();
}
int StreamString::read() {
if(length()) {
char c = charAt(0);
remove(0, 1);
return c;
}
return -1;
}
int StreamString::peek() {
if(length()) {
char c = charAt(0);
return c;
}
return -1;
}
void StreamString::flush() {
}

View File

@@ -0,0 +1,39 @@
/**
StreamString.h
Copyright (c) 2015 Markus Sattler. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef STREAMSTRING_H_
#define STREAMSTRING_H_
class StreamString: public Stream, public String
{
public:
size_t write(const uint8_t *buffer, size_t size) override;
size_t write(uint8_t data) override;
int available() override;
int read() override;
int peek() override;
void flush() override;
};
#endif /* STREAMSTRING_H_ */

View File

@@ -0,0 +1,203 @@
/* Copyright (c) Kuba Szczodrzyński 2022-05-29. */
#include "Update.h"
UpdateClass::UpdateClass() : ctx(NULL), info(NULL), buf(NULL) {
cleanup();
}
/**
* @brief Initialize the update process.
*
* @param size total UF2 file size
* @param command must be U_FLASH
* @return false if parameters are invalid or update is running, true otherwise
*/
bool UpdateClass::begin(size_t size, int command, int unused2, uint8_t unused3, const char *unused4) {
if (ctx)
return false;
cleanup();
ctx = uf2_ctx_init(LT.otaGetTarget(), FAMILY);
info = uf2_info_init();
if (!size)
return errorArd(UPDATE_ERROR_SIZE);
if (command != U_FLASH)
return errorArd(UPDATE_ERROR_BAD_ARGUMENT);
bytesTotal = size;
return true;
}
/**
* @brief Finalize the update process. Check for errors and update completion, then activate the new firmware image.
*
* @param evenIfRemaining no idea
* @return false in case of errors or no update running, true otherwise
*/
bool UpdateClass::end(bool evenIfRemaining) {
if (hasError() || !ctx)
// false if not running
return false;
if (!isFinished() && !evenIfRemaining) {
// abort if not finished
return errorArd(UPDATE_ERROR_ABORT);
}
// TODO what is evenIfRemaining for?
if (!LT.otaSwitch())
// try to activate the second OTA
return errorArd(UPDATE_ERROR_ACTIVATE);
cleanup();
return true;
}
/**
* @brief Write a chunk of data to the buffer or flash memory.
*
* It's advised to write in 512-byte chunks (or its multiples).
*
* @param data
* @param len
* @return size_t
*/
size_t UpdateClass::write(uint8_t *data, size_t len) {
size_t written = 0;
if (hasError() || !ctx)
// 0 if not running
return 0;
/* while (buf == bufPos && len >= UF2_BLOCK_SIZE) {
// buffer empty and entire block is in data
if (!tryWriteData(data, UF2_BLOCK_SIZE)) {
// returns 0 if data contains an invalid block
return written;
}
data += UF2_BLOCK_SIZE;
len -= UF2_BLOCK_SIZE;
written += UF2_BLOCK_SIZE;
} */
// write until buffer space is available
uint16_t toWrite;
while (len && (toWrite = min(len, bufLeft()))) {
tryWriteData(data, toWrite);
if (hasError())
// return on errors
return written;
data += toWrite;
len -= toWrite;
written += toWrite;
}
return written;
}
size_t UpdateClass::writeStream(Stream &data) {
size_t written = 0;
if (hasError() || !ctx)
// 0 if not running
return 0;
uint32_t lastData = millis();
// loop until the update is complete
while (remaining()) {
// check stream availability
int available = data.available();
if (available <= 0) {
if (millis() - lastData > UPDATE_TIMEOUT_MS) {
// waited for data too long; abort with error
errorArd(UPDATE_ERROR_STREAM);
return written;
}
continue;
}
// available > 0
lastData = millis();
// read data to fit in the remaining buffer space
bufAlloc();
uint16_t read = data.readBytes(bufPos, bufLeft());
bufPos += read;
written += read;
tryWriteData();
if (hasError())
// return on errors
return written;
}
return written;
}
/**
* @brief Try to use the buffer as a block to write. In case of UF2 errors,
* error codes are set, the update is aborted and 0 is returned
*
* @param data received data to copy to buffer or NULL if already in buffer
* @param len received data length - must be at most bufLeft()
* @return size_t "used" data size - 0 or 512
*/
size_t UpdateClass::tryWriteData(uint8_t *data, size_t len) {
uf2_block_t *block = NULL;
if (len == UF2_BLOCK_SIZE) {
// data has a complete block
block = (uf2_block_t *)data;
} else if (data && len) {
// data has a part of a block, copy it to buffer
bufAlloc();
memcpy(bufPos, data, len);
bufPos += len;
}
if (!block && bufSize() == UF2_BLOCK_SIZE) {
// use buffer as block (only if not found above)
block = (uf2_block_t *)buf;
}
// a complete block has been found
if (block) {
if (errorUf2(uf2_check_block(ctx, block)))
// block is invalid
return 0;
if (errUf2 == UF2_ERR_IGNORE)
// treat ignored blocks as valid
return UF2_BLOCK_SIZE;
if (!bytesWritten) {
// parse header block to allow retrieving firmware info
if (errorUf2(uf2_parse_header(ctx, block, info)))
// header is invalid
return 0;
if (bytesTotal == UPDATE_SIZE_UNKNOWN) {
// set total update size from block count info
bytesTotal = block->block_count * UF2_BLOCK_SIZE;
} else if (bytesTotal != block->block_count * UF2_BLOCK_SIZE) {
// given update size does not match the block count
return errorArd(UPDATE_ERROR_SIZE);
}
} else {
// write data blocks normally
if (errorUf2(uf2_write(ctx, block)))
// block writing failed
return 0;
}
// increment total writing progress
bytesWritten += UF2_BLOCK_SIZE;
// call progress callback
if (callback)
callback(bytesWritten, bytesTotal);
// reset the buffer as it's used already
if (bufSize() == UF2_BLOCK_SIZE)
bufPos = buf;
return UF2_BLOCK_SIZE;
}
return 0;
}
UpdateClass Update;

View File

@@ -0,0 +1,150 @@
#pragma once
#include <Arduino.h>
#include <functional>
#include "uf2ota/uf2ota.h"
// No Error
#define UPDATE_ERROR_OK (0)
// Flash Write Failed
#define UPDATE_ERROR_WRITE (1)
// Flash Erase Failed
#define UPDATE_ERROR_ERASE (2)
// Flash Read Failed
#define UPDATE_ERROR_READ (3)
// Not Enough Space
#define UPDATE_ERROR_SPACE (4)
// Bad Size Given
#define UPDATE_ERROR_SIZE (5)
// Stream Read Timeout
#define UPDATE_ERROR_STREAM (6)
// MD5 Check Failed
#define UPDATE_ERROR_MD5 (7)
// Wrong Magic Byte
#define UPDATE_ERROR_MAGIC_BYTE (8)
// Could Not Activate The Firmware
#define UPDATE_ERROR_ACTIVATE (9)
// Partition Could Not be Found
#define UPDATE_ERROR_NO_PARTITION (10)
// Bad Argument
#define UPDATE_ERROR_BAD_ARGUMENT (11)
// Aborted
#define UPDATE_ERROR_ABORT (12)
#define UPDATE_SIZE_UNKNOWN 0xFFFFFFFF
#define U_FLASH 0
#define U_SPIFFS 100
#define U_AUTH 200
#define ENCRYPTED_BLOCK_SIZE 16
#define UPDATE_TIMEOUT_MS 30 * 1000
class UpdateClass {
public:
typedef std::function<void(size_t, size_t)> THandlerFunction_Progress;
public: /* Update.cpp */
UpdateClass();
bool begin(
size_t size = UPDATE_SIZE_UNKNOWN,
int command = U_FLASH,
int unused2 = -1,
uint8_t unused3 = LOW,
const char *unused4 = NULL // this is for SPIFFS
);
bool end(bool evenIfRemaining = false);
size_t write(uint8_t *data, size_t len);
size_t writeStream(Stream &data);
bool canRollBack();
bool rollBack();
// bool setMD5(const char *expected_md5);
private: /* Update.cpp */
size_t tryWriteData(uint8_t *data = NULL, size_t len = 0);
public: /* UpdateUtil.cpp */
UpdateClass &onProgress(THandlerFunction_Progress callback);
void abort();
void printError(Print &out);
const char *errorString();
const char *getFirmwareName();
const char *getFirmwareVersion();
const char *getLibreTuyaVersion();
const char *getBoardName();
private: /* UpdateUtil.cpp */
void cleanup();
bool errorUf2(uf2_err_t err);
bool errorArd(uint8_t err);
void bufAlloc();
uint16_t bufLeft();
uint16_t bufSize();
private:
// uf2ota context
uf2_ota_t *ctx;
uf2_info_t *info;
// block buffer
uint8_t *buf;
uint8_t *bufPos;
// update progress - multiplies of 512 bytes
uint32_t bytesWritten;
uint32_t bytesTotal;
// errors
uf2_err_t errUf2;
uint8_t errArd;
// progress callback
THandlerFunction_Progress callback;
// String _target_md5;
// MD5Builder _md5;
public:
String md5String(void) {
// return _md5.toString();
}
void md5(uint8_t *result) {
// return _md5.getBytes(result);
}
uint8_t getError() {
return errArd;
}
uf2_err_t getUF2Error() {
return errUf2;
}
void clearError() {
errorUf2(UF2_ERR_OK);
}
bool hasError() {
return errArd != UPDATE_ERROR_OK;
}
bool isRunning() {
return ctx != NULL;
}
bool isFinished() {
return bytesWritten == bytesTotal;
}
size_t size() {
return bytesTotal;
}
size_t progress() {
return bytesWritten;
}
size_t remaining() {
return bytesTotal - bytesWritten;
}
};
extern UpdateClass Update;

View File

@@ -0,0 +1,162 @@
/* Copyright (c) Kuba Szczodrzyński 2022-05-30. */
#include "Update.h"
static const uint8_t errorMap[] = {
UPDATE_ERROR_OK, /* UF2_ERR_OK - no error */
UPDATE_ERROR_OK, /* UF2_ERR_IGNORE - block should be ignored */
UPDATE_ERROR_MAGIC_BYTE, /* UF2_ERR_MAGIC - wrong magic numbers */
UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_FAMILY - family ID mismatched */
UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_NOT_HEADER - block is not a header */
UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_OTA_VER - unknown/invalid OTA format version */
UPDATE_ERROR_MAGIC_BYTE, /* UF2_ERR_OTA_WRONG - no data for current OTA index */
UPDATE_ERROR_NO_PARTITION, /* UF2_ERR_PART_404 - no partition with that name */
UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_PART_ONE - only one partition tag in a block */
UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_PART_UNSET - attempted to write without target partition */
UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_DATA_TOO_LONG - data too long - tags won't fit */
UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_SEQ_MISMATCH - sequence number mismatched */
UPDATE_ERROR_ERASE, /* UF2_ERR_ERASE_FAILED - erasing flash failed */
UPDATE_ERROR_WRITE, /* UF2_ERR_WRITE_FAILED - writing to flash failed */
UPDATE_ERROR_WRITE /* UF2_ERR_WRITE_LENGTH - wrote fewer data than requested */
};
static char errorStr[14];
/**
* @brief Set the callback invoked after writing data to flash.
*/
UpdateClass &UpdateClass::onProgress(THandlerFunction_Progress callback) {
this->callback = callback;
return *this;
}
void UpdateClass::cleanup() {
free(ctx); // NULL in constructor
ctx = NULL;
uf2_info_free(info); // NULL in constructor
info = NULL;
free(buf); // NULL in constructor
buf = bufPos = NULL;
bytesWritten = 0;
bytesTotal = 0;
errUf2 = UF2_ERR_OK;
errArd = UPDATE_ERROR_OK;
}
/**
* @brief Check for UF2 errors. Set errArd and errUf2 in case of errors.
* Ignored blocks are not reported as errors.
* Abort the update.
* Use like: "if (errorUf2(...)) return false;"
* @return true if err is not OK, false otherwise
*/
bool UpdateClass::errorUf2(uf2_err_t err) {
if (err <= UF2_ERR_IGNORE)
return false;
cleanup();
errUf2 = err;
errArd = errorMap[err];
return true;
}
/**
* @brief Set errUf2 and errArd according to given Arduino error code.
* Abort the update.
* Use like: "return errorArd(...);"
* @return false - always
*/
bool UpdateClass::errorArd(uint8_t err) {
cleanup();
errUf2 = UF2_ERR_OK;
errArd = err;
return false;
}
/**
* @brief Abort the update with UPDATE_ERROR_ABORT reason.
*/
void UpdateClass::abort() {
errorArd(UPDATE_ERROR_ABORT);
}
void UpdateClass::bufAlloc() {
if (!buf)
buf = bufPos = (uint8_t *)malloc(UF2_BLOCK_SIZE);
}
uint16_t UpdateClass::bufLeft() {
return buf + UF2_BLOCK_SIZE - bufPos;
}
uint16_t UpdateClass::bufSize() {
return bufPos - buf;
}
/**
* @brief Print string error info to the stream.
*/
void UpdateClass::printError(Print &out) {
out.println(errorString());
}
/**
* @brief Get string representation of the error in format
* "ard=..,uf2=..". Returns "" if no error.
*/
const char *UpdateClass::errorString() {
if (!errArd)
return "";
sprintf(errorStr, "ard=%u,uf2=%u", errArd, errUf2);
return errorStr;
}
/**
* @brief Get firmware name from UF2 info.
*/
const char *UpdateClass::getFirmwareName() {
if (info)
return info->fw_name;
return NULL;
}
/**
* @brief Get firmware version from UF2 info.
*/
const char *UpdateClass::getFirmwareVersion() {
if (info)
return info->fw_version;
return NULL;
}
/**
* @brief Get LibreTuya version from UF2 info.
*/
const char *UpdateClass::getLibreTuyaVersion() {
if (info)
return info->lt_version;
return NULL;
}
/**
* @brief Get target board name from UF2 info.
*/
const char *UpdateClass::getBoardName() {
if (info)
return info->board;
return NULL;
}
/**
* @brief See LT.otaCanRollback() for more info.
*/
bool UpdateClass::canRollBack() {
return LT.otaCanRollback();
}
/**
* @brief See LT.otaRollback() for more info.
*/
bool UpdateClass::rollBack() {
return LT.otaRollback();
}

View File

@@ -0,0 +1,32 @@
/* Copyright (c) Kuba Szczodrzyński 2022-05-29. */
#include "uf2priv.h"
uf2_err_t uf2_binpatch(uint8_t *data, const uint8_t *binpatch, uint8_t binpatch_len) {
const uint8_t *binpatch_end = binpatch + binpatch_len;
// +2 to make sure opcode and length is present
while ((binpatch + 2) < binpatch_end) {
uf2_opcode_t opcode = binpatch[0];
uint8_t len = binpatch[1];
switch (opcode) {
case UF2_OPC_DIFF32:
uf2_binpatch_diff32(data, binpatch + 1);
break;
}
// advance by opcode + length + data
binpatch += len + 2;
}
return UF2_ERR_OK;
}
void uf2_binpatch_diff32(uint8_t *data, const uint8_t *patch) {
uint8_t num_offs = patch[0] - 4; // read offset count
uint32_t diff = *((uint32_t *)(patch + 1)); // read diff value
patch += 5; // skip num_offs and diff value
for (uint8_t i = 0; i < num_offs; i++) {
// patch the data
uint8_t offs = patch[i];
uint32_t *value = (uint32_t *)(data + offs);
*(value) += diff;
}
}

View File

@@ -0,0 +1,26 @@
/* Copyright (c) Kuba Szczodrzyński 2022-05-29. */
#pragma once
#include "uf2types.h"
/**
* @brief Apply binary patch to data.
*
* @param data input data
* @param data_len input data length
* @param binpatch binary patch data
* @param binpatch_len binary patch data length
* @return uf2_err_t error code
*/
uf2_err_t uf2_binpatch(uint8_t *data, const uint8_t *binpatch, uint8_t binpatch_len);
/**
* Apply DIFF32 binary patch.
*
* @param data input data
* @param len input data length
* @param patch patch data, incl. length byte
* @return uf2_err_t error code
*/
void uf2_binpatch_diff32(uint8_t *data, const uint8_t *patch);

View File

@@ -0,0 +1,100 @@
/* Copyright (c) Kuba Szczodrzyński 2022-05-29. */
#include "uf2priv.h"
uf2_ota_t *uf2_ctx_init(uint8_t ota_idx, uint32_t family_id) {
uf2_ota_t *ctx = (uf2_ota_t *)zalloc(sizeof(uf2_ota_t));
ctx->ota_idx = ota_idx;
ctx->family_id = family_id;
return ctx;
}
uf2_info_t *uf2_info_init() {
uf2_info_t *info = (uf2_info_t *)zalloc(sizeof(uf2_info_t));
return info;
}
void uf2_info_free(uf2_info_t *info) {
if (!info)
return;
free(info->fw_name);
free(info->fw_version);
free(info->lt_version);
free(info->board);
free(info);
}
uf2_err_t uf2_check_block(uf2_ota_t *ctx, uf2_block_t *block) {
if (block->magic1 != UF2_MAGIC_1)
return UF2_ERR_MAGIC;
if (block->magic2 != UF2_MAGIC_2)
return UF2_ERR_MAGIC;
if (block->magic3 != UF2_MAGIC_3)
return UF2_ERR_MAGIC;
if (block->file_container)
// ignore file containers, for now
return UF2_ERR_IGNORE;
if (!block->has_family_id || block->file_size != ctx->family_id)
// require family_id
return UF2_ERR_FAMILY;
return UF2_ERR_OK;
}
uf2_err_t uf2_parse_header(uf2_ota_t *ctx, uf2_block_t *block, uf2_info_t *info) {
if (!block->has_tags || block->file_container || block->len)
// header must have tags and no data
return UF2_ERR_NOT_HEADER;
uf2_err_t err = uf2_parse_block(ctx, block, info);
if (err)
return err;
if ((ctx->ota_idx == 1 && !ctx->has_ota1) || !ctx->has_ota2)
return UF2_ERR_OTA_WRONG;
return UF2_ERR_OK;
}
uf2_err_t uf2_write(uf2_ota_t *ctx, uf2_block_t *block) {
if (ctx->seq == 0)
return uf2_parse_header(ctx, block, NULL);
if (block->not_main_flash || !block->len)
// ignore blocks not meant for flashing
return UF2_ERR_IGNORE;
uf2_err_t err = uf2_parse_block(ctx, block, NULL);
if (err)
return err;
if (!ctx->part1 && !ctx->part2)
// no partitions set at all
return UF2_ERR_PART_UNSET;
fal_partition_t part = uf2_get_target_part(ctx);
if (!part)
// image is not for current OTA scheme
return UF2_ERR_IGNORE;
if (ctx->ota_idx == 2 && ctx->binpatch_len) {
// apply binpatch
err = uf2_binpatch(block->data, ctx->binpatch, ctx->binpatch_len);
if (err)
return err;
}
int ret;
// erase sectors if needed
if (!uf2_is_erased(ctx, block->addr, block->len)) {
ret = fal_partition_erase(part, block->addr, block->len);
if (ret < 0)
return UF2_ERR_ERASE_FAILED;
ctx->erased_offset = block->addr;
ctx->erased_length = ret;
}
// write data to flash
ret = fal_partition_write(part, block->addr, block->data, block->len);
if (ret < 0)
return UF2_ERR_WRITE_FAILED;
if (ret != block->len)
return UF2_ERR_WRITE_LENGTH;
return UF2_ERR_OK;
}

View File

@@ -0,0 +1,68 @@
/* Copyright (c) Kuba Szczodrzyński 2022-05-28. */
#pragma once
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#include "uf2types.h"
/**
* @brief Create an UF2 OTA context.
*
* @param ota_idx target OTA index
* @param family_id expected family ID
* @return uf2_ota_t* heap-allocated structure
*/
uf2_ota_t *uf2_ctx_init(uint8_t ota_idx, uint32_t family_id);
/**
* @brief Create an UF2 Info structure.
*
* @return uf2_info_t* heap-allocated structure
*/
uf2_info_t *uf2_info_init();
/**
* @brief Free values in the info structure AND the structure itself.
*
* @param info structure to free; may be NULL
*/
void uf2_info_free(uf2_info_t *info);
/**
* @brief Check if block is valid.
*
* @param ctx context
* @param block block to check
* @return uf2_err_t error code; UF2_ERR_OK and UF2_ERR_IGNORE denote valid blocks
*/
uf2_err_t uf2_check_block(uf2_ota_t *ctx, uf2_block_t *block);
/**
* @brief Parse header block (LibreTuya UF2 first block).
*
* Note: caller should call uf2_check_block() first.
*
* @param ctx context
* @param block block to parse
* @param info structure to write firmware info, NULL if not used
* @return uf2_err_t error code
*/
uf2_err_t uf2_parse_header(uf2_ota_t *ctx, uf2_block_t *block, uf2_info_t *info);
/**
* @brief Write the block to flash memory.
*
* Note: caller should call uf2_check_block() first.
*
* @param ctx context
* @param block block to write
* @return uf2_err_t error code
*/
uf2_err_t uf2_write(uf2_ota_t *ctx, uf2_block_t *block);
#ifdef __cplusplus
} // extern "C"
#endif

View File

@@ -0,0 +1,146 @@
/* Copyright (c) Kuba Szczodrzyński 2022-05-29. */
#include "uf2priv.h"
uf2_err_t uf2_parse_block(uf2_ota_t *ctx, uf2_block_t *block, uf2_info_t *info) {
if (block->block_seq != ctx->seq)
// sequence number must match
return UF2_ERR_SEQ_MISMATCH;
ctx->seq++; // increment sequence number after checking it
if (!block->has_tags)
// no tags in this block, no further processing needed
return UF2_ERR_OK;
if (block->len > (476 - 4 - 4))
// at least one tag + last tag must fit
return UF2_ERR_DATA_TOO_LONG;
uint8_t *tags_start = block->data + block->len;
uint8_t tags_len = 476 - block->len;
uint8_t tags_pos = 0;
if (block->has_md5)
tags_len -= 24;
ctx->binpatch_len = 0; // binpatch applies to one block only
char *part1 = NULL;
char *part2 = NULL;
uf2_tag_type_t type;
while (tags_pos < tags_len) {
uint8_t len = uf2_read_tag(tags_start + tags_pos, &type);
if (!len)
break;
tags_pos += 4; // skip tag header
uint8_t *tag = tags_start + tags_pos;
char **str_dest = NULL; // char* to copy the tag into
switch (type) {
case UF2_TAG_OTA_VERSION:
if (tag[0] != 1)
return UF2_ERR_OTA_VER;
break;
case UF2_TAG_FIRMWARE:
if (info)
str_dest = &(info->fw_name);
break;
case UF2_TAG_VERSION:
if (info)
str_dest = &(info->fw_version);
break;
case UF2_TAG_LT_VERSION:
if (info)
str_dest = &(info->lt_version);
break;
case UF2_TAG_BOARD:
if (info)
str_dest = &(info->board);
break;
case UF2_TAG_HAS_OTA1:
ctx->has_ota1 = tag[0];
break;
case UF2_TAG_HAS_OTA2:
ctx->has_ota2 = tag[0];
break;
case UF2_TAG_PART_1:
str_dest = &(part1);
break;
case UF2_TAG_PART_2:
str_dest = &(part2);
break;
case UF2_TAG_BINPATCH:
ctx->binpatch = tag;
ctx->binpatch_len = len;
break;
default:
break;
}
if (str_dest) {
*str_dest = (char *)zalloc(len + 1);
memcpy(*str_dest, tag, len);
}
// align position to 4 bytes
tags_pos += (((len - 1) / 4) + 1) * 4;
}
if (part1 && part2) {
// update current target partition
uf2_err_t err = uf2_update_parts(ctx, part1, part2);
if (err)
return err;
} else if (part1 || part2) {
// only none or both partitions can be specified
return UF2_ERR_PART_ONE;
}
return UF2_ERR_OK;
}
uint8_t uf2_read_tag(const uint8_t *data, uf2_tag_type_t *type) {
uint8_t len = data[0];
if (!len)
return 0;
uint32_t tag_type = *((uint32_t *)data);
if (!tag_type)
return 0;
*type = tag_type >> 8; // remove tag length byte
return len - 4;
}
uf2_err_t uf2_update_parts(uf2_ota_t *ctx, char *part1, char *part2) {
// reset both target partitions
ctx->part1 = NULL;
ctx->part2 = NULL;
// reset offsets as they probably don't apply to this partition
ctx->erased_offset = 0;
ctx->erased_length = 0;
if (part1[0]) {
ctx->part1 = (fal_partition_t)fal_partition_find(part1);
if (!ctx->part1)
return UF2_ERR_PART_404;
}
if (part2[0]) {
ctx->part2 = (fal_partition_t)fal_partition_find(part2);
if (!ctx->part2)
return UF2_ERR_PART_404;
}
return UF2_ERR_OK;
}
fal_partition_t uf2_get_target_part(uf2_ota_t *ctx) {
if (ctx->ota_idx == 1)
return ctx->part1;
if (ctx->ota_idx == 2)
return ctx->part2;
return NULL;
}
bool uf2_is_erased(uf2_ota_t *ctx, uint32_t offset, uint32_t length) {
uint32_t erased_end = ctx->erased_offset + ctx->erased_length;
uint32_t end = offset + length;
return (offset >= ctx->erased_offset) && (end <= erased_end);
}

View File

@@ -0,0 +1,61 @@
/* Copyright (c) Kuba Szczodrzyński 2022-05-28. */
#pragma once
// include family stdlib APIs
#include <WVariant.h>
#include "uf2binpatch.h"
#include "uf2types.h"
/**
* @brief Parse a block and extract information from tags.
*
* @param ctx context
* @param block block to parse
* @param info structure to write firmware info, NULL if not used
* @return uf2_err_t error code
*/
uf2_err_t uf2_parse_block(uf2_ota_t *ctx, uf2_block_t *block, uf2_info_t *info);
/**
* @brief Parse a tag.
*
* @param data pointer to tag header beginning
* @param type [out] parsed tag type
* @return uint8_t parsed tag data length (excl. header); 0 if invalid/last tag
*/
uint8_t uf2_read_tag(const uint8_t *data, uf2_tag_type_t *type);
/**
* @brief Update destination partitions in context.
*
* Partition names cannot be NULL.
*
* Returns UF2_ERR_IGNORE if specified partitions don't match the
* current OTA index.
*
* @param ctx context
* @param part1 partition 1 name or empty string
* @param part2 partition 2 name or empty string
* @return uf2_err_t error code
*/
uf2_err_t uf2_update_parts(uf2_ota_t *ctx, char *part1, char *part2);
/**
* @brief Get target flashing partition, depending on OTA index.
*
* @param ctx context
* @return fal_partition_t target partition or NULL if not set
*/
fal_partition_t uf2_get_target_part(uf2_ota_t *ctx);
/**
* Check if specified flash memory region was already erased during update.
*
* @param ctx context
* @param offset offset to check
* @param length length to check
* @return bool true/false
*/
bool uf2_is_erased(uf2_ota_t *ctx, uint32_t offset, uint32_t length);

View File

@@ -0,0 +1,104 @@
/* Copyright (c) Kuba Szczodrzyński 2022-05-28. */
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include <fal.h>
#define UF2_MAGIC_1 0x0A324655
#define UF2_MAGIC_2 0x9E5D5157
#define UF2_MAGIC_3 0x0AB16F30
#define UF2_BLOCK_SIZE sizeof(uf2_block_t)
typedef struct __attribute__((packed)) {
// 32 byte header
uint32_t magic1;
uint32_t magic2;
// flags split as bitfields
bool not_main_flash : 1;
uint16_t dummy1 : 11;
bool file_container : 1;
bool has_family_id : 1;
bool has_md5 : 1;
bool has_tags : 1;
uint16_t dummy2 : 16;
uint32_t addr;
uint32_t len;
uint32_t block_seq;
uint32_t block_count;
uint32_t file_size; // or familyID;
uint8_t data[476];
uint32_t magic3;
} uf2_block_t;
typedef struct {
uint32_t seq; // current block sequence number
uint8_t *binpatch; // current block's binpatch (if any) -> pointer inside block->data
uint8_t binpatch_len; // binpatch length
bool has_ota1; // image has any data for OTA1
bool has_ota2; // image has any data for OTA2
uint8_t ota_idx; // target OTA index
uint32_t family_id; // expected family ID
uint32_t erased_offset; // offset of region erased during update
uint32_t erased_length; // length of erased region
fal_partition_t part1; // OTA1 target partition
fal_partition_t part2; // OTA2 target partition
} uf2_ota_t;
typedef struct {
char *fw_name;
char *fw_version;
char *lt_version;
char *board;
} uf2_info_t;
typedef enum {
UF2_TAG_VERSION = 0x9FC7BC, // version of firmware file - UTF8 semver string
UF2_TAG_PAGE_SIZE = 0x0BE9F7, // page size of target device (32 bit unsigned number)
UF2_TAG_SHA2 = 0xB46DB0, // SHA-2 checksum of firmware (can be of various size)
UF2_TAG_DEVICE = 0x650D9D, // description of device (UTF8)
UF2_TAG_DEVICE_ID = 0xC8A729, // device type identifier
// LibreTuya custom, tags
UF2_TAG_OTA_VERSION = 0x5D57D0, // format version
UF2_TAG_BOARD = 0xCA25C8, // board name (lowercase code)
UF2_TAG_FIRMWARE = 0x00DE43, // firmware description / name
UF2_TAG_BUILD_DATE = 0x822F30, // build date/time as Unix timestamp
UF2_TAG_LT_VERSION = 0x59563D, // LT version (semver)
UF2_TAG_PART_1 = 0x805946, // OTA1 partition name
UF2_TAG_PART_2 = 0xA1E4D7, // OTA2 partition name
UF2_TAG_HAS_OTA1 = 0xBBD965, // image has any data for OTA1
UF2_TAG_HAS_OTA2 = 0x92280E, // image has any data for OTA2
UF2_TAG_BINPATCH = 0xB948DE, // binary patch to convert OTA1->OTA2
} uf2_tag_type_t;
typedef enum {
UF2_OPC_DIFF32 = 0xFE,
} uf2_opcode_t;
typedef enum {
UF2_ERR_OK = 0,
UF2_ERR_IGNORE, // block should be ignored
UF2_ERR_MAGIC, // wrong magic numbers
UF2_ERR_FAMILY, // family ID mismatched
UF2_ERR_NOT_HEADER, // block is not a header
UF2_ERR_OTA_VER, // unknown/invalid OTA format version
UF2_ERR_OTA_WRONG, // no data for current OTA index
UF2_ERR_PART_404, // no partition with that name
UF2_ERR_PART_ONE, // only one partition tag in a block
UF2_ERR_PART_UNSET, // image broken - attempted to write without target partition
UF2_ERR_DATA_TOO_LONG, // data too long - tags won't fit
UF2_ERR_SEQ_MISMATCH, // sequence number mismatched
UF2_ERR_ERASE_FAILED, // erasing flash failed
UF2_ERR_WRITE_FAILED, // writing to flash failed
UF2_ERR_WRITE_LENGTH, // wrote fewer data than requested
} uf2_err_t;

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