68 Commits

Author SHA1 Message Date
Kuba Szczodrzyński
aae2f65b9e [release] v0.9.0
Some checks failed
Lint check / Lint with clang-format (push) Has been cancelled
Lint check / Lint with black (push) Has been cancelled
PlatformIO Publish / publish (push) Has been cancelled
2022-08-06 13:42:37 +02:00
Kuba Szczodrzyński
d02197474e [docs] Update ESPHome docs, add cloudcutter guide 2022-08-06 13:37:47 +02:00
Kuba Szczodrzyński
41b37e9c24 [core] Update ltchiptool to v1.4.0 2022-08-06 13:06:44 +02:00
Kuba Szczodrzyński
b03400fac2 [beken-72xx] Implement OTA API, add Update debugging 2022-08-06 11:36:53 +02:00
Kuba Szczodrzyński
3e808f7b6b [beken-72xx] Write OTA package to UF2 image 2022-08-05 20:29:48 +02:00
Kuba Szczodrzyński
1e3a8971fb [core] Migrate tools to ltchiptool 2022-08-05 20:29:45 +02:00
Kuba Szczodrzyński
d8c0105b97 [examples] Fix PinScan compilation on realtek-ambz 2022-08-03 12:48:50 +02:00
Kuba Szczodrzyński
b3689cbac8 [beken-72xx] Specify keys for OTA packaging 2022-08-01 19:56:34 +02:00
Kuba Szczodrzyński
1b5d6472f7 [examples] Fix PinScan telnet functionality 2022-08-01 11:28:56 +02:00
Kuba Szczodrzyński
e9511c507a [core] Allow disabling LT logger programmatically 2022-08-01 11:28:16 +02:00
Kuba Szczodrzyński
365f64ded5 [beken-72xx] Make Serial.end() disable hardware UART 2022-08-01 11:27:57 +02:00
Kuba Szczodrzyński
3601fa63d8 [examples] Add PinScan example 2022-08-01 10:52:58 +02:00
Kuba Szczodrzyński
5d00ddf516 [beken-72xx] Fix detaching interrupt handler 2022-07-31 23:25:12 +02:00
Kuba Szczodrzyński
0051453cad [beken-72xx] Implement interrupts 2022-07-31 21:35:02 +02:00
Kuba Szczodrzyński
7920ea2dda [beken-72xx] Fix SerialClass character reading 2022-07-31 14:52:09 +02:00
Kuba Szczodrzyński
9416e45a75 [docs] Restructure documentation, clarify some parts 2022-07-31 13:05:24 +02:00
Kuba Szczodrzyński
98a65c81af [boards] Add usage info to board README 2022-07-31 12:47:24 +02:00
Kuba Szczodrzyński
8e1f06e79b [boards] Add LSC LMA35 board, update boardgen 2022-07-30 19:48:58 +02:00
Kuba Szczodrzyński
58a09f453d [realtek-ambz] Fix errors related to lwIP 2022-07-30 17:18:46 +02:00
Kuba Szczodrzyński
7dc69982b6 [beken-72xx] Fix putchar_p UART index 2022-07-30 15:42:30 +02:00
Kuba Szczodrzyński
46e4041ed8 [beken-72xx] Mark mDNS as broken 2022-07-28 22:18:04 +02:00
Kuba Szczodrzyński
0e129130b1 [core] Print errors about starting main task 2022-07-28 20:29:53 +02:00
Kuba Szczodrzyński
33c9868f90 [core] Remove duplicated WMath functions 2022-07-28 13:46:42 +02:00
Kuba Szczodrzyński
fb04b1830e [release] v0.8.0
Some checks failed
Lint check / Lint with clang-format (push) Has been cancelled
Lint check / Lint with black (push) Has been cancelled
PlatformIO Publish / publish (push) Has been cancelled
2022-07-26 11:11:52 +02:00
Kuba Szczodrzyński
9509194bd0 [beken-72xx] Correct sys_config.h path 2022-07-26 11:11:14 +02:00
Kuba Szczodrzyński
60322a243a [boards] Fix missing vendor field in generic boards 2022-07-26 11:10:45 +02:00
Kuba Szczodrzyński
4ed7067537 [boards] Add generic definitions for each family 2022-07-25 19:59:53 +02:00
Kuba Szczodrzyński
69086e8fba [boards] Rename small/large base boards to show size 2022-07-25 19:58:16 +02:00
Kuba Szczodrzyński
a4b63bb037 [tools] Make util/markdown.py pre-Python 3.10 compatible 2022-07-21 23:08:53 +02:00
Kuba Szczodrzyński
5ffb2f6619 [boards] Add BW15 board definition, update boardgen 2022-07-21 23:08:49 +02:00
Kuba Szczodrzyński
41eaf9b9e4 [realtek-ambz2] Add initial AmebaZ2 support 2022-07-21 23:08:45 +02:00
Kuba Szczodrzyński
28bb777399 [core] Move family config to separate dir, define Realtek parent 2022-07-21 23:08:39 +02:00
Kuba Szczodrzyński
f375a35cc8 [core] Move library include wrappers to common 2022-07-21 23:08:39 +02:00
Kuba Szczodrzyński
1d41d84083 [boards] Move common partitions to base JSON 2022-07-21 23:08:28 +02:00
Kuba Szczodrzyński
357be177fc [core] Make WiFi sleep & TX power methods weak 2022-07-12 21:12:54 +02:00
Kuba Szczodrzyński
23c3335de8 [beken-72xx] Use Hostapd MD5 implementation 2022-07-12 13:05:02 +02:00
Kuba Szczodrzyński
963b164783 [beken-72xx] Define struct ip_addr as IPv4 2022-07-12 13:01:46 +02:00
Kuba Szczodrzyński
0c22a02641 [beken-72xx] Use mbedTLS MD5 implementation 2022-07-12 12:48:27 +02:00
Kuba Szczodrzyński
10cb5c2c76 [core] Add missing C++ stdlib includes 2022-07-12 12:48:02 +02:00
Kuba Szczodrzyński
6d36c9ef7b [boards] Add remaining WB2x and WB3x boards 2022-07-11 16:42:45 +02:00
Kuba Szczodrzyński
aed97a5e92 [boards] Add remaining WR2x and WR3x boards 2022-07-11 14:23:10 +02:00
Kuba Szczodrzyński
b6008fc9bb [docs] Add family flashing guides 2022-07-11 12:03:28 +02:00
Kuba Szczodrzyński
f9359679ad [docs] Add Getting started guide 2022-07-11 10:54:16 +02:00
Kuba Szczodrzyński
052d7be1a9 [beken-72xx] Move to GNU++11 2022-07-10 20:18:12 +02:00
Kuba Szczodrzyński
ead577a116 [release] v0.7.0
Some checks failed
Lint check / Lint with clang-format (push) Has been cancelled
Lint check / Lint with black (push) Has been cancelled
PlatformIO Publish / publish (push) Has been cancelled
2022-07-10 19:50:07 +02:00
Kuba Szczodrzyński
ccf7d972ce [beken-72xx] Implement WiFi events 2022-07-10 19:49:14 +02:00
Kuba Szczodrzyński
b2df9e6a8b [beken-72xx] Use chip ID based on MAC address 2022-07-07 18:01:35 +02:00
Kuba Szczodrzyński
e37014ebd6 [beken-72xx] Wrap BkDriverFlash for correct partition offsets 2022-07-07 17:45:58 +02:00
Kuba Szczodrzyński
c96ef2ff7a [beken-72xx] Add draft BK7231N support 2022-07-07 17:18:25 +02:00
Kuba Szczodrzyński
c19dd0d87e [beken-72xx] Fix WiFi using DHCP 2022-07-07 17:15:52 +02:00
Kuba Szczodrzyński
02f972bd5f [boards] Add CB2S board definition 2022-07-07 14:57:35 +02:00
Kuba Szczodrzyński
15facd8866 [realtek-ambz] Fix reading MAC address without WiFi enabled 2022-07-05 13:16:51 +02:00
Kuba Szczodrzyński
cf584c3bd6 [tools] Fix link2bin with long command line 2022-07-04 22:37:25 +02:00
Kuba Szczodrzyński
4744351964 [core] Allow changing SDK, logger & Serial output ports 2022-07-04 13:56:03 +02:00
Kuba Szczodrzyński
31b753ab5a [core] Allow configuring silencing of SDK output 2022-07-04 13:55:58 +02:00
Kuba Szczodrzyński
3cb944dde2 [realtek-ambz] Implement SoftwareSerial class 2022-07-03 22:54:18 +02:00
Kuba Szczodrzyński
1b4265f522 [docs] Add TODO list 2022-07-03 19:50:27 +02:00
Kuba Szczodrzyński
5d16338faa [realtek-ambz] Add missing #define 2022-07-03 19:48:24 +02:00
Kuba Szczodrzyński
673b8233e5 [realtek-ambz] Refactor Serial class 2022-07-03 19:15:33 +02:00
Kuba Szczodrzyński
0dd2e2583b [core] Rename init() to initArduino() 2022-07-03 16:49:46 +02:00
Kuba Szczodrzyński
c19f24cbfd [beken-72xx] Implement WiFi Access Point mode 2022-07-01 19:16:48 +02:00
Kuba Szczodrzyński
cfb6830d95 [beken-72xx] Revert scanning before connecting 2022-07-01 19:15:14 +02:00
Kuba Szczodrzyński
27dea356cf [beken-72xx] Fix station with static IP 2022-07-01 19:14:41 +02:00
Kuba Szczodrzyński
352a425c4f [beken-72xx] Wait for init_thread to start TCP/IP 2022-07-01 18:49:14 +02:00
Kuba Szczodrzyński
4beaa79d02 [beken-72xx] Revert to standard station config struct 2022-07-01 18:48:11 +02:00
Kuba Szczodrzyński
e54eab83f2 [beken-72xx] Use station data structs in WiFiData 2022-07-01 16:17:48 +02:00
Kuba Szczodrzyński
e74a491b4a [core] Move SSID & passphrase validation to common 2022-07-01 15:36:49 +02:00
Kuba Szczodrzyński
a9415c1db7 [core] Fix compilation and linking on Linux 2022-07-01 12:47:32 +02:00
316 changed files with 14293 additions and 4997 deletions

