1 /* Copyright 2023 Unionman Technology Co., Ltd.
2 *
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
17 #include <cstdio>
18 #include "serial_uart.h"
19
20 #include <termios.h>
21
22 constexpr int RECV_HEAD = 0xaa;
23 constexpr int RECV_END = 0x55;
24 constexpr int EVT_RIGHT = 0x01;
25 constexpr int EVT_LEFT = 0x02;
26 constexpr int EVT_BACK = 0x03;
27 constexpr int EVT_FORWARD = 0x04;
28 constexpr int EVT_PULLUP = 0x05;
29 constexpr int EVT_PULLDOWN = 0x06;
30 constexpr int EVT_PULLREMOVE = 0x07;
31 constexpr int EVT_TOUCH1 = 0x21;
32 constexpr int EVT_TOUCH2 = 0x22;
33 constexpr int EVT_TOUCH3 = 0x23;
34 constexpr int EVT_TOUCH4 = 0x24;
35 constexpr int EVT_TOUCH5 = 0x25;
36 constexpr int START = 0;
37 constexpr int DATA = 1;
38 constexpr int CHECK = 2;
39 constexpr int END = 3;
40
41 // 设置串行端口的波特率
set_baud(int fd,int baud)42 static void set_baud(int fd, int baud)
43 {
44 int ret = -1;
45 struct termios opt; // 用于描述和控制终端设备的各种属性,如波特率、字符大小、停止位等。
46
47 tcgetattr(fd, &opt); // tcgetattr用来获取终端参数,将从终端获得的信息fd,保存到opt结构体中(这个函数会根据文件描述符(fd)所代表的终端设备,从操作系统内核的终端驱动程序中获取相应的参数信息。)
48 tcflush(fd, TCIOFLUSH); // 清空缓冲区
49 cfsetispeed(&opt, baud); // 源码应该是//third/musl/src/termios/cfsetospeed.c里那个
50 cfsetospeed(&opt, baud); // 同上
51
52 ret = tcsetattr(fd, TCSANOW, &opt); // 将配置信息对象应用到指定的串行端口,TCSANOW表示立即生效
53 if (ret == -1) {
54 perror("tcsetattr fd");
55 return;
56 }
57
58 tcflush(fd, TCIOFLUSH); // 清空缓冲区
59 }
60
61 // 根据输入的数据位数量设置相应的标志位,用于配置串行端口的数据位
setup_data_bits(int setup_databits,struct termios * options_databits)62 static int setup_data_bits(int setup_databits, struct termios *options_databits)
63 {
64 switch (setup_databits) {
65 case 5L:
66 options_databits->c_cflag |= CS5; // 按位或运算,只修改对应标志位,其他的保持不变
67 break;
68 case 6L:
69 options_databits->c_cflag |= CS6;
70 break;
71 case 7L:
72 options_databits->c_cflag |= CS7;
73 break;
74 case 8L:
75 options_databits->c_cflag |= CS8;
76 break;
77 default:
78 return -1;
79 }
80 return 1;
81 }
82
83 // 设置校验位
set_params_parity(int setup_parity,struct termios * options_parity)84 static int set_params_parity(int setup_parity, struct termios *options_parity)
85 {
86 switch (setup_parity) {
87 case 'n':
88 case 'N': // 无奇偶校验位
89 options_parity->c_cflag &= ~PARENB; // 清除PARENB位
90 options_parity->c_iflag &= ~INPCK; // 禁用输入奇偶校验检查
91 break;
92
93 case 'o':
94 case 'O': // 设置为奇校验
95 options_parity->c_cflag |= (PARODD | PARENB); // 开启奇偶校验并把奇校验开启
96 options_parity->c_iflag |= INPCK; // 启用输入奇偶校验检查
97 break;
98
99 case 'e':
100 case 'E': // 设置为偶校验
101 options_parity->c_cflag |= PARENB;
102 options_parity->c_cflag &= ~PARODD;
103 options_parity->c_iflag |= INPCK;
104 break;
105
106 case 'M':
107 case 'm': // 指示使用奇偶校验位作为标记位(奇校验)
108 options_parity->c_cflag |= PARENB | CMSPAR | PARODD;
109 options_parity->c_iflag |= INPCK; // enable parity checking /
110 break;
111
112 case 'S':
113 case 's': // 指示使用奇偶校验位作为标记位(偶校验)
114 options_parity->c_cflag |= PARENB | CMSPAR;
115 options_parity->c_cflag &= ~PARODD;
116 options_parity->c_iflag |= INPCK; // enable parity checking /
117 break;
118
119 default:
120 return -1;
121 }
122 return 1;
123 }
124
125 // 设置串行端口的参数
set_params(int fd,int databits,int stopbits,int parity)126 static int set_params(int fd, int databits, int stopbits, int parity)
127 {
128 struct termios options;
129 int ret = 0;
130
131 if (tcgetattr(fd, &options) != 0) {
132 perror("tcgetattr fail");
133 return -1;
134 }
135 // 禁用任何特殊的输入和输出处理
136 options.c_iflag = 0;
137 options.c_oflag = 0;
138
139 // setup data bits
140 options.c_cflag &= ~CSIZE;
141 ret = setup_data_bits(databits, &options);
142 if (ret == -1) {
143 return -1;
144 }
145
146 // 配置校验选项
147 ret = set_params_parity(parity, &options);
148 if (ret == -1) {
149 return -1;
150 }
151
152 // stop bits/
153 switch (stopbits) {
154 // CSTOPB对应位0表示一位,1表示两位
155 case 1:
156 options.c_cflag &= ~CSTOPB;
157 break;
158
159 case 2L:
160 options.c_cflag |= CSTOPB;
161 break;
162
163 default:
164 return -1;
165 }
166
167 // 请求发送和清除发送
168 options.c_cflag &= ~CRTSCTS; // 禁用硬件控制流(一种对接收双方之间数据传输速度匹配的控制机制)
169 options.c_lflag = 0; // 禁用本地模式选项
170 options.c_cc[VTIME] = 10; // 读取数据时,如果在该值/10秒内没有数据到达则返回
171 options.c_cc[VMIN] = 1; // 最小读取字符,设置至少读取一个字符后才会返回
172
173 tcflush(fd, TCIFLUSH);
174 // 将新的参数应用到串口设备上
175 if (tcsetattr(fd, TCSANOW, &options) != 0) {
176 return -1;
177 }
178
179 return 0;
180 }
181
182 // 转换波特率为对应的枚举值
conver_baudrate(int baudrate)183 static speed_t conver_baudrate(int baudrate)
184 {
185 switch (baudrate) {
186 case 9600L:
187 return B9600;
188 case 19200L:
189 return B19200;
190 case 38400L:
191 return B38400;
192 case 115200L:
193 return B115200;
194 case 1152000L:
195 return B1152000;
196 default:
197 return B1152000;
198 }
199 }
200
201 // uart配置
uart_init(int fd,int uartBaud)202 int uart_init(int fd, int uartBaud)
203 {
204 set_baud(fd, conver_baudrate(uartBaud));
205 // uart param /
206 if (set_params(fd, 8L, 1, 'n')) {
207 printf("Set uart parameters fail.\n");
208 return -1;
209 }
210 return 0;
211 }
212
213 // 传感器数据处理
data_proce(int * recv)214 std::string data_proce(int *recv)
215 {
216 std::string ret;
217 if (recv == nullptr) {
218 printf("data proce error");
219 }
220
221 if ((recv[START] == RECV_HEAD) && (recv[END] == RECV_END) && (recv[DATA] == (0xff - recv[CHECK]))) {
222 switch (recv[DATA]) {
223 case EVT_BACK:
224 ret="手势识别为向后";
225 break;
226 case EVT_FORWARD:
227 ret="手势识别为向前";
228 break;
229 case EVT_RIGHT:
230 ret="手势识别为向右";
231 break;
232 case EVT_LEFT:
233 ret="手势识别为向左";
234 break;
235 case EVT_PULLUP:
236 ret="手势识别为上拉";
237 break;
238 case EVT_PULLDOWN:
239 ret="手势识别为下压";
240 break;
241 case EVT_PULLREMOVE:
242 ret="手势识别为上拉下压后松开";
243 break;
244 case EVT_TOUCH1:
245 ret="触摸点1";
246 break;
247 case EVT_TOUCH2:
248 ret="触摸点2";
249 break;
250 case EVT_TOUCH3:
251 ret="触摸点3";
252 break;
253 case EVT_TOUCH4:
254 ret="触摸点4";
255 break;
256 case EVT_TOUCH5:
257 ret="触摸点5";
258 break;
259 default:
260 ret="数据错误";
261 break;
262 }
263 return ret;
264 }
265 ret="错误";
266 return ret;
267 }