rs_232 2.0.4

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,358 @@
1
+ /*
2
+ * Copyright (c) 2013, Ingenico Inc.
3
+ *
4
+ * Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted,
5
+ * provided that the above copyright notice and this permission notice appear in all copies.
6
+ *
7
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
8
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
9
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
10
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
11
+ * PERFORMANCE OF THIS SOFTWARE.
12
+ *
13
+ **/
14
+
15
+ #include "port.h"
16
+
17
+
18
+ VALUE setDtrIO(VALUE self, VALUE rb_int)
19
+ {
20
+ {
21
+ Check_Type(rb_int, T_FIXNUM);
22
+ }
23
+
24
+ int boolean = FIX2INT(rb_int);
25
+
26
+ PortDescriptor *port = NULL;
27
+
28
+ Data_Get_Struct(self, PortDescriptor, port);
29
+
30
+ return INT2FIX( EscapeCommFunction(port->fd, boolean == 1 ? SETDTR : CLRDTR) );
31
+ }
32
+
33
+
34
+ VALUE setRtsIO(VALUE self, VALUE rb_int)
35
+ {
36
+ {
37
+ Check_Type(rb_int, T_FIXNUM);
38
+ }
39
+
40
+ int boolean = FIX2INT(rb_int);
41
+
42
+ PortDescriptor *port = NULL;
43
+
44
+ Data_Get_Struct(self, PortDescriptor, port);
45
+
46
+ return INT2FIX( EscapeCommFunction(port->fd, boolean == 1 ? SETRTS : CLRRTS) );
47
+ }
48
+
49
+
50
+ VALUE lineStatusIO(VALUE self)
51
+ {
52
+
53
+ PortDescriptor *port = NULL;
54
+
55
+ Data_Get_Struct(self, PortDescriptor, port);
56
+
57
+ unsigned long Status = 0, Temp = 0;
58
+
59
+ GetCommModemStatus(port->fd, &Temp);
60
+
61
+ if (Temp & MS_CTS_ON) Status |= LS_CTS;
62
+ if (Temp & MS_DSR_ON) Status |= LS_DSR;
63
+ if (Temp & MS_RING_ON) Status |= LS_RI;
64
+ if (Temp & MS_RLSD_ON) Status |= LS_DCD;
65
+
66
+ return LONG2FIX(Status);
67
+ }
68
+
69
+
70
+ static void platformInitIO(PortDescriptor *port)
71
+ {
72
+ port->fd = INVALID_HANDLE_VALUE;
73
+ port->status = 1;
74
+ }
75
+
76
+
77
+ void updateSettings(PortDescriptor *port)
78
+ {
79
+
80
+ if (port->status != 0)
81
+ rb_raise(rb_eException, "Can not set due to comport is not open, status: %d\n", port->status);
82
+
83
+
84
+ if (port->toBeUpdated & T_BaudRate)
85
+ port->commConfig.dcb.BaudRate = port->settings.BaudRate;
86
+
87
+
88
+ if (port->toBeUpdated & T_Parity)
89
+ {
90
+ port->commConfig.dcb.Parity = (BYTE) port->settings.Parity;
91
+ port->commConfig.dcb.fParity = (port->settings.Parity == PAR_NONE) ? 0 : 1;
92
+ }
93
+
94
+
95
+ if (port->toBeUpdated & T_DataBits)
96
+ {
97
+ port->commConfig.dcb.ByteSize = (BYTE) port->settings.DataBits;
98
+ }
99
+
100
+
101
+ if (port->toBeUpdated & T_StopBits)
102
+ {
103
+ switch (port->settings.StopBits)
104
+ {
105
+ case STOP_1:
106
+ port->commConfig.dcb.StopBits = ONESTOPBIT;
107
+ break;
108
+ case STOP_2:
109
+ port->commConfig.dcb.StopBits = TWOSTOPBITS;
110
+ break;
111
+ }
112
+ }
113
+
114
+ if (port->toBeUpdated & T_Flow)
115
+ {
116
+ switch (port->settings.FlowControl)
117
+ {
118
+ case FLOW_OFF:
119
+ port->commConfig.dcb.fOutxCtsFlow = 0;
120
+ port->commConfig.dcb.fRtsControl = RTS_CONTROL_DISABLE;
121
+ port->commConfig.dcb.fInX = 0;
122
+ port->commConfig.dcb.fOutX = 0;
123
+ break;
124
+ case FLOW_XONXOFF:
125
+ port->commConfig.dcb.fOutxCtsFlow = 0;
126
+ port->commConfig.dcb.fRtsControl = RTS_CONTROL_DISABLE;
127
+ port->commConfig.dcb.fInX = 1;
128
+ port->commConfig.dcb.fOutX = 1;
129
+ break;
130
+ case FLOW_HARDWARE:
131
+ port->commConfig.dcb.fOutxCtsFlow = 1;
132
+ port->commConfig.dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
133
+ port->commConfig.dcb.fInX = 0;
134
+ port->commConfig.dcb.fOutX = 0;
135
+ break;
136
+ }
137
+ }
138
+
139
+ if (port->toBeUpdated & T_TimeOut)
140
+ {
141
+ int millisec = port->settings.Timeout_Millisec;
142
+
143
+ if (millisec == -1)
144
+ {
145
+ port->commTimeouts.ReadIntervalTimeout = MAXDWORD;
146
+ port->commTimeouts.ReadTotalTimeoutConstant = 0;
147
+ } else
148
+ {
149
+ port->commTimeouts.ReadIntervalTimeout = MAXDWORD;
150
+ port->commTimeouts.ReadTotalTimeoutConstant = millisec;
151
+ }
152
+ port->commTimeouts.ReadTotalTimeoutMultiplier = 0;
153
+ port->commTimeouts.WriteTotalTimeoutMultiplier = millisec;
154
+ port->commTimeouts.WriteTotalTimeoutConstant = 0;
155
+ }
156
+
157
+
158
+ if (port->toBeUpdated & T_SettingsDone)
159
+ SetCommConfig(port->fd, &port->commConfig, sizeof(COMMCONFIG));
160
+
161
+ if ((port->toBeUpdated & T_TimeOut))
162
+ SetCommTimeouts(port->fd, &port->commTimeouts);
163
+
164
+ port->toBeUpdated = 0;
165
+ }
166
+
167
+
168
+ static int queryStatusIO(VALUE self)
169
+ {
170
+ PortDescriptor *port = NULL;
171
+
172
+ Data_Get_Struct(self, PortDescriptor, port);
173
+
174
+ return port->status;
175
+ }
176
+
177
+
178
+ VALUE isClosedIO(VALUE self)
179
+ {
180
+ return queryStatusIO(self) != 0 ? Qtrue : Qfalse;
181
+ }
182
+
183
+
184
+ VALUE flushIO(VALUE self)
185
+ {
186
+ PortDescriptor *port = NULL;
187
+
188
+ Data_Get_Struct(self, PortDescriptor, port);
189
+
190
+ return (INT2FIX(FlushFileBuffers(port->fd)));
191
+ }
192
+
193
+
194
+ VALUE bytesAvailableIO(VALUE self)
195
+ {
196
+ PortDescriptor *port = NULL;
197
+
198
+ Data_Get_Struct(self, PortDescriptor, port);
199
+
200
+ DWORD Errors;
201
+ COMSTAT Status;
202
+ if (ClearCommError(port->fd, &Errors, &Status))
203
+ {
204
+ return INT2FIX(Status.cbInQue);
205
+ }
206
+ return INT2FIX(0);
207
+ }
208
+
209
+
210
+ VALUE openIO(VALUE self)
211
+ {
212
+
213
+ PortDescriptor *port = NULL;
214
+
215
+ Data_Get_Struct(self, PortDescriptor, port);
216
+
217
+ if (port->status == 0)
218
+ return INT2FIX(port->status);
219
+
220
+ DWORD conf_length = sizeof(COMMCONFIG);
221
+ port->commConfig.dwSize = conf_length;
222
+ DWORD threading = 0;
223
+
224
+ port->fd = CreateFileA(port->settings.ComPort,
225
+ GENERIC_READ | GENERIC_WRITE,
226
+ 0,
227
+ NULL,
228
+ OPEN_EXISTING,
229
+ threading,
230
+ NULL);
231
+
232
+ if (port->fd == INVALID_HANDLE_VALUE)
233
+ {
234
+
235
+ port->status = 1;
236
+ rb_raise(rb_eException, "Unable to open comport: %s\n", port->settings.ComPort);
237
+
238
+ } else
239
+ {
240
+
241
+ port->status = 0;
242
+ rb_iv_set(self, "@open", INT2FIX(port->status));
243
+
244
+ GetCommConfig(port->fd, &port->commConfig, &conf_length);
245
+ GetCommState(port->fd, &(port->commConfig.dcb));
246
+
247
+ port->commConfig.dcb.fBinary = 1;
248
+ port->commConfig.dcb.fInX = 0;
249
+ port->commConfig.dcb.fOutX = 0;
250
+ port->commConfig.dcb.fAbortOnError = 0;
251
+ port->commConfig.dcb.fNull = 0;
252
+
253
+ port->commConfig.dcb.fDtrControl = 1;
254
+
255
+ port->toBeUpdated = T_ALL;
256
+
257
+ setSettings(self);
258
+
259
+ }
260
+
261
+ return INT2FIX(port->status);
262
+ }
263
+
264
+
265
+ VALUE writeIO(VALUE self, VALUE message)
266
+ {
267
+
268
+ int recv;
269
+ int len;
270
+ PortDescriptor *port = NULL;
271
+
272
+ Data_Get_Struct(self, PortDescriptor, port);
273
+
274
+ Check_Type(message, T_STRING);
275
+
276
+ len = RSTRING_LEN(message);
277
+ char cStr[len];
278
+ strcpy(cStr, RSTRING_PTR(message));
279
+
280
+ if (!WriteFile(port->fd, cStr, len, (LPDWORD)((void *) &recv), NULL))
281
+ {
282
+ rb_raise(rb_eIOError, "IO: writing of the %d bytes has been failed", len);
283
+ }
284
+
285
+ return (INT2FIX(recv));
286
+
287
+ }
288
+
289
+
290
+ VALUE readIO(VALUE self, VALUE rb_int)
291
+ {
292
+
293
+ {
294
+ Check_Type(rb_int, T_FIXNUM);
295
+ }
296
+
297
+ PortDescriptor *port = NULL;
298
+
299
+ Data_Get_Struct(self, PortDescriptor, port);
300
+
301
+ int n;
302
+ int len = FIX2INT(rb_int);
303
+ char buf[len];
304
+
305
+ ReadFile(port->fd, &buf, len, (LPDWORD)((void *) &n), NULL);
306
+
307
+ if (n > 0)
308
+ return rb_str_new(buf, n);
309
+
310
+ return Qnil;
311
+ }
312
+
313
+
314
+ VALUE closeIO(VALUE self)
315
+ {
316
+
317
+ PortDescriptor *port = NULL;
318
+
319
+ Data_Get_Struct(self, PortDescriptor, port);
320
+
321
+ flushIO(self);
322
+ port->status = CloseHandle(port->fd);
323
+ port->fd = INVALID_HANDLE_VALUE;
324
+
325
+ rb_iv_set(self, "@open", INT2FIX(port->status));
326
+
327
+ return INT2FIX(port->status);
328
+
329
+ }
330
+
331
+
332
+ VALUE initializeStruct(VALUE self, VALUE portName)
333
+ {
334
+
335
+ {
336
+ Check_Type(portName, T_STRING);
337
+ }
338
+
339
+ PortDescriptor *port = NULL;
340
+
341
+ Data_Get_Struct(self, PortDescriptor, port);
342
+
343
+ port->settings.BaudRate = BAUD115200;
344
+ port->settings.Parity = PAR_NONE;
345
+ port->settings.FlowControl = FLOW_OFF;
346
+ port->settings.DataBits = DATA_8;
347
+ port->settings.StopBits = STOP_1;
348
+ port->settings.Timeout_Millisec = 0;
349
+
350
+ snprintf(port->settings.ComPort, sizeof(port->settings.ComPort) - 1, WIN_PATTERN, RSTRING_PTR(portName));
351
+
352
+ platformInitIO(port);
353
+
354
+ rb_iv_set(self, "@port", portName);
355
+
356
+ return self;
357
+ }
358
+
@@ -0,0 +1,53 @@
1
+ /*
2
+ * Copyright (c) 2013, Ingenico Inc.
3
+ *
4
+ * Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted,
5
+ * provided that the above copyright notice and this permission notice appear in all copies.
6
+ *
7
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
8
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
9
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
10
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
11
+ * PERFORMANCE OF THIS SOFTWARE.
12
+ *
13
+ **/
14
+
15
+ #ifndef rs_232_port_h____FILEEXTENSION___
16
+ #define rs_232_port_h____FILEEXTENSION___
17
+
18
+ # include <ruby.h>
19
+ # include <ruby/io.h>
20
+ # include <windows.h>
21
+ # include <fcntl.h>
22
+ # include <io.h>
23
+ # include <stdio.h>
24
+ # include <string.h>
25
+ # include "structs.h"
26
+
27
+ #define WIN_PATTERN "\\\\.\\%s"
28
+
29
+ void setBaudRate(VALUE, VALUE);
30
+
31
+ VALUE getBaudRate(VALUE);
32
+
33
+ void setParity(VALUE, VALUE);
34
+
35
+ VALUE getParity(VALUE);
36
+
37
+ void setDataBits(VALUE, VALUE);
38
+
39
+ VALUE getDataBits(VALUE);
40
+
41
+ void setStopBits(VALUE, VALUE);
42
+
43
+ VALUE getStopBits(VALUE);
44
+
45
+ void setFlowControl(VALUE, VALUE);
46
+
47
+ VALUE getFlowControl(VALUE);
48
+
49
+ void setTimeout(VALUE, VALUE);
50
+
51
+ void setSettings(VALUE);
52
+
53
+ #endif
@@ -0,0 +1,2 @@
1
+ SERIAL_PORT: COM20
2
+ DEBUG: 0
@@ -0,0 +1,8 @@
1
+ Feature: Connection
2
+
3
+ Scenario: Should have an ability to check open or not
4
+
5
+
6
+ * connection instance "should" be available
7
+ * I "close" connection
8
+ * connection instance "should not" be available
@@ -0,0 +1,33 @@
1
+ When /^connection instance "(should|should not)" be available$/ do |matcher|
2
+
3
+ action = matcher == 'should' ? :should : :should_not
4
+
5
+ if respond_to? :should
6
+ adapter.open?.send(action, be_true)
7
+ else
8
+ assert_equal(adapter.open?, action == :should)
9
+ end
10
+
11
+ end
12
+
13
+ Given /^I "(open|close)" connection$/ do |action|
14
+
15
+ adapter.send(action)
16
+
17
+ if action == 'close'
18
+ if respond_to? :should
19
+ adapter.open?.should be_false
20
+ else
21
+ assert_equal(connection.open?, false)
22
+ end
23
+ else
24
+ if respond_to? :should
25
+ adapter.open?.should be_true
26
+ else
27
+ assert_equal(connection.open?, true)
28
+ end
29
+ end
30
+
31
+ end
32
+
33
+
@@ -0,0 +1,131 @@
1
+ class Adapter::Dev < Adapter::Generic
2
+ attr_reader :interface
3
+ include CommPort
4
+
5
+ # == constructor with default params
6
+ # by default port will be configured with:
7
+ #
8
+ # @baud_rate = 115200 # BAUD_115200
9
+ # @data_bits = 8 # DATA_BITS_8
10
+ # @parity = 0 # PAR_NONE
11
+ # @stop_bits = 1 # STOP_1
12
+ # @flow_control = 0 # FLOW_OFF
13
+ #
14
+ #
15
+ def initialize(port, &block)
16
+ @interface ||= Rs232.new(port)
17
+ connect
18
+ $stdout.puts "*** Rs232 instance has been initialized. Build v#{CommPort::VERSION}"
19
+ super(&block)
20
+ end
21
+
22
+ # Open and configure interface
23
+ #
24
+ # @return [Bool]
25
+ #
26
+ def connect
27
+ @interface.open
28
+ # custom configuration should be there if required
29
+ # @interface.baud_rate = BAUD_115200
30
+ # @interface.data_bits = DATA_BITS_8
31
+ # @interface.parity = PAR_NONE
32
+ # @interface.stop_bits = STOP_1
33
+ # @interface.flow_control = FLOW_OFF
34
+ @open = open?
35
+ end
36
+
37
+ # == Write function implementation
38
+ #
39
+ # @param [String] bytes
40
+ # @return [Int]
41
+ #
42
+ def write(bytes)
43
+ @interface.write(bytes)
44
+ end
45
+
46
+ # == Closing interface and freeing structures
47
+ #
48
+ # @return [Bool]
49
+ #
50
+ def close
51
+ @interface.flush
52
+ @interface.close
53
+ @open = open?
54
+ !open?
55
+ end
56
+
57
+ # == Flashing buffer function
58
+ #
59
+ def flush
60
+ @interface.flush
61
+ end
62
+
63
+ # @return [Bool]
64
+ #
65
+ def open?
66
+ @interface && !@interface.closed?
67
+ end
68
+
69
+ # == read() implementation example
70
+ #
71
+ # @param +count+ [Int]
72
+ # @param +blocking+ [Bool]
73
+ #
74
+ # @return [String]
75
+ #
76
+ # === Alternative implementation:
77
+ # @usage:
78
+ #
79
+ # +timeout+ = blocking_value ? 15000 : 0
80
+ # +@interface.timeout+ = +timeout+
81
+ # +@interface.read( +count+ )+
82
+ #
83
+ def read(count, blocking = false)
84
+ array = []
85
+
86
+ bytes_count = (count == -1) ? @interface.available? : count
87
+
88
+ if blocking
89
+ bytes = read_io_until(count, count)
90
+ array.push bytes if bytes
91
+ else
92
+ bytes_count.times do
93
+ byte = @interface.read(1)
94
+ array.push byte if byte
95
+ end
96
+ end
97
+ array.empty? ? nil : array.join
98
+ end
99
+
100
+ private
101
+
102
+ # == simulate blocking function
103
+ #
104
+ # @param +count+ [Int]
105
+ # @param +up_to+ [Int]
106
+ #
107
+ # no direct ruby usage
108
+ #
109
+ def block_io_until(count, up_to)
110
+ while @interface.available? < count && up_to > 0
111
+ up_to -= 1
112
+ end
113
+ up_to > 0
114
+ end
115
+
116
+ # == simulate blocking function
117
+ #
118
+ # @param +count+ [Int]
119
+ # @param +up_to+ [Int]
120
+ #
121
+ # no direct ruby usage
122
+ #
123
+ def read_io_until(count, up_to)
124
+ until block_io_until(count, up_to)
125
+ sleep 0.001
126
+ end
127
+ read(count)
128
+ end
129
+
130
+ end
131
+
@@ -0,0 +1,64 @@
1
+ require 'monitor'
2
+
3
+ module Adapter
4
+
5
+ class Generic
6
+ include MonitorMixin
7
+ include RsLogger
8
+
9
+ attr_accessor :event
10
+
11
+ def initialize(*args, &block)
12
+ Thread.abort_on_exception = true
13
+ unless instance_variables.include?(:@rxd)
14
+ @rxd = true
15
+ end
16
+ @event = block
17
+ super(*args)
18
+ run
19
+ end
20
+
21
+ def reading_allowed?
22
+ @rxd
23
+ end
24
+
25
+ def defer_reading
26
+ @rxd = false
27
+ !reading_allowed?
28
+ end
29
+
30
+ def allow_reading
31
+ @rxd = true
32
+ end
33
+
34
+ def rx(int, blocking = false)
35
+ byte = read(int, blocking)
36
+ if byte
37
+ logger.debug "RX [#{byte.length}]: #{byte.inspect}"
38
+ end
39
+ byte
40
+ end
41
+
42
+ def tx(bytes)
43
+ int = write(bytes)
44
+ logger.debug "TX [#{int}]: #{bytes.inspect}"
45
+ int
46
+ end
47
+
48
+ def restart_rx_thread
49
+ allow_reading
50
+ run
51
+ end
52
+
53
+ def run
54
+ Thread.new do
55
+ loop do
56
+ rx(1, false) if reading_allowed?
57
+ sleep(0.005)
58
+ end
59
+ end
60
+ end
61
+
62
+ end
63
+
64
+ end
@@ -0,0 +1,36 @@
1
+ require "logger"
2
+
3
+ module Adapter::RsLogger
4
+
5
+ class LogFormatter < ::Logger::Formatter
6
+
7
+ def call(severity, time, progname, msg)
8
+ "#{format_datetime(time)}[TID:#{$$}] [Rs232::#{severity}]: #{msg}\n"
9
+ end
10
+
11
+
12
+ private
13
+
14
+ def format_datetime(time)
15
+ if @datetime_format.nil?
16
+ time.strftime("%Y-%m-%d %H:%M:%S.") << "%06d " % time.usec
17
+ else
18
+ time.strftime(@datetime_format)
19
+ end
20
+ end
21
+
22
+ end
23
+
24
+ def logger
25
+ @logger ||= begin
26
+ logger = ::Logger.new( ENV["LOG"]||$stdout )
27
+ logger.level = ENV["DEBUG"].to_i
28
+ logger.formatter= LogFormatter.new
29
+ logger
30
+ end
31
+ end
32
+
33
+ module_function :logger
34
+
35
+ end
36
+
@@ -0,0 +1,5 @@
1
+ module Adapter
2
+ autoload :RsLogger, File.expand_path("../adapter/rs_logger", __FILE__)
3
+ autoload :Generic, File.expand_path("../adapter/generic", __FILE__)
4
+ autoload :Dev, File.expand_path("../adapter/dev", __FILE__)
5
+ end
@@ -0,0 +1,5 @@
1
+ After do
2
+ adapter.close
3
+ logger.debug "Closed..."
4
+ end
5
+