From c31caa0e72beaa26d7de6f6328025f066611fe62 Mon Sep 17 00:00:00 2001 From: chenyf <1343619937@qq.com> Date: Thu, 21 Nov 2024 16:59:31 +0800 Subject: [PATCH] =?UTF-8?q?fix(add):=20=E6=96=B0=E5=A2=9Eresp=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 6 +- erpc_core.c | 364 ++++++++++++++++++++++-------------------- erpc_core.h | 114 ++++++------- erpc_core.o | Bin 6276 -> 8141 bytes port_self.c | 11 ++ port_self.exe | Bin 70831 -> 72754 bytes port_self.o | Bin 10099 -> 10658 bytes 7 files changed, 268 insertions(+), 227 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index c9ee9c3..db529d0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -16,7 +16,11 @@ "list.h": "c", "array": "c", "string": "c", - "string_view": "c" + "string_view": "c", + "windows.h": "c", + "string.h": "c", + "stdio.h": "c", + "stdlib.h": "c" }, "makefile.launchConfigurations": [ { diff --git a/erpc_core.c b/erpc_core.c index 2bd711c..12e6915 100644 --- a/erpc_core.c +++ b/erpc_core.c @@ -9,14 +9,11 @@ erpc_sleep erpc_sleep_tick = NULL; static list_t erpc_hw; -void clean_cache(erpc_hw_cfg_t *hw) -{ - for (int i = 0; i < MAX_REC_CMD_CACHE_NUM; i++) - { +void clean_cache(erpc_hw_cfg_t *hw) { + 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++) - { + for (int i = 0; i < MAX_SEND_CMD_CACHE_NUM; i++) { hw->send_cache[i].state = ERPC_CMD_NO_ERROR; } } @@ -24,35 +21,29 @@ void clean_cache(erpc_hw_cfg_t *hw) * 注册 hardware 设备 * 线程不安全 */ -u32 erpc_hw_add(erpc_hw_cfg_t *hw) -{ +u32 erpc_hw_add(erpc_hw_cfg_t *hw) { list_t *list = &erpc_hw; - if (list->data == NULL) - { + 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) - { + if (list_node == NULL) { return ERPC_ERR_MALLOC_ERROR; } list_node->data = (void *)hw; u8 hw_ord = hw->ord; // 检查hw是否已经存在 - while (list != NULL) - { + while (list != NULL) { erpc_hw_cfg_t *hw_cfg = (erpc_hw_cfg_t *)list->data; - if (hw_cfg->ord == hw_ord) - { + 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) - { + if (result == NULL) { return ERPC_ERR_MALLOC_ERROR; } clean_cache(hw); @@ -62,17 +53,14 @@ 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_add_cmd_list(erpc_hw_cfg_t *hw, erpc_cmd_list_t *cmd_list) { list_t *list = &hw->cmd_list; - if (list->data == NULL) - { + if (list->data == NULL) { list->data = (void *)cmd_list; return ERPC_NO_ERROR; } list = list_append(&hw->cmd_list, cmd_list); - if (list == NULL) - { + if (list == NULL) { return ERPC_ERR_MALLOC_ERROR; } return ERPC_NO_ERROR; @@ -81,18 +69,14 @@ u32 erpc_add_cmd_list(erpc_hw_cfg_t *hw, erpc_cmd_list_t *cmd_list) * 移除 hardware 设备 * 线程不安全 */ -u32 erpc_hw_remove(u8 hw) -{ +u32 erpc_hw_remove(u8 hw) { list_t *list = &erpc_hw; - if (list->data == NULL) - { + if (list->data == NULL) { return ERPC_ERR_NOFOND_HW; } - while (list != NULL) - { + while (list != NULL) { erpc_hw_cfg_t *hw_cfg = (erpc_hw_cfg_t *)list->data; - if (hw_cfg->ord == hw) - { + if (hw_cfg->ord == hw) { list_delete(&erpc_hw, list); free(list); return ERPC_NO_ERROR; @@ -104,87 +88,78 @@ u32 erpc_hw_remove(u8 hw) /** * 获取 hardware 设备 */ -erpc_hw_cfg_t *erpc_hw_get(u8 hw) -{ +erpc_hw_cfg_t *erpc_hw_get(u8 hw) { list_t *list = &erpc_hw; - if (list->data == NULL) - { + if (list->data == NULL) { return NULL; } - while (list != NULL) - { + while (list != NULL) { erpc_hw_cfg_t *hw_cfg = (erpc_hw_cfg_t *)list->data; - if (hw_cfg->ord == hw) - { + 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); +u32 erpc_send_base(erpc_hw_cfg_t *hw_cfg, u8 dest_id, u16 port, u8 package_type, + u8 *data, u16 len) { 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) - { + for (int i = 0; i < MAX_SEND_CMD_CACHE_NUM; i++) { + if (hw_cfg->send_cache[i].state == ERPC_CMD_NO_ERROR) { printf("find send cache %d\n", i); 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]; + 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; + if (data != NULL) { + cmd->head.msg_len = 0; + } + cmd->head.type = package_type; cmd->head.src_id = hw_cfg->local_id; - memcpy(cmd->data, data, len); + if (len > 0 && data != NULL) { + 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) - { + 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) - { + if (hw_cfg->send_cache[cache_ord].state == ERPC_CMD_DEST_BUSY) { return ERPC_ERR_DEST_BUSY; } - if (erpc_sleep_tick != NULL) - { + if (erpc_sleep_tick != NULL) { erpc_sleep_tick(1); } - wait_time--; } u32 ret = ERPC_NO_ERROR; - do - { - if (wait_time == 0) - { + do { + if (wait_time == 0) { ret = ERPC_ERR_SEND_TIMEOUT; break; } - if (hw_cfg->send_cache[cache_ord].state == ERPC_CMD_SEND_ONCE) - { + if (hw_cfg->send_cache[cache_ord].state == ERPC_CMD_SEND_ONCE) { ret = ERPC_ERR_DEST_NO_RESPONSE; break; } - if (hw_cfg->send_cache[cache_ord].state == ERPC_CMD_SEND_REPEAT) - { + if (hw_cfg->send_cache[cache_ord].state == ERPC_CMD_SEND_REPEAT) { ret = ERPC_ERR_DEST_NO_RESPONSE; break; } @@ -192,13 +167,69 @@ u32 erpc_send(u8 hw, u8 dest_id, u16 port, u8 *data, u16 len) hw_cfg->send_cache[cache_ord].state = ERPC_CMD_NO_ERROR; return ret; } +u32 erpc_send(u8 hw, u8 dest_id, u16 port, u8 *data, u16 len) { + erpc_hw_cfg_t *hw_cfg = erpc_hw_get(hw); + u32 ret = + erpc_send_base(hw_cfg, dest_id, port, PACKAGE_TYPE_CMD_REQ, data, len); + return ret; +} -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) - { +u32 erpc_wait_resp_package(u8 hw, u8 dest_id, u16 port, u8 *reply_data, + u16 *reply_len, u32 time_out) { + erpc_hw_cfg_t *hw_cfg = erpc_hw_get(hw); + CHECK_IF_ERROR(hw_cfg == NULL, ERPC_ERR_NOFOND_HW); + while (time_out > 0) { + for (int i = 0; i < MAX_REC_CMD_CACHE_NUM; i++) { + erpc_data_cache_t *rec_cahce = &hw_cfg->rec_cache[i]; + if (rec_cahce->state != ERPC_CMD_RESP_OK) { + continue; + } + erpc_cmd_def_t *cmd = (erpc_cmd_def_t *)&rec_cahce->data[0]; + if (cmd->head.port != port) { + continue; + } + if (cmd->head.src_id != dest_id) { + continue; + } + if (reply_data != NULL) { + memccpy(reply_data, cmd->data, 0, cmd->head.msg_len); + *reply_len = cmd->head.msg_len; + } + rec_cahce->state = ERPC_CMD_NO_ERROR; + return ERPC_NO_ERROR; + } + if (erpc_sleep_tick != NULL) { + erpc_sleep_tick(1); + } + time_out--; + } + CHECK_IF_ERROR(time_out == 0, ERPC_ERR_DEST_NO_REPLY); + return ERPC_NO_ERROR; +} +u32 erpc_send_wait_reply(u8 hw, u8 dest_id, u16 port, u8 *data, u16 len, + u8 *reply_data, u16 *reply_len, u32 timeout) { + u32 ret = erpc_send(hw, dest_id, port, data, len); + if (reply_len != NULL) { + *reply_len = 0; + } + CHECK_IF_ERROR(ret != ERPC_NO_ERROR, ret); + printf("send ok\n"); + ret = + erpc_wait_resp_package(hw, dest_id, port, reply_data, reply_len, timeout); + CHECK_IF_ERROR(ret != ERPC_NO_ERROR, ret); + return ERPC_NO_ERROR; +} +u32 erpc_replay(u8 hw, u8 dest_id, u16 port, u8 *data_out, u16 len) { + erpc_hw_cfg_t *hw_cfg = erpc_hw_get(hw); + u32 ret = erpc_send_base(hw_cfg, dest_id, port, PACKAGE_TYPE_CMD_REPEAT, + data_out, len); + + return ret; +} + +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(); @@ -208,17 +239,15 @@ u32 erpc_send_data(erpc_hw_cfg_t *hw) hw->send_cache[i].state = ERPC_CMD_SEND_ONCE; } } + return ERPC_NO_ERROR; } -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) - { +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) - { + if (cmd_rev->head.port == cmd_send->head.port) { hw->send_cache[i].state = ERPC_CMD_SEND_OK; return ERPC_NO_ERROR; } @@ -226,30 +255,41 @@ u32 erpc_rev_ack_package(erpc_hw_cfg_t *hw, erpc_cmd_def_t *cmd_rev) } return ERPC_NO_ERROR; } - +u32 erpc_rev_resp_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_RESP_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_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) - { +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) - { + 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); + u32 ret = hw->write((u8 *)hw->send_cache[i].data, len); hw->send_unlock(); hw->send_cache[i].state = ERPC_CMD_SEND_REPEAT; + CHECK_IF_ERROR(ret, ERPC_ERR_HW_SEND_FAIL); // return ERPC_NO_ERROR; } } } return ERPC_NO_ERROR; } -u32 erpc_send_ack_package(erpc_hw_cfg_t *hw, erpc_cmd_def_t *cmd_rev) -{ +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; @@ -265,73 +305,68 @@ u32 erpc_send_ack_package(erpc_hw_cfg_t *hw, erpc_cmd_def_t *cmd_rev) 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) - { +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) - { + if (crc_result) { hw->rec_cache[i].state = ERPC_CMD_NO_ERROR; continue; } // 丢弃不是本地数据包 - if (cmd->head.dest_id != hw->local_id) - { - + 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: + switch (cmd->head.type) { + case PACKAGE_TYPE_CMD_REQ: + printf("{REQ}\n"); + erpc_send_ack_package(hw, cmd); + hw->rec_cache[i].state = ERPC_CMD_WAIT_TASK_DEAL; + break; + case PACKAGE_TYPE_CMD_REQ_ACK: + case PACKAGE_TYPE_CMD_RESP_ACK: + printf("{ACK}\n"); + 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; + case PACKAGE_TYPE_CMD_RESP: + printf("{RESP}\n"); + erpc_rev_resp_package(hw, cmd); + hw->rec_cache[i].state = ERPC_CMD_RESP_OK; + break; + default: - break; + break; } } } + return ERPC_NO_ERROR; } -void erpc_rev_package_core() -{ - +void erpc_rev_package_core() { list_t *list = &erpc_hw; - if (list->data == NULL) - { + if (list->data == NULL) { return; } - while (list != NULL) - { + 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) -{ +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) - { + for (int i = 0; i < MAX_REC_CMD_CACHE_NUM; i++) { + if (hw_cfg->rec_cache[i].state == ERPC_CMD_NO_ERROR) { printf("set rev cache %d\r\n", i); memcpy(hw_cfg->rec_cache[i].data, data, len); hw_cfg->rec_cache[i].state = ERPC_CMD_WAIT_SERVER_DEAL; @@ -340,77 +375,63 @@ u32 erpc_set_rev_cahce(u8 hw, u8 *data, u16 len) } return ERPC_ERR_REC_CACHE_FULL; } -void erpc_send_deal_core() -{ +void erpc_send_deal_core() { list_t *list = &erpc_hw; - if (list->data == NULL) - { + if (list->data == NULL) { return; } - while (list != NULL) - { + while (list != NULL) { erpc_hw_cfg_t *hw = (erpc_hw_cfg_t *)list->data; erpc_send_data(hw); } - if (erpc_sleep_tick != NULL) - { + if (erpc_sleep_tick != NULL) { erpc_sleep_tick(1); } } -void erpc_rev_deal_core() -{ +void erpc_rev_deal_core() { list_t *list = &erpc_hw; - if (list->data == NULL) - { + if (list->data == NULL) { return; } - while (list != NULL) - { + 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) - { + { // 遍历接收缓存 + for (int j = 0; j < MAX_REC_CMD_CACHE_NUM; j++) { + { // 发现等待处理的数据包 + if (hw->rec_cache[j].state != ERPC_CMD_WAIT_TASK_DEAL) { continue; } } - { // 多线程下,抢占处理权限 + { // 多线程下,抢占处理权限 hw->deal_lock(); - if (hw->rec_cache[j].state == ERPC_CMD_WAIT_TASK_DEAL) - { + if (hw->rec_cache[j].state == ERPC_CMD_WAIT_TASK_DEAL) { // 获取指令的处理权限 hw->rec_cache[j].state = ERPC_CMD_WAIT_TASK_DEAL_FINISH; - } - else - { + } else { // 已经有线程抢先执行了 hw->deal_unlock(); continue; } hw->deal_unlock(); } - { // 处理指令 + { // 处理指令 // 搜索指令列表 list_t *cmd_list = &hw->cmd_list; // 链表是空的 - if (cmd_list->data == NULL) - { + if (cmd_list->data == NULL) { continue; } // 获取指令指针 erpc_cmd_def_t *cmd_def = (erpc_cmd_def_t *)hw->rec_cache[j].data; - while (cmd_list != NULL) - { // 搜索指令列表 + while (cmd_list != NULL) { // 搜索指令列表 erpc_cmd_list_t *cmd_obj = (erpc_cmd_list_t *)cmd_list->data; - if (cmd_obj->cmd == cmd_def->head.port) - { - if (cmd_obj->handle != NULL) - { + if (cmd_obj->cmd == cmd_def->head.port) { + if (cmd_obj->handle != NULL) { // 指令调用 - cmd_obj->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); + cmd_obj->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); } break; @@ -424,8 +445,7 @@ void erpc_rev_deal_core() } list = list->next; } - if (erpc_sleep_tick != NULL) - { + 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 a32907d..1834a27 100644 --- a/erpc_core.h +++ b/erpc_core.h @@ -1,21 +1,21 @@ #ifndef ERPC_CORE_H_ #define ERPC_CORE_H_ -#include "config.h" -#include "list.h" #include #include #include + +#include "config.h" +#include "list.h" #define ERPC_VERSION "0.0.1" -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_REPEAT, // crc校验失败,请求重发 + PACKAGE_TYPE_CMD_REPEAT, // crc校验失败,请求重发 PACKAGE_TYPE_DEV_POWER_OFF, PACKAGE_TYPE_CMD_SERCH_DEV_ONLINE, } package_type; @@ -23,61 +23,58 @@ typedef enum package_type // 广播ID #define ERPC_BOARDCAST_ID 0xff -typedef struct erpc_cmd_head_t -{ +typedef struct erpc_cmd_head_t { u8 src_id; u8 dest_id; - package_type type; - u16 port; // 指令号,指令号=端口号 + u8 type; // package_type + u16 port; // 指令号,指令号=端口号 u8 msg_len; } erpc_cmd_head_t; -typedef struct erpc_cmd_def_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, // 目标设备忙 +#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_CMD_RESP_OK, // 指令响应成功 } erpc_status; -typedef struct erpc_data_cache_t -{ +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 u32 (*erpc_cmd_handle_t)(u8 src_id, u8 dest_id, u16 port, u8 *data, + u16 len); -typedef struct erpc_cmd_list_t -{ +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 enum ERPC_ROLE -{ +typedef enum ERPC_ROLE { ERPC_ROLE_MASTER, ERPC_ROLE_SLAVE, } ERPC_ROLE; -typedef struct erpc_hw_cfg_t -{ +typedef struct erpc_hw_cfg_t { u8 ord; u8 local_id; u8 (*write)(u8 *data, u16 len); @@ -91,40 +88,49 @@ typedef struct erpc_hw_cfg_t } erpc_hw_cfg_t; #define CHECK_IF_ERROR(condition, error) \ - if (condition) \ - { \ + if (condition) { \ return error; \ } #define CHECK_IF_ERROR_AND_DO(condition, error, action) \ - if (condition) \ - { \ + if (condition) { \ action; \ return error; \ } -typedef enum erpc_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_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_ERR_DEST_NO_RESPONSE, // 目标设备无响应 + ERPC_ERR_DEST_NO_REPLY, // 目标设备无回复或者回复超时 + 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(); // 处理接受到的指令,业务层面处理 +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); +/** + * 发送消息并等待回复 + */ +u32 erpc_send_wait_reply(u8 hw, u8 dest_id, u16 port, u8 *data, u16 len, + u8 *reply_data, u16 *reply_len, u32 timeout); +/** + * 回复消息 + */ +u32 erpc_replay(u8 hw, u8 dest_id, u16 port, u8 *data_out, u16 len); #endif /* ERPC_CORE_H_ */ \ No newline at end of file diff --git a/erpc_core.o b/erpc_core.o index f4ec43652f5900f2c1abc5a755018f5cc29cc63f..9d0e0bafc42b28563693fc46f2935ac98afee59f 100644 GIT binary patch literal 8141 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 delta 2103 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 delta 17361 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 z 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 OX|}xoMeKIn$^REuc73n_