toholio-serialport 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,667 @@
1
+ /* Ruby/SerialPort $Id$
2
+ * Guillaume Pierronnet <moumar@netcourrier.com>
3
+ * Alan Stern <stern@rowland.harvard.edu>
4
+ * Daniel E. Shipton <dshipton@redshiptechnologies.com>
5
+ *
6
+ * This code is hereby licensed for public consumption under either the
7
+ * GNU GPL v2 or greater.
8
+ *
9
+ * You should have received a copy of the GNU General Public License
10
+ * along with this program; if not, write to the Free Software
11
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
12
+ *
13
+ * For documentation on serial programming, see the excellent:
14
+ * "Serial Programming Guide for POSIX Operating Systems"
15
+ * written Michael R. Sweet.
16
+ * http://www.easysw.com/~mike/serial/
17
+ */
18
+
19
+ #include "serialport.h"
20
+
21
+ /* Check if we are on a posix compliant system. */
22
+ #if !defined(OS_MSWIN) && !defined(OS_BCCWIN)
23
+
24
+ #include <stdio.h> /* Standard input/output definitions */
25
+ #include <unistd.h> /* UNIX standard function definitions */
26
+ #include <fcntl.h> /* File control definitions */
27
+ #include <errno.h> /* Error number definitions */
28
+ #include <termios.h> /* POSIX terminal control definitions */
29
+ #include <sys/ioctl.h>
30
+
31
+ #ifdef CRTSCTS
32
+ #define HAVE_FLOWCONTROL_HARD 1
33
+ #else
34
+ #undef HAVE_FLOWCONTROL_HARD
35
+ #endif
36
+
37
+
38
+ static char sTcgetattr[] = "tcgetattr";
39
+ static char sTcsetattr[] = "tcsetattr";
40
+ static char sIoctl[] = "ioctl";
41
+
42
+
43
+ int get_fd_helper(obj)
44
+ VALUE obj;
45
+ {
46
+ OpenFile *fptr;
47
+
48
+ GetOpenFile(obj, fptr);
49
+ return (fileno(fptr->f));
50
+ }
51
+
52
+ VALUE sp_create_impl(class, _port)
53
+ VALUE class, _port;
54
+ {
55
+ OpenFile *fp;
56
+ int fd;
57
+ int num_port;
58
+ char *port;
59
+ char *ports[] = {
60
+ #if defined(OS_LINUX) || defined(OS_CYGWIN)
61
+ "/dev/ttyS0", "/dev/ttyS1", "/dev/ttyS2", "/dev/ttyS3",
62
+ "/dev/ttyS4", "/dev/ttyS5", "/dev/ttyS6", "/dev/ttyS7"
63
+ #elif defined(OS_FREEBSD) || defined(OS_NETBSD) || defined(OS_OPENBSD)
64
+ "/dev/cuaa0", "/dev/cuaa1", "/dev/cuaa2", "/dev/cuaa3",
65
+ "/dev/cuaa4", "/dev/cuaa5", "/dev/cuaa6", "/dev/cuaa7"
66
+ #elif defined(OS_SOLARIS)
67
+ "/dev/ttya", "/dev/ttyb", "/dev/ttyc", "/dev/ttyd",
68
+ "/dev/ttye", "/dev/ttyf", "/dev/ttyg", "/dev/ttyh"
69
+ #elif defined(OS_AIX)
70
+ "/dev/tty0", "/dev/tty1", "/dev/tty2", "/dev/tty3",
71
+ "/dev/tty4", "/dev/tty5", "/dev/tty6", "/dev/tty7"
72
+ #elif defined(OS_IRIX)
73
+ "/dev/ttyf1", "/dev/ttyf2", "/dev/ttyf3", "/dev/ttyf4",
74
+ "/dev/ttyf5", "/dev/ttyf6", "/dev/ttyf7", "/dev/ttyf8"
75
+ #endif
76
+ };
77
+ struct termios params;
78
+
79
+ NEWOBJ(sp, struct RFile);
80
+ rb_secure(4);
81
+ OBJSETUP(sp, class, T_FILE);
82
+ MakeOpenFile((VALUE) sp, fp);
83
+
84
+ switch(TYPE(_port))
85
+ {
86
+ case T_FIXNUM:
87
+ num_port = FIX2INT(_port);
88
+ if (num_port < 0 || num_port > sizeof(ports) / sizeof(ports[0]))
89
+ {
90
+ rb_raise(rb_eArgError, "illegal port number");
91
+ }
92
+ port = ports[num_port];
93
+ break;
94
+
95
+ case T_STRING:
96
+ Check_SafeStr(_port);
97
+ port = RSTRING(_port)->ptr;
98
+ break;
99
+
100
+ default:
101
+ rb_raise(rb_eTypeError, "wrong argument type");
102
+ break;
103
+ }
104
+
105
+ fd = open(port, O_RDWR | O_NOCTTY | O_NDELAY);
106
+ if (fd == -1)
107
+ {
108
+ rb_sys_fail(port);
109
+ }
110
+
111
+ if (!isatty(fd))
112
+ {
113
+ close(fd);
114
+ rb_raise(rb_eArgError, "not a serial port");
115
+ }
116
+
117
+ /* enable blocking read */
118
+ fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK);
119
+
120
+ if (tcgetattr(fd, &params) == -1)
121
+ {
122
+ close(fd);
123
+ rb_sys_fail(sTcgetattr);
124
+ }
125
+
126
+ params.c_oflag = 0;
127
+ params.c_lflag = 0;
128
+ params.c_iflag &= (IXON | IXOFF | IXANY);
129
+ params.c_cflag |= CLOCAL | CREAD;
130
+ params.c_cflag &= ~HUPCL;
131
+
132
+ if (tcsetattr(fd, TCSANOW, &params) == -1)
133
+ {
134
+ close(fd);
135
+ rb_sys_fail(sTcsetattr);
136
+ }
137
+
138
+ fp->f = rb_fdopen(fd, "r+");
139
+ fp->mode = FMODE_READWRITE | FMODE_SYNC;
140
+
141
+ return (VALUE) sp;
142
+ }
143
+
144
+ VALUE sp_set_modem_params_impl(argc, argv, self)
145
+ int argc;
146
+ VALUE *argv, self;
147
+ {
148
+ int fd;
149
+ struct termios params;
150
+ VALUE _data_rate, _data_bits, _parity, _stop_bits;
151
+ int use_hash = 0;
152
+ int data_rate, data_bits;
153
+ _data_rate = _data_bits = _parity = _stop_bits = Qnil;
154
+
155
+ if (argc == 0)
156
+ {
157
+ return self;
158
+ }
159
+
160
+ if (argc == 1 && T_HASH == TYPE(argv[0]))
161
+ {
162
+ use_hash = 1;
163
+ _data_rate = rb_hash_aref(argv[0], sBaud);
164
+ _data_bits = rb_hash_aref(argv[0], sDataBits);
165
+ _stop_bits = rb_hash_aref(argv[0], sStopBits);
166
+ _parity = rb_hash_aref(argv[0], sParity);
167
+ }
168
+
169
+ fd = get_fd_helper(self);
170
+ if (tcgetattr(fd, &params) == -1)
171
+ {
172
+ rb_sys_fail(sTcgetattr);
173
+ }
174
+
175
+ if (!use_hash)
176
+ {
177
+ _data_rate = argv[0];
178
+ }
179
+
180
+ if (NIL_P(_data_rate))
181
+ {
182
+ goto SkipDataRate;
183
+ }
184
+ Check_Type(_data_rate, T_FIXNUM);
185
+
186
+ switch(FIX2INT(_data_rate))
187
+ {
188
+ case 50: data_rate = B50; break;
189
+ case 75: data_rate = B75; break;
190
+ case 110: data_rate = B110; break;
191
+ case 134: data_rate = B134; break;
192
+ case 150: data_rate = B150; break;
193
+ case 200: data_rate = B200; break;
194
+ case 300: data_rate = B300; break;
195
+ case 600: data_rate = B600; break;
196
+ case 1200: data_rate = B1200; break;
197
+ case 1800: data_rate = B1800; break;
198
+ case 2400: data_rate = B2400; break;
199
+ case 4800: data_rate = B4800; break;
200
+ case 9600: data_rate = B9600; break;
201
+ case 19200: data_rate = B19200; break;
202
+ case 38400: data_rate = B38400; break;
203
+ #ifdef B57600
204
+ case 57600: data_rate = B57600; break;
205
+ #endif
206
+ #ifdef B76800
207
+ case 76800: data_rate = B76800; break;
208
+ #endif
209
+ #ifdef B115200
210
+ case 115200: data_rate = B115200; break;
211
+ #endif
212
+ #ifdef B230400
213
+ case 230400: data_rate = B230400; break;
214
+ #endif
215
+
216
+ default:
217
+ rb_raise(rb_eArgError, "unknown baud rate");
218
+ break;
219
+ }
220
+ cfsetispeed(&params, data_rate);
221
+ cfsetospeed(&params, data_rate);
222
+
223
+ SkipDataRate:
224
+
225
+ if (!use_hash)
226
+ {
227
+ _data_bits = (argc >= 2 ? argv[1] : INT2FIX(8));
228
+ }
229
+
230
+ if (NIL_P(_data_bits))
231
+ {
232
+ goto SkipDataBits;
233
+ }
234
+ Check_Type(_data_bits, T_FIXNUM);
235
+
236
+ switch(FIX2INT(_data_bits))
237
+ {
238
+ case 5:
239
+ data_bits = CS5;
240
+ break;
241
+ case 6:
242
+ data_bits = CS6;
243
+ break;
244
+ case 7:
245
+ data_bits = CS7;
246
+ break;
247
+ case 8:
248
+ data_bits = CS8;
249
+ break;
250
+ default:
251
+ rb_raise(rb_eArgError, "unknown character size");
252
+ break;
253
+ }
254
+ params.c_cflag &= ~CSIZE;
255
+ params.c_cflag |= data_bits;
256
+
257
+ SkipDataBits:
258
+
259
+ if (!use_hash)
260
+ {
261
+ _stop_bits = (argc >= 3 ? argv[2] : INT2FIX(1));
262
+ }
263
+
264
+ if (NIL_P(_stop_bits))
265
+ {
266
+ goto SkipStopBits;
267
+ }
268
+
269
+ Check_Type(_stop_bits, T_FIXNUM);
270
+
271
+ switch(FIX2INT(_stop_bits))
272
+ {
273
+ case 1:
274
+ params.c_cflag &= ~CSTOPB;
275
+ break;
276
+ case 2:
277
+ params.c_cflag |= CSTOPB;
278
+ break;
279
+ default:
280
+ rb_raise(rb_eArgError, "unknown number of stop bits");
281
+ break;
282
+ }
283
+
284
+ SkipStopBits:
285
+
286
+ if (!use_hash)
287
+ {
288
+ _parity = (argc >= 4 ? argv[3] : ((params.c_cflag & CSIZE) == CS8 ?
289
+ INT2FIX(NONE) : INT2FIX(EVEN)));
290
+ }
291
+
292
+ if (NIL_P(_parity))
293
+ {
294
+ goto SkipParity;
295
+ }
296
+
297
+ Check_Type(_parity, T_FIXNUM);
298
+
299
+ switch(FIX2INT(_parity))
300
+ {
301
+ case EVEN:
302
+ params.c_cflag |= PARENB;
303
+ params.c_cflag &= ~PARODD;
304
+ break;
305
+
306
+ case ODD:
307
+ params.c_cflag |= PARENB;
308
+ params.c_cflag |= PARODD;
309
+ break;
310
+
311
+ case NONE:
312
+ params.c_cflag &= ~PARENB;
313
+ break;
314
+
315
+ default:
316
+ rb_raise(rb_eArgError, "unknown parity");
317
+ break;
318
+ }
319
+
320
+ SkipParity:
321
+
322
+ if (tcsetattr(fd, TCSANOW, &params) == -1)
323
+ {
324
+ rb_sys_fail(sTcsetattr);
325
+ }
326
+ return argv[0];
327
+ }
328
+
329
+ void get_modem_params_impl(self, mp)
330
+ VALUE self;
331
+ struct modem_params *mp;
332
+ {
333
+ int fd;
334
+ struct termios params;
335
+
336
+ fd = get_fd_helper(self);
337
+ if (tcgetattr(fd, &params) == -1)
338
+ {
339
+ rb_sys_fail(sTcgetattr);
340
+ }
341
+
342
+ switch (cfgetospeed(&params))
343
+ {
344
+ case B50: mp->data_rate = 50; break;
345
+ case B75: mp->data_rate = 75; break;
346
+ case B110: mp->data_rate = 110; break;
347
+ case B134: mp->data_rate = 134; break;
348
+ case B150: mp->data_rate = 150; break;
349
+ case B200: mp->data_rate = 200; break;
350
+ case B300: mp->data_rate = 300; break;
351
+ case B600: mp->data_rate = 600; break;
352
+ case B1200: mp->data_rate = 1200; break;
353
+ case B1800: mp->data_rate = 1800; break;
354
+ case B2400: mp->data_rate = 2400; break;
355
+ case B4800: mp->data_rate = 4800; break;
356
+ case B9600: mp->data_rate = 9600; break;
357
+ case B19200: mp->data_rate = 19200; break;
358
+ case B38400: mp->data_rate = 38400; break;
359
+ #ifdef B57600
360
+ case B57600: mp->data_rate = 57600; break;
361
+ #endif
362
+ #ifdef B76800
363
+ case B76800: mp->data_rate = 76800; break;
364
+ #endif
365
+ #ifdef B115200
366
+ case B115200: mp->data_rate = 115200; break;
367
+ #endif
368
+ #ifdef B230400
369
+ case B230400: mp->data_rate = 230400; break;
370
+ #endif
371
+ }
372
+
373
+ switch(params.c_cflag & CSIZE)
374
+ {
375
+ case CS5:
376
+ mp->data_bits = 5;
377
+ break;
378
+ case CS6:
379
+ mp->data_bits = 6;
380
+ break;
381
+ case CS7:
382
+ mp->data_bits = 7;
383
+ break;
384
+ case CS8:
385
+ mp->data_bits = 8;
386
+ break;
387
+ default:
388
+ mp->data_bits = 0;
389
+ break;
390
+ }
391
+
392
+ mp->stop_bits = (params.c_cflag & CSTOPB ? 2 : 1);
393
+
394
+ if (!(params.c_cflag & PARENB))
395
+ {
396
+ mp->parity = NONE;
397
+ }
398
+ else if (params.c_cflag & PARODD)
399
+ {
400
+ mp->parity = ODD;
401
+ }
402
+ else
403
+ {
404
+ mp->parity = EVEN;
405
+ }
406
+ }
407
+
408
+ VALUE sp_set_flow_control_impl(self, val)
409
+ VALUE self, val;
410
+ {
411
+ int fd;
412
+ int flowc;
413
+ struct termios params;
414
+
415
+ Check_Type(val, T_FIXNUM);
416
+
417
+ fd = get_fd_helper(self);
418
+ if (tcgetattr(fd, &params) == -1)
419
+ {
420
+ rb_sys_fail(sTcgetattr);
421
+ }
422
+
423
+ flowc = FIX2INT(val);
424
+ if (flowc & HARD)
425
+ {
426
+ #ifdef HAVE_FLOWCONTROL_HARD
427
+ params.c_cflag |= CRTSCTS;
428
+ }
429
+ else
430
+ {
431
+ params.c_cflag &= ~CRTSCTS;
432
+ }
433
+ #else
434
+ rb_raise(rb_eIOError, "Hardware flow control not supported");
435
+ }
436
+ #endif
437
+
438
+ if (flowc & SOFT)
439
+ {
440
+ params.c_iflag |= (IXON | IXOFF | IXANY);
441
+ }
442
+ else
443
+ {
444
+ params.c_iflag &= ~(IXON | IXOFF | IXANY);
445
+ }
446
+
447
+ if (tcsetattr(fd, TCSANOW, &params) == -1)
448
+ {
449
+ rb_sys_fail(sTcsetattr);
450
+ }
451
+
452
+ return val;
453
+ }
454
+
455
+ VALUE sp_get_flow_control_impl(self)
456
+ VALUE self;
457
+ {
458
+ int ret;
459
+ int fd;
460
+ struct termios params;
461
+
462
+ fd = get_fd_helper(self);
463
+ if (tcgetattr(fd, &params) == -1)
464
+ {
465
+ rb_sys_fail(sTcgetattr);
466
+ }
467
+
468
+ ret = 0;
469
+
470
+ #ifdef HAVE_FLOWCONTROL_HARD
471
+ if (params.c_cflag & CRTSCTS)
472
+ {
473
+ ret += HARD;
474
+ }
475
+ #endif
476
+
477
+ if (params.c_iflag & (IXON | IXOFF | IXANY))
478
+ {
479
+ ret += SOFT;
480
+ }
481
+
482
+ return INT2FIX(ret);
483
+ }
484
+
485
+ VALUE sp_set_read_timeout_impl(self, val)
486
+ VALUE self, val;
487
+ {
488
+ int timeout;
489
+ int fd;
490
+ struct termios params;
491
+
492
+ Check_Type(val, T_FIXNUM);
493
+ timeout = FIX2INT(val);
494
+
495
+ fd = get_fd_helper(self);
496
+ if (tcgetattr(fd, &params) == -1)
497
+ {
498
+ rb_sys_fail(sTcgetattr);
499
+ }
500
+
501
+ if (timeout < 0)
502
+ {
503
+ params.c_cc[VTIME] = 0;
504
+ params.c_cc[VMIN] = 0;
505
+ }
506
+ else if (timeout == 0)
507
+ {
508
+ params.c_cc[VTIME] = 0;
509
+ params.c_cc[VMIN] = 1;
510
+ }
511
+ else
512
+ {
513
+ params.c_cc[VTIME] = (timeout + 50) / 100;
514
+ params.c_cc[VMIN] = 0;
515
+ }
516
+
517
+ if (tcsetattr(fd, TCSANOW, &params) == -1)
518
+ {
519
+ rb_sys_fail(sTcsetattr);
520
+ }
521
+
522
+ return val;
523
+ }
524
+
525
+ VALUE sp_get_read_timeout_impl(self)
526
+ VALUE self;
527
+ {
528
+ int fd;
529
+ struct termios params;
530
+
531
+ fd = get_fd_helper(self);
532
+ if (tcgetattr(fd, &params) == -1)
533
+ {
534
+ rb_sys_fail(sTcgetattr);
535
+ }
536
+
537
+ if (params.c_cc[VTIME] == 0 && params.c_cc[VMIN] == 0)
538
+ {
539
+ return INT2FIX(-1);
540
+ }
541
+
542
+ return INT2FIX(params.c_cc[VTIME] * 100);
543
+ }
544
+
545
+ VALUE sp_set_write_timeout_impl(self, val)
546
+ VALUE self, val;
547
+ {
548
+ rb_notimplement();
549
+ return self;
550
+ }
551
+
552
+ VALUE sp_get_write_timeout_impl(self)
553
+ VALUE self;
554
+ {
555
+ rb_notimplement();
556
+ return self;
557
+ }
558
+
559
+ VALUE sp_break_impl(self, time)
560
+ VALUE self, time;
561
+ {
562
+ int fd;
563
+
564
+ Check_Type(time, T_FIXNUM);
565
+
566
+ fd = get_fd_helper(self);
567
+
568
+ if (tcsendbreak(fd, FIX2INT(time) / 3) == -1)
569
+ {
570
+ rb_sys_fail("tcsendbreak");
571
+ }
572
+
573
+ return Qnil;
574
+ }
575
+
576
+ void get_line_signals_helper_impl(obj, ls)
577
+ VALUE obj;
578
+ struct line_signals *ls;
579
+ {
580
+ int fd, status;
581
+
582
+ fd = get_fd_helper(obj);
583
+
584
+ if (ioctl(fd, TIOCMGET, &status) == -1)
585
+ {
586
+ rb_sys_fail(sIoctl);
587
+ }
588
+
589
+ ls->rts = (status & TIOCM_RTS ? 1 : 0);
590
+ ls->dtr = (status & TIOCM_DTR ? 1 : 0);
591
+ ls->cts = (status & TIOCM_CTS ? 1 : 0);
592
+ ls->dsr = (status & TIOCM_DSR ? 1 : 0);
593
+ ls->dcd = (status & TIOCM_CD ? 1 : 0);
594
+ ls->ri = (status & TIOCM_RI ? 1 : 0);
595
+ }
596
+
597
+ VALUE set_signal_impl(obj, val, sig)
598
+ VALUE obj,val;
599
+ int sig;
600
+ {
601
+ int status;
602
+ int fd;
603
+ int set;
604
+
605
+ Check_Type(val, T_FIXNUM);
606
+ fd = get_fd_helper(obj);
607
+
608
+ if (ioctl(fd, TIOCMGET, &status) == -1)
609
+ {
610
+ rb_sys_fail(sIoctl);
611
+ }
612
+
613
+ set = FIX2INT(val);
614
+
615
+ if (set == 0)
616
+ {
617
+ status &= ~sig;
618
+ }
619
+ else if (set == 1)
620
+ {
621
+ status |= sig;
622
+ }
623
+ else
624
+ {
625
+ rb_raise(rb_eArgError, "invalid value");
626
+ }
627
+
628
+ if (ioctl(fd, TIOCMSET, &status) == -1)
629
+ {
630
+ rb_sys_fail(sIoctl);
631
+ }
632
+
633
+ return val;
634
+ }
635
+
636
+ VALUE sp_set_rts_impl(self, val)
637
+ VALUE self, val;
638
+ {
639
+ return set_signal(self, val, TIOCM_RTS);
640
+ }
641
+
642
+ VALUE sp_set_dtr_impl(self, val)
643
+ VALUE self, val;
644
+ {
645
+ return set_signal(self, val, TIOCM_DTR);
646
+ }
647
+
648
+ VALUE sp_get_rts_impl(self)
649
+ VALUE self;
650
+ {
651
+ struct line_signals ls;
652
+
653
+ get_line_signals_helper(self, &ls);
654
+ return INT2FIX(ls.rts);
655
+ }
656
+
657
+ VALUE sp_get_dtr_impl(self)
658
+ VALUE self;
659
+ {
660
+ struct line_signals ls;
661
+
662
+ get_line_signals_helper(self, &ls);
663
+
664
+ return INT2FIX(ls.dtr);
665
+ }
666
+
667
+ #endif /* !defined(OS_MSWIN) || !defined(OS_BCCWIN) */