-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserial.cpp
More file actions
67 lines (62 loc) · 2.1 KB
/
Copy pathserial.cpp
File metadata and controls
67 lines (62 loc) · 2.1 KB
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
#include <asm/fcntl.h>
#include <asm/termios.h>
#include "serial.h"
#include "util.h"
// glibc goes out of its way to make it hard to set custom baud rates.
// We have to include kernel header files and make direct ioctl()s. These
// header files conflict with the glibc versions. So, all of this code has
// to live in its own compilation unit, and we need to import the small
// number of glibc symbols that we need without actually using system headers.
extern "C" {
int open(const char *, int, ...);
int ioctl(int, unsigned long, ...);
#ifndef __useconds_t_defined
int usleep(unsigned);
#else
int usleep(__useconds_t);
#endif
}
int Serial::open(const char *s) {
int fd = ::open(s, O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK|O_SYNC);
if (fd < 0) {
DBGc(1, "Failed to open serial port for DMX: " << s);
return -1;
}
// DMX uses 8N2 at 250,000 baud. We don't care about the receiver, but
// we have to explicitly turn on the transmitter by pulling RTS to low.
struct termios2 opt;
ioctl(fd, TCGETS2, &opt);
opt.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
opt.c_oflag &= ~(OPOST);
opt.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
opt.c_cflag &= ~(CBAUD|CSIZE|PARENB|CRTSCTS);
opt.c_cflag |= BOTHER|CS8|CLOCAL|CSTOPB;
opt.c_ispeed =
opt.c_ospeed = 250000;
ioctl(fd, TCSETS2, &opt);
ioctl(fd, TIOCCBRK, 0);
// Clear RTS to enable the output.
int status;
ioctl(fd, TIOCMGET, &status);
status &= ~TIOCM_RTS;
ioctl(fd, TIOCMSET, &status);
DBGc(2, "Serial port " << s << " open on fd " << fd);
return fd;
}
void Serial::brk(int fd) {
// Drain output buffers before sending break.
ioctl(fd, TCSBRK, (void *)1);
// Time between breaks should be at least 1204µs.
const auto now = Util::micros();
static std::remove_const<decltype(now)>::type last = 0;
if (last && (now - last) < 1204U) {
usleep(1204 - (now - last));
}
last = Util::micros();
// Send a break that is at least 92µs long, and that is followed by a
// MAB (make-after-break) of at least 12µs.
ioctl(fd, TIOCSBRK, 0);
usleep(92);
ioctl(fd, TIOCCBRK, 0);
usleep(12);
}