├── Manifest ├── ext ├── extconf.rb ├── serialport.h ├── serialport.c └── impl │ ├── win_serialport.c │ └── posix_serialport.c ├── examples └── miniterm.rb ├── ChangeLog ├── Rakefile ├── lib └── serialport.rb ├── README └── LICENSE /Manifest: -------------------------------------------------------------------------------- 1 | ChangeLog 2 | ext/extconf.rb 3 | ext/serialport.c 4 | ext/serialport.h 5 | ext/impl/posix_serialport.c 6 | ext/impl/win_serialport.c 7 | lib/serialport.rb 8 | LICENSE 9 | Manifest 10 | Rakefile 11 | README 12 | examples/miniterm.rb 13 | -------------------------------------------------------------------------------- /ext/extconf.rb: -------------------------------------------------------------------------------- 1 | require 'mkmf' 2 | 3 | printf("checking for OS... ") 4 | STDOUT.flush 5 | os = /-([a-z]+)/.match(RUBY_PLATFORM)[1] 6 | puts(os) 7 | $CFLAGS += " -DOS_#{os.upcase}" 8 | 9 | if !(os == 'mswin' or os == 'bccwin') 10 | exit(1) if not have_header("termios.h") or not have_header("unistd.h") 11 | end 12 | 13 | create_makefile('serialport') 14 | -------------------------------------------------------------------------------- /examples/miniterm.rb: -------------------------------------------------------------------------------- 1 | require "../serialport.so" 2 | 3 | 4 | if ARGV.size < 4 5 | STDERR.print < ??? 2 | * fix compile under ruby 1.9.1 (essentially applying patch from 3 | http://makrotopia.org/browser/makrosys/makrobe/ruby-serialport/patches/10-fix-for-ruby-1.9) 4 | 5 | === 0.7.0 => 11/1/2009 6 | * Replaced handwritten Rake tasks and Gemspec with Echoe 7 | * Fully RDoc'ified 8 | * Support for Mac OS X 9 | * Major Code Cleanup 10 | * It's a proper RubyGem now 11 | 12 | === 0.6.1 => 25/03/2003 13 | * Minor changes 14 | 15 | === 0.6 => 12/02/2003 16 | * Windows support 17 | * Get/set modem parameters 18 | * Read and write timeouts 19 | * Open method 20 | 21 | === 0.5 => 25/10/2002 22 | * Cygwin support 23 | 24 | === 0.4 => 19/09/2002 25 | * Added more serial ports (total of 8 ports) 26 | 27 | === 0.3 => 15/03/2002 28 | * Damn, another bug found 29 | 30 | === 0.2 => 14/03/2002 31 | * A bug fixed (read() was not blocking) 32 | 33 | === 0.1 => 14/03/2002 34 | * First release 35 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require 'rubygems' 4 | require 'echoe' 5 | 6 | # get the version directly from the .h file 7 | version_file = File.join File.dirname(__FILE__), "ext", "serialport.h" 8 | version = File.read(version_file).match(/RUBY_SERIAL_PORT_VERSION.*"(.*)"/)[1] 9 | 10 | # try "rake -T" so see the wunderfull tasks generated by the little code below ;-) 11 | e = Echoe.new('ruby-serialport', version) do |s| 12 | # set only a platform when building binary gems. 13 | # in this case the Manifest has also to be changed to include the compiled extension 14 | #s.platform = Gem::Platform::CURRENT 15 | s.summary = "Ruby/SerialPort is a Ruby library that provides a class for using RS-232 serial ports." 16 | 17 | s.rdoc_pattern = [ "README", "CHANGELOG", "ext/serialport.c", "lib/serialport.rb" ] 18 | s.ignore_pattern = Dir.glob("{tmp}/**/*") 19 | 20 | s.author = ["Guillaume Pierronnet", "Alan Stern", "Daniel E. Shipton", "Jonas Bähr"] 21 | s.email = "daniel.shipton.oss@gmail.com" 22 | s.project = 'ruby-serialport' 23 | s.url = "http://ruby-serialport.rubyforge.org" 24 | 25 | s.rubygems_version = nil 26 | end 27 | -------------------------------------------------------------------------------- /lib/serialport.rb: -------------------------------------------------------------------------------- 1 | require "serialport.so" 2 | 3 | class SerialPort 4 | private_class_method(:create) 5 | 6 | # Creates a serial port object. 7 | # 8 | # port may be a port number 9 | # or the file name of a defice. 10 | # The number is portable; so 0 is mapped to "COM1" on Windows, 11 | # "/dev/ttyS0" on Linux, "/dev/cuaa0" on Mac OS X, etc. 12 | # 13 | # params can be used to configure the serial port. 14 | # See SerialPort#set_modem_params for details 15 | def SerialPort::new(port, *params) 16 | sp = create(port) 17 | begin 18 | sp.set_modem_params(*params) 19 | rescue 20 | sp.close 21 | raise 22 | end 23 | return sp 24 | end 25 | 26 | # This behaves like SerialPort#new, except that you can pass a block 27 | # to which the new serial port object will be passed. In this case 28 | # the connection is automaticaly closed when the block has finished. 29 | def SerialPort::open(port, *params) 30 | sp = create(port) 31 | begin 32 | sp.set_modem_params(*params) 33 | if (block_given?) 34 | yield sp 35 | sp.close 36 | return nil 37 | end 38 | rescue 39 | sp.close 40 | raise 41 | end 42 | return sp 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /ext/serialport.h: -------------------------------------------------------------------------------- 1 | /* Ruby/SerialPort $Id$ 2 | * Guillaume Pierronnet 3 | * Alan Stern 4 | * Daniel E. Shipton 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 | #ifndef _RUBY_SERIAL_PORT_H_ 20 | #define _RUBY_SERIAL_PORT_H_ 21 | 22 | #define RUBY_SERIAL_PORT_VERSION "0.7.1" 23 | 24 | #include /* ruby inclusion */ 25 | #include /* ruby io inclusion */ 26 | 27 | struct modem_params 28 | { 29 | int data_rate; 30 | int data_bits; 31 | int stop_bits; 32 | int parity; 33 | }; 34 | 35 | struct line_signals 36 | { 37 | int rts; 38 | int dtr; 39 | int cts; 40 | int dsr; 41 | int dcd; 42 | int ri; 43 | }; 44 | 45 | #define NONE 0 46 | #define HARD 1 47 | #define SOFT 2 48 | 49 | #if defined(OS_MSWIN) || defined(OS_BCCWIN) 50 | #define SPACE SPACEPARITY 51 | #define MARK MARKPARITY 52 | #define EVEN EVENPARITY 53 | #define ODD ODDPARITY 54 | #else 55 | #define SPACE 0 56 | #define MARK 0 57 | #define EVEN 1 58 | #define ODD 2 59 | #endif 60 | 61 | static VALUE sBaud, sDataBits, sStopBits, sParity; /* strings */ 62 | static VALUE sRts, sDtr, sCts, sDsr, sDcd, sRi; 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | = Ruby/SerialPort 2 | 3 | == Description 4 | 5 | Ruby/SerialPort is a Ruby library that provides a class for using 6 | RS-232 serial ports. This class also contains low-level functions to 7 | check and set the current state of the signals on the line. 8 | 9 | It support POSIX (Linux, *BSD, Solaris, AIX, Mac OS X), Cygwin and native Windows. 10 | The native Windows version of this library supports Microsoft's Visual C++ 11 | and Borland's C++ compilers. 12 | 13 | == Installation 14 | 15 | $ gem install ruby-serialport 16 | 17 | Any files and older versions can be found at http://rubyforge.org/projects/ruby-serialport/ 18 | 19 | == Examples 20 | 21 | reuire 'rubygems' 22 | require 'serialport' 23 | sp = SerialPort.new "/dev/my-modem", 9600 24 | sp.write "AT\r\n" 25 | puts sp.read # hopefully "OK" ;-) 26 | 27 | A functional example can be found in examples/miniterm.rb -- Ruby's copy of miniterm.c 28 | 29 | For a compeate API reference see the RDoc of SerialPort. 30 | 31 | == License and Copyright 32 | 33 | Copyright (C) 2008 Jonas Bähr 34 | (C) 2008 Daniel E. Shipton 35 | (C) 2003 Alan Stern 36 | (C) 2002 Guillaume Pierronnet 37 | 38 | This program is free software; you can redistribute it and/or 39 | modify it under the terms of the GNU General Public License 40 | as published by the Free Software Foundation; either version 2 41 | of the License, or (at your option) any later version. 42 | 43 | This program is distributed in the hope that it will be useful, 44 | but WITHOUT ANY WARRANTY; without even the implied warranty of 45 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 46 | GNU General Public License for more details. 47 | 48 | You should have received a copy of the GNU General Public License 49 | along with this program; if not, write to the Free Software 50 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 51 | 52 | -------------------------------------------------------------------------------- /ext/serialport.c: -------------------------------------------------------------------------------- 1 | /* Ruby/SerialPort $Id$ 2 | * Guillaume Pierronnet 3 | * Alan Stern 4 | * Daniel E. Shipton 5 | * Jonas Bähr 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 | /* include only the implementation we need */ 23 | #if defined(OS_MSWIN) || defined(OS_BCCWIN) 24 | #include "impl/win_serialport.c" 25 | #else 26 | #include "impl/posix_serialport.c" 27 | #endif /* defined(OS_MSWIN) || defined(OS_BCCWIN) */ 28 | 29 | VALUE cSerialPort; /* serial port class */ 30 | 31 | /* 32 | * :nodoc: This method is privat and will be called by SerialPort#new or SerialPort#open. 33 | */ 34 | static VALUE sp_create(class, _port) 35 | VALUE class, _port; 36 | { 37 | return sp_create_impl(class, _port); 38 | } 39 | 40 | /* 41 | * Configure the serial port. You can pass a hash or multiple values 42 | * as separate arguments. Invalid or unsupported values will raise 43 | * an ArgumentError. 44 | * 45 | * When using a hash the following keys are recognized: 46 | * ["baud"] Integer from 50 to 256000, depends on platform 47 | * ["data_bits"] Integer from 5 to 8 (4 is allowed on Windows too) 48 | * ["stop_bits"] An integer, only allowed values are 1 or 2 (1.5 is not supported) 49 | * ["parity"] One of the constants NONE, EVEN or ODD (Windows allows also MARK and SPACE) 50 | * 51 | * When using separate arguments, they are interpreted as: 52 | * (baud, data_bits = 8, stop_bits = 1, parity = (previous_databits==8 ? NONE : EVEN)) 53 | * 54 | * Nota: A baudrate of nil will keep the old value. The default parity depends on the 55 | * number of databits configured before this function call. 56 | */ 57 | static VALUE sp_set_modem_params(argc, argv, self) 58 | int argc; 59 | VALUE *argv, self; 60 | { 61 | return sp_set_modem_params_impl(argc, argv, self); 62 | } 63 | 64 | /* 65 | * Send a break for the given time. 66 | * 67 | * time is an integer of tenths-of-a-second for the break. 68 | * 69 | * Note: Under Posix, this value is very approximate. 70 | */ 71 | static VALUE sp_break(self, time) 72 | VALUE self, time; 73 | { 74 | return sp_break_impl(self, time); 75 | } 76 | 77 | /* 78 | * Get the state (0 or 1) of the DTR line (not available on Windows) 79 | */ 80 | static VALUE sp_get_dtr(self) 81 | VALUE self; 82 | { 83 | return sp_get_dtr_impl(self); 84 | } 85 | 86 | /* 87 | * Get the flow control. The result is either NONE, HARD, SOFT or (HARD | SOFT) 88 | */ 89 | static VALUE sp_get_flow_control(self) 90 | VALUE self; 91 | { 92 | return sp_get_flow_control_impl(self); 93 | } 94 | 95 | /* 96 | * Get the timeout value (in milliseconds) for reading. 97 | * See SerialPort#set_read_timeout for details. 98 | */ 99 | static VALUE sp_get_read_timeout(self) 100 | VALUE self; 101 | { 102 | return sp_get_read_timeout_impl(self); 103 | } 104 | 105 | /* 106 | * Get the state (0 or 1) of the RTS line (not available on Windows) 107 | */ 108 | static VALUE sp_get_rts(self) 109 | VALUE self; 110 | { 111 | return sp_get_rts_impl(self); 112 | } 113 | 114 | /* 115 | * Get the write timeout (in milliseconds) 116 | * 117 | * Note: Under Posix, write timeouts are not implemented. 118 | */ 119 | static VALUE sp_get_write_timeout(self) 120 | VALUE self; 121 | { 122 | return sp_get_write_timeout_impl(self); 123 | } 124 | 125 | /* 126 | * Set the state (0 or 1) of the DTR line 127 | */ 128 | static VALUE sp_set_dtr(self, val) 129 | { 130 | return sp_set_dtr_impl(self, val); 131 | } 132 | 133 | /* 134 | * Set the flow control to either NONE, HARD, SOFT or (HARD | SOFT) 135 | * 136 | * Note: SerialPort::HARD mode is not supported on all platforms. 137 | * SerialPort::HARD uses RTS/CTS handshaking; DSR/DTR is not 138 | * supported. 139 | */ 140 | static VALUE sp_set_flow_control(self, val) 141 | { 142 | return sp_set_flow_control_impl(self, val); 143 | } 144 | 145 | /* 146 | * Set the timeout value (in milliseconds) for reading. 147 | * A negative read timeout will return all the available data without 148 | * waiting, a zero read timeout will not return until at least one 149 | * byte is available, and a positive read timeout returns when the 150 | * requested number of bytes is available or the interval between the 151 | * arrival of two bytes exceeds the timeout value. 152 | * 153 | * Note: Read timeouts don't mix well with multi-threading. 154 | */ 155 | static VALUE sp_set_read_timeout(self, val) 156 | { 157 | return sp_set_read_timeout_impl(self, val); 158 | } 159 | 160 | /* 161 | * Set the state (0 or 1) of the RTS line 162 | */ 163 | static VALUE sp_set_rts(self, val) 164 | { 165 | return sp_set_rts_impl(self, val); 166 | } 167 | 168 | /* 169 | * Set a write timeout (in milliseconds) 170 | * 171 | * Note: Under Posix, write timeouts are not implemented. 172 | */ 173 | static VALUE sp_set_write_timeout(self, val) 174 | { 175 | return sp_set_write_timeout_impl(self, val); 176 | } 177 | 178 | static void get_modem_params(self, mp) 179 | VALUE self; 180 | struct modem_params *mp; 181 | { 182 | get_modem_params_impl(self, mp); 183 | } 184 | 185 | /* 186 | * Set the baud rate, see SerialPort#set_modem_params for details. 187 | */ 188 | static VALUE sp_set_data_rate(self, data_rate) 189 | VALUE self, data_rate; 190 | { 191 | VALUE argv[4]; 192 | 193 | argv[0] = data_rate; 194 | argv[1] = argv[2] = argv[3] = Qnil; 195 | sp_set_modem_params(4, argv, self); 196 | 197 | return data_rate; 198 | } 199 | 200 | /* 201 | * Set the data bits, see SerialPort#set_modem_params for details. 202 | */ 203 | static VALUE sp_set_data_bits(self, data_bits) 204 | VALUE self, data_bits; 205 | { 206 | VALUE argv[4]; 207 | 208 | argv[1] = data_bits; 209 | argv[0] = argv[2] = argv[3] = Qnil; 210 | sp_set_modem_params(4, argv, self); 211 | 212 | return data_bits; 213 | } 214 | 215 | /* 216 | * Set the stop bits, see SerialPort#set_modem_params for details. 217 | */ 218 | static VALUE sp_set_stop_bits(self, stop_bits) 219 | VALUE self, stop_bits; 220 | { 221 | VALUE argv[4]; 222 | 223 | argv[2] = stop_bits; 224 | argv[0] = argv[1] = argv[3] = Qnil; 225 | sp_set_modem_params(4, argv, self); 226 | 227 | return stop_bits; 228 | } 229 | 230 | /* 231 | * Set the parity, see SerialPort#set_modem_params for details. 232 | */ 233 | static VALUE sp_set_parity(self, parity) 234 | VALUE self, parity; 235 | { 236 | VALUE argv[4]; 237 | 238 | argv[3] = parity; 239 | argv[0] = argv[1] = argv[2] = Qnil; 240 | sp_set_modem_params(4, argv, self); 241 | 242 | return parity; 243 | } 244 | 245 | /* 246 | * Get the current baud rate, see SerialPort#get_modem_params for details. 247 | */ 248 | static VALUE sp_get_data_rate(self) 249 | VALUE self; 250 | { 251 | struct modem_params mp; 252 | 253 | get_modem_params(self, &mp); 254 | 255 | return INT2FIX(mp.data_rate); 256 | } 257 | 258 | /* 259 | * Get the current data bits, see SerialPort#get_modem_params for details. 260 | */ 261 | static VALUE sp_get_data_bits(self) 262 | VALUE self; 263 | { 264 | struct modem_params mp; 265 | 266 | get_modem_params(self, &mp); 267 | 268 | return INT2FIX(mp.data_bits); 269 | } 270 | 271 | /* 272 | * Get the current stop bits, see SerialPort#get_modem_params for details. 273 | */ 274 | static VALUE sp_get_stop_bits(self) 275 | VALUE self; 276 | { 277 | struct modem_params mp; 278 | 279 | get_modem_params(self, &mp); 280 | 281 | return INT2FIX(mp.stop_bits); 282 | } 283 | 284 | /* 285 | * Get the current parity, see SerialPort#get_modem_params for details. 286 | */ 287 | static VALUE sp_get_parity(self) 288 | VALUE self; 289 | { 290 | struct modem_params mp; 291 | 292 | get_modem_params(self, &mp); 293 | 294 | return INT2FIX(mp.parity); 295 | } 296 | 297 | 298 | /* 299 | * Get the configure of the serial port. 300 | * 301 | * Returned is a hash with the following keys: 302 | * ["baud"] Integer with the baud rate 303 | * ["data_bits"] Integer from 5 to 8 (4 is possible on Windows too) 304 | * ["stop_bits"] Integer, 1 or 2 (1.5 is not supported) 305 | * ["parity"] One of the constants NONE, EVEN or ODD (on Windows may also MARK or SPACE) 306 | */ 307 | static VALUE sp_get_modem_params(self) 308 | VALUE self; 309 | { 310 | struct modem_params mp; 311 | VALUE hash; 312 | 313 | get_modem_params(self, &mp); 314 | 315 | hash = rb_hash_new(); 316 | 317 | rb_hash_aset(hash, sBaud, INT2FIX(mp.data_rate)); 318 | rb_hash_aset(hash, sDataBits, INT2FIX(mp.data_bits)); 319 | rb_hash_aset(hash, sStopBits, INT2FIX(mp.stop_bits)); 320 | rb_hash_aset(hash, sParity, INT2FIX(mp.parity)); 321 | 322 | return hash; 323 | } 324 | 325 | /* 326 | * Get the state (0 or 1) of the CTS line 327 | */ 328 | static VALUE sp_get_cts(self) 329 | VALUE self; 330 | { 331 | struct line_signals ls; 332 | 333 | get_line_signals_helper(self, &ls); 334 | 335 | return INT2FIX(ls.cts); 336 | } 337 | 338 | /* 339 | * Get the state (0 or 1) of the DSR line 340 | */ 341 | static VALUE sp_get_dsr(self) 342 | VALUE self; 343 | { 344 | struct line_signals ls; 345 | 346 | get_line_signals_helper(self, &ls); 347 | 348 | return INT2FIX(ls.dsr); 349 | } 350 | 351 | /* 352 | * Get the state (0 or 1) of the DCD line 353 | */ 354 | static VALUE sp_get_dcd(self) 355 | VALUE self; 356 | { 357 | struct line_signals ls; 358 | 359 | get_line_signals_helper(self, &ls); 360 | 361 | return INT2FIX(ls.dcd); 362 | } 363 | 364 | /* 365 | * Get the state (0 or 1) of the RI line 366 | */ 367 | static VALUE sp_get_ri(self) 368 | VALUE self; 369 | { 370 | struct line_signals ls; 371 | 372 | get_line_signals_helper(self, &ls); 373 | 374 | return INT2FIX(ls.ri); 375 | } 376 | 377 | /* 378 | * Return a hash with the state of each line status bit. Keys are 379 | * "rts", "dtr", "cts", "dsr", "dcd", and "ri". 380 | * 381 | * Note: Under Windows, the rts and dtr values are not included. 382 | */ 383 | static VALUE sp_signals(self) 384 | VALUE self; 385 | { 386 | struct line_signals ls; 387 | VALUE hash; 388 | 389 | get_line_signals_helper(self, &ls); 390 | 391 | hash = rb_hash_new(); 392 | 393 | #if !(defined(OS_MSWIN) || defined(OS_BCCWIN)) 394 | rb_hash_aset(hash, sRts, INT2FIX(ls.rts)); 395 | rb_hash_aset(hash, sDtr, INT2FIX(ls.dtr)); 396 | #endif 397 | rb_hash_aset(hash, sCts, INT2FIX(ls.cts)); 398 | rb_hash_aset(hash, sDsr, INT2FIX(ls.dsr)); 399 | rb_hash_aset(hash, sDcd, INT2FIX(ls.dcd)); 400 | rb_hash_aset(hash, sRi, INT2FIX(ls.ri)); 401 | 402 | return hash; 403 | } 404 | 405 | /* 406 | * This class is used for communication over a serial port. 407 | * In addition to the methods here, you can use everything 408 | * Ruby's IO-class provides (read, write, getc, readlines, ...) 409 | */ 410 | void Init_serialport() 411 | { 412 | sBaud = rb_str_new2("baud"); 413 | sDataBits = rb_str_new2("data_bits"); 414 | sStopBits = rb_str_new2("stop_bits"); 415 | sParity = rb_str_new2("parity"); 416 | sRts = rb_str_new2("rts"); 417 | sDtr = rb_str_new2("dtr"); 418 | sCts = rb_str_new2("cts"); 419 | sDsr = rb_str_new2("dsr"); 420 | sDcd = rb_str_new2("dcd"); 421 | sRi = rb_str_new2("ri"); 422 | 423 | rb_gc_register_address(&sBaud); 424 | rb_gc_register_address(&sDataBits); 425 | rb_gc_register_address(&sStopBits); 426 | rb_gc_register_address(&sParity); 427 | rb_gc_register_address(&sRts); 428 | rb_gc_register_address(&sDtr); 429 | rb_gc_register_address(&sCts); 430 | rb_gc_register_address(&sDsr); 431 | rb_gc_register_address(&sDcd); 432 | rb_gc_register_address(&sRi); 433 | 434 | cSerialPort = rb_define_class("SerialPort", rb_cIO); 435 | rb_define_singleton_method(cSerialPort, "create", sp_create, 1); 436 | 437 | rb_define_method(cSerialPort, "get_modem_params", sp_get_modem_params, 0); 438 | rb_define_method(cSerialPort, "set_modem_params", sp_set_modem_params, -1); 439 | rb_define_method(cSerialPort, "modem_params", sp_get_modem_params, 0); 440 | rb_define_method(cSerialPort, "modem_params=", sp_set_modem_params, -1); 441 | rb_define_method(cSerialPort, "baud", sp_get_data_rate, 0); 442 | rb_define_method(cSerialPort, "baud=", sp_set_data_rate, 1); 443 | rb_define_method(cSerialPort, "data_bits", sp_get_data_bits, 0); 444 | rb_define_method(cSerialPort, "data_bits=", sp_set_data_bits, 1); 445 | rb_define_method(cSerialPort, "stop_bits", sp_get_stop_bits, 0); 446 | rb_define_method(cSerialPort, "stop_bits=", sp_set_stop_bits, 1); 447 | rb_define_method(cSerialPort, "parity", sp_get_parity, 0); 448 | rb_define_method(cSerialPort, "parity=", sp_set_parity, 1); 449 | 450 | rb_define_method(cSerialPort, "flow_control=", sp_set_flow_control, 1); 451 | rb_define_method(cSerialPort, "flow_control", sp_get_flow_control, 0); 452 | 453 | rb_define_method(cSerialPort, "read_timeout", sp_get_read_timeout, 0); 454 | rb_define_method(cSerialPort, "read_timeout=", sp_set_read_timeout, 1); 455 | rb_define_method(cSerialPort, "write_timeout", sp_get_write_timeout, 0); 456 | rb_define_method(cSerialPort, "write_timeout=", sp_set_write_timeout, 1); 457 | 458 | rb_define_method(cSerialPort, "break", sp_break, 1); 459 | 460 | rb_define_method(cSerialPort, "signals", sp_signals, 0); 461 | rb_define_method(cSerialPort, "get_signals", sp_signals, 0); 462 | rb_define_method(cSerialPort, "rts", sp_get_rts, 0); 463 | rb_define_method(cSerialPort, "rts=", sp_set_rts, 1); 464 | rb_define_method(cSerialPort, "dtr", sp_get_dtr, 0); 465 | rb_define_method(cSerialPort, "dtr=", sp_set_dtr, 1); 466 | rb_define_method(cSerialPort, "cts", sp_get_cts, 0); 467 | rb_define_method(cSerialPort, "dsr", sp_get_dsr, 0); 468 | rb_define_method(cSerialPort, "dcd", sp_get_dcd, 0); 469 | rb_define_method(cSerialPort, "ri", sp_get_ri, 0); 470 | 471 | rb_define_const(cSerialPort, "NONE", INT2FIX(NONE)); 472 | rb_define_const(cSerialPort, "HARD", INT2FIX(HARD)); 473 | rb_define_const(cSerialPort, "SOFT", INT2FIX(SOFT)); 474 | 475 | rb_define_const(cSerialPort, "SPACE", INT2FIX(SPACE)); 476 | rb_define_const(cSerialPort, "MARK", INT2FIX(MARK)); 477 | rb_define_const(cSerialPort, "EVEN", INT2FIX(EVEN)); 478 | rb_define_const(cSerialPort, "ODD", INT2FIX(ODD)); 479 | 480 | /* the package's version as a string "X.Y.Z", beeing major, minor and patch level */ 481 | rb_define_const(cSerialPort, "VERSION", rb_str_new2(RUBY_SERIAL_PORT_VERSION)); 482 | } 483 | -------------------------------------------------------------------------------- /ext/impl/win_serialport.c: -------------------------------------------------------------------------------- 1 | /* Ruby/SerialPort $Id$ 2 | * Guillaume Pierronnet 3 | * Alan Stern 4 | * Daniel E. Shipton 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 /* Standard input/output definitions */ 20 | #include /* Low-level I/O definitions */ 21 | #include /* File control definitions */ 22 | #include /* 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 | 612 | -------------------------------------------------------------------------------- /ext/impl/posix_serialport.c: -------------------------------------------------------------------------------- 1 | /* Ruby/SerialPort $Id$ 2 | * Guillaume Pierronnet 3 | * Alan Stern 4 | * Daniel E. Shipton 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 /* Standard input/output definitions */ 20 | #include /* UNIX standard function definitions */ 21 | #include /* File control definitions */ 22 | #include /* Error number definitions */ 23 | #include /* POSIX terminal control definitions */ 24 | #include 25 | 26 | #ifdef CRTSCTS 27 | #define HAVE_FLOWCONTROL_HARD 1 28 | #else 29 | #undef HAVE_FLOWCONTROL_HARD 30 | #endif 31 | 32 | 33 | static char sTcgetattr[] = "tcgetattr"; 34 | static char sTcsetattr[] = "tcsetattr"; 35 | static char sIoctl[] = "ioctl"; 36 | 37 | 38 | 39 | static int get_fd_helper(obj) 40 | VALUE obj; 41 | { 42 | rb_io_t *fptr; 43 | 44 | GetOpenFile(obj, fptr); 45 | return (fptr->fd); 46 | } 47 | 48 | static VALUE sp_create_impl(class, _port) 49 | VALUE class, _port; 50 | { 51 | rb_io_t *fp; 52 | int fd; 53 | int num_port; 54 | char *port; 55 | char *ports[] = { 56 | #if defined(OS_LINUX) || defined(OS_CYGWIN) 57 | "/dev/ttyS0", "/dev/ttyS1", "/dev/ttyS2", "/dev/ttyS3", 58 | "/dev/ttyS4", "/dev/ttyS5", "/dev/ttyS6", "/dev/ttyS7" 59 | #elif defined(OS_FREEBSD) || defined(OS_NETBSD) || defined(OS_OPENBSD) || defined(OS_DARWIN) 60 | "/dev/cuaa0", "/dev/cuaa1", "/dev/cuaa2", "/dev/cuaa3", 61 | "/dev/cuaa4", "/dev/cuaa5", "/dev/cuaa6", "/dev/cuaa7" 62 | #elif defined(OS_SOLARIS) 63 | "/dev/ttya", "/dev/ttyb", "/dev/ttyc", "/dev/ttyd", 64 | "/dev/ttye", "/dev/ttyf", "/dev/ttyg", "/dev/ttyh" 65 | #elif defined(OS_AIX) 66 | "/dev/tty0", "/dev/tty1", "/dev/tty2", "/dev/tty3", 67 | "/dev/tty4", "/dev/tty5", "/dev/tty6", "/dev/tty7" 68 | #elif defined(OS_IRIX) 69 | "/dev/ttyf1", "/dev/ttyf2", "/dev/ttyf3", "/dev/ttyf4", 70 | "/dev/ttyf5", "/dev/ttyf6", "/dev/ttyf7", "/dev/ttyf8" 71 | #endif 72 | }; 73 | struct termios params; 74 | 75 | NEWOBJ(sp, struct RFile); 76 | rb_secure(4); 77 | OBJSETUP(sp, class, T_FILE); 78 | MakeOpenFile((VALUE) sp, fp); 79 | switch(TYPE(_port)) 80 | { 81 | case T_FIXNUM: 82 | num_port = FIX2INT(_port); 83 | if (num_port < 0 || num_port > sizeof(ports) / sizeof(ports[0])) 84 | { 85 | rb_raise(rb_eArgError, "illegal port number"); 86 | } 87 | port = ports[num_port]; 88 | break; 89 | 90 | case T_STRING: 91 | Check_SafeStr(_port); 92 | port = RSTRING_PTR(_port); 93 | break; 94 | 95 | default: 96 | rb_raise(rb_eTypeError, "wrong argument type"); 97 | break; 98 | } 99 | 100 | fd = open(port, O_RDWR | O_NOCTTY | O_NDELAY); 101 | if (fd == -1) 102 | { 103 | rb_sys_fail(port); 104 | } 105 | 106 | if (!isatty(fd)) 107 | { 108 | close(fd); 109 | rb_raise(rb_eArgError, "not a serial port"); 110 | } 111 | 112 | /* enable blocking read */ 113 | fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK); 114 | 115 | if (tcgetattr(fd, ¶ms) == -1) 116 | { 117 | close(fd); 118 | rb_sys_fail(sTcgetattr); 119 | } 120 | 121 | params.c_oflag = 0; 122 | params.c_lflag = 0; 123 | params.c_iflag &= (IXON | IXOFF | IXANY); 124 | params.c_cflag |= CLOCAL | CREAD; 125 | params.c_cflag &= ~HUPCL; 126 | 127 | if (tcsetattr(fd, TCSANOW, ¶ms) == -1) 128 | { 129 | close(fd); 130 | rb_sys_fail(sTcsetattr); 131 | } 132 | 133 | fp->fd = fd; 134 | fp->mode = FMODE_READWRITE | FMODE_SYNC; 135 | 136 | return (VALUE) sp; 137 | } 138 | 139 | static VALUE sp_set_modem_params_impl(argc, argv, self) 140 | int argc; 141 | VALUE *argv, self; 142 | { 143 | int fd; 144 | struct termios params; 145 | VALUE _data_rate, _data_bits, _parity, _stop_bits; 146 | int use_hash = 0; 147 | int data_rate, data_bits; 148 | _data_rate = _data_bits = _parity = _stop_bits = Qnil; 149 | 150 | if (argc == 0) 151 | { 152 | return self; 153 | } 154 | 155 | if (argc == 1 && T_HASH == TYPE(argv[0])) 156 | { 157 | use_hash = 1; 158 | _data_rate = rb_hash_aref(argv[0], sBaud); 159 | _data_bits = rb_hash_aref(argv[0], sDataBits); 160 | _stop_bits = rb_hash_aref(argv[0], sStopBits); 161 | _parity = rb_hash_aref(argv[0], sParity); 162 | } 163 | 164 | fd = get_fd_helper(self); 165 | if (tcgetattr(fd, ¶ms) == -1) 166 | { 167 | rb_sys_fail(sTcgetattr); 168 | } 169 | 170 | if (!use_hash) 171 | { 172 | _data_rate = argv[0]; 173 | } 174 | 175 | if (NIL_P(_data_rate)) 176 | { 177 | goto SkipDataRate; 178 | } 179 | Check_Type(_data_rate, T_FIXNUM); 180 | 181 | switch(FIX2INT(_data_rate)) 182 | { 183 | case 50: data_rate = B50; break; 184 | case 75: data_rate = B75; break; 185 | case 110: data_rate = B110; break; 186 | case 134: data_rate = B134; break; 187 | case 150: data_rate = B150; break; 188 | case 200: data_rate = B200; break; 189 | case 300: data_rate = B300; break; 190 | case 600: data_rate = B600; break; 191 | case 1200: data_rate = B1200; break; 192 | case 1800: data_rate = B1800; break; 193 | case 2400: data_rate = B2400; break; 194 | case 4800: data_rate = B4800; break; 195 | case 9600: data_rate = B9600; break; 196 | case 19200: data_rate = B19200; break; 197 | case 38400: data_rate = B38400; break; 198 | #ifdef B57600 199 | case 57600: data_rate = B57600; break; 200 | #endif 201 | #ifdef B76800 202 | case 76800: data_rate = B76800; break; 203 | #endif 204 | #ifdef B115200 205 | case 115200: data_rate = B115200; break; 206 | #endif 207 | #ifdef B230400 208 | case 230400: data_rate = B230400; break; 209 | #endif 210 | 211 | default: 212 | rb_raise(rb_eArgError, "unknown baud rate"); 213 | break; 214 | } 215 | cfsetispeed(¶ms, data_rate); 216 | cfsetospeed(¶ms, data_rate); 217 | 218 | SkipDataRate: 219 | 220 | if (!use_hash) 221 | { 222 | _data_bits = (argc >= 2 ? argv[1] : INT2FIX(8)); 223 | } 224 | 225 | if (NIL_P(_data_bits)) 226 | { 227 | goto SkipDataBits; 228 | } 229 | Check_Type(_data_bits, T_FIXNUM); 230 | 231 | switch(FIX2INT(_data_bits)) 232 | { 233 | case 5: 234 | data_bits = CS5; 235 | break; 236 | case 6: 237 | data_bits = CS6; 238 | break; 239 | case 7: 240 | data_bits = CS7; 241 | break; 242 | case 8: 243 | data_bits = CS8; 244 | break; 245 | default: 246 | rb_raise(rb_eArgError, "unknown character size"); 247 | break; 248 | } 249 | params.c_cflag &= ~CSIZE; 250 | params.c_cflag |= data_bits; 251 | 252 | SkipDataBits: 253 | 254 | if (!use_hash) 255 | { 256 | _stop_bits = (argc >= 3 ? argv[2] : INT2FIX(1)); 257 | } 258 | 259 | if (NIL_P(_stop_bits)) 260 | { 261 | goto SkipStopBits; 262 | } 263 | 264 | Check_Type(_stop_bits, T_FIXNUM); 265 | 266 | switch(FIX2INT(_stop_bits)) 267 | { 268 | case 1: 269 | params.c_cflag &= ~CSTOPB; 270 | break; 271 | case 2: 272 | params.c_cflag |= CSTOPB; 273 | break; 274 | default: 275 | rb_raise(rb_eArgError, "unknown number of stop bits"); 276 | break; 277 | } 278 | 279 | SkipStopBits: 280 | 281 | if (!use_hash) 282 | { 283 | _parity = (argc >= 4 ? argv[3] : ((params.c_cflag & CSIZE) == CS8 ? 284 | INT2FIX(NONE) : INT2FIX(EVEN))); 285 | } 286 | 287 | if (NIL_P(_parity)) 288 | { 289 | goto SkipParity; 290 | } 291 | 292 | Check_Type(_parity, T_FIXNUM); 293 | 294 | switch(FIX2INT(_parity)) 295 | { 296 | case EVEN: 297 | params.c_cflag |= PARENB; 298 | params.c_cflag &= ~PARODD; 299 | break; 300 | 301 | case ODD: 302 | params.c_cflag |= PARENB; 303 | params.c_cflag |= PARODD; 304 | break; 305 | 306 | case NONE: 307 | params.c_cflag &= ~PARENB; 308 | break; 309 | 310 | default: 311 | rb_raise(rb_eArgError, "unknown parity"); 312 | break; 313 | } 314 | 315 | SkipParity: 316 | if (tcsetattr(fd, TCSANOW, ¶ms) == -1) 317 | { 318 | rb_sys_fail(sTcsetattr); 319 | } 320 | return argv[0]; 321 | } 322 | 323 | static void get_modem_params_impl(self, mp) 324 | VALUE self; 325 | struct modem_params *mp; 326 | { 327 | int fd; 328 | struct termios params; 329 | 330 | fd = get_fd_helper(self); 331 | if (tcgetattr(fd, ¶ms) == -1) 332 | { 333 | rb_sys_fail(sTcgetattr); 334 | } 335 | 336 | switch (cfgetospeed(¶ms)) 337 | { 338 | case B50: mp->data_rate = 50; break; 339 | case B75: mp->data_rate = 75; break; 340 | case B110: mp->data_rate = 110; break; 341 | case B134: mp->data_rate = 134; break; 342 | case B150: mp->data_rate = 150; break; 343 | case B200: mp->data_rate = 200; break; 344 | case B300: mp->data_rate = 300; break; 345 | case B600: mp->data_rate = 600; break; 346 | case B1200: mp->data_rate = 1200; break; 347 | case B1800: mp->data_rate = 1800; break; 348 | case B2400: mp->data_rate = 2400; break; 349 | case B4800: mp->data_rate = 4800; break; 350 | case B9600: mp->data_rate = 9600; break; 351 | case B19200: mp->data_rate = 19200; break; 352 | case B38400: mp->data_rate = 38400; break; 353 | #ifdef B57600 354 | case B57600: mp->data_rate = 57600; break; 355 | #endif 356 | #ifdef B76800 357 | case B76800: mp->data_rate = 76800; break; 358 | #endif 359 | #ifdef B115200 360 | case B115200: mp->data_rate = 115200; break; 361 | #endif 362 | #ifdef B230400 363 | case B230400: mp->data_rate = 230400; break; 364 | #endif 365 | } 366 | 367 | switch(params.c_cflag & CSIZE) 368 | { 369 | case CS5: 370 | mp->data_bits = 5; 371 | break; 372 | case CS6: 373 | mp->data_bits = 6; 374 | break; 375 | case CS7: 376 | mp->data_bits = 7; 377 | break; 378 | case CS8: 379 | mp->data_bits = 8; 380 | break; 381 | default: 382 | mp->data_bits = 0; 383 | break; 384 | } 385 | 386 | mp->stop_bits = (params.c_cflag & CSTOPB ? 2 : 1); 387 | 388 | if (!(params.c_cflag & PARENB)) 389 | { 390 | mp->parity = NONE; 391 | } 392 | else if (params.c_cflag & PARODD) 393 | { 394 | mp->parity = ODD; 395 | } 396 | else 397 | { 398 | mp->parity = EVEN; 399 | } 400 | } 401 | 402 | static VALUE sp_set_flow_control_impl(self, val) 403 | VALUE self, val; 404 | { 405 | int fd; 406 | int flowc; 407 | struct termios params; 408 | 409 | Check_Type(val, T_FIXNUM); 410 | 411 | fd = get_fd_helper(self); 412 | if (tcgetattr(fd, ¶ms) == -1) 413 | { 414 | rb_sys_fail(sTcgetattr); 415 | } 416 | 417 | flowc = FIX2INT(val); 418 | if (flowc & HARD) 419 | { 420 | #ifdef HAVE_FLOWCONTROL_HARD 421 | params.c_cflag |= CRTSCTS; 422 | } 423 | else 424 | { 425 | params.c_cflag &= ~CRTSCTS; 426 | } 427 | #else 428 | rb_raise(rb_eIOError, "Hardware flow control not supported"); 429 | } 430 | #endif 431 | 432 | if (flowc & SOFT) 433 | { 434 | params.c_iflag |= (IXON | IXOFF | IXANY); 435 | } 436 | else 437 | { 438 | params.c_iflag &= ~(IXON | IXOFF | IXANY); 439 | } 440 | 441 | if (tcsetattr(fd, TCSANOW, ¶ms) == -1) 442 | { 443 | rb_sys_fail(sTcsetattr); 444 | } 445 | 446 | return val; 447 | } 448 | 449 | static VALUE sp_get_flow_control_impl(self) 450 | VALUE self; 451 | { 452 | int ret; 453 | int fd; 454 | struct termios params; 455 | 456 | fd = get_fd_helper(self); 457 | if (tcgetattr(fd, ¶ms) == -1) 458 | { 459 | rb_sys_fail(sTcgetattr); 460 | } 461 | 462 | ret = 0; 463 | 464 | #ifdef HAVE_FLOWCONTROL_HARD 465 | if (params.c_cflag & CRTSCTS) 466 | { 467 | ret += HARD; 468 | } 469 | #endif 470 | 471 | if (params.c_iflag & (IXON | IXOFF | IXANY)) 472 | { 473 | ret += SOFT; 474 | } 475 | 476 | return INT2FIX(ret); 477 | } 478 | 479 | static VALUE sp_set_read_timeout_impl(self, val) 480 | VALUE self, val; 481 | { 482 | int timeout; 483 | int fd; 484 | struct termios params; 485 | 486 | Check_Type(val, T_FIXNUM); 487 | timeout = FIX2INT(val); 488 | 489 | fd = get_fd_helper(self); 490 | if (tcgetattr(fd, ¶ms) == -1) 491 | { 492 | rb_sys_fail(sTcgetattr); 493 | } 494 | 495 | if (timeout < 0) 496 | { 497 | params.c_cc[VTIME] = 0; 498 | params.c_cc[VMIN] = 0; 499 | } 500 | else if (timeout == 0) 501 | { 502 | params.c_cc[VTIME] = 0; 503 | params.c_cc[VMIN] = 1; 504 | } 505 | else 506 | { 507 | params.c_cc[VTIME] = (timeout + 50) / 100; 508 | params.c_cc[VMIN] = 0; 509 | } 510 | 511 | if (tcsetattr(fd, TCSANOW, ¶ms) == -1) 512 | { 513 | rb_sys_fail(sTcsetattr); 514 | } 515 | 516 | return val; 517 | } 518 | 519 | static VALUE sp_get_read_timeout_impl(self) 520 | VALUE self; 521 | { 522 | int fd; 523 | struct termios params; 524 | 525 | fd = get_fd_helper(self); 526 | if (tcgetattr(fd, ¶ms) == -1) 527 | { 528 | rb_sys_fail(sTcgetattr); 529 | } 530 | 531 | if (params.c_cc[VTIME] == 0 && params.c_cc[VMIN] == 0) 532 | { 533 | return INT2FIX(-1); 534 | } 535 | 536 | return INT2FIX(params.c_cc[VTIME] * 100); 537 | } 538 | 539 | static VALUE sp_set_write_timeout_impl(self, val) 540 | VALUE self, val; 541 | { 542 | rb_notimplement(); 543 | return self; 544 | } 545 | 546 | static VALUE sp_get_write_timeout_impl(self) 547 | VALUE self; 548 | { 549 | rb_notimplement(); 550 | return self; 551 | } 552 | 553 | static VALUE sp_break_impl(self, time) 554 | VALUE self, time; 555 | { 556 | int fd; 557 | 558 | Check_Type(time, T_FIXNUM); 559 | 560 | fd = get_fd_helper(self); 561 | 562 | if (tcsendbreak(fd, FIX2INT(time) / 3) == -1) 563 | { 564 | rb_sys_fail("tcsendbreak"); 565 | } 566 | 567 | return Qnil; 568 | } 569 | 570 | static void get_line_signals_helper(obj, ls) 571 | VALUE obj; 572 | struct line_signals *ls; 573 | { 574 | int fd, status; 575 | 576 | fd = get_fd_helper(obj); 577 | 578 | if (ioctl(fd, TIOCMGET, &status) == -1) 579 | { 580 | rb_sys_fail(sIoctl); 581 | } 582 | 583 | ls->rts = (status & TIOCM_RTS ? 1 : 0); 584 | ls->dtr = (status & TIOCM_DTR ? 1 : 0); 585 | ls->cts = (status & TIOCM_CTS ? 1 : 0); 586 | ls->dsr = (status & TIOCM_DSR ? 1 : 0); 587 | ls->dcd = (status & TIOCM_CD ? 1 : 0); 588 | ls->ri = (status & TIOCM_RI ? 1 : 0); 589 | } 590 | 591 | static VALUE set_signal_impl(obj, val, sig) 592 | VALUE obj,val; 593 | int sig; 594 | { 595 | int status; 596 | int fd; 597 | int set; 598 | 599 | Check_Type(val, T_FIXNUM); 600 | fd = get_fd_helper(obj); 601 | 602 | if (ioctl(fd, TIOCMGET, &status) == -1) 603 | { 604 | rb_sys_fail(sIoctl); 605 | } 606 | 607 | set = FIX2INT(val); 608 | 609 | if (set == 0) 610 | { 611 | status &= ~sig; 612 | } 613 | else if (set == 1) 614 | { 615 | status |= sig; 616 | } 617 | else 618 | { 619 | rb_raise(rb_eArgError, "invalid value"); 620 | } 621 | 622 | if (ioctl(fd, TIOCMSET, &status) == -1) 623 | { 624 | rb_sys_fail(sIoctl); 625 | } 626 | 627 | return val; 628 | } 629 | 630 | static VALUE sp_set_rts_impl(self, val) 631 | VALUE self, val; 632 | { 633 | return set_signal(self, val, TIOCM_RTS); 634 | } 635 | 636 | static VALUE sp_set_dtr_impl(self, val) 637 | VALUE self, val; 638 | { 639 | return set_signal(self, val, TIOCM_DTR); 640 | } 641 | 642 | static VALUE sp_get_rts_impl(self) 643 | VALUE self; 644 | { 645 | struct line_signals ls; 646 | 647 | get_line_signals_helper(self, &ls); 648 | return INT2FIX(ls.rts); 649 | } 650 | 651 | static VALUE sp_get_dtr_impl(self) 652 | VALUE self; 653 | { 654 | struct line_signals ls; 655 | 656 | get_line_signals_helper(self, &ls); 657 | 658 | return INT2FIX(ls.dtr); 659 | } 660 | 661 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | --------------------------------------------------------------------------------