rubyserial-with-blocking 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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