diff --git a/doc.go b/doc.go index fff8acf..ef85cae 100644 --- a/doc.go +++ b/doc.go @@ -5,7 +5,7 @@ // /* -A cross-platform serial library for the go language. +Package serial is a cross-platform serial library for the go language. The canonical import for this library is go.bug.st/serial so the import line is the following: @@ -43,9 +43,9 @@ The following snippets shows how to declare a configuration for 57600_E71: mode := &serial.Mode{ BaudRate: 57600, - Parity: serial.PARITY_EVEN, + Parity: serial.EvenParity, DataBits: 7, - StopBits: serial.STOPBITS_ONE, + StopBits: serial.OneStopBit, } The configuration can be changed at any time with the SetMode function: diff --git a/example_getportlist_test.go b/example_getportlist_test.go index be34e81..79ff243 100644 --- a/example_getportlist_test.go +++ b/example_getportlist_test.go @@ -23,4 +23,3 @@ func ExampleGetPortsList() { } } } - diff --git a/example_serialport_test.go b/example_serialport_test.go index 2ee936c..c470ac9 100644 --- a/example_serialport_test.go +++ b/example_serialport_test.go @@ -17,13 +17,12 @@ func ExampleSerialPort_SetMode() { } mode := &serial.Mode{ BaudRate: 9600, - Parity: serial.PARITY_NONE, + Parity: serial.NoParity, DataBits: 8, - StopBits: serial.STOPBITS_ONE, + StopBits: serial.OneStopBit, } if err := port.SetMode(mode); err != nil { log.Fatal(err) } fmt.Println("Port set to 9600 N81") } - diff --git a/example_test.go b/example_test.go index c087746..c408e1e 100644 --- a/example_test.go +++ b/example_test.go @@ -31,9 +31,9 @@ func Example_sendAndReceive() { // Open the first serial port detected at 9600bps N81 mode := &serial.Mode{ BaudRate: 9600, - Parity: serial.PARITY_NONE, + Parity: serial.NoParity, DataBits: 8, - StopBits: serial.STOPBITS_ONE, + StopBits: serial.OneStopBit, } port, err := serial.OpenPort(ports[0], mode) if err != nil { @@ -63,4 +63,3 @@ func Example_sendAndReceive() { fmt.Printf("%v", string(buff[:n])) } } - diff --git a/serial.go b/serial.go index 9cb1052..09a7e21 100644 --- a/serial.go +++ b/serial.go @@ -6,7 +6,7 @@ package serial // import "go.bug.st/serial" -// This structure describes a serial port configuration. +// Mode describes a serial port configuration. type Mode struct { BaudRate int // The serial port bitrate (aka Baudrate) DataBits int // Size of the character (must be 5, 6, 7 or 8) @@ -14,62 +14,82 @@ type Mode struct { StopBits StopBits // Stop bits (see StopBits type for more info) } +// Parity describes a serial port parity setting type Parity int const ( - PARITY_NONE Parity = iota // No parity (default) - PARITY_ODD // Odd parity - PARITY_EVEN // Even parity - PARITY_MARK // Mark parity (always 1) - PARITY_SPACE // Space parity (always 0) + // NoParity disable parity control (default) + NoParity Parity = iota + // OddParity enable odd-parity check + OddParity + // EvenParity enable even-parity check + EvenParity + // MarkParity enable mark-parity (always 1) check + MarkParity + // SpaceParity enable space-parity (always 0) check + SpaceParity ) +// StopBits describe a serial port stop bits setting type StopBits int const ( - STOPBITS_ONE StopBits = iota // 1 Stop bit - STOPBITS_ONEPOINTFIVE // 1.5 Stop bits - STOPBITS_TWO // 2 Stop bits + // OneStopBit sets 1 stop bit (default) + OneStopBit StopBits = iota + // OnePointFiveStopBits sets 1.5 stop bits + OnePointFiveStopBits + // TwoStopBits sets 2 stop bits + TwoStopBits ) -// Platform independent error type for serial ports -type SerialPortError struct { +// PortError is a platform independent error type for serial ports +type PortError struct { err string - code int + code PortErrorCode } +// PortErrorCode is a code to easily identify the type of error +type PortErrorCode int + const ( - ERROR_PORT_BUSY = iota - ERROR_PORT_NOT_FOUND - ERROR_INVALID_SERIAL_PORT - ERROR_PERMISSION_DENIED - ERROR_INVALID_PORT_SPEED - ERROR_INVALID_PORT_DATA_BITS - ERROR_ENUMERATING_PORTS - ERROR_OTHER + // PortBusy the serial port is already in used by another process + PortBusy PortErrorCode = iota + // PortNotFound the requested port doesn't exist + PortNotFound + // InvalidSerialPort the requested port is not a serial port + InvalidSerialPort + // PermissionDenied the user doesn't have enough priviledges + PermissionDenied + // InvalidSpeed the requested speed is not valid or not supported + InvalidSpeed + // InvalidDataBits the number of data bits is not valid or not supported + InvalidDataBits + // ErrorEnumeratingPorts an error occurred while listing serial port + ErrorEnumeratingPorts ) -func (e SerialPortError) Error() string { +// Error returns a string explaining the error occurred +func (e PortError) Error() string { switch e.code { - case ERROR_PORT_BUSY: + case PortBusy: return "Serial port busy" - case ERROR_PORT_NOT_FOUND: + case PortNotFound: return "Serial port not found" - case ERROR_INVALID_SERIAL_PORT: + case InvalidSerialPort: return "Invalid serial port" - case ERROR_PERMISSION_DENIED: + case PermissionDenied: return "Permission denied" - case ERROR_INVALID_PORT_SPEED: + case InvalidSpeed: return "Invalid port speed" - case ERROR_INVALID_PORT_DATA_BITS: + case InvalidDataBits: return "Invalid port data bits" - case ERROR_ENUMERATING_PORTS: + case ErrorEnumeratingPorts: return "Could not enumerate serial ports" } return e.err } -func (e SerialPortError) Code() int { +// Code returns an identifier for the kind of error occurred +func (e PortError) Code() PortErrorCode { return e.code } - diff --git a/serial_darwin.go b/serial_darwin.go index 52742c0..7a1da90 100644 --- a/serial_darwin.go +++ b/serial_darwin.go @@ -43,12 +43,12 @@ var databitsMap = map[int]int{ 8: syscall.CS8, } -const tc_CMSPAR int = 0 // may be CMSPAR or PAREXT -const tc_IUCLC int = 0 +const tcCMSPAR int = 0 // may be CMSPAR or PAREXT +const tcIUCLC int = 0 // syscall wrappers //sys ioctl(fd int, req uint64, data uintptr) (err error) -const ioctl_tcgetattr = syscall.TIOCGETA -const ioctl_tcsetattr = syscall.TIOCSETA +const ioctlTcgetattr = syscall.TIOCGETA +const ioctlTcsetattr = syscall.TIOCSETA diff --git a/serial_linux.go b/serial_linux.go index 4376806..0369a82 100644 --- a/serial_linux.go +++ b/serial_linux.go @@ -55,8 +55,8 @@ var databitsMap = map[int]int{ 8: syscall.CS8, } -const tc_CMSPAR int = 0 // may be CMSPAR or PAREXT -const tc_IUCLC = syscall.IUCLC +const tcCMSPAR int = 0 // may be CMSPAR or PAREXT +const tcIUCLC = syscall.IUCLC func termiosMask(data int) uint32 { return uint32(data) @@ -66,5 +66,5 @@ func termiosMask(data int) uint32 { //sys ioctl(fd int, req uint64, data uintptr) (err error) -const ioctl_tcgetattr = syscall.TCGETS -const ioctl_tcsetattr = syscall.TCSETS +const ioctlTcgetattr = syscall.TCGETS +const ioctlTcsetattr = syscall.TCSETS diff --git a/serial_unix.go b/serial_unix.go index a58347c..29c0b10 100644 --- a/serial_unix.go +++ b/serial_unix.go @@ -40,8 +40,7 @@ func (port *SerialPort) Write(p []byte) (n int, err error) { return syscall.Write(port.handle, p) } -// Set all parameters of the serial port. See the Mode structure for more -// info. +// SetMode sets all parameters of the serial port func (port *SerialPort) SetMode(mode *Mode) error { settings, err := port.getTermSettings() if err != nil { @@ -62,15 +61,15 @@ func (port *SerialPort) SetMode(mode *Mode) error { return port.setTermSettings(settings) } -// Open the serial port using the specified modes +// OpenPort opens the serial port using the specified modes func OpenPort(portName string, mode *Mode) (*SerialPort, error) { h, err := syscall.Open(portName, syscall.O_RDWR|syscall.O_NOCTTY|syscall.O_NDELAY, 0) if err != nil { switch err { case syscall.EBUSY: - return nil, &SerialPortError{code: ERROR_PORT_BUSY} + return nil, &PortError{code: PortBusy} case syscall.EACCES: - return nil, &SerialPortError{code: ERROR_PERMISSION_DENIED} + return nil, &PortError{code: PermissionDenied} } return nil, err } @@ -81,19 +80,19 @@ func OpenPort(portName string, mode *Mode) (*SerialPort, error) { // Setup serial port if port.SetMode(mode) != nil { port.Close() - return nil, &SerialPortError{code: ERROR_INVALID_SERIAL_PORT} + return nil, &PortError{code: InvalidSerialPort} } // Set raw mode settings, err := port.getTermSettings() if err != nil { port.Close() - return nil, &SerialPortError{code: ERROR_INVALID_SERIAL_PORT} + return nil, &PortError{code: InvalidSerialPort} } setRawMode(settings) if port.setTermSettings(settings) != nil { port.Close() - return nil, &SerialPortError{code: ERROR_INVALID_SERIAL_PORT} + return nil, &PortError{code: InvalidSerialPort} } syscall.SetNonblock(h, false) @@ -103,6 +102,7 @@ func OpenPort(portName string, mode *Mode) (*SerialPort, error) { return port, nil } +// GetPortsList retrieve the list of available serial ports func GetPortsList() ([]string, error) { files, err := ioutil.ReadDir(devFolder) if err != nil { @@ -131,8 +131,8 @@ func GetPortsList() ([]string, error) { if strings.HasPrefix(f.Name(), "ttyS") { port, err := OpenPort(portName, &Mode{}) if err != nil { - serr, ok := err.(*SerialPortError) - if ok && serr.Code() == ERROR_INVALID_SERIAL_PORT { + serr, ok := err.(*PortError) + if ok && serr.Code() == InvalidSerialPort { continue } } else { @@ -152,7 +152,7 @@ func GetPortsList() ([]string, error) { func setTermSettingsBaudrate(speed int, settings *syscall.Termios) error { baudrate, ok := baudrateMap[speed] if !ok { - return &SerialPortError{code: ERROR_INVALID_PORT_SPEED} + return &PortError{code: InvalidSpeed} } // revert old baudrate BAUDMASK := 0 @@ -169,23 +169,23 @@ func setTermSettingsBaudrate(speed int, settings *syscall.Termios) error { func setTermSettingsParity(parity Parity, settings *syscall.Termios) error { switch parity { - case PARITY_NONE: - settings.Cflag &= ^termiosMask(syscall.PARENB | syscall.PARODD | tc_CMSPAR) + case NoParity: + settings.Cflag &= ^termiosMask(syscall.PARENB | syscall.PARODD | tcCMSPAR) settings.Iflag &= ^termiosMask(syscall.INPCK) - case PARITY_ODD: + case OddParity: settings.Cflag |= termiosMask(syscall.PARENB | syscall.PARODD) - settings.Cflag &= ^termiosMask(tc_CMSPAR) + settings.Cflag &= ^termiosMask(tcCMSPAR) settings.Iflag |= termiosMask(syscall.INPCK) - case PARITY_EVEN: - settings.Cflag &= ^termiosMask(syscall.PARODD | tc_CMSPAR) + case EvenParity: + settings.Cflag &= ^termiosMask(syscall.PARODD | tcCMSPAR) settings.Cflag |= termiosMask(syscall.PARENB) settings.Iflag |= termiosMask(syscall.INPCK) - case PARITY_MARK: - settings.Cflag |= termiosMask(syscall.PARENB | syscall.PARODD | tc_CMSPAR) + case MarkParity: + settings.Cflag |= termiosMask(syscall.PARENB | syscall.PARODD | tcCMSPAR) settings.Iflag |= termiosMask(syscall.INPCK) - case PARITY_SPACE: + case SpaceParity: settings.Cflag &= ^termiosMask(syscall.PARODD) - settings.Cflag |= termiosMask(syscall.PARENB | tc_CMSPAR) + settings.Cflag |= termiosMask(syscall.PARENB | tcCMSPAR) settings.Iflag |= termiosMask(syscall.INPCK) } return nil @@ -194,7 +194,7 @@ func setTermSettingsParity(parity Parity, settings *syscall.Termios) error { func setTermSettingsDataBits(bits int, settings *syscall.Termios) error { databits, ok := databitsMap[bits] if !ok { - return &SerialPortError{code: ERROR_INVALID_PORT_DATA_BITS} + return &PortError{code: InvalidDataBits} } settings.Cflag &= ^termiosMask(syscall.CSIZE) settings.Cflag |= termiosMask(databits) @@ -203,9 +203,9 @@ func setTermSettingsDataBits(bits int, settings *syscall.Termios) error { func setTermSettingsStopBits(bits StopBits, settings *syscall.Termios) error { switch bits { - case STOPBITS_ONE: + case OneStopBit: settings.Cflag &= ^termiosMask(syscall.CSTOPB) - case STOPBITS_ONEPOINTFIVE, STOPBITS_TWO: + case OnePointFiveStopBits, TwoStopBits: settings.Cflag |= termiosMask(syscall.CSTOPB) } return nil @@ -220,7 +220,7 @@ func setRawMode(settings *syscall.Termios) { syscall.ECHONL | syscall.ECHOCTL | syscall.ECHOPRT | syscall.ECHOKE | syscall.ISIG | syscall.IEXTEN) settings.Iflag &= ^termiosMask(syscall.IXON | syscall.IXOFF | syscall.IXANY | syscall.INPCK | syscall.IGNPAR | syscall.PARMRK | syscall.ISTRIP | syscall.IGNBRK | syscall.BRKINT | syscall.INLCR | - syscall.IGNCR | syscall.ICRNL | tc_IUCLC) + syscall.IGNCR | syscall.ICRNL | tcIUCLC) settings.Oflag &= ^termiosMask(syscall.OPOST) // Block reads until at least one char is available (no timeout) @@ -232,12 +232,12 @@ func setRawMode(settings *syscall.Termios) { func (port *SerialPort) getTermSettings() (*syscall.Termios, error) { settings := &syscall.Termios{} - err := ioctl(port.handle, ioctl_tcgetattr, uintptr(unsafe.Pointer(settings))) + err := ioctl(port.handle, ioctlTcgetattr, uintptr(unsafe.Pointer(settings))) return settings, err } func (port *SerialPort) setTermSettings(settings *syscall.Termios) error { - return ioctl(port.handle, ioctl_tcsetattr, uintptr(unsafe.Pointer(settings))) + return ioctl(port.handle, ioctlTcsetattr, uintptr(unsafe.Pointer(settings))) } func (port *SerialPort) acquireExclusiveAccess() error { diff --git a/serial_windows.go b/serial_windows.go index 999c309..01d4ca4 100644 --- a/serial_windows.go +++ b/serial_windows.go @@ -28,18 +28,18 @@ type SerialPort struct { func GetPortsList() ([]string, error) { subKey, err := syscall.UTF16PtrFromString("HARDWARE\\DEVICEMAP\\SERIALCOMM\\") if err != nil { - return nil, &SerialPortError{code: ERROR_ENUMERATING_PORTS} + return nil, &PortError{code: ErrorEnumeratingPorts} } var h syscall.Handle if syscall.RegOpenKeyEx(syscall.HKEY_LOCAL_MACHINE, subKey, 0, syscall.KEY_READ, &h) != nil { - return nil, &SerialPortError{code: ERROR_ENUMERATING_PORTS} + return nil, &PortError{code: ErrorEnumeratingPorts} } defer syscall.RegCloseKey(h) var valuesCount uint32 if syscall.RegQueryInfoKey(h, nil, nil, nil, nil, nil, nil, &valuesCount, nil, nil, nil, nil) != nil { - return nil, &SerialPortError{code: ERROR_ENUMERATING_PORTS} + return nil, &PortError{code: ErrorEnumeratingPorts} } list := make([]string, valuesCount) @@ -49,7 +49,7 @@ func GetPortsList() ([]string, error) { var name [1024]uint16 nameSize := uint32(len(name)) if RegEnumValue(h, uint32(i), &name[0], &nameSize, nil, nil, &data[0], &dataSize) != nil { - return nil, &SerialPortError{code: ERROR_ENUMERATING_PORTS} + return nil, &PortError{code: ErrorEnumeratingPorts} } list[i] = syscall.UTF16ToString(data[:]) } @@ -175,7 +175,7 @@ func (port *SerialPort) SetMode(mode *Mode) error { params := DCB{} if GetCommState(port.handle, ¶ms) != nil { port.Close() - return &SerialPortError{code: ERROR_INVALID_SERIAL_PORT} + return &PortError{code: InvalidSerialPort} } if mode.BaudRate == 0 { params.BaudRate = 9600 // Default to 9600 @@ -191,7 +191,7 @@ func (port *SerialPort) SetMode(mode *Mode) error { params.Parity = byte(mode.Parity) if SetCommState(port.handle, ¶ms) != nil { port.Close() - return &SerialPortError{code: ERROR_INVALID_SERIAL_PORT} + return &PortError{code: InvalidSerialPort} } return nil } @@ -212,9 +212,9 @@ func OpenPort(portName string, mode *Mode) (*SerialPort, error) { if err != nil { switch err { case syscall.ERROR_ACCESS_DENIED: - return nil, &SerialPortError{code: ERROR_PORT_BUSY} + return nil, &PortError{code: PortBusy} case syscall.ERROR_FILE_NOT_FOUND: - return nil, &SerialPortError{code: ERROR_PORT_NOT_FOUND} + return nil, &PortError{code: PortNotFound} } return nil, err } @@ -226,13 +226,13 @@ func OpenPort(portName string, mode *Mode) (*SerialPort, error) { // Set port parameters if port.SetMode(mode) != nil { port.Close() - return nil, &SerialPortError{code: ERROR_INVALID_SERIAL_PORT} + return nil, &PortError{code: InvalidSerialPort} } params := &DCB{} if GetCommState(port.handle, params) != nil { port.Close() - return nil, &SerialPortError{code: ERROR_INVALID_SERIAL_PORT} + return nil, &PortError{code: InvalidSerialPort} } params.Flags |= DCB_RTS_CONTROL_ENABLE | DCB_DTR_CONTROL_ENABLE params.Flags &= ^uint32(DCB_OUT_X_CTS_FLOW) @@ -249,7 +249,7 @@ func OpenPort(portName string, mode *Mode) (*SerialPort, error) { params.XoffChar = 19 // C3 if SetCommState(port.handle, params) != nil { port.Close() - return nil, &SerialPortError{code: ERROR_INVALID_SERIAL_PORT} + return nil, &PortError{code: InvalidSerialPort} } // Set timeouts to 1 second @@ -262,9 +262,8 @@ func OpenPort(portName string, mode *Mode) (*SerialPort, error) { } if SetCommTimeouts(port.handle, timeouts) != nil { port.Close() - return nil, &SerialPortError{code: ERROR_INVALID_SERIAL_PORT} + return nil, &PortError{code: InvalidSerialPort} } return port, nil } -