Repository navigation
Description
@jbenedictocenteno, for you to look at and decide; nothing is in a branch.
What failed
KodeOS does not build with CONFIG_KODEOS_RADIO=n, which is how kode-sim (the Kode Dot simulator on Espressif's esp-emu) builds it: there is no C5 in the emulator, so it leaves the radio out. On the board nothing changes, as the radio is always on there.
- Host: macOS 26 (Apple silicon). ESP-IDF: v6.1.
- Revisions: KodeOS
developdb93026, itssdk/at 21029b6. - Build: KodeOS's own
sdkconfig.defaultsplusCONFIG_KODEOS_RADIO=n(andCONFIG_KODE_TEST_DOT=n, whose#errorsays it needs the radio).
Output
Compiling components/kgui/kgui_ao.c:
kgui_ao.c:24726:36: error: implicit declaration of function 'gui_radio_words'
kgui_ao.c:24738:40: error: format '%s' expects argument of type 'char *', but argument 4 has type 'int'
kgui_ao.c:3245:13: error: 'gui_ble_name_send' used but never defined [-Werror]
With those two fixed, the link:
undefined reference to `radio_boot_hold' (Gui_initial)
undefined reference to `radio_boot_release' (gui_keep_gate)
undefined reference to `net_http_ask' (gui_os_ask)
undefined reference to `net_stream_open_request', `net_stream_read_request',
`net_stream_return', `net_stream_close_request', `net_stream_buf' (kgui_assets.c, gather*)
Why
kgui calls the radio's and AO_Net's API outside the guards their own sources are built under. kaos/CMakeLists.txt builds radio_ao.c only with CONFIG_KODEOS_RADIO, and net_ao.c only with RADIO, WIFI and NET. kaos.h says so next to the radio calls ("Compiled under CONFIG_KODEOS_RADIO; guard the call the same way"). In kgui:
gui_radio_words()is defined underCONFIG_KODEOS_WIFI, butgui_more_value()uses it for the Wi-Fi and Bluetooth rows of "More" with no guard.gui_ble_name_send()is defined underCONFIG_KODEOS_BLE; its prototype and its call inGui_running(theble_name_owedsend) are not guarded.radio_boot_hold()andradio_boot_release()are called with no guard.gui_os_ask()callsnet_http_ask(), andkgui_assets.c's gatherer callsnet_stream_*(), with no guard.
How it can be solved
Guard each call as its definition is guarded, with an answer for a build without it:
- More's Wi-Fi and Bluetooth rows: "Off" without
KODEOS_WIFIorKODEOS_BLE. - The BLE name: prototypes and the send under
KODEOS_BLE. - The boot hold and release: under
KODEOS_RADIO. - The update check: without
KODEOS_NET,gui_os_failed(me, "built without the network"). - The gatherer: without
KODEOS_NET, a URL fails at once (gather_fail(KODE_DENIED)); the close, read, buffer and return branches for a stream are underKODEOS_NET.
The words "Off" and "built without the network" are a suggestion. 35 lines in two files; the diff below is what I tried.
Tested
With this diff and the display fix in kodediy/kode-sdk#122 (kdrv's drain after a panel read, which otherwise hangs the display task with no DSI host), KodeOS builds without the radio. kode-sim's emulator suite then passes 25 of 25 on it:
- it boots to its UI;
- installs an app over the console (
install src="terminal") and goes home by the held button and by reset, with the glass kept lit; - mounts the card;
- the battery and ship mode;
- the clock with no network;
review.
Not run: tools/ checks of KodeOS (size, layers, MISRA), and anything on a board, where this changes nothing.
The diff (against develop db93026)
diff --git a/components/kgui/kgui_ao.c b/components/kgui/kgui_ao.c
index c093ac5..d9b2656 100644
--- a/components/kgui/kgui_ao.c
+++ b/components/kgui/kgui_ao.c
@@ -3241,9 +3241,11 @@ static void gui_more_fill(Gui * const me);
static void gui_time_fill(Gui * const me);
static void gui_time_follow(Gui * const me);
static uint32_t gui_time_minute(Gui const * const me, struct tm *out);
+#if CONFIG_KODEOS_BLE
static const char *gui_ble_name_shown(Gui const * const me);
static void gui_ble_name_send(Gui const * const me);
static void gui_ble_name_config(Gui * const me, KodeConfigReqEvt const * const r);
+#endif
static bool gui_row_cut(Gui const * const me, int32_t cy, kgui_rail_t const *edge);
static void gui_vol_motor(Gui const * const me);
static void gui_first_hold_tick(Gui * const me);
@@ -12065,7 +12067,9 @@ static void gui_keep_gate(Gui * const me)
&& ((uint8_t)GUI_KEEP_READ_NONE == me->keep_read) )
{
me->keep_gate_open = true;
+#if CONFIG_KODEOS_RADIO
radio_boot_release();
+#endif
}
}
@@ -24595,6 +24599,7 @@ static void gui_os_ask(Gui * const me, const char *why)
gui_os_failed(me, "no memory for the answer");
return;
}
+#if CONFIG_KODEOS_NET
if ( net_http_ask(&me->super, false, GUI_OS_SERVICE, NULL, 0U, NULL,
me->os->answer, KGUI_OSREL_ANSWER_MAX) == KODE_OK )
{
@@ -24605,6 +24610,10 @@ static void gui_os_ask(Gui * const me, const char *why)
{
gui_os_failed(me, "AO_Net did not take the question");
}
+#else
+ (void)why;
+ gui_os_failed(me, "built without the network");
+#endif
}
/**
@@ -24723,6 +24732,7 @@ static void gui_more_value(Gui const * const me, uint8_t which, char *out,
break;
}
case GUI_MORE_WIFI: {
+#if CONFIG_KODEOS_WIFI
const char * const w = gui_radio_words(me, me->wifi_on, me->wifi_linked,
me->wifi_reconnecting);
const char *say = me->wifi_ssid;
@@ -24732,10 +24742,17 @@ static void gui_more_value(Gui const * const me, uint8_t which, char *out,
say = w;
}
(void)snprintf(out, cap, "%s", say);
+#else
+ (void)snprintf(out, cap, "%s", "Off"); /* built without Wi-Fi */
+#endif
break;
}
case GUI_MORE_BLE: {
+#if CONFIG_KODEOS_BLE
(void)snprintf(out, cap, "%s", gui_radio_words(me, me->ble_on, false, false));
+#else
+ (void)snprintf(out, cap, "%s", "Off"); /* built without Bluetooth */
+#endif
break;
}
case GUI_MORE_TIME: {
@@ -33389,7 +33406,9 @@ static QState Gui_initial(Gui * const me, void const * const par)
{
kgui_assets_start();
}
+#if CONFIG_KODEOS_RADIO
radio_boot_hold();
+#endif
/* The name chosen for Bluetooth: the radio keeps it for its adverts. It
* is sent once every owner has its queue (GUI_TICK_SIG): this AO starts
* in kode_init()'s early row, before AO_Radio, and a post to an AO with
@@ -33670,11 +33689,13 @@ static QState Gui_running(Gui * const me, QEvt const * const e)
me->settings_owed = false;
gui_settings_ask();
}
+#if CONFIG_KODEOS_BLE
if ( me->ble_name_owed && kode_up() )
{
me->ble_name_owed = false;
gui_ble_name_send(me);
}
+#endif
/* The long step of the whole system, which is why AO_Gui sits
* near the bottom of the priority list, with only AO_Net below
* it: a repaint spends most of its time blocked inside LVGL
diff --git a/components/kgui/kgui_assets.c b/components/kgui/kgui_assets.c
index b58415e..0dde167 100644
--- a/components/kgui/kgui_assets.c
+++ b/components/kgui/kgui_assets.c
@@ -471,6 +471,8 @@ static void say_source(bool state)
/* ---- The gatherer: one file, read whole, into one PSRAM block --------------- */
+static void gather_fail(kode_status_t rc);
+
/**
* @brief Start reading a whole file from a path or a URL.
* @param net true for a URL (AO_Net's stream), false for a path.
@@ -492,7 +494,11 @@ static void gather(bool net, const char *where, uint32_t limit)
s_a.g_probing = false;
if ( net )
{
+#if CONFIG_KODEOS_NET
net_stream_open_request(s_a.g_where, s_a.ao);
+#else
+ gather_fail(KODE_DENIED); /* built without the network: no URL opens */
+#endif
}
else
{
@@ -503,11 +509,13 @@ static void gather(bool net, const char *where, uint32_t limit)
/** @brief Close the gather's file or stream; buffers on loan go back with it. */
static void gather_close(void)
{
+#if CONFIG_KODEOS_NET
if ( s_a.g_net )
{
net_stream_close_request();
}
else
+#endif
{
storage_close_request();
}
@@ -569,11 +577,13 @@ static void gather_opened(StorageOpenRspEvt const * const r)
gather_fail(KODE_NO_RESOURCES);
return;
}
+#if CONFIG_KODEOS_NET
if ( s_a.g_net )
{
net_stream_read_request();
}
else
+#endif
{
storage_read_request();
}
@@ -624,11 +634,13 @@ static void gather_data(StorageDataEvt const * const d)
{
const uint8_t *src = NULL;
+#if CONFIG_KODEOS_NET
if ( s_a.g_net )
{
src = net_stream_buf(d->idx);
}
else
+#endif
{
src = storage_buf(d->idx);
}
@@ -655,10 +667,12 @@ static void gather_data(StorageDataEvt const * const d)
s_a.op = OP_NONE;
post_result(KODE_OK, true);
}
+#if CONFIG_KODEOS_NET
else if ( s_a.g_net )
{
net_stream_return(d->idx); /* a return IS the next read */
}
+#endif
else
{
storage_next_request(d->idx);
Activity