protocol.h代码:
root@iZwz99zhkxxl5h6ecbm2xwZ:~/serial-ipc# cat protocol.h 
#ifndef __PROTOCOL_H__
#define __PROTOCOL_H__
#include <stdint.h>
#include <stdbool.h>
enum PACKAGE_TYPE {
	TYPE_HEART_BEAT = 0x01,
	TYPE_SOMKE = 0x02,
};
typedef struct __package {
	uint8_t type;                // 命令类型
	uint8_t waterNum;            // 流水号,递增,避免命令重传时重复执行
	uint8_t checksum;            // crc
	uint8_t len;                 // 内容长度
	//void * content;
	uint8_t content[256];        256byte足够串口使用,如果高波特率,请用上面的*content和malloc/free
} uart_pack;
extern bool marshal(uint8_t * buf, uint8_t len, uart_pack * packObj);
extern bool unmarshal(uint8_t * buf, uint8_t len, uart_pack * packObj);
extern void packageSchedule(uart_pack * packObj);
#endif
root@iZwz99zhkxxl5h6ecbm2xwZ:~/serial-ipc#protocol.c 代码,实现二进制流序列化、反序列化。
root@iZwz99zhkxxl5h6ecbm2xwZ:~/serial-ipc# cat protocol.c 
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "protocol.h"
bool marshal(uint8_t * buf, uint8_t len, uart_pack * packObj)
{
	/*if (len < sizeof(uart_pack) + packObj->len) {
		printf("package head fail\r\n");
		return false;
	}*/
	buf[0] = packObj->type;
	buf[1] = packObj->waterNum;
	buf[2] = packObj->checksum;
	buf[3] = packObj->len;
	if (packObj->len) {
		memcpy(&buf[4], packObj->content, packObj->len);
	}
	return true;
}
bool unmarshal(uint8_t * buf, uint8_t len, uart_pack * packObj)
{
	/*if (len < sizeof(uart_pack) + packObj->len) {
		return false;
	}*/
	packObj->type = buf[0];
	packObj->waterNum = buf[1];
	packObj->checksum = buf[2];
	packObj->len = buf[3];
	if (packObj->len) {
		memcpy(packObj->content, &buf[4], packObj->len);
	}
	return true;
}
void packageSchedule(uart_pack * packObj)
{
	switch (packObj->type) {
		case TYPE_HEART_BEAT:
			printf("received one heart beat package\r\n");
			break;
	
		case TYPE_SOMKE:
			printf("received one smoke package\r\n");
			break;
		default:
			break;
	}
}
root@iZwz99zhkxxl5h6ecbm2xwZ:~/serial-ipc#main.c代码:
root@iZwz99zhkxxl5h6ecbm2xwZ:~/serial-ipc# cat main.c 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <string.h>
#include <signal.h>
#include <sys/select.h>
#include "protocol.h"
#define SERIAL_PORT "/dev/ttyUSB0"  // 替换为您的串口设备
//#define SERIAL_PORT "/dev/ttyCH341USB0"  // 替换为您的串口设备
#define BUFFER_SIZE 256
volatile sig_atomic_t stop = 0;
void sigint_handler(int signum) {
	stop = 1;
}
int main() {
	int serial_fd;
	struct termios serial_options;
	fd_set rfds;
	struct timeval tv;
	int retval;
	char buffer[BUFFER_SIZE];
	int n;
	// 打开串口
	serial_fd = open(SERIAL_PORT, O_RDWR | O_NOCTTY | O_NDELAY);
	if (serial_fd == -1) {
		perror("Failed to open serial port");
		return -1;
	}
	// 配置串口选项
	tcgetattr(serial_fd, &serial_options);		// 读取串口默认配置
	
	cfsetispeed(&serial_options, B115200);		// set io speed
	cfsetospeed(&serial_options, B115200);
	//
	serial_options.c_cflag |= (CLOCAL | CREAD);
	serial_options.c_cflag &= ~CSIZE;
	serial_options.c_cflag |= CS8;
	serial_options.c_cflag &= ~PARENB;
	serial_options.c_cflag &= ~CSTOPB;
	// 设置最少字符和等待时间
	serial_options.c_cc[VMIN] = 1;     // 读数据的最小字节数
	serial_options.c_cc[VTIME]  = 0;   //等待第1个数据,单位是10s
	serial_options.c_cflag &= ~CRTSCTS;
	serial_options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
	serial_options.c_iflag &= ~(IXON | IXOFF | IXANY);
	serial_options.c_oflag &= ~OPOST;
	tcsetattr(serial_fd, TCSANOW, &serial_options);
	signal(SIGINT, sigint_handler);
	while (!stop) {
		FD_ZERO(&rfds);
		FD_SET(serial_fd, &rfds);
		tv.tv_sec = 5;
		tv.tv_usec = 0;
		// 使用 select 等待串口可读
		retval = select(serial_fd + 1, &rfds, NULL, NULL, &tv);
		if (retval == -1) {
			perror("Select error");
			break;
		}
		else if (retval) {	
			printf("Data is available now.\n");
			/* FD_ISSET(0, &rfds) will be true. */
			if (FD_ISSET(serial_fd, &rfds)) {
				n = read(serial_fd, buffer, BUFFER_SIZE);
				if (n > 0) {
					buffer[n] = '\0';
					printf("Received: %s\n", buffer);
					write(serial_fd, "ack:", 3);
					write(serial_fd, buffer, n);
					uart_pack packObj;
					bool ret = unmarshal(buffer, n, &packObj);
					if (ret) {
						packageSchedule(&packObj);
					}
				}
			}
		}
		else {
			printf("No data within five seconds.\n");		
		}
	}
	// 关闭串口
	close(serial_fd);
	return 0;
}
root@iZwz99zhkxxl5h6ecbm2xwZ:~/serial-ipc#Makefile
root@iZwz99zhkxxl5h6ecbm2xwZ:~/serial-ipc# cat Makefile 
.PHONY:all
all:
	gcc -g main.c protocol.c -o uart-ipc
clean:
	rm -rf uart-ipc
root@iZwz99zhkxxl5h6ecbm2xwZ:~/serial-ipc#                









