156 Commits

Author SHA1 Message Date
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
Kuba Szczodrzyński
ed76b23c69 [release] v0.3.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-06 20:28:10 +02:00
Kuba Szczodrzyński
a469a466ff [github] Update README.md badges 2022-05-06 20:27:43 +02:00
Kuba Szczodrzyński
589d3ef4d8 [core] Refactor realtek-ambz, cleanup, reformat, add missing copyrights 2022-05-06 20:27:06 +02:00
Kuba Szczodrzyński
5aba2eb4a1 [core] Reformat filter_rtl_hard_fault.py with updated black 2022-05-06 15:47:46 +02:00
Kuba Szczodrzyński
b7df8d7b37 [github] Add lint check workflow 2022-05-06 15:42:54 +02:00
Kuba Szczodrzyński
61554e6c7e [realtek-ambz] Describe C library functions 2022-05-06 15:42:27 +02:00
Kuba Szczodrzyński
d8cc61bc0e [realtek-ambz] Remove old WiFi library 2022-05-06 12:14:48 +02:00
Kuba Szczodrzyński
4b6e3956d6 [realtek-ambz] Implement SSL client, cleanup compilation 2022-05-05 21:25:19 +02:00
Kuba Szczodrzyński
9659ff8afa [core] Add MbedTLSClient 2022-05-05 20:56:37 +02:00
Kuba Szczodrzyński
783955cc5d [core] Refactor build system, cleanup unused files 2022-05-04 21:45:30 +02:00
Kuba Szczodrzyński
048556803b [core] Move non-interface classes to libraries 2022-04-30 21:08:09 +02:00
384 changed files with 21632 additions and 18088 deletions

29
.clang-format Normal file
View File

@@ -0,0 +1,29 @@
Language: Cpp
BasedOnStyle: LLVM
AlignAfterOpenBracket: BlockIndent
AlignArrayOfStructures: Left
AlignConsecutiveAssignments: true
AlignConsecutiveMacros: AcrossComments
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: false
AllowShortBlocksOnASingleLine: Empty
AllowShortFunctionsOnASingleLine: Empty
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: false
BinPackParameters: false
BreakBeforeTernaryOperators: true
ColumnLimit: 120
ContinuationIndentWidth: 4
EmptyLineBeforeAccessModifier: Always
FixNamespaceComments: true
IndentAccessModifiers: false
IndentCaseLabels: true
IndentWidth: 4
LambdaBodyIndentation: Signature
MaxEmptyLinesToKeep: 1
# PointerAlignment: Left # TODO enable this and reformat project
QualifierAlignment: Left
ReflowComments: true
SeparateDefinitionBlocks: Always
TabWidth: 4
UseTab: Always

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

35
.github/workflows/lint.yml vendored Normal file
View File

@@ -0,0 +1,35 @@
name: Lint check
on: [push, pull_request]
jobs:
lint-clang-format:
name: Lint with clang-format
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Check code with clang-format
uses: jidicula/clang-format-action@v4.5.0
with:
clang-format-version: "14"
lint-black:
name: Lint with black
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: "3.9"
- name: Install test dependencies
uses: BSFishy/pip-action@v1
with:
packages: |
black
isort
- name: Check code with black
run: black --check .
- name: Check code with isort
run: isort --profile black . --check-only

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

200
README.md
View File

