RflySimSDK v3.05
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 ssize_t messageLength = ::read(serial->fd, &tempBuffer, BUFFER_SIZE_RFLY);
154 if (messageLength > 0)
155 {
156 tempBuffer[messageLength] = '\0';
157 if(serial->onRawMessageReceived){
158 serial->onRawMessageReceived(tempBuffer,bytesRead);
159 }
160 }else{
161 sleep(0.002);
162 }
163 #endif
164 }
165
166 }
167
168 // Reads a byte from the serial port.
169 // @return: The byte read, or std::nullopt if no data is available.
170 bool read(uint8_t &byte);
171
172 // Writes a byte to the serial port.
173 // @param data: The byte to write to the port.
174 // @return: true if the data was written successfully, false otherwise.
175 bool write(const uint8_t byte);
176
177 std::string portName; // The name of the serial port.
178 size_t baudRate; // The baud rate at which the communications device operates.
179 std::mutex mutex; // The mutex used to synchronize access to the serial port.
180
181#ifdef _WIN32
182 HANDLE hSerial; // The handle to the serial port (Windows only).
183#else
184 int fd; // The file descriptor for the serial port (non-Windows only).
185#endif
186};
187
188
189SerialCPP::SerialCPP()
190{
191#ifdef _WIN32
192 hSerial = INVALID_HANDLE_VALUE;
193#else
194 fd = -1;
195#endif
196}
197
198
199
200SerialCPP::~SerialCPP()
201{
202 close();
203}
204
205bool SerialCPP::open(const std::string &port, size_t baud)
206{
207 portName=port;
208 baudRate=baud;
209
210 // Lock the mutex to prevent multiple threads from accessing the serial port at the same time.
211 std::lock_guard<std::mutex> lock(mutex);
212
213#ifdef _WIN32
214 hSerial = CreateFile(portName.c_str(), GENERIC_READ | GENERIC_WRITE, NULL, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
215 if (hSerial == INVALID_HANDLE_VALUE)
216 {
217 return false;
218 }
219 else
220 {
221 DCB dcbSerialParameters = {0};
222
223 if (!GetCommState(hSerial, &dcbSerialParameters))
224 {
225 return false;
226 }
227 else
228 {
229 dcbSerialParameters.BaudRate = (DWORD)baudRate;
230 dcbSerialParameters.ByteSize = 8;
231 dcbSerialParameters.StopBits = ONESTOPBIT;
232 dcbSerialParameters.Parity = NOPARITY;
233 dcbSerialParameters.fDtrControl = DTR_CONTROL_ENABLE;
234
235 if (!SetCommState(hSerial, &dcbSerialParameters))
236 {
237 return false;
238 }
239 else
240 {
241 // Set The Read Timeouts To Make ReadFile Non-Blocking
242 COMMTIMEOUTS timeouts = {0};
243 timeouts.ReadIntervalTimeout = MAXDWORD;
244 timeouts.ReadTotalTimeoutConstant = 0;
245 timeouts.ReadTotalTimeoutMultiplier = 0;
246 if (!SetCommTimeouts(hSerial, &timeouts))
247 {
248 return false;
249 }
250 }
251 }
252 }
253#else
254 fd = ::open(portName.c_str(), O_RDWR | O_NOCTTY /* | O_NONBLOCK*/);
255 if (fd < 0)
256 {
257 return false;
258 }
259
260 struct termios tty;
261 memset(&tty, 0, sizeof(tty));
262
263 if (tcgetattr(fd, &tty) != 0)
264 {
265 return false;
266 }
267
268 speed_t speed;
269 switch (baudRate)
270 {
271 case 4800:
272 speed = B4800;
273 break;
274 case 9600:
275 speed = B9600;
276 break;
277 case 19200:
278 speed = B19200;
279 break;
280 case 38400:
281 speed = B38400;
282 break;
283 case 57600:
284 speed = B57600;
285 break;
286 case 115200:
287 speed = B115200;
288 break;
289 case 230400:
290 speed = B230400;
291 break;
292 case 460800:
293 speed = B460800;
294 break;
295 case 921600:
296 speed = B921600;
297 break;
298 default:
299 return false; // Unsupported baud rate
300 }
301
302 tty.c_cflag &= ~PARENB; // Clear parity bit, disabling parity (most common)
303 tty.c_cflag &= ~CSTOPB; // Clear stop field, only one stop bit used in communication (most common)
304 tty.c_cflag |= CS8; // 8 bits per byte (most common)
305 tty.c_cflag &= ~CRTSCTS; // Disable RTS/CTS hardware flow control (most common)
306 tty.c_cflag |= CREAD | CLOCAL; // Turn on READ & ignore ctrl lines (CLOCAL = 1)
307
308 tty.c_lflag &= ~ICANON;
309 tty.c_lflag &= ~ECHO; // Disable echo
310 tty.c_lflag &= ~ECHOE; // Disable erasure
311 tty.c_lflag &= ~ECHONL; // Disable new-line echo
312 tty.c_lflag &= ~ISIG; // Disable interpretation of INTR, QUIT and SUSP
313
314 tty.c_iflag &= ~(IXON | IXOFF | IXANY); // Turn off s/w flow ctrl
315 tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL); // Disable any special handling of received bytes
316
317 tty.c_oflag &= ~OPOST; // Prevent special interpretation of output bytes (e.g. newline chars)
318 tty.c_oflag &= ~ONLCR; // Prevent conversion of newline to carriage return/line feed
319
320 // Set in/out baud rate to be speed
321 cfsetispeed(&tty, speed);
322 cfsetospeed(&tty, speed);
323
324 // Save tty settings, also checking for error
325 if (tcsetattr(fd, TCSANOW, &tty) != 0)
326 {
327 return false;
328 }
329#endif
330
331 return true;
332}
333
334void SerialCPP::StartRecvThread(){
335 std::thread t(ReceiveThread, this); // usage with Connect()
336 t.detach();
337}
338
339bool SerialCPP::close()
340{
341 // Lock the mutex to prevent multiple threads from accessing the serial port at the same time.
342 std::lock_guard<std::mutex> lock(mutex);
343
344#ifdef _WIN32
345 if (hSerial != INVALID_HANDLE_VALUE)
346 {
347 if (!CloseHandle(hSerial))
348 {
349 return false;
350 }
351 hSerial = INVALID_HANDLE_VALUE;
352 }
353#else
354 if (fd >= 0)
355 {
356 if (::close(fd) == -1)
357 {
358 return false;
359 }
360 fd = -1;
361 }
362#endif
363
364 return true;
365}
366
367bool SerialCPP::write(uint8_t byte)
368{
369#ifdef _WIN32
370 DWORD bytesWritten;
371 if (!WriteFile(hSerial, &byte, 1, &bytesWritten, NULL))
372 {
373 return false;
374 }
375#else
376 ssize_t result = ::write(fd, &byte, 1);
377 if (result == -1)
378 {
379 return false;
380 }
381#endif
382 return true;
383}
384
385bool SerialCPP::writeBytes(const std::vector<uint8_t> &data)
386{
387 // Lock the mutex to prevent multiple threads from accessing the serial port at the same time.
388 std::lock_guard<std::mutex> lock(mutex);
389
390 for (const uint8_t &byte : data)
391 {
392 if (!write(byte))
393 {
394 return false;
395 }
396 }
397 return true;
398}
399
400bool SerialCPP::writeLine(const std::string &data)
401{
402 // Lock the mutex to prevent multiple threads from accessing the serial port at the same time.
403 std::lock_guard<std::mutex> lock(mutex);
404
405 // Convert string to a byte array
406 std::vector<uint8_t> byteData(data.begin(), data.end());
407
408 // Append newline character
409 byteData.push_back('\n');
410
411 // Write the byte array using the write method
412 for (size_t i = 0; i < byteData.size(); ++i)
413 {
414 if (!write(byteData.data()[i]))
415 {
416 return false;
417 }
418 }
419 return true;
420}
421
422bool SerialCPP::read(uint8_t &byteR)
423{
424 uint8_t byte;
425#ifdef _WIN32
426 DWORD bytesRead;
427 if (!ReadFile(hSerial, &byte, 1, &bytesRead, NULL) || bytesRead == 0)
428 {
429 return false;
430 }
431#else
432 ssize_t result = ::read(fd, &byte, 1);
433 if (result <= 0)
434 {
435 return false;
436 }
437#endif
438 byteR = byte;
439 return true;
440}
441
442std::vector<uint8_t> SerialCPP::readBytes(size_t n)
443{
444 // Lock the mutex to prevent multiple threads from accessing the serial port at the same time.
445 std::lock_guard<std::mutex> lock(mutex);
446
447 std::vector<uint8_t> buffer;
448 uint8_t byte;
449 for (size_t i = 0; i < n && read(byte); ++i)
450 {
451 buffer.push_back(byte);
452 }
453 return buffer;
454}
455
456std::string SerialCPP::readLine()
457{
458 std::lock_guard<std::mutex> lock(mutex);
459
460 std::string line;
461 uint8_t byte;
462 while (read(byte) && byte != '\n')
463 {
464 line += static_cast<char>(byte);
465 }
466
467 // Remove Potential Trailing Newline & Carriage Return Characters
468 line.erase(std::remove(line.begin(), line.end(), '\n'), line.end());
469 line.erase(std::remove(line.begin(), line.end(), '\r'), line.end());
470
471 return line;
472}
473
474bool SerialCPP::isDeviceConnected()
475{
476#ifdef _WIN32
477 if (hSerial == INVALID_HANDLE_VALUE)
478 {
479 close();
480 return false;
481 }
482 else
483 {
484 DWORD errors;
485 COMSTAT status;
486 ClearCommError(hSerial, &errors, &status);
487 return errors == 0;
488 }
489#else
490 if (fd < 0)
491 {
492 close();
493 return false;
494 }
495 else
496 {
497 int mcs = 0;
498 if (ioctl(fd, TIOCMGET, &mcs) < 0)
499 {
500 close();
501 return false;
502 }
503 return true;
504 }
505#endif
506}
定义 rfly_serial.h:27