Seite 1 von 1

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

Verfasst: 12.10.2024 16:12
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. :)

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

Verfasst: 12.10.2024 17:54
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

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

Verfasst: 12.10.2024 19:07
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).

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

Verfasst: 12.10.2024 20:31
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.

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

Verfasst: 14.10.2024 07:24
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.

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

Verfasst: 14.10.2024 22:58
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 ?

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

Verfasst: 15.10.2024 06:42
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

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

Verfasst: 15.10.2024 16:40
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