1 /*
2 * Copyright (c) 2020 Tridonic GmbH & Co KG
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define LOG_LEVEL CONFIG_OPENTHREAD_LOG_LEVEL
8 #define LOG_MODULE_NAME net_otPlat_uart
9
10 #include <zephyr/logging/log.h>
11 LOG_MODULE_REGISTER(LOG_MODULE_NAME);
12
13 #include <zephyr/kernel.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16
17 #include <zephyr/drivers/uart.h>
18
19 #include <zephyr/sys/ring_buffer.h>
20 #include <zephyr/sys/atomic.h>
21
22 #include <zephyr/usb/usb_device.h>
23
24 #include <openthread/ncp.h>
25 #include <openthread-system.h>
26 #include <utils/uart.h>
27
28 #include "platform-zephyr.h"
29
30 struct openthread_uart {
31 struct ring_buf *rx_ringbuf;
32 const struct device *dev;
33 atomic_t tx_busy;
34 atomic_t tx_finished;
35 };
36
37 #define OT_UART_DEFINE(_name, _ringbuf_size) \
38 RING_BUF_DECLARE(_name##_rx_ringbuf, _ringbuf_size); \
39 static struct openthread_uart _name = { \
40 .rx_ringbuf = &_name##_rx_ringbuf, \
41 }
42
43 OT_UART_DEFINE(ot_uart, CONFIG_OPENTHREAD_COPROCESSOR_UART_RING_BUFFER_SIZE);
44
45 #define RX_FIFO_SIZE 128
46
47 static bool is_panic_mode;
48 static const uint8_t *write_buffer;
49 static uint16_t write_length;
50
uart_rx_handle(const struct device * dev)51 static void uart_rx_handle(const struct device *dev)
52 {
53 uint8_t *data;
54 uint32_t len;
55 uint32_t rd_len;
56 bool new_data = false;
57
58 do {
59 len = ring_buf_put_claim(
60 ot_uart.rx_ringbuf, &data,
61 ot_uart.rx_ringbuf->size);
62 if (len > 0) {
63 rd_len = uart_fifo_read(dev, data, len);
64 if (rd_len > 0) {
65 new_data = true;
66 }
67
68 int err = ring_buf_put_finish(
69 ot_uart.rx_ringbuf, rd_len);
70 (void)err;
71 __ASSERT_NO_MSG(err == 0);
72 } else {
73 uint8_t dummy;
74
75 /* No space in the ring buffer - consume byte. */
76 LOG_WRN("RX ring buffer full.");
77
78 rd_len = uart_fifo_read(dev, &dummy, 1);
79 }
80 } while (rd_len && (rd_len == len));
81
82 if (new_data) {
83 otSysEventSignalPending();
84 }
85 }
86
uart_tx_handle(const struct device * dev)87 static void uart_tx_handle(const struct device *dev)
88 {
89 uint32_t len;
90
91 if (write_length) {
92 len = uart_fifo_fill(dev, write_buffer, write_length);
93 write_buffer += len;
94 write_length -= len;
95 } else {
96 uart_irq_tx_disable(dev);
97 ot_uart.tx_busy = 0;
98 atomic_set(&(ot_uart.tx_finished), 1);
99 otSysEventSignalPending();
100 }
101 }
102
uart_callback(const struct device * dev,void * user_data)103 static void uart_callback(const struct device *dev, void *user_data)
104 {
105 ARG_UNUSED(user_data);
106
107 while (uart_irq_update(dev) && uart_irq_is_pending(dev)) {
108
109 if (uart_irq_rx_ready(dev)) {
110 uart_rx_handle(dev);
111 }
112
113 if (uart_irq_tx_ready(dev) &&
114 atomic_get(&ot_uart.tx_busy) == 1) {
115 uart_tx_handle(dev);
116 }
117 }
118 }
119
otPlatUartReceived(const uint8_t * aBuf,uint16_t aBufLength)120 void otPlatUartReceived(const uint8_t *aBuf, uint16_t aBufLength)
121 {
122 otNcpHdlcReceive(aBuf, aBufLength);
123 }
124
otPlatUartSendDone(void)125 void otPlatUartSendDone(void)
126 {
127 otNcpHdlcSendDone();
128 }
129
platformUartProcess(otInstance * aInstance)130 void platformUartProcess(otInstance *aInstance)
131 {
132 uint32_t len = 0;
133 const uint8_t *data;
134
135 /* Process UART RX */
136 while ((len = ring_buf_get_claim(
137 ot_uart.rx_ringbuf,
138 (uint8_t **)&data,
139 ot_uart.rx_ringbuf->size)) > 0) {
140 int err;
141
142 otPlatUartReceived(data, len);
143 err = ring_buf_get_finish(
144 ot_uart.rx_ringbuf,
145 len);
146 (void)err;
147 __ASSERT_NO_MSG(err == 0);
148 }
149
150 /* Process UART TX */
151 if (ot_uart.tx_finished) {
152 LOG_DBG("UART TX done");
153 otPlatUartSendDone();
154 ot_uart.tx_finished = 0;
155 }
156 }
157
otPlatUartEnable(void)158 otError otPlatUartEnable(void)
159 {
160 ot_uart.dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_ot_uart));
161
162 if (!device_is_ready(ot_uart.dev)) {
163 LOG_ERR("UART device not ready");
164 return OT_ERROR_FAILED;
165 }
166
167 uart_irq_callback_user_data_set(ot_uart.dev,
168 uart_callback,
169 (void *)&ot_uart);
170
171 if (DT_NODE_HAS_COMPAT(DT_CHOSEN(zephyr_ot_uart), zephyr_cdc_acm_uart)) {
172 int ret;
173
174 ret = usb_enable(NULL);
175 if (ret != 0 && ret != -EALREADY) {
176 LOG_ERR("Failed to enable USB");
177 return OT_ERROR_FAILED;
178 }
179
180 /* Data Carrier Detect Modem - mark connection as established */
181 (void)uart_line_ctrl_set(ot_uart.dev, UART_LINE_CTRL_DCD, 1);
182 /* Data Set Ready - the NCP SoC is ready to communicate */
183 (void)uart_line_ctrl_set(ot_uart.dev, UART_LINE_CTRL_DSR, 1);
184 }
185
186 uart_irq_rx_enable(ot_uart.dev);
187
188 return OT_ERROR_NONE;
189 }
190
otPlatUartDisable(void)191 otError otPlatUartDisable(void)
192 {
193 if (DT_NODE_HAS_COMPAT(DT_CHOSEN(zephyr_ot_uart), zephyr_cdc_acm_uart)) {
194 int ret = usb_disable();
195
196 if (ret) {
197 LOG_WRN("Failed to disable USB (%d)", ret);
198 }
199 }
200
201 uart_irq_tx_disable(ot_uart.dev);
202 uart_irq_rx_disable(ot_uart.dev);
203 return OT_ERROR_NONE;
204 }
205
otPlatUartSend(const uint8_t * aBuf,uint16_t aBufLength)206 otError otPlatUartSend(const uint8_t *aBuf, uint16_t aBufLength)
207 {
208 if (aBuf == NULL) {
209 return OT_ERROR_FAILED;
210 }
211
212 if (atomic_cas(&(ot_uart.tx_busy), 0, 1)) {
213 write_buffer = aBuf;
214 write_length = aBufLength;
215
216 if (is_panic_mode) {
217 /* In panic mode all data have to be send immediately
218 * without using interrupts
219 */
220 otPlatUartFlush();
221 } else {
222 uart_irq_tx_enable(ot_uart.dev);
223 }
224 return OT_ERROR_NONE;
225 }
226
227 return OT_ERROR_BUSY;
228 }
229
otPlatUartFlush(void)230 otError otPlatUartFlush(void)
231 {
232 otError result = OT_ERROR_NONE;
233
234 if (write_length) {
235 for (size_t i = 0; i < write_length; i++) {
236 uart_poll_out(ot_uart.dev, *(write_buffer+i));
237 }
238 }
239
240 ot_uart.tx_busy = 0;
241 atomic_set(&(ot_uart.tx_finished), 1);
242 otSysEventSignalPending();
243 return result;
244 }
245
platformUartPanic(void)246 void platformUartPanic(void)
247 {
248 is_panic_mode = true;
249 /* In panic mode data are send without using interrupts.
250 * Reception in this mode is not supported.
251 */
252 uart_irq_tx_disable(ot_uart.dev);
253 uart_irq_rx_disable(ot_uart.dev);
254 }
255