借助五一假期,写了一个串口通信协议基础库,虽然写着适用于单片机,但实际上并不限制具体的硬件平台。

特点如下:

  • 不涉及到具体硬件,libserial_protocol 纯软件协议,与具体硬件分离。
  • 内存空间占用可控,libserial_protocol 支持动静态内存,内存空间可控。
  • 接口简单容易复用,libserial_protocol 采用面向对象方式实现,提供大小数据量解码方式。 

源码仓库:

gitee: libserial_protocol: 适用于单片机的串口通信协议基础库

github: https://github.com/lovemengx/libserial_protocol

一、接口定义

// 缓存数据结构(编解码不能同时使用同一块缓存)
typedef struct{
	unsigned char *buf;			// 缓存位置, 由用户指向一块可用的内存空间
	unsigned int total;			// 缓存大小, 标明该内存空间的总长度
}libserial_protocol_buf_t;

/*---------------------------------------------------------------------
*	函数:	libserial_protocol_create
*	功能:	使用接口内部申请指定可用大小的空间
*	参数:	size: 申请可用缓冲区大小 
*	返回:	NULL: 申请内存空间失败		>0: 申请成功
*	备注:	接口内部会多申请内部数据结构所需的空间大小
*---------------------------------------------------------------------*/
libserial_protocol_buf_t *libserial_protocol_create(unsigned int size);

/*---------------------------------------------------------------------
*	函数: 	libserial_protocol_release
*	功能:	释放接口内部申请的内存空间
*	参数:	splbuf: 由 libserial_protocol_create() 创建的内存空间
*	返回:	0: 不满足最小长度要求  >0: 可供用户使用的大小 
*---------------------------------------------------------------------*/
void libserial_protocol_release(libserial_protocol_buf_t *splbuf);

/*---------------------------------------------------------------------
*	函数: 	libserial_protocol_internal_size
*	功能:	返回内部数据结构占用字节数
*	参数:	
*	返回:	返回内部数据结构占用字节数 
*---------------------------------------------------------------------*/
unsigned int libserial_protocol_internal_size();

/*---------------------------------------------------------------------
*	函数: 	libserial_protocol_init
*	功能:	使用用户提供的或创建接口的缓冲区, 初始化内部数据结构
*	参数:	splbuf: 缓冲区  size: 缓冲区大小 
*	返回:	0: 不满足最小长度要求  >0: 可供用户使用的大小 
*---------------------------------------------------------------------*/
unsigned int libserial_protocol_init(libserial_protocol_buf_t *splbuf);

/*---------------------------------------------------------------------
*	函数: 	libserial_protocol_reset
*	功能:	重置解码器
*	参数:	splbuf: 缓冲区
*	返回:	无返回值
*---------------------------------------------------------------------*/
void libserial_protocol_decode_reset(libserial_protocol_buf_t *splbuf);

/*---------------------------------------------------------------------
*	函数: 	libserial_protocol_decode
*	功能:	解码数据
*	参数:	splbuf: 缓冲区  indata: 输入数据  dalen: 解成功的数据长度
*	返回:	0: 正在解码  1:解码成功  -1: 校验失败	
*---------------------------------------------------------------------*/
int libserial_protocol_decode(libserial_protocol_buf_t *splbuf, unsigned char indata, unsigned int *dalen);

/*---------------------------------------------------------------------
*	函数: 	libserial_protocol_decode_find
*	功能:	寻找数据区域(适合较大数据量)
*	参数:	splbuf: 缓冲区  indata: 输入数据
*	返回:	0: 正在寻找  >0: 数据区域长度
*---------------------------------------------------------------------*/
unsigned int libserial_protocol_decode_find(libserial_protocol_buf_t *splbuf, unsigned char indata);

/*---------------------------------------------------------------------
*	函数: 	libserial_protocol_decode_copy
*	功能:	拷贝数据区域(适合较大数据量)
*	参数:	splbuf: 缓冲区  indata: 输入数据  dalen: 输入的数据长度
*	返回:	0: 完成拷贝  -1: 校验失败  -2: 数据长度或解码状态错误
*---------------------------------------------------------------------*/
int libserial_protocol_decode_copy(libserial_protocol_buf_t *splbuf, unsigned char *indata, unsigned int len);

/*---------------------------------------------------------------------
*	函数: 	libserial_protocol_encode
*	功能:	数据编码
*	参数:	splbuf: 缓冲区  indata: 输入数据  dalen: 输入的数据长度
*	返回:	0: 数据长度不合法  >0: 编码后的数据长度
*---------------------------------------------------------------------*/
unsigned int libserial_protocol_encode(libserial_protocol_buf_t *splbuf, const void *indata, unsigned int dalen);

二、示例代码

#include <stdio.h>
#include "libserial_protocol.h"

#define iprintf(format,...) 	printf("[inf]%s():%05d " format , __func__, __LINE__,##__VA_ARGS__)


/*---------------------------------------------------------------------
*	函数: 	static_libserial_protocol
*	功能:	演示采用静态内存方式进行两种方法解码
*---------------------------------------------------------------------*/
void static_libserial_protocol(const char *data, unsigned int length)
{
	int result = 0;
	unsigned int i = 0;
	unsigned char buf1[512], buf2[512];
	libserial_protocol_buf_t splbuf1, splbuf2;

	// 使用静态内存
	splbuf1.buf = buf1;
	splbuf2.buf = buf2;
	splbuf1.total = sizeof(buf1);
	splbuf2.total = sizeof(buf2);

	// 初始化内部数据结构
	unsigned int avail1 = libserial_protocol_init(&splbuf1);
	unsigned int avail2 = libserial_protocol_init(&splbuf2);
	iprintf("avail1:%d  avail2:%d\n", avail1, avail2);

	// 对数据进行编码
	unsigned int enbyte = libserial_protocol_encode(&splbuf1, data, length);
	iprintf("enbyte:%d  datalen:%d\n", enbyte, length);

	// 使用最简单的方式解码, 适合小数据量
	unsigned int debyte = 0x00;
	for (i = 0; i < enbyte; i++) {
		if ((result = libserial_protocol_decode(&splbuf2, splbuf1.buf[i], &debyte)) == 1) {
			iprintf("simple mode: decode success debyte:%d data:[%s]\n", debyte, splbuf2.buf);
			break;
		}
	}

	// 使用较高性能方式解码, 适合大数据量
	for (i = 0; i < enbyte; i++){
		if ((debyte = libserial_protocol_decode_find(&splbuf2, splbuf1.buf[i])) > 0) {
			if (libserial_protocol_decode_copy(&splbuf2, splbuf1.buf + i + 1, debyte) == 0) {
				iprintf("comple mode: decode success debyte:%d data:[%s]\n", debyte, splbuf2.buf);
			}
			break;
		}
	}

	iprintf("static run done...\n\n");
	return;
}

/*---------------------------------------------------------------------
*	函数: 	static_libserial_protocol
*	功能:	演示采用动态内存方式进行两种方法解码
*---------------------------------------------------------------------*/
void dynamic_libserial_protocol(const char* data, unsigned int length)
{
	int result = 0;
	unsigned int i = 0;
	libserial_protocol_buf_t* splbuf1, * splbuf2;

	// 使用动态内存
	splbuf1 = libserial_protocol_create(512);
	splbuf2 = libserial_protocol_create(512);
	if (!splbuf1 || !splbuf2) {
		iprintf("create dynamic failed.\n");
		libserial_protocol_release(splbuf1);
		libserial_protocol_release(splbuf2);
		return ;
	}

	// 初始化内部数据结构
	unsigned int avail1 = libserial_protocol_init(splbuf1);
	unsigned int avail2 = libserial_protocol_init(splbuf2);
	iprintf("avail1:%d  avail2:%d\n", avail1, avail2);

	// 对数据进行编码
	unsigned int enbyte = libserial_protocol_encode(splbuf1, data, length);
	iprintf("enbyte:%d  datalen:%d\n", enbyte, length);

	// 使用最简单的方式解码, 适合小数据量
	unsigned int debyte = 0x00;
	for (i = 0; i < enbyte; i++) {
		if ((result = libserial_protocol_decode(splbuf2, splbuf1->buf[i], &debyte)) == 1) {
			iprintf("simple mode: decode success debyte:%d data:[%s]\n", debyte, splbuf2->buf);
			break;
		}
	}

	// 使用较高性能方式解码, 适合大数据量
	for (i = 0; i < enbyte; i++) {
		if ((debyte = libserial_protocol_decode_find(splbuf2, splbuf1->buf[i])) > 0) {
			if (libserial_protocol_decode_copy(splbuf2, splbuf1->buf + i + 1, debyte) == 0) {
				iprintf("comple mode: decode success debyte:%d data:[%s]\n", debyte, splbuf2->buf);
			}
			break;
		}
	}

	// 释放内存空间
	libserial_protocol_release(splbuf1);
	libserial_protocol_release(splbuf2);

	iprintf("dynamic run done...\n\n");
	return;
}

int main(int argc, char* argv[])
{
	char data[256] = { 0 };

	// 填充数据, 最后一字节存储 '\0'
	for (unsigned int i = 0, j = 0; i < sizeof(data) - 1; i++) {
		data[i] = '0' + j;
		j = '9' == data[i] ? 0 : j + 1;
	}

	static_libserial_protocol(data, sizeof(data));
	dynamic_libserial_protocol(data, sizeof(data));
	
	return 0;
}

三、代码运行结果