View File

@@ -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,8 +65,8 @@ NVS / Preferences | ❌ | ❌
SPIFFS | ❌ | ❌
BLE | - | ❌
NTP | ❌ | ❌
OTA | ✔️ |
MDNS | ✔️ | ✔️
OTA | ✔️ | ✔️
MDNS | ✔️ | BK7231T only
MQTT | ✅ | ❌
SD | ❌ | ❌

View File

@@ -1,9 +1,29 @@
* [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/cloudcutter.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)
* Realtek AmebaZ Series
* [General info](docs/platform/realtek/README.md)
* [Flashing (AmebaZ)](docs/platform/realtek-ambz/flashing.md)
* [Debugging](docs/platform/realtek/debugging.md)
* [Exception decoder](docs/platform/realtek/exception-decoder.md)
* C library
* [Built-in functions](docs/platform/realtek-ambz/stdlib.md)
* [Memory management](docs/platform/realtek-ambz/memory-management.md)
* [All supported boards](boards/)
* 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 +34,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 +57,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
View 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)

View File

@@ -14,19 +14,17 @@
// 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

View File

@@ -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,11 +14,16 @@
#define FLASH_OP_RDID 20
extern "C" {
#include <flash_pub.h>
#include <param_config.h>
#include <sys_ctrl.h>
#include <sys_rtos.h>
#include <wlan_ui_pub.h>
}
extern uint8_t system_mac[];
} // extern "C"
void LibreTuya::restart() {
bk_reboot();
@@ -35,10 +41,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 +110,14 @@ uint32_t LibreTuya::getMaxAllocHeap() {
/* OTA-related */
static int8_t otaImage2Valid = -1;
uint8_t LibreTuya::otaGetStoredIndex() {
return 1;
return otaHasImage2() ? 2 : 1;
}
bool LibreTuya::otaSupportsDual() {
return false;
return true;
}
bool LibreTuya::otaHasImage1() {
@@ -118,11 +125,28 @@ 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
}
/* Global instance */

View File

@@ -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
@@ -24,7 +26,10 @@ SerialClass::SerialClass(uint8_t port) {
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) {
buf->store_char(ch);
}
}
void SerialClass::begin(unsigned long baudrate, uint16_t config) {
@@ -39,17 +44,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;
}

View File

@@ -3,18 +3,27 @@
#include <Arduino.h>
extern "C" {
#include <rtos_pub.h>
#include <sys_rtos.h>
}
extern int uart_print_port;
} // extern "C"
beken_thread_t mainThread;
void initArduino() {
// set default UART output port
uart_print_port = LT_UART_DEFAULT_PORT - 1;
}
bool startMainTask() {
OSStatus ret = rtos_create_thread(
&mainThread,
THD_APPLICATION_PRIORITY,
"main",
(beken_thread_function_t)main_task,
(beken_thread_function_t)mainTask,
8192,
NULL
);

View File

@@ -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,6 +35,7 @@ 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++) {
@@ -84,7 +97,13 @@ void analogWrite(pin_size_t pinNumber, int value) {
float percent = value * 1.0 / (1 << _analogWriteResolution);
uint32_t dutyCycle = percent * _analogWritePeriod * 26 - 1;
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 = dutyCycle;
pwm.duty_cycle3 = dutyCycle;
#endif
if (!pinEnabled(pin, PIN_PWM)) {
// enable PWM and set its value

View File

@@ -0,0 +1,76 @@
/* Copyright (c) Kuba Szczodrzyński 2022-07-31. */
#include <Arduino.h>
static void *irqHandlerList[PINS_COUNT] = {NULL};
static void *irqHandlerArgs[PINS_COUNT] = {NULL};
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 (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;
switch (mode) {
case LOW:
event = GPIO_INT_LEVEL_LOW;
modeNew = INPUT_PULLUP;
break;
case HIGH:
event = GPIO_INT_LEVEL_HIGH;
modeNew = INPUT_PULLDOWN;
break;
case FALLING:
event = GPIO_INT_LEVEL_FALLING;
modeNew = INPUT_PULLUP;
break;
case RISING:
event = GPIO_INT_LEVEL_RISING;
modeNew = INPUT_PULLDOWN;
break;
default:
return;
}
irqHandlerList[interruptNumber] = callback;
irqHandlerArgs[interruptNumber] = param;
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;
gpio_int_disable(pin->gpio);
pin->enabled &= ~PIN_IRQ;
}

View File

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

View File

@@ -15,6 +15,7 @@ WiFiStatus eventTypeToStatus(uint8_t type) {
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 +23,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;

View File

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

View File

@@ -12,11 +12,9 @@ extern "C" {
} // 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;

View File

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

View File

@@ -4,16 +4,26 @@
bool WiFiClass::modePriv(WiFiMode mode, WiFiModeAction sta, WiFiModeAction ap) {
__wrap_bk_printf_disable();
startWifiTask();
if (mode && !data.statusIp) {
data.statusIp = (IPStatusTypedef *)malloc(sizeof(IPStatusTypedef));
data.statusLink = (LinkStatusTypeDef *)malloc(sizeof(LinkStatusTypeDef));
data.configSta = zalloc(sizeof(network_InitTypeDef_st));
data.configAp = zalloc(sizeof(network_InitTypeDef_ap_st));
data.statusIp = malloc(sizeof(IPStatusTypedef));
data.statusLink = malloc(sizeof(LinkStatusTypeDef));
STA_CFG->dhcp_mode = DHCP_CLIENT;
}
if (!__bk_rf_is_init) {
LT_D_WG("Initializing func&app");
func_init_extended();
app_pre_start();
// wait for the init_thread to finish its job
while (xTaskGetHandle("init_thread")) {
LT_V_WG("Waiting for init_thread");
delay(10);
}
LT_D_WG("Success");
__bk_rf_is_init = true;
}
@@ -22,9 +32,11 @@ bool WiFiClass::modePriv(WiFiMode mode, WiFiModeAction sta, WiFiModeAction ap) {
if (sta == WLMODE_ENABLE) {
LT_D_WG("Enabling STA");
bk_wlan_sta_init(NULL);
wifiEventSendArduino(ARDUINO_EVENT_WIFI_STA_START);
} else if (sta == WLMODE_DISABLE) {
LT_D_WG("Disabling STA");
bk_wlan_stop(BK_STATION);
wifiEventSendArduino(ARDUINO_EVENT_WIFI_STA_STOP);
}
LT_HEAP_I();
@@ -32,14 +44,20 @@ bool WiFiClass::modePriv(WiFiMode mode, WiFiModeAction sta, WiFiModeAction ap) {
if (ap == WLMODE_ENABLE) {
LT_D_WG("Enabling AP");
bk_wlan_ap_init(NULL);
wifiEventSendArduino(ARDUINO_EVENT_WIFI_AP_START);
} else if (ap == WLMODE_DISABLE) {
LT_D_WG("Disabling AP");
bk_wlan_stop(BK_SOFT_AP);
wifiEventSendArduino(ARDUINO_EVENT_WIFI_AP_STOP);
}
if (!mode) {
free(data.configSta);
free(data.configAp);
free(data.statusIp);
free(data.statusLink);
data.configSta = NULL;
data.configAp = NULL;
data.statusIp = NULL;
data.statusLink = NULL;
}
@@ -47,6 +65,7 @@ bool WiFiClass::modePriv(WiFiMode mode, WiFiModeAction sta, WiFiModeAction ap) {
LT_HEAP_I();
__wrap_bk_printf_enable();
return true;
}
WiFiMode WiFiClass::getMode() {
@@ -58,7 +77,10 @@ WiFiMode WiFiClass::getMode() {
}
WiFiStatus WiFiClass::status() {
return eventTypeToStatus(mhdr_get_station_status());
rw_evt_type status = mhdr_get_station_status();
if (status == RW_EVT_STA_CONNECTED && STA_CFG->dhcp_mode == DHCP_DISABLE)
status = RW_EVT_STA_GOT_IP;
return eventTypeToStatus(status);
}
IPAddress WiFiClass::hostByName(const char *hostname) {

View File

@@ -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>
@@ -28,10 +30,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,15 +40,17 @@ 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)

View File

@@ -4,24 +4,19 @@
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();
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,28 +25,36 @@ 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;
// need to initialize data struct first
enableSTA(true);
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]);
}
if (dns1)
sprintf(config.dns, "%u.%u.%u.%u", ADDR_STA_DNS);
bk_wlan_set_ip_status(&config, BK_STATION);
}
// 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]) {
if (!bssid && !STA_CFG->wifi_ssid[0]) {
LT_E("(B)SSID not specified");
goto error;
}
@@ -59,55 +62,30 @@ bool WiFiClass::reconnect(const uint8_t *bssid) {
if (bssid) {
LT_D_WG("Connecting to " MACSTR, MAC2STR(bssid));
} else {
LT_D_WG("Connecting to %s", data.ssid);
LT_D_WG("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));
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_D_WG("Static IP: %s / %s / %s", STA_CFG->local_ip_addr, STA_CFG->net_mask, STA_CFG->gateway_ip_addr);
LT_D_WG("Static DNS: %s", STA_CFG->dns_server_ip_addr);
} else {
config.dhcp_mode = DHCP_CLIENT;
LT_D_WG("Using DHCP");
}
if (ADDR_STA_DNS) {
sprintf(config.dns_server_ip_addr, "%u.%u.%u.%u", ADDR_STA_DNS);
LT_D_WG("Static DNS: %s", config.dns_server_ip_addr);
}
if (!data.scannedAt || millis() - data.scannedAt > 10000) {
LT_D_WG("Scan needed");
// apparently a scan must be performed first,
// else it hangs at "[sa_sta]MM_START_REQ"
scanNetworks(false);
}
LT_D_WG("Starting WiFi...");
__wrap_bk_printf_disable();
bk_wlan_start_sta(&config);
bk_wlan_start_sta(STA_CFG);
__wrap_bk_printf_enable();
LT_D_WG("bk_wlan_start() OK");
LT_D_WG("Start OK");
return true;
error:
@@ -116,6 +94,8 @@ error:
bool WiFiClass::disconnect(bool wifiOff) {
bk_wlan_connection_loss();
if (wifiOff)
enableSTA(false);
return true;
}
@@ -128,34 +108,30 @@ bool WiFiClass::getAutoReconnect() {
}
IPAddress WiFiClass::localIP() {
IPStatusTypedef config;
bk_wlan_get_ip_status(&config, BK_STATION);
bk_wlan_get_ip_status(IP_STATUS, BK_STATION);
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);
bk_wlan_get_ip_status(IP_STATUS, BK_STATION);
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);
bk_wlan_get_ip_status(IP_STATUS, BK_STATION);
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);
bk_wlan_get_ip_status(IP_STATUS, BK_STATION);
IPAddress ip;
ip.fromString(config.dns);
ip.fromString(IP_STATUS->dns);
return ip;
}
@@ -164,12 +140,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,7 +156,19 @@ 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_E("Invalid MAC address");
return false;
}
// ensure "mac_inited" is true
wifi_get_mac_address((char *)system_mac, BK_STATION);
// store the MAC globally
memcpy(system_mac, mac, 6);
WiFiMode previousMode = getMode();
if (previousMode) {
mode(WIFI_MODE_NULL);
mode(previousMode);
}
return true;
}

View File

@@ -38,6 +38,8 @@ 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);
@@ -57,17 +59,26 @@ int16_t WiFiClass::scanNetworks(bool async, bool showHidden, bool passive, uint3
__wrap_bk_printf_disable();
mhdr_scanu_reg_cb(scanHandler, this);
bk_wlan_start_scan();
__wrap_bk_printf_enable();
LT_HEAP_I();
scan->running = true;
int16_t ret = WIFI_SCAN_RUNNING;
if (!async) {
LT_I("Waiting for results");
xSemaphoreTake(data.scanSem, 1); // reset the semaphore quickly
xSemaphoreTake(data.scanSem, pdMS_TO_TICKS(maxMsPerChannel * 20));
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;
}

View File

@@ -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);

