/** * 日期: 2025-08-26 * 作者: coffee * 描述: 调度协议, 用于多数据口接收数据和发送数据后回复数据临时调度回来 */ #ifndef __HD_PROTOCOL_SERVER_H__ #define __HD_PROTOCOL_SERVER_H__ #include "HRingBuffer.h" #include #ifndef __COUNT_ARGS_IMPL #define __COUNT_ARGS_IMPL(_, _1, _2, _3, _4, _5, _6, _7, _8, _9, N, ...) N #endif #ifndef __COUNT_ARGS #define __COUNT_ARGS(...) __COUNT_ARGS_IMPL(dummy, ##__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) #endif /** * demo: * 1. 设置调度回调函数 HDProtocolSetCallback(HScheduleCallback callback); * 2. 注册调度数据信息数组 HDProtocolRegisterInfo(HDProtocolServerInfo *info, uint8_t src, void *data, int dataLen); * 3. HDProtocolRun(); */ // 再次发送超时时间 #define HDPROTOCOL_DELAY_TIMEOUT (100) // 数据占用时间 #define HDPROTOCOL_OCCUPY_TIMEOUT (1000) enum eHDProtocolSupport { kHDProtocolNone = 0x00, ///< 无协议, 不阻塞等待 kHDProtocolFpga = 0x01, ///< fpga协议, 独占解析端 kHDProtocolVP = 0x02, ///< vp协议, 独占解析端 kHDProtocolTV = 0x04, ///< tv协议 }; /** * @brief 协议信息结构 * @note 协议信息结构里面的buffer需要用户自己分配内存, 通过 HDProtocolInitInfo 初始化传递内存 * 用户只需要读取环状缓冲区即可 */ typedef struct __attribute__((__packed__)) HDProtocolServerInfo { HRingBufferType *readBuff; ///< 读取环状缓冲区, 内存需要用户调用 HDProtocolInitInfo 提供, 最低需要 sizeof(_HRingBufferBase) + 1 的空间 uint8_t supportProtocol; ///< 支持的协议, 用于解析端选择, 避免多路口同时解析 uint8_t src; ///< 源数据口 uint8_t dst; ///< 目标数据口(如果需要始终转发可以修改该项目, 否则默认和src一样) uint8_t tmpDst; ///< 临时回送目标数据口(用于该指令需要先请求某个数据后才能回复的情况) uint8_t tmpReadCount : 5; ///< 临时数据最大等待回复次数 uint8_t tmpEnable : 1; ///< 当前临时目标等待数据, 需要等待数据内部标记开启, 数据完成或者超时后自动关闭 uint8_t run : 1; ///< 内部标记当前正常读取, 如果再次触发解析, 则不等待 uint8_t checkAlarm : 1; ///< 启动缓存报警检查 uint8_t notifyAlarm : 1; ///< 通知缓存报警(内部管理) uint8_t occupy : 1; ///< 内部标记当前正在占用 uint8_t delayCount : 6; ///< 延时等待次数(默认: 1), 每次等待时间为 HSCHEDULE_DELAY_TIMEOUT } HDProtocolServerInfo; /** * @brief 读取回调函数 * @param info 协议信息 * param isTimeout 是否超时, 1: 表示当前数据已经超时, 协议需要重置让渡给其他解析, 0: 表示当前数据未超时 * @return 返回协议解析长度, 返回0表示解析结束 */ typedef int (*HDProtocolReadCallback)(HDProtocolServerInfo *info, uint8_t isTimeout); typedef void (*HDProtocolWriteCallback)(HDProtocolServerInfo *info, const uint8_t *data, int len); typedef void (*HDProtocolCheckAlarmCallback)(HDProtocolServerInfo *info); /** * @brief 设置协议回调函数 * @param readCall 读取回调函数 * @param writeCall 写入回调函数 */ void HDProtocolSetCallback(HDProtocolReadCallback readCall, HDProtocolWriteCallback writeCall); /** * @brief 设置缓冲区报警回调, 需要立刻返回, 不能阻塞 * @param checkCall 检查缓冲区报警回调函数 */ void HDProtocolCheckAlarmCall(HDProtocolCheckAlarmCallback checkCall); /** * @brief 初始化协议信息结构, 将原始缓冲器转换成环状缓冲区(需要消耗一些字节) * @param info 协议信息结构 * @param src 源数据口和目标数据口 * @param data 原始缓冲区 * @param dataLen 原始缓冲区长度 */ void HDProtocolInitInfo(HDProtocolServerInfo *info, uint8_t src, void *data, int dataLen); /** * @brief 设置支持的协议 * @param info 协议信息结构 * @param len 支持的协议个数 * @param ... 支持的协议 */ void _HDProtocolSetSupportProtocol(HDProtocolServerInfo *info, int len, ...); #define HDProtocolSetSupportProtocol(info, ...) _HDProtocolSetSupportProtocol(info, __COUNT_ARGS(__VA_ARGS__), ##__VA_ARGS__) /** * @brief 注册协议信息 * @param info 协议信息结构 * @param len 协议信息结构长度 */ void HDProtocolRegisterInit(HDProtocolServerInfo *info, int len); /** * @brief 根据当前路由发送(用于解析数据后回送数据, 如果不是读取回调的时候调用, 则找不到对应路由报错, 返回0) * @param data 发送数据 * @param len 发送数据长度 * @return 发送成功返回1 失败返回0 */ uint8_t HDProtocolCurrSend(const void *data, int len); /** * @brief 根据目标数据口发送 * @param dst 需要往那个目标数据口发送 * @param data 发送数据 * @param len 发送数据长度 */ void HDProtocolSendPort(uint8_t dst, const void *data, int len); /** * @brief 临时路由发送(用于发送目标端口的数据后, 解析端临时更改目标端口, 通过 HDProtocolGetDest 获取目标端口) * @param src 发送源端口 * @param dst 回送后需要转发到的目标端口 * @param data 发送数据 * @param len 发送数据长度 * @param needReadCount 需要读取次数 * @param waitCount 等待次数 */ void HDProtocolTmpSend(uint8_t src, uint8_t dst, const void *data, int len, uint8_t needReadCount, uint8_t waitCount); /** * @brief 获取目标数据口 * @param info 协议信息 * @return 目标数据口 */ uint8_t HDProtocolGetDest(HDProtocolServerInfo *info); /** * @brief 获取当前协议信息 * @return 当前协议信息 */ HDProtocolServerInfo *HDProtocolGetCurrInfo(); /** * @brief 告知服务当前对应源端读取数据 * @param src 源数据口 * @param data 读取数据 * @param len 读取数据长度 */ void HDProtocolRead(uint8_t src, const void *data, int len); /** * @brief 运行调度协议 */ void HDProtocolRun(); #endif // __HD_PROTOCOL_SERVER_H__