From 85da7464b6515c2e58bf7567d4996a5a19a3fbf1 Mon Sep 17 00:00:00 2001 From: Jerzy Kasenberg Date: Wed, 6 May 2026 09:03:27 +0200 Subject: [PATCH 1/4] sys/config: Add static conf handlers support So far conf_handlers could be registered at run time. This approach delays loading of configuration till application start processing events. This limits what can be configured in config. Now system supports static configuration, conf_handler can be put in link time table so conf_handler is ready from the very start and configuration can be loaded earlier. CONFIG_AUTO_LOAD syscfg value allows to load configuration during initialization of config subsystem as static handlers are already in place. Dynamic handlers are still supported while discuraged. Signed-off-by: Jerzy Kasenberg --- sys/config/include/config/config.h | 7 ++++ sys/config/pkg.yml | 3 ++ sys/config/src/config.c | 53 +++++++++++++++++++++++------- sys/config/src/config_init.c | 4 +++ sys/config/src/config_store.c | 18 +++++++--- sys/config/syscfg.yml | 17 ++++++++++ 6 files changed, 87 insertions(+), 15 deletions(-) diff --git a/sys/config/include/config/config.h b/sys/config/include/config/config.h index 81ab7a6f4a..84f67ce08d 100644 --- a/sys/config/include/config/config.h +++ b/sys/config/include/config/config.h @@ -28,6 +28,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -426,6 +427,12 @@ void conf_lock(void); */ void conf_unlock(void); +typedef struct conf_handler *conf_handler_t; +LINK_TABLE(struct conf_handler *, static_conf_handlers); + +#define STATIC_CONF_HANDLER(handler) \ + LINK_TABLE_ELEMENT_REF(static_conf_handlers, handler, handler); + #ifdef __cplusplus } #endif diff --git a/sys/config/pkg.yml b/sys/config/pkg.yml index 3866f31f1e..9f78297168 100644 --- a/sys/config/pkg.yml +++ b/sys/config/pkg.yml @@ -41,6 +41,9 @@ pkg.deps.CONFIG_LITTLEFS: pkg.whole_archive: true +pkg.link_tables: + - static_conf_handlers + pkg.init: config_pkg_init: 'MYNEWT_VAL(CONFIG_SYSINIT_STAGE_1)' config_pkg_init_stage2: 'MYNEWT_VAL(CONFIG_SYSINIT_STAGE_2)' diff --git a/sys/config/src/config.c b/sys/config/src/config.c index b03a285e1a..3e675b6b1a 100644 --- a/sys/config/src/config.c +++ b/sys/config/src/config.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "os/mynewt.h" #include "base64/base64.h" @@ -48,7 +49,9 @@ conf_init(void) os_mutex_init(&conf_mtx); - SLIST_INIT(&conf_handlers); + if (MYNEWT_VAL(CONFIG_HANDLERS_DYNAMIC)) { + SLIST_INIT(&conf_handlers); + } conf_store_init(); (void)rc; @@ -104,9 +107,18 @@ conf_handler_lookup(char *name) { struct conf_handler *ch; - SLIST_FOREACH(ch, &conf_handlers, ch_list) { - if (!strcmp(name, ch->ch_name)) { - return ch; + if (MYNEWT_VAL(CONFIG_HANDLERS_STATIC)) { + LINK_TABLE_FOREACH(h, static_conf_handlers) { + if (!strcmp(name, (*h)->ch_name)) { + return *h; + } + } + } + if (MYNEWT_VAL(CONFIG_HANDLERS_DYNAMIC)) { + SLIST_FOREACH(ch, &conf_handlers, ch_list) { + if (!strcmp(name, ch->ch_name)) { + return ch; + } } } return NULL; @@ -412,8 +424,15 @@ conf_export(conf_export_func_t export_func, enum conf_export_tgt tgt) struct conf_handler *ch; conf_lock(); - SLIST_FOREACH(ch, &conf_handlers, ch_list) { - conf_export_cb(ch, export_func, tgt); + if (MYNEWT_VAL(CONFIG_HANDLERS_STATIC)) { + LINK_TABLE_FOREACH(h, static_conf_handlers) { + conf_export_cb(*h, export_func, tgt); + } + } + if (MYNEWT_VAL(CONFIG_HANDLERS_DYNAMIC)) { + SLIST_FOREACH(ch, &conf_handlers, ch_list) { + conf_export_cb(ch, export_func, tgt); + } } conf_unlock(); } @@ -487,11 +506,23 @@ conf_commit(char *name) rc = conf_commit_cb(ch); } else { rc = 0; - SLIST_FOREACH(ch, &conf_handlers, ch_list) { - if (ch->ch_commit) { - rc2 = conf_commit_cb(ch); - if (!rc) { - rc = rc2; + if (MYNEWT_VAL(CONFIG_HANDLERS_STATIC)) { + LINK_TABLE_FOREACH(h, static_conf_handlers) { + if ((*h)->ch_commit) { + rc2 = conf_commit_cb(*h); + if (!rc) { + rc = rc2; + } + }; + } + } + if (MYNEWT_VAL(CONFIG_HANDLERS_DYNAMIC)) { + SLIST_FOREACH(ch, &conf_handlers, ch_list) { + if (ch->ch_commit) { + rc2 = conf_commit_cb(ch); + if (!rc) { + rc = rc2; + } } } } diff --git a/sys/config/src/config_init.c b/sys/config/src/config_init.c index 8108713f5e..2392ede506 100644 --- a/sys/config/src/config_init.c +++ b/sys/config/src/config_init.c @@ -125,6 +125,10 @@ config_pkg_init(void) #elif MYNEWT_VAL(CONFIG_FCB2) config_init_fcb2(); #endif +#if MYNEWT_VAL(CONFIG_AUTO_LOAD) + conf_load(); +#endif + #endif } diff --git a/sys/config/src/config_store.c b/sys/config/src/config_store.c index a5bc5828a7..f1ac586a0c 100644 --- a/sys/config/src/config_store.c +++ b/sys/config/src/config_store.c @@ -304,10 +304,20 @@ conf_save(void) cs->cs_itf->csi_save_start(cs); } rc = 0; - SLIST_FOREACH(ch, &conf_handlers, ch_list) { - rc2 = conf_export_cb(ch, conf_store_one, CONF_EXPORT_PERSIST); - if (!rc) { - rc = rc2; + if (MYNEWT_VAL(CONFIG_HANDLERS_STATIC)) { + LINK_TABLE_FOREACH(h, static_conf_handlers) { + rc2 = conf_export_cb(*h, conf_store_one, CONF_EXPORT_PERSIST); + if (!rc) { + rc = rc2; + } + } + } + if (MYNEWT_VAL(CONFIG_HANDLERS_DYNAMIC)) { + SLIST_FOREACH(ch, &conf_handlers, ch_list) { + rc2 = conf_export_cb(ch, conf_store_one, CONF_EXPORT_PERSIST); + if (!rc) { + rc = rc2; + } } } if (cs->cs_itf->csi_save_end) { diff --git a/sys/config/syscfg.yml b/sys/config/syscfg.yml index f4de27fdba..49731dee26 100644 --- a/sys/config/syscfg.yml +++ b/sys/config/syscfg.yml @@ -83,6 +83,23 @@ syscfg.defs: description: 'Automatically configure a single config region at bootup' value: 1 + CONFIG_AUTO_LOAD: + description: > + Load config values during config init stage. This could be enabled + if all config handlers are statically defined. + value: 0 + + CONFIG_HANDLERS_DYNAMIC: + description: > + Config handler can be registered in runtime via conf_register. + value: 1 + + CONFIG_HANDLERS_STATIC: + description: > + Config handler are configured during build. Reducing memory + footprint and package init dependency + value: 1 + CONFIG_SYSINIT_STAGE_1: description: > Primary sysinit stage for the config package. From cc2130821044d291d718865947e5930695213bf2 Mon Sep 17 00:00:00 2001 From: Jerzy Kasenberg Date: Wed, 6 May 2026 09:06:26 +0200 Subject: [PATCH 2/4] sys/fault: Use static conf_handler registration Now conf_handler is statically registerd at build time. Signed-off-by: Jerzy Kasenberg --- sys/fault/pkg.yml | 2 ++ sys/fault/src/fault.c | 4 ---- sys/fault/src/fault_conf.c | 6 +----- sys/fault/src/fault_priv.h | 1 - 4 files changed, 3 insertions(+), 10 deletions(-) diff --git a/sys/fault/pkg.yml b/sys/fault/pkg.yml index bf5f460f67..6691fd3c1b 100644 --- a/sys/fault/pkg.yml +++ b/sys/fault/pkg.yml @@ -32,5 +32,7 @@ pkg.deps: pkg.deps.FAULT_CLI: - "@apache-mynewt-core/sys/fault/fault_cli" +pkg.whole_archive: true + pkg.init: fault_init: MYNEWT_VAL(FAULT_SYSINIT_STAGE) diff --git a/sys/fault/src/fault.c b/sys/fault/src/fault.c index b8ff7aa1db..2a372baf27 100644 --- a/sys/fault/src/fault.c +++ b/sys/fault/src/fault.c @@ -345,10 +345,6 @@ fault_register_domain_priv(int domain_id, uint8_t success_delta, void fault_init(void) { - int rc; - - rc = fault_conf_init(); - SYSINIT_PANIC_ASSERT(rc == 0); } #endif /* !MYNEWT_VAL(FAULT_STUB) */ diff --git a/sys/fault/src/fault_conf.c b/sys/fault/src/fault_conf.c index 0e00ab6ca1..73773f17fd 100644 --- a/sys/fault/src/fault_conf.c +++ b/sys/fault/src/fault_conf.c @@ -103,8 +103,4 @@ fault_conf_persist_chronic_counts(void) return conf_save_one("fault/chronfail", buf); } -int -fault_conf_init(void) -{ - return conf_register(&fault_conf_handler); -} +STATIC_CONF_HANDLER(fault_conf_handler) diff --git a/sys/fault/src/fault_priv.h b/sys/fault/src/fault_priv.h index f0aee061ef..4e10c721fe 100644 --- a/sys/fault/src/fault_priv.h +++ b/sys/fault/src/fault_priv.h @@ -26,6 +26,5 @@ extern uint8_t fault_chronic_counts[MYNEWT_VAL(FAULT_MAX_DOMAINS)]; int fault_conf_persist_chronic_counts(void); -int fault_conf_init(void); #endif From 83266d6c8f432d831da3df37f5795bad60f6951a Mon Sep 17 00:00:00 2001 From: Jerzy Kasenberg Date: Wed, 6 May 2026 09:07:37 +0200 Subject: [PATCH 3/4] sys/id: Register conf_handler statically Now id_conf handler is statically registered at build time. Signed-off-by: Jerzy Kasenberg --- sys/id/pkg.yml | 2 ++ sys/id/src/id.c | 7 ++----- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/sys/id/pkg.yml b/sys/id/pkg.yml index ac6cceff0e..4824b2b66a 100644 --- a/sys/id/pkg.yml +++ b/sys/id/pkg.yml @@ -33,5 +33,7 @@ pkg.deps: - "@apache-mynewt-core/sys/mfg" - "@apache-mynewt-core/encoding/base64" +pkg.whole_archive: true + pkg.init: id_init: 'MYNEWT_VAL(ID_SYSINIT_STAGE)' diff --git a/sys/id/src/id.c b/sys/id/src/id.c index 4a6a2e5f8e..8a8ee1bf6e 100644 --- a/sys/id/src/id.c +++ b/sys/id/src/id.c @@ -236,14 +236,11 @@ id_read_mfghash(void) void id_init(void) { - int rc; - /* Ensure this function only gets called by sysinit. */ SYSINIT_ASSERT_ACTIVE(); - rc = conf_register(&id_conf); - SYSINIT_PANIC_ASSERT(rc == 0); - /* Attempt to read the manufacturing image hash from the meta region. */ id_read_mfghash(); } + +STATIC_CONF_HANDLER(id_conf) From 288a5b6f8d3d3843dc2d89c4b7b9f772fab1d292 Mon Sep 17 00:00:00 2001 From: Jerzy Kasenberg Date: Wed, 6 May 2026 09:28:01 +0200 Subject: [PATCH 4/4] stm32_eth: Add configuration support Now MAC address can be configured in sys/config instead of syscfg. Additionally eth link can be brough up at startup. DHCP can also be started atuomatically so when application code starts network is already correctly initialized. STM32_ETH_MAC_ADDR syscfg value can be used for specifying MAC address, STM32_MAC_ADDR is now defunct (name was inconsistent with other values and syntax was limiting how value can be used) STM32_ETH_AUTO_UP syscfg value allows to set link up during startup. STM32_ETH_DHCP syscfg value allows to start DHCP automatically. When STM32_ETH_SYS_CONFIG syscfg value is 1 configuration is taken from sys/config instead of syscfg.yml Signed-off-by: Jerzy Kasenberg --- hw/drivers/lwip/stm32_eth/pkg.yml | 5 + hw/drivers/lwip/stm32_eth/src/stm32_eth.c | 165 +++++++++++++++++++++- hw/drivers/lwip/stm32_eth/syscfg.yml | 23 ++- 3 files changed, 191 insertions(+), 2 deletions(-) diff --git a/hw/drivers/lwip/stm32_eth/pkg.yml b/hw/drivers/lwip/stm32_eth/pkg.yml index c28fe565a2..55d3241de4 100644 --- a/hw/drivers/lwip/stm32_eth/pkg.yml +++ b/hw/drivers/lwip/stm32_eth/pkg.yml @@ -29,6 +29,9 @@ pkg.deps: - "@apache-mynewt-core/hw/hal" - "@apache-mynewt-core/net/ip/lwip_mn" +pkg.deps.STM32_ETH_SYS_CONFIG: + - "@apache-mynewt-core/sys/config" + pkg.deps.MCU_STM32F4: - "@apache-mynewt-core/hw/mcu/stm/stm32f4xx" @@ -47,6 +50,8 @@ app.cflags: - -DCHECKSUM_CHECK_ICMP=0 - -DCHECKSUM_CHECK_ICMP6=0 +pkg.whole_archive: true + pkg.req_apis: pkg.init: diff --git a/hw/drivers/lwip/stm32_eth/src/stm32_eth.c b/hw/drivers/lwip/stm32_eth/src/stm32_eth.c index a896ca34e9..8e6a12da5a 100644 --- a/hw/drivers/lwip/stm32_eth/src/stm32_eth.c +++ b/hw/drivers/lwip/stm32_eth/src/stm32_eth.c @@ -25,6 +25,13 @@ #include #include +#if MYNEWT_VAL(STM32_ETH_SYS_CONFIG) +#include +#endif + +#include +#include + #if MYNEWT_VAL(MCU_STM32F4) #include #include @@ -205,6 +212,149 @@ HAL_ETH_RxLinkCallback(void **p_start, void **p_end, uint8_t *buff, uint16_t len } } +#define _Args(...) __VA_ARGS__ +#define STRIP_PARENS(X) X +#define UNMANGLE_MYNEWT_VAL(X) STRIP_PARENS(_Args X) + +static uint8_t stm32_eth_mac_address[6] = { UNMANGLE_MYNEWT_VAL( + MYNEWT_VAL_STM32_ETH_MAC_ADDR) }; +static uint8_t stm32_eth_auto_up; +static uint8_t stm32_eth_dhcp; + +#if MYNEWT_VAL(STM32_ETH_SYS_CONFIG) +#define equals(a, b) (strcmp(a, b) == 0) + +static uint8_t +format_hex_digit(int v) +{ + v &= 0xF; + + return (v < 10) ? (v + '0') : (v - 10 + 'A'); +} + +static char * +format_mac_address(const uint8_t *mac, char *buf, size_t buf_len) +{ + if (buf_len < 18) { + buf = NULL; + } else { + for (int i = 0; i < 6; ++i) { + buf[i * 3] = format_hex_digit(stm32_eth_mac_address[i] >> 4); + buf[i * 3 + 1] = format_hex_digit(stm32_eth_mac_address[i]); + buf[i * 3 + 2] = i < 5 ? ':' : '\0'; + } + } + return buf; +} + +static char * +stm32_eth_conf_get(int argc, char **argv, char *val, int val_len_max) +{ + char *ret = NULL; + + if (argc == 1) { + if (equals(argv[0], "up")) { + ret = conf_str_from_value(CONF_BOOL, &stm32_eth_auto_up, val, val_len_max); + } else if (equals(argv[0], "dhcp")) { + ret = conf_str_from_value(CONF_BOOL, &stm32_eth_dhcp, val, val_len_max); + } else if (equals(argv[0], "mac") && val_len_max >= 18) { + ret = format_mac_address(stm32_eth_mac_address, val, val_len_max); + } + } + return ret; +} + +static const char * +byte_from_str(const char *str, uint8_t *out_byte) +{ + uint8_t b = 0; + char c; + + for (int i = 0; i < 2; ++i) { + c = toupper(str[i]); + if (isdigit(c)) { + b = (b << 4) + c - '0'; + } else if (isxdigit(c)) { + b = (b << 4) + c - 'A' + 10; + } else { + return NULL; + } + } + *out_byte = b; + return str + 2; +} + +static int +stm32_eth_conf_set(int argc, char **argv, char *val) +{ + uint8_t mac[6]; + int i; + const char *buf = val; + const char *name = argv[0]; + + if (argc != 1) { + return 0; + } + + if (equals(name, "mac")) { + for (i = 0; buf != NULL && i < 6; ++i) { + buf = byte_from_str(buf, &mac[i]); + if (buf == NULL) { + break; + } + if (i < 5 && buf[0] == ':') { + buf++; + } + } + if (i == 6) { + memcpy(stm32_eth_mac_address, mac, 6); + } else { + return -1; + } + } else if (equals(name, "up")) { + CONF_VALUE_SET(val, CONF_BOOL, stm32_eth_auto_up); + } else if (equals(name, "dhcp")) { + CONF_VALUE_SET(val, CONF_BOOL, stm32_eth_dhcp); + } + + return 0; +} + +static int +stm32_eth_conf_commit(void) +{ + return OS_ENOENT; +} + +static int +stm32_eth_conf_export(void (*export_func)(char *name, char *val), + enum conf_export_tgt tgt) +{ + char buf[20]; + + (void)tgt; + + export_func("eth/mac", + format_mac_address(stm32_eth_mac_address, buf, sizeof(buf))); + export_func("eth/up", conf_str_from_value(CONF_BOOL, &stm32_eth_auto_up, + buf, sizeof(buf))); + export_func("eth/dhcp", + conf_str_from_value(CONF_BOOL, &stm32_eth_dhcp, buf, sizeof(buf))); + + return 0; +} + +struct conf_handler stm32_eth_conf = { .ch_name = "eth", + .ch_get = stm32_eth_conf_get, + .ch_commit = stm32_eth_conf_commit, + .ch_set = stm32_eth_conf_set, + .ch_export = stm32_eth_conf_export }; + +/* Register conf handler statically */ +STATIC_CONF_HANDLER(stm32_eth_conf); + +#endif + /* * Hardware configuration. Should be called from BSP init. */ @@ -476,6 +626,10 @@ stm32_eth_open(void) struct netif *nif; struct ip4_addr addr; int rc; + bool up = MYNEWT_VAL(STM32_ETH_SYS_CONFIG) ? stm32_eth_auto_up + : MYNEWT_VAL(STM32_ETH_AUTO_UP); + bool dhcp = MYNEWT_VAL(STM32_ETH_SYS_CONFIG) ? stm32_eth_dhcp + : MYNEWT_VAL(STM32_ETH_DHCP); if (ses->cfg == NULL) { /* @@ -484,7 +638,7 @@ stm32_eth_open(void) return -1; } - stm32_eth_set_hwaddr(MYNEWT_VAL(STM32_MAC_ADDR)); + stm32_eth_set_hwaddr(stm32_eth_mac_address); if (ses->cfg->sec_phy_irq >= 0) { rc = hal_gpio_irq_init(ses->cfg->sec_phy_irq, stm32_phy_isr, ses, @@ -499,5 +653,14 @@ stm32_eth_open(void) nif = netif_add(&ses->st_nif, &addr, &addr, &addr, NULL, stm32_lwip_init, tcpip_input); assert(nif); + + if (up) { + netif_set_up(nif); + netif_set_default(nif); + if (dhcp) { + dhcp_start(nif); + } + } + return 0; } diff --git a/hw/drivers/lwip/stm32_eth/syscfg.yml b/hw/drivers/lwip/stm32_eth/syscfg.yml index 9fc306941f..65ac9f71c4 100644 --- a/hw/drivers/lwip/stm32_eth/syscfg.yml +++ b/hw/drivers/lwip/stm32_eth/syscfg.yml @@ -24,9 +24,30 @@ syscfg.defs: value: 240 STM32_MAC_ADDR: + description: "Use STM32_ETH_MAC_ADDR instead" + defunct: 1 + + STM32_ETH_MAC_ADDR: description: "Use given array of 6 bytes for MAC address." - value: ((uint8_t[6]){0x00, 0x01, 0x01, 0x02, 0x02, 0x03}) + value: 0x00,0x01,0x01,0x02,0x02,0x03 STM32_ETH_RX_BUFFER_CNT: description: "Number of buffers to store RX packets" value: 10 + + STM32_ETH_AUTO_UP: + description: > + When set to 1 interface will be enabled automatically. + value: 1 + + STM32_ETH_DHCP: + description: > + When set to 1 dhcp will be started automatically. + value: 1 + + STM32_ETH_SYS_CONFIG: + description: > + When set to 1 mac address auto up and dhcp settings + are taken from sys/config instead of syscfg. + value: 0 +