freeRTOS操作系统机器人实现
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.
 
 
 
 

389 lines
13 KiB

/******************************************************************************
版权所有 (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;
}