subsys: mgmt: Shell transport for SMP (mcumgr).
Enable the shell to transport mcumgr SMP requests and responses. Signed-off-by: Christopher Collins <ccollins@apache.org>
This commit is contained in:
parent
6721d64735
commit
76bf5646d5
6 changed files with 599 additions and 3 deletions
|
@ -21,6 +21,8 @@ extern "C" {
|
|||
struct console_input {
|
||||
/** FIFO uses first 4 bytes itself, reserve space */
|
||||
int _unused;
|
||||
/** Whether this is an mcumgr command */
|
||||
u8_t is_mcumgr : 1;
|
||||
/** Buffer where the input line is recorded */
|
||||
char line[CONSOLE_MAX_LINE_LEN];
|
||||
};
|
||||
|
|
141
include/mgmt/serial.h
Normal file
141
include/mgmt/serial.h
Normal file
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* Copyright Runtime.io 2018. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Utility functions used by the UART and shell mcumgr transports.
|
||||
*
|
||||
* Mcumgr packets sent over serial are fragmented into frames of 128 bytes or
|
||||
* fewer.
|
||||
*
|
||||
* The initial frame in a packet has the following format:
|
||||
* offset 0: 0x06 0x09
|
||||
* === Begin base64 encoding ===
|
||||
* offset 2: {16-bit packet-length}
|
||||
* offset ?: {body}
|
||||
* offset ?: {crc16} (if final frame)
|
||||
* === End base64 encoding ===
|
||||
* offset ?: 0x0a (newline)
|
||||
*
|
||||
* All subsequent frames have the following format:
|
||||
* offset 0: 0x04 0x14
|
||||
* === Begin base64 encoding ===
|
||||
* offset 2: {body}
|
||||
* offset ?: {crc16} (if final frame)
|
||||
* === End base64 encoding ===
|
||||
* offset ?: 0x0a (newline)
|
||||
*
|
||||
* All integers are represented in big-endian. The packet fields are described
|
||||
* below:
|
||||
*
|
||||
* | Field | Description |
|
||||
* | -------------- | ------------------------------------------------------- |
|
||||
* | 0x06 0x09 | Byte pair indicating the start of a packet. |
|
||||
* | 0x04 0x14 | Byte pair indicating the start of a continuation frame. |
|
||||
* | Packet length | The combined total length of the *unencoded* body. |
|
||||
* | Body | The actual SMP data (i.e., 8-byte header and CBOR |
|
||||
* | | key-value map). |
|
||||
* | CRC16 | A CRC16 of the *unencoded* body of the entire packet. |
|
||||
* | | This field is only present in the final frame of a |
|
||||
* | | packet. |
|
||||
* | Newline | A 0x0a byte; terminates a frame. |
|
||||
*
|
||||
* The packet is fully received when {packet-length} bytes of body has been
|
||||
* received.
|
||||
*
|
||||
* ## CRC details
|
||||
*
|
||||
* The CRC16 should be calculated with the following parameters:
|
||||
*
|
||||
* | Field | Value |
|
||||
* | ------------- | ------------- |
|
||||
* | Polynomial | 0x1021 |
|
||||
* | Initial Value | 0 |
|
||||
*/
|
||||
|
||||
#ifndef H_MGMT_SERIAL_
|
||||
#define H_MGMT_SERIAL_
|
||||
|
||||
#include <zephyr/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MCUMGR_SERIAL_HDR_PKT 0x0609
|
||||
#define MCUMGR_SERIAL_HDR_FRAG 0x0414
|
||||
#define MCUMGR_SERIAL_MAX_FRAME 128
|
||||
|
||||
#define MCUMGR_SERIAL_HDR_PKT_1 (MCUMGR_SERIAL_HDR_PKT >> 8)
|
||||
#define MCUMGR_SERIAL_HDR_PKT_2 (MCUMGR_SERIAL_HDR_PKT & 0xff)
|
||||
#define MCUMGR_SERIAL_HDR_FRAG_1 (MCUMGR_SERIAL_HDR_FRAG >> 8)
|
||||
#define MCUMGR_SERIAL_HDR_FRAG_2 (MCUMGR_SERIAL_HDR_FRAG & 0xff)
|
||||
|
||||
/**
|
||||
* @brief Maintains state for an incoming mcumgr request packet.
|
||||
*/
|
||||
struct mcumgr_serial_rx_ctxt {
|
||||
/* Contains the partially- or fully-received mcumgr request. Data
|
||||
* stored in this buffer has already been base64-decoded.
|
||||
*/
|
||||
struct net_buf *nb;
|
||||
|
||||
/* Length of full packet, as read from header. */
|
||||
u16_t pkt_len;
|
||||
};
|
||||
|
||||
/** @typedef mcumgr_serial_tx_cb
|
||||
* @brief Transmits a chunk of raw response data.
|
||||
*
|
||||
* @param data The data to transmit.
|
||||
* @param len The number of bytes to transmit.
|
||||
* @param arg An optional argument.
|
||||
*
|
||||
* @return 0 on success; negative error code on failure.
|
||||
*/
|
||||
typedef int (*mcumgr_serial_tx_cb)(const void *data, int len, void *arg);
|
||||
|
||||
/**
|
||||
* @brief Processes an mcumgr request fragment received over a serial
|
||||
* transport.
|
||||
*
|
||||
* Processes an mcumgr request fragment received over a serial transport. If
|
||||
* the fragment is the end of a valid mcumgr request, this function returns a
|
||||
* net_buf containing the decoded request. It is the caller's responsibility
|
||||
* to free the net_buf after it has been processed.
|
||||
*
|
||||
* @param rx_ctxt The receive context associated with the serial
|
||||
* transport being used.
|
||||
* @param frag The incoming fragment to process.
|
||||
* @param frag_len The length of the fragment, in bytes.
|
||||
*
|
||||
* @return A net_buf containing the decoded request if a
|
||||
* complete and valid request has been
|
||||
* received.
|
||||
* NULL if the packet is incomplete or invalid.
|
||||
*/
|
||||
struct net_buf *mcumgr_serial_process_frag(
|
||||
struct mcumgr_serial_rx_ctxt *rx_ctxt,
|
||||
const u8_t *frag, int frag_len);
|
||||
|
||||
/**
|
||||
* @brief Encodes and transmits an mcumgr packet over serial.
|
||||
*
|
||||
* @param data The mcumgr packet data to send.
|
||||
* @param len The length of the unencoded mcumgr packet.
|
||||
* @param cb A callback used to transmit raw bytes.
|
||||
* @param arg An optional argument to pass to the callback.
|
||||
*
|
||||
* @return 0 on success; negative error code on failure.
|
||||
*/
|
||||
int mcumgr_serial_tx_pkt(const u8_t *data, int len, mcumgr_serial_tx_cb cb,
|
||||
void *arg);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -44,6 +44,19 @@ struct shell_module {
|
|||
shell_prompt_function_t prompt;
|
||||
};
|
||||
|
||||
/** @typedef shell_mcumgr_function_t
|
||||
* @brief Callback that is executed when an mcumgr packet is received over the
|
||||
* shell.
|
||||
*
|
||||
* The packet argument must be exactly what was received over the console,
|
||||
* except the terminating newline must be replaced with '\0'.
|
||||
*
|
||||
* @param line The received mcumgr packet.
|
||||
* @param arg An optional argument.
|
||||
*
|
||||
* @return on success; negative error code on failure.
|
||||
*/
|
||||
typedef int (*shell_mcumgr_function_t)(const char *line, void *arg);
|
||||
|
||||
/**
|
||||
* @brief Kernel Shell API
|
||||
|
@ -148,6 +161,13 @@ void shell_register_prompt_handler(shell_prompt_function_t handler);
|
|||
*/
|
||||
void shell_register_default_module(const char *name);
|
||||
|
||||
/** @brief Configures a callback for received mcumgr packets.
|
||||
*
|
||||
* @param handler The callback to execute when an mcumgr packet is received.
|
||||
* @param arg An optional argument to pass to the callback.
|
||||
*/
|
||||
void shell_register_mcumgr_handler(shell_mcumgr_function_t handler, void *arg);
|
||||
|
||||
/** @brief Execute command line.
|
||||
*
|
||||
* Pass command line to shell to execute. The line cannot be a C string literal
|
||||
|
|
332
subsys/mgmt/serial_util.c
Normal file
332
subsys/mgmt/serial_util.c
Normal file
|
@ -0,0 +1,332 @@
|
|||
/*
|
||||
* Copyright Runtime.io 2018. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
#include <crc16.h>
|
||||
#include <misc/byteorder.h>
|
||||
#include <net/buf.h>
|
||||
#include <mbedtls/base64.h>
|
||||
#include <mgmt/buf.h>
|
||||
#include <mgmt/serial.h>
|
||||
|
||||
static void mcumgr_serial_free_rx_ctxt(struct mcumgr_serial_rx_ctxt *rx_ctxt)
|
||||
{
|
||||
if (rx_ctxt->nb != NULL) {
|
||||
mcumgr_buf_free(rx_ctxt->nb);
|
||||
rx_ctxt->nb = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static u16_t mcumgr_serial_calc_crc(const u8_t *data, int len)
|
||||
{
|
||||
return crc16(data, len, 0x1021, 0, true);
|
||||
}
|
||||
|
||||
static int mcumgr_serial_parse_op(const u8_t *buf, int len)
|
||||
{
|
||||
u16_t op;
|
||||
|
||||
if (len < sizeof(op)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memcpy(&op, buf, sizeof(op));
|
||||
op = sys_be16_to_cpu(op);
|
||||
|
||||
if (op != MCUMGR_SERIAL_HDR_PKT && op != MCUMGR_SERIAL_HDR_FRAG) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
static int mcumgr_serial_extract_len(struct mcumgr_serial_rx_ctxt *rx_ctxt)
|
||||
{
|
||||
if (rx_ctxt->nb->len < 2) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rx_ctxt->pkt_len = net_buf_pull_be16(rx_ctxt->nb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mcumgr_serial_decode_frag(struct mcumgr_serial_rx_ctxt *rx_ctxt,
|
||||
const u8_t *frag, int frag_len)
|
||||
{
|
||||
int dec_len;
|
||||
int rc;
|
||||
|
||||
rc = mbedtls_base64_decode(rx_ctxt->nb->data + rx_ctxt->nb->len,
|
||||
net_buf_tailroom(rx_ctxt->nb), &dec_len,
|
||||
frag, frag_len);
|
||||
if (rc != 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rx_ctxt->nb->len += dec_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a received mcumgr frame.
|
||||
*
|
||||
* @return true if a complete packet was received;
|
||||
* false if the frame is invalid or if additional
|
||||
* fragments are expected.
|
||||
*/
|
||||
struct net_buf *mcumgr_serial_process_frag(
|
||||
struct mcumgr_serial_rx_ctxt *rx_ctxt,
|
||||
const u8_t *frag, int frag_len)
|
||||
{
|
||||
struct net_buf *nb;
|
||||
u16_t crc;
|
||||
u16_t op;
|
||||
int rc;
|
||||
|
||||
if (rx_ctxt->nb == NULL) {
|
||||
rx_ctxt->nb = mcumgr_buf_alloc();
|
||||
if (rx_ctxt->nb == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
op = mcumgr_serial_parse_op(frag, frag_len);
|
||||
switch (op) {
|
||||
case MCUMGR_SERIAL_HDR_PKT:
|
||||
net_buf_reset(rx_ctxt->nb);
|
||||
break;
|
||||
|
||||
case MCUMGR_SERIAL_HDR_FRAG:
|
||||
if (rx_ctxt->nb->len == 0) {
|
||||
mcumgr_serial_free_rx_ctxt(rx_ctxt);
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rc = mcumgr_serial_decode_frag(rx_ctxt,
|
||||
frag + sizeof(op),
|
||||
frag_len - sizeof(op));
|
||||
if (rc != 0) {
|
||||
mcumgr_serial_free_rx_ctxt(rx_ctxt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (op == MCUMGR_SERIAL_HDR_PKT) {
|
||||
rc = mcumgr_serial_extract_len(rx_ctxt);
|
||||
if (rc < 0) {
|
||||
mcumgr_serial_free_rx_ctxt(rx_ctxt);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (rx_ctxt->nb->len < rx_ctxt->pkt_len) {
|
||||
/* More fragments expected. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (rx_ctxt->nb->len > rx_ctxt->pkt_len) {
|
||||
/* Payload longer than indicated in header. */
|
||||
mcumgr_serial_free_rx_ctxt(rx_ctxt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
crc = mcumgr_serial_calc_crc(rx_ctxt->nb->data, rx_ctxt->nb->len);
|
||||
if (crc != 0) {
|
||||
mcumgr_serial_free_rx_ctxt(rx_ctxt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Packet is complete; strip the CRC. */
|
||||
rx_ctxt->nb->len -= 2;
|
||||
|
||||
nb = rx_ctxt->nb;
|
||||
rx_ctxt->nb = NULL;
|
||||
return nb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base64-encodes a small chunk of data and transmits it. The data must be no
|
||||
* larger than three bytes.
|
||||
*/
|
||||
static int mcumgr_serial_tx_small(const void *data, int len,
|
||||
mcumgr_serial_tx_cb cb, void *arg)
|
||||
{
|
||||
u8_t b64[4 + 1]; /* +1 required for null terminator. */
|
||||
size_t dst_len;
|
||||
int rc;
|
||||
|
||||
rc = mbedtls_base64_encode(b64, sizeof(b64), &dst_len, data, len);
|
||||
assert(rc == 0);
|
||||
assert(dst_len == 4);
|
||||
|
||||
return cb(b64, 4, arg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transmits a single mcumgr frame over serial.
|
||||
*
|
||||
* @param data The frame payload to transmit. This does not
|
||||
* include a header or CRC.
|
||||
* @param first Whether this is the first frame in the packet.
|
||||
* @param len The number of untransmitted data bytes in the
|
||||
* packet.
|
||||
* @param crc The 16-bit CRC of the entire packet.
|
||||
* @param cb A callback used for transmitting raw data.
|
||||
* @param arg An optional argument that gets passed to the
|
||||
* callback.
|
||||
* @param out_data_bytes_txed On success, the number of data bytes
|
||||
* transmitted gets written here.
|
||||
*
|
||||
* @return 0 on success; negative error code on failure.
|
||||
*/
|
||||
int mcumgr_serial_tx_frame(const u8_t *data, bool first, int len,
|
||||
u16_t crc, mcumgr_serial_tx_cb cb, void *arg,
|
||||
int *out_data_bytes_txed)
|
||||
{
|
||||
u8_t raw[3];
|
||||
u16_t u16;
|
||||
int dst_off;
|
||||
int src_off;
|
||||
int rem;
|
||||
int rc;
|
||||
|
||||
src_off = 0;
|
||||
dst_off = 0;
|
||||
|
||||
if (first) {
|
||||
u16 = sys_cpu_to_be16(MCUMGR_SERIAL_HDR_PKT);
|
||||
} else {
|
||||
u16 = sys_cpu_to_be16(MCUMGR_SERIAL_HDR_FRAG);
|
||||
}
|
||||
|
||||
rc = cb(&u16, sizeof(u16), arg);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
dst_off += 2;
|
||||
|
||||
/* Only the first fragment contains the packet length. */
|
||||
if (first) {
|
||||
u16 = sys_cpu_to_be16(len);
|
||||
memcpy(raw, &u16, sizeof(u16));
|
||||
raw[2] = data[0];
|
||||
|
||||
rc = mcumgr_serial_tx_small(raw, 3, cb, arg);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
src_off++;
|
||||
dst_off += 4;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (dst_off >= MCUMGR_SERIAL_MAX_FRAME - 4) {
|
||||
/* Can't fit any more data in this frame. */
|
||||
break;
|
||||
}
|
||||
|
||||
/* If we have reached the end of the packet, we need to encode
|
||||
* and send the CRC.
|
||||
*/
|
||||
rem = len - src_off;
|
||||
if (rem == 0) {
|
||||
raw[0] = (crc & 0xff00) >> 8;
|
||||
raw[1] = crc & 0x00ff;
|
||||
rc = mcumgr_serial_tx_small(raw, 2, cb, arg);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (rem == 1) {
|
||||
raw[0] = data[src_off];
|
||||
src_off++;
|
||||
|
||||
raw[1] = (crc & 0xff00) >> 8;
|
||||
raw[2] = crc & 0x00ff;
|
||||
rc = mcumgr_serial_tx_small(raw, 3, cb, arg);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (rem == 2) {
|
||||
raw[0] = data[src_off];
|
||||
raw[1] = data[src_off + 1];
|
||||
src_off += 2;
|
||||
|
||||
raw[2] = (crc & 0xff00) >> 8;
|
||||
rc = mcumgr_serial_tx_small(raw, 3, cb, arg);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
raw[0] = crc & 0x00ff;
|
||||
rc = mcumgr_serial_tx_small(raw, 1, cb, arg);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Otherwise, just encode payload data. */
|
||||
memcpy(raw, data + src_off, 3);
|
||||
rc = mcumgr_serial_tx_small(raw, 3, cb, arg);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
src_off += 3;
|
||||
dst_off += 4;
|
||||
}
|
||||
|
||||
rc = cb("\n", 1, arg);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
*out_data_bytes_txed = src_off;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mcumgr_serial_tx_pkt(const u8_t *data, int len, mcumgr_serial_tx_cb cb,
|
||||
void *arg)
|
||||
{
|
||||
u16_t crc;
|
||||
int data_bytes_txed;
|
||||
int src_off;
|
||||
int rc;
|
||||
|
||||
/* Calculate CRC of entire packet. */
|
||||
crc = mcumgr_serial_calc_crc(data, len);
|
||||
|
||||
/* Transmit packet as a sequence of frames. */
|
||||
src_off = 0;
|
||||
while (src_off < len) {
|
||||
rc = mcumgr_serial_tx_frame(data + src_off,
|
||||
src_off == 0,
|
||||
len - src_off,
|
||||
crc, cb, arg,
|
||||
&data_bytes_txed);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
src_off += data_bytes_txed;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
80
subsys/mgmt/smp_shell.c
Normal file
80
subsys/mgmt/smp_shell.c
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright Runtime.io 2018. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* @brief Shell transport for the mcumgr SMP protocol.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <zephyr.h>
|
||||
#include <init.h>
|
||||
#include "net/buf.h"
|
||||
#include "shell/shell.h"
|
||||
#include "mgmt/mgmt.h"
|
||||
#include "mgmt/serial.h"
|
||||
#include "mgmt/buf.h"
|
||||
#include "mgmt/smp.h"
|
||||
|
||||
struct device;
|
||||
|
||||
static struct zephyr_smp_transport smp_shell_transport;
|
||||
|
||||
static struct mcumgr_serial_rx_ctxt smp_shell_rx_ctxt;
|
||||
|
||||
/**
|
||||
* Processes a single line (i.e., a single SMP frame)
|
||||
*/
|
||||
static int smp_shell_rx_line(const char *line, void *arg)
|
||||
{
|
||||
struct net_buf *nb;
|
||||
int line_len;
|
||||
|
||||
/* Strip the trailing newline. */
|
||||
line_len = strlen(line) - 1;
|
||||
|
||||
nb = mcumgr_serial_process_frag(&smp_shell_rx_ctxt, line, line_len);
|
||||
if (nb != NULL) {
|
||||
zephyr_smp_rx_req(&smp_shell_transport, nb);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u16_t smp_shell_get_mtu(const struct net_buf *nb)
|
||||
{
|
||||
return CONFIG_MCUMGR_SMP_SHELL_MTU;
|
||||
}
|
||||
|
||||
static int smp_shell_tx_raw(const void *data, int len, void *arg)
|
||||
{
|
||||
/* Cast away const. */
|
||||
k_str_out((void *)data, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smp_shell_tx_pkt(struct zephyr_smp_transport *zst,
|
||||
struct net_buf *nb)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = mcumgr_serial_tx_pkt(nb->data, nb->len, smp_shell_tx_raw, NULL);
|
||||
mcumgr_buf_free(nb);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int smp_shell_init(struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
zephyr_smp_transport_init(&smp_shell_transport, smp_shell_tx_pkt,
|
||||
smp_shell_get_mtu);
|
||||
shell_register_mcumgr_handler(smp_shell_rx_line, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SYS_INIT(smp_shell_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);
|
|
@ -9,7 +9,6 @@
|
|||
* @brief Console handler implementation of shell.h API
|
||||
*/
|
||||
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
@ -18,6 +17,7 @@
|
|||
#include <console/console.h>
|
||||
#include <misc/printk.h>
|
||||
#include <misc/util.h>
|
||||
#include "mgmt/serial.h"
|
||||
|
||||
#ifdef CONFIG_UART_CONSOLE
|
||||
#include <console/uart_console.h>
|
||||
|
@ -66,6 +66,9 @@ static struct k_fifo cmds_queue;
|
|||
static shell_cmd_function_t app_cmd_handler;
|
||||
static shell_prompt_function_t app_prompt_handler;
|
||||
|
||||
static shell_mcumgr_function_t mcumgr_cmd_handler;
|
||||
static void *mcumgr_arg;
|
||||
|
||||
static const char *get_prompt(void)
|
||||
{
|
||||
if (app_prompt_handler) {
|
||||
|
@ -361,6 +364,12 @@ static const struct shell_cmd *get_internal(const char *command)
|
|||
return get_cmd(internal_commands, command);
|
||||
}
|
||||
|
||||
void shell_register_mcumgr_handler(shell_mcumgr_function_t handler, void *arg)
|
||||
{
|
||||
mcumgr_cmd_handler = handler;
|
||||
mcumgr_arg = arg;
|
||||
}
|
||||
|
||||
int shell_exec(char *line)
|
||||
{
|
||||
char *argv[ARGC_MAX + 1], **argv_start = argv;
|
||||
|
@ -425,6 +434,8 @@ done:
|
|||
|
||||
static void shell(void *p1, void *p2, void *p3)
|
||||
{
|
||||
bool skip_prompt = false;
|
||||
|
||||
ARG_UNUSED(p1);
|
||||
ARG_UNUSED(p2);
|
||||
ARG_UNUSED(p3);
|
||||
|
@ -434,7 +445,7 @@ static void shell(void *p1, void *p2, void *p3)
|
|||
while (1) {
|
||||
struct console_input *cmd;
|
||||
|
||||
if (!no_promt) {
|
||||
if (!no_promt && !skip_prompt) {
|
||||
printk("%s", get_prompt());
|
||||
#if defined(CONFIG_NATIVE_POSIX_CONSOLE)
|
||||
/* The native printk driver is line buffered */
|
||||
|
@ -444,7 +455,17 @@ static void shell(void *p1, void *p2, void *p3)
|
|||
|
||||
cmd = k_fifo_get(&cmds_queue, K_FOREVER);
|
||||
|
||||
shell_exec(cmd->line);
|
||||
/* If the received line is an mcumgr frame, divert it to the
|
||||
* mcumgr handler. Don't print the shell prompt this time, as
|
||||
* that will interfere with the mcumgr response.
|
||||
*/
|
||||
if (mcumgr_cmd_handler != NULL && cmd->is_mcumgr) {
|
||||
mcumgr_cmd_handler(cmd->line, mcumgr_arg);
|
||||
skip_prompt = true;
|
||||
} else {
|
||||
shell_exec(cmd->line);
|
||||
skip_prompt = false;
|
||||
}
|
||||
|
||||
k_fifo_put(&avail_queue, cmd);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue