Skip to content

Commit a1dd846

Browse files
KAGA164rlubos
authored andcommitted
shell: Add the IPC service shell backend
Adds the IPC service backend for the shell interface. NCSDK-13995 Signed-off-by: Kamil Gawor <Kamil.Gawor@nordicsemi.no>
1 parent 8079e3c commit a1dd846

File tree

5 files changed

+316
-2
lines changed

5 files changed

+316
-2
lines changed

include/shell/shell_ipc.h

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright (c) 2022 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
*/
6+
7+
#ifndef SHELL_IPC_H_
8+
#define SHELL_IPC_H_
9+
10+
#include <shell/shell.h>
11+
12+
/**
13+
* @file
14+
* @defgroup shell_ipc IPC service shell transport
15+
* @{
16+
* @brief IPC Service shell transport API.
17+
*/
18+
19+
#ifdef __cplusplus
20+
extern "C" {
21+
#endif
22+
23+
/**
24+
* @brief This function provides a pointer to the shell IPC Service backend instance.
25+
*
26+
* The function returns a pointer to the shell IPC Service instance. This instance can then be
27+
* used with the shell_execute_cmd function to test the behavior of the command.
28+
*
29+
* @returns Pointer to the shell instance.
30+
*/
31+
const struct shell *shell_backend_ipc_get_ptr(void);
32+
33+
#ifdef __cplusplus
34+
}
35+
#endif
36+
37+
/**
38+
*@}
39+
*/
40+
41+
#endif /* SHELL_IPC_H_ */

