Floppy-rb232 0.2.0

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.
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
+