Each module's thread follows the same pattern of waiting for new messages and handling them by executing a state machine. For example, a simplified version of the Network module's thread looks like this:
static void network_module(void)
{
int err;
int task_wdt_id;
const uint32_t wdt_timeout_ms =
(CONFIG_APP_NETWORK_WATCHDOG_TIMEOUT_SECONDS * MSEC_PER_SEC);
const uint32_t execution_time_ms =
(CONFIG_APP_NETWORK_MSG_PROCESSING_TIMEOUT_SECONDS * MSEC_PER_SEC);
const k_timeout_t zbus_wait = K_MSEC(wdt_timeout_ms - execution_time_ms);
task_wdt_id = task_wdt_add(wdt_timeout_ms, network_wdt_callback, (void *)k_current_get());
/* Initialize the state machine to the initial state */
smf_set_initial(SMF_CTX(&network_state), &states[STATE_DISCONNECTED]);
while (true) {
/* Feed the watchdog before blocking on the next message */
err = task_wdt_feed(task_wdt_id);
/* Wait for a message on any subscribed channel */
err = zbus_sub_wait_msg(&network, &network_state.chan,
network_state.msg_buf, zbus_wait);
if (err == -ENOMSG) {
continue;
} else if (err) {
LOG_ERR("zbus_sub_wait_msg, error: %d", err);
FATAL_ERROR();
}
/* Run the state machine with the received message */
err = smf_run_state(SMF_CTX(&network_state));
if (err) {
LOG_ERR("smf_run_state(), error: %d", err);
FATAL_ERROR();
}
}
}
In this pattern:
- The thread feeds its task watchdog, then waits for a message using
zbus_sub_wait_msg(). - When a message arrives, it is stored in the state object's buffer along with the channel it was received on.
- The state machine is then executed with
smf_run_state(), which calls the appropriate handler for the current state. - The handler processes the message based on its type and the current state, potentially triggering state transitions.
- The loop continues, waiting for the next message.
The wait is bounded rather than K_FOREVER so that the watchdog is fed even when no messages arrive. The timeout is the watchdog timeout minus the time budgeted for processing a single message, which leaves room for the longest possible message handling before the watchdog expires. A timeout returns -ENOMSG, which simply restarts the loop.