Тестер для обнуления регистров Modbus (QT)

Монтажники устали обнулять значения через Modbus Poll, устройств очень много ...
Попросили накидать програмку которая бы проверяла ID, выводила список ответивших и записывала в указанные регистры — указанные значения.

Времени было жалко, нашел в ./Examples Qt готовый терминал для SerialPort, немного обстругал и видоизменил )
Принцип прост как мычание:
— терминал отправляет запрос на чтение с адреса 0x0000, 2 байта
— далее следует указанная в параметрах пауза
— если ответа нет, вердикт — ID не ответил
если ответил — проверяется CRC и если все правильно, далее отправляется пакет на «мультизапись» с указанными параметрами.

Все работает в одном методе:

void MainWindow::ModHandler(void)
{
    switch(PollStatus)
    {
        case POLL_STATUS_STOP: break;
        case POLL_STATUS_POLL:
            if(SelectedID < ui->EditcountID->text().toInt())
            {
                SelectedID ++;
                serial->clear();
                /* запрос на чтение */
                ModRequest();
                PollStatus = POLL_STATUS_RECIVE;
            }
            else
            {
                /* Цикл завершен, стоп */
                PollStatus = POLL_STATUS_STOP;
            }
       break;
       case POLL_STATUS_RECIVE:
            if(ReadPacketData()==0)
            {
                /* нет ответа */
                ui->textEdit->insertPlainText("Reply ERROR, ID - ");
                ui->textEdit->insertPlainText(QString::number(SelectedID,10)+"\r\n");
                ui->textEdit->moveCursor(QTextCursor::End);
            }
            PollStatus = POLL_STATUS_POLL;
       break;
   }
}

Так формируется запрос на чтение, он крайне прост:

void MainWindow::ModRequest(void)
{
    QByteArray DataTx;
    int i =0;
    quint16 crc;
    DataTx[i++] = SelectedID;
    DataTx[i++] = POLL_READ;
    DataTx[i++] = POLL_ADDRESS_L;
    DataTx[i++] = POLL_ADDRESS_H;
    DataTx[i++] = POLL_LENG_L;
    DataTx[i++] = POLL_LENG_H;
    crc = getCRC(DataTx, i);
    DataTx[i++] = crc & 0x00FF;
    DataTx[i++] = (crc & 0xFF00)>>8;
    serial->write(DataTx);
}

Прием ответа:

int MainWindow::ReadPacketData()
{
    quint16 LengPack;
    /* Отсеиваем мусор, мало ли */
    if((serial->size()>50)||(serial->size()==0))
    {
        return 0;
    }
    QByteArray DataTXRX = serial->readAll();
    /* Длина данных */
    LengPack = DataTXRX[2];

    quint16 crc = getCRC(DataTXRX, LengPack + 3);
    if(((crc & 0x00FF)==(0x000000FF & DataTXRX[LengPack+3]))&&((crc & 0xFF00)>>8)== (0x000000FF & DataTXRX[LengPack+4]))
    {
        /* вывод результатов */
        ui->textEdit->insertPlainText("Reply ");
        ui->textEdit->setTextColor("red");
        ui->textEdit->insertPlainText("Ok, ID - ");
        ui->textEdit->setTextColor("black");
        ui->textEdit->insertPlainText(QString::number(SelectedID,10));
        QString tempstring = "0x";
        /* данные начинаются с третьего байта, после ID, заголовка и кода команды */
        for(int i=0; i<LengPack+3;i++)
        {
            tempstring = tempstring + "-" + QString::number(DataTXRX[i],16);
        }
        ui->textEdit->insertPlainText(" (" + tempstring + ")" + "\r\n");
        ui->textEdit->moveCursor(QTextCursor::End);

        /* Тут же формируется пакет на мультизацись в регистры */
        DataTXRX[0]=SelectedID;
        /* Function code */
        DataTXRX[1]= 0x10;
        quint16 temp;
        temp = ui->EditReg->text().toInt();
        /* Starting Address */
        DataTXRX[2]=  temp & 0x00FF;
        DataTXRX[3]=  (temp & 0xFF00)>>8;
        temp = ui->EditLeng->text().toInt();
        /* Quantity of Registers */
        DataTXRX[5]=  temp & 0x00FF;
        DataTXRX[4]=  (temp & 0xFF00)>>8;
        /* Byte Count */
        DataTXRX[6]=  (temp*2) & 0x00FF;
        /* Get Data */
        int couReg=7;
        quint16 data = ui->EditData->text().toInt();
        for(int a=0;a<temp;a++)
        {
            DataTXRX[couReg++]=  (data & 0xFF00)>>8;
            DataTXRX[couReg++]=  (data & 0x00FF);
        }
        crc = getCRC(DataTXRX, couReg);
        DataTXRX[couReg++] =crc & 0x00FF;
        DataTXRX[couReg++]=(crc & 0xFF00)>>8;
        serial->write(DataTXRX,couReg);

        ui->textEdit->insertPlainText("CLEARED ... ");
        ui->textEdit->setTextColor("red");
        ui->textEdit->insertPlainText(QString::number(temp,10)+" Bytes");
        ui->textEdit->insertPlainText(", Ok, ID - ");
        ui->textEdit->setTextColor("black");
        ui->textEdit->insertPlainText(QString::number(SelectedID,10));
        tempstring = "0x";
        for(int i=0; i<LengPack+3;i++)
        {
            tempstring = tempstring + "-" + QString::number(DataTXRX[i],16);
        }
        ui->textEdit->insertPlainText(" (" + tempstring + ")" + "\r\n");
        ui->textEdit->moveCursor(QTextCursor::End);
        return 1;
    }
    return 0;
}


Некоторое время я протупил пытаясь разобраться — отчего не получается с записью,
но документация все прояснила:



в действии, до:

процесс:

после:

в идеале наверно стоит дописать контроль ответа на запись, в случае не ответа — сколько то попыток повторить запись.
вот нужно ли это ..?
  • +5
  • 05 сентября 2014, 17:25
  • khomin
  • 1
Файлы в топике: v0.zip

Комментарии (4)

RSS свернуть / развернуть
проект прикреплен
0
У меня как раз было жедание накидать что-то подобное. Вердикт: нужно.
0
  • avatar
  • dekar
  • 05 сентября 2014, 20:22
Некоторое время я протупил пытаясь разобраться — отчего не получается с записью,
И отчего же?
0
  • avatar
  • Vga
  • 05 сентября 2014, 22:53
у меня было неверное представление, думал длина указывается в 2-х байтах, оказалось одним )
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.