-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSerialPort.cpp
More file actions
237 lines (197 loc) · 4.93 KB
/
Copy pathSerialPort.cpp
File metadata and controls
237 lines (197 loc) · 4.93 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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
#include "SerialPort.h"
#include <fcntl.h>
#include <sys/select.h>
#include <termios.h>
#include <unistd.h>
#include <cstring>
#include <iostream>
#include <sstream>
SerialPort::SerialPort() : m_fd(-1) {
}
SerialPort::~SerialPort() {
close();
}
bool SerialPort::open(const std::string& portName, int baudRate) {
// 如果已经打开,先关闭
if (m_fd >= 0) {
close();
}
m_portName = portName;
// 以读写方式打开串口,不占用控制终端,非阻塞模式
m_fd = ::open(portName.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
if (m_fd < 0) {
m_errorMsg = "打开串口失败: " + std::string(strerror(errno));
return false;
}
// 设置串口参数
if (!configurePort(baudRate)) {
::close(m_fd);
m_fd = -1;
return false;
}
return true;
}
void SerialPort::close() {
if (m_fd >= 0) {
::close(m_fd);
m_fd = -1;
}
}
bool SerialPort::configurePort(int baudRate) {
struct termios options;
// 获取当前串口属性
if (tcgetattr(m_fd, &options) != 0) {
m_errorMsg = "获取串口属性失败: " + std::string(strerror(errno));
return false;
}
// 设置波特率
speed_t speed = getBaudRateConstant(baudRate);
if (speed == B0) {
m_errorMsg = "不支持的波特率: " + std::to_string(baudRate);
return false;
}
cfsetispeed(&options, speed);
cfsetospeed(&options, speed);
// 控制模式标志
options.c_cflag |= (CLOCAL | CREAD); // 启用接收器,忽略调制解调器控制线
options.c_cflag &= ~CSIZE; // 清除数据位设置
options.c_cflag |= CS8; // 8位数据位
options.c_cflag &= ~PARENB; // 无校验位
options.c_cflag &= ~CSTOPB; // 1位停止位
options.c_cflag &= ~CRTSCTS; // 禁用硬件流控制
// 本地模式标志
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // 原始输入模式
// 输入模式标志
options.c_iflag &= ~(IXON | IXOFF | IXANY); // 禁用软件流控制
options.c_iflag &= ~(INLCR | ICRNL | IGNCR); // 禁用换行符转换
// 输出模式标志
options.c_oflag &= ~OPOST; // 原始输出模式
// 设置读取超时
options.c_cc[VMIN] = 0; // 非阻塞模式,read立即返回
options.c_cc[VTIME] = 1; // 超时时间 100ms (单位:分秒)
// 清空缓冲区
tcflush(m_fd, TCIOFLUSH);
// 应用设置
if (tcsetattr(m_fd, TCSANOW, &options) != 0) {
m_errorMsg = "设置串口属性失败: " + std::string(strerror(errno));
return false;
}
return true;
}
speed_t SerialPort::getBaudRateConstant(int baudRate) {
switch (baudRate) {
case 9600:
return B9600;
case 19200:
return B19200;
case 38400:
return B38400;
case 57600:
return B57600;
case 115200:
return B115200;
case 230400:
return B230400;
case 460800:
return B460800;
case 500000:
return B500000;
case 576000:
return B576000;
case 921600:
return B921600;
case 1000000:
return B1000000;
case 1152000:
return B1152000;
case 1500000:
return B1500000;
case 2000000:
return B2000000;
case 2500000:
return B2500000;
case 3000000:
return B3000000;
case 3500000:
return B3500000;
case 4000000:
return B4000000;
default:
return B0; // 无效波特率
}
}
int SerialPort::write(const uint8_t* data, int length) {
if (m_fd < 0) {
m_errorMsg = "串口未打开";
return -1;
}
int bytesWritten = ::write(m_fd, data, length);
if (bytesWritten < 0) {
m_errorMsg = "写入失败: " + std::string(strerror(errno));
return -1;
}
// 确保数据完全发送
tcdrain(m_fd);
return bytesWritten;
}
int SerialPort::writeString(const std::string& str, bool addNewline) {
std::string toSend = str;
if (addNewline) {
toSend += "\n";
}
return write(reinterpret_cast<const uint8_t*>(toSend.c_str()), toSend.length());
}
int SerialPort::read(uint8_t* buffer, int maxLength, int timeoutMs) {
if (m_fd < 0) {
m_errorMsg = "串口未打开";
return -1;
}
fd_set readSet;
struct timeval timeout;
FD_ZERO(&readSet);
FD_SET(m_fd, &readSet);
timeout.tv_sec = timeoutMs / 1000;
timeout.tv_usec = (timeoutMs % 1000) * 1000;
// 等待数据可读
int selectResult = select(m_fd + 1, &readSet, NULL, NULL, (timeoutMs >= 0) ? &timeout : NULL);
if (selectResult < 0) {
m_errorMsg = "select错误: " + std::string(strerror(errno));
return -1;
} else if (selectResult == 0) {
// 超时,没有数据
return 0;
}
// 读取数据
int bytesRead = ::read(m_fd, buffer, maxLength);
if (bytesRead < 0) {
m_errorMsg = "读取失败: " + std::string(strerror(errno));
return -1;
}
return bytesRead;
}
std::string SerialPort::readLine(int timeoutMs) {
std::string line;
uint8_t ch;
while (true) {
int bytesRead = read(&ch, 1, timeoutMs);
if (bytesRead == 1) {
if (ch == '\n') {
break; // 遇到换行符结束
} else if (ch != '\r') {
line += static_cast<char>(ch); // 忽略回车符
}
} else if (bytesRead == 0) {
// 超时,返回已读取的部分
break;
} else {
// 错误
break;
}
}
return line;
}
void SerialPort::flush() {
if (m_fd >= 0) {
tcflush(m_fd, TCIOFLUSH);
}
}