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#