Ports parallel abfragen

Alles rund um die Programmierung mit Qt
Antworten
darkshine
Beiträge: 102
Registriert: 20. August 2010 11:39

Ports parallel abfragen

Beitrag von darkshine »

Hallo Qt-Gemeinde,

ich habe ein Terminalprogramm geschrieben. Ich stelle den Comport und Baudrate ein und mit "V" meldet sich mein Gerät.
Nun wollte ich es automatisieren und an alle Com-Ports ein V senden und schauen welcher sich meldet.
Dies habe ich in einer Schleife gelöst:

1. Port öffnen
2. "V" senden
3. Auf eine Antwort warten
4. Port schließen
5. Nächsten Port öffnen

Das klappt auch alles. Allerdings nutze ich auch Bluetooth und da werden gerne mal 10 oder mehr Ports angelegt die abgefragt werden müssen. Da dauert es wirklich sehr lange.
Es sollte aber doch möglich sein alle Ports gleichzeitig zu öffnen und schauen welcher Port sich zurück meldet.
Ich habe es mit Objekten versucht. Dafür erstelle ich z.B 10 Comport Objekte und weise jedem Objekt einen eigenen Port zu. Leider habe ich dadurch keine Geschwindigkeitsverbesserung erziehlt.

Wären Threads eine Lösung? Ich habe allerdings von Threads gar keine Ahnung und weiß nicht, was diese überhaupt leisten können.

Vielen Dank
upsala
Beiträge: 3946
Registriert: 5. Februar 2006 20:52
Wohnort: Landshut
Kontaktdaten:

Beitrag von upsala »

Wie werden die Daten ausgelesen? Wie sieht der Code dazu aus?
darkshine
Beiträge: 102
Registriert: 20. August 2010 11:39

Beitrag von darkshine »

Ich erstelle comport Objekte und weise den Objekten jeweils einen vorhandenen Comport zu. Die Objekte speichere ich einer einer QHash. Welche Comports wirklich existieren habe ich vorher abgefragt und in einer QStringlist comliste gespeichert.
Die comliste gibt dann einen String in der Form "COM1" usw zurück.

Code: Alles auswählen

QHash<int, Comports*> porthash;
	
for(int i=0; i<=9; i++)
{		
		porthash[i] = new Comports(comliste.at(i));
}
In der Klasse Comports findet die Abfrage statt.

Code: Alles auswählen

Comports::Comports(QString com)
{
	comport = com;	
	verbinde();
	qDebug() << "Erstelle Port";
}

Code: Alles auswählen

