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.

289 lines
5.9 KiB
C

/* Includes ------------------------------------------------------------------*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
/* 标准C库头文件. */
#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"
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));
cfmakeraw(&termios_new);
if (tcgetattr(fd, &termios_old) != 0)
{
DBG(DBG_M_SERIAL, "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)
{
DBG(DBG_M_SERIAL, "Open SerialPort(%s) failed[error = %d, %s]!!!!!!!\r\n",
devname, errno, strerror(errno));
return E_SYS_CALL;
}
strcpy(attr.tty, devname);
attr.baudrate = baudrate;
serial_attr_set(fd, &attr);
DBG(DBG_M_SERIAL, "Open SerialPort(%s:%d) port success!!!\r\n", devname, baudrate);
return fd;
}
int serial_read(int fd, unsigned char * data, int len)
{
int ret = -1;
fd_set fs_read;
int maxfd = -1;
if (fd < 0 || data == NULL || len <= 0)
{
DBG(DBG_M_SERIAL, "Param Error, fd = %d or NULL == data or len <= 0.\r\n", fd);
return E_ERROR;
}
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)
{
DBG(DBG_M_SERIAL, "select error[%d, %s]!!!\r\n", errno, strerror(errno));
return E_SYS_CALL;
}
if (ret == 0)
{
DBG(DBG_M_SERIAL, "Timeout......\r\n");
return E_TIMEOUT;
}
ret = read(fd, data, len);
if (ret < 0)
{
DBG(DBG_M_SERIAL, "read error[%d, %s]\r\n", errno, strerror(errno));
return E_SYS_CALL;
}
return ret;
}
int serial_write(int fd, unsigned char * data, int len)
{
if (fd < 0 || NULL == data || len <= 0)
{
DBG(DBG_M_SERIAL, "Param Error, fd = %d or NULL == data or len = %d.\r\n", fd, len);
return E_BAD_PARAM;
}
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)
{
DBG(DBG_M_SERIAL, "select Error[errno = %d, %s]\r\n", errno, strerror(errno));
return E_SYS_CALL;
}
else if (ret == 0)
{
DBG(DBG_M_SERIAL, "Timeout!\r\n");
return E_TIMEOUT;
}
if (FD_ISSET(fd, &fs_write))
{
int pos = 0;
while (len > 0)
{
ret = write(fd, data + pos, len);
if (ret < 0)
{
DBG(DBG_M_SERIAL, "write com[fd = %d] error[errno = %d, %s]\r\n", fd, errno, strerror(errno));
return E_SYS_CALL;
}
len -= ret;
pos += ret;
}
}
return len;
}
void serial_close(int fd)
{
if (fd > 0)
{
close(fd);
}
}