21 Commits

Author SHA1 Message Date
Kuba Szczodrzyński
1ed0000819 [release] v1.4.1
Some checks failed
Release / Run Clang lint (push) Has been cancelled
Release / Publish PlatformIO platform (push) Has been cancelled
Release / Publish GitHub release (push) Has been cancelled
2023-09-22 17:54:18 +02:00
Mike La Spina
3b79636d00 [libs] Fix SerialClass available() return value (#173)
Co-authored-by: descipher <120155735+GelidusResearch@users.noreply.github.com>
2023-09-21 17:19:51 +02:00
Kuba Szczodrzyński
5a4b932a37 [release] v1.4.0
Some checks failed
Release / Run Clang lint (push) Has been cancelled
Release / Publish PlatformIO platform (push) Has been cancelled
Release / Publish GitHub release (push) Has been cancelled
2023-09-10 19:37:52 +02:00
Kuba Szczodrzyński
dd2ae149ad [github] Move repository to libretiny-eu organization 2023-09-10 19:31:57 +02:00
Kuba Szczodrzyński
0f5d0a8889 [platform] Install ltchiptool in separate virtual environment (#166)
* [platform] Install ltchiptool in separate virtual environment

* [platform] Fix f-string syntax, set LibreTiny path in ltchiptool

* [platform] Fix venv site-packages path

* [platform] Fix installing pip without ensurepip

* [platform] Install binary dependencies only
2023-09-10 19:23:27 +02:00
Kuba Szczodrzyński
3750ae6953 [docs] Fix flashing redirect links 2023-09-02 15:20:08 +02:00
Kuba Szczodrzyński
5be993f9eb [docs] Add various redirect links for ESPHome docs 2023-09-02 15:12:12 +02:00
Kuba Szczodrzyński
57c43ce515 [libs] Fix possible MD5 memory leak in Update 2023-08-30 11:35:11 +02:00
Kuba Szczodrzyński
159ffa76fd [release] v1.3.0
Some checks failed
Release / Run Clang lint (push) Has been cancelled
Release / Publish PlatformIO platform (push) Has been cancelled
Release / Publish GitHub release (push) Has been cancelled
2023-08-29 19:21:09 +02:00
Kuba Szczodrzyński
1ac3d30d84 [libs] Implement Update MD5 2023-08-29 19:19:28 +02:00
Kuba Szczodrzyński
631ef6ba59 [github] Reuse GitHub workflows 2023-08-29 14:39:39 +02:00
Kuba Szczodrzyński
27393e47c3 [beken-72xx] Initialize UART to fix deep sleep 2023-08-23 16:08:03 +02:00
Péter Sárközi
bd47772c04 [beken-72xx] Fix GPIO deep sleep wakeup edge (#159)
Manufacturer docs: https://docs-bekencorp-com.translate.goog/sdk_3.0.x/bk7238/html/developer-guide/power_save/sleep_test.html?_x_tr_sl=auto&_x_tr_tl=en&_x_tr_hl=hu&_x_tr_pto=wapp

Discussion: https://github.com/libretiny-eu/libretiny-esphome/pull/11
2023-08-23 16:06:55 +02:00
Kuba Szczodrzyński
f3871388ce [docs] Restore feature support table 2023-08-18 13:47:06 +02:00
Ivan Kravets
62874bebf4 [misc] Fix PlatformIO repository URL (#157) 2023-08-17 19:23:10 +02:00
Kuba Szczodrzyński
2ca368305c [release] v1.2.1
Some checks failed
Lint check / Lint with clang-format (push) Has been cancelled
Lint check / Lint with black (push) Has been cancelled
PlatformIO Publish / publish (push) Has been cancelled
2023-08-17 19:04:50 +02:00
Kuba Szczodrzyński
f697ae6f11 [docs] Add migration to OpenBeken guide 2023-08-17 18:38:04 +02:00
Kuba Szczodrzyński
ef6dd35977 [docs] Rewrite flashing guides 2023-08-17 17:17:10 +02:00
Hajo Noerenberg
ccf21b4eab [realtek-ambz] Enable Mbed-TLS for MD5 hashing, remove Polar SSL (#156)
* Enable Mbed-TLS, remove Polar SSL

* Reformat lt_defs.h

---------

Co-authored-by: Kuba Szczodrzyński <kuba@szczodrzynski.pl>
2023-08-17 15:20:02 +02:00
Kuba Szczodrzyński
e99c6124e7 [docs] Add video guide link, use ready Docker images 2023-07-13 21:19:04 +02:00
Kuba Szczodrzyński
5721bd74d7 [docs] Update LibreTiny ESPHome component naming 2023-07-13 20:41:21 +02:00
66 changed files with 1031 additions and 575 deletions

View File

@@ -1,35 +0,0 @@
name: Lint check
on: [push, pull_request]
jobs:
lint-clang-format:
name: Lint with clang-format
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Check code with clang-format
uses: jidicula/clang-format-action@v4.5.0
with:
clang-format-version: "14"
lint-black:
name: Lint with black
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: "3.9"
- name: Install test dependencies
uses: BSFishy/pip-action@v1
with:
packages: |
black
isort
- name: Check code with black
run: black --check .
- name: Check code with isort
run: isort --profile black . --check-only

View File

@@ -1,46 +0,0 @@
name: PlatformIO Publish
on:
push:
tags:
- v*.*.*
jobs:
publish:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Cache pip
uses: actions/cache@v2
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Cache PlatformIO
uses: actions/cache@v2
with:
path: ~/.platformio
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
- name: Set up Python
uses: actions/setup-python@v2
- name: Install PlatformIO
run: |
python -m pip install --upgrade pip
pip install --upgrade platformio
- name: Publish PlatformIO package
run: pio package publish --non-interactive
env:
CI: true
PLATFORMIO_AUTH_TOKEN: ${{ secrets.PLATFORMIO_AUTH_TOKEN }}
- name: Get latest version
id: get_version
run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//}
- name: Release on GitHub
uses: softprops/action-gh-release@v1
with:
name: ${{ steps.get_version.outputs.VERSION }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

12
.github/workflows/push-dev.yml vendored Normal file
View File

@@ -0,0 +1,12 @@
name: Push (dev), Pull Request
on:
push:
branches: ["**"]
pull_request:
jobs:
lint-clang:
name: Run Clang lint
uses: kuba2k2/kuba2k2/.github/workflows/lint-clang.yml@master
lint-python:
name: Run Python lint
uses: kuba2k2/kuba2k2/.github/workflows/lint-python.yml@master

View File

@@ -1,10 +1,8 @@
name: Deploy docs on GitHub Pages
name: Push (master)
on:
push:
branches:
- master
branches: ["master"]
workflow_dispatch:
jobs:
docs:
name: Deploy docs

22
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,22 @@
name: Release
on:
push:
tags: ["v*.*.*"]
jobs:
lint-clang:
name: Run Clang lint
uses: kuba2k2/kuba2k2/.github/workflows/lint-clang.yml@master
publish-pio-platform:
name: Publish PlatformIO platform
needs:
- lint-clang
uses: kuba2k2/kuba2k2/.github/workflows/publish-pio-platform.yml@master
secrets:
PLATFORMIO_AUTH_TOKEN: ${{ secrets.PLATFORMIO_AUTH_TOKEN }}
gh-release:
name: Publish GitHub release
needs:
- publish-pio-platform
uses: kuba2k2/kuba2k2/.github/workflows/gh-release.yml@master
permissions:
contents: write

View File

@@ -1,9 +1,11 @@
# LibreTiny
<small>(formerly LibreTuya)</small>
<div align="center" markdown>
[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/kuba2k2/libretiny/Deploy%20docs%20on%20GitHub%20Pages?label=docs&logo=markdown)](https://kuba2k2.github.io/libretiny/)
![GitHub last commit](https://img.shields.io/github/last-commit/kuba2k2/libretiny?logo=github)
[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/libretiny-eu/libretiny/push-master.yml?label=docs&logo=markdown)](https://docs.libretiny.eu/)
![GitHub last commit](https://img.shields.io/github/last-commit/libretiny-eu/libretiny?logo=github)
[![Code style: clang-format](https://img.shields.io/badge/code%20style-clang--format-purple.svg)](.clang-format)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
@@ -16,13 +18,7 @@
</div>
## LibreTuya is now LibreTiny! 🎉
We have [renamed the project](https://github.com/kuba2k2/libretiny/issues/92) to LibreTiny, also marking the very first v1.0.0 release, along with a huge structure refactor. While some care has been taken to ensure that things don't break, you may still need to update some references in your code to use the new name.
---
PlatformIO development platform for IoT modules manufactured by Tuya Inc.
PlatformIO development platform for BK7231 and RTL8710 IoT chips.
The main goal of this project is to provide a usable build environment for IoT developers. While also providing vendor SDKs as PlatformIO cores,
the project focuses on developing working Arduino-compatible cores for supported families. The cores are inspired by Espressif's official core for ESP32,
@@ -32,62 +28,11 @@ which should make it easier to port/run existing ESP apps on less-common, unsupp
**Note:** this project is work-in-progress.
## Usage
<div align="center" markdown>
1. [Install PlatformIO](https://platformio.org/platformio-ide)
2. `platformio platform install -f https://github.com/kuba2k2/libretiny`
3. Create a project, build it and upload!
4. See the [docs](https://docs.libretiny.eu/) for any questions/problems.
## [⭐ Getting started ⭐](https://docs.libretiny.eu/docs/getting-started/)
<!--
## Arduino Core support status
Note: this list will probably change with each functionality update.
&nbsp; | `realtek-ambz` | `beken-72xx`
--------------------|----------------|-------------
Core functions | ✔️ | ✔️
GPIO/PWM/IRQ | ✔️/✔️/✔️ | ✔️/✔️/✔️
Analog input (ADC) | ✔️ | ✔️
Serial | ✔️ | ✔️
Serial (extra) | 0, 1, 2 | 1, 2
Flash I/O | ✔️ | ✔️
**CORE LIBRARIES** | |
SoftwareSerial | ✔️ | ❌
SPI | ❌ | ❌
Wire | ❗ | ❌
**OTHER LIBRARIES** | |
Wi-Fi STA/AP/Mixed | ✔️ | ✔️
Wi-Fi Events | ✔️ | ✔️
TCP Client (SSL) | ✔️ (✔️) | ✔️ (❗)
TCP Server | ✔️ | ✔️
IPv6 | ❌ | ❌
HTTP Client (SSL) | ✔️ (✔️) | ❓
HTTP Server | ✔️ | ✔️
NVS / Preferences | ✔️ | ✔️
SPIFFS | ❌ | ❌
BLE | - | ❌
NTP | ✔️ | ✔️
OTA | ✔️ | ✔️
MDNS | ✔️ | ✔️
MQTT | ✅ | ❌
SD | ❌ | ❌
Symbols:
- ✔️ working
- ✅ tested, external library
- ❓ untested
- ❗ broken
- ❌ not implemented (yet?)
- \- not applicable
Names:
- Core functions - stuff like delay(), millis(), yield(), etc.
- **CORE LIBRARIES** - included normally in all Arduino cores
- **OTHER LIBRARIES** - included in ESP32 core or downloadable
-->
</div>
## License

View File

@@ -1,11 +1,15 @@
* [Home](README.md)
* [](SUMMARY.md)
* [😊 Getting started](docs/getting-started/README.md)
* [➡️ Info on accessing GPIOs](docs/getting-started/gpio.md)
* [](SUMMARY.md)
* [📺 Cloudcutter & ESPHome video guide](https://www.youtube.com/watch?v=sSj8f-HCHQ0)
* [💡 ESPHome setup guide](docs/projects/esphome.md)
* [🛖 ESPHome Hassio Add-On](https://github.com/libretiny-eu/esphome-hass-addon/pkgs/container/libretiny-esphome-hassio)
* [](SUMMARY.md)
* [📲 Flashing/dumping guide](docs/flashing/)
* [🔌 How to connect the chip in download mode?](docs/flashing/chip-connection/)
* [💻 Supported chips](docs/status/supported.md)
* [🔌 How to flash/enter download mode?](docs/platform/)
* [](SUMMARY.md)
* [💻 Chips, boards, features](docs/status/supported.md)
* [All boards](boards/)
* [](SUMMARY.md)
* 🍪 Chip family docs & info

View File

@@ -41,8 +41,7 @@
}
},
"links": {
"General info": "../../docs/platform/beken-72xx/README.md",
"Flashing guide": "../../docs/platform/beken-72xx/flashing.md"
"Info & flashing guide": "../../docs/platform/beken-72xx/README.md"
},
"extra": [
"Bootloader and app partitions contain CRC16 sums every 32 bytes. That results in the actual flash offsets/sizes not aligned to sector boundaries. To simplify calculations, the values shown in the table (extracted from bootloader's partition table) were aligned to 4096 bytes."

View File

@@ -45,8 +45,7 @@
}
},
"links": {
"General info": "../../docs/platform/realtek-amb/README.md",
"Flashing guide": "../../docs/platform/realtek-ambz/flashing.md",
"Info & flashing guide": "../../docs/platform/realtek-ambz/README.md",
"Debugging": "../../docs/platform/realtek-ambz/debugging.md"
}
}

View File

@@ -18,7 +18,7 @@
"extra": [
"## Information",
"This is a generic board definition for RTL8710BX with 4 MiB of flash. It has a bigger application partition size (980 KiB). The used bootloader is also different from the standard Tuya one.",
"It can be found in [Ezviz T31 smart plug](https://www.ezviz.com/product/T31/2021) - bare chip soldered onto the manufacturer-made PCB. The plug is not Tuya/SmartLife-compatible and has a 25Q32CSIG flash chip. Refer to [libretiny#23](https://github.com/kuba2k2/libretiny/issues/23) for photos and more information.",
"It can be found in [Ezviz T31 smart plug](https://www.ezviz.com/product/T31/2021) - bare chip soldered onto the manufacturer-made PCB. The plug is not Tuya/SmartLife-compatible and has a 25Q32CSIG flash chip. Refer to [libretiny#23](https://github.com/libretiny-eu/libretiny/issues/23) for photos and more information.",
"Note that stock firmware seems to use smaller app images (0x80000 / 512 KiB). After 0x180000 some product-test data and device logs can be found. Because the OTA2 offset is 0x100000, the board definition was configured to use all available space."
]
},

View File

@@ -17,6 +17,13 @@ env: Environment = DefaultEnvironment()
platform: PlatformBase = env.PioPlatform()
board: PlatformBoardConfig = env.BoardConfig()
python_deps = {
"ltchiptool": ">=4.5.1,<5.0",
}
env.SConscript("python-venv.py", exports="env")
env.ConfigurePythonVenv()
env.InstallPythonDependencies(python_deps)
# Utilities
env.SConscript("utils/config.py", exports="env")
env.SConscript("utils/cores.py", exports="env")
@@ -24,7 +31,7 @@ env.SConscript("utils/env.py", exports="env")
env.SConscript("utils/flash.py", exports="env")
env.SConscript("utils/libs-external.py", exports="env")
env.SConscript("utils/libs-queue.py", exports="env")
env.SConscript("utils/ltchiptool.py", exports="env")
env.SConscript("utils/ltchiptool-util.py", exports="env")
# Firmware name
if env.get("PROGNAME", "program") == "program":

122
builder/python-venv.py Normal file
View File

@@ -0,0 +1,122 @@
# Copyright (c) Kuba Szczodrzyński 2023-09-07.
import json
import site
import subprocess
import sys
from pathlib import Path
import semantic_version
from platformio.compat import IS_WINDOWS
from platformio.package.version import pepver_to_semver
from platformio.platform.base import PlatformBase
from SCons.Script import DefaultEnvironment, Environment
env: Environment = DefaultEnvironment()
platform: PlatformBase = env.PioPlatform()
# code borrowed and modified from espressif32/builder/frameworks/espidf.py
def env_configure_python_venv(env: Environment):
venv_path = Path(env.subst("${PROJECT_CORE_DIR}"), "penv", ".libretiny")
pip_path = venv_path.joinpath(
"Scripts" if IS_WINDOWS else "bin",
"pip" + (".exe" if IS_WINDOWS else ""),
)
python_path = venv_path.joinpath(
"Scripts" if IS_WINDOWS else "bin",
"python" + (".exe" if IS_WINDOWS else ""),
)
site_path = venv_path.joinpath(
"Lib" if IS_WINDOWS else "lib",
"." if IS_WINDOWS else f"python{sys.version_info[0]}.{sys.version_info[1]}",
"site-packages",
)
if not pip_path.is_file():
# Use the built-in PlatformIO Python to create a standalone virtual env
result = env.Execute(
env.VerboseAction(
f'"$PYTHONEXE" -m venv --clear "{venv_path.absolute()}"',
"LibreTiny: Creating a virtual environment for Python dependencies",
)
)
if not python_path.is_file():
# Creating the venv failed
raise RuntimeError(
f"Failed to create virtual environment. Error code {result}"
)
if not pip_path.is_file():
# Creating the venv succeeded but pip didn't get installed
# (i.e. Debian/Ubuntu without ensurepip)
print(
"LibreTiny: Failed to install pip, running get-pip.py", file=sys.stderr
)
import requests
with requests.get("https://bootstrap.pypa.io/get-pip.py") as r:
p = subprocess.Popen(
args=str(python_path.absolute()),
stdin=subprocess.PIPE,
)
p.communicate(r.content)
p.wait()
assert (
pip_path.is_file()
), f"Error: Missing the pip binary in virtual environment `{pip_path.absolute()}`"
assert (
python_path.is_file()
), f"Error: Missing Python executable file `{python_path.absolute()}`"
assert (
site_path.is_dir()
), f"Error: Missing site-packages directory `{site_path.absolute()}`"
env.Replace(LTPYTHONEXE=python_path.absolute(), LTPYTHONENV=venv_path.absolute())
site.addsitedir(str(site_path.absolute()))
def env_install_python_dependencies(env: Environment, dependencies: dict):
try:
pip_output = subprocess.check_output(
[
env.subst("${LTPYTHONEXE}"),
"-m",
"pip",
"list",
"--format=json",
"--disable-pip-version-check",
]
)
pip_data = json.loads(pip_output)
packages = {p["name"]: pepver_to_semver(p["version"]) for p in pip_data}
except:
print(
"LibreTiny: Warning! Couldn't extract the list of installed Python packages"
)
packages = {}
to_install = []
for name, spec in dependencies.items():
install_spec = f'"{name}{dependencies[name]}"'
if name not in packages:
to_install.append(install_spec)
elif spec:
version_spec = semantic_version.Spec(spec)
if not version_spec.match(packages[name]):
to_install.append(install_spec)
if to_install:
env.Execute(
env.VerboseAction(
'"${LTPYTHONEXE}" -m pip install --prefer-binary -U '
+ " ".join(to_install),
"LibreTiny: Installing Python dependencies",
)
)
env.AddMethod(env_configure_python_venv, "ConfigurePythonVenv")
env.AddMethod(env_install_python_dependencies, "InstallPythonDependencies")

View File

@@ -8,6 +8,7 @@ from subprocess import PIPE, Popen
from typing import Dict
from ltchiptool import Family, get_version
from ltchiptool.util.lvm import LVM
from ltchiptool.util.misc import sizeof
from platformio.platform.base import PlatformBase
from platformio.platform.board import PlatformBoardConfig
@@ -77,7 +78,7 @@ def env_configure(
# ltchiptool config:
# -r output raw log messages
# -i 1 indent log messages
LTCHIPTOOL='"${PYTHONEXE}" -m ltchiptool -r -i 1',
LTCHIPTOOL='"${LTPYTHONEXE}" -m ltchiptool -r -i 1 -L "${LT_DIR}"',
# Fix for link2bin to get tmpfile name in argv
LINKCOM="${LINK} ${LINKARGS}",
LINKARGS="${TEMPFILE('-o $TARGET $LINKFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS', '$LINKCOMSTR')}",
@@ -87,6 +88,8 @@ def env_configure(
)
# Store family parameters as environment variables
env.Replace(**dict(family))
# Set platform directory in ltchiptool (for use in this process only)
LVM.add_path(platform.get_dir())
return family

View File

@@ -47,6 +47,10 @@ void SerialClass::configure(unsigned long baudrate, uint16_t config) {
.flow_control = FLOW_CTRL_DISABLED,
};
if (port == 1)
uart1_init();
else if (port == 2)
uart2_init();
uart_hw_set_change(port, &cfg);
uart_rx_callback_set(port, callback, &BUF);

View File

@@ -6,4 +6,9 @@
void lt_init_family() {
// set default UART output port
uart_print_port = LT_UART_DEFAULT_PORT - 1;
// initialize the UART (needed e.g. after deep sleep)
if (uart_print_port == 1)
uart1_init();
else if (uart_print_port == 2)
uart2_init();
}

View File

@@ -9,9 +9,9 @@ void lt_deep_sleep_config_gpio(uint32_t gpio_index_map, bool on_high) {
deep_sleep_param.wake_up_way |= PS_DEEP_WAKEUP_GPIO;
deep_sleep_param.gpio_index_map |= gpio_index_map;
if (on_high) {
deep_sleep_param.gpio_edge_map &= (~gpio_index_map);
} else {
deep_sleep_param.gpio_edge_map |= gpio_index_map;
} else {
deep_sleep_param.gpio_edge_map &= (~gpio_index_map);
}
}

View File

@@ -24,7 +24,7 @@ void SerialClass::adrParse(uint8_t c) {
#endif
int SerialClass::available() {
return this->buf && this->buf->available();
return this->buf ? this->buf->available() : 0;
}
int SerialClass::peek() {

View File

@@ -5,9 +5,6 @@
#include <Arduino.h>
// available built-in implementations
#if LT_ARD_MD5_POLARSSL
#include "MD5PolarSSLImpl.h"
#endif
#if LT_ARD_MD5_MBEDTLS
#include "MD5MbedTLSImpl.h"
#endif

View File

@@ -1,24 +0,0 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-03. */
#if LT_ARD_MD5_POLARSSL
extern "C" {
#include <polarssl/md5.h>
void MD5Init(md5_context *context) {
md5_init(context);
md5_starts(context);
}
void MD5Update(md5_context *context, const unsigned char *buf, unsigned len) {
md5_update(context, buf, len);
}
void MD5Final(unsigned char digest[16], md5_context *context) {
md5_finish(context, digest);
}
} // extern "C"
#endif // LT_ARD_MD5_POLARSSL

View File

@@ -1,19 +0,0 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-03. */
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
unsigned long total[2]; /*!< number of bytes processed */
unsigned long state[4]; /*!< intermediate digest state */
unsigned char buffer[64]; /*!< data block being processed */
} md5_context;
#define LT_MD5_CTX_T md5_context
#ifdef __cplusplus
} // extern "C"
#endif

View File

@@ -61,6 +61,10 @@ bool UpdateClass::begin(
lt_ota_begin(this->ctx, size);
this->ctx->callback = reinterpret_cast<void (*)(void *)>(progressHandler);
this->ctx->callback_param = this;
this->md5Ctx = static_cast<LT_MD5_CTX_T *>(malloc(sizeof(LT_MD5_CTX_T)));
MD5Init(this->md5Ctx);
return true;
}
@@ -79,6 +83,10 @@ bool UpdateClass::end(bool evenIfRemaining) {
// abort if not finished
this->errArd = UPDATE_ERROR_ABORT;
if (!this->md5Digest)
this->md5Digest = static_cast<uint8_t *>(malloc(16));
MD5Final(this->md5Digest, this->md5Ctx);
this->cleanup(/* clearError= */ evenIfRemaining);
return !this->hasError();
}
@@ -97,6 +105,10 @@ void UpdateClass::cleanup(bool clearError) {
// activating firmware failed
this->errArd = UPDATE_ERROR_ACTIVATE;
this->errUf2 = UF2_ERR_OK;
} else if (this->md5Digest && this->md5Expected && memcmp(this->md5Digest, this->md5Expected, 16) != 0) {
// MD5 doesn't match
this->errArd = UPDATE_ERROR_MD5;
this->errUf2 = UF2_ERR_OK;
} else if (clearError) {
// successful finish and activation, clear error codes
this->clearError();
@@ -116,6 +128,12 @@ void UpdateClass::cleanup(bool clearError) {
free(this->ctx);
this->ctx = nullptr;
free(this->md5Ctx);
this->md5Ctx = nullptr;
free(this->md5Digest);
this->md5Digest = nullptr;
free(this->md5Expected);
this->md5Expected = nullptr;
}
/**
@@ -132,6 +150,7 @@ size_t UpdateClass::write(const uint8_t *data, size_t len) {
return 0;
size_t written = lt_ota_write(ctx, data, len);
MD5Update(this->md5Ctx, data, len);
if (written != len)
this->cleanup(/* clearError= */ false);
return written;
@@ -171,6 +190,8 @@ size_t UpdateClass::writeStream(Stream &data) {
// read data to fit in the remaining buffer space
auto bufSize = this->ctx->buf_pos - this->ctx->buf;
auto read = data.readBytes(this->ctx->buf_pos, UF2_BLOCK_SIZE - bufSize);
// update MD5
MD5Update(this->md5Ctx, this->ctx->buf_pos, read);
// increment buffer writing head
this->ctx->buf_pos += read;
// process the block if complete

View File

@@ -1,6 +1,7 @@
#pragma once
#include <Arduino.h>
#include <MD5.h>
#include <functional>
#include <uf2ota/uf2ota.h>
@@ -56,6 +57,9 @@ class UpdateClass {
UpdateClass &onProgress(THandlerFunction_Progress handler);
static bool canRollBack();
static bool rollBack();
bool setMD5(const char *md5);
String md5String();
void md5(uint8_t *result);
uint16_t getErrorCode() const;
bool hasError() const;
void clearError();
@@ -71,6 +75,9 @@ class UpdateClass {
uf2_err_t errUf2{UF2_ERR_OK};
UpdateError errArd{UPDATE_ERROR_OK};
THandlerFunction_Progress callback{nullptr};
LT_MD5_CTX_T *md5Ctx{nullptr};
uint8_t *md5Digest{nullptr};
uint8_t *md5Expected{nullptr};
public:
/**

View File

@@ -71,6 +71,42 @@ bool UpdateClass::rollBack() {
return lt_ota_switch(/* revert= */ false);
}
/**
* @brief Set the expected MD5 of the firmware (hexadecimal string).
*/
bool UpdateClass::setMD5(const char *md5) {
if (strlen(md5) != 32)
return false;
if (!this->md5Expected)
this->md5Expected = static_cast<uint8_t *>(malloc(16));
if (!this->md5Expected)
return false;
lt_xtob(md5, 32, this->md5Expected);
return true;
}
/**
* @brief Return a hexadecimal string of calculated firmware MD5 sum.
*/
String UpdateClass::md5String() {
if (!this->md5Digest)
return "";
char out[32 + 1];
lt_btox(this->md5Digest, 16, out);
return String(out);
}
/**
* @brief Get calculated MD5 digest of the firmware.
*/
void UpdateClass::md5(uint8_t *result) {
if (!this->md5Digest) {
memset(result, '\0', 16);
return;
}
memcpy(result, this->md5Digest, 16);
}
/**
* @brief Get combined error code of the update.
*/

View File

@@ -21,7 +21,7 @@ void lt_deep_sleep_unset_gpio(uint32_t gpio_index_map);
/**
* @brief Set a sleep timer to wake up the device
* @param sleep_duration the time in seconds to sleep
* @param sleep_duration the time in milliseconds to sleep
*/
void lt_deep_sleep_config_timer(uint32_t sleep_duration);

View File

@@ -39,3 +39,36 @@ void hexdump(const uint8_t *buf, size_t len, uint32_t offset, uint8_t width) {
pos += lineWidth;
}
}
char *lt_btox(const uint8_t *src, int len, char *dest) {
// https://stackoverflow.com/a/53966346
const char hex[] = "0123456789abcdef";
len *= 2;
dest[len] = '\0';
while (--len >= 0)
dest[len] = hex[(src[len >> 1] >> ((1 - (len & 1)) << 2)) & 0xF];
return dest;
}
uint8_t *lt_xtob(const char *src, int len, uint8_t *dest) {
// https://gist.github.com/vi/dd3b5569af8a26b97c8e20ae06e804cb
// mapping of ASCII characters to hex values
// (16-byte swapped to reduce XOR 0x10 operation)
const uint8_t mapping[] = {
0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, // @ABCDEFG
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // HIJKLMNO
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // 01234567
0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 89:;<=>?
};
int j = 0;
uint8_t idx0;
uint8_t idx1;
for (int i = 0; i < len; i += 2) {
idx0 = ((uint8_t)src[i + 0] & 0x1F);
idx1 = ((uint8_t)src[i + 1] & 0x1F);
dest[j++] = (mapping[idx0] << 4) | (mapping[idx1] << 0);
}
return dest;
}

View File

@@ -45,3 +45,23 @@ void hexdump(
uint8_t width
#endif
);
/**
* @brief Convert a byte array to hexadecimal string.
*
* @param src source byte array
* @param len source length (bytes)
* @param dest destination string
* @return destination string
*/
char *lt_btox(const uint8_t *src, int len, char *dest);
/**
* @brief Convert a hexadecimal string to byte array.
*
* @param src source string
* @param len source length (chars)
* @param dest destination byte array
* @return destination byte array
*/
uint8_t *lt_xtob(const char *src, int len, uint8_t *dest);

View File

@@ -2,5 +2,5 @@
#error "Don't include this file directly"
#define LT_ARD_HAS_SERIAL 1
#define LT_ARD_MD5_POLARSSL 1
#define LT_ARD_HAS_SERIAL 1
#define LT_ARD_MD5_MBEDTLS 1

View File

@@ -9,5 +9,5 @@ The [LibreTiny C API](../dev/lt-api.md) functions are split between three types:
A quick outline of all available functions and their types:
{%
include-markdown "lt-api-functions.md"
include-markdown "./lt-api-functions.md"
%}

View File

@@ -152,7 +152,6 @@ Checking for option value should be done with `#if` (not with `#ifdef`!) - if it
- `LT_ARD_HAS_WIFI` - WiFi library implemented
- `LT_ARD_HAS_WIRE` - Wire (I²C) library implemented
- `LT_ARD_HAS_SPI` - SPI library implemented
- `LT_ARD_MD5_POLARSSL` - use PolarSSL for MD5 library
- `LT_ARD_MD5_MBEDTLS` - use mbedTLS for MD5 library
- `LT_ARD_MD5_HOSTAPD` - use hostapd for MD5 library
- misc options

View File

@@ -1,8 +1,8 @@
# Flashing/dumping methods & guides
* [ltchiptool GUI manual](tools/ltchiptool.md)
* [Flashing PlatformIO projects](platformio.md)
* [Flashing ESPHome](esphome.md)
* [Dumping stock firmware](dumping.md)
* [Using ltchiptool GUI](tools/ltchiptool.md)
* [Converting with tuya-cloudcutter](tools/cloudcutter.md)
* [Auto-download-reboot](tools/adr.md)

View File

@@ -1,4 +0,0 @@
# Chip connection guides
* [Beken BK72xx](../../platform/beken-72xx/flashing.md)
* [Realtek RTL8710Bx](../../platform/realtek-ambz/flashing.md)

View File

@@ -1,5 +1,8 @@
# Flashing ESPHome
!!! tip
See the [Cloudcutter video guide](https://www.youtube.com/watch?v=sSj8f-HCHQ0) for a complete tutorial on flashing with [Cloudcutter](https://github.com/tuya-cloudcutter/tuya-cloudcutter) and installing [LibreTiny-ESPHome](../projects/esphome.md). **Includes Home Assistant Add-On setup.**
ESPHome can be flashed in few different ways, depending on your needs.
!!! abstract
@@ -20,7 +23,7 @@ ESPHome can be flashed in few different ways, depending on your needs.
<!-- the line below needs to be indented by 4 spaces!!! -->
{%
include-markdown "inc/uart-info.md"
include-markdown "../inc/uart-info.md"
%}
If your device is already running ESPHome, refer to the OTA guide below.
@@ -30,7 +33,7 @@ ESPHome can be flashed in few different ways, depending on your needs.
The built-in flasher is not yet available in the GUI. Here are your options:
- OTA, using the downloaded UF2 file (if you're already running ESPHome)
- wired (also UF2), using ltchiptool
- wired (also UF2), using [ltchiptool](tools/ltchiptool.md)
- wirelessly, using tuya-cloudcutter
Read below for more details on each of these methods.
@@ -43,13 +46,23 @@ This method requires having ESPHome already installed on your device.
- You can also use ESPHome CLI to flash via OTA. Add a `--device` argument to the command, as such: `python -m esphome upload yourdevice.yml --device yourdevice.local`
{%
include-markdown "inc/uart-ltchiptool.md"
include-markdown "../inc/uart-ltchiptool.md"
%}
{%
include-markdown "inc/ota-cloudcutter.md"
include-markdown "../inc/ota-cloudcutter.md"
%}
{%
include-markdown "inc/ota-openbeken.md"
include-markdown "../inc/ota-openbeken.md"
%}
### Migrating from ESPHome to OpenBeken
ESPHome is only compatible with UF2 OTA packages, which OpenBeken doesn't provide. You need to create an UF2 package manually, using ltchiptool (see [ltchiptool#7](https://github.com/libretiny-eu/ltchiptool/issues/7) for more info). Grab an .RBL file from OpenBeken Releases page, and run this command:
```
ltchiptool uf2 write -b generic-bk7231n-qfn32-tuya -o OpenBeken.uf2 "OpenBK7231N_1.17.205.rbl=device:download"
```
This will create `OpenBeken.uf2` file that you can upload on the ESPHome web server dashboard page. **Pay attention to the chip selection** - incorrectly built UF2 file may brick your device! Make sure to download the right .RBL file of OpenBeken, and to choose the correct board (`-b`) parameter.

View File

@@ -1 +0,0 @@
The device needs to be connected to your PC with a UART-TTL adapter. Refer to [chip connection guides](../chip-connection/SUMMARY.md) to learn how to connect your device.

View File

@@ -1,6 +0,0 @@
## Using ltchiptool (wired, via UART)
You can use the [ltchiptool](../tools/ltchiptool.md) GUI or CLI to manually flash the firmware. Grab the `firmware.uf2` file from the build directory. Then, follow the [ltchiptool usage guide](../tools/ltchiptool.md) to flash it to the device.
!!! tip
The UF2 file may have a different name, depending on the project you're building. Usually it's best to grab the latest (sorted by date) file with UF2 extension from the build directory.

View File

@@ -20,9 +20,9 @@ upload_port = COM96
```
{%
include-markdown "inc/uart-info.md"
include-markdown "../inc/uart-info.md"
%}
{%
include-markdown "inc/uart-ltchiptool.md"
include-markdown "../inc/uart-ltchiptool.md"
%}

View File

@@ -1,5 +1,8 @@
# Converting with tuya-cloudcutter
!!! tip
See the [Cloudcutter video guide](https://www.youtube.com/watch?v=sSj8f-HCHQ0) for a complete tutorial on flashing with [Cloudcutter](https://github.com/tuya-cloudcutter/tuya-cloudcutter) and installing [LibreTiny-ESPHome](../../projects/esphome.md). **Includes Home Assistant Add-On setup.**
!!! note
This currently applies to BK7231T and BK7231N only. `tuya-cloudcutter` can't be used for other chips.

View File

@@ -53,7 +53,7 @@ It is a good idea to dump the stock firmware (full flash contents) of your devic
1. Choose the `Read flash` option. If you've previously chosen an input or output file, it will generate a dump filename based on the current timestamp and chip type. Otherwise, click `Browse` and choose the output file.
2. You need to pick the "family" of your chip (the chip model). If you choose the wrong option, the process will fail, but the device won't be bricked.
3. Now, connect the chip to your PC, according to the [chip connection guides](../chip-connection/SUMMARY.md). Select the COM port that your UART adapter is using.
3. Now, connect the chip to your PC, according to the [chip connection guides](../../platform/SUMMARY.md). Select the COM port that your UART adapter is using.
4. By default, the tool will attempt to read the entire flash chip (usually 2 MiB). Unless you know what you're doing, the default values don't need to be changed.
5. Hit `Start`. The tool will try to connect to the chip on the selected UART port. The black log window will print any warnings/errors. The dumping process should begin shortly.
@@ -65,7 +65,7 @@ If you want to flash custom firmware, or restore stock firmware from a previousl
LibreTiny generates multiple firmware files in the build directory. **You usually want to flash the `.uf2` file**, but since ltchiptool can detect file types, you can choose a different firmware file and it'll tell you if that works.
1. Choose `Write flash`. Click `Browse` and select a valid firmware file. The file type and chip type will be auto-detected, along with correct flash offset and length. No need to worry about overwriting the bootloader anymore!
2. Connect the chip to your PC, according to the [chip connection guides](../chip-connection/SUMMARY.md). Select the COM port that your UART adapter is using.
2. Connect the chip to your PC, according to the [chip connection guides](../../platform/SUMMARY.md). Select the COM port that your UART adapter is using.
3. Hit `Start`. The tool will try to connect to the chip on the selected UART port. The black log window will print any warnings/errors. The flashing process should begin shortly.
!!! info

View File

@@ -3,7 +3,10 @@
Using LibreTiny is simple, just like every other PlatformIO development platform.
1. [Install PlatformIO](https://platformio.org/platformio-ide)
2. `platformio platform install -f https://github.com/kuba2k2/libretiny`
2. `platformio platform install -f https://github.com/libretiny-eu/libretiny`
!!! tip
See the [Cloudcutter video guide](https://www.youtube.com/watch?v=sSj8f-HCHQ0) for a complete tutorial on flashing with [Cloudcutter](https://github.com/tuya-cloudcutter/tuya-cloudcutter) and installing [LibreTiny-ESPHome](../projects/esphome.md). **Includes Home Assistant Add-On setup.**
## Board selection

1
docs/inc/find-board.md Normal file
View File

@@ -0,0 +1 @@
You need to know which board your device uses. Head to [Supported Boards](../status/supported.md) to find it. A good number of popular boards have their dedicated support and documentation pages in LibreTiny. Otherwise, you have to use one of the **Generic** boards that matches the CPU model of your device.

View File

@@ -5,4 +5,4 @@
Grab the `image_bk7231x_app.ota.ug.bin` file from the build directory - take care to choose the correct file. It must have "OTA" and "UG" in its name.
Next, refer to [Using tuya-cloudcutter](../tools/cloudcutter.md) guide.
Next, refer to [Using tuya-cloudcutter](../flashing/tools/cloudcutter.md) guide.

1
docs/inc/uart-adr.md Normal file
View File

@@ -0,0 +1 @@
If you have a recent version of LibreTiny already installed on the chip, you don't need to perform any steps to enter download mode. Instead, [Auto-download-reboot](../flashing/tools/adr.md) will reboot the chip automatically, as soon as it notices the flasher program. This is enabled by default, so you don't have to configure anything.

4
docs/inc/uart-cen.md Normal file
View File

@@ -0,0 +1,4 @@
!!! note
"CEN" pin is the RESET pin - connecting it to GND will keep the chip in "reset" state. Disconnecting it will allow the chip to start back up.
If you're having issues with using CEN pin (or if it's not accessible on your device) you can toggle the 3.3V power instead. Removing power will keep it in "reset", and applying it back will start it again.

1
docs/inc/uart-info.md Normal file
View File

@@ -0,0 +1 @@
The device needs to be connected to your PC with a UART-TTL adapter. Refer to [chip connection guides](../platform/SUMMARY.md) to learn how to connect your device.

View File

@@ -0,0 +1,6 @@
## Using ltchiptool (wired, via UART)
You can use the [ltchiptool](../flashing/tools/ltchiptool.md) GUI or CLI to manually flash the firmware. Grab the `firmware.uf2` file from the build directory. Then, follow the [ltchiptool usage guide](../flashing/tools/ltchiptool.md) to flash it to the device.
!!! tip
The UF2 file may have a different name, depending on the project you're building. Usually it's best to grab the latest (sorted by date) file with UF2 extension from the build directory.

4
docs/inc/uart-power.md Normal file
View File

@@ -0,0 +1,4 @@
!!! warning "Important"
Using a **good, stable 3.3V power supply** is crucial. Most flashing issues are caused by either voltage drops during intensive flash operations, or bad/loose wires. The UART adapter's 3.3V power regulator is usually **not enough**.
Instead, a regulated bench power supply, or a linear 1117-type regulator is recommended.

4
docs/platform/SUMMARY.md Normal file
View File

@@ -0,0 +1,4 @@
# Flashing guides
* [Beken BK72xx](beken-72xx/README.md)
* [Realtek RTL8710Bx](realtek-ambz/README.md)

View File

@@ -1,24 +1,123 @@
# Beken 72xx
<div align="center" markdown>
## Introduction
[Read flashing guide](flashing.md){ .md-button }
</div>
Beken BK7231 is a family of Wi-Fi and BLE microcontrollers, of which most popular are BK7231N and BK7231T.
## Resources
Features:
Name | Notes
------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------
[BK7231U Datasheet v0.71](https://cdn.discordapp.com/attachments/983843871320580096/1050461302537064508/BK7231Uv0.71.zh-CN.en.pdf) | Machine-translated to English
[BL2028N Datasheet v1.0](https://cdn.discordapp.com/attachments/983843871320580096/1050461346111697028/BL2028N_Datasheet_v1.0.pdf) | BL2028N is a "clone" of BK7231N
[BK72XX SDK User Manual 3.0.3](https://cdn.discordapp.com/attachments/983843871320580096/1003661237730672730/BK72XX_SDK_User_Manual-3.0.3.pdf) | Machine-translated to English
[BEKEN WiFi SDK API Reference 3.0.27](https://cdn.discordapp.com/attachments/983843871320580096/1003661237349003355/BEKEN_WiFi_SDK_API_Reference-3.0.27_compressed.pdf) | Machine-translated to English
[Beken SDK documentation (online)](http://docs.bekencorp.com/backup/v3.0/) | Not much here
[`encrypt v0.3` source code](https://github.com/ghsecuritylab/tysdk_for_bk7231/tree/master/toolchain/encrypt_crc) |
[`ota_tools` source code](https://github.com/tiancj/rtt_ota_tools) | Encryption routines and FPGA code used on the chip
[BK7231 OpenOCD debugging](https://www.elektroda.com/rtvforum/viewtopic.php?p=20028605#20028605) | From Elektroda.pl user `@xabean`
- ARM968E-S (ARMv5TE) CPU (120 MHz)
- 256 KiB SRAM
- built-in 2 MiB SPI flash with XiP
- 802.11b/g/n Wi-Fi
## General info
Resources:
- [BK7231U Datasheet v0.71](https://cdn.discordapp.com/attachments/983843871320580096/1050461302537064508/BK7231Uv0.71.zh-CN.en.pdf) (Machine-translated to English)
- [BL2028N Datasheet v1.0](https://cdn.discordapp.com/attachments/983843871320580096/1050461346111697028/BL2028N_Datasheet_v1.0.pdf) (BL2028N is a "clone" of BK7231N)
- [BK72XX SDK User Manual 3.0.3](https://cdn.discordapp.com/attachments/983843871320580096/1003661237730672730/BK72XX_SDK_User_Manual-3.0.3.pdf) (Machine-translated to English)
- [BEKEN WiFi SDK API Reference 3.0.27](https://cdn.discordapp.com/attachments/983843871320580096/1003661237349003355/BEKEN_WiFi_SDK_API_Reference-3.0.27_compressed.pdf) (Machine-translated to English)
- [Beken SDK documentation (online)](http://docs.bekencorp.com/backup/v3.0/)
- [`encrypt v0.3` source code](https://github.com/ghsecuritylab/tysdk_for_bk7231/tree/master/toolchain/encrypt_crc) (Encryption routines and FPGA code used on the chip)
- [`ota_tools` source code](https://github.com/tiancj/rtt_ota_tools)
- [BK7231 OpenOCD debugging](https://www.elektroda.com/rtvforum/viewtopic.php?p=20028605#20028605) (From Elektroda.pl user `@xabean`)
## Finding your board
{%
include-markdown "../../inc/find-board.md"
%}
## Flashing
BK7231 has two UART ports - UART2 (sometimes called LOG_UART) and UART1. The UART1 port is used for flashing (and external components, such as TuyaMCU) and has no text output. The UART2 port is used for log viewing only.
You need to find which pins correspond to UART1 TX and RX. If your board is supported, you'll find the pinout on its documentation page. Otherwise (and for generic boards), you'll have to find the pinout online.
For best experience, you should have two USB<->UART adapters plugged in:
- One for flashing, preferably a real FT232RL or a good alternative. This connects to UART1 of the chip.
- One for log output - BK72xx outputs messages on a separate port. You can have a terminal session continuously open on this adapter. This connects to UART2 of the chip - but it's not necessary for flashing.
### Wiring
Connect UART1 of the BK7231 to the USB-TTL adapter:
PC | BK7231
----|-----------------------
RX | TX1 (GPIO11 / P11)
TX | RX1 (GPIO10 / P10)
GND | GND
{%
include-markdown "../../inc/uart-power.md"
%}
The download mode is entered when the chip communicates with the flasher program. Hence, the first step is running the flasher program (described below). While the program is trying to establish communication, **the chip has to be rebooted**. In order to do that, you need to bridge CEN pin to GND with a wire.
{%
include-markdown "../../inc/uart-cen.md"
%}
Keep in mind that BK7231T (not N) will exit the download mode when it can't communicate with the flasher (or when the flasher finishes its work). It's not possible to forcefully enter download mode without it.
After linking with the chip, the flasher program will begin writing (or reading) the firmware automatically. If that doesn't happen, try resetting the chip again until it works.
If you're getting a `No response received` (or similar) error, this means that:
- the power supply is too weak (read above)
- you're resetting the chip too quickly, i.e. you resetted it *after* the program started communicating with it
### Flashing
The recommended tool to flash (or dump firmware) is `ltchiptool`.
**Read [Using ltchiptool](../../flashing/tools/ltchiptool.md) to learn the flashing procedure**
!!! tip
BK7231N can't be software-bricked, because it has a ROM that contains the download mode. **BK7231T doesn't contain it, so be careful with this one**.
`ltchiptool`'s Beken flashing program is based on [bk7231tools](https://github.com/tuya-cloudcutter/bk7231tools). Refer to the guide for information how to use it, but keep in mind that using the ltchiptool GUI is probably just easier.
### Auto-download-reboot
{%
include-markdown "../../inc/uart-adr.md"
%}
## Single UART adapter usage
If you only have a single adapter, or just want to use the UART1 (upload) port only, you can change the logging port of LibreTiny firmware.
Refer to [Options & config](../../dev/config.md) (`Serial output` section). Set `LT_UART_DEFAULT_PORT` to `1`, which will use UART1 for all output.
## Firmware output files
These files are present in the build directory after successful compilation:
File | Description
--------------------------------|----------------------------------------
**firmware.uf2** | **UF2 package for UART and OTA upload**
image_bk7231t_app.ota.rbl | Beken OTA package (e.g. OpenBeken)
image_bk7231t_app.ota.ug.bin | Tuya OTA package (incl. Cloudcutter)
image_bk7231t_app.0x011000.rbl | App partition - flashable at 0x11000
image_bk7231t_app.0x011000.crc | Encrypted app image - not for flashing
image_bk7231t_app.0x129F0A.rblh | RBL header - not for flashing
## SPI flashing (unbricking BK7231T)
The [bk7231_spi_flasher.py](https://github.com/openshwprojects/BK7231_SPI_Flasher/blob/main/bk7231_spi_flasher.py) script can be used to put BK7231 in SPI flashing mode. Then, one can use [flashrom](https://www.flashrom.org/Flashrom) to read/write the raw flash chip.
## Other tools/guides
These tools are **not recommended** and are kept here for reference only. Don't use them, please.
- [Flashing (Tuya manual)](https://developer.tuya.com/en/docs/iot/burn-and-authorize-wb-series-modules?id=Ka78f4pttsytd)
- [BkWriter v1.6.0](https://images.tuyacn.com/smart/bk_writer1.60/bk_writer1.60.exe)
- [hid_download_py](https://github.com/tiancj/hid_download_py)
## Other info
There are many chip variations in this SoC family:
@@ -31,7 +130,7 @@ There are many chip variations in this SoC family:
The "officially existing" ones are BK7231Q, BK7231N and BK7231U. These are supported by Beken SDKs, such as `bdk_freertos`, although `bk7231s_alios_sdk` also existed at some point.
- BK7231N is substantially different than the other chips, so running T code on N (and vice versa) is not directly possible.
- BK7231Q does not have eFuse.
- BK7231Q does not have eFuse **and BLE**
- there are some references to U meaning USB support
- T seems to be exclusive to Tuya boards (that would explain the name); in the T SDK from Tuya, `CFG_SOC_NAME` is set to `SOC_BK7231U`
- T's bootloader greets with `BK7231S_1.0.5` on UART

View File

@@ -1,75 +0,0 @@
# Download mode - Beken 72xx
<div align="center" markdown>
[Read chip docs](README.md){ .md-button }
</div>
Downloading is done using UART. For best experience, you should have two USB<->UART adapters plugged in:
- One for flashing, preferably a real FT232RL or a good alternative. This connects to UART1 of the chip.
- One for log output - BK72xx outputs messages on a separate port. You can have a terminal session continuously open on this adapter. This connects to UART2 of the chip - but it's not necessary for flashing.
**Read [Using ltchiptool](../../flashing/tools/ltchiptool.md) to learn the flashing procedure**
!!! success "Wiring"
Connect UART1 of the BK7231 to the USB-TTL adapter:
PC | BK7231
----|-----------------------
RX | TX1 (GPIO11 / P11)
TX | RX1 (GPIO10 / P10)
RTS | CEN (or RST, optional)
GND | GND
Make sure to use a good 3.3V power supply, otherwise the adapter might
lose power during chip reset. Usually, the adapter's power regulator
is not enough and an external power supply is needed (like AMS1117).
If you didn't connect RTS to CEN, after starting the flasher you have
around 20 seconds to reset the chip manually. In order to do that,
you need to bridge CEN to GND with a wire.
Note that the download mode can only be activated when the flasher is running (there's no GPIO-strapping like on ESP8266). Additionally, BK7231T (not N) will exit the download mode when the flasher finishes its work.
!!! tip
BK7231N can't be software-bricked, because it has a ROM that contains the download mode. **BK7231T doesn't contain it, so be careful with this one**.
## bk7231tools
`ltchiptool`'s Beken flashing program is based on [bk7231tools](https://github.com/tuya-cloudcutter/bk7231tools). Refer to the guide for information how to use it, but keep in mind that using the ltchiptool GUI is probably just easier.
## Auto-download-reboot
If you have a recent version of LibreTiny installed on the chip, you can use [Auto-download-reboot](../../flashing/tools/adr.md) to reboot the chip automatically. This is enabled by default, so you don't have to change anything.
## Single-adapter usage
If you only have a single adapter, or just want to use the UART1 (upload) port only, you can change the logging port.
Refer to [Options & config](../../dev/config.md) (`Serial output` section). Set `LT_UART_DEFAULT_PORT` to `1`, which will use UART1 for all output.
## Firmware output files
These files are present in the build directory after successful compilation:
File | Description
--------------------------------|----------------------------------------
**firmware.uf2** | **UF2 package for UART and OTA upload**
image_bk7231t_app.ota.rbl | Beken OTA package (e.g. OpenBeken)
image_bk7231t_app.ota.ug.bin | Tuya OTA package (incl. Cloudcutter)
image_bk7231t_app.0x011000.rbl | App partition - flashable at 0x11000
image_bk7231t_app.0x011000.crc | Encrypted app image - not for flashing
image_bk7231t_app.0x129F0A.rblh | RBL header - not for flashing
## SPI flashing (unbricking BK7231T)
The [bk7231_spi_flasher.py](https://github.com/openshwprojects/BK7231_SPI_Flasher/blob/main/bk7231_spi_flasher.py) script can be used to put BK7231 in SPI flashing mode. Then, one can use [flashrom](https://www.flashrom.org/Flashrom) to read/write the raw flash chip.
## Other tools/guides
These tools are **not recommended** and are kept here for reference only. Don't use them, please.
- [Flashing (Tuya manual)](https://developer.tuya.com/en/docs/iot/burn-and-authorize-wb-series-modules?id=Ka78f4pttsytd)
- [BkWriter v1.6.0](https://images.tuyacn.com/smart/bk_writer1.60/bk_writer1.60.exe)
- [hid_download_py](https://github.com/tiancj/hid_download_py)

View File

@@ -1,51 +1,115 @@
# Realtek AmebaZ
<div align="center" markdown>
## Introduction
[Read flashing guide](flashing.md){ .md-button }
</div>
Realtek AmebaZ is a family of Wi-Fi microcontrollers, primarily consisting of two chips - RTL8710BN and RTL8710BX.
## Resources
RTL8710BX seems to be the same chip but clocked at 62.5 MHz (instead of 125 MHz for BN). However, it seems that firmware compiled for either of the chips can run on the other with no issues.
Name | Notes
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------
[Realtek Ameba-Z datasheet v3.4](https://web.archive.org/web/20211203124711if_/https://adelectronicsru.files.wordpress.com/2018/10/um0114-realtek-ameba-z-data-sheet-v3-4.pdf) |
[Ameba1/AmebaZ SDK](https://github.com/ambiot/amb1_sdk) |
Features:
## Realtek documents
- ARM Cortex M4 CPU (up to 125 MHz)
- 512 KiB ROM
- 256 KiB SRAM
- SPI flash interface with XiP
- 802.11b/g/n Wi-Fi
Code | Name
-------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
&nbsp; | From **amb1_sdk**
AN0004 | [Realtek low power wi-fi mp user guide](https://raw.githubusercontent.com/ambiot/amb1_sdk/0c8da639b097f01c60e419405aecfafab1d08e43/doc/AN0004%20Realtek%20low%20power%20wi-fi%20mp%20user%20guide.pdf)
AN0011 | [Realtek wlan simple configuration](https://raw.githubusercontent.com/ambiot/amb1_sdk/0c8da639b097f01c60e419405aecfafab1d08e43/doc/AN0011%20Realtek%20wlan%20simple%20configuration.pdf)
AN0012 | [Realtek secure socket layer(ssl)](https://raw.githubusercontent.com/ambiot/amb1_sdk/0c8da639b097f01c60e419405aecfafab1d08e43/doc/AN0012%20Realtek%20secure%20socket%20layer(ssl).pdf)
AN0025 | [Realtek at command](https://raw.githubusercontent.com/ambiot/amb1_sdk/0c8da639b097f01c60e419405aecfafab1d08e43/doc/AN0025%20Realtek%20at%20command.pdf)
AN0033 | [Realtek Ameba-1 over the air firmware update](https://raw.githubusercontent.com/ambiot/amb1_sdk/0c8da639b097f01c60e419405aecfafab1d08e43/doc/AN0033%20Realtek%20Ameba-1%20over%20the%20air%20firmware%20update.pdf)
AN0045 | [Realtek Ameba-1 power modes](https://raw.githubusercontent.com/ambiot/amb1_sdk/0c8da639b097f01c60e419405aecfafab1d08e43/doc/AN0045%20Realtek%20Ameba-1%20power%20modes.pdf)
AN0046 | [Realtek Ameba uart adapter](https://raw.githubusercontent.com/ambiot/amb1_sdk/0c8da639b097f01c60e419405aecfafab1d08e43/doc/AN0046%20Realtek%20Ameba%20uart%20adapter.pdf)
AN0060 | [Realtek UART update user manual](https://raw.githubusercontent.com/ambiot/amb1_sdk/0c8da639b097f01c60e419405aecfafab1d08e43/doc/AN0060%20Realtek%20UART%20update%20user%20manual.pdf)
AN0075 | [Realtek Ameba-all at command v2.0](https://raw.githubusercontent.com/ambiot/amb1_sdk/0c8da639b097f01c60e419405aecfafab1d08e43/doc/AN0075%20Realtek%20Ameba-all%20at%20command%20v2.0.pdf)
AN0096 | [Realtek xmodem UART update user manual](https://raw.githubusercontent.com/ambiot/amb1_sdk/0c8da639b097f01c60e419405aecfafab1d08e43/doc/AN0096%20Realtek%20xmodem%20UART%20update%20user%20manual.pdf)
AN0110 | [Realtek Ameba-Z over the air firmware update](https://raw.githubusercontent.com/ambiot/amb1_sdk/0c8da639b097f01c60e419405aecfafab1d08e43/doc/AN0110%20Realtek%20Ameba-Z%20over%20the%20air%20firmware%20update.pdf)
AN0111 | [Realtek Ameba-Z FreeRTOS tickless](https://raw.githubusercontent.com/ambiot/amb1_sdk/0c8da639b097f01c60e419405aecfafab1d08e43/doc/AN0111%20Realtek%20Ameba-Z%20FreeRTOS%20tickless.pdf)
UM0006 | [Realtek wificonf application programming interface](https://raw.githubusercontent.com/ambiot/amb1_sdk/0c8da639b097f01c60e419405aecfafab1d08e43/doc/UM0006%20Realtek%20wificonf%20application%20programming%20interface.pdf)
UM0014 | [Realtek web server user guide](https://raw.githubusercontent.com/ambiot/amb1_sdk/0c8da639b097f01c60e419405aecfafab1d08e43/doc/UM0014%20Realtek%20web%20server%20user%20guide.pdf)
UM0023 | [Realtek Ameba-1 build environment setup - iar](https://raw.githubusercontent.com/ambiot/amb1_sdk/0c8da639b097f01c60e419405aecfafab1d08e43/doc/UM0023%20Realtek%20Ameba-1%20build%20environment%20setup%20-%20iar.pdf)
UM0027 | [Realtek Ameba-1 crypto engine](https://raw.githubusercontent.com/ambiot/amb1_sdk/0c8da639b097f01c60e419405aecfafab1d08e43/doc/UM0027%20Realtek%20Ameba-1%20crypto%20engine.pdf)
UM0034 | [Realtek Ameba-1 memory layout](https://raw.githubusercontent.com/ambiot/amb1_sdk/0c8da639b097f01c60e419405aecfafab1d08e43/doc/UM0034%20Realtek%20Ameba-1%20memory%20layout.pdf)
UM0039 | [Realtek Ameba-1 SDK quick start](https://raw.githubusercontent.com/ambiot/amb1_sdk/0c8da639b097f01c60e419405aecfafab1d08e43/doc/UM0039%20Realtek%20Ameba-1%20SDK%20quick%20start.pdf)
UM0048 | [Realtek Ameba1 DEV 1v0 User Manual_1v8_20160328](https://raw.githubusercontent.com/ambiot/amb1_sdk/0c8da639b097f01c60e419405aecfafab1d08e43/doc/UM0048%20Realtek%20Ameba1%20DEV%201v0%20User%20Manual_1v8_20160328.pdf)
UM0060 | [Realtek Ameba-1 mqtt user guide](https://raw.githubusercontent.com/ambiot/amb1_sdk/0c8da639b097f01c60e419405aecfafab1d08e43/doc/UM0060%20Realtek%20Ameba-1%20mqtt%20user%20guide.pdf)
UM0096 | [Realtek Ameba build environment setup - gcc](https://raw.githubusercontent.com/ambiot/amb1_sdk/0c8da639b097f01c60e419405aecfafab1d08e43/doc/UM0096%20Realtek%20Ameba%20build%20environment%20setup%20-%20gcc.pdf)
UM0096 | [Realtek Ameba-1 build environment setup - gcc](https://raw.githubusercontent.com/ambiot/amb1_sdk/0c8da639b097f01c60e419405aecfafab1d08e43/doc/UM0096%20Realtek%20Ameba-1%20build%20environment%20setup%20-%20gcc.pdf)
UM0101 | [Realtek Ameba-1 peripheral developerment user manual](https://raw.githubusercontent.com/ambiot/amb1_sdk/0c8da639b097f01c60e419405aecfafab1d08e43/doc/UM0101%20Realtek%20Ameba-1%20peripheral%20developerment%20user%20manual.pdf)
UM0110 | [Realtek Ameba-Z build environment setup - iar](https://raw.githubusercontent.com/ambiot/amb1_sdk/0c8da639b097f01c60e419405aecfafab1d08e43/doc/UM0110%20Realtek%20Ameba-Z%20build%20environment%20setup%20-%20iar.pdf)
UM0111 | [Realtek Ameba-Z memory layout](https://raw.githubusercontent.com/ambiot/amb1_sdk/0c8da639b097f01c60e419405aecfafab1d08e43/doc/UM0111%20Realtek%20Ameba-Z%20memory%20layout.pdf)
UM0112 | [Realtek Ameba-Z SDK quick start](https://raw.githubusercontent.com/ambiot/amb1_sdk/0c8da639b097f01c60e419405aecfafab1d08e43/doc/UM0112%20Realtek%20Ameba-Z%20SDK%20quick%20start.pdf)
UM0113 | [Realtek Ameba-Z DEV 1v0 User Manual](https://raw.githubusercontent.com/ambiot/amb1_sdk/0c8da639b097f01c60e419405aecfafab1d08e43/doc/UM0113%20Realtek%20Ameba-Z%20DEV%201v0%20User%20Manual.pdf)
UM0115 | [Realtek Ameba-Z Introduction](https://raw.githubusercontent.com/ambiot/amb1_sdk/0c8da639b097f01c60e419405aecfafab1d08e43/doc/UM0115%20Realtek%20Ameba-Z%20Introduction.pdf)
UM0116 | [Realtek Ameba-Z SDK change](https://raw.githubusercontent.com/ambiot/amb1_sdk/0c8da639b097f01c60e419405aecfafab1d08e43/doc/UM0116%20Realtek%20Ameba-Z%20SDK%20change.pdf)
UM0120 | [Realtek Ameba-Z User Configuration](https://raw.githubusercontent.com/ambiot/amb1_sdk/0c8da639b097f01c60e419405aecfafab1d08e43/doc/UM0120%20Realtek%20Ameba-Z%20User%20Configuration.pdf)
UM0121 | [Realtek Ameba-Z suspend resume api](https://raw.githubusercontent.com/ambiot/amb1_sdk/0c8da639b097f01c60e419405aecfafab1d08e43/doc/UM0121%20Realtek%20Ameba-Z%20suspend%20resume%20api.pdf)
UM0123 | [Realtek Ameba-Z power modes](https://raw.githubusercontent.com/ambiot/amb1_sdk/0c8da639b097f01c60e419405aecfafab1d08e43/doc/UM0123%20Realtek%20Ameba-Z%20power%20modes.pdf)
Resources:
- [Realtek Ameba-Z datasheet v3.4](https://web.archive.org/web/20211203124711if_/https://adelectronicsru.files.wordpress.com/2018/10/um0114-realtek-ameba-z-data-sheet-v3-4.pdf)
- [Realtek product page](https://www.realtek.com/en/products/communications-network-ics/item/rtl8710bn)
- [Realtek PDFs for Ameba1/AmebaZ](https://github.com/ambiot/amb1_sdk/tree/0c8da639b097f01c60e419405aecfafab1d08e43/doc/)
- [Ameba1/AmebaZ SDK](https://github.com/ambiot/amb1_sdk)
## Finding your board
{%
include-markdown "../../inc/find-board.md"
%}
## Flashing
Realtek RTL8710B has two UART ports - UART2 (sometimes called LOG_UART) and UART0. The port used for flashing and viewing logs is UART2.
You need to find which pins correspond to UART2 TX and RX. If your board is supported, you'll find the pinout on its documentation page. Otherwise (and for generic boards), you'll have to find the pinout online.
!!! tip
You need a good USB<->UART adapter for the process. Some chips may not support 1.5M baud rate,
required by the ROM for the initial handshake. Widespread PL2303 is currently known not to work,
at least under Windows. FT232RL is verified to work reliably.
### Wiring
Connect UART2 of the Realtek chip to the USB-TTL adapter:
PC | RTL8710B
----|--------------------
RX | TX2 (Log_TX / PA30)
TX | RX2 (Log_RX / PA29)
GND | GND
{%
include-markdown "../../inc/uart-power.md"
%}
In order to flash the chip, you need to enable **download mode**. This is done by resetting the chip while pulling down the TX2 pin.
Do this, in order:
- connect CEN to GND
- connect TX2 to GND
- release CEN from GND
- release TX2 from GND
{%
include-markdown "../../inc/uart-cen.md"
%}
To find out whether download mode is enabled, open a serial terminal (such as PuTTY) on your PC. You should see a few characters printed to the serial console every second (usually some kind of grey blocks, or other non-letter characters).
Note that you will not see any characters before you release TX2 from GND.
### Partition layout
When you compile firmware for Realtek with LibreTiny (either ESPHome or other PlatformIO projects), you need to choose a **board**. Different Realtek boards have different partition layouts - the main difference is the OTA2 firmware address. Choosing a board with wrong address will make it harder to flash OTA updates.
Flashing over UART will update (set) the on-chip OTA address to match the firmware being flashed. **OTA flashing will not update the address** - so make sure to choose the correct board, and **keep using the same board** for OTA flashing.
Using incorrect boards may result in OTA updates having no effect, or (worst case) bricking the device completely.
### Flashing
The recommended tool to flash (or dump firmware) is `ltchiptool`.
**Read [Using ltchiptool](../../flashing/tools/ltchiptool.md) to learn the flashing procedure**
!!! tip
Because the UART uploading code is programmed in the ROM of the chip, it can't be software-bricked, even if you damage the bootloader.
### Auto-download-reboot
{%
include-markdown "../../inc/uart-adr.md"
%}
## Firmware output files
These files are present in the build directory after successful compilation:
File | Description
------------------------|-------------------------------------------------------------------
**firmware.uf2** | **UF2 package for UART and OTA upload**
image_ota1.0x00B000.bin | OTA 1 image, flashable to 0xB000
image_ota2.0x0D0000.bin | OTA 2 image, flashable to 0xD0000 (the address might be different)
## Other tools/guides
These tools are **not recommended** and are kept here for reference only. Don't use them, please.
- [Flashing (Tuya manual)](https://developer.tuya.com/en/docs/iot/burn-and-authorize-wr-series-modules?id=Ka789pjc581u8)
- [ImageTool (AmebaZ/AmebaD)](https://images.tuyacn.com/smart/Image_Tool/Image_Tool.zip)
- [rtltool.py](https://github.com/libretiny-eu/ltchiptool/blob/master/ltchiptool/soc/ambz/util/rtltool.py)
OTA1/2 files can be flashed using `ImageTool_v2.3.1_AmebaZ(8710b)`. Browse and select one of the files and enter an appropriate address. Select COM port, press `Open` and then `Download`.
This method is not recommended, as it requires you to know the currently enabled OTA index (1 or 2). Flashing the wrong file will either not make any changes, or upload firmware which won't run.

View File

@@ -1,64 +0,0 @@
# Download mode - Realtek AmebaZ
<div align="center" markdown>
[Read chip docs](README.md){ .md-button }
</div>
Downloading is done using UART2 (sometimes called Log_UART). Refer to your board documentation to find the correct pins.
!!! tip
You need a good USB<->UART adapter for the process. Some chips may not support 1.5M baud rate,
required by the ROM for the initial handshake. Widespread PL2303 is currently known not to work,
at least under Windows. FT232RL is verified to work reliably.
**Read [Using ltchiptool](../../flashing/tools/ltchiptool.md) to learn the flashing procedure**
!!! success "Wiring"
Connect UART2 of the Realtek chip to the USB-TTL adapter:
PC | RTL8710B
----|------------------------------
RX | TX2 (Log_TX / PA30)
TX | RX2 (Log_RX / PA29)
GND | GND
Make sure to use a good 3.3V power supply, otherwise the adapter might
lose power during chip reset. Usually, the adapter's power regulator
is not enough and an external power supply is needed (like AMS1117).
You need to put the chip in download mode manually:
- connect CEN to GND
- connect TX2 to GND
- release CEN from GND
- release TX2 from GND
If the download mode is enabled, you'll see a few garbage characters
printed to the serial console every second.
!!! tip
Because the UART uploading code is programmed in the ROM of the chip, it can't be software-bricked, even if you damage the bootloader.
## Firmware output files
These files are present in the build directory after successful compilation:
File | Description
------------------------|-------------------------------------------------------------------
**firmware.uf2** | **UF2 package for UART and OTA upload**
image_ota1.0x00B000.bin | OTA 1 image, flashable to 0xB000
image_ota2.0x0D0000.bin | OTA 2 image, flashable to 0xD0000 (the address might be different)
## Other tools/guides
These tools are **not recommended** and are kept here for reference only. Don't use them, please.
- [Flashing (Tuya manual)](https://developer.tuya.com/en/docs/iot/burn-and-authorize-wr-series-modules?id=Ka789pjc581u8)
- [ImageTool (AmebaZ/AmebaD)](https://images.tuyacn.com/smart/Image_Tool/Image_Tool.zip)
- [rtltool.py](https://github.com/libretiny-eu/ltchiptool/blob/master/ltchiptool/soc/ambz/util/rtltool.py)
OTA1/2 files can be flashed using `ImageTool_v2.3.1_AmebaZ(8710b)`. Browse and select one of the files and enter an appropriate address. Select COM port, press `Open` and then `Download`.
This method is not recommended, as it requires you to know the currently enabled OTA index (1 or 2). Flashing the wrong file will either not make any changes, or upload firmware which won't run.

View File

@@ -1,11 +1,15 @@
# ESPHome
!!! tip
See the [Cloudcutter video guide](https://www.youtube.com/watch?v=sSj8f-HCHQ0) for a complete tutorial on flashing with [Cloudcutter](https://github.com/tuya-cloudcutter/tuya-cloudcutter) and installing LibreTiny-ESPHome. **Includes Home Assistant Add-On setup.**
Because ESPHome does not natively support running on non-ESP chips, you need to use a fork of the project.
There are two basic ways to install and use LibreTiny-ESPHome. You can choose the option that best suits you:
There are three basic ways to install and use LibreTiny-ESPHome. You can choose the option that best suits you:
- command line (CLI) - for more experienced users; compilation using CLI commands, somewhat easier to troubleshoot
- ESPHome Dashboard (GUI) - for new users, might be an easy way to go; config management & compilation using web-based dashboard
- command line (CLI) - for more experienced users; compilation using CLI commands, somewhat easier to troubleshoot
- [Home Assistant Add-On](https://github.com/libretiny-eu/esphome-hass-addon/pkgs/container/libretiny-esphome-hassio) - using LibreTiny-ESPHome in Home Assistant, alongside your normal ESPHome installation - click the link for more info
!!! tip
You can use LibreTiny-ESPHome for ESP32/ESP8266 compilation as well - the forked version *extends* the base, and doesn't remove any existing features. Keep in mind that you might not have latest ESPHome updates until the fork gets updated (which usually happens at most every few weeks).
@@ -18,6 +22,30 @@ If your board isn't listed, use one of the **Generic** boards, depending on the
## Download ESPHome
=== "GUI"
For this, you need Docker, Docker Compose and Python installed. After running the commands, you'll have a running ESPHome Dashboard interface that you can connect to.
1. Open a terminal/cmd.exe.
2. Create a `docker-compose.yml` file in a directory of choice:
```yaml title="docker-compose.yml"
version: "3"
services:
esphome:
container_name: esphome-libretiny
image: docker pull ghcr.io/libretiny-eu/libretiny-esphome-docker:latest
volumes:
- ./configs:/config:rw # (1)!
- /etc/localtime:/etc/localtime:ro
restart: always
privileged: false
network_mode: host
```
1. You can change `./configs` to another path, in which your ESPHome configs will be stored.
3. Start the container using `docker-compose up`. You should be able to open the GUI on [http://localhost:6052/](http://localhost:6052/).
=== "CLI"
!!! important
@@ -28,7 +56,7 @@ If your board isn't listed, use one of the **Generic** boards, depending on the
Assuming you have PlatformIO, git and Python installed:
1. Open a terminal/cmd.exe, create `esphome` directory and `cd` into it.
2. `git clone https://github.com/kuba2k2/libretiny-esphome`
2. `git clone https://github.com/libretiny-eu/libretiny-esphome`
3. `cd` into the newly created `libretiny-esphome` directory.
4. Check if it works by typing `python -m esphome`
@@ -38,34 +66,19 @@ If your board isn't listed, use one of the **Generic** boards, depending on the
- uninstall ESPHome first: `pip uninstall esphome`
- install the forked version: `pip install -e .`
## Create your device config
=== "GUI"
For this, you need Docker, Docker Compose and Python installed. After running the commands, you'll have a running ESPHome Dashboard interface that you can connect to.
1. `git clone https://github.com/kuba2k2/libretiny-esphome` (or download the .ZIP and unpack it, not recommended)
2. Open a terminal/cmd.exe in the cloned directory (`libretiny-esphome`).
3. `python docker/build.py --tag libretiny --arch amd64 --build-type docker build` - this will build the Docker image of ESPHome. Change `amd64` to something else if you're using a Raspberry Pi.
4. Create a `docker-compose.yml` file in the same directory:
```yaml title="docker-compose.yml"
version: "3"
services:
esphome:
container_name: esphome-libretiny
image: esphome/esphome-amd64:libretiny # (2)!
volumes:
- ./configs:/config:rw # (1)!
- /etc/localtime:/etc/localtime:ro
restart: always
privileged: false
network_mode: host
```
1. You can change `./configs` to another path, in which your ESPHome configs will be stored.
2. Ensure the architecture (`amd64`) matches the one you selected in step 3.
5. Start the container - `docker-compose up`. You should be able to open the GUI on [http://localhost:6052/](http://localhost:6052/).
## Create your device config
1. Open the GUI on [http://localhost:6052/](http://localhost:6052/) (or a different IP address if you're running on a Pi).
2. Go through the wizard steps:
- `New Device`
- `Continue`
- enter name and WiFi details
- choose `LibreTiny`
- choose the board that you found before
- select `Skip`
3. A new config file will be added. Press `Edit` and proceed to the next section.
=== "CLI"
@@ -76,8 +89,8 @@ If your board isn't listed, use one of the **Generic** boards, depending on the
esphome:
name: yourdevice
libretiny:
board: wr3 # THIS IS YOUR BOARD CODE
bk72xx: # adjust accordingly: bk72xx or rtl87xx
board: cb2s # THIS IS YOUR BOARD CODE
framework:
version: latest
@@ -95,17 +108,9 @@ If your board isn't listed, use one of the **Generic** boards, depending on the
password: "Dv2hZMGZRUvy"
```
=== "GUI"
## Automatically generate config
1. Open the GUI on [http://localhost:6052/](http://localhost:6052/) (or a different IP address if you're running on a Pi).
2. Go through the wizard steps:
- `New Device`
- `Continue`
- enter name and WiFi details
- choose `LibreTiny`
- choose the board that you found before
- select `Skip`
3. A new config file will be added. Press `Edit` and proceed to the next section.
Instead of adding components manually and writing everything from scratch, you can use [UPK2ESPHome](https://upk.libretiny.eu/) to generate a working config (for supported BK7231 devices only). If your device has a Cloudcutter profile, there's a high chance it can have a generated config.
## Add components
@@ -118,14 +123,14 @@ Now, just like with standard ESPHome on ESP32/ESP8266, you need to add component
## Build & upload
=== "CLI"
The command `python -m esphome compile yourdevice.yml` will compile ESPHome.
=== "GUI"
Close the config editor. Press the three dots icon and select `Install`. Choose `Manual download` and `Modern format`. The firmware will be compiled and a UF2 file will be downloaded automatically.
=== "CLI"
The command `python -m esphome compile yourdevice.yml` will compile ESPHome.
Now, refer to the [flashing guide](../flashing/esphome.md) to learn how to upload ESPHome to your device. There's also info on using `tuya-cloudcutter` in that guide.
## Advanced: LT configuration
@@ -133,10 +138,10 @@ Now, refer to the [flashing guide](../flashing/esphome.md) to learn how to uploa
!!! note
This part is for advanced users. You'll probably be fine with the default options.
All options from [Options & config](../dev/config.md) can be customized in the `libretiny:` block:
All options from [Options & config](../dev/config.md) can be customized in the LibreTiny block:
```yaml title="yourdevice.yml"
libretiny:
bk72xx:
framework:
version: latest
lt_config:
@@ -149,7 +154,7 @@ libretiny:
Additionally, few options have their dedicated keys:
```yaml title="yourdevice.yml"
libretiny:
bk72xx:
framework:
version: latest
# verbose/trace/debug/info/warn/error/fatal

View File

@@ -4,4 +4,5 @@ mkdocs-literate-nav==0.5.0
mkdocs-section-index
mkdocs-include-markdown-plugin
mkdocs-git-revision-date-localized-plugin
-e git+https://github.com/kuba2k2/mkdoxy#egg=mkdoxy
-e git+https://github.com/libretiny-eu/mkdoxy#egg=mkdoxy
mkdocs-redirects

View File

@@ -1,7 +0,0 @@
# Implementation status
{%
include-markdown "../../README.md"
start="\n## Arduino Core support status\n"
end="\n## License\n"
%}

View File

@@ -3,7 +3,7 @@
## Board list
{%
include-markdown "supported_boards.md"
include-markdown "./supported_boards.md"
%}
\* I/O count includes GPIOs, ADCs, PWM outputs and UART, but doesn't count CEN/RST and power pins.
@@ -13,7 +13,7 @@
Chips currently supported by the project:
{%
include-markdown "supported_chips.md"
include-markdown "./supported_chips.md"
%}
This list is not exhaustive, i.e. a similar chip (but different package) might work just fine, but there's no board definition for it yet.
@@ -26,12 +26,49 @@ A list of chip families currently supported by this project.
!!! note
The term *family* was chosen over *platform*, in order to reduce possible confusion between LibreTiny supported "platforms" and PlatformIO's "platform", as an entire package. *Family* is also more compatible with the UF2 term.
The following list corresponds to UF2 OTA format family names, and is also [available as JSON](../../families.json). The IDs are also present in [lt_types.h](../../ltapi/lt__types_8h.md).
The following list corresponds to UF2 OTA format family names, and is also [available as JSON](../../families.json). The IDs are also present in [lt_types.h](../../ltapi/lt__types_8h.md). You can view the family list by using `ltchiptool list families`.
{%
include-markdown "supported_families.md"
include-markdown "./supported_families.md"
%}
## Feature support
If you notice a feature that you've tested, which works (or not) and doesn't match this table, feel free to submit an issue on GitHub.
&nbsp; | `BK7231T` | `BK7231N` | `RTL8710B` | `RTL8720C` | `BK7231Q`
-------------------------|-----------|-----------|------------|------------|----------
Stability | 5/5 | 5/5 | 4/5 | 2/5 | 1/5
LibreTiny Core | ✔️ | ✔️ | ✔️ | ✔️ | ✔️
Wiring Core | ✔️ | ✔️ | ✔️ | ✔️ | ✔️
**PERIPHERALS** (Core) | | | | |
UART I/O | ✔️ | ✔️ | ✔️ | ✔️ | ✔️
Flash I/O | ✔️ | ✔️ | ✔️ | ❓ | ❓
Deep sleep | ❓ | ✔️ | ❌ | ❌ | ❓
Watchdog timer | ✔️ | ✔️ | ✔️ | ❓ | ❓
**PERIPHERALS** (Wiring) | | | | |
Digital I/O | ✔️ | ✔️ | ✔️ | ❓ | ❓
PWM | ✔️ | ✔️ | ✔️ | ❓ | ❓
Interrupts | ✔️ | ✔️ | ✔️ | ❓ | ❓
Analog input (ADC) | ✔️ | ✔️ | ✔️ | ❓ | ❓
`Wire` (I²C) | ❌ | ❌ | ❗ | ❌ | ❌
`SPI` | ❌ | ❌ | ❌ | ❌ | ❌
`Serial` | ✔️ | ✔️ | ✔️ | ✔️ | ❓
`SoftwareSerial` | ❌ | ❌ | ✔️ | ❌ | ❌
**NETWORKING** | | | | |
Wi-Fi STA/AP/Mixed | ✔️ | ✔️ | ✔️ | ❓ | ❌
Wi-Fi Events | ✔️ | ✔️ | ✔️ | ❓ | ❌
OTA updates | ✔️ | ✔️ | ✔️ | ❌ | ❌
MDNS | ✔️ | ✔️ | ✔️ | ❓ | ❓
Symbols:
- ✔️ working
- ❓ untested
- ❗ broken
- ❌ not implemented (yet?)
- \- not applicable
## Unsupported boards
### Tuya Inc.
@@ -40,5 +77,5 @@ The following list corresponds to UF2 OTA format family names, and is also [avai
Only modules featuring at least Wi-Fi are included in the table. (TY)JW, (TY)WE and (TY)LC Series are omitted, as they contain Espressif chips.
{%
include-markdown "unsupported_boards_tuya_all.md"
include-markdown "./unsupported_boards_tuya_all.md"
%}

View File

@@ -2,7 +2,7 @@ site_name: LibreTiny
docs_dir: .
site_url: https://docs.libretiny.eu/
repo_url: https://github.com/kuba2k2/libretiny
repo_url: https://github.com/libretiny-eu/libretiny
theme:
name: material
@@ -32,6 +32,18 @@ plugins:
save-api: .
- literate-nav:
nav_file: SUMMARY.md
- redirects:
redirect_maps:
"link/cloudcutter-video.md": 'https://www.youtube.com/watch?v=sSj8f-HCHQ0'
"link/cloudcutter-digiblur.md": 'https://digiblur.com/2023/08/19/updated-tuya-cloudcutter-with-esphome-bk7231-how-to-guide/'
"link/boards.md": "docs/status/supported.md"
"link/gpio-access.md": "docs/getting-started/gpio.md"
"link/config.md": "docs/dev/config.md"
"link/config-debug.md": "docs/dev/config.md#per-module-logging-debugging"
"link/config-serial.md": "docs/dev/config.md#serial-output"
"link/flashing-beken-72xx.md": "docs/platform/beken-72xx/README.md#flashing"
"link/flashing-realtek-ambz.md": "docs/platform/realtek-ambz/README.md#flashing"
"link/kickstart.md": "https://github.com/libretiny-eu/esphome-kickstart/releases/latest"
- section-index
- include-markdown
- search

View File

@@ -4,9 +4,9 @@
"description": "PlatformIO development platform for IoT modules",
"repository": {
"type": "git",
"url": "https://github.com/kuba2k2/platformio-libretiny"
"url": "https://github.com/libretiny-eu/libretiny.git"
},
"version": "1.2.0",
"version": "1.4.1",
"frameworks": {
"base": {
"title": "Base Framework (SDK only)",

View File

@@ -1,12 +1,12 @@
# Copyright (c) Kuba Szczodrzyński 2022-04-20.
import importlib
import json
import os
import platform
import site
import sys
from os.path import dirname
from subprocess import Popen
from pathlib import Path
from typing import Dict, List
import click
@@ -15,73 +15,8 @@ from platformio.debug.exception import DebugInvalidOptionsError
from platformio.package.meta import PackageItem
from platformio.platform.base import PlatformBase
from platformio.platform.board import PlatformBoardConfig
from semantic_version import SimpleSpec, Version
LTCHIPTOOL_VERSION = "^4.2.3"
# Install & import tools
def check_ltchiptool(install: bool):
if install:
# update ltchiptool to a supported version
print("Installing/updating ltchiptool")
p = Popen(
[
sys.executable,
"-m",
"pip",
"install",
"-U",
"--force-reinstall",
f"ltchiptool >= {LTCHIPTOOL_VERSION[1:]}, < 5.0",
],
)
p.wait()
# unload all modules from the old version
for name, module in list(sorted(sys.modules.items())):
if not name.startswith("ltchiptool"):
continue
del sys.modules[name]
del module
# try to import it
ltchiptool = importlib.import_module("ltchiptool")
# check if the version is known
version = Version.coerce(ltchiptool.get_version()).truncate()
if version in SimpleSpec(LTCHIPTOOL_VERSION):
return
if not install:
raise ImportError(f"Version incompatible: {version}")
def try_check_ltchiptool():
install_modes = [False, True]
exception = None
for install in install_modes:
try:
check_ltchiptool(install)
return
except (ImportError, AttributeError) as ex:
exception = ex
print(
"!!! Installing ltchiptool failed, or version outdated. "
"Please install ltchiptool manually using pip. "
f"Cannot continue. {type(exception).name}: {exception}"
)
raise exception
try_check_ltchiptool()
import ltchiptool
# Remove current dir so it doesn't conflict with PIO
if dirname(__file__) in sys.path:
sys.path.remove(dirname(__file__))
# Let ltchiptool know about LT's location
ltchiptool.lt_set_path(dirname(__file__))
site.addsitedir(Path(__file__).absolute().parent.joinpath("tools"))
def get_os_specifiers():
@@ -119,6 +54,12 @@ class LibretinyPlatform(PlatformBase):
super().__init__(manifest_path)
self.custom_opts = {}
self.versions = {}
self.verbose = (
"-v" in sys.argv
or "--verbose" in sys.argv
or "PIOVERBOSE=1" in sys.argv
or os.environ.get("PIOVERBOSE", "0") == "1"
)
def print(self, *args, **kwargs):
if not self.verbose:
@@ -137,11 +78,8 @@ class LibretinyPlatform(PlatformBase):
return spec
def configure_default_packages(self, options: dict, targets: List[str]):
from ltchiptool.util.dict import RecursiveDict
from libretiny import RecursiveDict
self.verbose = (
"-v" in sys.argv or "--verbose" in sys.argv or "PIOVERBOSE=1" in sys.argv
)
self.print(f"configure_default_packages(targets={targets})")
pioframework = options.get("pioframework") or ["base"]
@@ -298,19 +236,19 @@ class LibretinyPlatform(PlatformBase):
return result
def update_board(self, board: PlatformBoardConfig):
from libretiny import Board, Family, merge_dicts
if "_base" in board:
board._manifest = ltchiptool.Board.get_data(board._manifest)
board._manifest = Board.get_data(board._manifest)
board._manifest.pop("_base")
if self.custom("board"):
from ltchiptool.util.dict import merge_dicts
with open(self.custom("board"), "r") as f:
custom_board = json.load(f)
board._manifest = merge_dicts(board._manifest, custom_board)
family = board.get("build.family")
family = ltchiptool.Family.get(short_name=family)
family = Family.get(short_name=family)
# add "frameworks" key with the default "base"
board.manifest["frameworks"] = ["base"]
# add "arduino" framework if supported

View File

@@ -0,0 +1,14 @@
# Copyright (c) Kuba Szczodrzyński 2023-09-07.
from .board import Board
from .dict import RecursiveDict, merge_dicts
from .family import Family
# TODO refactor and remove all this from here
__all__ = [
"Board",
"Family",
"RecursiveDict",
"merge_dicts",
]

34
tools/libretiny/board.py Normal file
View File

@@ -0,0 +1,34 @@
# Copyright (c) Kuba Szczodrzyński 2022-07-29.
from typing import Union
from genericpath import isfile
from .dict import merge_dicts
from .fileio import readjson
from .lvm import lvm_load_json
class Board:
@staticmethod
def get_data(board: Union[str, dict]) -> dict:
if not isinstance(board, dict):
if isfile(board):
board = readjson(board)
if not board:
raise FileNotFoundError(f"Board not found: {board}")
else:
source = board
board = lvm_load_json(f"boards/{board}.json")
board["source"] = source
if "_base" in board:
base = board["_base"]
if not isinstance(base, list):
base = [base]
result = {}
for base_name in base:
board_base = lvm_load_json(f"boards/_base/{base_name}.json")
merge_dicts(result, board_base)
merge_dicts(result, board)
board = result
return board

65
tools/libretiny/dict.py Normal file
View File

@@ -0,0 +1,65 @@
# Copyright (c) Kuba Szczodrzyński 2022-07-29.
from .obj import get, has, pop, set_
class RecursiveDict(dict):
def __init__(self, data: dict = None):
if data:
data = {
key: RecursiveDict(value) if isinstance(value, dict) else value
for key, value in data.items()
}
super().__init__(data)
else:
super().__init__()
def __getitem__(self, key):
if "." not in key:
return super().get(key, None)
return get(self, key)
def __setitem__(self, key, value):
if "." not in key:
return super().__setitem__(key, value)
set_(self, key, value, newtype=RecursiveDict)
def __delitem__(self, key):
if "." not in key:
return super().pop(key, None)
return pop(self, key)
def __contains__(self, key) -> bool:
if "." not in key:
return super().__contains__(key)
return has(self, key)
def get(self, key, default=None):
if "." not in key:
return super().get(key, default)
return get(self, key) or default
def pop(self, key, default=None):
if "." not in key:
return super().pop(key, default)
return pop(self, key, default)
def merge_dicts(d1, d2):
# force RecursiveDict instances to be treated as regular dicts
d1_type = dict if isinstance(d1, RecursiveDict) else type(d1)
d2_type = dict if isinstance(d2, RecursiveDict) else type(d2)
if d1 is not None and d1_type != d2_type:
raise TypeError(f"d1 and d2 are of different types: {type(d1)} vs {type(d2)}")
if isinstance(d2, list):
if d1 is None:
d1 = []
d1.extend(merge_dicts(None, item) for item in d2)
elif isinstance(d2, dict):
if d1 is None:
d1 = {}
for key in d2:
d1[key] = merge_dicts(d1.get(key, None), d2[key])
else:
d1 = d2
return d1

97
tools/libretiny/family.py Normal file
View File

@@ -0,0 +1,97 @@
# Copyright (c) Kuba Szczodrzyński 2022-06-02.
from dataclasses import dataclass, field
from typing import List, Optional, Union
from .lvm import lvm_load_json, lvm_path
LT_FAMILIES: List["Family"] = []
@dataclass
class Family:
name: str
parent: Union["Family", None]
code: str
description: str
id: Optional[int] = None
short_name: Optional[str] = None
package: Optional[str] = None
mcus: List[str] = field(default_factory=lambda: [])
children: List["Family"] = field(default_factory=lambda: [])
# noinspection PyTypeChecker
def __post_init__(self):
if self.id:
self.id = int(self.id, 16)
self.mcus = set(self.mcus)
@classmethod
def get_all(cls) -> List["Family"]:
global LT_FAMILIES
if LT_FAMILIES:
return LT_FAMILIES
families = lvm_load_json("families.json")
LT_FAMILIES = [
cls(name=k, **v) for k, v in families.items() if isinstance(v, dict)
]
# attach parents and children to all families
for family in LT_FAMILIES:
if family.parent is None:
continue
try:
parent = next(f for f in LT_FAMILIES if f.name == family.parent)
except StopIteration:
raise ValueError(
f"Family parent '{family.parent}' of '{family.name}' doesn't exist"
)
family.parent = parent
parent.children.append(family)
return LT_FAMILIES
@classmethod
def get(
cls,
any: str = None,
id: Union[str, int] = None,
short_name: str = None,
name: str = None,
code: str = None,
description: str = None,
) -> "Family":
if any:
id = any
short_name = any
name = any
code = any
description = any
if id and isinstance(id, str) and id.startswith("0x"):
id = int(id, 16)
for family in cls.get_all():
if id and family.id == id:
return family
if short_name and family.short_name == short_name.upper():
return family
if name and family.name == name.lower():
return family
if code and family.code == code.lower():
return family
if description and family.description == description:
return family
if any:
raise ValueError(f"Family not found - {any}")
items = [hex(id) if id else None, short_name, name, code, description]
text = ", ".join(filter(None, items))
raise ValueError(f"Family not found - {text}")
@property
def has_arduino_core(self) -> bool:
if lvm_path().joinpath("cores", self.name, "arduino").is_dir():
return True
if self.parent:
return self.parent.has_arduino_core
return False
@property
def target_package(self) -> Optional[str]:
return self.package or self.parent and self.parent.target_package

17
tools/libretiny/fileio.py Normal file
View File

@@ -0,0 +1,17 @@
# Copyright (c) Kuba Szczodrzyński 2022-06-10.
import json
from json import JSONDecodeError
from os.path import isfile
from typing import Optional, Union
def readjson(file: str) -> Optional[Union[dict, list]]:
"""Read a JSON file into a dict or list."""
if not isfile(file):
return None
with open(file, "r", encoding="utf-8") as f:
try:
return json.load(f)
except JSONDecodeError:
return None

19
tools/libretiny/lvm.py Normal file
View File

@@ -0,0 +1,19 @@
# Copyright (c) Kuba Szczodrzyński 2023-3-18.
import json
from pathlib import Path
from typing import Dict, Union
json_cache: Dict[str, Union[list, dict]] = {}
libretiny_path = Path(__file__).parents[2]
def lvm_load_json(path: str) -> Union[list, dict]:
if path not in json_cache:
with libretiny_path.joinpath(path).open("rb") as f:
json_cache[path] = json.load(f)
return json_cache[path]
def lvm_path() -> Path:
return libretiny_path

62
tools/libretiny/obj.py Normal file
View File

@@ -0,0 +1,62 @@
# Copyright (c) Kuba Szczodrzyński 2022-06-02.
from enum import Enum
from typing import Type
# The following helpers force using base dict class' methods.
# Because RecursiveDict uses these helpers, this prevents it
# from running into endless nested loops.
def get(data: dict, path: str):
if not isinstance(data, dict) or not path:
return None
if dict.__contains__(data, path):
return dict.get(data, path, None)
key, _, path = path.partition(".")
return get(dict.get(data, key, None), path)
def pop(data: dict, path: str, default=None):
if not isinstance(data, dict) or not path:
return default
if dict.__contains__(data, path):
return dict.pop(data, path, default)
key, _, path = path.partition(".")
return pop(dict.get(data, key, None), path, default)
def has(data: dict, path: str) -> bool:
if not isinstance(data, dict) or not path:
return False
if dict.__contains__(data, path):
return True
key, _, path = path.partition(".")
return has(dict.get(data, key, None), path)
def set_(data: dict, path: str, value, newtype=dict):
if not isinstance(data, dict) or not path:
return
# can't use __contains__ here, as we're setting,
# so it's obvious 'data' doesn't have the item
if "." not in path:
dict.__setitem__(data, path, value)
else:
key, _, path = path.partition(".")
# allow creation of parent objects
if key in data:
sub_data = dict.__getitem__(data, key)
else:
sub_data = newtype()
dict.__setitem__(data, key, sub_data)
set_(sub_data, path, value)
def str2enum(cls: Type[Enum], key: str):
if not key:
return None
try:
return next(e for e in cls if e.name.lower() == key.lower())
except StopIteration:
return None