update to ruby binding from steven jenkins:
authorFrank Mori Hess <fmhess@speakeasy.net>
Mon, 29 Mar 2004 01:39:36 +0000 (01:39 +0000)
committerFrank Mori Hess <fmhess@speakeasy.net>
Mon, 29 Mar 2004 01:39:36 +0000 (01:39 +0000)
Better exception handling. More consistent handling of return values. Updated
documentation.

swig/ruby/README
swig/ruby/demo/cmd
swig/ruby/demo/common.rb
swig/ruby/demo/inp [new file with mode: 0755]
swig/ruby/demo/outp [new file with mode: 0755]
swig/ruby/lib/comedi.rb

index 56fffd04770c9e4dae6c29ce3ef0831b383f0c9c..220683276424a6e2a158f51b4e68f1834bd2a21b 100644 (file)
@@ -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
index b6408145827268f00e2ca9a2ac04675595218a25..7920b5520c8847f1fe67cad8ac07a494f9c28a81 100755 (executable)
@@ -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)
index ff4abce243c5c12dc0bab019d316c9899a2bdb54..31b562716f51298425fab51bdc9e607fb7f67006 100644 (file)
@@ -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 (executable)
index 0000000..be21a62
--- /dev/null
@@ -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 (executable)
index 0000000..d829202
--- /dev/null
@@ -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
index f769d18c32c5cb31b514ae686596ea0ddeaed141..47d42ae92939e341713e079a19f4b68b580241d2 100644 (file)
@@ -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.
 #
 # (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