RflySimSDK v3.08
RflySimSDK说明文档
载入中...
搜索中...
未找到
rfly_serial.h
1#pragma once
2
3#include <algorithm>
4#include <cstdint>
5#include <vector>
6#include <string>
7#include <mutex>
8#include <thread>
9#ifdef _WIN32
10#include <windows.h>
11#else
12#include <termios.h>
13#include <unistd.h>
14#include <fcntl.h>
15#include <cstring>
16#include <sys/ioctl.h>
17#endif
18
19#ifndef BUFFER_SIZE_RFLY
20#define BUFFER_SIZE_RFLY 65500
21#endif
22
23#include <functional>
24
25
27{
28public:
29
30 // function for calling program
31 std::function<void(const char*, size_t)> onRawMessageReceived;
32
33 // Constructor: Initializes a new instance of the SerialCPP class.
34 SerialCPP();
35
36 // Destructor: Closes the serial port if it is open.
37 ~SerialCPP();
38
39 // Opens the serial port for communication.
40 // @param port: The name of the serial port to connect to.
41 // @param baudRate: The baud rate at which the communications device operates.
42 // @return: true if the port was opened successfully, false otherwise.
43 bool open(const std::string &port, size_t baud = 115200);
44
45 // Closes the serial port.
46 // @return: true if the port was closed successfully, false otherwise.
47 bool close();
48
49 // Writes data to the serial port.
50 // @param data: The data to write to the port.
51 // @return: true if the data was written successfully, false otherwise.
52 bool writeBytes(const std::vector<uint8_t> &data);
53
54 // Writes a string to the serial port, followed by a newline character.
55 // @param data: The string to write to the port.
56 // @return: true if the string was written successfully, false otherwise.
57 bool writeLine(const std::string &data);
58
59 // Reads data from the serial port.
60 // @param n: The maximum number of bytes to try and read.
61 // @return: A vector containing the actual bytes read.
62 std::vector<uint8_t> readBytes(size_t n);
63
64 // Reads a line of text from the serial port.
65 // @return: The line of text read from the port, or an empty string if no data is available.
66 std::string readLine();
67
68 void StartRecvThread();
69
70 // Returns True if the serial port is open, False otherwise.
71 // @return: True if the serial port is open, False otherwise.
72 bool isDeviceConnected();
73
74 int RecvNoblock(char * buf, int maxrecvlen=BUFFER_SIZE_RFLY){
75 int readFlag=0;
76
77 #ifdef _WIN32
78 DWORD bytesRead;
79 if (ReadFile(hSerial, buf, maxrecvlen, &bytesRead, NULL) && bytesRead > 0)
80 {
81 buf[bytesRead]='\0';
82 readFlag=bytesRead;
83 }else{
84 buf[0]='\0';
85 readFlag=-1;
86 }
87 #else
88 ssize_t messageLength = ::read(fd, buf, maxrecvlen);
89 if (messageLength > 0) // 如果成功读到数据
90 {
91 buf[messageLength]='\0';
92 readFlag=messageLength;
93 }else{
94 buf[0]='\0';
95 readFlag=-1;
96 }
97 #endif
98
99 return readFlag;
100 }
101
102
103 int SendTo(const char* bytes, size_t byteslength){
104 // Lock the mutex to prevent multiple threads from accessing the serial port at the same time.
105 std::lock_guard<std::mutex> lock(mutex);
106
107#ifdef _WIN32
108 DWORD bytesWritten;
109 if (!WriteFile(hSerial, bytes, (DWORD)byteslength, &bytesWritten, NULL))
110 {
111 return -1;
112 }else{
113 return (int)byteslength;
114 }
115#else
116 ssize_t result = ::write(fd, bytes, byteslength);
117 if (result == -1)
118 {
119 return -1;
120 }else{
121 return (int)result;
122 }
123#endif
124
125 }
126
127 // Overload of the bool operator.
128 operator bool()
129 {
130 return isDeviceConnected();
131 }
132
133
134
135private:
136
137 static void ReceiveThread(SerialCPP *serial){
138 char tempBuffer[BUFFER_SIZE_RFLY+1];
139 while (true){
140 #ifdef _WIN32
141 DWORD bytesRead;
142 if (ReadFile(serial->hSerial, &tempBuffer, BUFFER_SIZE_RFLY, &bytesRead, NULL) && bytesRead > 0)
143 {
144 tempBuffer[bytesRead] = '\0';
145 if(serial->onRawMessageReceived)
146 {
147 serial->onRawMessageReceived(tempBuffer,bytesRead);
148 }
149 }else{
150 Sleep(2);
151 }
152 #else
153 size_t bytesRead;
154 ssize_t messageLength = ::read(serial->fd, &tempBuffer, BUFFER_SIZE_RFLY);
155 if (messageLength > 0)
156 {
157 tempBuffer[messageLength] = '\0';
158 if(serial->onRawMessageReceived){
159 serial->onRawMessageReceived(tempBuffer,bytesRead);
160 }
161 }else{
162 sleep(0.002);
163 }
164 #endif
165 }
166
167 }
168
169 // Reads a byte from the serial port.
170 // @return: The byte read, or std::nullopt if no data is available.
171 bool read(uint8_t &byte);
172
173 // Writes a byte to the serial port.
174 // @param data: The byte to write to the port.
175 // @return: true if the data was written successfully, false otherwise.
176 bool write(const uint8_t byte);
177
178 std::string portName; // The name of the serial port.
179 size_t baudRate; // The baud rate at which the communications device operates.
180 std::mutex mutex; // The mutex used to synchronize access to the serial port.
181
182#ifdef _WIN32
183 HANDLE hSerial; // The handle to the serial port (Windows only).
184#else
185 int fd; // The file descriptor for the serial port (non-Windows only).
186#endif
187};
188
189
190SerialCPP::SerialCPP()
191{
192#ifdef _WIN32
193 hSerial = INVALID_HANDLE_VALUE;
194#else
195 fd = -1;
196#endif
197}
198
199
200
201SerialCPP::~SerialCPP()
202{
203 close();
204}
205
206bool SerialCPP::open(const std::string &port, size_t baud)
207{
208 portName=port;
209 baudRate=baud;
210
211 // Lock the mutex to prevent multiple threads from accessing the serial port at the same time.
212 std::lock_guard<std::mutex> lock(mutex);
213
214#ifdef _WIN32
215 hSerial = CreateFile(portName.c_str(), GENERIC_READ | GENERIC_WRITE, NULL, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
216 if (hSerial == INVALID_HANDLE_VALUE)
217 {
218 return false;
219 }
220 else
221 {
222 DCB dcbSerialParameters = {0};
223
224 if (!GetCommState(hSerial, &dcbSerialParameters))
225 {
226 return false;
227 }
228 else
229 {
230 dcbSerialParameters.BaudRate = (DWORD)baudRate;
231 dcbSerialParameters.ByteSize = 8;
232 dcbSerialParameters.StopBits = ONESTOPBIT;
233 dcbSerialParameters.Parity = NOPARITY;
234 dcbSerialParameters.fDtrControl = DTR_CONTROL_ENABLE;
235
236 if (!SetCommState(hSerial, &dcbSerialParameters))
237 {
238 return false;
239 }
240 else
241 {
242 // Set The Read Timeouts To Make ReadFile Non-Blocking
243 COMMTIMEOUTS timeouts = {0};
244 timeouts.ReadIntervalTimeout = MAXDWORD;
245 timeouts.ReadTotalTimeoutConstant = 0;
246 timeouts.ReadTotalTimeoutMultiplier = 0;
247 if (!SetCommTimeouts(hSerial, &timeouts))
248 {
249 return false;
250 }
251 }
252 }
253 }
254#else
255 fd = ::open(portName.c_str(), O_RDWR | O_NOCTTY /* | O_NONBLOCK*/);
256 if (fd < 0)
257 {
258 return false;
259 }
260
261 struct termios tty;
262 memset(&tty, 0, sizeof(tty));
263
264 if (tcgetattr(fd, &tty) != 0)
265 {
266 return false;
267 }
268
269 speed_t speed;
270 switch (baudRate)
271 {
272 case 4800:
273 speed = B4800;
274 break;
275 case 9600:
276 speed = B9600;
277 break;
278 case 19200:
279 speed = B19200;
280 break;
281 case 38400:
282 speed = B38400;
283 break;
284 case 57600:
285 speed = B57600;
286 break;
287 case 115200:
288 speed = B115200;
289 break;
290 case 230400:
291 speed = B230400;
292 break;
293 case 460800:
294 speed = B460800;
295 break;
296 case 921600:
297 speed = B921600;
298 break;
299 default:
300 return false; // Unsupported baud rate
301 }
302
303 tty.c_cflag &= ~PARENB; // Clear parity bit, disabling parity (most common)
304 tty.c_cflag &= ~CSTOPB; // Clear stop field, only one stop bit used in communication (most common)
305 tty.c_cflag |= CS8; // 8 bits per byte (most common)
306 tty.c_cflag &= ~CRTSCTS; // Disable RTS/CTS hardware flow control (most common)
307 tty.c_cflag |= CREAD | CLOCAL; // Turn on READ & ignore ctrl lines (CLOCAL = 1)
308
309 tty.c_lflag &= ~ICANON;
310 tty.c_lflag &= ~ECHO; // Disable echo
311 tty.c_lflag &= ~ECHOE; // Disable erasure
312 tty.c_lflag &= ~ECHONL; // Disable new-line echo
313 tty.c_lflag &= ~ISIG; // Disable interpretation of INTR, QUIT and SUSP
314
315 tty.c_iflag &= ~(IXON | IXOFF | IXANY); // Turn off s/w flow ctrl
316 tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL); // Disable any special handling of received bytes
317
318 tty.c_oflag &= ~OPOST; // Prevent special interpretation of output bytes (e.g. newline chars)
319 tty.c_oflag &= ~ONLCR; // Prevent conversion of newline to carriage return/line feed
320
321 // Set in/out baud rate to be speed
322 cfsetispeed(&tty, speed);
323 cfsetospeed(&tty, speed);
324
325 // Save tty settings, also checking for error
326 if (tcsetattr(fd, TCSANOW, &tty) != 0)
327 {
328 return false;
329 }
330#endif
331
332 return true;
333}
334
335void SerialCPP::StartRecvThread(){
336 std::thread t(ReceiveThread, this); // usage with Connect()
337 t.detach();
338}
339
340bool SerialCPP::close()
341{
342 // Lock the mutex to prevent multiple threads from accessing the serial port at the same time.
343 std::lock_guard<std::mutex> lock(mutex);
344
345#ifdef _WIN32
346 if (hSerial != INVALID_HANDLE_VALUE)
347 {
348 if (!CloseHandle(hSerial))
349 {
350 return false;
351 }
352 hSerial = INVALID_HANDLE_VALUE;
353 }
354#else
355 if (fd >= 0)
356 {
357 if (::close(fd) == -1)
358 {
359 return false;
360 }
361 fd = -1;
362 }
363#endif
364
365 return true;
366}
367
368bool SerialCPP::write(uint8_t byte)
369{
370#ifdef _WIN32
371 DWORD bytesWritten;
372 if (!WriteFile(hSerial, &byte, 1, &bytesWritten, NULL))
373 {
374 return false;
375 }
376#else
377 ssize_t result = ::write(fd, &byte, 1);
378 if (result == -1)
379 {
380 return false;
381 }
382#endif
383 return true;
384}
385
386bool SerialCPP::writeBytes(const std::vector<uint8_t> &data)
387{
388 // Lock the mutex to prevent multiple threads from accessing the serial port at the same time.
389 std::lock_guard<std::mutex> lock(mutex);
390
391 for (const uint8_t &byte : data)
392 {
393 if (!write(byte))
394 {
395 return false;
396 }
397 }
398 return true;
399}
400
401bool SerialCPP::writeLine(const std::string &data)
402{
403 // Lock the mutex to prevent multiple threads from accessing the serial port at the same time.
404 std::lock_guard<std::mutex> lock(mutex);
405
406 // Convert string to a byte array
407 std::vector<uint8_t> byteData(data.begin(), data.end());
408
409 // Append newline character
410 byteData.push_back('\n');
411
412 // Write the byte array using the write method
413 for (size_t i = 0; i < byteData.size(); ++i)
414 {
415 if (!write(byteData.data()[i]))
416 {
417 return false;
418 }
419 }
420 return true;
421}
422
423bool SerialCPP::read(uint8_t &byteR)
424{
425 uint8_t byte;
426#ifdef _WIN32
427 DWORD bytesRead;
428 if (!ReadFile(hSerial, &byte, 1, &bytesRead, NULL) || bytesRead == 0)
429 {
430 return false;
431 }
432#else
433 ssize_t result = ::read(fd, &byte, 1);
434 if (result <= 0)
435 {
436 return false;
437 }
438#endif
439 byteR = byte;
440 return true;
441}
442
443std::vector<uint8_t> SerialCPP::readBytes(size_t n)
444{
445 // Lock the mutex to prevent multiple threads from accessing the serial port at the same time.
446 std::lock_guard<std::mutex> lock(mutex);
447
448 std::vector<uint8_t> buffer;
449 uint8_t byte;
450 for (size_t i = 0; i < n && read(byte); ++i)
451 {
452 buffer.push_back(byte);
453 }
454 return buffer;
455}
456
457std::string SerialCPP::readLine()
458{
459 std::lock_guard<std::mutex> lock(mutex);
460
461 std::string line;
462 uint8_t byte;
463 while (read(byte) && byte != '\n')
464 {
465 line += static_cast<char>(byte);
466 }
467
468 // Remove Potential Trailing Newline & Carriage Return Characters
469 line.erase(std::remove(line.begin(), line.end(), '\n'), line.end());
470 line.erase(std::remove(line.begin(), line.end(), '\r'), line.end());
471
472 return line;
473}
474
475bool SerialCPP::isDeviceConnected()
476{
477#ifdef _WIN32
478 if (hSerial == INVALID_HANDLE_VALUE)
479 {
480 close();
481 return false;
482 }
483 else
484 {
485 DWORD errors;
486 COMSTAT status;
487 ClearCommError(hSerial, &errors, &status);
488 return errors == 0;
489 }
490#else
491 if (fd < 0)
492 {
493 close();
494 return false;
495 }
496 else
497 {
498 int mcs = 0;
499 if (ioctl(fd, TIOCMGET, &mcs) < 0)
500 {
501 close();
502 return false;
503 }
504 return true;
505 }
506#endif
507}
定义 rfly_serial.h:27