pserialport 1.3.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,657 @@
1
+ /* Ruby/SerialPort
2
+ * Guillaume Pierronnet <moumar@netcourrier.com>
3
+ * Alan Stern <stern@rowland.harvard.edu>
4
+ * Daniel E. Shipton <dshipton@redshiptechnologies.com>
5
+ * Hector G. Parra <hector@hectorparra.com>
6
+ *
7
+ * This code is hereby licensed for public consumption under either the
8
+ * GNU GPL v2 or greater.
9
+ *
10
+ * You should have received a copy of the GNU General Public License
11
+ * along with this program; if not, write to the Free Software
12
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
13
+ *
14
+ * For documentation on serial programming, see the excellent:
15
+ * "Serial Programming Guide for POSIX Operating Systems"
16
+ * written Michael R. Sweet.
17
+ * http://www.easysw.com/~mike/serial/
18
+ */
19
+
20
+ #include "serialport.h"
21
+
22
+ #if defined(OS_MSWIN) || defined(OS_BCCWIN) || defined(OS_MINGW)
23
+
24
+ #include <stdio.h> /* Standard input/output definitions */
25
+ #include <io.h> /* Low-level I/O definitions */
26
+ #include <fcntl.h> /* File control definitions */
27
+ #include <windows.h> /* Windows standard function definitions */
28
+
29
+
30
+ static char sGetCommState[] = "GetCommState";
31
+ static char sSetCommState[] = "SetCommState";
32
+ static char sGetCommTimeouts[] = "GetCommTimeouts";
33
+ static char sSetCommTimeouts[] = "SetCommTimeouts";
34
+
35
+
36
+ static HANDLE get_handle_helper(obj)
37
+ VALUE obj;
38
+ {
39
+ #ifdef HAVE_RUBY_IO_H
40
+ rb_io_t *fptr;
41
+ #else
42
+ OpenFile *fptr;
43
+ #endif
44
+
45
+ GetOpenFile(obj, fptr);
46
+ #ifdef HAVE_RUBY_IO_H
47
+ return (HANDLE) _get_osfhandle(fptr->fd);
48
+ #else
49
+ return (HANDLE) _get_osfhandle(fileno(fptr->f));
50
+ #endif
51
+ }
52
+
53
+ /* hack to work around the fact that Ruby doesn't use GetLastError? */
54
+ static void _rb_win32_fail(const char *function_call) {
55
+ rb_raise(
56
+ rb_eRuntimeError,
57
+ "%s failed: GetLastError returns %d",
58
+ function_call, GetLastError( )
59
+ );
60
+ }
61
+
62
+ VALUE RB_SERIAL_EXPORT sp_create_impl(class, _port)
63
+ VALUE class, _port;
64
+ {
65
+ #ifdef HAVE_RUBY_IO_H
66
+ rb_io_t *fp;
67
+ #else
68
+ OpenFile *fp;
69
+ #endif
70
+ int fd;
71
+ HANDLE fh;
72
+ int num_port;
73
+ char *str_port;
74
+ char port[260]; /* Windows XP MAX_PATH. See http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx */
75
+
76
+ DCB dcb;
77
+
78
+ NEWOBJ(sp, struct RFile);
79
+ OBJSETUP(sp, class, T_FILE);
80
+ MakeOpenFile((VALUE) sp, fp);
81
+
82
+ switch(TYPE(_port))
83
+ {
84
+ case T_FIXNUM:
85
+ num_port = FIX2INT(_port);
86
+ if (num_port < 0)
87
+ {
88
+ rb_raise(rb_eArgError, "illegal port number");
89
+ }
90
+ snprintf(port, sizeof(port) - 1, "\\\\.\\COM%d", num_port + 1); /* '0' is actually COM1, etc. */
91
+ port[sizeof(port) - 1] = 0;
92
+
93
+ break;
94
+
95
+ case T_STRING:
96
+ str_port = StringValueCStr(_port);
97
+ if (str_port[0] != '\\') /* Check for Win32 Device Namespace prefix "\\.\" */
98
+ {
99
+ snprintf(port, sizeof(port) - 1, "\\\\.\\%s", str_port);
100
+ port[sizeof(port) - 1] = 0;
101
+ }
102
+ else
103
+ {
104
+ snprintf(port, sizeof(port) - 1, "%s", str_port);
105
+ port[sizeof(port) - 1] = 0;
106
+ }
107
+ break;
108
+
109
+ default:
110
+ rb_raise(rb_eTypeError, "wrong argument type");
111
+ break;
112
+ }
113
+
114
+ fd = open(port, O_BINARY | O_RDWR);
115
+ if (fd == -1)
116
+ {
117
+ rb_sys_fail(port);
118
+ }
119
+
120
+ fh = (HANDLE) _get_osfhandle(fd);
121
+ if (SetupComm(fh, 1024, 1024) == 0)
122
+ {
123
+ close(fd);
124
+ rb_raise(rb_eArgError, "not a serial port");
125
+ }
126
+
127
+ dcb.DCBlength = sizeof(dcb);
128
+ if (GetCommState(fh, &dcb) == 0)
129
+ {
130
+ close(fd);
131
+ _rb_win32_fail(sGetCommState);
132
+ }
133
+ dcb.fBinary = TRUE;
134
+ dcb.fParity = FALSE;
135
+ dcb.fOutxDsrFlow = FALSE;
136
+ dcb.fDtrControl = DTR_CONTROL_ENABLE;
137
+ dcb.fDsrSensitivity = FALSE;
138
+ dcb.fTXContinueOnXoff = FALSE;
139
+ dcb.fErrorChar = FALSE;
140
+ dcb.fNull = FALSE;
141
+ dcb.fAbortOnError = FALSE;
142
+ dcb.XonChar = 17;
143
+ dcb.XoffChar = 19;
144
+ if (SetCommState(fh, &dcb) == 0)
145
+ {
146
+ close(fd);
147
+ _rb_win32_fail(sSetCommState);
148
+ }
149
+
150
+ errno = 0;
151
+ fp->mode = FMODE_READWRITE | FMODE_BINMODE | FMODE_SYNC;
152
+ #ifdef HAVE_RUBY_IO_H
153
+ fp->fd = fd;
154
+ #else
155
+ fp->f = fdopen(fd, "rb+");
156
+ #endif
157
+ return (VALUE) sp;
158
+ }
159
+
160
+ VALUE RB_SERIAL_EXPORT sp_set_modem_params_impl(argc, argv, self)
161
+ int argc;
162
+ VALUE *argv, self;
163
+ {
164
+ HANDLE fh;
165
+ DCB dcb;
166
+ VALUE _data_rate, _data_bits, _parity, _stop_bits;
167
+ int use_hash = 0;
168
+ int data_rate, data_bits, parity;
169
+
170
+ if (argc == 0)
171
+ {
172
+ return self;
173
+ }
174
+ if (argc == 1 && T_HASH == TYPE(argv[0]))
175
+ {
176
+ use_hash = 1;
177
+ _data_rate = rb_hash_aref(argv[0], sBaud);
178
+ _data_bits = rb_hash_aref(argv[0], sDataBits);
179
+ _stop_bits = rb_hash_aref(argv[0], sStopBits);
180
+ _parity = rb_hash_aref(argv[0], sParity);
181
+ }
182
+
183
+ fh = get_handle_helper(self);
184
+ dcb.DCBlength = sizeof(dcb);
185
+ if (GetCommState(fh, &dcb) == 0)
186
+ {
187
+ _rb_win32_fail(sGetCommState);
188
+ }
189
+
190
+ if (!use_hash)
191
+ {
192
+ _data_rate = argv[0];
193
+ }
194
+
195
+ if (NIL_P(_data_rate))
196
+ {
197
+ goto SkipDataRate;
198
+ }
199
+
200
+ Check_Type(_data_rate, T_FIXNUM);
201
+
202
+ data_rate = FIX2INT(_data_rate);
203
+ dcb.BaudRate = data_rate;
204
+
205
+ SkipDataRate:
206
+
207
+ if (!use_hash)
208
+ {
209
+ _data_bits = (argc >= 2 ? argv[1] : INT2FIX(8));
210
+ }
211
+
212
+ if (NIL_P(_data_bits))
213
+ {
214
+ goto SkipDataBits;
215
+ }
216
+
217
+ Check_Type(_data_bits, T_FIXNUM);
218
+
219
+ data_bits = FIX2INT(_data_bits);
220
+ if (4 <= data_bits && data_bits <= 8)
221
+ {
222
+ dcb.ByteSize = data_bits;
223
+ }
224
+ else
225
+ {
226
+ rb_raise(rb_eArgError, "unknown character size");
227
+ }
228
+
229
+ SkipDataBits:
230
+
231
+ if (!use_hash)
232
+ {
233
+ _stop_bits = (argc >= 3 ? argv[2] : INT2FIX(1));
234
+ }
235
+
236
+ if (NIL_P(_stop_bits))
237
+ {
238
+ goto SkipStopBits;
239
+ }
240
+
241
+ Check_Type(_stop_bits, T_FIXNUM);
242
+
243
+ switch (FIX2INT(_stop_bits))
244
+ {
245
+ case 1:
246
+ dcb.StopBits = ONESTOPBIT;
247
+ break;
248
+ case 2:
249
+ dcb.StopBits = TWOSTOPBITS;
250
+ break;
251
+ default:
252
+ rb_raise(rb_eArgError, "unknown number of stop bits");
253
+ break;
254
+ }
255
+
256
+ SkipStopBits:
257
+
258
+ if (!use_hash)
259
+ {
260
+ _parity = (argc >= 4 ? argv[3] : (dcb.ByteSize == 8 ?
261
+ INT2FIX(NOPARITY) : INT2FIX(EVENPARITY)));
262
+ }
263
+
264
+ if (NIL_P(_parity))
265
+ {
266
+ goto SkipParity;
267
+ }
268
+
269
+ Check_Type(_parity, T_FIXNUM);
270
+
271
+ parity = FIX2INT(_parity);
272
+ switch (parity)
273
+ {
274
+ case EVENPARITY:
275
+ case ODDPARITY:
276
+ case MARKPARITY:
277
+ case SPACEPARITY:
278
+ case NOPARITY:
279
+ dcb.Parity = parity;
280
+ break;
281
+
282
+ default:
283
+ rb_raise(rb_eArgError, "unknown parity");
284
+ break;
285
+ }
286
+
287
+ SkipParity:
288
+
289
+ if (SetCommState(fh, &dcb) == 0)
290
+ {
291
+ _rb_win32_fail(sSetCommState);
292
+ }
293
+
294
+ return argv[0];
295
+ }
296
+
297
+ void RB_SERIAL_EXPORT get_modem_params_impl(self, mp)
298
+ VALUE self;
299
+ struct modem_params *mp;
300
+ {
301
+ HANDLE fh;
302
+ DCB dcb;
303
+
304
+ fh = get_handle_helper(self);
305
+ dcb.DCBlength = sizeof(dcb);
306
+ if (GetCommState(fh, &dcb) == 0)
307
+ {
308
+ _rb_win32_fail(sGetCommState);
309
+ }
310
+
311
+ mp->data_rate = dcb.BaudRate;
312
+ mp->data_bits = dcb.ByteSize;
313
+ mp->stop_bits = (dcb.StopBits == ONESTOPBIT ? 1 : 2);
314
+ mp->parity = dcb.Parity;
315
+ }
316
+
317
+ VALUE RB_SERIAL_EXPORT sp_set_flow_control_impl(self, val)
318
+ VALUE self, val;
319
+ {
320
+ HANDLE fh;
321
+ int flowc;
322
+ DCB dcb;
323
+
324
+ Check_Type(val, T_FIXNUM);
325
+
326
+ fh = get_handle_helper(self);
327
+ dcb.DCBlength = sizeof(dcb);
328
+ if (GetCommState(fh, &dcb) == 0)
329
+ {
330
+ _rb_win32_fail(sGetCommState);
331
+ }
332
+
333
+ flowc = FIX2INT(val);
334
+ if (flowc & HARD)
335
+ {
336
+ dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
337
+ dcb.fOutxCtsFlow = TRUE;
338
+ }
339
+ else
340
+ {
341
+ dcb.fRtsControl = RTS_CONTROL_ENABLE;
342
+ dcb.fOutxCtsFlow = FALSE;
343
+ }
344
+
345
+ if (flowc & SOFT)
346
+ {
347
+ dcb.fOutX = dcb.fInX = TRUE;
348
+ }
349
+ else
350
+ {
351
+ dcb.fOutX = dcb.fInX = FALSE;
352
+ }
353
+
354
+ if (SetCommState(fh, &dcb) == 0)
355
+ {
356
+ _rb_win32_fail(sSetCommState);
357
+ }
358
+
359
+ return val;
360
+ }
361
+
362
+ VALUE RB_SERIAL_EXPORT sp_get_flow_control_impl(self)
363
+ VALUE self;
364
+ {
365
+ HANDLE fh;
366
+ int ret;
367
+ DCB dcb;
368
+
369
+ fh = get_handle_helper(self);
370
+ dcb.DCBlength = sizeof(dcb);
371
+ if (GetCommState(fh, &dcb) == 0)
372
+ {
373
+ _rb_win32_fail(sGetCommState);
374
+ }
375
+
376
+ ret = 0;
377
+ if (dcb.fOutxCtsFlow)
378
+ {
379
+ ret += HARD;
380
+ }
381
+
382
+ if (dcb.fOutX)
383
+ {
384
+ ret += SOFT;
385
+ }
386
+
387
+ return INT2FIX(ret);
388
+ }
389
+
390
+ VALUE RB_SERIAL_EXPORT sp_set_read_timeout_impl(self, val)
391
+ VALUE self, val;
392
+ {
393
+ int timeout;
394
+ HANDLE fh;
395
+ COMMTIMEOUTS ctout;
396
+
397
+ Check_Type(val, T_FIXNUM);
398
+ timeout = FIX2INT(val);
399
+
400
+ fh = get_handle_helper(self);
401
+ if (GetCommTimeouts(fh, &ctout) == 0)
402
+ {
403
+ _rb_win32_fail(sGetCommTimeouts);
404
+ }
405
+
406
+ if (timeout < 0)
407
+ {
408
+ ctout.ReadIntervalTimeout = MAXDWORD;
409
+ ctout.ReadTotalTimeoutMultiplier = 0;
410
+ ctout.ReadTotalTimeoutConstant = 0;
411
+ }
412
+ else if (timeout == 0)
413
+ {
414
+ ctout.ReadIntervalTimeout = MAXDWORD;
415
+ ctout.ReadTotalTimeoutMultiplier = MAXDWORD;
416
+ ctout.ReadTotalTimeoutConstant = MAXDWORD - 1;
417
+ }
418
+ else
419
+ {
420
+ ctout.ReadIntervalTimeout = timeout;
421
+ ctout.ReadTotalTimeoutMultiplier = 0;
422
+ ctout.ReadTotalTimeoutConstant = timeout;
423
+ }
424
+
425
+ if (SetCommTimeouts(fh, &ctout) == 0)
426
+ {
427
+ _rb_win32_fail(sSetCommTimeouts);
428
+ }
429
+
430
+ return val;
431
+ }
432
+
433
+ VALUE RB_SERIAL_EXPORT sp_get_read_timeout_impl(self)
434
+ VALUE self;
435
+ {
436
+ HANDLE fh;
437
+ COMMTIMEOUTS ctout;
438
+
439
+ fh = get_handle_helper(self);
440
+ if (GetCommTimeouts(fh, &ctout) == 0)
441
+ {
442
+ _rb_win32_fail(sGetCommTimeouts);
443
+ }
444
+
445
+ switch (ctout.ReadTotalTimeoutConstant)
446
+ {
447
+ case 0:
448
+ return INT2FIX(-1);
449
+ case MAXDWORD:
450
+ return INT2FIX(0);
451
+ }
452
+
453
+ return INT2FIX(ctout.ReadTotalTimeoutConstant);
454
+ }
455
+
456
+ VALUE RB_SERIAL_EXPORT sp_set_write_timeout_impl(self, val)
457
+ VALUE self, val;
458
+ {
459
+ int timeout;
460
+ HANDLE fh;
461
+ COMMTIMEOUTS ctout;
462
+
463
+ Check_Type(val, T_FIXNUM);
464
+ timeout = FIX2INT(val);
465
+
466
+ fh = get_handle_helper(self);
467
+ if (GetCommTimeouts(fh, &ctout) == 0)
468
+ {
469
+ _rb_win32_fail(sGetCommTimeouts);
470
+ }
471
+
472
+ if (timeout <= 0)
473
+ {
474
+ ctout.WriteTotalTimeoutMultiplier = 0;
475
+ ctout.WriteTotalTimeoutConstant = 0;
476
+ }
477
+ else
478
+ {
479
+ ctout.WriteTotalTimeoutMultiplier = timeout;
480
+ ctout.WriteTotalTimeoutConstant = 0;
481
+ }
482
+
483
+ if (SetCommTimeouts(fh, &ctout) == 0)
484
+ {
485
+ _rb_win32_fail(sSetCommTimeouts);
486
+ }
487
+
488
+ return val;
489
+ }
490
+
491
+ VALUE RB_SERIAL_EXPORT sp_get_write_timeout_impl(self)
492
+ VALUE self;
493
+ {
494
+ HANDLE fh;
495
+ COMMTIMEOUTS ctout;
496
+
497
+ fh = get_handle_helper(self);
498
+ if (GetCommTimeouts(fh, &ctout) == 0)
499
+ {
500
+ _rb_win32_fail(sGetCommTimeouts);
501
+ }
502
+
503
+ return INT2FIX(ctout.WriteTotalTimeoutMultiplier);
504
+ }
505
+
506
+ static void delay_ms(time)
507
+ int time;
508
+ {
509
+ HANDLE ev;
510
+
511
+ ev = CreateEvent(NULL, FALSE, FALSE, NULL);
512
+ if (!ev)
513
+ {
514
+ _rb_win32_fail("CreateEvent");
515
+ }
516
+
517
+ if (WaitForSingleObject(ev, time) == WAIT_FAILED)
518
+ {
519
+ _rb_win32_fail("WaitForSingleObject");
520
+ }
521
+
522
+ CloseHandle(ev);
523
+ }
524
+
525
+ VALUE RB_SERIAL_EXPORT sp_break_impl(self, time)
526
+ VALUE self, time;
527
+ {
528
+ HANDLE fh;
529
+
530
+ Check_Type(time, T_FIXNUM);
531
+
532
+ fh = get_handle_helper(self);
533
+ if (SetCommBreak(fh) == 0)
534
+ {
535
+ _rb_win32_fail("SetCommBreak");
536
+ }
537
+
538
+ delay_ms(FIX2INT(time) * 100);
539
+ ClearCommBreak(fh);
540
+
541
+ return Qnil;
542
+ }
543
+
544
+ void RB_SERIAL_EXPORT get_line_signals_helper_impl(obj, ls)
545
+ VALUE obj;
546
+ struct line_signals *ls;
547
+ {
548
+ HANDLE fh;
549
+ unsigned long status; /* DWORD */
550
+
551
+ fh = get_handle_helper(obj);
552
+ if (GetCommModemStatus(fh, &status) == 0)
553
+ {
554
+ _rb_win32_fail("GetCommModemStatus");
555
+ }
556
+
557
+ ls->cts = (status & MS_CTS_ON ? 1 : 0);
558
+ ls->dsr = (status & MS_DSR_ON ? 1 : 0);
559
+ ls->dcd = (status & MS_RLSD_ON ? 1 : 0);
560
+ ls->ri = (status & MS_RING_ON ? 1 : 0);
561
+ }
562
+
563
+ static VALUE set_signal(obj, val, sigoff, sigon)
564
+ VALUE obj,val;
565
+ int sigoff, sigon;
566
+ {
567
+ HANDLE fh;
568
+ int set, sig;
569
+
570
+ Check_Type(val, T_FIXNUM);
571
+ fh = get_handle_helper(obj);
572
+
573
+ set = FIX2INT(val);
574
+ if (set == 0)
575
+ {
576
+ sig = sigoff;
577
+ }
578
+ else if (set == 1)
579
+ {
580
+ sig = sigon;
581
+ }
582
+ else
583
+ {
584
+ rb_raise(rb_eArgError, "invalid value");
585
+ }
586
+
587
+ if (EscapeCommFunction(fh, sig) == 0)
588
+ {
589
+ _rb_win32_fail("EscapeCommFunction");
590
+ }
591
+
592
+ return val;
593
+ }
594
+
595
+ VALUE RB_SERIAL_EXPORT sp_set_rts_impl(self, val)
596
+ VALUE self, val;
597
+ {
598
+ return set_signal(self, val, CLRRTS, SETRTS);
599
+ }
600
+
601
+ VALUE RB_SERIAL_EXPORT sp_set_dtr_impl(self, val)
602
+ VALUE self, val;
603
+ {
604
+ return set_signal(self, val, CLRDTR, SETDTR);
605
+ }
606
+
607
+ VALUE RB_SERIAL_EXPORT sp_get_rts_impl(self)
608
+ VALUE self;
609
+ {
610
+ rb_notimplement();
611
+ return self;
612
+ }
613
+
614
+ VALUE RB_SERIAL_EXPORT sp_get_dtr_impl(self)
615
+ VALUE self;
616
+ {
617
+ rb_notimplement();
618
+ return self;
619
+ }
620
+
621
+ #define PURGE_RXABORT 0x02
622
+ #define PURGE_RXCLEAR 0x08
623
+ VALUE RB_SERIAL_EXPORT sp_flush_input_data_impl(self)
624
+ VALUE self;
625
+ {
626
+ BOOL ret;
627
+ HANDLE fh;
628
+
629
+ fh = get_handle_helper(self);
630
+
631
+ ret = PurgeComm(fh, (DWORD)(PURGE_RXCLEAR | PURGE_RXABORT));
632
+ if(!ret) {
633
+ return Qfalse;
634
+ }
635
+ return Qtrue;
636
+ }
637
+
638
+ #define PURGE_TXABORT 0x01
639
+ #define PURGE_TXCLEAR 0x04
640
+ VALUE RB_SERIAL_EXPORT sp_flush_output_data_impl(self)
641
+ VALUE self;
642
+ {
643
+ BOOL ret;
644
+ HANDLE fh;
645
+
646
+ fh = get_handle_helper(self);
647
+
648
+ ret = PurgeComm(fh, (DWORD)(PURGE_TXCLEAR | PURGE_TXABORT));
649
+ if(!ret) {
650
+ return Qfalse;
651
+ }
652
+ return Qtrue;
653
+ }
654
+
655
+
656
+
657
+ #endif /* defined(OS_MSWIN) || defined(OS_BCCWIN) || defined(OS_MINGW) */
@@ -0,0 +1,3 @@
1
+ class SerialPort
2
+ VERSION = "1.3.2"
3
+ end
data/lib/serialport.rb ADDED
@@ -0,0 +1,60 @@
1
+ require 'serialport.so'
2
+ require 'serialport/version'
3
+
4
+
5
+ # This class is used for communication over a serial port.
6
+ # In addition to the methods here, you can use Ruby IO methods, e.g. read, write, getc, readlines, etc.
7
+ #
8
+ # @see http://rubydoc.info/stdlib/core/IO Ruby IO class
9
+ # @see http://www.cmrr.umn.edu/~strupp/serial.html "Serial Programming Guide for POSIX Operating Systems"
10
+ class SerialPort
11
+ private_class_method(:create)
12
+
13
+ # Creates a serial port object.
14
+ # Accepts the port identifier and a variable list for configuration as paramaters or hash.
15
+ # Please see SerialPort#set_modem_params
16
+ #
17
+ # @overload new(port, *params)
18
+ # @param port [Integer] the serial port number,
19
+ # where 0 is mapped to "COM1" on Windows, "/dev/ttyS0" on Linux, "/dev/cuaa0" on Mac OS X, etc.
20
+ # @overload new(port, *params)
21
+ # @param port [String] the serial port file e.g. "/dev/ttyS0"
22
+ # @return [SerialPort]
23
+ # @see SerialPort#set_modem_params
24
+ def SerialPort::new(port, *params)
25
+ sp = create(port)
26
+ begin
27
+ sp.set_modem_params(*params)
28
+ rescue
29
+ sp.close
30
+ raise
31
+ end
32
+ return sp
33
+ end
34
+
35
+ # This behaves like SerialPort#new, except that you can pass a block
36
+ # to which the new serial port object will be passed. In this case
37
+ # the connection is automaticaly closed when the block has finished.
38
+ #
39
+ # @yield [serial_port] the serial port number or filename
40
+ # @see SerialPort#new
41
+ # @see SerialPort#set_modem_params
42
+ def SerialPort::open(port, *params)
43
+ sp = create(port)
44
+ begin
45
+ sp.set_modem_params(*params)
46
+ rescue
47
+ sp.close
48
+ raise
49
+ end
50
+ if (block_given?)
51
+ begin
52
+ yield sp
53
+ ensure
54
+ sp.close
55
+ end
56
+ return nil
57
+ end
58
+ return sp
59
+ end
60
+ end