Compare commits
142 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a286b5d067 | ||
|
|
f071f57abf | ||
|
|
0e0fe334cd | ||
|
|
23410c618d | ||
|
|
b44898f08d | ||
|
|
165f356439 | ||
|
|
1d0df2936b | ||
|
|
1684d63e04 | ||
|
|
cf5dfb43d6 | ||
|
|
ded6638ef6 | ||
|
|
a8228851d9 | ||
|
|
633289def6 | ||
|
|
f4ff13d6b7 | ||
|
|
0493ec2245 | ||
|
|
4c6bbb8aae | ||
|
|
b625f636be | ||
|
|
3bfd62d075 | ||
|
|
b405adb359 | ||
|
|
accf37de39 | ||
|
|
582eed3be8 | ||
|
|
35d5ec03a3 | ||
|
|
737c627d44 | ||
|
|
84a3120c7f | ||
|
|
99b9ed1181 | ||
|
|
0d636a3285 | ||
|
|
79ccd47f71 | ||
|
|
3ffc70abe5 | ||
|
|
f4f2eda481 | ||
|
|
f4b2c74b0e | ||
|
|
111e5a66b6 | ||
|
|
b90723130d | ||
|
|
e6179761d4 | ||
|
|
b371fd3468 | ||
|
|
c8fccdbb47 | ||
|
|
4876401809 | ||
|
|
45af7c188a | ||
|
|
236e9ccda6 | ||
|
|
94e8b9f87e | ||
|
|
c9580d6627 | ||
|
|
87929373e2 | ||
|
|
4e2aec9ced | ||
|
|
fa7957f5e2 | ||
|
|
4f15805246 | ||
|
|
cf67c815e9 | ||
|
|
5533dc807f | ||
|
|
ac2aabe6e3 | ||
|
|
c6a428ddd4 | ||
|
|
a83a845d5a | ||
|
|
c91b188f96 | ||
|
|
53a6f4593e | ||
|
|
0dda769d0f | ||
|
|
848df066c4 | ||
|
|
b4005d8bad | ||
|
|
34c0df2761 | ||
|
|
cedfc2c8db | ||
|
|
c9fe63ec7b | ||
|
|
2fedcb61b5 | ||
|
|
272b033253 | ||
|
|
cae03d54d6 | ||
|
|
e70f1a591f | ||
|
|
0e768ac6e4 | ||
|
|
bc056eaca2 | ||
|
|
a6ad84a3b8 | ||
|
|
a5b953dc80 | ||
|
|
d446b05387 | ||
|
|
e864e5ef24 | ||
|
|
e669507759 | ||
|
|
e50c04cbe1 | ||
|
|
56dd57f4a0 | ||
|
|
f2abb564c7 | ||
|
|
4e7abb2350 | ||
|
|
540e499389 | ||
|
|
191a2bdd2a | ||
|
|
4d1c8357b4 | ||
|
|
85b5b1df91 | ||
|
|
c3e2c105d4 | ||
|
|
dba602a081 | ||
|
|
c3f2ce57f0 | ||
|
|
bbf8e0b6b6 | ||
|
|
03ab020dc8 | ||
|
|
9c1f3225a6 | ||
|
|
f72dd3b7d7 | ||
|
|
48f6210607 | ||
|
|
6f9be2b139 | ||
|
|
3217525873 | ||
|
|
e26972bd2f | ||
|
|
bf31533306 | ||
|
|
0ca0577667 | ||
|
|
0e797e7e04 | ||
|
|
a661ef3a3f | ||
|
|
17dc1dcf8c | ||
|
|
4c27aa57b1 | ||
|
|
a21c07fa03 | ||
|
|
bdffa7ef53 | ||
|
|
22d40825bb | ||
|
|
50f26f546c | ||
|
|
9c7ea46ec3 | ||
|
|
5b4cf53d8a | ||
|
|
79a701a4d4 | ||
|
|
81897e634c | ||
|
|
3e11da4dd4 | ||
|
|
12aa7fef04 | ||
|
|
1ea6420bbc | ||
|
|
f3f1f36525 | ||
|
|
dee9a98cc3 | ||
|
|
3345ce3fb9 | ||
|
|
de70583838 | ||
|
|
a43a737004 | ||
|
|
1f6899354f | ||
|
|
9110a0c47e | ||
|
|
b549790798 | ||
|
|
5df430f3be | ||
|
|
f3e8bcd74a | ||
|
|
4b050e11cf | ||
|
|
7ddbc09564 | ||
|
|
d3d62f80fd | ||
|
|
bc7dbe6eec | ||
|
|
e625f55353 | ||
|
|
aeebff9d5d | ||
|
|
9a3c077ef1 | ||
|
|
91ae692058 | ||
|
|
ad590d1eb2 | ||
|
|
8b00358901 | ||
|
|
bf4d8bb9be | ||
|
|
157dd2f407 | ||
|
|
1dc47878d4 | ||
|
|
36e4b6fd45 | ||
|
|
36d9a6e7e4 | ||
|
|
b7cceed4d3 | ||
|
|
694c06e7f5 | ||
|
|
12338747bf | ||
|
|
f4f9788f68 | ||
|
|
b9cdcad262 | ||
|
|
e4cd2ddec8 | ||
|
|
1477649a50 | ||
|
|
2e80469ab3 | ||
|
|
ccf63a4cdb | ||
|
|
b464871f73 | ||
|
|
e44834a95e | ||
|
|
4efefc5c6c | ||
|
|
dfd852b2db | ||
|
|
afa7141ceb |
5
.github/workflows/docs.yml
vendored
5
.github/workflows/docs.yml
vendored
@@ -1,11 +1,12 @@
|
||||
name: Deploy docs on GitHub Pages
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build:
|
||||
docs:
|
||||
name: Deploy docs
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
@@ -17,5 +18,5 @@ jobs:
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
CONFIG_FILE: mkdocs.yml
|
||||
EXTRA_PACKAGES: build-base
|
||||
EXTRA_PACKAGES: build-base doxygen
|
||||
REQUIREMENTS: docs/requirements.txt
|
||||
|
||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -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
2
.gitmodules
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
[submodule "tools/boardgen"]
|
||||
url = https://github.com/kuba2k2/boardgen
|
||||
201
README.md
201
README.md
@@ -2,26 +2,27 @@
|
||||
|
||||
<div align="center" markdown>
|
||||
|
||||
[](https://kuba2k2.github.io/libretuya/)
|
||||

|
||||
[](https://kuba2k2.github.io/libretuya/)
|
||||

|
||||
|
||||
[](https://github.com/psf/black)
|
||||
[](.clang-format)
|
||||
[](https://github.com/psf/black)
|
||||
|
||||
[](https://discord.gg/SyGCB9Xwtf)
|
||||
[](https://registry.platformio.org/platforms/kuba2k2/libretuya)
|
||||
|
||||

|
||||

|
||||
|
||||
<!-- [](https://registry.platformio.org/platforms/kuba2k2/libretuya) -->
|
||||
</div>
|
||||
|
||||
PlatformIO development platform for IoT modules manufactured by Tuya Inc.
|
||||
|
||||
The main goal of this project is to provide a usable build environment for IoT developers. While also providing vendor SDKs as PlatformIO cores,
|
||||
the project focuses on developing working Arduino-compatible cores for supported platforms. The cores are inspired by Espressif's official core for ESP32,
|
||||
which should make it easier to port/run existing ESP apps on Tuya IoT (and 3-rd party) platforms.
|
||||
the project focuses on developing working Arduino-compatible cores for supported families. The cores are inspired by Espressif's official core for ESP32,
|
||||
which should make it easier to port/run existing ESP apps on Tuya IoT (and 3-rd party) modules.
|
||||
|
||||
LibreTuya also provides a common interface for all platform implementations. The interface is based on ESP32 official libraries.
|
||||
LibreTuya also provides a common interface for all family implementations. The interface is based on ESP32 official libraries.
|
||||
|
||||
**Note:** this project is work-in-progress.
|
||||
|
||||
@@ -34,168 +35,40 @@ LibreTuya also provides a common interface for all platform implementations. The
|
||||
|
||||
## Board List
|
||||
|
||||
A (mostly) complete* list of Tuya wireless module boards.
|
||||
|
||||
| Module Name | MCU | Flash | RAM | Pins** | Wi-Fi | BLE | Platform name
|
||||
------------------------------|------------------------------------------------------------------------------------------------|-------------------------|-------|----------|-------------|-------|-----|---------------
|
||||
❌ | [WB1S](https://developer.tuya.com/en/docs/iot/wb1s?id=K9duevbj3ol4x) | BK7231T @ 120 MHz | 2 MiB | 256 KiB | 18 (11 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [WB2L](https://developer.tuya.com/en/docs/iot/wb2l-datasheet?id=K9duegc9bualu) | BK7231T @ 120 MHz | 2 MiB | 256 KiB | 7 (5 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [WB2S](https://developer.tuya.com/en/docs/iot/wb2s-module-datasheet?id=K9ghecl7kc479) | BK7231T @ 120 MHz | 2 MiB | 256 KiB | 11 (8 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [WB3L](https://developer.tuya.com/en/docs/iot/wb3l-module-datasheet?id=K9duiggw2v8sp) | BK7231T @ 120 MHz | 2 MiB | 256 KiB | 16 (12 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [WB3S](https://developer.tuya.com/en/docs/iot/wb3s-module-datasheet?id=K9dx20n6hz5n4) | BK7231T @ 120 MHz | 2 MiB | 256 KiB | 16 (11 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [WB3S-IPEX](https://developer.tuya.com/en/docs/iot/wb3sipex-module-datasheet?id=K9irq0laun21z) | BK7231T @ 120 MHz | 2 MiB | 256 KiB | 16 (11 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [WB8P](https://developer.tuya.com/en/docs/iot/wb8p-module-datasheet?id=K9fwx4f89tvzd) | BK7231T @ 120 MHz | 2 MiB | 256 KiB | 10 (8 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [WBLC5](https://developer.tuya.com/en/docs/iot/wblc5-module-datasheet?id=K9duilns1f3gi) | BK7231T @ 120 MHz | 2 MiB | 256 KiB | 6 (3 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [WBLC9](https://developer.tuya.com/en/docs/iot/wblc9-module-datasheet?id=K9hgglry2jp5h) | BK7231T @ 120 MHz | 2 MiB | 256 KiB | 8 (6 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [CB1S](https://developer.tuya.com/en/docs/iot/cb1s-module-datasheet?id=Kaij1abmwyjq2) | BK7231N @ 120 MHz | 2 MiB | 256 KiB | 18 (11 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [CB2L](https://developer.tuya.com/en/docs/iot/cb2l-module-datasheet?id=Kai2eku1m3pyl) | BK7231N @ 120 MHz | 2 MiB | 256 KiB | 7 (5 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [CB2S](https://developer.tuya.com/en/docs/iot/cb2s-module-datasheet?id=Kafgfsa2aaypq) | BK7231N @ 120 MHz | 2 MiB | 256 KiB | 11 (8 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [CB3L](https://developer.tuya.com/en/docs/iot/cb3l-module-datasheet?id=Kai51ngmrh3qm) | BK7231N @ 120 MHz | 2 MiB | 256 KiB | 16 (11 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [CB3S](https://developer.tuya.com/en/docs/iot/cb3s?id=Kai94mec0s076) | BK7231N @ 120 MHz | 2 MiB | 256 KiB | 22 (14 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [CB3S-NL](https://developer.tuya.com/en/docs/iot/CB3S-NL-module-datasheet?id=Kbaesan0vyoms) | BK7231NL (?) @ 120 MHz | 2 MiB | 256 KiB | 22 (14 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [CB3SE](https://developer.tuya.com/en/docs/iot/CB3SE-Module-Datasheet?id=Kanoiluul7nl2) | BK7231N @ 120 MHz | 2 MiB | 256 KiB | 22 (17 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [CB8P](https://developer.tuya.com/en/docs/iot/cb8p-module-datasheet?id=Kahvig14r1yk9) | BK7231N @ 120 MHz | 2 MiB | 256 KiB | 10 (8 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [CBLC5](https://developer.tuya.com/en/docs/iot/cblc5-module-datasheet?id=Ka07iqyusq1wm) | BK7231N @ 120 MHz | 2 MiB | 256 KiB | 6 (3 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [CBLC9](https://developer.tuya.com/en/docs/iot/cblc9-module-datasheet?id=Ka42cqnj9r0i5) | BK7231N @ 120 MHz | 2 MiB | 256 KiB | 8 (6 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [CBU](https://developer.tuya.com/en/docs/iot/cbu-module-datasheet?id=Ka07pykl5dk4u) | BK7231N @ 120 MHz | 2 MiB | 256 KiB | 21 (18 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [CBU-IPEX](https://developer.tuya.com/en/docs/iot/cbuipex-module-datasheet?id=Kaedsyurckrhu) | BK7231N @ 120 MHz | 2 MiB | 256 KiB | 21 (18 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [CBU-NL](https://developer.tuya.com/en/docs/iot/CBU-NL-module-datasheet?id=Kbaeq6j53y0yg) | BK7231N (?) @ 120 MHz | 2 MiB | 256 KiB | 21 (18 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [WR1](https://developer.tuya.com/en/docs/iot/wifiwr1module?id=K9605tc0k90t3) | RTL8710BN @ 125 MHz | 1 MiB | 256 KiB | 18 (11 I/O) | ✔️ | ❌ | -
|
||||
❌ | [WR1-IPEX](https://developer.tuya.com/en/docs/iot/wifiwr1ipexmodule?id=K9605t977tx5u) | RTL8710BN @ 125 MHz | 1 MiB | 256 KiB | 18 (11 I/O) | ✔️ | ❌ | -
|
||||
❌ | [WR1E](https://developer.tuya.com/en/docs/iot/wr1e?id=K96smbbeycxtf) | RTL8710BN @ 125 MHz | 2 MiB | 256 KiB | 18 (11 I/O) | ✔️ | ❌ | -
|
||||
❌ | [WR2](https://developer.tuya.com/en/docs/iot/wifiwr2module?id=K9605tko0juc3) | RTL8710BN @ 125 MHz | 2 MiB | 256 KiB | 11 (8 I/O) | ✔️ | ❌ | -
|
||||
❌ | [WR2E](https://developer.tuya.com/en/docs/iot/wr2e?id=K97scnsjhue4h) | RTL8710BN @ 125 MHz | 2 MiB | 256 KiB | 11 (8 I/O) | ✔️ | ❌ | -
|
||||
❌ | [WR2L](https://developer.tuya.com/en/docs/iot/wifiwr2lmodule?id=K9605tnbj7gva) | RTL8710BX @ 62.5 MHz | 2 MiB | 256 KiB | 7 (5 I/O) | ✔️ | ❌ | -
|
||||
❌ | [WR2LE](https://developer.tuya.com/en/docs/iot/wr2le?id=K9eio9y9e8i8c) | RTL8710BX @ 62.5 MHz | 2 MiB | 256 KiB | 7 (5 I/O) | ✔️ | ❌ | -
|
||||
[`wr3`](boards/wr3/README.md) | [WR3](https://developer.tuya.com/en/docs/iot/wr3-module-datasheet?id=K9g3ainzbj9z1) | RTL8710BN @ 125 MHz | 2 MiB | 256 KiB | 16 (12 I/O) | ✔️ | ❌ | `realtek-ambz`
|
||||
❌ | [WR3E](https://developer.tuya.com/en/docs/iot/wr3e-module-datasheet?id=K9elwlqbfosbc) | RTL8710BN @ 125 MHz | 2 MiB | 256 KiB | 16 (12 I/O) | ✔️ | ❌ | -
|
||||
❌ | [WR3L](https://developer.tuya.com/en/docs/iot/wifiwr3lmodule?id=K9605tt0kveqm) | RTL8710BX @ 125 MHz (?) | 2 MiB | 256 KiB | 16 (12 I/O) | ✔️ | ❌ | -
|
||||
❌ | [WR3LE](https://developer.tuya.com/en/docs/iot/wr3le?id=K986l7a1ha8tm) | RTL8710BX @ 62.5 MHz | 2 MiB | 256 KiB | 16 (12 I/O) | ✔️ | ❌ | -
|
||||
❌ | [WR3N](https://developer.tuya.com/en/docs/iot/wr3n-datasheet?id=K98zdx31ztdge) | RTL8710BN @ 125 MHz | 2 MiB | 256 KiB | 16 (10 I/O) | ✔️ | ❌ | -
|
||||
❌ | [WR4](https://developer.tuya.com/en/docs/iot/wifiwr4module?id=K9605tvu78p3e) | RTL8710BN @ 125 MHz | 1 MiB | 256 KiB | 16 (12 I/O) | ✔️ | ❌ | -
|
||||
❌ | [WR5E](https://developer.tuya.com/en/docs/iot/wr5e?id=K986r9pxqxa8i) | RTL8710BX @ 62.5 MHz | 2 MiB | 256 KiB | 15 (12 I/O) | ✔️ | ❌ | -
|
||||
❌ | [WR6-H](https://developer.tuya.com/en/docs/iot/wr6h-module-datasheet?id=K9pork8eeowgl) | RTL8710BN @ 125 MHz | 2 MiB | 256 KiB | 18 (12 I/O) | ✔️ | ❌ | -
|
||||
❌ | [WR6](https://developer.tuya.com/en/docs/iot/wr6-datasheet?id=K97rp45u6gff9) | RTL8710BN @ 125 MHz | 2 MiB | 256 KiB | 18 (12 I/O) | ✔️ | ❌ | -
|
||||
❌ | [WRG1](https://developer.tuya.com/en/docs/iot/wr6-datasheet?id=K97rp45u6gff9) | RTL8711AM @ 166 MHz | 4 MiB | 2048 KiB | 25 (20 I/O) | ✔️ | ❌ | -
|
||||
❌ | [XR1](https://developer.tuya.com/en/docs/iot/xr1?id=K9lq3y9xo0zkx) | XR809 @ 160 MHz | 2 MiB | 384 KiB | 18 (11 I/O) | ✔️ | ❌ | -
|
||||
❌ | [XR1-IPEX](https://developer.tuya.com/en/docs/iot/xr1ipex-module-datasheet?id=K9razqu9gqele) | XR809 @ 160 MHz | 2 MiB | 384 KiB | 18 (11 I/O) | ✔️ | ❌ | -
|
||||
❌ | [XR3](https://developer.tuya.com/en/docs/iot/xr3-datasheet?id=K98s9168qi49g) | XR809 @ 160 MHz | 2 MiB | 384 KiB | 22 (17 I/O) | ✔️ | ❌ | -
|
||||
❌ | [WE1S](https://developer.tuya.com/en/docs/iot/wifie1smodule?id=K9605thnvg3e7) | ESP8266EX @ 80/160 MHz | 2 MiB | 36 KiB | 18 (11 I/O) | ✔️ | ❌ | -
|
||||
❌ | [WE2L](https://developer.tuya.com/en/docs/iot/wifie2lmodule?id=K9605ud0gkjmh) | ESP8285 @ 80/160 MHz | 1 MiB | 50 KiB | 7 (5 I/O) | ✔️ | ❌ | -
|
||||
❌ | [WE2S](https://developer.tuya.com/en/docs/iot/wifie2smodule?id=K9605u79tgxug) | ESP8285 @ 80/160 MHz | 1 MiB | 50 KiB | 11 (8 I/O) | ✔️ | ❌ | -
|
||||
❌ | [WE3L](https://developer.tuya.com/en/docs/iot/wifie3lpinmodule?id=K9605uj1ar87n) | ESP8266 @ 80/160 MHz | 2 MiB | 50 KiB | 16 (12 I/O) | ✔️ | ❌ | -
|
||||
❌ | [WE3S](https://developer.tuya.com/en/docs/iot/wifie3smodule?id=K9605ua1cx9tv) | ESP8266 @ 80/160 MHz | 2 MiB | 50 KiB | 16 (12 I/O) | ✔️ | ❌ | -
|
||||
❌ | [WE3SE](https://developer.tuya.com/en/docs/iot/we3se?id=K97qv6ab7oh8d) | ESP32 @ 240 MHz | 4 MiB | 520 KiB | 22 (17 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [WE5P](https://developer.tuya.com/en/docs/iot/wifie5pmodule?id=K9605um3dtjbx) | ESP8266 @ 80/160 MHz | 1 MiB | 50 KiB | 15 (11 I/O) | ✔️ | ❌ | -
|
||||
|
||||
\* Only modules featuring at least Wi-Fi. WBR, JWBR, CR, (TY)JW and (TY)LC Series are not included here
|
||||
|
||||
** I/O count includes GPIOs, ADCs, PWM outputs and UART, but doesn't count CEN/RST and power pins.
|
||||
|
||||
## Project structure
|
||||
|
||||
```
|
||||
arduino/
|
||||
├─ <platform name>/ Arduino Core for specific SoC
|
||||
│ ├─ cores/ Wiring core files
|
||||
│ ├─ libraries/ Supported built-in platform libraries
|
||||
├─ libretuya/
|
||||
│ ├─ api/ LibreTuya API (interfaces + LT class) for Arduino frameworks
|
||||
│ ├─ common/ Units common to all platforms
|
||||
│ ├─ compat/ Fixes for compatibility with ESP32 framework
|
||||
│ ├─ libraries/ Built-in platform-independent libraries
|
||||
boards/
|
||||
├─ <board name>/ Board-specific code
|
||||
│ ├─ variant.cpp Arduino variant initialization
|
||||
│ ├─ variant.h Arduino variant pin configs
|
||||
├─ <board name>.json PlatformIO board description
|
||||
builder/
|
||||
├─ frameworks/ Framework builders for PlatformIO
|
||||
│ ├─ <platform name>-sdk.py Vanilla SDK build system
|
||||
│ ├─ <platform name>-arduino.py Arduino Core build system
|
||||
├─ arduino-common.py Builder to provide ArduinoCore-API and LibreTuya APIs
|
||||
├─ main.py Main PlatformIO builder
|
||||
├─ utils.py SCons utils used during the build
|
||||
docs/ Project documentation, guides, tips, etc.
|
||||
platform/
|
||||
├─ <platform name>/ Platform-specific configurations
|
||||
│ ├─ bin/ Binary blobs (bootloaders, etc.)
|
||||
│ ├─ fixups/ Code fix-ups to replace SDK parts
|
||||
│ ├─ ld/ Linker scripts
|
||||
│ ├─ openocd/ OpenOCD configuration files
|
||||
tools/
|
||||
├─ <tool name>/ Tools used during the build
|
||||
platform.json PlatformIO manifest
|
||||
platform.py Custom PlatformIO script
|
||||
```
|
||||
|
||||
## Platforms
|
||||
|
||||
A list of platforms currently available in this project.
|
||||
|
||||
Platform name | Supported MCU(s) | Arduino Core | Source SDK (PIO framework)
|
||||
---------------|------------------------------------------------------------------------|--------------|--------------------------------------------------------------------------
|
||||
`realtek-ambz` | Realtek [AmebaZ](https://www.amebaiot.com/en/amebaz/) SoC (`RTL87xxB`) | ✔️ | `framework-realtek-amb1` ([amb1_sdk](https://github.com/ambiot/amb1_sdk))
|
||||
|
||||
### Realtek Ameba
|
||||
|
||||
The logic behind naming of Realtek chips and their series took me some time to figure out:
|
||||
|
||||
- RTL8xxxA - Ameba1/Ameba Series
|
||||
- RTL8xxxB - AmebaZ Series
|
||||
- RTL8xxxC - AmebaZ2/ZII Series
|
||||
- RTL8xxxD - AmebaD Series
|
||||
|
||||
As such, there are numerous CPUs with the same numbers but different series, which makes them require different code and SDKs.
|
||||
|
||||
- [RTL8195AM](https://www.realtek.com/en/products/communications-network-ics/item/rtl8195am)
|
||||
- RTL8710AF (found in amb1_arduino)
|
||||
- [RTL8711AM](https://www.realtek.com/en/products/communications-network-ics/item/rtl8711am)
|
||||
- [RTL8710BN](https://www.realtek.com/en/products/communications-network-ics/item/rtl8710bn)
|
||||
- RTL8710BX (found in Tuya product pages)
|
||||
- RTL8710B? (found in amb1_sdk)
|
||||
- RTL8711B? (found in amb1_sdk)
|
||||
- [RTL8710CM](https://www.realtek.com/en/products/communications-network-ics/item/rtl8710cm)
|
||||
- RTL8722CSM (found in ambd_arduino)
|
||||
- RTL8720DN (found in ambd_arduino)
|
||||
- [RTL8721DM](https://www.realtek.com/en/products/communications-network-ics/item/rtl8721dm)
|
||||
- RTL8722DM (found in ambd_arduino)
|
||||
- and probably many more
|
||||
|
||||
Different Ameba series are not compatible with each other. Apparently, there isn't an official public SDK for AmebaZ that can support C++ properly.
|
||||
See [Boards & CPU list](https://kuba2k2.github.io/libretuya/docs/supported/).
|
||||
|
||||
## Arduino Core support status
|
||||
|
||||
Note: this list will probably change with each functionality update.
|
||||
|
||||
| `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 | ❌
|
||||
| `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
53
SUMMARY.md
Normal 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)
|
||||
32
arduino/beken-72xx/cores/arduino/Arduino.h
Normal file
32
arduino/beken-72xx/cores/arduino/Arduino.h
Normal 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
|
||||
130
arduino/beken-72xx/cores/arduino/LibreTuyaAPI.cpp
Normal file
130
arduino/beken-72xx/cores/arduino/LibreTuyaAPI.cpp
Normal 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;
|
||||
75
arduino/beken-72xx/cores/arduino/SerialClass.cpp
Normal file
75
arduino/beken-72xx/cores/arduino/SerialClass.cpp
Normal 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;
|
||||
}
|
||||
38
arduino/beken-72xx/cores/arduino/SerialClass.h
Normal file
38
arduino/beken-72xx/cores/arduino/SerialClass.h
Normal 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
|
||||
21
arduino/beken-72xx/cores/arduino/WVariant.h
Normal file
21
arduino/beken-72xx/cores/arduino/WVariant.h
Normal 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
|
||||
25
arduino/beken-72xx/cores/arduino/main.cpp
Normal file
25
arduino/beken-72xx/cores/arduino/main.cpp
Normal 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;
|
||||
}
|
||||
30
arduino/beken-72xx/cores/arduino/sdk_extern.h
Normal file
30
arduino/beken-72xx/cores/arduino/sdk_extern.h
Normal 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
|
||||
20
arduino/beken-72xx/cores/arduino/sdk_mem.h
Normal file
20
arduino/beken-72xx/cores/arduino/sdk_mem.h
Normal 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
|
||||
32
arduino/beken-72xx/cores/arduino/wiring.c
Normal file
32
arduino/beken-72xx/cores/arduino/wiring.c
Normal 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();
|
||||
}
|
||||
113
arduino/beken-72xx/cores/arduino/wiring_analog.c
Normal file
113
arduino/beken-72xx/cores/arduino/wiring_analog.c
Normal 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);
|
||||
}
|
||||
}
|
||||
62
arduino/beken-72xx/cores/arduino/wiring_digital.c
Normal file
62
arduino/beken-72xx/cores/arduino/wiring_digital.c
Normal 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);
|
||||
}
|
||||
56
arduino/beken-72xx/libraries/WiFi/WiFi.cpp
Normal file
56
arduino/beken-72xx/libraries/WiFi/WiFi.cpp
Normal 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;
|
||||
}
|
||||
10
arduino/beken-72xx/libraries/WiFi/WiFi.h
Normal file
10
arduino/beken-72xx/libraries/WiFi/WiFi.h
Normal 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"
|
||||
8
arduino/beken-72xx/libraries/WiFi/WiFiClient.h
Normal file
8
arduino/beken-72xx/libraries/WiFi/WiFiClient.h
Normal 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;
|
||||
8
arduino/beken-72xx/libraries/WiFi/WiFiClientSecure.h
Normal file
8
arduino/beken-72xx/libraries/WiFi/WiFiClientSecure.h
Normal 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;
|
||||
23
arduino/beken-72xx/libraries/WiFi/WiFiData.h
Normal file
23
arduino/beken-72xx/libraries/WiFi/WiFiData.h
Normal 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;
|
||||
71
arduino/beken-72xx/libraries/WiFi/WiFiGeneric.cpp
Normal file
71
arduino/beken-72xx/libraries/WiFi/WiFiGeneric.cpp
Normal 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();
|
||||
}
|
||||
57
arduino/beken-72xx/libraries/WiFi/WiFiPriv.h
Normal file
57
arduino/beken-72xx/libraries/WiFi/WiFiPriv.h
Normal 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"
|
||||
219
arduino/beken-72xx/libraries/WiFi/WiFiSTA.cpp
Normal file
219
arduino/beken-72xx/libraries/WiFi/WiFiSTA.cpp
Normal 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);
|
||||
}
|
||||
73
arduino/beken-72xx/libraries/WiFi/WiFiScan.cpp
Normal file
73
arduino/beken-72xx/libraries/WiFi/WiFiScan.cpp
Normal 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;
|
||||
}
|
||||
8
arduino/beken-72xx/libraries/WiFi/WiFiServer.h
Normal file
8
arduino/beken-72xx/libraries/WiFi/WiFiServer.h
Normal 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;
|
||||
45
arduino/beken-72xx/port/flashdb/fal_flash_bk72xx_port.c
Normal file
45
arduino/beken-72xx/port/flashdb/fal_flash_bk72xx_port.c
Normal 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,
|
||||
};
|
||||
17
arduino/beken-72xx/port/printf/printf.c
Normal file
17
arduino/beken-72xx/port/printf/printf.c
Normal 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);
|
||||
7
arduino/beken-72xx/port/printf/printf_port.h
Normal file
7
arduino/beken-72xx/port/printf/printf_port.h
Normal file
@@ -0,0 +1,7 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-06-20. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <printf_config.h>
|
||||
|
||||
WRAP_DISABLE_DEF(bk_printf);
|
||||
@@ -1,2 +0,0 @@
|
||||
realtek-ambz Realtek AmebaZ Arduino Core
|
||||
libretuya Interfaces for LibreTuya Arduino cores
|
||||
5
arduino/libretuya/api/Events.cpp
Normal file
5
arduino/libretuya/api/Events.cpp
Normal file
@@ -0,0 +1,5 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-17. */
|
||||
|
||||
#include "Events.h"
|
||||
|
||||
uint16_t EventHandler_s::lastId = 1;
|
||||
117
arduino/libretuya/api/Events.h
Normal file
117
arduino/libretuya/api/Events.h
Normal 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;
|
||||
@@ -1,27 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-04-24. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct {
|
||||
uint8_t manufacturerId;
|
||||
uint8_t chipId;
|
||||
uint8_t chipSizeId;
|
||||
} FlashId;
|
||||
|
||||
class IFlashClass {
|
||||
public:
|
||||
IFlashClass() {}
|
||||
|
||||
~IFlashClass() {}
|
||||
|
||||
virtual FlashId getChipId() = 0;
|
||||
virtual uint32_t getSize() = 0;
|
||||
|
||||
virtual bool eraseSector(uint32_t sector) = 0;
|
||||
virtual bool readBlock(uint32_t offset, uint8_t *data, size_t size) = 0;
|
||||
virtual bool writeBlock(uint32_t offset, uint8_t *data, size_t size) = 0;
|
||||
};
|
||||
@@ -1,17 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-04-29. */
|
||||
|
||||
#include "LibreTuyaAPI.h"
|
||||
|
||||
__weak char *strdup(const char *s) {
|
||||
size_t len = strlen(s) + 1;
|
||||
void *newp = malloc(len);
|
||||
if (newp == NULL)
|
||||
return NULL;
|
||||
return (char *)memcpy(newp, s, len);
|
||||
}
|
||||
|
||||
String ipToString(const IPAddress &ip) {
|
||||
char szRet[16];
|
||||
sprintf(szRet, "%hhu.%hhu.%hhu.%hhu", ip[0], ip[1], ip[2], ip[3]);
|
||||
return String(szRet);
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "api/String.h"
|
||||
#include <api/String.h>
|
||||
|
||||
typedef enum {
|
||||
PT_I8,
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
46
arduino/libretuya/api/WiFi/WiFi.cpp
Normal file
46
arduino/libretuya/api/WiFi/WiFi.cpp
Normal 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;
|
||||
194
arduino/libretuya/api/WiFi/WiFi.h
Normal file
194
arduino/libretuya/api/WiFi/WiFi.h
Normal 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;
|
||||
23
arduino/libretuya/api/WiFi/WiFiAP.cpp
Normal file
23
arduino/libretuya/api/WiFi/WiFiAP.cpp
Normal 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();
|
||||
}
|
||||
84
arduino/libretuya/api/WiFi/WiFiEvents.cpp
Normal file
84
arduino/libretuya/api/WiFi/WiFiEvents.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
173
arduino/libretuya/api/WiFi/WiFiEvents.h
Normal file
173
arduino/libretuya/api/WiFi/WiFiEvents.h
Normal 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;
|
||||
93
arduino/libretuya/api/WiFi/WiFiGeneric.cpp
Normal file
93
arduino/libretuya/api/WiFi/WiFiGeneric.cpp
Normal 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;
|
||||
}
|
||||
48
arduino/libretuya/api/WiFi/WiFiSTA.cpp
Normal file
48
arduino/libretuya/api/WiFi/WiFiSTA.cpp
Normal 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();
|
||||
}
|
||||
83
arduino/libretuya/api/WiFi/WiFiScan.cpp
Normal file
83
arduino/libretuya/api/WiFi/WiFiScan.cpp
Normal 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;
|
||||
}
|
||||
149
arduino/libretuya/api/WiFi/WiFiType.h
Normal file
149
arduino/libretuya/api/WiFi/WiFiType.h
Normal 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;
|
||||
@@ -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;
|
||||
66
arduino/libretuya/api/Wire.h
Normal file
66
arduino/libretuya/api/Wire.h
Normal 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;
|
||||
}
|
||||
};
|
||||
53
arduino/libretuya/common/main.cpp
Normal file
53
arduino/libretuya/common/main.cpp
Normal 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;
|
||||
}
|
||||
11
arduino/libretuya/common/serial_event.cpp
Normal file
11
arduino/libretuya/common/serial_event.cpp
Normal 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();
|
||||
}
|
||||
6
arduino/libretuya/compat/md5.h
Normal file
6
arduino/libretuya/compat/md5.h
Normal 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>
|
||||
29
arduino/libretuya/core/ChipType.h
Normal file
29
arduino/libretuya/core/ChipType.h
Normal 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
|
||||
};
|
||||
63
arduino/libretuya/core/LibreTuyaAPI.cpp
Normal file
63
arduino/libretuya/core/LibreTuyaAPI.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,11 @@
|
||||
|
||||
#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
|
||||
@@ -15,7 +20,10 @@
|
||||
#define LT_BOARD_STR STRINGIFY_MACRO(LT_BOARD)
|
||||
|
||||
// Includes
|
||||
#include "LibreTuyaConfig.h"
|
||||
#include "LibreTuyaClass.h" // global LT class
|
||||
#include "LibreTuyaCompat.h" // compatibility methods
|
||||
#include "LibreTuyaConfig.h" // configuration macros
|
||||
#include "LibreTuyaCustom.h" // family-defined methods (Wiring custom)
|
||||
#include <Arduino.h>
|
||||
|
||||
// C includes
|
||||
@@ -24,6 +32,7 @@ extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#include "lt_logger.h"
|
||||
#include "lt_posix_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
@@ -38,14 +47,11 @@ extern "C" {
|
||||
"LibreTuya v" LT_VERSION_STR " on " LT_BOARD_STR ", compiled at " __DATE__ " " __TIME__ \
|
||||
)
|
||||
|
||||
// ArduinoCore-API doesn't define these anymore
|
||||
#define FPSTR(pstr_pointer) (reinterpret_cast<const __FlashStringHelper *>(pstr_pointer))
|
||||
#define PGM_VOID_P const void *
|
||||
void lt_rand_bytes(uint8_t *buf, size_t len);
|
||||
|
||||
// C functions
|
||||
extern char *strdup(const char *);
|
||||
|
||||
// C++ only functions
|
||||
#ifdef __cplusplus
|
||||
String ipToString(const IPAddress &ip);
|
||||
void hexdump(uint8_t *buf, size_t len, uint32_t offset = 0, uint8_t width = 16);
|
||||
#else
|
||||
void hexdump(uint8_t *buf, size_t len, uint32_t offset, uint8_t width);
|
||||
#endif
|
||||
132
arduino/libretuya/core/LibreTuyaClass.cpp
Normal file
132
arduino/libretuya/core/LibreTuyaClass.cpp
Normal 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
|
||||
}
|
||||
142
arduino/libretuya/core/LibreTuyaClass.h
Normal file
142
arduino/libretuya/core/LibreTuyaClass.h
Normal 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
|
||||
33
arduino/libretuya/core/LibreTuyaCompat.cpp
Normal file
33
arduino/libretuya/core/LibreTuyaCompat.cpp
Normal 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
|
||||
42
arduino/libretuya/core/LibreTuyaCompat.h
Normal file
42
arduino/libretuya/core/LibreTuyaCompat.h
Normal 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
|
||||
@@ -44,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
|
||||
103
arduino/libretuya/core/LibreTuyaCustom.c
Normal file
103
arduino/libretuya/core/LibreTuyaCustom.c
Normal 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) {}
|
||||
87
arduino/libretuya/core/LibreTuyaCustom.h
Normal file
87
arduino/libretuya/core/LibreTuyaCustom.h
Normal 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
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#if LT_LOGGER_TASK
|
||||
#if LT_LOGGER_TASK && LT_HAS_FREERTOS
|
||||
#include <FreeRTOS.h>
|
||||
#include <task.h>
|
||||
#endif
|
||||
@@ -57,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);
|
||||
@@ -90,16 +90,15 @@ void lt_log(const uint8_t level, const char *format, ...) {
|
||||
#if LT_LOGGER_CALLER
|
||||
"%s():%hu: "
|
||||
#endif
|
||||
#if LT_LOGGER_TASK
|
||||
#if LT_LOGGER_TASK && LT_HAS_FREERTOS
|
||||
"%s%c "
|
||||
#endif
|
||||
,
|
||||
levels[level]
|
||||
#if LT_LOGGER_COLOR
|
||||
,
|
||||
c_bright, // whether text is bright
|
||||
c_value // text color
|
||||
c_value, // text color
|
||||
#endif
|
||||
levels[level]
|
||||
#if LT_LOGGER_TIMESTAMP
|
||||
,
|
||||
seconds // float
|
||||
@@ -113,7 +112,7 @@ void lt_log(const uint8_t level, const char *format, ...) {
|
||||
caller,
|
||||
line
|
||||
#endif
|
||||
#if LT_LOGGER_TASK
|
||||
#if LT_LOGGER_TASK && LT_HAS_FREERTOS
|
||||
,
|
||||
task_name,
|
||||
task_colon // printing outside of tasks
|
||||
@@ -51,6 +51,12 @@ void lt_log(const uint8_t level, const char *format, ...);
|
||||
#define LT_F(...)
|
||||
#endif
|
||||
|
||||
#if LT_LOG_HEAP
|
||||
#define LT_HEAP_I() LT_I("Free heap: %u", LT_HEAP_FUNC());
|
||||
#else
|
||||
#define LT_HEAP_I()
|
||||
#endif
|
||||
|
||||
// ESP32 compat
|
||||
#define log_printf(...) LT_I(__VA_ARGS__)
|
||||
#define log_v(...) LT_V(__VA_ARGS__)
|
||||
@@ -75,6 +81,8 @@ void lt_log(const uint8_t level, const char *format, ...);
|
||||
#define ESP_EARLY_LOGI(...) LT_I(__VA_ARGS__)
|
||||
#define ESP_EARLY_LOGW(...) LT_W(__VA_ARGS__)
|
||||
#define ESP_EARLY_LOGE(...) LT_E(__VA_ARGS__)
|
||||
#define ets_printf(...) LT_I(__VA_ARGS__)
|
||||
#define ETS_PRINTF(...) LT_I(__VA_ARGS__)
|
||||
|
||||
#define LT_T_MOD(module, ...) \
|
||||
do { \
|
||||
@@ -126,6 +134,16 @@ void lt_log(const uint8_t level, const char *format, ...);
|
||||
return ret; \
|
||||
}
|
||||
|
||||
#if LT_LOG_ERRNO
|
||||
#define LT_ERRNO() \
|
||||
if (errno) { \
|
||||
LT_E("errno=%d", errno); \
|
||||
errno = 0; \
|
||||
}
|
||||
#else
|
||||
#define LT_ERRNO()
|
||||
#endif
|
||||
|
||||
// WiFi.cpp
|
||||
#define LT_T_WG(...) LT_T_MOD(LT_DEBUG_WIFI, __VA_ARGS__)
|
||||
#define LT_V_WG(...) LT_T_MOD(LT_DEBUG_WIFI, __VA_ARGS__)
|
||||
30
arduino/libretuya/libraries/Flash/Flash.cpp
Normal file
30
arduino/libretuya/libraries/Flash/Flash.cpp
Normal 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;
|
||||
}
|
||||
@@ -2,20 +2,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "api/Flash.h"
|
||||
|
||||
struct flash_s;
|
||||
typedef struct flash_s flash_t;
|
||||
|
||||
class FlashClass : public IFlashClass {
|
||||
private:
|
||||
flash_t *flash;
|
||||
void initialize();
|
||||
#include <Arduino.h>
|
||||
|
||||
class FlashClass {
|
||||
public:
|
||||
FlashClass();
|
||||
~FlashClass();
|
||||
|
||||
FlashId getChipId();
|
||||
uint32_t getSize();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <WiFiClient.h>
|
||||
// #include <WiFiClientSecure.h>
|
||||
#include <WiFiClientSecure.h>
|
||||
#include <memory>
|
||||
|
||||
/// Cookie jar support
|
||||
|
||||
31
arduino/libretuya/libraries/MD5/MD5.h
Normal file
31
arduino/libretuya/libraries/MD5/MD5.h
Normal 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
|
||||
28
arduino/libretuya/libraries/MD5/MD5PolarSSLImpl.cpp
Normal file
28
arduino/libretuya/libraries/MD5/MD5PolarSSLImpl.cpp
Normal 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
|
||||
14
arduino/libretuya/libraries/MD5/MD5PolarSSLImpl.h
Normal file
14
arduino/libretuya/libraries/MD5/MD5PolarSSLImpl.h
Normal 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
|
||||
@@ -1,7 +1,29 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-04-26. */
|
||||
|
||||
#include "WiFiClient.h"
|
||||
#include "WiFiPriv.h"
|
||||
#if LT_ARD_HAS_WIFI && LT_HAS_LWIP
|
||||
|
||||
#include "LwIPClient.h"
|
||||
|
||||
#define MAX_SOCK_NUM 4
|
||||
#define WIFI_CLIENT_CONNECT_TIMEOUT 3000
|
||||
#define WIFI_CLIENT_READ_TIMEOUT 3000
|
||||
#define WIFI_CLIENT_WRITE_RETRY 10
|
||||
#define WIFI_CLIENT_SELECT_TIMEOUT 1000
|
||||
#define WIFI_CLIENT_FLUSH_BUF_SIZE 1024
|
||||
|
||||
// disable #defines removing lwip_ prefix
|
||||
#undef LWIP_COMPAT_SOCKETS
|
||||
#define LWIP_COMPAT_SOCKETS 0
|
||||
|
||||
extern "C" {
|
||||
|
||||
#include <lwip/api.h>
|
||||
#include <lwip/dns.h>
|
||||
#include <lwip/err.h>
|
||||
#include <lwip/sockets.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
} // extern "C"
|
||||
|
||||
class SocketHandle {
|
||||
public:
|
||||
@@ -14,28 +36,28 @@ class SocketHandle {
|
||||
}
|
||||
};
|
||||
|
||||
WiFiClient::WiFiClient() {
|
||||
LT_V_WC("WiFiClient()");
|
||||
LwIPClient::LwIPClient() {
|
||||
LT_V_WC("LwIPClient()");
|
||||
_connected = false;
|
||||
_sock = NULL;
|
||||
_rxBuffer = NULL;
|
||||
_timeout = WIFI_CLIENT_CONNECT_TIMEOUT;
|
||||
}
|
||||
|
||||
WiFiClient::WiFiClient(int sock) {
|
||||
LT_V_WC("WiFiClient(%d)", sock);
|
||||
LwIPClient::LwIPClient(int sock) {
|
||||
LT_V_WC("LwIPClient(%d)", sock);
|
||||
_connected = true;
|
||||
_sock = std::make_shared<SocketHandle>(sock);
|
||||
_rxBuffer = std::make_shared<LwIPRxBuffer>(sock);
|
||||
_timeout = WIFI_CLIENT_CONNECT_TIMEOUT;
|
||||
}
|
||||
|
||||
WiFiClient::~WiFiClient() {
|
||||
LT_V_WC("~WiFiClient()");
|
||||
LwIPClient::~LwIPClient() {
|
||||
LT_V_WC("~LwIPClient()");
|
||||
stop();
|
||||
}
|
||||
|
||||
WiFiClient &WiFiClient::operator=(const WiFiClient &other) {
|
||||
LwIPClient &LwIPClient::operator=(const LwIPClient &other) {
|
||||
stop();
|
||||
_connected = other._connected;
|
||||
_sock = other._sock;
|
||||
@@ -47,29 +69,37 @@ bool IWiFiClient::operator==(const IWiFiClient &other) const {
|
||||
return fd() == other.fd() && remoteIP() == other.remoteIP() && remotePort() == other.remotePort();
|
||||
}
|
||||
|
||||
int WiFiClient::connect(IPAddress ip, uint16_t port) {
|
||||
int LwIPClient::connect(IPAddress ip, uint16_t port) {
|
||||
return connect(ip, port, _timeout);
|
||||
}
|
||||
|
||||
int WiFiClient::connect(const char *host, uint16_t port) {
|
||||
int LwIPClient::connect(const char *host, uint16_t port) {
|
||||
return connect(host, port, _timeout);
|
||||
}
|
||||
|
||||
int WiFiClient::connect(const char *host, uint16_t port, int32_t timeout) {
|
||||
int LwIPClient::connect(const char *host, uint16_t port, int32_t timeout) {
|
||||
IPAddress ip = WiFi.hostByName(host);
|
||||
if (!ip)
|
||||
return 0;
|
||||
return connect(ip, port, timeout);
|
||||
}
|
||||
|
||||
int WiFiClient::connect(IPAddress ip, uint16_t port, int32_t timeout) {
|
||||
int LwIPClient::connect(IPAddress ip, uint16_t port, int32_t timeout) {
|
||||
if (_connected)
|
||||
stop();
|
||||
int sock = lwip_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (sock < 0) {
|
||||
LT_D_WC("socket failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (timeout <= 0)
|
||||
timeout = _timeout; // use default when -1 passed as timeout
|
||||
|
||||
lwip_fcntl(sock, F_SETFL, lwip_fcntl(sock, F_GETFL, 0) | O_NONBLOCK);
|
||||
|
||||
LT_ERRNO();
|
||||
|
||||
struct sockaddr_in addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
@@ -80,7 +110,7 @@ int WiFiClient::connect(IPAddress ip, uint16_t port, int32_t timeout) {
|
||||
FD_ZERO(&fdset);
|
||||
FD_SET(sock, &fdset);
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = timeout * 1000;
|
||||
tv.tv_usec = timeout * 1000; // millis -> micros
|
||||
|
||||
int res = lwip_connect(sock, (struct sockaddr *)&addr, sizeof(addr));
|
||||
if (res < 0 && errno != EINPROGRESS) {
|
||||
@@ -117,19 +147,23 @@ int WiFiClient::connect(IPAddress ip, uint16_t port, int32_t timeout) {
|
||||
lwip_setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &enable, sizeof(enable));
|
||||
lwip_setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable));
|
||||
|
||||
LT_ERRNO();
|
||||
|
||||
lwip_fcntl(sock, F_SETFL, lwip_fcntl(sock, F_GETFL, 0) & ~O_NONBLOCK);
|
||||
|
||||
LT_ERRNO();
|
||||
|
||||
_connected = true;
|
||||
_sock = std::make_shared<SocketHandle>(sock);
|
||||
_rxBuffer = std::make_shared<LwIPRxBuffer>(sock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t WiFiClient::write(uint8_t data) {
|
||||
size_t LwIPClient::write(uint8_t data) {
|
||||
return write(&data, 1);
|
||||
}
|
||||
|
||||
size_t WiFiClient::write(Stream &stream) {
|
||||
size_t LwIPClient::write(Stream &stream) {
|
||||
uint8_t *buf = (uint8_t *)malloc(1360);
|
||||
if (!buf) {
|
||||
return 0;
|
||||
@@ -146,7 +180,7 @@ size_t WiFiClient::write(Stream &stream) {
|
||||
return written;
|
||||
}
|
||||
|
||||
size_t WiFiClient::write(const uint8_t *buf, size_t size) {
|
||||
size_t LwIPClient::write(const uint8_t *buf, size_t size) {
|
||||
if (_sock < 0 || !_connected || !size) {
|
||||
setWriteError();
|
||||
return 0;
|
||||
@@ -189,36 +223,38 @@ size_t WiFiClient::write(const uint8_t *buf, size_t size) {
|
||||
}
|
||||
}
|
||||
}
|
||||
LT_D_WC("wrote %d bytes", written);
|
||||
return written;
|
||||
}
|
||||
|
||||
int WiFiClient::available() {
|
||||
int LwIPClient::available() {
|
||||
if (!_connected || !_rxBuffer)
|
||||
return 0;
|
||||
int res = _rxBuffer->available();
|
||||
if (_rxBuffer->failed()) {
|
||||
LT_ERRNO();
|
||||
stop();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int WiFiClient::fd() const {
|
||||
int LwIPClient::fd() const {
|
||||
if (!_sock)
|
||||
return -1;
|
||||
return _sock->fd;
|
||||
}
|
||||
|
||||
int WiFiClient::socket() {
|
||||
int LwIPClient::socket() {
|
||||
return fd();
|
||||
}
|
||||
|
||||
int WiFiClient::setTimeout(uint32_t seconds) {
|
||||
int LwIPClient::setTimeout(uint32_t seconds) {
|
||||
Client::setTimeout(seconds * 1000);
|
||||
lwip_setsockopt(fd(), SOL_SOCKET, SO_RCVTIMEO, &_timeout, sizeof(_timeout));
|
||||
return lwip_setsockopt(fd(), SOL_SOCKET, SO_SNDTIMEO, &_timeout, sizeof(_timeout));
|
||||
}
|
||||
|
||||
int WiFiClient::read() {
|
||||
int LwIPClient::read() {
|
||||
uint8_t data;
|
||||
int res = read(&data, 1);
|
||||
if (res < 0)
|
||||
@@ -228,7 +264,7 @@ int WiFiClient::read() {
|
||||
return data;
|
||||
}
|
||||
|
||||
int WiFiClient::read(uint8_t *buf, size_t size) {
|
||||
int LwIPClient::read(uint8_t *buf, size_t size) {
|
||||
int res = -1;
|
||||
if (_rxBuffer) {
|
||||
res = _rxBuffer->read(buf, size);
|
||||
@@ -239,7 +275,7 @@ int WiFiClient::read(uint8_t *buf, size_t size) {
|
||||
return res;
|
||||
}
|
||||
|
||||
int WiFiClient::peek() {
|
||||
int LwIPClient::peek() {
|
||||
int res = -1;
|
||||
if (_rxBuffer) {
|
||||
res = _rxBuffer->peek();
|
||||
@@ -250,7 +286,7 @@ int WiFiClient::peek() {
|
||||
return res;
|
||||
}
|
||||
|
||||
void WiFiClient::flush() {
|
||||
void LwIPClient::flush() {
|
||||
int res;
|
||||
size_t len = available();
|
||||
if (!len)
|
||||
@@ -269,14 +305,14 @@ void WiFiClient::flush() {
|
||||
free(buf);
|
||||
}
|
||||
|
||||
void WiFiClient::stop() {
|
||||
LT_V_WC("stop()");
|
||||
void LwIPClient::stop() {
|
||||
LT_V_WC("Stopping TCP");
|
||||
_connected = false;
|
||||
_sock = NULL;
|
||||
_rxBuffer = NULL;
|
||||
}
|
||||
|
||||
uint8_t WiFiClient::connected() {
|
||||
uint8_t LwIPClient::connected() {
|
||||
if (_connected) {
|
||||
uint8_t dummy;
|
||||
if (lwip_recv(fd(), &dummy, 0, MSG_DONTWAIT) <= 0) {
|
||||
@@ -320,34 +356,36 @@ uint16_t __attribute__((noinline)) getport(int sock, int (*func)(int, struct soc
|
||||
return ntohs(s->sin_port);
|
||||
}
|
||||
|
||||
IPAddress WiFiClient::remoteIP() const {
|
||||
IPAddress LwIPClient::remoteIP() const {
|
||||
return getaddr(fd(), lwip_getpeername);
|
||||
}
|
||||
|
||||
IPAddress WiFiClient::remoteIP(int fd) const {
|
||||
IPAddress LwIPClient::remoteIP(int fd) const {
|
||||
return getaddr(fd, lwip_getpeername);
|
||||
}
|
||||
|
||||
uint16_t WiFiClient::remotePort() const {
|
||||
uint16_t LwIPClient::remotePort() const {
|
||||
return getport(fd(), lwip_getpeername);
|
||||
}
|
||||
|
||||
uint16_t WiFiClient::remotePort(int fd) const {
|
||||
uint16_t LwIPClient::remotePort(int fd) const {
|
||||
return getport(fd, lwip_getpeername);
|
||||
}
|
||||
|
||||
IPAddress WiFiClient::localIP() const {
|
||||
IPAddress LwIPClient::localIP() const {
|
||||
return getaddr(fd(), lwip_getsockname);
|
||||
}
|
||||
|
||||
IPAddress WiFiClient::localIP(int fd) const {
|
||||
IPAddress LwIPClient::localIP(int fd) const {
|
||||
return getaddr(fd, lwip_getsockname);
|
||||
}
|
||||
|
||||
uint16_t WiFiClient::localPort() const {
|
||||
uint16_t LwIPClient::localPort() const {
|
||||
return getport(fd(), lwip_getsockname);
|
||||
}
|
||||
|
||||
uint16_t WiFiClient::localPort(int fd) const {
|
||||
uint16_t LwIPClient::localPort(int fd) const {
|
||||
return getport(fd, lwip_getsockname);
|
||||
}
|
||||
|
||||
#endif
|
||||
56
arduino/libretuya/libraries/NetUtils/lwip/LwIPClient.h
Normal file
56
arduino/libretuya/libraries/NetUtils/lwip/LwIPClient.h
Normal 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;
|
||||
};
|
||||
@@ -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;
|
||||
@@ -1,17 +1,30 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-04-26. */
|
||||
|
||||
#include "WiFiServer.h"
|
||||
#include "WiFiPriv.h"
|
||||
#if LT_ARD_HAS_WIFI && LT_HAS_LWIP
|
||||
|
||||
WiFiServer::WiFiServer(uint32_t addr, uint16_t port, uint8_t maxClients)
|
||||
#include "LwIPServer.h"
|
||||
|
||||
// disable #defines removing lwip_ prefix
|
||||
#undef LWIP_COMPAT_SOCKETS
|
||||
#define LWIP_COMPAT_SOCKETS 0
|
||||
|
||||
extern "C" {
|
||||
#include <lwip/api.h>
|
||||
// #include <lwip/dns.h>
|
||||
#include <lwip/err.h>
|
||||
#include <lwip/sockets.h>
|
||||
#include <sys/time.h>
|
||||
}
|
||||
|
||||
LwIPServer::LwIPServer(uint32_t addr, uint16_t port, uint8_t maxClients)
|
||||
: _sock(-1), _sockAccepted(-1), _addr(addr), _port(port), _maxClients(maxClients), _active(false), _noDelay(false) {
|
||||
}
|
||||
|
||||
WiFiServer::operator bool() {
|
||||
LwIPServer::operator bool() {
|
||||
return _active;
|
||||
}
|
||||
|
||||
bool WiFiServer::begin(uint16_t port, bool reuseAddr) {
|
||||
bool LwIPServer::begin(uint16_t port, bool reuseAddr) {
|
||||
if (_active)
|
||||
return true;
|
||||
if (port)
|
||||
@@ -50,7 +63,7 @@ bool WiFiServer::begin(uint16_t port, bool reuseAddr) {
|
||||
_sockAccepted = -1;
|
||||
}
|
||||
|
||||
void WiFiServer::end() {
|
||||
void LwIPServer::end() {
|
||||
if (_sock == -1)
|
||||
return;
|
||||
lwip_close(_sock);
|
||||
@@ -58,7 +71,7 @@ void WiFiServer::end() {
|
||||
_active = -1;
|
||||
}
|
||||
|
||||
WiFiClient WiFiServer::accept() {
|
||||
WiFiClient LwIPServer::accept() {
|
||||
if (!_active)
|
||||
return WiFiClient();
|
||||
|
||||
@@ -96,7 +109,7 @@ WiFiClient WiFiServer::accept() {
|
||||
return WiFiClient();
|
||||
}
|
||||
|
||||
int WiFiServer::setTimeout(uint32_t seconds) {
|
||||
int LwIPServer::setTimeout(uint32_t seconds) {
|
||||
struct timeval tv;
|
||||
tv.tv_sec = seconds;
|
||||
tv.tv_usec = 0;
|
||||
@@ -105,15 +118,15 @@ int WiFiServer::setTimeout(uint32_t seconds) {
|
||||
return lwip_setsockopt(_sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
|
||||
}
|
||||
|
||||
void WiFiServer::setNoDelay(bool noDelay) {
|
||||
void LwIPServer::setNoDelay(bool noDelay) {
|
||||
_noDelay = noDelay;
|
||||
}
|
||||
|
||||
bool WiFiServer::getNoDelay() {
|
||||
bool LwIPServer::getNoDelay() {
|
||||
return _noDelay;
|
||||
}
|
||||
|
||||
bool WiFiServer::hasClient() {
|
||||
bool LwIPServer::hasClient() {
|
||||
if (_sockAccepted >= 0) {
|
||||
return true;
|
||||
}
|
||||
@@ -125,3 +138,5 @@ bool WiFiServer::hasClient() {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
47
arduino/libretuya/libraries/NetUtils/lwip/LwIPServer.h
Normal file
47
arduino/libretuya/libraries/NetUtils/lwip/LwIPServer.h
Normal 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();
|
||||
};
|
||||
@@ -1,31 +1,33 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-04-30. */
|
||||
|
||||
#if LT_ARD_HAS_WIFI && LT_HAS_MBEDTLS
|
||||
|
||||
#include "MbedTLSClient.h"
|
||||
|
||||
#include <IPAddress.h>
|
||||
#include <WiFi.h>
|
||||
#include <WiFiClient.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#include <mbedtls/debug.h>
|
||||
#include <mbedtls/platform.h>
|
||||
#include <mbedtls/sha256.h>
|
||||
#include <mbedtls/ssl.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
MbedTLSClient::MbedTLSClient() : WiFiClient() {}
|
||||
MbedTLSClient::MbedTLSClient() : WiFiClient() {
|
||||
init(); // ensure the context is zero filled
|
||||
}
|
||||
|
||||
MbedTLSClient::MbedTLSClient(int sock) : WiFiClient(sock) {}
|
||||
MbedTLSClient::MbedTLSClient(int sock) : WiFiClient(sock) {
|
||||
init(); // ensure the context is zero filled
|
||||
}
|
||||
|
||||
MbedTLSClient::~MbedTLSClient() {
|
||||
LT_V_WC("~MbedTLSClient()");
|
||||
stop();
|
||||
}
|
||||
|
||||
void MbedTLSClient::stop() {
|
||||
WiFiClient::stop();
|
||||
LT_V_SSL("Closing SSL connection");
|
||||
LT_V_SSL("Stopping SSL");
|
||||
|
||||
if (_sslCfg.ca_chain) {
|
||||
mbedtls_x509_crt_free(&_caCert);
|
||||
@@ -36,6 +38,7 @@ void MbedTLSClient::stop() {
|
||||
}
|
||||
mbedtls_ssl_free(&_sslCtx);
|
||||
mbedtls_ssl_config_free(&_sslCfg);
|
||||
LT_HEAP_I();
|
||||
}
|
||||
|
||||
void MbedTLSClient::init() {
|
||||
@@ -46,73 +49,71 @@ void MbedTLSClient::init() {
|
||||
}
|
||||
|
||||
int MbedTLSClient::connect(IPAddress ip, uint16_t port, int32_t timeout) {
|
||||
return connect(ipToString(ip).c_str(), port, timeout) == 0;
|
||||
return connect(ipToString(ip).c_str(), port, timeout);
|
||||
}
|
||||
|
||||
int MbedTLSClient::connect(const char *host, uint16_t port, int32_t timeout) {
|
||||
if (_pskIdentStr && _pskStr)
|
||||
return connect(host, port, NULL, NULL, NULL, _pskIdentStr, _pskStr, _alpnProtocols) == 0;
|
||||
return connect(host, port, _caCertStr, _clientCertStr, _clientKeyStr, NULL, NULL, _alpnProtocols) == 0;
|
||||
return connect(host, port, timeout, NULL, NULL, NULL, _pskIdentStr, _pskStr) == 0;
|
||||
return connect(host, port, timeout, _caCertStr, _clientCertStr, _clientKeyStr, NULL, NULL) == 0;
|
||||
}
|
||||
|
||||
int MbedTLSClient::connect(
|
||||
IPAddress ip, uint16_t port, const char *rootCABuf, const char *clientCert, const char *clientKey
|
||||
) {
|
||||
return connect(ipToString(ip).c_str(), port, rootCABuf, clientCert, clientKey, NULL, NULL, _alpnProtocols) == 0;
|
||||
return connect(ipToString(ip).c_str(), port, 0, rootCABuf, clientCert, clientKey, NULL, NULL) == 0;
|
||||
}
|
||||
|
||||
int MbedTLSClient::connect(
|
||||
const char *host, uint16_t port, const char *rootCABuf, const char *clientCert, const char *clientKey
|
||||
) {
|
||||
return connect(host, port, rootCABuf, clientCert, clientKey, NULL, NULL, _alpnProtocols) == 0;
|
||||
return connect(host, port, 0, rootCABuf, clientCert, clientKey, NULL, NULL) == 0;
|
||||
}
|
||||
|
||||
int MbedTLSClient::connect(IPAddress ip, uint16_t port, const char *pskIdent, const char *psk) {
|
||||
return connect(ipToString(ip).c_str(), port, NULL, NULL, NULL, pskIdent, psk, _alpnProtocols) == 0;
|
||||
return connect(ipToString(ip).c_str(), port, 0, NULL, NULL, NULL, pskIdent, psk) == 0;
|
||||
}
|
||||
|
||||
int MbedTLSClient::connect(const char *host, uint16_t port, const char *pskIdent, const char *psk) {
|
||||
return connect(host, port, NULL, NULL, NULL, pskIdent, psk, _alpnProtocols) == 0;
|
||||
return connect(host, port, 0, NULL, NULL, NULL, pskIdent, psk) == 0;
|
||||
}
|
||||
|
||||
static int ssl_random(void *data, unsigned char *output, size_t len) {
|
||||
int *buf = (int *)output;
|
||||
size_t i;
|
||||
for (i = 0; len >= sizeof(int); len -= sizeof(int)) {
|
||||
buf[i++] = rand();
|
||||
}
|
||||
if (len) {
|
||||
int rem = rand();
|
||||
unsigned char *pRem = (unsigned char *)&rem;
|
||||
memcpy(output + i * sizeof(int), pRem, len);
|
||||
}
|
||||
lt_rand_bytes((uint8_t *)output, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void debug_cb(void *ctx, int level, const char *file, int line, const char *str) {
|
||||
LT_I("%04d: |%d| %s", line, level, str);
|
||||
// do not print the trailing \n
|
||||
uint16_t len = strlen(str);
|
||||
char *msg = (char *)str;
|
||||
msg[len - 1] = '\0';
|
||||
LT_I("%04d: |%d| %s", line, level, msg);
|
||||
}
|
||||
|
||||
int MbedTLSClient::connect(
|
||||
const char *host,
|
||||
uint16_t port,
|
||||
int32_t timeout,
|
||||
const char *rootCABuf,
|
||||
const char *clientCert,
|
||||
const char *clientKey,
|
||||
const char *pskIdent,
|
||||
const char *psk,
|
||||
const char **alpnProtocols
|
||||
const char *psk
|
||||
) {
|
||||
LT_D_SSL("Free heap before TLS: TODO");
|
||||
LT_HEAP_I();
|
||||
|
||||
if (!rootCABuf && !pskIdent && !psk && !_insecure && !_useRootCA)
|
||||
return -1;
|
||||
|
||||
if (timeout <= 0)
|
||||
timeout = _timeout; // use default when -1 passed as timeout
|
||||
|
||||
IPAddress addr = WiFi.hostByName(host);
|
||||
if (!(uint32_t)addr)
|
||||
return -1;
|
||||
|
||||
int ret = WiFiClient::connect(addr, port, _timeout);
|
||||
int ret = WiFiClient::connect(addr, port, timeout);
|
||||
if (ret < 0) {
|
||||
LT_E("SSL socket failed");
|
||||
return ret;
|
||||
@@ -122,6 +123,7 @@ int MbedTLSClient::connect(
|
||||
|
||||
LT_V_SSL("Init SSL");
|
||||
init();
|
||||
LT_HEAP_I();
|
||||
|
||||
// mbedtls_debug_set_threshold(4);
|
||||
// mbedtls_ssl_conf_dbg(&_sslCfg, debug_cb, NULL);
|
||||
@@ -135,8 +137,8 @@ int MbedTLSClient::connect(
|
||||
LT_RET_NZ(ret);
|
||||
|
||||
#ifdef MBEDTLS_SSL_ALPN
|
||||
if (alpnProtocols) {
|
||||
ret = mbedtls_ssl_conf_alpn_protocols(&_sslCfg, alpnProtocols);
|
||||
if (_alpnProtocols) {
|
||||
ret = mbedtls_ssl_conf_alpn_protocols(&_sslCfg, _alpnProtocols);
|
||||
LT_RET_NZ(ret);
|
||||
}
|
||||
#endif
|
||||
@@ -208,10 +210,13 @@ int MbedTLSClient::connect(
|
||||
|
||||
_sockTls = fd();
|
||||
mbedtls_ssl_set_bio(&_sslCtx, &_sockTls, mbedtls_net_send, mbedtls_net_recv, NULL);
|
||||
mbedtls_net_set_nonblock((mbedtls_net_context *)&_sockTls);
|
||||
|
||||
LT_HEAP_I();
|
||||
|
||||
LT_V_SSL("SSL handshake");
|
||||
if (_handshakeTimeout == 0)
|
||||
_handshakeTimeout = _timeout * 1000;
|
||||
_handshakeTimeout = timeout;
|
||||
unsigned long start = millis();
|
||||
while (ret = mbedtls_ssl_handshake(&_sslCtx)) {
|
||||
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
|
||||
@@ -224,6 +229,8 @@ int MbedTLSClient::connect(
|
||||
delay(2);
|
||||
}
|
||||
|
||||
LT_HEAP_I();
|
||||
|
||||
if (clientCert && clientKey) {
|
||||
LT_D_SSL(
|
||||
"Protocol %s, ciphersuite %s",
|
||||
@@ -441,3 +448,5 @@ bool MbedTLSClient::getFingerprintSHA256(uint8_t result[32]) {
|
||||
mbedtls_sha256_finish(&shaCtx, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // LT_ARD_HAS_WIFI && LT_HAS_MBEDTLS
|
||||
|
||||
@@ -2,20 +2,17 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <api/WiFi/WiFi.h>
|
||||
#include <api/WiFiClient.h>
|
||||
#include <api/WiFiClientSecure.h>
|
||||
|
||||
#include <WiFiClient.h> // extend platform's WiFiClient impl
|
||||
#include <WiFiClient.h> // extend family's WiFiClient impl
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#include <mbedtls/net.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
class MbedTLSClient : public WiFiClient, public IWiFiClientSecure {
|
||||
private:
|
||||
@@ -42,17 +39,18 @@ class MbedTLSClient : public WiFiClient, public IWiFiClientSecure {
|
||||
int connect(
|
||||
const char *host,
|
||||
uint16_t port,
|
||||
int32_t timeout,
|
||||
const char *rootCABuf,
|
||||
const char *clientCert,
|
||||
const char *clientKey,
|
||||
const char *pskIdent,
|
||||
const char *psk,
|
||||
const char **alpnProtocols
|
||||
const char *psk
|
||||
);
|
||||
|
||||
public:
|
||||
MbedTLSClient();
|
||||
MbedTLSClient(int sock);
|
||||
~MbedTLSClient();
|
||||
|
||||
int connect(IPAddress ip, uint16_t port, int32_t timeout);
|
||||
int connect(const char *host, uint16_t port, int32_t timeout);
|
||||
|
||||
66
arduino/libretuya/libraries/StreamString/StreamString.cpp
Normal file
66
arduino/libretuya/libraries/StreamString/StreamString.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
StreamString.cpp
|
||||
|
||||
Copyright (c) 2015 Markus Sattler. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "StreamString.h"
|
||||
|
||||
size_t StreamString::write(const uint8_t *data, size_t size) {
|
||||
if(size && data) {
|
||||
const unsigned int newlen = len + size;
|
||||
if(reserve(newlen + 1)) {
|
||||
memcpy((void *) (buffer + len), (const void *) data, size);
|
||||
changeBuffer(newlen);
|
||||
*(buffer + newlen) = 0x00; // add null for string end
|
||||
return size;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t StreamString::write(uint8_t data) {
|
||||
return concat((char) data);
|
||||
}
|
||||
|
||||
int StreamString::available() {
|
||||
return length();
|
||||
}
|
||||
|
||||
int StreamString::read() {
|
||||
if(length()) {
|
||||
char c = charAt(0);
|
||||
remove(0, 1);
|
||||
return c;
|
||||
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int StreamString::peek() {
|
||||
if(length()) {
|
||||
char c = charAt(0);
|
||||
return c;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void StreamString::flush() {
|
||||
}
|
||||
39
arduino/libretuya/libraries/StreamString/StreamString.h
Normal file
39
arduino/libretuya/libraries/StreamString/StreamString.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
StreamString.h
|
||||
|
||||
Copyright (c) 2015 Markus Sattler. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#ifndef STREAMSTRING_H_
|
||||
#define STREAMSTRING_H_
|
||||
|
||||
|
||||
class StreamString: public Stream, public String
|
||||
{
|
||||
public:
|
||||
size_t write(const uint8_t *buffer, size_t size) override;
|
||||
size_t write(uint8_t data) override;
|
||||
|
||||
int available() override;
|
||||
int read() override;
|
||||
int peek() override;
|
||||
void flush() override;
|
||||
};
|
||||
|
||||
|
||||
#endif /* STREAMSTRING_H_ */
|
||||
203
arduino/libretuya/libraries/Update/Update.cpp
Normal file
203
arduino/libretuya/libraries/Update/Update.cpp
Normal file
@@ -0,0 +1,203 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-29. */
|
||||
|
||||
#include "Update.h"
|
||||
|
||||
UpdateClass::UpdateClass() : ctx(NULL), info(NULL), buf(NULL) {
|
||||
cleanup();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize the update process.
|
||||
*
|
||||
* @param size total UF2 file size
|
||||
* @param command must be U_FLASH
|
||||
* @return false if parameters are invalid or update is running, true otherwise
|
||||
*/
|
||||
bool UpdateClass::begin(size_t size, int command, int unused2, uint8_t unused3, const char *unused4) {
|
||||
if (ctx)
|
||||
return false;
|
||||
cleanup();
|
||||
|
||||
ctx = uf2_ctx_init(LT.otaGetTarget(), FAMILY);
|
||||
info = uf2_info_init();
|
||||
|
||||
if (!size)
|
||||
return errorArd(UPDATE_ERROR_SIZE);
|
||||
|
||||
if (command != U_FLASH)
|
||||
return errorArd(UPDATE_ERROR_BAD_ARGUMENT);
|
||||
|
||||
bytesTotal = size;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Finalize the update process. Check for errors and update completion, then activate the new firmware image.
|
||||
*
|
||||
* @param evenIfRemaining no idea
|
||||
* @return false in case of errors or no update running, true otherwise
|
||||
*/
|
||||
bool UpdateClass::end(bool evenIfRemaining) {
|
||||
if (hasError() || !ctx)
|
||||
// false if not running
|
||||
return false;
|
||||
|
||||
if (!isFinished() && !evenIfRemaining) {
|
||||
// abort if not finished
|
||||
return errorArd(UPDATE_ERROR_ABORT);
|
||||
}
|
||||
// TODO what is evenIfRemaining for?
|
||||
if (!LT.otaSwitch())
|
||||
// try to activate the second OTA
|
||||
return errorArd(UPDATE_ERROR_ACTIVATE);
|
||||
|
||||
cleanup();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write a chunk of data to the buffer or flash memory.
|
||||
*
|
||||
* It's advised to write in 512-byte chunks (or its multiples).
|
||||
*
|
||||
* @param data
|
||||
* @param len
|
||||
* @return size_t
|
||||
*/
|
||||
size_t UpdateClass::write(uint8_t *data, size_t len) {
|
||||
size_t written = 0;
|
||||
if (hasError() || !ctx)
|
||||
// 0 if not running
|
||||
return 0;
|
||||
|
||||
/* while (buf == bufPos && len >= UF2_BLOCK_SIZE) {
|
||||
// buffer empty and entire block is in data
|
||||
if (!tryWriteData(data, UF2_BLOCK_SIZE)) {
|
||||
// returns 0 if data contains an invalid block
|
||||
return written;
|
||||
}
|
||||
data += UF2_BLOCK_SIZE;
|
||||
len -= UF2_BLOCK_SIZE;
|
||||
written += UF2_BLOCK_SIZE;
|
||||
} */
|
||||
|
||||
// write until buffer space is available
|
||||
uint16_t toWrite;
|
||||
while (len && (toWrite = min(len, bufLeft()))) {
|
||||
tryWriteData(data, toWrite);
|
||||
if (hasError())
|
||||
// return on errors
|
||||
return written;
|
||||
data += toWrite;
|
||||
len -= toWrite;
|
||||
written += toWrite;
|
||||
}
|
||||
return written;
|
||||
}
|
||||
|
||||
size_t UpdateClass::writeStream(Stream &data) {
|
||||
size_t written = 0;
|
||||
if (hasError() || !ctx)
|
||||
// 0 if not running
|
||||
return 0;
|
||||
|
||||
uint32_t lastData = millis();
|
||||
// loop until the update is complete
|
||||
while (remaining()) {
|
||||
// check stream availability
|
||||
int available = data.available();
|
||||
if (available <= 0) {
|
||||
if (millis() - lastData > UPDATE_TIMEOUT_MS) {
|
||||
// waited for data too long; abort with error
|
||||
errorArd(UPDATE_ERROR_STREAM);
|
||||
return written;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// available > 0
|
||||
lastData = millis();
|
||||
|
||||
// read data to fit in the remaining buffer space
|
||||
bufAlloc();
|
||||
uint16_t read = data.readBytes(bufPos, bufLeft());
|
||||
bufPos += read;
|
||||
written += read;
|
||||
tryWriteData();
|
||||
if (hasError())
|
||||
// return on errors
|
||||
return written;
|
||||
}
|
||||
return written;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Try to use the buffer as a block to write. In case of UF2 errors,
|
||||
* error codes are set, the update is aborted and 0 is returned
|
||||
*
|
||||
* @param data received data to copy to buffer or NULL if already in buffer
|
||||
* @param len received data length - must be at most bufLeft()
|
||||
* @return size_t "used" data size - 0 or 512
|
||||
*/
|
||||
size_t UpdateClass::tryWriteData(uint8_t *data, size_t len) {
|
||||
uf2_block_t *block = NULL;
|
||||
|
||||
if (len == UF2_BLOCK_SIZE) {
|
||||
// data has a complete block
|
||||
block = (uf2_block_t *)data;
|
||||
} else if (data && len) {
|
||||
// data has a part of a block, copy it to buffer
|
||||
bufAlloc();
|
||||
memcpy(bufPos, data, len);
|
||||
bufPos += len;
|
||||
}
|
||||
|
||||
if (!block && bufSize() == UF2_BLOCK_SIZE) {
|
||||
// use buffer as block (only if not found above)
|
||||
block = (uf2_block_t *)buf;
|
||||
}
|
||||
|
||||
// a complete block has been found
|
||||
if (block) {
|
||||
if (errorUf2(uf2_check_block(ctx, block)))
|
||||
// block is invalid
|
||||
return 0;
|
||||
|
||||
if (errUf2 == UF2_ERR_IGNORE)
|
||||
// treat ignored blocks as valid
|
||||
return UF2_BLOCK_SIZE;
|
||||
|
||||
if (!bytesWritten) {
|
||||
// parse header block to allow retrieving firmware info
|
||||
if (errorUf2(uf2_parse_header(ctx, block, info)))
|
||||
// header is invalid
|
||||
return 0;
|
||||
|
||||
if (bytesTotal == UPDATE_SIZE_UNKNOWN) {
|
||||
// set total update size from block count info
|
||||
bytesTotal = block->block_count * UF2_BLOCK_SIZE;
|
||||
} else if (bytesTotal != block->block_count * UF2_BLOCK_SIZE) {
|
||||
// given update size does not match the block count
|
||||
return errorArd(UPDATE_ERROR_SIZE);
|
||||
}
|
||||
} else {
|
||||
// write data blocks normally
|
||||
if (errorUf2(uf2_write(ctx, block)))
|
||||
// block writing failed
|
||||
return 0;
|
||||
}
|
||||
|
||||
// increment total writing progress
|
||||
bytesWritten += UF2_BLOCK_SIZE;
|
||||
// call progress callback
|
||||
if (callback)
|
||||
callback(bytesWritten, bytesTotal);
|
||||
// reset the buffer as it's used already
|
||||
if (bufSize() == UF2_BLOCK_SIZE)
|
||||
bufPos = buf;
|
||||
return UF2_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
UpdateClass Update;
|
||||
150
arduino/libretuya/libraries/Update/Update.h
Normal file
150
arduino/libretuya/libraries/Update/Update.h
Normal file
@@ -0,0 +1,150 @@
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <functional>
|
||||
|
||||
#include "uf2ota/uf2ota.h"
|
||||
|
||||
// No Error
|
||||
#define UPDATE_ERROR_OK (0)
|
||||
// Flash Write Failed
|
||||
#define UPDATE_ERROR_WRITE (1)
|
||||
// Flash Erase Failed
|
||||
#define UPDATE_ERROR_ERASE (2)
|
||||
// Flash Read Failed
|
||||
#define UPDATE_ERROR_READ (3)
|
||||
// Not Enough Space
|
||||
#define UPDATE_ERROR_SPACE (4)
|
||||
// Bad Size Given
|
||||
#define UPDATE_ERROR_SIZE (5)
|
||||
// Stream Read Timeout
|
||||
#define UPDATE_ERROR_STREAM (6)
|
||||
// MD5 Check Failed
|
||||
#define UPDATE_ERROR_MD5 (7)
|
||||
// Wrong Magic Byte
|
||||
#define UPDATE_ERROR_MAGIC_BYTE (8)
|
||||
// Could Not Activate The Firmware
|
||||
#define UPDATE_ERROR_ACTIVATE (9)
|
||||
// Partition Could Not be Found
|
||||
#define UPDATE_ERROR_NO_PARTITION (10)
|
||||
// Bad Argument
|
||||
#define UPDATE_ERROR_BAD_ARGUMENT (11)
|
||||
// Aborted
|
||||
#define UPDATE_ERROR_ABORT (12)
|
||||
|
||||
#define UPDATE_SIZE_UNKNOWN 0xFFFFFFFF
|
||||
|
||||
#define U_FLASH 0
|
||||
#define U_SPIFFS 100
|
||||
#define U_AUTH 200
|
||||
|
||||
#define ENCRYPTED_BLOCK_SIZE 16
|
||||
|
||||
#define UPDATE_TIMEOUT_MS 30 * 1000
|
||||
|
||||
class UpdateClass {
|
||||
public:
|
||||
typedef std::function<void(size_t, size_t)> THandlerFunction_Progress;
|
||||
|
||||
public: /* Update.cpp */
|
||||
UpdateClass();
|
||||
bool begin(
|
||||
size_t size = UPDATE_SIZE_UNKNOWN,
|
||||
int command = U_FLASH,
|
||||
int unused2 = -1,
|
||||
uint8_t unused3 = LOW,
|
||||
const char *unused4 = NULL // this is for SPIFFS
|
||||
);
|
||||
bool end(bool evenIfRemaining = false);
|
||||
size_t write(uint8_t *data, size_t len);
|
||||
size_t writeStream(Stream &data);
|
||||
bool canRollBack();
|
||||
bool rollBack();
|
||||
// bool setMD5(const char *expected_md5);
|
||||
|
||||
private: /* Update.cpp */
|
||||
size_t tryWriteData(uint8_t *data = NULL, size_t len = 0);
|
||||
|
||||
public: /* UpdateUtil.cpp */
|
||||
UpdateClass &onProgress(THandlerFunction_Progress callback);
|
||||
void abort();
|
||||
void printError(Print &out);
|
||||
const char *errorString();
|
||||
const char *getFirmwareName();
|
||||
const char *getFirmwareVersion();
|
||||
const char *getLibreTuyaVersion();
|
||||
const char *getBoardName();
|
||||
|
||||
private: /* UpdateUtil.cpp */
|
||||
void cleanup();
|
||||
bool errorUf2(uf2_err_t err);
|
||||
bool errorArd(uint8_t err);
|
||||
void bufAlloc();
|
||||
uint16_t bufLeft();
|
||||
uint16_t bufSize();
|
||||
|
||||
private:
|
||||
// uf2ota context
|
||||
uf2_ota_t *ctx;
|
||||
uf2_info_t *info;
|
||||
// block buffer
|
||||
uint8_t *buf;
|
||||
uint8_t *bufPos;
|
||||
// update progress - multiplies of 512 bytes
|
||||
uint32_t bytesWritten;
|
||||
uint32_t bytesTotal;
|
||||
// errors
|
||||
uf2_err_t errUf2;
|
||||
uint8_t errArd;
|
||||
// progress callback
|
||||
THandlerFunction_Progress callback;
|
||||
// String _target_md5;
|
||||
// MD5Builder _md5;
|
||||
|
||||
public:
|
||||
String md5String(void) {
|
||||
// return _md5.toString();
|
||||
}
|
||||
|
||||
void md5(uint8_t *result) {
|
||||
// return _md5.getBytes(result);
|
||||
}
|
||||
|
||||
uint8_t getError() {
|
||||
return errArd;
|
||||
}
|
||||
|
||||
uf2_err_t getUF2Error() {
|
||||
return errUf2;
|
||||
}
|
||||
|
||||
void clearError() {
|
||||
errorUf2(UF2_ERR_OK);
|
||||
}
|
||||
|
||||
bool hasError() {
|
||||
return errArd != UPDATE_ERROR_OK;
|
||||
}
|
||||
|
||||
bool isRunning() {
|
||||
return ctx != NULL;
|
||||
}
|
||||
|
||||
bool isFinished() {
|
||||
return bytesWritten == bytesTotal;
|
||||
}
|
||||
|
||||
size_t size() {
|
||||
return bytesTotal;
|
||||
}
|
||||
|
||||
size_t progress() {
|
||||
return bytesWritten;
|
||||
}
|
||||
|
||||
size_t remaining() {
|
||||
return bytesTotal - bytesWritten;
|
||||
}
|
||||
};
|
||||
|
||||
extern UpdateClass Update;
|
||||
162
arduino/libretuya/libraries/Update/UpdateUtil.cpp
Normal file
162
arduino/libretuya/libraries/Update/UpdateUtil.cpp
Normal file
@@ -0,0 +1,162 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-30. */
|
||||
|
||||
#include "Update.h"
|
||||
|
||||
static const uint8_t errorMap[] = {
|
||||
UPDATE_ERROR_OK, /* UF2_ERR_OK - no error */
|
||||
UPDATE_ERROR_OK, /* UF2_ERR_IGNORE - block should be ignored */
|
||||
UPDATE_ERROR_MAGIC_BYTE, /* UF2_ERR_MAGIC - wrong magic numbers */
|
||||
UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_FAMILY - family ID mismatched */
|
||||
UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_NOT_HEADER - block is not a header */
|
||||
UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_OTA_VER - unknown/invalid OTA format version */
|
||||
UPDATE_ERROR_MAGIC_BYTE, /* UF2_ERR_OTA_WRONG - no data for current OTA index */
|
||||
UPDATE_ERROR_NO_PARTITION, /* UF2_ERR_PART_404 - no partition with that name */
|
||||
UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_PART_ONE - only one partition tag in a block */
|
||||
UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_PART_UNSET - attempted to write without target partition */
|
||||
UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_DATA_TOO_LONG - data too long - tags won't fit */
|
||||
UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_SEQ_MISMATCH - sequence number mismatched */
|
||||
UPDATE_ERROR_ERASE, /* UF2_ERR_ERASE_FAILED - erasing flash failed */
|
||||
UPDATE_ERROR_WRITE, /* UF2_ERR_WRITE_FAILED - writing to flash failed */
|
||||
UPDATE_ERROR_WRITE /* UF2_ERR_WRITE_LENGTH - wrote fewer data than requested */
|
||||
};
|
||||
|
||||
static char errorStr[14];
|
||||
|
||||
/**
|
||||
* @brief Set the callback invoked after writing data to flash.
|
||||
*/
|
||||
UpdateClass &UpdateClass::onProgress(THandlerFunction_Progress callback) {
|
||||
this->callback = callback;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void UpdateClass::cleanup() {
|
||||
free(ctx); // NULL in constructor
|
||||
ctx = NULL;
|
||||
uf2_info_free(info); // NULL in constructor
|
||||
info = NULL;
|
||||
free(buf); // NULL in constructor
|
||||
buf = bufPos = NULL;
|
||||
|
||||
bytesWritten = 0;
|
||||
bytesTotal = 0;
|
||||
errUf2 = UF2_ERR_OK;
|
||||
errArd = UPDATE_ERROR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check for UF2 errors. Set errArd and errUf2 in case of errors.
|
||||
* Ignored blocks are not reported as errors.
|
||||
* Abort the update.
|
||||
* Use like: "if (errorUf2(...)) return false;"
|
||||
* @return true if err is not OK, false otherwise
|
||||
*/
|
||||
bool UpdateClass::errorUf2(uf2_err_t err) {
|
||||
if (err <= UF2_ERR_IGNORE)
|
||||
return false;
|
||||
cleanup();
|
||||
errUf2 = err;
|
||||
errArd = errorMap[err];
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set errUf2 and errArd according to given Arduino error code.
|
||||
* Abort the update.
|
||||
* Use like: "return errorArd(...);"
|
||||
* @return false - always
|
||||
*/
|
||||
bool UpdateClass::errorArd(uint8_t err) {
|
||||
cleanup();
|
||||
errUf2 = UF2_ERR_OK;
|
||||
errArd = err;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Abort the update with UPDATE_ERROR_ABORT reason.
|
||||
*/
|
||||
void UpdateClass::abort() {
|
||||
errorArd(UPDATE_ERROR_ABORT);
|
||||
}
|
||||
|
||||
void UpdateClass::bufAlloc() {
|
||||
if (!buf)
|
||||
buf = bufPos = (uint8_t *)malloc(UF2_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
uint16_t UpdateClass::bufLeft() {
|
||||
return buf + UF2_BLOCK_SIZE - bufPos;
|
||||
}
|
||||
|
||||
uint16_t UpdateClass::bufSize() {
|
||||
return bufPos - buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Print string error info to the stream.
|
||||
*/
|
||||
void UpdateClass::printError(Print &out) {
|
||||
out.println(errorString());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get string representation of the error in format
|
||||
* "ard=..,uf2=..". Returns "" if no error.
|
||||
*/
|
||||
const char *UpdateClass::errorString() {
|
||||
if (!errArd)
|
||||
return "";
|
||||
sprintf(errorStr, "ard=%u,uf2=%u", errArd, errUf2);
|
||||
return errorStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get firmware name from UF2 info.
|
||||
*/
|
||||
const char *UpdateClass::getFirmwareName() {
|
||||
if (info)
|
||||
return info->fw_name;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get firmware version from UF2 info.
|
||||
*/
|
||||
const char *UpdateClass::getFirmwareVersion() {
|
||||
if (info)
|
||||
return info->fw_version;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get LibreTuya version from UF2 info.
|
||||
*/
|
||||
const char *UpdateClass::getLibreTuyaVersion() {
|
||||
if (info)
|
||||
return info->lt_version;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get target board name from UF2 info.
|
||||
*/
|
||||
const char *UpdateClass::getBoardName() {
|
||||
if (info)
|
||||
return info->board;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief See LT.otaCanRollback() for more info.
|
||||
*/
|
||||
bool UpdateClass::canRollBack() {
|
||||
return LT.otaCanRollback();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief See LT.otaRollback() for more info.
|
||||
*/
|
||||
bool UpdateClass::rollBack() {
|
||||
return LT.otaRollback();
|
||||
}
|
||||
32
arduino/libretuya/libraries/Update/uf2ota/uf2binpatch.c
Normal file
32
arduino/libretuya/libraries/Update/uf2ota/uf2binpatch.c
Normal file
@@ -0,0 +1,32 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-29. */
|
||||
|
||||
#include "uf2priv.h"
|
||||
|
||||
uf2_err_t uf2_binpatch(uint8_t *data, const uint8_t *binpatch, uint8_t binpatch_len) {
|
||||
const uint8_t *binpatch_end = binpatch + binpatch_len;
|
||||
// +2 to make sure opcode and length is present
|
||||
while ((binpatch + 2) < binpatch_end) {
|
||||
uf2_opcode_t opcode = binpatch[0];
|
||||
uint8_t len = binpatch[1];
|
||||
switch (opcode) {
|
||||
case UF2_OPC_DIFF32:
|
||||
uf2_binpatch_diff32(data, binpatch + 1);
|
||||
break;
|
||||
}
|
||||
// advance by opcode + length + data
|
||||
binpatch += len + 2;
|
||||
}
|
||||
return UF2_ERR_OK;
|
||||
}
|
||||
|
||||
void uf2_binpatch_diff32(uint8_t *data, const uint8_t *patch) {
|
||||
uint8_t num_offs = patch[0] - 4; // read offset count
|
||||
uint32_t diff = *((uint32_t *)(patch + 1)); // read diff value
|
||||
patch += 5; // skip num_offs and diff value
|
||||
for (uint8_t i = 0; i < num_offs; i++) {
|
||||
// patch the data
|
||||
uint8_t offs = patch[i];
|
||||
uint32_t *value = (uint32_t *)(data + offs);
|
||||
*(value) += diff;
|
||||
}
|
||||
}
|
||||
26
arduino/libretuya/libraries/Update/uf2ota/uf2binpatch.h
Normal file
26
arduino/libretuya/libraries/Update/uf2ota/uf2binpatch.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-29. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "uf2types.h"
|
||||
|
||||
/**
|
||||
* @brief Apply binary patch to data.
|
||||
*
|
||||
* @param data input data
|
||||
* @param data_len input data length
|
||||
* @param binpatch binary patch data
|
||||
* @param binpatch_len binary patch data length
|
||||
* @return uf2_err_t error code
|
||||
*/
|
||||
uf2_err_t uf2_binpatch(uint8_t *data, const uint8_t *binpatch, uint8_t binpatch_len);
|
||||
|
||||
/**
|
||||
* Apply DIFF32 binary patch.
|
||||
*
|
||||
* @param data input data
|
||||
* @param len input data length
|
||||
* @param patch patch data, incl. length byte
|
||||
* @return uf2_err_t error code
|
||||
*/
|
||||
void uf2_binpatch_diff32(uint8_t *data, const uint8_t *patch);
|
||||
100
arduino/libretuya/libraries/Update/uf2ota/uf2ota.c
Normal file
100
arduino/libretuya/libraries/Update/uf2ota/uf2ota.c
Normal file
@@ -0,0 +1,100 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-29. */
|
||||
|
||||
#include "uf2priv.h"
|
||||
|
||||
uf2_ota_t *uf2_ctx_init(uint8_t ota_idx, uint32_t family_id) {
|
||||
uf2_ota_t *ctx = (uf2_ota_t *)zalloc(sizeof(uf2_ota_t));
|
||||
ctx->ota_idx = ota_idx;
|
||||
ctx->family_id = family_id;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
uf2_info_t *uf2_info_init() {
|
||||
uf2_info_t *info = (uf2_info_t *)zalloc(sizeof(uf2_info_t));
|
||||
return info;
|
||||
}
|
||||
|
||||
void uf2_info_free(uf2_info_t *info) {
|
||||
if (!info)
|
||||
return;
|
||||
free(info->fw_name);
|
||||
free(info->fw_version);
|
||||
free(info->lt_version);
|
||||
free(info->board);
|
||||
free(info);
|
||||
}
|
||||
|
||||
uf2_err_t uf2_check_block(uf2_ota_t *ctx, uf2_block_t *block) {
|
||||
if (block->magic1 != UF2_MAGIC_1)
|
||||
return UF2_ERR_MAGIC;
|
||||
if (block->magic2 != UF2_MAGIC_2)
|
||||
return UF2_ERR_MAGIC;
|
||||
if (block->magic3 != UF2_MAGIC_3)
|
||||
return UF2_ERR_MAGIC;
|
||||
if (block->file_container)
|
||||
// ignore file containers, for now
|
||||
return UF2_ERR_IGNORE;
|
||||
if (!block->has_family_id || block->file_size != ctx->family_id)
|
||||
// require family_id
|
||||
return UF2_ERR_FAMILY;
|
||||
return UF2_ERR_OK;
|
||||
}
|
||||
|
||||
uf2_err_t uf2_parse_header(uf2_ota_t *ctx, uf2_block_t *block, uf2_info_t *info) {
|
||||
if (!block->has_tags || block->file_container || block->len)
|
||||
// header must have tags and no data
|
||||
return UF2_ERR_NOT_HEADER;
|
||||
|
||||
uf2_err_t err = uf2_parse_block(ctx, block, info);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if ((ctx->ota_idx == 1 && !ctx->has_ota1) || !ctx->has_ota2)
|
||||
return UF2_ERR_OTA_WRONG;
|
||||
return UF2_ERR_OK;
|
||||
}
|
||||
|
||||
uf2_err_t uf2_write(uf2_ota_t *ctx, uf2_block_t *block) {
|
||||
if (ctx->seq == 0)
|
||||
return uf2_parse_header(ctx, block, NULL);
|
||||
if (block->not_main_flash || !block->len)
|
||||
// ignore blocks not meant for flashing
|
||||
return UF2_ERR_IGNORE;
|
||||
|
||||
uf2_err_t err = uf2_parse_block(ctx, block, NULL);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!ctx->part1 && !ctx->part2)
|
||||
// no partitions set at all
|
||||
return UF2_ERR_PART_UNSET;
|
||||
|
||||
fal_partition_t part = uf2_get_target_part(ctx);
|
||||
if (!part)
|
||||
// image is not for current OTA scheme
|
||||
return UF2_ERR_IGNORE;
|
||||
|
||||
if (ctx->ota_idx == 2 && ctx->binpatch_len) {
|
||||
// apply binpatch
|
||||
err = uf2_binpatch(block->data, ctx->binpatch, ctx->binpatch_len);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
int ret;
|
||||
// erase sectors if needed
|
||||
if (!uf2_is_erased(ctx, block->addr, block->len)) {
|
||||
ret = fal_partition_erase(part, block->addr, block->len);
|
||||
if (ret < 0)
|
||||
return UF2_ERR_ERASE_FAILED;
|
||||
ctx->erased_offset = block->addr;
|
||||
ctx->erased_length = ret;
|
||||
}
|
||||
// write data to flash
|
||||
ret = fal_partition_write(part, block->addr, block->data, block->len);
|
||||
if (ret < 0)
|
||||
return UF2_ERR_WRITE_FAILED;
|
||||
if (ret != block->len)
|
||||
return UF2_ERR_WRITE_LENGTH;
|
||||
return UF2_ERR_OK;
|
||||
}
|
||||
68
arduino/libretuya/libraries/Update/uf2ota/uf2ota.h
Normal file
68
arduino/libretuya/libraries/Update/uf2ota/uf2ota.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-28. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#include "uf2types.h"
|
||||
|
||||
/**
|
||||
* @brief Create an UF2 OTA context.
|
||||
*
|
||||
* @param ota_idx target OTA index
|
||||
* @param family_id expected family ID
|
||||
* @return uf2_ota_t* heap-allocated structure
|
||||
*/
|
||||
uf2_ota_t *uf2_ctx_init(uint8_t ota_idx, uint32_t family_id);
|
||||
|
||||
/**
|
||||
* @brief Create an UF2 Info structure.
|
||||
*
|
||||
* @return uf2_info_t* heap-allocated structure
|
||||
*/
|
||||
uf2_info_t *uf2_info_init();
|
||||
|
||||
/**
|
||||
* @brief Free values in the info structure AND the structure itself.
|
||||
*
|
||||
* @param info structure to free; may be NULL
|
||||
*/
|
||||
void uf2_info_free(uf2_info_t *info);
|
||||
|
||||
/**
|
||||
* @brief Check if block is valid.
|
||||
*
|
||||
* @param ctx context
|
||||
* @param block block to check
|
||||
* @return uf2_err_t error code; UF2_ERR_OK and UF2_ERR_IGNORE denote valid blocks
|
||||
*/
|
||||
uf2_err_t uf2_check_block(uf2_ota_t *ctx, uf2_block_t *block);
|
||||
|
||||
/**
|
||||
* @brief Parse header block (LibreTuya UF2 first block).
|
||||
*
|
||||
* Note: caller should call uf2_check_block() first.
|
||||
*
|
||||
* @param ctx context
|
||||
* @param block block to parse
|
||||
* @param info structure to write firmware info, NULL if not used
|
||||
* @return uf2_err_t error code
|
||||
*/
|
||||
uf2_err_t uf2_parse_header(uf2_ota_t *ctx, uf2_block_t *block, uf2_info_t *info);
|
||||
|
||||
/**
|
||||
* @brief Write the block to flash memory.
|
||||
*
|
||||
* Note: caller should call uf2_check_block() first.
|
||||
*
|
||||
* @param ctx context
|
||||
* @param block block to write
|
||||
* @return uf2_err_t error code
|
||||
*/
|
||||
uf2_err_t uf2_write(uf2_ota_t *ctx, uf2_block_t *block);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
146
arduino/libretuya/libraries/Update/uf2ota/uf2priv.c
Normal file
146
arduino/libretuya/libraries/Update/uf2ota/uf2priv.c
Normal file
@@ -0,0 +1,146 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-29. */
|
||||
|
||||
#include "uf2priv.h"
|
||||
|
||||
uf2_err_t uf2_parse_block(uf2_ota_t *ctx, uf2_block_t *block, uf2_info_t *info) {
|
||||
if (block->block_seq != ctx->seq)
|
||||
// sequence number must match
|
||||
return UF2_ERR_SEQ_MISMATCH;
|
||||
ctx->seq++; // increment sequence number after checking it
|
||||
|
||||
if (!block->has_tags)
|
||||
// no tags in this block, no further processing needed
|
||||
return UF2_ERR_OK;
|
||||
|
||||
if (block->len > (476 - 4 - 4))
|
||||
// at least one tag + last tag must fit
|
||||
return UF2_ERR_DATA_TOO_LONG;
|
||||
|
||||
uint8_t *tags_start = block->data + block->len;
|
||||
uint8_t tags_len = 476 - block->len;
|
||||
uint8_t tags_pos = 0;
|
||||
if (block->has_md5)
|
||||
tags_len -= 24;
|
||||
|
||||
ctx->binpatch_len = 0; // binpatch applies to one block only
|
||||
char *part1 = NULL;
|
||||
char *part2 = NULL;
|
||||
|
||||
uf2_tag_type_t type;
|
||||
while (tags_pos < tags_len) {
|
||||
uint8_t len = uf2_read_tag(tags_start + tags_pos, &type);
|
||||
if (!len)
|
||||
break;
|
||||
tags_pos += 4; // skip tag header
|
||||
uint8_t *tag = tags_start + tags_pos;
|
||||
|
||||
char **str_dest = NULL; // char* to copy the tag into
|
||||
|
||||
switch (type) {
|
||||
case UF2_TAG_OTA_VERSION:
|
||||
if (tag[0] != 1)
|
||||
return UF2_ERR_OTA_VER;
|
||||
break;
|
||||
case UF2_TAG_FIRMWARE:
|
||||
if (info)
|
||||
str_dest = &(info->fw_name);
|
||||
break;
|
||||
case UF2_TAG_VERSION:
|
||||
if (info)
|
||||
str_dest = &(info->fw_version);
|
||||
break;
|
||||
case UF2_TAG_LT_VERSION:
|
||||
if (info)
|
||||
str_dest = &(info->lt_version);
|
||||
break;
|
||||
case UF2_TAG_BOARD:
|
||||
if (info)
|
||||
str_dest = &(info->board);
|
||||
break;
|
||||
case UF2_TAG_HAS_OTA1:
|
||||
ctx->has_ota1 = tag[0];
|
||||
break;
|
||||
case UF2_TAG_HAS_OTA2:
|
||||
ctx->has_ota2 = tag[0];
|
||||
break;
|
||||
case UF2_TAG_PART_1:
|
||||
str_dest = &(part1);
|
||||
break;
|
||||
case UF2_TAG_PART_2:
|
||||
str_dest = &(part2);
|
||||
break;
|
||||
case UF2_TAG_BINPATCH:
|
||||
ctx->binpatch = tag;
|
||||
ctx->binpatch_len = len;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (str_dest) {
|
||||
*str_dest = (char *)zalloc(len + 1);
|
||||
memcpy(*str_dest, tag, len);
|
||||
}
|
||||
// align position to 4 bytes
|
||||
tags_pos += (((len - 1) / 4) + 1) * 4;
|
||||
}
|
||||
|
||||
if (part1 && part2) {
|
||||
// update current target partition
|
||||
uf2_err_t err = uf2_update_parts(ctx, part1, part2);
|
||||
if (err)
|
||||
return err;
|
||||
} else if (part1 || part2) {
|
||||
// only none or both partitions can be specified
|
||||
return UF2_ERR_PART_ONE;
|
||||
}
|
||||
|
||||
return UF2_ERR_OK;
|
||||
}
|
||||
|
||||
uint8_t uf2_read_tag(const uint8_t *data, uf2_tag_type_t *type) {
|
||||
uint8_t len = data[0];
|
||||
if (!len)
|
||||
return 0;
|
||||
uint32_t tag_type = *((uint32_t *)data);
|
||||
if (!tag_type)
|
||||
return 0;
|
||||
*type = tag_type >> 8; // remove tag length byte
|
||||
return len - 4;
|
||||
}
|
||||
|
||||
uf2_err_t uf2_update_parts(uf2_ota_t *ctx, char *part1, char *part2) {
|
||||
// reset both target partitions
|
||||
ctx->part1 = NULL;
|
||||
ctx->part2 = NULL;
|
||||
// reset offsets as they probably don't apply to this partition
|
||||
ctx->erased_offset = 0;
|
||||
ctx->erased_length = 0;
|
||||
|
||||
if (part1[0]) {
|
||||
ctx->part1 = (fal_partition_t)fal_partition_find(part1);
|
||||
if (!ctx->part1)
|
||||
return UF2_ERR_PART_404;
|
||||
}
|
||||
if (part2[0]) {
|
||||
ctx->part2 = (fal_partition_t)fal_partition_find(part2);
|
||||
if (!ctx->part2)
|
||||
return UF2_ERR_PART_404;
|
||||
}
|
||||
|
||||
return UF2_ERR_OK;
|
||||
}
|
||||
|
||||
fal_partition_t uf2_get_target_part(uf2_ota_t *ctx) {
|
||||
if (ctx->ota_idx == 1)
|
||||
return ctx->part1;
|
||||
if (ctx->ota_idx == 2)
|
||||
return ctx->part2;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool uf2_is_erased(uf2_ota_t *ctx, uint32_t offset, uint32_t length) {
|
||||
uint32_t erased_end = ctx->erased_offset + ctx->erased_length;
|
||||
uint32_t end = offset + length;
|
||||
return (offset >= ctx->erased_offset) && (end <= erased_end);
|
||||
}
|
||||
61
arduino/libretuya/libraries/Update/uf2ota/uf2priv.h
Normal file
61
arduino/libretuya/libraries/Update/uf2ota/uf2priv.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-28. */
|
||||
|
||||
#pragma once
|
||||
|
||||
// include family stdlib APIs
|
||||
#include <WVariant.h>
|
||||
|
||||
#include "uf2binpatch.h"
|
||||
#include "uf2types.h"
|
||||
|
||||
/**
|
||||
* @brief Parse a block and extract information from tags.
|
||||
*
|
||||
* @param ctx context
|
||||
* @param block block to parse
|
||||
* @param info structure to write firmware info, NULL if not used
|
||||
* @return uf2_err_t error code
|
||||
*/
|
||||
uf2_err_t uf2_parse_block(uf2_ota_t *ctx, uf2_block_t *block, uf2_info_t *info);
|
||||
|
||||
/**
|
||||
* @brief Parse a tag.
|
||||
*
|
||||
* @param data pointer to tag header beginning
|
||||
* @param type [out] parsed tag type
|
||||
* @return uint8_t parsed tag data length (excl. header); 0 if invalid/last tag
|
||||
*/
|
||||
uint8_t uf2_read_tag(const uint8_t *data, uf2_tag_type_t *type);
|
||||
|
||||
/**
|
||||
* @brief Update destination partitions in context.
|
||||
*
|
||||
* Partition names cannot be NULL.
|
||||
*
|
||||
* Returns UF2_ERR_IGNORE if specified partitions don't match the
|
||||
* current OTA index.
|
||||
*
|
||||
* @param ctx context
|
||||
* @param part1 partition 1 name or empty string
|
||||
* @param part2 partition 2 name or empty string
|
||||
* @return uf2_err_t error code
|
||||
*/
|
||||
uf2_err_t uf2_update_parts(uf2_ota_t *ctx, char *part1, char *part2);
|
||||
|
||||
/**
|
||||
* @brief Get target flashing partition, depending on OTA index.
|
||||
*
|
||||
* @param ctx context
|
||||
* @return fal_partition_t target partition or NULL if not set
|
||||
*/
|
||||
fal_partition_t uf2_get_target_part(uf2_ota_t *ctx);
|
||||
|
||||
/**
|
||||
* Check if specified flash memory region was already erased during update.
|
||||
*
|
||||
* @param ctx context
|
||||
* @param offset offset to check
|
||||
* @param length length to check
|
||||
* @return bool true/false
|
||||
*/
|
||||
bool uf2_is_erased(uf2_ota_t *ctx, uint32_t offset, uint32_t length);
|
||||
104
arduino/libretuya/libraries/Update/uf2ota/uf2types.h
Normal file
104
arduino/libretuya/libraries/Update/uf2ota/uf2types.h
Normal file
@@ -0,0 +1,104 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-28. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <fal.h>
|
||||
|
||||
#define UF2_MAGIC_1 0x0A324655
|
||||
#define UF2_MAGIC_2 0x9E5D5157
|
||||
#define UF2_MAGIC_3 0x0AB16F30
|
||||
|
||||
#define UF2_BLOCK_SIZE sizeof(uf2_block_t)
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
// 32 byte header
|
||||
uint32_t magic1;
|
||||
uint32_t magic2;
|
||||
|
||||
// flags split as bitfields
|
||||
bool not_main_flash : 1;
|
||||
uint16_t dummy1 : 11;
|
||||
bool file_container : 1;
|
||||
bool has_family_id : 1;
|
||||
bool has_md5 : 1;
|
||||
bool has_tags : 1;
|
||||
uint16_t dummy2 : 16;
|
||||
|
||||
uint32_t addr;
|
||||
uint32_t len;
|
||||
uint32_t block_seq;
|
||||
uint32_t block_count;
|
||||
uint32_t file_size; // or familyID;
|
||||
uint8_t data[476];
|
||||
uint32_t magic3;
|
||||
} uf2_block_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t seq; // current block sequence number
|
||||
|
||||
uint8_t *binpatch; // current block's binpatch (if any) -> pointer inside block->data
|
||||
uint8_t binpatch_len; // binpatch length
|
||||
|
||||
bool has_ota1; // image has any data for OTA1
|
||||
bool has_ota2; // image has any data for OTA2
|
||||
|
||||
uint8_t ota_idx; // target OTA index
|
||||
uint32_t family_id; // expected family ID
|
||||
|
||||
uint32_t erased_offset; // offset of region erased during update
|
||||
uint32_t erased_length; // length of erased region
|
||||
|
||||
fal_partition_t part1; // OTA1 target partition
|
||||
fal_partition_t part2; // OTA2 target partition
|
||||
} uf2_ota_t;
|
||||
|
||||
typedef struct {
|
||||
char *fw_name;
|
||||
char *fw_version;
|
||||
char *lt_version;
|
||||
char *board;
|
||||
} uf2_info_t;
|
||||
|
||||
typedef enum {
|
||||
UF2_TAG_VERSION = 0x9FC7BC, // version of firmware file - UTF8 semver string
|
||||
UF2_TAG_PAGE_SIZE = 0x0BE9F7, // page size of target device (32 bit unsigned number)
|
||||
UF2_TAG_SHA2 = 0xB46DB0, // SHA-2 checksum of firmware (can be of various size)
|
||||
UF2_TAG_DEVICE = 0x650D9D, // description of device (UTF8)
|
||||
UF2_TAG_DEVICE_ID = 0xC8A729, // device type identifier
|
||||
// LibreTuya custom, tags
|
||||
UF2_TAG_OTA_VERSION = 0x5D57D0, // format version
|
||||
UF2_TAG_BOARD = 0xCA25C8, // board name (lowercase code)
|
||||
UF2_TAG_FIRMWARE = 0x00DE43, // firmware description / name
|
||||
UF2_TAG_BUILD_DATE = 0x822F30, // build date/time as Unix timestamp
|
||||
UF2_TAG_LT_VERSION = 0x59563D, // LT version (semver)
|
||||
UF2_TAG_PART_1 = 0x805946, // OTA1 partition name
|
||||
UF2_TAG_PART_2 = 0xA1E4D7, // OTA2 partition name
|
||||
UF2_TAG_HAS_OTA1 = 0xBBD965, // image has any data for OTA1
|
||||
UF2_TAG_HAS_OTA2 = 0x92280E, // image has any data for OTA2
|
||||
UF2_TAG_BINPATCH = 0xB948DE, // binary patch to convert OTA1->OTA2
|
||||
} uf2_tag_type_t;
|
||||
|
||||
typedef enum {
|
||||
UF2_OPC_DIFF32 = 0xFE,
|
||||
} uf2_opcode_t;
|
||||
|
||||
typedef enum {
|
||||
UF2_ERR_OK = 0,
|
||||
UF2_ERR_IGNORE, // block should be ignored
|
||||
UF2_ERR_MAGIC, // wrong magic numbers
|
||||
UF2_ERR_FAMILY, // family ID mismatched
|
||||
UF2_ERR_NOT_HEADER, // block is not a header
|
||||
UF2_ERR_OTA_VER, // unknown/invalid OTA format version
|
||||
UF2_ERR_OTA_WRONG, // no data for current OTA index
|
||||
UF2_ERR_PART_404, // no partition with that name
|
||||
UF2_ERR_PART_ONE, // only one partition tag in a block
|
||||
UF2_ERR_PART_UNSET, // image broken - attempted to write without target partition
|
||||
UF2_ERR_DATA_TOO_LONG, // data too long - tags won't fit
|
||||
UF2_ERR_SEQ_MISMATCH, // sequence number mismatched
|
||||
UF2_ERR_ERASE_FAILED, // erasing flash failed
|
||||
UF2_ERR_WRITE_FAILED, // writing to flash failed
|
||||
UF2_ERR_WRITE_LENGTH, // wrote fewer data than requested
|
||||
} uf2_err_t;
|
||||
@@ -19,6 +19,8 @@
|
||||
Modified 8 May 2015 by Hristo Gochkov (proper post and file upload handling)
|
||||
*/
|
||||
|
||||
#if LT_ARD_HAS_WIFI
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "WebServer.h"
|
||||
@@ -603,3 +605,5 @@ bool WebServer::_parseFormUploadAborted() {
|
||||
_currentHandler->upload(*this, _currentUri, *_currentUpload);
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif // LT_ARD_HAS_WIFI
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
Modified 8 May 2015 by Hristo Gochkov (proper post and file upload handling)
|
||||
*/
|
||||
|
||||
#if LT_ARD_HAS_WIFI
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "FS.h"
|
||||
@@ -41,7 +43,7 @@ WebServer::WebServer(IPAddress addr, int port)
|
||||
_statusChange(0), _nullDelay(true), _currentHandler(nullptr), _firstHandler(nullptr), _lastHandler(nullptr),
|
||||
_currentArgCount(0), _currentArgs(nullptr), _postArgsLen(0), _postArgs(nullptr), _headerKeysCount(0),
|
||||
_currentHeaders(nullptr), _contentLength(0), _chunked(false) {
|
||||
log_v("WebServer::Webserver(addr=%s, port=%d)", addr.toString().c_str(), port);
|
||||
log_v("WebServer::Webserver(addr=%s, port=%d)", ipToString(addr).c_str(), port);
|
||||
}
|
||||
|
||||
WebServer::WebServer(int port)
|
||||
@@ -263,7 +265,7 @@ void WebServer::handleClient() {
|
||||
return;
|
||||
}
|
||||
|
||||
log_v("New client: client.localIP()=%s", client.localIP().toString().c_str());
|
||||
log_v("New client: client.localIP()=%s", ipToString(client.localIP()).c_str());
|
||||
|
||||
_currentClient = client;
|
||||
_currentStatus = HC_WAIT_READ;
|
||||
@@ -715,3 +717,5 @@ String WebServer::_responseCodeToString(int code) {
|
||||
return F("");
|
||||
}
|
||||
}
|
||||
|
||||
#endif // LT_ARD_HAS_WIFI
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#if LT_ARD_HAS_WIFI
|
||||
|
||||
#include "WiFiMulti.h"
|
||||
#include <Arduino.h>
|
||||
#include <limits.h>
|
||||
@@ -203,11 +205,14 @@ uint8_t WiFiMulti::run(uint32_t connectTimeout) {
|
||||
status = WiFi.status();
|
||||
}
|
||||
|
||||
IPAddress ip;
|
||||
switch (status) {
|
||||
case WL_CONNECTED:
|
||||
LT_I("Connecting done");
|
||||
LT_D("SSID: %s", WiFi.SSID().c_str());
|
||||
LT_D("IP: %s", WiFi.localIP().toString().c_str());
|
||||
// TODO fix this after implementing IP format for printf()
|
||||
ip = WiFi.localIP();
|
||||
LT_D("IP: %u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
|
||||
LT_D("MAC: %s", WiFi.BSSIDstr().c_str());
|
||||
LT_D("Channel: %d", WiFi.channel());
|
||||
break;
|
||||
@@ -236,3 +241,5 @@ uint8_t WiFiMulti::run(uint32_t connectTimeout) {
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
#endif // LT_ARD_HAS_WIFI
|
||||
|
||||
2
arduino/libretuya/libraries/cbuf/.clang-format
Normal file
2
arduino/libretuya/libraries/cbuf/.clang-format
Normal file
@@ -0,0 +1,2 @@
|
||||
DisableFormat: true
|
||||
SortIncludes: Never
|
||||
196
arduino/libretuya/libraries/cbuf/cbuf.cpp
Normal file
196
arduino/libretuya/libraries/cbuf/cbuf.cpp
Normal file
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
cbuf.cpp - Circular buffer implementation
|
||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "cbuf.h"
|
||||
|
||||
cbuf::cbuf(size_t size) :
|
||||
next(NULL), _size(size+1), _buf(new char[size+1]), _bufend(_buf + size + 1), _begin(_buf), _end(_begin)
|
||||
{
|
||||
}
|
||||
|
||||
cbuf::~cbuf()
|
||||
{
|
||||
delete[] _buf;
|
||||
}
|
||||
|
||||
size_t cbuf::resizeAdd(size_t addSize)
|
||||
{
|
||||
return resize(_size + addSize);
|
||||
}
|
||||
|
||||
size_t cbuf::resize(size_t newSize)
|
||||
{
|
||||
|
||||
size_t bytes_available = available();
|
||||
newSize += 1;
|
||||
// not lose any data
|
||||
// if data can be lost use remove or flush before resize
|
||||
if((newSize < bytes_available) || (newSize == _size)) {
|
||||
return _size;
|
||||
}
|
||||
|
||||
char *newbuf = new char[newSize];
|
||||
char *oldbuf = _buf;
|
||||
|
||||
if(!newbuf) {
|
||||
return _size;
|
||||
}
|
||||
|
||||
if(_buf) {
|
||||
read(newbuf, bytes_available);
|
||||
memset((newbuf + bytes_available), 0x00, (newSize - bytes_available));
|
||||
}
|
||||
|
||||
_begin = newbuf;
|
||||
_end = newbuf + bytes_available;
|
||||
_bufend = newbuf + newSize;
|
||||
_size = newSize;
|
||||
|
||||
_buf = newbuf;
|
||||
delete[] oldbuf;
|
||||
|
||||
return _size;
|
||||
}
|
||||
|
||||
size_t cbuf::available() const
|
||||
{
|
||||
if(_end >= _begin) {
|
||||
return _end - _begin;
|
||||
}
|
||||
return _size - (_begin - _end);
|
||||
}
|
||||
|
||||
size_t cbuf::size()
|
||||
{
|
||||
return _size;
|
||||
}
|
||||
|
||||
size_t cbuf::room() const
|
||||
{
|
||||
if(_end >= _begin) {
|
||||
return _size - (_end - _begin) - 1;
|
||||
}
|
||||
return _begin - _end - 1;
|
||||
}
|
||||
|
||||
int cbuf::peek()
|
||||
{
|
||||
if(empty()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return static_cast<int>(*_begin);
|
||||
}
|
||||
|
||||
size_t cbuf::peek(char *dst, size_t size)
|
||||
{
|
||||
size_t bytes_available = available();
|
||||
size_t size_to_read = (size < bytes_available) ? size : bytes_available;
|
||||
size_t size_read = size_to_read;
|
||||
char * begin = _begin;
|
||||
if(_end < _begin && size_to_read > (size_t) (_bufend - _begin)) {
|
||||
size_t top_size = _bufend - _begin;
|
||||
memcpy(dst, _begin, top_size);
|
||||
begin = _buf;
|
||||
size_to_read -= top_size;
|
||||
dst += top_size;
|
||||
}
|
||||
memcpy(dst, begin, size_to_read);
|
||||
return size_read;
|
||||
}
|
||||
|
||||
int cbuf::read()
|
||||
{
|
||||
if(empty()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
char result = *_begin;
|
||||
_begin = wrap_if_bufend(_begin + 1);
|
||||
return static_cast<int>(result);
|
||||
}
|
||||
|
||||
size_t cbuf::read(char* dst, size_t size)
|
||||
{
|
||||
size_t bytes_available = available();
|
||||
size_t size_to_read = (size < bytes_available) ? size : bytes_available;
|
||||
size_t size_read = size_to_read;
|
||||
if(_end < _begin && size_to_read > (size_t) (_bufend - _begin)) {
|
||||
size_t top_size = _bufend - _begin;
|
||||
memcpy(dst, _begin, top_size);
|
||||
_begin = _buf;
|
||||
size_to_read -= top_size;
|
||||
dst += top_size;
|
||||
}
|
||||
memcpy(dst, _begin, size_to_read);
|
||||
_begin = wrap_if_bufend(_begin + size_to_read);
|
||||
return size_read;
|
||||
}
|
||||
|
||||
size_t cbuf::write(char c)
|
||||
{
|
||||
if(full()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*_end = c;
|
||||
_end = wrap_if_bufend(_end + 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t cbuf::write(const char* src, size_t size)
|
||||
{
|
||||
size_t bytes_available = room();
|
||||
size_t size_to_write = (size < bytes_available) ? size : bytes_available;
|
||||
size_t size_written = size_to_write;
|
||||
if(_end >= _begin && size_to_write > (size_t) (_bufend - _end)) {
|
||||
size_t top_size = _bufend - _end;
|
||||
memcpy(_end, src, top_size);
|
||||
_end = _buf;
|
||||
size_to_write -= top_size;
|
||||
src += top_size;
|
||||
}
|
||||
memcpy(_end, src, size_to_write);
|
||||
_end = wrap_if_bufend(_end + size_to_write);
|
||||
return size_written;
|
||||
}
|
||||
|
||||
void cbuf::flush()
|
||||
{
|
||||
_begin = _buf;
|
||||
_end = _buf;
|
||||
}
|
||||
|
||||
size_t cbuf::remove(size_t size)
|
||||
{
|
||||
size_t bytes_available = available();
|
||||
if(size >= bytes_available) {
|
||||
flush();
|
||||
return 0;
|
||||
}
|
||||
size_t size_to_remove = (size < bytes_available) ? size : bytes_available;
|
||||
if(_end < _begin && size_to_remove > (size_t) (_bufend - _begin)) {
|
||||
size_t top_size = _bufend - _begin;
|
||||
_begin = _buf;
|
||||
size_to_remove -= top_size;
|
||||
}
|
||||
_begin = wrap_if_bufend(_begin + size_to_remove);
|
||||
return available();
|
||||
}
|
||||
79
arduino/libretuya/libraries/cbuf/cbuf.h
Normal file
79
arduino/libretuya/libraries/cbuf/cbuf.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
cbuf.h - Circular buffer implementation
|
||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __cbuf_h
|
||||
#define __cbuf_h
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
class cbuf
|
||||
{
|
||||
public:
|
||||
cbuf(size_t size);
|
||||
~cbuf();
|
||||
|
||||
size_t resizeAdd(size_t addSize);
|
||||
size_t resize(size_t newSize);
|
||||
size_t available() const;
|
||||
size_t size();
|
||||
|
||||
size_t room() const;
|
||||
|
||||
inline bool empty() const
|
||||
{
|
||||
return _begin == _end;
|
||||
}
|
||||
|
||||
inline bool full() const
|
||||
{
|
||||
return wrap_if_bufend(_end + 1) == _begin;
|
||||
}
|
||||
|
||||
int peek();
|
||||
size_t peek(char *dst, size_t size);
|
||||
|
||||
int read();
|
||||
size_t read(char* dst, size_t size);
|
||||
|
||||
size_t write(char c);
|
||||
size_t write(const char* src, size_t size);
|
||||
|
||||
void flush();
|
||||
size_t remove(size_t size);
|
||||
|
||||
cbuf *next;
|
||||
|
||||
protected:
|
||||
inline char* wrap_if_bufend(char* ptr) const
|
||||
{
|
||||
return (ptr == _bufend) ? _buf : ptr;
|
||||
}
|
||||
|
||||
size_t _size;
|
||||
char* _buf;
|
||||
const char* _bufend;
|
||||
char* _begin;
|
||||
char* _end;
|
||||
|
||||
};
|
||||
|
||||
#endif//__cbuf_h
|
||||
5
arduino/libretuya/libraries/mDNS/ESPmDNS.h
Normal file
5
arduino/libretuya/libraries/mDNS/ESPmDNS.h
Normal file
@@ -0,0 +1,5 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-23. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "mDNS.h"
|
||||
154
arduino/libretuya/libraries/mDNS/LwIPmDNS.cpp
Normal file
154
arduino/libretuya/libraries/mDNS/LwIPmDNS.cpp
Normal file
@@ -0,0 +1,154 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-23. */
|
||||
|
||||
#ifdef LT_HAS_LWIP2
|
||||
|
||||
#include "mDNS.h"
|
||||
|
||||
extern "C" {
|
||||
#include <lwip/apps/mdns.h>
|
||||
#include <lwip/netif.h>
|
||||
}
|
||||
|
||||
static u8_t mdns_netif_client_id = 0; // TODO fix this
|
||||
|
||||
struct mdns_domain {
|
||||
/* Encoded domain name */
|
||||
u8_t name[256];
|
||||
/* Total length of domain name, including zero */
|
||||
u16_t length;
|
||||
/* Set if compression of this domain is not allowed */
|
||||
u8_t skip_compression;
|
||||
};
|
||||
|
||||
/** Description of a service */
|
||||
struct mdns_service {
|
||||
/** TXT record to answer with */
|
||||
struct mdns_domain txtdata;
|
||||
/** Name of service, like 'myweb' */
|
||||
char name[MDNS_LABEL_MAXLEN + 1];
|
||||
/** Type of service, like '_http' */
|
||||
char service[MDNS_LABEL_MAXLEN + 1];
|
||||
/** Callback function and userdata
|
||||
* to update txtdata buffer */
|
||||
service_get_txt_fn_t txt_fn;
|
||||
void *txt_userdata;
|
||||
/** TTL in seconds of SRV/TXT replies */
|
||||
u32_t dns_ttl;
|
||||
/** Protocol, TCP or UDP */
|
||||
u16_t proto;
|
||||
/** Port of the service */
|
||||
u16_t port;
|
||||
};
|
||||
|
||||
/** Description of a host/netif */
|
||||
struct mdns_host {
|
||||
/** Hostname */
|
||||
char name[MDNS_LABEL_MAXLEN + 1];
|
||||
/** Pointer to services */
|
||||
struct mdns_service *services[MDNS_MAX_SERVICES];
|
||||
/** TTL in seconds of A/AAAA/PTR replies */
|
||||
u32_t dns_ttl;
|
||||
};
|
||||
|
||||
static String mdnsInstanceName = "default_instance";
|
||||
|
||||
mDNS::mDNS() {}
|
||||
|
||||
mDNS::~mDNS() {}
|
||||
|
||||
bool mDNS::begin(const char *hostname) {
|
||||
mdns_resp_init();
|
||||
struct netif *netif = netif_list;
|
||||
uint8_t enabled = 0;
|
||||
while (netif != NULL) {
|
||||
// TODO: detect mdns_netif_client_id by checking netif_get_client_data()
|
||||
// and finding the requested hostname in struct mdns_host
|
||||
if (netif_is_up(netif) && mdns_resp_add_netif(netif, hostname, 255) == ERR_OK) {
|
||||
enabled++;
|
||||
}
|
||||
netif = netif->next;
|
||||
}
|
||||
return enabled > 0;
|
||||
}
|
||||
|
||||
void mDNS::end() {
|
||||
struct netif *netif = netif_list;
|
||||
while (netif != NULL) {
|
||||
if (netif_is_up(netif))
|
||||
mdns_resp_remove_netif(netif);
|
||||
netif = netif->next;
|
||||
}
|
||||
}
|
||||
|
||||
void mDNS::setInstanceName(String name) {
|
||||
mdnsInstanceName = name;
|
||||
}
|
||||
|
||||
bool mDNS::addService(char *service, char *proto, uint16_t port) {
|
||||
char _service[strlen(service) + 2];
|
||||
char _proto[strlen(proto) + 2];
|
||||
_service[0] = '_';
|
||||
_proto[0] = '_';
|
||||
// prepend names with _
|
||||
strcpy(_service + 1, service + (service[0] == '_'));
|
||||
strcpy(_proto + 1, proto + (proto[0] == '_'));
|
||||
|
||||
mdns_sd_proto protocol = DNSSD_PROTO_UDP;
|
||||
if (strncmp(_proto + 1, "tcp", 3) == 0)
|
||||
protocol = DNSSD_PROTO_TCP;
|
||||
|
||||
struct netif *netif = netif_list;
|
||||
while (netif != NULL) {
|
||||
if (netif_is_up(netif)) {
|
||||
mdns_resp_add_service(netif, mdnsInstanceName.c_str(), service, protocol, port, 255, NULL, NULL);
|
||||
}
|
||||
netif = netif->next;
|
||||
}
|
||||
}
|
||||
|
||||
bool mDNS::addServiceTxt(char *name, char *proto, char *key, char *value) {
|
||||
char _name[strlen(name) + 2];
|
||||
char _proto[strlen(proto) + 2];
|
||||
_name[0] = '_';
|
||||
_proto[0] = '_';
|
||||
// prepend names with _
|
||||
strcpy(_name + 1, name + (name[0] == '_'));
|
||||
strcpy(_proto + 1, proto + (proto[0] == '_'));
|
||||
|
||||
mdns_sd_proto protocol = DNSSD_PROTO_UDP;
|
||||
if (strncmp(_proto + 1, "tcp", 3) == 0)
|
||||
protocol = DNSSD_PROTO_TCP;
|
||||
|
||||
struct netif *netif = netif_list;
|
||||
struct mdns_host *mdns;
|
||||
struct mdns_service *service;
|
||||
|
||||
uint8_t txt_len = strlen(key) + strlen(value) + 1;
|
||||
char *txt = (char *)malloc(txt_len + 1);
|
||||
sprintf(txt, "%s=%s", key, value);
|
||||
|
||||
while (netif != NULL) {
|
||||
if (netif_is_up(netif)) {
|
||||
mdns = (struct mdns_host *)netif_get_client_data(netif, mdns_netif_client_id);
|
||||
|
||||
for (uint8_t i = 0; i < MDNS_MAX_SERVICES; i++) {
|
||||
service = mdns->services[i];
|
||||
if (service == NULL)
|
||||
continue;
|
||||
if (strcmp(service->service, _name) || service->proto != protocol)
|
||||
continue;
|
||||
if (mdns_resp_add_service_txtitem(service, txt, txt_len) != ERR_OK) {
|
||||
free(txt);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
netif = netif->next;
|
||||
}
|
||||
free(txt);
|
||||
return true;
|
||||
}
|
||||
|
||||
MDNSResponder MDNS;
|
||||
|
||||
#endif
|
||||
119
arduino/libretuya/libraries/mDNS/mDNS.h
Normal file
119
arduino/libretuya/libraries/mDNS/mDNS.h
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
ESP8266 Multicast DNS (port of CC3000 Multicast DNS library)
|
||||
Version 1.1
|
||||
Copyright (c) 2013 Tony DiCola (tony@tonydicola.com)
|
||||
ESP8266 port (c) 2015 Ivan Grokhotkov (ivan@esp8266.com)
|
||||
MDNS-SD Suport 2015 Hristo Gochkov (hristo@espressif.com)
|
||||
Extended MDNS-SD support 2016 Lars Englund (lars.englund@gmail.com)
|
||||
Rewritten for ESP32 by Hristo Gochkov (hristo@espressif.com)
|
||||
|
||||
This is a simple implementation of multicast DNS query support for an Arduino
|
||||
running on ESP32 chip.
|
||||
|
||||
Usage:
|
||||
- Include the ESP32 Multicast DNS library in the sketch.
|
||||
- Call the begin method in the sketch's setup and provide a domain name (without
|
||||
the '.local' suffix, i.e. just provide 'foo' to resolve 'foo.local'), and the
|
||||
Adafruit CC3000 class instance. Optionally provide a time to live (in seconds)
|
||||
for the DNS record--the default is 1 hour.
|
||||
- Call the update method in each iteration of the sketch's loop function.
|
||||
|
||||
License (MIT license):
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <api/IPv6Address.h>
|
||||
|
||||
class mDNS {
|
||||
public:
|
||||
mDNS();
|
||||
~mDNS();
|
||||
|
||||
bool begin(const char *hostname);
|
||||
void end();
|
||||
|
||||
void setInstanceName(String name);
|
||||
bool addService(char *service, char *proto, uint16_t port);
|
||||
bool addServiceTxt(char *name, char *proto, char *key, char *value);
|
||||
// void enableArduino(uint16_t port = 3232, bool auth = false);
|
||||
// void disableArduino();
|
||||
// void enableWorkstation(esp_interface_t interface = ESP_IF_WIFI_STA);
|
||||
// void disableWorkstation();
|
||||
|
||||
IPAddress queryHost(char *host, uint32_t timeout = 2000);
|
||||
int queryService(char *service, char *proto);
|
||||
|
||||
String hostname(int idx);
|
||||
IPAddress IP(int idx);
|
||||
IPv6Address IPv6(int idx);
|
||||
uint16_t port(int idx);
|
||||
int numTxt(int idx);
|
||||
bool hasTxt(int idx, const char *key);
|
||||
String txt(int idx, const char *key);
|
||||
String txt(int idx, int txtIdx);
|
||||
String txtKey(int idx, int txtIdx);
|
||||
|
||||
void setInstanceName(const char *name) {
|
||||
setInstanceName(String(name));
|
||||
}
|
||||
|
||||
void setInstanceName(char *name) {
|
||||
setInstanceName(String(name));
|
||||
}
|
||||
|
||||
bool addService(const char *service, const char *proto, uint16_t port) {
|
||||
return addService((char *)service, (char *)proto, port);
|
||||
}
|
||||
|
||||
bool addService(String service, String proto, uint16_t port) {
|
||||
return addService(service.c_str(), proto.c_str(), port);
|
||||
}
|
||||
|
||||
void addServiceTxt(const char *name, const char *proto, const char *key, const char *value) {
|
||||
addServiceTxt((char *)name, (char *)proto, (char *)key, (char *)value);
|
||||
}
|
||||
|
||||
void addServiceTxt(String name, String proto, String key, String value) {
|
||||
addServiceTxt(name.c_str(), proto.c_str(), key.c_str(), value.c_str());
|
||||
}
|
||||
|
||||
IPAddress queryHost(const char *host, uint32_t timeout = 2000) {
|
||||
return queryHost((char *)host, timeout);
|
||||
}
|
||||
|
||||
IPAddress queryHost(String host, uint32_t timeout = 2000) {
|
||||
return queryHost(host.c_str(), timeout);
|
||||
}
|
||||
|
||||
int queryService(const char *service, const char *proto) {
|
||||
return queryService((char *)service, (char *)proto);
|
||||
}
|
||||
|
||||
int queryService(String service, String proto) {
|
||||
return queryService(service.c_str(), proto.c_str());
|
||||
}
|
||||
};
|
||||
|
||||
typedef mDNS MDNSResponder;
|
||||
|
||||
extern MDNSResponder MDNS;
|
||||
38
arduino/libretuya/port/flashdb/fal_cfg.h
Normal file
38
arduino/libretuya/port/flashdb/fal_cfg.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-24. */
|
||||
|
||||
#pragma once
|
||||
|
||||
inline void printf_nop(const char *fmt, ...) {}
|
||||
|
||||
#define FAL_PRINTF printf_nop
|
||||
#define FAL_DEBUG 0
|
||||
|
||||
// Flash device configuration
|
||||
extern const struct fal_flash_dev flash0;
|
||||
|
||||
#define FAL_FLASH_DEV_NAME "flash0"
|
||||
|
||||
#define FAL_FLASH_DEV_TABLE \
|
||||
{ &flash0, }
|
||||
|
||||
#define FAL_DEV_NAME_MAX 16 // no need for 24 chars (default)
|
||||
|
||||
// Partition table
|
||||
#define FAL_PART_HAS_TABLE_CFG
|
||||
|
||||
#define FAL_PART_TABLE_ITEM(part_lower, part_upper) \
|
||||
{ \
|
||||
.magic_word = FAL_PART_MAGIC_WORD, /* magic word */ \
|
||||
.name = #part_lower, /* lowercase name as string */ \
|
||||
.flash_name = FAL_FLASH_DEV_NAME, /* flash device name */ \
|
||||
.offset = FLASH_##part_upper##_OFFSET, /* partition offset macro as uppercase string */ \
|
||||
.len = FLASH_##part_upper##_LENGTH, /* partition length macro as uppercase string */ \
|
||||
},
|
||||
|
||||
// for fal_partition_t
|
||||
#include <fal_def.h>
|
||||
|
||||
/**
|
||||
* @brief Root partition table, representing the entire flash.
|
||||
*/
|
||||
extern fal_partition_t fal_root_part;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user