A1210_Desktop/modbushandler.cpp

517 lines
17 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#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);
}
}