Files
CPP_Core/Core/Serial/Serial_win.cpp
T
2026-06-29 09:40:55 +08:00

548 lines
18 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#ifdef WIN32
#include "../Base/global_include.h"
#include "Serial_p.h"
#include <string_view>
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(std::string_view port_name) {
auto port_path = "\\\\.\\" + std::string(port_name);
HANDLE hSerial =
CreateFile(port_path.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) {
auto port_name_string = std::string(port_name);
LOG_ERROR(VAR_STR_1(port_name_string))
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;
}
}
} // namespace Psc::serial
#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;
// }
// }