【开源】libserial_protocol:适用于单片机的串口通信协议基础库

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

特点如下:

  • 不涉及到具体硬件,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;
}

三、代码运行结果

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: libserial_port.so是一个用于串口通信的开源,可以在编写串口通信程序时使用。以下是使用libserial_port.so的步骤: 1. 首先,你需要将libserial_port.so文件添加到你的编译环境中。可以通过在编译时链接该来实现,也可以将文件放在系统目录下,使得编译器可以找到它。 2. 在程序中包含serialport.h头文件,该头文件包含了使用串口通信的函数和结构体定义。 3. 创建一个serialport_t类型的变量,用于表示一个串口设备。可以使用serialport_open函数打开一个串口设备,函数原型如下: ```c serialport_t serialport_open(const char* portname, int baudrate); ``` 这个函数接受一个字符串参数portname,表示需要打开的串口设备名称,例如"/dev/ttyS0"表示第一个串口;还接受一个整型参数baudrate,表示波特率。 4. 可以使用serialport_read函数读取串口接收缓冲区中的数据,函数原型如下: ```c int serialport_read(serialport_t port, void* buf, int buflen); ``` 这个函数接受一个串口设备变量port,一个缓冲区buf用于接收数据,以及一个整型参数buflen,表示接收缓冲区的长度。函数会返回实际读取到的数据长度。 5. 使用serialport_write函数往串口发送数据,函数原型如下: ```c int serialport_write(serialport_t port, const void* buf, int buflen); ``` 这个函数接受一个串口设备变量port,一个缓冲区buf用于发送数据,以及一个整型参数buflen,表示发送数据的长度。函数会返回实际发送的数据长度。 6. 当完成串口通信后,可以使用serialport_close函数关闭串口设备,函数原型如下: ```c void serialport_close(serialport_t port); ``` 这个函数接受一个串口设备变量port,用于关闭已打开的串口设备。 以上就是libserial_port.so的基本使用方法。可以根据自己的需求,使用这些函数来完成串口通信操作。当然,在实际应用中,还需要处理各种错误情况和异常情况,对函数返回值进行判断和错误处理,以确保程序的稳定运行。 ### 回答2: libserial_port.so是一个用于串口通信的动态链接。它提供了一组函数,可以方便地操作串口设备。 使用libserial_port.so,首先需要在程序中加载动态链接。可以使用dlopen函数来加载libserial_port.so文件,然后使用dlsym函数获取动态中的函数。 加载后,可以通过调用相关函数来打开串口设备,设置串口的参数(如波特率、数据位、停止位等),读写数据等。 例如,可以通过调用serial_port_open函数来打开一个串口设备,并指定设备文件路径。然后可以使用serial_port_set_baud_rate函数设置波特率,使用serial_port_set_data_bits函数设置数据位数,使用serial_port_set_stop_bits函数设置停止位数等等。 在设置好串口参数后,可以通过serial_port_read函数从串口读取数据,然后使用serial_port_write函数向串口写入数据。 当不再需要使用串口时,可以通过serial_port_close函数关闭串口设备。 需要注意的是,使用libserial_port.so时需要提前安装该,以及动态链接的依赖。在编写程序时,需要包含libserial_port.h头文件,并链接相应的文件。 总之,libserial_port.so是一个方便易用的,可以帮助开发者快速开发串口通信功能的应用程序。 ### 回答3: libserial_port.so是一个串口通信,主要用于在Linux操作系统上进行串口通信。 使用libserial_port.so,我们需要先安装该并将其链接到我们的程序中。这可以通过使用软件包管理器来完成,例如在Ubuntu上使用apt-get命令。 一旦安装完毕,我们可以在代码中包含libserial_port.h头文件,并使用提供的函数进行串口通信。 提供了一些函数,如sp_get_port_list(),用于获取系统中可用的串口列表。该函数返回一个指向结构体数组的指针,其中包含串口的设备路径、描述和制造商信息。 另一个重要的函数是sp_new(),用于打开一个串口设备。通过指定串口设备的路径、波特率、数据位、校验位、停止位等参数,我们可以成功打开一个串口。该函数将返回一个指向串口设备的指针。 一旦打开了一个串口设备,我们可以使用sp_blocking_write()函数向串口发送数据,并使用sp_blocking_read()函数从串口接收数据。这两个函数都是阻塞式的,意味着在发送或接收完数据之前,程序将一直等待。 使用完毕后,我们需要使用sp_free_port()函数关闭串口并释放资源。 总而言之,libserial_port.so是一个功能强大的,可以帮助我们在Linux操作系统上进行串口通信。它提供了一组简单易用的函数,让我们可以方便地控制和访问串口设备。使用这个,我们可以轻松地与外部设备进行通信,并实现各种应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值