diff --git a/doc.go b/doc.go index ef85cae..d7f6fea 100644 --- a/doc.go +++ b/doc.go @@ -26,17 +26,17 @@ GetPortsList function: fmt.Printf("Found port: %v\n", port) } -The serial port can be opened with the OpenPort function: +The serial port can be opened with the Open function: mode := &serial.Mode{ BaudRate: 115200, } - port, err := serial.OpenPort("/dev/ttyUSB0", mode) + port, err := serial.Open("/dev/ttyUSB0", mode) if err != nil { log.Fatal(err) } -The OpenPort command needs a "mode" parameter that specifies the configuration +The Open function needs a "mode" parameter that specifies the configuration options for the serial port. If not specified the default options are 9600_N81, in the example above only the speed is changed so the port is opened using 115200_N81. The following snippets shows how to declare a configuration for 57600_E71: diff --git a/example_serialport_test.go b/example_serialport_test.go index c470ac9..eb51176 100644 --- a/example_serialport_test.go +++ b/example_serialport_test.go @@ -11,7 +11,7 @@ import "log" import "go.bug.st/serial" func ExampleSerialPort_SetMode() { - port, err := serial.OpenPort("/dev/ttyACM0", &serial.Mode{}) + port, err := serial.Open("/dev/ttyACM0", &serial.Mode{}) if err != nil { log.Fatal(err) } diff --git a/example_test.go b/example_test.go index c408e1e..3805210 100644 --- a/example_test.go +++ b/example_test.go @@ -35,7 +35,7 @@ func Example_sendAndReceive() { DataBits: 8, StopBits: serial.OneStopBit, } - port, err := serial.OpenPort(ports[0], mode) + port, err := serial.Open(ports[0], mode) if err != nil { log.Fatal(err) } diff --git a/serial.go b/serial.go index 09a7e21..805f979 100644 --- a/serial.go +++ b/serial.go @@ -6,6 +6,36 @@ package serial // import "go.bug.st/serial" +// Port is the interface for a serial Port +type Port interface { + // SetMode sets all parameters of the serial port + SetMode(mode *Mode) error + + // Stores data received from the serial port into the provided byte array + // buffer. The function returns the number of bytes read. + // + // The Read function blocks until (at least) one byte is received from + // the serial port or an error occurs. + Read(p []byte) (n int, err error) + + // Send the content of the data byte array to the serial port. + // Returns the number of bytes written. + Write(p []byte) (n int, err error) + + // Close the serial port + Close() error +} + +// Open opens the serial port using the specified modes +func Open(portName string, mode *Mode) (Port, error) { + return nativeOpen(portName, mode) +} + +// GetPortsList retrieve the list of available serial ports +func GetPortsList() ([]string, error) { + return nativeGetPortsList() +} + // Mode describes a serial port configuration. type Mode struct { BaudRate int // The serial port bitrate (aka Baudrate) diff --git a/serial_unix.go b/serial_unix.go index f308dc0..357ee25 100644 --- a/serial_unix.go +++ b/serial_unix.go @@ -14,34 +14,24 @@ import "strings" import "syscall" import "unsafe" -// Port is the handler for a serial Port -type Port struct { +type unixPort struct { handle int } -// Close the serial port -func (port *Port) Close() error { +func (port *unixPort) Close() error { port.releaseExclusiveAccess() return syscall.Close(port.handle) } -// Stores data received from the serial port into the provided byte array -// buffer. The function returns the number of bytes read. -// -// The Read function blocks until (at least) one byte is received from -// the serial port or an error occurs. -func (port *Port) Read(p []byte) (n int, err error) { +func (port *unixPort) Read(p []byte) (n int, err error) { return syscall.Read(port.handle, p) } -// Send the content of the data byte array to the serial port. -// Returns the number of bytes written. -func (port *Port) Write(p []byte) (n int, err error) { +func (port *unixPort) Write(p []byte) (n int, err error) { return syscall.Write(port.handle, p) } -// SetMode sets all parameters of the serial port -func (port *Port) SetMode(mode *Mode) error { +func (port *unixPort) SetMode(mode *Mode) error { settings, err := port.getTermSettings() if err != nil { return err @@ -61,8 +51,7 @@ func (port *Port) SetMode(mode *Mode) error { return port.setTermSettings(settings) } -// OpenPort opens the serial port using the specified modes -func OpenPort(portName string, mode *Mode) (*Port, error) { +func nativeOpen(portName string, mode *Mode) (*unixPort, error) { h, err := syscall.Open(portName, syscall.O_RDWR|syscall.O_NOCTTY|syscall.O_NDELAY, 0) if err != nil { switch err { @@ -73,7 +62,7 @@ func OpenPort(portName string, mode *Mode) (*Port, error) { } return nil, err } - port := &Port{ + port := &unixPort{ handle: h, } @@ -102,8 +91,7 @@ func OpenPort(portName string, mode *Mode) (*Port, error) { return port, nil } -// GetPortsList retrieve the list of available serial ports -func GetPortsList() ([]string, error) { +func nativeGetPortsList() ([]string, error) { files, err := ioutil.ReadDir(devFolder) if err != nil { return nil, err @@ -129,7 +117,7 @@ func GetPortsList() ([]string, error) { // Check if serial port is real or is a placeholder serial port "ttySxx" if strings.HasPrefix(f.Name(), "ttyS") { - port, err := OpenPort(portName, &Mode{}) + port, err := nativeOpen(portName, &Mode{}) if err != nil { serr, ok := err.(*PortError) if ok && serr.Code() == InvalidSerialPort { @@ -230,20 +218,20 @@ func setRawMode(settings *syscall.Termios) { // native syscall wrapper functions -func (port *Port) getTermSettings() (*syscall.Termios, error) { +func (port *unixPort) getTermSettings() (*syscall.Termios, error) { settings := &syscall.Termios{} err := ioctl(port.handle, ioctlTcgetattr, uintptr(unsafe.Pointer(settings))) return settings, err } -func (port *Port) setTermSettings(settings *syscall.Termios) error { +func (port *unixPort) setTermSettings(settings *syscall.Termios) error { return ioctl(port.handle, ioctlTcsetattr, uintptr(unsafe.Pointer(settings))) } -func (port *Port) acquireExclusiveAccess() error { +func (port *unixPort) acquireExclusiveAccess() error { return ioctl(port.handle, syscall.TIOCEXCL, 0) } -func (port *Port) releaseExclusiveAccess() error { +func (port *unixPort) releaseExclusiveAccess() error { return ioctl(port.handle, syscall.TIOCNXCL, 0) } diff --git a/serial_windows.go b/serial_windows.go index b2cff41..52285c5 100644 --- a/serial_windows.go +++ b/serial_windows.go @@ -18,13 +18,13 @@ package serial // import "go.bug.st/serial" import "syscall" -type Port struct { +type windowsPort struct { handle syscall.Handle } //sys RegEnumValue(key syscall.Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, value *uint16, valueLen *uint32) (regerrno error) = advapi32.RegEnumValueW -func GetPortsList() ([]string, error) { +func nativeGetPortsList() ([]string, error) { subKey, err := syscall.UTF16PtrFromString("HARDWARE\\DEVICEMAP\\SERIALCOMM\\") if err != nil { return nil, &PortError{code: ErrorEnumeratingPorts} @@ -55,11 +55,11 @@ func GetPortsList() ([]string, error) { return list, nil } -func (port *Port) Close() error { +func (port *windowsPort) Close() error { return syscall.CloseHandle(port.handle) } -func (port *Port) Read(p []byte) (int, error) { +func (port *windowsPort) Read(p []byte) (int, error) { var readed uint32 params := &DCB{} for { @@ -82,7 +82,7 @@ func (port *Port) Read(p []byte) (int, error) { } } -func (port *Port) Write(p []byte) (int, error) { +func (port *windowsPort) Write(p []byte) (int, error) { var writed uint32 err := syscall.WriteFile(port.handle, p, &writed, nil) return int(writed), err @@ -170,7 +170,7 @@ const ( TWOSTOPBITS = 2 ) -func (port *Port) SetMode(mode *Mode) error { +func (port *windowsPort) SetMode(mode *Mode) error { params := DCB{} if GetCommState(port.handle, ¶ms) != nil { port.Close() @@ -195,7 +195,7 @@ func (port *Port) SetMode(mode *Mode) error { return nil } -func OpenPort(portName string, mode *Mode) (*Port, error) { +func nativeOpen(portName string, mode *Mode) (*windowsPort, error) { portName = "\\\\.\\" + portName path, err := syscall.UTF16PtrFromString(portName) if err != nil { @@ -218,7 +218,7 @@ func OpenPort(portName string, mode *Mode) (*Port, error) { return nil, err } // Create the serial port - port := &Port{ + port := &windowsPort{ handle: handle, }