Hallo zusammen. Ich erstelle eine SW für einen Raspberry Pi in C# (bzw. GTK# mit Mono). In der SW verwende ich die Serialport-Klasse. Das funktioniert auch soweit. Meine Frage ist: Gibt es eine Möglichkeit festzustellen, wann Serialport.Write (oder .Writeline) "fertig" ist (d.h. "alle Bytes wurden aus dem Ausgangspuffer "herausgetaktet"")? Der Grund der Frage: Ich verwende einen RS485-Transceiver im Halbduplex-Modus, d.h. nach dem Senden muss ich den Driver deaktivieren und den Receiver aktivieren. Dazu muss ich jedoch wissen, wann tatsächlich die Daten aus dem Port "herausgetaktet" wurden. Zwei mögliche "Workarounds" sind mir schon eingefallen: 1) Eine "Wartezeit" nach .Write() einfügen (z.B. 500 ms), wobei das natürlich nicht "schön" ist (da nicht deterministisch). 2) Den Receiver dauerhaft eingeschaltet lassen und die Sende-Botschaft auf der Sender-Seite mitlesen und nach vollständiger Botschaft den Driver abschalten. Was denkt ihr? Habt ihr das schon mal gemacht? Eure Anregungen sind willkommen! Viele Grüße, Alex
Alex B. schrieb: > Habt ihr das schon mal gemacht? ja, aber ohne Raspi. Ich habe einen USB-RS485 Konverter, der schaltet selbstständig ab, wenn er nichts mehr zu senden hat. Dabei musste ich nichts in C# beachten. Ich bin mir gar nicht sicher ob das Betriebssystem überhaupt mitbekommt, wenn das letzte bit übertragen wurde (also wirklich die Hardware verlassen hat)
Was sagt denn die BytesToWrite-Eigenschaft? Springt die nicht auf 0, wenn der Puffer leer ist? Wenn die nix sagt, kannst Du die Wartezeit vielleicht anhand der Baudrate etwas tunen, indem Du Wartezeit = (Anzahl Bits/Byte * Anzahl zu sendender Bytes)/ Baudrate + Sicherheitsaufschlag rechnest? (Hmm, ggf. müsste man wohl wissen, wie, wann und wie schnell beim Raspi die Daten vom Buffer des SerPort in den FIFO übertragen werden)
Kontrolle über die Hardware-Puffer/Treiber-Puffer hat man über die normale SerialPort-Klasse nicht, lediglich über die Windows-eigenen Puffer. Im .NET Micro Framework, das eher für kleinere Geräte gedacht ist (aber vermutlich in Mono nicht verfügbar ist), hat die SerialPort-Klasse eine Flush()-Methode, die hier vermutlich brauchbar gewesen wäre ;D ...aber macht die "Wandlung" nach Halbduplex nicht normalerweise der Treiber (oder gar erst die Hardware) und in der Software hat man damit gar nichts zu tun?
Alex B. schrieb: > Hallo zusammen. > > Ich erstelle eine SW für einen Raspberry Pi in C# (bzw. GTK# mit Mono). > In der SW verwende ich die Serialport-Klasse. Das funktioniert auch > soweit. > > Meine Frage ist: Gibt es eine Möglichkeit festzustellen, wann > Serialport.Write (oder .Writeline) "fertig" ist (d.h. "alle Bytes wurden > aus dem Ausgangspuffer "herausgetaktet"")? > > Der Grund der Frage: Ich verwende einen RS485-Transceiver im > Halbduplex-Modus, d.h. nach dem Senden muss ich den /Driver/ > deaktivieren und den Receiver aktivieren. Dazu muss ich jedoch wissen, > wann tatsächlich die Daten aus dem Port "herausgetaktet" wurden. > > Zwei mögliche "Workarounds" sind mir schon eingefallen: > 1) Eine "Wartezeit" nach .Write() einfügen (z.B. 500 ms), wobei das > natürlich nicht "schön" ist (da nicht deterministisch). > 2) Den Receiver dauerhaft eingeschaltet lassen und die Sende-Botschaft > auf der Sender-Seite mitlesen und nach vollständiger Botschaft den > Driver abschalten. > > Was denkt ihr? Habt ihr das schon mal gemacht? > Eure Anregungen sind willkommen! > Viele Grüße, > Alex Keine Ahnung wie das Mono implementiert. Im .NET-Framework hat der BaseStream die Methode Flush 1) die intern die Win32-Funktion FlushFileBuffers 2) aufruft. Zu FlushFileBuffers ist z.B. unter PurgeComm 3) zu finden: "Note, however, that FlushFileBuffers is subject to flow control but not to write time-outs, and it will not return until all pending write operations have been transmitted." Kurzfassung: aSerialPort.BaseStream.Flush() sollte das Problem lösen. 1) http://referencesource.microsoft.com/#System/sys/system/io/ports/SerialStream.cs,825 2) https://msdn.microsoft.com/en-us/library/windows/desktop/aa364439%28v=vs.85%29.aspx 3) https://msdn.microsoft.com/de-de/library/windows/desktop/aa363428%28v=vs.85%29.aspx Edith sagt: Mono macht da genau gar nichts, versucht noch nicht mal was zu tun https://github.com/mono/mono/blob/88d2b9da2a87b4e5c82abaea4e5110188d49601d/mcs/class/System/System.IO.Ports/WinSerialStream.cs bzw. unter Unices https://github.com/mono/mono/blob/master/mcs/class/System/System.IO.Ports/SerialPortStream.cs
:
Bearbeitet durch User
Alex B. schrieb: > da nicht deterministisch Seit wann ist ein fixes Delay "nicht deterministisch"?
:
Bearbeitet durch User
Läubi .. schrieb: > Alex B. schrieb: >> da nicht deterministisch > Seit wann ist ein fixes Delay "nicht deterministisch"? Vielleicht kenne ich mich mit Betriebssystemen nicht gut genug aus oder habe es einfach ungeschickt formuliert. Meine Annahme ist es, dass die Zeit zwischen dem Aufruf der Methode SerialPort.Write() und dem tatsächlichen physikalischen heraustakten der Bits eine unbestimmte Zeit vergeht, deren Länge von verschiedenen, nicht zu beeinflussenden Umständen (z.B. CPU-Auslastung) abhängt. Wählt man eine beliebige Verzögerung ("Delay"), dann passt dies zwar vermutlich für "die meißten" Fälle, es ist aber nicht 100%-ig sicher, dass es immer klappt.
Alex B. schrieb: > Meine Frage ist: Gibt es eine Möglichkeit festzustellen, wann > Serialport.Write (oder .Writeline) "fertig" ist (d.h. "alle Bytes wurden > aus dem Ausgangspuffer "herausgetaktet"")? Ganz einfach: Häng einen IO-Pin an die Leitung und zähl die Pegelwechsel, oder ... Alex B. schrieb: > Der Grund der Frage: Ich verwende einen RS485-Transceiver im > Halbduplex-Modus gib noch 20 Cent mehr aus und mach das Ganze Full-Duplex. Eine dritte Möglichkeit wäre, einen IO-Pin als Enable-Pin zu verwenden: Die Gegenstelle setzt dann den Pin auf high, wenn alle angefragten Daten angekommen sind. Gruß Klaus
Danke für die Anregungen, Klaus! Klaus schrieb: > gib noch 20 Cent mehr aus und mach das Ganze Full-Duplex. Ich denke das würde mehr werden, die ganze Verkabelung müsste dann zwei Leitungen mehr bekommen. Klaus schrieb: > Eine dritte Möglichkeit wäre, einen IO-Pin als Enable-Pin zu verwenden: > Die Gegenstelle setzt dann den Pin auf high, wenn alle angefragten Daten > angekommen sind. Also quasi "flow control". Ich werde es zunächst mit einem großzügigen Delay versuchen, da es in diesem Fall nicht auf eine besonders gute Latenz ankommt. Sollte ich feststellen, dass Datenverlust auftritt, dann werde ich es so versuchen, wie oben beschrieben: Auf Sender-Seite die eigenen, gesendeten Daten selbst mitlesen und erst nach erfolgreichem Senden den Treiber ausschalten. Danke euch allen und viele Grüße, Alex
Alex B. schrieb: > es ist aber nicht 100%-ig sicher, dass es > immer klappt. Eine BS- und überhaupt softwareunabhängige Methode: einen retriggerbaren Monoflop an den Ausgang schalten, der ca. eine ganze Zeichen-Zeit nach der letzten Flanke den Treiber abschaltet. Das funktioniert zuverlässig bei bekannter Baudrate bzw. muss an diese angepasst werden. Per Software liesse sich das zuverlässig nur im Low-Level-Treiber realisieren und man bräuchte einen zusätzlichen I/O dazu. Georg
Alex B. schrieb: > Ich denke das würde mehr werden, die ganze Verkabelung müsste dann zwei > Leitungen mehr bekommen. Na wenn das so ist, dann würde ich natürlich auch eher auf die Bastellösung setzen...
Klaus schrieb: > Die Gegenstelle setzt dann den Pin auf high, wenn alle angefragten Daten > angekommen sind. Das geht sinnvollerweise nur bei Punkt-zu-Punkt, nicht an einem Bus. In dem Fall kann man aber gleich Sende- und Empfangsleitungen getrennt führen und hat das ganze Problem nicht. Jetzt kommt natürlich gleich das Argument, dass man dann 2 Drähte mehr braucht und nicht nur einen: solche Kabel bekommt man aber i.d.R. sowieso nur mit Leiterpaaren. Georg
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.