Lesen vom seriellen Port mit Qextserialport & WinAPI

Alles rund um die Programmierung mit Qt
Antworten
diddely
Beiträge: 49
Registriert: 9. Juli 2008 16:19

Lesen vom seriellen Port mit Qextserialport & WinAPI

Beitrag von diddely »

Hi,

für das arbeiten an der RS232 Schnittstelle, habe ich mich für die Qextserialport Klasse entschieden.
Mir ist aufgefallen, dass diese Klasse für das Lesen der Daten von der Schnittstelle doch nicht geeignet ist.
Es wird kein Signal emittiert, dass Daten angekommen sind.(readyRead)
Daher kam mir die Idee mit dem Polling, welches aber auch nicht die sauberste Lösung ist. (Starte in einem seperaten Thread das Polling, alle ~10 µs oder so ähnlich)

Die letzte Idee, die ich hatte ist das direkte zugreifen auf die WinAPI (SetCommMask & WaitCommEvent).

Ich habe mir überlegt eine extra (Thread) Klasse zu schreiben, die über die WinAPI auf der Leitung lauscht und falls was passiert meine andere (reine QT) Klasse informiert.
So spare ich mir das dauerhafte Polling.

Was haltet ihr davon?
Bei einer Portierung auf Linux würde ich natürlich das Modul auswechseln usw....

Wo ich mir noch nicht sicher bin ist folgendes:

Die (QT) Klasse soll schreiben und lesen ( mit der Hilfe der API-Klasse).
Die QT-Klasse öffnet das Gerät als ReadWrite und gleichzeitig müsste meine API-Hilfsklasse das Gerät auch zum lesen öffnen können um auf das Event zu lauschen.

Geht das ?
Oder habt ihr eventuell noch eine andere Idee?
Sephral
Beiträge: 201
Registriert: 1. Februar 2006 09:40
Kontaktdaten:

Beitrag von Sephral »

Der Fehler lässt sich nicht direkt in Qextserialport beheben?
So könnten auch andere von deinem Bugfix profitieren.
diddely
Beiträge: 49
Registriert: 9. Juli 2008 16:19

Beitrag von diddely »

hmm ob das ein Fehler ist weiss ich nciht....

Habe aber irgendwo gelesen, dass schon QIODevice kein Signal emitted.
Da QextSerial davon abgeleitet wurde....
Theoretisch müsste ich da in die QT-Sources eingreifen.

Deswegen habe ich mir da keine zusätzlichen Gedanken gemacht.
elli
Beiträge: 12
Registriert: 7. Mai 2008 21:53

Beitrag von elli »

hello,
Mir ist aufgefallen, dass diese Klasse für das Lesen der Daten von der Schnittstelle doch nicht geeignet ist.
Es wird kein Signal emittiert, dass Daten angekommen sind.(readyRead)
da kann ich Dir nur zustimmen. Eine serielle Schnittstelle ist zutiefst eine asynchrone Schnittstelle. N-Zeichen lesen wollen und erwarten das sie kommen ist relativ unsinnig, zumal es auch ein ungesicherte Schnittstelle
ist und theoretisch denkbar ist das Zeichen verloren gehen. (Früher besonders unter Win 98 war das Usus).

Ich programmiere seit Jahren auf seriellen Schnittstellen und habe auch Windows Device Treiber für diverse virtuelle serielle Port Emulation geschrieben und kann daher sehen wie die Schnittstelle durch ein Anwendungsprogramm bedient wird. Man sieht schreckliches bis hin zum dummen lesen von jeweils einem Byte ...

