diff --git a/README.md b/README.md index 81db23a..0a72237 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,23 @@ -GoSerial +[![GoDoc](https://godoc.org/github.com/tarm/serial?status.svg)](http://godoc.org/github.com/tarm/serial) + +Serial ======== -A simple go package to allow you to read and write from the +A Go package to allow you to read and write from the serial port as a stream of bytes. Details ------- It aims to have the same API on all platforms, including windows. As an added bonus, the windows package does not use cgo, so you can cross -compile for windows from another platform. Unfortunately goinstall -does not currently let you cross compile so you will have to do it -manually: +compile for windows from another platform. - GOOS=windows make clean install +You can cross compile with + GOOS=windows GOARCH=386 go install github.com/tarm/serial Currently there is very little in the way of configurability. You can set the baud rate. Then you can Read(), Write(), or Close() the -connection. Read() will block until at least one byte is returned. -Write is the same. There is currently no exposed way to set the -timeouts, though patches are welcome. +connection. By default Read() will block until at least one byte is +returned. Write is the same. Currently all ports are opened with 8 data bits, 1 stop bit, no parity, no hardware flow control, and no software flow control. This @@ -33,8 +33,9 @@ Usage package main import ( - "github.com/tarm/goserial" "log" + + "github.com/tarm/serial" ) func main() { @@ -60,12 +61,12 @@ func main() { NonBlocking Mode ---------------- -By default goserial reads in blocking mode. Which means `Read()` will -block until at least one byte is returned. If that's not what you want, -specify a positive ReadTimeout and the Read() will timeout returning 0 -bytes if no bytes are read. -Please note that this is the total timeout the read operation will wait -and not the interval timeout between two bytes. +By default the returned Port reads in blocking mode. Which means +`Read()` will block until at least one byte is returned. If that's not +what you want, specify a positive ReadTimeout and the Read() will +timeout returning 0 bytes if no bytes are read. Please note that this +is the total timeout the read operation will wait and not the interval +timeout between two bytes. ```go c := &serial.Config{Name: "COM45", Baud: 115200, ReadTimeout: time.Second * 5} diff --git a/serial.go b/serial.go index 97f14ce..143d75f 100644 --- a/serial.go +++ b/serial.go @@ -56,7 +56,6 @@ Example usage: package serial import ( - "io" "time" ) @@ -92,7 +91,7 @@ type Config struct { } // OpenPort opens a serial port with the specified configuration -func OpenPort(c *Config) (io.ReadWriteCloser, error) { +func OpenPort(c *Config) (*Port, error) { return openPort(c.Name, c.Baud, c.ReadTimeout) } diff --git a/serial_linux.go b/serial_linux.go index 4217a55..fefd946 100644 --- a/serial_linux.go +++ b/serial_linux.go @@ -3,15 +3,13 @@ package serial import ( - "io" "os" "syscall" "time" "unsafe" ) -func openPort(name string, baud int, readTimeout time.Duration) (rwc io.ReadWriteCloser, err error) { - +func openPort(name string, baud int, readTimeout time.Duration) (p *Port, err error) { var bauds = map[int]uint32{ 50: syscall.B50, 75: syscall.B75, @@ -88,5 +86,23 @@ func openPort(name string, baud int, readTimeout time.Duration) (rwc io.ReadWrit return } - return f, nil + return &Port{f: f}, nil +} + +type Port struct { + // We intentionly do not use an "embedded" struct so that we + // don't export File + f *os.File +} + +func (p *Port) Read(b []byte) (n int, err error) { + return p.f.Read(b) +} + +func (p *Port) Write(b []byte) (n int, err error) { + return p.f.Write(b) +} + +func (p *Port) Close() (err error) { + return p.f.Close() } diff --git a/serial_posix.go b/serial_posix.go index 2ccdea0..2b6ebb4 100644 --- a/serial_posix.go +++ b/serial_posix.go @@ -11,14 +11,13 @@ import "C" import ( "errors" "fmt" - "io" "os" "syscall" "time" //"unsafe" ) -func openPort(name string, baud int, readTimeout time.Duration) (rwc io.ReadWriteCloser, err error) { +func openPort(name string, baud int, readTimeout time.Duration) (p *Port, err error) { f, err := os.OpenFile(name, syscall.O_RDWR|syscall.O_NOCTTY|syscall.O_NONBLOCK, 0666) if err != nil { return @@ -117,5 +116,23 @@ func openPort(name string, baud int, readTimeout time.Duration) (rwc io.ReadWrit } */ - return f, nil + return &Port{f: f}, nil +} + +type Port struct { + // We intentionly do not use an "embedded" struct so that we + // don't export File + f *os.File +} + +func (p *Port) Read(b []byte) (n int, err error) { + return p.f.Read(b) +} + +func (p *Port) Write(b []byte) (n int, err error) { + return p.f.Write(b) +} + +func (p *Port) Close() (err error) { + return p.f.Close() } diff --git a/serial_windows.go b/serial_windows.go index 31e6b1b..5ca47f5 100644 --- a/serial_windows.go +++ b/serial_windows.go @@ -4,7 +4,6 @@ package serial import ( "fmt" - "io" "os" "sync" "syscall" @@ -12,7 +11,7 @@ import ( "unsafe" ) -type serialPort struct { +type Port struct { f *os.File fd syscall.Handle rl sync.Mutex @@ -38,7 +37,7 @@ type structTimeouts struct { WriteTotalTimeoutConstant uint32 } -func openPort(name string, baud int, readTimeout time.Duration) (rwc io.ReadWriteCloser, err error) { +func openPort(name string, baud int, readTimeout time.Duration) (p *Port, err error) { if len(name) > 0 && name[0] != '\\' { name = "\\\\.\\" + name } @@ -81,7 +80,7 @@ func openPort(name string, baud int, readTimeout time.Duration) (rwc io.ReadWrit if err != nil { return } - port := new(serialPort) + port := new(Port) port.f = f port.fd = h port.ro = ro @@ -90,11 +89,11 @@ func openPort(name string, baud int, readTimeout time.Duration) (rwc io.ReadWrit return port, nil } -func (p *serialPort) Close() error { +func (p *Port) Close() error { return p.f.Close() } -func (p *serialPort) Write(buf []byte) (int, error) { +func (p *Port) Write(buf []byte) (int, error) { p.wl.Lock() defer p.wl.Unlock() @@ -109,7 +108,7 @@ func (p *serialPort) Write(buf []byte) (int, error) { return getOverlappedResult(p.fd, p.wo) } -func (p *serialPort) Read(buf []byte) (int, error) { +func (p *Port) Read(buf []byte) (int, error) { if p == nil || p.f == nil { return 0, fmt.Errorf("Invalid port on read %v %v", p, p.f) }