1 /*
2  * Copyright (c) 2006-2021, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2017-12-06     JasonJia     first version
9  */
10 
11 #include <rtthread.h>
12 #include <unistd.h>
13 #include <fcntl.h>
14 #include <string.h>
15 #include <sys/time.h>
16 
17 #define JOINT(x,y) x##y
18 #define B(x) JOINT(B,x)
19 #define Default_baud_rate   115200
20 #define Default_parity      'n'
21 #define BUFFER_SIZE         64
22 
23 struct termios_test_s
24 {
25     int baud_rate;
26     const char *dev;
27 };
28 
29 static struct termios_test_s term_param;
30 
_check_baud_rate(int baud_rate)31 static int _check_baud_rate(int baud_rate)
32 {
33     #define BAUD_RATE(x) \
34     {\
35         if(x==baud_rate) \
36         {\
37             rt_kprintf("%d baud rate\n",baud_rate);\
38             return JOINT(B,x);\
39         }\
40     }
41     BAUD_RATE(110);
42     BAUD_RATE(200);
43     BAUD_RATE(300);
44     BAUD_RATE(600);
45     BAUD_RATE(1200);
46     BAUD_RATE(1800);
47     BAUD_RATE(2400);
48     BAUD_RATE(4800);
49     BAUD_RATE(9600);
50     BAUD_RATE(19200);
51     BAUD_RATE(38400);
52     BAUD_RATE(57600);
53     BAUD_RATE(115200);
54     BAUD_RATE(230400);
55     BAUD_RATE(460800);
56     BAUD_RATE(921600);
57 
58     rt_kprintf("%d is not support,use default %d value.\n",baud_rate,Default_baud_rate);
59     return B(Default_baud_rate);
60 }
61 
open_comm(const char * name)62 int open_comm(const char *name)
63 {
64     int fd;
65     fd = open(name, O_RDWR | O_NOCTTY | O_NONBLOCK, 0);
66     if(fd == -1)
67     {
68         rt_kprintf("Open %s fail.\n",name);
69         return -1;
70     }
71     else
72     {
73         rt_kprintf("Open %s success,fd:%d\n",name,fd);
74     }
75 
76     return fd;
77 }
78 
close_comm(int fd)79 void close_comm(int fd)
80 {
81     if(fd != -1)
82     {
83         close(fd);
84     }
85 }
86 
config_comm(int fd,int speed_baud_rate,char parity,int data_bits,int stop_bits)87 void config_comm(int fd, int speed_baud_rate, char parity, int data_bits, int stop_bits)
88 {
89     int valid_baud_rate = 0;
90     struct termios new_tc;
91 
92     memset(&new_tc, 0x00, sizeof(struct termios));
93 
94     valid_baud_rate = _check_baud_rate(speed_baud_rate);
95 
96     new_tc.c_cflag |= (CLOCAL | CREAD);//Enable in default.
97 
98     /*
99     *Set baud rate. e.g B115200 is 115200 bauds.
100     */
101     cfsetispeed(&new_tc, valid_baud_rate);//input speed
102     cfsetospeed(&new_tc, valid_baud_rate);//output speed
103 
104     /*
105     *Set parity.
106     */
107     switch(parity)
108     {
109         case 'n':
110         case 'N':
111             new_tc.c_cflag &= ~PARENB;  //Disable parity.
112             break;
113         case 'o':
114         case 'O':
115             new_tc.c_cflag |= PARENB;   //Enable parity.
116             new_tc.c_cflag |= PARODD;   //Odd parity.
117             break;
118         case 'e':
119         case 'E':
120             new_tc.c_cflag |= PARENB;   //Enable parity.
121             new_tc.c_cflag &= ~PARODD;  //even parity.
122             break;
123     }
124 
125     /*
126     *Set data bits.
127     */
128     new_tc.c_cflag &= ~CSIZE;
129     switch(data_bits)
130     {
131         case 5:
132             break;
133         case 6:
134             break;
135         case 7:
136             new_tc.c_cflag |= CS7;
137             break;
138         case 8:
139             new_tc.c_cflag |= CS8;
140             break;
141     }
142 
143     /*
144     *Set stop bits.
145     */
146     (stop_bits == 2)?(new_tc.c_cflag |= CSTOPB):(new_tc.c_cflag &= ~ CSTOPB);
147 
148     tcflush(fd,TCIFLUSH);
149     //new_tc.c_cc[VTIME] = 0;
150     //new_tc.c_cc[VMIN] = 1;
151 
152     if( tcsetattr(fd, TCSANOW, &new_tc) != 0)
153     {
154         rt_kprintf("Set port config fail!\n");
155     }
156 }
157 
recv_comm(int fd,unsigned char * buffer,rt_size_t size,struct timeval * timeout)158 int recv_comm(int fd, unsigned char *buffer, rt_size_t size, struct timeval *timeout)
159 {
160     struct timeval t;
161     int ret = 0;
162     rt_size_t drv_recved = 0;
163     int recved = 0, need = size;
164     int timeout_cnt = 0;
165     unsigned char *c = RT_NULL;
166     fd_set readSet;
167 
168     RT_ASSERT(RT_NULL != buffer);
169 
170     if(fd == -1)
171     {
172         return -1;
173     }
174 
175     t.tv_sec = 0;
176     t.tv_usec = 100000;
177 
178     if(RT_NULL == timeout)
179     {
180         /* Wait forever approximate, it's a large time. */
181         timeout_cnt = 0xffffffff;
182     }
183     else
184     {
185         timeout_cnt = (timeout->tv_sec * 1000 * 1000 + timeout->tv_usec)/(t.tv_sec * 1000 * 1000 + t.tv_usec);
186     }
187 
188     while(1)
189     {
190         FD_ZERO(&readSet);
191         FD_SET(fd, &readSet);
192 
193         ret = select(fd+1,&readSet,RT_NULL,RT_NULL,&t);
194         if(ret < 0)
195         {
196             rt_kprintf("select error %d\n",ret);
197             break;
198         }
199         else if(ret == 0)
200         {
201             /* timeout */
202             timeout_cnt--;
203 
204             if(timeout_cnt == 0)
205             {
206                 rt_kprintf("need %d data in timeout %d ms,but only %d recved.\n",
207                             size,
208                             timeout->tv_sec * 1000 + timeout->tv_usec / 1000,
209                             recved);
210 
211                 recved = 0;
212 
213                 break;
214             }
215         }
216         else
217         {
218             if(FD_ISSET(fd, &readSet))
219             {
220                 c = &buffer[size - need];
221                 ioctl(fd, FIONREAD, &drv_recved);
222 
223                 /* check poll and ioctl */
224                 RT_ASSERT(drv_recved != 0);
225 
226                 drv_recved = (drv_recved > need ? need : drv_recved);
227                 recved = read(fd, c, drv_recved);
228                 if(recved != drv_recved)
229                 {
230                     rt_kprintf("fatal error %s(%d).\n",__FUNCTION__,__LINE__);
231                     RT_ASSERT(0);
232                     recved = 0;
233                     break;
234                 }
235 
236                 need -= recved;
237 
238                 if(need)
239                 {
240                     continue;
241                 }
242                 else if (need == 0)
243                 {
244                     recved = size;
245                     break;
246                 }
247                 else
248                 {
249                     rt_kprintf("fatal error %s(%d).\n",__FUNCTION__,__LINE__);
250                     RT_ASSERT(0);
251                 }
252 
253             }
254         }
255     }
256 
257     return recved;
258 }
259 
send_comm(int fd,const unsigned char * buffer,rt_size_t size)260 int send_comm(int fd, const unsigned char *buffer, rt_size_t size)
261 {
262     RT_ASSERT(RT_NULL != buffer);
263 
264     if(fd == -1)
265     {
266         return -1;
267     }
268 
269     //serial framework does not support poll out now
270     write(fd, buffer, size);
271 
272     return 0;
273 }
274 
flush_comm(int fd)275 int flush_comm(int fd)
276 {
277     if(fd == -1)
278     {
279         return -1;
280     }
281     tcflush(fd,TCIFLUSH);
282     return 0;
283 }
284 
termios_test_entry(void * p)285 void termios_test_entry(void *p)
286 {
287     int len = 0;
288     int fd = -1;
289     unsigned char *pBuf = RT_NULL;
290     struct termios_test_s *pTerm = (struct termios_test_s *)p;
291 
292     if((fd = open_comm(pTerm->dev)) == -1)
293     {
294         rt_kprintf("Check the device name...\n");
295         return;
296     }
297 
298     pBuf = (unsigned char *)rt_malloc(BUFFER_SIZE);
299     RT_ASSERT(pBuf != RT_NULL);
300 
301     memset(pBuf, 0x00, BUFFER_SIZE);
302 
303     config_comm(fd, pTerm->baud_rate, Default_parity, 8, 1);
304 
305     flush_comm(fd);
306 
307     rt_kprintf("Block recv 10 bytes.\n");
308     /* Block recv 10 bytes */
309     len = recv_comm(fd, pBuf, 10, RT_NULL);
310 
311     rt_kprintf("Recv:%s\n", pBuf);
312 
313     send_comm(fd, pBuf, len);
314     rt_kprintf("Termios test exit.\n");
315 
316     close_comm(fd);
317 
318     rt_free(pBuf);
319     pBuf = RT_NULL;
320 }
321 
termios_test(int argc,char ** argv)322 int termios_test(int argc, char **argv)
323 {
324     rt_thread_t tid;
325 
326     if(argc < 2)
327     {
328         rt_kprintf("Please input device name...\n");
329         return -1;
330     }
331 
332     term_param.dev = argv[1];
333     term_param.baud_rate = ((argc >= 3) ? atoi(argv[2]) : Default_baud_rate);
334 
335     tid = rt_thread_create("termtest",
336         termios_test_entry, (void *)&term_param,
337         512, RT_THREAD_PRIORITY_MAX/3, 20);
338 
339     if (tid != RT_NULL)
340         rt_thread_startup(tid);
341 
342     return 0;
343 }
344 
345 #ifdef RT_USING_FINSH
346     #include <finsh.h>
347     #ifdef RT_USING_FINSH
348         MSH_CMD_EXPORT_ALIAS(termios_test, termtest, e.g: termtest /dev/uart4 115200);
349     #endif /* RT_USING_FINSH */
350 #endif /* RT_USING_FINSH */
351 
352