You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
346 lines
6.9 KiB
C
346 lines
6.9 KiB
C
![]()
1 year ago
|
#include <stdio.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/stat.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <errno.h>
|
||
|
#include <string.h>
|
||
|
#include <unistd.h>
|
||
|
#include <termios.h>
|
||
|
|
||
|
#include "serial.h"
|
||
|
#include "debug.h"
|
||
|
|
||
|
int serial_band_convert(unsigned int baudrate)
|
||
|
{
|
||
|
switch (baudrate)
|
||
|
{
|
||
|
case 2400:
|
||
|
return B2400;
|
||
|
|
||
|
case 4800:
|
||
|
return B4800;
|
||
|
|
||
|
case 9600:
|
||
|
return B9600;
|
||
|
|
||
|
case 19200:
|
||
|
return B19200;
|
||
|
|
||
|
case 38400:
|
||
|
return B38400;
|
||
|
|
||
|
case 57600:
|
||
|
return B57600;
|
||
|
|
||
|
case 115200:
|
||
|
return B115200;
|
||
|
|
||
|
case 921600:
|
||
|
return B921600;
|
||
|
|
||
|
case 1152000:
|
||
|
return B1152000;
|
||
|
|
||
|
default:
|
||
|
return B115200;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int serial_attr_set(int fd, serial_attr_t * attr)
|
||
|
{
|
||
|
unsigned char databit = 0;
|
||
|
unsigned char stopbit = 0;
|
||
|
unsigned char parity = 0;
|
||
|
unsigned char fctl = 0;
|
||
|
int ret = -1;
|
||
|
unsigned int baudrate = 0;
|
||
|
|
||
|
struct termios termios_old;
|
||
|
struct termios termios_new;
|
||
|
|
||
|
memset(&termios_old, 0, sizeof(termios_old));
|
||
|
memset(&termios_new, 0, sizeof(termios_new));
|
||
|
|
||
|
//CHECK_SERIAL_PORT_FD;
|
||
|
|
||
|
cfmakeraw(&termios_new);
|
||
|
|
||
|
if (tcgetattr(fd, &termios_old) != 0)
|
||
|
{
|
||
|
perror("Setup Serial!\r\n");
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
//baudrates
|
||
|
baudrate = serial_band_convert(attr->baudrate);
|
||
|
cfsetispeed(&termios_new, baudrate);
|
||
|
cfsetospeed(&termios_new, baudrate);
|
||
|
termios_new.c_cflag |= CLOCAL;
|
||
|
termios_new.c_cflag |= CREAD;
|
||
|
|
||
|
//flow control
|
||
|
fctl = attr-> fctl;
|
||
|
switch (fctl)
|
||
|
{
|
||
|
case 0:
|
||
|
termios_new.c_cflag &= ~CRTSCTS; //no flow control
|
||
|
break;
|
||
|
case 1:
|
||
|
termios_new.c_cflag |= CRTSCTS; //hardware flow control
|
||
|
break;
|
||
|
|
||
|
case 2:
|
||
|
termios_new.c_iflag |= IXON | IXOFF | IXANY; //software flow control
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//data bits
|
||
|
termios_new.c_cflag &= ~CSIZE; //控制模式,屏蔽字符大小位
|
||
|
databit = attr->databit;
|
||
|
switch (databit)
|
||
|
{
|
||
|
case 5:
|
||
|
termios_new.c_cflag |= CS5;
|
||
|
break;
|
||
|
|
||
|
case 6:
|
||
|
termios_new.c_cflag |= CS6;
|
||
|
break;
|
||
|
|
||
|
case 7:
|
||
|
termios_new.c_cflag |= CS7;
|
||
|
break;
|
||
|
|
||
|
case 8:
|
||
|
termios_new.c_cflag |= CS8;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
termios_new.c_cflag |= CS8;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//parity check
|
||
|
parity = attr->parity;
|
||
|
switch (parity)
|
||
|
{
|
||
|
case 0: //no parity check
|
||
|
termios_new.c_cflag &= ~PARENB;
|
||
|
break;
|
||
|
|
||
|
case 1: //odd check
|
||
|
termios_new.c_cflag |= PARENB;
|
||
|
termios_new.c_cflag &= ~PARODD;
|
||
|
break;
|
||
|
|
||
|
case 2: //even check
|
||
|
termios_new.c_cflag |= PARENB;
|
||
|
termios_new.c_cflag |= PARODD;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//stop bits
|
||
|
stopbit = attr->stopbit;
|
||
|
if (stopbit == 2)
|
||
|
{
|
||
|
termios_new.c_cflag |= CSTOPB;
|
||
|
}
|
||
|
else if (stopbit == 1)
|
||
|
{
|
||
|
termios_new.c_cflag &= ~CSTOPB;
|
||
|
}
|
||
|
|
||
|
//other attributions default
|
||
|
termios_new.c_oflag &= ~OPOST;
|
||
|
termios_new.c_cc[VMIN] = 1;
|
||
|
termios_new.c_cc[VTIME] = 1;
|
||
|
tcflush(fd, TCIFLUSH);
|
||
|
ret = tcsetattr(fd, TCSANOW, &termios_new);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
int serial_open(const char * devname, int baudrate)
|
||
|
{
|
||
|
int fd;
|
||
|
serial_attr_t attr;
|
||
|
fd = open(devname, O_RDWR | O_NOCTTY | O_NONBLOCK);
|
||
|
if (fd < 0)
|
||
|
{
|
||
|
LOG("Open SerialPort(%s) failed[error = %d, %s]!!!!!!!\n\n",
|
||
|
devname, errno, strerror(errno));
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
strcpy(attr.tty, devname);
|
||
|
attr.baudrate = baudrate;
|
||
|
|
||
|
serial_attr_set(fd, &attr);
|
||
|
|
||
|
LOG("Open SerialPort(%s:%d) port success!!!\n", devname, baudrate);
|
||
|
|
||
|
return fd;
|
||
|
}
|
||
|
|
||
|
#if 1
|
||
|
int serial_read(int fd, unsigned char * data, int len)
|
||
|
{
|
||
|
int ret = -1;
|
||
|
fd_set fs_read;
|
||
|
int maxfd = -1;
|
||
|
|
||
|
//CHECK_SERIAL_PORT_FD;
|
||
|
if (fd < 0)
|
||
|
{
|
||
|
LOG("error fd = %d\n", fd);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
if (data == NULL || len <= 0)
|
||
|
{
|
||
|
LOG("Param Error, NULL == data || len <= 0.\n");
|
||
|
return -1;
|
||
|
}
|
||
|
//#if 0
|
||
|
FD_ZERO(&fs_read);
|
||
|
FD_SET(fd, &fs_read);
|
||
|
maxfd = fd + 1;
|
||
|
struct timeval tv;
|
||
|
tv.tv_sec = 0;
|
||
|
tv.tv_usec = 1000 * 1000;
|
||
|
|
||
|
ret = select(maxfd, &fs_read, NULL, NULL, &tv);
|
||
|
if (ret < 0)
|
||
|
{
|
||
|
LOG("select error[%d, %s]!!!\n", errno, strerror(errno));
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
if (ret == 0)
|
||
|
{
|
||
|
LOG("Timeout......\n\n\n");
|
||
|
return -1;
|
||
|
}
|
||
|
//#endif
|
||
|
|
||
|
ret = read(fd, data, len);
|
||
|
if (ret < 0)
|
||
|
{
|
||
|
LOG("read error[%d, %s]\n", errno, strerror(errno));
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
#else
|
||
|
int serial_read(int fd, unsigned char * data, int len)
|
||
|
{
|
||
|
int ret, fs_sel;
|
||
|
fd_set fs_read;
|
||
|
|
||
|
struct timeval time;
|
||
|
|
||
|
FD_ZERO(&fs_read);
|
||
|
FD_SET(fd, &fs_read);
|
||
|
time.tv_sec = 1;
|
||
|
time.tv_usec = 0; //1s
|
||
|
//使用select实现串口的多路通信
|
||
|
fs_sel = select(fd + 1, &fs_read, NULL, NULL, &time);
|
||
|
if(fs_sel)
|
||
|
{
|
||
|
ret = read(fd, data, len);
|
||
|
printf("read len=%d\n", ret);
|
||
|
print_raw_data(data, len);
|
||
|
return ret;
|
||
|
}
|
||
|
return 0;
|
||
|
// return read(fd, rcv_buf, rcv_len);
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#if 1
|
||
|
int serial_write(int fd, unsigned char * data, int len)
|
||
|
{
|
||
|
//CHECK_SERIAL_PORT_FD;
|
||
|
if (fd < 0)
|
||
|
{
|
||
|
LOG("error fd = %d\n", fd);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
if (NULL == data || len <= 0)
|
||
|
{
|
||
|
LOG("Param Error, NULL == data or len = %d.\n", len);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
fd_set fs_write;
|
||
|
FD_ZERO(&fs_write);
|
||
|
FD_SET(fd, &fs_write);
|
||
|
|
||
|
int maxfd = fd + 1;
|
||
|
struct timeval tv;
|
||
|
tv.tv_sec = 0;
|
||
|
tv.tv_usec = 1000 * 1000;
|
||
|
|
||
|
int ret = select(maxfd, NULL, &fs_write, NULL, &tv);
|
||
|
if (ret < 0)
|
||
|
{
|
||
|
LOG("select Error[errno = %d, %s]", errno, strerror(errno));
|
||
|
return -1;
|
||
|
}
|
||
|
else if (ret == 0)
|
||
|
{
|
||
|
LOG("Timeout!\n");
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
if (FD_ISSET(fd, &fs_write))
|
||
|
{
|
||
|
int pos = 0;
|
||
|
|
||
|
while (len > 0)
|
||
|
{
|
||
|
ret = write(fd, data + pos, len);
|
||
|
if (ret < 0)
|
||
|
{
|
||
|
LOG("write com[fd = %d] error[errno = %d, %s]\n", fd, errno, strerror(errno));
|
||
|
return -1;
|
||
|
}
|
||
|
len -= ret;
|
||
|
pos += ret;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return len;
|
||
|
}
|
||
|
#else
|
||
|
int serial_write(int fd, unsigned char * data, int len)
|
||
|
{
|
||
|
int ret;
|
||
|
print_raw_data(data, len);
|
||
|
ret = write(fd, data, len);
|
||
|
if (len == ret)
|
||
|
{
|
||
|
return 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
tcflush(fd, TCOFLUSH);
|
||
|
return 0;
|
||
|
}
|
||
|
// return write(fd, send_buf, data_len);
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
void serial_close(int fd)
|
||
|
{
|
||
|
if (fd > 0)
|
||
|
{
|
||
|
close(fd);
|
||
|
}
|
||
|
}
|
||
|
|