rubyserial-with-blocking 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,140 @@
1
+ require 'ffi'
2
+
3
+ class Serial
4
+
5
+ Defaults = {
6
+ baude_rate: 9600,
7
+ data_bits: 8,
8
+ vmin: 0,
9
+ }
10
+
11
+ attr_reader :config
12
+
13
+ # config value order is, in that order, from low to high:
14
+ #
15
+ # config hash -over-> baud_rate, data_bits -over-> Defaults
16
+ #
17
+ def initialize(address, baude_rate = nil, data_bits = nil, config = {})
18
+ # XXX this is kind of ugly, but neccessary to preserve old orginal code
19
+ # behaviour with default values
20
+ config[:baude_rate] ||= (baude_rate || Defaults[:baude_rate])
21
+ config[:data_bits] ||= (data_bits || Defaults[:data_bits])
22
+ @config = Defaults.merge(config)
23
+
24
+ file_opts = RubySerial::Posix::O_RDWR | RubySerial::Posix::O_NOCTTY | RubySerial::Posix::O_NONBLOCK
25
+ @fd = RubySerial::Posix.open(address, file_opts)
26
+
27
+ if @fd == -1
28
+ raise RubySerial::Exception, RubySerial::Posix::ERROR_CODES[FFI.errno]
29
+ else
30
+ @open = true
31
+ end
32
+
33
+ fl = RubySerial::Posix.fcntl(@fd, RubySerial::Posix::F_GETFL, :int, 0)
34
+ if fl == -1
35
+ raise RubySerial::Exception, RubySerial::Posix::ERROR_CODES[FFI.errno]
36
+ end
37
+
38
+ err = RubySerial::Posix.fcntl(@fd, RubySerial::Posix::F_SETFL, :int, ~RubySerial::Posix::O_NONBLOCK & fl)
39
+ if err == -1
40
+ raise RubySerial::Exception, RubySerial::Posix::ERROR_CODES[FFI.errno]
41
+ end
42
+
43
+ termio = build_config(@config)
44
+ err = RubySerial::Posix.tcsetattr(@fd, RubySerial::Posix::TCSANOW, termio)
45
+ if err == -1
46
+ raise RubySerial::Exception, RubySerial::Posix::ERROR_CODES[FFI.errno]
47
+ end
48
+ end
49
+
50
+ def closed?
51
+ !@open
52
+ end
53
+
54
+ # use the file descriptor, or IO object instance around it, for blocking read
55
+ # with IO#select or for waiting on multiple i/o lines & events
56
+ #
57
+ attr_reader :fd
58
+ def io; @io ||= IO.new(@fd); end
59
+
60
+ def close
61
+ err = RubySerial::Posix.close(@fd)
62
+ if err == -1
63
+ raise RubySerial::Exception, RubySerial::Posix::ERROR_CODES[FFI.errno]
64
+ else
65
+ @open = false
66
+ end
67
+ end
68
+
69
+ def write(data)
70
+ data = data.to_s
71
+ n = 0
72
+ while data.size > n do
73
+ buff = FFI::MemoryPointer.from_string(data[n..-1].to_s)
74
+ i = RubySerial::Posix.write(@fd, buff, buff.size-1)
75
+ if i == -1
76
+ raise RubySerial::Exception, RubySerial::Posix::ERROR_CODES[FFI.errno]
77
+ else
78
+ n = n+i
79
+ end
80
+ end
81
+
82
+ # return number of bytes written
83
+ n
84
+ end
85
+
86
+ def read(size)
87
+ buff = FFI::MemoryPointer.new :char, size
88
+ i = RubySerial::Posix.read(@fd, buff, size)
89
+ if i == -1
90
+ raise RubySerial::Exception, RubySerial::Posix::ERROR_CODES[FFI.errno]
91
+ end
92
+ buff.get_bytes(0, i)
93
+ end
94
+
95
+ def getbyte
96
+ buff = FFI::MemoryPointer.new :char, 1
97
+ i = RubySerial::Posix.read(@fd, buff, 1)
98
+ if i == -1
99
+ raise RubySerial::Exception, RubySerial::Posix::ERROR_CODES[FFI.errno]
100
+ end
101
+
102
+ if i == 0
103
+ nil
104
+ else
105
+ buff.get_bytes(0,1).bytes.first
106
+ end
107
+ end
108
+
109
+ def gets(sep=$/, limit=nil)
110
+ sep = "\n\n" if sep == ''
111
+ # This allows the method signature to be (sep) or (limit)
112
+ (limit = sep; sep="\n") if sep.is_a? Integer
113
+ bytes = []
114
+ loop do
115
+ current_byte = getbyte
116
+ bytes << current_byte unless current_byte.nil?
117
+ break if (bytes.last(sep.bytes.to_a.size) == sep.bytes.to_a) || ((bytes.size == limit) if limit)
118
+ end
119
+
120
+ bytes.map { |e| e.chr }.join
121
+ end
122
+
123
+ private
124
+
125
+ def build_config(opts)
126
+ termio = RubySerial::Posix::Termios.new
127
+
128
+ termio[:c_iflag] = RubySerial::Posix::IGNPAR
129
+ termio[:c_ispeed] = RubySerial::Posix::BAUDE_RATES[opts[:baude_rate]]
130
+ termio[:c_ospeed] = RubySerial::Posix::BAUDE_RATES[opts[:baude_rate]]
131
+ termio[:c_cflag] = RubySerial::Posix::DATA_BITS[opts[:data_bits]] |
132
+ RubySerial::Posix::CREAD |
133
+ RubySerial::Posix::CLOCAL |
134
+ RubySerial::Posix::BAUDE_RATES[opts[:baude_rate]]
135
+
136
+ termio[:cc_c][RubySerial::Posix::VMIN] = opts[:vmin]
137
+
138
+ termio
139
+ end
140
+ end
@@ -0,0 +1,5 @@
1
+ module RubySerial
2
+ unless const_defined?('VERSION')
3
+ VERSION = "0.2.3"
4
+ end
5
+ end
@@ -0,0 +1,104 @@
1
+ require 'ffi'
2
+
3
+ class Serial
4
+ def initialize(address, baude_rate=9600, data_bits=8)
5
+ file_opts = RubySerial::Win32::GENERIC_READ | RubySerial::Win32::GENERIC_WRITE
6
+ @fd = RubySerial::Win32.CreateFileA("\\\\.\\#{address}", file_opts, 0, nil, RubySerial::Win32::OPEN_EXISTING, 0, nil)
7
+ err = FFI.errno
8
+ if err != 0
9
+ raise RubySerial::Exception, RubySerial::Win32::ERROR_CODES[err]
10
+ else
11
+ @open = true
12
+ end
13
+
14
+ RubySerial::Win32::DCB.new.tap do |dcb|
15
+ dcb[:dcblength] = RubySerial::Win32::DCB::Sizeof
16
+ err = RubySerial::Win32.GetCommState @fd, dcb
17
+ if err == 0
18
+ raise RubySerial::Exception, RubySerial::Win32::ERROR_CODES[FFI.errno]
19
+ end
20
+ dcb[:baudrate] = baude_rate
21
+ dcb[:bytesize] = data_bits
22
+ dcb[:stopbits] = RubySerial::Win32::DCB::ONESTOPBIT
23
+ dcb[:parity] = RubySerial::Win32::DCB::NOPARITY
24
+ err = RubySerial::Win32.SetCommState @fd, dcb
25
+ if err == 0
26
+ raise RubySerial::Exception, RubySerial::Win32::ERROR_CODES[FFI.errno]
27
+ end
28
+ end
29
+
30
+ RubySerial::Win32::CommTimeouts.new.tap do |timeouts|
31
+ timeouts[:read_interval_timeout] = 10
32
+ timeouts[:read_total_timeout_multiplier] = 1
33
+ timeouts[:read_total_timeout_constant] = 10
34
+ timeouts[:write_total_timeout_multiplier] = 1
35
+ timeouts[:write_total_timeout_constant] = 10
36
+ err = RubySerial::Win32.SetCommTimeouts @fd, timeouts
37
+ if err == 0
38
+ raise RubySerial::Exception, RubySerial::Win32::ERROR_CODES[FFI.errno]
39
+ end
40
+ end
41
+ end
42
+
43
+ def read(size)
44
+ buff = FFI::MemoryPointer.new :char, size
45
+ count = FFI::MemoryPointer.new :uint32, 1
46
+ err = RubySerial::Win32.ReadFile(@fd, buff, size, count, nil)
47
+ if err == 0
48
+ raise RubySerial::Exception, RubySerial::Win32::ERROR_CODES[FFI.errno]
49
+ end
50
+ buff.get_bytes(0, count.read_int)
51
+ end
52
+
53
+ def getbyte
54
+ buff = FFI::MemoryPointer.new :char, 1
55
+ count = FFI::MemoryPointer.new :uint32, 1
56
+ err = RubySerial::Win32.ReadFile(@fd, buff, 1, count, nil)
57
+ if err == 0
58
+ raise RubySerial::Exception, RubySerial::Win32::ERROR_CODES[FFI.errno]
59
+ end
60
+
61
+ if count.read_int == 0
62
+ nil
63
+ else
64
+ buff.read_string.unpack('C').first
65
+ end
66
+ end
67
+
68
+ def write(data)
69
+ buff = FFI::MemoryPointer.from_string(data.to_s)
70
+ count = FFI::MemoryPointer.new :uint32, 1
71
+ err = RubySerial::Win32.WriteFile(@fd, buff, buff.size-1, count, nil)
72
+ if err == 0
73
+ raise RubySerial::Exception, RubySerial::Win32::ERROR_CODES[FFI.errno]
74
+ end
75
+ count.read_int
76
+ end
77
+
78
+ def gets(sep=$/, limit=nil)
79
+ sep = "\n\n" if sep == ''
80
+ # This allows the method signature to be (sep) or (limit)
81
+ (limit = sep; sep="\n") if sep.is_a? Integer
82
+ bytes = []
83
+ loop do
84
+ current_byte = getbyte
85
+ bytes << current_byte unless current_byte.nil?
86
+ break if (bytes.last(sep.bytes.to_a.size) == sep.bytes.to_a) || ((bytes.size == limit) if limit)
87
+ end
88
+
89
+ bytes.map { |e| e.chr }.join
90
+ end
91
+
92
+ def close
93
+ err = RubySerial::Win32.CloseHandle(@fd)
94
+ if err == 0
95
+ raise RubySerial::Exception, RubySerial::Win32::ERROR_CODES[FFI.errno]
96
+ else
97
+ @open = false
98
+ end
99
+ end
100
+
101
+ def closed?
102
+ !@open
103
+ end
104
+ end
@@ -0,0 +1,275 @@
1
+ require 'ffi'
2
+
3
+ module RubySerial
4
+ module Win32
5
+ extend FFI::Library
6
+ ffi_lib 'kernel32'
7
+ ffi_convention :stdcall
8
+
9
+ GENERIC_READ = 0x80000000
10
+ GENERIC_WRITE = 0x40000000
11
+ OPEN_EXISTING = 3
12
+
13
+ ERROR_CODES = {
14
+ 5 => "ERROR_ACCESS_DENIED",
15
+ 57 => "ERROR_ADAP_HDW_ERR",
16
+ 85 => "ERROR_ALREADY_ASSIGNED",
17
+ 183 => "ERROR_ALREADY_EXISTS",
18
+ 7 => "ERROR_ARENA_TRASHED",
19
+ 174 => "ERROR_ATOMIC_LOCKS_NOT_SUPPORTED",
20
+ 199 => "ERROR_AUTODATASEG_EXCEEDS_64k",
21
+ 160 => "ERROR_BAD_ARGUMENTS",
22
+ 22 => "ERROR_BAD_COMMAND",
23
+ 66 => "ERROR_BAD_DEV_TYPE",
24
+ 119 => "ERROR_BAD_DRIVER_LEVEL",
25
+ 10 => "ERROR_BAD_ENVIRONMENT",
26
+ 193 => "ERROR_BAD_EXE_FORMAT",
27
+ 222 => "ERROR_BAD_FILE_TYPE",
28
+ 11 => "ERROR_BAD_FORMAT",
29
+ 24 => "ERROR_BAD_LENGTH",
30
+ 67 => "ERROR_BAD_NET_NAME",
31
+ 58 => "ERROR_BAD_NET_RESP",
32
+ 53 => "ERROR_BAD_NETPATH",
33
+ 161 => "ERROR_BAD_PATHNAME",
34
+ 230 => "ERROR_BAD_PIPE",
35
+ 60 => "ERROR_BAD_REM_ADAP",
36
+ 159 => "ERROR_BAD_THREADID_ADDR",
37
+ 20 => "ERROR_BAD_UNIT",
38
+ 109 => "ERROR_BROKEN_PIPE",
39
+ 111 => "ERROR_BUFFER_OVERFLOW",
40
+ 142 => "ERROR_BUSY_DRIVE",
41
+ 170 => "ERROR_BUSY",
42
+ 120 => "ERROR_CALL_NOT_IMPLEMENTED",
43
+ 173 => "ERROR_CANCEL_VIOLATION",
44
+ 266 => "ERROR_CANNOT_COPY",
45
+ 82 => "ERROR_CANNOT_MAKE",
46
+ 221 => "ERROR_CHECKOUT_REQUIRED",
47
+ 129 => "ERROR_CHILD_NOT_COMPLETE",
48
+ 23 => "ERROR_CRC",
49
+ 16 => "ERROR_CURRENT_DIRECTORY",
50
+ 303 => "ERROR_DELETE_PENDING",
51
+ 55 => "ERROR_DEV_NOT_EXIST",
52
+ 145 => "ERROR_DIR_NOT_EMPTY",
53
+ 144 => "ERROR_DIR_NOT_ROOT",
54
+ 130 => "ERROR_DIRECT_ACCESS_HANDLE",
55
+ 267 => "ERROR_DIRECTORY",
56
+ 157 => "ERROR_DISCARDED",
57
+ 107 => "ERROR_DISK_CHANGE",
58
+ 112 => "ERROR_DISK_FULL",
59
+ 302 => "ERROR_DISK_TOO_FRAGMENTED",
60
+ 108 => "ERROR_DRIVE_LOCKED",
61
+ 52 => "ERROR_DUP_NAME",
62
+ 196 => "ERROR_DYNLINK_FROM_INVALID_RING",
63
+ 276 => "ERROR_EA_FILE_CORRUPT",
64
+ 255 => "ERROR_EA_LIST_INCONSISTENT",
65
+ 277 => "ERROR_EA_TABLE_FULL",
66
+ 275 => "ERROR_EAS_DIDNT_FIT",
67
+ 282 => "ERROR_EAS_NOT_SUPPORTED",
68
+ 203 => "ERROR_ENVVAR_NOT_FOUND",
69
+ 101 => "ERROR_EXCL_SEM_ALREADY_OWNED",
70
+ 217 => "ERROR_EXE_CANNOT_MODIFY_SIGNED_BINARY",
71
+ 218 => "ERROR_EXE_CANNOT_MODIFY_STRONG_SIGNED_BINARY",
72
+ 216 => "ERROR_EXE_MACHINE_TYPE_MISMATCH",
73
+ 192 => "ERROR_EXE_MARKED_INVALID",
74
+ 83 => "ERROR_FAIL_I24",
75
+ 350 => "ERROR_FAIL_NOACTION_REBOOT",
76
+ 352 => "ERROR_FAIL_RESTART",
77
+ 351 => "ERROR_FAIL_SHUTDOWN",
78
+ 220 => "ERROR_FILE_CHECKED_OUT",
79
+ 80 => "ERROR_FILE_EXISTS",
80
+ 2 => "ERROR_FILE_NOT_FOUND",
81
+ 223 => "ERROR_FILE_TOO_LARGE",
82
+ 206 => "ERROR_FILENAME_EXCED_RANGE",
83
+ 224 => "ERROR_FORMS_AUTH_REQUIRED",
84
+ 31 => "ERROR_GEN_FAILURE",
85
+ 39 => "ERROR_HANDLE_DISK_FULL",
86
+ 38 => "ERROR_HANDLE_EOF",
87
+ 308 => "ERROR_IMAGE_SUBSYSTEM_NOT_PRESENT",
88
+ 304 => "ERROR_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING",
89
+ 202 => "ERROR_INFLOOP_IN_RELOC_CHAIN",
90
+ 122 => "ERROR_INSUFFICIENT_BUFFER",
91
+ 12 => "ERROR_INVALID_ACCESS",
92
+ 487 => "ERROR_INVALID_ADDRESS",
93
+ 104 => "ERROR_INVALID_AT_INTERRUPT_TIME",
94
+ 9 => "ERROR_INVALID_BLOCK",
95
+ 117 => "ERROR_INVALID_CATEGORY",
96
+ 13 => "ERROR_INVALID_DATA",
97
+ 15 => "ERROR_INVALID_DRIVE",
98
+ 278 => "ERROR_INVALID_EA_HANDLE",
99
+ 254 => "ERROR_INVALID_EA_NAME",
100
+ 151 => "ERROR_INVALID_EVENT_COUNT",
101
+ 191 => "ERROR_INVALID_EXE_SIGNATURE",
102
+ 186 => "ERROR_INVALID_FLAG_NUMBER",
103
+ 1 => "ERROR_INVALID_FUNCTION",
104
+ 6 => "ERROR_INVALID_HANDLE",
105
+ 124 => "ERROR_INVALID_LEVEL",
106
+ 153 => "ERROR_INVALID_LIST_FORMAT",
107
+ 307 => "ERROR_INVALID_LOCK_RANGE",
108
+ 195 => "ERROR_INVALID_MINALLOCSIZE",
109
+ 190 => "ERROR_INVALID_MODULETYPE",
110
+ 123 => "ERROR_INVALID_NAME",
111
+ 301 => "ERROR_INVALID_OPLOCK_PROTOCOL",
112
+ 182 => "ERROR_INVALID_ORDINAL",
113
+ 87 => "ERROR_INVALID_PARAMETER",
114
+ 86 => "ERROR_INVALID_PASSWORD",
115
+ 198 => "ERROR_INVALID_SEGDPL",
116
+ 180 => "ERROR_INVALID_SEGMENT_NUMBER",
117
+ 209 => "ERROR_INVALID_SIGNAL_NUMBER",
118
+ 189 => "ERROR_INVALID_STACKSEG",
119
+ 188 => "ERROR_INVALID_STARTING_CODESEG",
120
+ 114 => "ERROR_INVALID_TARGET_HANDLE",
121
+ 118 => "ERROR_INVALID_VERIFY_SWITCH",
122
+ 197 => "ERROR_IOPL_NOT_ENABLED",
123
+ 147 => "ERROR_IS_JOIN_PATH",
124
+ 133 => "ERROR_IS_JOIN_TARGET",
125
+ 134 => "ERROR_IS_JOINED",
126
+ 146 => "ERROR_IS_SUBST_PATH",
127
+ 149 => "ERROR_IS_SUBST_TARGET",
128
+ 135 => "ERROR_IS_SUBSTED",
129
+ 194 => "ERROR_ITERATED_DATA_EXCEEDS_64k",
130
+ 138 => "ERROR_JOIN_TO_JOIN",
131
+ 140 => "ERROR_JOIN_TO_SUBST",
132
+ 154 => "ERROR_LABEL_TOO_LONG",
133
+ 167 => "ERROR_LOCK_FAILED",
134
+ 33 => "ERROR_LOCK_VIOLATION",
135
+ 212 => "ERROR_LOCKED",
136
+ 353 => "ERROR_MAX_SESSIONS_REACHED",
137
+ 164 => "ERROR_MAX_THRDS_REACHED",
138
+ 208 => "ERROR_META_EXPANSION_TOO_LONG",
139
+ 126 => "ERROR_MOD_NOT_FOUND",
140
+ 234 => "ERROR_MORE_DATA",
141
+ 317 => "ERROR_MR_MID_NOT_FOUND",
142
+ 131 => "ERROR_NEGATIVE_SEEK",
143
+ 215 => "ERROR_NESTING_NOT_ALLOWED",
144
+ 88 => "ERROR_NET_WRITE_FAULT",
145
+ 64 => "ERROR_NETNAME_DELETED",
146
+ 65 => "ERROR_NETWORK_ACCESS_DENIED",
147
+ 54 => "ERROR_NETWORK_BUSY",
148
+ 232 => "ERROR_NO_DATA",
149
+ 18 => "ERROR_NO_MORE_FILES",
150
+ 259 => "ERROR_NO_MORE_ITEMS",
151
+ 113 => "ERROR_NO_MORE_SEARCH_HANDLES",
152
+ 89 => "ERROR_NO_PROC_SLOTS",
153
+ 205 => "ERROR_NO_SIGNAL_SENT",
154
+ 62 => "ERROR_NO_SPOOL_SPACE",
155
+ 125 => "ERROR_NO_VOLUME_LABEL",
156
+ 26 => "ERROR_NOT_DOS_DISK",
157
+ 8 => "ERROR_NOT_ENOUGH_MEMORY",
158
+ 136 => "ERROR_NOT_JOINED",
159
+ 158 => "ERROR_NOT_LOCKED",
160
+ 288 => "ERROR_NOT_OWNER",
161
+ 21 => "ERROR_NOT_READY",
162
+ 17 => "ERROR_NOT_SAME_DEVICE",
163
+ 137 => "ERROR_NOT_SUBSTED",
164
+ 50 => "ERROR_NOT_SUPPORTED",
165
+ 309 => "ERROR_NOTIFICATION_GUID_ALREADY_DEFINED",
166
+ 110 => "ERROR_OPEN_FAILED",
167
+ 300 => "ERROR_OPLOCK_NOT_GRANTED",
168
+ 28 => "ERROR_OUT_OF_PAPER",
169
+ 84 => "ERROR_OUT_OF_STRUCTURES",
170
+ 14 => "ERROR_OUTOFMEMORY",
171
+ 299 => "ERROR_PARTIAL_COPY",
172
+ 148 => "ERROR_PATH_BUSY",
173
+ 3 => "ERROR_PATH_NOT_FOUND",
174
+ 231 => "ERROR_PIPE_BUSY",
175
+ 229 => "ERROR_PIPE_LOCAL",
176
+ 233 => "ERROR_PIPE_NOT_CONNECTED",
177
+ 63 => "ERROR_PRINT_CANCELLED",
178
+ 61 => "ERROR_PRINTQ_FULL",
179
+ 127 => "ERROR_PROC_NOT_FOUND",
180
+ 402 => "ERROR_PROCESS_MODE_ALREADY_BACKGROUND",
181
+ 403 => "ERROR_PROCESS_MODE_NOT_BACKGROUND",
182
+ 30 => "ERROR_READ_FAULT",
183
+ 72 => "ERROR_REDIR_PAUSED",
184
+ 201 => "ERROR_RELOC_CHAIN_XEEDS_SEGLIM",
185
+ 51 => "ERROR_REM_NOT_LIST",
186
+ 71 => "ERROR_REQ_NOT_ACCEP",
187
+ 207 => "ERROR_RING2_STACK_IN_USE",
188
+ 200 => "ERROR_RING2SEG_MUST_BE_MOVABLE",
189
+ 143 => "ERROR_SAME_DRIVE",
190
+ 318 => "ERROR_SCOPE_NOT_FOUND",
191
+ 27 => "ERROR_SECTOR_NOT_FOUND",
192
+ 306 => "ERROR_SECURITY_STREAM_IS_INCONSISTENT",
193
+ 132 => "ERROR_SEEK_ON_DEVICE",
194
+ 25 => "ERROR_SEEK",
195
+ 102 => "ERROR_SEM_IS_SET",
196
+ 187 => "ERROR_SEM_NOT_FOUND",
197
+ 105 => "ERROR_SEM_OWNER_DIED",
198
+ 121 => "ERROR_SEM_TIMEOUT",
199
+ 106 => "ERROR_SEM_USER_LIMIT",
200
+ 36 => "ERROR_SHARING_BUFFER_EXCEEDED",
201
+ 70 => "ERROR_SHARING_PAUSED",
202
+ 32 => "ERROR_SHARING_VIOLATION",
203
+ 305 => "ERROR_SHORT_NAMES_NOT_ENABLED_ON_VOLUME",
204
+ 162 => "ERROR_SIGNAL_PENDING",
205
+ 156 => "ERROR_SIGNAL_REFUSED",
206
+ 141 => "ERROR_SUBST_TO_JOIN",
207
+ 139 => "ERROR_SUBST_TO_SUBST",
208
+ 0 => "ERROR_SUCCESS",
209
+ 150 => "ERROR_SYSTEM_TRACE",
210
+ 210 => "ERROR_THREAD_1_INACTIVE",
211
+ 400 => "ERROR_THREAD_MODE_ALREADY_BACKGROUND",
212
+ 401 => "ERROR_THREAD_MODE_NOT_BACKGROUND",
213
+ 56 => "ERROR_TOO_MANY_CMDS",
214
+ 214 => "ERROR_TOO_MANY_MODULES",
215
+ 152 => "ERROR_TOO_MANY_MUXWAITERS",
216
+ 68 => "ERROR_TOO_MANY_NAMES",
217
+ 4 => "ERROR_TOO_MANY_OPEN_FILES",
218
+ 298 => "ERROR_TOO_MANY_POSTS",
219
+ 103 => "ERROR_TOO_MANY_SEM_REQUESTS",
220
+ 100 => "ERROR_TOO_MANY_SEMAPHORES",
221
+ 69 => "ERROR_TOO_MANY_SESS",
222
+ 155 => "ERROR_TOO_MANY_TCBS",
223
+ 59 => "ERROR_UNEXP_NET_ERR",
224
+ 240 => "ERROR_VC_DISCONNECTED",
225
+ 226 => "ERROR_VIRUS_DELETED",
226
+ 225 => "ERROR_VIRUS_INFECTED",
227
+ 128 => "ERROR_WAIT_NO_CHILDREN",
228
+ 29 => "ERROR_WRITE_FAULT",
229
+ 19 => "ERROR_WRITE_PROTECT",
230
+ 34 => "ERROR_WRONG_DISK",
231
+ 258 => "WAIT_TIMEOUT"
232
+ }
233
+
234
+ class DCB < FFI::Struct
235
+ layout :dcblength, :uint32,
236
+ :baudrate, :uint32,
237
+ :flags, :uint32, # :flag is actually a bit fields compound:
238
+ :wreserved, :uint16, # uint32 fBinary :1;
239
+ :xonlim, :uint16, # uint32 fParity :1;
240
+ :xofflim, :uint16, # uint32 fParity :1;
241
+ :bytesize, :uint8, # uint32 fOutxCtsFlow :1;
242
+ :parity, :uint8, # uint32 fOutxDsrFlow :1;
243
+ :stopbits, :uint8, # uint32 fDtrControl :2;
244
+ :xonchar, :int8, # uint32 fDsrSensitivity :1;
245
+ :xoffchar, :int8, # uint32 fTXContinueOnXoff :1;
246
+ :errorchar, :int8, # uint32 fOutX :1;
247
+ :eofchar, :int8, # uint32 fInX :1;
248
+ :evtchar, :int8, # uint32 fErrorChar :1;
249
+ :wreserved1, :uint16 # uint32 fNull :1;
250
+ # uint32 fRtsControl :2;
251
+ # uint32 fAbortOnError :1;
252
+ # uint32 fDummy2 :17;
253
+ Sizeof = 28
254
+ ONESTOPBIT = 0
255
+ NOPARITY = 0
256
+ end
257
+
258
+ class CommTimeouts < FFI::Struct
259
+ layout :read_interval_timeout, :uint32,
260
+ :read_total_timeout_multiplier, :uint32,
261
+ :read_total_timeout_constant, :uint32,
262
+ :write_total_timeout_multiplier, :uint32,
263
+ :write_total_timeout_constant, :uint32
264
+ end
265
+
266
+ attach_function :CreateFileA, [:pointer, :uint32, :uint32, :pointer, :uint32, :uint32, :pointer], :pointer
267
+ attach_function :CloseHandle, [:pointer], :int
268
+ attach_function :ReadFile, [:pointer, :pointer, :uint32, :pointer, :pointer], :int32
269
+ attach_function :WriteFile, [:pointer, :pointer, :uint32, :pointer, :pointer], :int32
270
+ attach_function :GetCommState, [:pointer, RubySerial::Win32::DCB], :int32
271
+ attach_function :SetCommState, [:pointer, RubySerial::Win32::DCB], :int32
272
+ attach_function :GetCommTimeouts, [:pointer, RubySerial::Win32::CommTimeouts], :int32
273
+ attach_function :SetCommTimeouts, [:pointer, RubySerial::Win32::CommTimeouts], :int32
274
+ end
275
+ end