From 2627e20b3266434a7ca5469ef325e3158afc97e4 Mon Sep 17 00:00:00 2001 From: chenyf <1343619937@qq.com> Date: Wed, 20 Nov 2024 23:03:26 +0800 Subject: [PATCH] 1 --- .vscode/launch.json | 7 + .vscode/settings.json | 4 +- config.h | 2 +- crc16.c | 12 +- crc16.o | Bin 0 -> 2198 bytes erpc_core.c | 451 ++++++++++++++++++++++++++++++++++++------ erpc_core.h | 130 +++++++++--- erpc_core.o | Bin 0 -> 6128 bytes erpc设计文档.md | 57 ------ list.c | 89 +++++++++ list.h | 17 ++ list.o | Bin 0 -> 1700 bytes makefile | 36 ++++ port_self.c | 133 +++++++++++++ port_self.exe | Bin 0 -> 70831 bytes port_self.h | 0 port_self.o | Bin 0 -> 9981 bytes unit_test.c | 2 + 18 files changed, 783 insertions(+), 157 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 crc16.o create mode 100644 erpc_core.o create mode 100644 list.c create mode 100644 list.h create mode 100644 list.o create mode 100644 makefile create mode 100644 port_self.c create mode 100644 port_self.exe create mode 100644 port_self.h create mode 100644 port_self.o create mode 100644 unit_test.c diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..f980ab9 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,7 @@ +{ + // 使用 IntelliSense 了解相关属性。 + // 悬停以查看现有属性的描述。 + // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 8f9ce70..964e7d2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -11,6 +11,8 @@ "cor.h": "c", "eprc_core.h": "c", "erpc_core.h": "c", - "type_traits": "c" + "type_traits": "c", + "list": "c", + "list.h": "c" } } \ No newline at end of file diff --git a/config.h b/config.h index b9c966d..b39ffb5 100644 --- a/config.h +++ b/config.h @@ -1,7 +1,7 @@ #ifndef _CONFIG_H_ #define _CONFIG_H_ -#define ERPC_VERSION "0.0.1" + #define u8 unsigned char diff --git a/crc16.c b/crc16.c index 7cfea11..190d082 100644 --- a/crc16.c +++ b/crc16.c @@ -42,12 +42,12 @@ uint16_t crc16(const unsigned char *buf, size_t len) { u16 cmd_cal_crc16(erpc_cmd_def_t *cmd) { u16 crc = 0; u32 counter = 0; - crc = (crc << 8) ^ crc16tab[((crc >> 8) ^ cmd->src_id) & 0x00FF]; - crc = (crc << 8) ^ crc16tab[((crc >> 8) ^ cmd->dest_id) & 0x00FF]; - crc = (crc << 8) ^ crc16tab[((crc >> 8) ^ cmd->msg_len) & 0x00FF]; - crc = (crc << 8) ^ crc16tab[((crc >> 8) ^ cmd->type) & 0x00FF]; - crc = (crc << 8) ^ crc16tab[((crc >> 8) ^ cmd->port) & 0x00FF]; - for (counter = 0; counter < cmd->msg_len; counter++) + crc = (crc << 8) ^ crc16tab[((crc >> 8) ^ cmd->head.src_id) & 0x00FF]; + crc = (crc << 8) ^ crc16tab[((crc >> 8) ^ cmd->head.dest_id) & 0x00FF]; + crc = (crc << 8) ^ crc16tab[((crc >> 8) ^ cmd->head.msg_len) & 0x00FF]; + crc = (crc << 8) ^ crc16tab[((crc >> 8) ^ cmd->head.type) & 0x00FF]; + crc = (crc << 8) ^ crc16tab[((crc >> 8) ^ cmd->head.port) & 0x00FF]; + for (counter = 0; counter < cmd->head.msg_len; counter++) crc = (crc << 8) ^ crc16tab[((crc >> 8) ^ cmd->data[counter]) & 0x00FF]; cmd->crc_16[0] = (u8)(crc >> 8); cmd->crc_16[1] = (u8)(crc & 0x00FF); diff --git a/crc16.o b/crc16.o new file mode 100644 index 0000000000000000000000000000000000000000..6f0997b2e66ed2a17d888bc37106f619207130a6 GIT binary patch literal 2198 zcmYdkV`l(?Cu|H1qF@#agI-B$MG2S}Fz7HcFt`BKfB;B`0z*K8UP@v~B3J}B z;lL1ZKrgAd7`FU3a8aL}tjRi^?}vWFF2oq>a10j9bKKy_VE ze{ce|I4~GE=$oMHWnf@|s)5M>{oxSm(fQP)`Hg@_r!NqPN~9fk{l&m=-1QGg(Q6O> z?XJHLKHzZdJOE;)9elyTzx{+qx2u3hZvZ1uy#W6<2L5da3{L%)kU<{JM+9OIBijwM_aDgKA0T^yO8xr!)@~Wll zkD_I;poh4rBY+1a0ORn2I4F^508T*Nz5*}Q{{8@VEPL^n{-W;`f@8vm%|9`&sI7!9XM1h4-Qj;_NwKQ(=FQXfB*M)!VNeRKBgU9Gj;doy}H=T5KN zmUlJoi=VKakzSx&0pI-p``+KZ|L45)eyjD7^DFv0Ca!Eewej^ro{PE%{XXVDY!Fz; zaLC}X0!x6ZgIhs*!p`OylYcM1wb}Nt%;oyWai2FbO%VF5bjirnNhGK|DXi$#*3(N@ zOzmvV`|AHx=PK{fM<$0=7Kk*mq?Nd*sD!Y(++O}``^@$o)8n7leV09MbN#Z~C$ouc z8^prX%F0CDOu~F_=APvHssHlC%$J>AJ6ErCiAeQet5DB4An}l+$zria?dh1?_OIoB z|Lndod-v*DyGy-7qRg|zsy=dEklL&@$x81p|J$6qzGqkM?Oyw0?#W)Y8upx&7+0S~ zHqAN@WDfGkzqk7zd%ouW?Df0$-|YV}Up&vOF4V6iZnEAcyNi4uB~Y z7%uo}r!r149VV3|=5+VK@k9fyzXP zm^m=rLRfil)(SZ58=M8y0Ipe>f#$$i96%O75Ho|_461jS83f?6B5+xdFCelqaFzmG zRxd3xCl$y8fq(xQ7}6P&i;@k^^pYV$U=l1+l9&YIfb3^x0E>X-fT7Evz`z7_DK-Fd zA1GwOYQPF)fg~uLAtK1NDaZ(BMo_pzYF)5$Ac0(y0wsZJU@{0AxfTUgidfYk)u3Qs zFfxFQLjlOOC#d>iW(3urr~tX<1XY9(HK6(u73e~_;IL=3N0kKfEPxnNtE*I1RWT&z Xro<;F=EOsS7R<{?P0oh$krV;|qGV^` literal 0 HcmV?d00001 diff --git a/erpc_core.c b/erpc_core.c index 4526e07..fa0db9d 100644 --- a/erpc_core.c +++ b/erpc_core.c @@ -2,70 +2,399 @@ #include "crc16.h" -u32 erpc_report_node_self(node_cfg_t *node_cfg) { - erpc_cmd_def_t cmd; - cmd.src_id = node_cfg->local_id; - cmd.dest_id = 0xFF; - cmd.msg_len = 0; - cmd.type = PACKAGE_TYPE_DEV_POWER_ON; - cmd_cal_crc16(&cmd); - return node_cfg->write((u8 *)&cmd, sizeof(erpc_cmd_def_t)); -} +/** + * 操作系统相关 + */ -u32 erpc_search_all_node(node_cfg_t *node_cfg) { - erpc_cmd_def_t cmd; - cmd.src_id = node_cfg->local_id; - cmd.dest_id = 0xFF; - cmd.msg_len = 0; - cmd.type = PACKAGE_TYPE_CMD_SERCH_DEV_ONLINE; - cmd_cal_crc16(&cmd); - return node_cfg->write((u8 *)&cmd, sizeof(erpc_cmd_def_t)); -} +erpc_sleep erpc_sleep_tick = NULL; -u32 erpc_send_cmd(node_cfg_t *node_cfg, u8 dest_id, u8 *data, u32 len) { - erpc_cmd_def_t cmd; - cmd.src_id = node_cfg->local_id; - cmd.dest_id = dest_id; - cmd.msg_len = len; - cmd.type = PACKAGE_TYPE_CMD_REQ; - cmd.data = data; - cmd_cal_crc16(&cmd); - return node_cfg->write((u8 *)&cmd, sizeof(erpc_cmd_def_t) + len); -} - -u32 erpc_send_cmd_ack(node_cfg_t *node_cfg, erpc_cmd_def_t *cmd_rec, - u8 is_ack) { - erpc_cmd_def_t cmd_send; - cmd_send.src_id = node_cfg->local_id; - cmd_send.dest_id = cmd_rec->src_id; - if (is_ack) - cmd_send.type = PACKAGE_TYPE_CMD_REQ_ACK; - else - cmd_send.type = PACKAGE_TYPE_CMD_RESP_NACK; - cmd_send.msg_len = 0; - cmd_cal_crc16(&cmd_send); - return node_cfg->write((u8 *)&cmd_send, sizeof(erpc_cmd_def_t)); -} - -u32 erpc_send_repeat(node_cfg_t *node_cfg,u8 dest_id) +static list_t erpc_hw; +void clean_cache(erpc_hw_cfg_t *hw) { - erpc_cmd_def_t cmd; - cmd.src_id = node_cfg->local_id; - cmd.dest_id = dest_id; - cmd.type = PACKAGE_TYPE_CMD_REPEAT; - cmd.msg_len = 0; - cmd_cal_crc16(&cmd); - return node_cfg->write((u8 *)&cmd, sizeof(erpc_cmd_def_t)); -} -u32 erpc_send_msg(node_cfg_t *node_cfg, u8 dest_id, u8 *data, u32 len) { - int retry = CMD_MAX_RETRY; - node_cfg->bus_lock(); - u32 ret = 0; - while (retry-- > 0) { - u32 ret = erpc_send_cmd(node_cfg, dest_id, data, len); - + for (int i = 0; i < MAX_REC_CMD_CACHE_NUM; i++) + { + hw->rec_cache->state = ERPC_CMD_NO_ERROR; + } + for (int i = 0; i < MAX_SEND_CMD_CACHE_NUM; i++) + { + hw->send_cache[i].state = ERPC_CMD_NO_ERROR; } - return ret; } -u32 erpc_rec_msg_core(node_cfg_t *node_cfg, u8 *data, u32 len) { +/** + * 注册 hardware 设备 + * 线程不安全 + */ +u32 erpc_hw_add(erpc_hw_cfg_t *hw) +{ + list_t *list = &erpc_hw; + if (list->data == NULL) + { + list->data = (void *)hw; + clean_cache(hw); + return ERPC_NO_ERROR; + } + list_t *list_node = malloc(sizeof(list_t)); + if (list_node == NULL) + { + return ERPC_ERR_MALLOC_ERROR; + } + list_node->data = (void *)hw; + u8 hw_ord = hw->ord; + // 检查hw是否已经存在 + while (list != NULL) + { + erpc_hw_cfg_t *hw_cfg = (erpc_hw_cfg_t *)list->data; + if (hw_cfg->ord == hw_ord) + { + return ERPC_ERR_HW_EXIST; + } + list = list->next; + } + list_t *result = list_append(&erpc_hw, hw); + if (result == NULL) + { + return ERPC_ERR_MALLOC_ERROR; + } + clean_cache(hw); + return ERPC_NO_ERROR; +} +/** + * 注册命令列表 + * 线程不安全 + */ +u32 erpc_add_cmd_list(erpc_hw_cfg_t *hw, erpc_cmd_list_t *cmd_list) +{ + list_t *list = &hw->cmd_list; + if (list->data == NULL) + { + list->data = (void *)cmd_list; + return ERPC_NO_ERROR; + } + list = list_append(&hw->cmd_list, cmd_list); + if (list == NULL) + { + return ERPC_ERR_MALLOC_ERROR; + } + return ERPC_NO_ERROR; +} +/** + * 移除 hardware 设备 + * 线程不安全 + */ +u32 erpc_hw_remove(u8 hw) +{ + list_t *list = &erpc_hw; + if (list->data == NULL) + { + return ERPC_ERR_NOFOND_HW; + } + while (list != NULL) + { + erpc_hw_cfg_t *hw_cfg = (erpc_hw_cfg_t *)list->data; + if (hw_cfg->ord == hw) + { + list_delete(&erpc_hw, list); + free(list); + return ERPC_NO_ERROR; + } + list = list->next; + } + return ERPC_ERR_NOFOND_HW; +} +/** + * 获取 hardware 设备 + */ +erpc_hw_cfg_t *erpc_hw_get(u8 hw) +{ + list_t *list = &erpc_hw; + if (list->data == NULL) + { + return NULL; + } + while (list != NULL) + { + erpc_hw_cfg_t *hw_cfg = (erpc_hw_cfg_t *)list->data; + if (hw_cfg->ord == hw) + { + return hw_cfg; + } + } + return NULL; +} + +u32 erpc_send(u8 hw, u8 dest_id, u16 port, u8 *data, u16 len) +{ + erpc_hw_cfg_t *hw_cfg = erpc_hw_get(hw); + CHECK_IF_ERROR(hw_cfg == NULL, ERPC_ERR_NOFOND_HW); + u8 cache_ord = 255; + // 查找可用的发送缓存 + for (int i = 0; i < MAX_SEND_CMD_CACHE_NUM; i++) + { + if (hw_cfg->send_cache[i].state == ERPC_CMD_NO_ERROR) + { + cache_ord = i; + break; + } + } + CHECK_IF_ERROR(cache_ord == 255, ERPC_ERR_SEND_CACHE_FULL); + // 准备数据 + hw_cfg->send_cache[cache_ord].state = ERPC_CMD_DATA_DEAL; + erpc_cmd_def_t *cmd = (erpc_cmd_def_t *)&hw_cfg->send_cache[cache_ord].data[0]; + cmd->head.dest_id = dest_id; + cmd->head.port = port; + cmd->head.msg_len = len; + cmd->head.type = PACKAGE_TYPE_CMD_REQ; + cmd->head.src_id = hw_cfg->local_id; + memcpy(cmd->data, data, len); + // 计算校验和 + cmd_cal_crc16(cmd); + // 发送数据 + hw_cfg->send_cache[cache_ord].state = ERPC_CMD_WAIT_SEND; + // 等待数据发送完成 + int wait_time = CMD_TIMEOUT; + while (wait_time > 0) + { + if (hw_cfg->send_cache[cache_ord].state == ERPC_CMD_SEND_OK) + { + break; + } + if (hw_cfg->send_cache[cache_ord].state == ERPC_CMD_DEST_BUSY) + { + return ERPC_ERR_DEST_BUSY; + } + if (erpc_sleep_tick != NULL) + { + erpc_sleep_tick(1); + } + + wait_time--; + } + CHECK_IF_ERROR(wait_time == 0, ERPC_ERR_SEND_TIMEOUT); + CHECK_IF_ERROR(hw_cfg->send_cache[cache_ord].state == ERPC_CMD_SEND_ONCE, ERPC_ERR_DEST_NO_RESPONSE); + CHECK_IF_ERROR(hw_cfg->send_cache[cache_ord].state == ERPC_CMD_SEND_REPEAT, ERPC_ERR_DEST_NO_RESPONSE); + return ERPC_NO_ERROR; +} + +u32 erpc_send_data(erpc_hw_cfg_t *hw) +{ + for (int i = 0; i < MAX_SEND_CMD_CACHE_NUM; i++) + { + if (hw->send_cache[i].state == ERPC_CMD_WAIT_SEND) + { + erpc_cmd_def_t *cmd = (erpc_cmd_def_t *)&hw->send_cache[i].data[0]; + u32 len = sizeof(erpc_cmd_head_t) + 2 + cmd->head.msg_len; + hw->send_lock(); + u8 ret = hw->write((u8 *)hw->send_cache[i].data, len); + hw->send_unlock(); + CHECK_IF_ERROR(ret != 0, ERPC_ERR_HW_SEND_FAIL); + hw->send_cache[i].state = ERPC_CMD_SEND_ONCE; + } + } +} + +u32 erpc_rev_ack_package(erpc_hw_cfg_t *hw, erpc_cmd_def_t *cmd_rev) +{ + for (int i = 0; i < MAX_SEND_CMD_CACHE_NUM; i++) + { + if (hw->send_cache[i].state == ERPC_CMD_SEND_ONCE || hw->send_cache[i].state == ERPC_CMD_SEND_REPEAT) + { + erpc_cmd_def_t *cmd_send = (erpc_cmd_def_t *)&hw->send_cache[i].data[0]; + if (cmd_rev->head.port == cmd_send->head.port) + { + hw->send_cache[i].state = ERPC_CMD_SEND_OK; + return ERPC_NO_ERROR; + } + } + } + return ERPC_NO_ERROR; +} + +// 重发数据包 +u32 erpc_rev_repeat_package(erpc_hw_cfg_t *hw, erpc_cmd_def_t *cmd_rev) +{ + for (int i = 0; i < MAX_SEND_CMD_CACHE_NUM; i++) + { + if (hw->send_cache[i].state == ERPC_CMD_SEND_ONCE || hw->send_cache[i].state == ERPC_CMD_SEND_REPEAT) + { + erpc_cmd_def_t *cmd_send = (erpc_cmd_def_t *)&hw->send_cache[i].data[0]; + if (cmd_rev->head.port == cmd_send->head.port) + { + u32 len = sizeof(erpc_cmd_head_t) + 2 + cmd_send->head.msg_len; + hw->send_lock(); + u8 ret = hw->write((u8 *)hw->send_cache[i].data, len); + hw->send_unlock(); + hw->send_cache[i].state = ERPC_CMD_SEND_REPEAT; + return ERPC_NO_ERROR; + } + } + } + return ERPC_NO_ERROR; +} +u32 erpc_send_ack_package(erpc_hw_cfg_t *hw, erpc_cmd_def_t *cmd_rev) +{ + erpc_cmd_def_t cmd_send; + cmd_send.head.dest_id = cmd_rev->head.src_id; + cmd_send.head.port = cmd_rev->head.port; + cmd_send.head.msg_len = 0; + cmd_send.head.type = PACKAGE_TYPE_CMD_REQ_ACK; + cmd_send.head.src_id = hw->local_id; + cmd_cal_crc16(&cmd_send); + u32 len = sizeof(erpc_cmd_head_t) + 2 + cmd_send.head.msg_len; + hw->send_lock(); + u8 ret = hw->write((u8 *)&cmd_send, len); + hw->send_unlock(); + CHECK_IF_ERROR(ret != 0, ERPC_ERR_HW_SEND_FAIL); + return ERPC_NO_ERROR; +} + +u32 erpc_rev_package(erpc_hw_cfg_t *hw) +{ + for (int i = 0; i < MAX_REC_CMD_CACHE_NUM; i++) + { + if (hw->rec_cache[i].state == ERPC_CMD_WAIT_SERVER_DEAL) + { + erpc_cmd_def_t *cmd = (erpc_cmd_def_t *)&hw->rec_cache[i].data[0]; + // 检查crc + u8 crc_result = cmd_check_crc16(cmd); + // 丢弃错误数据包 + if (crc_result) + { + hw->rec_cache[i].state = ERPC_CMD_NO_ERROR; + continue; + } + // 丢弃不是本地数据包 + if (cmd->head.dest_id != hw->local_id) + { + + hw->rec_cache[i].state = ERPC_CMD_NO_ERROR; + continue; + } + // 处理数据包 + switch (cmd->head.type) + { + case PACKAGE_TYPE_CMD_REQ: + erpc_send_ack_package(hw, cmd); + hw->rec_cache[i].state = ERPC_CMD_WAIT_TASK_DEAL; + break; + case PACKAGE_TYPE_CMD_REQ_ACK: + erpc_rev_ack_package(hw, cmd); + hw->rec_cache[i].state = ERPC_CMD_NO_ERROR; + break; + case PACKAGE_TYPE_CMD_REPEAT: + erpc_rev_repeat_package(hw, cmd); + hw->rec_cache[i].state = ERPC_CMD_NO_ERROR; + break; + default: + + break; + } + } + } +} +void erpc_rev_package_core() +{ + + list_t *list = &erpc_hw; + if (list->data == NULL) + { + return; + } + while (list != NULL) + { + erpc_hw_cfg_t *hw = (erpc_hw_cfg_t *)list->data; + erpc_rev_package(hw); + list = list->next; + } +} +u32 erpc_set_rev_cahce(u8 hw, u8 *data, u16 len) +{ + erpc_hw_cfg_t *hw_cfg = erpc_hw_get(hw); + CHECK_IF_ERROR(hw_cfg == NULL, ERPC_ERR_NOFOND_HW); + for (int i = 0; i < MAX_REC_CMD_CACHE_NUM; i++) + { + if (hw_cfg->rec_cache[i].state == ERPC_CMD_NO_ERROR) + { + memcpy(hw_cfg->rec_cache[i].data, data, len); + hw_cfg->rec_cache[i].state = ERPC_CMD_WAIT_SERVER_DEAL; + return ERPC_NO_ERROR; + } + } + return ERPC_ERR_REC_CACHE_FULL; +} +void erpc_send_deal_core() +{ + list_t *list = &erpc_hw; + if (list->data == NULL) + { + return; + } + while (list != NULL) + { + erpc_hw_cfg_t *hw = (erpc_hw_cfg_t *)list->data; + erpc_send_data(hw); + } + if (erpc_sleep_tick != NULL) + { + erpc_sleep_tick(1); + } +} + +void erpc_rev_deal_core() +{ + list_t *list = &erpc_hw; + if (list->data == NULL) + { + return; + } + while (list != NULL) + { + erpc_hw_cfg_t *hw = (erpc_hw_cfg_t *)list->data; + + for (int j = 0; j < MAX_REC_CMD_CACHE_NUM; j++) + { + if (hw->rec_cache[j].state == ERPC_CMD_WAIT_TASK_DEAL) + { + // 多线程处理 + hw->deal_lock(); + if (hw->rec_cache[j].state == ERPC_CMD_WAIT_TASK_DEAL) + { + // 获取指令的处理权限 + hw->rec_cache[j].state = ERPC_CMD_WAIT_TASK_DEAL_FINISH; + } + else + { + // 已经有线程抢先执行了 + hw->deal_unlock(); + continue; + } + hw->deal_unlock(); + + list_t *list = &hw->cmd_list; + // 链表是空的 + if (list->data == NULL) + { + continue; + } + while (list != NULL) + { + erpc_cmd_list_t *cmd_list = (erpc_cmd_list_t *)list->data; + erpc_cmd_def_t *cmd_def = (erpc_cmd_def_t *)hw->rec_cache[j].data; + if (cmd_list->cmd == cmd_def->head.port) + { + if (cmd_list->handle != NULL) + { + // 指令调用 + cmd_list->handle(hw->ord, cmd_def->head.src_id, cmd_def->head.dest_id, cmd_def->head.port, cmd_def->data, cmd_def->head.msg_len); + } + // 处理完成 丢弃缓存 + hw->rec_cache[j].state = ERPC_CMD_NO_ERROR; + } + } + } + } + } + if (erpc_sleep_tick != NULL) + { + erpc_sleep_tick(1); + } } \ No newline at end of file diff --git a/erpc_core.h b/erpc_core.h index 9ebbfc9..cfbe330 100644 --- a/erpc_core.h +++ b/erpc_core.h @@ -2,56 +2,124 @@ #define ERPC_CORE_H_ #include "config.h" +#include "list.h" +#include +#include +#include +#define ERPC_VERSION "0.0.1" -#define MAX_CMD_LEN (256 - 5) // crc16最大支持256字节 -#define CMD_MAX_RETRY 5 // 最大重发次数 -#define CMD_TIMEOUT 30 // 超时时间 tick -#define MAX_COM 20 // 最大支持端口打开数量,可认为是同时通讯的号 - -typedef enum erpc_error { - DEST_SYS_BUSY = 0, // 目标系统繁忙,接收到nack - DEST_SYS_TIMEOUT, // 目标系统处理超时 - BUS_CRC_ERROR, // 总线CRC错误,可能是总线通讯质量不佳 -}; -typedef enum package_type { +typedef enum package_type +{ PACKAGE_TYPE_DEV_POWER_ON = 0, PACKAGE_TYPE_CMD_REQ, PACKAGE_TYPE_CMD_REQ_ACK, PACKAGE_TYPE_CMD_RESP, PACKAGE_TYPE_CMD_RESP_ACK, - PACKAGE_TYPE_CMD_RESP_NACK, - PACKAGE_TYPE_CMD_REPEAT, // crc校验失败,请求重发 + PACKAGE_TYPE_CMD_REPEAT, // crc校验失败,请求重发 PACKAGE_TYPE_DEV_POWER_OFF, PACKAGE_TYPE_CMD_SERCH_DEV_ONLINE, } package_type; -typedef struct node_cfg_t { - u8 local_id; - struct port_t { - u16 com_id; - volatile u32 time_out; - void (*pre_deal)(u8 *data, u32 len); // 数据预处理接口 - u8 send_ack : 2; // 0:没有ack返回,1:ack返回 2:nack返回 - u8 rec_crc : 1; // 0:crc没有故障, 1: crc有故障 - u8 req_resend : 1; // 1:客户端请求重发 - } port[MAX_COM]; - u32 (*write)(u8 *data, u32 len); - void (*bus_lock)(void); - void (*bus_unlock)(void); - void (*sleep)(void); -} node_cfg_t; - // 广播ID #define ERPC_BOARDCAST_ID 0xff -typedef struct erpc_cmd_def_t { +typedef struct erpc_cmd_head_t +{ u8 src_id; u8 dest_id; package_type type; - u16 port; // 指令号,指令号=端口号 + u16 port; // 指令号,指令号=端口号 u8 msg_len; +} erpc_cmd_head_t; + +typedef struct erpc_cmd_def_t +{ + erpc_cmd_head_t head; u8 crc_16[2]; u8 *data; } erpc_cmd_def_t; +#define MAX_CMD_LEN (256 - sizeof(erpc_cmd_head_t)) // crc16最大支持256字节 +#define CMD_MAX_RETRY 5 // 最大重发次数 +#define CMD_TIMEOUT 30 // 超时时间 tick +#define MAX_REC_CMD_CACHE_NUM 10 // 最大接收指令缓存数量,接受指令优先级>处理指令优先级 +#define MAX_SEND_CMD_CACHE_NUM 10 // 最大发送指令缓存数量,发送指令优先级>接收指令优先级 +typedef enum erpc_status +{ + ERPC_CMD_NO_ERROR, // 发送cache,接收cache空闲 + ERPC_CMD_DATA_DEAL, // 发送cache数据组织中 + ERPC_CMD_WAIT_SERVER_DEAL, // 等待服务线程处理接受cache + ERPC_CMD_WAIT_TASK_DEAL, // 等待任务线程处理指令 + ERPC_CMD_WAIT_TASK_DEAL_FINISH, // 等待任务线程处理指令完成 + ERPC_CMD_WAIT_SEND, // 等待服务线程处理发送cache + ERPC_CMD_SEND_ONCE, // 发送指令成功 + ERPC_CMD_SEND_REPEAT, // 发送指令重发 + ERPC_CMD_SEND_OK, // 发送指令成功 + ERPC_CMD_DEST_BUSY, // 目标设备忙 +}erpc_status; + +typedef struct erpc_data_cache_t +{ + u8 state; + u8 data[256]; +} erpc_data_cache_t; + +typedef u32 (*erpc_cmd_handle_t)(u8 src_id, u8 dest_id, u16 port, u8 *data, u16 len); + +typedef struct erpc_cmd_list_t +{ + u16 cmd; + u32 (*handle)(u8 hw, u8 src_id, u8 dest_id, u16 port, u8 *data, u16 len); +} erpc_cmd_list_t; + +typedef struct erpc_hw_cfg_t +{ + u8 ord; + u8 local_id; + u8 (*write)(u8 *data, u16 len); + void (*send_lock)(void); + void (*send_unlock)(void); + erpc_data_cache_t rec_cache[MAX_REC_CMD_CACHE_NUM]; + erpc_data_cache_t send_cache[MAX_SEND_CMD_CACHE_NUM]; + void (*deal_lock)(void); + void (*deal_unlock)(void); + list_t cmd_list; +} erpc_hw_cfg_t; + +#define CHECK_IF_ERROR(condition, error) \ + if (condition) \ + { \ + return error; \ + } + +typedef enum erpc_error +{ + ERPC_NO_ERROR = 0, + ERPC_ERR_NOFOND_HW, + ERPC_ERR_SEND_CACHE_FULL, + ERPC_ERR_SEND_TIMEOUT, + ERPC_ERR_HW_SEND_FAIL, // 硬件层发来的错误 erpc_hw_cfg_t.write返回错误 + ERPC_ERR_DEST_BUSY, + ERPC_ERR_DEST_NO_RESPONSE, // 目标设备无响应 + ERPC_ERR_MALLOC_ERROR, // malloc失败,内存不足 + ERPC_ERR_HW_EXIST, // 硬件已经存在 + ERPC_ERR_HW_NOT_EXIST, // 硬件不存在 + ERPC_ERR_REC_CACHE_FULL, // 接收缓存满 +}erpc_error; +typedef void (*erpc_sleep)(u32 tick); + + +void erpc_send_deal_core(); // 发送指令处理线程 +u32 erpc_set_rev_cahce(u8 hw, u8 *data, u16 len); // 写入接受缓存 +void erpc_rev_package_core(); // 处理接受到的包,通讯层面处理 +void erpc_rev_deal_core(); // 处理接受到的指令,业务层面处理 +extern erpc_sleep erpc_sleep_tick; + + + +u32 erpc_hw_add(erpc_hw_cfg_t *hw); +u32 erpc_add_cmd_list(erpc_hw_cfg_t *hw, erpc_cmd_list_t *cmd_list); + + +u32 erpc_send(u8 hw, u8 dest_id, u16 port, u8 *data, u16 len); #endif /* ERPC_CORE_H_ */ \ No newline at end of file diff --git a/erpc_core.o b/erpc_core.o new file mode 100644 index 0000000000000000000000000000000000000000..afdbadc8b96362b9daf7da09b043ecca06b856b5 GIT binary patch literal 6128 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 = data; + node->next = NULL; + return node; +} + +list_t *list_append(list_t *head, void *data) +{ + list_t *node = list_create(data); + if (node == NULL) + { + return NULL; + } + if (head == NULL) + { + return NULL; + } + else + { + list_t *tail = head; + while (tail->next != NULL) + { + tail = tail->next; + } + tail->next = node; + } + return head; +} + +void list_print(list_t *head) +{ + list_t *node = head; + while (node != NULL) + { + printf("%p\n", node->data); + node = node->next; + } +} + +/** + * Destroy a list and all its nodes. + * @param head The head of the list. + */ +void list_destroy(list_t *head) +{ + list_t *node = head; + while (node != NULL) + { + list_t *next = node->next; + free(node); + node = next; + } +} +/** + * Delete a node from the list. + * @param head The head of the list. + */ +void list_delete(list_t *head, void *data) +{ + list_t *node = head; + list_t *prev = NULL; + while (node != NULL) + { + if (node->data == data) + { + if (prev == NULL) + { + head = node->next; + } + else + { + prev->next = node->next; + } + free(node); + return; + } + prev = node; + node = node->next; + } +} diff --git a/list.h b/list.h new file mode 100644 index 0000000..786051e --- /dev/null +++ b/list.h @@ -0,0 +1,17 @@ +#ifndef _LIST_H_ +#define _LIST_H_ + + +typedef struct list_t { + void *data; + struct list_t *next; +} list_t; + +list_t *list_create(void *data); +list_t *list_append(list_t *head, void *data); +void list_print(list_t *head); +void list_destroy(list_t *head); +void list_delete(list_t *head, void *data); + + +#endif /* _LIST_H_ */ \ No newline at end of file diff --git a/list.o b/list.o new file mode 100644 index 0000000000000000000000000000000000000000..e32bab7d9229e02418d4b25af71dbec74cdddd01 GIT binary patch literal 1700 zcmb7EL2DCH5PsWDZID_Q5slQtA{8q%YqTLm5nL^yPoxmU*pt*W*=i&<%Vr~KK@h6K zQia~V>VMFSR4w%2#hZBapcdjGC&@vKGjH-XFJ>j*JTV*=N#Hqtk}taRjfxgKvD}XNm_4#v2T_ zhkPF7I(*|{hc(7tqu!e2n_$^27(6fp+_mF^h~|x*)U6L{ARZJFz)JAo-QJ6Cw+rFg z5Uw4Dy9}BUYO}zFz`0IqoUXCsA^~wF;3wOSALJ;sd616_`tYSP$O+;?5%2l)1DGY% zB*TTZecp;lT}CmLRN4YVF};!@3;8}@qGC|_q9neXYvZq4H)K}lbBV?*y~c!chtZ;k z-4yl7Iy?A;;`h`6e8{0XUQroaC|X<}jbD%HTAs20#dyzE+(7Vr3v0Z0#^75?0LGKU zngWdHM_4JqC*A$9_ho)=?t(ep%x0D{>7-k$SDMMXb2sTZ4^lJcl}4rNo6BqFLS=P+ zF}avYo32;8=al@@X4X1uLBK;0>IkeD`wBa1G4>tyqXJoQtH_4E3=udO{wH-{N`(4^ zuwfnKH9~Ya^kOXX9uJWjda+jWPKRhF^kVho#ZQhX)ES7Q zN=M>9qRu}YE0G*!_F+$S4X59rsB;gqAdY+u;#$hg+b1{}ZCI}LOgQ~@4eK71`^9Rt z7QQ^ZGjqMls=p#xXj$YuYl{}~DJA{j_>#UXui+BXfPTluv MYf`B?z*oZj1r~KRA^-pY literal 0 HcmV?d00001 diff --git a/makefile b/makefile new file mode 100644 index 0000000..9460005 --- /dev/null +++ b/makefile @@ -0,0 +1,36 @@ +# Makefile for the mutex example project + +# 指定编译器 +CC = gcc +# 指定编译选项 +CFLAGS = -Wall -Wextra -std=c11 + +# 源文件 +SRCS = erpc_core.c \ + port_self.c \ + crc16.c\ + list.c + +# 目标文件 +OBJS = $(SRCS:.c=.o) + +# 可执行文件 +TARGET = port_self.exe + +# 默认目标 +all: $(TARGET) + +# 链接目标 +$(TARGET): $(OBJS) + $(CC) -o $@ $^ + +# 编译源文件 +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +# 清理目标 +clean: + rm -f $(OBJS) $(TARGET) + +# 伪目标 +.PHONY: all clean diff --git a/port_self.c b/port_self.c new file mode 100644 index 0000000..adc5278 --- /dev/null +++ b/port_self.c @@ -0,0 +1,133 @@ + +// #ifndef WINDOWS +// #error "This file is for Windows only" +// #endif + +#include "erpc_core.h" +#include "windows.h" +#include +void hellworld() +{ + printf("Hello World!\n"); +} +void hello_cat() +{ + printf("Hello Cat!\n"); +} +erpc_cmd_list_t erpc_cmd_list[] = { + {.cmd = 0x01, hellworld}, + {.cmd = 0x02, hello_cat}, +}; + +HANDLE deal_lock; +HANDLE send_lock; + +static void deal_lock_h() +{ + WaitForSingleObject(deal_lock, INFINITE); +} + +static void deal_unlock_h() +{ + ReleaseMutex(deal_lock); +} +static void send_lock_h() +{ + WaitForSingleObject(send_lock, INFINITE); +} + +static void send_unlock_h() +{ + ReleaseMutex(send_lock); +} +u8 data[300]; +static u8 data_write(u8 *data, u32 len) +{ + erpc_set_rev_cahce(0, data, len); + return 0; +} + +erpc_hw_cfg_t self_hw_cfg = { + .ord = 0, + .deal_lock = deal_lock_h, + .deal_unlock = deal_unlock_h, + .send_lock = send_lock_h, + .send_unlock = send_unlock_h, + .local_id = 0x01, + .write = data_write, +}; +void erpc_cmd_config() +{ + for (int i = 0; i < sizeof(erpc_cmd_list) / sizeof(erpc_cmd_list[0]); i++) + { + erpc_add_cmd_list(&self_hw_cfg, &erpc_cmd_list[i]); + } +} +void sys_sleep(u32 ms) +{ + Sleep(ms); +} + +DWORD WINAPI send_task(LPVOID lpParam) +{ + while (1) + { + erpc_send_deal_core(); + } +} +DWORD WINAPI rev_task(LPVOID lpParam) +{ + + while (1) + { + erpc_rev_deal_core(); + } +} + +DWORD WINAPI test_task(LPVOID lpParam) +{ + printf("test_task\n"); + while (1) + { + printf("[test_task]send\n"); + u32 ret = erpc_send(self_hw_cfg.ord, self_hw_cfg.local_id, 0x01, NULL, 0); + printf("[test_task]send ret:%d\n", ret); + sys_sleep(1000); + } +} + +int main(int argc, char *argv[]) +{ + u32 ret = 0; + printf("erpc_port_self start\n"); + ret = erpc_hw_add(&self_hw_cfg); + printf("erpc_hw_add ret:%d\n", ret); + CHECK_IF_ERROR(ret, 0); + erpc_cmd_config(); + printf("erpc_cmd_config ret:%d\n", ret); + erpc_sleep_tick = sys_sleep; + + HANDLE threadHandle[3]; + deal_lock = CreateMutex(NULL, FALSE, NULL); + if (deal_lock == NULL) + { + printf("创建互斥锁失败,错误代码:%d\n", GetLastError()); + return 1; + } + send_lock = CreateMutex(NULL, FALSE, NULL); + if (send_lock == NULL) + { + printf("创建互斥锁失败,错误代码:%d\n", GetLastError()); + return 1; + } + threadHandle[0] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)send_task, NULL, 0, NULL); + threadHandle[1] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)rev_task, NULL, 0, NULL); + threadHandle[2] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)test_task, NULL, 0, NULL); + + WaitForSingleObject(threadHandle[0], INFINITE); + WaitForSingleObject(threadHandle[1], INFINITE); + WaitForSingleObject(threadHandle[2], INFINITE); + CloseHandle(threadHandle[0]); + CloseHandle(threadHandle[1]); + return 0; +} \ No newline at end of file diff --git a/port_self.exe b/port_self.exe new file mode 100644 index 0000000000000000000000000000000000000000..38942700b79afaf80d145779fb430a471ab4b81c GIT binary patch literal 70831 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 literal 0 HcmV?d00001 diff --git a/port_self.h b/port_self.h new file mode 100644 index 0000000..e69de29 diff --git a/port_self.o b/port_self.o new file mode 100644 index 0000000000000000000000000000000000000000..5b4f9b4beb69f436885f411d848522124106909b GIT binary patch literal 9981 zcmeHNZEO@p7@q501yMpZ5Q&nog(9HsQJ|L6ka(q3HrnEa55W(zJ?^&c+3Ve9ZwrN> zLJEdUX)J^g6n-dBe`$!uAYVTYA!4FIeh?EQCN-hZ1`^Oj1F=w_cV>5Puh#}m_~%Zt zJI_4tJ73T2&du#i1sp@3pV;AAv5Ig z+cuf8Glh&5O&8=iL;=>A@oz|_9B!k+Z7i7a8@UB$;JM`KT=xJA2K*hleuv;Pl;>9- z@F(;A4m`uyYgYSaBVT~QFJkCnbE9t8qykh}eYH9GW#(1bDG>({ZO!uw2IkFwA;+-@ zsWb4qq6ivNvOrNVutrVytDQF$wR<8N2I$tKcAi((pL3YVHo6H?Gp2U2Q^N>q`mEZ; znc+)$h1j0|%IV=0mu@IZubJ9aH+9n2nVNJ)?OIcGlG@9=a)P(q+0*h1bwfnnnA=r1 zq#jVu_W9KGH)^+Nx#tp3OjO{(3+SvH^1!k4j%VYK)Z6l`WT?2Sp=eAkVCE&Lo^-sh7ah#wy&ilWl|TGay(m?M z%5$itxoX#U7fwfKM(smg-`JV%-5V>@z}T6788g#uwX3c#@6`c0FdBJ#G_ue6dQwhj z+J0q%>(BLAfu1sFD6kTk;zY0>sbdu@O3;J)qsN52^Os`u8J-Glo+95{CD>gglbKi+=p%turq51#Sf!to1y zUQdv*hl*GJ$1)9v|6YNqf%bP?ifK$9x8g>`v^7C7ebX(mV*0LIj*DXY=DWm-3+dxI zFvTlytp=tzhN}^n;`b;GOz~b^9l#V9;-m5oV2Z1-4@h78m9kJQ+8hrj+S;mTMD$Qh zizULXGfEfc7-+ypHPEKqj8bfoEw8PuR_1h6Rce(LWywS;+EJF$TgnW5V|l5vv^^R# zl?|JfhG=~G+OoBk6-v@byp4^zxk{CPzMnceB0PpP>EdHWxRZmAJuA8AC07G9lUrBe zPFo5-)+#yb`CQIXUrAdZJB+*VqiqJkT>uh(e*w+M~mIipD|kIX&w` zZJ|KtLA;*vxFdrVsBY(}5VCkZ^m|ZkyYSd~B82jIJsp!7qjMnH;5-dNYSGs2$lyE) zf=b|XdZY_;o&qW4K8Nys949~?kv=qIWrOqd2es7ec`0jjpo{0@|5>=P=bmI}h>Z}=!y4#AAG>@+%pneNa{FpKk;`W!~n?2$(y%zmQQ z<@k`LHII2WkJ*#MB->5L2_L)UBhtraj^{DoOAC#zw#kT^x>(I-SFS9zIi>L$MRvYimaF9lwa?KL-gGKA7EL)CnQatM ztVzQ?70G4c zT0;++!dhcd%XPCplrrlKBVputt!{yH#HM12l&*&25lqiw5OhD%30oA_|C;Qe e<%FdrACGXtu)HYK2#WvZ;2Fff2&;zdF#iKO6Jz=S literal 0 HcmV?d00001 diff --git a/unit_test.c b/unit_test.c new file mode 100644 index 0000000..2bf60ca --- /dev/null +++ b/unit_test.c @@ -0,0 +1,2 @@ +#include "erpc_core.h" +