Delphi-PRAXiS
Seite 2 von 4     12 34      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi COM Port Daten auslesen und auf bestimmtes Char reagieren (https://www.delphipraxis.net/188192-com-port-daten-auslesen-und-auf-bestimmtes-char-reagieren.html)

AJ_Oldendorf 8. Feb 2016 20:19

AW: COM Port Daten auslesen und auf bestimmtes Char reagieren
 
@Photoner:

Danke, das klingt sehr interessant.
Also das würde dann so aussehen, oder?

Delphi-Quellcode:
ReadIntervalTimeout := MaxDWord;
ReadTotalTimeoutConstant := 0;
ReadTotalTimeoutMultiplier := 0;

TmpMask := EV_RXFLAG;
WaitCommEvent(MyHandle, TmpMask, @rOverlapped);

ReadFile (MyHandle, ReceiveBuffer, 1024, ReceivedBytes, @rOverlapped);
Und wenn das Event von WaitCommEvent getriggert wird, rufe ich ReadFile auf oder?
Dann brauch ich doch bei dem ReadFile auch kein Overlapped Event mehr übergeben, da dies ja bereits getriggert wurde, richtig?

Grüße

AJ_Oldendorf 9. Feb 2016 07:20

AW: COM Port Daten auslesen und auf bestimmtes Char reagieren
 
Ich habe das mal so versucht, dass ich die Zeiten entsprechend gesetzt habe und anschließend mit WaitCommEvent auf das #10 gewartet habe. Anschließend reagiere ich auf das Event mit ReadFile:

Delphi-Quellcode:
ReadFile (MyHandle, ReceiveBuffer, 1024, ReceivedBytes, Nil);
Leider ist der ReceiveBuffer an dieser Stelle immer leer und auch die ReceivedBytes sind 0.

Frage ich die ReceivedBytes nach dem ReadFile so ab
Delphi-Quellcode:
ReceivedBytes := rOverlapped.InternalHigh;
dann stehen da 4 Bytes als Anzahl. Aber leider habe ich immer noch nicht die Daten die gelesen wurden, da mit ReadFile anscheind keine Daten gelesen wurden

Photoner 9. Feb 2016 10:05

AW: COM Port Daten auslesen und auf bestimmtes Char reagieren
 
WaitCommEvent

"If hFile was opened with FILE_FLAG_OVERLAPPED and lpOverlapped is not NULL, WaitCommEvent is performed as an overlapped operation. In this case, the OVERLAPPED structure must contain a handle to a manual-reset event object (created by using the CreateEvent function).

If hFile was not opened with FILE_FLAG_OVERLAPPED, WaitCommEvent does not return until one of the specified events or an error occurs."

In dem Overlapped Record muss also ein Handle auf ein Event (das mit CreateEvent erzeugt wird) drin sein. Wie schaut
Delphi-Quellcode:
rOverlapped
aus?

Alternativ:

Lass das FILE_FLAG_OVERLAPPED mal im CreateFile weg und verzichte auch danach darauf. Mir selbst ist nicht ganz klar wie der asynchrone Zugriff denn genau funktioniert. Ich glaube du musst vor dem ReadFile die Funktion WaitForSingleObject mit dem oben erwähnten Handle aufrufen. Synchron tuts hier auch da der Rücksprung aus WaitCommEvent ohne das
Delphi-Quellcode:
rOverlapped
erst kommt wenn dein RX_Char #10 tatsächlich im Buffer ist.

AJ_Oldendorf 9. Feb 2016 10:15

AW: COM Port Daten auslesen und auf bestimmtes Char reagieren
 
hEvent wird gesetzt beim Init des ComPorts:

Delphi-Quellcode:
rOverlapped.hEvent := CreateEventA (NIL, True, False, NullStr);
Dann kommt das WaitCommEvent wie oben schonmal geschrieben und wenn dieses getriggert wird sieht mein Aufruf so aus:

Delphi-Quellcode:
ReadFile (MyHandle, ReceiveBuffer, 1024, ReceivedBytes, Nil); //<- ReceivedBytes ist hier 0
ReceivedBytes := SeriellComp.rOverlapped.InternalHigh; //<- ReceivedBytes ist hier 4
ResetEvent(rOverlapped.hEvent);
So wäre das ja richtig von der Reihenfolge oder?

Grüße

AJ_Oldendorf 9. Feb 2016 10:48

AW: COM Port Daten auslesen und auf bestimmtes Char reagieren
 
@Sir Rufo...
Zitat:

Also ich würde so etwas immer aufteilen.

Eine Klasse holt Bytefolgen vom ComPort ab und gibt diese mit dem Zeitstempel weiter.

Eine Klasse nimmt die Bytefolge/Zeitstempel Nachricht und baut bei jedem Vorkommen von #13#10 eine Nachricht mit Bytefolge/Zeitstempel und gibt diese weiter.
Ich habe jetzt mal Byteweise die COM abgefragt und mir entsprechend beim Auftreten meines #10 den String zusammen gebaut. Das ist ja im Endeffekt ein Pollen der Seriellen Schnittstelle und man merkt dabei "deutlich", dass das mehr Rechenleistung benötigt.

Der bessere Weg ist auf ein bestimmtes Zeichen nur zur Triggern (WaitCommEvent) und dann die Daten auslesen.
Das Problem ist nur, dass dann bei mir nichts im Buffer steht wenn ich ReadFile nach dem WaitCommEvent aufrufe

Photoner 9. Feb 2016 11:02

AW: COM Port Daten auslesen und auf bestimmtes Char reagieren
 
Der Rücksprung aus der Funktion WaitCommEvent erfolgt sofort obwohl das Ereignis RX_Char noch gar nicht eingetreten ist. Das Readfile danach findet dann meist auch nichts.

WaitForSingleObject ist das Stichwort.

Diese Funktion wartet auf ein bestimmtes Ereignis und hat einen Timeout.

Wenn das Event RX_Char auslöst, dann wird das Event im Overlapped signalisiert und ein Rücksprung aus WaitForSingleObject erfolgt.


WaitCommEvent
WaitForSingleObject
Readfile

Photoner 9. Feb 2016 11:05

AW: COM Port Daten auslesen und auf bestimmtes Char reagieren
 
Oder du verzichtest komplett auf das Overlapped (== synchroner Zugriff) und dann erfolgt der Rücksprung aus WaitCommEvent erst wenn das Event auslöst oder ein Fehler passiert. In den MSDN Links steht alles was du brauchst.

AJ_Oldendorf 9. Feb 2016 11:10

AW: COM Port Daten auslesen und auf bestimmtes Char reagieren
 
Das habe ich auch so.

Mein Thread:

Delphi-Quellcode:
while not Terminated do
begin
  HandleBuffer[0] := rOverlapped.hEvent;
  HandleBuffer[1] := wOverlapped.hEvent;
  Return := MsgWaitForMultipleObjects (Handles, HandleBuffer, False,
                                       2000, QS_ALLINPUT);
  if Terminated then exit;
  Case Return of
    WAIT_OBJECT_0  : begin            
                       ReadFile (MyHandle, ReceiveBuffer, 1024, ReceivedBytes, Nil); //<- ReceivedBytes = 0
                       ReceivedBytes := rOverlapped.InternalHigh; //<- ReceivedBytes = 4
                       //ReceiveBuffer ist leer
                       ResetEvent(rOverlapped.hEvent);
                       rOverlapped.Offset := 0;
                       rOverlapped.OffsetHigh := 0;
                       if ReceivedBytes > 0 then
                       begin
...
WAIT_OBJECT_0+1 ist fürs Schreiben.

Abfrage der Schnittstelle:

Delphi-Quellcode:
rOverlapped.Offset    := 0;
rOverlapped.OffsetHigh := 0;

TmpMask := EV_RXFLAG;
WaitCommEvent(MyHandle, TmpMask, @rOverlapped);
Sollte dem von dir entsprechen...
Zeiten sind beim Init entsprechend auf 0 oder MaxDWord

AJ_Oldendorf 9. Feb 2016 11:17

AW: COM Port Daten auslesen und auf bestimmtes Char reagieren
 
Habe bei dem ReadFile anstatt dem Nil als letzten Parameter nochmal die gleiche Overlapped Struktur angegeben.
Dann bekomme ich auch in den ReceivedBytes was zurück. Nämlich die angegebenen 1024. Ich will ja aber keine 1024 lesen sondern immer nur zwischen zwei #10 Characters.

Sir Rufo 9. Feb 2016 11:23

AW: COM Port Daten auslesen und auf bestimmtes Char reagieren
 
Zitat:

Zitat von AJ_Oldendorf (Beitrag 1329845)
@Sir Rufo...
Zitat:

Also ich würde so etwas immer aufteilen.

Eine Klasse holt Bytefolgen vom ComPort ab und gibt diese mit dem Zeitstempel weiter.

Eine Klasse nimmt die Bytefolge/Zeitstempel Nachricht und baut bei jedem Vorkommen von #13#10 eine Nachricht mit Bytefolge/Zeitstempel und gibt diese weiter.
Ich habe jetzt mal Byteweise die COM abgefragt und mir entsprechend beim Auftreten meines #10 den String zusammen gebaut. Das ist ja im Endeffekt ein Pollen der Seriellen Schnittstelle und man merkt dabei "deutlich", dass das mehr Rechenleistung benötigt.

Der bessere Weg ist auf ein bestimmtes Zeichen nur zur Triggern (WaitCommEvent) und dann die Daten auslesen.
Das Problem ist nur, dass dann bei mir nichts im Buffer steht wenn ich ReadFile nach dem WaitCommEvent aufrufe

So sollst du das ja auch nicht machen :stupid:

Hole dir alles was du vom ComPort kriegen kannst. Das ist ja eine Bytefolge. Diese packst du dann in einen Record
Delphi-Quellcode:
TDataBlock = record
  Data: TBytes;
  Timestamp: TDateTime;
end;
und den dann in eine Queue. Diese Queue wird dann von einem anderen Thread abgefragt und verarbeitet. Dort erfolgt dann das Untersuchen und Zerteilen der Nachrichten und wenn eine komplette Nachricht erkannt wurde, dann schickt dieser Thread die Nachricht raus bzw. reicht diese Nachricht an eine weitere Queue, wo dann ein Versender-Thread diese Queue abfragt und die Nachrichten an die Empfänger schickt.

Durch die unterschiedlichen Threads laufen Empfänger, Zerteiler und Versender völlig unabhängig voneinander und stören sich folglich nicht gegenseitig.

Das Konzept selber ist eine DataFlow-Pipeline und eine Implementierung findest du
https://github.com/gabr42/OmniThread...1_Pipeline.pas


Alle Zeitangaben in WEZ +1. Es ist jetzt 13:42 Uhr.
Seite 2 von 4     12 34      

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz