Initial commit

This commit is contained in:
2026-06-16 10:56:40 +08:00
commit d2f95e0e27
2047 changed files with 619063 additions and 0 deletions
+541
View File
@@ -0,0 +1,541 @@
#ifdef WIN32
#include "../Base/global_include.h"
#include "Serial_p.h"
namespace Psc::serial {
void reset(Serial_Settings& serial_info) {
// 清空整个结构体
ZeroMemory(&serial_info, sizeof(DCB));
serial_info.DCBlength = sizeof(DCB);
// 设置默认参数(你可以根据需要修改)
serial_info.BaudRate = CBR_9600; // 默认波特率
serial_info.ByteSize = 8; // 8位数据位
serial_info.Parity = NOPARITY; // 无校验
serial_info.StopBits = ONESTOPBIT; // 1位停止位
serial_info.fBinary = TRUE; // 必须设为 TRUE
serial_info.fDtrControl = DTR_CONTROL_ENABLE;
serial_info.fRtsControl = RTS_CONTROL_ENABLE;
}
void set_buffer_byte_size(HANDLE fd, int byte_size) {
if (fd == INVALID_HANDLE_VALUE) {
LOG_ERROR(VAR_STR_2(fd, byte_size) + "Invalid serial handle!")
}
// 设置输入缓冲区和输出缓冲区的大小
if (!SetupComm(fd, byte_size, byte_size)) {
LOG_ERROR(VAR_STR_2(fd, byte_size) + "Failed to set buffer size!")
}
// 清空缓冲区,防止遗留数据干扰
if (!PurgeComm(fd, PURGE_RXCLEAR | PURGE_TXCLEAR)) {
LOG_ERROR(VAR_STR_2(fd, byte_size) + "Failed to purge buffers!")
}
}
int get_buffer_byte_size(HANDLE fd) {
COMMPROP commProp = {0};
if (GetCommProperties(fd, &commProp)) {
return commProp.dwCurrentRxQueue; // 或者返回 commProp.dwCurrentTxQueue
} else {
LOG_ERROR(VAR_STR_1(fd) + "Failed to get serial port properties.")
}
return 0;
}
void set_binary_mode(Serial_Settings& serial_info) {
//windows下默认就是
}
HANDLE open(const std::string& port_name) {
HANDLE hSerial = CreateFile(("\\\\.\\" + port_name).c_str(),
GENERIC_READ | GENERIC_WRITE,
0, // No sharing
NULL, // Default security attributes
OPEN_EXISTING, // Open the existing port
0, // 0 : No overlapped I/O FILE_FLAG_OVERLAPPED是异步
NULL); // No template file
if (hSerial == INVALID_HANDLE_VALUE) {
LOG_ERROR(VAR_STR_1(port_name))
Psc::fail_fast();
return INVALID_HANDLE_VALUE;
}
return hSerial;
}
//typedef struct _COMMTIMEOUTS {
// DWORD ReadIntervalTimeout; // 读间隔超时
// DWORD ReadTotalTimeoutMultiplier; // 读时间系数
// DWORD ReadTotalTimeoutConstant; // 读时间常量
// DWORD WriteTotalTimeoutMultiplier; // 写时间系数
// DWORD WriteTotalTimeoutConstant; // 写时间常量
//} COMMTIMEOUTS,*LPCOMMTIMEOUTS;
// 有两种超时:间隔超时和总超时。间隔超时是指在接收时两个字符之间的最大时延,总超时是指读写操作总共花费的最大时间。
// 写操作只支持总超时,而读操作两种超时均支持。
// 用COMMTIMEOUTS结构可以规定读/写操作的超时,该结构的定义为: COMMTIMEOUTS结构的成员都以毫秒为单位。总超时的计算公式是:
// 总超时=时间系数×要求读/写的字符数 + 时间常量// 
// 例如,如果要读入10个字符,那么读操作的总超时的计算公式为:
// 读总超时=ReadTotalTimeoutMultiplier×10 + ReadTotalTimeoutConstant
// 如果所有写超时参数均为0,那么就不使用写超时。如果ReadIntervalTimeout为0,那么就不使用读间隔超时,如果 ReadTotalTimeoutMultiplier和ReadTotalTimeoutConstant都为0
// 则不使用读总超时。
// 如果读间隔超时被设置成MAXDWORD并且两个读总超时为0,那么在读一次输入缓冲区中的内容后读操作就立即完成,而不管是否读入了要求的字符。
// 在用重叠方式读写串行口时,虽然ReadFile和WriteFile在完成操作以前就可能返回,但超时仍然是起作用的。在这种情况下,超时规定的是操作的完成时间,而不是ReadFile和WriteFile的返回时间。
void set_block(HANDLE fd, bool block) {
// 获取当前串口的超时设置
COMMTIMEOUTS timeouts = {0};
if (!GetCommTimeouts(fd, &timeouts)) {
LOG_ERROR(VAR_STR_2(fd, block))
return;
}
// 根据 block 参数设置不同的超时行为
if (block) {
// 阻塞模式:没有超时
timeouts.ReadIntervalTimeout = 0;
timeouts.ReadTotalTimeoutConstant = 0;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.WriteTotalTimeoutConstant = 0;
timeouts.WriteTotalTimeoutMultiplier = 0;
} else {
// 非阻塞模式:设置适当的超时(例如 50 毫秒)
// timeouts.ReadIntervalTimeout = 50;
// timeouts.ReadTotalTimeoutConstant = 50;
// timeouts.ReadTotalTimeoutMultiplier = 10;
timeouts.WriteTotalTimeoutConstant = 50;
timeouts.WriteTotalTimeoutMultiplier = 10;
timeouts.ReadIntervalTimeout = MAXDWORD;
timeouts.ReadTotalTimeoutConstant = 0;
timeouts.ReadTotalTimeoutMultiplier = 0;
}
// 设置新的超时参数
if (!SetCommTimeouts(fd, &timeouts)) {
LOG_ERROR("")
}
}
void close(Serial_FD fd) {
if (fd != INVALID_HANDLE_VALUE) {
if (CloseHandle(fd)) {
if (serial_logger) serial_logger->debug("", {}, VAR_STR_1(fd) + " Serial port closed successfully.");
} else {
LOG_ERROR(VAR_STR_1(fd) + " Failed to close the serial port.")
}
} else {
LOG_ERROR(VAR_STR_1(fd))
}
}
DCB get_serial_info(HANDLE fd) {
DCB dcbSerialParams = {0}; // 初始化 DCB 结构
// 获取串口的当前状态
if (!GetCommState(fd, &dcbSerialParams)) {
LOG_ERROR(VAR_STR_1(fd))
// 如果获取失败,可以返回一个默认的 DCB 结构(全为零)
return dcbSerialParams;
}
// 成功获取配置后返回 DCB 结构
return dcbSerialParams;
}
void set_serial_info(HANDLE fd, DCB serial_info) {
// 设置串口配置
if (!SetCommState(fd, &serial_info)) {
// 如果设置失败,输出错误信息
LOG_ERROR(VAR_STR_1(fd))
}
}
int get_written_bytes(Serial_FD fd) {
COMSTAT comStat;
DWORD dwErrors;
// 获取串口通信状态
if (!ClearCommError(fd, &dwErrors, &comStat)) {
fprintf(stderr, "ClearCommError failed: %ld\n", GetLastError());
return -1;
}
// 返回发送缓冲区中的字节数
return comStat.cbOutQue;
}
int get_available_bytes(HANDLE fd) {
COMSTAT comStat;
DWORD dwErrors;
// 使用 ClearCommError 获取串口状态和接收队列中的字节数
if (!ClearCommError(fd, &dwErrors, &comStat)) {
LOG_ERROR(VAR_STR_1(fd))
return -1; // 出现错误时返回 -1
}
// 返回接收队列中的字节数
return comStat.cbInQue;
}
int64_t read_data(HANDLE fd, char* data, int64_t maxSize) {
DWORD bytesRead = 0;
if (!ReadFile(fd, data, maxSize, &bytesRead, NULL)) {
return -1;
}
return bytesRead;
}
// int64_t read_data(Serial_FD fd, char* data, int64_t maxSize) {
// OVERLAPPED overlapped = {};
// DWORD bytesRead = 0;
// if (ReadFile(fd, data, maxSize, &bytesRead, &overlapped) || GetLastError() == ERROR_IO_PENDING) {
// if (GetOverlappedResult(fd, &overlapped, &bytesRead, TRUE)) {
// return bytesRead;
// }
// }
// return 0; // 如果没有数据可以读取,直接返回
// }
int64_t write(HANDLE fd, const char* data, int64_t maxSize, bool nonBlocking = false) {
DWORD bytesWritten = 0;
OVERLAPPED overlapped = {0};
if (nonBlocking) {
overlapped.hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
if (!overlapped.hEvent) {
std::cerr << "创建事件失败" << std::endl;
return -1;
}
}
BOOL success = WriteFile(
fd,
data,
static_cast<DWORD>(maxSize),
&bytesWritten,
nonBlocking ? &overlapped : nullptr
);
if (!success) {
DWORD error = GetLastError();
if (error == ERROR_IO_PENDING) {
if (nonBlocking) {
CloseHandle(overlapped.hEvent);
return 0; // 非阻塞模式下返回0表示操作挂起
}
return -1;
} else if (error == ERROR_TIMEOUT) {
CloseHandle(overlapped.hEvent);
return 0;
} else {
CloseHandle(overlapped.hEvent);
std::cerr << "写入错误, 错误代码: " << error << std::endl;
return -1;
}
}
if (nonBlocking) {
CloseHandle(overlapped.hEvent);
}
return bytesWritten;
}
int64_t write(HANDLE fd, const char* data, int64_t size) {
DWORD written;
BOOL success = WriteFile(
fd,
data,
static_cast<DWORD>(size),
&written,
nullptr
);
if (!success)
{
LOG_ERROR("");
return -1;
}
if (written != size)
{
LOG_ERROR("");
}
return written;
}
void set_baud_rate(DCB& serial_info, Serial_FD fd, int baud) {
// 设置串口波特率
serial_info.BaudRate = baud;
}
int get_baud_rate(DCB& serial_info) {
return serial_info.BaudRate;
}
void set_data_bits(DCB& serial_info, DataBits data_bits) {
serial_info.ByteSize = static_cast<BYTE>(data_bits);
}
DataBits get_data_bits(DCB& serial_info) {
return static_cast<DataBits>(serial_info.ByteSize);
}
void set_stop_bits(DCB& serial_info, StopBits stop_bits) {
switch (stop_bits) {
case StopBits::OneStop: serial_info.StopBits = ONESTOPBIT;
break;
case StopBits::OneAndHalfStop: serial_info.StopBits = ONE5STOPBITS;
break;
case StopBits::TwoStop: serial_info.StopBits = TWOSTOPBITS;
break;
default: std::cerr << "Invalid stop bits value." << std::endl;
return;
}
}
StopBits get_stop_bits(DCB& serial_info) {
switch (serial_info.StopBits) {
case ONESTOPBIT: return StopBits::OneStop;
case ONE5STOPBITS: return StopBits::OneAndHalfStop;
case TWOSTOPBITS: return StopBits::TwoStop;
default: return StopBits::UnknownStopBits;
}
}
void set_parity(DCB& serial_info, Parity parity) {
switch (parity) {
case Parity::NoParity: serial_info.Parity = NOPARITY;
break;
case Parity::EvenParity: serial_info.Parity = EVENPARITY;
break;
case Parity::OddParity: serial_info.Parity = ODDPARITY;
break;
case Parity::SpaceParity: serial_info.Parity = SPACEPARITY;
break;
case Parity::MarkParity: serial_info.Parity = MARKPARITY;
break;
default: std::cerr << "Invalid parity value." << std::endl;
return;
}
}
Parity get_parity(DCB& serial_info) {
switch (serial_info.Parity) {
case NOPARITY: return Parity::NoParity;
case EVENPARITY: return Parity::EvenParity;
case ODDPARITY: return Parity::OddParity;
case SPACEPARITY: return Parity::SpaceParity;
case MARKPARITY: return Parity::MarkParity;
default: return Parity::UnknownParity;
}
}
// 设置流控制
// 主要用于流控
// CTS Clear to Send)接收端
// RTS Request To Send 发送端
// 初始化阶段 用于准备就绪信号
// DSR Data Set Ready)接收端
// DTR Data Terminal Ready)发送端
// fInX = TRUE:启用接收端的软件流控,接收端在接收到 XOFF 时暂停接收数据,在接收到 XON 时恢复接收。
// fOutX = TRUE:启用发送端的软件流控,发送端会根据接收端发送的 XON/XOFF 指令控制数据发送
void set_flow_control(DCB& serial_info, FlowControl flow_control) {
switch (flow_control) {
case FlowControl::NoFlowControl:
// 关闭所有流控制
serial_info.fOutxCtsFlow = FALSE;
serial_info.fOutxDsrFlow = FALSE;
serial_info.fInX = FALSE;
serial_info.fOutX = FALSE;
serial_info.fDtrControl = DTR_CONTROL_DISABLE;
serial_info.fRtsControl = RTS_CONTROL_DISABLE;
break;
case FlowControl::HardwareControl:
// 启用硬件流控制
serial_info.fOutxCtsFlow = TRUE;
serial_info.fOutxDsrFlow = TRUE;
serial_info.fInX = FALSE;
serial_info.fOutX = FALSE;
serial_info.fDtrControl = DTR_CONTROL_ENABLE;
serial_info.fRtsControl = RTS_CONTROL_ENABLE;
break;
case FlowControl::SoftwareControl:
// 启用软件流控制
serial_info.fOutxCtsFlow = FALSE;
serial_info.fOutxDsrFlow = FALSE;
serial_info.fInX = TRUE;
serial_info.fOutX = TRUE;
serial_info.fDtrControl = DTR_CONTROL_ENABLE;
serial_info.fRtsControl = RTS_CONTROL_ENABLE;
break;
default: std::cerr << "Unknown flow control type." << std::endl;
return;
}
}
// 获取流控制
FlowControl get_flow_control(DCB& serial_info) {
if (serial_info.fInX && serial_info.fOutX) {
return FlowControl::SoftwareControl;
} else if (serial_info.fOutxCtsFlow && serial_info.fOutxDsrFlow) {
return FlowControl::HardwareControl;
} else if (!serial_info.fOutxCtsFlow && !serial_info.fOutxDsrFlow && !serial_info.fInX && !serial_info.fOutX) {
return FlowControl::NoFlowControl;
} else {
return FlowControl::UnknownFlowControl;
}
}
}
#endif
// int64_t read_data(HANDLE fd, char* data, int64_t maxSize, bool nonBlocking = false) {
// DWORD bytesRead = 0;
// OVERLAPPED overlapped = {0};
//
// if (nonBlocking) {
// overlapped.hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
// if (!overlapped.hEvent) {
// std::cerr << "创建事件失败" << std::endl;
// return -1;
// }
// }
//
// BOOL success = ReadFile(
// fd,
// data,
// static_cast<DWORD>(maxSize),
// &bytesRead,
// nonBlocking ? &overlapped : nullptr
// );
//
// if (!success) {
// DWORD error = GetLastError();
// if (error == ERROR_IO_PENDING) {
// if (nonBlocking) {
// // 等待操作完成
// if (WaitForSingleObject(overlapped.hEvent, INFINITE) == WAIT_OBJECT_0) {
// if (GetOverlappedResult(fd, &overlapped, &bytesRead, FALSE)) {
// CloseHandle(overlapped.hEvent);
// return bytesRead;
// } else {
// std::cerr << "获取异步操作结果失败,错误代码: " << GetLastError() << std::endl;
// CloseHandle(overlapped.hEvent);
// return -1;
// }
// } else {
// std::cerr << "等待事件失败,错误代码: " << GetLastError() << std::endl;
// CloseHandle(overlapped.hEvent);
// return -1;
// }
// }
// return -1;
// } else {
// std::cerr << "读取错误,错误代码: " << error << std::endl;
// if (nonBlocking) {
// CloseHandle(overlapped.hEvent);
// }
// return -1;
// }
// }
//
// if (nonBlocking) {
// CloseHandle(overlapped.hEvent);
// }
//
// return bytesRead;
// }
// int64_t read_data(HANDLE fd, char* data, int64_t maxSize) {
// DWORD bytesAvailable = 0;
// // 先探测是否有数据
// if (!PeekNamedPipe(fd, NULL, 0, NULL, &bytesAvailable, NULL)) {
// std::cerr << "PeekNamedPipe 失败,错误代码: " << GetLastError() << std::endl;
// return -1;
// }
// if (bytesAvailable > 0) {
// DWORD bytesRead = 0;
// if (!ReadFile(fd, data, static_cast<DWORD>(maxSize), &bytesRead, NULL)) {
// std::cerr << "ReadFile 失败,错误代码: " << GetLastError() << std::endl;
// return -1;
// }
// return bytesRead;
// } else {
// // 没有数据则直接返回,下次再读
// errno = EAGAIN; // 或者根据需要返回 0,这里返回 -1 表示无数据
// return -1;
// }
// }
// int64_t read_data(HANDLE fd, char* data, int64_t maxSize) {
// //return read_data(fd, data, maxSize, true); // 返回读取的字节数
// OVERLAPPED overlapped = {};
// DWORD bytesRead = 0;
// if (ReadFile(fd, data, maxSize, &bytesRead, &overlapped) || GetLastError() == ERROR_IO_PENDING) {
// std::cout << "bytesRead:" << bytesRead;
// if (GetOverlappedResult(fd, &overlapped, &bytesRead, FALSE)) {
// return bytesRead;
// }
// }
// return 0; // 如果没有数据可以读取,直接返回
//
// }
//
// int64_t read_data(HANDLE fd, char* data, int64_t maxSize) {
// DWORD bytesRead = 0;
// OVERLAPPED overlapped = {};
// // 为异步操作创建一个事件句柄,必须使用手动复位(TRUE)模式
// overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
// if (!overlapped.hEvent) {
// LOG_ERROR("CreateEvent failed!");
// return -1;
// }
//
// // 发起异步读取操作
// BOOL result = ReadFile(fd, data, static_cast<DWORD>(maxSize), &bytesRead, &overlapped);
// if (!result) {
// DWORD err = GetLastError();
// if (err != ERROR_IO_PENDING) {
// LOG_ERROR("ReadFile failed");
// CloseHandle(overlapped.hEvent);
// return -1;
// }
// } else {
// // 操作同步完成,直接返回读取的字节数
// CloseHandle(overlapped.hEvent);
// return bytesRead;
// }
//
// // 如果操作处于异步状态,则等待操作完成,超时时间为5000毫秒
// DWORD waitResult = WaitForSingleObject(overlapped.hEvent, 1000);
// if (waitResult == WAIT_OBJECT_0) {
// if (GetOverlappedResult(fd, &overlapped, &bytesRead, FALSE)) {
// CloseHandle(overlapped.hEvent);
// return bytesRead;
// } else {
// LOG_ERROR("GetOverlappedResult failed!")
// CloseHandle(overlapped.hEvent);
// return -1;
// }
// } else if (waitResult == WAIT_TIMEOUT) {
// //LOG_ERROR("WAIT_TIMEOUT")
// // CancelIo(fd);
// // CloseHandle(overlapped.hEvent);
// // errno = ETIMEDOUT;
// return 0; // 返回0表示超时未读到数据
// } else {
// LOG_ERROR("WaitForSingleObject failed!")
// CloseHandle(overlapped.hEvent);
// return -1;
// }
// }