Я отправляю (записываю) байты на устройство через мой последовательный порт. Я использую модуль QSerialPort (http://qt-project.org/wiki/QtSerialPort) для создания поддержки ввода-вывода устройства. Когда я отправляю сообщения на модем INSTEON (последовательный), после чтения моего сообщения устройство отправляет обратно копию моего сообщения + 0x06 (ACK Byte), за которым следует сообщение о состоянии.Последовательный порт Qt - постоянное чтение данных
Я проверил свое сообщение с помощью DockLight (http://www.docklight.de/). Я посылаю следующее сообщение для запроса состояния устройства:
02 62 1D E9 4B 05 19 00
Использование Docklight, я получаю ответ:
02 62 1D E9 4B 05 19 00 06 02 50 20 CB CF 1E DA F7 21 00 FF
Возвращенный сообщение указывает на то, что я ожидал бы, что устройство включено , Если вы выключен, модем отправит обратно 0x00 в последнюю позицию байта, если устройство выключено. Теперь моя проблема - я не должен правильно настроить свою функцию для отправки, а затем получить байты ответа. Я пробовал много различных примеров и конфигураций, в настоящее время я использую следующие: соединения сигнал-слот
Setup:
QObject::connect(&thread, SIGNAL(sendResponse(QByteArray)),
this, SLOT(handleResponse(QByteArray)));
QObject::connect(&thread, SIGNAL(error(QString)),
this, SLOT(processError(QString)));
QObject::connect(&thread, SIGNAL(timeout(QString)),
this, SLOT(processTimeout(QString)));
Функция используется для перебора QList устройств. Если требуемый тип устройства («Свет»), мы отформатируем идентификатор устройства в предполагаемой структуре сообщения QByteArray. Передайте сообщение в поток для отправки. (Тема редактировался QSerialPort BlockingMaster
например
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;
bool msgStatus;
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?";
//send(msg,&msgStatus, &updateStatus);
//msg.clear();
thread.setupPort("COM3",500,msg);
if(devStatus!=updateStatus){
qDebug() << deviceList->at(i)->name << " is now: " << updateStatus;
updateStatus = !updateStatus;
}
}
}
}
SetupThread
функция используется для установки локальных переменных потоков и выполняет (запускается) нить
void serialThread::setupPort(const QString &portName, int waitTimeout, const QByteArray &msg){
qDebug() << "Send Message " << msg.toHex();
QMutexLocker locker(&mutex);
this->portName = portName;
this->waitTimeout = waitTimeout;
this->msg = msg;
if(!isRunning())
start();
else
cond.wakeOne();
}
Run
функция -.. Handled отправка и получение
void serialThread::run(){
bool currentPortNameChanged = false;
qDebug() << "Thread executed";
mutex.lock();
QString currentPortName;
if(currentPortName != portName){
currentPortName = portName;
currentPortNameChanged = true;
}
int currentWaitTimeout = waitTimeout;
QByteArray sendMsg = msg;
mutex.unlock();
QSerialPort serial;
while(!quit){
if(currentPortNameChanged){
serial.close();
serial.setPortName("COM3");
if (!serial.open(QIODevice::ReadWrite)) {
emit error(tr("Can't open %1, error code %2")
.arg(portName).arg(serial.error()));
return;
}
if (!serial.setBaudRate(QSerialPort::Baud19200)) {
emit error(tr("Can't set baud rate 9600 baud to port %1, error code %2")
.arg(portName).arg(serial.error()));
return;
}
if (!serial.setDataBits(QSerialPort::Data8)) {
emit error(tr("Can't set 8 data bits to port %1, error code %2")
.arg(portName).arg(serial.error()));
return;
}
if (!serial.setParity(QSerialPort::NoParity)) {
emit error(tr("Can't set no patity to port %1, error code %2")
.arg(portName).arg(serial.error()));
return;
}
if (!serial.setStopBits(QSerialPort::OneStop)) {
emit error(tr("Can't set 1 stop bit to port %1, error code %2")
.arg(portName).arg(serial.error()));
return;
}
if (!serial.setFlowControl(QSerialPort::NoFlowControl)) {
emit error(tr("Can't set no flow control to port %1, error code %2")
.arg(portName).arg(serial.error()));
return;
}
}
//write request
serial.write(msg);
if (serial.waitForBytesWritten(waitTimeout)) {
//! [8] //! [10]
// read response
if (serial.waitForReadyRead(currentWaitTimeout)) {
QByteArray responseData = serial.readAll();
while (serial.waitForReadyRead(10)){
responseData += serial.readAll();
}
QByteArray response = responseData;
//! [12]
emit this->sendResponse(response);
//! [10] //! [11] //! [12]
} else {
emit this->timeout(tr("Wait read response timeout %1")
.arg(QTime::currentTime().toString()));
}
//! [9] //! [11]
} else {
emit timeout(tr("Wait write request timeout %1")
.arg(QTime::currentTime().toString()));
}
mutex.lock();
cond.wait(&mutex);
if (currentPortName != portName) {
currentPortName = portName;
currentPortNameChanged = true;
} else {
currentPortNameChanged = false;
}
currentWaitTimeout = waitTimeout;
sendMsg = msg;
mutex.unlock();
}
serial.close();
}
handleResponse
функция, SLOT, которая принимает ответный сигнал
void Device::handleResponse(const QByteArray &msg){
qDebug() << "Read: " << msg.toHex();
}
я получаю следующий результат:
Has device "Living Room Light" Changed?
Send Message "02621de94b051900"
Has device "Bedroom Light" Changed?
Send Message "026220cbcf051900"
Thread executed
Read: "026220cbcf05190006"
Polling for changes...
Has device "Living Room Light" Changed?
Send Message "02621de94b051900"
Has device "Bedroom Light" Changed?
Send Message "026220cbcf051900"
Read: "025020cbcf1edaf721000002621de94b05190006"
Polling for changes...
Has device "Living Room Light" Changed?
Send Message "02621de94b051900"
Has device "Bedroom Light" Changed?
Send Message "026220cbcf051900"
Read: "02501de94b1edaf72100ff02621de94b05190006"
две проблемы.
Я не получаю никакого ответа относительно второго устройства (Light Bedroom), это сообщение, которое отправляется вторым. Кажется, что отправка блокируется, как бы вы порекомендовали мне отформатировать мою отправку, чтобы отправить сообщение после получения ответа для первой отправки? Существует только 1 COM-порт, который можно использовать для отправки/получения. Я считаю, что я должен отправить сообщение на устройство 1, получить ответ устройства 1, отправить на устройство 2, получить устройство 2. Могу ли я в конечном итоге увидеть огромную пробку с большим количеством устройств и использовать условия ожидания, т.е. дождаться завершения коммуникационного процесса устройства 1 до выполнения комм-процесса для устройства 2?
Самое первое прочитанное содержит соответствующую 1-ю половину приема.
Read: "026220cbcf05190006"
Второй получить содержит 2-й половине 1-го ответа, затем 1-й половине второго ответа: Read 2 -Read: "025020cbcf1edaf721000002621de94b05190006"
Соответствующий полный ответ02621DE94B05190006 025020CBCF1EDAF72100FF
(обратите внимание20CBCF
это устройство 2 в ID в полном примере ответа)
Какие корректировки должны быть сделаны в отношении того, как я получаю данные из последовательного порта? Спасибо!
Благодарим вас за комментарии. Я скорректировал свой код довольно существенно. Теперь я получаю более «последовательный» ответ, однако он по-прежнему не соответствует моим намерениям. –
+1 для «невообразимого лапши-кода» ... и полезный ответ. – cgmb
Проблема с использованием bytesAvailable() заключается в том, что ответ не является установленным числом байтов. Каждый ответ может быть переменной длины в зависимости от типа и формата сообщения, отправленного на устройство. –