This commit is contained in:
parent
de5c5a1e9b
commit
2627e20b32
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
// 使用 IntelliSense 了解相关属性。
|
||||
// 悬停以查看现有属性的描述。
|
||||
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": []
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
2
config.h
2
config.h
|
@ -1,7 +1,7 @@
|
|||
#ifndef _CONFIG_H_
|
||||
#define _CONFIG_H_
|
||||
|
||||
#define ERPC_VERSION "0.0.1"
|
||||
|
||||
|
||||
|
||||
#define u8 unsigned char
|
||||
|
|
12
crc16.c
12
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);
|
||||
|
|
451
erpc_core.c
451
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);
|
||||
}
|
||||
}
|
130
erpc_core.h
130
erpc_core.h
|
@ -2,56 +2,124 @@
|
|||
#define ERPC_CORE_H_
|
||||
|
||||
#include "config.h"
|
||||
#include "list.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#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_ */
|
Binary file not shown.
57
erpc设计文档.md
57
erpc设计文档.md
|
@ -1,58 +1 @@
|
|||
|
||||
|
||||
|
||||
CRC16 校验长度为 16-256字节较为合适。
|
||||
|
||||
ACK丢了不重发
|
||||
|
||||
|
||||
|
||||
|
||||
# 发送指令流程
|
||||
1.发送数据后,始终要等待ack
|
||||
2.接收数据后,始终要回复ack
|
||||
3.获得ack不代表指令成功
|
||||
4.crc校验不成功,发送repeat包
|
||||
5.指令号=端口号
|
||||
|
||||
## 正常传输
|
||||
| host | slave |
|
||||
| ---------------- | ---------------- |
|
||||
| 发送指令 | 等待指令 |
|
||||
| 等待ACK回复 | 发送ACK |
|
||||
| 等待指令处理完成 | 处理指令 |
|
||||
| 等待指令处理完成 | 发送resp |
|
||||
| 发送resp_ack | 等待resp_ack回复 |
|
||||
| 处理完成 | 处理完成 |
|
||||
## 指令丢失
|
||||
| host | slave |
|
||||
| ---------------- | --------------------- |
|
||||
| 发送指令 | 等待指令 |
|
||||
| 发送指令丢失 | 等待指令 |
|
||||
| 超时重发指令 | 等待指令 |
|
||||
| 等待ACK回复 | 指令接收成功,发送ACK |
|
||||
| 等待指令处理完成 | 处理指令 |
|
||||
| 等待指令处理完成 | 发送resp |
|
||||
| 发送resp_ack | 等待resp_ack回复 |
|
||||
| 处理完成 | 处理完成 |
|
||||
## cmd ack 丢失
|
||||
| host | slave |
|
||||
| ---------------- | -------------------------- |
|
||||
| 发送指令 | 等待指令 |
|
||||
| 等待ACK回复 | 指令接收成功,发送ACK |
|
||||
| 超时重发 | 指令已经开始行,发现重发包,发送ACK|
|
||||
| 等待ACK回复 | 处理指令 |
|
||||
| 等待指令处理完成 | 处理指令 |
|
||||
| 等待指令处理完成 | 发送resp |
|
||||
| 发送resp_ack | 等待resp_ack回复 |
|
||||
| 处理完成 | 处理完成 |
|
||||
## resp ack 丢失
|
||||
| host | slave |
|
||||
| ---------------- | ---------------- |
|
||||
| 发送指令 | 等待指令 |
|
||||
| 等待ACK回复 | 发送ACK |
|
||||
| 等待指令处理完成 | 处理指令 |
|
||||
| 等待指令处理完成 | 发送resp |
|
||||
| 发送resp_ack | 等待resp_ack回复 |
|
||||
| 处理完成 |发送resp |
|
||||
| 发送resp_ack | 处理完成 |
|
|
@ -0,0 +1,89 @@
|
|||
#include "list.h"
|
||||
#include "stdio.h"
|
||||
|
||||
list_t *list_create(void *data)
|
||||
{
|
||||
list_t *node = (list_t *)malloc(sizeof(list_t));
|
||||
if (node == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
node->data = 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;
|
||||
}
|
||||
}
|
|
@ -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_ */
|
|
@ -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
|
|
@ -0,0 +1,133 @@
|
|||
|
||||
// #ifndef WINDOWS
|
||||
// #error "This file is for Windows only"
|
||||
// #endif
|
||||
|
||||
#include "erpc_core.h"
|
||||
#include "windows.h"
|
||||
#include <stdio.h>
|
||||
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;
|
||||
}
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,2 @@
|
|||
#include "erpc_core.h"
|
||||
|
Loading…
Reference in New Issue