Compare commits
61 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a21c07fa03 | ||
|
|
bdffa7ef53 | ||
|
|
22d40825bb | ||
|
|
50f26f546c | ||
|
|
9c7ea46ec3 | ||
|
|
5b4cf53d8a | ||
|
|
79a701a4d4 | ||
|
|
81897e634c | ||
|
|
3e11da4dd4 | ||
|
|
12aa7fef04 | ||
|
|
1ea6420bbc | ||
|
|
f3f1f36525 | ||
|
|
dee9a98cc3 | ||
|
|
3345ce3fb9 | ||
|
|
de70583838 | ||
|
|
a43a737004 | ||
|
|
1f6899354f | ||
|
|
9110a0c47e | ||
|
|
b549790798 | ||
|
|
5df430f3be | ||
|
|
f3e8bcd74a | ||
|
|
4b050e11cf | ||
|
|
7ddbc09564 | ||
|
|
d3d62f80fd | ||
|
|
bc7dbe6eec | ||
|
|
e625f55353 | ||
|
|
aeebff9d5d | ||
|
|
9a3c077ef1 | ||
|
|
91ae692058 | ||
|
|
ad590d1eb2 | ||
|
|
8b00358901 | ||
|
|
bf4d8bb9be | ||
|
|
157dd2f407 | ||
|
|
1dc47878d4 | ||
|
|
36e4b6fd45 | ||
|
|
36d9a6e7e4 | ||
|
|
b7cceed4d3 | ||
|
|
694c06e7f5 | ||
|
|
12338747bf | ||
|
|
f4f9788f68 | ||
|
|
b9cdcad262 | ||
|
|
e4cd2ddec8 | ||
|
|
1477649a50 | ||
|
|
2e80469ab3 | ||
|
|
ccf63a4cdb | ||
|
|
b464871f73 | ||
|
|
e44834a95e | ||
|
|
4efefc5c6c | ||
|
|
dfd852b2db | ||
|
|
afa7141ceb | ||
|
|
ed76b23c69 | ||
|
|
a469a466ff | ||
|
|
589d3ef4d8 | ||
|
|
5aba2eb4a1 | ||
|
|
b7df8d7b37 | ||
|
|
61554e6c7e | ||
|
|
d8cc61bc0e | ||
|
|
4b6e3956d6 | ||
|
|
9659ff8afa | ||
|
|
783955cc5d | ||
|
|
048556803b |
29
.clang-format
Normal file
29
.clang-format
Normal file
@@ -0,0 +1,29 @@
|
||||
Language: Cpp
|
||||
BasedOnStyle: LLVM
|
||||
AlignAfterOpenBracket: BlockIndent
|
||||
AlignArrayOfStructures: Left
|
||||
AlignConsecutiveAssignments: true
|
||||
AlignConsecutiveMacros: AcrossComments
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: Empty
|
||||
AllowShortFunctionsOnASingleLine: Empty
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
BreakBeforeTernaryOperators: true
|
||||
ColumnLimit: 120
|
||||
ContinuationIndentWidth: 4
|
||||
EmptyLineBeforeAccessModifier: Always
|
||||
FixNamespaceComments: true
|
||||
IndentAccessModifiers: false
|
||||
IndentCaseLabels: true
|
||||
IndentWidth: 4
|
||||
LambdaBodyIndentation: Signature
|
||||
MaxEmptyLinesToKeep: 1
|
||||
# PointerAlignment: Left # TODO enable this and reformat project
|
||||
QualifierAlignment: Left
|
||||
ReflowComments: true
|
||||
SeparateDefinitionBlocks: Always
|
||||
TabWidth: 4
|
||||
UseTab: Always
|
||||
5
.github/workflows/docs.yml
vendored
5
.github/workflows/docs.yml
vendored
@@ -1,11 +1,12 @@
|
||||
name: Deploy docs on GitHub Pages
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build:
|
||||
docs:
|
||||
name: Deploy docs
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
@@ -17,5 +18,5 @@ jobs:
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
CONFIG_FILE: mkdocs.yml
|
||||
EXTRA_PACKAGES: build-base
|
||||
EXTRA_PACKAGES: build-base doxygen
|
||||
REQUIREMENTS: docs/requirements.txt
|
||||
|
||||
35
.github/workflows/lint.yml
vendored
Normal file
35
.github/workflows/lint.yml
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
name: Lint check
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
lint-clang-format:
|
||||
name: Lint with clang-format
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Check code with clang-format
|
||||
uses: jidicula/clang-format-action@v4.5.0
|
||||
with:
|
||||
clang-format-version: "14"
|
||||
lint-black:
|
||||
name: Lint with black
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: "3.9"
|
||||
- name: Install test dependencies
|
||||
uses: BSFishy/pip-action@v1
|
||||
with:
|
||||
packages: |
|
||||
black
|
||||
isort
|
||||
- name: Check code with black
|
||||
run: black --check .
|
||||
- name: Check code with isort
|
||||
run: isort --profile black . --check-only
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -252,3 +252,9 @@ cython_debug/
|
||||
# End of https://www.toptal.com/developers/gitignore/api/c,c++,visualstudiocode,python
|
||||
|
||||
.vscode/settings.json
|
||||
|
||||
# mkdocs
|
||||
xml/
|
||||
ltapi/
|
||||
ltambz/
|
||||
hashChanges.yaml
|
||||
|
||||
2
.gitmodules
vendored
Normal file
2
.gitmodules
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
[submodule "tools/boardgen"]
|
||||
url = https://github.com/kuba2k2/boardgen
|
||||
102
README.md
102
README.md
@@ -2,9 +2,14 @@
|
||||
|
||||
<div align="center" markdown>
|
||||
|
||||
[](https://kuba2k2.github.io/libretuya/)
|
||||

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

|
||||
|
||||

|
||||
|
||||
@@ -13,17 +18,17 @@
|
||||
PlatformIO development platform for IoT modules manufactured by Tuya Inc.
|
||||
|
||||
The main goal of this project is to provide a usable build environment for IoT developers. While also providing vendor SDKs as PlatformIO cores,
|
||||
the project focuses on developing working Arduino-compatible cores for supported platforms. The cores are inspired by Espressif's official core for ESP32,
|
||||
which should make it easier to port/run existing ESP apps on Tuya IoT (and 3-rd party) platforms.
|
||||
the project focuses on developing working Arduino-compatible cores for supported families. The cores are inspired by Espressif's official core for ESP32,
|
||||
which should make it easier to port/run existing ESP apps on Tuya IoT (and 3-rd party) modules.
|
||||
|
||||
LibreTuya also provides a common interface for all platform implementations. The interface is based on ESP32 official libraries.
|
||||
LibreTuya also provides a common interface for all family implementations. The interface is based on ESP32 official libraries.
|
||||
|
||||
**Note:** this project is work-in-progress.
|
||||
|
||||
## Usage
|
||||
|
||||
1. [Install PlatformIO](https://platformio.org/platformio-ide)
|
||||
2. `platformio platform install libretuya`
|
||||
2. `platformio platform install https://github.com/kuba2k2/libretuya`
|
||||
3. Create a project, build it and upload!
|
||||
4. See the [docs](https://kuba2k2.github.io/libretuya/) for any questions/problems.
|
||||
|
||||
@@ -31,7 +36,7 @@ LibreTuya also provides a common interface for all platform implementations. The
|
||||
|
||||
A (mostly) complete* list of Tuya wireless module boards.
|
||||
|
||||
| Module Name | MCU | Flash | RAM | Pins** | Wi-Fi | BLE | Platform name
|
||||
| Module Name | MCU | Flash | RAM | Pins** | Wi-Fi | BLE | Family name
|
||||
------------------------------|------------------------------------------------------------------------------------------------|-------------------------|-------|----------|-------------|-------|-----|---------------
|
||||
❌ | [WB1S](https://developer.tuya.com/en/docs/iot/wb1s?id=K9duevbj3ol4x) | BK7231T @ 120 MHz | 2 MiB | 256 KiB | 18 (11 I/O) | ✔️ | ✔️ | -
|
||||
❌ | [WB2L](https://developer.tuya.com/en/docs/iot/wb2l-datasheet?id=K9duegc9bualu) | BK7231T @ 120 MHz | 2 MiB | 256 KiB | 7 (5 I/O) | ✔️ | ✔️ | -
|
||||
@@ -87,76 +92,6 @@ A (mostly) complete* list of Tuya wireless module boards.
|
||||
|
||||
** I/O count includes GPIOs, ADCs, PWM outputs and UART, but doesn't count CEN/RST and power pins.
|
||||
|
||||
## Project structure
|
||||
|
||||
```
|
||||
arduino/
|
||||
├─ <platform name>/ Arduino Core for specific platform
|
||||
│ ├─ cores/ Core files
|
||||
│ ├─ libraries/ Supported built-in libraries
|
||||
├─ libretuya/
|
||||
│ ├─ api/ LibreTuya API for Arduino frameworks
|
||||
│ ├─ compat/ Fixes for compatibility with ESP32 framework
|
||||
│ ├─ libraries/ Built-in platform-independent libraries
|
||||
boards/
|
||||
├─ <board name>/ Board-specific code
|
||||
│ ├─ variant.cpp Arduino variant initialization
|
||||
│ ├─ variant.h Arduino variant pin configs
|
||||
├─ <board name>.json PlatformIO board description
|
||||
builder/
|
||||
├─ frameworks/ Framework builders for PlatformIO
|
||||
│ ├─ <platform name>-sdk.py Vanilla SDK build system
|
||||
│ ├─ <platform name>-arduino.py Arduino Core build system
|
||||
├─ arduino-common.py Builder to provide ArduinoCore-API and LibreTuya APIs
|
||||
├─ main.py Main PlatformIO builder
|
||||
docs/ Project documentation, guides, tips, etc.
|
||||
platform/
|
||||
├─ <platform name>/ Platform-specific configurations
|
||||
│ ├─ bin/ Binary blobs (bootloaders, etc.)
|
||||
│ ├─ fixups/ Code fix-ups to replace SDK parts
|
||||
│ ├─ ld/ Linker scripts
|
||||
│ ├─ openocd/ OpenOCD configuration files
|
||||
tools/
|
||||
├─ <tool name>/ Tools used during the build
|
||||
platform.json PlatformIO manifest
|
||||
platform.py Custom PlatformIO script
|
||||
```
|
||||
|
||||
## Platforms
|
||||
|
||||
A list of platforms currently available in this project.
|
||||
|
||||
Platform name | Supported MCU(s) | Arduino Core | Source SDK (PIO framework)
|
||||
---------------|------------------------------------------------------------------------|--------------|--------------------------------------------------------------------------
|
||||
`realtek-ambz` | Realtek [AmebaZ](https://www.amebaiot.com/en/amebaz/) SoC (`RTL87xxB`) | ✔️ | `framework-realtek-amb1` ([amb1_sdk](https://github.com/ambiot/amb1_sdk))
|
||||
|
||||
### Realtek Ameba
|
||||
|
||||
The logic behind naming of Realtek chips and their series took me some time to figure out:
|
||||
|
||||
- RTL8xxxA - Ameba1/Ameba Series
|
||||
- RTL8xxxB - AmebaZ Series
|
||||
- RTL8xxxC - AmebaZ2/ZII Series
|
||||
- RTL8xxxD - AmebaD Series
|
||||
|
||||
As such, there are numerous CPUs with the same numbers but different series, which makes them require different code and SDKs.
|
||||
|
||||
- [RTL8195AM](https://www.realtek.com/en/products/communications-network-ics/item/rtl8195am)
|
||||
- RTL8710AF (found in amb1_arduino)
|
||||
- [RTL8711AM](https://www.realtek.com/en/products/communications-network-ics/item/rtl8711am)
|
||||
- [RTL8710BN](https://www.realtek.com/en/products/communications-network-ics/item/rtl8710bn)
|
||||
- RTL8710BX (found in Tuya product pages)
|
||||
- RTL8710B? (found in amb1_sdk)
|
||||
- RTL8711B? (found in amb1_sdk)
|
||||
- [RTL8710CM](https://www.realtek.com/en/products/communications-network-ics/item/rtl8710cm)
|
||||
- RTL8722CSM (found in ambd_arduino)
|
||||
- RTL8720DN (found in ambd_arduino)
|
||||
- [RTL8721DM](https://www.realtek.com/en/products/communications-network-ics/item/rtl8721dm)
|
||||
- RTL8722DM (found in ambd_arduino)
|
||||
- and probably many more
|
||||
|
||||
Different Ameba series are not compatible with each other. Apparently, there isn't an official public SDK for AmebaZ that can support C++ properly.
|
||||
|
||||
## Arduino Core support status
|
||||
|
||||
Note: this list will probably change with each functionality update.
|
||||
@@ -171,22 +106,21 @@ Flash I/O | ❓
|
||||
**CORE LIBRARIES** |
|
||||
SoftwareSerial | ❌
|
||||
SPI | ❌
|
||||
Wire | ❌
|
||||
Wire | ❗
|
||||
**OTHER LIBRARIES** |
|
||||
Wi-Fi STA/AP/Mixed | ✔️
|
||||
Wi-Fi Client (SSL) | ✔️ (❌)
|
||||
Wi-Fi Client (SSL) | ✔️ (✔️)
|
||||
Wi-Fi Server | ✔️
|
||||
Wi-Fi Events | ❌
|
||||
Wi-Fi Events | ✔️
|
||||
IPv6 | ❌
|
||||
HTTP Client (SSL) | ✔️ (❌)
|
||||
HTTP Client (SSL) | ✔️ (✔️)
|
||||
HTTP Server | ✔️
|
||||
NVS / Preferences | ❌
|
||||
NVS / Preferences | ✔️
|
||||
SPIFFS | ❌
|
||||
BLE | -
|
||||
HTTP | ❌
|
||||
NTP | ❌
|
||||
OTA | ❌
|
||||
MDNS | ❌
|
||||
OTA | ❓
|
||||
MDNS | ✔️
|
||||
MQTT | ✅
|
||||
SD | ❌
|
||||
|
||||
|
||||
55
SUMMARY.md
Normal file
55
SUMMARY.md
Normal file
@@ -0,0 +1,55 @@
|
||||
* [Home](README.md)
|
||||
* [💻 Family list](docs/families.md)
|
||||
* [✔️ Implementation status](docs/implementation-status.md)
|
||||
* [🔧 Configuration](docs/config.md)
|
||||
* [📁 Project structure](docs/project-structure.md)
|
||||
* 🔖 Code reference
|
||||
* [LibreTuya API](docs/reference/lt-api.md)
|
||||
* [Class reference](ltapi/class_libre_tuya.md)
|
||||
* [Static functions](ltapi/_libre_tuya_a_p_i_8cpp.md)
|
||||
* [Logger](ltapi/lt__logger_8h.md)
|
||||
* [Chip types & UF2 families](ltapi/_chip_type_8h.md)
|
||||
* [POSIX utilities](ltapi/lt__posix__api_8h.md)
|
||||
* Common API
|
||||
* [Flash](ltapi/class_i_flash_class.md)
|
||||
* [FS](ltapi/classfs_1_1_f_s.md)
|
||||
* [Preferences](ltapi/class_i_preferences.md)
|
||||
* [WiFi API](ltapi/class_i_wi_fi_generic_class.md)
|
||||
* [Station](ltapi/class_i_wi_fi_s_t_a_class.md)
|
||||
* [Access Point](ltapi/class_i_wi_fi_a_p_class.md)
|
||||
* [Scanning](ltapi/class_i_wi_fi_scan_class.md)
|
||||
* [TCP Client](ltapi/class_i_wi_fi_client.md)
|
||||
* [SSL Client](ltapi/class_i_wi_fi_client_secure.md)
|
||||
* [TCP Server](ltapi/class_i_wi_fi_server.md)
|
||||
* [LibreTuya libraries](docs/libs-built-in.md)
|
||||
* [base64](ltapi/classbase64.md)
|
||||
* [HTTPClient](ltapi/class_h_t_t_p_client.md)
|
||||
* [mDNS](ltapi/classm_d_n_s.md)
|
||||
* NetUtils
|
||||
* [ssl/MbedTLSClient](ltapi/class_mbed_t_l_s_client.md)
|
||||
* [IPv6Address](ltapi/classarduino_1_1_i_pv6_address.md)
|
||||
* [LwIPRxBuffer](ltapi/class_lw_i_p_rx_buffer.md)
|
||||
* [Update](ltapi/class_update_class.md)
|
||||
* [WebServer](ltapi/class_web_server.md)
|
||||
* [WiFiMulti](ltapi/class_wi_fi_multi.md)
|
||||
* [Third party libraries](docs/libs-3rd-party.md)
|
||||
* Full documentation
|
||||
* [Classes](ltapi/classes.md)
|
||||
* [Functions](ltapi/functions.md)
|
||||
* [Macros](ltapi/macros.md)
|
||||
* [File list](ltapi/files.md)
|
||||
* [✈️ OTA format](docs/ota/README.md)
|
||||
* [uf2ota.py tool](docs/ota/uf2ota.md)
|
||||
* [uf2ota.h library](docs/ota/library.md)
|
||||
* [uf2ota.h reference](ltapi/uf2ota_8h.md)
|
||||
* Families
|
||||
* [Realtek - notes](docs/platform/realtek/README.md)
|
||||
* Realtek AmebaZ Series
|
||||
* Boards
|
||||
* [WR3](boards/wr3/README.md)
|
||||
* 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)
|
||||
* [🔗 Resources](docs/resources.md)
|
||||
5
arduino/libretuya/api/Events.cpp
Normal file
5
arduino/libretuya/api/Events.cpp
Normal file
@@ -0,0 +1,5 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-17. */
|
||||
|
||||
#include "Events.h"
|
||||
|
||||
uint16_t EventHandler_s::lastId = 1;
|
||||
117
arduino/libretuya/api/Events.h
Normal file
117
arduino/libretuya/api/Events.h
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
ESP8266WiFiGeneric.h - esp8266 Wifi support.
|
||||
Based on WiFi.h from Ardiono WiFi shield library.
|
||||
Copyright (c) 2011-2014 Arduino. All right reserved.
|
||||
Modified by Ivan Grokhotkov, December 2014
|
||||
Reworked by Markus Sattler, December 2015
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "WiFiEvents.h"
|
||||
|
||||
typedef enum {
|
||||
ARDUINO_EVENT_WIFI_READY = 0, /**< ESP32 WiFi ready */
|
||||
ARDUINO_EVENT_WIFI_SCAN_DONE, /**< ESP32 finish scanning AP */
|
||||
ARDUINO_EVENT_WIFI_STA_START, /**< ESP32 station start */
|
||||
ARDUINO_EVENT_WIFI_STA_STOP, /**< ESP32 station stop */
|
||||
ARDUINO_EVENT_WIFI_STA_CONNECTED, /**< ESP32 station connected to AP */
|
||||
ARDUINO_EVENT_WIFI_STA_DISCONNECTED, /**< ESP32 station disconnected from AP */
|
||||
ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE, /**< the auth mode of AP connected by ESP32 station changed */
|
||||
ARDUINO_EVENT_WIFI_STA_GOT_IP,
|
||||
ARDUINO_EVENT_WIFI_STA_GOT_IP6,
|
||||
ARDUINO_EVENT_WIFI_STA_LOST_IP,
|
||||
ARDUINO_EVENT_WIFI_AP_START, /**< ESP32 soft-AP start */
|
||||
ARDUINO_EVENT_WIFI_AP_STOP, /**< ESP32 soft-AP stop */
|
||||
ARDUINO_EVENT_WIFI_AP_STACONNECTED, /**< a station connected to ESP32 soft-AP */
|
||||
ARDUINO_EVENT_WIFI_AP_STADISCONNECTED, /**< a station disconnected from ESP32 soft-AP */
|
||||
ARDUINO_EVENT_WIFI_AP_STAIPASSIGNED,
|
||||
ARDUINO_EVENT_WIFI_AP_PROBEREQRECVED, /**< Receive probe request packet in soft-AP interface */
|
||||
ARDUINO_EVENT_WIFI_AP_GOT_IP6,
|
||||
ARDUINO_EVENT_WIFI_FTM_REPORT, /**< Receive report of FTM procedure */
|
||||
ARDUINO_EVENT_ETH_START,
|
||||
ARDUINO_EVENT_ETH_STOP,
|
||||
ARDUINO_EVENT_ETH_CONNECTED,
|
||||
ARDUINO_EVENT_ETH_DISCONNECTED,
|
||||
ARDUINO_EVENT_ETH_GOT_IP,
|
||||
ARDUINO_EVENT_ETH_GOT_IP6,
|
||||
ARDUINO_EVENT_WPS_ER_SUCCESS, /**< ESP32 station wps succeeds in enrollee mode */
|
||||
ARDUINO_EVENT_WPS_ER_FAILED, /**< ESP32 station wps fails in enrollee mode */
|
||||
ARDUINO_EVENT_WPS_ER_TIMEOUT, /**< ESP32 station wps timeout in enrollee mode */
|
||||
ARDUINO_EVENT_WPS_ER_PIN, /**< ESP32 station wps pin code in enrollee mode */
|
||||
ARDUINO_EVENT_WPS_ER_PBC_OVERLAP, /**< ESP32 station wps overlap in enrollee mode */
|
||||
ARDUINO_EVENT_SC_SCAN_DONE,
|
||||
ARDUINO_EVENT_SC_FOUND_CHANNEL,
|
||||
ARDUINO_EVENT_SC_GOT_SSID_PSWD,
|
||||
ARDUINO_EVENT_SC_SEND_ACK_DONE,
|
||||
ARDUINO_EVENT_PROV_INIT,
|
||||
ARDUINO_EVENT_PROV_DEINIT,
|
||||
ARDUINO_EVENT_PROV_START,
|
||||
ARDUINO_EVENT_PROV_END,
|
||||
ARDUINO_EVENT_PROV_CRED_RECV,
|
||||
ARDUINO_EVENT_PROV_CRED_FAIL,
|
||||
ARDUINO_EVENT_PROV_CRED_SUCCESS,
|
||||
ARDUINO_EVENT_MAX
|
||||
} arduino_event_id_t;
|
||||
|
||||
typedef union {
|
||||
wifi_event_sta_scan_done_t wifi_scan_done;
|
||||
wifi_event_sta_authmode_change_t wifi_sta_authmode_change;
|
||||
wifi_event_sta_connected_t wifi_sta_connected;
|
||||
wifi_event_sta_disconnected_t wifi_sta_disconnected;
|
||||
wifi_event_sta_wps_er_pin_t wps_er_pin;
|
||||
wifi_event_sta_wps_fail_reason_t wps_fail_reason;
|
||||
wifi_event_ap_probe_req_rx_t wifi_ap_probereqrecved;
|
||||
wifi_event_ap_staconnected_t wifi_ap_staconnected;
|
||||
wifi_event_ap_stadisconnected_t wifi_ap_stadisconnected;
|
||||
wifi_event_ftm_report_t wifi_ftm_report;
|
||||
ip_event_ap_staipassigned_t wifi_ap_staipassigned;
|
||||
ip_event_got_ip_t got_ip;
|
||||
ip_event_got_ip6_t got_ip6;
|
||||
// smartconfig_event_got_ssid_pswd_t sc_got_ssid_pswd;
|
||||
// esp_eth_handle_t eth_connected;
|
||||
// wifi_sta_config_t prov_cred_recv;
|
||||
// wifi_prov_sta_fail_reason_t prov_fail_reason;
|
||||
} arduino_event_info_t;
|
||||
|
||||
typedef struct {
|
||||
arduino_event_id_t event_id;
|
||||
arduino_event_info_t event_info;
|
||||
} arduino_event_t;
|
||||
|
||||
#define EventId arduino_event_id_t
|
||||
#define EventId_t arduino_event_id_t
|
||||
#define EventInfo arduino_event_info_t
|
||||
#define EventInfo_t arduino_event_info_t
|
||||
#define Event_t arduino_event_t
|
||||
|
||||
typedef void (*EventCb)(EventId event);
|
||||
typedef std::function<void(EventId event, EventInfo info)> EventFuncCb;
|
||||
typedef void (*EventSysCb)(Event_t *event);
|
||||
|
||||
typedef struct EventHandler_s {
|
||||
static uint16_t lastId;
|
||||
uint16_t id;
|
||||
EventCb cb;
|
||||
EventFuncCb fcb;
|
||||
EventSysCb scb;
|
||||
EventId eventId;
|
||||
|
||||
EventHandler_s() : id(lastId++), cb(NULL), fcb(NULL), scb(NULL) {}
|
||||
} EventHandler;
|
||||
@@ -1,3 +1,5 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-04-24. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
/*
|
||||
IPv6Address.cpp - Base class that provides IPv6Address
|
||||
Copyright (c) 2011 Adrian McEwen. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <api/Print.h>
|
||||
|
||||
#include "IPv6Address.h"
|
||||
|
||||
IPv6Address::IPv6Address()
|
||||
{
|
||||
memset(_address.bytes, 0, sizeof(_address.bytes));
|
||||
}
|
||||
|
||||
IPv6Address::IPv6Address(const uint8_t *address)
|
||||
{
|
||||
memcpy(_address.bytes, address, sizeof(_address.bytes));
|
||||
}
|
||||
|
||||
IPv6Address::IPv6Address(const uint32_t *address)
|
||||
{
|
||||
memcpy(_address.bytes, (const uint8_t *)address, sizeof(_address.bytes));
|
||||
}
|
||||
|
||||
IPv6Address& IPv6Address::operator=(const uint8_t *address)
|
||||
{
|
||||
memcpy(_address.bytes, address, sizeof(_address.bytes));
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool IPv6Address::operator==(const uint8_t* addr) const
|
||||
{
|
||||
return memcmp(addr, _address.bytes, sizeof(_address.bytes)) == 0;
|
||||
}
|
||||
|
||||
size_t IPv6Address::printTo(Print& p) const
|
||||
{
|
||||
/* size_t n = 0;
|
||||
for(int i = 0; i < 16; i+=2) {
|
||||
if(i){
|
||||
n += p.print(':');
|
||||
}
|
||||
n += p.printf("%02x", _address.bytes[i]);
|
||||
n += p.printf("%02x", _address.bytes[i+1]);
|
||||
|
||||
}
|
||||
return n; */
|
||||
}
|
||||
|
||||
String IPv6Address::toString() const
|
||||
{
|
||||
char szRet[40];
|
||||
sprintf(szRet,"%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
|
||||
_address.bytes[0], _address.bytes[1], _address.bytes[2], _address.bytes[3],
|
||||
_address.bytes[4], _address.bytes[5], _address.bytes[6], _address.bytes[7],
|
||||
_address.bytes[8], _address.bytes[9], _address.bytes[10], _address.bytes[11],
|
||||
_address.bytes[12], _address.bytes[13], _address.bytes[14], _address.bytes[15]);
|
||||
return String(szRet);
|
||||
}
|
||||
|
||||
bool IPv6Address::fromString(const char *address)
|
||||
{
|
||||
//format 0011:2233:4455:6677:8899:aabb:ccdd:eeff
|
||||
if(strlen(address) != 39){
|
||||
return false;
|
||||
}
|
||||
char * pos = (char *)address;
|
||||
size_t i = 0;
|
||||
for(i = 0; i < 16; i+=2) {
|
||||
if(!sscanf(pos, "%2hhx", &_address.bytes[i]) || !sscanf(pos+2, "%2hhx", &_address.bytes[i+1])){
|
||||
return false;
|
||||
}
|
||||
pos += 5;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
/*
|
||||
IPv6Address.h - Base class that provides IPv6Address
|
||||
Copyright (c) 2011 Adrian McEwen. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <api/String.h>
|
||||
#include <api/Print.h>
|
||||
|
||||
// A class to make it easier to handle and pass around IP addresses
|
||||
|
||||
namespace arduino {
|
||||
|
||||
class IPv6Address: public Printable
|
||||
{
|
||||
private:
|
||||
union {
|
||||
uint8_t bytes[16]; // IPv4 address
|
||||
uint32_t dword[4];
|
||||
} _address;
|
||||
|
||||
// Access the raw byte array containing the address. Because this returns a pointer
|
||||
// to the internal structure rather than a copy of the address this function should only
|
||||
// be used when you know that the usage of the returned uint8_t* will be transient and not
|
||||
// stored.
|
||||
uint8_t* raw_address()
|
||||
{
|
||||
return _address.bytes;
|
||||
}
|
||||
|
||||
public:
|
||||
// Constructors
|
||||
IPv6Address();
|
||||
IPv6Address(const uint8_t *address);
|
||||
IPv6Address(const uint32_t *address);
|
||||
virtual ~IPv6Address() {}
|
||||
|
||||
bool fromString(const char *address);
|
||||
bool fromString(const String &address) { return fromString(address.c_str()); }
|
||||
|
||||
operator const uint8_t*() const
|
||||
{
|
||||
return _address.bytes;
|
||||
}
|
||||
operator const uint32_t*() const
|
||||
{
|
||||
return _address.dword;
|
||||
}
|
||||
bool operator==(const IPv6Address& addr) const
|
||||
{
|
||||
return (_address.dword[0] == addr._address.dword[0])
|
||||
&& (_address.dword[1] == addr._address.dword[1])
|
||||
&& (_address.dword[2] == addr._address.dword[2])
|
||||
&& (_address.dword[3] == addr._address.dword[3]);
|
||||
}
|
||||
bool operator==(const uint8_t* addr) const;
|
||||
|
||||
// Overloaded index operator to allow getting and setting individual octets of the address
|
||||
uint8_t operator[](int index) const
|
||||
{
|
||||
return _address.bytes[index];
|
||||
}
|
||||
uint8_t& operator[](int index)
|
||||
{
|
||||
return _address.bytes[index];
|
||||
}
|
||||
|
||||
// Overloaded copy operators to allow initialisation of IPv6Address objects from other types
|
||||
IPv6Address& operator=(const uint8_t *address);
|
||||
|
||||
// TODO implement printTo()
|
||||
virtual size_t printTo(Print& p) const;
|
||||
String toString() const;
|
||||
|
||||
friend class UDP;
|
||||
friend class Client;
|
||||
friend class Server;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
using arduino::IPv6Address;
|
||||
@@ -1,42 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef LT_VERSION
|
||||
#define LT_VERSION 1.0.0
|
||||
#endif
|
||||
|
||||
#ifndef LT_BOARD
|
||||
#define LT_BOARD unknown
|
||||
#endif
|
||||
|
||||
#define STRINGIFY(x) #x
|
||||
#define STRINGIFY_MACRO(x) STRINGIFY(x)
|
||||
#define LT_VERSION_STR STRINGIFY_MACRO(LT_VERSION)
|
||||
#define LT_BOARD_STR STRINGIFY_MACRO(LT_BOARD)
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "LibreTuyaConfig.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#include "lt_logger.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#define LT_BANNER() \
|
||||
LT_LOG( \
|
||||
LT_LEVEL_INFO, \
|
||||
"main.cpp", \
|
||||
__LINE__, \
|
||||
"LibreTuya v" LT_VERSION_STR " on " LT_BOARD_STR ", compiled at " __DATE__ " " __TIME__ \
|
||||
)
|
||||
|
||||
extern char *strdup(const char *);
|
||||
|
||||
// ArduinCore-API doesn't define these anymore
|
||||
#define FPSTR(pstr_pointer) (reinterpret_cast<const __FlashStringHelper *>(pstr_pointer))
|
||||
#define PGM_VOID_P const void *
|
||||
@@ -17,7 +17,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "api/String.h"
|
||||
#include <api/String.h>
|
||||
|
||||
typedef enum {
|
||||
PT_I8,
|
||||
|
||||
84
arduino/libretuya/api/WiFi.cpp
Normal file
84
arduino/libretuya/api/WiFi.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-17. */
|
||||
|
||||
#include "WiFi.h"
|
||||
|
||||
std::vector<EventHandler> IWiFiGenericClass::handlers;
|
||||
|
||||
uint16_t IWiFiGenericClass::onEvent(EventCb callback, EventId eventId) {
|
||||
if (!callback)
|
||||
return 0;
|
||||
EventHandler handler;
|
||||
handler.cb = callback;
|
||||
handler.eventId = eventId;
|
||||
handlers.push_back(handler);
|
||||
return handler.id;
|
||||
}
|
||||
|
||||
uint16_t IWiFiGenericClass::onEvent(EventFuncCb callback, EventId eventId) {
|
||||
if (!callback)
|
||||
return 0;
|
||||
EventHandler handler;
|
||||
handler.fcb = callback;
|
||||
handler.eventId = eventId;
|
||||
handlers.push_back(handler);
|
||||
return handler.id;
|
||||
}
|
||||
|
||||
uint16_t IWiFiGenericClass::onEvent(EventSysCb callback, EventId eventId) {
|
||||
if (!callback)
|
||||
return 0;
|
||||
EventHandler handler;
|
||||
handler.scb = callback;
|
||||
handler.eventId = eventId;
|
||||
handlers.push_back(handler);
|
||||
return handler.id;
|
||||
}
|
||||
|
||||
void IWiFiGenericClass::removeEvent(EventCb callback, EventId eventId) {
|
||||
if (!callback)
|
||||
return;
|
||||
for (uint16_t i = 0; i < handlers.size(); i++) {
|
||||
EventHandler handler = handlers[i];
|
||||
if (handler.cb == callback && handler.eventId == eventId) {
|
||||
handlers.erase(handlers.begin() + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IWiFiGenericClass::removeEvent(EventSysCb callback, EventId eventId) {
|
||||
if (!callback)
|
||||
return;
|
||||
for (uint16_t i = 0; i < handlers.size(); i++) {
|
||||
EventHandler handler = handlers[i];
|
||||
if (handler.scb == callback && handler.eventId == eventId) {
|
||||
handlers.erase(handlers.begin() + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IWiFiGenericClass::removeEvent(uint16_t id) {
|
||||
for (uint16_t i = 0; i < handlers.size(); i++) {
|
||||
EventHandler handler = handlers[i];
|
||||
if (handler.id == id) {
|
||||
handlers.erase(handlers.begin() + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IWiFiGenericClass::postEvent(EventId eventId, EventInfo eventInfo) {
|
||||
for (auto handler : handlers) {
|
||||
if (handler.eventId != ARDUINO_EVENT_MAX && handler.eventId != eventId)
|
||||
continue;
|
||||
if (handler.cb) {
|
||||
handler.cb(eventId);
|
||||
} else if (handler.fcb) {
|
||||
handler.fcb(eventId, eventInfo);
|
||||
} else if (handler.scb) {
|
||||
Event_t event = {
|
||||
.event_id = eventId,
|
||||
.event_info = eventInfo,
|
||||
};
|
||||
handler.scb(&event);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,12 +26,11 @@
|
||||
#include <api/IPAddress.h>
|
||||
#include <api/IPv6Address.h>
|
||||
#include <api/Print.h>
|
||||
#include <vector>
|
||||
|
||||
#include "Events.h"
|
||||
#include "WiFiType.h"
|
||||
|
||||
// TODO wifi events
|
||||
// TODO WiFiMulti library
|
||||
|
||||
class IWiFiClass {
|
||||
public:
|
||||
virtual void printDiag(Print &dest) = 0;
|
||||
@@ -64,6 +63,20 @@ class IWiFiGenericClass {
|
||||
static IPAddress calculateBroadcast(IPAddress ip, IPAddress subnet);
|
||||
static uint8_t calculateSubnetCIDR(IPAddress subnetMask);
|
||||
static String macToString(uint8_t *mac);
|
||||
|
||||
protected:
|
||||
static std::vector<EventHandler> handlers;
|
||||
|
||||
public:
|
||||
uint16_t onEvent(EventCb callback, EventId eventId = ARDUINO_EVENT_MAX);
|
||||
uint16_t onEvent(EventFuncCb callback, EventId eventId = ARDUINO_EVENT_MAX);
|
||||
uint16_t onEvent(EventSysCb callback, EventId eventId = ARDUINO_EVENT_MAX);
|
||||
void removeEvent(EventCb callback, EventId eventId);
|
||||
void removeEvent(EventSysCb callback, EventId eventId);
|
||||
void removeEvent(uint16_t id);
|
||||
|
||||
protected:
|
||||
static void postEvent(EventId eventId, EventInfo eventInfo);
|
||||
};
|
||||
|
||||
class IWiFiSTAClass {
|
||||
|
||||
@@ -22,42 +22,28 @@
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "WiFi.h"
|
||||
#include "WiFiClient.h"
|
||||
|
||||
class IWiFiClientSecure : public IWiFiClient {
|
||||
class IWiFiClientSecure {
|
||||
public:
|
||||
int connect(IPAddress ip, uint16_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key);
|
||||
int connect(const char *host, uint16_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key);
|
||||
int connect(IPAddress ip, uint16_t port, const char *pskIdent, const char *psKey);
|
||||
int connect(const char *host, uint16_t port, const char *pskIdent, const char *psKey);
|
||||
virtual int
|
||||
connect(IPAddress ip, uint16_t port, const char *rootCABuf, const char *clientCert, const char *clientKey) = 0;
|
||||
virtual int
|
||||
connect(const char *host, uint16_t port, const char *rootCABuf, const char *clientCert, const char *clientKey) = 0;
|
||||
virtual int connect(IPAddress ip, uint16_t port, const char *pskIdent, const char *psk) = 0;
|
||||
virtual int connect(const char *host, uint16_t port, const char *pskIdent, const char *psk) = 0;
|
||||
|
||||
int lastError(char *buf, const size_t size);
|
||||
void setInsecure(); // Don't validate the chain, just accept whatever is given. VERY INSECURE!
|
||||
void setPreSharedKey(const char *pskIdent, const char *psKey); // psKey in Hex
|
||||
void setCACert(const char *rootCA);
|
||||
void setCertificate(const char *client_ca);
|
||||
void setPrivateKey(const char *private_key);
|
||||
bool loadCACert(Stream &stream, size_t size);
|
||||
bool loadCertificate(Stream &stream, size_t size);
|
||||
bool loadPrivateKey(Stream &stream, size_t size);
|
||||
bool verify(const char *fingerprint, const char *domain_name);
|
||||
void setHandshakeTimeout(unsigned long handshake_timeout);
|
||||
|
||||
WiFiClientSecure &operator=(const WiFiClientSecure &other);
|
||||
|
||||
bool operator==(const bool value) {
|
||||
return bool() == value;
|
||||
}
|
||||
|
||||
bool operator!=(const bool value) {
|
||||
return bool() != value;
|
||||
}
|
||||
|
||||
bool operator==(const WiFiClientSecure &);
|
||||
|
||||
bool operator!=(const WiFiClientSecure &rhs) {
|
||||
return !this->operator==(rhs);
|
||||
};
|
||||
|
||||
using Print::write;
|
||||
virtual int lastError(char *buf, const size_t size) = 0;
|
||||
virtual void setInsecure() = 0; // Don't validate the chain, just accept whatever is given. VERY INSECURE!
|
||||
virtual void setPreSharedKey(const char *pskIdent, const char *psk) = 0; // psk in hex
|
||||
virtual void setCACert(const char *rootCA) = 0;
|
||||
virtual void setCertificate(const char *clientCA) = 0;
|
||||
virtual void setPrivateKey(const char *privateKey) = 0;
|
||||
virtual bool loadCACert(Stream &stream, size_t size) = 0;
|
||||
virtual bool loadCertificate(Stream &stream, size_t size) = 0;
|
||||
virtual bool loadPrivateKey(Stream &stream, size_t size) = 0;
|
||||
virtual bool verify(const char *fingerprint, const char *domainName) = 0;
|
||||
virtual void setHandshakeTimeout(unsigned long handshakeTimeout) = 0;
|
||||
virtual void setAlpnProtocols(const char **alpnProtocols) = 0;
|
||||
virtual bool getFingerprintSHA256(uint8_t result[32]) = 0;
|
||||
};
|
||||
|
||||
173
arduino/libretuya/api/WiFiEvents.h
Normal file
173
arduino/libretuya/api/WiFiEvents.h
Normal file
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "WiFiType.h"
|
||||
|
||||
/** Argument structure for WIFI_EVENT_SCAN_DONE event */
|
||||
typedef struct {
|
||||
uint32_t status; /**< status of scanning APs: 0 - success, 1 - failure */
|
||||
uint8_t number; /**< number of scan results */
|
||||
uint8_t scan_id; /**< scan sequence number, used for block scan */
|
||||
} wifi_event_sta_scan_done_t;
|
||||
|
||||
/** Argument structure for WIFI_EVENT_STA_CONNECTED event */
|
||||
typedef struct {
|
||||
uint8_t ssid[32]; /**< SSID of connected AP */
|
||||
uint8_t ssid_len; /**< SSID length of connected AP */
|
||||
uint8_t bssid[6]; /**< BSSID of connected AP*/
|
||||
uint8_t channel; /**< channel of connected AP*/
|
||||
wifi_auth_mode_t authmode; /**< authentication mode used by AP*/
|
||||
} wifi_event_sta_connected_t;
|
||||
|
||||
/** Argument structure for WIFI_EVENT_STA_DISCONNECTED event */
|
||||
typedef struct {
|
||||
uint8_t ssid[32]; /**< SSID of disconnected AP */
|
||||
uint8_t ssid_len; /**< SSID length of disconnected AP */
|
||||
uint8_t bssid[6]; /**< BSSID of disconnected AP */
|
||||
uint8_t reason; /**< reason of disconnection */
|
||||
} wifi_event_sta_disconnected_t;
|
||||
|
||||
/** Argument structure for WIFI_EVENT_STA_AUTHMODE_CHANGE event */
|
||||
typedef struct {
|
||||
wifi_auth_mode_t old_mode; /**< the old auth mode of AP */
|
||||
wifi_auth_mode_t new_mode; /**< the new auth mode of AP */
|
||||
} wifi_event_sta_authmode_change_t;
|
||||
|
||||
/** Argument structure for WIFI_EVENT_STA_WPS_ER_PIN event */
|
||||
typedef struct {
|
||||
uint8_t pin_code[8]; /**< PIN code of station in enrollee mode */
|
||||
} wifi_event_sta_wps_er_pin_t;
|
||||
|
||||
/** Argument structure for WIFI_EVENT_STA_WPS_ER_FAILED event */
|
||||
typedef enum {
|
||||
WPS_FAIL_REASON_NORMAL = 0, /**< ESP32 WPS normal fail reason */
|
||||
WPS_FAIL_REASON_RECV_M2D, /**< ESP32 WPS receive M2D frame */
|
||||
WPS_FAIL_REASON_MAX
|
||||
} wifi_event_sta_wps_fail_reason_t;
|
||||
|
||||
#define MAX_SSID_LEN 32
|
||||
#define MAX_PASSPHRASE_LEN 64
|
||||
#define MAX_WPS_AP_CRED 3
|
||||
|
||||
/** Argument structure for WIFI_EVENT_STA_WPS_ER_SUCCESS event */
|
||||
typedef struct {
|
||||
uint8_t ap_cred_cnt; /**< Number of AP credentials received */
|
||||
|
||||
struct {
|
||||
uint8_t ssid[MAX_SSID_LEN]; /**< SSID of AP */
|
||||
uint8_t passphrase[MAX_PASSPHRASE_LEN]; /**< Passphrase for the AP */
|
||||
} ap_cred[MAX_WPS_AP_CRED]; /**< All AP credentials received from WPS handshake */
|
||||
} wifi_event_sta_wps_er_success_t;
|
||||
|
||||
/** Argument structure for WIFI_EVENT_AP_STACONNECTED event */
|
||||
typedef struct {
|
||||
uint8_t mac[6]; /**< MAC address of the station connected to ESP32 soft-AP */
|
||||
uint8_t aid; /**< the aid that ESP32 soft-AP gives to the station connected to */
|
||||
bool is_mesh_child; /**< flag to identify mesh child */
|
||||
} wifi_event_ap_staconnected_t;
|
||||
|
||||
/** Argument structure for WIFI_EVENT_AP_STADISCONNECTED event */
|
||||
typedef struct {
|
||||
uint8_t mac[6]; /**< MAC address of the station disconnects to ESP32 soft-AP */
|
||||
uint8_t aid; /**< the aid that ESP32 soft-AP gave to the station disconnects to */
|
||||
bool is_mesh_child; /**< flag to identify mesh child */
|
||||
} wifi_event_ap_stadisconnected_t;
|
||||
|
||||
/** Argument structure for WIFI_EVENT_AP_PROBEREQRECVED event */
|
||||
typedef struct {
|
||||
int rssi; /**< Received probe request signal strength */
|
||||
uint8_t mac[6]; /**< MAC address of the station which send probe request */
|
||||
} wifi_event_ap_probe_req_rx_t;
|
||||
|
||||
/**
|
||||
* @brief FTM operation status types
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
FTM_STATUS_SUCCESS = 0, /**< FTM exchange is successful */
|
||||
FTM_STATUS_UNSUPPORTED, /**< Peer does not support FTM */
|
||||
FTM_STATUS_CONF_REJECTED, /**< Peer rejected FTM configuration in FTM Request */
|
||||
FTM_STATUS_NO_RESPONSE, /**< Peer did not respond to FTM Requests */
|
||||
FTM_STATUS_FAIL, /**< Unknown error during FTM exchange */
|
||||
} wifi_ftm_status_t;
|
||||
|
||||
/** Argument structure for */
|
||||
typedef struct {
|
||||
uint8_t dlog_token; /**< Dialog Token of the FTM frame */
|
||||
int8_t rssi; /**< RSSI of the FTM frame received */
|
||||
uint32_t rtt; /**< Round Trip Time in pSec with a peer */
|
||||
uint64_t t1; /**< Time of departure of FTM frame from FTM Responder in pSec */
|
||||
uint64_t t2; /**< Time of arrival of FTM frame at FTM Initiator in pSec */
|
||||
uint64_t t3; /**< Time of departure of ACK from FTM Initiator in pSec */
|
||||
uint64_t t4; /**< Time of arrival of ACK at FTM Responder in pSec */
|
||||
} wifi_ftm_report_entry_t;
|
||||
|
||||
/** Argument structure for WIFI_EVENT_FTM_REPORT event */
|
||||
typedef struct {
|
||||
uint8_t peer_mac[6]; /**< MAC address of the FTM Peer */
|
||||
wifi_ftm_status_t status; /**< Status of the FTM operation */
|
||||
uint32_t rtt_raw; /**< Raw average Round-Trip-Time with peer in Nano-Seconds */
|
||||
uint32_t rtt_est; /**< Estimated Round-Trip-Time with peer in Nano-Seconds */
|
||||
uint32_t dist_est; /**< Estimated one-way distance in Centi-Meters */
|
||||
wifi_ftm_report_entry_t
|
||||
*ftm_report_data; /**< Pointer to FTM Report with multiple entries, should be freed after use */
|
||||
uint8_t ftm_report_num_entries; /**< Number of entries in the FTM Report data */
|
||||
} wifi_event_ftm_report_t;
|
||||
|
||||
#define WIFI_STATIS_BUFFER (1 << 0)
|
||||
#define WIFI_STATIS_RXTX (1 << 1)
|
||||
#define WIFI_STATIS_HW (1 << 2)
|
||||
#define WIFI_STATIS_DIAG (1 << 3)
|
||||
#define WIFI_STATIS_PS (1 << 4)
|
||||
#define WIFI_STATIS_ALL (-1)
|
||||
|
||||
/** Argument structure for WIFI_EVENT_ACTION_TX_STATUS event */
|
||||
typedef struct {
|
||||
int ifx; /**< WiFi interface to send request to */
|
||||
uint32_t context; /**< Context to identify the request */
|
||||
uint8_t da[6]; /**< Destination MAC address */
|
||||
uint8_t status; /**< Status of the operation */
|
||||
} wifi_event_action_tx_status_t;
|
||||
|
||||
/** Argument structure for WIFI_EVENT_ROC_DONE event */
|
||||
typedef struct {
|
||||
uint32_t context; /**< Context to identify the request */
|
||||
} wifi_event_roc_done_t;
|
||||
|
||||
/** Event structure for IP_EVENT_STA_GOT_IP, IP_EVENT_ETH_GOT_IP events */
|
||||
typedef struct {
|
||||
esp_ip4_addr_t ip; /**< Interface IPV4 address */
|
||||
esp_ip4_addr_t netmask; /**< Interface IPV4 netmask */
|
||||
esp_ip4_addr_t gw; /**< Interface IPV4 gateway address */
|
||||
} esp_netif_ip_info_t;
|
||||
|
||||
/** @brief IPV6 IP address information
|
||||
*/
|
||||
typedef struct {
|
||||
esp_ip6_addr_t ip; /**< Interface IPV6 address */
|
||||
} esp_netif_ip6_info_t;
|
||||
|
||||
typedef struct {
|
||||
int if_index; /*!< Interface index for which the event is received (left for legacy compilation) */
|
||||
void *esp_netif; /*!< Pointer to corresponding esp-netif object */
|
||||
esp_netif_ip_info_t ip_info; /*!< IP address, netmask, gatway IP address */
|
||||
bool ip_changed; /*!< Whether the assigned IP has changed or not */
|
||||
} ip_event_got_ip_t;
|
||||
|
||||
/** Event structure for IP_EVENT_GOT_IP6 event */
|
||||
typedef struct {
|
||||
int if_index; /*!< Interface index for which the event is received (left for legacy compilation) */
|
||||
void *esp_netif; /*!< Pointer to corresponding esp-netif object */
|
||||
esp_netif_ip6_info_t ip6_info; /*!< IPv6 address of the interface */
|
||||
int ip_index; /*!< IPv6 address index */
|
||||
} ip_event_got_ip6_t;
|
||||
|
||||
/** Event structure for IP_EVENT_AP_STAIPASSIGNED event */
|
||||
typedef struct {
|
||||
esp_ip4_addr_t ip; /*!< IP address which was assigned to the station */
|
||||
} ip_event_ap_staipassigned_t;
|
||||
@@ -34,12 +34,28 @@
|
||||
#define WIFI_AP WIFI_MODE_AP
|
||||
#define WIFI_AP_STA WIFI_MODE_APSTA
|
||||
|
||||
#define WiFiEvent_t arduino_event_id_t
|
||||
#define WiFiEventInfo_t arduino_event_info_t
|
||||
#define WiFiEventId_t uint16_t
|
||||
|
||||
struct esp_ip6_addr {
|
||||
uint32_t addr[4];
|
||||
uint8_t zone;
|
||||
};
|
||||
|
||||
struct esp_ip4_addr {
|
||||
uint32_t addr;
|
||||
};
|
||||
|
||||
typedef struct esp_ip4_addr esp_ip4_addr_t;
|
||||
typedef struct esp_ip6_addr esp_ip6_addr_t;
|
||||
|
||||
typedef enum {
|
||||
WIFI_MODE_NULL = 0,
|
||||
WIFI_MODE_STA,
|
||||
WIFI_MODE_AP,
|
||||
WIFI_MODE_APSTA,
|
||||
WIFI_MODE_MAX,
|
||||
WIFI_MODE_NULL = 0, /**< null mode */
|
||||
WIFI_MODE_STA, /**< WiFi station mode */
|
||||
WIFI_MODE_AP, /**< WiFi soft-AP mode */
|
||||
WIFI_MODE_APSTA, /**< WiFi station + soft-AP mode */
|
||||
WIFI_MODE_MAX
|
||||
} wifi_mode_t;
|
||||
|
||||
typedef enum {
|
||||
@@ -54,13 +70,54 @@ typedef enum {
|
||||
} wl_status_t;
|
||||
|
||||
typedef enum {
|
||||
WIFI_AUTH_INVALID = 255,
|
||||
WIFI_AUTH_AUTO = 200,
|
||||
WIFI_AUTH_OPEN = 0,
|
||||
WIFI_AUTH_WEP = 1,
|
||||
WIFI_AUTH_WPA = 5,
|
||||
WIFI_AUTH_WPA2 = 6,
|
||||
WIFI_AUTH_WPA_PSK = 2,
|
||||
WIFI_AUTH_WPA2_PSK = 3,
|
||||
WIFI_AUTH_WPA_WPA2_PSK = 4,
|
||||
WIFI_AUTH_OPEN = 0, /**< authenticate mode : open */
|
||||
WIFI_AUTH_WEP, /**< authenticate mode : WEP */
|
||||
WIFI_AUTH_WPA_PSK, /**< authenticate mode : WPA_PSK */
|
||||
WIFI_AUTH_WPA2_PSK, /**< authenticate mode : WPA2_PSK */
|
||||
WIFI_AUTH_WPA_WPA2_PSK, /**< authenticate mode : WPA_WPA2_PSK */
|
||||
WIFI_AUTH_WPA2_ENTERPRISE, /**< authenticate mode : WPA2_ENTERPRISE */
|
||||
WIFI_AUTH_WPA3_PSK, /**< authenticate mode : WPA3_PSK */
|
||||
WIFI_AUTH_WPA2_WPA3_PSK, /**< authenticate mode : WPA2_WPA3_PSK */
|
||||
WIFI_AUTH_WAPI_PSK, /**< authenticate mode : WAPI_PSK */
|
||||
WIFI_AUTH_WPA,
|
||||
WIFI_AUTH_WPA2,
|
||||
WIFI_AUTH_AUTO = 200,
|
||||
WIFI_AUTH_INVALID = 255,
|
||||
WIFI_AUTH_MAX
|
||||
} wifi_auth_mode_t;
|
||||
|
||||
typedef enum {
|
||||
WIFI_REASON_UNSPECIFIED = 1,
|
||||
WIFI_REASON_AUTH_EXPIRE = 2,
|
||||
WIFI_REASON_AUTH_LEAVE = 3,
|
||||
WIFI_REASON_ASSOC_EXPIRE = 4,
|
||||
WIFI_REASON_ASSOC_TOOMANY = 5,
|
||||
WIFI_REASON_NOT_AUTHED = 6,
|
||||
WIFI_REASON_NOT_ASSOCED = 7,
|
||||
WIFI_REASON_ASSOC_LEAVE = 8,
|
||||
WIFI_REASON_ASSOC_NOT_AUTHED = 9,
|
||||
WIFI_REASON_DISASSOC_PWRCAP_BAD = 10,
|
||||
WIFI_REASON_DISASSOC_SUPCHAN_BAD = 11,
|
||||
WIFI_REASON_BSS_TRANSITION_DISASSOC = 12,
|
||||
WIFI_REASON_IE_INVALID = 13,
|
||||
WIFI_REASON_MIC_FAILURE = 14,
|
||||
WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT = 15,
|
||||
WIFI_REASON_GROUP_KEY_UPDATE_TIMEOUT = 16,
|
||||
WIFI_REASON_IE_IN_4WAY_DIFFERS = 17,
|
||||
WIFI_REASON_GROUP_CIPHER_INVALID = 18,
|
||||
WIFI_REASON_PAIRWISE_CIPHER_INVALID = 19,
|
||||
WIFI_REASON_AKMP_INVALID = 20,
|
||||
WIFI_REASON_UNSUPP_RSN_IE_VERSION = 21,
|
||||
WIFI_REASON_INVALID_RSN_IE_CAP = 22,
|
||||
WIFI_REASON_802_1X_AUTH_FAILED = 23,
|
||||
WIFI_REASON_CIPHER_SUITE_REJECTED = 24,
|
||||
WIFI_REASON_INVALID_PMKID = 53,
|
||||
WIFI_REASON_BEACON_TIMEOUT = 200,
|
||||
WIFI_REASON_NO_AP_FOUND = 201,
|
||||
WIFI_REASON_AUTH_FAIL = 202,
|
||||
WIFI_REASON_ASSOC_FAIL = 203,
|
||||
WIFI_REASON_HANDSHAKE_TIMEOUT = 204,
|
||||
WIFI_REASON_CONNECTION_FAIL = 205,
|
||||
WIFI_REASON_AP_TSF_RESET = 206,
|
||||
WIFI_REASON_ROAMING = 207,
|
||||
} wifi_err_reason_t;
|
||||
|
||||
66
arduino/libretuya/api/Wire.h
Normal file
66
arduino/libretuya/api/Wire.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-09. */
|
||||
|
||||
#include <api/Stream.h>
|
||||
|
||||
class ITwoWire : public Stream {
|
||||
protected:
|
||||
int8_t _sda = -1;
|
||||
int8_t _scl = -1;
|
||||
uint32_t _freq = 0;
|
||||
|
||||
void (*onRequestCallback)(void);
|
||||
void (*onReceiveCallback)(int);
|
||||
|
||||
public:
|
||||
bool begin() {
|
||||
return begin(_sda, _scl, _freq);
|
||||
}
|
||||
|
||||
bool begin(uint8_t address) {
|
||||
return begin(address, _sda, _scl, _freq);
|
||||
}
|
||||
|
||||
virtual bool setPins(int8_t sda, int8_t scl) = 0;
|
||||
|
||||
virtual bool begin(int8_t sda, int8_t scl, uint32_t frequency = 0) = 0;
|
||||
virtual bool begin(uint8_t address, int8_t sda, int8_t scl, uint32_t frequency = 0) = 0;
|
||||
virtual bool end() = 0;
|
||||
|
||||
virtual bool setClock(uint32_t freq) = 0;
|
||||
|
||||
virtual void beginTransmission(uint8_t address) = 0;
|
||||
virtual uint8_t endTransmission(bool stopBit) = 0;
|
||||
|
||||
virtual size_t requestFrom(uint8_t address, size_t len, bool stopBit) = 0;
|
||||
|
||||
virtual size_t write(const uint8_t *data, size_t len) = 0;
|
||||
|
||||
virtual int available() = 0;
|
||||
virtual int read() = 0;
|
||||
virtual int peek() = 0;
|
||||
virtual void flush() = 0;
|
||||
|
||||
uint32_t getClock() {
|
||||
return _freq;
|
||||
}
|
||||
|
||||
uint8_t endTransmission() {
|
||||
return endTransmission(true);
|
||||
}
|
||||
|
||||
size_t requestFrom(uint8_t address, size_t len) {
|
||||
return requestFrom(address, len, true);
|
||||
}
|
||||
|
||||
virtual size_t write(uint8_t data) {
|
||||
return write(&data, 1);
|
||||
}
|
||||
|
||||
void onReceive(void (*cb)(int)) {
|
||||
onReceiveCallback = cb;
|
||||
}
|
||||
|
||||
void onRequest(void (*cb)(void)) {
|
||||
onRequestCallback = cb;
|
||||
}
|
||||
};
|
||||
@@ -1,114 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "LibreTuyaConfig.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#if LT_LOGGER_FILE
|
||||
#define LT_LOG(level, file, line, ...) lt_log(level, file, line, __VA_ARGS__)
|
||||
void lt_log(const uint8_t level, const char *filename, const unsigned short line, const char *format, ...);
|
||||
#else
|
||||
#define LT_LOG(level, file, line, ...) lt_log(level, __VA_ARGS__)
|
||||
void lt_log(const uint8_t level, const char *format, ...);
|
||||
#endif
|
||||
|
||||
#if LT_LEVEL_TRACE >= LT_LOGLEVEL
|
||||
#define LT_T(...) LT_LOG(LT_LEVEL_TRACE, __FILE__, __LINE__, __VA_ARGS__)
|
||||
#define LT_V(...) LT_LOG(LT_LEVEL_TRACE, __FILE__, __LINE__, __VA_ARGS__)
|
||||
#else
|
||||
#define LT_T(...)
|
||||
#define LT_V(...)
|
||||
#endif
|
||||
|
||||
#if LT_LEVEL_DEBUG >= LT_LOGLEVEL
|
||||
#define LT_D(...) LT_LOG(LT_LEVEL_DEBUG, __FILE__, __LINE__, __VA_ARGS__)
|
||||
#else
|
||||
#define LT_D(...)
|
||||
#endif
|
||||
|
||||
#if LT_LEVEL_INFO >= LT_LOGLEVEL
|
||||
#define LT_I(...) LT_LOG(LT_LEVEL_INFO, __FILE__, __LINE__, __VA_ARGS__)
|
||||
#else
|
||||
#define LT_I(...)
|
||||
#endif
|
||||
|
||||
#if LT_LEVEL_WARN >= LT_LOGLEVEL
|
||||
#define LT_W(...) LT_LOG(LT_LEVEL_WARN, __FILE__, __LINE__, __VA_ARGS__)
|
||||
#else
|
||||
#define LT_W(...)
|
||||
#endif
|
||||
|
||||
#if LT_LEVEL_ERROR >= LT_LOGLEVEL
|
||||
#define LT_E(...) LT_LOG(LT_LEVEL_ERROR, __FILE__, __LINE__, __VA_ARGS__)
|
||||
#else
|
||||
#define LT_E(...)
|
||||
#endif
|
||||
|
||||
#if LT_LEVEL_FATAL >= LT_LOGLEVEL
|
||||
#define LT_F(...) LT_LOG(LT_LEVEL_FATAL, __FILE__, __LINE__, __VA_ARGS__)
|
||||
#else
|
||||
#define LT_F(...)
|
||||
#endif
|
||||
|
||||
// ESP32 compat
|
||||
#define log_printf(...) LT_I(__VA_ARGS__)
|
||||
#define log_v(...) LT_V(__VA_ARGS__)
|
||||
#define log_d(...) LT_D(__VA_ARGS__)
|
||||
#define log_i(...) LT_I(__VA_ARGS__)
|
||||
#define log_w(...) LT_W(__VA_ARGS__)
|
||||
#define log_e(...) LT_E(__VA_ARGS__)
|
||||
#define log_n(...) LT_E(__VA_ARGS__)
|
||||
#define isr_log_v(...) LT_V(__VA_ARGS__)
|
||||
#define isr_log_d(...) LT_D(__VA_ARGS__)
|
||||
#define isr_log_i(...) LT_I(__VA_ARGS__)
|
||||
#define isr_log_w(...) LT_W(__VA_ARGS__)
|
||||
#define isr_log_e(...) LT_E(__VA_ARGS__)
|
||||
#define isr_log_n(...) LT_E(__VA_ARGS__)
|
||||
#define ESP_LOGV(...) LT_V(__VA_ARGS__)
|
||||
#define ESP_LOGD(...) LT_D(__VA_ARGS__)
|
||||
#define ESP_LOGI(...) LT_I(__VA_ARGS__)
|
||||
#define ESP_LOGW(...) LT_W(__VA_ARGS__)
|
||||
#define ESP_LOGE(...) LT_E(__VA_ARGS__)
|
||||
#define ESP_EARLY_LOGV(...) LT_V(__VA_ARGS__)
|
||||
#define ESP_EARLY_LOGD(...) LT_D(__VA_ARGS__)
|
||||
#define ESP_EARLY_LOGI(...) LT_I(__VA_ARGS__)
|
||||
#define ESP_EARLY_LOGW(...) LT_W(__VA_ARGS__)
|
||||
#define ESP_EARLY_LOGE(...) LT_E(__VA_ARGS__)
|
||||
|
||||
#define LT_T_MOD(module, ...) \
|
||||
do { \
|
||||
if (module) { \
|
||||
LT_T(__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define LT_D_MOD(module, ...) \
|
||||
do { \
|
||||
if (module) { \
|
||||
LT_D(__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// WiFi.cpp
|
||||
#define LT_T_WG(...) LT_T_MOD(LT_DEBUG_WIFI, __VA_ARGS__)
|
||||
#define LT_V_WG(...) LT_T_MOD(LT_DEBUG_WIFI, __VA_ARGS__)
|
||||
#define LT_D_WG(...) LT_D_MOD(LT_DEBUG_WIFI, __VA_ARGS__)
|
||||
|
||||
// WiFiClient.cpp
|
||||
#define LT_T_WC(...) LT_T_MOD(LT_DEBUG_WIFI_CLIENT, __VA_ARGS__)
|
||||
#define LT_V_WC(...) LT_T_MOD(LT_DEBUG_WIFI_CLIENT, __VA_ARGS__)
|
||||
#define LT_D_WC(...) LT_D_MOD(LT_DEBUG_WIFI_CLIENT, __VA_ARGS__)
|
||||
|
||||
// WiFiServer.cpp
|
||||
#define LT_T_WS(...) LT_T_MOD(LT_DEBUG_WIFI_SERVER, __VA_ARGS__)
|
||||
#define LT_V_WS(...) LT_T_MOD(LT_DEBUG_WIFI_SERVER, __VA_ARGS__)
|
||||
#define LT_D_WS(...) LT_D_MOD(LT_DEBUG_WIFI_SERVER, __VA_ARGS__)
|
||||
|
||||
// WiFiSTA.cpp
|
||||
#define LT_T_WSTA(...) LT_T_MOD(LT_DEBUG_WIFI_STA, __VA_ARGS__)
|
||||
#define LT_V_WSTA(...) LT_T_MOD(LT_DEBUG_WIFI_STA, __VA_ARGS__)
|
||||
#define LT_D_WSTA(...) LT_D_MOD(LT_DEBUG_WIFI_STA, __VA_ARGS__)
|
||||
|
||||
// WiFiAP.cpp
|
||||
#define LT_T_WAP(...) LT_T_MOD(LT_DEBUG_WIFI_AP, __VA_ARGS__)
|
||||
#define LT_V_WAP(...) LT_T_MOD(LT_DEBUG_WIFI_AP, __VA_ARGS__)
|
||||
#define LT_D_WAP(...) LT_D_MOD(LT_DEBUG_WIFI_AP, __VA_ARGS__)
|
||||
55
arduino/libretuya/common/WMath.cpp
Normal file
55
arduino/libretuya/common/WMath.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
Copyright (c) 2014 Arduino. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
void randomSeed(uint32_t dwSeed) {
|
||||
if (dwSeed != 0) {
|
||||
srand(dwSeed);
|
||||
}
|
||||
}
|
||||
|
||||
long random(long howbig) {
|
||||
if (howbig == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return rand() % howbig;
|
||||
}
|
||||
|
||||
long random(long howsmall, long howbig) {
|
||||
if (howsmall >= howbig) {
|
||||
return howsmall;
|
||||
}
|
||||
|
||||
long diff = howbig - howsmall;
|
||||
|
||||
return random(diff) + howsmall;
|
||||
}
|
||||
|
||||
extern long map(long x, long in_min, long in_max, long out_min, long out_max) {
|
||||
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
||||
}
|
||||
|
||||
extern uint16_t makeWord(uint16_t w) {
|
||||
return w;
|
||||
}
|
||||
|
||||
extern uint16_t makeWord(uint8_t h, uint8_t l) {
|
||||
return (h << 8) | l;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2012 Arduino. All right reserved.
|
||||
Copyright (c) 2014 Arduino LLC. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
@@ -16,19 +16,21 @@
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef RESET_H
|
||||
#define RESET_H
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
extern "C" void __cxa_pure_virtual(void) __attribute__((__noreturn__));
|
||||
extern "C" void __cxa_deleted_virtual(void) __attribute__((__noreturn__));
|
||||
|
||||
void initiateReset(int ms);
|
||||
void tickReset();
|
||||
void cancelReset();
|
||||
|
||||
#ifdef __cplusplus
|
||||
void __cxa_pure_virtual(void) {
|
||||
// We might want to write some diagnostics to uart in this case
|
||||
// std::terminate();
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
void __cxa_deleted_virtual(void) {
|
||||
// We might want to write some diagnostics to uart in this case
|
||||
// std::terminate();
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
@@ -18,16 +18,11 @@
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifdef ARDUINO_AMEBA
|
||||
#include <Arduino.h>
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
char *dtostrf (double val, signed char width, unsigned char prec, char *sout) {
|
||||
char fmt[20];
|
||||
sprintf(fmt, "%%%d.%df", width, prec);
|
||||
sprintf(sout, fmt, val);
|
||||
return sout;
|
||||
char *dtostrf(double val, signed char width, unsigned char prec, char *sout) {
|
||||
char fmt[20];
|
||||
sprintf(fmt, "%%%d.%df", width, prec);
|
||||
sprintf(sout, fmt, val);
|
||||
return sout;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2012 Arduino. All right reserved.
|
||||
Copyright (c) 2015 Arduino LLC. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
@@ -29,12 +29,7 @@ static void __empty() {
|
||||
// Empty
|
||||
}
|
||||
|
||||
#include "cmsis_os.h"
|
||||
|
||||
void yield(void) {
|
||||
vTaskDelay(1);
|
||||
taskYIELD();
|
||||
}
|
||||
void yield(void) __attribute__((weak, alias("__empty")));
|
||||
|
||||
/**
|
||||
* SysTick hook
|
||||
@@ -46,7 +41,8 @@ static int __false() {
|
||||
// Return false
|
||||
return 0;
|
||||
}
|
||||
int sysTickHook(void) __attribute__ ((weak, alias("__false")));
|
||||
|
||||
int sysTickHook(void) __attribute__((weak, alias("__false")));
|
||||
|
||||
/**
|
||||
* SVC hook
|
||||
@@ -60,5 +56,6 @@ static void __halt() {
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
void svcHook(void) __attribute__ ((weak, alias("__halt")));
|
||||
void pendSVHook(void) __attribute__ ((weak, alias("__halt")));
|
||||
|
||||
void svcHook(void) __attribute__((weak, alias("__halt")));
|
||||
void pendSVHook(void) __attribute__((weak, alias("__halt")));
|
||||
111
arduino/libretuya/common/itoa.c
Normal file
111
arduino/libretuya/common/itoa.c
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
Copyright (c) 2014 Arduino LLC. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
char *ltoa(long value, char *string, int radix) {
|
||||
char tmp[33];
|
||||
char *tp = tmp;
|
||||
long i;
|
||||
unsigned long v;
|
||||
int sign;
|
||||
char *sp;
|
||||
|
||||
if (string == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (radix > 36 || radix <= 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
sign = (radix == 10 && value < 0);
|
||||
if (sign) {
|
||||
v = -value;
|
||||
} else {
|
||||
v = (unsigned long)value;
|
||||
}
|
||||
|
||||
while (v || tp == tmp) {
|
||||
i = v % radix;
|
||||
v = v / radix;
|
||||
if (i < 10)
|
||||
*tp++ = i + '0';
|
||||
else
|
||||
*tp++ = i + 'a' - 10;
|
||||
}
|
||||
|
||||
sp = string;
|
||||
|
||||
if (sign)
|
||||
*sp++ = '-';
|
||||
while (tp > tmp)
|
||||
*sp++ = *--tp;
|
||||
*sp = 0;
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
char *ultoa(unsigned long value, char *string, int radix) {
|
||||
char tmp[33];
|
||||
char *tp = tmp;
|
||||
long i;
|
||||
unsigned long v = value;
|
||||
char *sp;
|
||||
|
||||
if (string == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (radix > 36 || radix <= 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (v || tp == tmp) {
|
||||
i = v % radix;
|
||||
v = v / radix;
|
||||
if (i < 10)
|
||||
*tp++ = i + '0';
|
||||
else
|
||||
*tp++ = i + 'a' - 10;
|
||||
}
|
||||
|
||||
sp = string;
|
||||
|
||||
while (tp > tmp)
|
||||
*sp++ = *--tp;
|
||||
*sp = 0;
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
char *itoa(int value, char *string, int radix) {
|
||||
return ltoa(value, string, radix);
|
||||
}
|
||||
|
||||
char *utoa(unsigned int value, char *string, int radix) {
|
||||
return ultoa(value, string, radix);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
54
arduino/libretuya/common/wiring_shift.c
Normal file
54
arduino/libretuya/common/wiring_shift.c
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
Copyright (c) 2014 Arduino. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <stdint.h>
|
||||
|
||||
uint8_t shiftIn(pin_size_t ulDataPin, pin_size_t ulClockPin, BitOrder ulBitOrder) {
|
||||
uint8_t value = 0;
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < 8; ++i) {
|
||||
digitalWrite(ulClockPin, HIGH);
|
||||
|
||||
if (ulBitOrder == LSBFIRST) {
|
||||
value |= digitalRead(ulDataPin) << i;
|
||||
} else {
|
||||
value |= digitalRead(ulDataPin) << (7 - i);
|
||||
}
|
||||
|
||||
digitalWrite(ulClockPin, LOW);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void shiftOut(pin_size_t ulDataPin, pin_size_t ulClockPin, BitOrder ulBitOrder, uint8_t ulVal) {
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (ulBitOrder == LSBFIRST) {
|
||||
digitalWrite(ulDataPin, !!(ulVal & (1 << i)));
|
||||
} else {
|
||||
digitalWrite(ulDataPin, !!(ulVal & (1 << (7 - i))));
|
||||
}
|
||||
|
||||
digitalWrite(ulClockPin, HIGH);
|
||||
digitalWrite(ulClockPin, LOW);
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-04-30. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <api/FS.h>
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-04-30. */
|
||||
|
||||
// nop
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-04-26. */
|
||||
|
||||
#pragma once
|
||||
|
||||
// ESP32 WiFi examples use WiFiAP.h include
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-04-30. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <api/deprecated-avr-comp/avr/pgmspace.h>
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-04-30. */
|
||||
|
||||
// nop
|
||||
|
||||
23
arduino/libretuya/core/ChipType.h
Normal file
23
arduino/libretuya/core/ChipType.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-28. */
|
||||
|
||||
enum ChipFamily {
|
||||
// used in UF2 Family ID
|
||||
RTL8710A = 0x9FFFD543, // Realtek Ameba1
|
||||
RTL8710B = 0x22E0D6FC, // Realtek AmebaZ (realtek-ambz)
|
||||
RTL8720C = 0xE08F7564, // Realtek AmebaZ2
|
||||
RTL8720D = 0x3379CFE2, // Realtek AmebaD
|
||||
BK7231T = 0x675A40B0, // Beken 7231T
|
||||
BK7231N = 0x7B3EF230, // Beken 7231N
|
||||
BL602 = 0xDE1270B7, // Boufallo 602
|
||||
XR809 = 0x51E903A8, // Xradiotech 809
|
||||
};
|
||||
|
||||
enum ChipType {
|
||||
// IDs copied from rtl8710b_efuse.h
|
||||
RTL8710BL = ((RTL8710B >> 24) << 8) | 0xE0, // ???
|
||||
RTL8710BN = ((RTL8710B >> 24) << 8) | 0xFF, // CHIPID_8710BN / QFN32
|
||||
RTL8710BU = ((RTL8710B >> 24) << 8) | 0xFE, // CHIPID_8710BU / QFN48
|
||||
RTL8710BX = ((RTL8710B >> 24) << 8) | 0xFB, // CHIPID_8710BN_L0 / QFN32
|
||||
RTL8711BN = ((RTL8710B >> 24) << 8) | 0xFD, // CHIPID_8711BN / QFN48
|
||||
RTL8711BU = ((RTL8710B >> 24) << 8) | 0xFC, // CHIPID_8711BG / QFN68
|
||||
};
|
||||
162
arduino/libretuya/core/LibreTuyaAPI.cpp
Normal file
162
arduino/libretuya/core/LibreTuyaAPI.cpp
Normal file
@@ -0,0 +1,162 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-04-29. */
|
||||
|
||||
#include "LibreTuyaAPI.h"
|
||||
|
||||
String ipToString(const IPAddress &ip) {
|
||||
char szRet[16];
|
||||
sprintf(szRet, "%hhu.%hhu.%hhu.%hhu", ip[0], ip[1], ip[2], ip[3]);
|
||||
return String(szRet);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Generate random bytes using rand().
|
||||
*
|
||||
* @param buf destination pointer
|
||||
* @param len how many bytes to generate
|
||||
*/
|
||||
void lt_rand_bytes(uint8_t *buf, size_t len) {
|
||||
int *data = (int *)buf;
|
||||
size_t i;
|
||||
for (i = 0; len >= sizeof(int); len -= sizeof(int)) {
|
||||
data[i++] = rand();
|
||||
}
|
||||
if (len) {
|
||||
int rem = rand();
|
||||
unsigned char *pRem = (unsigned char *)&rem;
|
||||
memcpy(buf + i * sizeof(int), pRem, len);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Print data pointed to by buf in hexdump-like format (hex+ASCII).
|
||||
*
|
||||
* @param buf source pointer
|
||||
* @param len how many bytes to print
|
||||
* @param offset increment printed offset by this value
|
||||
* @param width how many bytes on a line
|
||||
*/
|
||||
void hexdump(uint8_t *buf, size_t len, uint32_t offset, uint8_t width) {
|
||||
uint16_t pos = 0;
|
||||
while (pos < len) {
|
||||
// print hex offset
|
||||
printf("%06x ", offset + pos);
|
||||
// calculate current line width
|
||||
uint8_t lineWidth = min(width, len - pos);
|
||||
// print hexadecimal representation
|
||||
for (uint8_t i = 0; i < lineWidth; i++) {
|
||||
if (i % 8 == 0) {
|
||||
printf(" ");
|
||||
}
|
||||
printf("%02x ", buf[pos + i]);
|
||||
}
|
||||
// print ascii representation
|
||||
printf(" |");
|
||||
for (uint8_t i = 0; i < lineWidth; i++) {
|
||||
char c = buf[pos + i];
|
||||
printf("%c", isprint(c) ? c : '.');
|
||||
}
|
||||
printf("|\n");
|
||||
pos += lineWidth;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get LibreTuya version string.
|
||||
*/
|
||||
const char *LibreTuya::getVersion() {
|
||||
return LT_VERSION_STR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get board name.
|
||||
*/
|
||||
const char *LibreTuya::getBoard() {
|
||||
return LT_BOARD_STR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get CPU family ID.
|
||||
*/
|
||||
ChipFamily LibreTuya::getChipFamily() {
|
||||
return FAMILY;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get CPU family name as string.
|
||||
*/
|
||||
const char *LibreTuya::getChipFamilyName() {
|
||||
return STRINGIFY_MACRO(FAMILY);
|
||||
}
|
||||
|
||||
static char *deviceName = NULL;
|
||||
|
||||
/**
|
||||
* @brief Get device friendly name in format "LT-<board>-<chip id>".
|
||||
* Can be used as hostname.
|
||||
*/
|
||||
const char *LibreTuya::getDeviceName() {
|
||||
if (deviceName)
|
||||
return deviceName;
|
||||
uint32_t chipId = getChipId();
|
||||
uint8_t *id = (uint8_t *)&chipId;
|
||||
|
||||
const char *board = getBoard();
|
||||
uint8_t boardLen = strlen(board);
|
||||
deviceName = (char *)malloc(3 + boardLen + 1 + 6 + 1);
|
||||
|
||||
sprintf(deviceName, "LT-%s-%02x%02x%02x", board, id[0], id[1], id[2]);
|
||||
return deviceName;
|
||||
}
|
||||
|
||||
static uint8_t otaRunningIndex = 0;
|
||||
|
||||
/**
|
||||
* @brief Get the currently running firmware OTA index.
|
||||
*/
|
||||
uint8_t LibreTuya::otaGetRunning() {
|
||||
if (otaRunningIndex)
|
||||
return otaRunningIndex;
|
||||
// otaRunningIndex will be correct even after switchOta()
|
||||
return otaRunningIndex = otaGetStoredIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the OTA index for updated firmware.
|
||||
*
|
||||
* Note: returns 1 for chips without dual-OTA.
|
||||
*/
|
||||
uint8_t LibreTuya::otaGetTarget() {
|
||||
if (!otaSupportsDual())
|
||||
return 1;
|
||||
return otaGetRunning() ^ 0b11;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Perform OTA rollback.
|
||||
*
|
||||
* @return false if no second image to run, writing failed or dual-OTA not supported
|
||||
*/
|
||||
bool LibreTuya::otaRollback() {
|
||||
if (!otaCanRollback())
|
||||
return false;
|
||||
if (otaGetRunning() != otaGetStoredIndex())
|
||||
// force switching back to current image
|
||||
return otaSwitch(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if OTA rollback is supported and available (there is another image to run).
|
||||
* @return false if no second image to run or dual-OTA not supported
|
||||
*/
|
||||
bool LibreTuya::otaCanRollback() {
|
||||
if (!otaSupportsDual())
|
||||
return false;
|
||||
if (otaGetRunning() == otaGetStoredIndex())
|
||||
return true;
|
||||
if (otaGetRunning() == 1 && otaHasImage1())
|
||||
return true;
|
||||
if (otaGetRunning() == 2 && otaHasImage2())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
181
arduino/libretuya/core/LibreTuyaAPI.h
Normal file
181
arduino/libretuya/core/LibreTuyaAPI.h
Normal file
@@ -0,0 +1,181 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-04-28. */
|
||||
|
||||
#pragma once
|
||||
|
||||
// LibreTuya version macros
|
||||
#ifndef LT_VERSION
|
||||
#define LT_VERSION 1.0.0
|
||||
#endif
|
||||
#ifndef LT_BOARD
|
||||
#define LT_BOARD unknown
|
||||
#endif
|
||||
#define STRINGIFY(x) #x
|
||||
#define STRINGIFY_MACRO(x) STRINGIFY(x)
|
||||
#define LT_VERSION_STR STRINGIFY_MACRO(LT_VERSION)
|
||||
#define LT_BOARD_STR STRINGIFY_MACRO(LT_BOARD)
|
||||
|
||||
// Includes
|
||||
#include "LibreTuyaConfig.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
// C includes
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#include "lt_logger.h"
|
||||
#include "lt_posix_api.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
// Functional macros
|
||||
#define LT_BANNER() \
|
||||
LT_LOG( \
|
||||
LT_LEVEL_INFO, \
|
||||
__FUNCTION__, \
|
||||
__LINE__, \
|
||||
"LibreTuya v" LT_VERSION_STR " on " LT_BOARD_STR ", compiled at " __DATE__ " " __TIME__ \
|
||||
)
|
||||
|
||||
// ArduinoCore-API doesn't define these anymore
|
||||
#define FPSTR(pstr_pointer) (reinterpret_cast<const __FlashStringHelper *>(pstr_pointer))
|
||||
#define PGM_VOID_P const void *
|
||||
|
||||
void lt_rand_bytes(uint8_t *buf, size_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
String ipToString(const IPAddress &ip);
|
||||
void hexdump(uint8_t *buf, size_t len, uint32_t offset = 0, uint8_t width = 16);
|
||||
#else
|
||||
void hexdump(uint8_t *buf, size_t len, uint32_t offset, uint8_t width);
|
||||
#endif
|
||||
|
||||
// Main class
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <Flash.h> // for flash inline methods
|
||||
#include <core/ChipType.h>
|
||||
|
||||
/**
|
||||
* @brief Main LibreTuya API class.
|
||||
*
|
||||
* This class contains all functions common amongst all families.
|
||||
* Implementations of these methods may vary between families.
|
||||
*
|
||||
* The class is accessible using the `LT` global object (defined by the family).
|
||||
*/
|
||||
class LibreTuya {
|
||||
public: /* Common methods - note: these are documented in LibreTuyaAPI.cpp */
|
||||
const char *getVersion();
|
||||
const char *getBoard();
|
||||
ChipFamily getChipFamily();
|
||||
const char *getChipFamilyName();
|
||||
const char *getDeviceName();
|
||||
uint8_t otaGetRunning();
|
||||
uint8_t otaGetTarget();
|
||||
bool otaRollback();
|
||||
bool otaCanRollback();
|
||||
|
||||
public: /* Inline methods */
|
||||
inline uint32_t getFlashChipSize() {
|
||||
return Flash.getSize();
|
||||
}
|
||||
|
||||
// inline bool flashEraseSector(uint32_t sector) {}
|
||||
// inline bool flashWrite(uint32_t offset, uint32_t *data, size_t size) {}
|
||||
// inline bool flashRead(uint32_t offset, uint32_t *data, size_t size) {}
|
||||
// inline bool partitionEraseRange(const esp_partition_t *partition, uint32_t offset, size_t size) {}
|
||||
// inline bool partitionWrite(const esp_partition_t *partition, uint32_t offset, uint32_t *data, size_t size) {}
|
||||
// inline bool partitionRead(const esp_partition_t *partition, uint32_t offset, uint32_t *data, size_t size) {}
|
||||
|
||||
public: /* Family-defined methods */
|
||||
/**
|
||||
* @brief Reboot the CPU.
|
||||
*/
|
||||
void restart();
|
||||
|
||||
public: /* CPU-related */
|
||||
/**
|
||||
* @brief Get CPU model ID.
|
||||
*/
|
||||
ChipType getChipType();
|
||||
/**
|
||||
* @brief Get CPU model name as string.
|
||||
*/
|
||||
const char *getChipModel();
|
||||
/**
|
||||
* @brief Get CPU unique ID. This may be based on MAC, eFuse, etc.
|
||||
*/
|
||||
uint32_t getChipId();
|
||||
/**
|
||||
* @brief Get CPU core count.
|
||||
*/
|
||||
uint8_t getChipCores();
|
||||
/**
|
||||
* @brief Get CPU core type name as string.
|
||||
*/
|
||||
const char *getChipCoreType();
|
||||
/**
|
||||
* @brief Get CPU frequency in MHz.
|
||||
*/
|
||||
uint32_t getCpuFreqMHz();
|
||||
/**
|
||||
* @brief Get CPU cycle count.
|
||||
*/
|
||||
inline uint32_t getCycleCount() __attribute__((always_inline));
|
||||
|
||||
public: /* Memory management */
|
||||
/**
|
||||
* @brief Get total RAM size.
|
||||
*/
|
||||
uint32_t getRamSize();
|
||||
/**
|
||||
* @brief Get total heap size.
|
||||
*/
|
||||
uint32_t getHeapSize();
|
||||
/**
|
||||
* @brief Get free heap size.
|
||||
*/
|
||||
uint32_t getFreeHeap();
|
||||
/**
|
||||
* @brief Get lowest level of free heap memory.
|
||||
*/
|
||||
uint32_t getMinFreeHeap();
|
||||
/**
|
||||
* @brief Get largest block of heap that can be allocated at once.
|
||||
*/
|
||||
uint32_t getMaxAllocHeap();
|
||||
|
||||
public: /* OTA-related */
|
||||
/**
|
||||
* @brief Read the currently active OTA index, i.e. the one that will boot upon restart.
|
||||
*/
|
||||
uint8_t otaGetStoredIndex();
|
||||
/**
|
||||
* @brief Check if the chip supports dual-OTA.
|
||||
*/
|
||||
bool otaSupportsDual();
|
||||
/**
|
||||
* @brief Check if OTA1 image is valid.
|
||||
*/
|
||||
bool otaHasImage1();
|
||||
/**
|
||||
* @brief Check if OTA2 image is valid.
|
||||
*/
|
||||
bool otaHasImage2();
|
||||
/**
|
||||
* @brief Try to switch OTA index to the other image.
|
||||
*
|
||||
* Note: should return true for chips without dual-OTA. Should return false if one of two images is not valid.
|
||||
*
|
||||
* @param force switch even if other image already marked as active
|
||||
* @return false if writing failed; true otherwise
|
||||
*/
|
||||
bool otaSwitch(bool force = false);
|
||||
};
|
||||
|
||||
extern LibreTuya LT;
|
||||
extern LibreTuya ESP;
|
||||
#endif
|
||||
@@ -1,3 +1,5 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-04-28. */
|
||||
|
||||
#pragma once
|
||||
|
||||
// see docs/API Configuration
|
||||
@@ -21,8 +23,8 @@
|
||||
#define LT_LOGGER_TIMESTAMP 1
|
||||
#endif
|
||||
|
||||
#ifndef LT_LOGGER_FILE
|
||||
#define LT_LOGGER_FILE 0
|
||||
#ifndef LT_LOGGER_CALLER
|
||||
#define LT_LOGGER_CALLER 1
|
||||
#endif
|
||||
|
||||
#ifndef LT_LOGGER_TASK
|
||||
@@ -42,6 +44,11 @@
|
||||
#define LT_LOGLEVEL LT_LEVEL_INFO
|
||||
#endif
|
||||
|
||||
// Free heap size debugging
|
||||
#ifndef LT_LOG_HEAP
|
||||
#define LT_LOG_HEAP 0
|
||||
#endif
|
||||
|
||||
// Per-module debugging
|
||||
#ifndef LT_DEBUG_WIFI
|
||||
#define LT_DEBUG_WIFI 0
|
||||
@@ -62,3 +69,7 @@
|
||||
#ifndef LT_DEBUG_WIFI_AP
|
||||
#define LT_DEBUG_WIFI_AP 0
|
||||
#endif
|
||||
|
||||
#ifndef LT_DEBUG_SSL
|
||||
#define LT_DEBUG_SSL 0
|
||||
#endif
|
||||
@@ -1,3 +1,5 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-04-28. */
|
||||
|
||||
#include "lt_logger.h"
|
||||
|
||||
#include <Arduino.h>
|
||||
@@ -40,8 +42,8 @@ const uint8_t colors[] = {
|
||||
|
||||
unsigned long millis(void);
|
||||
|
||||
#if LT_LOGGER_FILE
|
||||
void lt_log(const uint8_t level, const char *filename, const unsigned short line, const char *format, ...) {
|
||||
#if LT_LOGGER_CALLER
|
||||
void lt_log(const uint8_t level, const char *caller, const unsigned short line, const char *format, ...) {
|
||||
#else
|
||||
void lt_log(const uint8_t level, const char *format, ...) {
|
||||
#endif
|
||||
@@ -85,8 +87,8 @@ void lt_log(const uint8_t level, const char *format, ...) {
|
||||
#if LT_LOGGER_COLOR
|
||||
"\e[0m"
|
||||
#endif
|
||||
#if LT_LOGGER_FILE
|
||||
"%s:%hu: "
|
||||
#if LT_LOGGER_CALLER
|
||||
"%s():%hu: "
|
||||
#endif
|
||||
#if LT_LOGGER_TASK
|
||||
"%s%c "
|
||||
@@ -106,9 +108,9 @@ void lt_log(const uint8_t level, const char *format, ...) {
|
||||
zero // append missing zeroes if printf "%11.3f" prints "0."
|
||||
#endif
|
||||
#endif
|
||||
#if LT_LOGGER_FILE
|
||||
#if LT_LOGGER_CALLER
|
||||
,
|
||||
filename,
|
||||
caller,
|
||||
line
|
||||
#endif
|
||||
#if LT_LOGGER_TASK
|
||||
163
arduino/libretuya/core/lt_logger.h
Normal file
163
arduino/libretuya/core/lt_logger.h
Normal file
@@ -0,0 +1,163 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-04-28. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "LibreTuyaConfig.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#if LT_LOGGER_CALLER
|
||||
#define LT_LOG(level, caller, line, ...) lt_log(level, caller, line, __VA_ARGS__)
|
||||
void lt_log(const uint8_t level, const char *caller, const unsigned short line, const char *format, ...);
|
||||
#else
|
||||
#define LT_LOG(level, caller, line, ...) lt_log(level, __VA_ARGS__)
|
||||
void lt_log(const uint8_t level, const char *format, ...);
|
||||
#endif
|
||||
|
||||
#if LT_LEVEL_TRACE >= LT_LOGLEVEL
|
||||
#define LT_T(...) LT_LOG(LT_LEVEL_TRACE, __FUNCTION__, __LINE__, __VA_ARGS__)
|
||||
#define LT_V(...) LT_LOG(LT_LEVEL_TRACE, __FUNCTION__, __LINE__, __VA_ARGS__)
|
||||
#else
|
||||
#define LT_T(...)
|
||||
#define LT_V(...)
|
||||
#endif
|
||||
|
||||
#if LT_LEVEL_DEBUG >= LT_LOGLEVEL
|
||||
#define LT_D(...) LT_LOG(LT_LEVEL_DEBUG, __FUNCTION__, __LINE__, __VA_ARGS__)
|
||||
#else
|
||||
#define LT_D(...)
|
||||
#endif
|
||||
|
||||
#if LT_LEVEL_INFO >= LT_LOGLEVEL
|
||||
#define LT_I(...) LT_LOG(LT_LEVEL_INFO, __FUNCTION__, __LINE__, __VA_ARGS__)
|
||||
#else
|
||||
#define LT_I(...)
|
||||
#endif
|
||||
|
||||
#if LT_LEVEL_WARN >= LT_LOGLEVEL
|
||||
#define LT_W(...) LT_LOG(LT_LEVEL_WARN, __FUNCTION__, __LINE__, __VA_ARGS__)
|
||||
#else
|
||||
#define LT_W(...)
|
||||
#endif
|
||||
|
||||
#if LT_LEVEL_ERROR >= LT_LOGLEVEL
|
||||
#define LT_E(...) LT_LOG(LT_LEVEL_ERROR, __FUNCTION__, __LINE__, __VA_ARGS__)
|
||||
#else
|
||||
#define LT_E(...)
|
||||
#endif
|
||||
|
||||
#if LT_LEVEL_FATAL >= LT_LOGLEVEL
|
||||
#define LT_F(...) LT_LOG(LT_LEVEL_FATAL, __FUNCTION__, __LINE__, __VA_ARGS__)
|
||||
#else
|
||||
#define LT_F(...)
|
||||
#endif
|
||||
|
||||
#if LT_LOG_HEAP
|
||||
#define LT_HEAP_I() LT_I("Free heap: %u", LT_HEAP_FUNC());
|
||||
#else
|
||||
#define LT_HEAP_I()
|
||||
#endif
|
||||
|
||||
// ESP32 compat
|
||||
#define log_printf(...) LT_I(__VA_ARGS__)
|
||||
#define log_v(...) LT_V(__VA_ARGS__)
|
||||
#define log_d(...) LT_D(__VA_ARGS__)
|
||||
#define log_i(...) LT_I(__VA_ARGS__)
|
||||
#define log_w(...) LT_W(__VA_ARGS__)
|
||||
#define log_e(...) LT_E(__VA_ARGS__)
|
||||
#define log_n(...) LT_E(__VA_ARGS__)
|
||||
#define isr_log_v(...) LT_V(__VA_ARGS__)
|
||||
#define isr_log_d(...) LT_D(__VA_ARGS__)
|
||||
#define isr_log_i(...) LT_I(__VA_ARGS__)
|
||||
#define isr_log_w(...) LT_W(__VA_ARGS__)
|
||||
#define isr_log_e(...) LT_E(__VA_ARGS__)
|
||||
#define isr_log_n(...) LT_E(__VA_ARGS__)
|
||||
#define ESP_LOGV(...) LT_V(__VA_ARGS__)
|
||||
#define ESP_LOGD(...) LT_D(__VA_ARGS__)
|
||||
#define ESP_LOGI(...) LT_I(__VA_ARGS__)
|
||||
#define ESP_LOGW(...) LT_W(__VA_ARGS__)
|
||||
#define ESP_LOGE(...) LT_E(__VA_ARGS__)
|
||||
#define ESP_EARLY_LOGV(...) LT_V(__VA_ARGS__)
|
||||
#define ESP_EARLY_LOGD(...) LT_D(__VA_ARGS__)
|
||||
#define ESP_EARLY_LOGI(...) LT_I(__VA_ARGS__)
|
||||
#define ESP_EARLY_LOGW(...) LT_W(__VA_ARGS__)
|
||||
#define ESP_EARLY_LOGE(...) LT_E(__VA_ARGS__)
|
||||
|
||||
#define LT_T_MOD(module, ...) \
|
||||
do { \
|
||||
if (module) { \
|
||||
LT_T(__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define LT_D_MOD(module, ...) \
|
||||
do { \
|
||||
if (module) { \
|
||||
LT_D(__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define LT_RET(ret) \
|
||||
LT_E("ret=%d", ret); \
|
||||
return ret;
|
||||
|
||||
#define LT_RET_NZ(ret) \
|
||||
if (ret) { \
|
||||
LT_E("ret=%d", ret); \
|
||||
return ret; \
|
||||
}
|
||||
#define LT_RET_LZ(ret) \
|
||||
if (ret < 0) { \
|
||||
LT_E("ret=%d", ret); \
|
||||
return ret; \
|
||||
}
|
||||
#define LT_RET_LEZ(ret) \
|
||||
if (ret <= 0) { \
|
||||
LT_E("ret=%d", ret); \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
#define LT_ERRNO_NZ(ret) \
|
||||
if (ret) { \
|
||||
LT_E("errno=%d, ret=%d", errno, ret); \
|
||||
return ret; \
|
||||
}
|
||||
#define LT_ERRNO_LZ(ret) \
|
||||
if (ret < 0) { \
|
||||
LT_E("errno=%d, ret=%d", errno, ret); \
|
||||
return ret; \
|
||||
}
|
||||
#define LT_ERRNO_LEZ(ret) \
|
||||
if (ret <= 0) { \
|
||||
LT_E("errno=%d, ret=%d", errno, ret); \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
// WiFi.cpp
|
||||
#define LT_T_WG(...) LT_T_MOD(LT_DEBUG_WIFI, __VA_ARGS__)
|
||||
#define LT_V_WG(...) LT_T_MOD(LT_DEBUG_WIFI, __VA_ARGS__)
|
||||
#define LT_D_WG(...) LT_D_MOD(LT_DEBUG_WIFI, __VA_ARGS__)
|
||||
|
||||
// WiFiClient.cpp
|
||||
#define LT_T_WC(...) LT_T_MOD(LT_DEBUG_WIFI_CLIENT, __VA_ARGS__)
|
||||
#define LT_V_WC(...) LT_T_MOD(LT_DEBUG_WIFI_CLIENT, __VA_ARGS__)
|
||||
#define LT_D_WC(...) LT_D_MOD(LT_DEBUG_WIFI_CLIENT, __VA_ARGS__)
|
||||
|
||||
// WiFiServer.cpp
|
||||
#define LT_T_WS(...) LT_T_MOD(LT_DEBUG_WIFI_SERVER, __VA_ARGS__)
|
||||
#define LT_V_WS(...) LT_T_MOD(LT_DEBUG_WIFI_SERVER, __VA_ARGS__)
|
||||
#define LT_D_WS(...) LT_D_MOD(LT_DEBUG_WIFI_SERVER, __VA_ARGS__)
|
||||
|
||||
// WiFiSTA.cpp
|
||||
#define LT_T_WSTA(...) LT_T_MOD(LT_DEBUG_WIFI_STA, __VA_ARGS__)
|
||||
#define LT_V_WSTA(...) LT_T_MOD(LT_DEBUG_WIFI_STA, __VA_ARGS__)
|
||||
#define LT_D_WSTA(...) LT_D_MOD(LT_DEBUG_WIFI_STA, __VA_ARGS__)
|
||||
|
||||
// WiFiAP.cpp
|
||||
#define LT_T_WAP(...) LT_T_MOD(LT_DEBUG_WIFI_AP, __VA_ARGS__)
|
||||
#define LT_V_WAP(...) LT_T_MOD(LT_DEBUG_WIFI_AP, __VA_ARGS__)
|
||||
#define LT_D_WAP(...) LT_D_MOD(LT_DEBUG_WIFI_AP, __VA_ARGS__)
|
||||
|
||||
// WiFiClientSecure.cpp & implementations
|
||||
#define LT_T_SSL(...) LT_T_MOD(LT_DEBUG_SSL, __VA_ARGS__)
|
||||
#define LT_V_SSL(...) LT_T_MOD(LT_DEBUG_SSL, __VA_ARGS__)
|
||||
#define LT_D_SSL(...) LT_D_MOD(LT_DEBUG_SSL, __VA_ARGS__)
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
#ifdef HTTPCLIENT_1_1_COMPATIBLE
|
||||
#include <WiFi.h>
|
||||
// #include <WiFiClientSecure.h>
|
||||
#include <WiFiClientSecure.h>
|
||||
#endif
|
||||
|
||||
// #include <StreamString.h>
|
||||
@@ -63,7 +63,7 @@ class TLSTraits : public TransportTraits {
|
||||
TLSTraits(const char *CAcert, const char *clicert = nullptr, const char *clikey = nullptr)
|
||||
: _cacert(CAcert), _clicert(clicert), _clikey(clikey) {}
|
||||
|
||||
/* std::unique_ptr<WiFiClient> create() override {
|
||||
std::unique_ptr<WiFiClient> create() override {
|
||||
return std::unique_ptr<WiFiClient>(new WiFiClientSecure());
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ class TLSTraits : public TransportTraits {
|
||||
wcs.setPrivateKey(_clikey);
|
||||
}
|
||||
return true;
|
||||
} */
|
||||
}
|
||||
|
||||
protected:
|
||||
const char *_cacert;
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <WiFiClient.h>
|
||||
// #include <WiFiClientSecure.h>
|
||||
#include <WiFiClientSecure.h>
|
||||
#include <memory>
|
||||
|
||||
/// Cookie jar support
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-04-29. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <time.h>
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
DisableFormat: true
|
||||
SortIncludes: Never
|
||||
98
arduino/libretuya/libraries/NetUtils/IPv6Address.cpp
Normal file
98
arduino/libretuya/libraries/NetUtils/IPv6Address.cpp
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
IPv6Address.cpp - Base class that provides IPv6Address
|
||||
Copyright (c) 2011 Adrian McEwen. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "IPv6Address.h"
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <api/Print.h>
|
||||
|
||||
IPv6Address::IPv6Address() {
|
||||
memset(_address.bytes, 0, sizeof(_address.bytes));
|
||||
}
|
||||
|
||||
IPv6Address::IPv6Address(const uint8_t *address) {
|
||||
memcpy(_address.bytes, address, sizeof(_address.bytes));
|
||||
}
|
||||
|
||||
IPv6Address::IPv6Address(const uint32_t *address) {
|
||||
memcpy(_address.bytes, (const uint8_t *)address, sizeof(_address.bytes));
|
||||
}
|
||||
|
||||
IPv6Address &IPv6Address::operator=(const uint8_t *address) {
|
||||
memcpy(_address.bytes, address, sizeof(_address.bytes));
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool IPv6Address::operator==(const uint8_t *addr) const {
|
||||
return memcmp(addr, _address.bytes, sizeof(_address.bytes)) == 0;
|
||||
}
|
||||
|
||||
size_t IPv6Address::printTo(Print &p) const {
|
||||
/* size_t n = 0;
|
||||
for(int i = 0; i < 16; i+=2) {
|
||||
if(i){
|
||||
n += p.print(':');
|
||||
}
|
||||
n += p.printf("%02x", _address.bytes[i]);
|
||||
n += p.printf("%02x", _address.bytes[i+1]);
|
||||
|
||||
}
|
||||
return n; */
|
||||
}
|
||||
|
||||
String IPv6Address::toString() const {
|
||||
char szRet[40];
|
||||
sprintf(
|
||||
szRet,
|
||||
"%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
|
||||
_address.bytes[0],
|
||||
_address.bytes[1],
|
||||
_address.bytes[2],
|
||||
_address.bytes[3],
|
||||
_address.bytes[4],
|
||||
_address.bytes[5],
|
||||
_address.bytes[6],
|
||||
_address.bytes[7],
|
||||
_address.bytes[8],
|
||||
_address.bytes[9],
|
||||
_address.bytes[10],
|
||||
_address.bytes[11],
|
||||
_address.bytes[12],
|
||||
_address.bytes[13],
|
||||
_address.bytes[14],
|
||||
_address.bytes[15]
|
||||
);
|
||||
return String(szRet);
|
||||
}
|
||||
|
||||
bool IPv6Address::fromString(const char *address) {
|
||||
// format 0011:2233:4455:6677:8899:aabb:ccdd:eeff
|
||||
if (strlen(address) != 39) {
|
||||
return false;
|
||||
}
|
||||
char *pos = (char *)address;
|
||||
size_t i = 0;
|
||||
for (i = 0; i < 16; i += 2) {
|
||||
if (!sscanf(pos, "%2hhx", &_address.bytes[i]) || !sscanf(pos + 2, "%2hhx", &_address.bytes[i + 1])) {
|
||||
return false;
|
||||
}
|
||||
pos += 5;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
97
arduino/libretuya/libraries/NetUtils/IPv6Address.h
Normal file
97
arduino/libretuya/libraries/NetUtils/IPv6Address.h
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
IPv6Address.h - Base class that provides IPv6Address
|
||||
Copyright (c) 2011 Adrian McEwen. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <api/Print.h>
|
||||
#include <api/String.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// A class to make it easier to handle and pass around IP addresses
|
||||
|
||||
namespace arduino {
|
||||
|
||||
class IPv6Address : public Printable {
|
||||
private:
|
||||
union {
|
||||
uint8_t bytes[16]; // IPv4 address
|
||||
uint32_t dword[4];
|
||||
} _address;
|
||||
|
||||
// Access the raw byte array containing the address. Because this returns a pointer
|
||||
// to the internal structure rather than a copy of the address this function should only
|
||||
// be used when you know that the usage of the returned uint8_t* will be transient and not
|
||||
// stored.
|
||||
uint8_t *raw_address() {
|
||||
return _address.bytes;
|
||||
}
|
||||
|
||||
public:
|
||||
// Constructors
|
||||
IPv6Address();
|
||||
IPv6Address(const uint8_t *address);
|
||||
IPv6Address(const uint32_t *address);
|
||||
|
||||
virtual ~IPv6Address() {}
|
||||
|
||||
bool fromString(const char *address);
|
||||
|
||||
bool fromString(const String &address) {
|
||||
return fromString(address.c_str());
|
||||
}
|
||||
|
||||
operator const uint8_t *() const {
|
||||
return _address.bytes;
|
||||
}
|
||||
|
||||
operator const uint32_t *() const {
|
||||
return _address.dword;
|
||||
}
|
||||
|
||||
bool operator==(const IPv6Address &addr) const {
|
||||
return (_address.dword[0] == addr._address.dword[0]) && (_address.dword[1] == addr._address.dword[1]) &&
|
||||
(_address.dword[2] == addr._address.dword[2]) && (_address.dword[3] == addr._address.dword[3]);
|
||||
}
|
||||
|
||||
bool operator==(const uint8_t *addr) const;
|
||||
|
||||
// Overloaded index operator to allow getting and setting individual octets of the address
|
||||
uint8_t operator[](int index) const {
|
||||
return _address.bytes[index];
|
||||
}
|
||||
|
||||
uint8_t &operator[](int index) {
|
||||
return _address.bytes[index];
|
||||
}
|
||||
|
||||
// Overloaded copy operators to allow initialisation of IPv6Address objects from other types
|
||||
IPv6Address &operator=(const uint8_t *address);
|
||||
|
||||
// TODO implement printTo()
|
||||
virtual size_t printTo(Print &p) const;
|
||||
String toString() const;
|
||||
|
||||
friend class UDP;
|
||||
friend class Client;
|
||||
friend class Server;
|
||||
};
|
||||
|
||||
} // namespace arduino
|
||||
|
||||
using arduino::IPv6Address;
|
||||
@@ -19,7 +19,7 @@ size_t LwIPRxBuffer::r_available() {
|
||||
return 0;
|
||||
}
|
||||
uint16_t count = 0;
|
||||
int res = lwip_ioctl(_sock, FIONREAD, &count);
|
||||
int res = lwip_ioctl(_sock, FIONREAD, &count);
|
||||
if (res < 0) {
|
||||
_failed = true;
|
||||
return 0;
|
||||
5
arduino/libretuya/libraries/NetUtils/api/IPv6Address.h
Normal file
5
arduino/libretuya/libraries/NetUtils/api/IPv6Address.h
Normal file
@@ -0,0 +1,5 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-04-30. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../IPv6Address.h"
|
||||
442
arduino/libretuya/libraries/NetUtils/ssl/MbedTLSClient.cpp
Normal file
442
arduino/libretuya/libraries/NetUtils/ssl/MbedTLSClient.cpp
Normal file
@@ -0,0 +1,442 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-04-30. */
|
||||
|
||||
#include "MbedTLSClient.h"
|
||||
|
||||
#include <IPAddress.h>
|
||||
#include <WiFi.h>
|
||||
#include <WiFiClient.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#include <mbedtls/debug.h>
|
||||
#include <mbedtls/platform.h>
|
||||
#include <mbedtls/sha256.h>
|
||||
#include <mbedtls/ssl.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
MbedTLSClient::MbedTLSClient() : WiFiClient() {
|
||||
init(); // ensure the context is zero filled
|
||||
}
|
||||
|
||||
MbedTLSClient::MbedTLSClient(int sock) : WiFiClient(sock) {
|
||||
init(); // ensure the context is zero filled
|
||||
}
|
||||
|
||||
void MbedTLSClient::stop() {
|
||||
WiFiClient::stop();
|
||||
LT_V_SSL("Closing SSL connection");
|
||||
|
||||
if (_sslCfg.ca_chain) {
|
||||
mbedtls_x509_crt_free(&_caCert);
|
||||
}
|
||||
if (_sslCfg.key_cert) {
|
||||
mbedtls_x509_crt_free(&_clientCert);
|
||||
mbedtls_pk_free(&_clientKey);
|
||||
}
|
||||
mbedtls_ssl_free(&_sslCtx);
|
||||
mbedtls_ssl_config_free(&_sslCfg);
|
||||
}
|
||||
|
||||
void MbedTLSClient::init() {
|
||||
// Realtek AmbZ: init platform here to ensure HW crypto is initialized in ssl_init
|
||||
mbedtls_platform_set_calloc_free(calloc, free);
|
||||
mbedtls_ssl_init(&_sslCtx);
|
||||
mbedtls_ssl_config_init(&_sslCfg);
|
||||
}
|
||||
|
||||
int MbedTLSClient::connect(IPAddress ip, uint16_t port, int32_t timeout) {
|
||||
return connect(ipToString(ip).c_str(), port, timeout);
|
||||
}
|
||||
|
||||
int MbedTLSClient::connect(const char *host, uint16_t port, int32_t timeout) {
|
||||
if (_pskIdentStr && _pskStr)
|
||||
return connect(host, port, timeout, NULL, NULL, NULL, _pskIdentStr, _pskStr) == 0;
|
||||
return connect(host, port, timeout, _caCertStr, _clientCertStr, _clientKeyStr, NULL, NULL) == 0;
|
||||
}
|
||||
|
||||
int MbedTLSClient::connect(
|
||||
IPAddress ip, uint16_t port, const char *rootCABuf, const char *clientCert, const char *clientKey
|
||||
) {
|
||||
return connect(ipToString(ip).c_str(), port, 0, rootCABuf, clientCert, clientKey, NULL, NULL) == 0;
|
||||
}
|
||||
|
||||
int MbedTLSClient::connect(
|
||||
const char *host, uint16_t port, const char *rootCABuf, const char *clientCert, const char *clientKey
|
||||
) {
|
||||
return connect(host, port, 0, rootCABuf, clientCert, clientKey, NULL, NULL) == 0;
|
||||
}
|
||||
|
||||
int MbedTLSClient::connect(IPAddress ip, uint16_t port, const char *pskIdent, const char *psk) {
|
||||
return connect(ipToString(ip).c_str(), port, 0, NULL, NULL, NULL, pskIdent, psk) == 0;
|
||||
}
|
||||
|
||||
int MbedTLSClient::connect(const char *host, uint16_t port, const char *pskIdent, const char *psk) {
|
||||
return connect(host, port, 0, NULL, NULL, NULL, pskIdent, psk) == 0;
|
||||
}
|
||||
|
||||
static int ssl_random(void *data, unsigned char *output, size_t len) {
|
||||
lt_rand_bytes((uint8_t *)output, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void debug_cb(void *ctx, int level, const char *file, int line, const char *str) {
|
||||
LT_I("%04d: |%d| %s", line, level, str);
|
||||
}
|
||||
|
||||
int MbedTLSClient::connect(
|
||||
const char *host,
|
||||
uint16_t port,
|
||||
int32_t timeout,
|
||||
const char *rootCABuf,
|
||||
const char *clientCert,
|
||||
const char *clientKey,
|
||||
const char *pskIdent,
|
||||
const char *psk
|
||||
) {
|
||||
LT_D_SSL("Free heap before TLS: TODO");
|
||||
|
||||
if (!rootCABuf && !pskIdent && !psk && !_insecure && !_useRootCA)
|
||||
return -1;
|
||||
|
||||
if (timeout <= 0)
|
||||
timeout = _timeout; // use default when -1 passed as timeout
|
||||
|
||||
IPAddress addr = WiFi.hostByName(host);
|
||||
if (!(uint32_t)addr)
|
||||
return -1;
|
||||
|
||||
int ret = WiFiClient::connect(addr, port, timeout);
|
||||
if (ret < 0) {
|
||||
LT_E("SSL socket failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *uid = "lt-ssl"; // TODO
|
||||
|
||||
LT_V_SSL("Init SSL");
|
||||
init();
|
||||
|
||||
// mbedtls_debug_set_threshold(4);
|
||||
// mbedtls_ssl_conf_dbg(&_sslCfg, debug_cb, NULL);
|
||||
|
||||
ret = mbedtls_ssl_config_defaults(
|
||||
&_sslCfg,
|
||||
MBEDTLS_SSL_IS_CLIENT,
|
||||
MBEDTLS_SSL_TRANSPORT_STREAM,
|
||||
MBEDTLS_SSL_PRESET_DEFAULT
|
||||
);
|
||||
LT_RET_NZ(ret);
|
||||
|
||||
#ifdef MBEDTLS_SSL_ALPN
|
||||
if (_alpnProtocols) {
|
||||
ret = mbedtls_ssl_conf_alpn_protocols(&_sslCfg, _alpnProtocols);
|
||||
LT_RET_NZ(ret);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (_insecure) {
|
||||
mbedtls_ssl_conf_authmode(&_sslCfg, MBEDTLS_SSL_VERIFY_NONE);
|
||||
} else if (rootCABuf) {
|
||||
mbedtls_x509_crt_init(&_caCert);
|
||||
mbedtls_ssl_conf_authmode(&_sslCfg, MBEDTLS_SSL_VERIFY_REQUIRED);
|
||||
ret = mbedtls_x509_crt_parse(&_caCert, (const unsigned char *)rootCABuf, strlen(rootCABuf) + 1);
|
||||
mbedtls_ssl_conf_ca_chain(&_sslCfg, &_caCert, NULL);
|
||||
if (ret < 0) {
|
||||
mbedtls_x509_crt_free(&_caCert);
|
||||
LT_RET(ret);
|
||||
}
|
||||
} else if (_useRootCA) {
|
||||
return -1; // not implemented
|
||||
} else if (pskIdent && psk) {
|
||||
#ifdef MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED
|
||||
uint16_t len = strlen(psk);
|
||||
if ((len & 1) != 0 || len > 2 * MBEDTLS_PSK_MAX_LEN) {
|
||||
LT_E("PSK length invalid");
|
||||
return -1;
|
||||
}
|
||||
unsigned char pskBin[MBEDTLS_PSK_MAX_LEN] = {};
|
||||
for (uint8_t i = 0; i < len; i++) {
|
||||
uint8_t c = psk[i];
|
||||
c |= 0b00100000; // make lowercase
|
||||
c -= '0' * (c >= '0' && c <= '9');
|
||||
c -= ('a' - 10) * (c >= 'a' && c <= 'z');
|
||||
if (c > 0xf)
|
||||
return -1;
|
||||
pskBin[i / 2] |= c << (4 * ((i & 1) ^ 1));
|
||||
}
|
||||
ret = mbedtls_ssl_conf_psk(&_sslCfg, pskBin, len / 2, (const unsigned char *)pskIdent, strlen(pskIdent));
|
||||
LT_RET_NZ(ret);
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!_insecure && clientCert && clientKey) {
|
||||
mbedtls_x509_crt_init(&_clientCert);
|
||||
mbedtls_pk_init(&_clientKey);
|
||||
LT_V_SSL("Loading client cert");
|
||||
ret = mbedtls_x509_crt_parse(&_clientCert, (const unsigned char *)clientCert, strlen(clientCert) + 1);
|
||||
if (ret < 0) {
|
||||
mbedtls_x509_crt_free(&_clientCert);
|
||||
LT_RET(ret);
|
||||
}
|
||||
LT_V_SSL("Loading private key");
|
||||
ret = mbedtls_pk_parse_key(&_clientKey, (const unsigned char *)clientKey, strlen(clientKey) + 1, NULL, 0);
|
||||
if (ret < 0) {
|
||||
mbedtls_x509_crt_free(&_clientCert);
|
||||
LT_RET(ret);
|
||||
}
|
||||
mbedtls_ssl_conf_own_cert(&_sslCfg, &_clientCert, &_clientKey);
|
||||
}
|
||||
|
||||
LT_V_SSL("Setting TLS hostname");
|
||||
ret = mbedtls_ssl_set_hostname(&_sslCtx, host);
|
||||
LT_RET_NZ(ret);
|
||||
|
||||
mbedtls_ssl_conf_rng(&_sslCfg, ssl_random, NULL);
|
||||
ret = mbedtls_ssl_setup(&_sslCtx, &_sslCfg);
|
||||
LT_RET_NZ(ret);
|
||||
|
||||
_sockTls = fd();
|
||||
mbedtls_ssl_set_bio(&_sslCtx, &_sockTls, mbedtls_net_send, mbedtls_net_recv, NULL);
|
||||
mbedtls_net_set_nonblock((mbedtls_net_context *)&_sockTls);
|
||||
|
||||
LT_V_SSL("SSL handshake");
|
||||
if (_handshakeTimeout == 0)
|
||||
_handshakeTimeout = timeout;
|
||||
unsigned long start = millis();
|
||||
while (ret = mbedtls_ssl_handshake(&_sslCtx)) {
|
||||
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
|
||||
LT_RET(ret);
|
||||
}
|
||||
if ((millis() - start) > _handshakeTimeout) {
|
||||
LT_E("SSL handshake timeout");
|
||||
return -1;
|
||||
}
|
||||
delay(2);
|
||||
}
|
||||
|
||||
if (clientCert && clientKey) {
|
||||
LT_D_SSL(
|
||||
"Protocol %s, ciphersuite %s",
|
||||
mbedtls_ssl_get_version(&_sslCtx),
|
||||
mbedtls_ssl_get_ciphersuite(&_sslCtx)
|
||||
);
|
||||
ret = mbedtls_ssl_get_record_expansion(&_sslCtx);
|
||||
if (ret >= 0)
|
||||
LT_D_SSL("Record expansion: %d", ret);
|
||||
else {
|
||||
LT_W("Record expansion unknown");
|
||||
}
|
||||
}
|
||||
|
||||
LT_V_SSL("Verifying certificate");
|
||||
ret = mbedtls_ssl_get_verify_result(&_sslCtx);
|
||||
if (ret) {
|
||||
char buf[512];
|
||||
memset(buf, 0, sizeof(buf));
|
||||
mbedtls_x509_crt_verify_info(buf, sizeof(buf), " ! ", ret);
|
||||
LT_E("Failed to verify peer certificate! Verification info: %s", buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (rootCABuf)
|
||||
mbedtls_x509_crt_free(&_caCert);
|
||||
if (clientCert)
|
||||
mbedtls_x509_crt_free(&_clientCert);
|
||||
if (clientKey != NULL)
|
||||
mbedtls_pk_free(&_clientKey);
|
||||
return 0; // OK
|
||||
}
|
||||
|
||||
size_t MbedTLSClient::write(const uint8_t *buf, size_t size) {
|
||||
int ret = -1;
|
||||
while ((ret = mbedtls_ssl_write(&_sslCtx, buf, size)) <= 0) {
|
||||
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE && ret < 0) {
|
||||
LT_RET(ret);
|
||||
}
|
||||
delay(2);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int MbedTLSClient::available() {
|
||||
bool peeked = _peeked >= 0;
|
||||
if (!connected())
|
||||
return peeked;
|
||||
|
||||
int ret = mbedtls_ssl_read(&_sslCtx, NULL, 0);
|
||||
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE && ret < 0) {
|
||||
stop();
|
||||
return peeked ? peeked : ret;
|
||||
}
|
||||
return mbedtls_ssl_get_bytes_avail(&_sslCtx) + peeked;
|
||||
}
|
||||
|
||||
int MbedTLSClient::read(uint8_t *buf, size_t size) {
|
||||
bool peeked = false;
|
||||
int toRead = available();
|
||||
if ((!buf && size) || toRead <= 0)
|
||||
return -1;
|
||||
if (!size)
|
||||
return 0;
|
||||
if (_peeked >= 0) {
|
||||
buf[0] = _peeked;
|
||||
_peeked = -1;
|
||||
size--;
|
||||
toRead--;
|
||||
if (!size || !toRead)
|
||||
return 1;
|
||||
buf++;
|
||||
peeked = true;
|
||||
}
|
||||
|
||||
int ret = mbedtls_ssl_read(&_sslCtx, buf, size);
|
||||
if (ret < 0) {
|
||||
stop();
|
||||
return peeked ? peeked : ret;
|
||||
}
|
||||
return ret + peeked;
|
||||
}
|
||||
|
||||
int MbedTLSClient::peek() {
|
||||
if (_peeked >= 0)
|
||||
return _peeked;
|
||||
_peeked = timedRead();
|
||||
return _peeked;
|
||||
}
|
||||
|
||||
void MbedTLSClient::flush() {}
|
||||
|
||||
int MbedTLSClient::lastError(char *buf, const size_t size) {
|
||||
return 0; // TODO (?)
|
||||
}
|
||||
|
||||
void MbedTLSClient::setInsecure() {
|
||||
_caCertStr = NULL;
|
||||
_clientCertStr = NULL;
|
||||
_clientKeyStr = NULL;
|
||||
_pskIdentStr = NULL;
|
||||
_pskStr = NULL;
|
||||
_insecure = true;
|
||||
}
|
||||
|
||||
void MbedTLSClient::setPreSharedKey(const char *pskIdent, const char *psk) {
|
||||
_pskIdentStr = pskIdent;
|
||||
_pskStr = psk;
|
||||
}
|
||||
|
||||
void MbedTLSClient::setCACert(const char *rootCA) {
|
||||
_caCertStr = rootCA;
|
||||
}
|
||||
|
||||
void MbedTLSClient::setCertificate(const char *clientCA) {
|
||||
_clientCertStr = clientCA;
|
||||
}
|
||||
|
||||
void MbedTLSClient::setPrivateKey(const char *privateKey) {
|
||||
_clientKeyStr = privateKey;
|
||||
}
|
||||
|
||||
char *streamToStr(Stream &stream, size_t size) {
|
||||
char *buf = (char *)malloc(size + 1);
|
||||
if (!buf)
|
||||
return NULL;
|
||||
if (size != stream.readBytes(buf, size)) {
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
buf[size] = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
bool MbedTLSClient::loadCACert(Stream &stream, size_t size) {
|
||||
char *str = streamToStr(stream, size);
|
||||
if (str) {
|
||||
_caCertStr = str;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MbedTLSClient::loadCertificate(Stream &stream, size_t size) {
|
||||
char *str = streamToStr(stream, size);
|
||||
if (str) {
|
||||
_clientCertStr = str;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MbedTLSClient::loadPrivateKey(Stream &stream, size_t size) {
|
||||
char *str = streamToStr(stream, size);
|
||||
if (str) {
|
||||
_clientKeyStr = str;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MbedTLSClient::verify(const char *fingerprint, const char *domainName) {
|
||||
uint8_t fpLocal[32] = {};
|
||||
uint16_t len = strlen(fingerprint);
|
||||
uint8_t byte = 0;
|
||||
for (uint8_t i = 0; i < len; i++) {
|
||||
uint8_t c = fingerprint[i];
|
||||
while ((c == ' ' || c == ':') && i < len) {
|
||||
c = fingerprint[++i];
|
||||
}
|
||||
c |= 0b00100000; // make lowercase
|
||||
c -= '0' * (c >= '0' && c <= '9');
|
||||
c -= ('a' - 10) * (c >= 'a' && c <= 'z');
|
||||
if (c > 0xf)
|
||||
return -1;
|
||||
fpLocal[byte / 2] |= c << (4 * ((byte & 1) ^ 1));
|
||||
byte++;
|
||||
if (byte >= 64)
|
||||
break;
|
||||
}
|
||||
|
||||
uint8_t fpRemote[32];
|
||||
if (!getFingerprintSHA256(fpRemote))
|
||||
return false;
|
||||
|
||||
if (memcmp(fpLocal, fpRemote, 32)) {
|
||||
LT_D_SSL("Fingerprints don't match");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!domainName)
|
||||
return true;
|
||||
// TODO domain name verification
|
||||
return true;
|
||||
}
|
||||
|
||||
void MbedTLSClient::setHandshakeTimeout(unsigned long handshakeTimeout) {
|
||||
_handshakeTimeout = handshakeTimeout * 1000;
|
||||
}
|
||||
|
||||
void MbedTLSClient::setAlpnProtocols(const char **alpnProtocols) {
|
||||
_alpnProtocols = alpnProtocols;
|
||||
}
|
||||
|
||||
bool MbedTLSClient::getFingerprintSHA256(uint8_t result[32]) {
|
||||
const mbedtls_x509_crt *cert = mbedtls_ssl_get_peer_cert(&_sslCtx);
|
||||
if (!cert) {
|
||||
LT_E("Failed to get peer certificate");
|
||||
return false;
|
||||
}
|
||||
mbedtls_sha256_context shaCtx;
|
||||
mbedtls_sha256_init(&shaCtx);
|
||||
mbedtls_sha256_starts(&shaCtx, false);
|
||||
mbedtls_sha256_update(&shaCtx, cert->raw.p, cert->raw.len);
|
||||
mbedtls_sha256_finish(&shaCtx, result);
|
||||
return true;
|
||||
}
|
||||
90
arduino/libretuya/libraries/NetUtils/ssl/MbedTLSClient.h
Normal file
90
arduino/libretuya/libraries/NetUtils/ssl/MbedTLSClient.h
Normal file
@@ -0,0 +1,90 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-04-30. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <api/WiFiClient.h>
|
||||
#include <api/WiFiClientSecure.h>
|
||||
|
||||
#include <WiFiClient.h> // extend family's WiFiClient impl
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#include <mbedtls/net.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
class MbedTLSClient : public WiFiClient, public IWiFiClientSecure {
|
||||
private:
|
||||
mbedtls_ssl_context _sslCtx;
|
||||
mbedtls_ssl_config _sslCfg;
|
||||
mbedtls_x509_crt _caCert;
|
||||
mbedtls_x509_crt _clientCert;
|
||||
mbedtls_pk_context _clientKey;
|
||||
uint32_t _handshakeTimeout = 0;
|
||||
|
||||
void init();
|
||||
int _sockTls = -1;
|
||||
bool _insecure = false;
|
||||
bool _useRootCA = false;
|
||||
int _peeked = -1;
|
||||
|
||||
const char *_caCertStr;
|
||||
const char *_clientCertStr;
|
||||
const char *_clientKeyStr;
|
||||
const char *_pskIdentStr;
|
||||
const char *_pskStr;
|
||||
const char **_alpnProtocols;
|
||||
|
||||
int connect(
|
||||
const char *host,
|
||||
uint16_t port,
|
||||
int32_t timeout,
|
||||
const char *rootCABuf,
|
||||
const char *clientCert,
|
||||
const char *clientKey,
|
||||
const char *pskIdent,
|
||||
const char *psk
|
||||
);
|
||||
|
||||
public:
|
||||
MbedTLSClient();
|
||||
MbedTLSClient(int sock);
|
||||
|
||||
int connect(IPAddress ip, uint16_t port, int32_t timeout);
|
||||
int connect(const char *host, uint16_t port, int32_t timeout);
|
||||
|
||||
int connect(IPAddress ip, uint16_t port, const char *rootCABuf, const char *clientCert, const char *clientKey);
|
||||
int connect(const char *host, uint16_t port, const char *rootCABuf, const char *clientCert, const char *clientKey);
|
||||
int connect(IPAddress ip, uint16_t port, const char *pskIdent, const char *psk);
|
||||
int connect(const char *host, uint16_t port, const char *pskIdent, const char *psk);
|
||||
|
||||
size_t write(const uint8_t *buf, size_t size);
|
||||
|
||||
int available();
|
||||
|
||||
int read(uint8_t *buf, size_t size);
|
||||
int peek();
|
||||
void flush();
|
||||
void stop();
|
||||
|
||||
int lastError(char *buf, const size_t size);
|
||||
void setInsecure(); // Don't validate the chain, just accept whatever is given. VERY INSECURE!
|
||||
void setPreSharedKey(const char *pskIdent, const char *psk); // psk in hex
|
||||
void setCACert(const char *rootCA);
|
||||
void setCertificate(const char *clientCA);
|
||||
void setPrivateKey(const char *privateKey);
|
||||
bool loadCACert(Stream &stream, size_t size);
|
||||
bool loadCertificate(Stream &stream, size_t size);
|
||||
bool loadPrivateKey(Stream &stream, size_t size);
|
||||
bool verify(const char *fingerprint, const char *domainName);
|
||||
void setHandshakeTimeout(unsigned long handshakeTimeout);
|
||||
void setAlpnProtocols(const char **alpnProtocols);
|
||||
bool getFingerprintSHA256(uint8_t result[32]);
|
||||
|
||||
using WiFiClient::connect;
|
||||
using WiFiClient::read;
|
||||
};
|
||||
199
arduino/libretuya/libraries/Update/Update.cpp
Normal file
199
arduino/libretuya/libraries/Update/Update.cpp
Normal file
@@ -0,0 +1,199 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-29. */
|
||||
|
||||
#include "Update.h"
|
||||
|
||||
UpdateClass::UpdateClass() : ctx(NULL), info(NULL), buf(NULL) {
|
||||
cleanup();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize the update process.
|
||||
*
|
||||
* @param size total UF2 file size
|
||||
* @param command must be U_FLASH
|
||||
* @return false if parameters are invalid or update is running, true otherwise
|
||||
*/
|
||||
bool UpdateClass::begin(size_t size, int command, int unused2, uint8_t unused3, const char *unused4) {
|
||||
if (ctx)
|
||||
return false;
|
||||
cleanup();
|
||||
|
||||
ctx = uf2_ctx_init(LT.otaGetTarget(), FAMILY);
|
||||
info = uf2_info_init();
|
||||
|
||||
if (!size)
|
||||
return errorArd(UPDATE_ERROR_SIZE);
|
||||
|
||||
if (command != U_FLASH)
|
||||
return errorArd(UPDATE_ERROR_BAD_ARGUMENT);
|
||||
|
||||
bytesTotal = size;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Finalize the update process. Check for errors and update completion, then activate the new firmware image.
|
||||
*
|
||||
* @param evenIfRemaining no idea
|
||||
* @return false in case of errors or no update running, true otherwise
|
||||
*/
|
||||
bool UpdateClass::end(bool evenIfRemaining) {
|
||||
if (hasError() || !ctx)
|
||||
// false if not running
|
||||
return false;
|
||||
|
||||
if (!isFinished() && !evenIfRemaining) {
|
||||
// abort if not finished
|
||||
return errorArd(UPDATE_ERROR_ABORT);
|
||||
}
|
||||
// TODO what is evenIfRemaining for?
|
||||
if (!LT.otaSwitch())
|
||||
// try to activate the second OTA
|
||||
return errorArd(UPDATE_ERROR_ACTIVATE);
|
||||
|
||||
cleanup();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write a chunk of data to the buffer or flash memory.
|
||||
*
|
||||
* It's advised to write in 512-byte chunks (or its multiples).
|
||||
*
|
||||
* @param data
|
||||
* @param len
|
||||
* @return size_t
|
||||
*/
|
||||
size_t UpdateClass::write(uint8_t *data, size_t len) {
|
||||
size_t written = 0;
|
||||
if (hasError() || !ctx)
|
||||
// 0 if not running
|
||||
return 0;
|
||||
|
||||
/* while (buf == bufPos && len >= UF2_BLOCK_SIZE) {
|
||||
// buffer empty and entire block is in data
|
||||
if (!tryWriteData(data, UF2_BLOCK_SIZE)) {
|
||||
// returns 0 if data contains an invalid block
|
||||
return written;
|
||||
}
|
||||
data += UF2_BLOCK_SIZE;
|
||||
len -= UF2_BLOCK_SIZE;
|
||||
written += UF2_BLOCK_SIZE;
|
||||
} */
|
||||
|
||||
// write until buffer space is available
|
||||
uint16_t toWrite;
|
||||
while (len && (toWrite = min(len, bufLeft()))) {
|
||||
tryWriteData(data, toWrite);
|
||||
if (hasError())
|
||||
// return on errors
|
||||
return written;
|
||||
data += toWrite;
|
||||
len -= toWrite;
|
||||
written += toWrite;
|
||||
}
|
||||
return written;
|
||||
}
|
||||
|
||||
size_t UpdateClass::writeStream(Stream &data) {
|
||||
size_t written = 0;
|
||||
if (hasError() || !ctx)
|
||||
// 0 if not running
|
||||
return 0;
|
||||
|
||||
uint32_t lastData = millis();
|
||||
// loop until the update is complete
|
||||
while (remaining()) {
|
||||
// check stream availability
|
||||
int available = data.available();
|
||||
if (available <= 0) {
|
||||
if (millis() - lastData > UPDATE_TIMEOUT_MS) {
|
||||
// waited for data too long; abort with error
|
||||
errorArd(UPDATE_ERROR_STREAM);
|
||||
return written;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// available > 0
|
||||
lastData = millis();
|
||||
|
||||
// read data to fit in the remaining buffer space
|
||||
bufAlloc();
|
||||
uint16_t read = data.readBytes(bufPos, bufLeft());
|
||||
bufPos += read;
|
||||
written += read;
|
||||
tryWriteData();
|
||||
if (hasError())
|
||||
// return on errors
|
||||
return written;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Try to use the buffer as a block to write. In case of UF2 errors,
|
||||
* error codes are set, the update is aborted and 0 is returned
|
||||
*
|
||||
* @param data received data to copy to buffer or NULL if already in buffer
|
||||
* @param len received data length - must be at most bufLeft()
|
||||
* @return size_t "used" data size - 0 or 512
|
||||
*/
|
||||
size_t UpdateClass::tryWriteData(uint8_t *data, size_t len) {
|
||||
uf2_block_t *block = NULL;
|
||||
|
||||
if (len == UF2_BLOCK_SIZE) {
|
||||
// data has a complete block
|
||||
block = (uf2_block_t *)data;
|
||||
} else if (data && len) {
|
||||
// data has a part of a block, copy it to buffer
|
||||
bufAlloc();
|
||||
memcpy(bufPos, data, len);
|
||||
bufPos += len;
|
||||
}
|
||||
|
||||
if (!block && bufSize() == UF2_BLOCK_SIZE) {
|
||||
// use buffer as block (only if not found above)
|
||||
block = (uf2_block_t *)buf;
|
||||
}
|
||||
|
||||
// a complete block has been found
|
||||
if (block) {
|
||||
if (errorUf2(uf2_check_block(ctx, block)))
|
||||
// block is invalid
|
||||
return 0;
|
||||
|
||||
if (errUf2 == UF2_ERR_IGNORE)
|
||||
// treat ignored blocks as valid
|
||||
return UF2_BLOCK_SIZE;
|
||||
|
||||
if (!bytesWritten) {
|
||||
// parse header block to allow retrieving firmware info
|
||||
if (errorUf2(uf2_parse_header(ctx, block, info)))
|
||||
// header is invalid
|
||||
return 0;
|
||||
|
||||
if (bytesTotal == UPDATE_SIZE_UNKNOWN) {
|
||||
// set total update size from block count info
|
||||
bytesTotal = block->block_count * UF2_BLOCK_SIZE;
|
||||
} else if (bytesTotal != block->block_count * UF2_BLOCK_SIZE) {
|
||||
// given update size does not match the block count
|
||||
return errorArd(UPDATE_ERROR_SIZE);
|
||||
}
|
||||
} else {
|
||||
// write data blocks normally
|
||||
if (errorUf2(uf2_write(ctx, block)))
|
||||
// block writing failed
|
||||
return 0;
|
||||
}
|
||||
|
||||
// increment total writing progress
|
||||
bytesWritten += UF2_BLOCK_SIZE;
|
||||
// call progress callback
|
||||
if (callback)
|
||||
callback(bytesWritten, bytesTotal);
|
||||
return UF2_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
UpdateClass Update;
|
||||
150
arduino/libretuya/libraries/Update/Update.h
Normal file
150
arduino/libretuya/libraries/Update/Update.h
Normal file
@@ -0,0 +1,150 @@
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <functional>
|
||||
|
||||
#include "uf2ota/uf2ota.h"
|
||||
|
||||
// No Error
|
||||
#define UPDATE_ERROR_OK (0)
|
||||
// Flash Write Failed
|
||||
#define UPDATE_ERROR_WRITE (1)
|
||||
// Flash Erase Failed
|
||||
#define UPDATE_ERROR_ERASE (2)
|
||||
// Flash Read Failed
|
||||
#define UPDATE_ERROR_READ (3)
|
||||
// Not Enough Space
|
||||
#define UPDATE_ERROR_SPACE (4)
|
||||
// Bad Size Given
|
||||
#define UPDATE_ERROR_SIZE (5)
|
||||
// Stream Read Timeout
|
||||
#define UPDATE_ERROR_STREAM (6)
|
||||
// MD5 Check Failed
|
||||
#define UPDATE_ERROR_MD5 (7)
|
||||
// Wrong Magic Byte
|
||||
#define UPDATE_ERROR_MAGIC_BYTE (8)
|
||||
// Could Not Activate The Firmware
|
||||
#define UPDATE_ERROR_ACTIVATE (9)
|
||||
// Partition Could Not be Found
|
||||
#define UPDATE_ERROR_NO_PARTITION (10)
|
||||
// Bad Argument
|
||||
#define UPDATE_ERROR_BAD_ARGUMENT (11)
|
||||
// Aborted
|
||||
#define UPDATE_ERROR_ABORT (12)
|
||||
|
||||
#define UPDATE_SIZE_UNKNOWN 0xFFFFFFFF
|
||||
|
||||
#define U_FLASH 0
|
||||
#define U_SPIFFS 100
|
||||
#define U_AUTH 200
|
||||
|
||||
#define ENCRYPTED_BLOCK_SIZE 16
|
||||
|
||||
#define UPDATE_TIMEOUT_MS 30 * 1000
|
||||
|
||||
class UpdateClass {
|
||||
public:
|
||||
typedef std::function<void(size_t, size_t)> THandlerFunction_Progress;
|
||||
|
||||
public: /* Update.cpp */
|
||||
UpdateClass();
|
||||
bool begin(
|
||||
size_t size = UPDATE_SIZE_UNKNOWN,
|
||||
int command = U_FLASH,
|
||||
int unused2 = -1,
|
||||
uint8_t unused3 = LOW,
|
||||
const char *unused4 = NULL // this is for SPIFFS
|
||||
);
|
||||
bool end(bool evenIfRemaining = false);
|
||||
size_t write(uint8_t *data, size_t len);
|
||||
size_t writeStream(Stream &data);
|
||||
bool canRollBack();
|
||||
bool rollBack();
|
||||
// bool setMD5(const char *expected_md5);
|
||||
|
||||
private: /* Update.cpp */
|
||||
size_t tryWriteData(uint8_t *data = NULL, size_t len = 0);
|
||||
|
||||
public: /* UpdateUtil.cpp */
|
||||
UpdateClass &onProgress(THandlerFunction_Progress callback);
|
||||
void abort();
|
||||
void printError(Print &out);
|
||||
const char *errorString();
|
||||
const char *getFirmwareName();
|
||||
const char *getFirmwareVersion();
|
||||
const char *getLibreTuyaVersion();
|
||||
const char *getBoardName();
|
||||
|
||||
private: /* UpdateUtil.cpp */
|
||||
void cleanup();
|
||||
bool errorUf2(uf2_err_t err);
|
||||
bool errorArd(uint8_t err);
|
||||
void bufAlloc();
|
||||
uint16_t bufLeft();
|
||||
uint16_t bufSize();
|
||||
|
||||
private:
|
||||
// uf2ota context
|
||||
uf2_ota_t *ctx;
|
||||
uf2_info_t *info;
|
||||
// block buffer
|
||||
uint8_t *buf;
|
||||
uint8_t *bufPos;
|
||||
// update progress - multiplies of 512 bytes
|
||||
uint32_t bytesWritten;
|
||||
uint32_t bytesTotal;
|
||||
// errors
|
||||
uf2_err_t errUf2;
|
||||
uint8_t errArd;
|
||||
// progress callback
|
||||
THandlerFunction_Progress callback;
|
||||
// String _target_md5;
|
||||
// MD5Builder _md5;
|
||||
|
||||
public:
|
||||
String md5String(void) {
|
||||
// return _md5.toString();
|
||||
}
|
||||
|
||||
void md5(uint8_t *result) {
|
||||
// return _md5.getBytes(result);
|
||||
}
|
||||
|
||||
uint8_t getError() {
|
||||
return errArd;
|
||||
}
|
||||
|
||||
uf2_err_t getUF2Error() {
|
||||
return errUf2;
|
||||
}
|
||||
|
||||
void clearError() {
|
||||
errorUf2(UF2_ERR_OK);
|
||||
}
|
||||
|
||||
bool hasError() {
|
||||
return errArd != UPDATE_ERROR_OK;
|
||||
}
|
||||
|
||||
bool isRunning() {
|
||||
return ctx != NULL;
|
||||
}
|
||||
|
||||
bool isFinished() {
|
||||
return bytesWritten == bytesTotal;
|
||||
}
|
||||
|
||||
size_t size() {
|
||||
return bytesTotal;
|
||||
}
|
||||
|
||||
size_t progress() {
|
||||
return bytesWritten;
|
||||
}
|
||||
|
||||
size_t remaining() {
|
||||
return bytesTotal - bytesWritten;
|
||||
}
|
||||
};
|
||||
|
||||
extern UpdateClass Update;
|
||||
162
arduino/libretuya/libraries/Update/UpdateUtil.cpp
Normal file
162
arduino/libretuya/libraries/Update/UpdateUtil.cpp
Normal file
@@ -0,0 +1,162 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-30. */
|
||||
|
||||
#include "Update.h"
|
||||
|
||||
static const uint8_t errorMap[] = {
|
||||
UPDATE_ERROR_OK, /* UF2_ERR_OK - no error */
|
||||
UPDATE_ERROR_OK, /* UF2_ERR_IGNORE - block should be ignored */
|
||||
UPDATE_ERROR_MAGIC_BYTE, /* UF2_ERR_MAGIC - wrong magic numbers */
|
||||
UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_FAMILY - family ID mismatched */
|
||||
UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_NOT_HEADER - block is not a header */
|
||||
UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_OTA_VER - unknown/invalid OTA format version */
|
||||
UPDATE_ERROR_MAGIC_BYTE, /* UF2_ERR_OTA_WRONG - no data for current OTA index */
|
||||
UPDATE_ERROR_NO_PARTITION, /* UF2_ERR_PART_404 - no partition with that name */
|
||||
UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_PART_ONE - only one partition tag in a block */
|
||||
UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_PART_UNSET - attempted to write without target partition */
|
||||
UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_DATA_TOO_LONG - data too long - tags won't fit */
|
||||
UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_SEQ_MISMATCH - sequence number mismatched */
|
||||
UPDATE_ERROR_ERASE, /* UF2_ERR_ERASE_FAILED - erasing flash failed */
|
||||
UPDATE_ERROR_WRITE, /* UF2_ERR_WRITE_FAILED - writing to flash failed */
|
||||
UPDATE_ERROR_WRITE /* UF2_ERR_WRITE_LENGTH - wrote fewer data than requested */
|
||||
};
|
||||
|
||||
static char errorStr[14];
|
||||
|
||||
/**
|
||||
* @brief Set the callback invoked after writing data to flash.
|
||||
*/
|
||||
UpdateClass &UpdateClass::onProgress(THandlerFunction_Progress callback) {
|
||||
this->callback = callback;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void UpdateClass::cleanup() {
|
||||
free(ctx); // NULL in constructor
|
||||
ctx = NULL;
|
||||
uf2_info_free(info); // NULL in constructor
|
||||
info = NULL;
|
||||
free(buf); // NULL in constructor
|
||||
buf = bufPos = NULL;
|
||||
|
||||
bytesWritten = 0;
|
||||
bytesTotal = 0;
|
||||
errUf2 = UF2_ERR_OK;
|
||||
errArd = UPDATE_ERROR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check for UF2 errors. Set errArd and errUf2 in case of errors.
|
||||
* Ignored blocks are not reported as errors.
|
||||
* Abort the update.
|
||||
* Use like: "if (errorUf2(...)) return false;"
|
||||
* @return true if err is not OK, false otherwise
|
||||
*/
|
||||
bool UpdateClass::errorUf2(uf2_err_t err) {
|
||||
if (err <= UF2_ERR_IGNORE)
|
||||
return false;
|
||||
cleanup();
|
||||
errUf2 = err;
|
||||
errArd = errorMap[err];
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set errUf2 and errArd according to given Arduino error code.
|
||||
* Abort the update.
|
||||
* Use like: "return errorArd(...);"
|
||||
* @return false - always
|
||||
*/
|
||||
bool UpdateClass::errorArd(uint8_t err) {
|
||||
cleanup();
|
||||
errUf2 = UF2_ERR_OK;
|
||||
errArd = err;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Abort the update with UPDATE_ERROR_ABORT reason.
|
||||
*/
|
||||
void UpdateClass::abort() {
|
||||
errorArd(UPDATE_ERROR_ABORT);
|
||||
}
|
||||
|
||||
void UpdateClass::bufAlloc() {
|
||||
if (!buf)
|
||||
buf = bufPos = (uint8_t *)malloc(UF2_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
uint16_t UpdateClass::bufLeft() {
|
||||
return buf + UF2_BLOCK_SIZE - bufPos;
|
||||
}
|
||||
|
||||
uint16_t UpdateClass::bufSize() {
|
||||
return bufPos - buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Print string error info to the stream.
|
||||
*/
|
||||
void UpdateClass::printError(Print &out) {
|
||||
out.println(errorString());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get string representation of the error in format
|
||||
* "ard=..,uf2=..". Returns "" if no error.
|
||||
*/
|
||||
const char *UpdateClass::errorString() {
|
||||
if (!errArd)
|
||||
return "";
|
||||
sprintf(errorStr, "ard=%u,uf2=%u", errArd, errUf2);
|
||||
return errorStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get firmware name from UF2 info.
|
||||
*/
|
||||
const char *UpdateClass::getFirmwareName() {
|
||||
if (info)
|
||||
return info->fw_name;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get firmware version from UF2 info.
|
||||
*/
|
||||
const char *UpdateClass::getFirmwareVersion() {
|
||||
if (info)
|
||||
return info->fw_version;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get LibreTuya version from UF2 info.
|
||||
*/
|
||||
const char *UpdateClass::getLibreTuyaVersion() {
|
||||
if (info)
|
||||
return info->lt_version;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get target board name from UF2 info.
|
||||
*/
|
||||
const char *UpdateClass::getBoardName() {
|
||||
if (info)
|
||||
return info->board;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief See LT.otaCanRollback() for more info.
|
||||
*/
|
||||
bool UpdateClass::canRollBack() {
|
||||
return LT.otaCanRollback();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief See LT.otaRollback() for more info.
|
||||
*/
|
||||
bool UpdateClass::rollBack() {
|
||||
return LT.otaRollback();
|
||||
}
|
||||
32
arduino/libretuya/libraries/Update/uf2ota/uf2binpatch.c
Normal file
32
arduino/libretuya/libraries/Update/uf2ota/uf2binpatch.c
Normal file
@@ -0,0 +1,32 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-29. */
|
||||
|
||||
#include "uf2priv.h"
|
||||
|
||||
uf2_err_t uf2_binpatch(uint8_t *data, const uint8_t *binpatch, uint8_t binpatch_len) {
|
||||
const uint8_t *binpatch_end = binpatch + binpatch_len;
|
||||
// +2 to make sure opcode and length is present
|
||||
while ((binpatch + 2) < binpatch_end) {
|
||||
uf2_opcode_t opcode = binpatch[0];
|
||||
uint8_t len = binpatch[1];
|
||||
switch (opcode) {
|
||||
case UF2_OPC_DIFF32:
|
||||
uf2_binpatch_diff32(data, binpatch + 1);
|
||||
break;
|
||||
}
|
||||
// advance by opcode + length + data
|
||||
binpatch += len + 2;
|
||||
}
|
||||
return UF2_ERR_OK;
|
||||
}
|
||||
|
||||
void uf2_binpatch_diff32(uint8_t *data, const uint8_t *patch) {
|
||||
uint8_t num_offs = patch[0] - 4; // read offset count
|
||||
uint32_t diff = *((uint32_t *)(patch + 1)); // read diff value
|
||||
patch += 5; // skip num_offs and diff value
|
||||
for (uint8_t i = 0; i < num_offs; i++) {
|
||||
// patch the data
|
||||
uint8_t offs = patch[i];
|
||||
uint32_t *value = (uint32_t *)(data + offs);
|
||||
*(value) += diff;
|
||||
}
|
||||
}
|
||||
26
arduino/libretuya/libraries/Update/uf2ota/uf2binpatch.h
Normal file
26
arduino/libretuya/libraries/Update/uf2ota/uf2binpatch.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-29. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "uf2types.h"
|
||||
|
||||
/**
|
||||
* @brief Apply binary patch to data.
|
||||
*
|
||||
* @param data input data
|
||||
* @param data_len input data length
|
||||
* @param binpatch binary patch data
|
||||
* @param binpatch_len binary patch data length
|
||||
* @return uf2_err_t error code
|
||||
*/
|
||||
uf2_err_t uf2_binpatch(uint8_t *data, const uint8_t *binpatch, uint8_t binpatch_len);
|
||||
|
||||
/**
|
||||
* Apply DIFF32 binary patch.
|
||||
*
|
||||
* @param data input data
|
||||
* @param len input data length
|
||||
* @param patch patch data, incl. length byte
|
||||
* @return uf2_err_t error code
|
||||
*/
|
||||
void uf2_binpatch_diff32(uint8_t *data, const uint8_t *patch);
|
||||
100
arduino/libretuya/libraries/Update/uf2ota/uf2ota.c
Normal file
100
arduino/libretuya/libraries/Update/uf2ota/uf2ota.c
Normal file
@@ -0,0 +1,100 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-29. */
|
||||
|
||||
#include "uf2priv.h"
|
||||
|
||||
uf2_ota_t *uf2_ctx_init(uint8_t ota_idx, uint32_t family_id) {
|
||||
uf2_ota_t *ctx = (uf2_ota_t *)zalloc(sizeof(uf2_ota_t));
|
||||
ctx->ota_idx = ota_idx;
|
||||
ctx->family_id = family_id;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
uf2_info_t *uf2_info_init() {
|
||||
uf2_info_t *info = (uf2_info_t *)zalloc(sizeof(uf2_info_t));
|
||||
return info;
|
||||
}
|
||||
|
||||
void uf2_info_free(uf2_info_t *info) {
|
||||
if (!info)
|
||||
return;
|
||||
free(info->fw_name);
|
||||
free(info->fw_version);
|
||||
free(info->lt_version);
|
||||
free(info->board);
|
||||
free(info);
|
||||
}
|
||||
|
||||
uf2_err_t uf2_check_block(uf2_ota_t *ctx, uf2_block_t *block) {
|
||||
if (block->magic1 != UF2_MAGIC_1)
|
||||
return UF2_ERR_MAGIC;
|
||||
if (block->magic2 != UF2_MAGIC_2)
|
||||
return UF2_ERR_MAGIC;
|
||||
if (block->magic3 != UF2_MAGIC_3)
|
||||
return UF2_ERR_MAGIC;
|
||||
if (block->file_container)
|
||||
// ignore file containers, for now
|
||||
return UF2_ERR_IGNORE;
|
||||
if (!block->has_family_id || block->file_size != ctx->family_id)
|
||||
// require family_id
|
||||
return UF2_ERR_FAMILY;
|
||||
return UF2_ERR_OK;
|
||||
}
|
||||
|
||||
uf2_err_t uf2_parse_header(uf2_ota_t *ctx, uf2_block_t *block, uf2_info_t *info) {
|
||||
if (!block->has_tags || block->file_container || block->len)
|
||||
// header must have tags and no data
|
||||
return UF2_ERR_NOT_HEADER;
|
||||
|
||||
uf2_err_t err = uf2_parse_block(ctx, block, info);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if ((ctx->ota_idx == 1 && !ctx->has_ota1) || !ctx->has_ota2)
|
||||
return UF2_ERR_OTA_WRONG;
|
||||
return UF2_ERR_OK;
|
||||
}
|
||||
|
||||
uf2_err_t uf2_write(uf2_ota_t *ctx, uf2_block_t *block) {
|
||||
if (ctx->seq == 0)
|
||||
return uf2_parse_header(ctx, block, NULL);
|
||||
if (block->not_main_flash || !block->len)
|
||||
// ignore blocks not meant for flashing
|
||||
return UF2_ERR_IGNORE;
|
||||
|
||||
uf2_err_t err = uf2_parse_block(ctx, block, NULL);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!ctx->part1 && !ctx->part2)
|
||||
// no partitions set at all
|
||||
return UF2_ERR_PART_UNSET;
|
||||
|
||||
fal_partition_t part = uf2_get_target_part(ctx);
|
||||
if (!part)
|
||||
// image is not for current OTA scheme
|
||||
return UF2_ERR_IGNORE;
|
||||
|
||||
if (ctx->ota_idx == 2 && ctx->binpatch_len) {
|
||||
// apply binpatch
|
||||
err = uf2_binpatch(block->data, ctx->binpatch, ctx->binpatch_len);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
int ret;
|
||||
// erase sectors if needed
|
||||
if (!uf2_is_erased(ctx, block->addr, block->len)) {
|
||||
ret = fal_partition_erase(part, block->addr, block->len);
|
||||
if (ret < 0)
|
||||
return UF2_ERR_ERASE_FAILED;
|
||||
ctx->erased_offset = block->addr;
|
||||
ctx->erased_length = ret;
|
||||
}
|
||||
// write data to flash
|
||||
ret = fal_partition_write(part, block->addr, block->data, block->len);
|
||||
if (ret < 0)
|
||||
return UF2_ERR_WRITE_FAILED;
|
||||
if (ret != block->len)
|
||||
return UF2_ERR_WRITE_LENGTH;
|
||||
return UF2_ERR_OK;
|
||||
}
|
||||
68
arduino/libretuya/libraries/Update/uf2ota/uf2ota.h
Normal file
68
arduino/libretuya/libraries/Update/uf2ota/uf2ota.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-28. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#include "uf2types.h"
|
||||
|
||||
/**
|
||||
* @brief Create an UF2 OTA context.
|
||||
*
|
||||
* @param ota_idx target OTA index
|
||||
* @param family_id expected family ID
|
||||
* @return uf2_ota_t* heap-allocated structure
|
||||
*/
|
||||
uf2_ota_t *uf2_ctx_init(uint8_t ota_idx, uint32_t family_id);
|
||||
|
||||
/**
|
||||
* @brief Create an UF2 Info structure.
|
||||
*
|
||||
* @return uf2_info_t* heap-allocated structure
|
||||
*/
|
||||
uf2_info_t *uf2_info_init();
|
||||
|
||||
/**
|
||||
* @brief Free values in the info structure AND the structure itself.
|
||||
*
|
||||
* @param info structure to free; may be NULL
|
||||
*/
|
||||
void uf2_info_free(uf2_info_t *info);
|
||||
|
||||
/**
|
||||
* @brief Check if block is valid.
|
||||
*
|
||||
* @param ctx context
|
||||
* @param block block to check
|
||||
* @return uf2_err_t error code; UF2_ERR_OK and UF2_ERR_IGNORE denote valid blocks
|
||||
*/
|
||||
uf2_err_t uf2_check_block(uf2_ota_t *ctx, uf2_block_t *block);
|
||||
|
||||
/**
|
||||
* @brief Parse header block (LibreTuya UF2 first block).
|
||||
*
|
||||
* Note: caller should call uf2_check_block() first.
|
||||
*
|
||||
* @param ctx context
|
||||
* @param block block to parse
|
||||
* @param info structure to write firmware info, NULL if not used
|
||||
* @return uf2_err_t error code
|
||||
*/
|
||||
uf2_err_t uf2_parse_header(uf2_ota_t *ctx, uf2_block_t *block, uf2_info_t *info);
|
||||
|
||||
/**
|
||||
* @brief Write the block to flash memory.
|
||||
*
|
||||
* Note: caller should call uf2_check_block() first.
|
||||
*
|
||||
* @param ctx context
|
||||
* @param block block to write
|
||||
* @return uf2_err_t error code
|
||||
*/
|
||||
uf2_err_t uf2_write(uf2_ota_t *ctx, uf2_block_t *block);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
146
arduino/libretuya/libraries/Update/uf2ota/uf2priv.c
Normal file
146
arduino/libretuya/libraries/Update/uf2ota/uf2priv.c
Normal file
@@ -0,0 +1,146 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-29. */
|
||||
|
||||
#include "uf2priv.h"
|
||||
|
||||
uf2_err_t uf2_parse_block(uf2_ota_t *ctx, uf2_block_t *block, uf2_info_t *info) {
|
||||
if (block->block_seq != ctx->seq)
|
||||
// sequence number must match
|
||||
return UF2_ERR_SEQ_MISMATCH;
|
||||
ctx->seq++; // increment sequence number after checking it
|
||||
|
||||
if (!block->has_tags)
|
||||
// no tags in this block, no further processing needed
|
||||
return UF2_ERR_OK;
|
||||
|
||||
if (block->len > (476 - 4 - 4))
|
||||
// at least one tag + last tag must fit
|
||||
return UF2_ERR_DATA_TOO_LONG;
|
||||
|
||||
uint8_t *tags_start = block->data + block->len;
|
||||
uint8_t tags_len = 476 - block->len;
|
||||
uint8_t tags_pos = 0;
|
||||
if (block->has_md5)
|
||||
tags_len -= 24;
|
||||
|
||||
ctx->binpatch_len = 0; // binpatch applies to one block only
|
||||
char *part1 = NULL;
|
||||
char *part2 = NULL;
|
||||
|
||||
uf2_tag_type_t type;
|
||||
while (tags_pos < tags_len) {
|
||||
uint8_t len = uf2_read_tag(tags_start + tags_pos, &type);
|
||||
if (!len)
|
||||
break;
|
||||
tags_pos += 4; // skip tag header
|
||||
uint8_t *tag = tags_start + tags_pos;
|
||||
|
||||
char **str_dest = NULL; // char* to copy the tag into
|
||||
|
||||
switch (type) {
|
||||
case UF2_TAG_OTA_VERSION:
|
||||
if (tag[0] != 1)
|
||||
return UF2_ERR_OTA_VER;
|
||||
break;
|
||||
case UF2_TAG_FIRMWARE:
|
||||
if (info)
|
||||
str_dest = &(info->fw_name);
|
||||
break;
|
||||
case UF2_TAG_VERSION:
|
||||
if (info)
|
||||
str_dest = &(info->fw_version);
|
||||
break;
|
||||
case UF2_TAG_LT_VERSION:
|
||||
if (info)
|
||||
str_dest = &(info->lt_version);
|
||||
break;
|
||||
case UF2_TAG_BOARD:
|
||||
if (info)
|
||||
str_dest = &(info->board);
|
||||
break;
|
||||
case UF2_TAG_HAS_OTA1:
|
||||
ctx->has_ota1 = tag[0];
|
||||
break;
|
||||
case UF2_TAG_HAS_OTA2:
|
||||
ctx->has_ota2 = tag[0];
|
||||
break;
|
||||
case UF2_TAG_PART_1:
|
||||
str_dest = &(part1);
|
||||
break;
|
||||
case UF2_TAG_PART_2:
|
||||
str_dest = &(part2);
|
||||
break;
|
||||
case UF2_TAG_BINPATCH:
|
||||
ctx->binpatch = tag;
|
||||
ctx->binpatch_len = len;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (str_dest) {
|
||||
*str_dest = (char *)zalloc(len + 1);
|
||||
memcpy(*str_dest, tag, len);
|
||||
}
|
||||
// align position to 4 bytes
|
||||
tags_pos += (((len - 1) / 4) + 1) * 4;
|
||||
}
|
||||
|
||||
if (part1 && part2) {
|
||||
// update current target partition
|
||||
uf2_err_t err = uf2_update_parts(ctx, part1, part2);
|
||||
if (err)
|
||||
return err;
|
||||
} else if (part1 || part2) {
|
||||
// only none or both partitions can be specified
|
||||
return UF2_ERR_PART_ONE;
|
||||
}
|
||||
|
||||
return UF2_ERR_OK;
|
||||
}
|
||||
|
||||
uint8_t uf2_read_tag(const uint8_t *data, uf2_tag_type_t *type) {
|
||||
uint8_t len = data[0];
|
||||
if (!len)
|
||||
return 0;
|
||||
uint32_t tag_type = *((uint32_t *)data);
|
||||
if (!tag_type)
|
||||
return 0;
|
||||
*type = tag_type >> 8; // remove tag length byte
|
||||
return len - 4;
|
||||
}
|
||||
|
||||
uf2_err_t uf2_update_parts(uf2_ota_t *ctx, char *part1, char *part2) {
|
||||
// reset both target partitions
|
||||
ctx->part1 = NULL;
|
||||
ctx->part2 = NULL;
|
||||
// reset offsets as they probably don't apply to this partition
|
||||
ctx->erased_offset = 0;
|
||||
ctx->erased_length = 0;
|
||||
|
||||
if (part1[0]) {
|
||||
ctx->part1 = fal_partition_find(part1);
|
||||
if (!ctx->part1)
|
||||
return UF2_ERR_PART_404;
|
||||
}
|
||||
if (part2[0]) {
|
||||
ctx->part2 = fal_partition_find(part2);
|
||||
if (!ctx->part2)
|
||||
return UF2_ERR_PART_404;
|
||||
}
|
||||
|
||||
return UF2_ERR_OK;
|
||||
}
|
||||
|
||||
fal_partition_t uf2_get_target_part(uf2_ota_t *ctx) {
|
||||
if (ctx->ota_idx == 1)
|
||||
return ctx->part1;
|
||||
if (ctx->ota_idx == 2)
|
||||
return ctx->part2;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool uf2_is_erased(uf2_ota_t *ctx, uint32_t offset, uint32_t length) {
|
||||
uint32_t erased_end = ctx->erased_offset + ctx->erased_length;
|
||||
uint32_t end = offset + length;
|
||||
return (offset >= ctx->erased_offset) && (end <= erased_end);
|
||||
}
|
||||
61
arduino/libretuya/libraries/Update/uf2ota/uf2priv.h
Normal file
61
arduino/libretuya/libraries/Update/uf2ota/uf2priv.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-28. */
|
||||
|
||||
#pragma once
|
||||
|
||||
// include family stdlib APIs
|
||||
#include <WVariant.h>
|
||||
|
||||
#include "uf2binpatch.h"
|
||||
#include "uf2types.h"
|
||||
|
||||
/**
|
||||
* @brief Parse a block and extract information from tags.
|
||||
*
|
||||
* @param ctx context
|
||||
* @param block block to parse
|
||||
* @param info structure to write firmware info, NULL if not used
|
||||
* @return uf2_err_t error code
|
||||
*/
|
||||
uf2_err_t uf2_parse_block(uf2_ota_t *ctx, uf2_block_t *block, uf2_info_t *info);
|
||||
|
||||
/**
|
||||
* @brief Parse a tag.
|
||||
*
|
||||
* @param data pointer to tag header beginning
|
||||
* @param type [out] parsed tag type
|
||||
* @return uint8_t parsed tag data length (excl. header); 0 if invalid/last tag
|
||||
*/
|
||||
uint8_t uf2_read_tag(const uint8_t *data, uf2_tag_type_t *type);
|
||||
|
||||
/**
|
||||
* @brief Update destination partitions in context.
|
||||
*
|
||||
* Partition names cannot be NULL.
|
||||
*
|
||||
* Returns UF2_ERR_IGNORE if specified partitions don't match the
|
||||
* current OTA index.
|
||||
*
|
||||
* @param ctx context
|
||||
* @param part1 partition 1 name or empty string
|
||||
* @param part2 partition 2 name or empty string
|
||||
* @return uf2_err_t error code
|
||||
*/
|
||||
uf2_err_t uf2_update_parts(uf2_ota_t *ctx, char *part1, char *part2);
|
||||
|
||||
/**
|
||||
* @brief Get target flashing partition, depending on OTA index.
|
||||
*
|
||||
* @param ctx context
|
||||
* @return fal_partition_t target partition or NULL if not set
|
||||
*/
|
||||
fal_partition_t uf2_get_target_part(uf2_ota_t *ctx);
|
||||
|
||||
/**
|
||||
* Check if specified flash memory region was already erased during update.
|
||||
*
|
||||
* @param ctx context
|
||||
* @param offset offset to check
|
||||
* @param length length to check
|
||||
* @return bool true/false
|
||||
*/
|
||||
bool uf2_is_erased(uf2_ota_t *ctx, uint32_t offset, uint32_t length);
|
||||
104
arduino/libretuya/libraries/Update/uf2ota/uf2types.h
Normal file
104
arduino/libretuya/libraries/Update/uf2ota/uf2types.h
Normal file
@@ -0,0 +1,104 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-28. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <fal.h>
|
||||
|
||||
#define UF2_MAGIC_1 0x0A324655
|
||||
#define UF2_MAGIC_2 0x9E5D5157
|
||||
#define UF2_MAGIC_3 0x0AB16F30
|
||||
|
||||
#define UF2_BLOCK_SIZE sizeof(uf2_block_t)
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
// 32 byte header
|
||||
uint32_t magic1;
|
||||
uint32_t magic2;
|
||||
|
||||
// flags split as bitfields
|
||||
bool not_main_flash : 1;
|
||||
uint16_t dummy1 : 11;
|
||||
bool file_container : 1;
|
||||
bool has_family_id : 1;
|
||||
bool has_md5 : 1;
|
||||
bool has_tags : 1;
|
||||
uint16_t dummy2 : 16;
|
||||
|
||||
uint32_t addr;
|
||||
uint32_t len;
|
||||
uint32_t block_seq;
|
||||
uint32_t block_count;
|
||||
uint32_t file_size; // or familyID;
|
||||
uint8_t data[476];
|
||||
uint32_t magic3;
|
||||
} uf2_block_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t seq; // current block sequence number
|
||||
|
||||
uint8_t *binpatch; // current block's binpatch (if any) -> pointer inside block->data
|
||||
uint8_t binpatch_len; // binpatch length
|
||||
|
||||
bool has_ota1; // image has any data for OTA1
|
||||
bool has_ota2; // image has any data for OTA2
|
||||
|
||||
uint8_t ota_idx; // target OTA index
|
||||
uint32_t family_id; // expected family ID
|
||||
|
||||
uint32_t erased_offset; // offset of region erased during update
|
||||
uint32_t erased_length; // length of erased region
|
||||
|
||||
fal_partition_t part1; // OTA1 target partition
|
||||
fal_partition_t part2; // OTA2 target partition
|
||||
} uf2_ota_t;
|
||||
|
||||
typedef struct {
|
||||
char *fw_name;
|
||||
char *fw_version;
|
||||
char *lt_version;
|
||||
char *board;
|
||||
} uf2_info_t;
|
||||
|
||||
typedef enum {
|
||||
UF2_TAG_VERSION = 0x9FC7BC, // version of firmware file - UTF8 semver string
|
||||
UF2_TAG_PAGE_SIZE = 0x0BE9F7, // page size of target device (32 bit unsigned number)
|
||||
UF2_TAG_SHA2 = 0xB46DB0, // SHA-2 checksum of firmware (can be of various size)
|
||||
UF2_TAG_DEVICE = 0x650D9D, // description of device (UTF8)
|
||||
UF2_TAG_DEVICE_ID = 0xC8A729, // device type identifier
|
||||
// LibreTuya custom, tags
|
||||
UF2_TAG_OTA_VERSION = 0x5D57D0, // format version
|
||||
UF2_TAG_BOARD = 0xCA25C8, // board name (lowercase code)
|
||||
UF2_TAG_FIRMWARE = 0x00DE43, // firmware description / name
|
||||
UF2_TAG_BUILD_DATE = 0x822F30, // build date/time as Unix timestamp
|
||||
UF2_TAG_LT_VERSION = 0x59563D, // LT version (semver)
|
||||
UF2_TAG_PART_1 = 0x805946, // OTA1 partition name
|
||||
UF2_TAG_PART_2 = 0xA1E4D7, // OTA2 partition name
|
||||
UF2_TAG_HAS_OTA1 = 0xBBD965, // image has any data for OTA1
|
||||
UF2_TAG_HAS_OTA2 = 0x92280E, // image has any data for OTA2
|
||||
UF2_TAG_BINPATCH = 0xB948DE, // binary patch to convert OTA1->OTA2
|
||||
} uf2_tag_type_t;
|
||||
|
||||
typedef enum {
|
||||
UF2_OPC_DIFF32 = 0xFE,
|
||||
} uf2_opcode_t;
|
||||
|
||||
typedef enum {
|
||||
UF2_ERR_OK = 0,
|
||||
UF2_ERR_IGNORE, // block should be ignored
|
||||
UF2_ERR_MAGIC, // wrong magic numbers
|
||||
UF2_ERR_FAMILY, // family ID mismatched
|
||||
UF2_ERR_NOT_HEADER, // block is not a header
|
||||
UF2_ERR_OTA_VER, // unknown/invalid OTA format version
|
||||
UF2_ERR_OTA_WRONG, // no data for current OTA index
|
||||
UF2_ERR_PART_404, // no partition with that name
|
||||
UF2_ERR_PART_ONE, // only one partition tag in a block
|
||||
UF2_ERR_PART_UNSET, // image broken - attempted to write without target partition
|
||||
UF2_ERR_DATA_TOO_LONG, // data too long - tags won't fit
|
||||
UF2_ERR_SEQ_MISMATCH, // sequence number mismatched
|
||||
UF2_ERR_ERASE_FAILED, // erasing flash failed
|
||||
UF2_ERR_WRITE_FAILED, // writing to flash failed
|
||||
UF2_ERR_WRITE_LENGTH, // wrote fewer data than requested
|
||||
} uf2_err_t;
|
||||
2
arduino/libretuya/libraries/base64/.clang-format
Normal file
2
arduino/libretuya/libraries/base64/.clang-format
Normal file
@@ -0,0 +1,2 @@
|
||||
DisableFormat: true
|
||||
SortIncludes: Never
|
||||
5
arduino/libretuya/libraries/mDNS/ESPmDNS.h
Normal file
5
arduino/libretuya/libraries/mDNS/ESPmDNS.h
Normal file
@@ -0,0 +1,5 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-23. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "mDNS.h"
|
||||
153
arduino/libretuya/libraries/mDNS/LwIPmDNS.cpp
Normal file
153
arduino/libretuya/libraries/mDNS/LwIPmDNS.cpp
Normal file
@@ -0,0 +1,153 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-23. */
|
||||
|
||||
#ifdef LT_HAS_LWIP2
|
||||
|
||||
#include "mDNS.h"
|
||||
|
||||
extern "C" {
|
||||
#include <lwip/apps/mdns.h>
|
||||
#include <lwip/netif.h>
|
||||
}
|
||||
|
||||
static u8_t mdns_netif_client_id = 0; // TODO fix this
|
||||
|
||||
struct mdns_domain {
|
||||
/* Encoded domain name */
|
||||
u8_t name[256];
|
||||
/* Total length of domain name, including zero */
|
||||
u16_t length;
|
||||
/* Set if compression of this domain is not allowed */
|
||||
u8_t skip_compression;
|
||||
};
|
||||
|
||||
/** Description of a service */
|
||||
struct mdns_service {
|
||||
/** TXT record to answer with */
|
||||
struct mdns_domain txtdata;
|
||||
/** Name of service, like 'myweb' */
|
||||
char name[MDNS_LABEL_MAXLEN + 1];
|
||||
/** Type of service, like '_http' */
|
||||
char service[MDNS_LABEL_MAXLEN + 1];
|
||||
/** Callback function and userdata
|
||||
* to update txtdata buffer */
|
||||
service_get_txt_fn_t txt_fn;
|
||||
void *txt_userdata;
|
||||
/** TTL in seconds of SRV/TXT replies */
|
||||
u32_t dns_ttl;
|
||||
/** Protocol, TCP or UDP */
|
||||
u16_t proto;
|
||||
/** Port of the service */
|
||||
u16_t port;
|
||||
};
|
||||
|
||||
/** Description of a host/netif */
|
||||
struct mdns_host {
|
||||
/** Hostname */
|
||||
char name[MDNS_LABEL_MAXLEN + 1];
|
||||
/** Pointer to services */
|
||||
struct mdns_service *services[MDNS_MAX_SERVICES];
|
||||
/** TTL in seconds of A/AAAA/PTR replies */
|
||||
u32_t dns_ttl;
|
||||
};
|
||||
|
||||
static String mdnsInstanceName = "default_instance";
|
||||
|
||||
mDNS::mDNS() {}
|
||||
|
||||
mDNS::~mDNS() {}
|
||||
|
||||
bool mDNS::begin(const char *hostname) {
|
||||
mdns_resp_init();
|
||||
struct netif *netif = netif_list;
|
||||
while (netif != NULL) {
|
||||
// TODO: detect mdns_netif_client_id by checking netif_get_client_data()
|
||||
// and finding the requested hostname in struct mdns_host
|
||||
if (netif_is_up(netif) && mdns_resp_add_netif(netif, hostname, 255) != ERR_OK) {
|
||||
return false;
|
||||
}
|
||||
netif = netif->next;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void mDNS::end() {
|
||||
struct netif *netif = netif_list;
|
||||
while (netif != NULL) {
|
||||
if (netif_is_up(netif))
|
||||
mdns_resp_remove_netif(netif);
|
||||
netif = netif->next;
|
||||
}
|
||||
}
|
||||
|
||||
void mDNS::setInstanceName(String name) {
|
||||
mdnsInstanceName = name;
|
||||
}
|
||||
|
||||
bool mDNS::addService(char *service, char *proto, uint16_t port) {
|
||||
char _service[strlen(service) + 2];
|
||||
char _proto[strlen(proto) + 2];
|
||||
_service[0] = '_';
|
||||
_proto[0] = '_';
|
||||
// prepend names with _
|
||||
strcpy(_service + 1, service + (service[0] == '_'));
|
||||
strcpy(_proto + 1, proto + (proto[0] == '_'));
|
||||
|
||||
mdns_sd_proto protocol = DNSSD_PROTO_UDP;
|
||||
if (strncmp(_proto + 1, "tcp", 3) == 0)
|
||||
protocol = DNSSD_PROTO_TCP;
|
||||
|
||||
struct netif *netif = netif_list;
|
||||
while (netif != NULL) {
|
||||
if (netif_is_up(netif)) {
|
||||
mdns_resp_add_service(netif, mdnsInstanceName.c_str(), service, protocol, port, 255, NULL, NULL);
|
||||
}
|
||||
netif = netif->next;
|
||||
}
|
||||
}
|
||||
|
||||
bool mDNS::addServiceTxt(char *name, char *proto, char *key, char *value) {
|
||||
char _name[strlen(name) + 2];
|
||||
char _proto[strlen(proto) + 2];
|
||||
_name[0] = '_';
|
||||
_proto[0] = '_';
|
||||
// prepend names with _
|
||||
strcpy(_name + 1, name + (name[0] == '_'));
|
||||
strcpy(_proto + 1, proto + (proto[0] == '_'));
|
||||
|
||||
mdns_sd_proto protocol = DNSSD_PROTO_UDP;
|
||||
if (strncmp(_proto + 1, "tcp", 3) == 0)
|
||||
protocol = DNSSD_PROTO_TCP;
|
||||
|
||||
struct netif *netif = netif_list;
|
||||
struct mdns_host *mdns;
|
||||
struct mdns_service *service;
|
||||
|
||||
uint8_t txt_len = strlen(key) + strlen(value) + 1;
|
||||
char *txt = (char *)malloc(txt_len + 1);
|
||||
sprintf(txt, "%s=%s", key, value);
|
||||
|
||||
while (netif != NULL) {
|
||||
if (netif_is_up(netif)) {
|
||||
mdns = (struct mdns_host *)netif_get_client_data(netif, mdns_netif_client_id);
|
||||
|
||||
for (uint8_t i = 0; i < MDNS_MAX_SERVICES; i++) {
|
||||
service = mdns->services[i];
|
||||
if (service == NULL)
|
||||
continue;
|
||||
if (strcmp(service->service, _name) || service->proto != protocol)
|
||||
continue;
|
||||
if (mdns_resp_add_service_txtitem(service, txt, txt_len) != ERR_OK) {
|
||||
free(txt);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
netif = netif->next;
|
||||
}
|
||||
free(txt);
|
||||
return true;
|
||||
}
|
||||
|
||||
MDNSResponder MDNS;
|
||||
|
||||
#endif
|
||||
119
arduino/libretuya/libraries/mDNS/mDNS.h
Normal file
119
arduino/libretuya/libraries/mDNS/mDNS.h
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
ESP8266 Multicast DNS (port of CC3000 Multicast DNS library)
|
||||
Version 1.1
|
||||
Copyright (c) 2013 Tony DiCola (tony@tonydicola.com)
|
||||
ESP8266 port (c) 2015 Ivan Grokhotkov (ivan@esp8266.com)
|
||||
MDNS-SD Suport 2015 Hristo Gochkov (hristo@espressif.com)
|
||||
Extended MDNS-SD support 2016 Lars Englund (lars.englund@gmail.com)
|
||||
Rewritten for ESP32 by Hristo Gochkov (hristo@espressif.com)
|
||||
|
||||
This is a simple implementation of multicast DNS query support for an Arduino
|
||||
running on ESP32 chip.
|
||||
|
||||
Usage:
|
||||
- Include the ESP32 Multicast DNS library in the sketch.
|
||||
- Call the begin method in the sketch's setup and provide a domain name (without
|
||||
the '.local' suffix, i.e. just provide 'foo' to resolve 'foo.local'), and the
|
||||
Adafruit CC3000 class instance. Optionally provide a time to live (in seconds)
|
||||
for the DNS record--the default is 1 hour.
|
||||
- Call the update method in each iteration of the sketch's loop function.
|
||||
|
||||
License (MIT license):
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <api/IPv6Address.h>
|
||||
|
||||
class mDNS {
|
||||
public:
|
||||
mDNS();
|
||||
~mDNS();
|
||||
|
||||
bool begin(const char *hostname);
|
||||
void end();
|
||||
|
||||
void setInstanceName(String name);
|
||||
bool addService(char *service, char *proto, uint16_t port);
|
||||
bool addServiceTxt(char *name, char *proto, char *key, char *value);
|
||||
// void enableArduino(uint16_t port = 3232, bool auth = false);
|
||||
// void disableArduino();
|
||||
// void enableWorkstation(esp_interface_t interface = ESP_IF_WIFI_STA);
|
||||
// void disableWorkstation();
|
||||
|
||||
IPAddress queryHost(char *host, uint32_t timeout = 2000);
|
||||
int queryService(char *service, char *proto);
|
||||
|
||||
String hostname(int idx);
|
||||
IPAddress IP(int idx);
|
||||
IPv6Address IPv6(int idx);
|
||||
uint16_t port(int idx);
|
||||
int numTxt(int idx);
|
||||
bool hasTxt(int idx, const char *key);
|
||||
String txt(int idx, const char *key);
|
||||
String txt(int idx, int txtIdx);
|
||||
String txtKey(int idx, int txtIdx);
|
||||
|
||||
void setInstanceName(const char *name) {
|
||||
setInstanceName(String(name));
|
||||
}
|
||||
|
||||
void setInstanceName(char *name) {
|
||||
setInstanceName(String(name));
|
||||
}
|
||||
|
||||
bool addService(const char *service, const char *proto, uint16_t port) {
|
||||
return addService((char *)service, (char *)proto, port);
|
||||
}
|
||||
|
||||
bool addService(String service, String proto, uint16_t port) {
|
||||
return addService(service.c_str(), proto.c_str(), port);
|
||||
}
|
||||
|
||||
void addServiceTxt(const char *name, const char *proto, const char *key, const char *value) {
|
||||
addServiceTxt((char *)name, (char *)proto, (char *)key, (char *)value);
|
||||
}
|
||||
|
||||
void addServiceTxt(String name, String proto, String key, String value) {
|
||||
addServiceTxt(name.c_str(), proto.c_str(), key.c_str(), value.c_str());
|
||||
}
|
||||
|
||||
IPAddress queryHost(const char *host, uint32_t timeout = 2000) {
|
||||
return queryHost((char *)host, timeout);
|
||||
}
|
||||
|
||||
IPAddress queryHost(String host, uint32_t timeout = 2000) {
|
||||
return queryHost(host.c_str(), timeout);
|
||||
}
|
||||
|
||||
int queryService(const char *service, const char *proto) {
|
||||
return queryService((char *)service, (char *)proto);
|
||||
}
|
||||
|
||||
int queryService(String service, String proto) {
|
||||
return queryService(service.c_str(), proto.c_str());
|
||||
}
|
||||
};
|
||||
|
||||
typedef mDNS MDNSResponder;
|
||||
|
||||
extern MDNSResponder MDNS;
|
||||
25
arduino/libretuya/port/flashdb/fal_cfg.h
Normal file
25
arduino/libretuya/port/flashdb/fal_cfg.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-24. */
|
||||
|
||||
#pragma once
|
||||
|
||||
// Flash device configuration
|
||||
extern const struct fal_flash_dev flash0;
|
||||
|
||||
#define FAL_FLASH_DEV_NAME "flash0"
|
||||
|
||||
#define FAL_FLASH_DEV_TABLE \
|
||||
{ &flash0, }
|
||||
|
||||
#define FAL_DEV_NAME_MAX 16 // no need for 24 chars (default)
|
||||
|
||||
// Partition table
|
||||
#define FAL_PART_HAS_TABLE_CFG
|
||||
|
||||
#define FAL_PART_TABLE_ITEM(part_lower, part_upper) \
|
||||
{ \
|
||||
.magic_word = FAL_PART_MAGIC_WORD, /* magic word */ \
|
||||
.name = #part_lower, /* lowercase name as string */ \
|
||||
.flash_name = FAL_FLASH_DEV_NAME, /* flash device name */ \
|
||||
.offset = FLASH_##part_upper##_OFFSET, /* partition offset macro as uppercase string */ \
|
||||
.len = FLASH_##part_upper##_LENGTH, /* partition length macro as uppercase string */ \
|
||||
},
|
||||
45
arduino/libretuya/port/flashdb/fdb_cfg.h
Normal file
45
arduino/libretuya/port/flashdb/fdb_cfg.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Armink, <armink.ztl@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _FDB_CFG_H_
|
||||
#define _FDB_CFG_H_
|
||||
|
||||
/* using KVDB feature */
|
||||
#define FDB_USING_KVDB
|
||||
|
||||
#ifdef FDB_USING_KVDB
|
||||
/* Auto update KV to latest default when current KVDB version number is changed. @see fdb_kvdb.ver_num */
|
||||
// #define FDB_KV_AUTO_UPDATE
|
||||
#endif
|
||||
|
||||
/* using TSDB (Time series database) feature */
|
||||
// #define FDB_USING_TSDB
|
||||
|
||||
/* Using FAL storage mode */
|
||||
#define FDB_USING_FAL_MODE
|
||||
|
||||
#ifdef FDB_USING_FAL_MODE
|
||||
/* the flash write granularity, unit: bit
|
||||
* only support 1(nor flash)/ 8(stm32f2/f4)/ 32(stm32f1) */
|
||||
#define FDB_WRITE_GRAN 8
|
||||
#endif
|
||||
|
||||
/* Using file storage mode by LIBC file API, like fopen/fread/fwrte/fclose */
|
||||
// #define FDB_USING_FILE_LIBC_MODE
|
||||
|
||||
/* Using file storage mode by POSIX file API, like open/read/write/close */
|
||||
// #define FDB_USING_FILE_POSIX_MODE
|
||||
|
||||
/* MCU Endian Configuration, default is Little Endian Order. */
|
||||
// #define FDB_BIG_ENDIAN
|
||||
|
||||
/* log print macro. default EF_PRINT macro is printf() */
|
||||
#define FDB_PRINT(...)
|
||||
|
||||
/* print debug information */
|
||||
// #define FDB_DEBUG_ENABLE
|
||||
|
||||
#endif /* _FDB_CFG_H_ */
|
||||
2
arduino/libretuya/posix/.clang-format
Normal file
2
arduino/libretuya/posix/.clang-format
Normal file
@@ -0,0 +1,2 @@
|
||||
DisableFormat: true
|
||||
SortIncludes: Never
|
||||
5
arduino/libretuya/posix/lt_posix_api.h
Normal file
5
arduino/libretuya/posix/lt_posix_api.h
Normal file
@@ -0,0 +1,5 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-16. */
|
||||
|
||||
extern char *strdup(const char *);
|
||||
extern int strcasecmp(const char *s1, const char *s2);
|
||||
extern int strncasecmp(const char *s1, const char *s2, size_t n);
|
||||
97
arduino/libretuya/posix/strcasecmp.c
Normal file
97
arduino/libretuya/posix/strcasecmp.c
Normal file
@@ -0,0 +1,97 @@
|
||||
/* $OpenBSD: strcasecmp.c,v 1.6 2005/08/08 08:05:37 espie Exp $ */
|
||||
/*
|
||||
* Copyright (c) 1987, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
#include <string.h>
|
||||
typedef unsigned char u_char;
|
||||
/*
|
||||
* This array is designed for mapping upper and lower case letter
|
||||
* together for a case independent comparison. The mappings are
|
||||
* based upon ascii character sequences.
|
||||
*/
|
||||
static const u_char charmap[] = {
|
||||
'\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
|
||||
'\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
|
||||
'\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
|
||||
'\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
|
||||
'\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
|
||||
'\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
|
||||
'\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
|
||||
'\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
|
||||
'\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
|
||||
'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
|
||||
'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
|
||||
'\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
|
||||
'\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
|
||||
'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
|
||||
'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
|
||||
'\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
|
||||
'\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
|
||||
'\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
|
||||
'\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
|
||||
'\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
|
||||
'\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
|
||||
'\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
|
||||
'\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
|
||||
'\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
|
||||
'\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307',
|
||||
'\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317',
|
||||
'\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327',
|
||||
'\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337',
|
||||
'\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
|
||||
'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
|
||||
'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
|
||||
'\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
|
||||
};
|
||||
int
|
||||
strcasecmp(const char *s1, const char *s2)
|
||||
{
|
||||
const u_char *cm = charmap;
|
||||
const u_char *us1 = (const u_char *)s1;
|
||||
const u_char *us2 = (const u_char *)s2;
|
||||
while (cm[*us1] == cm[*us2++])
|
||||
if (*us1++ == '\0')
|
||||
return (0);
|
||||
return (cm[*us1] - cm[*--us2]);
|
||||
}
|
||||
int
|
||||
strncasecmp(const char *s1, const char *s2, size_t n)
|
||||
{
|
||||
if (n != 0) {
|
||||
const u_char *cm = charmap;
|
||||
const u_char *us1 = (const u_char *)s1;
|
||||
const u_char *us2 = (const u_char *)s2;
|
||||
do {
|
||||
if (cm[*us1] != cm[*us2++])
|
||||
return (cm[*us1] - cm[*--us2]);
|
||||
if (*us1++ == '\0')
|
||||
break;
|
||||
} while (--n != 0);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "LibreTuyaAPI.h"
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-16. */
|
||||
|
||||
__weak char *strdup(const char *s) {
|
||||
#include <stddef.h>
|
||||
|
||||
__attribute__((weak)) char *strdup(const char *s) {
|
||||
size_t len = strlen(s) + 1;
|
||||
void *newp = malloc(len);
|
||||
if (newp == NULL)
|
||||
@@ -1,58 +1,29 @@
|
||||
/*
|
||||
Arduino.h - Main include file for the Arduino SDK
|
||||
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
|
||||
*/
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-04-23. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include "WCharacterFixup.h"
|
||||
#endif
|
||||
|
||||
#define PinMode PinModeArduino // this conflicts with SDK enum
|
||||
#include <api/ArduinoAPI.h>
|
||||
#include <api/LibreTuyaAPI.h>
|
||||
#include <core/LibreTuyaAPI.h>
|
||||
#undef PinMode
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
extern "C" uint32_t SystemCoreClock;
|
||||
#else
|
||||
extern uint32_t SystemCoreClock;
|
||||
|
||||
#define clockCyclesPerMicrosecond() ( SystemCoreClock / 1000000L )
|
||||
#define clockCyclesToMicroseconds(a) ( ((a) * 1000L) / (SystemCoreClock / 1000L) )
|
||||
#define microsecondsToClockCycles(a) ( (a) * (SystemCoreClock / 1000000L) )
|
||||
|
||||
#include "WVariant.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
#define clockCyclesPerMicrosecond() (SystemCoreClock / 1000000L)
|
||||
#define clockCyclesToMicroseconds(a) (((a)*1000L) / (SystemCoreClock / 1000L))
|
||||
#define microsecondsToClockCycles(a) ((a) * (SystemCoreClock / 1000000L))
|
||||
|
||||
// Include board variant
|
||||
#include "variant.h"
|
||||
|
||||
#define interrupts() vPortClearInterruptMask(0)
|
||||
#define interrupts() vPortClearInterruptMask(0)
|
||||
#define noInterrupts() ulPortSetInterruptMask()
|
||||
|
||||
/*
|
||||
* \brief SAM3 products have only one reference for ADC
|
||||
*/
|
||||
typedef enum _eAnalogReference
|
||||
{
|
||||
AR_DEFAULT,
|
||||
} eAnalogReference ;
|
||||
// Include family-specific code
|
||||
#include "WVariant.h"
|
||||
// Include board variant
|
||||
#include "variant.h"
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
#include <api/Print.h>
|
||||
|
||||
class CountingStream : public Print
|
||||
{
|
||||
virtual size_t write(uint8_t) { return 1; };
|
||||
virtual size_t write(const uint8_t *buffer, size_t size) { return size; };
|
||||
};
|
||||
@@ -1,198 +0,0 @@
|
||||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2006-2015 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef MBED_FUNCTIONPOINTER_H
|
||||
#define MBED_FUNCTIONPOINTER_H
|
||||
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
/* If we had variaditic templates, this wouldn't be a problem, but until C++11 is enabled, we are stuck with multiple classes... */
|
||||
|
||||
/** A class for storing and calling a pointer to a static or member function
|
||||
*/
|
||||
template <typename R, typename A1>
|
||||
class FunctionPointerArg1{
|
||||
public:
|
||||
/** Create a FunctionPointer, attaching a static function
|
||||
*
|
||||
* @param function The static function to attach (default is none)
|
||||
*/
|
||||
FunctionPointerArg1(R (*function)(A1) = 0) {
|
||||
attach(function);
|
||||
}
|
||||
|
||||
/** Create a FunctionPointer, attaching a member function
|
||||
*
|
||||
* @param object The object pointer to invoke the member function on (i.e. the this pointer)
|
||||
* @param function The address of the member function to attach
|
||||
*/
|
||||
template<typename T>
|
||||
FunctionPointerArg1(T *object, R (T::*member)(A1)) {
|
||||
attach(object, member);
|
||||
}
|
||||
|
||||
/** Attach a static function
|
||||
*
|
||||
* @param function The static function to attach (default is none)
|
||||
*/
|
||||
void attach(R (*function)(A1)) {
|
||||
_p.function = function;
|
||||
_membercaller = 0;
|
||||
}
|
||||
|
||||
/** Attach a member function
|
||||
*
|
||||
* @param object The object pointer to invoke the member function on (i.e. the this pointer)
|
||||
* @param function The address of the member function to attach
|
||||
*/
|
||||
template<typename T>
|
||||
void attach(T *object, R (T::*member)(A1)) {
|
||||
_p.object = static_cast<void*>(object);
|
||||
*reinterpret_cast<R (T::**)(A1)>(_member) = member;
|
||||
_membercaller = &FunctionPointerArg1::membercaller<T>;
|
||||
}
|
||||
|
||||
/** Call the attached static or member function
|
||||
*/
|
||||
R call(A1 a) {
|
||||
if (_membercaller == 0 && _p.function) {
|
||||
return _p.function(a);
|
||||
} else if (_membercaller && _p.object) {
|
||||
return _membercaller(_p.object, _member, a);
|
||||
}
|
||||
return (R)0;
|
||||
}
|
||||
|
||||
/** Get registered static function
|
||||
*/
|
||||
R(*get_function(A1))() {
|
||||
return _membercaller ? (R(*)(A1))0 : (R(*)(A1))_p.function;
|
||||
}
|
||||
|
||||
R operator ()(A1 a) {
|
||||
return call(a);
|
||||
}
|
||||
operator bool(void) const {
|
||||
return (_membercaller != NULL ? _p.object : (void*)_p.function) != NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
static R membercaller(void *object, uintptr_t *member, A1 a) {
|
||||
T* o = static_cast<T*>(object);
|
||||
R (T::**m)(A1) = reinterpret_cast<R (T::**)(A1)>(member);
|
||||
return (o->**m)(a);
|
||||
}
|
||||
|
||||
union {
|
||||
R (*function)(A1); // static function pointer
|
||||
void *object; // object this pointer
|
||||
} _p;
|
||||
uintptr_t _member[4]; // aligned raw member function pointer storage - converted back by registered _membercaller
|
||||
R (*_membercaller)(void*, uintptr_t*, A1); // registered membercaller function to convert back and call _m.member on _object
|
||||
};
|
||||
|
||||
/** A class for storing and calling a pointer to a static or member function (R ()(void))
|
||||
*/
|
||||
template <typename R>
|
||||
class FunctionPointerArg1<R, void>{
|
||||
public:
|
||||
/** Create a FunctionPointer, attaching a static function
|
||||
*
|
||||
* @param function The static function to attach (default is none)
|
||||
*/
|
||||
FunctionPointerArg1(R (*function)(void) = 0) {
|
||||
attach(function);
|
||||
}
|
||||
|
||||
/** Create a FunctionPointer, attaching a member function
|
||||
*
|
||||
* @param object The object pointer to invoke the member function on (i.e. the this pointer)
|
||||
* @param function The address of the void member function to attach
|
||||
*/
|
||||
template<typename T>
|
||||
FunctionPointerArg1(T *object, R (T::*member)(void)) {
|
||||
attach(object, member);
|
||||
}
|
||||
|
||||
/** Attach a static function
|
||||
*
|
||||
* @param function The void static function to attach (default is none)
|
||||
*/
|
||||
void attach(R (*function)(void)) {
|
||||
_p.function = function;
|
||||
_membercaller = 0;
|
||||
}
|
||||
|
||||
/** Attach a member function
|
||||
*
|
||||
* @param object The object pointer to invoke the member function on (i.e. the this pointer)
|
||||
* @param function The address of the void member function to attach
|
||||
*/
|
||||
template<typename T>
|
||||
void attach(T *object, R (T::*member)(void)) {
|
||||
_p.object = static_cast<void*>(object);
|
||||
*reinterpret_cast<R (T::**)(void)>(_member) = member;
|
||||
_membercaller = &FunctionPointerArg1::membercaller<T>;
|
||||
}
|
||||
|
||||
/** Call the attached static or member function
|
||||
*/
|
||||
R call(){
|
||||
if (_membercaller == 0 && _p.function) {
|
||||
return _p.function();
|
||||
} else if (_membercaller && _p.object) {
|
||||
return _membercaller(_p.object, _member);
|
||||
}
|
||||
return (R)0;
|
||||
}
|
||||
|
||||
/** Get registered static function
|
||||
*/
|
||||
R(*get_function())() {
|
||||
return _membercaller ? (R(*)())0 : (R(*)())_p.function;
|
||||
}
|
||||
|
||||
R operator ()(void) {
|
||||
return call();
|
||||
}
|
||||
operator bool(void) const {
|
||||
return (_membercaller != NULL ? _p.object : (void*)_p.function) != NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
static R membercaller(void *object, uintptr_t *member) {
|
||||
T* o = static_cast<T*>(object);
|
||||
R (T::**m)(void) = reinterpret_cast<R (T::**)(void)>(member);
|
||||
return (o->**m)();
|
||||
}
|
||||
|
||||
union {
|
||||
R (*function)(void); // static function pointer
|
||||
void *object; // object this pointer
|
||||
} _p;
|
||||
uintptr_t _member[4]; // aligned raw member function pointer storage - converted back by registered _membercaller
|
||||
R (*_membercaller)(void*, uintptr_t*); // registered membercaller function to convert back and call _m.member on _object
|
||||
};
|
||||
|
||||
typedef FunctionPointerArg1<void, void> FunctionPointer;
|
||||
typedef FunctionPointerArg1<void, int> event_callback_t;
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -16,117 +16,83 @@
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
#include "LOGUARTClass.h"
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#define LOG_UART_MODIFIABLE_BAUD_RATE 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "osdep_service.h"
|
||||
#include "rtl8710b.h"
|
||||
extern int LOGUART_SetBaud(uint32_t BaudRate); // from fixups/log_uart.c
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
RingBuffer rx_buffer0;
|
||||
|
||||
LOGUARTClass::LOGUARTClass(int dwIrq, RingBuffer* pRx_buffer )
|
||||
{
|
||||
_rx_buffer = pRx_buffer;
|
||||
_dwIrq = dwIrq;
|
||||
LOGUARTClass::LOGUARTClass(int dwIrq, RingBuffer *pRx_buffer) {
|
||||
_rx_buffer = pRx_buffer;
|
||||
_dwIrq = dwIrq;
|
||||
}
|
||||
|
||||
// Protected Methods //////////////////////////////////////////////////////////////
|
||||
void IrqHandler(void) {
|
||||
uint8_t data = 0;
|
||||
BOOL PullMode = _FALSE;
|
||||
uint32_t IrqEn = DiagGetIsrEnReg();
|
||||
|
||||
DiagSetIsrEnReg(0);
|
||||
|
||||
|
||||
|
||||
// Public Methods //////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void IrqHandler( void )
|
||||
{
|
||||
|
||||
uint8_t data = 0;
|
||||
BOOL PullMode = _FALSE;
|
||||
uint32_t IrqEn = DiagGetIsrEnReg();
|
||||
|
||||
DiagSetIsrEnReg(0);
|
||||
|
||||
data = DiagGetChar(PullMode);
|
||||
if ( data > 0 )
|
||||
data = DiagGetChar(PullMode);
|
||||
if (data > 0)
|
||||
rx_buffer0.store_char(data);
|
||||
|
||||
DiagSetIsrEnReg(IrqEn);
|
||||
|
||||
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::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 ;
|
||||
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::available(void) {
|
||||
return (uint32_t)(SERIAL_BUFFER_SIZE + _rx_buffer->_iHead - _rx_buffer->_iTail) % SERIAL_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
int LOGUARTClass::peek( void )
|
||||
{
|
||||
int LOGUARTClass::peek(void) {
|
||||
|
||||
if ( _rx_buffer->_iHead == _rx_buffer->_iTail )
|
||||
return -1 ;
|
||||
|
||||
return _rx_buffer->_aucBuffer[_rx_buffer->_iTail] ;
|
||||
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 ;
|
||||
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)
|
||||
;
|
||||
*/
|
||||
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;
|
||||
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;
|
||||
return Serial.available() > 0;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
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.
|
||||
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
|
||||
@@ -18,36 +18,41 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "api/HardwareSerial.h"
|
||||
#include "api/RingBuffer.h"
|
||||
#include <api/HardwareSerial.h>
|
||||
#include <api/RingBuffer.h>
|
||||
|
||||
using namespace arduino;
|
||||
|
||||
class LOGUARTClass : public HardwareSerial
|
||||
{
|
||||
// TODO this class begs to be rewritten :(
|
||||
|
||||
class LOGUARTClass : public HardwareSerial {
|
||||
public:
|
||||
LOGUARTClass(int dwIrq, RingBuffer* pRx_buffer );
|
||||
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);
|
||||
void begin(const uint32_t dwBaudRate);
|
||||
|
||||
using Print::write; // pull in write(str) and write(buf, size) from Print
|
||||
inline void begin(const uint32_t dwBaudRate, uint16_t config) {
|
||||
begin(dwBaudRate); // TODO implement this properly
|
||||
}
|
||||
|
||||
operator bool() { return true; }; // UART always active
|
||||
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;
|
||||
RingBuffer *_rx_buffer;
|
||||
|
||||
int _dwIrq;
|
||||
int _dwIrq;
|
||||
|
||||
private:
|
||||
friend bool Serial_available();
|
||||
friend bool Serial_available();
|
||||
};
|
||||
|
||||
145
arduino/realtek-ambz/cores/arduino/LibreTuyaAPI.cpp
Normal file
145
arduino/realtek-ambz/cores/arduino/LibreTuyaAPI.cpp
Normal file
@@ -0,0 +1,145 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-28. */
|
||||
|
||||
#include <LibreTuyaAPI.h>
|
||||
|
||||
extern "C" {
|
||||
#include <flash_api.h>
|
||||
#include <rtl8710b.h>
|
||||
#include <sys_api.h>
|
||||
}
|
||||
|
||||
void LibreTuya::restart() {
|
||||
sys_reset();
|
||||
}
|
||||
|
||||
/* CPU-related */
|
||||
|
||||
ChipType LibreTuya::getChipType() {
|
||||
uint8_t chipId;
|
||||
EFUSE_OneByteReadROM(9902, 0xF8, &chipId, L25EOUTVOLTAGE);
|
||||
return (ChipType)(((RTL8710B >> 24) << 8) | chipId);
|
||||
}
|
||||
|
||||
const char *LibreTuya::getChipModel() {
|
||||
return STRINGIFY_MACRO(MCU);
|
||||
}
|
||||
|
||||
uint32_t LibreTuya::getChipId() {
|
||||
uint32_t chipId = 0;
|
||||
uint8_t *id = (uint8_t *)&chipId;
|
||||
// 9902 was extracted from ROM disassembly, probably not needed
|
||||
EFUSE_OneByteReadROM(9902, 0x3B, id + 0, L25EOUTVOLTAGE);
|
||||
EFUSE_OneByteReadROM(9902, 0x3C, id + 1, L25EOUTVOLTAGE);
|
||||
EFUSE_OneByteReadROM(9902, 0x3D, id + 2, L25EOUTVOLTAGE);
|
||||
return chipId;
|
||||
}
|
||||
|
||||
uint8_t LibreTuya::getChipCores() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *LibreTuya::getChipCoreType() {
|
||||
return "ARM Cortex-M4F";
|
||||
}
|
||||
|
||||
uint32_t LibreTuya::getCpuFreqMHz() {
|
||||
return CPU_ClkGet(false) / 1000000;
|
||||
}
|
||||
|
||||
inline uint32_t LibreTuya::getCycleCount() {
|
||||
return microsecondsToClockCycles(micros());
|
||||
}
|
||||
|
||||
/* Memory management */
|
||||
|
||||
uint32_t LibreTuya::getRamSize() {
|
||||
return 256 * 1024;
|
||||
}
|
||||
|
||||
uint32_t LibreTuya::getHeapSize() {
|
||||
return configTOTAL_HEAP_SIZE;
|
||||
}
|
||||
|
||||
uint32_t LibreTuya::getFreeHeap() {
|
||||
return xPortGetFreeHeapSize();
|
||||
}
|
||||
|
||||
uint32_t LibreTuya::getMinFreeHeap() {
|
||||
return xPortGetMinimumEverFreeHeapSize();
|
||||
}
|
||||
|
||||
uint32_t LibreTuya::getMaxAllocHeap() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* OTA-related */
|
||||
|
||||
uint8_t LibreTuya::otaGetStoredIndex() {
|
||||
uint32_t *otaAddress = (uint32_t *)0x8009000;
|
||||
if (*otaAddress == 0xFFFFFFFF)
|
||||
return 1;
|
||||
uint32_t otaCounter = *((uint32_t *)0x8009004);
|
||||
// even count of zero-bits means OTA1, odd count means OTA2
|
||||
// this allows to switch OTA images by simply clearing next bits,
|
||||
// without needing to erase the flash
|
||||
uint8_t count = 0;
|
||||
for (uint8_t i = 0; i < 32; i++) {
|
||||
if ((otaCounter & (1 << i)) == 0)
|
||||
count++;
|
||||
}
|
||||
return 1 + (count % 2);
|
||||
}
|
||||
|
||||
bool LibreTuya::otaSupportsDual() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LibreTuya::otaHasImage1() {
|
||||
uint8_t *ota1Addr = (uint8_t *)(SPI_FLASH_BASE + FLASH_OTA1_OFFSET);
|
||||
return memcmp(ota1Addr, "81958711", 8) == 0;
|
||||
}
|
||||
|
||||
bool LibreTuya::otaHasImage2() {
|
||||
uint8_t *ota2Addr = (uint8_t *)(SPI_FLASH_BASE + FLASH_OTA2_OFFSET);
|
||||
return memcmp(ota2Addr, "81958711", 8) == 0;
|
||||
}
|
||||
|
||||
bool LibreTuya::otaSwitch(bool force) {
|
||||
if (!force && otaGetRunning() != otaGetStoredIndex())
|
||||
// OTA has already been switched
|
||||
return true;
|
||||
// this function does:
|
||||
// - read OTA1 firmware magic from 0xB000
|
||||
// - read OTA2 address from 0x9000
|
||||
// - read OTA2 firmware magic from that address
|
||||
// - read current OTA switch value from 0x9004
|
||||
// - reset OTA switch to 0xFFFFFFFF if it's 0x0
|
||||
// - check first non-zero bit of OTA switch
|
||||
// - write OTA switch with first non-zero bit cleared
|
||||
// sys_clear_ota_signature();
|
||||
// ok, this function is broken (crashes with HardFault)
|
||||
|
||||
if (!otaHasImage1() || !otaHasImage2())
|
||||
return false;
|
||||
|
||||
uint32_t value = HAL_READ32(SPI_FLASH_BASE, FLASH_SYSTEM_OFFSET + 4);
|
||||
if (value == 0) {
|
||||
// TODO does this work at all?
|
||||
FLASH_EreaseDwordsXIP(FLASH_SYSTEM_OFFSET + 4, 1);
|
||||
}
|
||||
uint8_t i;
|
||||
// find first non-zero bit
|
||||
for (i = 0; i < 32; i++) {
|
||||
if (value & (1 << i))
|
||||
break;
|
||||
}
|
||||
// clear the bit
|
||||
value &= ~(1 << i);
|
||||
// write OTA switch to flash
|
||||
flash_write_word(NULL, FLASH_SYSTEM_OFFSET + 4, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Global instance */
|
||||
|
||||
LibreTuya LT;
|
||||
@@ -1,76 +0,0 @@
|
||||
#ifndef _POWER_MANAGEMENT_H_
|
||||
#define _POWER_MANAGEMENT_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
/**
|
||||
* @class PowerManagementClass PowerManagement.h
|
||||
* @brief Power management in Ameba
|
||||
*/
|
||||
class PowerManagementClass {
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Allow OS automatically save power while idle
|
||||
*
|
||||
* As OS consider it would idle for more than 2s, it will invoke system suspend.
|
||||
* If wlan is associated with AP, than it will under asslociated idle state.
|
||||
*/
|
||||
static void sleep(void);
|
||||
static void sleep(uint32_t bitflg);
|
||||
|
||||
/**
|
||||
* @brief Disallow OS automatically save power while idle
|
||||
*/
|
||||
static void active(void);
|
||||
static void active(uint32_t bitflg);
|
||||
|
||||
/**
|
||||
* @brief Reserved PLL while sleep
|
||||
*
|
||||
* Reserve PLL would keep FIFO of peripherals (Ex. UART) but cost more power (around 5mA).
|
||||
* If we don't reserve PLL, it saves more power but we might missing data because FIFO is turned of this way.
|
||||
*
|
||||
* @param[in] reserve true for reserved, false for non-reserved
|
||||
*/
|
||||
static void setPllReserved(bool reserve);
|
||||
|
||||
/**
|
||||
* @brief Enter deepsleep immediately
|
||||
*
|
||||
* Invoke deepsleep would make system enter deepsleep state immediately.
|
||||
* It's the state that saves most power.
|
||||
* As it wakeup from deepsleep, the system would behave just like reboot.
|
||||
*
|
||||
* @param[in] duration_ms wakeup after specific time in unit of millisecond
|
||||
*/
|
||||
static void deepsleep(uint32_t duration_ms);
|
||||
|
||||
/**
|
||||
* @brief Check if system is allowed enter any power save state
|
||||
*
|
||||
* The pin 18 (GPIOE_5) is designed as safe lock.
|
||||
* If pin 18 is HIGH, then we prevent Ameba enter any power save state.\n\n
|
||||
* Under any power save state, we are not able to flash image to Ameba.
|
||||
* Thus if user misuse deepsleep and make Ameba enter deepsleep immediately after boot up,
|
||||
* then he would find it's hard to flash image.
|
||||
* In this case, he can pull up pin 18.
|
||||
*
|
||||
* @return true if system not allowed enter any power save state, and false vise versa
|
||||
*/
|
||||
static bool safeLock();
|
||||
|
||||
/**
|
||||
* @brief Reboot system
|
||||
*
|
||||
* Reboot system in soft way. Some registers is not powered off in this case, but mostly we could regard this as reboot.
|
||||
*/
|
||||
static void softReset();
|
||||
|
||||
private:
|
||||
static bool reservePLL;
|
||||
};
|
||||
|
||||
extern PowerManagementClass PowerManagement;
|
||||
|
||||
#endif
|
||||
@@ -1,17 +1,12 @@
|
||||
#if 1 // !defined(BOARD_RTL8710)
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
extern void pinRemoveMode(pin_size_t pinNumber);
|
||||
extern void _tone(uint32_t ulPin, unsigned int frequency, unsigned long duration);
|
||||
}
|
||||
#endif
|
||||
|
||||
// a wrapper that support default value of duration
|
||||
void tone(uint32_t ulPin, unsigned int frequency, unsigned long duration)
|
||||
{
|
||||
_tone(ulPin, frequency, duration);
|
||||
void tone(uint32_t ulPin, unsigned int frequency, unsigned long duration) {
|
||||
_tone(ulPin, frequency, duration);
|
||||
}
|
||||
|
||||
#endif
|
||||
void noTone(uint32_t ulPin) {
|
||||
pinRemoveMode(ulPin);
|
||||
}
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
#include "Arduino.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "gpio_api.h"
|
||||
#include "gpio_irq_api.h"
|
||||
#include "gpio_irq_ex_api.h"
|
||||
#include <Arduino.h>
|
||||
#include <gpio_api.h>
|
||||
#include <gpio_irq_api.h>
|
||||
#include <gpio_irq_ex_api.h>
|
||||
|
||||
extern void *gpio_pin_struct[PINS_COUNT];
|
||||
extern void *gpio_irq_handler_list[PINS_COUNT];
|
||||
|
||||
extern bool pinInvalid(pin_size_t pinNumber);
|
||||
extern void pinRemoveMode(pin_size_t pinNumber);
|
||||
|
||||
void gpioIrqHandler(uint32_t id, gpio_irq_event event) {
|
||||
if (gpio_irq_handler_list[id] != NULL) {
|
||||
((void (*)(uint32_t, uint32_t))gpio_irq_handler_list[id])(id, (uint32_t)event);
|
||||
@@ -36,7 +34,7 @@ void attachInterrupt(pin_size_t interruptNumber, voidFuncPtr callback, PinStatus
|
||||
|
||||
if (g_APinDescription[interruptNumber].ulPinType == NOT_INITIAL) {
|
||||
// allocate memory if pin not used before
|
||||
gpio = malloc(sizeof(gpio_irq_t));
|
||||
gpio = malloc(sizeof(gpio_irq_t));
|
||||
gpio_pin_struct[interruptNumber] = gpio;
|
||||
gpio_irq_init(gpio, g_APinDescription[interruptNumber].pinname, gpioIrqHandler, interruptNumber);
|
||||
g_APinDescription[interruptNumber].ulPinType = PIO_GPIO_IRQ;
|
||||
@@ -78,7 +76,3 @@ void detachInterrupt(pin_size_t interruptNumber) {
|
||||
}
|
||||
gpio_irq_handler_list[interruptNumber] = NULL;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,77 +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 <inttypes.h>
|
||||
#include "api/Common.h"
|
||||
|
||||
extern "C" {
|
||||
extern void rtl_srandom( uint32_t seed );
|
||||
extern uint32_t rtl_random( void );
|
||||
}
|
||||
|
||||
#ifndef srand
|
||||
#define srand rtl_srandom
|
||||
#endif
|
||||
#ifndef rand
|
||||
#define rand rtl_random
|
||||
#endif
|
||||
|
||||
extern void randomSeed( uint32_t dwSeed )
|
||||
{
|
||||
if ( dwSeed != 0 )
|
||||
{
|
||||
srand( dwSeed ) ;
|
||||
}
|
||||
}
|
||||
|
||||
extern long random( long howbig )
|
||||
{
|
||||
if ( howbig == 0 )
|
||||
{
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
return rand() % howbig;
|
||||
}
|
||||
|
||||
extern long random( long howsmall, long howbig )
|
||||
{
|
||||
if (howsmall >= howbig)
|
||||
{
|
||||
return howsmall;
|
||||
}
|
||||
|
||||
long diff = howbig - howsmall;
|
||||
|
||||
return random(diff) + howsmall;
|
||||
}
|
||||
|
||||
extern long map(long x, long in_min, long in_max, long out_min, long out_max)
|
||||
{
|
||||
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
||||
}
|
||||
|
||||
extern uint16_t makeWord( uint16_t w )
|
||||
{
|
||||
return w ;
|
||||
}
|
||||
|
||||
extern uint16_t makeWord( uint8_t h, uint8_t l )
|
||||
{
|
||||
return (h << 8) | l ;
|
||||
}
|
||||
@@ -1,104 +1,60 @@
|
||||
#pragma once
|
||||
|
||||
#include "wiring_os.h"
|
||||
#include "wiring_watchdog.h"
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#define boolean boolean_rtl
|
||||
#include "rtl_lib.h"
|
||||
#undef boolean
|
||||
#include "sdk_extern.h"
|
||||
#include "sdk_mem.h"
|
||||
#include "sdk_os.h"
|
||||
|
||||
/* moved from Arduino.h */
|
||||
/*
|
||||
* \brief Set CPU CLK 166MHz
|
||||
* clk : 0 - 166666666 Hz, 1 - 83333333 Hz, 2 - 41666666 Hz, 3 - 20833333 Hz, 4 - 10416666 Hz, 5 - 4000000 Hz
|
||||
* baud: 38400,...
|
||||
*/
|
||||
extern void Init_CPU_CLK_UART(int clkn, int baud);
|
||||
extern void sys_info(void);
|
||||
/* HalGetChipId:
|
||||
* 0xff - RTL8711AM, 0xfe - RTL8195AM, 0xfd - RTL8711AF,
|
||||
* 0xfc - RTL8710AF, 0xfb - RTL8711AN, 0xfa - RTL8710AM */
|
||||
extern unsigned char HalGetChipId(void);
|
||||
extern unsigned int HalGetCpuClk(void);
|
||||
|
||||
extern void wait_us(int us);
|
||||
#define delay_us wait_us
|
||||
|
||||
extern void yield(void);
|
||||
|
||||
#ifndef printf
|
||||
#define printf rtl_printf
|
||||
#endif
|
||||
#ifndef sprintf
|
||||
#define sprintf rtl_sprintf
|
||||
#endif
|
||||
|
||||
#define NOT_INITIAL (1UL<<0)
|
||||
#define PIO_GPIO (1UL<<1)
|
||||
#define PIO_PWM (1UL<<2)
|
||||
#define PIO_I2C (1UL<<3)
|
||||
#define PIO_ADC (1UL<<4)
|
||||
#define PIO_DAC (1UL<<5)
|
||||
#define PIO_GPIO_IRQ (1UL<<6)
|
||||
#define NOT_INITIAL (1UL << 0)
|
||||
#define PIO_GPIO (1UL << 1)
|
||||
#define PIO_PWM (1UL << 2)
|
||||
#define PIO_I2C (1UL << 3)
|
||||
#define PIO_ADC (1UL << 4)
|
||||
#define PIO_DAC (1UL << 5)
|
||||
#define PIO_GPIO_IRQ (1UL << 6)
|
||||
|
||||
#define PWM_MODE_ENABLED 1
|
||||
#define PWM_MODE_DISABLED 0
|
||||
|
||||
/* Types used for the tables below */
|
||||
typedef struct _PinDescription
|
||||
{
|
||||
// HW PinNames
|
||||
uint32_t pinname;
|
||||
// Current Pin Type
|
||||
uint32_t ulPinType;
|
||||
// Supported Pin Function
|
||||
uint32_t ulPinAttribute;
|
||||
// Current Pin Mode
|
||||
uint32_t ulPinMode;
|
||||
} PinDescription ;
|
||||
|
||||
/* Pins table to be instanciated into variant.cpp */
|
||||
extern PinDescription g_APinDescription[];
|
||||
|
||||
extern bool pinInvalid(pin_size_t pinNumber);
|
||||
extern void pinRemoveMode(pin_size_t pinNumber);
|
||||
|
||||
/* moved from wiring_digital.h */
|
||||
/**************************** Extend API by RTK ***********************************/
|
||||
extern uint32_t digitalPinToPort( uint32_t pinNumber );
|
||||
extern uint32_t digitalPinToBitMask( uint32_t pinNumber );
|
||||
|
||||
/* moved from wiring_analog.h */
|
||||
/*
|
||||
* \brief Set the resolution of analogRead return values. Default is 10 bits (range from 0 to 1023).
|
||||
*
|
||||
* \param res
|
||||
*/
|
||||
extern void analogReadResolution(int res);
|
||||
/*
|
||||
* \brief Set the resolution of analogWrite parameters. Default is 8 bits (range from 0 to 255).
|
||||
*
|
||||
* \param res
|
||||
*/
|
||||
extern void analogWriteResolution(int res);
|
||||
extern void analogOutputInit( void ) ;
|
||||
extern void analogWritePeriod(int us);
|
||||
|
||||
/* moved from wiring_constants.h */
|
||||
#define DEFAULT 1
|
||||
#define DEFAULT 1
|
||||
#define EXTERNAL 0
|
||||
|
||||
#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
|
||||
#define round(x) ((x) >= 0 ? (long)((x) + 0.5) : (long)((x)-0.5))
|
||||
|
||||
extern uint32_t ulPortSetInterruptMask( void );
|
||||
extern void vPortClearInterruptMask( uint32_t ulNewMask );
|
||||
typedef enum _eAnalogReference {
|
||||
AR_DEFAULT,
|
||||
} eAnalogReference;
|
||||
|
||||
// Types used for the table below
|
||||
typedef struct _PinDescription {
|
||||
// HW PinNames
|
||||
uint32_t pinname;
|
||||
// Current Pin Type
|
||||
uint32_t ulPinType;
|
||||
// Supported Pin Function
|
||||
uint32_t ulPinAttribute;
|
||||
// Current Pin Mode
|
||||
uint32_t ulPinMode;
|
||||
} PinDescription;
|
||||
|
||||
// Pins table to be instantiated into variant.cpp
|
||||
extern PinDescription g_APinDescription[];
|
||||
|
||||
// Additional Wiring functions
|
||||
extern uint32_t digitalPinToPort(uint32_t pinNumber);
|
||||
extern uint32_t digitalPinToBitMask(uint32_t pinNumber);
|
||||
extern void analogReadResolution(int res);
|
||||
extern void analogWriteResolution(int res);
|
||||
extern void analogOutputInit(void);
|
||||
extern void analogWritePeriod(int us);
|
||||
extern void wait_for_debug();
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
/*
|
||||
* WebSocketClient + SSL/TSL
|
||||
* RTL8710AF pvvx 12/12/2016
|
||||
*
|
||||
*/
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "WebSocketClient.h"
|
||||
|
||||
WebSocketClient::WebSocketClient() {
|
||||
}
|
||||
|
||||
WebSocketClient::WebSocketClient(char *url, int port, char *path, char* origin) {
|
||||
client = create_wsclient(url, port, path, origin);
|
||||
}
|
||||
|
||||
WebSocketClient::~WebSocketClient() {
|
||||
close();
|
||||
}
|
||||
|
||||
int WebSocketClient::begin(char *url, int port, char *path, char* origin) {
|
||||
client = create_wsclient(url, port, path, origin);
|
||||
if(client != NULL) return 1;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
int WebSocketClient::connect() {
|
||||
if(client != NULL) return ws_connect_url(client);
|
||||
else return -1;
|
||||
}
|
||||
|
||||
void WebSocketClient::send(char* message, int message_len, int use_mask) {
|
||||
if(client != NULL && client->readyState > CLOSED) {
|
||||
ws_send(message, message_len, use_mask, client);
|
||||
ws_poll(0, client);
|
||||
}
|
||||
}
|
||||
|
||||
void WebSocketClient::sendBinary(uint8_t* message, int message_len, int use_mask) {
|
||||
if(client != NULL && client->readyState > CLOSED) {
|
||||
ws_sendBinary(message, message_len, use_mask, client);
|
||||
ws_poll(0, client);
|
||||
}
|
||||
}
|
||||
|
||||
void WebSocketClient::sendPing() {
|
||||
if(client != NULL && client->readyState > CLOSED) {
|
||||
ws_sendPing(client);
|
||||
ws_poll(0, client);
|
||||
}
|
||||
}
|
||||
|
||||
void WebSocketClient::poll(int timeout) {
|
||||
if(client != NULL) ws_poll(timeout, client);
|
||||
}
|
||||
|
||||
readyStateValues WebSocketClient::getReadyState() {
|
||||
if(client != NULL) return ws_getReadyState(client);
|
||||
else return CLOSED;
|
||||
}
|
||||
|
||||
void WebSocketClient::dispatch(void (*callback)(wsclient_context *, int))
|
||||
{
|
||||
if(client != NULL) ws_dispatch(callback);
|
||||
}
|
||||
|
||||
void WebSocketClient::close() {
|
||||
if(client != NULL) {
|
||||
ws_close(client);
|
||||
if(client->ssl) {
|
||||
free(client->ssl);
|
||||
client->ssl = NULL;
|
||||
}
|
||||
client = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void set_ssl_func(wsclient_context *wsclient); // in example_wsclient.c
|
||||
|
||||
void WebSocketClient::ssl_func_on(void)
|
||||
{
|
||||
set_ssl_func(client);
|
||||
/*
|
||||
client->fun_ops.ssl_fun_ops.memory_set_own = memory_set_own;
|
||||
client->fun_ops.ssl_fun_ops.net_connect = net_connect;
|
||||
client->fun_ops.ssl_fun_ops.ssl_init = ssl_init;
|
||||
client->fun_ops.ssl_fun_ops.ssl_set_endpoint = ssl_set_endpoint;
|
||||
client->fun_ops.ssl_fun_ops.ssl_set_authmode = ssl_set_authmode;
|
||||
client->fun_ops.ssl_fun_ops.ssl_set_rng = ssl_set_rng;
|
||||
client->fun_ops.ssl_fun_ops.ssl_set_bio = ssl_set_bio;
|
||||
client->fun_ops.ssl_fun_ops.ssl_handshake = ssl_handshake;
|
||||
client->fun_ops.ssl_fun_ops.net_close = net_close;
|
||||
client->fun_ops.ssl_fun_ops.ssl_free = ssl_free;
|
||||
client->fun_ops.ssl_fun_ops.ssl_read = ssl_read;
|
||||
client->fun_ops.ssl_fun_ops.ssl_write = ssl_write;
|
||||
client->fun_ops.ssl_fun_ops.net_recv = net_recv;
|
||||
client->fun_ops.ssl_fun_ops.net_send = net_send;
|
||||
client->ssl = (void *)zalloc(sizeof(struct _ssl_context)); // 380 bytes
|
||||
*/
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
/*
|
||||
* WebSocketClient + SSL/TSL
|
||||
* RTL8710AF pvvx 12/12/2016
|
||||
*
|
||||
*/
|
||||
#ifndef WEBSOCKETCLIENT_H_
|
||||
#define WEBSOCKETCLIENT_H_
|
||||
|
||||
#include <Arduino.h>
|
||||
extern "C" {
|
||||
#include "libwsclient.h"
|
||||
#include "wsclient_api.h"
|
||||
}
|
||||
|
||||
class WebSocketClient {
|
||||
public:
|
||||
WebSocketClient();
|
||||
~WebSocketClient();
|
||||
|
||||
/*************************************************************************************************
|
||||
** Function Name : begin
|
||||
** Description : Creating the websocket client context structure
|
||||
** Input : url:websocket server's url
|
||||
** port:websocket server's port, if not given, default 80 for "ws", 443 for "wss"
|
||||
** origin: the address or url of your self
|
||||
** Return : Ok: 1
|
||||
** Failed: 0
|
||||
**************************************************************************************************/
|
||||
WebSocketClient(char *url, int port, char *path = NULL, char* origin = NULL);
|
||||
int begin(char *url, int port, char *path = NULL, char* origin = NULL);
|
||||
|
||||
/*************************************************************************************************
|
||||
** Function Name : connect
|
||||
** Description : Connecting to the websocket server
|
||||
** Input : wsclient: the websocket client context created by create_wsclientfunction
|
||||
** Return : Connected: the socket value
|
||||
** Failed: -1
|
||||
**************************************************************************************************/
|
||||
int connect();
|
||||
|
||||
/*************************************************************************************************
|
||||
** Function Name : ws_send
|
||||
** Description : Create the sending string data and copy to tx_buf
|
||||
** Input : message: the string that send to server(cannot exceeding the MAX_DATA_LEN
|
||||
** message_len: the length of the string
|
||||
** use_mask: 0/1; 1 means using mask for bynary
|
||||
** wsclient: the websocket client context
|
||||
** Return : None
|
||||
**************************************************************************************************/
|
||||
void send(char* message, int message_len, int use_mask);
|
||||
|
||||
/*************************************************************************************************
|
||||
** Function Name : sendBinary
|
||||
** Description : Create the sending binary data and copy to tx_buf
|
||||
** Input : message: the binary that send to server(cannot exceeding the MAX_DATA_LEN
|
||||
** message_len: the length of the binary
|
||||
** use_mask: 0/1; 1 means using mask for bynary
|
||||
** wsclient: the websocket client context
|
||||
** Return : None
|
||||
**************************************************************************************************/
|
||||
void sendBinary(uint8_t* message, int message_len, int use_mask);
|
||||
|
||||
/*************************************************************************************************
|
||||
** Function Name : sendPing
|
||||
** Description : Sending Ping to websocket server
|
||||
** Input : wsclient: the websocket client context
|
||||
** Return : None
|
||||
**************************************************************************************************/
|
||||
void sendPing();
|
||||
|
||||
/*************************************************************************************************
|
||||
** Function Name : poll
|
||||
** Description : Receicing data from server and send the data in tx_buf
|
||||
** Input : timeout(in milliseconds)
|
||||
wsclient: the websocket client context
|
||||
** Return : None
|
||||
**************************************************************************************************/
|
||||
void poll(int timeout);
|
||||
|
||||
/*************************************************************************************************
|
||||
** Function Name : dispatch
|
||||
** Description : callback function when getting message from server
|
||||
** Input : function that resolve the message received and the message length
|
||||
** Return : None
|
||||
**************************************************************************************************/
|
||||
void dispatch(void (*callback)(wsclient_context *, int));
|
||||
|
||||
/*************************************************************************************************
|
||||
** Function Name : getReadyState
|
||||
** Description : Getting the connection status
|
||||
** Input : wsclient: the websocket client context
|
||||
** Return : readyStateValues(4 types: CLOSING, CLOSED, CONNECTING, OPEN )
|
||||
**************************************************************************************************/
|
||||
readyStateValues getReadyState();
|
||||
|
||||
/*************************************************************************************************
|
||||
** Function Name : close
|
||||
** Description : Closing the connection with websocket server
|
||||
** Input : wsclient: the websocket client context
|
||||
** Return : None
|
||||
**************************************************************************************************/
|
||||
void close();
|
||||
|
||||
/*************************************************************************************************
|
||||
** Function Name : ssl_func_on
|
||||
** Description : Set SSL/TSL function
|
||||
** Input : None
|
||||
** Return : None
|
||||
**************************************************************************************************/
|
||||
void ssl_func_on(void);
|
||||
|
||||
private:
|
||||
wsclient_context *client;
|
||||
};
|
||||
|
||||
#endif // WEBSOCKETCLIENT_H_
|
||||
@@ -1,214 +0,0 @@
|
||||
#include <platform_opts.h>
|
||||
#include <lwip/sockets.h>
|
||||
#include <lwip/netif.h>
|
||||
#include <platform/platform_stdlib.h>
|
||||
#include "ard_socket.h"
|
||||
|
||||
int start_server(uint16_t port, uint8_t protMode)
|
||||
{
|
||||
int _sock;
|
||||
int timeout;
|
||||
|
||||
if(protMode == 0) {
|
||||
timeout = 3000;
|
||||
_sock = lwip_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
lwip_setsockopt(_sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
|
||||
} else {
|
||||
timeout = 1000;
|
||||
_sock = lwip_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
lwip_setsockopt(_sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
|
||||
}
|
||||
|
||||
if (_sock < 0) {
|
||||
printf("\r\nERROR opening socket\r\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct sockaddr_in localHost;
|
||||
memset(&localHost, 0, sizeof(localHost));
|
||||
|
||||
localHost.sin_family = AF_INET;
|
||||
localHost.sin_port = htons(port);
|
||||
localHost.sin_addr.s_addr = INADDR_ANY;
|
||||
|
||||
if (lwip_bind(_sock, (struct sockaddr *)&localHost, sizeof(localHost)) < 0) {
|
||||
printf("\r\nERROR on binding\r\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _sock;
|
||||
}
|
||||
|
||||
int sock_listen(int sock, int max)
|
||||
{
|
||||
if(lwip_listen(sock , max) < 0){
|
||||
printf("\r\nERROR on listening\r\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_available(int sock)
|
||||
{
|
||||
int enable = 1;
|
||||
int timeout;
|
||||
int client_fd;
|
||||
int err;
|
||||
struct sockaddr_in cli_addr;
|
||||
|
||||
socklen_t client = sizeof(cli_addr);
|
||||
|
||||
do {
|
||||
client_fd = lwip_accept(sock, (struct sockaddr *) &cli_addr, &client);
|
||||
if (client_fd < 0) {
|
||||
err = get_sock_errno(sock);
|
||||
if (err != EAGAIN) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (client_fd < 0);
|
||||
|
||||
if(client_fd < 0){
|
||||
printf("\r\nERROR on accept\r\n");
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
timeout = 3000;
|
||||
lwip_setsockopt(client_fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
|
||||
timeout = 30000;
|
||||
lwip_setsockopt(client_fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
|
||||
lwip_setsockopt(client_fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable));
|
||||
lwip_setsockopt(client_fd, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable));
|
||||
printf("\r\nA client connected to this server :\r\n[PORT]: %d\r\n[IP]:%s\r\n\r\n", ntohs(cli_addr.sin_port), inet_ntoa(cli_addr.sin_addr.s_addr));
|
||||
return client_fd;
|
||||
}
|
||||
}
|
||||
|
||||
int get_receive(int sock, uint8_t* data, int length, int flag, uint32_t *peer_addr, uint16_t *peer_port)
|
||||
{
|
||||
int ret = 0;
|
||||
struct sockaddr from;
|
||||
socklen_t fromlen;
|
||||
|
||||
uint8_t backup_recvtimeout = 0;
|
||||
int backup_recv_timeout, recv_timeout, len;
|
||||
|
||||
if (flag & 0x01) {
|
||||
// for MSG_PEEK, we try to peek packets by changing receiving timeout to 10ms
|
||||
ret = lwip_getsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &backup_recv_timeout, &len);
|
||||
if (ret >= 0) {
|
||||
recv_timeout = 10;
|
||||
ret = lwip_setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &recv_timeout, sizeof(recv_timeout));
|
||||
if (ret >= 0) {
|
||||
backup_recvtimeout = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = lwip_recvfrom(sock, data, length, flag, &from, &fromlen);
|
||||
if ( ret >= 0 ) {
|
||||
if (peer_addr != NULL) {
|
||||
*peer_addr = ((struct sockaddr_in *)&from)->sin_addr.s_addr;
|
||||
}
|
||||
if (peer_port != NULL) {
|
||||
*peer_port = ntohs(((struct sockaddr_in *)&from)->sin_port);
|
||||
}
|
||||
}
|
||||
|
||||
if ((flag & 0x01) && (backup_recvtimeout == 1)) {
|
||||
// restore receiving timeout
|
||||
lwip_setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &backup_recv_timeout, sizeof(recv_timeout));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int get_sock_errno(int sock)
|
||||
{
|
||||
int so_error;
|
||||
socklen_t len = sizeof(so_error);
|
||||
getsockopt(sock, SOL_SOCKET, SO_ERROR, &so_error, &len);
|
||||
return so_error;
|
||||
}
|
||||
|
||||
int set_sock_recv_timeout(int sock, int timeout)
|
||||
{
|
||||
return lwip_setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
|
||||
}
|
||||
|
||||
void stop_socket(int sock)
|
||||
{
|
||||
lwip_close(sock);
|
||||
}
|
||||
|
||||
int send_data(int sock, const uint8_t *data, uint16_t len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = lwip_write(sock, data, len);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sendto_data(int sock, const uint8_t *data, uint16_t len, uint32_t peer_ip, uint16_t peer_port)
|
||||
{
|
||||
int ret;
|
||||
|
||||
struct sockaddr_in peer_addr;
|
||||
memset(&peer_addr, 0, sizeof(peer_addr));
|
||||
peer_addr.sin_family = AF_INET;
|
||||
peer_addr.sin_addr.s_addr = peer_ip;
|
||||
peer_addr.sin_port = htons(peer_port);
|
||||
|
||||
ret = lwip_sendto(sock, data, len, 0, (struct sockaddr*)&peer_addr, sizeof(struct sockaddr_in));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int start_client(uint32_t ipAddress, uint16_t port, uint8_t protMode)
|
||||
{
|
||||
int enable = 1;
|
||||
int timeout;
|
||||
int _sock;
|
||||
|
||||
if(protMode == 0)//tcp
|
||||
_sock = lwip_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
else
|
||||
_sock = lwip_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
|
||||
if (_sock < 0) {
|
||||
printf("\r\nERROR opening socket\r\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct sockaddr_in serv_addr;
|
||||
memset(&serv_addr, 0, sizeof(serv_addr));
|
||||
serv_addr.sin_family = AF_INET;
|
||||
serv_addr.sin_addr.s_addr = ipAddress;
|
||||
serv_addr.sin_port = htons(port);
|
||||
|
||||
if (protMode == 0){//TCP MODE
|
||||
if(connect(_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == 0){
|
||||
printf("\r\nConnect to Server successful!\r\n");
|
||||
|
||||
timeout = 3000;
|
||||
lwip_setsockopt(_sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
|
||||
timeout = 30000;
|
||||
lwip_setsockopt(_sock, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
|
||||
lwip_setsockopt(_sock, IPPROTO_TCP, TCP_NODELAY, &enable, sizeof(enable));
|
||||
lwip_setsockopt(_sock, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable));
|
||||
|
||||
return _sock;
|
||||
}
|
||||
else{
|
||||
printf("\r\nConnect to Server failed!\r\n");
|
||||
stop_socket(_sock);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
//printf("\r\nUdp client setup Server's information successful!\r\n");
|
||||
}
|
||||
|
||||
return _sock;
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
#ifndef ARD_SOCKET_H
|
||||
#define ARD_SOCKET_H
|
||||
#include "main.h"
|
||||
|
||||
int start_server(uint16_t port, uint8_t protMode);
|
||||
|
||||
int sock_listen(int sock, int max);
|
||||
|
||||
int get_available(int sock);
|
||||
|
||||
int get_receive(int sock, uint8_t* data, int length, int flag, uint32_t *peer_addr, uint16_t *peer_port);
|
||||
|
||||
int get_sock_errno(int sock);
|
||||
|
||||
int set_sock_recv_timeout(int sock, int timeout);
|
||||
|
||||
void stop_socket(int sock);
|
||||
|
||||
int send_data(int sock, const uint8_t *data, uint16_t len);
|
||||
|
||||
int sendto_data(int sock, const uint8_t *data, uint16_t len, uint32_t peer_ip, uint16_t peer_port);
|
||||
|
||||
int start_client(uint32_t ipAddress, uint16_t port, uint8_t protMode);
|
||||
|
||||
#endif
|
||||
@@ -1,402 +0,0 @@
|
||||
#include "Arduino.h"
|
||||
#include <sockets.h>
|
||||
#include <lwip/netif.h>
|
||||
#include <mbedtls/ssl.h>
|
||||
#include <mbedtls/net_sockets.h>
|
||||
#include <mbedtls/error.h>
|
||||
#include <mbedtls/debug.h>
|
||||
#include "ard_ssl.h"
|
||||
|
||||
#define ARDUINO_MBEDTLS_DEBUG_LEVEL 0 // Set to 0 to disable debug messsages, 5 to enable all debug messages
|
||||
|
||||
static unsigned int ard_ssl_arc4random(void)
|
||||
{
|
||||
unsigned int res = xTaskGetTickCount();
|
||||
static unsigned int seed = 0xDEADB00B;
|
||||
|
||||
seed = ((seed & 0x007F00FF) << 7) ^
|
||||
((seed & 0x0F80FF00) >> 8) ^ // be sure to stir those low bits
|
||||
(res << 13) ^ (res >> 9); // using the clock too!
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
||||
static void get_random_bytes(void *buf, size_t len)
|
||||
{
|
||||
unsigned int ranbuf;
|
||||
unsigned int *lp;
|
||||
int i, count;
|
||||
count = len / sizeof(unsigned int);
|
||||
lp = (unsigned int *) buf;
|
||||
|
||||
for (i = 0; i < count; i ++) {
|
||||
lp[i] = ard_ssl_arc4random();
|
||||
len -= sizeof(unsigned int);
|
||||
}
|
||||
|
||||
if (len > 0) {
|
||||
ranbuf = ard_ssl_arc4random();
|
||||
memcpy(&lp[i], &ranbuf, len);
|
||||
}
|
||||
}
|
||||
|
||||
static int my_random(void *p_rng, unsigned char *output, size_t output_len)
|
||||
{
|
||||
p_rng = p_rng;
|
||||
get_random_bytes(output, output_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int my_verify(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags)
|
||||
{
|
||||
char buf[1024];
|
||||
((void)data);
|
||||
|
||||
mbedtls_x509_crt_info(buf, (sizeof(buf) - 1), "", crt);
|
||||
|
||||
if(ARDUINO_MBEDTLS_DEBUG_LEVEL < 3)
|
||||
return(0);
|
||||
|
||||
printf( "\nVerify requested for (Depth %d):\n", depth );
|
||||
printf( "%s", buf );
|
||||
|
||||
if ((*flags) == 0)
|
||||
printf(" This certificate has no flags\n");
|
||||
else
|
||||
{
|
||||
mbedtls_x509_crt_verify_info(buf, sizeof( buf ), " ! ", *flags);
|
||||
printf("%s\n", buf);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static void* my_calloc(size_t nelements, size_t elementSize)
|
||||
{
|
||||
size_t size;
|
||||
void *ptr = NULL;
|
||||
|
||||
size = nelements * elementSize;
|
||||
ptr = pvPortMalloc(size);
|
||||
|
||||
if(ptr)
|
||||
memset(ptr, 0, size);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static void my_debug(void *ctx, int level, const char *file, int line, const char *str )
|
||||
{
|
||||
const char *p, *basename;
|
||||
|
||||
ctx = ctx; // Remove unused parameter warning
|
||||
// Extract basename from file
|
||||
for( p = basename = file; *p != '\0'; p++ )
|
||||
if( *p == '/' || *p == '\\' )
|
||||
basename = p + 1;
|
||||
|
||||
printf("%s:%04d: |%d| %s", basename, line, level, str );
|
||||
}
|
||||
|
||||
int start_ssl_client(sslclient_context *ssl_client, uint32_t ipAddress, uint32_t port, unsigned char* rootCABuff, unsigned char* cli_cert, unsigned char* cli_key, unsigned char* pskIdent, unsigned char* psKey, char* SNI_hostname)
|
||||
{
|
||||
int ret = 0;
|
||||
//int timeout;
|
||||
int enable = 1;
|
||||
int keep_idle = 30;
|
||||
mbedtls_x509_crt* cacert = NULL;
|
||||
mbedtls_x509_crt* _cli_crt = NULL;
|
||||
mbedtls_pk_context* _clikey_rsa = NULL;
|
||||
|
||||
do {
|
||||
ssl_client->socket = -1;
|
||||
ssl_client->socket = lwip_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (ssl_client->socket < 0) {
|
||||
printf("ERROR: opening socket failed! \r\n");
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
struct sockaddr_in serv_addr;
|
||||
memset(&serv_addr, 0, sizeof(serv_addr));
|
||||
serv_addr.sin_family = AF_INET;
|
||||
serv_addr.sin_addr.s_addr = ipAddress;
|
||||
serv_addr.sin_port = htons(port);
|
||||
|
||||
lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable));
|
||||
lwip_setsockopt(ssl_client->socket, IPPROTO_TCP, TCP_KEEPIDLE, &keep_idle, sizeof(keep_idle));
|
||||
if (lwip_connect(ssl_client->socket, ((struct sockaddr *)&serv_addr), sizeof(serv_addr)) < 0) {
|
||||
lwip_close(ssl_client->socket);
|
||||
printf("ERROR: Connect to Server failed! \r\n");
|
||||
ret = -1;
|
||||
break;
|
||||
} else {
|
||||
/*/
|
||||
if (lwip_connect(ssl_client->socket, ((struct sockaddr *)&serv_addr), sizeof(serv_addr)) == 0) {
|
||||
timeout = ssl_client->recvTimeout;
|
||||
lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
|
||||
timeout = 30000;
|
||||
lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
|
||||
lwip_setsockopt(ssl_client->socket, IPPROTO_TCP, TCP_NODELAY, &enable, sizeof(enable));
|
||||
lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable));
|
||||
} else {
|
||||
printf("ERROR: Connect to Server failed!\r\n");
|
||||
ret = -1;
|
||||
break;
|
||||
}//*/
|
||||
|
||||
mbedtls_platform_set_calloc_free(my_calloc,vPortFree);
|
||||
|
||||
ssl_client->ssl = (mbedtls_ssl_context *)malloc(sizeof(mbedtls_ssl_context));
|
||||
ssl_client->conf = (mbedtls_ssl_config *)malloc(sizeof(mbedtls_ssl_config));
|
||||
if (( ssl_client->ssl == NULL )||( ssl_client->conf == NULL )) {
|
||||
printf("ERROR: malloc ssl failed! \r\n");
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
mbedtls_ssl_init(ssl_client->ssl);
|
||||
mbedtls_ssl_config_init(ssl_client->conf);
|
||||
|
||||
if (ARDUINO_MBEDTLS_DEBUG_LEVEL > 0) {
|
||||
mbedtls_ssl_conf_verify(ssl_client->conf, my_verify, NULL);
|
||||
mbedtls_ssl_conf_dbg(ssl_client->conf, my_debug, NULL);
|
||||
mbedtls_debug_set_threshold(ARDUINO_MBEDTLS_DEBUG_LEVEL);
|
||||
}
|
||||
|
||||
if((mbedtls_ssl_config_defaults(ssl_client->conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
|
||||
printf("ERROR: mbedtls ssl config defaults failed! \r\n");
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
mbedtls_ssl_conf_rng(ssl_client->conf, my_random, NULL);
|
||||
|
||||
if (rootCABuff != NULL) {
|
||||
// Configure mbedTLS to use certificate authentication method
|
||||
cacert = (mbedtls_x509_crt *) mbedtls_calloc( sizeof(mbedtls_x509_crt), 1);
|
||||
mbedtls_x509_crt_init(cacert);
|
||||
if (mbedtls_x509_crt_parse(cacert, rootCABuff, (strlen((char*)rootCABuff)) + 1) != 0) {
|
||||
printf("ERROR: mbedtls x509 crt parse failed! \r\n");
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
mbedtls_ssl_conf_ca_chain(ssl_client->conf, cacert, NULL);
|
||||
mbedtls_ssl_conf_authmode(ssl_client->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
|
||||
} else if (pskIdent != NULL && psKey != NULL) {
|
||||
// Configure mbedTLS to use PSK authentication method
|
||||
// Check for max length and even number of chars
|
||||
uint16_t pskey_char_len = strlen((char*)psKey);
|
||||
if ( ((pskey_char_len % 2) != 0) || (pskey_char_len > 2*MBEDTLS_PSK_MAX_LEN) ) {
|
||||
printf("ERROR: TLS PSK not in valid hex format or too long \n");
|
||||
return -1;
|
||||
}
|
||||
uint16_t psk_len = pskey_char_len/2;
|
||||
unsigned char psk[MBEDTLS_PSK_MAX_LEN];
|
||||
// Convert PSK from hexadecimal chars to binary
|
||||
int i;
|
||||
for (i = 0; i < pskey_char_len; i = i + 2) {
|
||||
char c = psKey[i];
|
||||
// Convert first 4 bits
|
||||
if (c >= '0' && c <= '9') {
|
||||
c = c - '0';
|
||||
} else if (c >= 'A' && c <= 'F') {
|
||||
c = c - 'A' + 10;
|
||||
} else if (c >= 'a' && c <= 'f') {
|
||||
c = c - 'a' + 10;
|
||||
} else {
|
||||
printf("ERROR: TLS PSK not in valid hex format \n");
|
||||
return -1;
|
||||
}
|
||||
psk[i/2] = c << 4;
|
||||
c = psKey[i+1];
|
||||
// Convert next 4 bits
|
||||
if (c >= '0' && c <= '9') {
|
||||
c = c - '0';
|
||||
} else if (c >= 'A' && c <= 'F') {
|
||||
c = c - 'A' + 10;
|
||||
} else if (c >= 'a' && c <= 'f') {
|
||||
c = c - 'a' + 10;
|
||||
} else {
|
||||
printf("ERROR: TLS PSK not in valid hex format \r\n");
|
||||
return -1;
|
||||
}
|
||||
psk[i/2] |= c;
|
||||
}
|
||||
if (mbedtls_ssl_conf_psk(ssl_client->conf, psk, psk_len, pskIdent, strlen((char*)pskIdent)) != 0) {
|
||||
printf("ERROR: mbedtls conf psk failed! \r\n");
|
||||
}
|
||||
} else {
|
||||
mbedtls_ssl_conf_authmode(ssl_client->conf, MBEDTLS_SSL_VERIFY_NONE);
|
||||
}
|
||||
|
||||
if ((cli_cert != NULL) && (cli_key != NULL)) {
|
||||
_cli_crt = (mbedtls_x509_crt *) mbedtls_calloc( sizeof(mbedtls_x509_crt), 1);
|
||||
if (_cli_crt == NULL) {
|
||||
printf("ERROR: malloc client_crt failed! \r\n");
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
mbedtls_x509_crt_init(_cli_crt);
|
||||
|
||||
_clikey_rsa = (mbedtls_pk_context *) mbedtls_calloc( sizeof(mbedtls_pk_context), 1);
|
||||
if (_clikey_rsa == NULL) {
|
||||
printf("ERROR: malloc client_rsa failed! \r\n");
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
mbedtls_pk_init(_clikey_rsa);
|
||||
|
||||
if (mbedtls_x509_crt_parse(_cli_crt, cli_cert, strlen((char*)cli_cert)+1) != 0) {
|
||||
printf("ERROR: mbedtls x509 parse client_crt failed! \r\n");
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (mbedtls_pk_parse_key(_clikey_rsa, cli_key, strlen((char*)cli_key)+1, NULL, 0) != 0) {
|
||||
printf("ERROR: mbedtls x509 parse client_rsa failed! \r\n");
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
mbedtls_ssl_conf_own_cert(ssl_client->conf, _cli_crt, _clikey_rsa);
|
||||
}
|
||||
|
||||
if((mbedtls_ssl_setup(ssl_client->ssl, ssl_client->conf)) != 0) {
|
||||
printf("ERROR: mbedtls ssl setup failed!\r\n");
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
mbedtls_ssl_set_bio(ssl_client->ssl, &ssl_client->socket, mbedtls_net_send, mbedtls_net_recv, NULL);
|
||||
|
||||
mbedtls_ssl_set_hostname(ssl_client->ssl, SNI_hostname);
|
||||
|
||||
ret = mbedtls_ssl_handshake(ssl_client->ssl);
|
||||
if (ret < 0) {
|
||||
printf("ERROR: mbedtls ssl handshake failed: -0x%04X \r\n", -ret);
|
||||
ret = -1;
|
||||
} else {
|
||||
if (ARDUINO_MBEDTLS_DEBUG_LEVEL > 0) {
|
||||
printf("mbedTLS SSL handshake success \r\n");
|
||||
}
|
||||
}
|
||||
//mbedtls_debug_set_threshold(ARDUINO_MBEDTLS_DEBUG_LEVEL);
|
||||
}
|
||||
} while (0);
|
||||
|
||||
if (_clikey_rsa) {
|
||||
mbedtls_pk_free(_clikey_rsa);
|
||||
mbedtls_free(_clikey_rsa);
|
||||
_clikey_rsa = NULL;
|
||||
}
|
||||
|
||||
if (_cli_crt) {
|
||||
mbedtls_x509_crt_free(_cli_crt);
|
||||
mbedtls_free(_cli_crt);
|
||||
_cli_crt = NULL;
|
||||
}
|
||||
|
||||
if (cacert) {
|
||||
mbedtls_x509_crt_free(cacert);
|
||||
mbedtls_free(cacert);
|
||||
cacert = NULL;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
if (ssl_client->socket >= 0) {
|
||||
mbedtls_net_free((mbedtls_net_context *)&ssl_client->socket);
|
||||
ssl_client->socket = -1;
|
||||
}
|
||||
|
||||
if (ssl_client->ssl != NULL) {
|
||||
mbedtls_ssl_free(ssl_client->ssl);
|
||||
free(ssl_client->ssl);
|
||||
ssl_client->ssl = NULL;
|
||||
}
|
||||
if (ssl_client->conf != NULL) {
|
||||
mbedtls_ssl_config_free(ssl_client->conf);
|
||||
free(ssl_client->conf);
|
||||
ssl_client->conf = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return ssl_client->socket;
|
||||
}
|
||||
|
||||
void stop_ssl_socket(sslclient_context *ssl_client)
|
||||
{
|
||||
lwip_shutdown(ssl_client->socket, SHUT_RDWR);
|
||||
lwip_close(ssl_client->socket);
|
||||
//mbedtls_net_free((mbedtls_net_context *)&ssl_client->socket);
|
||||
ssl_client->socket = -1;
|
||||
|
||||
if (ssl_client->ssl != NULL) {
|
||||
mbedtls_ssl_free(ssl_client->ssl);
|
||||
free(ssl_client->ssl);
|
||||
ssl_client->ssl = NULL;
|
||||
}
|
||||
if (ssl_client->conf != NULL) {
|
||||
mbedtls_ssl_config_free(ssl_client->conf);
|
||||
free(ssl_client->conf);
|
||||
ssl_client->conf = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int send_ssl_data(sslclient_context *ssl_client, const uint8_t *data, uint16_t len)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
if (ssl_client->ssl != NULL) {
|
||||
ret = mbedtls_ssl_write(ssl_client->ssl, data, len);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int get_ssl_receive(sslclient_context *ssl_client, uint8_t* data, int length, int flag)
|
||||
{
|
||||
int ret = 0;
|
||||
uint8_t has_backup_recvtimeout = 0;
|
||||
int backup_recv_timeout, recv_timeout;
|
||||
socklen_t len;
|
||||
|
||||
if (ssl_client->ssl == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (flag & 0x01) {
|
||||
// peek for 10ms
|
||||
ret = lwip_getsockopt(ssl_client->socket, SOL_SOCKET, SO_RCVTIMEO, &backup_recv_timeout, &len);
|
||||
if (ret >= 0) {
|
||||
recv_timeout = 100;
|
||||
ret = lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_RCVTIMEO, &recv_timeout, sizeof(recv_timeout));
|
||||
if (ret >= 0) {
|
||||
has_backup_recvtimeout = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memset(data, 0, length);
|
||||
ret = mbedtls_ssl_read(ssl_client->ssl, data, length);
|
||||
|
||||
if ((flag & 0x01) && (has_backup_recvtimeout == 1)) {
|
||||
// restore receiving timeout
|
||||
lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_RCVTIMEO, &backup_recv_timeout, sizeof(recv_timeout));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int get_ssl_sock_errno(sslclient_context *ssl_client) {
|
||||
int so_error;
|
||||
socklen_t len = sizeof(so_error);
|
||||
lwip_getsockopt(ssl_client->socket, SOL_SOCKET, SO_ERROR, &so_error, &len);
|
||||
return so_error;
|
||||
}
|
||||
|
||||
int get_ssl_bytes_avail(sslclient_context *ssl_client) {
|
||||
if (ssl_client->ssl != NULL) {
|
||||
return mbedtls_ssl_get_bytes_avail(ssl_client->ssl);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
#ifndef ARD_SSL_H
|
||||
#define ARD_SSL_H
|
||||
|
||||
struct mbedtls_ssl_context;
|
||||
struct mbedtls_ssl_config;
|
||||
|
||||
typedef struct {
|
||||
int socket;
|
||||
int recvTimeout;
|
||||
mbedtls_ssl_context *ssl;
|
||||
mbedtls_ssl_config *conf;
|
||||
} sslclient_context;
|
||||
|
||||
int start_ssl_client(sslclient_context *ssl_client, uint32_t ipAddress, uint32_t port, unsigned char* rootCABuff, unsigned char* cli_cert, unsigned char* cli_key, unsigned char* pskIdent, unsigned char* psKey, char* SNI_hostname);
|
||||
|
||||
void stop_ssl_socket(sslclient_context *ssl_client);
|
||||
|
||||
int send_ssl_data(sslclient_context *ssl_client, const uint8_t *data, uint16_t len);
|
||||
|
||||
int get_ssl_receive(sslclient_context *ssl_client, uint8_t* data, int length, int flag);
|
||||
|
||||
int get_ssl_sock_errno(sslclient_context *ssl_client);
|
||||
|
||||
int get_ssl_bytes_avail(sslclient_context *ssl_client);
|
||||
|
||||
#endif
|
||||
@@ -1,71 +0,0 @@
|
||||
// Simple Base64 code
|
||||
// (c) Copyright 2010 MCQN Ltd.
|
||||
// Released under Apache License, version 2.0
|
||||
|
||||
#include "b64.h"
|
||||
|
||||
/* Simple test program
|
||||
#include <stdio.h>
|
||||
void main()
|
||||
{
|
||||
char* in = "amcewen";
|
||||
char out[22];
|
||||
|
||||
b64_encode(in, 15, out, 22);
|
||||
out[21] = '\0';
|
||||
|
||||
printf(out);
|
||||
}
|
||||
*/
|
||||
|
||||
int b64_encode(const unsigned char* aInput, int aInputLen, unsigned char* aOutput, int aOutputLen)
|
||||
{
|
||||
// Work out if we've got enough space to encode the input
|
||||
// Every 6 bits of input becomes a byte of output
|
||||
if (aOutputLen < (aInputLen*8)/6)
|
||||
{
|
||||
// FIXME Should we return an error here, or just the length
|
||||
return (aInputLen*8)/6;
|
||||
}
|
||||
|
||||
// If we get here we've got enough space to do the encoding
|
||||
|
||||
const char* b64_dictionary = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
if (aInputLen == 3)
|
||||
{
|
||||
aOutput[0] = b64_dictionary[aInput[0] >> 2];
|
||||
aOutput[1] = b64_dictionary[(aInput[0] & 0x3)<<4|(aInput[1]>>4)];
|
||||
aOutput[2] = b64_dictionary[(aInput[1]&0x0F)<<2|(aInput[2]>>6)];
|
||||
aOutput[3] = b64_dictionary[aInput[2]&0x3F];
|
||||
}
|
||||
else if (aInputLen == 2)
|
||||
{
|
||||
aOutput[0] = b64_dictionary[aInput[0] >> 2];
|
||||
aOutput[1] = b64_dictionary[(aInput[0] & 0x3)<<4|(aInput[1]>>4)];
|
||||
aOutput[2] = b64_dictionary[(aInput[1]&0x0F)<<2];
|
||||
aOutput[3] = '=';
|
||||
}
|
||||
else if (aInputLen == 1)
|
||||
{
|
||||
aOutput[0] = b64_dictionary[aInput[0] >> 2];
|
||||
aOutput[1] = b64_dictionary[(aInput[0] & 0x3)<<4];
|
||||
aOutput[2] = '=';
|
||||
aOutput[3] = '=';
|
||||
}
|
||||
else
|
||||
{
|
||||
// Break the input into 3-byte chunks and process each of them
|
||||
int i;
|
||||
for (i = 0; i < aInputLen/3; i++)
|
||||
{
|
||||
b64_encode(&aInput[i*3], 3, &aOutput[i*4], 4);
|
||||
}
|
||||
if (aInputLen % 3 > 0)
|
||||
{
|
||||
// It doesn't fit neatly into a 3-byte chunk, so process what's left
|
||||
b64_encode(&aInput[i*3], aInputLen % 3, &aOutput[i*4], aOutputLen - (i*4));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
#ifndef b64_h
|
||||
#define b64_h
|
||||
|
||||
int b64_encode(const unsigned char* aInput, int aInputLen, unsigned char* aOutput, int aOutputLen);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,26 +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
|
||||
*/
|
||||
|
||||
extern "C" void __cxa_pure_virtual(void) ;
|
||||
|
||||
/* We compile with nodefaultlibs, so we need to provide an error
|
||||
* handler for an empty pure virtual function */
|
||||
extern "C" void __cxa_pure_virtual(void) {
|
||||
while(1)
|
||||
;
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
#ifndef ARD_DEBUG_H
|
||||
#define ARD_DEBUG_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef DEBUG_RTL_CORE
|
||||
#define DEBUGV(...) rtl_printf(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#ifndef DEBUGV
|
||||
#define DEBUGV(...)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
void hexdump(void * addr, int len = 16);
|
||||
#else
|
||||
void hexdump(void * addr, int len);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void print_udp_pcb(void);
|
||||
void print_tcp_pcb(void);
|
||||
void DumpForOneBytes(void *addr, int cnt); // cnt max 0x70 !
|
||||
|
||||
void __panic_func(const char* file, int line, const char* func) __attribute__((noreturn));
|
||||
#define panic() __panic_func(__FILE__, __LINE__, __func__)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif//ARD_DEBUG_H
|
||||
@@ -1,116 +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 "api/itoa.h"
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"{
|
||||
#endif // __cplusplus
|
||||
|
||||
extern char* ltoa(long value, char *string, int radix)
|
||||
{
|
||||
char tmp[33];
|
||||
char *tp = tmp;
|
||||
long i;
|
||||
unsigned long v;
|
||||
int sign;
|
||||
char *sp;
|
||||
|
||||
if ( string == NULL )
|
||||
{
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
if (radix > 36 || radix <= 1)
|
||||
{
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
sign = (radix == 10 && value < 0);
|
||||
if (sign)
|
||||
{
|
||||
v = -value;
|
||||
}
|
||||
else
|
||||
{
|
||||
v = (unsigned long)value;
|
||||
}
|
||||
|
||||
while (v || tp == tmp)
|
||||
{
|
||||
i = v % radix;
|
||||
v = v / radix;
|
||||
if (i < 10)
|
||||
*tp++ = i+'0';
|
||||
else
|
||||
*tp++ = i + 'a' - 10;
|
||||
}
|
||||
|
||||
sp = string;
|
||||
|
||||
if (sign)
|
||||
*sp++ = '-';
|
||||
while (tp > tmp)
|
||||
*sp++ = *--tp;
|
||||
*sp = 0;
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
extern char* ultoa(unsigned long value, char *string, int radix)
|
||||
{
|
||||
char tmp[33];
|
||||
char *tp = tmp;
|
||||
long i;
|
||||
unsigned long v = value;
|
||||
char *sp;
|
||||
|
||||
if ( string == NULL )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (radix > 36 || radix <= 1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (v || tp == tmp)
|
||||
{
|
||||
i = v % radix;
|
||||
v = v / radix;
|
||||
if (i < 10)
|
||||
*tp++ = i+'0';
|
||||
else
|
||||
*tp++ = i + 'a' - 10;
|
||||
}
|
||||
|
||||
sp = string;
|
||||
|
||||
|
||||
while (tp > tmp)
|
||||
*sp++ = *--tp;
|
||||
*sp = 0;
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif // __cplusplus
|
||||
@@ -1,120 +0,0 @@
|
||||
#ifndef EASYWSCLIENT_H
|
||||
#define EASYWSCLIENT_H
|
||||
#include <platform/platform_stdlib.h>
|
||||
|
||||
/****************Define the debug message level*********************/
|
||||
#define DEBUG_WSCLIENT 1
|
||||
|
||||
#define WSCLIENT_LOG(level, fmt, ...) printf("\n\r[WSCLIENT %s] %s: " fmt "\n", level, __FUNCTION__, ##__VA_ARGS__)
|
||||
#if DEBUG_WSCLIENT == 2
|
||||
#define WSCLIENT_DEBUG(fmt, ...) WSCLIENT_LOG("DEBUG", fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define WSCLIENT_DEBUG(fmt, ...)
|
||||
#endif
|
||||
#if DEBUG_WSCLIENT
|
||||
#define WSCLIENT_ERROR(fmt, ...) WSCLIENT_LOG("ERROR", fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define WSCLIENT_ERROR(fmt, ...)
|
||||
#endif
|
||||
/*******************************************************************/
|
||||
|
||||
/****************Define the structures used*************************/
|
||||
typedef enum{
|
||||
CLOSING,
|
||||
CLOSED,
|
||||
CONNECTING,
|
||||
OPEN
|
||||
} readyStateValues;
|
||||
|
||||
struct wsheader_type{
|
||||
unsigned header_size;
|
||||
int fin;
|
||||
int mask;
|
||||
enum opcode_type {
|
||||
CONTINUATION = 0x0,
|
||||
TEXT_FRAME = 0x1,
|
||||
BINARY_FRAME = 0x2,
|
||||
CLOSE = 8,
|
||||
PING = 9,
|
||||
PONG = 0xa,
|
||||
} opcode;
|
||||
int N0;
|
||||
uint64_t N;
|
||||
uint8_t masking_key[4];
|
||||
};
|
||||
|
||||
struct _wsclient_context;
|
||||
struct _ssl_context;
|
||||
|
||||
struct ssl_fun_ops{
|
||||
int (*memory_set_own)( void * (*malloc_func)( size_t ),void (*free_func)( void * ) );
|
||||
int (*net_connect)( int *fd, const char *host, int port );
|
||||
int (*ssl_init)( struct _ssl_context *ssl );
|
||||
void (*ssl_set_endpoint)( struct _ssl_context *ssl, int endpoint );
|
||||
void (*ssl_set_authmode)( struct _ssl_context *ssl, int authmode );
|
||||
void (*ssl_set_rng)( struct _ssl_context *ssl,
|
||||
int (*f_rng)(void *, unsigned char *, size_t),
|
||||
void *p_rng );
|
||||
void (*ssl_set_bio)( struct _ssl_context *ssl,
|
||||
int (*f_recv)(void *, unsigned char *, size_t), void *p_recv,
|
||||
int (*f_send)(void *, const unsigned char *, size_t), void *p_send );
|
||||
int (*ssl_handshake)( struct _ssl_context *ssl );
|
||||
void (*net_close)( int fd );
|
||||
void (*ssl_free)( struct _ssl_context *ssl );
|
||||
int (*ssl_read)( struct _ssl_context *ssl, unsigned char *buf, size_t len );
|
||||
int (*ssl_write)( struct _ssl_context *ssl, const unsigned char *buf, size_t len );
|
||||
const char *(*ssl_get_ciphersuite)( const struct _ssl_context *ssl );
|
||||
int (*net_recv)( void *ctx, unsigned char *buf, size_t len );
|
||||
int (*net_send)( void *ctx, const unsigned char *buf, size_t len );
|
||||
};
|
||||
|
||||
struct ws_fun_ops{
|
||||
int (*hostname_connect)(struct _wsclient_context *wsclient);
|
||||
void (*client_close)(struct _wsclient_context *wsclient);
|
||||
int (*client_send)(struct _wsclient_context *wsclient, unsigned char *data, size_t data_len);
|
||||
int (*client_read)(struct _wsclient_context *wsclient, unsigned char *data, size_t data_len);
|
||||
struct ssl_fun_ops ssl_fun_ops;
|
||||
};
|
||||
|
||||
typedef struct _wsclient_context{
|
||||
char host[128];
|
||||
char path[128];
|
||||
char origin[200];
|
||||
int port;
|
||||
uint8_t use_ssl;
|
||||
int sockfd;
|
||||
readyStateValues readyState;
|
||||
int tx_len;
|
||||
void *ssl;
|
||||
uint8_t *txbuf;
|
||||
uint8_t *rxbuf;
|
||||
uint8_t *receivedData;
|
||||
struct ws_fun_ops fun_ops;
|
||||
}wsclient_context;
|
||||
/*******************************************************************/
|
||||
|
||||
/****************General functions used by wsclient*****************/
|
||||
void ws_get_random_bytes(void *buf, size_t len);
|
||||
void* ws_malloc(unsigned int size);
|
||||
void ws_free(void *buf);
|
||||
int ws_client_handshake(wsclient_context *wsclient);
|
||||
int ws_check_handshake(wsclient_context *wsclient);
|
||||
void ws_sendData(uint8_t type, size_t message_size, uint8_t* message, int useMask, wsclient_context *wsclient);
|
||||
/*******************************************************************/
|
||||
|
||||
/*************Functions used by wsclient without SSL****************/
|
||||
|
||||
int ws_hostname_connect(wsclient_context *wsclient);
|
||||
int ws_client_read(wsclient_context *wsclient, unsigned char *data, size_t data_len);
|
||||
int ws_client_send(wsclient_context *wsclient, unsigned char *data, size_t data_len);
|
||||
void ws_client_close(wsclient_context *wsclient);
|
||||
/*******************************************************************/
|
||||
|
||||
/***************Functions used by wsclient with SSL*****************/
|
||||
int wss_hostname_connect(wsclient_context *wsclient);
|
||||
int wss_client_read(wsclient_context *wsclient, unsigned char *data, size_t data_len);
|
||||
int wss_client_send(wsclient_context *wsclient, unsigned char *data, size_t data_len);
|
||||
void wss_client_close(wsclient_context *wsclient);
|
||||
/*******************************************************************/
|
||||
|
||||
#endif
|
||||
@@ -1,122 +0,0 @@
|
||||
#include "Arduino.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "lwip_netconf.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/tcpip.h"
|
||||
#include "lwip/err.h"
|
||||
//#include "lwip/mem.h"
|
||||
#include "lwip/tcp.h"
|
||||
#include "lwip/tcp_impl.h"
|
||||
#include "lwip/udp.h"
|
||||
|
||||
/* Get one byte from the 4-byte address */
|
||||
#define ip4_addr1(ipaddr) (((u8_t*)(ipaddr))[0])
|
||||
#define ip4_addr2(ipaddr) (((u8_t*)(ipaddr))[1])
|
||||
#define ip4_addr3(ipaddr) (((u8_t*)(ipaddr))[2])
|
||||
#define ip4_addr4(ipaddr) (((u8_t*)(ipaddr))[3])
|
||||
/* These are cast to u16_t, with the intent that they are often arguments
|
||||
* to printf using the U16_F format from cc.h. */
|
||||
#define ip4_addr1_16(ipaddr) ((u16_t)ip4_addr1(ipaddr))
|
||||
#define ip4_addr2_16(ipaddr) ((u16_t)ip4_addr2(ipaddr))
|
||||
#define ip4_addr3_16(ipaddr) ((u16_t)ip4_addr3(ipaddr))
|
||||
#define ip4_addr4_16(ipaddr) ((u16_t)ip4_addr4(ipaddr))
|
||||
|
||||
#define IP2STR(ipaddr) ip4_addr1_16(ipaddr), \
|
||||
ip4_addr2_16(ipaddr), \
|
||||
ip4_addr3_16(ipaddr), \
|
||||
ip4_addr4_16(ipaddr)
|
||||
|
||||
#define IPSTR "%d.%d.%d.%d"
|
||||
|
||||
extern const char * const tcp_state_str[];
|
||||
/*
|
||||
static const char * const tcp_state_str[] = {
|
||||
"CLOSED",
|
||||
"LISTEN",
|
||||
"SYN_SENT",
|
||||
"SYN_RCVD",
|
||||
"ESTABLISHED",
|
||||
"FIN_WAIT_1",
|
||||
"FIN_WAIT_2",
|
||||
"CLOSE_WAIT",
|
||||
"CLOSING",
|
||||
"LAST_ACK",
|
||||
"TIME_WAIT"
|
||||
};
|
||||
*/
|
||||
/******************************************************************************
|
||||
* FunctionName : debug
|
||||
* Parameters :
|
||||
* Returns :
|
||||
*******************************************************************************/
|
||||
void print_udp_pcb(void)
|
||||
{
|
||||
struct udp_pcb *pcb;
|
||||
bool prt_none = true;
|
||||
rtl_printf("UDP pcbs:\n");
|
||||
for(pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {
|
||||
rtl_printf("flg:%02x\t" IPSTR ":%d\t" IPSTR ":%d\trecv:%p\n", pcb->flags, IP2STR(&pcb->local_ip), pcb->local_port, IP2STR(&pcb->remote_ip), pcb->remote_port, pcb->recv );
|
||||
prt_none = false;
|
||||
}
|
||||
if(prt_none) rtl_printf("none\n");
|
||||
}
|
||||
/******************************************************************************
|
||||
* FunctionName : debug
|
||||
* Parameters :
|
||||
* Returns :
|
||||
*******************************************************************************/
|
||||
void print_tcp_pcb(void)
|
||||
{
|
||||
struct tcp_pcb *pcb;
|
||||
rtl_printf("Active PCB states:\n");
|
||||
bool prt_none = true;
|
||||
for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
|
||||
rtl_printf("Port %d|%d\tflg:%02x\ttmr:%p\t%s\n", pcb->local_port, pcb->remote_port, pcb->flags, pcb->tmr, tcp_state_str[pcb->state]);
|
||||
prt_none = false;
|
||||
}
|
||||
if(prt_none) rtl_printf("none\n");
|
||||
rtl_printf("Listen PCB states:\n");
|
||||
prt_none = true;
|
||||
for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next) {
|
||||
rtl_printf("Port %d|%d\tflg:%02x\ttmr:%p\t%s\n", pcb->local_port, pcb->remote_port, pcb->flags, pcb->tmr, tcp_state_str[pcb->state]);
|
||||
prt_none = false;
|
||||
}
|
||||
if(prt_none) rtl_printf("none\n");
|
||||
rtl_printf("TIME-WAIT PCB states:\n");
|
||||
prt_none = true;
|
||||
for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
|
||||
rtl_printf("Port %d|%d\tflg:%02x\ttmr:%p\t%s\n", pcb->local_port, pcb->remote_port, pcb->flags, pcb->tmr, tcp_state_str[pcb->state]);
|
||||
prt_none = false;
|
||||
}
|
||||
if(prt_none) rtl_printf("none\n");
|
||||
}
|
||||
/******************************************************************************
|
||||
* FunctionName : debug
|
||||
* Parameters :
|
||||
* Returns :
|
||||
*******************************************************************************/
|
||||
#if 0
|
||||
//------------------------------------------------------------------------------
|
||||
void chow_tcp_connection_info(void)
|
||||
{
|
||||
rtl_printf("TCP Server connections:\n");
|
||||
TCP_SERV_CFG * p;
|
||||
TCP_SERV_CONN * ts_conn;
|
||||
bool prt_none = true;
|
||||
for(p = phcfg; p != NULL; p = p->next) {
|
||||
for(ts_conn = p->conn_links; ts_conn != NULL; ts_conn = ts_conn->next) {
|
||||
rtl_printf("%d "IPSTR ":%d %s\n", p->port, ts_conn->remote_ip.b[0], ts_conn->remote_ip.b[1], ts_conn->remote_ip.b[2], ts_conn->remote_ip.b[3], ts_conn->remote_port, tspsrv_srvconn_state_msg(ts_conn->state) );
|
||||
prt_none = false;
|
||||
}
|
||||
}
|
||||
if(prt_none) rtl_printf("none\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -18,87 +18,62 @@
|
||||
*/
|
||||
|
||||
#define ARDUINO_MAIN
|
||||
#include "Arduino.h"
|
||||
#include "cmsis_os.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#include "rtl8710b.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "diag.h"
|
||||
extern void HalCpuClkConfig(u8 CpuType);
|
||||
extern void SystemCoreClockUpdate(void);
|
||||
extern void En32KCalibration(void);
|
||||
extern int tcm_heap_freeSpace(void);
|
||||
extern void console_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
osThreadId main_tid = 0;
|
||||
#include <Arduino.h>
|
||||
#include <cmsis_os.h>
|
||||
|
||||
// Weak empty variant initialization function.
|
||||
// May be redefined by variant files.
|
||||
void initVariant() __attribute__((weak));
|
||||
void initVariant() { }
|
||||
|
||||
void initVariant() {}
|
||||
|
||||
// Initialize C library
|
||||
extern "C" void __libc_init_array(void);
|
||||
|
||||
/*
|
||||
* \brief Init Random()
|
||||
* \note Use in void __low_level_init(void) { Init_Rand(); } !
|
||||
*/
|
||||
void Init_Rand(void)
|
||||
{
|
||||
extern u32 _rand_z1, _rand_z2, _rand_z3, _rand_z4, _rand_first;
|
||||
u32 *p = (u32 *)0x1FFFFF00;
|
||||
while(p < (u32 *)0x20000000) _rand_z1 ^= *p++;
|
||||
_rand_z1 ^= (*((u32 *)0x40002018) << 24) ^ (*((u32 *)0x40002118) << 16) ^ (*((u32 *)0x40002218) << 8) ^ *((u32 *)0x40002318);
|
||||
_rand_z2 = ((_rand_z1 & 0x007F00FF) << 7) ^ ((_rand_z1 & 0x0F80FF00) >> 8);
|
||||
_rand_z3 = ((_rand_z2 & 0x007F00FF) << 7) ^ ((_rand_z2 & 0x0F80FF00) >> 8);
|
||||
_rand_z4 = ((_rand_z3 & 0x007F00FF) << 7) ^ ((_rand_z3 & 0x0F80FF00) >> 8);
|
||||
_rand_first = 1;
|
||||
osThreadId main_tid = 0;
|
||||
|
||||
void main_task(const void *arg) {
|
||||
setup();
|
||||
|
||||
for (;;) {
|
||||
loop();
|
||||
if (serialEventRun)
|
||||
serialEventRun();
|
||||
yield();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* \brief handle sketch
|
||||
*/
|
||||
void main_task( void const *arg )
|
||||
{
|
||||
setup();
|
||||
int main(void) {
|
||||
LT_BANNER();
|
||||
init();
|
||||
|
||||
for (;;)
|
||||
{
|
||||
loop();
|
||||
if (serialEventRun) serialEventRun();
|
||||
yield();
|
||||
}
|
||||
__libc_init_array();
|
||||
|
||||
initVariant();
|
||||
|
||||
osThreadDef(main_task, osPriorityRealtime, 1, 4096 * 4);
|
||||
main_tid = osThreadCreate(osThread(main_task), NULL);
|
||||
|
||||
osKernelStart();
|
||||
|
||||
while (1)
|
||||
;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void serialEvent() __attribute__((weak));
|
||||
bool Serial_available() __attribute__((weak));
|
||||
|
||||
/*
|
||||
* \brief Main entry point of Arduino application
|
||||
*/
|
||||
int main( void )
|
||||
{
|
||||
LT_BANNER();
|
||||
init();
|
||||
|
||||
__libc_init_array();
|
||||
|
||||
initVariant();
|
||||
|
||||
osThreadDef(main_task, osPriorityRealtime, 1, 4096*4);
|
||||
main_tid = osThreadCreate(osThread (main_task), NULL);
|
||||
|
||||
osKernelStart();
|
||||
|
||||
while(1);
|
||||
|
||||
return 0;
|
||||
void serialEventRun(void) {
|
||||
if (Serial_available && serialEvent && Serial_available())
|
||||
serialEvent();
|
||||
}
|
||||
|
||||
void wait_for_debug() {
|
||||
while (((CoreDebug->DHCSR) & CoreDebug_DHCSR_C_DEBUGEN_Msk) == 0) {
|
||||
asm("nop");
|
||||
}
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
#ifndef __NETBIOS_H__
|
||||
#define __NETBIOS_H__
|
||||
|
||||
/** default port number for "NetBIOS Name service */
|
||||
#define NETBIOS_PORT 137
|
||||
|
||||
/** size of a NetBIOS name */
|
||||
#define NETBIOS_NAME_LEN 16
|
||||
|
||||
#ifndef NET_IF_NUM
|
||||
#define NET_IF_NUM 2
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern char netbios_name[NET_IF_NUM][NETBIOS_NAME_LEN + 1]; // default netifs/interfacenum: 0 - SoftAP, 1 - Station, 2 - Ethernet
|
||||
|
||||
// struct udp_pcb * netbios_pcb(void);
|
||||
void netbios_init(void);
|
||||
bool netbios_set_name(unsigned char interfacenum, char * name); // default netifs/interfacenum: 0 - SoftAP, 1 - Station, 2 - Ethernet
|
||||
bool netbios_off(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __NETBIOS_H__ */
|
||||
@@ -1,215 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2014 Arduino. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#include <diag.h>
|
||||
|
||||
extern void *pvPortMalloc( size_t xWantedSize );
|
||||
extern void *os_zalloc( size_t xWantedSize );
|
||||
extern void vPortFree( void *pv );
|
||||
extern void *pvPortReAlloc( void *pv, size_t xWantedSize );
|
||||
extern size_t xPortGetFreeHeapSize( void );
|
||||
extern size_t xPortGetMinimumEverFreeHeapSize( void );
|
||||
|
||||
extern void *tcm_heap_malloc(int size);
|
||||
extern void *tcm_heap_calloc(int size);
|
||||
extern void tcm_heap_free(void * mem);
|
||||
extern void tcm_heap_dump(void);
|
||||
extern int tcm_heap_freeSpace(void);
|
||||
|
||||
|
||||
__attribute__((noreturn)) void __panic_func(const char* file, int line, const char* func)
|
||||
{
|
||||
DiagPrintf("\r\nPanic: %s, line: %d, %s\r\n");
|
||||
while(1);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
void hexdump(void * ptr, int cnt)
|
||||
{
|
||||
char * p = (char *) ptr;
|
||||
int c = cnt;
|
||||
while(c > 64) {
|
||||
DumpForOneBytes((void *)p, 64);
|
||||
p += 64;
|
||||
c -= 64;
|
||||
}
|
||||
if(c != 0) DumpForOneBytes((void *)p, c);
|
||||
}
|
||||
|
||||
void debug_on(void)
|
||||
{
|
||||
ConfigDebugErr = -1;
|
||||
ConfigDebugInfo = -1;
|
||||
ConfigDebugWarn = -1;
|
||||
CfgSysDebugErr = -1;
|
||||
CfgSysDebugInfo = -1;
|
||||
CfgSysDebugWarn = -1;
|
||||
}
|
||||
|
||||
void sys_info(void) {
|
||||
rtl_printf("\r\nCLK CPU\t\t%d Hz\r\nRAM heap\t%d bytes\r\nTCM heap\t%d bytes\r\n",
|
||||
HalGetCpuClk(), xPortGetFreeHeapSize(), tcm_heap_freeSpace());
|
||||
}
|
||||
|
||||
|
||||
/* void * malloc(size_t size)
|
||||
{
|
||||
void * ret;
|
||||
if((ret = pvPortMalloc(size)) == NULL)
|
||||
ret = tcm_heap_malloc(size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void * zalloc(size_t size)
|
||||
{
|
||||
void * ret;
|
||||
if((ret = pvPortMalloc(size)) == NULL)
|
||||
ret = tcm_heap_calloc(size);
|
||||
else memset(ret, 0, size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *calloc(size_t count, size_t size)
|
||||
{
|
||||
return zalloc(count * size);
|
||||
} */
|
||||
|
||||
void free(void *pv)
|
||||
{
|
||||
vPortFree(pv);
|
||||
}
|
||||
|
||||
void * realloc(void *pv, size_t size)
|
||||
{
|
||||
return pvPortReAlloc(pv, size);
|
||||
}
|
||||
|
||||
/* void *operator new(size_t size)
|
||||
{
|
||||
void * ret;
|
||||
if((ret = zalloc(size)) == NULL) {
|
||||
DiagPrintf("\r\nMEM error!\r\n");
|
||||
while(1);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *operator new[](size_t size)
|
||||
{
|
||||
void * ret;
|
||||
if((ret = zalloc(size)) == NULL) {
|
||||
DiagPrintf("\r\nMEM error!\r\n");
|
||||
while(1);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void operator delete(void * ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void operator delete[](void * ptr)
|
||||
{
|
||||
free(ptr);
|
||||
} */
|
||||
|
||||
/*
|
||||
extern "C" void __cxa_pure_virtual(void) __attribute__ ((__noreturn__));
|
||||
extern "C" void __cxa_deleted_virtual(void) __attribute__ ((__noreturn__));
|
||||
|
||||
void __cxa_pure_virtual(void)
|
||||
{
|
||||
panic();
|
||||
}
|
||||
|
||||
void __cxa_deleted_virtual(void)
|
||||
{
|
||||
panic();
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
uint8_t guard;
|
||||
uint8_t ps;
|
||||
} guard_t;
|
||||
|
||||
extern "C" int __cxa_guard_acquire(__guard* pg)
|
||||
{
|
||||
uint8_t ps = xt_rsil(15);
|
||||
if (reinterpret_cast<guard_t*>(pg)->guard) {
|
||||
xt_wsr_ps(ps);
|
||||
return 0;
|
||||
}
|
||||
reinterpret_cast<guard_t*>(pg)->ps = ps;
|
||||
return 1;
|
||||
}
|
||||
|
||||
extern "C" void __cxa_guard_release(__guard* pg)
|
||||
{
|
||||
reinterpret_cast<guard_t*>(pg)->guard = 1;
|
||||
xt_wsr_ps(reinterpret_cast<guard_t*>(pg)->ps);
|
||||
}
|
||||
|
||||
extern "C" void __cxa_guard_abort(__guard* pg)
|
||||
{
|
||||
xt_wsr_ps(reinterpret_cast<guard_t*>(pg)->ps);
|
||||
}
|
||||
|
||||
|
||||
namespace std
|
||||
{
|
||||
void __throw_bad_function_call()
|
||||
{
|
||||
panic();
|
||||
}
|
||||
|
||||
void __throw_length_error(char const*)
|
||||
{
|
||||
panic();
|
||||
}
|
||||
|
||||
void __throw_bad_alloc()
|
||||
{
|
||||
panic();
|
||||
}
|
||||
|
||||
void __throw_logic_error(const char* str)
|
||||
{
|
||||
panic();
|
||||
}
|
||||
|
||||
void __throw_out_of_range(const char* str)
|
||||
{
|
||||
panic();
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
53
arduino/realtek-ambz/cores/arduino/sdk_extern.h
Normal file
53
arduino/realtek-ambz/cores/arduino/sdk_extern.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-06. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// disable typedef in basic_types.h
|
||||
#define boolean boolean_rtl
|
||||
|
||||
#include <strproc.h> // define string macros first
|
||||
#undef isdigit // then remove them, as they conflict
|
||||
#undef islower // with ctype.h macros
|
||||
#undef isprint
|
||||
#undef isspace
|
||||
#undef isxdigit
|
||||
#undef strtol
|
||||
#undef strtoul
|
||||
|
||||
#include <ameba_soc.h>
|
||||
#include <gpio_api.h>
|
||||
#include <main.h>
|
||||
#include <rand.h>
|
||||
#include <rt_lib_rom.h>
|
||||
#include <rtl_lib.h>
|
||||
#include <wait_api.h>
|
||||
|
||||
// remove previously defined workaround
|
||||
#undef boolean
|
||||
|
||||
// stdio.h
|
||||
#define printf rtl_printf
|
||||
#define sprintf rtl_sprintf
|
||||
|
||||
// moved from syscalls.h
|
||||
#define _close __rtl_close
|
||||
#define _fstat __rtl_fstat
|
||||
#define _isatty __rtl_isatty
|
||||
#define _lseek __rtl_lseek
|
||||
#define _open __rtl_open
|
||||
#define _read __rtl_read
|
||||
#define _write __rtl_write
|
||||
#define _sbrk __rtl_sbrk
|
||||
|
||||
#define delay_us wait_us
|
||||
|
||||
extern void wait_us(int us);
|
||||
extern int LOGUART_SetBaud(uint32_t BaudRate); // from fixups/log_uart.c
|
||||
extern void DumpForOneBytes(void *addr, int cnt); // cnt max 0x70!
|
||||
extern void SystemCoreClockUpdate(void);
|
||||
|
||||
extern int _sscanf_patch(const char *buf, const char *fmt, ...);
|
||||
16
arduino/realtek-ambz/cores/arduino/sdk_mem.c
Normal file
16
arduino/realtek-ambz/cores/arduino/sdk_mem.c
Normal file
@@ -0,0 +1,16 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-06. */
|
||||
|
||||
#include "sdk_mem.h"
|
||||
|
||||
#include <Arduino.h> // for memset
|
||||
|
||||
void *pvPortZalloc(size_t size) {
|
||||
void *pvReturn = pvPortMalloc(size);
|
||||
if (pvReturn)
|
||||
memset(pvReturn, 0, size);
|
||||
return pvReturn;
|
||||
}
|
||||
|
||||
void *pvPortCalloc(size_t nmemb, size_t size) {
|
||||
return pvPortZalloc(nmemb * size);
|
||||
}
|
||||
21
arduino/realtek-ambz/cores/arduino/sdk_mem.h
Normal file
21
arduino/realtek-ambz/cores/arduino/sdk_mem.h
Normal file
@@ -0,0 +1,21 @@
|
||||
/* Copyright (c) Kuba Szczodrzyński 2022-05-06. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
// provide extern functions directly, as callers
|
||||
// generally don't expect needing to include malloc()
|
||||
extern void *pvPortMalloc(size_t xWantedSize);
|
||||
extern void *pvPortZalloc(size_t size);
|
||||
extern void *pvPortCalloc(size_t nmemb, size_t size);
|
||||
extern void *pvPortReAlloc(void *pv, size_t xWantedSize);
|
||||
extern void vPortFree(void *pv);
|
||||
|
||||
#define malloc pvPortMalloc
|
||||
#define zalloc pvPortZalloc
|
||||
#define calloc pvPortCalloc
|
||||
#define realloc pvPortReAlloc
|
||||
#define free vPortFree
|
||||
|
||||
#define LT_HEAP_FUNC xPortGetFreeHeapSize
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user