ipc_service: samples: Add sample that uses icmsg backend

Add sample to demonstrate newly introduced backend (icmsg).

Signed-off-by: Emil Obalski <emil.obalski@nordicsemi.no>
This commit is contained in:
Emil Obalski 2022-03-09 15:30:36 +01:00 committed by Carles Cufí
commit 66a8d5baef
11 changed files with 456 additions and 0 deletions

View file

@ -0,0 +1,32 @@
#
# Copyright (c) 2022 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: Apache-2.0
#
cmake_minimum_required(VERSION 3.20.0)
set(REMOTE_ZEPHYR_DIR ${CMAKE_CURRENT_BINARY_DIR}/ipc_service_remote-prefix/src/ipc_service_remote-build/zephyr)
if("${BOARD}" STREQUAL "nrf5340dk_nrf5340_cpuapp")
set(BOARD_REMOTE "nrf5340dk_nrf5340_cpunet")
else()
message(FATAL_ERROR "${BOARD} is not supported for this sample")
endif()
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(ipc_service_host)
target_sources(app PRIVATE src/main.c)
include(ExternalProject)
ExternalProject_Add(
ipc_service_remote
SOURCE_DIR ${APPLICATION_SOURCE_DIR}/remote
INSTALL_COMMAND "" # This particular build system has no install command
CMAKE_CACHE_ARGS -DBOARD:STRING=${BOARD_REMOTE}
BUILD_BYPRODUCTS "${REMOTE_ZEPHYR_DIR}/${KERNEL_BIN_NAME}"
# NB: Do we need to pass on more CMake variables?
BUILD_ALWAYS True
)

View file

@ -0,0 +1,2 @@
CONFIG_BOARD_ENABLE_CPUNET=y
CONFIG_MBOX_NRFX_IPC=y

View file

