|
#include "Common/crc16.h"
|
#include "rs485_wired_cell.h"
|
//---------------------------------------------------------------------
|
#include <stdio.h> /*标准输入输出定义*/
|
#include <stdlib.h> /*标准函数库定义*/
|
#include <string.h>
|
#include <unistd.h> /*Unix 标准函数定义*/
|
#include <sys/types.h>
|
#include <sys/stat.h>
|
#include <fcntl.h> /*文件控制定义*/
|
#include <termios.h> /*PPSIX 终端控制定义*/
|
#include <errno.h> /*错误号定义*/
|
|
//#define EN_THREAD_WORK_DEBUG
|
#ifdef EN_THREAD_WORK_DEBUG
|
#define THREAD_WORK_DEBUG qDebug
|
#else
|
#define THREAD_WORK_DEBUG(...)
|
#endif
|
|
#define CMD_READ 0x00A0
|
#define CMD_SET_ADDR 0x00A2
|
#define CMD_ADJ_VOL 0x00A3
|
|
|
RS485_WIRED::RS485_WIRED(const char *Dev, int order)
|
{
|
AdjStart = 0;
|
adj_index = 0;
|
adj_vol = 0;
|
adj_addr = 0;
|
AdjStatue = 0;
|
|
memset(battVolData,0x00,sizeof(battVolData));
|
|
Work_Order = order;
|
Work_Num = 0;
|
BattGroup = 0;
|
EachGroupBattSum = 1;
|
EachGroupModule = 1;
|
|
if (-1 == this->OpenDev(Dev))
|
qDebug("Can't Open %s\n", Dev);
|
else qDebug("Open %s OK!\n", Dev);
|
|
this->SetDevAttr(19200, 8,1,'N');
|
|
com_error_count = 200;
|
}
|
|
RS485_WIRED::~RS485_WIRED()
|
{
|
RS485_RUN_EN =false;
|
quit();
|
wait();
|
}
|
|
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
/**
|
*@brief 设置串口通信速率
|
*@param fd 类型 int 打开串口的文件句柄
|
*@param speed 类型 int 串口速度
|
*@return void
|
*/
|
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
static int speed_arr[] = { B115200, B57600, B38400, B19200, B9600};
|
static int name_arr[] = { 115200, 57600, 38400, 19200, 9600};
|
void RS485_WIRED::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 RS485_WIRED::set_Parity(int fd, int databits,int stopbits,int parity)
|
{
|
if(fd < 0)
|
return -1;
|
|
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 'M':
|
case 'm': /**/
|
options.c_cflag |= (PARENB|CMSPAR|PARODD);
|
options.c_iflag |= INPCK;
|
break;
|
case 'S':
|
case 's': /**/
|
options.c_cflag |= (PARENB|CMSPAR);
|
options.c_cflag &= ~PARODD;
|
options.c_iflag |= INPCK;
|
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 RS485_WIRED::OpenDev(const char *Dev)
|
{
|
FD = open(Dev, O_RDWR|O_NOCTTY|O_NDELAY);
|
|
return FD;
|
}
|
//---------------------------------------------------------------------
|
void RS485_WIRED::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 RS485_WIRED::WriteDev(void *buf, int len)
|
{
|
if(FD < 0)
|
return 0;
|
|
return write(FD, (char *)buf, len);
|
}
|
//---------------------------------------------------------------------
|
int RS485_WIRED::ReadDev(void *buf, int len)
|
{
|
if(FD < 0)
|
return 0;
|
|
char *pbuff = (char *)buf;
|
return (read(FD, pbuff, len));
|
}
|
|
bool RS485_WIRED::ReadData(void *RxData, const int RxDataLen)
|
{
|
bool res = true;
|
|
quint16 rx_len = 0;
|
quint8 rx_dat_t = 0;
|
quint16 rx_time_out = 0;
|
quint8 *p_rxdata = (quint8 *)RxData;
|
|
while(RxDataLen > 0)
|
{
|
while(1 == ReadDev(&rx_dat_t, 1))
|
{
|
//qDebug("%x-",rx_dat_t);
|
rx_time_out = 0;
|
if(rx_len < RxDataLen)
|
{
|
p_rxdata[rx_len++] = rx_dat_t;
|
|
if(rx_len >= RxDataLen)
|
break;
|
}
|
else
|
break;
|
|
}
|
|
if(rx_len >= RxDataLen)
|
break;
|
else if(rx_len > 0)
|
{
|
if(rx_time_out > 10)
|
{
|
res = false;
|
break;
|
}
|
}
|
else
|
{
|
//if(rx_time_out > 40)
|
{
|
res = false;
|
break;
|
}
|
}
|
|
rx_time_out++;
|
msleep(5);
|
}
|
|
return res;
|
}
|
|
void RS485_WIRED::ReadWiredData(quint8 Addr)
|
{
|
RFData data_buf;
|
Rx_Data_RF temp;
|
bool read_success = false;
|
|
for(int i=0;i<5;i++)
|
{
|
memset(&data_buf,0,sizeof(data_buf));
|
data_buf.Addr[0] = 0xAB;
|
data_buf.Addr[1] = 0xCD;
|
data_buf.Addr[2] = 0x00;
|
data_buf.Addr[3] = Addr+1;
|
data_buf.CMD = CMD_READ;
|
data_buf.CRC = CRC16::CalCRC16(&data_buf,14);
|
SentAddrData(&data_buf.Addr[3],&data_buf,sizeof(data_buf));
|
|
msleep(80);
|
memset(&data_buf,0,sizeof(data_buf));
|
|
memset(&temp,0,sizeof(temp));
|
|
for(int i=0;i<4;i++)
|
temp.VolData[i] = 20000;
|
|
temp.Addr = Addr+1;
|
|
if(ReadData(&data_buf,sizeof(data_buf)))
|
{
|
if(data_buf.CRC == CRC16::CalCRC16(&data_buf,14))
|
{
|
memcpy(temp.VolData,data_buf.VolData,8);
|
read_success = true;
|
break;
|
}
|
else
|
{
|
THREAD_WORK_DEBUG("addr=%d CRC ERR",Addr+1);
|
}
|
}
|
else
|
{
|
THREAD_WORK_DEBUG("addr=%d read err",temp.Addr);
|
}
|
msleep(80);
|
}
|
ClassXML::set_battVolData(Addr,temp.VolData,battVolData,Work_Order,
|
EachGroupBattSum,EachGroupModule,BattGroup);
|
if(read_success)
|
com_error_count = 0;
|
else
|
{
|
if(com_error_count<200)
|
com_error_count++;
|
}
|
}
|
|
quint8 RS485_WIRED::isOdd(quint8 Addr)
|
{
|
quint8 cnt = 0;
|
/*quint8 cnt1 = 0;
|
for(int i=0;i<8;i++)
|
{
|
if(Addr & (0x01<<i))
|
cnt1++;
|
}*/
|
while(Addr)
|
{
|
Addr &= Addr-1;
|
cnt++;
|
}
|
|
return cnt;
|
}
|
void RS485_WIRED::SentAddrData(quint8 *Addr,void *Data,int Len)
|
{
|
ClearRx();
|
set_Parity(FD,8,1,'M');
|
WriteDev(Addr,1);
|
set_Parity(FD,8,1,'S');
|
WriteDev(Data,Len);
|
|
if(isOdd(*Addr)%2 == 0)
|
set_Parity(FD,8,1,'M');
|
}
|
|
void RS485_WIRED::ClearRx(void)
|
{
|
char tmp[32] = {0};
|
while(1)
|
{
|
int len = ReadDev(tmp, 32);
|
if(len > 0)
|
continue;
|
else break;
|
}
|
}
|
|
void RS485_WIRED::setWorkNum(int num_g,int num_eachm){
|
BattGroup = num_g;
|
EachGroupBattSum = num_eachm;
|
if((EachGroupBattSum%4) == 0)
|
EachGroupModule = EachGroupBattSum/4;
|
else EachGroupModule = EachGroupBattSum/4 + 1;
|
|
Work_Num = EachGroupModule*num_g;
|
}
|
|
void RS485_WIRED::setWorkParam(int param1){
|
//编号顺序、频段
|
Work_Order = param1;
|
memset(battVolData,0x00,sizeof(battVolData));
|
}
|
|
void RS485_WIRED::GetBattVolData(void *data)
|
{
|
memcpy(data,battVolData,sizeof(battVolData));
|
}
|
|
bool RS485_WIRED::if_com_normal()
|
{
|
// qDebug("com_error_count = %d",com_error_count);
|
if(com_error_count<Work_Num)
|
return true;
|
return false;
|
}
|
|
void RS485_WIRED::run()
|
{
|
THREAD_WORK_DEBUG("---RS485_WIRED-run");
|
|
RS485_RUN_EN = true;
|
if(FD < 0)
|
RS485_RUN_EN = false;
|
|
while(RS485_RUN_EN)
|
{
|
if(AdjStart == 0)
|
{
|
for(int maddr=0;maddr<Work_Num;maddr++){
|
ReadWiredData(maddr);
|
}
|
}
|
else if(AdjStart == 1)
|
{
|
AdjMonoVol(adj_index,adj_vol);
|
AdjStart = 0;
|
//ReadWiredData(adj_index/4 + 1);
|
}
|
else if(AdjStart == 2)
|
{
|
AdjMonoAddr(adj_addr);
|
AdjStart = 0;
|
}
|
|
msleep(100);
|
}
|
}
|
|
void RS485_WIRED::setAdjIndex(const quint16 index)
|
{
|
adj_index = index;
|
}
|
void RS485_WIRED::setAdjVol(const quint16 vol)
|
{
|
adj_vol = vol;
|
AdjStart = 1;
|
}
|
void RS485_WIRED::setAddr(const quint16 add)
|
{
|
adj_addr = add;
|
AdjStart = 2;
|
}
|
const quint8 &RS485_WIRED::getAdjStart(void)
|
{
|
return AdjStart;
|
}
|
quint8 RS485_WIRED::getAdjStatue(void)
|
{
|
return AdjStatue;
|
}
|
|
int RS485_WIRED::AdjMonoVol(const quint16 index,const quint16 vol)//单体号index(经过减1)
|
{
|
AdjStatue = -1;
|
quint8 addr_index = ClassXML::getMonModuleAddr(index,EachGroupModule,EachGroupBattSum);//计算单体号对应的模块地址
|
|
if(addr_index >= Work_Num)
|
return AdjStatue;
|
|
RFData data_buf;
|
|
data_buf.Addr[0] = 0xAB;
|
data_buf.Addr[1] = 0xCD;
|
data_buf.Addr[2] = 0x00;
|
data_buf.Addr[3] = addr_index+1;
|
data_buf.CMD = CMD_ADJ_VOL;
|
|
for(int i=0;i<4;i++)
|
data_buf.VolData[i] = 0;
|
|
ClassXML::set_addr_VolData(addr_index,data_buf.VolData,battVolData,Work_Order,EachGroupBattSum,EachGroupModule,BattGroup);
|
|
for(int i=0;i<4;i++)
|
data_buf.VolData[i] = ClassXML::getMonomerVol(MONO_TYPE_WIRED,data_buf.VolData[i]);
|
|
ClassXML::set_adj_vol(addr_index,index,data_buf.VolData,vol,
|
Work_Order,EachGroupBattSum,EachGroupModule);
|
|
data_buf.CRC = CRC16::CalCRC16(&data_buf,14);
|
SentAddrData(&data_buf.Addr[3],&data_buf,sizeof(data_buf));
|
|
//for(int i=0;i<16;i++)
|
// qDebug("0x%x",*((char *)&data_buf + i));
|
|
msleep(80);
|
memset(&data_buf,0,sizeof(data_buf));
|
|
Rx_Data_RF temp;
|
memset(&temp,0,sizeof(temp));
|
temp.Addr = addr_index+1;
|
|
if(ReadData(&data_buf,sizeof(data_buf)))
|
{
|
if(data_buf.CRC == CRC16::CalCRC16(&data_buf,14))
|
{
|
memcpy(temp.VolData,data_buf.VolData,8);
|
AdjStatue = 0;
|
//AddDataTemp(temp);
|
THREAD_WORK_DEBUG("addr=%d-%d-%d-%d-%d",temp.Addr,temp.VolData[0],temp.VolData[1],temp.VolData[2],temp.VolData[3]);
|
}
|
else
|
{
|
AdjStatue = -1;
|
THREAD_WORK_DEBUG("ReadWiredData CRC ERR");
|
}
|
}
|
else
|
{
|
AdjStatue = -1;
|
THREAD_WORK_DEBUG("adj addr=%d read err",temp.Addr);
|
}
|
|
//for(int i=0;i<16;i++)
|
// qDebug("0x%x",*((char *)&data_buf + i));
|
|
return AdjStatue;
|
}
|
int RS485_WIRED::AdjMonoAddr(const quint8 Addr)
|
{
|
AdjStatue = 0;
|
|
RFData data_buf;
|
|
data_buf.Addr[0] = 0xAB;
|
data_buf.Addr[1] = 0xCD;
|
data_buf.Addr[2] = 0x00;
|
data_buf.Addr[3] = 0x00;
|
data_buf.CMD = CMD_SET_ADDR;
|
data_buf.VolData[0] = 0xCDAB;
|
data_buf.VolData[1] = Addr<<8;
|
data_buf.VolData[2] = 0x00;
|
data_buf.VolData[3] = 0x00;
|
|
data_buf.CRC = CRC16::CalCRC16(&data_buf,14);
|
SentAddrData(&data_buf.Addr[3],&data_buf,sizeof(data_buf));
|
|
//for(int i=0;i<16;i++)
|
// qDebug("0x%x",*((char *)&data_buf + i));
|
|
msleep(80);
|
memset(&data_buf,0,sizeof(data_buf));
|
|
if(ReadData(&data_buf,sizeof(data_buf)))
|
{
|
if(data_buf.CRC == CRC16::CalCRC16(&data_buf,14))
|
{
|
if(data_buf.CMD == CMD_SET_ADDR && data_buf.Addr[3] == Addr)
|
{
|
if(Addr>=1){ //数据清零
|
Rx_Data_RF temp;
|
memset(&temp,0,sizeof(temp));
|
temp.Addr = Addr;
|
ClassXML::set_battVolData(Addr-1,temp.VolData,battVolData,Work_Order,
|
EachGroupBattSum,EachGroupModule,BattGroup);
|
}
|
}
|
}
|
else
|
{
|
AdjStatue = -1;
|
THREAD_WORK_DEBUG("ReadWiredData CRC ERR");
|
}
|
}
|
else
|
{
|
AdjStatue = -1;
|
THREAD_WORK_DEBUG("adj addr=%d read err",Addr);
|
}
|
|
//for(int i=0;i<16;i++)
|
// qDebug("0x%x",*((char *)&data_buf + i));
|
|
return AdjStatue;
|
}
|