Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 31 additions & 32 deletions drivers/console/uart_mcumgr.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(uart_mcumgr, CONFIG_MCUMGR_TRANSPORT_LOG_LEVEL);

static const struct device *const uart_mcumgr_dev =
DEVICE_DT_GET(DT_CHOSEN(zephyr_uart_mcumgr));

/** Callback to execute when a valid fragment has been received. */
static uart_mcumgr_recv_fn *uart_mcumgr_recv_cb;

Expand All @@ -43,7 +40,7 @@
static int async_current;
#endif

static struct uart_mcumgr_rx_buf *uart_mcumgr_alloc_rx_buf(void)
static struct uart_mcumgr_rx_buf *uart_mcumgr_alloc_rx_buf(const struct device *const dev)
{
struct uart_mcumgr_rx_buf *rx_buf;
void *block;
Expand All @@ -56,6 +53,9 @@

rx_buf = block;
rx_buf->length = 0;
#if defined(CONFIG_MCUMGR_TRANSPORT_FORWARD_TREE)
rx_buf->dev = dev;
#endif
return rx_buf;
}

Expand All @@ -71,26 +71,26 @@
/**
* Reads a chunk of received data from the UART.
*/
static int uart_mcumgr_read_chunk(void *buf, int capacity)
static int uart_mcumgr_read_chunk(const struct device *const dev, void *buf, int capacity)
{
if (!uart_irq_rx_ready(uart_mcumgr_dev)) {
if (!uart_irq_rx_ready(dev)) {
return 0;
}

return uart_fifo_read(uart_mcumgr_dev, buf, capacity);
return uart_fifo_read(dev, buf, capacity);
}
#endif

/**
* Processes a single incoming byte.
*/
static struct uart_mcumgr_rx_buf *uart_mcumgr_rx_byte(uint8_t byte)
static struct uart_mcumgr_rx_buf *uart_mcumgr_rx_byte(const struct device *const dev, uint8_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();
uart_mcumgr_cur_buf = uart_mcumgr_alloc_rx_buf(dev);
if (uart_mcumgr_cur_buf == NULL) {
LOG_WRN("Insufficient buffers, fragment dropped");
uart_mcumgr_ignoring = true;
Expand Down Expand Up @@ -124,7 +124,7 @@
}

#if defined(CONFIG_MCUMGR_TRANSPORT_UART_ASYNC)
static void uart_mcumgr_async(const struct device *dev, struct uart_event *evt, void *user_data)
static void uart_mcumgr_async(const struct device *const dev, struct uart_event *evt, void *user_data)

Check warning on line 127 in drivers/console/uart_mcumgr.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

LONG_LINE

drivers/console/uart_mcumgr.c:127 line length of 102 exceeds 100 columns

Check warning on line 127 in drivers/console/uart_mcumgr.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

LONG_LINE

drivers/console/uart_mcumgr.c:127 line length of 102 exceeds 100 columns
{
struct uart_mcumgr_rx_buf *rx_buf;
uint8_t *p;
Expand All @@ -141,7 +141,7 @@
p = &evt->data.rx.buf[evt->data.rx.offset];

for (int i = 0; i < len; i++) {
rx_buf = uart_mcumgr_rx_byte(p[i]);
rx_buf = uart_mcumgr_rx_byte(dev, p[i]);
if (rx_buf != NULL) {
uart_mcumgr_recv_cb(rx_buf);
}
Expand Down Expand Up @@ -172,26 +172,25 @@
/**
* ISR that is called when UART bytes are received.
*/
static void uart_mcumgr_isr(const struct device *unused, void *user_data)
static void uart_mcumgr_isr(const struct device *const dev, void *user_data)
{
struct uart_mcumgr_rx_buf *rx_buf;
uint8_t buf[32];
int chunk_len;
int i;

ARG_UNUSED(unused);
ARG_UNUSED(user_data);

while (uart_irq_update(uart_mcumgr_dev) &&
uart_irq_is_pending(uart_mcumgr_dev)) {
while (uart_irq_update(dev) &&
uart_irq_is_pending(dev)) {

chunk_len = uart_mcumgr_read_chunk(buf, sizeof(buf));
chunk_len = uart_mcumgr_read_chunk(dev, buf, sizeof(buf));
if (chunk_len == 0) {
continue;
}

for (i = 0; i < chunk_len; i++) {
rx_buf = uart_mcumgr_rx_byte(buf[i]);
rx_buf = uart_mcumgr_rx_byte(dev, buf[i]);
if (rx_buf != NULL) {
uart_mcumgr_recv_cb(rx_buf);
}
Expand All @@ -203,48 +202,48 @@
/**
* Sends raw data over the UART.
*/
static int uart_mcumgr_send_raw(const void *data, int len)
static int uart_mcumgr_send_raw(const struct device *const dev, const void *data, int len)
{
const uint8_t *u8p;

u8p = data;
while (len--) {
uart_poll_out(uart_mcumgr_dev, *u8p++);
uart_poll_out(dev, *u8p++);
}

return 0;
}

int uart_mcumgr_send(const uint8_t *data, int len)
int uart_mcumgr_send(const struct device *const dev, const uint8_t *data, int len)
{
return mcumgr_serial_tx_pkt(data, len, uart_mcumgr_send_raw);
return mcumgr_serial_tx_pkt(dev, data, len, uart_mcumgr_send_raw);
}


#if defined(CONFIG_MCUMGR_TRANSPORT_UART_ASYNC)
static void uart_mcumgr_setup(const struct device *uart)
static void uart_mcumgr_setup(const struct device *const dev)
{
uart_callback_set(uart, uart_mcumgr_async, NULL);
uart_callback_set(dev, uart_mcumgr_async, NULL);

uart_rx_enable(uart, async_buffer[0], sizeof(async_buffer[0]), 0);
uart_rx_enable(dev, async_buffer[0], sizeof(async_buffer[0]), 0);
}
#else
static void uart_mcumgr_setup(const struct device *uart)
static void uart_mcumgr_setup(const struct device *const dev)
{
uart_irq_rx_disable(uart);
uart_irq_tx_disable(uart);
uart_irq_rx_disable(dev);
uart_irq_tx_disable(dev);

uart_irq_callback_set(uart, uart_mcumgr_isr);
uart_irq_callback_set(dev, uart_mcumgr_isr);

uart_irq_rx_enable(uart);
uart_irq_rx_enable(dev);
}
#endif

void uart_mcumgr_register(uart_mcumgr_recv_fn *cb)
void uart_mcumgr_register(const struct device *const dev, uart_mcumgr_recv_fn *cb)
{
uart_mcumgr_recv_cb = cb;

if (device_is_ready(uart_mcumgr_dev)) {
uart_mcumgr_setup(uart_mcumgr_dev);
if (device_is_ready(dev)) {
uart_mcumgr_setup(dev);
}
}
83 changes: 83 additions & 0 deletions dts/bindings/misc/zephyr,smpmgr-forward.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Copyright (c) 2025 Freedom Veiculos Eletricos
# SPDX-License-Identifier: Apache-2.0

description: |
The SMP MCUmgr Mux is a software defined muxer to route SMP requests between
nodes in the hardware. It is composed from one upstream port and a finite
number of downstream ports.

The zephyr,smpmgr-forward node should be added in the zephyr,uart-mcumgr chosen
node. The zephyr,smpmgr-forward router uses a counter in the protocol to know
when it should stop to forward the data downstream. In this case, the data
is sent to the local device in the zephyr,uart-mcumgr interface.

In the below snip it is possible to see the definition of my_muxer. The
my_muxer is composed by three node: 'the_upstream', 'down1' and 'down2'. In
this case the 'down1' node is the 'index 0' and 'down2' is the 'index 1'.

/ {
chosen {
zephyr,uart-mcumgr = &my_muxer;
};

the_upstream: the_upstream{
compatible = "zephyr,smpmgr-transport";
status = "okay";

transport = <&cdc_acm_uart0>;
type = "serial";
};

down1: down1{
compatible = "zephyr,smpmgr-transport";
status = "okay";

transport = <&uart1>;
type = "serial";
};

down2: down2{
compatible = "zephyr,smpmgr-transport";
status = "okay";

transport = <&uart0>;
type = "ble";
};

my_muxer: my_muxer {
compatible = "zephyr,smpmgr-forward";
status = "okay";

upstream = <&the_upstream>;
downstream = <&down1>, <&down2>;
};
};

In the above example when the protocol mux counter is 0 the content is
pushed to zephyr,uart-mcumgr. In any other case the system will forward to
the respective downstream port. An error is returned if the index is out of
range.

The content that came from the local or a downstream port is forward to the
upstream interface.

compatible: "zephyr,smpmgr-forward"

include:
- name: base.yaml

properties:
upstream:
type: phandle
required: true
description: |
phandle to the upstream node. This should be a zephyr,smpmgr-transport
node.

downstream:
type: phandles
required: true
description: |
list of the phandle to all downstream nodes. These should be a
zephyr,smpmgr-transport node. The order of the nodes define the interface
number.
23 changes: 23 additions & 0 deletions dts/bindings/misc/zephyr,smpmgr-transport.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Copyright (c) 2025 Freedom Veiculos Eletricos
# SPDX-License-Identifier: Apache-2.0

description: SMP MCUmgr Interface

compatible: "zephyr,smpmgr-transport"

include:
- name: base.yaml

properties:
transport:
type: phandle
required: true
description: phandle to the transport node.

type:
type: string
required: true
enum:
- "serial"
- "ble"
description: define the transport type.
9 changes: 7 additions & 2 deletions include/zephyr/drivers/console/uart_mcumgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ struct uart_mcumgr_rx_buf {
void *fifo_reserved; /* 1st word reserved for use by fifo */
uint8_t data[CONFIG_UART_MCUMGR_RX_BUF_SIZE];
int length;
#if defined(CONFIG_MCUMGR_TRANSPORT_FORWARD_TREE)
const struct device *dev;
#endif
};

/** @typedef uart_mcumgr_recv_fn
Expand All @@ -43,12 +46,13 @@ typedef void uart_mcumgr_recv_fn(struct uart_mcumgr_rx_buf *rx_buf);
/**
* @brief Sends an mcumgr packet over UART.
*
* @param dev Device instance
* @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 uint8_t *data, int len);
int uart_mcumgr_send(const struct device *const dev, const uint8_t *data, int len);

/**
* @brief Frees the supplied receive buffer.
Expand All @@ -63,10 +67,11 @@ void uart_mcumgr_free_rx_buf(struct uart_mcumgr_rx_buf *rx_buf);
* Configures the mcumgr UART driver to call the specified function when an
* mcumgr request packet is received.
*
* @param dev Device instance
* @param cb The callback to execute when an mcumgr request
* packet is received.
*/
void uart_mcumgr_register(uart_mcumgr_recv_fn *cb);
void uart_mcumgr_register(const struct device *const dev, uart_mcumgr_recv_fn *cb);

#ifdef __cplusplus
}
Expand Down
4 changes: 4 additions & 0 deletions include/zephyr/mgmt/mcumgr/smp/smp.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ struct smp_streamer {
*/
int smp_process_request_packet(struct smp_streamer *streamer, void *req);

#if defined(CONFIG_MCUMGR_TRANSPORT_FORWARD_TREE)
int smp_ft_process_request_packet(struct smp_streamer *streamer, void *vreq);
#endif

/**
* @brief Appends an "err" response
*
Expand Down
7 changes: 5 additions & 2 deletions include/zephyr/mgmt/mcumgr/transport/serial.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,13 @@ struct mcumgr_serial_rx_ctxt {
/** @typedef mcumgr_serial_tx_cb
* @brief Transmits a chunk of raw response data.
*
* @param dev Device instance
* @param data The data to transmit.
* @param len The number of bytes to transmit.
*
* @return 0 on success; negative error code on failure.
*/
typedef int (*mcumgr_serial_tx_cb)(const void *data, int len);
typedef int (*mcumgr_serial_tx_cb)(const struct device *const dev, const void *data, int len);

/**
* @brief Processes an mcumgr request fragment received over a serial
Expand Down Expand Up @@ -85,13 +86,15 @@ struct net_buf *mcumgr_serial_process_frag(
/**
* @brief Encodes and transmits an mcumgr packet over serial.
*
* @param dev Device instance
* @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.
*
* @return 0 on success; negative error code on failure.
*/
int mcumgr_serial_tx_pkt(const uint8_t *data, int len, mcumgr_serial_tx_cb cb);
int mcumgr_serial_tx_pkt(const struct device *const dev, const uint8_t *data,
int len, mcumgr_serial_tx_cb cb);

#ifdef __cplusplus
}
Expand Down
Loading
Loading