From: Frank Mori Hess Date: Mon, 29 Mar 2004 01:39:36 +0000 (+0000) Subject: update to ruby binding from steven jenkins: X-Git-Tag: r0_7_22~59 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=dfc1ffbdbaa9a6554d16f1cbdd90ae666bbcfe69;p=comedilib.git update to ruby binding from steven jenkins: Better exception handling. More consistent handling of return values. Updated documentation. --- diff --git a/swig/ruby/README b/swig/ruby/README index 56fffd0..2206832 100644 --- a/swig/ruby/README +++ b/swig/ruby/README @@ -28,23 +28,492 @@ The file 'lib/comedi.rb' provides syntactic sugar in four forms: 4. A ComediError exception class. If the underlying comedi function returns an error indication, the ruby method will raise - ComediError. + ComediError. If the comedi function returns both a status and a + value (e.g., comedi_data_read), the status is not returned by the + ruby method unless it carries information in addition to indication + of failure (e.g., comedi_command_test). -The file 'demo/cmd' is a straight port of 'cmd.c' from the -Comedilib 'demo' directory. It illustrates the basics of programming +5. Ruby booleans. Comedi functions that return C integer boolean values + (comedi_range_is_chan_specific, comedi_maxdata_is_chan_specific) + have corresponding boolean ruby methods with '?' appended to the + method name. + +Files in 'demo' are straight ports of their C counterparts from the +Comedilib 'demo' directory. They illustrate the basics of programming Comedi commands using Ruby. -If a Comedilib function returns a value through a pointer passed as an -input parameter, its Ruby counterpart returns the value as an element -of an Array. +For completeness, the set of method definitions invoked by 'comedi.rb' +is as follows: + + # Module: Comedi + + def open(*args) + value = comedi_open(*args) + raise ComediError.new if value.nil? + return value + end + + # Module: Comedi + + def parse_calibration_file(*args) + value = comedi_parse_calibration_file(*args) + raise ComediError.new if value.nil? + return value + end + + # Module: Comedi + + def loglevel(*args) + value = comedi_loglevel(*args) + return value + end + + # Module: Comedi + + def perror(*args) + value = comedi_perror(*args) + return value + end + + # Module: Comedi + + def strerrno(*args) + value = comedi_strerrno(*args) + return value + end + + # Module: Comedi + + def errno(*args) + value = comedi_errno(*args) + return value + end + + # Module: Comedi + + def to_phys(*args) + value = comedi_to_phys(*args) + return value + end + + # Module: Comedi + + def from_phys(*args) + value = comedi_from_phys(*args) + return value + end + + # Module: Comedi + + def set_global_oor_behavior(*args) + value = comedi_set_global_oor_behavior(*args) + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def close(*args) + value = comedi_close(self, *args) + raise ComediError.new if value == -1 + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def fileno(*args) + value = comedi_fileno(self, *args) + raise ComediError.new if value == -1 + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def get_subdevice_type(*args) + value = comedi_get_subdevice_type(self, *args) + raise ComediError.new if value == -1 + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def find_subdevice_by_type(*args) + value = comedi_find_subdevice_by_type(self, *args) + raise ComediError.new if value == -1 + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def get_read_subdevice(*args) + value = comedi_get_read_subdevice(self, *args) + raise ComediError.new if value == -1 + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def get_write_device(*args) + value = comedi_get_write_device(self, *args) + raise ComediError.new if value == -1 + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def get_subdevice_flags(*args) + value = comedi_get_subdevice_flags(self, *args) + raise ComediError.new if value == -1 + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def get_n_channels(*args) + value = comedi_get_n_channels(self, *args) + raise ComediError.new if value == -1 + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def range_is_chan_specific?(*args) + value = comedi_range_is_chan_specific(self, *args) + raise ComediError.new if value == -1 + return ret == 1 + end + + # Module: SWIG::TYPE_p_comedi_t + + def maxdata_is_chan_specific?(*args) + value = comedi_maxdata_is_chan_specific(self, *args) + raise ComediError.new if value == -1 + return ret == 1 + end + + # Module: SWIG::TYPE_p_comedi_t + + def get_n_ranges(*args) + value = comedi_get_n_ranges(self, *args) + raise ComediError.new if value == -1 + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def find_range(*args) + value = comedi_find_range(self, *args) + raise ComediError.new if value == -1 + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def get_buffer_size(*args) + value = comedi_get_buffer_size(self, *args) + raise ComediError.new if value == -1 + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def get_max_buffer_size(*args) + value = comedi_get_max_buffer_size(self, *args) + raise ComediError.new if value == -1 + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def set_buffer_size(*args) + value = comedi_set_buffer_size(self, *args) + raise ComediError.new if value == -1 + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def trigger(*args) + value = comedi_trigger(self, *args) + raise ComediError.new if value == -1 + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def do_insnlist(*args) + value = comedi_do_insnlist(self, *args) + raise ComediError.new if value == -1 + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def do_insn(*args) + value = comedi_do_insn(self, *args) + raise ComediError.new if value == -1 + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def lock(*args) + value = comedi_lock(self, *args) + raise ComediError.new if value == -1 + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def unlock(*args) + value = comedi_unlock(self, *args) + raise ComediError.new if value == -1 + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def data_read_hint(*args) + value = comedi_data_read_hint(self, *args) + raise ComediError.new if value == -1 + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def data_write(*args) + value = comedi_data_write(self, *args) + raise ComediError.new if value == -1 + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def dio_config(*args) + value = comedi_dio_config(self, *args) + raise ComediError.new if value == -1 + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def dio_write(*args) + value = comedi_dio_write(self, *args) + raise ComediError.new if value == -1 + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def cancel(*args) + value = comedi_cancel(self, *args) + raise ComediError.new if value == -1 + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def command(*args) + value = comedi_command(self, *args) + raise ComediError.new if value == -1 + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def poll(*args) + value = comedi_poll(self, *args) + raise ComediError.new if value == -1 + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def set_max_buffer_size(*args) + value = comedi_set_max_buffer_size(self, *args) + raise ComediError.new if value == -1 + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def get_buffer_contents(*args) + value = comedi_get_buffer_contents(self, *args) + raise ComediError.new if value == -1 + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def mark_buffer_read(*args) + value = comedi_mark_buffer_read(self, *args) + raise ComediError.new if value == -1 + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def get_buffer_offset(*args) + value = comedi_get_buffer_offset(self, *args) + raise ComediError.new if value == -1 + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def data_read(*args) + status, value = comedi_data_read(self, *args) + raise ComediError.new if status == -1 + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def data_read_delayed(*args) + status, value = comedi_data_read_delayed(self, *args) + raise ComediError.new if status == -1 + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def dio_read(*args) + status, value = comedi_dio_read(self, *args) + raise ComediError.new if status == -1 + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def dio_bitfield(*args) + status, value = comedi_dio_bitfield(self, *args) + raise ComediError.new if status == -1 + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def get_cmd_src_mask(*args) + status, value = comedi_get_cmd_src_mask(self, *args) + raise ComediError.new if status == -1 + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def get_cmd_generic_timed(*args) + status, value = comedi_get_cmd_generic_timed(self, *args) + raise ComediError.new if status == -1 + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def command_test(*args) + status, value = comedi_command_test(self, *args) + raise ComediError.new if status == -1 + return status, value + end + + # Module: SWIG::TYPE_p_comedi_t + + def get_maxdata(*args) + value = comedi_get_maxdata(self, *args) + raise ComediError.new if value == 0 + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def apply_calibration(*args) + value = comedi_apply_calibration(self, *args) + raise ComediError.new if value < 0 + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def apply_parsed_calibration(*args) + value = comedi_apply_parsed_calibration(self, *args) + raise ComediError.new if value < 0 + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def get_driver_name(*args) + value = comedi_get_driver_name(self, *args) + raise ComediError.new if value.nil? + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def get_board_name(*args) + value = comedi_get_board_name(self, *args) + raise ComediError.new if value.nil? + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def get_range(*args) + value = comedi_get_range(self, *args) + raise ComediError.new if value.nil? + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def get_default_calibration_path(*args) + value = comedi_get_default_calibration_path(self, *args) + raise ComediError.new if value.nil? + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def get_n_subdevices(*args) + value = comedi_get_n_subdevices(self, *args) + return value + end + + # Module: SWIG::TYPE_p_comedi_t + + def get_version_code(*args) + value = comedi_get_version_code(self, *args) + return value + end + + # Module: Comedi::Comedi_sv_t + + def sv_init(*args) + value = comedi_sv_init(self, *args) + raise ComediError.new if value == -1 + return value + end + + # Module: Comedi::Comedi_sv_t + + def sv_update(*args) + value = comedi_sv_update(self, *args) + raise ComediError.new if value == -1 + return value + end + + # Module: Comedi::Comedi_sv_t - ret, cmd = dev.command_test(cmd) + def sv_measure(*args) + status, value = comedi_sv_measure(self, *args) + raise ComediError.new if status == -1 + return value + end -Because the command object is used by command_test() it appears as an -input parameter as well. If the pointer is used only for output, it is -omitted from the parameter list. For example: + # Module: Comedi::Comedi_calibration_t - data = dev.data_read(subdevice, channel, range, aref); + def cleanup_calibration_file(*args) + value = comedi_cleanup_calibration_file(self, *args) + return value + end Steven Jenkins steven.jenkins@ieee.org diff --git a/swig/ruby/demo/cmd b/swig/ruby/demo/cmd index b640814..7920b55 100755 --- a/swig/ruby/demo/cmd +++ b/swig/ruby/demo/cmd @@ -13,12 +13,12 @@ cmdtest_messages = [ "success", "invalid source", "source conflict", class SWIG::TYPE_p_comedi_t def prepare_cmd_lib(subdevice, freq, cmd) - ret, cmd = get_cmd_generic_timed(subdevice, cmd, - 1000000000.0 / freq) - - if ret < 0 + begin + cmd = get_cmd_generic_timed(subdevice, cmd, + 1000000000.0 / freq) + rescue ComediError printf("comedi_get_cmd_generic_timed failed\n") - return ret, cmd + return cmd end cmd.chanlist = $chanlist @@ -27,12 +27,12 @@ class SWIG::TYPE_p_comedi_t cmd.scan_end_arg = $n_chan cmd.stop_arg = $n_scan if cmd.stop_src == TRIG_COUNT - return 0, cmd + return cmd end end -parse_options($ARGV) +parse_options begin dev = Comedi::open($filename) @@ -46,7 +46,7 @@ $chanlist = Chanlist.new($n_chan) $chanlist[i] = cr_pack($channel + i, $range, $aref) end -ret, cmd = dev.prepare_cmd_lib($subdevice, $freq, Comedi_cmd_struct.new) +cmd = dev.prepare_cmd_lib($subdevice, $freq, Comedi_cmd_struct.new) $stderr.printf("command before testing:\n") dump_cmd($stderr, cmd) diff --git a/swig/ruby/demo/common.rb b/swig/ruby/demo/common.rb index ff4abce..31b5627 100644 --- a/swig/ruby/demo/common.rb +++ b/swig/ruby/demo/common.rb @@ -1,6 +1,7 @@ -def parse_options(argv) +def parse_options $filename = "/dev/comedi0" + $value = 0 $subdevice = 0 $channel = 0 $range = 0 @@ -8,6 +9,7 @@ def parse_options(argv) $n_chan = 4 $n_scan = 1000 $freq = 1000.0 + $verbose = false opts = GetoptLong.new( [ "--filename", "-f", GetoptLong::REQUIRED_ARGUMENT ], @@ -41,6 +43,8 @@ def parse_options(argv) $n_scan = arg.to_i when "--freq" $freq = arg.to_i + when "--verbose" + $verbose = true when "--diff" $aref = AREF_DIFF when "--ground" @@ -54,6 +58,10 @@ def parse_options(argv) exit 0 end end + + if ARGV.length > 0 + $value = ARGV.shift.to_i + end end def cmd_src(src) diff --git a/swig/ruby/demo/inp b/swig/ruby/demo/inp new file mode 100755 index 0000000..be21a62 --- /dev/null +++ b/swig/ruby/demo/inp @@ -0,0 +1,32 @@ +#!/usr/bin/env ruby + +require 'comedi' +require 'getoptlong' +require 'common' + +include Comedi + +parse_options + +begin + dev = Comedi::open($filename) +rescue + comedi_perror($filename) + exit 1 +end + +if $verbose + print "measuring device=#{$filename} subdevice=#{$subdevice}" + print " channel=#{$channel} range=#{$range}" + print " analog reference=#{$aref}\n" +end + +begin + data = dev.data_read($subdevice, $channel, $range, $aref) +rescue + comedi_perror($filename) + exit 1 +end +puts data + +exit 0 diff --git a/swig/ruby/demo/outp b/swig/ruby/demo/outp new file mode 100755 index 0000000..d829202 --- /dev/null +++ b/swig/ruby/demo/outp @@ -0,0 +1,34 @@ +#!/usr/bin/env ruby + +require 'comedi' +require 'getoptlong' +require 'common' + +include Comedi + +parse_options + +begin + dev = Comedi::open($filename) +rescue + comedi_perror($filename) + exit 1 +end + +data = $value + +if $verbose + print "writing #{$value} to device=#{$filename} subdevice=#{$subdevice}" + print " channel=#{$channel} range=#{$range}" + print " analog reference=#{$aref}\n" +end + +begin + dev.data_write($subdevice, $channel, $range, $aref, data) +rescue + comedi_perror($filename) + exit 1 +end +puts data + +exit 0 diff --git a/swig/ruby/lib/comedi.rb b/swig/ruby/lib/comedi.rb index f769d18..47d42ae 100644 --- a/swig/ruby/lib/comedi.rb +++ b/swig/ruby/lib/comedi.rb @@ -13,7 +13,7 @@ # This file is syntactic sugar for accessing the Ruby comedilib # extension library generated by SWIG. The syntactic sugar is in -# four forms: +# several forms: # # (1) Method names without the 'comedi_' prefix. The Comedi module # disambiguates the namespace. @@ -28,7 +28,14 @@ # # (4) A ComediError exception class. If the underlying comedi # function returns an error indication, the ruby method will raise -# ComediError. +# ComediError. If the comedi function returns both a status and a +# value (e.g., comedi_data_read), the status is not returned by the +# ruby method unless it carries information in addition to indication +# of failure (e.g., comedi_command_test). +# +# (5) Ruby booleans. Comedi functions that return C integer boolean values +# (comedi_range_is_chan_specific, comedi_maxdata_is_chan_specific) have +# corresponding boolean ruby methods with '?' appended to the method name. require 'comedi.so' @@ -67,26 +74,54 @@ private # wrap_method is the basis for wrap_module_method and # wrap_instance_method. - def wrap_method(mod, name, err, arglist) - wrap_def = %Q{ - def #{name}(*args) - ret = comedi_#{name}(#{arglist}) - } + def wrap_method(mod, name, err, multi, arglist) + + cname = name + ret = 'value' + status = 'value' + value = 'value' + + # If name ends in '?', make ruby wrapper a boolean. + + if bool = (name =~ /\?$/) + value = 'ret == 1' + cname = name.sub(/\?$/, '') + elsif multi == :simple + ret = 'status, value' + status = 'status' + value = 'value' + elsif multi == :compound + ret = 'status, value' + status = 'status' + value = 'status, value' + end + + wrap_def = %Q{# Module: #{mod}\n\n} + wrap_def << %Q{def #{name}(*args)\n} + wrap_def << %Q{ #{ret} = comedi_#{cname}(#{arglist})\n} + + # Raise exceptions if required. + unless err == :none - wrap_def << %Q{ raise ComediError.new if } + wrap_def << %Q{ raise ComediError.new if } case err when :neg - wrap_def << %Q{ ret < 0 } + wrap_def << %Q{#{status} < 0\n} when nil - wrap_def << %Q{ ret.nil? } + wrap_def << %Q{#{status}.nil?\n} else - wrap_def << %Q{ ret == #{err} } + wrap_def << %Q{#{status} == #{err}\n} end end - wrap_def << %Q{ - ret - end - } + + # Return value. + + wrap_def << %Q{ return #{value}\n} + wrap_def << %Q{end\n\n} + + # Execute definition. + + puts wrap_def if __FILE__ == 'comedi.rb' mod.module_eval wrap_def end @@ -94,8 +129,8 @@ private # unnecessary comedi_ prefix. The wrapped method raises # ComediError if the return value equals a specified value. - def wrap_module_method(mod, name, err) - wrap_method(mod, name, err, '*args') + def wrap_module_method(mod, name, err, multi) + wrap_method(mod, name, err, multi, '*args') end # wrap_instance_method defines instance methods for any of several @@ -103,28 +138,29 @@ private # explicit receiver. The wrapped method raises ComediError # if the return value equals a specified value. - def wrap_instance_method(mod, name, err) - wrap_method(mod, name, err, 'self, *args') + def wrap_instance_method(mod, name, err, multi) + wrap_method(mod, name, err, multi, 'self, *args') end - # This struct holds information for methods with return class and - # error indication. + # This struct holds information for methods with return class, + # error, and multi-return indication. + + Method_group = Struct.new(:class, :err, :multi, :names) - Method_group = Struct.new(:class, :err, :names) + # Define method groups. - # Wrap Comedi module methods + module_methods = [ - [ # Comedi module methods that return nil on error. - Method_group.new(Comedi, nil, %w{ + Method_group.new(Comedi, nil, nil, %w{ open parse_calibration_file }), # Comedi module methods that do not indicate errors. - Method_group.new(Comedi, :none, %w{ + Method_group.new(Comedi, :none, nil, %w{ loglevel perror strerrno @@ -133,18 +169,13 @@ private from_phys set_global_oor_behavior }), - ].each do |d| - d.names.each do |n| - wrap_module_method(d.class, n, d.err) - end - end - - # Wrap Instance methods + ] + + instance_methods = [ - [ # SWIG::TYPE_p_comedi_t methods that return -1 on error. - Method_group.new(SWIG::TYPE_p_comedi_t, -1, %w{ + Method_group.new(SWIG::TYPE_p_comedi_t, -1, nil, %w{ close fileno get_subdevice_type @@ -153,8 +184,8 @@ private get_write_device get_subdevice_flags get_n_channels - range_is_chan_specific - maxdata_is_chan_specific + range_is_chan_specific? + maxdata_is_chan_specific? get_n_ranges find_range get_buffer_size @@ -165,18 +196,12 @@ private do_insn lock unlock - data_read - data_read_delayed + data_read_hint data_write dio_config - dio_read dio_write - dio_bitfield - get_cmd_src_mask - get_cmd_generic_timed cancel command - command_test poll set_max_buffer_size get_buffer_contents @@ -184,22 +209,42 @@ private get_buffer_offset }), + # SWIG::TYPE_p_comedi_t methods that return status and a + # value. Status is -1 on error. Status is discarded. + + Method_group.new(SWIG::TYPE_p_comedi_t, -1, :simple, %w{ + data_read + data_read_delayed + dio_read + dio_bitfield + get_cmd_src_mask + get_cmd_generic_timed + }), + + # SWIG::TYPE_p_comedi_t methods that return status and a + # value. Status is -1 on error. Status and value are both + # returned. + + Method_group.new(SWIG::TYPE_p_comedi_t, -1, :compound, %w{ + command_test + }), + # SWIG::TYPE_p_comedi_t methods that return 0 on error. - Method_group.new(SWIG::TYPE_p_comedi_t, 0, %w{ + Method_group.new(SWIG::TYPE_p_comedi_t, 0, nil, %w{ get_maxdata }), # SWIG::TYPE_p_comedi_t methods that return <0 on error. - Method_group.new(SWIG::TYPE_p_comedi_t, :neg, %w{ + Method_group.new(SWIG::TYPE_p_comedi_t, :neg, nil, %w{ apply_calibration apply_parsed_calibration }), # SWIG::TYPE_p_comedi_t methods that return nil on error. - Method_group.new(SWIG::TYPE_p_comedi_t, nil, %w{ + Method_group.new(SWIG::TYPE_p_comedi_t, nil, nil, %w{ get_driver_name get_board_name get_range @@ -208,28 +253,45 @@ private # SWIG::TYPE_p_comedi_t methods that do not indicate errors. - Method_group.new(SWIG::TYPE_p_comedi_t, :none, %w{ + Method_group.new(SWIG::TYPE_p_comedi_t, :none, nil, %w{ get_n_subdevices get_version_code - data_read_hint }), - # Comedi_sv_t methods that return -1 on errors. + # Comedi_sv_t methods that return -1 on error. - Method_group.new(Comedi_sv_t, -1, %w{ + Method_group.new(Comedi_sv_t, -1, nil, %w{ sv_init sv_update + }), + + # Comedi_sv_t methods that return status and a value. Status + # is -1 on error. + + Method_group.new(Comedi_sv_t, -1, :simple, %w{ sv_measure }), # Comedi_calibration_t methods that do not indicate errors. - Method_group.new(Comedi_calibration_t, :none, %w{ + Method_group.new(Comedi_calibration_t, :none, nil, %w{ cleanup_calibration_file }) - ].each do |d| + ] + + # Wrap Comedi module methods. + + module_methods.each do |d| + d.names.each do |n| + wrap_module_method(d.class, n, d.err, d.multi) + end + end + + # Wrap instance methods. + + instance_methods.each do |d| d.names.each do |n| - wrap_instance_method(d.class, n, d.err) + wrap_instance_method(d.class, n, d.err, d.multi) end end end