Created interface Port. Rationalized documentation.

This commit is contained in:
Cristian Maglie
2016-04-24 17:19:32 +02:00
parent 88e647775e
commit f5be203394
6 changed files with 56 additions and 38 deletions

6
doc.go
View File

@@ -26,17 +26,17 @@ GetPortsList function:
fmt.Printf("Found port: %v\n", port) 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{ mode := &serial.Mode{
BaudRate: 115200, BaudRate: 115200,
} }
port, err := serial.OpenPort("/dev/ttyUSB0", mode) port, err := serial.Open("/dev/ttyUSB0", mode)
if err != nil { if err != nil {
log.Fatal(err) 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, 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. 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: The following snippets shows how to declare a configuration for 57600_E71:

View File

@@ -11,7 +11,7 @@ import "log"
import "go.bug.st/serial" import "go.bug.st/serial"
func ExampleSerialPort_SetMode() { func ExampleSerialPort_SetMode() {
port, err := serial.OpenPort("/dev/ttyACM0", &serial.Mode{}) port, err := serial.Open("/dev/ttyACM0", &serial.Mode{})
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }

View File

@@ -35,7 +35,7 @@ func Example_sendAndReceive() {
DataBits: 8, DataBits: 8,
StopBits: serial.OneStopBit, StopBits: serial.OneStopBit,
} }
port, err := serial.OpenPort(ports[0], mode) port, err := serial.Open(ports[0], mode)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }

View File

@@ -6,6 +6,36 @@
package serial // import "go.bug.st/serial" 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. // Mode describes a serial port configuration.
type Mode struct { type Mode struct {
BaudRate int // The serial port bitrate (aka Baudrate) BaudRate int // The serial port bitrate (aka Baudrate)

View File

@@ -14,34 +14,24 @@ import "strings"
import "syscall" import "syscall"
import "unsafe" import "unsafe"
// Port is the handler for a serial Port type unixPort struct {
type Port struct {
handle int handle int
} }
// Close the serial port func (port *unixPort) Close() error {
func (port *Port) Close() error {
port.releaseExclusiveAccess() port.releaseExclusiveAccess()
return syscall.Close(port.handle) return syscall.Close(port.handle)
} }
// Stores data received from the serial port into the provided byte array func (port *unixPort) Read(p []byte) (n int, err error) {
// 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) {
return syscall.Read(port.handle, p) return syscall.Read(port.handle, p)
} }
// Send the content of the data byte array to the serial port. func (port *unixPort) Write(p []byte) (n int, err error) {
// Returns the number of bytes written.
func (port *Port) Write(p []byte) (n int, err error) {
return syscall.Write(port.handle, p) return syscall.Write(port.handle, p)
} }
// SetMode sets all parameters of the serial port func (port *unixPort) SetMode(mode *Mode) error {
func (port *Port) SetMode(mode *Mode) error {
settings, err := port.getTermSettings() settings, err := port.getTermSettings()
if err != nil { if err != nil {
return err return err
@@ -61,8 +51,7 @@ func (port *Port) SetMode(mode *Mode) error {
return port.setTermSettings(settings) return port.setTermSettings(settings)
} }
// OpenPort opens the serial port using the specified modes func nativeOpen(portName string, mode *Mode) (*unixPort, error) {
func OpenPort(portName string, mode *Mode) (*Port, error) {
h, err := syscall.Open(portName, syscall.O_RDWR|syscall.O_NOCTTY|syscall.O_NDELAY, 0) h, err := syscall.Open(portName, syscall.O_RDWR|syscall.O_NOCTTY|syscall.O_NDELAY, 0)
if err != nil { if err != nil {
switch err { switch err {
@@ -73,7 +62,7 @@ func OpenPort(portName string, mode *Mode) (*Port, error) {
} }
return nil, err return nil, err
} }
port := &Port{ port := &unixPort{
handle: h, handle: h,
} }
@@ -102,8 +91,7 @@ func OpenPort(portName string, mode *Mode) (*Port, error) {
return port, nil return port, nil
} }
// GetPortsList retrieve the list of available serial ports func nativeGetPortsList() ([]string, error) {
func GetPortsList() ([]string, error) {
files, err := ioutil.ReadDir(devFolder) files, err := ioutil.ReadDir(devFolder)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -129,7 +117,7 @@ func GetPortsList() ([]string, error) {
// Check if serial port is real or is a placeholder serial port "ttySxx" // Check if serial port is real or is a placeholder serial port "ttySxx"
if strings.HasPrefix(f.Name(), "ttyS") { if strings.HasPrefix(f.Name(), "ttyS") {
port, err := OpenPort(portName, &Mode{}) port, err := nativeOpen(portName, &Mode{})
if err != nil { if err != nil {
serr, ok := err.(*PortError) serr, ok := err.(*PortError)
if ok && serr.Code() == InvalidSerialPort { if ok && serr.Code() == InvalidSerialPort {
@@ -230,20 +218,20 @@ func setRawMode(settings *syscall.Termios) {
// native syscall wrapper functions // native syscall wrapper functions
func (port *Port) getTermSettings() (*syscall.Termios, error) { func (port *unixPort) getTermSettings() (*syscall.Termios, error) {
settings := &syscall.Termios{} settings := &syscall.Termios{}
err := ioctl(port.handle, ioctlTcgetattr, uintptr(unsafe.Pointer(settings))) err := ioctl(port.handle, ioctlTcgetattr, uintptr(unsafe.Pointer(settings)))
return settings, err 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))) 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) return ioctl(port.handle, syscall.TIOCEXCL, 0)
} }
func (port *Port) releaseExclusiveAccess() error { func (port *unixPort) releaseExclusiveAccess() error {
return ioctl(port.handle, syscall.TIOCNXCL, 0) return ioctl(port.handle, syscall.TIOCNXCL, 0)
} }

View File

@@ -18,13 +18,13 @@ package serial // import "go.bug.st/serial"
import "syscall" import "syscall"
type Port struct { type windowsPort struct {
handle syscall.Handle 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 //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\\") subKey, err := syscall.UTF16PtrFromString("HARDWARE\\DEVICEMAP\\SERIALCOMM\\")
if err != nil { if err != nil {
return nil, &PortError{code: ErrorEnumeratingPorts} return nil, &PortError{code: ErrorEnumeratingPorts}
@@ -55,11 +55,11 @@ func GetPortsList() ([]string, error) {
return list, nil return list, nil
} }
func (port *Port) Close() error { func (port *windowsPort) Close() error {
return syscall.CloseHandle(port.handle) return syscall.CloseHandle(port.handle)
} }
func (port *Port) Read(p []byte) (int, error) { func (port *windowsPort) Read(p []byte) (int, error) {
var readed uint32 var readed uint32
params := &DCB{} params := &DCB{}
for { 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 var writed uint32
err := syscall.WriteFile(port.handle, p, &writed, nil) err := syscall.WriteFile(port.handle, p, &writed, nil)
return int(writed), err return int(writed), err
@@ -170,7 +170,7 @@ const (
TWOSTOPBITS = 2 TWOSTOPBITS = 2
) )
func (port *Port) SetMode(mode *Mode) error { func (port *windowsPort) SetMode(mode *Mode) error {
params := DCB{} params := DCB{}
if GetCommState(port.handle, &params) != nil { if GetCommState(port.handle, &params) != nil {
port.Close() port.Close()
@@ -195,7 +195,7 @@ func (port *Port) SetMode(mode *Mode) error {
return nil return nil
} }
func OpenPort(portName string, mode *Mode) (*Port, error) { func nativeOpen(portName string, mode *Mode) (*windowsPort, error) {
portName = "\\\\.\\" + portName portName = "\\\\.\\" + portName
path, err := syscall.UTF16PtrFromString(portName) path, err := syscall.UTF16PtrFromString(portName)
if err != nil { if err != nil {
@@ -218,7 +218,7 @@ func OpenPort(portName string, mode *Mode) (*Port, error) {
return nil, err return nil, err
} }
// Create the serial port // Create the serial port
port := &Port{ port := &windowsPort{
handle: handle, handle: handle,
} }