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