I believe that my problems have moved from the scope of this issue. With Kuzulis, I implemented Write / Read functions to successfully send and read sequential messages. Kuzulis recommended using a synchronous lock communication pattern, but later it was decided that the asynchronous non-locking method works best for my application.
My implementation closely follows the Wizard example provided by the QSerialPort source files.
I am using CurrentStatus to iterate through QList Device objects. For each βLightβ list in the βDeviceβ list, I will format an 8-byte message to request the current status of the device (ON / OFF).
void Device::currentStatus(QList<Device *> * deviceList){ QString devID, updateQry; int devStatus, updateStatus; updateStatus=0; QSqlQuery query; for(int i=0; i<deviceList->size(); i++){ if(deviceList->at(i)->type == "Light"){ devStatus = deviceList->at(i)->status; devID = deviceList->at(i)->deviceID; QByteArray msg; msg.resize(8); msg[0] = 0x02; msg[1] = 0x62; msg[2] = 0x00; msg[3] = 0x00; msg[4] = 0x00; msg[5] = 0x05; msg[6] = 0x19; msg[7] = 0x00; msg.replace(2, 3, QByteArray::fromHex( devID.toLocal8Bit() ) ); qDebug() << "Has device " << deviceList->at(i)->name << "Changed?"; emit writeRequest(msg); if(devStatus!=updateStatus){ qDebug() << deviceList->at(i)->name << " is now: " << updateStatus; updateStatus = !updateStatus; } } } }
In the constructor of the Device class, I connect the signals and slots:
Device::Device(){ serialTimer.setSingleShot(true); QObject::connect(&serial, SIGNAL(readyRead()), this, SLOT(handleResponse())); QObject::connect(&serialTimer, SIGNAL(timeout()), this, SLOT(processTimeout())); QObject::connect(this, SIGNAL(writeRequest(QByteArray)), this, SLOT(writeSerial(QByteArray))); }
After the message for sending CurrentStatus been prepared, emit writeRequest(msg); is called emit writeRequest(msg); . This sends a signal that is connected to the writeRequest slot. writeRequest is used to set up and actually write a message to the serial port.
void Device::writeSerial(const QByteArray &msg){ if (serial.portName() != "COM3") { serial.close(); serial.setPortName("COM3"); if (!serial.open(QIODevice::ReadWrite)) { processError(tr("Can't open %1, error code %2") .arg(serial.portName()).arg(serial.error())); return; } if (!serial.setBaudRate(QSerialPort::Baud19200)) { processError(tr("Can't set rate 19200 baud to port %1, error code %2") .arg(serial.portName()).arg(serial.error())); return; } if (!serial.setDataBits(QSerialPort::Data8)) { processError(tr("Can't set 8 data bits to port %1, error code %2") .arg(serial.portName()).arg(serial.error())); return; } if (!serial.setParity(QSerialPort::NoParity)) { processError(tr("Can't set no patity to port %1, error code %2") .arg(serial.portName()).arg(serial.error())); return; } if (!serial.setStopBits(QSerialPort::OneStop)) { processError(tr("Can't set 1 stop bit to port %1, error code %2") .arg(serial.portName()).arg(serial.error())); return; } if (!serial.setFlowControl(QSerialPort::NoFlowControl)) { processError(tr("Can't set no flow control to port %1, error code %2") .arg(serial.portName()).arg(serial.error())); return; } } qDebug() << "Message written"; this->msgRequest = msg; serial.write(msgRequest); serialTimer.start(400); }
After setting up the serial port, I save the current message until msgRequest . This may be required to resend the message if there is an error. After calling serial.write() , I set the timer to 400 ms. After this timer expires, I check what has been read from the serial port.
handleResponse() is a slot that is called every time a QSerialPort emits a readyRead() signal. readyRead() adds any available data to the QByteArray response .
void Device::handleResponse(){ response.append(serial.readAll()); }
After 400 ms, serialTimer (one shot timer) issues a timeout() signal. serialTimer was launched immediately after entering our requested message into the serial port. processTimeout() is where we finally check the response received from the PowerLinc bridge after sending our message. When messages are sent to the INSTEON PowerLinc (PLM) modem, PLM sends the message back and adds either 0x06 (positive ACK) or 0x15 (NACK). In processTimeout() I check that the last byte is an ACK byte, if not, repeat our originally requested message.
void Device::processTimeout(){ qDebug() << "Read: " << response.toHex(); int msgLength = this->msgRequest.length(); if(response.at(msgLength)!=0x06){ qDebug() << "Error, resend."; emit writeRequest(msgRequest); } response.clear(); }
I used Serial Port Monitor 4.0 (Eltima Software) to check write and read transactions on the serial port. Below you can view the log print for 1 sample transaction.
20:44:30:666 STATUS_SUCCESS 02 62 1d e9 4b 05 19 00 <--- Send 20:44:30:669 STATUS_SUCCESS 02 62 1d e9 4b 05 19 00 06 <--- Receive 20:44:30:875 STATUS_SUCCESS 02 <--- Receive 20:44:30:881 STATUS_SUCCESS 50 1d e9 4b 1e da f7 21 00 ff <--- Receive
For 20 shipments, I received the same answer. Thus, I can say with confidence that my problems with inconsistent data arrival have been resolved. Now I'm struggling with a few recording requests, but I think this is a separate issue for research. I thank everyone for their support.