
文章目录串口参数结构体全局变量打开串口检查超时函数重置超时计时函数发送指令并接收返回值关闭串口连接串口参数结构体structSP4A_COM_SETUP_STRUCT{intiCom;intiBaud;intiParity;intiDataBit;intiStopBit;int64_tlTimeout;//msint64_tlIntervalTimems50;//msJSON_HELPER(iCom,iBaud,iParity,iDataBit,iStopBit,lTimeout,lIntervalTimems)};全局变量HANDLE m_hCommNULL;staticstd::chrono::steady_clock::time_point g_threadStartTime;constexprintMAX_COM_NUM256;constexprintDEFAULT_READ_TIMEOUT_MULTI2;constexprintDEFAULT_READ_INTERVAL_TIMEOUT10;constexprsize_t COM_NAME_BUF_SIZE16;打开串口intopenPort(constSP4A_COM_SETUP_STRUCTstPortParam){if(stPortParam.iCom1||stPortParam.iComMAX_COM_NUM){printf([openPort] invalid com\n);return-1;}if(stPortParam.iBaud0||stPortParam.iDataBit5||stPortParam.iDataBit8){printf([openPort] invalid parameter\n);}closePort();charszCom[COM_NAME_BUF_SIZE]{0};if(stPortParam.iCom9){sprintf_s(szCom,COM_NAME_BUF_SIZE,\\\\.\\COM%d,stPortParam.iCom);}else{sprintf_s(szCom,COM_NAME_BUF_SIZE,COM%d,stPortParam.iCom);}std::string comName{szCom};//打开串口m_hCommCreateFileA(szCom,GENERIC_READ|GENERIC_WRITE,0,//独占访问NULL,//安全属性OPEN_EXISTING,//仅打开已存在的串口0,//同步IONULL);//无模板文件if(m_hCommINVALID_HANDLE_VALUE){printf([openPort] CreateFileA failed, 0x%x\n,GetLastError());closePort();return-1;}//配置串口参数DCB dcb{0};dcb.DCBlengthsizeof(DCB);if(!GetCommState(m_hComm,dcb)){printf([openPort] GetComState failed, 0x%x\n,GetLastError());closePort();return-1;}//更新串口参数dcb.BaudRatestPortParam.iBaud;dcb.StopBitsstPortParam.iStopBit;dcb.ByteSizestPortParam.iDataBit;dcb.ParitystPortParam.iParity;dcb.fParity(stPortParam.iParity!NOPARITY);//显式设置校验位使能if(!SetCommState(m_hComm,dcb)){printf([openPort] SetCommState failed, 0x%x\n,GetLastError());closePort();return-1;}//配置超时参数COMMTIMEOUTS timeout{0};if(!GetCommTimeouts(m_hComm,timeout)){printf([openPort] GetCommTimeouts failed, 0x%x\n,GetLastError());closePort();return-1;}timeout.WriteTotalTimeoutConstantstPortParam.lIntervalTimems;//写超时常量timeout.ReadTotalTimeoutMultiplierDEFAULT_READ_TIMEOUT_MULTI;//读超时乘数timeout.ReadIntervalTimeoutDEFAULT_READ_INTERVAL_TIMEOUT;//读间隔超时if(!SetCommTimeouts(m_hComm,timeout)){printf([openPort] SetCommTimeouts failed, 0x%x\n,GetLastError());closePort();return-1;}//清空串口缓冲区if(!PurgeComm(m_hComm,PURGE_RXCLEAR|PURGE_TXCLEAR)){printf([openPort] PurgeComm failed, 0x%x\n,GetLastError());closePort();return-1;}printf([SerialPort] COM%d opened successfully\n,stPortParam.iCom);return0;}检查超时函数/** *brief *param *return */boolcheckThreadTimeout(inttimeoutMs){autodurationstd::chrono::duration_caststd::chrono::milliseconds(std::chrono::steady_clock::now()-g_threadStartTime);returnduration.count()timeoutMs;}重置超时计时函数/** *brief 重置超时计时 */voidresetThreadTimeout(){g_threadStartTimestd::chrono::steady_clock::now();}发送指令并接收返回值/** * brief 串口发送指令并接收返回数据完善版 * param stCommand 串口指令结构体包含指令、结束符、读取配置等 * param sRet 输出参数接收串口返回的数据 * param timeoutMs 超时时间默认3000ms * return int 0成功-1失败 */intsendCmd(SP4A_STRING_COMMAND_RS232_STRUCTstCommand,std::stringsRet,inttimeoutMs){if(m_hCommNULL||m_hCommINVALID_HANDLE_VALUE){printf([sendCmd] error: invalid comm handle\n);return-1;}if(stCommand.sCmdData.empty()){printf([sendCmd] error: empty command\n);return-1;}sRet.clear();autocommFunc[]()-int{intrc0;std::string sFullCmdstCommand.sCmdDatastCommand.sEndByte;constBYTE*cmdBufferreinterpret_castconstBYTE*(sFullCmd.c_str());intcmdLenstatic_castint(sFullCmd.size());try{//清理串口缓冲区if(!PurgeComm(m_hComm,PURGE_TXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR)){printf([sendCmd] PurgeComm error, 0x%x\n,GetLastError());return-1;}//发送指令DWORD bytesSent0;BOOL bWriteWriteFile(m_hComm,//串口句柄cmdBuffer,//发送缓冲区cmdLen,//发送长度bytesSent,//实际发送字节数NULL//非重叠IO);if(!bWrite||bytesSent!cmdLen){printf([sendCmd] failed, system code: 0x%x, send length: %d, actual length: %d\n,GetLastError(),cmdLen,bytesSent);return-1;}printf([sendCmd] successful: %s\n,stCommand.sCmdData.c_str());//接收返回数据std::string sRetData;BYTE recvBuffer[1024]{0};DWORD bytesRead0;boolbFinishfalse;resetThreadTimeout();//重置超时计时while(!bFinish!checkThreadTimeout(timeoutMs)){//读取串口数据每次最多1024字节BOOL bReadReadFile(m_hComm,recvBuffer,sizeof(recvBuffer)-1,//预留终止符位置bytesRead,NULL);if(!bRead){DWORD errGetLastError();//无数据时继续等待ERROR_IO_PENDING是正常等待非错误if(err!ERROR_IO_PENDINGerr!ERROR_TIMEOUT){printf([sendCmd] error, 0x%x\n,err);rc-1;break;}std::this_thread::sleep_for(std::chrono::milliseconds(10));//短暂延时continue;}if(bytesRead0){sRetData.append(reinterpret_castchar*(recvBuffer),bytesRead);memset(recvBuffer,0,sizeof(recvBuffer));//清空接收缓冲区用0填充if(!stCommand.sEndByte.empty())//检测结束符{size_t endPossRetData.rfind(stCommand.sEndByte);if(endPos!string::nposendPossRetData.size()-stCommand.sEndByte.size()){bFinishtrue;}}if(!bFinish!stCommand.listEndStateKey.empty())//检测结束关键字{for(constautokey:stCommand.listEndStateKey){if(sRetData.find(key)!string::npos){bFinishtrue;break;}}}//达到期望读取长度if(!bFinishstCommand.iReadSize0sRetData.size()stCommand.iReadSize){bFinishtrue;}}else{std::this_thread::sleep_for(std::chrono::milliseconds(10));}}if(checkThreadTimeout(timeoutMs)){printf([sendCmd] receive timeout, %s\n,sRetData.c_str());rc-1;}elseif(rc0){sRetsRetData;printf([sendCmd] receive successful, %s, length:%zd,sRetData.c_str(),sRetData.size());}}catch(conststd::exceptione){printf([sendCmd] errror, %s\n,e.what());rc-1;}catch(...){printf([sendCmd] unknown error\n);rc-1;}returnrc;};//异步执行//std::thread t(commFunc);//t.join();//同步执行intresultcommFunc();if(result!0){PurgeComm(m_hComm,PURGE_RXCLEAR);}returnresult;}关闭串口连接intclosePort(){intrc0;if(m_hComm!NULLm_hComm!INVALID_HANDLE_VALUE){BOOL bResultCloseHandle(m_hComm);if(bResult!TRUE){printf([closePort] error, 0x%x\n,GetLastError());rc-1;}else{m_hCommNULL;}}returnrc;}