874 lines
21 KiB
C
874 lines
21 KiB
C
|
/*
|
||
|
***************************************************************************
|
||
|
*
|
||
|
* Author: Teunis van Beelen
|
||
|
*
|
||
|
* Copyright (C) 2005 - 2019 Teunis van Beelen
|
||
|
*
|
||
|
* Email: teuniz@protonmail.com
|
||
|
*
|
||
|
***************************************************************************
|
||
|
*
|
||
|
* This program is free software: you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License as published by
|
||
|
* the Free Software Foundation, either version 3 of the License, or
|
||
|
* (at your option) any later version.
|
||
|
*
|
||
|
* This program is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
*
|
||
|
***************************************************************************
|
||
|
*/
|
||
|
|
||
|
|
||
|
/* Last revision: May 31, 2019 */
|
||
|
/* Added support for hardware flow control using RTS and CTS lines */
|
||
|
/* For more info and how to use this library, visit: http://www.teuniz.net/RS-232/ */
|
||
|
|
||
|
|
||
|
#include "rs232.h"
|
||
|
|
||
|
|
||
|
#if defined(__linux__) || defined(__FreeBSD__) /* Linux & FreeBSD */
|
||
|
|
||
|
#define RS232_PORTNR 38
|
||
|
|
||
|
|
||
|
int Cport[RS232_PORTNR],
|
||
|
error;
|
||
|
|
||
|
struct termios new_port_settings,
|
||
|
old_port_settings[RS232_PORTNR];
|
||
|
|
||
|
const char *comports[RS232_PORTNR]={"/dev/ttyS0","/dev/ttyS1","/dev/ttyS2","/dev/ttyS3","/dev/ttyS4","/dev/ttyS5",
|
||
|
"/dev/ttyS6","/dev/ttyS7","/dev/ttyS8","/dev/ttyS9","/dev/ttyS10","/dev/ttyS11",
|
||
|
"/dev/ttyS12","/dev/ttyS13","/dev/ttyS14","/dev/ttyS15","/dev/ttyUSB0",
|
||
|
"/dev/ttyUSB1","/dev/ttyUSB2","/dev/ttyUSB3","/dev/ttyUSB4","/dev/ttyUSB5",
|
||
|
"/dev/ttyAMA0","/dev/ttyAMA1","/dev/ttyACM0","/dev/ttyACM1",
|
||
|
"/dev/rfcomm0","/dev/rfcomm1","/dev/ircomm0","/dev/ircomm1",
|
||
|
"/dev/cuau0","/dev/cuau1","/dev/cuau2","/dev/cuau3",
|
||
|
"/dev/cuaU0","/dev/cuaU1","/dev/cuaU2","/dev/cuaU3"};
|
||
|
|
||
|
int RS232_OpenComport(int comport_number, int baudrate, const char *mode, int flowctrl)
|
||
|
{
|
||
|
int baudr,
|
||
|
status;
|
||
|
|
||
|
if((comport_number>=RS232_PORTNR)||(comport_number<0))
|
||
|
{
|
||
|
printf("illegal comport number\n");
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
switch(baudrate)
|
||
|
{
|
||
|
case 50 : baudr = B50;
|
||
|
break;
|
||
|
case 75 : baudr = B75;
|
||
|
break;
|
||
|
case 110 : baudr = B110;
|
||
|
break;
|
||
|
case 134 : baudr = B134;
|
||
|
break;
|
||
|
case 150 : baudr = B150;
|
||
|
break;
|
||
|
case 200 : baudr = B200;
|
||
|
break;
|
||
|
case 300 : baudr = B300;
|
||
|
break;
|
||
|
case 600 : baudr = B600;
|
||
|
break;
|
||
|
case 1200 : baudr = B1200;
|
||
|
break;
|
||
|
case 1800 : baudr = B1800;
|
||
|
break;
|
||
|
case 2400 : baudr = B2400;
|
||
|
break;
|
||
|
case 4800 : baudr = B4800;
|
||
|
break;
|
||
|
case 9600 : baudr = B9600;
|
||
|
break;
|
||
|
case 19200 : baudr = B19200;
|
||
|
break;
|
||
|
case 38400 : baudr = B38400;
|
||
|
break;
|
||
|
case 57600 : baudr = B57600;
|
||
|
break;
|
||
|
case 115200 : baudr = B115200;
|
||
|
break;
|
||
|
case 230400 : baudr = B230400;
|
||
|
break;
|
||
|
case 460800 : baudr = B460800;
|
||
|
break;
|
||
|
case 500000 : baudr = B500000;
|
||
|
break;
|
||
|
case 576000 : baudr = B576000;
|
||
|
break;
|
||
|
case 921600 : baudr = B921600;
|
||
|
break;
|
||
|
case 1000000 : baudr = B1000000;
|
||
|
break;
|
||
|
case 1152000 : baudr = B1152000;
|
||
|
break;
|
||
|
case 1500000 : baudr = B1500000;
|
||
|
break;
|
||
|
case 2000000 : baudr = B2000000;
|
||
|
break;
|
||
|
case 2500000 : baudr = B2500000;
|
||
|
break;
|
||
|
case 3000000 : baudr = B3000000;
|
||
|
break;
|
||
|
case 3500000 : baudr = B3500000;
|
||
|
break;
|
||
|
case 4000000 : baudr = B4000000;
|
||
|
break;
|
||
|
default : printf("invalid baudrate\n");
|
||
|
return(1);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
int cbits=CS8,
|
||
|
cpar=0,
|
||
|
ipar=IGNPAR,
|
||
|
bstop=0;
|
||
|
|
||
|
if(strlen(mode) != 3)
|
||
|
{
|
||
|
printf("invalid mode \"%s\"\n", mode);
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
switch(mode[0])
|
||
|
{
|
||
|
case '8': cbits = CS8;
|
||
|
break;
|
||
|
case '7': cbits = CS7;
|
||
|
break;
|
||
|
case '6': cbits = CS6;
|
||
|
break;
|
||
|
case '5': cbits = CS5;
|
||
|
break;
|
||
|
default : printf("invalid number of data-bits '%c'\n", mode[0]);
|
||
|
return(1);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
switch(mode[1])
|
||
|
{
|
||
|
case 'N':
|
||
|
case 'n': cpar = 0;
|
||
|
ipar = IGNPAR;
|
||
|
break;
|
||
|
case 'E':
|
||
|
case 'e': cpar = PARENB;
|
||
|
ipar = INPCK;
|
||
|
break;
|
||
|
case 'O':
|
||
|
case 'o': cpar = (PARENB | PARODD);
|
||
|
ipar = INPCK;
|
||
|
break;
|
||
|
default : printf("invalid parity '%c'\n", mode[1]);
|
||
|
return(1);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
switch(mode[2])
|
||
|
{
|
||
|
case '1': bstop = 0;
|
||
|
break;
|
||
|
case '2': bstop = CSTOPB;
|
||
|
break;
|
||
|
default : printf("invalid number of stop bits '%c'\n", mode[2]);
|
||
|
return(1);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
http://pubs.opengroup.org/onlinepubs/7908799/xsh/termios.h.html
|
||
|
|
||
|
http://man7.org/linux/man-pages/man3/termios.3.html
|
||
|
*/
|
||
|
|
||
|
Cport[comport_number] = open(comports[comport_number], O_RDWR | O_NOCTTY | O_NDELAY);
|
||
|
if(Cport[comport_number]==-1)
|
||
|
{
|
||
|
perror("unable to open comport ");
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
/* lock access so that another process can't also use the port */
|
||
|
if(flock(Cport[comport_number], LOCK_EX | LOCK_NB) != 0)
|
||
|
{
|
||
|
close(Cport[comport_number]);
|
||
|
perror("Another process has locked the comport.");
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
error = tcgetattr(Cport[comport_number], old_port_settings + comport_number);
|
||
|
if(error==-1)
|
||
|
{
|
||
|
close(Cport[comport_number]);
|
||
|
flock(Cport[comport_number], LOCK_UN); /* free the port so that others can use it. */
|
||
|
perror("unable to read portsettings ");
|
||
|
return(1);
|
||
|
}
|
||
|
memset(&new_port_settings, 0, sizeof(new_port_settings)); /* clear the new struct */
|
||
|
|
||
|
new_port_settings.c_cflag = cbits | cpar | bstop | CLOCAL | CREAD;
|
||
|
if(flowctrl)
|
||
|
{
|
||
|
new_port_settings.c_cflag |= CRTSCTS;
|
||
|
}
|
||
|
new_port_settings.c_iflag = ipar;
|
||
|
new_port_settings.c_oflag = 0;
|
||
|
new_port_settings.c_lflag = 0;
|
||
|
new_port_settings.c_cc[VMIN] = 0; /* block untill n bytes are received */
|
||
|
new_port_settings.c_cc[VTIME] = 0; /* block untill a timer expires (n * 100 mSec.) */
|
||
|
|
||
|
cfsetispeed(&new_port_settings, baudr);
|
||
|
cfsetospeed(&new_port_settings, baudr);
|
||
|
|
||
|
error = tcsetattr(Cport[comport_number], TCSANOW, &new_port_settings);
|
||
|
if(error==-1)
|
||
|
{
|
||
|
tcsetattr(Cport[comport_number], TCSANOW, old_port_settings + comport_number);
|
||
|
close(Cport[comport_number]);
|
||
|
flock(Cport[comport_number], LOCK_UN); /* free the port so that others can use it. */
|
||
|
perror("unable to adjust portsettings ");
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
/* http://man7.org/linux/man-pages/man4/tty_ioctl.4.html */
|
||
|
|
||
|
if(ioctl(Cport[comport_number], TIOCMGET, &status) == -1)
|
||
|
{
|
||
|
tcsetattr(Cport[comport_number], TCSANOW, old_port_settings + comport_number);
|
||
|
flock(Cport[comport_number], LOCK_UN); /* free the port so that others can use it. */
|
||
|
perror("unable to get portstatus");
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
status |= TIOCM_DTR; /* turn on DTR */
|
||
|
status |= TIOCM_RTS; /* turn on RTS */
|
||
|
|
||
|
if(ioctl(Cport[comport_number], TIOCMSET, &status) == -1)
|
||
|
{
|
||
|
tcsetattr(Cport[comport_number], TCSANOW, old_port_settings + comport_number);
|
||
|
flock(Cport[comport_number], LOCK_UN); /* free the port so that others can use it. */
|
||
|
perror("unable to set portstatus");
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
|
||
|
int RS232_PollComport(int comport_number, unsigned char *buf, int size)
|
||
|
{
|
||
|
int n;
|
||
|
|
||
|
n = read(Cport[comport_number], buf, size);
|
||
|
|
||
|
if(n < 0)
|
||
|
{
|
||
|
if(errno == EAGAIN) return 0;
|
||
|
}
|
||
|
|
||
|
return(n);
|
||
|
}
|
||
|
|
||
|
|
||
|
int RS232_SendByte(int comport_number, unsigned char byte)
|
||
|
{
|
||
|
int n = write(Cport[comport_number], &byte, 1);
|
||
|
if(n < 0)
|
||
|
{
|
||
|
if(errno == EAGAIN)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
|
||
|
int RS232_SendBuf(int comport_number, unsigned char *buf, int size)
|
||
|
{
|
||
|
int n = write(Cport[comport_number], buf, size);
|
||
|
if(n < 0)
|
||
|
{
|
||
|
if(errno == EAGAIN)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return(n);
|
||
|
}
|
||
|
|
||
|
|
||
|
void RS232_CloseComport(int comport_number)
|
||
|
{
|
||
|
int status;
|
||
|
|
||
|
if(ioctl(Cport[comport_number], TIOCMGET, &status) == -1)
|
||
|
{
|
||
|
perror("unable to get portstatus");
|
||
|
}
|
||
|
|
||
|
status &= ~TIOCM_DTR; /* turn off DTR */
|
||
|
status &= ~TIOCM_RTS; /* turn off RTS */
|
||
|
|
||
|
if(ioctl(Cport[comport_number], TIOCMSET, &status) == -1)
|
||
|
{
|
||
|
perror("unable to set portstatus");
|
||
|
}
|
||
|
|
||
|
tcsetattr(Cport[comport_number], TCSANOW, old_port_settings + comport_number);
|
||
|
close(Cport[comport_number]);
|
||
|
|
||
|
flock(Cport[comport_number], LOCK_UN); /* free the port so that others can use it. */
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
Constant Description
|
||
|
TIOCM_LE DSR (data set ready/line enable)
|
||
|
TIOCM_DTR DTR (data terminal ready)
|
||
|
TIOCM_RTS RTS (request to send)
|
||
|
TIOCM_ST Secondary TXD (transmit)
|
||
|
TIOCM_SR Secondary RXD (receive)
|
||
|
TIOCM_CTS CTS (clear to send)
|
||
|
TIOCM_CAR DCD (data carrier detect)
|
||
|
TIOCM_CD see TIOCM_CAR
|
||
|
TIOCM_RNG RNG (ring)
|
||
|
TIOCM_RI see TIOCM_RNG
|
||
|
TIOCM_DSR DSR (data set ready)
|
||
|
|
||
|
http://man7.org/linux/man-pages/man4/tty_ioctl.4.html
|
||
|
*/
|
||
|
|
||
|
int RS232_IsDCDEnabled(int comport_number)
|
||
|
{
|
||
|
int status;
|
||
|
|
||
|
ioctl(Cport[comport_number], TIOCMGET, &status);
|
||
|
|
||
|
if(status&TIOCM_CAR) return(1);
|
||
|
else return(0);
|
||
|
}
|
||
|
|
||
|
|
||
|
int RS232_IsRINGEnabled(int comport_number)
|
||
|
{
|
||
|
int status;
|
||
|
|
||
|
ioctl(Cport[comport_number], TIOCMGET, &status);
|
||
|
|
||
|
if(status&TIOCM_RNG) return(1);
|
||
|
else return(0);
|
||
|
}
|
||
|
|
||
|
|
||
|
int RS232_IsCTSEnabled(int comport_number)
|
||
|
{
|
||
|
int status;
|
||
|
|
||
|
ioctl(Cport[comport_number], TIOCMGET, &status);
|
||
|
|
||
|
if(status&TIOCM_CTS) return(1);
|
||
|
else return(0);
|
||
|
}
|
||
|
|
||
|
|
||
|
int RS232_IsDSREnabled(int comport_number)
|
||
|
{
|
||
|
int status;
|
||
|
|
||
|
ioctl(Cport[comport_number], TIOCMGET, &status);
|
||
|
|
||
|
if(status&TIOCM_DSR) return(1);
|
||
|
else return(0);
|
||
|
}
|
||
|
|
||
|
|
||
|
void RS232_enableDTR(int comport_number)
|
||
|
{
|
||
|
int status;
|
||
|
|
||
|
if(ioctl(Cport[comport_number], TIOCMGET, &status) == -1)
|
||
|
{
|
||
|
perror("unable to get portstatus");
|
||
|
}
|
||
|
|
||
|
status |= TIOCM_DTR; /* turn on DTR */
|
||
|
|
||
|
if(ioctl(Cport[comport_number], TIOCMSET, &status) == -1)
|
||
|
{
|
||
|
perror("unable to set portstatus");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void RS232_disableDTR(int comport_number)
|
||
|
{
|
||
|
int status;
|
||
|
|
||
|
if(ioctl(Cport[comport_number], TIOCMGET, &status) == -1)
|
||
|
{
|
||
|
perror("unable to get portstatus");
|
||
|
}
|
||
|
|
||
|
status &= ~TIOCM_DTR; /* turn off DTR */
|
||
|
|
||
|
if(ioctl(Cport[comport_number], TIOCMSET, &status) == -1)
|
||
|
{
|
||
|
perror("unable to set portstatus");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void RS232_enableRTS(int comport_number)
|
||
|
{
|
||
|
int status;
|
||
|
|
||
|
if(ioctl(Cport[comport_number], TIOCMGET, &status) == -1)
|
||
|
{
|
||
|
perror("unable to get portstatus");
|
||
|
}
|
||
|
|
||
|
status |= TIOCM_RTS; /* turn on RTS */
|
||
|
|
||
|
if(ioctl(Cport[comport_number], TIOCMSET, &status) == -1)
|
||
|
{
|
||
|
perror("unable to set portstatus");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void RS232_disableRTS(int comport_number)
|
||
|
{
|
||
|
int status;
|
||
|
|
||
|
if(ioctl(Cport[comport_number], TIOCMGET, &status) == -1)
|
||
|
{
|
||
|
perror("unable to get portstatus");
|
||
|
}
|
||
|
|
||
|
status &= ~TIOCM_RTS; /* turn off RTS */
|
||
|
|
||
|
if(ioctl(Cport[comport_number], TIOCMSET, &status) == -1)
|
||
|
{
|
||
|
perror("unable to set portstatus");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void RS232_flushRX(int comport_number)
|
||
|
{
|
||
|
tcflush(Cport[comport_number], TCIFLUSH);
|
||
|
}
|
||
|
|
||
|
|
||
|
void RS232_flushTX(int comport_number)
|
||
|
{
|
||
|
tcflush(Cport[comport_number], TCOFLUSH);
|
||
|
}
|
||
|
|
||
|
|
||
|
void RS232_flushRXTX(int comport_number)
|
||
|
{
|
||
|
tcflush(Cport[comport_number], TCIOFLUSH);
|
||
|
}
|
||
|
|
||
|
|
||
|
#else /* windows */
|
||
|
|
||
|
#define RS232_PORTNR 32
|
||
|
|
||
|
HANDLE Cport[RS232_PORTNR];
|
||
|
|
||
|
|
||
|
const char *comports[RS232_PORTNR]={"\\\\.\\COM1", "\\\\.\\COM2", "\\\\.\\COM3", "\\\\.\\COM4",
|
||
|
"\\\\.\\COM5", "\\\\.\\COM6", "\\\\.\\COM7", "\\\\.\\COM8",
|
||
|
"\\\\.\\COM9", "\\\\.\\COM10", "\\\\.\\COM11", "\\\\.\\COM12",
|
||
|
"\\\\.\\COM13", "\\\\.\\COM14", "\\\\.\\COM15", "\\\\.\\COM16",
|
||
|
"\\\\.\\COM17", "\\\\.\\COM18", "\\\\.\\COM19", "\\\\.\\COM20",
|
||
|
"\\\\.\\COM21", "\\\\.\\COM22", "\\\\.\\COM23", "\\\\.\\COM24",
|
||
|
"\\\\.\\COM25", "\\\\.\\COM26", "\\\\.\\COM27", "\\\\.\\COM28",
|
||
|
"\\\\.\\COM29", "\\\\.\\COM30", "\\\\.\\COM31", "\\\\.\\COM32"};
|
||
|
|
||
|
char mode_str[128];
|
||
|
|
||
|
|
||
|
int RS232_OpenComport(int comport_number, int baudrate, const char *mode, int flowctrl)
|
||
|
{
|
||
|
if((comport_number>=RS232_PORTNR)||(comport_number<0))
|
||
|
{
|
||
|
printf("illegal comport number\n");
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
switch(baudrate)
|
||
|
{
|
||
|
case 110 : strcpy(mode_str, "baud=110");
|
||
|
break;
|
||
|
case 300 : strcpy(mode_str, "baud=300");
|
||
|
break;
|
||
|
case 600 : strcpy(mode_str, "baud=600");
|
||
|
break;
|
||
|
case 1200 : strcpy(mode_str, "baud=1200");
|
||
|
break;
|
||
|
case 2400 : strcpy(mode_str, "baud=2400");
|
||
|
break;
|
||
|
case 4800 : strcpy(mode_str, "baud=4800");
|
||
|
break;
|
||
|
case 9600 : strcpy(mode_str, "baud=9600");
|
||
|
break;
|
||
|
case 19200 : strcpy(mode_str, "baud=19200");
|
||
|
break;
|
||
|
case 38400 : strcpy(mode_str, "baud=38400");
|
||
|
break;
|
||
|
case 57600 : strcpy(mode_str, "baud=57600");
|
||
|
break;
|
||
|
case 115200 : strcpy(mode_str, "baud=115200");
|
||
|
break;
|
||
|
case 128000 : strcpy(mode_str, "baud=128000");
|
||
|
break;
|
||
|
case 256000 : strcpy(mode_str, "baud=256000");
|
||
|
break;
|
||
|
case 500000 : strcpy(mode_str, "baud=500000");
|
||
|
break;
|
||
|
case 921600 : strcpy(mode_str, "baud=921600");
|
||
|
break;
|
||
|
case 1000000 : strcpy(mode_str, "baud=1000000");
|
||
|
break;
|
||
|
case 1500000 : strcpy(mode_str, "baud=1500000");
|
||
|
break;
|
||
|
case 2000000 : strcpy(mode_str, "baud=2000000");
|
||
|
break;
|
||
|
case 3000000 : strcpy(mode_str, "baud=3000000");
|
||
|
break;
|
||
|
default : printf("invalid baudrate\n");
|
||
|
return(1);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if(strlen(mode) != 3)
|
||
|
{
|
||
|
printf("invalid mode \"%s\"\n", mode);
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
switch(mode[0])
|
||
|
{
|
||
|
case '8': strcat(mode_str, " data=8");
|
||
|
break;
|
||
|
case '7': strcat(mode_str, " data=7");
|
||
|
break;
|
||
|
case '6': strcat(mode_str, " data=6");
|
||
|
break;
|
||
|
case '5': strcat(mode_str, " data=5");
|
||
|
break;
|
||
|
default : printf("invalid number of data-bits '%c'\n", mode[0]);
|
||
|
return(1);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
switch(mode[1])
|
||
|
{
|
||
|
case 'N':
|
||
|
case 'n': strcat(mode_str, " parity=n");
|
||
|
break;
|
||
|
case 'E':
|
||
|
case 'e': strcat(mode_str, " parity=e");
|
||
|
break;
|
||
|
case 'O':
|
||
|
case 'o': strcat(mode_str, " parity=o");
|
||
|
break;
|
||
|
default : printf("invalid parity '%c'\n", mode[1]);
|
||
|
return(1);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
switch(mode[2])
|
||
|
{
|
||
|
case '1': strcat(mode_str, " stop=1");
|
||
|
break;
|
||
|
case '2': strcat(mode_str, " stop=2");
|
||
|
break;
|
||
|
default : printf("invalid number of stop bits '%c'\n", mode[2]);
|
||
|
return(1);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if(flowctrl)
|
||
|
{
|
||
|
strcat(mode_str, " xon=off to=off odsr=off dtr=on rts=off");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
strcat(mode_str, " xon=off to=off odsr=off dtr=on rts=on");
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
http://msdn.microsoft.com/en-us/library/windows/desktop/aa363145%28v=vs.85%29.aspx
|
||
|
|
||
|
http://technet.microsoft.com/en-us/library/cc732236.aspx
|
||
|
|
||
|
https://docs.microsoft.com/en-us/windows/desktop/api/winbase/ns-winbase-_dcb
|
||
|
*/
|
||
|
|
||
|
Cport[comport_number] = CreateFileA(comports[comport_number],
|
||
|
GENERIC_READ|GENERIC_WRITE,
|
||
|
0, /* no share */
|
||
|
NULL, /* no security */
|
||
|
OPEN_EXISTING,
|
||
|
0, /* no threads */
|
||
|
NULL); /* no templates */
|
||
|
|
||
|
if(Cport[comport_number]==INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
printf("unable to open comport\n");
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
DCB port_settings;
|
||
|
memset(&port_settings, 0, sizeof(port_settings)); /* clear the new struct */
|
||
|
port_settings.DCBlength = sizeof(port_settings);
|
||
|
|
||
|
if(!BuildCommDCBA(mode_str, &port_settings))
|
||
|
{
|
||
|
printf("unable to set comport dcb settings\n");
|
||
|
CloseHandle(Cport[comport_number]);
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
if(flowctrl)
|
||
|
{
|
||
|
port_settings.fOutxCtsFlow = TRUE;
|
||
|
port_settings.fRtsControl = RTS_CONTROL_HANDSHAKE;
|
||
|
}
|
||
|
|
||
|
if(!SetCommState(Cport[comport_number], &port_settings))
|
||
|
{
|
||
|
printf("unable to set comport cfg settings\n");
|
||
|
CloseHandle(Cport[comport_number]);
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
COMMTIMEOUTS Cptimeouts;
|
||
|
|
||
|
Cptimeouts.ReadIntervalTimeout = MAXDWORD;
|
||
|
Cptimeouts.ReadTotalTimeoutMultiplier = 0;
|
||
|
Cptimeouts.ReadTotalTimeoutConstant = 0;
|
||
|
Cptimeouts.WriteTotalTimeoutMultiplier = 0;
|
||
|
Cptimeouts.WriteTotalTimeoutConstant = 0;
|
||
|
|
||
|
if(!SetCommTimeouts(Cport[comport_number], &Cptimeouts))
|
||
|
{
|
||
|
printf("unable to set comport time-out settings\n");
|
||
|
CloseHandle(Cport[comport_number]);
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
|
||
|
int RS232_PollComport(int comport_number, unsigned char *buf, int size)
|
||
|
{
|
||
|
int n;
|
||
|
|
||
|
/* added the void pointer cast, otherwise gcc will complain about */
|
||
|
/* "warning: dereferencing type-punned pointer will break strict aliasing rules" */
|
||
|
|
||
|
ReadFile(Cport[comport_number], buf, size, (LPDWORD)((void *)&n), NULL);
|
||
|
|
||
|
return(n);
|
||
|
}
|
||
|
|
||
|
|
||
|
int RS232_SendByte(int comport_number, unsigned char byte)
|
||
|
{
|
||
|
int n;
|
||
|
|
||
|
WriteFile(Cport[comport_number], &byte, 1, (LPDWORD)((void *)&n), NULL);
|
||
|
|
||
|
if(n<0) return(1);
|
||
|
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
|
||
|
int RS232_SendBuf(int comport_number, unsigned char *buf, int size)
|
||
|
{
|
||
|
int n;
|
||
|
|
||
|
if(WriteFile(Cport[comport_number], buf, size, (LPDWORD)((void *)&n), NULL))
|
||
|
{
|
||
|
return(n);
|
||
|
}
|
||
|
|
||
|
return(-1);
|
||
|
}
|
||
|
|
||
|
|
||
|
void RS232_CloseComport(int comport_number)
|
||
|
{
|
||
|
CloseHandle(Cport[comport_number]);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
http://msdn.microsoft.com/en-us/library/windows/desktop/aa363258%28v=vs.85%29.aspx
|
||
|
*/
|
||
|
|
||
|
int RS232_IsDCDEnabled(int comport_number)
|
||
|
{
|
||
|
int status;
|
||
|
|
||
|
GetCommModemStatus(Cport[comport_number], (LPDWORD)((void *)&status));
|
||
|
|
||
|
if(status&MS_RLSD_ON) return(1);
|
||
|
else return(0);
|
||
|
}
|
||
|
|
||
|
|
||
|
int RS232_IsRINGEnabled(int comport_number)
|
||
|
{
|
||
|
int status;
|
||
|
|
||
|
GetCommModemStatus(Cport[comport_number], (LPDWORD)((void *)&status));
|
||
|
|
||
|
if(status&MS_RING_ON) return(1);
|
||
|
else return(0);
|
||
|
}
|
||
|
|
||
|
|
||
|
int RS232_IsCTSEnabled(int comport_number)
|
||
|
{
|
||
|
int status;
|
||
|
|
||
|
GetCommModemStatus(Cport[comport_number], (LPDWORD)((void *)&status));
|
||
|
|
||
|
if(status&MS_CTS_ON) return(1);
|
||
|
else return(0);
|
||
|
}
|
||
|
|
||
|
|
||
|
int RS232_IsDSREnabled(int comport_number)
|
||
|
{
|
||
|
int status;
|
||
|
|
||
|
GetCommModemStatus(Cport[comport_number], (LPDWORD)((void *)&status));
|
||
|
|
||
|
if(status&MS_DSR_ON) return(1);
|
||
|
else return(0);
|
||
|
}
|
||
|
|
||
|
|
||
|
void RS232_enableDTR(int comport_number)
|
||
|
{
|
||
|
EscapeCommFunction(Cport[comport_number], SETDTR);
|
||
|
}
|
||
|
|
||
|
|
||
|
void RS232_disableDTR(int comport_number)
|
||
|
{
|
||
|
EscapeCommFunction(Cport[comport_number], CLRDTR);
|
||
|
}
|
||
|
|
||
|
|
||
|
void RS232_enableRTS(int comport_number)
|
||
|
{
|
||
|
EscapeCommFunction(Cport[comport_number], SETRTS);
|
||
|
}
|
||
|
|
||
|
|
||
|
void RS232_disableRTS(int comport_number)
|
||
|
{
|
||
|
EscapeCommFunction(Cport[comport_number], CLRRTS);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
https://msdn.microsoft.com/en-us/library/windows/desktop/aa363428%28v=vs.85%29.aspx
|
||
|
*/
|
||
|
|
||
|
void RS232_flushRX(int comport_number)
|
||
|
{
|
||
|
PurgeComm(Cport[comport_number], PURGE_RXCLEAR | PURGE_RXABORT);
|
||
|
}
|
||
|
|
||
|
|
||
|
void RS232_flushTX(int comport_number)
|
||
|
{
|
||
|
PurgeComm(Cport[comport_number], PURGE_TXCLEAR | PURGE_TXABORT);
|
||
|
}
|
||
|
|
||
|
|
||
|
void RS232_flushRXTX(int comport_number)
|
||
|
{
|
||
|
PurgeComm(Cport[comport_number], PURGE_RXCLEAR | PURGE_RXABORT);
|
||
|
PurgeComm(Cport[comport_number], PURGE_TXCLEAR | PURGE_TXABORT);
|
||
|
}
|
||
|
|
||
|
|
||
|
#endif
|
||
|
|
||
|
|
||
|
void RS232_cputs(int comport_number, const char *text) /* sends a string to serial port */
|
||
|
{
|
||
|
while(*text != 0) RS232_SendByte(comport_number, *(text++));
|
||
|
}
|
||
|
|
||
|
|
||
|
/* return index in comports matching to device name or -1 if not found */
|
||
|
int RS232_GetPortnr(const char *devname)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
char str[32];
|
||
|
|
||
|
#if defined(__linux__) || defined(__FreeBSD__) /* Linux & FreeBSD */
|
||
|
strcpy(str, "/dev/");
|
||
|
#else /* windows */
|
||
|
strcpy(str, "\\\\.\\");
|
||
|
#endif
|
||
|
strncat(str, devname, 16);
|
||
|
str[31] = 0;
|
||
|
|
||
|
for(i=0; i<RS232_PORTNR; i++)
|
||
|
{
|
||
|
if(!strcmp(comports[i], str))
|
||
|
{
|
||
|
return i;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return -1; /* device not found */
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|