Skip to content

Commit 1ba1ec4

Browse files
samples: zbus: add ZBus multidomain UART forwarder sample
Add sample application demonstrating ZBus multidomain communication over UART between two devices. Shows practical usage of shadow channels and proxy agents for inter-domain message forwarding. The sample consists of two devices: - Device A: Acts as request publisher with master request_channel - Device B: Acts as request listener/responder with shadow request_channel Device A publishes periodic requests which are automatically forwarded via UART to Device B. Device B processes requests and sends responses back through the response_channel, demonstrating bidirectional multidomain zbus communication. Key features demonstrated: - ZBUS_MULTIDOMAIN_CHAN_DEFINE for shared conditional channel definitions - ZBUS_PROXY_AGENT_DEFINE for UART backend configuration - Shadow vs master channel behavior - Automatic message forwarding via proxy agents Signed-off-by: Trond F. Christiansen <[email protected]>
1 parent ddf3eea commit 1ba1ec4

File tree

11 files changed

+369
-0
lines changed

11 files changed

+369
-0
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#ifndef COMMON_H
2+
#define COMMON_H
3+
4+
#include <zephyr/zbus/zbus.h>
5+
6+
/* Sample data structures for request and response */
7+
struct request_data {
8+
int request_id;
9+
int min_value;
10+
int max_value;
11+
};
12+
13+
struct response_data {
14+
int response_id;
15+
int value;
16+
};
17+
18+
/* Conditional compilation for device-specific code, needed if channels should be included on a
19+
* subset of applications devices
20+
*/
21+
#if defined(ZBUS_DEVICE_A) || defined(ZBUS_DEVICE_B)
22+
#define include_on_device_a_b 1
23+
#else
24+
#define include_on_device_a_b 0
25+
#endif
26+
27+
/* Define shared channels for request and response
28+
* request_channel is master on device A and shadow on device B
29+
* response_channel is shadow on device A and master on device B
30+
*/
31+
ZBUS_MULTIDOMAIN_CHAN_DEFINE(request_channel, struct request_data, NULL, NULL, ZBUS_OBSERVERS_EMPTY,
32+
ZBUS_MSG_INIT(0), IS_ENABLED(ZBUS_DEVICE_A), include_on_device_a_b);
33+
34+
ZBUS_MULTIDOMAIN_CHAN_DEFINE(response_channel, struct response_data, NULL, NULL,
35+
ZBUS_OBSERVERS_EMPTY, ZBUS_MSG_INIT(0), IS_ENABLED(ZBUS_DEVICE_B),
36+
include_on_device_a_b);
37+
38+
#endif /* COMMON_H */
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#
2+
# Copyright (c) 2025 Nordic Semiconductor ASA
3+
#
4+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
#
6+
7+
cmake_minimum_required(VERSION 3.20.0)
8+
9+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
10+
project(zbus_uart_forwarder_dev_a)
11+
12+
13+
zephyr_library_include_directories(
14+
src
15+
../common
16+
)
17+
18+
# Define which device this is
19+
zephyr_compile_definitions(ZBUS_DEVICE_A=1)
20+
21+
target_sources(app PRIVATE src/main.c)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#
2+
# Copyright (c) 2025 Nordic Semiconductor ASA
3+
#
4+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
#
6+
7+
source "Kconfig.zephyr"
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
*/
6+
7+
&uart1 {
8+
status = "okay";
9+
current-speed = <1000000>;
10+
/delete-property/ hw-flow-control;
11+
};
12+
13+
&uart2 {
14+
compatible = "nordic,nrf-uarte";
15+
status = "okay";
16+
current-speed = <1000000>;
17+
pinctrl-0 = <&uart2_default>;
18+
pinctrl-1 = <&uart2_sleep>;
19+
pinctrl-names = "default", "sleep";
20+
/delete-property/ hw-flow-control;
21+
};
22+
23+
&pinctrl {
24+
uart2_default: uart2_default {
25+
group1 {
26+
psels = <NRF_PSEL(UART_TX, 1, 7)>,
27+
<NRF_PSEL(UART_RTS, 0, 9)>;
28+
};
29+
30+
group2 {
31+
psels = <NRF_PSEL(UART_RX, 1, 6)>,
32+
<NRF_PSEL(UART_CTS, 0, 8)>;
33+
bias-pull-up;
34+
};
35+
};
36+
37+
uart2_sleep: uart2_sleep {
38+
group1 {
39+
psels = <NRF_PSEL(UART_TX, 1, 7)>,
40+
<NRF_PSEL(UART_RX, 1, 6)>,
41+
<NRF_PSEL(UART_RTS, 0, 9)>,
42+
<NRF_PSEL(UART_CTS, 0, 8)>;
43+
low-power-enable;
44+
};
45+
};
46+
};
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Copyright (c) 2025 Nordic Semiconductor ASA
2+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
3+
4+
5+
CONFIG_LOG=y
6+
# CONFIG_LOG_MODE_MINIMAL=y
7+
CONFIG_LOG_DBG_COLOR_BLUE=y
8+
9+
CONFIG_SERIAL=y
10+
CONFIG_UART_ASYNC_API=y
11+
12+
CONFIG_UART_1_NRF_ASYNC_LOW_POWER=y
13+
CONFIG_UART_2_NRF_ASYNC_LOW_POWER=y
14+
15+
CONFIG_ZBUS=y
16+
17+
CONFIG_ZBUS_MULTIDOMAIN=y
18+
CONFIG_ZBUS_MULTIDOMAIN_UART=y
19+
CONFIG_ZBUS_MULTIDOMAIN_LOG_LEVEL_INF=y
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
*/
6+
7+
#include <zephyr/kernel.h>
8+
#include <zephyr/logging/log.h>
9+
#include <string.h>
10+
#include <zephyr/zbus/zbus.h>
11+
#include <zephyr/zbus/multidomain/zbus_multidomain.h>
12+
13+
#include "common.h"
14+
15+
LOG_MODULE_REGISTER(main, LOG_LEVEL_DBG);
16+
17+
/* NOTE: Shared channels request_channel and response_channel are defined in common.h */
18+
19+
/* Set up proxy agent for UART1 and add response channel to be forwarded */
20+
ZBUS_PROXY_AGENT_DEFINE(uart1_proxy, ZBUS_MULTIDOMAIN_TYPE_UART, uart1);
21+
ZBUS_PROXY_ADD_CHANNEL(uart1_proxy, request_channel);
22+
23+
/* Log response data coming from the response channel */
24+
void uart_forwarder_listener_cb(const struct zbus_channel *chan)
25+
{
26+
const struct response_data *data = zbus_chan_const_msg(chan);
27+
28+
LOG_INF("Received message on channel %s", chan->name);
29+
LOG_INF("Response ID: %d, Value: %d", data->response_id, data->value);
30+
}
31+
32+
ZBUS_LISTENER_DEFINE(uart_forwarder_listener, uart_forwarder_listener_cb);
33+
ZBUS_CHAN_ADD_OBS(response_channel, uart_forwarder_listener, 0);
34+
35+
bool print_channel_info(const struct zbus_channel *chan)
36+
{
37+
if (!chan) {
38+
LOG_ERR("Channel is NULL");
39+
return false;
40+
}
41+
LOG_INF("Channel %s is a %s channel", chan->name,
42+
ZBUS_CHANNEL_IS_SHADOW(chan) ? "shadow" : "master");
43+
44+
return true;
45+
}
46+
47+
int main(void)
48+
{
49+
LOG_INF("ZBUS Multidomain UART Forwarder Sample Application");
50+
zbus_iterate_over_channels(print_channel_info);
51+
52+
struct request_data data = {.request_id = 1, .min_value = -1, .max_value = 1};
53+
54+
while (1) {
55+
int ret = zbus_chan_pub(&request_channel, &data, K_MSEC(100));
56+
57+
if (ret < 0) {
58+
LOG_ERR("Failed to publish on channel %s: %d", request_channel.name, ret);
59+
} else {
60+
LOG_INF("Published on channel %s. Request ID=%d, Min=%d, Max=%d",
61+
request_channel.name, data.request_id, data.min_value,
62+
data.max_value);
63+
}
64+
65+
data.request_id++;
66+
data.min_value -= 1;
67+
data.max_value += 1;
68+
k_sleep(K_SECONDS(5));
69+
}
70+
return 0;
71+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#
2+
# Copyright (c) 2025 Nordic Semiconductor ASA
3+
#
4+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
#
6+
7+
cmake_minimum_required(VERSION 3.20.0)
8+
9+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
10+
project(zbus_uart_forwarder_dev_b)
11+
12+
13+
zephyr_library_include_directories(
14+
src
15+
../common
16+
)
17+
18+
# Define which device this is
19+
zephyr_compile_definitions(ZBUS_DEVICE_B=1)
20+
21+
target_sources(app PRIVATE src/main.c)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#
2+
# Copyright (c) 2025 Nordic Semiconductor ASA
3+
#
4+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
#
6+
7+
source "Kconfig.zephyr"
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
*/
6+
7+
&uart1 {
8+
status = "okay";
9+
current-speed = <1000000>;
10+
/delete-property/ hw-flow-control;
11+
};
12+
13+
&uart2 {
14+
compatible = "nordic,nrf-uarte";
15+
status = "okay";
16+
current-speed = <1000000>;
17+
pinctrl-0 = <&uart2_default>;
18+
pinctrl-1 = <&uart2_sleep>;
19+
pinctrl-names = "default", "sleep";
20+
/delete-property/ hw-flow-control;
21+
};
22+
23+
&pinctrl {
24+
uart2_default: uart2_default {
25+
group1 {
26+
psels = <NRF_PSEL(UART_TX, 1, 7)>,
27+
<NRF_PSEL(UART_RTS, 0, 9)>;
28+
};
29+
30+
group2 {
31+
psels = <NRF_PSEL(UART_RX, 1, 6)>,
32+
<NRF_PSEL(UART_CTS, 0, 8)>;
33+
bias-pull-up;
34+
};
35+
};
36+
37+
uart2_sleep: uart2_sleep {
38+
group1 {
39+
psels = <NRF_PSEL(UART_TX, 1, 7)>,
40+
<NRF_PSEL(UART_RX, 1, 6)>,
41+
<NRF_PSEL(UART_RTS, 0, 9)>,
42+
<NRF_PSEL(UART_CTS, 0, 8)>;
43+
low-power-enable;
44+
};
45+
};
46+
};
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Copyright (c) 2025 Nordic Semiconductor ASA
2+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
3+
4+
5+
CONFIG_LOG=y
6+
# CONFIG_LOG_MODE_MINIMAL=y
7+
CONFIG_LOG_DBG_COLOR_BLUE=y
8+
9+
CONFIG_SERIAL=y
10+
CONFIG_UART_ASYNC_API=y
11+
12+
CONFIG_TEST_RANDOM_GENERATOR=y
13+
14+
CONFIG_UART_1_NRF_ASYNC_LOW_POWER=y
15+
CONFIG_UART_2_NRF_ASYNC_LOW_POWER=y
16+
17+
CONFIG_ZBUS=y
18+
19+
CONFIG_ZBUS_MULTIDOMAIN=y
20+
CONFIG_ZBUS_MULTIDOMAIN_UART=y
21+
CONFIG_ZBUS_MULTIDOMAIN_LOG_LEVEL_INF=y

0 commit comments

Comments
 (0)