Skip to content

[Windows] Possible byte loss due to missing SetupComm/WaitCommEvent and non-standard CommTimeouts #217

Description

@eca1227

Describe the problem

On Windows, responses from a serial device occasionally arrive with exactly 1 byte missing at the head (e.g., IDO 06,F0,... → DO 06,F0,...). Same hardware with a C++ MFC implementation using direct Win32 calls (SetupComm + SetCommMask(EV_RXCHAR) + WaitCommEvent + drain-until-empty loop, MSDN-standard CommTimeouts) runs thousands of cycles without any byte loss. The Go library skips SetupComm and WaitCommEvent, and uses a non-standard CommTimeouts pattern (MAXDWORD, MAXDWORD, 0x7FFFFFFE — labeled "CH340 hack" in source). The hypothesis is that without event-driven drain, gaps between Read() calls allow the driver RX queue (default size, possibly small) to drop bytes under bursty traffic.

To reproduce

Connect to a serial device that emits short responses (~30 bytes) at ~200ms intervals (e.g., a polled status interface returning 8 hex pairs).
Send another short command via Write() immediately after each response.
Loop for several hundred cycles.
Observe: occasional 1-byte truncation at the start of an incoming response. Frequency ~1 per a few hundred cycles on RS-232 at 57600 baud.

// SERVER (controller emulator) — run on COM4
package main

import (
	"bytes"
	"log"
	"time"
	"go.bug.st/serial"
)

func main() {
	p, err := serial.Open("COM4", &serial.Mode{BaudRate: 57600,
		DataBits: 8, Parity: serial.NoParity, StopBits: serial.OneStopBit})
	if err != nil { log.Fatal(err) }
	defer p.Close()
	p.SetReadTimeout(1 * time.Second)

	buf := make([]byte, 4096)
	var accum []byte
	resp := []byte("IDI 0F,12,34,56,78,9A,BC,DE\r\n")
	for {
		n, err := p.Read(buf)
		if err != nil { return }
		if n == 0 { continue }
		accum = append(accum, buf[:n]...)
		for {
			idx := bytes.Index(accum, []byte("\r\n"))
			if idx < 0 { break }
			accum = accum[idx+2:]
			// 즉시 응답 (실제 controller 처럼 빠르게)
			p.Write(resp)
		}
	}
}

Please double-check that you have reported each of the following

before submitting the issue.

  • I've provided the FULL source code that causes the problem
  • I've provided all the actions required to reproduce the problem

Expected behavior

Bytes delivered by the driver to the application should not be silently dropped. The C++ Win32 pattern (SetupComm(handle, 4096, 4096) + SetCommMask(EV_RXCHAR) + WaitCommEvent + do { ReadFile } while (n > 0)) on identical hardware delivers all bytes intact for 1000+ cycles. Reading via this library should give equivalent reliability.

Operating system and version

Windows 10 (also reproducible on Windows 11). USB-Serial RS-232 adapter at 57600 8N1, 1m cable. go.bug.st/serial v1.6.4, Go 1.26.

Please describe your hardware setup

To reproduce

  1. Install com0com (https://com0com.sourceforge.net/) — creates virtual COM3↔COM4.
  2. Run server (provided below) on COM4 — echoes "IDI ..." responses.
  3. Run client (provided above) on COM3 — polls every 300ms.
  4. Wait several hundred cycles.

Note: byte loss is hardware-dependent. Virtual com0com driver may not
reproduce it exactly. On physical hardware (RS-232 + USB-Serial adapter +
real controller), it reproduces consistently at ~1 per 200-800 cycles.
The underlying concern is the code-level analysis below.

Additional context

No response

Issue checklist

  • I searched for previous requests in the issue tracker
  • My request contains all necessary details

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions