########################  base.rb -- brent@mbari.org  #####################
# $Source: /home/cvs/ESP/gen2/software/esp/utils/base.rb,v $
#    Copyright (C) 2003 MBARI
#    MBARI Proprietary Information. All rights reserved.
# $Id: base.rb,v 1.10 2005/11/01 07:54:32 brent Exp $
#
#  common initialization code for all operation modes
#  plus outer ESP shell scripts
#
############################################################################

require 'i2c/shaft'
require 'i2c/servo'
require 'i2c/solenoid'
require 'i2c/thermal'

MsgTarget = {}  #hash of target names to targets

module I2C
  DwarfAdr = {  #addresses of dwarves on the real or simulated I2C bus
                #and their unique initial for indentification in the log
    :processing=>  [?P, 0x15],    #processing station dwarf
    :manipulator=> [?M, 0x16],    #manuipulator arm dwarf
    :collection=>  [?C, 0x17],    #collection station dwarf
    :storage=>     [?A, 0x18],    #puck storage elevator and carousel
    :sampler=>     [?S, 0x19]     #sampler station
  }

  DwarfNet = I2C::Network.new

  Dwarf={}  #placeholder for Dwarf I2C targets
  
# all dwarves run the same firmware, so all models and parser are the same
# we need only one parser instance because it is stateless
  DwarfParser = I2C::Solenoid::Parser.new<<I2C::Thermal::Parser.new<<
                I2C::Shaft::Parser.new<<I2C::Servo::Parser.new

  def self.targetInitials
  #return a hash of targets to their corresponding initials for logging
    targets={}
    MsgTarget.each {|name, targetAlias|
      targets[targetAlias.last] = targetAlias.first
    }
    targets
  end
  
  def self.buildControllers names=Dwarf.keys, targetHash=Dwarf, 
                            adrHash=DwarfAdr
  #create microcontroller interfaces corresponding to each dwarf
    [:Servos, :Shafts, :Thermals, :Solenoids].each do |hash|
      const_set hash, {}
    end
    names.each {|name|
      target=targetHash[name]
      adr=adrHash[name].last
      Servos[name]=Servo.new target, adr
      Shafts[name]=Shaft.new target, adr
      Thermals[name]=Thermal.new target, adr
      Solenoids[name]=Solenoid.new target, adr
    }
  end
end


class Symbol
  def denotes object, scope=Object
  #assign constant scope::self to object modified to 
  #return self in reponse to #intern
    scope.const_set self, object
    object.intern=self
  end
end


module ESP

  def self.shell mainThreadName, targets=I2C::targetInitials
    logger = Log.default
    sch = Thread.schedule
    targets[Thread.current]=?m
    main = Thread mainThreadName do
      begin
        targets[Thread.current]=?t
        logger.denote targets
        yield if block_given?
        Delay.sleep #wait until scheduler has started processing events
        execute 'configure'
        Delay.sleep #ensure all pending events have been processed
        runApplication
      rescue Exception => err
        $lastErr = err  #see SourceRef.doMethod
        Delay.sleep
        logger.recordException err
      ensure
        sch.stop
      end
    end
    begin
      sch.start
    rescue Exception => err
      main.raise err
      retry
    end
  end
end