View File

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

View File

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

View File

@@ -14,6 +14,8 @@ void WiFiClass::printDiag(Print &dest) {
dest.print("SSID: ");
dest.println(SSID());
if (isConnected()) {
dest.print("Channel: ");
dest.println(channel());
dest.print("BSSID: ");
dest.println(BSSIDstr());
dest.print("RSSI: ");
@@ -42,5 +44,24 @@ void WiFiClass::printDiag(Print &dest) {
}
}
bool WiFiClass::validate(const char *ssid, const char *passphrase) {
if (!ssid || *ssid == 0x00 || strlen(ssid) > 32) {
LT_W("SSID not specified or too long");
return false;
}
if (passphrase) {
uint16_t length = strlen(passphrase);
if (length < 8) {
LT_W("Passphrase too short (%u)", length);
return false;
}
if (length > 63) {
LT_W("Passphrase too long (%u)", length);
return false;
}
}
return true;
}
WiFiClass WiFi;
WiFiClass *pWiFi = NULL;

View File

@@ -46,6 +46,7 @@ class WiFiClass {
WiFiClass();
~WiFiClass();
void printDiag(Print &dest);
bool validate(const char *ssid, const char *passphrase);
public: /* WiFiGeneric.cpp */
bool mode(WiFiMode mode);

View File

@@ -38,6 +38,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;

View File

@@ -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;
}

View File

@@ -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 (;;) {
@@ -36,7 +36,7 @@ int main(void) {
// print a startup banner
LT_BANNER();
// initialize Arduino framework
init();
initArduino();
// initialize C library
__libc_init_array();
// optionally initialize per-variant code
@@ -46,7 +46,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_E("Couldn't start the main task");
}
while (1) {}
return 0;

View File

@@ -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)
@@ -26,4 +28,7 @@ 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_BK7231T, 0x1A), // *SCTRL_CHIP_ID = 0x7231a
BK7231N = CHIP_TYPE(F_BK7231N, 0x1C), // *SCTRL_CHIP_ID = 0x7231c
};

