📄 port.c
字号:
#include <stdio.h> // printf
#include <fcntl.h> // open
#include <string.h> // bzero
#include <stdlib.h> // exit
#include <sys/times.h> // times
#include <sys/stat.h> // lstat
#include <pthread.h>
#include <signal.h>
#include <sys/types.h> // pid_t
#include <limits.h> // CHAR_MAX
#include <termios.h>
#include <unistd.h>
#include <sys/ioctl.h> // ioctl
#include "../include/types.h" // INT32, INT16, INT8, UINT32, UINT16, UINT8
#include "../include/arithmetic.h"
#define TTY_DEV "/dev/ttyS"
#define BUFFER_LEN 1024 // sendfile()
#define E_CANNOT_OPEN -0x10 // 串口不能打开
#define E_CANNOT_CLOSE -0x11 // 串口不能关闭
#define E_SET_ATTR -0x12 // 设置串口属性错误
#define E_CLOSED -0x13
#define E_OPENED -0x14
#define E_NODATA -0x15
#define E_INVALID_BAUDRATE -0x01
#define E_GET_ERROR -0x16 //取串口信号错误
#define E_SET_ERROR -0x17
#define S_PROCESS 0x00 // 函数返回成功
static portinfo_t portinfo =
{
0, // print prompt after receiving
2400, // baudrate: 115200
8, // databit: 8
0, // debug: off
0, // echo: off
1, // flow control: hardware
2, // tty: COM1
0, // parity: none
1, // stopbit: 1
0 // reserved
};
/* tty.c */
INT8 tty_is_open();
int tty_open(const portinfo_t * p_portinfo,const char *);
void tty_close();
//读写控制
int tty_read(void *data, int datalength); //读指定长度的数据
int tty_write(BYTE * data, int datalength); //写指定长度的数据
int tty_set_read_sigon(void); //信号读设置
int tty_signal_resume(void); //控制线恢复
int tty_rts_request(void); //信道请求
int tty_rts_cancel(void); //信道释放
int tty_tcflush(int queue);
int tty_send_checking(void); //串口有没有数据发送检测
int tty_get_signal(int *status); //串口信号线控制
int tty_set_signal(int *status);
//串口指令操作
void tty_input(void); //串口指令接收
int tty_output(BYTE * send_data, UINT32 len); //串口指令发送
#define TIMEOUT_SEC(buflen,baud) (buflen*20/baud+2)
#define TIMEOUT_USEC 0
static int fd = -1; // ttyS端口文件描述符
static struct termios termios_old, termios_new; //定义termios
static struct timeval tv_timeout;
static int tty_get_baudrate();
static char *tty_get_ptty(INT8 tty);
static int tty_set_attr(const portinfo_t * pportinfo);
static void tty_set_baudrate(int);
static void tty_set_databit(INT8 databit);
static void tty_set_flow_control(INT8 fctrl);
static void tty_set_parity_check(INT8 parity);
static void tty_set_stopbit(INT8 stopbit);
static void tty_sig_handler();
INT8 tty_is_open()
{
return -1 == fd ? 0 : 1; // fd == -1, return 0
}
/*
* 参数 : portinfo_t* pportinfo;
* 返回值 : fd 端口描述符、
* 描述 : 打开特定波特率的端口
*/
int tty_open(const portinfo_t * pportinfo,const char *tty)
{
char *ptty;
int retval;
pportinfo->tty = atoi(tty);
ptty = tty_get_ptty(pportinfo->tty);
if (tty_is_open()) {
return (E_OPENED);
}
fd = open(ptty, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (-1 == fd) {
fprintf(stderr, "cannot open port %s\n", ptty);
return (E_CANNOT_OPEN);
}
tcgetattr(fd, &termios_old); // 存储旧的termios值
// 0 on success, -1 on failure
retval = tty_set_attr(pportinfo);
if (-1 == retval) {
fprintf(stderr, "\nport %s cannot set baudrate at %d\n", ptty,
pportinfo->baudrate);
return (E_SET_ATTR);
}
return (0);
}
/*
* 参数 : none
* 返回值 : none
* 描述 : 关闭串口
*/
void tty_close()
{
if (!tty_is_open()) {
return;
}
tcsetattr(fd, TCSADRAIN, &termios_old);
close(fd);
fd = -1;
}
/*
* 参数 : void *data, int datalength;
* 返回值 : E_CLOSE : 端口没有打开
* E_NODATA : 在指定时间内没有数据
* 描述 : 从端口读数据
*/
int tty_read(void *data, int datalength)
{
int retval = 0;
fd_set fs_read;
if (!tty_is_open()) {
return (E_CLOSED);
}
FD_ZERO(&fs_read);
FD_SET(fd, &fs_read);
tv_timeout.tv_sec = TIMEOUT_SEC(datalength, tty_get_baudrate());
tv_timeout.tv_usec = TIMEOUT_USEC;
retval = select(fd + 1, &fs_read, NULL, NULL, &tv_timeout);
if (retval) {
return (read(fd, data, datalength));
} else {
return (E_NODATA);
}
}
/*
* 参数 : UINT8 *data, int datalength;
* 返回值 : 所写的字节数
* 描述 : 写数据到缓冲区
*/
int tty_write(BYTE * data, int datalength)
{
int retval, len = 0, total_len = 0;
fd_set fs_write;
char tmp[50];
int i=0;
if (!tty_is_open()) {
printf("-!tty_is_open\n");
return (E_CLOSED);
}
FD_ZERO(&fs_write);
FD_SET(fd, &fs_write);
tv_timeout.tv_sec = TIMEOUT_SEC(datalength, tty_get_baudrate());
tv_timeout.tv_usec = TIMEOUT_USEC;
strncpy(tmp,"0123456789",10);
for (total_len = 0, len = 0; total_len < datalength;) {
retval = select(fd + 1, NULL, &fs_write, NULL, &tv_timeout);
if (retval) {
len = write(fd, tmp,10);//&data[total_len],10);// datalength - total_len);
for(i=0;i<10;i++)
{
printf("write data :%c\n",tmp[i]);
}
if (len > 0) {
total_len += len;
}
} else {
tcflush(fd, TCOFLUSH); // 刷新所有的输出数据
break;
}
}
return (total_len);
}
/*
* 参数 : void;
* 返回值 :
* 描述 : 取串口波特率
*/
static int tty_get_baudrate()
{
switch (cfgetospeed(&termios_new)) {
case B0:
return (0);
case B50:
return (50);
case B75:
return (75);
case B110:
return (110);
case B134:
return (134);
case B150:
return (150);
case B200:
return (200);
case B300:
return (300);
case B600:
return (600);
case B1200:
return (1200);
case B2400:
return (9600);
case B9600:
return (9600);
case B19200:
return (19200);
case B38400:
return (38400);
case B57600:
return (57600);
case B115200:
return (115200);
default:
return (E_INVALID_BAUDRATE);
}
}
/*
* 参数 : INT8 tty
* 返回值 : 串口描述(ttyS0...);
* 描述 : 取得串口的描述
*/
static char *tty_get_ptty(INT8 tty)
{
char *ptty;
if (0 == tty) {
ptty = TTY_DEV "0";
} else if (1 == tty) {
ptty = TTY_DEV "1";
} else if (2 == tty) {
ptty = TTY_DEV "2";
} else if (3 == tty) {
ptty = TTY_DEV "3";
} else if (4 == tty) {
ptty = TTY_DEV "4";
} else if (5 == tty) {
ptty = TTY_DEV "5";
} else if (6 == tty) {
ptty = TTY_DEV "6";
} else if (7 == tty) {
ptty = TTY_DEV "7";
} else {
ptty = TTY_DEV "0";
}
return (ptty);
}
/*
* 参数 : const portinfo_t* pportinfo;
* 返回值 :
* 描述 : 设置端口的属性
*/
static int tty_set_attr(const portinfo_t * pportinfo)
{
bzero(&termios_new, sizeof(termios_new));
cfmakeraw(&termios_new);
// tty_set_baudrate(pportinfo->baudrate);
tty_set_baudrate(9600);
termios_new.c_cflag |= CLOCAL | CREAD;
tty_set_flow_control(pportinfo->fctrl);
tty_set_databit(pportinfo->databit);
tty_set_parity_check(pportinfo->parity);
tty_set_stopbit(pportinfo->stopbit);
termios_new.c_oflag &= ~OPOST;
termios_new.c_cc[VTIME] = 1; // unit: (1/10) second.
termios_new.c_cc[VMIN] = 1; // minimal characters for reading
tcflush(fd, TCIFLUSH);
return (tcsetattr(fd, TCSANOW, &termios_new));
}
/*
* 参数 : int baudrate;
* 返回值 :
* 描述 : 设置串口的波特率
*/
static void tty_set_baudrate(int baudrate)
{
if (115200<= baudrate) {
termios_new.c_cflag = B115200;
} else if (57600 <= baudrate) {
termios_new.c_cflag = B57600;
} else if (38400 <= baudrate) {
termios_new.c_cflag = B38400;
} else if (19200 <= baudrate) {
termios_new.c_cflag = B19200;
} else if (9600 <= baudrate) {
termios_new.c_cflag = B9600;
} else if (2400 <= baudrate) {
termios_new.c_cflag = B2400;
} else if (1200 <= baudrate) {
termios_new.c_cflag = B1200;
} else if (600 <= baudrate) {
termios_new.c_cflag = B600;
} else if (300 <= baudrate) {
termios_new.c_cflag = B300;
} else if (200 <= baudrate) {
termios_new.c_cflag = B200;
} else if (150 <= baudrate) {
termios_new.c_cflag = B150;
} else if (134 <= baudrate) {
termios_new.c_cflag = B134;
} else if (110 <= baudrate) {
termios_new.c_cflag = B110;
} else if (75 <= baudrate) {
termios_new.c_cflag = B75;
} else if (50 <= baudrate) {
termios_new.c_cflag = B50;
} else if (0 <= baudrate) {
tty_close();
}
}
/*
* 参数 : INT8 databit;
* 返回值 :
* 描述 : 数据位设置(Set databit)
*/
static void tty_set_databit(INT8 databit)
{
termios_new.c_cflag &= ~CSIZE;
if (7 == databit) {
termios_new.c_cflag |= CS7;
} else if (6 == databit) {
termios_new.c_cflag |= CS6;
} else if (5 == databit) {
termios_new.c_cflag |= CS5;
} else {
termios_new.c_cflag |= CS8;
}
}
/*
* 参数 : int fctrl;
* 0: No Flow Control;
* 1: Hardware Control;
* 2: Software Control;
* 返回值 : none
* 描述 : 设置流控制
*/
static void tty_set_flow_control(INT8 fctrl)
{
#if 0
if (0 == fctrl) // no flow control
{
termios_new.c_cflag &= ~CRTSCTS;
} else if (1 == fctrl) // hardware flow control
{
termios_new.c_cflag |= CRTSCTS;
} else if (2 == fctrl) // software flow control
{
termios_new.c_iflag |= IXON | IXOFF | IXANY;
}
#endif
termios_new.c_cflag &= ~CRTSCTS;
}
/*
* 参数 : INT8 parity;
* 返回值 :
* 描述 : 设置奇偶校验
*/
static void tty_set_parity_check(INT8 parity)
{
parity = parity % 3;
if (2 == parity) // even
{
termios_new.c_cflag |= PARENB;
termios_new.c_cflag &= ~PARODD;
} else if (1 == parity) // odd
{
termios_new.c_cflag |= PARENB;
termios_new.c_cflag |= ~PARODD;
} else // no parity check
{
termios_new.c_cflag &= ~PARENB;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -