OpenSerialPort(), In/Out-Buffergröße ermitteln

Windowsspezifisches Forum , API ,..
Beiträge, die plattformübergreifend sind, gehören ins 'Allgemein'-Forum.
Benutzeravatar
TheCube
Beiträge: 168
Registriert: 20.07.2010 23:59
Computerausstattung: Risen 3400G 16MB Win10-64Bit
Wohnort: NRW

OpenSerialPort(), In/Out-Buffergröße ermitteln

Beitrag von TheCube »

Hallo,
ich frage diesmal nach einer Windowsfunktion (deshalb hier) um die realen COM-Buffergrößen zu erhalten.
(Den z.T. ähnlich gelagerten alten Thread https://www.purebasic.fr/german/viewtop ... er#p365820 lasse ich mal schlafen ...)
Mir ist bewusst das mir die Buffergrössen egal sein könnten, wenn ich mit eigenem COM-Thread alles sofort in eigenen Ringpuffer transferiere.
Aber meine SW läuft schon stabil und ich möchte nur im worst case den % Füllgrad berechnen bzw. wissen ab wieviel Bytes im Buffer mit Datenverlust
zu rechnen ist.
Setup: PB6.04-6.12 64Bit / Win10 und Win11 x64 / Silicon Labs CP210x USB to UART Bridge als COM-Device

Code: Alles auswählen

If OpenSerialPort(0, "COM28", 500000, #PB_SerialPort_NoParity, 8, 1, #PB_SerialPort_NoHandshake, 1024, 1024)
  Debug "COM Success"
  Repeat
    Debug (AvailableSerialPortInput(0)) ; Läuft bei mir bis max. 65536 hoch, stagniert dann. Weitere COM-Daten werden verworfen.  
    Debug (SerialPortError(0))		; Zeigt bei mir immer 28, auch mit vollgelaufenem In-Buffer
    Delay (100)
  ForEver  
Else
  Debug "COM Failed"
EndIf
Mit Hilfe einer externen COM-Datensenders lasse ich testweise den eigenen COM-Input-Puffer volllaufen.
Ich komme so bis 64K, egal was ich in der Windows-Systemsteuerung einstelle.
Andere haben bei anderen Setups oder COM-Adaptern ("Echte COM", CH341SER, FTDIxxx, etc.) auch weniger, z.B. gerademal 4K.

Daher meine Frage nach einer Windows-Api-Funktion, die in meinem Fall eben 65536 zurückgeben würde ... falls es sowas gibt.
Denn das stumpfe Ausprobieren oben ist natürlich Müll und nicht universell.
Ein passender Funktionsname zum Googlen wäre schon super, eine Lösung als PB-Codeschnipsel traumhaft. :)
DePe
Beiträge: 194
Registriert: 26.11.2017 16:17

Re: OpenSerialPort(), In/Out-Buffergröße ermitteln

Beitrag von DePe »

Ich habe die Funktion nicht ausprobiert, aber es gibt 'GetCommProperties' mit der man 'dwMaxRxQueue' abfragen kann:

Zitat:
The maximum size of the driver's internal input buffer, in bytes. A value of zero indicates that no maximum value is imposed by the serial provider.

Peter
Benutzeravatar
H.Brill
Beiträge: 496
Registriert: 15.10.2004 17:42
Wohnort: 66557 Neunkirchen

Re: OpenSerialPort(), In/Out-Buffergröße ermitteln

Beitrag von H.Brill »

Wozu braucht man sowas ?
Das Volllaufen des Puffers, wie im obigen Code ist ja ziemlich sinnfrei.
Soviel, wie ich weiß, wird ja bei jedem Lesen des Puffers (ReadSerialPortData()) der Puffer geleert.
Somit würde ja auch ein Auslesen der Puffergröße nicht viel bringen.
Wenn du wissen möchtest , wann du 65536 gelesen hast, bräuchtest du doch nur
bei jedem gelesen ReadSerialPortData die gelesenen Bytes addieren. Die gibt ja
ReadSerialPortData() zurück.

Was die 64 kb betrifft, wenn du die am Stück lesen tust, könnte das auch am drunter liegenden Treiber liegen.
Die 64 kb erinnern mich da an die damalige begrenzte Stringlänge bei versch. Sprachen und auch an die DOS-Zeit.
Das war damals so eine 'magische Zahl'. Gottseidank sind diese Zeiten vorbei und Strings können so lang sein, wie
es halt das RAM hergibt Die Listbox war ja auch so ein Fall, wo nicht mehr als 65535 Einträge gingen.
aber es gibt 'GetCommProperties' mit der man 'dwMaxRxQueue' abfragen kann:
Die DCB - Struktur, die einige Daten enthält, wird aber nur die Maximalwerte, die mit
OpenSerialPort() mit den beiden letzten Parametern gesetzt wurden, zurück geben und
nicht die Summe Bytes, die seit Beginn der Sitzung bereits gelesen wurden. In dem Falle
halt RX (Eingangspuffer).
PB 6.10
Benutzeravatar
TheCube
Beiträge: 168
Registriert: 20.07.2010 23:59
Computerausstattung: Risen 3400G 16MB Win10-64Bit
Wohnort: NRW

Re: OpenSerialPort(), In/Out-Buffergröße ermitteln

Beitrag von TheCube »

@DePe: Danke, probier ich mal aus ... kann aber etwas dauern. :allright:

@H.Brill: Danke erstmal für deinen Beitrag,
Aber das Lesen Puffers mit ReadSerialPortData() entnimmt nur soviele Bytes wie man angibt.
Gibt man mehr an als im Puffer ist blockt der Befehl sogar, weshalb man (wenn man den Puffer komplett haben will)
das z.B. mit ReadSerialPortData(0, *Puffer, AvailableSerialPortInput(0)) macht.
Wozu braucht man sowas ? Das Volllaufen des Puffers, wie im obigen Code ist ja ziemlich sinnfrei.
Absolut, war nur um im Debugfenster die nutzbare Buffergrösse zu erkennen, eben weil diese nicht mehr weiter steigt .... /:->
Und ich finde es kann je nach Anwendung schon interessant sein, ob nun 4K oder 64K zur Verfügung stehen.
Benutzeravatar
PIC18F2550
Beiträge: 104
Registriert: 29.04.2024 09:10
Computerausstattung: Server HP Proliant G7
PC AMD FX(tm)-9590, 64Gb Ram, 2x 2TB Raid5 SAS

Re: OpenSerialPort(), In/Out-Buffergröße ermitteln

Beitrag von PIC18F2550 »

Sende einfach z.B. das Zeichen "A" 64k mal, und hole danach die empfangen Zechen ab.
Die Anzahl der Zeichen ist die Summe über alle Puffer.
Barbarus hic ergo sum, quia non intellegor ulli.
Ein Barbar bin ich hier, da ich von keinem verstanden werde.
ʎɐqǝ ıǝq ɹnʇɐʇsɐʇ ǝuıǝ ɹǝpǝıʍ ǝıu ǝɟnɐʞ ɥɔı ´uuɐɯ ɥo
Benutzeravatar
TheCube
Beiträge: 168
Registriert: 20.07.2010 23:59
Computerausstattung: Risen 3400G 16MB Win10-64Bit
Wohnort: NRW

Re: OpenSerialPort(), In/Out-Buffergröße ermitteln

Beitrag von TheCube »

@ PIC18F2550: Klar, mit externer Hilfe kann man das rausfinden (bei dir quasi per Nullmodem ? ) oder (wie ich) lässt sich vom µC am USB-COM Daten senden, holt sie nicht ab, und schaut wann AvailableSerialPortInput(0)) nicht mehr wächst, dann ist man schon fertig.
So oder so bleibts aber rumprobieren, was selbst bei 500000 Baud zu lange dauern kann. Ungeeignet für Exe in ggf. wechselden PC/OS Umgebungen.

