Je suis confronté à un problème particulier concernant la communication série sous win32. Je communique avec un appareil qui ne peut accepter que des images lorsqu'il ne communique pas déjà. Je dois donc trouver un cadre valide et ensuite immédiatement envoyer ma demande.Ajuster les paramètres de la lecture du port série
J'ai développé une classe nommée Serial qui gère les opérations de base sur le port série (ouvrir, fermer, lire, écrire) puis un appel Thread dans une boucle de lecture et d'écriture.
boucle de fil
//Device is an object of class Serial
while(device->isOpen() && !terminate)
{
unsigned int readed = 0;
unsigned long error = ERROR_SUCCESS;
unsigned char* data = device->read(&readed, &error);
if(error==ERROR_SUCCESS)
{
//If data received, deliver to upper level
if(readed>0)
{
QByteArray output((const char*)data, (signed int)readed);
emit dataArrived(output, readed);
}
}
else
{
//unrelated stuff
}
//Here I manage the writting issue
//Only when nothing is received, and Upper layer wants to send a frame
//(Upper layer only will mark as something to send when it detects a valid frame)
if(readed==0)
{
out_lock.lock();
//If something to send...
if(something_to_send > 0)
{
if(device->write(output_buffer, output_size, &error))
{ //things...
}
}
}
}
Le fil conserve essentiellement la lecture, et quand rien reçu, voit si quelqu'un a signalé à envoyer une trame (ce qui signifie qu'une trame valide est reçu juste). Lorsque cela se produit, il écrit le cadre via le port série.
Voici mon problème. Dans la fonction série :: read():
J'utilise le chemin chevauchée de la lecture:
::ClearCommError(handle, &dwErrors, &stat);
if(stat.cbInQue)
{
//If there's something to read, read it, please note the bytes to read parameter, here 1.
bool ok = ::ReadFile(handle, buffer_in, 1, &bytes_read, &ov_reader);
if(!ok)
{
DWORD _error = ::GetLastError();
if(_error == ERROR_IO_PENDING)
{
DWORD result = ::WaitForMultipleObjects(2, waiters, FALSE,INFINITE);
switch(result)
{ //Eventshutdown
case WAIT_OBJECT_0: /*code omitted*/break;
case WAIT_OBJECT_0+1: ok = ::GetOverlappedResult(handle, &ov_reader, &bytes_read, true);
//check ok value omitted
break;
}
}
}
}
if(bytes_read>0)
{
*size = bytes_read;
}
Ici commence mon problème. Lorsque le périphérique m'envoie de petites trames (environ 30 octets), tout fonctionne correctement, mais lorsque des trames plus grandes sont envoyées, le code ne peut pas trouver de temps libre entre les trames. .
Si j'augmente le nombre d'octets à lire dans la fonction de lecture(), perdre la capacité de détecter lorsque le dispositif "écoute": ok = bool :: ReadFile (poignée, buffer_in, 50, & bytes_read, & ov_reader); Cela se produit parce que mon application peut recevoir la fin d'une image avec le début de la suivante. Ce comportement est très commun. En revanche, si je modifie l'argument INFINITE par un délai d'expiration valide dans la fonction WaitForMultipleObjects
, je perds des données.
Donc, ma question est essentiellement ... ce que je fais mal? Pourquoi en lisant 1 octet chaque fois que je ne trouve pas de temps libre pour envoyer mes propres images?
Merci
Vous avez un problème beaucoup plus important, il y a une course inévitable ici. Vous pouvez décider que l'appareil n'envoie pas une microseconde avant l'envoi des étoiles. Vous ne pouvez pas faire ce travail. –
@nobugz soulève un point VRAIMENT VRAIMENT important! Est-ce que vous supposez une longue pause entre les paquets d'état ou quelque chose? – mtrw
Bien que ce type de communication de l'appareil n'est pas universelle, il n'est pas non plus inconnu. Ce que le protocole appelle généralement, c'est que si vous commencez à envoyer et que le périphérique démarre également, vous perdez et devez arrêter, gérer tout ce que le périphérique envoie puis réessayer. C'est une sorte de détection de collision d'un pauvre sur une liaison RS232. C'est une douleur, et c'est mieux géré au niveau du pilote UART, mais ce n'est probablement pas une option réaliste sur Windows. –