1 /*
2 * Copyright (C) 2022 Beken Corporation
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <stdio.h>
17 #include <string.h>
18
19 #include "cli.h"
20 #include "shell_drv.h"
21
22 #define TX_QUEUE_LEN 8
23 #define RX_BUFF_SIZE 160
24 #define ECHO_BUFF_SIZE 64
25
26
27 typedef struct
28 {
29 u8 * packet;
30 u16 len;
31 u16 tag;
32 } dev_tx_packet_t;
33
34
35 typedef struct
36 {
37 u8 uart_id;
38
39 /* ======== TX channel ======= */
40 /* tx queue */
41 dev_tx_packet_t tx_list[TX_QUEUE_LEN];
42 u16 list_out_idx;
43 u16 list_in_idx;
44
45 /* currently tx packet info */
46 u8 *cur_packet;
47 u16 packet_len;
48 u16 packet_tag;
49 u16 packet_tx_len;
50
51 u8 tx_stopped;
52
53 u8 echo_buff[ECHO_BUFF_SIZE];
54 u8 echo_wr_idx;
55 u8 echo_rd_idx;
56
57 tx_complete_t tx_complete_callback;
58
59 /* ======== RX channel ======= */
60 /* rx buffer */
61 u8 rx_buff[RX_BUFF_SIZE];
62 u16 rx_buff_wr_idx;
63 u16 rx_buff_rd_idx;
64
65 u8 rx_over_flow;
66
67 rx_indicate_t rx_indicate_callback;
68
69 } shell_uart_ext_t;
70
71 static bool_t shell_uart_init(shell_dev_t * shell_dev);
72 static bool_t shell_uart_open(shell_dev_t * shell_dev, tx_complete_t tx_callback, rx_indicate_t rx_callback);
73 static u16 shell_uart_write_async(shell_dev_t * shell_dev, u8 * pBuf, u16 BufLen, u16 Tag);
74 static u16 shell_uart_read(shell_dev_t * shell_dev, u8 * pBuf, u16 BufLen);
75 static u16 shell_uart_write_sync(shell_dev_t * shell_dev, u8 * pBuf, u16 BufLen);
76 static u16 shell_uart_write_echo(shell_dev_t * shell_dev, u8 * pBuf, u16 BufLen);
77 static bool_t shell_uart_ctrl(shell_dev_t * shell_dev, u8 cmd, void *param);
78 static bool_t shell_uart_close(shell_dev_t * shell_dev);
79
80 static const shell_dev_drv_t shell_uart_drv =
81 {
82 .init = shell_uart_init,
83 .open = shell_uart_open,
84 .write_async = shell_uart_write_async,
85 .read = shell_uart_read,
86 .write_sync = shell_uart_write_sync,
87 .write_echo = shell_uart_write_echo,
88 .io_ctrl = shell_uart_ctrl,
89 .close = shell_uart_close
90 };
91
92 static shell_uart_ext_t uart1_ext =
93 {
94 .uart_id = CONFIG_UART_PRINT_PORT
95 };
96
97 shell_dev_t shell_uart =
98 {
99 .dev_drv = (struct _shell_dev_drv *)&shell_uart_drv,
100 .dev_type = SHELL_DEV_UART,
101 .dev_ext = &uart1_ext
102 };
103
104 #if 0
105 static shell_uart_ext_t uart3_ext =
106 {
107 .uart_id = UART_ID_2
108 };
109
110 shell_dev_t shell_uart3 =
111 {
112 .dev_drv = (struct _shell_dev_drv *)&shell_uart_drv,
113 .dev_type = SHELL_DEV_UART,
114 .dev_ext = &uart3_ext
115 };
116 #endif
117
118 /* =============================== internal functions =========================== */
119
shell_uart_rx_isr(int uartn,shell_uart_ext_t * uart_ext)120 static void shell_uart_rx_isr(int uartn, shell_uart_ext_t *uart_ext)
121 {
122 u16 free_buff_len, rx_cnt = 0;
123 u8 rx_data;
124 int ret = -1;
125
126 (void)uartn;
127
128 if(uart_ext->rx_buff_wr_idx >= uart_ext->rx_buff_rd_idx)
129 {
130 free_buff_len = RX_BUFF_SIZE - uart_ext->rx_buff_wr_idx + uart_ext->rx_buff_rd_idx;
131 }
132 else
133 {
134 free_buff_len = uart_ext->rx_buff_rd_idx - uart_ext->rx_buff_wr_idx;
135 }
136
137 while(bTRUE) /* read all data from rx-FIFO. */
138 {
139 ret = uart_read_byte_ex(uart_ext->uart_id, &rx_data);
140 if (ret == -1)
141 break;
142
143 rx_cnt++;
144
145 /* rx_buff_wr_idx == rx_buff_rd_idx means empty, so reserve one byte. */
146 if(rx_cnt < free_buff_len) /* reserved one byte space. */
147 {
148 uart_ext->rx_buff[uart_ext->rx_buff_wr_idx] = rx_data;
149
150 uart_ext->rx_buff_wr_idx = (uart_ext->rx_buff_wr_idx + 1) % RX_BUFF_SIZE;
151
152 }
153 else
154 {
155 /* discard rx-data, rx overflow. */
156 uart_ext->rx_over_flow = 1; // bTRUE; // rx overflow, disable rx interrupt to stop rx.
157 }
158 }
159
160 if(uart_ext->rx_indicate_callback != NULL)
161 {
162 uart_ext->rx_indicate_callback();
163 }
164 }
165
shell_uart_tx_isr(int uartn,shell_uart_ext_t * uart_ext)166 static void shell_uart_tx_isr(int uartn, shell_uart_ext_t *uart_ext)
167 {
168 int ret;
169 (void)uartn;
170
171 while(bTRUE) /* write data to tx-FIFO. */
172 {
173 ret = uart_write_ready(uart_ext->uart_id);
174 if(ret != 0)
175 break;
176
177 /* previous packet tx complete, check ECHO before new packet. */
178 if((uart_ext->cur_packet == NULL) || (uart_ext->packet_len == 0))
179 {
180 if(uart_ext->echo_rd_idx != uart_ext->echo_wr_idx) /* tx echo firstly. */
181 {
182 uart_write_byte(uart_ext->uart_id, uart_ext->echo_buff[uart_ext->echo_rd_idx]);
183
184 uart_ext->echo_rd_idx = (uart_ext->echo_rd_idx + 1) % ECHO_BUFF_SIZE;
185
186 continue; /* continue to ECHO next byte to tx-FIFO. */
187 }
188 else
189 {
190 if(uart_ext->list_out_idx != uart_ext->list_in_idx)
191 {
192 uart_ext->cur_packet = uart_ext->tx_list[uart_ext->list_out_idx].packet;
193 uart_ext->packet_len = uart_ext->tx_list[uart_ext->list_out_idx].len;
194 uart_ext->packet_tag = uart_ext->tx_list[uart_ext->list_out_idx].tag;
195 uart_ext->packet_tx_len = 0;
196 }
197 else
198 {
199 /* all packets tx complete. */
200 /* disable tx interrupt ? */ // disable TX firstly, then set tx_stopped to 1.
201 bk_uart_disable_tx_interrupt(uart_ext->uart_id);
202
203 uart_ext->tx_stopped = 1; /* bTRUE;*/ /* all data tranferred, tx stopped.*/
204 break;
205 }
206 }
207 }
208
209 if(uart_ext->packet_tx_len < uart_ext->packet_len)
210 {
211 uart_write_byte(uart_ext->uart_id, uart_ext->cur_packet[uart_ext->packet_tx_len]);
212
213 uart_ext->packet_tx_len++;
214
215 continue; /* continue to TX next byte to tx-FIFO. */
216 }
217 else
218 {
219 /* sent the whole packet, notify app. */
220 if(uart_ext->tx_complete_callback != NULL)
221 {
222 uart_ext->tx_complete_callback(uart_ext->cur_packet, uart_ext->packet_tag);
223 }
224
225 uart_ext->cur_packet = NULL;
226 uart_ext->packet_len = 0;
227 uart_ext->packet_tx_len = 0;
228
229 /* to next packet. */
230 uart_ext->list_out_idx = (uart_ext->list_out_idx + 1) % TX_QUEUE_LEN;
231
232 continue; /* continue to TX next packet. */
233 }
234 }
235
236 }
237
shell_uart_flush(shell_uart_ext_t * uart_ext)238 static void shell_uart_flush(shell_uart_ext_t *uart_ext)
239 {
240 int ret;
241
242 while(uart_ext->tx_stopped == 0) /* log tx pending. */
243 {
244 ret = uart_write_ready(uart_ext->uart_id);
245 if(ret == BK_OK)
246 {
247 shell_uart_tx_isr(uart_ext->uart_id, uart_ext);
248 }
249 }
250 }
251
shell_uart_tx_trigger(shell_uart_ext_t * uart_ext)252 static void shell_uart_tx_trigger(shell_uart_ext_t *uart_ext)
253 {
254 if(uart_ext->tx_stopped == 0)
255 return;
256
257 uart_ext->tx_stopped = 0; // set tx_stopped to 0 firstly, then enable TX.
258
259 bk_uart_enable_tx_interrupt(uart_ext->uart_id);
260 }
261
262 /* =============================== shell uart driver APIs =========================== */
263
shell_uart_init(shell_dev_t * shell_dev)264 static bool_t shell_uart_init(shell_dev_t * shell_dev)
265 {
266 u8 uart_id;
267 shell_uart_ext_t *uart_ext;
268
269 if(shell_dev == NULL)
270 return bFALSE;
271
272 uart_ext = (shell_uart_ext_t *)shell_dev->dev_ext;
273 uart_id = uart_ext->uart_id;
274
275 memset(uart_ext, 0, sizeof(shell_uart_ext_t));
276 uart_ext->rx_over_flow = 0;
277 uart_ext->tx_stopped = 1;
278 uart_ext->uart_id = uart_id;
279
280 return bTRUE;
281 }
282
shell_uart_open(shell_dev_t * shell_dev,tx_complete_t tx_callback,rx_indicate_t rx_callback)283 static bool_t shell_uart_open(shell_dev_t * shell_dev, tx_complete_t tx_callback, rx_indicate_t rx_callback)
284 {
285 shell_uart_ext_t *uart_ext;
286
287 if(shell_dev == NULL)
288 return bFALSE;
289
290 uart_ext = (shell_uart_ext_t *)shell_dev->dev_ext;
291
292 uart_ext->tx_complete_callback = tx_callback;
293 uart_ext->rx_indicate_callback = rx_callback;
294
295 bk_uart_disable_sw_fifo(uart_ext->uart_id);
296
297 // call uart driver to register isr callback;
298 bk_uart_register_rx_isr(uart_ext->uart_id, (uart_isr_t)shell_uart_rx_isr, uart_ext);
299 bk_uart_register_tx_isr(uart_ext->uart_id, (uart_isr_t)shell_uart_tx_isr, uart_ext);
300
301 bk_uart_enable_rx_interrupt(uart_ext->uart_id);
302
303 return bTRUE;
304 }
305
shell_uart_write_async(shell_dev_t * shell_dev,u8 * pBuf,u16 BufLen,u16 Tag)306 static u16 shell_uart_write_async(shell_dev_t * shell_dev, u8 * pBuf, u16 BufLen, u16 Tag)
307 {
308 u16 free_items;
309 shell_uart_ext_t *uart_ext;
310
311 if(shell_dev == NULL)
312 return 0;
313
314 uart_ext = (shell_uart_ext_t *)shell_dev->dev_ext;
315
316 if((pBuf == NULL) /*|| (BufLen == 0)*/)
317 return 0;
318
319 /* enqueue pBuf even if BufLen is 0, upper layer need tx-complete-callback to free this pBuf. */
320
321 if(uart_ext->list_out_idx > uart_ext->list_in_idx)
322 free_items = uart_ext->list_out_idx - uart_ext->list_in_idx;
323 else
324 free_items = TX_QUEUE_LEN - uart_ext->list_in_idx + uart_ext->list_out_idx;
325
326 /* list_out_idx == list_in_idx means empty, so reserved one item. */
327 if(free_items > 1)
328 {
329 uart_ext->tx_list[uart_ext->list_in_idx].packet = pBuf;
330 uart_ext->tx_list[uart_ext->list_in_idx].len = BufLen;
331 uart_ext->tx_list[uart_ext->list_in_idx].tag = Tag;
332
333 uart_ext->list_in_idx = (uart_ext->list_in_idx + 1) % TX_QUEUE_LEN;
334
335 shell_uart_tx_trigger(uart_ext);
336
337 return 1;
338 }
339 else
340 {
341 return 0;
342 }
343 }
344
shell_uart_read(shell_dev_t * shell_dev,u8 * pBuf,u16 BufLen)345 static u16 shell_uart_read(shell_dev_t * shell_dev, u8 * pBuf, u16 BufLen)
346 {
347 u16 read_cnt = 0;
348
349 shell_uart_ext_t *uart_ext;
350
351 if(shell_dev == NULL)
352 return 0;
353
354 uart_ext = (shell_uart_ext_t *)shell_dev->dev_ext;
355
356 if((pBuf == NULL) || (BufLen == 0))
357 return 0;
358
359 while(uart_ext->rx_buff_rd_idx != uart_ext->rx_buff_wr_idx)
360 {
361 pBuf[read_cnt] = uart_ext->rx_buff[uart_ext->rx_buff_rd_idx];
362
363 uart_ext->rx_buff_rd_idx = (uart_ext->rx_buff_rd_idx + 1) % RX_BUFF_SIZE;
364
365 read_cnt++;
366 if(read_cnt >= BufLen)
367 break;
368 }
369
370 return read_cnt;
371
372 }
373
374 /* call this after interrupt is DISABLED. */
shell_uart_write_sync(shell_dev_t * shell_dev,u8 * pBuf,u16 BufLen)375 static u16 shell_uart_write_sync(shell_dev_t * shell_dev, u8 * pBuf, u16 BufLen)
376 {
377 shell_uart_ext_t *uart_ext;
378
379 if(shell_dev == NULL)
380 return 0;
381
382 uart_ext = (shell_uart_ext_t *)shell_dev->dev_ext;
383
384 if((pBuf == NULL) || (BufLen == 0))
385 return 0;
386
387 u16 wr_cnt = 0;
388
389 while(bTRUE) /* write data to tx-FIFO. */
390 {
391 uart_write_byte(uart_ext->uart_id, *pBuf); // it is macro define, do NOT use *pBuf++;
392
393 pBuf++; wr_cnt++;
394
395 if(wr_cnt >= BufLen)
396 break;
397 }
398
399 return BufLen;
400 }
401
shell_uart_write_echo(shell_dev_t * shell_dev,u8 * pBuf,u16 BufLen)402 static u16 shell_uart_write_echo(shell_dev_t * shell_dev, u8 * pBuf, u16 BufLen)
403 {
404 u16 free_buff_len, wr_cnt = 0;
405
406 shell_uart_ext_t *uart_ext;
407
408 if(shell_dev == NULL)
409 return 0;
410
411 uart_ext = (shell_uart_ext_t *)shell_dev->dev_ext;
412
413 if((pBuf == NULL) || (BufLen == 0))
414 return 0;
415
416 if(uart_ext->echo_wr_idx >= uart_ext->echo_rd_idx)
417 {
418 free_buff_len = ECHO_BUFF_SIZE - uart_ext->echo_wr_idx + uart_ext->echo_rd_idx;
419 }
420 else
421 {
422 free_buff_len = uart_ext->echo_rd_idx - uart_ext->echo_wr_idx;
423 }
424
425 /* echo_wr_idx == echo_rd_idx means empty, so reserved one byte. */
426 while(free_buff_len > 1)
427 {
428 uart_ext->echo_buff[uart_ext->echo_wr_idx] = pBuf[wr_cnt];
429 uart_ext->echo_wr_idx = (uart_ext->echo_wr_idx + 1) % ECHO_BUFF_SIZE;
430
431 free_buff_len--;
432
433 wr_cnt++;
434 if(wr_cnt >= BufLen)
435 break;
436 }
437
438 if(wr_cnt > 0)
439 shell_uart_tx_trigger(uart_ext);
440
441 return wr_cnt;
442
443 }
444
shell_uart_ctrl(shell_dev_t * shell_dev,u8 cmd,void * param)445 static bool_t shell_uart_ctrl(shell_dev_t * shell_dev, u8 cmd, void *param)
446 {
447 shell_uart_ext_t *uart_ext;
448
449 if(shell_dev == NULL)
450 return bFALSE;
451
452 uart_ext = (shell_uart_ext_t *)shell_dev->dev_ext;
453
454 switch(cmd)
455 {
456 case SHELL_IO_CTRL_GET_STATUS:
457 if(param == NULL)
458 return bFALSE;
459
460 u16 free_items;
461
462 if(uart_ext->list_out_idx > uart_ext->list_in_idx)
463 free_items = uart_ext->list_out_idx - uart_ext->list_in_idx;
464 else
465 free_items = TX_QUEUE_LEN - uart_ext->list_in_idx + uart_ext->list_out_idx;
466
467 if(free_items > 1)
468 *((u16 *)param) = free_items - 1;
469 else
470 *((u16 *)param) = 0;
471
472 break;
473
474 case SHELL_IO_CTRL_RX_RESET:
475 uart_ext->rx_buff_rd_idx = 0;
476 uart_ext->rx_buff_wr_idx = 0;
477 break;
478
479 case SHELL_IO_CTRL_TX_RESET:
480 uart_ext->list_out_idx = 0;
481 uart_ext->list_in_idx = 0;
482
483 uart_ext->cur_packet = NULL;
484 uart_ext->packet_len = 0;
485 uart_ext->packet_tx_len = 0;
486
487 break;
488
489 case SHELL_IO_CTRL_FLUSH:
490 shell_uart_flush(uart_ext);
491 break;
492
493 case SHELL_IO_CTRL_SET_UART_PORT:
494 if(param == NULL) {
495 return bFALSE;
496 }
497 u8 uart_port = *(u8 *)param;
498 uart_ext->uart_id = uart_port;
499 break;
500
501 case SHELL_IO_CTRL_GET_RX_STATUS:
502 if(param == NULL)
503 return bFALSE;
504
505 *((u16 *)param) = uart_ext->rx_over_flow;
506 uart_ext->rx_over_flow = 0; // clear it after read by user.
507
508 break;
509
510 default:
511 return bFALSE;
512 break;
513 }
514
515 return bTRUE;
516 }
517
shell_uart_close(shell_dev_t * shell_dev)518 static bool_t shell_uart_close(shell_dev_t * shell_dev)
519 {
520 shell_uart_ext_t *uart_ext;
521
522 if(shell_dev == NULL)
523 return bFALSE;
524
525 uart_ext = (shell_uart_ext_t *)shell_dev->dev_ext;
526
527 // call uart driver to register isr callback;
528 bk_uart_register_rx_isr(uart_ext->uart_id, NULL, NULL);
529 bk_uart_register_tx_isr(uart_ext->uart_id, NULL, NULL);
530
531 uart_ext->tx_complete_callback = NULL;
532 uart_ext->rx_indicate_callback = NULL;
533
534 return bTRUE;
535 }
536
537