zephyr/modules/openthread/platform/uart.c
Przemyslaw Bida cc85223ed4 net: openthread: Remove waiting for DTR in openthread UART.
Uart driver for openthread have been waiting for host to start
communicating with coprocessor, during booting of the Zephyr and
by that blocking start os OS. There is no longer a need for
that since the stack will be soft rebooted after host connects
to coprocessor, removing the need to wait on host communication.

Signed-off-by: Przemyslaw Bida <przemyslaw.bida@nordicsemi.no>
2023-10-20 14:59:47 +02:00

255 lines
5.1 KiB
C

/*
* 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 <zephyr/logging/log.h>
LOG_MODULE_REGISTER(LOG_MODULE_NAME);
#include <zephyr/kernel.h>
#include <stdio.h>
#include <stdlib.h>
#include <zephyr/drivers/uart.h>
#include <zephyr/sys/ring_buffer.h>
#include <zephyr/sys/atomic.h>
#include <zephyr/usb/usb_device.h>
#include <openthread/ncp.h>
#include <openthread-system.h>
#include <utils/uart.h>
#include "platform-zephyr.h"
struct openthread_uart {
struct ring_buf *rx_ringbuf;
const struct device *dev;
atomic_t tx_busy;
atomic_t tx_finished;
};
#define OT_UART_DEFINE(_name, _ringbuf_size) \
RING_BUF_DECLARE(_name##_rx_ringbuf, _ringbuf_size); \
static struct openthread_uart _name = { \
.rx_ringbuf = &_name##_rx_ringbuf, \
}
OT_UART_DEFINE(ot_uart, CONFIG_OPENTHREAD_COPROCESSOR_UART_RING_BUFFER_SIZE);
#define RX_FIFO_SIZE 128
static bool is_panic_mode;
static const uint8_t *write_buffer;
static uint16_t write_length;
static void uart_rx_handle(const struct device *dev)
{
uint8_t *data;
uint32_t len;
uint32_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(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 {
uint8_t dummy;
/* No space in the ring buffer - consume byte. */
LOG_WRN("RX ring buffer full.");
rd_len = uart_fifo_read(dev, &dummy, 1);
}
} while (rd_len && (rd_len == len));
if (new_data) {
otSysEventSignalPending();
}
}
static void uart_tx_handle(const struct device *dev)
{
uint32_t len;
if (write_length) {
len = uart_fifo_fill(dev, write_buffer, write_length);
write_buffer += len;
write_length -= len;
} else {
uart_irq_tx_disable(dev);
ot_uart.tx_busy = 0;
atomic_set(&(ot_uart.tx_finished), 1);
otSysEventSignalPending();
}
}
static void uart_callback(const struct device *dev, void *user_data)
{
ARG_UNUSED(user_data);
while (uart_irq_update(dev) && uart_irq_is_pending(dev)) {
if (uart_irq_rx_ready(dev)) {
uart_rx_handle(dev);
}
if (uart_irq_tx_ready(dev) &&
atomic_get(&ot_uart.tx_busy) == 1) {
uart_tx_handle(dev);
}
}
}
void otPlatUartReceived(const uint8_t *aBuf, uint16_t aBufLength)
{
otNcpHdlcReceive(aBuf, aBufLength);
}
void otPlatUartSendDone(void)
{
otNcpHdlcSendDone();
}
void platformUartProcess(otInstance *aInstance)
{
uint32_t len = 0;
const uint8_t *data;
/* Process UART RX */
while ((len = ring_buf_get_claim(
ot_uart.rx_ringbuf,
(uint8_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_DT_GET(DT_CHOSEN(zephyr_ot_uart));
if (!device_is_ready(ot_uart.dev)) {
LOG_ERR("UART device not ready");
return OT_ERROR_FAILED;
}
uart_irq_callback_user_data_set(ot_uart.dev,
uart_callback,
(void *)&ot_uart);
if (DT_NODE_HAS_COMPAT(DT_CHOSEN(zephyr_ot_uart), zephyr_cdc_acm_uart)) {
int ret;
ret = usb_enable(NULL);
if (ret != 0 && ret != -EALREADY) {
LOG_ERR("Failed to enable USB");
return OT_ERROR_FAILED;
}
/* Data Carrier Detect Modem - mark connection as established */
(void)uart_line_ctrl_set(ot_uart.dev, UART_LINE_CTRL_DCD, 1);
/* Data Set Ready - the NCP SoC is ready to communicate */
(void)uart_line_ctrl_set(ot_uart.dev, UART_LINE_CTRL_DSR, 1);
}
uart_irq_rx_enable(ot_uart.dev);
return OT_ERROR_NONE;
}
otError otPlatUartDisable(void)
{
if (DT_NODE_HAS_COMPAT(DT_CHOSEN(zephyr_ot_uart), zephyr_cdc_acm_uart)) {
int ret = usb_disable();
if (ret) {
LOG_WRN("Failed to disable USB (%d)", ret);
}
}
uart_irq_tx_disable(ot_uart.dev);
uart_irq_rx_disable(ot_uart.dev);
return OT_ERROR_NONE;
}
otError otPlatUartSend(const uint8_t *aBuf, uint16_t aBufLength)
{
if (aBuf == NULL) {
return OT_ERROR_FAILED;
}
if (atomic_cas(&(ot_uart.tx_busy), 0, 1)) {
write_buffer = aBuf;
write_length = aBufLength;
if (is_panic_mode) {
/* In panic mode all data have to be send immediately
* without using interrupts
*/
otPlatUartFlush();
} else {
uart_irq_tx_enable(ot_uart.dev);
}
return OT_ERROR_NONE;
}
return OT_ERROR_BUSY;
}
otError otPlatUartFlush(void)
{
otError result = OT_ERROR_NONE;
if (write_length) {
for (size_t i = 0; i < write_length; i++) {
uart_poll_out(ot_uart.dev, *(write_buffer+i));
}
}
ot_uart.tx_busy = 0;
atomic_set(&(ot_uart.tx_finished), 1);
otSysEventSignalPending();
return result;
}
void platformUartPanic(void)
{
is_panic_mode = true;
/* In panic mode data are send without using interrupts.
* Reception in this mode is not supported.
*/
uart_irq_tx_disable(ot_uart.dev);
uart_irq_rx_disable(ot_uart.dev);
}