/** * 日期: 2025-09-04 * 作者: coffee * 描述: ARM和MCU交互通信模块 * demo: * 首次需要先初始化RPC调用 * HDRPCInitCall(发送回调, 存储RPC回调缓存, 回调缓存长度, 读取RPC会话); * 读取数据: * HDRPCReadData(...); * 发送调用 * HDRPCSendData(sesion, 枚举值, 回调函数); * 不需要回调 * HDRPCSendDataNotCall(sesion, 枚举值); */ #ifndef __HDRPC_H__ #define __HDRPC_H__ #include // 设置超时时间 #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 /** * 类型数据, 多节字节按照大端解析: * 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, ///< 参数类型不匹配 }; 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 struct __attribute__((packed)) HDRPCCallBuffer { uint8_t enbale : 1; ///< 是否启用 uint8_t skipExce: 1; ///< 跳过异常 uint8_t nameLen : 6; ///< 函数名长度 uint32_t lastTime; ///< 上次调用时间 const char *name; ///< 函数名 HDRPCCallback callback; ///< 回调 } HDRPCCallBuffer; /** * @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 /** * @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 检查参数类型是否匹配 * @param session 参数会话 * @param type 参数类型 * @param len 参数个数 * @return 1成功, 0失败 */ uint8_t _HDRPCCheckArgs(HDRPCSession *session, uint8_t *type, uint8_t len); #define HDRPCCheckArgs(session, ...) ({ uint8_t __type[] = {__VA_ARGS__}; uint8_t __ret = _HDRPCCheckArgs(session, __type, sizeof(__type) / sizeof(__type[0])); __ret; }) /** * @brief 获取指定位置数值数据 * @param session 参数会话 * @param type 参数类型 * @param index 参数索引 * @return 参数 */ HDRPCValue_t _HDRPCGetValue(HDRPCSession *session, uint8_t type, uint8_t index); #define HDRPCGetValueU8(session, index) _HDRPCGetValue(session, kHDRPCU8, index) #define HDRPCGetValueU16(session, index) _HDRPCGetValue(session, kHDRPCU16, index) #define HDRPCGetValueU32(session, index) _HDRPCGetValue(session, kHDRPCU32, index) #ifdef HDRPC_USE_64 #define HDRPCGetValueU64(session, index) _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 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 funcName 函数名称 * @param nameLen 名称长度 */ void _HDRPCSendData(HDRPCSession *session, uint16_t funcCode, HDRPCCallback callBack, const char *funcName, uint8_t nameLen); #define HDRPCSendData(session, code, func) _HDRPCSendData(session, code, func, #func, sizeof(#func) - 1) #define HDRPCSendDataNotCall(session, code) _HDRPCSendData(session, code, NULL, NULL, 0) /** * @brief 参数会话转换成发送数据 * @param session 参数会话 * @param data 写入缓存 * @param len 缓存长度 * return 写入长度 */ uint16_t HDRPCConvSendData(HDRPCSession *session, uint8_t *data, uint16_t len); #endif // __HDRPC_H__