//---------------------------------------------------------------------
|
#include <stdio.h> /*标准输入输出定义*/
|
#include <stdlib.h> /*标准函数库定义*/
|
#include <string.h>
|
#include <unistd.h> /*Unix 标准函数定义*/
|
#include <sys/types.h>
|
#include <sys/stat.h>
|
//---------------------------------------------------------------------
|
#include <termios.h> /*PPSIX 终端控制定义*/
|
#include <fcntl.h> /*文件控制定义*/
|
#include <unistd.h> /*Unix 标准函数定义*/
|
#include <linux/serial.h>
|
#include <sys/ioctl.h>
|
|
#include "uart_driver.h"
|
|
Uart_Driver::Uart_Driver(QObject *parent) :
|
QThread(parent)
|
{
|
|
}
|
|
//---------------------------------------------------------------------
|
/**
|
*@brief 设置串口通信速率
|
*@param fd 类型 int 打开串口的文件句柄
|
*@param speed 类型 int 串口速度
|
*@return void
|
*/
|
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
int speed_arr[] = { B115200, B57600, B38400, B19200, B9600};
|
int name_arr[] = { 115200, 57600, 38400, 19200, 9600};
|
void Uart_Driver::set_speed(int fd, int speed)
|
{
|
int status;
|
struct termios Opt;
|
tcgetattr(fd, &Opt);
|
for ( unsigned int i= 0; i < sizeof(speed_arr) / sizeof(int); i++)
|
{
|
if(speed == name_arr[i])
|
{
|
tcflush(fd, TCIOFLUSH);
|
cfsetispeed(&Opt, speed_arr[i]);
|
cfsetospeed(&Opt, speed_arr[i]);
|
status = tcsetattr(fd, TCSANOW, &Opt);
|
if(status != 0)
|
{
|
perror("tcsetattr fd1");
|
return;
|
}
|
tcflush(fd,TCIOFLUSH);
|
}
|
}
|
}
|
//---------------------------------------------------------------------
|
/**
|
*@brief 设置串口数据位,停止位和效验位
|
*@param fd 类型 int 打开的串口文件句柄
|
*@param databits 类型 int 数据位 取值 为 7 或者8
|
*@param stopbits 类型 int 停止位 取值为 1 或者2
|
*@param parity 类型 int 效验类型 取值为N,E,O,,S
|
*/
|
//---------------------------------------------------------------------
|
int Uart_Driver::set_Parity(int fd,int databits,int stopbits,int parity)
|
{
|
struct termios options;
|
if(tcgetattr(fd, &options) != 0)
|
{
|
perror("SetupSerial 1");
|
return(-1);
|
}
|
|
//--------------- 二进制传输模式 -------------------------
|
options.c_iflag = 0;
|
options.c_oflag = 0;
|
//------------------------------------------------------
|
|
options.c_cflag &= ~CSIZE;
|
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);/*Input*/
|
options.c_oflag &= ~OPOST;/*Output*/
|
switch (databits) /*设置数据位数*/
|
{
|
case 7:
|
options.c_cflag |= CS7;
|
break;
|
case 8:
|
options.c_cflag |= CS8;
|
break;
|
default:
|
fprintf(stderr,"Unsupported data size\n");
|
return (-1);
|
}
|
switch (parity)
|
{
|
case 'n':
|
case 'N':
|
options.c_cflag &= ~PARENB; /* Clear parity enable */
|
options.c_iflag &= ~INPCK; /* Enable parity checking */
|
break;
|
case 'o':
|
case 'O':
|
options.c_cflag |= (PARODD | PARENB); /* 设置为奇效验*/
|
options.c_iflag |= INPCK; /* Disnable parity checking */
|
break;
|
case 'e':
|
case 'E':
|
options.c_cflag |= PARENB; /* Enable parity */
|
options.c_cflag &= ~PARODD; /* 转换为偶效验*/
|
options.c_iflag |= INPCK; /* Disnable parity checking */
|
break;
|
case 'S':
|
case 's': /*as no parity*/
|
options.c_cflag &= ~PARENB;
|
options.c_cflag &= ~CSTOPB;
|
break;
|
default:
|
fprintf(stderr,"Unsupported parity\n");
|
return (-1);
|
}
|
/* 设置停止位*/
|
switch (stopbits)
|
{
|
case 1:
|
options.c_cflag &= ~CSTOPB;
|
break;
|
case 2:
|
options.c_cflag |= CSTOPB;
|
break;
|
default:
|
fprintf(stderr,"Unsupported stop bits\n");
|
return (-1);
|
}
|
/* Set input parity option */
|
if (parity != 'n')
|
options.c_iflag |= INPCK;
|
|
tcflush(fd, TCIFLUSH);
|
options.c_cc[VTIME] = 0; /* 0.1S */
|
options.c_cc[VMIN] = 0;
|
/* Update the options and do it NOW */
|
if (tcsetattr(fd,TCSANOW,&options) != 0)
|
{
|
perror("SetupSerial 3");
|
return (-1);
|
}
|
return (0);
|
}
|
//---------------------------------------------------------------------
|
int Uart_Driver::OpenDev(const char *Dev)
|
{
|
FD = open(Dev, O_RDWR|O_NOCTTY|O_NDELAY);
|
|
return FD;
|
}
|
//---------------------------------------------------------------------
|
void Uart_Driver::SetDevAttr(int bitrate, char bitlen,
|
char stopbitlen, char checktype)
|
{
|
if(FD < 0)
|
return;
|
|
set_speed(FD, bitrate);
|
|
if(set_Parity(FD, bitlen, stopbitlen, checktype) < 0)
|
{
|
qDebug("Set Parity Error\n");
|
}
|
|
|
if(fcntl(FD, F_SETFL, FNDELAY) < 0)//非阻塞,覆盖前面open的属性
|
{
|
qDebug("fcntl failed\n");
|
}
|
}
|
//---------------------------------------------------------------------
|
int Uart_Driver::WriteDev(void *buf, int len)
|
{
|
if(FD < 0)
|
return 0;
|
|
return write(FD, (char *)buf, len);
|
}
|
//---------------------------------------------------------------------
|
int Uart_Driver::ReadDev(void *buf, int len)
|
{
|
if(FD < 0)
|
return 0;
|
|
char *pbuff = (char *)buf;
|
return (read(FD, pbuff, len));
|
}
|
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
|
int Uart_Driver::ReadData(void *buf, const int len, const int timeout_ms)
|
{
|
quint16 rx_len = 0;
|
quint16 rx_time_out = 0;
|
quint8 *p_rxdata = (quint8 *)buf;
|
|
quint8 rx_databuff[512] = {0};
|
quint16 bytes = 0;
|
|
int timeout_5ms = timeout_ms/5;
|
|
while(1)
|
{
|
ioctl(FD, FIONREAD, &bytes); //确认字节数
|
|
if(bytes > 512){
|
bytes = 512;
|
}
|
|
if(bytes > 0){
|
int rlen = ReadDev(&rx_databuff, bytes);
|
|
if(rlen > 0){
|
for(int i=0;i<rlen;i++)
|
{
|
if(rx_len < len){
|
p_rxdata[rx_len++] = rx_databuff[i];
|
}
|
else
|
break;
|
}
|
|
rx_time_out = 0;
|
}
|
}
|
else{
|
if(rx_len>0 && rx_time_out>40) //收到了部分字节后,字节之间超时 x*5ms
|
{
|
qDebug("rx_len = %d",rx_len);
|
|
/*
|
qDebug("******* 5 ********");
|
for(int n=0;n<5;n++){
|
qDebug("0x%2X",rx_databuff[n]);
|
}
|
*/
|
|
return rx_len;
|
}
|
|
if(rx_time_out > timeout_5ms) //接收超时 timeout_5ms * 5ms
|
{
|
return CommRxError;
|
}
|
}
|
|
if(rx_len >= len){
|
return CommOK;
|
}
|
|
rx_time_out++;
|
|
msleep(5);
|
}
|
}
|
|
void Uart_Driver::ClearRxBuff(void)
|
{
|
int bytes = 0;
|
int rxlen = 0;
|
char tmp[64] = {0};
|
|
while(1)
|
{
|
ioctl(FD, FIONREAD, &bytes); //确认字节数
|
|
if(bytes > 0){
|
rxlen = ReadDev(tmp, 64);
|
if(rxlen>0)
|
continue;
|
else
|
return;
|
}
|
else
|
return;
|
}
|
}
|
|
int Uart_Driver::ModBusRead( const quint8 device_addr,const quint16 data_addr,const quint16 read_data_num,
|
void *read_data_buf, const quint16 timeout_ms)
|
{
|
int res = CommOK;
|
|
quint8 txData[16] = {0};
|
quint8 rxData[264] = {0};
|
|
txData[0] = device_addr;
|
txData[1] = FUNC_CODE_READ;
|
txData[2] = data_addr/256;
|
txData[3] = data_addr%256;
|
txData[4] = read_data_num/256;
|
txData[5] = read_data_num%256;
|
unsigned short crc = CRC16::CalModbusCRC16(txData,6);
|
txData[6] = (quint8)(crc>>8);
|
txData[7] = (quint8)crc;
|
|
const quint16 tx_data_len = 8;
|
quint16 rx_data_len = 0;
|
|
/*
|
if(device_addr>1){
|
for(int n=0;n<8;n++){
|
qDebug("0x%02X",txData[n]);
|
}
|
}
|
*/
|
|
ClearRxBuff();
|
|
if(tx_data_len != WriteDev(txData, tx_data_len))
|
res = CommTxError;
|
|
rx_data_len = read_data_num*2+5;
|
if(rx_data_len>264)
|
rx_data_len = 264;
|
|
if(CommOK == res)
|
{
|
res = ReadData(rxData, rx_data_len, timeout_ms);
|
}
|
|
if(CommOK == res)
|
{
|
crc = rxData[rx_data_len-2];
|
crc = (crc<<8) + rxData[rx_data_len-1];
|
|
if(crc == CRC16::CalModbusCRC16(rxData, rx_data_len-2))
|
{
|
if(NULL != read_data_buf)
|
{
|
quint8 *pRecvData = (quint8 *)read_data_buf;
|
for (quint8 i = 3; i<rx_data_len-2; i++)
|
{
|
*pRecvData++ = rxData[i];
|
}
|
}
|
}
|
else
|
{
|
res = CommDataError;
|
}
|
}
|
|
if(CommOK != res){
|
if(device_addr < 254){
|
qDebug("ModBusRead error,devaddr:%d,errorcode:%d",device_addr,res);
|
}
|
}
|
|
return res;
|
}
|
|
int Uart_Driver::ModBusMultiWrite(const quint8 device_addr, const quint16 data_addr,quint16 *wr_data_buf,
|
const quint16 WriteDataNum, const quint16 timeout_ms)
|
{
|
int res = CommOK;
|
|
quint8 txData[128] = {0};
|
quint8 rxData[16] = {0};
|
|
quint16 wrdatanum = WriteDataNum;
|
|
if(wrdatanum>48)
|
wrdatanum = 48;
|
|
quint16 lenth = 0;
|
|
txData[lenth++] = device_addr;
|
txData[lenth++] = FUNC_CODE_MULTI_WRITE; //多点写
|
txData[lenth++] = data_addr/256;
|
txData[lenth++] = data_addr%256;
|
txData[lenth++] = wrdatanum/256;
|
txData[lenth++] = wrdatanum%256;
|
txData[lenth++] = wrdatanum*2;
|
|
for(int i=0;i<wrdatanum;i++)
|
{
|
txData[lenth++] = wr_data_buf[i]/256;
|
txData[lenth++] = wr_data_buf[i]%256;
|
}
|
|
unsigned short crc = CRC16::CalModbusCRC16(txData,lenth);
|
|
txData[lenth++] = (quint8)(crc>>8);
|
txData[lenth++] = (quint8)crc;
|
|
/*
|
qDebug("******* 4 ********");
|
for(int n=0;n<lenth;n++){
|
qDebug("0x%X",txData[n]);
|
}
|
*/
|
|
const quint16 rx_data_len = 8;
|
quint16 rx_data = 0;
|
|
ClearRxBuff();
|
|
if(lenth != WriteDev(txData, lenth))
|
res = CommTxError;
|
|
if(CommOK == res)
|
{
|
res = ReadData(rxData, rx_data_len, timeout_ms);
|
}
|
|
if(CommOK == res)
|
{
|
crc = rxData[rx_data_len-2];
|
crc = (crc<<8) + rxData[rx_data_len-1];
|
|
if(crc == CRC16::CalModbusCRC16(rxData, rx_data_len-2))
|
{
|
rx_data = (quint16)(rxData[4]<<8)+rxData[5];
|
if(0 == rx_data) //pass==1
|
res = CommWrFailError;
|
}
|
else
|
{
|
res = CommDataError;
|
}
|
}
|
else if(res > 0)
|
{
|
int dl = res;
|
|
if(dl >= 5)
|
{
|
crc = rxData[dl-2];
|
crc = (crc<<8) + rxData[dl-1];
|
|
if(crc == CRC16::CalModbusCRC16(rxData, dl-2))
|
{
|
res = CommOK;
|
}
|
else
|
{
|
res = CommDataError;
|
}
|
}
|
else
|
res = CommDataError;
|
}
|
|
if(CommOK != res){
|
qDebug("ModBusMultiWrite error,devaddr:%d,errorcode:%d",device_addr,res);
|
}
|
|
return res;
|
}
|
|
int Uart_Driver::ModBusSingleWrite( const quint8 device_addr,const quint16 data_addr,
|
const quint16 wr_data, const quint16 timeout_ms )
|
{
|
int res = CommOK;
|
|
quint8 txData[16] = {0};
|
quint8 rxData[16] = {0};
|
|
txData[0] = device_addr;
|
txData[1] = FUNC_CODE_SINGLE_WRITE;
|
txData[2] = data_addr/256;
|
txData[3] = data_addr%256;
|
txData[4] = wr_data/256;
|
txData[5] = wr_data%256;
|
|
unsigned short crc = CRC16::CalModbusCRC16(txData,6);
|
txData[6] = (quint8)(crc>>8);
|
txData[7] = (quint8)crc;
|
|
const quint16 rx_data_len = 8;
|
const quint16 tx_data_len = 8;
|
quint16 rx_data = 0;
|
|
ClearRxBuff();
|
|
if(tx_data_len != WriteDev(txData, tx_data_len))
|
res = CommTxError;
|
|
if(CommOK == res)
|
{
|
res = ReadData(rxData, rx_data_len, timeout_ms);
|
}
|
|
if(CommOK == res)
|
{
|
crc = rxData[rx_data_len-2];
|
crc = (crc<<8) + rxData[rx_data_len-1];
|
|
if(crc == CRC16::CalModbusCRC16(rxData, rx_data_len-2))
|
{
|
rx_data = (quint16)(rxData[4]<<8)+rxData[5];
|
if(0 == rx_data) //pass==1
|
res = CommWrFailError;
|
}
|
else
|
{
|
res = CommDataError;
|
}
|
}
|
|
if(CommOK != res){
|
qDebug("ModBusSingleWrite error,devaddr:%d,errorcode:%d",device_addr,res);
|
}
|
|
return res;
|
}
|
|
int Uart_Driver::Tx_Rx_Data(void *txdata, const int txlen, void *rxdata, const int timeout_ms)
|
{
|
ClearRxBuff();
|
|
WriteDev(txdata, txlen);
|
|
quint16 rx_len = 0;
|
quint16 rx_time_out = 0;
|
quint8 *p_rxdata = (quint8 *)rxdata;
|
|
quint8 rx_databuff[512] = {0};
|
quint16 bytes = 0;
|
|
int timeout_5ms = timeout_ms/5;
|
|
while(1)
|
{
|
ioctl(FD, FIONREAD, &bytes); //确认字节数
|
|
if(bytes > 512){
|
bytes = 512;
|
}
|
|
if(bytes > 0){
|
int rlen = ReadDev(&rx_databuff, bytes);
|
|
if(rlen > 0){
|
for(int i=0;i<rlen;i++)
|
{
|
if(rx_len < 1024)
|
p_rxdata[rx_len++] = rx_databuff[i];
|
}
|
|
rx_time_out = 0;
|
}
|
}
|
else{
|
if(rx_len>0 && rx_time_out>40) //收到了部分字节后,字节之间超时 x*5ms
|
{
|
return rx_len;
|
}
|
|
if(rx_time_out > timeout_5ms) //接收超时 timeout_5ms * 5ms
|
{
|
return 0;
|
}
|
}
|
|
rx_time_out++;
|
|
msleep(5);
|
}
|
|
return 0;
|
}
|
|
int Uart_Driver::Tx_Rx_Data_ESP32(void *txdata, const int txlen, void *rxdata, const int rxlen)
|
{
|
ClearRxBuff();
|
|
WriteDev(txdata, txlen);
|
|
quint16 rx_len = 0;
|
quint16 rx_time_out = 0;
|
quint8 *p_rxdata = (quint8 *)rxdata;
|
|
quint8 rx_databuff[512] = {0};
|
quint16 bytes = 0;
|
|
while(1)
|
{
|
ioctl(FD, FIONREAD, &bytes); //确认字节数
|
|
if(bytes > 512){
|
bytes = 512;
|
}
|
|
if(bytes > 0){
|
int rlen = ReadDev(&rx_databuff, bytes);
|
|
if(rlen > 0){
|
for(int i=0;i<rlen;i++)
|
{
|
if(rx_len < rxlen)
|
p_rxdata[rx_len++] = rx_databuff[i];
|
}
|
|
rx_time_out = 0;
|
}
|
}
|
else{
|
if(rx_len >= rxlen){
|
return 0;
|
}
|
|
if(rx_len>0 && rx_time_out>40) //收到了部分字节后,字节之间超时 x*5ms
|
{
|
return rx_len;
|
}
|
|
if(rx_time_out > 120) //接收超时 x * 5ms
|
{
|
return -1;
|
}
|
}
|
|
rx_time_out++;
|
|
msleep(5);
|
}
|
|
return 0;
|
}
|
|
int Uart_Driver::ReadData_ESP32(void *rxdata, const int timeout_ms)
|
{
|
quint16 rx_len = 0;
|
quint16 rx_time_out = 0;
|
quint8 *p_rxdata = (quint8 *)rxdata;
|
|
quint8 rx_databuff[512] = {0};
|
quint16 bytes = 0;
|
|
int timeout_5ms = timeout_ms/5;
|
|
while(1)
|
{
|
ioctl(FD, FIONREAD, &bytes); //确认字节数
|
|
if(bytes > 512){
|
bytes = 512;
|
}
|
|
if(bytes > 0){
|
|
//qDebug("bytes = %d",bytes);
|
|
int rlen = ReadDev(&rx_databuff, bytes);
|
|
if(rlen > 0){
|
|
//qDebug("rlen = %d",rlen);
|
|
for(int i=0;i<rlen;i++)
|
{
|
if(rx_len < 1000)
|
p_rxdata[rx_len++] = rx_databuff[i];
|
}
|
|
rx_time_out = 0;
|
}
|
}
|
else{
|
if(rx_len>0)
|
{
|
if(rx_time_out>timeout_5ms){
|
return rx_len;
|
}
|
}
|
else{
|
return 0;
|
}
|
}
|
|
rx_time_out++;
|
|
msleep(5);
|
}
|
|
return 0;
|
}
|