9 #include <QCoreApplication>
12 #include <QStringList>
19 for (int i=0; i<x.size(); i++) { \
20 str << QString("%1").arg( (quint8) x[i], 2, 16, QChar('0')); \
22 qDebug() << str.join(" "); \
26 MODBUSTCP::~MODBUSTCP() {
52 qDebug() <<
"MODBUSTCP::slotInit()" <<
this;
53 m_timer =
new QTimer(
this);
54 m_timer->setInterval(10);
55 m_timer->setSingleShot(
true);
56 connect(m_timer, SIGNAL(timeout()),
62 SOCKETLIST->open(
m_line.line);
63 }
catch (QString e) {};
67 void MODBUSTCP::slotQuit() {
109 tr(
"Sleeping %1 secs to begin new reading cycle").arg(secs)
111 m_timer->setInterval(secs*1000);
120 tr(
"Going to read next invertor")
122 m_timer->setInterval(10);
129 void MODBUSTCP::readInvertor() {
140 qDebug() <<
"MODBUSTCP::readInvertor()" << e;
143 }
catch (QString e) {};
149 #define CLEANSOCKET() { \
151 socket->waitForReadyRead(m_line.timeout/10); \
156 QByteArray MODBUSTCP::readModbus(
const DBT_INVERTORS& invertor, quint16 regaddress, quint16 regcnt, quint16 expectedLength) {
158 QTcpSocket *socket = SOCKETLIST->socket(invertor.line);
159 quint8 unitid = invertor.address;
161 quint8 *f = (quint8 *)(&m_frameid);
162 quint8 *l = (quint8 *)(&length);
163 quint16 reg = regaddress - 1;
174 cmd[8] = (reg >> 8) & 0xff;
176 cmd[10] = (regcnt >> 8) & 0xff;
177 cmd[11] = regcnt & 0xff;
181 qDebug() <<
"zapis povelu do TCP address" << invertor.address <<
"frameid" << m_frameid;
183 setStatus(invertor.address, 0, QString(), tr(
"Writing data to TCP socket"));
184 if (!socket->waitForBytesWritten(1000)) {
185 throw tr(
"Could not write data to %1").arg(
m_line.hostname);
187 qDebug() <<
"zapsano";
190 for (
int trynumber=0; trynumber <= 5; trynumber++) {
191 qDebug() <<
"cteni z TCP";
192 setStatus(invertor.address, 0, QString(), tr(
"Reading data from TCP socket"));
194 if (!socket->waitForReadyRead(
m_line.timeout)) {
196 throw tr(
"Could not read data from %1").arg(
m_line.hostname);
200 QTimer::singleShot(100, &loop, SLOT(
quit()));
203 rec = socket->readAll();
204 qDebug() <<
"precteno" << rec.size();
206 uint rtcode =
static_cast<uint
>(rec[7]);
207 if (rec.size() == 9 && rtcode == 0x83) {
209 int exceptionCode = (int)rec[8];
210 QString exceptionText = tr(
"Modbus protocol exception: 0x83 0x%1 %2")
211 .arg(exceptionCode, 2, 16, QChar(
'0'))
212 .arg(exceptionCodeToString(exceptionCode))
214 qDebug() << exceptionText;
218 if (rec.size() < expectedLength) {
221 throw tr(
"Bad response: read %1 bytes, expected: %2 bytes").arg(rec.size()).arg(expectedLength);
224 int fid = (int)((
unsigned char)rec[0]) * 256
225 + (
int)((
unsigned char)rec[1]);
226 if (fid != m_frameid && trynumber++ < 5 ) {
227 qDebug() <<
"pozadovana adresa" << m_frameid <<
"vracena adresa" << fid;
232 if (trynumber >= 5) {
234 throw tr(
"Bad response: frame id received differs from frame id sent");
240 setStatus(invertor.address, 0, QString(), tr(
"Decoding data read from TCP socket"));
243 throw tr(
"Bad response: unexpected unit id: %1, expected: %2").arg(uid).arg(unitid);
252 void MODBUSTCP::readInvertorInfo(
const DBT_INVERTORS& invertor) {
253 qDebug() <<
"MODBUSTCP::readInvertorInfo() invertor line address: " << invertor.line << invertor.invertor << invertor.address;
257 QByteArray rec = readModbus(invertor,
261 int errcode = integer16(rec, 9);
262 qDebug() <<
"Invertor status:" << errcode << stateToString(errcode);
266 for (
int i=0; i<3; i++) {
267 rec = readModbus(invertor,
271 istatus = integer16(rec, 103);
272 if (istatus != 7) {
break; }
273 if (errcode != 0) {
break; }
278 bool working =
false;
280 case 1: working =
false; status =
"OFF";
break;
281 case 2: working =
false; status =
"SLEEPING";
break;
282 case 3: working =
false; status =
"STARTING";
break;
283 case 4: working =
true; status =
"MPPT";
break;
284 case 5: working =
true; status =
"THROTTLED";
break;
285 case 6: working =
false; status =
"SHUTTING_DOWN";
break;
286 case 7: working =
false; status =
"FAULT";
break;
287 case 8: working =
false; status =
"STANDBY";
break;
288 case 9: working =
false; status =
"NO_BUSINIT";
break;
289 case 10: working =
false; status =
"NO_COMM_INV";
break;
290 case 11: working =
false; status =
"SN_OVERCURRENT";
break;
291 case 12: working =
false; status =
"BOOTLOAD";
break;
292 case 13: working =
false; status =
"AFCI";
break;
293 default: working =
false; status =
"UNKNOWN";
break;
296 x.error = tr(
"Status Fault, error code: %1: %2").arg(errcode).arg(stateToString(errcode));
300 x.invertor = invertor.invertor;
301 x.now_power = (working) ? float32(rec, 51) : 0;
302 x.now_ac_current = (working) ? float32(rec, 11) : 0;
303 x.now_ac_voltage = 0;
304 x.now_ac_frequency = (working) ? float32(rec, 55) : 0;
305 x.now_dc_current = (working) ? float32(rec, 75) : 0;
306 x.now_dc_voltage = (working) ? float32(rec, 79) : 0;
308 x.day_power_maximum = 0;
309 x.day_ac_voltage_maximum = 0;
310 x.day_ac_voltage_minimum = 0;
311 x.day_dc_voltage_maximum = 0;
312 x.day_operating_hours = 0;
313 x.total_energy = (working) ? float32(rec, 71) : 0;
314 x.total_power_maximum = 0;
315 x.total_ac_voltage_maximum = 0;
316 x.total_ac_voltage_minimum = 0;
317 x.total_dc_voltage_maximum = 0;
318 x.total_operating_hours = 0;
361 float MODBUSTCP::float32(
const QByteArray& data,
int offset)
const {
362 int ival0 = data[offset++];
363 int ival1 = data[offset++];
364 int ival2 = data[offset++];
365 int ival3 = data[offset++];
366 int ival = (ival0 << 24) + (ival1 << 16) + (ival2 << 8) + ival3;
367 float value = *(
float*)&ival;
372 qint16 MODBUSTCP::integer16(
const QByteArray& data,
int offset)
const {
373 int ival0 = data[offset++];
374 int ival1 = data[offset++];
375 int ival = (ival0 << 8) + ival1;
380 qint32 MODBUSTCP::integer32(
const QByteArray& data,
int offset)
const {
381 int ival0 = data[offset++];
382 int ival1 = data[offset++];
383 int ival2 = data[offset++];
384 int ival3 = data[offset++];
385 int ival = (ival0 << 24) + (ival1 << 16) + (ival2 << 8) + ival3;
390 QString MODBUSTCP::stateToString(
int state) {
392 case 102:
return "AC voltage too high";
393 case 103:
return "AC voltage too low";
394 case 105:
return "AC frequenci too high";
395 case 106:
return "AC frequenci too low";
396 case 107:
return "AC grid outside the permissible limits";
397 case 108:
return "Stand alone operation detected";
398 case 112:
return "RCMU error";
400 case 301:
return "Overcurrent (AC)";
401 case 302:
return "Overcurrent (DC)";
402 case 303:
return "Power stage set over temperature";
403 case 304:
return "Internal temperature too high";
404 case 306:
return "Intermediate circuit voltage too low for feeding energy into the grid";
405 case 307:
return "DC input voltage too low for feeding energy into the grid";
406 case 308:
return "Intermediate circuit overvoltage";
407 case 309:
return "DC input voltage MPPT 1 too high";
408 case 313:
return "DC input voltage MPPT 2 too high";
410 case 401:
return "No communication with power stage set possible ";
411 case 406:
return "Power stage set temperature sensor faulty";
412 case 407:
return "Internal temperature sensor faulty";
413 case 408:
return "DC feeding into the grid detected";
414 case 412:
return "Fixed voltage mode has been selected instead of MPP voltage mode and the fixed voltage has been set to too low or too high a value";
415 case 415:
return "Safety cut out via option card or RECERBO has triggered ";
416 case 416:
return "No communication possible between power stage set and control system";
417 case 417:
return "Hardware ID problem";
418 case 419:
return "Unique ID conflict";
419 case 421:
return "HID range error";
420 case 425:
return "No communication possible with the power stage set";
421 case 426:
return "Possible hardware fault";
422 case 427:
return "Possible hardware fault";
423 case 428:
return "Possible hardware fault";
424 case 431:
return "Software problem";
425 case 436:
return "Functional incompatibility (one or more PC boards in the inverter are not compatible with each other, e.g. after a PC board has been replaced.";
426 case 437:
return "Power stage set problem";
427 case 438:
return "Functional incompatibility (one or more PC boards in the inverter in the inverter are not compatible with each other, e.g. after a PC board has been replaced)";
428 case 443:
return "Intermediate circuit voltage too low or asymmetric";
429 case 445:
return "Invalid limit value settings";
430 case 447:
return "Insulation fault";
431 case 448:
return "Neutral conductor not connected";
432 case 450:
return "Guard cannot be found";
433 case 452:
return "Memory error detected";
434 case 453:
return "Short term grid voltage error";
435 case 454:
return "Short term grid frequency error";
436 case 456:
return "Anti-islanding function is no longer implemented correctly";
437 case 457:
return "Grid relay sticking";
438 case 459:
return "Error when recording the measuring signal for the insulation test";
439 case 460:
return "Reference voltage source for the digital signal processor (DSP) is working out of tolerance";
440 case 461:
return "Fault in the DSP data memory";
441 case 462:
return "Error with DC feed monitoring routine";
442 case 463:
return "Reversed AC polarity, AC connector inserted incorrectly";
443 case 474:
return "RCMU sensor faulty";
444 case 475:
return "Solar panel ground fault, insulation fault (connection between solar panel and ground)";
445 case 476:
return "Driver supply voltage too low";
446 case 480:
return "Functional incompatibility (one or more PC boards in the inverter are not compatible with each other, e.g. after a PC board has been replaced)";
447 case 481:
return "Functional incompatibility (one or more PC boards in the inverter are not compatible with each other, e.g. after a PC board has been replaced)";
448 case 482:
return "Startup incomplete";
449 case 483:
return "Voltage UDC fixed on MPP2 string out of limits";
450 case 485:
return "CAN transmit buffer is full";
452 case 501:
return "Insulation error on the solar panels";
453 case 509:
return "No energy fed into the grid in the past 24 hours";
454 case 515:
return "No communication with filter possible";
455 case 516:
return "No communication possible with the storage unit";
456 case 517:
return "Derating caused by too high a temperature";
457 case 558:
return "Functional incompatibility (one or more PC boards in the inverter are not compatible with each other, e.g. after a PC board has been replaced)";
458 case 560:
return "Derating caused by over-frequency";
459 case 566:
return "Arc detector switched off (e.g. during external arc monitoring)";
461 case 705:
return "Conflict when setting the inverter number (e.g. number already assigned)";
462 case 721:
return "EEPROM has been reinitialised or EEPROM is faulty";
463 case 731:
return "Initialisation error – USB stick is not supported";
464 case 732:
return "Over current on USB stick";
465 case 733:
return "No USB stick connected";
466 case 734:
return "Update file not recognised or not present";
467 case 735:
return "Update file does not match the device, update file too old";
468 case 736:
return "Write or read error occurred";
469 case 738:
return "Log file cannot be saved (e.g. USB stick is write protected or full)";
470 case 743:
return "Error occurred during update process";
471 case 745:
return "Update file corrupt";
472 case 751:
return "Time lost";
473 case 752:
return "Real Time Clock module communication error";
474 case 757:
return "Hardware error in the Real Time Clock module";
475 case 758:
return "Internal error: Real Time Clock module is in emergency mode";
476 case 766:
return "Emergency power de-rating has been activated";
479 return "Uknown status code";
483 QString MODBUSTCP::exceptionCodeToString(
int exceptionCode) {
484 switch(exceptionCode) {
485 case 0x01:
return "Illegal function";
486 case 0x02:
return "Illegal data address";
487 case 0x03:
return "Illegal data value";
488 case 0x04:
return "Slave device failure";
489 case 0x05:
return "Acknowledge";
490 case 0x06:
return "Slave device busy";
491 case 0x07:
return "Negative acknowledge";
492 case 0x08:
return "Memory parity error";
493 case 0x0a:
return "Gateway path unavailable";
494 case 0x0b:
return "Gateway target device failed to respond";
void quit()
Quits the running thread.
INVERTOR_status status()
Returns current status of the line.
MODBUSTCP()
Constructor. The very basic initializations.
void data(DBT_DATA)
Signal to send retrieved data to other objects.
void open()
Opens serial port.
Class describing database table DATA.
DBT_LINES m_line
Stores information about line.
QList< DBT_INVERTORS > m_invertors
Stores information about all invertors connected to the line.
void slotInit()
Function called within running thread to initialize all needed child objects.
Virtual class for invertor communication.
void loopFinished(int number_of_ok, int number_of_err)
Signal is sent when reading cycle was finished and all invertors were read.
int m_current_invertor_index
Current index in INVERTOR::m_invertors list.
void setStatus(int address, int retries, const QString &command, const QString &status)
Set status of line.
void loop()
Loops the invertors's list.
Class describing database table INVERTORS.