-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathyj_protocol.h
More file actions
235 lines (207 loc) · 8.31 KB
/
yj_protocol.h
File metadata and controls
235 lines (207 loc) · 8.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
#ifndef YJ_PROTOCOL_H
#define YJ_PROTOCOL_H
#include <stdint.h>
#include <stddef.h> // 用于size_t
#include "yj_protocol_config.h" // 用户配置和yj_checksum_mode_t
/**
* @file yj_protocol.h
* @brief YJ串口通信协议API接口
* @version 2.0
* @date 2024
*
* 本文件定义了协议的数据结构、状态机和API接口
*
* 协议帧格式:
* +--------+--------+--------+---------+----------+-----------+------+----------+
* | 帧头 | 源地址 | 目的地址| 功能码 | 长度低位 | 长度高位 | 数据 | 校验字段 |
* | 1字节 | 1字节 | 1字节 | 1字节 | 1字节 | 1字节 | N字节| 2字节 |
* +--------+--------+--------+---------+----------+-----------+------+----------+
*
* 校验字段(2字节):
* - 原始模式: [和校验][累加校验]
* - CRC模式: [CRC高位][CRC低位] (大端序)
*/
/* 帧结构常量定义 */
#define YJ_FRAME_OFFSET_HEAD 0 // 帧头偏移
#define YJ_FRAME_OFFSET_SADDR 1 // 源地址偏移
#define YJ_FRAME_OFFSET_DADDR 2 // 目标地址偏移
#define YJ_FRAME_OFFSET_FUNC_ID 3 // 功能ID偏移
#define YJ_FRAME_OFFSET_LEN_LOW 4 // 长度低字节偏移
#define YJ_FRAME_OFFSET_LEN_HIGH 5 // 长度高字节偏移
#define YJ_FRAME_OFFSET_DATA_START 6 // 数据起始偏移
#define YJ_FRAME_HEADER_SIZE YJ_FRAME_OFFSET_DATA_START // 帧头大小
#define YJ_FRAME_CHECKSUM_FIELD_SIZE 2 // 校验和字段大小(固定2字节)
#define YJ_FRAME_MIN_OVERHEAD (YJ_FRAME_HEADER_SIZE + YJ_FRAME_CHECKSUM_FIELD_SIZE) // 最小开销
#define YJ_MAX_FRAME_SIZE (YJ_FRAME_MIN_OVERHEAD + YJ_MAX_DATA_PAYLOAD_SIZE) // 最大帧大小
/* 协议接收状态枚举 */
typedef enum {
YJ_RX_STATE_WAIT_HEAD, // 等待帧头
YJ_RX_STATE_WAIT_SADDR, // 等待源地址
YJ_RX_STATE_WAIT_DADDR, // 等待目标地址
YJ_RX_STATE_WAIT_FUNC_ID, // 等待功能ID
YJ_RX_STATE_WAIT_LEN_LOW, // 等待长度低字节
YJ_RX_STATE_WAIT_LEN_HIGH, // 等待长度高字节
YJ_RX_STATE_WAIT_DATA, // 等待数据
YJ_RX_STATE_WAIT_CHECKSUM_BYTE1, // 等待校验和字节1
YJ_RX_STATE_WAIT_CHECKSUM_BYTE2 // 等待校验和字节2
} yj_rx_state_t;
/* 帧数据结构体 */
typedef struct {
uint8_t head; // 帧头(0xAB)
uint8_t s_addr; // 源地址
uint8_t d_addr; // 目标地址
uint8_t func_id; // 功能ID
uint16_t data_len; // 数据长度
uint8_t data[YJ_MAX_DATA_PAYLOAD_SIZE]; // 数据负载
uint8_t received_checksum_bytes[YJ_FRAME_CHECKSUM_FIELD_SIZE]; // 接收到的校验和字节
} yj_frame_t;
/* 协议处理实例结构体 */
typedef struct {
/* 接收状态机 */
yj_rx_state_t rx_state; // 当前接收状态
yj_frame_t current_rx_frame; // 当前接收帧
uint16_t rx_data_bytes_received; // 已接收数据字节数
/* 校验模式相关 */
yj_checksum_mode_t active_checksum_mode; // 当前校验模式
uint8_t rx_calc_original_sc; // 原始求和校验计算值
uint8_t rx_calc_original_ac; // 原始累加校验计算值
uint16_t rx_calc_crc16; // CRC16计算值
/* 接收环形缓冲区 */
uint8_t rx_circ_buffer[YJ_RX_BUFFER_SIZE]; // 环形缓冲区
volatile uint16_t rx_circ_buffer_head; // 缓冲区头指针
volatile uint16_t rx_circ_buffer_tail; // 缓冲区尾指针
volatile uint16_t rx_circ_buffer_count; // 缓冲区数据计数
/* 物理层和回调函数 */
yj_send_byte_func_t send_byte_func; // 字节发送函数指针
void (*frame_received_callback)(yj_frame_t* received_frame); // 帧接收回调函数
} yj_protocol_handler_t;
/* API函数声明 */
/**
* @brief 初始化协议处理器
* @param handler 协议处理器实例指针
* @param send_byte_impl 字节发送函数指针
* @param frame_received_cb 帧接收回调函数
* @param mode 校验模式(YJ_CHECKSUM_MODE_ORIGINAL或YJ_CHECKSUM_MODE_CRC16)
*/
void yj_protocol_init(yj_protocol_handler_t* handler,
yj_send_byte_func_t send_byte_impl,
void (*frame_received_cb)(yj_frame_t* received_frame),
yj_checksum_mode_t mode);
/**
* @brief 发送数据帧
* @param handler 协议处理器实例指针
* @param dest_addr 目标地址
* @param func_id 功能ID
* @param data 数据指针
* @param data_len 数据长度
* @return 0成功, 负数失败
*/
int32_t yj_protocol_send_frame(yj_protocol_handler_t* handler,
uint8_t dest_addr,
uint8_t func_id,
const uint8_t* data,
uint16_t data_len);
/**
* @brief 处理接收到的字节
* @param handler 协议处理器实例指针
* @param byte_received 接收到的字节
*/
void yj_protocol_process_byte(yj_protocol_handler_t* handler, uint8_t byte_received);
/**
* @brief 向接收环形缓冲区添加字节
* @param handler 协议处理器实例指针
* @param byte_to_add 要添加的字节
* @return 0成功, -1缓冲区已满
*/
int32_t yj_protocol_rx_buffer_add_byte(yj_protocol_handler_t* handler, uint8_t byte_to_add);
/**
* @brief 协议处理器主循环处理函数
* @param handler 协议处理器实例指针
*/
void yj_protocol_tick(yj_protocol_handler_t* handler);
/* 数据打包/解包辅助函数(小端字节序) */
void yj_pack_u16_le(uint8_t* buffer, uint16_t value);
uint16_t yj_unpack_u16_le(const uint8_t* buffer);
void yj_pack_i16_le(uint8_t* buffer, int16_t value);
int16_t yj_unpack_i16_le(const uint8_t* buffer);
void yj_pack_u32_le(uint8_t* buffer, uint32_t value);
uint32_t yj_unpack_u32_le(const uint8_t* buffer);
void yj_pack_i32_le(uint8_t* buffer, int32_t value);
int32_t yj_unpack_i32_le(const uint8_t* buffer);
void yj_pack_float_le(uint8_t* buffer, float value);
float yj_unpack_float_le(const uint8_t* buffer);
// 发送队列结构
typedef struct {
uint8_t data[YJ_MAX_DATA_PAYLOAD_SIZE];
uint16_t len;
uint32_t send_time;
uint8_t retry_count;
uint8_t dest;
uint8_t func;
} yj_pending_frame_t;
/* 应用层扩展函数 */
/**
* @brief 带重传机制的发送函数
* @param handler 协议处理器实例指针
* @param dest 目标地址
* @param func 功能ID
* @param data 数据指针
* @param len 数据长度
* @return 0成功, 负数失败
*/
int32_t yj_send_with_retry(yj_protocol_handler_t* handler,
uint8_t dest, uint8_t func,
const uint8_t* data, uint16_t len);
/**
* @brief 超时检测函数(需在主循环中调用)
* @param handler 协议处理器实例指针
*/
void yj_check_timeouts(yj_protocol_handler_t* handler);
/**
* @brief 带序号的发送函数
* @param handler 协议处理器实例指针
* @param dest 目标地址
* @param func 功能ID
* @param data 数据指针
* @param len 数据长度
*/
void yj_send_with_seq(yj_protocol_handler_t* handler,
uint8_t dest, uint8_t func,
const uint8_t* data, uint16_t len);
/* 高级扩展功能 */
#define YJ_FUNC_ACK 0xF0 // ACK功能码
#define YJ_FUNC_NACK 0xF1 // NACK功能码
/**
* @brief 启用/禁用帧确认机制
* @param handler 协议处理器实例指针
* @param enable 1启用, 0禁用
*/
void yj_enable_ack(yj_protocol_handler_t* handler, uint8_t enable);
/**
* @brief 设置滑动窗口大小
* @param handler 协议处理器实例指针
* @param window_size 窗口大小(1-255)
*/
void yj_set_window_size(yj_protocol_handler_t* handler, uint8_t window_size);
/**
* @brief 大数据分包发送
* @param handler 协议处理器实例指针
* @param dest 目标地址
* @param func 功能ID
* @param data 数据指针
* @param total_len 数据总长度
*/
void yj_send_large_data(yj_protocol_handler_t* handler,
uint8_t dest, uint8_t func,
const uint8_t* data, uint32_t total_len);
/**
* @brief 获取协议统计信息
* @param handler 协议处理器实例指针
* @param tx_count 输出:发送帧计数
* @param rx_count 输出:接收帧计数
* @param error_count 输出:错误计数
*/
void yj_get_stats(yj_protocol_handler_t* handler,
uint32_t* tx_count, uint32_t* rx_count,
uint32_t* error_count);
#endif // YJ_PROTOCOL_H