0
点赞
收藏
分享

微信扫一扫

linux c串口应用编程,参照golang里面的json.Marshal/json.Unmarshal


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#


举报

相关推荐

0 条评论