re-add problems
[RPi-MMU-example.git] / src / lib / rs232 / rs232.c
blob0ae2a592541ccc829e6464ebca5f3009684e6239
1 /*
2 ***************************************************************************
4 * Author: Teunis van Beelen
6 * Copyright (C) 2005 - 2019 Teunis van Beelen
8 * Email: teuniz@protonmail.com
10 ***************************************************************************
12 * This program is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation, either version 3 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25 ***************************************************************************
29 /* Last revision: May 31, 2019 */
30 /* Added support for hardware flow control using RTS and CTS lines */
31 /* For more info and how to use this library, visit: http://www.teuniz.net/RS-232/ */
34 #include "rs232.h"
37 #if defined(__linux__) || defined(__FreeBSD__) /* Linux & FreeBSD */
39 #define RS232_PORTNR 38
42 int Cport[RS232_PORTNR],
43 error;
45 struct termios new_port_settings,
46 old_port_settings[RS232_PORTNR];
48 char *comports[RS232_PORTNR]={"/dev/ttyS0","/dev/ttyS1","/dev/ttyS2","/dev/ttyS3","/dev/ttyS4","/dev/ttyS5",
49 "/dev/ttyS6","/dev/ttyS7","/dev/ttyS8","/dev/ttyS9","/dev/ttyS10","/dev/ttyS11",
50 "/dev/ttyS12","/dev/ttyS13","/dev/ttyS14","/dev/ttyS15","/dev/ttyUSB0",
51 "/dev/ttyUSB1","/dev/ttyUSB2","/dev/ttyUSB3","/dev/ttyUSB4","/dev/ttyUSB5",
52 "/dev/ttyAMA0","/dev/ttyAMA1","/dev/ttyACM0","/dev/ttyACM1",
53 "/dev/rfcomm0","/dev/rfcomm1","/dev/ircomm0","/dev/ircomm1",
54 "/dev/cuau0","/dev/cuau1","/dev/cuau2","/dev/cuau3",
55 "/dev/cuaU0","/dev/cuaU1","/dev/cuaU2","/dev/cuaU3"};
57 int RS232_OpenComport(int comport_number, int baudrate, const char *mode, int flowctrl)
59 int baudr,
60 status;
62 if((comport_number>=RS232_PORTNR)||(comport_number<0))
64 printf("illegal comport number\n");
65 return(1);
68 switch(baudrate)
70 case 50 : baudr = B50;
71 break;
72 case 75 : baudr = B75;
73 break;
74 case 110 : baudr = B110;
75 break;
76 case 134 : baudr = B134;
77 break;
78 case 150 : baudr = B150;
79 break;
80 case 200 : baudr = B200;
81 break;
82 case 300 : baudr = B300;
83 break;
84 case 600 : baudr = B600;
85 break;
86 case 1200 : baudr = B1200;
87 break;
88 case 1800 : baudr = B1800;
89 break;
90 case 2400 : baudr = B2400;
91 break;
92 case 4800 : baudr = B4800;
93 break;
94 case 9600 : baudr = B9600;
95 break;
96 case 19200 : baudr = B19200;
97 break;
98 case 38400 : baudr = B38400;
99 break;
100 case 57600 : baudr = B57600;
101 break;
102 case 115200 : baudr = B115200;
103 break;
104 case 230400 : baudr = B230400;
105 break;
106 case 460800 : baudr = B460800;
107 break;
108 case 500000 : baudr = B500000;
109 break;
110 case 576000 : baudr = B576000;
111 break;
112 case 921600 : baudr = B921600;
113 break;
114 case 1000000 : baudr = B1000000;
115 break;
116 case 1152000 : baudr = B1152000;
117 break;
118 case 1500000 : baudr = B1500000;
119 break;
120 case 2000000 : baudr = B2000000;
121 break;
122 case 2500000 : baudr = B2500000;
123 break;
124 case 3000000 : baudr = B3000000;
125 break;
126 case 3500000 : baudr = B3500000;
127 break;
128 case 4000000 : baudr = B4000000;
129 break;
130 default : printf("invalid baudrate\n");
131 return(1);
132 break;
135 int cbits=CS8,
136 cpar=0,
137 ipar=IGNPAR,
138 bstop=0;
140 if(strlen(mode) != 3)
142 printf("invalid mode \"%s\"\n", mode);
143 return(1);
146 switch(mode[0])
148 case '8': cbits = CS8;
149 break;
150 case '7': cbits = CS7;
151 break;
152 case '6': cbits = CS6;
153 break;
154 case '5': cbits = CS5;
155 break;
156 default : printf("invalid number of data-bits '%c'\n", mode[0]);
157 return(1);
158 break;
161 switch(mode[1])
163 case 'N':
164 case 'n': cpar = 0;
165 ipar = IGNPAR;
166 break;
167 case 'E':
168 case 'e': cpar = PARENB;
169 ipar = INPCK;
170 break;
171 case 'O':
172 case 'o': cpar = (PARENB | PARODD);
173 ipar = INPCK;
174 break;
175 default : printf("invalid parity '%c'\n", mode[1]);
176 return(1);
177 break;
180 switch(mode[2])
182 case '1': bstop = 0;
183 break;
184 case '2': bstop = CSTOPB;
185 break;
186 default : printf("invalid number of stop bits '%c'\n", mode[2]);
187 return(1);
188 break;
192 http://pubs.opengroup.org/onlinepubs/7908799/xsh/termios.h.html
194 http://man7.org/linux/man-pages/man3/termios.3.html
197 Cport[comport_number] = open(comports[comport_number], O_RDWR | O_NOCTTY | O_NDELAY);
198 if(Cport[comport_number]==-1)
200 perror("unable to open comport ");
201 return(1);
204 /* lock access so that another process can't also use the port */
205 if(flock(Cport[comport_number], LOCK_EX | LOCK_NB) != 0)
207 close(Cport[comport_number]);
208 perror("Another process has locked the comport.");
209 return(1);
212 error = tcgetattr(Cport[comport_number], old_port_settings + comport_number);
213 if(error==-1)
215 close(Cport[comport_number]);
216 flock(Cport[comport_number], LOCK_UN); /* free the port so that others can use it. */
217 perror("unable to read portsettings ");
218 return(1);
220 memset(&new_port_settings, 0, sizeof(new_port_settings)); /* clear the new struct */
222 new_port_settings.c_cflag = cbits | cpar | bstop | CLOCAL | CREAD;
223 if(flowctrl)
225 new_port_settings.c_cflag |= CRTSCTS;
227 new_port_settings.c_iflag = ipar;
228 new_port_settings.c_oflag = 0;
229 new_port_settings.c_lflag = 0;
230 new_port_settings.c_cc[VMIN] = 0; /* block untill n bytes are received */
231 new_port_settings.c_cc[VTIME] = 0; /* block untill a timer expires (n * 100 mSec.) */
233 cfsetispeed(&new_port_settings, baudr);
234 cfsetospeed(&new_port_settings, baudr);
236 error = tcsetattr(Cport[comport_number], TCSANOW, &new_port_settings);
237 if(error==-1)
239 tcsetattr(Cport[comport_number], TCSANOW, old_port_settings + comport_number);
240 close(Cport[comport_number]);
241 flock(Cport[comport_number], LOCK_UN); /* free the port so that others can use it. */
242 perror("unable to adjust portsettings ");
243 return(1);
246 /* http://man7.org/linux/man-pages/man4/tty_ioctl.4.html */
248 if(ioctl(Cport[comport_number], TIOCMGET, &status) == -1)
250 tcsetattr(Cport[comport_number], TCSANOW, old_port_settings + comport_number);
251 flock(Cport[comport_number], LOCK_UN); /* free the port so that others can use it. */
252 perror("unable to get portstatus");
253 return(1);
256 status |= TIOCM_DTR; /* turn on DTR */
257 status |= TIOCM_RTS; /* turn on RTS */
259 if(ioctl(Cport[comport_number], TIOCMSET, &status) == -1)
261 tcsetattr(Cport[comport_number], TCSANOW, old_port_settings + comport_number);
262 flock(Cport[comport_number], LOCK_UN); /* free the port so that others can use it. */
263 perror("unable to set portstatus");
264 return(1);
267 return(0);
271 int RS232_PollComport(int comport_number, unsigned char *buf, int size)
273 int n;
275 n = read(Cport[comport_number], buf, size);
277 if(n < 0)
279 if(errno == EAGAIN) return 0;
282 return(n);
286 int RS232_SendByte(int comport_number, unsigned char byte)
288 int n = write(Cport[comport_number], &byte, 1);
289 if(n < 0)
291 if(errno == EAGAIN)
293 return 0;
295 else
297 return 1;
301 return(0);
305 int RS232_SendBuf(int comport_number, unsigned char *buf, int size)
307 int n = write(Cport[comport_number], buf, size);
308 if(n < 0)
310 if(errno == EAGAIN)
312 return 0;
314 else
316 return -1;
320 return(n);
324 void RS232_CloseComport(int comport_number)
326 int status;
328 if(ioctl(Cport[comport_number], TIOCMGET, &status) == -1)
330 perror("unable to get portstatus");
333 status &= ~TIOCM_DTR; /* turn off DTR */
334 status &= ~TIOCM_RTS; /* turn off RTS */
336 if(ioctl(Cport[comport_number], TIOCMSET, &status) == -1)
338 perror("unable to set portstatus");
341 tcsetattr(Cport[comport_number], TCSANOW, old_port_settings + comport_number);
342 close(Cport[comport_number]);
344 flock(Cport[comport_number], LOCK_UN); /* free the port so that others can use it. */
348 Constant Description
349 TIOCM_LE DSR (data set ready/line enable)
350 TIOCM_DTR DTR (data terminal ready)
351 TIOCM_RTS RTS (request to send)
352 TIOCM_ST Secondary TXD (transmit)
353 TIOCM_SR Secondary RXD (receive)
354 TIOCM_CTS CTS (clear to send)
355 TIOCM_CAR DCD (data carrier detect)
356 TIOCM_CD see TIOCM_CAR
357 TIOCM_RNG RNG (ring)
358 TIOCM_RI see TIOCM_RNG
359 TIOCM_DSR DSR (data set ready)
361 http://man7.org/linux/man-pages/man4/tty_ioctl.4.html
364 int RS232_IsDCDEnabled(int comport_number)
366 int status;
368 ioctl(Cport[comport_number], TIOCMGET, &status);
370 if(status&TIOCM_CAR) return(1);
371 else return(0);
375 int RS232_IsRINGEnabled(int comport_number)
377 int status;
379 ioctl(Cport[comport_number], TIOCMGET, &status);
381 if(status&TIOCM_RNG) return(1);
382 else return(0);
386 int RS232_IsCTSEnabled(int comport_number)
388 int status;
390 ioctl(Cport[comport_number], TIOCMGET, &status);
392 if(status&TIOCM_CTS) return(1);
393 else return(0);
397 int RS232_IsDSREnabled(int comport_number)
399 int status;
401 ioctl(Cport[comport_number], TIOCMGET, &status);
403 if(status&TIOCM_DSR) return(1);
404 else return(0);
408 void RS232_enableDTR(int comport_number)
410 int status;
412 if(ioctl(Cport[comport_number], TIOCMGET, &status) == -1)
414 perror("unable to get portstatus");
417 status |= TIOCM_DTR; /* turn on DTR */
419 if(ioctl(Cport[comport_number], TIOCMSET, &status) == -1)
421 perror("unable to set portstatus");
426 void RS232_disableDTR(int comport_number)
428 int status;
430 if(ioctl(Cport[comport_number], TIOCMGET, &status) == -1)
432 perror("unable to get portstatus");
435 status &= ~TIOCM_DTR; /* turn off DTR */
437 if(ioctl(Cport[comport_number], TIOCMSET, &status) == -1)
439 perror("unable to set portstatus");
444 void RS232_enableRTS(int comport_number)
446 int status;
448 if(ioctl(Cport[comport_number], TIOCMGET, &status) == -1)
450 perror("unable to get portstatus");
453 status |= TIOCM_RTS; /* turn on RTS */
455 if(ioctl(Cport[comport_number], TIOCMSET, &status) == -1)
457 perror("unable to set portstatus");
462 void RS232_disableRTS(int comport_number)
464 int status;
466 if(ioctl(Cport[comport_number], TIOCMGET, &status) == -1)
468 perror("unable to get portstatus");
471 status &= ~TIOCM_RTS; /* turn off RTS */
473 if(ioctl(Cport[comport_number], TIOCMSET, &status) == -1)
475 perror("unable to set portstatus");
480 void RS232_flushRX(int comport_number)
482 tcflush(Cport[comport_number], TCIFLUSH);
486 void RS232_flushTX(int comport_number)
488 tcflush(Cport[comport_number], TCOFLUSH);
492 void RS232_flushRXTX(int comport_number)
494 tcflush(Cport[comport_number], TCIOFLUSH);
498 #else /* windows */
500 #define RS232_PORTNR 32
502 HANDLE Cport[RS232_PORTNR];
505 char *comports[RS232_PORTNR]={"\\\\.\\COM1", "\\\\.\\COM2", "\\\\.\\COM3", "\\\\.\\COM4",
506 "\\\\.\\COM5", "\\\\.\\COM6", "\\\\.\\COM7", "\\\\.\\COM8",
507 "\\\\.\\COM9", "\\\\.\\COM10", "\\\\.\\COM11", "\\\\.\\COM12",
508 "\\\\.\\COM13", "\\\\.\\COM14", "\\\\.\\COM15", "\\\\.\\COM16",
509 "\\\\.\\COM17", "\\\\.\\COM18", "\\\\.\\COM19", "\\\\.\\COM20",
510 "\\\\.\\COM21", "\\\\.\\COM22", "\\\\.\\COM23", "\\\\.\\COM24",
511 "\\\\.\\COM25", "\\\\.\\COM26", "\\\\.\\COM27", "\\\\.\\COM28",
512 "\\\\.\\COM29", "\\\\.\\COM30", "\\\\.\\COM31", "\\\\.\\COM32"};
514 char mode_str[128];
517 int RS232_OpenComport(int comport_number, int baudrate, const char *mode, int flowctrl)
519 if((comport_number>=RS232_PORTNR)||(comport_number<0))
521 printf("illegal comport number\n");
522 return(1);
525 switch(baudrate)
527 case 110 : strcpy(mode_str, "baud=110");
528 break;
529 case 300 : strcpy(mode_str, "baud=300");
530 break;
531 case 600 : strcpy(mode_str, "baud=600");
532 break;
533 case 1200 : strcpy(mode_str, "baud=1200");
534 break;
535 case 2400 : strcpy(mode_str, "baud=2400");
536 break;
537 case 4800 : strcpy(mode_str, "baud=4800");
538 break;
539 case 9600 : strcpy(mode_str, "baud=9600");
540 break;
541 case 19200 : strcpy(mode_str, "baud=19200");
542 break;
543 case 38400 : strcpy(mode_str, "baud=38400");
544 break;
545 case 57600 : strcpy(mode_str, "baud=57600");
546 break;
547 case 115200 : strcpy(mode_str, "baud=115200");
548 break;
549 case 128000 : strcpy(mode_str, "baud=128000");
550 break;
551 case 256000 : strcpy(mode_str, "baud=256000");
552 break;
553 case 500000 : strcpy(mode_str, "baud=500000");
554 break;
555 case 921600 : strcpy(mode_str, "baud=921600");
556 break;
557 case 1000000 : strcpy(mode_str, "baud=1000000");
558 break;
559 case 1500000 : strcpy(mode_str, "baud=1500000");
560 break;
561 case 2000000 : strcpy(mode_str, "baud=2000000");
562 break;
563 case 3000000 : strcpy(mode_str, "baud=3000000");
564 break;
565 default : printf("invalid baudrate\n");
566 return(1);
567 break;
570 if(strlen(mode) != 3)
572 printf("invalid mode \"%s\"\n", mode);
573 return(1);
576 switch(mode[0])
578 case '8': strcat(mode_str, " data=8");
579 break;
580 case '7': strcat(mode_str, " data=7");
581 break;
582 case '6': strcat(mode_str, " data=6");
583 break;
584 case '5': strcat(mode_str, " data=5");
585 break;
586 default : printf("invalid number of data-bits '%c'\n", mode[0]);
587 return(1);
588 break;
591 switch(mode[1])
593 case 'N':
594 case 'n': strcat(mode_str, " parity=n");
595 break;
596 case 'E':
597 case 'e': strcat(mode_str, " parity=e");
598 break;
599 case 'O':
600 case 'o': strcat(mode_str, " parity=o");
601 break;
602 default : printf("invalid parity '%c'\n", mode[1]);
603 return(1);
604 break;
607 switch(mode[2])
609 case '1': strcat(mode_str, " stop=1");
610 break;
611 case '2': strcat(mode_str, " stop=2");
612 break;
613 default : printf("invalid number of stop bits '%c'\n", mode[2]);
614 return(1);
615 break;
618 if(flowctrl)
620 strcat(mode_str, " xon=off to=off odsr=off dtr=on rts=off");
622 else
624 strcat(mode_str, " xon=off to=off odsr=off dtr=on rts=on");
628 http://msdn.microsoft.com/en-us/library/windows/desktop/aa363145%28v=vs.85%29.aspx
630 http://technet.microsoft.com/en-us/library/cc732236.aspx
632 https://docs.microsoft.com/en-us/windows/desktop/api/winbase/ns-winbase-_dcb
635 Cport[comport_number] = CreateFileA(comports[comport_number],
636 GENERIC_READ|GENERIC_WRITE,
637 0, /* no share */
638 NULL, /* no security */
639 OPEN_EXISTING,
640 0, /* no threads */
641 NULL); /* no templates */
643 if(Cport[comport_number]==INVALID_HANDLE_VALUE)
645 printf("unable to open comport\n");
646 return(1);
649 DCB port_settings;
650 memset(&port_settings, 0, sizeof(port_settings)); /* clear the new struct */
651 port_settings.DCBlength = sizeof(port_settings);
653 if(!BuildCommDCBA(mode_str, &port_settings))
655 printf("unable to set comport dcb settings\n");
656 CloseHandle(Cport[comport_number]);
657 return(1);
660 if(flowctrl)
662 port_settings.fOutxCtsFlow = TRUE;
663 port_settings.fRtsControl = RTS_CONTROL_HANDSHAKE;
666 if(!SetCommState(Cport[comport_number], &port_settings))
668 printf("unable to set comport cfg settings\n");
669 CloseHandle(Cport[comport_number]);
670 return(1);
673 COMMTIMEOUTS Cptimeouts;
675 Cptimeouts.ReadIntervalTimeout = MAXDWORD;
676 Cptimeouts.ReadTotalTimeoutMultiplier = 0;
677 Cptimeouts.ReadTotalTimeoutConstant = 0;
678 Cptimeouts.WriteTotalTimeoutMultiplier = 0;
679 Cptimeouts.WriteTotalTimeoutConstant = 0;
681 if(!SetCommTimeouts(Cport[comport_number], &Cptimeouts))
683 printf("unable to set comport time-out settings\n");
684 CloseHandle(Cport[comport_number]);
685 return(1);
688 return(0);
692 int RS232_PollComport(int comport_number, unsigned char *buf, int size)
694 int n;
696 /* added the void pointer cast, otherwise gcc will complain about */
697 /* "warning: dereferencing type-punned pointer will break strict aliasing rules" */
699 ReadFile(Cport[comport_number], buf, size, (LPDWORD)((void *)&n), NULL);
701 return(n);
705 int RS232_SendByte(int comport_number, unsigned char byte)
707 int n;
709 WriteFile(Cport[comport_number], &byte, 1, (LPDWORD)((void *)&n), NULL);
711 if(n<0) return(1);
713 return(0);
717 int RS232_SendBuf(int comport_number, unsigned char *buf, int size)
719 int n;
721 if(WriteFile(Cport[comport_number], buf, size, (LPDWORD)((void *)&n), NULL))
723 return(n);
726 return(-1);
730 void RS232_CloseComport(int comport_number)
732 CloseHandle(Cport[comport_number]);
736 http://msdn.microsoft.com/en-us/library/windows/desktop/aa363258%28v=vs.85%29.aspx
739 int RS232_IsDCDEnabled(int comport_number)
741 int status;
743 GetCommModemStatus(Cport[comport_number], (LPDWORD)((void *)&status));
745 if(status&MS_RLSD_ON) return(1);
746 else return(0);
750 int RS232_IsRINGEnabled(int comport_number)
752 int status;
754 GetCommModemStatus(Cport[comport_number], (LPDWORD)((void *)&status));
756 if(status&MS_RING_ON) return(1);
757 else return(0);
761 int RS232_IsCTSEnabled(int comport_number)
763 int status;
765 GetCommModemStatus(Cport[comport_number], (LPDWORD)((void *)&status));
767 if(status&MS_CTS_ON) return(1);
768 else return(0);
772 int RS232_IsDSREnabled(int comport_number)
774 int status;
776 GetCommModemStatus(Cport[comport_number], (LPDWORD)((void *)&status));
778 if(status&MS_DSR_ON) return(1);
779 else return(0);
783 void RS232_enableDTR(int comport_number)
785 EscapeCommFunction(Cport[comport_number], SETDTR);
789 void RS232_disableDTR(int comport_number)
791 EscapeCommFunction(Cport[comport_number], CLRDTR);
795 void RS232_enableRTS(int comport_number)
797 EscapeCommFunction(Cport[comport_number], SETRTS);
801 void RS232_disableRTS(int comport_number)
803 EscapeCommFunction(Cport[comport_number], CLRRTS);
807 https://msdn.microsoft.com/en-us/library/windows/desktop/aa363428%28v=vs.85%29.aspx
810 void RS232_flushRX(int comport_number)
812 PurgeComm(Cport[comport_number], PURGE_RXCLEAR | PURGE_RXABORT);
816 void RS232_flushTX(int comport_number)
818 PurgeComm(Cport[comport_number], PURGE_TXCLEAR | PURGE_TXABORT);
822 void RS232_flushRXTX(int comport_number)
824 PurgeComm(Cport[comport_number], PURGE_RXCLEAR | PURGE_RXABORT);
825 PurgeComm(Cport[comport_number], PURGE_TXCLEAR | PURGE_TXABORT);
829 #endif
832 void RS232_cputs(int comport_number, const char *text) /* sends a string to serial port */
834 while(*text != 0) RS232_SendByte(comport_number, *(text++));
838 /* return index in comports matching to device name or -1 if not found */
839 int RS232_GetPortnr(const char *devname)
841 int i;
843 char str[32];
845 #if defined(__linux__) || defined(__FreeBSD__) /* Linux & FreeBSD */
846 strcpy(str, "/dev/");
847 #else /* windows */
848 strcpy(str, "\\\\.\\");
849 #endif
850 strncat(str, devname, 16);
851 str[31] = 0;
853 for(i=0; i<RS232_PORTNR; i++)
855 if(!strcmp(comports[i], str))
857 return i;
861 return -1; /* device not found */