前言
https://github.com/Tuotaba/air_protocol
air_protocol提供一套应用于嵌入式设备的通讯协议。协议涉及协议完整性的验证,长短数据的灵活调整,以及数据过滤等。适合设备的数据传输、文件传输等。
例1 收发数据
#include "air_protocol.h"
#include "fifo_buffer.h"
#include <stdio.h>
#include <stdlib.h>
#define MAX_BUFFER_LEN 256
static uint8_t pUartData[MAX_BUFFER_LEN];
static buffer_list_t UartBuf;
static uint8_t air_buffer[MAX_BUFFER_LEN];
void send_uart(uint8_t cmd,uint8_t *buf,uint16_t len)
{
air_result_t result;
air_ret_t ret;
ret = air_alloc_pack(cmd,buf,len,&result);
if(ret == AIR_FAIL)
return;
printf("send:\n");
air_show_log(result.pdata,result.len);
printf("\n");
buffer_append(&UartBuf,result.pdata,result.len);
free(result.pdata);
}
void uart_data_parser(void)
{
air_result_t result;
air_ret_t ret;
air_header_t air_header;
uint8_t *pdata;
int i,len;
air_header.tag = AIR_TAG;
i = buffer_find(&UartBuf,(uint8_t *)&air_header.tag,sizeof(air_header.tag));
if(i >= 0)
{
if(i>0)
buffer_pop(&UartBuf,NULL,i);
if(get_data_length(&UartBuf) > AIR_HEADER_LEN)
{
pdata = (uint8_t *)&air_header;
for(i=0;i<AIR_HEADER_LEN;i++)
pdata[i] = buffer_get(&UartBuf,i);
len = (AIR_HEADER_LEN+air_header.len+1);
if(get_data_length(&UartBuf) >= len)
{
buffer_pop(&UartBuf,air_buffer,len);
ret = air_data_parser(air_buffer,len,&result);
if(ret == AIR_SUCCESS)
{
printf("recv:cmd = %02X,len =%d\n",result.cmd,result.len);
air_show_log(result.pdata,result.len);
printf("\n");
}
}
}
}
}
int main()
{
int i,len;
uint8_t data[] = {0xAA ,0xAA ,0xAA ,0xAA ,0xAA ,0xAA ,0xAA ,0xAA ,0xAA ,0xAA ,0xAA ,0xAA ,0xAA ,0xAA ,0xAA};
buffer_init(&UartBuf,pUartData,MAX_BUFFER_LEN);
send_uart(0x0A,data,sizeof(data));
uart_data_parser();
return 0;
}
一般数据的收发,数据完整性验证,结果:
send:
8D 7C 6B 5A 0A 00 0F 00 AA AA AA AA AA AA AA AA
AA AA AA AA AA AA AA DD
recv:cmd = 0A,len =15
AA AA AA AA AA AA AA AA AA AA AA AA AA AA AA
例2 运动数据解析
#include "air_protocol.h"
#include "fifo_buffer.h"
#include <stdio.h>
#include <stdlib.h>
#define MAX_BUFFER_LEN 256
static uint8_t pUartData[MAX_BUFFER_LEN];
static buffer_list_t UartBuf;
static uint8_t air_buffer[MAX_BUFFER_LEN];
typedef struct
{
uint32_t calories;
uint32_t speed;
uint32_t distance;
uint32_t time;
}_sport_data_t;
#define CMD_SPORT_DATA 0x10
void send_uart(uint8_t cmd,uint8_t *buf,uint16_t len)
{
air_result_t result;
air_ret_t ret;
ret = air_alloc_pack(cmd,buf,len,&result);
if(ret == AIR_FAIL)
return;
buffer_append(&UartBuf,result.pdata,result.len);
free(result.pdata);
}
static void command_handler(uint8_t cmd,uint8_t *buf,uint16_t len)
{
_sport_data_t *p_sport_data;
switch(cmd)
{
case CMD_SPORT_DATA:
p_sport_data = (_sport_data_t *)buf;
printf("calories : %d\n",p_sport_data->calories);
printf("speed : %d\n",p_sport_data->speed);
printf("distance : %d\n",p_sport_data->distance);
printf("time : %d\n",p_sport_data->time);
break;
default:break;
}
}
void uart_data_parser(void)
{
air_result_t result;
air_ret_t ret;
air_header_t air_header;
uint8_t *pdata;
int i,len;
air_header.tag = AIR_TAG;
i = buffer_find(&UartBuf,(uint8_t *)&air_header.tag,sizeof(air_header.tag));
if(i >= 0)
{
if(i>0)
buffer_pop(&UartBuf,NULL,i);
if(get_data_length(&UartBuf) > AIR_HEADER_LEN)
{
pdata = (uint8_t *)&air_header;
for(i=0;i<AIR_HEADER_LEN;i++)
pdata[i] = buffer_get(&UartBuf,i);
len = (AIR_HEADER_LEN+air_header.len+1);
if(get_data_length(&UartBuf) >= len)
{
buffer_pop(&UartBuf,air_buffer,len);
ret = air_data_parser(air_buffer,len,&result);
if(ret == AIR_SUCCESS)
{
command_handler(result.cmd,result.pdata,result.len);
}
}
}
}
}
int main()
{
int i,len;
_sport_data_t data = {322,23,1000,30};
buffer_init(&UartBuf,pUartData,MAX_BUFFER_LEN);
send_uart(CMD_SPORT_DATA,(uint8_t*)&data,sizeof(_sport_data_t));
uart_data_parser();
return 0;
}
收到对方发来的CMD_SPORT_DATA命令,附带_sport_data_t数据包,进行解析,解析出结果:
calories : 322
speed : 23
distance : 1000
time : 30
例3 文件传输
#include "air_protocol.h"
#include "fifo_buffer.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define MAX_BUFFER_LEN 512
static uint8_t pUartData[MAX_BUFFER_LEN];
static buffer_list_t UartBuf;
static uint8_t air_buffer[MAX_BUFFER_LEN];
typedef struct
{
uint32_t addr;
uint32_t len;
uint8_t data[256];
}_file_data_t;
#define CMD_FILE_BEGIN 0x10
#define CMD_FILE_DATA 0x11
#define CMD_FILE_END 0x12
void send_uart(uint8_t cmd,uint8_t *buf,uint16_t len)
{
air_result_t result;
air_ret_t ret;
ret = air_alloc_pack(cmd,buf,len,&result);
if(ret == AIR_FAIL)
return;
buffer_append(&UartBuf,result.pdata,result.len);
free(result.pdata);
}
static void command_handler(uint8_t cmd,uint8_t *buf,uint16_t len)
{
_file_data_t file_data;
static uint32_t require_addr = 0;
switch(cmd)
{
case CMD_FILE_BEGIN:
require_addr = 0;
break;
case CMD_FILE_DATA:
memcpy(&file_data,buf,len);
printf("%08X :\n",file_data.addr);
if(file_data.addr == require_addr){
air_show_log(file_data.data,file_data.len);
require_addr += file_data.len;
}
else{
printf("please resend addr %08X\n",require_addr);
}
break;
case CMD_FILE_END:
printf("file is done\n");
break;
default:break;
}
}
void uart_data_parser(void)
{
air_result_t result;
air_ret_t ret;
air_header_t air_header;
uint8_t *pdata;
int i,len;
air_header.tag = AIR_TAG;
do{
i = buffer_find(&UartBuf,(uint8_t *)&air_header.tag,sizeof(air_header.tag));
if(i >= 0)
{
if(i>0)
buffer_pop(&UartBuf,NULL,i);
if(get_data_length(&UartBuf) > AIR_HEADER_LEN)
{
pdata = (uint8_t *)&air_header;
for(i=0;i<AIR_HEADER_LEN;i++)
pdata[i] = buffer_get(&UartBuf,i);
len = (AIR_HEADER_LEN+air_header.len+1);
if(get_data_length(&UartBuf) >= len)
{
buffer_pop(&UartBuf,air_buffer,len);
ret = air_data_parser(air_buffer,len,&result);
if(ret == AIR_SUCCESS)
{
command_handler(result.cmd,result.pdata,result.len);
}
continue;
}
}
}
break;
}while(1);
}
int main()
{
int len;
FILE *fp = NULL;
_file_data_t file_data;
buffer_init(&UartBuf,pUartData,MAX_BUFFER_LEN);
file_data.addr = 0;
fp = fopen("./test.bin","r");
if(fp == NULL)
{
printf("not found test.bin\n");
return 0;
}
send_uart(CMD_FILE_BEGIN,NULL,0);
while(1){
len = fread(file_data.data,1,256,fp);
if(len <= 0)
break;
file_data.len = len;
send_uart(CMD_FILE_DATA,(uint8_t*)&file_data,file_data.len+8);
uart_data_parser();
file_data.addr += len;
}
send_uart(CMD_FILE_END,NULL,0);
uart_data_parser();
fclose(fp);
return 0;
}
将test.bin读出,并进行传输,结果:
00000000 :
61 61 61 61 61 61 61 61 0A
file is done
如果文件足够大,会打印出更多的信息。
因为协议有对每帧数据进行完整性验证,所以不怕数据会出错,也不需要收全文件再进行检验。