Skip to content

Commit 8587bb1

Browse files
Mierunskinashif
authored andcommitted
smp: shell: Add support for SMP in new shell.
Added smp support for new shell. Signed-off-by: Mieszko Mierunski <[email protected]>
1 parent 1d033a9 commit 8587bb1

File tree

7 files changed

+219
-20
lines changed

7 files changed

+219
-20
lines changed

include/mgmt/smp_shell.h

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright (c) 2019 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/** @file
8+
* @brief Shell transport for the mcumgr SMP protocol.
9+
*/
10+
11+
#ifndef ZEPHYR_INCLUDE_MGMT_SMP_SHELL_H_
12+
#define ZEPHYR_INCLUDE_MGMT_SMP_SHELL_H_
13+
14+
#include <zephyr/types.h>
15+
16+
#ifdef __cplusplus
17+
extern "C" {
18+
#endif
19+
20+
/** @brief Data used by SMP shell */
21+
struct smp_shell_data {
22+
char mcumgr_buff[128];
23+
bool cmd_rdy;
24+
atomic_t esc_state;
25+
u32_t cur;
26+
u32_t end;
27+
};
28+
29+
/**
30+
* @brief Attempts to process a received byte as part of an SMP frame.
31+
*
32+
* This function should be called with every received byte.
33+
*
34+
* @param data SMP shell transfer data.
35+
* @param byte The byte just received.
36+
*
37+
* @return true if the command being received is an mcumgr frame; false if it
38+
* is a plain shell command.
39+
*/
40+
bool smp_shell_rx_byte(struct smp_shell_data *data, uint8_t byte);
41+
42+
/**
43+
* @brief Processes SMP data and executes command if full frame was received.
44+
*
45+
* This function should be called from thread context.
46+
*
47+
* @param data SMP shell transfer data.
48+
*/
49+
void smp_shell_process(struct smp_shell_data *data);
50+
51+
#ifdef __cplusplus
52+
}
53+
#endif
54+
55+
#endif

include/shell/shell.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,15 @@ struct shell_transport_api {
330330
int (*read)(const struct shell_transport *transport,
331331
void *data, size_t length, size_t *cnt);
332332

333+
/**
334+
* @brief Function called in shell thread loop.
335+
*
336+
* Can be used for backend operations that require longer execution time
337+
*
338+
* @param[in] transport Pointer to the transfer instance.
339+
*/
340+
void (*update)(const struct shell_transport *transport);
341+
333342
};
334343

