//
|
// Created by YY on 2017/9/5.
|
//
|
|
#include <jni.h>
|
#include <string>
|
#include <mutex>
|
#include <sys/stat.h>
|
#include <stdbool.h>
|
#include <stdint.h>
|
#include <termios.h>
|
#include <android/log.h>
|
#include <sys/ioctl.h>
|
#include <unistd.h>
|
#include <sys/types.h>
|
#include <sys/stat.h>
|
#include <fcntl.h>
|
#include "../jni_log.h"
|
#include "serial_port.h"
|
|
using namespace std;
|
|
SerialPort::SerialPort(struct serial_config cfg)
|
{
|
this->cfg = cfg;
|
}
|
|
SerialPort::~SerialPort()
|
{
|
UninitSerialPort();
|
}
|
|
int SerialPort::setRTS(int level)
|
{
|
int status;
|
|
if (ioctl(fd, TIOCMGET, &status) == -1) {
|
LOGD("setRTS(): TIOCMGET");
|
return 0;
|
}
|
if (level)
|
status |= TIOCM_RTS;
|
else
|
status &= ~TIOCM_RTS;
|
|
if (ioctl(fd, TIOCMSET, &status) == -1) {
|
LOGD("setRTS(): TIOCMSET");
|
return 0;
|
}
|
return 1;
|
}
|
|
/*********************************************************************
|
* PUBLIC FUNCTIONS
|
*/
|
int SerialPort::SetSerialPort(int fd, int speed, int databits, char parity, int stopbits, int flowctrl) {
|
int status = 0;
|
struct termios opt;
|
int speed_arr[] = {B921600, B576000, B500000, B460800, B230400, B115200, B38400, B19200,
|
B9600, B4800, B2400, B1200, B300};
|
int name_arr[] = {921600, 576000, 500000, 460800, 230400, 115200, 38400, 19200, 9600, 4800,
|
2400, 1200, 300};
|
|
status = tcgetattr(fd, &opt);
|
if (status != 0) {
|
goto SET_SERIAL_PORT_END;
|
}
|
|
status = tcflush(fd, TCIOFLUSH);
|
if (status != 0) {
|
goto SET_SERIAL_PORT_END;
|
}
|
//Set baud
|
for (int i = 0; i < sizeof(speed_arr) / sizeof(int); i++) {
|
if (speed == name_arr[i]) {
|
cfsetispeed(&opt, speed_arr[i]);
|
cfsetospeed(&opt, speed_arr[i]);
|
break;
|
}
|
}
|
|
//Set databit
|
opt.c_cflag &= ~CSIZE;
|
|
if (databits == 7) {
|
opt.c_cflag |= CS7;
|
} else {
|
opt.c_cflag |= CS8;
|
}
|
//Set parity
|
switch (parity) {
|
case 'E':
|
case 'e':
|
opt.c_cflag |= PARENB; /*Enable parity*/
|
opt.c_cflag &= ~PARODD;
|
opt.c_iflag |= INPCK; /*Enable pairty checking*/
|
break;
|
case 'O':
|
case 'o':
|
opt.c_cflag |= PARENB | PARODD;
|
opt.c_iflag |= INPCK;
|
break;
|
|
case 'N':
|
case 'n':
|
default:
|
opt.c_cflag &= ~PARENB;
|
opt.c_iflag &= ~INPCK;
|
break;
|
}
|
//Set stop
|
if (stopbits == 2) {
|
opt.c_cflag |= CSTOPB;
|
} else {
|
opt.c_cflag &= ~CSTOPB;
|
}
|
|
opt.c_cflag |= CLOCAL | CREAD;
|
|
//Set raw mode
|
opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); /*Input*/
|
opt.c_oflag &= ~OPOST; /*Output*/
|
opt.c_iflag &= ~(IXON | IXOFF | IXANY | ICRNL); //Disable XON/XOFF flowcontrol
|
opt.c_iflag &= ~(ICRNL | INLCR); //Disable 0x0d and 0x0a convert
|
|
opt.c_cc[VTIME] = 0;//150; //15 seconds 150x100ms = 15s
|
opt.c_cc[VMIN] = 1; //Recv one char, read() will return
|
|
if (flowctrl) {
|
opt.c_cflag |= CRTSCTS;
|
} else {
|
opt.c_cflag &= ~CRTSCTS; //Disable hard flowcontrol
|
}
|
|
tcflush(fd, TCIOFLUSH);
|
|
status = tcsetattr(fd, TCSANOW, &opt);
|
|
SET_SERIAL_PORT_END:
|
if (status != 0) {
|
LOGD("Serial Port set fail");
|
} else {
|
LOGD("Serial Port set success");
|
}
|
|
// setRTS(fd, 1);
|
|
return status;
|
}
|
|
int SerialPort::OpenSerialPort(const char *name) {
|
int uart_fd;
|
|
// uart_fd = open(name, O_RDWR /*| O_NONBLOCK/*| O_NOCTTY | O_NDELAY*/);
|
uart_fd = open(name, O_RDWR | O_NOCTTY);
|
LOGD("open serial port fd = %d", uart_fd);
|
return uart_fd;
|
}
|
|
void SerialPort::CloseSerialPort(int fd) {
|
close(fd);
|
}
|
|
int SerialPort::WriteSerialPort(const void *buf, int len) {
|
int ret = -1;
|
int fds_ret;
|
|
struct timeval tv;
|
fd_set wrfds;
|
|
if (fd <= 0) {
|
return -1;
|
}
|
|
tv.tv_sec = 1;
|
tv.tv_usec = 0;
|
|
FD_ZERO(&wrfds); //clean
|
FD_SET(fd, &wrfds); //set
|
|
lock_guard<std::mutex> lock(mtx);
|
|
fds_ret = select(fd + 1, NULL, &wrfds, NULL, &tv);
|
|
if (fds_ret < 0) {
|
LOGE("Serial port select error\n");
|
}
|
else if(fds_ret == 0) {
|
LOGE("Serial port write timeout\n");
|
}
|
else if(FD_ISSET(fd, &wrfds)) {
|
ret = write(fd, buf, len); //serial write data
|
if (ret != len ) {
|
LOGE("Serial Port Error\n");
|
tcflush(fd, TCOFLUSH);
|
}
|
}
|
else {
|
LOGE("Serial Port error 2\n");
|
}
|
|
return ret;
|
}
|
|
int SerialPort::InitSerialPort(void)
|
{
|
// char name[32];
|
//
|
// if (id == UART_0) {
|
// strcpy(name, "/dev/ttyCH341USB5");
|
// } else if (id == UART_1) {
|
// strcpy(name, "/dev/ttyCH341USB6");
|
// } else {
|
// return -1;
|
// }
|
|
fd = OpenSerialPort(cfg.name);
|
if (fd <= 0) {
|
return -1;
|
}
|
|
if (SetSerialPort(fd, cfg.baud, cfg.data_bit, cfg.verify_bit, cfg.stop_bit, cfg.flow_ctrl) != 0) {
|
return -2;
|
}
|
|
return 0;
|
}
|
|
void SerialPort::UninitSerialPort(void)
|
{
|
if (fd > 0) {
|
CloseSerialPort(fd);
|
fd = 0;
|
}
|
}
|
|
int SerialPort::ReadSerialPort(uint8_t *out, uint16_t length)
|
{
|
if (fd <= 0) return 0;
|
|
struct timeval tv;
|
fd_set wrfds;
|
|
tv.tv_sec = 5;
|
tv.tv_usec = 0;
|
|
FD_ZERO(&wrfds); //clean
|
FD_SET(fd, &wrfds); //set
|
|
int fds_ret = select(fd + 1, &wrfds, NULL, NULL, &tv);
|
|
if (fds_ret < 0) {
|
return -1;
|
}
|
else if(fds_ret == 0) {
|
// timeout
|
return -2;
|
}
|
else if(FD_ISSET(fd, &wrfds)) {
|
return read(fd, out, length);
|
}
|
|
return -3;
|
}
|