...
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 package serial
27
28 import (
29 "errors"
30 "io"
31 )
32 import "os"
33 import "syscall"
34 import "unsafe"
35
36
37 type cc_t byte
38 type speed_t uint64
39 type tcflag_t uint64
40
41
42 const (
43 kCS5 = 0x00000000
44 kCS6 = 0x00000100
45 kCS7 = 0x00000200
46 kCS8 = 0x00000300
47 kCLOCAL = 0x00008000
48 kCREAD = 0x00000800
49 kCSTOPB = 0x00000400
50 kIGNPAR = 0x00000004
51 kPARENB = 0x00001000
52 kPARODD = 0x00002000
53 kCCTS_OFLOW = 0x00010000
54 kCRTS_IFLOW = 0x00020000
55 kCRTSCTS = kCCTS_OFLOW | kCRTS_IFLOW
56
57 kNCCS = 20
58
59 kVMIN = tcflag_t(16)
60 kVTIME = tcflag_t(17)
61 )
62
63 const (
64
65
66 kTIOCGETA = 1078490131
67 kTIOCSETA = 2152231956
68
69
70 kIOSSIOSPEED = 0x80045402
71 )
72
73
74 type termios struct {
75 c_iflag tcflag_t
76 c_oflag tcflag_t
77 c_cflag tcflag_t
78 c_lflag tcflag_t
79 c_cc [kNCCS]cc_t
80 c_ispeed speed_t
81 c_ospeed speed_t
82 }
83
84
85
86
87 func setTermios(fd uintptr, src *termios) error {
88
89 r1, _, errno :=
90 syscall.Syscall(
91 syscall.SYS_IOCTL,
92 fd,
93 uintptr(kTIOCSETA),
94 uintptr(unsafe.Pointer(src)))
95
96
97 if errno != 0 {
98 return os.NewSyscallError("SYS_IOCTL", errno)
99 }
100
101
102 if r1 != 0 {
103 return errors.New("Unknown error from SYS_IOCTL.")
104 }
105
106 return nil
107 }
108
109 func convertOptions(options OpenOptions) (*termios, error) {
110 var result termios
111
112
113
114 result.c_cflag |= kCLOCAL
115
116
117
118
119
120 result.c_cflag |= kCREAD
121
122
123 vtime := uint(round(float64(options.InterCharacterTimeout)/100.0) * 100)
124 vmin := options.MinimumReadSize
125
126 if vmin == 0 && vtime < 100 {
127 return nil, errors.New("Invalid values for InterCharacterTimeout and MinimumReadSize.")
128 }
129
130 if vtime > 25500 {
131 return nil, errors.New("Invalid value for InterCharacterTimeout.")
132 }
133
134
135 result.c_cc[kVTIME] = cc_t(vtime / 100)
136 result.c_cc[kVMIN] = cc_t(vmin)
137
138 if !IsStandardBaudRate(options.BaudRate) {
139
140
141
142 result.c_ispeed = 14400
143 result.c_ospeed = 14400
144 } else {
145 result.c_ispeed = speed_t(options.BaudRate)
146 result.c_ospeed = speed_t(options.BaudRate)
147 }
148
149
150 switch options.DataBits {
151 case 5:
152 result.c_cflag |= kCS5
153 case 6:
154 result.c_cflag |= kCS6
155 case 7:
156 result.c_cflag |= kCS7
157 case 8:
158 result.c_cflag |= kCS8
159 default:
160 return nil, errors.New("Invalid setting for DataBits.")
161 }
162
163
164 switch options.StopBits {
165 case 1:
166
167 case 2:
168 result.c_cflag |= kCSTOPB
169 default:
170 return nil, errors.New("Invalid setting for StopBits.")
171 }
172
173
174 switch options.ParityMode {
175 case PARITY_NONE:
176
177 case PARITY_ODD:
178
179
180
181 result.c_cflag |= kPARENB
182 result.c_cflag |= kPARODD
183 case PARITY_EVEN:
184
185
186
187 result.c_cflag |= kPARENB
188 default:
189 return nil, errors.New("Invalid setting for ParityMode.")
190 }
191
192 if options.RTSCTSFlowControl {
193 result.c_cflag |= kCRTSCTS
194 }
195
196 return &result, nil
197 }
198
199 func openInternal(options OpenOptions) (io.ReadWriteCloser, error) {
200
201
202 file, err :=
203 os.OpenFile(
204 options.PortName,
205 syscall.O_RDWR|syscall.O_NOCTTY|syscall.O_NONBLOCK,
206 0600)
207
208 if err != nil {
209 return nil, err
210 }
211
212
213 r1, _, errno :=
214 syscall.Syscall(
215 syscall.SYS_FCNTL,
216 uintptr(file.Fd()),
217 uintptr(syscall.F_SETFL),
218 uintptr(0))
219
220 if errno != 0 {
221 return nil, os.NewSyscallError("SYS_FCNTL", errno)
222 }
223
224 if r1 != 0 {
225 return nil, errors.New("Unknown error from SYS_FCNTL.")
226 }
227
228
229 terminalOptions, err := convertOptions(options)
230 if err != nil {
231 return nil, err
232 }
233
234 err = setTermios(file.Fd(), terminalOptions)
235 if err != nil {
236 return nil, err
237 }
238
239 if !IsStandardBaudRate(options.BaudRate) {
240
241 r2, _, errno2 := syscall.Syscall(
242 syscall.SYS_IOCTL,
243 uintptr(file.Fd()),
244 uintptr(kIOSSIOSPEED),
245 uintptr(unsafe.Pointer(&options.BaudRate)))
246
247 if errno2 != 0 {
248 return nil, os.NewSyscallError("SYS_IOCTL", errno2)
249 }
250
251 if r2 != 0 {
252 return nil, errors.New("Unknown error from SYS_IOCTL.")
253 }
254 }
255
256
257 return file, nil
258 }
259
View as plain text