335344
struct shell_transport {

include/shell/shell_uart.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
#include <shell/shell.h>
1111
#include <ring_buffer.h>
1212
#include <atomic.h>
13+
#ifdef CONFIG_MCUMGR_SMP_SHELL
14+
#include "mgmt/smp_shell.h"
15+
#endif
1316

1417
#ifdef __cplusplus
1518
extern "C" {
@@ -24,6 +27,9 @@ struct shell_uart_ctrl_blk {
2427
void *context;
2528
atomic_t tx_busy;
2629
bool blocking;
30+
#ifdef CONFIG_MCUMGR_SMP_SHELL
31+
struct smp_shell_data smp;
32+
#endif /* CONFIG_MCUMGR_SMP_SHELL */
2733
};
2834

2935
#ifdef CONFIG_SHELL_BACKEND_SERIAL_INTERRUPT_DRIVEN

subsys/mgmt/Kconfig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ config MCUMGR_SMP_BT
1919
config MCUMGR_SMP_SHELL
2020
bool "Shell mcumgr SMP transport"
2121
select MCUMGR
22-
select UART_CONSOLE_MCUMGR
23-
select CONSOLE_SHELL
22+
select SHELL
23+
select SHELL_BACKEND_SERIAL
2424
select BASE64
2525
help
2626
Enables handling of SMP commands received over shell. This allows

subsys/mgmt/smp_shell.c

Lines changed: 104 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,30 +17,120 @@
1717
#include "mgmt/serial.h"
1818
#include "mgmt/buf.h"
1919
#include "mgmt/smp.h"
20-
21-
struct device;
20+
#include "mgmt/smp_shell.h"
2221

2322
static struct zephyr_smp_transport smp_shell_transport;
2423

2524
static struct mcumgr_serial_rx_ctxt smp_shell_rx_ctxt;
2625

27-
/**
28-
* Processes a single line (i.e., a single SMP frame)
29-
*/
30-
static int smp_shell_rx_line(const char *line, void *arg)
26+
/** SMP mcumgr frame fragments. */
27+
enum smp_shell_esc_mcumgr {
28+
ESC_MCUMGR_PKT_1,
29+
ESC_MCUMGR_PKT_2,
30+
ESC_MCUMGR_FRAG_1,
31+
ESC_MCUMGR_FRAG_2,
32+
};
33+
34+
/** These states indicate whether an mcumgr frame is being received. */
35+
enum smp_shell_mcumgr_state {
36+
SMP_SHELL_MCUMGR_STATE_NONE,
37+
SMP_SHELL_MCUMGR_STATE_HEADER,
38+
SMP_SHELL_MCUMGR_STATE_PAYLOAD
39+
};
40+
41+
static int read_mcumgr_byte(struct smp_shell_data *data, u8_t byte)
42+
{
43+
bool frag_1;
44+
bool frag_2;
45+
bool pkt_1;
46+
bool pkt_2;
47+
48+
pkt_1 = atomic_test_bit(&data->esc_state, ESC_MCUMGR_PKT_1);
49+
pkt_2 = atomic_test_bit(&data->esc_state, ESC_MCUMGR_PKT_2);
50+
frag_1 = atomic_test_bit(&data->esc_state, ESC_MCUMGR_FRAG_1);
51+
frag_2 = atomic_test_bit(&data->esc_state, ESC_MCUMGR_FRAG_2);
52+
53+
if (pkt_2 || frag_2) {
54+
/* Already fully framed. */
55+
return SMP_SHELL_MCUMGR_STATE_PAYLOAD;
56+
}
57+
58+
if (pkt_1) {
59+
if (byte == MCUMGR_SERIAL_HDR_PKT_2) {
60+
/* Final framing byte received. */
61+
atomic_set_bit(&data->esc_state, ESC_MCUMGR_PKT_2);
62+
return SMP_SHELL_MCUMGR_STATE_PAYLOAD;
63+
}
64+
} else if (frag_1) {
65+
if (byte == MCUMGR_SERIAL_HDR_FRAG_2) {
66+
/* Final framing byte received. */
67+
atomic_set_bit(&data->esc_state, ESC_MCUMGR_FRAG_2);
68+
return SMP_SHELL_MCUMGR_STATE_PAYLOAD;
69+
}
70+
} else {
71+
if (byte == MCUMGR_SERIAL_HDR_PKT_1) {
72+
/* First framing byte received. */
73+
atomic_set_bit(&data->esc_state, ESC_MCUMGR_PKT_1);
74+
return SMP_SHELL_MCUMGR_STATE_HEADER;
75+
} else if (byte == MCUMGR_SERIAL_HDR_FRAG_1) {
76+
/* First framing byte received. */
77+
atomic_set_bit(&data->esc_state, ESC_MCUMGR_FRAG_1);
78+
return SMP_SHELL_MCUMGR_STATE_HEADER;
79+
}
80+
}
81+
82+
/* Non-mcumgr byte received. */
83+
return SMP_SHELL_MCUMGR_STATE_NONE;
84+
}
85+
86+
bool smp_shell_rx_byte(struct smp_shell_data *data, uint8_t byte)
3187
{
32-
struct net_buf *nb;
33-
int line_len;
88+
int mcumgr_state;
3489

35-
/* Strip the trailing newline. */
36-
line_len = strlen(line) - 1;
90+
mcumgr_state = read_mcumgr_byte(data, byte);
91+
if (mcumgr_state == SMP_SHELL_MCUMGR_STATE_NONE) {
92+
/* Not an mcumgr command; let the shell process the byte. */
93+
return false;
94+
}
3795

38-
nb = mcumgr_serial_process_frag(&smp_shell_rx_ctxt, line, line_len);
39-
if (nb != NULL) {
40-
zephyr_smp_rx_req(&smp_shell_transport, nb);
96+
/*
97+
* The received byte is part of an mcumgr command. Process the byte
98+
* and return true to indicate that shell should ignore it.
99+
*/
100+
if (data->cur + data->end < sizeof(data->mcumgr_buff) - 1) {
101+
data->mcumgr_buff[data->cur++] = byte;
102+
}
103+
if (mcumgr_state == SMP_SHELL_MCUMGR_STATE_PAYLOAD && byte == '\n') {
104+
data->mcumgr_buff[data->cur + data->end] = '\0';
105+
data->cmd_rdy = true;
106+
atomic_clear_bit(&data->esc_state, ESC_MCUMGR_PKT_1);
107+
atomic_clear_bit(&data->esc_state, ESC_MCUMGR_PKT_2);
108+
atomic_clear_bit(&data->esc_state, ESC_MCUMGR_FRAG_1);
109+
atomic_clear_bit(&data->esc_state, ESC_MCUMGR_FRAG_2);
110+
data->cur = 0U;
111+
data->end = 0U;
41112
}
42113

43-
return 0;
114+
return true;
115+
}
116+
117+
void smp_shell_process(struct smp_shell_data *data)
118+
{
119+
if (data->cmd_rdy) {
120+
data->cmd_rdy = false;
121+
struct net_buf *nb;
122+
int line_len;
123+
124+
/* Strip the trailing newline. */
125+
line_len = strlen(data->mcumgr_buff) - 1;
126+
127+
nb = mcumgr_serial_process_frag(&smp_shell_rx_ctxt,
128+
data->mcumgr_buff,
129+
line_len);
130+
if (nb != NULL) {
131+
zephyr_smp_rx_req(&smp_shell_transport, nb);
132+
}
133+
}
44134
}
45135

46136
static u16_t smp_shell_get_mtu(const struct net_buf *nb)
@@ -72,7 +162,6 @@ static int smp_shell_init(struct device *dev)
72162

73163
zephyr_smp_transport_init(&smp_shell_transport, smp_shell_tx_pkt,
74164
smp_shell_get_mtu, NULL, NULL);
75-
shell_register_mcumgr_handler(smp_shell_rx_line, NULL);
76165

77166
return 0;
78167
}

subsys/shell/shell.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1216,6 +1216,9 @@ void shell_thread(void *shell_handle, void *arg_log_backend,
12161216
}
12171217

12181218
while (true) {
1219+
if (shell->iface->api->update) {
1220+
shell->iface->api->update(shell->iface);
1221+
}
12191222
int num_events = (shell->ctx->state != SHELL_STATE_COMMAND) ?
12201223
SHELL_SIGNALS : SHELL_SIGNAL_TXDONE;
12211224

subsys/shell/shell_uart.c

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,30 @@ static void uart_rx_handle(const struct shell_uart *sh_uart)
4141
if (len) {
4242
rd_len = uart_fifo_read(sh_uart->ctrl_blk->dev,
4343
data, len);
44-
44+
#ifdef CONFIG_MCUMGR_SMP_SHELL
45+
/* Divert bytes from shell handling if it is
46+
* part of an mcumgr frame.
47+
*/
48+
size_t i;
49+
50+
for (i = 0; i < rd_len; i++) {
51+
if (!smp_shell_rx_byte(&sh_uart->ctrl_blk->smp,
52+
data[i])) {
53+
break;
54+
}
55+
}
56+
rd_len -= i;
4557
if (rd_len) {
4658
new_data = true;
59+
for (u32_t j = 0; j < rd_len; j++) {
60+
data[j] = data[i + j];
61+
}
4762
}
48-
63+
#else
64+
if (rd_len) {
65+
new_data = true;
66+
}
67+
#endif /* CONFIG_MCUMGR_SMP_SHELL */
4968
ring_buf_put_finish(sh_uart->rx_ringbuf, rd_len);
5069
} else {
5170
u8_t dummy;
@@ -55,6 +74,12 @@ static void uart_rx_handle(const struct shell_uart *sh_uart)
5574

5675
rd_len = uart_fifo_read(sh_uart->ctrl_blk->dev,
5776
&dummy, 1);
77+
#ifdef CONFIG_MCUMGR_SMP_SHELL
78+
/* Divert this byte from shell handling if it
79+
* is part of an mcumgr frame.
80+
*/
81+
smp_shell_rx_byte(&sh_uart->ctrl_blk->smp, dummy);
82+
#endif /* CONFIG_MCUMGR_SMP_SHELL */
5883
}
5984
} while (rd_len && (rd_len == len));
6085

@@ -219,12 +244,24 @@ static int read(const struct shell_transport *transport,
219244
return 0;
220245
}
221246

247+
#ifdef CONFIG_MCUMGR_SMP_SHELL
248+
static void update(const struct shell_transport *transport)
249+
{
250+
struct shell_uart *sh_uart = (struct shell_uart *)transport->ctx;
251+
252+
smp_shell_process(&sh_uart->ctrl_blk->smp);
253+
}
254+
#endif /* CONFIG_MCUMGR_SMP_SHELL */
255+
222256
const struct shell_transport_api shell_uart_transport_api = {
223257
.init = init,
224258
.uninit = uninit,
225259
.enable = enable,
226260
.write = write,
227-
.read = read
261+
.read = read,
262+
#ifdef CONFIG_MCUMGR_SMP_SHELL
263+
.update = update,
264+
#endif /* CONFIG_MCUMGR_SMP_SHELL */
228265
};
229266

230267
static int enable_shell_uart(struct device *arg)

0 commit comments

Comments
 (0)