Compare commits
167 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b85f6f8c3f | ||
|
|
d036ac9fba | ||
|
|
f63a114371 | ||
|
|
8cb59661ac | ||
|
|
fc1da609f2 | ||
|
|
c6566323fd | ||
|
|
30e1533ad9 | ||
|
|
71dfea1904 | ||
|
|
4fa7457423 | ||
|
|
9583bb35f5 | ||
|
|
e806c4db3a | ||
|
|
665ab22de5 | ||
|
|
ec4e946643 | ||
|
|
9e4bbe3e36 | ||
|
|
1172c1a852 | ||
|
|
8a4392bb22 | ||
|
|
a79a2d60d3 | ||
|
|
9553ff66a3 | ||
|
|
79c6f05291 | ||
|
|
3e691de24a | ||
|
|
303def49cb | ||
|
|
18653781d5 | ||
|
|
2a75bdbeda | ||
|
|
4a6926eb6c | ||
|
|
3dc4007fa7 | ||
|
|
9c3833d66c | ||
|
|
41966f33c2 | ||
|
|
50fea2a8f0 | ||
|
|
05cb7f7947 | ||
|
|
5b6b80e3cd | ||
|
|
2c59af8399 | ||
|
|
b404f9fa42 | ||
|
|
8dc8340ce4 | ||
|
|
30f08a145e | ||
|
|
d3d140fa60 | ||
|
|
5f8e687e68 | ||
|
|
fab640901d | ||
|
|
9a053fb6ff | ||
|
|
24e4b0b376 | ||
|
|
b8eee999e2 | ||
|
|
7fe9a114b7 | ||
|
|
05b2fb4fcb | ||
|
|
830d8762cd | ||
|
|
3f81666369 | ||
|
|
d40f4003b5 | ||
|
|
1585e425ce | ||
|
|
bbc7613079 | ||
|
|
ec54745174 | ||
|
|
a29453de12 | ||
|
|
db5bf4fc46 | ||
|
|
9495e3418c | ||
|
|
83573a743b | ||
|
|
f5dcd82747 | ||
|
|
070ec2f48f | ||
|
|
96c7fdc02c | ||
|
|
dfde2d8a62 | ||
|
|
a3f57114da | ||
|
|
904af10914 | ||
|
|
9b5013a694 | ||
|
|
922adfd3d4 | ||
|
|
362144033b | ||
|
|
caf9a579d3 | ||
|
|
cb40fdcdbe | ||
|
|
ef15e754c9 | ||
|
|
d55568c146 | ||
|
|
e134863db1 | ||
|
|
c37ae51dd3 | ||
|
|
4fc2ff43c1 | ||
|
|
607f13d935 | ||
|
|
44c1a3f695 | ||
|
|
d30decfbc8 | ||
|
|
705b2f794e | ||
|
|
4958690d9e | ||
|
|
d7749d3a24 | ||
|
|
73e07a594f | ||
|
|
755c2ef400 | ||
|
|
3f588e970a | ||
|
|
3264807e77 | ||
|
|
01225d4648 | ||
|
|
48aa809c98 | ||
|
|
4a722d4069 | ||
|
|
07aca2a0e7 | ||
|
|
10000d9b6c | ||
|
|
f0e247f31e | ||
|
|
593dec5e88 | ||
|
|
c45b86c993 | ||
|
|
02f01f2199 | ||
|
|
88b1adc2d6 | ||
|
|
a0a0e6775b | ||
|
|
4096253694 | ||
|
|
33ba44ebda | ||
|
|
9b4cf2a92b | ||
|
|
e6b915d8e3 | ||
|
|
bb73fb5f55 | ||
|
|
10c5945afb | ||
|
|
0bd613d556 | ||
|
|
aae2f65b9e | ||
|
|
d02197474e | ||
|
|
41b37e9c24 | ||
|
|
b03400fac2 | ||
|
|
3e808f7b6b | ||
|
|
1e3a8971fb | ||
|
|
d8c0105b97 | ||
|
|
b3689cbac8 | ||
|
|
1b5d6472f7 | ||
|
|
e9511c507a | ||
|
|
365f64ded5 | ||
|
|
3601fa63d8 | ||
|
|
5d00ddf516 | ||
|
|
0051453cad | ||
|
|
7920ea2dda | ||
|
|
9416e45a75 | ||
|
|
98a65c81af | ||
|
|
8e1f06e79b | ||
|
|
58a09f453d | ||
|
|
7dc69982b6 | ||
|
|
46e4041ed8 | ||
|
|
0e129130b1 | ||
|
|
33c9868f90 | ||
|
|
fb04b1830e | ||
|
|
9509194bd0 | ||
|
|
60322a243a | ||
|
|
4ed7067537 | ||
|
|
69086e8fba | ||
|
|
a4b63bb037 | ||
|
|
5ffb2f6619 | ||
|
|
41eaf9b9e4 | ||
|
|
28bb777399 | ||
|
|
f375a35cc8 | ||
|
|
1d41d84083 | ||
|
|
357be177fc | ||
|
|
23c3335de8 | ||
|
|
963b164783 | ||
|
|
0c22a02641 | ||
|
|
10cb5c2c76 | ||
|
|
6d36c9ef7b | ||
|
|
aed97a5e92 | ||
|
|
b6008fc9bb | ||
|
|
f9359679ad | ||
|
|
052d7be1a9 | ||
|
|
ead577a116 | ||
|
|
ccf7d972ce | ||
|
|
b2df9e6a8b | ||
|
|
e37014ebd6 | ||
|
|
c96ef2ff7a | ||
|
|
c19dd0d87e | ||
|
|
02f972bd5f | ||
|
|
15facd8866 | ||
|
|
cf584c3bd6 | ||
|
|
4744351964 | ||
|
|
31b753ab5a | ||
|
|
3cb944dde2 | ||
|
|
1b4265f522 | ||
|
|
5d16338faa | ||
|
|
673b8233e5 | ||
|
|
0dd2e2583b | ||
|
|
c19f24cbfd | ||
|
|
cfb6830d95 | ||
|
|
27dea356cf | ||
|
|
352a425c4f | ||
|
|
4beaa79d02 | ||
|
|
e54eab83f2 | ||
|
|
e74a491b4a | ||
|
|
a9415c1db7 | ||
|
|
a83959ab5f | ||
|
|
b1896002e5 | ||
|
|
cc39de9b04 |
3
.github/FUNDING.yml
vendored
Normal file
3
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
ko_fi: kuba2k2
|
||||
custom:
|
||||
- "https://paypal.me/kuba2k2"
|
||||
22
.github/workflows/docs.yml
vendored
22
.github/workflows/docs.yml
vendored
@@ -13,10 +13,30 @@ jobs:
|
||||
- name: Checkout main
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
- name: Install ltchiptool
|
||||
run: pip install ltchiptool
|
||||
|
||||
- name: Generate static JSON files
|
||||
run: |
|
||||
mkdir -p site/
|
||||
python docs/build_json.py
|
||||
cp *.json site/
|
||||
|
||||
- name: Set custom domain
|
||||
run: |
|
||||
mkdir -p site/
|
||||
echo docs.libretuya.ml > site/CNAME
|
||||
|
||||
- name: Deploy docs
|
||||
uses: mhausenblas/mkdocs-deploy-gh-pages@master
|
||||
uses: libretuya/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
|
||||
|
||||
14
README.md
14
README.md
@@ -35,7 +35,7 @@ LibreTuya also provides a common interface for all family implementations. The i
|
||||
|
||||
## Board List
|
||||
|
||||
See [Boards & CPU list](https://kuba2k2.github.io/libretuya/docs/supported/).
|
||||
See [Boards & CPU list](https://kuba2k2.github.io/libretuya/docs/status/supported/).
|
||||
|
||||
## Arduino Core support status
|
||||
|
||||
@@ -44,18 +44,18 @@ Note: this list will probably change with each functionality update.
|
||||
| `realtek-ambz` | `beken-72xx`
|
||||
--------------------|----------------|-------------
|
||||
Core functions | ✔️ | ✔️
|
||||
GPIO/PWM/IRQ | ✔️/✔️/✔️ | ❓/✔️/❌
|
||||
GPIO/PWM/IRQ | ✔️/✔️/✔️ | ✔️/✔️/✔️
|
||||
Analog input (ADC) | ✔️ | ✔️
|
||||
Serial | ✔️ | ✔️
|
||||
Serial (extra) | ❌ | 1, 2
|
||||
Serial (extra) | 0, 1, 2 | 1, 2
|
||||
Flash I/O | ✔️ | ✔️
|
||||
**CORE LIBRARIES** | |
|
||||
SoftwareSerial | ❌ | ❌
|
||||
SoftwareSerial | ✔️ | ❌
|
||||
SPI | ❌ | ❌
|
||||
Wire | ❗ | ❌
|
||||
**OTHER LIBRARIES** | |
|
||||
Wi-Fi STA/AP/Mixed | ✔️ | ✔️/❌/❌
|
||||
Wi-Fi Events | ✔️ | ❌
|
||||
Wi-Fi STA/AP/Mixed | ✔️ | ✔️
|
||||
Wi-Fi Events | ✔️ | ✔️
|
||||
TCP Client (SSL) | ✔️ (✔️) | ✔️ (❗)
|
||||
TCP Server | ✔️ | ✔️
|
||||
IPv6 | ❌ | ❌
|
||||
@@ -65,7 +65,7 @@ NVS / Preferences | ❌ | ❌
|
||||
SPIFFS | ❌ | ❌
|
||||
BLE | - | ❌
|
||||
NTP | ❌ | ❌
|
||||
OTA | ✔️ | ❌
|
||||
OTA | ✔️ | ✔️
|
||||
MDNS | ✔️ | ✔️
|
||||
MQTT | ✅ | ❌
|
||||
SD | ❌ | ❌
|
||||
|
||||
54
SUMMARY.md
54
SUMMARY.md
@@ -1,9 +1,32 @@
|
||||
* [Home](README.md)
|
||||
* [💻 Boards & CPU list](docs/supported.md)
|
||||
* [✔️ Implementation status](docs/implementation-status.md)
|
||||
* [🔧 Configuration](docs/config.md)
|
||||
* [📁 Project structure](docs/project-structure.md)
|
||||
* 🔖 Code reference
|
||||
* 😊 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)
|
||||
@@ -14,6 +37,7 @@
|
||||
* Common API
|
||||
* [FS](ltapi/classfs_1_1_f_s.md)
|
||||
* [Preferences](ltapi/class_i_preferences.md)
|
||||
* [SoftwareSerial](ltapi/class_software_serial.md)
|
||||
* [WiFi API](ltapi/class_wi_fi_class.md)
|
||||
* [TCP Client](ltapi/class_i_wi_fi_client.md)
|
||||
* [SSL Client](ltapi/class_i_wi_fi_client_secure.md)
|
||||
@@ -36,18 +60,10 @@
|
||||
* [Functions](ltapi/functions.md)
|
||||
* [Macros](ltapi/macros.md)
|
||||
* [File list](ltapi/files.md)
|
||||
* [✈️ OTA format](docs/ota/README.md)
|
||||
* [uf2ota.py tool](docs/ota/uf2ota.md)
|
||||
* [uf2ota.h library](docs/ota/library.md)
|
||||
* [uf2ota.h reference](ltapi/uf2ota_8h.md)
|
||||
* Families
|
||||
* [Realtek - notes](docs/platform/realtek/README.md)
|
||||
* [Beken 72xx - notes](docs/platform/beken-72xx/README.md)
|
||||
* Realtek AmebaZ Series
|
||||
* C library
|
||||
* [Built-in functions](docs/platform/realtek-ambz/stdlib.md)
|
||||
* [Memory management](docs/platform/realtek-ambz/memory-management.md)
|
||||
* [Debugging](docs/platform/realtek/debugging.md)
|
||||
* [Exception decoder](docs/platform/realtek/exception-decoder.md)
|
||||
* [All supported boards](boards/)
|
||||
* [📁 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)
|
||||
|
||||
43
TODO.md
Normal file
43
TODO.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# TODO list
|
||||
|
||||
## General
|
||||
|
||||
### New families
|
||||
|
||||
- BL602
|
||||
- RTL8710A
|
||||
- RTL8720C
|
||||
- RTL8720D
|
||||
- W600 and/or W800
|
||||
- LN8825
|
||||
- host-native family
|
||||
|
||||
### Tools
|
||||
|
||||
- write OpenOCD flashers, using uf2ota library + FAL for partitions (in ltchiptool repository)
|
||||
|
||||
### Serial
|
||||
|
||||
- configuration of RX/TX pins
|
||||
- SoftwareSerial library - receiving + Beken family
|
||||
|
||||
### Other
|
||||
|
||||
- watchdog API
|
||||
- `Preferences` library
|
||||
- test/fix IPv6 on different families
|
||||
- what is `PowerManagement` at all? probably useless -> remove
|
||||
|
||||
## BK7231
|
||||
|
||||
- implement OTA
|
||||
- fix WiFi on BK7231N, test other functionality
|
||||
- fix SSL (mbedTLS)
|
||||
- I2C (Wire)
|
||||
- SPI
|
||||
- BLE
|
||||
|
||||
## RTL8710B
|
||||
|
||||
- move to GNU++11 (and verify that it works) - take all stdio functions from stdio.h
|
||||
- rewrite most of Wiring (it was copied from `ambd_arduino`, and is ugly)
|
||||
@@ -6,27 +6,27 @@
|
||||
#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"
|
||||
#ifdef HAS_SERIAL_CLASS
|
||||
// declare instances of available Serial* components
|
||||
// map Serial to Serial2 if available, else to Serial1
|
||||
#ifdef PIN_SERIAL1_RX
|
||||
extern SerialClass Serial1;
|
||||
#endif
|
||||
#ifdef PIN_SERIAL2_RX
|
||||
extern SerialClass Serial2;
|
||||
#define Serial Serial2
|
||||
#else
|
||||
#define Serial Serial1
|
||||
#endif
|
||||
#endif
|
||||
#include <core/SerialExtern.h>
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/* 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
|
||||
@@ -13,16 +14,54 @@
|
||||
#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() {
|
||||
@@ -35,10 +74,9 @@ const char *LibreTuya::getChipModel() {
|
||||
}
|
||||
|
||||
uint32_t LibreTuya::getChipId() {
|
||||
// TODO determine if this really is unique
|
||||
uint32_t chipId = REG_READ(SCTRL_DEVICE_ID);
|
||||
chipId &= 0xFFFFFF;
|
||||
return chipId;
|
||||
uint8_t 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() {
|
||||
@@ -105,12 +143,19 @@ uint32_t LibreTuya::getMaxAllocHeap() {
|
||||
|
||||
/* OTA-related */
|
||||
|
||||
uint8_t LibreTuya::otaGetStoredIndex() {
|
||||
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 false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LibreTuya::otaHasImage1() {
|
||||
@@ -118,13 +163,46 @@ bool LibreTuya::otaHasImage1() {
|
||||
}
|
||||
|
||||
bool LibreTuya::otaHasImage2() {
|
||||
return false;
|
||||
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) {
|
||||
return true;
|
||||
// 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;
|
||||
|
||||
@@ -3,17 +3,19 @@
|
||||
#include "SerialClass.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
#include <uart_pub.h>
|
||||
|
||||
extern void bk_send_byte(uint8_t uport, uint8_t data);
|
||||
extern void uart_hw_set_change(uint8_t uport, bk_uart_config_t *uart_config);
|
||||
extern int uart_rx_callback_set(int uport, uart_callback callback, void *param);
|
||||
}
|
||||
|
||||
#ifdef PIN_SERIAL1_RX
|
||||
} // extern "C"
|
||||
|
||||
#ifdef PIN_SERIAL1_TX
|
||||
SerialClass Serial1(UART1_PORT);
|
||||
#endif
|
||||
#ifdef PIN_SERIAL2_RX
|
||||
#ifdef PIN_SERIAL2_TX
|
||||
SerialClass Serial2(UART2_PORT);
|
||||
#endif
|
||||
|
||||
@@ -22,9 +24,31 @@ SerialClass::SerialClass(uint8_t 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;
|
||||
buf->store_char(uart_read_byte(port));
|
||||
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) {
|
||||
@@ -39,17 +63,27 @@ void SerialClass::begin(unsigned long baudrate, uint16_t config) {
|
||||
.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;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,9 +9,10 @@ extern "C" {
|
||||
#include "sdk_extern.h"
|
||||
#include "sdk_mem.h"
|
||||
|
||||
// allow BDK use its own delay() and let Arduino code use delayMilliseconds()
|
||||
void delayMilliseconds(unsigned long);
|
||||
#define delay delayMilliseconds
|
||||
// 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;
|
||||
|
||||
@@ -3,18 +3,31 @@
|
||||
#include <Arduino.h>
|
||||
|
||||
extern "C" {
|
||||
|
||||
#include <rtos_pub.h>
|
||||
#include <sys_rtos.h>
|
||||
}
|
||||
|
||||
extern int uart_print_port;
|
||||
|
||||
} // extern "C"
|
||||
|
||||
beken_thread_t mainThread;
|
||||
|
||||
void initArduino() {
|
||||
// set default UART output port
|
||||
uart_print_port = LT_UART_DEFAULT_PORT - 1;
|
||||
#if LT_AUTO_DOWNLOAD_REBOOT && defined(PIN_SERIAL1_RX) && defined(PIN_SERIAL1_TX)
|
||||
// initialize auto-download-reboot parser
|
||||
Serial1.begin(115200);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool startMainTask() {
|
||||
OSStatus ret = rtos_create_thread(
|
||||
&mainThread,
|
||||
THD_APPLICATION_PRIORITY,
|
||||
"main",
|
||||
(beken_thread_function_t)main_task,
|
||||
(beken_thread_function_t)mainTask,
|
||||
8192,
|
||||
NULL
|
||||
);
|
||||
|
||||
@@ -1,20 +1,57 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-06-19. */
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <arm_arch.h>
|
||||
#include <bk_timer.h>
|
||||
#include <bk_timer_pub.h>
|
||||
#include <rtos_pub.h>
|
||||
#include <sys_rtos.h>
|
||||
|
||||
#define TICKS_PER_US (CFG_XTAL_FREQUENCE / 1000 / 1000)
|
||||
#define US_PER_OVERFLOW (portTICK_PERIOD_MS * 1000)
|
||||
#define TICKS_PER_OVERFLOW (TICKS_PER_US * US_PER_OVERFLOW)
|
||||
|
||||
void delayMilliseconds(unsigned long ms) {
|
||||
rtos_delay_milliseconds(ms);
|
||||
}
|
||||
|
||||
static uint32_t getTicksCount() {
|
||||
// copied from bk_timer_ctrl(), for speeds
|
||||
uint32_t timeout = 0;
|
||||
REG_WRITE(TIMER0_2_READ_CTL, (BKTIMER0 << 2) | 1);
|
||||
while (REG_READ(TIMER0_2_READ_CTL) & 1) {
|
||||
timeout++;
|
||||
if (timeout > (120 * 1000))
|
||||
return 0;
|
||||
}
|
||||
return REG_READ(TIMER0_2_READ_VALUE);
|
||||
}
|
||||
|
||||
void delayMicroseconds(unsigned int us) {
|
||||
// TODO implement this properly
|
||||
us /= 10;
|
||||
#if LT_MICROS_HIGH_RES
|
||||
if (us == 0)
|
||||
return;
|
||||
us--;
|
||||
uint32_t startTick = getTicksCount();
|
||||
/* startTick2 accounts for the case where the timer counter overflows */
|
||||
uint32_t startTick2 = startTick - TICKS_PER_OVERFLOW;
|
||||
uint32_t delayTicks = TICKS_PER_US * us;
|
||||
while (delayTicks > TICKS_PER_OVERFLOW) {
|
||||
// The delay is longer than what the timer can count.
|
||||
// Let it overflow until only a fraction of TICKS_PER_OVERFLOW remain.
|
||||
while (getTicksCount() > startTick) {}
|
||||
while (getTicksCount() < startTick) {}
|
||||
delayTicks -= TICKS_PER_OVERFLOW;
|
||||
}
|
||||
while ((getTicksCount() - startTick < delayTicks) || // normal case
|
||||
(getTicksCount() - startTick2 < delayTicks) // counter overflow case
|
||||
) {}
|
||||
#else
|
||||
volatile uint32_t i, j;
|
||||
for (i = 0; i < us; i++) {
|
||||
for (j = 0; j < 100; j++) {}
|
||||
for (j = 0; j < 6; j++) {}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned long millis() {
|
||||
@@ -22,11 +59,51 @@ unsigned long millis() {
|
||||
}
|
||||
|
||||
unsigned long micros() {
|
||||
// TODO implement this properly
|
||||
#if (CFG_SOC_NAME == SOC_BK7231)
|
||||
#error "Not implemented"
|
||||
#endif
|
||||
|
||||
#if LT_MICROS_HIGH_RES
|
||||
static uint32_t lastMillis = 0;
|
||||
static uint32_t correctedMillis = 0;
|
||||
static uint32_t lastTicks = 0;
|
||||
uint32_t nowMillis = millis();
|
||||
uint32_t nowTicks = getTicksCount();
|
||||
bool tickOverflow = nowTicks < lastTicks;
|
||||
bool millisUpdated = nowMillis != lastMillis;
|
||||
if (millisUpdated) {
|
||||
/* reset artificially corrected millis */
|
||||
correctedMillis = nowMillis;
|
||||
} else if (tickOverflow) {
|
||||
/*
|
||||
This can happen if micros is called from within a interruptLock block (interrupts disabled).
|
||||
In this case, if the tick counter rolls over, millis() won't be updated, and micros will
|
||||
lag by US_PER_OVERFLOW milliseconds (one rollover).
|
||||
The workaround only works as long as micros() calls happen within 2ms of eachother.
|
||||
WARNING: if interrupts are disabled for more than 2ms, micros() and millis() will temporarily get out of sync.
|
||||
*/
|
||||
correctedMillis += portTICK_PERIOD_MS;
|
||||
}
|
||||
lastMillis = nowMillis;
|
||||
lastTicks = nowTicks;
|
||||
return correctedMillis * 1000 + nowTicks / (CFG_XTAL_FREQUENCE / 1000 / 1000);
|
||||
#else
|
||||
#if 0
|
||||
uint32_t timeout = 0;
|
||||
REG_WRITE(TIMER3_5_READ_CTL, (BKTIMER3 << 2) | 1);
|
||||
while (REG_READ(TIMER3_5_READ_CTL) & 1) {
|
||||
timeout++;
|
||||
if (timeout > (120 * 1000))
|
||||
return 0;
|
||||
}
|
||||
return millis() * 1000 + REG_READ(TIMER3_5_READ_VALUE) / 32;
|
||||
#endif
|
||||
return millis() * 1000;
|
||||
#endif
|
||||
}
|
||||
|
||||
void yield() {
|
||||
runPeriodicTasks();
|
||||
vTaskDelay(1);
|
||||
taskYIELD();
|
||||
}
|
||||
|
||||
@@ -13,6 +13,18 @@ static GPIO_INDEX pwmToGpio[] = {
|
||||
GPIO26, // PWM5
|
||||
};
|
||||
|
||||
#if CFG_SOC_NAME == SOC_BK7231N
|
||||
static GPIO_INDEX adcToGpio[] = {
|
||||
-1, // ADC0 - VBAT
|
||||
GPIONUM, // ADC1
|
||||
GPIONUM, // ADC2
|
||||
GPIO23, // ADC3
|
||||
GPIONUM, // ADC4
|
||||
GPIONUM, // ADC5
|
||||
GPIONUM, // ADC6
|
||||
GPIONUM, // ADC7
|
||||
};
|
||||
#else
|
||||
static GPIO_INDEX adcToGpio[] = {
|
||||
-1, // ADC0 - VBAT
|
||||
GPIO4, // ADC1
|
||||
@@ -23,9 +35,10 @@ static GPIO_INDEX adcToGpio[] = {
|
||||
GPIO12, // ADC6
|
||||
GPIO13, // ADC7
|
||||
};
|
||||
#endif
|
||||
|
||||
static uint8_t gpioToPwm(GPIO_INDEX gpio) {
|
||||
for (uint8_t i = 0; i < sizeof(pwmToGpio); i++) {
|
||||
for (uint8_t i = 0; i < sizeof(pwmToGpio) / sizeof(GPIO_INDEX); i++) {
|
||||
if (pwmToGpio[i] == gpio)
|
||||
return i;
|
||||
}
|
||||
@@ -33,7 +46,7 @@ static uint8_t gpioToPwm(GPIO_INDEX gpio) {
|
||||
}
|
||||
|
||||
static uint8_t gpioToAdc(GPIO_INDEX gpio) {
|
||||
for (uint8_t i = 0; i < sizeof(adcToGpio); i++) {
|
||||
for (uint8_t i = 0; i < sizeof(adcToGpio) / sizeof(GPIO_INDEX); i++) {
|
||||
if (adcToGpio[i] == gpio)
|
||||
return i;
|
||||
}
|
||||
@@ -81,33 +94,50 @@ void analogWrite(pin_size_t pinNumber, int value) {
|
||||
if (!pinSupported(pin, PIN_PWM))
|
||||
return;
|
||||
|
||||
float percent = value * 1.0 / (1 << _analogWriteResolution);
|
||||
uint32_t dutyCycle = percent * _analogWritePeriod * 26 - 1;
|
||||
float percent = value * 1.0 / ((1 << _analogWriteResolution) - 1);
|
||||
uint32_t frequency = 26 * _analogWritePeriod - 1;
|
||||
uint32_t dutyCycle = percent * frequency;
|
||||
pwm.channel = gpioToPwm(pin->gpio);
|
||||
pwm.duty_cycle = dutyCycle;
|
||||
#if CFG_SOC_NAME != SOC_BK7231N
|
||||
pwm.duty_cycle = dutyCycle;
|
||||
#else
|
||||
pwm.duty_cycle1 = dutyCycle;
|
||||
pwm.duty_cycle2 = 0;
|
||||
pwm.duty_cycle3 = 0;
|
||||
#endif
|
||||
|
||||
if (!pinEnabled(pin, PIN_PWM)) {
|
||||
// enable PWM and set its value
|
||||
pwm.cfg.bits.en = PWM_ENABLE;
|
||||
pwm.cfg.bits.int_en = PWM_INT_DIS;
|
||||
pwm.cfg.bits.mode = PWM_PWM_MODE;
|
||||
pwm.cfg.bits.clk = PWM_CLK_26M;
|
||||
pwm.end_value = 26 * _analogWritePeriod - 1;
|
||||
pwm.p_Int_Handler = NULL;
|
||||
__wrap_bk_printf_disable();
|
||||
sddev_control(PWM_DEV_NAME, CMD_PWM_INIT_PARAM, &pwm);
|
||||
__wrap_bk_printf_enable();
|
||||
pin->enabled &= ~PIN_GPIO;
|
||||
pin->enabled |= PIN_PWM;
|
||||
} else if (value == 0) {
|
||||
// disable PWM
|
||||
pwm.cfg.bits.en = PWM_DISABLE;
|
||||
__wrap_bk_printf_disable();
|
||||
sddev_control(PWM_DEV_NAME, CMD_PWM_DEINIT_PARAM, &pwm);
|
||||
__wrap_bk_printf_enable();
|
||||
pin->enabled &= ~PIN_PWM;
|
||||
if (value) {
|
||||
if (!pinEnabled(pin, PIN_PWM)) {
|
||||
// enable PWM and set its value
|
||||
pwm.cfg.bits.en = PWM_ENABLE;
|
||||
pwm.cfg.bits.int_en = PWM_INT_DIS;
|
||||
pwm.cfg.bits.mode = PWM_PWM_MODE;
|
||||
pwm.cfg.bits.clk = PWM_CLK_26M;
|
||||
pwm.end_value = frequency;
|
||||
pwm.p_Int_Handler = NULL;
|
||||
__wrap_bk_printf_disable();
|
||||
sddev_control(PWM_DEV_NAME, CMD_PWM_INIT_PARAM, &pwm);
|
||||
sddev_control(PWM_DEV_NAME, CMD_PWM_INIT_LEVL_SET_HIGH, &pwm.channel);
|
||||
sddev_control(PWM_DEV_NAME, CMD_PWM_UNIT_ENABLE, &pwm.channel);
|
||||
__wrap_bk_printf_enable();
|
||||
pin->enabled &= ~PIN_GPIO;
|
||||
pin->enabled |= PIN_PWM;
|
||||
} else {
|
||||
// update duty cycle
|
||||
sddev_control(PWM_DEV_NAME, CMD_PWM_SET_DUTY_CYCLE, &pwm);
|
||||
}
|
||||
} else {
|
||||
// update duty cycle
|
||||
sddev_control(PWM_DEV_NAME, CMD_PWM_SET_DUTY_CYCLE, &pwm);
|
||||
if (pinEnabled(pin, PIN_PWM)) {
|
||||
// disable PWM
|
||||
pwm.cfg.bits.en = PWM_DISABLE;
|
||||
__wrap_bk_printf_disable();
|
||||
sddev_control(PWM_DEV_NAME, CMD_PWM_SET_DUTY_CYCLE, &pwm);
|
||||
sddev_control(PWM_DEV_NAME, CMD_PWM_DEINIT_PARAM, &pwm);
|
||||
__wrap_bk_printf_enable();
|
||||
pin->enabled &= ~PIN_PWM;
|
||||
}
|
||||
// force level as LOW
|
||||
pinMode(pinNumber, OUTPUT);
|
||||
digitalWrite(pinNumber, LOW);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ PinStatus digitalRead(pin_size_t pinNumber) {
|
||||
if (!pin)
|
||||
return 0;
|
||||
// pin is not GPIO yet or not INPUT; change the mode
|
||||
if (!pinEnabled(pin, PIN_GPIO) || !pinIsOutput(pin))
|
||||
if (!pinEnabled(pin, PIN_GPIO) || !pinIsInput(pin))
|
||||
pinMode(pinNumber, INPUT);
|
||||
// read the value
|
||||
return gpio_input(pin->gpio);
|
||||
|
||||
99
arduino/beken-72xx/cores/arduino/wiring_irq.c
Normal file
99
arduino/beken-72xx/cores/arduino/wiring_irq.c
Normal file
@@ -0,0 +1,99 @@
|
||||
/* 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;
|
||||
}
|
||||
5
arduino/beken-72xx/libraries/MD5/MD5Impl.h
Normal file
5
arduino/beken-72xx/libraries/MD5/MD5Impl.h
Normal file
@@ -0,0 +1,5 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-07-11. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#define LT_MD5_USE_HOSTAPD 1
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "WiFiPriv.h"
|
||||
|
||||
WiFiClass::WiFiClass() {
|
||||
memset(&data, 0x00, sizeof(WiFiData));
|
||||
data.scanSem = xSemaphoreCreateBinary();
|
||||
}
|
||||
|
||||
@@ -10,11 +11,36 @@ WiFiClass::~WiFiClass() {
|
||||
vSemaphoreDelete(data.scanSem);
|
||||
}
|
||||
|
||||
void WiFiClass::dataInitialize() {
|
||||
if (data.statusIp)
|
||||
return;
|
||||
LT_DM(WIFI, "Data init");
|
||||
data.configSta = zalloc(sizeof(network_InitTypeDef_st));
|
||||
data.configAp = zalloc(sizeof(network_InitTypeDef_ap_st));
|
||||
data.statusIp = malloc(sizeof(IPStatusTypedef));
|
||||
data.statusLink = malloc(sizeof(LinkStatusTypeDef));
|
||||
STA_CFG->dhcp_mode = DHCP_CLIENT;
|
||||
LT_DM(WIFI, "Data = %p", data.configSta);
|
||||
}
|
||||
|
||||
void WiFiClass::dataFree() {
|
||||
LT_DM(WIFI, "Data free");
|
||||
free(data.configSta);
|
||||
free(data.configAp);
|
||||
free(data.statusIp);
|
||||
free(data.statusLink);
|
||||
data.configSta = NULL;
|
||||
data.configAp = NULL;
|
||||
data.statusIp = NULL;
|
||||
data.statusLink = NULL;
|
||||
}
|
||||
|
||||
WiFiStatus eventTypeToStatus(uint8_t type) {
|
||||
// rw_msg_pub.h:9
|
||||
switch (type) {
|
||||
case RW_EVT_STA_IDLE:
|
||||
return WL_IDLE_STATUS;
|
||||
case RW_EVT_STA_NO_AP_FOUND:
|
||||
return WL_NO_SSID_AVAIL;
|
||||
case RW_EVT_STA_CONNECTING:
|
||||
case RW_EVT_STA_CONNECTED:
|
||||
@@ -22,7 +48,6 @@ WiFiStatus eventTypeToStatus(uint8_t type) {
|
||||
case RW_EVT_STA_GOT_IP:
|
||||
return WL_CONNECTED;
|
||||
case RW_EVT_STA_PASSWORD_WRONG:
|
||||
case RW_EVT_STA_NO_AP_FOUND:
|
||||
case RW_EVT_STA_ASSOC_FULL:
|
||||
case RW_EVT_STA_CONNECT_FAILED:
|
||||
return WL_CONNECT_FAILED;
|
||||
|
||||
127
arduino/beken-72xx/libraries/WiFi/WiFiAP.cpp
Normal file
127
arduino/beken-72xx/libraries/WiFi/WiFiAP.cpp
Normal file
@@ -0,0 +1,127 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-07-01. */
|
||||
|
||||
#include "WiFiPriv.h"
|
||||
|
||||
bool WiFiClass::softAP(const char *ssid, const char *passphrase, int channel, bool ssidHidden, int maxClients) {
|
||||
if (!enableAP(true))
|
||||
return WL_CONNECT_FAILED;
|
||||
if (!validate(ssid, passphrase))
|
||||
return WL_CONNECT_FAILED;
|
||||
|
||||
LT_HEAP_I();
|
||||
|
||||
// Beken SDK bug: bk_wlan_ap_init_adv() doesn't null-terminate the passphrase
|
||||
memset(g_ap_param_ptr->key, '\0', 65);
|
||||
|
||||
strcpy(AP_CFG->wifi_ssid, ssid);
|
||||
if (passphrase) {
|
||||
strcpy(AP_CFG->wifi_key, passphrase);
|
||||
AP_CFG->security = BK_SECURITY_TYPE_WPA2_MIXED;
|
||||
} else {
|
||||
AP_CFG->wifi_key[0] = '\0';
|
||||
AP_CFG->security = BK_SECURITY_TYPE_NONE;
|
||||
}
|
||||
|
||||
AP_CFG->channel = channel;
|
||||
AP_CFG->ssid_hidden = ssidHidden;
|
||||
AP_CFG->max_con = maxClients;
|
||||
AP_CFG->dhcp_mode = DHCP_SERVER;
|
||||
AP_CFG->wifi_retry_interval = 100;
|
||||
|
||||
LT_IM(WIFI, "Creating SoftAP %s", ssid);
|
||||
|
||||
if (!AP_CFG->local_ip_addr[0]) {
|
||||
LT_DM(WIFI, "Setting default IP config");
|
||||
softAPConfig((uint32_t)0, (uint32_t)0, (uint32_t)0);
|
||||
}
|
||||
|
||||
LT_DM(WIFI, "Static IP: %s / %s / %s", AP_CFG->local_ip_addr, AP_CFG->net_mask, AP_CFG->gateway_ip_addr);
|
||||
|
||||
__wrap_bk_printf_disable();
|
||||
OSStatus ret = bk_wlan_start_ap_adv(AP_CFG);
|
||||
__wrap_bk_printf_enable();
|
||||
|
||||
if (ret != 0) {
|
||||
LT_EM(WIFI, "SoftAP failed; ret=%d", ret);
|
||||
return false;
|
||||
}
|
||||
LT_DM(WIFI, "AP start OK");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WiFiClass::softAPConfig(IPAddress localIP, IPAddress gateway, IPAddress subnet) {
|
||||
dataInitialize();
|
||||
if (!localIP) {
|
||||
localIP = gateway = IPAddress(192, 168, 43, 1);
|
||||
subnet = IPAddress(255, 255, 255, 0);
|
||||
}
|
||||
sprintf(AP_CFG->local_ip_addr, IP_FMT, localIP[0], localIP[1], localIP[2], localIP[3]);
|
||||
sprintf(AP_CFG->net_mask, IP_FMT, subnet[0], subnet[1], subnet[2], subnet[3]);
|
||||
sprintf(AP_CFG->gateway_ip_addr, IP_FMT, gateway[0], gateway[1], gateway[2], gateway[3]);
|
||||
// from wlan_ui.c:1370
|
||||
if (uap_ip_is_start()) {
|
||||
uap_ip_down();
|
||||
ip_address_set(
|
||||
BK_STATION,
|
||||
AP_CFG->dhcp_mode,
|
||||
AP_CFG->local_ip_addr,
|
||||
AP_CFG->net_mask,
|
||||
AP_CFG->gateway_ip_addr,
|
||||
AP_CFG->dns_server_ip_addr
|
||||
);
|
||||
uap_ip_start();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WiFiClass::softAPdisconnect(bool wifiOff) {
|
||||
if (!(getMode() & WIFI_MODE_AP))
|
||||
// do not call SDK methods before even initializing WiFi first
|
||||
return true;
|
||||
return bk_wlan_stop(BK_SOFT_AP) == kNoErr;
|
||||
}
|
||||
|
||||
uint8_t WiFiClass::softAPgetStationNum() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
IPAddress WiFiClass::softAPIP() {
|
||||
AP_GET_IP_STATUS_RETURN((uint32_t)0);
|
||||
IPAddress ip;
|
||||
ip.fromString(IP_STATUS->ip);
|
||||
return ip;
|
||||
}
|
||||
|
||||
IPAddress WiFiClass::softAPSubnetMask() {
|
||||
AP_GET_IP_STATUS_RETURN((uint32_t)0);
|
||||
IPAddress ip;
|
||||
ip.fromString(IP_STATUS->mask);
|
||||
return ip;
|
||||
}
|
||||
|
||||
const char *WiFiClass::softAPgetHostname() {
|
||||
struct netif *ifs = (struct netif *)net_get_uap_handle();
|
||||
return netif_get_hostname(ifs);
|
||||
}
|
||||
|
||||
bool WiFiClass::softAPsetHostname(const char *hostname) {
|
||||
struct netif *ifs = (struct netif *)net_get_uap_handle();
|
||||
netif_set_hostname(ifs, (char *)hostname);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t *WiFiClass::softAPmacAddress(uint8_t *mac) {
|
||||
setMacAddress(mac);
|
||||
return mac;
|
||||
}
|
||||
|
||||
String WiFiClass::softAPmacAddress(void) {
|
||||
uint8_t mac[ETH_ALEN];
|
||||
wifi_get_mac_address((char *)mac, CONFIG_ROLE_AP);
|
||||
return macToString(mac);
|
||||
}
|
||||
|
||||
const String WiFiClass::softAPSSID(void) {
|
||||
AP_GET_LINK_STATUS_RETURN("");
|
||||
return AP_CFG->wifi_ssid;
|
||||
}
|
||||
@@ -7,17 +7,19 @@
|
||||
extern "C" {
|
||||
|
||||
#include <FreeRTOS.h>
|
||||
#include <rw_msg_pub.h>
|
||||
#include <semphr.h>
|
||||
|
||||
} // extern "C"
|
||||
|
||||
typedef struct {
|
||||
char ssid[32 + 1];
|
||||
char pass[64 + 1];
|
||||
void *configSta;
|
||||
void *configAp;
|
||||
unsigned long scannedAt;
|
||||
uint32_t ipSta[4];
|
||||
uint32_t ipAp[4];
|
||||
SemaphoreHandle_t scanSem;
|
||||
void *statusIp;
|
||||
void *statusLink;
|
||||
rw_evt_type lastStaEvent;
|
||||
rw_evt_type lastApEvent;
|
||||
bool apEnabled;
|
||||
} WiFiData;
|
||||
|
||||
149
arduino/beken-72xx/libraries/WiFi/WiFiEvents.cpp
Normal file
149
arduino/beken-72xx/libraries/WiFi/WiFiEvents.cpp
Normal file
@@ -0,0 +1,149 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-07-10. */
|
||||
|
||||
#include "WiFiPriv.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
static xQueueHandle wifiEventQueueHandle = NULL;
|
||||
static xTaskHandle wifiEventTaskHandle = NULL;
|
||||
|
||||
static const rw_evt_type eventConnected = RW_EVT_STA_CONNECTED;
|
||||
|
||||
// callback for bk_wlan_status_register_cb()
|
||||
static void wifiStatusCallback(rw_evt_type *pEvent) {
|
||||
if (wifiEventQueueHandle && wifiEventTaskHandle) {
|
||||
xQueueSend(wifiEventQueueHandle, pEvent, portMAX_DELAY);
|
||||
} else {
|
||||
wifiEventHandler(*pEvent);
|
||||
}
|
||||
}
|
||||
|
||||
static void wifiEventTask(void *arg) {
|
||||
rw_evt_type event = RW_EVT_MAX;
|
||||
for (;;) {
|
||||
if (xQueueReceive(wifiEventQueueHandle, &event, portMAX_DELAY) == pdTRUE) {
|
||||
wifiEventHandler(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wifiEventSendArduino(EventId event) {
|
||||
event = (EventId)(RW_EVT_ARDUINO | event);
|
||||
wifiStatusCallback((rw_evt_type *)&event);
|
||||
}
|
||||
|
||||
void startWifiTask() {
|
||||
if (!wifiEventQueueHandle) {
|
||||
LT_HEAP_I();
|
||||
wifiEventQueueHandle = xQueueCreate(32, sizeof(rw_evt_type));
|
||||
LT_HEAP_I();
|
||||
}
|
||||
if (!wifiEventTaskHandle) {
|
||||
LT_HEAP_I();
|
||||
xTaskCreate(wifiEventTask, "wifievent", 512, NULL, 4, &wifiEventTaskHandle);
|
||||
LT_HEAP_I();
|
||||
}
|
||||
bk_wlan_status_register_cb((FUNC_1PARAM_PTR)wifiStatusCallback);
|
||||
}
|
||||
|
||||
void wifiEventHandler(rw_evt_type event) {
|
||||
if (!pWiFi)
|
||||
return; // failsafe
|
||||
|
||||
LT_DM(WIFI, "BK event %u", event);
|
||||
|
||||
if (event <= RW_EVT_STA_GOT_IP)
|
||||
pWiFi->data.lastStaEvent = event;
|
||||
else
|
||||
pWiFi->data.lastApEvent = event;
|
||||
|
||||
EventId eventId;
|
||||
EventInfo eventInfo;
|
||||
String ssid;
|
||||
|
||||
memset(&eventInfo, 0, sizeof(EventInfo));
|
||||
|
||||
switch (event) {
|
||||
case RW_EVT_STA_IDLE:
|
||||
eventId = ARDUINO_EVENT_WIFI_READY;
|
||||
break;
|
||||
|
||||
case RW_EVT_STA_BEACON_LOSE:
|
||||
case RW_EVT_STA_PASSWORD_WRONG:
|
||||
case RW_EVT_STA_NO_AP_FOUND:
|
||||
case RW_EVT_STA_ASSOC_FULL:
|
||||
case RW_EVT_STA_DISCONNECTED:
|
||||
case RW_EVT_STA_CONNECT_FAILED:
|
||||
eventId = ARDUINO_EVENT_WIFI_STA_DISCONNECTED;
|
||||
eventInfo.wifi_sta_disconnected.ssid_len = 0;
|
||||
switch (event) {
|
||||
case RW_EVT_STA_BEACON_LOSE:
|
||||
eventInfo.wifi_sta_disconnected.reason = WIFI_REASON_BEACON_TIMEOUT;
|
||||
break;
|
||||
case RW_EVT_STA_PASSWORD_WRONG:
|
||||
eventInfo.wifi_sta_disconnected.reason = WIFI_REASON_AUTH_FAIL;
|
||||
break;
|
||||
case RW_EVT_STA_NO_AP_FOUND:
|
||||
eventInfo.wifi_sta_disconnected.reason = WIFI_REASON_NO_AP_FOUND;
|
||||
break;
|
||||
case RW_EVT_STA_ASSOC_FULL:
|
||||
eventInfo.wifi_sta_disconnected.reason = WIFI_REASON_ASSOC_TOOMANY;
|
||||
break;
|
||||
case RW_EVT_STA_DISCONNECTED:
|
||||
eventInfo.wifi_sta_disconnected.reason = WIFI_REASON_ASSOC_LEAVE;
|
||||
break;
|
||||
case RW_EVT_STA_CONNECT_FAILED:
|
||||
eventInfo.wifi_sta_disconnected.reason = WIFI_REASON_CONNECTION_FAIL;
|
||||
break;
|
||||
default:
|
||||
eventInfo.wifi_sta_disconnected.reason = WIFI_REASON_UNSPECIFIED;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case RW_EVT_STA_CONNECTED:
|
||||
eventId = ARDUINO_EVENT_WIFI_STA_CONNECTED;
|
||||
ssid = pWiFi->SSID();
|
||||
eventInfo.wifi_sta_connected.ssid_len = ssid.length();
|
||||
eventInfo.wifi_sta_connected.channel = pWiFi->channel();
|
||||
eventInfo.wifi_sta_connected.authmode = pWiFi->getEncryption();
|
||||
memcpy(eventInfo.wifi_sta_connected.ssid, ssid.c_str(), eventInfo.wifi_sta_connected.ssid_len + 1);
|
||||
memcpy(eventInfo.wifi_sta_connected.bssid, pWiFi->BSSID(), 6);
|
||||
break;
|
||||
|
||||
case RW_EVT_STA_GOT_IP:
|
||||
eventId = ARDUINO_EVENT_WIFI_STA_GOT_IP;
|
||||
eventInfo.got_ip.if_index = 0;
|
||||
eventInfo.got_ip.ip_changed = true;
|
||||
eventInfo.got_ip.ip_info.ip.addr = WiFi.localIP();
|
||||
eventInfo.got_ip.ip_info.netmask.addr = WiFi.subnetMask();
|
||||
eventInfo.got_ip.ip_info.gw.addr = WiFi.gatewayIP();
|
||||
break;
|
||||
|
||||
case RW_EVT_AP_CONNECTED:
|
||||
eventId = ARDUINO_EVENT_WIFI_AP_STACONNECTED;
|
||||
// TODO station MAC
|
||||
break;
|
||||
|
||||
case RW_EVT_AP_DISCONNECTED:
|
||||
eventId = ARDUINO_EVENT_WIFI_AP_STADISCONNECTED;
|
||||
// TODO station MAC
|
||||
break;
|
||||
|
||||
case RW_EVT_ARDUINO | ARDUINO_EVENT_WIFI_SCAN_DONE:
|
||||
eventId = ARDUINO_EVENT_WIFI_SCAN_DONE;
|
||||
eventInfo.wifi_scan_done.status = 0;
|
||||
if (pWiFi->scan)
|
||||
eventInfo.wifi_scan_done.number = pWiFi->scan->count;
|
||||
eventInfo.wifi_scan_done.scan_id = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (event < RW_EVT_ARDUINO)
|
||||
return;
|
||||
eventId = (EventId)(event - RW_EVT_ARDUINO);
|
||||
break;
|
||||
}
|
||||
|
||||
pWiFi->postEvent(eventId, eventInfo);
|
||||
}
|
||||
@@ -4,61 +4,79 @@
|
||||
|
||||
bool WiFiClass::modePriv(WiFiMode mode, WiFiModeAction sta, WiFiModeAction ap) {
|
||||
__wrap_bk_printf_disable();
|
||||
|
||||
if (mode && !data.statusIp) {
|
||||
data.statusIp = (IPStatusTypedef *)malloc(sizeof(IPStatusTypedef));
|
||||
data.statusLink = (LinkStatusTypeDef *)malloc(sizeof(LinkStatusTypeDef));
|
||||
}
|
||||
startWifiTask();
|
||||
|
||||
if (!__bk_rf_is_init) {
|
||||
LT_D_WG("Initializing func&app");
|
||||
LT_DM(WIFI, "Initializing func&app");
|
||||
func_init_extended();
|
||||
app_pre_start();
|
||||
// wait for the init_thread to finish its job
|
||||
while (xTaskGetHandle("init_thread")) {
|
||||
LT_VM(WIFI, "Waiting for init_thread");
|
||||
delay(10);
|
||||
}
|
||||
LT_DM(WIFI, "Init OK");
|
||||
__bk_rf_is_init = true;
|
||||
}
|
||||
|
||||
LT_HEAP_I();
|
||||
|
||||
if (mode) {
|
||||
LT_DM(WIFI, "Wakeup RF");
|
||||
uint32_t reg = 1; // this is only checked for being true-ish
|
||||
sddev_control(SCTRL_DEV_NAME, CMD_RF_HOLD_BIT_SET, ®);
|
||||
}
|
||||
|
||||
if (sta == WLMODE_ENABLE) {
|
||||
LT_D_WG("Enabling STA");
|
||||
LT_DM(WIFI, "Enabling STA");
|
||||
bk_wlan_sta_init(NULL);
|
||||
#if CFG_WPA_CTRL_IFACE
|
||||
wlan_sta_enable();
|
||||
#endif
|
||||
wifiEventSendArduino(ARDUINO_EVENT_WIFI_STA_START);
|
||||
} else if (sta == WLMODE_DISABLE) {
|
||||
LT_D_WG("Disabling STA");
|
||||
LT_DM(WIFI, "Disabling STA");
|
||||
bk_wlan_stop(BK_STATION);
|
||||
wifiEventSendArduino(ARDUINO_EVENT_WIFI_STA_STOP);
|
||||
}
|
||||
|
||||
LT_HEAP_I();
|
||||
|
||||
if (ap == WLMODE_ENABLE) {
|
||||
LT_D_WG("Enabling AP");
|
||||
bk_wlan_ap_init(NULL);
|
||||
LT_DM(WIFI, "Enabling AP");
|
||||
// fake it - on BK7231, enabling the AP without starting it breaks all connection attempts
|
||||
data.apEnabled = true;
|
||||
wifiEventSendArduino(ARDUINO_EVENT_WIFI_AP_START);
|
||||
} else if (ap == WLMODE_DISABLE) {
|
||||
LT_D_WG("Disabling AP");
|
||||
LT_DM(WIFI, "Disabling AP");
|
||||
bk_wlan_stop(BK_SOFT_AP);
|
||||
data.apEnabled = false;
|
||||
wifiEventSendArduino(ARDUINO_EVENT_WIFI_AP_STOP);
|
||||
}
|
||||
|
||||
if (!mode) {
|
||||
free(data.statusIp);
|
||||
free(data.statusLink);
|
||||
data.statusIp = NULL;
|
||||
data.statusLink = NULL;
|
||||
}
|
||||
// force checking actual mode again
|
||||
mode = getMode();
|
||||
|
||||
if (!mode)
|
||||
dataFree();
|
||||
|
||||
LT_HEAP_I();
|
||||
|
||||
__wrap_bk_printf_enable();
|
||||
return true;
|
||||
}
|
||||
|
||||
WiFiMode WiFiClass::getMode() {
|
||||
if (!g_wlan_general_param)
|
||||
return WIFI_MODE_NULL;
|
||||
uint8_t role = g_wlan_general_param->role;
|
||||
// change 1->2, 2->1
|
||||
return (WiFiMode)(role + (role == 1) - (role == 2));
|
||||
uint8_t sta = !!bk_wlan_has_role(VIF_STA) * WIFI_MODE_STA;
|
||||
uint8_t ap = data.apEnabled * WIFI_MODE_AP; // report the faked value
|
||||
return (WiFiMode)(sta | ap);
|
||||
}
|
||||
|
||||
WiFiStatus WiFiClass::status() {
|
||||
return eventTypeToStatus(mhdr_get_station_status());
|
||||
rw_evt_type status = data.lastStaEvent;
|
||||
if (status == RW_EVT_STA_CONNECTED && STA_CFG->dhcp_mode == DHCP_DISABLE)
|
||||
status = RW_EVT_STA_GOT_IP;
|
||||
return eventTypeToStatus(status);
|
||||
}
|
||||
|
||||
IPAddress WiFiClass::hostByName(const char *hostname) {
|
||||
|
||||
@@ -9,6 +9,8 @@ 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>
|
||||
@@ -18,6 +20,9 @@ extern "C" {
|
||||
#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>
|
||||
|
||||
@@ -28,10 +33,6 @@ extern void bk_wlan_ap_init(network_InitTypeDef_st *inNetworkInitPara);
|
||||
// func/hostapd-2.5/wpa_supplicant/main_supplicant.c
|
||||
extern struct wpa_ssid_value *wpas_connect_ssid;
|
||||
|
||||
// func/lwip_intf/lwip-2.0.2/port/net.c
|
||||
extern struct netif *net_get_sta_handle(void);
|
||||
extern struct netif *net_get_uap_handle(void);
|
||||
|
||||
// app/param_config.c
|
||||
extern general_param_t *g_wlan_general_param;
|
||||
extern ap_param_t *g_ap_param_ptr;
|
||||
@@ -42,16 +43,48 @@ extern uint8_t system_mac[6];
|
||||
WiFiStatus eventTypeToStatus(uint8_t type);
|
||||
WiFiAuthMode securityTypeToAuthMode(uint8_t type);
|
||||
|
||||
#define ADDR_STA_IP data.ipSta[0]
|
||||
#define ADDR_STA_MASK data.ipSta[1]
|
||||
#define ADDR_STA_GW data.ipSta[2]
|
||||
#define ADDR_STA_DNS data.ipSta[3]
|
||||
#define ADDR_AP_IP data.ipAp[0]
|
||||
#define ADDR_AP_MASK data.ipAp[1]
|
||||
#define ADDR_AP_GW data.ipAp[2]
|
||||
#define ADDR_AP_DNS data.ipAp[3]
|
||||
// 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"
|
||||
|
||||
@@ -4,24 +4,21 @@
|
||||
|
||||
WiFiStatus
|
||||
WiFiClass::begin(const char *ssid, const char *passphrase, int32_t channel, const uint8_t *bssid, bool connect) {
|
||||
enableSTA(true);
|
||||
|
||||
if (!ssid || *ssid == 0x00 || strlen(ssid) > 32) {
|
||||
LT_W("SSID not specified or too long");
|
||||
if (!enableSTA(true))
|
||||
return WL_CONNECT_FAILED;
|
||||
}
|
||||
|
||||
if (passphrase && strlen(passphrase) > 64) {
|
||||
LT_W("Passphrase too long");
|
||||
if (!validate(ssid, passphrase))
|
||||
return WL_CONNECT_FAILED;
|
||||
}
|
||||
|
||||
// store the network data for later
|
||||
strcpy(data.ssid, ssid);
|
||||
if (passphrase)
|
||||
strcpy(data.pass, passphrase);
|
||||
else
|
||||
data.pass[0] = 0;
|
||||
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;
|
||||
@@ -30,84 +27,77 @@ WiFiClass::begin(const char *ssid, const char *passphrase, int32_t channel, cons
|
||||
}
|
||||
|
||||
bool WiFiClass::config(IPAddress localIP, IPAddress gateway, IPAddress subnet, IPAddress dns1, IPAddress dns2) {
|
||||
ADDR_STA_IP = (uint32_t)localIP;
|
||||
ADDR_STA_GW = (uint32_t)gateway;
|
||||
ADDR_STA_MASK = (uint32_t)subnet;
|
||||
ADDR_STA_DNS = (uint32_t)dns1;
|
||||
dataInitialize();
|
||||
|
||||
if (status() == WL_CONNECTED) {
|
||||
IPStatusTypedef config;
|
||||
config.dhcp = !localIP[0];
|
||||
if (localIP) {
|
||||
sprintf(config.ip, "%u.%u.%u.%u", ADDR_STA_IP);
|
||||
sprintf(config.mask, "%u.%u.%u.%u", ADDR_STA_MASK);
|
||||
sprintf(config.gate, "%u.%u.%u.%u", ADDR_STA_GW);
|
||||
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';
|
||||
}
|
||||
if (dns1)
|
||||
sprintf(config.dns, "%u.%u.%u.%u", ADDR_STA_DNS);
|
||||
bk_wlan_set_ip_status(&config, BK_STATION);
|
||||
} 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) {
|
||||
if (!bssid && !data.ssid[0]) {
|
||||
LT_E("(B)SSID not specified");
|
||||
dataInitialize();
|
||||
if (!bssid && !STA_CFG->wifi_ssid[0]) {
|
||||
LT_EM(WIFI, "(B)SSID not specified");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (bssid) {
|
||||
LT_D_WG("Connecting to " MACSTR, MAC2STR(bssid));
|
||||
LT_IM(WIFI, "Connecting to " MACSTR, MAC2STR(bssid));
|
||||
} else {
|
||||
LT_D_WG("Connecting to %s", data.ssid);
|
||||
LT_IM(WIFI, "Connecting to %s", STA_CFG->wifi_ssid);
|
||||
}
|
||||
|
||||
network_InitTypeDef_st config;
|
||||
memset(&config, 0, sizeof(network_InitTypeDef_st));
|
||||
// network_InitTypeDef_adv_st config;
|
||||
// memset(&config, 0, sizeof(network_InitTypeDef_adv_st));
|
||||
LT_DM(WIFI, "Data = %p", data.configSta);
|
||||
|
||||
config.wifi_mode = BK_STATION;
|
||||
config.wifi_retry_interval = 100;
|
||||
// config.ap_info.security = BK_SECURITY_TYPE_WPA2_MIXED;
|
||||
// config.ap_info.channel = 6;
|
||||
strcpy(config.wifi_ssid, data.ssid);
|
||||
// strcpy(config.ap_info.ssid, data.ssid);
|
||||
strcpy(config.wifi_key, data.pass);
|
||||
// strcpy(config.key, data.pass);
|
||||
// config.key_len = strlen(data.pass);
|
||||
STA_CFG->wifi_mode = BK_STATION;
|
||||
STA_CFG->wifi_retry_interval = 100;
|
||||
if (bssid)
|
||||
memcpy(config.wifi_bssid, bssid, 6);
|
||||
// memcpy(config.ap_info.bssid, bssid, 6);
|
||||
memcpy(STA_CFG->wifi_bssid, bssid, 6);
|
||||
else
|
||||
memset(STA_CFG->wifi_bssid, 0x00, 6);
|
||||
|
||||
if (ADDR_STA_IP && ADDR_STA_MASK && ADDR_STA_GW) {
|
||||
config.dhcp_mode = DHCP_DISABLE;
|
||||
sprintf(config.local_ip_addr, "%u.%u.%u.%u", ADDR_STA_IP);
|
||||
sprintf(config.net_mask, "%u.%u.%u.%u", ADDR_STA_MASK);
|
||||
sprintf(config.gateway_ip_addr, "%u.%u.%u.%u", ADDR_STA_GW);
|
||||
LT_D_WG("Static IP: %s / %s / %s", config.local_ip_addr, config.net_mask, config.gateway_ip_addr);
|
||||
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 {
|
||||
config.dhcp_mode = DHCP_CLIENT;
|
||||
LT_D_WG("Using DHCP");
|
||||
LT_DM(WIFI, "Using DHCP");
|
||||
}
|
||||
|
||||
if (ADDR_STA_DNS) {
|
||||
sprintf(config.dns_server_ip_addr, "%u.%u.%u.%u", ADDR_STA_DNS);
|
||||
LT_D_WG("Static DNS: %s", config.dns_server_ip_addr);
|
||||
}
|
||||
LT_DM(WIFI, "Starting WiFi...");
|
||||
|
||||
if (!data.scannedAt || millis() - data.scannedAt > 10000) {
|
||||
LT_D_WG("Scan needed");
|
||||
// apparently a scan must be performed first,
|
||||
// else it hangs at "[sa_sta]MM_START_REQ"
|
||||
scanNetworks(false);
|
||||
}
|
||||
|
||||
LT_D_WG("Starting WiFi...");
|
||||
__wrap_bk_printf_disable();
|
||||
bk_wlan_start_sta(&config);
|
||||
bk_wlan_start_sta(STA_CFG);
|
||||
__wrap_bk_printf_enable();
|
||||
LT_D_WG("bk_wlan_start() OK");
|
||||
|
||||
LT_DM(WIFI, "Start OK");
|
||||
return true;
|
||||
|
||||
error:
|
||||
@@ -115,7 +105,14 @@ error:
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -128,34 +125,30 @@ bool WiFiClass::getAutoReconnect() {
|
||||
}
|
||||
|
||||
IPAddress WiFiClass::localIP() {
|
||||
IPStatusTypedef config;
|
||||
bk_wlan_get_ip_status(&config, BK_STATION);
|
||||
STA_GET_IP_STATUS_RETURN((uint32_t)0);
|
||||
IPAddress ip;
|
||||
ip.fromString(config.ip);
|
||||
ip.fromString(IP_STATUS->ip);
|
||||
return ip;
|
||||
}
|
||||
|
||||
IPAddress WiFiClass::subnetMask() {
|
||||
IPStatusTypedef config;
|
||||
bk_wlan_get_ip_status(&config, BK_STATION);
|
||||
STA_GET_IP_STATUS_RETURN((uint32_t)0);
|
||||
IPAddress ip;
|
||||
ip.fromString(config.mask);
|
||||
ip.fromString(IP_STATUS->mask);
|
||||
return ip;
|
||||
}
|
||||
|
||||
IPAddress WiFiClass::gatewayIP() {
|
||||
IPStatusTypedef config;
|
||||
bk_wlan_get_ip_status(&config, BK_STATION);
|
||||
STA_GET_IP_STATUS_RETURN((uint32_t)0);
|
||||
IPAddress ip;
|
||||
ip.fromString(config.gate);
|
||||
ip.fromString(IP_STATUS->gate);
|
||||
return ip;
|
||||
}
|
||||
|
||||
IPAddress WiFiClass::dnsIP(uint8_t dns_no) {
|
||||
IPStatusTypedef config;
|
||||
bk_wlan_get_ip_status(&config, BK_STATION);
|
||||
STA_GET_IP_STATUS_RETURN((uint32_t)0);
|
||||
IPAddress ip;
|
||||
ip.fromString(config.dns);
|
||||
ip.fromString(IP_STATUS->dns);
|
||||
return ip;
|
||||
}
|
||||
|
||||
@@ -164,12 +157,12 @@ IPAddress WiFiClass::broadcastIP() {
|
||||
}
|
||||
|
||||
const char *WiFiClass::getHostname() {
|
||||
struct netif *ifs = net_get_sta_handle();
|
||||
struct netif *ifs = (struct netif *)net_get_sta_handle();
|
||||
return netif_get_hostname(ifs);
|
||||
}
|
||||
|
||||
bool WiFiClass::setHostname(const char *hostname) {
|
||||
struct netif *ifs = net_get_sta_handle();
|
||||
struct netif *ifs = (struct netif *)net_get_sta_handle();
|
||||
netif_set_hostname(ifs, (char *)hostname);
|
||||
return true;
|
||||
}
|
||||
@@ -180,12 +173,24 @@ uint8_t *WiFiClass::macAddress(uint8_t *mac) {
|
||||
}
|
||||
|
||||
bool WiFiClass::setMacAddress(const uint8_t *mac) {
|
||||
wifi_set_mac_address((char *)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() {
|
||||
bk_wlan_get_link_status(LINK_STATUS);
|
||||
STA_GET_LINK_STATUS_RETURN("");
|
||||
return (char *)LINK_STATUS->ssid;
|
||||
}
|
||||
|
||||
@@ -199,21 +204,21 @@ const String WiFiClass::psk() {
|
||||
}
|
||||
|
||||
uint8_t *WiFiClass::BSSID() {
|
||||
bk_wlan_get_link_status(LINK_STATUS);
|
||||
STA_GET_LINK_STATUS_RETURN(NULL);
|
||||
return LINK_STATUS->bssid;
|
||||
}
|
||||
|
||||
int32_t WiFiClass::channel() {
|
||||
bk_wlan_get_link_status(LINK_STATUS);
|
||||
STA_GET_LINK_STATUS_RETURN(0);
|
||||
return LINK_STATUS->channel;
|
||||
}
|
||||
|
||||
int8_t WiFiClass::RSSI() {
|
||||
bk_wlan_get_link_status(LINK_STATUS);
|
||||
STA_GET_LINK_STATUS_RETURN(0);
|
||||
return LINK_STATUS->wifi_strength;
|
||||
}
|
||||
|
||||
WiFiAuthMode WiFiClass::getEncryption() {
|
||||
bk_wlan_get_link_status(LINK_STATUS);
|
||||
STA_GET_LINK_STATUS_RETURN(WIFI_AUTH_INVALID);
|
||||
return securityTypeToAuthMode(LINK_STATUS->security);
|
||||
}
|
||||
|
||||
@@ -6,25 +6,25 @@ static void scanHandler(void *ctx, uint8_t param) {
|
||||
LT_HEAP_I();
|
||||
WiFiClass *cls = (WiFiClass *)ctx;
|
||||
if (!cls) {
|
||||
LT_W("Called without ctx");
|
||||
LT_WM(WIFI, "Called without ctx");
|
||||
return;
|
||||
}
|
||||
WiFiScanData *scan = cls->scan;
|
||||
if (!scan) {
|
||||
LT_W("Called without cls->scan");
|
||||
LT_WM(WIFI, "Called without cls->scan");
|
||||
return;
|
||||
}
|
||||
|
||||
ScanResult_adv result;
|
||||
if (wlan_sta_scan_result(&result)) {
|
||||
LT_E("Failed to get scan result");
|
||||
LT_EM(WIFI, "Failed to get scan result");
|
||||
goto end;
|
||||
}
|
||||
LT_D_WG("Found %d APs", result.ApNum);
|
||||
LT_IM(WIFI, "Found %d APs", result.ApNum);
|
||||
|
||||
cls->scanAlloc(result.ApNum);
|
||||
if (!scan->ap) {
|
||||
LT_W("scan->ap alloc failed");
|
||||
LT_WM(WIFI, "scan->ap alloc failed");
|
||||
goto end;
|
||||
}
|
||||
|
||||
@@ -38,36 +38,58 @@ static void scanHandler(void *ctx, uint8_t param) {
|
||||
|
||||
cls->data.scannedAt = millis();
|
||||
|
||||
wifiEventSendArduino(ARDUINO_EVENT_WIFI_SCAN_DONE);
|
||||
|
||||
end:
|
||||
scan->running = false;
|
||||
xSemaphoreGive(cls->data.scanSem);
|
||||
scan->timeout = 0;
|
||||
if (scan->running) {
|
||||
// running == false means it was discarded (timeout)
|
||||
scan->running = false;
|
||||
xSemaphoreGive(cls->data.scanSem);
|
||||
}
|
||||
LT_HEAP_I();
|
||||
return;
|
||||
}
|
||||
|
||||
int16_t WiFiClass::scanNetworks(bool async, bool showHidden, bool passive, uint32_t maxMsPerChannel, uint8_t channel) {
|
||||
if (scan && scan->running)
|
||||
return WIFI_SCAN_RUNNING;
|
||||
if (scan && scan->running) {
|
||||
if (scan->timeout && millis() > scan->timeout) {
|
||||
LT_WM(WIFI, "Scan timeout, discarding");
|
||||
scan->running = false;
|
||||
} else {
|
||||
return WIFI_SCAN_RUNNING;
|
||||
}
|
||||
}
|
||||
enableSTA(true);
|
||||
scanDelete();
|
||||
scanInit();
|
||||
|
||||
LT_I("Starting WiFi scan");
|
||||
LT_IM(WIFI, "Starting WiFi scan");
|
||||
|
||||
__wrap_bk_printf_disable();
|
||||
mhdr_scanu_reg_cb(scanHandler, this);
|
||||
bk_wlan_start_scan();
|
||||
__wrap_bk_printf_enable();
|
||||
|
||||
LT_HEAP_I();
|
||||
|
||||
scan->running = true;
|
||||
scan->timeout = millis() + maxMsPerChannel * 20 + 1000;
|
||||
|
||||
int16_t ret = WIFI_SCAN_RUNNING;
|
||||
if (!async) {
|
||||
LT_I("Waiting for results");
|
||||
LT_IM(WIFI, "Waiting for results");
|
||||
xSemaphoreTake(data.scanSem, 1); // reset the semaphore quickly
|
||||
xSemaphoreTake(data.scanSem, pdMS_TO_TICKS(maxMsPerChannel * 20));
|
||||
return scan->count;
|
||||
if (scan->running) {
|
||||
scanDelete();
|
||||
ret = WIFI_SCAN_FAILED;
|
||||
goto exit;
|
||||
}
|
||||
ret = scan->count;
|
||||
goto exit;
|
||||
}
|
||||
return WIFI_SCAN_RUNNING;
|
||||
|
||||
exit:
|
||||
__wrap_bk_printf_enable();
|
||||
return ret;
|
||||
}
|
||||
|
||||
8
arduino/beken-72xx/libraries/WiFi/WiFiUdp.h
Normal file
8
arduino/beken-72xx/libraries/WiFi/WiFiUdp.h
Normal file
@@ -0,0 +1,8 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-09-10. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <api/WiFi/WiFi.h>
|
||||
#include <lwip/LwIPUdp.h>
|
||||
|
||||
typedef LwIPUDP WiFiUDP;
|
||||
@@ -1,5 +1,6 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-06-19. */
|
||||
|
||||
#include <lt_logger.h>
|
||||
#include <sdk_extern.h>
|
||||
|
||||
#include <fal.h>
|
||||
@@ -8,10 +9,27 @@
|
||||
#define FLASH_ERASE_MIN_SIZE (4 * 1024)
|
||||
|
||||
extern uint32_t flash_ctrl(uint32_t cmd, void *param);
|
||||
extern PROTECT_TYPE get_flash_protect();
|
||||
extern void flash_protection_op(uint8_t mode, PROTECT_TYPE type);
|
||||
|
||||
static void unprotect() {
|
||||
PROTECT_TYPE type = get_flash_protect();
|
||||
if (type != FLASH_PROTECT_NONE) {
|
||||
flash_protection_op(0, FLASH_PROTECT_NONE);
|
||||
#if LT_LOGLEVEL <= LT_LEVEL_DEBUG
|
||||
LT_D("Flash protect: %u -> %u", type, get_flash_protect());
|
||||
uint16_t sr = 0;
|
||||
flash_ctrl(CMD_FLASH_READ_SR, &sr);
|
||||
LT_D("SR = %04x", sr);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static int init() {
|
||||
__wrap_bk_printf_disable();
|
||||
flash_init();
|
||||
flash_ctrl(CMD_FLASH_WRITE_ENABLE, NULL);
|
||||
unprotect();
|
||||
__wrap_bk_printf_enable();
|
||||
return 0;
|
||||
}
|
||||
@@ -22,11 +40,13 @@ static int read(long offset, uint8_t *buf, size_t size) {
|
||||
}
|
||||
|
||||
static int write(long offset, const uint8_t *buf, size_t size) {
|
||||
unprotect();
|
||||
flash_write((char *)buf, size, offset);
|
||||
return size;
|
||||
}
|
||||
|
||||
static int erase(long offset, size_t size) {
|
||||
unprotect();
|
||||
size = ((size - 1) / FLASH_ERASE_MIN_SIZE) + 1;
|
||||
for (uint16_t i = 0; i < size; i++) {
|
||||
uint32_t addr = offset + i * FLASH_ERASE_MIN_SIZE;
|
||||
|
||||
@@ -14,4 +14,8 @@ void putchar_(char c) {
|
||||
bk_send_byte(uart_print_port, c);
|
||||
}
|
||||
|
||||
void putchar_p(char c, unsigned long port) {
|
||||
bk_send_byte((port & 0xFF) - 1, c);
|
||||
}
|
||||
|
||||
WRAP_PRINTF(bk_printf);
|
||||
|
||||
45
arduino/libretuya/api/SoftwareSerial.cpp
Normal file
45
arduino/libretuya/api/SoftwareSerial.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-07-03. */
|
||||
|
||||
#include "SoftwareSerial.h"
|
||||
|
||||
#ifdef LT_ARD_HAS_SOFTSERIAL
|
||||
|
||||
SoftwareSerial::SoftwareSerial(pin_size_t receivePin, pin_size_t transmitPin, bool inverted) {
|
||||
data.rx.buf = NULL;
|
||||
data.tx.buf = NULL;
|
||||
data.rx.pin = receivePin;
|
||||
data.tx.pin = transmitPin;
|
||||
data.invert = inverted == true;
|
||||
}
|
||||
|
||||
int SoftwareSerial::available() {
|
||||
return data.rx.buf->available();
|
||||
}
|
||||
|
||||
int SoftwareSerial::peek() {
|
||||
return data.rx.buf->peek();
|
||||
}
|
||||
|
||||
int SoftwareSerial::read() {
|
||||
return data.rx.buf->read_char();
|
||||
}
|
||||
|
||||
void SoftwareSerial::flush() {
|
||||
while (data.rx.buf->available()) {
|
||||
yield();
|
||||
}
|
||||
}
|
||||
|
||||
size_t SoftwareSerial::write(uint8_t c) {
|
||||
while (data.tx.buf->isFull()) {
|
||||
yield();
|
||||
}
|
||||
data.tx.buf->store_char(c);
|
||||
if (data.tx.state == SS_IDLE) {
|
||||
data.tx.state = SS_START;
|
||||
this->startTx();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
76
arduino/libretuya/api/SoftwareSerial.h
Normal file
76
arduino/libretuya/api/SoftwareSerial.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-07-03. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef LT_ARD_HAS_SOFTSERIAL
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <api/HardwareSerial.h>
|
||||
#include <api/RingBuffer.h>
|
||||
|
||||
using namespace arduino;
|
||||
|
||||
typedef enum {
|
||||
SS_IDLE = 0,
|
||||
SS_START,
|
||||
SS_DATA0,
|
||||
SS_DATA1,
|
||||
SS_DATA2,
|
||||
SS_DATA3,
|
||||
SS_DATA4,
|
||||
SS_DATA5,
|
||||
SS_DATA6,
|
||||
SS_DATA7,
|
||||
SS_STOP,
|
||||
SS_END,
|
||||
} SoftState;
|
||||
|
||||
typedef struct {
|
||||
SoftState state;
|
||||
RingBuffer *buf;
|
||||
uint8_t byte;
|
||||
pin_size_t pin;
|
||||
void *param;
|
||||
} SoftData;
|
||||
|
||||
typedef struct {
|
||||
SoftData rx;
|
||||
SoftData tx;
|
||||
uint8_t invert;
|
||||
void *param;
|
||||
} SoftSerial;
|
||||
|
||||
class SoftwareSerial : public HardwareSerial {
|
||||
private:
|
||||
SoftSerial data;
|
||||
void *param;
|
||||
|
||||
public:
|
||||
SoftwareSerial(pin_size_t receivePin, pin_size_t transmitPin, bool inverted = false);
|
||||
|
||||
inline void begin(unsigned long baudrate) {
|
||||
begin(baudrate, SERIAL_8N1);
|
||||
}
|
||||
|
||||
int available();
|
||||
int peek();
|
||||
int read();
|
||||
void flush();
|
||||
size_t write(uint8_t c);
|
||||
|
||||
operator bool() {
|
||||
return data.rx.buf || data.tx.buf;
|
||||
}
|
||||
|
||||
public: // Family needs to implement these methods only
|
||||
void begin(unsigned long baudrate, uint16_t config);
|
||||
void end();
|
||||
|
||||
private:
|
||||
void startTx();
|
||||
void endTx();
|
||||
|
||||
using Print::write;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -12,8 +12,10 @@ void WiFiClass::printDiag(Print &dest) {
|
||||
if (getMode() & WIFI_MODE_STA) {
|
||||
dest.println("-- Station --");
|
||||
dest.print("SSID: ");
|
||||
dest.println(SSID());
|
||||
if (isConnected()) {
|
||||
dest.println(SSID());
|
||||
dest.print("Channel: ");
|
||||
dest.println(channel());
|
||||
dest.print("BSSID: ");
|
||||
dest.println(BSSIDstr());
|
||||
dest.print("RSSI: ");
|
||||
@@ -26,21 +28,50 @@ void WiFiClass::printDiag(Print &dest) {
|
||||
dest.println(macAddress());
|
||||
dest.print("Hostname: ");
|
||||
dest.println(getHostname());
|
||||
} else {
|
||||
dest.println("disconnected");
|
||||
}
|
||||
}
|
||||
|
||||
if (getMode() & WIFI_MODE_AP) {
|
||||
dest.println("-- Access Point --");
|
||||
dest.print("SSID: ");
|
||||
dest.println(softAPSSID());
|
||||
dest.print("IP: ");
|
||||
dest.println(softAPIP());
|
||||
dest.print("MAC: ");
|
||||
dest.println(softAPmacAddress());
|
||||
dest.print("Hostname: ");
|
||||
dest.println(softAPgetHostname());
|
||||
if (softAPSSID().length()) {
|
||||
dest.println(softAPSSID());
|
||||
dest.print("IP: ");
|
||||
dest.println(softAPIP());
|
||||
dest.print("MAC: ");
|
||||
dest.println(softAPmacAddress());
|
||||
dest.print("Hostname: ");
|
||||
dest.println(softAPgetHostname());
|
||||
} else {
|
||||
dest.println("disconnected");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool WiFiClass::validate(const char *ssid, const char *passphrase) {
|
||||
if (!ssid || *ssid == 0x00 || strlen(ssid) > 32) {
|
||||
LT_WM(WIFI, "SSID not specified or too long");
|
||||
return false;
|
||||
}
|
||||
if (passphrase) {
|
||||
uint16_t length = strlen(passphrase);
|
||||
if (length < 8) {
|
||||
LT_WM(WIFI, "Passphrase too short (%u)", length);
|
||||
return false;
|
||||
}
|
||||
if (length > 63) {
|
||||
LT_WM(WIFI, "Passphrase too long (%u)", length);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
__attribute__((weak)) void WiFiClass::dataInitialize() {}
|
||||
|
||||
__attribute__((weak)) void WiFiClass::dataFree() {}
|
||||
|
||||
WiFiClass WiFi;
|
||||
WiFiClass *pWiFi = NULL;
|
||||
|
||||
@@ -46,6 +46,9 @@ class WiFiClass {
|
||||
WiFiClass();
|
||||
~WiFiClass();
|
||||
void printDiag(Print &dest);
|
||||
bool validate(const char *ssid, const char *passphrase);
|
||||
void dataInitialize();
|
||||
void dataFree();
|
||||
|
||||
public: /* WiFiGeneric.cpp */
|
||||
bool mode(WiFiMode mode);
|
||||
|
||||
@@ -7,7 +7,7 @@ bool WiFiClass::mode(WiFiMode mode) {
|
||||
pWiFi = this;
|
||||
|
||||
WiFiMode currentMode = getMode();
|
||||
LT_D_WG("Mode changing %u -> %u", currentMode, mode);
|
||||
LT_DM(WIFI, "Mode changing %u -> %u", currentMode, mode);
|
||||
if (mode == currentMode)
|
||||
return true;
|
||||
|
||||
@@ -15,11 +15,19 @@ bool WiFiClass::mode(WiFiMode mode) {
|
||||
WiFiModeAction sta = WiFiModeAction((mode & WIFI_MODE_STA) != (currentMode & WIFI_MODE_STA));
|
||||
WiFiModeAction ap = WiFiModeAction((mode & WIFI_MODE_AP) != (currentMode & WIFI_MODE_AP));
|
||||
// change 0/1 to 1/2
|
||||
sta = WiFiModeAction(sta + sta * (mode & WIFI_MODE_STA));
|
||||
ap = WiFiModeAction(ap + ap * (mode & WIFI_MODE_AP));
|
||||
sta = WiFiModeAction(sta + sta * !!(mode & WIFI_MODE_STA));
|
||||
ap = WiFiModeAction(ap + ap * !!(mode & WIFI_MODE_AP));
|
||||
// initialize data structures if wifi is enabled
|
||||
if (mode)
|
||||
dataInitialize();
|
||||
// actually change the mode
|
||||
LT_HEAP_I();
|
||||
return modePriv(mode, sta, ap);
|
||||
if (!modePriv(mode, sta, ap))
|
||||
return false;
|
||||
if (getMode() != mode) {
|
||||
LT_WM(WIFI, "Mode changed to %d (requested %d)", getMode(), mode);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WiFiClass::enableSTA(bool enable) {
|
||||
@@ -38,6 +46,22 @@ bool WiFiClass::enableAP(bool enable) {
|
||||
return true;
|
||||
}
|
||||
|
||||
__attribute__((weak)) bool WiFiClass::setSleep(bool enable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
__attribute__((weak)) bool WiFiClass::getSleep() {
|
||||
return false;
|
||||
}
|
||||
|
||||
__attribute__((weak)) bool WiFiClass::setTxPower(int power) {
|
||||
return false;
|
||||
}
|
||||
|
||||
__attribute__((weak)) int WiFiClass::getTxPower() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WiFiClass::hostByName(const char *hostname, IPAddress &aResult) {
|
||||
aResult = hostByName(hostname);
|
||||
return true;
|
||||
|
||||
@@ -137,9 +137,10 @@ typedef struct {
|
||||
} WiFiScanAP;
|
||||
|
||||
typedef struct {
|
||||
bool running = false;
|
||||
uint8_t count = 0;
|
||||
WiFiScanAP *ap = NULL;
|
||||
bool running = false;
|
||||
unsigned long timeout = 0;
|
||||
uint8_t count = 0;
|
||||
WiFiScanAP *ap = NULL;
|
||||
} WiFiScanData;
|
||||
|
||||
typedef enum {
|
||||
|
||||
@@ -5,7 +5,28 @@
|
||||
|
||||
class IWiFiUDP : public UDP {
|
||||
public:
|
||||
uint8_t beginMulticast(IPAddress ip, uint16_t port);
|
||||
int beginMulticastPacket();
|
||||
int beginPacket();
|
||||
IWiFiUDP() {}
|
||||
|
||||
~IWiFiUDP() {}
|
||||
|
||||
virtual uint8_t begin(IPAddress ip, uint16_t port) = 0;
|
||||
virtual uint8_t begin(uint16_t port) = 0;
|
||||
virtual uint8_t beginMulticast(IPAddress ip, uint16_t port) = 0;
|
||||
virtual void stop() = 0;
|
||||
virtual int beginMulticastPacket() = 0;
|
||||
virtual int beginPacket() = 0;
|
||||
virtual int beginPacket(IPAddress ip, uint16_t port) = 0;
|
||||
virtual int beginPacket(const char *host, uint16_t port) = 0;
|
||||
virtual int endPacket() = 0;
|
||||
virtual size_t write(uint8_t) = 0;
|
||||
virtual size_t write(const uint8_t *buffer, size_t size) = 0;
|
||||
virtual int parsePacket() = 0;
|
||||
virtual int available() = 0;
|
||||
virtual int read() = 0;
|
||||
virtual int read(unsigned char *buffer, size_t len) = 0;
|
||||
virtual int read(char *buffer, size_t len) = 0;
|
||||
virtual int peek() = 0;
|
||||
virtual void flush() = 0;
|
||||
virtual IPAddress remoteIP() = 0;
|
||||
virtual uint16_t remotePort() = 0;
|
||||
};
|
||||
|
||||
@@ -41,15 +41,3 @@ long random(long howsmall, long howbig) {
|
||||
|
||||
return random(diff) + howsmall;
|
||||
}
|
||||
|
||||
extern long map(long x, long in_min, long in_max, long out_min, long out_max) {
|
||||
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
||||
}
|
||||
|
||||
extern uint16_t makeWord(uint16_t w) {
|
||||
return w;
|
||||
}
|
||||
|
||||
extern uint16_t makeWord(uint8_t h, uint8_t l) {
|
||||
return (h << 8) | l;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
/* 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)
|
||||
|
||||
@@ -9,8 +11,9 @@ enum ChipFamily {
|
||||
F_RTL8710B = 0x22E0D6FC, // Realtek AmebaZ (realtek-ambz)
|
||||
F_RTL8720C = 0xE08F7564, // Realtek AmebaZ2
|
||||
F_RTL8720D = 0x3379CFE2, // Realtek AmebaD
|
||||
F_BK7231T = 0x675A40B0, // Beken 7231T
|
||||
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
|
||||
@@ -26,4 +29,9 @@ enum ChipType {
|
||||
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
|
||||
};
|
||||
|
||||
@@ -14,6 +14,7 @@ String ipToString(const IPAddress &ip) {
|
||||
* @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;
|
||||
@@ -37,7 +38,7 @@ void lt_rand_bytes(uint8_t *buf, size_t len) {
|
||||
* @param offset increment printed offset by this value
|
||||
* @param width how many bytes on a line
|
||||
*/
|
||||
void hexdump(uint8_t *buf, size_t len, uint32_t offset, uint8_t width) {
|
||||
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
|
||||
@@ -61,3 +62,4 @@ void hexdump(uint8_t *buf, size_t len, uint32_t offset, uint8_t width) {
|
||||
pos += lineWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,26 @@
|
||||
#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
|
||||
@@ -47,11 +64,17 @@ extern "C" {
|
||||
"LibreTuya v" LT_VERSION_STR " on " LT_BOARD_STR ", compiled at " __DATE__ " " __TIME__ \
|
||||
)
|
||||
|
||||
void lt_rand_bytes(uint8_t *buf, size_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
String ipToString(const IPAddress &ip);
|
||||
void hexdump(uint8_t *buf, size_t len, uint32_t offset = 0, uint8_t width = 16);
|
||||
|
||||
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 hexdump(uint8_t *buf, size_t len, uint32_t offset, uint8_t width);
|
||||
|
||||
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
|
||||
|
||||
@@ -50,6 +50,33 @@ const char *LibreTuya::getDeviceName() {
|
||||
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.
|
||||
*/
|
||||
@@ -74,18 +101,6 @@ __attribute__((weak)) uint32_t LibreTuya::getFlashChipSize() {
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint8_t otaRunningIndex = 0;
|
||||
|
||||
/**
|
||||
* @brief Get the currently running firmware OTA index.
|
||||
*/
|
||||
uint8_t LibreTuya::otaGetRunning() {
|
||||
if (otaRunningIndex)
|
||||
return otaRunningIndex;
|
||||
// otaRunningIndex will be correct even after switchOta()
|
||||
return otaRunningIndex = otaGetStoredIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the OTA index for updated firmware.
|
||||
*
|
||||
@@ -98,7 +113,8 @@ uint8_t LibreTuya::otaGetTarget() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Perform OTA rollback.
|
||||
* @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
|
||||
*/
|
||||
|
||||
@@ -7,6 +7,18 @@
|
||||
#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.
|
||||
*/
|
||||
@@ -31,18 +43,34 @@ class LibreTuya {
|
||||
ChipFamily getChipFamily();
|
||||
const char *getChipFamilyName();
|
||||
const char *getDeviceName();
|
||||
const char *getResetReasonName(ResetReason reason = RESET_REASON_MAX);
|
||||
uint32_t getCpuFreqMHz();
|
||||
uint32_t getFlashChipSize();
|
||||
uint8_t otaGetRunning();
|
||||
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.
|
||||
@@ -109,12 +137,18 @@ class LibreTuya {
|
||||
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.
|
||||
* @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();
|
||||
/**
|
||||
@@ -134,6 +168,23 @@ class LibreTuya {
|
||||
* @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;
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#define LT_LEVEL_WARN 3
|
||||
#define LT_LEVEL_ERROR 4
|
||||
#define LT_LEVEL_FATAL 5
|
||||
#define LT_LEVEL_NONE 6
|
||||
|
||||
// Logger enabled/disabled
|
||||
#ifndef LT_LOGGER
|
||||
@@ -24,11 +25,11 @@
|
||||
#endif
|
||||
|
||||
#ifndef LT_LOGGER_CALLER
|
||||
#define LT_LOGGER_CALLER 1
|
||||
#define LT_LOGGER_CALLER 0
|
||||
#endif
|
||||
|
||||
#ifndef LT_LOGGER_TASK
|
||||
#define LT_LOGGER_TASK 1
|
||||
#define LT_LOGGER_TASK 0
|
||||
#endif
|
||||
|
||||
#ifndef LT_LOGGER_COLOR
|
||||
@@ -44,6 +45,11 @@
|
||||
#define LT_LOGLEVEL LT_LEVEL_INFO
|
||||
#endif
|
||||
|
||||
#if !LT_LOGGER
|
||||
#undef LT_LOGLEVEL
|
||||
#define LT_LOGLEVEL LT_LEVEL_NONE
|
||||
#endif
|
||||
|
||||
// Free heap size debugging
|
||||
#ifndef LT_LOG_HEAP
|
||||
#define LT_LOG_HEAP 0
|
||||
@@ -54,27 +60,73 @@
|
||||
#define LT_LOG_ERRNO 0
|
||||
#endif
|
||||
|
||||
// Per-module debugging
|
||||
// Serial output options
|
||||
#ifndef LT_UART_SILENT_ENABLED
|
||||
#define LT_UART_SILENT_ENABLED 1
|
||||
#endif
|
||||
|
||||
#ifndef LT_UART_SILENT_ALL
|
||||
#define LT_UART_SILENT_ALL 0
|
||||
#endif
|
||||
|
||||
#ifndef LT_UART_DEFAULT_LOGGER
|
||||
#define LT_UART_DEFAULT_LOGGER LT_UART_DEFAULT_PORT
|
||||
#endif
|
||||
|
||||
#ifndef LT_UART_DEFAULT_SERIAL
|
||||
#define LT_UART_DEFAULT_SERIAL LT_UART_DEFAULT_PORT
|
||||
#endif
|
||||
|
||||
// Misc options
|
||||
#ifndef LT_USE_TIME
|
||||
#define LT_USE_TIME 0
|
||||
#endif
|
||||
|
||||
#ifndef LT_MICROS_HIGH_RES // NOTE: this is also defined in fixups/clock_rtos.c
|
||||
#define LT_MICROS_HIGH_RES 1
|
||||
#endif
|
||||
|
||||
#ifndef LT_AUTO_DOWNLOAD_REBOOT
|
||||
#define LT_AUTO_DOWNLOAD_REBOOT 1
|
||||
#endif
|
||||
|
||||
// Per-module logging output - applies to all loglevels
|
||||
#ifndef LT_DEBUG_ALL
|
||||
#define LT_DEBUG_ALL 0
|
||||
#endif
|
||||
|
||||
#ifndef LT_DEBUG_WIFI
|
||||
#define LT_DEBUG_WIFI 0
|
||||
#define LT_DEBUG_WIFI 1
|
||||
#endif
|
||||
|
||||
#ifndef LT_DEBUG_WIFI_CLIENT
|
||||
#define LT_DEBUG_WIFI_CLIENT 0
|
||||
#ifndef LT_DEBUG_CLIENT
|
||||
#define LT_DEBUG_CLIENT LT_DEBUG_ALL
|
||||
#endif
|
||||
|
||||
#ifndef LT_DEBUG_WIFI_SERVER
|
||||
#define LT_DEBUG_WIFI_SERVER 0
|
||||
#endif
|
||||
|
||||
#ifndef LT_DEBUG_WIFI_STA
|
||||
#define LT_DEBUG_WIFI_STA 0
|
||||
#endif
|
||||
|
||||
#ifndef LT_DEBUG_WIFI_AP
|
||||
#define LT_DEBUG_WIFI_AP 0
|
||||
#ifndef LT_DEBUG_SERVER
|
||||
#define LT_DEBUG_SERVER LT_DEBUG_ALL
|
||||
#endif
|
||||
|
||||
#ifndef LT_DEBUG_SSL
|
||||
#define LT_DEBUG_SSL 0
|
||||
#define LT_DEBUG_SSL LT_DEBUG_ALL
|
||||
#endif
|
||||
|
||||
#ifndef LT_DEBUG_OTA
|
||||
#define LT_DEBUG_OTA 1
|
||||
#endif
|
||||
|
||||
#ifndef LT_DEBUG_FDB
|
||||
#define LT_DEBUG_FDB 0
|
||||
#endif
|
||||
|
||||
#ifndef LT_DEBUG_MDNS
|
||||
#define LT_DEBUG_MDNS LT_DEBUG_ALL
|
||||
#endif
|
||||
|
||||
#ifndef LT_DEBUG_LWIP
|
||||
#define LT_DEBUG_LWIP 0
|
||||
#endif
|
||||
|
||||
#ifndef LT_DEBUG_LWIP_ASSERT
|
||||
#define LT_DEBUG_LWIP_ASSERT 0
|
||||
#endif
|
||||
|
||||
@@ -9,7 +9,9 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Run main_task & start OS kernel (family-defined)
|
||||
* @brief Run mainTask & start OS kernel (family-defined).
|
||||
* Return false if an error occured; else do not return and
|
||||
* and keep the OS kernel running.
|
||||
*/
|
||||
extern bool startMainTask();
|
||||
|
||||
@@ -17,7 +19,14 @@ extern bool startMainTask();
|
||||
* @brief Main setup() and loop() task.
|
||||
* Not to be called directly.
|
||||
*/
|
||||
extern void main_task(const void *arg);
|
||||
extern void mainTask(const void *arg);
|
||||
|
||||
/**
|
||||
* @brief Run periodic tasks, like printing free heap or checking millis() overflow.
|
||||
*
|
||||
* This is called during delaying operations, like yield() or delay().
|
||||
*/
|
||||
extern void runPeriodicTasks();
|
||||
|
||||
#define PIN_NONE (1 << 0)
|
||||
#define PIN_GPIO (1 << 1)
|
||||
|
||||
25
arduino/libretuya/core/SerialExtern.h
Normal file
25
arduino/libretuya/core/SerialExtern.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-07-04. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#ifdef HAS_SERIAL_CLASS // failsafe for circular inclusion
|
||||
|
||||
#ifdef PIN_SERIAL0_TX
|
||||
extern SerialClass Serial0;
|
||||
#endif
|
||||
|
||||
#ifdef PIN_SERIAL1_TX
|
||||
extern SerialClass Serial1;
|
||||
#endif
|
||||
|
||||
#ifdef PIN_SERIAL2_TX
|
||||
extern SerialClass Serial2;
|
||||
#endif
|
||||
|
||||
#define SerialN(x) Serial##x
|
||||
#define SerialM(x) SerialN(x)
|
||||
#define Serial SerialM(LT_UART_DEFAULT_SERIAL)
|
||||
|
||||
#endif
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "lt_logger.h"
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <printf/printf.h>
|
||||
|
||||
#if LT_LOGGER_TASK && LT_HAS_FREERTOS
|
||||
#include <FreeRTOS.h>
|
||||
@@ -27,10 +28,11 @@
|
||||
#define COLOR_BRIGHT_CYAN 0x16
|
||||
#define COLOR_BRIGHT_WHITE 0x17
|
||||
|
||||
const char levels[] = {'V', 'D', 'I', 'W', 'E', 'F'};
|
||||
static uint32_t uart_port = LT_UART_DEFAULT_LOGGER;
|
||||
static const char levels[] = {'V', 'D', 'I', 'W', 'E', 'F'};
|
||||
|
||||
#if LT_LOGGER_COLOR
|
||||
const uint8_t colors[] = {
|
||||
static const uint8_t colors[] = {
|
||||
COLOR_BRIGHT_CYAN,
|
||||
COLOR_BRIGHT_BLUE,
|
||||
COLOR_BRIGHT_GREEN,
|
||||
@@ -48,6 +50,9 @@ void lt_log(const uint8_t level, const char *caller, const unsigned short line,
|
||||
void lt_log(const uint8_t level, const char *format, ...) {
|
||||
#endif
|
||||
|
||||
if (uart_port == 0xFF)
|
||||
return;
|
||||
|
||||
#if LT_LOGGER_TIMESTAMP
|
||||
float seconds = millis() / 1000.0f;
|
||||
#if LT_PRINTF_BROKEN
|
||||
@@ -72,7 +77,10 @@ void lt_log(const uint8_t level, const char *format, ...) {
|
||||
char c_value = '0' + (colors[level] & 0x7);
|
||||
#endif
|
||||
|
||||
printf(
|
||||
fctprintf(
|
||||
(void (*)(char, void *))putchar_p,
|
||||
(void *)uart_port,
|
||||
// format:
|
||||
#if LT_LOGGER_COLOR
|
||||
"\e[%c;3%cm"
|
||||
#endif
|
||||
@@ -94,6 +102,7 @@ void lt_log(const uint8_t level, const char *format, ...) {
|
||||
"%s%c "
|
||||
#endif
|
||||
,
|
||||
// arguments:
|
||||
#if LT_LOGGER_COLOR
|
||||
c_bright, // whether text is bright
|
||||
c_value, // text color
|
||||
@@ -121,7 +130,16 @@ void lt_log(const uint8_t level, const char *format, ...) {
|
||||
|
||||
va_list va_args;
|
||||
va_start(va_args, format);
|
||||
vprintf(format, va_args);
|
||||
vfctprintf((void (*)(char, void *))putchar_p, (void *)uart_port, format, va_args);
|
||||
va_end(va_args);
|
||||
printf("\r\n");
|
||||
putchar_p('\r', uart_port);
|
||||
putchar_p('\n', uart_port);
|
||||
}
|
||||
|
||||
void lt_log_set_port(uint8_t port) {
|
||||
uart_port = port;
|
||||
}
|
||||
|
||||
void lt_log_disable() {
|
||||
uart_port = 0xFF;
|
||||
}
|
||||
|
||||
@@ -7,48 +7,87 @@
|
||||
|
||||
#if LT_LOGGER_CALLER
|
||||
#define LT_LOG(level, caller, line, ...) lt_log(level, caller, line, __VA_ARGS__)
|
||||
void lt_log(const uint8_t level, const char *caller, const unsigned short line, const char *format, ...);
|
||||
#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__)
|
||||
void lt_log(const uint8_t level, const char *format, ...);
|
||||
#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_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_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_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_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_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_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
|
||||
@@ -84,20 +123,6 @@ void lt_log(const uint8_t level, const char *format, ...);
|
||||
#define ets_printf(...) LT_I(__VA_ARGS__)
|
||||
#define ETS_PRINTF(...) LT_I(__VA_ARGS__)
|
||||
|
||||
#define LT_T_MOD(module, ...) \
|
||||
do { \
|
||||
if (module) { \
|
||||
LT_T(__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define LT_D_MOD(module, ...) \
|
||||
do { \
|
||||
if (module) { \
|
||||
LT_D(__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define LT_RET(ret) \
|
||||
LT_E("ret=%d", ret); \
|
||||
return ret;
|
||||
@@ -143,33 +168,3 @@ void lt_log(const uint8_t level, const char *format, ...);
|
||||
#else
|
||||
#define LT_ERRNO()
|
||||
#endif
|
||||
|
||||
// WiFi.cpp
|
||||
#define LT_T_WG(...) LT_T_MOD(LT_DEBUG_WIFI, __VA_ARGS__)
|
||||
#define LT_V_WG(...) LT_T_MOD(LT_DEBUG_WIFI, __VA_ARGS__)
|
||||
#define LT_D_WG(...) LT_D_MOD(LT_DEBUG_WIFI, __VA_ARGS__)
|
||||
|
||||
// WiFiClient.cpp
|
||||
#define LT_T_WC(...) LT_T_MOD(LT_DEBUG_WIFI_CLIENT, __VA_ARGS__)
|
||||
#define LT_V_WC(...) LT_T_MOD(LT_DEBUG_WIFI_CLIENT, __VA_ARGS__)
|
||||
#define LT_D_WC(...) LT_D_MOD(LT_DEBUG_WIFI_CLIENT, __VA_ARGS__)
|
||||
|
||||
// WiFiServer.cpp
|
||||
#define LT_T_WS(...) LT_T_MOD(LT_DEBUG_WIFI_SERVER, __VA_ARGS__)
|
||||
#define LT_V_WS(...) LT_T_MOD(LT_DEBUG_WIFI_SERVER, __VA_ARGS__)
|
||||
#define LT_D_WS(...) LT_D_MOD(LT_DEBUG_WIFI_SERVER, __VA_ARGS__)
|
||||
|
||||
// WiFiSTA.cpp
|
||||
#define LT_T_WSTA(...) LT_T_MOD(LT_DEBUG_WIFI_STA, __VA_ARGS__)
|
||||
#define LT_V_WSTA(...) LT_T_MOD(LT_DEBUG_WIFI_STA, __VA_ARGS__)
|
||||
#define LT_D_WSTA(...) LT_D_MOD(LT_DEBUG_WIFI_STA, __VA_ARGS__)
|
||||
|
||||
// WiFiAP.cpp
|
||||
#define LT_T_WAP(...) LT_T_MOD(LT_DEBUG_WIFI_AP, __VA_ARGS__)
|
||||
#define LT_V_WAP(...) LT_T_MOD(LT_DEBUG_WIFI_AP, __VA_ARGS__)
|
||||
#define LT_D_WAP(...) LT_D_MOD(LT_DEBUG_WIFI_AP, __VA_ARGS__)
|
||||
|
||||
// WiFiClientSecure.cpp & implementations
|
||||
#define LT_T_SSL(...) LT_T_MOD(LT_DEBUG_SSL, __VA_ARGS__)
|
||||
#define LT_V_SSL(...) LT_T_MOD(LT_DEBUG_SSL, __VA_ARGS__)
|
||||
#define LT_D_SSL(...) LT_D_MOD(LT_DEBUG_SSL, __VA_ARGS__)
|
||||
|
||||
@@ -12,7 +12,7 @@ fal_partition_t fal_root_part = NULL;
|
||||
|
||||
// Arduino framework initialization.
|
||||
// May be redefined by family files.
|
||||
void init() __attribute__((weak));
|
||||
void initArduino() __attribute__((weak));
|
||||
|
||||
// Weak empty variant initialization function.
|
||||
// May be redefined by variant files.
|
||||
@@ -21,7 +21,7 @@ void initVariant() __attribute__((weak));
|
||||
// Initialize C library
|
||||
extern "C" void __libc_init_array(void);
|
||||
|
||||
void main_task(const void *arg) {
|
||||
void mainTask(const void *arg) {
|
||||
setup();
|
||||
|
||||
for (;;) {
|
||||
@@ -32,13 +32,32 @@ void main_task(const void *arg) {
|
||||
}
|
||||
}
|
||||
|
||||
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 Arduino framework
|
||||
init();
|
||||
// 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
|
||||
@@ -46,7 +65,9 @@ int main(void) {
|
||||
// provide root partition
|
||||
fal_root_part = (fal_partition_t)fal_partition_find("root");
|
||||
// start the main task and OS kernel
|
||||
startMainTask();
|
||||
if (!startMainTask()) {
|
||||
LT_F("Couldn't start the main task");
|
||||
}
|
||||
|
||||
while (1) {}
|
||||
return 0;
|
||||
@@ -9,6 +9,12 @@
|
||||
#if LT_MD5_USE_POLARSSL
|
||||
#include "MD5PolarSSLImpl.h"
|
||||
#endif
|
||||
#if LT_MD5_USE_MBEDTLS
|
||||
#include "MD5MbedTLSImpl.h"
|
||||
#endif
|
||||
#if LT_MD5_USE_HOSTAPD
|
||||
#include "MD5HostapdImpl.h"
|
||||
#endif
|
||||
|
||||
// common API
|
||||
#ifdef __cplusplus
|
||||
|
||||
14
arduino/libretuya/libraries/MD5/MD5HostapdImpl.h
Normal file
14
arduino/libretuya/libraries/MD5/MD5HostapdImpl.h
Normal file
@@ -0,0 +1,14 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-07-12. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <crypto/md5_i.h>
|
||||
#define LT_MD5_CTX_T struct MD5Context
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
28
arduino/libretuya/libraries/MD5/MD5MbedTLSImpl.cpp
Normal file
28
arduino/libretuya/libraries/MD5/MD5MbedTLSImpl.cpp
Normal file
@@ -0,0 +1,28 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-07-11. */
|
||||
|
||||
#if LT_ARD_HAS_MD5
|
||||
|
||||
#include "MD5.h"
|
||||
|
||||
#if LT_MD5_USE_MBEDTLS
|
||||
|
||||
extern "C" {
|
||||
|
||||
void MD5Init(LT_MD5_CTX_T *context) {
|
||||
mbedtls_md5_init(context);
|
||||
mbedtls_md5_starts(context);
|
||||
}
|
||||
|
||||
void MD5Update(LT_MD5_CTX_T *context, const unsigned char *buf, unsigned len) {
|
||||
mbedtls_md5_update(context, buf, len);
|
||||
}
|
||||
|
||||
void MD5Final(unsigned char digest[16], LT_MD5_CTX_T *context) {
|
||||
mbedtls_md5_finish(context, digest);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
#endif // LT_MD5_USE_MBEDTLS
|
||||
|
||||
#endif // LT_ARD_HAS_MD5
|
||||
14
arduino/libretuya/libraries/MD5/MD5MbedTLSImpl.h
Normal file
14
arduino/libretuya/libraries/MD5/MD5MbedTLSImpl.h
Normal file
@@ -0,0 +1,14 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-07-11. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <mbedtls/md5.h>
|
||||
#define LT_MD5_CTX_T mbedtls_md5_context
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
@@ -37,7 +37,7 @@ class SocketHandle {
|
||||
};
|
||||
|
||||
LwIPClient::LwIPClient() {
|
||||
LT_V_WC("LwIPClient()");
|
||||
LT_VM(CLIENT, "LwIPClient()");
|
||||
_connected = false;
|
||||
_sock = NULL;
|
||||
_rxBuffer = NULL;
|
||||
@@ -45,7 +45,7 @@ LwIPClient::LwIPClient() {
|
||||
}
|
||||
|
||||
LwIPClient::LwIPClient(int sock) {
|
||||
LT_V_WC("LwIPClient(%d)", sock);
|
||||
LT_VM(CLIENT, "LwIPClient(%d)", sock);
|
||||
_connected = true;
|
||||
_sock = std::make_shared<SocketHandle>(sock);
|
||||
_rxBuffer = std::make_shared<LwIPRxBuffer>(sock);
|
||||
@@ -53,7 +53,7 @@ LwIPClient::LwIPClient(int sock) {
|
||||
}
|
||||
|
||||
LwIPClient::~LwIPClient() {
|
||||
LT_V_WC("~LwIPClient()");
|
||||
LT_VM(CLIENT, "~LwIPClient()");
|
||||
stop();
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ int LwIPClient::connect(IPAddress ip, uint16_t port, int32_t timeout) {
|
||||
stop();
|
||||
int sock = lwip_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (sock < 0) {
|
||||
LT_D_WC("socket failed");
|
||||
LT_DM(CLIENT, "socket failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -114,19 +114,19 @@ int LwIPClient::connect(IPAddress ip, uint16_t port, int32_t timeout) {
|
||||
|
||||
int res = lwip_connect(sock, (struct sockaddr *)&addr, sizeof(addr));
|
||||
if (res < 0 && errno != EINPROGRESS) {
|
||||
LT_E("Connect failed; errno=%d", errno);
|
||||
LT_EM(CLIENT, "Connect failed; errno=%d", errno);
|
||||
lwip_close(sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = lwip_select(sock + 1, NULL, &fdset, NULL, timeout < 0 ? NULL : &tv);
|
||||
if (res < 0) {
|
||||
LT_E("Select failed; errno=%d", errno);
|
||||
LT_EM(CLIENT, "Select failed; errno=%d", errno);
|
||||
lwip_close(sock);
|
||||
return 0;
|
||||
}
|
||||
if (res == 0) {
|
||||
LT_E("Select timeout; errno=%d", errno);
|
||||
LT_EM(CLIENT, "Select timeout; errno=%d", errno);
|
||||
lwip_close(sock);
|
||||
return 0;
|
||||
}
|
||||
@@ -136,7 +136,7 @@ int LwIPClient::connect(IPAddress ip, uint16_t port, int32_t timeout) {
|
||||
res = lwip_getsockopt(sock, SOL_SOCKET, SO_ERROR, &sockerr, &len);
|
||||
|
||||
if (res < 0 || sockerr != 0) {
|
||||
LT_E("Socket error; res=%d, sockerr=%d", res, sockerr);
|
||||
LT_EM(CLIENT, "Socket error; res=%d, sockerr=%d", res, sockerr);
|
||||
lwip_close(sock);
|
||||
return 0;
|
||||
}
|
||||
@@ -198,7 +198,7 @@ size_t LwIPClient::write(const uint8_t *buf, size_t size) {
|
||||
retry--;
|
||||
|
||||
if (lwip_select(fd() + 1, NULL, &fdset, NULL, &tv) < 0) {
|
||||
LT_W("Select failed; errno=%d", errno);
|
||||
LT_WM(CLIENT, "Select failed; errno=%d", errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -214,7 +214,7 @@ size_t LwIPClient::write(const uint8_t *buf, size_t size) {
|
||||
retry = WIFI_CLIENT_WRITE_RETRY;
|
||||
}
|
||||
} else if (res < 0 && errno != EAGAIN) {
|
||||
LT_W("Send failed; errno=%d", errno);
|
||||
LT_WM(CLIENT, "Send failed; errno=%d", errno);
|
||||
setWriteError(res);
|
||||
_connected = false;
|
||||
retry = 0;
|
||||
@@ -223,7 +223,7 @@ size_t LwIPClient::write(const uint8_t *buf, size_t size) {
|
||||
}
|
||||
}
|
||||
}
|
||||
LT_D_WC("wrote %d bytes", written);
|
||||
LT_DM(CLIENT, "wrote %d bytes", written);
|
||||
return written;
|
||||
}
|
||||
|
||||
@@ -306,7 +306,7 @@ void LwIPClient::flush() {
|
||||
}
|
||||
|
||||
void LwIPClient::stop() {
|
||||
LT_V_WC("Stopping TCP");
|
||||
LT_VM(CLIENT, "Stopping TCP");
|
||||
_connected = false;
|
||||
_sock = NULL;
|
||||
_rxBuffer = NULL;
|
||||
@@ -327,11 +327,11 @@ uint8_t LwIPClient::connected() {
|
||||
case ECONNRESET:
|
||||
case ECONNREFUSED:
|
||||
case ECONNABORTED:
|
||||
LT_W("Connection closed; errno=%d", errno);
|
||||
LT_IM(CLIENT, "Connection closed; errno=%d", errno);
|
||||
_connected = false;
|
||||
break;
|
||||
default:
|
||||
LT_I("Connection status unknown; errno=%d", errno);
|
||||
LT_WM(CLIENT, "Connection status unknown; errno=%d", errno);
|
||||
_connected = true;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -14,13 +14,13 @@ extern "C" {
|
||||
|
||||
size_t LwIPRxBuffer::r_available() {
|
||||
if (_sock < 0) {
|
||||
LT_D_WC("_sock < 0");
|
||||
LT_DM(CLIENT, "_sock < 0");
|
||||
return 0;
|
||||
}
|
||||
int count = 0; // must be of same size as in lwip_ioctl()
|
||||
int res = lwip_ioctl(_sock, FIONREAD, &count);
|
||||
if (res < 0) {
|
||||
LT_D_WC("lwip_ioctl()=%d, errno=%d", res, errno);
|
||||
LT_DM(CLIENT, "lwip_ioctl()=%d, errno=%d", res, errno);
|
||||
_failed = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ bool LwIPServer::begin(uint16_t port, bool reuseAddr) {
|
||||
|
||||
_sock = lwip_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (_sock < 0) {
|
||||
LT_E("Socket failed; errno=%d", errno);
|
||||
LT_EM(SERVER, "Socket failed; errno=%d", errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -45,17 +45,17 @@ bool LwIPServer::begin(uint16_t port, bool reuseAddr) {
|
||||
addr.sin_port = htons(_port);
|
||||
|
||||
if (lwip_bind(_sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
LT_E("Bind failed; errno=%d", errno);
|
||||
LT_EM(SERVER, "Bind failed; errno=%d", errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lwip_listen(_sock, _maxClients) < 0) {
|
||||
LT_E("Bind failed; errno=%d", errno);
|
||||
LT_EM(SERVER, "Bind failed; errno=%d", errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t *addrB = (uint8_t *)&_addr;
|
||||
LT_I("Server running on %hhu.%hhu.%hhu.%hhu:%hu", addrB[0], addrB[1], addrB[2], addrB[3], _port);
|
||||
LT_IM(SERVER, "Server running on %hhu.%hhu.%hhu.%hhu:%hu", addrB[0], addrB[1], addrB[2], addrB[3], _port);
|
||||
|
||||
lwip_fcntl(_sock, F_SETFL, O_NONBLOCK);
|
||||
_active = true;
|
||||
@@ -99,7 +99,7 @@ WiFiClient LwIPServer::accept() {
|
||||
// and receive data, so LwIP still sees a connected client that sends nothing. At least
|
||||
// that's what I understand. And any loop that doesn't call delay() seems to block the TCP
|
||||
// stack completely and prevents it from even being pinged.
|
||||
LT_D_WS("Got client");
|
||||
LT_DM(SERVER, "Got client");
|
||||
delay(5);
|
||||
return WiFiClient(sock);
|
||||
}
|
||||
|
||||
286
arduino/libretuya/libraries/NetUtils/lwip/LwIPUdp.cpp
Normal file
286
arduino/libretuya/libraries/NetUtils/lwip/LwIPUdp.cpp
Normal file
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
Udp.cpp - UDP class for Raspberry Pi
|
||||
Copyright (c) 2016 Hristo Gochkov 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
|
||||
*/
|
||||
|
||||
#if LT_ARD_HAS_WIFI && LT_HAS_LWIP
|
||||
|
||||
#include "LwIPUdp.h"
|
||||
#include <errno.h>
|
||||
|
||||
extern "C" {
|
||||
|
||||
#include <lwip/netdb.h>
|
||||
#include <lwip/sockets.h>
|
||||
|
||||
} // extern "C"
|
||||
|
||||
#undef write
|
||||
#undef read
|
||||
|
||||
LwIPUDP::LwIPUDP() : udp_server(-1), server_port(0), remote_port(0), tx_buffer(0), tx_buffer_len(0), rx_buffer(0) {}
|
||||
|
||||
LwIPUDP::~LwIPUDP() {
|
||||
stop();
|
||||
}
|
||||
|
||||
uint8_t LwIPUDP::begin(IPAddress address, uint16_t port) {
|
||||
stop();
|
||||
|
||||
server_port = port;
|
||||
|
||||
tx_buffer = new char[1460];
|
||||
if (!tx_buffer) {
|
||||
log_e("could not create tx buffer: %d", errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((udp_server = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
|
||||
log_e("could not create socket: %d", errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int yes = 1;
|
||||
if (setsockopt(udp_server, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
|
||||
log_e("could not set socket option: %d", errno);
|
||||
stop();
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct sockaddr_in addr;
|
||||
memset((char *)&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(server_port);
|
||||
addr.sin_addr.s_addr = (in_addr_t)address;
|
||||
if (bind(udp_server, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
|
||||
log_e("could not bind socket: %d", errno);
|
||||
stop();
|
||||
return 0;
|
||||
}
|
||||
fcntl(udp_server, F_SETFL, O_NONBLOCK);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t LwIPUDP::begin(uint16_t p) {
|
||||
return begin(IPAddress(INADDR_ANY), p);
|
||||
}
|
||||
|
||||
uint8_t LwIPUDP::beginMulticast(IPAddress a, uint16_t p) {
|
||||
if (begin(IPAddress(INADDR_ANY), p)) {
|
||||
if ((uint32_t)a != 0) {
|
||||
struct ip_mreq mreq;
|
||||
mreq.imr_multiaddr.s_addr = (in_addr_t)a;
|
||||
mreq.imr_interface.s_addr = INADDR_ANY;
|
||||
if (setsockopt(udp_server, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
|
||||
log_e("could not join igmp: %d", errno);
|
||||
stop();
|
||||
return 0;
|
||||
}
|
||||
multicast_ip = a;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void LwIPUDP::stop() {
|
||||
if (tx_buffer) {
|
||||
delete[] tx_buffer;
|
||||
tx_buffer = NULL;
|
||||
}
|
||||
tx_buffer_len = 0;
|
||||
if (rx_buffer) {
|
||||
cbuf *b = rx_buffer;
|
||||
rx_buffer = NULL;
|
||||
delete b;
|
||||
}
|
||||
if (udp_server == -1)
|
||||
return;
|
||||
if ((uint32_t)multicast_ip != 0) {
|
||||
struct ip_mreq mreq;
|
||||
mreq.imr_multiaddr.s_addr = (in_addr_t)multicast_ip;
|
||||
mreq.imr_interface.s_addr = (in_addr_t)0;
|
||||
setsockopt(udp_server, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq));
|
||||
multicast_ip = IPAddress(INADDR_ANY);
|
||||
}
|
||||
close(udp_server);
|
||||
udp_server = -1;
|
||||
}
|
||||
|
||||
int LwIPUDP::beginMulticastPacket() {
|
||||
if (!server_port || multicast_ip == IPAddress(INADDR_ANY))
|
||||
return 0;
|
||||
remote_ip = multicast_ip;
|
||||
remote_port = server_port;
|
||||
return beginPacket();
|
||||
}
|
||||
|
||||
int LwIPUDP::beginPacket() {
|
||||
if (!remote_port)
|
||||
return 0;
|
||||
|
||||
// allocate tx_buffer if is necessary
|
||||
if (!tx_buffer) {
|
||||
tx_buffer = new char[1460];
|
||||
if (!tx_buffer) {
|
||||
log_e("could not create tx buffer: %d", errno);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
tx_buffer_len = 0;
|
||||
|
||||
// check whereas socket is already open
|
||||
if (udp_server != -1)
|
||||
return 1;
|
||||
|
||||
if ((udp_server = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
|
||||
log_e("could not create socket: %d", errno);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fcntl(udp_server, F_SETFL, O_NONBLOCK);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LwIPUDP::beginPacket(IPAddress ip, uint16_t port) {
|
||||
remote_ip = ip;
|
||||
remote_port = port;
|
||||
return beginPacket();
|
||||
}
|
||||
|
||||
int LwIPUDP::beginPacket(const char *host, uint16_t port) {
|
||||
struct hostent *server;
|
||||
server = gethostbyname(host);
|
||||
if (server == NULL) {
|
||||
log_e("could not get host from dns: %d", errno);
|
||||
return 0;
|
||||
}
|
||||
return beginPacket(IPAddress((const uint8_t *)(server->h_addr_list[0])), port);
|
||||
}
|
||||
|
||||
int LwIPUDP::endPacket() {
|
||||
struct sockaddr_in recipient;
|
||||
recipient.sin_addr.s_addr = (uint32_t)remote_ip;
|
||||
recipient.sin_family = AF_INET;
|
||||
recipient.sin_port = htons(remote_port);
|
||||
int sent = sendto(udp_server, tx_buffer, tx_buffer_len, 0, (struct sockaddr *)&recipient, sizeof(recipient));
|
||||
if (sent < 0) {
|
||||
log_e("could not send data: %d", errno);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t LwIPUDP::write(uint8_t data) {
|
||||
if (tx_buffer_len == 1460) {
|
||||
endPacket();
|
||||
tx_buffer_len = 0;
|
||||
}
|
||||
tx_buffer[tx_buffer_len++] = data;
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t LwIPUDP::write(const uint8_t *buffer, size_t size) {
|
||||
size_t i;
|
||||
for (i = 0; i < size; i++)
|
||||
write(buffer[i]);
|
||||
return i;
|
||||
}
|
||||
|
||||
int LwIPUDP::parsePacket() {
|
||||
if (rx_buffer)
|
||||
return 0;
|
||||
struct sockaddr_in si_other;
|
||||
int slen = sizeof(si_other), len;
|
||||
char *buf = new char[1460];
|
||||
if (!buf) {
|
||||
return 0;
|
||||
}
|
||||
if ((len = recvfrom(udp_server, buf, 1460, MSG_DONTWAIT, (struct sockaddr *)&si_other, (socklen_t *)&slen)) == -1) {
|
||||
delete[] buf;
|
||||
if (errno == EWOULDBLOCK) {
|
||||
return 0;
|
||||
}
|
||||
log_e("could not receive data: %d", errno);
|
||||
return 0;
|
||||
}
|
||||
remote_ip = IPAddress(si_other.sin_addr.s_addr);
|
||||
remote_port = ntohs(si_other.sin_port);
|
||||
if (len > 0) {
|
||||
rx_buffer = new cbuf(len);
|
||||
rx_buffer->write(buf, len);
|
||||
}
|
||||
delete[] buf;
|
||||
return len;
|
||||
}
|
||||
|
||||
int LwIPUDP::available() {
|
||||
if (!rx_buffer)
|
||||
return 0;
|
||||
return rx_buffer->available();
|
||||
}
|
||||
|
||||
int LwIPUDP::read() {
|
||||
if (!rx_buffer)
|
||||
return -1;
|
||||
int out = rx_buffer->read();
|
||||
if (!rx_buffer->available()) {
|
||||
cbuf *b = rx_buffer;
|
||||
rx_buffer = 0;
|
||||
delete b;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
int LwIPUDP::read(unsigned char *buffer, size_t len) {
|
||||
return read((char *)buffer, len);
|
||||
}
|
||||
|
||||
int LwIPUDP::read(char *buffer, size_t len) {
|
||||
if (!rx_buffer)
|
||||
return 0;
|
||||
int out = rx_buffer->read(buffer, len);
|
||||
if (!rx_buffer->available()) {
|
||||
cbuf *b = rx_buffer;
|
||||
rx_buffer = 0;
|
||||
delete b;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
int LwIPUDP::peek() {
|
||||
if (!rx_buffer)
|
||||
return -1;
|
||||
return rx_buffer->peek();
|
||||
}
|
||||
|
||||
void LwIPUDP::flush() {
|
||||
if (!rx_buffer)
|
||||
return;
|
||||
cbuf *b = rx_buffer;
|
||||
rx_buffer = 0;
|
||||
delete b;
|
||||
}
|
||||
|
||||
IPAddress LwIPUDP::remoteIP() {
|
||||
return remote_ip;
|
||||
}
|
||||
|
||||
uint16_t LwIPUDP::remotePort() {
|
||||
return remote_port;
|
||||
}
|
||||
|
||||
#endif
|
||||
43
arduino/libretuya/libraries/NetUtils/lwip/LwIPUdp.h
Normal file
43
arduino/libretuya/libraries/NetUtils/lwip/LwIPUdp.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-09-10. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <api/WiFi/WiFi.h>
|
||||
#include <api/WiFiUdp.h>
|
||||
#include <cbuf.h>
|
||||
|
||||
class LwIPUDP : public IWiFiUDP {
|
||||
private:
|
||||
int udp_server;
|
||||
IPAddress multicast_ip;
|
||||
IPAddress remote_ip;
|
||||
uint16_t server_port;
|
||||
uint16_t remote_port;
|
||||
char *tx_buffer;
|
||||
size_t tx_buffer_len;
|
||||
cbuf *rx_buffer;
|
||||
|
||||
public:
|
||||
LwIPUDP();
|
||||
~LwIPUDP();
|
||||
uint8_t begin(IPAddress ip, uint16_t port);
|
||||
uint8_t begin(uint16_t port);
|
||||
uint8_t beginMulticast(IPAddress ip, uint16_t port);
|
||||
void stop();
|
||||
int beginMulticastPacket();
|
||||
int beginPacket();
|
||||
int beginPacket(IPAddress ip, uint16_t port);
|
||||
int beginPacket(const char *host, uint16_t port);
|
||||
int endPacket();
|
||||
size_t write(uint8_t);
|
||||
size_t write(const uint8_t *buffer, size_t size);
|
||||
int parsePacket();
|
||||
int available();
|
||||
int read();
|
||||
int read(unsigned char *buffer, size_t len);
|
||||
int read(char *buffer, size_t len);
|
||||
int peek();
|
||||
void flush();
|
||||
IPAddress remoteIP();
|
||||
uint16_t remotePort();
|
||||
};
|
||||
@@ -22,12 +22,12 @@ MbedTLSClient::MbedTLSClient(int sock) : WiFiClient(sock) {
|
||||
}
|
||||
|
||||
MbedTLSClient::~MbedTLSClient() {
|
||||
LT_V_WC("~MbedTLSClient()");
|
||||
LT_VM(CLIENT, "~MbedTLSClient()");
|
||||
stop();
|
||||
}
|
||||
|
||||
void MbedTLSClient::stop() {
|
||||
LT_V_SSL("Stopping SSL");
|
||||
LT_VM(SSL, "Stopping SSL");
|
||||
|
||||
if (_sslCfg.ca_chain) {
|
||||
mbedtls_x509_crt_free(&_caCert);
|
||||
@@ -88,7 +88,7 @@ void debug_cb(void *ctx, int level, const char *file, int line, const char *str)
|
||||
uint16_t len = strlen(str);
|
||||
char *msg = (char *)str;
|
||||
msg[len - 1] = '\0';
|
||||
LT_I("%04d: |%d| %s", line, level, msg);
|
||||
LT_IM(SSL, "%04d: |%d| %s", line, level, msg);
|
||||
}
|
||||
|
||||
int MbedTLSClient::connect(
|
||||
@@ -115,13 +115,13 @@ int MbedTLSClient::connect(
|
||||
|
||||
int ret = WiFiClient::connect(addr, port, timeout);
|
||||
if (ret < 0) {
|
||||
LT_E("SSL socket failed");
|
||||
LT_EM(SSL, "SSL socket failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *uid = "lt-ssl"; // TODO
|
||||
|
||||
LT_V_SSL("Init SSL");
|
||||
LT_VM(SSL, "Init SSL");
|
||||
init();
|
||||
LT_HEAP_I();
|
||||
|
||||
@@ -160,7 +160,7 @@ int MbedTLSClient::connect(
|
||||
#ifdef MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED
|
||||
uint16_t len = strlen(psk);
|
||||
if ((len & 1) != 0 || len > 2 * MBEDTLS_PSK_MAX_LEN) {
|
||||
LT_E("PSK length invalid");
|
||||
LT_EM(SSL, "PSK length invalid");
|
||||
return -1;
|
||||
}
|
||||
unsigned char pskBin[MBEDTLS_PSK_MAX_LEN] = {};
|
||||
@@ -185,13 +185,13 @@ int MbedTLSClient::connect(
|
||||
if (!_insecure && clientCert && clientKey) {
|
||||
mbedtls_x509_crt_init(&_clientCert);
|
||||
mbedtls_pk_init(&_clientKey);
|
||||
LT_V_SSL("Loading client cert");
|
||||
LT_VM(SSL, "Loading client cert");
|
||||
ret = mbedtls_x509_crt_parse(&_clientCert, (const unsigned char *)clientCert, strlen(clientCert) + 1);
|
||||
if (ret < 0) {
|
||||
mbedtls_x509_crt_free(&_clientCert);
|
||||
LT_RET(ret);
|
||||
}
|
||||
LT_V_SSL("Loading private key");
|
||||
LT_VM(SSL, "Loading private key");
|
||||
ret = mbedtls_pk_parse_key(&_clientKey, (const unsigned char *)clientKey, strlen(clientKey) + 1, NULL, 0);
|
||||
if (ret < 0) {
|
||||
mbedtls_x509_crt_free(&_clientCert);
|
||||
@@ -200,7 +200,7 @@ int MbedTLSClient::connect(
|
||||
mbedtls_ssl_conf_own_cert(&_sslCfg, &_clientCert, &_clientKey);
|
||||
}
|
||||
|
||||
LT_V_SSL("Setting TLS hostname");
|
||||
LT_VM(SSL, "Setting TLS hostname");
|
||||
ret = mbedtls_ssl_set_hostname(&_sslCtx, host);
|
||||
LT_RET_NZ(ret);
|
||||
|
||||
@@ -214,7 +214,7 @@ int MbedTLSClient::connect(
|
||||
|
||||
LT_HEAP_I();
|
||||
|
||||
LT_V_SSL("SSL handshake");
|
||||
LT_VM(SSL, "SSL handshake");
|
||||
if (_handshakeTimeout == 0)
|
||||
_handshakeTimeout = timeout;
|
||||
unsigned long start = millis();
|
||||
@@ -223,7 +223,7 @@ int MbedTLSClient::connect(
|
||||
LT_RET(ret);
|
||||
}
|
||||
if ((millis() - start) > _handshakeTimeout) {
|
||||
LT_E("SSL handshake timeout");
|
||||
LT_EM(SSL, "SSL handshake timeout");
|
||||
return -1;
|
||||
}
|
||||
delay(2);
|
||||
@@ -232,26 +232,27 @@ int MbedTLSClient::connect(
|
||||
LT_HEAP_I();
|
||||
|
||||
if (clientCert && clientKey) {
|
||||
LT_D_SSL(
|
||||
LT_DM(
|
||||
SSL,
|
||||
"Protocol %s, ciphersuite %s",
|
||||
mbedtls_ssl_get_version(&_sslCtx),
|
||||
mbedtls_ssl_get_ciphersuite(&_sslCtx)
|
||||
);
|
||||
ret = mbedtls_ssl_get_record_expansion(&_sslCtx);
|
||||
if (ret >= 0)
|
||||
LT_D_SSL("Record expansion: %d", ret);
|
||||
LT_DM(SSL, "Record expansion: %d", ret);
|
||||
else {
|
||||
LT_W("Record expansion unknown");
|
||||
LT_WM(SSL, "Record expansion unknown");
|
||||
}
|
||||
}
|
||||
|
||||
LT_V_SSL("Verifying certificate");
|
||||
LT_VM(SSL, "Verifying certificate");
|
||||
ret = mbedtls_ssl_get_verify_result(&_sslCtx);
|
||||
if (ret) {
|
||||
char buf[512];
|
||||
memset(buf, 0, sizeof(buf));
|
||||
mbedtls_x509_crt_verify_info(buf, sizeof(buf), " ! ", ret);
|
||||
LT_E("Failed to verify peer certificate! Verification info: %s", buf);
|
||||
LT_EM(SSL, "Failed to verify peer certificate! Verification info: %s", buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -417,7 +418,7 @@ bool MbedTLSClient::verify(const char *fingerprint, const char *domainName) {
|
||||
return false;
|
||||
|
||||
if (memcmp(fpLocal, fpRemote, 32)) {
|
||||
LT_D_SSL("Fingerprints don't match");
|
||||
LT_DM(SSL, "Fingerprints don't match");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -438,7 +439,7 @@ void MbedTLSClient::setAlpnProtocols(const char **alpnProtocols) {
|
||||
bool MbedTLSClient::getFingerprintSHA256(uint8_t result[32]) {
|
||||
const mbedtls_x509_crt *cert = mbedtls_ssl_get_peer_cert(&_sslCtx);
|
||||
if (!cert) {
|
||||
LT_E("Failed to get peer certificate");
|
||||
LT_EM(SSL, "Failed to get peer certificate");
|
||||
return false;
|
||||
}
|
||||
mbedtls_sha256_context shaCtx;
|
||||
|
||||
@@ -25,13 +25,8 @@
|
||||
|
||||
size_t StreamString::write(const uint8_t *data, size_t size) {
|
||||
if(size && data) {
|
||||
const unsigned int newlen = len + size;
|
||||
if(reserve(newlen + 1)) {
|
||||
memcpy((void *) (buffer + len), (const void *) data, size);
|
||||
changeBuffer(newlen);
|
||||
*(buffer + newlen) = 0x00; // add null for string end
|
||||
return size;
|
||||
}
|
||||
concat(data, size);
|
||||
return size;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -18,14 +18,20 @@ bool UpdateClass::begin(size_t size, int command, int unused2, uint8_t unused3,
|
||||
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)
|
||||
return errorArd(UPDATE_ERROR_SIZE);
|
||||
if (!size) {
|
||||
cleanup(UPDATE_ERROR_SIZE);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (command != U_FLASH)
|
||||
return errorArd(UPDATE_ERROR_BAD_ARGUMENT);
|
||||
if (command != U_FLASH) {
|
||||
cleanup(UPDATE_ERROR_BAD_ARGUMENT);
|
||||
return false;
|
||||
}
|
||||
|
||||
bytesTotal = size;
|
||||
return true;
|
||||
@@ -44,12 +50,15 @@ bool UpdateClass::end(bool evenIfRemaining) {
|
||||
|
||||
if (!isFinished() && !evenIfRemaining) {
|
||||
// abort if not finished
|
||||
return errorArd(UPDATE_ERROR_ABORT);
|
||||
cleanup(UPDATE_ERROR_ABORT);
|
||||
return false;
|
||||
}
|
||||
// TODO what is evenIfRemaining for?
|
||||
if (!LT.otaSwitch())
|
||||
if (!LT.otaSwitch()) {
|
||||
// try to activate the second OTA
|
||||
return errorArd(UPDATE_ERROR_ACTIVATE);
|
||||
cleanup(UPDATE_ERROR_ACTIVATE);
|
||||
return false;
|
||||
}
|
||||
|
||||
cleanup();
|
||||
return true;
|
||||
@@ -70,6 +79,8 @@ size_t UpdateClass::write(uint8_t *data, size_t len) {
|
||||
// 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)) {
|
||||
@@ -82,12 +93,14 @@ size_t UpdateClass::write(uint8_t *data, size_t len) {
|
||||
} */
|
||||
|
||||
// write until buffer space is available
|
||||
uint16_t toWrite;
|
||||
uint16_t toWrite; // 1..512
|
||||
while (len && (toWrite = min(len, bufLeft()))) {
|
||||
tryWriteData(data, toWrite);
|
||||
if (hasError())
|
||||
if (hasError()) {
|
||||
// return on errors
|
||||
printErrorContext2(data, toWrite);
|
||||
return written;
|
||||
}
|
||||
data += toWrite;
|
||||
len -= toWrite;
|
||||
written += toWrite;
|
||||
@@ -109,7 +122,7 @@ size_t UpdateClass::writeStream(Stream &data) {
|
||||
if (available <= 0) {
|
||||
if (millis() - lastData > UPDATE_TIMEOUT_MS) {
|
||||
// waited for data too long; abort with error
|
||||
errorArd(UPDATE_ERROR_STREAM);
|
||||
cleanup(UPDATE_ERROR_STREAM);
|
||||
return written;
|
||||
}
|
||||
continue;
|
||||
@@ -123,9 +136,11 @@ size_t UpdateClass::writeStream(Stream &data) {
|
||||
bufPos += read;
|
||||
written += read;
|
||||
tryWriteData();
|
||||
if (hasError())
|
||||
if (hasError()) {
|
||||
// return on errors
|
||||
printErrorContext2(NULL, read); // buf is not valid anymore
|
||||
return written;
|
||||
}
|
||||
}
|
||||
return written;
|
||||
}
|
||||
@@ -141,6 +156,8 @@ size_t UpdateClass::writeStream(Stream &data) {
|
||||
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;
|
||||
@@ -158,7 +175,7 @@ size_t UpdateClass::tryWriteData(uint8_t *data, size_t len) {
|
||||
|
||||
// a complete block has been found
|
||||
if (block) {
|
||||
if (errorUf2(uf2_check_block(ctx, block)))
|
||||
if (checkUf2Error(uf2_check_block(ctx, block)))
|
||||
// block is invalid
|
||||
return 0;
|
||||
|
||||
@@ -168,20 +185,24 @@ size_t UpdateClass::tryWriteData(uint8_t *data, size_t len) {
|
||||
|
||||
if (!bytesWritten) {
|
||||
// parse header block to allow retrieving firmware info
|
||||
if (errorUf2(uf2_parse_header(ctx, block, 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
|
||||
return errorArd(UPDATE_ERROR_SIZE);
|
||||
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 (errorUf2(uf2_write(ctx, block)))
|
||||
if (checkUf2Error(uf2_write(ctx, block)))
|
||||
// block writing failed
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <functional>
|
||||
|
||||
#include "uf2ota/uf2ota.h"
|
||||
#include <uf2ota/uf2ota.h>
|
||||
|
||||
// No Error
|
||||
#define UPDATE_ERROR_OK (0)
|
||||
@@ -76,10 +75,11 @@ class UpdateClass {
|
||||
const char *getBoardName();
|
||||
|
||||
private: /* UpdateUtil.cpp */
|
||||
void cleanup();
|
||||
bool errorUf2(uf2_err_t err);
|
||||
bool errorArd(uint8_t err);
|
||||
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();
|
||||
|
||||
@@ -118,8 +118,12 @@ class UpdateClass {
|
||||
return errUf2;
|
||||
}
|
||||
|
||||
uint16_t getErrorCode() {
|
||||
return (errArd << 8) | errUf2;
|
||||
}
|
||||
|
||||
void clearError() {
|
||||
errorUf2(UF2_ERR_OK);
|
||||
cleanup(UPDATE_ERROR_OK);
|
||||
}
|
||||
|
||||
bool hasError() {
|
||||
|
||||
@@ -30,7 +30,15 @@ UpdateClass &UpdateClass::onProgress(THandlerFunction_Progress callback) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
void UpdateClass::cleanup() {
|
||||
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
|
||||
@@ -40,8 +48,6 @@ void UpdateClass::cleanup() {
|
||||
|
||||
bytesWritten = 0;
|
||||
bytesTotal = 0;
|
||||
errUf2 = UF2_ERR_OK;
|
||||
errArd = UPDATE_ERROR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -51,33 +57,19 @@ void UpdateClass::cleanup() {
|
||||
* Use like: "if (errorUf2(...)) return false;"
|
||||
* @return true if err is not OK, false otherwise
|
||||
*/
|
||||
bool UpdateClass::errorUf2(uf2_err_t err) {
|
||||
bool UpdateClass::checkUf2Error(uf2_err_t err) {
|
||||
if (err <= UF2_ERR_IGNORE)
|
||||
return false;
|
||||
cleanup();
|
||||
errUf2 = err;
|
||||
errArd = errorMap[err];
|
||||
cleanup(errorMap[err], err);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set errUf2 and errArd according to given Arduino error code.
|
||||
* Abort the update.
|
||||
* Use like: "return errorArd(...);"
|
||||
* @return false - always
|
||||
*/
|
||||
bool UpdateClass::errorArd(uint8_t err) {
|
||||
cleanup();
|
||||
errUf2 = UF2_ERR_OK;
|
||||
errArd = err;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Abort the update with UPDATE_ERROR_ABORT reason.
|
||||
*/
|
||||
void UpdateClass::abort() {
|
||||
errorArd(UPDATE_ERROR_ABORT);
|
||||
LT_DM(OTA, "Aborting update");
|
||||
cleanup(UPDATE_ERROR_ABORT);
|
||||
}
|
||||
|
||||
void UpdateClass::bufAlloc() {
|
||||
@@ -100,12 +92,48 @@ 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)
|
||||
if (!errArd && !errUf2)
|
||||
return "";
|
||||
sprintf(errorStr, "ard=%u,uf2=%u", errArd, errUf2);
|
||||
return errorStr;
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-29. */
|
||||
|
||||
#include "uf2priv.h"
|
||||
|
||||
uf2_err_t uf2_binpatch(uint8_t *data, const uint8_t *binpatch, uint8_t binpatch_len) {
|
||||
const uint8_t *binpatch_end = binpatch + binpatch_len;
|
||||
// +2 to make sure opcode and length is present
|
||||
while ((binpatch + 2) < binpatch_end) {
|
||||
uf2_opcode_t opcode = binpatch[0];
|
||||
uint8_t len = binpatch[1];
|
||||
switch (opcode) {
|
||||
case UF2_OPC_DIFF32:
|
||||
uf2_binpatch_diff32(data, binpatch + 1);
|
||||
break;
|
||||
}
|
||||
// advance by opcode + length + data
|
||||
binpatch += len + 2;
|
||||
}
|
||||
return UF2_ERR_OK;
|
||||
}
|
||||
|
||||
void uf2_binpatch_diff32(uint8_t *data, const uint8_t *patch) {
|
||||
uint8_t num_offs = patch[0] - 4; // read offset count
|
||||
uint32_t diff = *((uint32_t *)(patch + 1)); // read diff value
|
||||
patch += 5; // skip num_offs and diff value
|
||||
for (uint8_t i = 0; i < num_offs; i++) {
|
||||
// patch the data
|
||||
uint8_t offs = patch[i];
|
||||
uint32_t *value = (uint32_t *)(data + offs);
|
||||
*(value) += diff;
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-29. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "uf2types.h"
|
||||
|
||||
/**
|
||||
* @brief Apply binary patch to data.
|
||||
*
|
||||
* @param data input data
|
||||
* @param data_len input data length
|
||||
* @param binpatch binary patch data
|
||||
* @param binpatch_len binary patch data length
|
||||
* @return uf2_err_t error code
|
||||
*/
|
||||
uf2_err_t uf2_binpatch(uint8_t *data, const uint8_t *binpatch, uint8_t binpatch_len);
|
||||
|
||||
/**
|
||||
* Apply DIFF32 binary patch.
|
||||
*
|
||||
* @param data input data
|
||||
* @param len input data length
|
||||
* @param patch patch data, incl. length byte
|
||||
* @return uf2_err_t error code
|
||||
*/
|
||||
void uf2_binpatch_diff32(uint8_t *data, const uint8_t *patch);
|
||||
@@ -1,100 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-29. */
|
||||
|
||||
#include "uf2priv.h"
|
||||
|
||||
uf2_ota_t *uf2_ctx_init(uint8_t ota_idx, uint32_t family_id) {
|
||||
uf2_ota_t *ctx = (uf2_ota_t *)zalloc(sizeof(uf2_ota_t));
|
||||
ctx->ota_idx = ota_idx;
|
||||
ctx->family_id = family_id;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
uf2_info_t *uf2_info_init() {
|
||||
uf2_info_t *info = (uf2_info_t *)zalloc(sizeof(uf2_info_t));
|
||||
return info;
|
||||
}
|
||||
|
||||
void uf2_info_free(uf2_info_t *info) {
|
||||
if (!info)
|
||||
return;
|
||||
free(info->fw_name);
|
||||
free(info->fw_version);
|
||||
free(info->lt_version);
|
||||
free(info->board);
|
||||
free(info);
|
||||
}
|
||||
|
||||
uf2_err_t uf2_check_block(uf2_ota_t *ctx, uf2_block_t *block) {
|
||||
if (block->magic1 != UF2_MAGIC_1)
|
||||
return UF2_ERR_MAGIC;
|
||||
if (block->magic2 != UF2_MAGIC_2)
|
||||
return UF2_ERR_MAGIC;
|
||||
if (block->magic3 != UF2_MAGIC_3)
|
||||
return UF2_ERR_MAGIC;
|
||||
if (block->file_container)
|
||||
// ignore file containers, for now
|
||||
return UF2_ERR_IGNORE;
|
||||
if (!block->has_family_id || block->file_size != ctx->family_id)
|
||||
// require family_id
|
||||
return UF2_ERR_FAMILY;
|
||||
return UF2_ERR_OK;
|
||||
}
|
||||
|
||||
uf2_err_t uf2_parse_header(uf2_ota_t *ctx, uf2_block_t *block, uf2_info_t *info) {
|
||||
if (!block->has_tags || block->file_container || block->len)
|
||||
// header must have tags and no data
|
||||
return UF2_ERR_NOT_HEADER;
|
||||
|
||||
uf2_err_t err = uf2_parse_block(ctx, block, info);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if ((ctx->ota_idx == 1 && !ctx->has_ota1) || !ctx->has_ota2)
|
||||
return UF2_ERR_OTA_WRONG;
|
||||
return UF2_ERR_OK;
|
||||
}
|
||||
|
||||
uf2_err_t uf2_write(uf2_ota_t *ctx, uf2_block_t *block) {
|
||||
if (ctx->seq == 0)
|
||||
return uf2_parse_header(ctx, block, NULL);
|
||||
if (block->not_main_flash || !block->len)
|
||||
// ignore blocks not meant for flashing
|
||||
return UF2_ERR_IGNORE;
|
||||
|
||||
uf2_err_t err = uf2_parse_block(ctx, block, NULL);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!ctx->part1 && !ctx->part2)
|
||||
// no partitions set at all
|
||||
return UF2_ERR_PART_UNSET;
|
||||
|
||||
fal_partition_t part = uf2_get_target_part(ctx);
|
||||
if (!part)
|
||||
// image is not for current OTA scheme
|
||||
return UF2_ERR_IGNORE;
|
||||
|
||||
if (ctx->ota_idx == 2 && ctx->binpatch_len) {
|
||||
// apply binpatch
|
||||
err = uf2_binpatch(block->data, ctx->binpatch, ctx->binpatch_len);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
int ret;
|
||||
// erase sectors if needed
|
||||
if (!uf2_is_erased(ctx, block->addr, block->len)) {
|
||||
ret = fal_partition_erase(part, block->addr, block->len);
|
||||
if (ret < 0)
|
||||
return UF2_ERR_ERASE_FAILED;
|
||||
ctx->erased_offset = block->addr;
|
||||
ctx->erased_length = ret;
|
||||
}
|
||||
// write data to flash
|
||||
ret = fal_partition_write(part, block->addr, block->data, block->len);
|
||||
if (ret < 0)
|
||||
return UF2_ERR_WRITE_FAILED;
|
||||
if (ret != block->len)
|
||||
return UF2_ERR_WRITE_LENGTH;
|
||||
return UF2_ERR_OK;
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-28. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#include "uf2types.h"
|
||||
|
||||
/**
|
||||
* @brief Create an UF2 OTA context.
|
||||
*
|
||||
* @param ota_idx target OTA index
|
||||
* @param family_id expected family ID
|
||||
* @return uf2_ota_t* heap-allocated structure
|
||||
*/
|
||||
uf2_ota_t *uf2_ctx_init(uint8_t ota_idx, uint32_t family_id);
|
||||
|
||||
/**
|
||||
* @brief Create an UF2 Info structure.
|
||||
*
|
||||
* @return uf2_info_t* heap-allocated structure
|
||||
*/
|
||||
uf2_info_t *uf2_info_init();
|
||||
|
||||
/**
|
||||
* @brief Free values in the info structure AND the structure itself.
|
||||
*
|
||||
* @param info structure to free; may be NULL
|
||||
*/
|
||||
void uf2_info_free(uf2_info_t *info);
|
||||
|
||||
/**
|
||||
* @brief Check if block is valid.
|
||||
*
|
||||
* @param ctx context
|
||||
* @param block block to check
|
||||
* @return uf2_err_t error code; UF2_ERR_OK and UF2_ERR_IGNORE denote valid blocks
|
||||
*/
|
||||
uf2_err_t uf2_check_block(uf2_ota_t *ctx, uf2_block_t *block);
|
||||
|
||||
/**
|
||||
* @brief Parse header block (LibreTuya UF2 first block).
|
||||
*
|
||||
* Note: caller should call uf2_check_block() first.
|
||||
*
|
||||
* @param ctx context
|
||||
* @param block block to parse
|
||||
* @param info structure to write firmware info, NULL if not used
|
||||
* @return uf2_err_t error code
|
||||
*/
|
||||
uf2_err_t uf2_parse_header(uf2_ota_t *ctx, uf2_block_t *block, uf2_info_t *info);
|
||||
|
||||
/**
|
||||
* @brief Write the block to flash memory.
|
||||
*
|
||||
* Note: caller should call uf2_check_block() first.
|
||||
*
|
||||
* @param ctx context
|
||||
* @param block block to write
|
||||
* @return uf2_err_t error code
|
||||
*/
|
||||
uf2_err_t uf2_write(uf2_ota_t *ctx, uf2_block_t *block);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
@@ -1,146 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-29. */
|
||||
|
||||
#include "uf2priv.h"
|
||||
|
||||
uf2_err_t uf2_parse_block(uf2_ota_t *ctx, uf2_block_t *block, uf2_info_t *info) {
|
||||
if (block->block_seq != ctx->seq)
|
||||
// sequence number must match
|
||||
return UF2_ERR_SEQ_MISMATCH;
|
||||
ctx->seq++; // increment sequence number after checking it
|
||||
|
||||
if (!block->has_tags)
|
||||
// no tags in this block, no further processing needed
|
||||
return UF2_ERR_OK;
|
||||
|
||||
if (block->len > (476 - 4 - 4))
|
||||
// at least one tag + last tag must fit
|
||||
return UF2_ERR_DATA_TOO_LONG;
|
||||
|
||||
uint8_t *tags_start = block->data + block->len;
|
||||
uint8_t tags_len = 476 - block->len;
|
||||
uint8_t tags_pos = 0;
|
||||
if (block->has_md5)
|
||||
tags_len -= 24;
|
||||
|
||||
ctx->binpatch_len = 0; // binpatch applies to one block only
|
||||
char *part1 = NULL;
|
||||
char *part2 = NULL;
|
||||
|
||||
uf2_tag_type_t type;
|
||||
while (tags_pos < tags_len) {
|
||||
uint8_t len = uf2_read_tag(tags_start + tags_pos, &type);
|
||||
if (!len)
|
||||
break;
|
||||
tags_pos += 4; // skip tag header
|
||||
uint8_t *tag = tags_start + tags_pos;
|
||||
|
||||
char **str_dest = NULL; // char* to copy the tag into
|
||||
|
||||
switch (type) {
|
||||
case UF2_TAG_OTA_VERSION:
|
||||
if (tag[0] != 1)
|
||||
return UF2_ERR_OTA_VER;
|
||||
break;
|
||||
case UF2_TAG_FIRMWARE:
|
||||
if (info)
|
||||
str_dest = &(info->fw_name);
|
||||
break;
|
||||
case UF2_TAG_VERSION:
|
||||
if (info)
|
||||
str_dest = &(info->fw_version);
|
||||
break;
|
||||
case UF2_TAG_LT_VERSION:
|
||||
if (info)
|
||||
str_dest = &(info->lt_version);
|
||||
break;
|
||||
case UF2_TAG_BOARD:
|
||||
if (info)
|
||||
str_dest = &(info->board);
|
||||
break;
|
||||
case UF2_TAG_HAS_OTA1:
|
||||
ctx->has_ota1 = tag[0];
|
||||
break;
|
||||
case UF2_TAG_HAS_OTA2:
|
||||
ctx->has_ota2 = tag[0];
|
||||
break;
|
||||
case UF2_TAG_PART_1:
|
||||
str_dest = &(part1);
|
||||
break;
|
||||
case UF2_TAG_PART_2:
|
||||
str_dest = &(part2);
|
||||
break;
|
||||
case UF2_TAG_BINPATCH:
|
||||
ctx->binpatch = tag;
|
||||
ctx->binpatch_len = len;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (str_dest) {
|
||||
*str_dest = (char *)zalloc(len + 1);
|
||||
memcpy(*str_dest, tag, len);
|
||||
}
|
||||
// align position to 4 bytes
|
||||
tags_pos += (((len - 1) / 4) + 1) * 4;
|
||||
}
|
||||
|
||||
if (part1 && part2) {
|
||||
// update current target partition
|
||||
uf2_err_t err = uf2_update_parts(ctx, part1, part2);
|
||||
if (err)
|
||||
return err;
|
||||
} else if (part1 || part2) {
|
||||
// only none or both partitions can be specified
|
||||
return UF2_ERR_PART_ONE;
|
||||
}
|
||||
|
||||
return UF2_ERR_OK;
|
||||
}
|
||||
|
||||
uint8_t uf2_read_tag(const uint8_t *data, uf2_tag_type_t *type) {
|
||||
uint8_t len = data[0];
|
||||
if (!len)
|
||||
return 0;
|
||||
uint32_t tag_type = *((uint32_t *)data);
|
||||
if (!tag_type)
|
||||
return 0;
|
||||
*type = tag_type >> 8; // remove tag length byte
|
||||
return len - 4;
|
||||
}
|
||||
|
||||
uf2_err_t uf2_update_parts(uf2_ota_t *ctx, char *part1, char *part2) {
|
||||
// reset both target partitions
|
||||
ctx->part1 = NULL;
|
||||
ctx->part2 = NULL;
|
||||
// reset offsets as they probably don't apply to this partition
|
||||
ctx->erased_offset = 0;
|
||||
ctx->erased_length = 0;
|
||||
|
||||
if (part1[0]) {
|
||||
ctx->part1 = (fal_partition_t)fal_partition_find(part1);
|
||||
if (!ctx->part1)
|
||||
return UF2_ERR_PART_404;
|
||||
}
|
||||
if (part2[0]) {
|
||||
ctx->part2 = (fal_partition_t)fal_partition_find(part2);
|
||||
if (!ctx->part2)
|
||||
return UF2_ERR_PART_404;
|
||||
}
|
||||
|
||||
return UF2_ERR_OK;
|
||||
}
|
||||
|
||||
fal_partition_t uf2_get_target_part(uf2_ota_t *ctx) {
|
||||
if (ctx->ota_idx == 1)
|
||||
return ctx->part1;
|
||||
if (ctx->ota_idx == 2)
|
||||
return ctx->part2;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool uf2_is_erased(uf2_ota_t *ctx, uint32_t offset, uint32_t length) {
|
||||
uint32_t erased_end = ctx->erased_offset + ctx->erased_length;
|
||||
uint32_t end = offset + length;
|
||||
return (offset >= ctx->erased_offset) && (end <= erased_end);
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-28. */
|
||||
|
||||
#pragma once
|
||||
|
||||
// include family stdlib APIs
|
||||
#include <WVariant.h>
|
||||
|
||||
#include "uf2binpatch.h"
|
||||
#include "uf2types.h"
|
||||
|
||||
/**
|
||||
* @brief Parse a block and extract information from tags.
|
||||
*
|
||||
* @param ctx context
|
||||
* @param block block to parse
|
||||
* @param info structure to write firmware info, NULL if not used
|
||||
* @return uf2_err_t error code
|
||||
*/
|
||||
uf2_err_t uf2_parse_block(uf2_ota_t *ctx, uf2_block_t *block, uf2_info_t *info);
|
||||
|
||||
/**
|
||||
* @brief Parse a tag.
|
||||
*
|
||||
* @param data pointer to tag header beginning
|
||||
* @param type [out] parsed tag type
|
||||
* @return uint8_t parsed tag data length (excl. header); 0 if invalid/last tag
|
||||
*/
|
||||
uint8_t uf2_read_tag(const uint8_t *data, uf2_tag_type_t *type);
|
||||
|
||||
/**
|
||||
* @brief Update destination partitions in context.
|
||||
*
|
||||
* Partition names cannot be NULL.
|
||||
*
|
||||
* Returns UF2_ERR_IGNORE if specified partitions don't match the
|
||||
* current OTA index.
|
||||
*
|
||||
* @param ctx context
|
||||
* @param part1 partition 1 name or empty string
|
||||
* @param part2 partition 2 name or empty string
|
||||
* @return uf2_err_t error code
|
||||
*/
|
||||
uf2_err_t uf2_update_parts(uf2_ota_t *ctx, char *part1, char *part2);
|
||||
|
||||
/**
|
||||
* @brief Get target flashing partition, depending on OTA index.
|
||||
*
|
||||
* @param ctx context
|
||||
* @return fal_partition_t target partition or NULL if not set
|
||||
*/
|
||||
fal_partition_t uf2_get_target_part(uf2_ota_t *ctx);
|
||||
|
||||
/**
|
||||
* Check if specified flash memory region was already erased during update.
|
||||
*
|
||||
* @param ctx context
|
||||
* @param offset offset to check
|
||||
* @param length length to check
|
||||
* @return bool true/false
|
||||
*/
|
||||
bool uf2_is_erased(uf2_ota_t *ctx, uint32_t offset, uint32_t length);
|
||||
@@ -1,104 +0,0 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-28. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <fal.h>
|
||||
|
||||
#define UF2_MAGIC_1 0x0A324655
|
||||
#define UF2_MAGIC_2 0x9E5D5157
|
||||
#define UF2_MAGIC_3 0x0AB16F30
|
||||
|
||||
#define UF2_BLOCK_SIZE sizeof(uf2_block_t)
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
// 32 byte header
|
||||
uint32_t magic1;
|
||||
uint32_t magic2;
|
||||
|
||||
// flags split as bitfields
|
||||
bool not_main_flash : 1;
|
||||
uint16_t dummy1 : 11;
|
||||
bool file_container : 1;
|
||||
bool has_family_id : 1;
|
||||
bool has_md5 : 1;
|
||||
bool has_tags : 1;
|
||||
uint16_t dummy2 : 16;
|
||||
|
||||
uint32_t addr;
|
||||
uint32_t len;
|
||||
uint32_t block_seq;
|
||||
uint32_t block_count;
|
||||
uint32_t file_size; // or familyID;
|
||||
uint8_t data[476];
|
||||
uint32_t magic3;
|
||||
} uf2_block_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t seq; // current block sequence number
|
||||
|
||||
uint8_t *binpatch; // current block's binpatch (if any) -> pointer inside block->data
|
||||
uint8_t binpatch_len; // binpatch length
|
||||
|
||||
bool has_ota1; // image has any data for OTA1
|
||||
bool has_ota2; // image has any data for OTA2
|
||||
|
||||
uint8_t ota_idx; // target OTA index
|
||||
uint32_t family_id; // expected family ID
|
||||
|
||||
uint32_t erased_offset; // offset of region erased during update
|
||||
uint32_t erased_length; // length of erased region
|
||||
|
||||
fal_partition_t part1; // OTA1 target partition
|
||||
fal_partition_t part2; // OTA2 target partition
|
||||
} uf2_ota_t;
|
||||
|
||||
typedef struct {
|
||||
char *fw_name;
|
||||
char *fw_version;
|
||||
char *lt_version;
|
||||
char *board;
|
||||
} uf2_info_t;
|
||||
|
||||
typedef enum {
|
||||
UF2_TAG_VERSION = 0x9FC7BC, // version of firmware file - UTF8 semver string
|
||||
UF2_TAG_PAGE_SIZE = 0x0BE9F7, // page size of target device (32 bit unsigned number)
|
||||
UF2_TAG_SHA2 = 0xB46DB0, // SHA-2 checksum of firmware (can be of various size)
|
||||
UF2_TAG_DEVICE = 0x650D9D, // description of device (UTF8)
|
||||
UF2_TAG_DEVICE_ID = 0xC8A729, // device type identifier
|
||||
// LibreTuya custom, tags
|
||||
UF2_TAG_OTA_VERSION = 0x5D57D0, // format version
|
||||
UF2_TAG_BOARD = 0xCA25C8, // board name (lowercase code)
|
||||
UF2_TAG_FIRMWARE = 0x00DE43, // firmware description / name
|
||||
UF2_TAG_BUILD_DATE = 0x822F30, // build date/time as Unix timestamp
|
||||
UF2_TAG_LT_VERSION = 0x59563D, // LT version (semver)
|
||||
UF2_TAG_PART_1 = 0x805946, // OTA1 partition name
|
||||
UF2_TAG_PART_2 = 0xA1E4D7, // OTA2 partition name
|
||||
UF2_TAG_HAS_OTA1 = 0xBBD965, // image has any data for OTA1
|
||||
UF2_TAG_HAS_OTA2 = 0x92280E, // image has any data for OTA2
|
||||
UF2_TAG_BINPATCH = 0xB948DE, // binary patch to convert OTA1->OTA2
|
||||
} uf2_tag_type_t;
|
||||
|
||||
typedef enum {
|
||||
UF2_OPC_DIFF32 = 0xFE,
|
||||
} uf2_opcode_t;
|
||||
|
||||
typedef enum {
|
||||
UF2_ERR_OK = 0,
|
||||
UF2_ERR_IGNORE, // block should be ignored
|
||||
UF2_ERR_MAGIC, // wrong magic numbers
|
||||
UF2_ERR_FAMILY, // family ID mismatched
|
||||
UF2_ERR_NOT_HEADER, // block is not a header
|
||||
UF2_ERR_OTA_VER, // unknown/invalid OTA format version
|
||||
UF2_ERR_OTA_WRONG, // no data for current OTA index
|
||||
UF2_ERR_PART_404, // no partition with that name
|
||||
UF2_ERR_PART_ONE, // only one partition tag in a block
|
||||
UF2_ERR_PART_UNSET, // image broken - attempted to write without target partition
|
||||
UF2_ERR_DATA_TOO_LONG, // data too long - tags won't fit
|
||||
UF2_ERR_SEQ_MISMATCH, // sequence number mismatched
|
||||
UF2_ERR_ERASE_FAILED, // erasing flash failed
|
||||
UF2_ERR_WRITE_FAILED, // writing to flash failed
|
||||
UF2_ERR_WRITE_LENGTH, // wrote fewer data than requested
|
||||
} uf2_err_t;
|
||||
@@ -50,27 +50,27 @@ bool WiFiMulti::addAP(const char *ssid, const char *passphrase) {
|
||||
|
||||
if (!ssid || *ssid == 0x00 || strlen(ssid) > 31) {
|
||||
// fail SSID too long or missing!
|
||||
LT_E("SSID missing or too long");
|
||||
LT_EM(WIFI, "SSID missing or too long");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (passphrase && strlen(passphrase) > 64) {
|
||||
// fail passphrase too long!
|
||||
LT_E("Passphrase too long");
|
||||
LT_EM(WIFI, "Passphrase too long");
|
||||
return false;
|
||||
}
|
||||
|
||||
newAP.ssid = strdup(ssid);
|
||||
|
||||
if (!newAP.ssid) {
|
||||
LT_E("Fail newAP.ssid == 0");
|
||||
LT_EM(WIFI, "Fail newAP.ssid == 0");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (passphrase && *passphrase != 0x00) {
|
||||
newAP.passphrase = strdup(passphrase);
|
||||
if (!newAP.passphrase) {
|
||||
LT_E("Fail newAP.passphrase == 0");
|
||||
LT_EM(WIFI, "Fail newAP.passphrase == 0");
|
||||
free(newAP.ssid);
|
||||
return false;
|
||||
}
|
||||
@@ -79,7 +79,7 @@ bool WiFiMulti::addAP(const char *ssid, const char *passphrase) {
|
||||
}
|
||||
|
||||
APlist.push_back(newAP);
|
||||
LT_V("Add SSID: %s", newAP.ssid);
|
||||
LT_VM(WIFI, "Add SSID: %s", newAP.ssid);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -108,12 +108,12 @@ uint8_t WiFiMulti::run(uint32_t connectTimeout) {
|
||||
uint8_t bestBSSID[6];
|
||||
int32_t bestChannel = 0;
|
||||
|
||||
LT_I("Scan finished");
|
||||
LT_IM(WIFI, "Scan finished");
|
||||
|
||||
if (scanResult == 0) {
|
||||
LT_I("No networks found");
|
||||
LT_IM(WIFI, "No networks found");
|
||||
} else {
|
||||
LT_I("%d networks found", scanResult);
|
||||
LT_IM(WIFI, "%d networks found", scanResult);
|
||||
for (int8_t i = 0; i < scanResult; ++i) {
|
||||
|
||||
String ssid_scan;
|
||||
@@ -144,7 +144,8 @@ uint8_t WiFiMulti::run(uint32_t connectTimeout) {
|
||||
}
|
||||
|
||||
if (known) {
|
||||
LT_D(
|
||||
LT_DM(
|
||||
WIFI,
|
||||
" ---> %d: [%d][%02X:%02X:%02X:%02X:%02X:%02X] %s (%d) %c",
|
||||
i,
|
||||
chan_scan,
|
||||
@@ -159,7 +160,8 @@ uint8_t WiFiMulti::run(uint32_t connectTimeout) {
|
||||
(sec_scan == WIFI_AUTH_OPEN) ? ' ' : '*'
|
||||
);
|
||||
} else {
|
||||
LT_D(
|
||||
LT_DM(
|
||||
WIFI,
|
||||
" %d: [%d][%02X:%02X:%02X:%02X:%02X:%02X] %s (%d) %c",
|
||||
i,
|
||||
chan_scan,
|
||||
@@ -181,7 +183,8 @@ uint8_t WiFiMulti::run(uint32_t connectTimeout) {
|
||||
WiFi.scanDelete();
|
||||
|
||||
if (bestNetwork.ssid) {
|
||||
LT_I(
|
||||
LT_IM(
|
||||
WIFI,
|
||||
"Connecting to BSSID: %02X:%02X:%02X:%02X:%02X:%02X SSID: %s Channel: %d (%d)",
|
||||
bestBSSID[0],
|
||||
bestBSSID[1],
|
||||
@@ -208,33 +211,33 @@ uint8_t WiFiMulti::run(uint32_t connectTimeout) {
|
||||
IPAddress ip;
|
||||
switch (status) {
|
||||
case WL_CONNECTED:
|
||||
LT_I("Connecting done");
|
||||
LT_D("SSID: %s", WiFi.SSID().c_str());
|
||||
LT_IM(WIFI, "Connecting done");
|
||||
LT_DM(WIFI, "SSID: %s", WiFi.SSID().c_str());
|
||||
// TODO fix this after implementing IP format for printf()
|
||||
ip = WiFi.localIP();
|
||||
LT_D("IP: %u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
|
||||
LT_D("MAC: %s", WiFi.BSSIDstr().c_str());
|
||||
LT_D("Channel: %d", WiFi.channel());
|
||||
LT_DM(WIFI, "IP: %u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
|
||||
LT_DM(WIFI, "MAC: %s", WiFi.BSSIDstr().c_str());
|
||||
LT_DM(WIFI, "Channel: %d", WiFi.channel());
|
||||
break;
|
||||
case WL_NO_SSID_AVAIL:
|
||||
LT_E("Connecting failed; AP not found");
|
||||
LT_EM(WIFI, "Connecting failed; AP not found");
|
||||
break;
|
||||
case WL_CONNECT_FAILED:
|
||||
LT_E("Connecting failed");
|
||||
LT_EM(WIFI, "Connecting failed");
|
||||
break;
|
||||
default:
|
||||
LT_E("Connecting failed (%d)", status);
|
||||
LT_EM(WIFI, "Connecting failed (%d)", status);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
LT_E("No matching network found!");
|
||||
LT_EM(WIFI, "No matching network found!");
|
||||
}
|
||||
} else {
|
||||
// start scan
|
||||
LT_V("Delete old wifi config...");
|
||||
LT_VM(WIFI, "Delete old wifi config...");
|
||||
WiFi.disconnect();
|
||||
|
||||
LT_D("Start scan");
|
||||
LT_DM(WIFI, "Start scan");
|
||||
// scan wifi async mode
|
||||
WiFi.scanNetworks(true);
|
||||
}
|
||||
|
||||
@@ -3,70 +3,66 @@
|
||||
#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 u8_t mdns_netif_client_id = 0; // TODO fix this
|
||||
|
||||
struct mdns_domain {
|
||||
/* Encoded domain name */
|
||||
u8_t name[256];
|
||||
/* Total length of domain name, including zero */
|
||||
u16_t length;
|
||||
/* Set if compression of this domain is not allowed */
|
||||
u8_t skip_compression;
|
||||
};
|
||||
|
||||
/** Description of a service */
|
||||
struct mdns_service {
|
||||
/** TXT record to answer with */
|
||||
struct mdns_domain txtdata;
|
||||
/** Name of service, like 'myweb' */
|
||||
char name[MDNS_LABEL_MAXLEN + 1];
|
||||
/** Type of service, like '_http' */
|
||||
char service[MDNS_LABEL_MAXLEN + 1];
|
||||
/** Callback function and userdata
|
||||
* to update txtdata buffer */
|
||||
service_get_txt_fn_t txt_fn;
|
||||
void *txt_userdata;
|
||||
/** TTL in seconds of SRV/TXT replies */
|
||||
u32_t dns_ttl;
|
||||
/** Protocol, TCP or UDP */
|
||||
u16_t proto;
|
||||
/** Port of the service */
|
||||
u16_t port;
|
||||
};
|
||||
|
||||
/** Description of a host/netif */
|
||||
struct mdns_host {
|
||||
/** Hostname */
|
||||
char name[MDNS_LABEL_MAXLEN + 1];
|
||||
/** Pointer to services */
|
||||
struct mdns_service *services[MDNS_MAX_SERVICES];
|
||||
/** TTL in seconds of A/AAAA/PTR replies */
|
||||
u32_t dns_ttl;
|
||||
};
|
||||
|
||||
static String mdnsInstanceName = "default_instance";
|
||||
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();
|
||||
struct netif *netif = netif_list;
|
||||
uint8_t enabled = 0;
|
||||
while (netif != NULL) {
|
||||
// TODO: detect mdns_netif_client_id by checking netif_get_client_data()
|
||||
// and finding the requested hostname in struct mdns_host
|
||||
if (netif_is_up(netif) && mdns_resp_add_netif(netif, hostname, 255) == ERR_OK) {
|
||||
enabled++;
|
||||
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);
|
||||
}
|
||||
netif = netif->next;
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -80,72 +76,53 @@ void mDNS::end() {
|
||||
}
|
||||
}
|
||||
|
||||
void mDNS::setInstanceName(String name) {
|
||||
mdnsInstanceName = name;
|
||||
}
|
||||
|
||||
bool mDNS::addService(char *service, char *proto, uint16_t port) {
|
||||
char _service[strlen(service) + 2];
|
||||
char _proto[strlen(proto) + 2];
|
||||
_service[0] = '_';
|
||||
_proto[0] = '_';
|
||||
// prepend names with _
|
||||
strcpy(_service + 1, service + (service[0] == '_'));
|
||||
strcpy(_proto + 1, proto + (proto[0] == '_'));
|
||||
|
||||
mdns_sd_proto protocol = DNSSD_PROTO_UDP;
|
||||
if (strncmp(_proto + 1, "tcp", 3) == 0)
|
||||
protocol = DNSSD_PROTO_TCP;
|
||||
|
||||
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)) {
|
||||
mdns_resp_add_service(netif, mdnsInstanceName.c_str(), service, protocol, port, 255, NULL, NULL);
|
||||
// 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::addServiceTxt(char *name, char *proto, char *key, char *value) {
|
||||
char _name[strlen(name) + 2];
|
||||
char _proto[strlen(proto) + 2];
|
||||
_name[0] = '_';
|
||||
_proto[0] = '_';
|
||||
// prepend names with _
|
||||
strcpy(_name + 1, name + (name[0] == '_'));
|
||||
strcpy(_proto + 1, proto + (proto[0] == '_'));
|
||||
|
||||
mdns_sd_proto protocol = DNSSD_PROTO_UDP;
|
||||
if (strncmp(_proto + 1, "tcp", 3) == 0)
|
||||
protocol = DNSSD_PROTO_TCP;
|
||||
|
||||
struct netif *netif = netif_list;
|
||||
struct mdns_host *mdns;
|
||||
struct mdns_service *service;
|
||||
|
||||
uint8_t txt_len = strlen(key) + strlen(value) + 1;
|
||||
char *txt = (char *)malloc(txt_len + 1);
|
||||
sprintf(txt, "%s=%s", key, value);
|
||||
|
||||
while (netif != NULL) {
|
||||
if (netif_is_up(netif)) {
|
||||
mdns = (struct mdns_host *)netif_get_client_data(netif, mdns_netif_client_id);
|
||||
|
||||
for (uint8_t i = 0; i < MDNS_MAX_SERVICES; i++) {
|
||||
service = mdns->services[i];
|
||||
if (service == NULL)
|
||||
continue;
|
||||
if (strcmp(service->service, _name) || service->proto != protocol)
|
||||
continue;
|
||||
if (mdns_resp_add_service_txtitem(service, txt, txt_len) != ERR_OK) {
|
||||
free(txt);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
netif = netif->next;
|
||||
}
|
||||
free(txt);
|
||||
if (index == -1)
|
||||
return false;
|
||||
|
||||
records[index].push_back(strdup(item));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
40
arduino/libretuya/libraries/mDNS/mDNS.cpp
Normal file
40
arduino/libretuya/libraries/mDNS/mDNS.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-08-26. */
|
||||
|
||||
#include "mDNS.h"
|
||||
|
||||
static char *ensureUnderscore(const char *value) {
|
||||
uint8_t len = strlen(value) + 1;
|
||||
char *result = (char *)malloc(len);
|
||||
result[0] = '_';
|
||||
strcpy(result + 1, value + (value[0] == '_'));
|
||||
return result;
|
||||
}
|
||||
|
||||
void mDNS::setInstanceName(const char *name) {
|
||||
if (instanceName)
|
||||
free(instanceName);
|
||||
instanceName = strdup(name);
|
||||
}
|
||||
|
||||
bool mDNS::addService(char *service, char *proto, uint16_t port) {
|
||||
char *_service = ensureUnderscore(service);
|
||||
uint8_t _proto = strncmp(proto + (proto[0] == '_'), "tcp", 3) == 0 ? MDNS_TCP : MDNS_UDP;
|
||||
|
||||
bool result = addServiceImpl(instanceName ? instanceName : "LT mDNS", _service, _proto, port);
|
||||
free(_service);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool mDNS::addServiceTxt(char *service, char *proto, char *key, char *value) {
|
||||
char *_service = ensureUnderscore(service);
|
||||
uint8_t _proto = strncmp(proto + (proto[0] == '_'), "tcp", 3) == 0 ? MDNS_TCP : MDNS_UDP;
|
||||
|
||||
uint8_t txt_len = strlen(key) + strlen(value) + 1;
|
||||
char *txt = (char *)malloc(txt_len + 1);
|
||||
sprintf(txt, "%s=%s", key, value);
|
||||
|
||||
bool result = addServiceTxtImpl(_service, _proto, txt);
|
||||
free(_service);
|
||||
free(txt);
|
||||
return result;
|
||||
}
|
||||
@@ -44,7 +44,16 @@ License (MIT license):
|
||||
#include <Arduino.h>
|
||||
#include <api/IPv6Address.h>
|
||||
|
||||
#define MDNS_UDP 0
|
||||
#define MDNS_TCP 1
|
||||
|
||||
class mDNS {
|
||||
private:
|
||||
bool addServiceImpl(const char *name, const char *service, uint8_t proto, uint16_t port);
|
||||
bool addServiceTxtImpl(const char *service, uint8_t proto, const char *item);
|
||||
|
||||
char *instanceName = NULL;
|
||||
|
||||
public:
|
||||
mDNS();
|
||||
~mDNS();
|
||||
@@ -52,9 +61,9 @@ class mDNS {
|
||||
bool begin(const char *hostname);
|
||||
void end();
|
||||
|
||||
void setInstanceName(String name);
|
||||
void setInstanceName(const char *name);
|
||||
bool addService(char *service, char *proto, uint16_t port);
|
||||
bool addServiceTxt(char *name, char *proto, char *key, char *value);
|
||||
bool addServiceTxt(char *service, char *proto, char *key, char *value);
|
||||
// void enableArduino(uint16_t port = 3232, bool auth = false);
|
||||
// void disableArduino();
|
||||
// void enableWorkstation(esp_interface_t interface = ESP_IF_WIFI_STA);
|
||||
@@ -73,12 +82,12 @@ class mDNS {
|
||||
String txt(int idx, int txtIdx);
|
||||
String txtKey(int idx, int txtIdx);
|
||||
|
||||
void setInstanceName(const char *name) {
|
||||
setInstanceName(String(name));
|
||||
void setInstanceName(String name) {
|
||||
setInstanceName(name.c_str());
|
||||
}
|
||||
|
||||
void setInstanceName(char *name) {
|
||||
setInstanceName(String(name));
|
||||
setInstanceName((const char *)name);
|
||||
}
|
||||
|
||||
bool addService(const char *service, const char *proto, uint16_t port) {
|
||||
@@ -89,12 +98,12 @@ class mDNS {
|
||||
return addService(service.c_str(), proto.c_str(), port);
|
||||
}
|
||||
|
||||
void addServiceTxt(const char *name, const char *proto, const char *key, const char *value) {
|
||||
addServiceTxt((char *)name, (char *)proto, (char *)key, (char *)value);
|
||||
void addServiceTxt(const char *service, const char *proto, const char *key, const char *value) {
|
||||
addServiceTxt((char *)service, (char *)proto, (char *)key, (char *)value);
|
||||
}
|
||||
|
||||
void addServiceTxt(String name, String proto, String key, String value) {
|
||||
addServiceTxt(name.c_str(), proto.c_str(), key.c_str(), value.c_str());
|
||||
void addServiceTxt(String service, String proto, String key, String value) {
|
||||
addServiceTxt(service.c_str(), proto.c_str(), key.c_str(), value.c_str());
|
||||
}
|
||||
|
||||
IPAddress queryHost(const char *host, uint32_t timeout = 2000) {
|
||||
|
||||
@@ -36,10 +36,14 @@
|
||||
/* MCU Endian Configuration, default is Little Endian Order. */
|
||||
// #define FDB_BIG_ENDIAN
|
||||
|
||||
/* log print macro. default EF_PRINT macro is printf() */
|
||||
#define FDB_PRINT(...)
|
||||
#include <printf_config.h>
|
||||
|
||||
/* print debug information */
|
||||
// #define FDB_DEBUG_ENABLE
|
||||
#if LT_DEBUG_FDB
|
||||
#include <printf/printf.h>
|
||||
#define FDB_PRINT(...) __wrap_printf(__VA_ARGS__)
|
||||
#define FDB_DEBUG_ENABLE
|
||||
#else
|
||||
#define FDB_PRINT(...)
|
||||
#endif
|
||||
|
||||
#endif /* _FDB_CFG_H_ */
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibreTuyaConfig.h>
|
||||
|
||||
#define PRINTF_HAS_DISABLE 1
|
||||
|
||||
// make printf.c define wrapper functions
|
||||
@@ -12,12 +14,33 @@
|
||||
#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() { \
|
||||
@@ -39,6 +62,24 @@
|
||||
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, ...) { \
|
||||
@@ -50,6 +91,15 @@
|
||||
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; \
|
||||
@@ -68,13 +118,6 @@
|
||||
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); \
|
||||
}
|
||||
|
||||
#define WRAP_VSPRINTF(name) \
|
||||
int __wrap_##name(char *s, const char *format, va_list arg) { \
|
||||
return vsprintf(s, format, arg); \
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-16. */
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
extern char *strdup(const char *);
|
||||
extern int strcasecmp(const char *s1, const char *s2);
|
||||
extern int strncasecmp(const char *s1, const char *s2, size_t n);
|
||||
|
||||
50
arduino/libretuya/posix/time.c
Normal file
50
arduino/libretuya/posix/time.c
Normal file
@@ -0,0 +1,50 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-09-03. */
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <errno.h>
|
||||
|
||||
static uint32_t reset_epoch = 0; // epoch corresponding to millis() == 0
|
||||
static uint32_t reset_millis = 0; // millis() when epoch reset was performed
|
||||
|
||||
int __wrap_gettimeofday(struct timeval *tv, void *tz) {
|
||||
if (millis() < reset_millis) {
|
||||
// the clock overflowed
|
||||
reset_epoch += UINT32_MAX / 1000;
|
||||
reset_millis = millis();
|
||||
}
|
||||
if (!tv) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
unsigned long m = millis();
|
||||
tv->tv_sec = reset_epoch + (m / 1000);
|
||||
tv->tv_usec = (m % 1000) * 1000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __wrap_settimeofday(const struct timeval *tv, const struct timezone *tz) {
|
||||
if (!tv) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
unsigned long m = millis();
|
||||
reset_epoch = tv->tv_sec - (m / 1000);
|
||||
reset_millis = m;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gettimeofday(struct timeval *tv, void *tz) {
|
||||
return __wrap_gettimeofday(tv, tz);
|
||||
}
|
||||
|
||||
int settimeofday(const struct timeval *tv, const struct timezone *tz) {
|
||||
return __wrap_settimeofday(tv, tz);
|
||||
}
|
||||
|
||||
int _gettimeofday(struct timeval *tv, void *tz) {
|
||||
return __wrap_gettimeofday(tv, tz);
|
||||
}
|
||||
|
||||
int _settimeofday(const struct timeval *tv, const struct timezone *tz) {
|
||||
return __wrap_settimeofday(tv, tz);
|
||||
}
|
||||
@@ -16,7 +16,19 @@
|
||||
// Include board variant
|
||||
#include "variant.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include "LOGUARTClass.h"
|
||||
extern LOGUARTClass Serial;
|
||||
// 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,98 +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 "LOGUARTClass.h"
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#define LOG_UART_MODIFIABLE_BAUD_RATE 1
|
||||
|
||||
RingBuffer rx_buffer0;
|
||||
|
||||
LOGUARTClass::LOGUARTClass(int dwIrq, RingBuffer *pRx_buffer) {
|
||||
_rx_buffer = pRx_buffer;
|
||||
_dwIrq = dwIrq;
|
||||
}
|
||||
|
||||
void IrqHandler(void) {
|
||||
uint8_t data = 0;
|
||||
BOOL PullMode = _FALSE;
|
||||
uint32_t IrqEn = DiagGetIsrEnReg();
|
||||
|
||||
DiagSetIsrEnReg(0);
|
||||
|
||||
data = DiagGetChar(PullMode);
|
||||
if (data > 0)
|
||||
rx_buffer0.store_char(data);
|
||||
|
||||
DiagSetIsrEnReg(IrqEn);
|
||||
}
|
||||
|
||||
void LOGUARTClass::begin(const uint32_t dwBaudRate) {
|
||||
DIAG_UartReInit((IRQ_FUN)IrqHandler);
|
||||
NVIC_SetPriority(UART_LOG_IRQ, 10);
|
||||
LOGUART_SetBaud(dwBaudRate);
|
||||
}
|
||||
|
||||
void LOGUARTClass::end(void) {
|
||||
// clear any received data
|
||||
_rx_buffer->_iHead = _rx_buffer->_iTail;
|
||||
}
|
||||
|
||||
int LOGUARTClass::available(void) {
|
||||
return (uint32_t)(SERIAL_BUFFER_SIZE + _rx_buffer->_iHead - _rx_buffer->_iTail) % SERIAL_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
int LOGUARTClass::peek(void) {
|
||||
|
||||
if (_rx_buffer->_iHead == _rx_buffer->_iTail)
|
||||
return -1;
|
||||
|
||||
return _rx_buffer->_aucBuffer[_rx_buffer->_iTail];
|
||||
}
|
||||
|
||||
int LOGUARTClass::read(void) {
|
||||
// if the head isn't ahead of the tail, we don't have any characters
|
||||
if (_rx_buffer->_iHead == _rx_buffer->_iTail)
|
||||
return -1;
|
||||
|
||||
uint8_t uc = _rx_buffer->_aucBuffer[_rx_buffer->_iTail];
|
||||
_rx_buffer->_iTail = (unsigned int)(_rx_buffer->_iTail + 1) % SERIAL_BUFFER_SIZE;
|
||||
return uc;
|
||||
}
|
||||
|
||||
void LOGUARTClass::flush(void) {
|
||||
// TODO:
|
||||
// while ( serial_writable(&(this->sobj)) != 1 );
|
||||
/*
|
||||
// Wait for transmission to complete
|
||||
while ((_pUart->UART_SR & UART_SR_TXRDY) != UART_SR_TXRDY)
|
||||
;
|
||||
*/
|
||||
}
|
||||
|
||||
size_t LOGUARTClass::write(const uint8_t uc_data) {
|
||||
DiagPutChar(uc_data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
LOGUARTClass Serial(UART_LOG_IRQ, &rx_buffer0);
|
||||
|
||||
bool Serial_available() {
|
||||
return Serial.available() > 0;
|
||||
}
|
||||
@@ -1,58 +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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <api/HardwareSerial.h>
|
||||
#include <api/RingBuffer.h>
|
||||
|
||||
using namespace arduino;
|
||||
|
||||
// TODO this class begs to be rewritten :(
|
||||
|
||||
class LOGUARTClass : public HardwareSerial {
|
||||
public:
|
||||
LOGUARTClass(int dwIrq, RingBuffer *pRx_buffer);
|
||||
|
||||
void begin(const uint32_t dwBaudRate);
|
||||
|
||||
inline void begin(const uint32_t dwBaudRate, uint16_t config) {
|
||||
begin(dwBaudRate); // TODO implement this properly
|
||||
}
|
||||
|
||||
void end(void);
|
||||
int available(void);
|
||||
int peek(void);
|
||||
int read(void);
|
||||
void flush(void);
|
||||
size_t write(const uint8_t c);
|
||||
|
||||
using Print::write; // pull in write(str) and write(buf, size) from Print
|
||||
|
||||
operator bool() {
|
||||
return true; // UART always active
|
||||
}
|
||||
|
||||
protected:
|
||||
RingBuffer *_rx_buffer;
|
||||
|
||||
int _dwIrq;
|
||||
|
||||
private:
|
||||
friend bool Serial_available();
|
||||
};
|
||||
@@ -6,10 +6,25 @@ 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() {
|
||||
@@ -24,7 +39,7 @@ void LibreTuya::gpioRecover() {
|
||||
ChipType LibreTuya::getChipType() {
|
||||
uint8_t chipId;
|
||||
EFUSE_OneByteReadROM(9902, 0xF8, &chipId, L25EOUTVOLTAGE);
|
||||
return CHIP_TYPE_ENUM(F_RTL8710B, chipId);
|
||||
return CHIP_TYPE_ENUM(FAMILY, chipId);
|
||||
}
|
||||
|
||||
const char *LibreTuya::getChipModel() {
|
||||
@@ -43,6 +58,7 @@ uint32_t LibreTuya::getChipId() {
|
||||
// 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;
|
||||
}
|
||||
|
||||
@@ -98,6 +114,13 @@ uint32_t LibreTuya::getMaxAllocHeap() {
|
||||
|
||||
/* 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)
|
||||
@@ -164,6 +187,22 @@ bool LibreTuya::otaSwitch(bool force) {
|
||||
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;
|
||||
|
||||
98
arduino/realtek-ambz/cores/arduino/SerialClass.cpp
Normal file
98
arduino/realtek-ambz/cores/arduino/SerialClass.cpp
Normal file
@@ -0,0 +1,98 @@
|
||||
/* 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;
|
||||
}
|
||||
46
arduino/realtek-ambz/cores/arduino/SerialClass.h
Normal file
46
arduino/realtek-ambz/cores/arduino/SerialClass.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/* 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
|
||||
@@ -10,9 +10,9 @@ static void *gpio_irq_handler_args[PINS_COUNT] = {NULL};
|
||||
extern bool pinInvalid(pin_size_t pinNumber);
|
||||
extern void pinRemoveMode(pin_size_t pinNumber);
|
||||
|
||||
void gpioIrqHandler(uint32_t id, gpio_irq_event event) {
|
||||
static void gpioIrqHandler(uint32_t id, gpio_irq_event event) {
|
||||
if (gpio_irq_handler_list[id] != NULL) {
|
||||
if (gpio_irq_handler_args[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]);
|
||||
|
||||
@@ -1,42 +1,30 @@
|
||||
/*
|
||||
main.cpp - Main loop for Arduino sketches
|
||||
Copyright (c) 2005-2013 Arduino Team. 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
|
||||
*/
|
||||
|
||||
#define ARDUINO_MAIN
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-06-19. */
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <cmsis_os.h>
|
||||
|
||||
osThreadId main_tid = 0;
|
||||
extern "C" {
|
||||
|
||||
#include <cmsis_os.h>
|
||||
|
||||
extern uint32_t GlobalDebugEnable;
|
||||
extern uint16_t GlobalDebugLevel;
|
||||
extern uint8_t GlobalPrivateLog;
|
||||
extern uint8_t lt_uart_port;
|
||||
|
||||
void init() {
|
||||
} // extern "C"
|
||||
|
||||
osThreadId main_tid = 0;
|
||||
|
||||
void initArduino() {
|
||||
// make the SDK less verbose by default
|
||||
GlobalDebugEnable = 0;
|
||||
GlobalPrivateLog = 0;
|
||||
lt_uart_port = LT_UART_DEFAULT_PORT;
|
||||
}
|
||||
|
||||
bool startMainTask() {
|
||||
osThreadDef(main_task, osPriorityRealtime, 1, 4096 * 4);
|
||||
main_tid = osThreadCreate(osThread(main_task), NULL);
|
||||
osThreadDef(mainTask, osPriorityRealtime, 1, 4096 * 4);
|
||||
main_tid = osThreadCreate(osThread(mainTask), NULL);
|
||||
osKernelStart();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-07-03. */
|
||||
|
||||
#include "SoftwareSerial.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
#include <timer_api.h>
|
||||
|
||||
} // extern "C"
|
||||
|
||||
#define TIMER_MAX 3
|
||||
#define OBJ ((gtimer_t *)this->param)
|
||||
|
||||
static uint32_t timNum[TIMER_MAX] = {TIMER1, TIMER2, TIMER3};
|
||||
static gtimer_t *timObj[TIMER_MAX] = {NULL, NULL, NULL};
|
||||
|
||||
static void callback(SoftSerial *data) {
|
||||
SoftData *tx = &data->tx;
|
||||
|
||||
switch (tx->state) {
|
||||
case SS_IDLE:
|
||||
goto finish;
|
||||
|
||||
case SS_END:
|
||||
case SS_START:
|
||||
if (!tx->buf->available())
|
||||
goto finish;
|
||||
tx->byte = tx->buf->read_char();
|
||||
digitalWrite(tx->pin, LOW);
|
||||
tx->state = SS_DATA0;
|
||||
return;
|
||||
|
||||
case SS_STOP:
|
||||
digitalWrite(tx->pin, HIGH);
|
||||
break;
|
||||
|
||||
default:
|
||||
digitalWrite(tx->pin, (tx->byte & 0x1) ^ data->invert);
|
||||
tx->byte /= 2;
|
||||
break;
|
||||
}
|
||||
|
||||
tx->state = (SoftState)(tx->state + 1);
|
||||
return;
|
||||
|
||||
finish:
|
||||
gtimer_stop((gtimer_t *)data->param);
|
||||
data->tx.state = SS_IDLE;
|
||||
return;
|
||||
}
|
||||
|
||||
void SoftwareSerial::begin(unsigned long baudrate, uint16_t config) {
|
||||
if (data.rx.buf || data.tx.buf)
|
||||
return;
|
||||
|
||||
uint8_t i;
|
||||
for (i = 0; i < TIMER_MAX; i++) {
|
||||
if (timObj[i] == NULL)
|
||||
break;
|
||||
}
|
||||
if (i == TIMER_MAX) {
|
||||
LT_E("No more timers for SoftwareSerial");
|
||||
return;
|
||||
}
|
||||
|
||||
pinMode(data.tx.pin, OUTPUT);
|
||||
digitalWrite(data.tx.pin, HIGH);
|
||||
|
||||
data.rx.buf = new RingBuffer();
|
||||
data.tx.buf = new RingBuffer();
|
||||
data.rx.state = SS_IDLE;
|
||||
data.tx.state = SS_IDLE;
|
||||
|
||||
uint32_t us = 1E6 / baudrate;
|
||||
|
||||
timObj[i] = (gtimer_t *)malloc(sizeof(gtimer_t));
|
||||
param = data.param = data.tx.param = timObj[i];
|
||||
gtimer_init(OBJ, timNum[i]);
|
||||
OBJ->is_periodcal = true;
|
||||
OBJ->handler = (void *)callback;
|
||||
OBJ->hid = (uint32_t)&data;
|
||||
gtimer_reload(OBJ, us);
|
||||
}
|
||||
|
||||
void SoftwareSerial::end() {
|
||||
gtimer_stop(OBJ);
|
||||
gtimer_deinit(OBJ);
|
||||
free(OBJ);
|
||||
delete data.rx.buf;
|
||||
delete data.tx.buf;
|
||||
}
|
||||
|
||||
void SoftwareSerial::startTx() {
|
||||
gtimer_start(OBJ);
|
||||
}
|
||||
|
||||
void SoftwareSerial::endTx() {
|
||||
gtimer_stop(OBJ);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-07-03. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <api/SoftwareSerial.h>
|
||||
@@ -9,22 +9,14 @@ typedef struct {
|
||||
|
||||
bool WiFiClass::softAP(const char *ssid, const char *passphrase, int channel, bool ssidHidden, int maxClients) {
|
||||
if (!enableAP(true))
|
||||
return false;
|
||||
return WL_CONNECT_FAILED;
|
||||
if (!validate(ssid, passphrase))
|
||||
return WL_CONNECT_FAILED;
|
||||
|
||||
LT_HEAP_I();
|
||||
|
||||
vTaskDelay(20);
|
||||
|
||||
if (!ssid || *ssid == 0x00 || strlen(ssid) > 32) {
|
||||
LT_W("SSID not specified or too long");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (passphrase && strlen(passphrase) < 8) {
|
||||
LT_W("Passphrase too short");
|
||||
return false;
|
||||
}
|
||||
|
||||
strcpy((char *)ap.ssid.val, ssid);
|
||||
ap.ssid.len = strlen(ssid);
|
||||
ap.channel = channel;
|
||||
@@ -42,7 +34,7 @@ bool WiFiClass::softAP(const char *ssid, const char *passphrase, int channel, bo
|
||||
|
||||
dhcps_deinit();
|
||||
|
||||
LT_I("Creating SoftAP %s", ssid);
|
||||
LT_IM(WIFI, "Creating SoftAP %s", ssid);
|
||||
|
||||
int ret;
|
||||
if (!ssidHidden) {
|
||||
@@ -68,7 +60,7 @@ bool WiFiClass::softAP(const char *ssid, const char *passphrase, int channel, bo
|
||||
wifi_indication(WIFI_EVENT_CONNECT, NULL, ARDUINO_EVENT_WIFI_AP_START, -2);
|
||||
|
||||
if (ret < 0) {
|
||||
LT_E("SoftAP failed; ret=%d", ret);
|
||||
LT_EM(WIFI, "SoftAP failed; ret=%d", ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -63,6 +63,9 @@ void wifi_unreg_event_handler(unsigned int event_cmds, rtw_event_handler_t handl
|
||||
}
|
||||
} // extern "C"
|
||||
|
||||
// TODO queue handling is apparently done all wrong here
|
||||
// (passing pointers to pointers in xQueueSend/xQueueReceive)
|
||||
|
||||
// function called by wext_wlan_indicate
|
||||
void wifi_indication(rtw_event_indicate_t event, char *buf, int buf_len, int flags) {
|
||||
LT_HEAP_I();
|
||||
@@ -104,7 +107,7 @@ static void wifiEventTask(void *arg) {
|
||||
void startWifiTask() {
|
||||
if (!wifiEventQueueHandle) {
|
||||
LT_HEAP_I();
|
||||
wifiEventQueueHandle = xQueueCreate(32, sizeof(Event_t *));
|
||||
wifiEventQueueHandle = xQueueCreate(32, sizeof(rtw_event_t *));
|
||||
LT_HEAP_I();
|
||||
}
|
||||
if (!wifiEventTaskHandle) {
|
||||
|
||||
@@ -15,7 +15,7 @@ bool WiFiClass::modePriv(WiFiMode mode, WiFiModeAction sta, WiFiModeAction ap) {
|
||||
|
||||
if (!data.initialized) {
|
||||
// initialize wifi first
|
||||
LT_I("Initializing LwIP");
|
||||
LT_IM(WIFI, "Initializing LwIP");
|
||||
LwIP_Init();
|
||||
reset_wifi_struct();
|
||||
data.initialized = true;
|
||||
@@ -23,7 +23,7 @@ bool WiFiClass::modePriv(WiFiMode mode, WiFiModeAction sta, WiFiModeAction ap) {
|
||||
LT_HEAP_I();
|
||||
if (getMode()) {
|
||||
// stop wifi to change mode
|
||||
LT_D_WG("Stopping WiFi to change mode");
|
||||
LT_DM(WIFI, "Stopping WiFi to change mode");
|
||||
if (wifi_off() != RTW_SUCCESS)
|
||||
goto error;
|
||||
vTaskDelay(20);
|
||||
@@ -32,7 +32,7 @@ bool WiFiClass::modePriv(WiFiMode mode, WiFiModeAction sta, WiFiModeAction ap) {
|
||||
}
|
||||
|
||||
if (wifi_on((rtw_mode_t)mode) != RTW_SUCCESS) {
|
||||
LT_E("Error while changing mode(%u)", mode);
|
||||
LT_EM(WIFI, "Error while changing mode(%u)", mode);
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -72,12 +72,14 @@ WiFiStatus WiFiClass::status() {
|
||||
}
|
||||
|
||||
bool WiFiClass::setSleep(bool enable) {
|
||||
LT_D_WG("WiFi sleep mode %u", enable);
|
||||
if (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)
|
||||
} else {
|
||||
if (wifi_disable_powersave() != RTW_SUCCESS)
|
||||
return false;
|
||||
}
|
||||
data.sleep = enable;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -6,19 +6,11 @@ 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();
|
||||
|
||||
if (!ssid || *ssid == 0x00 || strlen(ssid) > 32) {
|
||||
LT_W("SSID not specified or too long");
|
||||
return WL_CONNECT_FAILED;
|
||||
}
|
||||
|
||||
if (passphrase && strlen(passphrase) > 64) {
|
||||
LT_W("Passphrase too long");
|
||||
return WL_CONNECT_FAILED;
|
||||
}
|
||||
|
||||
memset(wifi.bssid.octet, 0, ETH_ALEN);
|
||||
strcpy((char *)wifi.ssid.val, ssid);
|
||||
wifi.ssid.len = strlen(ssid);
|
||||
@@ -71,7 +63,7 @@ bool WiFiClass::reconnect(const uint8_t *bssid) {
|
||||
int ret;
|
||||
uint8_t dhcpRet;
|
||||
|
||||
LT_I("Connecting to %s", wifi.ssid.val);
|
||||
LT_IM(WIFI, "Connecting to %s", wifi.ssid.val);
|
||||
__wrap_rtl_printf_disable();
|
||||
__wrap_DiagPrintf_disable();
|
||||
|
||||
@@ -118,11 +110,11 @@ bool WiFiClass::reconnect(const uint8_t *bssid) {
|
||||
__wrap_DiagPrintf_enable();
|
||||
return true;
|
||||
}
|
||||
LT_E("DHCP failed; dhcpRet=%d", dhcpRet);
|
||||
LT_EM(WIFI, "DHCP failed; dhcpRet=%d", dhcpRet);
|
||||
wifi_disconnect();
|
||||
goto error;
|
||||
}
|
||||
LT_E("Connection failed; ret=%d", ret);
|
||||
LT_EM(WIFI, "Connection failed; ret=%d", ret);
|
||||
error:
|
||||
__wrap_rtl_printf_enable();
|
||||
__wrap_DiagPrintf_enable();
|
||||
@@ -153,9 +145,14 @@ IPAddress WiFiClass::localIP() {
|
||||
}
|
||||
|
||||
uint8_t *WiFiClass::macAddress(uint8_t *mac) {
|
||||
uint8_t *macLocal = LwIP_GetMAC(NETIF_RTW_STA);
|
||||
memcpy(mac, macLocal, ETH_ALEN);
|
||||
free(macLocal);
|
||||
if (getMode() == WIFI_MODE_NULL) {
|
||||
uint8_t *efuse = (uint8_t *)malloc(512);
|
||||
EFUSE_LogicalMap_Read(efuse);
|
||||
memcpy(mac, efuse + 0x11A, ETH_ALEN);
|
||||
free(efuse);
|
||||
return mac;
|
||||
}
|
||||
memcpy(mac, LwIP_GetMAC(NETIF_RTW_STA), ETH_ALEN);
|
||||
return mac;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ int16_t WiFiClass::scanNetworks(bool async, bool showHidden, bool passive, uint3
|
||||
scanDelete();
|
||||
scanInit();
|
||||
|
||||
LT_I("Starting WiFi scan");
|
||||
LT_IM(WIFI, "Starting WiFi scan");
|
||||
|
||||
if (wifi_scan_networks(scanHandler, this) != RTW_SUCCESS)
|
||||
return WIFI_SCAN_FAILED;
|
||||
@@ -47,7 +47,7 @@ int16_t WiFiClass::scanNetworks(bool async, bool showHidden, bool passive, uint3
|
||||
scan->running = true;
|
||||
|
||||
if (!async) {
|
||||
LT_I("Waiting for results");
|
||||
LT_IM(WIFI, "Waiting for results");
|
||||
xSemaphoreTake(data.scanSem, 1); // reset the semaphore quickly
|
||||
xSemaphoreTake(data.scanSem, pdMS_TO_TICKS(maxMsPerChannel * 20));
|
||||
return scan->count;
|
||||
|
||||
8
arduino/realtek-ambz/libraries/WiFi/WiFiUdp.h
Normal file
8
arduino/realtek-ambz/libraries/WiFi/WiFiUdp.h
Normal file
@@ -0,0 +1,8 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-09-10. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <api/WiFi/WiFi.h>
|
||||
#include <lwip/LwIPUdp.h>
|
||||
|
||||
typedef LwIPUDP WiFiUDP;
|
||||
@@ -7,10 +7,29 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
extern void LOGUART_PutChar(char c);
|
||||
#define LOG_UART_REG_BASE 0x40003000
|
||||
#define UART0_REG_BASE 0x40040000
|
||||
#define UART1_REG_BASE 0x40040400
|
||||
#define UART2_REG_BASE LOG_UART_REG_BASE
|
||||
|
||||
extern uint32_t UART_Writable(void *UARTx);
|
||||
extern void UART_CharPut(void *UARTx, uint8_t TxData);
|
||||
|
||||
static const void *uart_dev[3] = {
|
||||
UART0_REG_BASE,
|
||||
UART1_REG_BASE,
|
||||
LOG_UART_REG_BASE,
|
||||
};
|
||||
|
||||
uint8_t lt_uart_port = 2;
|
||||
|
||||
void putchar_(char c) {
|
||||
LOGUART_PutChar(c);
|
||||
putchar_p(c, lt_uart_port);
|
||||
}
|
||||
|
||||
void putchar_p(char c, unsigned long port) {
|
||||
while (UART_Writable(uart_dev[port]) == 0) {}
|
||||
UART_CharPut(uart_dev[port], c);
|
||||
}
|
||||
|
||||
WRAP_PRINTF(rtl_printf);
|
||||
|
||||
@@ -1,6 +1,31 @@
|
||||
<!-- 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)
|
||||
- [WB2L Wi-Fi Module](../boards/wb2l/README.md)
|
||||
- [WR3 Wi-Fi Module](../boards/wr3/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)
|
||||
|
||||
6
boards/_base/beken-7231n-tuya.json
Normal file
6
boards/_base/beken-7231n-tuya.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"build": {
|
||||
"bkcrypt_coeffs": "510fb093a3cbeadc5993a17ec7adeb03",
|
||||
"bkboot_version": "1.0.1-bk7231n"
|
||||
}
|
||||
}
|
||||
33
boards/_base/beken-7231n.json
Normal file
33
boards/_base/beken-7231n.json
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"build": {
|
||||
"family": "BK7231N",
|
||||
"ldscript_sdk": "bk7231n_bsp.ld",
|
||||
"ldscript_arduino": "bk7231n_bsp.ld",
|
||||
"bkboot_version": "1.0.1-bk7231n",
|
||||
"bkrbl_size_app": "0x107800"
|
||||
},
|
||||
"flash": {
|
||||
"bootloader": "0x000000+0x11000",
|
||||
"app": "0x011000+0x119000",
|
||||
"download": "0x12A000+0xA6000",
|
||||
"calibration": "0x1D0000+0x1000",
|
||||
"net": "0x1D1000+0x1000",
|
||||
"tlv": "0x1D2000+0x1000",
|
||||
"kvs": "0x1D3000+0x8000",
|
||||
"userdata": "0x1DB000+0x25000"
|
||||
},
|
||||
"upload": {
|
||||
"maximum_size": 1083136,
|
||||
"speed": 460800
|
||||
},
|
||||
"connectivity": [
|
||||
"ble"
|
||||
],
|
||||
"doc": {
|
||||
"params": {
|
||||
"extra": {
|
||||
"Bluetooth": "BLE v5.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +1,6 @@
|
||||
{
|
||||
"build": {
|
||||
"bkcrypt_coeffs": "510fb093a3cbeadc5993a17ec7adeb03",
|
||||
"bkboot_version": "1.0.5-bk7231s",
|
||||
"bkrbl_size_app": "0x107800"
|
||||
},
|
||||
"flash": {
|
||||
"bootloader": "0x000000+0x11000",
|
||||
"app": "0x011000+0x121000",
|
||||
"download": "0x132000+0xA6000",
|
||||
"kvs": "0x1D8000+0x8000",
|
||||
"tlv": "0x1E0000+0x1000",
|
||||
"net": "0x1E1000+0x2000",
|
||||
"userdata": "0x1E3000+0x1D000"
|
||||
},
|
||||
"upload": {
|
||||
"maximum_size": 1083136
|
||||
},
|
||||
"doc": {
|
||||
"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."
|
||||
]
|
||||
"bkboot_version": "1.0.5-bk7231s"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"build": {
|
||||
"family": "BK7231T",
|
||||
"ldscript_sdk": "bk7231_bsp.ld",
|
||||
"ldscript_arduino": "bk7231_bsp.ld"
|
||||
},
|
||||
"doc": {
|
||||
"params": {
|
||||
"extra": {
|
||||
"Bluetooth": "BLE v4.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
33
boards/_base/beken-7231u.json
Normal file
33
boards/_base/beken-7231u.json
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"build": {
|
||||
"family": "BK7231U",
|
||||
"ldscript_sdk": "bk7231_bsp.ld",
|
||||
"ldscript_arduino": "bk7231_bsp.ld",
|
||||
"bkboot_version": "1.0.8-bk7231u",
|
||||
"bkrbl_size_app": "0x108700"
|
||||
},
|
||||
"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": {
|
||||
"maximum_size": 1083136,
|
||||
"speed": 921600
|
||||
},
|
||||
"connectivity": [
|
||||
"ble"
|
||||
],
|
||||
"doc": {
|
||||
"params": {
|
||||
"extra": {
|
||||
"Bluetooth": "BLE v4.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
40
boards/_base/beken-7252.json
Normal file
40
boards/_base/beken-7252.json
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"build": {
|
||||
"family": "BK7251",
|
||||
"f_cpu": "180000000L",
|
||||
"ldscript_sdk": "bk7231_bsp.ld",
|
||||
"ldscript_arduino": "bk7231_bsp.ld",
|
||||
"bkboot_version": "0.1.3-bk7252",
|
||||
"bkrbl_size_app": "0x1A0000"
|
||||
},
|
||||
"flash": {
|
||||
"bootloader": "0x000000+0x11000",
|
||||
"app": "0x011000+0x1BA000",
|
||||
"filesystem": "0x1CB000+0x119000",
|
||||
"kvs": "0x2E4000+0x8000",
|
||||
"download": "0x2EC000+0x112000",
|
||||
"calibration": "0x3FE000+0x1000",
|
||||
"tlv": "0x3FF000+0x1000"
|
||||
},
|
||||
"debug": {
|
||||
"gdb_init": [
|
||||
"mem 0x200000 0x400000 ro"
|
||||
]
|
||||
},
|
||||
"upload": {
|
||||
"maximum_ram_size": 524288,
|
||||
"flash_size": 4194304,
|
||||
"maximum_size": 1703936,
|
||||
"speed": 921600
|
||||
},
|
||||
"connectivity": [
|
||||
"ble"
|
||||
],
|
||||
"doc": {
|
||||
"params": {
|
||||
"extra": {
|
||||
"Bluetooth": "BLE v5.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,16 @@
|
||||
{
|
||||
"build": {
|
||||
"f_cpu": "120000000L",
|
||||
"prefix": "arm-none-eabi-"
|
||||
"prefix": "arm-none-eabi-",
|
||||
"bkota": {
|
||||
"encryption": "aes256",
|
||||
"compression": "gzip",
|
||||
"key": "0123456789ABCDEF0123456789ABCDEF",
|
||||
"iv": "0123456789ABCDEF"
|
||||
}
|
||||
},
|
||||
"connectivity": [
|
||||
"wifi",
|
||||
"ble"
|
||||
"wifi"
|
||||
],
|
||||
"debug": {
|
||||
"protocol": "openocd",
|
||||
@@ -25,7 +30,6 @@
|
||||
"maximum_ram_size": 262144,
|
||||
"flash_size": 2097152,
|
||||
"require_upload_port": true,
|
||||
"speed": 921600,
|
||||
"protocol": "uart",
|
||||
"protocols": [
|
||||
"uart"
|
||||
@@ -42,8 +46,11 @@
|
||||
},
|
||||
"links": {
|
||||
"General info": "../../docs/platform/beken-72xx/README.md",
|
||||
"Flashing (Tuya manual)": "https://developer.tuya.com/en/docs/iot/burn-and-authorize-wb-series-modules?id=Ka78f4pttsytd",
|
||||
"Flashing guide": "../../docs/platform/beken-72xx/flashing.md",
|
||||
"BkWriter v1.6.0": "https://images.tuyacn.com/smart/bk_writer1.60/bk_writer1.60.exe"
|
||||
}
|
||||
},
|
||||
"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."
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
7
boards/_base/generic.json
Normal file
7
boards/_base/generic.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"pcb": {
|
||||
"symbol": "GENERIC",
|
||||
"templates": [],
|
||||
"vars": {}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user