subsys/CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ if (CONFIG_NFC_T2T_NRFXLIB OR
4747
endif()
4848

4949
add_subdirectory_ifdef(CONFIG_FW_INFO fw_info)
50-
add_subdirectory_ifdef(CONFIG_SHELL_BT_NUS shell)
50+
add_subdirectory(shell)
5151

5252
add_subdirectory(debug)
5353
add_subdirectory(partition_manager)

subsys/shell/CMakeLists.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@
44
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
55
#
66

7-
zephyr_sources(shell_bt_nus.c)
7+
zephyr_sources_ifdef(CONFIG_SHELL_BT_NUS shell_bt_nus.c)
8+
zephyr_sources_ifdef(CONFIG_SHELL_IPC shell_ipc.c)

subsys/shell/Kconfig

+76
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,79 @@ config SHELL_BT_NUS_RX_RING_BUFFER_SIZE
7777
required to increase it.
7878

7979
endif #SHELL_BT_NUS
80+
81+
menuconfig SHELL_IPC
82+
bool "Shell IPC transport"
83+
depends on IPC_SERVICE
84+
select RING_BUFFER
85+
help
86+
Enable Shell IPC transport
87+
88+
if SHELL_IPC
89+
90+
config SHELL_PROMPT_IPC
91+
string "Displayed prompt name"
92+
default "remote_cpu:~$ "
93+
help
94+
Displayed prompt name for IPC service backend.
95+
96+
config SHELL_IPC_ENDPOINT_NAME
97+
string "Shell IPC Service endpoint name"
98+
default "remote shell"
99+
help
100+
Shell IPC Service endpoint name
101+
102+
config SHELL_IPC_BACKEND_RX_RING_BUFFER_SIZE
103+
int "Set RX ring buffer size"
104+
default 64
105+
help
106+
RX ring buffer size impacts accepted latency of handling incoming
107+
bytes by shell. If shell input is coming from the keyboard then it is
108+
usually enough if ring buffer is few bytes (more than one due to
109+
escape sequences). However, if bulk data is transferred it may be
110+
required to increase it.
111+
112+
choice
113+
prompt "Initial log level limit"
114+
default SHELL_IPC_INIT_LOG_LEVEL_DEFAULT
115+
116+
config SHELL_IPC_INIT_LOG_LEVEL_DEFAULT
117+
bool "System limit (LOG_MAX_LEVEL)"
118+
119+
config SHELL_IPC_INIT_LOG_LEVEL_DBG
120+
bool "Debug"
121+
122+
config SHELL_IPC_INIT_LOG_LEVEL_INF
123+
bool "Info"
124+
125+
config SHELL_IPC_INIT_LOG_LEVEL_WRN
126+
bool "Warning"
127+
128+
config SHELL_IPC_INIT_LOG_LEVEL_ERR
129+
bool "Error"
130+
131+
config SHELL_IPC_INIT_LOG_LEVEL_NONE
132+
bool "None"
133+
134+
endchoice
135+
136+
config SHELL_IPC_INIT_LOG_LEVEL
137+
int
138+
default 0 if SHELL_IPC_INIT_LOG_LEVEL_NONE
139+
default 1 if SHELL_IPC_INIT_LOG_LEVEL_ERR
140+
default 2 if SHELL_IPC_INIT_LOG_LEVEL_WRN
141+
default 3 if SHELL_IPC_INIT_LOG_LEVEL_INF
142+
default 4 if SHELL_IPC_INIT_LOG_LEVEL_DBG
143+
default 5 if SHELL_IPC_INIT_LOG_LEVEL_DEFAULT
144+
145+
module = SHELL_IPC
146+
module-str = Shell over the IPC Service
147+
source "${ZEPHYR_BASE}/subsys/logging/Kconfig.template.log_config"
148+
149+
default-timeout = 100
150+
source "${ZEPHYR_BASE}/subsys/shell/Kconfig.template.shell_log_queue_timeout"
151+
152+
default-size = 10
153+
source "${ZEPHYR_BASE}/subsys/shell/Kconfig.template.shell_log_queue_size"
154+
155+
endif #SHELL_IPC

subsys/shell/shell_ipc.c

+196
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
/*
2+
* Copyright (c) 2022 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
*/
6+
7+
#include <device.h>
8+
#include <ipc/ipc_service.h>
9+
#include <shell/shell_ipc.h>
10+
11+
#include <logging/log.h>
12+
13+
LOG_MODULE_REGISTER(shell_ipc, CONFIG_SHELL_IPC_LOG_LEVEL);
14+
15+
RING_BUF_DECLARE(shell_rx_ring_buffer, CONFIG_SHELL_IPC_BACKEND_RX_RING_BUFFER_SIZE);
16+
17+
/* Shell IPC transport API declaration. */
18+
static const struct shell_transport_api shell_ipc_transport_api;
19+
20+
/* Shell IPC instance. */
21+
static struct shell_ipc {
22+
/* IPC Service endpoint configuration. */
23+
struct ipc_ept_cfg ept_cfg;
24+
25+
/* IPC Service endpoint structure. */
26+
struct ipc_ept ept;
27+
28+
/* IPC Service endpoint bond semaphore. */
29+
struct k_sem ept_bond_sem;
30+
31+
/* Shell transport handlers. */
32+
shell_transport_handler_t handler;
33+
34+
/* Shell transport context. */
35+
void *context;
36+
37+
/* Pointer to the Rx ring buffer instance. */
38+
struct ring_buf *rx_ringbuf;
39+
} shell_ipc_transport = {
40+
.rx_ringbuf = &shell_rx_ring_buffer
41+
};
42+
43+
static struct shell_transport shell_transport_ipc = {
44+
.api = &shell_ipc_transport_api,
45+
.ctx = &shell_ipc_transport
46+
};
47+
48+
SHELL_DEFINE(shell_ipc, CONFIG_SHELL_PROMPT_IPC, &shell_transport_ipc,
49+
CONFIG_SHELL_IPC_LOG_MESSAGE_QUEUE_SIZE,
50+
CONFIG_SHELL_IPC_LOG_MESSAGE_QUEUE_TIMEOUT,
51+
SHELL_FLAG_OLF_CRLF);
52+
53+
static void ipc_bound(void *priv)
54+
{
55+
struct shell_ipc *sh_ipc = priv;
56+
57+
LOG_DBG("Shell IPC Service endpoint bonded");
58+
59+
k_sem_give(&sh_ipc->ept_bond_sem);
60+
}
61+
62+
static void ipc_received(const void *data, size_t len, void *priv)
63+
{
64+
struct shell_ipc *sh_ipc = priv;
65+
uint32_t written_bytes;
66+
67+
LOG_DBG("Received %d bytes.", len);
68+
69+
written_bytes = ring_buf_put(sh_ipc->rx_ringbuf, data, len);
70+
if (written_bytes < len) {
71+
LOG_INF("RX ring buffer full. Dropping %d bytes", len - written_bytes);
72+
}
73+
74+
sh_ipc->handler(SHELL_TRANSPORT_EVT_RX_RDY, sh_ipc->context);
75+
}
76+
77+
static struct ipc_service_cb ipc_cb = {
78+
.bound = ipc_bound,
79+
.received = ipc_received
80+
};
81+
82+
static int write(const struct shell_transport *transport,
83+
const void *data, size_t length, size_t *cnt)
84+
{
85+
int err;
86+
struct shell_ipc *sh_ipc = transport->ctx;
87+
88+
err = ipc_service_send(&sh_ipc->ept, data, length);
89+
if (err < 0) {
90+
return err;
91+
}
92+
93+
*cnt = length;
94+
95+
sh_ipc->handler(SHELL_TRANSPORT_EVT_TX_RDY, sh_ipc->context);
96+
97+
return 0;
98+
}
99+
100+
static int read(const struct shell_transport *transport,
101+
void *data, size_t length, size_t *cnt)
102+
{
103+
struct shell_ipc *sh_ipc = transport->ctx;
104+
105+
*cnt = ring_buf_get(sh_ipc->rx_ringbuf, data, length);
106+
107+
return 0;
108+
}
109+
110+
static int init(const struct shell_transport *transport,
111+
const void *config,
112+
shell_transport_handler_t evt_handler,
113+
void *context)
114+
{
115+
int err;
116+
struct shell_ipc *ipc = transport->ctx;
117+
const struct device *dev = config;
118+
119+
ipc->ept_cfg.name = CONFIG_SHELL_IPC_ENDPOINT_NAME;
120+
ipc->ept_cfg.cb = ipc_cb;
121+
ipc->ept_cfg.priv = ipc;
122+
ipc->handler = evt_handler;
123+
ipc->context = context;
124+
125+
err = k_sem_init(&ipc->ept_bond_sem, 0, 1);
126+
if (err) {
127+
return err;
128+
}
129+
130+
err = ipc_service_open_instance(dev);
131+
if (err < 0 && err != -EALREADY) {
132+
LOG_ERR("ipc_service_open_instance() failure\n");
133+
return err;
134+
}
135+
136+
err = ipc_service_register_endpoint(dev, &ipc->ept, &ipc->ept_cfg);
137+
if (err < 0) {
138+
LOG_ERR("ipc_service_register_endpoint() failure\n");
139+
return err;
140+
}
141+
142+
LOG_DBG("Shell IPC Service initialization done");
143+
144+
k_sem_take(&ipc->ept_bond_sem, K_FOREVER);
145+
146+
return 0;
147+
}
148+
149+
static int uninit(const struct shell_transport *transport)
150+
{
151+
ARG_UNUSED(transport);
152+
153+
return 0;
154+
}
155+
156+
static int enable(const struct shell_transport *transport,
157+
bool blocking_tx)
158+
{
159+
ARG_UNUSED(transport);
160+
ARG_UNUSED(blocking_tx);
161+
162+
return 0;
163+
}
164+
165+
static const struct shell_transport_api shell_ipc_transport_api = {
166+
.init = init,
167+
.uninit = uninit,
168+
.enable = enable,
169+
.write = write,
170+
.read = read,
171+
};
172+
173+
static int enable_shell_ipc(const struct device *arg)
174+
{
175+
ARG_UNUSED(arg);
176+
177+
const struct device *dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_shell_ipc));
178+
bool log_backend = CONFIG_SHELL_IPC_INIT_LOG_LEVEL > 0;
179+
uint32_t level = (CONFIG_SHELL_IPC_INIT_LOG_LEVEL > LOG_LEVEL_DBG) ?
180+
CONFIG_LOG_MAX_LEVEL : CONFIG_SHELL_IPC_INIT_LOG_LEVEL;
181+
static const struct shell_backend_config_flags cfg_flags =
182+
SHELL_DEFAULT_BACKEND_CONFIG_FLAGS;
183+
184+
if (!device_is_ready(dev)) {
185+
return -ENODEV;
186+
}
187+
188+
return shell_init(&shell_ipc, dev, cfg_flags, log_backend, level);
189+
}
190+
191+
SYS_INIT(enable_shell_ipc, APPLICATION, 0);
192+
193+
const struct shell *shell_backend_ipc_get_ptr(void)
194+
{
195+
return &shell_ipc;
196+
}

0 commit comments

Comments
 (0)