###################################################################### # # $Source$ # # $Revision$ # $Date$ # # $Author$ # # Copyright (C) 2003,2004 James Steven Jenkins # ###################################################################### # This file is syntactic sugar for accessing the Ruby comedilib # extension library generated by SWIG. The syntactic sugar is in # several forms: # # (1) Method names without the 'comedi_' prefix. The Comedi module # disambiguates the namespace. # # (2) Instance methods that take an explicit receiver instead of # passing the target object as an initial pointer. For example: # comedi_close(dev) can be written as dev.close. # # (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. 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' include Comedi # SWIG::TYPE_p_comedi_t_struct is returned by Comedi::open class SWIG::TYPE_p_comedi_t_struct # create an IO object to access the comedi_t_struct fileno def 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_method is the basis for wrap_module_method and # wrap_instance_method. 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 } case err when :neg wrap_def << %Q{#{status} < 0\n} when nil wrap_def << %Q{#{status}.nil?\n} else wrap_def << %Q{#{status} == #{err}\n} end 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 # 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, multi) wrap_method(mod, name, err, multi, '*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. The wrapped method raises ComediError # if the return value equals a specified value. 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, # error, and multi-return indication. Method_group = Struct.new(:class, :err, :multi, :names) # Define method groups. module_methods = [ # Comedi module methods that return nil on error. Method_group.new(Comedi, nil, nil, %w{ open parse_calibration_file }), # Comedi module methods that do not indicate errors. Method_group.new(Comedi, :none, nil, %w{ loglevel perror strerrno errno to_phys from_phys set_global_oor_behavior to_physical from_physical }), ] instance_methods = [ # SWIG::TYPE_p_comedi_t_struct methods that return -1 on error. Method_group.new(SWIG::TYPE_p_comedi_t_struct, -1, nil, %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_hint data_write dio_get_config dio_config dio_write cancel command poll set_max_buffer_size get_buffer_contents mark_buffer_read mark_buffer_written get_buffer_offset get_buffer_read_offset get_buffer_write_offset get_softcal_converter get_hardcal_converter internal_trigger arm arm_channel disarm disarm_channel reset reset_channel set_counter_mode set_clock_source set_filter set_gate_source set_other_source set_routing get_hardware_buffer_size digital_trigger_disable digital_trigger_enable_edges digital_trigger_enable_levels set_read_subdevice set_write_subdevice }), # SWIG::TYPE_p_comedi_t_struct methods that return status and a # value. Status is -1 on error. Status is discarded. Method_group.new(SWIG::TYPE_p_comedi_t_struct, -1, :simple, %w{ data_read data_read_delayed dio_read dio_bitfield dio_bitfield2 get_cmd_src_mask get_cmd_generic_timed get_gate_source get_routing get_buffer_read_count get_buffer_write_count }), # TODO: add get_clock_source, but it returns status and two values. # SWIG::TYPE_p_comedi_t_struct 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_struct, -1, :compound, %w{ command_test }), # SWIG::TYPE_p_comedi_t_struct methods that return 0 on error. Method_group.new(SWIG::TYPE_p_comedi_t_struct, 0, nil, %w{ get_maxdata }), # SWIG::TYPE_p_comedi_t_struct methods that return <0 on error. Method_group.new(SWIG::TYPE_p_comedi_t_struct, :neg, nil, %w{ apply_calibration apply_parsed_calibration }), # SWIG::TYPE_p_comedi_t_struct methods that return nil on error. Method_group.new(SWIG::TYPE_p_comedi_t_struct, nil, nil, %w{ get_driver_name get_board_name get_range get_default_calibration_path }), # SWIG::TYPE_p_comedi_t_struct methods that do not indicate errors. Method_group.new(SWIG::TYPE_p_comedi_t_struct, :none, nil, %w{ get_n_subdevices get_version_code }), # Comedi_sv_t methods that return -1 on error. 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, nil, %w{ cleanup_calibration }) ] # 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, d.multi) end end end