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] [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 8794182af..3fc7e73a0 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 d4c122cfb..95bd98f43 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 284ab5dbc..51d41790c 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 280d5b003..8848e08fd 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 000000000..d767cbbbc --- /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 000000000..200802724 --- /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 000000000..9eaed7888 --- /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 000000000..05d28b1c2 --- /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 000000000..f6038fede --- /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 000000000..2961e76f4 --- /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 000000000..b0648d087 --- /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 46e6c1137..000000000 --- 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 000000000..56aa518e8 --- /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 000000000..983ddadad --- /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 000000000..b97c5d53b --- /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 000000000..eae8685d9 --- /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 000000000..5e7da4b4a --- /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 000000000..521a5bd14 --- /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 000000000..a33788024 --- /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 09f1bddde..000000000 --- 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 8564dbd9e..4bb98c8ea 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 000000000..df7c40939 --- /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 000000000..4adac4210 --- /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 8e2ff6a49..000000000 --- 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 000000000..eb346cf26 --- /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 000000000..19511d71d --- /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 000000000..73438795e --- /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 000000000..c9c0167d7 --- /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 000000000..c3e5a4a08 --- /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 000000000..7ed571025 --- /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 72131a55a..000000000 --- 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 000000000..7f9c1ef14 --- /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 000000000..5cfff7e30 --- /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 000000000..f83ce88a7 --- /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 000000000..b079d4c14 --- /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 000000000..d96af85d1 --- /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 83c5f2d5d..000000000 --- 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 000000000..44e70328b --- /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 61cc4d8d0..3a11fc967 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 000000000..2845e5938 --- /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 924ed82ab..f3b1cd652 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 000000000..9346cbd8c --- /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 0329105e5..39d3ba57a 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