@@ -2,193 +2,73 @@
<div align="center" markdown>
[![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)](.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)
![GitHub last commit](https://img.shields.io/github/last-commit/kuba2k2/libretuya)
![RTL8710BN](https://img.shields.io/badge/-rtl8710bn-blue)
![BK7231](https://img.shields.io/badge/-bk7231-blue)
</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.
## Usage
1. [Install PlatformIO](https://platformio.org/platformio-ide)
2. `platformio platform install libretuya`
2. `platformio platform install https://github.com/kuba2k2/libretuya`
3. Create a project, build it and upload!
4. See the [docs](https://kuba2k2.github.io/libretuya/) for any questions/problems.
## 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 platform
│ ├─ cores/ Core files
│ ├─ libraries/ Supported built-in libraries
├─ libretuya/
│ ├─ api/ LibreTuya API for Arduino frameworks
│ ├─ 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
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) | ❌ | 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:

53
SUMMARY.md Normal file
View File

@@ -0,0 +1,53 @@
* [Home](README.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)
* [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
* [Realtek - notes](docs/platform/realtek/README.md)
* [Beken 72xx - notes](docs/platform/beken-72xx/README.md)
* Realtek AmebaZ Series
* C library
* [Built-in functions](docs/platform/realtek-ambz/stdlib.md)
* [Memory management](docs/platform/realtek-ambz/memory-management.md)
* [Debugging](docs/platform/realtek/debugging.md)
* [Exception decoder](docs/platform/realtek/exception-decoder.md)
* [All supported boards](boards/)
* [🔗 Resources](docs/resources.md)

View File

@@ -0,0 +1,32 @@
/* 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"
#ifdef __cplusplus
#include "SerialClass.h"
#ifdef HAS_SERIAL_CLASS
// declare instances of available Serial* components
// map Serial to Serial2 if available, else to Serial1
#ifdef PIN_SERIAL1_RX
extern SerialClass Serial1;
#endif
#ifdef PIN_SERIAL2_RX
extern SerialClass Serial2;
#define Serial Serial2
#else
#define Serial Serial1
#endif
#endif
#endif

View File

@@ -0,0 +1,130 @@
/* 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 <sys_ctrl.h>
#include <sys_rtos.h>
#include <wlan_ui_pub.h>
}
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() {
// TODO determine if this really is unique
uint32_t chipId = REG_READ(SCTRL_DEVICE_ID);
chipId &= 0xFFFFFF;
return chipId;
}
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,75 @@
/* 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);
}
#ifdef PIN_SERIAL1_RX
SerialClass Serial1(UART1_PORT);
#endif
#ifdef PIN_SERIAL2_RX
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,25 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-19. */
#include <Arduino.h>
extern "C" {
#include <rtos_pub.h>
#include <sys_rtos.h>
}
beken_thread_t mainThread;
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,113 @@
/* 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
};
static GPIO_INDEX adcToGpio[] = {
-1, // ADC0 - VBAT
GPIO4, // ADC1
GPIO5, // ADC2
GPIO23, // ADC3
GPIO2, // ADC4
GPIO3, // ADC5
GPIO12, // ADC6
GPIO13, // ADC7
};
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);
pwm.duty_cycle = dutyCycle;
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,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;
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_NO_AP_FOUND:
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,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,23 @@
/* 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 {
char ssid[32 + 1];
char pass[64 + 1];
unsigned long scannedAt;
uint32_t ipSta[4];
uint32_t ipAp[4];
SemaphoreHandle_t scanSem;
void *statusIp;
void *statusLink;
} WiFiData;

View File

@@ -0,0 +1,71 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-26. */
#include "WiFiPriv.h"
bool WiFiClass::modePriv(WiFiMode mode, WiFiModeAction sta, WiFiModeAction ap) {
__wrap_bk_printf_disable();
if (mode && !data.statusIp) {
data.statusIp = (IPStatusTypedef *)malloc(sizeof(IPStatusTypedef));
data.statusLink = (LinkStatusTypeDef *)malloc(sizeof(LinkStatusTypeDef));
}
if (!__bk_rf_is_init) {
LT_D_WG("Initializing func&app");
func_init_extended();
app_pre_start();
__bk_rf_is_init = true;
}
LT_HEAP_I();
if (sta == WLMODE_ENABLE) {
LT_D_WG("Enabling STA");
bk_wlan_sta_init(NULL);
} else if (sta == WLMODE_DISABLE) {
LT_D_WG("Disabling STA");
bk_wlan_stop(BK_STATION);
}
LT_HEAP_I();
if (ap == WLMODE_ENABLE) {
LT_D_WG("Enabling AP");
bk_wlan_ap_init(NULL);
} else if (ap == WLMODE_DISABLE) {
LT_D_WG("Disabling AP");
bk_wlan_stop(BK_SOFT_AP);
}
if (!mode) {
free(data.statusIp);
free(data.statusLink);
data.statusIp = NULL;
data.statusLink = NULL;
}
LT_HEAP_I();
__wrap_bk_printf_enable();
}
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() {
return eventTypeToStatus(mhdr_get_station_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>
#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;
// func/lwip_intf/lwip-2.0.2/port/net.c
extern struct netif *net_get_sta_handle(void);
extern struct netif *net_get_uap_handle(void);
// 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);
#define ADDR_STA_IP data.ipSta[0]
#define ADDR_STA_MASK data.ipSta[1]
#define ADDR_STA_GW data.ipSta[2]
#define ADDR_STA_DNS data.ipSta[3]
#define ADDR_AP_IP data.ipAp[0]
#define ADDR_AP_MASK data.ipAp[1]
#define ADDR_AP_GW data.ipAp[2]
#define ADDR_AP_DNS data.ipAp[3]
#define IP_STATUS ((IPStatusTypedef *)data.statusIp)
#define LINK_STATUS ((LinkStatusTypeDef *)data.statusLink)
} // extern "C"

View File

@@ -0,0 +1,219 @@
/* 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) {
enableSTA(true);
if (!ssid || *ssid == 0x00 || strlen(ssid) > 32) {
LT_W("SSID not specified or too long");
return WL_CONNECT_FAILED;
}
if (passphrase && strlen(passphrase) > 64) {
LT_W("Passphrase too long");
return WL_CONNECT_FAILED;
}
// store the network data for later
strcpy(data.ssid, ssid);
if (passphrase)
strcpy(data.pass, passphrase);
else
data.pass[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) {
ADDR_STA_IP = (uint32_t)localIP;
ADDR_STA_GW = (uint32_t)gateway;
ADDR_STA_MASK = (uint32_t)subnet;
ADDR_STA_DNS = (uint32_t)dns1;
if (status() == WL_CONNECTED) {
IPStatusTypedef config;
config.dhcp = !localIP[0];
if (localIP) {
sprintf(config.ip, "%u.%u.%u.%u", ADDR_STA_IP);
sprintf(config.mask, "%u.%u.%u.%u", ADDR_STA_MASK);
sprintf(config.gate, "%u.%u.%u.%u", ADDR_STA_GW);
}
if (dns1)
sprintf(config.dns, "%u.%u.%u.%u", ADDR_STA_DNS);
bk_wlan_set_ip_status(&config, BK_STATION);
}
return true;
}
bool WiFiClass::reconnect(const uint8_t *bssid) {
if (!bssid && !data.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", data.ssid);
}
network_InitTypeDef_st config;
memset(&config, 0, sizeof(network_InitTypeDef_st));
// network_InitTypeDef_adv_st config;
// memset(&config, 0, sizeof(network_InitTypeDef_adv_st));
config.wifi_mode = BK_STATION;
config.wifi_retry_interval = 100;
// config.ap_info.security = BK_SECURITY_TYPE_WPA2_MIXED;
// config.ap_info.channel = 6;
strcpy(config.wifi_ssid, data.ssid);
// strcpy(config.ap_info.ssid, data.ssid);
strcpy(config.wifi_key, data.pass);
// strcpy(config.key, data.pass);
// config.key_len = strlen(data.pass);
if (bssid)
memcpy(config.wifi_bssid, bssid, 6);
// memcpy(config.ap_info.bssid, bssid, 6);
if (ADDR_STA_IP && ADDR_STA_MASK && ADDR_STA_GW) {
config.dhcp_mode = DHCP_DISABLE;
sprintf(config.local_ip_addr, "%u.%u.%u.%u", ADDR_STA_IP);
sprintf(config.net_mask, "%u.%u.%u.%u", ADDR_STA_MASK);
sprintf(config.gateway_ip_addr, "%u.%u.%u.%u", ADDR_STA_GW);
LT_D_WG("Static IP: %s / %s / %s", config.local_ip_addr, config.net_mask, config.gateway_ip_addr);
} else {
config.dhcp_mode = DHCP_CLIENT;
LT_D_WG("Using DHCP");
}
if (ADDR_STA_DNS) {
sprintf(config.dns_server_ip_addr, "%u.%u.%u.%u", ADDR_STA_DNS);
LT_D_WG("Static DNS: %s", config.dns_server_ip_addr);
}
if (!data.scannedAt || millis() - data.scannedAt > 10000) {
LT_D_WG("Scan needed");
// apparently a scan must be performed first,
// else it hangs at "[sa_sta]MM_START_REQ"
scanNetworks(false);
}
LT_D_WG("Starting WiFi...");
__wrap_bk_printf_disable();
bk_wlan_start_sta(&config);
__wrap_bk_printf_enable();
LT_D_WG("bk_wlan_start() OK");
return true;
error:
return false;
}
bool WiFiClass::disconnect(bool wifiOff) {
bk_wlan_connection_loss();
return true;
}
bool WiFiClass::setAutoReconnect(bool autoReconnect) {
return false;
}
bool WiFiClass::getAutoReconnect() {
return false;
}
IPAddress WiFiClass::localIP() {
IPStatusTypedef config;
bk_wlan_get_ip_status(&config, BK_STATION);
IPAddress ip;
ip.fromString(config.ip);
return ip;
}
IPAddress WiFiClass::subnetMask() {
IPStatusTypedef config;
bk_wlan_get_ip_status(&config, BK_STATION);
IPAddress ip;
ip.fromString(config.mask);
return ip;
}
IPAddress WiFiClass::gatewayIP() {
IPStatusTypedef config;
bk_wlan_get_ip_status(&config, BK_STATION);
IPAddress ip;
ip.fromString(config.gate);
return ip;
}
IPAddress WiFiClass::dnsIP(uint8_t dns_no) {
IPStatusTypedef config;
bk_wlan_get_ip_status(&config, BK_STATION);
IPAddress ip;
ip.fromString(config.dns);
return ip;
}
IPAddress WiFiClass::broadcastIP() {
return calculateBroadcast(localIP(), subnetMask());
}
const char *WiFiClass::getHostname() {
struct netif *ifs = net_get_sta_handle();
return netif_get_hostname(ifs);
}
bool WiFiClass::setHostname(const char *hostname) {
struct netif *ifs = 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) {
wifi_set_mac_address((char *)mac);
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,73 @@
/* 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();
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();
__wrap_bk_printf_enable();
LT_HEAP_I();
scan->running = true;
if (!async) {
LT_I("Waiting for results");
xSemaphoreTake(data.scanSem, 1); // reset the semaphore quickly
xSemaphoreTake(data.scanSem, pdMS_TO_TICKS(maxMsPerChannel * 20));
return scan->count;
}
return WIFI_SCAN_RUNNING;
}

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,17 @@
/* 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);
}
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,25 +0,0 @@
#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,91 +0,0 @@
/*
IPv6Address.cpp - Base class that provides IPv6Address
Copyright (c) 2011 Adrian McEwen. All right 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
*/
#include <Arduino.h>
#include <api/Print.h>
#include "IPv6Address.h"
IPv6Address::IPv6Address()
{
memset(_address.bytes, 0, sizeof(_address.bytes));
}
IPv6Address::IPv6Address(const uint8_t *address)
{
memcpy(_address.bytes, address, sizeof(_address.bytes));
}
IPv6Address::IPv6Address(const uint32_t *address)
{
memcpy(_address.bytes, (const uint8_t *)address, sizeof(_address.bytes));
}
IPv6Address& IPv6Address::operator=(const uint8_t *address)
{
memcpy(_address.bytes, address, sizeof(_address.bytes));
return *this;
}
bool IPv6Address::operator==(const uint8_t* addr) const
{
return memcmp(addr, _address.bytes, sizeof(_address.bytes)) == 0;
}
size_t IPv6Address::printTo(Print& p) const
{
/* size_t n = 0;
for(int i = 0; i < 16; i+=2) {
if(i){
n += p.print(':');
}
n += p.printf("%02x", _address.bytes[i]);
n += p.printf("%02x", _address.bytes[i+1]);
}
return n; */
}
String IPv6Address::toString() const
{
char szRet[40];
sprintf(szRet,"%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
_address.bytes[0], _address.bytes[1], _address.bytes[2], _address.bytes[3],
_address.bytes[4], _address.bytes[5], _address.bytes[6], _address.bytes[7],
_address.bytes[8], _address.bytes[9], _address.bytes[10], _address.bytes[11],
_address.bytes[12], _address.bytes[13], _address.bytes[14], _address.bytes[15]);
return String(szRet);
}
bool IPv6Address::fromString(const char *address)
{
//format 0011:2233:4455:6677:8899:aabb:ccdd:eeff
if(strlen(address) != 39){
return false;
}
char * pos = (char *)address;
size_t i = 0;
for(i = 0; i < 16; i+=2) {
if(!sscanf(pos, "%2hhx", &_address.bytes[i]) || !sscanf(pos+2, "%2hhx", &_address.bytes[i+1])){
return false;
}
pos += 5;
}
return true;
}

View File

@@ -1,98 +0,0 @@
/*
IPv6Address.h - Base class that provides IPv6Address
Copyright (c) 2011 Adrian McEwen. All right 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
*/
#pragma once
#include <stdint.h>
#include <api/String.h>
#include <api/Print.h>
// A class to make it easier to handle and pass around IP addresses
namespace arduino {
class IPv6Address: public Printable
{
private:
union {
uint8_t bytes[16]; // IPv4 address
uint32_t dword[4];
} _address;
// Access the raw byte array containing the address. Because this returns a pointer
// to the internal structure rather than a copy of the address this function should only
// be used when you know that the usage of the returned uint8_t* will be transient and not
// stored.
uint8_t* raw_address()
{
return _address.bytes;
}
public:
// Constructors
IPv6Address();
IPv6Address(const uint8_t *address);
IPv6Address(const uint32_t *address);
virtual ~IPv6Address() {}
bool fromString(const char *address);
bool fromString(const String &address) { return fromString(address.c_str()); }
operator const uint8_t*() const
{
return _address.bytes;
}
operator const uint32_t*() const
{
return _address.dword;
}
bool operator==(const IPv6Address& addr) const
{
return (_address.dword[0] == addr._address.dword[0])
&& (_address.dword[1] == addr._address.dword[1])
&& (_address.dword[2] == addr._address.dword[2])
&& (_address.dword[3] == addr._address.dword[3]);
}
bool operator==(const uint8_t* addr) const;
// Overloaded index operator to allow getting and setting individual octets of the address
uint8_t operator[](int index) const
{
return _address.bytes[index];
}
uint8_t& operator[](int index)
{
return _address.bytes[index];
}
// Overloaded copy operators to allow initialisation of IPv6Address objects from other types
IPv6Address& operator=(const uint8_t *address);
// TODO implement printTo()
virtual size_t printTo(Print& p) const;
String toString() const;
friend class UDP;
friend class Client;
friend class Server;
};
}
using arduino::IPv6Address;

View File

@@ -1,9 +0,0 @@
#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);
}

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

@@ -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,46 @@
/* 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("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());
}
}
WiFiClass WiFi;
WiFiClass *pWiFi = NULL;

View File

@@ -0,0 +1,194 @@
/*
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);
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,93 @@
/* 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;
}
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

@@ -22,42 +22,28 @@
#include <Arduino.h>
#include "WiFi.h"
#include "WiFiClient.h"
class IWiFiClientSecure : public IWiFiClient {
class IWiFiClientSecure {
public:
int connect(IPAddress ip, uint16_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key);
int connect(const char *host, uint16_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key);
int connect(IPAddress ip, uint16_t port, const char *pskIdent, const char *psKey);
int connect(const char *host, uint16_t port, const char *pskIdent, const char *psKey);
virtual int
connect(IPAddress ip, uint16_t port, const char *rootCABuf, const char *clientCert, const char *clientKey) = 0;
virtual int
connect(const char *host, uint16_t port, const char *rootCABuf, const char *clientCert, const char *clientKey) = 0;
virtual int connect(IPAddress ip, uint16_t port, const char *pskIdent, const char *psk) = 0;
virtual int connect(const char *host, uint16_t port, const char *pskIdent, const char *psk) = 0;
int lastError(char *buf, const size_t size);
void setInsecure(); // Don't validate the chain, just accept whatever is given. VERY INSECURE!
void setPreSharedKey(const char *pskIdent, const char *psKey); // psKey in Hex
void setCACert(const char *rootCA);
void setCertificate(const char *client_ca);
void setPrivateKey(const char *private_key);
bool loadCACert(Stream &stream, size_t size);
bool loadCertificate(Stream &stream, size_t size);
bool loadPrivateKey(Stream &stream, size_t size);
bool verify(const char *fingerprint, const char *domain_name);
void setHandshakeTimeout(unsigned long handshake_timeout);
WiFiClientSecure &operator=(const WiFiClientSecure &other);
bool operator==(const bool value) {
return bool() == value;
}
bool operator!=(const bool value) {
return bool() != value;
}
bool operator==(const WiFiClientSecure &);
bool operator!=(const WiFiClientSecure &rhs) {
return !this->operator==(rhs);
};
using Print::write;
virtual int lastError(char *buf, const size_t size) = 0;
virtual void setInsecure() = 0; // Don't validate the chain, just accept whatever is given. VERY INSECURE!
virtual void setPreSharedKey(const char *pskIdent, const char *psk) = 0; // psk in hex
virtual void setCACert(const char *rootCA) = 0;
virtual void setCertificate(const char *clientCA) = 0;
virtual void setPrivateKey(const char *privateKey) = 0;
virtual bool loadCACert(Stream &stream, size_t size) = 0;
virtual bool loadCertificate(Stream &stream, size_t size) = 0;
virtual bool loadPrivateKey(Stream &stream, size_t size) = 0;
virtual bool verify(const char *fingerprint, const char *domainName) = 0;
virtual void setHandshakeTimeout(unsigned long handshakeTimeout) = 0;
virtual void setAlpnProtocols(const char **alpnProtocols) = 0;
virtual bool getFingerprintSHA256(uint8_t result[32]) = 0;
};

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

@@ -1,114 +0,0 @@
#pragma once
#include "LibreTuyaConfig.h"
#include <stdint.h>
#if LT_LOGGER_FILE
#define LT_LOG(level, file, line, ...) lt_log(level, file, line, __VA_ARGS__)
void lt_log(const uint8_t level, const char *filename, const unsigned short line, const char *format, ...);
#else
#define LT_LOG(level, file, line, ...) lt_log(level, __VA_ARGS__)
void lt_log(const uint8_t level, const char *format, ...);
#endif
#if LT_LEVEL_TRACE >= LT_LOGLEVEL
#define LT_T(...) LT_LOG(LT_LEVEL_TRACE, __FILE__, __LINE__, __VA_ARGS__)
#define LT_V(...) LT_LOG(LT_LEVEL_TRACE, __FILE__, __LINE__, __VA_ARGS__)
#else
#define LT_T(...)
#define LT_V(...)
#endif
#if LT_LEVEL_DEBUG >= LT_LOGLEVEL
#define LT_D(...) LT_LOG(LT_LEVEL_DEBUG, __FILE__, __LINE__, __VA_ARGS__)
#else
#define LT_D(...)
#endif
#if LT_LEVEL_INFO >= LT_LOGLEVEL
#define LT_I(...) LT_LOG(LT_LEVEL_INFO, __FILE__, __LINE__, __VA_ARGS__)
#else
#define LT_I(...)
#endif
#if LT_LEVEL_WARN >= LT_LOGLEVEL
#define LT_W(...) LT_LOG(LT_LEVEL_WARN, __FILE__, __LINE__, __VA_ARGS__)
#else
#define LT_W(...)
#endif
#if LT_LEVEL_ERROR >= LT_LOGLEVEL
#define LT_E(...) LT_LOG(LT_LEVEL_ERROR, __FILE__, __LINE__, __VA_ARGS__)
#else
#define LT_E(...)
#endif
#if LT_LEVEL_FATAL >= LT_LOGLEVEL
#define LT_F(...) LT_LOG(LT_LEVEL_FATAL, __FILE__, __LINE__, __VA_ARGS__)
#else
#define LT_F(...)
#endif
// ESP32 compat
#define log_printf(...) LT_I(__VA_ARGS__)
#define log_v(...) LT_V(__VA_ARGS__)
#define log_d(...) LT_D(__VA_ARGS__)
#define log_i(...) LT_I(__VA_ARGS__)
#define log_w(...) LT_W(__VA_ARGS__)
#define log_e(...) LT_E(__VA_ARGS__)
#define log_n(...) LT_E(__VA_ARGS__)
#define isr_log_v(...) LT_V(__VA_ARGS__)
#define isr_log_d(...) LT_D(__VA_ARGS__)
#define isr_log_i(...) LT_I(__VA_ARGS__)
#define isr_log_w(...) LT_W(__VA_ARGS__)
#define isr_log_e(...) LT_E(__VA_ARGS__)
#define isr_log_n(...) LT_E(__VA_ARGS__)
#define ESP_LOGV(...) LT_V(__VA_ARGS__)
#define ESP_LOGD(...) LT_D(__VA_ARGS__)
#define ESP_LOGI(...) LT_I(__VA_ARGS__)
#define ESP_LOGW(...) LT_W(__VA_ARGS__)
#define ESP_LOGE(...) LT_E(__VA_ARGS__)
#define ESP_EARLY_LOGV(...) LT_V(__VA_ARGS__)
#define ESP_EARLY_LOGD(...) LT_D(__VA_ARGS__)
#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 LT_T_MOD(module, ...) \
do { \
if (module) { \
LT_T(__VA_ARGS__); \
} \
} while (0)
#define LT_D_MOD(module, ...) \
do { \
if (module) { \
LT_D(__VA_ARGS__); \
} \
} while (0)
// 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__)
#define LT_D_WG(...) LT_D_MOD(LT_DEBUG_WIFI, __VA_ARGS__)
// WiFiClient.cpp
#define LT_T_WC(...) LT_T_MOD(LT_DEBUG_WIFI_CLIENT, __VA_ARGS__)
#define LT_V_WC(...) LT_T_MOD(LT_DEBUG_WIFI_CLIENT, __VA_ARGS__)
#define LT_D_WC(...) LT_D_MOD(LT_DEBUG_WIFI_CLIENT, __VA_ARGS__)
// WiFiServer.cpp
#define LT_T_WS(...) LT_T_MOD(LT_DEBUG_WIFI_SERVER, __VA_ARGS__)
#define LT_V_WS(...) LT_T_MOD(LT_DEBUG_WIFI_SERVER, __VA_ARGS__)
#define LT_D_WS(...) LT_D_MOD(LT_DEBUG_WIFI_SERVER, __VA_ARGS__)
// WiFiSTA.cpp
#define LT_T_WSTA(...) LT_T_MOD(LT_DEBUG_WIFI_STA, __VA_ARGS__)
#define LT_V_WSTA(...) LT_T_MOD(LT_DEBUG_WIFI_STA, __VA_ARGS__)
#define LT_D_WSTA(...) LT_D_MOD(LT_DEBUG_WIFI_STA, __VA_ARGS__)
// WiFiAP.cpp
#define LT_T_WAP(...) LT_T_MOD(LT_DEBUG_WIFI_AP, __VA_ARGS__)
#define LT_V_WAP(...) LT_T_MOD(LT_DEBUG_WIFI_AP, __VA_ARGS__)
#define LT_D_WAP(...) LT_D_MOD(LT_DEBUG_WIFI_AP, __VA_ARGS__)

View File

@@ -0,0 +1,55 @@
/*
Copyright (c) 2014 Arduino. All right 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
*/
#include <Arduino.h>
void randomSeed(uint32_t dwSeed) {
if (dwSeed != 0) {
srand(dwSeed);
}
}
long random(long howbig) {
if (howbig == 0) {
return 0;
}
return rand() % howbig;
}
long random(long howsmall, long howbig) {
if (howsmall >= howbig) {
return howsmall;
}
long diff = howbig - howsmall;
return random(diff) + howsmall;
}
extern long map(long x, long in_min, long in_max, long out_min, long out_max) {
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
extern uint16_t makeWord(uint16_t w) {
return w;
}
extern uint16_t makeWord(uint8_t h, uint8_t l) {
return (h << 8) | l;
}

View File

@@ -1,5 +1,5 @@
/*
Copyright (c) 2012 Arduino. All right reserved.
Copyright (c) 2014 Arduino LLC. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@@ -16,19 +16,21 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef RESET_H
#define RESET_H
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
extern "C" void __cxa_pure_virtual(void) __attribute__((__noreturn__));
extern "C" void __cxa_deleted_virtual(void) __attribute__((__noreturn__));
void initiateReset(int ms);
void tickReset();
void cancelReset();
#ifdef __cplusplus
void __cxa_pure_virtual(void) {
// We might want to write some diagnostics to uart in this case
// std::terminate();
while (1)
;
}
#endif
#endif
void __cxa_deleted_virtual(void) {
// We might want to write some diagnostics to uart in this case
// std::terminate();
while (1)
;
}

View File

@@ -18,16 +18,11 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifdef ARDUINO_AMEBA
#include <Arduino.h>
#else
#include <stdio.h>
#endif
char *dtostrf (double val, signed char width, unsigned char prec, char *sout) {
char fmt[20];
sprintf(fmt, "%%%d.%df", width, prec);
sprintf(sout, fmt, val);
return sout;
char *dtostrf(double val, signed char width, unsigned char prec, char *sout) {
char fmt[20];
sprintf(fmt, "%%%d.%df", width, prec);
sprintf(sout, fmt, val);
return sout;
}

View File

@@ -1,5 +1,5 @@
/*
Copyright (c) 2012 Arduino. All right reserved.
Copyright (c) 2015 Arduino LLC. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@@ -29,12 +29,7 @@ static void __empty() {
// Empty
}
#include "cmsis_os.h"
void yield(void) {
vTaskDelay(1);
taskYIELD();
}
void yield(void) __attribute__((weak, alias("__empty")));
/**
* SysTick hook
@@ -46,7 +41,8 @@ static int __false() {
// Return false
return 0;
}
int sysTickHook(void) __attribute__ ((weak, alias("__false")));
int sysTickHook(void) __attribute__((weak, alias("__false")));
/**
* SVC hook
@@ -60,5 +56,6 @@ static void __halt() {
while (1)
;
}
void svcHook(void) __attribute__ ((weak, alias("__halt")));
void pendSVHook(void) __attribute__ ((weak, alias("__halt")));
void svcHook(void) __attribute__((weak, alias("__halt")));
void pendSVHook(void) __attribute__((weak, alias("__halt")));

View File

@@ -0,0 +1,111 @@
/*
Copyright (c) 2014 Arduino LLC. All right 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
*/
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
char *ltoa(long value, char *string, int radix) {
char tmp[33];
char *tp = tmp;
long i;
unsigned long v;
int sign;
char *sp;
if (string == NULL) {
return 0;
}
if (radix > 36 || radix <= 1) {
return 0;
}
sign = (radix == 10 && value < 0);
if (sign) {
v = -value;
} else {
v = (unsigned long)value;
}
while (v || tp == tmp) {
i = v % radix;
v = v / radix;
if (i < 10)
*tp++ = i + '0';
else
*tp++ = i + 'a' - 10;
}
sp = string;
if (sign)
*sp++ = '-';
while (tp > tmp)
*sp++ = *--tp;
*sp = 0;
return string;
}
char *ultoa(unsigned long value, char *string, int radix) {
char tmp[33];
char *tp = tmp;
long i;
unsigned long v = value;
char *sp;
if (string == NULL) {
return 0;
}
if (radix > 36 || radix <= 1) {
return 0;
}
while (v || tp == tmp) {
i = v % radix;
v = v / radix;
if (i < 10)
*tp++ = i + '0';
else
*tp++ = i + 'a' - 10;
}
sp = string;
while (tp > tmp)
*sp++ = *--tp;
*sp = 0;
return string;
}
char *itoa(int value, char *string, int radix) {
return ltoa(value, string, radix);
}
char *utoa(unsigned int value, char *string, int radix) {
return ultoa(value, string, radix);
}
#ifdef __cplusplus
} // extern "C"
#endif

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 init() __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
init();
// 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,54 @@
/*
Copyright (c) 2014 Arduino. All right 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
*/
#include <Arduino.h>
#include <stdint.h>
uint8_t shiftIn(pin_size_t ulDataPin, pin_size_t ulClockPin, BitOrder ulBitOrder) {
uint8_t value = 0;
uint8_t i;
for (i = 0; i < 8; ++i) {
digitalWrite(ulClockPin, HIGH);
if (ulBitOrder == LSBFIRST) {
value |= digitalRead(ulDataPin) << i;
} else {
value |= digitalRead(ulDataPin) << (7 - i);
}
digitalWrite(ulClockPin, LOW);
}
return value;
}
void shiftOut(pin_size_t ulDataPin, pin_size_t ulClockPin, BitOrder ulBitOrder, uint8_t ulVal) {
uint8_t i;
for (i = 0; i < 8; i++) {
if (ulBitOrder == LSBFIRST) {
digitalWrite(ulDataPin, !!(ulVal & (1 << i)));
} else {
digitalWrite(ulDataPin, !!(ulVal & (1 << (7 - i))));
}
digitalWrite(ulClockPin, HIGH);
digitalWrite(ulClockPin, LOW);
}
}

View File

@@ -1,3 +1,5 @@
/* Copyright (c) Kuba Szczodrzyński 2022-04-30. */
#pragma once
#include <api/FS.h>

View File

@@ -1 +1,3 @@
/* Copyright (c) Kuba Szczodrzyński 2022-04-30. */
// nop

View File

@@ -1,3 +1,5 @@
/* Copyright (c) Kuba Szczodrzyński 2022-04-26. */
#pragma once
// ESP32 WiFi examples use WiFiAP.h include

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

@@ -1,3 +1,5 @@
/* Copyright (c) Kuba Szczodrzyński 2022-04-30. */
#pragma once
#include <api/deprecated-avr-comp/avr/pgmspace.h>

View File

@@ -1 +1,3 @@
/* Copyright (c) Kuba Szczodrzyński 2022-04-30. */
// nop

View File

@@ -0,0 +1,29 @@
/* 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
};

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

@@ -1,42 +1,57 @@
/* Copyright (c) Kuba Szczodrzyński 2022-04-28. */
#pragma once
// C standard libraries
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
// LibreTuya version macros
#ifndef LT_VERSION
#define LT_VERSION 1.0.0
#endif
#ifndef LT_BOARD
#define LT_BOARD unknown
#endif
#define STRINGIFY(x) #x
#define STRINGIFY_MACRO(x) STRINGIFY(x)
#define LT_VERSION_STR STRINGIFY_MACRO(LT_VERSION)
#define LT_BOARD_STR STRINGIFY_MACRO(LT_BOARD)
// Includes
#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>
#include "LibreTuyaConfig.h"
// C includes
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#include "lt_logger.h"
#include "lt_posix_api.h"
#ifdef __cplusplus
} // extern "C"
#endif
// Functional macros
#define LT_BANNER() \
LT_LOG( \
LT_LEVEL_INFO, \
"main.cpp", \
__FUNCTION__, \
__LINE__, \
"LibreTuya v" LT_VERSION_STR " on " LT_BOARD_STR ", compiled at " __DATE__ " " __TIME__ \
)
extern char *strdup(const char *);
void lt_rand_bytes(uint8_t *buf, size_t len);
// ArduinCore-API doesn't define these anymore
#define FPSTR(pstr_pointer) (reinterpret_cast<const __FlashStringHelper *>(pstr_pointer))
#define PGM_VOID_P const void *
#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

@@ -1,3 +1,5 @@
/* Copyright (c) Kuba Szczodrzyński 2022-04-28. */
#pragma once
// see docs/API Configuration
@@ -21,8 +23,8 @@
#define LT_LOGGER_TIMESTAMP 1
#endif
#ifndef LT_LOGGER_FILE
#define LT_LOGGER_FILE 0
#ifndef LT_LOGGER_CALLER
#define LT_LOGGER_CALLER 1
#endif
#ifndef LT_LOGGER_TASK
@@ -42,6 +44,16 @@
#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
// Per-module debugging
#ifndef LT_DEBUG_WIFI
#define LT_DEBUG_WIFI 0
@@ -62,3 +74,7 @@
#ifndef LT_DEBUG_WIFI_AP
#define LT_DEBUG_WIFI_AP 0
#endif
#ifndef LT_DEBUG_SSL
#define LT_DEBUG_SSL 0
#endif

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

@@ -1,8 +1,10 @@
/* Copyright (c) Kuba Szczodrzyński 2022-04-28. */
#include "lt_logger.h"
#include <Arduino.h>
#if LT_LOGGER_TASK
#if LT_LOGGER_TASK && LT_HAS_FREERTOS
#include <FreeRTOS.h>
#include <task.h>
#endif
@@ -40,8 +42,8 @@ const uint8_t colors[] = {
unsigned long millis(void);
#if LT_LOGGER_FILE
void lt_log(const uint8_t level, const char *filename, const unsigned short line, const char *format, ...) {
#if LT_LOGGER_CALLER
void lt_log(const uint8_t level, const char *caller, const unsigned short line, const char *format, ...) {
#else
void lt_log(const uint8_t level, const char *format, ...) {
#endif
@@ -55,7 +57,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);
@@ -85,19 +87,18 @@ void lt_log(const uint8_t level, const char *format, ...) {
#if LT_LOGGER_COLOR
"\e[0m"
#endif
#if LT_LOGGER_FILE
"%s:%hu: "
#if LT_LOGGER_CALLER
"%s():%hu: "
#endif
#if LT_LOGGER_TASK
#if LT_LOGGER_TASK && LT_HAS_FREERTOS
"%s%c "
#endif
,
levels[level]
#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
@@ -106,12 +107,12 @@ void lt_log(const uint8_t level, const char *format, ...) {
zero // append missing zeroes if printf "%11.3f" prints "0."
#endif
#endif
#if LT_LOGGER_FILE
#if LT_LOGGER_CALLER
,
filename,
caller,
line
#endif
#if LT_LOGGER_TASK
#if LT_LOGGER_TASK && LT_HAS_FREERTOS
,
task_name,
task_colon // printing outside of tasks

View File

@@ -0,0 +1,175 @@
/* Copyright (c) Kuba Szczodrzyński 2022-04-28. */
#pragma once
#include "LibreTuyaConfig.h"
#include <stdint.h>
#if LT_LOGGER_CALLER
#define LT_LOG(level, caller, line, ...) lt_log(level, caller, line, __VA_ARGS__)
void lt_log(const uint8_t level, const char *caller, const unsigned short line, const char *format, ...);
#else
#define LT_LOG(level, caller, line, ...) lt_log(level, __VA_ARGS__)
void lt_log(const uint8_t level, const char *format, ...);
#endif
#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__)
#else
#define LT_T(...)
#define LT_V(...)
#endif
#if LT_LEVEL_DEBUG >= LT_LOGLEVEL
#define LT_D(...) LT_LOG(LT_LEVEL_DEBUG, __FUNCTION__, __LINE__, __VA_ARGS__)
#else
#define LT_D(...)
#endif
#if LT_LEVEL_INFO >= LT_LOGLEVEL
#define LT_I(...) LT_LOG(LT_LEVEL_INFO, __FUNCTION__, __LINE__, __VA_ARGS__)
#else
#define LT_I(...)
#endif
#if LT_LEVEL_WARN >= LT_LOGLEVEL
#define LT_W(...) LT_LOG(LT_LEVEL_WARN, __FUNCTION__, __LINE__, __VA_ARGS__)
#else
#define LT_W(...)
#endif
#if LT_LEVEL_ERROR >= LT_LOGLEVEL
#define LT_E(...) LT_LOG(LT_LEVEL_ERROR, __FUNCTION__, __LINE__, __VA_ARGS__)
#else
#define LT_E(...)
#endif
#if LT_LEVEL_FATAL >= LT_LOGLEVEL
#define LT_F(...) LT_LOG(LT_LEVEL_FATAL, __FUNCTION__, __LINE__, __VA_ARGS__)
#else
#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__)
#define log_d(...) LT_D(__VA_ARGS__)
#define log_i(...) LT_I(__VA_ARGS__)
#define log_w(...) LT_W(__VA_ARGS__)
#define log_e(...) LT_E(__VA_ARGS__)
#define log_n(...) LT_E(__VA_ARGS__)
#define isr_log_v(...) LT_V(__VA_ARGS__)
#define isr_log_d(...) LT_D(__VA_ARGS__)
#define isr_log_i(...) LT_I(__VA_ARGS__)
#define isr_log_w(...) LT_W(__VA_ARGS__)
#define isr_log_e(...) LT_E(__VA_ARGS__)
#define isr_log_n(...) LT_E(__VA_ARGS__)
#define ESP_LOGV(...) LT_V(__VA_ARGS__)
#define ESP_LOGD(...) LT_D(__VA_ARGS__)
#define ESP_LOGI(...) LT_I(__VA_ARGS__)
#define ESP_LOGW(...) LT_W(__VA_ARGS__)
#define ESP_LOGE(...) LT_E(__VA_ARGS__)
#define ESP_EARLY_LOGV(...) LT_V(__VA_ARGS__)
#define ESP_EARLY_LOGD(...) LT_D(__VA_ARGS__)
#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 { \
if (module) { \
LT_T(__VA_ARGS__); \
} \
} while (0)
#define LT_D_MOD(module, ...) \
do { \
if (module) { \
LT_D(__VA_ARGS__); \
} \
} while (0)
#define LT_RET(ret) \
LT_E("ret=%d", ret); \
return ret;
#define LT_RET_NZ(ret) \
if (ret) { \
LT_E("ret=%d", ret); \
return ret; \
}
#define LT_RET_LZ(ret) \
if (ret < 0) { \
LT_E("ret=%d", ret); \
return ret; \
}
#define LT_RET_LEZ(ret) \
if (ret <= 0) { \
LT_E("ret=%d", ret); \
return ret; \
}
#define LT_ERRNO_NZ(ret) \
if (ret) { \
LT_E("errno=%d, ret=%d", errno, ret); \
return ret; \
}
#define LT_ERRNO_LZ(ret) \
if (ret < 0) { \
LT_E("errno=%d, ret=%d", errno, ret); \
return ret; \
}
#define LT_ERRNO_LEZ(ret) \
if (ret <= 0) { \
LT_E("errno=%d, ret=%d", errno, ret); \
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__)
#define LT_D_WG(...) LT_D_MOD(LT_DEBUG_WIFI, __VA_ARGS__)
// WiFiClient.cpp
#define LT_T_WC(...) LT_T_MOD(LT_DEBUG_WIFI_CLIENT, __VA_ARGS__)
#define LT_V_WC(...) LT_T_MOD(LT_DEBUG_WIFI_CLIENT, __VA_ARGS__)
#define LT_D_WC(...) LT_D_MOD(LT_DEBUG_WIFI_CLIENT, __VA_ARGS__)
// WiFiServer.cpp
#define LT_T_WS(...) LT_T_MOD(LT_DEBUG_WIFI_SERVER, __VA_ARGS__)
#define LT_V_WS(...) LT_T_MOD(LT_DEBUG_WIFI_SERVER, __VA_ARGS__)
#define LT_D_WS(...) LT_D_MOD(LT_DEBUG_WIFI_SERVER, __VA_ARGS__)
// WiFiSTA.cpp
#define LT_T_WSTA(...) LT_T_MOD(LT_DEBUG_WIFI_STA, __VA_ARGS__)
#define LT_V_WSTA(...) LT_T_MOD(LT_DEBUG_WIFI_STA, __VA_ARGS__)
#define LT_D_WSTA(...) LT_D_MOD(LT_DEBUG_WIFI_STA, __VA_ARGS__)
// WiFiAP.cpp
#define LT_T_WAP(...) LT_T_MOD(LT_DEBUG_WIFI_AP, __VA_ARGS__)
#define LT_V_WAP(...) LT_T_MOD(LT_DEBUG_WIFI_AP, __VA_ARGS__)
#define LT_D_WAP(...) LT_D_MOD(LT_DEBUG_WIFI_AP, __VA_ARGS__)
// WiFiClientSecure.cpp & implementations
#define LT_T_SSL(...) LT_T_MOD(LT_DEBUG_SSL, __VA_ARGS__)
#define LT_V_SSL(...) LT_T_MOD(LT_DEBUG_SSL, __VA_ARGS__)
#define LT_D_SSL(...) LT_D_MOD(LT_DEBUG_SSL, __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

@@ -1,19 +1,11 @@
/* Copyright (c) Kuba Szczodrzyński 2022-04-24. */
#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

@@ -1,3 +1,5 @@
/* Copyright (c) Kuba Szczodrzyński 2022-04-29. */
#pragma once
#include <time.h>

View File

@@ -0,0 +1,2 @@
DisableFormat: true
SortIncludes: Never

View File

@@ -0,0 +1,31 @@
/* 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
// 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,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

@@ -0,0 +1,98 @@
/*
IPv6Address.cpp - Base class that provides IPv6Address
Copyright (c) 2011 Adrian McEwen. All right 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
*/
#include "IPv6Address.h"
#include <Arduino.h>
#include <api/Print.h>
IPv6Address::IPv6Address() {
memset(_address.bytes, 0, sizeof(_address.bytes));
}
IPv6Address::IPv6Address(const uint8_t *address) {
memcpy(_address.bytes, address, sizeof(_address.bytes));
}
IPv6Address::IPv6Address(const uint32_t *address) {
memcpy(_address.bytes, (const uint8_t *)address, sizeof(_address.bytes));
}
IPv6Address &IPv6Address::operator=(const uint8_t *address) {
memcpy(_address.bytes, address, sizeof(_address.bytes));
return *this;
}
bool IPv6Address::operator==(const uint8_t *addr) const {
return memcmp(addr, _address.bytes, sizeof(_address.bytes)) == 0;
}
size_t IPv6Address::printTo(Print &p) const {
/* size_t n = 0;
for(int i = 0; i < 16; i+=2) {
if(i){
n += p.print(':');
}
n += p.printf("%02x", _address.bytes[i]);
n += p.printf("%02x", _address.bytes[i+1]);
}
return n; */
}
String IPv6Address::toString() const {
char szRet[40];
sprintf(
szRet,
"%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
_address.bytes[0],
_address.bytes[1],
_address.bytes[2],
_address.bytes[3],
_address.bytes[4],
_address.bytes[5],
_address.bytes[6],
_address.bytes[7],
_address.bytes[8],
_address.bytes[9],
_address.bytes[10],
_address.bytes[11],
_address.bytes[12],
_address.bytes[13],
_address.bytes[14],
_address.bytes[15]
);
return String(szRet);
}
bool IPv6Address::fromString(const char *address) {
// format 0011:2233:4455:6677:8899:aabb:ccdd:eeff
if (strlen(address) != 39) {
return false;
}
char *pos = (char *)address;
size_t i = 0;
for (i = 0; i < 16; i += 2) {
if (!sscanf(pos, "%2hhx", &_address.bytes[i]) || !sscanf(pos + 2, "%2hhx", &_address.bytes[i + 1])) {
return false;
}
pos += 5;
}
return true;
}

View File

@@ -0,0 +1,97 @@
/*
IPv6Address.h - Base class that provides IPv6Address
Copyright (c) 2011 Adrian McEwen. All right 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
*/
#pragma once
#include <api/Print.h>
#include <api/String.h>
#include <stdint.h>
// A class to make it easier to handle and pass around IP addresses
namespace arduino {
class IPv6Address : public Printable {
private:
union {
uint8_t bytes[16]; // IPv4 address
uint32_t dword[4];
} _address;
// Access the raw byte array containing the address. Because this returns a pointer
// to the internal structure rather than a copy of the address this function should only
// be used when you know that the usage of the returned uint8_t* will be transient and not
// stored.
uint8_t *raw_address() {
return _address.bytes;
}
public:
// Constructors
IPv6Address();
IPv6Address(const uint8_t *address);
IPv6Address(const uint32_t *address);
virtual ~IPv6Address() {}
bool fromString(const char *address);
bool fromString(const String &address) {
return fromString(address.c_str());
}
operator const uint8_t *() const {
return _address.bytes;
}
operator const uint32_t *() const {
return _address.dword;
}
bool operator==(const IPv6Address &addr) const {
return (_address.dword[0] == addr._address.dword[0]) && (_address.dword[1] == addr._address.dword[1]) &&
(_address.dword[2] == addr._address.dword[2]) && (_address.dword[3] == addr._address.dword[3]);
}
bool operator==(const uint8_t *addr) const;
// Overloaded index operator to allow getting and setting individual octets of the address
uint8_t operator[](int index) const {
return _address.bytes[index];
}
uint8_t &operator[](int index) {
return _address.bytes[index];
}
// Overloaded copy operators to allow initialisation of IPv6Address objects from other types
IPv6Address &operator=(const uint8_t *address);
// TODO implement printTo()
virtual size_t printTo(Print &p) const;
String toString() const;
friend class UDP;
friend class Client;
friend class Server;
};
} // namespace arduino
using arduino::IPv6Address;

View File

@@ -0,0 +1,5 @@
/* Copyright (c) Kuba Szczodrzyński 2022-04-30. */
#pragma once
#include "../IPv6Address.h"

View File

@@ -1,5 +1,29 @@
#include "WiFiClient.h"
#include "WiFiPriv.h"
/* Copyright (c) Kuba Szczodrzyński 2022-04-26. */
#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:
@@ -12,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;
@@ -45,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;
@@ -78,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) {
@@ -115,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;
@@ -144,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;
@@ -187,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)
@@ -226,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);
@@ -237,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();
@@ -248,7 +286,7 @@ int WiFiClient::peek() {
return res;
}
void WiFiClient::flush() {
void LwIPClient::flush() {
int res;
size_t len = available();
if (!len)
@@ -267,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) {
@@ -318,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,15 +1,30 @@
#include "WiFiServer.h"
#include "WiFiPriv.h"
/* Copyright (c) Kuba Szczodrzyński 2022-04-26. */
WiFiServer::WiFiServer(uint32_t addr, uint16_t port, uint8_t maxClients)
#if LT_ARD_HAS_WIFI && LT_HAS_LWIP
#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)
@@ -48,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);
@@ -56,7 +71,7 @@ void WiFiServer::end() {
_active = -1;
}
WiFiClient WiFiServer::accept() {
WiFiClient LwIPServer::accept() {
if (!_active)
return WiFiClient();
@@ -94,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;
@@ -103,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;
}
@@ -123,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

@@ -0,0 +1,452 @@
/* Copyright (c) Kuba Szczodrzyński 2022-04-30. */
#if LT_ARD_HAS_WIFI && LT_HAS_MBEDTLS
#include "MbedTLSClient.h"
extern "C" {
#include <mbedtls/debug.h>
#include <mbedtls/platform.h>
#include <mbedtls/sha256.h>
#include <mbedtls/ssl.h>
} // extern "C"
MbedTLSClient::MbedTLSClient() : WiFiClient() {
init(); // ensure the context is zero filled
}
MbedTLSClient::MbedTLSClient(int sock) : WiFiClient(sock) {
init(); // ensure the context is zero filled
}
MbedTLSClient::~MbedTLSClient() {
LT_V_WC("~MbedTLSClient()");
stop();
}
void MbedTLSClient::stop() {
LT_V_SSL("Stopping SSL");
if (_sslCfg.ca_chain) {
mbedtls_x509_crt_free(&_caCert);
}
if (_sslCfg.key_cert) {
mbedtls_x509_crt_free(&_clientCert);
mbedtls_pk_free(&_clientKey);
}
mbedtls_ssl_free(&_sslCtx);
mbedtls_ssl_config_free(&_sslCfg);
LT_HEAP_I();
}
void MbedTLSClient::init() {
// Realtek AmbZ: init platform here to ensure HW crypto is initialized in ssl_init
mbedtls_platform_set_calloc_free(calloc, free);
mbedtls_ssl_init(&_sslCtx);
mbedtls_ssl_config_init(&_sslCfg);
}
int MbedTLSClient::connect(IPAddress ip, uint16_t port, int32_t timeout) {
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, 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, 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, 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, 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, 0, NULL, NULL, NULL, pskIdent, psk) == 0;
}
static int ssl_random(void *data, unsigned char *output, size_t 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) {
// 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
) {
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);
if (ret < 0) {
LT_E("SSL socket failed");
return ret;
}
char *uid = "lt-ssl"; // TODO
LT_V_SSL("Init SSL");
init();
LT_HEAP_I();
// mbedtls_debug_set_threshold(4);
// mbedtls_ssl_conf_dbg(&_sslCfg, debug_cb, NULL);
ret = mbedtls_ssl_config_defaults(
&_sslCfg,
MBEDTLS_SSL_IS_CLIENT,
MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT
);
LT_RET_NZ(ret);
#ifdef MBEDTLS_SSL_ALPN
if (_alpnProtocols) {
ret = mbedtls_ssl_conf_alpn_protocols(&_sslCfg, _alpnProtocols);
LT_RET_NZ(ret);
}
#endif
if (_insecure) {
mbedtls_ssl_conf_authmode(&_sslCfg, MBEDTLS_SSL_VERIFY_NONE);
} else if (rootCABuf) {
mbedtls_x509_crt_init(&_caCert);
mbedtls_ssl_conf_authmode(&_sslCfg, MBEDTLS_SSL_VERIFY_REQUIRED);
ret = mbedtls_x509_crt_parse(&_caCert, (const unsigned char *)rootCABuf, strlen(rootCABuf) + 1);
mbedtls_ssl_conf_ca_chain(&_sslCfg, &_caCert, NULL);
if (ret < 0) {
mbedtls_x509_crt_free(&_caCert);
LT_RET(ret);
}
} else if (_useRootCA) {
return -1; // not implemented
} else if (pskIdent && psk) {
#ifdef MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED
uint16_t len = strlen(psk);
if ((len & 1) != 0 || len > 2 * MBEDTLS_PSK_MAX_LEN) {
LT_E("PSK length invalid");
return -1;
}
unsigned char pskBin[MBEDTLS_PSK_MAX_LEN] = {};
for (uint8_t i = 0; i < len; i++) {
uint8_t c = psk[i];
c |= 0b00100000; // make lowercase
c -= '0' * (c >= '0' && c <= '9');
c -= ('a' - 10) * (c >= 'a' && c <= 'z');
if (c > 0xf)
return -1;
pskBin[i / 2] |= c << (4 * ((i & 1) ^ 1));
}
ret = mbedtls_ssl_conf_psk(&_sslCfg, pskBin, len / 2, (const unsigned char *)pskIdent, strlen(pskIdent));
LT_RET_NZ(ret);
#else
return -1;
#endif
} else {
return -1;
}
if (!_insecure && clientCert && clientKey) {
mbedtls_x509_crt_init(&_clientCert);
mbedtls_pk_init(&_clientKey);
LT_V_SSL("Loading client cert");
ret = mbedtls_x509_crt_parse(&_clientCert, (const unsigned char *)clientCert, strlen(clientCert) + 1);
if (ret < 0) {
mbedtls_x509_crt_free(&_clientCert);
LT_RET(ret);
}
LT_V_SSL("Loading private key");
ret = mbedtls_pk_parse_key(&_clientKey, (const unsigned char *)clientKey, strlen(clientKey) + 1, NULL, 0);
if (ret < 0) {
mbedtls_x509_crt_free(&_clientCert);
LT_RET(ret);
}
mbedtls_ssl_conf_own_cert(&_sslCfg, &_clientCert, &_clientKey);
}
LT_V_SSL("Setting TLS hostname");
ret = mbedtls_ssl_set_hostname(&_sslCtx, host);
LT_RET_NZ(ret);
mbedtls_ssl_conf_rng(&_sslCfg, ssl_random, NULL);
ret = mbedtls_ssl_setup(&_sslCtx, &_sslCfg);
LT_RET_NZ(ret);
_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;
unsigned long start = millis();
while (ret = mbedtls_ssl_handshake(&_sslCtx)) {
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
LT_RET(ret);
}
if ((millis() - start) > _handshakeTimeout) {
LT_E("SSL handshake timeout");
return -1;
}
delay(2);
}
LT_HEAP_I();
if (clientCert && clientKey) {
LT_D_SSL(
"Protocol %s, ciphersuite %s",
mbedtls_ssl_get_version(&_sslCtx),
mbedtls_ssl_get_ciphersuite(&_sslCtx)
);
ret = mbedtls_ssl_get_record_expansion(&_sslCtx);
if (ret >= 0)
LT_D_SSL("Record expansion: %d", ret);
else {
LT_W("Record expansion unknown");
}
}
LT_V_SSL("Verifying certificate");
ret = mbedtls_ssl_get_verify_result(&_sslCtx);
if (ret) {
char buf[512];
memset(buf, 0, sizeof(buf));
mbedtls_x509_crt_verify_info(buf, sizeof(buf), " ! ", ret);
LT_E("Failed to verify peer certificate! Verification info: %s", buf);
return ret;
}
if (rootCABuf)
mbedtls_x509_crt_free(&_caCert);
if (clientCert)
mbedtls_x509_crt_free(&_clientCert);
if (clientKey != NULL)
mbedtls_pk_free(&_clientKey);
return 0; // OK
}
size_t MbedTLSClient::write(const uint8_t *buf, size_t size) {
int ret = -1;
while ((ret = mbedtls_ssl_write(&_sslCtx, buf, size)) <= 0) {
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE && ret < 0) {
LT_RET(ret);
}
delay(2);
}
return ret;
}
int MbedTLSClient::available() {
bool peeked = _peeked >= 0;
if (!connected())
return peeked;
int ret = mbedtls_ssl_read(&_sslCtx, NULL, 0);
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE && ret < 0) {
stop();
return peeked ? peeked : ret;
}
return mbedtls_ssl_get_bytes_avail(&_sslCtx) + peeked;
}
int MbedTLSClient::read(uint8_t *buf, size_t size) {
bool peeked = false;
int toRead = available();
if ((!buf && size) || toRead <= 0)
return -1;
if (!size)
return 0;
if (_peeked >= 0) {
buf[0] = _peeked;
_peeked = -1;
size--;
toRead--;
if (!size || !toRead)
return 1;
buf++;
peeked = true;
}
int ret = mbedtls_ssl_read(&_sslCtx, buf, size);
if (ret < 0) {
stop();
return peeked ? peeked : ret;
}
return ret + peeked;
}
int MbedTLSClient::peek() {
if (_peeked >= 0)
return _peeked;
_peeked = timedRead();
return _peeked;
}
void MbedTLSClient::flush() {}
int MbedTLSClient::lastError(char *buf, const size_t size) {
return 0; // TODO (?)
}
void MbedTLSClient::setInsecure() {
_caCertStr = NULL;
_clientCertStr = NULL;
_clientKeyStr = NULL;
_pskIdentStr = NULL;
_pskStr = NULL;
_insecure = true;
}
void MbedTLSClient::setPreSharedKey(const char *pskIdent, const char *psk) {
_pskIdentStr = pskIdent;
_pskStr = psk;
}
void MbedTLSClient::setCACert(const char *rootCA) {
_caCertStr = rootCA;
}
void MbedTLSClient::setCertificate(const char *clientCA) {
_clientCertStr = clientCA;
}
void MbedTLSClient::setPrivateKey(const char *privateKey) {
_clientKeyStr = privateKey;
}
char *streamToStr(Stream &stream, size_t size) {
char *buf = (char *)malloc(size + 1);
if (!buf)
return NULL;
if (size != stream.readBytes(buf, size)) {
free(buf);
return NULL;
}
buf[size] = '\0';
return buf;
}
bool MbedTLSClient::loadCACert(Stream &stream, size_t size) {
char *str = streamToStr(stream, size);
if (str) {
_caCertStr = str;
return true;
}
return false;
}
bool MbedTLSClient::loadCertificate(Stream &stream, size_t size) {
char *str = streamToStr(stream, size);
if (str) {
_clientCertStr = str;
return true;
}
return false;
}
bool MbedTLSClient::loadPrivateKey(Stream &stream, size_t size) {
char *str = streamToStr(stream, size);
if (str) {
_clientKeyStr = str;
return true;
}
return false;
}
bool MbedTLSClient::verify(const char *fingerprint, const char *domainName) {
uint8_t fpLocal[32] = {};
uint16_t len = strlen(fingerprint);
uint8_t byte = 0;
for (uint8_t i = 0; i < len; i++) {
uint8_t c = fingerprint[i];
while ((c == ' ' || c == ':') && i < len) {
c = fingerprint[++i];
}
c |= 0b00100000; // make lowercase
c -= '0' * (c >= '0' && c <= '9');
c -= ('a' - 10) * (c >= 'a' && c <= 'z');
if (c > 0xf)
return -1;
fpLocal[byte / 2] |= c << (4 * ((byte & 1) ^ 1));
byte++;
if (byte >= 64)
break;
}
uint8_t fpRemote[32];
if (!getFingerprintSHA256(fpRemote))
return false;
if (memcmp(fpLocal, fpRemote, 32)) {
LT_D_SSL("Fingerprints don't match");
return false;
}
if (!domainName)
return true;
// TODO domain name verification
return true;
}
void MbedTLSClient::setHandshakeTimeout(unsigned long handshakeTimeout) {
_handshakeTimeout = handshakeTimeout * 1000;
}
void MbedTLSClient::setAlpnProtocols(const char **alpnProtocols) {
_alpnProtocols = alpnProtocols;
}
bool MbedTLSClient::getFingerprintSHA256(uint8_t result[32]) {
const mbedtls_x509_crt *cert = mbedtls_ssl_get_peer_cert(&_sslCtx);
if (!cert) {
LT_E("Failed to get peer certificate");
return false;
}
mbedtls_sha256_context shaCtx;
mbedtls_sha256_init(&shaCtx);
mbedtls_sha256_starts(&shaCtx, false);
mbedtls_sha256_update(&shaCtx, cert->raw.p, cert->raw.len);
mbedtls_sha256_finish(&shaCtx, result);
return true;
}
#endif // LT_ARD_HAS_WIFI && LT_HAS_MBEDTLS

View File

@@ -0,0 +1,88 @@
/* Copyright (c) Kuba Szczodrzyński 2022-04-30. */
#pragma once
#include <api/WiFi/WiFi.h>
#include <api/WiFiClient.h>
#include <api/WiFiClientSecure.h>
#include <WiFiClient.h> // extend family's WiFiClient impl
extern "C" {
#include <mbedtls/net.h>
} // extern "C"
class MbedTLSClient : public WiFiClient, public IWiFiClientSecure {
private:
mbedtls_ssl_context _sslCtx;
mbedtls_ssl_config _sslCfg;
mbedtls_x509_crt _caCert;
mbedtls_x509_crt _clientCert;
mbedtls_pk_context _clientKey;
uint32_t _handshakeTimeout = 0;
void init();
int _sockTls = -1;
bool _insecure = false;
bool _useRootCA = false;
int _peeked = -1;
const char *_caCertStr;
const char *_clientCertStr;
const char *_clientKeyStr;
const char *_pskIdentStr;
const char *_pskStr;
const char **_alpnProtocols;
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
);
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);
int connect(IPAddress ip, uint16_t port, const char *rootCABuf, const char *clientCert, const char *clientKey);
int connect(const char *host, uint16_t port, const char *rootCABuf, const char *clientCert, const char *clientKey);
int connect(IPAddress ip, uint16_t port, const char *pskIdent, const char *psk);
int connect(const char *host, uint16_t port, const char *pskIdent, const char *psk);
size_t write(const uint8_t *buf, size_t size);
int available();
int read(uint8_t *buf, size_t size);
int peek();
void flush();
void stop();
int lastError(char *buf, const size_t size);
void setInsecure(); // Don't validate the chain, just accept whatever is given. VERY INSECURE!
void setPreSharedKey(const char *pskIdent, const char *psk); // psk in hex
void setCACert(const char *rootCA);
void setCertificate(const char *clientCA);
void setPrivateKey(const char *privateKey);
bool loadCACert(Stream &stream, size_t size);
bool loadCertificate(Stream &stream, size_t size);
bool loadPrivateKey(Stream &stream, size_t size);
bool verify(const char *fingerprint, const char *domainName);
void setHandshakeTimeout(unsigned long handshakeTimeout);
void setAlpnProtocols(const char **alpnProtocols);
bool getFingerprintSHA256(uint8_t result[32]);
using WiFiClient::connect;
using WiFiClient::read;
};

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