From 15f3b90f5aa95db8f95705d9631598f046480978 Mon Sep 17 00:00:00 2001 From: coffee Date: Mon, 8 Sep 2025 13:53:16 +0800 Subject: [PATCH] =?UTF-8?q?1.=20=E4=BF=AE=E5=A4=8DRPC=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/HDRPC.h | 225 +++++++++++++++++++++ src/HDRPC.c | 526 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 751 insertions(+) create mode 100644 include/HDRPC.h create mode 100644 src/HDRPC.c diff --git a/include/HDRPC.h b/include/HDRPC.h new file mode 100644 index 0000000..6a32bdb --- /dev/null +++ b/include/HDRPC.h @@ -0,0 +1,225 @@ +/** + * 日期: 2025-09-04 + * 作者: coffee + * 描述: ARM和MCU交互通信模块 + */ + +#ifndef __HDRPC_H__ +#define __HDRPC_H__ + +#include + +// 无效类型 +#define HDRPC_INVAID_TYPE 0xFF + +// 无效功能 +#define HDRPC_INVAID_FUNC 0xFFFF + +// 默认超时 +#define HDRPC_TIMEOUT 3000 + +// 如果使用栈参数解析, 则最大支持的参数个数 +#define HDRPC_USE_SESSION_ARGS (5) + +// 使用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 +}; + +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 __attribute__((packed)) HDRPCSession +{ + uint8_t index; ///< 当前添加到的参数索引 + uint8_t len; ///< 参数总长度 + uint16_t func; ///< 调用功能, 用于解析数据得到 + HDRPCArgs *args; +} HDRPCSession; + +// 此宏用于其他回调的参数声明 +#define HDRPC_CALL_ARGS HDRPCSession *session +typedef void (*HDRPCCallback)(HDRPCSession *session); +typedef void (*HDRPCSendData)(HDRPCSession *session); + +// 调用缓存, 数据由用户提供 +typedef struct __attribute__((packed)) HDRPCCallBuffer { + uint8_t enbale : 1; + uint8_t nameLen : 7; + uint32_t time; + const char *name; + HDRPCCallback callback; +} HDRPCCallBuffer; + +/** + * @brief 初始化RPC会话 + * @param session 参数会话 + * @param len 参数会话长度 + */ +void HDRPCInitSession(HDRPCSession *session, HDRPCArgs *args, uint8_t len); + +/** + * @brief 初始化RPC调用 + * @param sendCall 发送数据回调 + * @param callback 回调缓存, 用于可注册RPC回调数量 + * @param callLen 回调缓存长度 + * @param buffer 参数会话(如果不传递则使用栈分配) + */ +void HDRPCInitCall(HDRPCSendData sendCall, HDRPCCallBuffer *callBuff, uint8_t callLen, HDRPCSession *buffer); + +/** + * @brief 使用这个来创建栈内参数包, 内部自增一个用于存储内部需要使用的用户数据 + * @param _name 参数包名称 + * @param _len 参数包长度 + */ +#define HDRPCCreate(_name, _len) HDRPCArgs _args##_name[_len + 1]; HDRPCSession _name; HDRPCInitSession(&_name, _args##_name, _len + 1) + +/** + * @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 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 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, int 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, int index, uint8_t *len); +#define HDRPCGetData(session, index, len) (uint8_t *)_HDRPCGetData(session, kHDRPCBuffer, 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 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__ diff --git a/src/HDRPC.c b/src/HDRPC.c new file mode 100644 index 0000000..34aa21f --- /dev/null +++ b/src/HDRPC.c @@ -0,0 +1,526 @@ + + +#include "HDRPC.h" +#include "HDLog.h" +#include +#include + +#ifndef LogD +#include +#define LogD(format, ...) printf("[%s:%s:%d]"format "\r\n", __FILE_NAME__, __FUNCTION__, __LINE__, ##__VA_ARGS__) +#endif + +struct RPCInfo { + HDRPCSendData writeCall; + HDRPCCallBuffer *callback; + HDRPCSession *session; + uint8_t callLen; +}; + +static struct RPCInfo sInfo; + +static void UpdateTimeout(HDRPCCallBuffer *callBuff) { + if (callBuff == NULL) { + return ; + } + + if (callBuff->enbale == 0) { + return ; + } + + uint32_t curr = HDLogGetTime(); + if (curr - callBuff->time > HDRPC_TIMEOUT) { + callBuff->enbale = 0; + LogD("Call[%s] Timeout", callBuff->name); + } +} + +static void Call(HDRPCSession *session) { + if (session == NULL) { + LogD("Session is nullptr"); + return ; + } + + // 不是用户数据, 说明不需要回调 + const uint8_t index = session->index - 1; + if (session->index > 0 && session->args[index].type != kHDRPCUserData) { + LogD("func type[0x%x] Not call", session->args[index].type); + return ; + } + + for (int i = 0; i < sInfo.callLen; i++) { + UpdateTimeout(&sInfo.callback[i]); + if (sInfo.callback[i].enbale == 0) { + continue; + } + + if (sInfo.callback[i].nameLen != session->args[index].buffer.len) { + continue; + } + + if (strncmp(sInfo.callback[i].name, (char *)session->args[index].buffer.data, session->args[index].buffer.len) != 0) { + continue; + } + + LogD("Call[%s]", sInfo.callback[i].name); + sInfo.callback[i].callback(session); + LogD("Call[%s] End", sInfo.callback[i].name); + + sInfo.callback[i].enbale = 0; + sInfo.callback[i].nameLen = 0; + sInfo.callback[i].name = NULL; + break; + } +} + +static int16_t AddCall(HDRPCCallback callBack, const char *funcName, uint8_t nameLen) { + if (callBack == NULL || nameLen == 0) { + LogD("funcName[%s], len[%d] add Faild", funcName, nameLen); + return -1; + } + + for (int i = 0; i < sInfo.callLen; i++) { + UpdateTimeout(&sInfo.callback[i]); + if (sInfo.callback[i].enbale == 1) { + continue; + } + + + sInfo.callback[i].enbale = 1; + sInfo.callback[i].callback = callBack; + sInfo.callback[i].nameLen = nameLen; + sInfo.callback[i].name = funcName; + sInfo.callback[i].time = HDLogGetTime(); + return i; + } + + LogD("add call is full, callLen[%d]", sInfo.callLen); + return -1; +} + +static uint8_t GetArgLen(HDRPCArgs *args) +{ + switch (args->type) { + case kHDRPCUserData: + case kHDRPCBuffer: + case kHDRPCString: + return args->buffer.len + 1; + case kHDRPCU8: + return sizeof(uint8_t); + case kHDRPCException: + case kHDRPCU16: + return sizeof(uint16_t); + case kHDRPCU32: + return sizeof(uint32_t); +#ifdef HDRPC_USE_64 + case kHDRPCU64: + return sizeof(uint64_t); +#endif + default: + LogD("Not support type[0x%x]", args->type); + break; + } + + return 0; +} + +static void AddArgToBuffer(HDRPCArgs *args, uint8_t *data) +{ + switch (args->type) { + case kHDRPCUserData: + case kHDRPCBuffer: + case kHDRPCString: + data[0] = args->buffer.len; + memcpy(data + 1, args->buffer.data, args->buffer.len); + break; + case kHDRPCU8: + data[0] = args->dataU8; + break; + case kHDRPCException: + case kHDRPCU16: + data[0] = args->dataU16 >> 8; + data[1] = args->dataU16 & 0xFF; + break; + case kHDRPCU32: + data[0] = args->dataU32 >> 24; + data[1] = (args->dataU32 >> 16) & 0xFF; + data[2] = (args->dataU32 >> 8) & 0xFF; + data[3] = args->dataU32 & 0xFF; + break; +#ifdef HDRPC_USE_64 + case kHDRPCU64: + data[0] = args->dataU64 >> 56; + data[1] = (args->dataU64 >> 48) & 0xFF; + data[2] = (args->dataU64 >> 40) & 0xFF; + data[3] = (args->dataU64 >> 32) & 0xFF; + data[4] = (args->dataU64 >> 24) & 0xFF; + data[5] = (args->dataU64 >> 16) & 0xFF; + data[6] = (args->dataU64 >> 8) & 0xFF; + data[7] = args->dataU64 & 0xFF; + break; +#endif + default: + LogD("Not support type[0x%x]", args->type); + break; + } +} + +static uint16_t IconvReadData(HDRPCSession *session, uint16_t type, uint8_t *data, uint16_t len) { + if (session == NULL || data == NULL || len == 0) { + LogD("read error, type[0x%x], len[%d]", type, len); + return len; + } + + if (session->index >= session->len) { + LogD("index[%d] len[%d] error", session->index, session->len); + return len; + } + + const uint8_t index = session->index++; + session->args[index].type = type; + switch (type) { + case kHDRPCUserData: + case kHDRPCBuffer: + case kHDRPCString: + if (len < 2) { + LogD("type[0x%x], len[%d] error", type, len); + return len; + } + session->args[index].buffer.len = data[0]; + session->args[index].buffer.data = data + 1; + return session->args[index].buffer.len + 1; + case kHDRPCU8: + session->args[index].dataU8 = data[0]; + return sizeof(uint8_t); + case kHDRPCException: + case kHDRPCU16: + if (len < sizeof(uint16_t)) { + LogD("type[0x%x], len[%d] error", type, len); + return len; + } + + session->args[index].dataU16 = data[0] << 8 | data[1]; + return sizeof(uint16_t); + case kHDRPCU32: + if (len < sizeof(uint32_t)) { + LogD("type[0x%x], len[%d] error", type, len); + return len; + } + + session->args[index].dataU32 = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; + return sizeof(uint32_t); +#ifdef HDRPC_USE_64 + case kHDRPCU64: + if (len < sizeof(uint64_t)) { + LogD("type[0x%x], len[%d] error", type, len); + return len; + } + session->args[index].dataU64 = data[0] << 56 | data[1] << 48 | data[2] << 40 | data[3] << 32 | data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7]; + return sizeof(uint64_t); +#endif + default: + LogD("Not support type[0x%x]", type); + break; + } + + return 1; +} + +static void ReadCall(HDRPCSession *session, void *data, uint16_t len) { + // 解析数据到参数会话 + if (HDRPCParseArgs(data, len, session) == 0) { + LogD("Parse args faild"); + } + + // 无效功能码 + if (session->func == HDRPC_INVAID_FUNC) { + LogD("Invalid Func[0x%x]", session->func); + return ; + } + + Call(session); +} + + +void HDRPCInitSession(HDRPCSession *session, HDRPCArgs *args, uint8_t len) +{ + if (session == NULL) { + return ; + } + + session->index = 0; + session->len = len; + session->func = 0; + session->args = args; + if (args == NULL && len > 0) { + LogD("args is nullptr, len[%d] error", len); + session->len = 0; + } + + for (uint16_t i = 0; i < session->len; ++i) { + memset(&session->args[i], 0, sizeof(HDRPCArgs)); + } +} + +void HDRPCInitCall(HDRPCSendData writeCall, HDRPCCallBuffer *callBuff, uint8_t len, HDRPCSession *buffer) +{ + sInfo.writeCall = writeCall; + sInfo.callback = callBuff; + sInfo.session = buffer; + sInfo.callLen = len; + if (callBuff == NULL && len > 0) { + LogD("callBuff is nullptr, len[%d] error", len); + sInfo.callLen = 0; + } + + for (uint16_t i = 0; i < sInfo.callLen; ++i) { + memset(&callBuff[i], 0, sizeof(HDRPCCallBuffer)); + } +} + +uint8_t _HDRPCAddArgs(HDRPCSession *session, uint8_t type, void *args, uint8_t len) +{ + if (session == NULL) { + LogD("Session is nullptr"); + return 0; + } + + if (len == 0) { + LogD("type[0x%x], args len is 0", type); + return 0; + } + + for (uint16_t i = 0; i < len; ++i) { + if (session->index >= session->len) { + LogD("Session type[0x%x] is full", type); + return 0; + } + + const uint8_t index = session->index; + ++session->index; + session->args[index].type = type; + switch (type) { + case kHDRPCU8: + session->args[index].dataU8 = *(uint8_t *)args; + break; + case kHDRPCException: + case kHDRPCU16: + session->args[index].dataU16 = *(uint16_t *)args; + break; + case kHDRPCU32: + session->args[index].dataU32 = *(uint32_t *)args; + break; +#ifdef HDRPC_USE_64 + case kHDRPCU64: + session->args[index].dataU64 = *(uint64_t *)args; + break; +#endif + case kHDRPCUserData: + case kHDRPCBuffer: + case kHDRPCString: + session->args[index].buffer.data = (uint8_t *)args; + session->args[index].buffer.len = len; + return 1; + default: + LogD("Not support type[0x%x]", type); + break; + } + } + + return 1; +} + +uint8_t HDRPCParseArgs(void *data, uint16_t len, HDRPCSession *session) +{ + if (session == NULL) { + return 0; + } + + session->func = HDRPC_INVAID_FUNC; + if (len < 2) { + return 0; + } + + /** + * 1 - 2字节 - 调用功能ID + * 2 - 多字节 - 参数包 + * 参数包根据1字节类型判断对应长度 + */ + session->index = 0; + uint8_t *d = (uint8_t *)data; + session->func = d[0] << 8 | d[1]; + uint16_t index = 2; + while (index < len) { + const uint8_t type = d[index++]; + if (index >= len) { + LogD("func[%x], type[0x%x], index[%d] len[%d] error", session->func, type, index, len); + return 0; + } + + const uint8_t useLen = IconvReadData(session, type, d + index, len - index); + index += useLen; + } + + return 1; +} + +uint8_t _HDRPCCheckArgs(HDRPCSession *session, uint8_t *type, uint8_t len) +{ + for (uint16_t i = 0; i < len; ++i) { + if (session->args[i].type != type[i]) { + LogD("Check index[%d] Type[0x%x] faild", i, type[i]); + return 0; + } + } + + return 1; +} + +HDRPCValue_t _HDRPCGetValue(HDRPCSession *session, uint8_t type, int index) +{ + if (session == NULL) { + LogD("Session is nullptr"); + return 0; + } + + if (index < 0 || index >= session->len) { + LogD("index[%d] len[%d] error", index, session->len); + return 0; + } + + if (session->args[index].type != type) { + LogD("index[%d] type[0x%x][0x%x] Not match", index, session->args[index].type, type); + return 0; + } + + switch (type) { + case kHDRPCU8: + return session->args[index].dataU8; + case kHDRPCException: + case kHDRPCU16: + return session->args[index].dataU16; + case kHDRPCU32: + return session->args[index].dataU32; +#ifdef HDRPC_USE_64 + case kHDRPCU64: + return session->args[index].dataU64; +#endif + default: + LogD("Not match type[0x%x] index[%d]", type, index); + break; + } + + return 0; +} + +void *_HDRPCGetData(HDRPCSession *session, uint8_t type, int index, uint8_t *len) +{ + if (session == NULL) { + LogD("Session is nullptr"); + return NULL; + } + + if (index < 0 || index >= session->len) { + LogD("index[%d] len[%d] error", index, session->len); + return NULL; + } + + if (session->args[index].type != type) { + LogD("index[%d] type[0x%x][0x%x] Not match", index, session->args[index].type, type); + return NULL; + } + + switch (type) { + case kHDRPCUserData: + case kHDRPCBuffer: + if (len) { + *len = session->args[index].buffer.len; + } + + return session->args[index].buffer.data; + case kHDRPCString: + if (len) { + *len = session->args[index].buffer.len / 2; + } + + return session->args[index].buffer.data; + default: + LogD("Not match type[0x%x] index[%d]", type, index); + break; + } + + return NULL; +} + +void HDRPCReadData(void *data, uint16_t len) +{ + if (sInfo.callback == NULL || sInfo.callLen ==0) { + return ; + } + + HDRPCSession *session = sInfo.session; + if (session == NULL) { + HDRPCSession buff; + session = &buff; + HDRPCArgs args[HDRPC_USE_SESSION_ARGS]; + HDRPCInitSession(session, args, HDRPC_USE_SESSION_ARGS); + ReadCall(session, data, len); + return ; + } + + ReadCall(session, data, len); +} + +void _HDRPCSendData(HDRPCSession *session, uint16_t funcCode, HDRPCCallback callBack, const char *funcName, uint8_t nameLen) +{ + if (sInfo.writeCall == NULL) { + LogD("Write Call is nullptr"); + return ; + } + + if (session) { + session->func = funcCode; + } + + do { + if (nameLen == 0 || callBack == NULL) { + break; + } + + if (HDRPCAddUserData(session, (void *)funcName, nameLen) == 0) { + LogD("Add Call Data[%s] faild", funcName); + break; + } + + if (AddCall(callBack, funcName, nameLen) == -1) { + LogD("Add Call[%s] faild", funcName); + } + } while (0); + + sInfo.writeCall(session); +} + + +uint16_t HDRPCConvSendData(HDRPCSession *session, uint8_t *data, uint16_t len) +{ + if (session == NULL || data == NULL || len < 2) { + return 0; + } + + int useLen = 0; + data[useLen++] = session->func >> 8; + data[useLen++] = session->func & 0xFF; + for (int i = 0; i < session->index; ++i) { + const uint8_t argLen = GetArgLen(&session->args[i]); + if (useLen + 1 > len) { + LogD("write Buffer Not enough, len[%d] useLen[%d]", len, useLen); + break; + } + + data[useLen++] = session->args[i].type; + AddArgToBuffer(&session->args[i], data + useLen); + useLen += argLen; + } + + return useLen; +}