View File

@@ -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

View File

@@ -98,7 +98,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
*/

View File

@@ -114,7 +114,9 @@ class LibreTuya {
*/
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();
/**

View File

@@ -54,6 +54,23 @@
#define LT_LOG_ERRNO 0
#endif
// Serial output options
#ifndef LT_UART_SILENT_ENABLED
#define LT_UART_SILENT_ENABLED 1
#endif
#ifndef LT_UART_SILENT_ALL
#define LT_UART_SILENT_ALL 0
#endif
#ifndef LT_UART_DEFAULT_LOGGER
#define LT_UART_DEFAULT_LOGGER LT_UART_DEFAULT_PORT
#endif
#ifndef LT_UART_DEFAULT_SERIAL
#define LT_UART_DEFAULT_SERIAL LT_UART_DEFAULT_PORT
#endif
// Per-module debugging
#ifndef LT_DEBUG_WIFI
#define LT_DEBUG_WIFI 0
@@ -78,3 +95,7 @@
#ifndef LT_DEBUG_SSL
#define LT_DEBUG_SSL 0
#endif
#ifndef LT_DEBUG_OTA
#define LT_DEBUG_OTA 0
#endif

View File

@@ -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,7 @@ 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);
#define PIN_NONE (1 << 0)
#define PIN_GPIO (1 << 1)

View File

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

View File

@@ -3,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;
}

View File

@@ -13,6 +13,18 @@ void lt_log(const uint8_t level, const char *caller, const unsigned short line,
void lt_log(const uint8_t level, const char *format, ...);
#endif
/**
* @brief Change log output port.
*
* @param port UART port index - can be 0, 1 or 2
*/
void lt_log_set_port(uint8_t port);
/**
* @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__)
@@ -173,3 +185,8 @@ void lt_log(const uint8_t level, const char *format, ...);
#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__)
// Update.cpp
#define LT_T_OTA(...) LT_T_MOD(LT_DEBUG_OTA, __VA_ARGS__)
#define LT_V_OTA(...) LT_T_MOD(LT_DEBUG_OTA, __VA_ARGS__)
#define LT_D_OTA(...) LT_D_MOD(LT_DEBUG_OTA, __VA_ARGS__)

View File

@@ -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

View File

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

View File

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

View File

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

View File

@@ -18,6 +18,8 @@ bool UpdateClass::begin(size_t size, int command, int unused2, uint8_t unused3,
return false;
cleanup();
LT_D_OTA("begin(%u, ...) / OTA curr: %u, trgt: %u", size, LT.otaGetRunning(), LT.otaGetTarget());
ctx = uf2_ctx_init(LT.otaGetTarget(), FAMILY);
info = uf2_info_init();
@@ -70,6 +72,8 @@ size_t UpdateClass::write(uint8_t *data, size_t len) {
// 0 if not running
return 0;
LT_D_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,7 +86,7 @@ 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())
@@ -141,6 +145,8 @@ size_t UpdateClass::writeStream(Stream &data) {
size_t UpdateClass::tryWriteData(uint8_t *data, size_t len) {
uf2_block_t *block = NULL;
LT_V_OTA("Writing %u to buffer (%u/512)", len, bufSize());
if (len == UF2_BLOCK_SIZE) {
// data has a complete block
block = (uf2_block_t *)data;
@@ -172,11 +178,14 @@ size_t UpdateClass::tryWriteData(uint8_t *data, size_t len) {
// header is invalid
return 0;
LT_I("OTA: %s v%s - LT v%s @ %s", info->fw_name, info->fw_version, info->lt_version, info->board);
if (bytesTotal == UPDATE_SIZE_UNKNOWN) {
// set total update size from block count info
bytesTotal = block->block_count * UF2_BLOCK_SIZE;
} else if (bytesTotal != block->block_count * UF2_BLOCK_SIZE) {
// given update size does not match the block count
LT_D_OTA("Image size wrong; got %u, calculated %u", bytesTotal, block->block_count * UF2_BLOCK_SIZE);
return errorArd(UPDATE_ERROR_SIZE);
}
} else {

View File

@@ -2,8 +2,7 @@
#include <Arduino.h>
#include <functional>
#include "uf2ota/uf2ota.h"
#include <uf2ota/uf2ota.h>
// No Error
#define UPDATE_ERROR_OK (0)
@@ -119,7 +118,7 @@ class UpdateClass {
}
void clearError() {
errorUf2(UF2_ERR_OK);
errorArd(UPDATE_ERROR_OK);
}
bool hasError() {

View File

@@ -52,6 +52,8 @@ void UpdateClass::cleanup() {
* @return true if err is not OK, false otherwise
*/
bool UpdateClass::errorUf2(uf2_err_t err) {
if (err)
LT_D_OTA("[%4d] errorUf2(%d)", ctx ? ctx->seq : 0, err);
if (err <= UF2_ERR_IGNORE)
return false;
cleanup();
@@ -67,6 +69,8 @@ bool UpdateClass::errorUf2(uf2_err_t err) {
* @return false - always
*/
bool UpdateClass::errorArd(uint8_t err) {
if (err)
LT_D_OTA("[%4d] errorArd(%d)", ctx ? ctx->seq : 0, err);
cleanup();
errUf2 = UF2_ERR_OK;
errArd = err;
@@ -77,6 +81,7 @@ bool UpdateClass::errorArd(uint8_t err) {
* @brief Abort the update with UPDATE_ERROR_ABORT reason.
*/
void UpdateClass::abort() {
LT_D_OTA("Aborting update");
errorArd(UPDATE_ERROR_ABORT);
}
@@ -105,7 +110,7 @@ void UpdateClass::printError(Print &out) {
* "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;

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -61,6 +61,7 @@ bool mDNS::begin(const char *hostname) {
struct netif *netif = netif_list;
uint8_t enabled = 0;
while (netif != NULL) {
netif->flags |= NETIF_FLAG_IGMP;
// 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) {
@@ -100,7 +101,7 @@ bool mDNS::addService(char *service, char *proto, uint16_t port) {
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);
mdns_resp_add_service(netif, mdnsInstanceName.c_str(), _service, protocol, port, 255, NULL, NULL);
}
netif = netif->next;
}

View File

@@ -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); \

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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();
};

View File

@@ -43,6 +43,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;
}

View 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;
}

View 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

View File

@@ -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]);

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -0,0 +1,5 @@
/* Copyright (c) Kuba Szczodrzyński 2022-07-03. */
#pragma once
#include <api/SoftwareSerial.h>

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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);
@@ -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;
}

View File

@@ -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);

View File

@@ -1,6 +1,25 @@
<!-- 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 - RTL8710BN (2M/468k)](../boards/generic-rtl8710bn-2mb-468k/README.md)
- [Generic - RTL8710BN (2M/788k)](../boards/generic-rtl8710bn-2mb-788k/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)
- [CB2S](../boards/cb2s/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)

View File

@@ -0,0 +1,24 @@
{
"build": {
"bkcrypt_coeffs": "510fb093a3cbeadc5993a17ec7adeb03",
"bkboot_version": "1.0.1-bk7231n",
"bkrbl_size_app": "0x107800"
},
"flash": {
"bootloader": "0x000000+0x11000",
"app": "0x011000+0x119000",
"download": "0x12A000+0xA6000",
"tlv": "0x1D0000+0x1000",
"net": "0x1D1000+0x2000",
"kvs": "0x1D3000+0x8000",
"userdata": "0x1DB000+0x25000"
},
"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."
]
}
}

