Skip to content

cSerialPort Advanced ​

📖 Table of Contents ​


Flow Control Details ​

Flow control coordinates the sender and receiver rates to prevent data loss. cSerialConfig supports five flow control modes.

Flow Control Types ​

ModeConstantDescription
No flow controlfcNoneNo flow control
Software flow controlfcXonXoffControlled via XON/XOFF characters
Hardware flow control RTS/CTSfcRtsCtsControlled via RTS/CTS signal lines
Hardware flow control DTR/DSRfcDtrDsrControlled via DTR/DSR signal lines
Mixed flow controlfcRtsCtsAndXonXoffBoth hardware and software flow control

Software Flow Control (XON/XOFF) ​

The sender receives XOFF(&H13) to pause sending when data volume is excessive, and XON(&H11) to resume sending.

vb
cfg.FlowControl = fcXonXoff
' Can customize XON/XOFF characters
cfg.XonChar = &H11
cfg.XoffChar = &H13

You can also manually send XON/XOFF:

vb
sp.SendXOff    ' Request peer to pause sending
sp.SendXOn     ' Request peer to resume sending

Hardware Flow Control (RTS/CTS) ​

Uses RTS/CTS signal lines for hardware handshake. Sender transmits data only when CTS is high.

vb
cfg.FlowControl = fcRtsCts
' Setting FlowControl automatically sets RtsControl to rcHandshake

Note: After enabling hardware flow control, manual SetRTS/SetDTR may be overridden by flow control mechanisms.

DTR/RTS Control Modes ​

ModeConstantDTR/RTS Behavior
DisabledcDisable/rcDisableSignal line stays low
EnabledcEnable/rcEnableSignal line stays high
HandshakedcHandshake/rcHandshakeAutomatically managed by flow control
TogglercToggleRTS only, pulls high when data present

Timeout Strategy Details ​

Win32 serial port timeout is controlled by five parameters. Understanding their working mechanism is crucial.

Timeout Parameters ​

ParameterDescription
ReadIntervalTimeoutMaximum interval between two read characters(ms)
ReadTotalTimeoutMultiplierPer-byte timeout multiplier(ms/byte)
ReadTotalTimeoutConstantRead fixed timeout(ms)
WriteTotalTimeoutMultiplierWrite per-byte timeout multiplier
WriteTotalTimeoutConstantWrite fixed timeout(ms)

Read Timeout Calculation ​

Total timeout = ReadTotalTimeoutMultiplier × requested data amount + ReadTotalTimeoutConstant

Three Preset Modes ​

1. Non-Blocking Read ​

Read returns immediately, reads data if available, returns empty if not.

vb
cfg.SetNonBlockingRead
' Equivalent to:
' ReadIntervalTimeout = MAXDWORD (&HFFFFFFFF)
' ReadTotalTimeoutMultiplier = 0
' ReadTotalTimeoutConstant = 0

2. Blocking Read ​

Wait until specified byte count is read, may block permanently.

vb
cfg.SetBlockingRead
' Equivalent to:
' ReadIntervalTimeout = 0
' ReadTotalTimeoutMultiplier = 0
' ReadTotalTimeoutConstant = 0

⚠️ Warning: Blocking mode will hang permanently if no data arrives. Recommend using with ReadTotalTimeoutConstant.

3. Read With Timeout ​

Specify total timeout duration.

vb
cfg.SetReadTimeout 2000    ' 2 second timeout
' Equivalent to:
' ReadIntervalTimeout = 50
' ReadTotalTimeoutMultiplier = 0
' ReadTotalTimeoutConstant = 2000

Custom Timeout Example ​

Calculate timeout by byte count, suitable for scenarios with known data length:

vb
' Per byte 10ms + fixed 100ms
cfg.ReadIntervalTimeout = 50
cfg.ReadTotalTimeoutMultiplier = 10
cfg.ReadTotalTimeoutConstant = 100
' Reading 100 bytes total timeout = 10×100 + 100 = 1100ms

Binary Protocol Handling ​

Send Binary Frame ​

vb
' Build Modbus RTU request frame
Dim frame(7) As Byte
frame(0) = &H01    ' Slave address
frame(1) = &H03    ' Function code: read holding registers
frame(2) = &H00    ' Start address high byte
frame(3) = &H00    ' Start address low byte
frame(4) = &H00    ' Register count high byte
frame(5) = &H0A    ' Register count low byte
frame(6) = &HC5    ' CRC low byte
frame(7) = &HCD    ' CRC high byte

sp.WriteData frame

Receive and Parse Binary Frame ​

vb
Private Sub m_Port_DataReceived(ByVal BytesCount As Long)
    Dim buf() As Byte
    Dim n As Long
    n = m_Port.ReadData(buf)

    If n < 5 Then Exit Sub    ' Modbus response at least 5 bytes

    ' Parse Modbus response
    Dim slaveAddr As Byte
    Dim funcCode As Byte
    slaveAddr = buf(0)
    funcCode = buf(1)

    If funcCode And &H80 Then
        ' Exception response
        Dim errCode As Byte
        errCode = buf(2)
        Debug.Print "Modbus exception: " & errCode
    Else
        ' Normal response
        Dim byteCount As Byte
        byteCount = buf(2)
        Debug.Print "Received " & byteCount & " bytes of data"
    End If
End Sub

Hex Display Debugging ​

