Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows hardware flow control (DTR/CTS) #48

Open
chinenual opened this issue Apr 23, 2020 · 2 comments
Open

Windows hardware flow control (DTR/CTS) #48

chinenual opened this issue Apr 23, 2020 · 2 comments

Comments

@chinenual
Copy link

chinenual commented Apr 23, 2020

I'm having trouble using the library on Windows. It's working great on macos.

I'm using read timeouts to allow me to detect when there are bytes to be read (part of the comm protocol for this device is that in certain circumstances I need to "drain" unwanted bytes and wait for the stream to empty before trying to send a command or wait for response, so I wait for a read to timeout). This works fine on macos, but on Windows, the stream is giving me a non-ending stream of "0" bytes (never timing out). My suspicion is that despite having set Hardware flow control on the COM1 port (via Device Manager), DTR is being ignored? Ideas?

Code looks like this:

	readerChannel = make(chan serialReadResponse)
	readerChannelQuit = make(chan bool)
	go func () {
		var arr []byte = make([]byte,1);
		for {
			select {
			case <- readerChannelQuit:
				close(readerChannelQuit)
				close(readerChannel)
				return
			default:
				var response serialReadResponse
				var n int
				n, response.err = stream.Read(arr);
				if n == 1 {
					response.data = arr[0]
				}
				readerChannel <- response
			}
		}
	}()

and the application level reads look like:

	select {
	case response := <-readerChannel:
		if response.err != nil {
			return response.data,errors.Wrap(err, "failed to read byte")
		}
		return response.data, nil
	case <-time.After(time.Millisecond * time.Duration(timeoutMS)):
		// call timed out
		return 0,errors.Errorf("TIMEOUT: read timed out at %d ms", timeoutMS)
	}

and I'm initializing the connection thusly:

	options := serial.OpenOptions{
		PortName: port,
		BaudRate: 9600,
		ParityMode: serial.PARITY_NONE,
		RTSCTSFlowControl: true,
		InterCharacterTimeout: 500,
		MinimumReadSize: 1,
		DataBits: 8,
		StopBits: 1,
	}
@chinenual
Copy link
Author

I still believe this is probably a bug -- Nonzero InterCharacterTimeout and non-zero MinimumReadSize is supposed to cause read to block, but what I'm actually seeing is an immediate return of the Read with n=0 and err=nil.

My workaround is to treat that condition as a "block", like this in my goroutine:

	go func () {
		var arr []byte = make([]byte,1);
		for {
			select {
			case <- readerChannelQuit:
				close(readerChannelQuit)
				close(readerChannel)
				return
			default:
				var response serialReadResponse
				var n int
				n, response.err = stream.Read(arr);
				if err != nil {
					response.data = 0
					readerChannel <- response
				} else if n == 1 {
					response.data = arr[0]
					readerChannel <- response
				} else if err == nil {
					// on windows, despite asking for blocking IO
					// the Read is returning immediately with
					// n == 0, but no error.  Sleep for a
					// while so we don't chew up infinite CPU
					time.Sleep(time.Duration(500) * time.Millisecond)
				}
			}
		}
	}()

@chinenual
Copy link
Author

My work around (above) is not really practical. While this does emulate blocking IO, it results in SUPER SLOW reads -- apparently even when there is data on the line, I'm getting at least as many empty reads that good ones - so that 1/2 second delay is effectively happening on every byte.

Hoping someone else using the library on Windows has some insights...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant