diff --git a/serial.h b/serial.h index f75afd9..0949d8e 100644 --- a/serial.h +++ b/serial.h @@ -1,5 +1,9 @@ #include <windows.h> static void NullifyParams(struct _DCB *params) { +/* LPCTSTR str = "baud=115200 parity=N data=8 stop=1"; + + BuildCommDCB(str,params); +*/ params->fBinary = TRUE; params->fNull = FALSE; params->fErrorChar = FALSE; diff --git a/serial_posix.go b/serial_posix.go index 24fc2f6..eb5e5b3 100644 --- a/serial_posix.go +++ b/serial_posix.go @@ -6,6 +6,7 @@ import "C" import ( "os" + "io" "fmt" "syscall" //"unsafe" @@ -19,7 +20,7 @@ func (e SError) String() string { return e.msg } -func OpenPort(name string, baud int) (f *os.File, err os.Error) { +func OpenPort(name string, baud int) (f io.ReadWriteCloser, err os.Error) { f, err = os.Open(name, os.O_RDWR|os.O_NOCTTY|os.O_NONBLOCK, 0666) if err != nil { return diff --git a/serial_windows.go b/serial_windows.go index 14b34b8..5e6e0ca 100644 --- a/serial_windows.go +++ b/serial_windows.go @@ -1,15 +1,21 @@ package serial // #include <windows.h> -// #include "serial.h" import "C" import ( "os" + "io" "fmt" "unsafe" ) -func OpenPort(name string, baud int) (*os.File, os.Error) { +type serialPort struct { + f *os.File +} + +const EV_RXCHAR = 0x0001 + +func OpenPort(name string, baud int) (io.ReadWriteCloser, os.Error) { f, err := os.Open(name, os.O_RDWR|os.O_NDELAY, 0666) if err != nil { return nil, err @@ -21,18 +27,16 @@ func OpenPort(name string, baud int) (*os.File, os.Error) { handle = hp(unsafe.Pointer(&fd)) var params C.struct__DCB params.DCBlength = C.DWORD(unsafe.Sizeof(params)) - /*if ok, err := C.GetCommState(*handle, ¶ms); ok == C.FALSE { - f.Close() - return nil, err - } - */ + + params.XonLim = 0 + params.XoffLim = 0 + params.BaudRate = C.DWORD(baud) params.ByteSize = 8 params.StopBits = C.ONESTOPBIT - params.Parity = C.NOPARITY - C.NullifyParams(¶ms) + params.Parity = C.NOPARITY - fmt.Println(params) + //fmt.Printf("%#v %v\n", params, params) if ok, err := C.SetCommState(*handle, ¶ms); ok == C.FALSE { f.Close() @@ -46,12 +50,56 @@ func OpenPort(name string, baud int) (*os.File, os.Error) { } var timeouts C.struct__COMMTIMEOUTS - timeouts.ReadIntervalTimeout = 1 + const DWORDMAX = 1<<32 - 1 + timeouts.ReadIntervalTimeout = DWORDMAX + timeouts.ReadTotalTimeoutConstant = 0 if ok, err := C.SetCommTimeouts(*handle, &timeouts); ok == C.FALSE { f.Close() return nil, err } - fmt.Println(timeouts) + //fmt.Printf("%#v\n", timeouts) + + if ok, err := C.SetCommMask(*handle, EV_RXCHAR); ok == C.FALSE { + f.Close() + return nil, err + } + + port := serialPort{f} + + return &port, nil +} + +func (p *serialPort) Close() os.Error { + return p.f.Close() +} + +func (p *serialPort) Write(buf []byte) (int, os.Error) { + return p.f.Write(buf) +} + +func (p *serialPort) Read(buf []byte) (int, os.Error) { + type hp *C.HANDLE + var handle *C.HANDLE + fd := p.f.Fd() + handle = hp(unsafe.Pointer(&fd)) + + var events C.DWORD + var overlapped *C.struct__OVERLAPPED + +loop: + if ok, err := C.WaitCommEvent(*handle, &events, overlapped); ok == C.FALSE { + fmt.Printf("%v, 0x%04x\n", err, events) + return 0, err + } + // There is a small race window here between returning from WaitCommEvent and reading from the file. + // If we receive data in this window, we will read that data, but the RXFLAG will still be set + // and next time the WaitCommEvent() will return but we will have already read the data. That's + // why we have the stupid goto loop on EOF. + n, err := p.f.Read(buf) + if err == os.EOF && n == 0 { + //fmt.Printf("%v, %v, %v, 0x%04x\n", err, n, len(buf), events) + goto loop + } - return f, nil + return n, err }