vb
Private Sub m_Port_DataReceived(ByVal BytesCount As Long)
    Dim buf() As Byte
    m_Port.ReadData buf

    Dim hexStr As String
    Dim i As Long
    For i = 0 To UBound(buf)
        hexStr = hexStr & Right$("0" & Hex$(buf(i)), 2) & " "
    Next
    Debug.Print "RX: " & Trim$(hexStr)
End Sub

Virtual Serial Ports & Loopback Testing ​

Virtual Serial Port Software ​

In development environments without physical serial ports, virtual serial port software can create port pairs:

  • com0com (Free, open source)
  • Virtual Serial Port Driver (Commercial software)
  • VSPD (Commercial software)

After installation, create virtual serial port pairs (e.g., COM3 ↔ COM4). Data sent to COM3 will appear in COM4's receive buffer.

Loopback Test Code ​

vb
Public Sub TestLoopback()
    Dim spTx As New cSerialPort
    Dim spRx As New cSerialPort

    ' Open both ports of the virtual pair
    spTx.PortName = "COM3"
    spRx.PortName = "COM4"

    Dim cfg As New cSerialConfig
    cfg.BaudRate = br9600
    Set spTx.Config = cfg
    Set spRx.Config = cfg.Clone()

    If Not spTx.OpenPort() Then
        Debug.Print "Failed to open COM3"
        Exit Sub
    End If
    If Not spRx.OpenPort() Then
        Debug.Print "Failed to open COM4"
        spTx.ClosePort
        Exit Sub
    End If

    ' Clear buffers
    spTx.PurgeAll
    spRx.PurgeAll

    ' Send
    Dim testStr As String
    testStr = "LOOPBACK_TEST_12345"
    spTx.WriteText testStr
    Debug.Print "Sent: " & testStr

    ' Wait for data arrival
    Dim t As Single
    t = Timer
    Do While spRx.InBufferCount < Len(testStr) And (Timer - t) < 2
        DoEvents
    Loop

    ' Receive
    Dim received As String
    received = spRx.ReadExisting()
    Debug.Print "Received: " & received

    If received = testStr Then
        Debug.Print "[PASS] Loopback test passed"
    Else
        Debug.Print "[FAIL] Loopback test failed"
    End If

    spTx.ClosePort
    spRx.ClosePort
End Sub

Dynamic Configuration Management ​

Runtime Configuration Changes ​

vb
sp.OpenPort "COM3"

' Change baud rate
sp.Config.BaudRate = br115200
sp.ApplyConfig          ' Manually apply to opened port

' Read actual configuration from port
sp.RefreshConfig
Debug.Print "Actual baud rate: " & sp.Config.BaudRate

Configuration Cloning ​

vb
Dim cfg1 As New cSerialConfig
cfg1.BaudRate = br115200
cfg1.Parity = ptEven

' Clone configuration (independent)
Dim cfg2 As cSerialConfig
Set cfg2 = cfg1.Clone()

cfg2.BaudRate = br9600
Debug.Print cfg1.BaudRate   ' Still 115200

Mode String ​

vb
Dim cfg As New cSerialConfig
cfg.FromModeString "baud=115200 parity=N data=8 stop=1"
Debug.Print cfg.ToModeString()   ' baud=115200 parity=N data=8 stop=1

Modbus RTU Practice ​

Complete Modbus RTU Master Request ​

vb
Public Function ModbusReadHoldingRegisters( _
    ByVal sp As cSerialPort, _
    ByVal SlaveAddr As Byte, _
    ByVal StartAddr As Integer, _
    ByVal Quantity As Integer) As Byte()

    ' Build request frame
    Dim frame(7) As Byte
    frame(0) = SlaveAddr
    frame(1) = &H03    ' Function code: read holding registers
    frame(2) = (StartAddr And &HFF00) \ &H100
    frame(3) = StartAddr And &HFF
    frame(4) = (Quantity And &HFF00) \ &H100
    frame(5) = Quantity And &HFF

    ' Calculate CRC16
    Dim crc As Long
    crc = CalcCRC16(frame, 6)
    frame(6) = crc And &HFF
    frame(7) = (crc And &HFF00) \ &H100

    ' Clear buffers and send
    sp.PurgeAll
    sp.WriteData frame

    ' Wait for response (1 second timeout)
    Dim t As Single
    t = Timer
    Do While sp.InBufferCount < 5 And (Timer - t) < 1
        DoEvents
    Loop

    ' Read response
    Dim buf() As Byte
    Dim n As Long
    n = sp.ReadData(buf)
    If n >= 5 Then
        ModbusReadHoldingRegisters = buf
    End If
End Function

Usage Example ​

vb
Dim sp As New cSerialPort
sp.PortName = "COM3"
sp.Config.BaudRate = br9600
sp.Config.DataBits = 8
sp.Config.Parity = ptEven      ' Modbus RTU typically uses even parity
sp.Config.StopBits = sb1
sp.OpenPort

' Read holding registers from slave 1, start address 0, count 10
Dim response() As Byte
response = ModbusReadHoldingRegisters(sp, 1, 0, 10)

If UBound(response) >= 0 Then
    ' Parse response data
    Dim byteCount As Byte
    byteCount = response(2)
    Debug.Print "Received " & byteCount & " bytes of data"
End If

sp.ClosePort

Last Updated: 2026-07-05

VB6 and LOGO copyright of Microsoft Corporation