HCoreBase/include/HDRPC.h
coffee 507c72cb98 1. 完善RPC
2. 修复协议调度的重叠问题
2025-11-25 11:17:01 +08:00

339 lines
11 KiB
C

/**
* 日期: 2025-09-04
* 作者: coffee
* 描述: ARM和MCU交互通信模块
* demo:
* 首次需要先初始化RPC调用
* HDRPCInitCall(发送回调, 存储RPC回调缓存, 回调缓存长度, 读取RPC会话);
* 读取数据:
* HDRPCReadData(...);
* 发送调用
* HDRPCSendData(sesion, 枚举值, 回调函数);
* 不需要回调
* HDRPCSendDataNotCall(sesion, 枚举值);
*/
#ifndef __HDRPC_H__
#define __HDRPC_H__
#include <stdint.h>
#include <string.h>
// 设置超时时间
#ifndef HDRPC_TIMEOUT
#define HDRPC_TIMEOUT 3000
#endif
// 如果使用栈参数解析, 则最大支持的参数个数
#ifndef HDRPC_USE_SESSION_ARGS
#define HDRPC_USE_SESSION_ARGS (0)
#endif
// 使用64位
#define HDRPC_USE_64
// 数值类型
#ifdef HDRPC_USE_64
typedef uint64_t HDRPCValue_t;
#else
typedef uint32_t HDRPCValue_t;
#endif
// 发送后配置索引id
typedef int16_t HDRPCIndexId_t;
/**
* 类型数据, 多节字节按照大端解析:
* 0x00: 用户数据, 数据首个字节为长度
* 0x01: u8
* 0x02: u16
* 0x03: u32
* 0x04: u64(保留扩展)
* 0x10: 字符串/缓冲数据, 数据首个字节为长度
* 0x11: UTF-16BE字符串, 数据首个字节为长度
* 0x20: 异常类型, u16类型
*/
enum eHDRPCType
{
kHDRPCUserData = 0x00, ///< 用户数据
kHDRPCU8 = 0x01, ///< u8
kHDRPCU16 = 0x02, ///< u16
kHDRPCU32 = 0x03, ///< u32
kHDRPCU64 = 0x04, ///< u64(保留扩展, 不使用)
kHDRPCBuffer = 0x10, ///< 字符串/缓冲数据, 数据首个字节为长度
kHDRPCString = 0x11, ///< UTF-16BE字符串, 数据首个字节为长度
kHDRPCException = 0x20, ///< 异常, u16
};
// 协议异常指令
enum eHDRPCException {
kHDRPCNotException = 0x00, ///< 无异常
kHDRPCNotSupportFunction = 0x01, ///< 对应功能不支持
kHDRPCArgsTypeNotMatch = 0x02, ///< 参数类型不匹配
kHDRPCNotReply = 0x03, ///< 无回复
};
typedef struct __attribute__((packed)) _HDRPCBuffer
{
uint8_t len; ///< 数据长度
uint8_t *data; ///< 数据
} _HDRPCBuffer;
///< 参数包
typedef struct __attribute__((packed)) HDRPCArgs
{
uint8_t type; ///< 类型数据
union __attribute__((packed))
{
uint8_t dataU8;
uint16_t dataU16;
uint32_t dataU32;
#ifdef HDRPC_USE_64
uint64_t dataU64;
#endif
_HDRPCBuffer buffer;
};
} HDRPCArgs;
typedef struct HDRPCSession
{
uint16_t func; ///< 调用功能, 用于解析数据得到
uint8_t index; ///< 当前添加到的参数索引
uint8_t exceptionNotSkip: 1; ///< 异常时跳过调用回调(默认0: 不调用回调, 1: 调用回调)
uint8_t len : 7; ///< 参数总长度
HDRPCArgs *args; ///< 参数
} HDRPCSession;
// 此宏用于其他回调的参数声明
#define HDRPC_CALL_ARGS HDRPCSession *_session, uint8_t _exception
#define HDRPC_CALL_ARG_SESSION _session
#define HDRPC_CALL_ARG_EXCEPTION _exception
#define HDRPC_IS_EXCEPTION() (exception != kHDRPCNotException)
// 发送RPC后得到数据的回调
typedef void (*HDRPCCallback)(HDRPCSession *session, uint8_t exception);
// 发送RPC数据到对端
typedef void (*HDRPCSendDataCall)(HDRPCSession *session);
// 对端发送RPC数据到本地端解析后的处理
typedef void (*HDRPCReadDataCall)(HDRPCSession *session);
// 超时回调
typedef void (*HDRPCTimeoutCall)();
// 调用缓存, 内存由用户提供
typedef struct __attribute__((packed)) HDRPCCallBuffer {
uint32_t enbale : 1; ///< 是否启用
uint32_t skipExce : 1; ///< 跳过异常
uint32_t nameLen : 6; ///< 函数名长度
#ifdef HDRPC_TIMEOUT
uint32_t isTimeout : 1; ///< 已经超时
uint32_t delayMs : 23; ///< 等待超时时间(ms)
#endif
uint16_t funcCode; ///< 功能码
uint32_t lastTime; ///< 上次调用时间
const char *name; ///< 函数名
HDRPCCallback callback; ///< 回调
#ifdef HDRPC_TIMEOUT
HDRPCTimeoutCall timeout; ///< 超时回调, 不为空时, 调用后释放
#endif
} HDRPCCallBuffer;
#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
/**
* @brief 初始化RPC会话
* @param session 参数会话
* @param args 参数包, 用于存储参数
* @param len 参数会话长度
*/
void HDRPCInitSession(HDRPCSession *session, HDRPCArgs *args, uint8_t len);
/**
* @brief 初始化RPC调用
* @param sendCall 发送数据回调
* @param callBuff 回调缓存, 用于可注册RPC回调数量, 必须提供对应的内存, 如为空则无回调
* @param callLen 回调缓存长度
* @param buffer 读取的RPC会话(如果不传递则使用栈分配)
*/
void HDRPCInitCall(HDRPCSendDataCall sendCall, HDRPCCallBuffer *callBuff, uint8_t callLen, HDRPCSession *buffer);
/**
* @brief 初始化对端RPC调用本地
* @param readCall 读取数据完成后的回调处理对于功能
* @param buffer 读取的RPC会话(如果不传递则使用栈分配)
*/
void HDRPCInitReadCall(HDRPCReadDataCall readCall, HDRPCSession *session);
/**
* @brief 设置异常时是否跳过回调
* @param session 参数会话
* @param enable 是否跳过
*/
void HDRPCSetExceptionNotSkip(HDRPCSession *session, uint8_t enable);
/**
* @brief 使用这个来创建栈内参数包, 内部自增一个用于存储内部回调数据
* @param _name 参数包名称
* @param _len 参数包长度
*/
#define HDRPCCreate(_name, _len) HDRPCArgs _args##_name[_len + 1]; HDRPCSession _session##_name; HDRPCInitSession(&_session##_name, _args##_name, _len + 1); HDRPCSession *_name = &_session##_name
#define HDRPCResetN(_name, _len) HDRPCInitSession(&_session##_name, _args##_name, _len + 1)
#define HDRPCReset(_name) HDRPCInitSession(&_session##_name, _args##_name, (sizeof(_args##_name) / sizeof(_args##_name[0])))
/**
* @brief 用于辅助宏添加数据到session
* @param session RPC参数会话
* @param type 数据类型
* @param args 数据
* @param len 数据长度
* @return 1成功, 0失败
*/
uint8_t _HDRPCAddArgs(HDRPCSession *session, uint8_t type, void *args, uint8_t len);
#define _HDRPCAdd(session, type, key, ...) do {type __args[] = {__VA_ARGS__}; _HDRPCAddArgs(session, key, __args, sizeof(__args) / sizeof(__args[0])); } while (0)
#define _HDRPCUseAdd(session, type, ...) _HDRPCAdd((session), uint##type##_t, kHDRPCU##type, __VA_ARGS__)
/**
* @brief 添加参数到会话
*/
#define HDRPCAddU8(session, ...) _HDRPCUseAdd(session, 8, __VA_ARGS__)
#define HDRPCAddU16(session, ...) _HDRPCUseAdd(session, 16, __VA_ARGS__)
#define HDRPCAddU32(session, ...) _HDRPCUseAdd(session, 32, __VA_ARGS__)
#ifdef HDRPC_USE_64
#define HDRPCAddU64(session, ...) _HDRPCUseAdd(session, 64, __VA_ARGS__)
#endif
#define HDRPCAddException(session, ...) _HDRPCAdd((session), uint16_t, kHDRPCException, __VA_ARGS__)
#define HDRPCAddBuffer(session, data, len) _HDRPCAddArgs((session), kHDRPCBuffer, (data), (len))
#define HDRPCAddString(session, data, len) _HDRPCAddArgs((session), kHDRPCString, (data), (len) * 2)
// 注: 如果需要用户数据, 要求用户数据添加到所有参数后面
#define HDRPCAddUserData(session, data, len) _HDRPCAddArgs((session), kHDRPCUserData, (data), (len))
/**
* @brief 添加参数到会话, 方便添加用户数据到会话
* @param session 参数会话
* @param args 参数
* @return 1成功, 0失败
*/
uint8_t HDRPCAddArgs(HDRPCSession *session, HDRPCArgs *args);
/**
* @brief 将数据反序列化解析参数会话
* @param data 参数包数据
* @param len 参数包长度
* @param session 参数会话
* @return 1成功, 0失败
*/
uint8_t HDRPCParseArgs(void *data, uint16_t len, HDRPCSession *session);
/**
* @brief 检查参数类型是否匹配, 仅支持最大参数9个
* @param session 参数会话
* @param type 参数类型
* @param index 参数索引
* @param len 参数个数
* @return 1成功, 0失败
*/
uint8_t _HDRPCCheckArgs(HDRPCSession *session, uint8_t *type, uint8_t index, uint8_t len);
uint8_t __HDRPCCheckArgs(HDRPCSession *session, int len, ...);
#define HDRPCCheckArgs(session, ...) __HDRPCCheckArgs((session), __COUNT_ARGS(__VA_ARGS__), __VA_ARGS__)
/**
* @brief 获取指定位置数值数据
* @param session 参数会话
* @param type 参数类型
* @param index 参数索引
* @return 参数
*/
HDRPCValue_t _HDRPCGetValue(HDRPCSession *session, uint8_t type, uint8_t index);
#define HDRPCGetValueU8(session, index) (uint8_t)_HDRPCGetValue(session, kHDRPCU8, index)
#define HDRPCGetValueU16(session, index) (uint16_t)_HDRPCGetValue(session, kHDRPCU16, index)
#define HDRPCGetValueU32(session, index) (uint32_t)_HDRPCGetValue(session, kHDRPCU32, index)
#ifdef HDRPC_USE_64
#define HDRPCGetValueU64(session, index) (uint64_t)_HDRPCGetValue(session, kHDRPCU64, index)
#endif
/**
* @brief 获取指定位置缓存数据
* @param session 参数会话
* @param type 参数类型
* @param index 参数索引
* @return 参数
*/
void *_HDRPCGetData(HDRPCSession *session, uint8_t type, uint8_t index, uint8_t *len);
#define HDRPCGetCharData(session, index, len) (char *)_HDRPCGetData(session, kHDRPCBuffer, index, len)
#define HDRPCGetData(session, index, len) (uint8_t *)_HDRPCGetData(session, kHDRPCBuffer, index, len)
#define HDRPCGetUserData(session, index, len) (uint8_t *)_HDRPCGetData(session, kHDRPCUserData, index, len)
#define HDRPCGetString(session, index, len) (uint16_t *)_HDRPCGetData(session, kHDRPCString, index, len)
/**
* @brief 处理返回的数据调用回调
* @param data 数据
* @param len 数据长度
*/
void HDRPCReadData(void *data, uint16_t len);
/**
* @brief 处理对方请求调用的数据
* @param data 数据
* @param len 数据长度
*/
void HDRPCReadCallData(void *data, uint16_t len);
/**
* @brief 发送数据
* @param session 参数会话
* @param funcCode 功能码
* @param callBack 功能回调
* @param funcName 函数名称
* @param nameLen 名称长度
* @param timeout 超时回调
* @return int16_t id索引(返回-1则无存储返回回调)
*/
HDRPCIndexId_t _HDRPCSendData(HDRPCSession *session, uint16_t funcCode, HDRPCCallback callBack, const char *funcName, uint8_t nameLen, HDRPCTimeoutCall timeout);
#define HDRPCSendData(session, code, func) _HDRPCSendData(session, code, func, #func, sizeof(#func) - 1, NULL)
#define HDRPCSendDataNotCall(session, code) _HDRPCSendData(session, code, NULL, NULL, 0, NULL)
#define HDRPCSendDataTimeout(session, code, func, timeout) _HDRPCSendData(session, code, func, #func, sizeof(#func) - 1, timeout)
/**
* @brief 参数会话转换成发送数据
* @param session 参数会话
* @param data 写入缓存
* @param len 缓存长度
* return 写入长度
*/
uint16_t HDRPCConvSendData(HDRPCSession *session, uint8_t *data, uint16_t len);
/**
* @brief 设置超时时间
* @brief idIndex 发送返回的id索引
* @brief delayMs 超时时间(ms)
*/
void HDRPCSetDelayTime(HDRPCIndexId_t idIndex, uint16_t delayMs);
/**
* @brief 移除任务
* @brief idIndex 发送返回的id索引
*/
void HDRPCRemoveTask(HDRPCIndexId_t idIndex);
/**
* @brief 获取对于任务的回调函数
* @param idIndex 发送返回的id索引
* @return 无效返回NULL
*/
HDRPCCallback HDRPCGetCallBack(HDRPCIndexId_t idIndex);
/**
* @brief 运转RPC, 主要用于处理超时
*/
void HDRPCRun();
#endif // __HDRPC_H__