forked from bugst/go-serial
-
Notifications
You must be signed in to change notification settings - Fork 0
/
serial.go
242 lines (210 loc) · 7.61 KB
/
serial.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
//
// 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)
RS485 RS485Config // RS485 configuration
}
// RS485Config -- platform independent RS485 config. Thie structure is ignored unless Enable is true.
type RS485Config struct {
// Enable RS485 support
Enabled bool
// Delay RTS prior to send
DelayRtsBeforeSend time.Duration
// Delay RTS after send
DelayRtsAfterSend time.Duration
// Set RTS high during send
RtsHighDuringSend bool
// Set RTS high after send
RtsHighAfterSend bool
// Rx during Tx
RxDuringTx bool
}
// 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
// ReadFailed indicates the read failed
ReadFailed
// ConfigureRS485Error indicates an error configuring RS485 on the platform
ConfigureRS485Error
// NoPlatformSupportForRS485 indicates no platform support for RS485
NoPlatformSupportForRS485
)
// 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"
case ReadFailed:
return "Read failed"
case ConfigureRS485Error:
return "Error configuring RS485 on the platform"
case NoPlatformSupportForRS485:
return "Platform does not support RS485"
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
}