|
开源一个串行通讯私有协议框架,请求-应答模式,超时检测,CRC,消息回调机制。
https://gitee.com/davidxu1993/serial-private-protocol
https://github.com/DavidXuZZF/serial-private-protocol
[C] 纯文本查看 复制代码 /**
* @file pp_custom_config.h
* @author David Xu ([email]davidxuzzf@gmail.com[/email])
* @brief User define this file to custom pp. The macro define
* in this file can instead the item in pp_config.h .
* @version 1.0.0
*
* MIT License
*
* Copyright (c) 2024 DAVID XU
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef example_pp_custom_config_h
#define example_pp_custom_config_h
#ifdef __cplusplus
extern "C" {
#endif
/* 本配置文件以rt-thread为例 */
// #include <rtthread.h>
/* 串行接收缓存长度 */
#define PP_RINGBUFFER_LEN (4 * 1024)
/* 用于临时保存一帧数据的缓存,至少比最大报文长度多20字节 */
#define PP_FRAMEBUFFER_LEN (1024 + 20)
/* 应答超时检测功能的使能。且每条发送报文都会申请一个超时检测的动态内存。 */
/* !!!该功能需要动态内存分配功能使能。 */
#define PP_TIMEOUT_DET_EN (1)
/* 允许的最大payload长度,仅用于接收报文合法性的检查。 */
#define PP_PAYLOAD_MAX_LEN (1024)
/* 标准输出接口 */
#define PP_PRINTF rt_kprintf
/* 调试日志输出使能 */
#define PP_LOG_DEBUG_EN (1)
/* 错误日志输出使能 */
#define PP_LOG_ERROR_EN (1)
/* 动态内存分配功能使能 */
/* !!!若不使能,协议句柄使用的是全局变量,因此不能让同一个协议实例化多个实例。除非自己改pp_template_handle_new函数 */
/* !!!由于应答超时检查功能需要动态内存,因此若不使能,超时检查功能将失效。 */
#define PP_DYNAMIC_MEMORY_EN (1)
/* 动态内存分配函数 */
#define PP_MALLOC rt_malloc
/* 动态内存释放函数 */
#define PP_FREE rt_free
/* 超时断帧时间,写0则不使能超时断帧功能 */
#define FRAME_TIMEOUT (2000)
/* 轮询延时,用于释放cpu资源 */
#define POLL_DELAY (rt_thread_mdelay(1))
#ifdef __cplusplus
}
#endif
#endif /* example_pp_custom_config_h */
[C] 纯文本查看 复制代码 /**
* @file main.c
* @author David Xu ([email]davidxuzzf@gmail.com[/email])
* @brief example.
* @version 1.0.0
*
* MIT License
*
* Copyright (c) 2024 DAVID XU
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <rtthread.h>
#include "inc/pp_template.h"
#define LOG_D(fmt, ...) rt_kprintf(fmt "\n", ##__VA_ARGS__)
/* 协议句柄 */
struct pp_template_handle *h_template = NULL;
/**
* @brief 串口发送回调函数,即用户调用硬件发送数据。
*
* @param data 发送数据
* @param len 发送数据长度
* @return int 发送的字节数。等于len时,表示发送成功。等于其他值时,表示发送失败。
*/
static int my_hw_send_cb(const uint8_t *data, uint16_t len);
/**
* @brief 事件回调函数,用于处理协议事件。包括接收的应答报文事件和应答超时事件。
*
* @param h 协议句柄
* @param evt 事件码
* @param param 事件参数
*/
static void my_notify_cb(struct pp_handle *h, uint8_t evt, const void *param);
/**
* @brief 获取时间戳。
*
* @return uint32_t 时间戳
*/
uint32_t pp_get_time_tick(void)
{
return rt_tick_get();
}
int main(void)
{
h_template = pp_template_handle_new();
if (!h_template)
{
printf("create template handle fail.");
exit(-1);
}
pp_template_handle_init(h_template, my_hw_send_cb, my_notify_cb);
while (1)
{
pp_poll((struct pp_handle *)h_template);
}
pp_template_handle_delete(h_template);
exit(0);
}
static void my_notify_cb(struct pp_handle *h, uint8_t evt, const void *param)
{
switch (evt)
{
/* 从机收到的事件 */
case EVT_SET_SPEED:
{
const param_of_notify_set_speed_t *evt_param = param;
/* 从机收到主机设置转速的命令,此处执行主机的操作,然后应答主机 */
// 伪代码 ret = set_speed(evt_param->speed);
/* 应答主机 */
param_of_notify_resp_of_set_speed_t resp_param;
resp_param.result.index = evt_param->frame_index;
resp_param.result.result = ret; /* 设置转速的执行情况 注意 类型为pp_err_t */
resp_param.speed = evt_param->speed;
pp_template_resp_of_set_speed(h, &resp_param);
}
break;
case EVT_REQ_TEMPERATURE:
{
const param_of_notify_req_temperature_t *evt_param = param;
/* 类似同上 */
}
break;
case EVT_SET_TEMPERATURE:
{
const param_of_notify_set_temperature_t *evt_param = param;
/* 类似同上 */
}
break;
/* 主机收到的事件 */
case EVT_RESP_OF_SET_SPEED:
{
const param_of_notify_resp_of_set_speed_t *evt_param = param;
if (evt_param->result.result == PP_EOK)
{
/* 收到从机的应答,且没有出错 */
LOG_D("Set speed success. index:%d, speed:%.2f", evt_param->frame_index, evt_param->speed);
}
else if (evt_param->result.result == PP_ETIMEOUT)
{
/* 说明主机没有收到从机应答SET_SPEED报文,此处可以选择重发或者记录丢包率。 */
LOG_D("Set speed timeout. index:%d, speed:%.2f", evt_param->frame_index, evt_param->speed);
}
else
{
/* 其他情况,用户自定义处理机制。 */
}
}
break;
case EVT_RESP_OF_REQ_TEMPERATURE:
{
const param_of_notify_resp_of_req_temperature_t *evt_param = param;
/* 用户自定义处理机制 */
}
break;
case EVT_RESP_OF_SET_TEMPERATURE:
{
const param_of_notify_resp_of_set_temperature_t *evt_param = param;
/* 用户自定义处理机制 */
}
break;
default:
LOG_D("unkown event.\n");
break;
}
}
/************************************************************************************
* P O R T
*
***********************************************************************************/
/* This func must be call, when you recieve data. */
void hw_recv_data(uint8_t *data, uint16_t len)
{
/* 串口收到的数据,通过这个函数保存到接收buffer中 */
pp_save_hw_recv_data((struct pp_handle *)h_template, data, len);
}
static int my_hw_send_cb(const uint8_t *data, uint16_t len)
{
/* Use USB,UART,TCP etc. to send data */
// 伪代码 rt_hw_uart_send(data, len);
return len; /* !!!若发送成功必须返回len,若发送失败不得返回len */
}
发现bug欢迎指正,共同进步。
|
|