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

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions