189 lines
3.5 KiB
C
189 lines
3.5 KiB
C
#include <sys/file.h>
|
|
#include <unistd.h>
|
|
#include <termios.h>
|
|
#include <stdio.h>
|
|
#include <fcntl.h>
|
|
#include <sys/ioctl.h>
|
|
#include "debug.h"
|
|
#include "serial.h"
|
|
|
|
int ser_get_bps_const(int speed)
|
|
{
|
|
int bps_rate = 0;
|
|
|
|
LOG_ENTER();
|
|
|
|
LOG(LOG_DEBUG, "Checking speed: %d", speed);
|
|
|
|
switch (speed) {
|
|
case 115200:
|
|
bps_rate = B115200;
|
|
break;
|
|
case 57600:
|
|
bps_rate = B57600;
|
|
break;
|
|
case 38400:
|
|
bps_rate = B38400;
|
|
break;
|
|
case 19200:
|
|
bps_rate = B19200;
|
|
break;
|
|
case 9600:
|
|
bps_rate = B9600;
|
|
break;
|
|
case 4800:
|
|
bps_rate = B4800;
|
|
break;
|
|
case 2400:
|
|
bps_rate = B2400;
|
|
break;
|
|
case 1200:
|
|
bps_rate = B1200;
|
|
break;
|
|
case 600:
|
|
bps_rate = B600;
|
|
break;
|
|
case 300:
|
|
bps_rate = B300;
|
|
break;
|
|
case 150:
|
|
bps_rate = B150;
|
|
break;
|
|
case 134:
|
|
bps_rate = B134;
|
|
break;
|
|
case 110:
|
|
bps_rate = B110;
|
|
break;
|
|
case 75:
|
|
bps_rate = B75;
|
|
break;
|
|
case 50:
|
|
bps_rate = B50;
|
|
break;
|
|
case 0:
|
|
bps_rate = B0;
|
|
break;
|
|
default:
|
|
ELOG(LOG_FATAL, "Unknown baud rate");
|
|
bps_rate = -1;
|
|
}
|
|
LOG_EXIT();
|
|
return bps_rate;
|
|
|
|
}
|
|
|
|
int ser_init_conn(char *tty, int speed)
|
|
{
|
|
int fd = -1;
|
|
struct termios tio;
|
|
int bps_rate = 0;
|
|
|
|
LOG_ENTER();
|
|
|
|
bps_rate = ser_get_bps_const(speed);
|
|
|
|
if (bps_rate > -1) {
|
|
/* open the device to be non-blocking (read will return immediatly) */
|
|
LOG(LOG_INFO, "Opening serial device");
|
|
|
|
fd = open(tty, O_RDWR | O_NOCTTY);
|
|
|
|
if (fd < 0) {
|
|
ELOG(LOG_FATAL, "TTY %s could not be opened", tty);
|
|
}
|
|
else {
|
|
LOG(LOG_INFO, "Opened serial device %s at speed %d as fd %d", tty, speed, fd);
|
|
|
|
/* Make the file descriptor asynchronous (the manual page says only
|
|
O_APPEND and O_NONBLOCK, will work with F_SETFL...) */
|
|
fcntl(fd, F_SETFL, FASYNC);
|
|
|
|
tio.c_cflag = bps_rate | CS8 | CLOCAL | CREAD | CRTSCTS;
|
|
|
|
tio.c_iflag = (IGNBRK);
|
|
tio.c_oflag = 0;
|
|
tio.c_lflag = 0;
|
|
tio.c_cc[VMIN] = 1;
|
|
tio.c_cc[VTIME] = 0;
|
|
|
|
tcflush(fd, TCIFLUSH);
|
|
cfsetispeed(&tio, bps_rate);
|
|
cfsetospeed(&tio, bps_rate);
|
|
tcsetattr(fd, TCSANOW, &tio);
|
|
LOG(LOG_INFO, "serial device configured");
|
|
}
|
|
}
|
|
|
|
LOG_EXIT();
|
|
return fd;
|
|
}
|
|
|
|
|
|
int ser_set_flow_control(int fd, int status)
|
|
{
|
|
struct termios tio;
|
|
|
|
if (0 != tcgetattr(fd, &tio)) {
|
|
ELOG(LOG_FATAL, "Could not get serial port attributes");
|
|
return -1;
|
|
}
|
|
// turn all off.
|
|
tio.c_cflag &= ~(IXON | IXOFF | CRTSCTS);
|
|
tio.c_cflag |= status;
|
|
if (0 != tcsetattr(fd, TCSANOW, &tio)) {
|
|
ELOG(LOG_FATAL, "Could not set serial port attributes");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
int ser_get_control_lines(int fd)
|
|
{
|
|
int status;
|
|
|
|
|
|
if (0 > ioctl(fd, TIOCMGET, &status)) {
|
|
ELOG(LOG_FATAL, "Could not obtain serial port status");
|
|
return -1;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
int ser_set_control_lines(int fd, int state)
|
|
{
|
|
unsigned int status;
|
|
|
|
|
|
if (0 > (status = ser_get_control_lines(fd))) {
|
|
return status;
|
|
}
|
|
status &= ~(TIOCM_RTS | TIOCM_DTR);
|
|
status |= state;
|
|
if (0 > ioctl(fd, TIOCMSET, &status)) {
|
|
#ifndef WIN32
|
|
ELOG(LOG_FATAL, "Could not set serial port status");
|
|
return -1;
|
|
#else
|
|
ELOG(LOG_WARN, "Could not set serial port status, CYGWIN bug?");
|
|
#endif
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int ser_write(int fd, char *data, int len)
|
|
{
|
|
log_trace(TRACE_MODEM_OUT, data, len);
|
|
return write(fd, data, len);
|
|
}
|
|
|
|
int ser_read(int fd, char *data, int len)
|
|
{
|
|
int res;
|
|
|
|
res = read(fd, data, len);
|
|
log_trace(TRACE_MODEM_IN, data, res);
|
|
return res;
|
|
}
|