@ -0,0 +1,50 @@
/*
* Copyright (c) 2022 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/delete-node/ &ipc0;
/ {
chosen {
/delete-property/ zephyr,ipc_shm;
};
reserved-memory {
/delete-node/ memory@20070000;
sram_tx: memory@20070000 {
reg = <0x20070000 0x0800>;
};
sram_rx: memory@20078000 {
reg = <0x20078000 0x0800>;
};
};
soc {
peripheral@50000000 {
/delete-node/ ipc@2a000;
mbox: mbox@2a000 {
compatible = "nordic,mbox-nrf-ipc";
reg = <0x2a000 0x1000>;
tx-mask = <0x0000ffff>;
rx-mask = <0x0000ffff>;
interrupts = <42 NRF_DEFAULT_IRQ_PRIORITY>;
#mbox-cells = <1>;
status = "okay";
};
};
};
ipc0: ipc0 {
compatible = "zephyr,ipc-icmsg";
tx-region = <&sram_tx>;
rx-region = <&sram_rx>;
mboxes = <&mbox 0>, <&mbox 1>;
mbox-names = "tx", "rx";
status = "okay";
};
};

View file

@ -0,0 +1,7 @@
CONFIG_PRINTK=y
CONFIG_IPC_SERVICE=y
CONFIG_IPC_SERVICE_BACKEND_ICMSG=y
CONFIG_MBOX=y
CONFIG_LOG=y

View file

@ -0,0 +1,12 @@
#
# Copyright (c) 2022 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
#
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(ipc_service_remote)
target_sources(app PRIVATE src/main.c)

View file

@ -0,0 +1 @@
CONFIG_MBOX_NRFX_IPC=y

View file

@ -0,0 +1,48 @@
/*
* Copyright (c) 2022 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/delete-node/ &ipc0;
/ {
chosen {
/delete-property/ zephyr,ipc_shm;
};
reserved-memory {
/delete-node/ memory@20070000;
sram_rx: memory@20070000 {
reg = <0x20070000 0x0800>;
};
sram_tx: memory@20078000 {
reg = <0x20078000 0x0800>;
};
};
soc {
/delete-node/ ipc@41012000;
mbox: mbox@41012000 {
compatible = "nordic,mbox-nrf-ipc";
reg = <0x41012000 0x1000>;
tx-mask = <0x0000ffff>;
rx-mask = <0x0000ffff>;
interrupts = <18 NRF_DEFAULT_IRQ_PRIORITY>;
#mbox-cells = <1>;
status = "okay";
};
};
ipc0: ipc0 {
compatible = "zephyr,ipc-icmsg";
tx-region = <&sram_tx>;
rx-region = <&sram_rx>;
mboxes = <&mbox 0>, <&mbox 1>;
mbox-names = "rx", "tx";
status = "okay";
};
};

View file

@ -0,0 +1,7 @@
CONFIG_PRINTK=y
CONFIG_IPC_SERVICE=y
CONFIG_IPC_SERVICE_BACKEND_ICMSG=y
CONFIG_MBOX=y
CONFIG_LOG=y

View file

@ -0,0 +1,144 @@
/*
* Copyright (c) 2022 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <device.h>
#include <ipc/ipc_service.h>
#include <logging/log.h>
LOG_MODULE_REGISTER(remote, LOG_LEVEL_INF);
#define MLEN_0 40
struct data_packet {
unsigned char message;
unsigned char data[100];
};
K_SEM_DEFINE(bound_sem, 0, 1);
static void ep_bound(void *priv)
{
k_sem_give(&bound_sem);
LOG_INF("Ep bounded");
}
static void ep_recv(const void *data, size_t len, void *priv)
{
char received_data = *((char *)data);
static char expected_message = 'a';
static uint16_t expected_len = MLEN_0;
static unsigned long long cnt;
static unsigned int stats_every;
static uint32_t start;
static unsigned int err;
if (start == 0) {
start = k_uptime_get_32();
}
if (received_data != expected_message) {
err++;
}
if (len != expected_len) {
err++;
}
expected_message++;
expected_len++;
cnt += len;
if (expected_message > 'z') {
if (stats_every++ > 50) {
/* Print throuhput [Bytes/s]. Use printk not to overload CPU with logger.
* Sample never reaches lower priority thread because of high throughput
* (100% cpu load) so logging would not be able to handle messages in
* deferred mode (immediate mode would be heavier than printk).
*/
printk("%llu\n", (1000*cnt)/(k_uptime_get_32() - start));
stats_every = 0;
}
if (err) {
printk("Unexpected message\n");
}
expected_message = 'a';
}
if (expected_len > sizeof(struct data_packet)) {
expected_len = MLEN_0;
}
}
static struct ipc_ept_cfg ep_cfg = {
.cb = {
.bound = ep_bound,
.received = ep_recv,
},
};
int main(void)
{
const struct device *ipc0_instance;
struct data_packet msg = {.message = 'A'};
struct ipc_ept ep;
int ret;
LOG_INF("IPC-service REMOTE demo started");
ipc0_instance = DEVICE_DT_GET(DT_NODELABEL(ipc0));
ret = ipc_service_open_instance(ipc0_instance);
if ((ret < 0) && (ret != -EALREADY)) {
LOG_INF("ipc_service_open_instance() failure");
return ret;
}
ret = ipc_service_register_endpoint(ipc0_instance, &ep, &ep_cfg);
if (ret < 0) {
printf("ipc_service_register_endpoint() failure");
return ret;
}
k_sem_take(&bound_sem, K_FOREVER);
uint16_t mlen = MLEN_0;
while (true) {
ret = ipc_service_send(&ep, &msg, mlen);
if (ret == -ENOMEM) {
/* No space in the buffer. Retry. */
continue;
} else if (ret < 0) {
LOG_ERR("send_message(%d) failed with ret %d", msg.message, ret);
break;
}
msg.message++;
if (msg.message > 'Z') {
msg.message = 'A';
}
mlen++;
if (mlen > sizeof(struct data_packet)) {
mlen = MLEN_0;
}
/* Quasi minimal busy wait time which allows to continuosly send
* data without -ENOMEM error code. The purpose is to test max
* throughput. Determined experimentally.
*/
k_busy_wait(50);
}
LOG_INF("IPC-service REMOTE demo ended.");
return 0;
}

