ruby-serialport 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,611 @@
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 <stdio.h> /* Standard input/output definitions */
20
+ #include <io.h> /* Low-level I/O definitions */
21
+ #include <fcntl.h> /* File control definitions */
22
+ #include <windows.h> /* Windows standard function definitions */
23
+
24
+ #ifndef RB_SERIAL_EXPORT
25
+ #define RB_SERIAL_EXPORT __declspec(dllexport)
26
+ //#define RB_SERIAL_EXPORT
27
+ #endif
28
+
29
+ static char sGetCommState[] = "GetCommState";
30
+ static char sSetCommState[] = "SetCommState";
31
+ static char sGetCommTimeouts[] = "GetCommTimeouts";
32
+ static char sSetCommTimeouts[] = "SetCommTimeouts";
33
+
34
+
35
+ static HANDLE get_handle_helper(obj)
36
+ VALUE obj;
37
+ {
38
+ OpenFile *fptr;
39
+
40
+ GetOpenFile(obj, fptr);
41
+ return (HANDLE) _get_osfhandle(fileno(fptr->f));
42
+ }
43
+
44
+ VALUE RB_SERIAL_EXPORT sp_create_impl(class, _port)
45
+ VALUE class, _port;
46
+ {
47
+ OpenFile *fp;
48
+ int fd;
49
+ HANDLE fh;
50
+ int num_port;
51
+ char *port;
52
+ char *ports[] = {
53
+ "COM1", "COM2", "COM3", "COM4",
54
+ "COM5", "COM6", "COM7", "COM8"
55
+ };
56
+ //int new_fd;
57
+
58
+ DCB dcb;
59
+
60
+ NEWOBJ(sp, struct RFile);
61
+ rb_secure(4);
62
+ OBJSETUP(sp, class, T_FILE);
63
+ MakeOpenFile((VALUE) sp, fp);
64
+
65
+ switch(TYPE(_port))
66
+ {
67
+ case T_FIXNUM:
68
+ num_port = FIX2INT(_port);
69
+ if (num_port < 0 || num_port > sizeof(ports) / sizeof(ports[0]))
70
+ {
71
+ rb_raise(rb_eArgError, "illegal port number");
72
+ }
73
+ port = ports[num_port];
74
+ break;
75
+
76
+ case T_STRING:
77
+ Check_SafeStr(_port);
78
+ port = RSTRING(_port)->ptr;
79
+ break;
80
+
81
+ default:
82
+ rb_raise(rb_eTypeError, "wrong argument type");
83
+ break;
84
+ }
85
+
86
+ printf("SerialPort => %s\n", port);
87
+ fd = open(port, O_BINARY | O_RDWR);
88
+ printf(" fd => %i\n", fd);
89
+ if (fd == -1)
90
+ rb_sys_fail(port);
91
+ fh = (HANDLE) _get_osfhandle(fd);
92
+ printf(" fh => %i\n", fh);
93
+ if (SetupComm(fh, 1024, 1024) == 0)
94
+ {
95
+ close(fd);
96
+ rb_raise(rb_eArgError, "not a serial port");
97
+ }
98
+
99
+ dcb.DCBlength = sizeof(dcb);
100
+ if (GetCommState(fh, &dcb) == 0)
101
+ {
102
+ close(fd);
103
+ rb_sys_fail(sGetCommState);
104
+ }
105
+ dcb.fBinary = TRUE;
106
+ dcb.fParity = FALSE;
107
+ dcb.fOutxDsrFlow = FALSE;
108
+ dcb.fDtrControl = DTR_CONTROL_ENABLE;
109
+ dcb.fDsrSensitivity = FALSE;
110
+ dcb.fTXContinueOnXoff = FALSE;
111
+ dcb.fErrorChar = FALSE;
112
+ dcb.fNull = FALSE;
113
+ dcb.fAbortOnError = FALSE;
114
+ dcb.XonChar = 17;
115
+ dcb.XoffChar = 19;
116
+ if (SetCommState(fh, &dcb) == 0)
117
+ {
118
+ close(fd);
119
+ rb_sys_fail(sSetCommState);
120
+ }
121
+
122
+ errno = 0;
123
+ fp->mode = FMODE_READWRITE | FMODE_BINMODE | FMODE_SYNC;
124
+ fp->f = fdopen(fd, "rb+");
125
+ return (VALUE) sp;
126
+ }
127
+
128
+ VALUE RB_SERIAL_EXPORT sp_set_modem_params_impl(argc, argv, self)
129
+ int argc;
130
+ VALUE *argv, self;
131
+ {
132
+ HANDLE fh;
133
+ DCB dcb;
134
+ VALUE _data_rate, _data_bits, _parity, _stop_bits;
135
+ int use_hash = 0;
136
+ int data_rate, data_bits, parity;
137
+
138
+ if (argc == 0)
139
+ {
140
+ return self;
141
+ }
142
+ if (argc == 1 && T_HASH == TYPE(argv[0]))
143
+ {
144
+ use_hash = 1;
145
+ _data_rate = rb_hash_aref(argv[0], sBaud);
146
+ _data_bits = rb_hash_aref(argv[0], sDataBits);
147
+ _stop_bits = rb_hash_aref(argv[0], sStopBits);
148
+ _parity = rb_hash_aref(argv[0], sParity);
149
+ }
150
+
151
+ fh = get_handle_helper(self);
152
+ dcb.DCBlength = sizeof(dcb);
153
+ if (GetCommState(fh, &dcb) == 0)
154
+ {
155
+ rb_sys_fail(sGetCommState);
156
+ }
157
+
158
+ if (!use_hash)
159
+ {
160
+ _data_rate = argv[0];
161
+ }
162
+
163
+ if (NIL_P(_data_rate))
164
+ {
165
+ goto SkipDataRate;
166
+ }
167
+
168
+ Check_Type(_data_rate, T_FIXNUM);
169
+
170
+ data_rate = FIX2INT(_data_rate);
171
+ switch (data_rate)
172
+ {
173
+ case 110:
174
+ case 300:
175
+ case 600:
176
+ case 1200:
177
+ case 2400:
178
+ case 4800:
179
+ case 9600:
180
+ case 14400:
181
+ case 19200:
182
+ case 38400:
183
+ case 56000:
184
+ case 57600:
185
+ case 115200:
186
+ case 128000:
187
+ case 256000:
188
+ dcb.BaudRate = data_rate;
189
+ break;
190
+
191
+ default:
192
+ rb_raise(rb_eArgError, "unknown baud rate");
193
+ break;
194
+ }
195
+
196
+ SkipDataRate:
197
+
198
+ if (!use_hash)
199
+ {
200
+ _data_bits = (argc >= 2 ? argv[1] : INT2FIX(8));
201
+ }
202
+
203
+ if (NIL_P(_data_bits))
204
+ {
205
+ goto SkipDataBits;
206
+ }
207
+
208
+ Check_Type(_data_bits, T_FIXNUM);
209
+
210
+ data_bits = FIX2INT(_data_bits);
211
+ if (4 <= data_bits && data_bits <= 8)
212
+ {
213
+ dcb.ByteSize = data_bits;
214
+ }
215
+ else
216
+ {
217
+ rb_raise(rb_eArgError, "unknown character size");
218
+ }
219
+
220
+ SkipDataBits:
221
+
222
+ if (!use_hash)
223
+ {
224
+ _stop_bits = (argc >= 3 ? argv[2] : INT2FIX(1));
225
+ }
226
+
227
+ if (NIL_P(_stop_bits))
228
+ {
229
+ goto SkipStopBits;
230
+ }
231
+
232
+ Check_Type(_stop_bits, T_FIXNUM);
233
+
234
+ switch (FIX2INT(_stop_bits))
235
+ {
236
+ case 1:
237
+ dcb.StopBits = ONESTOPBIT;
238
+ break;
239
+ case 2:
240
+ dcb.StopBits = TWOSTOPBITS;
241
+ break;
242
+ default:
243
+ rb_raise(rb_eArgError, "unknown number of stop bits");
244
+ break;
245
+ }
246
+
247
+ SkipStopBits:
248
+
249
+ if (!use_hash)
250
+ {
251
+ _parity = (argc >= 4 ? argv[3] : (dcb.ByteSize == 8 ?
252
+ INT2FIX(NOPARITY) : INT2FIX(EVENPARITY)));
253
+ }
254
+
255
+ if (NIL_P(_parity))
256
+ {
257
+ goto SkipParity;
258
+ }
259
+
260
+ Check_Type(_parity, T_FIXNUM);
261
+
262
+ parity = FIX2INT(_parity);
263
+ switch (parity)
264
+ {
265
+ case EVENPARITY:
266
+ case ODDPARITY:
267
+ case MARKPARITY:
268
+ case SPACEPARITY:
269
+ case NOPARITY:
270
+ dcb.Parity = parity;
271
+ break;
272
+
273
+ default:
274
+ rb_raise(rb_eArgError, "unknown parity");
275
+ break;
276
+ }
277
+
278
+ SkipParity:
279
+
280
+ if (SetCommState(fh, &dcb) == 0)
281
+ {
282
+ rb_sys_fail(sSetCommState);
283
+ }
284
+
285
+ return argv[0];
286
+ }
287
+
288
+ void RB_SERIAL_EXPORT get_modem_params_impl(self, mp)
289
+ VALUE self;
290
+ struct modem_params *mp;
291
+ {
292
+ HANDLE fh;
293
+ DCB dcb;
294
+
295
+ fh = get_handle_helper(self);
296
+ dcb.DCBlength = sizeof(dcb);
297
+ if (GetCommState(fh, &dcb) == 0)
298
+ {
299
+ rb_sys_fail(sGetCommState);
300
+ }
301
+
302
+ mp->data_rate = dcb.BaudRate;
303
+ mp->data_bits = dcb.ByteSize;
304
+ mp->stop_bits = (dcb.StopBits == ONESTOPBIT ? 1 : 2);
305
+ mp->parity = dcb.Parity;
306
+ }
307
+
308
+ VALUE RB_SERIAL_EXPORT sp_set_flow_control_impl(self, val)
309
+ VALUE self, val;
310
+ {
311
+ HANDLE fh;
312
+ int flowc;
313
+ DCB dcb;
314
+
315
+ Check_Type(val, T_FIXNUM);
316
+
317
+ fh = get_handle_helper(self);
318
+ dcb.DCBlength = sizeof(dcb);
319
+ if (GetCommState(fh, &dcb) == 0)
320
+ {
321
+ rb_sys_fail(sGetCommState);
322
+ }
323
+
324
+ flowc = FIX2INT(val);
325
+ if (flowc & HARD)
326
+ {
327
+ dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
328
+ dcb.fOutxCtsFlow = TRUE;
329
+ }
330
+ else
331
+ {
332
+ dcb.fRtsControl = RTS_CONTROL_ENABLE;
333
+ dcb.fOutxCtsFlow = FALSE;
334
+ }
335
+
336
+ if (flowc & SOFT)
337
+ {
338
+ dcb.fOutX = dcb.fInX = TRUE;
339
+ }
340
+ else
341
+ {
342
+ dcb.fOutX = dcb.fInX = FALSE;
343
+ }
344
+
345
+ if (SetCommState(fh, &dcb) == 0)
346
+ {
347
+ rb_sys_fail(sSetCommState);
348
+ }
349
+
350
+ return val;
351
+ }
352
+
353
+ VALUE RB_SERIAL_EXPORT sp_get_flow_control_impl(self)
354
+ VALUE self;
355
+ {
356
+ HANDLE fh;
357
+ int ret;
358
+ DCB dcb;
359
+
360
+ fh = get_handle_helper(self);
361
+ dcb.DCBlength = sizeof(dcb);
362
+ if (GetCommState(fh, &dcb) == 0)
363
+ {
364
+ rb_sys_fail(sGetCommState);
365
+ }
366
+
367
+ ret = 0;
368
+ if (dcb.fOutxCtsFlow)
369
+ {
370
+ ret += HARD;
371
+ }
372
+
373
+ if (dcb.fOutX)
374
+ {
375
+ ret += SOFT;
376
+ }
377
+
378
+ return INT2FIX(ret);
379
+ }
380
+
381
+ VALUE RB_SERIAL_EXPORT sp_set_read_timeout_impl(self, val)
382
+ VALUE self, val;
383
+ {
384
+ int timeout;
385
+ HANDLE fh;
386
+ COMMTIMEOUTS ctout;
387
+
388
+ Check_Type(val, T_FIXNUM);
389
+ timeout = FIX2INT(val);
390
+
391
+ fh = get_handle_helper(self);
392
+ if (GetCommTimeouts(fh, &ctout) == 0)
393
+ {
394
+ rb_sys_fail(sGetCommTimeouts);
395
+ }
396
+
397
+ if (timeout < 0)
398
+ {
399
+ ctout.ReadIntervalTimeout = MAXDWORD;
400
+ ctout.ReadTotalTimeoutMultiplier = 0;
401
+ ctout.ReadTotalTimeoutConstant = 0;
402
+ }
403
+ else if (timeout == 0)
404
+ {
405
+ ctout.ReadIntervalTimeout = MAXDWORD;
406
+ ctout.ReadTotalTimeoutMultiplier = MAXDWORD;
407
+ ctout.ReadTotalTimeoutConstant = MAXDWORD - 1;
408
+ }
409
+ else
410
+ {
411
+ ctout.ReadIntervalTimeout = timeout;
412
+ ctout.ReadTotalTimeoutMultiplier = 0;
413
+ ctout.ReadTotalTimeoutConstant = timeout;
414
+ }
415
+
416
+ if (SetCommTimeouts(fh, &ctout) == 0)
417
+ {
418
+ rb_sys_fail(sSetCommTimeouts);
419
+ }
420
+
421
+ return val;
422
+ }
423
+
424
+ VALUE RB_SERIAL_EXPORT sp_get_read_timeout_impl(self)
425
+ VALUE self;
426
+ {
427
+ HANDLE fh;
428
+ COMMTIMEOUTS ctout;
429
+
430
+ fh = get_handle_helper(self);
431
+ if (GetCommTimeouts(fh, &ctout) == 0)
432
+ {
433
+ rb_sys_fail(sGetCommTimeouts);
434
+ }
435
+
436
+ switch (ctout.ReadTotalTimeoutConstant)
437
+ {
438
+ case 0:
439
+ return INT2FIX(-1);
440
+ case MAXDWORD:
441
+ return INT2FIX(0);
442
+ }
443
+
444
+ return INT2FIX(ctout.ReadTotalTimeoutConstant);
445
+ }
446
+
447
+ VALUE RB_SERIAL_EXPORT sp_set_write_timeout_impl(self, val)
448
+ VALUE self, val;
449
+ {
450
+ int timeout;
451
+ HANDLE fh;
452
+ COMMTIMEOUTS ctout;
453
+
454
+ Check_Type(val, T_FIXNUM);
455
+ timeout = FIX2INT(val);
456
+
457
+ fh = get_handle_helper(self);
458
+ if (GetCommTimeouts(fh, &ctout) == 0)
459
+ {
460
+ rb_sys_fail(sGetCommTimeouts);
461
+ }
462
+
463
+ if (timeout <= 0)
464
+ {
465
+ ctout.WriteTotalTimeoutMultiplier = 0;
466
+ ctout.WriteTotalTimeoutConstant = 0;
467
+ }
468
+ else
469
+ {
470
+ ctout.WriteTotalTimeoutMultiplier = timeout;
471
+ ctout.WriteTotalTimeoutConstant = 0;
472
+ }
473
+
474
+ if (SetCommTimeouts(fh, &ctout) == 0)
475
+ {
476
+ rb_sys_fail(sSetCommTimeouts);
477
+ }
478
+
479
+ return val;
480
+ }
481
+
482
+ VALUE RB_SERIAL_EXPORT sp_get_write_timeout_impl(self)
483
+ VALUE self;
484
+ {
485
+ HANDLE fh;
486
+ COMMTIMEOUTS ctout;
487
+
488
+ fh = get_handle_helper(self);
489
+ if (GetCommTimeouts(fh, &ctout) == 0)
490
+ {
491
+ rb_sys_fail(sGetCommTimeouts);
492
+ }
493
+
494
+ return INT2FIX(ctout.WriteTotalTimeoutMultiplier);
495
+ }
496
+
497
+ static void delay_ms(time)
498
+ int time;
499
+ {
500
+ HANDLE ev;
501
+
502
+ ev = CreateEvent(NULL, FALSE, FALSE, NULL);
503
+ if (!ev)
504
+ {
505
+ rb_sys_fail("CreateEvent");
506
+ }
507
+
508
+ if (WaitForSingleObject(ev, time) == WAIT_FAILED)
509
+ {
510
+ rb_sys_fail("WaitForSingleObject");
511
+ }
512
+
513
+ CloseHandle(ev);
514
+ }
515
+
516
+ VALUE RB_SERIAL_EXPORT sp_break_impl(self, time)
517
+ VALUE self, time;
518
+ {
519
+ HANDLE fh;
520
+
521
+ Check_Type(time, T_FIXNUM);
522
+
523
+ fh = get_handle_helper(self);
524
+ if (SetCommBreak(fh) == 0)
525
+ {
526
+ rb_sys_fail("SetCommBreak");
527
+ }
528
+
529
+ delay_ms(FIX2INT(time) * 100);
530
+ ClearCommBreak(fh);
531
+
532
+ return Qnil;
533
+ }
534
+
535
+ void RB_SERIAL_EXPORT get_line_signals_helper(obj, ls)
536
+ VALUE obj;
537
+ struct line_signals *ls;
538
+ {
539
+ HANDLE fh;
540
+ int status;
541
+
542
+ fh = get_handle_helper(obj);
543
+ if (GetCommModemStatus(fh, &status) == 0)
544
+ {
545
+ rb_sys_fail("GetCommModemStatus");
546
+ }
547
+
548
+ ls->cts = (status & MS_CTS_ON ? 1 : 0);
549
+ ls->dsr = (status & MS_DSR_ON ? 1 : 0);
550
+ ls->dcd = (status & MS_RLSD_ON ? 1 : 0);
551
+ ls->ri = (status & MS_RING_ON ? 1 : 0);
552
+ }
553
+
554
+ static VALUE set_signal(obj, val, sigoff, sigon)
555
+ VALUE obj,val;
556
+ int sigoff, sigon;
557
+ {
558
+ HANDLE fh;
559
+ int set, sig;
560
+
561
+ Check_Type(val, T_FIXNUM);
562
+ fh = get_handle_helper(obj);
563
+
564
+ set = FIX2INT(val);
565
+ if (set == 0)
566
+ {
567
+ sig = sigoff;
568
+ }
569
+ else if (set == 1)
570
+ {
571
+ sig = sigon;
572
+ }
573
+ else
574
+ {
575
+ rb_raise(rb_eArgError, "invalid value");
576
+ }
577
+
578
+ if (EscapeCommFunction(fh, sig) == 0)
579
+ {
580
+ rb_sys_fail("EscapeCommFunction");
581
+ }
582
+
583
+ return val;
584
+ }
585
+
586
+ VALUE RB_SERIAL_EXPORT sp_set_rts_impl(self, val)
587
+ VALUE self, val;
588
+ {
589
+ return set_signal(self, val, CLRRTS, SETRTS);
590
+ }
591
+
592
+ VALUE RB_SERIAL_EXPORT sp_set_dtr_impl(self, val)
593
+ VALUE self, val;
594
+ {
595
+ return set_signal(self, val, CLRDTR, SETDTR);
596
+ }
597
+
598
+ VALUE RB_SERIAL_EXPORT sp_get_rts_impl(self)
599
+ VALUE self;
600
+ {
601
+ rb_notimplement();
602
+ return self;
603
+ }
604
+
605
+ VALUE RB_SERIAL_EXPORT sp_get_dtr_impl(self)
606
+ VALUE self;
607
+ {
608
+ rb_notimplement();
609
+ return self;
610
+ }
611
+