This section demonstrates how to add a new event to a module and handle it in another. In this example, you add events to the UART Power Control module to notify the system when VBUS is connected or disconnected on the Thingy:91 X. The Main module subscribes to these events and requests specific LED patterns from the LED module in response:
- When VBUS is connected, the LED blinks white rapidly.
- When VBUS is disconnected, the LED blinks purple slowly.
To add a new zbus event, complete the following procedure:
-
Create a header for the new channel and message type at
app/src/modules/uart_power_control/uart_power_control.h.#ifndef UART_POWER_CONTROL_H_ #define UART_POWER_CONTROL_H_ #include <zephyr/zbus/zbus.h> enum vbus_msg_type { /* VBUS power supply is connected. */ VBUS_CONNECTED, /* VBUS power supply is disconnected. */ VBUS_DISCONNECTED, }; struct vbus_msg { enum vbus_msg_type type; }; ZBUS_CHAN_DECLARE(vbus_chan); #endif /* UART_POWER_CONTROL_H_ */ -
Define the channel and publish events from the existing
event_callback()function inapp/src/modules/uart_power_control/uart_power_control.c. Add the include and channel definition near the top of the file:#include "uart_power_control.h" #include "app_common.h" ZBUS_CHAN_DEFINE(vbus_chan, struct vbus_msg, NULL, NULL, ZBUS_OBSERVERS_EMPTY, ZBUS_MSG_INIT(0));Then publish the events from inside
event_callback():if (pins & BIT(NPM13XX_EVENT_VBUS_DETECTED)) { LOG_DBG("VBUS detected"); vbus_present = true; struct vbus_msg msg = { .type = VBUS_CONNECTED }; int pub_err = zbus_chan_pub(&vbus_chan, &msg, PUB_TIMEOUT); if (pub_err) { LOG_ERR("zbus_chan_pub, error: %d", pub_err); SEND_FATAL_ERROR(); } // ... existing code ... } if (pins & BIT(NPM13XX_EVENT_VBUS_REMOVED)) { LOG_DBG("VBUS removed"); vbus_present = false; struct vbus_msg msg = { .type = VBUS_DISCONNECTED }; int pub_err = zbus_chan_pub(&vbus_chan, &msg, PUB_TIMEOUT); if (pub_err) { LOG_ERR("zbus_chan_pub, error: %d", pub_err); SEND_FATAL_ERROR(); } // ... existing code ... } -
Make sure the channel is observed by the subscriber module. In
app/src/main.c, addvbus_chanto theCHANNEL_LISTso it is gated byCONFIG_APP_UART_POWER_CONTROL:#include "uart_power_control.h" #define CHANNEL_LIST(X) \ X(cloud_chan, struct cloud_msg) \ X(fota_chan, struct fota_msg) \ X(network_chan, struct network_msg) \ X(location_chan, struct location_msg) \ X(storage_chan, struct storage_msg) \ X(timer_chan, struct timer_msg) \ X(priv_main_chan, struct priv_main_msg) \ IF_ENABLED(CONFIG_APP_BUTTON, (X(button_chan, struct button_msg))) \ IF_ENABLED(CONFIG_APP_POWER, (X(power_chan, struct power_msg))) \ IF_ENABLED(CONFIG_APP_UART_POWER_CONTROL, (X(vbus_chan, struct vbus_msg)))If you are subscribing from a different module, add the channel to that module's
CHANNEL_LISTinstead. -
Implement a handler for the new events in the subscriber module. For example, add the following block to the
running_run()state handler inapp/src/main.c:if (state_object->chan == &vbus_chan) { const struct vbus_msg *msg = (const struct vbus_msg *)state_object->msg_buf; if (msg->type == VBUS_CONNECTED) { LOG_DBG("VBUS connected, request white LED blinking rapidly for 10 seconds"); struct led_msg led_msg = { .type = LED_RGB_SET, .red = 255, .green = 255, .blue = 255, .duration_on_msec = 300, .duration_off_msec = 300, .repetitions = 10, }; int err = zbus_chan_pub(&led_chan, &led_msg, PUB_TIMEOUT); if (err) { LOG_ERR("zbus_chan_pub, error: %d", err); SEND_FATAL_ERROR(); } return SMF_EVENT_HANDLED; } else if (msg->type == VBUS_DISCONNECTED) { LOG_DBG("VBUS disconnected, request purple LED blinking slowly for 10 seconds"); struct led_msg led_msg = { .type = LED_RGB_SET, .red = 255, .green = 0, .blue = 255, .duration_on_msec = 1000, .duration_off_msec = 700, .repetitions = 10, }; int err = zbus_chan_pub(&led_chan, &led_msg, PUB_TIMEOUT); if (err) { LOG_ERR("zbus_chan_pub, error: %d", err); SEND_FATAL_ERROR(); } return SMF_EVENT_HANDLED; } } -
Test the implementation by connecting and disconnecting VBUS to verify the LED patterns change as expected.