Hallo zusammen,
ich brauch mal eure Hilfe. Ich habe eine DLL mit C++ erstellt, in der
sich diverse Routinen für die RS232 befinden (z.B. send_data(),
receive_data(), setup_comm() usw.). Von einem anderen Programm binde ich
die DLL ein, bzw. nutze die Funktionen innerhalb der DLL. Alle
Funktionen liefern hierbei ein Ergebnis zurück - meist eine BOOL (z.B.
success = receive_data(Parameter)).
Da ich innerhalb der Funktion receive_data im Polling-Modus auf Daten
warte, und gleichzeitig dort auch einen Timeout-Timer laufen habe, kommt
es nun vor, dass der Timeout-Timer (ca. 3s) immer dann anspricht, wenn
keine Daten über die RS232 von einem entsprechenden Device zurückkommen
- soweit ist das ja OK. Aber jetzt ist es so, dass mein Hauptprogramm
ca. 70 Devices, die über einen Bus vernetzt sind, in regelmäßigen
Abständen abfragt (abfragen muss!)
Da es sich um eine Art TOKEN-RING-BUS handelt (HARDWARE ist fest
vorhanden
und NICHT verhandelbar!) kann es in seltenen Ausnahmen vorkommen, dass
eben
ein Device in dieser Kette nicht mehr reagiert und somit das
Gesamtsystem lahmlegt. Dann spricht bei jeder Abfrage der Timeout-Timer
an - bei 70 Devices a)3s kann man sich ja ausrechnen, wie lange das
Gesamtsystem blockiert wird.
Soviel zum Vorgeplänkel.
Jetzt meine Frage: Welche Möglichkeit habe ich, dass z.B. die Daten
nicht mehr im Polling-Modus abgefragt werden? Wie kann ich, solange noch
kein Rückgabewert der Funktion vorhanden ist, im Hauptprogramm
weitermachen, ohne dass das System blockiert wird. Als Parameter zum
Aufruf der Funktion dient u.a. ein Pufferbereich, der die Daten
aufnehmen soll, die Adresse des abzufragenden Devices usw.
Danke schon mal - auch fürs durchlesen
Gruß
TK
Hi
In deinem Fall wäre es günstiger der COM-Schnittstelle einen eigenen
Thread zu spendieren. Die Kommunikation zwischen Hauptprogamm und Thread
erfolgt dann nur noch auf der Message-Ebene. Wenn du wissen willst, wie
so etwas aussieht, dann suche mal nach 'cport'. Version 3 oder höher.
MfG Spess
Das mit einem eigenen Thread ist so eine Sache.
Ich benutze die DLL mit den 'Low-Level-Routinen' in fast allen
Programmen,
die eine RS232 Kommunikation benötigen. Da müsste ich ja alle Programme
umschreiben. Ist dann doch ein wenig zu viel. Ich komme um die DLL nicht
herum. Mein erster Lösungsansatz war eigentlich die Timeout-Zeit von 3s
auf z.B. 300ms zu reduzieren. Die Frage ist dann nur, ob die Devices
nicht doch gerade in einer Interruptroutine irgendwas machen (z.B. Zeit
verbraten). Wie könnte ich denn innerhalb der DLL einen Thread
aktivieren, der die Daten von der RS232 einliest UND wie kann ich dann
dem Hauptprogramm mitteilen, dass die Daten im Puffer stehen, wenn die
DLL-Funktion bereits verlassen wurde?
Das ist hierbei mein größtes Problem. Kurz gesagt - ans Hauptprogramm
möchte ich nicht ran. Aber wahrscheinlich komm ich wohl nicht darum.
Gruß
TK
Hi
Vorab erst mal : ich programmiere meine Programme mit Delphi. Aber die
Verwendung von API-Funktionen verläuft genauso wie unter C++.
Hast du die die Routinen in eine eigene Class verpackt? Wenn nicht,
gehst du am Konzept von C++ vorbei und da sind deine Schwierigkeiten
vorprogrammiert.
MfG Spess
Ich habe die Routinen nicht in eine Klasse verpackt. Ich sehe aber hier
auch nicht das Problem. OK - nur weil ich den Borland C++ Compiler hab
muss ich ja nicht unbedingt immer auf die C++ Konzepte zurückgreifen. Im
übrigen versteht der ja auch Delphi.
Wo wäre denn der Vorteil bei der Behebung meines Problems, wenn die
Routinen in einer Klasse stecken würden?
Gruß
TK
Hi
Wie gesagt, ich komme aus der Delphi-Ecke. Der Vorteil für mich ist,
dass ich eine Serielle Schnittstelle als Komponente in ein Formular
einfügen kann. Über die Schnittstellen der Komponente wird dann auf die
Eigenschaften und Funktionen zugegriffen.
Zum Beispiel kann deine Komponente(class) einen eigenen Timer besitzen.
Der fragt in bestimmten Abständen den COM-Port ab und liest ,wenn
vorhanden, die Daten in einen internen Puffer. Danach wird eine
Nachricht (message) an das Hauptprogramm geschickt. Das Hauptprogramm
holt dann die Daten über eine Funktion der Class ab. Damit hast du die
eigentliche Behandlung des COM-Ports vom Hauptprogramm abgekoppelt. Dein
Hauptprogramm kann dann in aller Ruhe überprüfen, ob irgendwelche Sender
ein Timeout haben, ohne blockiert zu werden.
MfG Spess
Generell hab ich auch kein Problem mit Delphi. Ich hab AUCH in C++ eine
Komponente für die serielle Schnittstelle. Die kann ich hier aber nicht
benutzen (Lizenzprobleme)! Deshalb hab ich ja die DLL geschrieben. Die
kann ich nämlich weitergeben, OHNE Probleme mit anderen zu bekommen. Und
selbst eine Komponente erstellen - so weit bin ich noch nicht in die
Materie eingestiegen. Klar hat eine Komponente die Vorteile, die du
angesprochen hast. Man kann dann schön auf Ereignisse reagieren usw.
Nur ist es bei diesem Projekt so, dass ich zwar das Hauptprogramm
erstellt habe, aber dieses nur als "Demo" an einen Kunden rausging. Der
hat jetzt sein eigenes Programm entwickelt und muss eben die DLL für die
Kommunikation mit den Devices benutzen (da sind eben nicht nur RS232
Routinen drin). Da liegt jetzt das Problem. Ich bzw. er kommt ohne die
DLL nicht klar. Und die Routinen/Funktionen offen legen möchte ich dann
auch nicht.
Vielleicht gibts ja eine Möglichkeit einen GLOBALEN Puffer zu
deklarieren, den sowohl das Hauptprogramm, als auch die DLL benutzen
können. Den könnte man ja dann füllen, wenn tatsächlich Daten da sind.
Demnach müsste jede DLL Routine sofort wieder verlassen werden und das
Hauptprogramm müsste dann zyklisch den Inhalt des Puffers prüfen. Aber
auch hier seh ich eigentlich zu viel Aufwand für die DLL und das
Hauptprogramm. Momentan bin ich echt ratlos.
Gruß
TK
Hallo,
nur damit ich es verstanden habe:
- ca. 70 Geräte hängen am gleichen CommPort
- Dein Hauptprogramm ruft eine Funktion in der DLL auf um Daten an ein
einzelnes Gerät zu senden oder von einem einzelnen Gerät zu empfangen.
Unter dieser Annahme, könntest Du in der DLL einen Thread bauen der von
sich aus mit allen Geräten spricht und die Ergebnisse in ein einen
Puffer ablegt.
Deine Funktionen die von Deinem Hauptprogramm aufgerufen werden lesen
dann z.B. nicht mehr von der Schnittstelle sondern aus der
Ergebnisliste. Da da z.B. drinnsteht, das ein Timeout aufgetreten ist
muss der Funktionsaufruf nicht bis zum Timeout dauern, sondern kehrt
sofort zurück.
Allerdings musst Du mit Threads in DLLs aufpassen. Z.B. darfst Du im
Initialisierungsbereich keine Threads erzeugen oder im
Zerstörungsbereich keine Threads beenden. Falls Dein Hauptprogramm eine
Funktion "Öffen CommPort" aufruft kannst Du dort den Thread erzeugen
(und bei "Schließe CommPort" beenden).
Und du musst den Zugriff auf Deine Ergebnisse mit z.B. Critical Sections
schützen, damit nicht das Chaos losbricht wenn Dein Hauptprogramm und
Dein Thread gleichzeitig auf diese Bereiche zugreifen.
Gruß Ekkehard
@ Ekkehard
Genau so / so ähnlich hab ich mir das vorgestellt.
Jetzt mal zu meinem Verständnis: Also die DLL agiert autark und fragt
dann
zyklisch alle Teilnehmer von sich aus ab, trägt die gesammelten Daten in
einen Ereignispuffer und wartet nur noch darauf, dass das Hauptprogramm
den Puffer ausliest.
OK - soweit verstanden.
Jetzt kommt allerdings eine Kleinigkeit dazu. Es gibt ja mehrere
Funktionen innerhalb der DLL, die auch unterschiedliche Ereignisse an
den Devices auslösen. Also z.B. Datenwerte abfragen, Parameter
übergeben, Selbsttests durchführen lassen usw.
Und jede dieser Routinen benutzt letztendlich die Schnittstelle mit den
Timeoutvorgaben.
Durch den Thread könnte ich also z.B. die Hauptfunktion (nämlich
Datenwerte abfragen) automatisieren. Alle anderen Funktionen würden ohne
Threadsteuerung arbeiten wie bisher - also mit Timeout.
Aber ich denke, das wäre schon mal ein riesiger Schritt in die richtige
Richtung. Ich mach mich dann mal an die Überlegungen für einen
Threadaufbau und dann an die Programmierung.
Danke erst mal
Gruß
TK