214 lines
6.7 KiB
Go
214 lines
6.7 KiB
Go
|
//
|
||
|
// Copyright 2014-2023 Cristian Maglie. All rights reserved.
|
||
|
// Use of this source code is governed by a BSD-style
|
||
|
// license that can be found in the LICENSE file.
|
||
|
//
|
||
|
|
||
|
package serial
|
||
|
|
||
|
import "time"
|
||
|
|
||
|
//go:generate go run golang.org/x/sys/windows/mkwinsyscall -output zsyscall_windows.go syscall_windows.go
|
||
|
|
||
|
// 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)
|
||
|
|
||
|
// Wait until all data in the buffer are sent
|
||
|
Drain() error
|
||
|
|
||
|
// ResetInputBuffer Purges port read buffer
|
||
|
ResetInputBuffer() error
|
||
|
|
||
|
// ResetOutputBuffer Purges port write buffer
|
||
|
ResetOutputBuffer() error
|
||
|
|
||
|
// SetDTR sets the modem status bit DataTerminalReady
|
||
|
SetDTR(dtr bool) error
|
||
|
|
||
|
// SetRTS sets the modem status bit RequestToSend
|
||
|
SetRTS(rts bool) error
|
||
|
|
||
|
// GetModemStatusBits returns a ModemStatusBits structure containing the
|
||
|
// modem status bits for the serial port (CTS, DSR, etc...)
|
||
|
GetModemStatusBits() (*ModemStatusBits, error)
|
||
|
|
||
|
// SetReadTimeout sets the timeout for the Read operation or use serial.NoTimeout
|
||
|
// to disable read timeout.
|
||
|
SetReadTimeout(t time.Duration) error
|
||
|
|
||
|
// Close the serial port
|
||
|
Close() error
|
||
|
|
||
|
// Break sends a break for a determined time
|
||
|
Break(time.Duration) error
|
||
|
}
|
||
|
|
||
|
// NoTimeout should be used as a parameter to SetReadTimeout to disable timeout.
|
||
|
var NoTimeout time.Duration = -1
|
||
|
|
||
|
// ModemStatusBits contains all the modem input status bits for a serial port (CTS, DSR, etc...).
|
||
|
// It can be retrieved with the Port.GetModemStatusBits() method.
|
||
|
type ModemStatusBits struct {
|
||
|
CTS bool // ClearToSend status
|
||
|
DSR bool // DataSetReady status
|
||
|
RI bool // RingIndicator status
|
||
|
DCD bool // DataCarrierDetect status
|
||
|
}
|
||
|
|
||
|
// ModemOutputBits contains all the modem output bits for a serial port.
|
||
|
// This is used in the Mode.InitialStatusBits struct to specify the initial status of the bits.
|
||
|
// Note: Linux and MacOSX (and basically all unix-based systems) can not set the status bits
|
||
|
// before opening the port, even if the initial state of the bit is set to false they will go
|
||
|
// anyway to true for a few milliseconds, resulting in a small pulse.
|
||
|
type ModemOutputBits struct {
|
||
|
RTS bool // ReadyToSend status
|
||
|
DTR bool // DataTerminalReady status
|
||
|
}
|
||
|
|
||
|
// Open opens the serial port using the specified modes
|
||
|
func Open(portName string, mode *Mode) (Port, error) {
|
||
|
port, err := nativeOpen(portName, mode)
|
||
|
if err != nil {
|
||
|
// Return a nil interface, for which var==nil is true (instead of
|
||
|
// a nil pointer to a struct that satisfies the interface).
|
||
|
return nil, err
|
||
|
}
|
||
|
return port, err
|
||
|
}
|
||
|
|
||
|
// 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)
|
||
|
DataBits int // Size of the character (must be 5, 6, 7 or 8)
|
||
|
Parity Parity // Parity (see Parity type for more info)
|
||
|
StopBits StopBits // Stop bits (see StopBits type for more info)
|
||
|
InitialStatusBits *ModemOutputBits // Initial output modem bits status (if nil defaults to DTR=true and RTS=true)
|
||
|
}
|
||
|
|
||
|
// Parity describes a serial port parity setting
|
||
|
type Parity int
|
||
|
|
||
|
const (
|
||
|
// 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 (
|
||
|
// OneStopBit sets 1 stop bit (default)
|
||
|
OneStopBit StopBits = iota
|
||
|
// OnePointFiveStopBits sets 1.5 stop bits
|
||
|
OnePointFiveStopBits
|
||
|
// TwoStopBits sets 2 stop bits
|
||
|
TwoStopBits
|
||
|
)
|
||
|
|
||
|
// PortError is a platform independent error type for serial ports
|
||
|
type PortError struct {
|
||
|
code PortErrorCode
|
||
|
causedBy error
|
||
|
}
|
||
|
|
||
|
// PortErrorCode is a code to easily identify the type of error
|
||
|
type PortErrorCode int
|
||
|
|
||
|
const (
|
||
|
// 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
|
||
|
// InvalidParity the selected parity is not valid or not supported
|
||
|
InvalidParity
|
||
|
// InvalidStopBits the selected number of stop bits is not valid or not supported
|
||
|
InvalidStopBits
|
||
|
// InvalidTimeoutValue the timeout value is not valid or not supported
|
||
|
InvalidTimeoutValue
|
||
|
// ErrorEnumeratingPorts an error occurred while listing serial port
|
||
|
ErrorEnumeratingPorts
|
||
|
// PortClosed the port has been closed while the operation is in progress
|
||
|
PortClosed
|
||
|
// FunctionNotImplemented the requested function is not implemented
|
||
|
FunctionNotImplemented
|
||
|
)
|
||
|
|
||
|
// EncodedErrorString returns a string explaining the error code
|
||
|
func (e PortError) EncodedErrorString() string {
|
||
|
switch e.code {
|
||
|
case PortBusy:
|
||
|
return "Serial port busy"
|
||
|
case PortNotFound:
|
||
|
return "Serial port not found"
|
||
|
case InvalidSerialPort:
|
||
|
return "Invalid serial port"
|
||
|
case PermissionDenied:
|
||
|
return "Permission denied"
|
||
|
case InvalidSpeed:
|
||
|
return "Port speed invalid or not supported"
|
||
|
case InvalidDataBits:
|
||
|
return "Port data bits invalid or not supported"
|
||
|
case InvalidParity:
|
||
|
return "Port parity invalid or not supported"
|
||
|
case InvalidStopBits:
|
||
|
return "Port stop bits invalid or not supported"
|
||
|
case InvalidTimeoutValue:
|
||
|
return "Timeout value invalid or not supported"
|
||
|
case ErrorEnumeratingPorts:
|
||
|
return "Could not enumerate serial ports"
|
||
|
case PortClosed:
|
||
|
return "Port has been closed"
|
||
|
case FunctionNotImplemented:
|
||
|
return "Function not implemented"
|
||
|
default:
|
||
|
return "Other error"
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Error returns the complete error code with details on the cause of the error
|
||
|
func (e PortError) Error() string {
|
||
|
if e.causedBy != nil {
|
||
|
return e.EncodedErrorString() + ": " + e.causedBy.Error()
|
||
|
}
|
||
|
return e.EncodedErrorString()
|
||
|
}
|
||
|
|
||
|
// Code returns an identifier for the kind of error occurred
|
||
|
func (e PortError) Code() PortErrorCode {
|
||
|
return e.code
|
||
|
}
|