Basierend auf einem Codeschnipsel von Helle, 2008, wollte ich jetzt mal die Parameter auslesen, klappt aber noch nicht.
CreateFile_()-Rückgabewert RS232 ist immer -1, Unicode wie Ascii ... :cry:

Code: Alles auswählen

ComP.COMMPROP
DcbP.DCB

PortUni.s="Com28"                           ; Auch Schreibweise ""COM28" erfolglos getestet
PortAscii.s = Space(Len(PortUni))           ; Nur zum Testen
PokeS(@PortAscii, PortUni, -1, #PB_Ascii)   ; mit CreateFile_() unten
RS232 = CreateFile_(PortAscii, #GENERIC_READ | #GENERIC_WRITE, 0, #Null, #OPEN_EXISTING, #Null, #Null)
Debug RS232

GetCommState_(RS232, @ComP)
Debug ComP\dwMaxBaud
Debug ComP\dwMaxRxQueue

GetCommState_(RS232, @DcbP)
Debug DcbP\BaudRate             ; =  115200 (Ermttelt per ext Prg ComPortInfo.exe)
Debug DcbP\XonLim		; =  32768  (Ermttelt per ext Prg ComPortInfo.exe)
Debug DcbP\XoffLim		; =   8192  (Ermttelt per ext Prg ComPortInfo.exe)

CloseHandle_(RS232)
Vielleicht geht das 16 Jahre später ja so einfach nicht mehr ?
DePe
Beiträge: 194
Registriert: 26.11.2017 16:17

Re: OpenSerialPort(), In/Out-Buffergröße ermitteln

Beitrag von DePe »

Du kannst nur 'COM1' bis 'COM9' verwenden, ansonst musst du '\\.\COMxx' schreiben.

Zitat:
For example, if you want to open the system's serial communications port 1, you can use "COM1" in the call to the CreateFile function. This works because COM1–COM9 are part of the reserved names in the NT namespace, although using the "\\.\" prefix will also work with these device names. By comparison, if you have a 100 port serial expansion board installed and want to open COM56, you cannot open it using "COM56" because there is no predefined NT namespace for COM56. You will need to open it using "\\.\COM56" because "\\.\" goes directly to the device namespace without attempting to locate a predefined alias.

Dein Beispiel funktioniert hier mit COM1: "RS232 = CreateFile_("COM1", ..."

Code: Alles auswählen

[06:38:51] Waiting for executable to start...
[06:38:50] Executable type: Windows - x86  (32bit, Unicode, Thread, Purifier)
[06:38:51] Executable started.
[06:38:51] [Debug] 184
[06:38:51] [Debug] 1249536
[06:38:51] [Debug] 459264
[06:38:51] [Debug] 1200
[06:38:51] [Debug] 2048
[06:38:51] [Debug] 512
[06:38:51] The Program execution has finished.
Peter
Benutzeravatar
TheCube
Beiträge: 168
Registriert: 20.07.2010 23:59
Computerausstattung: Risen 3400G 16MB Win10-64Bit
Wohnort: NRW

Re: OpenSerialPort(), In/Out-Buffergröße ermitteln

Beitrag von TheCube »

@DePe: Da wär ich wohl niemals drauf gekommen :freak: Danke für die Korrektur !
Damit ist dwMaxRxQueue (mit bei mir 532480) wohl wie befürchtet raus, aber XonLim x 2 = Mein realer In-Buffer interessant.
Das würde auch bei deinem 4096-Byte In-Buffer passen.

Ob das Zufall ist und/oder inwieweit überhaupt verlässlich .... wer weiss.

Hier noch ein Codeschnipsel um sich alle COMMPROP und DCB Strukurwerte anzusehen, falls es jemand braucht:
(Darunter auch noch meine Werte ...)

Code: Alles auswählen

ComP.COMMPROP
DcbP.DCB

PortUni.s="\\.\COM28"                       ; "\\.\" prefix for COM>9 !
RS232 = CreateFile_(PortUni, #GENERIC_READ | #GENERIC_WRITE, 0, #Null, #OPEN_EXISTING, #Null, #Null)
Debug RS232
Delay(1000)

GetCommState_(RS232, @ComP)
Debug "----- Structure COMMPROP: -----------------"
Debug StrU(ComP\wPacketLength,#PB_Word) + " .... wPacketLength"
Debug StrU(ComP\wPacketVersion,#PB_Word) + " .... wPacketVersion"
Debug StrU(ComP\dwServiceMask,#PB_Long) + " .... dwServiceMask"
Debug StrU(ComP\dwReserved1,#PB_Long) + " .... dwReserved1"
Debug StrU(ComP\dwMaxTxQueue,#PB_Long) + " .... dwMaxTxQueue"
Debug StrU(ComP\dwMaxRxQueue,#PB_Long) + " .... dwMaxRxQueue"
Debug StrU(ComP\dwMaxBaud,#PB_Long) + " .... dwMaxBaud"
Debug StrU(ComP\dwProvSubType,#PB_Long) + " .... dwProvSubType"
Debug StrU(ComP\dwProvCapabilities,#PB_Long) + " .... dwProvCapabilities"
Debug StrU(ComP\dwSettableParams,#PB_Long) + " .... dwSettableParams"
Debug StrU(ComP\dwSettableBaud,#PB_Long) + " .... dwSettableBaud"
Debug StrU(ComP\dwMaxBaud,#PB_Long) + " .... dwMaxBaud"
Debug StrU(ComP\wSettableData,#PB_Word) + " .... wSettableData"
Debug StrU(ComP\wSettableStopParity,#PB_Word) + " .... wSettableStopParity"
Debug StrU(ComP\dwCurrentTxQueue,#PB_Long) + " .... dwCurrentTxQueue"
Debug StrU(ComP\dwCurrentRxQueue,#PB_Long) + " .... dwCurrentRxQueue"
Debug StrU(ComP\dwProvSpec1,#PB_Long) + " .... dwProvSpec1"
Debug StrU(ComP\dwProvSpec2,#PB_Long) + " .... dwProvSpec2"

GetCommState_(RS232, @DcbP)
Debug "" : Debug "----- Structure DCB: ---------------------"
Debug StrU(DcbP\DCBlength,#PB_Long) + " .... DCBlength"
Debug StrU(DcbP\BaudRate,#PB_Long) + " .... BaudRate"
Debug StrU(DcbP\fbits,#PB_Long) + " .... fbits"
Debug StrU(DcbP\XonLim,#PB_Word) + " .... XonLim"
Debug StrU(DcbP\XoffLim,#PB_Word) + " .... XoffLim"
Debug StrU(DcbP\ByteSize,#PB_Byte) + " .... ByteSize"
Debug StrU(DcbP\Parity,#PB_Byte) + " .... Parity"
Debug StrU(DcbP\StopBits,#PB_Byte) + " .... StopBits"
Debug StrU(DcbP\XonChar,#PB_Byte) + " .... XonChar"
Debug StrU(DcbP\XoffChar,#PB_Byte) + " .... XoffChar"
Debug StrU(DcbP\ErrorChar,#PB_Byte) + " .... ErrorChar"
Debug StrU(DcbP\EofChar,#PB_Byte) + " .... EofChar"
Debug StrU(DcbP\EvtChar,#PB_Byte) + " .... EvtChar"

CloseHandle_(RS232)
End

Code: Alles auswählen

; Test "TheCube":
; Driver             : C:\Windows\system32\DRIVERS\silabser.sys (Version: 6.7.3  Date: 2018-02-16  Company: Silicon Laboratories Inc.)
; FriendlyName       : Silicon Labs CP210x USB To UART Bridge (COM28)
; ----- Structure COMMPROP: -----------------
; 28 .... wPacketLength
; 0 .... wPacketVersion
; 500000 .... dwServiceMask
; 1 .... dwReserved1
; 2147483648 .... dwMaxTxQueue
; 532480 .... dwMaxRxQueue
; 1249536 .... dwMaxBaud
; 0 .... dwProvSubType
; 0 .... dwProvCapabilities
; 0 .... dwSettableParams
; 0 .... dwSettableBaud
; 1249536 .... dwMaxBaud
; 0 .... wSettableData
; 0 .... wSettableStopParity
; 0 .... dwCurrentTxQueue
; 0 .... dwCurrentRxQueue
; 0 .... dwProvSpec1
; 0 .... dwProvSpec2
; 
; ----- Structure DCB: ---------------------
; 28 .... DCBlength
; 500000 .... BaudRate
; 1 .... fbits
; 32768 .... XonLim
; 8192 .... XoffLim
; 8 .... ByteSize
; 0 .... Parity
; 0 .... StopBits
; 17 .... XonChar
; 19 .... XoffChar
; 0 .... ErrorChar
; 0 .... EofChar
; 0 .... EvtChar
Antworten