-
Notifications
You must be signed in to change notification settings - Fork 0
/
Serial.cpp
144 lines (114 loc) · 3.64 KB
/
Serial.cpp
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
//
// Serial.cpp
// testSerial
//
// Created by Ryan Homer on 2021-07-24.
//
#include <fcntl.h>
#include <unistd.h>
#include <algorithm>
#include <iostream>
#include <vector>
#include "Serial.hpp"
#include "Formatter.hpp"
using namespace std;
#define IS_OPEN(fd) ((fd) >= 0)
Serial::Serial(const string &port_,
speed_t baudrate,
bool parity_,
unsigned short stopBits,
unsigned short bitSize)
: port(port_), parity(parity_)
{
setBaudrate(baudrate);
setStopBits(stopBits);
setBitSize(bitSize);
open();
}
void Serial::setBaudrate(speed_t baudrate) {
static const vector<int> baudrates = {
B0, B50, B75, B110, B134, B150, B200, B300, B600, B1200, B1800, B2400, B4800, B9600, B19200, B38400
#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
, B7200, B14400, B28800, B57600, B76800, B115200, B230400
#endif
};
if (binary_search(baudrates.begin(), baudrates.end(), baudrate)) {
_baudrate = baudrate;
return;
}
fprintf(stderr, "Warning: %lu is not a valid baudrate. Using baudrate %lu.\n", baudrate, _baudrate);
}
void Serial::setBitSize(unsigned short bitSize) {
if (bitSize >= 5 && bitSize <= 8) {
_bitSize = bitSize;
}
}
unsigned short Serial::mapBitSizeToMask(unsigned short bitSize) {
switch (bitSize) {
case 5: return CS5;
case 6: return CS6;
case 7: return CS7;
case 8: return CS8;
}
throw invalid_argument("bitSize must be 5, 6, 7 or 8");
}
void Serial::setStopBits(unsigned short stopBits) {
if (stopBits == 1 || stopBits == 2) {
_stopBits = stopBits;
return;
}
throw invalid_argument("stopBits must be 1 or 2");
}
void Serial::updateTty(struct termios& tty)
{
// control modes
updateTtyFlag(tty.c_cflag, PARENB, parity);
updateTtyFlag(tty.c_cflag, CSTOPB, _stopBits == 2);
clearTtyFlagBits(tty.c_cflag, CSIZE);
setTtyFlagBits(tty.c_cflag, mapBitSizeToMask(_bitSize));
clearTtyFlagBits(tty.c_cflag, CRTSCTS);
setTtyFlagBits(tty.c_cflag, CREAD | CLOCAL);
// local modes
clearTtyFlagBits(tty.c_lflag, ICANON | ECHO | ECHOE | ECHONL | ISIG);
// input modes
clearTtyFlagBits(tty.c_iflag, IXON | IXOFF | IXANY | IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL);
// output modes
clearTtyFlagBits(tty.c_oflag, OPOST | ONLCR | OXTABS | ONOEOT);
tty.c_cc[VTIME] = 0;
tty.c_cc[VMIN] = 0;
}
void Serial::open() {
if (IS_OPEN(_fd)) return;
_fd = ::open(port.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK);
if (!IS_OPEN(_fd)) {
throw runtime_error(Formatter("Error opening port (%i): %s\n", errno, strerror(errno)).msg());
}
struct termios tty;
// get current tty settings
if (tcgetattr(_fd, &tty) != 0) {
throw runtime_error(Formatter("Error getting tty settings (%i): %s\n", errno, strerror(errno)).msg());
}
updateTty(tty);
// set baud rate
cfsetispeed(&tty, _baudrate);
cfsetospeed(&tty, _baudrate);
// save tty settings
if (tcsetattr(_fd, TCSANOW, &tty) != 0) {
throw runtime_error(Formatter("Error setting tty settings (%i): %s\n", errno, strerror(errno)).msg());
}
}
void Serial::write(const string& str) {
if (!IS_OPEN(_fd)) throw runtime_error("Error: Port is not open.");
auto buf = str.c_str();
::write(_fd, buf, strlen(buf));
}
const string Serial::read() {
if (!IS_OPEN(_fd)) throw runtime_error("Error: Port is not open.");
size_t len = ::read(_fd, _buf, _bufSz);
return string(_buf, len);
}
void Serial::close() {
if (IS_OPEN(_fd)) {
::close(_fd);
}
}