541 lines
18 KiB
C++
541 lines
18 KiB
C++
#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;
|
||
// }
|
||
// }
|