重构代码
This commit is contained in:
parent
1d81a3b02c
commit
5c9384b9af
|
@ -1,16 +0,0 @@
|
|||
<mxfile host="Electron" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/24.7.17 Chrome/128.0.6613.36 Electron/32.0.1 Safari/537.36" version="24.7.17">
|
||||
<diagram name="第 1 页" id="iJ2ThG75liGc15h7RsxG">
|
||||
<mxGraphModel dx="1036" dy="614" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="KNYXeKKRTsCmKzyxKpLt-1" value="host" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="60" y="280" width="90" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="KNYXeKKRTsCmKzyxKpLt-2" value="slave" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="270" y="280" width="90" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
|
@ -1,5 +1,7 @@
|
|||
{
|
||||
"files.associations": {
|
||||
"*.ndjson": "jsonl",
|
||||
"*.dbclient-js": "javascript",
|
||||
"spi_port.h": "c",
|
||||
"cmd_def.h": "c",
|
||||
"config.h": "c",
|
||||
|
@ -20,7 +22,10 @@
|
|||
"windows.h": "c",
|
||||
"string.h": "c",
|
||||
"stdio.h": "c",
|
||||
"stdlib.h": "c"
|
||||
"stdlib.h": "c",
|
||||
"algorithm": "c",
|
||||
"initializer_list": "c",
|
||||
"utility": "c"
|
||||
},
|
||||
"makefile.launchConfigurations": [
|
||||
{
|
||||
|
|
BIN
build/crc16.o
BIN
build/crc16.o
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
build/list.o
BIN
build/list.o
Binary file not shown.
Binary file not shown.
10
config.h
10
config.h
|
@ -9,6 +9,14 @@
|
|||
#define u32 unsigned int
|
||||
|
||||
#define UNUSED(x) (void)(x)
|
||||
|
||||
|
||||
#define ERPC_DEBUG_ENABLE 1
|
||||
#if(ERPC_DEBUG_ENABLE == 1)
|
||||
#define ERPC_DEBUG(...) printf(__VA_ARGS__)
|
||||
// #define ERPC_DEBUG(...)
|
||||
#else
|
||||
#define ERPC_DEBUG(...)
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _CONFIG_H_ */
|
41
crc16.c
41
crc16.c
|
@ -1,6 +1,6 @@
|
|||
#include "crc16.h"
|
||||
|
||||
static const uint16_t crc16tab[256] = {
|
||||
static const u16 crc16tab[256] = {
|
||||
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108,
|
||||
0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210,
|
||||
0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b,
|
||||
|
@ -31,38 +31,7 @@ static const uint16_t crc16tab[256] = {
|
|||
0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74,
|
||||
0x2e93, 0x3eb2, 0x0ed1, 0x1ef0};
|
||||
|
||||
// uint16_t crc16(const unsigned char *buf, size_t len) {
|
||||
// int counter;
|
||||
// uint16_t crc = 0;
|
||||
// for (counter = 0; counter < (int)len; counter++)
|
||||
// crc = (crc << 8) ^ crc16tab[((crc >> 8) ^ *buf++) & 0x00FF];
|
||||
// return crc;
|
||||
// }
|
||||
|
||||
u16 cmd_cal_crc16(erpc_cmd_def_t *cmd) {
|
||||
u16 crc = 0;
|
||||
u32 counter = 0;
|
||||
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);
|
||||
return crc;
|
||||
}
|
||||
/**
|
||||
* 检查crc16校验
|
||||
* return 0:校验成功
|
||||
* return 1:校验失败
|
||||
*/
|
||||
u8 cmd_check_crc16(erpc_cmd_def_t *cmd) {
|
||||
u16 crc = cmd_cal_crc16(cmd);
|
||||
if (cmd->crc_16[0] != (u8)(crc >> 8) ||
|
||||
cmd->crc_16[1] != (u8)(crc & 0x00FF)) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
inline u16 crc16_cal(u16 data,u16 crc)
|
||||
{
|
||||
return (crc << 8) ^ crc16tab[((crc >> 8) ^ data) & 0x00FF];
|
||||
}
|
||||
|
|
6
crc16.h
6
crc16.h
|
@ -8,10 +8,8 @@ extern "C" {
|
|||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "config.h"
|
||||
#include "erpc_core.h"
|
||||
uint16_t crc16(const unsigned char *buf, size_t len);
|
||||
u8 cmd_check_crc16(erpc_cmd_def_t *cmd);
|
||||
u16 cmd_cal_crc16(erpc_cmd_def_t *cmd);
|
||||
u16 crc16_cal(u16 data,u16 crc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
|
985
erpc_core.c
985
erpc_core.c
File diff suppressed because it is too large
Load Diff
227
erpc_core.h
227
erpc_core.h
|
@ -1,145 +1,110 @@
|
|||
#ifndef ERPC_CORE_H_
|
||||
#define ERPC_CORE_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef _ERPC_CORE_H_
|
||||
#define _ERPC_CORE_H_
|
||||
#include "config.h"
|
||||
#include "list.h"
|
||||
#define ERPC_VERSION "0.0.1"
|
||||
#define ERPC_VERSION_MAJOR 1
|
||||
#define ERPC_VERSION_MINOR 0
|
||||
#define ERPC_VERSION_PATCH 0
|
||||
|
||||
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_DEV_POWER_OFF,
|
||||
PACKAGE_TYPE_CMD_SERCH_DEV_ONLINE,
|
||||
} package_type;
|
||||
#define ERPC_MSG_HEADER_SIZE 9
|
||||
#define ERPC_MSG_DATA_MAX_SIZE (256 - ERPC_MSG_HEADER_SIZE + 2)
|
||||
#define ERPC_MSG_CACHE_SIZE 16 // Maximum number of messages in cache
|
||||
|
||||
// 广播ID
|
||||
#define ERPC_BOARDCAST_ID 0xff
|
||||
#define ERPC_SEND_TIMEOUT 30 // 发送超时时间,单位tick
|
||||
typedef struct erpc_msg_t
|
||||
{
|
||||
u8 src_id;
|
||||
u8 dest_id;
|
||||
u8 type;
|
||||
u16 port;
|
||||
u16 len;
|
||||
u16 crc;
|
||||
u8 data[ERPC_MSG_DATA_MAX_SIZE];
|
||||
} erpc_msg_t;
|
||||
|
||||
typedef struct erpc_cmd_head_t {
|
||||
u8 src_id;
|
||||
u8 dest_id;
|
||||
u8 type; // package_type
|
||||
u16 port; // 指令号,指令号=端口号
|
||||
u8 msg_len;
|
||||
} erpc_cmd_head_t;
|
||||
|
||||
#define MAX_CMD_LEN (256 - sizeof(erpc_cmd_head_t)) // crc16最大支持256字节
|
||||
|
||||
typedef struct erpc_cmd_def_t {
|
||||
erpc_cmd_head_t head;
|
||||
u8 crc_16[2];
|
||||
u8 data[MAX_CMD_LEN];
|
||||
} erpc_cmd_def_t;
|
||||
|
||||
#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_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 {
|
||||
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 enum ERPC_ROLE {
|
||||
ERPC_ROLE_MASTER,
|
||||
ERPC_ROLE_SLAVE,
|
||||
} ERPC_ROLE;
|
||||
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; \
|
||||
}
|
||||
#define CHECK_IF_ERROR_AND_DO(condition, error, action) \
|
||||
if (condition) { \
|
||||
action; \
|
||||
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_DEST_NO_REPLY, // 目标设备无回复或者回复超时
|
||||
ERPC_ERR_MALLOC_ERROR, // malloc失败,内存不足
|
||||
ERPC_ERR_HW_EXIST, // 硬件已经存在
|
||||
ERPC_ERR_HW_NOT_EXIST, // 硬件不存在
|
||||
ERPC_ERR_REC_CACHE_FULL, // 接收缓存满
|
||||
typedef struct erpc_cache_t
|
||||
{
|
||||
u8 state;
|
||||
erpc_msg_t msg;
|
||||
} erpc_cache_t;
|
||||
typedef enum erpc_msg_type
|
||||
{
|
||||
ERPC_MSG_TYPE_REQUEST = 0,
|
||||
ERPC_MSG_TYPE_ACK,
|
||||
ERPC_MSG_TYPE_RESPONSE,
|
||||
}erpc_msg_type;
|
||||
typedef enum erpc_cache_state
|
||||
{
|
||||
CACHE_FREE = 0,
|
||||
// 占用
|
||||
CACHE_IN_USE,
|
||||
// 发送cache
|
||||
CACHE_WAIT_SEND,
|
||||
CACHE_SEND_OK,
|
||||
CACHE_SEND_HW_ERR,
|
||||
// 接收cache
|
||||
CACHE_GET_DATA, // 发现数据
|
||||
CACHE_GET_MSG, // 发现完整消息
|
||||
CACHE_REC_ACK, // 收到ACK
|
||||
CACHE_GET_RESP, // 收到RESP数据包
|
||||
CACHE_WAIT_HANDLE, // 等待处理
|
||||
} erpc_cache_state;
|
||||
typedef enum erpc_error
|
||||
{
|
||||
ERPC_OK = 0,
|
||||
// 发送REQ
|
||||
ERPC_ERR_NO_FREE_SEND_CACHE, // 没有空闲的发送缓存
|
||||
ERPC_ERR_SEND_TIMEOUT, // 发送REQ超时
|
||||
ERPC_ERR_SEND_ACK_TIMEOUT, // 发送REQ成功,但是没有收到ACK
|
||||
ERPC_ERR_SEND_PORT_IS_INUSE, // 发送失败,端口已被占用
|
||||
ERPC_ERR_SEND_HW_ERR, // 发送失败,硬件错误
|
||||
// 接收REQ
|
||||
ERPC_ERR_NO_CMD_RETURN, // 发生REQ成功,但是没有收到RESP包
|
||||
} erpc_error;
|
||||
typedef void (*erpc_sleep)(u32 tick);
|
||||
typedef struct erpc_hw_t
|
||||
{
|
||||
u8 local_id;
|
||||
void (*lock)(void);
|
||||
void (*unlock)(void);
|
||||
void (*sleep)(u32 ms);
|
||||
u32 (*send)(u8 *data, u16 len);
|
||||
erpc_cache_t send_cache[ERPC_MSG_CACHE_SIZE];
|
||||
erpc_cache_t recv_cache[ERPC_MSG_CACHE_SIZE];
|
||||
list_t handler_list;
|
||||
} erpc_hw_t;
|
||||
|
||||
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;
|
||||
typedef struct handler_list_t
|
||||
{
|
||||
u16 port;
|
||||
void (*handle)(erpc_hw_t *hw, erpc_cache_t *cache, u8 *data, u16 len);
|
||||
} handler_list_t;
|
||||
|
||||
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);
|
||||
#define CHECK_DEAL(condition, error) \
|
||||
if ((condition)) \
|
||||
return error;
|
||||
/**
|
||||
* 单纯发送消息
|
||||
* 内核函数,需要手动sleep
|
||||
*/
|
||||
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);
|
||||
void send_core(erpc_hw_t *hw);
|
||||
void recv_core(erpc_hw_t *hw);
|
||||
void recv_handle(erpc_hw_t *hw);
|
||||
|
||||
/**
|
||||
* 广播消息
|
||||
* 用户函数
|
||||
*/
|
||||
u32 erpc_boardcast(u16 port, u8 *data, u16 len);
|
||||
u32 send_request(erpc_hw_t *hw, u8 dest_id, u16 port, u8 *data, u16 len, u16 timeout, u8 retry);
|
||||
u32 send_request_wait_response(erpc_hw_t *hw, u8 dest_id, u16 port, u8 *data_out, u16 len_out, u8 *data_in, u16 *len_in, u16 send_timeout, u16 recv_timeout, u8 retry);
|
||||
u32 send_response(erpc_hw_t *hw, erpc_cache_t *cache, u8 *data, u16 len, u16 timeout, u8 retry);
|
||||
u32 write_rec_cache(erpc_hw_t *hw, u8 *data, u16 len);
|
||||
/**
|
||||
* 注册处理函数
|
||||
*/
|
||||
#define EXPORT_ERPC_HANDLE(hw, _port, _handle) \
|
||||
static handler_list_t _A##_handle = \
|
||||
{ \
|
||||
.port = _port,\
|
||||
.handle = _handle,\
|
||||
};\
|
||||
EXPORT_LIST_NODE(hw.list,_A##_handle);
|
||||
|
||||
|
||||
#endif /* ERPC_CORE_H_ */
|
||||
#endif /* _ERPC_CORE_H_ */
|
|
@ -1,3 +0,0 @@
|
|||
#include "erpc_net.h"
|
||||
#include "erpc_core.h"
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
#include "erpc_core.h"
|
||||
|
||||
u32 erpc_find_all();
|
|
@ -0,0 +1,104 @@
|
|||
#include "erpc_core.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
HANDLE hMutex;
|
||||
|
||||
static void lock()
|
||||
{
|
||||
WaitForSingleObject(hMutex, INFINITE);
|
||||
}
|
||||
|
||||
static void unlock()
|
||||
{
|
||||
ReleaseMutex(hMutex);
|
||||
}
|
||||
static void sleep(u32 ms)
|
||||
{
|
||||
Sleep(ms);
|
||||
}
|
||||
extern erpc_hw_t port_self;
|
||||
static u32 erpc_send(u8 *data, u16 len)
|
||||
{
|
||||
write_rec_cache(&port_self,data,len);
|
||||
}
|
||||
erpc_hw_t port_self = {
|
||||
.lock = lock,
|
||||
.unlock = unlock,
|
||||
.sleep = sleep,
|
||||
.local_id = 0x12,
|
||||
.send = erpc_send,
|
||||
};
|
||||
|
||||
|
||||
static void test1(){
|
||||
|
||||
}
|
||||
DWORD WINAPI fun(LPVOID lpParam)
|
||||
{
|
||||
UNUSED(lpParam);
|
||||
while (1)
|
||||
{
|
||||
Sleep(1000);
|
||||
}
|
||||
}
|
||||
DWORD WINAPI send_thread(LPVOID lpParam)
|
||||
{
|
||||
UNUSED(lpParam);
|
||||
while (1)
|
||||
{
|
||||
send_core(&port_self);
|
||||
Sleep(1);
|
||||
}
|
||||
}
|
||||
DWORD WINAPI recv_thread(LPVOID lpParam)
|
||||
{
|
||||
UNUSED(lpParam);
|
||||
while (1)
|
||||
{
|
||||
recv_core(&port_self);
|
||||
Sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
DWORD WINAPI recv_handle_thread(LPVOID lpParam)
|
||||
{
|
||||
UNUSED(lpParam);
|
||||
while (1)
|
||||
{
|
||||
recv_handle(&port_self);
|
||||
Sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
hMutex = CreateMutex(NULL, FALSE, TEXT("MyMutex"));
|
||||
|
||||
if (hMutex == NULL)
|
||||
{
|
||||
printf("CreateMutex error: %d\n", GetLastError());
|
||||
return 1;
|
||||
}
|
||||
|
||||
HANDLE hThreads[4];
|
||||
|
||||
hThreads[0] = CreateThread(NULL, 0, fun, NULL, 0, NULL);
|
||||
hThreads[1] = CreateThread(NULL, 0, send_thread, NULL, 0, NULL);
|
||||
hThreads[2] = CreateThread(NULL, 0, recv_thread, NULL, 0, NULL);
|
||||
hThreads[3] = CreateThread(NULL, 0, recv_handle_thread, NULL, 0, NULL);
|
||||
// 等待所有线程完成
|
||||
WaitForMultipleObjects(4, hThreads, TRUE, INFINITE);
|
||||
|
||||
// 关闭线程句柄
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
CloseHandle(hThreads[i]);
|
||||
}
|
||||
|
||||
// 关闭Mutex句柄
|
||||
CloseHandle(hMutex);
|
||||
|
||||
return 0;
|
||||
}
|
39
erpc设计文档.md
39
erpc设计文档.md
|
@ -1,39 +0,0 @@
|
|||
|
||||
## 协议设计
|
||||
|
||||
### 指令通讯
|
||||
1. 指令发送方法:<br>
|
||||
采用send-ack模式,即主机发送指令后,等待目标设备的ack确认,确认后才认为指令发送成功。
|
||||
2. notify-noreply模式:<br>
|
||||
接口:<br>
|
||||
```c
|
||||
u32 erpc_sand(u8 hw, u8 dest_id, u16 port, u8 *data, u16 len)
|
||||
```
|
||||
描述:<br>
|
||||
主机对目标设备发送一条指令,并不期待回复。其本质就是发送一次指令。
|
||||

|
||||
3. notify-reply模式:<br>
|
||||
接口:<br>
|
||||
```c
|
||||
//主机:
|
||||
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);
|
||||
|
||||
```
|
||||
描述:<br>
|
||||
本质由2条指令组成。<br>
|
||||
主机发送req指令,从机直接回复。主机开始等待从机指令。<br>
|
||||
从机处理完成后,向主机发送rep指令,并附带回复数据。<br>
|
||||
主机收到rep指令后,开始等待rep指令的ack确认。<br>
|
||||

|
||||
4. 指令工作在单线程模式下:<br>
|
||||
指令发送后,等待ack确认,直到确认后才认为指令发送成功。如果确认超时,则认为指令发送失败。
|
||||
可以在上述的接口中发现 cmd 并不定义为cmd,而是用了port的称呼。port的取值范围为0~65535,可以用来表示不同的指令。<br>
|
||||
|
||||
4. 多device通讯方法:<br>
|
||||
每个port工作是单线程的,这就意味着,如果有多个device需要同时发送指令,则需要多线程或多进程。也就意味着需要定义不同的port号,来区分不同的线程,哪怕他是相同的指令。<br>
|
||||
例如:节点0x03中挂在了3个电机,需要这3个电机同时运动,此时理论上指令是相同的,但是device不同的。通讯库没有做device id的区分。为此需要将port号划分为cmd + device id的形式。cmd相同的指令,device id不同,这样就可以实现多device通讯。<br>
|
||||
u16(port) = u8(cmd) + u8(device_id);<br>
|
||||
这样一个cmd号需要链接到多个port上。此时的cmd可叫做cmd组
|
||||

|
110
list.c
110
list.c
|
@ -1,90 +1,86 @@
|
|||
#include "list.h"
|
||||
#include "stdio.h"
|
||||
#include "stdlib.h"
|
||||
#include "config.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;
|
||||
}
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
list_t *list_append(list_t *head, void *data)
|
||||
int list_node_add(list_t *list, void *data)
|
||||
{
|
||||
list_t *node = list_create(data);
|
||||
if (node == NULL)
|
||||
list_node_t *new_node = (list_node_t *)malloc(sizeof(list_node_t));
|
||||
if (new_node == NULL)
|
||||
{
|
||||
return NULL;
|
||||
return LIST_ERR_MALLOC_FAILED;
|
||||
}
|
||||
if (head == NULL)
|
||||
new_node->data = data;
|
||||
new_node->next = NULL;
|
||||
if (*list == NULL)
|
||||
{
|
||||
return NULL;
|
||||
*list = new_node;
|
||||
}
|
||||
else
|
||||
{
|
||||
list_t *tail = head;
|
||||
while (tail->next != NULL)
|
||||
list_node_t *node = *list;
|
||||
while (node->next != NULL)
|
||||
{
|
||||
tail = tail->next;
|
||||
node = node->next;
|
||||
}
|
||||
tail->next = node;
|
||||
node->next = new_node;
|
||||
}
|
||||
return head;
|
||||
}
|
||||
|
||||
void list_print(list_t *head)
|
||||
{
|
||||
list_t *node = head;
|
||||
while (node != NULL)
|
||||
{
|
||||
ERPC_DEBUG("%p\n", node->data);
|
||||
node = node->next;
|
||||
}
|
||||
return LIST_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy a list and all its nodes.
|
||||
* @param head The head of the list.
|
||||
*/
|
||||
void list_destroy(list_t *head)
|
||||
int list_node_remove(list_t *list, void *data)
|
||||
{
|
||||
list_t *node = head;
|
||||
while (node != NULL)
|
||||
if (*list == NULL)
|
||||
{
|
||||
list_t *next = node->next;
|
||||
free(node);
|
||||
node = next;
|
||||
return LIST_ERR_LIST_IS_NULL;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 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;
|
||||
list_node_t *node = *list;
|
||||
list_node_t *prev = NULL;
|
||||
while (node != NULL)
|
||||
{
|
||||
if (node->data == data)
|
||||
{
|
||||
if (prev == NULL)
|
||||
{
|
||||
head = node->next;
|
||||
if (node->next != NULL)
|
||||
{
|
||||
*list = node->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
*list = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
prev->next = node->next;
|
||||
if (node->next != NULL)
|
||||
{
|
||||
prev->next = node->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
prev->next = NULL;
|
||||
}
|
||||
}
|
||||
free(node);
|
||||
return;
|
||||
return LIST_OK;
|
||||
}
|
||||
prev = node;
|
||||
node = node->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int list_size(list_t *list)
|
||||
{
|
||||
if (*list == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
int size = 0;
|
||||
list_node_t *node = *list;
|
||||
while (node != NULL)
|
||||
{
|
||||
size++;
|
||||
node = node->next;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
|
60
list.h
60
list.h
|
@ -1,17 +1,47 @@
|
|||
#ifndef _LIST_H_
|
||||
#define _LIST_H_
|
||||
#ifndef LIST_H
|
||||
#define LIST_H
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif // __cplusplus
|
||||
typedef struct list_node_t
|
||||
{
|
||||
void *data;
|
||||
struct list_node_t *next;
|
||||
} list_node_t;
|
||||
|
||||
typedef list_node_t *list_t;
|
||||
typedef enum list_error
|
||||
{
|
||||
LIST_OK = 0,
|
||||
LIST_ERR_LIST_IS_NULL = 1,
|
||||
LIST_ERR_MALLOC_FAILED,
|
||||
} list_error;
|
||||
/**
|
||||
* @brief 创建一个节点,如果list为NULL,则创建一个空链表,否则创建一个节点并添加到链表尾部
|
||||
* @param list 链表指针
|
||||
* @param data 数据指针
|
||||
*/
|
||||
int list_node_add(list_t *list, void *data);
|
||||
/**
|
||||
* @brief 从链表中删除节点
|
||||
* @param list 链表指针
|
||||
* @param data 数据指针
|
||||
*/
|
||||
int list_node_remove(list_t *list, void *data);
|
||||
int list_size(list_t *list);
|
||||
|
||||
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_ */
|
||||
/**
|
||||
* @param list 链表
|
||||
* @param data 要添加的数据不要取地址,在宏定义里面自动取地址
|
||||
* @warning 这种方式增加节点,会导致无法确定节点添加的先后顺序,更换编译环境后可能会影响编译效率
|
||||
*/
|
||||
#define EXPORT_LIST_NODE(list, data) \
|
||||
int __attribute__((constructor)) export_list_node_##list_##data(void) \
|
||||
{ \
|
||||
return list_node_add(&list, (void *)&data); \
|
||||
}
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
#endif // LIST_H
|
||||
|
|
2
makefile
2
makefile
|
@ -7,7 +7,7 @@ CFLAGS = -Wall -Wextra -std=c11 -g
|
|||
BUILD_DIR = build
|
||||
# 源文件
|
||||
SRCS = erpc_core.c \
|
||||
port_self.c \
|
||||
erpc_port_self.c \
|
||||
crc16.c\
|
||||
list.c
|
||||
|
||||
|
|
BIN
picture/1.jpg
BIN
picture/1.jpg
Binary file not shown.
Before Width: | Height: | Size: 9.6 KiB |
BIN
picture/2.jpg
BIN
picture/2.jpg
Binary file not shown.
Before Width: | Height: | Size: 18 KiB |
BIN
picture/3.jpg
BIN
picture/3.jpg
Binary file not shown.
Before Width: | Height: | Size: 11 KiB |
208
port_self.c
208
port_self.c
|
@ -1,208 +0,0 @@
|
|||
|
||||
// #ifndef WINDOWS
|
||||
// #error "This file is for Windows only"
|
||||
// #endif
|
||||
|
||||
#include "erpc_core.h"
|
||||
#include "windows.h"
|
||||
#include <stdio.h>
|
||||
u32 hellworld(u8 hw, u8 src_id, u8 dest_id, u16 port, u8 *data, u16 len)
|
||||
{
|
||||
ERPC_DEBUG("Hello World:\n");
|
||||
ERPC_DEBUG("len = %d, msg :%s\n", len, data);
|
||||
// 防止编译警告
|
||||
UNUSED(hw);
|
||||
UNUSED(src_id);
|
||||
UNUSED(dest_id);
|
||||
UNUSED(port);
|
||||
UNUSED(data);
|
||||
UNUSED(len);
|
||||
return 0;
|
||||
}
|
||||
u32 hello_cat(u8 hw, u8 src_id, u8 dest_id, u16 port, u8 *data, u16 len)
|
||||
{
|
||||
ERPC_DEBUG("Hello Cat!\n");
|
||||
// 防止编译警告
|
||||
UNUSED(hw);
|
||||
UNUSED(src_id);
|
||||
UNUSED(dest_id);
|
||||
UNUSED(port);
|
||||
UNUSED(data);
|
||||
UNUSED(len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
u32 hello_dog(u8 hw, u8 src_id, u8 dest_id, u16 port, u8 *data, u16 len)
|
||||
{
|
||||
ERPC_DEBUG("Hello Dog!\n");
|
||||
// 防止编译警告
|
||||
u8 data_out[10] = "12345";
|
||||
u32 ret = erpc_replay(hw, dest_id, port, data_out, sizeof(data_out));
|
||||
ERPC_DEBUG("erpc_replay ret:%d\n", ret);
|
||||
// 防止编译警告
|
||||
UNUSED(ret);
|
||||
UNUSED(hw);
|
||||
UNUSED(src_id);
|
||||
UNUSED(dest_id);
|
||||
UNUSED(port);
|
||||
UNUSED(data);
|
||||
UNUSED(len);
|
||||
return 0;
|
||||
}
|
||||
erpc_cmd_list_t erpc_cmd_list[] = {
|
||||
{.cmd = 0x01, hellworld},
|
||||
{.cmd = 0x02, hello_cat},
|
||||
{.cmd = 0x03, hello_dog},
|
||||
};
|
||||
|
||||
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, u16 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 < (int)sizeof(erpc_cmd_list) / (int)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)
|
||||
{
|
||||
UNUSED(lpParam);
|
||||
while (1)
|
||||
{
|
||||
erpc_send_deal_core();
|
||||
}
|
||||
}
|
||||
DWORD WINAPI rev_package_task(LPVOID lpParam)
|
||||
{
|
||||
UNUSED(lpParam);
|
||||
|
||||
while (1)
|
||||
{
|
||||
// ERPC_DEBUG("rev_task\n");
|
||||
erpc_rev_package_core();
|
||||
erpc_rev_deal_core();
|
||||
}
|
||||
}
|
||||
|
||||
DWORD WINAPI rev_deal_task(LPVOID lpParam)
|
||||
{
|
||||
UNUSED(lpParam);
|
||||
|
||||
while (1)
|
||||
{
|
||||
// ERPC_DEBUG("rev_task\n");
|
||||
erpc_rev_package_core();
|
||||
erpc_rev_deal_core();
|
||||
}
|
||||
}
|
||||
|
||||
DWORD WINAPI test_task(LPVOID lpParam)
|
||||
{
|
||||
UNUSED(lpParam);
|
||||
ERPC_DEBUG("test_task\n");
|
||||
while (1)
|
||||
{
|
||||
// ERPC_DEBUG("[test_task]send\n");
|
||||
char msg[] = "miao miao miao\n";
|
||||
u32 ret = erpc_send(self_hw_cfg.ord, self_hw_cfg.local_id, 0x01, (u8 *)msg, sizeof(msg));
|
||||
ERPC_DEBUG("[test_task]send ret:%d\n", ret);
|
||||
ret = erpc_send(self_hw_cfg.ord, self_hw_cfg.local_id, 0x02, NULL, 0);
|
||||
ERPC_DEBUG("[test_task]send ret:%d\n", ret);
|
||||
u16 reply_len = 30;
|
||||
u8 data[reply_len];
|
||||
ret = erpc_send_wait_reply(self_hw_cfg.ord, self_hw_cfg.local_id, 0x03, NULL, 0, data, &reply_len, 1000);
|
||||
ERPC_DEBUG("[test_task]send ret:%d\n", ret);
|
||||
for (int i = 0; i < reply_len; i++)
|
||||
{
|
||||
ERPC_DEBUG("%c", data[i]);
|
||||
}
|
||||
ERPC_DEBUG("\n");
|
||||
|
||||
UNUSED(ret);
|
||||
sys_sleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
UNUSED(argc);
|
||||
UNUSED(argv);
|
||||
u32 ret = 0;
|
||||
ERPC_DEBUG("erpc_port_self start\n");
|
||||
ret = erpc_hw_add(&self_hw_cfg);
|
||||
ERPC_DEBUG("erpc_hw_add ret:%d\n", ret);
|
||||
CHECK_IF_ERROR(ret, 0);
|
||||
erpc_cmd_config();
|
||||
ERPC_DEBUG("erpc_cmd_config ret:%d\n", ret);
|
||||
erpc_sleep_tick = sys_sleep;
|
||||
|
||||
HANDLE threadHandle[4];
|
||||
deal_lock = CreateMutex(NULL, FALSE, NULL);
|
||||
if (deal_lock == NULL)
|
||||
{
|
||||
ERPC_DEBUG("创建互斥锁失败\n");
|
||||
return 1;
|
||||
}
|
||||
send_lock = CreateMutex(NULL, FALSE, NULL);
|
||||
if (send_lock == NULL)
|
||||
{
|
||||
ERPC_DEBUG("创建互斥锁失败\n");
|
||||
return 1;
|
||||
}
|
||||
threadHandle[0] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)send_task, NULL, 0, NULL);
|
||||
threadHandle[1] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)rev_package_task, NULL, 0, NULL);
|
||||
threadHandle[3] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)rev_deal_task, NULL, 0, NULL);
|
||||
threadHandle[4] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)test_task, NULL, 0, NULL);
|
||||
|
||||
WaitForSingleObject(threadHandle[0], INFINITE);
|
||||
WaitForSingleObject(threadHandle[1], INFINITE);
|
||||
WaitForSingleObject(threadHandle[2], INFINITE);
|
||||
WaitForSingleObject(threadHandle[3], INFINITE);
|
||||
CloseHandle(threadHandle[0]);
|
||||
CloseHandle(threadHandle[1]);
|
||||
CloseHandle(threadHandle[2]);
|
||||
CloseHandle(threadHandle[3]);
|
||||
return 0;
|
||||
}
|
BIN
port_self.exe
BIN
port_self.exe
Binary file not shown.
|
@ -1,3 +0,0 @@
|
|||
#include "spi_port.h"
|
||||
|
||||
|
|
@ -1 +0,0 @@
|
|||
#include "config.h"
|
|
@ -1,2 +0,0 @@
|
|||
#include "erpc_core.h"
|
||||
|
45
架构.drawio
45
架构.drawio
|
@ -1,45 +0,0 @@
|
|||
<mxfile host="Electron" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/24.7.17 Chrome/128.0.6613.36 Electron/32.0.1 Safari/537.36" version="24.7.17">
|
||||
<diagram name="第 1 页" id="iJ2ThG75liGc15h7RsxG">
|
||||
<mxGraphModel dx="1050" dy="629" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="EQYeASZG-p6UUSDICV0d-25" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="EQYeASZG-p6UUSDICV0d-19" target="EQYeASZG-p6UUSDICV0d-23">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="EQYeASZG-p6UUSDICV0d-19" value="port1" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="151" y="392" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="EQYeASZG-p6UUSDICV0d-26" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="EQYeASZG-p6UUSDICV0d-20" target="EQYeASZG-p6UUSDICV0d-23">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="410" y="550" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="EQYeASZG-p6UUSDICV0d-20" value="port2" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="151" y="490" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="EQYeASZG-p6UUSDICV0d-27" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="EQYeASZG-p6UUSDICV0d-21" target="EQYeASZG-p6UUSDICV0d-23">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="EQYeASZG-p6UUSDICV0d-21" value="..." style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="151" y="583" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="EQYeASZG-p6UUSDICV0d-28" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="EQYeASZG-p6UUSDICV0d-22" target="EQYeASZG-p6UUSDICV0d-23">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="EQYeASZG-p6UUSDICV0d-22" value="portn" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="151" y="680" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="EQYeASZG-p6UUSDICV0d-29" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="EQYeASZG-p6UUSDICV0d-23" target="EQYeASZG-p6UUSDICV0d-24">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="EQYeASZG-p6UUSDICV0d-23" value="cmd组" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="414" y="530" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="EQYeASZG-p6UUSDICV0d-24" value="相同的处理函数" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxGeometry x="630" y="530" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
Loading…
Reference in New Issue