From 07e9aa1dedc88fca19c3a1c9d779c3325f70aa25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Fri, 19 May 2023 10:42:59 +0200 Subject: [PATCH 01/31] [realtek-ambz2] Make compiling base core possible --- boards/_base/realtek-ambz2-2mb-900k.json | 12 +++ boards/_base/realtek-ambz2-image.json | 96 +++++++++++++++++ boards/_base/realtek-ambz2.json | 6 +- boards/bw15.json | 26 +++++ boards/generic-rtl8720cf-2mb-992k.json | 102 ++++++++++++++++++ builder/family/realtek-ambz2.py | 20 +++- cores/common/base/lt_types.h | 2 + cores/realtek-amb/base/sdk_private.h | 1 + .../base/lt_api.c | 0 .../base/port/printf.c | 0 .../base/port/printf_port.h | 0 cores/realtek-ambz2/base/fixups/cmd_shell.c | 3 + cores/realtek-ambz2/base/port/printf.c | 38 +++++++ cores/realtek-ambz2/base/port/printf_port.h | 18 ++++ 14 files changed, 321 insertions(+), 3 deletions(-) create mode 100644 boards/_base/realtek-ambz2-2mb-900k.json create mode 100644 boards/_base/realtek-ambz2-image.json create mode 100644 boards/bw15.json create mode 100644 boards/generic-rtl8720cf-2mb-992k.json rename cores/{realtek-amb => realtek-ambz}/base/lt_api.c (100%) rename cores/{realtek-amb => realtek-ambz}/base/port/printf.c (100%) rename cores/{realtek-amb => realtek-ambz}/base/port/printf_port.h (100%) create mode 100644 cores/realtek-ambz2/base/fixups/cmd_shell.c create mode 100644 cores/realtek-ambz2/base/port/printf.c create mode 100644 cores/realtek-ambz2/base/port/printf_port.h diff --git a/boards/_base/realtek-ambz2-2mb-900k.json b/boards/_base/realtek-ambz2-2mb-900k.json new file mode 100644 index 0000000..b1f9ed8 --- /dev/null +++ b/boards/_base/realtek-ambz2-2mb-900k.json @@ -0,0 +1,12 @@ +{ + "flash": { + "ota1": "0x010000+0xE0000", + "ota2": "0x0F0000+0xE0000", + "kvs": "0x1D0000+0x8000", + "userdata": "0x1D8000+0x28000" + }, + "upload": { + "flash_size": 2097152, + "maximum_size": 917504 + } +} diff --git a/boards/_base/realtek-ambz2-image.json b/boards/_base/realtek-ambz2-image.json new file mode 100644 index 0000000..1ac54e3 --- /dev/null +++ b/boards/_base/realtek-ambz2-image.json @@ -0,0 +1,96 @@ +{ + "image": { + "keys": { + "decryption": "a0d6dae7e062ca94cbb294bf896b9f68cf8438774256ac7403ca4fd9a1c9564f", + "keyblock": { + "part_table": "882aa16c8c44a7760aa8c9ab22e3568c6fa16c2afa4f0cea29a10abcdf60e44f", + "boot": "882aa16c8c44a7760aa8c9ab22e3568c6fa16c2afa4f0cea29a10abcdf60e44f" + }, + "hash_keys": { + "part_table": "47e5661335a4c5e0a94d69f3c737d54f2383791332939753ef24279608f6d72b", + "boot": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "ota1": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e5f", + "ota2": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e5f" + }, + "user_keys": { + "boot": "aa0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "ota1": "bb0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "ota2": "bb0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" + }, + "xip_sce_key": "a0d6dae7e062ca94cbb294bf896b9f68", + "xip_sce_iv": "94879487948794879487948794879487" + }, + "ptable": { + "boot": "BOOT", + "ota1": "FW1", + "ota2": "FW2" + }, + "boot": { + "name": "boot.sram", + "type": "SRAM", + "entry": "__ram_start_table_start__", + "elf": [ + ".ram.func.table", + ".data", + ".ram.code_text", + ".ram.code_rodata" + ], + "is_boot": true + }, + "fw": [ + { + "type": "FWHS_S", + "sections": [ + { + "name": "fwhs.sram", + "type": "SRAM", + "entry": "__ram_start_table_start__", + "elf": [ + ".ram.img.signature", + ".ram.func.table", + ".data", + ".ram.code_text", + ".ram.code_rodata" + ] + }, + { + "name": "fwhs.psram", + "type": "PSRAM", + "entry": "__psram_start__", + "elf": [ + ".psram.data", + ".psram.code_text", + ".psram.code_rodata" + ] + } + ] + }, + { + "type": "XIP", + "sections": [ + { + "name": "fwhs.xip_c", + "entry": "XIP_RamImgSignature_s", + "type": "XIP", + "elf": [ + ".xip.code_c" + ] + } + ] + }, + { + "type": "XIP", + "sections": [ + { + "name": "fwhs.xip_p", + "entry": "__xip_code_rodata_start__", + "type": "XIP", + "elf": [ + ".xip.code_p" + ] + } + ] + } + ] + } +} diff --git a/boards/_base/realtek-ambz2.json b/boards/_base/realtek-ambz2.json index be1f316..0bdd708 100644 --- a/boards/_base/realtek-ambz2.json +++ b/boards/_base/realtek-ambz2.json @@ -16,7 +16,11 @@ "protocols": [] }, "upload": { - "maximum_ram_size": 262144 + "maximum_ram_size": 262144, + "protocol": "uart", + "protocols": [ + "uart" + ] }, "doc": { "params": { diff --git a/boards/bw15.json b/boards/bw15.json new file mode 100644 index 0000000..e2b972e --- /dev/null +++ b/boards/bw15.json @@ -0,0 +1,26 @@ +{ + "_base": [ + "realtek-ambz2", + "realtek-ambz2-8720", + "realtek-ambz2-image", + "realtek-ambz2-2mb-992k", + "ic/rtl8720cf", + "pcb/bw15" + ], + "build": { + "mcu": "rtl8720cf", + "variant": "bw15" + }, + "name": "BW15", + "url": "https://docs.ai-thinker.com/_media/rtl8710/docs/bw15_datasheet_en.pdf", + "vendor": "Ai-Thinker Co., Ltd.", + "pcb": { + "symbol": "BW15" + }, + "doc": { + "fccid": "2AXVG-BW15", + "links": { + "Vendor datasheet": "https://docs.ai-thinker.com/_media/rtl8710/docs/bw15_datasheet_en.pdf" + } + } +} diff --git a/boards/generic-rtl8720cf-2mb-992k.json b/boards/generic-rtl8720cf-2mb-992k.json new file mode 100644 index 0000000..906f297 --- /dev/null +++ b/boards/generic-rtl8720cf-2mb-992k.json @@ -0,0 +1,102 @@ +{ + "_base": [ + "generic", + "realtek-ambz2", + "realtek-ambz2-8720", + "realtek-ambz2-image", + "realtek-ambz2-2mb-992k", + "ic/rtl8720cf" + ], + "build": { + "mcu": "rtl8720cf", + "variant": "generic-rtl8720cf-2mb-992k" + }, + "name": "Generic - RTL8720CF (2M/992k)", + "symbol": "RTL8720CF (2M/992k)", + "url": "https://docs.libretiny.eu/boards/generic-rtl8720cf-2mb-992k/", + "vendor": "Generic", + "pcb": { + "pinout": { + "1": { + "IC": 15, + "ARD": "D0" + }, + "2": { + "IC": 16, + "ARD": "D1" + }, + "3": { + "IC": 18, + "ARD": "D2" + }, + "4": { + "IC": 19, + "ARD": "D3" + }, + "5": { + "IC": 20, + "ARD": "D4" + }, + "6": { + "IC": 21, + "ARD": "D5" + }, + "7": { + "IC": 22, + "ARD": "D6" + }, + "8": { + "IC": 23, + "ARD": "D7" + }, + "9": { + "IC": 24, + "ARD": "D8" + }, + "10": { + "IC": 25, + "ARD": "D9" + }, + "11": { + "IC": 26, + "ARD": "D10" + }, + "12": { + "IC": 33, + "ARD": "D11" + }, + "13": { + "IC": 34, + "ARD": "D12" + }, + "14": { + "IC": 36, + "ARD": "D13" + }, + "15": { + "IC": 37, + "ARD": "D14" + }, + "16": { + "IC": 38, + "ARD": "D15" + }, + "17": { + "IC": 39, + "ARD": "D16" + }, + "18": { + "IC": 40, + "ARD": "D17" + }, + "19": { + "IC": 1, + "ARD": "D18" + }, + "20": { + "IC": 3, + "ARD": "D19" + } + } + } +} diff --git a/builder/family/realtek-ambz2.py b/builder/family/realtek-ambz2.py index 2cab2fe..51a0db7 100644 --- a/builder/family/realtek-ambz2.py +++ b/builder/family/realtek-ambz2.py @@ -1,6 +1,7 @@ # Copyright (c) Kuba Szczodrzyński 2022-07-20. -from os.path import join +from os.path import isfile, join +from shutil import copyfile from platformio.platform.base import PlatformBase from platformio.platform.board import PlatformBoardConfig @@ -436,10 +437,25 @@ env.Replace( SIZEPRINTCMD="$SIZETOOL -B -d $SOURCES", ) +# Bootloader - copy for linking +# fmt: off +bootloader_src = env.subst("${SDK_DIR}/component/soc/realtek/8710c/misc/bsp/image/bootloader.axf") +bootloader_dst = env.subst("${BUILD_DIR}/bootloader.axf") +# fmt: on +if not isfile(bootloader_dst): + copyfile(bootloader_src, bootloader_dst) + # Build all libraries queue.BuildLibraries() # Main firmware outputs and actions +image_firmware_is = "${BUILD_DIR}/image_firmware_is.${FLASH_OTA1_OFFSET}.bin" env.Replace( - # TODO + # linker command (dual .bin outputs) + LINK="${LTCHIPTOOL} link2bin ${BOARD_JSON} '' ''", + # UF2OTA input list + UF2OTA=[ + # same OTA images for flasher and device + f"{image_firmware_is},{image_firmware_is}=device:ota1,ota2;flasher:ota1,ota2", + ], ) diff --git a/cores/common/base/lt_types.h b/cores/common/base/lt_types.h index eab0f69..1f280f1 100644 --- a/cores/common/base/lt_types.h +++ b/cores/common/base/lt_types.h @@ -40,6 +40,8 @@ typedef enum { RTL8711BU = CPU_MODEL(F_RTL8710B, 0xFC), // CHIPID_8711BG / QFN68 MX1290 = RTL8710BN, MX1290V2 = RTL8710BX, + // Realtek AmebaZ2 + RTL8720CF = CPU_MODEL(F_RTL8720C, 0x00), // TODO // Beken 72XX BK7231T = CPU_MODEL(F_BK7231U, 0x1A), // *SCTRL_CHIP_ID = 0x7231a BK7231N = CPU_MODEL(F_BK7231N, 0x1C), // *SCTRL_CHIP_ID = 0x7231c diff --git a/cores/realtek-amb/base/sdk_private.h b/cores/realtek-amb/base/sdk_private.h index 4b89051..ffda530 100644 --- a/cores/realtek-amb/base/sdk_private.h +++ b/cores/realtek-amb/base/sdk_private.h @@ -20,6 +20,7 @@ extern "C" { #include #endif #if LT_RTL8720C +#include #include #endif diff --git a/cores/realtek-amb/base/lt_api.c b/cores/realtek-ambz/base/lt_api.c similarity index 100% rename from cores/realtek-amb/base/lt_api.c rename to cores/realtek-ambz/base/lt_api.c diff --git a/cores/realtek-amb/base/port/printf.c b/cores/realtek-ambz/base/port/printf.c similarity index 100% rename from cores/realtek-amb/base/port/printf.c rename to cores/realtek-ambz/base/port/printf.c diff --git a/cores/realtek-amb/base/port/printf_port.h b/cores/realtek-ambz/base/port/printf_port.h similarity index 100% rename from cores/realtek-amb/base/port/printf_port.h rename to cores/realtek-ambz/base/port/printf_port.h diff --git a/cores/realtek-ambz2/base/fixups/cmd_shell.c b/cores/realtek-ambz2/base/fixups/cmd_shell.c new file mode 100644 index 0000000..d90ccab --- /dev/null +++ b/cores/realtek-ambz2/base/fixups/cmd_shell.c @@ -0,0 +1,3 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-04-12. */ + +void shell_cmd_init() {} diff --git a/cores/realtek-ambz2/base/port/printf.c b/cores/realtek-ambz2/base/port/printf.c new file mode 100644 index 0000000..74b5200 --- /dev/null +++ b/cores/realtek-ambz2/base/port/printf.c @@ -0,0 +1,38 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-04-12. */ + +#include +#include + +#include + +static UART0_Type *uart_dev[4] = { + UART0, + UART1, + UART2, + UART3, +}; + +uint8_t lt_uart_port = 2; + +void putchar_(char c) { + putchar_p(c, lt_uart_port); +} + +void putchar_p(char c, unsigned long port) { + // while (UART_Writable(uart_dev[port]) == 0) {} + uart_dev[port]->thr = c; +} + +WRAP_PRINTF(rtl_printf); +WRAP_SPRINTF(rtl_sprintf); +WRAP_SNPRINTF(rtl_snprintf); +WRAP_VSNPRINTF(rtl_vsnprintf); +WRAP_VSNPRINTF(rtl_vsnprintf_r); +WRAP_VPRINTF(rtl_vprintf); +WRAP_PRINTF(DiagPrintf); +WRAP_SPRINTF(DiagSPrintf); +WRAP_SNPRINTF(DiagSnPrintf); +WRAP_PRINTF(prvDiagPrintf); +WRAP_SPRINTF(prvDiagSPrintf); +WRAP_VSPRINTF(VSprintf); +WRAP_PRINTF(LOG_PRINTF); diff --git a/cores/realtek-ambz2/base/port/printf_port.h b/cores/realtek-ambz2/base/port/printf_port.h new file mode 100644 index 0000000..74d770e --- /dev/null +++ b/cores/realtek-ambz2/base/port/printf_port.h @@ -0,0 +1,18 @@ +/* Copyright (c) Kuba Szczodrzyński 2022-06-20. */ + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +WRAP_DISABLE_DEF(rtl_printf); +WRAP_DISABLE_DEF(DiagPrintf); +WRAP_DISABLE_DEF(prvDiagPrintf); +WRAP_DISABLE_DEF(LOG_PRINTF); + +#ifdef __cplusplus +} // extern "C" +#endif From 8c636e44f72f3f7478605130f5a70949614cfe91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Tue, 23 May 2023 12:11:17 +0200 Subject: [PATCH 02/31] [realtek-ambz2] Add initial SDK fixups and API layer --- builder/family/realtek-ambz2.py | 18 ++---------------- .../base/fixups/basic_types.h | 0 .../base/fixups/machine/endian.h | 0 .../base/fixups/platform/platform_stdlib.h | 0 .../base/fixups/platform_stdlib.h | 6 ++++-- .../base/fixups/section_config.h | 0 .../base/port/fal_flash_ambz_port.c | 10 ++++++---- .../realtek-ambz2/base/config/platform_conf.h | 19 +++++++++++++++++++ cores/realtek-ambz2/base/fixups/cmd_shell.c | 6 +++++- cores/realtek-ambz2/base/fixups/cmsis.h | 10 ++++++++++ cores/realtek-ambz2/base/fixups/diag.h | 19 +++++++++++++++++++ cores/realtek-ambz2/base/lt_api.c | 19 +++++++++++++++++++ cores/realtek-ambz2/base/port/printf.c | 19 +++++-------------- cores/realtek-ambz2/base/port/printf_port.h | 6 ++---- 14 files changed, 91 insertions(+), 41 deletions(-) rename cores/{realtek-ambz => realtek-amb}/base/fixups/basic_types.h (100%) rename cores/{realtek-ambz => realtek-amb}/base/fixups/machine/endian.h (100%) rename cores/{realtek-ambz => realtek-amb}/base/fixups/platform/platform_stdlib.h (100%) rename cores/{realtek-ambz => realtek-amb}/base/fixups/platform_stdlib.h (82%) rename cores/{realtek-ambz => realtek-amb}/base/fixups/section_config.h (100%) create mode 100644 cores/realtek-ambz2/base/config/platform_conf.h create mode 100644 cores/realtek-ambz2/base/fixups/cmsis.h create mode 100644 cores/realtek-ambz2/base/fixups/diag.h create mode 100644 cores/realtek-ambz2/base/lt_api.c diff --git a/builder/family/realtek-ambz2.py b/builder/family/realtek-ambz2.py index 51a0db7..acdb0fc 100644 --- a/builder/family/realtek-ambz2.py +++ b/builder/family/realtek-ambz2.py @@ -92,6 +92,7 @@ queue.AppendPublic( "-Wl,-wrap,memset", # TODO remove this if possible "-Wl,-wrap,putc", + # rt_printf wrappers are not here, as they're just changing code using #defines ], ) @@ -104,17 +105,6 @@ queue.AddLibrary( # cmsis "+", "+", - # console - "+", - "+", - "+", - "+", - "+", - "+", - "+", - "+", - "+", - "+", # utilities "+", "+", @@ -147,13 +137,9 @@ queue.AddLibrary( "+", "+", "+", - # TODO remove this - "+", - "+", ], includes=[ "+<$SDK_DIR/project/realtek_amebaz2_v0_example/inc>", - "+", "+", "+", "+", @@ -175,7 +161,6 @@ queue.AddLibrary( "+", "+", "+", - "+", "+", "+", "+", @@ -286,6 +271,7 @@ queue.AddLibrary( # "+", "+", "+", + "-", ], includes=[ "+<.>", diff --git a/cores/realtek-ambz/base/fixups/basic_types.h b/cores/realtek-amb/base/fixups/basic_types.h similarity index 100% rename from cores/realtek-ambz/base/fixups/basic_types.h rename to cores/realtek-amb/base/fixups/basic_types.h diff --git a/cores/realtek-ambz/base/fixups/machine/endian.h b/cores/realtek-amb/base/fixups/machine/endian.h similarity index 100% rename from cores/realtek-ambz/base/fixups/machine/endian.h rename to cores/realtek-amb/base/fixups/machine/endian.h diff --git a/cores/realtek-ambz/base/fixups/platform/platform_stdlib.h b/cores/realtek-amb/base/fixups/platform/platform_stdlib.h similarity index 100% rename from cores/realtek-ambz/base/fixups/platform/platform_stdlib.h rename to cores/realtek-amb/base/fixups/platform/platform_stdlib.h diff --git a/cores/realtek-ambz/base/fixups/platform_stdlib.h b/cores/realtek-amb/base/fixups/platform_stdlib.h similarity index 82% rename from cores/realtek-ambz/base/fixups/platform_stdlib.h rename to cores/realtek-amb/base/fixups/platform_stdlib.h index ebe54e1..1d7af6b 100644 --- a/cores/realtek-ambz/base/fixups/platform_stdlib.h +++ b/cores/realtek-amb/base/fixups/platform_stdlib.h @@ -16,7 +16,9 @@ #include #include "basic_types.h" // fixup: replaces typedef boolean for Arduino compatibility -#include "memproc.h" // fixup: redirects to stdlib -#include "strproc.h" // fixup: redirects to stdlib +#ifdef LT_RTL8710B +#include "memproc.h" // fixup: redirects to stdlib +#endif +#include "strproc.h" // fixup: redirects to stdlib #include "diag.h" diff --git a/cores/realtek-ambz/base/fixups/section_config.h b/cores/realtek-amb/base/fixups/section_config.h similarity index 100% rename from cores/realtek-ambz/base/fixups/section_config.h rename to cores/realtek-amb/base/fixups/section_config.h diff --git a/cores/realtek-amb/base/port/fal_flash_ambz_port.c b/cores/realtek-amb/base/port/fal_flash_ambz_port.c index cea509b..8eb033d 100644 --- a/cores/realtek-amb/base/port/fal_flash_ambz_port.c +++ b/cores/realtek-amb/base/port/fal_flash_ambz_port.c @@ -7,24 +7,26 @@ #define FLASH_ERASE_MIN_SIZE (4 * 1024) +static flash_t flash_obj; + static int init() { - flash_get_status(NULL); + flash_get_status(&flash_obj); return 0; } static int read(long offset, uint8_t *buf, size_t size) { - return size * flash_stream_read(NULL, offset, size, buf); + return size * flash_stream_read(&flash_obj, offset, size, buf); } static int write(long offset, const uint8_t *buf, size_t size) { - return size * flash_stream_write(NULL, offset, size, (uint8_t *)buf); + return size * flash_stream_write(&flash_obj, offset, size, (uint8_t *)buf); } static int erase(long offset, size_t size) { offset &= ~(FLASH_ERASE_MIN_SIZE - 1); size = ((size - 1) / FLASH_ERASE_MIN_SIZE) + 1; for (uint16_t i = 0; i < size; i++) { - flash_erase_sector(NULL, offset + i * FLASH_ERASE_MIN_SIZE); + flash_erase_sector(&flash_obj, offset + i * FLASH_ERASE_MIN_SIZE); } return size * FLASH_ERASE_MIN_SIZE; } diff --git a/cores/realtek-ambz2/base/config/platform_conf.h b/cores/realtek-ambz2/base/config/platform_conf.h new file mode 100644 index 0000000..4b5d67d --- /dev/null +++ b/cores/realtek-ambz2/base/config/platform_conf.h @@ -0,0 +1,19 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-05-23. */ + +#pragma once + +#include_next "platform_conf.h" + +#undef CONFIG_DEBUG_LOG +#undef CONFIG_DEBUG_ERROR +#undef CONFIG_DEBUG_WARN +#undef CONFIG_DEBUG_INFO +#define CONFIG_DEBUG_LOG 0 +#define CONFIG_DEBUG_ERROR 0 +#define CONFIG_DEBUG_WARN 0 +#define CONFIG_DEBUG_INFO 0 + +// diag.h doesn't define this if CONFIG_DEBUG_LOG is 0 +#define DBG_SCE_ERR(...) +#define DBG_SCE_WARN(...) +#define DBG_SCE_INFO(...) diff --git a/cores/realtek-ambz2/base/fixups/cmd_shell.c b/cores/realtek-ambz2/base/fixups/cmd_shell.c index d90ccab..622802c 100644 --- a/cores/realtek-ambz2/base/fixups/cmd_shell.c +++ b/cores/realtek-ambz2/base/fixups/cmd_shell.c @@ -1,3 +1,7 @@ /* Copyright (c) Kuba Szczodrzyński 2023-04-12. */ -void shell_cmd_init() {} +extern void lt_main(); + +void shell_cmd_init() { + lt_main(); +} diff --git a/cores/realtek-ambz2/base/fixups/cmsis.h b/cores/realtek-ambz2/base/fixups/cmsis.h new file mode 100644 index 0000000..1124176 --- /dev/null +++ b/cores/realtek-ambz2/base/fixups/cmsis.h @@ -0,0 +1,10 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-05-23. */ + +// use platform_conf.h from realtek-ambz2/base/config +#include +// use basic_types.h from realtek-amb/base/fixups +#include +// use basic_types.h from realtek-ambz2/base/fixups +#include "diag.h" + +#include_next "cmsis.h" diff --git a/cores/realtek-ambz2/base/fixups/diag.h b/cores/realtek-ambz2/base/fixups/diag.h new file mode 100644 index 0000000..96e30da --- /dev/null +++ b/cores/realtek-ambz2/base/fixups/diag.h @@ -0,0 +1,19 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-05-23. */ + +// remove component/soc/realtek/8710c/app/rtl_printf/include/rt_printf.h +// replace with #defines below +#ifndef _RT_PRINTF__H +#define _RT_PRINTF__H +#endif + +#undef log_printf +#include_next "diag.h" +#undef log_printf + +#define rt_printf(...) __wrap_rt_printf(__VA_ARGS__) +#define rt_printfl(...) __wrap_rt_printf(__VA_ARGS__) +#define rt_sprintf(...) __wrap_rt_sprintf(__VA_ARGS__) +#define rt_sprintfl(...) __wrap_rt_sprintf(__VA_ARGS__) +#define rt_snprintf(...) __wrap_rt_snprintf(__VA_ARGS__) +#define rt_snprintfl(...) __wrap_rt_snprintf(__VA_ARGS__) +#define rt_log_printf(...) __wrap_rt_log_printf(__VA_ARGS__) diff --git a/cores/realtek-ambz2/base/lt_api.c b/cores/realtek-ambz2/base/lt_api.c new file mode 100644 index 0000000..53b838c --- /dev/null +++ b/cores/realtek-ambz2/base/lt_api.c @@ -0,0 +1,19 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-05-22. */ + +#include +#include + +extern uint8_t lt_uart_port; + +void lt_init_family() { + // make the SDK less verbose by default + ConfigDebugErr = 0; + ConfigDebugWarn = 0; + ConfigDebugInfo = 0; + lt_uart_port = LT_UART_DEFAULT_PORT; +} + +lt_reboot_reason_t lt_get_reboot_reason() { + // TODO + return REBOOT_REASON_UNKNOWN; +} diff --git a/cores/realtek-ambz2/base/port/printf.c b/cores/realtek-ambz2/base/port/printf.c index 74b5200..1ec6a0b 100644 --- a/cores/realtek-ambz2/base/port/printf.c +++ b/cores/realtek-ambz2/base/port/printf.c @@ -19,20 +19,11 @@ void putchar_(char c) { } void putchar_p(char c, unsigned long port) { - // while (UART_Writable(uart_dev[port]) == 0) {} + while (uart_dev[port]->lsr_b.txfifo_empty == 0) {} uart_dev[port]->thr = c; } -WRAP_PRINTF(rtl_printf); -WRAP_SPRINTF(rtl_sprintf); -WRAP_SNPRINTF(rtl_snprintf); -WRAP_VSNPRINTF(rtl_vsnprintf); -WRAP_VSNPRINTF(rtl_vsnprintf_r); -WRAP_VPRINTF(rtl_vprintf); -WRAP_PRINTF(DiagPrintf); -WRAP_SPRINTF(DiagSPrintf); -WRAP_SNPRINTF(DiagSnPrintf); -WRAP_PRINTF(prvDiagPrintf); -WRAP_SPRINTF(prvDiagSPrintf); -WRAP_VSPRINTF(VSprintf); -WRAP_PRINTF(LOG_PRINTF); +WRAP_PRINTF(rt_printf); +WRAP_SPRINTF(rt_sprintf); +WRAP_SNPRINTF(rt_snprintf); +WRAP_PRINTF(rt_log_printf); diff --git a/cores/realtek-ambz2/base/port/printf_port.h b/cores/realtek-ambz2/base/port/printf_port.h index 74d770e..4c65b6c 100644 --- a/cores/realtek-ambz2/base/port/printf_port.h +++ b/cores/realtek-ambz2/base/port/printf_port.h @@ -8,10 +8,8 @@ extern "C" { #endif // __cplusplus -WRAP_DISABLE_DEF(rtl_printf); -WRAP_DISABLE_DEF(DiagPrintf); -WRAP_DISABLE_DEF(prvDiagPrintf); -WRAP_DISABLE_DEF(LOG_PRINTF); +WRAP_DISABLE_DEF(rt_printf); +WRAP_DISABLE_DEF(rt_log_printf); #ifdef __cplusplus } // extern "C" From 620e457eb6b0e4cc1f85c21e28a047b90a12f929 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Tue, 23 May 2023 12:56:42 +0200 Subject: [PATCH 03/31] [realtek-ambz2] Fix C++ linker support --- cores/realtek-ambz2/misc/rtl8710c_ram.ld | 46 +++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/cores/realtek-ambz2/misc/rtl8710c_ram.ld b/cores/realtek-ambz2/misc/rtl8710c_ram.ld index 3977d81..cc6a48d 100644 --- a/cores/realtek-ambz2/misc/rtl8710c_ram.ld +++ b/cores/realtek-ambz2/misc/rtl8710c_ram.ld @@ -1,6 +1,10 @@ /* Linker script to configure memory regions. */ -/* LT changes: added .ARM.exidx section */ +/* LibreTiny changes: + - added .ARM.exidx section + - added .ARM.extab + - added missing C++ support +*/ /* !! the include symbole may failed if the symbol file name is too long!! */ INCLUDE "romsym_is.so" @@ -278,6 +282,29 @@ SECTIONS /* put RO data sections need to be encrypted here */ *(.xip.sec_rodata*) + /* Add This for C++ support */ + /* ambd_arduino/Arduino_package/hardware/variants/rtl8720dn_bw16/linker_scripts/gcc/rlx8721d_img2_is_arduino.ld */ + . = ALIGN(4); + __preinit_array_start = .; + KEEP(*(.preinit_array)) + __preinit_array_end = .; + . = ALIGN(4); + __init_array_start = .; + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + __init_array_end = .; + . = ALIGN(4); + __fini_array_start = .; + KEEP(*(SORT(.fini_array.*))) + KEEP(*(.fini_array)) + __fini_array_end = .; + /*-----------------*/ + /* https://community.silabs.com/s/article/understand-the-gnu-linker-script-of-cortex-m4?language=en_US */ + KEEP(*(.init)) + KEEP(*(.fini)) + *(.init) + *(.fini) + __xip_code_text_end__ = .; } > XIP_FLASH_C @@ -292,10 +319,27 @@ SECTIONS *(.rodata*) *(.rodata.str1*) + /* https://www.embedded.com/building-bare-metal-arm-systems-with-gnu-part-3/ */ + KEEP(*crtbegin.o(.ctors)) + KEEP(*(EXCLUDE_FILE (*ctrend.o) .ctors)) + KEEP(*(SORT(.ctors.*))) + KEEP(*crtend.o(.ctors)) + KEEP(*crtbegin.o(.dtors)) + KEEP(*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP(*(SORT(.dtors.*))) + KEEP(*crtend.o(.dtors)) + *(.rodata .rodata.* .gnu.linkonce.r.*) + . = ALIGN(4); __xip_code_rodata_end__ = .; } > XIP_FLASH_P + /* Add This for C++ support */ + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > XIP_FLASH_P + .ARM.exidx : { __exidx_start = .; From c40bdd68af2a25c553a637083219baafffc61d7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Tue, 23 May 2023 15:14:59 +0200 Subject: [PATCH 04/31] [realtek-ambz2] Use external FreeRTOS port --- builder/family/realtek-ambz2.py | 12 +++++------- .../base/fixups/cmsis_ipsr.c | 0 .../base/fixups/rtl8710c_freertos_pmu.h | 11 +++++++++++ platform.json | 5 ++++- 4 files changed, 20 insertions(+), 8 deletions(-) rename cores/{realtek-ambz => realtek-amb}/base/fixups/cmsis_ipsr.c (100%) create mode 100644 cores/realtek-ambz2/base/fixups/rtl8710c_freertos_pmu.h diff --git a/builder/family/realtek-ambz2.py b/builder/family/realtek-ambz2.py index acdb0fc..c6b2bbe 100644 --- a/builder/family/realtek-ambz2.py +++ b/builder/family/realtek-ambz2.py @@ -116,11 +116,6 @@ queue.AddLibrary( "+", "+", "+", - # os - freertos - "+", - # os - freertos - portable - "+", - "+", # peripheral - api "+", # peripheral - hal @@ -157,8 +152,6 @@ queue.AddLibrary( "+", "+", "+", - "+", - "+", "+", "+", "+", @@ -191,6 +184,11 @@ queue.AddLibrary( ), ) +# Sources - FreeRTOS +env.Replace(FREERTOS_PORT=env["FAMILY_NAME"], FREERTOS_PORT_DEFINE="REALTEK_AMBZ2") +queue.AddExternalLibrary("freertos") +queue.AddExternalLibrary("freertos-port") + # Sources - network utilities queue.AddLibrary( name="ambz2_net", diff --git a/cores/realtek-ambz/base/fixups/cmsis_ipsr.c b/cores/realtek-amb/base/fixups/cmsis_ipsr.c similarity index 100% rename from cores/realtek-ambz/base/fixups/cmsis_ipsr.c rename to cores/realtek-amb/base/fixups/cmsis_ipsr.c diff --git a/cores/realtek-ambz2/base/fixups/rtl8710c_freertos_pmu.h b/cores/realtek-ambz2/base/fixups/rtl8710c_freertos_pmu.h new file mode 100644 index 0000000..ab014d8 --- /dev/null +++ b/cores/realtek-ambz2/base/fixups/rtl8710c_freertos_pmu.h @@ -0,0 +1,11 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-05-23. */ + +#include + +// rtl8710c_freertos_pmu.h needs the u32/u16/u8 integer typedefs, +// so it relies on the caller (freertos_pmu.c) to provide these, +// which relies on FreeRTOS.h to include FreeRTOSConfig.h, +// which relies on diag.h included to get printf() functions, +// which just happens to include basic_types.h as well, +// and that's what makes the whole thing even compile +#include_next "rtl8710c_freertos_pmu.h" diff --git a/platform.json b/platform.json index abff61d..dad8560 100644 --- a/platform.json +++ b/platform.json @@ -43,6 +43,9 @@ "version_prefix": true, "toolchains": { "any": "gccarmnoneeabi@~1.100301.0" + }, + "libraries": { + "freertos": "10.0.1" } }, "framework-beken-bdk": { @@ -80,7 +83,7 @@ }, "library-freertos-port": { "type": "framework", - "version": "https://github.com/libretiny-eu/library-freertos-port#2023.03.13" + "version": "https://github.com/libretiny-eu/library-freertos-port#2023.05.23" }, "library-flashdb": { "type": "framework", From 43c9d0db1092d5b12a346460446e7e4700597d5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Tue, 23 May 2023 15:58:11 +0200 Subject: [PATCH 05/31] [docs] Add Porting new families guide --- SUMMARY.md | 10 ++- docs/{dev => contrib}/ota/README.md | 0 docs/{dev => contrib}/ota/library.md | 0 docs/{dev => contrib}/ota/uf2ota.md | 0 docs/contrib/porting.md | 93 ++++++++++++++++++++++ docs/{dev => contrib}/project-structure.md | 0 docs/{dev => contrib}/stdlib.md | 0 7 files changed, 99 insertions(+), 4 deletions(-) rename docs/{dev => contrib}/ota/README.md (100%) rename docs/{dev => contrib}/ota/library.md (100%) rename docs/{dev => contrib}/ota/uf2ota.md (100%) create mode 100644 docs/contrib/porting.md rename docs/{dev => contrib}/project-structure.md (100%) rename docs/{dev => contrib}/stdlib.md (100%) diff --git a/SUMMARY.md b/SUMMARY.md index fbe2623..284ab5d 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -47,10 +47,12 @@ * [Macros](ltapi/macros.md) * [File list](ltapi/files.md) * 👷 Contributor's manual (WIP) - * [📁 Project structure](docs/dev/project-structure.md) - * [✈️ OTA format](docs/dev/ota/README.md) - * [uf2ota.py tool](docs/dev/ota/uf2ota.md) - * [uf2ota.h library](docs/dev/ota/library.md) + * [Porting new families](docs/contrib/porting.md) + * [📁 Project structure](docs/contrib/project-structure.md) + * [C standard library](docs/contrib/stdlib.md) + * [✈️ OTA format](docs/contrib/ota/README.md) + * [uf2ota.py tool](docs/contrib/ota/uf2ota.md) + * [uf2ota.h library](docs/contrib/ota/library.md) * [📓 TODO](docs/TODO.md) * [](SUMMARY.md) * [🔗 Resources](docs/resources/) diff --git a/docs/dev/ota/README.md b/docs/contrib/ota/README.md similarity index 100% rename from docs/dev/ota/README.md rename to docs/contrib/ota/README.md diff --git a/docs/dev/ota/library.md b/docs/contrib/ota/library.md similarity index 100% rename from docs/dev/ota/library.md rename to docs/contrib/ota/library.md diff --git a/docs/dev/ota/uf2ota.md b/docs/contrib/ota/uf2ota.md similarity index 100% rename from docs/dev/ota/uf2ota.md rename to docs/contrib/ota/uf2ota.md diff --git a/docs/contrib/porting.md b/docs/contrib/porting.md new file mode 100644 index 0000000..48f7275 --- /dev/null +++ b/docs/contrib/porting.md @@ -0,0 +1,93 @@ +# Porting new families + +This document briefly outlines what needs to be done, in order to port a new chip family to LibreTiny. + +## Base framework + builders + +The base framework is the core part, that provides little functionality and a small HAL (over some things like OTA or sys control). It also includes a builder script for the vendor SDK. + +Here's what has to be done to make that work: + +1. Find vendor SDK - should be self-explanatory. We can't work without a working SDK (yet). +2. Test vendor SDK - compile a sample program "as it was meant to be done". + + - Most SDKs provide some example programs (like Hello World, WiFi scanning, etc.) that can usually be compiled by running a single "make" command. + - Sometimes you need to configure your environment in a weird and complicated way. For me, using Cygwin on Windows was usually enough, though. + - You need to flash this to the chip as well. The SDK usually bundles some flashing tools. + - This step is crucial to understand the vendor build system, and to have working binaries to compare out results against. + +3. "Clean up" vendor SDK. + + - SDKs usually bundle entire compiler toolchains, which can take up hundreds of megabytes. We want to keep the downloaded PlatformIO packages as small as possible. + - On existing families, GitHub Workflows produce the packages by removing some files and adding `package.json` to them. See [framework-beken-bdk/.github/workflows/platformio-package.yml](https://github.com/libretiny-eu/framework-beken-bdk/blob/actions/.github/workflows/platformio-package.yml) for an example. + +4. Write base family and board definitions. + + - `families.json` needs to have the new family added to it. + - `platform.json` needs to know the vendor SDK repository. + - Add any boards and base JSONs to the `boards/` directory. It's easiest to start with generic boards. + - Use `boardgen ltci` to generate variant sources (.c and .h). + +5. Add base core code. + + - `lt_defs.h`, `lt_family.h` and `lt_api.c` files need to be created, and initialized with (even empty) functions and definitions. + - Make the SDK call `lt_main()` as the entrypoint. If needed, use fixups. + +6. Write a binary manipulation tool. + + - While this step could be optional, as these tools are provided in the SDK, they're usually platform-specific (i.e. Windows-only) and use proprietary executables, with no source code nor documentation. This is unacceptable for LibreTiny, as we need to support multiple architectures & platforms (Windows, Linux, Raspberry Pi, etc.). Naturally, doing that in Python seems to be the best choice. + - All binary tools are currently in [ltchiptool/soc/.../binary.py](https://github.com/libretiny-eu/ltchiptool/blob/master/ltchiptool/soc/bk72xx/binary.py). The `elf2bin()` function is what takes an .ELF file, and generates a set of binaries that can be flashed to the chip. + - It's best to test if the generation is correct, by taking an .ELF compiled by vendor SDK, running it through ltchiptool and checking if the resulting binaries are identical. + - Ghidra/IDA Pro is your friend here; you can decompile the SDK tools. + +7. Write a flashing tool. + + - mostly the same as above. Refer to the existing tools for examples. It's useful to make the flasher class "standalone", i.e. a class that is then wrapped by ltchiptool, like in [`realtek-ambz2`](https://github.com/libretiny-eu/ltchiptool/blob/master/ltchiptool/soc/ambz2/util/ambz2tool.py). + +8. Write builder scripts. + + - `builder/family/xxx.py` files are builders, which contain all SDK sources and include paths. Write the script, based on the existing families, and any Makefiles or other scripts from the SDK. + - Make sure not to make a mess in the `CCFLAGS`/`CPPDEFINES`, and only include what's needed there. Some flags are project-wide (family-independent) in `builder/frameworks/base.py`. + - Use a **pure PlatformIO** project - **not ESPHome!**. Pass one of the generic boards you created before, and `framework = base` in `platformio.ini`. Generally, try to get the thing to compile. + - Use a simple Hello World program - C, not C++. Only add `main()` function with a `printf()` and a `while(1)` loop. + +9. When you get it to link successfully, build a UF2 file. + + - UF2 packages are for flashing and for OTA. + - Add `UF2OTA` to the env, to provide binaries that will go to the UF2. Some understanding of the chip's partition and flash layout will be needed. + +10. Flash it, test if it works! + + - It probably won't. You may need to remove `__libc_init_array()` from `cores/common/base/lt_api.c` so that it doesn't crash. Most SDKs don't support C++ properly. + +## Making it *actually* work + +1. Write `flashdb` and `printf` ports. + + - The ports are in `cores/.../base/port/`. It's a simple flash access layer, and a character printing function. Not a lot of work, but it needs to be done first. + +2. Add fixups so that string & memory stdlib functions are not from SDK. + + - Refer to [stdlib.md](stdlib.md) to find functions that need to be wrapped. + - SDK should not define them, you have to figure out a way to remove them from headers. Fixups can mess with includes and trick the SDK into using our own functions. + +3. Clean up FreeRTOS. + + - FreeRTOS' headers usually include some SDK headers, which pull in a lot of macros and typedefs, which usually break lots of non-SDK code, which doesn't expect these macros. + - [library-freertos](https://github.com/libretiny-eu/library-freertos) repo contains some FreeRTOS versions, adapted for SDKs. Basically, copy a clean (straight from FreeRTOS github) version to the repo, commit it. Then copy the version from SDK and compare the differences. + - Try to make it look as "stock" as possible. Discard any formatting differences (and backports). + - Annotate any parts that can't be removed with `#ifdef FREERTOS_PORT_REALTEK_AMB1`. + - Put the FreeRTOS vendor-specific port in [library-freertos-port](https://github.com/libretiny-eu/library-freertos-port). + - Remove all FreeRTOS sources from builder scripts. Replace with: + + ```py + env.Replace(FREERTOS_PORT=env["FAMILY_NAME"], FREERTOS_PORT_DEFINE="REALTEK_AMB1") + queue.AddExternalLibrary("freertos") + queue.AddExternalLibrary("freertos-port") + ``` + +4. Do the same with lwIP - later. + +5. Write LibreTiny C APIs - in `lt_api.c`. + +6. At this point, your Hello World code should work fine. diff --git a/docs/dev/project-structure.md b/docs/contrib/project-structure.md similarity index 100% rename from docs/dev/project-structure.md rename to docs/contrib/project-structure.md diff --git a/docs/dev/stdlib.md b/docs/contrib/stdlib.md similarity index 100% rename from docs/dev/stdlib.md rename to docs/contrib/stdlib.md From b073290989db3a7fedbe56435f1538c775d525fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Tue, 23 May 2023 19:54:00 +0200 Subject: [PATCH 06/31] [realtek-ambz2] Implement base C API --- cores/beken-72xx/base/lt_api.c | 4 - cores/common/base/api/lt_device.h | 2 +- cores/common/base/lt_api.c | 30 +++-- cores/common/base/lt_main.c | 2 +- cores/common/base/lt_types.h | 9 +- cores/realtek-amb/base/fixups/basic_types.h | 8 ++ .../realtek-amb/base/fixups/platform_stdlib.h | 6 +- cores/realtek-amb/base/lt_api.c | 42 +++++++ .../base/port/fal_flash_ambz_port.c | 10 +- cores/realtek-amb/base/sdk_private.h | 18 +-- cores/realtek-ambz/base/lt_api.c | 15 --- cores/realtek-ambz/base/sdk_extern.h | 14 +++ cores/realtek-ambz2/base/fixups/strproc.c | 4 +- cores/realtek-ambz2/base/lt_api.c | 106 +++++++++++++++++- cores/realtek-ambz2/base/sdk_extern.h | 26 +++++ docs/resources/documents.md | 2 +- 16 files changed, 246 insertions(+), 52 deletions(-) create mode 100644 cores/realtek-amb/base/lt_api.c create mode 100644 cores/realtek-ambz/base/sdk_extern.h create mode 100644 cores/realtek-ambz2/base/sdk_extern.h diff --git a/cores/beken-72xx/base/lt_api.c b/cores/beken-72xx/base/lt_api.c index c8994e9..1191cb2 100644 --- a/cores/beken-72xx/base/lt_api.c +++ b/cores/beken-72xx/base/lt_api.c @@ -29,10 +29,6 @@ lt_cpu_model_t lt_cpu_get_model() { return CPU_MODEL_ENUM(FAMILY, chipId); } -uint32_t lt_cpu_get_unique_id() { - return lt_cpu_get_mac_id(); -} - uint32_t lt_cpu_get_mac_id() { uint8_t mac[6]; cfg_load_mac(mac); // force loading MAC from TLV (ignore user-set WiFi MAC) diff --git a/cores/common/base/api/lt_device.h b/cores/common/base/api/lt_device.h index d57560e..36e9a14 100644 --- a/cores/common/base/api/lt_device.h +++ b/cores/common/base/api/lt_device.h @@ -15,7 +15,7 @@ const char *lt_get_version(); const char *lt_get_board_code(); /** - * @brief Get device friendly name in format "LT--". + * @brief Get device friendly name in format "LT--". * Can be used as hostname. */ const char *lt_get_device_name(); diff --git a/cores/common/base/lt_api.c b/cores/common/base/lt_api.c index 7259fd0..df0e15d 100644 --- a/cores/common/base/lt_api.c +++ b/cores/common/base/lt_api.c @@ -35,6 +35,10 @@ const char *lt_cpu_get_model_code() { return STRINGIFY_MACRO(MCULC); } +__attribute__((weak)) uint32_t lt_cpu_get_unique_id() { + return lt_cpu_get_mac_id(); +} + __attribute__((weak)) uint8_t lt_cpu_get_core_count() { return 1; } @@ -85,6 +89,12 @@ const char *lt_get_device_name() { return device_name; } +__attribute__((weak)) void lt_reboot() { + // The Watchdog Way + lt_wdt_enable(1L); + while (1) {} +} + __attribute__((weak)) bool lt_reboot_wdt() { if (!lt_wdt_enable(1L)) return false; @@ -95,24 +105,30 @@ __attribute__((weak)) bool lt_reboot_download_mode() { return false; } +__attribute__((weak)) lt_reboot_reason_t lt_get_reboot_reason() { + return REBOOT_REASON_UNKNOWN; +} + const char *lt_get_reboot_reason_name(lt_reboot_reason_t reason) { if (!reason) reason = lt_get_reboot_reason(); switch (reason) { - case RESET_REASON_POWER: + case REBOOT_REASON_POWER: return "Power-On"; - case RESET_REASON_BROWNOUT: + case REBOOT_REASON_BROWNOUT: return "Brownout"; - case RESET_REASON_HARDWARE: + case REBOOT_REASON_HARDWARE: return "HW Reboot"; - case RESET_REASON_SOFTWARE: + case REBOOT_REASON_SOFTWARE: return "SW Reboot"; - case RESET_REASON_WATCHDOG: + case REBOOT_REASON_WATCHDOG: return "WDT Reset"; - case RESET_REASON_CRASH: + case REBOOT_REASON_CRASH: return "Crash"; - case RESET_REASON_SLEEP: + case REBOOT_REASON_SLEEP: return "Sleep Wakeup"; + case REBOOT_REASON_DEBUGGER: + return "Debugger"; default: return "Unknown"; } diff --git a/cores/common/base/lt_main.c b/cores/common/base/lt_main.c index 92a4bd0..c66eefe 100644 --- a/cores/common/base/lt_main.c +++ b/cores/common/base/lt_main.c @@ -20,7 +20,7 @@ int lt_main(void) { // initialize C library __libc_init_array(); // inform about the reset reason - LT_I("Reset reason: %u", lt_get_reboot_reason()); + LT_I("Reset reason: %s", lt_get_reboot_reason_name(0)); // initialize FAL fal_init(); // provide root partition diff --git a/cores/common/base/lt_types.h b/cores/common/base/lt_types.h index 1f280f1..8d65618 100644 --- a/cores/common/base/lt_types.h +++ b/cores/common/base/lt_types.h @@ -40,8 +40,10 @@ typedef enum { RTL8711BU = CPU_MODEL(F_RTL8710B, 0xFC), // CHIPID_8711BG / QFN68 MX1290 = RTL8710BN, MX1290V2 = RTL8710BX, - // Realtek AmebaZ2 - RTL8720CF = CPU_MODEL(F_RTL8720C, 0x00), // TODO + // Realtek AmebaZ2 (chip_id << 2 | flash_mode) + RTL8720CM = CPU_MODEL(F_RTL8720C, 0xEC), // 0xFB << 2 | 0 + RTL8720CF = CPU_MODEL(F_RTL8720C, 0xED), // 0xFB << 2 | 1 + RTL8720CX = RTL8720CM, // Beken 72XX BK7231T = CPU_MODEL(F_BK7231U, 0x1A), // *SCTRL_CHIP_ID = 0x7231a BK7231N = CPU_MODEL(F_BK7231N, 0x1C), // *SCTRL_CHIP_ID = 0x7231c @@ -63,7 +65,8 @@ typedef enum { REBOOT_REASON_WATCHDOG = 6, REBOOT_REASON_CRASH = 7, REBOOT_REASON_SLEEP = 8, - REBOOT_REASON_MAX = 9, + REBOOT_REASON_DEBUGGER = 9, + REBOOT_REASON_MAX = 10, } lt_reboot_reason_t; /** diff --git a/cores/realtek-amb/base/fixups/basic_types.h b/cores/realtek-amb/base/fixups/basic_types.h index 600279d..8b00424 100644 --- a/cores/realtek-amb/base/fixups/basic_types.h +++ b/cores/realtek-amb/base/fixups/basic_types.h @@ -4,5 +4,13 @@ #ifdef ARDUINO #define boolean boolean_rtl #endif + +#include + +#ifndef bool +#define bool bool +#endif + #include_next "basic_types.h" + #undef boolean diff --git a/cores/realtek-amb/base/fixups/platform_stdlib.h b/cores/realtek-amb/base/fixups/platform_stdlib.h index 1d7af6b..170a1ab 100644 --- a/cores/realtek-amb/base/fixups/platform_stdlib.h +++ b/cores/realtek-amb/base/fixups/platform_stdlib.h @@ -16,9 +16,11 @@ #include #include "basic_types.h" // fixup: replaces typedef boolean for Arduino compatibility -#ifdef LT_RTL8710B -#include "memproc.h" // fixup: redirects to stdlib +#if __has_include() +#include // fixup: redirects to stdlib #endif +#if __has_include() #include "strproc.h" // fixup: redirects to stdlib +#endif #include "diag.h" diff --git a/cores/realtek-amb/base/lt_api.c b/cores/realtek-amb/base/lt_api.c new file mode 100644 index 0000000..8e2ff6a --- /dev/null +++ b/cores/realtek-amb/base/lt_api.c @@ -0,0 +1,42 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-05-23. */ + +#include +#include + +/*______ _ _ + | ____| | | | + | |__ | | __ _ ___| |__ + | __| | |/ _` / __| '_ \ + | | | | (_| \__ \ | | | + |_| |_|\__,_|___/_| |*/ +lt_flash_id_t lt_flash_get_id() { + lt_flash_id_t id; + uint8_t idBytes[3]; + flash_read_id(<_flash_obj, idBytes, 3); + id.manufacturer_id = idBytes[0]; + id.chip_id = idBytes[1]; + id.chip_size_id = idBytes[2]; + return id; +} + +/*_ __ _ _ _ + \ \ / / | | | | | | + \ \ /\ / /_ _| |_ ___| |__ __| | ___ __ _ + \ \/ \/ / _` | __/ __| '_ \ / _` |/ _ \ / _` | + \ /\ / (_| | || (__| | | | (_| | (_) | (_| | + \/ \/ \__,_|\__\___|_| |_|\__,_|\___/ \__, | + __/ | + |___*/ +bool lt_wdt_enable(uint32_t timeout) { + watchdog_init(timeout); + watchdog_start(); + return true; +} + +void lt_wdt_disable() { + watchdog_stop(); +} + +void lt_wdt_feed() { + watchdog_refresh(); +} diff --git a/cores/realtek-amb/base/port/fal_flash_ambz_port.c b/cores/realtek-amb/base/port/fal_flash_ambz_port.c index 8eb033d..9cf5f0a 100644 --- a/cores/realtek-amb/base/port/fal_flash_ambz_port.c +++ b/cores/realtek-amb/base/port/fal_flash_ambz_port.c @@ -7,26 +7,26 @@ #define FLASH_ERASE_MIN_SIZE (4 * 1024) -static flash_t flash_obj; +flash_t lt_flash_obj; static int init() { - flash_get_status(&flash_obj); + flash_get_status(<_flash_obj); return 0; } static int read(long offset, uint8_t *buf, size_t size) { - return size * flash_stream_read(&flash_obj, offset, size, buf); + return size * flash_stream_read(<_flash_obj, offset, size, buf); } static int write(long offset, const uint8_t *buf, size_t size) { - return size * flash_stream_write(&flash_obj, offset, size, (uint8_t *)buf); + return size * flash_stream_write(<_flash_obj, offset, size, (uint8_t *)buf); } static int erase(long offset, size_t size) { offset &= ~(FLASH_ERASE_MIN_SIZE - 1); size = ((size - 1) / FLASH_ERASE_MIN_SIZE) + 1; for (uint16_t i = 0; i < size; i++) { - flash_erase_sector(&flash_obj, offset + i * FLASH_ERASE_MIN_SIZE); + flash_erase_sector(<_flash_obj, offset + i * FLASH_ERASE_MIN_SIZE); } return size * FLASH_ERASE_MIN_SIZE; } diff --git a/cores/realtek-amb/base/sdk_private.h b/cores/realtek-amb/base/sdk_private.h index ffda530..aaf51af 100644 --- a/cores/realtek-amb/base/sdk_private.h +++ b/cores/realtek-amb/base/sdk_private.h @@ -21,6 +21,7 @@ extern "C" { #endif #if LT_RTL8720C #include +#include #include #endif @@ -30,6 +31,10 @@ extern "C" { #include #include +#include +#if LT_RTL8720C +#include +#endif #include #include #include @@ -43,6 +48,10 @@ extern "C" { #include #include +#if __has_include() +#include +#endif + // remove previously defined workarounds #undef PinMode @@ -67,14 +76,7 @@ extern "C" { #define _write __rtl_write #define _sbrk __rtl_sbrk -#define delay_us wait_us - -extern void wait_us(int us); -extern int LOGUART_SetBaud(uint32_t BaudRate); // from fixups/log_uart.c -extern void DumpForOneBytes(void *addr, int cnt); // cnt max 0x70! -extern void SystemCoreClockUpdate(void); - -extern int _sscanf_patch(const char *buf, const char *fmt, ...); +extern flash_t lt_flash_obj; #ifdef __cplusplus } // extern "C" diff --git a/cores/realtek-ambz/base/lt_api.c b/cores/realtek-ambz/base/lt_api.c index a225a14..94624e6 100644 --- a/cores/realtek-ambz/base/lt_api.c +++ b/cores/realtek-ambz/base/lt_api.c @@ -27,10 +27,6 @@ lt_cpu_model_t lt_cpu_get_model() { return CPU_MODEL_ENUM(FAMILY, chipId); } -uint32_t lt_cpu_get_unique_id() { - return lt_cpu_get_mac_id(); -} - uint32_t lt_cpu_get_mac_id() { uint32_t chipId = 0; uint8_t *id = (uint8_t *)&chipId; @@ -61,12 +57,6 @@ uint32_t lt_cpu_get_freq() { | | | |/ _ \ \ / / |/ __/ _ \ | |__| | __/\ V /| | (_| __/ |_____/ \___| \_/ |_|\___\__*/ -void lt_reboot() { - // The Watchdog Way - lt_wdt_enable(1L); - while (1) {} -} - bool lt_reboot_download_mode() { // mww 0x40000138 0x8 HAL_WRITE32(SYSTEM_CTRL_BASE, REG_SYS_NORESET_FF, 0x08); @@ -76,11 +66,6 @@ bool lt_reboot_download_mode() { return true; } -lt_reboot_reason_t lt_get_reboot_reason() { - // TODO - return REBOOT_REASON_UNKNOWN; -} - void lt_gpio_recover() { // PA14 and PA15 are apparently unusable with SWD enabled sys_jtag_off(); diff --git a/cores/realtek-ambz/base/sdk_extern.h b/cores/realtek-ambz/base/sdk_extern.h new file mode 100644 index 0000000..b03191a --- /dev/null +++ b/cores/realtek-ambz/base/sdk_extern.h @@ -0,0 +1,14 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-05-23. */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +int LOGUART_SetBaud(uint32_t BaudRate); // from fixups/log_uart.c +extern void DumpForOneBytes(void *addr, int cnt); // cnt max 0x70! + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/cores/realtek-ambz2/base/fixups/strproc.c b/cores/realtek-ambz2/base/fixups/strproc.c index 18d9de8..3feac76 100644 --- a/cores/realtek-ambz2/base/fixups/strproc.c +++ b/cores/realtek-ambz2/base/fixups/strproc.c @@ -151,7 +151,7 @@ unsigned int atoui(const char *num) { return strproc_stubs.atoui(num); } -size_t strnlen(const char *s, size_t count) { +__attribute__((weak)) size_t strnlen(const char *s, size_t count) { return strproc_stubs.strnlen(s, count); } @@ -163,6 +163,6 @@ int strnicmp(const char *s1, const char *s2, size_t len) { return strproc_stubs.strnicmp(s1, s2, len); } -char *strsep(char **s, const char *ct) { +__attribute__((weak)) char *strsep(char **s, const char *ct) { return strproc_stubs.strsep(s, ct); } diff --git a/cores/realtek-ambz2/base/lt_api.c b/cores/realtek-ambz2/base/lt_api.c index 53b838c..658a4a9 100644 --- a/cores/realtek-ambz2/base/lt_api.c +++ b/cores/realtek-ambz2/base/lt_api.c @@ -13,7 +13,107 @@ void lt_init_family() { lt_uart_port = LT_UART_DEFAULT_PORT; } -lt_reboot_reason_t lt_get_reboot_reason() { - // TODO - return REBOOT_REASON_UNKNOWN; +/* _____ _____ _ _ + / ____| __ \| | | | + | | | |__) | | | | + | | | ___/| | | | + | |____| | | |__| | + \_____|_| \____*/ +lt_cpu_model_t lt_cpu_get_model() { + uint32_t *addr = (uint32_t *)0x40000038; + uint8_t flash_mode = (addr[0] >> 5) & 0b11; + uint32_t chip_id = 0; + hal_get_chip_id(&chip_id); + chip_id <<= 2; + return CPU_MODEL_ENUM(FAMILY, (chip_id & 0xFF) | flash_mode); +} + +uint32_t lt_cpu_get_mac_id() { + uint8_t mac[3]; + efuse_logical_read(0x11A + 3, 3, mac); + return (mac[0] << 0) | (mac[1] << 8) | (mac[2] << 16); +} + +const char *lt_cpu_get_core_type() { + return "ARM Cortex-M4"; +} + +uint32_t lt_cpu_get_freq() { + return hal_syson_query_sys_clk(); +} + +/*_____ _ + | __ \ (_) + | | | | _____ ___ ___ ___ + | | | |/ _ \ \ / / |/ __/ _ \ + | |__| | __/\ V /| | (_| __/ + |_____/ \___| \_/ |_|\___\__*/ +void lt_reboot() { + sys_cpu_reset(); + while (1) {} +} + +bool lt_reboot_download_mode() { + sys_uart_download_mode(); + while (1) {} + return true; +} + +lt_reboot_reason_t lt_get_reboot_reason() { + hal_reset_reason_t reason = -1; + rtl8710c_reset_reason_get(&reason); + switch (reason) { + case HAL_RESET_REASON_POWER_ON: + return REBOOT_REASON_POWER; + case HAL_RESET_REASON_SOFTWARE: + return REBOOT_REASON_SOFTWARE; + case HAL_RESET_REASON_WATCHDOG: + return REBOOT_REASON_WATCHDOG; + case HAL_RESET_REASON_JTAG: + return REBOOT_REASON_DEBUGGER; + default: + return REBOOT_REASON_UNKNOWN; + } +} + +void lt_gpio_recover() { + sys_jtag_off(); +} + +/*__ __ + | \/ | + | \ / | ___ _ __ ___ ___ _ __ _ _ + | |\/| |/ _ \ '_ ` _ \ / _ \| '__| | | | + | | | | __/ | | | | | (_) | | | |_| | + |_| |_|\___|_| |_| |_|\___/|_| \__, | + __/ | + |__*/ +uint32_t lt_ram_get_size() { + return 256 * 1024; +} + +/* ____ _______ + / __ \__ __|/\ + | | | | | | / \ + | | | | | | / /\ \ + | |__| | | |/ ____ \ + \____/ |_/_/ \*/ +lt_ota_type_t lt_ota_get_type() { + return OTA_TYPE_DUAL; +} + +bool lt_ota_is_valid(uint8_t index) { + return false; +} + +uint8_t lt_ota_dual_get_current() { + return 0; +} + +uint8_t lt_ota_dual_get_stored() { + return 0; +} + +bool lt_ota_switch(bool revert) { + return false; } diff --git a/cores/realtek-ambz2/base/sdk_extern.h b/cores/realtek-ambz2/base/sdk_extern.h new file mode 100644 index 0000000..c0270ce --- /dev/null +++ b/cores/realtek-ambz2/base/sdk_extern.h @@ -0,0 +1,26 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-05-23. */ + +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// SDK +void software_reset(); +void sys_uart_download_mode(); +void sys_download_mode(uint8_t mode); + +// blobs +bool Hal_GetPhyEfuseMACAddr(uint32_t xFFFFE5BB, uint8_t *buf); +bool rtw_efuse_map_read(uint32_t xFFFFE5BB, uint32_t offset, uint32_t length, uint8_t *buf); +uint32_t efuse_OneByteRead(uint32_t x33300000, uint32_t addr, uint8_t *buf, uint32_t ldo); +uint32_t EFUSERead8(uint32_t x33300000, uint32_t addr, uint8_t *buf, uint32_t ldo); +uint32_t hal_get_chip_id(uint32_t *id); + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/docs/resources/documents.md b/docs/resources/documents.md index 16dd7d5..96bf276 100644 --- a/docs/resources/documents.md +++ b/docs/resources/documents.md @@ -17,4 +17,4 @@ UM0201 | [Ameba Common BT Application User Manual EN](https://raw.githubusercont   | Found elsewhere AN0400 | [Ameba-D Application Note_v3_watermark](https://files.seeedstudio.com/products/102110419/Basic%20documents/AN0400%20Ameba-D%20Application%20Note_v3_watermark.pdf) AN0500 | [Realtek Ameba-ZII application note](https://www.e-paper-display.com/99IOT/00015797-AN0500-Realtek-Ameba-ZII-application-note.en_233850.pdf) -  | [Realtek Ameba-ZII datasheet v0.8](https://www.e-paper-display.com/Ameba-Z_II_DataSheet_v0r8_RTL8720Cx_20190424%29.pdf) +  | [Realtek Ameba-ZII datasheet v0.8](https://web.archive.org/web/20230523175304if_/https://cetest02.cn-bj.ufileos.com/100001_2110255103/RTL872xZ2%20IC%20Datasheet.pdf) From 3836ad20b780ee8af2638d71f29dc7f72ece8899 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Wed, 24 May 2023 11:55:07 +0200 Subject: [PATCH 07/31] [core] Refactor SerialClass as API library --- builder/frameworks/arduino.py | 2 +- .../arduino/libraries/Serial/Serial.cpp | 66 ++------ .../arduino/libraries/Serial/SerialPrivate.h | 14 ++ cores/beken-72xx/base/lt_family.h | 4 + cores/beken-72xx/base/sdk_extern.h | 24 +++ cores/beken-72xx/base/sdk_private.h | 4 +- .../arduino/libraries/api/Serial/Serial.cpp | 34 ++++ .../arduino/libraries/api}/Serial/Serial.h | 16 +- cores/common/arduino/src/Arduino.h | 2 + cores/common/arduino/src/wiring_custom.h | 2 + .../arduino/libraries/Serial/Serial.cpp | 146 ------------------ .../arduino/libraries/Serial/Serial.h | 44 ------ cores/realtek-amb/arduino/src/lt_defs.h | 8 - cores/realtek-amb/base/fixups/basic_types.h | 3 + cores/realtek-amb/base/fixups/cmsis_ipsr.c | 5 +- .../arduino/libraries/Serial/Serial.cpp | 142 +++++++++++++++++ .../arduino/libraries/Serial/SerialPrivate.h | 21 +++ cores/realtek-ambz/arduino/src/lt_defs.h | 7 + cores/realtek-ambz/base/lt_family.h | 10 ++ cores/realtek-ambz/base/sdk_extern.h | 7 +- cores/realtek-ambz2/base/port/printf.c | 2 +- docs/TODO.md | 1 - 22 files changed, 296 insertions(+), 268 deletions(-) create mode 100644 cores/beken-72xx/arduino/libraries/Serial/SerialPrivate.h create mode 100644 cores/beken-72xx/base/sdk_extern.h create mode 100644 cores/common/arduino/libraries/api/Serial/Serial.cpp rename cores/{beken-72xx/arduino/libraries => common/arduino/libraries/api}/Serial/Serial.h (72%) delete mode 100644 cores/realtek-amb/arduino/libraries/Serial/Serial.cpp delete mode 100644 cores/realtek-amb/arduino/libraries/Serial/Serial.h create mode 100644 cores/realtek-ambz/arduino/libraries/Serial/Serial.cpp create mode 100644 cores/realtek-ambz/arduino/libraries/Serial/SerialPrivate.h create mode 100644 cores/realtek-ambz/arduino/src/lt_defs.h diff --git a/builder/frameworks/arduino.py b/builder/frameworks/arduino.py index 3d150e1..d2e0d40 100644 --- a/builder/frameworks/arduino.py +++ b/builder/frameworks/arduino.py @@ -34,7 +34,7 @@ for f in family.inheritance: code = f"{f.code}_arduino" path = join("$CORES_DIR", f.name, "arduino") - found = found or env.AddCoreSources(queue, name=code, path=join(path, "src")) + found = env.AddCoreSources(queue, name=code, path=join(path, "src")) or found env.AddArduinoLibraries(queue, name=code, path=join(path, "libraries")) if f.short_name: diff --git a/cores/beken-72xx/arduino/libraries/Serial/Serial.cpp b/cores/beken-72xx/arduino/libraries/Serial/Serial.cpp index 6e90c20..50f7bbc 100644 --- a/cores/beken-72xx/arduino/libraries/Serial/Serial.cpp +++ b/cores/beken-72xx/arduino/libraries/Serial/Serial.cpp @@ -1,18 +1,6 @@ /* Copyright (c) Kuba Szczodrzyński 2022-06-23. */ -#include "Serial.h" - -#include - -extern "C" { - -#include - -extern void bk_send_byte(uint8_t uport, uint8_t data); -extern void uart_hw_set_change(uint8_t uport, bk_uart_config_t *uart_config); -extern int uart_rx_callback_set(int uport, uart_callback callback, void *param); - -} // extern "C" +#include "SerialPrivate.h" #if HAS_SERIAL1 SerialClass Serial1(UART1_PORT); @@ -21,39 +9,22 @@ SerialClass Serial1(UART1_PORT); SerialClass Serial2(UART2_PORT); #endif -SerialClass::SerialClass(uint8_t port) { - this->port = port; - this->buf = NULL; -} - -#if LT_AUTO_DOWNLOAD_REBOOT -static uint8_t adrState = 0; -static const uint8_t adrCmd[] = {0x01, 0xE0, 0xFC, 0x01, 0x00}; - -static void adrParse(uint8_t c) { - // parse and respond to link check command (CMD_LinkCheck=0) - adrState = (adrState + 1) * (c == adrCmd[adrState]); - if (adrState == 5) { - LT_I("Auto download mode: rebooting"); - LT.restart(); - } -} -#endif - static void callback(int port, void *param) { - RingBuffer *buf = (RingBuffer *)param; int ch; while ((ch = uart_read_byte(port)) != -1) { -#if LT_AUTO_DOWNLOAD_REBOOT && defined(PIN_SERIAL1_RX) +#if LT_AUTO_DOWNLOAD_REBOOT && defined(LT_UART_ADR_PATTERN) && defined(PIN_SERIAL1_RX) // parse UART protocol commands on UART1 if (port == UART1_PORT) - adrParse(ch); + SerialClass::adrParse(ch); #endif - buf->store_char(ch); + pBUF->store_char(ch); } } void SerialClass::begin(unsigned long baudrate, uint16_t config) { + this->data = new SerialData(); + this->buf = &BUF; + uint8_t dataWidth = ((config & SERIAL_DATA_MASK) >> 8) - 1; // 0x100..0x400 -> 0..3 uint8_t parity = 3 - (config & SERIAL_PARITY_MASK); // 0x3..0x1 -> 0..2 uint8_t stopBits = (config & SERIAL_STOP_BIT_MASK) == SERIAL_STOP_BIT_2; // 0x10..0x30 -> 0..1 @@ -66,14 +37,8 @@ void SerialClass::begin(unsigned long baudrate, uint16_t config) { .flow_control = FLOW_CTRL_DISABLED, }; - if (this->buf) { - this->buf->clear(); - } else { - this->buf = new RingBuffer(); - } - uart_hw_set_change(port, &cfg); - uart_rx_callback_set(port, callback, this->buf); + uart_rx_callback_set(port, callback, &BUF); } void SerialClass::end() { @@ -86,19 +51,8 @@ void SerialClass::end() { uart2_exit(); break; } - delete this->buf; -} - -int SerialClass::available() { - return buf->available(); -} - -int SerialClass::peek() { - return buf->peek(); -} - -int SerialClass::read() { - return buf->read_char(); + this->buf = NULL; + delete DATA; } void SerialClass::flush() { diff --git a/cores/beken-72xx/arduino/libraries/Serial/SerialPrivate.h b/cores/beken-72xx/arduino/libraries/Serial/SerialPrivate.h new file mode 100644 index 0000000..c481237 --- /dev/null +++ b/cores/beken-72xx/arduino/libraries/Serial/SerialPrivate.h @@ -0,0 +1,14 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-05-24. */ + +#pragma once + +#include +#include + +typedef struct { + RingBuffer buf; +} SerialData; + +#define DATA ((SerialData *)data) +#define BUF (DATA->buf) +#define pBUF ((RingBuffer *)param) diff --git a/cores/beken-72xx/base/lt_family.h b/cores/beken-72xx/base/lt_family.h index 4484a1d..fce1aa6 100644 --- a/cores/beken-72xx/base/lt_family.h +++ b/cores/beken-72xx/base/lt_family.h @@ -14,3 +14,7 @@ #error "No serial port is available" #endif #endif + +// Auto-download-reboot detection pattern +// Link check command (CMD_LinkCheck=0) +#define LT_UART_ADR_PATTERN 0x01, 0xE0, 0xFC, 0x01, 0x00 diff --git a/cores/beken-72xx/base/sdk_extern.h b/cores/beken-72xx/base/sdk_extern.h new file mode 100644 index 0000000..08452ac --- /dev/null +++ b/cores/beken-72xx/base/sdk_extern.h @@ -0,0 +1,24 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-05-24. */ + +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#include + +// SDK +extern uint8_t system_mac[]; +extern int uart_print_port; +uint32_t wdt_ctrl(uint32_t cmd, void *param); +void bk_send_byte(uint8_t uport, uint8_t data); +void uart_hw_set_change(uint8_t uport, bk_uart_config_t *uart_config); +int uart_rx_callback_set(int uport, uart_callback callback, void *param); + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/cores/beken-72xx/base/sdk_private.h b/cores/beken-72xx/base/sdk_private.h index 41d6a56..044e2cb 100644 --- a/cores/beken-72xx/base/sdk_private.h +++ b/cores/beken-72xx/base/sdk_private.h @@ -19,9 +19,7 @@ extern "C" { #include #include -extern uint8_t system_mac[]; -extern uint32_t wdt_ctrl(uint32_t cmd, void *param); -extern int uart_print_port; +#include // conflict with stl_algobase.h #undef min diff --git a/cores/common/arduino/libraries/api/Serial/Serial.cpp b/cores/common/arduino/libraries/api/Serial/Serial.cpp new file mode 100644 index 0000000..2f64f42 --- /dev/null +++ b/cores/common/arduino/libraries/api/Serial/Serial.cpp @@ -0,0 +1,34 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-05-23. */ + +#include "Serial.h" + +SerialClass::SerialClass(uint32_t port) { + this->port = port; + this->buf = NULL; + this->data = NULL; +} + +#if LT_AUTO_DOWNLOAD_REBOOT && defined(LT_UART_ADR_PATTERN) +static uint8_t adrState = 0; +static uint8_t adrCmd[] = {LT_UART_ADR_PATTERN}; + +void SerialClass::adrParse(uint8_t c) { + adrState = (adrState + 1) * (c == adrCmd[adrState]); + if (adrState == sizeof(adrCmd) / sizeof(uint8_t)) { + LT_I("Auto download mode: rebooting"); + LT.restartDownloadMode(); + } +} +#endif + +int SerialClass::available() { + return this->buf && this->buf->available(); +} + +int SerialClass::peek() { + return this->buf ? this->buf->peek() : -1; +} + +int SerialClass::read() { + return this->buf ? this->buf->read_char() : -1; +} diff --git a/cores/beken-72xx/arduino/libraries/Serial/Serial.h b/cores/common/arduino/libraries/api/Serial/Serial.h similarity index 72% rename from cores/beken-72xx/arduino/libraries/Serial/Serial.h rename to cores/common/arduino/libraries/api/Serial/Serial.h index 5c77c4d..ca46229 100644 --- a/cores/beken-72xx/arduino/libraries/Serial/Serial.h +++ b/cores/common/arduino/libraries/api/Serial/Serial.h @@ -2,7 +2,7 @@ #pragma once -#include +#include #include #include @@ -10,11 +10,14 @@ using namespace arduino; class SerialClass : public HardwareSerial { private: - uint8_t port; + uint32_t port; RingBuffer *buf; public: - SerialClass(uint8_t port); + void *data; + + public: + SerialClass(uint32_t port); inline void begin(unsigned long baudrate) { begin(baudrate, SERIAL_8N1); @@ -32,5 +35,12 @@ class SerialClass : public HardwareSerial { return !!buf; } + public: +#if LT_AUTO_DOWNLOAD_REBOOT + static void adrParse(uint8_t c); +#endif + using Print::write; }; + +#define HAS_SERIAL_CLASS 1 diff --git a/cores/common/arduino/src/Arduino.h b/cores/common/arduino/src/Arduino.h index dec3c7e..7e3e184 100644 --- a/cores/common/arduino/src/Arduino.h +++ b/cores/common/arduino/src/Arduino.h @@ -42,6 +42,7 @@ using std::min; #if defined(__cplusplus) && LT_ARD_HAS_SERIAL #include +#if HAS_SERIAL_CLASS #if HAS_SERIAL0 extern SerialClass Serial0; #endif @@ -51,6 +52,7 @@ extern SerialClass Serial1; #if HAS_SERIAL2 extern SerialClass Serial2; #endif +#endif #define SerialN(x) Serial##x #define SerialM(x) SerialN(x) diff --git a/cores/common/arduino/src/wiring_custom.h b/cores/common/arduino/src/wiring_custom.h index 4dd43f1..392e280 100644 --- a/cores/common/arduino/src/wiring_custom.h +++ b/cores/common/arduino/src/wiring_custom.h @@ -21,6 +21,8 @@ extern "C" { #define PIN_SWD (1 << 10) #define PIN_UART (1 << 11) +#define PIN_INVALID 255 + typedef struct { /** * @brief GPIO name in the family SDK. diff --git a/cores/realtek-amb/arduino/libraries/Serial/Serial.cpp b/cores/realtek-amb/arduino/libraries/Serial/Serial.cpp deleted file mode 100644 index c387d47..0000000 --- a/cores/realtek-amb/arduino/libraries/Serial/Serial.cpp +++ /dev/null @@ -1,146 +0,0 @@ -/* Copyright (c) Kuba Szczodrzyński 2022-07-03. */ - -#include "Serial.h" - -#include -#include - -#if HAS_SERIAL0 -SerialClass Serial0(UART0_DEV, UART0_IRQ, PIN_SERIAL0_RX, PIN_SERIAL0_TX); -#endif -#if HAS_SERIAL1 -SerialClass Serial1(UART1_DEV, UART1_IRQ, PIN_SERIAL1_RX, PIN_SERIAL1_TX); -#endif -#if HAS_SERIAL2 -SerialClass Serial2(UART2_DEV, UART_LOG_IRQ, PIN_SERIAL2_RX, PIN_SERIAL2_TX); -#endif - -SerialClass::SerialClass(void *uart, uint8_t irq, pin_size_t rx, pin_size_t tx) { - data.uart = uart; - data.buf = NULL; - this->irq = irq; - this->rx = rx; - this->tx = tx; -} - -#if LT_AUTO_DOWNLOAD_REBOOT -static uint8_t adrState = 0; - -// clang-format off -// Family ID, big-endian -static const uint8_t adrCmd[] = { - 0x55, 0xAA, - (FAMILY >> 24) & 0xFF, - (FAMILY >> 16) & 0xFF, - (FAMILY >> 8) & 0xFF, - (FAMILY >> 0) & 0xFF -}; - -// clang-format on - -static void adrParse(uint8_t c) { - adrState = (adrState + 1) * (c == adrCmd[adrState]); - if (adrState == 6) { - LT_I("Auto download mode: rebooting"); - LT.restartDownloadMode(); - } -} -#endif - -static uint32_t callback(void *param) { - SerialData *data = (SerialData *)param; - UART_TypeDef *uart = (UART_TypeDef *)data->uart; - - uint32_t intcr = uart->DLH_INTCR; - uart->DLH_INTCR = 0; - - uint8_t c; - while (UART_Readable(uart)) { - UART_CharGet(uart, &c); -#if LT_AUTO_DOWNLOAD_REBOOT && defined(PIN_SERIAL2_RX) - // parse UART protocol commands on UART2 - if (uart == UART2_DEV) - adrParse(c); -#endif - data->buf->store_char(c); - } - - uart->DLH_INTCR = intcr; - return 0; -} - -void SerialClass::begin(unsigned long baudrate, uint16_t config) { - // RUART_WLS_7BITS / RUART_WLS_8BITS - uint8_t dataWidth = (config & SERIAL_DATA_MASK) == SERIAL_DATA_8; - // RUART_PARITY_DISABLE / RUART_PARITY_ENABLE - uint8_t parity = (config & SERIAL_PARITY_MASK) != SERIAL_PARITY_NONE; - // RUART_ODD_PARITY / RUART_EVEN_PARITY - uint8_t parityType = (config & SERIAL_PARITY_MASK) == SERIAL_PARITY_EVEN; - // RUART_STOP_BIT_1 / RUART_STOP_BIT_2 - uint8_t stopBits = (config & SERIAL_STOP_BIT_MASK) == SERIAL_STOP_BIT_2; - - switch ((uint32_t)data.uart) { - case UART0_REG_BASE: - RCC_PeriphClockCmd(APBPeriph_UART0, APBPeriph_UART0_CLOCK, ENABLE); - break; - case UART1_REG_BASE: - RCC_PeriphClockCmd(APBPeriph_UART1, APBPeriph_UART1_CLOCK, ENABLE); - break; - } - - Pinmux_Config(pinInfo(this->rx)->gpio, PINMUX_FUNCTION_UART); - Pinmux_Config(pinInfo(this->tx)->gpio, PINMUX_FUNCTION_UART); - PAD_PullCtrl(pinInfo(this->rx)->gpio, GPIO_PuPd_UP); - - UART_InitTypeDef cfg; - UART_StructInit(&cfg); - cfg.WordLen = dataWidth; - cfg.Parity = parity; - cfg.ParityType = parityType; - cfg.StopBit = stopBits; - UART_Init((UART_TypeDef *)data.uart, &cfg); - UART_SetBaud((UART_TypeDef *)data.uart, baudrate); - - if (data.buf) { - data.buf->clear(); - } else { - data.buf = new RingBuffer(); - } - - VECTOR_IrqUnRegister(this->irq); - VECTOR_IrqRegister(callback, this->irq, (uint32_t)&data, 10); - VECTOR_IrqEn(this->irq, 10); - - UART_RxCmd((UART_TypeDef *)data.uart, ENABLE); - UART_INTConfig((UART_TypeDef *)data.uart, RUART_IER_ERBI, ENABLE); -} - -void SerialClass::end() { - if (data.uart == UART2_DEV) { - // restore command line mode - DIAG_UartReInit((IRQ_FUN)UartLogIrqHandle); - } - delete data.buf; -} - -int SerialClass::available() { - return data.buf->available(); -} - -int SerialClass::peek() { - return data.buf->peek(); -} - -int SerialClass::read() { - return data.buf->read_char(); -} - -void SerialClass::flush() { - UART_WaitBusy((UART_TypeDef *)data.uart, 10); -} - -size_t SerialClass::write(uint8_t c) { - while (UART_Writable((UART_TypeDef *)data.uart) == 0) {} - UART_CharPut((UART_TypeDef *)data.uart, c); - return 1; -} diff --git a/cores/realtek-amb/arduino/libraries/Serial/Serial.h b/cores/realtek-amb/arduino/libraries/Serial/Serial.h deleted file mode 100644 index aa0a78b..0000000 --- a/cores/realtek-amb/arduino/libraries/Serial/Serial.h +++ /dev/null @@ -1,44 +0,0 @@ -/* Copyright (c) Kuba Szczodrzyński 2022-07-03. */ - -#pragma once - -#include -#include -#include - -using namespace arduino; - -typedef struct { - void *uart; // UART_TypeDef - RingBuffer *buf; -} SerialData; - -class SerialClass : public HardwareSerial { - private: - // data accessible to IRQ handler - SerialData data; - uint8_t irq; // IRQn - pin_size_t rx; - pin_size_t tx; - - public: - SerialClass(void *uart, uint8_t irq, pin_size_t rx, pin_size_t tx); - - inline void begin(unsigned long baudrate) { - begin(baudrate, SERIAL_8N1); - } - - void begin(unsigned long baudrate, uint16_t config); - void end(); - int available(); - int peek(); - int read(); - void flush(); - size_t write(uint8_t c); - - operator bool() { - return !!data.buf; - } - - using Print::write; -}; diff --git a/cores/realtek-amb/arduino/src/lt_defs.h b/cores/realtek-amb/arduino/src/lt_defs.h index 2083962..948ea56 100644 --- a/cores/realtek-amb/arduino/src/lt_defs.h +++ b/cores/realtek-amb/arduino/src/lt_defs.h @@ -4,13 +4,5 @@ #define LT_ARD_HAS_WIFI 1 #define LT_ARD_HAS_SOFTSERIAL 1 -#define LT_ARD_HAS_SERIAL 1 - -#define LT_ARD_MD5_POLARSSL 1 #define ARDUINO_AMEBA - -// the SDK declares bool if not defined before -// which conflicts with C++ built-in bool -// so it's either -fpermissive or this: -#define bool bool diff --git a/cores/realtek-amb/base/fixups/basic_types.h b/cores/realtek-amb/base/fixups/basic_types.h index 8b00424..c9a7f10 100644 --- a/cores/realtek-amb/base/fixups/basic_types.h +++ b/cores/realtek-amb/base/fixups/basic_types.h @@ -7,6 +7,9 @@ #include +// the SDK declares bool if not defined before +// which conflicts with C++ built-in bool +// so it's either -fpermissive or this: #ifndef bool #define bool bool #endif diff --git a/cores/realtek-amb/base/fixups/cmsis_ipsr.c b/cores/realtek-amb/base/fixups/cmsis_ipsr.c index d6307fd..7819c32 100644 --- a/cores/realtek-amb/base/fixups/cmsis_ipsr.c +++ b/cores/realtek-amb/base/fixups/cmsis_ipsr.c @@ -4,9 +4,8 @@ // for some reason, cmsis_os.c does not link properly when this method is inlined in core_cmFunc.h // (or I am too stupid to understand this) -__attribute__((weak)) uint32_t __get_IPSR() -{ +__attribute__((weak)) uint32_t __get_IPSR() { uint32_t result; - asm volatile ("MRS %0, ipsr" : "=r" (result) ); + asm volatile("MRS %0, ipsr" : "=r"(result)); return result; } diff --git a/cores/realtek-ambz/arduino/libraries/Serial/Serial.cpp b/cores/realtek-ambz/arduino/libraries/Serial/Serial.cpp new file mode 100644 index 0000000..c4bbde3 --- /dev/null +++ b/cores/realtek-ambz/arduino/libraries/Serial/Serial.cpp @@ -0,0 +1,142 @@ +/* Copyright (c) Kuba Szczodrzyński 2022-07-03. */ + +#include "SerialPrivate.h" + +#if HAS_SERIAL0 +SerialClass Serial0(0); +#endif +#if HAS_SERIAL1 +SerialClass Serial1(1); +#endif +#if HAS_SERIAL2 +SerialClass Serial2(2); +#endif + +static UART_TypeDef *PORT_UART[3] = {UART0_DEV, UART1_DEV, UART2_DEV}; +static const IRQn PORT_IRQ[3] = {UART0_IRQ, UART1_IRQ, UART_LOG_IRQ}; +static const pin_size_t PORT_RX[3] = { +#ifdef PIN_SERIAL0_RX + PIN_SERIAL0_RX, +#else + PIN_INVALID, +#endif +#ifdef PIN_SERIAL1_RX + PIN_SERIAL1_RX, +#else + PIN_INVALID, +#endif +#ifdef PIN_SERIAL2_RX + PIN_SERIAL2_RX, +#else + PIN_INVALID, +#endif +}; +static const pin_size_t PORT_TX[3] = { +#ifdef PIN_SERIAL0_TX + PIN_SERIAL0_TX, +#else + PIN_INVALID, +#endif +#ifdef PIN_SERIAL1_TX + PIN_SERIAL1_TX, +#else + PIN_INVALID, +#endif +#ifdef PIN_SERIAL2_TX + PIN_SERIAL2_TX, +#else + PIN_INVALID, +#endif +}; + +static uint32_t callback(void *param) { + UART_TypeDef *uart = pdUART; + + uint32_t intcr = uart->DLH_INTCR; + uart->DLH_INTCR = 0; + + uint8_t c; + while (UART_Readable(uart)) { + UART_CharGet(uart, &c); +#if LT_AUTO_DOWNLOAD_REBOOT && defined(LT_UART_ADR_PATTERN) && defined(PIN_SERIAL2_RX) + // parse UART protocol commands on UART2 + if (uart == UART2_DEV) + SerialClass::adrParse(c); +#endif + pdBUF.store_char(c); + } + + uart->DLH_INTCR = intcr; + return 0; +} + +void SerialClass::begin(unsigned long baudrate, uint16_t config) { + this->data = new SerialData(); + this->buf = &BUF; + DATA->uart = PORT_UART[this->port]; + DATA->irq = PORT_IRQ[this->port]; + DATA->rx = PORT_RX[this->port]; + DATA->tx = PORT_TX[this->port]; + + // RUART_WLS_7BITS / RUART_WLS_8BITS + uint8_t dataWidth = (config & SERIAL_DATA_MASK) == SERIAL_DATA_8; + // RUART_PARITY_DISABLE / RUART_PARITY_ENABLE + uint8_t parity = (config & SERIAL_PARITY_MASK) != SERIAL_PARITY_NONE; + // RUART_ODD_PARITY / RUART_EVEN_PARITY + uint8_t parityType = (config & SERIAL_PARITY_MASK) == SERIAL_PARITY_EVEN; + // RUART_STOP_BIT_1 / RUART_STOP_BIT_2 + uint8_t stopBits = (config & SERIAL_STOP_BIT_MASK) == SERIAL_STOP_BIT_2; + + switch ((uint32_t)DATA->uart) { + case UART0_REG_BASE: + RCC_PeriphClockCmd(APBPeriph_UART0, APBPeriph_UART0_CLOCK, ENABLE); + break; + case UART1_REG_BASE: + RCC_PeriphClockCmd(APBPeriph_UART1, APBPeriph_UART1_CLOCK, ENABLE); + break; + } + + if (DATA->tx != PIN_INVALID) { + Pinmux_Config(DATA->tx, PINMUX_FUNCTION_UART); + } + if (DATA->rx != PIN_INVALID) { + Pinmux_Config(DATA->rx, PINMUX_FUNCTION_UART); + PAD_PullCtrl(DATA->rx, GPIO_PuPd_UP); + } + + UART_InitTypeDef cfg; + UART_StructInit(&cfg); + cfg.WordLen = dataWidth; + cfg.Parity = parity; + cfg.ParityType = parityType; + cfg.StopBit = stopBits; + UART_Init(UART, &cfg); + UART_SetBaud(UART, baudrate); + + if (DATA->rx != PIN_INVALID) { + VECTOR_IrqUnRegister(DATA->irq); + VECTOR_IrqRegister(callback, DATA->irq, (uint32_t)&data, 10); + VECTOR_IrqEn(DATA->irq, 10); + UART_RxCmd(UART, ENABLE); + UART_INTConfig(UART, RUART_IER_ERBI, ENABLE); + } +} + +void SerialClass::end() { + if (UART == UART2_DEV) { + // restore command line mode + DIAG_UartReInit((IRQ_FUN)UartLogIrqHandle); + } + this->buf = NULL; + delete DATA; +} + +void SerialClass::flush() { + UART_WaitBusy(UART, 10); +} + +size_t SerialClass::write(uint8_t c) { + while (UART_Writable(UART) == 0) {} + UART_CharPut(UART, c); + return 1; +} diff --git a/cores/realtek-ambz/arduino/libraries/Serial/SerialPrivate.h b/cores/realtek-ambz/arduino/libraries/Serial/SerialPrivate.h new file mode 100644 index 0000000..aba22e7 --- /dev/null +++ b/cores/realtek-ambz/arduino/libraries/Serial/SerialPrivate.h @@ -0,0 +1,21 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-05-23. */ + +#pragma once + +#include +#include + +typedef struct { + UART_TypeDef *uart; + IRQn irq; + pin_size_t rx; + pin_size_t tx; + RingBuffer buf; +} SerialData; + +#define DATA ((SerialData *)data) +#define pDATA ((SerialData *)param) +#define BUF (DATA->buf) +#define pdBUF (pDATA->buf) +#define UART (DATA->uart) +#define pdUART (pDATA->uart) diff --git a/cores/realtek-ambz/arduino/src/lt_defs.h b/cores/realtek-ambz/arduino/src/lt_defs.h new file mode 100644 index 0000000..aff5c9b --- /dev/null +++ b/cores/realtek-ambz/arduino/src/lt_defs.h @@ -0,0 +1,7 @@ +#pragma once + +#error "Don't include this file directly" + +#define LT_ARD_HAS_SERIAL 1 + +#define LT_ARD_MD5_POLARSSL 1 diff --git a/cores/realtek-ambz/base/lt_family.h b/cores/realtek-ambz/base/lt_family.h index 9723ffb..3a25b48 100644 --- a/cores/realtek-ambz/base/lt_family.h +++ b/cores/realtek-ambz/base/lt_family.h @@ -16,3 +16,13 @@ #error "No serial port is available" #endif #endif + +// clang-format off +// Auto-download-reboot detection pattern +// Family ID, big-endian +#define LT_UART_ADR_PATTERN 0x55, 0xAA, \ + (FAMILY >> 24) & 0xFF, \ + (FAMILY >> 16) & 0xFF, \ + (FAMILY >> 8) & 0xFF, \ + (FAMILY >> 0) & 0xFF +// clang-format on diff --git a/cores/realtek-ambz/base/sdk_extern.h b/cores/realtek-ambz/base/sdk_extern.h index b03191a..131f623 100644 --- a/cores/realtek-ambz/base/sdk_extern.h +++ b/cores/realtek-ambz/base/sdk_extern.h @@ -2,12 +2,15 @@ #pragma once +#include +#include + #ifdef __cplusplus extern "C" { #endif // __cplusplus -int LOGUART_SetBaud(uint32_t BaudRate); // from fixups/log_uart.c -extern void DumpForOneBytes(void *addr, int cnt); // cnt max 0x70! +int LOGUART_SetBaud(uint32_t BaudRate); // from fixups/log_uart.c +void DumpForOneBytes(void *addr, int cnt); // cnt max 0x70! #ifdef __cplusplus } // extern "C" diff --git a/cores/realtek-ambz2/base/port/printf.c b/cores/realtek-ambz2/base/port/printf.c index 1ec6a0b..f3aa09b 100644 --- a/cores/realtek-ambz2/base/port/printf.c +++ b/cores/realtek-ambz2/base/port/printf.c @@ -19,7 +19,7 @@ void putchar_(char c) { } void putchar_p(char c, unsigned long port) { - while (uart_dev[port]->lsr_b.txfifo_empty == 0) {} + while ((uart_dev[port]->tflvr & 0x1F) > 15) {} uart_dev[port]->thr = c; } diff --git a/docs/TODO.md b/docs/TODO.md index 937adbc..1d69e48 100644 --- a/docs/TODO.md +++ b/docs/TODO.md @@ -43,7 +43,6 @@ Explicit is better than implicit. ### Other -- refactor `SerialClass` to have a shared header `Serial.h` in the common core (and `SerialData`, just like WiFi). Move ADR to common core - implement Wire on BK, refactor the API and class - watchdog API - `Preferences` library From bc74c21599cd579472776596d2fdb207eec4a07e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Wed, 24 May 2023 13:02:33 +0200 Subject: [PATCH 08/31] [realtek-ambz2] Enable compilation of Arduino core --- builder/frameworks/arduino.py | 1 - builder/utils/config.py | 16 ++++++++++++---- .../arduino/libraries/common/mDNS/LwIPmDNS.cpp | 8 ++++++++ cores/common/arduino/src/Arduino.h | 1 + cores/common/base/config/lwipopts.h | 3 +++ cores/realtek-amb/arduino/src/main.cpp | 5 +---- cores/realtek-amb/arduino/src/wiring_pulse.c | 4 ++-- cores/realtek-amb/base/sdk_private.h | 5 +++++ cores/realtek-ambz2/base/config/platform_conf.h | 3 +++ 9 files changed, 35 insertions(+), 11 deletions(-) diff --git a/builder/frameworks/arduino.py b/builder/frameworks/arduino.py index d2e0d40..1281079 100644 --- a/builder/frameworks/arduino.py +++ b/builder/frameworks/arduino.py @@ -73,7 +73,6 @@ queue.AppendPublic( ("ARDUINO_SDK", 1), ], LINKFLAGS=[ - "--specs=nosys.specs", "-Wl,--as-needed", "-Wl,--build-id=none", "-Wl,--cref", diff --git a/builder/utils/config.py b/builder/utils/config.py index 8a49589..8ebf701 100644 --- a/builder/utils/config.py +++ b/builder/utils/config.py @@ -20,13 +20,21 @@ def env_load_defines(env: Environment, path: str): line = line[7:].strip() line = line.split(None, 2) if len(line) == 1: - env.Append(CPPDEFINES=[(line[0], 1)]) - config[line[0]] = 1 + key, value = line[0], 1 elif len(line) == 2: - env.Append(CPPDEFINES=[(line[0], line[1])]) - config[line[0]] = line[1] + key, value = line[0], line[1] else: raise ValueError(f"Unknown directive: {line}") + for tpl in env["CPPDEFINES"]: + if isinstance(tpl, tuple): + k = tpl[0] + else: + k = tpl + if k == key: + env["CPPDEFINES"].remove(tpl) + break + env.Append(CPPDEFINES=[(key, value)]) + config[key] = value env.Append( CONFIG=config, ) diff --git a/cores/common/arduino/libraries/common/mDNS/LwIPmDNS.cpp b/cores/common/arduino/libraries/common/mDNS/LwIPmDNS.cpp index 40c16ca..f69eb04 100644 --- a/cores/common/arduino/libraries/common/mDNS/LwIPmDNS.cpp +++ b/cores/common/arduino/libraries/common/mDNS/LwIPmDNS.cpp @@ -13,6 +13,8 @@ extern "C" { #include } +#if LWIP_MDNS_RESPONDER + static std::vector services_name; static std::vector services; static std::vector protos; @@ -81,7 +83,11 @@ static bool enableMDNS(struct netif *netif) { err_t ret = mdns_resp_add_netif(netif, hostName, 255); if (ret == ERR_OK) { LT_DM(MDNS, "mDNS started on netif %u, announcing it to network", netif->num); +#if LWIP_VERSION_SIMPLE >= 20100 mdns_resp_announce(netif); +#else +#warning "lwIP version older than 2.1.0, mdns_resp_announce() unavailable" +#endif return true; } else { LT_DM(MDNS, "Cannot start mDNS on netif %u; ret=%d, errno=%d", netif->num, ret, errno); @@ -188,3 +194,5 @@ bool mDNS::addServiceTxtImpl(const char *service, uint8_t proto, const char *ite MDNSResponder MDNS; #endif + +#endif diff --git a/cores/common/arduino/src/Arduino.h b/cores/common/arduino/src/Arduino.h index 7e3e184..cdda136 100644 --- a/cores/common/arduino/src/Arduino.h +++ b/cores/common/arduino/src/Arduino.h @@ -25,6 +25,7 @@ using std::min; #include #ifdef __cplusplus #include +using namespace arduino; #endif // Include family-specific code diff --git a/cores/common/base/config/lwipopts.h b/cores/common/base/config/lwipopts.h index 833df85..2557d02 100644 --- a/cores/common/base/config/lwipopts.h +++ b/cores/common/base/config/lwipopts.h @@ -33,6 +33,9 @@ // clang-format on #endif +// lwIP version as a decimal number, with 2 digits for each part (major, minor, patch) +#define LWIP_VERSION_SIMPLE (LWIP_VERSION_MAJOR * 10000 + LWIP_VERSION_MINOR * 100 + LWIP_VERSION_REVISION) + // remove family-defined debugging options (use lwIP defaults, or user-defined) #undef ETHARP_DEBUG #undef NETIF_DEBUG diff --git a/cores/realtek-amb/arduino/src/main.cpp b/cores/realtek-amb/arduino/src/main.cpp index 9587dc7..7db967f 100644 --- a/cores/realtek-amb/arduino/src/main.cpp +++ b/cores/realtek-amb/arduino/src/main.cpp @@ -5,12 +5,9 @@ extern "C" { -#include -#include - osThreadId main_tid = 0; -#if LT_AUTO_DOWNLOAD_REBOOT && defined(PIN_SERIAL2_RX) && defined(PIN_SERIAL2_TX) +#if LT_AUTO_DOWNLOAD_REBOOT && LT_ARD_HAS_SERIAL && defined(PIN_SERIAL2_RX) && defined(PIN_SERIAL2_TX) void lt_init_arduino() { // initialize auto-download-reboot parser Serial2.begin(115200); diff --git a/cores/realtek-amb/arduino/src/wiring_pulse.c b/cores/realtek-amb/arduino/src/wiring_pulse.c index 85161e6..83aeed9 100644 --- a/cores/realtek-amb/arduino/src/wiring_pulse.c +++ b/cores/realtek-amb/arduino/src/wiring_pulse.c @@ -31,14 +31,14 @@ extern unsigned long pulseIn(uint8_t pinNumber, uint8_t state, unsigned long tim // digitalRead() instead yields much coarser resolution. PinInfo *pin = pinInfo(pinNumber); if (pin == NULL) - return; + return 0; uint32_t index = pinIndex(pin); gpio_t *pGpio_t; uint32_t start_ticks, cur_ticks; - if (pin < 0 || pin > PINS_COUNT || (pin->gpio == NC)) + if (pin->gpio == NC) return 0; /* Handle */ diff --git a/cores/realtek-amb/base/sdk_private.h b/cores/realtek-amb/base/sdk_private.h index aaf51af..d3bbf01 100644 --- a/cores/realtek-amb/base/sdk_private.h +++ b/cores/realtek-amb/base/sdk_private.h @@ -14,6 +14,7 @@ extern "C" { // remove log_printf() if included before sdk_private.h #undef log_printf +// CMSIS & Realtek APIs #if LT_RTL8710B #include #include @@ -25,6 +26,9 @@ extern "C" { #include #endif +#include + +// mbed APIs #include #undef MBED_GPIO_API_H // ..no comment #include @@ -48,6 +52,7 @@ extern "C" { #include #include +// other SDK APIs #if __has_include() #include #endif diff --git a/cores/realtek-ambz2/base/config/platform_conf.h b/cores/realtek-ambz2/base/config/platform_conf.h index 4b5d67d..fbf831f 100644 --- a/cores/realtek-ambz2/base/config/platform_conf.h +++ b/cores/realtek-ambz2/base/config/platform_conf.h @@ -17,3 +17,6 @@ #define DBG_SCE_ERR(...) #define DBG_SCE_WARN(...) #define DBG_SCE_INFO(...) + +// ...? +#define CONFIG_ADC_EN From e5f98ff41f690c5d4de9648db2c4f880aa7e2761 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Wed, 24 May 2023 18:20:22 +0200 Subject: [PATCH 09/31] [core] Refactor Wiring, use PinData for parameters --- cores/beken-72xx/arduino/src/wiring.c | 35 ++++--- cores/beken-72xx/arduino/src/wiring_analog.c | 32 ++---- cores/beken-72xx/arduino/src/wiring_data.h | 23 +++++ cores/beken-72xx/arduino/src/wiring_digital.c | 51 ++++------ cores/beken-72xx/arduino/src/wiring_irq.c | 98 +++++++------------ cores/beken-72xx/base/sdk_private.h | 8 +- cores/common/arduino/src/wiring.c | 17 ++++ cores/common/arduino/src/wiring_custom.c | 28 +++--- cores/common/arduino/src/wiring_custom.h | 20 +++- cores/common/arduino/src/wiring_irq.c | 7 ++ cores/common/arduino/src/wiring_private.c | 25 +++++ cores/common/arduino/src/wiring_private.h | 64 ++++++++++++ cores/realtek-amb/arduino/src/Tone.cpp | 12 --- cores/realtek-amb/arduino/src/wiring.c | 67 +++++-------- cores/realtek-amb/arduino/src/wiring_analog.c | 72 +++++--------- cores/realtek-amb/arduino/src/wiring_data.h | 24 +++++ .../realtek-amb/arduino/src/wiring_digital.c | 95 +++++------------- cores/realtek-amb/arduino/src/wiring_irq.c | 95 ++++++++---------- cores/realtek-amb/arduino/src/wiring_pulse.c | 13 +-- cores/realtek-amb/base/sdk_private.h | 3 + cores/realtek-ambz2/base/lt_api.c | 1 + cores/realtek-ambz2/base/sdk_extern.h | 1 + 22 files changed, 397 insertions(+), 394 deletions(-) create mode 100644 cores/beken-72xx/arduino/src/wiring_data.h create mode 100644 cores/common/arduino/src/wiring.c create mode 100644 cores/common/arduino/src/wiring_irq.c create mode 100644 cores/common/arduino/src/wiring_private.c create mode 100644 cores/common/arduino/src/wiring_private.h delete mode 100644 cores/realtek-amb/arduino/src/Tone.cpp create mode 100644 cores/realtek-amb/arduino/src/wiring_data.h diff --git a/cores/beken-72xx/arduino/src/wiring.c b/cores/beken-72xx/arduino/src/wiring.c index a1f5d48..f6d7873 100644 --- a/cores/beken-72xx/arduino/src/wiring.c +++ b/cores/beken-72xx/arduino/src/wiring.c @@ -1,22 +1,11 @@ /* Copyright (c) Kuba Szczodrzyński 2022-06-19. */ -#include -#include - -#include -#include -#include -#include -#include +#include "wiring_private.h" #define TICKS_PER_US (CFG_XTAL_FREQUENCE / 1000 / 1000) #define US_PER_OVERFLOW (portTICK_PERIOD_MS * 1000) #define TICKS_PER_OVERFLOW (TICKS_PER_US * US_PER_OVERFLOW) -void delayMilliseconds(unsigned long ms) { - rtos_delay_milliseconds(ms); -} - static uint32_t getTicksCount() { // copied from bk_timer_ctrl(), for speeds uint32_t timeout = 0; @@ -104,8 +93,22 @@ unsigned long micros() { #endif } -void yield() { - runPeriodicTasks(); - vTaskDelay(1); - taskYIELD(); +void pinRemoveMode(PinInfo *pin, uint32_t mask) { + PinData *data = pinData(pin); + if ((mask & PIN_GPIO) && (pin->enabled & PIN_GPIO)) { + gpio_config(pin->gpio, GMODE_INPUT_PULLDOWN); + pinDisable(pin, PIN_GPIO); + } + if ((mask & PIN_IRQ) && (pin->enabled & PIN_IRQ)) { + data->irqHandler = NULL; + gpio_int_disable(pin->gpio); + pinDisable(pin, PIN_IRQ); + } + if ((mask & PIN_PWM) && (pin->enabled & PIN_PWM)) { + data->pwm->cfg.bits.en = PWM_DISABLE; + __wrap_bk_printf_disable(); + sddev_control(PWM_DEV_NAME, CMD_PWM_DEINIT_PARAM, data->pwm); + __wrap_bk_printf_enable(); + pinDisable(pin, PIN_PWM); + } } diff --git a/cores/beken-72xx/arduino/src/wiring_analog.c b/cores/beken-72xx/arduino/src/wiring_analog.c index 71971df..5808b99 100644 --- a/cores/beken-72xx/arduino/src/wiring_analog.c +++ b/cores/beken-72xx/arduino/src/wiring_analog.c @@ -1,10 +1,6 @@ /* Copyright (c) Kuba Szczodrzyński 2022-06-20. */ -#include - -#include -#include -#include +#include "wiring_private.h" static GPIO_INDEX pwmToGpio[] = { GPIO6, // PWM0 @@ -59,11 +55,7 @@ static pwm_param_t pwm; static uint16_t adcData[1]; uint16_t analogReadVoltage(pin_size_t pinNumber) { - PinInfo *pin = pinInfo(pinNumber); - if (!pin) - return 0; - if (!pinSupported(pin, PIN_ADC)) - return 0; + pinCheckGetInfo(pinNumber, PIN_ADC, 0); UINT32 status; saradc_desc_t adc; @@ -90,11 +82,10 @@ uint16_t analogReadMaxVoltage(pin_size_t pinNumber) { } void analogWrite(pin_size_t pinNumber, int value) { - PinInfo *pin = pinInfo(pinNumber); - if (!pin) - return; - if (!pinSupported(pin, PIN_PWM)) - return; + pinCheckGetData(pinNumber, PIN_PWM, ); + + // GPIO can't be used together with PWM + pinRemoveMode(pin, PIN_GPIO | PIN_IRQ); float percent = value * 1.0 / ((1 << _analogWriteResolution) - 1); uint32_t frequency = 26 * _analogWritePeriod - 1; @@ -122,8 +113,9 @@ void analogWrite(pin_size_t pinNumber, int value) { sddev_control(PWM_DEV_NAME, CMD_PWM_INIT_LEVL_SET_HIGH, &pwm.channel); sddev_control(PWM_DEV_NAME, CMD_PWM_UNIT_ENABLE, &pwm.channel); __wrap_bk_printf_enable(); - pin->enabled &= ~PIN_GPIO; - pin->enabled |= PIN_PWM; + // pass global PWM object pointer + data->pwm = &pwm; + pinEnable(pin, PIN_PWM); } else { // update duty cycle sddev_control(PWM_DEV_NAME, CMD_PWM_SET_DUTY_CYCLE, &pwm); @@ -131,11 +123,7 @@ void analogWrite(pin_size_t pinNumber, int value) { } else { if (pinEnabled(pin, PIN_PWM)) { // disable PWM - pwm.cfg.bits.en = PWM_DISABLE; - __wrap_bk_printf_disable(); - sddev_control(PWM_DEV_NAME, CMD_PWM_DEINIT_PARAM, &pwm); - __wrap_bk_printf_enable(); - pin->enabled &= ~PIN_PWM; + pinRemoveMode(pin, PIN_PWM); } // force level as LOW pinMode(pinNumber, OUTPUT); diff --git a/cores/beken-72xx/arduino/src/wiring_data.h b/cores/beken-72xx/arduino/src/wiring_data.h new file mode 100644 index 0000000..c6d5210 --- /dev/null +++ b/cores/beken-72xx/arduino/src/wiring_data.h @@ -0,0 +1,23 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-05-24. */ + +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct PinData_s { + pwm_param_t *pwm; + PinMode gpioMode; + PinStatus irqMode; + void *irqHandler; + void *irqParam; + bool irqChange; +}; + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/cores/beken-72xx/arduino/src/wiring_digital.c b/cores/beken-72xx/arduino/src/wiring_digital.c index 27f0016..ab7dcff 100644 --- a/cores/beken-72xx/arduino/src/wiring_digital.c +++ b/cores/beken-72xx/arduino/src/wiring_digital.c @@ -1,20 +1,16 @@ /* Copyright (c) Kuba Szczodrzyński 2022-06-20. */ -#include - -#include +#include "wiring_private.h" void pinMode(pin_size_t pinNumber, PinMode pinMode) { - PinInfo *pin = pinInfo(pinNumber); - if (!pin) - return; - if (!pinSupported(pin, PIN_GPIO)) - return; - if (pinEnabled(pin, PIN_PWM)) - // disable PWM before using the pin - analogWrite(pinNumber, 0); - if (pinEnabled(pin, PIN_GPIO) && pin->mode == pinMode) + pinCheckGetData(pinNumber, PIN_GPIO, ); + + if (pinEnabled(pin, PIN_GPIO) && data->gpioMode == pinMode) return; + + // GPIO can't be used together with PWM + pinRemoveMode(pin, PIN_PWM); + switch (pinMode) { case INPUT: gpio_config(pin->gpio, GMODE_INPUT); @@ -31,34 +27,21 @@ void pinMode(pin_size_t pinNumber, PinMode pinMode) { case OUTPUT_OPENDRAIN: gpio_config(pin->gpio, GMODE_SET_HIGH_IMPENDANCE); break; + default: + return; } - pin->enabled |= PIN_GPIO; - pin->mode = pinMode; + pinEnable(pin, PIN_GPIO); + data->gpioMode = pinMode; } void digitalWrite(pin_size_t pinNumber, PinStatus status) { - // verify level is 0 or 1 - if (status > HIGH) - return; - PinInfo *pin = pinInfo(pinNumber); - if (!pin) - return; - // pin is not GPIO yet or not OUTPUT; enable or disable input pullup - if (!pinEnabled(pin, PIN_GPIO) || !pinIsOutput(pin)) { - pinMode(pinNumber, status * INPUT_PULLUP); - return; - } - // write the new state - gpio_output(pin->gpio, status); + pinCheckGetData(pinNumber, PIN_GPIO, ); + pinSetOutputPull(pin, data, pinNumber, status); + gpio_output(pin->gpio, !!status); } PinStatus digitalRead(pin_size_t pinNumber) { - PinInfo *pin = pinInfo(pinNumber); - if (!pin) - return 0; - // pin is not GPIO yet or not INPUT; change the mode - if (!pinEnabled(pin, PIN_GPIO) || !pinIsInput(pin)) - pinMode(pinNumber, INPUT); - // read the value + pinCheckGetData(pinNumber, PIN_GPIO, LOW); + pinSetInputMode(pin, data, pinNumber); return gpio_input(pin->gpio); } diff --git a/cores/beken-72xx/arduino/src/wiring_irq.c b/cores/beken-72xx/arduino/src/wiring_irq.c index d014b42..884bc03 100644 --- a/cores/beken-72xx/arduino/src/wiring_irq.c +++ b/cores/beken-72xx/arduino/src/wiring_irq.c @@ -1,98 +1,70 @@ /* Copyright (c) Kuba Szczodrzyński 2022-07-31. */ -#include - -#include - -static void *irqHandlerList[PINS_COUNT] = {NULL}; -static void *irqHandlerArgs[PINS_COUNT] = {NULL}; -static bool irqChangeList[PINS_COUNT]; +#include "wiring_private.h" static void irqHandler(unsigned char gpio) { PinInfo *pin = pinByGpio(gpio); if (pin == NULL) return; - uint32_t index = pinIndex(pin); - if (!irqHandlerList[index]) + PinData *data = pinData(pin); + if (!data->irqHandler) return; - if (irqChangeList[index]) { - if (pin->mode == INPUT_PULLDOWN) { - pin->mode = INPUT_PULLUP; + if (data->irqChange) { + if (data->gpioMode == INPUT_PULLDOWN) { + data->gpioMode = INPUT_PULLUP; gpio_int_enable(pin->gpio, GPIO_INT_LEVEL_FALLING, irqHandler); - } else if (pin->mode == INPUT_PULLUP) { - pin->mode = INPUT_PULLDOWN; + } else if (data->gpioMode == INPUT_PULLUP) { + data->gpioMode = INPUT_PULLDOWN; gpio_int_enable(pin->gpio, GPIO_INT_LEVEL_RISING, irqHandler); } } - if (irqHandlerArgs[index] == NULL) { - ((voidFuncPtr)irqHandlerList[index])(); - } else { - ((voidFuncPtrParam)irqHandlerList[index])(irqHandlerArgs[index]); - } -} - -void attachInterrupt(pin_size_t interruptNumber, voidFuncPtr callback, PinStatus mode) { - attachInterruptParam(interruptNumber, (voidFuncPtrParam)callback, mode, NULL); + if (!data->irqParam) + ((voidFuncPtr)data->irqHandler)(); + else + ((voidFuncPtrParam)data->irqHandler)(data->irqParam); } void attachInterruptParam(pin_size_t interruptNumber, voidFuncPtrParam callback, PinStatus mode, void *param) { - PinInfo *pin = pinInfo(interruptNumber); - if (!pin) - return; - if (!pinSupported(pin, PIN_IRQ)) - return; - uint32_t index = pinIndex(pin); - uint32_t event = 0; - PinMode modeNew = 0; - bool change = 0; + pinCheckGetData(interruptNumber, PIN_IRQ, ); + data->irqHandler = callback; + data->irqParam = param; + + if (pinEnabled(pin, PIN_IRQ) && data->irqMode == mode) + return; + + // GPIO can't be used together with PWM + pinRemoveMode(pin, PIN_PWM); + + uint32_t event = 0; + bool change = false; switch (mode) { case LOW: - event = GPIO_INT_LEVEL_LOW; - modeNew = INPUT_PULLUP; - change = false; + event = GPIO_INT_LEVEL_LOW; break; case HIGH: - event = GPIO_INT_LEVEL_HIGH; - modeNew = INPUT_PULLDOWN; - change = false; + event = GPIO_INT_LEVEL_HIGH; break; case FALLING: - event = GPIO_INT_LEVEL_FALLING; - modeNew = INPUT_PULLUP; - change = false; + event = GPIO_INT_LEVEL_FALLING; break; case RISING: - event = GPIO_INT_LEVEL_RISING; - modeNew = INPUT_PULLDOWN; - change = false; + event = GPIO_INT_LEVEL_RISING; break; case CHANGE: - event = GPIO_INT_LEVEL_FALLING; - modeNew = INPUT_PULLUP; - change = true; + event = GPIO_INT_LEVEL_FALLING; + change = true; break; default: return; } - irqHandlerList[index] = callback; - irqHandlerArgs[index] = param; - irqChangeList[index] = change; + pinEnable(pin, PIN_IRQ); + data->irqMode = mode; + data->irqChange = change; + gpio_int_enable(pin->gpio, event, irqHandler); - pin->enabled |= PIN_IRQ | PIN_GPIO; - pin->mode = modeNew; } void detachInterrupt(pin_size_t interruptNumber) { - PinInfo *pin = pinInfo(interruptNumber); - if (!pin) - return; - if (!pinSupported(pin, PIN_IRQ)) - return; - uint32_t index = pinIndex(pin); - irqHandlerList[index] = NULL; - irqHandlerArgs[index] = NULL; - irqChangeList[index] = false; - gpio_int_disable(pin->gpio); - pin->enabled &= ~PIN_IRQ; + pinModeRemove(interruptNumber, PIN_IRQ); } diff --git a/cores/beken-72xx/base/sdk_private.h b/cores/beken-72xx/base/sdk_private.h index 044e2cb..268c7df 100644 --- a/cores/beken-72xx/base/sdk_private.h +++ b/cores/beken-72xx/base/sdk_private.h @@ -6,12 +6,18 @@ extern "C" { #endif // __cplusplus -// most stuff is here +// most stuff is here - this has to be before other includes! #include // other includes +#include +#include +#include #include #include #include +#include +#include +#include #include #include #include diff --git a/cores/common/arduino/src/wiring.c b/cores/common/arduino/src/wiring.c new file mode 100644 index 0000000..5f344de --- /dev/null +++ b/cores/common/arduino/src/wiring.c @@ -0,0 +1,17 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-05-24. */ + +#include + +#if LT_HAS_FREERTOS + +__attribute__((weak)) void delay(uint32_t ms) { + vTaskDelay(pdMS_TO_TICKS(ms)); +} + +__attribute__((weak)) void yield() { + runPeriodicTasks(); + vTaskDelay(1); + taskYIELD(); +} + +#endif diff --git a/cores/common/arduino/src/wiring_custom.c b/cores/common/arduino/src/wiring_custom.c index a002ea1..31bd582 100644 --- a/cores/common/arduino/src/wiring_custom.c +++ b/cores/common/arduino/src/wiring_custom.c @@ -1,6 +1,6 @@ /* Copyright (c) Kuba Szczodrzyński 2022-06-20. */ -#include "wiring_custom.h" +#include "wiring_private.h" #if LT_HAS_FREERTOS #include @@ -32,6 +32,18 @@ void runPeriodicTasks() { #endif } +/** + * @brief Disable modes specified by 'mask'. + */ +void pinModeRemove(pin_size_t pinNumber, uint32_t mask) { + PinInfo *pin = pinInfo(pinNumber); + if (!pin) + return; + pinRemoveMode(pin, mask); + if (pin->enabled == PIN_NONE && mask == PIN_MODE_ALL) + pinRemoveData(pin); +} + /** * @brief Get PinInfo struct for the specified number. * Returns NULL if pin number is invalid. @@ -85,20 +97,6 @@ bool pinEnabled(PinInfo *pin, uint32_t mask) { return (pin->enabled & mask) == mask; } -/** - * @brief Check if GPIO pin is configured as output. - */ -bool pinIsOutput(PinInfo *pin) { - return pin->mode == OUTPUT || pin->mode == OUTPUT_OPENDRAIN; -} - -/** - * @brief Check if GPIO pin is configured as output. - */ -bool pinIsInput(PinInfo *pin) { - return pin->mode == INPUT || pin->mode == INPUT_PULLUP || pin->mode == INPUT_PULLDOWN; -} - /** * @brief Read voltage from ADC and return a value between 0 and * the current reading resolution. diff --git a/cores/common/arduino/src/wiring_custom.h b/cores/common/arduino/src/wiring_custom.h index 392e280..befc254 100644 --- a/cores/common/arduino/src/wiring_custom.h +++ b/cores/common/arduino/src/wiring_custom.h @@ -21,7 +21,10 @@ extern "C" { #define PIN_SWD (1 << 10) #define PIN_UART (1 << 11) -#define PIN_INVALID 255 +#define PIN_MODE_ALL 0xFFFFFFFF +#define PIN_INVALID 255 + +typedef struct PinData_s PinData; typedef struct { /** @@ -37,9 +40,9 @@ typedef struct { */ uint32_t enabled; /** - * @brief Pin mode (direction, IRQ level, etc.). + * @brief Pin data (direction, IRQ level, etc.). The structure is family-specific. */ - uint32_t mode; + PinData *data; } PinInfo; extern PinInfo lt_arduino_pin_info_list[PINS_COUNT]; @@ -57,14 +60,21 @@ bool startMainTask(void); void mainTask(const void *arg); // implemented in main.cpp void runPeriodicTasks(); // implemented in wiring_custom.c +void pinModeRemove(pin_size_t pinNumber, uint32_t mask); PinInfo *pinInfo(pin_size_t pinNumber); PinInfo *pinByIndex(uint32_t index); PinInfo *pinByGpio(uint32_t gpio); uint32_t pinIndex(PinInfo *pin); bool pinSupported(PinInfo *pin, uint32_t mask); bool pinEnabled(PinInfo *pin, uint32_t mask); -bool pinIsOutput(PinInfo *pin); -bool pinIsInput(PinInfo *pin); +void pinRemoveMode(PinInfo *pin, uint32_t mask); + +/** + * @brief Deinitialize the pin, by removing all enabled modes. + */ +inline void pinModeNone(pin_size_t pinNumber) { + pinModeRemove(pinNumber, PIN_MODE_ALL); +} int analogRead(pin_size_t pinNumber); void analogReadResolution(int res); diff --git a/cores/common/arduino/src/wiring_irq.c b/cores/common/arduino/src/wiring_irq.c new file mode 100644 index 0000000..f8efc37 --- /dev/null +++ b/cores/common/arduino/src/wiring_irq.c @@ -0,0 +1,7 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-05-24. */ + +#include + +void attachInterrupt(pin_size_t interruptNumber, voidFuncPtr callback, PinStatus mode) { + attachInterruptParam(interruptNumber, (voidFuncPtrParam)callback, mode, NULL); +} diff --git a/cores/common/arduino/src/wiring_private.c b/cores/common/arduino/src/wiring_private.c new file mode 100644 index 0000000..0810d80 --- /dev/null +++ b/cores/common/arduino/src/wiring_private.c @@ -0,0 +1,25 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-05-24. */ + +#include "wiring_private.h" + +#if __has_include() +/** + * @brief Allocate and return a PinData structure (family-specific). + */ +PinData *pinData(PinInfo *pin) { + if (pin->data == NULL) { + pin->data = calloc(1, sizeof(PinData)); + } + return (PinData *)pin->data; +} + +/** + * @brief Deallocate the PinData structure. + */ +void pinRemoveData(PinInfo *pin) { + if (pin->data != NULL) { + free(pin->data); + } + pin->data = NULL; +} +#endif diff --git a/cores/common/arduino/src/wiring_private.h b/cores/common/arduino/src/wiring_private.h new file mode 100644 index 0000000..5d0b9c3 --- /dev/null +++ b/cores/common/arduino/src/wiring_private.h @@ -0,0 +1,64 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-05-24. */ + +#pragma once + +#include + +#if __has_include() +#include +#endif + +#if __has_include() +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +PinData *pinData(PinInfo *pin); +void pinRemoveData(PinInfo *pin); + +inline void pinEnable(PinInfo *pin, uint32_t mask) { + pin->enabled |= mask; +} + +inline void pinDisable(PinInfo *pin, uint32_t mask) { + pin->enabled &= ~mask; +} + +#define pinCheckGetInfo(pinNumber, mask, ret) \ + PinInfo *pin = pinInfo(pinNumber); \ + if (!pin) \ + return ret; \ + if (!pinSupported(pin, mask)) \ + return ret; + +#define pinCheckGetData(pinNumber, mask, ret) \ + PinInfo *pin = pinInfo(pinNumber); \ + if (!pin) \ + return ret; \ + if (!pinSupported(pin, mask)) \ + return ret; \ + PinData *data = pinData(pin); + +#define pinIsOutput(pin, data) (pinEnabled(pin, PIN_GPIO) && (data->gpioMode ^ 0b101) < 5) +#define pinIsInput(pin, data) (pinEnabled(pin, PIN_GPIO) && (data->gpioMode ^ 0b101) > 4) + +#define pinSetOutputPull(pin, data, pinNumber, status) \ + do { \ + if (!pinIsOutput(pin, data)) { \ + pinMode(pinNumber, INPUT_PULLDOWN ^ !!status); \ + return; \ + } \ + } while (0); + +#define pinSetInputMode(pin, data, pinNumber) \ + do { \ + if (!pinIsInput(pin, data)) \ + pinMode(pinNumber, INPUT); \ + } while (0); + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/cores/realtek-amb/arduino/src/Tone.cpp b/cores/realtek-amb/arduino/src/Tone.cpp deleted file mode 100644 index 816114e..0000000 --- a/cores/realtek-amb/arduino/src/Tone.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include - -extern void pinRemoveMode(pin_size_t pinNumber); -extern void _tone(uint32_t ulPin, unsigned int frequency, unsigned long duration); - -void tone(uint32_t ulPin, unsigned int frequency, unsigned long duration) { - _tone(ulPin, frequency, duration); -} - -void noTone(uint32_t ulPin) { - pinRemoveMode(ulPin); -} diff --git a/cores/realtek-amb/arduino/src/wiring.c b/cores/realtek-amb/arduino/src/wiring.c index 0cc3839..bb0fc6b 100644 --- a/cores/realtek-amb/arduino/src/wiring.c +++ b/cores/realtek-amb/arduino/src/wiring.c @@ -1,48 +1,11 @@ -/* - Copyright (c) 2011 Arduino. All right reserved. +/* Copyright (c) Kuba Szczodrzyński 2022-04-23. */ - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include - -#include +#include "wiring_private.h" #ifndef portNVIC_SYSTICK_CURRENT_VALUE_REG #define portNVIC_SYSTICK_CURRENT_VALUE_REG (*((volatile uint32_t *)0xe000e018)) #endif -extern uint32_t xTaskGetTickCount(); -extern uint32_t xTaskGetTickCountFromISR(); - -static __inline uint32_t __get_ipsr__(void) { - volatile uint32_t __regIPSR __asm("ipsr"); - return (__regIPSR); -} - -void *gpio_pin_struct[PINS_COUNT] = {NULL}; - -void delay(uint32_t ms) { - /* osStatus ret; */ - - /* ret = */ osDelay(ms); - /* if ((ret != osEventTimeout) && (ret != osOK)) { - printf("delay : ERROR : 0x%x \n", ret); - } */ -} - void delayMicroseconds(unsigned int us) { int i; uint32_t t0, tn; @@ -61,7 +24,7 @@ void delayMicroseconds(unsigned int us) { } unsigned long millis(void) { - return (__get_ipsr__() == 0) ? xTaskGetTickCount() : xTaskGetTickCountFromISR(); + return (__get_IPSR() == 0) ? xTaskGetTickCount() : xTaskGetTickCountFromISR(); } unsigned long micros(void) { @@ -69,7 +32,7 @@ unsigned long micros(void) { uint32_t us; uint32_t tick_per_us = F_CPU / 1000; - if (__get_ipsr__() == 0) { + if (__get_IPSR() == 0) { tick1 = xTaskGetTickCount(); us = portNVIC_SYSTICK_CURRENT_VALUE_REG; tick2 = xTaskGetTickCount(); @@ -88,8 +51,22 @@ unsigned long micros(void) { } } -void yield(void) { - runPeriodicTasks(); - vTaskDelay(1); - taskYIELD(); +void pinRemoveMode(PinInfo *pin, uint32_t mask) { + PinData *data = pinData(pin); + if ((mask & PIN_GPIO) && (pin->enabled & PIN_GPIO)) { + gpio_deinit(data->gpio); + free(data->gpio); + pinDisable(pin, PIN_GPIO); + } + if ((mask & PIN_IRQ) && (pin->enabled & PIN_IRQ)) { + data->irqHandler = NULL; + gpio_irq_free(data->irq); + free(data->irq); + pinDisable(pin, PIN_IRQ); + } + if ((mask & PIN_PWM) && (pin->enabled & PIN_PWM)) { + pwmout_free(data->pwm); + free(data->pwm); + pinDisable(pin, PIN_PWM); + } } diff --git a/cores/realtek-amb/arduino/src/wiring_analog.c b/cores/realtek-amb/arduino/src/wiring_analog.c index 05d0796..68b7f83 100644 --- a/cores/realtek-amb/arduino/src/wiring_analog.c +++ b/cores/realtek-amb/arduino/src/wiring_analog.c @@ -1,23 +1,6 @@ -/* - Copyright (c) 2011 Arduino. All right reserved. +/* Copyright (c) Kuba Szczodrzyński 2022-06-20. */ - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include +#include "wiring_private.h" /* ADC */ static analogin_t adc1; @@ -28,17 +11,13 @@ static bool g_adc_enabled[] = {false, false, false}; // from realtek_amebaz_va0_example/example_sources/adc_vbat/src/main.c #define AD2MV(ad, offset, gain) (((ad >> 4) - offset) * 1000 / gain) -extern void *gpio_pin_struct[]; - -extern void pinRemoveMode(pin_size_t pinNumber); - // TODO implement custom ADC calibration uint16_t analogReadVoltage(pin_size_t pinNumber) { uint16_t ret = 0; switch (pinNumber) { -#ifdef PIN_A1 - case PIN_A1: +#ifdef PIN_ADC2 + case PIN_ADC2: if (g_adc_enabled[1] == false) { analogin_init(&adc2, AD_2); g_adc_enabled[1] = true; @@ -47,8 +26,8 @@ uint16_t analogReadVoltage(pin_size_t pinNumber) { // AD_1 - 0.0V-5.0V return AD2MV(ret, 0x496, 0xBA); #endif -#ifdef PIN_A0 - case PIN_A0: +#ifdef PIN_ADC1 + case PIN_ADC1: if (g_adc_enabled[0] == false) { analogin_init(&adc1, AD_1); g_adc_enabled[0] = true; @@ -56,8 +35,8 @@ uint16_t analogReadVoltage(pin_size_t pinNumber) { ret = analogin_read_u16(&adc1); break; #endif -#ifdef PIN_A2 - case PIN_A2: +#ifdef PIN_ADC3 + case PIN_ADC3: if (g_adc_enabled[2] == false) { analogin_init(&adc3, AD_3); g_adc_enabled[2] = true; @@ -82,27 +61,20 @@ uint16_t analogReadMaxVoltage(pin_size_t pinNumber) { } void analogWrite(pin_size_t pinNumber, int value) { - PinInfo *pin = pinInfo(pinNumber); - if (!pin) - return; - pwmout_t *obj; + pinCheckGetData(pinNumber, PIN_PWM, ); - if (pinSupported(pin, PIN_PWM)) { - float percent = value * 1.0 / (1 << _analogWriteResolution); - if (pin->enabled != PIN_PWM) { - if ((pin->enabled == PIN_GPIO) || (pin->enabled == PIN_IRQ)) { - pinRemoveMode(pinNumber); - } - gpio_pin_struct[pinNumber] = malloc(sizeof(pwmout_t)); - pwmout_t *obj = (pwmout_t *)gpio_pin_struct[pinNumber]; - pwmout_init(obj, pin->gpio); - pwmout_period_us(obj, _analogWritePeriod); - pwmout_write(obj, percent); - pin->enabled = PIN_PWM; - } else { - pwmout_t *obj = (pwmout_t *)gpio_pin_struct[pinNumber]; - // pwmout_period_us(obj, _writePeriod); - pwmout_write(obj, percent); - } + // GPIO can't be used together with PWM + pinRemoveMode(pin, PIN_GPIO | PIN_IRQ); + + pwmout_t *pwm = data->pwm; + if (!pwm) { + // allocate memory if pin not used before + data->pwm = pwm = malloc(sizeof(pwmout_t)); + pwmout_init(pwm, pin->gpio); + pwmout_period_us(pwm, _analogWritePeriod); + pinEnable(pin, PIN_PWM); } + + float percent = value * 1.0 / (1 << _analogWriteResolution); + pwmout_write(pwm, percent); } diff --git a/cores/realtek-amb/arduino/src/wiring_data.h b/cores/realtek-amb/arduino/src/wiring_data.h new file mode 100644 index 0000000..1f0038f --- /dev/null +++ b/cores/realtek-amb/arduino/src/wiring_data.h @@ -0,0 +1,24 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-05-24. */ + +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct PinData_s { + gpio_t *gpio; + gpio_irq_t *irq; + pwmout_t *pwm; + PinMode gpioMode; + PinStatus irqMode; + void *irqHandler; + void *irqParam; +}; + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/cores/realtek-amb/arduino/src/wiring_digital.c b/cores/realtek-amb/arduino/src/wiring_digital.c index 0c8cb32..1eb2f9c 100644 --- a/cores/realtek-amb/arduino/src/wiring_digital.c +++ b/cores/realtek-amb/arduino/src/wiring_digital.c @@ -1,68 +1,32 @@ -#include -#include +/* Copyright (c) Kuba Szczodrzyński 2022-04-23. */ -extern void *gpio_pin_struct[PINS_COUNT]; - -void pinRemoveMode(pin_size_t pinNumber) { - PinInfo *pin = pinInfo(pinNumber); - if (!pin) - return; - if (pinEnabled(pin, PIN_PWM)) { - pwmout_t *obj = (pwmout_t *)gpio_pin_struct[pinNumber]; - pwmout_free(obj); - } - if (pinEnabled(pin, PIN_GPIO)) { - gpio_t *obj = (gpio_t *)gpio_pin_struct[pinNumber]; - gpio_deinit(obj); - free(obj); - } - if (pinEnabled(pin, PIN_IRQ)) { - gpio_irq_t *obj = (gpio_irq_t *)gpio_pin_struct[pinNumber]; - gpio_irq_deinit(obj); - free(obj); - } - gpio_pin_struct[pinNumber] = NULL; - pin->enabled = PIN_NONE; -} +#include "wiring_private.h" void pinMode(pin_size_t pinNumber, PinMode pinMode) { - PinInfo *pin = pinInfo(pinNumber); - if (!pin) + pinCheckGetData(pinNumber, PIN_GPIO, ); + + if (pinEnabled(pin, PIN_GPIO) && data->gpioMode == pinMode) return; - if (pinEnabled(pin, PIN_GPIO) && pin->mode == pinMode) - // Nothing changes in pin mode - return; +#if LT_RTL8720C + // apparently IRQ can't be used with any kind of pull-up/down + // TODO verify if it can be used on AmebaZ + pinRemoveMode(pin, PIN_PWM | PIN_IRQ); +#else + // GPIO can't be used together with PWM + pinRemoveMode(pin, PIN_PWM); +#endif - if (!pinSupported(pin, PIN_GPIO)) - // cannot set ADC as I/O - return; - - /* if (pin->enabled == PIN_PWM) { - // If this pin has been configured as PWM, then it cannot change to another mode - return; - } */ - - if (pin->enabled != PIN_GPIO) - // pin mode changes; deinit gpio and free memory - pinRemoveMode(pinNumber); - - gpio_t *gpio; - - if (pin->enabled == PIN_NONE) { + gpio_t *gpio = data->gpio; + if (!gpio) { // allocate memory if pin not used before - gpio = malloc(sizeof(gpio_t)); - gpio_pin_struct[pinNumber] = gpio; + data->gpio = gpio = malloc(sizeof(gpio_t)); gpio_init(gpio, pin->gpio); - pin->enabled = PIN_GPIO; - } else { - // pin already used as gpio - gpio = (gpio_t *)gpio_pin_struct[pinNumber]; + pinEnable(pin, PIN_GPIO); } - pin->mode = pinMode; PinDirection dir; - PinMode mode; + PinModeRTL mode; switch (pinMode) { case INPUT: @@ -88,29 +52,20 @@ void pinMode(pin_size_t pinNumber, PinMode pinMode) { default: return; } + data->gpioMode = pinMode; gpio_dir(gpio, dir); gpio_mode(gpio, mode); } void digitalWrite(pin_size_t pinNumber, PinStatus status) { - PinInfo *pin = pinInfo(pinNumber); - if (!pin) - return; - if (pin->enabled != PIN_GPIO) - return; - - gpio_t *gpio = (gpio_t *)gpio_pin_struct[pinNumber]; - gpio_write(gpio, status); + pinCheckGetData(pinNumber, PIN_GPIO, ); + pinSetOutputPull(pin, data, pinNumber, status); + gpio_write(data->gpio, !!status); } PinStatus digitalRead(pin_size_t pinNumber) { - PinInfo *pin = pinInfo(pinNumber); - if (!pin) - return LOW; - if (pin->enabled != PIN_GPIO) - return LOW; - - gpio_t *gpio = (gpio_t *)gpio_pin_struct[pinNumber]; - return gpio_read(gpio); + pinCheckGetData(pinNumber, PIN_GPIO, LOW); + pinSetInputMode(pin, data, pinNumber); + return gpio_read(data->gpio); } diff --git a/cores/realtek-amb/arduino/src/wiring_irq.c b/cores/realtek-amb/arduino/src/wiring_irq.c index 4fd7cd5..f387fcc 100644 --- a/cores/realtek-amb/arduino/src/wiring_irq.c +++ b/cores/realtek-amb/arduino/src/wiring_irq.c @@ -1,59 +1,50 @@ -#include -#include +/* Copyright (c) Kuba Szczodrzyński 2022-04-23. */ -extern void *gpio_pin_struct[PINS_COUNT]; -static void *gpio_irq_handler_list[PINS_COUNT] = {NULL}; -static void *gpio_irq_handler_args[PINS_COUNT] = {NULL}; - -extern void pinRemoveMode(pin_size_t pinNumber); +#include "wiring_private.h" static void gpioIrqHandler(uint32_t id, gpio_irq_event event) { - // id is pin index - if (gpio_irq_handler_list[id] != NULL) { - if (gpio_irq_handler_args[id] == NULL) - ((voidFuncPtr)gpio_irq_handler_list[id])(); - else - ((voidFuncPtrParam)gpio_irq_handler_list[id])(gpio_irq_handler_args[id]); - } -} - -void attachInterrupt(pin_size_t interruptNumber, voidFuncPtr callback, PinStatus mode) { - attachInterruptParam(interruptNumber, (voidFuncPtrParam)callback, mode, NULL); + // id is pin data + PinData *data = (PinData *)id; + if (!data->irqHandler) + return; + if (!data->irqParam) + ((voidFuncPtr)data->irqHandler)(); + else + ((voidFuncPtrParam)data->irqHandler)(data->irqParam); } void attachInterruptParam(pin_size_t interruptNumber, voidFuncPtrParam callback, PinStatus mode, void *param) { - PinInfo *pin = pinInfo(interruptNumber); - if (pin == NULL) - return; - uint32_t index = pinIndex(pin); + pinCheckGetData(interruptNumber, PIN_IRQ, ); - gpio_irq_handler_list[index] = callback; - gpio_irq_handler_args[index] = param; + data->irqHandler = callback; + data->irqParam = param; - if (pin->enabled == PIN_IRQ && pin->mode == mode) - // Nothing changes in pin mode + if (pinEnabled(pin, PIN_IRQ) && data->irqMode == mode) return; - if (pin->enabled != PIN_IRQ) - // pin mode changes; deinit gpio and free memory - pinRemoveMode(interruptNumber); +#if LT_RTL8720C + // apparently IRQ can't be used with any kind of pull-up/down + // TODO verify if it can be used on AmebaZ + pinRemoveMode(pin, PIN_PWM | PIN_GPIO); +#else + // GPIO can't be used together with PWM + pinRemoveMode(pin, PIN_PWM); +#endif - gpio_irq_t *gpio; - - if (pin->enabled == PIN_NONE) { + gpio_irq_t *irq = data->irq; + if (!irq) { // allocate memory if pin not used before - gpio = malloc(sizeof(gpio_irq_t)); - gpio_pin_struct[index] = gpio; - gpio_irq_init(gpio, pin->gpio, gpioIrqHandler, index); - pin->enabled = PIN_IRQ; - } else { - // pin already used as irq - gpio = (gpio_irq_t *)gpio_pin_struct[index]; + data->irq = irq = malloc(sizeof(gpio_irq_t)); + if (gpio_irq_init(irq, pin->gpio, gpioIrqHandler, (uint32_t)data) != 0) { + LT_W("IRQ init failed"); + free(data->irq); + data->irq = NULL; + return; + } + pinEnable(pin, PIN_IRQ); } - pin->mode = mode; gpio_irq_event event; - switch (mode) { case LOW: event = IRQ_LOW; @@ -67,22 +58,22 @@ void attachInterruptParam(pin_size_t interruptNumber, voidFuncPtrParam callback, case RISING: event = IRQ_RISE; break; + case CHANGE: +#if LT_RTL8720C + event = IRQ_FALL_RISE; +#else + LT_W("CHANGE interrupts not supported"); +#endif + break; default: return; } + data->irqMode = mode; - gpio_irq_set(gpio, event, 1); - gpio_irq_enable(gpio); + gpio_irq_set(irq, event, 1); + gpio_irq_enable(irq); } void detachInterrupt(pin_size_t interruptNumber) { - PinInfo *pin = pinInfo(interruptNumber); - if (pin == NULL) - return; - uint32_t index = pinIndex(pin); - - if (pin->enabled == PIN_IRQ) { - pinRemoveMode(interruptNumber); - } - gpio_irq_handler_list[index] = NULL; + pinModeRemove(interruptNumber, PIN_IRQ); } diff --git a/cores/realtek-amb/arduino/src/wiring_pulse.c b/cores/realtek-amb/arduino/src/wiring_pulse.c index 83aeed9..9fcd794 100644 --- a/cores/realtek-amb/arduino/src/wiring_pulse.c +++ b/cores/realtek-amb/arduino/src/wiring_pulse.c @@ -16,10 +16,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include -#include - -extern void *gpio_pin_struct[]; +#include "wiring_private.h" /* Measures the length (in microseconds) of a pulse on the pin; state is HIGH * or LOW, the type of pulse to measure. Works on pulses from 2-3 microseconds @@ -34,19 +31,17 @@ extern unsigned long pulseIn(uint8_t pinNumber, uint8_t state, unsigned long tim return 0; uint32_t index = pinIndex(pin); - gpio_t *pGpio_t; - uint32_t start_ticks, cur_ticks; if (pin->gpio == NC) return 0; /* Handle */ - if (pin->enabled != PIN_GPIO) { + if (!pinEnabled(pin, PIN_GPIO)) { return 0; } - - pGpio_t = (gpio_t *)gpio_pin_struct[index]; + PinData *data = pinData(pin); + gpio_t *pGpio_t = data->gpio; // wait for any previous pulse to end start_ticks = us_ticker_read(); diff --git a/cores/realtek-amb/base/sdk_private.h b/cores/realtek-amb/base/sdk_private.h index d3bbf01..fb4977e 100644 --- a/cores/realtek-amb/base/sdk_private.h +++ b/cores/realtek-amb/base/sdk_private.h @@ -27,6 +27,9 @@ extern "C" { #endif #include +#undef malloc +#undef free +#undef calloc // mbed APIs #include diff --git a/cores/realtek-ambz2/base/lt_api.c b/cores/realtek-ambz2/base/lt_api.c index 658a4a9..3de1f67 100644 --- a/cores/realtek-ambz2/base/lt_api.c +++ b/cores/realtek-ambz2/base/lt_api.c @@ -78,6 +78,7 @@ lt_reboot_reason_t lt_get_reboot_reason() { void lt_gpio_recover() { sys_jtag_off(); + sys_swd_off(); } /*__ __ diff --git a/cores/realtek-ambz2/base/sdk_extern.h b/cores/realtek-ambz2/base/sdk_extern.h index c0270ce..476e0ee 100644 --- a/cores/realtek-ambz2/base/sdk_extern.h +++ b/cores/realtek-ambz2/base/sdk_extern.h @@ -11,6 +11,7 @@ extern "C" { // SDK void software_reset(); +void sys_swd_off(); void sys_uart_download_mode(); void sys_download_mode(uint8_t mode); From c0cc602c9ace1fb23788c2244a2433962c12a47e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 25 May 2023 14:29:35 +0200 Subject: [PATCH 10/31] [core] Add configure() for SerialClass --- .../arduino/libraries/Serial/Serial.cpp | 30 +++- .../arduino/libraries/api/Serial/Serial.cpp | 4 +- .../arduino/libraries/api/Serial/Serial.h | 34 ++++- cores/realtek-amb/base/sdk_private.h | 1 + .../arduino/libraries/Serial/Serial.cpp | 134 ++++++++---------- .../arduino/libraries/Serial/SerialPrivate.h | 2 - 6 files changed, 125 insertions(+), 80 deletions(-) diff --git a/cores/beken-72xx/arduino/libraries/Serial/Serial.cpp b/cores/beken-72xx/arduino/libraries/Serial/Serial.cpp index 50f7bbc..4f3403a 100644 --- a/cores/beken-72xx/arduino/libraries/Serial/Serial.cpp +++ b/cores/beken-72xx/arduino/libraries/Serial/Serial.cpp @@ -12,7 +12,7 @@ SerialClass Serial2(UART2_PORT); static void callback(int port, void *param) { int ch; while ((ch = uart_read_byte(port)) != -1) { -#if LT_AUTO_DOWNLOAD_REBOOT && defined(LT_UART_ADR_PATTERN) && defined(PIN_SERIAL1_RX) +#if LT_AUTO_DOWNLOAD_REBOOT && defined(LT_UART_ADR_PATTERN) && PIN_SERIAL1_RX != PIN_INVALID // parse UART protocol commands on UART1 if (port == UART1_PORT) SerialClass::adrParse(ch); @@ -22,8 +22,18 @@ static void callback(int port, void *param) { } void SerialClass::begin(unsigned long baudrate, uint16_t config) { - this->data = new SerialData(); - this->buf = &BUF; + if (!this->data) { + this->data = new SerialData(); + this->buf = &BUF; + } + + if (this->baudrate != baudrate || this->config != config) + this->configure(baudrate, config); +} + +void SerialClass::configure(unsigned long baudrate, uint16_t config) { + if (!this->data) + return; uint8_t dataWidth = ((config & SERIAL_DATA_MASK) >> 8) - 1; // 0x100..0x400 -> 0..3 uint8_t parity = 3 - (config & SERIAL_PARITY_MASK); // 0x3..0x1 -> 0..2 @@ -39,9 +49,15 @@ void SerialClass::begin(unsigned long baudrate, uint16_t config) { uart_hw_set_change(port, &cfg); uart_rx_callback_set(port, callback, &BUF); + + this->baudrate = baudrate; + this->config = config; } void SerialClass::end() { + if (!this->data) + return; + uart_rx_callback_set(port, NULL, NULL); switch (port) { case 1: @@ -51,15 +67,21 @@ void SerialClass::end() { uart2_exit(); break; } - this->buf = NULL; + + this->buf = NULL; + this->baudrate = 0; delete DATA; } void SerialClass::flush() { + if (!this->data) + return; uart_wait_tx_over(); } size_t SerialClass::write(uint8_t c) { + if (!this->data) + return 0; bk_send_byte(port, c); return 1; } diff --git a/cores/common/arduino/libraries/api/Serial/Serial.cpp b/cores/common/arduino/libraries/api/Serial/Serial.cpp index 2f64f42..509d353 100644 --- a/cores/common/arduino/libraries/api/Serial/Serial.cpp +++ b/cores/common/arduino/libraries/api/Serial/Serial.cpp @@ -2,8 +2,10 @@ #include "Serial.h" -SerialClass::SerialClass(uint32_t port) { +SerialClass::SerialClass(uint32_t port, pin_size_t rx, pin_size_t tx) { this->port = port; + this->rx = rx; + this->tx = tx; this->buf = NULL; this->data = NULL; } diff --git a/cores/common/arduino/libraries/api/Serial/Serial.h b/cores/common/arduino/libraries/api/Serial/Serial.h index ca46229..da3bf02 100644 --- a/cores/common/arduino/libraries/api/Serial/Serial.h +++ b/cores/common/arduino/libraries/api/Serial/Serial.h @@ -8,22 +8,52 @@ using namespace arduino; +#ifndef PIN_SERIAL0_RX +#define PIN_SERIAL0_RX PIN_INVALID +#endif +#ifndef PIN_SERIAL1_RX +#define PIN_SERIAL1_RX PIN_INVALID +#endif +#ifndef PIN_SERIAL2_RX +#define PIN_SERIAL2_RX PIN_INVALID +#endif +#ifndef PIN_SERIAL0_TX +#define PIN_SERIAL0_TX PIN_INVALID +#endif +#ifndef PIN_SERIAL1_TX +#define PIN_SERIAL1_TX PIN_INVALID +#endif +#ifndef PIN_SERIAL2_TX +#define PIN_SERIAL2_TX PIN_INVALID +#endif + class SerialClass : public HardwareSerial { private: uint32_t port; - RingBuffer *buf; + pin_size_t rx; + pin_size_t tx; public: void *data; + private: + RingBuffer *buf; + uint32_t baudrate; + uint16_t config; + public: - SerialClass(uint32_t port); + SerialClass(uint32_t port, pin_size_t rx = PIN_INVALID, pin_size_t tx = PIN_INVALID); inline void begin(unsigned long baudrate) { begin(baudrate, SERIAL_8N1); } + inline void configure(unsigned long baudrate) { + configure(baudrate, SERIAL_8N1); + } + void begin(unsigned long baudrate, uint16_t config); + void configure(unsigned long baudrate, uint16_t config); void end(); int available(); int peek(); diff --git a/cores/realtek-amb/base/sdk_private.h b/cores/realtek-amb/base/sdk_private.h index fb4977e..1a4f5df 100644 --- a/cores/realtek-amb/base/sdk_private.h +++ b/cores/realtek-amb/base/sdk_private.h @@ -49,6 +49,7 @@ extern "C" { #include #include #include +#include #include #include #include diff --git a/cores/realtek-ambz/arduino/libraries/Serial/Serial.cpp b/cores/realtek-ambz/arduino/libraries/Serial/Serial.cpp index c4bbde3..bc08cd5 100644 --- a/cores/realtek-ambz/arduino/libraries/Serial/Serial.cpp +++ b/cores/realtek-ambz/arduino/libraries/Serial/Serial.cpp @@ -3,51 +3,17 @@ #include "SerialPrivate.h" #if HAS_SERIAL0 -SerialClass Serial0(0); +SerialClass Serial0(0, PIN_SERIAL0_RX, PIN_SERIAL0_TX); #endif #if HAS_SERIAL1 -SerialClass Serial1(1); +SerialClass Serial1(1, PIN_SERIAL1_RX, PIN_SERIAL1_TX); #endif #if HAS_SERIAL2 -SerialClass Serial2(2); +SerialClass Serial2(2, PIN_SERIAL2_RX, PIN_SERIAL2_TX); #endif -static UART_TypeDef *PORT_UART[3] = {UART0_DEV, UART1_DEV, UART2_DEV}; -static const IRQn PORT_IRQ[3] = {UART0_IRQ, UART1_IRQ, UART_LOG_IRQ}; -static const pin_size_t PORT_RX[3] = { -#ifdef PIN_SERIAL0_RX - PIN_SERIAL0_RX, -#else - PIN_INVALID, -#endif -#ifdef PIN_SERIAL1_RX - PIN_SERIAL1_RX, -#else - PIN_INVALID, -#endif -#ifdef PIN_SERIAL2_RX - PIN_SERIAL2_RX, -#else - PIN_INVALID, -#endif -}; -static const pin_size_t PORT_TX[3] = { -#ifdef PIN_SERIAL0_TX - PIN_SERIAL0_TX, -#else - PIN_INVALID, -#endif -#ifdef PIN_SERIAL1_TX - PIN_SERIAL1_TX, -#else - PIN_INVALID, -#endif -#ifdef PIN_SERIAL2_TX - PIN_SERIAL2_TX, -#else - PIN_INVALID, -#endif -}; +static UART_TypeDef *PORT_UART[3] = {UART0_DEV, UART1_DEV, UART2_DEV}; +static const IRQn PORT_IRQ[3] = {UART0_IRQ, UART1_IRQ, UART_LOG_IRQ}; static uint32_t callback(void *param) { UART_TypeDef *uart = pdUART; @@ -58,7 +24,7 @@ static uint32_t callback(void *param) { uint8_t c; while (UART_Readable(uart)) { UART_CharGet(uart, &c); -#if LT_AUTO_DOWNLOAD_REBOOT && defined(LT_UART_ADR_PATTERN) && defined(PIN_SERIAL2_RX) +#if LT_AUTO_DOWNLOAD_REBOOT && defined(LT_UART_ADR_PATTERN) && PIN_SERIAL2_RX != PIN_INVALID // parse UART protocol commands on UART2 if (uart == UART2_DEV) SerialClass::adrParse(c); @@ -71,12 +37,45 @@ static uint32_t callback(void *param) { } void SerialClass::begin(unsigned long baudrate, uint16_t config) { - this->data = new SerialData(); - this->buf = &BUF; - DATA->uart = PORT_UART[this->port]; - DATA->irq = PORT_IRQ[this->port]; - DATA->rx = PORT_RX[this->port]; - DATA->tx = PORT_TX[this->port]; + if (!this->data) { + this->data = new SerialData(); + this->buf = &BUF; + DATA->uart = PORT_UART[this->port]; + DATA->irq = PORT_IRQ[this->port]; + + switch ((uint32_t)DATA->uart) { + case UART0_REG_BASE: + RCC_PeriphClockCmd(APBPeriph_UART0, APBPeriph_UART0_CLOCK, ENABLE); + break; + case UART1_REG_BASE: + RCC_PeriphClockCmd(APBPeriph_UART1, APBPeriph_UART1_CLOCK, ENABLE); + break; + } + + if (this->tx != PIN_INVALID) { + Pinmux_Config(this->tx, PINMUX_FUNCTION_UART); + } + if (this->rx != PIN_INVALID) { + Pinmux_Config(this->rx, PINMUX_FUNCTION_UART); + PAD_PullCtrl(this->rx, GPIO_PuPd_UP); + } + } + + if (this->baudrate != baudrate || this->config != config) + this->configure(baudrate, config); + + if (this->rx != PIN_INVALID) { + VECTOR_IrqUnRegister(DATA->irq); + VECTOR_IrqRegister(callback, DATA->irq, (uint32_t)this->data, 10); + VECTOR_IrqEn(DATA->irq, 10); + UART_RxCmd(UART, ENABLE); + UART_INTConfig(UART, RUART_IER_ERBI, ENABLE); + } +} + +void SerialClass::configure(unsigned long baudrate, uint16_t config) { + if (!this->data) + return; // RUART_WLS_7BITS / RUART_WLS_8BITS uint8_t dataWidth = (config & SERIAL_DATA_MASK) == SERIAL_DATA_8; @@ -87,23 +86,6 @@ void SerialClass::begin(unsigned long baudrate, uint16_t config) { // RUART_STOP_BIT_1 / RUART_STOP_BIT_2 uint8_t stopBits = (config & SERIAL_STOP_BIT_MASK) == SERIAL_STOP_BIT_2; - switch ((uint32_t)DATA->uart) { - case UART0_REG_BASE: - RCC_PeriphClockCmd(APBPeriph_UART0, APBPeriph_UART0_CLOCK, ENABLE); - break; - case UART1_REG_BASE: - RCC_PeriphClockCmd(APBPeriph_UART1, APBPeriph_UART1_CLOCK, ENABLE); - break; - } - - if (DATA->tx != PIN_INVALID) { - Pinmux_Config(DATA->tx, PINMUX_FUNCTION_UART); - } - if (DATA->rx != PIN_INVALID) { - Pinmux_Config(DATA->rx, PINMUX_FUNCTION_UART); - PAD_PullCtrl(DATA->rx, GPIO_PuPd_UP); - } - UART_InitTypeDef cfg; UART_StructInit(&cfg); cfg.WordLen = dataWidth; @@ -113,29 +95,39 @@ void SerialClass::begin(unsigned long baudrate, uint16_t config) { UART_Init(UART, &cfg); UART_SetBaud(UART, baudrate); - if (DATA->rx != PIN_INVALID) { - VECTOR_IrqUnRegister(DATA->irq); - VECTOR_IrqRegister(callback, DATA->irq, (uint32_t)&data, 10); - VECTOR_IrqEn(DATA->irq, 10); - UART_RxCmd(UART, ENABLE); - UART_INTConfig(UART, RUART_IER_ERBI, ENABLE); - } + this->baudrate = baudrate; + this->config = config; } void SerialClass::end() { + if (!this->data) + return; + + UART_INTConfig(UART, RUART_IER_ERBI, DISABLE); + UART_RxCmd(UART, DISABLE); + VECTOR_IrqDis(DATA->irq); + VECTOR_IrqUnRegister(DATA->irq); + UART_DeInit(UART); + if (UART == UART2_DEV) { // restore command line mode DIAG_UartReInit((IRQ_FUN)UartLogIrqHandle); } - this->buf = NULL; + + this->buf = NULL; + this->baudrate = 0; delete DATA; } void SerialClass::flush() { + if (!this->data) + return; UART_WaitBusy(UART, 10); } size_t SerialClass::write(uint8_t c) { + if (!this->data) + return 0; while (UART_Writable(UART) == 0) {} UART_CharPut(UART, c); return 1; diff --git a/cores/realtek-ambz/arduino/libraries/Serial/SerialPrivate.h b/cores/realtek-ambz/arduino/libraries/Serial/SerialPrivate.h index aba22e7..3151135 100644 --- a/cores/realtek-ambz/arduino/libraries/Serial/SerialPrivate.h +++ b/cores/realtek-ambz/arduino/libraries/Serial/SerialPrivate.h @@ -8,8 +8,6 @@ typedef struct { UART_TypeDef *uart; IRQn irq; - pin_size_t rx; - pin_size_t tx; RingBuffer buf; } SerialData; From 9b7d34fa65933a08ddd9c7d4d2a1aa0dcd12d494 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 25 May 2023 14:33:38 +0200 Subject: [PATCH 11/31] [realtek-ambz2] Fix C++ support, implement SerialClass --- builder/family/realtek-ambz2.py | 2 +- .../arduino/libraries/Serial/Serial.cpp | 94 +++++++++++++++++++ .../arduino/libraries/Serial/SerialPrivate.h | 18 ++++ cores/realtek-ambz2/arduino/src/lt_defs.h | 7 ++ cores/realtek-ambz2/base/lt_family.h | 4 + cores/realtek-ambz2/base/port/printf.c | 2 +- cores/realtek-ambz2/base/sdk_extern.h | 1 + cores/realtek-ambz2/misc/rtl8710c_ram.ld | 67 +++++-------- docs/contrib/porting.md | 7 ++ docs/flashing/tools/adr.md | 4 + 10 files changed, 161 insertions(+), 45 deletions(-) create mode 100644 cores/realtek-ambz2/arduino/libraries/Serial/Serial.cpp create mode 100644 cores/realtek-ambz2/arduino/libraries/Serial/SerialPrivate.h create mode 100644 cores/realtek-ambz2/arduino/src/lt_defs.h diff --git a/builder/family/realtek-ambz2.py b/builder/family/realtek-ambz2.py index c6b2bbe..1b8a617 100644 --- a/builder/family/realtek-ambz2.py +++ b/builder/family/realtek-ambz2.py @@ -53,7 +53,7 @@ queue.AppendPublic( "-mthumb", "-mcmse", "-mfloat-abi=soft", - "--specs=nosys.specs", + "--specs=nano.specs", "-Wl,--use-blx", "-Wl,--undefined=gRamStartFun", "-Wl,-wrap,aesccmp_construct_mic_iv", diff --git a/cores/realtek-ambz2/arduino/libraries/Serial/Serial.cpp b/cores/realtek-ambz2/arduino/libraries/Serial/Serial.cpp new file mode 100644 index 0000000..eb1e462 --- /dev/null +++ b/cores/realtek-ambz2/arduino/libraries/Serial/Serial.cpp @@ -0,0 +1,94 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-05-24. */ + +#include "SerialPrivate.h" + +#if HAS_SERIAL0 +SerialClass Serial0(0, PIN_SERIAL0_RX, PIN_SERIAL0_TX); +#endif +#if HAS_SERIAL1 +SerialClass Serial1(1, PIN_SERIAL1_RX, PIN_SERIAL1_TX); +#endif +#if HAS_SERIAL2 +SerialClass Serial2(2, PIN_SERIAL2_RX, PIN_SERIAL2_TX); +#endif + +static void callback(uint32_t param, uint32_t event) { + if (event != RxIrq) + return; + hal_uart_adapter_t *uart = &pdUART; + + uint8_t c; + while (hal_uart_rgetc(uart, (char *)&c)) { +#if LT_AUTO_DOWNLOAD_REBOOT && defined(LT_UART_ADR_PATTERN) && PIN_SERIAL2_RX != PIN_INVALID + // parse UART protocol commands on UART2 + if (uart->base_addr == UART2) + SerialClass::adrParse(c); +#endif + pdBUF.store_char(c); + } +} + +void SerialClass::begin(unsigned long baudrate, uint16_t config) { + if (!this->data) { + this->data = new SerialData(); + this->buf = &BUF; + + if (this->port == 2) { + hal_uart_deinit(&log_uart); + } + + // TODO handle PIN_INVALID + hal_uart_init(&UART, this->tx, this->rx, NULL); + + if (this->rx != PIN_INVALID) { + hal_uart_enter_critical(); + hal_uart_rxind_hook(&UART, callback, (uint32_t)this->data, RxIrq); + UART.base_addr->ier_b.erbi = 1; + UART.base_addr->ier_b.etbei = 0; + hal_uart_exit_critical(); + } + } + + if (this->baudrate != baudrate || this->config != config) + this->configure(baudrate, config); +} + +void SerialClass::configure(unsigned long baudrate, uint16_t config) { + if (!this->data) + return; + + uint8_t dataWidth = (config & SERIAL_DATA_MASK) == SERIAL_DATA_7 ? 7 : 8; + uint8_t parity = (config & SERIAL_PARITY_MASK) ^ 0b11; + uint8_t stopBits = (config & SERIAL_STOP_BIT_MASK) == SERIAL_STOP_BIT_2 ? 2 : 1; + + hal_uart_set_baudrate(&UART, baudrate); + hal_uart_set_format(&UART, dataWidth, parity, stopBits); + + this->baudrate = baudrate; + this->config = config; +} + +void SerialClass::end() { + if (!this->data) + return; + + hal_uart_deinit(&UART); + + this->buf = NULL; + this->baudrate = 0; + delete DATA; +} + +void SerialClass::flush() { + if (!this->data) + return; + while (UART.base_addr->tflvr_b.tx_fifo_lv != 0) {} +} + +size_t SerialClass::write(uint8_t c) { + if (!this->data) + return 0; + while (!hal_uart_writeable(&UART)) {} + hal_uart_putc(&UART, c); + return 1; +} diff --git a/cores/realtek-ambz2/arduino/libraries/Serial/SerialPrivate.h b/cores/realtek-ambz2/arduino/libraries/Serial/SerialPrivate.h new file mode 100644 index 0000000..48c4d04 --- /dev/null +++ b/cores/realtek-ambz2/arduino/libraries/Serial/SerialPrivate.h @@ -0,0 +1,18 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-05-24. */ + +#pragma once + +#include +#include + +typedef struct { + hal_uart_adapter_t uart; + RingBuffer buf; +} SerialData; + +#define DATA ((SerialData *)data) +#define pDATA ((SerialData *)param) +#define BUF (DATA->buf) +#define pdBUF (pDATA->buf) +#define UART (DATA->uart) +#define pdUART (pDATA->uart) diff --git a/cores/realtek-ambz2/arduino/src/lt_defs.h b/cores/realtek-ambz2/arduino/src/lt_defs.h new file mode 100644 index 0000000..b79eb88 --- /dev/null +++ b/cores/realtek-ambz2/arduino/src/lt_defs.h @@ -0,0 +1,7 @@ +#pragma once + +#error "Don't include this file directly" + +#define LT_ARD_HAS_SERIAL 1 + +#define LT_ARD_MD5_MBEDTLS 1 diff --git a/cores/realtek-ambz2/base/lt_family.h b/cores/realtek-ambz2/base/lt_family.h index 9723ffb..d9c9f41 100644 --- a/cores/realtek-ambz2/base/lt_family.h +++ b/cores/realtek-ambz2/base/lt_family.h @@ -16,3 +16,7 @@ #error "No serial port is available" #endif #endif + +// Auto-download-reboot detection pattern +// "ping" command for BootROM +#define LT_UART_ADR_PATTERN 'p', 'i', 'n', 'g', '\n' diff --git a/cores/realtek-ambz2/base/port/printf.c b/cores/realtek-ambz2/base/port/printf.c index f3aa09b..d151780 100644 --- a/cores/realtek-ambz2/base/port/printf.c +++ b/cores/realtek-ambz2/base/port/printf.c @@ -19,7 +19,7 @@ void putchar_(char c) { } void putchar_p(char c, unsigned long port) { - while ((uart_dev[port]->tflvr & 0x1F) > 15) {} + while (uart_dev[port]->tflvr_b.tx_fifo_lv >= Uart_Tx_FIFO_Size) {} uart_dev[port]->thr = c; } diff --git a/cores/realtek-ambz2/base/sdk_extern.h b/cores/realtek-ambz2/base/sdk_extern.h index 476e0ee..e5d5c1a 100644 --- a/cores/realtek-ambz2/base/sdk_extern.h +++ b/cores/realtek-ambz2/base/sdk_extern.h @@ -10,6 +10,7 @@ extern "C" { #endif // __cplusplus // SDK +extern hal_uart_adapter_t log_uart; void software_reset(); void sys_swd_off(); void sys_uart_download_mode(); diff --git a/cores/realtek-ambz2/misc/rtl8710c_ram.ld b/cores/realtek-ambz2/misc/rtl8710c_ram.ld index cc6a48d..221819e 100644 --- a/cores/realtek-ambz2/misc/rtl8710c_ram.ld +++ b/cores/realtek-ambz2/misc/rtl8710c_ram.ld @@ -134,26 +134,6 @@ SECTIONS *(.sram.data*) *(.data*) - . = ALIGN(4); - /* preinit data */ - PROVIDE_HIDDEN (__preinit_array_start = .); - KEEP(*(.preinit_array)) - PROVIDE_HIDDEN (__preinit_array_end = .); - - . = ALIGN(4); - /* init data */ - PROVIDE_HIDDEN (__init_array_start = .); - KEEP(*(SORT(.init_array.*))) - KEEP(*(.init_array)) - PROVIDE_HIDDEN (__init_array_end = .); - - . = ALIGN(4); - /* finit data */ - PROVIDE_HIDDEN (__fini_array_start = .); - KEEP(*(SORT(.fini_array.*))) - KEEP(*(.fini_array)) - PROVIDE_HIDDEN (__fini_array_end = .); - KEEP(*(.jcr*)) . = ALIGN(4); /* All data end */ @@ -282,29 +262,6 @@ SECTIONS /* put RO data sections need to be encrypted here */ *(.xip.sec_rodata*) - /* Add This for C++ support */ - /* ambd_arduino/Arduino_package/hardware/variants/rtl8720dn_bw16/linker_scripts/gcc/rlx8721d_img2_is_arduino.ld */ - . = ALIGN(4); - __preinit_array_start = .; - KEEP(*(.preinit_array)) - __preinit_array_end = .; - . = ALIGN(4); - __init_array_start = .; - KEEP(*(SORT(.init_array.*))) - KEEP(*(.init_array)) - __init_array_end = .; - . = ALIGN(4); - __fini_array_start = .; - KEEP(*(SORT(.fini_array.*))) - KEEP(*(.fini_array)) - __fini_array_end = .; - /*-----------------*/ - /* https://community.silabs.com/s/article/understand-the-gnu-linker-script-of-cortex-m4?language=en_US */ - KEEP(*(.init)) - KEEP(*(.fini)) - *(.init) - *(.fini) - __xip_code_text_end__ = .; } > XIP_FLASH_C @@ -330,6 +287,30 @@ SECTIONS KEEP(*crtend.o(.dtors)) *(.rodata .rodata.* .gnu.linkonce.r.*) + /* Add This for C++ support */ + /* ambd_arduino/Arduino_package/hardware/variants/rtl8720dn_bw16/linker_scripts/gcc/rlx8721d_img2_is_arduino.ld */ + . = ALIGN(4); + __preinit_array_start = .; + KEEP(*(.preinit_array)) + __preinit_array_end = .; + . = ALIGN(4); + __init_array_start = .; + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + __init_array_end = .; + . = ALIGN(4); + __fini_array_start = .; + KEEP(*(SORT(.fini_array.*))) + KEEP(*(.fini_array)) + __fini_array_end = .; + /*-----------------*/ + + /* https://community.silabs.com/s/article/understand-the-gnu-linker-script-of-cortex-m4?language=en_US */ + KEEP(*(.init)) + KEEP(*(.fini)) + *(.init) + *(.fini) + . = ALIGN(4); __xip_code_rodata_end__ = .; } > XIP_FLASH_P diff --git a/docs/contrib/porting.md b/docs/contrib/porting.md index 48f7275..61cc4d8 100644 --- a/docs/contrib/porting.md +++ b/docs/contrib/porting.md @@ -50,6 +50,7 @@ Here's what has to be done to make that work: - Make sure not to make a mess in the `CCFLAGS`/`CPPDEFINES`, and only include what's needed there. Some flags are project-wide (family-independent) in `builder/frameworks/base.py`. - Use a **pure PlatformIO** project - **not ESPHome!**. Pass one of the generic boards you created before, and `framework = base` in `platformio.ini`. Generally, try to get the thing to compile. - Use a simple Hello World program - C, not C++. Only add `main()` function with a `printf()` and a `while(1)` loop. + - I've noticed that using `nano.specs` instead of `nosys.specs` produces smaller binaries. 9. When you get it to link successfully, build a UF2 file. @@ -91,3 +92,9 @@ Here's what has to be done to make that work: 5. Write LibreTiny C APIs - in `lt_api.c`. 6. At this point, your Hello World code should work fine. + +## Porting Arduino Core - C++ support + +1. Add main.cpp and write wiring_*.c ports. GPIOs and stuff should work even without proper C++ support. + +2. Port Serial library first. This should already show whether C++ works fine or if it doesn't. For example, calling `Serial.println()` refers to the virtual function `Print::write`, which will probably crash the chip if C++ is not being linked properly. diff --git a/docs/flashing/tools/adr.md b/docs/flashing/tools/adr.md index a976b67..3c41299 100644 --- a/docs/flashing/tools/adr.md +++ b/docs/flashing/tools/adr.md @@ -16,3 +16,7 @@ The code listens on UART1 for a link-check command (`01 E0 FC 01 00`). The baudr ## Realtek AmebaZ This only works when using [ltchiptool](ltchiptool.md) for flashing. Upon starting UART communication, the tool sends `55 AA 22 E0 D6 FC` (0x55AA followed by the `realtek-ambz` family ID). After detecting that pattern, the chip proceeds to reboot into UART download mode (using [`lt_reboot_download_mode()`](../../../ltapi/lt__device_8h.md)) + +## Realtek AmebaZ2 + +The code listens on UART2 for a `ping\n` command, that is sent by [ltchiptool](ltchiptool.md) (and possibly by the vendor flasher, too). The device is then rebooted to download mode. From 4dae304f510b3328841c0cb452a6efb3cc2ea643 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 25 May 2023 20:43:00 +0200 Subject: [PATCH 12/31] [core] Add lt_get_device_mac() function --- cores/beken-72xx/base/lt_api.c | 10 ++++------ cores/common/base/api/lt_cpu.h | 1 + cores/common/base/api/lt_device.h | 7 +++++++ cores/common/base/lt_api.c | 6 ++++++ cores/realtek-amb/arduino/libraries/WiFi/WiFiSTA.cpp | 5 +---- cores/realtek-ambz/base/lt_api.c | 7 +++++++ cores/realtek-ambz2/base/lt_api.c | 10 ++++------ 7 files changed, 30 insertions(+), 16 deletions(-) diff --git a/cores/beken-72xx/base/lt_api.c b/cores/beken-72xx/base/lt_api.c index 1191cb2..04c0416 100644 --- a/cores/beken-72xx/base/lt_api.c +++ b/cores/beken-72xx/base/lt_api.c @@ -29,12 +29,6 @@ lt_cpu_model_t lt_cpu_get_model() { return CPU_MODEL_ENUM(FAMILY, chipId); } -uint32_t lt_cpu_get_mac_id() { - uint8_t mac[6]; - cfg_load_mac(mac); // force loading MAC from TLV (ignore user-set WiFi MAC) - return (mac[3]) | (mac[4] << 8) | (mac[5] << 16); -} - const char *lt_cpu_get_core_type() { return "ARM968E-S"; } @@ -45,6 +39,10 @@ const char *lt_cpu_get_core_type() { | | | |/ _ \ \ / / |/ __/ _ \ | |__| | __/\ V /| | (_| __/ |_____/ \___| \_/ |_|\___\__*/ +void lt_get_device_mac(uint8_t *mac) { + cfg_load_mac(mac); +} + void lt_reboot() { bk_reboot(); } diff --git a/cores/common/base/api/lt_cpu.h b/cores/common/base/api/lt_cpu.h index 7feb523..f2c6b80 100644 --- a/cores/common/base/api/lt_cpu.h +++ b/cores/common/base/api/lt_cpu.h @@ -38,6 +38,7 @@ uint32_t lt_cpu_get_unique_id(); /** * @brief Get CPU ID based on the last three octets of MAC address. * Note: the number is 24-bit (with the MSB being zero). + * The 3rd-to-last octet is least-significant, the last octet is most-significant. */ uint32_t lt_cpu_get_mac_id(); diff --git a/cores/common/base/api/lt_device.h b/cores/common/base/api/lt_device.h index 36e9a14..43d8477 100644 --- a/cores/common/base/api/lt_device.h +++ b/cores/common/base/api/lt_device.h @@ -20,6 +20,13 @@ const char *lt_get_board_code(); */ const char *lt_get_device_name(); +/** + * @brief Read device's *default* MAC address into 'mac' array. + * This can be used even without Wi-Fi enabled, and will ignore + * user-changed Wi-Fi MAC (if changing is possible). + */ +void lt_get_device_mac(uint8_t *mac); + /** * @brief Reboot the CPU. */ diff --git a/cores/common/base/lt_api.c b/cores/common/base/lt_api.c index df0e15d..b65a7ad 100644 --- a/cores/common/base/lt_api.c +++ b/cores/common/base/lt_api.c @@ -39,6 +39,12 @@ __attribute__((weak)) uint32_t lt_cpu_get_unique_id() { return lt_cpu_get_mac_id(); } +__attribute__((weak)) uint32_t lt_cpu_get_mac_id() { + uint8_t mac[6]; + lt_get_device_mac(mac); + return (mac[3] << 0) | (mac[4] << 8) | (mac[5] << 16); +} + __attribute__((weak)) uint8_t lt_cpu_get_core_count() { return 1; } diff --git a/cores/realtek-amb/arduino/libraries/WiFi/WiFiSTA.cpp b/cores/realtek-amb/arduino/libraries/WiFi/WiFiSTA.cpp index 7067a8f..926ecc7 100644 --- a/cores/realtek-amb/arduino/libraries/WiFi/WiFiSTA.cpp +++ b/cores/realtek-amb/arduino/libraries/WiFi/WiFiSTA.cpp @@ -158,10 +158,7 @@ IPAddress WiFiClass::localIP() { uint8_t *WiFiClass::macAddress(uint8_t *mac) { if ((getMode() & WIFI_MODE_STA) == 0) { - uint8_t *efuse = (uint8_t *)malloc(512); - EFUSE_LogicalMap_Read(efuse); - memcpy(mac, efuse + 0x11A, ETH_ALEN); - free(efuse); + lt_get_device_mac(mac); return mac; } memcpy(mac, NETIF_RTW_STA.hwaddr, ETH_ALEN); diff --git a/cores/realtek-ambz/base/lt_api.c b/cores/realtek-ambz/base/lt_api.c index 94624e6..2d7181a 100644 --- a/cores/realtek-ambz/base/lt_api.c +++ b/cores/realtek-ambz/base/lt_api.c @@ -57,6 +57,13 @@ uint32_t lt_cpu_get_freq() { | | | |/ _ \ \ / / |/ __/ _ \ | |__| | __/\ V /| | (_| __/ |_____/ \___| \_/ |_|\___\__*/ +void lt_get_device_mac(uint8_t *mac) { + uint8_t *efuse = (uint8_t *)malloc(512); + EFUSE_LogicalMap_Read(efuse); + memcpy(mac, efuse + 0x11A, 6); + free(efuse); +} + bool lt_reboot_download_mode() { // mww 0x40000138 0x8 HAL_WRITE32(SYSTEM_CTRL_BASE, REG_SYS_NORESET_FF, 0x08); diff --git a/cores/realtek-ambz2/base/lt_api.c b/cores/realtek-ambz2/base/lt_api.c index 3de1f67..ae1df72 100644 --- a/cores/realtek-ambz2/base/lt_api.c +++ b/cores/realtek-ambz2/base/lt_api.c @@ -28,12 +28,6 @@ lt_cpu_model_t lt_cpu_get_model() { return CPU_MODEL_ENUM(FAMILY, (chip_id & 0xFF) | flash_mode); } -uint32_t lt_cpu_get_mac_id() { - uint8_t mac[3]; - efuse_logical_read(0x11A + 3, 3, mac); - return (mac[0] << 0) | (mac[1] << 8) | (mac[2] << 16); -} - const char *lt_cpu_get_core_type() { return "ARM Cortex-M4"; } @@ -48,6 +42,10 @@ uint32_t lt_cpu_get_freq() { | | | |/ _ \ \ / / |/ __/ _ \ | |__| | __/\ V /| | (_| __/ |_____/ \___| \_/ |_|\___\__*/ +void lt_get_device_mac(uint8_t *mac) { + efuse_logical_read(0x11A, 6, mac); +} + void lt_reboot() { sys_cpu_reset(); while (1) {} From a80032d46c7731c2b466327ebf53741bc4cde057 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Fri, 26 May 2023 15:27:27 +0200 Subject: [PATCH 13/31] [core] Move Wiring common core to wiring/, reset watchdog in yield() --- builder/utils/cores.py | 2 + cores/common/arduino/src/common/hooks.c | 61 ------------------- .../common/arduino/src/{ => wiring}/wiring.c | 5 ++ .../src/{ => wiring}/wiring_compat.cpp | 0 .../arduino/src/{ => wiring}/wiring_compat.h | 0 .../arduino/src/{ => wiring}/wiring_custom.c | 0 .../arduino/src/{ => wiring}/wiring_custom.h | 0 .../arduino/src/{ => wiring}/wiring_irq.c | 0 .../WMath.cpp => wiring/wiring_math.cpp} | 0 .../arduino/src/{ => wiring}/wiring_private.c | 0 .../arduino/src/{ => wiring}/wiring_private.h | 0 .../src/{common => wiring}/wiring_shift.c | 0 12 files changed, 7 insertions(+), 61 deletions(-) delete mode 100644 cores/common/arduino/src/common/hooks.c rename cores/common/arduino/src/{ => wiring}/wiring.c (81%) rename cores/common/arduino/src/{ => wiring}/wiring_compat.cpp (100%) rename cores/common/arduino/src/{ => wiring}/wiring_compat.h (100%) rename cores/common/arduino/src/{ => wiring}/wiring_custom.c (100%) rename cores/common/arduino/src/{ => wiring}/wiring_custom.h (100%) rename cores/common/arduino/src/{ => wiring}/wiring_irq.c (100%) rename cores/common/arduino/src/{common/WMath.cpp => wiring/wiring_math.cpp} (100%) rename cores/common/arduino/src/{ => wiring}/wiring_private.c (100%) rename cores/common/arduino/src/{ => wiring}/wiring_private.h (100%) rename cores/common/arduino/src/{common => wiring}/wiring_shift.c (100%) diff --git a/builder/utils/cores.py b/builder/utils/cores.py index f4a8ad4..280d5b0 100644 --- a/builder/utils/cores.py +++ b/builder/utils/cores.py @@ -50,6 +50,7 @@ def env_add_core_sources(env: Environment, queue, name: str, path: str) -> bool: "+", "+", "+", + "+", "+", ], includes=[ @@ -58,6 +59,7 @@ def env_add_core_sources(env: Environment, queue, name: str, path: str) -> bool: "!", "!", "!", + "!", ], ) queue.AddLibrary( diff --git a/cores/common/arduino/src/common/hooks.c b/cores/common/arduino/src/common/hooks.c deleted file mode 100644 index 3f9b0a9..0000000 --- a/cores/common/arduino/src/common/hooks.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - Copyright (c) 2015 Arduino LLC. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -/** - * Empty yield() hook. - * - * This function is intended to be used by library writers to build - * libraries or sketches that supports cooperative threads. - * - * Its defined as a weak symbol and it can be redefined to implement a - * real cooperative scheduler. - */ -static void __empty() { - // Empty -} - -void yield(void) __attribute__((weak, alias("__empty"))); - -/** - * SysTick hook - * - * This function is called from SysTick handler, before the default - * handler provided by Arduino. - */ -static int __false() { - // Return false - return 0; -} - -int sysTickHook(void) __attribute__((weak, alias("__false"))); - -/** - * SVC hook - * PendSV hook - * - * These functions are called from SVC handler, and PensSV handler. - * Default action is halting. - */ -static void __halt() { - // Halts - while (1) - ; -} - -void svcHook(void) __attribute__((weak, alias("__halt"))); -void pendSVHook(void) __attribute__((weak, alias("__halt"))); diff --git a/cores/common/arduino/src/wiring.c b/cores/common/arduino/src/wiring/wiring.c similarity index 81% rename from cores/common/arduino/src/wiring.c rename to cores/common/arduino/src/wiring/wiring.c index 5f344de..f96fa62 100644 --- a/cores/common/arduino/src/wiring.c +++ b/cores/common/arduino/src/wiring/wiring.c @@ -12,6 +12,11 @@ __attribute__((weak)) void yield() { runPeriodicTasks(); vTaskDelay(1); taskYIELD(); + lt_wdt_feed(); } +#else + +__attribute__((weak)) void yield() {} + #endif diff --git a/cores/common/arduino/src/wiring_compat.cpp b/cores/common/arduino/src/wiring/wiring_compat.cpp similarity index 100% rename from cores/common/arduino/src/wiring_compat.cpp rename to cores/common/arduino/src/wiring/wiring_compat.cpp diff --git a/cores/common/arduino/src/wiring_compat.h b/cores/common/arduino/src/wiring/wiring_compat.h similarity index 100% rename from cores/common/arduino/src/wiring_compat.h rename to cores/common/arduino/src/wiring/wiring_compat.h diff --git a/cores/common/arduino/src/wiring_custom.c b/cores/common/arduino/src/wiring/wiring_custom.c similarity index 100% rename from cores/common/arduino/src/wiring_custom.c rename to cores/common/arduino/src/wiring/wiring_custom.c diff --git a/cores/common/arduino/src/wiring_custom.h b/cores/common/arduino/src/wiring/wiring_custom.h similarity index 100% rename from cores/common/arduino/src/wiring_custom.h rename to cores/common/arduino/src/wiring/wiring_custom.h diff --git a/cores/common/arduino/src/wiring_irq.c b/cores/common/arduino/src/wiring/wiring_irq.c similarity index 100% rename from cores/common/arduino/src/wiring_irq.c rename to cores/common/arduino/src/wiring/wiring_irq.c diff --git a/cores/common/arduino/src/common/WMath.cpp b/cores/common/arduino/src/wiring/wiring_math.cpp similarity index 100% rename from cores/common/arduino/src/common/WMath.cpp rename to cores/common/arduino/src/wiring/wiring_math.cpp diff --git a/cores/common/arduino/src/wiring_private.c b/cores/common/arduino/src/wiring/wiring_private.c similarity index 100% rename from cores/common/arduino/src/wiring_private.c rename to cores/common/arduino/src/wiring/wiring_private.c diff --git a/cores/common/arduino/src/wiring_private.h b/cores/common/arduino/src/wiring/wiring_private.h similarity index 100% rename from cores/common/arduino/src/wiring_private.h rename to cores/common/arduino/src/wiring/wiring_private.h diff --git a/cores/common/arduino/src/common/wiring_shift.c b/cores/common/arduino/src/wiring/wiring_shift.c similarity index 100% rename from cores/common/arduino/src/common/wiring_shift.c rename to cores/common/arduino/src/wiring/wiring_shift.c From 87ad0798e401dcd84c904e91b2ad3ef39408aa67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 27 May 2023 15:41:07 +0200 Subject: [PATCH 14/31] [realtek-ambz2] Adapt WiFi library to ambz2_sdk --- builder/family/realtek-ambz2.py | 1 + .../arduino/libraries/api/WiFi/WiFi.cpp | 10 +++--- .../libraries/api/WiFi/WiFiGeneric.cpp | 2 +- .../arduino/libraries/api/WiFi/WiFiType.h | 25 +++++++++++++++ .../libraries/common/WiFiUdp/LwIPUdp.cpp | 8 ++--- .../libraries/common/mDNS/LwIPmDNS.cpp | 5 +++ .../arduino/libraries/WiFi/WiFiEvents.cpp | 1 - .../arduino/libraries/WiFi/WiFiGeneric.cpp | 13 ++++---- .../arduino/libraries/WiFi/WiFiPrivate.h | 32 +++++++++++++++++++ .../arduino/libraries/WiFi/WiFiSTA.cpp | 9 ++---- cores/realtek-amb/base/config/lwipopts.h | 13 ++++++++ .../base/fixups/wifi_mode.c | 0 cores/realtek-ambz/base/config/lwipopts.h | 18 ----------- cores/realtek-ambz2/arduino/src/lt_defs.h | 1 + .../realtek-ambz2/base/config/platform_opts.h | 9 ++++++ 15 files changed, 106 insertions(+), 41 deletions(-) rename cores/{realtek-ambz => realtek-amb}/base/fixups/wifi_mode.c (100%) delete mode 100644 cores/realtek-ambz/base/config/lwipopts.h create mode 100644 cores/realtek-ambz2/base/config/platform_opts.h diff --git a/builder/family/realtek-ambz2.py b/builder/family/realtek-ambz2.py index 1b8a617..1fa5026 100644 --- a/builder/family/realtek-ambz2.py +++ b/builder/family/realtek-ambz2.py @@ -198,6 +198,7 @@ queue.AddLibrary( "+", # network - api - wifi "+", + "ARDUINO" in "ENV" and "-", # network - api - wifi - rtw_wpa_supplicant "+", "+", diff --git a/cores/common/arduino/libraries/api/WiFi/WiFi.cpp b/cores/common/arduino/libraries/api/WiFi/WiFi.cpp index 12344dc..d20012a 100644 --- a/cores/common/arduino/libraries/api/WiFi/WiFi.cpp +++ b/cores/common/arduino/libraries/api/WiFi/WiFi.cpp @@ -3,11 +3,11 @@ #include "WiFi.h" void WiFiClass::printDiag(Print &dest) { - const char *modes[] = {"NULL", "STA", "AP", "STA+AP"}; - const char *enc[] = {"Open", "WEP", "WPA PSK", "WPA2 PSK", "WPA/WPA2", "WPA", "WPA2"}; - dest.print("Mode: "); - dest.println(modes[getMode()]); + dest.println(WiFiModeText[getMode()]); + + dest.print("Status: "); + dest.println(WiFiStatusText[status()]); if (getMode() & WIFI_MODE_STA) { dest.println("-- Station --"); @@ -21,7 +21,7 @@ void WiFiClass::printDiag(Print &dest) { dest.print("RSSI: "); dest.println(RSSI()); dest.print("Encryption: "); - dest.println(enc[getEncryption()]); + dest.println(WiFiAuthModeText[getEncryption()]); dest.print("IP: "); dest.println(localIP()); dest.print("MAC: "); diff --git a/cores/common/arduino/libraries/api/WiFi/WiFiGeneric.cpp b/cores/common/arduino/libraries/api/WiFi/WiFiGeneric.cpp index 7e205bc..e3fddb4 100644 --- a/cores/common/arduino/libraries/api/WiFi/WiFiGeneric.cpp +++ b/cores/common/arduino/libraries/api/WiFi/WiFiGeneric.cpp @@ -11,7 +11,7 @@ bool WiFiClass::mode(WiFiMode mode) { pWiFi = this; WiFiMode currentMode = getMode(); - LT_DM(WIFI, "Mode changing %u -> %u", currentMode, mode); + LT_DM(WIFI, "Mode changing %s -> %s", WiFiModeText[currentMode], WiFiModeText[mode]); if (mode == currentMode) return true; diff --git a/cores/common/arduino/libraries/api/WiFi/WiFiType.h b/cores/common/arduino/libraries/api/WiFi/WiFiType.h index 027f00b..3d5942a 100644 --- a/cores/common/arduino/libraries/api/WiFi/WiFiType.h +++ b/cores/common/arduino/libraries/api/WiFi/WiFiType.h @@ -162,3 +162,28 @@ typedef enum { WLMODE_DISABLE = 1, WLMODE_ENABLE = 2, } WiFiModeAction; + +static const char *WiFiModeText[] = {"NULL", "STA", "AP", "AP+STA"}; +static const char *WiFiStatusText[] = { + "Idle", + "No SSID", + "Scan Completed", + "Connected", + "Connect failed", + "Connection lost", + "Disconnected", +}; +static const char *WiFiAuthModeText[] = { + "Open", + "WEP", + "WPA PSK", + "WPA2 PSK", + "WPA/WPA2 PSK", + "WPA2 EAP", + "WPA3 PSK", + "WPA2/WPA3 PSK", + "WAPI PSK", + "WPA", + "WPA2", + "Auto", +}; diff --git a/cores/common/arduino/libraries/common/WiFiUdp/LwIPUdp.cpp b/cores/common/arduino/libraries/common/WiFiUdp/LwIPUdp.cpp index 6e2dede..bf5e0e1 100644 --- a/cores/common/arduino/libraries/common/WiFiUdp/LwIPUdp.cpp +++ b/cores/common/arduino/libraries/common/WiFiUdp/LwIPUdp.cpp @@ -72,11 +72,11 @@ uint8_t LwIPUDP::begin(IPAddress address, uint16_t port) { } uint8_t LwIPUDP::begin(uint16_t p) { - return begin(IPAddress(INADDR_ANY), p); + return begin(IPAddress((uint32_t)INADDR_ANY), p); } uint8_t LwIPUDP::beginMulticast(IPAddress a, uint16_t p) { - if (begin(IPAddress(INADDR_ANY), p)) { + if (begin(IPAddress((uint32_t)INADDR_ANY), p)) { if ((uint32_t)a != 0) { struct ip_mreq mreq; mreq.imr_multiaddr.s_addr = (in_addr_t)a; @@ -111,14 +111,14 @@ void LwIPUDP::stop() { mreq.imr_multiaddr.s_addr = (in_addr_t)multicast_ip; mreq.imr_interface.s_addr = (in_addr_t)0; setsockopt(udp_server, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)); - multicast_ip = IPAddress(INADDR_ANY); + multicast_ip = IPAddress((uint32_t)INADDR_ANY); } close(udp_server); udp_server = -1; } int LwIPUDP::beginMulticastPacket() { - if (!server_port || multicast_ip == IPAddress(INADDR_ANY)) + if (!server_port || multicast_ip == IPAddress((uint32_t)INADDR_ANY)) return 0; remote_ip = multicast_ip; remote_port = server_port; diff --git a/cores/common/arduino/libraries/common/mDNS/LwIPmDNS.cpp b/cores/common/arduino/libraries/common/mDNS/LwIPmDNS.cpp index f69eb04..0f602db 100644 --- a/cores/common/arduino/libraries/common/mDNS/LwIPmDNS.cpp +++ b/cores/common/arduino/libraries/common/mDNS/LwIPmDNS.cpp @@ -13,6 +13,11 @@ extern "C" { #include } +#if LWIP_VERSION_SIMPLE < 20100 && defined(LWIP_NETIF_EXT_STATUS_CALLBACK) +#warning "LWIP_NETIF_EXT_STATUS_CALLBACK not available before lwIP 2.1.0" +#undef LWIP_NETIF_EXT_STATUS_CALLBACK +#endif + #if LWIP_MDNS_RESPONDER static std::vector services_name; diff --git a/cores/realtek-amb/arduino/libraries/WiFi/WiFiEvents.cpp b/cores/realtek-amb/arduino/libraries/WiFi/WiFiEvents.cpp index b889a9a..b0c5263 100644 --- a/cores/realtek-amb/arduino/libraries/WiFi/WiFiEvents.cpp +++ b/cores/realtek-amb/arduino/libraries/WiFi/WiFiEvents.cpp @@ -68,7 +68,6 @@ void wifi_unreg_event_handler(unsigned int event_cmds, rtw_event_handler_t handl // function called by wext_wlan_indicate void wifi_indication(rtw_event_indicate_t event, char *buf, int buf_len, int flags) { - LT_HEAP_I(); if (event >= WIFI_EVENT_MAX) return; if (wifiEventQueueHandle && wifiEventTaskHandle) { diff --git a/cores/realtek-amb/arduino/libraries/WiFi/WiFiGeneric.cpp b/cores/realtek-amb/arduino/libraries/WiFi/WiFiGeneric.cpp index 4c6a7f2..8448e1b 100644 --- a/cores/realtek-amb/arduino/libraries/WiFi/WiFiGeneric.cpp +++ b/cores/realtek-amb/arduino/libraries/WiFi/WiFiGeneric.cpp @@ -9,8 +9,7 @@ int32_t WiFiClass::channel() { } bool WiFiClass::modePriv(WiFiMode mode, WiFiModeAction sta, WiFiModeAction ap) { - __wrap_rtl_printf_disable(); - __wrap_DiagPrintf_disable(); + DIAG_PRINTF_DISABLE(); startWifiTask(); if (!DATA->initialized) { @@ -102,7 +101,11 @@ bool WiFiClass::modePriv(WiFiMode mode, WiFiModeAction sta, WiFiModeAction ap) { LT_DM(WIFI, "Mode: %s DISABLE", WLAN1_NAME); netif_set_link_down(WLAN1_NETIF); netif_set_down(WLAN1_NETIF); +#if !LT_RTL8720C rltk_stop_softap(WLAN1_NAME); +#else + rltk_suspend_softap(WLAN1_NAME); +#endif rltk_wlan_init(WLAN1_IDX, RTW_MODE_NONE); wext_set_mode(WLAN1_NAME, IW_MODE_INFRA); } @@ -152,13 +155,11 @@ bool WiFiClass::modePriv(WiFiMode mode, WiFiModeAction sta, WiFiModeAction ap) { } LT_HEAP_I(); - __wrap_rtl_printf_enable(); - __wrap_DiagPrintf_enable(); + DIAG_PRINTF_ENABLE(); return true; error: - __wrap_rtl_printf_enable(); - __wrap_DiagPrintf_enable(); + DIAG_PRINTF_ENABLE(); return false; } diff --git a/cores/realtek-amb/arduino/libraries/WiFi/WiFiPrivate.h b/cores/realtek-amb/arduino/libraries/WiFi/WiFiPrivate.h index aa3079d..99745a2 100644 --- a/cores/realtek-amb/arduino/libraries/WiFi/WiFiPrivate.h +++ b/cores/realtek-amb/arduino/libraries/WiFi/WiFiPrivate.h @@ -31,7 +31,9 @@ extern void dns_server_init(struct netif *pnetif); extern void dns_server_deinit(void); // wifi_util.c +#if !LT_RTL8720C extern void rltk_stop_softap(const char *ifname); +#endif extern void rltk_suspend_softap(const char *ifname); extern void rltk_suspend_softap_beacon(const char *ifname); @@ -65,3 +67,33 @@ typedef struct { #define DATA ((WiFiData *)data) #define pDATA ((WiFiData *)pWiFi->data) #define cDATA ((WiFiData *)cls->data) + +#if LT_RTL8710B // Realtek AmebaZ +#define DIAG_PRINTF_ENABLE() \ + do { \ + __wrap_rtl_printf_enable(); \ + __wrap_DiagPrintf_enable(); \ + } while (0); +#define DIAG_PRINTF_DISABLE() \ + do { \ + __wrap_rtl_printf_disable(); \ + __wrap_DiagPrintf_disable(); \ + } while (0); + +#elif LT_RTL8720C // Realtek AmebaZ2 +#define DIAG_PRINTF_ENABLE() \ + do { \ + __wrap_rt_printf_enable(); \ + __wrap_rt_log_printf_enable(); \ + } while (0); +#define DIAG_PRINTF_DISABLE() \ + do { \ + __wrap_rt_printf_disable(); \ + __wrap_rt_log_printf_disable(); \ + } while (0); + +#else +#define DIAG_PRINTF_ENABLE() +#define DIAG_PRINTF_DISABLE() + +#endif diff --git a/cores/realtek-amb/arduino/libraries/WiFi/WiFiSTA.cpp b/cores/realtek-amb/arduino/libraries/WiFi/WiFiSTA.cpp index 926ecc7..f5164ce 100644 --- a/cores/realtek-amb/arduino/libraries/WiFi/WiFiSTA.cpp +++ b/cores/realtek-amb/arduino/libraries/WiFi/WiFiSTA.cpp @@ -67,8 +67,7 @@ bool WiFiClass::reconnect(const uint8_t *bssid) { WiFiNetworkInfo &info = DATA->sta; LT_IM(WIFI, "Connecting to %s (bssid=%p)", info.ssid, bssid); - __wrap_rtl_printf_disable(); - __wrap_DiagPrintf_disable(); + DIAG_PRINTF_DISABLE(); wext_set_ssid(WLAN0_NAME, (uint8_t *)"-", 1); @@ -116,8 +115,7 @@ bool WiFiClass::reconnect(const uint8_t *bssid) { wifi_indication(WIFI_EVENT_CONNECT, (char *)eventInfo, ARDUINO_EVENT_WIFI_STA_GOT_IP, -2); // free memory as wifi_indication creates a copy free(eventInfo); - __wrap_rtl_printf_enable(); - __wrap_DiagPrintf_enable(); + DIAG_PRINTF_ENABLE(); return true; } LT_EM(WIFI, "DHCP failed; dhcpRet=%d", dhcpRet); @@ -126,8 +124,7 @@ bool WiFiClass::reconnect(const uint8_t *bssid) { } LT_EM(WIFI, "Connection failed; ret=%d", ret); error: - __wrap_rtl_printf_enable(); - __wrap_DiagPrintf_enable(); + DIAG_PRINTF_ENABLE(); return false; } diff --git a/cores/realtek-amb/base/config/lwipopts.h b/cores/realtek-amb/base/config/lwipopts.h index 97af786..326f60d 100644 --- a/cores/realtek-amb/base/config/lwipopts.h +++ b/cores/realtek-amb/base/config/lwipopts.h @@ -12,3 +12,16 @@ #ifndef INT_MAX #define INT_MAX 2147483647 // for RECV_BUFSIZE_DEFAULT #endif + +// - 2022-05-23 set LWIP_NUM_NETIF_CLIENT_DATA to 1 +#define LWIP_NUM_NETIF_CLIENT_DATA 1 +#define LWIP_NETIF_EXT_STATUS_CALLBACK 1 +// - 2022-05-23 set MEMP_NUM_UDP_PCB to 7 +#undef MEMP_NUM_UDP_PCB +#define MEMP_NUM_UDP_PCB 7 + +// LWIP_COMPAT_MUTEX cannot prevent priority inversion. It is recommended to implement priority-aware mutexes. (Define +// LWIP_COMPAT_MUTEX_ALLOWED to disable this error.) +#define LWIP_COMPAT_MUTEX_ALLOWED 1 + +#define LWIP_TCPIP_TIMEOUT 1 diff --git a/cores/realtek-ambz/base/fixups/wifi_mode.c b/cores/realtek-amb/base/fixups/wifi_mode.c similarity index 100% rename from cores/realtek-ambz/base/fixups/wifi_mode.c rename to cores/realtek-amb/base/fixups/wifi_mode.c diff --git a/cores/realtek-ambz/base/config/lwipopts.h b/cores/realtek-ambz/base/config/lwipopts.h deleted file mode 100644 index 8c5aa40..0000000 --- a/cores/realtek-ambz/base/config/lwipopts.h +++ /dev/null @@ -1,18 +0,0 @@ -/* Copyright (c) Kuba Szczodrzyński 2023-03-02. */ - -#pragma once - -#include_next "lwipopts.h" - -// - 2022-05-23 set LWIP_NUM_NETIF_CLIENT_DATA to 1 -#define LWIP_NUM_NETIF_CLIENT_DATA 1 -#define LWIP_NETIF_EXT_STATUS_CALLBACK 1 -// - 2022-05-23 set MEMP_NUM_UDP_PCB to 7 -#undef MEMP_NUM_UDP_PCB -#define MEMP_NUM_UDP_PCB 7 - -// LWIP_COMPAT_MUTEX cannot prevent priority inversion. It is recommended to implement priority-aware mutexes. (Define -// LWIP_COMPAT_MUTEX_ALLOWED to disable this error.) -#define LWIP_COMPAT_MUTEX_ALLOWED 1 - -#define LWIP_TCPIP_TIMEOUT 1 diff --git a/cores/realtek-ambz2/arduino/src/lt_defs.h b/cores/realtek-ambz2/arduino/src/lt_defs.h index b79eb88..13296ed 100644 --- a/cores/realtek-ambz2/arduino/src/lt_defs.h +++ b/cores/realtek-ambz2/arduino/src/lt_defs.h @@ -3,5 +3,6 @@ #error "Don't include this file directly" #define LT_ARD_HAS_SERIAL 1 +#define LT_ARD_HAS_WIFI 1 #define LT_ARD_MD5_MBEDTLS 1 diff --git a/cores/realtek-ambz2/base/config/platform_opts.h b/cores/realtek-ambz2/base/config/platform_opts.h new file mode 100644 index 0000000..95f84c4 --- /dev/null +++ b/cores/realtek-ambz2/base/config/platform_opts.h @@ -0,0 +1,9 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-05-25. */ + +#pragma once + +#include_next "platform_opts.h" + +// this needs example_wlan_fast_connect.c +#undef CONFIG_EXAMPLE_WLAN_FAST_CONNECT +#undef CONFIG_FAST_DHCP From 4532c888733fd2deca9dd816436d0d79e5c05f84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 27 May 2023 16:03:46 +0200 Subject: [PATCH 15/31] [core] Add lt_set_debug_mode() function, update core types --- cores/beken-72xx/base/lt_api.c | 2 +- cores/common/base/api/lt_device.h | 7 +++++ cores/common/base/lt_api.c | 6 +++- cores/common/base/lt_types.h | 6 ++++ cores/realtek-ambz/base/lt_api.c | 46 ++++++++++++------------------- cores/realtek-ambz2/base/lt_api.c | 28 ++++++++++++++++--- 6 files changed, 61 insertions(+), 34 deletions(-) diff --git a/cores/beken-72xx/base/lt_api.c b/cores/beken-72xx/base/lt_api.c index 04c0416..46e6c11 100644 --- a/cores/beken-72xx/base/lt_api.c +++ b/cores/beken-72xx/base/lt_api.c @@ -30,7 +30,7 @@ lt_cpu_model_t lt_cpu_get_model() { } const char *lt_cpu_get_core_type() { - return "ARM968E-S"; + return "ARM968E-S (ARMv5TE)"; } /*_____ _ diff --git a/cores/common/base/api/lt_device.h b/cores/common/base/api/lt_device.h index 43d8477..ae4d626 100644 --- a/cores/common/base/api/lt_device.h +++ b/cores/common/base/api/lt_device.h @@ -58,6 +58,13 @@ lt_reboot_reason_t lt_get_reboot_reason(); */ const char *lt_get_reboot_reason_name(lt_reboot_reason_t reason); +/** + * @brief Set debugger mode (JTAG, SWD or OFF). + * + * @return whether the mode is supported, and setting it was successful + */ +bool lt_set_debug_mode(lt_debug_mode_t mode); + /** * @brief Reconfigure GPIO pins used for debugging * (SWD/JTAG), so that they can be used as normal I/O. diff --git a/cores/common/base/lt_api.c b/cores/common/base/lt_api.c index b65a7ad..09f1bdd 100644 --- a/cores/common/base/lt_api.c +++ b/cores/common/base/lt_api.c @@ -140,8 +140,12 @@ const char *lt_get_reboot_reason_name(lt_reboot_reason_t reason) { } } +__attribute__((weak)) bool lt_set_debug_mode(lt_debug_mode_t mode) { + return false; +} + __attribute__((weak)) void lt_gpio_recover() { - // nop by default + lt_set_debug_mode(DEBUG_MODE_OFF); } /*______ _ _ diff --git a/cores/common/base/lt_types.h b/cores/common/base/lt_types.h index 8d65618..c7aae14 100644 --- a/cores/common/base/lt_types.h +++ b/cores/common/base/lt_types.h @@ -86,3 +86,9 @@ typedef enum { OTA_TYPE_DUAL = 1, OTA_TYPE_FILE = 2, } lt_ota_type_t; + +typedef enum { + DEBUG_MODE_OFF = 0, + DEBUG_MODE_JTAG = 1, + DEBUG_MODE_SWD = 2, +} lt_debug_mode_t; diff --git a/cores/realtek-ambz/base/lt_api.c b/cores/realtek-ambz/base/lt_api.c index 2d7181a..72131a5 100644 --- a/cores/realtek-ambz/base/lt_api.c +++ b/cores/realtek-ambz/base/lt_api.c @@ -44,7 +44,7 @@ uint32_t lt_cpu_get_mac_id() { } const char *lt_cpu_get_core_type() { - return "ARM Cortex-M4F"; + return "ARM Cortex-M4F (ARMv7E-M)"; } uint32_t lt_cpu_get_freq() { @@ -73,11 +73,23 @@ bool lt_reboot_download_mode() { return true; } -void lt_gpio_recover() { - // PA14 and PA15 are apparently unusable with SWD enabled - sys_jtag_off(); - Pinmux_Config(PA_14, PINMUX_FUNCTION_GPIO); - Pinmux_Config(PA_15, PINMUX_FUNCTION_GPIO); +bool lt_set_debug_mode(lt_debug_mode_t mode) { + uint32_t *swd; + switch (mode) { + case DEBUG_MODE_OFF: + sys_jtag_off(); + Pinmux_Config(PA_14, PINMUX_FUNCTION_GPIO); + Pinmux_Config(PA_15, PINMUX_FUNCTION_GPIO); + return true; + case DEBUG_MODE_SWD: + Pinmux_Config(PA_14, PINMUX_FUNCTION_SWD); + Pinmux_Config(PA_15, PINMUX_FUNCTION_SWD); + uint32_t *swd = (uint32_t *)0x400000A4; + *swd |= 0x1000; + return true; + default: + return false; + } } /*______ _ _ @@ -187,25 +199,3 @@ bool lt_ota_switch(bool revert) { flash_write_word(NULL, FLASH_SYSTEM_OFFSET + 4, value); return true; } - -/*_ __ _ _ _ - \ \ / / | | | | | | - \ \ /\ / /_ _| |_ ___| |__ __| | ___ __ _ - \ \/ \/ / _` | __/ __| '_ \ / _` |/ _ \ / _` | - \ /\ / (_| | || (__| | | | (_| | (_) | (_| | - \/ \/ \__,_|\__\___|_| |_|\__,_|\___/ \__, | - __/ | - |___*/ -bool lt_wdt_enable(uint32_t timeout) { - watchdog_init(timeout); - watchdog_start(); - return true; -} - -void lt_wdt_disable() { - watchdog_stop(); -} - -void lt_wdt_feed() { - watchdog_refresh(); -} diff --git a/cores/realtek-ambz2/base/lt_api.c b/cores/realtek-ambz2/base/lt_api.c index ae1df72..aec6832 100644 --- a/cores/realtek-ambz2/base/lt_api.c +++ b/cores/realtek-ambz2/base/lt_api.c @@ -29,7 +29,7 @@ lt_cpu_model_t lt_cpu_get_model() { } const char *lt_cpu_get_core_type() { - return "ARM Cortex-M4"; + return "ARM Cortex-M33 (ARMv8-M)"; } uint32_t lt_cpu_get_freq() { @@ -74,9 +74,29 @@ lt_reboot_reason_t lt_get_reboot_reason() { } } -void lt_gpio_recover() { - sys_jtag_off(); - sys_swd_off(); +bool lt_set_debug_mode(lt_debug_mode_t mode) { + switch (mode) { + case DEBUG_MODE_OFF: + if (hal_misc_jtag_pin_ctrl(0) != HAL_OK) + return false; + if (hal_misc_swd_pin_ctrl(0) != HAL_OK) + return false; + return true; + case DEBUG_MODE_JTAG: + if (hal_misc_swd_pin_ctrl(0) != HAL_OK) + return false; + if (hal_misc_jtag_pin_ctrl(1) != HAL_OK) + return false; + return true; + case DEBUG_MODE_SWD: + if (hal_misc_jtag_pin_ctrl(0) != HAL_OK) + return false; + if (hal_misc_swd_pin_ctrl(1) != HAL_OK) + return false; + return true; + default: + return false; + } } /*__ __ From babdb1287fab5949c12fb6334762fdf22ca25c7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 27 May 2023 20:54:40 +0200 Subject: [PATCH 16/31] [realtek-ambz2] Replace lwIP with external port --- builder/family/realtek-ambz2.py | 32 ++-------------------- cores/realtek-amb/base/config/lwipopts.h | 10 +++++-- cores/realtek-ambz2/base/config/lwipopts.h | 10 +++++++ cores/realtek-ambz2/base/fixups/wireless.h | 5 ++++ external-libs.json | 20 ++++++++++++++ platform.json | 7 ++++- 6 files changed, 52 insertions(+), 32 deletions(-) create mode 100644 cores/realtek-ambz2/base/config/lwipopts.h create mode 100644 cores/realtek-ambz2/base/fixups/wireless.h diff --git a/builder/family/realtek-ambz2.py b/builder/family/realtek-ambz2.py index 1fa5026..b3e2fd4 100644 --- a/builder/family/realtek-ambz2.py +++ b/builder/family/realtek-ambz2.py @@ -189,6 +189,9 @@ env.Replace(FREERTOS_PORT=env["FAMILY_NAME"], FREERTOS_PORT_DEFINE="REALTEK_AMBZ queue.AddExternalLibrary("freertos") queue.AddExternalLibrary("freertos-port") +# Sources - lwIP +queue.AddExternalLibrary("lwip", port="ambz2") + # Sources - network utilities queue.AddLibrary( name="ambz2_net", @@ -216,7 +219,6 @@ queue.AddLibrary( "+", # network "+", - "+", # network - websocket "+", # network - mdns @@ -301,34 +303,6 @@ queue.AddLibrary( ), ) - -# Sources - lwIP 2.0.2 -queue.AddLibrary( - name="ambz2_lwip", - base_dir=join(COMPONENT_DIR, "common", "network", "lwip", "lwip_v2.0.2"), - srcs=[ - "+", - "+", - "+", - "+", - "+", - "+", - "+", - "+", - ], - includes=[ - "+", - "+", - "+", - "+", - ], - options=dict( - CFLAGS=[ - "-Wno-implicit-function-declaration", - ], - ), -) - # Sources - mbedTLS queue.AddLibrary( name="ambz2_mbedtls", diff --git a/cores/realtek-amb/base/config/lwipopts.h b/cores/realtek-amb/base/config/lwipopts.h index 326f60d..fae78d4 100644 --- a/cores/realtek-amb/base/config/lwipopts.h +++ b/cores/realtek-amb/base/config/lwipopts.h @@ -4,8 +4,14 @@ #include_next "lwipopts.h" -#define ip_addr ip4_addr // LwIP 2.0.x compatibility -#define ip_addr_t ip4_addr_t // LwIP 2.0.x compatibility +#if (!defined(LWIP_IPV4) || LWIP_IPV4) && !LWIP_IPV6 +#define ip_addr ip4_addr // LwIP 2.0.x compatibility +#define ip_addr_t ip4_addr_t // LwIP 2.0.x compatibility +#endif +#if !LWIP_IPV4 && LWIP_IPV6 +#define ip_addr ip6_addr // LwIP 2.0.x compatibility +#define ip_addr_t ip6_addr_t // LwIP 2.0.x compatibility +#endif #define in_addr_t u32_t #define IN_ADDR_T_DEFINED 1 diff --git a/cores/realtek-ambz2/base/config/lwipopts.h b/cores/realtek-ambz2/base/config/lwipopts.h new file mode 100644 index 0000000..642ba35 --- /dev/null +++ b/cores/realtek-ambz2/base/config/lwipopts.h @@ -0,0 +1,10 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-05-27. */ + +#pragma once + +// lwipopts.h defines `unsigned int sys_now()`, while lwip/sys.h defines `u32_t sys_now()` +// since u32_t is unsigned long, these are incompatible +#define sys_now sys_now_dummy +#include_next "lwipopts.h" +#undef sys_now +extern unsigned long sys_now(void); diff --git a/cores/realtek-ambz2/base/fixups/wireless.h b/cores/realtek-ambz2/base/fixups/wireless.h new file mode 100644 index 0000000..c991585 --- /dev/null +++ b/cores/realtek-ambz2/base/fixups/wireless.h @@ -0,0 +1,5 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-05-27. */ + +#undef IFNAMSIZ + +#include_next "wireless.h" diff --git a/external-libs.json b/external-libs.json index 4cb871b..9b3ff07 100644 --- a/external-libs.json +++ b/external-libs.json @@ -121,5 +121,25 @@ "+", "+" ] + }, + "lwip-ambz2": { + "package": "library-lwip", + "sources": [ + "+", + "+", + "+", + "+", + "+", + "+", + "+", + "+", + "+" + ], + "includes": [ + "+", + "+", + "+", + "+" + ] } } diff --git a/platform.json b/platform.json index dad8560..eeea980 100644 --- a/platform.json +++ b/platform.json @@ -45,7 +45,12 @@ "any": "gccarmnoneeabi@~1.100301.0" }, "libraries": { - "freertos": "10.0.1" + "freertos": "10.0.1", + "lwip": { + "2.0.3": "2.0.3-ambz2", + "2.1.3": "2.1.3-ambz2", + "default": "2.1.3-ambz2" + } } }, "framework-beken-bdk": { From af8c7417b39e6d2e9502b9ed199d4a3f75b41884 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sun, 28 May 2023 19:18:54 +0200 Subject: [PATCH 17/31] [realtek-ambz2] Keep LOG UART enabled, wipe OTA2 in UF2 --- builder/family/realtek-ambz2.py | 8 ++++++++ .../arduino/libraries/api/Serial/Serial.h | 18 ++++++++++++------ .../arduino/libraries/Serial/Serial.cpp | 4 ---- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/builder/family/realtek-ambz2.py b/builder/family/realtek-ambz2.py index b3e2fd4..512f981 100644 --- a/builder/family/realtek-ambz2.py +++ b/builder/family/realtek-ambz2.py @@ -404,6 +404,12 @@ bootloader_dst = env.subst("${BUILD_DIR}/bootloader.axf") if not isfile(bootloader_dst): copyfile(bootloader_src, bootloader_dst) +# OTA2 clearing - 4096 bytes of 0xFF +image_ota_clear = env.subst("${BUILD_DIR}/raw_ota_clear.bin") +if not isfile(image_ota_clear): + with open(image_ota_clear, "wb") as f: + f.write(b"\xFF" * 4096) + # Build all libraries queue.BuildLibraries() @@ -416,5 +422,7 @@ env.Replace( UF2OTA=[ # same OTA images for flasher and device f"{image_firmware_is},{image_firmware_is}=device:ota1,ota2;flasher:ota1,ota2", + # clearing headers of the "other" OTA image (hence the indexes are swapped) + f"{image_ota_clear},{image_ota_clear}=device:ota2,ota1;flasher:ota2,ota1", ], ) diff --git a/cores/common/arduino/libraries/api/Serial/Serial.h b/cores/common/arduino/libraries/api/Serial/Serial.h index da3bf02..232c48c 100644 --- a/cores/common/arduino/libraries/api/Serial/Serial.h +++ b/cores/common/arduino/libraries/api/Serial/Serial.h @@ -8,24 +8,30 @@ using namespace arduino; +#if HAS_SERIAL0 #ifndef PIN_SERIAL0_RX #define PIN_SERIAL0_RX PIN_INVALID #endif -#ifndef PIN_SERIAL1_RX -#define PIN_SERIAL1_RX PIN_INVALID -#endif -#ifndef PIN_SERIAL2_RX -#define PIN_SERIAL2_RX PIN_INVALID -#endif #ifndef PIN_SERIAL0_TX #define PIN_SERIAL0_TX PIN_INVALID #endif +#endif +#if HAS_SERIAL1 +#ifndef PIN_SERIAL1_RX +#define PIN_SERIAL1_RX PIN_INVALID +#endif #ifndef PIN_SERIAL1_TX #define PIN_SERIAL1_TX PIN_INVALID #endif +#endif +#if HAS_SERIAL2 +#ifndef PIN_SERIAL2_RX +#define PIN_SERIAL2_RX PIN_INVALID +#endif #ifndef PIN_SERIAL2_TX #define PIN_SERIAL2_TX PIN_INVALID #endif +#endif class SerialClass : public HardwareSerial { private: diff --git a/cores/realtek-ambz2/arduino/libraries/Serial/Serial.cpp b/cores/realtek-ambz2/arduino/libraries/Serial/Serial.cpp index eb1e462..3b69859 100644 --- a/cores/realtek-ambz2/arduino/libraries/Serial/Serial.cpp +++ b/cores/realtek-ambz2/arduino/libraries/Serial/Serial.cpp @@ -33,10 +33,6 @@ void SerialClass::begin(unsigned long baudrate, uint16_t config) { this->data = new SerialData(); this->buf = &BUF; - if (this->port == 2) { - hal_uart_deinit(&log_uart); - } - // TODO handle PIN_INVALID hal_uart_init(&UART, this->tx, this->rx, NULL); From 6135e4f7b0be992947166719d3011a560231ba22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Mon, 29 May 2023 16:16:58 +0200 Subject: [PATCH 18/31] [boards] Update flash layouts, add W302 chip --- boards/_base/beken-7231n-tuya.json | 3 +++ boards/_base/beken-7231n.json | 1 - boards/_base/beken-7231t-tuya.json | 3 +++ boards/_base/beken-7231u.json | 1 - boards/_base/realtek-ambz-2mb-468k.json | 5 ++-- boards/_base/realtek-ambz-2mb-788k.json | 5 ++-- boards/_base/realtek-ambz-4mb-980k.json | 3 +-- boards/_base/realtek-ambz-tuya.json | 5 ++++ boards/_base/realtek-ambz.json | 9 +++---- boards/_base/realtek-ambz2-2mb-992k.json | 3 +-- boards/_base/realtek-ambz2-tuya.json | 5 ++++ boards/wr2.json | 1 + boards/wr2e.json | 1 + boards/wr2l.json | 1 + boards/wr2le.json | 1 + boards/wr3.json | 1 + boards/wr3e.json | 1 + boards/wr3l.json | 1 + boards/wr3le.json | 1 + boards/wr3n.json | 1 + cores/common/base/lt_types.h | 1 + docs/boards_tuya_all.json | 30 +++++++++++++++++++++++- 22 files changed, 64 insertions(+), 19 deletions(-) create mode 100644 boards/_base/realtek-ambz-tuya.json create mode 100644 boards/_base/realtek-ambz2-tuya.json diff --git a/boards/_base/beken-7231n-tuya.json b/boards/_base/beken-7231n-tuya.json index 733fe04..3c6e620 100644 --- a/boards/_base/beken-7231n-tuya.json +++ b/boards/_base/beken-7231n-tuya.json @@ -2,5 +2,8 @@ "build": { "bkcrypt_coeffs": "510fb093a3cbeadc5993a17ec7adeb03", "bkboot_version": "1.0.1-bk7231n" + }, + "flash": { + "tuya": "0x1ED000+0x13000" } } diff --git a/boards/_base/beken-7231n.json b/boards/_base/beken-7231n.json index 308a3ba..3946756 100644 --- a/boards/_base/beken-7231n.json +++ b/boards/_base/beken-7231n.json @@ -12,7 +12,6 @@ "download": "0x12A000+0xA6000", "calibration": "0x1D0000+0x1000", "net": "0x1D1000+0x1000", - "tlv": "0x1D2000+0x1000", "kvs": "0x1D3000+0x8000", "userdata": "0x1DB000+0x25000" }, diff --git a/boards/_base/beken-7231t-tuya.json b/boards/_base/beken-7231t-tuya.json index 5a36572..5049f2f 100644 --- a/boards/_base/beken-7231t-tuya.json +++ b/boards/_base/beken-7231t-tuya.json @@ -2,5 +2,8 @@ "build": { "bkcrypt_coeffs": "510fb093a3cbeadc5993a17ec7adeb03", "bkboot_version": "1.0.5-bk7231s" + }, + "flash": { + "tuya": "0x1ED000+0x13000" } } diff --git a/boards/_base/beken-7231u.json b/boards/_base/beken-7231u.json index 7516035..219111b 100644 --- a/boards/_base/beken-7231u.json +++ b/boards/_base/beken-7231u.json @@ -12,7 +12,6 @@ "download": "0x132000+0xA6000", "kvs": "0x1D8000+0x8000", "calibration": "0x1E0000+0x1000", - "tlv": "0x1E1000+0x1000", "net": "0x1E2000+0x1000", "userdata": "0x1E3000+0x1D000" }, diff --git a/boards/_base/realtek-ambz-2mb-468k.json b/boards/_base/realtek-ambz-2mb-468k.json index 6b8346c..2e016b2 100644 --- a/boards/_base/realtek-ambz-2mb-468k.json +++ b/boards/_base/realtek-ambz-2mb-468k.json @@ -5,9 +5,8 @@ "flash": { "ota1": "0x00B000+0x75000", "ota2": "0x080000+0x75000", - "kvs": "0xF5000+0x6000", - "userdata": "0xFB000+0x104000", - "rdp": "0x1FF000+0x1000" + "kvs": "0x0F5000+0x8000", + "userdata": "0x0FD000+0x102000" }, "upload": { "flash_size": 2097152, diff --git a/boards/_base/realtek-ambz-2mb-788k.json b/boards/_base/realtek-ambz-2mb-788k.json index 7df3e6e..9cf5546 100644 --- a/boards/_base/realtek-ambz-2mb-788k.json +++ b/boards/_base/realtek-ambz-2mb-788k.json @@ -5,9 +5,8 @@ "flash": { "ota1": "0x00B000+0xC5000", "ota2": "0x0D0000+0xC5000", - "kvs": "0x195000+0x6000", - "userdata": "0x19B000+0x64000", - "rdp": "0x1FF000+0x1000" + "kvs": "0x195000+0x8000", + "userdata": "0x19D000+0x62000" }, "upload": { "flash_size": 2097152, diff --git a/boards/_base/realtek-ambz-4mb-980k.json b/boards/_base/realtek-ambz-4mb-980k.json index 5f5fd0e..e90cf7f 100644 --- a/boards/_base/realtek-ambz-4mb-980k.json +++ b/boards/_base/realtek-ambz-4mb-980k.json @@ -6,8 +6,7 @@ "ota1": "0x00B000+0xF5000", "ota2": "0x100000+0xF5000", "kvs": "0x1F5000+0x8000", - "userdata": "0x1FD000+0x202000", - "rdp": "0x3FF000+0x1000" + "userdata": "0x1FD000+0x202000" }, "upload": { "flash_size": 4194304, diff --git a/boards/_base/realtek-ambz-tuya.json b/boards/_base/realtek-ambz-tuya.json new file mode 100644 index 0000000..629b69c --- /dev/null +++ b/boards/_base/realtek-ambz-tuya.json @@ -0,0 +1,5 @@ +{ + "flash": { + "tuya": "0x1EB000+0x15000" + } +} diff --git a/boards/_base/realtek-ambz.json b/boards/_base/realtek-ambz.json index 8fbbdae..21dc7f6 100644 --- a/boards/_base/realtek-ambz.json +++ b/boards/_base/realtek-ambz.json @@ -10,7 +10,8 @@ "boot_xip": "0x000000+0x4000", "boot_ram": "0x004000+0x4000", "system": "0x009000+0x1000", - "calibration": "0x00A000+0x1000" + "calibration": "0x00A000+0x1000", + "rdp": "0x1FF000+0x1000" }, "connectivity": [ "wifi" @@ -47,10 +48,6 @@ "General info": "../../docs/platform/realtek-amb/README.md", "Flashing guide": "../../docs/platform/realtek-ambz/flashing.md", "Debugging": "../../docs/platform/realtek-ambz/debugging.md" - }, - "extra": [ - "RDP is most likely not used in Tuya firmwares, as the System Data partition contains an incorrect offset 0xFF000 for RDP, which is in the middle of OTA2 image.", - "Additionally, Tuya firmware uses an encrypted KV or file storage, which resides at the end of flash memory. This seems to overlap system RDP area." - ] + } } } diff --git a/boards/_base/realtek-ambz2-2mb-992k.json b/boards/_base/realtek-ambz2-2mb-992k.json index ce06c54..58fb342 100644 --- a/boards/_base/realtek-ambz2-2mb-992k.json +++ b/boards/_base/realtek-ambz2-2mb-992k.json @@ -2,8 +2,7 @@ "flash": { "ota1": "0x00C000+0xF8000", "ota2": "0x104000+0xF8000", - "kvs": "0x1FC000+0x2000", - "userdata": "0x1FE000+0x2000" + "kvs": "0x1FC000+0x4000" }, "upload": { "flash_size": 2097152, diff --git a/boards/_base/realtek-ambz2-tuya.json b/boards/_base/realtek-ambz2-tuya.json new file mode 100644 index 0000000..1ad51a5 --- /dev/null +++ b/boards/_base/realtek-ambz2-tuya.json @@ -0,0 +1,5 @@ +{ + "flash": { + "tuya": "0x1D5000+0x10000" + } +} diff --git a/boards/wr2.json b/boards/wr2.json index c6619ae..4a1e7e4 100644 --- a/boards/wr2.json +++ b/boards/wr2.json @@ -1,6 +1,7 @@ { "_base": [ "realtek-ambz", + "realtek-ambz-tuya", "realtek-ambz-2mb-788k", "ic/rtl8710bn", "pcb/wr2-base", diff --git a/boards/wr2e.json b/boards/wr2e.json index 87bbe47..d53af88 100644 --- a/boards/wr2e.json +++ b/boards/wr2e.json @@ -1,6 +1,7 @@ { "_base": [ "realtek-ambz", + "realtek-ambz-tuya", "realtek-ambz-2mb-788k", "ic/rtl8710bn", "pcb/wr2-base", diff --git a/boards/wr2l.json b/boards/wr2l.json index 83343d3..4225f7b 100644 --- a/boards/wr2l.json +++ b/boards/wr2l.json @@ -1,6 +1,7 @@ { "_base": [ "realtek-ambz", + "realtek-ambz-tuya", "realtek-ambz-2mb-788k", "realtek-ambz-bx", "ic/rtl8710bn", diff --git a/boards/wr2le.json b/boards/wr2le.json index d620d69..c60d6eb 100644 --- a/boards/wr2le.json +++ b/boards/wr2le.json @@ -1,6 +1,7 @@ { "_base": [ "realtek-ambz", + "realtek-ambz-tuya", "realtek-ambz-2mb-788k", "realtek-ambz-bx", "ic/rtl8710bn", diff --git a/boards/wr3.json b/boards/wr3.json index 4f68710..b364406 100644 --- a/boards/wr3.json +++ b/boards/wr3.json @@ -1,6 +1,7 @@ { "_base": [ "realtek-ambz", + "realtek-ambz-tuya", "realtek-ambz-2mb-788k", "ic/rtl8710bn", "pcb/wr3-base", diff --git a/boards/wr3e.json b/boards/wr3e.json index 84a0417..8533468 100644 --- a/boards/wr3e.json +++ b/boards/wr3e.json @@ -1,6 +1,7 @@ { "_base": [ "realtek-ambz", + "realtek-ambz-tuya", "realtek-ambz-2mb-788k", "ic/rtl8710bn", "pcb/wr3-base", diff --git a/boards/wr3l.json b/boards/wr3l.json index fb815f5..0bda55d 100644 --- a/boards/wr3l.json +++ b/boards/wr3l.json @@ -1,6 +1,7 @@ { "_base": [ "realtek-ambz", + "realtek-ambz-tuya", "realtek-ambz-2mb-788k", "realtek-ambz-bx", "ic/rtl8710bn", diff --git a/boards/wr3le.json b/boards/wr3le.json index 44cff15..a06a6ed 100644 --- a/boards/wr3le.json +++ b/boards/wr3le.json @@ -1,6 +1,7 @@ { "_base": [ "realtek-ambz", + "realtek-ambz-tuya", "realtek-ambz-2mb-788k", "realtek-ambz-bx", "ic/rtl8710bn", diff --git a/boards/wr3n.json b/boards/wr3n.json index ae35e26..0a5c404 100644 --- a/boards/wr3n.json +++ b/boards/wr3n.json @@ -1,6 +1,7 @@ { "_base": [ "realtek-ambz", + "realtek-ambz-tuya", "realtek-ambz-2mb-788k", "ic/rtl8710bn", "pcb/wr3-base", diff --git a/cores/common/base/lt_types.h b/cores/common/base/lt_types.h index c7aae14..ef27c29 100644 --- a/cores/common/base/lt_types.h +++ b/cores/common/base/lt_types.h @@ -40,6 +40,7 @@ typedef enum { RTL8711BU = CPU_MODEL(F_RTL8710B, 0xFC), // CHIPID_8711BG / QFN68 MX1290 = RTL8710BN, MX1290V2 = RTL8710BX, + W302 = RTL8710BN, // Realtek AmebaZ2 (chip_id << 2 | flash_mode) RTL8720CM = CPU_MODEL(F_RTL8720C, 0xEC), // 0xFB << 2 | 0 RTL8720CF = CPU_MODEL(F_RTL8720C, 0xED), // 0xFB << 2 | 1 diff --git a/docs/boards_tuya_all.json b/docs/boards_tuya_all.json index 2832f16..290f6d0 100644 --- a/docs/boards_tuya_all.json +++ b/docs/boards_tuya_all.json @@ -441,6 +441,34 @@ "datasheet_id": "Kc5x1p35fs5zf" } }, + "t2": { + "t2-u": { + "mcu": "bk7231n", + "flash": 2097152, + "ram": 262144, + "pins_total": 21, + "connectivity": [ + "wifi", + "ble" + ], + "datasheet_name": "T2-U-module-datasheet", + "datasheet_id": "Kce1tncb80ldq" + } + }, + "t1": { + "t1-2s": { + "mcu": "t1a", + "flash": 1048576, + "ram": 294912, + "pins_total": 11, + "connectivity": [ + "wifi", + "ble" + ], + "datasheet_name": "T1-2S-module-datasheet", + "datasheet_id": "Kcl2d5xjy1rly" + } + }, "axy": { "axy2s": { "mcu": "ecr6600", @@ -493,7 +521,7 @@ }, "wt": { "wt3": { - "mcu": "t2", + "mcu": "bk7231n", "flash": 2097152, "ram": 262144, "pins_total": 16, From f1e41f7cc15c52d189e82e362c3b388bf2db9c31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Mon, 29 May 2023 22:25:23 +0200 Subject: [PATCH 19/31] [realtek-ambz2] Add GDB init command --- boards/_base/realtek-ambz2.json | 8 +++++++- cores/realtek-ambz2/base/lt_api.c | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/boards/_base/realtek-ambz2.json b/boards/_base/realtek-ambz2.json index 0bdd708..05d4ffd 100644 --- a/boards/_base/realtek-ambz2.json +++ b/boards/_base/realtek-ambz2.json @@ -13,7 +13,13 @@ }, "debug": { "protocol": "openocd", - "protocols": [] + "protocols": [ + "openocd" + ], + "openocd_config": "amebaz2.cfg", + "gdb_init": [ + "mem 0x9b000000 0x9c000000 ro" + ] }, "upload": { "maximum_ram_size": 262144, diff --git a/cores/realtek-ambz2/base/lt_api.c b/cores/realtek-ambz2/base/lt_api.c index aec6832..83c5f2d 100644 --- a/cores/realtek-ambz2/base/lt_api.c +++ b/cores/realtek-ambz2/base/lt_api.c @@ -7,7 +7,7 @@ extern uint8_t lt_uart_port; void lt_init_family() { // make the SDK less verbose by default - ConfigDebugErr = 0; + ConfigDebugErr = _DBG_MISC_ | _DBG_FAULT_ | _DBG_BOOT_; ConfigDebugWarn = 0; ConfigDebugInfo = 0; lt_uart_port = LT_UART_DEFAULT_PORT; From 41985e5743412ec996bb5468ab38ad969545ab4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Mon, 29 May 2023 22:26:12 +0200 Subject: [PATCH 20/31] [core] Move common flags to base.py --- builder/family/realtek-ambz2.py | 1 + builder/frameworks/arduino.py | 6 ------ builder/frameworks/base.py | 3 +++ 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/builder/family/realtek-ambz2.py b/builder/family/realtek-ambz2.py index 512f981..28e3320 100644 --- a/builder/family/realtek-ambz2.py +++ b/builder/family/realtek-ambz2.py @@ -56,6 +56,7 @@ queue.AppendPublic( "--specs=nano.specs", "-Wl,--use-blx", "-Wl,--undefined=gRamStartFun", + "-Wl,--warn-section-align", "-Wl,-wrap,aesccmp_construct_mic_iv", "-Wl,-wrap,aesccmp_construct_mic_header1", "-Wl,-wrap,aesccmp_construct_ctr_preload", diff --git a/builder/frameworks/arduino.py b/builder/frameworks/arduino.py index 1281079..5dbe110 100644 --- a/builder/frameworks/arduino.py +++ b/builder/frameworks/arduino.py @@ -73,12 +73,6 @@ queue.AppendPublic( ("ARDUINO_SDK", 1), ], LINKFLAGS=[ - "-Wl,--as-needed", - "-Wl,--build-id=none", - "-Wl,--cref", - "-Wl,--no-enum-size-warning", - "-Wl,--no-undefined", - "-Wl,--warn-common", # wrappers from posix/time.c "-Wl,-wrap,gettimeofday", "-Wl,-wrap,settimeofday", diff --git a/builder/frameworks/base.py b/builder/frameworks/base.py index bf1eaa6..fd8a886 100644 --- a/builder/frameworks/base.py +++ b/builder/frameworks/base.py @@ -138,11 +138,14 @@ queue.AppendPublic( LINKFLAGS=[ "-g2", "-Os", + "-Wl,--as-needed", "-Wl,--build-id=none", "-Wl,--cref", "-Wl,--gc-sections", "-Wl,--no-enum-size-warning", "-Wl,--no-wchar-size-warning", + "-Wl,--no-undefined", + "-Wl,--warn-common", # malloc.c wrappers "-Wl,-wrap,malloc", "-Wl,-wrap,calloc", From 9c6e9d152523d3f8d943a1b342117c5f5620471e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Tue, 30 May 2023 18:15:44 +0200 Subject: [PATCH 21/31] [realtek-ambz2] Disable SoftwareSerial and Wire --- .../arduino/libraries/SoftwareSerial/SoftwareSerial.cpp | 4 ++++ cores/realtek-amb/arduino/libraries/Wire/Wire.cpp | 4 ++++ cores/realtek-ambz2/arduino/src/lt_defs.h | 6 ++++-- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/cores/realtek-amb/arduino/libraries/SoftwareSerial/SoftwareSerial.cpp b/cores/realtek-amb/arduino/libraries/SoftwareSerial/SoftwareSerial.cpp index ebd7f0f..1176126 100644 --- a/cores/realtek-amb/arduino/libraries/SoftwareSerial/SoftwareSerial.cpp +++ b/cores/realtek-amb/arduino/libraries/SoftwareSerial/SoftwareSerial.cpp @@ -1,5 +1,7 @@ /* Copyright (c) Kuba Szczodrzyński 2022-07-03. */ +#if LT_RTL8710B + #include #include @@ -94,3 +96,5 @@ void SoftwareSerial::startTx() { void SoftwareSerial::endTx() { gtimer_stop(OBJ); } + +#endif diff --git a/cores/realtek-amb/arduino/libraries/Wire/Wire.cpp b/cores/realtek-amb/arduino/libraries/Wire/Wire.cpp index aa93e65..09c7f25 100644 --- a/cores/realtek-amb/arduino/libraries/Wire/Wire.cpp +++ b/cores/realtek-amb/arduino/libraries/Wire/Wire.cpp @@ -1,5 +1,7 @@ /* Copyright (c) Kuba Szczodrzyński 2022-05-08. */ +#if LT_RTL8710B + #include "Wire.h" #include @@ -191,3 +193,5 @@ int TwoWire::peek() { } void TwoWire::flush() {} + +#endif diff --git a/cores/realtek-ambz2/arduino/src/lt_defs.h b/cores/realtek-ambz2/arduino/src/lt_defs.h index 13296ed..72fc05a 100644 --- a/cores/realtek-ambz2/arduino/src/lt_defs.h +++ b/cores/realtek-ambz2/arduino/src/lt_defs.h @@ -2,7 +2,9 @@ #error "Don't include this file directly" -#define LT_ARD_HAS_SERIAL 1 -#define LT_ARD_HAS_WIFI 1 +#define LT_ARD_HAS_SERIAL 1 +#define LT_ARD_HAS_WIFI 1 +#define LT_ARD_HAS_SOFTSERIAL 0 +#define LT_ARD_HAS_WIRE 0 #define LT_ARD_MD5_MBEDTLS 1 From e256ac8e4618c950c93654ec5834e048b2116d1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Tue, 30 May 2023 18:49:58 +0200 Subject: [PATCH 22/31] [builder] Fix ltchiptool empty quotes on Windows --- builder/family/beken-72xx.py | 2 +- builder/family/realtek-ambz2.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/builder/family/beken-72xx.py b/builder/family/beken-72xx.py index 12cef25..dc1038f 100644 --- a/builder/family/beken-72xx.py +++ b/builder/family/beken-72xx.py @@ -538,7 +538,7 @@ image_app_rblh = "${BUILD_DIR}/image_${MCULC}_app.${FLASH_RBL_OFFSET}.rblh" image_ota_rbl = "${BUILD_DIR}/image_${MCULC}_app.ota.rbl" env.Replace( # linker command (encryption + packaging) - LINK="${LTCHIPTOOL} link2bin ${BOARD_JSON} '' ''", + LINK='${LTCHIPTOOL} link2bin ${BOARD_JSON} "" ""', # UF2OTA input list UF2OTA=[ # app binary image (enc+crc) for flasher diff --git a/builder/family/realtek-ambz2.py b/builder/family/realtek-ambz2.py index 28e3320..14aff21 100644 --- a/builder/family/realtek-ambz2.py +++ b/builder/family/realtek-ambz2.py @@ -418,7 +418,7 @@ queue.BuildLibraries() image_firmware_is = "${BUILD_DIR}/image_firmware_is.${FLASH_OTA1_OFFSET}.bin" env.Replace( # linker command (dual .bin outputs) - LINK="${LTCHIPTOOL} link2bin ${BOARD_JSON} '' ''", + LINK='${LTCHIPTOOL} link2bin ${BOARD_JSON} "" ""', # UF2OTA input list UF2OTA=[ # same OTA images for flasher and device From 1e49c3ff6f2398387c42b20b071062a1f8cc96da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Wed, 31 May 2023 12:36:46 +0200 Subject: [PATCH 23/31] [realtek-ambz2] Fix missing flash API resource lock unit --- builder/family/realtek-ambz2.py | 1 + cores/realtek-ambz2/base/fixups/hal_flash.h | 13 +++++++++++++ cores/realtek-ambz2/misc/rtl8710c_ram.ld | 8 +++++++- 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 cores/realtek-ambz2/base/fixups/hal_flash.h diff --git a/builder/family/realtek-ambz2.py b/builder/family/realtek-ambz2.py index 14aff21..a6786e0 100644 --- a/builder/family/realtek-ambz2.py +++ b/builder/family/realtek-ambz2.py @@ -106,6 +106,7 @@ queue.AddLibrary( # cmsis "+", "+", + "+", # utilities "+", "+", diff --git a/cores/realtek-ambz2/base/fixups/hal_flash.h b/cores/realtek-ambz2/base/fixups/hal_flash.h new file mode 100644 index 0000000..ebbf1f7 --- /dev/null +++ b/cores/realtek-ambz2/base/fixups/hal_flash.h @@ -0,0 +1,13 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-05-31. */ + +// - flash_api.c and flash_api_ext.c are both compiled in libambz2_sdk.a +// - the former declares weak functions 'flash_resource_lock' and 'flash_resource_unlock', +// while the latter actually implements them +// - for some reason, the linker resolves the weak functions only, +// and doesn't include them in the final binary + +#include_next "hal_flash.h" + +// try to remove the weak attribute +#undef __weak +#define __weak diff --git a/cores/realtek-ambz2/misc/rtl8710c_ram.ld b/cores/realtek-ambz2/misc/rtl8710c_ram.ld index 221819e..7dbe133 100644 --- a/cores/realtek-ambz2/misc/rtl8710c_ram.ld +++ b/cores/realtek-ambz2/misc/rtl8710c_ram.ld @@ -385,5 +385,11 @@ SECTIONS PROVIDE(__sram_end__ = __StackLimit); /* Check if data + heap + stack exceeds RAM limit */ - /* TODO: ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack") */ + ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack") + ASSERT(__bss_start__ >= __ram_code_text_end__, "sram heap will overwrite sram text") + ASSERT(__bss_start__ >= __ram_code_rodata_end__, "sram heap will overwrite sram rodata") + ASSERT(__bss_start__ >= __data_end__, "sram heap will overwrite sram data") + ASSERT(__psram_bss_start__ >= __psram_code_text_end__, "psram heap will overwrite psram text") + ASSERT(__psram_bss_start__ >= __psram_code_rodata_end__, "psram heap will overwrite psram rodata") + ASSERT(__psram_bss_start__ >= __psram_data_end__, "psram heap will overwrite psram data") } From e7f35c584bed7f0b78da20a943e548c20ae82554 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Wed, 31 May 2023 12:37:34 +0200 Subject: [PATCH 24/31] [realtek-ambz2] Reuse Log UART for Serial --- .../arduino/libraries/Serial/Serial.cpp | 3 +- .../arduino/libraries/Serial/Serial.cpp | 3 +- .../arduino/libraries/Serial/Serial.cpp | 38 ++++++++++++------- .../arduino/libraries/Serial/SerialPrivate.h | 2 +- 4 files changed, 30 insertions(+), 16 deletions(-) diff --git a/cores/beken-72xx/arduino/libraries/Serial/Serial.cpp b/cores/beken-72xx/arduino/libraries/Serial/Serial.cpp index 4f3403a..bde481d 100644 --- a/cores/beken-72xx/arduino/libraries/Serial/Serial.cpp +++ b/cores/beken-72xx/arduino/libraries/Serial/Serial.cpp @@ -68,9 +68,10 @@ void SerialClass::end() { break; } + delete DATA; + this->data = NULL; this->buf = NULL; this->baudrate = 0; - delete DATA; } void SerialClass::flush() { diff --git a/cores/realtek-ambz/arduino/libraries/Serial/Serial.cpp b/cores/realtek-ambz/arduino/libraries/Serial/Serial.cpp index bc08cd5..f075d19 100644 --- a/cores/realtek-ambz/arduino/libraries/Serial/Serial.cpp +++ b/cores/realtek-ambz/arduino/libraries/Serial/Serial.cpp @@ -114,9 +114,10 @@ void SerialClass::end() { DIAG_UartReInit((IRQ_FUN)UartLogIrqHandle); } + delete DATA; + this->data = NULL; this->buf = NULL; this->baudrate = 0; - delete DATA; } void SerialClass::flush() { diff --git a/cores/realtek-ambz2/arduino/libraries/Serial/Serial.cpp b/cores/realtek-ambz2/arduino/libraries/Serial/Serial.cpp index 3b69859..709425a 100644 --- a/cores/realtek-ambz2/arduino/libraries/Serial/Serial.cpp +++ b/cores/realtek-ambz2/arduino/libraries/Serial/Serial.cpp @@ -15,7 +15,7 @@ SerialClass Serial2(2, PIN_SERIAL2_RX, PIN_SERIAL2_TX); static void callback(uint32_t param, uint32_t event) { if (event != RxIrq) return; - hal_uart_adapter_t *uart = &pdUART; + hal_uart_adapter_t *uart = pdUART; uint8_t c; while (hal_uart_rgetc(uart, (char *)&c)) { @@ -33,14 +33,19 @@ void SerialClass::begin(unsigned long baudrate, uint16_t config) { this->data = new SerialData(); this->buf = &BUF; - // TODO handle PIN_INVALID - hal_uart_init(&UART, this->tx, this->rx, NULL); + if (this->port == 2) { + DATA->uart = &log_uart; + } else { + UART = new hal_uart_adapter_t(); + // TODO handle PIN_INVALID + hal_uart_init(UART, this->tx, this->rx, NULL); + } if (this->rx != PIN_INVALID) { hal_uart_enter_critical(); - hal_uart_rxind_hook(&UART, callback, (uint32_t)this->data, RxIrq); - UART.base_addr->ier_b.erbi = 1; - UART.base_addr->ier_b.etbei = 0; + hal_uart_rxind_hook(UART, callback, (uint32_t)this->data, RxIrq); + UART->base_addr->ier_b.erbi = 1; + UART->base_addr->ier_b.etbei = 0; hal_uart_exit_critical(); } } @@ -57,8 +62,8 @@ void SerialClass::configure(unsigned long baudrate, uint16_t config) { uint8_t parity = (config & SERIAL_PARITY_MASK) ^ 0b11; uint8_t stopBits = (config & SERIAL_STOP_BIT_MASK) == SERIAL_STOP_BIT_2 ? 2 : 1; - hal_uart_set_baudrate(&UART, baudrate); - hal_uart_set_format(&UART, dataWidth, parity, stopBits); + hal_uart_set_baudrate(UART, baudrate); + hal_uart_set_format(UART, dataWidth, parity, stopBits); this->baudrate = baudrate; this->config = config; @@ -68,23 +73,30 @@ void SerialClass::end() { if (!this->data) return; - hal_uart_deinit(&UART); + if (this->port == 2) { + UART->base_addr->ier_b.erbi = 0; + hal_uart_rxind_hook(UART, NULL, 0, RxIrq); + } else { + hal_uart_deinit(UART); + delete UART; + } + delete DATA; + this->data = NULL; this->buf = NULL; this->baudrate = 0; - delete DATA; } void SerialClass::flush() { if (!this->data) return; - while (UART.base_addr->tflvr_b.tx_fifo_lv != 0) {} + while (UART->base_addr->tflvr_b.tx_fifo_lv != 0) {} } size_t SerialClass::write(uint8_t c) { if (!this->data) return 0; - while (!hal_uart_writeable(&UART)) {} - hal_uart_putc(&UART, c); + while (!hal_uart_writeable(UART)) {} + hal_uart_putc(UART, c); return 1; } diff --git a/cores/realtek-ambz2/arduino/libraries/Serial/SerialPrivate.h b/cores/realtek-ambz2/arduino/libraries/Serial/SerialPrivate.h index 48c4d04..6fb1ec9 100644 --- a/cores/realtek-ambz2/arduino/libraries/Serial/SerialPrivate.h +++ b/cores/realtek-ambz2/arduino/libraries/Serial/SerialPrivate.h @@ -6,7 +6,7 @@ #include typedef struct { - hal_uart_adapter_t uart; + hal_uart_adapter_t *uart; RingBuffer buf; } SerialData; From e2794d5f8459273bd55b07442ac662df78701590 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Wed, 31 May 2023 12:38:15 +0200 Subject: [PATCH 25/31] [builder] Fix running ltchiptool with no baudrate --- builder/utils/ltchiptool.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/builder/utils/ltchiptool.py b/builder/utils/ltchiptool.py index fc1238d..4ac01c1 100644 --- a/builder/utils/ltchiptool.py +++ b/builder/utils/ltchiptool.py @@ -59,14 +59,23 @@ def env_uf2ota(env: Environment, *args, **kwargs): def env_flash_write(env: Environment): + # UPLOAD_PROTOCOL = upload_protocol or board->upload.protocol + # UPLOAD_PORT = upload_port (PIO can choose this automatically I guess) + # UPLOAD_SPEED = upload_speed or board->upload.speed (**can be empty**) protocol = env.subst("${UPLOAD_PROTOCOL}") + speed = env.subst("${UPLOAD_SPEED}") if protocol == "uart": # upload via UART + if speed: + return [ + "-d", + "${UPLOAD_PORT}", + "-b", + "${UPLOAD_SPEED}", + ] return [ "-d", "${UPLOAD_PORT}", - "-b", - "${UPLOAD_SPEED}", ] else: # can't upload via ltchiptool From 74659901c0dc7f2217cf33794a4e66e1173d0ebc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Tue, 20 Jun 2023 19:09:46 +0200 Subject: [PATCH 26/31] [boards] Fix BW15 PCB template name --- boards/_base/pcb/bw15.json | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/boards/_base/pcb/bw15.json b/boards/_base/pcb/bw15.json index 57e8fa7..217692d 100644 --- a/boards/_base/pcb/bw15.json +++ b/boards/_base/pcb/bw15.json @@ -2,14 +2,9 @@ "pcb": { "templates": [ "esp12s", - "esp12s-shield", + "pcb-black", "rf-type1" ], - "vars": { - "MASK_PRESET": "mask_black", - "TRACE_COLOR": "#FAFD9D", - "SILK_COLOR": "white" - }, "pinout_hidden": "I2S,TRIG,WAKE,CTS,RTS,SD", "pinout": { "1": { From b38a4d5d46e10f3af3cb77de4e20ddf26d77c756 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Wed, 21 Jun 2023 17:02:48 +0200 Subject: [PATCH 27/31] [core] Add hardware peripheral availability defines --- cores/beken-7231n/base/lt_defs.h | 5 ++ cores/beken-7231t/base/lt_defs.h | 5 ++ cores/beken-7251/base/lt_defs.h | 5 ++ .../arduino/libraries/Serial/Serial.cpp | 4 +- cores/beken-72xx/arduino/src/lt_defs.h | 5 +- cores/beken-72xx/base/lt_defs.h | 15 ++-- cores/beken-72xx/base/lt_family.h | 6 +- .../arduino/libraries/api/Serial/Serial.h | 25 ------- cores/common/arduino/src/Arduino.h | 6 +- .../common/arduino/src/wiring/wiring_custom.h | 1 - cores/common/base/libretiny.h | 1 + cores/common/base/lt_pins.h | 69 +++++++++++++++++++ cores/realtek-amb/arduino/src/main.cpp | 2 +- cores/realtek-amb/base/lt_defs.h | 4 +- .../arduino/libraries/Serial/Serial.cpp | 6 +- cores/realtek-ambz/arduino/src/lt_defs.h | 3 +- cores/realtek-ambz/base/lt_defs.h | 4 +- cores/realtek-ambz/base/lt_family.h | 8 +-- .../arduino/libraries/Serial/Serial.cpp | 6 +- cores/realtek-ambz2/arduino/src/lt_defs.h | 5 +- cores/realtek-ambz2/base/lt_defs.h | 4 +- cores/realtek-ambz2/base/lt_family.h | 8 +-- docs/dev/config.md | 49 +++++++++---- 23 files changed, 166 insertions(+), 80 deletions(-) create mode 100644 cores/beken-7231n/base/lt_defs.h create mode 100644 cores/beken-7231t/base/lt_defs.h create mode 100644 cores/beken-7251/base/lt_defs.h create mode 100644 cores/common/base/lt_pins.h diff --git a/cores/beken-7231n/base/lt_defs.h b/cores/beken-7231n/base/lt_defs.h new file mode 100644 index 0000000..e099505 --- /dev/null +++ b/cores/beken-7231n/base/lt_defs.h @@ -0,0 +1,5 @@ +#pragma once + +#error "Don't include this file directly" + +#define LT_HW_BLE 1 diff --git a/cores/beken-7231t/base/lt_defs.h b/cores/beken-7231t/base/lt_defs.h new file mode 100644 index 0000000..e099505 --- /dev/null +++ b/cores/beken-7231t/base/lt_defs.h @@ -0,0 +1,5 @@ +#pragma once + +#error "Don't include this file directly" + +#define LT_HW_BLE 1 diff --git a/cores/beken-7251/base/lt_defs.h b/cores/beken-7251/base/lt_defs.h new file mode 100644 index 0000000..e099505 --- /dev/null +++ b/cores/beken-7251/base/lt_defs.h @@ -0,0 +1,5 @@ +#pragma once + +#error "Don't include this file directly" + +#define LT_HW_BLE 1 diff --git a/cores/beken-72xx/arduino/libraries/Serial/Serial.cpp b/cores/beken-72xx/arduino/libraries/Serial/Serial.cpp index bde481d..c4a071d 100644 --- a/cores/beken-72xx/arduino/libraries/Serial/Serial.cpp +++ b/cores/beken-72xx/arduino/libraries/Serial/Serial.cpp @@ -2,10 +2,10 @@ #include "SerialPrivate.h" -#if HAS_SERIAL1 +#if LT_HW_UART1 SerialClass Serial1(UART1_PORT); #endif -#if HAS_SERIAL2 +#if LT_HW_UART2 SerialClass Serial2(UART2_PORT); #endif diff --git a/cores/beken-72xx/arduino/src/lt_defs.h b/cores/beken-72xx/arduino/src/lt_defs.h index 6250f1c..3acbe64 100644 --- a/cores/beken-72xx/arduino/src/lt_defs.h +++ b/cores/beken-72xx/arduino/src/lt_defs.h @@ -2,7 +2,6 @@ #error "Don't include this file directly" -#define LT_ARD_HAS_WIFI 1 -#define LT_ARD_HAS_SERIAL 1 - +#define LT_ARD_HAS_WIFI 1 +#define LT_ARD_HAS_SERIAL 1 #define LT_ARD_MD5_HOSTAPD 1 diff --git a/cores/beken-72xx/base/lt_defs.h b/cores/beken-72xx/base/lt_defs.h index e80ef9d..3aac8ce 100644 --- a/cores/beken-72xx/base/lt_defs.h +++ b/cores/beken-72xx/base/lt_defs.h @@ -2,11 +2,16 @@ #error "Don't include this file directly" -#define LT_HAS_PRINTF 1 -#define LT_HAS_LWIP 1 -#define LT_HAS_LWIP2 1 -#define LT_HAS_FREERTOS 1 -#define LT_HAS_MBEDTLS 1 +#define LT_HAS_FLASH 1 +#define LT_HAS_FREERTOS 1 +#define LT_HAS_LWIP 1 +#define LT_HAS_LWIP2 1 +#define LT_HAS_MBEDTLS 1 +#define LT_HAS_OTA 1 +#define LT_HAS_PRINTF 1 +#define LT_HW_DEEP_SLEEP 1 +#define LT_HW_WATCHDOG 1 +#define LT_HW_WIFI 1 #define LT_HEAP_FUNC xPortGetFreeHeapSize #define LT_REALLOC_FUNC pvPortRealloc diff --git a/cores/beken-72xx/base/lt_family.h b/cores/beken-72xx/base/lt_family.h index fce1aa6..cf31399 100644 --- a/cores/beken-72xx/base/lt_family.h +++ b/cores/beken-72xx/base/lt_family.h @@ -2,13 +2,13 @@ #pragma once -#include LT_VARIANT_H +#include // Choose the main UART output port #ifndef LT_UART_DEFAULT_PORT -#if HAS_SERIAL2 +#if LT_HW_UART2 #define LT_UART_DEFAULT_PORT 2 -#elif HAS_SERIAL1 +#elif LT_HW_UART1 #define LT_UART_DEFAULT_PORT 1 #else #error "No serial port is available" diff --git a/cores/common/arduino/libraries/api/Serial/Serial.h b/cores/common/arduino/libraries/api/Serial/Serial.h index 232c48c..1b80b68 100644 --- a/cores/common/arduino/libraries/api/Serial/Serial.h +++ b/cores/common/arduino/libraries/api/Serial/Serial.h @@ -8,31 +8,6 @@ using namespace arduino; -#if HAS_SERIAL0 -#ifndef PIN_SERIAL0_RX -#define PIN_SERIAL0_RX PIN_INVALID -#endif -#ifndef PIN_SERIAL0_TX -#define PIN_SERIAL0_TX PIN_INVALID -#endif -#endif -#if HAS_SERIAL1 -#ifndef PIN_SERIAL1_RX -#define PIN_SERIAL1_RX PIN_INVALID -#endif -#ifndef PIN_SERIAL1_TX -#define PIN_SERIAL1_TX PIN_INVALID -#endif -#endif -#if HAS_SERIAL2 -#ifndef PIN_SERIAL2_RX -#define PIN_SERIAL2_RX PIN_INVALID -#endif -#ifndef PIN_SERIAL2_TX -#define PIN_SERIAL2_TX PIN_INVALID -#endif -#endif - class SerialClass : public HardwareSerial { private: uint32_t port; diff --git a/cores/common/arduino/src/Arduino.h b/cores/common/arduino/src/Arduino.h index cdda136..4688e28 100644 --- a/cores/common/arduino/src/Arduino.h +++ b/cores/common/arduino/src/Arduino.h @@ -44,13 +44,13 @@ using namespace arduino; #include #if HAS_SERIAL_CLASS -#if HAS_SERIAL0 +#if LT_HW_UART0 extern SerialClass Serial0; #endif -#if HAS_SERIAL1 +#if LT_HW_UART1 extern SerialClass Serial1; #endif -#if HAS_SERIAL2 +#if LT_HW_UART2 extern SerialClass Serial2; #endif #endif diff --git a/cores/common/arduino/src/wiring/wiring_custom.h b/cores/common/arduino/src/wiring/wiring_custom.h index befc254..7be9b6b 100644 --- a/cores/common/arduino/src/wiring/wiring_custom.h +++ b/cores/common/arduino/src/wiring/wiring_custom.h @@ -22,7 +22,6 @@ extern "C" { #define PIN_UART (1 << 11) #define PIN_MODE_ALL 0xFFFFFFFF -#define PIN_INVALID 255 typedef struct PinData_s PinData; diff --git a/cores/common/base/libretiny.h b/cores/common/base/libretiny.h index 22a133a..1d394e9 100644 --- a/cores/common/base/libretiny.h +++ b/cores/common/base/libretiny.h @@ -44,6 +44,7 @@ // APIs #include "lt_api.h" // main API function definitions #include "lt_logger.h" // UART logger utility +#include "lt_pins.h" // additional pin macros #include "lt_posix_api.h" // POSIX compat functions // printf silencing methods #include diff --git a/cores/common/base/lt_pins.h b/cores/common/base/lt_pins.h new file mode 100644 index 0000000..7e9f626 --- /dev/null +++ b/cores/common/base/lt_pins.h @@ -0,0 +1,69 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-06-21. */ + +#include LT_VARIANT_H + +#define PIN_INVALID 255 + +#define LT_HW_UART0 HAS_SERIAL0 +#define LT_HW_UART1 HAS_SERIAL1 +#define LT_HW_UART2 HAS_SERIAL2 +#define LT_HW_I2C0 HAS_WIRE0 +#define LT_HW_I2C1 HAS_WIRE1 +#define LT_HW_I2C2 HAS_WIRE2 +#define LT_HW_SPI0 HAS_SPI0 +#define LT_HW_SPI1 HAS_SPI1 +#define LT_HW_SPI2 HAS_SPI2 + +#if LT_HW_UART0 +#ifndef PIN_SERIAL0_RX +#define PIN_SERIAL0_RX PIN_INVALID +#endif +#ifndef PIN_SERIAL0_TX +#define PIN_SERIAL0_TX PIN_INVALID +#endif +#endif + +#if LT_HW_UART1 +#ifndef PIN_SERIAL1_RX +#define PIN_SERIAL1_RX PIN_INVALID +#endif +#ifndef PIN_SERIAL1_TX +#define PIN_SERIAL1_TX PIN_INVALID +#endif +#endif + +#if LT_HW_UART2 +#ifndef PIN_SERIAL2_RX +#define PIN_SERIAL2_RX PIN_INVALID +#endif +#ifndef PIN_SERIAL2_TX +#define PIN_SERIAL2_TX PIN_INVALID +#endif +#endif + +#if LT_HW_I2C0 +#ifndef PIN_WIRE0_SDA +#define PIN_WIRE0_SDA PIN_INVALID +#endif +#ifndef PIN_WIRE0_SCL +#define PIN_WIRE0_SCL PIN_INVALID +#endif +#endif + +#if LT_HW_I2C1 +#ifndef PIN_WIRE1_SDA +#define PIN_WIRE1_SDA PIN_INVALID +#endif +#ifndef PIN_WIRE1_SCL +#define PIN_WIRE1_SCL PIN_INVALID +#endif +#endif + +#if LT_HW_I2C2 +#ifndef PIN_WIRE2_SDA +#define PIN_WIRE2_SDA PIN_INVALID +#endif +#ifndef PIN_WIRE2_SCL +#define PIN_WIRE2_SCL PIN_INVALID +#endif +#endif diff --git a/cores/realtek-amb/arduino/src/main.cpp b/cores/realtek-amb/arduino/src/main.cpp index 7db967f..4fcc21f 100644 --- a/cores/realtek-amb/arduino/src/main.cpp +++ b/cores/realtek-amb/arduino/src/main.cpp @@ -7,7 +7,7 @@ extern "C" { osThreadId main_tid = 0; -#if LT_AUTO_DOWNLOAD_REBOOT && LT_ARD_HAS_SERIAL && defined(PIN_SERIAL2_RX) && defined(PIN_SERIAL2_TX) +#if LT_AUTO_DOWNLOAD_REBOOT && LT_ARD_HAS_SERIAL && LT_HW_UART2 void lt_init_arduino() { // initialize auto-download-reboot parser Serial2.begin(115200); diff --git a/cores/realtek-amb/base/lt_defs.h b/cores/realtek-amb/base/lt_defs.h index e6250ff..1b387c6 100644 --- a/cores/realtek-amb/base/lt_defs.h +++ b/cores/realtek-amb/base/lt_defs.h @@ -2,7 +2,9 @@ #error "Don't include this file directly" -#define LT_HAS_PRINTF 1 +#define LT_HAS_FLASH 1 +#define LT_HW_WATCHDOG 1 +#define LT_HW_WIFI 1 #define LT_HEAP_FUNC xPortGetFreeHeapSize #define LT_REALLOC_FUNC pvPortReAlloc diff --git a/cores/realtek-ambz/arduino/libraries/Serial/Serial.cpp b/cores/realtek-ambz/arduino/libraries/Serial/Serial.cpp index f075d19..6f5d8e3 100644 --- a/cores/realtek-ambz/arduino/libraries/Serial/Serial.cpp +++ b/cores/realtek-ambz/arduino/libraries/Serial/Serial.cpp @@ -2,13 +2,13 @@ #include "SerialPrivate.h" -#if HAS_SERIAL0 +#if LT_HW_UART0 SerialClass Serial0(0, PIN_SERIAL0_RX, PIN_SERIAL0_TX); #endif -#if HAS_SERIAL1 +#if LT_HW_UART1 SerialClass Serial1(1, PIN_SERIAL1_RX, PIN_SERIAL1_TX); #endif -#if HAS_SERIAL2 +#if LT_HW_UART2 SerialClass Serial2(2, PIN_SERIAL2_RX, PIN_SERIAL2_TX); #endif diff --git a/cores/realtek-ambz/arduino/src/lt_defs.h b/cores/realtek-ambz/arduino/src/lt_defs.h index aff5c9b..39692e0 100644 --- a/cores/realtek-ambz/arduino/src/lt_defs.h +++ b/cores/realtek-ambz/arduino/src/lt_defs.h @@ -2,6 +2,5 @@ #error "Don't include this file directly" -#define LT_ARD_HAS_SERIAL 1 - +#define LT_ARD_HAS_SERIAL 1 #define LT_ARD_MD5_POLARSSL 1 diff --git a/cores/realtek-ambz/base/lt_defs.h b/cores/realtek-ambz/base/lt_defs.h index 0125e4b..a8f1344 100644 --- a/cores/realtek-ambz/base/lt_defs.h +++ b/cores/realtek-ambz/base/lt_defs.h @@ -2,7 +2,9 @@ #error "Don't include this file directly" +#define LT_HAS_FREERTOS 1 #define LT_HAS_LWIP 1 #define LT_HAS_LWIP2 1 -#define LT_HAS_FREERTOS 1 #define LT_HAS_MBEDTLS 1 +#define LT_HAS_OTA 1 +#define LT_HAS_PRINTF 1 diff --git a/cores/realtek-ambz/base/lt_family.h b/cores/realtek-ambz/base/lt_family.h index 3a25b48..205b9c8 100644 --- a/cores/realtek-ambz/base/lt_family.h +++ b/cores/realtek-ambz/base/lt_family.h @@ -2,15 +2,15 @@ #pragma once -#include LT_VARIANT_H +#include // Choose the main UART output port #ifndef LT_UART_DEFAULT_PORT -#if HAS_SERIAL2 +#if LT_HW_UART2 #define LT_UART_DEFAULT_PORT 2 -#elif HAS_SERIAL0 +#elif LT_HW_UART0 #define LT_UART_DEFAULT_PORT 0 -#elif HAS_SERIAL1 +#elif LT_HW_UART1 #define LT_UART_DEFAULT_PORT 1 #else #error "No serial port is available" diff --git a/cores/realtek-ambz2/arduino/libraries/Serial/Serial.cpp b/cores/realtek-ambz2/arduino/libraries/Serial/Serial.cpp index 709425a..9fb18d6 100644 --- a/cores/realtek-ambz2/arduino/libraries/Serial/Serial.cpp +++ b/cores/realtek-ambz2/arduino/libraries/Serial/Serial.cpp @@ -2,13 +2,13 @@ #include "SerialPrivate.h" -#if HAS_SERIAL0 +#if LT_HW_UART0 SerialClass Serial0(0, PIN_SERIAL0_RX, PIN_SERIAL0_TX); #endif -#if HAS_SERIAL1 +#if LT_HW_UART1 SerialClass Serial1(1, PIN_SERIAL1_RX, PIN_SERIAL1_TX); #endif -#if HAS_SERIAL2 +#if LT_HW_UART2 SerialClass Serial2(2, PIN_SERIAL2_RX, PIN_SERIAL2_TX); #endif diff --git a/cores/realtek-ambz2/arduino/src/lt_defs.h b/cores/realtek-ambz2/arduino/src/lt_defs.h index 72fc05a..f6cceb0 100644 --- a/cores/realtek-ambz2/arduino/src/lt_defs.h +++ b/cores/realtek-ambz2/arduino/src/lt_defs.h @@ -3,8 +3,7 @@ #error "Don't include this file directly" #define LT_ARD_HAS_SERIAL 1 -#define LT_ARD_HAS_WIFI 1 #define LT_ARD_HAS_SOFTSERIAL 0 +#define LT_ARD_HAS_WIFI 1 #define LT_ARD_HAS_WIRE 0 - -#define LT_ARD_MD5_MBEDTLS 1 +#define LT_ARD_MD5_MBEDTLS 1 diff --git a/cores/realtek-ambz2/base/lt_defs.h b/cores/realtek-ambz2/base/lt_defs.h index 0125e4b..4868572 100644 --- a/cores/realtek-ambz2/base/lt_defs.h +++ b/cores/realtek-ambz2/base/lt_defs.h @@ -2,7 +2,9 @@ #error "Don't include this file directly" +#define LT_HAS_FREERTOS 1 #define LT_HAS_LWIP 1 #define LT_HAS_LWIP2 1 -#define LT_HAS_FREERTOS 1 #define LT_HAS_MBEDTLS 1 +#define LT_HAS_PRINTF 1 +#define LT_HW_BLE 1 diff --git a/cores/realtek-ambz2/base/lt_family.h b/cores/realtek-ambz2/base/lt_family.h index d9c9f41..a574f6c 100644 --- a/cores/realtek-ambz2/base/lt_family.h +++ b/cores/realtek-ambz2/base/lt_family.h @@ -2,15 +2,15 @@ #pragma once -#include LT_VARIANT_H +#include // Choose the main UART output port #ifndef LT_UART_DEFAULT_PORT -#if HAS_SERIAL2 +#if LT_HW_UART2 #define LT_UART_DEFAULT_PORT 2 -#elif HAS_SERIAL0 +#elif LT_HW_UART0 #define LT_UART_DEFAULT_PORT 0 -#elif HAS_SERIAL1 +#elif LT_HW_UART1 #define LT_UART_DEFAULT_PORT 1 #else #error "No serial port is available" diff --git a/docs/dev/config.md b/docs/dev/config.md index 94950fb..1a976f3 100644 --- a/docs/dev/config.md +++ b/docs/dev/config.md @@ -70,7 +70,7 @@ build_flags = #### Per-module logging & debugging -The following options enable library-specific logging output. They are effective **for all loglevels** - i.e. disabling `LT_DEBUG_WIFI` will disable WiFi debug messages, as well as errors. +The following options enable library-specific logging output. They are effective **for all loglevels** - i.e. disabling `LT_DEBUG_WIFI` will disable WiFi debug messages, warnings, as well as errors. To see debug messages from i.e. OTA, loglevel must also be changed. @@ -119,24 +119,43 @@ Options for controlling default UART log output. - `LT_MICROS_HIGH_RES` (1) - count runtime microseconds using a high-resolution timer (if possible); disable if your application doesn't need `micros()` - `LT_AUTO_DOWNLOAD_REBOOT` (1) - automatically reboot into "download mode" after detecting a flashing protocol command; [read more](../flashing/tools/adr.md) -### Family feature config +### Family configuration !!! bug "Warning" These options are not meant for end-users. They're provided here as a reference for developers. **Do not set these options manually**. These options are selectively set by all families, as part of the build process. They are used for enabling LT core API parts, if the family has support for it. Files named `lt_defs.h`, containing these options, are read by the PlatformIO builders (note: they're never included by C code). -The `LT_ARD_*` options are only used with Arduino frameworks. +Checking for option value should be done with `#if` (not with `#ifdef`!) - if it's not defined, it will evaluate to 0. Otherwise, it will use the defined value, either 0 or 1. -The meaning of most flags is as follows: - -- `LT_HAS_FREERTOS` - FreeRTOS supported and used -- `LT_HAS_LWIP` - LwIP in SDK (any version) -- `LT_HAS_LWIP2` - LwIP v2.0.0 or newer -- `LT_HAS_MBEDTLS` - mbedTLS in SDK -- `LT_HAS_PRINTF` - printf library implemented -- `LT_ARD_HAS_SERIAL` - Serial class implemented, `Serial.h` available -- `LT_ARD_HAS_SOFTSERIAL` - SoftwareSerial library implemented, `SoftwareSerial.h` available -- `LT_ARD_HAS_WIFI` - WiFi library implemented, `WiFiData.h` available -- `LT_HEAP_FUNC` - function name used to get available heap size (for `LT_HEAP_I()`) -- `LT_REALLOC_FUNC` - function name used for `realloc()` call +- family-/chip-specific hardware peripherals + - `LT_HW_WIFI` - WiFi supported on the chip + - `LT_HW_BT` - Bluetooth Classic supported on the chip + - `LT_HW_BLE` - Bluetooth Low Energy supported on the chip + - `LT_HW_WATCHDOG` - watchdog available + - `LT_HW_DEEP_SLEEP` - deep sleep possible +- board-specific peripherals (note: defined in `lt_pins.h`, depending on available pin numbers) + - `LT_HW_UART#` - UART number # available on the board + - `LT_HW_I2C#` - I²C number # available on the board + - `LT_HW_SPI#` - SPI number # available on the board +- family software options (SDK features, LT implementation status) + - `LT_HAS_FREERTOS` - FreeRTOS supported and used + - `LT_HAS_LWIP` - LwIP in SDK (any version) + - `LT_HAS_LWIP2` - LwIP v2.0.0 or newer + - `LT_HAS_MBEDTLS` - mbedTLS in SDK + - `LT_HAS_PRINTF` - printf library implemented + - `LT_HAS_FLASH` - FAL flash port implemented + - `LT_HAS_OTA` - OTA implemented in base framework +- Arduino Core implementation status (only available and used along with Arduino framework) + - `LT_ARD_HAS_SERIAL` - Serial class implemented + - `LT_ARD_HAS_SOFTSERIAL` - SoftwareSerial library implemented + - `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 + - `LT_HEAP_FUNC` - function name used to get available heap size (for `LT_HEAP_I()`) + - `LT_REALLOC_FUNC` - function name used for `realloc()` call + - `LT_REMALLOC` - use `malloc()` and `memcpy()` in `realloc()` call From e38e53bac0bc51b65f9c0c3461bdb1df27c82c2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 22 Jun 2023 18:30:14 +0200 Subject: [PATCH 28/31] [core] Split lt_api.c into separate units --- .github/workflows/docs.yml | 3 +- .gitignore | 2 + SUMMARY.md | 3 +- builder/utils/cores.py | 1 + cores/beken-72xx/base/api/lt_cpu.c | 13 + cores/beken-72xx/base/api/lt_device.c | 41 +++ cores/beken-72xx/base/api/lt_flash.c | 26 ++ cores/beken-72xx/base/api/lt_init.c | 9 + cores/beken-72xx/base/api/lt_mem.c | 21 ++ cores/beken-72xx/base/api/lt_ota.c | 39 +++ cores/beken-72xx/base/api/lt_wdt.c | 18 ++ cores/beken-72xx/base/lt_api.c | 184 ----------- cores/common/base/api/lt_cpu.c | 58 ++++ cores/common/base/api/lt_device.c | 80 +++++ cores/common/base/api/lt_flash.c | 39 +++ cores/common/base/api/lt_mem.c | 26 ++ cores/common/base/api/lt_ota.c | 18 ++ cores/common/base/api/lt_utils.c | 41 +++ cores/common/base/api/lt_wdt.c | 11 + cores/common/base/lt_api.c | 296 ------------------ cores/common/base/lt_api.h | 2 +- .../arduino/src/{lt_api.c => api/lt_cpu.c} | 0 cores/realtek-amb/base/api/lt_flash.c | 14 + cores/realtek-amb/base/api/lt_wdt.c | 18 ++ cores/realtek-amb/base/lt_api.c | 42 --- cores/realtek-ambz/base/api/lt_cpu.c | 34 ++ cores/realtek-ambz/base/api/lt_device.c | 39 +++ cores/realtek-ambz/base/api/lt_flash.c | 14 + cores/realtek-ambz/base/api/lt_init.c | 16 + cores/realtek-ambz/base/api/lt_mem.c | 8 + cores/realtek-ambz/base/api/lt_ota.c | 78 +++++ cores/realtek-ambz/base/lt_api.c | 201 ------------ cores/realtek-ambz2/base/api/lt_cpu.c | 21 ++ cores/realtek-ambz2/base/api/lt_device.c | 61 ++++ cores/realtek-ambz2/base/api/lt_init.c | 14 + cores/realtek-ambz2/base/api/lt_mem.c | 8 + cores/realtek-ambz2/base/api/lt_ota.c | 24 ++ cores/realtek-ambz2/base/lt_api.c | 138 -------- docs/contrib/lt-api.md | 13 + docs/contrib/porting.md | 1 + docs/script.js | 6 + docs/scripts/build_json.py | 2 +- docs/scripts/write_apis.py | 125 ++++++++ .../{update_docs.py => write_boards.py} | 0 mkdocs.yml | 4 + 45 files changed, 947 insertions(+), 865 deletions(-) create mode 100644 cores/beken-72xx/base/api/lt_cpu.c create mode 100644 cores/beken-72xx/base/api/lt_device.c create mode 100644 cores/beken-72xx/base/api/lt_flash.c create mode 100644 cores/beken-72xx/base/api/lt_init.c create mode 100644 cores/beken-72xx/base/api/lt_mem.c create mode 100644 cores/beken-72xx/base/api/lt_ota.c create mode 100644 cores/beken-72xx/base/api/lt_wdt.c delete mode 100644 cores/beken-72xx/base/lt_api.c create mode 100644 cores/common/base/api/lt_cpu.c create mode 100644 cores/common/base/api/lt_device.c create mode 100644 cores/common/base/api/lt_flash.c create mode 100644 cores/common/base/api/lt_mem.c create mode 100644 cores/common/base/api/lt_ota.c create mode 100644 cores/common/base/api/lt_utils.c create mode 100644 cores/common/base/api/lt_wdt.c delete mode 100644 cores/common/base/lt_api.c rename cores/realtek-amb/arduino/src/{lt_api.c => api/lt_cpu.c} (100%) create mode 100644 cores/realtek-amb/base/api/lt_flash.c create mode 100644 cores/realtek-amb/base/api/lt_wdt.c delete mode 100644 cores/realtek-amb/base/lt_api.c create mode 100644 cores/realtek-ambz/base/api/lt_cpu.c create mode 100644 cores/realtek-ambz/base/api/lt_device.c create mode 100644 cores/realtek-ambz/base/api/lt_flash.c create mode 100644 cores/realtek-ambz/base/api/lt_init.c create mode 100644 cores/realtek-ambz/base/api/lt_mem.c create mode 100644 cores/realtek-ambz/base/api/lt_ota.c delete mode 100644 cores/realtek-ambz/base/lt_api.c create mode 100644 cores/realtek-ambz2/base/api/lt_cpu.c create mode 100644 cores/realtek-ambz2/base/api/lt_device.c create mode 100644 cores/realtek-ambz2/base/api/lt_init.c create mode 100644 cores/realtek-ambz2/base/api/lt_mem.c create mode 100644 cores/realtek-ambz2/base/api/lt_ota.c delete mode 100644 cores/realtek-ambz2/base/lt_api.c create mode 100644 docs/contrib/lt-api.md create mode 100644 docs/script.js create mode 100644 docs/scripts/write_apis.py rename docs/scripts/{update_docs.py => write_boards.py} (100%) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 8794182..3fc7e73 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -25,7 +25,8 @@ jobs: run: | mkdir -p site/ boardgen ltci - python docs/scripts/update_docs.py + python docs/scripts/write_boards.py + python docs/scripts/write_apis.py python docs/scripts/prepare_doxygen.py python docs/scripts/build_json.py cp *.json site/ diff --git a/.gitignore b/.gitignore index d4c122c..95bd98f 100644 --- a/.gitignore +++ b/.gitignore @@ -264,3 +264,5 @@ docs/status/supported_*.md docs/status/unsupported_boards_*.md boards/**/*.svg boards/**/*.md +# other generated files +docs/contrib/lt-api-functions.md diff --git a/SUMMARY.md b/SUMMARY.md index 284ab5d..51d4179 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -48,8 +48,9 @@ * [File list](ltapi/files.md) * 👷 Contributor's manual (WIP) * [Porting new families](docs/contrib/porting.md) - * [📁 Project structure](docs/contrib/project-structure.md) + * [API functions guide](docs/contrib/lt-api.md) * [C standard library](docs/contrib/stdlib.md) + * [📁 Project structure](docs/contrib/project-structure.md) * [✈️ OTA format](docs/contrib/ota/README.md) * [uf2ota.py tool](docs/contrib/ota/uf2ota.md) * [uf2ota.h library](docs/contrib/ota/library.md) diff --git a/builder/utils/cores.py b/builder/utils/cores.py index 280d5b0..8848e08 100644 --- a/builder/utils/cores.py +++ b/builder/utils/cores.py @@ -46,6 +46,7 @@ def env_add_core_sources(env: Environment, queue, name: str, path: str) -> bool: base_dir=path, srcs=[ "+<*.c*>", + "+", "+", "+", "+", diff --git a/cores/beken-72xx/base/api/lt_cpu.c b/cores/beken-72xx/base/api/lt_cpu.c new file mode 100644 index 0000000..d767cbb --- /dev/null +++ b/cores/beken-72xx/base/api/lt_cpu.c @@ -0,0 +1,13 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-02-27. */ + +#include +#include + +lt_cpu_model_t lt_cpu_get_model() { + uint8_t chipId = *(uint8_t *)(SCTRL_CHIP_ID); + return CPU_MODEL_ENUM(FAMILY, chipId); +} + +const char *lt_cpu_get_core_type() { + return "ARM968E-S (ARMv5TE)"; +} diff --git a/cores/beken-72xx/base/api/lt_device.c b/cores/beken-72xx/base/api/lt_device.c new file mode 100644 index 0000000..2008027 --- /dev/null +++ b/cores/beken-72xx/base/api/lt_device.c @@ -0,0 +1,41 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-02-27. */ + +#include +#include + +void lt_get_device_mac(uint8_t *mac) { + cfg_load_mac(mac); +} + +void lt_reboot() { + bk_reboot(); +} + +bool lt_reboot_download_mode() { + bk_reboot(); + return true; +} + +lt_reboot_reason_t lt_get_reboot_reason() { + switch (bk_misc_get_start_type()) { + case RESET_SOURCE_POWERON: + return REBOOT_REASON_POWER; + case RESET_SOURCE_REBOOT: + return REBOOT_REASON_SOFTWARE; + case RESET_SOURCE_WATCHDOG: + return REBOOT_REASON_WATCHDOG; + case RESET_SOURCE_CRASH_XAT0: + case RESET_SOURCE_CRASH_UNDEFINED: + case RESET_SOURCE_CRASH_PREFETCH_ABORT: + case RESET_SOURCE_CRASH_DATA_ABORT: + case RESET_SOURCE_CRASH_UNUSED: + case RESET_SOURCE_CRASH_PER_XAT0: + return REBOOT_REASON_CRASH; + case RESET_SOURCE_DEEPPS_GPIO: + case RESET_SOURCE_DEEPPS_RTC: + case RESET_SOURCE_DEEPPS_USB: + return REBOOT_REASON_SLEEP; + default: + return REBOOT_REASON_UNKNOWN; + } +} diff --git a/cores/beken-72xx/base/api/lt_flash.c b/cores/beken-72xx/base/api/lt_flash.c new file mode 100644 index 0000000..9eaed78 --- /dev/null +++ b/cores/beken-72xx/base/api/lt_flash.c @@ -0,0 +1,26 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-02-27. */ + +#include +#include + +// can't include as it collides with on Windows -_- +#define REG_FLASH_BASE 0x00803000 +#define REG_FLASH_OPERATE_SW (REG_FLASH_BASE + 0 * 4) +#define REG_FLASH_RDID (REG_FLASH_BASE + 4 * 4) +#define FLASH_BUSY_SW (0x01UL << 31) +#define FLASH_WP_VALUE (0x01UL << 30) +#define FLASH_OP_SW (0x01UL << 29) +#define FLASH_OP_TYPE_POS 24 +#define FLASH_OP_RDID 20 + +lt_flash_id_t lt_flash_get_id() { + uint32_t data = (FLASH_OP_RDID << FLASH_OP_TYPE_POS) | FLASH_OP_SW | FLASH_WP_VALUE; + REG_WRITE(REG_FLASH_OPERATE_SW, data); + while (REG_READ(REG_FLASH_OPERATE_SW) & FLASH_BUSY_SW) {} + lt_flash_id_t id = { + .manufacturer_id = REG_RD8(REG_FLASH_RDID, 2), + .chip_id = REG_RD8(REG_FLASH_RDID, 1), + .chip_size_id = REG_RD8(REG_FLASH_RDID, 0), + }; + return id; +} diff --git a/cores/beken-72xx/base/api/lt_init.c b/cores/beken-72xx/base/api/lt_init.c new file mode 100644 index 0000000..05d28b1 --- /dev/null +++ b/cores/beken-72xx/base/api/lt_init.c @@ -0,0 +1,9 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-02-27. */ + +#include +#include + +void lt_init_family() { + // set default UART output port + uart_print_port = LT_UART_DEFAULT_PORT - 1; +} diff --git a/cores/beken-72xx/base/api/lt_mem.c b/cores/beken-72xx/base/api/lt_mem.c new file mode 100644 index 0000000..f6038fe --- /dev/null +++ b/cores/beken-72xx/base/api/lt_mem.c @@ -0,0 +1,21 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-02-27. */ + +#include +#include + +uint32_t lt_ram_get_size() { + return 256 * 1024; +} + +uint32_t lt_heap_get_size() { +#if configDYNAMIC_HEAP_SIZE + extern unsigned char _empty_ram; +#if CFG_SOC_NAME == SOC_BK7231N + return (0x00400000 + 192 * 1024) - (uint32_t)(&_empty_ram); +#else + return (0x00400000 + 256 * 1024) - (uint32_t)(&_empty_ram); +#endif +#else + return configTOTAL_HEAP_SIZE; +#endif +} diff --git a/cores/beken-72xx/base/api/lt_ota.c b/cores/beken-72xx/base/api/lt_ota.c new file mode 100644 index 0000000..2961e76 --- /dev/null +++ b/cores/beken-72xx/base/api/lt_ota.c @@ -0,0 +1,39 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-02-27. */ + +#include +#include + +lt_ota_type_t lt_ota_get_type() { + return OTA_TYPE_SINGLE; +} + +bool lt_ota_is_valid(uint8_t index) { + if (index != 0) + return false; + // check download RBL + // TODO: maybe check header CRC or even binary hashes + uint32_t magic; + lt_flash_read(FLASH_DOWNLOAD_OFFSET, (uint8_t *)&magic, 4); + return magic == 0x004C4252; // "RBL\0", little-endian +} + +uint8_t lt_ota_dual_get_current() { + return 0; +} + +uint8_t lt_ota_dual_get_stored() { + return 0; +} + +bool lt_ota_switch(bool revert) { + if (!lt_ota_is_valid(0)) + // no valid "download" image + // - return false when trying to activate + // - return true when trying to revert + return revert; + if (revert) { + // there's a valid "download" image, which has to be removed + return lt_flash_erase_block(FLASH_DOWNLOAD_OFFSET); + } + return true; +} diff --git a/cores/beken-72xx/base/api/lt_wdt.c b/cores/beken-72xx/base/api/lt_wdt.c new file mode 100644 index 0000000..b0648d0 --- /dev/null +++ b/cores/beken-72xx/base/api/lt_wdt.c @@ -0,0 +1,18 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-02-27. */ + +#include +#include + +bool lt_wdt_enable(uint32_t timeout) { + wdt_ctrl(WCMD_SET_PERIOD, &timeout); + wdt_ctrl(WCMD_POWER_UP, NULL); + return true; +} + +void lt_wdt_disable() { + wdt_ctrl(WCMD_POWER_DOWN, NULL); +} + +void lt_wdt_feed() { + wdt_ctrl(WCMD_RELOAD_PERIOD, NULL); +} diff --git a/cores/beken-72xx/base/lt_api.c b/cores/beken-72xx/base/lt_api.c deleted file mode 100644 index 46e6c11..0000000 --- a/cores/beken-72xx/base/lt_api.c +++ /dev/null @@ -1,184 +0,0 @@ -/* Copyright (c) Kuba Szczodrzyński 2023-02-27. */ - -#include -#include - -// can't include as it collides with on Windows -_- -#define REG_FLASH_BASE 0x00803000 -#define REG_FLASH_OPERATE_SW (REG_FLASH_BASE + 0 * 4) -#define REG_FLASH_RDID (REG_FLASH_BASE + 4 * 4) -#define FLASH_BUSY_SW (0x01UL << 31) -#define FLASH_WP_VALUE (0x01UL << 30) -#define FLASH_OP_SW (0x01UL << 29) -#define FLASH_OP_TYPE_POS 24 -#define FLASH_OP_RDID 20 - -void lt_init_family() { - // set default UART output port - uart_print_port = LT_UART_DEFAULT_PORT - 1; -} - -/* _____ _____ _ _ - / ____| __ \| | | | - | | | |__) | | | | - | | | ___/| | | | - | |____| | | |__| | - \_____|_| \____*/ -lt_cpu_model_t lt_cpu_get_model() { - uint8_t chipId = *(uint8_t *)(SCTRL_CHIP_ID); - return CPU_MODEL_ENUM(FAMILY, chipId); -} - -const char *lt_cpu_get_core_type() { - return "ARM968E-S (ARMv5TE)"; -} - -/*_____ _ - | __ \ (_) - | | | | _____ ___ ___ ___ - | | | |/ _ \ \ / / |/ __/ _ \ - | |__| | __/\ V /| | (_| __/ - |_____/ \___| \_/ |_|\___\__*/ -void lt_get_device_mac(uint8_t *mac) { - cfg_load_mac(mac); -} - -void lt_reboot() { - bk_reboot(); -} - -bool lt_reboot_download_mode() { - bk_reboot(); - return true; -} - -lt_reboot_reason_t lt_get_reboot_reason() { - switch (bk_misc_get_start_type()) { - case RESET_SOURCE_POWERON: - return REBOOT_REASON_POWER; - case RESET_SOURCE_REBOOT: - return REBOOT_REASON_SOFTWARE; - case RESET_SOURCE_WATCHDOG: - return REBOOT_REASON_WATCHDOG; - case RESET_SOURCE_CRASH_XAT0: - case RESET_SOURCE_CRASH_UNDEFINED: - case RESET_SOURCE_CRASH_PREFETCH_ABORT: - case RESET_SOURCE_CRASH_DATA_ABORT: - case RESET_SOURCE_CRASH_UNUSED: - case RESET_SOURCE_CRASH_PER_XAT0: - return REBOOT_REASON_CRASH; - case RESET_SOURCE_DEEPPS_GPIO: - case RESET_SOURCE_DEEPPS_RTC: - case RESET_SOURCE_DEEPPS_USB: - return REBOOT_REASON_SLEEP; - default: - return REBOOT_REASON_UNKNOWN; - } -} - -/*______ _ _ - | ____| | | | - | |__ | | __ _ ___| |__ - | __| | |/ _` / __| '_ \ - | | | | (_| \__ \ | | | - |_| |_|\__,_|___/_| |*/ -lt_flash_id_t lt_flash_get_id() { - uint32_t data = (FLASH_OP_RDID << FLASH_OP_TYPE_POS) | FLASH_OP_SW | FLASH_WP_VALUE; - REG_WRITE(REG_FLASH_OPERATE_SW, data); - while (REG_READ(REG_FLASH_OPERATE_SW) & FLASH_BUSY_SW) {} - lt_flash_id_t id = { - .manufacturer_id = REG_RD8(REG_FLASH_RDID, 2), - .chip_id = REG_RD8(REG_FLASH_RDID, 1), - .chip_size_id = REG_RD8(REG_FLASH_RDID, 0), - }; - return id; -} - -/*__ __ - | \/ | - | \ / | ___ _ __ ___ ___ _ __ _ _ - | |\/| |/ _ \ '_ ` _ \ / _ \| '__| | | | - | | | | __/ | | | | | (_) | | | |_| | - |_| |_|\___|_| |_| |_|\___/|_| \__, | - __/ | - |__*/ -uint32_t lt_ram_get_size() { - return 256 * 1024; -} - -uint32_t lt_heap_get_size() { -#if configDYNAMIC_HEAP_SIZE - extern unsigned char _empty_ram; -#if CFG_SOC_NAME == SOC_BK7231N - return (0x00400000 + 192 * 1024) - (uint32_t)(&_empty_ram); -#else - return (0x00400000 + 256 * 1024) - (uint32_t)(&_empty_ram); -#endif -#else - return configTOTAL_HEAP_SIZE; -#endif -} - -/* ____ _______ - / __ \__ __|/\ - | | | | | | / \ - | | | | | | / /\ \ - | |__| | | |/ ____ \ - \____/ |_/_/ \*/ - -lt_ota_type_t lt_ota_get_type() { - return OTA_TYPE_SINGLE; -} - -bool lt_ota_is_valid(uint8_t index) { - if (index != 0) - return false; - // check download RBL - // TODO: maybe check header CRC or even binary hashes - uint32_t magic; - lt_flash_read(FLASH_DOWNLOAD_OFFSET, (uint8_t *)&magic, 4); - return magic == 0x004C4252; // "RBL\0", little-endian -} - -uint8_t lt_ota_dual_get_current() { - return 0; -} - -uint8_t lt_ota_dual_get_stored() { - return 0; -} - -bool lt_ota_switch(bool revert) { - if (!lt_ota_is_valid(0)) - // no valid "download" image - // - return false when trying to activate - // - return true when trying to revert - return revert; - if (revert) { - // there's a valid "download" image, which has to be removed - return lt_flash_erase_block(FLASH_DOWNLOAD_OFFSET); - } - return true; -} - -/*_ __ _ _ _ - \ \ / / | | | | | | - \ \ /\ / /_ _| |_ ___| |__ __| | ___ __ _ - \ \/ \/ / _` | __/ __| '_ \ / _` |/ _ \ / _` | - \ /\ / (_| | || (__| | | | (_| | (_) | (_| | - \/ \/ \__,_|\__\___|_| |_|\__,_|\___/ \__, | - __/ | - |___*/ -bool lt_wdt_enable(uint32_t timeout) { - wdt_ctrl(WCMD_SET_PERIOD, &timeout); - wdt_ctrl(WCMD_POWER_UP, NULL); - return true; -} - -void lt_wdt_disable() { - wdt_ctrl(WCMD_POWER_DOWN, NULL); -} - -void lt_wdt_feed() { - wdt_ctrl(WCMD_RELOAD_PERIOD, NULL); -} diff --git a/cores/common/base/api/lt_cpu.c b/cores/common/base/api/lt_cpu.c new file mode 100644 index 0000000..56aa518 --- /dev/null +++ b/cores/common/base/api/lt_cpu.c @@ -0,0 +1,58 @@ +/* Copyright (c) Kuba Szczodrzyński 2022-04-29. */ + +#include "lt_cpu.h" + +#if LT_HAS_FREERTOS +#include +#include +#endif + +lt_cpu_family_t lt_cpu_get_family() { + return FAMILY; +} + +const char *lt_cpu_get_family_name() { + return STRINGIFY_MACRO(FAMILY) + 2; +} + +__attribute__((weak)) lt_cpu_model_t lt_cpu_get_model() { + return MCU; +} + +const char *lt_cpu_get_model_name() { + return STRINGIFY_MACRO(MCU); +} + +const char *lt_cpu_get_model_code() { + return STRINGIFY_MACRO(MCULC); +} + +__attribute__((weak)) uint32_t lt_cpu_get_unique_id() { + return lt_cpu_get_mac_id(); +} + +__attribute__((weak)) uint32_t lt_cpu_get_mac_id() { + uint8_t mac[6]; + lt_get_device_mac(mac); + return (mac[3] << 0) | (mac[4] << 8) | (mac[5] << 16); +} + +__attribute__((weak)) uint8_t lt_cpu_get_core_count() { + return 1; +} + +#if LT_HAS_FREERTOS +__attribute__((weak)) uint32_t lt_cpu_get_freq() { + return configCPU_CLOCK_HZ; +} +#endif + +uint32_t lt_cpu_get_freq_mhz() { + return lt_cpu_get_freq() / 1000000; +} + +#if LT_HAS_FREERTOS +__attribute__((weak)) uint32_t lt_cpu_get_cycle_count() { + return xTaskGetTickCount() * (configCPU_CLOCK_HZ / configTICK_RATE_HZ); +} +#endif diff --git a/cores/common/base/api/lt_device.c b/cores/common/base/api/lt_device.c new file mode 100644 index 0000000..983ddad --- /dev/null +++ b/cores/common/base/api/lt_device.c @@ -0,0 +1,80 @@ +/* Copyright (c) Kuba Szczodrzyński 2022-04-29. */ + +#include "lt_device.h" + +static char *device_name = NULL; + +const char *lt_get_version() { + return LT_VERSION_STR; +} + +const char *lt_get_board_code() { + return LT_BOARD_STR; +} + +const char *lt_get_device_name() { + if (device_name) + return device_name; + uint32_t chip_id = lt_cpu_get_mac_id(); + uint8_t *id = (uint8_t *)&chip_id; + + const char *model = lt_cpu_get_model_code(); + uint8_t model_len = strlen(model); + device_name = (char *)malloc(3 + model_len + 1 + 6 + 1); + + sprintf(device_name, "LT-%s-%02x%02x%02x", model, id[0], id[1], id[2]); + return device_name; +} + +__attribute__((weak)) void lt_reboot() { + // The Watchdog Way + lt_wdt_enable(1L); + while (1) {} +} + +__attribute__((weak)) bool lt_reboot_wdt() { + if (!lt_wdt_enable(1L)) + return false; + while (1) {} +} + +__attribute__((weak)) bool lt_reboot_download_mode() { + return false; +} + +__attribute__((weak)) lt_reboot_reason_t lt_get_reboot_reason() { + return REBOOT_REASON_UNKNOWN; +} + +const char *lt_get_reboot_reason_name(lt_reboot_reason_t reason) { + if (!reason) + reason = lt_get_reboot_reason(); + switch (reason) { + case REBOOT_REASON_POWER: + return "Power-On"; + case REBOOT_REASON_BROWNOUT: + return "Brownout"; + case REBOOT_REASON_HARDWARE: + return "HW Reboot"; + case REBOOT_REASON_SOFTWARE: + return "SW Reboot"; + case REBOOT_REASON_WATCHDOG: + return "WDT Reset"; + case REBOOT_REASON_CRASH: + return "Crash"; + case REBOOT_REASON_SLEEP: + return "Sleep Wakeup"; + case REBOOT_REASON_DEBUGGER: + return "Debugger"; + default: + return "Unknown"; + } +} + +__attribute__((weak)) bool lt_set_debug_mode(lt_debug_mode_t mode) { + return false; +} + +__attribute__((weak)) void lt_gpio_recover() { + lt_set_debug_mode(DEBUG_MODE_OFF); +} diff --git a/cores/common/base/api/lt_flash.c b/cores/common/base/api/lt_flash.c new file mode 100644 index 0000000..b97c5d5 --- /dev/null +++ b/cores/common/base/api/lt_flash.c @@ -0,0 +1,39 @@ +/* Copyright (c) Kuba Szczodrzyński 2022-04-29. */ + +#include "lt_flash.h" + +#include + +__attribute__((weak)) uint32_t lt_flash_get_size() { + lt_flash_id_t id = lt_flash_get_id(); + if (id.chip_size_id >= 0x14 && id.chip_size_id <= 0x19) { + return (1 << id.chip_size_id); + } +#ifdef FLASH_LENGTH + return FLASH_LENGTH; +#else + return 0; +#endif +} + +bool lt_flash_erase(uint32_t offset, size_t length) { + return fal_partition_erase(fal_root_part, offset, length) >= 0; +} + +bool lt_flash_erase_block(uint32_t offset) { + return fal_partition_erase(fal_root_part, offset, 1) >= 0; +} + +uint32_t lt_flash_read(uint32_t offset, uint8_t *data, size_t length) { + int ret = fal_partition_read(fal_root_part, offset, data, length); + if (ret == -1) + return 0; + return ret; +} + +uint32_t lt_flash_write(uint32_t offset, const uint8_t *data, size_t length) { + int ret = fal_partition_write(fal_root_part, offset, data, length); + if (ret == -1) + return 0; + return ret; +} diff --git a/cores/common/base/api/lt_mem.c b/cores/common/base/api/lt_mem.c new file mode 100644 index 0000000..eae8685 --- /dev/null +++ b/cores/common/base/api/lt_mem.c @@ -0,0 +1,26 @@ +/* Copyright (c) Kuba Szczodrzyński 2022-04-29. */ + +#include "lt_mem.h" + +#if LT_HAS_FREERTOS +#include +#include +#endif + +#if LT_HAS_FREERTOS +__attribute__((weak)) uint32_t lt_heap_get_size() { + return configTOTAL_HEAP_SIZE; +} + +__attribute__((weak)) uint32_t lt_heap_get_free() { + return xPortGetFreeHeapSize(); +} + +__attribute__((weak)) uint32_t lt_heap_get_min_free() { + return xPortGetMinimumEverFreeHeapSize(); +} +#endif + +__attribute__((weak)) uint32_t lt_heap_get_max_alloc() { + return 0; +} diff --git a/cores/common/base/api/lt_ota.c b/cores/common/base/api/lt_ota.c new file mode 100644 index 0000000..5e7da4b --- /dev/null +++ b/cores/common/base/api/lt_ota.c @@ -0,0 +1,18 @@ +/* Copyright (c) Kuba Szczodrzyński 2022-04-29. */ + +#include "lt_ota.h" + +bool lt_ota_can_rollback() { + if (lt_ota_get_type() != OTA_TYPE_DUAL) + return false; + uint8_t current = lt_ota_dual_get_current(); + return lt_ota_is_valid(current ^ 0b11); +} + +uf2_ota_scheme_t lt_ota_get_uf2_scheme() { + if (lt_ota_get_type() == OTA_TYPE_SINGLE) + return UF2_SCHEME_DEVICE_SINGLE; + uint8_t current = lt_ota_dual_get_current(); + // UF2_SCHEME_DEVICE_DUAL_1 or UF2_SCHEME_DEVICE_DUAL_2 + return (uf2_ota_scheme_t)(current ^ 0b11); +} diff --git a/cores/common/base/api/lt_utils.c b/cores/common/base/api/lt_utils.c new file mode 100644 index 0000000..521a5bd --- /dev/null +++ b/cores/common/base/api/lt_utils.c @@ -0,0 +1,41 @@ +/* Copyright (c) Kuba Szczodrzyński 2022-04-29. */ + +#include "lt_utils.h" + +void lt_rand_bytes(uint8_t *buf, size_t len) { + int *data = (int *)buf; + size_t i; + for (i = 0; len >= sizeof(int); len -= sizeof(int)) { + data[i++] = rand(); + } + if (len) { + int rem = rand(); + unsigned char *pRem = (unsigned char *)&rem; + memcpy(buf + i * sizeof(int), pRem, len); + } +} + +void hexdump(const uint8_t *buf, size_t len, uint32_t offset, uint8_t width) { + uint16_t pos = 0; + while (pos < len) { + // print hex offset + printf("%06lx ", offset + pos); + // calculate current line width + uint8_t lineWidth = MIN(width, len - pos); + // print hexadecimal representation + for (uint8_t i = 0; i < lineWidth; i++) { + if (i % 8 == 0) { + printf(" "); + } + printf("%02x ", buf[pos + i]); + } + // print ascii representation + printf(" |"); + for (uint8_t i = 0; i < lineWidth; i++) { + char c = buf[pos + i]; + putchar((c >= 0x20 && c <= 0x7f) ? c : '.'); + } + puts("|\r"); + pos += lineWidth; + } +} diff --git a/cores/common/base/api/lt_wdt.c b/cores/common/base/api/lt_wdt.c new file mode 100644 index 0000000..a337880 --- /dev/null +++ b/cores/common/base/api/lt_wdt.c @@ -0,0 +1,11 @@ +/* Copyright (c) Kuba Szczodrzyński 2022-04-29. */ + +#include "lt_wdt.h" + +__attribute__((weak)) bool lt_wdt_enable(uint32_t timeout) { + return false; +} + +__attribute__((weak)) void lt_wdt_disable() {} + +__attribute__((weak)) void lt_wdt_feed() {} diff --git a/cores/common/base/lt_api.c b/cores/common/base/lt_api.c deleted file mode 100644 index 09f1bdd..0000000 --- a/cores/common/base/lt_api.c +++ /dev/null @@ -1,296 +0,0 @@ -/* Copyright (c) Kuba Szczodrzyński 2022-04-29. */ - -#include "lt_api.h" - -#include - -#if LT_HAS_FREERTOS -#include -#include -#endif - -/* _____ _____ _ _ - / ____| __ \| | | | - | | | |__) | | | | - | | | ___/| | | | - | |____| | | |__| | - \_____|_| \____*/ -lt_cpu_family_t lt_cpu_get_family() { - return FAMILY; -} - -const char *lt_cpu_get_family_name() { - return STRINGIFY_MACRO(FAMILY) + 2; -} - -__attribute__((weak)) lt_cpu_model_t lt_cpu_get_model() { - return MCU; -} - -const char *lt_cpu_get_model_name() { - return STRINGIFY_MACRO(MCU); -} - -const char *lt_cpu_get_model_code() { - return STRINGIFY_MACRO(MCULC); -} - -__attribute__((weak)) uint32_t lt_cpu_get_unique_id() { - return lt_cpu_get_mac_id(); -} - -__attribute__((weak)) uint32_t lt_cpu_get_mac_id() { - uint8_t mac[6]; - lt_get_device_mac(mac); - return (mac[3] << 0) | (mac[4] << 8) | (mac[5] << 16); -} - -__attribute__((weak)) uint8_t lt_cpu_get_core_count() { - return 1; -} - -#if LT_HAS_FREERTOS -__attribute__((weak)) uint32_t lt_cpu_get_freq() { - return configCPU_CLOCK_HZ; -} -#endif - -uint32_t lt_cpu_get_freq_mhz() { - return lt_cpu_get_freq() / 1000000; -} - -#if LT_HAS_FREERTOS -__attribute__((weak)) uint32_t lt_cpu_get_cycle_count() { - return xTaskGetTickCount() * (configCPU_CLOCK_HZ / configTICK_RATE_HZ); -} -#endif - -/*_____ _ - | __ \ (_) - | | | | _____ ___ ___ ___ - | | | |/ _ \ \ / / |/ __/ _ \ - | |__| | __/\ V /| | (_| __/ - |_____/ \___| \_/ |_|\___\__*/ -static char *device_name = NULL; - -const char *lt_get_version() { - return LT_VERSION_STR; -} - -const char *lt_get_board_code() { - return LT_BOARD_STR; -} - -const char *lt_get_device_name() { - if (device_name) - return device_name; - uint32_t chip_id = lt_cpu_get_mac_id(); - uint8_t *id = (uint8_t *)&chip_id; - - const char *model = lt_cpu_get_model_code(); - uint8_t model_len = strlen(model); - device_name = (char *)malloc(3 + model_len + 1 + 6 + 1); - - sprintf(device_name, "LT-%s-%02x%02x%02x", model, id[0], id[1], id[2]); - return device_name; -} - -__attribute__((weak)) void lt_reboot() { - // The Watchdog Way - lt_wdt_enable(1L); - while (1) {} -} - -__attribute__((weak)) bool lt_reboot_wdt() { - if (!lt_wdt_enable(1L)) - return false; - while (1) {} -} - -__attribute__((weak)) bool lt_reboot_download_mode() { - return false; -} - -__attribute__((weak)) lt_reboot_reason_t lt_get_reboot_reason() { - return REBOOT_REASON_UNKNOWN; -} - -const char *lt_get_reboot_reason_name(lt_reboot_reason_t reason) { - if (!reason) - reason = lt_get_reboot_reason(); - switch (reason) { - case REBOOT_REASON_POWER: - return "Power-On"; - case REBOOT_REASON_BROWNOUT: - return "Brownout"; - case REBOOT_REASON_HARDWARE: - return "HW Reboot"; - case REBOOT_REASON_SOFTWARE: - return "SW Reboot"; - case REBOOT_REASON_WATCHDOG: - return "WDT Reset"; - case REBOOT_REASON_CRASH: - return "Crash"; - case REBOOT_REASON_SLEEP: - return "Sleep Wakeup"; - case REBOOT_REASON_DEBUGGER: - return "Debugger"; - default: - return "Unknown"; - } -} - -__attribute__((weak)) bool lt_set_debug_mode(lt_debug_mode_t mode) { - return false; -} - -__attribute__((weak)) void lt_gpio_recover() { - lt_set_debug_mode(DEBUG_MODE_OFF); -} - -/*______ _ _ - | ____| | | | - | |__ | | __ _ ___| |__ - | __| | |/ _` / __| '_ \ - | | | | (_| \__ \ | | | - |_| |_|\__,_|___/_| |*/ -__attribute__((weak)) uint32_t lt_flash_get_size() { - lt_flash_id_t id = lt_flash_get_id(); - if (id.chip_size_id >= 0x14 && id.chip_size_id <= 0x19) { - return (1 << id.chip_size_id); - } -#ifdef FLASH_LENGTH - return FLASH_LENGTH; -#else - return 0; -#endif -} - -bool lt_flash_erase(uint32_t offset, size_t length) { - return fal_partition_erase(fal_root_part, offset, length) >= 0; -} - -bool lt_flash_erase_block(uint32_t offset) { - return fal_partition_erase(fal_root_part, offset, 1) >= 0; -} - -uint32_t lt_flash_read(uint32_t offset, uint8_t *data, size_t length) { - int ret = fal_partition_read(fal_root_part, offset, data, length); - if (ret == -1) - return 0; - return ret; -} - -uint32_t lt_flash_write(uint32_t offset, const uint8_t *data, size_t length) { - int ret = fal_partition_write(fal_root_part, offset, data, length); - if (ret == -1) - return 0; - return ret; -} - -/*__ __ - | \/ | - | \ / | ___ _ __ ___ ___ _ __ _ _ - | |\/| |/ _ \ '_ ` _ \ / _ \| '__| | | | - | | | | __/ | | | | | (_) | | | |_| | - |_| |_|\___|_| |_| |_|\___/|_| \__, | - __/ | - |__*/ -#if LT_HAS_FREERTOS -__attribute__((weak)) uint32_t lt_heap_get_size() { - return configTOTAL_HEAP_SIZE; -} - -__attribute__((weak)) uint32_t lt_heap_get_free() { - return xPortGetFreeHeapSize(); -} - -__attribute__((weak)) uint32_t lt_heap_get_min_free() { - return xPortGetMinimumEverFreeHeapSize(); -} -#endif - -__attribute__((weak)) uint32_t lt_heap_get_max_alloc() { - return 0; -} - -/* ____ _______ - / __ \__ __|/\ - | | | | | | / \ - | | | | | | / /\ \ - | |__| | | |/ ____ \ - \____/ |_/_/ \*/ -bool lt_ota_can_rollback() { - if (lt_ota_get_type() != OTA_TYPE_DUAL) - return false; - uint8_t current = lt_ota_dual_get_current(); - return lt_ota_is_valid(current ^ 0b11); -} - -uf2_ota_scheme_t lt_ota_get_uf2_scheme() { - if (lt_ota_get_type() == OTA_TYPE_SINGLE) - return UF2_SCHEME_DEVICE_SINGLE; - uint8_t current = lt_ota_dual_get_current(); - // UF2_SCHEME_DEVICE_DUAL_1 or UF2_SCHEME_DEVICE_DUAL_2 - return (uf2_ota_scheme_t)(current ^ 0b11); -} - -/*_ _ _ _ _ - | | | | | (_) | - | | | | |_ _| |___ - | | | | __| | / __| - | |__| | |_| | \__ \ - \____/ \__|_|_|__*/ -void lt_rand_bytes(uint8_t *buf, size_t len) { - int *data = (int *)buf; - size_t i; - for (i = 0; len >= sizeof(int); len -= sizeof(int)) { - data[i++] = rand(); - } - if (len) { - int rem = rand(); - unsigned char *pRem = (unsigned char *)&rem; - memcpy(buf + i * sizeof(int), pRem, len); - } -} - -void hexdump(const uint8_t *buf, size_t len, uint32_t offset, uint8_t width) { - uint16_t pos = 0; - while (pos < len) { - // print hex offset - printf("%06lx ", offset + pos); - // calculate current line width - uint8_t lineWidth = MIN(width, len - pos); - // print hexadecimal representation - for (uint8_t i = 0; i < lineWidth; i++) { - if (i % 8 == 0) { - printf(" "); - } - printf("%02x ", buf[pos + i]); - } - // print ascii representation - printf(" |"); - for (uint8_t i = 0; i < lineWidth; i++) { - char c = buf[pos + i]; - putchar((c >= 0x20 && c <= 0x7f) ? c : '.'); - } - puts("|\r"); - pos += lineWidth; - } -} - -/*_ __ _ _ _ - \ \ / / | | | | | | - \ \ /\ / /_ _| |_ ___| |__ __| | ___ __ _ - \ \/ \/ / _` | __/ __| '_ \ / _` |/ _ \ / _` | - \ /\ / (_| | || (__| | | | (_| | (_) | (_| | - \/ \/ \__,_|\__\___|_| |_|\__,_|\___/ \__, | - __/ | - |___*/ -__attribute__((weak)) bool lt_wdt_enable(uint32_t timeout) { - return false; -} - -__attribute__((weak)) void lt_wdt_disable() {} - -__attribute__((weak)) void lt_wdt_feed() {} diff --git a/cores/common/base/lt_api.h b/cores/common/base/lt_api.h index 8564dbd..4bb98c8 100644 --- a/cores/common/base/lt_api.h +++ b/cores/common/base/lt_api.h @@ -3,7 +3,7 @@ #pragma once // This file collects all LibreTiny C API includes. -// The functions are implemented in lt_api.c, which is located +// The functions are implemented in api/*.c units, which are located // in the common core, and in the family cores. #ifdef __cplusplus diff --git a/cores/realtek-amb/arduino/src/lt_api.c b/cores/realtek-amb/arduino/src/api/lt_cpu.c similarity index 100% rename from cores/realtek-amb/arduino/src/lt_api.c rename to cores/realtek-amb/arduino/src/api/lt_cpu.c diff --git a/cores/realtek-amb/base/api/lt_flash.c b/cores/realtek-amb/base/api/lt_flash.c new file mode 100644 index 0000000..df7c409 --- /dev/null +++ b/cores/realtek-amb/base/api/lt_flash.c @@ -0,0 +1,14 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-05-23. */ + +#include +#include + +lt_flash_id_t lt_flash_get_id() { + lt_flash_id_t id; + uint8_t idBytes[3]; + flash_read_id(<_flash_obj, idBytes, 3); + id.manufacturer_id = idBytes[0]; + id.chip_id = idBytes[1]; + id.chip_size_id = idBytes[2]; + return id; +} diff --git a/cores/realtek-amb/base/api/lt_wdt.c b/cores/realtek-amb/base/api/lt_wdt.c new file mode 100644 index 0000000..4adac42 --- /dev/null +++ b/cores/realtek-amb/base/api/lt_wdt.c @@ -0,0 +1,18 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-05-23. */ + +#include +#include + +bool lt_wdt_enable(uint32_t timeout) { + watchdog_init(timeout); + watchdog_start(); + return true; +} + +void lt_wdt_disable() { + watchdog_stop(); +} + +void lt_wdt_feed() { + watchdog_refresh(); +} diff --git a/cores/realtek-amb/base/lt_api.c b/cores/realtek-amb/base/lt_api.c deleted file mode 100644 index 8e2ff6a..0000000 --- a/cores/realtek-amb/base/lt_api.c +++ /dev/null @@ -1,42 +0,0 @@ -/* Copyright (c) Kuba Szczodrzyński 2023-05-23. */ - -#include -#include - -/*______ _ _ - | ____| | | | - | |__ | | __ _ ___| |__ - | __| | |/ _` / __| '_ \ - | | | | (_| \__ \ | | | - |_| |_|\__,_|___/_| |*/ -lt_flash_id_t lt_flash_get_id() { - lt_flash_id_t id; - uint8_t idBytes[3]; - flash_read_id(<_flash_obj, idBytes, 3); - id.manufacturer_id = idBytes[0]; - id.chip_id = idBytes[1]; - id.chip_size_id = idBytes[2]; - return id; -} - -/*_ __ _ _ _ - \ \ / / | | | | | | - \ \ /\ / /_ _| |_ ___| |__ __| | ___ __ _ - \ \/ \/ / _` | __/ __| '_ \ / _` |/ _ \ / _` | - \ /\ / (_| | || (__| | | | (_| | (_) | (_| | - \/ \/ \__,_|\__\___|_| |_|\__,_|\___/ \__, | - __/ | - |___*/ -bool lt_wdt_enable(uint32_t timeout) { - watchdog_init(timeout); - watchdog_start(); - return true; -} - -void lt_wdt_disable() { - watchdog_stop(); -} - -void lt_wdt_feed() { - watchdog_refresh(); -} diff --git a/cores/realtek-ambz/base/api/lt_cpu.c b/cores/realtek-ambz/base/api/lt_cpu.c new file mode 100644 index 0000000..eb346cf --- /dev/null +++ b/cores/realtek-ambz/base/api/lt_cpu.c @@ -0,0 +1,34 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-02-27. */ + +#include +#include + +lt_cpu_model_t lt_cpu_get_model() { + uint8_t chipId; + EFUSE_OneByteReadROM(9902, 0xF8, &chipId, L25EOUTVOLTAGE); + return CPU_MODEL_ENUM(FAMILY, chipId); +} + +uint32_t lt_cpu_get_mac_id() { + uint32_t chipId = 0; + uint8_t *id = (uint8_t *)&chipId; + // 9902 was extracted from ROM disassembly, probably not needed + /* EFUSE_OneByteReadROM(9902, 0x3B, id + 0, L25EOUTVOLTAGE); + EFUSE_OneByteReadROM(9902, 0x3C, id + 1, L25EOUTVOLTAGE); + EFUSE_OneByteReadROM(9902, 0x3D, id + 2, L25EOUTVOLTAGE); */ + // new method, based on EFUSE logical map + uint8_t *efuse = (uint8_t *)malloc(512); + // TODO do what EFUSE_LogicalMapRead() does, and read only the used data + EFUSE_LogicalMap_Read(efuse); + memcpy(id, efuse + 0x11A + 3, 3); + free(efuse); + return chipId; +} + +const char *lt_cpu_get_core_type() { + return "ARM Cortex-M4F (ARMv7E-M)"; +} + +uint32_t lt_cpu_get_freq() { + return CPU_ClkGet(false); +} diff --git a/cores/realtek-ambz/base/api/lt_device.c b/cores/realtek-ambz/base/api/lt_device.c new file mode 100644 index 0000000..19511d7 --- /dev/null +++ b/cores/realtek-ambz/base/api/lt_device.c @@ -0,0 +1,39 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-02-27. */ + +#include +#include + +void lt_get_device_mac(uint8_t *mac) { + uint8_t *efuse = (uint8_t *)malloc(512); + EFUSE_LogicalMap_Read(efuse); + memcpy(mac, efuse + 0x11A, 6); + free(efuse); +} + +bool lt_reboot_download_mode() { + // mww 0x40000138 0x8 + HAL_WRITE32(SYSTEM_CTRL_BASE, REG_SYS_NORESET_FF, 0x08); + // reboot it the ugly way + sys_reset(); + while (1) {} + return true; +} + +bool lt_set_debug_mode(lt_debug_mode_t mode) { + uint32_t *swd; + switch (mode) { + case DEBUG_MODE_OFF: + sys_jtag_off(); + Pinmux_Config(PA_14, PINMUX_FUNCTION_GPIO); + Pinmux_Config(PA_15, PINMUX_FUNCTION_GPIO); + return true; + case DEBUG_MODE_SWD: + Pinmux_Config(PA_14, PINMUX_FUNCTION_SWD); + Pinmux_Config(PA_15, PINMUX_FUNCTION_SWD); + uint32_t *swd = (uint32_t *)0x400000A4; + *swd |= 0x1000; + return true; + default: + return false; + } +} diff --git a/cores/realtek-ambz/base/api/lt_flash.c b/cores/realtek-ambz/base/api/lt_flash.c new file mode 100644 index 0000000..7343879 --- /dev/null +++ b/cores/realtek-ambz/base/api/lt_flash.c @@ -0,0 +1,14 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-02-27. */ + +#include +#include + +lt_flash_id_t lt_flash_get_id() { + lt_flash_id_t id; + uint8_t idBytes[3]; + flash_read_id(NULL, idBytes, 3); + id.manufacturer_id = idBytes[0]; + id.chip_id = idBytes[1]; + id.chip_size_id = idBytes[2]; + return id; +} diff --git a/cores/realtek-ambz/base/api/lt_init.c b/cores/realtek-ambz/base/api/lt_init.c new file mode 100644 index 0000000..c9c0167 --- /dev/null +++ b/cores/realtek-ambz/base/api/lt_init.c @@ -0,0 +1,16 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-02-27. */ + +#include +#include + +extern uint32_t GlobalDebugEnable; +extern uint16_t GlobalDebugLevel; +extern uint8_t GlobalPrivateLog; +extern uint8_t lt_uart_port; + +void lt_init_family() { + // make the SDK less verbose by default + GlobalDebugEnable = 0; + GlobalPrivateLog = 0; + lt_uart_port = LT_UART_DEFAULT_PORT; +} diff --git a/cores/realtek-ambz/base/api/lt_mem.c b/cores/realtek-ambz/base/api/lt_mem.c new file mode 100644 index 0000000..c3e5a4a --- /dev/null +++ b/cores/realtek-ambz/base/api/lt_mem.c @@ -0,0 +1,8 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-02-27. */ + +#include +#include + +uint32_t lt_ram_get_size() { + return 256 * 1024; +} diff --git a/cores/realtek-ambz/base/api/lt_ota.c b/cores/realtek-ambz/base/api/lt_ota.c new file mode 100644 index 0000000..7ed5710 --- /dev/null +++ b/cores/realtek-ambz/base/api/lt_ota.c @@ -0,0 +1,78 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-02-27. */ + +#include +#include + +lt_ota_type_t lt_ota_get_type() { + return OTA_TYPE_DUAL; +} + +bool lt_ota_is_valid(uint8_t index) { + uint32_t offset; + switch (index) { + case 1: + offset = FLASH_OTA1_OFFSET; + break; + case 2: + offset = FLASH_OTA2_OFFSET; + break; + default: + return false; + } + uint8_t *address = (uint8_t *)(SPI_FLASH_BASE + offset); + return memcmp(address, "81958711", 8) == 0; +} + +uint8_t lt_ota_dual_get_current() { + // RTL8710B is XIP, so check the code offset in flash + uint32_t addr = (uint32_t)lt_log; + uint32_t offs = addr - SPI_FLASH_BASE; + return offs > FLASH_OTA2_OFFSET ? 2 : 1; +} + +uint8_t lt_ota_dual_get_stored() { + uint32_t *ota_address = (uint32_t *)0x8009000; + if (*ota_address == 0xFFFFFFFF) + return 1; + uint32_t ota_counter = *((uint32_t *)0x8009004); + // even count of zero-bits means OTA1, odd count means OTA2 + // this allows to switch OTA images by simply clearing next bits, + // without needing to erase the flash + uint8_t count = 0; + for (uint8_t i = 0; i < 32; i++) { + if ((ota_counter & (1 << i)) == 0) + count++; + } + return 1 + (count % 2); +} + +bool lt_ota_switch(bool revert) { + uint8_t current = lt_ota_dual_get_current(); + uint8_t stored = lt_ota_dual_get_stored(); + if ((current == stored) == revert) + return true; + + if (!lt_ota_is_valid(stored ^ 0b11)) + return false; + + // - read current OTA switch value from 0x9004 + // - reset OTA switch to 0xFFFFFFFE if it's 0x0 + // - else check first non-zero bit of OTA switch + // - write OTA switch with first non-zero bit cleared + + uint32_t value = HAL_READ32(SPI_FLASH_BASE, FLASH_SYSTEM_OFFSET + 4); + if (value == 0) { + uint8_t *system = (uint8_t *)malloc(64); + lt_flash_read(FLASH_SYSTEM_OFFSET, system, 64); + // reset OTA switch + ((uint32_t *)system)[1] = -2; + lt_flash_erase_block(FLASH_SYSTEM_OFFSET); + return lt_flash_write(FLASH_SYSTEM_OFFSET, system, 64); + } + + // clear first non-zero bit + value <<= 1; + // write OTA switch to flash + flash_write_word(NULL, FLASH_SYSTEM_OFFSET + 4, value); + return true; +} diff --git a/cores/realtek-ambz/base/lt_api.c b/cores/realtek-ambz/base/lt_api.c deleted file mode 100644 index 72131a5..0000000 --- a/cores/realtek-ambz/base/lt_api.c +++ /dev/null @@ -1,201 +0,0 @@ -/* Copyright (c) Kuba Szczodrzyński 2023-02-27. */ - -#include -#include - -extern uint32_t GlobalDebugEnable; -extern uint16_t GlobalDebugLevel; -extern uint8_t GlobalPrivateLog; -extern uint8_t lt_uart_port; - -void lt_init_family() { - // make the SDK less verbose by default - GlobalDebugEnable = 0; - GlobalPrivateLog = 0; - lt_uart_port = LT_UART_DEFAULT_PORT; -} - -/* _____ _____ _ _ - / ____| __ \| | | | - | | | |__) | | | | - | | | ___/| | | | - | |____| | | |__| | - \_____|_| \____*/ -lt_cpu_model_t lt_cpu_get_model() { - uint8_t chipId; - EFUSE_OneByteReadROM(9902, 0xF8, &chipId, L25EOUTVOLTAGE); - return CPU_MODEL_ENUM(FAMILY, chipId); -} - -uint32_t lt_cpu_get_mac_id() { - uint32_t chipId = 0; - uint8_t *id = (uint8_t *)&chipId; - // 9902 was extracted from ROM disassembly, probably not needed - /* EFUSE_OneByteReadROM(9902, 0x3B, id + 0, L25EOUTVOLTAGE); - EFUSE_OneByteReadROM(9902, 0x3C, id + 1, L25EOUTVOLTAGE); - EFUSE_OneByteReadROM(9902, 0x3D, id + 2, L25EOUTVOLTAGE); */ - // new method, based on EFUSE logical map - uint8_t *efuse = (uint8_t *)malloc(512); - // TODO do what EFUSE_LogicalMapRead() does, and read only the used data - EFUSE_LogicalMap_Read(efuse); - memcpy(id, efuse + 0x11A + 3, 3); - free(efuse); - return chipId; -} - -const char *lt_cpu_get_core_type() { - return "ARM Cortex-M4F (ARMv7E-M)"; -} - -uint32_t lt_cpu_get_freq() { - return CPU_ClkGet(false); -} - -/*_____ _ - | __ \ (_) - | | | | _____ ___ ___ ___ - | | | |/ _ \ \ / / |/ __/ _ \ - | |__| | __/\ V /| | (_| __/ - |_____/ \___| \_/ |_|\___\__*/ -void lt_get_device_mac(uint8_t *mac) { - uint8_t *efuse = (uint8_t *)malloc(512); - EFUSE_LogicalMap_Read(efuse); - memcpy(mac, efuse + 0x11A, 6); - free(efuse); -} - -bool lt_reboot_download_mode() { - // mww 0x40000138 0x8 - HAL_WRITE32(SYSTEM_CTRL_BASE, REG_SYS_NORESET_FF, 0x08); - // reboot it the ugly way - sys_reset(); - while (1) {} - return true; -} - -bool lt_set_debug_mode(lt_debug_mode_t mode) { - uint32_t *swd; - switch (mode) { - case DEBUG_MODE_OFF: - sys_jtag_off(); - Pinmux_Config(PA_14, PINMUX_FUNCTION_GPIO); - Pinmux_Config(PA_15, PINMUX_FUNCTION_GPIO); - return true; - case DEBUG_MODE_SWD: - Pinmux_Config(PA_14, PINMUX_FUNCTION_SWD); - Pinmux_Config(PA_15, PINMUX_FUNCTION_SWD); - uint32_t *swd = (uint32_t *)0x400000A4; - *swd |= 0x1000; - return true; - default: - return false; - } -} - -/*______ _ _ - | ____| | | | - | |__ | | __ _ ___| |__ - | __| | |/ _` / __| '_ \ - | | | | (_| \__ \ | | | - |_| |_|\__,_|___/_| |*/ -lt_flash_id_t lt_flash_get_id() { - lt_flash_id_t id; - uint8_t idBytes[3]; - flash_read_id(NULL, idBytes, 3); - id.manufacturer_id = idBytes[0]; - id.chip_id = idBytes[1]; - id.chip_size_id = idBytes[2]; - return id; -} - -/*__ __ - | \/ | - | \ / | ___ _ __ ___ ___ _ __ _ _ - | |\/| |/ _ \ '_ ` _ \ / _ \| '__| | | | - | | | | __/ | | | | | (_) | | | |_| | - |_| |_|\___|_| |_| |_|\___/|_| \__, | - __/ | - |__*/ -uint32_t lt_ram_get_size() { - return 256 * 1024; -} - -/* ____ _______ - / __ \__ __|/\ - | | | | | | / \ - | | | | | | / /\ \ - | |__| | | |/ ____ \ - \____/ |_/_/ \*/ -lt_ota_type_t lt_ota_get_type() { - return OTA_TYPE_DUAL; -} - -bool lt_ota_is_valid(uint8_t index) { - uint32_t offset; - switch (index) { - case 1: - offset = FLASH_OTA1_OFFSET; - break; - case 2: - offset = FLASH_OTA2_OFFSET; - break; - default: - return false; - } - uint8_t *address = (uint8_t *)(SPI_FLASH_BASE + offset); - return memcmp(address, "81958711", 8) == 0; -} - -uint8_t lt_ota_dual_get_current() { - // RTL8710B is XIP, so check the code offset in flash - uint32_t addr = (uint32_t)lt_log; - uint32_t offs = addr - SPI_FLASH_BASE; - return offs > FLASH_OTA2_OFFSET ? 2 : 1; -} - -uint8_t lt_ota_dual_get_stored() { - uint32_t *ota_address = (uint32_t *)0x8009000; - if (*ota_address == 0xFFFFFFFF) - return 1; - uint32_t ota_counter = *((uint32_t *)0x8009004); - // even count of zero-bits means OTA1, odd count means OTA2 - // this allows to switch OTA images by simply clearing next bits, - // without needing to erase the flash - uint8_t count = 0; - for (uint8_t i = 0; i < 32; i++) { - if ((ota_counter & (1 << i)) == 0) - count++; - } - return 1 + (count % 2); -} - -bool lt_ota_switch(bool revert) { - uint8_t current = lt_ota_dual_get_current(); - uint8_t stored = lt_ota_dual_get_stored(); - if ((current == stored) == revert) - return true; - - if (!lt_ota_is_valid(stored ^ 0b11)) - return false; - - // - read current OTA switch value from 0x9004 - // - reset OTA switch to 0xFFFFFFFE if it's 0x0 - // - else check first non-zero bit of OTA switch - // - write OTA switch with first non-zero bit cleared - - uint32_t value = HAL_READ32(SPI_FLASH_BASE, FLASH_SYSTEM_OFFSET + 4); - if (value == 0) { - uint8_t *system = (uint8_t *)malloc(64); - lt_flash_read(FLASH_SYSTEM_OFFSET, system, 64); - // reset OTA switch - ((uint32_t *)system)[1] = -2; - lt_flash_erase_block(FLASH_SYSTEM_OFFSET); - return lt_flash_write(FLASH_SYSTEM_OFFSET, system, 64); - } - - // clear first non-zero bit - value <<= 1; - // write OTA switch to flash - flash_write_word(NULL, FLASH_SYSTEM_OFFSET + 4, value); - return true; -} diff --git a/cores/realtek-ambz2/base/api/lt_cpu.c b/cores/realtek-ambz2/base/api/lt_cpu.c new file mode 100644 index 0000000..7f9c1ef --- /dev/null +++ b/cores/realtek-ambz2/base/api/lt_cpu.c @@ -0,0 +1,21 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-05-22. */ + +#include +#include + +lt_cpu_model_t lt_cpu_get_model() { + uint32_t *addr = (uint32_t *)0x40000038; + uint8_t flash_mode = (addr[0] >> 5) & 0b11; + uint32_t chip_id = 0; + hal_get_chip_id(&chip_id); + chip_id <<= 2; + return CPU_MODEL_ENUM(FAMILY, (chip_id & 0xFF) | flash_mode); +} + +const char *lt_cpu_get_core_type() { + return "ARM Cortex-M33 (ARMv8-M)"; +} + +uint32_t lt_cpu_get_freq() { + return hal_syson_query_sys_clk(); +} diff --git a/cores/realtek-ambz2/base/api/lt_device.c b/cores/realtek-ambz2/base/api/lt_device.c new file mode 100644 index 0000000..5cfff7e --- /dev/null +++ b/cores/realtek-ambz2/base/api/lt_device.c @@ -0,0 +1,61 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-05-22. */ + +#include +#include + +void lt_get_device_mac(uint8_t *mac) { + efuse_logical_read(0x11A, 6, mac); +} + +void lt_reboot() { + sys_cpu_reset(); + while (1) {} +} + +bool lt_reboot_download_mode() { + sys_uart_download_mode(); + while (1) {} + return true; +} + +lt_reboot_reason_t lt_get_reboot_reason() { + hal_reset_reason_t reason = -1; + rtl8710c_reset_reason_get(&reason); + switch (reason) { + case HAL_RESET_REASON_POWER_ON: + return REBOOT_REASON_POWER; + case HAL_RESET_REASON_SOFTWARE: + return REBOOT_REASON_SOFTWARE; + case HAL_RESET_REASON_WATCHDOG: + return REBOOT_REASON_WATCHDOG; + case HAL_RESET_REASON_JTAG: + return REBOOT_REASON_DEBUGGER; + default: + return REBOOT_REASON_UNKNOWN; + } +} + +bool lt_set_debug_mode(lt_debug_mode_t mode) { + switch (mode) { + case DEBUG_MODE_OFF: + if (hal_misc_jtag_pin_ctrl(0) != HAL_OK) + return false; + if (hal_misc_swd_pin_ctrl(0) != HAL_OK) + return false; + return true; + case DEBUG_MODE_JTAG: + if (hal_misc_swd_pin_ctrl(0) != HAL_OK) + return false; + if (hal_misc_jtag_pin_ctrl(1) != HAL_OK) + return false; + return true; + case DEBUG_MODE_SWD: + if (hal_misc_jtag_pin_ctrl(0) != HAL_OK) + return false; + if (hal_misc_swd_pin_ctrl(1) != HAL_OK) + return false; + return true; + default: + return false; + } +} diff --git a/cores/realtek-ambz2/base/api/lt_init.c b/cores/realtek-ambz2/base/api/lt_init.c new file mode 100644 index 0000000..f83ce88 --- /dev/null +++ b/cores/realtek-ambz2/base/api/lt_init.c @@ -0,0 +1,14 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-05-22. */ + +#include +#include + +extern uint8_t lt_uart_port; + +void lt_init_family() { + // make the SDK less verbose by default + ConfigDebugErr = _DBG_MISC_ | _DBG_FAULT_ | _DBG_BOOT_; + ConfigDebugWarn = 0; + ConfigDebugInfo = 0; + lt_uart_port = LT_UART_DEFAULT_PORT; +} diff --git a/cores/realtek-ambz2/base/api/lt_mem.c b/cores/realtek-ambz2/base/api/lt_mem.c new file mode 100644 index 0000000..b079d4c --- /dev/null +++ b/cores/realtek-ambz2/base/api/lt_mem.c @@ -0,0 +1,8 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-05-22. */ + +#include +#include + +uint32_t lt_ram_get_size() { + return 256 * 1024; +} diff --git a/cores/realtek-ambz2/base/api/lt_ota.c b/cores/realtek-ambz2/base/api/lt_ota.c new file mode 100644 index 0000000..d96af85 --- /dev/null +++ b/cores/realtek-ambz2/base/api/lt_ota.c @@ -0,0 +1,24 @@ +/* Copyright (c) Kuba Szczodrzyński 2023-05-22. */ + +#include +#include + +lt_ota_type_t lt_ota_get_type() { + return OTA_TYPE_DUAL; +} + +bool lt_ota_is_valid(uint8_t index) { + return false; +} + +uint8_t lt_ota_dual_get_current() { + return 0; +} + +uint8_t lt_ota_dual_get_stored() { + return 0; +} + +bool lt_ota_switch(bool revert) { + return false; +} diff --git a/cores/realtek-ambz2/base/lt_api.c b/cores/realtek-ambz2/base/lt_api.c deleted file mode 100644 index 83c5f2d..0000000 --- a/cores/realtek-ambz2/base/lt_api.c +++ /dev/null @@ -1,138 +0,0 @@ -/* Copyright (c) Kuba Szczodrzyński 2023-05-22. */ - -#include -#include - -extern uint8_t lt_uart_port; - -void lt_init_family() { - // make the SDK less verbose by default - ConfigDebugErr = _DBG_MISC_ | _DBG_FAULT_ | _DBG_BOOT_; - ConfigDebugWarn = 0; - ConfigDebugInfo = 0; - lt_uart_port = LT_UART_DEFAULT_PORT; -} - -/* _____ _____ _ _ - / ____| __ \| | | | - | | | |__) | | | | - | | | ___/| | | | - | |____| | | |__| | - \_____|_| \____*/ -lt_cpu_model_t lt_cpu_get_model() { - uint32_t *addr = (uint32_t *)0x40000038; - uint8_t flash_mode = (addr[0] >> 5) & 0b11; - uint32_t chip_id = 0; - hal_get_chip_id(&chip_id); - chip_id <<= 2; - return CPU_MODEL_ENUM(FAMILY, (chip_id & 0xFF) | flash_mode); -} - -const char *lt_cpu_get_core_type() { - return "ARM Cortex-M33 (ARMv8-M)"; -} - -uint32_t lt_cpu_get_freq() { - return hal_syson_query_sys_clk(); -} - -/*_____ _ - | __ \ (_) - | | | | _____ ___ ___ ___ - | | | |/ _ \ \ / / |/ __/ _ \ - | |__| | __/\ V /| | (_| __/ - |_____/ \___| \_/ |_|\___\__*/ -void lt_get_device_mac(uint8_t *mac) { - efuse_logical_read(0x11A, 6, mac); -} - -void lt_reboot() { - sys_cpu_reset(); - while (1) {} -} - -bool lt_reboot_download_mode() { - sys_uart_download_mode(); - while (1) {} - return true; -} - -lt_reboot_reason_t lt_get_reboot_reason() { - hal_reset_reason_t reason = -1; - rtl8710c_reset_reason_get(&reason); - switch (reason) { - case HAL_RESET_REASON_POWER_ON: - return REBOOT_REASON_POWER; - case HAL_RESET_REASON_SOFTWARE: - return REBOOT_REASON_SOFTWARE; - case HAL_RESET_REASON_WATCHDOG: - return REBOOT_REASON_WATCHDOG; - case HAL_RESET_REASON_JTAG: - return REBOOT_REASON_DEBUGGER; - default: - return REBOOT_REASON_UNKNOWN; - } -} - -bool lt_set_debug_mode(lt_debug_mode_t mode) { - switch (mode) { - case DEBUG_MODE_OFF: - if (hal_misc_jtag_pin_ctrl(0) != HAL_OK) - return false; - if (hal_misc_swd_pin_ctrl(0) != HAL_OK) - return false; - return true; - case DEBUG_MODE_JTAG: - if (hal_misc_swd_pin_ctrl(0) != HAL_OK) - return false; - if (hal_misc_jtag_pin_ctrl(1) != HAL_OK) - return false; - return true; - case DEBUG_MODE_SWD: - if (hal_misc_jtag_pin_ctrl(0) != HAL_OK) - return false; - if (hal_misc_swd_pin_ctrl(1) != HAL_OK) - return false; - return true; - default: - return false; - } -} - -/*__ __ - | \/ | - | \ / | ___ _ __ ___ ___ _ __ _ _ - | |\/| |/ _ \ '_ ` _ \ / _ \| '__| | | | - | | | | __/ | | | | | (_) | | | |_| | - |_| |_|\___|_| |_| |_|\___/|_| \__, | - __/ | - |__*/ -uint32_t lt_ram_get_size() { - return 256 * 1024; -} - -/* ____ _______ - / __ \__ __|/\ - | | | | | | / \ - | | | | | | / /\ \ - | |__| | | |/ ____ \ - \____/ |_/_/ \*/ -lt_ota_type_t lt_ota_get_type() { - return OTA_TYPE_DUAL; -} - -bool lt_ota_is_valid(uint8_t index) { - return false; -} - -uint8_t lt_ota_dual_get_current() { - return 0; -} - -uint8_t lt_ota_dual_get_stored() { - return 0; -} - -bool lt_ota_switch(bool revert) { - return false; -} diff --git a/docs/contrib/lt-api.md b/docs/contrib/lt-api.md new file mode 100644 index 0000000..44e7032 --- /dev/null +++ b/docs/contrib/lt-api.md @@ -0,0 +1,13 @@ +# API functions guide + +The [LibreTiny C API](../dev/lt-api.md) functions are split between three types: common, weak and family. + +- Common functions are implemented in the base, common core and are the same between all families. +- Weak functions are provided in the common core, but can (and sometimes should) be overridden by family cores. They sometimes provide usable default implementations (which *can* be overriden to provide e.g. a better way to do something), otherwise they're empty (e.g. if a family doesn't support such a feature). +- Family functions are not provided in the common core and have to be implemented in the family core. + +A quick outline of all available functions and their types: + +{% + include-markdown "lt-api-functions.md" +%} diff --git a/docs/contrib/porting.md b/docs/contrib/porting.md index 61cc4d8..3a11fc9 100644 --- a/docs/contrib/porting.md +++ b/docs/contrib/porting.md @@ -31,6 +31,7 @@ Here's what has to be done to make that work: 5. Add base core code. - `lt_defs.h`, `lt_family.h` and `lt_api.c` files need to be created, and initialized with (even empty) functions and definitions. + - The list of family functions can be found [here](lt-api.md). - Make the SDK call `lt_main()` as the entrypoint. If needed, use fixups. 6. Write a binary manipulation tool. diff --git a/docs/script.js b/docs/script.js new file mode 100644 index 0000000..2845e59 --- /dev/null +++ b/docs/script.js @@ -0,0 +1,6 @@ +document$.subscribe(function () { + var tables = document.querySelectorAll("article table:not([class])") + tables.forEach(function (table) { + new Tablesort(table) + }) +}) diff --git a/docs/scripts/build_json.py b/docs/scripts/build_json.py index 924ed82..f3b1cd6 100644 --- a/docs/scripts/build_json.py +++ b/docs/scripts/build_json.py @@ -1,7 +1,7 @@ import json from ltchiptool import Board -from update_docs import board_obj_sort +from write_boards import board_obj_sort boards = map(Board, Board.get_list()) boards = list(sorted(boards, key=board_obj_sort)) diff --git a/docs/scripts/write_apis.py b/docs/scripts/write_apis.py new file mode 100644 index 0000000..9346cbd --- /dev/null +++ b/docs/scripts/write_apis.py @@ -0,0 +1,125 @@ +# Copyright (c) Kuba Szczodrzyński 2023-06-22. + +import re +from glob import glob +from os.path import dirname, join + +import colorama +from colorama import Fore, Style +from markdown import Markdown + +if __name__ == "__main__": + colorama.init() + + api_path = join(dirname(__file__), "..", "..", "cores/common/base/api/lt_*.*") + out_path = join(dirname(__file__), "..", "contrib") + + declaration = "" + implementation = "" + + for file in glob(api_path): + with open(file, "r") as f: + data = f.read() + if file.endswith(".h"): + declaration += data + elif file.endswith(".c"): + implementation += data + + block_comment_regex = r"\/\*[\d\D]+?\*\/" + line_comment_regex = r"\/\/.+?$" + macro_regex = r"#(?:[^\n\\]|\\\n)+$" + line_regex = r"\n+" + declaration = re.sub(block_comment_regex, "", declaration) + declaration = re.sub(line_comment_regex, "", declaration, flags=re.MULTILINE) + declaration = re.sub(macro_regex, "", declaration, flags=re.MULTILINE) + declaration = re.sub(line_regex, "\n", declaration) + implementation = re.sub(block_comment_regex, "", implementation) + implementation = re.sub(line_comment_regex, "", implementation, flags=re.MULTILINE) + implementation = re.sub(macro_regex, "", implementation, flags=re.MULTILINE) + implementation = re.sub(line_regex, "\n", implementation) + + declaration_regex = r"^([\d\w\s]+ \*?)([\S]+?)\(.*?\);$" + implementation_regex = r"^(__attribute__\(\(weak\)\) )?([\w\d* ]+?)([\w\d]+)\(.+?{" + + function_types = {} + decl_functions = set() + impl_functions = set() + weak_functions = set() + + for match in re.finditer( + pattern=declaration_regex, + string=declaration, + flags=re.DOTALL | re.MULTILINE, + ): + function_type = match[1].strip() + function_name = match[2].strip() + + if function_types.get(function_name, function_type) != function_type: + print( + Fore.YELLOW + + "WARNING: Wrong return type: " + + f"'{function_types[function_name]} {function_name}'" + + f"vs '{function_type} {function_name}'" + + Style.RESET_ALL + ) + + function_types[function_name] = function_type + decl_functions.add(function_name) + + for match in re.finditer( + pattern=implementation_regex, + string=implementation, + flags=re.DOTALL | re.MULTILINE, + ): + is_weak = match[1] + function_type = match[2].strip() + function_name = match[3].strip() + function_types[function_name] = function_type + + if function_types.get(function_name, function_type) != function_type: + print( + Fore.YELLOW + + "WARNING: Wrong return type: " + + f"'{function_types[function_name]} {function_name}'" + + f"vs '{function_type} {function_name}'" + + Style.RESET_ALL + ) + + if is_weak: + weak_functions.add(function_name) + else: + impl_functions.add(function_name) + + +common_functions = impl_functions.union(weak_functions) +family_functions = decl_functions - common_functions +undecl_functions = common_functions - decl_functions +if undecl_functions: + print(Fore.RED + "ERROR: Undeclared functions: " + ", ".join(undecl_functions)) + exit(1) + +md = Markdown(out_path, "lt-api-functions") +header = [ + "Type", + "Function", + "Common", + "Weak", + "Family", +] +rows = [] + +for function in ( + sorted(family_functions) + sorted(weak_functions) + sorted(impl_functions) +): + rows.append( + [ + f"`{function_types[function]}`", + f"{function}()", + "✔️" if function in impl_functions else "", + "✔️" if function in weak_functions else "", + "✔️" if function not in common_functions else "", + ] + ) + +md.add_table(header, *rows) +md.write() diff --git a/docs/scripts/update_docs.py b/docs/scripts/write_boards.py similarity index 100% rename from docs/scripts/update_docs.py rename to docs/scripts/write_boards.py diff --git a/mkdocs.yml b/mkdocs.yml index 0329105..39d3ba5 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -39,6 +39,10 @@ plugins: extra_css: - docs/style.css +extra_javascript: + - https://unpkg.com/tablesort@5.3.0/dist/tablesort.min.js + - docs/script.js + markdown_extensions: - md_in_html - admonition From 39df2e7b547c08d538a9ac2091e4e38dc7ca1259 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 13 Jul 2023 12:06:37 +0200 Subject: [PATCH 29/31] [core] Move C types to API units --- cores/common/base/api/lt_device.h | 35 ++++++++++++++++++++++ cores/common/base/api/lt_flash.h | 9 ++++++ cores/common/base/api/lt_ota.h | 9 ++++++ cores/common/base/lt_types.h | 50 ------------------------------- 4 files changed, 53 insertions(+), 50 deletions(-) diff --git a/cores/common/base/api/lt_device.h b/cores/common/base/api/lt_device.h index ae4d626..5074c28 100644 --- a/cores/common/base/api/lt_device.h +++ b/cores/common/base/api/lt_device.h @@ -4,6 +4,41 @@ #include +#define RESET_REASON_UNKNOWN REBOOT_REASON_UNKNOWN +#define RESET_REASON_POWER REBOOT_REASON_POWER +#define RESET_REASON_BROWNOUT REBOOT_REASON_BROWNOUT +#define RESET_REASON_HARDWARE REBOOT_REASON_HARDWARE +#define RESET_REASON_SOFTWARE REBOOT_REASON_SOFTWARE +#define RESET_REASON_WATCHDOG REBOOT_REASON_WATCHDOG +#define RESET_REASON_CRASH REBOOT_REASON_CRASH +#define RESET_REASON_SLEEP REBOOT_REASON_SLEEP +#define RESET_REASON_MAX REBOOT_REASON_MAX + +/** + * @brief Reset reason enumeration. + */ +typedef enum { + REBOOT_REASON_UNKNOWN = 1, + REBOOT_REASON_POWER = 2, + REBOOT_REASON_BROWNOUT = 3, + REBOOT_REASON_HARDWARE = 4, + REBOOT_REASON_SOFTWARE = 5, + REBOOT_REASON_WATCHDOG = 6, + REBOOT_REASON_CRASH = 7, + REBOOT_REASON_SLEEP = 8, + REBOOT_REASON_DEBUGGER = 9, + REBOOT_REASON_MAX = 10, +} lt_reboot_reason_t; + +/** + * @brief Debugging mode enumeration. + */ +typedef enum { + DEBUG_MODE_OFF = 0, + DEBUG_MODE_JTAG = 1, + DEBUG_MODE_SWD = 2, +} lt_debug_mode_t; + /** * @brief Get LibreTiny version string. */ diff --git a/cores/common/base/api/lt_flash.h b/cores/common/base/api/lt_flash.h index 549d6cb..6aba883 100644 --- a/cores/common/base/api/lt_flash.h +++ b/cores/common/base/api/lt_flash.h @@ -4,6 +4,15 @@ #include +/** + * @brief Flash chip ID structure. + */ +typedef struct { + uint8_t manufacturer_id; + uint8_t chip_id; + uint8_t chip_size_id; +} lt_flash_id_t; + /** * @brief Read flash chip ID and return a lt_flash_id_t struct. */ diff --git a/cores/common/base/api/lt_ota.h b/cores/common/base/api/lt_ota.h index ef0ffca..864fb2b 100644 --- a/cores/common/base/api/lt_ota.h +++ b/cores/common/base/api/lt_ota.h @@ -5,6 +5,15 @@ #include #include +/** + * @brief Chip's OTA type enumeration. + */ +typedef enum { + OTA_TYPE_SINGLE = 0, + OTA_TYPE_DUAL = 1, + OTA_TYPE_FILE = 2, +} lt_ota_type_t; + /** * @brief Get OTA type of the device's chip. */ diff --git a/cores/common/base/lt_types.h b/cores/common/base/lt_types.h index acf7b62..a8a4870 100644 --- a/cores/common/base/lt_types.h +++ b/cores/common/base/lt_types.h @@ -7,16 +7,6 @@ #define CPU_MODEL(family, chip_id) (((family >> 24) << 8) | chip_id) #define CPU_MODEL_ENUM(family, chip_id) (lt_cpu_model_t) CPU_MODEL(family, chip_id) -#define RESET_REASON_UNKNOWN REBOOT_REASON_UNKNOWN -#define RESET_REASON_POWER REBOOT_REASON_POWER -#define RESET_REASON_BROWNOUT REBOOT_REASON_BROWNOUT -#define RESET_REASON_HARDWARE REBOOT_REASON_HARDWARE -#define RESET_REASON_SOFTWARE REBOOT_REASON_SOFTWARE -#define RESET_REASON_WATCHDOG REBOOT_REASON_WATCHDOG -#define RESET_REASON_CRASH REBOOT_REASON_CRASH -#define RESET_REASON_SLEEP REBOOT_REASON_SLEEP -#define RESET_REASON_MAX REBOOT_REASON_MAX - typedef enum { F_RTL8710A = 0x9FFFD543, // Realtek Ameba1 F_RTL8710B = 0x22E0D6FC, // Realtek AmebaZ (realtek-ambz) @@ -55,43 +45,3 @@ typedef enum { BK7231S = BK7231T, BK7231U = BK7231T, } lt_cpu_model_t; - -/** - * @brief Reset reason enumeration. - */ -typedef enum { - REBOOT_REASON_UNKNOWN = 1, - REBOOT_REASON_POWER = 2, - REBOOT_REASON_BROWNOUT = 3, - REBOOT_REASON_HARDWARE = 4, - REBOOT_REASON_SOFTWARE = 5, - REBOOT_REASON_WATCHDOG = 6, - REBOOT_REASON_CRASH = 7, - REBOOT_REASON_SLEEP = 8, - REBOOT_REASON_DEBUGGER = 9, - REBOOT_REASON_MAX = 10, -} lt_reboot_reason_t; - -/** - * @brief Flash chip ID structure. - */ -typedef struct { - uint8_t manufacturer_id; - uint8_t chip_id; - uint8_t chip_size_id; -} lt_flash_id_t; - -/** - * @brief Chip's OTA type enumeration. - */ -typedef enum { - OTA_TYPE_SINGLE = 0, - OTA_TYPE_DUAL = 1, - OTA_TYPE_FILE = 2, -} lt_ota_type_t; - -typedef enum { - DEBUG_MODE_OFF = 0, - DEBUG_MODE_JTAG = 1, - DEBUG_MODE_SWD = 2, -} lt_debug_mode_t; From a3bbdf1c16cfb52aea13f0aa607907a9cfe4c61c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 13 Jul 2023 12:15:48 +0200 Subject: [PATCH 30/31] [core] Migrate to uf2ota v5.0.0, refactor OTA API --- builder/frameworks/base.py | 2 +- .../libraries/common/Update/Update.cpp | 268 +++++++---------- .../arduino/libraries/common/Update/Update.h | 208 +++++++------ .../libraries/common/Update/UpdateUtil.cpp | 283 ++++++++---------- cores/common/base/api/lt_ota.c | 140 +++++++++ cores/common/base/api/lt_ota.h | 66 ++++ cores/common/base/lt_logger.c | 9 +- docs/scripts/write_apis.py | 6 +- external-libs.json | 8 +- platform.json | 10 +- 10 files changed, 575 insertions(+), 425 deletions(-) diff --git a/builder/frameworks/base.py b/builder/frameworks/base.py index fd8a886..c9317c2 100644 --- a/builder/frameworks/base.py +++ b/builder/frameworks/base.py @@ -95,7 +95,7 @@ for f in family.inheritance: env.Prepend(CPPDEFINES=[(f"LT_{f.code.upper()}", "1")]) # Sources - external libraries -queue.AddExternalLibrary("ltchiptool") # uf2ota source code +queue.AddExternalLibrary("uf2ota") queue.AddExternalLibrary("flashdb") queue.AddExternalLibrary("printf") diff --git a/cores/common/arduino/libraries/common/Update/Update.cpp b/cores/common/arduino/libraries/common/Update/Update.cpp index 13f83de..6a2c6cd 100644 --- a/cores/common/arduino/libraries/common/Update/Update.cpp +++ b/cores/common/arduino/libraries/common/Update/Update.cpp @@ -2,9 +2,25 @@ #include "Update.h" -UpdateClass::UpdateClass() : ctx(NULL), info(NULL), buf(NULL) { - cleanup(); -} +static const UpdateError errorMap[] = { + UPDATE_ERROR_OK, /* UF2_ERR_OK - no error */ + UPDATE_ERROR_OK, /* UF2_ERR_IGNORE - block should be ignored */ + UPDATE_ERROR_MAGIC_BYTE, /* UF2_ERR_MAGIC - wrong magic numbers */ + UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_FAMILY - family ID mismatched */ + UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_NOT_HEADER - block is not a header */ + UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_OTA_VER - unknown/invalid OTA format version */ + UPDATE_ERROR_MAGIC_BYTE, /* UF2_ERR_OTA_WRONG - no data for current OTA scheme */ + UPDATE_ERROR_NO_PARTITION, /* UF2_ERR_PART_404 - no partition with that name */ + UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_PART_INVALID - invalid partition info tag */ + UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_PART_UNSET - attempted to write without target partition */ + UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_DATA_TOO_LONG - data too long - tags won't fit */ + UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_SEQ_MISMATCH - sequence number mismatched */ + UPDATE_ERROR_ERASE, /* UF2_ERR_ERASE_FAILED - erasing flash failed */ + UPDATE_ERROR_WRITE, /* UF2_ERR_WRITE_FAILED - writing to flash failed */ + UPDATE_ERROR_WRITE, /* UF2_ERR_WRITE_LENGTH - wrote fewer data than requested */ + UPDATE_ERROR_WRITE, /* UF2_ERR_WRITE_PROTECT - target area is write-protected */ + UPDATE_ERROR_WRITE, /* UF2_ERR_ALLOC_FAILED - dynamic memory allocation failed */ +}; /** * @brief Initialize the update process. @@ -13,55 +29,88 @@ UpdateClass::UpdateClass() : ctx(NULL), info(NULL), buf(NULL) { * @param command must be U_FLASH * @return false if parameters are invalid or update is running, true otherwise */ -bool UpdateClass::begin(size_t size, int command, int unused2, uint8_t unused3, const char *unused4) { - if (ctx) - return false; - cleanup(); - - LT_DM(OTA, "begin(%u, ...) / OTA curr: %u, scheme: %u", size, lt_ota_dual_get_current(), lt_ota_get_uf2_scheme()); - - ctx = uf2_ctx_init(lt_ota_get_uf2_scheme(), FAMILY); - info = uf2_info_init(); - - if (!size) { - cleanup(UPDATE_ERROR_SIZE); +bool UpdateClass::begin( + size_t size, + int command, + __attribute__((unused)) int ledPin, + __attribute__((unused)) uint8_t ledOn, + __attribute__((unused)) const char *label +) { + if (this->ctx) { + return false; + } + this->clearError(); + if (size == 0) { + this->errArd = UPDATE_ERROR_SIZE; return false; } - if (command != U_FLASH) { - cleanup(UPDATE_ERROR_BAD_ARGUMENT); + this->errArd = UPDATE_ERROR_BAD_ARGUMENT; return false; } + if (size == UPDATE_SIZE_UNKNOWN) { + size = 0; + } - bytesTotal = size; + this->ctx = static_cast(malloc(sizeof(lt_ota_ctx_t))); + lt_ota_begin(this->ctx, size); + this->ctx->callback = reinterpret_cast(progressHandler); + this->ctx->callback_param = this; return true; } /** * @brief Finalize the update process. Check for errors and update completion, then activate the new firmware image. * - * @param evenIfRemaining no idea - * @return false in case of errors or no update running, true otherwise + * @param evenIfRemaining don't raise errors if still in progress + * @return false in case of errors or no update running; true otherwise */ bool UpdateClass::end(bool evenIfRemaining) { - if (hasError() || !ctx) - // false if not running + if (!this->ctx) return false; - if (!isFinished() && !evenIfRemaining) { + // update is running or finished; cleanup and end it + if (!isFinished() && !evenIfRemaining) // abort if not finished - cleanup(UPDATE_ERROR_ABORT); - return false; - } - // TODO what is evenIfRemaining for? - // try to activate the second OTA - if (!lt_ota_switch(/* revert= */ false)) { - cleanup(UPDATE_ERROR_ACTIVATE); - return false; + this->errArd = UPDATE_ERROR_ABORT; + + this->cleanup(/* clearError= */ evenIfRemaining); + return !this->hasError(); +} + +/** + * @brief Cleanup (free) the update context. + * Try activating the firmware if possible, set local error codes. + * + * @param clearError assume successful finish after correct activation + */ +void UpdateClass::cleanup(bool clearError) { + if (!this->ctx) + return; + + if (!lt_ota_end(this->ctx)) { + // activating firmware failed + this->errArd = UPDATE_ERROR_ACTIVATE; + this->errUf2 = UF2_ERR_OK; + } else if (clearError) { + // successful finish and activation, clear error codes + this->clearError(); + } else if (this->ctx->error > UF2_ERR_IGNORE) { + // make error code based on UF2OTA code + this->errArd = errorMap[this->ctx->error]; + this->errUf2 = this->ctx->error; + } else { + // only keep Arduino error code (set by the caller) + this->errUf2 = UF2_ERR_OK; } - cleanup(); - return true; +#if LT_DEBUG_OTA + if (this->hasError()) + this->printErrorContext(); +#endif + + free(this->ctx); + this->ctx = nullptr; } /** @@ -69,60 +118,44 @@ bool UpdateClass::end(bool evenIfRemaining) { * * It's advised to write in 512-byte chunks (or its multiples). * - * @param data - * @param len - * @return size_t + * @param data chunk of data + * @param len length of the chunk + * @return size_t amount of bytes written */ -size_t UpdateClass::write(uint8_t *data, size_t len) { - size_t written = 0; - if (hasError() || !ctx) - // 0 if not running +size_t UpdateClass::write(const uint8_t *data, size_t len) { + if (!this->ctx) return 0; - LT_VM(OTA, "write(%u) / buf %u/512", len, bufSize()); - - /* while (buf == bufPos && len >= UF2_BLOCK_SIZE) { - // buffer empty and entire block is in data - if (!tryWriteData(data, UF2_BLOCK_SIZE)) { - // returns 0 if data contains an invalid block - return written; - } - data += UF2_BLOCK_SIZE; - len -= UF2_BLOCK_SIZE; - written += UF2_BLOCK_SIZE; - } */ - - // write until buffer space is available - uint16_t toWrite; // 1..512 - while (len && (toWrite = min(len, bufLeft()))) { - tryWriteData(data, toWrite); - if (hasError()) { - // return on errors - printErrorContext2(data, toWrite); - return written; - } - data += toWrite; - len -= toWrite; - written += toWrite; - } + size_t written = lt_ota_write(ctx, data, len); + if (written != len) + this->cleanup(/* clearError= */ false); return written; } +/** + * @brief Write all data remaining in the given stream. + * + * If the stream doesn't produce any data within UPDATE_TIMEOUT_MS, + * the update process will be aborted. + * + * @param data stream to read from + * @return size_t amount of bytes written + */ size_t UpdateClass::writeStream(Stream &data) { - size_t written = 0; - if (hasError() || !ctx) - // 0 if not running + if (!this->ctx) return 0; + size_t written = 0; uint32_t lastData = millis(); // loop until the update is complete while (remaining()) { // check stream availability - int available = data.available(); + auto available = data.available(); if (available <= 0) { if (millis() - lastData > UPDATE_TIMEOUT_MS) { // waited for data too long; abort with error - cleanup(UPDATE_ERROR_STREAM); + this->errArd = UPDATE_ERROR_STREAM; + this->cleanup(/* clearError= */ false); return written; } continue; @@ -131,94 +164,21 @@ size_t UpdateClass::writeStream(Stream &data) { lastData = millis(); // read data to fit in the remaining buffer space - bufAlloc(); - uint16_t read = data.readBytes(bufPos, bufLeft()); - bufPos += read; - written += read; - tryWriteData(); + auto bufSize = this->ctx->buf_pos - this->ctx->buf; + auto read = data.readBytes(this->ctx->buf_pos, UF2_BLOCK_SIZE - bufSize); + // increment buffer writing head + this->ctx->buf_pos += read; + // process the block if complete + if (bufSize + read == UF2_BLOCK_SIZE) + lt_ota_write_block(this->ctx, reinterpret_cast(this->ctx->buf)); + // abort on errors if (hasError()) { - // return on errors - printErrorContext2(NULL, read); // buf is not valid anymore + this->cleanup(/* clearError= */ false); return written; } + written += read; } return written; } -/** - * @brief Try to use the buffer as a block to write. In case of UF2 errors, - * error codes are set, the update is aborted and 0 is returned - * - * @param data received data to copy to buffer or NULL if already in buffer - * @param len received data length - must be at most bufLeft() - * @return size_t "used" data size - 0 or 512 - */ -size_t UpdateClass::tryWriteData(uint8_t *data, size_t len) { - uf2_block_t *block = NULL; - - LT_VM(OTA, "Writing %u to buffer (%u/512)", len, bufSize()); - - if (len == UF2_BLOCK_SIZE) { - // data has a complete block - block = (uf2_block_t *)data; - } else if (data && len) { - // data has a part of a block, copy it to buffer - bufAlloc(); - memcpy(bufPos, data, len); - bufPos += len; - } - - if (!block && bufSize() == UF2_BLOCK_SIZE) { - // use buffer as block (only if not found above) - block = (uf2_block_t *)buf; - } - - // a complete block has been found - if (block) { - if (checkUf2Error(uf2_check_block(ctx, block))) - // block is invalid - return 0; - - if (errUf2 == UF2_ERR_IGNORE) - // treat ignored blocks as valid - return UF2_BLOCK_SIZE; - - if (!bytesWritten) { - // parse header block to allow retrieving firmware info - if (checkUf2Error(uf2_parse_header(ctx, block, info))) - // header is invalid - return 0; - - LT_IM(OTA, "%s v%s - LT v%s @ %s", info->fw_name, info->fw_version, info->lt_version, info->board); - - if (bytesTotal == UPDATE_SIZE_UNKNOWN) { - // set total update size from block count info - bytesTotal = block->block_count * UF2_BLOCK_SIZE; - } else if (bytesTotal != block->block_count * UF2_BLOCK_SIZE) { - // given update size does not match the block count - LT_EM(OTA, "Image size wrong; got %u, calculated %u", bytesTotal, block->block_count * UF2_BLOCK_SIZE); - cleanup(UPDATE_ERROR_SIZE); - return 0; - } - } else { - // write data blocks normally - if (checkUf2Error(uf2_write(ctx, block))) - // block writing failed - return 0; - } - - // increment total writing progress - bytesWritten += UF2_BLOCK_SIZE; - // call progress callback - if (callback) - callback(bytesWritten, bytesTotal); - // reset the buffer as it's used already - if (bufSize() == UF2_BLOCK_SIZE) - bufPos = buf; - return UF2_BLOCK_SIZE; - } - - return 0; -} - UpdateClass Update; diff --git a/cores/common/arduino/libraries/common/Update/Update.h b/cores/common/arduino/libraries/common/Update/Update.h index 7e81790..e5277e5 100644 --- a/cores/common/arduino/libraries/common/Update/Update.h +++ b/cores/common/arduino/libraries/common/Update/Update.h @@ -4,39 +4,30 @@ #include #include -// No Error -#define UPDATE_ERROR_OK (0) -// Flash Write Failed -#define UPDATE_ERROR_WRITE (1) -// Flash Erase Failed -#define UPDATE_ERROR_ERASE (2) -// Flash Read Failed -#define UPDATE_ERROR_READ (3) -// Not Enough Space -#define UPDATE_ERROR_SPACE (4) -// Bad Size Given -#define UPDATE_ERROR_SIZE (5) -// Stream Read Timeout -#define UPDATE_ERROR_STREAM (6) -// MD5 Check Failed -#define UPDATE_ERROR_MD5 (7) -// Wrong Magic Byte -#define UPDATE_ERROR_MAGIC_BYTE (8) -// Could Not Activate The Firmware -#define UPDATE_ERROR_ACTIVATE (9) -// Partition Could Not be Found -#define UPDATE_ERROR_NO_PARTITION (10) -// Bad Argument -#define UPDATE_ERROR_BAD_ARGUMENT (11) -// Aborted -#define UPDATE_ERROR_ABORT (12) +typedef enum { + UPDATE_ERROR_OK = 0, //!< No Error + UPDATE_ERROR_WRITE = 1, //!< Flash Write Failed + UPDATE_ERROR_ERASE = 2, //!< Flash Erase Failed + UPDATE_ERROR_READ = 3, //!< Flash Read Failed + UPDATE_ERROR_SPACE = 4, //!< Not Enough Space + UPDATE_ERROR_SIZE = 5, //!< Bad Size Given + UPDATE_ERROR_STREAM = 6, //!< Stream Read Timeout + UPDATE_ERROR_MD5 = 7, //!< MD5 Check Failed + UPDATE_ERROR_MAGIC_BYTE = 8, //!< Wrong Magic Byte + UPDATE_ERROR_ACTIVATE = 9, //!< Could Not Activate The Firmware + UPDATE_ERROR_NO_PARTITION = 10, //!< Partition Could Not be Found + UPDATE_ERROR_BAD_ARGUMENT = 11, //!< Bad Argument + UPDATE_ERROR_ABORT = 12, //!< Aborted +} UpdateError; + +typedef enum { + U_FLASH = 0, + U_SPIFFS = 100, + U_AUTH = 200, +} UpdateCommand; #define UPDATE_SIZE_UNKNOWN 0xFFFFFFFF -#define U_FLASH 0 -#define U_SPIFFS 100 -#define U_AUTH 200 - #define ENCRYPTED_BLOCK_SIZE 16 #define UPDATE_TIMEOUT_MS 30 * 1000 @@ -46,109 +37,132 @@ class UpdateClass { typedef std::function THandlerFunction_Progress; public: /* Update.cpp */ - UpdateClass(); bool begin( - size_t size = UPDATE_SIZE_UNKNOWN, - int command = U_FLASH, - int unused2 = -1, - uint8_t unused3 = LOW, - const char *unused4 = NULL // this is for SPIFFS + size_t size = UPDATE_SIZE_UNKNOWN, + int command = U_FLASH, + int ledPin = -1, + uint8_t ledOn = LOW, + const char *label = nullptr ); bool end(bool evenIfRemaining = false); - size_t write(uint8_t *data, size_t len); + + size_t write(const uint8_t *data, size_t len); size_t writeStream(Stream &data); - bool canRollBack(); - bool rollBack(); - // bool setMD5(const char *expected_md5); private: /* Update.cpp */ - size_t tryWriteData(uint8_t *data = NULL, size_t len = 0); + void cleanup(bool clearError = false); public: /* UpdateUtil.cpp */ - UpdateClass &onProgress(THandlerFunction_Progress callback); - void abort(); - void printError(Print &out); - const char *errorString(); - const char *getFirmwareName(); - const char *getFirmwareVersion(); - const char *getLibreTinyVersion(); - const char *getBoardName(); + UpdateClass &onProgress(THandlerFunction_Progress handler); + static bool canRollBack(); + static bool rollBack(); + uint16_t getErrorCode() const; + bool hasError() const; + void clearError(); + const char *errorString() const; + void printError(Print &out) const; private: /* UpdateUtil.cpp */ - void cleanup(uint8_t ardErr = UPDATE_ERROR_OK, uf2_err_t uf2Err = UF2_ERR_OK); - bool checkUf2Error(uf2_err_t err); - void bufAlloc(); - void printErrorContext1(); - void printErrorContext2(const uint8_t *data, size_t len); - uint16_t bufLeft(); - uint16_t bufSize(); + static void progressHandler(UpdateClass *self); + void printErrorContext(); private: - // uf2ota context - uf2_ota_t *ctx; - uf2_info_t *info; - // block buffer - uint8_t *buf; - uint8_t *bufPos; - // update progress - multiplies of 512 bytes - uint32_t bytesWritten; - uint32_t bytesTotal; - // errors - uf2_err_t errUf2; - uint8_t errArd; - // progress callback - THandlerFunction_Progress callback; - // String _target_md5; - // MD5Builder _md5; + lt_ota_ctx_t *ctx{nullptr}; + uf2_err_t errUf2{UF2_ERR_OK}; + UpdateError errArd{UPDATE_ERROR_OK}; + THandlerFunction_Progress callback{nullptr}; public: - String md5String(void) { - // return _md5.toString(); - return ""; + /** + * @brief Get Arduino error code of the update. + */ + inline UpdateError getError() const { + return this->errArd; } - void md5(uint8_t *result) { - // return _md5.getBytes(result); + /** + * @brief Get UF2OTA error code of the update. + */ + inline uf2_err_t getUF2Error() const { + return this->ctx ? this->ctx->error : this->errUf2; } - uint8_t getError() { - return errArd; + /** + * @brief Same as end(). + */ + inline void abort() { + this->end(); } - uf2_err_t getUF2Error() { - return errUf2; + /** + * @brief Check if the update process has been started. + */ + inline bool isRunning() { + return this->ctx; } - uint16_t getErrorCode() { - return (errArd << 8) | errUf2; + /** + * @brief Check if the update process hasn't been started or has been completed. + */ + inline bool isFinished() { + return !(this->ctx && this->ctx->bytes_written != this->ctx->bytes_total); } - void clearError() { - cleanup(UPDATE_ERROR_OK); + /** + * @brief Return complete update image size. + */ + inline size_t size() { + return this->ctx ? this->ctx->bytes_total : 0; } - bool hasError() { - return errArd != UPDATE_ERROR_OK; + /** + * @brief Return amount of bytes already written. + */ + inline size_t progress() { + return this->ctx ? this->ctx->bytes_written : 0; } - bool isRunning() { - return ctx != NULL; + /** + * @brief Return amount of bytes remaining to write. + */ + inline size_t remaining() { + return this->size() - this->progress(); } - bool isFinished() { - return bytesWritten == bytesTotal; + /** + * @brief Get firmware name from UF2 info. + */ + inline const char *getFirmwareName() { + if (this->ctx) + return this->ctx->info.fw_name; + return nullptr; } - size_t size() { - return bytesTotal; + /** + * @brief Get firmware version from UF2 info. + */ + inline const char *getFirmwareVersion() { + if (this->ctx) + return this->ctx->info.fw_version; + return nullptr; } - size_t progress() { - return bytesWritten; + /** + * @brief Get LibreTiny version from UF2 info. + */ + inline const char *getLibreTinyVersion() { + if (this->ctx) + return this->ctx->info.lt_version; + return nullptr; } - size_t remaining() { - return bytesTotal - bytesWritten; + /** + * @brief Get target board name from UF2 info. + */ + inline const char *getBoardName() { + if (this->ctx) + return this->ctx->info.board; + return nullptr; } }; diff --git a/cores/common/arduino/libraries/common/Update/UpdateUtil.cpp b/cores/common/arduino/libraries/common/Update/UpdateUtil.cpp index d355c7a..4fe09ee 100644 --- a/cores/common/arduino/libraries/common/Update/UpdateUtil.cpp +++ b/cores/common/arduino/libraries/common/Update/UpdateUtil.cpp @@ -2,26 +2,46 @@ #include "Update.h" +#include + extern "C" { #include } -static const uint8_t errorMap[] = { - UPDATE_ERROR_OK, /* UF2_ERR_OK - no error */ - UPDATE_ERROR_OK, /* UF2_ERR_IGNORE - block should be ignored */ - UPDATE_ERROR_MAGIC_BYTE, /* UF2_ERR_MAGIC - wrong magic numbers */ - UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_FAMILY - family ID mismatched */ - UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_NOT_HEADER - block is not a header */ - UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_OTA_VER - unknown/invalid OTA format version */ - UPDATE_ERROR_MAGIC_BYTE, /* UF2_ERR_OTA_WRONG - no data for current OTA scheme */ - UPDATE_ERROR_NO_PARTITION, /* UF2_ERR_PART_404 - no partition with that name */ - UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_PART_INVALID - invalid partition info tag */ - UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_PART_UNSET - attempted to write without target partition */ - UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_DATA_TOO_LONG - data too long - tags won't fit */ - UPDATE_ERROR_BAD_ARGUMENT, /* UF2_ERR_SEQ_MISMATCH - sequence number mismatched */ - UPDATE_ERROR_ERASE, /* UF2_ERR_ERASE_FAILED - erasing flash failed */ - UPDATE_ERROR_WRITE, /* UF2_ERR_WRITE_FAILED - writing to flash failed */ - UPDATE_ERROR_WRITE /* UF2_ERR_WRITE_LENGTH - wrote fewer data than requested */ +static const char *errUf2Text[] = { + nullptr, // UF2_ERR_OK (0) + nullptr, // UF2_ERR_IGNORE (1) + "Bad Magic Number", // UF2_ERR_MAGIC (2) + "Bad Family ID", // UF2_ERR_FAMILY (3) + "Missing Header", // UF2_ERR_NOT_HEADER (4) + "Old OTA Format Found", // UF2_ERR_OTA_VER (5) + "Image Not Applicable", // UF2_ERR_OTA_WRONG (6) + "Partition Not Found", // UF2_ERR_PART_404 (7) + "Partition Info Invalid", // UF2_ERR_PART_INVALID (8) + "Partition Info Missing", // UF2_ERR_PART_UNSET (9) + "Block Data Too Long", // UF2_ERR_DATA_TOO_LONG (10) + "Bad Block Sequence Number", // UF2_ERR_SEQ_MISMATCH (11) + "Flash Erase Failed", // UF2_ERR_ERASE_FAILED (12) + "Flash Write Failed", // UF2_ERR_WRITE_FAILED (13) + "Write Failed Length", // UF2_ERR_WRITE_LENGTH (14) + "Partition Write-Protected", // UF2_ERR_WRITE_PROTECT (15) + "Memory Alloc Failed", // UF2_ERR_ALLOC_FAILED (16) +}; + +static const char *errArdText[] = { + nullptr, // UPDATE_ERROR_OK (0) + nullptr, // UPDATE_ERROR_WRITE (1) + nullptr, // UPDATE_ERROR_ERASE (2) + nullptr, // UPDATE_ERROR_READ (3) + nullptr, // UPDATE_ERROR_SPACE (4) + "Bad Size Given", // UPDATE_ERROR_SIZE (5) + "Stream Read Timeout", // UPDATE_ERROR_STREAM (6) + "MD5 Check Failed", // UPDATE_ERROR_MD5 (7) + nullptr, // UPDATE_ERROR_MAGIC_BYTE (8) + "Could Not Activate The Firmware", // UPDATE_ERROR_ACTIVATE (9) + nullptr, // UPDATE_ERROR_NO_PARTITION (10) + "Bad Argument", // UPDATE_ERROR_BAD_ARGUMENT (11) + "Aborted", // UPDATE_ERROR_ABORT (12) }; static char errorStr[14]; @@ -29,153 +49,14 @@ static char errorStr[14]; /** * @brief Set the callback invoked after writing data to flash. */ -UpdateClass &UpdateClass::onProgress(THandlerFunction_Progress callback) { - this->callback = callback; +UpdateClass &UpdateClass::onProgress(THandlerFunction_Progress handler) { + this->callback = std::move(handler); return *this; } -void UpdateClass::cleanup(uint8_t ardErr, uf2_err_t uf2Err) { - errUf2 = uf2Err; - errArd = ardErr; - -#if LT_DEBUG_OTA - if (hasError()) - printErrorContext1(); -#endif - - uf2_ctx_free(ctx); // NULL in constructor - ctx = NULL; - uf2_info_free(info); // NULL in constructor - info = NULL; - free(buf); // NULL in constructor - buf = bufPos = NULL; - - bytesWritten = 0; - bytesTotal = 0; -} - -/** - * @brief Check for UF2 errors. Set errArd and errUf2 in case of errors. - * Ignored blocks are not reported as errors. - * Abort the update. - * Use like: "if (errorUf2(...)) return false;" - * @return true if err is not OK, false otherwise - */ -bool UpdateClass::checkUf2Error(uf2_err_t err) { - if (err <= UF2_ERR_IGNORE) - return false; - cleanup(errorMap[err], err); - return true; -} - -/** - * @brief Abort the update with UPDATE_ERROR_ABORT reason. - */ -void UpdateClass::abort() { - LT_DM(OTA, "Aborting update"); - cleanup(UPDATE_ERROR_ABORT); -} - -void UpdateClass::bufAlloc() { - if (!buf) - buf = bufPos = (uint8_t *)malloc(UF2_BLOCK_SIZE); -} - -uint16_t UpdateClass::bufLeft() { - return buf + UF2_BLOCK_SIZE - bufPos; -} - -uint16_t UpdateClass::bufSize() { - return bufPos - buf; -} - -/** - * @brief Print string error info to the stream. - */ -void UpdateClass::printError(Print &out) { - out.println(errorString()); -} - -/** - * @brief Print details about the error and current OTA state. - */ -void UpdateClass::printErrorContext1() { -#if LT_DEBUG_OTA - LT_EM(OTA, "Error: %s", errorString()); - if (errArd == UPDATE_ERROR_ABORT) - return; - - LT_EM(OTA, "- written: %u of %u", bytesWritten, bytesTotal); - LT_EM(OTA, "- buf: size=%u, left=%u", bufSize(), bufLeft()); - hexdump(buf, bufSize()); - - if (ctx) - LT_EM( - OTA, - "- ctx: seq=%u, part=%s", - ctx->seq - 1, // print last parsed block seq - ctx->part ? ctx->part->name : NULL - ); - - uf2_block_t *block = (uf2_block_t *)buf; - if (buf) - LT_EM(OTA, "- buf: seq=%u/%u, addr=%u, len=%u", block->block_seq, block->block_count, block->addr, block->len); -#endif -} - -void UpdateClass::printErrorContext2(const uint8_t *data, size_t len) { -#if LT_DEBUG_OTA - LT_EM(OTA, "- while writing %u bytes", len); - if (data) - hexdump(data, len); -#endif -} - -/** - * @brief Get string representation of the error in format - * "ard=..,uf2=..". Returns "" if no error. - */ -const char *UpdateClass::errorString() { - if (!errArd && !errUf2) - return ""; - sprintf(errorStr, "ard=%u,uf2=%u", errArd, errUf2); - return errorStr; -} - -/** - * @brief Get firmware name from UF2 info. - */ -const char *UpdateClass::getFirmwareName() { - if (info) - return info->fw_name; - return NULL; -} - -/** - * @brief Get firmware version from UF2 info. - */ -const char *UpdateClass::getFirmwareVersion() { - if (info) - return info->fw_version; - return NULL; -} - -/** - * @brief Get LibreTiny version from UF2 info. - */ -const char *UpdateClass::getLibreTinyVersion() { - if (info) - return info->lt_version; - return NULL; -} - -/** - * @brief Get target board name from UF2 info. - */ -const char *UpdateClass::getBoardName() { - if (info) - return info->board; - return NULL; +void UpdateClass::progressHandler(UpdateClass *self) { + if (self->callback) + self->callback(self->ctx->bytes_written, self->ctx->bytes_total); } /** @copydoc lt_ota_can_rollback() */ @@ -187,5 +68,85 @@ bool UpdateClass::canRollBack() { bool UpdateClass::rollBack() { if (!lt_ota_can_rollback()) return false; - return lt_ota_switch(false); + return lt_ota_switch(/* revert= */ false); +} + +/** + * @brief Get combined error code of the update. + */ +uint16_t UpdateClass::getErrorCode() const { + return (this->getError() << 8) | this->getUF2Error(); +} + +/** + * @brief Check if any error has occurred (incl. aborting the update). + */ +bool UpdateClass::hasError() const { + return this->getError() != UPDATE_ERROR_OK || this->getUF2Error() > UF2_ERR_IGNORE; +} + +/** + * @brief Clear all errors. This is NOT recommended. + */ +void UpdateClass::clearError() { + this->errArd = UPDATE_ERROR_OK; + this->errUf2 = UF2_ERR_OK; + if (this->ctx) + this->ctx->error = UF2_ERR_OK; +} + +/** + * @brief Get a textual description of the error. + */ +const char *UpdateClass::errorString() const { + uint8_t err; + if ((err = this->getUF2Error()) > UF2_ERR_IGNORE) + return errUf2Text[err]; + if ((err = this->getError()) != UPDATE_ERROR_OK) + return errArdText[err]; + if (!this->hasError()) + return ""; + sprintf(errorStr, "ard=%u,uf2=%u", this->getError(), this->getUF2Error()); + return errorStr; +} + +/** + * @brief Print string error info to the stream. + */ +void UpdateClass::printError(Print &out) const { + out.println(errorString()); +} + +/** + * @brief Print details about the error and current OTA state. + */ +void UpdateClass::printErrorContext() { +#if LT_DEBUG_OTA + if (!this->ctx) + return; + + LT_EM(OTA, "Error: %s", errorString()); + if (errArd == UPDATE_ERROR_ABORT) + return; + + LT_EM(OTA, "- written: %u of %u", this->ctx->bytes_written, this->ctx->bytes_total); + LT_EM( + OTA, + "- buf: size=%lld, left=%lld", + this->ctx->buf_pos - this->ctx->buf, + this->ctx->buf + UF2_BLOCK_SIZE - this->ctx->buf_pos + ); + hexdump(this->ctx->buf, this->ctx->buf_pos - this->ctx->buf); + + if (ctx) + LT_EM( + OTA, + "- ctx: seq=%u, part=%s", + this->ctx->uf2.seq - 1, // print last parsed block seq + this->ctx->uf2.part ? this->ctx->uf2.part->name : nullptr + ); + + auto *block = (uf2_block_t *)this->ctx->buf; + LT_EM(OTA, "- buf: seq=%u/%u, addr=%u, len=%u", block->block_seq, block->block_count, block->addr, block->len); +#endif } diff --git a/cores/common/base/api/lt_ota.c b/cores/common/base/api/lt_ota.c index 5e7da4b..e122384 100644 --- a/cores/common/base/api/lt_ota.c +++ b/cores/common/base/api/lt_ota.c @@ -2,10 +2,148 @@ #include "lt_ota.h" +#include + +#define UF2_CTX_SIZE (sizeof(uf2_ota_t) + sizeof(uf2_info_t)) + +static inline size_t lt_ota_buf_left(lt_ota_ctx_t *ctx) { + return ctx->buf + UF2_BLOCK_SIZE - ctx->buf_pos; +} + +static inline size_t lt_ota_buf_size(lt_ota_ctx_t *ctx) { + return ctx->buf_pos - ctx->buf; +} + +void lt_ota_begin(lt_ota_ctx_t *ctx, size_t size) { + if (!ctx) + return; + + memset((void *)ctx + UF2_CTX_SIZE, 0, sizeof(lt_ota_ctx_t) - UF2_CTX_SIZE); + uf2_ctx_init(&ctx->uf2, lt_ota_get_uf2_scheme(), lt_cpu_get_family()); + uf2_info_init(&ctx->info); + ctx->buf_pos = ctx->buf; + ctx->bytes_total = size; + ctx->running = true; + + lt_ota_set_write_protect(&ctx->uf2); + + LT_DM(OTA, "begin(%u, ...) / OTA curr: %u, scheme: %u", size, lt_ota_dual_get_current(), lt_ota_get_uf2_scheme()); +} + +bool lt_ota_end(lt_ota_ctx_t *ctx) { + if (!ctx || !ctx->running) + return true; + + uf2_ctx_free(&ctx->uf2); + uf2_info_free(&ctx->info); + ctx->running = false; + + if (ctx->bytes_written && ctx->bytes_written == ctx->bytes_total) { + // try to activate the 2nd image + return lt_ota_switch(/* revert= */ false); + } + + // activation not attempted (update aborted) + return true; +} + +__attribute__((weak)) void lt_ota_set_write_protect(uf2_ota_t *uf2) {} + +size_t lt_ota_write(lt_ota_ctx_t *ctx, const uint8_t *data, size_t len) { + if (!ctx || !ctx->running) + return 0; + + // write until buffer space is available + size_t written = 0; + uint16_t to_write; // 1..512 + while (len && (to_write = MIN((uint16_t)len, lt_ota_buf_left(ctx)))) { + LT_VM(OTA, "Writing %u to buffer (%u/512)", len, lt_ota_buf_size(ctx)); + + uf2_block_t *block = NULL; + if (to_write == UF2_BLOCK_SIZE) { + // data has a complete block; don't use the buffer + block = (uf2_block_t *)data; + } else { + // data has a part of a block; append it to the buffer + memcpy(ctx->buf_pos, data, to_write); + ctx->buf_pos += to_write; + if (lt_ota_buf_size(ctx) == UF2_BLOCK_SIZE) { + // the block is complete now + block = (uf2_block_t *)ctx->buf; + } + } + + // write if a block is ready + if (block && lt_ota_write_block(ctx, block) == false) + // return on errors + return written; + data += to_write; + len -= to_write; + written += to_write; + } + return written; +} + +bool lt_ota_write_block(lt_ota_ctx_t *ctx, uf2_block_t *block) { + ctx->error = uf2_check_block(&ctx->uf2, block); + if (ctx->error > UF2_ERR_IGNORE) + // block is invalid + return false; + + if (!ctx->bytes_written) { + // parse header block to allow retrieving firmware info + ctx->error = uf2_parse_header(&ctx->uf2, block, &ctx->info); + if (ctx->error != UF2_ERR_OK) + return false; + + LT_IM( + OTA, + "%s v%s - LT v%s @ %s", + ctx->info.fw_name, + ctx->info.fw_version, + ctx->info.lt_version, + ctx->info.board + ); + + if (ctx->bytes_total == 0) { + // set total update size from block count info + ctx->bytes_total = block->block_count * UF2_BLOCK_SIZE; + } else if (ctx->bytes_total != block->block_count * UF2_BLOCK_SIZE) { + // given update size does not match the block count + LT_EM( + OTA, + "Image size wrong; got %u, calculated %llu", + ctx->bytes_total, + block->block_count * UF2_BLOCK_SIZE + ); + return false; + } + } else if (ctx->error == UF2_ERR_OK) { + // write data blocks normally + ctx->error = uf2_write(&ctx->uf2, block); + if (ctx->error > UF2_ERR_IGNORE) + // block writing failed + return false; + } + + // increment total writing progress + ctx->bytes_written += UF2_BLOCK_SIZE; + // call progress callback + if (ctx->callback) + ctx->callback(ctx->callback_param); + // reset the buffer as it's used already + if (lt_ota_buf_size(ctx) == UF2_BLOCK_SIZE) + ctx->buf_pos = ctx->buf; + + return true; +} + bool lt_ota_can_rollback() { if (lt_ota_get_type() != OTA_TYPE_DUAL) return false; uint8_t current = lt_ota_dual_get_current(); + if (current == 0) + return false; return lt_ota_is_valid(current ^ 0b11); } @@ -13,6 +151,8 @@ uf2_ota_scheme_t lt_ota_get_uf2_scheme() { if (lt_ota_get_type() == OTA_TYPE_SINGLE) return UF2_SCHEME_DEVICE_SINGLE; uint8_t current = lt_ota_dual_get_current(); + if (current == 0) + return UF2_SCHEME_DEVICE_DUAL_1; // UF2_SCHEME_DEVICE_DUAL_1 or UF2_SCHEME_DEVICE_DUAL_2 return (uf2_ota_scheme_t)(current ^ 0b11); } diff --git a/cores/common/base/api/lt_ota.h b/cores/common/base/api/lt_ota.h index 864fb2b..e86bf86 100644 --- a/cores/common/base/api/lt_ota.h +++ b/cores/common/base/api/lt_ota.h @@ -14,6 +14,72 @@ typedef enum { OTA_TYPE_FILE = 2, } lt_ota_type_t; +/** + * @brief OTA update process context. + */ +typedef struct { + uf2_ota_t uf2; + uf2_info_t info; + uint8_t buf[UF2_BLOCK_SIZE]; // block data buffer + uint8_t *buf_pos; // buffer writing position + uint32_t bytes_written; // update progress + uint32_t bytes_total; // total update size + uf2_err_t error; // LT OTA/uf2ota error code + bool running; // whether update has begun + void (*callback)(void *param); // progress callback + void *callback_param; // callback argument +} lt_ota_ctx_t; + +/** + * @brief Initialize the update context to begin OTA process. + * + * @param ctx OTA context + * @param size length of the update file; 0 if unknown + */ +void lt_ota_begin(lt_ota_ctx_t *ctx, size_t size); + +/** + * @brief Finish the update process. If the update has been written completely, + * try to activate the target image. Free allocated internal structures, regardless + * of the activation result. + * + * @param ctx OTA context + * @return false if activation was attempted and not successful; true otherwise + */ +bool lt_ota_end(lt_ota_ctx_t *ctx); + +/** + * @brief Set family-specific, write-protected flash areas in the OTA update context. + * This shouldn't be called manually, as it's done by lt_ota_begin(). + * + * @param uf2 uf2ota context + */ +void lt_ota_set_write_protect(uf2_ota_t *uf2); + +/** + * @brief Process a chunk of data. + * + * Data is written to the buffer, unless a full UF2 block is already available, + * in which case it's also processed by UF2OTA and written to flash. + * + * It's advised to write in 512-byte chunks (or its multiples). + * + * @param ctx OTA context + * @param data chunk of bytes to process + * @param len size of the chunk + * @return number of bytes correctly processed; should equal 'len' in case of no errors + */ +size_t lt_ota_write(lt_ota_ctx_t *ctx, const uint8_t *data, size_t len); + +/** + * @brief Try to write the block. In case of UF2 errors, error code is set in the context. + * Note: use lt_ota_write() instead. This is for internal usage only. + * + * @param block UF2 block to check and write; cannot be NULL + * @return whether no error has occurred + */ +bool lt_ota_write_block(lt_ota_ctx_t *ctx, uf2_block_t *block); + /** * @brief Get OTA type of the device's chip. */ diff --git a/cores/common/base/lt_logger.c b/cores/common/base/lt_logger.c index bec2361..8b80186 100644 --- a/cores/common/base/lt_logger.c +++ b/cores/common/base/lt_logger.c @@ -1,7 +1,10 @@ /* Copyright (c) Kuba Szczodrzyński 2022-04-28. */ #include "lt_logger.h" + +#if __has_include() #include +#endif #if LT_HAS_PRINTF #include @@ -33,7 +36,11 @@ #define COLOR_BRIGHT_CYAN 0x16 #define COLOR_BRIGHT_WHITE 0x17 -static uint32_t uart_port = LT_UART_DEFAULT_LOGGER; +#ifdef LT_UART_DEFAULT_PORT +static uint32_t uart_port = LT_UART_DEFAULT_LOGGER; +#else +static uint32_t uart_port = 0; +#endif static const char levels[] = {'V', 'D', 'I', 'W', 'E', 'F'}; #if LT_LOGGER_COLOR diff --git a/docs/scripts/write_apis.py b/docs/scripts/write_apis.py index 9346cbd..d1bf4de 100644 --- a/docs/scripts/write_apis.py +++ b/docs/scripts/write_apis.py @@ -38,7 +38,7 @@ if __name__ == "__main__": implementation = re.sub(macro_regex, "", implementation, flags=re.MULTILINE) implementation = re.sub(line_regex, "\n", implementation) - declaration_regex = r"^([\d\w\s]+ \*?)([\S]+?)\(.*?\);$" + declaration_regex = r"^([^\s][\d\w\s]+ \*?)([\S]+?)\(.*?\);$" implementation_regex = r"^(__attribute__\(\(weak\)\) )?([\w\d* ]+?)([\w\d]+)\(.+?{" function_types = {} @@ -85,11 +85,15 @@ if __name__ == "__main__": + Style.RESET_ALL ) + function_types[function_name] = function_type if is_weak: weak_functions.add(function_name) else: impl_functions.add(function_name) +for function in list(impl_functions): + if "static" in function_types[function]: + impl_functions.remove(function) common_functions = impl_functions.union(weak_functions) family_functions = decl_functions - common_functions diff --git a/external-libs.json b/external-libs.json index 9b3ff07..264e7ba 100644 --- a/external-libs.json +++ b/external-libs.json @@ -36,13 +36,13 @@ "PRINTF_INCLUDE_CONFIG_H": "1" } }, - "ltchiptool": { - "package": "tool-ltchiptool", + "uf2ota": { + "package": "library-uf2ota", "sources": [ - "+" + "+" ], "includes": [ - "+<.>" + "+" ] }, "arduino-api": { diff --git a/platform.json b/platform.json index facb6a3..cc46397 100644 --- a/platform.json +++ b/platform.json @@ -98,6 +98,10 @@ "type": "framework", "version": "https://github.com/libretiny-eu/library-printf#6.1.0" }, + "library-uf2ota": { + "type": "framework", + "version": "https://github.com/libretiny-eu/library-uf2ota#5.0.0" + }, "toolchain-gccarmnoneeabi": { "type": "toolchain", "optionalVersions": [ @@ -107,12 +111,6 @@ "~1.100301.0" ] }, - "tool-ltchiptool": { - "type": "uploader", - "version": "https://github.com/libretiny-eu/ltchiptool#v4.0.0", - "version_prefix": true, - "note": "This is used only for C/C++ code from ltchiptool." - }, "tool-openocd": { "type": "uploader", "optional": true, From 4d81fcac26569c3061e3566c6e3987d9afa9734c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 13 Jul 2023 17:00:42 +0200 Subject: [PATCH 31/31] [realtek-ambz2] Flash bootloader & partition table in UF2 --- builder/family/realtek-ambz2.py | 5 +++++ cores/common/arduino/libraries/common/Update/Update.cpp | 7 ++++++- cores/common/base/api/lt_ota.c | 4 +--- platform.py | 2 +- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/builder/family/realtek-ambz2.py b/builder/family/realtek-ambz2.py index a6786e0..e593bec 100644 --- a/builder/family/realtek-ambz2.py +++ b/builder/family/realtek-ambz2.py @@ -416,6 +416,8 @@ if not isfile(image_ota_clear): queue.BuildLibraries() # Main firmware outputs and actions +image_part_table = "${BUILD_DIR}/image_part_table.${FLASH_PART_TABLE_OFFSET}.bin" +image_bootloader = "${BUILD_DIR}/image_bootloader.${FLASH_BOOT_OFFSET}.bin" image_firmware_is = "${BUILD_DIR}/image_firmware_is.${FLASH_OTA1_OFFSET}.bin" env.Replace( # linker command (dual .bin outputs) @@ -424,6 +426,9 @@ env.Replace( UF2OTA=[ # same OTA images for flasher and device f"{image_firmware_is},{image_firmware_is}=device:ota1,ota2;flasher:ota1,ota2", + # having flashed an application image, update the bootloader and partition table (incl. keys) + f"{image_bootloader}=device:boot;flasher:boot", + f"{image_part_table}=device:part_table;flasher:part_table", # clearing headers of the "other" OTA image (hence the indexes are swapped) f"{image_ota_clear},{image_ota_clear}=device:ota2,ota1;flasher:ota2,ota1", ], diff --git a/cores/common/arduino/libraries/common/Update/Update.cpp b/cores/common/arduino/libraries/common/Update/Update.cpp index 6a2c6cd..8c1ff70 100644 --- a/cores/common/arduino/libraries/common/Update/Update.cpp +++ b/cores/common/arduino/libraries/common/Update/Update.cpp @@ -36,6 +36,11 @@ bool UpdateClass::begin( __attribute__((unused)) uint8_t ledOn, __attribute__((unused)) const char *label ) { +#if !LT_HAS_OTA + LT_E("OTA is not yet supported on this chip!"); + this->errArd = UPDATE_ERROR_BAD_ARGUMENT; + return false; +#endif if (this->ctx) { return false; } @@ -165,7 +170,7 @@ 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); + auto read = data.readBytes(this->ctx->buf_pos, UF2_BLOCK_SIZE - bufSize); // increment buffer writing head this->ctx->buf_pos += read; // process the block if complete diff --git a/cores/common/base/api/lt_ota.c b/cores/common/base/api/lt_ota.c index e122384..7eb27e2 100644 --- a/cores/common/base/api/lt_ota.c +++ b/cores/common/base/api/lt_ota.c @@ -4,8 +4,6 @@ #include -#define UF2_CTX_SIZE (sizeof(uf2_ota_t) + sizeof(uf2_info_t)) - static inline size_t lt_ota_buf_left(lt_ota_ctx_t *ctx) { return ctx->buf + UF2_BLOCK_SIZE - ctx->buf_pos; } @@ -18,7 +16,7 @@ void lt_ota_begin(lt_ota_ctx_t *ctx, size_t size) { if (!ctx) return; - memset((void *)ctx + UF2_CTX_SIZE, 0, sizeof(lt_ota_ctx_t) - UF2_CTX_SIZE); + memset(ctx, 0, sizeof(lt_ota_ctx_t)); uf2_ctx_init(&ctx->uf2, lt_ota_get_uf2_scheme(), lt_cpu_get_family()); uf2_info_init(&ctx->info); ctx->buf_pos = ctx->buf; diff --git a/platform.py b/platform.py index 2da5b4a..b4f27ab 100644 --- a/platform.py +++ b/platform.py @@ -17,7 +17,7 @@ from platformio.platform.base import PlatformBase from platformio.platform.board import PlatformBoardConfig from semantic_version import SimpleSpec, Version -LTCHIPTOOL_VERSION = "^4.0.1" +LTCHIPTOOL_VERSION = "^4.2.3" # Install & import tools