-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathSerial.cpp
More file actions
142 lines (109 loc) · 3.31 KB
/
Serial.cpp
File metadata and controls
142 lines (109 loc) · 3.31 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
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
/*
* Copyright © 2017 Matt Robinson
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include <cstring>
#include <iostream>
#include <system_error>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include "Serial.h"
Serial::Serial(const std::string& path)
{
fd = open(path.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1)
{
throw std::system_error(errno, std::system_category(), "Unable to open " + path);
}
int flags = fcntl(fd, F_GETFL, 0);
if(flags == -1)
{
throw std::system_error(errno, std::system_category(), "fcntl(F_GETFL) failed for port");
}
// Make calls to read() and write() blocking
flags &= ~O_NONBLOCK;
int ret = fcntl(fd, F_SETFL, flags);
if(ret == -1)
{
throw std::system_error(errno, std::system_category(), "fcntl(F_SETFL) failed for port");
}
struct termios options;
ret = tcgetattr(fd, &options);
if(ret)
{
throw std::system_error(errno, std::system_category(), "tcgetattr() for port failed");
}
// Set the baud rate
cfsetispeed(&options, B9600);
cfsetospeed(&options, B9600);
// Disable parity, 8 data bits, 1 stop-bit (8N1)
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
// Enable the receiver and set local mode
options.c_cflag |= (CLOCAL | CREAD);
// Read in 'raw mode'
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
// Disable input options which could modify the data
options.c_iflag &= ~(BRKINT | INLCR | IGNCR | ICRNL | IXON | IXOFF);
// Disable all processing of the output data
options.c_oflag &= ~(OPOST);
ret = tcsetattr(fd, TCSANOW, &options);
if(ret)
{
throw std::system_error(errno, std::system_category(), "tcsetattr() for port failed");
}
// Set up the pollfd structure ready for poll() in ReadBytes
memset(fds, 0, sizeof(fds));
fds[0].fd = fd;
fds[0].events = POLLIN;
}
Serial::~Serial()
{
int ret = close(fd);
if(ret)
{
std::cerr << "Failed to close port fd";
std::terminate();
}
}
std::vector<uint8_t> Serial::ReadBytes()
{
char readBuffer[256];
std::vector<uint8_t> allRead;
// Wait for up to a second before timing out at first
int pollTimeout = 1000;
do
{
int ret = poll(fds, (sizeof(fds) / sizeof(fds[0])), pollTimeout);
if(ret < 0)
{
throw std::system_error(errno, std::system_category(), "poll() for port data failed");
}
else if(ret == 0)
{
return allRead;
}
ssize_t readCount = read(fd, readBuffer, sizeof(readBuffer));
if(readCount == -1)
{
throw std::system_error(errno, std::system_category(), "read() from port failed");
}
allRead.insert(allRead.end(), readBuffer, readBuffer + readCount);
// As some data has now been read, drop the timeout so we return much
// faster after the last byte is received
pollTimeout = 25;
}
while(true);
}
void Serial::WriteBytes(const std::vector<uint8_t>& bytes)
{
ssize_t written = write(fd, bytes.data(), bytes.size());
if(written == -1)
{
throw std::system_error(errno, std::system_category(), "write() to port failed");
}
}