void Comports::verbinde()
{			


		portIni(comport); //ComPort wird inistalisiert
		
		// Sende ein V und warte schaue ob sich etwas am Port zurück meldet
		WriteFile(hCom,"V",1,&dwBytesWritten,0); 
                qWait(100); //Warte 100ms
		
		ReadFile(hCom,&output,1000,&dwBytesRead,0);	


			if(dwBytesRead != 0)
			{
				//Es gab eine Antort auf "V". Mein Gerät wurde gefunden				
			}	
			CloseHandle(hCom);
			
}	
Wenn ein Objekt erstellt wurde, dauert es doch recht lange bis das Nächste erstellt wird.
Ich würde gerne alle Objekte "gleichzeitig" erstellen und z.B nach 5Sek abfragen, ob sich auf einem Port etwas auf "V" gemeldet hat.
Ich hatte mit einen Gschwindigkeitsgewinn durch die Erstellung von Objekten in der for-Schleife erhofft, aber leider half es nichts :-(
upsala
Beiträge: 3946
Registriert: 5. Februar 2006 20:52
Wohnort: Landshut
Kontaktdaten:

Beitrag von upsala »

Sind writeFile und readFile in diesem Falle blockierende Funktionen? Wenn ja, dann erstell dir einen Thread und frage dort ab, wenn nicht kannst du das ganze doch mit Timern pollen.
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Beitrag von solarix »

Ohne ein vollständiges Pflichtenheft sind Tipps zum Aufbau einer Software immer schwierig (bis sogar gefährlich..). Aber das, was du bisher gezeigt hast, könnte man schon als Thread-Anwendung implementieren.

Es gibt immer viele Möglichkeiten, eine (Thread-)Anwendung zu implementieren, aber ich zeig mal ein paar Schlüsselstellen zu einer möglichen Lösung:

Initialisierung:

Code: Alles auswählen

  QThread   *context1 = new QThread();
  Comports  *comPort = new Comports();

  // Startet den Auftrag, sobald der Thread läuft
  connect(context1,SIGNAL(started()),  
              comPort, SLOT(testPort()));

  // Liefert das Ergebnis
  connect(comPort,SIGNAL(deviceDetected(QString,bool)),  
              this, SLOT(portResult(QString,bool)));
   
  comPort->moveToThread(context1 );
  context1->start();

Methode testPort:

Code: Alles auswählen

void Comports::testPort()
{         
      portIni(comport); //ComPort wird inistalisiert
      
      // Sende ein V und warte schaue ob sich etwas am Port zurück meldet
      WriteFile(hCom,"V",1,&dwBytesWritten,0);
      qWait(100);
      
      ReadFile(hCom,&output,1000,&dwBytesRead,0);   

      if(dwBytesRead != 0)
        emit deviceDetected(comport,true);
      else 
        emit deviceDetected(comport,false);

      CloseHandle(hCom);
}  
Die Grundlagen zu den Threads musst du dir natürlich selbst erarbeiten.

hth..
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Beitrag von RHBaum »

Für lese und schreibe operationen auf ressourcen bietet windows eh die "assynchronen Ports" an ...
Man kann also den lesevorgang starten lassen und hinterlegt eine routine, die gefeuert wird wenn die daten vollstaendig gelesen wurden.
Das ist so ziemlich das effektivste unter windows fuer assynchrones lesen. Braucht man keine threads zu (macht das BS).

Da hier effektivitaet ned im Vordergrundsteht, kann man das threaden auch selbst uebernehmen und weiterhin blockierende aufrufe verwenden ... Ist IMHO etwas intuitiver zu programmieren. mit den Overlapped und callbacks kriegt man noch mehr Kopfschmerzen auf Dauer als wie mit threading :-) Wobei es schon miteinander verwand ist :-)

"Pollen" macht IMHO wenig Sinn bei threads + blockierenden zugriffen.
mann kann die timouts fuer read und write so stellen, das die dinger "ewig auf daten warten" ... warum dann pollen ?

Ciao ...
darkshine
Beiträge: 102
Registriert: 20. August 2010 11:39

Beitrag von darkshine »

Ich habe ein einfaches QThread-Beispiel im Internet gefunden und auf mein Program übertragen.
Es läuft jetzt so ab:

Code: Alles auswählen

void Comports::run()
{    

      qDebug() << "run() läuft";

      portIni(comport); //ComPort wird inistalisiert
      
      // Sende ein V und warte schaue ob sich etwas am Port zurück meldet
      WriteFile(hCom,"V",1,&dwBytesWritten,0);
                qWait(100); //Warte 100ms
      
      ReadFile(hCom,&output,1000,&dwBytesRead,0);   


         if(dwBytesRead != 0)
         {
            //Es gab eine Antort auf "V". Mein Gerät wurde gefunden            
         }   
         CloseHandle(hCom);
         
}    
Und im Hauptprogram

Code: Alles auswählen

      for(int i=0; i<=9; i++)
	{		
		porthash[i] = new Comports(comliste.at(i));
	}	
	
	for(int i=0; i<=9; i++)
	porthash[i]->start();
Dadurch hat sich die "Abfragegeschwindigkeit" mehr als verdoppelt.

Dies ist bestimmt nicht der Königsweg, aber schon ein großer Fortschritt für mich
Antworten