1 /*
2  * Copyright (c) 2022 Libre Solar Technologies GmbH
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/device.h>
9 #include <zephyr/drivers/uart.h>
10 
11 #include <string.h>
12 
13 /* change this to any other UART peripheral if desired */
14 #define UART_DEVICE_NODE DT_CHOSEN(zephyr_shell_uart)
15 
16 #define MSG_SIZE 32
17 
18 /* queue to store up to 10 messages (aligned to 4-byte boundary) */
19 K_MSGQ_DEFINE(uart_msgq, MSG_SIZE, 10, 4);
20 
21 static const struct device *const uart_dev = DEVICE_DT_GET(UART_DEVICE_NODE);
22 
23 /* receive buffer used in UART ISR callback */
24 static char rx_buf[MSG_SIZE];
25 static int rx_buf_pos;
26 
27 /*
28  * Read characters from UART until line end is detected. Afterwards push the
29  * data to the message queue.
30  */
serial_cb(const struct device * dev,void * user_data)31 void serial_cb(const struct device *dev, void *user_data)
32 {
33 	uint8_t c;
34 
35 	if (!uart_irq_update(uart_dev)) {
36 		return;
37 	}
38 
39 	if (!uart_irq_rx_ready(uart_dev)) {
40 		return;
41 	}
42 
43 	/* read until FIFO empty */
44 	while (uart_fifo_read(uart_dev, &c, 1) == 1) {
45 		if ((c == '\n' || c == '\r') && rx_buf_pos > 0) {
46 			/* terminate string */
47 			rx_buf[rx_buf_pos] = '\0';
48 
49 			/* if queue is full, message is silently dropped */
50 			k_msgq_put(&uart_msgq, &rx_buf, K_NO_WAIT);
51 
52 			/* reset the buffer (it was copied to the msgq) */
53 			rx_buf_pos = 0;
54 		} else if (rx_buf_pos < (sizeof(rx_buf) - 1)) {
55 			rx_buf[rx_buf_pos++] = c;
56 		}
57 		/* else: characters beyond buffer size are dropped */
58 	}
59 }
60 
61 /*
62  * Print a null-terminated string character by character to the UART interface
63  */
print_uart(char * buf)64 void print_uart(char *buf)
65 {
66 	int msg_len = strlen(buf);
67 
68 	for (int i = 0; i < msg_len; i++) {
69 		uart_poll_out(uart_dev, buf[i]);
70 	}
71 }
72 
main(void)73 int main(void)
74 {
75 	char tx_buf[MSG_SIZE];
76 
77 	if (!device_is_ready(uart_dev)) {
78 		printk("UART device not found!");
79 		return 0;
80 	}
81 
82 	/* configure interrupt and callback to receive data */
83 	int ret = uart_irq_callback_user_data_set(uart_dev, serial_cb, NULL);
84 
85 	if (ret < 0) {
86 		if (ret == -ENOTSUP) {
87 			printk("Interrupt-driven UART API support not enabled\n");
88 		} else if (ret == -ENOSYS) {
89 			printk("UART device does not support interrupt-driven API\n");
90 		} else {
91 			printk("Error setting UART callback: %d\n", ret);
92 		}
93 		return 0;
94 	}
95 	uart_irq_rx_enable(uart_dev);
96 
97 	print_uart("Hello! I'm your echo bot.\r\n");
98 	print_uart("Tell me something and press enter:\r\n");
99 
100 	/* indefinitely wait for input from the user */
101 	while (k_msgq_get(&uart_msgq, &tx_buf, K_FOREVER) == 0) {
102 		print_uart("Echo: ");
103 		print_uart(tx_buf);
104 		print_uart("\r\n");
105 	}
106 	return 0;
107 }
108