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/ */
37 #if defined(__linux__) || defined(__FreeBSD__) /* Linux & FreeBSD */
39 #define RS232_PORTNR 38
42 int Cport
[RS232_PORTNR
],
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
)
62 if((comport_number
>=RS232_PORTNR
)||(comport_number
<0))
64 printf("illegal comport number\n");
70 case 50 : baudr
= B50
;
72 case 75 : baudr
= B75
;
74 case 110 : baudr
= B110
;
76 case 134 : baudr
= B134
;
78 case 150 : baudr
= B150
;
80 case 200 : baudr
= B200
;
82 case 300 : baudr
= B300
;
84 case 600 : baudr
= B600
;
86 case 1200 : baudr
= B1200
;
88 case 1800 : baudr
= B1800
;
90 case 2400 : baudr
= B2400
;
92 case 4800 : baudr
= B4800
;
94 case 9600 : baudr
= B9600
;
96 case 19200 : baudr
= B19200
;
98 case 38400 : baudr
= B38400
;
100 case 57600 : baudr
= B57600
;
102 case 115200 : baudr
= B115200
;
104 case 230400 : baudr
= B230400
;
106 case 460800 : baudr
= B460800
;
108 case 500000 : baudr
= B500000
;
110 case 576000 : baudr
= B576000
;
112 case 921600 : baudr
= B921600
;
114 case 1000000 : baudr
= B1000000
;
116 case 1152000 : baudr
= B1152000
;
118 case 1500000 : baudr
= B1500000
;
120 case 2000000 : baudr
= B2000000
;
122 case 2500000 : baudr
= B2500000
;
124 case 3000000 : baudr
= B3000000
;
126 case 3500000 : baudr
= B3500000
;
128 case 4000000 : baudr
= B4000000
;
130 default : printf("invalid baudrate\n");
140 if(strlen(mode
) != 3)
142 printf("invalid mode \"%s\"\n", mode
);
148 case '8': cbits
= CS8
;
150 case '7': cbits
= CS7
;
152 case '6': cbits
= CS6
;
154 case '5': cbits
= CS5
;
156 default : printf("invalid number of data-bits '%c'\n", mode
[0]);
168 case 'e': cpar
= PARENB
;
172 case 'o': cpar
= (PARENB
| PARODD
);
175 default : printf("invalid parity '%c'\n", mode
[1]);
184 case '2': bstop
= CSTOPB
;
186 default : printf("invalid number of stop bits '%c'\n", mode
[2]);
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 ");
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.");
212 error
= tcgetattr(Cport
[comport_number
], old_port_settings
+ comport_number
);
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 ");
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
;
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
);
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 ");
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");
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");
271 int RS232_PollComport(int comport_number
, unsigned char *buf
, int size
)
275 n
= read(Cport
[comport_number
], buf
, size
);
279 if(errno
== EAGAIN
) return 0;
286 int RS232_SendByte(int comport_number
, unsigned char byte
)
288 int n
= write(Cport
[comport_number
], &byte
, 1);
305 int RS232_SendBuf(int comport_number
, unsigned char *buf
, int size
)
307 int n
= write(Cport
[comport_number
], buf
, size
);
324 void RS232_CloseComport(int comport_number
)
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. */
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
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
)
368 ioctl(Cport
[comport_number
], TIOCMGET
, &status
);
370 if(status
&TIOCM_CAR
) return(1);
375 int RS232_IsRINGEnabled(int comport_number
)
379 ioctl(Cport
[comport_number
], TIOCMGET
, &status
);
381 if(status
&TIOCM_RNG
) return(1);
386 int RS232_IsCTSEnabled(int comport_number
)
390 ioctl(Cport
[comport_number
], TIOCMGET
, &status
);
392 if(status
&TIOCM_CTS
) return(1);
397 int RS232_IsDSREnabled(int comport_number
)
401 ioctl(Cport
[comport_number
], TIOCMGET
, &status
);
403 if(status
&TIOCM_DSR
) return(1);
408 void RS232_enableDTR(int comport_number
)
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
)
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
)
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
)
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
);
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"};
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");
527 case 110 : strcpy(mode_str
, "baud=110");
529 case 300 : strcpy(mode_str
, "baud=300");
531 case 600 : strcpy(mode_str
, "baud=600");
533 case 1200 : strcpy(mode_str
, "baud=1200");
535 case 2400 : strcpy(mode_str
, "baud=2400");
537 case 4800 : strcpy(mode_str
, "baud=4800");
539 case 9600 : strcpy(mode_str
, "baud=9600");
541 case 19200 : strcpy(mode_str
, "baud=19200");
543 case 38400 : strcpy(mode_str
, "baud=38400");
545 case 57600 : strcpy(mode_str
, "baud=57600");
547 case 115200 : strcpy(mode_str
, "baud=115200");
549 case 128000 : strcpy(mode_str
, "baud=128000");
551 case 256000 : strcpy(mode_str
, "baud=256000");
553 case 500000 : strcpy(mode_str
, "baud=500000");
555 case 921600 : strcpy(mode_str
, "baud=921600");
557 case 1000000 : strcpy(mode_str
, "baud=1000000");
559 case 1500000 : strcpy(mode_str
, "baud=1500000");
561 case 2000000 : strcpy(mode_str
, "baud=2000000");
563 case 3000000 : strcpy(mode_str
, "baud=3000000");
565 default : printf("invalid baudrate\n");
570 if(strlen(mode
) != 3)
572 printf("invalid mode \"%s\"\n", mode
);
578 case '8': strcat(mode_str
, " data=8");
580 case '7': strcat(mode_str
, " data=7");
582 case '6': strcat(mode_str
, " data=6");
584 case '5': strcat(mode_str
, " data=5");
586 default : printf("invalid number of data-bits '%c'\n", mode
[0]);
594 case 'n': strcat(mode_str
, " parity=n");
597 case 'e': strcat(mode_str
, " parity=e");
600 case 'o': strcat(mode_str
, " parity=o");
602 default : printf("invalid parity '%c'\n", mode
[1]);
609 case '1': strcat(mode_str
, " stop=1");
611 case '2': strcat(mode_str
, " stop=2");
613 default : printf("invalid number of stop bits '%c'\n", mode
[2]);
620 strcat(mode_str
, " xon=off to=off odsr=off dtr=on rts=off");
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
,
638 NULL
, /* no security */
641 NULL
); /* no templates */
643 if(Cport
[comport_number
]==INVALID_HANDLE_VALUE
)
645 printf("unable to open comport\n");
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
]);
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
]);
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
]);
692 int RS232_PollComport(int comport_number
, unsigned char *buf
, int size
)
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
);
705 int RS232_SendByte(int comport_number
, unsigned char byte
)
709 WriteFile(Cport
[comport_number
], &byte
, 1, (LPDWORD
)((void *)&n
), NULL
);
717 int RS232_SendBuf(int comport_number
, unsigned char *buf
, int size
)
721 if(WriteFile(Cport
[comport_number
], buf
, size
, (LPDWORD
)((void *)&n
), NULL
))
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
)
743 GetCommModemStatus(Cport
[comport_number
], (LPDWORD
)((void *)&status
));
745 if(status
&MS_RLSD_ON
) return(1);
750 int RS232_IsRINGEnabled(int comport_number
)
754 GetCommModemStatus(Cport
[comport_number
], (LPDWORD
)((void *)&status
));
756 if(status
&MS_RING_ON
) return(1);
761 int RS232_IsCTSEnabled(int comport_number
)
765 GetCommModemStatus(Cport
[comport_number
], (LPDWORD
)((void *)&status
));
767 if(status
&MS_CTS_ON
) return(1);
772 int RS232_IsDSREnabled(int comport_number
)
776 GetCommModemStatus(Cport
[comport_number
], (LPDWORD
)((void *)&status
));
778 if(status
&MS_DSR_ON
) return(1);
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
);
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
)
845 #if defined(__linux__) || defined(__FreeBSD__) /* Linux & FreeBSD */
846 strcpy(str
, "/dev/");
848 strcpy(str
, "\\\\.\\");
850 strncat(str
, devname
, 16);
853 for(i
=0; i
<RS232_PORTNR
; i
++)
855 if(!strcmp(comports
[i
], str
))
861 return -1; /* device not found */