1 /*
2  * Copyright (C)2021-2022 Intel Corporation.
3  * SPDX-License-Identifier: BSD-3-Clause
4  */
5 
6 #include <errno.h>
7 #include <fcntl.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <stdbool.h>
11 #include <string.h>
12 #include <termios.h>
13 #include <unistd.h>
14 #include <sys/queue.h>
15 #include <pthread.h>
16 #include <limits.h>
17 #include "uart.h"
18 #include "uart_channel.h"
19 #include "log.h"
20 #include "config.h"
21 
22 /* it read from uart, and if end is '\0' or '\n' or len = buff-len it will return */
try_receive_message_by_uart(int fd,void * buffer,size_t buf_len)23 static ssize_t try_receive_message_by_uart(int fd, void *buffer, size_t buf_len)
24 {
25 	ssize_t rc = 0U, count = 0U;
26 	char *tmp;
27 	unsigned int retry_times = RETRY_RECV_TIMES;
28 
29 	do {
30 		/* NOTE: Now we can't handle multi command message at one time. */
31 		rc = read(fd, buffer + count, buf_len - count);
32 		if (rc > 0) {
33 			count += rc;
34 			tmp = (char *)buffer;
35 			if ((tmp[count - 1] == '\0') || (tmp[count - 1] == '\n')
36 						|| (count == buf_len)) {
37 				if (tmp[count - 1] == '\n')
38 					tmp[count - 1] = '\0';
39 				break;
40 			}
41 		} else {
42 			if (errno == EAGAIN) {
43 				usleep(WAIT_RECV);
44 				retry_times--;
45 			} else {
46 				break;
47 			}
48 		}
49 	} while (retry_times != 0U);
50 
51 	return count;
52 }
53 /**
54  * @brief Receive message and retry RETRY_RECV_TIMES time if
55  * message is missed in some cases.
56  */
receive_message_by_uart(struct uart_dev * dev,void * buf,size_t len)57 ssize_t receive_message_by_uart(struct uart_dev *dev, void *buf, size_t len)
58 {
59 	if ((dev == NULL) || (buf == NULL) || (len == 0))
60 		return -EINVAL;
61 
62 	return try_receive_message_by_uart(dev->tty_fd, buf, len);
63 }
send_message_by_uart(struct uart_dev * dev,const void * buf,size_t len)64 ssize_t send_message_by_uart(struct uart_dev *dev, const void *buf, size_t len)
65 {
66 	ssize_t ret = 0;
67 
68 	if ((dev == NULL) || (buf == NULL) || (len == 0))
69 		return -EINVAL;
70 	ret = write(dev->tty_fd, buf, len + 1);
71 
72 	return ret;
73 }
set_tty_attr(int fd,int baudrate)74 static int set_tty_attr(int fd, int baudrate)
75 {
76 	struct termios tty;
77 
78 	if (tcgetattr(fd, &tty) < 0) {
79 		LOG_PRINTF("Error from tcgetattr: %s\n", strerror(errno));
80 		return errno;
81 	}
82 
83 	cfsetospeed(&tty, (speed_t)baudrate);
84 	cfsetispeed(&tty, (speed_t)baudrate);
85 
86 	/* set input-mode */
87 	tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK |
88 			ISTRIP | INLCR | IGNCR | ICRNL | IXON);
89 
90 	/* set output-mode */
91 	tty.c_oflag &= ~OPOST;
92 
93 	/* set control-mode */
94 	tty.c_cflag |= (CLOCAL | CREAD | CS8);
95 	tty.c_cflag &= ~(CSIZE | PARENB | CSTOPB | CRTSCTS);
96 
97 	/* set local-mode */
98 	tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
99 
100 	/* block until one char read, set next char's timeout */
101 	tty.c_cc[VMIN] = 1;
102 	tty.c_cc[VTIME] = 1;
103 
104 	tcflush(fd, TCIOFLUSH);
105 
106 	if (tcsetattr(fd, TCSANOW, &tty) != 0) {
107 		LOG_PRINTF("Error from tcsetattr: %s\n", strerror(errno));
108 		return errno;
109 	}
110 	return 0;
111 }
tty_listen_setup(const char * tty_path)112 static int tty_listen_setup(const char *tty_path)
113 {
114 	int fd = -1;
115 	int ret;
116 
117 	fd = open(tty_path, O_RDWR | O_NOCTTY | O_SYNC | O_NONBLOCK);
118 	if (fd < 0) {
119 		fprintf(stderr, "Can't open file %s\n", tty_path);
120 		return errno;
121 	}
122 	ret = set_tty_attr(fd, B115200);
123 	if (ret != 0) {
124 		close(fd);
125 		return ret;
126 	}
127 	LOG_PRINTF("Open tty device:%s, fd=%d\n", tty_path, fd);
128 	return fd;
129 }
130 
init_uart_dev(char * path)131 struct uart_dev *init_uart_dev(char *path)
132 {
133 	struct uart_dev *dev;
134 
135 	if (path == NULL)
136 		return NULL;
137 	LOG_PRINTF("UART device name:%s\n", path);
138 	dev = calloc(1, sizeof(*dev));
139 	if (!dev) {
140 		LOG_PRINTF("Failed to alloc mem for uart device %s\n", path);
141 		return NULL;
142 	}
143 	if (strlen(path) < TTY_PATH_MAX)
144 		memcpy(dev->tty_path, path, strlen(path));
145 
146 	dev->tty_fd = tty_listen_setup(dev->tty_path);
147 	if (dev->tty_fd < 0) {
148 		LOG_PRINTF("Failed to setup uart device %s\n", path);
149 		free(dev);
150 		return NULL;
151 	}
152 	return dev;
153 }
deinit_uart_dev(struct uart_dev * dev)154 void deinit_uart_dev(struct uart_dev *dev)
155 {
156 	if (dev != NULL) {
157 		LOG_PRINTF("Close device: %s\n", dev->tty_path);
158 		close(dev->tty_fd);
159 		dev->tty_fd = -1;
160 		free(dev);
161 	}
162 }
163 
164