1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
|
#include "serial.h"
static int rate_to_constant(int baudrate) {
#define B(x) case x: return B##x
switch(baudrate) {
B(50); B(75); B(110); B(134); B(150);
B(200); B(300); B(600); B(1200); B(1800);
B(2400); B(4800); B(9600); B(19200); B(38400);
B(57600); B(115200); B(230400); B(460800); B(500000);
B(576000); B(921600); B(1000000);B(1152000);B(1500000);
default: return 0;
}
#undef B
}
int serial_open(const char *devpath, unsigned long baudrate)
{
int fd, speed;
struct termios tty;
struct serial_struct serinfo;
// struct termios tty_old;
// open device
if ((fd = open(devpath, O_RDWR | O_NOCTTY)) < 0) {
return -1;
}
speed = rate_to_constant(baudrate);
if (speed == 0) {
/* custom divisor */
serinfo.reserved_char[0] = 0;
if (ioctl(fd, TIOCGSERIAL, &serinfo) < 0)
return -1;
serinfo.flags &= ~ASYNC_SPD_MASK;
serinfo.flags |= ASYNC_SPD_CUST;
serinfo.custom_divisor = (serinfo.baud_base + (baudrate / 2)) / baudrate;
if (serinfo.custom_divisor < 1)
serinfo.custom_divisor = 1;
if (ioctl(fd, TIOCSSERIAL, &serinfo) < 0)
return -1;
if (ioctl(fd, TIOCGSERIAL, &serinfo) < 0)
return -1;
if (serinfo.custom_divisor * baudrate != serinfo.baud_base) {
warnx("actual baudrate is %d / %d = %f",
serinfo.baud_base, serinfo.custom_divisor,
(float)serinfo.baud_base / serinfo.custom_divisor);
}
}
// set custom baudrate
ioctl(fd, TIOCGSERIAL, &serinfo);
serinfo.flags = ASYNC_SPD_CUST | ASYNC_LOW_LATENCY;
serinfo.custom_divisor = serinfo.baud_base / baudrate;
ioctl(fd, TIOCSSERIAL, &serinfo);
// set parameters
if (tcgetattr(fd, &tty) != 0) {
// perror("failed tcgetattr");
return -1;
}
cfsetispeed(&tty, speed ?: B38400);
cfsetospeed(&tty, speed ?: B38400);
cfmakeraw(&tty);
tty.c_cflag &= ~PARENB; // no parity
tty.c_cflag &= ~CSTOPB; // no stop bit
tty.c_cflag |= CS8; // 8 bit data
tty.c_cflag &= ~CRTSCTS; // no flow control
tty.c_lflag = 0; // no signaling chars, no echo, no canonical processing
tty.c_oflag = 0; // no remapping, no delays
tty.c_cc[VMIN] = 0; // no block read
tty.c_cc[VTIME] = 5; // .5 seconds read timeout
tty.c_cflag |= CREAD | CLOCAL; // turn on read and ignore ctrl lines
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // turn off s/w flow ctrl
tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // make raw
tty.c_oflag &= ~OPOST; // make raw
tcflush(fd , TCIFLUSH); // ?
if (tcsetattr (fd, TCSANOW, &tty) != 0) {
// perror("failed tcsetattr to set serial port.\n");
return -1;
}
return fd;
}
|