HCoreBase/src/HDProtocolServer.c

415 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;
}
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 >= 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);
}
}