View File

@@ -0,0 +1,17 @@
{
"build": {
"family": "BK7231N",
"ldscript_sdk": "bk7231n_bsp.ld",
"ldscript_arduino": "bk7231n_bsp.ld"
},
"upload": {
"speed": 460800
},
"doc": {
"params": {
"extra": {
"Bluetooth": "BLE v5.1"
}
}
}
}

View File

@@ -4,6 +4,9 @@
"ldscript_sdk": "bk7231_bsp.ld",
"ldscript_arduino": "bk7231_bsp.ld"
},
"upload": {
"speed": 921600
},
"doc": {
"params": {
"extra": {

View File

@@ -1,7 +1,13 @@
{
"build": {
"f_cpu": "120000000L",
"prefix": "arm-none-eabi-"
"prefix": "arm-none-eabi-",
"bkota": {
"encryption": "aes256",
"compression": "gzip",
"key": "0123456789ABCDEF0123456789ABCDEF",
"iv": "0123456789ABCDEF"
}
},
"connectivity": [
"wifi",
@@ -25,7 +31,6 @@
"maximum_ram_size": 262144,
"flash_size": 2097152,
"require_upload_port": true,
"speed": 921600,
"protocol": "uart",
"protocols": [
"uart"
@@ -42,7 +47,7 @@
},
"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"
}
}

View File

@@ -0,0 +1,7 @@
{
"pcb": {
"symbol": "GENERIC",
"templates": [],
"vars": {}
}
}

View File

@@ -0,0 +1,79 @@
{
"pcb": {
"templates": [
"esp12s",
"esp12s-shield",
"rf-16mm-type1"
],
"vars": {
"MASK_PRESET": "mask_black",
"TRACE_COLOR": "#FAFD9D",
"SILK_COLOR": "white",
"PINTYPE_VERT": "pin_vert_2mm_cast_nohole"
},
"pinout_hidden": "I2S,TRIG,WAKE,CTS,RTS,SD",
"pinout": {
"1": {
"IC": 38,
"ARD": "D0"
},
"2": {
"IC": 39,
"ARD": "D1"
},
"3": {
"IC": 14
},
"4": {
"IC": 18,
"ARD": "D2"
},
"5": {
"IC": 36,
"ARD": "D3"
},
"6": {
"IC": 20,
"ARD": "D4"
},
"7": {
"IC": 40,
"ARD": "D5"
},
"8": {
"PWR": 3.3
},
"9": {
"GND": null
},
"10": {
"IC": 1,
"ARD": "D6"
},
"11": {
"IC": 37,
"ARD": "D7"
},
"12": {
"IC": 15,
"ARD": "D8"
},
"13": {
"IC": 19,
"ARD": "D9"
},
"14": {
"IC": 16,
"ARD": "D10"
},
"15": {
"IC": 33,
"ARD": "D11"
},
"16": {
"IC": 34,
"ARD": "D12"
}
}
}
}

View File

@@ -0,0 +1,60 @@
{
"pcb": {
"scale": 11,
"test_pads": {
"TTX2": "cb2s.back.u2_txd.anchor",
"TRX2": "cb2s.back.u2_rxd.anchor",
"TCSN": "cb2s.back.csn.anchor"
},
"back": [
{
"type": "rect",
"pos": "6.0,8.9",
"size": "2.9,2.9",
"preset": "copper1"
},
{
"id": "u2_txd",
"name": "label_line_2mm_up",
"pos": "6.7,6.1",
"vars": {
"DIR": "left",
"W": 2.5,
"H": 0
}
},
{
"name": "test_pad_1mm",
"pos": "7.5,6.0"
},
{
"id": "u2_rxd",
"name": "label_line_2mm_up",
"pos": "6.2,8.1",
"vars": {
"DIR": "left",
"W": 2.0,
"H": 0
}
},
{
"name": "test_pad_1mm",
"pos": "7.0,8.0"
},
{
"id": "csn",
"name": "label_line_2mm_up",
"pos": "4.2,11.1",
"vars": {
"DIR": "left",
"W": 0,
"H": 0
}
},
{
"name": "test_pad_1mm",
"pos": "5.0,11.0"
}
]
}
}

View File

@@ -0,0 +1,73 @@
{
"pcb": {
"templates": [
"tuya2",
"rf-15mm-type1",
"tuya2-shield"
],
"vars": {
"MASK_PRESET": "mask_blue_light",
"TRACE_COLOR": "#58839B",
"SILK_COLOR": "white"
},
"pinout_hidden": "I2S,JTAG,FLASH",
"pinout": {
"1": {
"PWR": 3.3
},
"2": {
"IC": 22,
"ARD": "D0"
},
"3": {
"GND": null
},
"4": {
"IC": 23,
"ARD": "D1"
},
"5": {
"IC": 26,
"ARD": "D4"
},
"6": {
"IC": 24,
"ARD": "D2"
},
"7": {
"IC": 27,
"ARD": "D5"
},
"8": {
"IC": 17,
"ARD": [
"D3",
"A0"
]
},
"9": {
"IC": 16,
"ARD": "D6"
},
"10": {
"IC": 21
},
"11": {
"IC": 15,
"ARD": "D7"
},
"TRX2": {
"IC": 28,
"ARD": "D9"
},
"TTX2": {
"IC": 29,
"ARD": "D8"
},
"TCSN": {
"IC": 19,
"ARD": "D10"
}
}
}
}

View File

@@ -0,0 +1,186 @@
{
"pcb": {
"ic": {
"1": {
"C_NAME": "PIN_A20",
"GPIO": "PA20",
"IRQ": null,
"SD": "D1",
"SPI":
"0_MISO"
,
"UART": "2_RTS",
"I2C": "0_SDA",
"PWM": 0
},
"3": {
"C_NAME": "PIN_A23",
"GPIO": "PA23",
"IRQ": null,
"PWM": 7
},
"14": {
"IO": "I",
"CTRL": "CEN"
},
"15": {
"C_NAME": "PIN_A0",
"GPIO": "PA00",
"IRQ": null,
"JTAG": "TCK",
"UART": "1_RX",
"PWM": 0,
"SWD": "CLK"
},
"16": {
"C_NAME": "PIN_A1",
"GPIO": "PA01",
"IRQ": null,
"JTAG": "TMS",
"UART": "1_TX",
"PWM": 1,
"SWD": "DIO"
},
"18": {
"C_NAME": "PIN_A2",
"GPIO": "PA02",
"IRQ": null,
"JTAG": "TDO",
"UART": "1_RX",
"SPI": "0_CS",
"I2C": "0_SCL",
"PWM": 2
},
"19": {
"C_NAME": "PIN_A3",
"GPIO": "PA03",
"IRQ": null,
"JTAG": "TDI",
"UART": "1_TX",
"SPI": "0_SCK",
"I2C": "0_SDA",
"PWM": 3
},
"20": {
"C_NAME": "PIN_A4",
"GPIO": "PA04",
"IRQ": null,
"JTAG": "tRST",
"UART": "1_CTS",
"SPI": "0_MOSI",
"PWM": 4
},
"21": {
"C_NAME": "PIN_A7",
"GPIO": "PA07",
"IRQ": null,
"FLASH": "^FCS",
"SPI": "0_CS"
},
"22": {
"C_NAME": "PIN_A8",
"GPIO": "PA08",
"IRQ": null,
"FLASH": "FSCK",
"SPI": "0_SCK"
},
"23": {
"C_NAME": "PIN_A9",
"GPIO": "PA09",
"IRQ": null,
"FLASH": "FD2",
"SPI": "0_MOSI",
"UART": "0_RTS"
},
"24": {
"C_NAME": "PIN_A10",
"GPIO": "PA10",
"IRQ": null,
"FLASH": "FD1",
"SPI": "0_MISO",
"UART": "0_CTS"
},
"25": {
"C_NAME": "PIN_A11",
"GPIO": "PA11",
"IRQ": null,
"FLASH": "FD0",
"UART": "0_TX",
"I2C": "0_SCL",
"PWM": 0
},
"26": {
"C_NAME": "PIN_A12",
"GPIO": "PA12",
"IRQ": null,
"FLASH": "FD3",
"UART": "0_RX",
"I2C": "0_SDA",
"PWM": 1
},
"30": {
"IO": "I",
"C_NAME": "VBAT_IN"
},
"33": {
"C_NAME": "PIN_A13",
"GPIO": "PA13",
"IRQ": null,
"UART": "0_RX",
"PWM": 7
},
"34": {
"C_NAME": "PIN_A14",
"GPIO": "PA14",
"IRQ": null,
"SD": "INT",
"UART": "0_TX",
"PWM": 2
},
"36": {
"C_NAME": "PIN_A15",
"GPIO": "PA15",
"IRQ": null,
"SD": "D2",
"SPI": "0_CS",
"UART": "2_RX",
"I2C": "0_SCL",
"PWM": 3
},
"37": {
"C_NAME": "PIN_A16",
"GPIO": "PA16",
"IRQ": null,
"SD": "D3",
"SPI": "0_SCK",
"UART": "2_TX",
"I2C": "0_SDA",
"PWM": 4
},
"38": {
"C_NAME": "PIN_A17",
"GPIO": "PA17",
"IRQ": null,
"SD": "CMD",
"PWM": 5
},
"39": {
"C_NAME": "PIN_A18",
"GPIO": "PA18",
"IRQ": null,
"SD": "CLK",
"PWM": 6
},
"40": {
"C_NAME": "PIN_A19",
"GPIO": "PA19",
"IRQ": null,
"SD": "D0",
"SPI": "0_MOSI",
"UART": "2_CTS",
"I2C": "0_SCL",
"PWM": 7
}
}
}
}

View File

@@ -0,0 +1,102 @@
{
"pcb": {
"templates": [
"custom-20x24-22",
"rf-20mm-type1"
],
"vars": {
"MASK_PRESET": "mask_blue_light",
"TRACE_COLOR": "#58839B",
"SILK_COLOR": "white",
"PINTYPE_VERT": "pin_vert_2mm_cast_nohole",
"PINTYPE_HORZ": "pin_horz_2mm_cast_nohole"
},
"pinout_hidden": "I2S,JTAG,FLASH,SD,SPI,SDA1",
"pinout": {
"1": {
"PWR": 3.3
},
"2": {
"IC": 15,
"ARD": "D0"
},
"3": {
"IC": 11,
"ARD": "D1"
},
"4": {
"IC": 12,
"ARD": "D2"
},
"5": {
"IC": 16,
"ARD": "D3"
},
"6": {
"GND": null
},
"7": {
"IC": 18,
"ARD": "D4"
},
"8": {
"IC": 29,
"ARD": "D5"
},
"9": {
"IC": 17,
"ARD": [
"D6",
"A0"
]
},
"10": {
"CTRL": "?"
},
"11": {
"GND": null
},
"12": {
"IC": 24,
"ARD": "D7"
},
"13": {
"IC": 25,
"ARD": "D8"
},
"14": {
"GND": null
},
"15": {
"IC": 19,
"ARD": "D9"
},
"16": {
"IC": 22,
"ARD": "D10"
},
"17": {
"IC": 23,
"ARD": "D11"
},
"18": {
"IC": 26,
"ARD": "D12"
},
"19": {
"GND": null
},
"20": {
"IC": 27,
"ARD": "D13"
},
"21": {
"CTRL": "?"
},
"22": {
"IC": 28,
"ARD": "D14"
}
}
}
}

View File

@@ -0,0 +1,158 @@
{
"pcb": {
"test_pads": {
"TRST": "wb2s.back.cen.anchor",
"TRX2": "wb2s.back.2rx.anchor",
"TTX2": "wb2s.back.2tx.anchor",
"TGND": "wb2s.back.gnd.anchor",
"TSCK": "wb2s.back.sck.anchor",
"TCSN": "wb2s.back.csn.anchor",
"TSI": "wb2s.back.si.anchor",
"TSO": "wb2s.back.adc_so.anchor",
"TPWM3": "wb2s.back.pwm3.anchor",
"TVCC": "wb2s.back.vbat.anchor"
},
"back": [
{
"name": "test_pad_1mm",
"pos": "2.6,6.2"
},
{
"id": "sck",
"name": "label_line_2mm_up",
"pos": "2.6,5.4",
"vars": {
"DIR": "left",
"W": 1.3,
"H": 2
}
},
{
"name": "test_pad_1mm",
"pos": "4.6,6.2"
},
{
"id": "pwm3",
"name": "label_line_2mm_up",
"pos": "4.6,5.4",
"vars": {
"DIR": "left",
"W": 3.3,
"H": 4
}
},
{
"name": "test_pad_1mm",
"pos": "7.0,6.2"
},
{
"id": "2rx",
"name": "label_line_2mm_up",
"pos": "7.0,5.4",
"vars": {
"DIR": "right",
"W": 2,
"H": 4
}
},
{
"name": "test_pad_1mm",
"pos": "9.0,6.2"
},
{
"id": "2tx",
"name": "label_line_2mm_up",
"pos": "9.0,5.4",
"vars": {
"DIR": "right",
"W": 0,
"H": 2
}
},
{
"name": "test_pad_1mm",
"pos": "3.0,8.3"
},
{
"id": "csn",
"name": "label_line_2mm_up",
"pos": "2.2,8.4",
"vars": {
"DIR": "left",
"W": 0.9,
"H": 0
}
},
{
"name": "test_pad_1mm",
"pos": "5.2,8.8"
},
{
"id": "si",
"name": "label_line_2mm_up",
"pos": "6.0,8.9",
"vars": {
"DIR": "right",
"W": 3,
"H": 0
}
},
{
"name": "test_pad_1mm",
"pos": "2.1,11.6"
},
{
"id": "adc_so",
"name": "label_line_2mm_up",
"pos": "1.3,11.7",
"vars": {
"DIR": "left",
"W": 0,
"H": 0
}
},
{
"name": "test_pad_1mm",
"pos": "4.3,11.6"
},
{
"id": "cen",
"name": "label_line_2mm_up",
"pos": "5.1,11.7",
"vars": {
"DIR": "right",
"W": 3.9,
"H": 0
}
},
{
"name": "test_pad_1mm",
"pos": "2.5,14.5"
},
{
"id": "vbat",
"name": "label_line_2mm_up",
"pos": "1.7,14.6",
"vars": {
"DIR": "left",
"W": 0.4,
"H": 0
}
},
{
"name": "test_pad_1mm",
"pos": "4.8,14.5"
},
{
"id": "gnd",
"name": "label_line_2mm_up",
"pos": "5.6,14.6",
"vars": {
"DIR": "right",
"W": 3.4,
"H": 0
}
}
]
}
}

102
boards/_base/pcb/wb2s.json Normal file
View File

@@ -0,0 +1,102 @@
{
"pcb": {
"scale": 10.5,
"templates": [
"tuya2",
"rf-15mm-type1",
"tuya2-shield"
],
"vars": {
"MASK_PRESET": "mask_blue_light",
"TRACE_COLOR": "#58839B",
"SILK_COLOR": "white"
},
"pinout_hidden": "I2S,FLASH",
"pinout": {
"1": {
"PWR": 3.3
},
"2": {
"IC": 24,
"ARD": "D0"
},
"3": {
"GND": null
},
"4": {
"IC": 23,
"ARD": "D1"
},
"5": {
"IC": 26,
"ARD": "D4"
},
"6": {
"IC": 22,
"ARD": "D2"
},
"7": {
"IC": 27,
"ARD": "D5"
},
"8": {
"IC": 17,
"ARD": [
"D3",
"A0"
]
},
"9": {
"IC": 16,
"ARD": "D6"
},
"10": {
"IC": 21
},
"11": {
"IC": 15,
"ARD": "D7"
},
"TSCK": {
"IC": 20,
"ARD": "D8"
},
"TPWM3": {
"IC": 25,
"ARD": "D9"
},
"TRX2": {
"IC": 28,
"ARD": "D10"
},
"TTX2": {
"IC": 29,
"ARD": "D11"
},
"TCSN": {
"IC": 19,
"ARD": "D12"
},
"TSI": {
"IC": 18,
"ARD": "D13"
},
"TSO": {
"IC": 17,
"ARD": [
"D3",
"A0"
]
},
"TRST": {
"CTRL": "^RST"
},
"TVCC": {
"PWR": 3.3
},
"TGND": {
"GND": null
}
}
}
}

106
boards/_base/pcb/wb3l.json Normal file
View File

@@ -0,0 +1,106 @@
{
"pcb": {
"templates": [
"esp12e-21",
"esp12e-shield-nohole",
"tuya-16x24",
"rf-16mm-type1"
],
"vars": {
"MASK_PRESET": "mask_white",
"TRACE_COLOR": "#E0E0E0",
"SILK_COLOR": "black",
"PINTYPE_VERT": "pin_vert_2mm_cast_nohole",
"PINTYPE_HORZ": "pin_horz_2mm_cast_nohole"
},
"pinout_hidden": "I2S,SD,SPI",
"pinout": {
"1": {
"NC": null
},
"2": {
"IC": 17,
"ARD": [
"D0",
"A0"
]
},
"3": {
"IC": 21
},
"4": {
"IC": 11,
"ARD": "D1"
},
"5": {
"IC": 15,
"ARD": "D2"
},
"6": {
"IC": 16,
"ARD": "D3"
},
"7": {
"IC": 22,
"ARD": "D4"
},
"8": {
"PWR": 3.3
},
"9": {
"GND": null
},
"10": {
"IC": 25,
"ARD": "D5"
},
"11": {
"IC": 29,
"ARD": "D6"
},
"12": {
"IC": 12,
"ARD": "D7"
},
"13": {
"IC": 24,
"ARD": "D8"
},
"14": {
"IC": 23,
"ARD": "D9"
},
"15": {
"IC": 26,
"ARD": "D10"
},
"16": {
"IC": 27,
"ARD": "D11"
},
"17": {
"IC": 17,
"ARD": [
"D0",
"A0"
]
},
"18": {
"IC": 18,
"ARD": "D12"
},
"19": {
"IC": 19,
"ARD": "D13"
},
"20": {
"IC": 20,
"ARD": "D14"
},
"21": {
"IC": 28,
"ARD": "D15"
}
}
}
}

108
boards/_base/pcb/wb3s.json Normal file
View File

@@ -0,0 +1,108 @@
{
"pcb": {
"templates": [
"esp12e-22",
"esp12e-shield-nohole",
"tuya-16x24",
"rf-16mm-type1"
],
"vars": {
"MASK_PRESET": "mask_blue_light",
"TRACE_COLOR": "#58839B",
"SILK_COLOR": "white",
"PINTYPE_VERT": "pin_vert_2mm_cast_nohole",
"PINTYPE_HORZ": "pin_horz_2mm_cast_nohole"
},
"pinout_hidden": "I2S,SD,SPI",
"pinout": {
"1": {
"IC": 21
},
"2": {
"IC": 17,
"ARD": [
"D0",
"A0"
]
},
"3": {
"NC": null
},
"4": {
"IC": 11,
"ARD": "D1"
},
"5": {
"IC": 15,
"ARD": "D2"
},
"6": {
"IC": 16,
"ARD": "D3"
},
"7": {
"IC": 22,
"ARD": "D4"
},
"8": {
"PWR": 3.3
},
"9": {
"GND": null
},
"10": {
"IC": 23,
"ARD": "D5"
},
"11": {
"IC": 29,
"ARD": "D6"
},
"12": {
"IC": 28,
"ARD": "D7"
},
"13": {
"IC": 25,
"ARD": "D8"
},
"14": {
"IC": 24,
"ARD": "D9"
},
"15": {
"IC": 26,
"ARD": "D10"
},
"16": {
"IC": 27,
"ARD": "D11"
},
"17": {
"IC": 17,
"ARD": [
"D0",
"A0"
]
},
"18": {
"IC": 18,
"ARD": "D12"
},
"19": {
"IC": 19,
"ARD": "D13"
},
"20": {
"IC": 20,
"ARD": "D14"
},
"21": {
"NC": null
},
"22": {
"NC": null
}
}
}
}

View File

@@ -0,0 +1,14 @@
{
"pcb": {
"templates": [
"tuya2",
"rf-15mm-type1",
"tuya2-shield"
],
"vars": {
"MASK_PRESET": "mask_blue_light",
"TRACE_COLOR": "#58839B",
"SILK_COLOR": "white"
}
}
}

49
boards/_base/pcb/wr2.json Normal file
View File

@@ -0,0 +1,49 @@
{
"pcb": {
"scale": 10.5,
"pinout_hidden": "I2S,TRIG,WAKE,CTS,RTS,SD,SPI",
"pinout": {
"1": {
"PWR": 3.3
},
"2": {
"IC": 17,
"ARD": "D0"
},
"3": {
"GND": null
},
"4": {
"IC": 16,
"ARD": "D1"
},
"5": {
"IC": 29,
"ARD": "D4"
},
"6": {
"IC": 28,
"ARD": "D2"
},
"7": {
"IC": 32,
"ARD": "D5"
},
"8": {
"IC": 27,
"ARD": "A1"
},
"9": {
"IC": 13,
"ARD": "D6"
},
"10": {
"IC": 12
},
"11": {
"IC": 14,
"ARD": "D7"
}
}
}
}

View File

@@ -0,0 +1,52 @@
{
"pcb": {
"scale": 10.5,
"pinout_hidden": "I2S,TRIG,WAKE,CTS,RTS,SD,SPI,SDA0",
"pinout": {
"1": {
"PWR": 3.3
},
"2": {
"IC": 17,
"ARD": "D0"
},
"3": {
"GND": null
},
"4": {
"IC": 30,
"ARD": [
"D1",
"A0"
]
},
"5": {
"IC": 29,
"ARD": "D3"
},
"6": {
"IC": 28,
"ARD": "D2"
},
"7": {
"IC": 32,
"ARD": "D4"
},
"8": {
"IC": 27,
"ARD": "A1"
},
"9": {
"IC": 13,
"ARD": "D5"
},
"10": {
"IC": 12
},
"11": {
"IC": 14,
"ARD": "D6"
}
}
}
}

View File

@@ -0,0 +1,15 @@
{
"pcb": {
"templates": [
"tuya2l",
"rf-15mm-type1",
"tuya2l-shield"
],
"vars": {
"MASK_PRESET": "mask_blue_light",
"TRACE_COLOR": "#58839B",
"SILK_COLOR": "white",
"PINTYPE_HORZ": "pin_horz_2mm_cast_hole"
}
}
}

View File

@@ -0,0 +1,36 @@
{
"pcb": {
"pinout_hidden": "I2S,TRIG,WAKE,CTS,RTS,SD,SPI,I2C",
"pinout": {
"1": {
"IC": 14,
"ARD": "D0"
},
"2": {
"IC": 13,
"ARD": "D1"
},
"3": {
"IC": 28,
"ARD": "D2"
},
"4": {
"IC": 30,
"ARD": [
"D3",
"A0"
]
},
"5": {
"IC": 17,
"ARD": "D4"
},
"6": {
"GND": null
},
"7": {
"PWR": 3.3
}
}
}
}

View File

@@ -0,0 +1,33 @@
{
"pcb": {
"pinout_hidden": "I2S,TRIG,WAKE,CTS,RTS,SD,SPI,I2C",
"pinout": {
"1": {
"IC": 14,
"ARD": "D0"
},
"2": {
"IC": 13,
"ARD": "D1"
},
"3": {
"IC": 28,
"ARD": "D2"
},
"4": {
"IC": 31,
"ARD": "D3"
},
"5": {
"IC": 17,
"ARD": "D4"
},
"6": {
"GND": null
},
"7": {
"PWR": 3.3
}
}
}
}

View File

@@ -0,0 +1,16 @@
{
"pcb": {
"templates": [
"esp12s",
"esp12s-shield",
"tuya-16x24",
"rf-16mm-type1"
],
"vars": {
"MASK_PRESET": "mask_black",
"TRACE_COLOR": "#505050",
"SILK_COLOR": "white",
"PINTYPE_VERT": "pin_vert_2mm_cast_nohole"
}
}
}

View File

@@ -1,17 +1,5 @@
{
"pcb": {
"templates": [
"esp12s",
"esp12s-shield",
"tuya-16x24",
"rf-16mm-type1"
],
"vars": {
"MASK_PRESET": "mask_black",
"TRACE_COLOR": "#505050",
"SILK_COLOR": "white",
"PINTYPE_VERT": "pin_vert_2mm_cast_nohole"
},
"pinout_hidden": "I2S,TRIG,WAKE,CTS,RTS,SD",
"pinout": {
"1": {

View File

@@ -1,16 +1,9 @@
{
"pcb": {
"templates": [
"esp12s",
"esp12s-shield",
"tuya-16x24",
"rf-16mm-type1"
],
"vars": {
"MASK_PRESET": "mask_black",
"TRACE_COLOR": "#505050",
"SILK_COLOR": "white",
"PINTYPE_VERT": "pin_vert_2mm_cast_nohole"
"MASK_PRESET": "mask_blue_light",
"TRACE_COLOR": "#58839B",
"SILK_COLOR": "white"
},
"pinout_hidden": "I2S,TRIG,WAKE,CTS,RTS,SD",
"pinout": {
@@ -26,19 +19,19 @@
},
"4": {
"IC": 2,
"ARD": "D5"
"ARD": "D0"
},
"5": {
"IC": 13,
"ARD": "D2"
"ARD": "D1"
},
"6": {
"IC": 14,
"ARD": "D3"
"ARD": "D2"
},
"7": {
"IC": 31,
"ARD": "D0"
"ARD": "D3"
},
"8": {
"PWR": 3.3
@@ -52,12 +45,12 @@
},
"11": {
"IC": 1,
"ARD": "D6"
"ARD": "D5"
},
"12": {
"IC": 30,
"ARD": [
"D1",
"D6",
"A0"
]
},

View File

@@ -0,0 +1,16 @@
{
"pcb": {
"templates": [
"esp12s",
"esp12e-shield",
"tuya-16x24",
"rf-16mm-type1"
],
"vars": {
"MASK_PRESET": "mask_white",
"TRACE_COLOR": "#E0E0E0",
"SILK_COLOR": "black",
"PINTYPE_VERT": "pin_vert_2mm_cast_hole"
}
}
}

View File

@@ -0,0 +1,65 @@
{
"pcb": {
"pinout_hidden": "I2S,TRIG,WAKE,CTS,RTS,SD,SPI",
"pinout": {
"1": {
"NC": null
},
"2": {
"IC": 27,
"ARD": "A1"
},
"3": {
"IC": 12
},
"4": {
"IC": 2,
"ARD": "D0"
},
"5": {
"IC": 13,
"ARD": "D1"
},
"6": {
"IC": 14,
"ARD": "D2"
},
"7": {
"IC": 16,
"ARD": "D3"
},
"8": {
"PWR": 3.3
},
"9": {
"GND": null
},
"10": {
"NC": null
},
"11": {
"IC": 1,
"ARD": "D4"
},
"12": {
"NC": null
},
"13": {
"IC": 28,
"ARD": "D5"
},
"14": {
"IC": 17,
"ARD": "D6"
},
"15": {
"IC": 29,
"ARD": "D7"
},
"16": {
"IC": 32,
"ARD": "D8"
}
}
}
}

View File

@@ -5,10 +5,6 @@
"amb_boot_all": "boot_all_77F7.bin"
},
"flash": {
"boot_xip": "0x000000+0x4000",
"boot_ram": "0x004000+0x4000",
"system": "0x009000+0x1000",
"calibration": "0x00A000+0x1000",
"ota1": "0x00B000+0x75000",
"ota2": "0x080000+0x75000",
"kvs": "0xF5000+0x6000",

View File

@@ -5,10 +5,6 @@
"amb_boot_all": "boot_all_77F7.bin"
},
"flash": {
"boot_xip": "0x000000+0x4000",
"boot_ram": "0x004000+0x4000",
"system": "0x009000+0x1000",
"calibration": "0x00A000+0x1000",
"ota1": "0x00B000+0xC5000",
"ota2": "0x0D0000+0xC5000",
"kvs": "0x195000+0x6000",

View File

@@ -5,6 +5,12 @@
"prefix": "arm-none-eabi-",
"amb_flash_addr": "0x08000000"
},
"flash": {
"boot_xip": "0x000000+0x4000",
"boot_ram": "0x004000+0x4000",
"system": "0x009000+0x1000",
"calibration": "0x00A000+0x1000"
},
"connectivity": [
"wifi"
],
@@ -43,7 +49,8 @@
"links": {
"General info": "../../docs/platform/realtek/README.md",
"Debugging": "../../docs/platform/realtek/debugging.md",
"Flashing (Tuya manual)": "https://developer.tuya.com/en/docs/iot/burn-and-authorize-wr-series-modules?id=Ka789pjc581u8"
"Flashing guide": "../../docs/platform/realtek-ambz/flashing.md",
"ImageTool (AmebaZ/AmebaD)": "https://images.tuyacn.com/smart/Image_Tool/Image_Tool.zip"
},
"extra": [
"RDP is most likely not used in Tuya firmwares, as the System Data partition contains an incorrect offset 0xFF000 for RDP, which is in the middle of OTA2 image.",

View File

@@ -0,0 +1,12 @@
{
"flash": {
"ota1": "0x00C000+0xF8000",
"ota2": "0x104000+0xF8000",
"kvs": "0x1FC000+0x2000",
"userdata": "0x1FE000+0x2000"
},
"upload": {
"flash_size": 2097152,
"maximum_size": 1015808
}
}

View File

@@ -0,0 +1,12 @@
{
"connectivity": [
"wifi"
],
"doc": {
"params": {
"extra": {
"Wi-Fi": "802.11 b/g/n"
}
}
}
}

View File

@@ -0,0 +1,14 @@
{
"connectivity": [
"wifi",
"ble"
],
"doc": {
"params": {
"extra": {
"Wi-Fi": "802.11 b/g/n",
"BLE": "v4.2"
}
}
}
}

View File

@@ -0,0 +1,35 @@
{
"build": {
"family": "RTL8720C",
"f_cpu": "100000000L",
"prefix": "arm-none-eabi-",
"ldscript_sdk": "rtl8710c_ram.ld",
"ldscript_arduino": "rtl8710c_ram.ld"
},
"flash": {
"part_table": "0x000000+0x1000",
"system": "0x001000+0x1000",
"calibration": "0x002000+0x1000",
"boot": "0x004000+0x8000"
},
"debug": {
"protocol": "openocd",
"protocols": []
},
"frameworks": [
"realtek-ambz2-sdk"
],
"upload": {
"maximum_ram_size": 262144
},
"doc": {
"params": {
"manufacturer": "Realtek",
"series": "AmebaZ2",
"voltage": "3.0V - 3.6V"
},
"links": {
"General info": "../../docs/platform/realtek/README.md"
}
}
}

View File

@@ -1,7 +1,7 @@
{
"_base": [
"realtek-ambz",
"realtek-ambz-2mb-small",
"realtek-ambz-2mb-468k",
"realtek-ambz-bx",
"pcb/ic-rtl8710bn",
"pcb/bw12"

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