Compare commits
237 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
29303f7ec9 | ||
|
|
c6b06d4be6 | ||
|
|
c9b2f9dd23 | ||
|
|
40590d174f | ||
|
|
780fb72bba | ||
|
|
e9977a26e4 | ||
|
|
1d97f0ce84 | ||
|
|
895b6e89c5 | ||
|
|
9114bc4c49 | ||
|
|
9eae0cd253 | ||
|
|
37f096d3b5 | ||
|
|
6bf549b104 | ||
|
|
3054db9d9b | ||
|
|
69e7e2debe | ||
|
|
6083cca72e | ||
|
|
d17ea4da0f | ||
|
|
2ea0066536 | ||
|
|
3d23211c1e | ||
|
|
1769680d9e | ||
|
|
92351c0b92 | ||
|
|
0f6c31386b | ||
|
|
a9009a8cee | ||
|
|
31e1d51dbd | ||
|
|
41819f2fd6 | ||
|
|
17043f634f | ||
|
|
e1c5761df9 | ||
|
|
fbaae21011 | ||
|
|
fa2064b957 | ||
|
|
21a194f43d | ||
|
|
b255402659 | ||
|
|
dfabfbb921 | ||
|
|
3b36a70c9a | ||
|
|
d1386a8e9d | ||
|
|
67b92b7f56 | ||
|
|
a1f8516e60 | ||
|
|
cf52021d38 | ||
|
|
b78c9387a6 | ||
|
|
b748d99437 | ||
|
|
9a33fc0a69 | ||
|
|
4cddc01f22 | ||
|
|
1d80b5fff7 | ||
|
|
140cf07173 | ||
|
|
1e3a82f439 | ||
|
|
c90794e9f5 | ||
|
|
03c723c73d | ||
|
|
bad2ffdd07 | ||
|
|
eed39c9cfb | ||
|
|
7bd6d1d815 | ||
|
|
bb7fcd5c4d | ||
|
|
9b8e00c7fa | ||
|
|
b97825d552 | ||
|
|
085b5aed16 | ||
|
|
7f43624824 | ||
|
|
1ed0000819 | ||
|
|
3b79636d00 | ||
|
|
5a4b932a37 | ||
|
|
dd2ae149ad | ||
|
|
0f5d0a8889 | ||
|
|
3750ae6953 | ||
|
|
5be993f9eb | ||
|
|
57c43ce515 | ||
|
|
159ffa76fd | ||
|
|
1ac3d30d84 | ||
|
|
631ef6ba59 | ||
|
|
27393e47c3 | ||
|
|
bd47772c04 | ||
|
|
f3871388ce | ||
|
|
62874bebf4 | ||
|
|
2ca368305c | ||
|
|
f697ae6f11 | ||
|
|
ef6dd35977 | ||
|
|
ccf21b4eab | ||
|
|
e99c6124e7 | ||
|
|
5721bd74d7 | ||
|
|
ff443ca488 | ||
|
|
93e0a5d066 | ||
|
|
150c2ef26d | ||
|
|
4d81fcac26 | ||
|
|
a3bbdf1c16 | ||
|
|
39df2e7b54 | ||
|
|
6169f68119 | ||
|
|
e38e53bac0 | ||
|
|
b38a4d5d46 | ||
|
|
96412624d9 | ||
|
|
f8876bba87 | ||
|
|
68b5773827 | ||
|
|
74659901c0 | ||
|
|
73ede2838c | ||
|
|
273a86532b | ||
|
|
05e13dafed | ||
|
|
6af97d2691 | ||
|
|
f9fb78feed | ||
|
|
96dbbe0919 | ||
|
|
0ef66af342 | ||
|
|
7ed48bf9fc | ||
|
|
1335b84391 | ||
|
|
e2794d5f84 | ||
|
|
e7f35c584b | ||
|
|
1e49c3ff6f | ||
|
|
e256ac8e46 | ||
|
|
9c6e9d1525 | ||
|
|
41985e5743 | ||
|
|
f1e41f7cc1 | ||
|
|
6135e4f7b0 | ||
|
|
af8c7417b3 | ||
|
|
babdb1287f | ||
|
|
4532c88873 | ||
|
|
bc1b83d931 | ||
|
|
87ad0798e4 | ||
|
|
a80032d46c | ||
|
|
4dae304f51 | ||
|
|
9b7d34fa65 | ||
|
|
c0cc602c9a | ||
|
|
e5f98ff41f | ||
|
|
bc74c21599 | ||
|
|
3836ad20b7 | ||
|
|
b073290989 | ||
|
|
43c9d0db10 | ||
|
|
c40bdd68af | ||
|
|
620e457eb6 | ||
|
|
5c4da6e82b | ||
|
|
8c636e44f7 | ||
|
|
07e9aa1ded | ||
|
|
27a7faaab7 | ||
|
|
752768b1e2 | ||
|
|
f7c28eeea4 | ||
|
|
113b2fc31d | ||
|
|
86924d8785 | ||
|
|
219415174e | ||
|
|
8999cb9091 | ||
|
|
8337ac121e | ||
|
|
d332315e7a | ||
|
|
882f58bae4 | ||
|
|
2c86a36fe0 | ||
|
|
b984519546 | ||
|
|
7b0f6b22c1 | ||
|
|
3b8a4f1b60 | ||
|
|
edd2c0542b | ||
|
|
dbc905dca3 | ||
|
|
461e4c6df0 | ||
|
|
85a687fc56 | ||
|
|
c5361a4738 | ||
|
|
42c18859f3 | ||
|
|
1ba6834391 | ||
|
|
376a4db4cb | ||
|
|
775e06b259 | ||
|
|
3ba3c2a2be | ||
|
|
76ad89e2f1 | ||
|
|
2a7f1b52a0 | ||
|
|
bd75b54dce | ||
|
|
070f2afd66 | ||
|
|
0e84e08a18 | ||
|
|
4c1ab20ba4 | ||
|
|
63ac7b365d | ||
|
|
c51bf0b7db | ||
|
|
201db4668e | ||
|
|
250e67ab1f | ||
|
|
2e30d34021 | ||
|
|
2882eaa0c2 | ||
|
|
8faffedddc | ||
|
|
5260930919 | ||
|
|
24832d3277 | ||
|
|
8f338a6b30 | ||
|
|
3d3f3700a8 | ||
|
|
eae64d34e2 | ||
|
|
a27e76bfa7 | ||
|
|
b050662a5c | ||
|
|
f69b4bea4f | ||
|
|
4e3b081c60 | ||
|
|
a2de77ce30 | ||
|
|
5de98ed56c | ||
|
|
ff8ac6036c | ||
|
|
c3f12ab247 | ||
|
|
dfcb36361e | ||
|
|
c4a3e9e2ee | ||
|
|
fd1afea1bc | ||
|
|
65cf460691 | ||
|
|
046f7df7d1 | ||
|
|
8323bafd4c | ||
|
|
6b92aac1da | ||
|
|
3113b387c3 | ||
|
|
6d2b653f61 | ||
|
|
47daefe675 | ||
|
|
e8c18f4e66 | ||
|
|
76a82768fe | ||
|
|
8be5aeab59 | ||
|
|
fbfd96ecdb | ||
|
|
dee20c859c | ||
|
|
ce0a88147b | ||
|
|
7f62f1e965 | ||
|
|
b51501fb21 | ||
|
|
72ab64461c | ||
|
|
26b393e059 | ||
|
|
bc328657aa | ||
|
|
c579219427 | ||
|
|
3413d70210 | ||
|
|
8bbc7e13fb | ||
|
|
f1ecb312c7 | ||
|
|
3407891e9c | ||
|
|
8f447a4a72 | ||
|
|
8ace11e462 | ||
|
|
949dfe7266 | ||
|
|
f0d490aef9 | ||
|
|
bdedae981a | ||
|
|
9e0750c9d3 | ||
|
|
9a3e512b1b | ||
|
|
861e741030 | ||
|
|
a3e7e21d45 | ||
|
|
86db2fcf61 | ||
|
|
fcd72e013a | ||
|
|
2450f8c64b | ||
|
|
676a9b1686 | ||
|
|
b10db63c74 | ||
|
|
4b25ef7516 | ||
|
|
de0d19cda6 | ||
|
|
c55386af0e | ||
|
|
33fe1c7a54 | ||
|
|
bf6d05e92a | ||
|
|
b6113d8d2b | ||
|
|
bc31154035 | ||
|
|
edfe0329bf | ||
|
|
1e11dd776a | ||
|
|
028526d22d | ||
|
|
7ac2d854f2 | ||
|
|
279c81e431 | ||
|
|
4e319b40ed | ||
|
|
d082b39980 | ||
|
|
277402f577 | ||
|
|
9e95c507b1 | ||
|
|
7440fc6f46 | ||
|
|
a24028f674 | ||
|
|
00913b013f | ||
|
|
447d08d613 | ||
|
|
d4f7736b2d | ||
|
|
60f72fffdf | ||
|
|
77af9c1cba | ||
|
|
1b2414337f |
@@ -1,11 +1,14 @@
|
||||
# 2025-02-12
|
||||
Language: Cpp
|
||||
BasedOnStyle: LLVM
|
||||
AlignAfterOpenBracket: BlockIndent
|
||||
AlignArrayOfStructures: Left
|
||||
AlignConsecutiveAssignments: true
|
||||
AlignConsecutiveMacros: AcrossComments
|
||||
AlignEscapedNewlinesLeft: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: Empty
|
||||
AllowShortFunctionsOnASingleLine: Empty
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
@@ -21,7 +24,7 @@ IndentCaseLabels: true
|
||||
IndentWidth: 4
|
||||
LambdaBodyIndentation: Signature
|
||||
MaxEmptyLinesToKeep: 1
|
||||
# PointerAlignment: Left # TODO enable this and reformat project
|
||||
PenaltyReturnTypeOnItsOwnLine: 1000
|
||||
QualifierAlignment: Left
|
||||
ReflowComments: true
|
||||
SeparateDefinitionBlocks: Always
|
||||
|
||||
35
.github/workflows/lint.yml
vendored
35
.github/workflows/lint.yml
vendored
@@ -1,35 +0,0 @@
|
||||
name: Lint check
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
lint-clang-format:
|
||||
name: Lint with clang-format
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Check code with clang-format
|
||||
uses: jidicula/clang-format-action@v4.5.0
|
||||
with:
|
||||
clang-format-version: "14"
|
||||
lint-black:
|
||||
name: Lint with black
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: "3.9"
|
||||
- name: Install test dependencies
|
||||
uses: BSFishy/pip-action@v1
|
||||
with:
|
||||
packages: |
|
||||
black
|
||||
isort
|
||||
- name: Check code with black
|
||||
run: black --check .
|
||||
- name: Check code with isort
|
||||
run: isort --profile black . --check-only
|
||||
46
.github/workflows/platformio-publish.yml
vendored
46
.github/workflows/platformio-publish.yml
vendored
@@ -1,46 +0,0 @@
|
||||
name: PlatformIO Publish
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- v*.*.*
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Cache pip
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-
|
||||
- name: Cache PlatformIO
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.platformio
|
||||
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
- name: Install PlatformIO
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install --upgrade platformio
|
||||
- name: Publish PlatformIO package
|
||||
run: pio package publish --non-interactive
|
||||
env:
|
||||
CI: true
|
||||
PLATFORMIO_AUTH_TOKEN: ${{ secrets.PLATFORMIO_AUTH_TOKEN }}
|
||||
- name: Get latest version
|
||||
id: get_version
|
||||
run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//}
|
||||
- name: Release on GitHub
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
name: ${{ steps.get_version.outputs.VERSION }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
13
.github/workflows/push-dev.yml
vendored
Normal file
13
.github/workflows/push-dev.yml
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
name: Push (dev), Pull Request
|
||||
on:
|
||||
push:
|
||||
branches: ["**"]
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
lint-clang:
|
||||
name: Run Clang lint
|
||||
uses: kuba2k2/kuba2k2/.github/workflows/lint-clang.yml@master
|
||||
lint-python:
|
||||
name: Run Python lint
|
||||
uses: kuba2k2/kuba2k2/.github/workflows/lint-python.yml@master
|
||||
@@ -1,10 +1,8 @@
|
||||
name: Deploy docs on GitHub Pages
|
||||
|
||||
name: Push (master)
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
branches: ["master"]
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
docs:
|
||||
name: Deploy docs
|
||||
@@ -18,25 +16,29 @@ jobs:
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
- name: Install ltchiptool
|
||||
run: pip install ltchiptool
|
||||
- name: Install docs dependencies
|
||||
run: pip install -U ltchiptool "boardgen>=0.11.0"
|
||||
|
||||
- name: Generate static JSON files
|
||||
- name: Generate docs and static JSON files
|
||||
run: |
|
||||
mkdir -p site/
|
||||
python docs/build_json.py
|
||||
boardgen ltci
|
||||
python docs/scripts/write_boards.py
|
||||
python docs/scripts/write_apis.py
|
||||
python docs/scripts/prepare_doxygen.py
|
||||
python docs/scripts/build_json.py
|
||||
cp *.json site/
|
||||
|
||||
- name: Set custom domain
|
||||
run: |
|
||||
mkdir -p site/
|
||||
echo docs.libretuya.ml > site/CNAME
|
||||
echo docs.libretiny.eu > site/CNAME
|
||||
|
||||
- name: Deploy docs
|
||||
uses: libretuya/mkdocs-deploy-gh-pages@master
|
||||
uses: libretiny-eu/mkdocs-deploy-gh-pages@master
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
CONFIG_FILE: mkdocs.yml
|
||||
EXTRA_PACKAGES: build-base doxygen
|
||||
REQUIREMENTS: docs/requirements.txt
|
||||
CUSTOM_DOMAIN: docs.libretuya.ml
|
||||
CUSTOM_DOMAIN: docs.libretiny.eu
|
||||
22
.github/workflows/release.yml
vendored
Normal file
22
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
name: Release
|
||||
on:
|
||||
push:
|
||||
tags: ["v*.*.*"]
|
||||
jobs:
|
||||
lint-clang:
|
||||
name: Run Clang lint
|
||||
uses: kuba2k2/kuba2k2/.github/workflows/lint-clang.yml@master
|
||||
publish-pio-platform:
|
||||
name: Publish PlatformIO platform
|
||||
needs:
|
||||
- lint-clang
|
||||
uses: kuba2k2/kuba2k2/.github/workflows/publish-pio-platform.yml@master
|
||||
secrets:
|
||||
PLATFORMIO_AUTH_TOKEN: ${{ secrets.PLATFORMIO_AUTH_TOKEN }}
|
||||
gh-release:
|
||||
name: Publish GitHub release
|
||||
needs:
|
||||
- publish-pio-platform
|
||||
uses: kuba2k2/kuba2k2/.github/workflows/gh-release.yml@master
|
||||
permissions:
|
||||
contents: write
|
||||
9
.gitignore
vendored
9
.gitignore
vendored
@@ -256,6 +256,13 @@ cython_debug/
|
||||
# mkdocs
|
||||
xml/
|
||||
ltapi/
|
||||
ltambz/
|
||||
hashChanges.yaml
|
||||
.piopm
|
||||
|
||||
# board files
|
||||
docs/status/supported_*.md
|
||||
docs/status/unsupported_boards_*.md
|
||||
boards/**/*.svg
|
||||
boards/**/*.md
|
||||
# other generated files
|
||||
docs/contrib/lt-api-functions.md
|
||||
|
||||
2
.gitmodules
vendored
2
.gitmodules
vendored
@@ -1,2 +0,0 @@
|
||||
[submodule "tools/boardgen"]
|
||||
url = https://github.com/kuba2k2/boardgen
|
||||
76
README.md
76
README.md
@@ -1,89 +1,39 @@
|
||||
# LibreTuya
|
||||
# LibreTiny
|
||||
|
||||
<small>(formerly LibreTuya)</small>
|
||||
|
||||
<div align="center" markdown>
|
||||
|
||||
[](https://kuba2k2.github.io/libretuya/)
|
||||

|
||||
[](https://docs.libretiny.eu/)
|
||||

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

|
||||

|
||||

|
||||
|
||||
</div>
|
||||
|
||||
PlatformIO development platform for IoT modules manufactured by Tuya Inc.
|
||||
PlatformIO development platform for BK7231, RTL8710 and LN882H IoT chips.
|
||||
|
||||
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 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.
|
||||
which should make it easier to port/run existing ESP apps on less-common, unsupported IoT modules.
|
||||
|
||||
LibreTuya also provides a common interface for all family implementations. The interface is based on ESP32 official libraries.
|
||||
**There's an [ESPHome port](https://docs.libretiny.eu/docs/projects/esphome/) based on LibreTiny, which supports BK7231 and RTL8710B chips.**
|
||||
|
||||
**Note:** this project is work-in-progress.
|
||||
|
||||
## Usage
|
||||
<div align="center" markdown>
|
||||
|
||||
1. [Install PlatformIO](https://platformio.org/platformio-ide)
|
||||
2. `platformio platform install https://github.com/kuba2k2/libretuya`
|
||||
3. Create a project, build it and upload!
|
||||
4. See the [docs](https://kuba2k2.github.io/libretuya/) for any questions/problems.
|
||||
## [⭐ Getting started ⭐](https://docs.libretiny.eu/docs/getting-started/)
|
||||
|
||||
## Board List
|
||||
|
||||
See [Boards & CPU list](https://kuba2k2.github.io/libretuya/docs/status/supported/).
|
||||
|
||||
## Arduino Core support status
|
||||
|
||||
Note: this list will probably change with each functionality update.
|
||||
|
||||
| `realtek-ambz` | `beken-72xx`
|
||||
--------------------|----------------|-------------
|
||||
Core functions | ✔️ | ✔️
|
||||
GPIO/PWM/IRQ | ✔️/✔️/✔️ | ✔️/✔️/✔️
|
||||
Analog input (ADC) | ✔️ | ✔️
|
||||
Serial | ✔️ | ✔️
|
||||
Serial (extra) | 0, 1, 2 | 1, 2
|
||||
Flash I/O | ✔️ | ✔️
|
||||
**CORE LIBRARIES** | |
|
||||
SoftwareSerial | ✔️ | ❌
|
||||
SPI | ❌ | ❌
|
||||
Wire | ❗ | ❌
|
||||
**OTHER LIBRARIES** | |
|
||||
Wi-Fi STA/AP/Mixed | ✔️ | ✔️
|
||||
Wi-Fi Events | ✔️ | ✔️
|
||||
TCP Client (SSL) | ✔️ (✔️) | ✔️ (❗)
|
||||
TCP Server | ✔️ | ✔️
|
||||
IPv6 | ❌ | ❌
|
||||
HTTP Client (SSL) | ✔️ (✔️) | ❓
|
||||
HTTP Server | ✔️ | ✔️
|
||||
NVS / Preferences | ❌ | ❌
|
||||
SPIFFS | ❌ | ❌
|
||||
BLE | - | ❌
|
||||
NTP | ❌ | ❌
|
||||
OTA | ✔️ | ✔️
|
||||
MDNS | ✔️ | ✔️
|
||||
MQTT | ✅ | ❌
|
||||
SD | ❌ | ❌
|
||||
|
||||
Symbols:
|
||||
|
||||
- ✔️ working
|
||||
- ✅ tested, external library
|
||||
- ❓ untested
|
||||
- ❗ broken
|
||||
- ❌ not implemented (yet?)
|
||||
- \- not applicable
|
||||
|
||||
Names:
|
||||
|
||||
- Core functions - stuff like delay(), millis(), yield(), etc.
|
||||
- **CORE LIBRARIES** - included normally in all Arduino cores
|
||||
- **OTHER LIBRARIES** - included in ESP32 core or downloadable
|
||||
</div>
|
||||
|
||||
## License
|
||||
|
||||
|
||||
110
SUMMARY.md
110
SUMMARY.md
@@ -1,69 +1,65 @@
|
||||
* [Home](README.md)
|
||||
* 😊 Getting started
|
||||
* [Start here](docs/getting-started/README.md)
|
||||
* [Uploading](docs/getting-started/uploading.md)
|
||||
* [Options & config](docs/reference/config.md)
|
||||
* Examples
|
||||
* [PinScan](examples/PinScan/README.md)
|
||||
* [ESPHome port](docs/projects/esphome.md)
|
||||
* [Using tuya-cloudcutter](docs/getting-started/cloudcutter.md)
|
||||
* [Auto-download-reboot](docs/getting-started/adr.md)
|
||||
* [💻 Boards & CPU list](docs/status/supported.md)
|
||||
* [✔️ Implementation status](docs/status/arduino.md)
|
||||
* Supported chip families
|
||||
* Beken BK72xx
|
||||
* [General info](docs/platform/beken-72xx/README.md)
|
||||
* [Flashing](docs/platform/beken-72xx/flashing.md)
|
||||
* [Dumping](docs/platform/beken-72xx/dumping.md)
|
||||
* Realtek AmebaZ Series
|
||||
* [General info](docs/platform/realtek/README.md)
|
||||
* [Flashing (AmebaZ)](docs/platform/realtek-ambz/flashing.md)
|
||||
* [Dumping (AmebaZ)](docs/platform/realtek-ambz/dumping.md)
|
||||
* [Debugging](docs/platform/realtek/debugging.md)
|
||||
* [Exception decoder](docs/platform/realtek/exception-decoder.md)
|
||||
* C library
|
||||
* [Built-in functions](docs/platform/realtek-ambz/stdlib.md)
|
||||
* [Memory management](docs/platform/realtek-ambz/memory-management.md)
|
||||
* [All supported boards](boards/)
|
||||
* API & libraries
|
||||
* [Options & config](docs/reference/config.md)
|
||||
* [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)
|
||||
* [😊 Getting started](docs/getting-started/README.md)
|
||||
* [➡️ Info on accessing GPIOs](docs/getting-started/gpio.md)
|
||||
* [](SUMMARY.md)
|
||||
* [📺 Cloudcutter & ESPHome video guide](https://www.youtube.com/watch?v=sSj8f-HCHQ0)
|
||||
* [💡 ESPHome setup guide](docs/projects/esphome.md)
|
||||
* [🛖 ESPHome Hassio Add-On](https://github.com/libretiny-eu/esphome-hass-addon/pkgs/container/libretiny-esphome-hassio)
|
||||
* [](SUMMARY.md)
|
||||
* [📲 Flashing/dumping guide](docs/flashing/)
|
||||
* [🔌 How to flash/enter download mode?](docs/platform/)
|
||||
* [](SUMMARY.md)
|
||||
* [💻 Chips, boards, features](docs/status/supported.md)
|
||||
* [All boards](boards/)
|
||||
* [](SUMMARY.md)
|
||||
* 🍪 Chip family docs & info
|
||||
* [Beken BK72xx](docs/platform/beken-72xx/README.md)
|
||||
* [Finding encryption keys](docs/platform/beken-72xx/keys.md)
|
||||
* [Realtek Ameba - info](docs/platform/realtek-amb/README.md)
|
||||
* [Realtek AmebaZ](docs/platform/realtek-ambz/README.md)
|
||||
* [Debugging](docs/platform/realtek-ambz/debugging.md)
|
||||
* [Exception decoder](docs/platform/realtek-ambz/exception-decoder.md)
|
||||
* [Lightning LN882x](docs/platform/lightning-ln882x/README.md)
|
||||
* [🔧 LT Configuration](docs/dev/config.md)
|
||||
* 🧑 Programmer's manual
|
||||
* [⚠️ Migration guide](docs/dev/migration_v1.0.0.md)
|
||||
* [🔋 PlatformIO Examples](examples/)
|
||||
* [📖 LibreTiny API](docs/dev/lt-api.md)
|
||||
* [C API](ltapi/dir_c7e317b16142bccc961a83c0babf0065.md)
|
||||
* [C++ API](ltapi/dir_930634efd5dc4a957bbb6e685a3ccda1.md)
|
||||
* 📚 Arduino Libraries
|
||||
* [SoftwareSerial](ltapi/class_software_serial.md)
|
||||
* [WiFi API](ltapi/class_wi_fi_class.md)
|
||||
* [TCP Client](ltapi/class_i_wi_fi_client.md)
|
||||
* [SSL Client](ltapi/class_i_wi_fi_client_secure.md)
|
||||
* [TCP Server](ltapi/class_i_wi_fi_server.md)
|
||||
* [LibreTuya libraries](docs/libs-built-in.md)
|
||||
* [base64](ltapi/classbase64.md)
|
||||
* [WiFi](ltapi/class_wi_fi_class.md)
|
||||
* [](SUMMARY.md)
|
||||
* [Flash](ltapi/class_flash_class.md)
|
||||
* [HTTPClient](ltapi/class_h_t_t_p_client.md)
|
||||
* [IPv6Address](ltapi/classarduino_1_1_i_pv6_address.md)
|
||||
* [MD5](ltapi/libraries_2common_2_m_d5_2_m_d5_8h.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)
|
||||
* [WiFiClient](ltapi/class_i_wi_fi_client.md)
|
||||
* [WiFiClientSecure](ltapi/class_i_wi_fi_client_secure.md)
|
||||
* [WiFiServer](ltapi/class_i_wi_fi_server.md)
|
||||
* [WiFiUDP](ltapi/class_i_wi_fi_u_d_p.md)
|
||||
* [](SUMMARY.md)
|
||||
* [HTTPClient](ltapi/class_h_t_t_p_client.md)
|
||||
* [StreamString](ltapi/class_stream_string.md)
|
||||
* [WebServer](ltapi/class_web_server.md)
|
||||
* [WiFiMulti](ltapi/class_wi_fi_multi.md)
|
||||
* [Third party libraries](docs/libs-3rd-party.md)
|
||||
* [](SUMMARY.md)
|
||||
* [External compatible libraries](docs/dev/libs-3rd-party.md)
|
||||
* Full documentation
|
||||
* [Classes](ltapi/classes.md)
|
||||
* [Functions](ltapi/functions.md)
|
||||
* [Macros](ltapi/macros.md)
|
||||
* [File list](ltapi/files.md)
|
||||
* [📁 Project structure](docs/reference/project-structure.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)
|
||||
* [📓 TODO](TODO.md)
|
||||
* [🔗 Resources](docs/resources.md)
|
||||
* 👷 Contributor's manual (WIP)
|
||||
* [Porting new families](docs/contrib/porting.md)
|
||||
* [API functions guide](docs/contrib/lt-api.md)
|
||||
* [C standard library](docs/contrib/stdlib.md)
|
||||
* [📁 Project structure](docs/contrib/project-structure.md)
|
||||
* [✈️ OTA format](docs/contrib/ota/README.md)
|
||||
* [uf2ota.py tool](docs/contrib/ota/uf2ota.md)
|
||||
* [uf2ota.h library](docs/contrib/ota/library.md)
|
||||
* [📓 TODO](docs/TODO.md)
|
||||
* [](SUMMARY.md)
|
||||
* [🔗 Resources](docs/resources/)
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-06-14. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include "WCharacterFixup.h"
|
||||
#endif
|
||||
|
||||
#define delay delayMilliseconds // change delay()'s signature - it's defined as static inline in WVariant.h
|
||||
#include <api/ArduinoAPI.h>
|
||||
#include <core/LibreTuyaAPI.h>
|
||||
#undef delay
|
||||
|
||||
// Include family-specific code
|
||||
#include "WVariant.h"
|
||||
// Include board variant
|
||||
#include "variant.h"
|
||||
|
||||
// Choose the main UART output port
|
||||
#ifndef LT_UART_DEFAULT_PORT
|
||||
#if defined(PIN_SERIAL2_TX)
|
||||
#define LT_UART_DEFAULT_PORT 2
|
||||
#else
|
||||
#define LT_UART_DEFAULT_PORT 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Define available serial ports
|
||||
#ifdef __cplusplus
|
||||
#include "SerialClass.h"
|
||||
#include <core/SerialExtern.h>
|
||||
#endif
|
||||
@@ -1,208 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-06-19. */
|
||||
|
||||
#include <LibreTuyaAPI.h>
|
||||
#include <libraries/Flash/Flash.h>
|
||||
|
||||
// can't include <flash.h> as it collides with <Flash.h> on Windows -_-
|
||||
#define REG_FLASH_BASE 0x00803000
|
||||
#define REG_FLASH_OPERATE_SW (REG_FLASH_BASE + 0 * 4)
|
||||
#define REG_FLASH_RDID (REG_FLASH_BASE + 4 * 4)
|
||||
#define FLASH_BUSY_SW (0x01UL << 31)
|
||||
#define FLASH_WP_VALUE (0x01UL << 30)
|
||||
#define FLASH_OP_SW (0x01UL << 29)
|
||||
#define FLASH_OP_TYPE_POS 24
|
||||
#define FLASH_OP_RDID 20
|
||||
|
||||
extern "C" {
|
||||
|
||||
#include <flash_pub.h>
|
||||
#include <param_config.h>
|
||||
#include <start_type_pub.h>
|
||||
#include <sys_ctrl.h>
|
||||
#include <sys_rtos.h>
|
||||
#include <wdt_pub.h>
|
||||
#include <wlan_ui_pub.h>
|
||||
|
||||
extern uint8_t system_mac[];
|
||||
extern uint32_t wdt_ctrl(uint32_t cmd, void *param);
|
||||
|
||||
} // extern "C"
|
||||
|
||||
void LibreTuya::restart() {
|
||||
bk_reboot();
|
||||
}
|
||||
|
||||
void LibreTuya::restartDownloadMode() {
|
||||
bk_reboot();
|
||||
}
|
||||
|
||||
ResetReason LibreTuya::getResetReason() {
|
||||
switch (bk_misc_get_start_type()) {
|
||||
case RESET_SOURCE_POWERON:
|
||||
return RESET_REASON_POWER;
|
||||
|
||||
case RESET_SOURCE_REBOOT:
|
||||
return RESET_REASON_SOFTWARE;
|
||||
|
||||
case RESET_SOURCE_WATCHDOG:
|
||||
return RESET_REASON_WATCHDOG;
|
||||
|
||||
case RESET_SOURCE_CRASH_XAT0:
|
||||
case RESET_SOURCE_CRASH_UNDEFINED:
|
||||
case RESET_SOURCE_CRASH_PREFETCH_ABORT:
|
||||
case RESET_SOURCE_CRASH_DATA_ABORT:
|
||||
case RESET_SOURCE_CRASH_UNUSED:
|
||||
case RESET_SOURCE_CRASH_PER_XAT0:
|
||||
return RESET_REASON_CRASH;
|
||||
|
||||
case RESET_SOURCE_DEEPPS_GPIO:
|
||||
case RESET_SOURCE_DEEPPS_RTC:
|
||||
return RESET_REASON_SLEEP;
|
||||
}
|
||||
return RESET_REASON_UNKNOWN;
|
||||
}
|
||||
|
||||
/* CPU-related */
|
||||
|
||||
ChipType LibreTuya::getChipType() {
|
||||
uint8_t chipId = *(uint8_t *)(SCTRL_CHIP_ID);
|
||||
return CHIP_TYPE_ENUM(FAMILY, chipId);
|
||||
}
|
||||
|
||||
const char *LibreTuya::getChipModel() {
|
||||
return STRINGIFY_MACRO(MCU);
|
||||
}
|
||||
|
||||
uint32_t LibreTuya::getChipId() {
|
||||
uint8_t mac[6];
|
||||
cfg_load_mac(mac); // force loading MAC from TLV (ignore user-set WiFi MAC)
|
||||
return (mac[3]) | (mac[4] << 8) | (mac[5] << 16);
|
||||
}
|
||||
|
||||
uint8_t LibreTuya::getChipCores() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *LibreTuya::getChipCoreType() {
|
||||
return "ARM968E-S";
|
||||
}
|
||||
|
||||
uint32_t LibreTuya::getCpuFreq() {
|
||||
return configCPU_CLOCK_HZ;
|
||||
}
|
||||
|
||||
uint32_t LibreTuya::getCycleCount() {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Flash memory utilities */
|
||||
|
||||
FlashId LibreTuya::getFlashChipId() {
|
||||
uint32_t data = (FLASH_OP_RDID << FLASH_OP_TYPE_POS) | FLASH_OP_SW | FLASH_WP_VALUE;
|
||||
REG_WRITE(REG_FLASH_OPERATE_SW, data);
|
||||
while (REG_READ(REG_FLASH_OPERATE_SW) & FLASH_BUSY_SW) {}
|
||||
FlashId id = {
|
||||
.manufacturerId = REG_RD8(REG_FLASH_RDID, 2),
|
||||
.chipId = REG_RD8(REG_FLASH_RDID, 1),
|
||||
.chipSizeId = REG_RD8(REG_FLASH_RDID, 0),
|
||||
};
|
||||
return id;
|
||||
}
|
||||
|
||||
/* Memory management */
|
||||
|
||||
uint32_t LibreTuya::getRamSize() {
|
||||
return 256 * 1024;
|
||||
}
|
||||
|
||||
uint32_t LibreTuya::getHeapSize() {
|
||||
#if configDYNAMIC_HEAP_SIZE
|
||||
extern unsigned char _empty_ram;
|
||||
#if CFG_SOC_NAME == SOC_BK7231N
|
||||
return (0x00400000 + 192 * 1024) - (uint32_t)(&_empty_ram);
|
||||
#else
|
||||
return (0x00400000 + 256 * 1024) - (uint32_t)(&_empty_ram);
|
||||
#endif
|
||||
#else
|
||||
return configTOTAL_HEAP_SIZE;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t LibreTuya::getFreeHeap() {
|
||||
return xPortGetFreeHeapSize();
|
||||
}
|
||||
|
||||
uint32_t LibreTuya::getMinFreeHeap() {
|
||||
return xPortGetMinimumEverFreeHeapSize();
|
||||
}
|
||||
|
||||
uint32_t LibreTuya::getMaxAllocHeap() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* OTA-related */
|
||||
|
||||
static int8_t otaImage2Valid = -1;
|
||||
|
||||
uint8_t LibreTuya::otaGetRunning() {
|
||||
// Beken has bootloader-based OTA, running app is always index 1
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t LibreTuya::otaGetStoredIndex() {
|
||||
return otaHasImage2() ? 2 : 1;
|
||||
}
|
||||
|
||||
bool LibreTuya::otaSupportsDual() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LibreTuya::otaHasImage1() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LibreTuya::otaHasImage2() {
|
||||
if (otaImage2Valid != -1)
|
||||
return otaImage2Valid;
|
||||
// check download RBL
|
||||
// TODO: maybe check header CRC or even binary hashes
|
||||
uint32_t magic;
|
||||
Flash.readBlock(FLASH_DOWNLOAD_OFFSET, (uint8_t *)&magic, 4);
|
||||
otaImage2Valid = magic == 0x004C4252; // "RBL\0", little-endian
|
||||
return otaImage2Valid;
|
||||
}
|
||||
|
||||
bool LibreTuya::otaSwitch(bool force) {
|
||||
// no need to check otaGetStoredIndex() as it does the same as otaHasImage2()
|
||||
|
||||
// force checking validity again
|
||||
otaImage2Valid = -1;
|
||||
|
||||
if (otaHasImage2() && force) {
|
||||
// "rollback" - abort bootloader upgrade operation by wiping first sector
|
||||
return Flash.eraseSector(FLASH_DOWNLOAD_OFFSET);
|
||||
}
|
||||
|
||||
return otaHasImage2(); // false if second image is not valid
|
||||
}
|
||||
|
||||
/* Watchdog */
|
||||
|
||||
bool LibreTuya::wdtEnable(uint32_t timeout) {
|
||||
wdt_ctrl(WCMD_SET_PERIOD, &timeout);
|
||||
wdt_ctrl(WCMD_POWER_UP, NULL);
|
||||
}
|
||||
|
||||
void LibreTuya::wdtDisable() {
|
||||
wdt_ctrl(WCMD_POWER_DOWN, NULL);
|
||||
}
|
||||
|
||||
void LibreTuya::wdtFeed() {
|
||||
wdt_ctrl(WCMD_RELOAD_PERIOD, NULL);
|
||||
}
|
||||
|
||||
/* Global instance */
|
||||
|
||||
LibreTuya LT;
|
||||
LibreTuya ESP = LT;
|
||||
@@ -1,109 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-06-23. */
|
||||
|
||||
#include "SerialClass.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
#include <uart_pub.h>
|
||||
|
||||
extern void bk_send_byte(uint8_t uport, uint8_t data);
|
||||
extern void uart_hw_set_change(uint8_t uport, bk_uart_config_t *uart_config);
|
||||
extern int uart_rx_callback_set(int uport, uart_callback callback, void *param);
|
||||
|
||||
} // extern "C"
|
||||
|
||||
#ifdef PIN_SERIAL1_TX
|
||||
SerialClass Serial1(UART1_PORT);
|
||||
#endif
|
||||
#ifdef PIN_SERIAL2_TX
|
||||
SerialClass Serial2(UART2_PORT);
|
||||
#endif
|
||||
|
||||
SerialClass::SerialClass(uint8_t port) {
|
||||
this->port = port;
|
||||
this->buf = NULL;
|
||||
}
|
||||
|
||||
#if LT_AUTO_DOWNLOAD_REBOOT
|
||||
static uint8_t adrState = 0;
|
||||
static const uint8_t adrCmd[] = {0x01, 0xE0, 0xFC, 0x01, 0x00};
|
||||
|
||||
static void adrParse(uint8_t c) {
|
||||
// parse and respond to link check command (CMD_LinkCheck=0)
|
||||
adrState = (adrState + 1) * (c == adrCmd[adrState]);
|
||||
if (adrState == 5) {
|
||||
LT_I("Auto download mode: rebooting");
|
||||
LT.restart();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void callback(int port, void *param) {
|
||||
RingBuffer *buf = (RingBuffer *)param;
|
||||
int ch;
|
||||
while ((ch = uart_read_byte(port)) != -1) {
|
||||
#if LT_AUTO_DOWNLOAD_REBOOT && defined(PIN_SERIAL1_RX)
|
||||
// parse UART protocol commands on UART1
|
||||
if (port == UART1_PORT)
|
||||
adrParse(ch);
|
||||
#endif
|
||||
buf->store_char(ch);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
switch (port) {
|
||||
case 1:
|
||||
uart1_exit();
|
||||
break;
|
||||
case 2:
|
||||
uart2_exit();
|
||||
break;
|
||||
}
|
||||
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;
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-06-18. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "sdk_extern.h"
|
||||
#include "sdk_mem.h"
|
||||
|
||||
// define an inline delay() which overrides BDK's delay()
|
||||
static inline __attribute__((always_inline)) void delay(unsigned long ms) {
|
||||
delayMilliseconds(ms);
|
||||
}
|
||||
|
||||
// from fixups/arch_main.c
|
||||
extern unsigned char __bk_rf_is_init;
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
@@ -1,30 +0,0 @@
|
||||
/* 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
|
||||
@@ -1,20 +0,0 @@
|
||||
/* 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
|
||||
@@ -1,62 +0,0 @@
|
||||
/* 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) || !pinIsInput(pin))
|
||||
pinMode(pinNumber, INPUT);
|
||||
// read the value
|
||||
return gpio_input(pin->gpio);
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-07-31. */
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
static void *irqHandlerList[PINS_COUNT] = {NULL};
|
||||
static void *irqHandlerArgs[PINS_COUNT] = {NULL};
|
||||
static bool irqChangeList[PINS_COUNT];
|
||||
|
||||
static void irqHandler(unsigned char gpio) {
|
||||
int pin = -1;
|
||||
for (pin_size_t i = 0; i < PINS_COUNT; i++) {
|
||||
if (pinTable[i].gpio == gpio) {
|
||||
pin = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pin == -1)
|
||||
return;
|
||||
if (!irqHandlerList[pin])
|
||||
return;
|
||||
if (irqChangeList[pin]) {
|
||||
if (pinTable[pin].mode == INPUT_PULLDOWN) {
|
||||
pinTable[pin].mode = INPUT_PULLUP;
|
||||
gpio_int_enable(pinTable[pin].gpio, GPIO_INT_LEVEL_FALLING, irqHandler);
|
||||
} else if (pinTable[pin].mode == INPUT_PULLUP) {
|
||||
pinTable[pin].mode = INPUT_PULLDOWN;
|
||||
gpio_int_enable(pinTable[pin].gpio, GPIO_INT_LEVEL_RISING, irqHandler);
|
||||
}
|
||||
}
|
||||
if (irqHandlerArgs[pin] == NULL) {
|
||||
((voidFuncPtr)irqHandlerList[pin])();
|
||||
} else {
|
||||
((voidFuncPtrParam)irqHandlerList[pin])(irqHandlerArgs[pin]);
|
||||
}
|
||||
}
|
||||
|
||||
void attachInterrupt(pin_size_t interruptNumber, voidFuncPtr callback, PinStatus mode) {
|
||||
attachInterruptParam(interruptNumber, (voidFuncPtrParam)callback, mode, NULL);
|
||||
}
|
||||
|
||||
void attachInterruptParam(pin_size_t interruptNumber, voidFuncPtrParam callback, PinStatus mode, void *param) {
|
||||
PinInfo *pin = pinInfo(interruptNumber);
|
||||
if (!pin)
|
||||
return;
|
||||
if (!pinSupported(pin, PIN_IRQ))
|
||||
return;
|
||||
uint32_t event = 0;
|
||||
PinMode modeNew = 0;
|
||||
bool change = 0;
|
||||
|
||||
switch (mode) {
|
||||
case LOW:
|
||||
event = GPIO_INT_LEVEL_LOW;
|
||||
modeNew = INPUT_PULLUP;
|
||||
change = false;
|
||||
break;
|
||||
case HIGH:
|
||||
event = GPIO_INT_LEVEL_HIGH;
|
||||
modeNew = INPUT_PULLDOWN;
|
||||
change = false;
|
||||
break;
|
||||
case FALLING:
|
||||
event = GPIO_INT_LEVEL_FALLING;
|
||||
modeNew = INPUT_PULLUP;
|
||||
change = false;
|
||||
break;
|
||||
case RISING:
|
||||
event = GPIO_INT_LEVEL_RISING;
|
||||
modeNew = INPUT_PULLDOWN;
|
||||
change = false;
|
||||
break;
|
||||
case CHANGE:
|
||||
event = GPIO_INT_LEVEL_FALLING;
|
||||
modeNew = INPUT_PULLUP;
|
||||
change = true;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
irqHandlerList[interruptNumber] = callback;
|
||||
irqHandlerArgs[interruptNumber] = param;
|
||||
irqChangeList[interruptNumber] = change;
|
||||
gpio_int_enable(pin->gpio, event, irqHandler);
|
||||
pin->enabled |= PIN_IRQ | PIN_GPIO;
|
||||
pin->mode = modeNew;
|
||||
}
|
||||
|
||||
void detachInterrupt(pin_size_t interruptNumber) {
|
||||
PinInfo *pin = pinInfo(interruptNumber);
|
||||
if (!pin)
|
||||
return;
|
||||
if (!pinSupported(pin, PIN_IRQ))
|
||||
return;
|
||||
irqHandlerList[interruptNumber] = NULL;
|
||||
irqHandlerArgs[interruptNumber] = NULL;
|
||||
irqChangeList[interruptNumber] = false;
|
||||
gpio_int_disable(pin->gpio);
|
||||
pin->enabled &= ~PIN_IRQ;
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-07-11. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#define LT_MD5_USE_HOSTAPD 1
|
||||
@@ -1,10 +0,0 @@
|
||||
/* 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"
|
||||
@@ -1,8 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-06-27. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <api/WiFi/WiFi.h>
|
||||
#include <lwip/LwIPClient.h>
|
||||
|
||||
typedef LwIPClient WiFiClient;
|
||||
@@ -1,8 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-04. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <api/WiFi/WiFi.h>
|
||||
#include <ssl/MbedTLSClient.h>
|
||||
|
||||
typedef MbedTLSClient WiFiClientSecure;
|
||||
@@ -1,25 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-06-26. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
extern "C" {
|
||||
|
||||
#include <FreeRTOS.h>
|
||||
#include <rw_msg_pub.h>
|
||||
#include <semphr.h>
|
||||
|
||||
} // extern "C"
|
||||
|
||||
typedef struct {
|
||||
void *configSta;
|
||||
void *configAp;
|
||||
unsigned long scannedAt;
|
||||
SemaphoreHandle_t scanSem;
|
||||
void *statusIp;
|
||||
void *statusLink;
|
||||
rw_evt_type lastStaEvent;
|
||||
rw_evt_type lastApEvent;
|
||||
bool apEnabled;
|
||||
} WiFiData;
|
||||
@@ -1,90 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-06-26. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <api/WiFi/WiFi.h>
|
||||
|
||||
extern "C" {
|
||||
|
||||
#include <lwip/api.h>
|
||||
#include <lwip/ip_addr.h>
|
||||
#include <lwip/netif.h>
|
||||
// port/net.h
|
||||
#include <net.h>
|
||||
|
||||
#include <FreeRTOS.h>
|
||||
#include <semphr.h>
|
||||
|
||||
#include <common.h>
|
||||
#include <config.h>
|
||||
#include <main_none.h>
|
||||
#include <param_config.h>
|
||||
#include <rw_msg_rx.h>
|
||||
#include <sa_ap.h>
|
||||
#include <sys_ctrl_pub.h>
|
||||
#include <vif_mgmt.h>
|
||||
#include <wlan_ui_pub.h>
|
||||
#include <wpa_supplicant_i.h>
|
||||
|
||||
extern void func_init_extended();
|
||||
extern void app_pre_start();
|
||||
extern void bk_wlan_ap_init(network_InitTypeDef_st *inNetworkInitPara);
|
||||
|
||||
// func/hostapd-2.5/wpa_supplicant/main_supplicant.c
|
||||
extern struct wpa_ssid_value *wpas_connect_ssid;
|
||||
|
||||
// app/param_config.c
|
||||
extern general_param_t *g_wlan_general_param;
|
||||
extern ap_param_t *g_ap_param_ptr;
|
||||
extern sta_param_t *g_sta_param_ptr;
|
||||
extern uint8_t system_mac[6];
|
||||
|
||||
// WiFi.cpp
|
||||
WiFiStatus eventTypeToStatus(uint8_t type);
|
||||
WiFiAuthMode securityTypeToAuthMode(uint8_t type);
|
||||
|
||||
// WiFiEvents.cpp
|
||||
extern void wifiEventSendArduino(EventId event);
|
||||
extern void startWifiTask();
|
||||
extern void wifiEventHandler(rw_evt_type event);
|
||||
|
||||
#define RW_EVT_ARDUINO (1 << 7)
|
||||
|
||||
#define IP_FMT "%u.%u.%u.%u"
|
||||
|
||||
#define STA_CFG ((network_InitTypeDef_st *)data.configSta)
|
||||
#define AP_CFG ((network_InitTypeDef_ap_st *)data.configAp)
|
||||
#define IP_STATUS ((IPStatusTypedef *)data.statusIp)
|
||||
#define LINK_STATUS ((LinkStatusTypeDef *)data.statusLink)
|
||||
|
||||
#define STA_GET_LINK_STATUS_RETURN(ret) \
|
||||
{ \
|
||||
if (!sta_ip_is_start()) \
|
||||
return ret; \
|
||||
memset(LINK_STATUS, 0x00, sizeof(LinkStatusTypeDef)); \
|
||||
bk_wlan_get_link_status(LINK_STATUS); \
|
||||
}
|
||||
|
||||
#define STA_GET_IP_STATUS_RETURN(ret) \
|
||||
{ \
|
||||
if (!sta_ip_is_start()) \
|
||||
return ret; \
|
||||
memset(IP_STATUS, 0x00, sizeof(IPStatusTypedef)); \
|
||||
bk_wlan_get_ip_status(IP_STATUS, BK_STATION); \
|
||||
}
|
||||
|
||||
#define AP_GET_LINK_STATUS_RETURN(ret) \
|
||||
{ \
|
||||
if (!uap_ip_is_start()) \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
#define AP_GET_IP_STATUS_RETURN(ret) \
|
||||
{ \
|
||||
if (!uap_ip_is_start()) \
|
||||
return ret; \
|
||||
memset(IP_STATUS, 0x00, sizeof(IPStatusTypedef)); \
|
||||
bk_wlan_get_ip_status(IP_STATUS, BK_SOFT_AP); \
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
@@ -1,224 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-06-27. */
|
||||
|
||||
#include "WiFiPriv.h"
|
||||
|
||||
WiFiStatus
|
||||
WiFiClass::begin(const char *ssid, const char *passphrase, int32_t channel, const uint8_t *bssid, bool connect) {
|
||||
if (!enableSTA(true))
|
||||
return WL_CONNECT_FAILED;
|
||||
if (!validate(ssid, passphrase))
|
||||
return WL_CONNECT_FAILED;
|
||||
|
||||
LT_HEAP_I();
|
||||
|
||||
disconnect(false);
|
||||
|
||||
strcpy(STA_CFG->wifi_ssid, ssid);
|
||||
if (passphrase) {
|
||||
strcpy(STA_CFG->wifi_key, passphrase);
|
||||
} else {
|
||||
STA_CFG->wifi_bssid[0] = '\0';
|
||||
}
|
||||
|
||||
if (reconnect(bssid))
|
||||
return WL_CONNECTED;
|
||||
|
||||
return WL_CONNECT_FAILED;
|
||||
}
|
||||
|
||||
bool WiFiClass::config(IPAddress localIP, IPAddress gateway, IPAddress subnet, IPAddress dns1, IPAddress dns2) {
|
||||
dataInitialize();
|
||||
|
||||
STA_CFG->dhcp_mode = localIP ? DHCP_DISABLE : DHCP_CLIENT;
|
||||
if (localIP) {
|
||||
sprintf(STA_CFG->local_ip_addr, IP_FMT, localIP[0], localIP[1], localIP[2], localIP[3]);
|
||||
sprintf(STA_CFG->net_mask, IP_FMT, subnet[0], subnet[1], subnet[2], subnet[3]);
|
||||
sprintf(STA_CFG->gateway_ip_addr, IP_FMT, gateway[0], gateway[1], gateway[2], gateway[3]);
|
||||
if (dns1) {
|
||||
sprintf(STA_CFG->dns_server_ip_addr, IP_FMT, dns1[0], dns1[1], dns1[2], dns1[3]);
|
||||
} else {
|
||||
STA_CFG->dns_server_ip_addr[0] = '\0';
|
||||
}
|
||||
} else {
|
||||
STA_CFG->local_ip_addr[0] = '\0';
|
||||
STA_CFG->net_mask[0] = '\0';
|
||||
STA_CFG->gateway_ip_addr[0] = '\0';
|
||||
STA_CFG->dns_server_ip_addr[0] = '\0';
|
||||
}
|
||||
|
||||
// from wlan_ui.c:1370
|
||||
if (sta_ip_is_start()) {
|
||||
sta_ip_down();
|
||||
ip_address_set(
|
||||
BK_STATION,
|
||||
STA_CFG->dhcp_mode,
|
||||
STA_CFG->local_ip_addr,
|
||||
STA_CFG->net_mask,
|
||||
STA_CFG->gateway_ip_addr,
|
||||
STA_CFG->dns_server_ip_addr
|
||||
);
|
||||
sta_ip_start();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WiFiClass::reconnect(const uint8_t *bssid) {
|
||||
dataInitialize();
|
||||
if (!bssid && !STA_CFG->wifi_ssid[0]) {
|
||||
LT_EM(WIFI, "(B)SSID not specified");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (bssid) {
|
||||
LT_IM(WIFI, "Connecting to " MACSTR, MAC2STR(bssid));
|
||||
} else {
|
||||
LT_IM(WIFI, "Connecting to %s", STA_CFG->wifi_ssid);
|
||||
}
|
||||
|
||||
LT_DM(WIFI, "Data = %p", data.configSta);
|
||||
|
||||
STA_CFG->wifi_mode = BK_STATION;
|
||||
STA_CFG->wifi_retry_interval = 100;
|
||||
if (bssid)
|
||||
memcpy(STA_CFG->wifi_bssid, bssid, 6);
|
||||
else
|
||||
memset(STA_CFG->wifi_bssid, 0x00, 6);
|
||||
|
||||
if (STA_CFG->dhcp_mode == DHCP_DISABLE) {
|
||||
LT_DM(WIFI, "Static IP: %s / %s / %s", STA_CFG->local_ip_addr, STA_CFG->net_mask, STA_CFG->gateway_ip_addr);
|
||||
LT_DM(WIFI, "Static DNS: %s", STA_CFG->dns_server_ip_addr);
|
||||
} else {
|
||||
LT_DM(WIFI, "Using DHCP");
|
||||
}
|
||||
|
||||
LT_DM(WIFI, "Starting WiFi...");
|
||||
|
||||
__wrap_bk_printf_disable();
|
||||
bk_wlan_start_sta(STA_CFG);
|
||||
__wrap_bk_printf_enable();
|
||||
|
||||
LT_DM(WIFI, "Start OK");
|
||||
return true;
|
||||
|
||||
error:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WiFiClass::disconnect(bool wifiOff) {
|
||||
#if LT_DEBUG_WIFI
|
||||
memset(LINK_STATUS, 0x00, sizeof(LinkStatusTypeDef));
|
||||
bk_wlan_get_link_status(LINK_STATUS);
|
||||
LT_DM(WIFI, "Disconnecting from %s (wifiOff=%d)", LINK_STATUS ? LINK_STATUS->ssid : NULL, wifiOff);
|
||||
#endif
|
||||
bk_wlan_connection_loss();
|
||||
if (wifiOff)
|
||||
enableSTA(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WiFiClass::setAutoReconnect(bool autoReconnect) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WiFiClass::getAutoReconnect() {
|
||||
return false;
|
||||
}
|
||||
|
||||
IPAddress WiFiClass::localIP() {
|
||||
STA_GET_IP_STATUS_RETURN((uint32_t)0);
|
||||
IPAddress ip;
|
||||
ip.fromString(IP_STATUS->ip);
|
||||
return ip;
|
||||
}
|
||||
|
||||
IPAddress WiFiClass::subnetMask() {
|
||||
STA_GET_IP_STATUS_RETURN((uint32_t)0);
|
||||
IPAddress ip;
|
||||
ip.fromString(IP_STATUS->mask);
|
||||
return ip;
|
||||
}
|
||||
|
||||
IPAddress WiFiClass::gatewayIP() {
|
||||
STA_GET_IP_STATUS_RETURN((uint32_t)0);
|
||||
IPAddress ip;
|
||||
ip.fromString(IP_STATUS->gate);
|
||||
return ip;
|
||||
}
|
||||
|
||||
IPAddress WiFiClass::dnsIP(uint8_t dns_no) {
|
||||
STA_GET_IP_STATUS_RETURN((uint32_t)0);
|
||||
IPAddress ip;
|
||||
ip.fromString(IP_STATUS->dns);
|
||||
return ip;
|
||||
}
|
||||
|
||||
IPAddress WiFiClass::broadcastIP() {
|
||||
return calculateBroadcast(localIP(), subnetMask());
|
||||
}
|
||||
|
||||
const char *WiFiClass::getHostname() {
|
||||
struct netif *ifs = (struct netif *)net_get_sta_handle();
|
||||
return netif_get_hostname(ifs);
|
||||
}
|
||||
|
||||
bool WiFiClass::setHostname(const char *hostname) {
|
||||
struct netif *ifs = (struct netif *)net_get_sta_handle();
|
||||
netif_set_hostname(ifs, (char *)hostname);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t *WiFiClass::macAddress(uint8_t *mac) {
|
||||
wifi_get_mac_address((char *)mac, CONFIG_ROLE_STA);
|
||||
return mac;
|
||||
}
|
||||
|
||||
bool WiFiClass::setMacAddress(const uint8_t *mac) {
|
||||
if (mac[0] & 0x01) {
|
||||
LT_EM(WIFI, "Invalid MAC address");
|
||||
return false;
|
||||
}
|
||||
// ensure "mac_inited" is true
|
||||
wifi_get_mac_address((char *)system_mac, BK_STATION);
|
||||
// store the MAC globally
|
||||
memcpy(system_mac, mac, 6);
|
||||
WiFiMode previousMode = getMode();
|
||||
if (previousMode) {
|
||||
mode(WIFI_MODE_NULL);
|
||||
mode(previousMode);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const String WiFiClass::SSID() {
|
||||
STA_GET_LINK_STATUS_RETURN("");
|
||||
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() {
|
||||
STA_GET_LINK_STATUS_RETURN(NULL);
|
||||
return LINK_STATUS->bssid;
|
||||
}
|
||||
|
||||
int32_t WiFiClass::channel() {
|
||||
STA_GET_LINK_STATUS_RETURN(0);
|
||||
return LINK_STATUS->channel;
|
||||
}
|
||||
|
||||
int8_t WiFiClass::RSSI() {
|
||||
STA_GET_LINK_STATUS_RETURN(0);
|
||||
return LINK_STATUS->wifi_strength;
|
||||
}
|
||||
|
||||
WiFiAuthMode WiFiClass::getEncryption() {
|
||||
STA_GET_LINK_STATUS_RETURN(WIFI_AUTH_INVALID);
|
||||
return securityTypeToAuthMode(LINK_STATUS->security);
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-06-27. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <api/WiFi/WiFi.h>
|
||||
#include <lwip/LwIPServer.h>
|
||||
|
||||
typedef LwIPServer WiFiServer;
|
||||
@@ -1,8 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-09-10. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <api/WiFi/WiFi.h>
|
||||
#include <lwip/LwIPUdp.h>
|
||||
|
||||
typedef LwIPUDP WiFiUDP;
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2015 Arduino LLC. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
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
|
||||
*/
|
||||
|
||||
/**
|
||||
* Empty yield() hook.
|
||||
*
|
||||
* This function is intended to be used by library writers to build
|
||||
* libraries or sketches that supports cooperative threads.
|
||||
*
|
||||
* Its defined as a weak symbol and it can be redefined to implement a
|
||||
* real cooperative scheduler.
|
||||
*/
|
||||
static void __empty() {
|
||||
// Empty
|
||||
}
|
||||
|
||||
void yield(void) __attribute__((weak, alias("__empty")));
|
||||
|
||||
/**
|
||||
* SysTick hook
|
||||
*
|
||||
* This function is called from SysTick handler, before the default
|
||||
* handler provided by Arduino.
|
||||
*/
|
||||
static int __false() {
|
||||
// Return false
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sysTickHook(void) __attribute__((weak, alias("__false")));
|
||||
|
||||
/**
|
||||
* SVC hook
|
||||
* PendSV hook
|
||||
*
|
||||
* These functions are called from SVC handler, and PensSV handler.
|
||||
* Default action is halting.
|
||||
*/
|
||||
static void __halt() {
|
||||
// Halts
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
void svcHook(void) __attribute__((weak, alias("__halt")));
|
||||
void pendSVHook(void) __attribute__((weak, alias("__halt")));
|
||||
@@ -1,37 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-28. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#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_BK7231U = 0x675A40B0, // Beken 7231U/7231T
|
||||
F_BK7231N = 0x7B3EF230, // Beken 7231N
|
||||
F_BK7251 = 0x6A82CC42, // Beken 7251/7252
|
||||
F_BL602 = 0xDE1270B7, // Boufallo 602
|
||||
F_XR809 = 0x51E903A8, // Xradiotech 809
|
||||
F_NATIVE = 0xDEADBEEF, // Host-native
|
||||
};
|
||||
|
||||
enum ChipType {
|
||||
// Realtek AmebaZ
|
||||
// IDs copied from rtl8710b_efuse.h
|
||||
RTL8710BL = CHIP_TYPE(F_RTL8710B, 0xE0), // ???
|
||||
RTL8710BN = CHIP_TYPE(F_RTL8710B, 0xFF), // CHIPID_8710BN / QFN32
|
||||
RTL8710BU = CHIP_TYPE(F_RTL8710B, 0xFE), // CHIPID_8710BU / QFN48
|
||||
RTL8710BX = CHIP_TYPE(F_RTL8710B, 0xF6), // found on an actual RTL8710BX
|
||||
RTL8710L0 = CHIP_TYPE(F_RTL8710B, 0xFB), // CHIPID_8710BN_L0 / QFN32
|
||||
RTL8711BN = CHIP_TYPE(F_RTL8710B, 0xFD), // CHIPID_8711BN / QFN48
|
||||
RTL8711BU = CHIP_TYPE(F_RTL8710B, 0xFC), // CHIPID_8711BG / QFN68
|
||||
// Beken 72XX
|
||||
BK7231T = CHIP_TYPE(F_BK7231U, 0x1A), // *SCTRL_CHIP_ID = 0x7231a
|
||||
BK7231N = CHIP_TYPE(F_BK7231N, 0x1C), // *SCTRL_CHIP_ID = 0x7231c
|
||||
BL2028N = CHIP_TYPE(F_BK7231N, 0x1C), // *SCTRL_CHIP_ID = 0x7231c
|
||||
BK7252 = CHIP_TYPE(F_BK7251, 0x00), // TODO
|
||||
};
|
||||
@@ -1,65 +0,0 @@
|
||||
/* 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
|
||||
*/
|
||||
extern "C" {
|
||||
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(const 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-04-28. */
|
||||
|
||||
#pragma once
|
||||
|
||||
// C standard libraries
|
||||
#include <inttypes.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// C++ standard libraries
|
||||
#ifdef __cplusplus
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
using ::round;
|
||||
using std::abs;
|
||||
using std::isinf;
|
||||
using std::isnan;
|
||||
using std::max;
|
||||
using std::min;
|
||||
#endif
|
||||
|
||||
// LibreTuya version macros
|
||||
#ifndef LT_VERSION
|
||||
#define LT_VERSION 1.0.0
|
||||
#endif
|
||||
#ifndef LT_BOARD
|
||||
#define LT_BOARD unknown
|
||||
#endif
|
||||
#define STRINGIFY(x) #x
|
||||
#define STRINGIFY_MACRO(x) STRINGIFY(x)
|
||||
#define LT_VERSION_STR STRINGIFY_MACRO(LT_VERSION)
|
||||
#define LT_BOARD_STR STRINGIFY_MACRO(LT_BOARD)
|
||||
|
||||
// Includes
|
||||
#include "LibreTuyaClass.h" // global LT class
|
||||
#include "LibreTuyaCompat.h" // compatibility methods
|
||||
#include "LibreTuyaConfig.h" // configuration macros
|
||||
#include "LibreTuyaCustom.h" // family-defined methods (Wiring custom)
|
||||
#include <Arduino.h>
|
||||
|
||||
// C includes
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#include "lt_logger.h"
|
||||
#include "lt_posix_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
// Functional macros
|
||||
#define LT_BANNER() \
|
||||
LT_LOG( \
|
||||
LT_LEVEL_INFO, \
|
||||
__FUNCTION__, \
|
||||
__LINE__, \
|
||||
"LibreTuya v" LT_VERSION_STR " on " LT_BOARD_STR ", compiled at " __DATE__ " " __TIME__ \
|
||||
)
|
||||
|
||||
#ifdef __cplusplus
|
||||
String ipToString(const IPAddress &ip);
|
||||
|
||||
extern "C" {
|
||||
void lt_rand_bytes(uint8_t *buf, size_t len);
|
||||
void hexdump(const uint8_t *buf, size_t len, uint32_t offset = 0, uint8_t width = 16);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void lt_rand_bytes(uint8_t *buf, size_t len);
|
||||
void hexdump(const uint8_t *buf, size_t len, uint32_t offset, uint8_t width);
|
||||
|
||||
#endif
|
||||
@@ -1,148 +0,0 @@
|
||||
/* 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 a textual representation of a reset reason.
|
||||
*
|
||||
* @param reason value to convert to text, uses getResetReason() by default
|
||||
*/
|
||||
const char *LibreTuya::getResetReasonName(ResetReason reason) {
|
||||
if (reason >= RESET_REASON_MAX)
|
||||
reason = getResetReason();
|
||||
switch (reason) {
|
||||
case RESET_REASON_POWER:
|
||||
return "Power-On";
|
||||
case RESET_REASON_BROWNOUT:
|
||||
return "Brownout";
|
||||
case RESET_REASON_HARDWARE:
|
||||
return "HW Reboot";
|
||||
case RESET_REASON_SOFTWARE:
|
||||
return "SW Reboot";
|
||||
case RESET_REASON_WATCHDOG:
|
||||
return "WDT Reset";
|
||||
case RESET_REASON_CRASH:
|
||||
return "Crash";
|
||||
case RESET_REASON_SLEEP:
|
||||
return "Sleep Wakeup";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
}
|
||||
|
||||
/**
|
||||
* @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: switch to the previous image, or abort current
|
||||
* switched OTA update, if not rebooted yet.
|
||||
*
|
||||
* @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
|
||||
}
|
||||
@@ -1,193 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-06-06. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "LibreTuyaAPI.h"
|
||||
#include <core/ChipType.h>
|
||||
|
||||
typedef enum {
|
||||
RESET_REASON_UNKNOWN = 0,
|
||||
RESET_REASON_POWER = 1,
|
||||
RESET_REASON_BROWNOUT = 2,
|
||||
RESET_REASON_HARDWARE = 3,
|
||||
RESET_REASON_SOFTWARE = 4,
|
||||
RESET_REASON_WATCHDOG = 5,
|
||||
RESET_REASON_CRASH = 6,
|
||||
RESET_REASON_SLEEP = 7,
|
||||
RESET_REASON_MAX = 8,
|
||||
} ResetReason;
|
||||
|
||||
/**
|
||||
* @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();
|
||||
const char *getResetReasonName(ResetReason reason = RESET_REASON_MAX);
|
||||
uint32_t getCpuFreqMHz();
|
||||
uint32_t getFlashChipSize();
|
||||
uint8_t otaGetTarget();
|
||||
bool otaRollback();
|
||||
bool otaCanRollback();
|
||||
|
||||
public: /* Compatibility methods */
|
||||
/**
|
||||
* @brief Alias of getMaxAllocHeap().
|
||||
*/
|
||||
inline uint32_t getMaxFreeBlockSize() {
|
||||
return getMaxAllocHeap();
|
||||
}
|
||||
|
||||
public: /* Family-defined methods */
|
||||
/**
|
||||
* @brief Reboot the CPU.
|
||||
*/
|
||||
void restart();
|
||||
/**
|
||||
* @brief Reboot the CPU and stay in download mode (if possible).
|
||||
*/
|
||||
void restartDownloadMode();
|
||||
/**
|
||||
* @brief Get the reason of last chip reset.
|
||||
*/
|
||||
ResetReason getResetReason();
|
||||
/**
|
||||
* @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 Get the currently running firmware OTA index.
|
||||
*/
|
||||
uint8_t otaGetRunning();
|
||||
/**
|
||||
* @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 (i.e. OTA is flashed to a different partition).
|
||||
*
|
||||
* TODO: make this work for actual dual-OTA chips; remove checking this in otaGetTarget() etc.
|
||||
*/
|
||||
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);
|
||||
|
||||
public: /* Watchdog */
|
||||
/**
|
||||
* @brief Enable the hardware watchdog.
|
||||
*
|
||||
* @param timeout watchdog timeout, milliseconds (defaults to 10s)
|
||||
* @return whether the chip has a hardware watchdog
|
||||
*/
|
||||
bool wdtEnable(uint32_t timeout = 10000);
|
||||
/**
|
||||
* @brief Disable the hardware watchdog.
|
||||
*/
|
||||
void wdtDisable();
|
||||
/**
|
||||
* @brief Feed/reset the hardware watchdog timer.
|
||||
*/
|
||||
void wdtFeed();
|
||||
};
|
||||
|
||||
extern LibreTuya LT;
|
||||
extern LibreTuya ESP;
|
||||
|
||||
#endif
|
||||
@@ -1,33 +0,0 @@
|
||||
/* 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
|
||||
@@ -1,25 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-07-04. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#ifdef HAS_SERIAL_CLASS // failsafe for circular inclusion
|
||||
|
||||
#ifdef PIN_SERIAL0_TX
|
||||
extern SerialClass Serial0;
|
||||
#endif
|
||||
|
||||
#ifdef PIN_SERIAL1_TX
|
||||
extern SerialClass Serial1;
|
||||
#endif
|
||||
|
||||
#ifdef PIN_SERIAL2_TX
|
||||
extern SerialClass Serial2;
|
||||
#endif
|
||||
|
||||
#define SerialN(x) Serial##x
|
||||
#define SerialM(x) SerialN(x)
|
||||
#define Serial SerialM(LT_UART_DEFAULT_SERIAL)
|
||||
|
||||
#endif
|
||||
@@ -1,170 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-04-28. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "LibreTuyaConfig.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#if LT_LOGGER_CALLER
|
||||
#define LT_LOG(level, caller, line, ...) lt_log(level, caller, line, __VA_ARGS__)
|
||||
#define LT_LOGM(level, module, caller, line, ...) \
|
||||
do { \
|
||||
if (LT_DEBUG_##module) { \
|
||||
lt_log(level, caller, line, #module ": " __VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
void lt_log(const uint8_t level, const char *caller, const unsigned short line, const char *format, ...)
|
||||
__attribute__((format(printf, 4, 5)));
|
||||
#else
|
||||
#define LT_LOG(level, caller, line, ...) lt_log(level, __VA_ARGS__)
|
||||
#define LT_LOGM(level, module, caller, line, ...) \
|
||||
do { \
|
||||
if (LT_DEBUG_##module) { \
|
||||
lt_log(level, #module ": " __VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
void lt_log(const uint8_t level, const char *format, ...) __attribute__((format(printf, 2, 3)));
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Change log output port.
|
||||
*
|
||||
* @param port UART port index - can be 0, 1 or 2
|
||||
*/
|
||||
void lt_log_set_port(uint8_t port);
|
||||
|
||||
/**
|
||||
* @brief Disable LT logger. Enable it back using lt_log_set_port(LT_UART_DEFAULT_LOGGER).
|
||||
*/
|
||||
void lt_log_disable();
|
||||
|
||||
#if LT_LEVEL_TRACE >= LT_LOGLEVEL
|
||||
#define LT_T(...) LT_LOG(LT_LEVEL_TRACE, __FUNCTION__, __LINE__, __VA_ARGS__)
|
||||
#define LT_V(...) LT_LOG(LT_LEVEL_TRACE, __FUNCTION__, __LINE__, __VA_ARGS__)
|
||||
#define LT_TM(module, ...) LT_LOGM(LT_LEVEL_TRACE, module, __FUNCTION__, __LINE__, __VA_ARGS__)
|
||||
#define LT_VM(module, ...) LT_LOGM(LT_LEVEL_TRACE, module, __FUNCTION__, __LINE__, __VA_ARGS__)
|
||||
#else
|
||||
#define LT_T(...)
|
||||
#define LT_V(...)
|
||||
#define LT_TM(...)
|
||||
#define LT_VM(...)
|
||||
#endif
|
||||
|
||||
#if LT_LEVEL_DEBUG >= LT_LOGLEVEL
|
||||
#define LT_D(...) LT_LOG(LT_LEVEL_DEBUG, __FUNCTION__, __LINE__, __VA_ARGS__)
|
||||
#define LT_DM(module, ...) LT_LOGM(LT_LEVEL_DEBUG, module, __FUNCTION__, __LINE__, __VA_ARGS__)
|
||||
#else
|
||||
#define LT_D(...)
|
||||
#define LT_DM(...)
|
||||
#endif
|
||||
|
||||
#if LT_LEVEL_INFO >= LT_LOGLEVEL
|
||||
#define LT_I(...) LT_LOG(LT_LEVEL_INFO, __FUNCTION__, __LINE__, __VA_ARGS__)
|
||||
#define LT_IM(module, ...) LT_LOGM(LT_LEVEL_INFO, module, __FUNCTION__, __LINE__, __VA_ARGS__)
|
||||
#else
|
||||
#define LT_I(...)
|
||||
#define LT_IM(...)
|
||||
#endif
|
||||
|
||||
#if LT_LEVEL_WARN >= LT_LOGLEVEL
|
||||
#define LT_W(...) LT_LOG(LT_LEVEL_WARN, __FUNCTION__, __LINE__, __VA_ARGS__)
|
||||
#define LT_WM(module, ...) LT_LOGM(LT_LEVEL_WARN, module, __FUNCTION__, __LINE__, __VA_ARGS__)
|
||||
#else
|
||||
#define LT_W(...)
|
||||
#define LT_WM(...)
|
||||
#endif
|
||||
|
||||
#if LT_LEVEL_ERROR >= LT_LOGLEVEL
|
||||
#define LT_E(...) LT_LOG(LT_LEVEL_ERROR, __FUNCTION__, __LINE__, __VA_ARGS__)
|
||||
#define LT_EM(module, ...) LT_LOGM(LT_LEVEL_ERROR, module, __FUNCTION__, __LINE__, __VA_ARGS__)
|
||||
#else
|
||||
#define LT_E(...)
|
||||
#define LT_EM(...)
|
||||
#endif
|
||||
|
||||
#if LT_LEVEL_FATAL >= LT_LOGLEVEL
|
||||
#define LT_F(...) LT_LOG(LT_LEVEL_FATAL, __FUNCTION__, __LINE__, __VA_ARGS__)
|
||||
#define LT_FM(module, ...) LT_LOGM(LT_LEVEL_FATAL, module, __FUNCTION__, __LINE__, __VA_ARGS__)
|
||||
#else
|
||||
#define LT_F(...)
|
||||
#define LT_FM(...)
|
||||
#endif
|
||||
|
||||
#if LT_LOG_HEAP
|
||||
#define LT_HEAP_I() LT_I("Free heap: %u", LT_HEAP_FUNC());
|
||||
#else
|
||||
#define LT_HEAP_I()
|
||||
#endif
|
||||
|
||||
// ESP32 compat
|
||||
#define log_printf(...) LT_I(__VA_ARGS__)
|
||||
#define log_v(...) LT_V(__VA_ARGS__)
|
||||
#define log_d(...) LT_D(__VA_ARGS__)
|
||||
#define log_i(...) LT_I(__VA_ARGS__)
|
||||
#define log_w(...) LT_W(__VA_ARGS__)
|
||||
#define log_e(...) LT_E(__VA_ARGS__)
|
||||
#define log_n(...) LT_E(__VA_ARGS__)
|
||||
#define isr_log_v(...) LT_V(__VA_ARGS__)
|
||||
#define isr_log_d(...) LT_D(__VA_ARGS__)
|
||||
#define isr_log_i(...) LT_I(__VA_ARGS__)
|
||||
#define isr_log_w(...) LT_W(__VA_ARGS__)
|
||||
#define isr_log_e(...) LT_E(__VA_ARGS__)
|
||||
#define isr_log_n(...) LT_E(__VA_ARGS__)
|
||||
#define ESP_LOGV(...) LT_V(__VA_ARGS__)
|
||||
#define ESP_LOGD(...) LT_D(__VA_ARGS__)
|
||||
#define ESP_LOGI(...) LT_I(__VA_ARGS__)
|
||||
#define ESP_LOGW(...) LT_W(__VA_ARGS__)
|
||||
#define ESP_LOGE(...) LT_E(__VA_ARGS__)
|
||||
#define ESP_EARLY_LOGV(...) LT_V(__VA_ARGS__)
|
||||
#define ESP_EARLY_LOGD(...) LT_D(__VA_ARGS__)
|
||||
#define ESP_EARLY_LOGI(...) LT_I(__VA_ARGS__)
|
||||
#define ESP_EARLY_LOGW(...) LT_W(__VA_ARGS__)
|
||||
#define ESP_EARLY_LOGE(...) LT_E(__VA_ARGS__)
|
||||
#define ets_printf(...) LT_I(__VA_ARGS__)
|
||||
#define ETS_PRINTF(...) LT_I(__VA_ARGS__)
|
||||
|
||||
#define LT_RET(ret) \
|
||||
LT_E("ret=%d", ret); \
|
||||
return ret;
|
||||
|
||||
#define LT_RET_NZ(ret) \
|
||||
if (ret) { \
|
||||
LT_E("ret=%d", ret); \
|
||||
return ret; \
|
||||
}
|
||||
#define LT_RET_LZ(ret) \
|
||||
if (ret < 0) { \
|
||||
LT_E("ret=%d", ret); \
|
||||
return ret; \
|
||||
}
|
||||
#define LT_RET_LEZ(ret) \
|
||||
if (ret <= 0) { \
|
||||
LT_E("ret=%d", ret); \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
#define LT_ERRNO_NZ(ret) \
|
||||
if (ret) { \
|
||||
LT_E("errno=%d, ret=%d", errno, ret); \
|
||||
return ret; \
|
||||
}
|
||||
#define LT_ERRNO_LZ(ret) \
|
||||
if (ret < 0) { \
|
||||
LT_E("errno=%d, ret=%d", errno, ret); \
|
||||
return ret; \
|
||||
}
|
||||
#define LT_ERRNO_LEZ(ret) \
|
||||
if (ret <= 0) { \
|
||||
LT_E("errno=%d, ret=%d", errno, ret); \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
#if LT_LOG_ERRNO
|
||||
#define LT_ERRNO() \
|
||||
if (errno) { \
|
||||
LT_E("errno=%d", errno); \
|
||||
errno = 0; \
|
||||
}
|
||||
#else
|
||||
#define LT_ERRNO()
|
||||
#endif
|
||||
@@ -1,74 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-06-19. */
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <api/HardwareSerial.h>
|
||||
|
||||
using namespace arduino;
|
||||
|
||||
extern "C" {
|
||||
#include <fal.h>
|
||||
fal_partition_t fal_root_part = NULL;
|
||||
}
|
||||
|
||||
// Arduino framework initialization.
|
||||
// May be redefined by family files.
|
||||
void initArduino() __attribute__((weak));
|
||||
|
||||
// Weak empty variant initialization function.
|
||||
// May be redefined by variant files.
|
||||
void initVariant() __attribute__((weak));
|
||||
|
||||
// Initialize C library
|
||||
extern "C" void __libc_init_array(void);
|
||||
|
||||
void mainTask(const void *arg) {
|
||||
setup();
|
||||
|
||||
for (;;) {
|
||||
loop();
|
||||
if (serialEventRun)
|
||||
serialEventRun();
|
||||
yield();
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned long periodicTasks[] = {0, 0};
|
||||
|
||||
void runPeriodicTasks() {
|
||||
#if LT_LOG_HEAP
|
||||
if (millis() - periodicTasks[0] > 1000) {
|
||||
LT_HEAP_I();
|
||||
periodicTasks[0] = millis();
|
||||
}
|
||||
#endif
|
||||
#if LT_USE_TIME
|
||||
if (millis() - periodicTasks[1] > 10000) {
|
||||
gettimeofday(NULL, NULL);
|
||||
periodicTasks[1] = millis();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
// print a startup banner
|
||||
LT_BANNER();
|
||||
// initialize C library
|
||||
__libc_init_array();
|
||||
// inform about the reset reason
|
||||
LT_I("Reset reason: %u", LT.getResetReason());
|
||||
// initialize Arduino framework
|
||||
initArduino();
|
||||
// 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
|
||||
if (!startMainTask()) {
|
||||
LT_F("Couldn't start the main task");
|
||||
}
|
||||
|
||||
while (1) {}
|
||||
return 0;
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/* 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;
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-04-24. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
class FlashClass {
|
||||
public:
|
||||
FlashId getChipId();
|
||||
uint32_t getSize();
|
||||
|
||||
bool eraseSector(uint32_t offset);
|
||||
bool readBlock(uint32_t offset, uint8_t *data, size_t size);
|
||||
bool writeBlock(uint32_t offset, uint8_t *data, size_t size);
|
||||
};
|
||||
|
||||
extern FlashClass Flash;
|
||||
@@ -1,7 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-04-29. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <time.h>
|
||||
|
||||
extern char *strptime(const char *buf, const char *fmt, struct tm *tm);
|
||||
@@ -1,28 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-07-11. */
|
||||
|
||||
#if LT_ARD_HAS_MD5
|
||||
|
||||
#include "MD5.h"
|
||||
|
||||
#if LT_MD5_USE_MBEDTLS
|
||||
|
||||
extern "C" {
|
||||
|
||||
void MD5Init(LT_MD5_CTX_T *context) {
|
||||
mbedtls_md5_init(context);
|
||||
mbedtls_md5_starts(context);
|
||||
}
|
||||
|
||||
void MD5Update(LT_MD5_CTX_T *context, const unsigned char *buf, unsigned len) {
|
||||
mbedtls_md5_update(context, buf, len);
|
||||
}
|
||||
|
||||
void MD5Final(unsigned char digest[16], LT_MD5_CTX_T *context) {
|
||||
mbedtls_md5_finish(context, digest);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
#endif // LT_MD5_USE_MBEDTLS
|
||||
|
||||
#endif // LT_ARD_HAS_MD5
|
||||
@@ -1,14 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-07-11. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <mbedtls/md5.h>
|
||||
#define LT_MD5_CTX_T mbedtls_md5_context
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
@@ -1,28 +0,0 @@
|
||||
/* 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
|
||||
@@ -1,14 +0,0 @@
|
||||
/* 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,224 +0,0 @@
|
||||
/* 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();
|
||||
|
||||
LT_DM(OTA, "begin(%u, ...) / OTA curr: %u, trgt: %u", size, LT.otaGetRunning(), LT.otaGetTarget());
|
||||
|
||||
ctx = uf2_ctx_init(LT.otaGetTarget(), FAMILY);
|
||||
info = uf2_info_init();
|
||||
|
||||
if (!size) {
|
||||
cleanup(UPDATE_ERROR_SIZE);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (command != U_FLASH) {
|
||||
cleanup(UPDATE_ERROR_BAD_ARGUMENT);
|
||||
return false;
|
||||
}
|
||||
|
||||
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
|
||||
cleanup(UPDATE_ERROR_ABORT);
|
||||
return false;
|
||||
}
|
||||
// TODO what is evenIfRemaining for?
|
||||
if (!LT.otaSwitch()) {
|
||||
// try to activate the second OTA
|
||||
cleanup(UPDATE_ERROR_ACTIVATE);
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
LT_VM(OTA, "write(%u) / buf %u/512", len, bufSize());
|
||||
|
||||
/* 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; // 1..512
|
||||
while (len && (toWrite = min(len, bufLeft()))) {
|
||||
tryWriteData(data, toWrite);
|
||||
if (hasError()) {
|
||||
// return on errors
|
||||
printErrorContext2(data, toWrite);
|
||||
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
|
||||
cleanup(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
|
||||
printErrorContext2(NULL, read); // buf is not valid anymore
|
||||
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;
|
||||
|
||||
LT_VM(OTA, "Writing %u to buffer (%u/512)", len, bufSize());
|
||||
|
||||
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 (checkUf2Error(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 (checkUf2Error(uf2_parse_header(ctx, block, info)))
|
||||
// header is invalid
|
||||
return 0;
|
||||
|
||||
LT_IM(OTA, "%s v%s - LT v%s @ %s", info->fw_name, info->fw_version, info->lt_version, info->board);
|
||||
|
||||
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
|
||||
LT_EM(OTA, "Image size wrong; got %u, calculated %u", bytesTotal, block->block_count * UF2_BLOCK_SIZE);
|
||||
cleanup(UPDATE_ERROR_SIZE);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
// write data blocks normally
|
||||
if (checkUf2Error(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;
|
||||
@@ -1,154 +0,0 @@
|
||||
#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(uint8_t ardErr = UPDATE_ERROR_OK, uf2_err_t uf2Err = UF2_ERR_OK);
|
||||
bool checkUf2Error(uf2_err_t err);
|
||||
void bufAlloc();
|
||||
void printErrorContext1();
|
||||
void printErrorContext2(const uint8_t *data, size_t len);
|
||||
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;
|
||||
}
|
||||
|
||||
uint16_t getErrorCode() {
|
||||
return (errArd << 8) | errUf2;
|
||||
}
|
||||
|
||||
void clearError() {
|
||||
cleanup(UPDATE_ERROR_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;
|
||||
@@ -1,190 +0,0 @@
|
||||
/* 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(uint8_t ardErr, uf2_err_t uf2Err) {
|
||||
errUf2 = uf2Err;
|
||||
errArd = ardErr;
|
||||
|
||||
#if LT_DEBUG_OTA
|
||||
if (hasError())
|
||||
printErrorContext1();
|
||||
#endif
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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::checkUf2Error(uf2_err_t err) {
|
||||
if (err <= UF2_ERR_IGNORE)
|
||||
return false;
|
||||
cleanup(errorMap[err], err);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Abort the update with UPDATE_ERROR_ABORT reason.
|
||||
*/
|
||||
void UpdateClass::abort() {
|
||||
LT_DM(OTA, "Aborting update");
|
||||
cleanup(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 Print details about the error and current OTA state.
|
||||
*/
|
||||
void UpdateClass::printErrorContext1() {
|
||||
#if LT_DEBUG_OTA
|
||||
LT_EM(OTA, "Error: %s", errorString());
|
||||
if (errArd == UPDATE_ERROR_ABORT)
|
||||
return;
|
||||
|
||||
LT_EM(OTA, "- written: %u of %u", bytesWritten, bytesTotal);
|
||||
LT_EM(OTA, "- buf: size=%u, left=%u", bufSize(), bufLeft());
|
||||
hexdump(buf, bufSize());
|
||||
|
||||
if (ctx)
|
||||
LT_EM(
|
||||
OTA,
|
||||
"- ctx: seq=%u, part1=%s, part2=%s",
|
||||
ctx->seq - 1, // print last parsed block seq
|
||||
ctx->part1 ? ctx->part1->name : NULL,
|
||||
ctx->part2 ? ctx->part2->name : NULL
|
||||
);
|
||||
|
||||
uf2_block_t *block = (uf2_block_t *)buf;
|
||||
if (buf)
|
||||
LT_EM(OTA, "- buf: seq=%u/%u, addr=%u, len=%u", block->block_seq, block->block_count, block->addr, block->len);
|
||||
#endif
|
||||
}
|
||||
|
||||
void UpdateClass::printErrorContext2(const uint8_t *data, size_t len) {
|
||||
#if LT_DEBUG_OTA
|
||||
LT_EM(OTA, "- while writing %u bytes", len);
|
||||
if (data)
|
||||
hexdump(data, len);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get string representation of the error in format
|
||||
* "ard=..,uf2=..". Returns "" if no error.
|
||||
*/
|
||||
const char *UpdateClass::errorString() {
|
||||
if (!errArd && !errUf2)
|
||||
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();
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
/* Request Methods */
|
||||
#define HTTP_METHOD_MAP(XX) \
|
||||
XX(0, DELETE, DELETE) \
|
||||
XX(1, GET, GET) \
|
||||
XX(2, HEAD, HEAD) \
|
||||
XX(3, POST, POST) \
|
||||
XX(4, PUT, PUT) \
|
||||
/* pathological */ \
|
||||
XX(5, CONNECT, CONNECT) \
|
||||
XX(6, OPTIONS, OPTIONS) \
|
||||
XX(7, TRACE, TRACE) \
|
||||
/* WebDAV */ \
|
||||
XX(8, COPY, COPY) \
|
||||
XX(9, LOCK, LOCK) \
|
||||
XX(10, MKCOL, MKCOL) \
|
||||
XX(11, MOVE, MOVE) \
|
||||
XX(12, PROPFIND, PROPFIND) \
|
||||
XX(13, PROPPATCH, PROPPATCH) \
|
||||
XX(14, SEARCH, SEARCH) \
|
||||
XX(15, UNLOCK, UNLOCK) \
|
||||
XX(16, BIND, BIND) \
|
||||
XX(17, REBIND, REBIND) \
|
||||
XX(18, UNBIND, UNBIND) \
|
||||
XX(19, ACL, ACL) \
|
||||
/* subversion */ \
|
||||
XX(20, REPORT, REPORT) \
|
||||
XX(21, MKACTIVITY, MKACTIVITY) \
|
||||
XX(22, CHECKOUT, CHECKOUT) \
|
||||
XX(23, MERGE, MERGE) \
|
||||
/* upnp */ \
|
||||
XX(24, MSEARCH, M - SEARCH) \
|
||||
XX(25, NOTIFY, NOTIFY) \
|
||||
XX(26, SUBSCRIBE, SUBSCRIBE) \
|
||||
XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \
|
||||
/* RFC-5789 */ \
|
||||
XX(28, PATCH, PATCH) \
|
||||
XX(29, PURGE, PURGE) \
|
||||
/* CalDAV */ \
|
||||
XX(30, MKCALENDAR, MKCALENDAR) \
|
||||
/* RFC-2068, section 19.6.1.2 */ \
|
||||
XX(31, LINK, LINK) \
|
||||
XX(32, UNLINK, UNLINK) \
|
||||
/* icecast */ \
|
||||
XX(33, SOURCE, SOURCE)
|
||||
|
||||
enum http_method {
|
||||
|
||||
#define XX(num, name, string) HTTP_##name = num,
|
||||
HTTP_METHOD_MAP(XX)
|
||||
#undef XX
|
||||
};
|
||||
|
||||
typedef enum http_method HTTPMethod;
|
||||
#define HTTP_ANY (HTTPMethod)(255)
|
||||
@@ -1,131 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-23. */
|
||||
|
||||
#ifdef LT_HAS_LWIP2
|
||||
|
||||
#include "mDNS.h"
|
||||
#include <vector>
|
||||
|
||||
extern "C" {
|
||||
#include <errno.h>
|
||||
#include <lwip/apps/mdns.h>
|
||||
#include <lwip/igmp.h>
|
||||
#include <lwip/init.h>
|
||||
#include <lwip/netif.h>
|
||||
}
|
||||
|
||||
static std::vector<char *> services;
|
||||
static std::vector<uint8_t> protos;
|
||||
static std::vector<std::vector<char *>> records;
|
||||
|
||||
mDNS::mDNS() {}
|
||||
|
||||
mDNS::~mDNS() {}
|
||||
|
||||
static void mdnsTxtCallback(struct mdns_service *service, void *userdata) {
|
||||
size_t index = (size_t)userdata;
|
||||
if (index >= records.size())
|
||||
return;
|
||||
|
||||
for (const auto record : records[index]) {
|
||||
err_t err = mdns_resp_add_service_txtitem(service, record, strlen(record));
|
||||
if (err != ERR_OK)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void mdnsStatusCallback(struct netif *netif, uint8_t result) {
|
||||
LT_DM(MDNS, "Status: netif %u, status %u", netif->num, result);
|
||||
}
|
||||
|
||||
bool mDNS::begin(const char *hostname) {
|
||||
setInstanceName(hostname);
|
||||
LT_DM(MDNS, "Starting (%s)", hostname);
|
||||
#if LWIP_VERSION_MAJOR >= 2 && LWIP_VERSION_MINOR >= 1
|
||||
mdns_resp_register_name_result_cb(mdnsStatusCallback);
|
||||
#endif
|
||||
mdns_resp_init();
|
||||
uint8_t enabled = 0;
|
||||
|
||||
struct netif *netif;
|
||||
for (netif = netif_list; netif != NULL; netif = netif->next) {
|
||||
if (!netif_is_up(netif))
|
||||
continue;
|
||||
|
||||
LT_DM(MDNS, "Adding netif %u", netif->num);
|
||||
if ((netif->flags & NETIF_FLAG_IGMP) == 0) {
|
||||
LT_DM(MDNS, "Enabling IGMP");
|
||||
netif->flags |= NETIF_FLAG_IGMP;
|
||||
igmp_start(netif);
|
||||
}
|
||||
|
||||
err_t ret = mdns_resp_add_netif(netif, hostname, 255);
|
||||
if (ret == ERR_OK)
|
||||
enabled++;
|
||||
else
|
||||
LT_DM(MDNS, "Cannot add netif %u; ret=%d, errno=%d", netif->num, ret, errno);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
bool mDNS::addServiceImpl(const char *name, const char *service, uint8_t proto, uint16_t port) {
|
||||
bool added = false;
|
||||
struct netif *netif = netif_list;
|
||||
while (netif != NULL) {
|
||||
if (netif_is_up(netif)) {
|
||||
// register TXT callback;
|
||||
// pass service index as userdata parameter
|
||||
LT_DM(MDNS, "Add service: netif %u / %s / %s / %u / %u", netif->num, name, service, proto, port);
|
||||
mdns_resp_add_service(
|
||||
netif,
|
||||
name,
|
||||
service,
|
||||
(mdns_sd_proto)proto,
|
||||
port,
|
||||
255,
|
||||
mdnsTxtCallback,
|
||||
(void *)services.size() // index of newly added service
|
||||
);
|
||||
added = true;
|
||||
}
|
||||
netif = netif->next;
|
||||
}
|
||||
|
||||
if (!added)
|
||||
return false;
|
||||
|
||||
// add the service to TXT record arrays
|
||||
services.push_back(strdup(service));
|
||||
protos.push_back(proto);
|
||||
records.emplace_back();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mDNS::addServiceTxtImpl(const char *service, uint8_t proto, const char *item) {
|
||||
int8_t index = -1;
|
||||
for (uint8_t i = 0; i < services.size(); i++) {
|
||||
// find a matching service
|
||||
if (strcmp(services[i], service) == 0 && protos[i] == proto) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (index == -1)
|
||||
return false;
|
||||
|
||||
records[index].push_back(strdup(item));
|
||||
return true;
|
||||
}
|
||||
|
||||
MDNSResponder MDNS;
|
||||
|
||||
#endif
|
||||
@@ -1,129 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-06-19. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibreTuyaConfig.h>
|
||||
|
||||
#define PRINTF_HAS_DISABLE 1
|
||||
|
||||
// make printf.c define wrapper functions
|
||||
#define printf_ __wrap_printf
|
||||
#define sprintf_ __wrap_sprintf
|
||||
#define vsprintf_ __wrap_vsprintf
|
||||
#define snprintf_ __wrap_snprintf
|
||||
#define vsnprintf_ __wrap_vsnprintf
|
||||
#define vprintf_ __wrap_vprintf
|
||||
|
||||
// declare putchar() method with custom output port
|
||||
void putchar_p(char c, unsigned long port);
|
||||
|
||||
#define WRAP_DISABLE_DEF(name) \
|
||||
extern void __wrap_##name##_disable(); \
|
||||
extern void __wrap_##name##_enable(); \
|
||||
extern void __wrap_##name##_set(unsigned char disabled); \
|
||||
extern unsigned char __wrap_##name##_get();
|
||||
|
||||
#if !LT_UART_SILENT_ENABLED || LT_UART_SILENT_ALL
|
||||
|
||||
#define WRAP_DISABLE_DECL(name) \
|
||||
void __wrap_##name##_disable() {} \
|
||||
void __wrap_##name##_enable() {} \
|
||||
void __wrap_##name##_set(unsigned char disabled) {} \
|
||||
unsigned char __wrap_##name##_get() { \
|
||||
return LT_UART_SILENT_ALL; \
|
||||
}
|
||||
|
||||
#define WRAP_DISABLE_CHECK(name) \
|
||||
{ \
|
||||
if (LT_UART_SILENT_ALL) \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
#else // LT_UART_SILENT_ENABLED && !LT_UART_SILENT_ALL
|
||||
|
||||
#define WRAP_DISABLE_DECL(name) \
|
||||
static unsigned char __wrap_##name##_disabled = 0; \
|
||||
void __wrap_##name##_disable() { \
|
||||
__wrap_##name##_disabled = 1; \
|
||||
} \
|
||||
void __wrap_##name##_enable() { \
|
||||
__wrap_##name##_disabled = 0; \
|
||||
} \
|
||||
void __wrap_##name##_set(unsigned char disabled) { \
|
||||
__wrap_##name##_disabled = disabled; \
|
||||
} \
|
||||
unsigned char __wrap_##name##_get() { \
|
||||
return __wrap_##name##_disabled; \
|
||||
}
|
||||
|
||||
#define WRAP_DISABLE_CHECK(name) \
|
||||
{ \
|
||||
if (__wrap_##name##_disabled) \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
#endif // LT_UART_SILENT_ENABLED && !LT_UART_SILENT_ALL
|
||||
|
||||
#if LT_UART_SILENT_ALL
|
||||
|
||||
#define WRAP_PRINTF(name) \
|
||||
WRAP_DISABLE_DECL(name) \
|
||||
int __wrap_##name(const char *format, ...) { \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
#define WRAP_VPRINTF(name) \
|
||||
WRAP_DISABLE_DECL(name) \
|
||||
int __wrap_##name(const char *format, va_list arg) { \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
#else // !LT_UART_SILENT_ALL
|
||||
|
||||
#define WRAP_PRINTF(name) \
|
||||
WRAP_DISABLE_DECL(name) \
|
||||
int __wrap_##name(const char *format, ...) { \
|
||||
WRAP_DISABLE_CHECK(name); \
|
||||
va_list va; \
|
||||
va_start(va, format); \
|
||||
const int ret = vprintf(format, va); \
|
||||
va_end(va); \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
#define WRAP_VPRINTF(name) \
|
||||
WRAP_DISABLE_DECL(name) \
|
||||
int __wrap_##name(const char *format, va_list arg) { \
|
||||
WRAP_DISABLE_CHECK(name); \
|
||||
return vprintf(format, arg); \
|
||||
}
|
||||
|
||||
#endif // !LT_UART_SILENT_ALL
|
||||
|
||||
#define WRAP_SPRINTF(name) \
|
||||
int __wrap_##name(char *s, const char *format, ...) { \
|
||||
va_list va; \
|
||||
va_start(va, format); \
|
||||
const int ret = vsprintf(s, format, va); \
|
||||
va_end(va); \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
#define WRAP_SNPRINTF(name) \
|
||||
int __wrap_##name(char *s, size_t count, const char *format, ...) { \
|
||||
va_list va; \
|
||||
va_start(va, format); \
|
||||
const int ret = vsnprintf(s, count, format, va); \
|
||||
va_end(va); \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
#define WRAP_VSPRINTF(name) \
|
||||
int __wrap_##name(char *s, const char *format, va_list arg) { \
|
||||
return vsprintf(s, format, arg); \
|
||||
}
|
||||
|
||||
#define WRAP_VSNPRINTF(name) \
|
||||
int __wrap_##name(char *s, size_t count, const char *format, va_list arg) { \
|
||||
return vsnprintf(s, count, format, arg); \
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-04-23. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include "WCharacterFixup.h"
|
||||
#endif
|
||||
|
||||
#define PinMode PinModeArduino // this conflicts with SDK enum
|
||||
#include <api/ArduinoAPI.h>
|
||||
#include <core/LibreTuyaAPI.h>
|
||||
#undef PinMode
|
||||
|
||||
// Include family-specific code
|
||||
#include "WVariant.h"
|
||||
// Include board variant
|
||||
#include "variant.h"
|
||||
|
||||
// Choose the main UART output port
|
||||
#ifndef LT_UART_DEFAULT_PORT
|
||||
#if defined(PIN_SERIAL2_TX)
|
||||
#define LT_UART_DEFAULT_PORT 2
|
||||
#elif defined(PIN_SERIAL0_TX)
|
||||
#define LT_UART_DEFAULT_PORT 0
|
||||
#else
|
||||
#define LT_UART_DEFAULT_PORT 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Define available serial ports
|
||||
#ifdef __cplusplus
|
||||
#include "SerialClass.h"
|
||||
#include <core/SerialExtern.h>
|
||||
#endif
|
||||
@@ -1,208 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-28. */
|
||||
|
||||
#include <LibreTuyaAPI.h>
|
||||
|
||||
extern "C" {
|
||||
#include <flash_api.h>
|
||||
#include <rtl8710b.h>
|
||||
#include <sys_api.h>
|
||||
#include <wdt_api.h>
|
||||
}
|
||||
|
||||
void LibreTuya::restart() {
|
||||
// The Watchdog Way
|
||||
wdtEnable(1L);
|
||||
while (1) {}
|
||||
}
|
||||
|
||||
void LibreTuya::restartDownloadMode() {
|
||||
// mww 0x40000138 0x8
|
||||
HAL_WRITE32(SYSTEM_CTRL_BASE, REG_SYS_NORESET_FF, 0x08);
|
||||
// reboot it the ugly way
|
||||
sys_reset();
|
||||
while (1) {}
|
||||
}
|
||||
|
||||
ResetReason LibreTuya::getResetReason() {
|
||||
return RESET_REASON_UNKNOWN;
|
||||
}
|
||||
|
||||
void LibreTuya::gpioRecover() {
|
||||
// PA14 and PA15 are apparently unusable with SWD enabled
|
||||
sys_jtag_off();
|
||||
Pinmux_Config(PA_14, PINMUX_FUNCTION_GPIO);
|
||||
Pinmux_Config(PA_15, PINMUX_FUNCTION_GPIO);
|
||||
}
|
||||
|
||||
/* CPU-related */
|
||||
|
||||
ChipType LibreTuya::getChipType() {
|
||||
uint8_t chipId;
|
||||
EFUSE_OneByteReadROM(9902, 0xF8, &chipId, L25EOUTVOLTAGE);
|
||||
return CHIP_TYPE_ENUM(FAMILY, chipId);
|
||||
}
|
||||
|
||||
const char *LibreTuya::getChipModel() {
|
||||
return STRINGIFY_MACRO(MCU);
|
||||
}
|
||||
|
||||
uint32_t LibreTuya::getChipId() {
|
||||
uint32_t chipId = 0;
|
||||
uint8_t *id = (uint8_t *)&chipId;
|
||||
// 9902 was extracted from ROM disassembly, probably not needed
|
||||
/* EFUSE_OneByteReadROM(9902, 0x3B, id + 0, L25EOUTVOLTAGE);
|
||||
EFUSE_OneByteReadROM(9902, 0x3C, id + 1, L25EOUTVOLTAGE);
|
||||
EFUSE_OneByteReadROM(9902, 0x3D, id + 2, L25EOUTVOLTAGE); */
|
||||
// new method, based on EFUSE logical map
|
||||
uint8_t *efuse = (uint8_t *)malloc(512);
|
||||
// TODO do what EFUSE_LogicalMapRead() does, and read only the used data
|
||||
EFUSE_LogicalMap_Read(efuse);
|
||||
memcpy(id, efuse + 0x11A + 3, 3);
|
||||
free(efuse);
|
||||
return chipId;
|
||||
}
|
||||
|
||||
uint8_t LibreTuya::getChipCores() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *LibreTuya::getChipCoreType() {
|
||||
return "ARM Cortex-M4F";
|
||||
}
|
||||
|
||||
uint32_t LibreTuya::getCpuFreq() {
|
||||
return CPU_ClkGet(false);
|
||||
}
|
||||
|
||||
uint32_t LibreTuya::getCycleCount() {
|
||||
return microsecondsToClockCycles(micros());
|
||||
}
|
||||
|
||||
/* Flash memory utilities */
|
||||
|
||||
FlashId LibreTuya::getFlashChipId() {
|
||||
FlashId id;
|
||||
uint8_t idBytes[3];
|
||||
flash_read_id(NULL, idBytes, 3);
|
||||
id.manufacturerId = idBytes[0];
|
||||
id.chipId = idBytes[1];
|
||||
id.chipSizeId = idBytes[2];
|
||||
return id;
|
||||
}
|
||||
|
||||
/* Memory management */
|
||||
|
||||
uint32_t LibreTuya::getRamSize() {
|
||||
return 256 * 1024;
|
||||
}
|
||||
|
||||
uint32_t LibreTuya::getHeapSize() {
|
||||
return configTOTAL_HEAP_SIZE;
|
||||
}
|
||||
|
||||
uint32_t LibreTuya::getFreeHeap() {
|
||||
return xPortGetFreeHeapSize();
|
||||
}
|
||||
|
||||
uint32_t LibreTuya::getMinFreeHeap() {
|
||||
return xPortGetMinimumEverFreeHeapSize();
|
||||
}
|
||||
|
||||
uint32_t LibreTuya::getMaxAllocHeap() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* OTA-related */
|
||||
|
||||
uint8_t LibreTuya::otaGetRunning() {
|
||||
// RTL8710B is XIP, so check the code offset in flash
|
||||
uint32_t addr = (uint32_t)lt_log;
|
||||
uint32_t offs = addr - SPI_FLASH_BASE;
|
||||
return offs > FLASH_OTA2_OFFSET ? 2 : 1;
|
||||
}
|
||||
|
||||
uint8_t LibreTuya::otaGetStoredIndex() {
|
||||
uint32_t *otaAddress = (uint32_t *)0x8009000;
|
||||
if (*otaAddress == 0xFFFFFFFF)
|
||||
return 1;
|
||||
uint32_t otaCounter = *((uint32_t *)0x8009004);
|
||||
// even count of zero-bits means OTA1, odd count means OTA2
|
||||
// this allows to switch OTA images by simply clearing next bits,
|
||||
// without needing to erase the flash
|
||||
uint8_t count = 0;
|
||||
for (uint8_t i = 0; i < 32; i++) {
|
||||
if ((otaCounter & (1 << i)) == 0)
|
||||
count++;
|
||||
}
|
||||
return 1 + (count % 2);
|
||||
}
|
||||
|
||||
bool LibreTuya::otaSupportsDual() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LibreTuya::otaHasImage1() {
|
||||
uint8_t *ota1Addr = (uint8_t *)(SPI_FLASH_BASE + FLASH_OTA1_OFFSET);
|
||||
return memcmp(ota1Addr, "81958711", 8) == 0;
|
||||
}
|
||||
|
||||
bool LibreTuya::otaHasImage2() {
|
||||
uint8_t *ota2Addr = (uint8_t *)(SPI_FLASH_BASE + FLASH_OTA2_OFFSET);
|
||||
return memcmp(ota2Addr, "81958711", 8) == 0;
|
||||
}
|
||||
|
||||
bool LibreTuya::otaSwitch(bool force) {
|
||||
if (!force && otaGetRunning() != otaGetStoredIndex())
|
||||
// OTA has already been switched
|
||||
return true;
|
||||
// this function does:
|
||||
// - read OTA1 firmware magic from 0xB000
|
||||
// - read OTA2 address from 0x9000
|
||||
// - read OTA2 firmware magic from that address
|
||||
// - read current OTA switch value from 0x9004
|
||||
// - reset OTA switch to 0xFFFFFFFF if it's 0x0
|
||||
// - check first non-zero bit of OTA switch
|
||||
// - write OTA switch with first non-zero bit cleared
|
||||
// sys_clear_ota_signature();
|
||||
// ok, this function is broken (crashes with HardFault)
|
||||
|
||||
if (!otaHasImage1() || !otaHasImage2())
|
||||
return false;
|
||||
|
||||
uint32_t value = HAL_READ32(SPI_FLASH_BASE, FLASH_SYSTEM_OFFSET + 4);
|
||||
if (value == 0) {
|
||||
// TODO does this work at all?
|
||||
FLASH_EreaseDwordsXIP(FLASH_SYSTEM_OFFSET + 4, 1);
|
||||
}
|
||||
uint8_t i;
|
||||
// find first non-zero bit
|
||||
for (i = 0; i < 32; i++) {
|
||||
if (value & (1 << i))
|
||||
break;
|
||||
}
|
||||
// clear the bit
|
||||
value &= ~(1 << i);
|
||||
// write OTA switch to flash
|
||||
flash_write_word(NULL, FLASH_SYSTEM_OFFSET + 4, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Watchdog */
|
||||
|
||||
bool LibreTuya::wdtEnable(uint32_t timeout) {
|
||||
watchdog_init(timeout);
|
||||
watchdog_start();
|
||||
}
|
||||
|
||||
void LibreTuya::wdtDisable() {
|
||||
watchdog_stop();
|
||||
}
|
||||
|
||||
void LibreTuya::wdtFeed() {
|
||||
watchdog_refresh();
|
||||
}
|
||||
|
||||
/* Global instance */
|
||||
|
||||
LibreTuya LT;
|
||||
LibreTuya ESP = LT;
|
||||
@@ -1,98 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-07-03. */
|
||||
|
||||
#include "SerialClass.h"
|
||||
|
||||
#ifdef PIN_SERIAL0_TX
|
||||
SerialClass Serial0(UART0_DEV, UART0_IRQ, PIN_SERIAL0_RX, PIN_SERIAL0_TX);
|
||||
#endif
|
||||
#ifdef PIN_SERIAL1_TX
|
||||
SerialClass Serial1(UART1_DEV, UART1_IRQ, PIN_SERIAL1_RX, PIN_SERIAL1_TX);
|
||||
#endif
|
||||
#ifdef PIN_SERIAL2_TX
|
||||
SerialClass Serial2(UART2_DEV, UART_LOG_IRQ, PIN_SERIAL2_RX, PIN_SERIAL2_TX);
|
||||
#endif
|
||||
|
||||
SerialClass::SerialClass(UART_TypeDef *uart, IRQn irq, pin_size_t rx, pin_size_t tx) {
|
||||
data.uart = uart;
|
||||
data.buf = NULL;
|
||||
this->irq = irq;
|
||||
this->rx = rx;
|
||||
this->tx = tx;
|
||||
}
|
||||
|
||||
static uint32_t callback(void *param) {
|
||||
SerialData *data = (SerialData *)param;
|
||||
|
||||
uint32_t intcr = data->uart->DLH_INTCR;
|
||||
data->uart->DLH_INTCR = 0;
|
||||
|
||||
uint8_t c;
|
||||
UART_CharGet(data->uart, &c);
|
||||
if (c)
|
||||
data->buf->store_char(c);
|
||||
|
||||
data->uart->DLH_INTCR = intcr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SerialClass::begin(unsigned long baudrate, uint16_t config) {
|
||||
// RUART_WLS_7BITS / RUART_WLS_8BITS
|
||||
uint8_t dataWidth = (config & SERIAL_DATA_MASK) == SERIAL_DATA_8;
|
||||
// RUART_PARITY_DISABLE / RUART_PARITY_ENABLE
|
||||
uint8_t parity = (config & SERIAL_PARITY_MASK) != SERIAL_PARITY_NONE;
|
||||
// RUART_ODD_PARITY / RUART_EVEN_PARITY
|
||||
uint8_t parityType = (config & SERIAL_PARITY_MASK) == SERIAL_PARITY_EVEN;
|
||||
// RUART_STOP_BIT_1 / RUART_STOP_BIT_2
|
||||
uint8_t stopBits = (config & SERIAL_STOP_BIT_MASK) == SERIAL_STOP_BIT_2;
|
||||
|
||||
UART_InitTypeDef cfg;
|
||||
UART_StructInit(&cfg);
|
||||
cfg.WordLen = dataWidth;
|
||||
cfg.Parity = parity;
|
||||
cfg.ParityType = parityType;
|
||||
cfg.StopBit = stopBits;
|
||||
UART_Init(data.uart, &cfg);
|
||||
UART_SetBaud(data.uart, baudrate);
|
||||
|
||||
if (data.buf) {
|
||||
data.buf->clear();
|
||||
} else {
|
||||
data.buf = new RingBuffer();
|
||||
}
|
||||
|
||||
Pinmux_Config(pinInfo(this->rx)->gpio, PINMUX_FUNCTION_UART);
|
||||
Pinmux_Config(pinInfo(this->tx)->gpio, PINMUX_FUNCTION_UART);
|
||||
|
||||
VECTOR_IrqUnRegister(this->irq);
|
||||
VECTOR_IrqRegister(callback, this->irq, (uint32_t)&data, 10);
|
||||
}
|
||||
|
||||
void SerialClass::end() {
|
||||
if (data.uart == UART2_DEV) {
|
||||
// restore command line mode
|
||||
DIAG_UartReInit((IRQ_FUN)UartLogIrqHandle);
|
||||
}
|
||||
delete data.buf;
|
||||
}
|
||||
|
||||
int SerialClass::available() {
|
||||
return data.buf->available();
|
||||
}
|
||||
|
||||
int SerialClass::peek() {
|
||||
return data.buf->peek();
|
||||
}
|
||||
|
||||
int SerialClass::read() {
|
||||
return data.buf->read_char();
|
||||
}
|
||||
|
||||
void SerialClass::flush() {
|
||||
UART_WaitBusy(data.uart, 10);
|
||||
}
|
||||
|
||||
size_t SerialClass::write(uint8_t c) {
|
||||
while (UART_Writable(data.uart) == 0) {}
|
||||
UART_CharPut(data.uart, c);
|
||||
return 1;
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-07-03. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <api/HardwareSerial.h>
|
||||
#include <api/RingBuffer.h>
|
||||
|
||||
using namespace arduino;
|
||||
|
||||
typedef struct {
|
||||
UART_TypeDef *uart;
|
||||
RingBuffer *buf;
|
||||
} SerialData;
|
||||
|
||||
class SerialClass : public HardwareSerial {
|
||||
private:
|
||||
// data accessible to IRQ handler
|
||||
SerialData data;
|
||||
IRQn irq;
|
||||
pin_size_t rx;
|
||||
pin_size_t tx;
|
||||
|
||||
public:
|
||||
SerialClass(UART_TypeDef *uart, IRQn irq, pin_size_t rx, pin_size_t tx);
|
||||
|
||||
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 !!data.buf;
|
||||
}
|
||||
|
||||
using Print::write;
|
||||
};
|
||||
|
||||
#define HAS_SERIAL_CLASS 1
|
||||
@@ -1,12 +0,0 @@
|
||||
#include <Arduino.h>
|
||||
|
||||
extern void pinRemoveMode(pin_size_t pinNumber);
|
||||
extern void _tone(uint32_t ulPin, unsigned int frequency, unsigned long duration);
|
||||
|
||||
void tone(uint32_t ulPin, unsigned int frequency, unsigned long duration) {
|
||||
_tone(ulPin, frequency, duration);
|
||||
}
|
||||
|
||||
void noTone(uint32_t ulPin) {
|
||||
pinRemoveMode(ulPin);
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
#include <Arduino.h>
|
||||
#include <gpio_api.h>
|
||||
#include <gpio_irq_api.h>
|
||||
#include <gpio_irq_ex_api.h>
|
||||
|
||||
extern void *gpio_pin_struct[PINS_COUNT];
|
||||
static void *gpio_irq_handler_list[PINS_COUNT] = {NULL};
|
||||
static void *gpio_irq_handler_args[PINS_COUNT] = {NULL};
|
||||
|
||||
extern bool pinInvalid(pin_size_t pinNumber);
|
||||
extern void pinRemoveMode(pin_size_t pinNumber);
|
||||
|
||||
static void gpioIrqHandler(uint32_t id, gpio_irq_event event) {
|
||||
if (gpio_irq_handler_list[id] != NULL) {
|
||||
if (gpio_irq_handler_args[id] == NULL)
|
||||
((voidFuncPtr)gpio_irq_handler_list[id])();
|
||||
else
|
||||
((voidFuncPtrParam)gpio_irq_handler_list[id])(gpio_irq_handler_args[id]);
|
||||
}
|
||||
}
|
||||
|
||||
void attachInterrupt(pin_size_t interruptNumber, voidFuncPtr callback, PinStatus mode) {
|
||||
attachInterruptParam(interruptNumber, callback, mode, NULL);
|
||||
}
|
||||
|
||||
void attachInterruptParam(pin_size_t interruptNumber, voidFuncPtrParam callback, PinStatus mode, void *param) {
|
||||
if (pinInvalid(interruptNumber))
|
||||
return;
|
||||
|
||||
gpio_irq_handler_list[interruptNumber] = callback;
|
||||
gpio_irq_handler_args[interruptNumber] = param;
|
||||
|
||||
if (pinTable[interruptNumber].enabled == PIN_IRQ && pinTable[interruptNumber].mode == mode)
|
||||
// Nothing changes in pin mode
|
||||
return;
|
||||
|
||||
if (pinTable[interruptNumber].enabled != PIN_IRQ)
|
||||
// pin mode changes; deinit gpio and free memory
|
||||
pinRemoveMode(interruptNumber);
|
||||
|
||||
gpio_irq_t *gpio;
|
||||
|
||||
if (pinTable[interruptNumber].enabled == PIN_NONE) {
|
||||
// allocate memory if pin not used before
|
||||
gpio = malloc(sizeof(gpio_irq_t));
|
||||
gpio_pin_struct[interruptNumber] = gpio;
|
||||
gpio_irq_init(gpio, pinTable[interruptNumber].gpio, gpioIrqHandler, interruptNumber);
|
||||
pinTable[interruptNumber].enabled = PIN_IRQ;
|
||||
} else {
|
||||
// pin already used as irq
|
||||
gpio = (gpio_irq_t *)gpio_pin_struct[interruptNumber];
|
||||
}
|
||||
pinTable[interruptNumber].mode = mode;
|
||||
|
||||
gpio_irq_event event;
|
||||
|
||||
switch (mode) {
|
||||
case LOW:
|
||||
event = IRQ_LOW;
|
||||
break;
|
||||
case HIGH:
|
||||
event = IRQ_HIGH;
|
||||
break;
|
||||
case FALLING:
|
||||
event = IRQ_FALL;
|
||||
break;
|
||||
case RISING:
|
||||
event = IRQ_RISE;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
gpio_irq_set(gpio, event, 1);
|
||||
gpio_irq_enable(gpio);
|
||||
}
|
||||
|
||||
void detachInterrupt(pin_size_t interruptNumber) {
|
||||
if (pinInvalid(interruptNumber))
|
||||
return;
|
||||
|
||||
if (pinTable[interruptNumber].enabled == PIN_IRQ) {
|
||||
pinRemoveMode(interruptNumber);
|
||||
}
|
||||
gpio_irq_handler_list[interruptNumber] = NULL;
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "sdk_extern.h"
|
||||
#include "sdk_mem.h"
|
||||
#include "sdk_os.h"
|
||||
|
||||
#define DEFAULT 1
|
||||
#define EXTERNAL 0
|
||||
|
||||
#define round(x) ((x) >= 0 ? (long)((x) + 0.5) : (long)((x)-0.5))
|
||||
|
||||
// Additional Wiring functions
|
||||
extern uint32_t digitalPinToPort(uint32_t pinNumber);
|
||||
extern uint32_t digitalPinToBitMask(uint32_t pinNumber);
|
||||
extern void analogOutputInit(void);
|
||||
extern void wait_for_debug();
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" uint32_t SystemCoreClock;
|
||||
#else
|
||||
extern uint32_t SystemCoreClock;
|
||||
#endif
|
||||
#define clockCyclesPerMicrosecond() (SystemCoreClock / 1000000L)
|
||||
#define clockCyclesToMicroseconds(a) (a * 1000L / (SystemCoreClock / 1000L))
|
||||
#define microsecondsToClockCycles(a) (a * (SystemCoreClock / 1000000L))
|
||||
|
||||
#define interrupts() vPortClearInterruptMask(0)
|
||||
#define noInterrupts() ulPortSetInterruptMask()
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
@@ -1,60 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-06. */
|
||||
|
||||
#pragma once
|
||||
|
||||
// va_list is declared by SDK and conflicting
|
||||
#include <stdarg.h>
|
||||
|
||||
// disable typedef in basic_types.h
|
||||
#define boolean boolean_rtl
|
||||
|
||||
#include <strproc.h> // define string macros first
|
||||
#undef isdigit // then remove them, as they conflict
|
||||
#undef islower // with ctype.h macros
|
||||
#undef isprint
|
||||
#undef isspace
|
||||
#undef isxdigit
|
||||
#undef strtol
|
||||
#undef strtoul
|
||||
|
||||
#include <ameba_soc.h>
|
||||
#include <gpio_api.h>
|
||||
#include <main.h>
|
||||
#include <rand.h>
|
||||
#include <rt_lib_rom.h>
|
||||
#include <rtl_lib.h>
|
||||
#include <wait_api.h>
|
||||
|
||||
// remove previously defined workaround
|
||||
#undef boolean
|
||||
|
||||
// undefine ROM stdio in favor of printf() library (wrappers)
|
||||
#undef printf
|
||||
#undef sprintf
|
||||
#undef vsprintf
|
||||
#undef snprintf
|
||||
#undef vsnprintf
|
||||
#undef vprintf
|
||||
#include <stdio.h>
|
||||
|
||||
// moved from syscalls.h
|
||||
#define _close __rtl_close
|
||||
#define _fstat __rtl_fstat
|
||||
#define _isatty __rtl_isatty
|
||||
#define _lseek __rtl_lseek
|
||||
#define _open __rtl_open
|
||||
#define _read __rtl_read
|
||||
#define _write __rtl_write
|
||||
#define _sbrk __rtl_sbrk
|
||||
|
||||
#define delay_us wait_us
|
||||
|
||||
extern void wait_us(int us);
|
||||
extern int LOGUART_SetBaud(uint32_t BaudRate); // from fixups/log_uart.c
|
||||
extern void DumpForOneBytes(void *addr, int cnt); // cnt max 0x70!
|
||||
extern void SystemCoreClockUpdate(void);
|
||||
|
||||
extern int _sscanf_patch(const char *buf, const char *fmt, ...);
|
||||
|
||||
// include printf() wrapper disable methods
|
||||
#include <printf_port.h>
|
||||
@@ -1,16 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-06. */
|
||||
|
||||
#include "sdk_mem.h"
|
||||
|
||||
#include <Arduino.h> // for memset
|
||||
|
||||
void *pvPortZalloc(size_t size) {
|
||||
void *pvReturn = pvPortMalloc(size);
|
||||
if (pvReturn)
|
||||
memset(pvReturn, 0, size);
|
||||
return pvReturn;
|
||||
}
|
||||
|
||||
void *pvPortCalloc(size_t nmemb, size_t size) {
|
||||
return pvPortZalloc(nmemb * size);
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-06. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
// provide extern functions directly, as callers
|
||||
// generally don't expect needing to include malloc()
|
||||
extern void *pvPortMalloc(size_t xWantedSize);
|
||||
extern void *pvPortZalloc(size_t size);
|
||||
extern void *pvPortCalloc(size_t nmemb, size_t size);
|
||||
extern void *pvPortReAlloc(void *pv, size_t xWantedSize);
|
||||
extern void vPortFree(void *pv);
|
||||
|
||||
#define malloc pvPortMalloc
|
||||
#define zalloc pvPortZalloc
|
||||
#define calloc pvPortCalloc
|
||||
#define realloc pvPortReAlloc
|
||||
#define free vPortFree
|
||||
|
||||
#define LT_HEAP_FUNC xPortGetFreeHeapSize
|
||||
@@ -1,110 +0,0 @@
|
||||
#include "sdk_os.h"
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <cmsis_os.h>
|
||||
|
||||
uint32_t os_thread_create(void (*task)(const void *argument), void *argument, int priority, uint32_t stack_size) {
|
||||
|
||||
osThreadDef_t thread_def;
|
||||
|
||||
thread_def.pthread = task;
|
||||
thread_def.tpriority = (osPriority)priority;
|
||||
// the underlying freertos implementation on cmsis os divide stack size by 4
|
||||
thread_def.stacksize = stack_size * 4;
|
||||
thread_def.name = "ARDUINO";
|
||||
|
||||
return (uint32_t)osThreadCreate(&thread_def, argument);
|
||||
}
|
||||
|
||||
uint32_t os_thread_get_id(void) {
|
||||
return osThreadGetId();
|
||||
}
|
||||
|
||||
uint32_t os_thread_terminate(uint32_t thread_id) {
|
||||
return (uint32_t)osThreadTerminate(thread_id);
|
||||
}
|
||||
|
||||
uint32_t os_thread_yield(void) {
|
||||
return (uint32_t)osThreadYield();
|
||||
}
|
||||
|
||||
uint32_t os_thread_set_priority(uint32_t thread_id, int priority) {
|
||||
return (uint32_t)osThreadSetPriority(thread_id, (osPriority)priority);
|
||||
}
|
||||
|
||||
int os_thread_get_priority(uint32_t thread_id) {
|
||||
return (int)osThreadGetPriority(thread_id);
|
||||
}
|
||||
|
||||
int32_t os_signal_set(uint32_t thread_id, int32_t signals) {
|
||||
return osSignalSet(thread_id, signals);
|
||||
}
|
||||
|
||||
int32_t os_signal_clear(uint32_t thread_id, int32_t signals) {
|
||||
return osSignalClear(thread_id, signals);
|
||||
}
|
||||
|
||||
os_event_t os_signal_wait(int32_t signals, uint32_t millisec) {
|
||||
|
||||
osEvent evt;
|
||||
os_event_t ret;
|
||||
|
||||
evt = osSignalWait(signals, millisec);
|
||||
ret.status = (uint32_t)evt.status;
|
||||
ret.value.signals = evt.value.signals;
|
||||
ret.def.message_id = evt.def.message_id;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
typedef void (*os_ptimer)(const void *argument);
|
||||
|
||||
uint32_t os_timer_create(void (*callback)(const void *argument), uint8_t isPeriodic, void *argument) {
|
||||
|
||||
osTimerDef_t *pTimerDef;
|
||||
|
||||
pTimerDef = (osTimerDef_t *)malloc(sizeof(osTimerDef_t));
|
||||
pTimerDef->ptimer = callback;
|
||||
pTimerDef->custom = (struct os_timer_custom *)malloc(sizeof(struct os_timer_custom));
|
||||
|
||||
return osTimerCreate(pTimerDef, (isPeriodic ? osTimerPeriodic : osTimerOnce), argument);
|
||||
}
|
||||
|
||||
uint32_t os_timer_start(uint32_t timer_id, uint32_t millisec) {
|
||||
return osTimerStart(timer_id, millisec);
|
||||
}
|
||||
|
||||
uint32_t os_timer_stop(uint32_t timer_id) {
|
||||
return osTimerStop(timer_id);
|
||||
}
|
||||
|
||||
uint32_t os_timer_delete(uint32_t timer_id) {
|
||||
|
||||
osTimerDef_t *pTimerDef;
|
||||
|
||||
pTimerDef = (osTimerDef_t *)pvTimerGetTimerID(timer_id);
|
||||
free(pTimerDef->custom);
|
||||
free(pTimerDef);
|
||||
|
||||
return osTimerDelete(timer_id);
|
||||
}
|
||||
|
||||
uint32_t os_semaphore_create(int32_t count) {
|
||||
return (uint32_t)osSemaphoreCreate(NULL, count);
|
||||
}
|
||||
|
||||
int32_t os_semaphore_wait(uint32_t semaphore_id, uint32_t millisec) {
|
||||
if (osSemaphoreWait((osSemaphoreId)semaphore_id, millisec) == 0) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t os_semaphore_release(uint32_t semaphore_id) {
|
||||
return (uint32_t)osSemaphoreRelease((osSemaphoreId)semaphore_id);
|
||||
}
|
||||
|
||||
uint32_t os_semaphore_delete(uint32_t semaphore_id) {
|
||||
return (uint32_t)osSemaphoreDelete((osSemaphoreId)semaphore_id);
|
||||
}
|
||||
@@ -1,302 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @defgroup os_status os_status
|
||||
* Redefinition from enum osStatus
|
||||
* @{
|
||||
*/
|
||||
/** function completed; no error or event occurred. */
|
||||
#define OS_OK 0x00
|
||||
/** function completed; signal event occurred. */
|
||||
#define OS_EVENT_SIGNAL 0x08
|
||||
/** function completed; message event occurred. */
|
||||
#define OS_EVENT_MESSAGE 0x10
|
||||
/** function completed; mail event occurred. */
|
||||
#define OS_EVENT_MAIL 0x20
|
||||
/** function completed; timeout occurred. */
|
||||
#define OS_EVENT_TIMEOUT 0x40
|
||||
/** parameter error: a mandatory parameter was missing or specified an incorrect object. */
|
||||
#define OS_ERROR_PARAMETER 0x80
|
||||
/** resource not available: a specified resource was not available. */
|
||||
#define OS_ERROR_RESOURCE 0x81
|
||||
/** resource not available within given time: a specified resource was not available within the timeout period. */
|
||||
#define OS_ERROR_TIMEOUT_RESOURCE 0xC1
|
||||
/** not allowed in ISR context: the function cannot be called from interrupt service routines. */
|
||||
#define OS_ERROR_ISR 0x82
|
||||
/** function called multiple times from ISR with same object. */
|
||||
#define OS_ERROR_ISR_RECURSIVE 0x83
|
||||
/** system cannot determine priority or thread has illegal priority. */
|
||||
#define OS_ERROR_PRIORITY 0x84
|
||||
/** system is out of memory: it was impossible to allocate or reserve memory for the operation. */
|
||||
#define OS_ERROR_NO_MEMORY 0x85
|
||||
/** value of a parameter is out of range. */
|
||||
#define OS_ERROR_VALUE 0x86
|
||||
/** unspecified RTOS error: run-time error but no other error message fits. */
|
||||
#define OS_ERROR_OS 0xFF
|
||||
/** @} */ // end of group os_status
|
||||
|
||||
/**
|
||||
* @defgroup os_priority os_priority
|
||||
* Redefinition from enum osPriority
|
||||
* @{
|
||||
*/
|
||||
/** priority: idle (lowest) */
|
||||
#define OS_PRIORITY_IDLE (-3)
|
||||
/** priority: low */
|
||||
#define OS_PRIORITY_LOW (-2)
|
||||
/** priority: below normal */
|
||||
#define OS_PRIORITY_BELOW_NORMAL (-1)
|
||||
/** priority: normal (default) */
|
||||
#define OS_PRIORITY_NORMAL (0)
|
||||
/** priority: above normal */
|
||||
#define OS_PRIORITY_ABOVENORMAL (+1)
|
||||
/** priority: high */
|
||||
#define OS_PRIORITY_HIGH (+2)
|
||||
/** priority: realtime (highest) */
|
||||
#define OS_PRIORITY_REALTIME (+3)
|
||||
/** @} */ // end of group os_priority
|
||||
|
||||
#ifndef DEFAULT_STACK_SIZE
|
||||
/**
|
||||
* @ingroup wiring_os
|
||||
* @brief default stack size
|
||||
*
|
||||
* It is suggest that thread is assigned stack size more than DEFAULT_STACK_SIZE
|
||||
*/
|
||||
#define DEFAULT_STACK_SIZE 512
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @ingroup wiring_os
|
||||
* @struct os_event_t
|
||||
* Redefine osEvent in cmsis_os.h
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t status; ///< status code: event or error information
|
||||
|
||||
union {
|
||||
uint32_t v; ///< message as 32-bit value
|
||||
void *p; ///< message or mail as void pointer
|
||||
int32_t signals; ///< signal flags
|
||||
} value; ///< event value
|
||||
|
||||
union {
|
||||
void *mail_id; ///< mail id obtained by osMailCreate
|
||||
void *message_id; ///< message id obtained by osMessageCreate
|
||||
} def; ///< event definition
|
||||
} os_event_t;
|
||||
|
||||
/**
|
||||
* @defgroup thread_management thread_management
|
||||
* Thread management include create, get thread id, terminate, yield, and set/get priority
|
||||
**/
|
||||
|
||||
/**
|
||||
* @ingroup thread_management
|
||||
* @brief Create a thread and add it to Active Threads and set it to state READY.
|
||||
*
|
||||
* @param[in] task Function pointer which is the thread body. It should not run into the end of function unless
|
||||
* os_thread_terminate is invoked
|
||||
* @param[in] argument the data pointer which brings to task
|
||||
* @param[in] priority The underlying os is FreeRTOS. It executes tasks with highest priority which are not in idle
|
||||
* state.\n If there are more than 2 tasks to be executed, then they share the time slice.
|
||||
* @param[in] stack_size The stack_size is used as memory heap only for this task. \n
|
||||
* The local variables and call stacks would occupy this heap. Please make sure the the stack_size is big enough to
|
||||
* avoid curroption
|
||||
* @return The thread id which is used in thread operation and signaling.
|
||||
*/
|
||||
extern uint32_t os_thread_create(void (*task)(const void *argument), void *argument, int priority, uint32_t stack_size);
|
||||
|
||||
/**
|
||||
* @ingroup thread_management
|
||||
* @brief Return the thread ID of the current running thread.
|
||||
*
|
||||
* @return Current thread id which calls os_thread_get_id
|
||||
*/
|
||||
extern uint32_t os_thread_get_id(void);
|
||||
|
||||
/**
|
||||
* @ingroup thread_management
|
||||
* @brief Terminate execution of a thread and remove it from Active Threads.
|
||||
*
|
||||
* Thread should not ended without terminate first
|
||||
*
|
||||
* @param[in] thread_id Terminate the thread with specific thread_id
|
||||
* @return os_status code
|
||||
*/
|
||||
extern uint32_t os_thread_terminate(uint32_t thread_id);
|
||||
|
||||
/**
|
||||
* @ingroup thread_management
|
||||
* @brief Pass control to next thread that is in state \b READY.
|
||||
*
|
||||
* By default the minimal execution unit is 1 millisecond. In a scenario that if a thread with smaller want to handout
|
||||
* execution right to a thread with higher priority immediately without waiting for the ending of current 1 millisecond,
|
||||
* then invoke os_thread_yield can transfer exection right to OS's idle task and check which is the next execution
|
||||
* thread.
|
||||
*
|
||||
* @return os_status code
|
||||
*/
|
||||
extern uint32_t os_thread_yield(void);
|
||||
|
||||
/**
|
||||
* @ingroup thread_management
|
||||
* @brief Change priority of an active thread.
|
||||
*
|
||||
* @param[in] thread_id The target thread with the thread id to be changed
|
||||
* @param[in] priority The updated priority
|
||||
* @return os_status code
|
||||
*/
|
||||
extern uint32_t os_thread_set_priority(uint32_t thread_id, int priority);
|
||||
|
||||
/**
|
||||
* @ingroup thread_management
|
||||
* @brief Get current priority of an active thread.
|
||||
*
|
||||
* @param[in] thread_id The target thread with the thread id to be searched
|
||||
* @return os_priority
|
||||
*/
|
||||
extern int os_thread_get_priority(uint32_t thread_id);
|
||||
|
||||
/**
|
||||
* @defgroup signal_management signal_management
|
||||
* Signaling between threads include set, clear, and wait
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup signal_management
|
||||
* @brief Set the specified Signal Flags of an active thread.
|
||||
*
|
||||
* @param[in] thread_id Send signal to a thread with the thread id
|
||||
* @param[in] signals the signals to be send
|
||||
* @return os_status code
|
||||
*/
|
||||
extern int32_t os_signal_set(uint32_t thread_id, int32_t signals);
|
||||
|
||||
/**
|
||||
* @ingroup signal_management
|
||||
* @brief Clear the specified Signal Flags of an active thread.
|
||||
*
|
||||
* @param[in] thread_id Clear signal to a thread with the thread id
|
||||
* @param[in] signals The signals to be clear
|
||||
* @return os_status code
|
||||
*/
|
||||
extern int32_t os_signal_clear(uint32_t thread_id, int32_t signals);
|
||||
|
||||
/**
|
||||
* @ingroup signal_management
|
||||
* @brief Wait for one or more Signal Flags to become signaled for the current \b RUNNING thread.
|
||||
*
|
||||
* @param[in] signals the signals to be wait
|
||||
* @param[in] millisec the timeout value if no signal comes in. Fill in 0xFFFFFFFF for infinite wait.
|
||||
* @return os_status code
|
||||
*/
|
||||
extern os_event_t os_signal_wait(int32_t signals, uint32_t millisec);
|
||||
|
||||
/**
|
||||
* @defgroup timer_management timer_management
|
||||
* Software timer management include create, start, stop, delete.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup timer_management
|
||||
* @brief specify timer type that invoke only once
|
||||
*/
|
||||
#define OS_TIMER_ONCE (0)
|
||||
|
||||
/**
|
||||
* @ingroup timer_management
|
||||
* @brief specify timer type that invoke periodically
|
||||
*/
|
||||
#define OS_TIMER_PERIODIC (1)
|
||||
|
||||
/**
|
||||
* @ingroup timer_management
|
||||
* @brief Create a timer.
|
||||
*
|
||||
* @param[in] callback The function to be invoke when timer timeout
|
||||
* @param[in] isPeriodic \b OS_TIMER_ONCE or \b OS_TIMER_PERIODIC
|
||||
* @param[in] argument The argument that is bring into callback function
|
||||
* @return timer id
|
||||
*/
|
||||
extern uint32_t os_timer_create(void (*callback)(const void *argument), uint8_t isPeriodic, void *argument);
|
||||
|
||||
/**
|
||||
* @ingroup timer_management
|
||||
* @brief Start or restart a timer.
|
||||
*
|
||||
* @param[in] timer_id The timer id obtained from by os_timer_create
|
||||
* @param[in] millisec The delays after timer starts
|
||||
* @return os_status code
|
||||
*/
|
||||
extern uint32_t os_timer_start(uint32_t timer_id, uint32_t millisec);
|
||||
|
||||
/**
|
||||
* @ingroup timer_management
|
||||
* @brief Stop the timer.
|
||||
*
|
||||
* @param[in] timer_id The timer id obtained from by os_timer_create
|
||||
* @return os_status code
|
||||
*/
|
||||
extern uint32_t os_timer_stop(uint32_t timer_id);
|
||||
|
||||
/**
|
||||
* @ingroup timer_management
|
||||
* @brief Delete a timer that was created by os_timer_create
|
||||
*
|
||||
* @param[in] timer_id The timer id obtained from by os_timer_create
|
||||
* @return os_status code
|
||||
*/
|
||||
extern uint32_t os_timer_delete(uint32_t timer_id);
|
||||
|
||||
/**
|
||||
* @defgroup semaphore_management semaphore_management
|
||||
* Semaphore API between threads include create, wait, release, delete.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup semaphore_management
|
||||
* @brief Create and Initialize a Semaphore object used for managing resources
|
||||
*
|
||||
* @param[in] count The number of available resources
|
||||
* @return semaphore ID
|
||||
*/
|
||||
extern uint32_t os_semaphore_create(int32_t count);
|
||||
|
||||
/**
|
||||
* @ingroup semaphore_management
|
||||
* @brief Wait until a Semaphore token becomes available
|
||||
*
|
||||
* @param[in] semaphore_id semaphore id obtained from os_semaphore_create
|
||||
* @param[in] millisec timeout value
|
||||
* @return os_status code
|
||||
*/
|
||||
extern int32_t os_semaphore_wait(uint32_t semaphore_id, uint32_t millisec);
|
||||
|
||||
/**
|
||||
* @ingroup semaphore_management
|
||||
* @brief Release a Semaphore token
|
||||
*
|
||||
* @param[in] semaphore_id semaphore id obtained from os_semaphore_create
|
||||
* @return os_status code
|
||||
*/
|
||||
extern uint32_t os_semaphore_release(uint32_t semaphore_id);
|
||||
|
||||
/**
|
||||
* @ingroup semaphore_management
|
||||
* @brief Delete a Semaphore that was created by os_semaphore_create.
|
||||
*
|
||||
* @param[in] semaphore_id semaphore id obtained from os_semaphore_create
|
||||
* @return os_status code
|
||||
*/
|
||||
extern uint32_t os_semaphore_delete(uint32_t semaphore_id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,93 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2011 Arduino. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <cmsis_os.h>
|
||||
|
||||
#ifndef portNVIC_SYSTICK_CURRENT_VALUE_REG
|
||||
#define portNVIC_SYSTICK_CURRENT_VALUE_REG (*((volatile uint32_t *)0xe000e018))
|
||||
#endif
|
||||
|
||||
extern uint32_t xTaskGetTickCount();
|
||||
extern uint32_t xTaskGetTickCountFromISR();
|
||||
|
||||
static __inline uint32_t __get_ipsr__(void) {
|
||||
volatile uint32_t __regIPSR __asm("ipsr");
|
||||
return (__regIPSR);
|
||||
}
|
||||
|
||||
void *gpio_pin_struct[PINS_COUNT] = {NULL};
|
||||
|
||||
void delay(uint32_t ms) {
|
||||
/* osStatus ret; */
|
||||
|
||||
/* ret = */ osDelay(ms);
|
||||
/* if ((ret != osEventTimeout) && (ret != osOK)) {
|
||||
printf("delay : ERROR : 0x%x \n", ret);
|
||||
} */
|
||||
}
|
||||
|
||||
void delayMicroseconds(unsigned int us) {
|
||||
int i;
|
||||
uint32_t t0, tn;
|
||||
int dfactor = 20 * us - 10 + (81 * us / 100);
|
||||
|
||||
if (us > 100) {
|
||||
t0 = micros();
|
||||
do {
|
||||
tn = micros();
|
||||
} while (tn >= t0 && tn < (t0 + us - 1));
|
||||
} else {
|
||||
for (i = 0; i < dfactor; i++) {
|
||||
asm("nop");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long millis(void) {
|
||||
return (__get_ipsr__() == 0) ? xTaskGetTickCount() : xTaskGetTickCountFromISR();
|
||||
}
|
||||
|
||||
unsigned long micros(void) {
|
||||
uint32_t tick1, tick2;
|
||||
uint32_t us;
|
||||
uint32_t tick_per_us = F_CPU / 1000;
|
||||
|
||||
if (__get_ipsr__() == 0) {
|
||||
tick1 = xTaskGetTickCount();
|
||||
us = portNVIC_SYSTICK_CURRENT_VALUE_REG;
|
||||
tick2 = xTaskGetTickCount();
|
||||
} else {
|
||||
tick1 = xTaskGetTickCountFromISR();
|
||||
us = portNVIC_SYSTICK_CURRENT_VALUE_REG;
|
||||
tick2 = xTaskGetTickCountFromISR();
|
||||
}
|
||||
|
||||
if (tick1 == tick2) {
|
||||
return tick1 * 1000 - us * 1000 / tick_per_us;
|
||||
} else if ((us * 1000 / tick_per_us) < 500) {
|
||||
return tick1 * 1000 - us * 1000 / tick_per_us;
|
||||
} else {
|
||||
return tick1 * 1000;
|
||||
}
|
||||
}
|
||||
|
||||
void yield(void) {
|
||||
vTaskDelay(1);
|
||||
taskYIELD();
|
||||
}
|
||||
@@ -1,161 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2011 Arduino. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <analogin_api.h>
|
||||
#include <analogout_api.h>
|
||||
#include <gpio_ex_api.h>
|
||||
#include <pwmout_api.h>
|
||||
|
||||
/* ADC */
|
||||
analogin_t adc1;
|
||||
analogin_t adc2;
|
||||
analogin_t adc3;
|
||||
|
||||
bool g_adc_enabled[] = {false, false, false};
|
||||
// from realtek_amebaz_va0_example/example_sources/adc_vbat/src/main.c
|
||||
#define AD2MV(ad, offset, gain) (((ad >> 4) - offset) * 1000 / gain)
|
||||
|
||||
extern void *gpio_pin_struct[];
|
||||
|
||||
extern void pinRemoveMode(pin_size_t pinNumber);
|
||||
|
||||
// TODO implement custom ADC calibration
|
||||
|
||||
uint16_t analogReadVoltage(pin_size_t pinNumber) {
|
||||
uint16_t ret = 0;
|
||||
switch (pinNumber) {
|
||||
#ifdef PIN_A1
|
||||
case PIN_A1:
|
||||
if (g_adc_enabled[1] == false) {
|
||||
analogin_init(&adc2, AD_2);
|
||||
g_adc_enabled[1] = true;
|
||||
}
|
||||
ret = analogin_read_u16(&adc2);
|
||||
// AD_1 - 0.0V-5.0V
|
||||
return AD2MV(ret, 0x496, 0xBA);
|
||||
#endif
|
||||
#ifdef PIN_A0
|
||||
case PIN_A0:
|
||||
if (g_adc_enabled[0] == false) {
|
||||
analogin_init(&adc1, AD_1);
|
||||
g_adc_enabled[0] = true;
|
||||
}
|
||||
ret = analogin_read_u16(&adc1);
|
||||
break;
|
||||
#endif
|
||||
#ifdef PIN_A2
|
||||
case PIN_A2:
|
||||
if (g_adc_enabled[2] == false) {
|
||||
analogin_init(&adc3, AD_3);
|
||||
g_adc_enabled[2] = true;
|
||||
}
|
||||
ret = analogin_read_u16(&adc3);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
// AD_0, AD_2 - 0.0V-3.3V
|
||||
return AD2MV(ret, 0x418, 0x342);
|
||||
}
|
||||
|
||||
uint16_t analogReadMaxVoltage(pin_size_t pinNumber) {
|
||||
#ifdef PIN_A1
|
||||
if (pinNumber == PIN_A1)
|
||||
return 5000;
|
||||
#endif
|
||||
return 3300;
|
||||
}
|
||||
|
||||
void analogWrite(pin_size_t pinNumber, int value) {
|
||||
PinInfo *pin = pinInfo(pinNumber);
|
||||
if (!pin)
|
||||
return;
|
||||
pwmout_t *obj;
|
||||
|
||||
if (pinSupported(pin, PIN_PWM)) {
|
||||
float percent = value * 1.0 / (1 << _analogWriteResolution);
|
||||
if (pin->enabled != PIN_PWM) {
|
||||
if ((pin->enabled == PIN_GPIO) || (pin->enabled == PIN_IRQ)) {
|
||||
pinRemoveMode(pinNumber);
|
||||
}
|
||||
gpio_pin_struct[pinNumber] = malloc(sizeof(pwmout_t));
|
||||
pwmout_t *obj = (pwmout_t *)gpio_pin_struct[pinNumber];
|
||||
pwmout_init(obj, pin->gpio);
|
||||
pwmout_period_us(obj, _analogWritePeriod);
|
||||
pwmout_write(obj, percent);
|
||||
pin->enabled = PIN_PWM;
|
||||
} else {
|
||||
pwmout_t *obj = (pwmout_t *)gpio_pin_struct[pinNumber];
|
||||
// pwmout_period_us(obj, _writePeriod);
|
||||
pwmout_write(obj, percent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct _tone_argument {
|
||||
uint32_t ulPin;
|
||||
uint32_t timer_id;
|
||||
};
|
||||
|
||||
void _tone_timer_handler(const void *argument) {
|
||||
struct _tone_argument *arg = (struct _tone_argument *)argument;
|
||||
|
||||
uint32_t ulPin = (uint32_t)argument;
|
||||
|
||||
noTone(arg->ulPin);
|
||||
|
||||
os_timer_delete(arg->timer_id);
|
||||
|
||||
free((struct _tone_argument *)arg);
|
||||
}
|
||||
|
||||
void _tone(uint32_t ulPin, unsigned int frequency, unsigned long duration) {
|
||||
pwmout_t *obj;
|
||||
|
||||
if ((pinTable[ulPin].supported & PIN_PWM) != PIN_PWM) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pinTable[ulPin].enabled != PIN_PWM) {
|
||||
if ((pinTable[ulPin].enabled == PIN_GPIO) || (pinTable[ulPin].enabled == PIN_IRQ)) {
|
||||
pinRemoveMode(ulPin);
|
||||
}
|
||||
gpio_pin_struct[ulPin] = malloc(sizeof(pwmout_t));
|
||||
pwmout_t *obj = (pwmout_t *)gpio_pin_struct[ulPin];
|
||||
pwmout_init(obj, pinTable[ulPin].gpio);
|
||||
pwmout_period(obj, 1.0 / frequency);
|
||||
pwmout_pulsewidth(obj, 1.0 / (frequency * 2));
|
||||
pinTable[ulPin].enabled = PIN_PWM;
|
||||
|
||||
} else {
|
||||
// There is already a PWM configured
|
||||
pwmout_t *obj = (pwmout_t *)gpio_pin_struct[ulPin];
|
||||
pwmout_period(obj, 1.0 / frequency);
|
||||
pwmout_pulsewidth(obj, 1.0 / (frequency * 2));
|
||||
}
|
||||
|
||||
if (duration > 0) {
|
||||
struct _tone_argument *arg = (struct _tone_argument *)malloc(sizeof(struct _tone_argument));
|
||||
arg->ulPin = ulPin;
|
||||
arg->timer_id = os_timer_create(_tone_timer_handler, 0, arg);
|
||||
os_timer_start(arg->timer_id, duration);
|
||||
}
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
#include <Arduino.h>
|
||||
#include <gpio_api.h>
|
||||
#include <gpio_irq_api.h>
|
||||
#include <gpio_irq_ex_api.h>
|
||||
#include <pwmout_api.h>
|
||||
|
||||
extern void *gpio_pin_struct[PINS_COUNT];
|
||||
|
||||
void pinRemoveMode(pin_size_t pinNumber) {
|
||||
PinInfo *pin = pinInfo(pinNumber);
|
||||
if (!pin)
|
||||
return;
|
||||
if (pinEnabled(pin, PIN_PWM)) {
|
||||
pwmout_t *obj = (pwmout_t *)gpio_pin_struct[pinNumber];
|
||||
pwmout_free(obj);
|
||||
}
|
||||
if (pinEnabled(pin, PIN_GPIO)) {
|
||||
gpio_t *obj = (gpio_t *)gpio_pin_struct[pinNumber];
|
||||
gpio_deinit(obj, pin->gpio);
|
||||
free(obj);
|
||||
}
|
||||
if (pinEnabled(pin, PIN_IRQ)) {
|
||||
gpio_irq_t *obj = (gpio_irq_t *)gpio_pin_struct[pinNumber];
|
||||
gpio_irq_deinit(obj);
|
||||
free(obj);
|
||||
}
|
||||
gpio_pin_struct[pinNumber] = NULL;
|
||||
pin->enabled = PIN_NONE;
|
||||
}
|
||||
|
||||
void pinMode(pin_size_t pinNumber, PinModeArduino pinMode) {
|
||||
PinInfo *pin = pinInfo(pinNumber);
|
||||
if (!pin)
|
||||
return;
|
||||
|
||||
if (pinEnabled(pin, PIN_GPIO) && pin->mode == pinMode)
|
||||
// Nothing changes in pin mode
|
||||
return;
|
||||
|
||||
if (!pinSupported(pin, PIN_GPIO))
|
||||
// cannot set ADC as I/O
|
||||
return;
|
||||
|
||||
/* if (pin->enabled == PIN_PWM) {
|
||||
// If this pin has been configured as PWM, then it cannot change to another mode
|
||||
return;
|
||||
} */
|
||||
|
||||
if (pin->enabled != PIN_GPIO)
|
||||
// pin mode changes; deinit gpio and free memory
|
||||
pinRemoveMode(pinNumber);
|
||||
|
||||
gpio_t *gpio;
|
||||
|
||||
if (pin->enabled == PIN_NONE) {
|
||||
// allocate memory if pin not used before
|
||||
gpio = malloc(sizeof(gpio_t));
|
||||
gpio_pin_struct[pinNumber] = gpio;
|
||||
gpio_init(gpio, pin->gpio);
|
||||
pin->enabled = PIN_GPIO;
|
||||
} else {
|
||||
// pin already used as gpio
|
||||
gpio = (gpio_t *)gpio_pin_struct[pinNumber];
|
||||
}
|
||||
pin->mode = pinMode;
|
||||
|
||||
PinDirection dir;
|
||||
PinMode mode;
|
||||
|
||||
switch (pinMode) {
|
||||
case INPUT:
|
||||
dir = PIN_INPUT;
|
||||
mode = PullNone;
|
||||
break;
|
||||
case INPUT_PULLDOWN:
|
||||
dir = PIN_INPUT;
|
||||
mode = PullDown;
|
||||
break;
|
||||
case INPUT_PULLUP:
|
||||
dir = PIN_INPUT;
|
||||
mode = PullUp;
|
||||
break;
|
||||
case OUTPUT:
|
||||
dir = PIN_OUTPUT;
|
||||
mode = PullNone;
|
||||
break;
|
||||
case OUTPUT_OPENDRAIN:
|
||||
dir = PIN_OUTPUT;
|
||||
mode = OpenDrain;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
gpio_dir(gpio, dir);
|
||||
gpio_mode(gpio, mode);
|
||||
}
|
||||
|
||||
void digitalWrite(pin_size_t pinNumber, PinStatus status) {
|
||||
PinInfo *pin = pinInfo(pinNumber);
|
||||
if (!pin)
|
||||
return;
|
||||
if (pin->enabled != PIN_GPIO)
|
||||
return;
|
||||
|
||||
gpio_t *gpio = (gpio_t *)gpio_pin_struct[pinNumber];
|
||||
gpio_write(gpio, status);
|
||||
}
|
||||
|
||||
PinStatus digitalRead(pin_size_t pinNumber) {
|
||||
PinInfo *pin = pinInfo(pinNumber);
|
||||
if (!pin)
|
||||
return;
|
||||
if (pin->enabled != PIN_GPIO)
|
||||
return;
|
||||
|
||||
gpio_t *gpio = (gpio_t *)gpio_pin_struct[pinNumber];
|
||||
return gpio_read(gpio);
|
||||
}
|
||||
|
||||
/**************************** Extend API by RTK ***********************************/
|
||||
|
||||
uint32_t digitalPinToPort(uint32_t pinNumber) {
|
||||
if (pinInvalid(pinNumber))
|
||||
return 0xFFFFFFFF;
|
||||
|
||||
uint32_t pin_name = HAL_GPIO_GetPinName(pinTable[pinNumber].gpio);
|
||||
return HAL_GPIO_GET_PORT_BY_NAME(pin_name);
|
||||
}
|
||||
|
||||
uint32_t digitalPinToBitMask(uint32_t pinNumber) {
|
||||
if (pinInvalid(pinNumber))
|
||||
return 0xFFFFFFFF;
|
||||
|
||||
uint32_t pin_name = HAL_GPIO_GetPinName(pinTable[pinNumber].gpio);
|
||||
return 1 << (HAL_GPIO_GET_PIN_BY_NAME(pin_name));
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-06-03. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#define LT_MD5_USE_POLARSSL 1
|
||||
@@ -1,58 +0,0 @@
|
||||
#include "PowerManagement.h"
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#include <freertos_pmu.h>
|
||||
#include <sleep_ex_api.h>
|
||||
#include <sys_api.h>
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(BOARD_RTL8195A)
|
||||
#define SAVE_LOCK_PIN 18
|
||||
#elif defined(BOARD_RTL8710)
|
||||
#define SAVE_LOCK_PIN 7 // PB_1
|
||||
#else
|
||||
#define SAVE_LOCK_PIN 18
|
||||
#endif
|
||||
|
||||
bool PowerManagementClass::reservePLL = true;
|
||||
|
||||
void PowerManagementClass::sleep(uint32_t bitflg) {
|
||||
if (!safeLock()) {
|
||||
pmu_release_wakelock(bitflg);
|
||||
}
|
||||
}
|
||||
|
||||
void PowerManagementClass::sleep(void) {
|
||||
if (!safeLock()) {
|
||||
pmu_release_wakelock(BIT(PMU_OS));
|
||||
}
|
||||
}
|
||||
|
||||
void PowerManagementClass::active(uint32_t bitflg) {
|
||||
pmu_acquire_wakelock(bitflg);
|
||||
}
|
||||
|
||||
void PowerManagementClass::active(void) {
|
||||
pmu_acquire_wakelock(BIT(PMU_OS));
|
||||
}
|
||||
|
||||
void PowerManagementClass::deepsleep(uint32_t duration_ms) {
|
||||
if (!safeLock()) {
|
||||
deepsleep_ex(DSLEEP_WAKEUP_BY_TIMER, duration_ms);
|
||||
}
|
||||
}
|
||||
|
||||
bool PowerManagementClass::safeLock() {
|
||||
pinMode(SAVE_LOCK_PIN, INPUT_PULLUP);
|
||||
return (digitalRead(SAVE_LOCK_PIN) == 1) ? false : true;
|
||||
}
|
||||
|
||||
void PowerManagementClass::softReset() {
|
||||
sys_reset();
|
||||
}
|
||||
|
||||
PowerManagementClass PowerManagement;
|
||||
@@ -1,73 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
/**
|
||||
* @class PowerManagementClass PowerManagement.h
|
||||
* @brief Power management in Ameba
|
||||
*/
|
||||
class PowerManagementClass {
|
||||
public:
|
||||
/**
|
||||
* @brief Allow OS automatically save power while idle
|
||||
*
|
||||
* As OS consider it would idle for more than 2s, it will invoke system suspend.
|
||||
* If wlan is associated with AP, than it will under asslociated idle state.
|
||||
*/
|
||||
static void sleep(void);
|
||||
static void sleep(uint32_t bitflg);
|
||||
|
||||
/**
|
||||
* @brief Disallow OS automatically save power while idle
|
||||
*/
|
||||
static void active(void);
|
||||
static void active(uint32_t bitflg);
|
||||
|
||||
/**
|
||||
* @brief Reserved PLL while sleep
|
||||
*
|
||||
* Reserve PLL would keep FIFO of peripherals (Ex. UART) but cost more power (around 5mA).
|
||||
* If we don't reserve PLL, it saves more power but we might missing data because FIFO is turned of this way.
|
||||
*
|
||||
* @param[in] reserve true for reserved, false for non-reserved
|
||||
*/
|
||||
static void setPllReserved(bool reserve);
|
||||
|
||||
/**
|
||||
* @brief Enter deepsleep immediately
|
||||
*
|
||||
* Invoke deepsleep would make system enter deepsleep state immediately.
|
||||
* It's the state that saves most power.
|
||||
* As it wakeup from deepsleep, the system would behave just like reboot.
|
||||
*
|
||||
* @param[in] duration_ms wakeup after specific time in unit of millisecond
|
||||
*/
|
||||
static void deepsleep(uint32_t duration_ms);
|
||||
|
||||
/**
|
||||
* @brief Check if system is allowed enter any power save state
|
||||
*
|
||||
* The pin 18 (GPIOE_5) is designed as safe lock.
|
||||
* If pin 18 is HIGH, then we prevent Ameba enter any power save state.\n\n
|
||||
* Under any power save state, we are not able to flash image to Ameba.
|
||||
* Thus if user misuse deepsleep and make Ameba enter deepsleep immediately after boot up,
|
||||
* then he would find it's hard to flash image.
|
||||
* In this case, he can pull up pin 18.
|
||||
*
|
||||
* @return true if system not allowed enter any power save state, and false vise versa
|
||||
*/
|
||||
static bool safeLock();
|
||||
|
||||
/**
|
||||
* @brief Reboot system
|
||||
*
|
||||
* Reboot system in soft way. Some registers is not powered off in this case, but mostly we could regard this as
|
||||
* reboot.
|
||||
*/
|
||||
static void softReset();
|
||||
|
||||
private:
|
||||
static bool reservePLL;
|
||||
};
|
||||
|
||||
extern PowerManagementClass PowerManagement;
|
||||
@@ -1,5 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-07-03. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <api/SoftwareSerial.h>
|
||||
@@ -1,10 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-04-25. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <api/WiFi/WiFi.h>
|
||||
|
||||
#include "WiFiClient.h"
|
||||
#include "WiFiClientSecure.h"
|
||||
#include "WiFiServer.h"
|
||||
@@ -1,8 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-06-27. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <api/WiFi/WiFi.h>
|
||||
#include <lwip/LwIPClient.h>
|
||||
|
||||
typedef LwIPClient WiFiClient;
|
||||
@@ -1,8 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-04. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <api/WiFi/WiFi.h>
|
||||
#include <ssl/MbedTLSClient.h>
|
||||
|
||||
typedef MbedTLSClient WiFiClientSecure;
|
||||
@@ -1,18 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-06-23. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
extern "C" {
|
||||
|
||||
#include <FreeRTOS.h>
|
||||
#include <semphr.h>
|
||||
|
||||
} // extern "C"
|
||||
|
||||
typedef struct {
|
||||
bool initialized;
|
||||
bool sleep;
|
||||
SemaphoreHandle_t scanSem;
|
||||
} WiFiData;
|
||||
@@ -1,109 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-04-25. */
|
||||
|
||||
#include "WiFiPriv.h"
|
||||
|
||||
int32_t WiFiClass::channel() {
|
||||
int channel = 0;
|
||||
wifi_get_channel(&channel);
|
||||
return channel;
|
||||
}
|
||||
|
||||
bool WiFiClass::modePriv(WiFiMode mode, WiFiModeAction sta, WiFiModeAction ap) {
|
||||
__wrap_rtl_printf_disable();
|
||||
__wrap_DiagPrintf_disable();
|
||||
startWifiTask();
|
||||
|
||||
if (!data.initialized) {
|
||||
// initialize wifi first
|
||||
LT_IM(WIFI, "Initializing LwIP");
|
||||
LwIP_Init();
|
||||
reset_wifi_struct();
|
||||
data.initialized = true;
|
||||
}
|
||||
LT_HEAP_I();
|
||||
if (getMode()) {
|
||||
// stop wifi to change mode
|
||||
LT_DM(WIFI, "Stopping WiFi to change mode");
|
||||
if (wifi_off() != RTW_SUCCESS)
|
||||
goto error;
|
||||
vTaskDelay(20);
|
||||
if (mode == WIFI_MODE_NULL)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (wifi_on((rtw_mode_t)mode) != RTW_SUCCESS) {
|
||||
LT_EM(WIFI, "Error while changing mode(%u)", mode);
|
||||
goto error;
|
||||
}
|
||||
|
||||
// send STA start/stop events and AP stop event (start is handled in softAP())
|
||||
if (sta == WLMODE_ENABLE) {
|
||||
wifi_indication(WIFI_EVENT_CONNECT, NULL, ARDUINO_EVENT_WIFI_STA_START, -2);
|
||||
} else if (sta == WLMODE_DISABLE) {
|
||||
wifi_indication(WIFI_EVENT_CONNECT, NULL, ARDUINO_EVENT_WIFI_STA_STOP, -2);
|
||||
}
|
||||
if (ap == WLMODE_DISABLE) {
|
||||
wifi_indication(WIFI_EVENT_CONNECT, NULL, ARDUINO_EVENT_WIFI_AP_STOP, -2);
|
||||
}
|
||||
|
||||
LT_HEAP_I();
|
||||
__wrap_rtl_printf_enable();
|
||||
__wrap_DiagPrintf_enable();
|
||||
return true;
|
||||
|
||||
error:
|
||||
__wrap_rtl_printf_enable();
|
||||
__wrap_DiagPrintf_enable();
|
||||
return false;
|
||||
}
|
||||
|
||||
WiFiMode WiFiClass::getMode() {
|
||||
if (!data.initialized)
|
||||
return WIFI_MODE_NULL;
|
||||
return (WiFiMode)wifi_mode;
|
||||
}
|
||||
|
||||
WiFiStatus WiFiClass::status() {
|
||||
if (wifi_is_connected_to_ap() == 0) {
|
||||
return WL_CONNECTED;
|
||||
} else {
|
||||
return WL_DISCONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
bool WiFiClass::setSleep(bool enable) {
|
||||
LT_DM(WIFI, "WiFi sleep mode %u", enable);
|
||||
if (enable) {
|
||||
if (wifi_enable_powersave() != RTW_SUCCESS)
|
||||
return false;
|
||||
} else {
|
||||
if (wifi_disable_powersave() != RTW_SUCCESS)
|
||||
return false;
|
||||
}
|
||||
data.sleep = enable;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WiFiClass::getSleep() {
|
||||
return data.sleep;
|
||||
}
|
||||
|
||||
bool WiFiClass::setTxPower(int power) {
|
||||
return false; // wifi_set_txpower(power) == RTW_SUCCESS;
|
||||
}
|
||||
|
||||
int WiFiClass::getTxPower() {
|
||||
return 0;
|
||||
int power = 0;
|
||||
wifi_get_txpower(&power);
|
||||
return power;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-04-25. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <api/WiFi/WiFi.h>
|
||||
|
||||
extern "C" {
|
||||
|
||||
// copy defines from PIO builder (for IDE to understand)
|
||||
#define LWIP_TIMEVAL_PRIVATE 0
|
||||
#define LWIP_NETIF_HOSTNAME 1
|
||||
#define LWIP_SO_RCVBUF 1
|
||||
|
||||
#include <FreeRTOS.h>
|
||||
#include <autoconf.h>
|
||||
#include <dhcp/dhcps.h>
|
||||
#include <lwip/api.h>
|
||||
#include <lwip/dns.h>
|
||||
#include <lwip/err.h>
|
||||
#include <lwip_netconf.h>
|
||||
#include <semphr.h>
|
||||
#include <wifi_conf.h>
|
||||
#include <wifi_constants.h>
|
||||
#include <wifi_structures.h>
|
||||
|
||||
extern struct netif xnetif[NET_IF_NUM];
|
||||
|
||||
} // extern "C"
|
||||
|
||||
// WiFi.cpp
|
||||
extern rtw_network_info_t wifi;
|
||||
extern rtw_ap_info_t ap;
|
||||
extern rtw_wifi_setting_t wifi_setting;
|
||||
extern unsigned char sta_password[65];
|
||||
extern unsigned char ap_password[65];
|
||||
extern void reset_wifi_struct(void);
|
||||
extern rtw_mode_t wifi_mode;
|
||||
extern WiFiAuthMode securityTypeToAuthMode(uint8_t type);
|
||||
// WiFiEvents.cpp
|
||||
extern void startWifiTask();
|
||||
extern void handleRtwEvent(uint16_t event, char *data, int len, int flags);
|
||||
|
||||
#define NETIF_RTW_STA &xnetif[RTW_STA_INTERFACE]
|
||||
#define NETIF_RTW_AP (wifi_mode == WIFI_MODE_APSTA ? &xnetif[RTW_AP_INTERFACE] : NETIF_RTW_STA)
|
||||
|
||||
#define NETNAME_STA WLAN0_NAME
|
||||
#define NETNAME_AP (wifi_mode == WIFI_MODE_APSTA ? WLAN1_NAME : WLAN0_NAME)
|
||||
@@ -1,8 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-06-27. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <api/WiFi/WiFi.h>
|
||||
#include <lwip/LwIPServer.h>
|
||||
|
||||
typedef LwIPServer WiFiServer;
|
||||
@@ -1,8 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-09-10. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <api/WiFi/WiFi.h>
|
||||
#include <lwip/LwIPUdp.h>
|
||||
|
||||
typedef LwIPUDP WiFiUDP;
|
||||
@@ -1,31 +0,0 @@
|
||||
<!-- This file is auto-generated -->
|
||||
|
||||
- [Generic - BK7231N (Tuya QFN32)](../boards/generic-bk7231n-qfn32-tuya/README.md)
|
||||
- [Generic - BK7231T (Tuya QFN32)](../boards/generic-bk7231t-qfn32-tuya/README.md)
|
||||
- [Generic - BK7252](../boards/generic-bk7252/README.md)
|
||||
- [Generic - RTL8710BN (2M/468k)](../boards/generic-rtl8710bn-2mb-468k/README.md)
|
||||
- [Generic - RTL8710BN (2M/788k)](../boards/generic-rtl8710bn-2mb-788k/README.md)
|
||||
- [Generic - RTL8710BX (4M/980k)](../boards/generic-rtl8710bx-4mb-980k/README.md)
|
||||
- [Generic - RTL8720CF (2M/992k)](../boards/generic-rtl8720cf-2mb-992k/README.md)
|
||||
- [BW12](../boards/bw12/README.md)
|
||||
- [BW15](../boards/bw15/README.md)
|
||||
- [CB2L](../boards/cb2l/README.md)
|
||||
- [CB2S](../boards/cb2s/README.md)
|
||||
- [CB3L](../boards/cb3l/README.md)
|
||||
- [CB3S](../boards/cb3s/README.md)
|
||||
- [CB3SE](../boards/cb3se/README.md)
|
||||
- [WB2L](../boards/wb2l/README.md)
|
||||
- [WB2S](../boards/wb2s/README.md)
|
||||
- [WB3L](../boards/wb3l/README.md)
|
||||
- [WB3S](../boards/wb3s/README.md)
|
||||
- [WR2](../boards/wr2/README.md)
|
||||
- [WR2E](../boards/wr2e/README.md)
|
||||
- [WR3](../boards/wr3/README.md)
|
||||
- [WR3E](../boards/wr3e/README.md)
|
||||
- [WR3N](../boards/wr3n/README.md)
|
||||
- [WR2L](../boards/wr2l/README.md)
|
||||
- [WR2LE](../boards/wr2le/README.md)
|
||||
- [WR3L](../boards/wr3l/README.md)
|
||||
- [WR3LE](../boards/wr3le/README.md)
|
||||
- [LSC LMA35](../boards/lsc-lma35/README.md)
|
||||
- [Generic - Host-native](../boards/generic-native/README.md)
|
||||
8
boards/_base/beken-7231-tuya.json
Normal file
8
boards/_base/beken-7231-tuya.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"build": {
|
||||
"bkcrypt_coeffs": "510fb093a3cbeadc5993a17ec7adeb03"
|
||||
},
|
||||
"flash": {
|
||||
"tuya": "0x1ED000+0x13000"
|
||||
}
|
||||
}
|
||||
10
boards/_base/beken-7231.json
Normal file
10
boards/_base/beken-7231.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"build": {
|
||||
"ldscript": "bk7231_bsp.ld",
|
||||
"bkoffset_app": "0x10000",
|
||||
"bkrbl_size_app": "0x108700"
|
||||
},
|
||||
"upload": {
|
||||
"maximum_size": 1083136
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"build": {
|
||||
"bkcrypt_coeffs": "510fb093a3cbeadc5993a17ec7adeb03",
|
||||
"bkboot_version": "1.0.1-bk7231n"
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"build": {
|
||||
"family": "BK7231N",
|
||||
"ldscript_sdk": "bk7231n_bsp.ld",
|
||||
"ldscript_arduino": "bk7231n_bsp.ld",
|
||||
"ldscript": "bk7231n_bsp.ld",
|
||||
"bkboot_version": "1.0.1-bk7231n",
|
||||
"bkrbl_size_app": "0x107800"
|
||||
"bkoffset_app": "0x10000",
|
||||
"bkrbl_size_app": "0x108700"
|
||||
},
|
||||
"flash": {
|
||||
"bootloader": "0x000000+0x11000",
|
||||
|
||||
19
boards/_base/beken-7231q.json
Normal file
19
boards/_base/beken-7231q.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"build": {
|
||||
"family": "BK7231Q",
|
||||
"bkboot_version": "bk7231q"
|
||||
},
|
||||
"flash": {
|
||||
"bootloader": "0x000000+0x11000",
|
||||
"app": "0x011000+0x121000",
|
||||
"download": "0x132000+0xA6000",
|
||||
"kvs": "0x1D8000+0x8000",
|
||||
"calibration": "0x1E0000+0x1000",
|
||||
"tlv": "0x1E1000+0x1000",
|
||||
"net": "0x1E2000+0x1000",
|
||||
"userdata": "0x1E3000+0x1D000"
|
||||
},
|
||||
"upload": {
|
||||
"speed": 460800
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"build": {
|
||||
"bkcrypt_coeffs": "510fb093a3cbeadc5993a17ec7adeb03",
|
||||
"bkboot_version": "1.0.5-bk7231s"
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,7 @@
|
||||
{
|
||||
"build": {
|
||||
"family": "BK7231U",
|
||||
"ldscript_sdk": "bk7231_bsp.ld",
|
||||
"ldscript_arduino": "bk7231_bsp.ld",
|
||||
"bkboot_version": "1.0.8-bk7231u",
|
||||
"bkrbl_size_app": "0x108700"
|
||||
"family": "BK7231T",
|
||||
"bkboot_version": "1.0.5-bk7231s"
|
||||
},
|
||||
"flash": {
|
||||
"bootloader": "0x000000+0x11000",
|
||||
@@ -17,7 +14,6 @@
|
||||
"userdata": "0x1E3000+0x1D000"
|
||||
},
|
||||
"upload": {
|
||||
"maximum_size": 1083136,
|
||||
"speed": 921600
|
||||
},
|
||||
"connectivity": [
|
||||
@@ -2,9 +2,9 @@
|
||||
"build": {
|
||||
"family": "BK7251",
|
||||
"f_cpu": "180000000L",
|
||||
"ldscript_sdk": "bk7231_bsp.ld",
|
||||
"ldscript_arduino": "bk7231_bsp.ld",
|
||||
"ldscript": "bk7231_bsp.ld",
|
||||
"bkboot_version": "0.1.3-bk7252",
|
||||
"bkoffset_app": "0x10000",
|
||||
"bkrbl_size_app": "0x1A0000"
|
||||
},
|
||||
"flash": {
|
||||
|
||||
@@ -22,10 +22,6 @@
|
||||
"mem 0x000000 0x200000 ro"
|
||||
]
|
||||
},
|
||||
"frameworks": [
|
||||
"beken-72xx-sdk",
|
||||
"beken-72xx-arduino"
|
||||
],
|
||||
"upload": {
|
||||
"maximum_ram_size": 262144,
|
||||
"flash_size": 2097152,
|
||||
@@ -45,9 +41,7 @@
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"General info": "../../docs/platform/beken-72xx/README.md",
|
||||
"Flashing guide": "../../docs/platform/beken-72xx/flashing.md",
|
||||
"BkWriter v1.6.0": "https://images.tuyacn.com/smart/bk_writer1.60/bk_writer1.60.exe"
|
||||
"Info & flashing guide": "../../docs/platform/beken-72xx/README.md"
|
||||
},
|
||||
"extra": [
|
||||
"Bootloader and app partitions contain CRC16 sums every 32 bytes. That results in the actual flash offsets/sizes not aligned to sector boundaries. To simplify calculations, the values shown in the table (extracted from bootloader's partition table) were aligned to 4096 bytes."
|
||||
|
||||
170
boards/_base/ic/bk7231q-qfn40.json
Normal file
170
boards/_base/ic/bk7231q-qfn40.json
Normal file
@@ -0,0 +1,170 @@
|
||||
{
|
||||
"pcb": {
|
||||
"ic": {
|
||||
"11": {
|
||||
"C_NAME": "GPIO30",
|
||||
"GPIO": "P30",
|
||||
"IRQ": null,
|
||||
"USB": "DN"
|
||||
},
|
||||
"12": {
|
||||
"C_NAME": "GPIO29",
|
||||
"GPIO": "P29",
|
||||
"IRQ": null,
|
||||
"USB": "DP"
|
||||
},
|
||||
"14": {
|
||||
"C_NAME": "GPIO6",
|
||||
"GPIO": "P6",
|
||||
"IRQ": null,
|
||||
"PWM": 0
|
||||
},
|
||||
"15": {
|
||||
"C_NAME": "GPIO7",
|
||||
"GPIO": "P7",
|
||||
"IRQ": null,
|
||||
"PWM": 1
|
||||
},
|
||||
"16": {
|
||||
"C_NAME": "GPIO8",
|
||||
"GPIO": "P8",
|
||||
"IRQ": null,
|
||||
"PWM": 2
|
||||
},
|
||||
"17": {
|
||||
"C_NAME": "GPIO17",
|
||||
"GPIO": "P17",
|
||||
"IRQ": null,
|
||||
"SD": "D1",
|
||||
"SPI": "MISO"
|
||||
},
|
||||
"18": {
|
||||
"C_NAME": "GPIO16",
|
||||
"GPIO": "P16",
|
||||
"IRQ": null,
|
||||
"SD": "D0",
|
||||
"SPI": "MOSI"
|
||||
},
|
||||
"19": {
|
||||
"C_NAME": "GPIO14",
|
||||
"GPIO": "P14",
|
||||
"IRQ": null,
|
||||
"SD": "CLK",
|
||||
"SPI": "SCK"
|
||||
},
|
||||
"20": {
|
||||
"C_NAME": "GPIO15",
|
||||
"GPIO": "P15",
|
||||
"IRQ": null,
|
||||
"SD": "CMD",
|
||||
"SPI": "CS"
|
||||
},
|
||||
"21": {
|
||||
"C_NAME": "GPIO19",
|
||||
"GPIO": "P19",
|
||||
"IRQ": null,
|
||||
"SD": "D3",
|
||||
"PWM": 5
|
||||
},
|
||||
"22": {
|
||||
"C_NAME": "GPIO18",
|
||||
"GPIO": "P18",
|
||||
"IRQ": null,
|
||||
"SD": "D2",
|
||||
"PWM": 4
|
||||
},
|
||||
"23": {
|
||||
"IO": "I",
|
||||
"CTRL": "TEST"
|
||||
},
|
||||
"24": {
|
||||
"C_NAME": "GPIO9",
|
||||
"GPIO": "P9",
|
||||
"IRQ": null,
|
||||
"PWM": 3
|
||||
},
|
||||
"25": {
|
||||
"C_NAME": "GPIO10",
|
||||
"GPIO": "P10",
|
||||
"IRQ": null,
|
||||
"UART": "1_RX"
|
||||
},
|
||||
"26": {
|
||||
"C_NAME": "GPIO11",
|
||||
"GPIO": "P11",
|
||||
"IRQ": null,
|
||||
"UART": "1_TX"
|
||||
},
|
||||
"27": {
|
||||
"C_NAME": "GPIO1",
|
||||
"GPIO": "P1",
|
||||
"IRQ": null,
|
||||
"UART": "2_RX",
|
||||
"I2C": "2_SDA"
|
||||
},
|
||||
"28": {
|
||||
"C_NAME": "GPIO0",
|
||||
"GPIO": "P0",
|
||||
"IRQ": null,
|
||||
"UART": "2_TX",
|
||||
"I2C": "2_SCL"
|
||||
},
|
||||
"29": {
|
||||
"C_NAME": "GPIO20",
|
||||
"GPIO": "P20",
|
||||
"IRQ": null,
|
||||
"I2C": "1_SCL",
|
||||
"JTAG": "TCK",
|
||||
"FLASH": "FSCK"
|
||||
},
|
||||
"30": {
|
||||
"C_NAME": "GPIO21",
|
||||
"GPIO": "P21",
|
||||
"IRQ": null,
|
||||
"I2C": "1_SDA",
|
||||
"JTAG": "TMS",
|
||||
"FLASH": "^FCS"
|
||||
},
|
||||
"31": {
|
||||
"C_NAME": "GPIO22",
|
||||
"GPIO": "P22",
|
||||
"IRQ": null,
|
||||
"JTAG": "TDI",
|
||||
"FLASH": "FSI"
|
||||
},
|
||||
"32": {
|
||||
"C_NAME": "GPIO23",
|
||||
"GPIO": "P23",
|
||||
"IRQ": null,
|
||||
"ADC": 3,
|
||||
"JTAG": "TDO",
|
||||
"FLASH": "FSO"
|
||||
},
|
||||
"33": {
|
||||
"C_NAME": "GPIO25",
|
||||
"GPIO": "P25",
|
||||
"IRQ": null
|
||||
},
|
||||
"34": {
|
||||
"C_NAME": "GPIO28",
|
||||
"GPIO": "P28",
|
||||
"IRQ": null
|
||||
},
|
||||
"35": {
|
||||
"C_NAME": "GPIO4",
|
||||
"GPIO": "P4",
|
||||
"IRQ": null,
|
||||
"ADC": 1,
|
||||
"I2S": "DIN"
|
||||
},
|
||||
"36": {
|
||||
"IO": "I",
|
||||
"CTRL": "CODE"
|
||||
},
|
||||
"37": {
|
||||
"IO": "I",
|
||||
"CTRL": "CEN"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -103,7 +103,7 @@
|
||||
"C_NAME": "GPIO19",
|
||||
"GPIO": "P19",
|
||||
"IRQ": null,
|
||||
"SD": "D1"
|
||||
"SD": "D3"
|
||||
},
|
||||
"31": {
|
||||
"C_NAME": "GPIO17",
|
||||
|
||||
221
boards/_base/ic/ln882hk.json
Normal file
221
boards/_base/ic/ln882hk.json
Normal file
@@ -0,0 +1,221 @@
|
||||
{
|
||||
"pcb": {
|
||||
"ic": {
|
||||
"7": {
|
||||
"IO": "I",
|
||||
"CTRL": "CEN"
|
||||
},
|
||||
"8": {
|
||||
"C_NAME": "PA_0",
|
||||
"GPIO": "PA00",
|
||||
"IRQ": null,
|
||||
"ADC": 2,
|
||||
"I2C": [
|
||||
"0_SCL",
|
||||
"0_SDA"
|
||||
]
|
||||
},
|
||||
"9": {
|
||||
"C_NAME": "PA_1",
|
||||
"GPIO": "PA01",
|
||||
"IRQ": null,
|
||||
"ADC": 3,
|
||||
"SWD": "DIO",
|
||||
"I2C": [
|
||||
"0_SCL",
|
||||
"0_SDA"
|
||||
]
|
||||
},
|
||||
"10": {
|
||||
"C_NAME": "PA_2",
|
||||
"GPIO": "PA02",
|
||||
"IRQ": null,
|
||||
"UART": "0_TX",
|
||||
"I2C": [
|
||||
"0_SCL",
|
||||
"0_SDA"
|
||||
]
|
||||
},
|
||||
"11": {
|
||||
"C_NAME": "PA_3",
|
||||
"GPIO": "PA03",
|
||||
"IRQ": null,
|
||||
"UART": "0_RX",
|
||||
"I2C": [
|
||||
"0_SCL",
|
||||
"0_SDA"
|
||||
]
|
||||
},
|
||||
"12": {
|
||||
"C_NAME": "PA_4",
|
||||
"GPIO": "PA04",
|
||||
"IRQ": null,
|
||||
"ADC": 4,
|
||||
"SWD": "CLK",
|
||||
"I2C": [
|
||||
"0_SCL",
|
||||
"0_SDA"
|
||||
]
|
||||
},
|
||||
"13": {
|
||||
"C_NAME": "PA_5",
|
||||
"GPIO": "PA05",
|
||||
"IRQ": null,
|
||||
"I2C": [
|
||||
"0_SCL",
|
||||
"0_SDA"
|
||||
]
|
||||
},
|
||||
"14": {
|
||||
"C_NAME": "PA_6",
|
||||
"GPIO": "PA06",
|
||||
"IRQ": null,
|
||||
"SD": "D2",
|
||||
"I2C": [
|
||||
"0_SCL",
|
||||
"0_SDA"
|
||||
]
|
||||
},
|
||||
"15": {
|
||||
"C_NAME": "PA_7",
|
||||
"GPIO": "PA07",
|
||||
"IRQ": null,
|
||||
"SD": "D3",
|
||||
"I2S": "0_RX",
|
||||
"I2C": [
|
||||
"0_SCL",
|
||||
"0_SDA"
|
||||
]
|
||||
},
|
||||
"16": {
|
||||
"C_NAME": "PA_8",
|
||||
"GPIO": "PA08",
|
||||
"IRQ": null,
|
||||
"CTRL": "BOOT0",
|
||||
"SD": "CMD",
|
||||
"I2S": "0_WS",
|
||||
"I2C": [
|
||||
"0_SCL",
|
||||
"0_SDA"
|
||||
]
|
||||
},
|
||||
"17": {
|
||||
"C_NAME": "PA_9",
|
||||
"GPIO": "PA09",
|
||||
"IRQ": null,
|
||||
"CTRL": "BOOT1",
|
||||
"SD": "CLK",
|
||||
"I2S": "0_SCLK",
|
||||
"I2C": [
|
||||
"0_SCL",
|
||||
"0_SDA"
|
||||
]
|
||||
},
|
||||
"21": {
|
||||
"C_NAME": "PA_10",
|
||||
"GPIO": "PA10",
|
||||
"IRQ": null,
|
||||
"SD": "D0",
|
||||
"I2S": "0_TX",
|
||||
"I2C": [
|
||||
"0_SCL",
|
||||
"0_SDA"
|
||||
]
|
||||
},
|
||||
"22": {
|
||||
"C_NAME": "PA_11",
|
||||
"GPIO": "PA11",
|
||||
"IRQ": null,
|
||||
"SD": "D1",
|
||||
"I2C": [
|
||||
"0_SCL",
|
||||
"0_SDA"
|
||||
]
|
||||
},
|
||||
"23": {
|
||||
"C_NAME": "PA_12",
|
||||
"GPIO": "PA12",
|
||||
"IRQ": null,
|
||||
"I2C": [
|
||||
"0_SCL",
|
||||
"0_SDA"
|
||||
]
|
||||
},
|
||||
"24": {
|
||||
"C_NAME": "PB_3",
|
||||
"GPIO": "PB03",
|
||||
"GPIONUM": 19,
|
||||
"IRQ": null,
|
||||
"ADC": 5,
|
||||
"I2C": [
|
||||
"0_SCL",
|
||||
"0_SDA"
|
||||
]
|
||||
},
|
||||
"25": {
|
||||
"C_NAME": "PB_4",
|
||||
"GPIO": "PB04",
|
||||
"GPIONUM": 20,
|
||||
"IRQ": null,
|
||||
"ADC": 6,
|
||||
"I2C": [
|
||||
"0_SCL",
|
||||
"0_SDA"
|
||||
]
|
||||
},
|
||||
"26": {
|
||||
"C_NAME": "PB_5",
|
||||
"GPIO": "PB05",
|
||||
"GPIONUM": 21,
|
||||
"IRQ": null,
|
||||
"ADC": 7,
|
||||
"I2C": [
|
||||
"0_SCL",
|
||||
"0_SDA"
|
||||
]
|
||||
},
|
||||
"27": {
|
||||
"C_NAME": "PB_6",
|
||||
"GPIO": "PB06",
|
||||
"GPIONUM": 22,
|
||||
"IRQ": null,
|
||||
"I2C": [
|
||||
"0_SCL",
|
||||
"0_SDA"
|
||||
]
|
||||
},
|
||||
"28": {
|
||||
"C_NAME": "PB_7",
|
||||
"GPIO": "PB07",
|
||||
"GPIONUM": 23,
|
||||
"IRQ": null,
|
||||
"I2C": [
|
||||
"0_SCL",
|
||||
"0_SDA"
|
||||
]
|
||||
},
|
||||
"29": {
|
||||
"C_NAME": "PB_8",
|
||||
"GPIO": "PB08",
|
||||
"GPIONUM": 24,
|
||||
"IRQ": null,
|
||||
"UART": "1_RX",
|
||||
"I2C": [
|
||||
"0_SCL",
|
||||
"0_SDA"
|
||||
]
|
||||
},
|
||||
"30": {
|
||||
"C_NAME": "PB_9",
|
||||
"GPIO": "PB09",
|
||||
"GPIONUM": 25,
|
||||
"IRQ": null,
|
||||
"UART": "1_TX",
|
||||
"I2C": [
|
||||
"0_SCL",
|
||||
"0_SDA"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -92,6 +92,7 @@
|
||||
},
|
||||
"27": {
|
||||
"C_NAME": "AD_2",
|
||||
"GPIONUM": 41,
|
||||
"IO": "I",
|
||||
"ADC": 2
|
||||
},
|
||||
|
||||
31
boards/_base/lightning-ln882hki.json
Normal file
31
boards/_base/lightning-ln882hki.json
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"build": {
|
||||
"family": "LN882H",
|
||||
"ldscript": "ln882hki_bsp.ld",
|
||||
"bootfile": "boot_ln882h.bin"
|
||||
},
|
||||
"flash": {
|
||||
"boot": "0x000000+0x06000",
|
||||
"part_tab": "0x006000+0x01000",
|
||||
"app": "0x007000+0x12C000",
|
||||
"ota": "0x133000+0xAA000",
|
||||
"nvds": "0x1DD000+0x03000",
|
||||
"kv": "0x1E0000+0x04000",
|
||||
"kvs": "0x1E4000+0x08000",
|
||||
"user": "0x1EC000+0x14000"
|
||||
},
|
||||
"upload": {
|
||||
"flash_size": 2097152,
|
||||
"maximum_size": 1228800
|
||||
},
|
||||
"connectivity": [
|
||||
"ble"
|
||||
],
|
||||
"doc": {
|
||||
"params": {
|
||||
"extra": {
|
||||
"Bluetooth": "BLE v5.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
43
boards/_base/lightning-ln882x.json
Normal file
43
boards/_base/lightning-ln882x.json
Normal file
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"build": {
|
||||
"f_cpu": "160000000L",
|
||||
"prefix": "arm-none-eabi-"
|
||||
},
|
||||
"flash": {},
|
||||
"connectivity": [
|
||||
"wifi"
|
||||
],
|
||||
"debug": {
|
||||
"protocol": "openocd",
|
||||
"protocols": [
|
||||
"openocd"
|
||||
],
|
||||
"openocd_config": "ln882x.cfg",
|
||||
"gdb_init": [
|
||||
"mem 0x00000000 0x10000000 ro"
|
||||
]
|
||||
},
|
||||
"upload": {
|
||||
"maximum_ram_size": 302080,
|
||||
"require_upload_port": true,
|
||||
"speed": 115200,
|
||||
"protocol": "uart",
|
||||
"protocols": [
|
||||
"uart"
|
||||
]
|
||||
},
|
||||
"doc": {
|
||||
"params": {
|
||||
"manufacturer": "Lightning",
|
||||
"series": "LN882X",
|
||||
"voltage": "3.0V - 3.6V",
|
||||
"extra": {
|
||||
"Wi-Fi": "802.11 b/g/n"
|
||||
}
|
||||
},
|
||||
"links": {
|
||||
"Info & flashing guide": "../../docs/platform/lightning-ln882x/README.md",
|
||||
"Debugging": "../../docs/platform/lightning-ln882x/debugging.md"
|
||||
}
|
||||
}
|
||||
}
|
||||
90
boards/_base/pcb/afw121t.json
Normal file
90
boards/_base/pcb/afw121t.json
Normal file
@@ -0,0 +1,90 @@
|
||||
{
|
||||
"pcb": {
|
||||
"templates": [
|
||||
"99iot-21p",
|
||||
"pcb-blue-light",
|
||||
"rf-type1"
|
||||
],
|
||||
"scale": 16,
|
||||
"vars": {
|
||||
"TRACE_COLOR": "#FAFD9D"
|
||||
},
|
||||
"pinout_hidden": "I2S,TRIG,WAKE,CTS,RTS,SD",
|
||||
"pinout": {
|
||||
"1": {
|
||||
"GND": null
|
||||
},
|
||||
"2": {
|
||||
"CTRL": "RF_O"
|
||||
},
|
||||
"3": {
|
||||
"GND": null
|
||||
},
|
||||
"4": {
|
||||
"NC": null
|
||||
},
|
||||
"5": {
|
||||
"CTRL": "CEN"
|
||||
},
|
||||
"6": {
|
||||
"IC": 13,
|
||||
"ARD": "D0"
|
||||
},
|
||||
"7": {
|
||||
"IC": 14,
|
||||
"ARD": "D1"
|
||||
},
|
||||
"8": {
|
||||
"IC": 16,
|
||||
"ARD": "D2"
|
||||
},
|
||||
"9": {
|
||||
"IC": 17,
|
||||
"ARD": "D3"
|
||||
},
|
||||
"10": {
|
||||
"GND": null
|
||||
},
|
||||
"11": {
|
||||
"PWR": 3.3
|
||||
},
|
||||
"12": {
|
||||
"GND": null
|
||||
},
|
||||
"13": {
|
||||
"NC": null
|
||||
},
|
||||
"14": {
|
||||
"IC": 28,
|
||||
"ARD": "D5"
|
||||
},
|
||||
"15": {
|
||||
"IC": 29,
|
||||
"ARD": "D6"
|
||||
},
|
||||
"16": {
|
||||
"IC": 30,
|
||||
"ARD": "D7"
|
||||
},
|
||||
"17": {
|
||||
"IC": 31,
|
||||
"ARD": "D8"
|
||||
},
|
||||
"18": {
|
||||
"IC": 32,
|
||||
"ARD": "D9"
|
||||
},
|
||||
"19": {
|
||||
"IC": 1,
|
||||
"ARD": "D10"
|
||||
},
|
||||
"20": {
|
||||
"IC": 2,
|
||||
"ARD": "D4"
|
||||
},
|
||||
"21": {
|
||||
"GND": null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,14 +2,11 @@
|
||||
"pcb": {
|
||||
"templates": [
|
||||
"esp12s",
|
||||
"esp12s-shield",
|
||||
"rf-16mm-type1"
|
||||
"pcb-black",
|
||||
"rf-type1"
|
||||
],
|
||||
"vars": {
|
||||
"MASK_PRESET": "mask_black",
|
||||
"TRACE_COLOR": "#FAFD9D",
|
||||
"SILK_COLOR": "white",
|
||||
"PINTYPE_VERT": "pin_vert_2mm_cast_nohole"
|
||||
"TRACE_COLOR": "#FAFD9D"
|
||||
},
|
||||
"pinout_hidden": "I2S,TRIG,WAKE,CTS,RTS,SD",
|
||||
"pinout": {
|
||||
|
||||
@@ -2,15 +2,9 @@
|
||||
"pcb": {
|
||||
"templates": [
|
||||
"esp12s",
|
||||
"esp12s-shield",
|
||||
"rf-16mm-type1"
|
||||
"pcb-black",
|
||||
"rf-type1"
|
||||
],
|
||||
"vars": {
|
||||
"MASK_PRESET": "mask_black",
|
||||
"TRACE_COLOR": "#FAFD9D",
|
||||
"SILK_COLOR": "white",
|
||||
"PINTYPE_VERT": "pin_vert_2mm_cast_nohole"
|
||||
},
|
||||
"pinout_hidden": "I2S,TRIG,WAKE,CTS,RTS,SD",
|
||||
"pinout": {
|
||||
"1": {
|
||||
|
||||
69
boards/_base/pcb/cb1s-test.json
Normal file
69
boards/_base/pcb/cb1s-test.json
Normal file
@@ -0,0 +1,69 @@
|
||||
{
|
||||
"pcb": {
|
||||
"scale": 14,
|
||||
"test_pads": {
|
||||
"TSCK": "cb1s.back.sck.anchor",
|
||||
"TCSN": "cb1s.back.csn.anchor",
|
||||
"TSI": "cb1s.back.si.anchor",
|
||||
"TSO": "cb1s.back.so.anchor"
|
||||
},
|
||||
"back": [
|
||||
{
|
||||
"name": "test_pad_1mm",
|
||||
"pos": "2.66,14.4"
|
||||
},
|
||||
{
|
||||
"name": "test_pad_1mm",
|
||||
"pos": "2.66,15.9"
|
||||
},
|
||||
{
|
||||
"name": "test_pad_1mm",
|
||||
"pos": "2.66,17.4"
|
||||
},
|
||||
{
|
||||
"name": "test_pad_1mm",
|
||||
"pos": "2.66,18.9"
|
||||
},
|
||||
{
|
||||
"id": "sck",
|
||||
"name": "label_line_down",
|
||||
"pos": "3.5,14.3",
|
||||
"vars": {
|
||||
"DIR": "right",
|
||||
"W": 1.0,
|
||||
"H": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "csn",
|
||||
"name": "label_line_down",
|
||||
"pos": "3.5,15.8",
|
||||
"vars": {
|
||||
"DIR": "right",
|
||||
"W": 1.0,
|
||||
"H": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "si",
|
||||
"name": "label_line_down",
|
||||
"pos": "3.5,17.3",
|
||||
"vars": {
|
||||
"DIR": "right",
|
||||
"W": 1.0,
|
||||
"H": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "so",
|
||||
"name": "label_line_down",
|
||||
"pos": "3.5,18.8",
|
||||
"vars": {
|
||||
"DIR": "right",
|
||||
"W": 1.0,
|
||||
"H": 0
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
101
boards/_base/pcb/cb1s.json
Normal file
101
boards/_base/pcb/cb1s.json
Normal file
@@ -0,0 +1,101 @@
|
||||
{
|
||||
"pcb": {
|
||||
"templates": [
|
||||
"tuya1",
|
||||
"pcb-blue-light",
|
||||
"tuya-16x24",
|
||||
"rf-type1"
|
||||
],
|
||||
"scale": 15,
|
||||
"pinout_hidden": "I2S,TRIG,WAKE,CTS,RTS,SD",
|
||||
"pinout": {
|
||||
"1": {
|
||||
"PWR": "VCC5"
|
||||
},
|
||||
"2": {
|
||||
"IC": 27,
|
||||
"ARD": "D0"
|
||||
},
|
||||
"3": {
|
||||
"IC": 26,
|
||||
"ARD": "D1"
|
||||
},
|
||||
"4": {
|
||||
"PWR": 3.3
|
||||
},
|
||||
"5": {
|
||||
"GND": null
|
||||
},
|
||||
"6": {
|
||||
"IC": 22,
|
||||
"ARD": "D2"
|
||||
},
|
||||
"7": {
|
||||
"IC": 23,
|
||||
"ARD": "D3"
|
||||
},
|
||||
"8": {
|
||||
"IC": 29,
|
||||
"ARD": "D4"
|
||||
},
|
||||
"9": {
|
||||
"IC": 25,
|
||||
"ARD": "D5"
|
||||
},
|
||||
"10": {
|
||||
"IC": 24,
|
||||
"ARD": "D6"
|
||||
},
|
||||
"11": {
|
||||
"IC": 28,
|
||||
"ARD": "D7"
|
||||
},
|
||||
"12": {
|
||||
"IC": 16,
|
||||
"ARD": "D8"
|
||||
},
|
||||
"13": {
|
||||
"IC": 15,
|
||||
"ARD": "D9"
|
||||
},
|
||||
"14": {
|
||||
"GND": null
|
||||
},
|
||||
"15": {
|
||||
"GND": null
|
||||
},
|
||||
"16": {
|
||||
"IC": 21
|
||||
},
|
||||
"17": {
|
||||
"IC": 17,
|
||||
"ARD": [
|
||||
"D10",
|
||||
"A0"
|
||||
]
|
||||
},
|
||||
"18": {
|
||||
"GND": null
|
||||
},
|
||||
"TSCK": {
|
||||
"IC": 20,
|
||||
"ARD": "D11"
|
||||
},
|
||||
"TCSN": {
|
||||
"IC": 19,
|
||||
"ARD": "D12"
|
||||
},
|
||||
"TSO": {
|
||||
"IC": 17,
|
||||
"ARD": [
|
||||
"D10",
|
||||
"A0"
|
||||
]
|
||||
},
|
||||
"TSI": {
|
||||
"IC": 18,
|
||||
"ARD": "D13"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
{
|
||||
"pcb": {
|
||||
"scale": 11,
|
||||
"test_pads": {
|
||||
"TRST": "cb2l.back.rst.anchor",
|
||||
"TRX1": "cb2l.back.u1_rxd.anchor",
|
||||
@@ -10,26 +9,12 @@
|
||||
"TCSN": "cb2l.back.f_csn.anchor"
|
||||
},
|
||||
"back": [
|
||||
{
|
||||
"type": "rect",
|
||||
"pos": "0,0",
|
||||
"size": "15,17.3",
|
||||
"preset": "${MASK_PRESET}"
|
||||
},
|
||||
{
|
||||
"name": "pins_horz7_2mm_0.7mm",
|
||||
"pos": "1.15,17.3",
|
||||
"vars": {
|
||||
"PINTYPE": "${PINTYPE_HORZ}",
|
||||
"PINDIR": "down"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "test_pad_1mm",
|
||||
"pos": "1.5,7.5"
|
||||
},
|
||||
{
|
||||
"name": "label_line_2mm_down",
|
||||
"name": "label_line_down",
|
||||
"pos": "0.4,4.7",
|
||||
"vars": {
|
||||
"DIR": "right",
|
||||
@@ -51,7 +36,7 @@
|
||||
},
|
||||
{
|
||||
"id": "u2_txd",
|
||||
"name": "label_line_2mm_up",
|
||||
"name": "label_line_up",
|
||||
"pos": "2.2,5.1",
|
||||
"vars": {
|
||||
"DIR": "left",
|
||||
@@ -65,7 +50,7 @@
|
||||
},
|
||||
{
|
||||
"id": "u1_txd",
|
||||
"name": "label_line_2mm_up",
|
||||
"name": "label_line_up",
|
||||
"pos": "4.0,5.1",
|
||||
"vars": {
|
||||
"DIR": "left",
|
||||
@@ -79,7 +64,7 @@
|
||||
},
|
||||
{
|
||||
"id": "gnd",
|
||||
"name": "label_line_2mm_up",
|
||||
"name": "label_line_up",
|
||||
"pos": "9.2,5.1",
|
||||
"vars": {
|
||||
"DIR": "left",
|
||||
@@ -93,7 +78,7 @@
|
||||
},
|
||||
{
|
||||
"id": "rst",
|
||||
"name": "label_line_2mm_up",
|
||||
"name": "label_line_up",
|
||||
"pos": "2.2,9.9",
|
||||
"vars": {
|
||||
"DIR": "left",
|
||||
@@ -107,7 +92,7 @@
|
||||
},
|
||||
{
|
||||
"id": "f_csn",
|
||||
"name": "label_line_2mm_down",
|
||||
"name": "label_line_down",
|
||||
"pos": "2.2,12.8",
|
||||
"vars": {
|
||||
"DIR": "left",
|
||||
|
||||
@@ -2,15 +2,9 @@
|
||||
"pcb": {
|
||||
"templates": [
|
||||
"tuya2l",
|
||||
"rf-15mm-type1",
|
||||
"tuya2l-shield"
|
||||
"pcb-white",
|
||||
"rf-type1"
|
||||
],
|
||||
"vars": {
|
||||
"MASK_PRESET": "mask_white",
|
||||
"TRACE_COLOR": "#E0E0E0",
|
||||
"SILK_COLOR": "black",
|
||||
"PINTYPE_HORZ": "pin_horz_2mm_cast_hole"
|
||||
},
|
||||
"pinout_hidden": "I2S,I2C,JTAG,FLASH",
|
||||
"pinout": {
|
||||
"1": {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user