Qt Serial Port de Lecture de données de manière cohérente
Je suis d'envoi (par écrit) les octets à un périphérique via mon port série. Je suis l'aide de la QSerialPort (http://qt-project.org/wiki/QtSerialPort) module d'instancier périphérique d'e /s de soutien. Lorsque j'envoie des messages à mes INSTEON modem (série), à la lecture de mon message, l'appareil envoie une copie de mon message + 0x06 (accusé de réception de l'Octet), suivie par un message d'état.
J'ai testé mon message à l'aide de DockLight (http://www.docklight.de/). J'ai envoyer le message suivant à la requête de l'état de l'appareil:
02 62 1D E9 4B 05 19 00
À l'aide de Docklight, je reçois la réponse:
02 62 1D E9 4B 05 19 00 06 02 50 20 CB CF 1E DA F7 21 00 FF
L'a retourné le message indique exactement ce que je m'attends à ce que l'appareil est en marche. Si elle est désactivée, le modem serait de les envoyer en arrière 0x00 dans le dernier octet de la position si l'appareil a été éteint. Maintenant, mon problème - je ne dois pas avoir ma fonction correctement configuré afin d'envoyer et de recevoir la réponse d'octets. J'ai essayé beaucoup de différents exemples et des configurations, je suis actuellement en utilisant les éléments suivants:
De configuration connexions signal-slot:
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)));
Fonction utilisée pour parcourir QList de périphériques. Si l'appareil est de type désiré ("Lumière"), alors nous le format de l'ID de l'appareil à la destination de l'QByteArray structure du message. Passer message à fil pour l'envoi. (Sujet modifié à partir de QSerialPort BlockingMaster
exemple.
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
fonction utilisée pour définir les variables de thread et exécute (pistes) thread.
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
Fonction Manche envoi et la réception de
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
de fonction, LOGEMENT qui reçoit le signal de réponse
void Device::handleResponse(const QByteArray &msg){
qDebug() << "Read: " << msg.toHex();
}
- Je recevoir la sortie suivante:
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"
De deux questions.
-
Je n'ai jamais reçu aucune réponse concernant le deuxième dispositif (Chambre à coucher de la Lumière), c'est le message qui est envoyé à la seconde. Il semble que l'envoi est bloqué, comment voulez-vous recommander je format mon envoi afin que je vous envoie après la réception de la réponse de la première à envoyer? Il est à seulement 1 port COM qui peut être utilisé pour envoyer/recevoir. Je crois que je dois Envoyer un message à l'Appareil 1, le Dispositif de réception 1 réponse, Envoyer à l'Appareil 2, le Dispositif de réception 2. Pourrais-je voir un énorme embouteillage avec un grand nombre d'appareils et en utilisant les conditions d'attente, c'est à dire. attendez que l'appareil 1 processus de communication avant la fin de l'exécution de comm processus pour appareil 2?
-
La première lecture contient le cas échéant le 1er semestre de la recevoir.
Read: "026220cbcf05190006"
La deuxième recevez contient le 2ème semestre de la 1ère réponse, suivi par le 1er semestre de la deuxième réponse: Lire 2 -Read: "025020cbcf1edaf721000002621de94b05190006"
approprié réponse complète est02621DE94B05190006 025020CBCF1EDAF72100FF
(note20CBCF
est le Dispositif 2 de l'ID dans la réponse complète exemple)
Ce que des corrections doivent être apportées à la façon dont je suis la réception de données sur le port série?
Merci!!!!
Vous devez vous connecter pour publier un commentaire.
Je crois que mes problèmes ont changé, de la portée de cette question. Avec l'aide de Kuzulis j'ai mis en œuvre de Lecture/Écriture de fonctions pour réussir à lire et envoyer des messages série de manière cohérente. Kuzulis recommandé d'utiliser l'Synchrone à blocage de mode de communication, cependant plus tard, il fut décidé que l'Asynchrone Non-Blocage de la méthode qui convient le mieux à ma demande.
Mon suit de près la mise en œuvre du "Maître" exemple fourni avec le QSerialPort fichiers sources.
- Je utiliser
CurrentStatus
itérer dans une QList deDevice
objets. Pour chaque Lumière dans la liste des Périphériques, j'format de 8 Octets message pour demander à l'état actuel de l'appareil (on/OFF).Dans l'Appareil, le constructeur de la classe, je me connecte les signaux et les slots:
Après le message à envoyer dans
currentStatus
a été préparé,emit writeRequest(msg);
est appelé. Cela envoie un signal qui est connecté à la fentewriteRequest
. writeRequest est utilisé pour la configuration et le fait d'écrire le message sur le port série.Après la configuration du port série, j'ai enregistrer le message en cours de
msgRequest
. Cela peut être utilisé pour renvoyer le message si il y a une erreur. Aprèsserial.write()
est appelé, j'ai de l'installation d'une minuterie pour 400ms. Une fois que ce temps est écoulé, j'ai vérifier ce qui a été lu à partir du port série.handleResponse()
est un logement qui est appelée à chaque fois que QSerialPort émet lereadyRead()
signal.readyRead()
ajoute toutes les données disponibles pour le QByteArrayresponse
.Après 400ms, serialTimer (one shot Timer) émet un
timeout()
signal.serialTimer
a commencé juste après l'écriture de notre message demandé pour le port série.processTimeout()
est là que nous avons enfin vérifier la réponse reçue de la PowerLinc Modem après l'envoi de notre message. Lorsque des messages sont envoyés à la INSTEON PowerLinc Modem (PLM), PLM renvoie l'écho du message et ajoute soit 0x06 (Positif ACK) ou 0x15 (NACK). DansprocessTimeout()
j'assurez-vous que le dernier octet reçu est l'accusé de réception de l'octet, si ce n'est pas le renvoyer notre demandée à l'origine du message.J'ai utilisé le Serial Port Monitor 4.0 (Eltima Software) pour vérifier l'écrire et de lire les transactions sur le port série. Ci-dessous, vous pouvez voir le journal d'impression pour 1 exemple de transaction.
Pour 20 envoie, j'ai reçu la même réponse. Donc, je peux dire à mes questions avec des données incohérentes arrivée ont été résolus. Maintenant, je suis aux prises avec de multiples requêtes d'écriture, mais je crois que c'est une autre question à examiner. J'apprécie le soutien de tous.
Voir le BlockingMaster exemple dans le dépôt et la lecture de la documentation sur le blocage I/O. en outre, ne pas utiliser de blocage I/O inutilement.
Utilisation bytesAvailable() pour obtenir le nombre de données disponibles pour la lecture, parce que ce n'est le fait que vous recevez immédiatement une réponse complète paquet.