You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
390 lines
13 KiB
390 lines
13 KiB
|
3 days ago
|
/******************************************************************************
|
||
|
|
|
||
|
|
版权所有 (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;
|
||
|
|
}
|
||
|
|
|