[beken-72xx] Implement OTA API, add Update debugging

This commit is contained in:
Kuba Szczodrzyński
2022-08-06 11:35:53 +02:00
parent 3e808f7b6b
commit b03400fac2
9 changed files with 57 additions and 9 deletions

View File

@@ -1,6 +1,7 @@
/* Copyright (c) Kuba Szczodrzyński 2022-06-19. */
#include <LibreTuyaAPI.h>
#include <libraries/Flash/Flash.h>
// can't include <flash.h> as it collides with <Flash.h> on Windows -_-
#define REG_FLASH_BASE 0x00803000
@@ -109,12 +110,14 @@ uint32_t LibreTuya::getMaxAllocHeap() {
/* OTA-related */
static int8_t otaImage2Valid = -1;
uint8_t LibreTuya::otaGetStoredIndex() {
return 1;
return otaHasImage2() ? 2 : 1;
}
bool LibreTuya::otaSupportsDual() {
return false;
return true;
}
bool LibreTuya::otaHasImage1() {
@@ -122,11 +125,28 @@ bool LibreTuya::otaHasImage1() {
}
bool LibreTuya::otaHasImage2() {
return false;
if (otaImage2Valid != -1)
return otaImage2Valid;
// check download RBL
// TODO: maybe check header CRC or even binary hashes
uint32_t magic;
Flash.readBlock(FLASH_DOWNLOAD_OFFSET, (uint8_t *)&magic, 4);
otaImage2Valid = magic == 0x004C4252; // "RBL\0", little-endian
return otaImage2Valid;
}
bool LibreTuya::otaSwitch(bool force) {
return true;
// no need to check otaGetStoredIndex() as it does the same as otaHasImage2()
// force checking validity again
otaImage2Valid = -1;
if (otaHasImage2() && force) {
// "rollback" - abort bootloader upgrade operation by wiping first sector
return Flash.eraseSector(FLASH_DOWNLOAD_OFFSET);
}
return otaHasImage2(); // false if second image is not valid
}
/* Global instance */

View File

@@ -1,5 +1,7 @@
/* Copyright (c) Kuba Szczodrzyński 2022-05-28. */
#pragma once
#define CHIP_TYPE(family, chip_id) (((family >> 24) << 8) | chip_id)
#define CHIP_TYPE_ENUM(family, chip_id) (ChipType) CHIP_TYPE(family, chip_id)

View File

@@ -98,7 +98,8 @@ uint8_t LibreTuya::otaGetTarget() {
}
/**
* @brief Perform OTA rollback.
* @brief Perform OTA rollback: switch to the previous image, or abort current
* switched OTA update, if not rebooted yet.
*
* @return false if no second image to run, writing failed or dual-OTA not supported
*/

View File

@@ -114,7 +114,9 @@ class LibreTuya {
*/
uint8_t otaGetStoredIndex();
/**
* @brief Check if the chip supports dual-OTA.
* @brief Check if the chip supports dual-OTA (i.e. OTA is flashed to a different partition).
*
* TODO: make this work for actual dual-OTA chips; remove checking this in otaGetTarget() etc.
*/
bool otaSupportsDual();
/**

View File

@@ -95,3 +95,7 @@
#ifndef LT_DEBUG_SSL
#define LT_DEBUG_SSL 0
#endif
#ifndef LT_DEBUG_OTA
#define LT_DEBUG_OTA 0
#endif

View File

@@ -185,3 +185,8 @@ void lt_log_disable();
#define LT_T_SSL(...) LT_T_MOD(LT_DEBUG_SSL, __VA_ARGS__)
#define LT_V_SSL(...) LT_T_MOD(LT_DEBUG_SSL, __VA_ARGS__)
#define LT_D_SSL(...) LT_D_MOD(LT_DEBUG_SSL, __VA_ARGS__)
// Update.cpp
#define LT_T_OTA(...) LT_T_MOD(LT_DEBUG_OTA, __VA_ARGS__)
#define LT_V_OTA(...) LT_T_MOD(LT_DEBUG_OTA, __VA_ARGS__)
#define LT_D_OTA(...) LT_D_MOD(LT_DEBUG_OTA, __VA_ARGS__)

View File

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

View File

@@ -118,7 +118,7 @@ class UpdateClass {
}
void clearError() {
errorUf2(UF2_ERR_OK);
errorArd(UPDATE_ERROR_OK);
}
bool hasError() {

View File

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