subsys: mgmt: UART transport for SMP (mcumgr).
Add a UART driver dedicated to transporting mcumgr SMP requests and responses. Signed-off-by: Christopher Collins <ccollins@apache.org>
This commit is contained in:
parent
76bf5646d5
commit
14735116d1
|
@ -3,6 +3,7 @@ zephyr_sources_if_kconfig(ram_console.c)
|
|||
zephyr_sources_if_kconfig(rtt_console.c)
|
||||
zephyr_sources_if_kconfig(ipm_console_receiver.c)
|
||||
zephyr_sources_if_kconfig(ipm_console_sender.c)
|
||||
zephyr_sources_if_kconfig(uart_mcumgr.c)
|
||||
zephyr_sources_if_kconfig(uart_pipe.c)
|
||||
zephyr_sources_if_kconfig(telnet_console.c)
|
||||
zephyr_sources_if_kconfig(xtensa_sim_console.c)
|
||||
|
|
|
@ -79,6 +79,17 @@ config UART_CONSOLE_DEBUG_SERVER_HOOKS
|
|||
they are some sort of control characters, or let the regular console
|
||||
code handle them if they are of no special significance to it.
|
||||
|
||||
config UART_CONSOLE_MCUMGR
|
||||
bool
|
||||
prompt "Enable UART console mcumgr passthrough"
|
||||
default n
|
||||
depends on UART_CONSOLE
|
||||
help
|
||||
Enables the UART console to receive mcumgr frames for image upgrade
|
||||
and device management. When enabled, the UART console does not
|
||||
process mcumgr frames, but it hands them up to a higher level module
|
||||
(e.g., the shell). If unset, incoming mcumgr frames are dropped.
|
||||
|
||||
config USB_UART_CONSOLE
|
||||
bool
|
||||
prompt "Use USB port for console outputs"
|
||||
|
@ -189,6 +200,51 @@ config UART_PIPE_ON_DEV_NAME
|
|||
for pipe UART.
|
||||
endif
|
||||
|
||||
config UART_MCUMGR
|
||||
bool
|
||||
prompt "Enable mcumgr UART driver"
|
||||
select UART_INTERRUPT_DRIVEN
|
||||
default n
|
||||
help
|
||||
Enable the mcumgr UART driver. This driver allows the application to
|
||||
communicate over UART using the mcumgr protocol for image upgrade and
|
||||
device management. The driver doesn't inspect received data (as
|
||||
contrary to console UART driver) and all aspects of received protocol
|
||||
data are handled by an application provided callback.
|
||||
|
||||
if UART_MCUMGR
|
||||
if !HAS_DTS
|
||||
config UART_MCUMGR_ON_DEV_NAME
|
||||
string "Device Name of UART Device for mcumgr UART"
|
||||
default "UART_0"
|
||||
depends on UART_MCUMGR
|
||||
help
|
||||
This option specifies the name of UART device to be used
|
||||
for mcumgr UART.
|
||||
endif # !HAS_DTS
|
||||
|
||||
config UART_MCUMGR_RX_BUF_SIZE
|
||||
int
|
||||
prompt "Size of receive buffer for mcumgr fragments received over UART, in bytes"
|
||||
default 128
|
||||
help
|
||||
Specifies the size of the mcumgr UART receive buffer, in bytes. This
|
||||
value must be large enough to accommodate any line sent by an mcumgr
|
||||
client.
|
||||
|
||||
config UART_MCUMGR_RX_BUF_COUNT
|
||||
int
|
||||
prompt "Number of receive buffers for mcumgr fragments received over UART"
|
||||
default 2
|
||||
help
|
||||
Specifies the number of the mcumgr UART receive buffers. Receive
|
||||
buffers hold received mcumgr fragments prior to reassembly. This
|
||||
setting's value must satisfy the following relation:
|
||||
UART_MCUMGR_RX_BUF_COUNT * UART_MCUMGR_RX_BUF_SIZE >=
|
||||
MCUMGR_SMP_UART_MTU
|
||||
|
||||
endif # UART_MCUMGR
|
||||
|
||||
config XTENSA_SIM_CONSOLE
|
||||
bool
|
||||
prompt "Use Xtensa simulator console"
|
||||
|
|
|
@ -32,6 +32,9 @@
|
|||
#include <linker/sections.h>
|
||||
#include <atomic.h>
|
||||
#include <misc/printk.h>
|
||||
#ifdef CONFIG_UART_CONSOLE_MCUMGR
|
||||
#include "mgmt/serial.h"
|
||||
#endif
|
||||
|
||||
static struct device *uart_console_dev;
|
||||
|
||||
|
@ -43,8 +46,7 @@ void uart_console_in_debug_hook_install(uart_console_in_debug_hook_t hook)
|
|||
debug_hook_in = hook;
|
||||
}
|
||||
|
||||
static UART_CONSOLE_OUT_DEBUG_HOOK_SIG(debug_hook_out_nop)
|
||||
{
|
||||
static UART_CONSOLE_OUT_DEBUG_HOOK_SIG(debug_hook_out_nop) {
|
||||
ARG_UNUSED(c);
|
||||
return !UART_CONSOLE_DEBUG_HOOK_HANDLED;
|
||||
}
|
||||
|
@ -101,7 +103,7 @@ static int console_out(int c)
|
|||
return c;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_UART_CONSOLE_DEBUG_SERVER_HOOKS */
|
||||
#endif /* CONFIG_UART_CONSOLE_DEBUG_SERVER_HOOKS */
|
||||
|
||||
if ('\n' == c) {
|
||||
uart_poll_out(uart_console_dev, '\r');
|
||||
|
@ -116,16 +118,16 @@ static int console_out(int c)
|
|||
#if defined(CONFIG_STDOUT_CONSOLE)
|
||||
extern void __stdout_hook_install(int (*hook)(int));
|
||||
#else
|
||||
#define __stdout_hook_install(x) \
|
||||
do {/* nothing */ \
|
||||
#define __stdout_hook_install(x) \
|
||||
do { /* nothing */ \
|
||||
} while ((0))
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_PRINTK)
|
||||
extern void __printk_hook_install(int (*fn)(int));
|
||||
#else
|
||||
#define __printk_hook_install(x) \
|
||||
do {/* nothing */ \
|
||||
#define __printk_hook_install(x) \
|
||||
do { /* nothing */ \
|
||||
} while ((0))
|
||||
#endif
|
||||
|
||||
|
@ -239,7 +241,13 @@ enum {
|
|||
ESC_ANSI,
|
||||
ESC_ANSI_FIRST,
|
||||
ESC_ANSI_VAL,
|
||||
ESC_ANSI_VAL_2
|
||||
ESC_ANSI_VAL_2,
|
||||
#ifdef CONFIG_UART_CONSOLE_MCUMGR
|
||||
ESC_MCUMGR_PKT_1,
|
||||
ESC_MCUMGR_PKT_2,
|
||||
ESC_MCUMGR_FRAG_1,
|
||||
ESC_MCUMGR_FRAG_2,
|
||||
#endif
|
||||
};
|
||||
|
||||
static atomic_t esc_state;
|
||||
|
@ -335,6 +343,113 @@ ansi_cmd:
|
|||
atomic_clear_bit(&esc_state, ESC_ANSI);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_UART_CONSOLE_MCUMGR
|
||||
|
||||
static void clear_mcumgr(void)
|
||||
{
|
||||
atomic_clear_bit(&esc_state, ESC_MCUMGR_PKT_1);
|
||||
atomic_clear_bit(&esc_state, ESC_MCUMGR_PKT_2);
|
||||
atomic_clear_bit(&esc_state, ESC_MCUMGR_FRAG_1);
|
||||
atomic_clear_bit(&esc_state, ESC_MCUMGR_FRAG_2);
|
||||
}
|
||||
|
||||
/**
|
||||
* These states indicate whether an mcumgr frame is being received.
|
||||
*/
|
||||
#define CONSOLE_MCUMGR_STATE_NONE 1
|
||||
#define CONSOLE_MCUMGR_STATE_HEADER 2
|
||||
#define CONSOLE_MCUMGR_STATE_PAYLOAD 3
|
||||
|
||||
static int read_mcumgr_byte(uint8_t byte)
|
||||
{
|
||||
bool frag_1;
|
||||
bool frag_2;
|
||||
bool pkt_1;
|
||||
bool pkt_2;
|
||||
|
||||
pkt_1 = atomic_test_bit(&esc_state, ESC_MCUMGR_PKT_1);
|
||||
pkt_2 = atomic_test_bit(&esc_state, ESC_MCUMGR_PKT_2);
|
||||
frag_1 = atomic_test_bit(&esc_state, ESC_MCUMGR_FRAG_1);
|
||||
frag_2 = atomic_test_bit(&esc_state, ESC_MCUMGR_FRAG_2);
|
||||
|
||||
if (pkt_2 || frag_2) {
|
||||
/* Already fully framed. */
|
||||
return CONSOLE_MCUMGR_STATE_PAYLOAD;
|
||||
}
|
||||
|
||||
if (pkt_1) {
|
||||
if (byte == MCUMGR_SERIAL_HDR_PKT_2) {
|
||||
/* Final framing byte received. */
|
||||
atomic_set_bit(&esc_state, ESC_MCUMGR_PKT_2);
|
||||
return CONSOLE_MCUMGR_STATE_PAYLOAD;
|
||||
}
|
||||
} else if (frag_1) {
|
||||
if (byte == MCUMGR_SERIAL_HDR_FRAG_2) {
|
||||
/* Final framing byte received. */
|
||||
atomic_set_bit(&esc_state, ESC_MCUMGR_FRAG_2);
|
||||
return CONSOLE_MCUMGR_STATE_PAYLOAD;
|
||||
}
|
||||
} else {
|
||||
if (byte == MCUMGR_SERIAL_HDR_PKT_1) {
|
||||
/* First framing byte received. */
|
||||
atomic_set_bit(&esc_state, ESC_MCUMGR_PKT_1);
|
||||
return CONSOLE_MCUMGR_STATE_HEADER;
|
||||
} else if (byte == MCUMGR_SERIAL_HDR_FRAG_1) {
|
||||
/* First framing byte received. */
|
||||
atomic_set_bit(&esc_state, ESC_MCUMGR_FRAG_1);
|
||||
return CONSOLE_MCUMGR_STATE_HEADER;
|
||||
}
|
||||
}
|
||||
|
||||
/* Non-mcumgr byte received. */
|
||||
return CONSOLE_MCUMGR_STATE_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Attempts to process a received byte as part of an mcumgr frame.
|
||||
*
|
||||
* @param cmd The console command currently being received.
|
||||
* @param byte The byte just received.
|
||||
*
|
||||
* @return true if the command being received is an mcumgr frame; false if it
|
||||
* is a plain console command.
|
||||
*/
|
||||
static bool handle_mcumgr(struct console_input *cmd, uint8_t byte)
|
||||
{
|
||||
int mcumgr_state;
|
||||
|
||||
mcumgr_state = read_mcumgr_byte(byte);
|
||||
if (mcumgr_state == CONSOLE_MCUMGR_STATE_NONE) {
|
||||
/* Not an mcumgr command; let the normal console handling
|
||||
* process the byte.
|
||||
*/
|
||||
cmd->is_mcumgr = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* The received byte is part of an mcumgr command. Process the byte
|
||||
* and return true to indicate that normal console handling should
|
||||
* ignore it.
|
||||
*/
|
||||
if (cur + end < sizeof(cmd->line) - 1) {
|
||||
cmd->line[cur++] = byte;
|
||||
}
|
||||
if (mcumgr_state == CONSOLE_MCUMGR_STATE_PAYLOAD && byte == '\n') {
|
||||
cmd->line[cur + end] = '\0';
|
||||
cmd->is_mcumgr = 1;
|
||||
k_fifo_put(lines_queue, cmd);
|
||||
|
||||
clear_mcumgr();
|
||||
cmd = NULL;
|
||||
cur = 0;
|
||||
end = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_UART_CONSOLE_MCUMGR */
|
||||
|
||||
void uart_console_isr(struct device *unused)
|
||||
{
|
||||
ARG_UNUSED(unused);
|
||||
|
@ -373,6 +488,15 @@ void uart_console_isr(struct device *unused)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_UART_CONSOLE_MCUMGR
|
||||
/* Divert this byte from normal console handling if it is part
|
||||
* of an mcumgr frame.
|
||||
*/
|
||||
if (handle_mcumgr(cmd, byte)) {
|
||||
continue;
|
||||
}
|
||||
#endif /* CONFIG_UART_CONSOLE_MCUMGR */
|
||||
|
||||
/* Handle ANSI escape mode */
|
||||
if (atomic_test_bit(&esc_state, ESC_ANSI)) {
|
||||
handle_ansi(byte, cmd->line);
|
||||
|
@ -389,8 +513,8 @@ void uart_console_isr(struct device *unused)
|
|||
continue;
|
||||
}
|
||||
|
||||
/* Handle special control characters */
|
||||
if (!isprint(byte)) {
|
||||
/* Handle special control characters */
|
||||
switch (byte) {
|
||||
case DEL:
|
||||
if (cur > 0) {
|
||||
|
@ -417,8 +541,6 @@ void uart_console_isr(struct device *unused)
|
|||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Ignore characters if there's no more buffer space */
|
||||
|
@ -456,11 +578,11 @@ void uart_register_input(struct k_fifo *avail, struct k_fifo *lines,
|
|||
}
|
||||
|
||||
#else
|
||||
#define console_input_init(x) \
|
||||
do {/* nothing */ \
|
||||
#define console_input_init(x) \
|
||||
do { /* nothing */ \
|
||||
} while ((0))
|
||||
#define uart_register_input(x) \
|
||||
do {/* nothing */ \
|
||||
#define uart_register_input(x) \
|
||||
do { /* nothing */ \
|
||||
} while ((0))
|
||||
#endif
|
||||
|
||||
|
@ -510,10 +632,10 @@ static int uart_console_init(struct device *arg)
|
|||
/* UART console initializes after the UART device itself */
|
||||
SYS_INIT(uart_console_init,
|
||||
#if defined(CONFIG_USB_UART_CONSOLE)
|
||||
APPLICATION,
|
||||
APPLICATION,
|
||||
#elif defined(CONFIG_EARLY_CONSOLE)
|
||||
PRE_KERNEL_1,
|
||||
PRE_KERNEL_1,
|
||||
#else
|
||||
POST_KERNEL,
|
||||
POST_KERNEL,
|
||||
#endif
|
||||
CONFIG_UART_CONSOLE_INIT_PRIORITY);
|
||||
CONFIG_UART_CONSOLE_INIT_PRIORITY);
|
||||
|
|
190
drivers/console/uart_mcumgr.c
Normal file
190
drivers/console/uart_mcumgr.c
Normal file
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
* Copyright Runtime.io 2018. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief A driver for sending and receiving mcumgr packets over UART.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <kernel.h>
|
||||
#include <uart.h>
|
||||
#include <mgmt/serial.h>
|
||||
#include <console/uart_mcumgr.h>
|
||||
|
||||
static struct device *uart_mcumgr_dev;
|
||||
|
||||
/** Callback to execute when a valid fragment has been received. */
|
||||
static uart_mcumgr_recv_fn *uart_mgumgr_recv_cb;
|
||||
|
||||
/** Contains the fragment currently being received. */
|
||||
static struct uart_mcumgr_rx_buf *uart_mcumgr_cur_buf;
|
||||
|
||||
/**
|
||||
* Whether the line currently being read should be ignored. This is true if
|
||||
* the line is too long or if there is no buffer available to hold it.
|
||||
*/
|
||||
static bool uart_mcumgr_ignoring;
|
||||
|
||||
/** Contains buffers to hold incoming request fragments. */
|
||||
K_MEM_SLAB_DEFINE(uart_mcumgr_slab, sizeof(struct uart_mcumgr_rx_buf),
|
||||
CONFIG_UART_MCUMGR_RX_BUF_COUNT, 1);
|
||||
|
||||
static struct uart_mcumgr_rx_buf *uart_mcumgr_alloc_rx_buf(void)
|
||||
{
|
||||
struct uart_mcumgr_rx_buf *rx_buf;
|
||||
void *block;
|
||||
int rc;
|
||||
|
||||
rc = k_mem_slab_alloc(&uart_mcumgr_slab, &block, K_NO_WAIT);
|
||||
if (rc != 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rx_buf = block;
|
||||
rx_buf->length = 0;
|
||||
return rx_buf;
|
||||
}
|
||||
|
||||
void uart_mcumgr_free_rx_buf(struct uart_mcumgr_rx_buf *rx_buf)
|
||||
{
|
||||
void *block;
|
||||
|
||||
block = rx_buf;
|
||||
k_mem_slab_free(&uart_mcumgr_slab, &block);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a chunk of received data from the UART.
|
||||
*/
|
||||
static int uart_mcumgr_read_chunk(void *buf, int capacity)
|
||||
{
|
||||
if (!uart_irq_rx_ready(uart_mcumgr_dev)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return uart_fifo_read(uart_mcumgr_dev, buf, capacity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a single incoming byte.
|
||||
*/
|
||||
static struct uart_mcumgr_rx_buf *uart_mcumgr_rx_byte(u8_t byte)
|
||||
{
|
||||
struct uart_mcumgr_rx_buf *rx_buf;
|
||||
|
||||
if (!uart_mcumgr_ignoring) {
|
||||
if (uart_mcumgr_cur_buf == NULL) {
|
||||
uart_mcumgr_cur_buf = uart_mcumgr_alloc_rx_buf();
|
||||
if (uart_mcumgr_cur_buf == NULL) {
|
||||
/* Insufficient buffers; drop this fragment. */
|
||||
uart_mcumgr_ignoring = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rx_buf = uart_mcumgr_cur_buf;
|
||||
if (!uart_mcumgr_ignoring) {
|
||||
if (rx_buf->length >= sizeof(rx_buf->data)) {
|
||||
/* Line too long; drop this fragment. */
|
||||
uart_mcumgr_free_rx_buf(uart_mcumgr_cur_buf);
|
||||
uart_mcumgr_cur_buf = NULL;
|
||||
uart_mcumgr_ignoring = true;
|
||||
} else {
|
||||
rx_buf->data[rx_buf->length++] = byte;
|
||||
}
|
||||
}
|
||||
|
||||
if (byte == '\n') {
|
||||
/* Fragment complete. */
|
||||
if (uart_mcumgr_ignoring) {
|
||||
uart_mcumgr_ignoring = false;
|
||||
} else {
|
||||
uart_mcumgr_cur_buf = NULL;
|
||||
return rx_buf;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* ISR that is called when UART bytes are received.
|
||||
*/
|
||||
static void uart_mcumgr_isr(struct device *unused)
|
||||
{
|
||||
struct uart_mcumgr_rx_buf *rx_buf;
|
||||
u8_t buf[32];
|
||||
int chunk_len;
|
||||
int i;
|
||||
|
||||
ARG_UNUSED(unused);
|
||||
|
||||
while (uart_irq_update(uart_mcumgr_dev) &&
|
||||
uart_irq_is_pending(uart_mcumgr_dev)) {
|
||||
|
||||
chunk_len = uart_mcumgr_read_chunk(buf, sizeof(buf));
|
||||
if (chunk_len == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (i = 0; i < chunk_len; i++) {
|
||||
rx_buf = uart_mcumgr_rx_byte(buf[i]);
|
||||
if (rx_buf != NULL) {
|
||||
uart_mgumgr_recv_cb(rx_buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends raw data over the UART.
|
||||
*/
|
||||
static int uart_mcumgr_send_raw(const void *data, int len, void *arg)
|
||||
{
|
||||
const u8_t *u8p;
|
||||
|
||||
u8p = data;
|
||||
while (len--) {
|
||||
uart_poll_out(uart_mcumgr_dev, *u8p++);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uart_mcumgr_send(const u8_t *data, int len)
|
||||
{
|
||||
return mcumgr_serial_tx_pkt(data, len, uart_mcumgr_send_raw, NULL);
|
||||
}
|
||||
|
||||
static void uart_mcumgr_setup(struct device *uart)
|
||||
{
|
||||
u8_t c;
|
||||
|
||||
uart_irq_rx_disable(uart);
|
||||
uart_irq_tx_disable(uart);
|
||||
|
||||
/* Drain the fifo */
|
||||
while (uart_fifo_read(uart, &c, 1)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uart_irq_callback_set(uart, uart_mcumgr_isr);
|
||||
|
||||
uart_irq_rx_enable(uart);
|
||||
}
|
||||
|
||||
void uart_mcumgr_register(uart_mcumgr_recv_fn *cb)
|
||||
{
|
||||
uart_mgumgr_recv_cb = cb;
|
||||
|
||||
uart_mcumgr_dev = device_get_binding(CONFIG_UART_MCUMGR_ON_DEV_NAME);
|
||||
|
||||
if (uart_mcumgr_dev != NULL) {
|
||||
uart_mcumgr_setup(uart_mcumgr_dev);
|
||||
}
|
||||
}
|
75
include/drivers/console/uart_mcumgr.h
Normal file
75
include/drivers/console/uart_mcumgr.h
Normal file
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright Runtime.io 2018. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* @brief A driver for sending and receiving mcumgr packets over UART.
|
||||
*
|
||||
* @see include/mgmt/serial.h
|
||||
*/
|
||||
|
||||
#ifndef H_UART_MCUMGR_
|
||||
#define H_UART_MCUMGR_
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <zephyr/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Contains an mcumgr fragment received over UART.
|
||||
*/
|
||||
struct uart_mcumgr_rx_buf {
|
||||
void *fifo_reserved; /* 1st word reserved for use by fifo */
|
||||
u8_t data[CONFIG_UART_MCUMGR_RX_BUF_SIZE];
|
||||
int length;
|
||||
};
|
||||
|
||||
/** @typedef uart_mcumgr_recv_fn
|
||||
* @brief Function that gets called when an mcumgr packet is received.
|
||||
*
|
||||
* Function that gets called when an mcumgr packet is received. This function
|
||||
* gets called in the interrupt context. Ownership of the specified buffer is
|
||||
* transferred to the callback when this function gets called.
|
||||
*
|
||||
* @param rx_buf A buffer containing the incoming mcumgr packet.
|
||||
*/
|
||||
typedef void uart_mcumgr_recv_fn(struct uart_mcumgr_rx_buf *rx_buf);
|
||||
|
||||
/**
|
||||
* @brief Sends an mcumgr packet over UART.
|
||||
*
|
||||
* @param data Buffer containing the mcumgr packet to send.
|
||||
* @param len The length of the buffer, in bytes.
|
||||
*
|
||||
* @return 0 on success; negative error code on failure.
|
||||
*/
|
||||
int uart_mcumgr_send(const u8_t *data, int len);
|
||||
|
||||
/**
|
||||
* @brief Frees the supplied receive buffer.
|
||||
*
|
||||
* @param rx_buf The buffer to free.
|
||||
*/
|
||||
void uart_mcumgr_free_rx_buf(struct uart_mcumgr_rx_buf *rx_buf);
|
||||
|
||||
/**
|
||||
* @brief Registers an mcumgr UART receive handler.
|
||||
*
|
||||
* Configures the mcumgr UART driver to call the specified function when an
|
||||
* mcumgr request packet is received.
|
||||
*
|
||||
* @param cb The callback to execute when an mcumgr request
|
||||
* packet is received.
|
||||
*/
|
||||
void uart_mcumgr_register(uart_mcumgr_recv_fn *cb);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -877,7 +877,8 @@ def main():
|
|||
"CONFIG_UART_CONSOLE_ON_DEV_NAME": "zephyr,console",
|
||||
"CONFIG_BT_UART_ON_DEV_NAME": "zephyr,bt-uart",
|
||||
"CONFIG_UART_PIPE_ON_DEV_NAME": "zephyr,uart-pipe",
|
||||
"CONFIG_BT_MONITOR_ON_DEV_NAME": "zephyr,bt-mon-uart"
|
||||
"CONFIG_BT_MONITOR_ON_DEV_NAME": "zephyr,bt-mon-uart",
|
||||
"CONFIG_UART_MCUMGR_ON_DEV_NAME": "zephyr,uart-mcumgr",
|
||||
}
|
||||
|
||||
for k, v in name_dict.items():
|
||||
|
|
101
subsys/mgmt/smp_uart.c
Normal file
101
subsys/mgmt/smp_uart.c
Normal file
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Copyright Runtime.io 2018. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* @brief UART transport for the mcumgr SMP protocol.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <zephyr.h>
|
||||
#include <init.h>
|
||||
#include "net/buf.h"
|
||||
#include "console/uart_mcumgr.h"
|
||||
#include "mgmt/mgmt.h"
|
||||
#include <mgmt/serial.h>
|
||||
#include "mgmt/buf.h"
|
||||
#include "mgmt/smp.h"
|
||||
|
||||
struct device;
|
||||
|
||||
static void smp_uart_process_rx_queue(struct k_work *work);
|
||||
|
||||
K_FIFO_DEFINE(smp_uart_rx_fifo);
|
||||
K_WORK_DEFINE(smp_uart_work, smp_uart_process_rx_queue);
|
||||
|
||||
static struct mcumgr_serial_rx_ctxt smp_uart_rx_ctxt;
|
||||
static struct zephyr_smp_transport smp_uart_transport;
|
||||
|
||||
/**
|
||||
* Processes a single line (fragment) coming from the mcumgr UART driver.
|
||||
*/
|
||||
static void smp_uart_process_frag(struct uart_mcumgr_rx_buf *rx_buf)
|
||||
{
|
||||
struct net_buf *nb;
|
||||
|
||||
/* Decode the fragment and write the result to the global receive
|
||||
* context.
|
||||
*/
|
||||
nb = mcumgr_serial_process_frag(&smp_uart_rx_ctxt,
|
||||
rx_buf->data, rx_buf->length);
|
||||
|
||||
/* Release the encoded fragment. */
|
||||
uart_mcumgr_free_rx_buf(rx_buf);
|
||||
|
||||
/* If a complete packet has been received, pass it to SMP for
|
||||
* processing.
|
||||
*/
|
||||
if (nb != NULL) {
|
||||
zephyr_smp_rx_req(&smp_uart_transport, nb);
|
||||
}
|
||||
}
|
||||
|
||||
static void smp_uart_process_rx_queue(struct k_work *work)
|
||||
{
|
||||
struct uart_mcumgr_rx_buf *rx_buf;
|
||||
|
||||
while ((rx_buf = k_fifo_get(&smp_uart_rx_fifo, K_NO_WAIT)) != NULL) {
|
||||
smp_uart_process_frag(rx_buf);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues a received SMP fragment for later processing. This function
|
||||
* executes in the interrupt context.
|
||||
*/
|
||||
static void smp_uart_rx_frag(struct uart_mcumgr_rx_buf *rx_buf)
|
||||
{
|
||||
k_fifo_put(&smp_uart_rx_fifo, rx_buf);
|
||||
k_work_submit(&smp_uart_work);
|
||||
}
|
||||
|
||||
static u16_t smp_uart_get_mtu(const struct net_buf *nb)
|
||||
{
|
||||
return CONFIG_MCUMGR_SMP_UART_MTU;
|
||||
}
|
||||
|
||||
static int smp_uart_tx_pkt(struct zephyr_smp_transport *zst,
|
||||
struct net_buf *nb)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = uart_mcumgr_send(nb->data, nb->len);
|
||||
mcumgr_buf_free(nb);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int smp_uart_init(struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
zephyr_smp_transport_init(&smp_uart_transport, smp_uart_tx_pkt,
|
||||
smp_uart_get_mtu);
|
||||
uart_mcumgr_register(smp_uart_rx_frag);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SYS_INIT(smp_uart_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);
|
Loading…
Reference in a new issue