#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(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(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(data_bits); } DataBits get_data_bits(DCB &serial_info) { return static_cast(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(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(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(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; // } // }