Floppy-rb232 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/COPYING ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2008 James Smith (james@floppy.org.uk)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,54 @@
1
+ == RB232
2
+
3
+ A simple serial port library for Ruby.
4
+
5
+ Licensed under the MIT license (See COPYING file for details)
6
+
7
+ Author: James Smith (james@floppy.org.uk / http://www.floppy.org.uk)
8
+
9
+ Homepage: http://github.com/Floppy/rb232
10
+
11
+ == ABOUT
12
+
13
+ This library is a simple serial port library for Ruby.
14
+
15
+ You may ask, why not just use ruby-serialport? Mainly because the GPL license
16
+ it is under is too restrictive for my purposes. This code is under the MIT
17
+ license, so you can do anything you like with it.
18
+
19
+ == INSTALLATION
20
+
21
+ 1) Enable gems from github, if you haven't already done so (rubygems >= 1.2):
22
+ > sudo gem sources -a http://gems.github.com
23
+
24
+ 2) Install gem
25
+ > sudo gem install Floppy-rb232
26
+
27
+ == STATUS
28
+
29
+ Currently you can read from a serial port, but not write back. The code is only
30
+ tested on Linux - other unixes *may* work, Mac OSX *might* be ok, but Windows
31
+ is right out for now. Watch this space for further developments!
32
+
33
+ == USAGE
34
+
35
+ The following code will read a 10-character string from the specified port,
36
+ using the default port settings (9600/8/n/1)
37
+
38
+ @port = RB232::Port.new('/dev/ttyUSB0')
39
+ message = @port.read_string(10)
40
+
41
+ You can provide alternative settings when you create a new port:
42
+
43
+ RB232::Port.new('/dev/ttyS0', :baud_rate => 19200,
44
+ :data_bits => 7,
45
+ :parity => true,
46
+ :stop_bits => 2)
47
+
48
+ If you are using a simple text protocol over RS232, you can use the TextProtocol
49
+ class to help you out. It automatically monitors the port and splits messages
50
+ up by detecting separator characters. See examples/listen.rb for an example of
51
+ how to use this class.
52
+
53
+ See http://github.com/Floppy/rb232/tree/master/spec/port_spec.rb for more
54
+ details.
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ dir = File.dirname(__FILE__) + '/../lib'
4
+ $LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
5
+
6
+ require 'rb232'
7
+ require 'rb232/text_protocol'
8
+
9
+ class SimpleClient
10
+ def update(message)
11
+ puts("Message received:")
12
+ puts(message)
13
+ end
14
+ end
15
+
16
+ require 'optparse'
17
+
18
+ # Command-line options - just baud rate and separator for now
19
+ options = {:port => '/dev/ttyS0', :baud_rate => 9600, :separator => "\n"}
20
+ OptionParser.new do |opts|
21
+ opts.on("-p", "--serial_port SERIAL_PORT", "serial port") do |p|
22
+ options[:port] = p
23
+ end
24
+ opts.on("-b", "--baud_rate BAUD_RATE", "baud rate") do |b|
25
+ options[:baud_rate] = b
26
+ end
27
+ opts.on("-s", "--separator SEPARATOR", "message separator character") do |s|
28
+ options[:separator] = s
29
+ end
30
+ end.parse!
31
+
32
+ port = RB232::Port.new(options[:port], :baud_rate => options[:baud_rate])
33
+
34
+ protocol = RB232::TextProtocol.new(port, options[:separator])
35
+ client = SimpleClient.new
36
+ protocol.add_observer(client)
37
+
38
+ # Start receiving messags
39
+ protocol.start
40
+
41
+ # Wait a while
42
+ sleep(30)
43
+
44
+ # OK, finish now
45
+ protocol.stop
data/extconf.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'mkmf'
2
+ create_makefile('rb232', 'src')
@@ -0,0 +1,41 @@
1
+ require 'rb232'
2
+ require 'observer'
3
+
4
+ module RB232
5
+
6
+ class TextProtocol
7
+
8
+ include Observable
9
+
10
+ def initialize(port, separator = "\n")
11
+ @port = port
12
+ @separator = separator
13
+ end
14
+
15
+ attr_reader :separator
16
+ attr_reader :port
17
+
18
+ def start
19
+ @stop = false
20
+ @reader_thread = Thread.new {
21
+ buffer = ""
22
+ while (@stop == false)
23
+ buffer += @port.read_string(1)
24
+ messages = buffer.split(@separator,3)
25
+ if messages.size > 1
26
+ changed
27
+ notify_observers(messages[0])
28
+ buffer = ""
29
+ end
30
+ end
31
+ }
32
+ end
33
+
34
+ def stop
35
+ @stop = true
36
+ @reader_thread.join
37
+ end
38
+
39
+ end
40
+
41
+ end
data/src/port.c ADDED
@@ -0,0 +1,254 @@
1
+ #include "port.h"
2
+ #include "utility.h"
3
+
4
+ #include <fcntl.h>
5
+ #include <termios.h>
6
+
7
+ /* Module and class handles */
8
+ VALUE RB232 = Qnil;
9
+ VALUE RB232_Port = Qnil;
10
+
11
+ /*
12
+ * Data structure for storing object data
13
+ */
14
+ struct RB232_Port_Data {
15
+ /* Settings */
16
+ char* port_name;
17
+ int baud_rate;
18
+ int data_bits;
19
+ BOOL parity;
20
+ int stop_bits;
21
+ /* Internals */
22
+ int port_handle;
23
+ struct termios settings;
24
+ };
25
+
26
+ /* Helper for accessing port data */
27
+ struct RB232_Port_Data* get_port_data(VALUE self) {
28
+ struct RB232_Port_Data *port_data;
29
+ Data_Get_Struct(self, struct RB232_Port_Data, port_data);
30
+ return port_data;
31
+ };
32
+
33
+ /*
34
+ * Port data deallocation
35
+ */
36
+ VALUE rb232_port_data_free(void* p) {
37
+ struct RB232_Port_Data* port_data = p;
38
+ /* Close port */
39
+ close(port_data->port_handle);
40
+ /* Free memory */
41
+ free(port_data->port_name);
42
+ free(port_data);
43
+ }
44
+
45
+ /*
46
+ * Object allocation
47
+ */
48
+ VALUE rb232_port_alloc(VALUE klass) {
49
+ struct RB232_Port_Data* port_data = malloc(sizeof(struct RB232_Port_Data));
50
+ memset(port_data, 0, sizeof(struct RB232_Port_Data));
51
+ return Data_Wrap_Struct(klass, 0, rb232_port_data_free, port_data);
52
+ }
53
+
54
+ /*
55
+ * Object initialization. Takes a port name and a hash of port options.
56
+ */
57
+ VALUE rb232_port_initialize_with_options(VALUE self, VALUE port, VALUE options) {
58
+ /* Get port data */
59
+ struct RB232_Port_Data *port_data = get_port_data(self);
60
+ /* Store port name */
61
+ int port_name_len = RSTRING(port)->len;
62
+ port_data->port_name = malloc(port_name_len + 1);
63
+ strcpy(port_data->port_name, RSTRING(port)->ptr);
64
+ /* Store options */
65
+ port_data->baud_rate = rbx_int_from_hash_or_default(options, ID2SYM(rb_intern("baud_rate")), 9600);
66
+ port_data->data_bits = rbx_int_from_hash_or_default(options, ID2SYM(rb_intern("data_bits")), 8);
67
+ port_data->parity = rbx_bool_from_hash_or_default(options, ID2SYM(rb_intern("parity")), FALSE);
68
+ port_data->stop_bits = rbx_int_from_hash_or_default(options, ID2SYM(rb_intern("stop_bits")), 1);
69
+ /* Open the serial port */
70
+ port_data->port_handle = open(port_data->port_name, O_RDWR | O_NOCTTY);
71
+ if (port_data->port_handle < 0) {
72
+ rb_raise(rb_eArgError, "couldn't open the specified port");
73
+ }
74
+ /* Set port settings */
75
+ port_data->settings.c_cflag = CRTSCTS | CLOCAL | CREAD;
76
+ /* Baud rate */
77
+ switch (port_data->baud_rate) {
78
+ case 0:
79
+ port_data->settings.c_cflag |= B0;
80
+ break;
81
+ case 50:
82
+ port_data->settings.c_cflag |= B50;
83
+ break;
84
+ case 75:
85
+ port_data->settings.c_cflag |= B75;
86
+ break;
87
+ case 110:
88
+ port_data->settings.c_cflag |= B110;
89
+ break;
90
+ case 134:
91
+ port_data->settings.c_cflag |= B134;
92
+ break;
93
+ case 150:
94
+ port_data->settings.c_cflag |= B150;
95
+ break;
96
+ case 200:
97
+ port_data->settings.c_cflag |= B200;
98
+ break;
99
+ case 300:
100
+ port_data->settings.c_cflag |= B300;
101
+ break;
102
+ case 600:
103
+ port_data->settings.c_cflag |= B600;
104
+ break;
105
+ case 1200:
106
+ port_data->settings.c_cflag |= B1200;
107
+ break;
108
+ case 1800:
109
+ port_data->settings.c_cflag |= B1800;
110
+ break;
111
+ case 2400:
112
+ port_data->settings.c_cflag |= B2400;
113
+ break;
114
+ case 4800:
115
+ port_data->settings.c_cflag |= B4800;
116
+ break;
117
+ case 9600:
118
+ port_data->settings.c_cflag |= B9600;
119
+ break;
120
+ case 19200:
121
+ port_data->settings.c_cflag |= B19200;
122
+ break;
123
+ case 38400:
124
+ port_data->settings.c_cflag |= B38400;
125
+ break;
126
+ default:
127
+ rb_raise(rb_eArgError, "baud_rate must be a valid value");
128
+ }
129
+ port_data->settings.c_cflag |= B9600;
130
+ /* Data bits */
131
+ switch (port_data->data_bits) {
132
+ case 8:
133
+ port_data->settings.c_cflag |= CS8;
134
+ break;
135
+ case 7:
136
+ port_data->settings.c_cflag |= CS7;
137
+ break;
138
+ case 6:
139
+ port_data->settings.c_cflag |= CS6;
140
+ break;
141
+ case 5:
142
+ port_data->settings.c_cflag |= CS5;
143
+ break;
144
+ default:
145
+ rb_raise(rb_eArgError, "data_bits must be 5, 6, 7 or 8");
146
+ }
147
+ /* Parity */
148
+ if (port_data->parity) port_data->settings.c_cflag |= PARENB;
149
+ /* Stop bits */
150
+ switch (port_data->stop_bits) {
151
+ case 2:
152
+ port_data->settings.c_cflag |= CSTOPB;
153
+ break;
154
+ case 1:
155
+ break;
156
+ default:
157
+ rb_raise(rb_eArgError, "stop_bits must be 1 or 2");
158
+ }
159
+ /* Other settings */
160
+ port_data->settings.c_iflag = IGNPAR | ICRNL;
161
+ port_data->settings.c_oflag = 0;
162
+ port_data->settings.c_lflag = ICANON;
163
+ /* Flush input buffer */
164
+ tcflush(port_data->port_handle, TCIFLUSH);
165
+ /* Apply settings to port */
166
+ tcsetattr(port_data->port_handle, TCSANOW, &port_data->settings);
167
+ /* Done */
168
+ return Qnil;
169
+ }
170
+
171
+ /*
172
+ * This function implements a default argument for initialize().
173
+ * Equivalent Ruby would be def initialize(port, options = {}).
174
+ * This function calls the _with_options version, providing an empty
175
+ * hash if one is not passed in.
176
+ */
177
+ VALUE rb232_port_initialize(int argc, VALUE* argv, VALUE self) {
178
+ /* Only allow 1 or 2 arguments */
179
+ if (argc == 0 || argc >= 3) {
180
+ rb_raise(rb_eArgError, "wrong number of arguments (must be 1 or 2)");
181
+ return Qnil;
182
+ }
183
+ /* Get port name */
184
+ SafeStringValue(argv[0]);
185
+ VALUE port = argv[0];
186
+ /* Get options */
187
+ VALUE options = Qnil;
188
+ if (argc == 1)
189
+ options = rb_hash_new();
190
+ else
191
+ options = rb_convert_type(argv[1], T_HASH, "Hash", "to_hash");
192
+ /* Call real initialize function */
193
+ return rb232_port_initialize_with_options(self, port, options);
194
+ }
195
+
196
+ /* def port_name */
197
+ VALUE rb232_port_get_port_name(VALUE self) {
198
+ /* Return baud rate */
199
+ return rb_str_new2(get_port_data(self)->port_name);
200
+ }
201
+
202
+ /* def baud_rate */
203
+ VALUE rb232_port_get_baud_rate(VALUE self) {
204
+ /* Return baud rate */
205
+ return rb_uint_new(get_port_data(self)->baud_rate);
206
+ }
207
+
208
+ /* def data_bits */
209
+ VALUE rb232_port_get_data_bits(VALUE self) {
210
+ /* Return baud rate */
211
+ return rb_uint_new(get_port_data(self)->data_bits);
212
+ }
213
+
214
+ /* def parity */
215
+ VALUE rb232_port_get_parity(VALUE self) {
216
+ /* Return baud rate */
217
+ if (get_port_data(self)->parity == TRUE)
218
+ return Qtrue;
219
+ else
220
+ return Qfalse;
221
+ }
222
+
223
+ /* def stop_bits */
224
+ VALUE rb232_port_get_stop_bits(VALUE self) {
225
+ /* Return baud rate */
226
+ return rb_uint_new(get_port_data(self)->stop_bits);
227
+ }
228
+
229
+ /* Read raw data from port */
230
+ int rb232_port_read(VALUE self, char* buffer, VALUE count) {
231
+ int bytes_to_read = NUM2INT(count);
232
+ if (bytes_to_read > 255)
233
+ rb_raise(rb_eArgError, "can't read more than 255 bytes at once");
234
+ return read(get_port_data(self)->port_handle, buffer, bytes_to_read);
235
+ }
236
+
237
+ /* def read_bytes(count) */
238
+ VALUE rb232_port_read_bytes(VALUE self, VALUE count) {
239
+ char buffer[256];
240
+ int bytes_read = rb232_port_read(self, buffer, count);
241
+ VALUE data = rb_ary_new();
242
+ int i;
243
+ for (i=0; i<bytes_read; i++) {
244
+ rb_ary_push(data, INT2NUM(buffer[i]));
245
+ }
246
+ }
247
+
248
+ /* def read_string(count) */
249
+ VALUE rb232_port_read_string(VALUE self, VALUE count) {
250
+ char buffer[256];
251
+ int bytes_read = rb232_port_read(self, buffer, count);
252
+ buffer[bytes_read] = 0;
253
+ return rb_str_new2(buffer);
254
+ }
data/src/port.h ADDED
@@ -0,0 +1,34 @@
1
+ #include "ruby.h"
2
+
3
+ /* module RB232 */
4
+ extern VALUE RB232;
5
+
6
+ /* class Port */
7
+ extern VALUE RB232_Port;
8
+
9
+ /* Allocator for Port class */
10
+ VALUE rb232_port_alloc(VALUE klass);
11
+
12
+ /* def initialize(options = {}) */
13
+ VALUE rb232_port_initialize(int argc, VALUE* argv, VALUE self);
14
+
15
+ /* def port_name */
16
+ VALUE rb232_port_get_port_name(VALUE self);
17
+
18
+ /* def baud_rate */
19
+ VALUE rb232_port_get_baud_rate(VALUE self);
20
+
21
+ /* def data_bits */
22
+ VALUE rb232_port_get_data_bits(VALUE self);
23
+
24
+ /* def parity */
25
+ VALUE rb232_port_get_parity(VALUE self);
26
+
27
+ /* def stop_bits */
28
+ VALUE rb232_port_get_stop_bits(VALUE self);
29
+
30
+ /* def read_bytes(count) */
31
+ VALUE rb232_port_read_bytes(VALUE self, VALUE count);
32
+
33
+ /* def read_string(count) */
34
+ VALUE rb232_port_read_string(VALUE self, VALUE count);
data/src/rb232.c ADDED
@@ -0,0 +1,21 @@
1
+ #include "ruby.h"
2
+ #include "port.h"
3
+
4
+ /*
5
+ * Library initialization.
6
+ * Registers all classes and methods with the Ruby interpreter.
7
+ * Called automatically on require 'rb232'.
8
+ */
9
+ void Init_rb232() {
10
+ RB232 = rb_define_module("RB232");
11
+ RB232_Port = rb_define_class_under(RB232, "Port", rb_cObject);
12
+ rb_define_alloc_func(RB232_Port, rb232_port_alloc);
13
+ rb_define_method(RB232_Port, "initialize", rb232_port_initialize, -1);
14
+ rb_define_method(RB232_Port, "port_name", rb232_port_get_port_name, 0);
15
+ rb_define_method(RB232_Port, "baud_rate", rb232_port_get_baud_rate, 0);
16
+ rb_define_method(RB232_Port, "data_bits", rb232_port_get_data_bits, 0);
17
+ rb_define_method(RB232_Port, "parity", rb232_port_get_parity, 0);
18
+ rb_define_method(RB232_Port, "stop_bits", rb232_port_get_stop_bits, 0);
19
+ rb_define_method(RB232_Port, "read_bytes", rb232_port_read_bytes, 1);
20
+ rb_define_method(RB232_Port, "read_string", rb232_port_read_string, 1);
21
+ }
data/src/utility.c ADDED
@@ -0,0 +1,20 @@
1
+ #include "utility.h"
2
+
3
+ int rbx_int_from_hash_or_default(VALUE hash, VALUE key, int default_val) {
4
+ VALUE data = (rb_hash_aref(hash, key));
5
+ if (data == Qnil)
6
+ return default_val;
7
+ else
8
+ return NUM2INT(data);
9
+ }
10
+
11
+ BOOL rbx_bool_from_hash_or_default(VALUE hash, VALUE key, BOOL default_val) {
12
+ VALUE data = (rb_hash_aref(hash, key));
13
+ if (data == Qnil)
14
+ return default_val;
15
+ else
16
+ if (data == Qtrue)
17
+ return TRUE;
18
+ else
19
+ return FALSE;
20
+ }
data/src/utility.h ADDED
@@ -0,0 +1,19 @@
1
+ #include "ruby.h"
2
+
3
+ #define BOOL char
4
+ #define TRUE 1
5
+ #define FALSE 0
6
+
7
+ /*
8
+ * Get a key from a hash, or if it's not there, use the default.
9
+ * A bit like doing hash[key] || default_val in Ruby.
10
+ * Integer version.
11
+ */
12
+ int rbx_int_from_hash_or_default(VALUE hash, VALUE key, int default_val);
13
+
14
+ /*
15
+ * Get a key from a hash, or if it's not there, use the default.
16
+ * A bit like doing hash[key] || default_val in Ruby.
17
+ * Boolean version.
18
+ */
19
+ BOOL rbx_bool_from_hash_or_default(VALUE hash, VALUE key, BOOL default_val);
metadata ADDED
@@ -0,0 +1,62 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: Floppy-rb232
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - James Smith
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-08-19 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: james@floppy.org.uk
18
+ executables: []
19
+
20
+ extensions:
21
+ - extconf.rb
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - README
26
+ - COPYING
27
+ - extconf.rb
28
+ - src/port.c
29
+ - src/port.h
30
+ - src/rb232.c
31
+ - src/utility.c
32
+ - src/utility.h
33
+ - lib/rb232/text_protocol.rb
34
+ - examples/listen.rb
35
+ has_rdoc: false
36
+ homepage: http://github.com/Floppy/rb232
37
+ post_install_message:
38
+ rdoc_options: []
39
+
40
+ require_paths:
41
+ - lib
42
+ required_ruby_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: "0"
47
+ version:
48
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: "0"
53
+ version:
54
+ requirements: []
55
+
56
+ rubyforge_project:
57
+ rubygems_version: 1.2.0
58
+ signing_key:
59
+ specification_version: 2
60
+ summary: A simple serial port library for Ruby
61
+ test_files: []
62
+