From 41ce3f70a09940eb4e4b613013d0829f8058adf2 Mon Sep 17 00:00:00 2001 From: Frank Mori Hess Date: Sat, 6 Mar 2004 22:13:37 +0000 Subject: [PATCH] patch from Steven Jenkins ------- The attached patch updates files in comedilib/swig/ruby. lib/comedi.rb is updated to raise Ruby exceptions as indicated by the comedilib API documentation. README and demo/cmd are updated accordingly. --- swig/ruby/README | 8 +- swig/ruby/demo/cmd | 15 +-- swig/ruby/lib/comedi.rb | 227 ++++++++++++++++++++++++++++++---------- 3 files changed, 187 insertions(+), 63 deletions(-) diff --git a/swig/ruby/README b/swig/ruby/README index f1e0092..56fffd0 100644 --- a/swig/ruby/README +++ b/swig/ruby/README @@ -12,7 +12,7 @@ Instructions for building by hand (you shouldn't need to do this): library and the file lib/comedi.rb, which provides more Ruby-like method syntax. -The file 'lib/comedi.rb' provides syntactic sugar in three forms: +The file 'lib/comedi.rb' provides syntactic sugar in four forms: 1. Method names without the 'comedi_' prefix. The Comedi module disambiguates the namespace. For example, you can say @@ -26,6 +26,10 @@ The file 'lib/comedi.rb' provides syntactic sugar in three forms: reading from the file descriptor associated with the comedi device. Data from comedi device 'dev' can be read by 'dev.ios.read'. +4. A ComediError exception class. If the underlying comedi + function returns an error indication, the ruby method will raise + ComediError. + The file 'demo/cmd' is a straight port of 'cmd.c' from the Comedilib 'demo' directory. It illustrates the basics of programming Comedi commands using Ruby. @@ -44,4 +48,4 @@ omitted from the parameter list. For example: Steven Jenkins steven.jenkins@ieee.org -2004-01-12 +2004-03-02 diff --git a/swig/ruby/demo/cmd b/swig/ruby/demo/cmd index 861bb3c..b640814 100755 --- a/swig/ruby/demo/cmd +++ b/swig/ruby/demo/cmd @@ -51,16 +51,18 @@ ret, cmd = dev.prepare_cmd_lib($subdevice, $freq, Comedi_cmd_struct.new) $stderr.printf("command before testing:\n") dump_cmd($stderr, cmd) -ret, cmd = dev.command_test(cmd) -if ret < 0 +begin + ret, cmd = dev.command_test(cmd) +rescue comedi_perror("comedi_command_test") exit 1 end $stderr.printf("first test returned %d (%s)\n", ret, cmdtest_messages[ret]) dump_cmd($stderr, cmd) -ret, cmd = dev.command_test(cmd) -if ret < 0 +begin + ret, cmd = dev.command_test(cmd) +rescue comedi_perror("comedi_command_test") exit 1 end @@ -70,8 +72,9 @@ dump_cmd($stderr, cmd) tstart = Time.new $stderr.printf("start time: %d.%06d\n", tstart.tv_sec, tstart.tv_usec) -ret = dev.command(cmd) -if ret < 0 +begin + ret = dev.command(cmd) +rescue comedi_perror("comedi_command") exit 1 end diff --git a/swig/ruby/lib/comedi.rb b/swig/ruby/lib/comedi.rb index ef38f6f..f769d18 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 -# three forms: +# four forms: # # (1) Method names without the 'comedi_' prefix. The Comedi module # disambiguates the namespace. @@ -25,94 +25,211 @@ # (3) A pre-defined IO object and an accessor method to simplify # reading from the file descriptor associated with the comedi device. # Data from comedi device dev can be accessed with dev.ios.read. +# +# (4) A ComediError exception class. If the underlying comedi +# function returns an error indication, the ruby method will raise +# ComediError. require 'comedi.so' include Comedi -include SWIG - -module SWIG -# TYPE_p_comedi_t is returned by Comedi::open +# SWIG::TYPE_p_comedi_t is returned by Comedi::open -class TYPE_p_comedi_t +class SWIG::TYPE_p_comedi_t # create an IO object to access the comedi_t fileno def ios - @ios = IO.new(fileno, 'r') if @ios.nil? - @ios + def self.ios + @ios + end + @ios = IO.new(fileno, 'r') end end +# ComediError is raised by methods whose underlying comedi functions return +# indication of an error. + +class ComediError < SystemCallError + + def initialize + @comedi_errno = Comedi::errno + end + + attr_reader :comedi_errno end module Comedi private - # wrap_module_method defines Comedi module methods without the - # unnecessary comedi_ prefix. + # wrap_method is the basis for wrap_module_method and + # wrap_instance_method. - def wrap_module_method(mod, name) - mod.module_eval <<-EOF + def wrap_method(mod, name, err, arglist) + wrap_def = %Q{ def #{name}(*args) - comedi_#{name}(*args) + ret = comedi_#{name}(#{arglist}) + } + unless err == :none + wrap_def << %Q{ raise ComediError.new if } + case err + when :neg + wrap_def << %Q{ ret < 0 } + when nil + wrap_def << %Q{ ret.nil? } + else + wrap_def << %Q{ ret == #{err} } + end + end + wrap_def << %Q{ + ret end - EOF + } + mod.module_eval wrap_def + end + + # wrap_module_method defines Comedi module methods without the + # 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') end # wrap_instance_method defines instance methods for any of several # classes. It removes the comedi_ prefix and allows use of an - # explicit receiver. + # explicit receiver. The wrapped method raises ComediError + # if the return value equals a specified value. - def wrap_instance_method(mod, name) - mod.module_eval <<-EOF - def #{name}(*args) - comedi_#{name}(self, *args) - end - EOF + def wrap_instance_method(mod, name, err) + wrap_method(mod, name, err, 'self, *args') end - # Comedi module methods + # This struct holds information for methods with return class and + # error indication. - %w{ open loglevel perror strerrno errno to_phys from_phys - set_global_oor_behavior parse_calibration_file - }.each do |name| - wrap_module_method(Comedi, name) - end + Method_group = Struct.new(:class, :err, :names) - # Comedi_t_struct instance methods - - %w{ close fileno get_n_subdevices get_version_code - get_driver_name get_board_name get_subdevice_type - find_subdevice_by_type get_read_subdevice get_write_device - get_subdevice_flags get_n_channels range_is_chan_specific - maxdata_is_chan_specific get_maxdata get_n_ranges - get_range find_range get_buffer size - get_max_buffer_size set_buffer_size trigger - do_insnlist 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 - mark_buffer_read get_buffer_offset apply_calibration - apply_parsed_calibration get_default_calibration_path - }.each do |name| - wrap_instance_method(SWIG::TYPE_p_comedi_t, name) - end + # Wrap Comedi module methods - # Comedi_sv_t instance methods + [ + # Comedi module methods that return nil on error. - %w{ sv_init sv_update sv_measure - }.each do |name| - wrap_instance_method(Comedi_sv_t, name) - end + Method_group.new(Comedi, nil, %w{ + open + parse_calibration_file + }), - # Comedi_calibration_t instance methods + # Comedi module methods that do not indicate errors. + + Method_group.new(Comedi, :none, %w{ + loglevel + perror + strerrno + errno + to_phys + from_phys + set_global_oor_behavior + }), + ].each do |d| + d.names.each do |n| + wrap_module_method(d.class, n, d.err) + end + end - %w{ cleanup_calibration_file - }.each do |name| - wrap_instance_method(Comedi_calibration_t, name) + # Wrap Instance methods + + [ + # SWIG::TYPE_p_comedi_t methods that return -1 on error. + + Method_group.new(SWIG::TYPE_p_comedi_t, -1, %w{ + close + fileno + get_subdevice_type + find_subdevice_by_type + get_read_subdevice + get_write_device + get_subdevice_flags + get_n_channels + range_is_chan_specific + maxdata_is_chan_specific + get_n_ranges + find_range + get_buffer_size + get_max_buffer_size + set_buffer_size + trigger + do_insnlist + do_insn + lock + unlock + data_read + data_read_delayed + 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 + mark_buffer_read + get_buffer_offset + }), + + # SWIG::TYPE_p_comedi_t methods that return 0 on error. + + Method_group.new(SWIG::TYPE_p_comedi_t, 0, %w{ + get_maxdata + }), + + # SWIG::TYPE_p_comedi_t methods that return <0 on error. + + Method_group.new(SWIG::TYPE_p_comedi_t, :neg, %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{ + get_driver_name + get_board_name + get_range + get_default_calibration_path + }), + + # SWIG::TYPE_p_comedi_t methods that do not indicate errors. + + Method_group.new(SWIG::TYPE_p_comedi_t, :none, %w{ + get_n_subdevices + get_version_code + data_read_hint + }), + + # Comedi_sv_t methods that return -1 on errors. + + Method_group.new(Comedi_sv_t, -1, %w{ + sv_init + sv_update + sv_measure + }), + + # Comedi_calibration_t methods that do not indicate errors. + + Method_group.new(Comedi_calibration_t, :none, %w{ + cleanup_calibration_file + }) + ].each do |d| + d.names.each do |n| + wrap_instance_method(d.class, n, d.err) + end end end -- 2.26.2