517 lines
17 KiB
C++
517 lines
17 KiB
C++
#include "modbushandler.h"
|
||
|
||
|
||
|
||
|
||
|
||
#define REQ_PERIOD 1000 //прериод опроса
|
||
|
||
#define TIMEOUT 120
|
||
|
||
|
||
|
||
|
||
ModBusHandler::ModBusHandler(QObject *parent) : QObject(parent)
|
||
{
|
||
modbusDevice = new QModbusRtuSerialMaster;
|
||
//заводим таймер
|
||
|
||
tmr = new QTimer();
|
||
tmr->start(REQ_PERIOD);
|
||
connect(tmr, SIGNAL(timeout()), this, SLOT(requestPriborFromList()));
|
||
|
||
// 2. Если вы находитесь в состоянии соединения, отключите соединение
|
||
if (modbusDevice->state() == QModbusDevice::ConnectedState)
|
||
{
|
||
// отключимся если вдруг подключено
|
||
modbusDevice->disconnectDevice();
|
||
|
||
|
||
}
|
||
}
|
||
|
||
ModBusHandler::~ModBusHandler()
|
||
{
|
||
if (modbusDevice)
|
||
{
|
||
modbusDevice->disconnectDevice();
|
||
}
|
||
|
||
delete modbusDevice;
|
||
|
||
}
|
||
|
||
|
||
void ModBusHandler::requestPriborFromList() //слот для истекшего таймера
|
||
{
|
||
//пробегаемся по листу и опрашиваем выкидываая сигналы
|
||
|
||
//static uint numForReqest;
|
||
//QMap<uint,PrborConnectonAtr>::iterator iteratorPriborMap;
|
||
|
||
// qDebug()<<"Приборов в списке "<<PriborMap.size();
|
||
|
||
|
||
for(PrborConnectonAtr atr:PriborMap){
|
||
getDataFromPribor(atr);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
void ModBusHandler::addToReqList(PrborConnectonAtr pribor)
|
||
{
|
||
PriborMap.insert(pribor.adress, pribor);
|
||
}
|
||
|
||
void ModBusHandler::removeFromReqList(uint adress)
|
||
{
|
||
PriborMap.remove(adress);
|
||
|
||
}
|
||
|
||
|
||
void ModBusHandler::getDataFromPribor(PrborConnectonAtr atr) //слот для истекшего таймера
|
||
{
|
||
{
|
||
// modbusDevice->disconnectDevice();
|
||
|
||
modbusDevice->setConnectionParameter(QModbusDevice::SerialPortNameParameter, QVariant(atr.port));
|
||
modbusDevice->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, QSerialPort::OneStop);
|
||
modbusDevice->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, QSerialPort::Data8);
|
||
modbusDevice->setTimeout(TIMEOUT); //1 таймаута
|
||
modbusDevice->setNumberOfRetries(0);// попытки достучатся
|
||
modbusDevice->setConnectionParameter(QModbusDevice::SerialBaudRateParameter, atr.speed);
|
||
switch (atr.parity) {//выставляем парити
|
||
case UART_PARITY_NONE:
|
||
modbusDevice->setConnectionParameter(QModbusDevice::SerialParityParameter, QSerialPort::NoParity);
|
||
break;
|
||
|
||
case UART_PARITY_ODD:
|
||
modbusDevice->setConnectionParameter(QModbusDevice::SerialParityParameter, QSerialPort::OddParity);
|
||
break;
|
||
|
||
case UART_PARITY_EVEN:
|
||
modbusDevice->setConnectionParameter(QModbusDevice::SerialParityParameter, QSerialPort::EvenParity);
|
||
break;
|
||
}
|
||
}
|
||
modbusDevice->connectDevice(); //подключаемся!!!
|
||
isConnected = true;
|
||
|
||
readCoils(atr.adress, 5001, 11);
|
||
|
||
|
||
readCoils(atr.adress, 7004, 2);
|
||
|
||
|
||
}
|
||
|
||
void ModBusHandler::onReadReady()
|
||
{
|
||
auto reply = qobject_cast<QModbusReply*>(sender());
|
||
if (nullptr == reply)
|
||
{
|
||
return;
|
||
}
|
||
|
||
// определить, есть ли ошибка
|
||
if (reply->error() == QModbusDevice::NoError)
|
||
{
|
||
// Читать данные ответа
|
||
//qDebug() << "адрес ответа"<<reply->serverAddress();
|
||
const QModbusDataUnit responseData = reply->result();
|
||
// qDebug() << responseData.values(); //отсюда летит ответ
|
||
dataCollector(reply->serverAddress(),responseData.values());
|
||
}
|
||
else if (reply->error() == QModbusDevice::ProtocolError)
|
||
{
|
||
qDebug() << "Read response Protocol error: " << reply->errorString();
|
||
}
|
||
else
|
||
{
|
||
qDebug() << "Read response Error: " << reply->errorString();
|
||
}
|
||
isWaitingResponse=false;
|
||
reply->deleteLater();
|
||
}
|
||
|
||
|
||
|
||
void ModBusHandler::readCoils(uint16_t adress, uint16_t startCoil, uint16_t numCoil)
|
||
{
|
||
if(isWaitingResponse){
|
||
}
|
||
QModbusDataUnit data(QModbusDataUnit::HoldingRegisters, startCoil, numCoil);
|
||
QModbusReply* reply = modbusDevice->sendReadRequest(data, adress); //указатель куда складывать// адрес клиента
|
||
if (nullptr == reply)
|
||
{
|
||
qDebug() << "Отправка данных запроса не удалась:" << modbusDevice->errorString();
|
||
}
|
||
else
|
||
{
|
||
if (!reply->isFinished()) //если сразу не получилось
|
||
{// то создадим коннект
|
||
if(isWaitingResponse){
|
||
|
||
}
|
||
isWaitingResponse=1;
|
||
|
||
connect(reply, &QModbusReply::finished, this, &ModBusHandler::onReadReady);
|
||
}
|
||
else
|
||
{
|
||
if (reply->error() == QModbusDevice::NoError) //если без ошибок
|
||
{
|
||
// Читать данные ответа
|
||
qDebug() << "адрес ответа"<<reply->serverAddress();
|
||
const QModbusDataUnit responseData = reply->result();
|
||
dataCollector(reply->serverAddress(), responseData.values());
|
||
qDebug() << responseData.values();
|
||
|
||
|
||
}
|
||
else if (reply->error() == QModbusDevice::ProtocolError)
|
||
{
|
||
qDebug() << "Read response Protocol error: " << reply->errorString();
|
||
}
|
||
else
|
||
{
|
||
qDebug() << "Read response Error: " << reply->errorString();
|
||
}
|
||
|
||
//Парсим ответ по структуре или пока выведем в дебаг
|
||
isWaitingResponse=false;
|
||
delete reply;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
void ModBusHandler::dataCollector(quint16 adress, QVector<quint16>recivedData)
|
||
{
|
||
static bool sensIsRecived;
|
||
static bool stateIsRecived;
|
||
static DataStruct data;
|
||
data.adress=adress;
|
||
if (recivedData.size()==2){
|
||
usfloat result;
|
||
|
||
result.sh[0]=recivedData[1];
|
||
result.sh[1]=recivedData[0];
|
||
|
||
data.sens= result.fl;
|
||
sensIsRecived=1;
|
||
};
|
||
|
||
if (recivedData.size()==11){
|
||
data.in=(typeIIN)recivedData[0];
|
||
data.fv=(typeIFV)recivedData[1];
|
||
data.fn=(typeIFN)recivedData[2];
|
||
data.ku=(typeIKU)recivedData[3];
|
||
data.unit=(typeUnit)recivedData[9];
|
||
data.overload=(typeOverload)recivedData[10];
|
||
data.pz=(typePlavGround)recivedData[7];
|
||
stateIsRecived=1;
|
||
};
|
||
if(sensIsRecived&&stateIsRecived){
|
||
|
||
//connect(this,SIGNAL(dataRecivedNotify(DataStruct)),parent(),SLOT(dataSetter(DataStruct)));
|
||
emit dataRecivedNotify(data);
|
||
// qDebug()<<"Должен проити эмит";
|
||
sensIsRecived=0;
|
||
stateIsRecived=0;
|
||
}
|
||
}
|
||
|
||
// Входные параметры: startAddress - адрес первого элемента, count - количество элементов (1 или более).
|
||
QModbusDataUnit ModBusHandler::writeRequest(int startAddress, int count) const {
|
||
return QModbusDataUnit(QModbusDataUnit::HoldingRegisters, startAddress, count);
|
||
}
|
||
|
||
|
||
// Входные параметры: startAddress - адрес первого элемента, count - количество элементов (1 или более).
|
||
void ModBusHandler::prepareWrite(uint16_t adress, int startAddress, int count, QVector<uint16_t> values) {
|
||
if(!modbusDevice) return;
|
||
QModbusDataUnit writeUnit = writeRequest(startAddress, count);
|
||
writeUnit.setValues(values);
|
||
if(auto *lastRequest = modbusDevice->sendWriteRequest(writeUnit, adress)) {
|
||
if(!lastRequest->isFinished()) {
|
||
connect(lastRequest, &QModbusReply::finished, this, [this, lastRequest]() {
|
||
if(lastRequest->error() == QModbusDevice::ProtocolError) {
|
||
qDebug() << "ошибка протокола";
|
||
} else if(lastRequest->error() == QModbusDevice::TimeoutError) {
|
||
qDebug() << "таймаут";
|
||
} else if (lastRequest->error() != QModbusDevice::NoError) {
|
||
qDebug() << "Какая то ошибка";
|
||
qDebug() << lastRequest->rawResult();
|
||
} else if(lastRequest->error() == QModbusDevice::NoError) {
|
||
qDebug() << "успех)";
|
||
}
|
||
emit writeResult(lastRequest->error()); // сигналим о завершении операции
|
||
lastRequest->deleteLater();
|
||
qDebug() << "первый deleteLater";
|
||
});
|
||
} else {
|
||
lastRequest->deleteLater();
|
||
qDebug() << "второй deleteLater";
|
||
}
|
||
|
||
} else {
|
||
qDebug()<<"Ошибка записи: " + modbusDevice->errorString();
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
void ModBusHandler::scanAdressSignalChain(uint16_t adrToScan)
|
||
{
|
||
if(adrToScan<=247){// делаем запрос
|
||
{
|
||
|
||
isConnected = true;
|
||
|
||
QModbusDataUnit data(QModbusDataUnit::HoldingRegisters, 5001, 11); // формируем пакет на отправку
|
||
QModbusReply* reply = modbusDevice->sendReadRequest(data, adrToScan);
|
||
if (nullptr == reply)
|
||
{
|
||
qDebug() << "Отправка данных запроса не удалась:";
|
||
}
|
||
else
|
||
{
|
||
if (!reply->isFinished()) //
|
||
{
|
||
connect(reply, &QModbusReply::finished, this, &ModBusHandler::ScanPortOnReadReady);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
scanPort();//переделать на сигнал иначе стэк может охуеть с такого фокуса
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
void ModBusHandler::scanPort(QString port){
|
||
modbusDevice->setConnectionParameter(QModbusDevice::SerialPortNameParameter, QVariant(port));
|
||
modbusDevice->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, QSerialPort::OneStop);
|
||
modbusDevice->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, QSerialPort::Data8);
|
||
|
||
|
||
modbusDevice->setNumberOfRetries(0);// попытки достучатся
|
||
|
||
scanPort();
|
||
}
|
||
|
||
|
||
void ModBusHandler::scanPort() //принимает сигнал о завершенных адресах
|
||
{
|
||
|
||
// static uint s;//статик скорость // перенес в глобальные
|
||
// static uint b;//статик бит // перенес в глобальные
|
||
|
||
if(isScanning==0){s=0; b=0; isScanning=1;}//если новое новое сканирование обнуляем переменные
|
||
|
||
qDebug()<<"Скорость"<<BAUDRATE[s];
|
||
qDebug()<<"Бит"<<b;
|
||
|
||
if(b>=3){ //если инкрементится некуда
|
||
emit priborNotFounded();
|
||
s=0;
|
||
b=0;
|
||
isScanning=0;
|
||
return;}
|
||
|
||
|
||
modbusDevice->disconnectDevice();//отключавемся
|
||
modbusDevice->setConnectionParameter(QModbusDevice::SerialBaudRateParameter, BAUDRATE[s]);
|
||
|
||
switch (BAUDRATE[s]) {//выставляем парити
|
||
case 4800:
|
||
modbusDevice->setTimeout(120); //1 таймаута
|
||
break;
|
||
|
||
case 7200:
|
||
modbusDevice->setTimeout(90); //1 таймаута
|
||
break;
|
||
|
||
case 9600:
|
||
modbusDevice->setTimeout(80); //1 таймаута
|
||
break;
|
||
|
||
case 14400:
|
||
modbusDevice->setTimeout(70); //1 таймаута
|
||
break;
|
||
|
||
case 19200:
|
||
modbusDevice->setTimeout(60); //1 таймаута
|
||
break;
|
||
|
||
case 38400:
|
||
modbusDevice->setTimeout(50); //1 таймаута
|
||
break;
|
||
|
||
case 57600:
|
||
modbusDevice->setTimeout(40); //1 таймаута
|
||
break;
|
||
|
||
case 115200:
|
||
modbusDevice->setTimeout(30); //1 таймаута
|
||
break;
|
||
|
||
case 128000:
|
||
modbusDevice->setTimeout(30); //1 таймаута
|
||
break;
|
||
|
||
default:
|
||
qDebug()<< "пролет свитча с таймаутом";
|
||
break;
|
||
|
||
}
|
||
|
||
switch (b) {//выставляем парити
|
||
case UART_PARITY_NONE:
|
||
modbusDevice->setConnectionParameter(QModbusDevice::SerialParityParameter, QSerialPort::NoParity);
|
||
break;
|
||
|
||
case UART_PARITY_ODD:
|
||
modbusDevice->setConnectionParameter(QModbusDevice::SerialParityParameter, QSerialPort::OddParity);
|
||
break;
|
||
|
||
case UART_PARITY_EVEN:
|
||
modbusDevice->setConnectionParameter(QModbusDevice::SerialParityParameter, QSerialPort::EvenParity);
|
||
break;
|
||
}
|
||
modbusDevice->connectDevice(); //подключаемся
|
||
|
||
//фор меняем на отдельную функцию-слот работающую по сигналам
|
||
//меняем на отдельную функцию вопрошающиую всех по сигналам.
|
||
// если вернулся сигнал со значением 247 она вызывает снова сканпорт
|
||
|
||
scanAdressSignalChain(1);
|
||
|
||
//инкрементим скорость и/или бит
|
||
if(s<9) s++; //если s меньше крайнего значения индекса массива скоростей
|
||
else{s=0; b++;}
|
||
|
||
|
||
|
||
}//конец функции сканпорт
|
||
|
||
|
||
|
||
|
||
void ModBusHandler::ScanPortOnReadReady()
|
||
{
|
||
auto reply = qobject_cast<QModbusReply*>(sender());
|
||
if (nullptr == reply)
|
||
{
|
||
return;
|
||
}
|
||
|
||
// определить, есть ли ошибка
|
||
if (reply->error() == QModbusDevice::NoError)
|
||
{
|
||
|
||
//когда нашел прибор
|
||
const QModbusDataUnit responseData = reply->result();
|
||
qDebug() <<reply->serverAddress()<<"прибор грит"<< responseData.values(); //отсюда летит ответ
|
||
disconnect(this, SIGNAL(scanPlease(uint16_t)), this,SLOT(scanAdressSignalChain(uint16_t))); //рвем коннект цепочки ответ-запрос на всякий
|
||
isScanning =0;
|
||
emit priborFounded(reply->serverAddress(),s,b); // передаем сигнал с настройками прибора в окно
|
||
modbusDevice->disconnectDevice();
|
||
//не забудь закрыть соединение
|
||
}
|
||
|
||
else{
|
||
//Когда не нашел прибор но пытаешься еще
|
||
connect(this, SIGNAL(scanPlease(uint16_t)),SLOT(scanAdressSignalChain(uint16_t)));
|
||
emit scanPlease((reply->serverAddress()+1)); //
|
||
emit progressUpToStatusBar(1);
|
||
disconnect(this, SIGNAL(scanPlease(uint16_t)), this,SLOT(scanAdressSignalChain(uint16_t)));
|
||
}
|
||
|
||
reply->deleteLater();
|
||
|
||
|
||
}
|
||
|
||
|
||
void ModBusHandler::writeConnectionAttr(PrborConnectonAtr oldAtr,PrborConnectonAtr newAtr){
|
||
|
||
modbusDevice->setConnectionParameter(QModbusDevice::SerialPortNameParameter, QVariant(oldAtr.port));
|
||
modbusDevice->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, QSerialPort::OneStop);
|
||
modbusDevice->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, QSerialPort::Data8);
|
||
modbusDevice->setTimeout(100); //1 таймаута
|
||
modbusDevice->setNumberOfRetries(1);// попытки достучатся
|
||
modbusDevice->setConnectionParameter(QModbusDevice::SerialBaudRateParameter, oldAtr.speed);
|
||
switch (oldAtr.parity) {//выставляем парити
|
||
case UART_PARITY_NONE:
|
||
modbusDevice->setConnectionParameter(QModbusDevice::SerialParityParameter, QSerialPort::NoParity);
|
||
break;
|
||
|
||
case UART_PARITY_ODD:
|
||
modbusDevice->setConnectionParameter(QModbusDevice::SerialParityParameter, QSerialPort::OddParity);
|
||
break;
|
||
|
||
case UART_PARITY_EVEN:
|
||
modbusDevice->setConnectionParameter(QModbusDevice::SerialParityParameter, QSerialPort::EvenParity);
|
||
break;
|
||
}
|
||
|
||
modbusDevice->connectDevice(); //подключаемся!!!
|
||
|
||
QVector <uint16_t> dataValues(3);
|
||
dataValues={
|
||
dataValues[0]=newAtr.adress,
|
||
dataValues[2]=newAtr.parity,
|
||
};
|
||
|
||
for (int i=0; i<10; i++){ //todo: выкинуть палки-шишки - скорость в структуре как значениеб а передавать нужно индекс массива. Будь умничкой и сделай всё хорошо.
|
||
if(BAUDRATE[i]==newAtr.speed) dataValues[1]=i; //dataValues[один]
|
||
|
||
};
|
||
prepareWrite(oldAtr.adress, 4001, 3, dataValues);
|
||
|
||
|
||
}
|
||
|
||
|
||
|
||
void ModBusHandler::writeDataToPribor(DataStruct datastruct, typeReq type)
|
||
{
|
||
|
||
if(type==SENS_REQ_TYPE){
|
||
usfloat floated;
|
||
floated.fl = datastruct.sens;
|
||
QVector <uint16_t> floatedQVector(2);
|
||
floatedQVector[0]=floated.sh[1];
|
||
floatedQVector[1]=floated.sh[0];
|
||
prepareWrite(datastruct.adress, 7004, 2, floatedQVector);//7004*
|
||
}
|
||
|
||
if(type==STATE_REQ_TYPE){
|
||
QVector <uint16_t> dataValues(10);
|
||
dataValues={
|
||
dataValues[0]=datastruct.in,
|
||
dataValues[1]=datastruct.fv,
|
||
dataValues[2]=datastruct.fn,
|
||
dataValues[3]=datastruct.ku,
|
||
dataValues[4]=0,
|
||
dataValues[5]=0,
|
||
dataValues[6]=0,
|
||
dataValues[7]=datastruct.pz,
|
||
dataValues[8]=0,
|
||
dataValues[9]=datastruct.unit,
|
||
// dataValues[10]=datastruct.overload,
|
||
};
|
||
prepareWrite(datastruct.adress, 5001, 10, dataValues);
|
||
}
|
||
|
||
}
|