jacobsa / go-serial

A Go library for dealing with serial ports.
Apache License 2.0
626 stars 120 forks source link

blocking IO / read timeouts on windows #14

Closed luck02 closed 8 years ago

luck02 commented 8 years ago

On OSX I have a working integration test that relies on IO timeouts. I want to issue a read, then after a set amount of time cancel that read.

This works on OSX, but on windows it seems the read blocks indefinitly.

When I look at the windows code I see that it seems to ignore the options struct while setting timeouts.

Just wondering if you had any background on that.

func setCommTimeouts(h syscall.Handle) error {
    var timeouts structTimeouts
    const MAXDWORD = 1<<32 - 1
    timeouts.ReadIntervalTimeout = MAXDWORD
    timeouts.ReadTotalTimeoutMultiplier = MAXDWORD
    timeouts.ReadTotalTimeoutConstant = MAXDWORD - 1
    //timeouts.ReadTotalTimeoutConstant = 1
    fmt.Println("Got timeout 100")
    /* From http://msdn.microsoft.com/en-us/library/aa363190(v=VS.85).aspx

         For blocking I/O see below:

         Remarks:

         If an application sets ReadIntervalTimeout and
         ReadTotalTimeoutMultiplier to MAXDWORD and sets
         ReadTotalTimeoutConstant to a value greater than zero and
         less than MAXDWORD, one of the following occurs when the
         ReadFile function is called:

         If there are any bytes in the input buffer, ReadFile returns
               immediately with the bytes in the buffer.

         If there are no bytes in the input buffer, ReadFile waits
                   until a byte arrives and then returns immediately.

         If no bytes arrive within the time specified by
               ReadTotalTimeoutConstant, ReadFile times out.
    */

    r, _, err := syscall.Syscall(nSetCommTimeouts, 2, uintptr(h), uintptr(unsafe.Pointer(&timeouts)), 0)
    if r == 0 {
        return err
    }
    return nil
}

That doesn't seem to take the options struct at all into account.

Any thoughts?

Thanks!

luck02 commented 8 years ago

Addendum:

    timeouts.ReadIntervalTimeout = MAXDWORD
    timeouts.ReadTotalTimeoutMultiplier = 0
    timeouts.ReadTotalTimeoutConstant = 0 // MAXDWORD - 1

Makes the read call return instantly, but with a different error.

one windows we get: "multiple Read calls return no data or error" On OSX we get: "EOF"

I think we can map the options struct intelligently to windows. I'll submit a PR in the near future.

Also, ideally it would be nice to return the same error regardless of platform. EOF / Multiple reads isn't really an error, it's just saying there were no bytes on the port. I'll think about that, would appreciate any insight.

G

luck02 commented 8 years ago

Updated PR: https://github.com/jacobsa/go-serial/pull/16

luck02 commented 8 years ago

this has been merged by @jacobsa