#include "SerialSCF.h" #include #include #include #include #include #include #include SerialSCF::SerialSCF() : hCom(-1), m_BaudRate(115200), m_ByteSize(8), m_Parity(0), m_StopBits(1), m_ReadTimeout(1000), m_WriteTimeout(1000) { memset(&m_OriginalTermios, 0, sizeof(termios)); memset(&m_CurrentTermios, 0, sizeof(termios)); } SerialSCF::~SerialSCF() { Disconnect(); } int SerialSCF::ConnectCOM(const char* pCom, uint32_t BaudRate, uint32_t ByteSize, uint32_t Parity, uint32_t StopBits) { // 打开串口设备 (非阻塞模式) hCom = open(pCom, O_RDWR | O_NOCTTY | O_NONBLOCK); if (hCom < 0) { // 记录错误日志 return SCF_OPEN_FAILED; } // 保存原始串口设置 if (tcgetattr(hCom, &m_OriginalTermios) != 0) { close(hCom); hCom = -1; return SCF_OPEN_FAILED; } // 配置新的串口设置 memset(&m_CurrentTermios, 0, sizeof(termios)); m_CurrentTermios.c_cflag |= CLOCAL | CREAD; // 本地连接,启用接收 // 设置波特率 speed_t speed; switch (BaudRate) { case 50: speed = B50; break; case 75: speed = B75; break; case 110: speed = B110; break; case 134: speed = B134; break; case 150: speed = B150; break; case 200: speed = B200; break; case 300: speed = B300; break; case 600: speed = B600; break; case 1200: speed = B1200; break; case 1800: speed = B1800; break; case 2400: speed = B2400; break; case 4800: speed = B4800; break; case 9600: speed = B9600; break; case 19200: speed = B19200; break; case 38400: speed = B38400; break; case 57600: speed = B57600; break; case 115200: speed = B115200; break; case 230400: speed = B230400; break; case 460800: speed = B460800; break; case 500000: speed = B500000; break; case 576000: speed = B576000; break; case 921600: speed = B921600; break; case 1000000: speed = B1000000; break; default: close(hCom); hCom = -1; return SCF_PARAMETER_ERR; } cfsetispeed(&m_CurrentTermios, speed); cfsetospeed(&m_CurrentTermios, speed); // 设置数据位 m_CurrentTermios.c_cflag &= ~CSIZE; switch (ByteSize) { case 5: m_CurrentTermios.c_cflag |= CS5; break; case 6: m_CurrentTermios.c_cflag |= CS6; break; case 7: m_CurrentTermios.c_cflag |= CS7; break; case 8: m_CurrentTermios.c_cflag |= CS8; break; default: close(hCom); hCom = -1; return SCF_PARAMETER_ERR; } // 设置校验位 switch (Parity) { case 0: // None m_CurrentTermios.c_cflag &= ~PARENB; break; case 1: // Odd m_CurrentTermios.c_cflag |= PARENB; m_CurrentTermios.c_cflag |= PARODD; break; case 2: // Even m_CurrentTermios.c_cflag |= PARENB; m_CurrentTermios.c_cflag &= ~PARODD; break; default: close(hCom); hCom = -1; return SCF_PARAMETER_ERR; } // 设置停止位 switch (StopBits) { case 1: m_CurrentTermios.c_cflag &= ~CSTOPB; break; case 2: m_CurrentTermios.c_cflag |= CSTOPB; break; default: close(hCom); hCom = -1; return SCF_PARAMETER_ERR; } // 设置原始模式 (禁用规范模式) m_CurrentTermios.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); m_CurrentTermios.c_oflag &= ~OPOST; // 原始输出 // 设置超时和最小读取字节数 m_CurrentTermios.c_cc[VMIN] = 0; // 非阻塞模式 m_CurrentTermios.c_cc[VTIME] = m_ReadTimeout / 100; // 超时时间 (十分之一秒) // 刷新缓冲区并应用新设置 tcflush(hCom, TCIOFLUSH); if (tcsetattr(hCom, TCSANOW, &m_CurrentTermios) != 0) { close(hCom); hCom = -1; return SCF_OPEN_FAILED; } // 清除所有缓冲区 tcflush(hCom, TCIOFLUSH); return SCF_SUCCEED; } int SerialSCF::Connect(ResDataObject& Connectprameters, PacketParser callback, SCF_TRANSFERTYPE TransferType, uint32_t CommunicateTimeout) { int ret = SCF_FAILED; try { ResDataObject params = Connectprameters; params.MakeKeyLower(); std::string ConnectionType = (const char*)Connectprameters["type"]; std::string ThisType = GetConnectionType(); // 转换为小写比较 std::transform(ConnectionType.begin(), ConnectionType.end(), ConnectionType.begin(), ::tolower); std::transform(ThisType.begin(), ThisType.end(), ThisType.begin(), ::tolower); if (ConnectionType != ThisType) { return SCF_PARAMETER_ERR; } m_PortName = (const char*)Connectprameters["port"]; m_BaudRate = (uint32_t)Connectprameters["baudrate"]; m_ByteSize = (uint32_t)Connectprameters["bytesize"]; m_Parity = (uint32_t)Connectprameters["parity"]; m_StopBits = (uint32_t)Connectprameters["stopbits"]; ret = ConnectCOM(m_PortName.c_str(), m_BaudRate, m_ByteSize, m_Parity, m_StopBits); if (ret == SCF_SUCCEED) { // 初始化日志 std::string NewFileName = "com/s_" + m_PortName; InitSCF(NewFileName.c_str()); // 调用基类连接方法 ret = SCF::Connect(Connectprameters, callback, TransferType, CommunicateTimeout); } } catch (...) { ret = SCF_UNKNOWN; } return ret; } void SerialSCF::Disconnect() { SCF::Disconnect(); if (hCom >= 0) { // 恢复原始串口设置 tcsetattr(hCom, TCSANOW, &m_OriginalTermios); // 关闭串口 close(hCom); hCom = -1; } } bool SerialSCF::isConnected() { return (hCom >= 0); } const char* SerialSCF::GetConnectionType() { static const char* nType = "COM"; return nType; } int SerialSCF::SendPacket(SCFPacket* pPacket, uint32_t timeout) { return SendPacket((char*)(*pPacket), pPacket->GetPacketLen(), timeout); } int SerialSCF::SendPacket(const char* pPacket, uint32_t length, uint32_t timeout) { if (!isConnected()) { return SCF_DISCONNETED; } // 设置写超时 struct timeval tv; tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; fd_set write_fds; FD_ZERO(&write_fds); FD_SET(hCom, &write_fds); uint32_t bytesWritten = 0; while (bytesWritten < length) { // 等待串口可写 int selectRet = select(hCom + 1, NULL, &write_fds, NULL, &tv); if (selectRet <= 0) { // 超时或错误 return (selectRet == 0) ? SCF_TIMEOUT : SCF_WRITE_FAILED; } // 写入数据 ssize_t ret = write(hCom, pPacket + bytesWritten, length - bytesWritten); if (ret < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) { // 短暂等待后重试 usleep(10000); // 10ms continue; } return SCF_WRITE_FAILED; } bytesWritten += ret; } return bytesWritten; } int SerialSCF::ReadData(char* pPacket, uint32_t length, uint32_t timeout) { if (!isConnected()) { return SCF_DISCONNETED; } // 设置读超时 struct timeval tv; tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; fd_set read_fds; FD_ZERO(&read_fds); FD_SET(hCom, &read_fds); // 等待数据到达 int selectRet = select(hCom + 1, &read_fds, NULL, NULL, &tv); if (selectRet <= 0) { // 超时或错误 return (selectRet == 0) ? SCF_TIMEOUT : SCF_READ_FAILED; } // 读取可用数据 int bytesAvailable = 0; if (ioctl(hCom, FIONREAD, &bytesAvailable) < 0) { return SCF_READ_FAILED; } // 确保不超过缓冲区大小 uint32_t bytesToRead = std::min(static_cast(bytesAvailable), length); // 读取数据 ssize_t ret = read(hCom, pPacket, bytesToRead); if (ret < 0) { return SCF_READ_FAILED; } return ret; } SERIALSCF_C_API SCF* GetSCF() { SerialSCF* p = new SerialSCF(); return static_cast(p); } SERIALSCF_C_API void ReleaseSCF(SCF* p) { delete static_cast(p); }