Da ja eine serielle Schnittstelle auch Line Signals (DCD,CD, etc) und Framing Errors etc. generiert müßen sich diese Ereignisse als asychrone Ereignisse also "Signals" wiederspiegeln.
Ein Core Thread macht eine overlapped WaitForEvent und overlapped ReadFile mit sorgfältig eingestellten Timern und Abbruchbedingungen. Ankommende Zeichen werden dann per "Signal" gemeldet. Nur so kommt eine schnelle Prozessor schonende Verarbeitung zustande. Dieser Verarbeitungspfad stellt sicher das quasi die Kette Hardware Interrupt, Beendigung eines overlapped IO Controls /Read, Signalisierung der Anwendung durchlaufen wird.

Unter diesen Gesichtspunkten ist qextserialport nicht brauchbar. CreateFile wird noch nicht mal mit dem Flag overlapped gemacht.

Besser neu implementieren.

elli
diddely
Beiträge: 49
Registriert: 9. Juli 2008 16:19

Beitrag von diddely »

huh,..dieser Teil war mir etwas zu "kompliziert" ausgedrückt...
Ein Core Thread macht eine overlapped WaitForEvent und overlapped ReadFile mit sorgfältig eingestellten Timern und Abbruchbedingungen. Ankommende Zeichen werden dann per "Signal" gemeldet. Nur so kommt eine schnelle Prozessor schonende Verarbeitung zustande. Dieser Verarbeitungspfad stellt sicher das quasi die Kette Hardware Interrupt, Beendigung eines overlapped IO Controls /Read, Signalisierung der Anwendung durchlaufen wird.

Sehe aber, dass meine Überlegung nicht so ganz überzeugend war.
So eine Klasse neuimplementieren ist sicherlich eine schweißtreibende Arbeit,vorallem wenn man noch nie zuvor mit Serial Programming zu tun hatte.
Hmm.... Echt schade, dass QT sowas nicht bereitstellt.

Laut deiner Aussage, arbeitet qextserialport nonoverlapped ?!?
Wenn ich das overlapping richtig verstanden habe, ist damit das blockieren des aufrufenden threads gemeint.
Overlapping brauche ich doch nur wenn mehrere Threads gleichzeitig I/O Operationen auf die Schnittstelle ausführen wollen???

Bin mir gerade nicht sicher ob ich overlapping brauche.
Man könnte ja einen Master-Thread erzeugen, der als einziger an der "Leitung" arbeitet und die Worker-Threads versorgt.

Auf der anderen Seite wäre ein paralleler I/O Zugriff durch die ganzen Threads auch nicht schlecht. Alle könnten gleichzeitig lesen und gucken ob die Daten, die angekommen sind für ihn bestimmt sind. Falls ja verarbeiten, ansonsten idle....

Ich arbeite mich gerade in die ganze Thematik rein. Bin recht am Anfang des Projekts...und bin schon jetzt etwas frustriert... :evil:


Eine Kurzfassung meiner Aufgabe:

Bekomme über die serielle Schnittstelle Daten von mehreren Sensorquellen geliefert. Im Programm selbst soll je ein thread für eine Sensorquelle erzeugt werden.
Jetzt ist die Frage, macht man einen Master-Thread, der diese Worker-Threads versorgt oder nicht...
Oder alle greifen einfach selber via I/O zu und entscheiden...

Merke gerade, mein Problem wird zu Allgemein und kapselt sich langsam von QT ab. :)


Danke nochmals für die Mühe
elli
Beiträge: 12
Registriert: 7. Mai 2008 21:53

Beitrag von elli »

hello,
Jetzt ist die Frage, macht man einen Master-Thread, der diese Worker-Threads versorgt oder nicht...
Oder alle greifen einfach selber via I/O zu und entscheiden...
wenn ich das richtig verstehe hast Du genau eine serielle Schnittstelle und
dahinter befinden sich verschiedene Sensoren. Unter dieser Annahme
brauchst Du einen Thread der die serielle Schnittstelle bedient.

Dort wird der ansynchrone Zeichenstrom interpretiert (wenn es mehrere Sensoren sind muß ja ein Protokoll existieren). Sprich Du erkennst jetzt das Sensor X ein Datum geschickt. Jetzt kanns Du ein "Signal" an einen angemeldeten Consumer des Sensor X schicken, der wiederum einen Thread repräsentieren kann.

