• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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