|
@@ -26,15 +26,15 @@ SerialSCF::~SerialSCF() {
|
|
|
int SerialSCF::ConnectCOM(const char* pCom, uint32_t BaudRate, uint32_t ByteSize,
|
|
|
uint32_t Parity, uint32_t StopBits) {
|
|
|
std::cout << "Trying to open serial port: " << pCom << std::endl;
|
|
|
- // 打开串口设备 (非阻塞模式)
|
|
|
+ // 鎵撳紑涓插彛璁惧� (闈為樆濉炴ā寮�)
|
|
|
hCom = open(pCom, O_RDWR | O_NOCTTY);//| O_NONBLOCK
|
|
|
if (hCom < 0) {
|
|
|
- // 记录错误日志
|
|
|
+ // 璁板綍閿欒�鏃ュ織
|
|
|
return SCF_OPEN_FAILED;
|
|
|
}
|
|
|
|
|
|
std::cout << "Serial port " << pCom << " opened successfully (file descriptor: " << hCom << ")" << std::endl;
|
|
|
- // 保存原始串口设置
|
|
|
+ // 淇濆瓨鍘熷�涓插彛璁剧疆
|
|
|
if (tcgetattr(hCom, &m_OriginalTermios) != 0) {
|
|
|
std::cout << "Failed to get original termios attributes for port: " << pCom << std::endl;
|
|
|
close(hCom);
|
|
@@ -42,11 +42,11 @@ int SerialSCF::ConnectCOM(const char* pCom, uint32_t BaudRate, uint32_t ByteSize
|
|
|
return SCF_OPEN_FAILED;
|
|
|
}
|
|
|
|
|
|
- // 配置新的串口设置
|
|
|
+ // 閰嶇疆鏂扮殑涓插彛璁剧疆
|
|
|
memset(&m_CurrentTermios, 0, sizeof(termios));
|
|
|
- m_CurrentTermios.c_cflag |= CLOCAL | CREAD; // 本地连接,启用接收
|
|
|
+ m_CurrentTermios.c_cflag |= CLOCAL | CREAD; // 鏈�湴杩炴帴锛屽惎鐢ㄦ帴鏀�
|
|
|
std::cout << "Configuring serial port attributes..." << std::endl;
|
|
|
- // 设置波特率
|
|
|
+ // 璁剧疆娉㈢壒鐜�
|
|
|
speed_t speed;
|
|
|
switch (BaudRate) {
|
|
|
case 50: speed = B50; break;
|
|
@@ -82,7 +82,7 @@ int SerialSCF::ConnectCOM(const char* pCom, uint32_t BaudRate, uint32_t ByteSize
|
|
|
cfsetospeed(&m_CurrentTermios, speed);
|
|
|
std::cout << "Set baud rate to: " << BaudRate << std::endl;
|
|
|
|
|
|
- // 设置数据位
|
|
|
+ // 璁剧疆鏁版嵁浣�
|
|
|
m_CurrentTermios.c_cflag &= ~CSIZE;
|
|
|
switch (ByteSize) {
|
|
|
case 5: m_CurrentTermios.c_cflag |= CS5; break;
|
|
@@ -97,7 +97,7 @@ int SerialSCF::ConnectCOM(const char* pCom, uint32_t BaudRate, uint32_t ByteSize
|
|
|
}
|
|
|
std::cout << "Set data bits to: " << ByteSize << std::endl;
|
|
|
|
|
|
- // 设置校验位
|
|
|
+ // 璁剧疆鏍¢獙浣�
|
|
|
switch (Parity) {
|
|
|
case 0: // None
|
|
|
m_CurrentTermios.c_cflag &= ~PARENB;
|
|
@@ -120,7 +120,7 @@ int SerialSCF::ConnectCOM(const char* pCom, uint32_t BaudRate, uint32_t ByteSize
|
|
|
return SCF_PARAMETER_ERR;
|
|
|
}
|
|
|
|
|
|
- // 设置停止位
|
|
|
+ // 璁剧疆鍋滄�浣�
|
|
|
switch (StopBits) {
|
|
|
case 1:
|
|
|
m_CurrentTermios.c_cflag &= ~CSTOPB;
|
|
@@ -137,16 +137,16 @@ int SerialSCF::ConnectCOM(const char* pCom, uint32_t BaudRate, uint32_t ByteSize
|
|
|
return SCF_PARAMETER_ERR;
|
|
|
}
|
|
|
|
|
|
- // 设置原始模式 (禁用规范模式)
|
|
|
+ // 璁剧疆鍘熷�妯″紡 (绂佺敤瑙勮寖妯″紡)
|
|
|
m_CurrentTermios.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
|
|
|
- m_CurrentTermios.c_oflag &= ~OPOST; // 原始输出
|
|
|
+ m_CurrentTermios.c_oflag &= ~OPOST; // 鍘熷�杈撳嚭
|
|
|
std::cout << "Set serial port to raw mode" << std::endl;
|
|
|
|
|
|
- // 设置超时和最小读取字节数
|
|
|
- m_CurrentTermios.c_cc[VMIN] = 0; // 非阻塞模式
|
|
|
- m_CurrentTermios.c_cc[VTIME] = m_ReadTimeout / 100; // 超时时间 (十分之一秒)
|
|
|
+ // 璁剧疆瓒呮椂鍜屾渶灏忚�鍙栧瓧鑺傛暟
|
|
|
+ m_CurrentTermios.c_cc[VMIN] = 0; // 闈為樆濉炴ā寮�
|
|
|
+ m_CurrentTermios.c_cc[VTIME] = m_ReadTimeout / 100; // 瓒呮椂鏃堕棿 (鍗佸垎涔嬩竴绉�)
|
|
|
std::cout << "Set read timeout to: " << m_ReadTimeout << "ms" << std::endl;
|
|
|
- // 刷新缓冲区并应用新设置
|
|
|
+ // 鍒锋柊缂撳啿鍖哄苟搴旂敤鏂拌�缃�
|
|
|
tcflush(hCom, TCIOFLUSH);
|
|
|
if (tcsetattr(hCom, TCSANOW, &m_CurrentTermios) != 0) {
|
|
|
close(hCom);
|
|
@@ -155,7 +155,7 @@ int SerialSCF::ConnectCOM(const char* pCom, uint32_t BaudRate, uint32_t ByteSize
|
|
|
}
|
|
|
std::cout << "Serial port settings applied successfully" << std::endl;
|
|
|
|
|
|
- // 清除所有缓冲区
|
|
|
+ // 娓呴櫎鎵€鏈夌紦鍐插尯
|
|
|
tcflush(hCom, TCIOFLUSH);
|
|
|
std::cout << "Serial port buffers flushed" << std::endl;
|
|
|
|
|
@@ -174,7 +174,7 @@ int SerialSCF::Connect(ResDataObject& Connectprameters, PacketParser callback,
|
|
|
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);
|
|
|
|
|
@@ -199,12 +199,12 @@ int SerialSCF::Connect(ResDataObject& Connectprameters, PacketParser callback,
|
|
|
ret = ConnectCOM(m_PortName.c_str(), m_BaudRate, m_ByteSize, m_Parity, m_StopBits);
|
|
|
if (ret == SCF_SUCCEED) {
|
|
|
std::cout << "COM port connection successful." << std::endl;
|
|
|
- // 初始化日志
|
|
|
+ // 鍒濆�鍖栨棩蹇�
|
|
|
std::string NewFileName = "com/s_" + m_PortName;
|
|
|
std::cout << "Initializing SCF with log file: " << NewFileName << std::endl;
|
|
|
InitSCF(NewFileName.c_str());
|
|
|
|
|
|
- // 调用基类连接方法
|
|
|
+ // 璋冪敤鍩虹被杩炴帴鏂规硶
|
|
|
ret = SCF::Connect(Connectprameters, callback, TransferType, CommunicateTimeout);
|
|
|
}
|
|
|
}
|
|
@@ -219,50 +219,50 @@ void SerialSCF::Disconnect() {
|
|
|
SCF::Disconnect();
|
|
|
|
|
|
if (hCom >= 0) {
|
|
|
- // 恢复原始串口设置
|
|
|
+ // 鎭㈠�鍘熷�涓插彛璁剧疆
|
|
|
tcsetattr(hCom, TCSANOW, &m_OriginalTermios);
|
|
|
|
|
|
- // 关闭串口
|
|
|
+ // 鍏抽棴涓插彛
|
|
|
close(hCom);
|
|
|
hCom = -1;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
bool SerialSCF::isConnected() {
|
|
|
- // 1. 基础检查:文件描述符已无效,直接返回断开
|
|
|
+ // 1. 鍩虹�妫€鏌ワ細鏂囦欢鎻忚堪绗﹀凡鏃犳晥锛岀洿鎺ヨ繑鍥炴柇寮€
|
|
|
if (hCom < 0) {
|
|
|
std::cout << "[Debug] isConnected: hCom invalid (value: " << hCom << ")" << std::endl;
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- // 2. 检查文件描述符有效性(处理EIO和EBADF)
|
|
|
+ // 2. 妫€鏌ユ枃浠舵弿杩扮�鏈夋晥鎬э紙澶勭悊EIO鍜孍BADF锛�
|
|
|
int fdCheck = fcntl(hCom, F_GETFD);
|
|
|
if (fdCheck == -1) {
|
|
|
std::cout << "[Debug] isConnected: fcntl failed | errno=" << errno
|
|
|
<< " (" << (errno == EIO ? "EIO(I/O error)" : (errno == EBADF ? "EBADF(Bad file)" : "Unknown")) << ")" << std::endl;
|
|
|
- // 关键判断:用户环境中EIO=5(设备删除)、EBADF=9(描述符无效)均视为断开
|
|
|
+ // 鍏抽敭鍒ゆ柇锛氱敤鎴风幆澧冧腑EIO=5锛堣�澶囧垹闄わ級銆丒BADF=9锛堟弿杩扮�鏃犳晥锛夊潎瑙嗕负鏂�紑
|
|
|
if (errno == EIO || errno == EBADF) {
|
|
|
- hCom = -1; // 重置描述符状态,避免后续误判
|
|
|
+ hCom = -1; // 閲嶇疆鎻忚堪绗︾姸鎬侊紝閬垮厤鍚庣画璇�垽
|
|
|
return false;
|
|
|
}
|
|
|
- // 其他非致命错误(如临时权限问题)不判定为断开
|
|
|
+ // 鍏朵粬闈炶嚧鍛介敊璇�紙濡備复鏃舵潈闄愰棶棰橈級涓嶅垽瀹氫负鏂�紑
|
|
|
}
|
|
|
|
|
|
- // 3. 检查串口硬件状态(核心适配虚拟端口删除后的EIO错误)
|
|
|
+ // 3. 妫€鏌ヤ覆鍙g‖浠剁姸鎬侊紙鏍稿績閫傞厤铏氭嫙绔�彛鍒犻櫎鍚庣殑EIO閿欒�锛�
|
|
|
int portStatus;
|
|
|
int ioctlRet = ioctl(hCom, TIOCMGET, &portStatus);
|
|
|
if (ioctlRet == -1) {
|
|
|
std::cout << "[Debug] isConnected: ioctl(TIOCMGET) failed | errno=" << errno
|
|
|
<< " (" << (errno == EIO ? "EIO(I/O error)" : (errno == EBADF ? "EBADF(Bad file)" : "Unknown")) << ")" << std::endl;
|
|
|
- // 同样处理EIO和EBADF,覆盖虚拟端口删除场景
|
|
|
+ // 鍚屾牱澶勭悊EIO鍜孍BADF锛岃�鐩栬櫄鎷熺�鍙e垹闄ゅ満鏅�
|
|
|
if (errno == EIO || errno == EBADF) {
|
|
|
hCom = -1;
|
|
|
return false;
|
|
|
}
|
|
|
- // 临时I/O错误(如设备短暂无响应)不判定为断开
|
|
|
+ // 涓存椂I/O閿欒�锛堝�璁惧�鐭�殏鏃犲搷搴旓級涓嶅垽瀹氫负鏂�紑
|
|
|
}
|
|
|
|
|
|
- // 4. 所有检查通过,确认连接有效
|
|
|
+ // 4. 鎵€鏈夋�鏌ラ€氳繃锛岀‘璁よ繛鎺ユ湁鏁�
|
|
|
return true;
|
|
|
}
|
|
|
|
|
@@ -280,14 +280,14 @@ int SerialSCF::SendPacket(const char* pPacket, uint32_t length, uint32_t timeout
|
|
|
std::cout << "SendPacket failed: Not connected to serial port." << std::endl;
|
|
|
return SCF_DISCONNETED;
|
|
|
}
|
|
|
- // 验证输入参数
|
|
|
+ // 楠岃瘉杈撳叆鍙傛暟
|
|
|
if (pPacket == nullptr || length == 0) {
|
|
|
std::cout << "SendPacket failed: Invalid packet (nullptr or zero length)." << std::endl;
|
|
|
return SCF_WRITE_FAILED;
|
|
|
}
|
|
|
|
|
|
std::cout << "Starting to send packet. Length: " << length << " bytes, Timeout: " << timeout << " ms." << std::endl;
|
|
|
- // 设置写超时
|
|
|
+ // 璁剧疆鍐欒秴鏃�
|
|
|
struct timeval tv;
|
|
|
tv.tv_sec = timeout / 1000;
|
|
|
tv.tv_usec = (timeout % 1000) * 1000;
|
|
@@ -299,7 +299,7 @@ int SerialSCF::SendPacket(const char* pPacket, uint32_t length, uint32_t timeout
|
|
|
|
|
|
uint32_t bytesWritten = 0;
|
|
|
while (bytesWritten < length) {
|
|
|
- // 等待串口可写
|
|
|
+ // 绛夊緟涓插彛鍙�啓
|
|
|
int selectRet = select(hCom + 1, NULL, &write_fds, NULL, &tv);
|
|
|
if (selectRet <= 0) {
|
|
|
if (selectRet == 0) {
|
|
@@ -311,17 +311,17 @@ int SerialSCF::SendPacket(const char* pPacket, uint32_t length, uint32_t timeout
|
|
|
return SCF_WRITE_FAILED;
|
|
|
}
|
|
|
}
|
|
|
- // 检查串口是否可写
|
|
|
+ // 妫€鏌ヤ覆鍙f槸鍚﹀彲鍐�
|
|
|
if (!FD_ISSET(hCom, &write_fds)) {
|
|
|
std::cout << "SendPacket warning: Serial port not ready for writing, retrying..." << std::endl;
|
|
|
continue;
|
|
|
}
|
|
|
- // 写入数据
|
|
|
+ // 鍐欏叆鏁版嵁
|
|
|
ssize_t ret = write(hCom, pPacket + bytesWritten, length - bytesWritten);
|
|
|
if (ret < 0) {
|
|
|
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
|
|
std::cout << "SendPacket temporary error: Resource busy (EAGAIN/EWOULDBLOCK). Retrying..." << std::endl;
|
|
|
- usleep(10000); // 10ms等待后重试
|
|
|
+ usleep(10000); // 10ms绛夊緟鍚庨噸璇�
|
|
|
continue;
|
|
|
}
|
|
|
else {
|
|
@@ -343,7 +343,16 @@ int SerialSCF::ReadData(char* pPacket, uint32_t length, uint32_t timeout) {
|
|
|
return SCF_DISCONNETED;
|
|
|
}
|
|
|
|
|
|
- // 设置读超时
|
|
|
+ if (!pPacket || length == 0) {
|
|
|
+ std::cout << "[Debug] Invalid parameters: pPacket=" << (void*)pPacket << ", length=" << length << std::endl;
|
|
|
+ return SCF_PARAMETER_ERR;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 娓呯┖缂撳啿鍖猴紝闃叉�杩斿洖鍨冨溇鏁版嵁
|
|
|
+ memset(pPacket, 0, length);
|
|
|
+
|
|
|
+
|
|
|
+ // 璁剧疆璇昏秴鏃�
|
|
|
struct timeval tv;
|
|
|
tv.tv_sec = timeout / 1000;
|
|
|
tv.tv_usec = (timeout % 1000) * 1000;
|
|
@@ -352,14 +361,14 @@ int SerialSCF::ReadData(char* pPacket, uint32_t length, uint32_t timeout) {
|
|
|
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) {
|
|
|
std::cout << "[Debug] ioctl failed, errno: " << errno << std::endl;
|
|
@@ -370,26 +379,36 @@ int SerialSCF::ReadData(char* pPacket, uint32_t length, uint32_t timeout) {
|
|
|
return SCF_READ_FAILED;
|
|
|
}
|
|
|
|
|
|
- // 确保不超过缓冲区大小
|
|
|
+ // 濡傛灉娌℃湁鏁版嵁鍙��锛岃繑鍥炶秴鏃讹紙select宸茬粡琛ㄦ槑鏈夋暟鎹�紝浣唅octl璇存病鏈夛紝杩欐槸寮傚父鎯呭喌锛�
|
|
|
+ if (bytesAvailable <= 0) {
|
|
|
+ std::cout << "[Debug] ioctl reports no data available (bytesAvailable=" << bytesAvailable << "), but select indicated ready" << std::endl;
|
|
|
+ return SCF_TIMEOUT;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 纭�繚涓嶈秴杩囩紦鍐插尯澶у皬
|
|
|
uint32_t bytesToRead = std::min(static_cast<uint32_t>(bytesAvailable), length);
|
|
|
|
|
|
- // 读取数据
|
|
|
+ // 鍐嶆�纭��瑕佽�鍙栫殑瀛楄妭鏁颁笉涓�0
|
|
|
+ if (bytesToRead == 0) {
|
|
|
+ std::cout << "[Debug] bytesToRead is 0, length=" << length << ", bytesAvailable=" << bytesAvailable << std::endl;
|
|
|
+ return SCF_TIMEOUT;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 璇诲彇鏁版嵁
|
|
|
ssize_t ret = read(hCom, pPacket, bytesToRead);
|
|
|
if (ret < 0) {
|
|
|
std::cout << "[Debug] Read failed, errno: " << errno << std::endl;
|
|
|
return SCF_READ_FAILED;
|
|
|
}
|
|
|
else if (ret == 0) {
|
|
|
- std::cout << "[Debug] Read 0 bytes (maybe data split)" << std::endl;
|
|
|
- return 0;
|
|
|
+ std::cout << "[Debug] Read 0 bytes (maybe data split or EOF)" << std::endl;
|
|
|
+ return SCF_TIMEOUT; // 杩斿洖瓒呮椂鑰屼笉鏄�0锛岄伩鍏嶄笂灞傝�鍒�
|
|
|
}
|
|
|
else {
|
|
|
- // 原有的成功日志
|
|
|
+ // 鍘熸湁鐨勬垚鍔熸棩蹇椫�
|
|
|
std::cout << "[Serial Port: " << m_PortName << "] Read " << ret << " bytes." << std::endl;
|
|
|
return ret;
|
|
|
}
|
|
|
-
|
|
|
- return ret;
|
|
|
}
|
|
|
|
|
|
SERIALSCF_C_API SCF* GetSCF() {
|