net: openthread: Add UART platform backend for NCP
Currently based on CDC-ACM. Can possibly be used with plain UART as well. Signed-off-by: Markus Becker <markus.becker@tridonic.com>
This commit is contained in:
parent
653a15d138
commit
71ce94e0ed
5 changed files with 300 additions and 0 deletions
|
@ -201,6 +201,70 @@ config OPENTHREAD_DHCP6_SERVER
|
||||||
help
|
help
|
||||||
Enable DHCPv6 server capability in OpenThread stack
|
Enable DHCPv6 server capability in OpenThread stack
|
||||||
|
|
||||||
|
config OPENTHREAD_SLAAC
|
||||||
|
bool "SLAAC support"
|
||||||
|
help
|
||||||
|
Enable SLAAC capability in OpenThread stack
|
||||||
|
|
||||||
|
config OPENTHREAD_ENABLE_SERVICE
|
||||||
|
bool "Service support"
|
||||||
|
help
|
||||||
|
Enable service capability in OpenThread stack
|
||||||
|
|
||||||
|
config OPENTHREAD_RAW
|
||||||
|
bool "Raw Link support"
|
||||||
|
help
|
||||||
|
Enable raw link support in OpenThread stack
|
||||||
|
|
||||||
|
config OPENTHREAD_BORDER_AGENT
|
||||||
|
bool "Border Agent support"
|
||||||
|
help
|
||||||
|
Enable border agent support in OpenThread stack
|
||||||
|
|
||||||
|
config OPENTHREAD_BORDER_ROUTER
|
||||||
|
bool "Border Router support"
|
||||||
|
help
|
||||||
|
Enable border router support in OpenThread stack
|
||||||
|
|
||||||
|
config OPENTHREAD_NCP
|
||||||
|
bool "Network Co-Processor"
|
||||||
|
select RING_BUFFER
|
||||||
|
select UART_INTERRUPT_DRIVEN
|
||||||
|
help
|
||||||
|
Enable NCP in OpenThread stack
|
||||||
|
|
||||||
|
config OPENTHREAD_NCP_RADIO
|
||||||
|
bool "Network Co-Processor as Radio"
|
||||||
|
depends on OPENTHREAD_NCP
|
||||||
|
help
|
||||||
|
Enable NCP in OpenThread stack as radio-only
|
||||||
|
|
||||||
|
|
||||||
|
config OPENTHREAD_NCP_SPINEL_ON_UART_DEV_NAME
|
||||||
|
string "UART device to use for NCP SPINEL"
|
||||||
|
default "UART_0"
|
||||||
|
depends on OPENTHREAD_NCP
|
||||||
|
help
|
||||||
|
UART device to use for NCP SPINEL
|
||||||
|
|
||||||
|
config OPENTHREAD_NCP_UART_RING_BUFFER_SIZE
|
||||||
|
int "Set NCP UART ring buffer size"
|
||||||
|
default 4096
|
||||||
|
depends on OPENTHREAD_NCP
|
||||||
|
help
|
||||||
|
TX buffer size for the OpenThread NCP UART
|
||||||
|
|
||||||
|
config OPENTHREAD_NCP_SPINEL_ON_UART_ACM
|
||||||
|
bool "Run SPINEL over USB-ACM"
|
||||||
|
depends on OPENTHREAD_NCP && USB_CDC_ACM
|
||||||
|
help
|
||||||
|
Is the SPINEL device a USB-CDC-ACM device
|
||||||
|
|
||||||
|
config OPENTHREAD_UDP_FORWARD
|
||||||
|
bool "UDP forward support"
|
||||||
|
help
|
||||||
|
Enable UDP forward support in OpenThread stack
|
||||||
|
|
||||||
config OPENTHREAD_PLATFORM_INFO
|
config OPENTHREAD_PLATFORM_INFO
|
||||||
string "Platform information for OpenThread"
|
string "Platform information for OpenThread"
|
||||||
default "ZEPHYR"
|
default "ZEPHYR"
|
||||||
|
|
|
@ -10,6 +10,7 @@ zephyr_library_sources(
|
||||||
radio.c
|
radio.c
|
||||||
settings.c
|
settings.c
|
||||||
spi.c
|
spi.c
|
||||||
|
uart.c
|
||||||
)
|
)
|
||||||
|
|
||||||
zephyr_library_sources_ifdef(CONFIG_OPENTHREAD_SHELL shell.c)
|
zephyr_library_sources_ifdef(CONFIG_OPENTHREAD_SHELL shell.c)
|
||||||
|
|
|
@ -142,4 +142,12 @@
|
||||||
*/
|
*/
|
||||||
#define RADIO_CONFIG_SRC_MATCH_EXT_ENTRY_NUM 0
|
#define RADIO_CONFIG_SRC_MATCH_EXT_ENTRY_NUM 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @def OPENTHREAD_CONFIG_NCP_BUFFER_SIZE
|
||||||
|
*
|
||||||
|
* The size of the NCP buffers.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define OPENTHREAD_CONFIG_NCP_BUFFER_SIZE 2048
|
||||||
|
|
||||||
#endif /* OPENTHREAD_CORE_NRF52840_CONFIG_H_ */
|
#endif /* OPENTHREAD_CORE_NRF52840_CONFIG_H_ */
|
||||||
|
|
|
@ -45,6 +45,14 @@ void platformRadioInit(void);
|
||||||
*/
|
*/
|
||||||
void platformRadioProcess(otInstance *aInstance);
|
void platformRadioProcess(otInstance *aInstance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function performs UART driver processing.
|
||||||
|
*
|
||||||
|
* @param[in] aInstance The OpenThread instance structure.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void platformUartProcess(otInstance *aInstance);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get current channel from radio driver.
|
* Get current channel from radio driver.
|
||||||
*
|
*
|
||||||
|
|
219
subsys/net/lib/openthread/platform/uart.c
Normal file
219
subsys/net/lib/openthread/platform/uart.c
Normal file
|
@ -0,0 +1,219 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 Tridonic GmbH & Co KG
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define LOG_LEVEL CONFIG_OPENTHREAD_LOG_LEVEL
|
||||||
|
#define LOG_MODULE_NAME net_otPlat_uart
|
||||||
|
|
||||||
|
#include <logging/log.h>
|
||||||
|
LOG_MODULE_REGISTER(LOG_MODULE_NAME);
|
||||||
|
|
||||||
|
#include <kernel.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <drivers/uart.h>
|
||||||
|
|
||||||
|
#include <sys/ring_buffer.h>
|
||||||
|
#include <sys/atomic.h>
|
||||||
|
|
||||||
|
#ifdef CONFIG_OPENTHREAD_NCP_SPINEL_ON_UART_ACM
|
||||||
|
#include <usb/usb_device.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <openthread-system.h>
|
||||||
|
#include <openthread/platform/uart.h>
|
||||||
|
|
||||||
|
#include "platform-zephyr.h"
|
||||||
|
|
||||||
|
struct openthread_uart {
|
||||||
|
struct ring_buf *tx_ringbuf;
|
||||||
|
struct ring_buf *rx_ringbuf;
|
||||||
|
struct device *dev;
|
||||||
|
atomic_t tx_busy;
|
||||||
|
atomic_t tx_finished;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define OT_UART_DEFINE(_name, _ringbuf_size) \
|
||||||
|
RING_BUF_DECLARE(_name##_tx_ringbuf, _ringbuf_size); \
|
||||||
|
RING_BUF_DECLARE(_name##_rx_ringbuf, _ringbuf_size); \
|
||||||
|
static struct openthread_uart _name = { \
|
||||||
|
.tx_ringbuf = &_name##_tx_ringbuf, \
|
||||||
|
.rx_ringbuf = &_name##_rx_ringbuf, \
|
||||||
|
}
|
||||||
|
|
||||||
|
OT_UART_DEFINE(ot_uart, CONFIG_OPENTHREAD_NCP_UART_RING_BUFFER_SIZE);
|
||||||
|
|
||||||
|
#define RX_FIFO_SIZE 128
|
||||||
|
|
||||||
|
static void uart_rx_handle(void)
|
||||||
|
{
|
||||||
|
u8_t *data;
|
||||||
|
u32_t len;
|
||||||
|
u32_t rd_len;
|
||||||
|
bool new_data = false;
|
||||||
|
|
||||||
|
do {
|
||||||
|
len = ring_buf_put_claim(
|
||||||
|
ot_uart.rx_ringbuf, &data,
|
||||||
|
ot_uart.rx_ringbuf->size);
|
||||||
|
if (len > 0) {
|
||||||
|
rd_len = uart_fifo_read(
|
||||||
|
ot_uart.dev, data, len);
|
||||||
|
|
||||||
|
if (rd_len > 0) {
|
||||||
|
new_data = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int err = ring_buf_put_finish(
|
||||||
|
ot_uart.rx_ringbuf, rd_len);
|
||||||
|
(void)err;
|
||||||
|
__ASSERT_NO_MSG(err == 0);
|
||||||
|
} else {
|
||||||
|
u8_t dummy;
|
||||||
|
|
||||||
|
/* No space in the ring buffer - consume byte. */
|
||||||
|
LOG_WRN("RX ring buffer full.");
|
||||||
|
|
||||||
|
rd_len = uart_fifo_read(
|
||||||
|
ot_uart.dev, &dummy, 1);
|
||||||
|
}
|
||||||
|
} while (rd_len && (rd_len == len));
|
||||||
|
|
||||||
|
if (new_data) {
|
||||||
|
otSysEventSignalPending();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void uart_tx_handle(void)
|
||||||
|
{
|
||||||
|
u32_t len;
|
||||||
|
const u8_t *data;
|
||||||
|
|
||||||
|
len = ring_buf_get_claim(ot_uart.tx_ringbuf, (u8_t **)&data,
|
||||||
|
ot_uart.tx_ringbuf->size);
|
||||||
|
if (len) {
|
||||||
|
int err;
|
||||||
|
|
||||||
|
len = uart_fifo_fill(ot_uart.dev, data, len);
|
||||||
|
err = ring_buf_get_finish(ot_uart.tx_ringbuf, len);
|
||||||
|
(void)err;
|
||||||
|
__ASSERT_NO_MSG(err == 0);
|
||||||
|
} else {
|
||||||
|
uart_irq_tx_disable(ot_uart.dev);
|
||||||
|
ot_uart.tx_busy = 0;
|
||||||
|
atomic_set(&(ot_uart.tx_finished), 1);
|
||||||
|
otSysEventSignalPending();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void uart_callback(void *user_data)
|
||||||
|
{
|
||||||
|
ARG_UNUSED(user_data);
|
||||||
|
|
||||||
|
while (uart_irq_update(ot_uart.dev) &&
|
||||||
|
uart_irq_is_pending(ot_uart.dev)) {
|
||||||
|
|
||||||
|
if (uart_irq_rx_ready(ot_uart.dev)) {
|
||||||
|
uart_rx_handle();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uart_irq_tx_ready(ot_uart.dev)) {
|
||||||
|
uart_tx_handle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void platformUartProcess(otInstance *aInstance)
|
||||||
|
{
|
||||||
|
u32_t len = 0;
|
||||||
|
const u8_t *data;
|
||||||
|
|
||||||
|
/* Process UART RX */
|
||||||
|
while ((len = ring_buf_get_claim(
|
||||||
|
ot_uart.rx_ringbuf,
|
||||||
|
(u8_t **)&data,
|
||||||
|
ot_uart.rx_ringbuf->size)) > 0) {
|
||||||
|
int err;
|
||||||
|
|
||||||
|
otPlatUartReceived(data, len);
|
||||||
|
err = ring_buf_get_finish(
|
||||||
|
ot_uart.rx_ringbuf,
|
||||||
|
len);
|
||||||
|
(void)err;
|
||||||
|
__ASSERT_NO_MSG(err == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process UART TX */
|
||||||
|
if (ot_uart.tx_finished) {
|
||||||
|
LOG_DBG("UART TX done");
|
||||||
|
otPlatUartSendDone();
|
||||||
|
ot_uart.tx_finished = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
otError otPlatUartEnable(void)
|
||||||
|
{
|
||||||
|
ot_uart.dev = device_get_binding(
|
||||||
|
CONFIG_OPENTHREAD_NCP_SPINEL_ON_UART_DEV_NAME);
|
||||||
|
|
||||||
|
if ((&ot_uart)->dev == NULL) {
|
||||||
|
LOG_ERR("UART device not found");
|
||||||
|
return OT_ERROR_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_OPENTHREAD_NCP_SPINEL_ON_UART_ACM
|
||||||
|
int ret = usb_enable(NULL);
|
||||||
|
u32_t baudrate = 0U;
|
||||||
|
|
||||||
|
if (ret != 0) {
|
||||||
|
LOG_ERR("Failed to enable USB");
|
||||||
|
return OT_ERROR_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INF("Wait for host to settle");
|
||||||
|
k_sleep(MSEC_PER_SEC * 1);
|
||||||
|
|
||||||
|
ret = uart_line_ctrl_get(ot_uart.dev,
|
||||||
|
UART_LINE_CTRL_BAUD_RATE,
|
||||||
|
&baudrate);
|
||||||
|
if (ret) {
|
||||||
|
LOG_WRN("Failed to get baudrate, ret code %d", ret);
|
||||||
|
} else {
|
||||||
|
LOG_INF("Baudrate detected: %d", baudrate);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uart_irq_callback_user_data_set(
|
||||||
|
ot_uart.dev,
|
||||||
|
uart_callback,
|
||||||
|
(void *)&ot_uart);
|
||||||
|
uart_irq_rx_enable(ot_uart.dev);
|
||||||
|
|
||||||
|
return OT_ERROR_NONE;
|
||||||
|
};
|
||||||
|
|
||||||
|
otError otPlatUartDisable(void)
|
||||||
|
{
|
||||||
|
/* TODO: uninit UART */
|
||||||
|
LOG_WRN("%s not implemented.", __func__);
|
||||||
|
return OT_ERROR_NOT_IMPLEMENTED;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
otError otPlatUartSend(const u8_t *aBuf, u16_t aBufLength)
|
||||||
|
{
|
||||||
|
size_t cnt = ring_buf_put(ot_uart.tx_ringbuf, aBuf, aBufLength);
|
||||||
|
|
||||||
|
if (atomic_set(&(ot_uart.tx_busy), 1) == 0) {
|
||||||
|
uart_irq_tx_enable(ot_uart.dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cnt == aBufLength) {
|
||||||
|
return OT_ERROR_NONE;
|
||||||
|
} else {
|
||||||
|
return OT_ERROR_BUSY;
|
||||||
|
}
|
||||||
|
};
|
Loading…
Add table
Add a link
Reference in a new issue