A1210_Desktop/modbushandler.cpp

517 lines
17 KiB
C++
Raw Normal View History

#include "modbushandler.h"
#define REQ_PERIOD 1000 //прериод опроса
#define TIMEOUT 120
ModBusHandler::ModBusHandler(QObject *parent) : QObject(parent)
{
2023-12-13 14:34:51 +03:00
modbusDevice = new QModbusRtuSerialClient;
//заводим таймер
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);
2023-12-13 14:34:51 +03:00
//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);
}
}