Eine sehr gute Source ist das uralte Bespiel von M$ mttty. Hier ist die richtige Programmierung der seriellen Schnittstelle enthalten. Also googeln) Ich habe es damals auch als Vorlage für meine Implementierung genommen. Vielleicht mache ich mal eine QT Klasse draus.

elli
diddely
Beiträge: 49
Registriert: 9. Juli 2008 16:19

Beitrag von diddely »

Ja genau so ist es.

Der "Wächter" der schaut auf die serielle Schnittstelle und sagt meiner Master-Klasse "Hallo es sind Daten da".
Hier muss ich eventuell das File-Handle weiterreichen, ohne es zu schliessen oder??
Die Master-Klasse geht nun selber an die Schnittstelle und liest die Daten und guckt (anhand des Protokolls) von welchem Sensor die Daten kommen.
Falls noch kein Thread für diesen Sensor existiert, wird der vom Master erzeugt und die Daten werden an diesen weitergeleitet. Damit der sie verarbeiten, visualisieren etc... kann.

Wenn der User nun was an der GUI ändert ( pro Sensor eine GUI) wird dieser ganze Ablauf von hinten durchlaufen.
Thread schickt Daten/Befehle an den Master. Der schreibt die Daten/Befehle direkt auf die Schnittstelle ( nicht über den Wächter).

Habe heute erfahren, dass meine RS232 Schnittstelle nur RX/TX/GND benutzt alles andere wurde auf GND gelegt.
elli
Beiträge: 12
Registriert: 7. Mai 2008 21:53

Beitrag von elli »

Hello,
abe heute erfahren, dass meine RS232 Schnittstelle nur RX/TX/GND benutzt alles andere wurde auf GND gelegt.
das klingt nicht so gut, da anscheinend die Hardware Flow Control nicht möglich ist, zum anderen keine Erkennung möglich ist das ein Sensor gesteckt wurde. Typischerweise setzen Modems oder moderne Geräte DTR/DSR um anzuzeugen das sie da sind oder CD das logische Verbindungen existieren.

Vom Sensor zum PC muß es nicht unbedingt ein Problem sein, da die inzwischen alle schnell genug sind und ein Software Fifo im Treiber existiert.

Wenn man aber zuviele Daten zu den Sensoren schickt (was ich aber nicht annehme) kann man sie natürlich "überennen".

elli[/quote]
diddely
Beiträge: 49
Registriert: 9. Juli 2008 16:19

Beitrag von diddely »

bietet QextSerialPort eine möglichkeit einen Handle zu setzen?

In meinem Beispiel werde ich mit meiner Wächter-klasse mit createfile den Port öffnen und den dabei festgelegten Handle weiterreichen.

Falls qextserialport sowas nicht anbietet, müsste ich es ableiten und eine methode setHandle implementieren.

Oder seht ihr da eine einfachere Möglichkeit?
diddely
Beiträge: 49
Registriert: 9. Juli 2008 16:19

Beitrag von diddely »

UPDATE:

Habe mich dafür entschieden, Qextserialport abzuleiten und an den Ctor als Parameter das handle zu übergeben. Dafür musste ich noch die open Methode umschreiben.

Werde das ganze noch testen, hoffe mal es klappt so wie ich es mir vorgestellt habe.
diddely
Beiträge: 49
Registriert: 9. Juli 2008 16:19

Beitrag von diddely »

Weis einer von euch zufällig wie ich ein WaitCommEvent bei non-overlapped wieder aufheben kann?

Das blöde bei der ganzen Sache ist mein Wächter würde, bei einem WaitCommEvent die Leitung nie wieder loslassen.
Erst nur bei einem Event.

Die Sache wird immer blöder und blöder...ich glaube ich werde komplett auf qextserialport verzichten und mir meine eigene Klasse schreiben.
Antworten