200 lines
4.5 KiB
C
200 lines
4.5 KiB
C
#include "uart.h"
|
|
|
|
|
|
int fd = -1;
|
|
uart_cfg_t uart_cfg = {
|
|
.baudrate = 115200,
|
|
.dbit = 8,
|
|
.parity = 'N',
|
|
.sbit = 0,
|
|
};
|
|
|
|
|
|
static void io_handler(int sig, siginfo_t *info, void *context)
|
|
{
|
|
unsigned char buf[50] = {0};
|
|
int ret;
|
|
int n;
|
|
|
|
if(SIGRTMIN != sig)
|
|
return;
|
|
|
|
/* 判断串口是否有数据可读 */
|
|
if (POLL_IN == info->si_code) {
|
|
ret = read(fd, buf, 50); //一次最多读 50 个字节数据
|
|
printf("[ ");
|
|
|
|
for (n = 0; n < ret; n++)
|
|
printf("%hhx ", buf[n]);
|
|
|
|
printf("]\n");
|
|
}
|
|
}
|
|
|
|
int uart_Init(void)
|
|
{
|
|
/* 打开串口终端 */
|
|
fd = open(UART_DEV, O_RDWR | O_NOCTTY);
|
|
if (0 > fd) {
|
|
fprintf(stderr, "open error: %s: %s\n", UART_DEV, strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
setuart_cfg(&uart_cfg);
|
|
|
|
async_io_init();
|
|
|
|
return 0;
|
|
}
|
|
|
|
int setuart_cfg(const uart_cfg_t *cfg)
|
|
{
|
|
struct termios new_cfg = {0}; //将 new_cfg 对象清零
|
|
speed_t speed;
|
|
|
|
/* 设置为原始模式 */
|
|
cfmakeraw(&new_cfg);
|
|
|
|
/* 使能接收 */
|
|
new_cfg.c_cflag |= CREAD;
|
|
|
|
/* 设置波特率 */
|
|
switch (cfg->baudrate) {
|
|
case 1200: speed = B1200;
|
|
break;
|
|
case 1800: speed = B1800;
|
|
break;
|
|
case 2400: speed = B2400;
|
|
break;
|
|
case 4800: speed = B4800;
|
|
break;
|
|
case 9600: speed = B9600;
|
|
break;
|
|
case 19200: speed = B19200;
|
|
break;
|
|
case 38400: speed = B38400;
|
|
break;
|
|
case 57600: speed = B57600;
|
|
break;
|
|
case 115200: speed = B115200;
|
|
break;
|
|
case 230400: speed = B230400;
|
|
break;
|
|
case 460800: speed = B460800;
|
|
break;
|
|
case 500000: speed = B500000;
|
|
break;
|
|
default: //默认配置为 115200
|
|
speed = B115200;
|
|
printf("default baud rate: 115200\n");
|
|
break;
|
|
}
|
|
|
|
if (0 > cfsetspeed(&new_cfg, speed)) {
|
|
fprintf(stderr, "cfsetspeed error: %s\n", strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
/* 设置数据位大小 */
|
|
new_cfg.c_cflag &= ~CSIZE; //将数据位相关的比特位清零
|
|
switch (cfg->dbit) {
|
|
case 5:
|
|
new_cfg.c_cflag |= CS5;
|
|
break;
|
|
case 6:
|
|
new_cfg.c_cflag |= CS6;
|
|
break;
|
|
case 7:
|
|
new_cfg.c_cflag |= CS7;
|
|
break;
|
|
case 8:
|
|
new_cfg.c_cflag |= CS8;
|
|
break;
|
|
default: //默认数据位大小为 8
|
|
new_cfg.c_cflag |= CS8;
|
|
printf("default data bit size: 8\n");
|
|
break;
|
|
}
|
|
|
|
/* 设置奇偶校验 */
|
|
switch (cfg->parity) {
|
|
case 'N': //无校验
|
|
new_cfg.c_cflag &= ~PARENB;
|
|
new_cfg.c_iflag &= ~INPCK;
|
|
break;
|
|
case 'O': //奇校验
|
|
new_cfg.c_cflag |= (PARODD | PARENB);
|
|
new_cfg.c_iflag |= INPCK;
|
|
break;
|
|
case 'E': //偶校验
|
|
new_cfg.c_cflag |= PARENB;
|
|
new_cfg.c_cflag &= ~PARODD; /* 清除 PARODD 标志,配置为偶校验 */
|
|
new_cfg.c_iflag |= INPCK;
|
|
break;
|
|
default: //默认配置为无校验
|
|
new_cfg.c_cflag &= ~PARENB;
|
|
new_cfg.c_iflag &= ~INPCK;
|
|
printf("default parity: N\n");
|
|
break;
|
|
}
|
|
|
|
/* 设置停止位 */
|
|
switch (cfg->sbit) {
|
|
case 1: //1 个停止位
|
|
new_cfg.c_cflag &= ~CSTOPB;
|
|
break;
|
|
case 2: //2 个停止位
|
|
new_cfg.c_cflag |= CSTOPB;
|
|
break;
|
|
default: //默认配置为 1 个停止位
|
|
new_cfg.c_cflag &= ~CSTOPB;
|
|
printf("default stop bit size: 1\n");
|
|
break;
|
|
}
|
|
|
|
/* 将 MIN 和 TIME 设置为 0 */
|
|
new_cfg.c_cc[VTIME] = 0;
|
|
new_cfg.c_cc[VMIN] = 0;
|
|
|
|
/* 清空缓冲区 */
|
|
if (0 > tcflush(fd, TCIOFLUSH)) {
|
|
fprintf(stderr, "tcflush error: %s\n", strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
/* 写入配置、使配置生效 */
|
|
if (0 > tcsetattr(fd, TCSANOW, &new_cfg)) {
|
|
fprintf(stderr, "tcsetattr error: %s\n", strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
/* 配置 OK 退出 */
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
void async_io_init(void)
|
|
{
|
|
struct sigaction sigatn;
|
|
int flag;
|
|
|
|
/* 使能异步 I/O */
|
|
flag = fcntl(fd, F_GETFL); //使能串口的异步 I/O 功能
|
|
flag |= O_ASYNC;
|
|
fcntl(fd, F_SETFL, flag);
|
|
|
|
/* 设置异步 I/O 的所有者 */
|
|
fcntl(fd, F_SETOWN, getpid());
|
|
|
|
/* 指定实时信号 SIGRTMIN 作为异步 I/O 通知信号 */
|
|
fcntl(fd, F_SETSIG, SIGRTMIN);
|
|
|
|
/* 为实时信号 SIGRTMIN 注册信号处理函数 */
|
|
sigatn.sa_sigaction = io_handler; //当串口有数据可读时,会跳转到 io_handler 函数
|
|
sigatn.sa_flags = SA_SIGINFO;
|
|
sigemptyset(&sigatn.sa_mask);
|
|
sigaction(SIGRTMIN, &sigatn, NULL);
|
|
}
|
|
|