421 lines
11 KiB
C
421 lines
11 KiB
C
|
|
|
|
#include "HDProtocolServer.h"
|
|
#include "HRingBuffer.h"
|
|
// #include "src/sys/inc/HDSystemTask.h"
|
|
#include "HDLog.h"
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
|
|
|
|
#ifndef HDDelayMs
|
|
#define HDDelayMs(ms)
|
|
#endif
|
|
|
|
// 占用信息监测, 需要大于协议数量
|
|
#define OCCUPIED_MAX (10)
|
|
|
|
|
|
struct __attribute__((__packed__)) OccupiedInfo {
|
|
uint32_t occupyTime; ///< 当前数据占用时间(ms), 用于超时
|
|
uint8_t protocol; ///< 占用的协议
|
|
uint8_t index; ///< 占用的索引
|
|
uint8_t enbale : 1; ///< 是否占用
|
|
uint8_t waitOccupy : 1; ///< 是否等待占用
|
|
};
|
|
|
|
struct __attribute__((__packed__)) HScheduleRegisterInfo {
|
|
HDProtocolReadCallback readCall; ///< 读取回调
|
|
HDProtocolWriteCallback writeCall; ///< 写入回调
|
|
HDProtocolCheckAlarmCallback checkAlarmCall; ///< 检查缓冲区报警回调
|
|
HDProtocolServerInfo *info; ///< 协议信息
|
|
uint8_t infoLen; ///< 协议信息长度
|
|
uint8_t useIndex; ///< 当前使用的索引
|
|
};
|
|
|
|
static struct HScheduleRegisterInfo sInfo;
|
|
static struct OccupiedInfo sOccupiedInfo[OCCUPIED_MAX];
|
|
|
|
// 判断当前协议是否占用
|
|
static uint8_t IsOccupied(uint8_t currIndex, uint8_t protocol, uint8_t *occupiedIndex)
|
|
{
|
|
if (currIndex >= OCCUPIED_MAX) {
|
|
LogE("index[%d] out of range[%d]", currIndex, OCCUPIED_MAX);
|
|
return 0;
|
|
}
|
|
|
|
for (int i = 0; i < OCCUPIED_MAX; ++i) {
|
|
if (sOccupiedInfo[i].enbale == 0) {
|
|
continue;
|
|
}
|
|
|
|
if ((sOccupiedInfo[i].protocol & protocol) == 0) {
|
|
continue;
|
|
}
|
|
|
|
// 占用索引
|
|
if (occupiedIndex != NULL) {
|
|
*occupiedIndex = i;
|
|
}
|
|
|
|
if (sOccupiedInfo[i].index == currIndex) {
|
|
return 0;
|
|
}
|
|
|
|
// 被其他协议占用
|
|
sOccupiedInfo[i].waitOccupy = 1;
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void SetOccupied(uint8_t currIndex, uint8_t protocol, uint8_t enable)
|
|
{
|
|
if (currIndex >= OCCUPIED_MAX) {
|
|
LogE("index[%d] out of range[%d]", currIndex, OCCUPIED_MAX);
|
|
return ;
|
|
}
|
|
|
|
uint8_t index = OCCUPIED_MAX;
|
|
for (int i = 0; i < OCCUPIED_MAX; ++i) {
|
|
if (sOccupiedInfo[i].enbale == 0) {
|
|
if (index == OCCUPIED_MAX) {
|
|
index = i;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
// 检查当前索引是否已经使用占用
|
|
if (sOccupiedInfo[i].index != currIndex) {
|
|
continue;
|
|
}
|
|
|
|
// 如果是关闭的直接关闭掉
|
|
if (enable == 0) {
|
|
sOccupiedInfo[i].enbale = 0;
|
|
sOccupiedInfo[i].index = 0;
|
|
sOccupiedInfo[i].protocol = 0;
|
|
sOccupiedInfo[i].occupyTime = 0;
|
|
sOccupiedInfo[i].waitOccupy = 0;
|
|
|
|
sInfo.info[currIndex].occupy = 0;
|
|
return ;
|
|
}
|
|
|
|
sOccupiedInfo[i].protocol = protocol;
|
|
sOccupiedInfo[i].occupyTime = HDLogGetTime();
|
|
return ;
|
|
}
|
|
|
|
if (enable == 0 || index == OCCUPIED_MAX) {
|
|
return ;
|
|
}
|
|
|
|
sOccupiedInfo[index].enbale = 1;
|
|
sOccupiedInfo[index].index = currIndex;
|
|
sOccupiedInfo[index].protocol = protocol;
|
|
sOccupiedInfo[index].occupyTime = HDLogGetTime();
|
|
|
|
sInfo.info[currIndex].occupy = 1;
|
|
}
|
|
|
|
static void WaitRead(HDProtocolServerInfo *info)
|
|
{
|
|
if (info->tmpEnable == 0) {
|
|
return ;
|
|
}
|
|
|
|
for (int i = 0; i < info->delayCount; ++i) {
|
|
uint32_t curr = HDLogGetTime();
|
|
for (int j = 0; j < HDPROTOCOL_DELAY_TIMEOUT; ++j) {
|
|
HDProtocolRun();
|
|
if (info->tmpEnable == 0) {
|
|
break;
|
|
}
|
|
|
|
// 读取数据的时候触发的紧急读取不要去睡眠
|
|
if (info->run == 0) {
|
|
HDDelayMs(1);
|
|
}
|
|
|
|
if (HDLogGetTime() - curr >= HDPROTOCOL_DELAY_TIMEOUT) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (info->tmpEnable == 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (info->tmpEnable) {
|
|
LogD("wait tmp read not recv[%d]", info->src);
|
|
}
|
|
|
|
info->tmpEnable = 0;
|
|
}
|
|
|
|
static void ParseReadData(int index, int isTimeout)
|
|
{
|
|
sInfo.useIndex = index;
|
|
const int len = sInfo.readCall(&sInfo.info[index], isTimeout);
|
|
sInfo.useIndex = sInfo.infoLen;
|
|
// 当前在中断, 且自身处于占用状态, 立刻返回
|
|
if (sInfo.info[index].run && sInfo.info[index].occupy) {
|
|
return ;
|
|
}
|
|
|
|
sInfo.info[index].notifyAlarm = 0;
|
|
if (len == 0 && sInfo.info[index].tmpEnable) {
|
|
// 临时路由转发数据
|
|
if (sInfo.info[index].tmpReadCount > 0) {
|
|
--sInfo.info[index].tmpReadCount;
|
|
}
|
|
|
|
if (sInfo.info[index].tmpReadCount == 0) {
|
|
sInfo.info[index].tmpEnable = 0;
|
|
}
|
|
}
|
|
|
|
if (isTimeout) {
|
|
sInfo.info[index].tmpEnable = 0;
|
|
}
|
|
|
|
SetOccupied(index, sInfo.info[index].supportProtocol, len == 0 ? 0 : 1);
|
|
}
|
|
|
|
void HDProtocolSetCallback(HDProtocolReadCallback readCall, HDProtocolWriteCallback writeCall)
|
|
{
|
|
sInfo.readCall = readCall;
|
|
sInfo.writeCall = writeCall;
|
|
}
|
|
|
|
void HDProtocolCheckAlarmCall(HDProtocolCheckAlarmCallback checkCall)
|
|
{
|
|
sInfo.checkAlarmCall = checkCall;
|
|
}
|
|
|
|
void HDProtocolInitInfo(HDProtocolServerInfo *info, uint8_t src, void *data, int dataLen)
|
|
{
|
|
if (info == NULL) {
|
|
return ;
|
|
}
|
|
|
|
memset(info, 0, sizeof(HDProtocolServerInfo));
|
|
info->readBuff = data;
|
|
HRingbufferInit8(info->readBuff, dataLen);
|
|
info->delayCount = 1;
|
|
info->src = src;
|
|
info->dst = src;
|
|
}
|
|
|
|
void _HDProtocolSetSupportProtocol(HDProtocolServerInfo *info, int len, ...)
|
|
{
|
|
if (info == NULL) {
|
|
return;
|
|
}
|
|
|
|
va_list args;
|
|
va_start(args, len);
|
|
for (int i = 0; i < len; ++i) {
|
|
info->supportProtocol |= va_arg(args, int);
|
|
}
|
|
|
|
va_end(args);
|
|
}
|
|
|
|
|
|
void HDProtocolRegisterInit(HDProtocolServerInfo *info, int len)
|
|
{
|
|
sInfo.info = info;
|
|
sInfo.infoLen = len;
|
|
sInfo.useIndex = sInfo.infoLen;
|
|
}
|
|
|
|
uint8_t HDProtocolCurrSend(const void *data, int len)
|
|
{
|
|
if (data == NULL || len == 0) {
|
|
return 0;
|
|
}
|
|
|
|
HDProtocolServerInfo *info = HDProtocolGetCurrInfo();
|
|
if (info == NULL) {
|
|
LogD("curr not read call");
|
|
return 0;
|
|
}
|
|
|
|
WaitRead(info);
|
|
sInfo.writeCall(info, (const uint8_t *)data, len);
|
|
return 1;
|
|
}
|
|
|
|
void HDProtocolSendPort(uint8_t dst, const void *data, int len)
|
|
{
|
|
if (data == NULL || len == 0) {
|
|
return;
|
|
}
|
|
|
|
if (sInfo.writeCall == NULL || sInfo.info == NULL) {
|
|
return;
|
|
}
|
|
|
|
if (dst >= sInfo.infoLen) {
|
|
LogE("index[%d] is out of range[%d]", dst, sInfo.infoLen);
|
|
return;
|
|
}
|
|
|
|
WaitRead(&sInfo.info[dst]);
|
|
sInfo.writeCall(&sInfo.info[dst], (const uint8_t *)data, len);
|
|
}
|
|
|
|
void HDProtocolTmpSend(uint8_t src, uint8_t dst, const void *data, int len, uint8_t needReadCount, uint8_t waitCount)
|
|
{
|
|
if (data == NULL || len == 0) {
|
|
return;
|
|
}
|
|
|
|
if (sInfo.writeCall == NULL || sInfo.info == NULL) {
|
|
return;
|
|
}
|
|
|
|
if (src >= sInfo.infoLen) {
|
|
LogE("index[%d] is out of range[%d]", src, sInfo.infoLen);
|
|
return;
|
|
}
|
|
|
|
WaitRead(&sInfo.info[src]);
|
|
sInfo.info[src].tmpEnable = 1;
|
|
sInfo.info[src].tmpDst = dst;
|
|
sInfo.info[src].delayCount = waitCount;
|
|
sInfo.info[src].tmpReadCount = needReadCount;
|
|
sInfo.writeCall(&sInfo.info[src], (const uint8_t *)data, len);
|
|
}
|
|
|
|
uint8_t HDProtocolGetDest(HDProtocolServerInfo *info)
|
|
{
|
|
if (info == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
if (info->tmpEnable && info == HDProtocolGetCurrInfo()) {
|
|
return info->tmpDst;
|
|
}
|
|
|
|
return info->dst;
|
|
}
|
|
|
|
HDProtocolServerInfo *HDProtocolGetCurrInfo()
|
|
{
|
|
if (sInfo.useIndex >= sInfo.infoLen) {
|
|
return NULL;
|
|
}
|
|
|
|
return &sInfo.info[sInfo.useIndex];
|
|
}
|
|
|
|
void HDProtocolRead(uint8_t src, const void *data, int len)
|
|
{
|
|
if (sInfo.readCall == NULL || sInfo.info == NULL) {
|
|
return;
|
|
}
|
|
|
|
if (src >= sInfo.infoLen) {
|
|
LogE("index[%d] is out of range[%d]", src, sInfo.infoLen);
|
|
return;
|
|
}
|
|
|
|
if (sInfo.info[src].readBuff == NULL) {
|
|
LogE("readBuff is NULL");
|
|
return;
|
|
}
|
|
|
|
const uint8_t *srcData = (const uint8_t *)data;
|
|
uint8_t occupy = 0xff;
|
|
sInfo.info[src].run = 1;
|
|
for (int i = 0; i < len; ++i) {
|
|
if (HRingBufferFull(sInfo.info[src].readBuff)) {
|
|
// 当自身处于未占用时, 需要检查一次
|
|
if (sInfo.info[src].occupy == 0) {
|
|
occupy = IsOccupied(src, sInfo.info[src].supportProtocol, NULL);
|
|
}
|
|
|
|
// 自身处于占用状态或者当前可占用时执行读取
|
|
if (sInfo.info[src].occupy || occupy == 0) {
|
|
ParseReadData(src, 0);
|
|
}
|
|
}
|
|
|
|
HRingBufferAddDataOver(sInfo.info[src].readBuff, srcData[i]);
|
|
}
|
|
|
|
// 协议开启缓存报警检测时, 且未通知过
|
|
if (sInfo.info[src].checkAlarm && sInfo.info[src].notifyAlarm == 0 && sInfo.checkAlarmCall) {
|
|
const HRingBufferLenType readLen = HRingBufferGetUseByteLen(sInfo.info[src].readBuff);
|
|
const HRingBufferLenType buffLen = HRingBufferGetLen(sInfo.info[src].readBuff) >> 1;
|
|
if (readLen >= buffLen) {
|
|
// 只通知一次, 读取数据后再次检查
|
|
sInfo.info[src].notifyAlarm = 1;
|
|
sInfo.checkAlarmCall(&sInfo.info[src]);
|
|
}
|
|
}
|
|
sInfo.info[src].run = 0;
|
|
}
|
|
|
|
void HDProtocolRun()
|
|
{
|
|
if (sInfo.readCall == NULL || sInfo.info == NULL) {
|
|
return;
|
|
}
|
|
|
|
for (int i = 0; i < sInfo.infoLen; ++i) {
|
|
if (HRingBufferEmpty(sInfo.info[i].readBuff)) {
|
|
continue;
|
|
}
|
|
|
|
// 正在解析使用的协议触发的协议运转, 不要继续重叠处理
|
|
if (i == sInfo.useIndex) {
|
|
continue;
|
|
}
|
|
|
|
if (i >= OCCUPIED_MAX) {
|
|
LogE("index[%d] is out of range[%d]", i, OCCUPIED_MAX);
|
|
break;
|
|
}
|
|
|
|
// 有之前的数据已经占用了, 并且检查是否超时
|
|
uint8_t occupiedIndex = OCCUPIED_MAX;
|
|
if (IsOccupied(i, sInfo.info[i].supportProtocol, &occupiedIndex)) {
|
|
if (occupiedIndex >= OCCUPIED_MAX) {
|
|
LogE("occupiedIndex[%d] is out of range[%d]", occupiedIndex, OCCUPIED_MAX);
|
|
continue;
|
|
}
|
|
|
|
// 解析被占用, 检查超时
|
|
if (HDLogGetTime() - sOccupiedInfo[occupiedIndex].occupyTime <= HDPROTOCOL_OCCUPY_TIMEOUT) {
|
|
continue;
|
|
}
|
|
|
|
// 通知协议超时, 数据清空
|
|
ParseReadData(occupiedIndex, 1);
|
|
|
|
// 如果还占用, 说明用户那边自己要求继续占用
|
|
if (IsOccupied(i, sInfo.info[i].supportProtocol, &occupiedIndex)) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
uint8_t waitTime = 0;
|
|
if (occupiedIndex < OCCUPIED_MAX && sOccupiedInfo[occupiedIndex].waitOccupy) {
|
|
// 还有其他协议等待抢占, 检查时间
|
|
if (HDLogGetTime() - sOccupiedInfo[occupiedIndex].occupyTime > HDPROTOCOL_OCCUPY_TIMEOUT) {
|
|
waitTime = 1;
|
|
}
|
|
}
|
|
|
|
ParseReadData(i, waitTime);
|
|
}
|
|
}
|
|
|