/****************************************************************************** 版权所有 (C), 2018-2099, Radkil ****************************************************************************** 文 件 名 : com.c 版 本 号 : 初稿 作 者 : Radkil 生成日期 : 2026年3月27日星期五 最近修改 : 功能描述 : 串口通用控制模块 修改历史 : 1.日 期 : 2026年3月27日星期五 作 者 : Radkil 修改内容 : 创建文件 ******************************************************************************/ #include "com.h" #include "rd_time.h" /*----------------------------------------------* * 外部变量说明 * *----------------------------------------------*/ /*----------------------------------------------* * 外部函数原型说明 * *----------------------------------------------*/ /*----------------------------------------------* * 内部函数原型说明 * *----------------------------------------------*/ /*----------------------------------------------* * 全局变量 * *----------------------------------------------*/ /*----------------------------------------------* * 模块级变量 * *----------------------------------------------*/ static const UT_icd g_mutidev_ptr = {sizeof(void*), NULL, NULL, NULL}; /*----------------------------------------------* * 常量定义 * *----------------------------------------------*/ /*----------------------------------------------* * 宏定义 * *----------------------------------------------*/ /***************************************************************************** 函 数 名 : rd_ComCreate 功能描述 : 创建通信控制块 输入参数 : cbk_ComDecode _pfDecode 解码函数,为空的话默认单字节透传数据 cbk_ComSend _pfSend 发送函数,不可为空 int _iSize 环形缓冲区大小 void *_pUserData 用户数据 输出参数 : 无 返 回 值 : TComCtrl * 调用函数 : 被调函数 : 修改历史 : 1.日 期 : 2026年4月24日 作 者 : radkil 修改内容 : 新生成函数 *****************************************************************************/ TComCtrl *rd_ComCreate(cbk_ComCheck _pfCheck, cbk_ComDecode _pfDecode, cbk_ComSend _pfSend, int _iSize, void *_pUserData) { TComCtrl *ptComCtrl = RD_CALLOC(1, sizeof(TComCtrl)); if (NULL == ptComCtrl) return NULL; ptComCtrl->m_iBufferSize = _iSize; ptComCtrl->m_pUserData = _pUserData; //Rd_SemInit(&ptComCtrl->m_stComBuf.m_sem_Recv, 0, 0); Rd_SemInit(&ptComCtrl->m_stComBuf.m_sem_Send, 0, 0); ptComCtrl->m_stComBuf.m_ptRecv = rd_RingbufferCreate(_iSize); rd_RingbufferReset(ptComCtrl->m_stComBuf.m_ptRecv); ptComCtrl->m_stComBuf.m_ptSend = rd_RingbufferCreate(_iSize); rd_RingbufferReset(ptComCtrl->m_stComBuf.m_ptSend); ptComCtrl->m_pfSend = _pfSend; ptComCtrl->m_iDevIndex = -1; TMutiDev *ptMutiDev = RD_CALLOC(1, sizeof(TMutiDev)); ptMutiDev->m_pfCheck = _pfCheck; ptMutiDev->m_pfDecode = _pfDecode; utarray_new(ptComCtrl->m_pMutiDevArray, &g_mutidev_ptr); utarray_push_back(ptComCtrl->m_pMutiDevArray, &ptMutiDev); return ptComCtrl; } void rd_ComAddDev(TComCtrl *_ptComCtrl, cbk_ComCheck _pfCheck, cbk_ComDecode _pfDecode) { TMutiDev *ptMutiDev = RD_CALLOC(1, sizeof(TMutiDev)); ptMutiDev->m_pfCheck = _pfCheck; ptMutiDev->m_pfDecode = _pfDecode; utarray_push_back(_ptComCtrl->m_pMutiDevArray, &ptMutiDev); } int rd_ComDelete(TComCtrl *_ptComCtrl) { if (NULL == _ptComCtrl) return RD_FAILURE; if (_ptComCtrl->m_pMutiDevArray != NULL) { for(int i=0; i < utarray_len(_ptComCtrl->m_pMutiDevArray); i++) { TMutiDev **ppDev = (TMutiDev**)utarray_eltptr(_ptComCtrl->m_pMutiDevArray, i); if (*ppDev != NULL) { RD_FREE(*ppDev); } } utarray_free(_ptComCtrl->m_pMutiDevArray); } //Rd_SemDestroy(&_ptComCtrl->m_stComBuf.m_sem_Recv); Rd_SemDestroy(&_ptComCtrl->m_stComBuf.m_sem_Send); rd_RingbufferDestroy(_ptComCtrl->m_stComBuf.m_ptRecv); rd_RingbufferDestroy(_ptComCtrl->m_stComBuf.m_ptSend); RD_FREE(_ptComCtrl); return RD_SUCCESS; } /***************************************************************************** 函 数 名 : rd_ComSend 功能描述 : 直接发送函数(尽量不要要和rd_ComSendProc同时使用,除非做好竞态处理) 输入参数 : TComCtrl *_ptComCtrl char *_pBuffer uint32_t _iSize 输出参数 : 无 返 回 值 : int 调用函数 : 被调函数 : 修改历史 : 1.日 期 : 2026年4月24日 作 者 : radkil 修改内容 : 新生成函数 *****************************************************************************/ int rd_ComSend(TComCtrl *_ptComCtrl, char *_pBuffer, uint32_t _iSize) { if (NULL == _ptComCtrl || NULL == _ptComCtrl->m_pfSend) return RD_NULL; return _ptComCtrl->m_pfSend(_pBuffer, _iSize); } /***************************************************************************** 函 数 名 : rd_ComSendProc 功能描述 : 异步发送轮询(建议不要和rd_ComSend同时使用- ) 输入参数 : TComCtrl *_ptComCtrl 输出参数 : 无 返 回 值 : void 调用函数 : 被调函数 : 修改历史 : 1.日 期 : 2026年4月24日 作 者 : radkil 修改内容 : 新生成函数 *****************************************************************************/ void rd_ComSendProc(TComCtrl *_ptComCtrl) { if (NULL == _ptComCtrl) return; char *pcBuffer = RD_CALLOC(1, _ptComCtrl->m_iBufferSize);; int iRet = 0; Rd_SemWait(&_ptComCtrl->m_stComBuf.m_sem_Send, __func__, NULL); iRet = rd_RingbufferGet(_ptComCtrl->m_stComBuf.m_ptSend, pcBuffer, _ptComCtrl->m_iBufferSize); if (iRet > 0) { rd_ComSend(_ptComCtrl, pcBuffer, iRet); } RD_FREE(pcBuffer); } void rd_ComRecvProc(TComCtrl *_ptComCtrl, const char *_pBuffer, uint32_t _iSize) { if (NULL == _ptComCtrl) return; int iRet = rd_RingbufferPutForce(_ptComCtrl->m_stComBuf.m_ptRecv, _pBuffer, _iSize); if (iRet > 0) { Rd_SemPost(&_ptComCtrl->m_stComBuf.m_sem_Recv, __func__, NULL); } } int rd_ComWrite(TComCtrl *_ptComCtrl, char *_pBuffer, uint32_t _iSize) { if (NULL == _ptComCtrl) return RD_INVALUE; int iRet = rd_RingbufferPutForce(_ptComCtrl->m_stComBuf.m_ptSend, _pBuffer, _iSize); if (iRet > 0) { Rd_SemPost(&_ptComCtrl->m_stComBuf.m_sem_Send, __func__, NULL); } return iRet; } //static int rd_MutiDevIsconflict(TComCtrl *_ptComCtrl, char *_pBuffer, uint32_t _iSize, int _MyIdx) //{ // int iArrlen = utarray_len(_ptComCtrl->m_pMutiDevArray); // for(int i = 0; i < iArrlen; i++) // { // TMutiDev **ppMutiDev = (TMutiDev**)utarray_eltptr(_ptComCtrl->m_pMutiDevArray, i); // TMutiDev *ptMutiDev = *ppMutiDev; // if (i == _MyIdx) continue; // // int result = ptMutiDev->m_pfCheck(_pBuffer, _iSize); // if (result > 0) // { // return i; // } // } // return RD_NULL; //} /***************************************************************************** 函 数 名 : rd_ComRead 功能描述 : 读取一包数据,这里的入参用于存放校验通过的数据,如果buffer实际大小 过小会导致数据被截断,请确保分配足够大的buffer用于存放一包数据。当 然,你也可以选择在decode里做逻辑,这里不做限制。 输入参数 : TComCtrl *_ptComCtrl char *_pBuffer uint32_t _iSize 输出参数 : 无 返 回 值 : int 大于零表示数据长度,等于零表示外层需要继续处理,小于0表示异常 调用函数 : 被调函数 : 修改历史 : 1.日 期 : 2026年4月24日 作 者 : radkil 修改内容 : 新生成函数 *****************************************************************************/ int rd_ComRead(TComCtrl *_ptComCtrl, char *_pBuffer, uint32_t _iSize) { if (NULL == _ptComCtrl || NULL == _pBuffer || 0 == _iSize) { return RD_INVALUE; } uint32_t u32CurrentTime = Rd_GetTime(); Rd_SemWait(&_ptComCtrl->m_stComBuf.m_sem_Recv, __func__, NULL); char *pPeakData = NULL; int iPeakLen = rd_RingbufferPeak(_ptComCtrl->m_stComBuf.m_ptRecv, &pPeakData); if (iPeakLen < 0) { return RD_FAILURE; } else if (0 == iPeakLen) { return 0; } int iPackLen = 1; int iArrlen = utarray_len(_ptComCtrl->m_pMutiDevArray); if (_ptComCtrl->m_iDevIndex < 0) { int bFound = 0; // 标记是否找到 int bDataValid = 0; // 标记数据是否有效(即使不完整,只要有协议认领,就不能丢) for(int i = 0; i < iArrlen; i++) { TMutiDev **ppMutiDev = (TMutiDev**)utarray_eltptr(_ptComCtrl->m_pMutiDevArray, i); TMutiDev *ptMutiDev = *ppMutiDev; if (NULL != ptMutiDev->m_pfCheck) { iPackLen = ptMutiDev->m_pfCheck(pPeakData, iPeakLen); } if (iPackLen > 0 && iPackLen <= iPeakLen) { _ptComCtrl->m_iDevIndex = i; bFound = 1; bDataValid = 1; break; // 找到了就退出循环,去下面处理 } else if(0 == iPackLen) { if (ptMutiDev->m_uiLastRecvTime == 0) { ptMutiDev->m_uiLastRecvTime = u32CurrentTime; } if ((u32CurrentTime - ptMutiDev->m_uiLastRecvTime) > RECV_TIMEOUT) { char temp[1]; rd_RingbufferGet(_ptComCtrl->m_stComBuf.m_ptRecv, temp, 1); // 丢弃旧数据 // 重置该设备的时间戳,准备迎接下一次可能的通信 ptMutiDev->m_uiLastRecvTime = 0; bDataValid = 0; } else { bDataValid = 1; } } } // 如果遍历完所有设备都没找到包头 if (!bFound) { // 只有当所有协议都觉得这个字节没用 (bDataValid == 0) 时,才丢弃 if (!bDataValid) { char temp[1]; rd_RingbufferGet(_ptComCtrl->m_stComBuf.m_ptRecv, temp, 1); // 丢弃无效字节 return RD_FAILURE; } else { // 有协议认领了数据(返回了0),只是还没收完 // 此时直接返回 0,让主循环稍后重试 return 0; } } } if (_ptComCtrl->m_iDevIndex >= 0) { if (_ptComCtrl->m_iDevIndex >= iArrlen) { _ptComCtrl->m_iDevIndex = -1; return RD_FAILURE; } TMutiDev **ppMutiDev = (TMutiDev**)utarray_eltptr(_ptComCtrl->m_pMutiDevArray, _ptComCtrl->m_iDevIndex); TMutiDev *ptMutiDev = *ppMutiDev; if (NULL != ptMutiDev->m_pfCheck) { iPackLen = ptMutiDev->m_pfCheck(pPeakData, iPeakLen); } // if (rd_MutiDevIsconflict(_ptComCtrl, pPeakData, iPeakLen, _ptComCtrl->m_iDevIndex) >= 0) // { // _ptComCtrl->m_iDevIndex = -1; // char temp[1]; // rd_RingbufferGet(_ptComCtrl->m_stComBuf.m_ptRecv, temp, 1); // return RD_FAILURE; // } if (iPackLen > 0 && iPackLen <= iPeakLen) { int iLen = (_iSize > iPackLen) ? iPackLen : _iSize; int iRet = rd_RingbufferGet(_ptComCtrl->m_stComBuf.m_ptRecv, _pBuffer, iLen); if (iRet > 0) { _ptComCtrl->m_iDevIndex = -1; if(NULL != ptMutiDev->m_pfDecode) { ptMutiDev->m_uiLastRecvTime = 0; ptMutiDev->m_pfDecode(_pBuffer, iLen); } return iRet; } else { _ptComCtrl->m_iDevIndex = -1; return RD_FAILURE; } } else { // 长度错误或异常 char temp[1]; rd_RingbufferGet(_ptComCtrl->m_stComBuf.m_ptRecv, temp, 1); _ptComCtrl->m_iDevIndex = -1; return RD_FAILURE; } } return 0; }