View file

@ -0,0 +1,9 @@
sample:
name: IPC Service example integration (icmsg backend)
tests:
sample.ipc.icmsg:
platform_allow: nrf5340dk_nrf5340_cpuapp
integration_platforms:
- nrf5340dk_nrf5340_cpuapp
tags: ipc
build_only: true

View file

@ -0,0 +1,144 @@
/*
* Copyright (c) 2022 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <device.h>
#include <ipc/ipc_service.h>
#include <logging/log.h>
LOG_MODULE_REGISTER(host, LOG_LEVEL_INF);
#define MLEN_0 40
struct data_packet {
unsigned char message;
unsigned char data[100];
};
K_SEM_DEFINE(bound_sem, 0, 1);
static void ep_bound(void *priv)
{
k_sem_give(&bound_sem);
LOG_INF("Ep bounded");
}
static void ep_recv(const void *data, size_t len, void *priv)
{
char received_data = *((char *)data);
static char expected_message = 'A';
static uint16_t expected_len = MLEN_0;
static unsigned long long cnt;
static unsigned int stats_every;
static uint32_t start;
static unsigned int err;
if (start == 0) {
start = k_uptime_get_32();
}
if (received_data != expected_message) {
err++;
}
if (len != expected_len) {
err++;
}
expected_message++;
expected_len++;
cnt += len;
if (expected_message > 'Z') {
if (stats_every++ > 50) {
/* Print throuhput [Bytes/s]. Use printk not to overload CPU with logger.
* Sample never reaches lower priority thread because of high throughput
* (100% cpu load) so logging would not be able to handle messages in
* deferred mode (immediate mode would be heavier than printk).
*/
printk("%llu\n", (1000*cnt)/(k_uptime_get_32() - start));
stats_every = 0;
}
if (err) {
printk("Unexpected message\n");
}
expected_message = 'A';
}
if (expected_len > sizeof(struct data_packet)) {
expected_len = MLEN_0;
}
}
static struct ipc_ept_cfg ep_cfg = {
.cb = {
.bound = ep_bound,
.received = ep_recv,
},
};
int main(void)
{
const struct device *ipc0_instance;
struct data_packet msg = {.message = 'a'};
struct ipc_ept ep;
int ret;
LOG_INF("IPC-service HOST demo started");
ipc0_instance = DEVICE_DT_GET(DT_NODELABEL(ipc0));
ret = ipc_service_open_instance(ipc0_instance);
if ((ret < 0) && (ret != -EALREADY)) {
LOG_INF("ipc_service_open_instance() failure");
return ret;
}
ret = ipc_service_register_endpoint(ipc0_instance, &ep, &ep_cfg);
if (ret < 0) {
printf("ipc_service_register_endpoint() failure");
return ret;
}
k_sem_take(&bound_sem, K_FOREVER);
uint16_t mlen = MLEN_0;
while (true) {
ret = ipc_service_send(&ep, &msg, mlen);
if (ret == -ENOMEM) {
/* No space in the buffer. Retry. */
continue;
} else if (ret < 0) {
LOG_ERR("send_message(%d) failed with ret %d", msg.message, ret);
break;
}
msg.message++;
if (msg.message > 'z') {
msg.message = 'a';
}
mlen++;
if (mlen > sizeof(struct data_packet)) {
mlen = MLEN_0;
}
/* Quasi minimal busy wait time which allows to continuosly send
* data without -ENOMEM error code. The purpose is to test max
* throughput. Determined experimentally.
*/
k_busy_wait(100);
}
LOG_INF("IPC-service HOST demo ended.");
return 0;
}