476 lines
16 KiB
C++
476 lines
16 KiB
C++
|
#include "modbushandler.h"
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#define REQ_PERIOD 50 //прериод опроса
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
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;
|
|||
|
|
|||
|
qDebug()<<"Приборов в списке "<<PriborMap.size();
|
|||
|
|
|||
|
|
|||
|
for(PrborConnectonAtr atr:PriborMap){
|
|||
|
getDataFromPribor(atr);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/////это всё тлен и плюсы
|
|||
|
//делаем итератор где то наверху
|
|||
|
//обновляем количество элементов
|
|||
|
//проверяем, если элемент последний, то в начало
|
|||
|
//если нет то ++
|
|||
|
//делаем запрос. - он у нас раз в 300 мс, типа успеет отработать. Ну должен успеть
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void ModBusHandler::addToReqList(PrborConnectonAtr pribor)
|
|||
|
{
|
|||
|
PriborMap.insert(pribor.adress, pribor);
|
|||
|
}
|
|||
|
|
|||
|
void ModBusHandler::removeFromReqList(uint adress)
|
|||
|
{
|
|||
|
PriborMap.remove(adress);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void ModBusHandler::getDataFromPribor(PrborConnectonAtr atr) //слот для истекшего таймера
|
|||
|
{
|
|||
|
{
|
|||
|
modbusDevice->setConnectionParameter(QModbusDevice::SerialPortNameParameter, QVariant(atr.port));
|
|||
|
modbusDevice->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, QSerialPort::OneStop);
|
|||
|
modbusDevice->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, QSerialPort::Data8);
|
|||
|
modbusDevice->setTimeout(100); //1 таймаута
|
|||
|
modbusDevice->setNumberOfRetries(1);// попытки достучатся
|
|||
|
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(stateIsRecived&&stateIsRecived){
|
|||
|
|
|||
|
//connect(this,SIGNAL(dataRecivedNotify(DataStruct)),parent(),SLOT(dataSetter(DataStruct)));
|
|||
|
emit dataRecivedNotify(data);
|
|||
|
// qDebug()<<"Должен проити эмит";
|
|||
|
stateIsRecived=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() << "уууууууу";
|
|||
|
} 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->setTimeout(30); //1 таймаута
|
|||
|
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 (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)
|
|||
|
{
|
|||
|
|
|||
|
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*
|
|||
|
|
|||
|
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);
|
|||
|
|
|||
|
|
|||
|
}
|